From 638ebcee70012cb959b6c210f6f4c08ad64689b6 Mon Sep 17 00:00:00 2001 From: Tor Lillqvist Date: Thu, 11 Nov 1999 22:12:27 +0000 Subject: [PATCH] re-adding for manual rename of repository files. --- gdk/win32/gdk-win32.def | 323 ++ gdk/win32/gdk.c | 2115 +++++++++++++ gdk/win32/gdk.def | 323 ++ gdk/win32/gdkdnd-win32.c | 973 ++++++ gdk/win32/gdkdnd.c | 973 ++++++ gdk/win32/gdkdraw.c | 909 ++++++ gdk/win32/gdkdrawable-win32.c | 909 ++++++ gdk/win32/gdkevents-win32.c | 5193 ++++++++++++++++++++++++++++++++ gdk/win32/gdkevents.c | 5193 ++++++++++++++++++++++++++++++++ gdk/win32/gdkfont-win32.c | 1501 +++++++++ gdk/win32/gdkfont.c | 1501 +++++++++ gdk/win32/gdkgc-win32.c | 1392 +++++++++ gdk/win32/gdkgc.c | 1392 +++++++++ gdk/win32/gdkglobals-win32.c | 51 + gdk/win32/gdkglobals.c | 51 + gdk/win32/gdkim-win32.c | 394 +++ gdk/win32/gdkim.c | 394 +++ gdk/win32/gdkinput-win32.c | 1685 +++++++++++ gdk/win32/gdkinput.c | 1685 +++++++++++ gdk/win32/gdkmain-win32.c | 2115 +++++++++++++ gdk/win32/gdkpixmap-win32.c | 1002 ++++++ gdk/win32/gdkpixmap.c | 1002 ++++++ gdk/win32/gdkprivate-win32.h | 459 +++ gdk/win32/gdkprivate.h | 459 +++ gdk/win32/gdkproperty-win32.c | 228 ++ gdk/win32/gdkproperty.c | 228 ++ gdk/win32/gdkregion-win32.c | 367 +++ gdk/win32/gdkregion.c | 367 +++ gdk/win32/gdkselection-win32.c | 403 +++ gdk/win32/gdkselection.c | 403 +++ gdk/win32/gdkvisual-win32.c | 346 +++ gdk/win32/gdkvisual.c | 346 +++ gdk/win32/gdkwindow-win32.c | 2407 +++++++++++++++ gdk/win32/gdkwindow.c | 2407 +++++++++++++++ 34 files changed, 39496 insertions(+) create mode 100644 gdk/win32/gdk-win32.def create mode 100644 gdk/win32/gdk.c create mode 100644 gdk/win32/gdk.def create mode 100644 gdk/win32/gdkdnd-win32.c create mode 100644 gdk/win32/gdkdnd.c create mode 100644 gdk/win32/gdkdraw.c create mode 100644 gdk/win32/gdkdrawable-win32.c create mode 100644 gdk/win32/gdkevents-win32.c create mode 100644 gdk/win32/gdkevents.c create mode 100644 gdk/win32/gdkfont-win32.c create mode 100644 gdk/win32/gdkfont.c create mode 100644 gdk/win32/gdkgc-win32.c create mode 100644 gdk/win32/gdkgc.c create mode 100644 gdk/win32/gdkglobals-win32.c create mode 100644 gdk/win32/gdkglobals.c create mode 100644 gdk/win32/gdkim-win32.c create mode 100644 gdk/win32/gdkim.c create mode 100644 gdk/win32/gdkinput-win32.c create mode 100644 gdk/win32/gdkinput.c create mode 100644 gdk/win32/gdkmain-win32.c create mode 100644 gdk/win32/gdkpixmap-win32.c create mode 100644 gdk/win32/gdkpixmap.c create mode 100644 gdk/win32/gdkprivate-win32.h create mode 100644 gdk/win32/gdkprivate.h create mode 100644 gdk/win32/gdkproperty-win32.c create mode 100644 gdk/win32/gdkproperty.c create mode 100644 gdk/win32/gdkregion-win32.c create mode 100644 gdk/win32/gdkregion.c create mode 100644 gdk/win32/gdkselection-win32.c create mode 100644 gdk/win32/gdkselection.c create mode 100644 gdk/win32/gdkvisual-win32.c create mode 100644 gdk/win32/gdkvisual.c create mode 100644 gdk/win32/gdkwindow-win32.c create mode 100644 gdk/win32/gdkwindow.c diff --git a/gdk/win32/gdk-win32.def b/gdk/win32/gdk-win32.def new file mode 100644 index 000000000..564af22e4 --- /dev/null +++ b/gdk/win32/gdk-win32.def @@ -0,0 +1,323 @@ +EXPORTS + gdk_atom_intern + gdk_atom_name + gdk_beep + gdk_bitmap_create_from_data + gdk_bitmap_ref + gdk_bitmap_unref + gdk_char_height + gdk_char_measure + gdk_char_width + gdk_char_width_wc + gdk_color_alloc + gdk_color_black + gdk_color_change + gdk_color_copy + gdk_color_equal + gdk_color_free + gdk_color_hash + gdk_color_parse + gdk_color_white + gdk_colormap_alloc_color + gdk_colormap_alloc_colors + gdk_colormap_change + gdk_colormap_free_colors + gdk_colormap_get_system + gdk_colormap_get_system_size + gdk_colormap_get_visual + gdk_colormap_new + gdk_colormap_ref + gdk_colormap_unref + gdk_colors_alloc + gdk_colors_free + gdk_colors_store + gdk_cursor_destroy + gdk_cursor_new + gdk_cursor_new_from_pixmap + gdk_debug_flags + gdk_dnd_init + gdk_drag_abort + gdk_drag_begin + gdk_drag_context_new + gdk_drag_context_ref + gdk_drag_context_unref + gdk_drag_drop + gdk_drag_find_window + gdk_drag_get_protocol + gdk_drag_get_selection + gdk_drag_motion + gdk_drag_status + gdk_drop_finish + gdk_drop_reply + gdk_draw_arc + gdk_draw_gray_image + gdk_draw_image + gdk_draw_indexed_image + gdk_draw_line + gdk_draw_lines + gdk_draw_pixmap + gdk_draw_point + gdk_draw_points + gdk_draw_polygon + gdk_draw_rectangle + gdk_draw_rgb_32_image + gdk_draw_rgb_image + gdk_draw_rgb_image_dithalign + gdk_draw_segments + gdk_draw_string + gdk_draw_text + gdk_draw_text_wc + gdk_drawable_get_colormap + gdk_drawable_get_size + gdk_drawable_get_type + gdk_drawable_get_visual + gdk_drawable_set_colormap + gdk_drawable_set_data + gdk_error_code + gdk_error_trap_pop + gdk_error_trap_push + gdk_error_warnings + gdk_event_copy + gdk_event_free + gdk_event_get + gdk_event_get_graphics_expose + gdk_event_get_time + gdk_event_handler_set + gdk_event_peek + gdk_event_put + gdk_event_send_client_message + gdk_event_send_clientmessage_toall + gdk_events_pending + gdk_exit + gdk_flush + gdk_font_equal + gdk_font_id + gdk_font_list_free + gdk_font_list_new + gdk_font_load + gdk_font_ref + gdk_font_unref + gdk_font_xlfd_create + gdk_font_xlfd_free + gdk_fontset_load + gdk_free_compound_text + gdk_free_text_list + gdk_gc_copy + gdk_gc_destroy + gdk_gc_get_values + gdk_gc_new + gdk_gc_new_with_values + gdk_gc_ref + gdk_gc_set_background + gdk_gc_set_clip_mask + gdk_gc_set_clip_origin + gdk_gc_set_clip_rectangle + gdk_gc_set_clip_region + gdk_gc_set_dashes + gdk_gc_set_exposures + gdk_gc_set_fill + gdk_gc_set_font + gdk_gc_set_foreground + gdk_gc_set_function + gdk_gc_set_line_attributes + gdk_gc_set_stipple + gdk_gc_set_subwindow + gdk_gc_set_tile + gdk_gc_set_ts_origin + gdk_gc_unref + gdk_get_display + gdk_get_show_events + gdk_get_use_xshm + gdk_ic_destroy + gdk_ic_get_attr + gdk_ic_get_events + gdk_ic_get_style + gdk_ic_get_values + gdk_ic_new + gdk_ic_set_attr + gdk_ic_set_values + gdk_im_begin + gdk_im_decide_style + gdk_im_end + gdk_im_ready + gdk_im_set_best_style + gdk_image_bitmap_new + gdk_image_destroy + gdk_image_get + gdk_image_get_pixel + gdk_image_new + gdk_image_new_bitmap + gdk_image_put_pixel + gdk_init + gdk_init_check + gdk_input_add + gdk_input_add_full + gdk_input_exit + gdk_input_init + gdk_input_list_devices + gdk_input_motion_events + gdk_input_remove + gdk_input_set_axes + gdk_input_set_extension_events + gdk_input_set_key + gdk_input_set_mode + gdk_input_set_source + gdk_input_window_get_pointer + gdk_key_repeat_disable + gdk_key_repeat_restore + gdk_keyboard_grab + gdk_keyboard_ungrab + gdk_keyval_from_name + gdk_keyval_is_lower + gdk_keyval_is_upper + gdk_keyval_name + gdk_keyval_to_lower + gdk_keyval_to_upper + gdk_list_visuals + gdk_mbstowcs + gdk_null_window_warnings + gdk_pixmap_colormap_create_from_xpm + gdk_pixmap_colormap_create_from_xpm_d + gdk_pixmap_create_from_data + gdk_pixmap_create_from_xpm + gdk_pixmap_create_from_xpm_d + gdk_pixmap_create_on_shared_image + gdk_pixmap_foreign_new + gdk_pixmap_new + gdk_pixmap_ref + gdk_pixmap_unref + gdk_pointer_grab + gdk_pointer_is_grabbed + gdk_pointer_ungrab + gdk_progclass + gdk_property_change + gdk_property_delete + gdk_property_get + gdk_query_depths + gdk_query_visual_types + gdk_rectangle_intersect + gdk_rectangle_union + gdk_region_destroy + gdk_region_empty + gdk_region_equal + gdk_region_get_clipbox + gdk_region_new + gdk_region_offset + gdk_region_point_in + gdk_region_polygon + gdk_region_rect_in + gdk_region_shrink + gdk_region_union_with_rect + gdk_regions_intersect + gdk_regions_subtract + gdk_regions_union + gdk_regions_xor + gdk_rgb_cmap_free + gdk_rgb_cmap_new + gdk_rgb_ditherable + gdk_rgb_gc_set_background + gdk_rgb_gc_set_foreground + gdk_rgb_get_cmap + gdk_rgb_get_visual + gdk_rgb_init + gdk_rgb_set_install + gdk_rgb_set_min_colors + gdk_rgb_set_verbose + gdk_rgb_xpixel_from_rgb + gdk_root_parent + gdk_screen_height + gdk_screen_height_mm + gdk_screen_width + gdk_screen_width_mm + gdk_selection_convert + gdk_selection_owner_get + gdk_selection_owner_set + gdk_selection_property + gdk_selection_property_get + gdk_selection_send_notify + gdk_set_locale + gdk_set_show_events + gdk_set_use_xshm + gdk_string_extents + gdk_string_height + gdk_string_measure + gdk_string_to_compound_text + gdk_string_width + gdk_text_extents + gdk_text_extents_wc + gdk_text_height + gdk_text_measure + gdk_text_property_to_text_list + gdk_text_width + gdk_text_width_wc + gdk_threads_enter + gdk_threads_leave + gdk_threads_mutex + gdk_visual_get_best + gdk_visual_get_best_depth + gdk_visual_get_best_type + gdk_visual_get_best_with_both + gdk_visual_get_best_with_depth + gdk_visual_get_best_with_type + gdk_visual_get_system + gdk_visual_ref + gdk_visual_unref + gdk_wcstombs + gdk_window_add_filter + gdk_window_at_pointer + gdk_window_clear + gdk_window_clear_area + gdk_window_clear_area_e + gdk_window_destroy + gdk_window_foreign_new + gdk_window_get_deskrelative_origin + gdk_window_get_children + gdk_window_get_events + gdk_window_get_geometry + gdk_window_get_origin + gdk_window_get_parent + gdk_window_get_pointer + gdk_window_get_position + gdk_window_get_root_origin + gdk_window_get_toplevel + gdk_window_get_toplevels + gdk_window_get_user_data + gdk_window_hide + gdk_window_is_visible + gdk_window_is_viewable + gdk_window_lower + gdk_window_merge_child_shapes + gdk_window_move + gdk_window_move_resize + gdk_window_new + gdk_window_raise + gdk_window_ref + gdk_window_register_dnd + gdk_window_remove_filter + gdk_window_reparent + gdk_window_resize + gdk_window_set_back_pixmap + gdk_window_set_background + gdk_window_set_child_shapes + gdk_window_set_cursor + gdk_window_set_decorations + gdk_window_set_events + gdk_window_set_functions + gdk_window_set_geometry_hints + gdk_window_set_group + gdk_window_set_hints + gdk_window_set_icon + gdk_window_set_icon_name + gdk_window_set_override_redirect + gdk_window_set_role + gdk_window_set_static_gravities + gdk_window_set_title + gdk_window_set_transient_for + gdk_window_set_user_data + gdk_window_shape_combine_mask + gdk_window_show + gdk_window_unref + gdk_window_withdraw + gdk_xid_table_insert + gdk_xid_table_lookup + gdk_xid_table_remove \ No newline at end of file diff --git a/gdk/win32/gdk.c b/gdk/win32/gdk.c new file mode 100644 index 000000000..e8fa5af5d --- /dev/null +++ b/gdk/win32/gdk.c @@ -0,0 +1,2115 @@ +/* GDK - The GIMP Drawing Kit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * Copyright (C) 1998-1999 Tor Lillqvist + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* + * Modified by the GTK+ Team and others 1997-1999. See the AUTHORS + * file for a list of people on the GTK+ Team. See the ChangeLog + * files for a list of changes. These files are distributed with + * GTK+ at ftp://ftp.gtk.org/pub/gtk/. + */ + +#include "config.h" + +#include +#include +#include +#include +#include + +#include "gdk.h" +#include "gdkprivate.h" +#include "gdkinputprivate.h" +#include "gdkkeysyms.h" + +#include + +static void gdkx_XConvertCase (KeySym symbol, + KeySym *lower, + KeySym *upper); +static void gdk_exit_func (void); + + +/* Private variable declarations + */ +static int gdk_initialized = 0; /* 1 if the library is initialized, + * 0 otherwise. + */ +#ifdef G_ENABLE_DEBUG +static const GDebugKey gdk_debug_keys[] = { + {"events", GDK_DEBUG_EVENTS}, + {"misc", GDK_DEBUG_MISC}, + {"dnd", GDK_DEBUG_DND}, + {"color-context", GDK_DEBUG_COLOR_CONTEXT}, + {"xim", GDK_DEBUG_XIM}, + {"selection", GDK_DEBUG_SELECTION} +}; + +static const int gdk_ndebug_keys = sizeof(gdk_debug_keys)/sizeof(GDebugKey); + +#endif /* G_ENABLE_DEBUG */ + +int __stdcall +DllMain(HINSTANCE hinstDLL, + DWORD dwReason, + LPVOID reserved) +{ + gdk_DLLInstance = hinstDLL; + + return TRUE; +} + +/* + *-------------------------------------------------------------- + * gdk_init + * + * Initialize the library for use. + * + * Arguments: + * "argc" is the number of arguments. + * "argv" is an array of strings. + * + * Results: + * "argc" and "argv" are modified to reflect any arguments + * which were not handled. (Such arguments should either + * be handled by the application or dismissed). + * + * Side effects: + * The library is initialized. + * + *-------------------------------------------------------------- + */ + +gboolean +gdk_init_check (int *argc, + char ***argv) +{ + gint i, j, k; + + if (gdk_initialized) + return TRUE; + + if (g_thread_supported ()) + gdk_threads_mutex = g_mutex_new (); + +#ifdef G_ENABLE_DEBUG + { + gchar *debug_string = getenv("GDK_DEBUG"); + if (debug_string != NULL) + gdk_debug_flags = g_parse_debug_string (debug_string, + (GDebugKey *) gdk_debug_keys, + gdk_ndebug_keys); + } +#endif /* G_ENABLE_DEBUG */ + + if (getenv ("GDK_IGNORE_WINTAB") != NULL) + gdk_input_ignore_wintab = TRUE; + + if (getenv ("GDK_EVENT_FUNC_FROM_WINDOW_PROC") != NULL) + gdk_event_func_from_window_proc = TRUE; + + if (argc && argv) + { + if (*argc > 0) + { + gchar *d; + + d = strrchr((*argv)[0], G_DIR_SEPARATOR); + if (d != NULL) + g_set_prgname (d + 1); + else + g_set_prgname ((*argv)[0]); + } + + for (i = 1; i < *argc;) + { +#ifdef G_ENABLE_DEBUG + if ((strcmp ("--gdk-debug", (*argv)[i]) == 0) || + (strncmp ("--gdk-debug=", (*argv)[i], 12) == 0)) + { + gchar *equal_pos = strchr ((*argv)[i], '='); + + if (equal_pos != NULL) + { + gdk_debug_flags |= g_parse_debug_string (equal_pos+1, + (GDebugKey *) gdk_debug_keys, + gdk_ndebug_keys); + } + else if ((i + 1) < *argc && (*argv)[i + 1]) + { + gdk_debug_flags |= g_parse_debug_string ((*argv)[i+1], + (GDebugKey *) gdk_debug_keys, + gdk_ndebug_keys); + (*argv)[i] = NULL; + i += 1; + } + (*argv)[i] = NULL; + } + else if ((strcmp ("--gdk-no-debug", (*argv)[i]) == 0) || + (strncmp ("--gdk-no-debug=", (*argv)[i], 15) == 0)) + { + gchar *equal_pos = strchr ((*argv)[i], '='); + + if (equal_pos != NULL) + { + gdk_debug_flags &= ~g_parse_debug_string (equal_pos+1, + (GDebugKey *) gdk_debug_keys, + gdk_ndebug_keys); + } + else if ((i + 1) < *argc && (*argv)[i + 1]) + { + gdk_debug_flags &= ~g_parse_debug_string ((*argv)[i+1], + (GDebugKey *) gdk_debug_keys, + gdk_ndebug_keys); + (*argv)[i] = NULL; + i += 1; + } + (*argv)[i] = NULL; + } + else +#endif /* G_ENABLE_DEBUG */ + if (strcmp ("--sync", (*argv)[i]) == 0) + { + (*argv)[i] = NULL; + GdiSetBatchLimit (1); + } + else if (strcmp ("--name", (*argv)[i]) == 0) + { + if ((i + 1) < *argc && (*argv)[i + 1]) + { + (*argv)[i++] = NULL; + g_set_prgname ((*argv)[i]); + (*argv)[i] = NULL; + } + } + else if (strcmp ("--gdk-no-wintab", (*argv)[i]) == 0 + || strcmp ("--gdk-ignore-wintab", (*argv)[i]) == 0) + { + (*argv)[i] = NULL; + gdk_input_ignore_wintab = TRUE; + } + else if (strcmp ("--gdk-event-func-from-window-proc", (*argv)[i]) == 0) + { + (*argv)[i] = NULL; + gdk_event_func_from_window_proc = TRUE; + } + i += 1; + } + + for (i = 1; i < *argc; i++) + { + for (k = i; k < *argc; k++) + if ((*argv)[k] != NULL) + break; + + if (k > i) + { + k -= i; + for (j = i + k; j < *argc; j++) + (*argv)[j-k] = (*argv)[j]; + *argc -= k; + } + } + } + else + { + g_set_prgname (""); + } + + gdk_ProgInstance = GetModuleHandle (NULL); + gdk_DC = CreateDC ("DISPLAY", NULL, NULL, NULL); + gdk_root_window = GetDesktopWindow (); + windows_version = GetVersion (); + + CoInitialize (NULL); + + gdk_selection_request_msg = RegisterWindowMessage ("gdk-selection-request"); + gdk_selection_notify_msg = RegisterWindowMessage ("gdk-selection-notify"); + gdk_selection_clear_msg = RegisterWindowMessage ("gdk-selection-clear"); + + gdk_selection_property = gdk_atom_intern ("GDK_SELECTION", FALSE); + gdk_clipboard_atom = gdk_atom_intern ("CLIPBOARD", FALSE); + gdk_win32_dropfiles_atom = gdk_atom_intern ("DROPFILES_DND", FALSE); + gdk_ole2_dnd_atom = gdk_atom_intern ("OLE2_DND", FALSE); + + gdk_progclass = g_basename (g_get_prgname ()); + gdk_progclass[0] = toupper (gdk_progclass[0]); + + g_atexit (gdk_exit_func); + + gdk_events_init (); + gdk_visual_init (); + gdk_window_init (); + gdk_image_init (); + gdk_input_init (); + gdk_selection_init (); + gdk_dnd_init (); + + gdk_initialized = 1; + + return TRUE; +} + +void +gdk_init (int *argc, char ***argv) +{ + if (!gdk_init_check (argc, argv)) + { + g_warning ("cannot initialize GDK"); + exit(1); + } +} + +/* + *-------------------------------------------------------------- + * gdk_exit + * + * Restores the library to an un-itialized state and exits + * the program using the "exit" system call. + * + * Arguments: + * "errorcode" is the error value to pass to "exit". + * + * Results: + * Allocated structures are freed and the program exits + * cleanly. + * + * Side effects: + * + *-------------------------------------------------------------- + */ + +void +gdk_exit (gint errorcode) +{ + /* de-initialisation is done by the gdk_exit_func(), + no need to do this here (Alex J.) */ + exit (errorcode); +} + +void +gdk_set_use_xshm (gint use_xshm) +{ + /* Always on */ +} + +gint +gdk_get_use_xshm (void) +{ + return TRUE; +} + +/* + *-------------------------------------------------------------- + * gdk_screen_width + * + * Return the width of the screen. + * + * Arguments: + * + * Results: + * + * Side effects: + * + *-------------------------------------------------------------- + */ + +gint +gdk_screen_width (void) +{ + gint return_val; + + return_val = gdk_root_parent->drawable.width; + + return return_val; +} + +/* + *-------------------------------------------------------------- + * gdk_screen_height + * + * Return the height of the screen. + * + * Arguments: + * + * Results: + * + * Side effects: + * + *-------------------------------------------------------------- + */ + +gint +gdk_screen_height (void) +{ + gint return_val; + + return_val = gdk_root_parent->drawable.height; + + return return_val; +} + +/* + *-------------------------------------------------------------- + * gdk_screen_width_mm + * + * Return the width of the screen in millimetres. + * + * Arguments: + * + * Results: + * + * Side effects: + * + *-------------------------------------------------------------- + */ + +gint +gdk_screen_width_mm (void) +{ + HDC hdc; + gint return_val; + + hdc = GetDC (NULL); + return_val = GetDeviceCaps (hdc, HORZSIZE); + ReleaseDC (NULL, hdc); + + return return_val; +} + +/* + *-------------------------------------------------------------- + * gdk_screen_height + * + * Return the height of the screen in millimetres. + * + * Arguments: + * + * Results: + * + * Side effects: + * + *-------------------------------------------------------------- + */ + +gint +gdk_screen_height_mm (void) +{ + HDC hdc; + gint return_val; + + hdc = GetDC (NULL); + return_val = GetDeviceCaps (hdc, VERTSIZE); + ReleaseDC (NULL, hdc); + + return return_val; +} + +void +gdk_key_repeat_disable (void) +{ + /* XXX */ +} + +void +gdk_key_repeat_restore (void) +{ + /* XXX */ +} + + +/* + *-------------------------------------------------------------- + * gdk_flush + * + * Flushes the Xlib output buffer and then waits + * until all requests have been received and processed + * by the X server. The only real use for this function + * is in dealing with XShm. + * + * Arguments: + * + * Results: + * + * Side effects: + * + *-------------------------------------------------------------- + */ + +void +gdk_flush (void) +{ + GdiFlush (); +} + +void +gdk_beep (void) +{ + Beep(1000, 50); +} + +/* + *-------------------------------------------------------------- + * gdk_exit_func + * + * This is the "atexit" function that makes sure the + * library gets a chance to cleanup. + * + * Arguments: + * + * Results: + * + * Side effects: + * The library is un-initialized and the program exits. + * + *-------------------------------------------------------------- + */ + +static void +gdk_exit_func (void) +{ + static gboolean in_gdk_exit_func = FALSE; + + GDK_NOTE (MISC, g_print ("gdk_exit_func\n")); + /* This is to avoid an infinite loop if a program segfaults in + an atexit() handler (and yes, it does happen, especially if a program + has trounced over memory too badly for even g_message to work) */ + if (in_gdk_exit_func == TRUE) + return; + in_gdk_exit_func = TRUE; + + if (gdk_initialized) + { + gdk_image_exit (); + gdk_input_exit (); + gdk_key_repeat_restore (); + gdk_dnd_exit (); + + CoUninitialize (); + + DeleteDC (gdk_DC); + gdk_DC = NULL; + gdk_initialized = 0; + } +} + +gchar * +gdk_get_display(void) +{ + return "local:"; +} + +/************************************************************* + * gdk_error_trap_push: + * Push an error trap. X errors will be trapped until + * the corresponding gdk_error_pop(), which will return + * the error code, if any. + * arguments: + * + * results: + *************************************************************/ + +void +gdk_error_trap_push (void) +{ + /* ??? */ +} + +/************************************************************* + * gdk_error_trap_pop: + * Pop an error trap added with gdk_error_push() + * arguments: + * + * results: + * 0, if no error occured, otherwise the error code. + *************************************************************/ + +gint +gdk_error_trap_pop (void) +{ + /* ??? */ + return 0; +} + +static void +gdkx_XConvertCase (KeySym symbol, + KeySym *lower, + KeySym *upper) +{ + register KeySym sym = symbol; + + g_return_if_fail (lower != NULL); + g_return_if_fail (upper != NULL); + + *lower = sym; + *upper = sym; + + switch (sym >> 8) + { +#if defined (GDK_A) && defined (GDK_Ooblique) + case 0: /* Latin 1 */ + if ((sym >= GDK_A) && (sym <= GDK_Z)) + *lower += (GDK_a - GDK_A); + else if ((sym >= GDK_a) && (sym <= GDK_z)) + *upper -= (GDK_a - GDK_A); + else if ((sym >= GDK_Agrave) && (sym <= GDK_Odiaeresis)) + *lower += (GDK_agrave - GDK_Agrave); + else if ((sym >= GDK_agrave) && (sym <= GDK_odiaeresis)) + *upper -= (GDK_agrave - GDK_Agrave); + else if ((sym >= GDK_Ooblique) && (sym <= GDK_Thorn)) + *lower += (GDK_oslash - GDK_Ooblique); + else if ((sym >= GDK_oslash) && (sym <= GDK_thorn)) + *upper -= (GDK_oslash - GDK_Ooblique); + break; +#endif /* LATIN1 */ + +#if defined (GDK_Aogonek) && defined (GDK_tcedilla) + case 1: /* Latin 2 */ + /* Assume the KeySym is a legal value (ignore discontinuities) */ + if (sym == GDK_Aogonek) + *lower = GDK_aogonek; + else if (sym >= GDK_Lstroke && sym <= GDK_Sacute) + *lower += (GDK_lstroke - GDK_Lstroke); + else if (sym >= GDK_Scaron && sym <= GDK_Zacute) + *lower += (GDK_scaron - GDK_Scaron); + else if (sym >= GDK_Zcaron && sym <= GDK_Zabovedot) + *lower += (GDK_zcaron - GDK_Zcaron); + else if (sym == GDK_aogonek) + *upper = GDK_Aogonek; + else if (sym >= GDK_lstroke && sym <= GDK_sacute) + *upper -= (GDK_lstroke - GDK_Lstroke); + else if (sym >= GDK_scaron && sym <= GDK_zacute) + *upper -= (GDK_scaron - GDK_Scaron); + else if (sym >= GDK_zcaron && sym <= GDK_zabovedot) + *upper -= (GDK_zcaron - GDK_Zcaron); + else if (sym >= GDK_Racute && sym <= GDK_Tcedilla) + *lower += (GDK_racute - GDK_Racute); + else if (sym >= GDK_racute && sym <= GDK_tcedilla) + *upper -= (GDK_racute - GDK_Racute); + break; +#endif /* LATIN2 */ + +#if defined (GDK_Hstroke) && defined (GDK_Cabovedot) + case 2: /* Latin 3 */ + /* Assume the KeySym is a legal value (ignore discontinuities) */ + if (sym >= GDK_Hstroke && sym <= GDK_Hcircumflex) + *lower += (GDK_hstroke - GDK_Hstroke); + else if (sym >= GDK_Gbreve && sym <= GDK_Jcircumflex) + *lower += (GDK_gbreve - GDK_Gbreve); + else if (sym >= GDK_hstroke && sym <= GDK_hcircumflex) + *upper -= (GDK_hstroke - GDK_Hstroke); + else if (sym >= GDK_gbreve && sym <= GDK_jcircumflex) + *upper -= (GDK_gbreve - GDK_Gbreve); + else if (sym >= GDK_Cabovedot && sym <= GDK_Scircumflex) + *lower += (GDK_cabovedot - GDK_Cabovedot); + else if (sym >= GDK_cabovedot && sym <= GDK_scircumflex) + *upper -= (GDK_cabovedot - GDK_Cabovedot); + break; +#endif /* LATIN3 */ + +#if defined (GDK_Rcedilla) && defined (GDK_Amacron) + case 3: /* Latin 4 */ + /* Assume the KeySym is a legal value (ignore discontinuities) */ + if (sym >= GDK_Rcedilla && sym <= GDK_Tslash) + *lower += (GDK_rcedilla - GDK_Rcedilla); + else if (sym >= GDK_rcedilla && sym <= GDK_tslash) + *upper -= (GDK_rcedilla - GDK_Rcedilla); + else if (sym == GDK_ENG) + *lower = GDK_eng; + else if (sym == GDK_eng) + *upper = GDK_ENG; + else if (sym >= GDK_Amacron && sym <= GDK_Umacron) + *lower += (GDK_amacron - GDK_Amacron); + else if (sym >= GDK_amacron && sym <= GDK_umacron) + *upper -= (GDK_amacron - GDK_Amacron); + break; +#endif /* LATIN4 */ + +#if defined (GDK_Serbian_DJE) && defined (GDK_Cyrillic_yu) + case 6: /* Cyrillic */ + /* Assume the KeySym is a legal value (ignore discontinuities) */ + if (sym >= GDK_Serbian_DJE && sym <= GDK_Serbian_DZE) + *lower -= (GDK_Serbian_DJE - GDK_Serbian_dje); + else if (sym >= GDK_Serbian_dje && sym <= GDK_Serbian_dze) + *upper += (GDK_Serbian_DJE - GDK_Serbian_dje); + else if (sym >= GDK_Cyrillic_YU && sym <= GDK_Cyrillic_HARDSIGN) + *lower -= (GDK_Cyrillic_YU - GDK_Cyrillic_yu); + else if (sym >= GDK_Cyrillic_yu && sym <= GDK_Cyrillic_hardsign) + *upper += (GDK_Cyrillic_YU - GDK_Cyrillic_yu); + break; +#endif /* CYRILLIC */ + +#if defined (GDK_Greek_ALPHAaccent) && defined (GDK_Greek_finalsmallsigma) + case 7: /* Greek */ + /* Assume the KeySym is a legal value (ignore discontinuities) */ + if (sym >= GDK_Greek_ALPHAaccent && sym <= GDK_Greek_OMEGAaccent) + *lower += (GDK_Greek_alphaaccent - GDK_Greek_ALPHAaccent); + else if (sym >= GDK_Greek_alphaaccent && sym <= GDK_Greek_omegaaccent && + sym != GDK_Greek_iotaaccentdieresis && + sym != GDK_Greek_upsilonaccentdieresis) + *upper -= (GDK_Greek_alphaaccent - GDK_Greek_ALPHAaccent); + else if (sym >= GDK_Greek_ALPHA && sym <= GDK_Greek_OMEGA) + *lower += (GDK_Greek_alpha - GDK_Greek_ALPHA); + else if (sym >= GDK_Greek_alpha && sym <= GDK_Greek_omega && + sym != GDK_Greek_finalsmallsigma) + *upper -= (GDK_Greek_alpha - GDK_Greek_ALPHA); + break; +#endif /* GREEK */ + } +} + +static struct gdk_key { + guint keyval; + const char *name; +} gdk_keys_by_keyval[] = { + { 0x000020, "space" }, + { 0x000021, "exclam" }, + { 0x000022, "quotedbl" }, + { 0x000023, "numbersign" }, + { 0x000024, "dollar" }, + { 0x000025, "percent" }, + { 0x000026, "ampersand" }, + { 0x000027, "apostrophe" }, + { 0x000027, "quoteright" }, + { 0x000028, "parenleft" }, + { 0x000029, "parenright" }, + { 0x00002a, "asterisk" }, + { 0x00002b, "plus" }, + { 0x00002c, "comma" }, + { 0x00002d, "minus" }, + { 0x00002e, "period" }, + { 0x00002f, "slash" }, + { 0x000030, "0" }, + { 0x000031, "1" }, + { 0x000032, "2" }, + { 0x000033, "3" }, + { 0x000034, "4" }, + { 0x000035, "5" }, + { 0x000036, "6" }, + { 0x000037, "7" }, + { 0x000038, "8" }, + { 0x000039, "9" }, + { 0x00003a, "colon" }, + { 0x00003b, "semicolon" }, + { 0x00003c, "less" }, + { 0x00003d, "equal" }, + { 0x00003e, "greater" }, + { 0x00003f, "question" }, + { 0x000040, "at" }, + { 0x000041, "A" }, + { 0x000042, "B" }, + { 0x000043, "C" }, + { 0x000044, "D" }, + { 0x000045, "E" }, + { 0x000046, "F" }, + { 0x000047, "G" }, + { 0x000048, "H" }, + { 0x000049, "I" }, + { 0x00004a, "J" }, + { 0x00004b, "K" }, + { 0x00004c, "L" }, + { 0x00004d, "M" }, + { 0x00004e, "N" }, + { 0x00004f, "O" }, + { 0x000050, "P" }, + { 0x000051, "Q" }, + { 0x000052, "R" }, + { 0x000053, "S" }, + { 0x000054, "T" }, + { 0x000055, "U" }, + { 0x000056, "V" }, + { 0x000057, "W" }, + { 0x000058, "X" }, + { 0x000059, "Y" }, + { 0x00005a, "Z" }, + { 0x00005b, "bracketleft" }, + { 0x00005c, "backslash" }, + { 0x00005d, "bracketright" }, + { 0x00005e, "asciicircum" }, + { 0x00005f, "underscore" }, + { 0x000060, "grave" }, + { 0x000060, "quoteleft" }, + { 0x000061, "a" }, + { 0x000062, "b" }, + { 0x000063, "c" }, + { 0x000064, "d" }, + { 0x000065, "e" }, + { 0x000066, "f" }, + { 0x000067, "g" }, + { 0x000068, "h" }, + { 0x000069, "i" }, + { 0x00006a, "j" }, + { 0x00006b, "k" }, + { 0x00006c, "l" }, + { 0x00006d, "m" }, + { 0x00006e, "n" }, + { 0x00006f, "o" }, + { 0x000070, "p" }, + { 0x000071, "q" }, + { 0x000072, "r" }, + { 0x000073, "s" }, + { 0x000074, "t" }, + { 0x000075, "u" }, + { 0x000076, "v" }, + { 0x000077, "w" }, + { 0x000078, "x" }, + { 0x000079, "y" }, + { 0x00007a, "z" }, + { 0x00007b, "braceleft" }, + { 0x00007c, "bar" }, + { 0x00007d, "braceright" }, + { 0x00007e, "asciitilde" }, + { 0x0000a0, "nobreakspace" }, + { 0x0000a1, "exclamdown" }, + { 0x0000a2, "cent" }, + { 0x0000a3, "sterling" }, + { 0x0000a4, "currency" }, + { 0x0000a5, "yen" }, + { 0x0000a6, "brokenbar" }, + { 0x0000a7, "section" }, + { 0x0000a8, "diaeresis" }, + { 0x0000a9, "copyright" }, + { 0x0000aa, "ordfeminine" }, + { 0x0000ab, "guillemotleft" }, + { 0x0000ac, "notsign" }, + { 0x0000ad, "hyphen" }, + { 0x0000ae, "registered" }, + { 0x0000af, "macron" }, + { 0x0000b0, "degree" }, + { 0x0000b1, "plusminus" }, + { 0x0000b2, "twosuperior" }, + { 0x0000b3, "threesuperior" }, + { 0x0000b4, "acute" }, + { 0x0000b5, "mu" }, + { 0x0000b6, "paragraph" }, + { 0x0000b7, "periodcentered" }, + { 0x0000b8, "cedilla" }, + { 0x0000b9, "onesuperior" }, + { 0x0000ba, "masculine" }, + { 0x0000bb, "guillemotright" }, + { 0x0000bc, "onequarter" }, + { 0x0000bd, "onehalf" }, + { 0x0000be, "threequarters" }, + { 0x0000bf, "questiondown" }, + { 0x0000c0, "Agrave" }, + { 0x0000c1, "Aacute" }, + { 0x0000c2, "Acircumflex" }, + { 0x0000c3, "Atilde" }, + { 0x0000c4, "Adiaeresis" }, + { 0x0000c5, "Aring" }, + { 0x0000c6, "AE" }, + { 0x0000c7, "Ccedilla" }, + { 0x0000c8, "Egrave" }, + { 0x0000c9, "Eacute" }, + { 0x0000ca, "Ecircumflex" }, + { 0x0000cb, "Ediaeresis" }, + { 0x0000cc, "Igrave" }, + { 0x0000cd, "Iacute" }, + { 0x0000ce, "Icircumflex" }, + { 0x0000cf, "Idiaeresis" }, + { 0x0000d0, "ETH" }, + { 0x0000d0, "Eth" }, + { 0x0000d1, "Ntilde" }, + { 0x0000d2, "Ograve" }, + { 0x0000d3, "Oacute" }, + { 0x0000d4, "Ocircumflex" }, + { 0x0000d5, "Otilde" }, + { 0x0000d6, "Odiaeresis" }, + { 0x0000d7, "multiply" }, + { 0x0000d8, "Ooblique" }, + { 0x0000d9, "Ugrave" }, + { 0x0000da, "Uacute" }, + { 0x0000db, "Ucircumflex" }, + { 0x0000dc, "Udiaeresis" }, + { 0x0000dd, "Yacute" }, + { 0x0000de, "THORN" }, + { 0x0000de, "Thorn" }, + { 0x0000df, "ssharp" }, + { 0x0000e0, "agrave" }, + { 0x0000e1, "aacute" }, + { 0x0000e2, "acircumflex" }, + { 0x0000e3, "atilde" }, + { 0x0000e4, "adiaeresis" }, + { 0x0000e5, "aring" }, + { 0x0000e6, "ae" }, + { 0x0000e7, "ccedilla" }, + { 0x0000e8, "egrave" }, + { 0x0000e9, "eacute" }, + { 0x0000ea, "ecircumflex" }, + { 0x0000eb, "ediaeresis" }, + { 0x0000ec, "igrave" }, + { 0x0000ed, "iacute" }, + { 0x0000ee, "icircumflex" }, + { 0x0000ef, "idiaeresis" }, + { 0x0000f0, "eth" }, + { 0x0000f1, "ntilde" }, + { 0x0000f2, "ograve" }, + { 0x0000f3, "oacute" }, + { 0x0000f4, "ocircumflex" }, + { 0x0000f5, "otilde" }, + { 0x0000f6, "odiaeresis" }, + { 0x0000f7, "division" }, + { 0x0000f8, "oslash" }, + { 0x0000f9, "ugrave" }, + { 0x0000fa, "uacute" }, + { 0x0000fb, "ucircumflex" }, + { 0x0000fc, "udiaeresis" }, + { 0x0000fd, "yacute" }, + { 0x0000fe, "thorn" }, + { 0x0000ff, "ydiaeresis" }, + { 0x0001a1, "Aogonek" }, + { 0x0001a2, "breve" }, + { 0x0001a3, "Lstroke" }, + { 0x0001a5, "Lcaron" }, + { 0x0001a6, "Sacute" }, + { 0x0001a9, "Scaron" }, + { 0x0001aa, "Scedilla" }, + { 0x0001ab, "Tcaron" }, + { 0x0001ac, "Zacute" }, + { 0x0001ae, "Zcaron" }, + { 0x0001af, "Zabovedot" }, + { 0x0001b1, "aogonek" }, + { 0x0001b2, "ogonek" }, + { 0x0001b3, "lstroke" }, + { 0x0001b5, "lcaron" }, + { 0x0001b6, "sacute" }, + { 0x0001b7, "caron" }, + { 0x0001b9, "scaron" }, + { 0x0001ba, "scedilla" }, + { 0x0001bb, "tcaron" }, + { 0x0001bc, "zacute" }, + { 0x0001bd, "doubleacute" }, + { 0x0001be, "zcaron" }, + { 0x0001bf, "zabovedot" }, + { 0x0001c0, "Racute" }, + { 0x0001c3, "Abreve" }, + { 0x0001c5, "Lacute" }, + { 0x0001c6, "Cacute" }, + { 0x0001c8, "Ccaron" }, + { 0x0001ca, "Eogonek" }, + { 0x0001cc, "Ecaron" }, + { 0x0001cf, "Dcaron" }, + { 0x0001d0, "Dstroke" }, + { 0x0001d1, "Nacute" }, + { 0x0001d2, "Ncaron" }, + { 0x0001d5, "Odoubleacute" }, + { 0x0001d8, "Rcaron" }, + { 0x0001d9, "Uring" }, + { 0x0001db, "Udoubleacute" }, + { 0x0001de, "Tcedilla" }, + { 0x0001e0, "racute" }, + { 0x0001e3, "abreve" }, + { 0x0001e5, "lacute" }, + { 0x0001e6, "cacute" }, + { 0x0001e8, "ccaron" }, + { 0x0001ea, "eogonek" }, + { 0x0001ec, "ecaron" }, + { 0x0001ef, "dcaron" }, + { 0x0001f0, "dstroke" }, + { 0x0001f1, "nacute" }, + { 0x0001f2, "ncaron" }, + { 0x0001f5, "odoubleacute" }, + { 0x0001f8, "rcaron" }, + { 0x0001f9, "uring" }, + { 0x0001fb, "udoubleacute" }, + { 0x0001fe, "tcedilla" }, + { 0x0001ff, "abovedot" }, + { 0x0002a1, "Hstroke" }, + { 0x0002a6, "Hcircumflex" }, + { 0x0002a9, "Iabovedot" }, + { 0x0002ab, "Gbreve" }, + { 0x0002ac, "Jcircumflex" }, + { 0x0002b1, "hstroke" }, + { 0x0002b6, "hcircumflex" }, + { 0x0002b9, "idotless" }, + { 0x0002bb, "gbreve" }, + { 0x0002bc, "jcircumflex" }, + { 0x0002c5, "Cabovedot" }, + { 0x0002c6, "Ccircumflex" }, + { 0x0002d5, "Gabovedot" }, + { 0x0002d8, "Gcircumflex" }, + { 0x0002dd, "Ubreve" }, + { 0x0002de, "Scircumflex" }, + { 0x0002e5, "cabovedot" }, + { 0x0002e6, "ccircumflex" }, + { 0x0002f5, "gabovedot" }, + { 0x0002f8, "gcircumflex" }, + { 0x0002fd, "ubreve" }, + { 0x0002fe, "scircumflex" }, + { 0x0003a2, "kappa" }, + { 0x0003a2, "kra" }, + { 0x0003a3, "Rcedilla" }, + { 0x0003a5, "Itilde" }, + { 0x0003a6, "Lcedilla" }, + { 0x0003aa, "Emacron" }, + { 0x0003ab, "Gcedilla" }, + { 0x0003ac, "Tslash" }, + { 0x0003b3, "rcedilla" }, + { 0x0003b5, "itilde" }, + { 0x0003b6, "lcedilla" }, + { 0x0003ba, "emacron" }, + { 0x0003bb, "gcedilla" }, + { 0x0003bc, "tslash" }, + { 0x0003bd, "ENG" }, + { 0x0003bf, "eng" }, + { 0x0003c0, "Amacron" }, + { 0x0003c7, "Iogonek" }, + { 0x0003cc, "Eabovedot" }, + { 0x0003cf, "Imacron" }, + { 0x0003d1, "Ncedilla" }, + { 0x0003d2, "Omacron" }, + { 0x0003d3, "Kcedilla" }, + { 0x0003d9, "Uogonek" }, + { 0x0003dd, "Utilde" }, + { 0x0003de, "Umacron" }, + { 0x0003e0, "amacron" }, + { 0x0003e7, "iogonek" }, + { 0x0003ec, "eabovedot" }, + { 0x0003ef, "imacron" }, + { 0x0003f1, "ncedilla" }, + { 0x0003f2, "omacron" }, + { 0x0003f3, "kcedilla" }, + { 0x0003f9, "uogonek" }, + { 0x0003fd, "utilde" }, + { 0x0003fe, "umacron" }, + { 0x00047e, "overline" }, + { 0x0004a1, "kana_fullstop" }, + { 0x0004a2, "kana_openingbracket" }, + { 0x0004a3, "kana_closingbracket" }, + { 0x0004a4, "kana_comma" }, + { 0x0004a5, "kana_conjunctive" }, + { 0x0004a5, "kana_middledot" }, + { 0x0004a6, "kana_WO" }, + { 0x0004a7, "kana_a" }, + { 0x0004a8, "kana_i" }, + { 0x0004a9, "kana_u" }, + { 0x0004aa, "kana_e" }, + { 0x0004ab, "kana_o" }, + { 0x0004ac, "kana_ya" }, + { 0x0004ad, "kana_yu" }, + { 0x0004ae, "kana_yo" }, + { 0x0004af, "kana_tsu" }, + { 0x0004af, "kana_tu" }, + { 0x0004b0, "prolongedsound" }, + { 0x0004b1, "kana_A" }, + { 0x0004b2, "kana_I" }, + { 0x0004b3, "kana_U" }, + { 0x0004b4, "kana_E" }, + { 0x0004b5, "kana_O" }, + { 0x0004b6, "kana_KA" }, + { 0x0004b7, "kana_KI" }, + { 0x0004b8, "kana_KU" }, + { 0x0004b9, "kana_KE" }, + { 0x0004ba, "kana_KO" }, + { 0x0004bb, "kana_SA" }, + { 0x0004bc, "kana_SHI" }, + { 0x0004bd, "kana_SU" }, + { 0x0004be, "kana_SE" }, + { 0x0004bf, "kana_SO" }, + { 0x0004c0, "kana_TA" }, + { 0x0004c1, "kana_CHI" }, + { 0x0004c1, "kana_TI" }, + { 0x0004c2, "kana_TSU" }, + { 0x0004c2, "kana_TU" }, + { 0x0004c3, "kana_TE" }, + { 0x0004c4, "kana_TO" }, + { 0x0004c5, "kana_NA" }, + { 0x0004c6, "kana_NI" }, + { 0x0004c7, "kana_NU" }, + { 0x0004c8, "kana_NE" }, + { 0x0004c9, "kana_NO" }, + { 0x0004ca, "kana_HA" }, + { 0x0004cb, "kana_HI" }, + { 0x0004cc, "kana_FU" }, + { 0x0004cc, "kana_HU" }, + { 0x0004cd, "kana_HE" }, + { 0x0004ce, "kana_HO" }, + { 0x0004cf, "kana_MA" }, + { 0x0004d0, "kana_MI" }, + { 0x0004d1, "kana_MU" }, + { 0x0004d2, "kana_ME" }, + { 0x0004d3, "kana_MO" }, + { 0x0004d4, "kana_YA" }, + { 0x0004d5, "kana_YU" }, + { 0x0004d6, "kana_YO" }, + { 0x0004d7, "kana_RA" }, + { 0x0004d8, "kana_RI" }, + { 0x0004d9, "kana_RU" }, + { 0x0004da, "kana_RE" }, + { 0x0004db, "kana_RO" }, + { 0x0004dc, "kana_WA" }, + { 0x0004dd, "kana_N" }, + { 0x0004de, "voicedsound" }, + { 0x0004df, "semivoicedsound" }, + { 0x0005ac, "Arabic_comma" }, + { 0x0005bb, "Arabic_semicolon" }, + { 0x0005bf, "Arabic_question_mark" }, + { 0x0005c1, "Arabic_hamza" }, + { 0x0005c2, "Arabic_maddaonalef" }, + { 0x0005c3, "Arabic_hamzaonalef" }, + { 0x0005c4, "Arabic_hamzaonwaw" }, + { 0x0005c5, "Arabic_hamzaunderalef" }, + { 0x0005c6, "Arabic_hamzaonyeh" }, + { 0x0005c7, "Arabic_alef" }, + { 0x0005c8, "Arabic_beh" }, + { 0x0005c9, "Arabic_tehmarbuta" }, + { 0x0005ca, "Arabic_teh" }, + { 0x0005cb, "Arabic_theh" }, + { 0x0005cc, "Arabic_jeem" }, + { 0x0005cd, "Arabic_hah" }, + { 0x0005ce, "Arabic_khah" }, + { 0x0005cf, "Arabic_dal" }, + { 0x0005d0, "Arabic_thal" }, + { 0x0005d1, "Arabic_ra" }, + { 0x0005d2, "Arabic_zain" }, + { 0x0005d3, "Arabic_seen" }, + { 0x0005d4, "Arabic_sheen" }, + { 0x0005d5, "Arabic_sad" }, + { 0x0005d6, "Arabic_dad" }, + { 0x0005d7, "Arabic_tah" }, + { 0x0005d8, "Arabic_zah" }, + { 0x0005d9, "Arabic_ain" }, + { 0x0005da, "Arabic_ghain" }, + { 0x0005e0, "Arabic_tatweel" }, + { 0x0005e1, "Arabic_feh" }, + { 0x0005e2, "Arabic_qaf" }, + { 0x0005e3, "Arabic_kaf" }, + { 0x0005e4, "Arabic_lam" }, + { 0x0005e5, "Arabic_meem" }, + { 0x0005e6, "Arabic_noon" }, + { 0x0005e7, "Arabic_ha" }, + { 0x0005e7, "Arabic_heh" }, + { 0x0005e8, "Arabic_waw" }, + { 0x0005e9, "Arabic_alefmaksura" }, + { 0x0005ea, "Arabic_yeh" }, + { 0x0005eb, "Arabic_fathatan" }, + { 0x0005ec, "Arabic_dammatan" }, + { 0x0005ed, "Arabic_kasratan" }, + { 0x0005ee, "Arabic_fatha" }, + { 0x0005ef, "Arabic_damma" }, + { 0x0005f0, "Arabic_kasra" }, + { 0x0005f1, "Arabic_shadda" }, + { 0x0005f2, "Arabic_sukun" }, + { 0x0006a1, "Serbian_dje" }, + { 0x0006a2, "Macedonia_gje" }, + { 0x0006a3, "Cyrillic_io" }, + { 0x0006a4, "Ukrainian_ie" }, + { 0x0006a4, "Ukranian_je" }, + { 0x0006a5, "Macedonia_dse" }, + { 0x0006a6, "Ukrainian_i" }, + { 0x0006a6, "Ukranian_i" }, + { 0x0006a7, "Ukrainian_yi" }, + { 0x0006a7, "Ukranian_yi" }, + { 0x0006a8, "Cyrillic_je" }, + { 0x0006a8, "Serbian_je" }, + { 0x0006a9, "Cyrillic_lje" }, + { 0x0006a9, "Serbian_lje" }, + { 0x0006aa, "Cyrillic_nje" }, + { 0x0006aa, "Serbian_nje" }, + { 0x0006ab, "Serbian_tshe" }, + { 0x0006ac, "Macedonia_kje" }, + { 0x0006ae, "Byelorussian_shortu" }, + { 0x0006af, "Cyrillic_dzhe" }, + { 0x0006af, "Serbian_dze" }, + { 0x0006b0, "numerosign" }, + { 0x0006b1, "Serbian_DJE" }, + { 0x0006b2, "Macedonia_GJE" }, + { 0x0006b3, "Cyrillic_IO" }, + { 0x0006b4, "Ukrainian_IE" }, + { 0x0006b4, "Ukranian_JE" }, + { 0x0006b5, "Macedonia_DSE" }, + { 0x0006b6, "Ukrainian_I" }, + { 0x0006b6, "Ukranian_I" }, + { 0x0006b7, "Ukrainian_YI" }, + { 0x0006b7, "Ukranian_YI" }, + { 0x0006b8, "Cyrillic_JE" }, + { 0x0006b8, "Serbian_JE" }, + { 0x0006b9, "Cyrillic_LJE" }, + { 0x0006b9, "Serbian_LJE" }, + { 0x0006ba, "Cyrillic_NJE" }, + { 0x0006ba, "Serbian_NJE" }, + { 0x0006bb, "Serbian_TSHE" }, + { 0x0006bc, "Macedonia_KJE" }, + { 0x0006be, "Byelorussian_SHORTU" }, + { 0x0006bf, "Cyrillic_DZHE" }, + { 0x0006bf, "Serbian_DZE" }, + { 0x0006c0, "Cyrillic_yu" }, + { 0x0006c1, "Cyrillic_a" }, + { 0x0006c2, "Cyrillic_be" }, + { 0x0006c3, "Cyrillic_tse" }, + { 0x0006c4, "Cyrillic_de" }, + { 0x0006c5, "Cyrillic_ie" }, + { 0x0006c6, "Cyrillic_ef" }, + { 0x0006c7, "Cyrillic_ghe" }, + { 0x0006c8, "Cyrillic_ha" }, + { 0x0006c9, "Cyrillic_i" }, + { 0x0006ca, "Cyrillic_shorti" }, + { 0x0006cb, "Cyrillic_ka" }, + { 0x0006cc, "Cyrillic_el" }, + { 0x0006cd, "Cyrillic_em" }, + { 0x0006ce, "Cyrillic_en" }, + { 0x0006cf, "Cyrillic_o" }, + { 0x0006d0, "Cyrillic_pe" }, + { 0x0006d1, "Cyrillic_ya" }, + { 0x0006d2, "Cyrillic_er" }, + { 0x0006d3, "Cyrillic_es" }, + { 0x0006d4, "Cyrillic_te" }, + { 0x0006d5, "Cyrillic_u" }, + { 0x0006d6, "Cyrillic_zhe" }, + { 0x0006d7, "Cyrillic_ve" }, + { 0x0006d8, "Cyrillic_softsign" }, + { 0x0006d9, "Cyrillic_yeru" }, + { 0x0006da, "Cyrillic_ze" }, + { 0x0006db, "Cyrillic_sha" }, + { 0x0006dc, "Cyrillic_e" }, + { 0x0006dd, "Cyrillic_shcha" }, + { 0x0006de, "Cyrillic_che" }, + { 0x0006df, "Cyrillic_hardsign" }, + { 0x0006e0, "Cyrillic_YU" }, + { 0x0006e1, "Cyrillic_A" }, + { 0x0006e2, "Cyrillic_BE" }, + { 0x0006e3, "Cyrillic_TSE" }, + { 0x0006e4, "Cyrillic_DE" }, + { 0x0006e5, "Cyrillic_IE" }, + { 0x0006e6, "Cyrillic_EF" }, + { 0x0006e7, "Cyrillic_GHE" }, + { 0x0006e8, "Cyrillic_HA" }, + { 0x0006e9, "Cyrillic_I" }, + { 0x0006ea, "Cyrillic_SHORTI" }, + { 0x0006eb, "Cyrillic_KA" }, + { 0x0006ec, "Cyrillic_EL" }, + { 0x0006ed, "Cyrillic_EM" }, + { 0x0006ee, "Cyrillic_EN" }, + { 0x0006ef, "Cyrillic_O" }, + { 0x0006f0, "Cyrillic_PE" }, + { 0x0006f1, "Cyrillic_YA" }, + { 0x0006f2, "Cyrillic_ER" }, + { 0x0006f3, "Cyrillic_ES" }, + { 0x0006f4, "Cyrillic_TE" }, + { 0x0006f5, "Cyrillic_U" }, + { 0x0006f6, "Cyrillic_ZHE" }, + { 0x0006f7, "Cyrillic_VE" }, + { 0x0006f8, "Cyrillic_SOFTSIGN" }, + { 0x0006f9, "Cyrillic_YERU" }, + { 0x0006fa, "Cyrillic_ZE" }, + { 0x0006fb, "Cyrillic_SHA" }, + { 0x0006fc, "Cyrillic_E" }, + { 0x0006fd, "Cyrillic_SHCHA" }, + { 0x0006fe, "Cyrillic_CHE" }, + { 0x0006ff, "Cyrillic_HARDSIGN" }, + { 0x0007a1, "Greek_ALPHAaccent" }, + { 0x0007a2, "Greek_EPSILONaccent" }, + { 0x0007a3, "Greek_ETAaccent" }, + { 0x0007a4, "Greek_IOTAaccent" }, + { 0x0007a5, "Greek_IOTAdiaeresis" }, + { 0x0007a7, "Greek_OMICRONaccent" }, + { 0x0007a8, "Greek_UPSILONaccent" }, + { 0x0007a9, "Greek_UPSILONdieresis" }, + { 0x0007ab, "Greek_OMEGAaccent" }, + { 0x0007ae, "Greek_accentdieresis" }, + { 0x0007af, "Greek_horizbar" }, + { 0x0007b1, "Greek_alphaaccent" }, + { 0x0007b2, "Greek_epsilonaccent" }, + { 0x0007b3, "Greek_etaaccent" }, + { 0x0007b4, "Greek_iotaaccent" }, + { 0x0007b5, "Greek_iotadieresis" }, + { 0x0007b6, "Greek_iotaaccentdieresis" }, + { 0x0007b7, "Greek_omicronaccent" }, + { 0x0007b8, "Greek_upsilonaccent" }, + { 0x0007b9, "Greek_upsilondieresis" }, + { 0x0007ba, "Greek_upsilonaccentdieresis" }, + { 0x0007bb, "Greek_omegaaccent" }, + { 0x0007c1, "Greek_ALPHA" }, + { 0x0007c2, "Greek_BETA" }, + { 0x0007c3, "Greek_GAMMA" }, + { 0x0007c4, "Greek_DELTA" }, + { 0x0007c5, "Greek_EPSILON" }, + { 0x0007c6, "Greek_ZETA" }, + { 0x0007c7, "Greek_ETA" }, + { 0x0007c8, "Greek_THETA" }, + { 0x0007c9, "Greek_IOTA" }, + { 0x0007ca, "Greek_KAPPA" }, + { 0x0007cb, "Greek_LAMBDA" }, + { 0x0007cb, "Greek_LAMDA" }, + { 0x0007cc, "Greek_MU" }, + { 0x0007cd, "Greek_NU" }, + { 0x0007ce, "Greek_XI" }, + { 0x0007cf, "Greek_OMICRON" }, + { 0x0007d0, "Greek_PI" }, + { 0x0007d1, "Greek_RHO" }, + { 0x0007d2, "Greek_SIGMA" }, + { 0x0007d4, "Greek_TAU" }, + { 0x0007d5, "Greek_UPSILON" }, + { 0x0007d6, "Greek_PHI" }, + { 0x0007d7, "Greek_CHI" }, + { 0x0007d8, "Greek_PSI" }, + { 0x0007d9, "Greek_OMEGA" }, + { 0x0007e1, "Greek_alpha" }, + { 0x0007e2, "Greek_beta" }, + { 0x0007e3, "Greek_gamma" }, + { 0x0007e4, "Greek_delta" }, + { 0x0007e5, "Greek_epsilon" }, + { 0x0007e6, "Greek_zeta" }, + { 0x0007e7, "Greek_eta" }, + { 0x0007e8, "Greek_theta" }, + { 0x0007e9, "Greek_iota" }, + { 0x0007ea, "Greek_kappa" }, + { 0x0007eb, "Greek_lambda" }, + { 0x0007eb, "Greek_lamda" }, + { 0x0007ec, "Greek_mu" }, + { 0x0007ed, "Greek_nu" }, + { 0x0007ee, "Greek_xi" }, + { 0x0007ef, "Greek_omicron" }, + { 0x0007f0, "Greek_pi" }, + { 0x0007f1, "Greek_rho" }, + { 0x0007f2, "Greek_sigma" }, + { 0x0007f3, "Greek_finalsmallsigma" }, + { 0x0007f4, "Greek_tau" }, + { 0x0007f5, "Greek_upsilon" }, + { 0x0007f6, "Greek_phi" }, + { 0x0007f7, "Greek_chi" }, + { 0x0007f8, "Greek_psi" }, + { 0x0007f9, "Greek_omega" }, + { 0x0008a1, "leftradical" }, + { 0x0008a2, "topleftradical" }, + { 0x0008a3, "horizconnector" }, + { 0x0008a4, "topintegral" }, + { 0x0008a5, "botintegral" }, + { 0x0008a6, "vertconnector" }, + { 0x0008a7, "topleftsqbracket" }, + { 0x0008a8, "botleftsqbracket" }, + { 0x0008a9, "toprightsqbracket" }, + { 0x0008aa, "botrightsqbracket" }, + { 0x0008ab, "topleftparens" }, + { 0x0008ac, "botleftparens" }, + { 0x0008ad, "toprightparens" }, + { 0x0008ae, "botrightparens" }, + { 0x0008af, "leftmiddlecurlybrace" }, + { 0x0008b0, "rightmiddlecurlybrace" }, + { 0x0008b1, "topleftsummation" }, + { 0x0008b2, "botleftsummation" }, + { 0x0008b3, "topvertsummationconnector" }, + { 0x0008b4, "botvertsummationconnector" }, + { 0x0008b5, "toprightsummation" }, + { 0x0008b6, "botrightsummation" }, + { 0x0008b7, "rightmiddlesummation" }, + { 0x0008bc, "lessthanequal" }, + { 0x0008bd, "notequal" }, + { 0x0008be, "greaterthanequal" }, + { 0x0008bf, "integral" }, + { 0x0008c0, "therefore" }, + { 0x0008c1, "variation" }, + { 0x0008c2, "infinity" }, + { 0x0008c5, "nabla" }, + { 0x0008c8, "approximate" }, + { 0x0008c9, "similarequal" }, + { 0x0008cd, "ifonlyif" }, + { 0x0008ce, "implies" }, + { 0x0008cf, "identical" }, + { 0x0008d6, "radical" }, + { 0x0008da, "includedin" }, + { 0x0008db, "includes" }, + { 0x0008dc, "intersection" }, + { 0x0008dd, "union" }, + { 0x0008de, "logicaland" }, + { 0x0008df, "logicalor" }, + { 0x0008ef, "partialderivative" }, + { 0x0008f6, "function" }, + { 0x0008fb, "leftarrow" }, + { 0x0008fc, "uparrow" }, + { 0x0008fd, "rightarrow" }, + { 0x0008fe, "downarrow" }, + { 0x0009df, "blank" }, + { 0x0009e0, "soliddiamond" }, + { 0x0009e1, "checkerboard" }, + { 0x0009e2, "ht" }, + { 0x0009e3, "ff" }, + { 0x0009e4, "cr" }, + { 0x0009e5, "lf" }, + { 0x0009e8, "nl" }, + { 0x0009e9, "vt" }, + { 0x0009ea, "lowrightcorner" }, + { 0x0009eb, "uprightcorner" }, + { 0x0009ec, "upleftcorner" }, + { 0x0009ed, "lowleftcorner" }, + { 0x0009ee, "crossinglines" }, + { 0x0009ef, "horizlinescan1" }, + { 0x0009f0, "horizlinescan3" }, + { 0x0009f1, "horizlinescan5" }, + { 0x0009f2, "horizlinescan7" }, + { 0x0009f3, "horizlinescan9" }, + { 0x0009f4, "leftt" }, + { 0x0009f5, "rightt" }, + { 0x0009f6, "bott" }, + { 0x0009f7, "topt" }, + { 0x0009f8, "vertbar" }, + { 0x000aa1, "emspace" }, + { 0x000aa2, "enspace" }, + { 0x000aa3, "em3space" }, + { 0x000aa4, "em4space" }, + { 0x000aa5, "digitspace" }, + { 0x000aa6, "punctspace" }, + { 0x000aa7, "thinspace" }, + { 0x000aa8, "hairspace" }, + { 0x000aa9, "emdash" }, + { 0x000aaa, "endash" }, + { 0x000aac, "signifblank" }, + { 0x000aae, "ellipsis" }, + { 0x000aaf, "doubbaselinedot" }, + { 0x000ab0, "onethird" }, + { 0x000ab1, "twothirds" }, + { 0x000ab2, "onefifth" }, + { 0x000ab3, "twofifths" }, + { 0x000ab4, "threefifths" }, + { 0x000ab5, "fourfifths" }, + { 0x000ab6, "onesixth" }, + { 0x000ab7, "fivesixths" }, + { 0x000ab8, "careof" }, + { 0x000abb, "figdash" }, + { 0x000abc, "leftanglebracket" }, + { 0x000abd, "decimalpoint" }, + { 0x000abe, "rightanglebracket" }, + { 0x000abf, "marker" }, + { 0x000ac3, "oneeighth" }, + { 0x000ac4, "threeeighths" }, + { 0x000ac5, "fiveeighths" }, + { 0x000ac6, "seveneighths" }, + { 0x000ac9, "trademark" }, + { 0x000aca, "signaturemark" }, + { 0x000acb, "trademarkincircle" }, + { 0x000acc, "leftopentriangle" }, + { 0x000acd, "rightopentriangle" }, + { 0x000ace, "emopencircle" }, + { 0x000acf, "emopenrectangle" }, + { 0x000ad0, "leftsinglequotemark" }, + { 0x000ad1, "rightsinglequotemark" }, + { 0x000ad2, "leftdoublequotemark" }, + { 0x000ad3, "rightdoublequotemark" }, + { 0x000ad4, "prescription" }, + { 0x000ad6, "minutes" }, + { 0x000ad7, "seconds" }, + { 0x000ad9, "latincross" }, + { 0x000ada, "hexagram" }, + { 0x000adb, "filledrectbullet" }, + { 0x000adc, "filledlefttribullet" }, + { 0x000add, "filledrighttribullet" }, + { 0x000ade, "emfilledcircle" }, + { 0x000adf, "emfilledrect" }, + { 0x000ae0, "enopencircbullet" }, + { 0x000ae1, "enopensquarebullet" }, + { 0x000ae2, "openrectbullet" }, + { 0x000ae3, "opentribulletup" }, + { 0x000ae4, "opentribulletdown" }, + { 0x000ae5, "openstar" }, + { 0x000ae6, "enfilledcircbullet" }, + { 0x000ae7, "enfilledsqbullet" }, + { 0x000ae8, "filledtribulletup" }, + { 0x000ae9, "filledtribulletdown" }, + { 0x000aea, "leftpointer" }, + { 0x000aeb, "rightpointer" }, + { 0x000aec, "club" }, + { 0x000aed, "diamond" }, + { 0x000aee, "heart" }, + { 0x000af0, "maltesecross" }, + { 0x000af1, "dagger" }, + { 0x000af2, "doubledagger" }, + { 0x000af3, "checkmark" }, + { 0x000af4, "ballotcross" }, + { 0x000af5, "musicalsharp" }, + { 0x000af6, "musicalflat" }, + { 0x000af7, "malesymbol" }, + { 0x000af8, "femalesymbol" }, + { 0x000af9, "telephone" }, + { 0x000afa, "telephonerecorder" }, + { 0x000afb, "phonographcopyright" }, + { 0x000afc, "caret" }, + { 0x000afd, "singlelowquotemark" }, + { 0x000afe, "doublelowquotemark" }, + { 0x000aff, "cursor" }, + { 0x000ba3, "leftcaret" }, + { 0x000ba6, "rightcaret" }, + { 0x000ba8, "downcaret" }, + { 0x000ba9, "upcaret" }, + { 0x000bc0, "overbar" }, + { 0x000bc2, "downtack" }, + { 0x000bc3, "upshoe" }, + { 0x000bc4, "downstile" }, + { 0x000bc6, "underbar" }, + { 0x000bca, "jot" }, + { 0x000bcc, "quad" }, + { 0x000bce, "uptack" }, + { 0x000bcf, "circle" }, + { 0x000bd3, "upstile" }, + { 0x000bd6, "downshoe" }, + { 0x000bd8, "rightshoe" }, + { 0x000bda, "leftshoe" }, + { 0x000bdc, "lefttack" }, + { 0x000bfc, "righttack" }, + { 0x000cdf, "hebrew_doublelowline" }, + { 0x000ce0, "hebrew_aleph" }, + { 0x000ce1, "hebrew_bet" }, + { 0x000ce1, "hebrew_beth" }, + { 0x000ce2, "hebrew_gimel" }, + { 0x000ce2, "hebrew_gimmel" }, + { 0x000ce3, "hebrew_dalet" }, + { 0x000ce3, "hebrew_daleth" }, + { 0x000ce4, "hebrew_he" }, + { 0x000ce5, "hebrew_waw" }, + { 0x000ce6, "hebrew_zain" }, + { 0x000ce6, "hebrew_zayin" }, + { 0x000ce7, "hebrew_chet" }, + { 0x000ce7, "hebrew_het" }, + { 0x000ce8, "hebrew_tet" }, + { 0x000ce8, "hebrew_teth" }, + { 0x000ce9, "hebrew_yod" }, + { 0x000cea, "hebrew_finalkaph" }, + { 0x000ceb, "hebrew_kaph" }, + { 0x000cec, "hebrew_lamed" }, + { 0x000ced, "hebrew_finalmem" }, + { 0x000cee, "hebrew_mem" }, + { 0x000cef, "hebrew_finalnun" }, + { 0x000cf0, "hebrew_nun" }, + { 0x000cf1, "hebrew_samech" }, + { 0x000cf1, "hebrew_samekh" }, + { 0x000cf2, "hebrew_ayin" }, + { 0x000cf3, "hebrew_finalpe" }, + { 0x000cf4, "hebrew_pe" }, + { 0x000cf5, "hebrew_finalzade" }, + { 0x000cf5, "hebrew_finalzadi" }, + { 0x000cf6, "hebrew_zade" }, + { 0x000cf6, "hebrew_zadi" }, + { 0x000cf7, "hebrew_kuf" }, + { 0x000cf7, "hebrew_qoph" }, + { 0x000cf8, "hebrew_resh" }, + { 0x000cf9, "hebrew_shin" }, + { 0x000cfa, "hebrew_taf" }, + { 0x000cfa, "hebrew_taw" }, + { 0x000da1, "Thai_kokai" }, + { 0x000da2, "Thai_khokhai" }, + { 0x000da3, "Thai_khokhuat" }, + { 0x000da4, "Thai_khokhwai" }, + { 0x000da5, "Thai_khokhon" }, + { 0x000da6, "Thai_khorakhang" }, + { 0x000da7, "Thai_ngongu" }, + { 0x000da8, "Thai_chochan" }, + { 0x000da9, "Thai_choching" }, + { 0x000daa, "Thai_chochang" }, + { 0x000dab, "Thai_soso" }, + { 0x000dac, "Thai_chochoe" }, + { 0x000dad, "Thai_yoying" }, + { 0x000dae, "Thai_dochada" }, + { 0x000daf, "Thai_topatak" }, + { 0x000db0, "Thai_thothan" }, + { 0x000db1, "Thai_thonangmontho" }, + { 0x000db2, "Thai_thophuthao" }, + { 0x000db3, "Thai_nonen" }, + { 0x000db4, "Thai_dodek" }, + { 0x000db5, "Thai_totao" }, + { 0x000db6, "Thai_thothung" }, + { 0x000db7, "Thai_thothahan" }, + { 0x000db8, "Thai_thothong" }, + { 0x000db9, "Thai_nonu" }, + { 0x000dba, "Thai_bobaimai" }, + { 0x000dbb, "Thai_popla" }, + { 0x000dbc, "Thai_phophung" }, + { 0x000dbd, "Thai_fofa" }, + { 0x000dbe, "Thai_phophan" }, + { 0x000dbf, "Thai_fofan" }, + { 0x000dc0, "Thai_phosamphao" }, + { 0x000dc1, "Thai_moma" }, + { 0x000dc2, "Thai_yoyak" }, + { 0x000dc3, "Thai_rorua" }, + { 0x000dc4, "Thai_ru" }, + { 0x000dc5, "Thai_loling" }, + { 0x000dc6, "Thai_lu" }, + { 0x000dc7, "Thai_wowaen" }, + { 0x000dc8, "Thai_sosala" }, + { 0x000dc9, "Thai_sorusi" }, + { 0x000dca, "Thai_sosua" }, + { 0x000dcb, "Thai_hohip" }, + { 0x000dcc, "Thai_lochula" }, + { 0x000dcd, "Thai_oang" }, + { 0x000dce, "Thai_honokhuk" }, + { 0x000dcf, "Thai_paiyannoi" }, + { 0x000dd0, "Thai_saraa" }, + { 0x000dd1, "Thai_maihanakat" }, + { 0x000dd2, "Thai_saraaa" }, + { 0x000dd3, "Thai_saraam" }, + { 0x000dd4, "Thai_sarai" }, + { 0x000dd5, "Thai_saraii" }, + { 0x000dd6, "Thai_saraue" }, + { 0x000dd7, "Thai_sarauee" }, + { 0x000dd8, "Thai_sarau" }, + { 0x000dd9, "Thai_sarauu" }, + { 0x000dda, "Thai_phinthu" }, + { 0x000dde, "Thai_maihanakat_maitho" }, + { 0x000ddf, "Thai_baht" }, + { 0x000de0, "Thai_sarae" }, + { 0x000de1, "Thai_saraae" }, + { 0x000de2, "Thai_sarao" }, + { 0x000de3, "Thai_saraaimaimuan" }, + { 0x000de4, "Thai_saraaimaimalai" }, + { 0x000de5, "Thai_lakkhangyao" }, + { 0x000de6, "Thai_maiyamok" }, + { 0x000de7, "Thai_maitaikhu" }, + { 0x000de8, "Thai_maiek" }, + { 0x000de9, "Thai_maitho" }, + { 0x000dea, "Thai_maitri" }, + { 0x000deb, "Thai_maichattawa" }, + { 0x000dec, "Thai_thanthakhat" }, + { 0x000ded, "Thai_nikhahit" }, + { 0x000df0, "Thai_leksun" }, + { 0x000df1, "Thai_leknung" }, + { 0x000df2, "Thai_leksong" }, + { 0x000df3, "Thai_leksam" }, + { 0x000df4, "Thai_leksi" }, + { 0x000df5, "Thai_lekha" }, + { 0x000df6, "Thai_lekhok" }, + { 0x000df7, "Thai_lekchet" }, + { 0x000df8, "Thai_lekpaet" }, + { 0x000df9, "Thai_lekkao" }, + { 0x000ea1, "Hangul_Kiyeog" }, + { 0x000ea2, "Hangul_SsangKiyeog" }, + { 0x000ea3, "Hangul_KiyeogSios" }, + { 0x000ea4, "Hangul_Nieun" }, + { 0x000ea5, "Hangul_NieunJieuj" }, + { 0x000ea6, "Hangul_NieunHieuh" }, + { 0x000ea7, "Hangul_Dikeud" }, + { 0x000ea8, "Hangul_SsangDikeud" }, + { 0x000ea9, "Hangul_Rieul" }, + { 0x000eaa, "Hangul_RieulKiyeog" }, + { 0x000eab, "Hangul_RieulMieum" }, + { 0x000eac, "Hangul_RieulPieub" }, + { 0x000ead, "Hangul_RieulSios" }, + { 0x000eae, "Hangul_RieulTieut" }, + { 0x000eaf, "Hangul_RieulPhieuf" }, + { 0x000eb0, "Hangul_RieulHieuh" }, + { 0x000eb1, "Hangul_Mieum" }, + { 0x000eb2, "Hangul_Pieub" }, + { 0x000eb3, "Hangul_SsangPieub" }, + { 0x000eb4, "Hangul_PieubSios" }, + { 0x000eb5, "Hangul_Sios" }, + { 0x000eb6, "Hangul_SsangSios" }, + { 0x000eb7, "Hangul_Ieung" }, + { 0x000eb8, "Hangul_Jieuj" }, + { 0x000eb9, "Hangul_SsangJieuj" }, + { 0x000eba, "Hangul_Cieuc" }, + { 0x000ebb, "Hangul_Khieuq" }, + { 0x000ebc, "Hangul_Tieut" }, + { 0x000ebd, "Hangul_Phieuf" }, + { 0x000ebe, "Hangul_Hieuh" }, + { 0x000ebf, "Hangul_A" }, + { 0x000ec0, "Hangul_AE" }, + { 0x000ec1, "Hangul_YA" }, + { 0x000ec2, "Hangul_YAE" }, + { 0x000ec3, "Hangul_EO" }, + { 0x000ec4, "Hangul_E" }, + { 0x000ec5, "Hangul_YEO" }, + { 0x000ec6, "Hangul_YE" }, + { 0x000ec7, "Hangul_O" }, + { 0x000ec8, "Hangul_WA" }, + { 0x000ec9, "Hangul_WAE" }, + { 0x000eca, "Hangul_OE" }, + { 0x000ecb, "Hangul_YO" }, + { 0x000ecc, "Hangul_U" }, + { 0x000ecd, "Hangul_WEO" }, + { 0x000ece, "Hangul_WE" }, + { 0x000ecf, "Hangul_WI" }, + { 0x000ed0, "Hangul_YU" }, + { 0x000ed1, "Hangul_EU" }, + { 0x000ed2, "Hangul_YI" }, + { 0x000ed3, "Hangul_I" }, + { 0x000ed4, "Hangul_J_Kiyeog" }, + { 0x000ed5, "Hangul_J_SsangKiyeog" }, + { 0x000ed6, "Hangul_J_KiyeogSios" }, + { 0x000ed7, "Hangul_J_Nieun" }, + { 0x000ed8, "Hangul_J_NieunJieuj" }, + { 0x000ed9, "Hangul_J_NieunHieuh" }, + { 0x000eda, "Hangul_J_Dikeud" }, + { 0x000edb, "Hangul_J_Rieul" }, + { 0x000edc, "Hangul_J_RieulKiyeog" }, + { 0x000edd, "Hangul_J_RieulMieum" }, + { 0x000ede, "Hangul_J_RieulPieub" }, + { 0x000edf, "Hangul_J_RieulSios" }, + { 0x000ee0, "Hangul_J_RieulTieut" }, + { 0x000ee1, "Hangul_J_RieulPhieuf" }, + { 0x000ee2, "Hangul_J_RieulHieuh" }, + { 0x000ee3, "Hangul_J_Mieum" }, + { 0x000ee4, "Hangul_J_Pieub" }, + { 0x000ee5, "Hangul_J_PieubSios" }, + { 0x000ee6, "Hangul_J_Sios" }, + { 0x000ee7, "Hangul_J_SsangSios" }, + { 0x000ee8, "Hangul_J_Ieung" }, + { 0x000ee9, "Hangul_J_Jieuj" }, + { 0x000eea, "Hangul_J_Cieuc" }, + { 0x000eeb, "Hangul_J_Khieuq" }, + { 0x000eec, "Hangul_J_Tieut" }, + { 0x000eed, "Hangul_J_Phieuf" }, + { 0x000eee, "Hangul_J_Hieuh" }, + { 0x000eef, "Hangul_RieulYeorinHieuh" }, + { 0x000ef0, "Hangul_SunkyeongeumMieum" }, + { 0x000ef1, "Hangul_SunkyeongeumPieub" }, + { 0x000ef2, "Hangul_PanSios" }, + { 0x000ef3, "Hangul_KkogjiDalrinIeung" }, + { 0x000ef4, "Hangul_SunkyeongeumPhieuf" }, + { 0x000ef5, "Hangul_YeorinHieuh" }, + { 0x000ef6, "Hangul_AraeA" }, + { 0x000ef7, "Hangul_AraeAE" }, + { 0x000ef8, "Hangul_J_PanSios" }, + { 0x000ef9, "Hangul_J_KkogjiDalrinIeung" }, + { 0x000efa, "Hangul_J_YeorinHieuh" }, + { 0x000eff, "Korean_Won" }, + { 0x0013bc, "OE" }, + { 0x0013bd, "oe" }, + { 0x0013be, "Ydiaeresis" }, + { 0x0020a0, "EcuSign" }, + { 0x0020a1, "ColonSign" }, + { 0x0020a2, "CruzeiroSign" }, + { 0x0020a3, "FFrancSign" }, + { 0x0020a4, "LiraSign" }, + { 0x0020a5, "MillSign" }, + { 0x0020a6, "NairaSign" }, + { 0x0020a7, "PesetaSign" }, + { 0x0020a8, "RupeeSign" }, + { 0x0020a9, "WonSign" }, + { 0x0020aa, "NewSheqelSign" }, + { 0x0020ab, "DongSign" }, + { 0x0020ac, "EuroSign" }, + { 0x00fd01, "3270_Duplicate" }, + { 0x00fd02, "3270_FieldMark" }, + { 0x00fd03, "3270_Right2" }, + { 0x00fd04, "3270_Left2" }, + { 0x00fd05, "3270_BackTab" }, + { 0x00fd06, "3270_EraseEOF" }, + { 0x00fd07, "3270_EraseInput" }, + { 0x00fd08, "3270_Reset" }, + { 0x00fd09, "3270_Quit" }, + { 0x00fd0a, "3270_PA1" }, + { 0x00fd0b, "3270_PA2" }, + { 0x00fd0c, "3270_PA3" }, + { 0x00fd0d, "3270_Test" }, + { 0x00fd0e, "3270_Attn" }, + { 0x00fd0f, "3270_CursorBlink" }, + { 0x00fd10, "3270_AltCursor" }, + { 0x00fd11, "3270_KeyClick" }, + { 0x00fd12, "3270_Jump" }, + { 0x00fd13, "3270_Ident" }, + { 0x00fd14, "3270_Rule" }, + { 0x00fd15, "3270_Copy" }, + { 0x00fd16, "3270_Play" }, + { 0x00fd17, "3270_Setup" }, + { 0x00fd18, "3270_Record" }, + { 0x00fd19, "3270_ChangeScreen" }, + { 0x00fd1a, "3270_DeleteWord" }, + { 0x00fd1b, "3270_ExSelect" }, + { 0x00fd1c, "3270_CursorSelect" }, + { 0x00fd1d, "3270_PrintScreen" }, + { 0x00fd1e, "3270_Enter" }, + { 0x00fe01, "ISO_Lock" }, + { 0x00fe02, "ISO_Level2_Latch" }, + { 0x00fe03, "ISO_Level3_Shift" }, + { 0x00fe04, "ISO_Level3_Latch" }, + { 0x00fe05, "ISO_Level3_Lock" }, + { 0x00fe06, "ISO_Group_Latch" }, + { 0x00fe07, "ISO_Group_Lock" }, + { 0x00fe08, "ISO_Next_Group" }, + { 0x00fe09, "ISO_Next_Group_Lock" }, + { 0x00fe0a, "ISO_Prev_Group" }, + { 0x00fe0b, "ISO_Prev_Group_Lock" }, + { 0x00fe0c, "ISO_First_Group" }, + { 0x00fe0d, "ISO_First_Group_Lock" }, + { 0x00fe0e, "ISO_Last_Group" }, + { 0x00fe0f, "ISO_Last_Group_Lock" }, + { 0x00fe20, "ISO_Left_Tab" }, + { 0x00fe21, "ISO_Move_Line_Up" }, + { 0x00fe22, "ISO_Move_Line_Down" }, + { 0x00fe23, "ISO_Partial_Line_Up" }, + { 0x00fe24, "ISO_Partial_Line_Down" }, + { 0x00fe25, "ISO_Partial_Space_Left" }, + { 0x00fe26, "ISO_Partial_Space_Right" }, + { 0x00fe27, "ISO_Set_Margin_Left" }, + { 0x00fe28, "ISO_Set_Margin_Right" }, + { 0x00fe29, "ISO_Release_Margin_Left" }, + { 0x00fe2a, "ISO_Release_Margin_Right" }, + { 0x00fe2b, "ISO_Release_Both_Margins" }, + { 0x00fe2c, "ISO_Fast_Cursor_Left" }, + { 0x00fe2d, "ISO_Fast_Cursor_Right" }, + { 0x00fe2e, "ISO_Fast_Cursor_Up" }, + { 0x00fe2f, "ISO_Fast_Cursor_Down" }, + { 0x00fe30, "ISO_Continuous_Underline" }, + { 0x00fe31, "ISO_Discontinuous_Underline" }, + { 0x00fe32, "ISO_Emphasize" }, + { 0x00fe33, "ISO_Center_Object" }, + { 0x00fe34, "ISO_Enter" }, + { 0x00fe50, "dead_grave" }, + { 0x00fe51, "dead_acute" }, + { 0x00fe52, "dead_circumflex" }, + { 0x00fe53, "dead_tilde" }, + { 0x00fe54, "dead_macron" }, + { 0x00fe55, "dead_breve" }, + { 0x00fe56, "dead_abovedot" }, + { 0x00fe57, "dead_diaeresis" }, + { 0x00fe58, "dead_abovering" }, + { 0x00fe59, "dead_doubleacute" }, + { 0x00fe5a, "dead_caron" }, + { 0x00fe5b, "dead_cedilla" }, + { 0x00fe5c, "dead_ogonek" }, + { 0x00fe5d, "dead_iota" }, + { 0x00fe5e, "dead_voiced_sound" }, + { 0x00fe5f, "dead_semivoiced_sound" }, + { 0x00fe60, "dead_belowdot" }, + { 0x00fe70, "AccessX_Enable" }, + { 0x00fe71, "AccessX_Feedback_Enable" }, + { 0x00fe72, "RepeatKeys_Enable" }, + { 0x00fe73, "SlowKeys_Enable" }, + { 0x00fe74, "BounceKeys_Enable" }, + { 0x00fe75, "StickyKeys_Enable" }, + { 0x00fe76, "MouseKeys_Enable" }, + { 0x00fe77, "MouseKeys_Accel_Enable" }, + { 0x00fe78, "Overlay1_Enable" }, + { 0x00fe79, "Overlay2_Enable" }, + { 0x00fe7a, "AudibleBell_Enable" }, + { 0x00fed0, "First_Virtual_Screen" }, + { 0x00fed1, "Prev_Virtual_Screen" }, + { 0x00fed2, "Next_Virtual_Screen" }, + { 0x00fed4, "Last_Virtual_Screen" }, + { 0x00fed5, "Terminate_Server" }, + { 0x00fee0, "Pointer_Left" }, + { 0x00fee1, "Pointer_Right" }, + { 0x00fee2, "Pointer_Up" }, + { 0x00fee3, "Pointer_Down" }, + { 0x00fee4, "Pointer_UpLeft" }, + { 0x00fee5, "Pointer_UpRight" }, + { 0x00fee6, "Pointer_DownLeft" }, + { 0x00fee7, "Pointer_DownRight" }, + { 0x00fee8, "Pointer_Button_Dflt" }, + { 0x00fee9, "Pointer_Button1" }, + { 0x00feea, "Pointer_Button2" }, + { 0x00feeb, "Pointer_Button3" }, + { 0x00feec, "Pointer_Button4" }, + { 0x00feed, "Pointer_Button5" }, + { 0x00feee, "Pointer_DblClick_Dflt" }, + { 0x00feef, "Pointer_DblClick1" }, + { 0x00fef0, "Pointer_DblClick2" }, + { 0x00fef1, "Pointer_DblClick3" }, + { 0x00fef2, "Pointer_DblClick4" }, + { 0x00fef3, "Pointer_DblClick5" }, + { 0x00fef4, "Pointer_Drag_Dflt" }, + { 0x00fef5, "Pointer_Drag1" }, + { 0x00fef6, "Pointer_Drag2" }, + { 0x00fef7, "Pointer_Drag3" }, + { 0x00fef8, "Pointer_Drag4" }, + { 0x00fef9, "Pointer_EnableKeys" }, + { 0x00fefa, "Pointer_Accelerate" }, + { 0x00fefb, "Pointer_DfltBtnNext" }, + { 0x00fefc, "Pointer_DfltBtnPrev" }, + { 0x00fefd, "Pointer_Drag5" }, + { 0x00ff08, "BackSpace" }, + { 0x00ff09, "Tab" }, + { 0x00ff0a, "Linefeed" }, + { 0x00ff0b, "Clear" }, + { 0x00ff0d, "Return" }, + { 0x00ff13, "Pause" }, + { 0x00ff14, "Scroll_Lock" }, + { 0x00ff15, "Sys_Req" }, + { 0x00ff1b, "Escape" }, + { 0x00ff20, "Multi_key" }, + { 0x00ff21, "Kanji" }, + { 0x00ff22, "Muhenkan" }, + { 0x00ff23, "Henkan" }, + { 0x00ff23, "Henkan_Mode" }, + { 0x00ff24, "Romaji" }, + { 0x00ff25, "Hiragana" }, + { 0x00ff26, "Katakana" }, + { 0x00ff27, "Hiragana_Katakana" }, + { 0x00ff28, "Zenkaku" }, + { 0x00ff29, "Hankaku" }, + { 0x00ff2a, "Zenkaku_Hankaku" }, + { 0x00ff2b, "Touroku" }, + { 0x00ff2c, "Massyo" }, + { 0x00ff2d, "Kana_Lock" }, + { 0x00ff2e, "Kana_Shift" }, + { 0x00ff2f, "Eisu_Shift" }, + { 0x00ff30, "Eisu_toggle" }, + { 0x00ff31, "Hangul" }, + { 0x00ff32, "Hangul_Start" }, + { 0x00ff33, "Hangul_End" }, + { 0x00ff34, "Hangul_Hanja" }, + { 0x00ff35, "Hangul_Jamo" }, + { 0x00ff36, "Hangul_Romaja" }, + { 0x00ff37, "Codeinput" }, + { 0x00ff38, "Hangul_Jeonja" }, + { 0x00ff39, "Hangul_Banja" }, + { 0x00ff3a, "Hangul_PreHanja" }, + { 0x00ff3b, "Hangul_PostHanja" }, + { 0x00ff3c, "SingleCandidate" }, + { 0x00ff3d, "MultipleCandidate" }, + { 0x00ff3e, "PreviousCandidate" }, + { 0x00ff3f, "Hangul_Special" }, + { 0x00ff50, "Home" }, + { 0x00ff51, "Left" }, + { 0x00ff52, "Up" }, + { 0x00ff53, "Right" }, + { 0x00ff54, "Down" }, + { 0x00ff55, "Page_Up" }, + { 0x00ff55, "Prior" }, + { 0x00ff56, "Next" }, + { 0x00ff56, "Page_Down" }, + { 0x00ff57, "End" }, + { 0x00ff58, "Begin" }, + { 0x00ff60, "Select" }, + { 0x00ff61, "Print" }, + { 0x00ff62, "Execute" }, + { 0x00ff63, "Insert" }, + { 0x00ff65, "Undo" }, + { 0x00ff66, "Redo" }, + { 0x00ff67, "Menu" }, + { 0x00ff68, "Find" }, + { 0x00ff69, "Cancel" }, + { 0x00ff6a, "Help" }, + { 0x00ff6b, "Break" }, + { 0x00ff7e, "Arabic_switch" }, + { 0x00ff7e, "Greek_switch" }, + { 0x00ff7e, "Hangul_switch" }, + { 0x00ff7e, "Hebrew_switch" }, + { 0x00ff7e, "ISO_Group_Shift" }, + { 0x00ff7e, "Mode_switch" }, + { 0x00ff7e, "kana_switch" }, + { 0x00ff7e, "script_switch" }, + { 0x00ff7f, "Num_Lock" }, + { 0x00ff80, "KP_Space" }, + { 0x00ff89, "KP_Tab" }, + { 0x00ff8d, "KP_Enter" }, + { 0x00ff91, "KP_F1" }, + { 0x00ff92, "KP_F2" }, + { 0x00ff93, "KP_F3" }, + { 0x00ff94, "KP_F4" }, + { 0x00ff95, "KP_Home" }, + { 0x00ff96, "KP_Left" }, + { 0x00ff97, "KP_Up" }, + { 0x00ff98, "KP_Right" }, + { 0x00ff99, "KP_Down" }, + { 0x00ff9a, "KP_Page_Up" }, + { 0x00ff9a, "KP_Prior" }, + { 0x00ff9b, "KP_Next" }, + { 0x00ff9b, "KP_Page_Down" }, + { 0x00ff9c, "KP_End" }, + { 0x00ff9d, "KP_Begin" }, + { 0x00ff9e, "KP_Insert" }, + { 0x00ff9f, "KP_Delete" }, + { 0x00ffaa, "KP_Multiply" }, + { 0x00ffab, "KP_Add" }, + { 0x00ffac, "KP_Separator" }, + { 0x00ffad, "KP_Subtract" }, + { 0x00ffae, "KP_Decimal" }, + { 0x00ffaf, "KP_Divide" }, + { 0x00ffb0, "KP_0" }, + { 0x00ffb1, "KP_1" }, + { 0x00ffb2, "KP_2" }, + { 0x00ffb3, "KP_3" }, + { 0x00ffb4, "KP_4" }, + { 0x00ffb5, "KP_5" }, + { 0x00ffb6, "KP_6" }, + { 0x00ffb7, "KP_7" }, + { 0x00ffb8, "KP_8" }, + { 0x00ffb9, "KP_9" }, + { 0x00ffbd, "KP_Equal" }, + { 0x00ffbe, "F1" }, + { 0x00ffbf, "F2" }, + { 0x00ffc0, "F3" }, + { 0x00ffc1, "F4" }, + { 0x00ffc2, "F5" }, + { 0x00ffc3, "F6" }, + { 0x00ffc4, "F7" }, + { 0x00ffc5, "F8" }, + { 0x00ffc6, "F9" }, + { 0x00ffc7, "F10" }, + { 0x00ffc8, "F11" }, + { 0x00ffc9, "F12" }, + { 0x00ffca, "F13" }, + { 0x00ffcb, "F14" }, + { 0x00ffcc, "F15" }, + { 0x00ffcd, "F16" }, + { 0x00ffce, "F17" }, + { 0x00ffcf, "F18" }, + { 0x00ffd0, "F19" }, + { 0x00ffd1, "F20" }, + { 0x00ffd2, "F21" }, + { 0x00ffd3, "F22" }, + { 0x00ffd4, "F23" }, + { 0x00ffd5, "F24" }, + { 0x00ffd6, "F25" }, + { 0x00ffd7, "F26" }, + { 0x00ffd8, "F27" }, + { 0x00ffd9, "F28" }, + { 0x00ffda, "F29" }, + { 0x00ffdb, "F30" }, + { 0x00ffdc, "F31" }, + { 0x00ffdd, "F32" }, + { 0x00ffde, "F33" }, + { 0x00ffdf, "F34" }, + { 0x00ffe0, "F35" }, + { 0x00ffe1, "Shift_L" }, + { 0x00ffe2, "Shift_R" }, + { 0x00ffe3, "Control_L" }, + { 0x00ffe4, "Control_R" }, + { 0x00ffe5, "Caps_Lock" }, + { 0x00ffe6, "Shift_Lock" }, + { 0x00ffe7, "Meta_L" }, + { 0x00ffe8, "Meta_R" }, + { 0x00ffe9, "Alt_L" }, + { 0x00ffea, "Alt_R" }, + { 0x00ffeb, "Super_L" }, + { 0x00ffec, "Super_R" }, + { 0x00ffed, "Hyper_L" }, + { 0x00ffee, "Hyper_R" }, + { 0x00ffff, "Delete" }, + { 0xffffff, "VoidSymbol" }, +}; + +#define GDK_NUM_KEYS (sizeof (gdk_keys_by_keyval) / sizeof (gdk_keys_by_keyval[0])) + +static struct gdk_key *gdk_keys_by_name = NULL; + +static int +gdk_keys_keyval_compare (const void *pkey, const void *pbase) +{ + return (*(int *) pkey) - ((struct gdk_key *) pbase)->keyval; +} + +gchar* +gdk_keyval_name (guint keyval) +{ + struct gdk_key *found = + bsearch (&keyval, gdk_keys_by_keyval, + GDK_NUM_KEYS, sizeof (struct gdk_key), + gdk_keys_keyval_compare); + if (found != NULL) + return (gchar *) found->name; + else + return NULL; +} + +static int +gdk_key_compare_by_name (const void *a, const void *b) +{ + return strcmp (((const struct gdk_key *) a)->name, ((const struct gdk_key *) b)->name); +} + +static int +gdk_keys_name_compare (const void *pkey, const void *pbase) +{ + return strcmp ((const char *) pkey, ((const struct gdk_key *) pbase)->name); +} + +guint +gdk_keyval_from_name (const gchar *keyval_name) +{ + struct gdk_key *found; + + g_return_val_if_fail (keyval_name != NULL, 0); + + if (gdk_keys_by_name == NULL) + { + gdk_keys_by_name = g_new (struct gdk_key, GDK_NUM_KEYS); + + memcpy (gdk_keys_by_name, gdk_keys_by_keyval, + GDK_NUM_KEYS * sizeof (struct gdk_key)); + + qsort (gdk_keys_by_name, GDK_NUM_KEYS, sizeof (struct gdk_key), + gdk_key_compare_by_name); + } + + found = bsearch (keyval_name, gdk_keys_by_name, + GDK_NUM_KEYS, sizeof (struct gdk_key), + gdk_keys_name_compare); + if (found != NULL) + return found->keyval; + else + return GDK_VoidSymbol; +} + +guint +gdk_keyval_to_upper (guint keyval) +{ + if (keyval) + { + KeySym lower_val = 0; + KeySym upper_val = 0; + + gdkx_XConvertCase (keyval, &lower_val, &upper_val); + return upper_val; + } + return 0; +} + +guint +gdk_keyval_to_lower (guint keyval) +{ + if (keyval) + { + KeySym lower_val = 0; + KeySym upper_val = 0; + + gdkx_XConvertCase (keyval, &lower_val, &upper_val); + return lower_val; + } + return 0; +} + +gboolean +gdk_keyval_is_upper (guint keyval) +{ + if (keyval) + { + KeySym lower_val = 0; + KeySym upper_val = 0; + + gdkx_XConvertCase (keyval, &lower_val, &upper_val); + return upper_val == keyval; + } + return TRUE; +} + +gboolean +gdk_keyval_is_lower (guint keyval) +{ + if (keyval) + { + KeySym lower_val = 0; + KeySym upper_val = 0; + + gdkx_XConvertCase (keyval, &lower_val, &upper_val); + return lower_val == keyval; + } + return TRUE; +} + + +void +gdk_threads_enter () +{ + GDK_THREADS_ENTER (); +} + +void +gdk_threads_leave () +{ + GDK_THREADS_LEAVE (); +} diff --git a/gdk/win32/gdk.def b/gdk/win32/gdk.def new file mode 100644 index 000000000..564af22e4 --- /dev/null +++ b/gdk/win32/gdk.def @@ -0,0 +1,323 @@ +EXPORTS + gdk_atom_intern + gdk_atom_name + gdk_beep + gdk_bitmap_create_from_data + gdk_bitmap_ref + gdk_bitmap_unref + gdk_char_height + gdk_char_measure + gdk_char_width + gdk_char_width_wc + gdk_color_alloc + gdk_color_black + gdk_color_change + gdk_color_copy + gdk_color_equal + gdk_color_free + gdk_color_hash + gdk_color_parse + gdk_color_white + gdk_colormap_alloc_color + gdk_colormap_alloc_colors + gdk_colormap_change + gdk_colormap_free_colors + gdk_colormap_get_system + gdk_colormap_get_system_size + gdk_colormap_get_visual + gdk_colormap_new + gdk_colormap_ref + gdk_colormap_unref + gdk_colors_alloc + gdk_colors_free + gdk_colors_store + gdk_cursor_destroy + gdk_cursor_new + gdk_cursor_new_from_pixmap + gdk_debug_flags + gdk_dnd_init + gdk_drag_abort + gdk_drag_begin + gdk_drag_context_new + gdk_drag_context_ref + gdk_drag_context_unref + gdk_drag_drop + gdk_drag_find_window + gdk_drag_get_protocol + gdk_drag_get_selection + gdk_drag_motion + gdk_drag_status + gdk_drop_finish + gdk_drop_reply + gdk_draw_arc + gdk_draw_gray_image + gdk_draw_image + gdk_draw_indexed_image + gdk_draw_line + gdk_draw_lines + gdk_draw_pixmap + gdk_draw_point + gdk_draw_points + gdk_draw_polygon + gdk_draw_rectangle + gdk_draw_rgb_32_image + gdk_draw_rgb_image + gdk_draw_rgb_image_dithalign + gdk_draw_segments + gdk_draw_string + gdk_draw_text + gdk_draw_text_wc + gdk_drawable_get_colormap + gdk_drawable_get_size + gdk_drawable_get_type + gdk_drawable_get_visual + gdk_drawable_set_colormap + gdk_drawable_set_data + gdk_error_code + gdk_error_trap_pop + gdk_error_trap_push + gdk_error_warnings + gdk_event_copy + gdk_event_free + gdk_event_get + gdk_event_get_graphics_expose + gdk_event_get_time + gdk_event_handler_set + gdk_event_peek + gdk_event_put + gdk_event_send_client_message + gdk_event_send_clientmessage_toall + gdk_events_pending + gdk_exit + gdk_flush + gdk_font_equal + gdk_font_id + gdk_font_list_free + gdk_font_list_new + gdk_font_load + gdk_font_ref + gdk_font_unref + gdk_font_xlfd_create + gdk_font_xlfd_free + gdk_fontset_load + gdk_free_compound_text + gdk_free_text_list + gdk_gc_copy + gdk_gc_destroy + gdk_gc_get_values + gdk_gc_new + gdk_gc_new_with_values + gdk_gc_ref + gdk_gc_set_background + gdk_gc_set_clip_mask + gdk_gc_set_clip_origin + gdk_gc_set_clip_rectangle + gdk_gc_set_clip_region + gdk_gc_set_dashes + gdk_gc_set_exposures + gdk_gc_set_fill + gdk_gc_set_font + gdk_gc_set_foreground + gdk_gc_set_function + gdk_gc_set_line_attributes + gdk_gc_set_stipple + gdk_gc_set_subwindow + gdk_gc_set_tile + gdk_gc_set_ts_origin + gdk_gc_unref + gdk_get_display + gdk_get_show_events + gdk_get_use_xshm + gdk_ic_destroy + gdk_ic_get_attr + gdk_ic_get_events + gdk_ic_get_style + gdk_ic_get_values + gdk_ic_new + gdk_ic_set_attr + gdk_ic_set_values + gdk_im_begin + gdk_im_decide_style + gdk_im_end + gdk_im_ready + gdk_im_set_best_style + gdk_image_bitmap_new + gdk_image_destroy + gdk_image_get + gdk_image_get_pixel + gdk_image_new + gdk_image_new_bitmap + gdk_image_put_pixel + gdk_init + gdk_init_check + gdk_input_add + gdk_input_add_full + gdk_input_exit + gdk_input_init + gdk_input_list_devices + gdk_input_motion_events + gdk_input_remove + gdk_input_set_axes + gdk_input_set_extension_events + gdk_input_set_key + gdk_input_set_mode + gdk_input_set_source + gdk_input_window_get_pointer + gdk_key_repeat_disable + gdk_key_repeat_restore + gdk_keyboard_grab + gdk_keyboard_ungrab + gdk_keyval_from_name + gdk_keyval_is_lower + gdk_keyval_is_upper + gdk_keyval_name + gdk_keyval_to_lower + gdk_keyval_to_upper + gdk_list_visuals + gdk_mbstowcs + gdk_null_window_warnings + gdk_pixmap_colormap_create_from_xpm + gdk_pixmap_colormap_create_from_xpm_d + gdk_pixmap_create_from_data + gdk_pixmap_create_from_xpm + gdk_pixmap_create_from_xpm_d + gdk_pixmap_create_on_shared_image + gdk_pixmap_foreign_new + gdk_pixmap_new + gdk_pixmap_ref + gdk_pixmap_unref + gdk_pointer_grab + gdk_pointer_is_grabbed + gdk_pointer_ungrab + gdk_progclass + gdk_property_change + gdk_property_delete + gdk_property_get + gdk_query_depths + gdk_query_visual_types + gdk_rectangle_intersect + gdk_rectangle_union + gdk_region_destroy + gdk_region_empty + gdk_region_equal + gdk_region_get_clipbox + gdk_region_new + gdk_region_offset + gdk_region_point_in + gdk_region_polygon + gdk_region_rect_in + gdk_region_shrink + gdk_region_union_with_rect + gdk_regions_intersect + gdk_regions_subtract + gdk_regions_union + gdk_regions_xor + gdk_rgb_cmap_free + gdk_rgb_cmap_new + gdk_rgb_ditherable + gdk_rgb_gc_set_background + gdk_rgb_gc_set_foreground + gdk_rgb_get_cmap + gdk_rgb_get_visual + gdk_rgb_init + gdk_rgb_set_install + gdk_rgb_set_min_colors + gdk_rgb_set_verbose + gdk_rgb_xpixel_from_rgb + gdk_root_parent + gdk_screen_height + gdk_screen_height_mm + gdk_screen_width + gdk_screen_width_mm + gdk_selection_convert + gdk_selection_owner_get + gdk_selection_owner_set + gdk_selection_property + gdk_selection_property_get + gdk_selection_send_notify + gdk_set_locale + gdk_set_show_events + gdk_set_use_xshm + gdk_string_extents + gdk_string_height + gdk_string_measure + gdk_string_to_compound_text + gdk_string_width + gdk_text_extents + gdk_text_extents_wc + gdk_text_height + gdk_text_measure + gdk_text_property_to_text_list + gdk_text_width + gdk_text_width_wc + gdk_threads_enter + gdk_threads_leave + gdk_threads_mutex + gdk_visual_get_best + gdk_visual_get_best_depth + gdk_visual_get_best_type + gdk_visual_get_best_with_both + gdk_visual_get_best_with_depth + gdk_visual_get_best_with_type + gdk_visual_get_system + gdk_visual_ref + gdk_visual_unref + gdk_wcstombs + gdk_window_add_filter + gdk_window_at_pointer + gdk_window_clear + gdk_window_clear_area + gdk_window_clear_area_e + gdk_window_destroy + gdk_window_foreign_new + gdk_window_get_deskrelative_origin + gdk_window_get_children + gdk_window_get_events + gdk_window_get_geometry + gdk_window_get_origin + gdk_window_get_parent + gdk_window_get_pointer + gdk_window_get_position + gdk_window_get_root_origin + gdk_window_get_toplevel + gdk_window_get_toplevels + gdk_window_get_user_data + gdk_window_hide + gdk_window_is_visible + gdk_window_is_viewable + gdk_window_lower + gdk_window_merge_child_shapes + gdk_window_move + gdk_window_move_resize + gdk_window_new + gdk_window_raise + gdk_window_ref + gdk_window_register_dnd + gdk_window_remove_filter + gdk_window_reparent + gdk_window_resize + gdk_window_set_back_pixmap + gdk_window_set_background + gdk_window_set_child_shapes + gdk_window_set_cursor + gdk_window_set_decorations + gdk_window_set_events + gdk_window_set_functions + gdk_window_set_geometry_hints + gdk_window_set_group + gdk_window_set_hints + gdk_window_set_icon + gdk_window_set_icon_name + gdk_window_set_override_redirect + gdk_window_set_role + gdk_window_set_static_gravities + gdk_window_set_title + gdk_window_set_transient_for + gdk_window_set_user_data + gdk_window_shape_combine_mask + gdk_window_show + gdk_window_unref + gdk_window_withdraw + gdk_xid_table_insert + gdk_xid_table_lookup + gdk_xid_table_remove \ No newline at end of file diff --git a/gdk/win32/gdkdnd-win32.c b/gdk/win32/gdkdnd-win32.c new file mode 100644 index 000000000..da6da4bb5 --- /dev/null +++ b/gdk/win32/gdkdnd-win32.c @@ -0,0 +1,973 @@ +/* GDK - The GIMP Drawing Kit + * Copyright (C) 1995-1999 Peter Mattis, Spencer Kimball and Josh MacDonald + * Copyright (C) 1998-1999 Tor Lillqvist + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* + * Modified by the GTK+ Team and others 1997-1999. See the AUTHORS + * file for a list of people on the GTK+ Team. See the ChangeLog + * files for a list of changes. These files are distributed with + * GTK+ at ftp://ftp.gtk.org/pub/gtk/. + */ + +#include "config.h" + +#include + +/* #define OLE2_DND */ + +#define INITGUID + +#include "gdkdnd.h" +#include "gdkproperty.h" +#include "gdkprivate.h" +#include "gdkx.h" + +#ifdef OLE2_DND +#include +#else +#include +#endif + +#ifdef _MSC_VER /* These aren't in mingw32 */ +#include +#include +#endif + +#ifndef _MSC_VER +static IID IID_IUnknown = { + 0x00000000, 0x0000, 0x0000, { 0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46 } }; +static IID IID_IDropSource = { + 0x00000121, 0x0000, 0x0000, { 0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46 } }; +static IID IID_IDropTarget = { + 0x00000122, 0x0000, 0x0000, { 0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46 } }; +#endif + +#include + +typedef struct _GdkDragContextPrivate GdkDragContextPrivate; + +typedef enum { + GDK_DRAG_STATUS_DRAG, + GDK_DRAG_STATUS_MOTION_WAIT, + GDK_DRAG_STATUS_ACTION_WAIT, + GDK_DRAG_STATUS_DROP +} GtkDragStatus; + +typedef enum { + GDK_DRAG_SOURCE, + GDK_DRAG_TARGET +} GdkDragKind; + +#ifdef OLE2_DND + +#define PRINT_GUID(guid) \ + g_print ("guid = %.08x-%.04x-%.04x-%.02x%.02x-%.02x%.02x%.02x%.02x%.02x%.02x", \ + ((gulong *) guid)[0], \ + ((gushort *) guid)[2], \ + ((gushort *) guid)[3], \ + ((guchar *) guid)[8], \ + ((guchar *) guid)[9], \ + ((guchar *) guid)[10], \ + ((guchar *) guid)[11], \ + ((guchar *) guid)[12], \ + ((guchar *) guid)[13], \ + ((guchar *) guid)[14], \ + ((guchar *) guid)[15]); + + +#endif /* OLE2_DND */ + +/* Structure that holds information about a drag in progress. + * this is used on both source and destination sides. + */ +struct _GdkDragContextPrivate { + GdkDragContext context; + + guint ref_count; + + guint16 last_x; /* Coordinates from last event */ + guint16 last_y; + HWND dest_xid; + guint drag_status; /* Current status of drag */ +}; + +GdkDragContext *current_dest_drag = NULL; + +/* Drag Contexts */ + +static GList *contexts; + +GdkDragContext * +gdk_drag_context_new (void) +{ + GdkDragContextPrivate *result; + + result = g_new0 (GdkDragContextPrivate, 1); + + result->ref_count = 1; + + contexts = g_list_prepend (contexts, result); + + return (GdkDragContext *)result; +} + +void +gdk_drag_context_ref (GdkDragContext *context) +{ + g_return_if_fail (context != NULL); + + ((GdkDragContextPrivate *)context)->ref_count++; +} + +void +gdk_drag_context_unref (GdkDragContext *context) +{ + GdkDragContextPrivate *private = (GdkDragContextPrivate *)context; + + g_return_if_fail (context != NULL); + + private->ref_count--; + + GDK_NOTE (DND, g_print ("gdk_drag_context_unref: %d%s\n", + private->ref_count, + (private->ref_count == 0 ? " freeing" : ""))); + + if (private->ref_count == 0) + { + g_dataset_destroy (private); + + g_list_free (context->targets); + + if (context->source_window) + gdk_window_unref (context->source_window); + + if (context->dest_window) + gdk_window_unref (context->dest_window); + + contexts = g_list_remove (contexts, private); + g_free (private); + } +} + +#if 0 + +static GdkDragContext * +gdk_drag_context_find (gboolean is_source, + HWND source_xid, + HWND dest_xid) +{ + GList *tmp_list = contexts; + GdkDragContext *context; + + while (tmp_list) + { + context = (GdkDragContext *)tmp_list->data; + + if ((!context->is_source == !is_source) && + ((source_xid == None) || (context->source_window && + (GDK_WINDOW_XWINDOW (context->source_window) == source_xid))) && + ((dest_xid == None) || (context->dest_window && + (GDK_WINDOW_XWINDOW (context->dest_window) == dest_xid)))) + return context; + + tmp_list = tmp_list->next; + } + + return NULL; +} + +#endif + +typedef struct { +#ifdef OLE2_DND + IDropTarget idt; +#endif + GdkDragContext *context; +} target_drag_context; + +typedef struct { +#ifdef OLE2_DND + IDropSource ids; +#endif + GdkDragContext *context; +} source_drag_context; + +#ifdef OLE2_DND + +static ULONG STDMETHODCALLTYPE +m_add_ref_target (IDropTarget __RPC_FAR *This) +{ + target_drag_context *ctx = (target_drag_context *) This; + GdkDragContextPrivate *private = (GdkDragContextPrivate *) ctx->context; + + GDK_NOTE (DND, g_print ("m_add_ref_target\n")); + gdk_drag_context_ref (ctx->context); + + return private->ref_count; +} + +static HRESULT STDMETHODCALLTYPE +m_query_interface_target (IDropTarget __RPC_FAR *This, + REFIID riid, + void __RPC_FAR *__RPC_FAR *ppvObject) +{ + GDK_NOTE (DND, g_print ("m_query_interface_target\n")); + + *ppvObject = NULL; + + PRINT_GUID (riid); + + if (IsEqualGUID (riid, &IID_IUnknown)) + { + g_print ("...IUnknown\n"); + m_add_ref_target (This); + *ppvObject = This; + return S_OK; + } + else if (IsEqualGUID (riid, &IID_IDropTarget)) + { + g_print ("...IDropTarget\n"); + m_add_ref_target (This); + *ppvObject = This; + return S_OK; + } + else + { + g_print ("...Huh?\n"); + return E_NOINTERFACE; + } +} + +static ULONG STDMETHODCALLTYPE +m_release_target (IDropTarget __RPC_FAR *This) +{ + target_drag_context *ctx = (target_drag_context *) This; + GdkDragContextPrivate *private = (GdkDragContextPrivate *) ctx->context; + + GDK_NOTE (DND, g_print ("m_release_target\n")); + gdk_drag_context_unref (ctx->context); + + if (private->ref_count == 1) + { + gdk_drag_context_unref (ctx->context); + return 0; + } + else + return private->ref_count - 1; +} + +static HRESULT STDMETHODCALLTYPE +m_drag_enter (IDropTarget __RPC_FAR *This, + IDataObject __RPC_FAR *pDataObj, + DWORD grfKeyState, + POINTL pt, + DWORD __RPC_FAR *pdwEffect) +{ + GDK_NOTE (DND, g_print ("m_drag_enter\n")); + return E_UNEXPECTED; +} + +static HRESULT STDMETHODCALLTYPE +m_drag_over (IDropTarget __RPC_FAR *This, + DWORD grfKeyState, + POINTL pt, + DWORD __RPC_FAR *pdwEffect) +{ + GDK_NOTE (DND, g_print ("m_drag_over\n")); + return E_UNEXPECTED; +} + +static HRESULT STDMETHODCALLTYPE +m_drag_leave (IDropTarget __RPC_FAR *This) +{ + GDK_NOTE (DND, g_print ("m_drag_leave\n")); + return E_UNEXPECTED; +} + +static HRESULT STDMETHODCALLTYPE +m_drop (IDropTarget __RPC_FAR *This, + IDataObject __RPC_FAR *pDataObj, + DWORD grfKeyState, + POINTL pt, + DWORD __RPC_FAR *pdwEffect) +{ + GDK_NOTE (DND, g_print ("m_drop\n")); + return E_UNEXPECTED; +} + +static ULONG STDMETHODCALLTYPE +m_add_ref_source (IDropSource __RPC_FAR *This) +{ + source_drag_context *ctx = (source_drag_context *) This; + GdkDragContextPrivate *private = (GdkDragContextPrivate *) ctx->context; + + GDK_NOTE (DND, g_print ("m_add_ref_source\n")); + gdk_drag_context_ref (ctx->context); + + return private->ref_count; +} + +static HRESULT STDMETHODCALLTYPE +m_query_interface_source (IDropSource __RPC_FAR *This, + REFIID riid, + void __RPC_FAR *__RPC_FAR *ppvObject) +{ + GDK_NOTE (DND, g_print ("m_query_interface_source\n")); + + *ppvObject = NULL; + + PRINT_GUID (riid); + if (IsEqualGUID (riid, &IID_IUnknown)) + { + g_print ("...IUnknown\n"); + m_add_ref_source (This); + *ppvObject = This; + return S_OK; + } + else if (IsEqualGUID (riid, &IID_IDropSource)) + { + g_print ("...IDropSource\n"); + m_add_ref_source (This); + *ppvObject = This; + return S_OK; + } + else + { + g_print ("...Huh?\n"); + return E_NOINTERFACE; + } +} + +static ULONG STDMETHODCALLTYPE +m_release_source (IDropSource __RPC_FAR *This) +{ + source_drag_context *ctx = (source_drag_context *) This; + GdkDragContextPrivate *private = (GdkDragContextPrivate *) ctx->context; + + GDK_NOTE (DND, g_print ("m_release_source\n")); + gdk_drag_context_unref (ctx->context); + + if (private->ref_count == 1) + { + gdk_drag_context_unref (ctx->context); + return 0; + } + else + return private->ref_count - 1; +} + +static HRESULT STDMETHODCALLTYPE +m_query_continue_drag (IDropSource __RPC_FAR *This, + BOOL fEscapePressed, + DWORD grfKeyState) +{ + GDK_NOTE (DND, g_print ("m_query_continue_drag\n")); + return E_UNEXPECTED; +} + +static HRESULT STDMETHODCALLTYPE +m_give_feedback (IDropSource __RPC_FAR *This, + DWORD dwEffect) +{ + GDK_NOTE (DND, g_print ("m_give_feedback\n")); + return E_UNEXPECTED; +} + +static HRESULT STDMETHODCALLTYPE +m_query_interface_object (IDataObject __RPC_FAR *This, + REFIID riid, + void __RPC_FAR *__RPC_FAR *ppvObject) +{ + return E_UNEXPECTED; +} + +static ULONG STDMETHODCALLTYPE +m_add_ref_object (IDataObject __RPC_FAR *This) +{ + return E_UNEXPECTED; +} + +static ULONG STDMETHODCALLTYPE +m_release_object (IDataObject __RPC_FAR *This) +{ + return E_UNEXPECTED; +} + +static HRESULT STDMETHODCALLTYPE +m_get_data (IDataObject __RPC_FAR *This, + FORMATETC *pFormatEtc, + STGMEDIUM *pMedium) +{ + return E_UNEXPECTED; +} + +static HRESULT STDMETHODCALLTYPE +m_get_data_here (IDataObject __RPC_FAR *This, + FORMATETC *pFormatEtc, + STGMEDIUM *pMedium) +{ + return E_UNEXPECTED; +} + +static HRESULT STDMETHODCALLTYPE +m_query_get_data (IDataObject __RPC_FAR *This, + FORMATETC *pFormatEtc) +{ + return E_UNEXPECTED; +} + +static HRESULT STDMETHODCALLTYPE +m_get_canonical_format_etc (IDataObject __RPC_FAR *This, + FORMATETC *pFormatEtcIn, + FORMATETC *pFormatEtcOut) +{ + return E_UNEXPECTED; +} + +static HRESULT STDMETHODCALLTYPE +m_set_data (IDataObject __RPC_FAR *This, + FORMATETC *pFormatEtc, + STGMEDIUM *pMedium, + BOOL fRelease) +{ + return E_UNEXPECTED; +} + +static HRESULT STDMETHODCALLTYPE +m_enum_format_etc (IDataObject __RPC_FAR *This, + DWORD dwDirection, + IEnumFORMATETC **ppEnumFormatEtc) +{ + return E_UNEXPECTED; +} + +static HRESULT STDMETHODCALLTYPE + m_d_advise (IDataObject __RPC_FAR *This, + FORMATETC *pFormatetc, + DWORD advf, + IAdviseSink *pAdvSink, + DWORD *pdwConnection) +{ + return E_UNEXPECTED; +} + +static HRESULT STDMETHODCALLTYPE + m_d_unadvise (IDataObject __RPC_FAR *This, + DWORD dwConnection) +{ + return E_UNEXPECTED; +} + +static HRESULT STDMETHODCALLTYPE +m_enum_d_advise (IDataObject __RPC_FAR *This, + IEnumSTATDATA **ppenumAdvise) +{ + return E_UNEXPECTED; +} + +static IDropTargetVtbl idt_vtbl = { + m_query_interface_target, + m_add_ref_target, + m_release_target, + m_drag_enter, + m_drag_over, + m_drag_leave, + m_drop +}; + +static IDropSourceVtbl ids_vtbl = { + m_query_interface_source, + m_add_ref_source, + m_release_source, + m_query_continue_drag, + m_give_feedback +}; + +static IDataObjectVtbl ido_vtbl = { + m_query_interface_object, + m_add_ref_object, + m_release_object, + m_get_data, + m_get_data_here, + m_query_get_data, + m_get_canonical_format_etc, + m_set_data, + m_enum_format_etc, + m_d_advise, + m_d_unadvise, + m_enum_d_advise +}; + +#endif /* OLE2_DND */ + +static target_drag_context * +target_context_new (void) +{ + target_drag_context *result; + + result = g_new0 (target_drag_context, 1); + +#ifdef OLE2_DND + result->idt.lpVtbl = &idt_vtbl; +#endif + + result->context = gdk_drag_context_new (); + + return result; +} + +static source_drag_context * +source_context_new (void) +{ + source_drag_context *result; + + result = g_new0 (source_drag_context, 1); + +#ifdef OLE2_DND + result->ids.lpVtbl = &ids_vtbl; +#endif + + result->context = gdk_drag_context_new (); + + return result; +} + +#ifdef _MSC_VER + +/* From MS Knowledge Base article Q130698 */ + +/* resolve_link() fills the filename and path buffer + * with relevant information + * hWnd - calling app's window handle. + * + * lpszLinkName - name of the link file passed into the function. + * + * lpszPath - the buffer that will receive the file pathname. + */ + +static HRESULT +resolve_link(HWND hWnd, + LPCTSTR lpszLinkName, + LPSTR lpszPath, + LPSTR lpszDescription) +{ + HRESULT hres; + IShellLink *psl; + WIN32_FIND_DATA wfd; + + /* Assume Failure to start with: */ + *lpszPath = 0; + if (lpszDescription) + *lpszDescription = 0; + + /* Call CoCreateInstance to obtain the IShellLink interface + * pointer. This call fails if CoInitialize is not called, so it is + * assumed that CoInitialize has been called. + */ + + hres = CoCreateInstance (&CLSID_ShellLink, + NULL, + CLSCTX_INPROC_SERVER, + &IID_IShellLink, + (LPVOID *)&psl); + if (SUCCEEDED (hres)) + { + IPersistFile *ppf; + + /* The IShellLink interface supports the IPersistFile + * interface. Get an interface pointer to it. + */ + hres = psl->lpVtbl->QueryInterface (psl, + &IID_IPersistFile, + (LPVOID *) &ppf); + if (SUCCEEDED (hres)) + { + WORD wsz[MAX_PATH]; + + /* Convert the given link name string to wide character string. */ + MultiByteToWideChar (CP_ACP, 0, + lpszLinkName, + -1, wsz, MAX_PATH); + /* Load the file. */ + hres = ppf->lpVtbl->Load (ppf, wsz, STGM_READ); + if (SUCCEEDED (hres)) + { + /* Resolve the link by calling the Resolve() + * interface function. + */ + hres = psl->lpVtbl->Resolve(psl, hWnd, + SLR_ANY_MATCH | + SLR_NO_UI); + if (SUCCEEDED (hres)) + { + hres = psl->lpVtbl->GetPath (psl, lpszPath, + MAX_PATH, + (WIN32_FIND_DATA*)&wfd, + 0); + + if (SUCCEEDED (hres) && lpszDescription != NULL) + { + hres = psl->lpVtbl->GetDescription (psl, + lpszDescription, + MAX_PATH ); + + if (!SUCCEEDED (hres)) + return FALSE; + } + } + } + ppf->lpVtbl->Release (ppf); + } + psl->lpVtbl->Release (psl); + } + return SUCCEEDED (hres); +} + +#else + +#define resolve_link(hWnd, lpszLinkName, lpszPath, lpszDescription) FALSE + +#endif + +static GdkFilterReturn +gdk_dropfiles_filter (GdkXEvent *xev, + GdkEvent *event, + gpointer data) +{ + GdkDragContext *context; + GdkDragContextPrivate *private; + static GdkAtom text_uri_list_atom = GDK_NONE; + GString *result; + MSG *msg = (MSG *) xev; + HANDLE hdrop; + POINT pt; + gint nfiles, i, k; + guchar fileName[MAX_PATH], linkedFile[MAX_PATH]; + + if (text_uri_list_atom == GDK_NONE) + text_uri_list_atom = gdk_atom_intern ("text/uri-list", FALSE); + + if (msg->message == WM_DROPFILES) + { + GDK_NOTE (DND, g_print ("WM_DROPFILES: %#x\n", msg->hwnd)); + + context = gdk_drag_context_new (); + private = (GdkDragContextPrivate *) context; + context->protocol = GDK_DRAG_PROTO_WIN32_DROPFILES; + context->is_source = FALSE; + context->source_window = (GdkWindow *) gdk_root_parent; + context->dest_window = event->any.window; + gdk_window_ref (context->dest_window); + /* WM_DROPFILES drops are always file names */ + context->targets = + g_list_append (NULL, GUINT_TO_POINTER (text_uri_list_atom)); + current_dest_drag = context; + + event->dnd.type = GDK_DROP_START; + event->dnd.context = current_dest_drag; + gdk_drag_context_ref (current_dest_drag); + + hdrop = (HANDLE) msg->wParam; + DragQueryPoint (hdrop, &pt); + ClientToScreen (msg->hwnd, &pt); + + event->dnd.x_root = pt.x; + event->dnd.y_root = pt.y; + event->dnd.time = msg->time; + + nfiles = DragQueryFile (hdrop, 0xFFFFFFFF, NULL, 0); + + result = g_string_new (NULL); + for (i = 0; i < nfiles; i++) + { + g_string_append (result, "file:"); + DragQueryFile (hdrop, i, fileName, MAX_PATH); + + /* Resolve shortcuts */ + if (resolve_link (msg->hwnd, fileName, linkedFile, NULL)) + { + g_string_append (result, linkedFile); + GDK_NOTE (DND, g_print ("...%s link to %s\n", + fileName, linkedFile)); + } + else + { + g_string_append (result, fileName); + GDK_NOTE (DND, g_print ("...%s\n", fileName)); + } + g_string_append (result, "\015\012"); + } + gdk_sel_prop_store ((GdkWindow *) gdk_root_parent, + text_uri_list_atom, 8, result->str, result->len + 1); + + DragFinish (hdrop); + + return GDK_FILTER_TRANSLATE; + } + else + return GDK_FILTER_CONTINUE; +} + +/************************************************************* + ************************** Public API *********************** + *************************************************************/ + +void +gdk_dnd_init (void) +{ + HRESULT hres; +#ifdef OLE2_DND + hres = OleInitialize (NULL); + + if (! SUCCEEDED (hres)) + g_error ("OleInitialize failed"); +#endif +} + +void +gdk_dnd_exit (void) +{ +#ifdef OLE2_DND + OleUninitialize (); +#endif +} + +/* Source side */ + +static void +gdk_drag_do_leave (GdkDragContext *context, guint32 time) +{ + if (context->dest_window) + { + GDK_NOTE (DND, g_print ("gdk_drag_do_leave\n")); + gdk_window_unref (context->dest_window); + context->dest_window = NULL; + } +} + +GdkDragContext * +gdk_drag_begin (GdkWindow *window, + GList *targets) +{ + GList *tmp_list; + source_drag_context *ctx; + + g_return_val_if_fail (window != NULL, NULL); + + GDK_NOTE (DND, g_print ("gdk_drag_begin\n")); + + ctx = source_context_new (); + ctx->context->is_source = TRUE; + ctx->context->source_window = window; + gdk_window_ref (window); + + tmp_list = g_list_last (targets); + ctx->context->targets = NULL; + while (tmp_list) + { + ctx->context->targets = g_list_prepend (ctx->context->targets, + tmp_list->data); + tmp_list = tmp_list->prev; + } + + ctx->context->actions = 0; + +#if 0 + DoDragDrop (...); +#endif + return ctx->context; +} + +guint32 +gdk_drag_get_protocol (guint32 xid, + GdkDragProtocol *protocol) +{ + /* This isn't used */ + return 0; +} + +void +gdk_drag_find_window (GdkDragContext *context, + GdkWindow *drag_window, + gint x_root, + gint y_root, + GdkWindow **dest_window, + GdkDragProtocol *protocol) +{ + GdkDragContextPrivate *private = (GdkDragContextPrivate *)context; + GdkDrawablePrivate *drag_window_private = (GdkDrawablePrivate*) drag_window; + HWND recipient; + POINT pt; + + GDK_NOTE (DND, g_print ("gdk_drag_find_window: %#x +%d+%d\n", + (drag_window ? drag_window_private->xwindow : 0), + x_root, y_root)); + + pt.x = x_root; + pt.y = y_root; + recipient = WindowFromPoint (pt); + if (recipient == NULL) + *dest_window = NULL; + else + { + *dest_window = gdk_window_lookup (recipient); + if (*dest_window) + gdk_window_ref (*dest_window); + *protocol = GDK_DRAG_PROTO_WIN32_DROPFILES; + } +} + +gboolean +gdk_drag_motion (GdkDragContext *context, + GdkWindow *dest_window, + GdkDragProtocol protocol, + gint x_root, + gint y_root, + GdkDragAction suggested_action, + GdkDragAction possible_actions, + guint32 time) +{ + return FALSE; +} + +void +gdk_drag_drop (GdkDragContext *context, + guint32 time) +{ + g_return_if_fail (context != NULL); + + g_warning ("gdk_drag_drop: not implemented\n"); +} + +void +gdk_drag_abort (GdkDragContext *context, + guint32 time) +{ + g_return_if_fail (context != NULL); + + gdk_drag_do_leave (context, time); +} + +/* Destination side */ + +void +gdk_drag_status (GdkDragContext *context, + GdkDragAction action, + guint32 time) +{ + GDK_NOTE (DND, g_print ("gdk_drag_status\n")); +} + +void +gdk_drop_reply (GdkDragContext *context, + gboolean ok, + guint32 time) +{ +} + +void +gdk_drop_finish (GdkDragContext *context, + gboolean success, + guint32 time) +{ +} + +static GdkFilterReturn +gdk_destroy_filter (GdkXEvent *xev, + GdkEvent *event, + gpointer data) +{ +#ifdef OLE2_DND + MSG *msg = (MSG *) xev; + + if (msg->message == WM_DESTROY) + { + IDropTarget *idtp = (IDropTarget *) data; + + GDK_NOTE (DND, g_print ("gdk_destroy_filter: WM_DESTROY: %#x\n", msg->hwnd)); + RevokeDragDrop (msg->hwnd); + CoLockObjectExternal (idtp, FALSE, TRUE); + } +#endif + return GDK_FILTER_CONTINUE; +} + +void +gdk_window_register_dnd (GdkWindow *window) +{ + GdkDrawablePrivate *private = (GdkDrawablePrivate *) window; +#ifdef OLE2_DND + target_drag_context *context; + HRESULT hres; +#endif + + g_return_if_fail (window != NULL); + + GDK_NOTE (DND, g_print ("gdk_window_register_dnd: %#x\n", private->xwindow)); + + /* We always claim to accept dropped files, but in fact we might not, + * of course. This function is called in such a way that it cannot know + * whether the window (widget) in question actually accepts files + * (in gtk, data of type text/uri-list) or not. + */ + gdk_window_add_filter (window, gdk_dropfiles_filter, NULL); + DragAcceptFiles (private->xwindow, TRUE); + +#ifdef OLE2_DND + /* Register for OLE2 d&d */ + context = target_context_new (); + hres = CoLockObjectExternal ((IUnknown *) &context->idt, TRUE, FALSE); + if (!SUCCEEDED (hres)) + g_warning ("gdk_window_register_dnd: CoLockObjectExternal failed"); + else + { + hres = RegisterDragDrop (private->xwindow, &context->idt); + if (hres == DRAGDROP_E_ALREADYREGISTERED) + { + g_print ("DRAGDROP_E_ALREADYREGISTERED\n"); + CoLockObjectExternal ((IUnknown *) &context->idt, FALSE, FALSE); + } + else if (!SUCCEEDED (hres)) + g_warning ("gdk_window_register_dnd: RegisterDragDrop failed"); + else + { + gdk_window_add_filter (window, gdk_destroy_filter, &context->idt); + } + } +#endif +} + +/************************************************************* + * gdk_drag_get_selection: + * Returns the selection atom for the current source window + * arguments: + * + * results: + *************************************************************/ + +GdkAtom +gdk_drag_get_selection (GdkDragContext *context) +{ + if (context->protocol == GDK_DRAG_PROTO_WIN32_DROPFILES) + return gdk_win32_dropfiles_atom; + else if (context->protocol == GDK_DRAG_PROTO_OLE2) + return gdk_ole2_dnd_atom; + else + return GDK_NONE; +} diff --git a/gdk/win32/gdkdnd.c b/gdk/win32/gdkdnd.c new file mode 100644 index 000000000..da6da4bb5 --- /dev/null +++ b/gdk/win32/gdkdnd.c @@ -0,0 +1,973 @@ +/* GDK - The GIMP Drawing Kit + * Copyright (C) 1995-1999 Peter Mattis, Spencer Kimball and Josh MacDonald + * Copyright (C) 1998-1999 Tor Lillqvist + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* + * Modified by the GTK+ Team and others 1997-1999. See the AUTHORS + * file for a list of people on the GTK+ Team. See the ChangeLog + * files for a list of changes. These files are distributed with + * GTK+ at ftp://ftp.gtk.org/pub/gtk/. + */ + +#include "config.h" + +#include + +/* #define OLE2_DND */ + +#define INITGUID + +#include "gdkdnd.h" +#include "gdkproperty.h" +#include "gdkprivate.h" +#include "gdkx.h" + +#ifdef OLE2_DND +#include +#else +#include +#endif + +#ifdef _MSC_VER /* These aren't in mingw32 */ +#include +#include +#endif + +#ifndef _MSC_VER +static IID IID_IUnknown = { + 0x00000000, 0x0000, 0x0000, { 0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46 } }; +static IID IID_IDropSource = { + 0x00000121, 0x0000, 0x0000, { 0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46 } }; +static IID IID_IDropTarget = { + 0x00000122, 0x0000, 0x0000, { 0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46 } }; +#endif + +#include + +typedef struct _GdkDragContextPrivate GdkDragContextPrivate; + +typedef enum { + GDK_DRAG_STATUS_DRAG, + GDK_DRAG_STATUS_MOTION_WAIT, + GDK_DRAG_STATUS_ACTION_WAIT, + GDK_DRAG_STATUS_DROP +} GtkDragStatus; + +typedef enum { + GDK_DRAG_SOURCE, + GDK_DRAG_TARGET +} GdkDragKind; + +#ifdef OLE2_DND + +#define PRINT_GUID(guid) \ + g_print ("guid = %.08x-%.04x-%.04x-%.02x%.02x-%.02x%.02x%.02x%.02x%.02x%.02x", \ + ((gulong *) guid)[0], \ + ((gushort *) guid)[2], \ + ((gushort *) guid)[3], \ + ((guchar *) guid)[8], \ + ((guchar *) guid)[9], \ + ((guchar *) guid)[10], \ + ((guchar *) guid)[11], \ + ((guchar *) guid)[12], \ + ((guchar *) guid)[13], \ + ((guchar *) guid)[14], \ + ((guchar *) guid)[15]); + + +#endif /* OLE2_DND */ + +/* Structure that holds information about a drag in progress. + * this is used on both source and destination sides. + */ +struct _GdkDragContextPrivate { + GdkDragContext context; + + guint ref_count; + + guint16 last_x; /* Coordinates from last event */ + guint16 last_y; + HWND dest_xid; + guint drag_status; /* Current status of drag */ +}; + +GdkDragContext *current_dest_drag = NULL; + +/* Drag Contexts */ + +static GList *contexts; + +GdkDragContext * +gdk_drag_context_new (void) +{ + GdkDragContextPrivate *result; + + result = g_new0 (GdkDragContextPrivate, 1); + + result->ref_count = 1; + + contexts = g_list_prepend (contexts, result); + + return (GdkDragContext *)result; +} + +void +gdk_drag_context_ref (GdkDragContext *context) +{ + g_return_if_fail (context != NULL); + + ((GdkDragContextPrivate *)context)->ref_count++; +} + +void +gdk_drag_context_unref (GdkDragContext *context) +{ + GdkDragContextPrivate *private = (GdkDragContextPrivate *)context; + + g_return_if_fail (context != NULL); + + private->ref_count--; + + GDK_NOTE (DND, g_print ("gdk_drag_context_unref: %d%s\n", + private->ref_count, + (private->ref_count == 0 ? " freeing" : ""))); + + if (private->ref_count == 0) + { + g_dataset_destroy (private); + + g_list_free (context->targets); + + if (context->source_window) + gdk_window_unref (context->source_window); + + if (context->dest_window) + gdk_window_unref (context->dest_window); + + contexts = g_list_remove (contexts, private); + g_free (private); + } +} + +#if 0 + +static GdkDragContext * +gdk_drag_context_find (gboolean is_source, + HWND source_xid, + HWND dest_xid) +{ + GList *tmp_list = contexts; + GdkDragContext *context; + + while (tmp_list) + { + context = (GdkDragContext *)tmp_list->data; + + if ((!context->is_source == !is_source) && + ((source_xid == None) || (context->source_window && + (GDK_WINDOW_XWINDOW (context->source_window) == source_xid))) && + ((dest_xid == None) || (context->dest_window && + (GDK_WINDOW_XWINDOW (context->dest_window) == dest_xid)))) + return context; + + tmp_list = tmp_list->next; + } + + return NULL; +} + +#endif + +typedef struct { +#ifdef OLE2_DND + IDropTarget idt; +#endif + GdkDragContext *context; +} target_drag_context; + +typedef struct { +#ifdef OLE2_DND + IDropSource ids; +#endif + GdkDragContext *context; +} source_drag_context; + +#ifdef OLE2_DND + +static ULONG STDMETHODCALLTYPE +m_add_ref_target (IDropTarget __RPC_FAR *This) +{ + target_drag_context *ctx = (target_drag_context *) This; + GdkDragContextPrivate *private = (GdkDragContextPrivate *) ctx->context; + + GDK_NOTE (DND, g_print ("m_add_ref_target\n")); + gdk_drag_context_ref (ctx->context); + + return private->ref_count; +} + +static HRESULT STDMETHODCALLTYPE +m_query_interface_target (IDropTarget __RPC_FAR *This, + REFIID riid, + void __RPC_FAR *__RPC_FAR *ppvObject) +{ + GDK_NOTE (DND, g_print ("m_query_interface_target\n")); + + *ppvObject = NULL; + + PRINT_GUID (riid); + + if (IsEqualGUID (riid, &IID_IUnknown)) + { + g_print ("...IUnknown\n"); + m_add_ref_target (This); + *ppvObject = This; + return S_OK; + } + else if (IsEqualGUID (riid, &IID_IDropTarget)) + { + g_print ("...IDropTarget\n"); + m_add_ref_target (This); + *ppvObject = This; + return S_OK; + } + else + { + g_print ("...Huh?\n"); + return E_NOINTERFACE; + } +} + +static ULONG STDMETHODCALLTYPE +m_release_target (IDropTarget __RPC_FAR *This) +{ + target_drag_context *ctx = (target_drag_context *) This; + GdkDragContextPrivate *private = (GdkDragContextPrivate *) ctx->context; + + GDK_NOTE (DND, g_print ("m_release_target\n")); + gdk_drag_context_unref (ctx->context); + + if (private->ref_count == 1) + { + gdk_drag_context_unref (ctx->context); + return 0; + } + else + return private->ref_count - 1; +} + +static HRESULT STDMETHODCALLTYPE +m_drag_enter (IDropTarget __RPC_FAR *This, + IDataObject __RPC_FAR *pDataObj, + DWORD grfKeyState, + POINTL pt, + DWORD __RPC_FAR *pdwEffect) +{ + GDK_NOTE (DND, g_print ("m_drag_enter\n")); + return E_UNEXPECTED; +} + +static HRESULT STDMETHODCALLTYPE +m_drag_over (IDropTarget __RPC_FAR *This, + DWORD grfKeyState, + POINTL pt, + DWORD __RPC_FAR *pdwEffect) +{ + GDK_NOTE (DND, g_print ("m_drag_over\n")); + return E_UNEXPECTED; +} + +static HRESULT STDMETHODCALLTYPE +m_drag_leave (IDropTarget __RPC_FAR *This) +{ + GDK_NOTE (DND, g_print ("m_drag_leave\n")); + return E_UNEXPECTED; +} + +static HRESULT STDMETHODCALLTYPE +m_drop (IDropTarget __RPC_FAR *This, + IDataObject __RPC_FAR *pDataObj, + DWORD grfKeyState, + POINTL pt, + DWORD __RPC_FAR *pdwEffect) +{ + GDK_NOTE (DND, g_print ("m_drop\n")); + return E_UNEXPECTED; +} + +static ULONG STDMETHODCALLTYPE +m_add_ref_source (IDropSource __RPC_FAR *This) +{ + source_drag_context *ctx = (source_drag_context *) This; + GdkDragContextPrivate *private = (GdkDragContextPrivate *) ctx->context; + + GDK_NOTE (DND, g_print ("m_add_ref_source\n")); + gdk_drag_context_ref (ctx->context); + + return private->ref_count; +} + +static HRESULT STDMETHODCALLTYPE +m_query_interface_source (IDropSource __RPC_FAR *This, + REFIID riid, + void __RPC_FAR *__RPC_FAR *ppvObject) +{ + GDK_NOTE (DND, g_print ("m_query_interface_source\n")); + + *ppvObject = NULL; + + PRINT_GUID (riid); + if (IsEqualGUID (riid, &IID_IUnknown)) + { + g_print ("...IUnknown\n"); + m_add_ref_source (This); + *ppvObject = This; + return S_OK; + } + else if (IsEqualGUID (riid, &IID_IDropSource)) + { + g_print ("...IDropSource\n"); + m_add_ref_source (This); + *ppvObject = This; + return S_OK; + } + else + { + g_print ("...Huh?\n"); + return E_NOINTERFACE; + } +} + +static ULONG STDMETHODCALLTYPE +m_release_source (IDropSource __RPC_FAR *This) +{ + source_drag_context *ctx = (source_drag_context *) This; + GdkDragContextPrivate *private = (GdkDragContextPrivate *) ctx->context; + + GDK_NOTE (DND, g_print ("m_release_source\n")); + gdk_drag_context_unref (ctx->context); + + if (private->ref_count == 1) + { + gdk_drag_context_unref (ctx->context); + return 0; + } + else + return private->ref_count - 1; +} + +static HRESULT STDMETHODCALLTYPE +m_query_continue_drag (IDropSource __RPC_FAR *This, + BOOL fEscapePressed, + DWORD grfKeyState) +{ + GDK_NOTE (DND, g_print ("m_query_continue_drag\n")); + return E_UNEXPECTED; +} + +static HRESULT STDMETHODCALLTYPE +m_give_feedback (IDropSource __RPC_FAR *This, + DWORD dwEffect) +{ + GDK_NOTE (DND, g_print ("m_give_feedback\n")); + return E_UNEXPECTED; +} + +static HRESULT STDMETHODCALLTYPE +m_query_interface_object (IDataObject __RPC_FAR *This, + REFIID riid, + void __RPC_FAR *__RPC_FAR *ppvObject) +{ + return E_UNEXPECTED; +} + +static ULONG STDMETHODCALLTYPE +m_add_ref_object (IDataObject __RPC_FAR *This) +{ + return E_UNEXPECTED; +} + +static ULONG STDMETHODCALLTYPE +m_release_object (IDataObject __RPC_FAR *This) +{ + return E_UNEXPECTED; +} + +static HRESULT STDMETHODCALLTYPE +m_get_data (IDataObject __RPC_FAR *This, + FORMATETC *pFormatEtc, + STGMEDIUM *pMedium) +{ + return E_UNEXPECTED; +} + +static HRESULT STDMETHODCALLTYPE +m_get_data_here (IDataObject __RPC_FAR *This, + FORMATETC *pFormatEtc, + STGMEDIUM *pMedium) +{ + return E_UNEXPECTED; +} + +static HRESULT STDMETHODCALLTYPE +m_query_get_data (IDataObject __RPC_FAR *This, + FORMATETC *pFormatEtc) +{ + return E_UNEXPECTED; +} + +static HRESULT STDMETHODCALLTYPE +m_get_canonical_format_etc (IDataObject __RPC_FAR *This, + FORMATETC *pFormatEtcIn, + FORMATETC *pFormatEtcOut) +{ + return E_UNEXPECTED; +} + +static HRESULT STDMETHODCALLTYPE +m_set_data (IDataObject __RPC_FAR *This, + FORMATETC *pFormatEtc, + STGMEDIUM *pMedium, + BOOL fRelease) +{ + return E_UNEXPECTED; +} + +static HRESULT STDMETHODCALLTYPE +m_enum_format_etc (IDataObject __RPC_FAR *This, + DWORD dwDirection, + IEnumFORMATETC **ppEnumFormatEtc) +{ + return E_UNEXPECTED; +} + +static HRESULT STDMETHODCALLTYPE + m_d_advise (IDataObject __RPC_FAR *This, + FORMATETC *pFormatetc, + DWORD advf, + IAdviseSink *pAdvSink, + DWORD *pdwConnection) +{ + return E_UNEXPECTED; +} + +static HRESULT STDMETHODCALLTYPE + m_d_unadvise (IDataObject __RPC_FAR *This, + DWORD dwConnection) +{ + return E_UNEXPECTED; +} + +static HRESULT STDMETHODCALLTYPE +m_enum_d_advise (IDataObject __RPC_FAR *This, + IEnumSTATDATA **ppenumAdvise) +{ + return E_UNEXPECTED; +} + +static IDropTargetVtbl idt_vtbl = { + m_query_interface_target, + m_add_ref_target, + m_release_target, + m_drag_enter, + m_drag_over, + m_drag_leave, + m_drop +}; + +static IDropSourceVtbl ids_vtbl = { + m_query_interface_source, + m_add_ref_source, + m_release_source, + m_query_continue_drag, + m_give_feedback +}; + +static IDataObjectVtbl ido_vtbl = { + m_query_interface_object, + m_add_ref_object, + m_release_object, + m_get_data, + m_get_data_here, + m_query_get_data, + m_get_canonical_format_etc, + m_set_data, + m_enum_format_etc, + m_d_advise, + m_d_unadvise, + m_enum_d_advise +}; + +#endif /* OLE2_DND */ + +static target_drag_context * +target_context_new (void) +{ + target_drag_context *result; + + result = g_new0 (target_drag_context, 1); + +#ifdef OLE2_DND + result->idt.lpVtbl = &idt_vtbl; +#endif + + result->context = gdk_drag_context_new (); + + return result; +} + +static source_drag_context * +source_context_new (void) +{ + source_drag_context *result; + + result = g_new0 (source_drag_context, 1); + +#ifdef OLE2_DND + result->ids.lpVtbl = &ids_vtbl; +#endif + + result->context = gdk_drag_context_new (); + + return result; +} + +#ifdef _MSC_VER + +/* From MS Knowledge Base article Q130698 */ + +/* resolve_link() fills the filename and path buffer + * with relevant information + * hWnd - calling app's window handle. + * + * lpszLinkName - name of the link file passed into the function. + * + * lpszPath - the buffer that will receive the file pathname. + */ + +static HRESULT +resolve_link(HWND hWnd, + LPCTSTR lpszLinkName, + LPSTR lpszPath, + LPSTR lpszDescription) +{ + HRESULT hres; + IShellLink *psl; + WIN32_FIND_DATA wfd; + + /* Assume Failure to start with: */ + *lpszPath = 0; + if (lpszDescription) + *lpszDescription = 0; + + /* Call CoCreateInstance to obtain the IShellLink interface + * pointer. This call fails if CoInitialize is not called, so it is + * assumed that CoInitialize has been called. + */ + + hres = CoCreateInstance (&CLSID_ShellLink, + NULL, + CLSCTX_INPROC_SERVER, + &IID_IShellLink, + (LPVOID *)&psl); + if (SUCCEEDED (hres)) + { + IPersistFile *ppf; + + /* The IShellLink interface supports the IPersistFile + * interface. Get an interface pointer to it. + */ + hres = psl->lpVtbl->QueryInterface (psl, + &IID_IPersistFile, + (LPVOID *) &ppf); + if (SUCCEEDED (hres)) + { + WORD wsz[MAX_PATH]; + + /* Convert the given link name string to wide character string. */ + MultiByteToWideChar (CP_ACP, 0, + lpszLinkName, + -1, wsz, MAX_PATH); + /* Load the file. */ + hres = ppf->lpVtbl->Load (ppf, wsz, STGM_READ); + if (SUCCEEDED (hres)) + { + /* Resolve the link by calling the Resolve() + * interface function. + */ + hres = psl->lpVtbl->Resolve(psl, hWnd, + SLR_ANY_MATCH | + SLR_NO_UI); + if (SUCCEEDED (hres)) + { + hres = psl->lpVtbl->GetPath (psl, lpszPath, + MAX_PATH, + (WIN32_FIND_DATA*)&wfd, + 0); + + if (SUCCEEDED (hres) && lpszDescription != NULL) + { + hres = psl->lpVtbl->GetDescription (psl, + lpszDescription, + MAX_PATH ); + + if (!SUCCEEDED (hres)) + return FALSE; + } + } + } + ppf->lpVtbl->Release (ppf); + } + psl->lpVtbl->Release (psl); + } + return SUCCEEDED (hres); +} + +#else + +#define resolve_link(hWnd, lpszLinkName, lpszPath, lpszDescription) FALSE + +#endif + +static GdkFilterReturn +gdk_dropfiles_filter (GdkXEvent *xev, + GdkEvent *event, + gpointer data) +{ + GdkDragContext *context; + GdkDragContextPrivate *private; + static GdkAtom text_uri_list_atom = GDK_NONE; + GString *result; + MSG *msg = (MSG *) xev; + HANDLE hdrop; + POINT pt; + gint nfiles, i, k; + guchar fileName[MAX_PATH], linkedFile[MAX_PATH]; + + if (text_uri_list_atom == GDK_NONE) + text_uri_list_atom = gdk_atom_intern ("text/uri-list", FALSE); + + if (msg->message == WM_DROPFILES) + { + GDK_NOTE (DND, g_print ("WM_DROPFILES: %#x\n", msg->hwnd)); + + context = gdk_drag_context_new (); + private = (GdkDragContextPrivate *) context; + context->protocol = GDK_DRAG_PROTO_WIN32_DROPFILES; + context->is_source = FALSE; + context->source_window = (GdkWindow *) gdk_root_parent; + context->dest_window = event->any.window; + gdk_window_ref (context->dest_window); + /* WM_DROPFILES drops are always file names */ + context->targets = + g_list_append (NULL, GUINT_TO_POINTER (text_uri_list_atom)); + current_dest_drag = context; + + event->dnd.type = GDK_DROP_START; + event->dnd.context = current_dest_drag; + gdk_drag_context_ref (current_dest_drag); + + hdrop = (HANDLE) msg->wParam; + DragQueryPoint (hdrop, &pt); + ClientToScreen (msg->hwnd, &pt); + + event->dnd.x_root = pt.x; + event->dnd.y_root = pt.y; + event->dnd.time = msg->time; + + nfiles = DragQueryFile (hdrop, 0xFFFFFFFF, NULL, 0); + + result = g_string_new (NULL); + for (i = 0; i < nfiles; i++) + { + g_string_append (result, "file:"); + DragQueryFile (hdrop, i, fileName, MAX_PATH); + + /* Resolve shortcuts */ + if (resolve_link (msg->hwnd, fileName, linkedFile, NULL)) + { + g_string_append (result, linkedFile); + GDK_NOTE (DND, g_print ("...%s link to %s\n", + fileName, linkedFile)); + } + else + { + g_string_append (result, fileName); + GDK_NOTE (DND, g_print ("...%s\n", fileName)); + } + g_string_append (result, "\015\012"); + } + gdk_sel_prop_store ((GdkWindow *) gdk_root_parent, + text_uri_list_atom, 8, result->str, result->len + 1); + + DragFinish (hdrop); + + return GDK_FILTER_TRANSLATE; + } + else + return GDK_FILTER_CONTINUE; +} + +/************************************************************* + ************************** Public API *********************** + *************************************************************/ + +void +gdk_dnd_init (void) +{ + HRESULT hres; +#ifdef OLE2_DND + hres = OleInitialize (NULL); + + if (! SUCCEEDED (hres)) + g_error ("OleInitialize failed"); +#endif +} + +void +gdk_dnd_exit (void) +{ +#ifdef OLE2_DND + OleUninitialize (); +#endif +} + +/* Source side */ + +static void +gdk_drag_do_leave (GdkDragContext *context, guint32 time) +{ + if (context->dest_window) + { + GDK_NOTE (DND, g_print ("gdk_drag_do_leave\n")); + gdk_window_unref (context->dest_window); + context->dest_window = NULL; + } +} + +GdkDragContext * +gdk_drag_begin (GdkWindow *window, + GList *targets) +{ + GList *tmp_list; + source_drag_context *ctx; + + g_return_val_if_fail (window != NULL, NULL); + + GDK_NOTE (DND, g_print ("gdk_drag_begin\n")); + + ctx = source_context_new (); + ctx->context->is_source = TRUE; + ctx->context->source_window = window; + gdk_window_ref (window); + + tmp_list = g_list_last (targets); + ctx->context->targets = NULL; + while (tmp_list) + { + ctx->context->targets = g_list_prepend (ctx->context->targets, + tmp_list->data); + tmp_list = tmp_list->prev; + } + + ctx->context->actions = 0; + +#if 0 + DoDragDrop (...); +#endif + return ctx->context; +} + +guint32 +gdk_drag_get_protocol (guint32 xid, + GdkDragProtocol *protocol) +{ + /* This isn't used */ + return 0; +} + +void +gdk_drag_find_window (GdkDragContext *context, + GdkWindow *drag_window, + gint x_root, + gint y_root, + GdkWindow **dest_window, + GdkDragProtocol *protocol) +{ + GdkDragContextPrivate *private = (GdkDragContextPrivate *)context; + GdkDrawablePrivate *drag_window_private = (GdkDrawablePrivate*) drag_window; + HWND recipient; + POINT pt; + + GDK_NOTE (DND, g_print ("gdk_drag_find_window: %#x +%d+%d\n", + (drag_window ? drag_window_private->xwindow : 0), + x_root, y_root)); + + pt.x = x_root; + pt.y = y_root; + recipient = WindowFromPoint (pt); + if (recipient == NULL) + *dest_window = NULL; + else + { + *dest_window = gdk_window_lookup (recipient); + if (*dest_window) + gdk_window_ref (*dest_window); + *protocol = GDK_DRAG_PROTO_WIN32_DROPFILES; + } +} + +gboolean +gdk_drag_motion (GdkDragContext *context, + GdkWindow *dest_window, + GdkDragProtocol protocol, + gint x_root, + gint y_root, + GdkDragAction suggested_action, + GdkDragAction possible_actions, + guint32 time) +{ + return FALSE; +} + +void +gdk_drag_drop (GdkDragContext *context, + guint32 time) +{ + g_return_if_fail (context != NULL); + + g_warning ("gdk_drag_drop: not implemented\n"); +} + +void +gdk_drag_abort (GdkDragContext *context, + guint32 time) +{ + g_return_if_fail (context != NULL); + + gdk_drag_do_leave (context, time); +} + +/* Destination side */ + +void +gdk_drag_status (GdkDragContext *context, + GdkDragAction action, + guint32 time) +{ + GDK_NOTE (DND, g_print ("gdk_drag_status\n")); +} + +void +gdk_drop_reply (GdkDragContext *context, + gboolean ok, + guint32 time) +{ +} + +void +gdk_drop_finish (GdkDragContext *context, + gboolean success, + guint32 time) +{ +} + +static GdkFilterReturn +gdk_destroy_filter (GdkXEvent *xev, + GdkEvent *event, + gpointer data) +{ +#ifdef OLE2_DND + MSG *msg = (MSG *) xev; + + if (msg->message == WM_DESTROY) + { + IDropTarget *idtp = (IDropTarget *) data; + + GDK_NOTE (DND, g_print ("gdk_destroy_filter: WM_DESTROY: %#x\n", msg->hwnd)); + RevokeDragDrop (msg->hwnd); + CoLockObjectExternal (idtp, FALSE, TRUE); + } +#endif + return GDK_FILTER_CONTINUE; +} + +void +gdk_window_register_dnd (GdkWindow *window) +{ + GdkDrawablePrivate *private = (GdkDrawablePrivate *) window; +#ifdef OLE2_DND + target_drag_context *context; + HRESULT hres; +#endif + + g_return_if_fail (window != NULL); + + GDK_NOTE (DND, g_print ("gdk_window_register_dnd: %#x\n", private->xwindow)); + + /* We always claim to accept dropped files, but in fact we might not, + * of course. This function is called in such a way that it cannot know + * whether the window (widget) in question actually accepts files + * (in gtk, data of type text/uri-list) or not. + */ + gdk_window_add_filter (window, gdk_dropfiles_filter, NULL); + DragAcceptFiles (private->xwindow, TRUE); + +#ifdef OLE2_DND + /* Register for OLE2 d&d */ + context = target_context_new (); + hres = CoLockObjectExternal ((IUnknown *) &context->idt, TRUE, FALSE); + if (!SUCCEEDED (hres)) + g_warning ("gdk_window_register_dnd: CoLockObjectExternal failed"); + else + { + hres = RegisterDragDrop (private->xwindow, &context->idt); + if (hres == DRAGDROP_E_ALREADYREGISTERED) + { + g_print ("DRAGDROP_E_ALREADYREGISTERED\n"); + CoLockObjectExternal ((IUnknown *) &context->idt, FALSE, FALSE); + } + else if (!SUCCEEDED (hres)) + g_warning ("gdk_window_register_dnd: RegisterDragDrop failed"); + else + { + gdk_window_add_filter (window, gdk_destroy_filter, &context->idt); + } + } +#endif +} + +/************************************************************* + * gdk_drag_get_selection: + * Returns the selection atom for the current source window + * arguments: + * + * results: + *************************************************************/ + +GdkAtom +gdk_drag_get_selection (GdkDragContext *context) +{ + if (context->protocol == GDK_DRAG_PROTO_WIN32_DROPFILES) + return gdk_win32_dropfiles_atom; + else if (context->protocol == GDK_DRAG_PROTO_OLE2) + return gdk_ole2_dnd_atom; + else + return GDK_NONE; +} diff --git a/gdk/win32/gdkdraw.c b/gdk/win32/gdkdraw.c new file mode 100644 index 000000000..73f5e513d --- /dev/null +++ b/gdk/win32/gdkdraw.c @@ -0,0 +1,909 @@ +/* GDK - The GIMP Drawing Kit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* + * Modified by the GTK+ Team and others 1997-1999. See the AUTHORS + * file for a list of people on the GTK+ Team. See the ChangeLog + * files for a list of changes. These files are distributed with + * GTK+ at ftp://ftp.gtk.org/pub/gtk/. + */ + +#include "config.h" + +#include + +#include "gdkdrawable.h" +#include "gdkprivate.h" +#include "gdkwindow.h" +#include "gdkx.h" + +#ifndef G_PI +#define G_PI 3.14159265358979323846 +#endif + +/* Manipulation of drawables + */ +void +gdk_drawable_set_data (GdkDrawable *drawable, + const gchar *key, + gpointer data, + GDestroyNotify destroy_func) +{ + g_dataset_set_data_full (drawable, key, data, destroy_func); +} + +void +gdk_drawable_get_data (GdkDrawable *drawable, + const gchar *key) +{ + g_dataset_get_data (drawable, key); +} + +GdkDrawableType +gdk_drawable_get_type (GdkDrawable *drawable) +{ + g_return_val_if_fail (drawable != NULL, (GdkDrawableType) -1); + + return GDK_DRAWABLE_TYPE (drawable); +} + +void +gdk_drawable_get_size (GdkDrawable *drawable, + gint *width, + gint *height) +{ + GdkDrawablePrivate *drawable_private; + + g_return_if_fail (drawable != NULL); + + drawable_private = (GdkDrawablePrivate*) drawable; + + if (width) + *width = drawable_private->width; + if (height) + *height = drawable_private->height; +} + +void +gdk_drawable_set_colormap (GdkDrawable *drawable, + GdkColormap *colormap) +{ + GdkDrawablePrivate *drawable_private; + GdkColormapPrivate *colormap_private; + + g_return_if_fail (drawable != NULL); + g_return_if_fail (colormap != NULL); + + drawable_private = (GdkDrawablePrivate*) drawable; + colormap_private = (GdkColormapPrivate*) colormap; + + if (!GDK_DRAWABLE_DESTROYED (drawable)) + { + if (GDK_IS_WINDOW (drawable)) + { + g_return_if_fail (colormap_private->visual != + ((GdkColormapPrivate*)(drawable_private->colormap))->visual); + /* XXX ??? */ + GDK_NOTE (MISC, g_print ("gdk_drawable_set_colormap: %#x %#x\n", + GDK_DRAWABLE_XID (drawable), + colormap_private->xcolormap)); + } + if (drawable_private->colormap) + gdk_colormap_unref (drawable_private->colormap); + drawable_private->colormap = colormap; + gdk_colormap_ref (drawable_private->colormap); + + if (GDK_IS_WINDOW (drawable) && + drawable_private->window_type != GDK_WINDOW_TOPLEVEL) + gdk_window_add_colormap_windows (drawable); + } +} + +GdkColormap* +gdk_drawable_get_colormap (GdkDrawable *drawable) +{ + GdkDrawablePrivate *drawable_private; + + g_return_val_if_fail (drawable != NULL, NULL); + drawable_private = (GdkDrawablePrivate*) drawable; + + if (!GDK_DRAWABLE_DESTROYED (drawable)) + { + if (drawable_private->colormap == NULL) + return gdk_colormap_get_system (); /* XXX ??? */ + else + return drawable_private->colormap; + } + + return NULL; +} + +GdkVisual* +gdk_drawable_get_visual (GdkDrawable *drawable) +{ + GdkColormap *colormap; + + g_return_val_if_fail (drawable != NULL, NULL); + + colormap = gdk_drawable_get_colormap (drawable); + return colormap ? gdk_colormap_get_visual (colormap) : NULL; +} + +void +gdk_draw_point (GdkDrawable *drawable, + GdkGC *gc, + gint x, + gint y) +{ + GdkDrawablePrivate *drawable_private; + GdkGCPrivate *gc_private; + HDC hdc; + + g_return_if_fail (drawable != NULL); + g_return_if_fail (gc != NULL); + + if (GDK_DRAWABLE_DESTROYED (drawable)) + return; + drawable_private = (GdkDrawablePrivate*) drawable; + gc_private = (GdkGCPrivate*) gc; + + hdc = gdk_gc_predraw (drawable_private, gc_private); + + /* We use LineTo because SetPixel wants the COLORREF directly, + * and doesn't use the current pen, which is what we want. + */ + if (!MoveToEx (hdc, x, y, NULL)) + g_warning ("gdk_draw_point: MoveToEx failed"); + if (!LineTo (hdc, x + 1, y)) + g_warning ("gdk_draw_point: LineTo failed"); + + gdk_gc_postdraw (drawable_private, gc_private); +} + +void +gdk_draw_line (GdkDrawable *drawable, + GdkGC *gc, + gint x1, + gint y1, + gint x2, + gint y2) +{ + GdkDrawablePrivate *drawable_private; + GdkGCPrivate *gc_private; + HDC hdc; + + g_return_if_fail (drawable != NULL); + g_return_if_fail (gc != NULL); + + if (GDK_DRAWABLE_DESTROYED (drawable)) + return; + drawable_private = (GdkDrawablePrivate*) drawable; + gc_private = (GdkGCPrivate*) gc; + + hdc = gdk_gc_predraw (drawable_private, gc_private); + + GDK_NOTE (MISC, g_print ("gdk_draw_line: %#x (%d) +%d+%d..+%d+%d\n", + drawable_private->xwindow, gc_private, + x1, y1, x2, y2)); + + MoveToEx (hdc, x1, y1, NULL); + if (!LineTo (hdc, x2, y2)) + g_warning ("gdk_draw_line: LineTo #1 failed"); + /* LineTo doesn't draw the last point, so if we have a pen width of 1, + * we draw the end pixel separately... With wider pens we don't care. + * //HB: But the NT developers don't read their API documentation ... + */ + if (gc_private->pen_width == 1 && windows_version > 0x80000000) + if (!LineTo (hdc, x2 + 1, y2)) + g_warning ("gdk_draw_line: LineTo #2 failed"); + gdk_gc_postdraw (drawable_private, gc_private); +} + +void +gdk_draw_rectangle (GdkDrawable *drawable, + GdkGC *gc, + gint filled, + gint x, + gint y, + gint width, + gint height) +{ + GdkDrawablePrivate *drawable_private; + GdkGCPrivate *gc_private; + HDC hdc; + HGDIOBJ oldpen, oldbrush; + + g_return_if_fail (drawable != NULL); + g_return_if_fail (gc != NULL); + + if (GDK_DRAWABLE_DESTROYED (drawable)) + return; + drawable_private = (GdkDrawablePrivate*) drawable; + gc_private = (GdkGCPrivate*) gc; + + if (width == -1) + width = drawable_private->width; + if (height == -1) + height = drawable_private->height; + + hdc = gdk_gc_predraw (drawable_private, gc_private); + + GDK_NOTE (MISC, g_print ("gdk_draw_rectangle: %#x (%d) %s%dx%d@+%d+%d\n", + drawable_private->xwindow, + gc_private, + (filled ? "fill " : ""), + width, height, x, y)); + +#if 0 + { + HBRUSH hbr = GetCurrentObject (hdc, OBJ_BRUSH); + HPEN hpen = GetCurrentObject (hdc, OBJ_PEN); + LOGBRUSH lbr; + LOGPEN lpen; + GetObject (hbr, sizeof (lbr), &lbr); + GetObject (hpen, sizeof (lpen), &lpen); + + g_print ("current brush: style = %s, color = 0x%.08x\n", + (lbr.lbStyle == BS_SOLID ? "SOLID" : "???"), + lbr.lbColor); + g_print ("current pen: style = %s, width = %d, color = 0x%.08x\n", + (lpen.lopnStyle == PS_SOLID ? "SOLID" : "???"), + lpen.lopnWidth, + lpen.lopnColor); + } +#endif + + if (filled) + oldpen = SelectObject (hdc, GetStockObject (NULL_PEN)); + else + oldbrush = SelectObject (hdc, GetStockObject (HOLLOW_BRUSH)); + + if (!Rectangle (hdc, x, y, x+width+1, y+height+1)) + g_warning ("gdk_draw_rectangle: Rectangle failed"); + + if (filled) + SelectObject (hdc, oldpen); + else + SelectObject (hdc, oldbrush); + + gdk_gc_postdraw (drawable_private, gc_private); +} + +void +gdk_draw_arc (GdkDrawable *drawable, + GdkGC *gc, + gint filled, + gint x, + gint y, + gint width, + gint height, + gint angle1, + gint angle2) +{ + GdkDrawablePrivate *drawable_private; + GdkGCPrivate *gc_private; + HDC hdc; + int nXStartArc, nYStartArc, nXEndArc, nYEndArc; + + g_return_if_fail (drawable != NULL); + g_return_if_fail (gc != NULL); + + if (GDK_DRAWABLE_DESTROYED (drawable)) + return; + drawable_private = (GdkDrawablePrivate*) drawable; + gc_private = (GdkGCPrivate*) gc; + + if (width == -1) + width = drawable_private->width; + if (height == -1) + height = drawable_private->height; + + GDK_NOTE (MISC, g_print ("gdk_draw_arc: %#x %d,%d,%d,%d %d %d\n", + drawable_private->xwindow, + x, y, width, height, angle1, angle2)); + + if (width != 0 && height != 0 && angle2 != 0) + { + hdc = gdk_gc_predraw (drawable_private, gc_private); + + if (angle2 >= 360*64) + { + nXStartArc = nYStartArc = nXEndArc = nYEndArc = 0; + } + else if (angle2 > 0) + { + /* The 100. is just an arbitrary value */ + nXStartArc = x + width/2 + 100. * cos(angle1/64.*2.*G_PI/360.); + nYStartArc = y + height/2 + -100. * sin(angle1/64.*2.*G_PI/360.); + nXEndArc = x + width/2 + 100. * cos((angle1+angle2)/64.*2.*G_PI/360.); + nYEndArc = y + height/2 + -100. * sin((angle1+angle2)/64.*2.*G_PI/360.); + } + else + { + nXEndArc = x + width/2 + 100. * cos(angle1/64.*2.*G_PI/360.); + nYEndArc = y + height/2 + -100. * sin(angle1/64.*2.*G_PI/360.); + nXStartArc = x + width/2 + 100. * cos((angle1+angle2)/64.*2.*G_PI/360.); + nYStartArc = y + height/2 + -100. * sin((angle1+angle2)/64.*2.*G_PI/360.); + } + + if (filled) + { + GDK_NOTE (MISC, g_print ("...Pie(hdc,%d,%d,%d,%d,%d,%d,%d,%d)\n", + x, y, x+width, y+height, + nXStartArc, nYStartArc, + nXEndArc, nYEndArc)); + Pie (hdc, x, y, x+width, y+height, + nXStartArc, nYStartArc, nXEndArc, nYEndArc); + } + else + { + GDK_NOTE (MISC, g_print ("...Arc(hdc,%d,%d,%d,%d,%d,%d,%d,%d)\n", + x, y, x+width, y+height, + nXStartArc, nYStartArc, + nXEndArc, nYEndArc)); + Arc (hdc, x, y, x+width, y+height, + nXStartArc, nYStartArc, nXEndArc, nYEndArc); + } + gdk_gc_postdraw (drawable_private, gc_private); + } +} + +void +gdk_draw_polygon (GdkDrawable *drawable, + GdkGC *gc, + gint filled, + GdkPoint *points, + gint npoints) +{ + GdkDrawablePrivate *drawable_private; + GdkGCPrivate *gc_private; + HDC hdc; + POINT *pts; + int i; + + g_return_if_fail (drawable != NULL); + g_return_if_fail (gc != NULL); + + if (GDK_DRAWABLE_DESTROYED (drawable)) + return; + drawable_private = (GdkDrawablePrivate*) drawable; + gc_private = (GdkGCPrivate*) gc; + + GDK_NOTE (MISC, g_print ("gdk_draw_polygon: %#x (%d) %d\n", + drawable_private->xwindow, gc_private, + npoints)); + + if (npoints < 2) + return; + + hdc = gdk_gc_predraw (drawable_private, gc_private); + pts = g_malloc ((npoints+1) * sizeof (POINT)); + + for (i = 0; i < npoints; i++) + { + pts[i].x = points[i].x; + pts[i].y = points[i].y; + } + + if ((points[0].x != points[npoints-1].x) || + (points[0].y != points[npoints-1].y)) + { + pts[npoints].x = points[0].x; + pts[npoints].y = points[0].y; + npoints++; + } + if (filled) + { + if (!Polygon (hdc, pts, npoints)) + g_warning ("gdk_draw_polygon: Polygon failed"); + } + else + { + if (!Polyline (hdc, pts, npoints)) + g_warning ("gdk_draw_polygon: Polyline failed"); + } + g_free (pts); + gdk_gc_postdraw (drawable_private, gc_private); +} + +typedef struct +{ + gint x, y; + HDC hdc; +} gdk_draw_text_arg; + +/* gdk_draw_string + */ +void +gdk_draw_string (GdkDrawable *drawable, + GdkFont *font, + GdkGC *gc, + gint x, + gint y, + const gchar *string) +{ + gdk_draw_text (drawable, font, gc, x, y, string, strlen (string)); +} + +static void +gdk_draw_text_handler (GdkWin32SingleFont *singlefont, + const wchar_t *wcstr, + int wclen, + void *arg) +{ + HGDIOBJ oldfont; + SIZE size; + gdk_draw_text_arg *argp = (gdk_draw_text_arg *) arg; + + if (!singlefont) + return; + + if ((oldfont = SelectObject (argp->hdc, singlefont->xfont)) == NULL) + { + g_warning ("gdk_draw_text_handler: SelectObject failed"); + return; + } + + if (!TextOutW (argp->hdc, argp->x, argp->y, wcstr, wclen)) + g_warning ("gdk_draw_text_handler: TextOutW failed"); + GetTextExtentPoint32W (argp->hdc, wcstr, wclen, &size); + argp->x += size.cx; + + SelectObject (argp->hdc, oldfont); +} + +/* gdk_draw_text + * + */ +void +gdk_draw_text (GdkDrawable *drawable, + GdkFont *font, + GdkGC *gc, + gint x, + gint y, + const gchar *text, + gint text_length) +{ + GdkDrawablePrivate *drawable_private; + GdkGCPrivate *gc_private; + wchar_t *wcstr; + gint wlen; + gdk_draw_text_arg arg; + + g_return_if_fail (drawable != NULL); + g_return_if_fail (font != NULL); + g_return_if_fail (gc != NULL); + g_return_if_fail (text != NULL); + + if (GDK_DRAWABLE_DESTROYED (drawable)) + return; + + if (text_length == 0) + return; + + g_assert (font->type == GDK_FONT_FONT || font->type == GDK_FONT_FONTSET); + + drawable_private = (GdkDrawablePrivate*) drawable; + gc_private = (GdkGCPrivate*) gc; + + arg.x = x; + arg.y = y; + arg.hdc = gdk_gc_predraw (drawable_private, gc_private); + + GDK_NOTE (MISC, g_print ("gdk_draw_text: %#x (%d,%d) \"%.*s\" (len %d)\n", + drawable_private->xwindow, + x, y, + (text_length > 10 ? 10 : text_length), + text, text_length)); + + wcstr = g_new (wchar_t, text_length); + if ((wlen = gdk_nmbstowchar_ts (wcstr, text, text_length, text_length)) == -1) + g_warning ("gdk_draw_text: gdk_nmbstowchar_ts failed"); + else + gdk_wchar_text_handle (font, wcstr, wlen, + gdk_draw_text_handler, &arg); + + g_free (wcstr); + + gdk_gc_postdraw (drawable_private, gc_private); +} + +void +gdk_draw_text_wc (GdkDrawable *drawable, + GdkFont *font, + GdkGC *gc, + gint x, + gint y, + const GdkWChar *text, + gint text_length) +{ + GdkDrawablePrivate *drawable_private; + GdkGCPrivate *gc_private; + gint i, wlen; + wchar_t *wcstr; + gdk_draw_text_arg arg; + + g_return_if_fail (drawable != NULL); + g_return_if_fail (font != NULL); + g_return_if_fail (gc != NULL); + g_return_if_fail (text != NULL); + + if (GDK_DRAWABLE_DESTROYED (drawable)) + return; + + if (text_length == 0) + return; + + g_assert (font->type == GDK_FONT_FONT || font->type == GDK_FONT_FONTSET); + + drawable_private = (GdkDrawablePrivate*) drawable; + gc_private = (GdkGCPrivate*) gc; + + arg.x = x; + arg.y = y; + arg.hdc = gdk_gc_predraw (drawable_private, gc_private); + + GDK_NOTE (MISC, g_print ("gdk_draw_text_wc: %#x (%d,%d) len: %d\n", + drawable_private->xwindow, + x, y, text_length)); + + if (sizeof (wchar_t) != sizeof (GdkWChar)) + { + wcstr = g_new (wchar_t, text_length); + for (i = 0; i < text_length; i++) + wcstr[i] = text[i]; + } + else + wcstr = (wchar_t *) text; + + gdk_wchar_text_handle (font, wcstr, text_length, + gdk_draw_text_handler, &arg); + + if (sizeof (wchar_t) != sizeof (GdkWChar)) + g_free (wcstr); + + gdk_gc_postdraw (drawable_private, gc_private); +} + +void +gdk_draw_pixmap (GdkDrawable *drawable, + GdkGC *gc, + GdkPixmap *src, + gint xsrc, + gint ysrc, + gint xdest, + gint ydest, + gint width, + gint height) +{ + GdkDrawablePrivate *drawable_private; + GdkDrawablePrivate *src_private; + GdkGCPrivate *gc_private; + HDC hdc; + HDC srcdc; + HGDIOBJ hgdiobj; + HRGN src_rgn, draw_rgn, outside_rgn; + RECT r; + + g_return_if_fail (drawable != NULL); + g_return_if_fail (src != NULL); + g_return_if_fail (gc != NULL); + + if (GDK_DRAWABLE_DESTROYED (drawable) || GDK_DRAWABLE_DESTROYED (src)) + return; + drawable_private = (GdkDrawablePrivate*) drawable; + src_private = (GdkDrawablePrivate*) src; + gc_private = (GdkGCPrivate*) gc; + + if (width == -1) + width = src_private->width; /* Or should we subtract xsrc? */ + if (height == -1) + height = src_private->height; /* Ditto? */ + + GDK_NOTE (MISC, g_print ("gdk_draw_pixmap: dest: %#x " + "src: %#x %dx%d@+%d+%d" + " dest: %#x @+%d+%d\n", + drawable_private->xwindow, + src_private->xwindow, + width, height, xsrc, ysrc, + drawable_private->xwindow, xdest, ydest)); + + hdc = gdk_gc_predraw (drawable_private, gc_private); + + src_rgn = CreateRectRgn (0, 0, src_private->width + 1, src_private->height + 1); + draw_rgn = CreateRectRgn (xsrc, ysrc, xsrc + width + 1, ysrc + height + 1); + SetRectEmpty (&r); + outside_rgn = CreateRectRgnIndirect (&r); + + if (drawable_private->window_type != GDK_DRAWABLE_PIXMAP) + { + /* If we are drawing on a window, calculate the region that is + * outside the source pixmap, and invalidate that, causing it to + * be cleared. XXX + */ + if (CombineRgn (outside_rgn, draw_rgn, src_rgn, RGN_DIFF) != NULLREGION) + { + OffsetRgn (outside_rgn, xdest, ydest); + GDK_NOTE (MISC, (GetRgnBox (outside_rgn, &r), + g_print ("...calling InvalidateRgn, " + "bbox: %dx%d@+%d+%d\n", + r.right - r.left - 1, r.bottom - r.top - 1, + r.left, r.top))); + InvalidateRgn (drawable_private->xwindow, outside_rgn, TRUE); + } + } + +#if 1 /* Don't know if this is necessary */ + if (CombineRgn (draw_rgn, draw_rgn, src_rgn, RGN_AND) == COMPLEXREGION) + g_warning ("gdk_draw_pixmap: CombineRgn returned a COMPLEXREGION"); + + GetRgnBox (draw_rgn, &r); + if (r.left != xsrc + || r.top != ysrc + || r.right != xsrc + width + 1 + || r.bottom != ysrc + height + 1) + { + xdest += r.left - xsrc; + xsrc = r.left; + ydest += r.top - ysrc; + ysrc = r.top; + width = r.right - xsrc - 1; + height = r.bottom - ysrc - 1; + + GDK_NOTE (MISC, g_print ("... restricted to src: %dx%d@+%d+%d, " + "dest: @+%d+%d\n", + width, height, xsrc, ysrc, + xdest, ydest)); + } +#endif + + DeleteObject (src_rgn); + DeleteObject (draw_rgn); + DeleteObject (outside_rgn); + + /* Strangely enough, this function is called also to bitblt + * from a window. + */ + if (src_private->window_type == GDK_DRAWABLE_PIXMAP) + { + if ((srcdc = CreateCompatibleDC (hdc)) == NULL) + g_warning ("gdk_draw_pixmap: CreateCompatibleDC failed"); + + if ((hgdiobj = SelectObject (srcdc, src_private->xwindow)) == NULL) + g_warning ("gdk_draw_pixmap: SelectObject #1 failed"); + + if (!BitBlt (hdc, xdest, ydest, width, height, + srcdc, xsrc, ysrc, SRCCOPY)) + g_warning ("gdk_draw_pixmap: BitBlt failed"); + + if ((SelectObject (srcdc, hgdiobj) == NULL)) + g_warning ("gdk_draw_pixmap: SelectObject #2 failed"); + + if (!DeleteDC (srcdc)) + g_warning ("gdk_draw_pixmap: DeleteDC failed"); + } + else + { + if (drawable_private->xwindow == src_private->xwindow) + { + /* Blitting inside a window, use ScrollDC */ + RECT scrollRect, clipRect, emptyRect; + HRGN updateRgn; + + scrollRect.left = MIN (xsrc, xdest); + scrollRect.top = MIN (ysrc, ydest); + scrollRect.right = MAX (xsrc + width + 1, xdest + width + 1); + scrollRect.bottom = MAX (ysrc + height + 1, ydest + height + 1); + + clipRect.left = xdest; + clipRect.top = ydest; + clipRect.right = xdest + width + 1; + clipRect.bottom = ydest + height + 1; + + SetRectEmpty (&emptyRect); + updateRgn = CreateRectRgnIndirect (&emptyRect); + if (!ScrollDC (hdc, xdest - xsrc, ydest - ysrc, + &scrollRect, &clipRect, + updateRgn, NULL)) + g_warning ("gdk_draw_pixmap: ScrollDC failed"); + if (!InvalidateRgn (drawable_private->xwindow, updateRgn, FALSE)) + g_warning ("gdk_draw_pixmap: InvalidateRgn failed"); + if (!UpdateWindow (drawable_private->xwindow)) + g_warning ("gdk_draw_pixmap: UpdateWindow failed"); + } + else + { + if ((srcdc = GetDC (src_private->xwindow)) == NULL) + g_warning ("gdk_draw_pixmap: GetDC failed"); + + if (!BitBlt (hdc, xdest, ydest, width, height, + srcdc, xsrc, ysrc, SRCCOPY)) + g_warning ("gdk_draw_pixmap: BitBlt failed"); + ReleaseDC (src_private->xwindow, srcdc); + } + } + gdk_gc_postdraw (drawable_private, gc_private); +} + +void +gdk_draw_image (GdkDrawable *drawable, + GdkGC *gc, + GdkImage *image, + gint xsrc, + gint ysrc, + gint xdest, + gint ydest, + gint width, + gint height) +{ + GdkImagePrivate *image_private; + + g_return_if_fail (drawable != NULL); + g_return_if_fail (image != NULL); + g_return_if_fail (gc != NULL); + + image_private = (GdkImagePrivate*) image; + + g_return_if_fail (image_private->image_put != NULL); + + if (width == -1) + width = image->width; + if (height == -1) + height = image->height; + + (* image_private->image_put) (drawable, gc, image, xsrc, ysrc, + xdest, ydest, width, height); +} + +void +gdk_draw_points (GdkDrawable *drawable, + GdkGC *gc, + GdkPoint *points, + gint npoints) +{ + GdkDrawablePrivate *drawable_private; + GdkGCPrivate *gc_private; + HDC hdc; + int i; + + g_return_if_fail (drawable != NULL); + g_return_if_fail ((points != NULL) && (npoints > 0)); + g_return_if_fail (gc != NULL); + + if (GDK_DRAWABLE_DESTROYED (drawable)) + return; + drawable_private = (GdkDrawablePrivate*) drawable; + gc_private = (GdkGCPrivate*) gc; + + hdc = gdk_gc_predraw (drawable_private, gc_private); + + GDK_NOTE (MISC, g_print ("gdk_draw_points: %#x destdc: (%d) %#x " + "npoints: %d\n", + drawable_private->xwindow, gc_private, hdc, + npoints)); + + for (i = 0; i < npoints; i++) + { + if (!MoveToEx (hdc, points[i].x, points[i].y, NULL)) + g_warning ("gdk_draw_points: MoveToEx failed"); + if (!LineTo (hdc, points[i].x + 1, points[i].y)) + g_warning ("gdk_draw_points: LineTo failed"); + } + gdk_gc_postdraw (drawable_private, gc_private); +} + +void +gdk_draw_segments (GdkDrawable *drawable, + GdkGC *gc, + GdkSegment *segs, + gint nsegs) +{ + GdkDrawablePrivate *drawable_private; + GdkGCPrivate *gc_private; + HDC hdc; + int i; + + if (nsegs <= 0) + return; + + g_return_if_fail (drawable != NULL); + g_return_if_fail (segs != NULL); + g_return_if_fail (gc != NULL); + + if (GDK_DRAWABLE_DESTROYED (drawable)) + return; + drawable_private = (GdkDrawablePrivate*) drawable; + gc_private = (GdkGCPrivate*) gc; + + hdc = gdk_gc_predraw (drawable_private, gc_private); + + for (i = 0; i < nsegs; i++) + { + if (!MoveToEx (hdc, segs[i].x1, segs[i].y1, NULL)) + g_warning ("gdk_draw_segments: MoveToEx failed"); + if (!LineTo (hdc, segs[i].x2, segs[i].y2)) + g_warning ("gdk_draw_segments: LineTo #1 failed"); + + /* Draw end pixel */ + if (gc_private->pen_width == 1) + if (!LineTo (hdc, segs[i].x2 + 1, segs[i].y2)) + g_warning ("gdk_draw_segments: LineTo #2 failed"); + } + gdk_gc_postdraw (drawable_private, gc_private); +} + +void +gdk_draw_lines (GdkDrawable *drawable, + GdkGC *gc, + GdkPoint *points, + gint npoints) +{ + GdkDrawablePrivate *drawable_private; + GdkGCPrivate *gc_private; + HDC hdc; + POINT *pts; + int i; + + if (npoints < 2) + return; + + g_return_if_fail (drawable != NULL); + g_return_if_fail (points != NULL); + g_return_if_fail (gc != NULL); + + if (GDK_DRAWABLE_DESTROYED (drawable)) + return; + drawable_private = (GdkDrawablePrivate*) drawable; + gc_private = (GdkGCPrivate*) gc; + + hdc = gdk_gc_predraw (drawable_private, gc_private); +#if 1 + pts = g_malloc (npoints * sizeof (POINT)); + + for (i = 0; i < npoints; i++) + { + pts[i].x = points[i].x; + pts[i].y = points[i].y; + } + + if (!Polyline (hdc, pts, npoints)) + g_warning ("gdk_draw_lines: Polyline(,,%d) failed", npoints); + + g_free (pts); + + /* Draw end pixel */ + if (gc_private->pen_width == 1) + { + MoveToEx (hdc, points[npoints-1].x, points[npoints-1].y, NULL); + if (!LineTo (hdc, points[npoints-1].x + 1, points[npoints-1].y)) + g_warning ("gdk_draw_lines: LineTo failed"); + } +#else + MoveToEx (hdc, points[0].x, points[0].y, NULL); + for (i = 1; i < npoints; i++) + if (!LineTo (hdc, points[i].x, points[i].y)) + g_warning ("gdk_draw_lines: LineTo #1 failed"); + + /* Draw end pixel */ + if (gc_private->pen_width == 1) + if (!LineTo (hdc, points[npoints-1].x + 1, points[npoints-1].y)) + g_warning ("gdk_draw_lines: LineTo #2 failed"); +#endif + gdk_gc_postdraw (drawable_private, gc_private); +} diff --git a/gdk/win32/gdkdrawable-win32.c b/gdk/win32/gdkdrawable-win32.c new file mode 100644 index 000000000..73f5e513d --- /dev/null +++ b/gdk/win32/gdkdrawable-win32.c @@ -0,0 +1,909 @@ +/* GDK - The GIMP Drawing Kit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* + * Modified by the GTK+ Team and others 1997-1999. See the AUTHORS + * file for a list of people on the GTK+ Team. See the ChangeLog + * files for a list of changes. These files are distributed with + * GTK+ at ftp://ftp.gtk.org/pub/gtk/. + */ + +#include "config.h" + +#include + +#include "gdkdrawable.h" +#include "gdkprivate.h" +#include "gdkwindow.h" +#include "gdkx.h" + +#ifndef G_PI +#define G_PI 3.14159265358979323846 +#endif + +/* Manipulation of drawables + */ +void +gdk_drawable_set_data (GdkDrawable *drawable, + const gchar *key, + gpointer data, + GDestroyNotify destroy_func) +{ + g_dataset_set_data_full (drawable, key, data, destroy_func); +} + +void +gdk_drawable_get_data (GdkDrawable *drawable, + const gchar *key) +{ + g_dataset_get_data (drawable, key); +} + +GdkDrawableType +gdk_drawable_get_type (GdkDrawable *drawable) +{ + g_return_val_if_fail (drawable != NULL, (GdkDrawableType) -1); + + return GDK_DRAWABLE_TYPE (drawable); +} + +void +gdk_drawable_get_size (GdkDrawable *drawable, + gint *width, + gint *height) +{ + GdkDrawablePrivate *drawable_private; + + g_return_if_fail (drawable != NULL); + + drawable_private = (GdkDrawablePrivate*) drawable; + + if (width) + *width = drawable_private->width; + if (height) + *height = drawable_private->height; +} + +void +gdk_drawable_set_colormap (GdkDrawable *drawable, + GdkColormap *colormap) +{ + GdkDrawablePrivate *drawable_private; + GdkColormapPrivate *colormap_private; + + g_return_if_fail (drawable != NULL); + g_return_if_fail (colormap != NULL); + + drawable_private = (GdkDrawablePrivate*) drawable; + colormap_private = (GdkColormapPrivate*) colormap; + + if (!GDK_DRAWABLE_DESTROYED (drawable)) + { + if (GDK_IS_WINDOW (drawable)) + { + g_return_if_fail (colormap_private->visual != + ((GdkColormapPrivate*)(drawable_private->colormap))->visual); + /* XXX ??? */ + GDK_NOTE (MISC, g_print ("gdk_drawable_set_colormap: %#x %#x\n", + GDK_DRAWABLE_XID (drawable), + colormap_private->xcolormap)); + } + if (drawable_private->colormap) + gdk_colormap_unref (drawable_private->colormap); + drawable_private->colormap = colormap; + gdk_colormap_ref (drawable_private->colormap); + + if (GDK_IS_WINDOW (drawable) && + drawable_private->window_type != GDK_WINDOW_TOPLEVEL) + gdk_window_add_colormap_windows (drawable); + } +} + +GdkColormap* +gdk_drawable_get_colormap (GdkDrawable *drawable) +{ + GdkDrawablePrivate *drawable_private; + + g_return_val_if_fail (drawable != NULL, NULL); + drawable_private = (GdkDrawablePrivate*) drawable; + + if (!GDK_DRAWABLE_DESTROYED (drawable)) + { + if (drawable_private->colormap == NULL) + return gdk_colormap_get_system (); /* XXX ??? */ + else + return drawable_private->colormap; + } + + return NULL; +} + +GdkVisual* +gdk_drawable_get_visual (GdkDrawable *drawable) +{ + GdkColormap *colormap; + + g_return_val_if_fail (drawable != NULL, NULL); + + colormap = gdk_drawable_get_colormap (drawable); + return colormap ? gdk_colormap_get_visual (colormap) : NULL; +} + +void +gdk_draw_point (GdkDrawable *drawable, + GdkGC *gc, + gint x, + gint y) +{ + GdkDrawablePrivate *drawable_private; + GdkGCPrivate *gc_private; + HDC hdc; + + g_return_if_fail (drawable != NULL); + g_return_if_fail (gc != NULL); + + if (GDK_DRAWABLE_DESTROYED (drawable)) + return; + drawable_private = (GdkDrawablePrivate*) drawable; + gc_private = (GdkGCPrivate*) gc; + + hdc = gdk_gc_predraw (drawable_private, gc_private); + + /* We use LineTo because SetPixel wants the COLORREF directly, + * and doesn't use the current pen, which is what we want. + */ + if (!MoveToEx (hdc, x, y, NULL)) + g_warning ("gdk_draw_point: MoveToEx failed"); + if (!LineTo (hdc, x + 1, y)) + g_warning ("gdk_draw_point: LineTo failed"); + + gdk_gc_postdraw (drawable_private, gc_private); +} + +void +gdk_draw_line (GdkDrawable *drawable, + GdkGC *gc, + gint x1, + gint y1, + gint x2, + gint y2) +{ + GdkDrawablePrivate *drawable_private; + GdkGCPrivate *gc_private; + HDC hdc; + + g_return_if_fail (drawable != NULL); + g_return_if_fail (gc != NULL); + + if (GDK_DRAWABLE_DESTROYED (drawable)) + return; + drawable_private = (GdkDrawablePrivate*) drawable; + gc_private = (GdkGCPrivate*) gc; + + hdc = gdk_gc_predraw (drawable_private, gc_private); + + GDK_NOTE (MISC, g_print ("gdk_draw_line: %#x (%d) +%d+%d..+%d+%d\n", + drawable_private->xwindow, gc_private, + x1, y1, x2, y2)); + + MoveToEx (hdc, x1, y1, NULL); + if (!LineTo (hdc, x2, y2)) + g_warning ("gdk_draw_line: LineTo #1 failed"); + /* LineTo doesn't draw the last point, so if we have a pen width of 1, + * we draw the end pixel separately... With wider pens we don't care. + * //HB: But the NT developers don't read their API documentation ... + */ + if (gc_private->pen_width == 1 && windows_version > 0x80000000) + if (!LineTo (hdc, x2 + 1, y2)) + g_warning ("gdk_draw_line: LineTo #2 failed"); + gdk_gc_postdraw (drawable_private, gc_private); +} + +void +gdk_draw_rectangle (GdkDrawable *drawable, + GdkGC *gc, + gint filled, + gint x, + gint y, + gint width, + gint height) +{ + GdkDrawablePrivate *drawable_private; + GdkGCPrivate *gc_private; + HDC hdc; + HGDIOBJ oldpen, oldbrush; + + g_return_if_fail (drawable != NULL); + g_return_if_fail (gc != NULL); + + if (GDK_DRAWABLE_DESTROYED (drawable)) + return; + drawable_private = (GdkDrawablePrivate*) drawable; + gc_private = (GdkGCPrivate*) gc; + + if (width == -1) + width = drawable_private->width; + if (height == -1) + height = drawable_private->height; + + hdc = gdk_gc_predraw (drawable_private, gc_private); + + GDK_NOTE (MISC, g_print ("gdk_draw_rectangle: %#x (%d) %s%dx%d@+%d+%d\n", + drawable_private->xwindow, + gc_private, + (filled ? "fill " : ""), + width, height, x, y)); + +#if 0 + { + HBRUSH hbr = GetCurrentObject (hdc, OBJ_BRUSH); + HPEN hpen = GetCurrentObject (hdc, OBJ_PEN); + LOGBRUSH lbr; + LOGPEN lpen; + GetObject (hbr, sizeof (lbr), &lbr); + GetObject (hpen, sizeof (lpen), &lpen); + + g_print ("current brush: style = %s, color = 0x%.08x\n", + (lbr.lbStyle == BS_SOLID ? "SOLID" : "???"), + lbr.lbColor); + g_print ("current pen: style = %s, width = %d, color = 0x%.08x\n", + (lpen.lopnStyle == PS_SOLID ? "SOLID" : "???"), + lpen.lopnWidth, + lpen.lopnColor); + } +#endif + + if (filled) + oldpen = SelectObject (hdc, GetStockObject (NULL_PEN)); + else + oldbrush = SelectObject (hdc, GetStockObject (HOLLOW_BRUSH)); + + if (!Rectangle (hdc, x, y, x+width+1, y+height+1)) + g_warning ("gdk_draw_rectangle: Rectangle failed"); + + if (filled) + SelectObject (hdc, oldpen); + else + SelectObject (hdc, oldbrush); + + gdk_gc_postdraw (drawable_private, gc_private); +} + +void +gdk_draw_arc (GdkDrawable *drawable, + GdkGC *gc, + gint filled, + gint x, + gint y, + gint width, + gint height, + gint angle1, + gint angle2) +{ + GdkDrawablePrivate *drawable_private; + GdkGCPrivate *gc_private; + HDC hdc; + int nXStartArc, nYStartArc, nXEndArc, nYEndArc; + + g_return_if_fail (drawable != NULL); + g_return_if_fail (gc != NULL); + + if (GDK_DRAWABLE_DESTROYED (drawable)) + return; + drawable_private = (GdkDrawablePrivate*) drawable; + gc_private = (GdkGCPrivate*) gc; + + if (width == -1) + width = drawable_private->width; + if (height == -1) + height = drawable_private->height; + + GDK_NOTE (MISC, g_print ("gdk_draw_arc: %#x %d,%d,%d,%d %d %d\n", + drawable_private->xwindow, + x, y, width, height, angle1, angle2)); + + if (width != 0 && height != 0 && angle2 != 0) + { + hdc = gdk_gc_predraw (drawable_private, gc_private); + + if (angle2 >= 360*64) + { + nXStartArc = nYStartArc = nXEndArc = nYEndArc = 0; + } + else if (angle2 > 0) + { + /* The 100. is just an arbitrary value */ + nXStartArc = x + width/2 + 100. * cos(angle1/64.*2.*G_PI/360.); + nYStartArc = y + height/2 + -100. * sin(angle1/64.*2.*G_PI/360.); + nXEndArc = x + width/2 + 100. * cos((angle1+angle2)/64.*2.*G_PI/360.); + nYEndArc = y + height/2 + -100. * sin((angle1+angle2)/64.*2.*G_PI/360.); + } + else + { + nXEndArc = x + width/2 + 100. * cos(angle1/64.*2.*G_PI/360.); + nYEndArc = y + height/2 + -100. * sin(angle1/64.*2.*G_PI/360.); + nXStartArc = x + width/2 + 100. * cos((angle1+angle2)/64.*2.*G_PI/360.); + nYStartArc = y + height/2 + -100. * sin((angle1+angle2)/64.*2.*G_PI/360.); + } + + if (filled) + { + GDK_NOTE (MISC, g_print ("...Pie(hdc,%d,%d,%d,%d,%d,%d,%d,%d)\n", + x, y, x+width, y+height, + nXStartArc, nYStartArc, + nXEndArc, nYEndArc)); + Pie (hdc, x, y, x+width, y+height, + nXStartArc, nYStartArc, nXEndArc, nYEndArc); + } + else + { + GDK_NOTE (MISC, g_print ("...Arc(hdc,%d,%d,%d,%d,%d,%d,%d,%d)\n", + x, y, x+width, y+height, + nXStartArc, nYStartArc, + nXEndArc, nYEndArc)); + Arc (hdc, x, y, x+width, y+height, + nXStartArc, nYStartArc, nXEndArc, nYEndArc); + } + gdk_gc_postdraw (drawable_private, gc_private); + } +} + +void +gdk_draw_polygon (GdkDrawable *drawable, + GdkGC *gc, + gint filled, + GdkPoint *points, + gint npoints) +{ + GdkDrawablePrivate *drawable_private; + GdkGCPrivate *gc_private; + HDC hdc; + POINT *pts; + int i; + + g_return_if_fail (drawable != NULL); + g_return_if_fail (gc != NULL); + + if (GDK_DRAWABLE_DESTROYED (drawable)) + return; + drawable_private = (GdkDrawablePrivate*) drawable; + gc_private = (GdkGCPrivate*) gc; + + GDK_NOTE (MISC, g_print ("gdk_draw_polygon: %#x (%d) %d\n", + drawable_private->xwindow, gc_private, + npoints)); + + if (npoints < 2) + return; + + hdc = gdk_gc_predraw (drawable_private, gc_private); + pts = g_malloc ((npoints+1) * sizeof (POINT)); + + for (i = 0; i < npoints; i++) + { + pts[i].x = points[i].x; + pts[i].y = points[i].y; + } + + if ((points[0].x != points[npoints-1].x) || + (points[0].y != points[npoints-1].y)) + { + pts[npoints].x = points[0].x; + pts[npoints].y = points[0].y; + npoints++; + } + if (filled) + { + if (!Polygon (hdc, pts, npoints)) + g_warning ("gdk_draw_polygon: Polygon failed"); + } + else + { + if (!Polyline (hdc, pts, npoints)) + g_warning ("gdk_draw_polygon: Polyline failed"); + } + g_free (pts); + gdk_gc_postdraw (drawable_private, gc_private); +} + +typedef struct +{ + gint x, y; + HDC hdc; +} gdk_draw_text_arg; + +/* gdk_draw_string + */ +void +gdk_draw_string (GdkDrawable *drawable, + GdkFont *font, + GdkGC *gc, + gint x, + gint y, + const gchar *string) +{ + gdk_draw_text (drawable, font, gc, x, y, string, strlen (string)); +} + +static void +gdk_draw_text_handler (GdkWin32SingleFont *singlefont, + const wchar_t *wcstr, + int wclen, + void *arg) +{ + HGDIOBJ oldfont; + SIZE size; + gdk_draw_text_arg *argp = (gdk_draw_text_arg *) arg; + + if (!singlefont) + return; + + if ((oldfont = SelectObject (argp->hdc, singlefont->xfont)) == NULL) + { + g_warning ("gdk_draw_text_handler: SelectObject failed"); + return; + } + + if (!TextOutW (argp->hdc, argp->x, argp->y, wcstr, wclen)) + g_warning ("gdk_draw_text_handler: TextOutW failed"); + GetTextExtentPoint32W (argp->hdc, wcstr, wclen, &size); + argp->x += size.cx; + + SelectObject (argp->hdc, oldfont); +} + +/* gdk_draw_text + * + */ +void +gdk_draw_text (GdkDrawable *drawable, + GdkFont *font, + GdkGC *gc, + gint x, + gint y, + const gchar *text, + gint text_length) +{ + GdkDrawablePrivate *drawable_private; + GdkGCPrivate *gc_private; + wchar_t *wcstr; + gint wlen; + gdk_draw_text_arg arg; + + g_return_if_fail (drawable != NULL); + g_return_if_fail (font != NULL); + g_return_if_fail (gc != NULL); + g_return_if_fail (text != NULL); + + if (GDK_DRAWABLE_DESTROYED (drawable)) + return; + + if (text_length == 0) + return; + + g_assert (font->type == GDK_FONT_FONT || font->type == GDK_FONT_FONTSET); + + drawable_private = (GdkDrawablePrivate*) drawable; + gc_private = (GdkGCPrivate*) gc; + + arg.x = x; + arg.y = y; + arg.hdc = gdk_gc_predraw (drawable_private, gc_private); + + GDK_NOTE (MISC, g_print ("gdk_draw_text: %#x (%d,%d) \"%.*s\" (len %d)\n", + drawable_private->xwindow, + x, y, + (text_length > 10 ? 10 : text_length), + text, text_length)); + + wcstr = g_new (wchar_t, text_length); + if ((wlen = gdk_nmbstowchar_ts (wcstr, text, text_length, text_length)) == -1) + g_warning ("gdk_draw_text: gdk_nmbstowchar_ts failed"); + else + gdk_wchar_text_handle (font, wcstr, wlen, + gdk_draw_text_handler, &arg); + + g_free (wcstr); + + gdk_gc_postdraw (drawable_private, gc_private); +} + +void +gdk_draw_text_wc (GdkDrawable *drawable, + GdkFont *font, + GdkGC *gc, + gint x, + gint y, + const GdkWChar *text, + gint text_length) +{ + GdkDrawablePrivate *drawable_private; + GdkGCPrivate *gc_private; + gint i, wlen; + wchar_t *wcstr; + gdk_draw_text_arg arg; + + g_return_if_fail (drawable != NULL); + g_return_if_fail (font != NULL); + g_return_if_fail (gc != NULL); + g_return_if_fail (text != NULL); + + if (GDK_DRAWABLE_DESTROYED (drawable)) + return; + + if (text_length == 0) + return; + + g_assert (font->type == GDK_FONT_FONT || font->type == GDK_FONT_FONTSET); + + drawable_private = (GdkDrawablePrivate*) drawable; + gc_private = (GdkGCPrivate*) gc; + + arg.x = x; + arg.y = y; + arg.hdc = gdk_gc_predraw (drawable_private, gc_private); + + GDK_NOTE (MISC, g_print ("gdk_draw_text_wc: %#x (%d,%d) len: %d\n", + drawable_private->xwindow, + x, y, text_length)); + + if (sizeof (wchar_t) != sizeof (GdkWChar)) + { + wcstr = g_new (wchar_t, text_length); + for (i = 0; i < text_length; i++) + wcstr[i] = text[i]; + } + else + wcstr = (wchar_t *) text; + + gdk_wchar_text_handle (font, wcstr, text_length, + gdk_draw_text_handler, &arg); + + if (sizeof (wchar_t) != sizeof (GdkWChar)) + g_free (wcstr); + + gdk_gc_postdraw (drawable_private, gc_private); +} + +void +gdk_draw_pixmap (GdkDrawable *drawable, + GdkGC *gc, + GdkPixmap *src, + gint xsrc, + gint ysrc, + gint xdest, + gint ydest, + gint width, + gint height) +{ + GdkDrawablePrivate *drawable_private; + GdkDrawablePrivate *src_private; + GdkGCPrivate *gc_private; + HDC hdc; + HDC srcdc; + HGDIOBJ hgdiobj; + HRGN src_rgn, draw_rgn, outside_rgn; + RECT r; + + g_return_if_fail (drawable != NULL); + g_return_if_fail (src != NULL); + g_return_if_fail (gc != NULL); + + if (GDK_DRAWABLE_DESTROYED (drawable) || GDK_DRAWABLE_DESTROYED (src)) + return; + drawable_private = (GdkDrawablePrivate*) drawable; + src_private = (GdkDrawablePrivate*) src; + gc_private = (GdkGCPrivate*) gc; + + if (width == -1) + width = src_private->width; /* Or should we subtract xsrc? */ + if (height == -1) + height = src_private->height; /* Ditto? */ + + GDK_NOTE (MISC, g_print ("gdk_draw_pixmap: dest: %#x " + "src: %#x %dx%d@+%d+%d" + " dest: %#x @+%d+%d\n", + drawable_private->xwindow, + src_private->xwindow, + width, height, xsrc, ysrc, + drawable_private->xwindow, xdest, ydest)); + + hdc = gdk_gc_predraw (drawable_private, gc_private); + + src_rgn = CreateRectRgn (0, 0, src_private->width + 1, src_private->height + 1); + draw_rgn = CreateRectRgn (xsrc, ysrc, xsrc + width + 1, ysrc + height + 1); + SetRectEmpty (&r); + outside_rgn = CreateRectRgnIndirect (&r); + + if (drawable_private->window_type != GDK_DRAWABLE_PIXMAP) + { + /* If we are drawing on a window, calculate the region that is + * outside the source pixmap, and invalidate that, causing it to + * be cleared. XXX + */ + if (CombineRgn (outside_rgn, draw_rgn, src_rgn, RGN_DIFF) != NULLREGION) + { + OffsetRgn (outside_rgn, xdest, ydest); + GDK_NOTE (MISC, (GetRgnBox (outside_rgn, &r), + g_print ("...calling InvalidateRgn, " + "bbox: %dx%d@+%d+%d\n", + r.right - r.left - 1, r.bottom - r.top - 1, + r.left, r.top))); + InvalidateRgn (drawable_private->xwindow, outside_rgn, TRUE); + } + } + +#if 1 /* Don't know if this is necessary */ + if (CombineRgn (draw_rgn, draw_rgn, src_rgn, RGN_AND) == COMPLEXREGION) + g_warning ("gdk_draw_pixmap: CombineRgn returned a COMPLEXREGION"); + + GetRgnBox (draw_rgn, &r); + if (r.left != xsrc + || r.top != ysrc + || r.right != xsrc + width + 1 + || r.bottom != ysrc + height + 1) + { + xdest += r.left - xsrc; + xsrc = r.left; + ydest += r.top - ysrc; + ysrc = r.top; + width = r.right - xsrc - 1; + height = r.bottom - ysrc - 1; + + GDK_NOTE (MISC, g_print ("... restricted to src: %dx%d@+%d+%d, " + "dest: @+%d+%d\n", + width, height, xsrc, ysrc, + xdest, ydest)); + } +#endif + + DeleteObject (src_rgn); + DeleteObject (draw_rgn); + DeleteObject (outside_rgn); + + /* Strangely enough, this function is called also to bitblt + * from a window. + */ + if (src_private->window_type == GDK_DRAWABLE_PIXMAP) + { + if ((srcdc = CreateCompatibleDC (hdc)) == NULL) + g_warning ("gdk_draw_pixmap: CreateCompatibleDC failed"); + + if ((hgdiobj = SelectObject (srcdc, src_private->xwindow)) == NULL) + g_warning ("gdk_draw_pixmap: SelectObject #1 failed"); + + if (!BitBlt (hdc, xdest, ydest, width, height, + srcdc, xsrc, ysrc, SRCCOPY)) + g_warning ("gdk_draw_pixmap: BitBlt failed"); + + if ((SelectObject (srcdc, hgdiobj) == NULL)) + g_warning ("gdk_draw_pixmap: SelectObject #2 failed"); + + if (!DeleteDC (srcdc)) + g_warning ("gdk_draw_pixmap: DeleteDC failed"); + } + else + { + if (drawable_private->xwindow == src_private->xwindow) + { + /* Blitting inside a window, use ScrollDC */ + RECT scrollRect, clipRect, emptyRect; + HRGN updateRgn; + + scrollRect.left = MIN (xsrc, xdest); + scrollRect.top = MIN (ysrc, ydest); + scrollRect.right = MAX (xsrc + width + 1, xdest + width + 1); + scrollRect.bottom = MAX (ysrc + height + 1, ydest + height + 1); + + clipRect.left = xdest; + clipRect.top = ydest; + clipRect.right = xdest + width + 1; + clipRect.bottom = ydest + height + 1; + + SetRectEmpty (&emptyRect); + updateRgn = CreateRectRgnIndirect (&emptyRect); + if (!ScrollDC (hdc, xdest - xsrc, ydest - ysrc, + &scrollRect, &clipRect, + updateRgn, NULL)) + g_warning ("gdk_draw_pixmap: ScrollDC failed"); + if (!InvalidateRgn (drawable_private->xwindow, updateRgn, FALSE)) + g_warning ("gdk_draw_pixmap: InvalidateRgn failed"); + if (!UpdateWindow (drawable_private->xwindow)) + g_warning ("gdk_draw_pixmap: UpdateWindow failed"); + } + else + { + if ((srcdc = GetDC (src_private->xwindow)) == NULL) + g_warning ("gdk_draw_pixmap: GetDC failed"); + + if (!BitBlt (hdc, xdest, ydest, width, height, + srcdc, xsrc, ysrc, SRCCOPY)) + g_warning ("gdk_draw_pixmap: BitBlt failed"); + ReleaseDC (src_private->xwindow, srcdc); + } + } + gdk_gc_postdraw (drawable_private, gc_private); +} + +void +gdk_draw_image (GdkDrawable *drawable, + GdkGC *gc, + GdkImage *image, + gint xsrc, + gint ysrc, + gint xdest, + gint ydest, + gint width, + gint height) +{ + GdkImagePrivate *image_private; + + g_return_if_fail (drawable != NULL); + g_return_if_fail (image != NULL); + g_return_if_fail (gc != NULL); + + image_private = (GdkImagePrivate*) image; + + g_return_if_fail (image_private->image_put != NULL); + + if (width == -1) + width = image->width; + if (height == -1) + height = image->height; + + (* image_private->image_put) (drawable, gc, image, xsrc, ysrc, + xdest, ydest, width, height); +} + +void +gdk_draw_points (GdkDrawable *drawable, + GdkGC *gc, + GdkPoint *points, + gint npoints) +{ + GdkDrawablePrivate *drawable_private; + GdkGCPrivate *gc_private; + HDC hdc; + int i; + + g_return_if_fail (drawable != NULL); + g_return_if_fail ((points != NULL) && (npoints > 0)); + g_return_if_fail (gc != NULL); + + if (GDK_DRAWABLE_DESTROYED (drawable)) + return; + drawable_private = (GdkDrawablePrivate*) drawable; + gc_private = (GdkGCPrivate*) gc; + + hdc = gdk_gc_predraw (drawable_private, gc_private); + + GDK_NOTE (MISC, g_print ("gdk_draw_points: %#x destdc: (%d) %#x " + "npoints: %d\n", + drawable_private->xwindow, gc_private, hdc, + npoints)); + + for (i = 0; i < npoints; i++) + { + if (!MoveToEx (hdc, points[i].x, points[i].y, NULL)) + g_warning ("gdk_draw_points: MoveToEx failed"); + if (!LineTo (hdc, points[i].x + 1, points[i].y)) + g_warning ("gdk_draw_points: LineTo failed"); + } + gdk_gc_postdraw (drawable_private, gc_private); +} + +void +gdk_draw_segments (GdkDrawable *drawable, + GdkGC *gc, + GdkSegment *segs, + gint nsegs) +{ + GdkDrawablePrivate *drawable_private; + GdkGCPrivate *gc_private; + HDC hdc; + int i; + + if (nsegs <= 0) + return; + + g_return_if_fail (drawable != NULL); + g_return_if_fail (segs != NULL); + g_return_if_fail (gc != NULL); + + if (GDK_DRAWABLE_DESTROYED (drawable)) + return; + drawable_private = (GdkDrawablePrivate*) drawable; + gc_private = (GdkGCPrivate*) gc; + + hdc = gdk_gc_predraw (drawable_private, gc_private); + + for (i = 0; i < nsegs; i++) + { + if (!MoveToEx (hdc, segs[i].x1, segs[i].y1, NULL)) + g_warning ("gdk_draw_segments: MoveToEx failed"); + if (!LineTo (hdc, segs[i].x2, segs[i].y2)) + g_warning ("gdk_draw_segments: LineTo #1 failed"); + + /* Draw end pixel */ + if (gc_private->pen_width == 1) + if (!LineTo (hdc, segs[i].x2 + 1, segs[i].y2)) + g_warning ("gdk_draw_segments: LineTo #2 failed"); + } + gdk_gc_postdraw (drawable_private, gc_private); +} + +void +gdk_draw_lines (GdkDrawable *drawable, + GdkGC *gc, + GdkPoint *points, + gint npoints) +{ + GdkDrawablePrivate *drawable_private; + GdkGCPrivate *gc_private; + HDC hdc; + POINT *pts; + int i; + + if (npoints < 2) + return; + + g_return_if_fail (drawable != NULL); + g_return_if_fail (points != NULL); + g_return_if_fail (gc != NULL); + + if (GDK_DRAWABLE_DESTROYED (drawable)) + return; + drawable_private = (GdkDrawablePrivate*) drawable; + gc_private = (GdkGCPrivate*) gc; + + hdc = gdk_gc_predraw (drawable_private, gc_private); +#if 1 + pts = g_malloc (npoints * sizeof (POINT)); + + for (i = 0; i < npoints; i++) + { + pts[i].x = points[i].x; + pts[i].y = points[i].y; + } + + if (!Polyline (hdc, pts, npoints)) + g_warning ("gdk_draw_lines: Polyline(,,%d) failed", npoints); + + g_free (pts); + + /* Draw end pixel */ + if (gc_private->pen_width == 1) + { + MoveToEx (hdc, points[npoints-1].x, points[npoints-1].y, NULL); + if (!LineTo (hdc, points[npoints-1].x + 1, points[npoints-1].y)) + g_warning ("gdk_draw_lines: LineTo failed"); + } +#else + MoveToEx (hdc, points[0].x, points[0].y, NULL); + for (i = 1; i < npoints; i++) + if (!LineTo (hdc, points[i].x, points[i].y)) + g_warning ("gdk_draw_lines: LineTo #1 failed"); + + /* Draw end pixel */ + if (gc_private->pen_width == 1) + if (!LineTo (hdc, points[npoints-1].x + 1, points[npoints-1].y)) + g_warning ("gdk_draw_lines: LineTo #2 failed"); +#endif + gdk_gc_postdraw (drawable_private, gc_private); +} diff --git a/gdk/win32/gdkevents-win32.c b/gdk/win32/gdkevents-win32.c new file mode 100644 index 000000000..9ef45fe8d --- /dev/null +++ b/gdk/win32/gdkevents-win32.c @@ -0,0 +1,5193 @@ +/* GDK - The GIMP Drawing Kit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * Copyright (C) 1998-1999 Tor Lillqvist + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* + * Modified by the GTK+ Team and others 1997-1999. See the AUTHORS + * file for a list of people on the GTK+ Team. See the ChangeLog + * files for a list of changes. These files are distributed with + * GTK+ at ftp://ftp.gtk.org/pub/gtk/. + */ + +#include "config.h" + +#define NEW_PROPAGATION_CODE + +#define USE_DISPATCHMESSAGE + +/* Cannot use TrackMouseEvent, as the stupid WM_MOUSELEAVE message + * doesn't tell us where the mouse has gone. Thus we cannot use it to + * generate a correct GdkNotifyType. Pity, as using TrackMouseEvent + * otherwise would make it possible to reliably generate + * GDK_LEAVE_NOTIFY events, which would help get rid of those pesky + * tooltips sometimes popping up in the wrong place. + */ +/* define USE_TRACKMOUSEEVENT */ + +#include + +#include + +#include +#include + +#ifdef HAVE_DIMM_H +#include +#else +#include "surrogate-dimm.h" +#endif + +#ifdef HAVE_WINTAB +#include +#endif + +#include "gdk.h" +#include "gdkx.h" + +#include "gdkkeysyms.h" + +#include "gdkinputprivate.h" + +#define PING() printf("%s: %d\n",__FILE__,__LINE__),fflush(stdout) + +#define WINDOW_PRIVATE(wp) ((GdkWindowPrivate *) (wp)) + +typedef struct _GdkIOClosure GdkIOClosure; +typedef struct _GdkEventPrivate GdkEventPrivate; + +#define DOUBLE_CLICK_TIME 250 +#define TRIPLE_CLICK_TIME 500 +#define DOUBLE_CLICK_DIST 5 +#define TRIPLE_CLICK_DIST 5 + +gint gdk_event_func_from_window_proc = FALSE; + +typedef enum +{ + /* Following flag is set for events on the event queue during + * translation and cleared afterwards. + */ + GDK_EVENT_PENDING = 1 << 0 +} GdkEventFlags; + +struct _GdkIOClosure +{ + GdkInputFunction function; + GdkInputCondition condition; + GdkDestroyNotify notify; + gpointer data; +}; + +struct _GdkEventPrivate +{ + GdkEvent event; + guint flags; +}; + +/* + * Private function declarations + */ + +static GdkEvent *gdk_event_new (void); +static GdkFilterReturn + gdk_event_apply_filters(MSG *xevent, + GdkEvent *event, + GList *filters); +static gboolean gdk_event_translate (GdkEvent *event, + MSG *xevent, + gboolean *ret_val_flagp, + gint *ret_valp); +static void gdk_events_queue (void); +static GdkEvent *gdk_event_unqueue (void); +static gboolean gdk_event_prepare (gpointer source_data, + GTimeVal *current_time, + gint *timeout); +static gboolean gdk_event_check (gpointer source_data, + GTimeVal *current_time); +static gboolean gdk_event_dispatch (gpointer source_data, + GTimeVal *current_time, + gpointer user_data); + +static void gdk_synthesize_click (GdkEvent *event, + gint nclicks); + +/* Private variable declarations + */ + +static guint32 button_click_time[2]; /* The last 2 button click times. Used + * to determine if the latest button click + * is part of a double or triple click. + */ +static GdkWindow *button_window[2]; /* The last 2 windows to receive button presses. + * Also used to determine if the latest button + * click is part of a double or triple click. + */ +static guint button_number[2]; /* The last 2 buttons to be pressed. + */ +static GdkWindow *p_grab_window = NULL; /* Window that currently + * holds the pointer grab + */ + +static GdkWindow *k_grab_window = NULL; /* Window the holds the + * keyboard grab + */ + +static GList *client_filters; /* Filters for client messages */ + +static gboolean p_grab_automatic; +static GdkEventMask p_grab_mask; +static gboolean p_grab_owner_events, k_grab_owner_events; +static HCURSOR p_grab_cursor; + +static GdkEventFunc event_func = NULL; /* Callback for events */ +static gpointer event_data = NULL; +static GDestroyNotify event_notify = NULL; + +static GList *client_filters; /* Filters for client messages */ + +/* FIFO's for event queue, and for events put back using + * gdk_event_put(). + */ +static GList *queued_events = NULL; +static GList *queued_tail = NULL; + +static GSourceFuncs event_funcs = { + gdk_event_prepare, + gdk_event_check, + gdk_event_dispatch, + (GDestroyNotify)g_free +}; + +GPollFD event_poll_fd; + +static GdkWindow *curWnd = NULL; +static HWND active = NULL; +static gint curX, curY; +static gdouble curXroot, curYroot; +static UINT gdk_ping_msg; +static gboolean ignore_WM_CHAR = FALSE; +static gboolean is_AltGr_key = FALSE; + +static IActiveIMMApp *paimmapp = NULL; +static IActiveIMMMessagePumpOwner *paimmmpo = NULL; + +typedef BOOL (WINAPI *PFN_TrackMouseEvent) (LPTRACKMOUSEEVENT); +static PFN_TrackMouseEvent p_TrackMouseEvent = NULL; + +static gboolean use_IME_COMPOSITION = FALSE; + +LRESULT CALLBACK +gdk_WindowProc (HWND hWnd, + UINT message, + WPARAM wParam, + LPARAM lParam) +{ + GdkEvent event; + GdkEvent *eventp; + MSG msg; + DWORD pos; + LRESULT lres; + gint ret_val; + gboolean ret_val_flag; + + GDK_NOTE (EVENTS, g_print ("gdk_WindowProc: %#x %#.03x\n", hWnd, message)); + + msg.hwnd = hWnd; + msg.message = message; + msg.wParam = wParam; + msg.lParam = lParam; + msg.time = GetTickCount (); + pos = GetMessagePos (); + msg.pt.x = LOWORD (pos); + msg.pt.y = HIWORD (pos); + + ((GdkEventPrivate *)&event)->flags |= GDK_EVENT_PENDING; + if (gdk_event_translate (&event, &msg, &ret_val_flag, &ret_val)) + { + ((GdkEventPrivate *)&event)->flags &= ~GDK_EVENT_PENDING; +#if 1 + if (event.any.type == GDK_CONFIGURE) + { + /* Compress configure events */ + GList *list = queued_events; + + while (list != NULL + && (((GdkEvent *)list->data)->any.type != GDK_CONFIGURE + || ((GdkEvent *)list->data)->any.window != event.any.window)) + list = list->next; + if (list != NULL) + { + *((GdkEvent *)list->data) = event; + gdk_window_unref (event.any.window); + /* Wake up WaitMessage */ + PostMessage (NULL, gdk_ping_msg, 0, 0); + return FALSE; + } + } + else if (event.any.type == GDK_EXPOSE) + { + /* Compress expose events */ + GList *list = queued_events; + + while (list != NULL + && (((GdkEvent *)list->data)->any.type != GDK_EXPOSE + || ((GdkEvent *)list->data)->any.window != event.any.window)) + list = list->next; + if (list != NULL) + { + GdkRectangle u; + + gdk_rectangle_union (&event.expose.area, + &((GdkEvent *)list->data)->expose.area, + &u); + ((GdkEvent *)list->data)->expose.area = u; + gdk_window_unref (event.any.window); + /* Wake up WaitMessage */ + PostMessage (NULL, gdk_ping_msg, 0, 0); + return FALSE; + } + } +#endif + eventp = gdk_event_new (); + *eventp = event; + + /* Philippe Colantoni suggests this + * in order to handle events while opaque resizing neatly. I + * don't want it as default. Set the + * GDK_EVENT_FUNC_FROM_WINDOW_PROC env var to get this + * behaviour. + */ + if (gdk_event_func_from_window_proc && event_func) + { + GDK_THREADS_ENTER (); + + (*event_func) (eventp, event_data); + gdk_event_free (eventp); + + GDK_THREADS_LEAVE (); + } + else + { + gdk_event_queue_append (eventp); +#if 1 + /* Wake up WaitMessage */ + PostMessage (NULL, gdk_ping_msg, 0, 0); +#endif + } + + if (ret_val_flag) + return ret_val; + else + return FALSE; + } + + if (ret_val_flag) + return ret_val; + else + { + if (paimmapp == NULL + || (*paimmapp->lpVtbl->OnDefWindowProc) (paimmapp, hWnd, message, wParam, lParam, &lres) == S_FALSE) + return DefWindowProc (hWnd, message, wParam, lParam); + else + return lres; + } +} + +/********************************************* + * Functions for maintaining the event queue * + *********************************************/ + +/************************************************************* + * gdk_event_queue_find_first: + * Find the first event on the queue that is not still + * being filled in. + * arguments: + * + * results: + * Pointer to the list node for that event, or NULL + *************************************************************/ + +static GList* +gdk_event_queue_find_first (void) +{ + GList *tmp_list = queued_events; + + while (tmp_list) + { + GdkEventPrivate *event = tmp_list->data; + if (!(event->flags & GDK_EVENT_PENDING)) + return tmp_list; + + tmp_list = g_list_next (tmp_list); + } + + return NULL; +} + +/************************************************************* + * gdk_event_queue_remove_link: + * Remove a specified list node from the event queue. + * arguments: + * node: Node to remove. + * results: + *************************************************************/ + +static void +gdk_event_queue_remove_link (GList *node) +{ + if (node->prev) + node->prev->next = node->next; + else + queued_events = node->next; + + if (node->next) + node->next->prev = node->prev; + else + queued_tail = node->prev; + +} + +/************************************************************* + * gdk_event_queue_append: + * Append an event onto the tail of the event queue. + * arguments: + * event: Event to append. + * results: + *************************************************************/ + +void +gdk_event_queue_append (GdkEvent *event) +{ + queued_tail = g_list_append (queued_tail, event); + + if (!queued_events) + queued_events = queued_tail; + else + queued_tail = queued_tail->next; +} + +void +gdk_events_init (void) +{ + HRESULT hres; + HMODULE user32, imm32; + HINSTANCE commctrl32; + + if (g_pipe_readable_msg == 0) + g_pipe_readable_msg = RegisterWindowMessage ("g-pipe-readable"); + GDK_NOTE (EVENTS, g_print ("g-pipe-readable = %#.03x\n", + g_pipe_readable_msg)); + + gdk_ping_msg = RegisterWindowMessage ("gdk-ping"); + GDK_NOTE (EVENTS, g_print ("gdk-ping = %#.03x\n", + gdk_ping_msg)); + + g_source_add (GDK_PRIORITY_EVENTS, TRUE, &event_funcs, NULL, NULL, NULL); + + event_poll_fd.fd = G_WIN32_MSG_HANDLE; + event_poll_fd.events = G_IO_IN; + + g_main_add_poll (&event_poll_fd, GDK_PRIORITY_EVENTS); + + button_click_time[0] = 0; + button_click_time[1] = 0; + button_window[0] = NULL; + button_window[1] = NULL; + button_number[0] = -1; + button_number[1] = -1; + + hres = CoCreateInstance (&CLSID_CActiveIMM, + NULL, + CLSCTX_ALL, + &IID_IActiveIMMApp, + (LPVOID *) &paimmapp); + + if (hres == S_OK) + { + GDK_NOTE (EVENTS, g_print ("IActiveIMMApp created %#x\n", + paimmapp)); + (*paimmapp->lpVtbl->Activate) (paimmapp, TRUE); + + hres = (*paimmapp->lpVtbl->QueryInterface) (paimmapp, &IID_IActiveIMMMessagePumpOwner, &paimmmpo); + GDK_NOTE (EVENTS, g_print ("IActiveIMMMessagePumpOwner created %#x\n", + paimmmpo)); + (paimmmpo->lpVtbl->Start) (paimmmpo); + } + +#ifdef USE_TRACKMOUSEEVENT + user32 = GetModuleHandle ("user32.dll"); + if ((p_TrackMouseEvent = GetProcAddress (user32, "TrackMouseEvent")) == NULL) + { + if ((commctrl32 = LoadLibrary ("commctrl32.dll")) != NULL) + p_TrackMouseEvent = (PFN_TrackMouseEvent) + GetProcAddress (commctrl32, "_TrackMouseEvent"); + } + if (p_TrackMouseEvent != NULL) + GDK_NOTE (EVENTS, g_print ("Using TrackMouseEvent to detect leave events\n")); +#endif + if (windows_version < 0x80000000 && (windows_version & 0xFF) == 5) + { + /* On Win2k (Beta 3, at least) WM_IME_CHAR doesn't seem to work + * correctly for non-Unicode applications. Handle + * WM_IME_COMPOSITION with GCS_RESULTSTR instead, fetch the + * Unicode char from the IME with ImmGetCompositionStringW(). + */ + use_IME_COMPOSITION = TRUE; + } +} + +/* + *-------------------------------------------------------------- + * gdk_events_pending + * + * Returns if events are pending on the queue. + * + * Arguments: + * + * Results: + * Returns TRUE if events are pending + * + * Side effects: + * + *-------------------------------------------------------------- + */ + +gboolean +gdk_events_pending (void) +{ + MSG msg; + + return (gdk_event_queue_find_first() || PeekMessage (&msg, NULL, 0, 0, PM_NOREMOVE)); +} + +/* + *-------------------------------------------------------------- + * gdk_event_get_graphics_expose + * + * Waits for a GraphicsExpose or NoExpose event + * + * Arguments: + * + * Results: + * For GraphicsExpose events, returns a pointer to the event + * converted into a GdkEvent Otherwise, returns NULL. + * + * Side effects: + * + *-------------------------------------------------------------- */ + +GdkEvent* +gdk_event_get_graphics_expose (GdkWindow *window) +{ + MSG xevent; + GdkEvent *event; + GdkWindowPrivate *private = (GdkWindowPrivate *) window; + + g_return_val_if_fail (window != NULL, NULL); + + GDK_NOTE (EVENTS, g_print ("gdk_event_get_graphics_expose\n")); + +#if 1 + /* Some nasty bugs here, just return NULL for now. */ + return NULL; +#else + if (GetMessage (&xevent, private->xwindow, WM_PAINT, WM_PAINT)) + { + event = gdk_event_new (); + + if (gdk_event_translate (event, &xevent, NULL, NULL)) + return event; + else + gdk_event_free (event); + } + + return NULL; +#endif +} + +/************************************************************* + * gdk_event_handler_set: + * + * arguments: + * func: Callback function to be called for each event. + * data: Data supplied to the function + * notify: function called when function is no longer needed + * + * results: + *************************************************************/ + +void +gdk_event_handler_set (GdkEventFunc func, + gpointer data, + GDestroyNotify notify) +{ + if (event_notify) + (*event_notify) (event_data); + + event_func = func; + event_data = data; + event_notify = notify; +} + +/* + *-------------------------------------------------------------- + * gdk_event_get + * + * Gets the next event. + * + * Arguments: + * + * Results: + * If an event is waiting that we care about, returns + * a pointer to that event, to be freed with gdk_event_free. + * Otherwise, returns NULL. + * + * Side effects: + * + *-------------------------------------------------------------- + */ + +GdkEvent* +gdk_event_get (void) +{ + gdk_events_queue(); + + return gdk_event_unqueue(); +} + +/* + *-------------------------------------------------------------- + * gdk_event_peek + * + * Gets the next event. + * + * Arguments: + * + * Results: + * If an event is waiting that we care about, returns + * a copy of that event, but does not remove it from + * the queue. The pointer is to be freed with gdk_event_free. + * Otherwise, returns NULL. + * + * Side effects: + * + *-------------------------------------------------------------- + */ + +GdkEvent* +gdk_event_peek (void) +{ + GList *tmp_list; + + tmp_list = gdk_event_queue_find_first (); + + if (tmp_list) + return gdk_event_copy (tmp_list->data); + else + return NULL; +} + +void +gdk_event_put (GdkEvent *event) +{ + GdkEvent *new_event; + GList *tmp_list; + + g_return_if_fail (event != NULL); + + new_event = gdk_event_copy (event); + + gdk_event_queue_append (new_event); +} + +/* + *-------------------------------------------------------------- + * gdk_event_copy + * + * Copy a event structure into new storage. + * + * Arguments: + * "event" is the event struct to copy. + * + * Results: + * A new event structure. Free it with gdk_event_free. + * + * Side effects: + * The reference count of the window in the event is increased. + * + *-------------------------------------------------------------- + */ + +static GMemChunk *event_chunk = NULL; + +static GdkEvent* +gdk_event_new (void) +{ + GdkEventPrivate *new_event; + + if (event_chunk == NULL) + event_chunk = g_mem_chunk_new ("events", + sizeof (GdkEventPrivate), + 4096, + G_ALLOC_AND_FREE); + + new_event = g_chunk_new (GdkEventPrivate, event_chunk); + new_event->flags = 0; + + return (GdkEvent *) new_event; +} + +GdkEvent* +gdk_event_copy (GdkEvent *event) +{ + GdkEvent *new_event; + gchar *s; + + g_return_val_if_fail (event != NULL, NULL); + + new_event = gdk_event_new (); + + *new_event = *event; + gdk_window_ref (new_event->any.window); + + switch (event->any.type) + { + case GDK_KEY_PRESS: + case GDK_KEY_RELEASE: + if (event->key.length > 0) + { + s = event->key.string; + new_event->key.string = g_malloc (event->key.length + 1); + memcpy (new_event->key.string, s, event->key.length + 1); + } + break; + + case GDK_ENTER_NOTIFY: + case GDK_LEAVE_NOTIFY: + if (event->crossing.subwindow != NULL) + gdk_window_ref (event->crossing.subwindow); + break; + + case GDK_DRAG_ENTER: + case GDK_DRAG_LEAVE: + case GDK_DRAG_MOTION: + case GDK_DRAG_STATUS: + case GDK_DROP_START: + case GDK_DROP_FINISHED: + gdk_drag_context_ref (event->dnd.context); + break; + + default: + break; + } + + return new_event; +} + +/* + *-------------------------------------------------------------- + * gdk_event_free + * + * Free a event structure obtained from gdk_event_copy. Do not use + * with other event structures. + * + * Arguments: + * "event" is the event struct to free. + * + * Results: + * + * Side effects: + * The reference count of the window in the event is decreased and + * might be freed, too. + * + *-------------------------------------------------------------- */ + +void +gdk_event_free (GdkEvent *event) +{ + g_return_if_fail (event != NULL); + + g_assert (event_chunk != NULL); /* paranoid */ + + if (event->any.window) + gdk_window_unref (event->any.window); + + switch (event->any.type) + { + case GDK_KEY_PRESS: + case GDK_KEY_RELEASE: + g_free (event->key.string); + break; + + case GDK_ENTER_NOTIFY: + case GDK_LEAVE_NOTIFY: + if (event->crossing.subwindow != NULL) + gdk_window_unref (event->crossing.subwindow); + break; + + case GDK_DRAG_ENTER: + case GDK_DRAG_LEAVE: + case GDK_DRAG_MOTION: + case GDK_DRAG_STATUS: + case GDK_DROP_START: + case GDK_DROP_FINISHED: + gdk_drag_context_unref (event->dnd.context); + break; + + default: + break; + } + + g_mem_chunk_free (event_chunk, event); +} + +/* + *-------------------------------------------------------------- + * gdk_event_get_time: + * Get the timestamp from an event. + * arguments: + * event: + * results: + * The event's time stamp, if it has one, otherwise + * GDK_CURRENT_TIME. + *-------------------------------------------------------------- + */ + +guint32 +gdk_event_get_time (GdkEvent *event) +{ + if (event) + switch (event->type) + { + case GDK_MOTION_NOTIFY: + return event->motion.time; + case GDK_BUTTON_PRESS: + case GDK_2BUTTON_PRESS: + case GDK_3BUTTON_PRESS: + case GDK_BUTTON_RELEASE: + return event->button.time; + case GDK_KEY_PRESS: + case GDK_KEY_RELEASE: + return event->key.time; + case GDK_ENTER_NOTIFY: + case GDK_LEAVE_NOTIFY: + return event->crossing.time; + case GDK_PROPERTY_NOTIFY: + return event->property.time; + case GDK_SELECTION_CLEAR: + case GDK_SELECTION_REQUEST: + case GDK_SELECTION_NOTIFY: + return event->selection.time; + case GDK_PROXIMITY_IN: + case GDK_PROXIMITY_OUT: + return event->proximity.time; + case GDK_DRAG_ENTER: + case GDK_DRAG_LEAVE: + case GDK_DRAG_MOTION: + case GDK_DRAG_STATUS: + case GDK_DROP_START: + case GDK_DROP_FINISHED: + return event->dnd.time; + default: /* use current time */ + break; + } + + return GDK_CURRENT_TIME; +} + +/* + *-------------------------------------------------------------- + * gdk_set_show_events + * + * Turns on/off the showing of events. + * + * Arguments: + * "show_events" is a boolean describing whether or + * not to show the events gdk receives. + * + * Results: + * + * Side effects: + * When "show_events" is TRUE, calls to "gdk_event_get" + * will output debugging informatin regarding the event + * received to stdout. + * + *-------------------------------------------------------------- + */ + +void +gdk_set_show_events (gint show_events) +{ + if (show_events) + gdk_debug_flags |= GDK_DEBUG_EVENTS; + else + gdk_debug_flags &= ~GDK_DEBUG_EVENTS; +} + +gint +gdk_get_show_events (void) +{ + return gdk_debug_flags & GDK_DEBUG_EVENTS; +} + +/* + *-------------------------------------------------------------- + * gdk_pointer_grab + * + * Grabs the pointer to a specific window + * + * Arguments: + * "window" is the window which will receive the grab + * "owner_events" specifies whether events will be reported as is, + * or relative to "window" + * "event_mask" masks only interesting events + * "confine_to" limits the cursor movement to the specified window + * "cursor" changes the cursor for the duration of the grab + * "time" specifies the time + * + * Results: + * + * Side effects: + * requires a corresponding call to gdk_pointer_ungrab + * + *-------------------------------------------------------------- + */ + +gint +gdk_pointer_grab (GdkWindow * window, + gint owner_events, + GdkEventMask event_mask, + GdkWindow * confine_to, + GdkCursor * cursor, + guint32 time) +{ + HWND xwindow; + HWND xconfine_to; + HCURSOR xcursor; + GdkCursorPrivate *cursor_private; + gint return_val; + + g_return_val_if_fail (window != NULL, 0); + g_return_val_if_fail (GDK_IS_WINDOW (window), 0); + g_return_val_if_fail (confine_to == NULL || GDK_IS_WINDOW (confine_to), 0); + + cursor_private = (GdkCursorPrivate*) cursor; + + xwindow = GDK_DRAWABLE_XID (window); + + if (!confine_to || GDK_DRAWABLE_DESTROYED (confine_to)) + xconfine_to = NULL; + else + xconfine_to = GDK_DRAWABLE_XID (confine_to); + + if (!cursor) + xcursor = NULL; + else + xcursor = cursor_private->xcursor; + + if (gdk_input_vtable.grab_pointer) + return_val = gdk_input_vtable.grab_pointer (window, + owner_events, + event_mask, + confine_to, + time); + else + return_val = Success; + + if (return_val == Success) + { + if (!GDK_DRAWABLE_DESTROYED (window)) + { + GDK_NOTE (EVENTS, g_print ("gdk_pointer_grab: %#x %s %#x%s%s\n", + xwindow, + (owner_events ? "TRUE" : "FALSE"), + xcursor, + (event_mask & GDK_BUTTON_PRESS_MASK) ? + " PRESS" : "", + (event_mask & GDK_BUTTON_RELEASE_MASK) ? + " RELEASE" : "")); + p_grab_mask = event_mask; + p_grab_owner_events = (owner_events != 0); + p_grab_automatic = FALSE; + +#if 0 /* Menus don't work if we use mouse capture. Pity, because many other + * things work better with mouse capture. + */ + SetCapture (xwindow); +#endif + return_val = GrabSuccess; + } + else + return_val = AlreadyGrabbed; + } + + if (return_val == GrabSuccess) + { + p_grab_window = window; + p_grab_cursor = xcursor; + } + + return return_val; +} + +/* + *-------------------------------------------------------------- + * gdk_pointer_ungrab + * + * Releases any pointer grab + * + * Arguments: + * + * Results: + * + * Side effects: + * + *-------------------------------------------------------------- + */ + +void +gdk_pointer_ungrab (guint32 time) +{ + if (gdk_input_vtable.ungrab_pointer) + gdk_input_vtable.ungrab_pointer (time); +#if 0 + if (GetCapture () != NULL) + ReleaseCapture (); +#endif + GDK_NOTE (EVENTS, g_print ("gdk_pointer_ungrab\n")); + + p_grab_window = NULL; +} + +/* + *-------------------------------------------------------------- + * gdk_pointer_is_grabbed + * + * Tell wether there is an active x pointer grab in effect + * + * Arguments: + * + * Results: + * + * Side effects: + * + *-------------------------------------------------------------- + */ + +gint +gdk_pointer_is_grabbed (void) +{ + return p_grab_window != NULL; +} + +/* + *-------------------------------------------------------------- + * gdk_keyboard_grab + * + * Grabs the keyboard to a specific window + * + * Arguments: + * "window" is the window which will receive the grab + * "owner_events" specifies whether events will be reported as is, + * or relative to "window" + * "time" specifies the time + * + * Results: + * + * Side effects: + * requires a corresponding call to gdk_keyboard_ungrab + * + *-------------------------------------------------------------- + */ + +gint +gdk_keyboard_grab (GdkWindow * window, + gint owner_events, + guint32 time) +{ + gint return_val; + + g_return_val_if_fail (window != NULL, 0); + g_return_val_if_fail (GDK_IS_WINDOW (window), 0); + + GDK_NOTE (EVENTS, g_print ("gdk_keyboard_grab %#x\n", + GDK_DRAWABLE_XID (window))); + + if (!GDK_DRAWABLE_DESTROYED (window)) + { + k_grab_owner_events = owner_events != 0; + return_val = GrabSuccess; + } + else + return_val = AlreadyGrabbed; + + if (return_val == GrabSuccess) + k_grab_window = window; + + return return_val; +} + +/* + *-------------------------------------------------------------- + * gdk_keyboard_ungrab + * + * Releases any keyboard grab + * + * Arguments: + * + * Results: + * + * Side effects: + * + *-------------------------------------------------------------- + */ + +void +gdk_keyboard_ungrab (guint32 time) +{ + GDK_NOTE (EVENTS, g_print ("gdk_keyboard_ungrab\n")); + + k_grab_window = NULL; +} + +static void +gdk_io_destroy (gpointer data) +{ + GdkIOClosure *closure = data; + + if (closure->notify) + closure->notify (closure->data); + + g_free (closure); +} + +static gboolean +gdk_io_invoke (GIOChannel *source, + GIOCondition condition, + gpointer data) +{ + GdkIOClosure *closure = data; + GdkInputCondition gdk_cond = 0; + + if (condition & (G_IO_IN | G_IO_PRI)) + gdk_cond |= GDK_INPUT_READ; + if (condition & G_IO_OUT) + gdk_cond |= GDK_INPUT_WRITE; + if (condition & (G_IO_ERR | G_IO_HUP | G_IO_NVAL)) + gdk_cond |= GDK_INPUT_EXCEPTION; + + if (closure->condition & gdk_cond) + closure->function (closure->data, g_io_channel_unix_get_fd (source), gdk_cond); + + return TRUE; +} + +gint +gdk_input_add_full (gint source, + GdkInputCondition condition, + GdkInputFunction function, + gpointer data, + GdkDestroyNotify destroy) +{ + guint result; + GdkIOClosure *closure = g_new (GdkIOClosure, 1); + GIOChannel *channel; + GIOCondition cond = 0; + + closure->function = function; + closure->condition = condition; + closure->notify = destroy; + closure->data = data; + + if (condition & GDK_INPUT_READ) + cond |= (G_IO_IN | G_IO_PRI); + if (condition & GDK_INPUT_WRITE) + cond |= G_IO_OUT; + if (condition & GDK_INPUT_EXCEPTION) + cond |= G_IO_ERR|G_IO_HUP|G_IO_NVAL; + + channel = g_io_channel_unix_new (source); + result = g_io_add_watch_full (channel, G_PRIORITY_DEFAULT, cond, + gdk_io_invoke, + closure, gdk_io_destroy); + g_io_channel_unref (channel); + + return result; +} + +gint +gdk_input_add (gint source, + GdkInputCondition condition, + GdkInputFunction function, + gpointer data) +{ + return gdk_input_add_full (source, condition, function, data, NULL); +} + +void +gdk_input_remove (gint tag) +{ + g_source_remove (tag); +} + +static GdkFilterReturn +gdk_event_apply_filters (MSG *xevent, + GdkEvent *event, + GList *filters) +{ + GdkEventFilter *filter; + GList *tmp_list; + GdkFilterReturn result; + + tmp_list = filters; + + while (tmp_list) + { + filter = (GdkEventFilter *) tmp_list->data; + + result = (*filter->function) (xevent, event, filter->data); + if (result != GDK_FILTER_CONTINUE) + return result; + + tmp_list = tmp_list->next; + } + + return GDK_FILTER_CONTINUE; +} + +void +gdk_add_client_message_filter (GdkAtom message_type, + GdkFilterFunc func, + gpointer data) +{ + GdkClientFilter *filter = g_new (GdkClientFilter, 1); + + filter->type = message_type; + filter->function = func; + filter->data = data; + + client_filters = g_list_prepend (client_filters, filter); +} + +/* Thanks to Markus G. Kuhn for the ksysym<->Unicode + * mapping functions, from the xterm sources. + */ + +#if 0 /* Keyval-to-Unicode isn't actually needed */ + +struct k2u { + unsigned short keysym; + unsigned short ucs; +} k2utab[] = { + { 0x01a1, 0x0104 }, /* Aogonek Ą LATIN CAPITAL LETTER A WITH OGONEK */ + { 0x01a2, 0x02d8 }, /* breve ˘ BREVE */ + { 0x01a3, 0x0141 }, /* Lstroke Ł LATIN CAPITAL LETTER L WITH STROKE */ + { 0x01a5, 0x013d }, /* Lcaron Ľ LATIN CAPITAL LETTER L WITH CARON */ + { 0x01a6, 0x015a }, /* Sacute Ś LATIN CAPITAL LETTER S WITH ACUTE */ + { 0x01a9, 0x0160 }, /* Scaron Å  LATIN CAPITAL LETTER S WITH CARON */ + { 0x01aa, 0x015e }, /* Scedilla Ş LATIN CAPITAL LETTER S WITH CEDILLA */ + { 0x01ab, 0x0164 }, /* Tcaron Ť LATIN CAPITAL LETTER T WITH CARON */ + { 0x01ac, 0x0179 }, /* Zacute Ź LATIN CAPITAL LETTER Z WITH ACUTE */ + { 0x01ae, 0x017d }, /* Zcaron Ž LATIN CAPITAL LETTER Z WITH CARON */ + { 0x01af, 0x017b }, /* Zabovedot Å» LATIN CAPITAL LETTER Z WITH DOT ABOVE */ + { 0x01b1, 0x0105 }, /* aogonek ą LATIN SMALL LETTER A WITH OGONEK */ + { 0x01b2, 0x02db }, /* ogonek ˛ OGONEK */ + { 0x01b3, 0x0142 }, /* lstroke ł LATIN SMALL LETTER L WITH STROKE */ + { 0x01b5, 0x013e }, /* lcaron ľ LATIN SMALL LETTER L WITH CARON */ + { 0x01b6, 0x015b }, /* sacute ś LATIN SMALL LETTER S WITH ACUTE */ + { 0x01b7, 0x02c7 }, /* caron ˇ CARON */ + { 0x01b9, 0x0161 }, /* scaron Å¡ LATIN SMALL LETTER S WITH CARON */ + { 0x01ba, 0x015f }, /* scedilla ş LATIN SMALL LETTER S WITH CEDILLA */ + { 0x01bb, 0x0165 }, /* tcaron Å¥ LATIN SMALL LETTER T WITH CARON */ + { 0x01bc, 0x017a }, /* zacute ź LATIN SMALL LETTER Z WITH ACUTE */ + { 0x01bd, 0x02dd }, /* doubleacute ˝ DOUBLE ACUTE ACCENT */ + { 0x01be, 0x017e }, /* zcaron ž LATIN SMALL LETTER Z WITH CARON */ + { 0x01bf, 0x017c }, /* zabovedot ż LATIN SMALL LETTER Z WITH DOT ABOVE */ + { 0x01c0, 0x0154 }, /* Racute Ŕ LATIN CAPITAL LETTER R WITH ACUTE */ + { 0x01c3, 0x0102 }, /* Abreve Ă LATIN CAPITAL LETTER A WITH BREVE */ + { 0x01c5, 0x0139 }, /* Lacute Ĺ LATIN CAPITAL LETTER L WITH ACUTE */ + { 0x01c6, 0x0106 }, /* Cacute Ć LATIN CAPITAL LETTER C WITH ACUTE */ + { 0x01c8, 0x010c }, /* Ccaron Č LATIN CAPITAL LETTER C WITH CARON */ + { 0x01ca, 0x0118 }, /* Eogonek Ę LATIN CAPITAL LETTER E WITH OGONEK */ + { 0x01cc, 0x011a }, /* Ecaron Ě LATIN CAPITAL LETTER E WITH CARON */ + { 0x01cf, 0x010e }, /* Dcaron Ď LATIN CAPITAL LETTER D WITH CARON */ + { 0x01d0, 0x0110 }, /* Dstroke Đ LATIN CAPITAL LETTER D WITH STROKE */ + { 0x01d1, 0x0143 }, /* Nacute Ń LATIN CAPITAL LETTER N WITH ACUTE */ + { 0x01d2, 0x0147 }, /* Ncaron Ň LATIN CAPITAL LETTER N WITH CARON */ + { 0x01d5, 0x0150 }, /* Odoubleacute Ő LATIN CAPITAL LETTER O WITH DOUBLE ACUTE */ + { 0x01d8, 0x0158 }, /* Rcaron Ř LATIN CAPITAL LETTER R WITH CARON */ + { 0x01d9, 0x016e }, /* Uring Å® LATIN CAPITAL LETTER U WITH RING ABOVE */ + { 0x01db, 0x0170 }, /* Udoubleacute Å° LATIN CAPITAL LETTER U WITH DOUBLE ACUTE */ + { 0x01de, 0x0162 }, /* Tcedilla Å¢ LATIN CAPITAL LETTER T WITH CEDILLA */ + { 0x01e0, 0x0155 }, /* racute ŕ LATIN SMALL LETTER R WITH ACUTE */ + { 0x01e3, 0x0103 }, /* abreve ă LATIN SMALL LETTER A WITH BREVE */ + { 0x01e5, 0x013a }, /* lacute ĺ LATIN SMALL LETTER L WITH ACUTE */ + { 0x01e6, 0x0107 }, /* cacute ć LATIN SMALL LETTER C WITH ACUTE */ + { 0x01e8, 0x010d }, /* ccaron č LATIN SMALL LETTER C WITH CARON */ + { 0x01ea, 0x0119 }, /* eogonek ę LATIN SMALL LETTER E WITH OGONEK */ + { 0x01ec, 0x011b }, /* ecaron ě LATIN SMALL LETTER E WITH CARON */ + { 0x01ef, 0x010f }, /* dcaron ď LATIN SMALL LETTER D WITH CARON */ + { 0x01f0, 0x0111 }, /* dstroke đ LATIN SMALL LETTER D WITH STROKE */ + { 0x01f1, 0x0144 }, /* nacute ń LATIN SMALL LETTER N WITH ACUTE */ + { 0x01f2, 0x0148 }, /* ncaron ň LATIN SMALL LETTER N WITH CARON */ + { 0x01f5, 0x0151 }, /* odoubleacute ő LATIN SMALL LETTER O WITH DOUBLE ACUTE */ + { 0x01f8, 0x0159 }, /* rcaron ř LATIN SMALL LETTER R WITH CARON */ + { 0x01f9, 0x016f }, /* uring ů LATIN SMALL LETTER U WITH RING ABOVE */ + { 0x01fb, 0x0171 }, /* udoubleacute ű LATIN SMALL LETTER U WITH DOUBLE ACUTE */ + { 0x01fe, 0x0163 }, /* tcedilla Å£ LATIN SMALL LETTER T WITH CEDILLA */ + { 0x01ff, 0x02d9 }, /* abovedot ˙ DOT ABOVE */ + { 0x02a1, 0x0126 }, /* Hstroke Ħ LATIN CAPITAL LETTER H WITH STROKE */ + { 0x02a6, 0x0124 }, /* Hcircumflex Ĥ LATIN CAPITAL LETTER H WITH CIRCUMFLEX */ + { 0x02a9, 0x0130 }, /* Iabovedot Ä° LATIN CAPITAL LETTER I WITH DOT ABOVE */ + { 0x02ab, 0x011e }, /* Gbreve Ğ LATIN CAPITAL LETTER G WITH BREVE */ + { 0x02ac, 0x0134 }, /* Jcircumflex Ä´ LATIN CAPITAL LETTER J WITH CIRCUMFLEX */ + { 0x02b1, 0x0127 }, /* hstroke ħ LATIN SMALL LETTER H WITH STROKE */ + { 0x02b6, 0x0125 }, /* hcircumflex Ä¥ LATIN SMALL LETTER H WITH CIRCUMFLEX */ + { 0x02b9, 0x0131 }, /* idotless ı LATIN SMALL LETTER DOTLESS I */ + { 0x02bb, 0x011f }, /* gbreve ğ LATIN SMALL LETTER G WITH BREVE */ + { 0x02bc, 0x0135 }, /* jcircumflex ĵ LATIN SMALL LETTER J WITH CIRCUMFLEX */ + { 0x02c5, 0x010a }, /* Cabovedot Ċ LATIN CAPITAL LETTER C WITH DOT ABOVE */ + { 0x02c6, 0x0108 }, /* Ccircumflex Ĉ LATIN CAPITAL LETTER C WITH CIRCUMFLEX */ + { 0x02d5, 0x0120 }, /* Gabovedot Ä  LATIN CAPITAL LETTER G WITH DOT ABOVE */ + { 0x02d8, 0x011c }, /* Gcircumflex Ĝ LATIN CAPITAL LETTER G WITH CIRCUMFLEX */ + { 0x02dd, 0x016c }, /* Ubreve Ŭ LATIN CAPITAL LETTER U WITH BREVE */ + { 0x02de, 0x015c }, /* Scircumflex Ŝ LATIN CAPITAL LETTER S WITH CIRCUMFLEX */ + { 0x02e5, 0x010b }, /* cabovedot ċ LATIN SMALL LETTER C WITH DOT ABOVE */ + { 0x02e6, 0x0109 }, /* ccircumflex ĉ LATIN SMALL LETTER C WITH CIRCUMFLEX */ + { 0x02f5, 0x0121 }, /* gabovedot Ä¡ LATIN SMALL LETTER G WITH DOT ABOVE */ + { 0x02f8, 0x011d }, /* gcircumflex ĝ LATIN SMALL LETTER G WITH CIRCUMFLEX */ + { 0x02fd, 0x016d }, /* ubreve Å­ LATIN SMALL LETTER U WITH BREVE */ + { 0x02fe, 0x015d }, /* scircumflex ŝ LATIN SMALL LETTER S WITH CIRCUMFLEX */ + { 0x03a2, 0x0138 }, /* kra ĸ LATIN SMALL LETTER KRA */ + { 0x03a3, 0x0156 }, /* Rcedilla Ŗ LATIN CAPITAL LETTER R WITH CEDILLA */ + { 0x03a5, 0x0128 }, /* Itilde Ĩ LATIN CAPITAL LETTER I WITH TILDE */ + { 0x03a6, 0x013b }, /* Lcedilla Ä» LATIN CAPITAL LETTER L WITH CEDILLA */ + { 0x03aa, 0x0112 }, /* Emacron Ē LATIN CAPITAL LETTER E WITH MACRON */ + { 0x03ab, 0x0122 }, /* Gcedilla Ä¢ LATIN CAPITAL LETTER G WITH CEDILLA */ + { 0x03ac, 0x0166 }, /* Tslash Ŧ LATIN CAPITAL LETTER T WITH STROKE */ + { 0x03b3, 0x0157 }, /* rcedilla ŗ LATIN SMALL LETTER R WITH CEDILLA */ + { 0x03b5, 0x0129 }, /* itilde Ä© LATIN SMALL LETTER I WITH TILDE */ + { 0x03b6, 0x013c }, /* lcedilla ļ LATIN SMALL LETTER L WITH CEDILLA */ + { 0x03ba, 0x0113 }, /* emacron ē LATIN SMALL LETTER E WITH MACRON */ + { 0x03bb, 0x0123 }, /* gcedilla Ä£ LATIN SMALL LETTER G WITH CEDILLA */ + { 0x03bc, 0x0167 }, /* tslash ŧ LATIN SMALL LETTER T WITH STROKE */ + { 0x03bd, 0x014a }, /* ENG Ŋ LATIN CAPITAL LETTER ENG */ + { 0x03bf, 0x014b }, /* eng ŋ LATIN SMALL LETTER ENG */ + { 0x03c0, 0x0100 }, /* Amacron Ā LATIN CAPITAL LETTER A WITH MACRON */ + { 0x03c7, 0x012e }, /* Iogonek Ä® LATIN CAPITAL LETTER I WITH OGONEK */ + { 0x03cc, 0x0116 }, /* Eabovedot Ė LATIN CAPITAL LETTER E WITH DOT ABOVE */ + { 0x03cf, 0x012a }, /* Imacron Ī LATIN CAPITAL LETTER I WITH MACRON */ + { 0x03d1, 0x0145 }, /* Ncedilla Ņ LATIN CAPITAL LETTER N WITH CEDILLA */ + { 0x03d2, 0x014c }, /* Omacron Ō LATIN CAPITAL LETTER O WITH MACRON */ + { 0x03d3, 0x0136 }, /* Kcedilla Ķ LATIN CAPITAL LETTER K WITH CEDILLA */ + { 0x03d9, 0x0172 }, /* Uogonek Ų LATIN CAPITAL LETTER U WITH OGONEK */ + { 0x03dd, 0x0168 }, /* Utilde Ũ LATIN CAPITAL LETTER U WITH TILDE */ + { 0x03de, 0x016a }, /* Umacron Ū LATIN CAPITAL LETTER U WITH MACRON */ + { 0x03e0, 0x0101 }, /* amacron ā LATIN SMALL LETTER A WITH MACRON */ + { 0x03e7, 0x012f }, /* iogonek į LATIN SMALL LETTER I WITH OGONEK */ + { 0x03ec, 0x0117 }, /* eabovedot ė LATIN SMALL LETTER E WITH DOT ABOVE */ + { 0x03ef, 0x012b }, /* imacron Ä« LATIN SMALL LETTER I WITH MACRON */ + { 0x03f1, 0x0146 }, /* ncedilla ņ LATIN SMALL LETTER N WITH CEDILLA */ + { 0x03f2, 0x014d }, /* omacron ō LATIN SMALL LETTER O WITH MACRON */ + { 0x03f3, 0x0137 }, /* kcedilla Ä· LATIN SMALL LETTER K WITH CEDILLA */ + { 0x03f9, 0x0173 }, /* uogonek ų LATIN SMALL LETTER U WITH OGONEK */ + { 0x03fd, 0x0169 }, /* utilde Å© LATIN SMALL LETTER U WITH TILDE */ + { 0x03fe, 0x016b }, /* umacron Å« LATIN SMALL LETTER U WITH MACRON */ + { 0x047e, 0x203e }, /* overline ‾ OVERLINE */ + { 0x04a1, 0x3002 }, /* kana_fullstop 。 IDEOGRAPHIC FULL STOP */ + { 0x04a2, 0x300c }, /* kana_openingbracket 「 LEFT CORNER BRACKET */ + { 0x04a3, 0x300d }, /* kana_closingbracket 」 RIGHT CORNER BRACKET */ + { 0x04a4, 0x3001 }, /* kana_comma 、 IDEOGRAPHIC COMMA */ + { 0x04a5, 0x30fb }, /* kana_conjunctive ・ KATAKANA MIDDLE DOT */ + { 0x04a6, 0x30f2 }, /* kana_WO ヲ KATAKANA LETTER WO */ + { 0x04a7, 0x30a1 }, /* kana_a ァ KATAKANA LETTER SMALL A */ + { 0x04a8, 0x30a3 }, /* kana_i ィ KATAKANA LETTER SMALL I */ + { 0x04a9, 0x30a5 }, /* kana_u ゥ KATAKANA LETTER SMALL U */ + { 0x04aa, 0x30a7 }, /* kana_e ェ KATAKANA LETTER SMALL E */ + { 0x04ab, 0x30a9 }, /* kana_o ォ KATAKANA LETTER SMALL O */ + { 0x04ac, 0x30e3 }, /* kana_ya ャ KATAKANA LETTER SMALL YA */ + { 0x04ad, 0x30e5 }, /* kana_yu ュ KATAKANA LETTER SMALL YU */ + { 0x04ae, 0x30e7 }, /* kana_yo ョ KATAKANA LETTER SMALL YO */ + { 0x04af, 0x30c3 }, /* kana_tsu ッ KATAKANA LETTER SMALL TU */ + { 0x04b0, 0x30fc }, /* prolongedsound ー KATAKANA-HIRAGANA PROLONGED SOUND MARK */ + { 0x04b1, 0x30a2 }, /* kana_A ア KATAKANA LETTER A */ + { 0x04b2, 0x30a4 }, /* kana_I イ KATAKANA LETTER I */ + { 0x04b3, 0x30a6 }, /* kana_U ウ KATAKANA LETTER U */ + { 0x04b4, 0x30a8 }, /* kana_E エ KATAKANA LETTER E */ + { 0x04b5, 0x30aa }, /* kana_O オ KATAKANA LETTER O */ + { 0x04b6, 0x30ab }, /* kana_KA カ KATAKANA LETTER KA */ + { 0x04b7, 0x30ad }, /* kana_KI キ KATAKANA LETTER KI */ + { 0x04b8, 0x30af }, /* kana_KU ク KATAKANA LETTER KU */ + { 0x04b9, 0x30b1 }, /* kana_KE ケ KATAKANA LETTER KE */ + { 0x04ba, 0x30b3 }, /* kana_KO コ KATAKANA LETTER KO */ + { 0x04bb, 0x30b5 }, /* kana_SA サ KATAKANA LETTER SA */ + { 0x04bc, 0x30b7 }, /* kana_SHI シ KATAKANA LETTER SI */ + { 0x04bd, 0x30b9 }, /* kana_SU ス KATAKANA LETTER SU */ + { 0x04be, 0x30bb }, /* kana_SE セ KATAKANA LETTER SE */ + { 0x04bf, 0x30bd }, /* kana_SO ソ KATAKANA LETTER SO */ + { 0x04c0, 0x30bf }, /* kana_TA タ KATAKANA LETTER TA */ + { 0x04c1, 0x30c1 }, /* kana_CHI チ KATAKANA LETTER TI */ + { 0x04c2, 0x30c4 }, /* kana_TSU ツ KATAKANA LETTER TU */ + { 0x04c3, 0x30c6 }, /* kana_TE テ KATAKANA LETTER TE */ + { 0x04c4, 0x30c8 }, /* kana_TO ト KATAKANA LETTER TO */ + { 0x04c5, 0x30ca }, /* kana_NA ナ KATAKANA LETTER NA */ + { 0x04c6, 0x30cb }, /* kana_NI ニ KATAKANA LETTER NI */ + { 0x04c7, 0x30cc }, /* kana_NU ヌ KATAKANA LETTER NU */ + { 0x04c8, 0x30cd }, /* kana_NE ネ KATAKANA LETTER NE */ + { 0x04c9, 0x30ce }, /* kana_NO ノ KATAKANA LETTER NO */ + { 0x04ca, 0x30cf }, /* kana_HA ハ KATAKANA LETTER HA */ + { 0x04cb, 0x30d2 }, /* kana_HI ヒ KATAKANA LETTER HI */ + { 0x04cc, 0x30d5 }, /* kana_FU フ KATAKANA LETTER HU */ + { 0x04cd, 0x30d8 }, /* kana_HE ヘ KATAKANA LETTER HE */ + { 0x04ce, 0x30db }, /* kana_HO ホ KATAKANA LETTER HO */ + { 0x04cf, 0x30de }, /* kana_MA マ KATAKANA LETTER MA */ + { 0x04d0, 0x30df }, /* kana_MI ミ KATAKANA LETTER MI */ + { 0x04d1, 0x30e0 }, /* kana_MU ム KATAKANA LETTER MU */ + { 0x04d2, 0x30e1 }, /* kana_ME メ KATAKANA LETTER ME */ + { 0x04d3, 0x30e2 }, /* kana_MO モ KATAKANA LETTER MO */ + { 0x04d4, 0x30e4 }, /* kana_YA ヤ KATAKANA LETTER YA */ + { 0x04d5, 0x30e6 }, /* kana_YU ユ KATAKANA LETTER YU */ + { 0x04d6, 0x30e8 }, /* kana_YO ヨ KATAKANA LETTER YO */ + { 0x04d7, 0x30e9 }, /* kana_RA ラ KATAKANA LETTER RA */ + { 0x04d8, 0x30ea }, /* kana_RI リ KATAKANA LETTER RI */ + { 0x04d9, 0x30eb }, /* kana_RU ル KATAKANA LETTER RU */ + { 0x04da, 0x30ec }, /* kana_RE レ KATAKANA LETTER RE */ + { 0x04db, 0x30ed }, /* kana_RO ロ KATAKANA LETTER RO */ + { 0x04dc, 0x30ef }, /* kana_WA ワ KATAKANA LETTER WA */ + { 0x04dd, 0x30f3 }, /* kana_N ン KATAKANA LETTER N */ + { 0x04de, 0x309b }, /* voicedsound ゛ KATAKANA-HIRAGANA VOICED SOUND MARK */ + { 0x04df, 0x309c }, /* semivoicedsound ゜ KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK */ + { 0x05ac, 0x060c }, /* Arabic_comma ، ARABIC COMMA */ + { 0x05bb, 0x061b }, /* Arabic_semicolon ؛ ARABIC SEMICOLON */ + { 0x05bf, 0x061f }, /* Arabic_question_mark ؟ ARABIC QUESTION MARK */ + { 0x05c1, 0x0621 }, /* Arabic_hamza Ø¡ ARABIC LETTER HAMZA */ + { 0x05c2, 0x0622 }, /* Arabic_maddaonalef Ø¢ ARABIC LETTER ALEF WITH MADDA ABOVE */ + { 0x05c3, 0x0623 }, /* Arabic_hamzaonalef Ø£ ARABIC LETTER ALEF WITH HAMZA ABOVE */ + { 0x05c4, 0x0624 }, /* Arabic_hamzaonwaw ؤ ARABIC LETTER WAW WITH HAMZA ABOVE */ + { 0x05c5, 0x0625 }, /* Arabic_hamzaunderalef Ø¥ ARABIC LETTER ALEF WITH HAMZA BELOW */ + { 0x05c6, 0x0626 }, /* Arabic_hamzaonyeh ئ ARABIC LETTER YEH WITH HAMZA ABOVE */ + { 0x05c7, 0x0627 }, /* Arabic_alef ا ARABIC LETTER ALEF */ + { 0x05c8, 0x0628 }, /* Arabic_beh ب ARABIC LETTER BEH */ + { 0x05c9, 0x0629 }, /* Arabic_tehmarbuta Ø© ARABIC LETTER TEH MARBUTA */ + { 0x05ca, 0x062a }, /* Arabic_teh ت ARABIC LETTER TEH */ + { 0x05cb, 0x062b }, /* Arabic_theh Ø« ARABIC LETTER THEH */ + { 0x05cc, 0x062c }, /* Arabic_jeem ج ARABIC LETTER JEEM */ + { 0x05cd, 0x062d }, /* Arabic_hah Ø­ ARABIC LETTER HAH */ + { 0x05ce, 0x062e }, /* Arabic_khah Ø® ARABIC LETTER KHAH */ + { 0x05cf, 0x062f }, /* Arabic_dal د ARABIC LETTER DAL */ + { 0x05d0, 0x0630 }, /* Arabic_thal Ø° ARABIC LETTER THAL */ + { 0x05d1, 0x0631 }, /* Arabic_ra ر ARABIC LETTER REH */ + { 0x05d2, 0x0632 }, /* Arabic_zain ز ARABIC LETTER ZAIN */ + { 0x05d3, 0x0633 }, /* Arabic_seen س ARABIC LETTER SEEN */ + { 0x05d4, 0x0634 }, /* Arabic_sheen Ø´ ARABIC LETTER SHEEN */ + { 0x05d5, 0x0635 }, /* Arabic_sad ص ARABIC LETTER SAD */ + { 0x05d6, 0x0636 }, /* Arabic_dad ض ARABIC LETTER DAD */ + { 0x05d7, 0x0637 }, /* Arabic_tah Ø· ARABIC LETTER TAH */ + { 0x05d8, 0x0638 }, /* Arabic_zah ظ ARABIC LETTER ZAH */ + { 0x05d9, 0x0639 }, /* Arabic_ain ع ARABIC LETTER AIN */ + { 0x05da, 0x063a }, /* Arabic_ghain غ ARABIC LETTER GHAIN */ + { 0x05e0, 0x0640 }, /* Arabic_tatweel ـ ARABIC TATWEEL */ + { 0x05e1, 0x0641 }, /* Arabic_feh ف ARABIC LETTER FEH */ + { 0x05e2, 0x0642 }, /* Arabic_qaf ق ARABIC LETTER QAF */ + { 0x05e3, 0x0643 }, /* Arabic_kaf ك ARABIC LETTER KAF */ + { 0x05e4, 0x0644 }, /* Arabic_lam ل ARABIC LETTER LAM */ + { 0x05e5, 0x0645 }, /* Arabic_meem م ARABIC LETTER MEEM */ + { 0x05e6, 0x0646 }, /* Arabic_noon ن ARABIC LETTER NOON */ + { 0x05e7, 0x0647 }, /* Arabic_ha ه ARABIC LETTER HEH */ + { 0x05e8, 0x0648 }, /* Arabic_waw و ARABIC LETTER WAW */ + { 0x05e9, 0x0649 }, /* Arabic_alefmaksura ى ARABIC LETTER ALEF MAKSURA */ + { 0x05ea, 0x064a }, /* Arabic_yeh ي ARABIC LETTER YEH */ + { 0x05eb, 0x064b }, /* Arabic_fathatan ً ARABIC FATHATAN */ + { 0x05ec, 0x064c }, /* Arabic_dammatan ٌ ARABIC DAMMATAN */ + { 0x05ed, 0x064d }, /* Arabic_kasratan ٍ ARABIC KASRATAN */ + { 0x05ee, 0x064e }, /* Arabic_fatha َ ARABIC FATHA */ + { 0x05ef, 0x064f }, /* Arabic_damma ُ ARABIC DAMMA */ + { 0x05f0, 0x0650 }, /* Arabic_kasra ِ ARABIC KASRA */ + { 0x05f1, 0x0651 }, /* Arabic_shadda ّ ARABIC SHADDA */ + { 0x05f2, 0x0652 }, /* Arabic_sukun ْ ARABIC SUKUN */ + { 0x06a1, 0x0452 }, /* Serbian_dje ђ CYRILLIC SMALL LETTER DJE */ + { 0x06a2, 0x0453 }, /* Macedonia_gje ѓ CYRILLIC SMALL LETTER GJE */ + { 0x06a3, 0x0451 }, /* Cyrillic_io ё CYRILLIC SMALL LETTER IO */ + { 0x06a4, 0x0454 }, /* Ukrainian_ie є CYRILLIC SMALL LETTER UKRAINIAN IE */ + { 0x06a5, 0x0455 }, /* Macedonia_dse ѕ CYRILLIC SMALL LETTER DZE */ + { 0x06a6, 0x0456 }, /* Ukrainian_i і CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I */ + { 0x06a7, 0x0457 }, /* Ukrainian_yi ї CYRILLIC SMALL LETTER YI */ + { 0x06a8, 0x0458 }, /* Cyrillic_je ј CYRILLIC SMALL LETTER JE */ + { 0x06a9, 0x0459 }, /* Cyrillic_lje љ CYRILLIC SMALL LETTER LJE */ + { 0x06aa, 0x045a }, /* Cyrillic_nje њ CYRILLIC SMALL LETTER NJE */ + { 0x06ab, 0x045b }, /* Serbian_tshe ћ CYRILLIC SMALL LETTER TSHE */ + { 0x06ac, 0x045c }, /* Macedonia_kje ќ CYRILLIC SMALL LETTER KJE */ + { 0x06ae, 0x045e }, /* Byelorussian_shortu ў CYRILLIC SMALL LETTER SHORT U */ + { 0x06af, 0x045f }, /* Cyrillic_dzhe џ CYRILLIC SMALL LETTER DZHE */ + { 0x06b0, 0x2116 }, /* numerosign № NUMERO SIGN */ + { 0x06b1, 0x0402 }, /* Serbian_DJE Ђ CYRILLIC CAPITAL LETTER DJE */ + { 0x06b2, 0x0403 }, /* Macedonia_GJE Ѓ CYRILLIC CAPITAL LETTER GJE */ + { 0x06b3, 0x0401 }, /* Cyrillic_IO Ё CYRILLIC CAPITAL LETTER IO */ + { 0x06b4, 0x0404 }, /* Ukrainian_IE Є CYRILLIC CAPITAL LETTER UKRAINIAN IE */ + { 0x06b5, 0x0405 }, /* Macedonia_DSE Ѕ CYRILLIC CAPITAL LETTER DZE */ + { 0x06b6, 0x0406 }, /* Ukrainian_I І CYRILLIC CAPITAL LETTER BYELORUSSIAN-UKRAINIAN I */ + { 0x06b7, 0x0407 }, /* Ukrainian_YI Ї CYRILLIC CAPITAL LETTER YI */ + { 0x06b8, 0x0408 }, /* Cyrillic_JE Ј CYRILLIC CAPITAL LETTER JE */ + { 0x06b9, 0x0409 }, /* Cyrillic_LJE Љ CYRILLIC CAPITAL LETTER LJE */ + { 0x06ba, 0x040a }, /* Cyrillic_NJE Њ CYRILLIC CAPITAL LETTER NJE */ + { 0x06bb, 0x040b }, /* Serbian_TSHE Ћ CYRILLIC CAPITAL LETTER TSHE */ + { 0x06bc, 0x040c }, /* Macedonia_KJE Ќ CYRILLIC CAPITAL LETTER KJE */ + { 0x06be, 0x040e }, /* Byelorussian_SHORTU Ў CYRILLIC CAPITAL LETTER SHORT U */ + { 0x06bf, 0x040f }, /* Cyrillic_DZHE Џ CYRILLIC CAPITAL LETTER DZHE */ + { 0x06c0, 0x044e }, /* Cyrillic_yu ю CYRILLIC SMALL LETTER YU */ + { 0x06c1, 0x0430 }, /* Cyrillic_a а CYRILLIC SMALL LETTER A */ + { 0x06c2, 0x0431 }, /* Cyrillic_be б CYRILLIC SMALL LETTER BE */ + { 0x06c3, 0x0446 }, /* Cyrillic_tse ц CYRILLIC SMALL LETTER TSE */ + { 0x06c4, 0x0434 }, /* Cyrillic_de д CYRILLIC SMALL LETTER DE */ + { 0x06c5, 0x0435 }, /* Cyrillic_ie е CYRILLIC SMALL LETTER IE */ + { 0x06c6, 0x0444 }, /* Cyrillic_ef ф CYRILLIC SMALL LETTER EF */ + { 0x06c7, 0x0433 }, /* Cyrillic_ghe г CYRILLIC SMALL LETTER GHE */ + { 0x06c8, 0x0445 }, /* Cyrillic_ha х CYRILLIC SMALL LETTER HA */ + { 0x06c9, 0x0438 }, /* Cyrillic_i и CYRILLIC SMALL LETTER I */ + { 0x06ca, 0x0439 }, /* Cyrillic_shorti й CYRILLIC SMALL LETTER SHORT I */ + { 0x06cb, 0x043a }, /* Cyrillic_ka к CYRILLIC SMALL LETTER KA */ + { 0x06cc, 0x043b }, /* Cyrillic_el л CYRILLIC SMALL LETTER EL */ + { 0x06cd, 0x043c }, /* Cyrillic_em м CYRILLIC SMALL LETTER EM */ + { 0x06ce, 0x043d }, /* Cyrillic_en н CYRILLIC SMALL LETTER EN */ + { 0x06cf, 0x043e }, /* Cyrillic_o о CYRILLIC SMALL LETTER O */ + { 0x06d0, 0x043f }, /* Cyrillic_pe п CYRILLIC SMALL LETTER PE */ + { 0x06d1, 0x044f }, /* Cyrillic_ya я CYRILLIC SMALL LETTER YA */ + { 0x06d2, 0x0440 }, /* Cyrillic_er р CYRILLIC SMALL LETTER ER */ + { 0x06d3, 0x0441 }, /* Cyrillic_es с CYRILLIC SMALL LETTER ES */ + { 0x06d4, 0x0442 }, /* Cyrillic_te т CYRILLIC SMALL LETTER TE */ + { 0x06d5, 0x0443 }, /* Cyrillic_u у CYRILLIC SMALL LETTER U */ + { 0x06d6, 0x0436 }, /* Cyrillic_zhe ж CYRILLIC SMALL LETTER ZHE */ + { 0x06d7, 0x0432 }, /* Cyrillic_ve в CYRILLIC SMALL LETTER VE */ + { 0x06d8, 0x044c }, /* Cyrillic_softsign ь CYRILLIC SMALL LETTER SOFT SIGN */ + { 0x06d9, 0x044b }, /* Cyrillic_yeru ы CYRILLIC SMALL LETTER YERU */ + { 0x06da, 0x0437 }, /* Cyrillic_ze з CYRILLIC SMALL LETTER ZE */ + { 0x06db, 0x0448 }, /* Cyrillic_sha ш CYRILLIC SMALL LETTER SHA */ + { 0x06dc, 0x044d }, /* Cyrillic_e э CYRILLIC SMALL LETTER E */ + { 0x06dd, 0x0449 }, /* Cyrillic_shcha щ CYRILLIC SMALL LETTER SHCHA */ + { 0x06de, 0x0447 }, /* Cyrillic_che ч CYRILLIC SMALL LETTER CHE */ + { 0x06df, 0x044a }, /* Cyrillic_hardsign ъ CYRILLIC SMALL LETTER HARD SIGN */ + { 0x06e0, 0x042e }, /* Cyrillic_YU Ю CYRILLIC CAPITAL LETTER YU */ + { 0x06e1, 0x0410 }, /* Cyrillic_A А CYRILLIC CAPITAL LETTER A */ + { 0x06e2, 0x0411 }, /* Cyrillic_BE Б CYRILLIC CAPITAL LETTER BE */ + { 0x06e3, 0x0426 }, /* Cyrillic_TSE Ц CYRILLIC CAPITAL LETTER TSE */ + { 0x06e4, 0x0414 }, /* Cyrillic_DE Д CYRILLIC CAPITAL LETTER DE */ + { 0x06e5, 0x0415 }, /* Cyrillic_IE Е CYRILLIC CAPITAL LETTER IE */ + { 0x06e6, 0x0424 }, /* Cyrillic_EF Ф CYRILLIC CAPITAL LETTER EF */ + { 0x06e7, 0x0413 }, /* Cyrillic_GHE Г CYRILLIC CAPITAL LETTER GHE */ + { 0x06e8, 0x0425 }, /* Cyrillic_HA Ð¥ CYRILLIC CAPITAL LETTER HA */ + { 0x06e9, 0x0418 }, /* Cyrillic_I И CYRILLIC CAPITAL LETTER I */ + { 0x06ea, 0x0419 }, /* Cyrillic_SHORTI Й CYRILLIC CAPITAL LETTER SHORT I */ + { 0x06eb, 0x041a }, /* Cyrillic_KA К CYRILLIC CAPITAL LETTER KA */ + { 0x06ec, 0x041b }, /* Cyrillic_EL Л CYRILLIC CAPITAL LETTER EL */ + { 0x06ed, 0x041c }, /* Cyrillic_EM М CYRILLIC CAPITAL LETTER EM */ + { 0x06ee, 0x041d }, /* Cyrillic_EN Н CYRILLIC CAPITAL LETTER EN */ + { 0x06ef, 0x041e }, /* Cyrillic_O О CYRILLIC CAPITAL LETTER O */ + { 0x06f0, 0x041f }, /* Cyrillic_PE П CYRILLIC CAPITAL LETTER PE */ + { 0x06f1, 0x042f }, /* Cyrillic_YA Я CYRILLIC CAPITAL LETTER YA */ + { 0x06f2, 0x0420 }, /* Cyrillic_ER Р CYRILLIC CAPITAL LETTER ER */ + { 0x06f3, 0x0421 }, /* Cyrillic_ES С CYRILLIC CAPITAL LETTER ES */ + { 0x06f4, 0x0422 }, /* Cyrillic_TE Т CYRILLIC CAPITAL LETTER TE */ + { 0x06f5, 0x0423 }, /* Cyrillic_U У CYRILLIC CAPITAL LETTER U */ + { 0x06f6, 0x0416 }, /* Cyrillic_ZHE Ж CYRILLIC CAPITAL LETTER ZHE */ + { 0x06f7, 0x0412 }, /* Cyrillic_VE В CYRILLIC CAPITAL LETTER VE */ + { 0x06f8, 0x042c }, /* Cyrillic_SOFTSIGN Ь CYRILLIC CAPITAL LETTER SOFT SIGN */ + { 0x06f9, 0x042b }, /* Cyrillic_YERU Ы CYRILLIC CAPITAL LETTER YERU */ + { 0x06fa, 0x0417 }, /* Cyrillic_ZE З CYRILLIC CAPITAL LETTER ZE */ + { 0x06fb, 0x0428 }, /* Cyrillic_SHA Ш CYRILLIC CAPITAL LETTER SHA */ + { 0x06fc, 0x042d }, /* Cyrillic_E Э CYRILLIC CAPITAL LETTER E */ + { 0x06fd, 0x0429 }, /* Cyrillic_SHCHA Щ CYRILLIC CAPITAL LETTER SHCHA */ + { 0x06fe, 0x0427 }, /* Cyrillic_CHE Ч CYRILLIC CAPITAL LETTER CHE */ + { 0x06ff, 0x042a }, /* Cyrillic_HARDSIGN Ъ CYRILLIC CAPITAL LETTER HARD SIGN */ + { 0x07a1, 0x0386 }, /* Greek_ALPHAaccent Ά GREEK CAPITAL LETTER ALPHA WITH TONOS */ + { 0x07a2, 0x0388 }, /* Greek_EPSILONaccent Έ GREEK CAPITAL LETTER EPSILON WITH TONOS */ + { 0x07a3, 0x0389 }, /* Greek_ETAaccent Ή GREEK CAPITAL LETTER ETA WITH TONOS */ + { 0x07a4, 0x038a }, /* Greek_IOTAaccent Ί GREEK CAPITAL LETTER IOTA WITH TONOS */ + { 0x07a5, 0x03aa }, /* Greek_IOTAdiaeresis Ϊ GREEK CAPITAL LETTER IOTA WITH DIALYTIKA */ + { 0x07a7, 0x038c }, /* Greek_OMICRONaccent Ό GREEK CAPITAL LETTER OMICRON WITH TONOS */ + { 0x07a8, 0x038e }, /* Greek_UPSILONaccent Ύ GREEK CAPITAL LETTER UPSILON WITH TONOS */ + { 0x07a9, 0x03ab }, /* Greek_UPSILONdieresis Ϋ GREEK CAPITAL LETTER UPSILON WITH DIALYTIKA */ + { 0x07ab, 0x038f }, /* Greek_OMEGAaccent Ώ GREEK CAPITAL LETTER OMEGA WITH TONOS */ + { 0x07ae, 0x0385 }, /* Greek_accentdieresis ΅ GREEK DIALYTIKA TONOS */ + { 0x07af, 0x2015 }, /* Greek_horizbar ― HORIZONTAL BAR */ + { 0x07b1, 0x03ac }, /* Greek_alphaaccent ά GREEK SMALL LETTER ALPHA WITH TONOS */ + { 0x07b2, 0x03ad }, /* Greek_epsilonaccent έ GREEK SMALL LETTER EPSILON WITH TONOS */ + { 0x07b3, 0x03ae }, /* Greek_etaaccent ή GREEK SMALL LETTER ETA WITH TONOS */ + { 0x07b4, 0x03af }, /* Greek_iotaaccent ί GREEK SMALL LETTER IOTA WITH TONOS */ + { 0x07b5, 0x03ca }, /* Greek_iotadieresis ϊ GREEK SMALL LETTER IOTA WITH DIALYTIKA */ + { 0x07b6, 0x0390 }, /* Greek_iotaaccentdieresis ΐ GREEK SMALL LETTER IOTA WITH DIALYTIKA AND TONOS */ + { 0x07b7, 0x03cc }, /* Greek_omicronaccent ό GREEK SMALL LETTER OMICRON WITH TONOS */ + { 0x07b8, 0x03cd }, /* Greek_upsilonaccent ύ GREEK SMALL LETTER UPSILON WITH TONOS */ + { 0x07b9, 0x03cb }, /* Greek_upsilondieresis ϋ GREEK SMALL LETTER UPSILON WITH DIALYTIKA */ + { 0x07ba, 0x03b0 }, /* Greek_upsilonaccentdieresis ΰ GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND TONOS */ + { 0x07bb, 0x03ce }, /* Greek_omegaaccent ώ GREEK SMALL LETTER OMEGA WITH TONOS */ + { 0x07c1, 0x0391 }, /* Greek_ALPHA Α GREEK CAPITAL LETTER ALPHA */ + { 0x07c2, 0x0392 }, /* Greek_BETA Β GREEK CAPITAL LETTER BETA */ + { 0x07c3, 0x0393 }, /* Greek_GAMMA Γ GREEK CAPITAL LETTER GAMMA */ + { 0x07c4, 0x0394 }, /* Greek_DELTA Δ GREEK CAPITAL LETTER DELTA */ + { 0x07c5, 0x0395 }, /* Greek_EPSILON Ε GREEK CAPITAL LETTER EPSILON */ + { 0x07c6, 0x0396 }, /* Greek_ZETA Ζ GREEK CAPITAL LETTER ZETA */ + { 0x07c7, 0x0397 }, /* Greek_ETA Η GREEK CAPITAL LETTER ETA */ + { 0x07c8, 0x0398 }, /* Greek_THETA Θ GREEK CAPITAL LETTER THETA */ + { 0x07c9, 0x0399 }, /* Greek_IOTA Ι GREEK CAPITAL LETTER IOTA */ + { 0x07ca, 0x039a }, /* Greek_KAPPA Κ GREEK CAPITAL LETTER KAPPA */ + { 0x07cb, 0x039b }, /* Greek_LAMBDA Λ GREEK CAPITAL LETTER LAMDA */ + { 0x07cc, 0x039c }, /* Greek_MU Μ GREEK CAPITAL LETTER MU */ + { 0x07cd, 0x039d }, /* Greek_NU Ν GREEK CAPITAL LETTER NU */ + { 0x07ce, 0x039e }, /* Greek_XI Ξ GREEK CAPITAL LETTER XI */ + { 0x07cf, 0x039f }, /* Greek_OMICRON Ο GREEK CAPITAL LETTER OMICRON */ + { 0x07d0, 0x03a0 }, /* Greek_PI Π GREEK CAPITAL LETTER PI */ + { 0x07d1, 0x03a1 }, /* Greek_RHO Ρ GREEK CAPITAL LETTER RHO */ + { 0x07d2, 0x03a3 }, /* Greek_SIGMA Σ GREEK CAPITAL LETTER SIGMA */ + { 0x07d4, 0x03a4 }, /* Greek_TAU Τ GREEK CAPITAL LETTER TAU */ + { 0x07d5, 0x03a5 }, /* Greek_UPSILON Î¥ GREEK CAPITAL LETTER UPSILON */ + { 0x07d6, 0x03a6 }, /* Greek_PHI Φ GREEK CAPITAL LETTER PHI */ + { 0x07d7, 0x03a7 }, /* Greek_CHI Χ GREEK CAPITAL LETTER CHI */ + { 0x07d8, 0x03a8 }, /* Greek_PSI Ψ GREEK CAPITAL LETTER PSI */ + { 0x07d9, 0x03a9 }, /* Greek_OMEGA Ω GREEK CAPITAL LETTER OMEGA */ + { 0x07e1, 0x03b1 }, /* Greek_alpha α GREEK SMALL LETTER ALPHA */ + { 0x07e2, 0x03b2 }, /* Greek_beta β GREEK SMALL LETTER BETA */ + { 0x07e3, 0x03b3 }, /* Greek_gamma γ GREEK SMALL LETTER GAMMA */ + { 0x07e4, 0x03b4 }, /* Greek_delta δ GREEK SMALL LETTER DELTA */ + { 0x07e5, 0x03b5 }, /* Greek_epsilon ε GREEK SMALL LETTER EPSILON */ + { 0x07e6, 0x03b6 }, /* Greek_zeta ζ GREEK SMALL LETTER ZETA */ + { 0x07e7, 0x03b7 }, /* Greek_eta η GREEK SMALL LETTER ETA */ + { 0x07e8, 0x03b8 }, /* Greek_theta θ GREEK SMALL LETTER THETA */ + { 0x07e9, 0x03b9 }, /* Greek_iota ι GREEK SMALL LETTER IOTA */ + { 0x07ea, 0x03ba }, /* Greek_kappa κ GREEK SMALL LETTER KAPPA */ + { 0x07eb, 0x03bb }, /* Greek_lambda λ GREEK SMALL LETTER LAMDA */ + { 0x07ec, 0x03bc }, /* Greek_mu μ GREEK SMALL LETTER MU */ + { 0x07ed, 0x03bd }, /* Greek_nu ν GREEK SMALL LETTER NU */ + { 0x07ee, 0x03be }, /* Greek_xi ξ GREEK SMALL LETTER XI */ + { 0x07ef, 0x03bf }, /* Greek_omicron ο GREEK SMALL LETTER OMICRON */ + { 0x07f0, 0x03c0 }, /* Greek_pi π GREEK SMALL LETTER PI */ + { 0x07f1, 0x03c1 }, /* Greek_rho ρ GREEK SMALL LETTER RHO */ + { 0x07f2, 0x03c3 }, /* Greek_sigma σ GREEK SMALL LETTER SIGMA */ + { 0x07f3, 0x03c2 }, /* Greek_finalsmallsigma ς GREEK SMALL LETTER FINAL SIGMA */ + { 0x07f4, 0x03c4 }, /* Greek_tau τ GREEK SMALL LETTER TAU */ + { 0x07f5, 0x03c5 }, /* Greek_upsilon υ GREEK SMALL LETTER UPSILON */ + { 0x07f6, 0x03c6 }, /* Greek_phi φ GREEK SMALL LETTER PHI */ + { 0x07f7, 0x03c7 }, /* Greek_chi χ GREEK SMALL LETTER CHI */ + { 0x07f8, 0x03c8 }, /* Greek_psi ψ GREEK SMALL LETTER PSI */ + { 0x07f9, 0x03c9 }, /* Greek_omega ω GREEK SMALL LETTER OMEGA */ +/* 0x08a1 leftradical ? ??? */ +/* 0x08a2 topleftradical ? ??? */ +/* 0x08a3 horizconnector ? ??? */ + { 0x08a4, 0x2320 }, /* topintegral ⌠ TOP HALF INTEGRAL */ + { 0x08a5, 0x2321 }, /* botintegral ⌡ BOTTOM HALF INTEGRAL */ + { 0x08a6, 0x2502 }, /* vertconnector │ BOX DRAWINGS LIGHT VERTICAL */ +/* 0x08a7 topleftsqbracket ? ??? */ +/* 0x08a8 botleftsqbracket ? ??? */ +/* 0x08a9 toprightsqbracket ? ??? */ +/* 0x08aa botrightsqbracket ? ??? */ +/* 0x08ab topleftparens ? ??? */ +/* 0x08ac botleftparens ? ??? */ +/* 0x08ad toprightparens ? ??? */ +/* 0x08ae botrightparens ? ??? */ +/* 0x08af leftmiddlecurlybrace ? ??? */ +/* 0x08b0 rightmiddlecurlybrace ? ??? */ +/* 0x08b1 topleftsummation ? ??? */ +/* 0x08b2 botleftsummation ? ??? */ +/* 0x08b3 topvertsummationconnector ? ??? */ +/* 0x08b4 botvertsummationconnector ? ??? */ +/* 0x08b5 toprightsummation ? ??? */ +/* 0x08b6 botrightsummation ? ??? */ +/* 0x08b7 rightmiddlesummation ? ??? */ + { 0x08bc, 0x2264 }, /* lessthanequal ≤ LESS-THAN OR EQUAL TO */ + { 0x08bd, 0x2260 }, /* notequal ≠ NOT EQUAL TO */ + { 0x08be, 0x2265 }, /* greaterthanequal ≥ GREATER-THAN OR EQUAL TO */ + { 0x08bf, 0x222b }, /* integral ∫ INTEGRAL */ + { 0x08c0, 0x2234 }, /* therefore ∴ THEREFORE */ + { 0x08c1, 0x221d }, /* variation ∝ PROPORTIONAL TO */ + { 0x08c2, 0x221e }, /* infinity ∞ INFINITY */ + { 0x08c5, 0x2207 }, /* nabla ∇ NABLA */ + { 0x08c8, 0x2245 }, /* approximate ≅ APPROXIMATELY EQUAL TO */ +/* 0x08c9 similarequal ? ??? */ + { 0x08cd, 0x21d4 }, /* ifonlyif ⇔ LEFT RIGHT DOUBLE ARROW */ + { 0x08ce, 0x21d2 }, /* implies ⇒ RIGHTWARDS DOUBLE ARROW */ + { 0x08cf, 0x2261 }, /* identical ≡ IDENTICAL TO */ + { 0x08d6, 0x221a }, /* radical √ SQUARE ROOT */ + { 0x08da, 0x2282 }, /* includedin ⊂ SUBSET OF */ + { 0x08db, 0x2283 }, /* includes ⊃ SUPERSET OF */ + { 0x08dc, 0x2229 }, /* intersection ∩ INTERSECTION */ + { 0x08dd, 0x222a }, /* union ∪ UNION */ + { 0x08de, 0x2227 }, /* logicaland ∧ LOGICAL AND */ + { 0x08df, 0x2228 }, /* logicalor ∨ LOGICAL OR */ + { 0x08ef, 0x2202 }, /* partialderivative ∂ PARTIAL DIFFERENTIAL */ + { 0x08f6, 0x0192 }, /* function ƒ LATIN SMALL LETTER F WITH HOOK */ + { 0x08fb, 0x2190 }, /* leftarrow ← LEFTWARDS ARROW */ + { 0x08fc, 0x2191 }, /* uparrow ↑ UPWARDS ARROW */ + { 0x08fd, 0x2192 }, /* rightarrow → RIGHTWARDS ARROW */ + { 0x08fe, 0x2193 }, /* downarrow ↓ DOWNWARDS ARROW */ + { 0x09df, 0x2422 }, /* blank ␢ BLANK SYMBOL */ + { 0x09e0, 0x25c6 }, /* soliddiamond ◆ BLACK DIAMOND */ + { 0x09e1, 0x2592 }, /* checkerboard ▒ MEDIUM SHADE */ + { 0x09e2, 0x2409 }, /* ht ␉ SYMBOL FOR HORIZONTAL TABULATION */ + { 0x09e3, 0x240c }, /* ff ␌ SYMBOL FOR FORM FEED */ + { 0x09e4, 0x240d }, /* cr ␍ SYMBOL FOR CARRIAGE RETURN */ + { 0x09e5, 0x240a }, /* lf ␊ SYMBOL FOR LINE FEED */ + { 0x09e8, 0x2424 }, /* nl ␤ SYMBOL FOR NEWLINE */ + { 0x09e9, 0x240b }, /* vt ␋ SYMBOL FOR VERTICAL TABULATION */ + { 0x09ea, 0x2518 }, /* lowrightcorner ┘ BOX DRAWINGS LIGHT UP AND LEFT */ + { 0x09eb, 0x2510 }, /* uprightcorner ┐ BOX DRAWINGS LIGHT DOWN AND LEFT */ + { 0x09ec, 0x250c }, /* upleftcorner ┌ BOX DRAWINGS LIGHT DOWN AND RIGHT */ + { 0x09ed, 0x2514 }, /* lowleftcorner └ BOX DRAWINGS LIGHT UP AND RIGHT */ + { 0x09ee, 0x253c }, /* crossinglines ┼ BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL */ +/* 0x09ef horizlinescan1 ? ??? */ +/* 0x09f0 horizlinescan3 ? ??? */ + { 0x09f1, 0x2500 }, /* horizlinescan5 ─ BOX DRAWINGS LIGHT HORIZONTAL */ +/* 0x09f2 horizlinescan7 ? ??? */ +/* 0x09f3 horizlinescan9 ? ??? */ + { 0x09f4, 0x251c }, /* leftt ├ BOX DRAWINGS LIGHT VERTICAL AND RIGHT */ + { 0x09f5, 0x2524 }, /* rightt ┤ BOX DRAWINGS LIGHT VERTICAL AND LEFT */ + { 0x09f6, 0x2534 }, /* bott ┴ BOX DRAWINGS LIGHT UP AND HORIZONTAL */ + { 0x09f7, 0x252c }, /* topt ┬ BOX DRAWINGS LIGHT DOWN AND HORIZONTAL */ + { 0x09f8, 0x2502 }, /* vertbar │ BOX DRAWINGS LIGHT VERTICAL */ + { 0x0aa1, 0x2003 }, /* emspace   EM SPACE */ + { 0x0aa2, 0x2002 }, /* enspace   EN SPACE */ + { 0x0aa3, 0x2004 }, /* em3space   THREE-PER-EM SPACE */ + { 0x0aa4, 0x2005 }, /* em4space   FOUR-PER-EM SPACE */ + { 0x0aa5, 0x2007 }, /* digitspace   FIGURE SPACE */ + { 0x0aa6, 0x2008 }, /* punctspace   PUNCTUATION SPACE */ + { 0x0aa7, 0x2009 }, /* thinspace   THIN SPACE */ + { 0x0aa8, 0x200a }, /* hairspace   HAIR SPACE */ + { 0x0aa9, 0x2014 }, /* emdash — EM DASH */ + { 0x0aaa, 0x2013 }, /* endash – EN DASH */ +/* 0x0aac signifblank ? ??? */ + { 0x0aae, 0x2026 }, /* ellipsis … HORIZONTAL ELLIPSIS */ +/* 0x0aaf doubbaselinedot ? ??? */ + { 0x0ab0, 0x2153 }, /* onethird ⅓ VULGAR FRACTION ONE THIRD */ + { 0x0ab1, 0x2154 }, /* twothirds ⅔ VULGAR FRACTION TWO THIRDS */ + { 0x0ab2, 0x2155 }, /* onefifth ⅕ VULGAR FRACTION ONE FIFTH */ + { 0x0ab3, 0x2156 }, /* twofifths ⅖ VULGAR FRACTION TWO FIFTHS */ + { 0x0ab4, 0x2157 }, /* threefifths ⅗ VULGAR FRACTION THREE FIFTHS */ + { 0x0ab5, 0x2158 }, /* fourfifths ⅘ VULGAR FRACTION FOUR FIFTHS */ + { 0x0ab6, 0x2159 }, /* onesixth ⅙ VULGAR FRACTION ONE SIXTH */ + { 0x0ab7, 0x215a }, /* fivesixths ⅚ VULGAR FRACTION FIVE SIXTHS */ + { 0x0ab8, 0x2105 }, /* careof ℅ CARE OF */ + { 0x0abb, 0x2012 }, /* figdash ‒ FIGURE DASH */ + { 0x0abc, 0x2329 }, /* leftanglebracket 〈 LEFT-POINTING ANGLE BRACKET */ + { 0x0abd, 0x002e }, /* decimalpoint . FULL STOP */ + { 0x0abe, 0x232a }, /* rightanglebracket 〉 RIGHT-POINTING ANGLE BRACKET */ +/* 0x0abf marker ? ??? */ + { 0x0ac3, 0x215b }, /* oneeighth ⅛ VULGAR FRACTION ONE EIGHTH */ + { 0x0ac4, 0x215c }, /* threeeighths ⅜ VULGAR FRACTION THREE EIGHTHS */ + { 0x0ac5, 0x215d }, /* fiveeighths ⅝ VULGAR FRACTION FIVE EIGHTHS */ + { 0x0ac6, 0x215e }, /* seveneighths ⅞ VULGAR FRACTION SEVEN EIGHTHS */ + { 0x0ac9, 0x2122 }, /* trademark ™ TRADE MARK SIGN */ + { 0x0aca, 0x2613 }, /* signaturemark ☓ SALTIRE */ +/* 0x0acb trademarkincircle ? ??? */ + { 0x0acc, 0x25c1 }, /* leftopentriangle ◁ WHITE LEFT-POINTING TRIANGLE */ + { 0x0acd, 0x25b7 }, /* rightopentriangle ▷ WHITE RIGHT-POINTING TRIANGLE */ + { 0x0ace, 0x25cb }, /* emopencircle ○ WHITE CIRCLE */ + { 0x0acf, 0x25a1 }, /* emopenrectangle □ WHITE SQUARE */ + { 0x0ad0, 0x2018 }, /* leftsinglequotemark ‘ LEFT SINGLE QUOTATION MARK */ + { 0x0ad1, 0x2019 }, /* rightsinglequotemark ’ RIGHT SINGLE QUOTATION MARK */ + { 0x0ad2, 0x201c }, /* leftdoublequotemark “ LEFT DOUBLE QUOTATION MARK */ + { 0x0ad3, 0x201d }, /* rightdoublequotemark ” RIGHT DOUBLE QUOTATION MARK */ + { 0x0ad4, 0x211e }, /* prescription ℞ PRESCRIPTION TAKE */ + { 0x0ad6, 0x2032 }, /* minutes ′ PRIME */ + { 0x0ad7, 0x2033 }, /* seconds ″ DOUBLE PRIME */ + { 0x0ad9, 0x271d }, /* latincross ✝ LATIN CROSS */ +/* 0x0ada hexagram ? ??? */ + { 0x0adb, 0x25ac }, /* filledrectbullet ▬ BLACK RECTANGLE */ + { 0x0adc, 0x25c0 }, /* filledlefttribullet ◀ BLACK LEFT-POINTING TRIANGLE */ + { 0x0add, 0x25b6 }, /* filledrighttribullet ▶ BLACK RIGHT-POINTING TRIANGLE */ + { 0x0ade, 0x25cf }, /* emfilledcircle ● BLACK CIRCLE */ + { 0x0adf, 0x25a0 }, /* emfilledrect ■ BLACK SQUARE */ + { 0x0ae0, 0x25e6 }, /* enopencircbullet ◦ WHITE BULLET */ + { 0x0ae1, 0x25ab }, /* enopensquarebullet ▫ WHITE SMALL SQUARE */ + { 0x0ae2, 0x25ad }, /* openrectbullet ▭ WHITE RECTANGLE */ + { 0x0ae3, 0x25b3 }, /* opentribulletup △ WHITE UP-POINTING TRIANGLE */ + { 0x0ae4, 0x25bd }, /* opentribulletdown ▽ WHITE DOWN-POINTING TRIANGLE */ + { 0x0ae5, 0x2606 }, /* openstar ☆ WHITE STAR */ + { 0x0ae6, 0x2022 }, /* enfilledcircbullet • BULLET */ + { 0x0ae7, 0x25aa }, /* enfilledsqbullet ▪ BLACK SMALL SQUARE */ + { 0x0ae8, 0x25b2 }, /* filledtribulletup ▲ BLACK UP-POINTING TRIANGLE */ + { 0x0ae9, 0x25bc }, /* filledtribulletdown ▼ BLACK DOWN-POINTING TRIANGLE */ + { 0x0aea, 0x261c }, /* leftpointer ☜ WHITE LEFT POINTING INDEX */ + { 0x0aeb, 0x261e }, /* rightpointer ☞ WHITE RIGHT POINTING INDEX */ + { 0x0aec, 0x2663 }, /* club ♣ BLACK CLUB SUIT */ + { 0x0aed, 0x2666 }, /* diamond ♦ BLACK DIAMOND SUIT */ + { 0x0aee, 0x2665 }, /* heart ♥ BLACK HEART SUIT */ + { 0x0af0, 0x2720 }, /* maltesecross ✠ MALTESE CROSS */ + { 0x0af1, 0x2020 }, /* dagger † DAGGER */ + { 0x0af2, 0x2021 }, /* doubledagger ‡ DOUBLE DAGGER */ + { 0x0af3, 0x2713 }, /* checkmark ✓ CHECK MARK */ + { 0x0af4, 0x2717 }, /* ballotcross ✗ BALLOT X */ + { 0x0af5, 0x266f }, /* musicalsharp ♯ MUSIC SHARP SIGN */ + { 0x0af6, 0x266d }, /* musicalflat ♭ MUSIC FLAT SIGN */ + { 0x0af7, 0x2642 }, /* malesymbol ♂ MALE SIGN */ + { 0x0af8, 0x2640 }, /* femalesymbol ♀ FEMALE SIGN */ + { 0x0af9, 0x260e }, /* telephone ☎ BLACK TELEPHONE */ + { 0x0afa, 0x2315 }, /* telephonerecorder ⌕ TELEPHONE RECORDER */ + { 0x0afb, 0x2117 }, /* phonographcopyright ℗ SOUND RECORDING COPYRIGHT */ + { 0x0afc, 0x2038 }, /* caret ‸ CARET */ + { 0x0afd, 0x201a }, /* singlelowquotemark ‚ SINGLE LOW-9 QUOTATION MARK */ + { 0x0afe, 0x201e }, /* doublelowquotemark „ DOUBLE LOW-9 QUOTATION MARK */ +/* 0x0aff cursor ? ??? */ + { 0x0ba3, 0x003c }, /* leftcaret < LESS-THAN SIGN */ + { 0x0ba6, 0x003e }, /* rightcaret > GREATER-THAN SIGN */ + { 0x0ba8, 0x2228 }, /* downcaret ∨ LOGICAL OR */ + { 0x0ba9, 0x2227 }, /* upcaret ∧ LOGICAL AND */ + { 0x0bc0, 0x00af }, /* overbar ¯ MACRON */ + { 0x0bc2, 0x22a4 }, /* downtack ⊤ DOWN TACK */ + { 0x0bc3, 0x2229 }, /* upshoe ∩ INTERSECTION */ + { 0x0bc4, 0x230a }, /* downstile ⌊ LEFT FLOOR */ + { 0x0bc6, 0x005f }, /* underbar _ LOW LINE */ + { 0x0bca, 0x2218 }, /* jot ∘ RING OPERATOR */ + { 0x0bcc, 0x2395 }, /* quad ⎕ APL FUNCTIONAL SYMBOL QUAD (Unicode 3.0) */ + { 0x0bce, 0x22a5 }, /* uptack ⊥ UP TACK */ + { 0x0bcf, 0x25cb }, /* circle ○ WHITE CIRCLE */ + { 0x0bd3, 0x2308 }, /* upstile ⌈ LEFT CEILING */ + { 0x0bd6, 0x222a }, /* downshoe ∪ UNION */ + { 0x0bd8, 0x2283 }, /* rightshoe ⊃ SUPERSET OF */ + { 0x0bda, 0x2282 }, /* leftshoe ⊂ SUBSET OF */ + { 0x0bdc, 0x22a3 }, /* lefttack ⊣ LEFT TACK */ + { 0x0bfc, 0x22a2 }, /* righttack ⊢ RIGHT TACK */ + { 0x0cdf, 0x2017 }, /* hebrew_doublelowline ‗ DOUBLE LOW LINE */ + { 0x0ce0, 0x05d0 }, /* hebrew_aleph א HEBREW LETTER ALEF */ + { 0x0ce1, 0x05d1 }, /* hebrew_bet ב HEBREW LETTER BET */ + { 0x0ce2, 0x05d2 }, /* hebrew_gimel ג HEBREW LETTER GIMEL */ + { 0x0ce3, 0x05d3 }, /* hebrew_dalet ד HEBREW LETTER DALET */ + { 0x0ce4, 0x05d4 }, /* hebrew_he ה HEBREW LETTER HE */ + { 0x0ce5, 0x05d5 }, /* hebrew_waw ו HEBREW LETTER VAV */ + { 0x0ce6, 0x05d6 }, /* hebrew_zain ז HEBREW LETTER ZAYIN */ + { 0x0ce7, 0x05d7 }, /* hebrew_chet ח HEBREW LETTER HET */ + { 0x0ce8, 0x05d8 }, /* hebrew_tet ט HEBREW LETTER TET */ + { 0x0ce9, 0x05d9 }, /* hebrew_yod י HEBREW LETTER YOD */ + { 0x0cea, 0x05da }, /* hebrew_finalkaph ך HEBREW LETTER FINAL KAF */ + { 0x0ceb, 0x05db }, /* hebrew_kaph כ HEBREW LETTER KAF */ + { 0x0cec, 0x05dc }, /* hebrew_lamed ל HEBREW LETTER LAMED */ + { 0x0ced, 0x05dd }, /* hebrew_finalmem ם HEBREW LETTER FINAL MEM */ + { 0x0cee, 0x05de }, /* hebrew_mem מ HEBREW LETTER MEM */ + { 0x0cef, 0x05df }, /* hebrew_finalnun ן HEBREW LETTER FINAL NUN */ + { 0x0cf0, 0x05e0 }, /* hebrew_nun ×  HEBREW LETTER NUN */ + { 0x0cf1, 0x05e1 }, /* hebrew_samech ס HEBREW LETTER SAMEKH */ + { 0x0cf2, 0x05e2 }, /* hebrew_ayin ×¢ HEBREW LETTER AYIN */ + { 0x0cf3, 0x05e3 }, /* hebrew_finalpe ×£ HEBREW LETTER FINAL PE */ + { 0x0cf4, 0x05e4 }, /* hebrew_pe פ HEBREW LETTER PE */ + { 0x0cf5, 0x05e5 }, /* hebrew_finalzade ×¥ HEBREW LETTER FINAL TSADI */ + { 0x0cf6, 0x05e6 }, /* hebrew_zade צ HEBREW LETTER TSADI */ + { 0x0cf7, 0x05e7 }, /* hebrew_qoph ק HEBREW LETTER QOF */ + { 0x0cf8, 0x05e8 }, /* hebrew_resh ר HEBREW LETTER RESH */ + { 0x0cf9, 0x05e9 }, /* hebrew_shin ש HEBREW LETTER SHIN */ + { 0x0cfa, 0x05ea }, /* hebrew_taw ת HEBREW LETTER TAV */ + { 0x0da1, 0x0e01 }, /* Thai_kokai ก THAI CHARACTER KO KAI */ + { 0x0da2, 0x0e02 }, /* Thai_khokhai ข THAI CHARACTER KHO KHAI */ + { 0x0da3, 0x0e03 }, /* Thai_khokhuat ฃ THAI CHARACTER KHO KHUAT */ + { 0x0da4, 0x0e04 }, /* Thai_khokhwai ค THAI CHARACTER KHO KHWAI */ + { 0x0da5, 0x0e05 }, /* Thai_khokhon ฅ THAI CHARACTER KHO KHON */ + { 0x0da6, 0x0e06 }, /* Thai_khorakhang ฆ THAI CHARACTER KHO RAKHANG */ + { 0x0da7, 0x0e07 }, /* Thai_ngongu ง THAI CHARACTER NGO NGU */ + { 0x0da8, 0x0e08 }, /* Thai_chochan จ THAI CHARACTER CHO CHAN */ + { 0x0da9, 0x0e09 }, /* Thai_choching ฉ THAI CHARACTER CHO CHING */ + { 0x0daa, 0x0e0a }, /* Thai_chochang ช THAI CHARACTER CHO CHANG */ + { 0x0dab, 0x0e0b }, /* Thai_soso ซ THAI CHARACTER SO SO */ + { 0x0dac, 0x0e0c }, /* Thai_chochoe ฌ THAI CHARACTER CHO CHOE */ + { 0x0dad, 0x0e0d }, /* Thai_yoying ญ THAI CHARACTER YO YING */ + { 0x0dae, 0x0e0e }, /* Thai_dochada ฎ THAI CHARACTER DO CHADA */ + { 0x0daf, 0x0e0f }, /* Thai_topatak ฏ THAI CHARACTER TO PATAK */ + { 0x0db0, 0x0e10 }, /* Thai_thothan ฐ THAI CHARACTER THO THAN */ + { 0x0db1, 0x0e11 }, /* Thai_thonangmontho ฑ THAI CHARACTER THO NANGMONTHO */ + { 0x0db2, 0x0e12 }, /* Thai_thophuthao ฒ THAI CHARACTER THO PHUTHAO */ + { 0x0db3, 0x0e13 }, /* Thai_nonen ณ THAI CHARACTER NO NEN */ + { 0x0db4, 0x0e14 }, /* Thai_dodek ด THAI CHARACTER DO DEK */ + { 0x0db5, 0x0e15 }, /* Thai_totao ต THAI CHARACTER TO TAO */ + { 0x0db6, 0x0e16 }, /* Thai_thothung ถ THAI CHARACTER THO THUNG */ + { 0x0db7, 0x0e17 }, /* Thai_thothahan ท THAI CHARACTER THO THAHAN */ + { 0x0db8, 0x0e18 }, /* Thai_thothong ธ THAI CHARACTER THO THONG */ + { 0x0db9, 0x0e19 }, /* Thai_nonu น THAI CHARACTER NO NU */ + { 0x0dba, 0x0e1a }, /* Thai_bobaimai บ THAI CHARACTER BO BAIMAI */ + { 0x0dbb, 0x0e1b }, /* Thai_popla ป THAI CHARACTER PO PLA */ + { 0x0dbc, 0x0e1c }, /* Thai_phophung ผ THAI CHARACTER PHO PHUNG */ + { 0x0dbd, 0x0e1d }, /* Thai_fofa ฝ THAI CHARACTER FO FA */ + { 0x0dbe, 0x0e1e }, /* Thai_phophan พ THAI CHARACTER PHO PHAN */ + { 0x0dbf, 0x0e1f }, /* Thai_fofan ฟ THAI CHARACTER FO FAN */ + { 0x0dc0, 0x0e20 }, /* Thai_phosamphao ภ THAI CHARACTER PHO SAMPHAO */ + { 0x0dc1, 0x0e21 }, /* Thai_moma ม THAI CHARACTER MO MA */ + { 0x0dc2, 0x0e22 }, /* Thai_yoyak ย THAI CHARACTER YO YAK */ + { 0x0dc3, 0x0e23 }, /* Thai_rorua ร THAI CHARACTER RO RUA */ + { 0x0dc4, 0x0e24 }, /* Thai_ru ฤ THAI CHARACTER RU */ + { 0x0dc5, 0x0e25 }, /* Thai_loling ล THAI CHARACTER LO LING */ + { 0x0dc6, 0x0e26 }, /* Thai_lu ฦ THAI CHARACTER LU */ + { 0x0dc7, 0x0e27 }, /* Thai_wowaen ว THAI CHARACTER WO WAEN */ + { 0x0dc8, 0x0e28 }, /* Thai_sosala ศ THAI CHARACTER SO SALA */ + { 0x0dc9, 0x0e29 }, /* Thai_sorusi ษ THAI CHARACTER SO RUSI */ + { 0x0dca, 0x0e2a }, /* Thai_sosua ส THAI CHARACTER SO SUA */ + { 0x0dcb, 0x0e2b }, /* Thai_hohip ห THAI CHARACTER HO HIP */ + { 0x0dcc, 0x0e2c }, /* Thai_lochula ฬ THAI CHARACTER LO CHULA */ + { 0x0dcd, 0x0e2d }, /* Thai_oang อ THAI CHARACTER O ANG */ + { 0x0dce, 0x0e2e }, /* Thai_honokhuk ฮ THAI CHARACTER HO NOKHUK */ + { 0x0dcf, 0x0e2f }, /* Thai_paiyannoi ฯ THAI CHARACTER PAIYANNOI */ + { 0x0dd0, 0x0e30 }, /* Thai_saraa ะ THAI CHARACTER SARA A */ + { 0x0dd1, 0x0e31 }, /* Thai_maihanakat ั THAI CHARACTER MAI HAN-AKAT */ + { 0x0dd2, 0x0e32 }, /* Thai_saraaa า THAI CHARACTER SARA AA */ + { 0x0dd3, 0x0e33 }, /* Thai_saraam ำ THAI CHARACTER SARA AM */ + { 0x0dd4, 0x0e34 }, /* Thai_sarai ิ THAI CHARACTER SARA I */ + { 0x0dd5, 0x0e35 }, /* Thai_saraii ี THAI CHARACTER SARA II */ + { 0x0dd6, 0x0e36 }, /* Thai_saraue ึ THAI CHARACTER SARA UE */ + { 0x0dd7, 0x0e37 }, /* Thai_sarauee ื THAI CHARACTER SARA UEE */ + { 0x0dd8, 0x0e38 }, /* Thai_sarau ุ THAI CHARACTER SARA U */ + { 0x0dd9, 0x0e39 }, /* Thai_sarauu ู THAI CHARACTER SARA UU */ + { 0x0dda, 0x0e3a }, /* Thai_phinthu ฺ THAI CHARACTER PHINTHU */ + { 0x0dde, 0x0e3e }, /* Thai_maihanakat_maitho ฾ ??? */ + { 0x0ddf, 0x0e3f }, /* Thai_baht ฿ THAI CURRENCY SYMBOL BAHT */ + { 0x0de0, 0x0e40 }, /* Thai_sarae เ THAI CHARACTER SARA E */ + { 0x0de1, 0x0e41 }, /* Thai_saraae แ THAI CHARACTER SARA AE */ + { 0x0de2, 0x0e42 }, /* Thai_sarao โ THAI CHARACTER SARA O */ + { 0x0de3, 0x0e43 }, /* Thai_saraaimaimuan ใ THAI CHARACTER SARA AI MAIMUAN */ + { 0x0de4, 0x0e44 }, /* Thai_saraaimaimalai ไ THAI CHARACTER SARA AI MAIMALAI */ + { 0x0de5, 0x0e45 }, /* Thai_lakkhangyao ๅ THAI CHARACTER LAKKHANGYAO */ + { 0x0de6, 0x0e46 }, /* Thai_maiyamok ๆ THAI CHARACTER MAIYAMOK */ + { 0x0de7, 0x0e47 }, /* Thai_maitaikhu ็ THAI CHARACTER MAITAIKHU */ + { 0x0de8, 0x0e48 }, /* Thai_maiek ่ THAI CHARACTER MAI EK */ + { 0x0de9, 0x0e49 }, /* Thai_maitho ้ THAI CHARACTER MAI THO */ + { 0x0dea, 0x0e4a }, /* Thai_maitri ๊ THAI CHARACTER MAI TRI */ + { 0x0deb, 0x0e4b }, /* Thai_maichattawa ๋ THAI CHARACTER MAI CHATTAWA */ + { 0x0dec, 0x0e4c }, /* Thai_thanthakhat ์ THAI CHARACTER THANTHAKHAT */ + { 0x0ded, 0x0e4d }, /* Thai_nikhahit ํ THAI CHARACTER NIKHAHIT */ + { 0x0df0, 0x0e50 }, /* Thai_leksun ๐ THAI DIGIT ZERO */ + { 0x0df1, 0x0e51 }, /* Thai_leknung ๑ THAI DIGIT ONE */ + { 0x0df2, 0x0e52 }, /* Thai_leksong ๒ THAI DIGIT TWO */ + { 0x0df3, 0x0e53 }, /* Thai_leksam ๓ THAI DIGIT THREE */ + { 0x0df4, 0x0e54 }, /* Thai_leksi ๔ THAI DIGIT FOUR */ + { 0x0df5, 0x0e55 }, /* Thai_lekha ๕ THAI DIGIT FIVE */ + { 0x0df6, 0x0e56 }, /* Thai_lekhok ๖ THAI DIGIT SIX */ + { 0x0df7, 0x0e57 }, /* Thai_lekchet ๗ THAI DIGIT SEVEN */ + { 0x0df8, 0x0e58 }, /* Thai_lekpaet ๘ THAI DIGIT EIGHT */ + { 0x0df9, 0x0e59 }, /* Thai_lekkao ๙ THAI DIGIT NINE */ + { 0x0ea1, 0x3131 }, /* Hangul_Kiyeog ㄱ HANGUL LETTER KIYEOK */ + { 0x0ea2, 0x3132 }, /* Hangul_SsangKiyeog ㄲ HANGUL LETTER SSANGKIYEOK */ + { 0x0ea3, 0x3133 }, /* Hangul_KiyeogSios ㄳ HANGUL LETTER KIYEOK-SIOS */ + { 0x0ea4, 0x3134 }, /* Hangul_Nieun ㄴ HANGUL LETTER NIEUN */ + { 0x0ea5, 0x3135 }, /* Hangul_NieunJieuj ㄵ HANGUL LETTER NIEUN-CIEUC */ + { 0x0ea6, 0x3136 }, /* Hangul_NieunHieuh ㄶ HANGUL LETTER NIEUN-HIEUH */ + { 0x0ea7, 0x3137 }, /* Hangul_Dikeud ㄷ HANGUL LETTER TIKEUT */ + { 0x0ea8, 0x3138 }, /* Hangul_SsangDikeud ㄸ HANGUL LETTER SSANGTIKEUT */ + { 0x0ea9, 0x3139 }, /* Hangul_Rieul ㄹ HANGUL LETTER RIEUL */ + { 0x0eaa, 0x313a }, /* Hangul_RieulKiyeog ㄺ HANGUL LETTER RIEUL-KIYEOK */ + { 0x0eab, 0x313b }, /* Hangul_RieulMieum ㄻ HANGUL LETTER RIEUL-MIEUM */ + { 0x0eac, 0x313c }, /* Hangul_RieulPieub ㄼ HANGUL LETTER RIEUL-PIEUP */ + { 0x0ead, 0x313d }, /* Hangul_RieulSios ㄽ HANGUL LETTER RIEUL-SIOS */ + { 0x0eae, 0x313e }, /* Hangul_RieulTieut ㄾ HANGUL LETTER RIEUL-THIEUTH */ + { 0x0eaf, 0x313f }, /* Hangul_RieulPhieuf ㄿ HANGUL LETTER RIEUL-PHIEUPH */ + { 0x0eb0, 0x3140 }, /* Hangul_RieulHieuh ㅀ HANGUL LETTER RIEUL-HIEUH */ + { 0x0eb1, 0x3141 }, /* Hangul_Mieum ㅁ HANGUL LETTER MIEUM */ + { 0x0eb2, 0x3142 }, /* Hangul_Pieub ㅂ HANGUL LETTER PIEUP */ + { 0x0eb3, 0x3143 }, /* Hangul_SsangPieub ㅃ HANGUL LETTER SSANGPIEUP */ + { 0x0eb4, 0x3144 }, /* Hangul_PieubSios ㅄ HANGUL LETTER PIEUP-SIOS */ + { 0x0eb5, 0x3145 }, /* Hangul_Sios ㅅ HANGUL LETTER SIOS */ + { 0x0eb6, 0x3146 }, /* Hangul_SsangSios ㅆ HANGUL LETTER SSANGSIOS */ + { 0x0eb7, 0x3147 }, /* Hangul_Ieung ㅇ HANGUL LETTER IEUNG */ + { 0x0eb8, 0x3148 }, /* Hangul_Jieuj ㅈ HANGUL LETTER CIEUC */ + { 0x0eb9, 0x3149 }, /* Hangul_SsangJieuj ㅉ HANGUL LETTER SSANGCIEUC */ + { 0x0eba, 0x314a }, /* Hangul_Cieuc ㅊ HANGUL LETTER CHIEUCH */ + { 0x0ebb, 0x314b }, /* Hangul_Khieuq ㅋ HANGUL LETTER KHIEUKH */ + { 0x0ebc, 0x314c }, /* Hangul_Tieut ㅌ HANGUL LETTER THIEUTH */ + { 0x0ebd, 0x314d }, /* Hangul_Phieuf ㅍ HANGUL LETTER PHIEUPH */ + { 0x0ebe, 0x314e }, /* Hangul_Hieuh ㅎ HANGUL LETTER HIEUH */ + { 0x0ebf, 0x314f }, /* Hangul_A ㅏ HANGUL LETTER A */ + { 0x0ec0, 0x3150 }, /* Hangul_AE ㅐ HANGUL LETTER AE */ + { 0x0ec1, 0x3151 }, /* Hangul_YA ㅑ HANGUL LETTER YA */ + { 0x0ec2, 0x3152 }, /* Hangul_YAE ㅒ HANGUL LETTER YAE */ + { 0x0ec3, 0x3153 }, /* Hangul_EO ㅓ HANGUL LETTER EO */ + { 0x0ec4, 0x3154 }, /* Hangul_E ㅔ HANGUL LETTER E */ + { 0x0ec5, 0x3155 }, /* Hangul_YEO ㅕ HANGUL LETTER YEO */ + { 0x0ec6, 0x3156 }, /* Hangul_YE ㅖ HANGUL LETTER YE */ + { 0x0ec7, 0x3157 }, /* Hangul_O ㅗ HANGUL LETTER O */ + { 0x0ec8, 0x3158 }, /* Hangul_WA ㅘ HANGUL LETTER WA */ + { 0x0ec9, 0x3159 }, /* Hangul_WAE ㅙ HANGUL LETTER WAE */ + { 0x0eca, 0x315a }, /* Hangul_OE ㅚ HANGUL LETTER OE */ + { 0x0ecb, 0x315b }, /* Hangul_YO ㅛ HANGUL LETTER YO */ + { 0x0ecc, 0x315c }, /* Hangul_U ㅜ HANGUL LETTER U */ + { 0x0ecd, 0x315d }, /* Hangul_WEO ㅝ HANGUL LETTER WEO */ + { 0x0ece, 0x315e }, /* Hangul_WE ㅞ HANGUL LETTER WE */ + { 0x0ecf, 0x315f }, /* Hangul_WI ㅟ HANGUL LETTER WI */ + { 0x0ed0, 0x3160 }, /* Hangul_YU ㅠ HANGUL LETTER YU */ + { 0x0ed1, 0x3161 }, /* Hangul_EU ㅡ HANGUL LETTER EU */ + { 0x0ed2, 0x3162 }, /* Hangul_YI ㅢ HANGUL LETTER YI */ + { 0x0ed3, 0x3163 }, /* Hangul_I ㅣ HANGUL LETTER I */ + { 0x0ed4, 0x11a8 }, /* Hangul_J_Kiyeog ᆨ HANGUL JONGSEONG KIYEOK */ + { 0x0ed5, 0x11a9 }, /* Hangul_J_SsangKiyeog ᆩ HANGUL JONGSEONG SSANGKIYEOK */ + { 0x0ed6, 0x11aa }, /* Hangul_J_KiyeogSios ᆪ HANGUL JONGSEONG KIYEOK-SIOS */ + { 0x0ed7, 0x11ab }, /* Hangul_J_Nieun ᆫ HANGUL JONGSEONG NIEUN */ + { 0x0ed8, 0x11ac }, /* Hangul_J_NieunJieuj ᆬ HANGUL JONGSEONG NIEUN-CIEUC */ + { 0x0ed9, 0x11ad }, /* Hangul_J_NieunHieuh ᆭ HANGUL JONGSEONG NIEUN-HIEUH */ + { 0x0eda, 0x11ae }, /* Hangul_J_Dikeud ᆮ HANGUL JONGSEONG TIKEUT */ + { 0x0edb, 0x11af }, /* Hangul_J_Rieul ᆯ HANGUL JONGSEONG RIEUL */ + { 0x0edc, 0x11b0 }, /* Hangul_J_RieulKiyeog ᆰ HANGUL JONGSEONG RIEUL-KIYEOK */ + { 0x0edd, 0x11b1 }, /* Hangul_J_RieulMieum ᆱ HANGUL JONGSEONG RIEUL-MIEUM */ + { 0x0ede, 0x11b2 }, /* Hangul_J_RieulPieub ᆲ HANGUL JONGSEONG RIEUL-PIEUP */ + { 0x0edf, 0x11b3 }, /* Hangul_J_RieulSios ᆳ HANGUL JONGSEONG RIEUL-SIOS */ + { 0x0ee0, 0x11b4 }, /* Hangul_J_RieulTieut ᆴ HANGUL JONGSEONG RIEUL-THIEUTH */ + { 0x0ee1, 0x11b5 }, /* Hangul_J_RieulPhieuf ᆵ HANGUL JONGSEONG RIEUL-PHIEUPH */ + { 0x0ee2, 0x11b6 }, /* Hangul_J_RieulHieuh ᆶ HANGUL JONGSEONG RIEUL-HIEUH */ + { 0x0ee3, 0x11b7 }, /* Hangul_J_Mieum ᆷ HANGUL JONGSEONG MIEUM */ + { 0x0ee4, 0x11b8 }, /* Hangul_J_Pieub ᆸ HANGUL JONGSEONG PIEUP */ + { 0x0ee5, 0x11b9 }, /* Hangul_J_PieubSios ᆹ HANGUL JONGSEONG PIEUP-SIOS */ + { 0x0ee6, 0x11ba }, /* Hangul_J_Sios ᆺ HANGUL JONGSEONG SIOS */ + { 0x0ee7, 0x11bb }, /* Hangul_J_SsangSios ᆻ HANGUL JONGSEONG SSANGSIOS */ + { 0x0ee8, 0x11bc }, /* Hangul_J_Ieung ᆼ HANGUL JONGSEONG IEUNG */ + { 0x0ee9, 0x11bd }, /* Hangul_J_Jieuj ᆽ HANGUL JONGSEONG CIEUC */ + { 0x0eea, 0x11be }, /* Hangul_J_Cieuc ᆾ HANGUL JONGSEONG CHIEUCH */ + { 0x0eeb, 0x11bf }, /* Hangul_J_Khieuq ᆿ HANGUL JONGSEONG KHIEUKH */ + { 0x0eec, 0x11c0 }, /* Hangul_J_Tieut ᇀ HANGUL JONGSEONG THIEUTH */ + { 0x0eed, 0x11c1 }, /* Hangul_J_Phieuf ᇁ HANGUL JONGSEONG PHIEUPH */ + { 0x0eee, 0x11c2 }, /* Hangul_J_Hieuh ᇂ HANGUL JONGSEONG HIEUH */ + { 0x0eef, 0x316d }, /* Hangul_RieulYeorinHieuh ㅭ HANGUL LETTER RIEUL-YEORINHIEUH */ + { 0x0ef0, 0x3171 }, /* Hangul_SunkyeongeumMieum ㅱ HANGUL LETTER KAPYEOUNMIEUM */ + { 0x0ef1, 0x3178 }, /* Hangul_SunkyeongeumPieub ㅸ HANGUL LETTER KAPYEOUNPIEUP */ + { 0x0ef2, 0x317f }, /* Hangul_PanSios ㅿ HANGUL LETTER PANSIOS */ +/* 0x0ef3 Hangul_KkogjiDalrinIeung ? ??? */ + { 0x0ef4, 0x3184 }, /* Hangul_SunkyeongeumPhieuf ㆄ HANGUL LETTER KAPYEOUNPHIEUPH */ + { 0x0ef5, 0x3186 }, /* Hangul_YeorinHieuh ㆆ HANGUL LETTER YEORINHIEUH */ + { 0x0ef6, 0x318d }, /* Hangul_AraeA ㆍ HANGUL LETTER ARAEA */ + { 0x0ef7, 0x318e }, /* Hangul_AraeAE ㆎ HANGUL LETTER ARAEAE */ + { 0x0ef8, 0x11eb }, /* Hangul_J_PanSios ᇫ HANGUL JONGSEONG PANSIOS */ +/* 0x0ef9 Hangul_J_KkogjiDalrinIeung ? ??? */ + { 0x0efa, 0x11f9 }, /* Hangul_J_YeorinHieuh ᇹ HANGUL JONGSEONG YEORINHIEUH */ + { 0x0eff, 0x20a9 }, /* Korean_Won ₩ WON SIGN */ + { 0x13bc, 0x0152 }, /* OE Œ LATIN CAPITAL LIGATURE OE */ + { 0x13bd, 0x0153 }, /* oe œ LATIN SMALL LIGATURE OE */ + { 0x13be, 0x0178 }, /* Ydiaeresis Ÿ LATIN CAPITAL LETTER Y WITH DIAERESIS */ + { 0x20a0, 0x20a0 }, /* EcuSign ₠ EURO-CURRENCY SIGN */ + { 0x20a1, 0x20a1 }, /* ColonSign ₡ COLON SIGN */ + { 0x20a2, 0x20a2 }, /* CruzeiroSign ₢ CRUZEIRO SIGN */ + { 0x20a3, 0x20a3 }, /* FFrancSign ₣ FRENCH FRANC SIGN */ + { 0x20a4, 0x20a4 }, /* LiraSign ₤ LIRA SIGN */ + { 0x20a5, 0x20a5 }, /* MillSign ₥ MILL SIGN */ + { 0x20a6, 0x20a6 }, /* NairaSign ₦ NAIRA SIGN */ + { 0x20a7, 0x20a7 }, /* PesetaSign ₧ PESETA SIGN */ + { 0x20a8, 0x20a8 }, /* RupeeSign ₨ RUPEE SIGN */ + { 0x20a9, 0x20a9 }, /* WonSign ₩ WON SIGN */ + { 0x20aa, 0x20aa }, /* NewSheqelSign ₪ NEW SHEQEL SIGN */ + { 0x20ab, 0x20ab }, /* DongSign ₫ DONG SIGN */ + { 0x20ac, 0x20ac }, /* EuroSign € EURO SIGN */ +}; + +static guint +keyval_to_unicode (guint keysym) +{ + int min = 0; + int max = sizeof(k2utab) / sizeof(k2utab[0]) - 1; + int mid; + + /* First check for Latin-1 characters (1:1 mapping) */ + if ((keysym >= 0x0020 && keysym <= 0x007e) || + (keysym >= 0x00a0 && keysym <= 0x00ff)) + return keysym; + + /* Also check for directly encoded 24-bit UCS characters */ + if ((keysym & 0xff000000) == 0x01000000) + return keysym & 0x00ffffff; + + /* binary search in table */ + while (max >= min) { + mid = (min + max) / 2; + if (k2utab[mid].keysym < keysym) + min = mid + 1; + else if (k2utab[mid].keysym > keysym) + max = mid - 1; + else { + /* found it */ + return k2utab[mid].ucs; + } + } + + /* No matching Unicode value found */ + return -1; +} + +#endif /* 0 */ + +struct u2k { + unsigned short keysym; + unsigned short ucs; +} u2ktab[] = { + { 0x0abd, 0x002e }, /* decimalpoint . FULL STOP */ + { 0x0ba3, 0x003c }, /* leftcaret < LESS-THAN SIGN */ + { 0x0ba6, 0x003e }, /* rightcaret > GREATER-THAN SIGN */ + { 0x0bc6, 0x005f }, /* underbar _ LOW LINE */ + { 0x0bc0, 0x00af }, /* overbar ¯ MACRON */ + { 0x03c0, 0x0100 }, /* Amacron Ā LATIN CAPITAL LETTER A WITH MACRON */ + { 0x03e0, 0x0101 }, /* amacron ā LATIN SMALL LETTER A WITH MACRON */ + { 0x01c3, 0x0102 }, /* Abreve Ă LATIN CAPITAL LETTER A WITH BREVE */ + { 0x01e3, 0x0103 }, /* abreve ă LATIN SMALL LETTER A WITH BREVE */ + { 0x01a1, 0x0104 }, /* Aogonek Ą LATIN CAPITAL LETTER A WITH OGONEK */ + { 0x01b1, 0x0105 }, /* aogonek ą LATIN SMALL LETTER A WITH OGONEK */ + { 0x01c6, 0x0106 }, /* Cacute Ć LATIN CAPITAL LETTER C WITH ACUTE */ + { 0x01e6, 0x0107 }, /* cacute ć LATIN SMALL LETTER C WITH ACUTE */ + { 0x02c6, 0x0108 }, /* Ccircumflex Ĉ LATIN CAPITAL LETTER C WITH CIRCUMFLEX */ + { 0x02e6, 0x0109 }, /* ccircumflex ĉ LATIN SMALL LETTER C WITH CIRCUMFLEX */ + { 0x02c5, 0x010a }, /* Cabovedot Ċ LATIN CAPITAL LETTER C WITH DOT ABOVE */ + { 0x02e5, 0x010b }, /* cabovedot ċ LATIN SMALL LETTER C WITH DOT ABOVE */ + { 0x01c8, 0x010c }, /* Ccaron Č LATIN CAPITAL LETTER C WITH CARON */ + { 0x01e8, 0x010d }, /* ccaron č LATIN SMALL LETTER C WITH CARON */ + { 0x01cf, 0x010e }, /* Dcaron Ď LATIN CAPITAL LETTER D WITH CARON */ + { 0x01ef, 0x010f }, /* dcaron ď LATIN SMALL LETTER D WITH CARON */ + { 0x01d0, 0x0110 }, /* Dstroke Đ LATIN CAPITAL LETTER D WITH STROKE */ + { 0x01f0, 0x0111 }, /* dstroke đ LATIN SMALL LETTER D WITH STROKE */ + { 0x03aa, 0x0112 }, /* Emacron Ē LATIN CAPITAL LETTER E WITH MACRON */ + { 0x03ba, 0x0113 }, /* emacron ē LATIN SMALL LETTER E WITH MACRON */ + { 0x03cc, 0x0116 }, /* Eabovedot Ė LATIN CAPITAL LETTER E WITH DOT ABOVE */ + { 0x03ec, 0x0117 }, /* eabovedot ė LATIN SMALL LETTER E WITH DOT ABOVE */ + { 0x01ca, 0x0118 }, /* Eogonek Ę LATIN CAPITAL LETTER E WITH OGONEK */ + { 0x01ea, 0x0119 }, /* eogonek ę LATIN SMALL LETTER E WITH OGONEK */ + { 0x01cc, 0x011a }, /* Ecaron Ě LATIN CAPITAL LETTER E WITH CARON */ + { 0x01ec, 0x011b }, /* ecaron ě LATIN SMALL LETTER E WITH CARON */ + { 0x02d8, 0x011c }, /* Gcircumflex Ĝ LATIN CAPITAL LETTER G WITH CIRCUMFLEX */ + { 0x02f8, 0x011d }, /* gcircumflex ĝ LATIN SMALL LETTER G WITH CIRCUMFLEX */ + { 0x02ab, 0x011e }, /* Gbreve Ğ LATIN CAPITAL LETTER G WITH BREVE */ + { 0x02bb, 0x011f }, /* gbreve ğ LATIN SMALL LETTER G WITH BREVE */ + { 0x02d5, 0x0120 }, /* Gabovedot Ä  LATIN CAPITAL LETTER G WITH DOT ABOVE */ + { 0x02f5, 0x0121 }, /* gabovedot Ä¡ LATIN SMALL LETTER G WITH DOT ABOVE */ + { 0x03ab, 0x0122 }, /* Gcedilla Ä¢ LATIN CAPITAL LETTER G WITH CEDILLA */ + { 0x03bb, 0x0123 }, /* gcedilla Ä£ LATIN SMALL LETTER G WITH CEDILLA */ + { 0x02a6, 0x0124 }, /* Hcircumflex Ĥ LATIN CAPITAL LETTER H WITH CIRCUMFLEX */ + { 0x02b6, 0x0125 }, /* hcircumflex Ä¥ LATIN SMALL LETTER H WITH CIRCUMFLEX */ + { 0x02a1, 0x0126 }, /* Hstroke Ħ LATIN CAPITAL LETTER H WITH STROKE */ + { 0x02b1, 0x0127 }, /* hstroke ħ LATIN SMALL LETTER H WITH STROKE */ + { 0x03a5, 0x0128 }, /* Itilde Ĩ LATIN CAPITAL LETTER I WITH TILDE */ + { 0x03b5, 0x0129 }, /* itilde Ä© LATIN SMALL LETTER I WITH TILDE */ + { 0x03cf, 0x012a }, /* Imacron Ī LATIN CAPITAL LETTER I WITH MACRON */ + { 0x03ef, 0x012b }, /* imacron Ä« LATIN SMALL LETTER I WITH MACRON */ + { 0x03c7, 0x012e }, /* Iogonek Ä® LATIN CAPITAL LETTER I WITH OGONEK */ + { 0x03e7, 0x012f }, /* iogonek į LATIN SMALL LETTER I WITH OGONEK */ + { 0x02a9, 0x0130 }, /* Iabovedot Ä° LATIN CAPITAL LETTER I WITH DOT ABOVE */ + { 0x02b9, 0x0131 }, /* idotless ı LATIN SMALL LETTER DOTLESS I */ + { 0x02ac, 0x0134 }, /* Jcircumflex Ä´ LATIN CAPITAL LETTER J WITH CIRCUMFLEX */ + { 0x02bc, 0x0135 }, /* jcircumflex ĵ LATIN SMALL LETTER J WITH CIRCUMFLEX */ + { 0x03d3, 0x0136 }, /* Kcedilla Ķ LATIN CAPITAL LETTER K WITH CEDILLA */ + { 0x03f3, 0x0137 }, /* kcedilla Ä· LATIN SMALL LETTER K WITH CEDILLA */ + { 0x03a2, 0x0138 }, /* kra ĸ LATIN SMALL LETTER KRA */ + { 0x01c5, 0x0139 }, /* Lacute Ĺ LATIN CAPITAL LETTER L WITH ACUTE */ + { 0x01e5, 0x013a }, /* lacute ĺ LATIN SMALL LETTER L WITH ACUTE */ + { 0x03a6, 0x013b }, /* Lcedilla Ä» LATIN CAPITAL LETTER L WITH CEDILLA */ + { 0x03b6, 0x013c }, /* lcedilla ļ LATIN SMALL LETTER L WITH CEDILLA */ + { 0x01a5, 0x013d }, /* Lcaron Ľ LATIN CAPITAL LETTER L WITH CARON */ + { 0x01b5, 0x013e }, /* lcaron ľ LATIN SMALL LETTER L WITH CARON */ + { 0x01a3, 0x0141 }, /* Lstroke Ł LATIN CAPITAL LETTER L WITH STROKE */ + { 0x01b3, 0x0142 }, /* lstroke ł LATIN SMALL LETTER L WITH STROKE */ + { 0x01d1, 0x0143 }, /* Nacute Ń LATIN CAPITAL LETTER N WITH ACUTE */ + { 0x01f1, 0x0144 }, /* nacute ń LATIN SMALL LETTER N WITH ACUTE */ + { 0x03d1, 0x0145 }, /* Ncedilla Ņ LATIN CAPITAL LETTER N WITH CEDILLA */ + { 0x03f1, 0x0146 }, /* ncedilla ņ LATIN SMALL LETTER N WITH CEDILLA */ + { 0x01d2, 0x0147 }, /* Ncaron Ň LATIN CAPITAL LETTER N WITH CARON */ + { 0x01f2, 0x0148 }, /* ncaron ň LATIN SMALL LETTER N WITH CARON */ + { 0x03bd, 0x014a }, /* ENG Ŋ LATIN CAPITAL LETTER ENG */ + { 0x03bf, 0x014b }, /* eng ŋ LATIN SMALL LETTER ENG */ + { 0x03d2, 0x014c }, /* Omacron Ō LATIN CAPITAL LETTER O WITH MACRON */ + { 0x03f2, 0x014d }, /* omacron ō LATIN SMALL LETTER O WITH MACRON */ + { 0x01d5, 0x0150 }, /* Odoubleacute Ő LATIN CAPITAL LETTER O WITH DOUBLE ACUTE */ + { 0x01f5, 0x0151 }, /* odoubleacute ő LATIN SMALL LETTER O WITH DOUBLE ACUTE */ + { 0x13bc, 0x0152 }, /* OE Œ LATIN CAPITAL LIGATURE OE */ + { 0x13bd, 0x0153 }, /* oe œ LATIN SMALL LIGATURE OE */ + { 0x01c0, 0x0154 }, /* Racute Ŕ LATIN CAPITAL LETTER R WITH ACUTE */ + { 0x01e0, 0x0155 }, /* racute ŕ LATIN SMALL LETTER R WITH ACUTE */ + { 0x03a3, 0x0156 }, /* Rcedilla Ŗ LATIN CAPITAL LETTER R WITH CEDILLA */ + { 0x03b3, 0x0157 }, /* rcedilla ŗ LATIN SMALL LETTER R WITH CEDILLA */ + { 0x01d8, 0x0158 }, /* Rcaron Ř LATIN CAPITAL LETTER R WITH CARON */ + { 0x01f8, 0x0159 }, /* rcaron ř LATIN SMALL LETTER R WITH CARON */ + { 0x01a6, 0x015a }, /* Sacute Ś LATIN CAPITAL LETTER S WITH ACUTE */ + { 0x01b6, 0x015b }, /* sacute ś LATIN SMALL LETTER S WITH ACUTE */ + { 0x02de, 0x015c }, /* Scircumflex Ŝ LATIN CAPITAL LETTER S WITH CIRCUMFLEX */ + { 0x02fe, 0x015d }, /* scircumflex ŝ LATIN SMALL LETTER S WITH CIRCUMFLEX */ + { 0x01aa, 0x015e }, /* Scedilla Ş LATIN CAPITAL LETTER S WITH CEDILLA */ + { 0x01ba, 0x015f }, /* scedilla ş LATIN SMALL LETTER S WITH CEDILLA */ + { 0x01a9, 0x0160 }, /* Scaron Å  LATIN CAPITAL LETTER S WITH CARON */ + { 0x01b9, 0x0161 }, /* scaron Å¡ LATIN SMALL LETTER S WITH CARON */ + { 0x01de, 0x0162 }, /* Tcedilla Å¢ LATIN CAPITAL LETTER T WITH CEDILLA */ + { 0x01fe, 0x0163 }, /* tcedilla Å£ LATIN SMALL LETTER T WITH CEDILLA */ + { 0x01ab, 0x0164 }, /* Tcaron Ť LATIN CAPITAL LETTER T WITH CARON */ + { 0x01bb, 0x0165 }, /* tcaron Å¥ LATIN SMALL LETTER T WITH CARON */ + { 0x03ac, 0x0166 }, /* Tslash Ŧ LATIN CAPITAL LETTER T WITH STROKE */ + { 0x03bc, 0x0167 }, /* tslash ŧ LATIN SMALL LETTER T WITH STROKE */ + { 0x03dd, 0x0168 }, /* Utilde Ũ LATIN CAPITAL LETTER U WITH TILDE */ + { 0x03fd, 0x0169 }, /* utilde Å© LATIN SMALL LETTER U WITH TILDE */ + { 0x03de, 0x016a }, /* Umacron Ū LATIN CAPITAL LETTER U WITH MACRON */ + { 0x03fe, 0x016b }, /* umacron Å« LATIN SMALL LETTER U WITH MACRON */ + { 0x02dd, 0x016c }, /* Ubreve Ŭ LATIN CAPITAL LETTER U WITH BREVE */ + { 0x02fd, 0x016d }, /* ubreve Å­ LATIN SMALL LETTER U WITH BREVE */ + { 0x01d9, 0x016e }, /* Uring Å® LATIN CAPITAL LETTER U WITH RING ABOVE */ + { 0x01f9, 0x016f }, /* uring ů LATIN SMALL LETTER U WITH RING ABOVE */ + { 0x01db, 0x0170 }, /* Udoubleacute Å° LATIN CAPITAL LETTER U WITH DOUBLE ACUTE */ + { 0x01fb, 0x0171 }, /* udoubleacute ű LATIN SMALL LETTER U WITH DOUBLE ACUTE */ + { 0x03d9, 0x0172 }, /* Uogonek Ų LATIN CAPITAL LETTER U WITH OGONEK */ + { 0x03f9, 0x0173 }, /* uogonek ų LATIN SMALL LETTER U WITH OGONEK */ + { 0x13be, 0x0178 }, /* Ydiaeresis Ÿ LATIN CAPITAL LETTER Y WITH DIAERESIS */ + { 0x01ac, 0x0179 }, /* Zacute Ź LATIN CAPITAL LETTER Z WITH ACUTE */ + { 0x01bc, 0x017a }, /* zacute ź LATIN SMALL LETTER Z WITH ACUTE */ + { 0x01af, 0x017b }, /* Zabovedot Å» LATIN CAPITAL LETTER Z WITH DOT ABOVE */ + { 0x01bf, 0x017c }, /* zabovedot ż LATIN SMALL LETTER Z WITH DOT ABOVE */ + { 0x01ae, 0x017d }, /* Zcaron Ž LATIN CAPITAL LETTER Z WITH CARON */ + { 0x01be, 0x017e }, /* zcaron ž LATIN SMALL LETTER Z WITH CARON */ + { 0x08f6, 0x0192 }, /* function ƒ LATIN SMALL LETTER F WITH HOOK */ + { 0x01b7, 0x02c7 }, /* caron ˇ CARON */ + { 0x01a2, 0x02d8 }, /* breve ˘ BREVE */ + { 0x01ff, 0x02d9 }, /* abovedot ˙ DOT ABOVE */ + { 0x01b2, 0x02db }, /* ogonek ˛ OGONEK */ + { 0x01bd, 0x02dd }, /* doubleacute ˝ DOUBLE ACUTE ACCENT */ + { 0x07ae, 0x0385 }, /* Greek_accentdieresis ΅ GREEK DIALYTIKA TONOS */ + { 0x07a1, 0x0386 }, /* Greek_ALPHAaccent Ά GREEK CAPITAL LETTER ALPHA WITH TONOS */ + { 0x07a2, 0x0388 }, /* Greek_EPSILONaccent Έ GREEK CAPITAL LETTER EPSILON WITH TONOS */ + { 0x07a3, 0x0389 }, /* Greek_ETAaccent Ή GREEK CAPITAL LETTER ETA WITH TONOS */ + { 0x07a4, 0x038a }, /* Greek_IOTAaccent Ί GREEK CAPITAL LETTER IOTA WITH TONOS */ + { 0x07a7, 0x038c }, /* Greek_OMICRONaccent Ό GREEK CAPITAL LETTER OMICRON WITH TONOS */ + { 0x07a8, 0x038e }, /* Greek_UPSILONaccent Ύ GREEK CAPITAL LETTER UPSILON WITH TONOS */ + { 0x07ab, 0x038f }, /* Greek_OMEGAaccent Ώ GREEK CAPITAL LETTER OMEGA WITH TONOS */ + { 0x07b6, 0x0390 }, /* Greek_iotaaccentdieresis ΐ GREEK SMALL LETTER IOTA WITH DIALYTIKA AND TONOS */ + { 0x07c1, 0x0391 }, /* Greek_ALPHA Α GREEK CAPITAL LETTER ALPHA */ + { 0x07c2, 0x0392 }, /* Greek_BETA Β GREEK CAPITAL LETTER BETA */ + { 0x07c3, 0x0393 }, /* Greek_GAMMA Γ GREEK CAPITAL LETTER GAMMA */ + { 0x07c4, 0x0394 }, /* Greek_DELTA Δ GREEK CAPITAL LETTER DELTA */ + { 0x07c5, 0x0395 }, /* Greek_EPSILON Ε GREEK CAPITAL LETTER EPSILON */ + { 0x07c6, 0x0396 }, /* Greek_ZETA Ζ GREEK CAPITAL LETTER ZETA */ + { 0x07c7, 0x0397 }, /* Greek_ETA Η GREEK CAPITAL LETTER ETA */ + { 0x07c8, 0x0398 }, /* Greek_THETA Θ GREEK CAPITAL LETTER THETA */ + { 0x07c9, 0x0399 }, /* Greek_IOTA Ι GREEK CAPITAL LETTER IOTA */ + { 0x07ca, 0x039a }, /* Greek_KAPPA Κ GREEK CAPITAL LETTER KAPPA */ + { 0x07cb, 0x039b }, /* Greek_LAMBDA Λ GREEK CAPITAL LETTER LAMDA */ + { 0x07cc, 0x039c }, /* Greek_MU Μ GREEK CAPITAL LETTER MU */ + { 0x07cd, 0x039d }, /* Greek_NU Ν GREEK CAPITAL LETTER NU */ + { 0x07ce, 0x039e }, /* Greek_XI Ξ GREEK CAPITAL LETTER XI */ + { 0x07cf, 0x039f }, /* Greek_OMICRON Ο GREEK CAPITAL LETTER OMICRON */ + { 0x07d0, 0x03a0 }, /* Greek_PI Π GREEK CAPITAL LETTER PI */ + { 0x07d1, 0x03a1 }, /* Greek_RHO Ρ GREEK CAPITAL LETTER RHO */ + { 0x07d2, 0x03a3 }, /* Greek_SIGMA Σ GREEK CAPITAL LETTER SIGMA */ + { 0x07d4, 0x03a4 }, /* Greek_TAU Τ GREEK CAPITAL LETTER TAU */ + { 0x07d5, 0x03a5 }, /* Greek_UPSILON Î¥ GREEK CAPITAL LETTER UPSILON */ + { 0x07d6, 0x03a6 }, /* Greek_PHI Φ GREEK CAPITAL LETTER PHI */ + { 0x07d7, 0x03a7 }, /* Greek_CHI Χ GREEK CAPITAL LETTER CHI */ + { 0x07d8, 0x03a8 }, /* Greek_PSI Ψ GREEK CAPITAL LETTER PSI */ + { 0x07d9, 0x03a9 }, /* Greek_OMEGA Ω GREEK CAPITAL LETTER OMEGA */ + { 0x07a5, 0x03aa }, /* Greek_IOTAdiaeresis Ϊ GREEK CAPITAL LETTER IOTA WITH DIALYTIKA */ + { 0x07a9, 0x03ab }, /* Greek_UPSILONdieresis Ϋ GREEK CAPITAL LETTER UPSILON WITH DIALYTIKA */ + { 0x07b1, 0x03ac }, /* Greek_alphaaccent ά GREEK SMALL LETTER ALPHA WITH TONOS */ + { 0x07b2, 0x03ad }, /* Greek_epsilonaccent έ GREEK SMALL LETTER EPSILON WITH TONOS */ + { 0x07b3, 0x03ae }, /* Greek_etaaccent ή GREEK SMALL LETTER ETA WITH TONOS */ + { 0x07b4, 0x03af }, /* Greek_iotaaccent ί GREEK SMALL LETTER IOTA WITH TONOS */ + { 0x07ba, 0x03b0 }, /* Greek_upsilonaccentdieresis ΰ GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND TONOS */ + { 0x07e1, 0x03b1 }, /* Greek_alpha α GREEK SMALL LETTER ALPHA */ + { 0x07e2, 0x03b2 }, /* Greek_beta β GREEK SMALL LETTER BETA */ + { 0x07e3, 0x03b3 }, /* Greek_gamma γ GREEK SMALL LETTER GAMMA */ + { 0x07e4, 0x03b4 }, /* Greek_delta δ GREEK SMALL LETTER DELTA */ + { 0x07e5, 0x03b5 }, /* Greek_epsilon ε GREEK SMALL LETTER EPSILON */ + { 0x07e6, 0x03b6 }, /* Greek_zeta ζ GREEK SMALL LETTER ZETA */ + { 0x07e7, 0x03b7 }, /* Greek_eta η GREEK SMALL LETTER ETA */ + { 0x07e8, 0x03b8 }, /* Greek_theta θ GREEK SMALL LETTER THETA */ + { 0x07e9, 0x03b9 }, /* Greek_iota ι GREEK SMALL LETTER IOTA */ + { 0x07ea, 0x03ba }, /* Greek_kappa κ GREEK SMALL LETTER KAPPA */ + { 0x07eb, 0x03bb }, /* Greek_lambda λ GREEK SMALL LETTER LAMDA */ + { 0x07ec, 0x03bc }, /* Greek_mu μ GREEK SMALL LETTER MU */ + { 0x07ed, 0x03bd }, /* Greek_nu ν GREEK SMALL LETTER NU */ + { 0x07ee, 0x03be }, /* Greek_xi ξ GREEK SMALL LETTER XI */ + { 0x07ef, 0x03bf }, /* Greek_omicron ο GREEK SMALL LETTER OMICRON */ + { 0x07f0, 0x03c0 }, /* Greek_pi π GREEK SMALL LETTER PI */ + { 0x07f1, 0x03c1 }, /* Greek_rho ρ GREEK SMALL LETTER RHO */ + { 0x07f3, 0x03c2 }, /* Greek_finalsmallsigma ς GREEK SMALL LETTER FINAL SIGMA */ + { 0x07f2, 0x03c3 }, /* Greek_sigma σ GREEK SMALL LETTER SIGMA */ + { 0x07f4, 0x03c4 }, /* Greek_tau τ GREEK SMALL LETTER TAU */ + { 0x07f5, 0x03c5 }, /* Greek_upsilon υ GREEK SMALL LETTER UPSILON */ + { 0x07f6, 0x03c6 }, /* Greek_phi φ GREEK SMALL LETTER PHI */ + { 0x07f7, 0x03c7 }, /* Greek_chi χ GREEK SMALL LETTER CHI */ + { 0x07f8, 0x03c8 }, /* Greek_psi ψ GREEK SMALL LETTER PSI */ + { 0x07f9, 0x03c9 }, /* Greek_omega ω GREEK SMALL LETTER OMEGA */ + { 0x07b5, 0x03ca }, /* Greek_iotadieresis ϊ GREEK SMALL LETTER IOTA WITH DIALYTIKA */ + { 0x07b9, 0x03cb }, /* Greek_upsilondieresis ϋ GREEK SMALL LETTER UPSILON WITH DIALYTIKA */ + { 0x07b7, 0x03cc }, /* Greek_omicronaccent ό GREEK SMALL LETTER OMICRON WITH TONOS */ + { 0x07b8, 0x03cd }, /* Greek_upsilonaccent ύ GREEK SMALL LETTER UPSILON WITH TONOS */ + { 0x07bb, 0x03ce }, /* Greek_omegaaccent ώ GREEK SMALL LETTER OMEGA WITH TONOS */ + { 0x06b3, 0x0401 }, /* Cyrillic_IO Ё CYRILLIC CAPITAL LETTER IO */ + { 0x06b1, 0x0402 }, /* Serbian_DJE Ђ CYRILLIC CAPITAL LETTER DJE */ + { 0x06b2, 0x0403 }, /* Macedonia_GJE Ѓ CYRILLIC CAPITAL LETTER GJE */ + { 0x06b4, 0x0404 }, /* Ukrainian_IE Є CYRILLIC CAPITAL LETTER UKRAINIAN IE */ + { 0x06b5, 0x0405 }, /* Macedonia_DSE Ѕ CYRILLIC CAPITAL LETTER DZE */ + { 0x06b6, 0x0406 }, /* Ukrainian_I І CYRILLIC CAPITAL LETTER BYELORUSSIAN-UKRAINIAN I */ + { 0x06b7, 0x0407 }, /* Ukrainian_YI Ї CYRILLIC CAPITAL LETTER YI */ + { 0x06b8, 0x0408 }, /* Cyrillic_JE Ј CYRILLIC CAPITAL LETTER JE */ + { 0x06b9, 0x0409 }, /* Cyrillic_LJE Љ CYRILLIC CAPITAL LETTER LJE */ + { 0x06ba, 0x040a }, /* Cyrillic_NJE Њ CYRILLIC CAPITAL LETTER NJE */ + { 0x06bb, 0x040b }, /* Serbian_TSHE Ћ CYRILLIC CAPITAL LETTER TSHE */ + { 0x06bc, 0x040c }, /* Macedonia_KJE Ќ CYRILLIC CAPITAL LETTER KJE */ + { 0x06be, 0x040e }, /* Byelorussian_SHORTU Ў CYRILLIC CAPITAL LETTER SHORT U */ + { 0x06bf, 0x040f }, /* Cyrillic_DZHE Џ CYRILLIC CAPITAL LETTER DZHE */ + { 0x06e1, 0x0410 }, /* Cyrillic_A А CYRILLIC CAPITAL LETTER A */ + { 0x06e2, 0x0411 }, /* Cyrillic_BE Б CYRILLIC CAPITAL LETTER BE */ + { 0x06f7, 0x0412 }, /* Cyrillic_VE В CYRILLIC CAPITAL LETTER VE */ + { 0x06e7, 0x0413 }, /* Cyrillic_GHE Г CYRILLIC CAPITAL LETTER GHE */ + { 0x06e4, 0x0414 }, /* Cyrillic_DE Д CYRILLIC CAPITAL LETTER DE */ + { 0x06e5, 0x0415 }, /* Cyrillic_IE Е CYRILLIC CAPITAL LETTER IE */ + { 0x06f6, 0x0416 }, /* Cyrillic_ZHE Ж CYRILLIC CAPITAL LETTER ZHE */ + { 0x06fa, 0x0417 }, /* Cyrillic_ZE З CYRILLIC CAPITAL LETTER ZE */ + { 0x06e9, 0x0418 }, /* Cyrillic_I И CYRILLIC CAPITAL LETTER I */ + { 0x06ea, 0x0419 }, /* Cyrillic_SHORTI Й CYRILLIC CAPITAL LETTER SHORT I */ + { 0x06eb, 0x041a }, /* Cyrillic_KA К CYRILLIC CAPITAL LETTER KA */ + { 0x06ec, 0x041b }, /* Cyrillic_EL Л CYRILLIC CAPITAL LETTER EL */ + { 0x06ed, 0x041c }, /* Cyrillic_EM М CYRILLIC CAPITAL LETTER EM */ + { 0x06ee, 0x041d }, /* Cyrillic_EN Н CYRILLIC CAPITAL LETTER EN */ + { 0x06ef, 0x041e }, /* Cyrillic_O О CYRILLIC CAPITAL LETTER O */ + { 0x06f0, 0x041f }, /* Cyrillic_PE П CYRILLIC CAPITAL LETTER PE */ + { 0x06f2, 0x0420 }, /* Cyrillic_ER Р CYRILLIC CAPITAL LETTER ER */ + { 0x06f3, 0x0421 }, /* Cyrillic_ES С CYRILLIC CAPITAL LETTER ES */ + { 0x06f4, 0x0422 }, /* Cyrillic_TE Т CYRILLIC CAPITAL LETTER TE */ + { 0x06f5, 0x0423 }, /* Cyrillic_U У CYRILLIC CAPITAL LETTER U */ + { 0x06e6, 0x0424 }, /* Cyrillic_EF Ф CYRILLIC CAPITAL LETTER EF */ + { 0x06e8, 0x0425 }, /* Cyrillic_HA Ð¥ CYRILLIC CAPITAL LETTER HA */ + { 0x06e3, 0x0426 }, /* Cyrillic_TSE Ц CYRILLIC CAPITAL LETTER TSE */ + { 0x06fe, 0x0427 }, /* Cyrillic_CHE Ч CYRILLIC CAPITAL LETTER CHE */ + { 0x06fb, 0x0428 }, /* Cyrillic_SHA Ш CYRILLIC CAPITAL LETTER SHA */ + { 0x06fd, 0x0429 }, /* Cyrillic_SHCHA Щ CYRILLIC CAPITAL LETTER SHCHA */ + { 0x06ff, 0x042a }, /* Cyrillic_HARDSIGN Ъ CYRILLIC CAPITAL LETTER HARD SIGN */ + { 0x06f9, 0x042b }, /* Cyrillic_YERU Ы CYRILLIC CAPITAL LETTER YERU */ + { 0x06f8, 0x042c }, /* Cyrillic_SOFTSIGN Ь CYRILLIC CAPITAL LETTER SOFT SIGN */ + { 0x06fc, 0x042d }, /* Cyrillic_E Э CYRILLIC CAPITAL LETTER E */ + { 0x06e0, 0x042e }, /* Cyrillic_YU Ю CYRILLIC CAPITAL LETTER YU */ + { 0x06f1, 0x042f }, /* Cyrillic_YA Я CYRILLIC CAPITAL LETTER YA */ + { 0x06c1, 0x0430 }, /* Cyrillic_a а CYRILLIC SMALL LETTER A */ + { 0x06c2, 0x0431 }, /* Cyrillic_be б CYRILLIC SMALL LETTER BE */ + { 0x06d7, 0x0432 }, /* Cyrillic_ve в CYRILLIC SMALL LETTER VE */ + { 0x06c7, 0x0433 }, /* Cyrillic_ghe г CYRILLIC SMALL LETTER GHE */ + { 0x06c4, 0x0434 }, /* Cyrillic_de д CYRILLIC SMALL LETTER DE */ + { 0x06c5, 0x0435 }, /* Cyrillic_ie е CYRILLIC SMALL LETTER IE */ + { 0x06d6, 0x0436 }, /* Cyrillic_zhe ж CYRILLIC SMALL LETTER ZHE */ + { 0x06da, 0x0437 }, /* Cyrillic_ze з CYRILLIC SMALL LETTER ZE */ + { 0x06c9, 0x0438 }, /* Cyrillic_i и CYRILLIC SMALL LETTER I */ + { 0x06ca, 0x0439 }, /* Cyrillic_shorti й CYRILLIC SMALL LETTER SHORT I */ + { 0x06cb, 0x043a }, /* Cyrillic_ka к CYRILLIC SMALL LETTER KA */ + { 0x06cc, 0x043b }, /* Cyrillic_el л CYRILLIC SMALL LETTER EL */ + { 0x06cd, 0x043c }, /* Cyrillic_em м CYRILLIC SMALL LETTER EM */ + { 0x06ce, 0x043d }, /* Cyrillic_en н CYRILLIC SMALL LETTER EN */ + { 0x06cf, 0x043e }, /* Cyrillic_o о CYRILLIC SMALL LETTER O */ + { 0x06d0, 0x043f }, /* Cyrillic_pe п CYRILLIC SMALL LETTER PE */ + { 0x06d2, 0x0440 }, /* Cyrillic_er р CYRILLIC SMALL LETTER ER */ + { 0x06d3, 0x0441 }, /* Cyrillic_es с CYRILLIC SMALL LETTER ES */ + { 0x06d4, 0x0442 }, /* Cyrillic_te т CYRILLIC SMALL LETTER TE */ + { 0x06d5, 0x0443 }, /* Cyrillic_u у CYRILLIC SMALL LETTER U */ + { 0x06c6, 0x0444 }, /* Cyrillic_ef ф CYRILLIC SMALL LETTER EF */ + { 0x06c8, 0x0445 }, /* Cyrillic_ha х CYRILLIC SMALL LETTER HA */ + { 0x06c3, 0x0446 }, /* Cyrillic_tse ц CYRILLIC SMALL LETTER TSE */ + { 0x06de, 0x0447 }, /* Cyrillic_che ч CYRILLIC SMALL LETTER CHE */ + { 0x06db, 0x0448 }, /* Cyrillic_sha ш CYRILLIC SMALL LETTER SHA */ + { 0x06dd, 0x0449 }, /* Cyrillic_shcha щ CYRILLIC SMALL LETTER SHCHA */ + { 0x06df, 0x044a }, /* Cyrillic_hardsign ъ CYRILLIC SMALL LETTER HARD SIGN */ + { 0x06d9, 0x044b }, /* Cyrillic_yeru ы CYRILLIC SMALL LETTER YERU */ + { 0x06d8, 0x044c }, /* Cyrillic_softsign ь CYRILLIC SMALL LETTER SOFT SIGN */ + { 0x06dc, 0x044d }, /* Cyrillic_e э CYRILLIC SMALL LETTER E */ + { 0x06c0, 0x044e }, /* Cyrillic_yu ю CYRILLIC SMALL LETTER YU */ + { 0x06d1, 0x044f }, /* Cyrillic_ya я CYRILLIC SMALL LETTER YA */ + { 0x06a3, 0x0451 }, /* Cyrillic_io ё CYRILLIC SMALL LETTER IO */ + { 0x06a1, 0x0452 }, /* Serbian_dje ђ CYRILLIC SMALL LETTER DJE */ + { 0x06a2, 0x0453 }, /* Macedonia_gje ѓ CYRILLIC SMALL LETTER GJE */ + { 0x06a4, 0x0454 }, /* Ukrainian_ie є CYRILLIC SMALL LETTER UKRAINIAN IE */ + { 0x06a5, 0x0455 }, /* Macedonia_dse ѕ CYRILLIC SMALL LETTER DZE */ + { 0x06a6, 0x0456 }, /* Ukrainian_i і CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I */ + { 0x06a7, 0x0457 }, /* Ukrainian_yi ї CYRILLIC SMALL LETTER YI */ + { 0x06a8, 0x0458 }, /* Cyrillic_je ј CYRILLIC SMALL LETTER JE */ + { 0x06a9, 0x0459 }, /* Cyrillic_lje љ CYRILLIC SMALL LETTER LJE */ + { 0x06aa, 0x045a }, /* Cyrillic_nje њ CYRILLIC SMALL LETTER NJE */ + { 0x06ab, 0x045b }, /* Serbian_tshe ћ CYRILLIC SMALL LETTER TSHE */ + { 0x06ac, 0x045c }, /* Macedonia_kje ќ CYRILLIC SMALL LETTER KJE */ + { 0x06ae, 0x045e }, /* Byelorussian_shortu ў CYRILLIC SMALL LETTER SHORT U */ + { 0x06af, 0x045f }, /* Cyrillic_dzhe џ CYRILLIC SMALL LETTER DZHE */ + { 0x0ce0, 0x05d0 }, /* hebrew_aleph א HEBREW LETTER ALEF */ + { 0x0ce1, 0x05d1 }, /* hebrew_bet ב HEBREW LETTER BET */ + { 0x0ce2, 0x05d2 }, /* hebrew_gimel ג HEBREW LETTER GIMEL */ + { 0x0ce3, 0x05d3 }, /* hebrew_dalet ד HEBREW LETTER DALET */ + { 0x0ce4, 0x05d4 }, /* hebrew_he ה HEBREW LETTER HE */ + { 0x0ce5, 0x05d5 }, /* hebrew_waw ו HEBREW LETTER VAV */ + { 0x0ce6, 0x05d6 }, /* hebrew_zain ז HEBREW LETTER ZAYIN */ + { 0x0ce7, 0x05d7 }, /* hebrew_chet ח HEBREW LETTER HET */ + { 0x0ce8, 0x05d8 }, /* hebrew_tet ט HEBREW LETTER TET */ + { 0x0ce9, 0x05d9 }, /* hebrew_yod י HEBREW LETTER YOD */ + { 0x0cea, 0x05da }, /* hebrew_finalkaph ך HEBREW LETTER FINAL KAF */ + { 0x0ceb, 0x05db }, /* hebrew_kaph כ HEBREW LETTER KAF */ + { 0x0cec, 0x05dc }, /* hebrew_lamed ל HEBREW LETTER LAMED */ + { 0x0ced, 0x05dd }, /* hebrew_finalmem ם HEBREW LETTER FINAL MEM */ + { 0x0cee, 0x05de }, /* hebrew_mem מ HEBREW LETTER MEM */ + { 0x0cef, 0x05df }, /* hebrew_finalnun ן HEBREW LETTER FINAL NUN */ + { 0x0cf0, 0x05e0 }, /* hebrew_nun ×  HEBREW LETTER NUN */ + { 0x0cf1, 0x05e1 }, /* hebrew_samech ס HEBREW LETTER SAMEKH */ + { 0x0cf2, 0x05e2 }, /* hebrew_ayin ×¢ HEBREW LETTER AYIN */ + { 0x0cf3, 0x05e3 }, /* hebrew_finalpe ×£ HEBREW LETTER FINAL PE */ + { 0x0cf4, 0x05e4 }, /* hebrew_pe פ HEBREW LETTER PE */ + { 0x0cf5, 0x05e5 }, /* hebrew_finalzade ×¥ HEBREW LETTER FINAL TSADI */ + { 0x0cf6, 0x05e6 }, /* hebrew_zade צ HEBREW LETTER TSADI */ + { 0x0cf7, 0x05e7 }, /* hebrew_qoph ק HEBREW LETTER QOF */ + { 0x0cf8, 0x05e8 }, /* hebrew_resh ר HEBREW LETTER RESH */ + { 0x0cf9, 0x05e9 }, /* hebrew_shin ש HEBREW LETTER SHIN */ + { 0x0cfa, 0x05ea }, /* hebrew_taw ת HEBREW LETTER TAV */ + { 0x05ac, 0x060c }, /* Arabic_comma ، ARABIC COMMA */ + { 0x05bb, 0x061b }, /* Arabic_semicolon ؛ ARABIC SEMICOLON */ + { 0x05bf, 0x061f }, /* Arabic_question_mark ؟ ARABIC QUESTION MARK */ + { 0x05c1, 0x0621 }, /* Arabic_hamza Ø¡ ARABIC LETTER HAMZA */ + { 0x05c2, 0x0622 }, /* Arabic_maddaonalef Ø¢ ARABIC LETTER ALEF WITH MADDA ABOVE */ + { 0x05c3, 0x0623 }, /* Arabic_hamzaonalef Ø£ ARABIC LETTER ALEF WITH HAMZA ABOVE */ + { 0x05c4, 0x0624 }, /* Arabic_hamzaonwaw ؤ ARABIC LETTER WAW WITH HAMZA ABOVE */ + { 0x05c5, 0x0625 }, /* Arabic_hamzaunderalef Ø¥ ARABIC LETTER ALEF WITH HAMZA BELOW */ + { 0x05c6, 0x0626 }, /* Arabic_hamzaonyeh ئ ARABIC LETTER YEH WITH HAMZA ABOVE */ + { 0x05c7, 0x0627 }, /* Arabic_alef ا ARABIC LETTER ALEF */ + { 0x05c8, 0x0628 }, /* Arabic_beh ب ARABIC LETTER BEH */ + { 0x05c9, 0x0629 }, /* Arabic_tehmarbuta Ø© ARABIC LETTER TEH MARBUTA */ + { 0x05ca, 0x062a }, /* Arabic_teh ت ARABIC LETTER TEH */ + { 0x05cb, 0x062b }, /* Arabic_theh Ø« ARABIC LETTER THEH */ + { 0x05cc, 0x062c }, /* Arabic_jeem ج ARABIC LETTER JEEM */ + { 0x05cd, 0x062d }, /* Arabic_hah Ø­ ARABIC LETTER HAH */ + { 0x05ce, 0x062e }, /* Arabic_khah Ø® ARABIC LETTER KHAH */ + { 0x05cf, 0x062f }, /* Arabic_dal د ARABIC LETTER DAL */ + { 0x05d0, 0x0630 }, /* Arabic_thal Ø° ARABIC LETTER THAL */ + { 0x05d1, 0x0631 }, /* Arabic_ra ر ARABIC LETTER REH */ + { 0x05d2, 0x0632 }, /* Arabic_zain ز ARABIC LETTER ZAIN */ + { 0x05d3, 0x0633 }, /* Arabic_seen س ARABIC LETTER SEEN */ + { 0x05d4, 0x0634 }, /* Arabic_sheen Ø´ ARABIC LETTER SHEEN */ + { 0x05d5, 0x0635 }, /* Arabic_sad ص ARABIC LETTER SAD */ + { 0x05d6, 0x0636 }, /* Arabic_dad ض ARABIC LETTER DAD */ + { 0x05d7, 0x0637 }, /* Arabic_tah Ø· ARABIC LETTER TAH */ + { 0x05d8, 0x0638 }, /* Arabic_zah ظ ARABIC LETTER ZAH */ + { 0x05d9, 0x0639 }, /* Arabic_ain ع ARABIC LETTER AIN */ + { 0x05da, 0x063a }, /* Arabic_ghain غ ARABIC LETTER GHAIN */ + { 0x05e0, 0x0640 }, /* Arabic_tatweel ـ ARABIC TATWEEL */ + { 0x05e1, 0x0641 }, /* Arabic_feh ف ARABIC LETTER FEH */ + { 0x05e2, 0x0642 }, /* Arabic_qaf ق ARABIC LETTER QAF */ + { 0x05e3, 0x0643 }, /* Arabic_kaf ك ARABIC LETTER KAF */ + { 0x05e4, 0x0644 }, /* Arabic_lam ل ARABIC LETTER LAM */ + { 0x05e5, 0x0645 }, /* Arabic_meem م ARABIC LETTER MEEM */ + { 0x05e6, 0x0646 }, /* Arabic_noon ن ARABIC LETTER NOON */ + { 0x05e7, 0x0647 }, /* Arabic_ha ه ARABIC LETTER HEH */ + { 0x05e8, 0x0648 }, /* Arabic_waw و ARABIC LETTER WAW */ + { 0x05e9, 0x0649 }, /* Arabic_alefmaksura ى ARABIC LETTER ALEF MAKSURA */ + { 0x05ea, 0x064a }, /* Arabic_yeh ي ARABIC LETTER YEH */ + { 0x05eb, 0x064b }, /* Arabic_fathatan ً ARABIC FATHATAN */ + { 0x05ec, 0x064c }, /* Arabic_dammatan ٌ ARABIC DAMMATAN */ + { 0x05ed, 0x064d }, /* Arabic_kasratan ٍ ARABIC KASRATAN */ + { 0x05ee, 0x064e }, /* Arabic_fatha َ ARABIC FATHA */ + { 0x05ef, 0x064f }, /* Arabic_damma ُ ARABIC DAMMA */ + { 0x05f0, 0x0650 }, /* Arabic_kasra ِ ARABIC KASRA */ + { 0x05f1, 0x0651 }, /* Arabic_shadda ّ ARABIC SHADDA */ + { 0x05f2, 0x0652 }, /* Arabic_sukun ْ ARABIC SUKUN */ + { 0x0da1, 0x0e01 }, /* Thai_kokai ก THAI CHARACTER KO KAI */ + { 0x0da2, 0x0e02 }, /* Thai_khokhai ข THAI CHARACTER KHO KHAI */ + { 0x0da3, 0x0e03 }, /* Thai_khokhuat ฃ THAI CHARACTER KHO KHUAT */ + { 0x0da4, 0x0e04 }, /* Thai_khokhwai ค THAI CHARACTER KHO KHWAI */ + { 0x0da5, 0x0e05 }, /* Thai_khokhon ฅ THAI CHARACTER KHO KHON */ + { 0x0da6, 0x0e06 }, /* Thai_khorakhang ฆ THAI CHARACTER KHO RAKHANG */ + { 0x0da7, 0x0e07 }, /* Thai_ngongu ง THAI CHARACTER NGO NGU */ + { 0x0da8, 0x0e08 }, /* Thai_chochan จ THAI CHARACTER CHO CHAN */ + { 0x0da9, 0x0e09 }, /* Thai_choching ฉ THAI CHARACTER CHO CHING */ + { 0x0daa, 0x0e0a }, /* Thai_chochang ช THAI CHARACTER CHO CHANG */ + { 0x0dab, 0x0e0b }, /* Thai_soso ซ THAI CHARACTER SO SO */ + { 0x0dac, 0x0e0c }, /* Thai_chochoe ฌ THAI CHARACTER CHO CHOE */ + { 0x0dad, 0x0e0d }, /* Thai_yoying ญ THAI CHARACTER YO YING */ + { 0x0dae, 0x0e0e }, /* Thai_dochada ฎ THAI CHARACTER DO CHADA */ + { 0x0daf, 0x0e0f }, /* Thai_topatak ฏ THAI CHARACTER TO PATAK */ + { 0x0db0, 0x0e10 }, /* Thai_thothan ฐ THAI CHARACTER THO THAN */ + { 0x0db1, 0x0e11 }, /* Thai_thonangmontho ฑ THAI CHARACTER THO NANGMONTHO */ + { 0x0db2, 0x0e12 }, /* Thai_thophuthao ฒ THAI CHARACTER THO PHUTHAO */ + { 0x0db3, 0x0e13 }, /* Thai_nonen ณ THAI CHARACTER NO NEN */ + { 0x0db4, 0x0e14 }, /* Thai_dodek ด THAI CHARACTER DO DEK */ + { 0x0db5, 0x0e15 }, /* Thai_totao ต THAI CHARACTER TO TAO */ + { 0x0db6, 0x0e16 }, /* Thai_thothung ถ THAI CHARACTER THO THUNG */ + { 0x0db7, 0x0e17 }, /* Thai_thothahan ท THAI CHARACTER THO THAHAN */ + { 0x0db8, 0x0e18 }, /* Thai_thothong ธ THAI CHARACTER THO THONG */ + { 0x0db9, 0x0e19 }, /* Thai_nonu น THAI CHARACTER NO NU */ + { 0x0dba, 0x0e1a }, /* Thai_bobaimai บ THAI CHARACTER BO BAIMAI */ + { 0x0dbb, 0x0e1b }, /* Thai_popla ป THAI CHARACTER PO PLA */ + { 0x0dbc, 0x0e1c }, /* Thai_phophung ผ THAI CHARACTER PHO PHUNG */ + { 0x0dbd, 0x0e1d }, /* Thai_fofa ฝ THAI CHARACTER FO FA */ + { 0x0dbe, 0x0e1e }, /* Thai_phophan พ THAI CHARACTER PHO PHAN */ + { 0x0dbf, 0x0e1f }, /* Thai_fofan ฟ THAI CHARACTER FO FAN */ + { 0x0dc0, 0x0e20 }, /* Thai_phosamphao ภ THAI CHARACTER PHO SAMPHAO */ + { 0x0dc1, 0x0e21 }, /* Thai_moma ม THAI CHARACTER MO MA */ + { 0x0dc2, 0x0e22 }, /* Thai_yoyak ย THAI CHARACTER YO YAK */ + { 0x0dc3, 0x0e23 }, /* Thai_rorua ร THAI CHARACTER RO RUA */ + { 0x0dc4, 0x0e24 }, /* Thai_ru ฤ THAI CHARACTER RU */ + { 0x0dc5, 0x0e25 }, /* Thai_loling ล THAI CHARACTER LO LING */ + { 0x0dc6, 0x0e26 }, /* Thai_lu ฦ THAI CHARACTER LU */ + { 0x0dc7, 0x0e27 }, /* Thai_wowaen ว THAI CHARACTER WO WAEN */ + { 0x0dc8, 0x0e28 }, /* Thai_sosala ศ THAI CHARACTER SO SALA */ + { 0x0dc9, 0x0e29 }, /* Thai_sorusi ษ THAI CHARACTER SO RUSI */ + { 0x0dca, 0x0e2a }, /* Thai_sosua ส THAI CHARACTER SO SUA */ + { 0x0dcb, 0x0e2b }, /* Thai_hohip ห THAI CHARACTER HO HIP */ + { 0x0dcc, 0x0e2c }, /* Thai_lochula ฬ THAI CHARACTER LO CHULA */ + { 0x0dcd, 0x0e2d }, /* Thai_oang อ THAI CHARACTER O ANG */ + { 0x0dce, 0x0e2e }, /* Thai_honokhuk ฮ THAI CHARACTER HO NOKHUK */ + { 0x0dcf, 0x0e2f }, /* Thai_paiyannoi ฯ THAI CHARACTER PAIYANNOI */ + { 0x0dd0, 0x0e30 }, /* Thai_saraa ะ THAI CHARACTER SARA A */ + { 0x0dd1, 0x0e31 }, /* Thai_maihanakat ั THAI CHARACTER MAI HAN-AKAT */ + { 0x0dd2, 0x0e32 }, /* Thai_saraaa า THAI CHARACTER SARA AA */ + { 0x0dd3, 0x0e33 }, /* Thai_saraam ำ THAI CHARACTER SARA AM */ + { 0x0dd4, 0x0e34 }, /* Thai_sarai ิ THAI CHARACTER SARA I */ + { 0x0dd5, 0x0e35 }, /* Thai_saraii ี THAI CHARACTER SARA II */ + { 0x0dd6, 0x0e36 }, /* Thai_saraue ึ THAI CHARACTER SARA UE */ + { 0x0dd7, 0x0e37 }, /* Thai_sarauee ื THAI CHARACTER SARA UEE */ + { 0x0dd8, 0x0e38 }, /* Thai_sarau ุ THAI CHARACTER SARA U */ + { 0x0dd9, 0x0e39 }, /* Thai_sarauu ู THAI CHARACTER SARA UU */ + { 0x0dda, 0x0e3a }, /* Thai_phinthu ฺ THAI CHARACTER PHINTHU */ + { 0x0ddf, 0x0e3f }, /* Thai_baht ฿ THAI CURRENCY SYMBOL BAHT */ + { 0x0de0, 0x0e40 }, /* Thai_sarae เ THAI CHARACTER SARA E */ + { 0x0de1, 0x0e41 }, /* Thai_saraae แ THAI CHARACTER SARA AE */ + { 0x0de2, 0x0e42 }, /* Thai_sarao โ THAI CHARACTER SARA O */ + { 0x0de3, 0x0e43 }, /* Thai_saraaimaimuan ใ THAI CHARACTER SARA AI MAIMUAN */ + { 0x0de4, 0x0e44 }, /* Thai_saraaimaimalai ไ THAI CHARACTER SARA AI MAIMALAI */ + { 0x0de5, 0x0e45 }, /* Thai_lakkhangyao ๅ THAI CHARACTER LAKKHANGYAO */ + { 0x0de6, 0x0e46 }, /* Thai_maiyamok ๆ THAI CHARACTER MAIYAMOK */ + { 0x0de7, 0x0e47 }, /* Thai_maitaikhu ็ THAI CHARACTER MAITAIKHU */ + { 0x0de8, 0x0e48 }, /* Thai_maiek ่ THAI CHARACTER MAI EK */ + { 0x0de9, 0x0e49 }, /* Thai_maitho ้ THAI CHARACTER MAI THO */ + { 0x0dea, 0x0e4a }, /* Thai_maitri ๊ THAI CHARACTER MAI TRI */ + { 0x0deb, 0x0e4b }, /* Thai_maichattawa ๋ THAI CHARACTER MAI CHATTAWA */ + { 0x0dec, 0x0e4c }, /* Thai_thanthakhat ์ THAI CHARACTER THANTHAKHAT */ + { 0x0ded, 0x0e4d }, /* Thai_nikhahit ํ THAI CHARACTER NIKHAHIT */ + { 0x0df0, 0x0e50 }, /* Thai_leksun ๐ THAI DIGIT ZERO */ + { 0x0df1, 0x0e51 }, /* Thai_leknung ๑ THAI DIGIT ONE */ + { 0x0df2, 0x0e52 }, /* Thai_leksong ๒ THAI DIGIT TWO */ + { 0x0df3, 0x0e53 }, /* Thai_leksam ๓ THAI DIGIT THREE */ + { 0x0df4, 0x0e54 }, /* Thai_leksi ๔ THAI DIGIT FOUR */ + { 0x0df5, 0x0e55 }, /* Thai_lekha ๕ THAI DIGIT FIVE */ + { 0x0df6, 0x0e56 }, /* Thai_lekhok ๖ THAI DIGIT SIX */ + { 0x0df7, 0x0e57 }, /* Thai_lekchet ๗ THAI DIGIT SEVEN */ + { 0x0df8, 0x0e58 }, /* Thai_lekpaet ๘ THAI DIGIT EIGHT */ + { 0x0df9, 0x0e59 }, /* Thai_lekkao ๙ THAI DIGIT NINE */ + { 0x0ed4, 0x11a8 }, /* Hangul_J_Kiyeog ᆨ HANGUL JONGSEONG KIYEOK */ + { 0x0ed5, 0x11a9 }, /* Hangul_J_SsangKiyeog ᆩ HANGUL JONGSEONG SSANGKIYEOK */ + { 0x0ed6, 0x11aa }, /* Hangul_J_KiyeogSios ᆪ HANGUL JONGSEONG KIYEOK-SIOS */ + { 0x0ed7, 0x11ab }, /* Hangul_J_Nieun ᆫ HANGUL JONGSEONG NIEUN */ + { 0x0ed8, 0x11ac }, /* Hangul_J_NieunJieuj ᆬ HANGUL JONGSEONG NIEUN-CIEUC */ + { 0x0ed9, 0x11ad }, /* Hangul_J_NieunHieuh ᆭ HANGUL JONGSEONG NIEUN-HIEUH */ + { 0x0eda, 0x11ae }, /* Hangul_J_Dikeud ᆮ HANGUL JONGSEONG TIKEUT */ + { 0x0edb, 0x11af }, /* Hangul_J_Rieul ᆯ HANGUL JONGSEONG RIEUL */ + { 0x0edc, 0x11b0 }, /* Hangul_J_RieulKiyeog ᆰ HANGUL JONGSEONG RIEUL-KIYEOK */ + { 0x0edd, 0x11b1 }, /* Hangul_J_RieulMieum ᆱ HANGUL JONGSEONG RIEUL-MIEUM */ + { 0x0ede, 0x11b2 }, /* Hangul_J_RieulPieub ᆲ HANGUL JONGSEONG RIEUL-PIEUP */ + { 0x0edf, 0x11b3 }, /* Hangul_J_RieulSios ᆳ HANGUL JONGSEONG RIEUL-SIOS */ + { 0x0ee0, 0x11b4 }, /* Hangul_J_RieulTieut ᆴ HANGUL JONGSEONG RIEUL-THIEUTH */ + { 0x0ee1, 0x11b5 }, /* Hangul_J_RieulPhieuf ᆵ HANGUL JONGSEONG RIEUL-PHIEUPH */ + { 0x0ee2, 0x11b6 }, /* Hangul_J_RieulHieuh ᆶ HANGUL JONGSEONG RIEUL-HIEUH */ + { 0x0ee3, 0x11b7 }, /* Hangul_J_Mieum ᆷ HANGUL JONGSEONG MIEUM */ + { 0x0ee4, 0x11b8 }, /* Hangul_J_Pieub ᆸ HANGUL JONGSEONG PIEUP */ + { 0x0ee5, 0x11b9 }, /* Hangul_J_PieubSios ᆹ HANGUL JONGSEONG PIEUP-SIOS */ + { 0x0ee6, 0x11ba }, /* Hangul_J_Sios ᆺ HANGUL JONGSEONG SIOS */ + { 0x0ee7, 0x11bb }, /* Hangul_J_SsangSios ᆻ HANGUL JONGSEONG SSANGSIOS */ + { 0x0ee8, 0x11bc }, /* Hangul_J_Ieung ᆼ HANGUL JONGSEONG IEUNG */ + { 0x0ee9, 0x11bd }, /* Hangul_J_Jieuj ᆽ HANGUL JONGSEONG CIEUC */ + { 0x0eea, 0x11be }, /* Hangul_J_Cieuc ᆾ HANGUL JONGSEONG CHIEUCH */ + { 0x0eeb, 0x11bf }, /* Hangul_J_Khieuq ᆿ HANGUL JONGSEONG KHIEUKH */ + { 0x0eec, 0x11c0 }, /* Hangul_J_Tieut ᇀ HANGUL JONGSEONG THIEUTH */ + { 0x0eed, 0x11c1 }, /* Hangul_J_Phieuf ᇁ HANGUL JONGSEONG PHIEUPH */ + { 0x0eee, 0x11c2 }, /* Hangul_J_Hieuh ᇂ HANGUL JONGSEONG HIEUH */ + { 0x0ef8, 0x11eb }, /* Hangul_J_PanSios ᇫ HANGUL JONGSEONG PANSIOS */ + { 0x0efa, 0x11f9 }, /* Hangul_J_YeorinHieuh ᇹ HANGUL JONGSEONG YEORINHIEUH */ + { 0x0aa2, 0x2002 }, /* enspace   EN SPACE */ + { 0x0aa1, 0x2003 }, /* emspace   EM SPACE */ + { 0x0aa3, 0x2004 }, /* em3space   THREE-PER-EM SPACE */ + { 0x0aa4, 0x2005 }, /* em4space   FOUR-PER-EM SPACE */ + { 0x0aa5, 0x2007 }, /* digitspace   FIGURE SPACE */ + { 0x0aa6, 0x2008 }, /* punctspace   PUNCTUATION SPACE */ + { 0x0aa7, 0x2009 }, /* thinspace   THIN SPACE */ + { 0x0aa8, 0x200a }, /* hairspace   HAIR SPACE */ + { 0x0abb, 0x2012 }, /* figdash ‒ FIGURE DASH */ + { 0x0aaa, 0x2013 }, /* endash – EN DASH */ + { 0x0aa9, 0x2014 }, /* emdash — EM DASH */ + { 0x07af, 0x2015 }, /* Greek_horizbar ― HORIZONTAL BAR */ + { 0x0cdf, 0x2017 }, /* hebrew_doublelowline ‗ DOUBLE LOW LINE */ + { 0x0ad0, 0x2018 }, /* leftsinglequotemark ‘ LEFT SINGLE QUOTATION MARK */ + { 0x0ad1, 0x2019 }, /* rightsinglequotemark ’ RIGHT SINGLE QUOTATION MARK */ + { 0x0afd, 0x201a }, /* singlelowquotemark ‚ SINGLE LOW-9 QUOTATION MARK */ + { 0x0ad2, 0x201c }, /* leftdoublequotemark “ LEFT DOUBLE QUOTATION MARK */ + { 0x0ad3, 0x201d }, /* rightdoublequotemark ” RIGHT DOUBLE QUOTATION MARK */ + { 0x0afe, 0x201e }, /* doublelowquotemark „ DOUBLE LOW-9 QUOTATION MARK */ + { 0x0af1, 0x2020 }, /* dagger † DAGGER */ + { 0x0af2, 0x2021 }, /* doubledagger ‡ DOUBLE DAGGER */ + { 0x0ae6, 0x2022 }, /* enfilledcircbullet • BULLET */ + { 0x0aae, 0x2026 }, /* ellipsis … HORIZONTAL ELLIPSIS */ + { 0x0ad6, 0x2032 }, /* minutes ′ PRIME */ + { 0x0ad7, 0x2033 }, /* seconds ″ DOUBLE PRIME */ + { 0x0afc, 0x2038 }, /* caret ‸ CARET */ + { 0x047e, 0x203e }, /* overline ‾ OVERLINE */ + { 0x20a0, 0x20a0 }, /* EcuSign ₠ EURO-CURRENCY SIGN */ + { 0x20a1, 0x20a1 }, /* ColonSign ₡ COLON SIGN */ + { 0x20a2, 0x20a2 }, /* CruzeiroSign ₢ CRUZEIRO SIGN */ + { 0x20a3, 0x20a3 }, /* FFrancSign ₣ FRENCH FRANC SIGN */ + { 0x20a4, 0x20a4 }, /* LiraSign ₤ LIRA SIGN */ + { 0x20a5, 0x20a5 }, /* MillSign ₥ MILL SIGN */ + { 0x20a6, 0x20a6 }, /* NairaSign ₦ NAIRA SIGN */ + { 0x20a7, 0x20a7 }, /* PesetaSign ₧ PESETA SIGN */ + { 0x20a8, 0x20a8 }, /* RupeeSign ₨ RUPEE SIGN */ + { 0x0eff, 0x20a9 }, /* Korean_Won ₩ WON SIGN */ + { 0x20a9, 0x20a9 }, /* WonSign ₩ WON SIGN */ + { 0x20aa, 0x20aa }, /* NewSheqelSign ₪ NEW SHEQEL SIGN */ + { 0x20ab, 0x20ab }, /* DongSign ₫ DONG SIGN */ + { 0x20ac, 0x20ac }, /* EuroSign € EURO SIGN */ + { 0x0ab8, 0x2105 }, /* careof ℅ CARE OF */ + { 0x06b0, 0x2116 }, /* numerosign № NUMERO SIGN */ + { 0x0afb, 0x2117 }, /* phonographcopyright ℗ SOUND RECORDING COPYRIGHT */ + { 0x0ad4, 0x211e }, /* prescription ℞ PRESCRIPTION TAKE */ + { 0x0ac9, 0x2122 }, /* trademark ™ TRADE MARK SIGN */ + { 0x0ab0, 0x2153 }, /* onethird ⅓ VULGAR FRACTION ONE THIRD */ + { 0x0ab1, 0x2154 }, /* twothirds ⅔ VULGAR FRACTION TWO THIRDS */ + { 0x0ab2, 0x2155 }, /* onefifth ⅕ VULGAR FRACTION ONE FIFTH */ + { 0x0ab3, 0x2156 }, /* twofifths ⅖ VULGAR FRACTION TWO FIFTHS */ + { 0x0ab4, 0x2157 }, /* threefifths ⅗ VULGAR FRACTION THREE FIFTHS */ + { 0x0ab5, 0x2158 }, /* fourfifths ⅘ VULGAR FRACTION FOUR FIFTHS */ + { 0x0ab6, 0x2159 }, /* onesixth ⅙ VULGAR FRACTION ONE SIXTH */ + { 0x0ab7, 0x215a }, /* fivesixths ⅚ VULGAR FRACTION FIVE SIXTHS */ + { 0x0ac3, 0x215b }, /* oneeighth ⅛ VULGAR FRACTION ONE EIGHTH */ + { 0x0ac4, 0x215c }, /* threeeighths ⅜ VULGAR FRACTION THREE EIGHTHS */ + { 0x0ac5, 0x215d }, /* fiveeighths ⅝ VULGAR FRACTION FIVE EIGHTHS */ + { 0x0ac6, 0x215e }, /* seveneighths ⅞ VULGAR FRACTION SEVEN EIGHTHS */ + { 0x08fb, 0x2190 }, /* leftarrow ← LEFTWARDS ARROW */ + { 0x08fc, 0x2191 }, /* uparrow ↑ UPWARDS ARROW */ + { 0x08fd, 0x2192 }, /* rightarrow → RIGHTWARDS ARROW */ + { 0x08fe, 0x2193 }, /* downarrow ↓ DOWNWARDS ARROW */ + { 0x08ce, 0x21d2 }, /* implies ⇒ RIGHTWARDS DOUBLE ARROW */ + { 0x08cd, 0x21d4 }, /* ifonlyif ⇔ LEFT RIGHT DOUBLE ARROW */ + { 0x08ef, 0x2202 }, /* partialderivative ∂ PARTIAL DIFFERENTIAL */ + { 0x08c5, 0x2207 }, /* nabla ∇ NABLA */ + { 0x0bca, 0x2218 }, /* jot ∘ RING OPERATOR */ + { 0x08d6, 0x221a }, /* radical √ SQUARE ROOT */ + { 0x08c1, 0x221d }, /* variation ∝ PROPORTIONAL TO */ + { 0x08c2, 0x221e }, /* infinity ∞ INFINITY */ + { 0x08de, 0x2227 }, /* logicaland ∧ LOGICAL AND */ + { 0x0ba9, 0x2227 }, /* upcaret ∧ LOGICAL AND */ + { 0x08df, 0x2228 }, /* logicalor ∨ LOGICAL OR */ + { 0x0ba8, 0x2228 }, /* downcaret ∨ LOGICAL OR */ + { 0x08dc, 0x2229 }, /* intersection ∩ INTERSECTION */ + { 0x0bc3, 0x2229 }, /* upshoe ∩ INTERSECTION */ + { 0x08dd, 0x222a }, /* union ∪ UNION */ + { 0x0bd6, 0x222a }, /* downshoe ∪ UNION */ + { 0x08bf, 0x222b }, /* integral ∫ INTEGRAL */ + { 0x08c0, 0x2234 }, /* therefore ∴ THEREFORE */ + { 0x08c8, 0x2245 }, /* approximate ≅ APPROXIMATELY EQUAL TO */ + { 0x08bd, 0x2260 }, /* notequal ≠ NOT EQUAL TO */ + { 0x08cf, 0x2261 }, /* identical ≡ IDENTICAL TO */ + { 0x08bc, 0x2264 }, /* lessthanequal ≤ LESS-THAN OR EQUAL TO */ + { 0x08be, 0x2265 }, /* greaterthanequal ≥ GREATER-THAN OR EQUAL TO */ + { 0x08da, 0x2282 }, /* includedin ⊂ SUBSET OF */ + { 0x0bda, 0x2282 }, /* leftshoe ⊂ SUBSET OF */ + { 0x08db, 0x2283 }, /* includes ⊃ SUPERSET OF */ + { 0x0bd8, 0x2283 }, /* rightshoe ⊃ SUPERSET OF */ + { 0x0bfc, 0x22a2 }, /* righttack ⊢ RIGHT TACK */ + { 0x0bdc, 0x22a3 }, /* lefttack ⊣ LEFT TACK */ + { 0x0bc2, 0x22a4 }, /* downtack ⊤ DOWN TACK */ + { 0x0bce, 0x22a5 }, /* uptack ⊥ UP TACK */ + { 0x0bd3, 0x2308 }, /* upstile ⌈ LEFT CEILING */ + { 0x0bc4, 0x230a }, /* downstile ⌊ LEFT FLOOR */ + { 0x0afa, 0x2315 }, /* telephonerecorder ⌕ TELEPHONE RECORDER */ + { 0x08a4, 0x2320 }, /* topintegral ⌠ TOP HALF INTEGRAL */ + { 0x08a5, 0x2321 }, /* botintegral ⌡ BOTTOM HALF INTEGRAL */ + { 0x0abc, 0x2329 }, /* leftanglebracket 〈 LEFT-POINTING ANGLE BRACKET */ + { 0x0abe, 0x232a }, /* rightanglebracket 〉 RIGHT-POINTING ANGLE BRACKET */ + { 0x0bcc, 0x2395 }, /* quad ⎕ APL FUNCTIONAL SYMBOL QUAD (Unicode 3.0) */ + { 0x09e2, 0x2409 }, /* ht ␉ SYMBOL FOR HORIZONTAL TABULATION */ + { 0x09e5, 0x240a }, /* lf ␊ SYMBOL FOR LINE FEED */ + { 0x09e9, 0x240b }, /* vt ␋ SYMBOL FOR VERTICAL TABULATION */ + { 0x09e3, 0x240c }, /* ff ␌ SYMBOL FOR FORM FEED */ + { 0x09e4, 0x240d }, /* cr ␍ SYMBOL FOR CARRIAGE RETURN */ + { 0x09df, 0x2422 }, /* blank ␢ BLANK SYMBOL */ + { 0x09e8, 0x2424 }, /* nl ␤ SYMBOL FOR NEWLINE */ + { 0x09f1, 0x2500 }, /* horizlinescan5 ─ BOX DRAWINGS LIGHT HORIZONTAL */ + { 0x08a6, 0x2502 }, /* vertconnector │ BOX DRAWINGS LIGHT VERTICAL */ + { 0x09f8, 0x2502 }, /* vertbar │ BOX DRAWINGS LIGHT VERTICAL */ + { 0x09ec, 0x250c }, /* upleftcorner ┌ BOX DRAWINGS LIGHT DOWN AND RIGHT */ + { 0x09eb, 0x2510 }, /* uprightcorner ┐ BOX DRAWINGS LIGHT DOWN AND LEFT */ + { 0x09ed, 0x2514 }, /* lowleftcorner └ BOX DRAWINGS LIGHT UP AND RIGHT */ + { 0x09ea, 0x2518 }, /* lowrightcorner ┘ BOX DRAWINGS LIGHT UP AND LEFT */ + { 0x09f4, 0x251c }, /* leftt ├ BOX DRAWINGS LIGHT VERTICAL AND RIGHT */ + { 0x09f5, 0x2524 }, /* rightt ┤ BOX DRAWINGS LIGHT VERTICAL AND LEFT */ + { 0x09f7, 0x252c }, /* topt ┬ BOX DRAWINGS LIGHT DOWN AND HORIZONTAL */ + { 0x09f6, 0x2534 }, /* bott ┴ BOX DRAWINGS LIGHT UP AND HORIZONTAL */ + { 0x09ee, 0x253c }, /* crossinglines ┼ BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL */ + { 0x09e1, 0x2592 }, /* checkerboard ▒ MEDIUM SHADE */ + { 0x0adf, 0x25a0 }, /* emfilledrect ■ BLACK SQUARE */ + { 0x0acf, 0x25a1 }, /* emopenrectangle □ WHITE SQUARE */ + { 0x0ae7, 0x25aa }, /* enfilledsqbullet ▪ BLACK SMALL SQUARE */ + { 0x0ae1, 0x25ab }, /* enopensquarebullet ▫ WHITE SMALL SQUARE */ + { 0x0adb, 0x25ac }, /* filledrectbullet ▬ BLACK RECTANGLE */ + { 0x0ae2, 0x25ad }, /* openrectbullet ▭ WHITE RECTANGLE */ + { 0x0ae8, 0x25b2 }, /* filledtribulletup ▲ BLACK UP-POINTING TRIANGLE */ + { 0x0ae3, 0x25b3 }, /* opentribulletup △ WHITE UP-POINTING TRIANGLE */ + { 0x0add, 0x25b6 }, /* filledrighttribullet ▶ BLACK RIGHT-POINTING TRIANGLE */ + { 0x0acd, 0x25b7 }, /* rightopentriangle ▷ WHITE RIGHT-POINTING TRIANGLE */ + { 0x0ae9, 0x25bc }, /* filledtribulletdown ▼ BLACK DOWN-POINTING TRIANGLE */ + { 0x0ae4, 0x25bd }, /* opentribulletdown ▽ WHITE DOWN-POINTING TRIANGLE */ + { 0x0adc, 0x25c0 }, /* filledlefttribullet ◀ BLACK LEFT-POINTING TRIANGLE */ + { 0x0acc, 0x25c1 }, /* leftopentriangle ◁ WHITE LEFT-POINTING TRIANGLE */ + { 0x09e0, 0x25c6 }, /* soliddiamond ◆ BLACK DIAMOND */ + { 0x0ace, 0x25cb }, /* emopencircle ○ WHITE CIRCLE */ + { 0x0bcf, 0x25cb }, /* circle ○ WHITE CIRCLE */ + { 0x0ade, 0x25cf }, /* emfilledcircle ● BLACK CIRCLE */ + { 0x0ae0, 0x25e6 }, /* enopencircbullet ◦ WHITE BULLET */ + { 0x0ae5, 0x2606 }, /* openstar ☆ WHITE STAR */ + { 0x0af9, 0x260e }, /* telephone ☎ BLACK TELEPHONE */ + { 0x0aca, 0x2613 }, /* signaturemark ☓ SALTIRE */ + { 0x0aea, 0x261c }, /* leftpointer ☜ WHITE LEFT POINTING INDEX */ + { 0x0aeb, 0x261e }, /* rightpointer ☞ WHITE RIGHT POINTING INDEX */ + { 0x0af8, 0x2640 }, /* femalesymbol ♀ FEMALE SIGN */ + { 0x0af7, 0x2642 }, /* malesymbol ♂ MALE SIGN */ + { 0x0aec, 0x2663 }, /* club ♣ BLACK CLUB SUIT */ + { 0x0aee, 0x2665 }, /* heart ♥ BLACK HEART SUIT */ + { 0x0aed, 0x2666 }, /* diamond ♦ BLACK DIAMOND SUIT */ + { 0x0af6, 0x266d }, /* musicalflat ♭ MUSIC FLAT SIGN */ + { 0x0af5, 0x266f }, /* musicalsharp ♯ MUSIC SHARP SIGN */ + { 0x0af3, 0x2713 }, /* checkmark ✓ CHECK MARK */ + { 0x0af4, 0x2717 }, /* ballotcross ✗ BALLOT X */ + { 0x0ad9, 0x271d }, /* latincross ✝ LATIN CROSS */ + { 0x0af0, 0x2720 }, /* maltesecross ✠ MALTESE CROSS */ + { 0x04a4, 0x3001 }, /* kana_comma 、 IDEOGRAPHIC COMMA */ + { 0x04a1, 0x3002 }, /* kana_fullstop 。 IDEOGRAPHIC FULL STOP */ + { 0x04a2, 0x300c }, /* kana_openingbracket 「 LEFT CORNER BRACKET */ + { 0x04a3, 0x300d }, /* kana_closingbracket 」 RIGHT CORNER BRACKET */ + { 0x04de, 0x309b }, /* voicedsound ゛ KATAKANA-HIRAGANA VOICED SOUND MARK */ + { 0x04df, 0x309c }, /* semivoicedsound ゜ KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK */ + { 0x04a7, 0x30a1 }, /* kana_a ァ KATAKANA LETTER SMALL A */ + { 0x04b1, 0x30a2 }, /* kana_A ア KATAKANA LETTER A */ + { 0x04a8, 0x30a3 }, /* kana_i ィ KATAKANA LETTER SMALL I */ + { 0x04b2, 0x30a4 }, /* kana_I イ KATAKANA LETTER I */ + { 0x04a9, 0x30a5 }, /* kana_u ゥ KATAKANA LETTER SMALL U */ + { 0x04b3, 0x30a6 }, /* kana_U ウ KATAKANA LETTER U */ + { 0x04aa, 0x30a7 }, /* kana_e ェ KATAKANA LETTER SMALL E */ + { 0x04b4, 0x30a8 }, /* kana_E エ KATAKANA LETTER E */ + { 0x04ab, 0x30a9 }, /* kana_o ォ KATAKANA LETTER SMALL O */ + { 0x04b5, 0x30aa }, /* kana_O オ KATAKANA LETTER O */ + { 0x04b6, 0x30ab }, /* kana_KA カ KATAKANA LETTER KA */ + { 0x04b7, 0x30ad }, /* kana_KI キ KATAKANA LETTER KI */ + { 0x04b8, 0x30af }, /* kana_KU ク KATAKANA LETTER KU */ + { 0x04b9, 0x30b1 }, /* kana_KE ケ KATAKANA LETTER KE */ + { 0x04ba, 0x30b3 }, /* kana_KO コ KATAKANA LETTER KO */ + { 0x04bb, 0x30b5 }, /* kana_SA サ KATAKANA LETTER SA */ + { 0x04bc, 0x30b7 }, /* kana_SHI シ KATAKANA LETTER SI */ + { 0x04bd, 0x30b9 }, /* kana_SU ス KATAKANA LETTER SU */ + { 0x04be, 0x30bb }, /* kana_SE セ KATAKANA LETTER SE */ + { 0x04bf, 0x30bd }, /* kana_SO ソ KATAKANA LETTER SO */ + { 0x04c0, 0x30bf }, /* kana_TA タ KATAKANA LETTER TA */ + { 0x04c1, 0x30c1 }, /* kana_CHI チ KATAKANA LETTER TI */ + { 0x04af, 0x30c3 }, /* kana_tsu ッ KATAKANA LETTER SMALL TU */ + { 0x04c2, 0x30c4 }, /* kana_TSU ツ KATAKANA LETTER TU */ + { 0x04c3, 0x30c6 }, /* kana_TE テ KATAKANA LETTER TE */ + { 0x04c4, 0x30c8 }, /* kana_TO ト KATAKANA LETTER TO */ + { 0x04c5, 0x30ca }, /* kana_NA ナ KATAKANA LETTER NA */ + { 0x04c6, 0x30cb }, /* kana_NI ニ KATAKANA LETTER NI */ + { 0x04c7, 0x30cc }, /* kana_NU ヌ KATAKANA LETTER NU */ + { 0x04c8, 0x30cd }, /* kana_NE ネ KATAKANA LETTER NE */ + { 0x04c9, 0x30ce }, /* kana_NO ノ KATAKANA LETTER NO */ + { 0x04ca, 0x30cf }, /* kana_HA ハ KATAKANA LETTER HA */ + { 0x04cb, 0x30d2 }, /* kana_HI ヒ KATAKANA LETTER HI */ + { 0x04cc, 0x30d5 }, /* kana_FU フ KATAKANA LETTER HU */ + { 0x04cd, 0x30d8 }, /* kana_HE ヘ KATAKANA LETTER HE */ + { 0x04ce, 0x30db }, /* kana_HO ホ KATAKANA LETTER HO */ + { 0x04cf, 0x30de }, /* kana_MA マ KATAKANA LETTER MA */ + { 0x04d0, 0x30df }, /* kana_MI ミ KATAKANA LETTER MI */ + { 0x04d1, 0x30e0 }, /* kana_MU ム KATAKANA LETTER MU */ + { 0x04d2, 0x30e1 }, /* kana_ME メ KATAKANA LETTER ME */ + { 0x04d3, 0x30e2 }, /* kana_MO モ KATAKANA LETTER MO */ + { 0x04ac, 0x30e3 }, /* kana_ya ャ KATAKANA LETTER SMALL YA */ + { 0x04d4, 0x30e4 }, /* kana_YA ヤ KATAKANA LETTER YA */ + { 0x04ad, 0x30e5 }, /* kana_yu ュ KATAKANA LETTER SMALL YU */ + { 0x04d5, 0x30e6 }, /* kana_YU ユ KATAKANA LETTER YU */ + { 0x04ae, 0x30e7 }, /* kana_yo ョ KATAKANA LETTER SMALL YO */ + { 0x04d6, 0x30e8 }, /* kana_YO ヨ KATAKANA LETTER YO */ + { 0x04d7, 0x30e9 }, /* kana_RA ラ KATAKANA LETTER RA */ + { 0x04d8, 0x30ea }, /* kana_RI リ KATAKANA LETTER RI */ + { 0x04d9, 0x30eb }, /* kana_RU ル KATAKANA LETTER RU */ + { 0x04da, 0x30ec }, /* kana_RE レ KATAKANA LETTER RE */ + { 0x04db, 0x30ed }, /* kana_RO ロ KATAKANA LETTER RO */ + { 0x04dc, 0x30ef }, /* kana_WA ワ KATAKANA LETTER WA */ + { 0x04a6, 0x30f2 }, /* kana_WO ヲ KATAKANA LETTER WO */ + { 0x04dd, 0x30f3 }, /* kana_N ン KATAKANA LETTER N */ + { 0x04a5, 0x30fb }, /* kana_conjunctive ・ KATAKANA MIDDLE DOT */ + { 0x04b0, 0x30fc }, /* prolongedsound ー KATAKANA-HIRAGANA PROLONGED SOUND MARK */ + { 0x0ea1, 0x3131 }, /* Hangul_Kiyeog ㄱ HANGUL LETTER KIYEOK */ + { 0x0ea2, 0x3132 }, /* Hangul_SsangKiyeog ㄲ HANGUL LETTER SSANGKIYEOK */ + { 0x0ea3, 0x3133 }, /* Hangul_KiyeogSios ㄳ HANGUL LETTER KIYEOK-SIOS */ + { 0x0ea4, 0x3134 }, /* Hangul_Nieun ㄴ HANGUL LETTER NIEUN */ + { 0x0ea5, 0x3135 }, /* Hangul_NieunJieuj ㄵ HANGUL LETTER NIEUN-CIEUC */ + { 0x0ea6, 0x3136 }, /* Hangul_NieunHieuh ㄶ HANGUL LETTER NIEUN-HIEUH */ + { 0x0ea7, 0x3137 }, /* Hangul_Dikeud ㄷ HANGUL LETTER TIKEUT */ + { 0x0ea8, 0x3138 }, /* Hangul_SsangDikeud ㄸ HANGUL LETTER SSANGTIKEUT */ + { 0x0ea9, 0x3139 }, /* Hangul_Rieul ㄹ HANGUL LETTER RIEUL */ + { 0x0eaa, 0x313a }, /* Hangul_RieulKiyeog ㄺ HANGUL LETTER RIEUL-KIYEOK */ + { 0x0eab, 0x313b }, /* Hangul_RieulMieum ㄻ HANGUL LETTER RIEUL-MIEUM */ + { 0x0eac, 0x313c }, /* Hangul_RieulPieub ㄼ HANGUL LETTER RIEUL-PIEUP */ + { 0x0ead, 0x313d }, /* Hangul_RieulSios ㄽ HANGUL LETTER RIEUL-SIOS */ + { 0x0eae, 0x313e }, /* Hangul_RieulTieut ㄾ HANGUL LETTER RIEUL-THIEUTH */ + { 0x0eaf, 0x313f }, /* Hangul_RieulPhieuf ㄿ HANGUL LETTER RIEUL-PHIEUPH */ + { 0x0eb0, 0x3140 }, /* Hangul_RieulHieuh ㅀ HANGUL LETTER RIEUL-HIEUH */ + { 0x0eb1, 0x3141 }, /* Hangul_Mieum ㅁ HANGUL LETTER MIEUM */ + { 0x0eb2, 0x3142 }, /* Hangul_Pieub ㅂ HANGUL LETTER PIEUP */ + { 0x0eb3, 0x3143 }, /* Hangul_SsangPieub ㅃ HANGUL LETTER SSANGPIEUP */ + { 0x0eb4, 0x3144 }, /* Hangul_PieubSios ㅄ HANGUL LETTER PIEUP-SIOS */ + { 0x0eb5, 0x3145 }, /* Hangul_Sios ㅅ HANGUL LETTER SIOS */ + { 0x0eb6, 0x3146 }, /* Hangul_SsangSios ㅆ HANGUL LETTER SSANGSIOS */ + { 0x0eb7, 0x3147 }, /* Hangul_Ieung ㅇ HANGUL LETTER IEUNG */ + { 0x0eb8, 0x3148 }, /* Hangul_Jieuj ㅈ HANGUL LETTER CIEUC */ + { 0x0eb9, 0x3149 }, /* Hangul_SsangJieuj ㅉ HANGUL LETTER SSANGCIEUC */ + { 0x0eba, 0x314a }, /* Hangul_Cieuc ㅊ HANGUL LETTER CHIEUCH */ + { 0x0ebb, 0x314b }, /* Hangul_Khieuq ㅋ HANGUL LETTER KHIEUKH */ + { 0x0ebc, 0x314c }, /* Hangul_Tieut ㅌ HANGUL LETTER THIEUTH */ + { 0x0ebd, 0x314d }, /* Hangul_Phieuf ㅍ HANGUL LETTER PHIEUPH */ + { 0x0ebe, 0x314e }, /* Hangul_Hieuh ㅎ HANGUL LETTER HIEUH */ + { 0x0ebf, 0x314f }, /* Hangul_A ㅏ HANGUL LETTER A */ + { 0x0ec0, 0x3150 }, /* Hangul_AE ㅐ HANGUL LETTER AE */ + { 0x0ec1, 0x3151 }, /* Hangul_YA ㅑ HANGUL LETTER YA */ + { 0x0ec2, 0x3152 }, /* Hangul_YAE ㅒ HANGUL LETTER YAE */ + { 0x0ec3, 0x3153 }, /* Hangul_EO ㅓ HANGUL LETTER EO */ + { 0x0ec4, 0x3154 }, /* Hangul_E ㅔ HANGUL LETTER E */ + { 0x0ec5, 0x3155 }, /* Hangul_YEO ㅕ HANGUL LETTER YEO */ + { 0x0ec6, 0x3156 }, /* Hangul_YE ㅖ HANGUL LETTER YE */ + { 0x0ec7, 0x3157 }, /* Hangul_O ㅗ HANGUL LETTER O */ + { 0x0ec8, 0x3158 }, /* Hangul_WA ㅘ HANGUL LETTER WA */ + { 0x0ec9, 0x3159 }, /* Hangul_WAE ㅙ HANGUL LETTER WAE */ + { 0x0eca, 0x315a }, /* Hangul_OE ㅚ HANGUL LETTER OE */ + { 0x0ecb, 0x315b }, /* Hangul_YO ㅛ HANGUL LETTER YO */ + { 0x0ecc, 0x315c }, /* Hangul_U ㅜ HANGUL LETTER U */ + { 0x0ecd, 0x315d }, /* Hangul_WEO ㅝ HANGUL LETTER WEO */ + { 0x0ece, 0x315e }, /* Hangul_WE ㅞ HANGUL LETTER WE */ + { 0x0ecf, 0x315f }, /* Hangul_WI ㅟ HANGUL LETTER WI */ + { 0x0ed0, 0x3160 }, /* Hangul_YU ㅠ HANGUL LETTER YU */ + { 0x0ed1, 0x3161 }, /* Hangul_EU ㅡ HANGUL LETTER EU */ + { 0x0ed2, 0x3162 }, /* Hangul_YI ㅢ HANGUL LETTER YI */ + { 0x0ed3, 0x3163 }, /* Hangul_I ㅣ HANGUL LETTER I */ + { 0x0eef, 0x316d }, /* Hangul_RieulYeorinHieuh ㅭ HANGUL LETTER RIEUL-YEORINHIEUH */ + { 0x0ef0, 0x3171 }, /* Hangul_SunkyeongeumMieum ㅱ HANGUL LETTER KAPYEOUNMIEUM */ + { 0x0ef1, 0x3178 }, /* Hangul_SunkyeongeumPieub ㅸ HANGUL LETTER KAPYEOUNPIEUP */ + { 0x0ef2, 0x317f }, /* Hangul_PanSios ㅿ HANGUL LETTER PANSIOS */ + { 0x0ef4, 0x3184 }, /* Hangul_SunkyeongeumPhieuf ㆄ HANGUL LETTER KAPYEOUNPHIEUPH */ + { 0x0ef5, 0x3186 }, /* Hangul_YeorinHieuh ㆆ HANGUL LETTER YEORINHIEUH */ + { 0x0ef6, 0x318d }, /* Hangul_AraeA ㆍ HANGUL LETTER ARAEA */ + { 0x0ef7, 0x318e }, /* Hangul_AraeAE ㆎ HANGUL LETTER ARAEAE */ +}; + +static guint +unicode_to_keyval (wchar_t ucs) +{ + int min = 0; + int max = sizeof(u2ktab) / sizeof(u2ktab[0]) - 1; + int mid; + + /* First check for Latin-1 characters (1:1 mapping) */ + if ((ucs >= 0x0020 && ucs <= 0x007e) || + (ucs >= 0x00a0 && ucs <= 0x00ff)) + return ucs; + + /* Binary search in table */ + while (max >= min) { + mid = (min + max) / 2; + if (u2ktab[mid].ucs < ucs) + min = mid + 1; + else if (u2ktab[mid].ucs > ucs) + max = mid - 1; + else { + /* found it */ + return u2ktab[mid].keysym; + } + } + + /* + * No matching keysym value found, return Unicode value plus 0x01000000 + * (a convention introduced in the UTF-8 work on xterm). + */ + return ucs | 0x01000000; +} + +static void +build_key_event_state (GdkEvent *event) +{ + event->key.state = 0; + if (GetKeyState (VK_SHIFT) < 0) + event->key.state |= GDK_SHIFT_MASK; + if (GetKeyState (VK_CAPITAL) & 0x1) + event->key.state |= GDK_LOCK_MASK; + if (!is_AltGr_key) + { + if (GetKeyState (VK_CONTROL) < 0) + { + event->key.state |= GDK_CONTROL_MASK; + if (event->key.keyval < ' ') + event->key.keyval += '@'; + } + else if (event->key.keyval < ' ') + { + event->key.state |= GDK_CONTROL_MASK; + event->key.keyval += '@'; + } + if (GetKeyState (VK_MENU) < 0) + event->key.state |= GDK_MOD1_MASK; + } +} + +static gint +build_pointer_event_state (MSG *xevent) +{ + gint state; + + state = 0; + if (xevent->wParam & MK_CONTROL) + state |= GDK_CONTROL_MASK; + if (xevent->wParam & MK_LBUTTON) + state |= GDK_BUTTON1_MASK; + if (xevent->wParam & MK_MBUTTON) + state |= GDK_BUTTON2_MASK; + if (xevent->wParam & MK_RBUTTON) + state |= GDK_BUTTON3_MASK; + if (xevent->wParam & MK_SHIFT) + state |= GDK_SHIFT_MASK; + if (GetKeyState (VK_MENU) < 0) + state |= GDK_MOD1_MASK; + if (GetKeyState (VK_CAPITAL) & 0x1) + state |= GDK_LOCK_MASK; + + return state; +} + + +static void +build_keypress_event (GdkWindowPrivate *window_private, + GdkEvent *event, + MSG *xevent) +{ + HIMC hIMC; + gint i, bytesleft, bytecount, ucount, ucleft, len; + guchar buf[100], *bp; + wchar_t wbuf[100], *wcp; + + event->key.type = GDK_KEY_PRESS; + event->key.time = xevent->time; + + if (xevent->message == WM_IME_COMPOSITION) + { + hIMC = ImmGetContext (xevent->hwnd); + + bytecount = ImmGetCompositionStringW (hIMC, GCS_RESULTSTR, + wbuf, sizeof (wbuf)); + ucount = bytecount / 2; + } + else + { + if (xevent->message == WM_CHAR) + { + bytecount = MIN ((xevent->lParam & 0xFFFF), sizeof (buf)); + for (i = 0; i < bytecount; i++) + buf[i] = xevent->wParam; + } + else /* WM_IME_CHAR */ + { + event->key.keyval = GDK_VoidSymbol; + if (xevent->wParam & 0xFF00) + { + /* Contrary to some versions of the documentation, + * the lead byte is the most significant byte. + */ + buf[0] = ((xevent->wParam >> 8) & 0xFF); + buf[1] = (xevent->wParam & 0xFF); + bytecount = 2; + } + else + { + buf[0] = (xevent->wParam & 0xFF); + bytecount = 1; + } + } + + /* Convert from the window's current code page + * to Unicode. Then convert to UTF-8. + * We don't handle the surrogate stuff. Should we? + */ + ucount = MultiByteToWideChar (window_private->charset_info.ciACP, + 0, buf, bytecount, + wbuf, sizeof (wbuf) / sizeof (wbuf[0])); + + } + if (ucount == 0) + event->key.keyval = GDK_VoidSymbol; + else if (xevent->message == WM_CHAR) + if (xevent->wParam < ' ') + event->key.keyval = xevent->wParam + '@'; + else + event->key.keyval = unicode_to_keyval (wbuf[0]); + else + event->key.keyval = GDK_VoidSymbol; + + build_key_event_state (event); + + ucleft = ucount; + len = 0; + wcp = wbuf; + while (ucleft-- > 0) + { + wchar_t c = *wcp++; + + if (c < 0x80) + len += 1; + else if (c < 0x800) + len += 2; + else + len += 3; + } + + event->key.string = g_malloc (len + 1); + event->key.length = len; + + ucleft = ucount; + wcp = wbuf; + bp = event->key.string; + while (ucleft-- > 0) + { + int first; + int i; + wchar_t c = *wcp++; + + if (c < 0x80) + { + first = 0; + len = 1; + } + else if (c < 0x800) + { + first = 0xc0; + len = 2; + } + else + { + first = 0xe0; + len = 3; + } + +#if 1 + /* Woo-hoo! */ + switch (len) + { + case 3: bp[2] = (c & 0x3f) | 0x80; c >>= 6; /* Fall through */ + case 2: bp[1] = (c & 0x3f) | 0x80; c >>= 6; /* Fall through */ + case 1: bp[0] = c | first; + } +#else + for (i = len - 1; i > 0; --i) + { + bp[i] = (c & 0x3f) | 0x80; + c >>= 6; + } + bp[0] = c | first; +#endif + + bp += len; + } + *bp = 0; +} + +static void +build_keyrelease_event (GdkWindowPrivate *window_private, + GdkEvent *event, + MSG *xevent) +{ + guchar buf; + wchar_t wbuf; + + event->key.type = GDK_KEY_RELEASE; + event->key.time = xevent->time; + + if (xevent->message == WM_CHAR) + if (xevent->wParam < ' ') + event->key.keyval = xevent->wParam + '@'; + else + { + buf = xevent->wParam; + MultiByteToWideChar (window_private->charset_info.ciACP, + 0, &buf, 1, &wbuf, 1); + + event->key.keyval = unicode_to_keyval (wbuf); + } + else + event->key.keyval = GDK_VoidSymbol; + build_key_event_state (event); + event->key.string = NULL; + event->key.length = 0; +} + +static void +print_event_state (gint state) +{ + if (state & GDK_SHIFT_MASK) + g_print ("SHIFT "); + if (state & GDK_LOCK_MASK) + g_print ("LOCK "); + if (state & GDK_CONTROL_MASK) + g_print ("CONTROL "); + if (state & GDK_MOD1_MASK) + g_print ("MOD1 "); + if (state & GDK_BUTTON1_MASK) + g_print ("BUTTON1 "); + if (state & GDK_BUTTON2_MASK) + g_print ("BUTTON2 "); + if (state & GDK_BUTTON3_MASK) + g_print ("BUTTON3 "); +} + +static void +print_event (GdkEvent *event) +{ + gchar *escaped, *kvname; + + switch (event->any.type) + { + case GDK_NOTHING: g_print ("GDK_NOTHING "); break; + case GDK_DELETE: g_print ("GDK_DELETE "); break; + case GDK_DESTROY: g_print ("GDK_DESTROY "); break; + case GDK_EXPOSE: g_print ("GDK_EXPOSE "); break; + case GDK_MOTION_NOTIFY: g_print ("GDK_MOTION_NOTIFY "); break; + case GDK_BUTTON_PRESS: g_print ("GDK_BUTTON_PRESS "); break; + case GDK_2BUTTON_PRESS: g_print ("GDK_2BUTTON_PRESS "); break; + case GDK_3BUTTON_PRESS: g_print ("GDK_3BUTTON_PRESS "); break; + case GDK_BUTTON_RELEASE: g_print ("GDK_BUTTON_RELEASE "); break; + case GDK_KEY_PRESS: g_print ("GDK_KEY_PRESS "); break; + case GDK_KEY_RELEASE: g_print ("GDK_KEY_RELEASE "); break; + case GDK_ENTER_NOTIFY: g_print ("GDK_ENTER_NOTIFY "); break; + case GDK_LEAVE_NOTIFY: g_print ("GDK_LEAVE_NOTIFY "); break; + case GDK_FOCUS_CHANGE: g_print ("GDK_FOCUS_CHANGE "); break; + case GDK_CONFIGURE: g_print ("GDK_CONFIGURE "); break; + case GDK_MAP: g_print ("GDK_MAP "); break; + case GDK_UNMAP: g_print ("GDK_UNMAP "); break; + case GDK_PROPERTY_NOTIFY: g_print ("GDK_PROPERTY_NOTIFY "); break; + case GDK_SELECTION_CLEAR: g_print ("GDK_SELECTION_CLEAR "); break; + case GDK_SELECTION_REQUEST: g_print ("GDK_SELECTION_REQUEST "); break; + case GDK_SELECTION_NOTIFY: g_print ("GDK_SELECTION_NOTIFY "); break; + case GDK_PROXIMITY_IN: g_print ("GDK_PROXIMITY_IN "); break; + case GDK_PROXIMITY_OUT: g_print ("GDK_PROXIMITY_OUT "); break; + case GDK_DRAG_ENTER: g_print ("GDK_DRAG_ENTER "); break; + case GDK_DRAG_LEAVE: g_print ("GDK_DRAG_LEAVE "); break; + case GDK_DRAG_MOTION: g_print ("GDK_DRAG_MOTION "); break; + case GDK_DRAG_STATUS: g_print ("GDK_DRAG_STATUS "); break; + case GDK_DROP_START: g_print ("GDK_DROP_START "); break; + case GDK_DROP_FINISHED: g_print ("GDK_DROP_FINISHED "); break; + case GDK_CLIENT_EVENT: g_print ("GDK_CLIENT_EVENT "); break; + case GDK_VISIBILITY_NOTIFY: g_print ("GDK_VISIBILITY_NOTIFY "); break; + case GDK_NO_EXPOSE: g_print ("GDK_NO_EXPOSE "); break; + } + g_print ("%#x ", GDK_DRAWABLE_XID (event->any.window)); + + switch (event->any.type) + { + case GDK_EXPOSE: + g_print ("%dx%d@+%d+%d %d", + event->expose.area.width, + event->expose.area.height, + event->expose.area.x, + event->expose.area.y, + event->expose.count); + break; + case GDK_MOTION_NOTIFY: + g_print ("(%.4g,%.4g) %s", + event->motion.x, event->motion.y, + event->motion.is_hint ? "HINT " : ""); + print_event_state (event->motion.state); + break; + case GDK_BUTTON_PRESS: + case GDK_2BUTTON_PRESS: + case GDK_3BUTTON_PRESS: + case GDK_BUTTON_RELEASE: + g_print ("%d (%.4g,%.4g) ", + event->button.button, + event->button.x, event->button.y); + print_event_state (event->button.state); + break; + case GDK_KEY_PRESS: + case GDK_KEY_RELEASE: + if (event->key.length == 0) + escaped = g_strdup (""); + else + escaped = g_strescape (event->key.string, NULL); + kvname = gdk_keyval_name (event->key.keyval); + g_print ("%s %d:\"%s\" ", + (kvname ? kvname : "??"), + event->key.length, + escaped); + g_free (escaped); + print_event_state (event->key.state); + break; + case GDK_ENTER_NOTIFY: + case GDK_LEAVE_NOTIFY: + g_print (" %s", + (event->crossing.detail == GDK_NOTIFY_INFERIOR ? "INFERIOR" : + (event->crossing.detail == GDK_NOTIFY_ANCESTOR ? "ANCESTOR" : + (event->crossing.detail == GDK_NOTIFY_NONLINEAR ? "NONLINEAR" : + "???")))); + break; + } + g_print ("\n"); +} + +static void +synthesize_crossing_events (GdkWindow *window, + MSG *xevent) +{ + GdkEvent *event; + + /* If we are not using TrackMouseEvent, generate a leave notify + * event if necessary + */ + if (p_TrackMouseEvent == NULL + && curWnd + && (WINDOW_PRIVATE(curWnd)->event_mask & GDK_LEAVE_NOTIFY_MASK)) + { + GDK_NOTE (EVENTS, g_print ("synthesizing LEAVE_NOTIFY event\n")); + + event = gdk_event_new (); + event->crossing.type = GDK_LEAVE_NOTIFY; + event->crossing.window = curWnd; + gdk_window_ref (event->crossing.window); + event->crossing.subwindow = NULL; + event->crossing.time = xevent->time; + event->crossing.x = curX; + event->crossing.y = curY; + event->crossing.x_root = curXroot; + event->crossing.y_root = curYroot; + event->crossing.mode = GDK_CROSSING_NORMAL; + if (IsChild (GDK_DRAWABLE_XID (curWnd), GDK_DRAWABLE_XID (window))) + event->crossing.detail = GDK_NOTIFY_INFERIOR; + else if (IsChild (GDK_DRAWABLE_XID (window), GDK_DRAWABLE_XID (curWnd))) + event->crossing.detail = GDK_NOTIFY_ANCESTOR; + else + event->crossing.detail = GDK_NOTIFY_NONLINEAR; + + event->crossing.focus = TRUE; /* ??? */ + event->crossing.state = 0; /* ??? */ + + gdk_event_queue_append (event); + GDK_NOTE (EVENTS, print_event (event)); + } + + if (WINDOW_PRIVATE(window)->event_mask & GDK_ENTER_NOTIFY_MASK) + { + GDK_NOTE (EVENTS, g_print ("synthesizing ENTER_NOTIFY event\n")); + + event = gdk_event_new (); + event->crossing.type = GDK_ENTER_NOTIFY; + event->crossing.window = window; + gdk_window_ref (event->crossing.window); + event->crossing.subwindow = NULL; + event->crossing.time = xevent->time; + event->crossing.x = LOWORD (xevent->lParam); + event->crossing.y = HIWORD (xevent->lParam); + event->crossing.x_root = (gfloat) xevent->pt.x; + event->crossing.y_root = (gfloat) xevent->pt.y; + event->crossing.mode = GDK_CROSSING_NORMAL; + if (curWnd + && IsChild (GDK_DRAWABLE_XID (curWnd), GDK_DRAWABLE_XID (window))) + event->crossing.detail = GDK_NOTIFY_ANCESTOR; + else if (curWnd + && IsChild (GDK_DRAWABLE_XID (window), GDK_DRAWABLE_XID (curWnd))) + event->crossing.detail = GDK_NOTIFY_INFERIOR; + else + event->crossing.detail = GDK_NOTIFY_NONLINEAR; + + event->crossing.focus = TRUE; /* ??? */ + event->crossing.state = 0; /* ??? */ + + gdk_event_queue_append (event); + + GDK_NOTE (EVENTS, print_event (event)); + + if (WINDOW_PRIVATE(window)->extension_events != 0 + && gdk_input_vtable.enter_event) + gdk_input_vtable.enter_event (&event->crossing, window); + + } + + if (curWnd) + gdk_window_unref (curWnd); + curWnd = window; + gdk_window_ref (curWnd); +#ifdef USE_TRACKMOUSEEVENT + if (p_TrackMouseEvent != NULL) + { + TRACKMOUSEEVENT tme; + + tme.cbSize = sizeof (TRACKMOUSEEVENT); + tme.dwFlags = TME_LEAVE; + tme.hwndTrack = GDK_DRAWABLE_XID (curWnd); + tme.dwHoverTime = HOVER_DEFAULT; + + (*p_TrackMouseEvent) (&tme); + } +#endif +} + +#ifndef NEW_PROPAGATION_CODE + +static GdkWindow * +key_propagate (GdkWindow *window, + MSG *xevent) +{ + gdk_window_unref (window); + window = WINDOW_PRIVATE(window)->parent; + gdk_window_ref (window); + + return window; +} + +static GdkWindow * +pointer_propagate (GdkWindow *window, + MSG *xevent) +{ + POINT pt; + + pt.x = LOWORD (xevent->lParam); + pt.y = HIWORD (xevent->lParam); + ClientToScreen (GDK_DRAWABLE_XID (window), &pt); + gdk_window_unref (window); + window = WINDOW_PRIVATE(window)->parent; + gdk_window_ref (window); + ScreenToClient (GDK_DRAWABLE_XID (window), &pt); + xevent->lParam = MAKELPARAM (pt.x, pt.y); + + return window; +} + +#endif /* !NEW_PROPAGATION_CODE */ + +static void +translate_mouse_coords (GdkWindow *window1, + GdkWindow *window2, + MSG *xevent) +{ + POINT pt; + + pt.x = LOWORD (xevent->lParam); + pt.y = HIWORD (xevent->lParam); + ClientToScreen (GDK_DRAWABLE_XID (window1), &pt); + ScreenToClient (GDK_DRAWABLE_XID (window2), &pt); + xevent->lParam = MAKELPARAM (pt.x, pt.y); + GDK_NOTE (EVENTS, g_print ("...new coords are (%d,%d)\n", pt.x, pt.y)); +} + +#ifdef NEW_PROPAGATION_CODE + +static gboolean +propagate (GdkWindow **window, + MSG *xevent, + GdkWindow *grab_window, + gboolean grab_owner_events, + gint grab_mask, + gboolean (*doesnt_want_it) (gint mask, + MSG *xevent)) +{ + if (grab_window != NULL && !grab_owner_events) + { + /* Event source is grabbed with owner_events FALSE */ + GDK_NOTE (EVENTS, g_print ("...grabbed, owner_events FALSE, ")); + if ((*doesnt_want_it) (grab_mask, xevent)) + { + GDK_NOTE (EVENTS, g_print ("...grabber doesn't want it\n")); + return FALSE; + } + else + { + GDK_NOTE (EVENTS, g_print ("...sending to grabber %#x\n", + GDK_DRAWABLE_XID (grab_window))); + gdk_window_unref (*window); + *window = grab_window; + gdk_window_ref (*window); + return TRUE; + } + } + while (TRUE) + { + if ((*doesnt_want_it) (WINDOW_PRIVATE(*window)->event_mask, xevent)) + { + /* Owner doesn't want it, propagate to parent. */ + if (WINDOW_PRIVATE(*window)->parent == (GdkWindow *) gdk_root_parent) + { + /* No parent; check if grabbed */ + if (grab_window != NULL) + { + /* Event source is grabbed with owner_events TRUE */ + GDK_NOTE (EVENTS, g_print ("...undelivered, but grabbed\n")); + if ((*doesnt_want_it) (grab_mask, xevent)) + { + /* Grabber doesn't want it either */ + GDK_NOTE (EVENTS, g_print ("...grabber doesn't want it\n")); + return FALSE; + } + else + { + /* Grabbed! */ + GDK_NOTE (EVENTS, g_print ("...sending to grabber %#x\n", + GDK_DRAWABLE_XID (grab_window))); + gdk_window_unref (*window); + *window = grab_window; + gdk_window_ref (*window); + return TRUE; + } + } + else + { + GDK_NOTE (EVENTS, g_print ("...undelivered\n")); + return FALSE; + } + } + else + { + gdk_window_unref (*window); + *window = WINDOW_PRIVATE(*window)->parent; + gdk_window_ref (*window); + GDK_NOTE (EVENTS, g_print ("...propagating to %#x\n", + GDK_DRAWABLE_XID (*window))); + /* The only branch where we actually continue the loop */ + } + } + else + return TRUE; + } +} + +static gboolean +doesnt_want_key (gint mask, + MSG *xevent) +{ + return (((xevent->message == WM_KEYUP + || xevent->message == WM_SYSKEYUP) + && !(mask & GDK_KEY_RELEASE_MASK)) + || + ((xevent->message == WM_KEYDOWN + || xevent->message == WM_SYSKEYDOWN) + && !(mask & GDK_KEY_PRESS_MASK))); +} + +static gboolean +doesnt_want_char (gint mask, + MSG *xevent) +{ + return !(mask & (GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK)); +} + +static gboolean +doesnt_want_button_press (gint mask, + MSG *xevent) +{ + return !(mask & GDK_BUTTON_PRESS_MASK); +} + +static gboolean +doesnt_want_button_release (gint mask, + MSG *xevent) +{ + return !(mask & GDK_BUTTON_RELEASE_MASK); +} + +static gboolean +doesnt_want_button_motion (gint mask, + MSG *xevent) +{ + return !((mask & GDK_POINTER_MOTION_MASK) + || ((xevent->wParam & (MK_LBUTTON|MK_MBUTTON|MK_RBUTTON)) + && (mask & GDK_BUTTON_MOTION_MASK)) + || ((xevent->wParam & MK_LBUTTON) + && (mask & GDK_BUTTON1_MOTION_MASK)) + || ((xevent->wParam & MK_MBUTTON) + && (mask & GDK_BUTTON2_MOTION_MASK)) + || ((xevent->wParam & MK_RBUTTON) + && (mask & GDK_BUTTON3_MOTION_MASK))); +} + +#endif + +static gboolean +gdk_event_translate (GdkEvent *event, + MSG *xevent, + gboolean *ret_val_flagp, + gint *ret_valp) +{ + GdkWindow *window, *orig_window; + GdkColormapPrivate *colormap_private; + HWND owner; + DWORD pidActWin; + DWORD pidThis; + DWORD dwStyle; + PAINTSTRUCT paintstruct; + HDC hdc; + HBRUSH hbr; + RECT rect; + POINT pt; + MINMAXINFO *lpmmi; + GdkEventMask mask; + GdkDrawablePrivate *pixmap_private; + HDC bgdc; + HGDIOBJ oldbitmap; + int button; + int i, j, n, k; + gchar buf[256]; + gchar *msgname; + gboolean return_val; + gboolean flag; + + return_val = FALSE; + + if (ret_val_flagp) + *ret_val_flagp = FALSE; + +#ifndef USE_DISPATCHMESSAGE + if (xevent->message == gdk_ping_msg) + { + /* Messages we post ourselves just to wakeup WaitMessage. */ + GDK_NOTE (EVENTS, g_print ("gdk_ping_msg\n")); + + return FALSE; + } + else if (xevent->message == g_pipe_readable_msg) + { + GDK_NOTE (EVENTS, g_print ("g_pipe_readable_msg: %d %d\n", + xevent->wParam, xevent->lParam)); + + g_io_channel_win32_pipe_readable (xevent->wParam, xevent->lParam); + return FALSE; + } +#endif + + window = gdk_window_lookup (xevent->hwnd); + orig_window = window; + + if (window != NULL) + gdk_window_ref (window); + else + { + /* Handle WM_QUIT here ? */ + if (xevent->message == WM_QUIT) + { + GDK_NOTE (EVENTS, g_print ("WM_QUIT: %d\n", xevent->wParam)); + exit (xevent->wParam); + } + else if (xevent->message == WM_MOVE + || xevent->message == WM_SIZE) + { + /* It's quite normal to get these messages before we have + * had time to register the window in our lookup table, or + * when the window is being destroyed and we already have + * removed it. Repost the same message to our queue so that + * we will get it later when we are prepared. + */ + PostMessage (xevent->hwnd, xevent->message, + xevent->wParam, xevent->lParam); + } + return FALSE; + } + + if (!GDK_DRAWABLE_DESTROYED (window)) + { + /* Check for filters for this window */ + GdkFilterReturn result; + result = gdk_event_apply_filters + (xevent, event, WINDOW_PRIVATE(window)->filters); + + if (result != GDK_FILTER_CONTINUE) + { + return (result == GDK_FILTER_TRANSLATE) ? TRUE : FALSE; + } + } + + if (xevent->message == gdk_selection_notify_msg) + { + GDK_NOTE (SELECTION, g_print ("gdk_selection_notify_msg: %#x\n", + xevent->hwnd)); + + event->selection.type = GDK_SELECTION_NOTIFY; + event->selection.window = window; + event->selection.selection = xevent->wParam; + event->selection.target = xevent->lParam; + event->selection.property = gdk_selection_property; + event->selection.time = xevent->time; + + return_val = !GDK_DRAWABLE_DESTROYED (window); + + /* Will pass through switch below without match */ + } + else if (xevent->message == gdk_selection_request_msg) + { + GDK_NOTE (SELECTION, g_print ("gdk_selection_request_msg: %#x\n", + xevent->hwnd)); + + event->selection.type = GDK_SELECTION_REQUEST; + event->selection.window = window; + event->selection.selection = gdk_clipboard_atom; + event->selection.target = GDK_TARGET_STRING; + event->selection.property = gdk_selection_property; + event->selection.requestor = (guint32) xevent->hwnd; + event->selection.time = xevent->time; + + return_val = !GDK_DRAWABLE_DESTROYED (window); + + /* Again, will pass through switch below without match */ + } + else if (xevent->message == gdk_selection_clear_msg) + { + GDK_NOTE (SELECTION, g_print ("gdk_selection_clear_msg: %#x\n", + xevent->hwnd)); + + event->selection.type = GDK_SELECTION_CLEAR; + event->selection.window = window; + event->selection.selection = xevent->wParam; + event->selection.time = xevent->time; + + return_val = GDK_DRAWABLE_DESTROYED (window); + + /* Once again, we will pass through switch below without match */ + } + else + { + GList *tmp_list; + GdkFilterReturn result = GDK_FILTER_CONTINUE; + + tmp_list = client_filters; + while (tmp_list) + { + GdkClientFilter *filter = tmp_list->data; + if (filter->type == xevent->message) + { + GDK_NOTE (EVENTS, g_print ("client filter matched\n")); + result = (*filter->function) (xevent, event, filter->data); + switch (result) + { + case GDK_FILTER_REMOVE: + return_val = FALSE; + break; + + case GDK_FILTER_TRANSLATE: + return_val = TRUE; + break; + + case GDK_FILTER_CONTINUE: + return_val = TRUE; + event->client.type = GDK_CLIENT_EVENT; + event->client.window = window; + event->client.message_type = xevent->message; + event->client.data_format = 0; + event->client.data.l[0] = xevent->wParam; + event->client.data.l[1] = xevent->lParam; + break; + } + goto bypass_switch; /* Ouch */ + } + tmp_list = tmp_list->next; + } + } + + switch (xevent->message) + { + case WM_INPUTLANGCHANGE: + GDK_NOTE (EVENTS, + g_print ("WM_INPUTLANGCHANGE: %#x charset %d locale %x\n", + xevent->hwnd, xevent->wParam, xevent->lParam)); + WINDOW_PRIVATE(window)->input_locale = (HKL) xevent->lParam; + TranslateCharsetInfo ((DWORD FAR *) xevent->wParam, + &WINDOW_PRIVATE(window)->charset_info, + TCI_SRCCHARSET); + break; + + case WM_SYSKEYUP: + case WM_SYSKEYDOWN: + GDK_NOTE (EVENTS, + g_print ("WM_SYSKEY%s: %#x key: %s %#x %#.08x\n", + (xevent->message == WM_SYSKEYUP ? "UP" : "DOWN"), + xevent->hwnd, + (GetKeyNameText (xevent->lParam, buf, + sizeof (buf)) > 0 ? + buf : ""), + xevent->wParam, + xevent->lParam)); + + /* Let the system handle Alt-Tab and Alt-Enter */ + if (xevent->wParam == VK_TAB + || xevent->wParam == VK_RETURN + || xevent->wParam == VK_F4) + break; + /* If posted without us having keyboard focus, ignore */ + if (!(xevent->lParam & 0x20000000)) + break; +#if 0 + /* don't generate events for just the Alt key */ + if (xevent->wParam == VK_MENU) + break; +#endif + /* Jump to code in common with WM_KEYUP and WM_KEYDOWN */ + goto keyup_or_down; + + case WM_KEYUP: + case WM_KEYDOWN: + GDK_NOTE (EVENTS, + g_print ("WM_KEY%s: %#x key: %s %#x %#.08x\n", + (xevent->message == WM_KEYUP ? "UP" : "DOWN"), + xevent->hwnd, + (GetKeyNameText (xevent->lParam, buf, + sizeof (buf)) > 0 ? + buf : ""), + xevent->wParam, + xevent->lParam)); + + ignore_WM_CHAR = TRUE; + keyup_or_down: + +#ifdef NEW_PROPAGATION_CODE + if (!propagate (&window, xevent, + k_grab_window, k_grab_owner_events, GDK_ALL_EVENTS_MASK, + doesnt_want_key)) + break; + event->key.window = window; +#else + if (k_grab_window != NULL && !k_grab_owner_events) + { + /* Keyboard is grabbed with owner_events FALSE */ + GDK_NOTE (EVENTS, g_print ("...grabbed, owner_events FALSE, " + "sending to %#x\n", + GDK_DRAWABLE_XID (k_grab_window))); + event->key.window = k_grab_window; + /* Continue with switch statement below */ + } + else if (((xevent->message == WM_KEYUP + || xevent->message == WM_SYSKEYUP) + && !(WINDOW_PRIVATE(window)->event_mask & GDK_KEY_RELEASE_MASK)) + || ((xevent->message == WM_KEYDOWN + || xevent->message == WM_SYSKEYDOWN) + && !(WINDOW_PRIVATE(window)->event_mask & GDK_KEY_PRESS_MASK))) + { + /* Owner doesn't want it, propagate to parent. */ + if (WINDOW_PRIVATE(window)->parent == (GdkWindow *) gdk_root_parent) + { + /* No parent; check if grabbed */ + if (k_grab_window != NULL) + { + /* Keyboard is grabbed with owner_events TRUE */ + GDK_NOTE (EVENTS, g_print ("...undelivered, but grabbed\n")); + event->key.window = k_grab_window; + /* Continue with switch statement below */ + } + else + break; + } + else + { + window = key_propagate (window, xevent); + /* Jump back up */ + goto keyup_or_down; + } + } + else + event->key.window = window; + + g_assert (event->key.window == window); +#endif + switch (xevent->wParam) + { + case VK_LBUTTON: + event->key.keyval = GDK_Pointer_Button1; break; + case VK_RBUTTON: + event->key.keyval = GDK_Pointer_Button3; break; + case VK_MBUTTON: + event->key.keyval = GDK_Pointer_Button2; break; + case VK_CANCEL: + event->key.keyval = GDK_Cancel; break; + case VK_BACK: + event->key.keyval = GDK_BackSpace; break; + case VK_TAB: + event->key.keyval = (GetKeyState(VK_SHIFT) < 0 ? + GDK_ISO_Left_Tab : GDK_Tab); + break; + case VK_CLEAR: + event->key.keyval = GDK_Clear; break; + case VK_RETURN: + event->key.keyval = GDK_Return; break; + case VK_SHIFT: + event->key.keyval = GDK_Shift_L; break; + case VK_CONTROL: + if (xevent->lParam & 0x01000000) + event->key.keyval = GDK_Control_R; + else + event->key.keyval = GDK_Control_L; + break; + case VK_MENU: + if (xevent->lParam & 0x01000000) + { + /* AltGr key comes in as Control+Right Alt */ + if (GetKeyState (VK_CONTROL) < 0) + { + ignore_WM_CHAR = FALSE; + is_AltGr_key = TRUE; + } + event->key.keyval = GDK_Alt_R; + } + else + event->key.keyval = GDK_Alt_L; + break; + case VK_PAUSE: + event->key.keyval = GDK_Pause; break; + case VK_CAPITAL: + event->key.keyval = GDK_Caps_Lock; break; + case VK_ESCAPE: + event->key.keyval = GDK_Escape; break; + case VK_PRIOR: + event->key.keyval = GDK_Prior; break; + case VK_NEXT: + event->key.keyval = GDK_Next; break; + case VK_END: + event->key.keyval = GDK_End; break; + case VK_HOME: + event->key.keyval = GDK_Home; break; + case VK_LEFT: + event->key.keyval = GDK_Left; break; + case VK_UP: + event->key.keyval = GDK_Up; break; + case VK_RIGHT: + event->key.keyval = GDK_Right; break; + case VK_DOWN: + event->key.keyval = GDK_Down; break; + case VK_SELECT: + event->key.keyval = GDK_Select; break; + case VK_PRINT: + event->key.keyval = GDK_Print; break; + case VK_EXECUTE: + event->key.keyval = GDK_Execute; break; + case VK_INSERT: + event->key.keyval = GDK_Insert; break; + case VK_DELETE: + event->key.keyval = GDK_Delete; break; + case VK_HELP: + event->key.keyval = GDK_Help; break; + case VK_NUMPAD0: + case VK_NUMPAD1: + case VK_NUMPAD2: + case VK_NUMPAD3: + case VK_NUMPAD4: + case VK_NUMPAD5: + case VK_NUMPAD6: + case VK_NUMPAD7: + case VK_NUMPAD8: + case VK_NUMPAD9: + /* Apparently applications work better if we just pass numpad digits + * on as real digits? So wait for the WM_CHAR instead. + */ + ignore_WM_CHAR = FALSE; + break; + case VK_MULTIPLY: + event->key.keyval = GDK_KP_Multiply; break; + case VK_ADD: + /* Pass it on as an ASCII plus in WM_CHAR. */ + ignore_WM_CHAR = FALSE; + break; + case VK_SEPARATOR: + event->key.keyval = GDK_KP_Separator; break; + case VK_SUBTRACT: + /* Pass it on as an ASCII minus in WM_CHAR. */ + ignore_WM_CHAR = FALSE; + break; + case VK_DECIMAL: + /* The keypad decimal key should also be passed on as the decimal + * sign ('.' or ',' depending on the Windows locale settings, + * apparently). So wait for the WM_CHAR here, also. + */ + ignore_WM_CHAR = FALSE; + break; + case VK_DIVIDE: + event->key.keyval = GDK_KP_Divide; break; + case VK_F1: + event->key.keyval = GDK_F1; break; + case VK_F2: + event->key.keyval = GDK_F2; break; + case VK_F3: + event->key.keyval = GDK_F3; break; + case VK_F4: + event->key.keyval = GDK_F4; break; + case VK_F5: + event->key.keyval = GDK_F5; break; + case VK_F6: + event->key.keyval = GDK_F6; break; + case VK_F7: + event->key.keyval = GDK_F7; break; + case VK_F8: + event->key.keyval = GDK_F8; break; + case VK_F9: + event->key.keyval = GDK_F9; break; + case VK_F10: + event->key.keyval = GDK_F10; break; + case VK_F11: + event->key.keyval = GDK_F11; break; + case VK_F12: + event->key.keyval = GDK_F12; break; + case VK_F13: + event->key.keyval = GDK_F13; break; + case VK_F14: + event->key.keyval = GDK_F14; break; + case VK_F15: + event->key.keyval = GDK_F15; break; + case VK_F16: + event->key.keyval = GDK_F16; break; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + if (!is_AltGr_key && (GetKeyState (VK_CONTROL) < 0 + || GetKeyState (VK_MENU) < 0)) + /* Control- or Alt-digits won't come in as a WM_CHAR, + * but beware of AltGr-digits, which are used for instance + * on Finnish keyboards. + */ + event->key.keyval = GDK_0 + (xevent->wParam - '0'); + else + ignore_WM_CHAR = FALSE; + break; + case VK_OEM_PLUS: /* On my Win98, the '+' key comes in + * as VK_OEM_PLUS + */ + if (!is_AltGr_key && (GetKeyState (VK_CONTROL) < 0 + || GetKeyState (VK_MENU) < 0)) + /* Control- or Alt-plus won't come in as WM_CHAR, + * but beware of AltGr-plus which is backslash on + * Finnish keyboards + */ + event->key.keyval = '+'; + else + ignore_WM_CHAR = FALSE; + break; + default: + if (xevent->message == WM_SYSKEYDOWN || xevent->message == WM_SYSKEYUP) + event->key.keyval = xevent->wParam; + else + ignore_WM_CHAR = FALSE; + break; + } + + if (!ignore_WM_CHAR) + break; + + is_AltGr_key = FALSE; + event->key.type = ((xevent->message == WM_KEYDOWN + || xevent->message == WM_SYSKEYDOWN) ? + GDK_KEY_PRESS : GDK_KEY_RELEASE); + event->key.time = xevent->time; + event->key.state = 0; + if (GetKeyState (VK_SHIFT) < 0) + event->key.state |= GDK_SHIFT_MASK; + if (GetKeyState (VK_CAPITAL) & 0x1) + event->key.state |= GDK_LOCK_MASK; + if (GetKeyState (VK_CONTROL) < 0) + event->key.state |= GDK_CONTROL_MASK; + if (xevent->wParam != VK_MENU && GetKeyState (VK_MENU) < 0) + event->key.state |= GDK_MOD1_MASK; + event->key.string = NULL; + event->key.length = 0; + return_val = !GDK_DRAWABLE_DESTROYED (window); + break; + + case WM_IME_COMPOSITION: + if (!use_IME_COMPOSITION) + break; + GDK_NOTE (EVENTS, g_print ("WM_IME_COMPOSITION: %#x %#x\n", + xevent->hwnd, xevent->lParam)); + if (xevent->lParam & GCS_RESULTSTR) + goto wm_char; + break; + + case WM_IME_CHAR: + GDK_NOTE (EVENTS, + g_print ("WM_IME_CHAR: %#x bytes: %#.04x\n", + xevent->hwnd, xevent->wParam)); + goto wm_char; + + case WM_CHAR: + GDK_NOTE (EVENTS, + g_print ("WM_CHAR: %#x char: %#x %#.08x %s\n", + xevent->hwnd, xevent->wParam, xevent->lParam, + (ignore_WM_CHAR ? "ignored" : ""))); + + if (ignore_WM_CHAR) + { + ignore_WM_CHAR = FALSE; + break; + } + + wm_char: +#ifdef NEW_PROPAGATION_CODE + if (!propagate (&window, xevent, + k_grab_window, k_grab_owner_events, GDK_ALL_EVENTS_MASK, + doesnt_want_char)) + break; + event->key.window = window; +#else + /* This doesn't handle the rather theorethical case that a window + * wants key presses but still wants releases to be propagated, + * for instance. Or is that so theorethical? + */ + if (k_grab_window != NULL && !k_grab_owner_events) + { + /* Keyboard is grabbed with owner_events FALSE */ + GDK_NOTE (EVENTS, + g_print ("...grabbed, owner_events FALSE, " + "sending to %#x\n", + GDK_DRAWABLE_XID (k_grab_window))); + event->key.window = k_grab_window; + } + else if (!(WINDOW_PRIVATE(window)->event_mask & (GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK))) + { + /* Owner doesn't want it, propagate to parent. */ + if (WINDOW_PRIVATE(window)->parent == (GdkWindow *) gdk_root_parent) + { + /* No parent; check if grabbed */ + if (k_grab_window != NULL) + { + GDK_NOTE (EVENTS, g_print ("...undelivered, but grabbed\n")); + event->key.window = k_grab_window; + } + else + break; + } + else + { + window = key_propagate (window, xevent); + /* Jump back up */ + goto wm_char; + } + } + else + event->key.window = window; + + g_assert (event->key.window == window); +#endif + return_val = !GDK_DRAWABLE_DESTROYED (window); + if (return_val && (event->key.window == k_grab_window + || (WINDOW_PRIVATE(window)->event_mask & GDK_KEY_RELEASE_MASK))) + { + if (window == k_grab_window + || (WINDOW_PRIVATE(window)->event_mask & GDK_KEY_PRESS_MASK)) + { + /* Append a GDK_KEY_PRESS event to the pushback list + * (from which it will be fetched before the release + * event). + */ + GdkEvent *event2 = gdk_event_new (); + build_keypress_event (WINDOW_PRIVATE(window), event2, xevent); + event2->key.window = window; + gdk_window_ref (window); + gdk_event_queue_append (event2); + GDK_NOTE (EVENTS, print_event (event2)); + } + /* Return the key release event. */ + build_keyrelease_event (WINDOW_PRIVATE(window), event, xevent); + } + else if (return_val + && (WINDOW_PRIVATE(window)->event_mask & GDK_KEY_PRESS_MASK)) + { + /* Return just the key press event. */ + build_keypress_event (WINDOW_PRIVATE(window), event, xevent); + } + else + return_val = FALSE; + +#if 0 /* Don't reset is_AltGr_key here. Othewise we can't type several + * AltGr-accessed chars while keeping the AltGr pressed down + * all the time. + */ + is_AltGr_key = FALSE; +#endif + break; + + case WM_LBUTTONDOWN: + button = 1; + goto buttondown0; + case WM_MBUTTONDOWN: + button = 2; + goto buttondown0; + case WM_RBUTTONDOWN: + button = 3; + + buttondown0: + GDK_NOTE (EVENTS, + g_print ("WM_%cBUTTONDOWN: %#x (%d,%d)\n", + " LMR"[button], + xevent->hwnd, + LOWORD (xevent->lParam), HIWORD (xevent->lParam))); + + if (WINDOW_PRIVATE(window)->extension_events != 0 + && gdk_input_ignore_core) + { + GDK_NOTE (EVENTS, g_print ("...ignored\n")); + break; + } + + if (window != curWnd) + synthesize_crossing_events (window, xevent); + + event->button.type = GDK_BUTTON_PRESS; +#ifdef NEW_PROPAGATION_CODE + if (!propagate (&window, xevent, + p_grab_window, p_grab_owner_events, p_grab_mask, + doesnt_want_button_press)) + break; + event->button.window = window; +#else + buttondown: + mask = WINDOW_PRIVATE(window)->event_mask; + + if (p_grab_window != NULL && !p_grab_owner_events) + { + /* Pointer is grabbed with owner_events FALSE */ + GDK_NOTE (EVENTS, g_print ("...grabbed, owner_events FALSE\n")); + + mask = p_grab_mask; + if (!(mask & GDK_BUTTON_PRESS_MASK)) + /* Grabber doesn't want it */ + break; + else + event->button.window = p_grab_window; + GDK_NOTE (EVENTS, g_print ("...sending to %#x\n", + GDK_DRAWABLE_XID (p_grab_window))); + } + else if (!(mask & GDK_BUTTON_PRESS_MASK)) + { + /* Owner doesn't want it, propagate to parent. */ + if (WINDOW_PRIVATE(window)->parent == (GdkWindow *) gdk_root_parent) + { + /* No parent; check if grabbed */ + if (p_grab_window != NULL) + { + /* Pointer is grabbed wíth owner_events TRUE */ + GDK_NOTE (EVENTS, g_print ("...undelivered, but grabbed\n")); + mask = p_grab_mask; + if (!(mask & GDK_BUTTON_PRESS_MASK)) + { + /* Grabber doesn't want it either */ + GDK_NOTE (EVENTS, g_print ("...grabber uninterested\n")); + break; + } + else + event->button.window = p_grab_window; + GDK_NOTE (EVENTS, g_print ("...sending to %#x\n", + GDK_DRAWABLE_XID (p_grab_window))); + } + else + break; + } + else + { + window = pointer_propagate (window, xevent); + /* Jump back up */ + goto buttondown; /* What did Dijkstra say? */ + } + } + else + event->button.window = window; + + g_assert (event->button.window == window); +#endif + /* Emulate X11's automatic active grab */ + if (!p_grab_window) + { + /* No explicit active grab, let's start one automatically */ + gint owner_events = + WINDOW_PRIVATE(window)->event_mask + & (GDK_BUTTON_PRESS_MASK|GDK_BUTTON_RELEASE_MASK); + + GDK_NOTE (EVENTS, g_print ("...automatic grab started\n")); + gdk_pointer_grab (window, + owner_events, + WINDOW_PRIVATE(window)->event_mask, + NULL, NULL, 0); + p_grab_automatic = TRUE; + } + + event->button.time = xevent->time; + if (window != orig_window) + translate_mouse_coords (orig_window, window, xevent); + event->button.x = curX = LOWORD (xevent->lParam); + event->button.y = curY = HIWORD (xevent->lParam); + event->button.x_root = xevent->pt.x; + event->button.y_root = xevent->pt.y; + event->button.pressure = 0.5; + event->button.xtilt = 0; + event->button.ytilt = 0; + event->button.state = build_pointer_event_state (xevent); + event->button.button = button; + event->button.source = GDK_SOURCE_MOUSE; + event->button.deviceid = GDK_CORE_POINTER; + + if ((event->button.time < (button_click_time[1] + TRIPLE_CLICK_TIME)) && + (event->button.window == button_window[1]) && + (event->button.button == button_number[1])) + { + gdk_synthesize_click (event, 3); + + button_click_time[1] = 0; + button_click_time[0] = 0; + button_window[1] = NULL; + button_window[0] = 0; + button_number[1] = -1; + button_number[0] = -1; + } + else if ((event->button.time < (button_click_time[0] + DOUBLE_CLICK_TIME)) && + (event->button.window == button_window[0]) && + (event->button.button == button_number[0])) + { + gdk_synthesize_click (event, 2); + + button_click_time[1] = button_click_time[0]; + button_click_time[0] = event->button.time; + button_window[1] = button_window[0]; + button_window[0] = event->button.window; + button_number[1] = button_number[0]; + button_number[0] = event->button.button; + } + else + { + button_click_time[1] = 0; + button_click_time[0] = event->button.time; + button_window[1] = NULL; + button_window[0] = event->button.window; + button_number[1] = -1; + button_number[0] = event->button.button; + } + return_val = !GDK_DRAWABLE_DESTROYED (window); + break; + + case WM_LBUTTONUP: + button = 1; + goto buttonup0; + case WM_MBUTTONUP: + button = 2; + goto buttonup0; + case WM_RBUTTONUP: + button = 3; + + buttonup0: + GDK_NOTE (EVENTS, + g_print ("WM_%cBUTTONUP: %#x (%d,%d)\n", + " LMR"[button], + xevent->hwnd, + LOWORD (xevent->lParam), HIWORD (xevent->lParam))); + + if (WINDOW_PRIVATE(window)->extension_events != 0 + && gdk_input_ignore_core) + { + GDK_NOTE (EVENTS, g_print ("...ignored\n")); + break; + } + + if (window != curWnd) + synthesize_crossing_events (window, xevent); + + event->button.type = GDK_BUTTON_RELEASE; +#ifdef NEW_PROPAGATION_CODE + if (!propagate (&window, xevent, + p_grab_window, p_grab_owner_events, p_grab_mask, + doesnt_want_button_release)) + goto maybe_ungrab; + event->button.window = window; +#else + buttonup: + mask = WINDOW_PRIVATE(window)->event_mask; + + if (p_grab_window != NULL && !p_grab_owner_events) + { + /* Pointer is grabbed with owner_events FALSE */ + GDK_NOTE (EVENTS, g_print ("...grabbed, owner_events FALSE\n")); + + mask = p_grab_mask; + if (!(mask & GDK_BUTTON_RELEASE_MASK)) + /* Grabber doesn't want it */ + goto maybe_ungrab; + else + event->button.window = p_grab_window; + GDK_NOTE (EVENTS, g_print ("...sending to %#x\n", + GDK_DRAWABLE_XID (p_grab_window))); + } + else if (!(mask & GDK_BUTTON_RELEASE_MASK)) + { + /* Owner doesn't want it, propagate to parent. */ + if (WINDOW_PRIVATE(window)->parent == (GdkWindow *) gdk_root_parent) + { + /* No parent; check if grabbed */ + if (p_grab_window != NULL) + { + /* Pointer is grabbed wíth owner_events TRUE */ + GDK_NOTE (EVENTS, g_print ("...undelivered, but grabbed\n")); + mask = p_grab_mask; + if (!(mask & GDK_BUTTON_RELEASE_MASK)) + { + /* Grabber doesn't want it either */ + GDK_NOTE (EVENTS, g_print ("...grabber uninterested\n")); + goto maybe_ungrab; + } + else + event->button.window = p_grab_window; + GDK_NOTE (EVENTS, + g_print ("...sending to %#x\n", + GDK_DRAWABLE_XID (p_grab_window))); + } + else + break; + } + else + { + window = pointer_propagate (window, xevent); + /* Jump back up */ + goto buttonup; + } + } + else + event->button.window = window; + + g_assert (event->button.window == window); +#endif + event->button.time = xevent->time; + if (window != orig_window) + translate_mouse_coords (orig_window, window, xevent); + event->button.x = LOWORD (xevent->lParam); + event->button.y = HIWORD (xevent->lParam); + event->button.x_root = xevent->pt.x; + event->button.y_root = xevent->pt.y; + event->button.pressure = 0.5; + event->button.xtilt = 0; + event->button.ytilt = 0; + event->button.state = build_pointer_event_state (xevent); + event->button.button = button; + event->button.source = GDK_SOURCE_MOUSE; + event->button.deviceid = GDK_CORE_POINTER; + + return_val = !GDK_DRAWABLE_DESTROYED (window); + + maybe_ungrab: + if (p_grab_window != NULL + && p_grab_automatic + && (event->button.state & (GDK_BUTTON1_MASK | GDK_BUTTON2_MASK | GDK_BUTTON3_MASK)) == 0) + gdk_pointer_ungrab (0); + break; + + case WM_MOUSEMOVE: + GDK_NOTE (EVENTS, + g_print ("WM_MOUSEMOVE: %#x %#x (%d,%d)\n", + xevent->hwnd, xevent->wParam, + LOWORD (xevent->lParam), HIWORD (xevent->lParam))); + + /* If we haven't moved, don't create any event. + * Windows sends WM_MOUSEMOVE messages after button presses + * even if the mouse doesn't move. This disturbs gtk. + */ + if (window == curWnd + && LOWORD (xevent->lParam) == curX + && HIWORD (xevent->lParam) == curY) + break; + + /* HB: only process mouse move messages if we own the active window. */ + GetWindowThreadProcessId(GetActiveWindow(), &pidActWin); + GetWindowThreadProcessId(xevent->hwnd, &pidThis); + if (pidActWin != pidThis) + break; + + if (window != curWnd) + synthesize_crossing_events (window, xevent); + + if (WINDOW_PRIVATE(window)->extension_events != 0 + && gdk_input_ignore_core) + { + GDK_NOTE (EVENTS, g_print ("...ignored\n")); + break; + } + + event->motion.type = GDK_MOTION_NOTIFY; +#ifdef NEW_PROPAGATION_CODE + if (!propagate (&window, xevent, + p_grab_window, p_grab_owner_events, p_grab_mask, + doesnt_want_button_motion)) + break; + event->motion.window = window; +#else + mousemotion: + mask = WINDOW_PRIVATE(window)->event_mask; + + if (p_grab_window != NULL && !p_grab_owner_events) + { + /* Pointer is grabbed with owner_events FALSE */ + GDK_NOTE (EVENTS, g_print ("...grabbed, owner_events FALSE\n")); + + mask = p_grab_mask; + if (!((mask & GDK_POINTER_MOTION_MASK) + || ((xevent->wParam & (MK_LBUTTON|MK_MBUTTON|MK_RBUTTON)) + && (mask & GDK_BUTTON_MOTION_MASK)) + || ((xevent->wParam & MK_LBUTTON) + && (mask & GDK_BUTTON1_MOTION_MASK)) + || ((xevent->wParam & MK_MBUTTON) + && (mask & GDK_BUTTON2_MOTION_MASK)) + || ((xevent->wParam & MK_RBUTTON) + && (mask & GDK_BUTTON3_MOTION_MASK)))) + /* Grabber doesn't want it */ + break; + else + event->motion.window = p_grab_window; + GDK_NOTE (EVENTS, g_print ("...sending to %#x\n", + GDK_DRAWABLE_XID (p_grab_window))); + } + else if (!((mask & GDK_POINTER_MOTION_MASK) + || ((xevent->wParam & (MK_LBUTTON|MK_MBUTTON|MK_RBUTTON)) + && (mask & GDK_BUTTON_MOTION_MASK)) + || ((xevent->wParam & MK_LBUTTON) + && (mask & GDK_BUTTON1_MOTION_MASK)) + || ((xevent->wParam & MK_MBUTTON) + && (mask & GDK_BUTTON2_MOTION_MASK)) + || ((xevent->wParam & MK_RBUTTON) + && (mask & GDK_BUTTON3_MOTION_MASK)))) + { + /* Owner doesn't want it, propagate to parent. */ + if (WINDOW_PRIVATE(window)->parent == (GdkWindow *) gdk_root_parent) + { + /* No parent; check if grabbed */ + if (p_grab_window != NULL) + { + /* Pointer is grabbed wíth owner_events TRUE */ + GDK_NOTE (EVENTS, g_print ("...undelivered, but grabbed\n")); + mask = p_grab_mask; + if (!((p_grab_mask & GDK_POINTER_MOTION_MASK) + || ((xevent->wParam & (MK_LBUTTON|MK_MBUTTON|MK_RBUTTON)) + && (mask & GDK_BUTTON_MOTION_MASK)) + || ((xevent->wParam & MK_LBUTTON) + && (mask & GDK_BUTTON1_MOTION_MASK)) + || ((xevent->wParam & MK_MBUTTON) + && (mask & GDK_BUTTON2_MOTION_MASK)) + || ((xevent->wParam & MK_RBUTTON) + && (mask & GDK_BUTTON3_MOTION_MASK)))) + { + /* Grabber doesn't want it either */ + GDK_NOTE (EVENTS, g_print ("...grabber uninterested\n")); + break; + } + else + event->motion.window = p_grab_window; + GDK_NOTE (EVENTS, + g_print ("...sending to %#x\n", + GDK_DRAWABLE_XID (p_grab_window))); + } + else + break; + } + else + { + window = pointer_propagate (window, xevent); + /* Jump back up */ + goto mousemotion; + } + } + else + event->motion.window = window; +#endif + event->motion.time = xevent->time; + if (window != orig_window) + translate_mouse_coords (orig_window, window, xevent); + event->motion.x = curX = LOWORD (xevent->lParam); + event->motion.y = curY = HIWORD (xevent->lParam); + event->motion.x_root = xevent->pt.x; + event->motion.y_root = xevent->pt.y; + curXroot = event->motion.x_root; + curYroot = event->motion.y_root; + event->motion.pressure = 0.5; + event->motion.xtilt = 0; + event->motion.ytilt = 0; + event->motion.state = build_pointer_event_state (xevent); + event->motion.is_hint = FALSE; + event->motion.source = GDK_SOURCE_MOUSE; + event->motion.deviceid = GDK_CORE_POINTER; + + return_val = !GDK_DRAWABLE_DESTROYED (window); + break; + + case WM_NCMOUSEMOVE: + GDK_NOTE (EVENTS, + g_print ("WM_NCMOUSEMOVE: %#x x,y: %d %d\n", + xevent->hwnd, + LOWORD (xevent->lParam), HIWORD (xevent->lParam))); + if (p_TrackMouseEvent == NULL + && curWnd != NULL + && (WINDOW_PRIVATE(curWnd)->event_mask & GDK_LEAVE_NOTIFY_MASK)) + { + GDK_NOTE (EVENTS, g_print ("...synthesizing LEAVE_NOTIFY event\n")); + + event->crossing.type = GDK_LEAVE_NOTIFY; + event->crossing.window = curWnd; + event->crossing.subwindow = NULL; + event->crossing.time = xevent->time; + event->crossing.x = curX; + event->crossing.y = curY; + event->crossing.x_root = curXroot; + event->crossing.y_root = curYroot; + event->crossing.mode = GDK_CROSSING_NORMAL; + event->crossing.detail = GDK_NOTIFY_NONLINEAR; + + event->crossing.focus = TRUE; /* ??? */ + event->crossing.state = 0; /* ??? */ + return_val = TRUE; + } + + if (curWnd) + { + gdk_window_unref (curWnd); + curWnd = NULL; + } + + break; + +#ifdef USE_TRACKMOUSEEVENT + case WM_MOUSELEAVE: + GDK_NOTE (EVENTS, g_print ("WM_MOUSELEAVE: %#x\n", xevent->hwnd)); + + if (!(WINDOW_PRIVATE(window)->event_mask & GDK_LEAVE_NOTIFY_MASK)) + break; + + event->crossing.type = GDK_LEAVE_NOTIFY; + event->crossing.window = window; + event->crossing.subwindow = NULL; + event->crossing.time = xevent->time; + event->crossing.x = curX; + event->crossing.y = curY; + event->crossing.x_root = curXroot; + event->crossing.y_root = curYroot; + event->crossing.mode = GDK_CROSSING_NORMAL; + if (curWnd + && IsChild (GDK_DRAWABLE_XID (curWnd), GDK_DRAWABLE_XID (window))) + event->crossing.detail = GDK_NOTIFY_INFERIOR; + else if (curWnd + && IsChild (GDK_DRAWABLE_XID (window), GDK_DRAWABLE_XID (curWnd))) + event->crossing.detail = GDK_NOTIFY_ANCESTOR; + else + event->crossing.detail = GDK_NOTIFY_NONLINEAR; + + event->crossing.focus = TRUE; /* ??? */ + event->crossing.state = 0; /* ??? */ + + if (curWnd) + { + gdk_window_unref (curWnd); + curWnd = NULL; + } + + return_val = !GDK_DRAWABLE_DESTROYED (window); + break; +#endif + + case WM_SETFOCUS: + case WM_KILLFOCUS: + GDK_NOTE (EVENTS, g_print ("WM_%sFOCUS: %#x\n", + (xevent->message == WM_SETFOCUS ? + "SET" : "KILL"), + xevent->hwnd)); + + if (!(WINDOW_PRIVATE(window)->event_mask & GDK_FOCUS_CHANGE_MASK)) + break; + + event->focus_change.type = GDK_FOCUS_CHANGE; + event->focus_change.window = window; + event->focus_change.in = (xevent->message == WM_SETFOCUS); + return_val = !GDK_DRAWABLE_DESTROYED (window); + break; + + case WM_ERASEBKGND: + GDK_NOTE (EVENTS, g_print ("WM_ERASEBKGND: %#x dc %#x\n", + xevent->hwnd, xevent->wParam)); + + if (GDK_DRAWABLE_DESTROYED (window)) + break; + + colormap_private = (GdkColormapPrivate *) WINDOW_PRIVATE(window)->drawable.colormap; + hdc = (HDC) xevent->wParam; + if (colormap_private + && colormap_private->xcolormap->rc_palette) + { + int k; + + if (SelectPalette (hdc, colormap_private->xcolormap->palette, + FALSE) == NULL) + g_warning ("WM_ERASEBKGND: SelectPalette failed"); + if ((k = RealizePalette (hdc)) == GDI_ERROR) + g_warning ("WM_ERASEBKGND: RealizePalette failed"); +#if 0 + g_print ("WM_ERASEBKGND: selected %#x, realized %d colors\n", + colormap_private->xcolormap->palette, k); +#endif + } + *ret_val_flagp = TRUE; + *ret_valp = 1; + + if (WINDOW_PRIVATE(window)->bg_type == GDK_WIN32_BG_TRANSPARENT) + break; + + if (WINDOW_PRIVATE(window)->bg_type == GDK_WIN32_BG_PARENT_RELATIVE) + { + /* If this window should have the same background as the + * parent, fetch the parent. (And if the same goes for + * the parent, fetch the grandparent, etc.) + */ + while (window + && WINDOW_PRIVATE(window)->bg_type == GDK_WIN32_BG_PARENT_RELATIVE) + { + gdk_window_unref (window); + window = WINDOW_PRIVATE(window)->parent; + gdk_window_ref (window); + } + } + + if (WINDOW_PRIVATE(window)->bg_type == GDK_WIN32_BG_PIXEL) + { + COLORREF bg; + GetClipBox (hdc, &rect); + GDK_NOTE (EVENTS, + g_print ("...%dx%d@+%d+%d BG_PIXEL %s\n", + rect.right - rect.left, + rect.bottom - rect.top, + rect.left, rect.top, + gdk_color_to_string (&WINDOW_PRIVATE(window)->bg_pixel))); + bg = GetNearestColor + (hdc, RGB (WINDOW_PRIVATE(window)->bg_pixel.red >> 8, + WINDOW_PRIVATE(window)->bg_pixel.green >> 8, + WINDOW_PRIVATE(window)->bg_pixel.blue >> 8)); + hbr = CreateSolidBrush (bg); +#if 0 + g_print ("...CreateSolidBrush (%.08x) = %.08x\n", bg, hbr); +#endif + if (!FillRect (hdc, &rect, hbr)) + g_warning ("WM_ERASEBKGND: FillRect failed"); + DeleteObject (hbr); + } + else if (WINDOW_PRIVATE(window)->bg_type == GDK_WIN32_BG_PIXMAP) + { + pixmap_private = + (GdkDrawablePrivate*) WINDOW_PRIVATE(window)->bg_pixmap; + GetClipBox (hdc, &rect); + + if (pixmap_private->width <= 8 + && pixmap_private->height <= 8) + { + GDK_NOTE (EVENTS, g_print ("...small pixmap, using brush\n")); + hbr = CreatePatternBrush (pixmap_private->xwindow); + if (!FillRect (hdc, &rect, hbr)) + g_warning ("WM_ERASEBKGND: FillRect failed"); + DeleteObject (hbr); + } + else + { + GDK_NOTE (EVENTS, + g_print ("...blitting pixmap %#x (%dx%d) " + "all over the place,\n" + "...clip box = %dx%d@+%d+%d\n", + pixmap_private->xwindow, + pixmap_private->width, pixmap_private->height, + rect.right - rect.left, rect.bottom - rect.top, + rect.left, rect.top)); + + if (!(bgdc = CreateCompatibleDC (hdc))) + { + g_warning ("WM_ERASEBKGND: CreateCompatibleDC failed"); + break; + } + if (!(oldbitmap = SelectObject (bgdc, pixmap_private->xwindow))) + { + g_warning ("WM_ERASEBKGND: SelectObject failed"); + DeleteDC (bgdc); + break; + } + i = 0; + while (i < rect.right) + { + j = 0; + while (j < rect.bottom) + { + if (i + pixmap_private->width >= rect.left + && j + pixmap_private->height >= rect.top) + { + if (!BitBlt (hdc, i, j, + pixmap_private->width, pixmap_private->height, + bgdc, 0, 0, SRCCOPY)) + { + g_warning ("WM_ERASEBKGND: BitBlt failed"); + goto loopexit; + } + } + j += pixmap_private->height; + } + i += pixmap_private->width; + } + loopexit: + SelectObject (bgdc, oldbitmap); + DeleteDC (bgdc); + } + } + else + { + GDK_NOTE (EVENTS, g_print ("...BLACK_BRUSH (?)\n")); + hbr = GetStockObject (BLACK_BRUSH); + GetClipBox (hdc, &rect); + if (!FillRect (hdc, &rect, hbr)) + g_warning ("WM_ERASEBKGND: FillRect failed"); + } + break; + + case WM_PAINT: + hdc = BeginPaint (xevent->hwnd, &paintstruct); + + GDK_NOTE (EVENTS, + g_print ("WM_PAINT: %#x %dx%d@+%d+%d %s dc %#x\n", + xevent->hwnd, + paintstruct.rcPaint.right - paintstruct.rcPaint.left, + paintstruct.rcPaint.bottom - paintstruct.rcPaint.top, + paintstruct.rcPaint.left, paintstruct.rcPaint.top, + (paintstruct.fErase ? "erase" : ""), + hdc)); + + EndPaint (xevent->hwnd, &paintstruct); + + if (!(WINDOW_PRIVATE(window)->event_mask & GDK_EXPOSURE_MASK)) + break; + + event->expose.type = GDK_EXPOSE; + event->expose.window = window; + event->expose.area.x = paintstruct.rcPaint.left; + event->expose.area.y = paintstruct.rcPaint.top; + event->expose.area.width = paintstruct.rcPaint.right - paintstruct.rcPaint.left; + event->expose.area.height = paintstruct.rcPaint.bottom - paintstruct.rcPaint.top; + event->expose.count = 0; + + return_val = !GDK_DRAWABLE_DESTROYED (window); + if (return_val) + { + GList *list = queued_events; + while (list != NULL ) + { + if ((((GdkEvent *)list->data)->any.type == GDK_EXPOSE) && + (((GdkEvent *)list->data)->any.window == window) && + !(((GdkEventPrivate *)list->data)->flags & GDK_EVENT_PENDING)) + ((GdkEvent *)list->data)->expose.count++; + + list = list->next; + } + } + break; + + case WM_SETCURSOR: + GDK_NOTE (EVENTS, g_print ("WM_SETCURSOR: %#x %#x %#x\n", + xevent->hwnd, + LOWORD (xevent->lParam), HIWORD (xevent->lParam))); + + if (LOWORD (xevent->lParam) != HTCLIENT) + break; + if (p_grab_window != NULL && p_grab_cursor != NULL) + { + GDK_NOTE (EVENTS, g_print ("...SetCursor(%#x)\n", p_grab_cursor)); + SetCursor (p_grab_cursor); + } + else if (!GDK_DRAWABLE_DESTROYED (window) + && WINDOW_PRIVATE(window)->xcursor) + { + GDK_NOTE (EVENTS, g_print ("...SetCursor(%#x)\n", + WINDOW_PRIVATE(window)->xcursor)); + SetCursor (WINDOW_PRIVATE(window)->xcursor); + } + + if (window != curWnd) + synthesize_crossing_events (window, xevent); + + *ret_val_flagp = TRUE; + *ret_valp = FALSE; + break; + + case WM_SHOWWINDOW: + GDK_NOTE (EVENTS, g_print ("WM_SHOWWINDOW: %#x %d\n", + xevent->hwnd, + xevent->wParam)); + + if (!(WINDOW_PRIVATE(window)->event_mask & GDK_STRUCTURE_MASK)) + break; + + event->any.type = (xevent->wParam ? GDK_MAP : GDK_UNMAP); + event->any.window = window; + + if (event->any.type == GDK_UNMAP + && p_grab_window == window) + gdk_pointer_ungrab (xevent->time); + + if (event->any.type == GDK_UNMAP + && k_grab_window == window) + gdk_keyboard_ungrab (xevent->time); + + return_val = !GDK_DRAWABLE_DESTROYED (window); + break; + + case WM_SIZE: + GDK_NOTE (EVENTS, + g_print ("WM_SIZE: %#x %s %dx%d\n", + xevent->hwnd, + (xevent->wParam == SIZE_MAXHIDE ? "MAXHIDE" : + (xevent->wParam == SIZE_MAXIMIZED ? "MAXIMIZED" : + (xevent->wParam == SIZE_MAXSHOW ? "MAXSHOW" : + (xevent->wParam == SIZE_MINIMIZED ? "MINIMIZED" : + (xevent->wParam == SIZE_RESTORED ? "RESTORED" : "?"))))), + LOWORD (xevent->lParam), HIWORD (xevent->lParam))); + + if (!(WINDOW_PRIVATE(window)->event_mask & GDK_STRUCTURE_MASK)) + break; + + if (xevent->wParam == SIZE_MINIMIZED) + { + event->any.type = GDK_UNMAP; + event->any.window = window; + + if (p_grab_window == window) + gdk_pointer_ungrab (xevent->time); + + if (k_grab_window == window) + gdk_keyboard_ungrab (xevent->time); + + return_val = !GDK_DRAWABLE_DESTROYED (window); + } + else if ((xevent->wParam == SIZE_RESTORED + || xevent->wParam == SIZE_MAXIMIZED) +#if 1 + && GDK_DRAWABLE_TYPE (window) != GDK_WINDOW_CHILD +#endif + ) + { + if (LOWORD (xevent->lParam) == 0) + break; + + event->configure.type = GDK_CONFIGURE; + event->configure.window = window; + pt.x = 0; + pt.y = 0; + ClientToScreen (xevent->hwnd, &pt); + event->configure.x = pt.x; + event->configure.y = pt.y; + event->configure.width = LOWORD (xevent->lParam); + event->configure.height = HIWORD (xevent->lParam); + WINDOW_PRIVATE(window)->x = event->configure.x; + WINDOW_PRIVATE(window)->y = event->configure.y; + WINDOW_PRIVATE(window)->drawable.width = event->configure.width; + WINDOW_PRIVATE(window)->drawable.height = event->configure.height; + if (WINDOW_PRIVATE(window)->resize_count > 1) + WINDOW_PRIVATE(window)->resize_count -= 1; + + return_val = !GDK_DRAWABLE_DESTROYED (window); + if (return_val + && WINDOW_PRIVATE(window)->extension_events != 0 + && gdk_input_vtable.configure_event) + gdk_input_vtable.configure_event (&event->configure, window); + } + break; + + case WM_GETMINMAXINFO: + GDK_NOTE (EVENTS, g_print ("WM_GETMINMAXINFO: %#x\n", xevent->hwnd)); + + lpmmi = (MINMAXINFO*) xevent->lParam; + if (WINDOW_PRIVATE(window)->hint_flags & GDK_HINT_MIN_SIZE) + { + lpmmi->ptMinTrackSize.x = WINDOW_PRIVATE(window)->hint_min_width; + lpmmi->ptMinTrackSize.y = WINDOW_PRIVATE(window)->hint_min_height; + } + if (WINDOW_PRIVATE(window)->hint_flags & GDK_HINT_MAX_SIZE) + { + lpmmi->ptMaxTrackSize.x = WINDOW_PRIVATE(window)->hint_max_width; + lpmmi->ptMaxTrackSize.y = WINDOW_PRIVATE(window)->hint_max_height; + + lpmmi->ptMaxSize.x = WINDOW_PRIVATE(window)->hint_max_width; + lpmmi->ptMaxSize.y = WINDOW_PRIVATE(window)->hint_max_height; + } + break; + + case WM_MOVE: + GDK_NOTE (EVENTS, g_print ("WM_MOVE: %#x (%d,%d)\n", + xevent->hwnd, + LOWORD (xevent->lParam), HIWORD (xevent->lParam))); + + if (!(WINDOW_PRIVATE(window)->event_mask & GDK_STRUCTURE_MASK)) + break; + + if (GDK_DRAWABLE_TYPE (window) != GDK_WINDOW_CHILD) + { + event->configure.type = GDK_CONFIGURE; + event->configure.window = window; + event->configure.x = LOWORD (xevent->lParam); + event->configure.y = HIWORD (xevent->lParam); + GetClientRect (xevent->hwnd, &rect); + event->configure.width = rect.right; + event->configure.height = rect.bottom; + WINDOW_PRIVATE(window)->x = event->configure.x; + WINDOW_PRIVATE(window)->y = event->configure.y; + WINDOW_PRIVATE(window)->drawable.width = event->configure.width; + WINDOW_PRIVATE(window)->drawable.height = event->configure.height; + + return_val = !GDK_DRAWABLE_DESTROYED (window); + } + break; + + case WM_CLOSE: + GDK_NOTE (EVENTS, g_print ("WM_CLOSE: %#x\n", xevent->hwnd)); + + event->any.type = GDK_DELETE; + event->any.window = window; + + return_val = !GDK_DRAWABLE_DESTROYED (window); + break; + +#if 0 + /* No, don't use delayed rendering after all. It works only if the + * delayed SetClipboardData is called from the WindowProc, it + * seems. (The #else part below is test code for that. It succeeds + * in setting the clipboard data. But if I call SetClipboardData + * in gdk_property_change (as a consequence of the + * GDK_SELECTION_REQUEST event), it fails. I deduce that this is + * because delayed rendering requires that SetClipboardData is + * called in the window procedure.) + */ + case WM_RENDERFORMAT: + case WM_RENDERALLFORMATS: + flag = FALSE; + GDK_NOTE (EVENTS, flag = TRUE); + GDK_NOTE (SELECTION, flag = TRUE); + if (flag) + g_print ("WM_%s: %#x %#x (%s)\n", + (xevent->message == WM_RENDERFORMAT ? "RENDERFORMAT" : + "RENDERALLFORMATS"), + xevent->hwnd, + xevent->wParam, + (xevent->wParam == CF_TEXT ? "CF_TEXT" : + (xevent->wParam == CF_DIB ? "CF_DIB" : + (xevent->wParam == CF_UNICODETEXT ? "CF_UNICODETEXT" : + (GetClipboardFormatName (xevent->wParam, buf, sizeof (buf)), buf))))); + +#if 0 + event->selection.type = GDK_SELECTION_REQUEST; + event->selection.window = window; + event->selection.selection = gdk_clipboard_atom; + if (xevent->wParam == CF_TEXT) + event->selection.target = GDK_TARGET_STRING; + else + { + GetClipboardFormatName (xevent->wParam, buf, sizeof (buf)); + event->selection.target = gdk_atom_intern (buf, FALSE); + } + event->selection.property = gdk_selection_property; + event->selection.requestor = (guint32) xevent->hwnd; + event->selection.time = xevent->time; + return_val = !GDK_DRAWABLE_DESTROYED (window); +#else + /* Test code, to see if SetClipboardData works when called from + * the window procedure. + */ + { + HGLOBAL hdata = GlobalAlloc (GMEM_MOVEABLE|GMEM_DDESHARE, 10); + char *ptr = GlobalLock (hdata); + strcpy (ptr, "Huhhaa"); + GlobalUnlock (hdata); + if (!SetClipboardData (CF_TEXT, hdata)) + g_print ("SetClipboardData failed: %d\n", GetLastError ()); + } + *ret_valp = 0; + *ret_val_flagp = TRUE; + return_val = FALSE; +#endif + break; +#endif /* No delayed rendering */ + + case WM_DESTROY: + GDK_NOTE (EVENTS, g_print ("WM_DESTROY: %#x\n", xevent->hwnd)); + + event->any.type = GDK_DESTROY; + event->any.window = window; + if (window != NULL && window == curWnd) + { + gdk_window_unref (curWnd); + curWnd = NULL; + } + + if (p_grab_window == window) + gdk_pointer_ungrab (xevent->time); + + if (k_grab_window == window) + gdk_keyboard_ungrab (xevent->time); + + return_val = !GDK_DRAWABLE_DESTROYED (window); + break; + +#ifdef HAVE_WINTAB + /* Handle WINTAB events here, as we know that gdkinput.c will + * use the fixed WT_DEFBASE as lcMsgBase, and we thus can use the + * constants as case labels. + */ + case WT_PACKET: + GDK_NOTE (EVENTS, g_print ("WT_PACKET: %d %#x\n", + xevent->wParam, xevent->lParam)); + goto wintab; + + case WT_CSRCHANGE: + GDK_NOTE (EVENTS, g_print ("WT_CSRCHANGE: %d %#x\n", + xevent->wParam, xevent->lParam)); + goto wintab; + + case WT_PROXIMITY: + GDK_NOTE (EVENTS, + g_print ("WT_PROXIMITY: %#x %d %d\n", + xevent->wParam, + LOWORD (xevent->lParam), HIWORD (xevent->lParam))); + /* Fall through */ + wintab: + return_val = gdk_input_vtable.other_event(event, xevent); + break; +#endif + } + +bypass_switch: + + if (return_val) + { + if (event->any.window) + gdk_window_ref (event->any.window); + if (((event->any.type == GDK_ENTER_NOTIFY) || + (event->any.type == GDK_LEAVE_NOTIFY)) && + (event->crossing.subwindow != NULL)) + gdk_window_ref (event->crossing.subwindow); + + GDK_NOTE (EVENTS, print_event (event)); + } + else + { + /* Mark this event as having no resources to be freed */ + event->any.window = NULL; + event->any.type = GDK_NOTHING; + } + + if (window) + gdk_window_unref (window); + + return return_val; +} + +static void +gdk_events_queue (void) +{ + GList *node; + GdkEvent *event; + MSG msg; + LRESULT lres; + + while (!gdk_event_queue_find_first() + && PeekMessage (&msg, NULL, 0, 0, PM_REMOVE)) + { + GDK_NOTE (EVENTS, g_print ("PeekMessage: %#x %#x\n", + msg.hwnd, msg.message)); + + if (paimmmpo == NULL + || (paimmmpo->lpVtbl->OnTranslateMessage) (paimmmpo, &msg) != S_OK) + TranslateMessage (&msg); + +#ifdef USE_DISPATCHMESSAGE + if (msg.message == g_pipe_readable_msg) + { + GDK_NOTE (EVENTS, g_print ("g_pipe_readable_msg: %d %d\n", + msg.wParam, msg.lParam)); + + g_io_channel_win32_pipe_readable (msg.wParam, msg.lParam); + + continue; + } + + DispatchMessage (&msg); +#else + event = gdk_event_new (); + + event->any.type = GDK_NOTHING; + event->any.window = NULL; + event->any.send_event = FALSE; + + ((GdkEventPrivate *)event)->flags |= GDK_EVENT_PENDING; + + gdk_event_queue_append (event); + node = queued_tail; + + if (gdk_event_translate (event, &msg, NULL, NULL)) + ((GdkEventPrivate *)event)->flags &= ~GDK_EVENT_PENDING; + else + { + if (paimmapp == NULL + || (paimmapp->lpVtbl->OnDefWindowProc) (paimmapp, msg.hwnd, + msg.message, + msg.wParam, msg.lParam, + &lres) == S_FALSE) + DefWindowProc (msg.hwnd, msg.message, msg.wParam, msg.lParam); + gdk_event_queue_remove_link (node); + g_list_free_1 (node); + gdk_event_free (event); + } +#endif + } +} + +static gboolean +gdk_event_prepare (gpointer source_data, + GTimeVal *current_time, + gint *timeout) +{ + MSG msg; + gboolean retval; + + GDK_THREADS_ENTER (); + + *timeout = -1; + + retval = (gdk_event_queue_find_first () != NULL) + || PeekMessage (&msg, NULL, 0, 0, PM_NOREMOVE); + + GDK_THREADS_LEAVE (); + + return retval; +} + +static gboolean +gdk_event_check (gpointer source_data, + GTimeVal *current_time) +{ + MSG msg; + gboolean retval; + + GDK_THREADS_ENTER (); + + if (event_poll_fd.revents & G_IO_IN) + retval = (gdk_event_queue_find_first () != NULL) + || PeekMessage (&msg, NULL, 0, 0, PM_NOREMOVE); + else + retval = FALSE; + + GDK_THREADS_LEAVE (); + + return retval; +} + +static GdkEvent* +gdk_event_unqueue (void) +{ + GdkEvent *event = NULL; + GList *tmp_list; + + tmp_list = gdk_event_queue_find_first (); + + if (tmp_list) + { + event = tmp_list->data; + gdk_event_queue_remove_link (tmp_list); + g_list_free_1 (tmp_list); + } + + return event; +} + +static gboolean +gdk_event_dispatch (gpointer source_data, + GTimeVal *current_time, + gpointer user_data) +{ + GdkEvent *event; + + GDK_THREADS_ENTER (); + + gdk_events_queue(); + event = gdk_event_unqueue(); + + if (event) + { + if (event_func) + (*event_func) (event, event_data); + + gdk_event_free (event); + } + + GDK_THREADS_LEAVE (); + + return TRUE; +} + +static void +gdk_synthesize_click (GdkEvent *event, + gint nclicks) +{ + GdkEvent temp_event; + + g_return_if_fail (event != NULL); + + temp_event = *event; + temp_event.type = (nclicks == 2) ? GDK_2BUTTON_PRESS : GDK_3BUTTON_PRESS; + + gdk_event_put (&temp_event); +} + +void +gdk_event_button_generate (GdkEvent *event) +{ + if ((event->button.time < (button_click_time[1] + TRIPLE_CLICK_TIME)) && + (event->button.window == button_window[1]) && + (event->button.button == button_number[1])) + { + gdk_synthesize_click (event, 3); + + button_click_time[1] = 0; + button_click_time[0] = 0; + button_window[1] = NULL; + button_window[0] = 0; + button_number[1] = -1; + button_number[0] = -1; + } + else if ((event->button.time < (button_click_time[0] + DOUBLE_CLICK_TIME)) && + (event->button.window == button_window[0]) && + (event->button.button == button_number[0])) + { + gdk_synthesize_click (event, 2); + + button_click_time[1] = button_click_time[0]; + button_click_time[0] = event->button.time; + button_window[1] = button_window[0]; + button_window[0] = event->button.window; + button_number[1] = button_number[0]; + button_number[0] = event->button.button; + } + else + { + button_click_time[1] = 0; + button_click_time[0] = event->button.time; + button_window[1] = NULL; + button_window[0] = event->button.window; + button_number[1] = -1; + button_number[0] = event->button.button; + } +} + +/* Sends a ClientMessage to all toplevel client windows */ +gboolean +gdk_event_send_client_message (GdkEvent *event, guint32 xid) +{ + /* XXX */ + return FALSE; +} + +void +gdk_event_send_clientmessage_toall (GdkEvent *event) +{ + /* XXX */ +} + diff --git a/gdk/win32/gdkevents.c b/gdk/win32/gdkevents.c new file mode 100644 index 000000000..9ef45fe8d --- /dev/null +++ b/gdk/win32/gdkevents.c @@ -0,0 +1,5193 @@ +/* GDK - The GIMP Drawing Kit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * Copyright (C) 1998-1999 Tor Lillqvist + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* + * Modified by the GTK+ Team and others 1997-1999. See the AUTHORS + * file for a list of people on the GTK+ Team. See the ChangeLog + * files for a list of changes. These files are distributed with + * GTK+ at ftp://ftp.gtk.org/pub/gtk/. + */ + +#include "config.h" + +#define NEW_PROPAGATION_CODE + +#define USE_DISPATCHMESSAGE + +/* Cannot use TrackMouseEvent, as the stupid WM_MOUSELEAVE message + * doesn't tell us where the mouse has gone. Thus we cannot use it to + * generate a correct GdkNotifyType. Pity, as using TrackMouseEvent + * otherwise would make it possible to reliably generate + * GDK_LEAVE_NOTIFY events, which would help get rid of those pesky + * tooltips sometimes popping up in the wrong place. + */ +/* define USE_TRACKMOUSEEVENT */ + +#include + +#include + +#include +#include + +#ifdef HAVE_DIMM_H +#include +#else +#include "surrogate-dimm.h" +#endif + +#ifdef HAVE_WINTAB +#include +#endif + +#include "gdk.h" +#include "gdkx.h" + +#include "gdkkeysyms.h" + +#include "gdkinputprivate.h" + +#define PING() printf("%s: %d\n",__FILE__,__LINE__),fflush(stdout) + +#define WINDOW_PRIVATE(wp) ((GdkWindowPrivate *) (wp)) + +typedef struct _GdkIOClosure GdkIOClosure; +typedef struct _GdkEventPrivate GdkEventPrivate; + +#define DOUBLE_CLICK_TIME 250 +#define TRIPLE_CLICK_TIME 500 +#define DOUBLE_CLICK_DIST 5 +#define TRIPLE_CLICK_DIST 5 + +gint gdk_event_func_from_window_proc = FALSE; + +typedef enum +{ + /* Following flag is set for events on the event queue during + * translation and cleared afterwards. + */ + GDK_EVENT_PENDING = 1 << 0 +} GdkEventFlags; + +struct _GdkIOClosure +{ + GdkInputFunction function; + GdkInputCondition condition; + GdkDestroyNotify notify; + gpointer data; +}; + +struct _GdkEventPrivate +{ + GdkEvent event; + guint flags; +}; + +/* + * Private function declarations + */ + +static GdkEvent *gdk_event_new (void); +static GdkFilterReturn + gdk_event_apply_filters(MSG *xevent, + GdkEvent *event, + GList *filters); +static gboolean gdk_event_translate (GdkEvent *event, + MSG *xevent, + gboolean *ret_val_flagp, + gint *ret_valp); +static void gdk_events_queue (void); +static GdkEvent *gdk_event_unqueue (void); +static gboolean gdk_event_prepare (gpointer source_data, + GTimeVal *current_time, + gint *timeout); +static gboolean gdk_event_check (gpointer source_data, + GTimeVal *current_time); +static gboolean gdk_event_dispatch (gpointer source_data, + GTimeVal *current_time, + gpointer user_data); + +static void gdk_synthesize_click (GdkEvent *event, + gint nclicks); + +/* Private variable declarations + */ + +static guint32 button_click_time[2]; /* The last 2 button click times. Used + * to determine if the latest button click + * is part of a double or triple click. + */ +static GdkWindow *button_window[2]; /* The last 2 windows to receive button presses. + * Also used to determine if the latest button + * click is part of a double or triple click. + */ +static guint button_number[2]; /* The last 2 buttons to be pressed. + */ +static GdkWindow *p_grab_window = NULL; /* Window that currently + * holds the pointer grab + */ + +static GdkWindow *k_grab_window = NULL; /* Window the holds the + * keyboard grab + */ + +static GList *client_filters; /* Filters for client messages */ + +static gboolean p_grab_automatic; +static GdkEventMask p_grab_mask; +static gboolean p_grab_owner_events, k_grab_owner_events; +static HCURSOR p_grab_cursor; + +static GdkEventFunc event_func = NULL; /* Callback for events */ +static gpointer event_data = NULL; +static GDestroyNotify event_notify = NULL; + +static GList *client_filters; /* Filters for client messages */ + +/* FIFO's for event queue, and for events put back using + * gdk_event_put(). + */ +static GList *queued_events = NULL; +static GList *queued_tail = NULL; + +static GSourceFuncs event_funcs = { + gdk_event_prepare, + gdk_event_check, + gdk_event_dispatch, + (GDestroyNotify)g_free +}; + +GPollFD event_poll_fd; + +static GdkWindow *curWnd = NULL; +static HWND active = NULL; +static gint curX, curY; +static gdouble curXroot, curYroot; +static UINT gdk_ping_msg; +static gboolean ignore_WM_CHAR = FALSE; +static gboolean is_AltGr_key = FALSE; + +static IActiveIMMApp *paimmapp = NULL; +static IActiveIMMMessagePumpOwner *paimmmpo = NULL; + +typedef BOOL (WINAPI *PFN_TrackMouseEvent) (LPTRACKMOUSEEVENT); +static PFN_TrackMouseEvent p_TrackMouseEvent = NULL; + +static gboolean use_IME_COMPOSITION = FALSE; + +LRESULT CALLBACK +gdk_WindowProc (HWND hWnd, + UINT message, + WPARAM wParam, + LPARAM lParam) +{ + GdkEvent event; + GdkEvent *eventp; + MSG msg; + DWORD pos; + LRESULT lres; + gint ret_val; + gboolean ret_val_flag; + + GDK_NOTE (EVENTS, g_print ("gdk_WindowProc: %#x %#.03x\n", hWnd, message)); + + msg.hwnd = hWnd; + msg.message = message; + msg.wParam = wParam; + msg.lParam = lParam; + msg.time = GetTickCount (); + pos = GetMessagePos (); + msg.pt.x = LOWORD (pos); + msg.pt.y = HIWORD (pos); + + ((GdkEventPrivate *)&event)->flags |= GDK_EVENT_PENDING; + if (gdk_event_translate (&event, &msg, &ret_val_flag, &ret_val)) + { + ((GdkEventPrivate *)&event)->flags &= ~GDK_EVENT_PENDING; +#if 1 + if (event.any.type == GDK_CONFIGURE) + { + /* Compress configure events */ + GList *list = queued_events; + + while (list != NULL + && (((GdkEvent *)list->data)->any.type != GDK_CONFIGURE + || ((GdkEvent *)list->data)->any.window != event.any.window)) + list = list->next; + if (list != NULL) + { + *((GdkEvent *)list->data) = event; + gdk_window_unref (event.any.window); + /* Wake up WaitMessage */ + PostMessage (NULL, gdk_ping_msg, 0, 0); + return FALSE; + } + } + else if (event.any.type == GDK_EXPOSE) + { + /* Compress expose events */ + GList *list = queued_events; + + while (list != NULL + && (((GdkEvent *)list->data)->any.type != GDK_EXPOSE + || ((GdkEvent *)list->data)->any.window != event.any.window)) + list = list->next; + if (list != NULL) + { + GdkRectangle u; + + gdk_rectangle_union (&event.expose.area, + &((GdkEvent *)list->data)->expose.area, + &u); + ((GdkEvent *)list->data)->expose.area = u; + gdk_window_unref (event.any.window); + /* Wake up WaitMessage */ + PostMessage (NULL, gdk_ping_msg, 0, 0); + return FALSE; + } + } +#endif + eventp = gdk_event_new (); + *eventp = event; + + /* Philippe Colantoni suggests this + * in order to handle events while opaque resizing neatly. I + * don't want it as default. Set the + * GDK_EVENT_FUNC_FROM_WINDOW_PROC env var to get this + * behaviour. + */ + if (gdk_event_func_from_window_proc && event_func) + { + GDK_THREADS_ENTER (); + + (*event_func) (eventp, event_data); + gdk_event_free (eventp); + + GDK_THREADS_LEAVE (); + } + else + { + gdk_event_queue_append (eventp); +#if 1 + /* Wake up WaitMessage */ + PostMessage (NULL, gdk_ping_msg, 0, 0); +#endif + } + + if (ret_val_flag) + return ret_val; + else + return FALSE; + } + + if (ret_val_flag) + return ret_val; + else + { + if (paimmapp == NULL + || (*paimmapp->lpVtbl->OnDefWindowProc) (paimmapp, hWnd, message, wParam, lParam, &lres) == S_FALSE) + return DefWindowProc (hWnd, message, wParam, lParam); + else + return lres; + } +} + +/********************************************* + * Functions for maintaining the event queue * + *********************************************/ + +/************************************************************* + * gdk_event_queue_find_first: + * Find the first event on the queue that is not still + * being filled in. + * arguments: + * + * results: + * Pointer to the list node for that event, or NULL + *************************************************************/ + +static GList* +gdk_event_queue_find_first (void) +{ + GList *tmp_list = queued_events; + + while (tmp_list) + { + GdkEventPrivate *event = tmp_list->data; + if (!(event->flags & GDK_EVENT_PENDING)) + return tmp_list; + + tmp_list = g_list_next (tmp_list); + } + + return NULL; +} + +/************************************************************* + * gdk_event_queue_remove_link: + * Remove a specified list node from the event queue. + * arguments: + * node: Node to remove. + * results: + *************************************************************/ + +static void +gdk_event_queue_remove_link (GList *node) +{ + if (node->prev) + node->prev->next = node->next; + else + queued_events = node->next; + + if (node->next) + node->next->prev = node->prev; + else + queued_tail = node->prev; + +} + +/************************************************************* + * gdk_event_queue_append: + * Append an event onto the tail of the event queue. + * arguments: + * event: Event to append. + * results: + *************************************************************/ + +void +gdk_event_queue_append (GdkEvent *event) +{ + queued_tail = g_list_append (queued_tail, event); + + if (!queued_events) + queued_events = queued_tail; + else + queued_tail = queued_tail->next; +} + +void +gdk_events_init (void) +{ + HRESULT hres; + HMODULE user32, imm32; + HINSTANCE commctrl32; + + if (g_pipe_readable_msg == 0) + g_pipe_readable_msg = RegisterWindowMessage ("g-pipe-readable"); + GDK_NOTE (EVENTS, g_print ("g-pipe-readable = %#.03x\n", + g_pipe_readable_msg)); + + gdk_ping_msg = RegisterWindowMessage ("gdk-ping"); + GDK_NOTE (EVENTS, g_print ("gdk-ping = %#.03x\n", + gdk_ping_msg)); + + g_source_add (GDK_PRIORITY_EVENTS, TRUE, &event_funcs, NULL, NULL, NULL); + + event_poll_fd.fd = G_WIN32_MSG_HANDLE; + event_poll_fd.events = G_IO_IN; + + g_main_add_poll (&event_poll_fd, GDK_PRIORITY_EVENTS); + + button_click_time[0] = 0; + button_click_time[1] = 0; + button_window[0] = NULL; + button_window[1] = NULL; + button_number[0] = -1; + button_number[1] = -1; + + hres = CoCreateInstance (&CLSID_CActiveIMM, + NULL, + CLSCTX_ALL, + &IID_IActiveIMMApp, + (LPVOID *) &paimmapp); + + if (hres == S_OK) + { + GDK_NOTE (EVENTS, g_print ("IActiveIMMApp created %#x\n", + paimmapp)); + (*paimmapp->lpVtbl->Activate) (paimmapp, TRUE); + + hres = (*paimmapp->lpVtbl->QueryInterface) (paimmapp, &IID_IActiveIMMMessagePumpOwner, &paimmmpo); + GDK_NOTE (EVENTS, g_print ("IActiveIMMMessagePumpOwner created %#x\n", + paimmmpo)); + (paimmmpo->lpVtbl->Start) (paimmmpo); + } + +#ifdef USE_TRACKMOUSEEVENT + user32 = GetModuleHandle ("user32.dll"); + if ((p_TrackMouseEvent = GetProcAddress (user32, "TrackMouseEvent")) == NULL) + { + if ((commctrl32 = LoadLibrary ("commctrl32.dll")) != NULL) + p_TrackMouseEvent = (PFN_TrackMouseEvent) + GetProcAddress (commctrl32, "_TrackMouseEvent"); + } + if (p_TrackMouseEvent != NULL) + GDK_NOTE (EVENTS, g_print ("Using TrackMouseEvent to detect leave events\n")); +#endif + if (windows_version < 0x80000000 && (windows_version & 0xFF) == 5) + { + /* On Win2k (Beta 3, at least) WM_IME_CHAR doesn't seem to work + * correctly for non-Unicode applications. Handle + * WM_IME_COMPOSITION with GCS_RESULTSTR instead, fetch the + * Unicode char from the IME with ImmGetCompositionStringW(). + */ + use_IME_COMPOSITION = TRUE; + } +} + +/* + *-------------------------------------------------------------- + * gdk_events_pending + * + * Returns if events are pending on the queue. + * + * Arguments: + * + * Results: + * Returns TRUE if events are pending + * + * Side effects: + * + *-------------------------------------------------------------- + */ + +gboolean +gdk_events_pending (void) +{ + MSG msg; + + return (gdk_event_queue_find_first() || PeekMessage (&msg, NULL, 0, 0, PM_NOREMOVE)); +} + +/* + *-------------------------------------------------------------- + * gdk_event_get_graphics_expose + * + * Waits for a GraphicsExpose or NoExpose event + * + * Arguments: + * + * Results: + * For GraphicsExpose events, returns a pointer to the event + * converted into a GdkEvent Otherwise, returns NULL. + * + * Side effects: + * + *-------------------------------------------------------------- */ + +GdkEvent* +gdk_event_get_graphics_expose (GdkWindow *window) +{ + MSG xevent; + GdkEvent *event; + GdkWindowPrivate *private = (GdkWindowPrivate *) window; + + g_return_val_if_fail (window != NULL, NULL); + + GDK_NOTE (EVENTS, g_print ("gdk_event_get_graphics_expose\n")); + +#if 1 + /* Some nasty bugs here, just return NULL for now. */ + return NULL; +#else + if (GetMessage (&xevent, private->xwindow, WM_PAINT, WM_PAINT)) + { + event = gdk_event_new (); + + if (gdk_event_translate (event, &xevent, NULL, NULL)) + return event; + else + gdk_event_free (event); + } + + return NULL; +#endif +} + +/************************************************************* + * gdk_event_handler_set: + * + * arguments: + * func: Callback function to be called for each event. + * data: Data supplied to the function + * notify: function called when function is no longer needed + * + * results: + *************************************************************/ + +void +gdk_event_handler_set (GdkEventFunc func, + gpointer data, + GDestroyNotify notify) +{ + if (event_notify) + (*event_notify) (event_data); + + event_func = func; + event_data = data; + event_notify = notify; +} + +/* + *-------------------------------------------------------------- + * gdk_event_get + * + * Gets the next event. + * + * Arguments: + * + * Results: + * If an event is waiting that we care about, returns + * a pointer to that event, to be freed with gdk_event_free. + * Otherwise, returns NULL. + * + * Side effects: + * + *-------------------------------------------------------------- + */ + +GdkEvent* +gdk_event_get (void) +{ + gdk_events_queue(); + + return gdk_event_unqueue(); +} + +/* + *-------------------------------------------------------------- + * gdk_event_peek + * + * Gets the next event. + * + * Arguments: + * + * Results: + * If an event is waiting that we care about, returns + * a copy of that event, but does not remove it from + * the queue. The pointer is to be freed with gdk_event_free. + * Otherwise, returns NULL. + * + * Side effects: + * + *-------------------------------------------------------------- + */ + +GdkEvent* +gdk_event_peek (void) +{ + GList *tmp_list; + + tmp_list = gdk_event_queue_find_first (); + + if (tmp_list) + return gdk_event_copy (tmp_list->data); + else + return NULL; +} + +void +gdk_event_put (GdkEvent *event) +{ + GdkEvent *new_event; + GList *tmp_list; + + g_return_if_fail (event != NULL); + + new_event = gdk_event_copy (event); + + gdk_event_queue_append (new_event); +} + +/* + *-------------------------------------------------------------- + * gdk_event_copy + * + * Copy a event structure into new storage. + * + * Arguments: + * "event" is the event struct to copy. + * + * Results: + * A new event structure. Free it with gdk_event_free. + * + * Side effects: + * The reference count of the window in the event is increased. + * + *-------------------------------------------------------------- + */ + +static GMemChunk *event_chunk = NULL; + +static GdkEvent* +gdk_event_new (void) +{ + GdkEventPrivate *new_event; + + if (event_chunk == NULL) + event_chunk = g_mem_chunk_new ("events", + sizeof (GdkEventPrivate), + 4096, + G_ALLOC_AND_FREE); + + new_event = g_chunk_new (GdkEventPrivate, event_chunk); + new_event->flags = 0; + + return (GdkEvent *) new_event; +} + +GdkEvent* +gdk_event_copy (GdkEvent *event) +{ + GdkEvent *new_event; + gchar *s; + + g_return_val_if_fail (event != NULL, NULL); + + new_event = gdk_event_new (); + + *new_event = *event; + gdk_window_ref (new_event->any.window); + + switch (event->any.type) + { + case GDK_KEY_PRESS: + case GDK_KEY_RELEASE: + if (event->key.length > 0) + { + s = event->key.string; + new_event->key.string = g_malloc (event->key.length + 1); + memcpy (new_event->key.string, s, event->key.length + 1); + } + break; + + case GDK_ENTER_NOTIFY: + case GDK_LEAVE_NOTIFY: + if (event->crossing.subwindow != NULL) + gdk_window_ref (event->crossing.subwindow); + break; + + case GDK_DRAG_ENTER: + case GDK_DRAG_LEAVE: + case GDK_DRAG_MOTION: + case GDK_DRAG_STATUS: + case GDK_DROP_START: + case GDK_DROP_FINISHED: + gdk_drag_context_ref (event->dnd.context); + break; + + default: + break; + } + + return new_event; +} + +/* + *-------------------------------------------------------------- + * gdk_event_free + * + * Free a event structure obtained from gdk_event_copy. Do not use + * with other event structures. + * + * Arguments: + * "event" is the event struct to free. + * + * Results: + * + * Side effects: + * The reference count of the window in the event is decreased and + * might be freed, too. + * + *-------------------------------------------------------------- */ + +void +gdk_event_free (GdkEvent *event) +{ + g_return_if_fail (event != NULL); + + g_assert (event_chunk != NULL); /* paranoid */ + + if (event->any.window) + gdk_window_unref (event->any.window); + + switch (event->any.type) + { + case GDK_KEY_PRESS: + case GDK_KEY_RELEASE: + g_free (event->key.string); + break; + + case GDK_ENTER_NOTIFY: + case GDK_LEAVE_NOTIFY: + if (event->crossing.subwindow != NULL) + gdk_window_unref (event->crossing.subwindow); + break; + + case GDK_DRAG_ENTER: + case GDK_DRAG_LEAVE: + case GDK_DRAG_MOTION: + case GDK_DRAG_STATUS: + case GDK_DROP_START: + case GDK_DROP_FINISHED: + gdk_drag_context_unref (event->dnd.context); + break; + + default: + break; + } + + g_mem_chunk_free (event_chunk, event); +} + +/* + *-------------------------------------------------------------- + * gdk_event_get_time: + * Get the timestamp from an event. + * arguments: + * event: + * results: + * The event's time stamp, if it has one, otherwise + * GDK_CURRENT_TIME. + *-------------------------------------------------------------- + */ + +guint32 +gdk_event_get_time (GdkEvent *event) +{ + if (event) + switch (event->type) + { + case GDK_MOTION_NOTIFY: + return event->motion.time; + case GDK_BUTTON_PRESS: + case GDK_2BUTTON_PRESS: + case GDK_3BUTTON_PRESS: + case GDK_BUTTON_RELEASE: + return event->button.time; + case GDK_KEY_PRESS: + case GDK_KEY_RELEASE: + return event->key.time; + case GDK_ENTER_NOTIFY: + case GDK_LEAVE_NOTIFY: + return event->crossing.time; + case GDK_PROPERTY_NOTIFY: + return event->property.time; + case GDK_SELECTION_CLEAR: + case GDK_SELECTION_REQUEST: + case GDK_SELECTION_NOTIFY: + return event->selection.time; + case GDK_PROXIMITY_IN: + case GDK_PROXIMITY_OUT: + return event->proximity.time; + case GDK_DRAG_ENTER: + case GDK_DRAG_LEAVE: + case GDK_DRAG_MOTION: + case GDK_DRAG_STATUS: + case GDK_DROP_START: + case GDK_DROP_FINISHED: + return event->dnd.time; + default: /* use current time */ + break; + } + + return GDK_CURRENT_TIME; +} + +/* + *-------------------------------------------------------------- + * gdk_set_show_events + * + * Turns on/off the showing of events. + * + * Arguments: + * "show_events" is a boolean describing whether or + * not to show the events gdk receives. + * + * Results: + * + * Side effects: + * When "show_events" is TRUE, calls to "gdk_event_get" + * will output debugging informatin regarding the event + * received to stdout. + * + *-------------------------------------------------------------- + */ + +void +gdk_set_show_events (gint show_events) +{ + if (show_events) + gdk_debug_flags |= GDK_DEBUG_EVENTS; + else + gdk_debug_flags &= ~GDK_DEBUG_EVENTS; +} + +gint +gdk_get_show_events (void) +{ + return gdk_debug_flags & GDK_DEBUG_EVENTS; +} + +/* + *-------------------------------------------------------------- + * gdk_pointer_grab + * + * Grabs the pointer to a specific window + * + * Arguments: + * "window" is the window which will receive the grab + * "owner_events" specifies whether events will be reported as is, + * or relative to "window" + * "event_mask" masks only interesting events + * "confine_to" limits the cursor movement to the specified window + * "cursor" changes the cursor for the duration of the grab + * "time" specifies the time + * + * Results: + * + * Side effects: + * requires a corresponding call to gdk_pointer_ungrab + * + *-------------------------------------------------------------- + */ + +gint +gdk_pointer_grab (GdkWindow * window, + gint owner_events, + GdkEventMask event_mask, + GdkWindow * confine_to, + GdkCursor * cursor, + guint32 time) +{ + HWND xwindow; + HWND xconfine_to; + HCURSOR xcursor; + GdkCursorPrivate *cursor_private; + gint return_val; + + g_return_val_if_fail (window != NULL, 0); + g_return_val_if_fail (GDK_IS_WINDOW (window), 0); + g_return_val_if_fail (confine_to == NULL || GDK_IS_WINDOW (confine_to), 0); + + cursor_private = (GdkCursorPrivate*) cursor; + + xwindow = GDK_DRAWABLE_XID (window); + + if (!confine_to || GDK_DRAWABLE_DESTROYED (confine_to)) + xconfine_to = NULL; + else + xconfine_to = GDK_DRAWABLE_XID (confine_to); + + if (!cursor) + xcursor = NULL; + else + xcursor = cursor_private->xcursor; + + if (gdk_input_vtable.grab_pointer) + return_val = gdk_input_vtable.grab_pointer (window, + owner_events, + event_mask, + confine_to, + time); + else + return_val = Success; + + if (return_val == Success) + { + if (!GDK_DRAWABLE_DESTROYED (window)) + { + GDK_NOTE (EVENTS, g_print ("gdk_pointer_grab: %#x %s %#x%s%s\n", + xwindow, + (owner_events ? "TRUE" : "FALSE"), + xcursor, + (event_mask & GDK_BUTTON_PRESS_MASK) ? + " PRESS" : "", + (event_mask & GDK_BUTTON_RELEASE_MASK) ? + " RELEASE" : "")); + p_grab_mask = event_mask; + p_grab_owner_events = (owner_events != 0); + p_grab_automatic = FALSE; + +#if 0 /* Menus don't work if we use mouse capture. Pity, because many other + * things work better with mouse capture. + */ + SetCapture (xwindow); +#endif + return_val = GrabSuccess; + } + else + return_val = AlreadyGrabbed; + } + + if (return_val == GrabSuccess) + { + p_grab_window = window; + p_grab_cursor = xcursor; + } + + return return_val; +} + +/* + *-------------------------------------------------------------- + * gdk_pointer_ungrab + * + * Releases any pointer grab + * + * Arguments: + * + * Results: + * + * Side effects: + * + *-------------------------------------------------------------- + */ + +void +gdk_pointer_ungrab (guint32 time) +{ + if (gdk_input_vtable.ungrab_pointer) + gdk_input_vtable.ungrab_pointer (time); +#if 0 + if (GetCapture () != NULL) + ReleaseCapture (); +#endif + GDK_NOTE (EVENTS, g_print ("gdk_pointer_ungrab\n")); + + p_grab_window = NULL; +} + +/* + *-------------------------------------------------------------- + * gdk_pointer_is_grabbed + * + * Tell wether there is an active x pointer grab in effect + * + * Arguments: + * + * Results: + * + * Side effects: + * + *-------------------------------------------------------------- + */ + +gint +gdk_pointer_is_grabbed (void) +{ + return p_grab_window != NULL; +} + +/* + *-------------------------------------------------------------- + * gdk_keyboard_grab + * + * Grabs the keyboard to a specific window + * + * Arguments: + * "window" is the window which will receive the grab + * "owner_events" specifies whether events will be reported as is, + * or relative to "window" + * "time" specifies the time + * + * Results: + * + * Side effects: + * requires a corresponding call to gdk_keyboard_ungrab + * + *-------------------------------------------------------------- + */ + +gint +gdk_keyboard_grab (GdkWindow * window, + gint owner_events, + guint32 time) +{ + gint return_val; + + g_return_val_if_fail (window != NULL, 0); + g_return_val_if_fail (GDK_IS_WINDOW (window), 0); + + GDK_NOTE (EVENTS, g_print ("gdk_keyboard_grab %#x\n", + GDK_DRAWABLE_XID (window))); + + if (!GDK_DRAWABLE_DESTROYED (window)) + { + k_grab_owner_events = owner_events != 0; + return_val = GrabSuccess; + } + else + return_val = AlreadyGrabbed; + + if (return_val == GrabSuccess) + k_grab_window = window; + + return return_val; +} + +/* + *-------------------------------------------------------------- + * gdk_keyboard_ungrab + * + * Releases any keyboard grab + * + * Arguments: + * + * Results: + * + * Side effects: + * + *-------------------------------------------------------------- + */ + +void +gdk_keyboard_ungrab (guint32 time) +{ + GDK_NOTE (EVENTS, g_print ("gdk_keyboard_ungrab\n")); + + k_grab_window = NULL; +} + +static void +gdk_io_destroy (gpointer data) +{ + GdkIOClosure *closure = data; + + if (closure->notify) + closure->notify (closure->data); + + g_free (closure); +} + +static gboolean +gdk_io_invoke (GIOChannel *source, + GIOCondition condition, + gpointer data) +{ + GdkIOClosure *closure = data; + GdkInputCondition gdk_cond = 0; + + if (condition & (G_IO_IN | G_IO_PRI)) + gdk_cond |= GDK_INPUT_READ; + if (condition & G_IO_OUT) + gdk_cond |= GDK_INPUT_WRITE; + if (condition & (G_IO_ERR | G_IO_HUP | G_IO_NVAL)) + gdk_cond |= GDK_INPUT_EXCEPTION; + + if (closure->condition & gdk_cond) + closure->function (closure->data, g_io_channel_unix_get_fd (source), gdk_cond); + + return TRUE; +} + +gint +gdk_input_add_full (gint source, + GdkInputCondition condition, + GdkInputFunction function, + gpointer data, + GdkDestroyNotify destroy) +{ + guint result; + GdkIOClosure *closure = g_new (GdkIOClosure, 1); + GIOChannel *channel; + GIOCondition cond = 0; + + closure->function = function; + closure->condition = condition; + closure->notify = destroy; + closure->data = data; + + if (condition & GDK_INPUT_READ) + cond |= (G_IO_IN | G_IO_PRI); + if (condition & GDK_INPUT_WRITE) + cond |= G_IO_OUT; + if (condition & GDK_INPUT_EXCEPTION) + cond |= G_IO_ERR|G_IO_HUP|G_IO_NVAL; + + channel = g_io_channel_unix_new (source); + result = g_io_add_watch_full (channel, G_PRIORITY_DEFAULT, cond, + gdk_io_invoke, + closure, gdk_io_destroy); + g_io_channel_unref (channel); + + return result; +} + +gint +gdk_input_add (gint source, + GdkInputCondition condition, + GdkInputFunction function, + gpointer data) +{ + return gdk_input_add_full (source, condition, function, data, NULL); +} + +void +gdk_input_remove (gint tag) +{ + g_source_remove (tag); +} + +static GdkFilterReturn +gdk_event_apply_filters (MSG *xevent, + GdkEvent *event, + GList *filters) +{ + GdkEventFilter *filter; + GList *tmp_list; + GdkFilterReturn result; + + tmp_list = filters; + + while (tmp_list) + { + filter = (GdkEventFilter *) tmp_list->data; + + result = (*filter->function) (xevent, event, filter->data); + if (result != GDK_FILTER_CONTINUE) + return result; + + tmp_list = tmp_list->next; + } + + return GDK_FILTER_CONTINUE; +} + +void +gdk_add_client_message_filter (GdkAtom message_type, + GdkFilterFunc func, + gpointer data) +{ + GdkClientFilter *filter = g_new (GdkClientFilter, 1); + + filter->type = message_type; + filter->function = func; + filter->data = data; + + client_filters = g_list_prepend (client_filters, filter); +} + +/* Thanks to Markus G. Kuhn for the ksysym<->Unicode + * mapping functions, from the xterm sources. + */ + +#if 0 /* Keyval-to-Unicode isn't actually needed */ + +struct k2u { + unsigned short keysym; + unsigned short ucs; +} k2utab[] = { + { 0x01a1, 0x0104 }, /* Aogonek Ą LATIN CAPITAL LETTER A WITH OGONEK */ + { 0x01a2, 0x02d8 }, /* breve ˘ BREVE */ + { 0x01a3, 0x0141 }, /* Lstroke Ł LATIN CAPITAL LETTER L WITH STROKE */ + { 0x01a5, 0x013d }, /* Lcaron Ľ LATIN CAPITAL LETTER L WITH CARON */ + { 0x01a6, 0x015a }, /* Sacute Ś LATIN CAPITAL LETTER S WITH ACUTE */ + { 0x01a9, 0x0160 }, /* Scaron Å  LATIN CAPITAL LETTER S WITH CARON */ + { 0x01aa, 0x015e }, /* Scedilla Ş LATIN CAPITAL LETTER S WITH CEDILLA */ + { 0x01ab, 0x0164 }, /* Tcaron Ť LATIN CAPITAL LETTER T WITH CARON */ + { 0x01ac, 0x0179 }, /* Zacute Ź LATIN CAPITAL LETTER Z WITH ACUTE */ + { 0x01ae, 0x017d }, /* Zcaron Ž LATIN CAPITAL LETTER Z WITH CARON */ + { 0x01af, 0x017b }, /* Zabovedot Å» LATIN CAPITAL LETTER Z WITH DOT ABOVE */ + { 0x01b1, 0x0105 }, /* aogonek ą LATIN SMALL LETTER A WITH OGONEK */ + { 0x01b2, 0x02db }, /* ogonek ˛ OGONEK */ + { 0x01b3, 0x0142 }, /* lstroke ł LATIN SMALL LETTER L WITH STROKE */ + { 0x01b5, 0x013e }, /* lcaron ľ LATIN SMALL LETTER L WITH CARON */ + { 0x01b6, 0x015b }, /* sacute ś LATIN SMALL LETTER S WITH ACUTE */ + { 0x01b7, 0x02c7 }, /* caron ˇ CARON */ + { 0x01b9, 0x0161 }, /* scaron Å¡ LATIN SMALL LETTER S WITH CARON */ + { 0x01ba, 0x015f }, /* scedilla ş LATIN SMALL LETTER S WITH CEDILLA */ + { 0x01bb, 0x0165 }, /* tcaron Å¥ LATIN SMALL LETTER T WITH CARON */ + { 0x01bc, 0x017a }, /* zacute ź LATIN SMALL LETTER Z WITH ACUTE */ + { 0x01bd, 0x02dd }, /* doubleacute ˝ DOUBLE ACUTE ACCENT */ + { 0x01be, 0x017e }, /* zcaron ž LATIN SMALL LETTER Z WITH CARON */ + { 0x01bf, 0x017c }, /* zabovedot ż LATIN SMALL LETTER Z WITH DOT ABOVE */ + { 0x01c0, 0x0154 }, /* Racute Ŕ LATIN CAPITAL LETTER R WITH ACUTE */ + { 0x01c3, 0x0102 }, /* Abreve Ă LATIN CAPITAL LETTER A WITH BREVE */ + { 0x01c5, 0x0139 }, /* Lacute Ĺ LATIN CAPITAL LETTER L WITH ACUTE */ + { 0x01c6, 0x0106 }, /* Cacute Ć LATIN CAPITAL LETTER C WITH ACUTE */ + { 0x01c8, 0x010c }, /* Ccaron Č LATIN CAPITAL LETTER C WITH CARON */ + { 0x01ca, 0x0118 }, /* Eogonek Ę LATIN CAPITAL LETTER E WITH OGONEK */ + { 0x01cc, 0x011a }, /* Ecaron Ě LATIN CAPITAL LETTER E WITH CARON */ + { 0x01cf, 0x010e }, /* Dcaron Ď LATIN CAPITAL LETTER D WITH CARON */ + { 0x01d0, 0x0110 }, /* Dstroke Đ LATIN CAPITAL LETTER D WITH STROKE */ + { 0x01d1, 0x0143 }, /* Nacute Ń LATIN CAPITAL LETTER N WITH ACUTE */ + { 0x01d2, 0x0147 }, /* Ncaron Ň LATIN CAPITAL LETTER N WITH CARON */ + { 0x01d5, 0x0150 }, /* Odoubleacute Ő LATIN CAPITAL LETTER O WITH DOUBLE ACUTE */ + { 0x01d8, 0x0158 }, /* Rcaron Ř LATIN CAPITAL LETTER R WITH CARON */ + { 0x01d9, 0x016e }, /* Uring Å® LATIN CAPITAL LETTER U WITH RING ABOVE */ + { 0x01db, 0x0170 }, /* Udoubleacute Å° LATIN CAPITAL LETTER U WITH DOUBLE ACUTE */ + { 0x01de, 0x0162 }, /* Tcedilla Å¢ LATIN CAPITAL LETTER T WITH CEDILLA */ + { 0x01e0, 0x0155 }, /* racute ŕ LATIN SMALL LETTER R WITH ACUTE */ + { 0x01e3, 0x0103 }, /* abreve ă LATIN SMALL LETTER A WITH BREVE */ + { 0x01e5, 0x013a }, /* lacute ĺ LATIN SMALL LETTER L WITH ACUTE */ + { 0x01e6, 0x0107 }, /* cacute ć LATIN SMALL LETTER C WITH ACUTE */ + { 0x01e8, 0x010d }, /* ccaron č LATIN SMALL LETTER C WITH CARON */ + { 0x01ea, 0x0119 }, /* eogonek ę LATIN SMALL LETTER E WITH OGONEK */ + { 0x01ec, 0x011b }, /* ecaron ě LATIN SMALL LETTER E WITH CARON */ + { 0x01ef, 0x010f }, /* dcaron ď LATIN SMALL LETTER D WITH CARON */ + { 0x01f0, 0x0111 }, /* dstroke đ LATIN SMALL LETTER D WITH STROKE */ + { 0x01f1, 0x0144 }, /* nacute ń LATIN SMALL LETTER N WITH ACUTE */ + { 0x01f2, 0x0148 }, /* ncaron ň LATIN SMALL LETTER N WITH CARON */ + { 0x01f5, 0x0151 }, /* odoubleacute ő LATIN SMALL LETTER O WITH DOUBLE ACUTE */ + { 0x01f8, 0x0159 }, /* rcaron ř LATIN SMALL LETTER R WITH CARON */ + { 0x01f9, 0x016f }, /* uring ů LATIN SMALL LETTER U WITH RING ABOVE */ + { 0x01fb, 0x0171 }, /* udoubleacute ű LATIN SMALL LETTER U WITH DOUBLE ACUTE */ + { 0x01fe, 0x0163 }, /* tcedilla Å£ LATIN SMALL LETTER T WITH CEDILLA */ + { 0x01ff, 0x02d9 }, /* abovedot ˙ DOT ABOVE */ + { 0x02a1, 0x0126 }, /* Hstroke Ħ LATIN CAPITAL LETTER H WITH STROKE */ + { 0x02a6, 0x0124 }, /* Hcircumflex Ĥ LATIN CAPITAL LETTER H WITH CIRCUMFLEX */ + { 0x02a9, 0x0130 }, /* Iabovedot Ä° LATIN CAPITAL LETTER I WITH DOT ABOVE */ + { 0x02ab, 0x011e }, /* Gbreve Ğ LATIN CAPITAL LETTER G WITH BREVE */ + { 0x02ac, 0x0134 }, /* Jcircumflex Ä´ LATIN CAPITAL LETTER J WITH CIRCUMFLEX */ + { 0x02b1, 0x0127 }, /* hstroke ħ LATIN SMALL LETTER H WITH STROKE */ + { 0x02b6, 0x0125 }, /* hcircumflex Ä¥ LATIN SMALL LETTER H WITH CIRCUMFLEX */ + { 0x02b9, 0x0131 }, /* idotless ı LATIN SMALL LETTER DOTLESS I */ + { 0x02bb, 0x011f }, /* gbreve ğ LATIN SMALL LETTER G WITH BREVE */ + { 0x02bc, 0x0135 }, /* jcircumflex ĵ LATIN SMALL LETTER J WITH CIRCUMFLEX */ + { 0x02c5, 0x010a }, /* Cabovedot Ċ LATIN CAPITAL LETTER C WITH DOT ABOVE */ + { 0x02c6, 0x0108 }, /* Ccircumflex Ĉ LATIN CAPITAL LETTER C WITH CIRCUMFLEX */ + { 0x02d5, 0x0120 }, /* Gabovedot Ä  LATIN CAPITAL LETTER G WITH DOT ABOVE */ + { 0x02d8, 0x011c }, /* Gcircumflex Ĝ LATIN CAPITAL LETTER G WITH CIRCUMFLEX */ + { 0x02dd, 0x016c }, /* Ubreve Ŭ LATIN CAPITAL LETTER U WITH BREVE */ + { 0x02de, 0x015c }, /* Scircumflex Ŝ LATIN CAPITAL LETTER S WITH CIRCUMFLEX */ + { 0x02e5, 0x010b }, /* cabovedot ċ LATIN SMALL LETTER C WITH DOT ABOVE */ + { 0x02e6, 0x0109 }, /* ccircumflex ĉ LATIN SMALL LETTER C WITH CIRCUMFLEX */ + { 0x02f5, 0x0121 }, /* gabovedot Ä¡ LATIN SMALL LETTER G WITH DOT ABOVE */ + { 0x02f8, 0x011d }, /* gcircumflex ĝ LATIN SMALL LETTER G WITH CIRCUMFLEX */ + { 0x02fd, 0x016d }, /* ubreve Å­ LATIN SMALL LETTER U WITH BREVE */ + { 0x02fe, 0x015d }, /* scircumflex ŝ LATIN SMALL LETTER S WITH CIRCUMFLEX */ + { 0x03a2, 0x0138 }, /* kra ĸ LATIN SMALL LETTER KRA */ + { 0x03a3, 0x0156 }, /* Rcedilla Ŗ LATIN CAPITAL LETTER R WITH CEDILLA */ + { 0x03a5, 0x0128 }, /* Itilde Ĩ LATIN CAPITAL LETTER I WITH TILDE */ + { 0x03a6, 0x013b }, /* Lcedilla Ä» LATIN CAPITAL LETTER L WITH CEDILLA */ + { 0x03aa, 0x0112 }, /* Emacron Ē LATIN CAPITAL LETTER E WITH MACRON */ + { 0x03ab, 0x0122 }, /* Gcedilla Ä¢ LATIN CAPITAL LETTER G WITH CEDILLA */ + { 0x03ac, 0x0166 }, /* Tslash Ŧ LATIN CAPITAL LETTER T WITH STROKE */ + { 0x03b3, 0x0157 }, /* rcedilla ŗ LATIN SMALL LETTER R WITH CEDILLA */ + { 0x03b5, 0x0129 }, /* itilde Ä© LATIN SMALL LETTER I WITH TILDE */ + { 0x03b6, 0x013c }, /* lcedilla ļ LATIN SMALL LETTER L WITH CEDILLA */ + { 0x03ba, 0x0113 }, /* emacron ē LATIN SMALL LETTER E WITH MACRON */ + { 0x03bb, 0x0123 }, /* gcedilla Ä£ LATIN SMALL LETTER G WITH CEDILLA */ + { 0x03bc, 0x0167 }, /* tslash ŧ LATIN SMALL LETTER T WITH STROKE */ + { 0x03bd, 0x014a }, /* ENG Ŋ LATIN CAPITAL LETTER ENG */ + { 0x03bf, 0x014b }, /* eng ŋ LATIN SMALL LETTER ENG */ + { 0x03c0, 0x0100 }, /* Amacron Ā LATIN CAPITAL LETTER A WITH MACRON */ + { 0x03c7, 0x012e }, /* Iogonek Ä® LATIN CAPITAL LETTER I WITH OGONEK */ + { 0x03cc, 0x0116 }, /* Eabovedot Ė LATIN CAPITAL LETTER E WITH DOT ABOVE */ + { 0x03cf, 0x012a }, /* Imacron Ī LATIN CAPITAL LETTER I WITH MACRON */ + { 0x03d1, 0x0145 }, /* Ncedilla Ņ LATIN CAPITAL LETTER N WITH CEDILLA */ + { 0x03d2, 0x014c }, /* Omacron Ō LATIN CAPITAL LETTER O WITH MACRON */ + { 0x03d3, 0x0136 }, /* Kcedilla Ķ LATIN CAPITAL LETTER K WITH CEDILLA */ + { 0x03d9, 0x0172 }, /* Uogonek Ų LATIN CAPITAL LETTER U WITH OGONEK */ + { 0x03dd, 0x0168 }, /* Utilde Ũ LATIN CAPITAL LETTER U WITH TILDE */ + { 0x03de, 0x016a }, /* Umacron Ū LATIN CAPITAL LETTER U WITH MACRON */ + { 0x03e0, 0x0101 }, /* amacron ā LATIN SMALL LETTER A WITH MACRON */ + { 0x03e7, 0x012f }, /* iogonek į LATIN SMALL LETTER I WITH OGONEK */ + { 0x03ec, 0x0117 }, /* eabovedot ė LATIN SMALL LETTER E WITH DOT ABOVE */ + { 0x03ef, 0x012b }, /* imacron Ä« LATIN SMALL LETTER I WITH MACRON */ + { 0x03f1, 0x0146 }, /* ncedilla ņ LATIN SMALL LETTER N WITH CEDILLA */ + { 0x03f2, 0x014d }, /* omacron ō LATIN SMALL LETTER O WITH MACRON */ + { 0x03f3, 0x0137 }, /* kcedilla Ä· LATIN SMALL LETTER K WITH CEDILLA */ + { 0x03f9, 0x0173 }, /* uogonek ų LATIN SMALL LETTER U WITH OGONEK */ + { 0x03fd, 0x0169 }, /* utilde Å© LATIN SMALL LETTER U WITH TILDE */ + { 0x03fe, 0x016b }, /* umacron Å« LATIN SMALL LETTER U WITH MACRON */ + { 0x047e, 0x203e }, /* overline ‾ OVERLINE */ + { 0x04a1, 0x3002 }, /* kana_fullstop 。 IDEOGRAPHIC FULL STOP */ + { 0x04a2, 0x300c }, /* kana_openingbracket 「 LEFT CORNER BRACKET */ + { 0x04a3, 0x300d }, /* kana_closingbracket 」 RIGHT CORNER BRACKET */ + { 0x04a4, 0x3001 }, /* kana_comma 、 IDEOGRAPHIC COMMA */ + { 0x04a5, 0x30fb }, /* kana_conjunctive ・ KATAKANA MIDDLE DOT */ + { 0x04a6, 0x30f2 }, /* kana_WO ヲ KATAKANA LETTER WO */ + { 0x04a7, 0x30a1 }, /* kana_a ァ KATAKANA LETTER SMALL A */ + { 0x04a8, 0x30a3 }, /* kana_i ィ KATAKANA LETTER SMALL I */ + { 0x04a9, 0x30a5 }, /* kana_u ゥ KATAKANA LETTER SMALL U */ + { 0x04aa, 0x30a7 }, /* kana_e ェ KATAKANA LETTER SMALL E */ + { 0x04ab, 0x30a9 }, /* kana_o ォ KATAKANA LETTER SMALL O */ + { 0x04ac, 0x30e3 }, /* kana_ya ャ KATAKANA LETTER SMALL YA */ + { 0x04ad, 0x30e5 }, /* kana_yu ュ KATAKANA LETTER SMALL YU */ + { 0x04ae, 0x30e7 }, /* kana_yo ョ KATAKANA LETTER SMALL YO */ + { 0x04af, 0x30c3 }, /* kana_tsu ッ KATAKANA LETTER SMALL TU */ + { 0x04b0, 0x30fc }, /* prolongedsound ー KATAKANA-HIRAGANA PROLONGED SOUND MARK */ + { 0x04b1, 0x30a2 }, /* kana_A ア KATAKANA LETTER A */ + { 0x04b2, 0x30a4 }, /* kana_I イ KATAKANA LETTER I */ + { 0x04b3, 0x30a6 }, /* kana_U ウ KATAKANA LETTER U */ + { 0x04b4, 0x30a8 }, /* kana_E エ KATAKANA LETTER E */ + { 0x04b5, 0x30aa }, /* kana_O オ KATAKANA LETTER O */ + { 0x04b6, 0x30ab }, /* kana_KA カ KATAKANA LETTER KA */ + { 0x04b7, 0x30ad }, /* kana_KI キ KATAKANA LETTER KI */ + { 0x04b8, 0x30af }, /* kana_KU ク KATAKANA LETTER KU */ + { 0x04b9, 0x30b1 }, /* kana_KE ケ KATAKANA LETTER KE */ + { 0x04ba, 0x30b3 }, /* kana_KO コ KATAKANA LETTER KO */ + { 0x04bb, 0x30b5 }, /* kana_SA サ KATAKANA LETTER SA */ + { 0x04bc, 0x30b7 }, /* kana_SHI シ KATAKANA LETTER SI */ + { 0x04bd, 0x30b9 }, /* kana_SU ス KATAKANA LETTER SU */ + { 0x04be, 0x30bb }, /* kana_SE セ KATAKANA LETTER SE */ + { 0x04bf, 0x30bd }, /* kana_SO ソ KATAKANA LETTER SO */ + { 0x04c0, 0x30bf }, /* kana_TA タ KATAKANA LETTER TA */ + { 0x04c1, 0x30c1 }, /* kana_CHI チ KATAKANA LETTER TI */ + { 0x04c2, 0x30c4 }, /* kana_TSU ツ KATAKANA LETTER TU */ + { 0x04c3, 0x30c6 }, /* kana_TE テ KATAKANA LETTER TE */ + { 0x04c4, 0x30c8 }, /* kana_TO ト KATAKANA LETTER TO */ + { 0x04c5, 0x30ca }, /* kana_NA ナ KATAKANA LETTER NA */ + { 0x04c6, 0x30cb }, /* kana_NI ニ KATAKANA LETTER NI */ + { 0x04c7, 0x30cc }, /* kana_NU ヌ KATAKANA LETTER NU */ + { 0x04c8, 0x30cd }, /* kana_NE ネ KATAKANA LETTER NE */ + { 0x04c9, 0x30ce }, /* kana_NO ノ KATAKANA LETTER NO */ + { 0x04ca, 0x30cf }, /* kana_HA ハ KATAKANA LETTER HA */ + { 0x04cb, 0x30d2 }, /* kana_HI ヒ KATAKANA LETTER HI */ + { 0x04cc, 0x30d5 }, /* kana_FU フ KATAKANA LETTER HU */ + { 0x04cd, 0x30d8 }, /* kana_HE ヘ KATAKANA LETTER HE */ + { 0x04ce, 0x30db }, /* kana_HO ホ KATAKANA LETTER HO */ + { 0x04cf, 0x30de }, /* kana_MA マ KATAKANA LETTER MA */ + { 0x04d0, 0x30df }, /* kana_MI ミ KATAKANA LETTER MI */ + { 0x04d1, 0x30e0 }, /* kana_MU ム KATAKANA LETTER MU */ + { 0x04d2, 0x30e1 }, /* kana_ME メ KATAKANA LETTER ME */ + { 0x04d3, 0x30e2 }, /* kana_MO モ KATAKANA LETTER MO */ + { 0x04d4, 0x30e4 }, /* kana_YA ヤ KATAKANA LETTER YA */ + { 0x04d5, 0x30e6 }, /* kana_YU ユ KATAKANA LETTER YU */ + { 0x04d6, 0x30e8 }, /* kana_YO ヨ KATAKANA LETTER YO */ + { 0x04d7, 0x30e9 }, /* kana_RA ラ KATAKANA LETTER RA */ + { 0x04d8, 0x30ea }, /* kana_RI リ KATAKANA LETTER RI */ + { 0x04d9, 0x30eb }, /* kana_RU ル KATAKANA LETTER RU */ + { 0x04da, 0x30ec }, /* kana_RE レ KATAKANA LETTER RE */ + { 0x04db, 0x30ed }, /* kana_RO ロ KATAKANA LETTER RO */ + { 0x04dc, 0x30ef }, /* kana_WA ワ KATAKANA LETTER WA */ + { 0x04dd, 0x30f3 }, /* kana_N ン KATAKANA LETTER N */ + { 0x04de, 0x309b }, /* voicedsound ゛ KATAKANA-HIRAGANA VOICED SOUND MARK */ + { 0x04df, 0x309c }, /* semivoicedsound ゜ KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK */ + { 0x05ac, 0x060c }, /* Arabic_comma ، ARABIC COMMA */ + { 0x05bb, 0x061b }, /* Arabic_semicolon ؛ ARABIC SEMICOLON */ + { 0x05bf, 0x061f }, /* Arabic_question_mark ؟ ARABIC QUESTION MARK */ + { 0x05c1, 0x0621 }, /* Arabic_hamza Ø¡ ARABIC LETTER HAMZA */ + { 0x05c2, 0x0622 }, /* Arabic_maddaonalef Ø¢ ARABIC LETTER ALEF WITH MADDA ABOVE */ + { 0x05c3, 0x0623 }, /* Arabic_hamzaonalef Ø£ ARABIC LETTER ALEF WITH HAMZA ABOVE */ + { 0x05c4, 0x0624 }, /* Arabic_hamzaonwaw ؤ ARABIC LETTER WAW WITH HAMZA ABOVE */ + { 0x05c5, 0x0625 }, /* Arabic_hamzaunderalef Ø¥ ARABIC LETTER ALEF WITH HAMZA BELOW */ + { 0x05c6, 0x0626 }, /* Arabic_hamzaonyeh ئ ARABIC LETTER YEH WITH HAMZA ABOVE */ + { 0x05c7, 0x0627 }, /* Arabic_alef ا ARABIC LETTER ALEF */ + { 0x05c8, 0x0628 }, /* Arabic_beh ب ARABIC LETTER BEH */ + { 0x05c9, 0x0629 }, /* Arabic_tehmarbuta Ø© ARABIC LETTER TEH MARBUTA */ + { 0x05ca, 0x062a }, /* Arabic_teh ت ARABIC LETTER TEH */ + { 0x05cb, 0x062b }, /* Arabic_theh Ø« ARABIC LETTER THEH */ + { 0x05cc, 0x062c }, /* Arabic_jeem ج ARABIC LETTER JEEM */ + { 0x05cd, 0x062d }, /* Arabic_hah Ø­ ARABIC LETTER HAH */ + { 0x05ce, 0x062e }, /* Arabic_khah Ø® ARABIC LETTER KHAH */ + { 0x05cf, 0x062f }, /* Arabic_dal د ARABIC LETTER DAL */ + { 0x05d0, 0x0630 }, /* Arabic_thal Ø° ARABIC LETTER THAL */ + { 0x05d1, 0x0631 }, /* Arabic_ra ر ARABIC LETTER REH */ + { 0x05d2, 0x0632 }, /* Arabic_zain ز ARABIC LETTER ZAIN */ + { 0x05d3, 0x0633 }, /* Arabic_seen س ARABIC LETTER SEEN */ + { 0x05d4, 0x0634 }, /* Arabic_sheen Ø´ ARABIC LETTER SHEEN */ + { 0x05d5, 0x0635 }, /* Arabic_sad ص ARABIC LETTER SAD */ + { 0x05d6, 0x0636 }, /* Arabic_dad ض ARABIC LETTER DAD */ + { 0x05d7, 0x0637 }, /* Arabic_tah Ø· ARABIC LETTER TAH */ + { 0x05d8, 0x0638 }, /* Arabic_zah ظ ARABIC LETTER ZAH */ + { 0x05d9, 0x0639 }, /* Arabic_ain ع ARABIC LETTER AIN */ + { 0x05da, 0x063a }, /* Arabic_ghain غ ARABIC LETTER GHAIN */ + { 0x05e0, 0x0640 }, /* Arabic_tatweel ـ ARABIC TATWEEL */ + { 0x05e1, 0x0641 }, /* Arabic_feh ف ARABIC LETTER FEH */ + { 0x05e2, 0x0642 }, /* Arabic_qaf ق ARABIC LETTER QAF */ + { 0x05e3, 0x0643 }, /* Arabic_kaf ك ARABIC LETTER KAF */ + { 0x05e4, 0x0644 }, /* Arabic_lam ل ARABIC LETTER LAM */ + { 0x05e5, 0x0645 }, /* Arabic_meem م ARABIC LETTER MEEM */ + { 0x05e6, 0x0646 }, /* Arabic_noon ن ARABIC LETTER NOON */ + { 0x05e7, 0x0647 }, /* Arabic_ha ه ARABIC LETTER HEH */ + { 0x05e8, 0x0648 }, /* Arabic_waw و ARABIC LETTER WAW */ + { 0x05e9, 0x0649 }, /* Arabic_alefmaksura ى ARABIC LETTER ALEF MAKSURA */ + { 0x05ea, 0x064a }, /* Arabic_yeh ي ARABIC LETTER YEH */ + { 0x05eb, 0x064b }, /* Arabic_fathatan ً ARABIC FATHATAN */ + { 0x05ec, 0x064c }, /* Arabic_dammatan ٌ ARABIC DAMMATAN */ + { 0x05ed, 0x064d }, /* Arabic_kasratan ٍ ARABIC KASRATAN */ + { 0x05ee, 0x064e }, /* Arabic_fatha َ ARABIC FATHA */ + { 0x05ef, 0x064f }, /* Arabic_damma ُ ARABIC DAMMA */ + { 0x05f0, 0x0650 }, /* Arabic_kasra ِ ARABIC KASRA */ + { 0x05f1, 0x0651 }, /* Arabic_shadda ّ ARABIC SHADDA */ + { 0x05f2, 0x0652 }, /* Arabic_sukun ْ ARABIC SUKUN */ + { 0x06a1, 0x0452 }, /* Serbian_dje ђ CYRILLIC SMALL LETTER DJE */ + { 0x06a2, 0x0453 }, /* Macedonia_gje ѓ CYRILLIC SMALL LETTER GJE */ + { 0x06a3, 0x0451 }, /* Cyrillic_io ё CYRILLIC SMALL LETTER IO */ + { 0x06a4, 0x0454 }, /* Ukrainian_ie є CYRILLIC SMALL LETTER UKRAINIAN IE */ + { 0x06a5, 0x0455 }, /* Macedonia_dse ѕ CYRILLIC SMALL LETTER DZE */ + { 0x06a6, 0x0456 }, /* Ukrainian_i і CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I */ + { 0x06a7, 0x0457 }, /* Ukrainian_yi ї CYRILLIC SMALL LETTER YI */ + { 0x06a8, 0x0458 }, /* Cyrillic_je ј CYRILLIC SMALL LETTER JE */ + { 0x06a9, 0x0459 }, /* Cyrillic_lje љ CYRILLIC SMALL LETTER LJE */ + { 0x06aa, 0x045a }, /* Cyrillic_nje њ CYRILLIC SMALL LETTER NJE */ + { 0x06ab, 0x045b }, /* Serbian_tshe ћ CYRILLIC SMALL LETTER TSHE */ + { 0x06ac, 0x045c }, /* Macedonia_kje ќ CYRILLIC SMALL LETTER KJE */ + { 0x06ae, 0x045e }, /* Byelorussian_shortu ў CYRILLIC SMALL LETTER SHORT U */ + { 0x06af, 0x045f }, /* Cyrillic_dzhe џ CYRILLIC SMALL LETTER DZHE */ + { 0x06b0, 0x2116 }, /* numerosign № NUMERO SIGN */ + { 0x06b1, 0x0402 }, /* Serbian_DJE Ђ CYRILLIC CAPITAL LETTER DJE */ + { 0x06b2, 0x0403 }, /* Macedonia_GJE Ѓ CYRILLIC CAPITAL LETTER GJE */ + { 0x06b3, 0x0401 }, /* Cyrillic_IO Ё CYRILLIC CAPITAL LETTER IO */ + { 0x06b4, 0x0404 }, /* Ukrainian_IE Є CYRILLIC CAPITAL LETTER UKRAINIAN IE */ + { 0x06b5, 0x0405 }, /* Macedonia_DSE Ѕ CYRILLIC CAPITAL LETTER DZE */ + { 0x06b6, 0x0406 }, /* Ukrainian_I І CYRILLIC CAPITAL LETTER BYELORUSSIAN-UKRAINIAN I */ + { 0x06b7, 0x0407 }, /* Ukrainian_YI Ї CYRILLIC CAPITAL LETTER YI */ + { 0x06b8, 0x0408 }, /* Cyrillic_JE Ј CYRILLIC CAPITAL LETTER JE */ + { 0x06b9, 0x0409 }, /* Cyrillic_LJE Љ CYRILLIC CAPITAL LETTER LJE */ + { 0x06ba, 0x040a }, /* Cyrillic_NJE Њ CYRILLIC CAPITAL LETTER NJE */ + { 0x06bb, 0x040b }, /* Serbian_TSHE Ћ CYRILLIC CAPITAL LETTER TSHE */ + { 0x06bc, 0x040c }, /* Macedonia_KJE Ќ CYRILLIC CAPITAL LETTER KJE */ + { 0x06be, 0x040e }, /* Byelorussian_SHORTU Ў CYRILLIC CAPITAL LETTER SHORT U */ + { 0x06bf, 0x040f }, /* Cyrillic_DZHE Џ CYRILLIC CAPITAL LETTER DZHE */ + { 0x06c0, 0x044e }, /* Cyrillic_yu ю CYRILLIC SMALL LETTER YU */ + { 0x06c1, 0x0430 }, /* Cyrillic_a а CYRILLIC SMALL LETTER A */ + { 0x06c2, 0x0431 }, /* Cyrillic_be б CYRILLIC SMALL LETTER BE */ + { 0x06c3, 0x0446 }, /* Cyrillic_tse ц CYRILLIC SMALL LETTER TSE */ + { 0x06c4, 0x0434 }, /* Cyrillic_de д CYRILLIC SMALL LETTER DE */ + { 0x06c5, 0x0435 }, /* Cyrillic_ie е CYRILLIC SMALL LETTER IE */ + { 0x06c6, 0x0444 }, /* Cyrillic_ef ф CYRILLIC SMALL LETTER EF */ + { 0x06c7, 0x0433 }, /* Cyrillic_ghe г CYRILLIC SMALL LETTER GHE */ + { 0x06c8, 0x0445 }, /* Cyrillic_ha х CYRILLIC SMALL LETTER HA */ + { 0x06c9, 0x0438 }, /* Cyrillic_i и CYRILLIC SMALL LETTER I */ + { 0x06ca, 0x0439 }, /* Cyrillic_shorti й CYRILLIC SMALL LETTER SHORT I */ + { 0x06cb, 0x043a }, /* Cyrillic_ka к CYRILLIC SMALL LETTER KA */ + { 0x06cc, 0x043b }, /* Cyrillic_el л CYRILLIC SMALL LETTER EL */ + { 0x06cd, 0x043c }, /* Cyrillic_em м CYRILLIC SMALL LETTER EM */ + { 0x06ce, 0x043d }, /* Cyrillic_en н CYRILLIC SMALL LETTER EN */ + { 0x06cf, 0x043e }, /* Cyrillic_o о CYRILLIC SMALL LETTER O */ + { 0x06d0, 0x043f }, /* Cyrillic_pe п CYRILLIC SMALL LETTER PE */ + { 0x06d1, 0x044f }, /* Cyrillic_ya я CYRILLIC SMALL LETTER YA */ + { 0x06d2, 0x0440 }, /* Cyrillic_er р CYRILLIC SMALL LETTER ER */ + { 0x06d3, 0x0441 }, /* Cyrillic_es с CYRILLIC SMALL LETTER ES */ + { 0x06d4, 0x0442 }, /* Cyrillic_te т CYRILLIC SMALL LETTER TE */ + { 0x06d5, 0x0443 }, /* Cyrillic_u у CYRILLIC SMALL LETTER U */ + { 0x06d6, 0x0436 }, /* Cyrillic_zhe ж CYRILLIC SMALL LETTER ZHE */ + { 0x06d7, 0x0432 }, /* Cyrillic_ve в CYRILLIC SMALL LETTER VE */ + { 0x06d8, 0x044c }, /* Cyrillic_softsign ь CYRILLIC SMALL LETTER SOFT SIGN */ + { 0x06d9, 0x044b }, /* Cyrillic_yeru ы CYRILLIC SMALL LETTER YERU */ + { 0x06da, 0x0437 }, /* Cyrillic_ze з CYRILLIC SMALL LETTER ZE */ + { 0x06db, 0x0448 }, /* Cyrillic_sha ш CYRILLIC SMALL LETTER SHA */ + { 0x06dc, 0x044d }, /* Cyrillic_e э CYRILLIC SMALL LETTER E */ + { 0x06dd, 0x0449 }, /* Cyrillic_shcha щ CYRILLIC SMALL LETTER SHCHA */ + { 0x06de, 0x0447 }, /* Cyrillic_che ч CYRILLIC SMALL LETTER CHE */ + { 0x06df, 0x044a }, /* Cyrillic_hardsign ъ CYRILLIC SMALL LETTER HARD SIGN */ + { 0x06e0, 0x042e }, /* Cyrillic_YU Ю CYRILLIC CAPITAL LETTER YU */ + { 0x06e1, 0x0410 }, /* Cyrillic_A А CYRILLIC CAPITAL LETTER A */ + { 0x06e2, 0x0411 }, /* Cyrillic_BE Б CYRILLIC CAPITAL LETTER BE */ + { 0x06e3, 0x0426 }, /* Cyrillic_TSE Ц CYRILLIC CAPITAL LETTER TSE */ + { 0x06e4, 0x0414 }, /* Cyrillic_DE Д CYRILLIC CAPITAL LETTER DE */ + { 0x06e5, 0x0415 }, /* Cyrillic_IE Е CYRILLIC CAPITAL LETTER IE */ + { 0x06e6, 0x0424 }, /* Cyrillic_EF Ф CYRILLIC CAPITAL LETTER EF */ + { 0x06e7, 0x0413 }, /* Cyrillic_GHE Г CYRILLIC CAPITAL LETTER GHE */ + { 0x06e8, 0x0425 }, /* Cyrillic_HA Ð¥ CYRILLIC CAPITAL LETTER HA */ + { 0x06e9, 0x0418 }, /* Cyrillic_I И CYRILLIC CAPITAL LETTER I */ + { 0x06ea, 0x0419 }, /* Cyrillic_SHORTI Й CYRILLIC CAPITAL LETTER SHORT I */ + { 0x06eb, 0x041a }, /* Cyrillic_KA К CYRILLIC CAPITAL LETTER KA */ + { 0x06ec, 0x041b }, /* Cyrillic_EL Л CYRILLIC CAPITAL LETTER EL */ + { 0x06ed, 0x041c }, /* Cyrillic_EM М CYRILLIC CAPITAL LETTER EM */ + { 0x06ee, 0x041d }, /* Cyrillic_EN Н CYRILLIC CAPITAL LETTER EN */ + { 0x06ef, 0x041e }, /* Cyrillic_O О CYRILLIC CAPITAL LETTER O */ + { 0x06f0, 0x041f }, /* Cyrillic_PE П CYRILLIC CAPITAL LETTER PE */ + { 0x06f1, 0x042f }, /* Cyrillic_YA Я CYRILLIC CAPITAL LETTER YA */ + { 0x06f2, 0x0420 }, /* Cyrillic_ER Р CYRILLIC CAPITAL LETTER ER */ + { 0x06f3, 0x0421 }, /* Cyrillic_ES С CYRILLIC CAPITAL LETTER ES */ + { 0x06f4, 0x0422 }, /* Cyrillic_TE Т CYRILLIC CAPITAL LETTER TE */ + { 0x06f5, 0x0423 }, /* Cyrillic_U У CYRILLIC CAPITAL LETTER U */ + { 0x06f6, 0x0416 }, /* Cyrillic_ZHE Ж CYRILLIC CAPITAL LETTER ZHE */ + { 0x06f7, 0x0412 }, /* Cyrillic_VE В CYRILLIC CAPITAL LETTER VE */ + { 0x06f8, 0x042c }, /* Cyrillic_SOFTSIGN Ь CYRILLIC CAPITAL LETTER SOFT SIGN */ + { 0x06f9, 0x042b }, /* Cyrillic_YERU Ы CYRILLIC CAPITAL LETTER YERU */ + { 0x06fa, 0x0417 }, /* Cyrillic_ZE З CYRILLIC CAPITAL LETTER ZE */ + { 0x06fb, 0x0428 }, /* Cyrillic_SHA Ш CYRILLIC CAPITAL LETTER SHA */ + { 0x06fc, 0x042d }, /* Cyrillic_E Э CYRILLIC CAPITAL LETTER E */ + { 0x06fd, 0x0429 }, /* Cyrillic_SHCHA Щ CYRILLIC CAPITAL LETTER SHCHA */ + { 0x06fe, 0x0427 }, /* Cyrillic_CHE Ч CYRILLIC CAPITAL LETTER CHE */ + { 0x06ff, 0x042a }, /* Cyrillic_HARDSIGN Ъ CYRILLIC CAPITAL LETTER HARD SIGN */ + { 0x07a1, 0x0386 }, /* Greek_ALPHAaccent Ά GREEK CAPITAL LETTER ALPHA WITH TONOS */ + { 0x07a2, 0x0388 }, /* Greek_EPSILONaccent Έ GREEK CAPITAL LETTER EPSILON WITH TONOS */ + { 0x07a3, 0x0389 }, /* Greek_ETAaccent Ή GREEK CAPITAL LETTER ETA WITH TONOS */ + { 0x07a4, 0x038a }, /* Greek_IOTAaccent Ί GREEK CAPITAL LETTER IOTA WITH TONOS */ + { 0x07a5, 0x03aa }, /* Greek_IOTAdiaeresis Ϊ GREEK CAPITAL LETTER IOTA WITH DIALYTIKA */ + { 0x07a7, 0x038c }, /* Greek_OMICRONaccent Ό GREEK CAPITAL LETTER OMICRON WITH TONOS */ + { 0x07a8, 0x038e }, /* Greek_UPSILONaccent Ύ GREEK CAPITAL LETTER UPSILON WITH TONOS */ + { 0x07a9, 0x03ab }, /* Greek_UPSILONdieresis Ϋ GREEK CAPITAL LETTER UPSILON WITH DIALYTIKA */ + { 0x07ab, 0x038f }, /* Greek_OMEGAaccent Ώ GREEK CAPITAL LETTER OMEGA WITH TONOS */ + { 0x07ae, 0x0385 }, /* Greek_accentdieresis ΅ GREEK DIALYTIKA TONOS */ + { 0x07af, 0x2015 }, /* Greek_horizbar ― HORIZONTAL BAR */ + { 0x07b1, 0x03ac }, /* Greek_alphaaccent ά GREEK SMALL LETTER ALPHA WITH TONOS */ + { 0x07b2, 0x03ad }, /* Greek_epsilonaccent έ GREEK SMALL LETTER EPSILON WITH TONOS */ + { 0x07b3, 0x03ae }, /* Greek_etaaccent ή GREEK SMALL LETTER ETA WITH TONOS */ + { 0x07b4, 0x03af }, /* Greek_iotaaccent ί GREEK SMALL LETTER IOTA WITH TONOS */ + { 0x07b5, 0x03ca }, /* Greek_iotadieresis ϊ GREEK SMALL LETTER IOTA WITH DIALYTIKA */ + { 0x07b6, 0x0390 }, /* Greek_iotaaccentdieresis ΐ GREEK SMALL LETTER IOTA WITH DIALYTIKA AND TONOS */ + { 0x07b7, 0x03cc }, /* Greek_omicronaccent ό GREEK SMALL LETTER OMICRON WITH TONOS */ + { 0x07b8, 0x03cd }, /* Greek_upsilonaccent ύ GREEK SMALL LETTER UPSILON WITH TONOS */ + { 0x07b9, 0x03cb }, /* Greek_upsilondieresis ϋ GREEK SMALL LETTER UPSILON WITH DIALYTIKA */ + { 0x07ba, 0x03b0 }, /* Greek_upsilonaccentdieresis ΰ GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND TONOS */ + { 0x07bb, 0x03ce }, /* Greek_omegaaccent ώ GREEK SMALL LETTER OMEGA WITH TONOS */ + { 0x07c1, 0x0391 }, /* Greek_ALPHA Α GREEK CAPITAL LETTER ALPHA */ + { 0x07c2, 0x0392 }, /* Greek_BETA Β GREEK CAPITAL LETTER BETA */ + { 0x07c3, 0x0393 }, /* Greek_GAMMA Γ GREEK CAPITAL LETTER GAMMA */ + { 0x07c4, 0x0394 }, /* Greek_DELTA Δ GREEK CAPITAL LETTER DELTA */ + { 0x07c5, 0x0395 }, /* Greek_EPSILON Ε GREEK CAPITAL LETTER EPSILON */ + { 0x07c6, 0x0396 }, /* Greek_ZETA Ζ GREEK CAPITAL LETTER ZETA */ + { 0x07c7, 0x0397 }, /* Greek_ETA Η GREEK CAPITAL LETTER ETA */ + { 0x07c8, 0x0398 }, /* Greek_THETA Θ GREEK CAPITAL LETTER THETA */ + { 0x07c9, 0x0399 }, /* Greek_IOTA Ι GREEK CAPITAL LETTER IOTA */ + { 0x07ca, 0x039a }, /* Greek_KAPPA Κ GREEK CAPITAL LETTER KAPPA */ + { 0x07cb, 0x039b }, /* Greek_LAMBDA Λ GREEK CAPITAL LETTER LAMDA */ + { 0x07cc, 0x039c }, /* Greek_MU Μ GREEK CAPITAL LETTER MU */ + { 0x07cd, 0x039d }, /* Greek_NU Ν GREEK CAPITAL LETTER NU */ + { 0x07ce, 0x039e }, /* Greek_XI Ξ GREEK CAPITAL LETTER XI */ + { 0x07cf, 0x039f }, /* Greek_OMICRON Ο GREEK CAPITAL LETTER OMICRON */ + { 0x07d0, 0x03a0 }, /* Greek_PI Π GREEK CAPITAL LETTER PI */ + { 0x07d1, 0x03a1 }, /* Greek_RHO Ρ GREEK CAPITAL LETTER RHO */ + { 0x07d2, 0x03a3 }, /* Greek_SIGMA Σ GREEK CAPITAL LETTER SIGMA */ + { 0x07d4, 0x03a4 }, /* Greek_TAU Τ GREEK CAPITAL LETTER TAU */ + { 0x07d5, 0x03a5 }, /* Greek_UPSILON Î¥ GREEK CAPITAL LETTER UPSILON */ + { 0x07d6, 0x03a6 }, /* Greek_PHI Φ GREEK CAPITAL LETTER PHI */ + { 0x07d7, 0x03a7 }, /* Greek_CHI Χ GREEK CAPITAL LETTER CHI */ + { 0x07d8, 0x03a8 }, /* Greek_PSI Ψ GREEK CAPITAL LETTER PSI */ + { 0x07d9, 0x03a9 }, /* Greek_OMEGA Ω GREEK CAPITAL LETTER OMEGA */ + { 0x07e1, 0x03b1 }, /* Greek_alpha α GREEK SMALL LETTER ALPHA */ + { 0x07e2, 0x03b2 }, /* Greek_beta β GREEK SMALL LETTER BETA */ + { 0x07e3, 0x03b3 }, /* Greek_gamma γ GREEK SMALL LETTER GAMMA */ + { 0x07e4, 0x03b4 }, /* Greek_delta δ GREEK SMALL LETTER DELTA */ + { 0x07e5, 0x03b5 }, /* Greek_epsilon ε GREEK SMALL LETTER EPSILON */ + { 0x07e6, 0x03b6 }, /* Greek_zeta ζ GREEK SMALL LETTER ZETA */ + { 0x07e7, 0x03b7 }, /* Greek_eta η GREEK SMALL LETTER ETA */ + { 0x07e8, 0x03b8 }, /* Greek_theta θ GREEK SMALL LETTER THETA */ + { 0x07e9, 0x03b9 }, /* Greek_iota ι GREEK SMALL LETTER IOTA */ + { 0x07ea, 0x03ba }, /* Greek_kappa κ GREEK SMALL LETTER KAPPA */ + { 0x07eb, 0x03bb }, /* Greek_lambda λ GREEK SMALL LETTER LAMDA */ + { 0x07ec, 0x03bc }, /* Greek_mu μ GREEK SMALL LETTER MU */ + { 0x07ed, 0x03bd }, /* Greek_nu ν GREEK SMALL LETTER NU */ + { 0x07ee, 0x03be }, /* Greek_xi ξ GREEK SMALL LETTER XI */ + { 0x07ef, 0x03bf }, /* Greek_omicron ο GREEK SMALL LETTER OMICRON */ + { 0x07f0, 0x03c0 }, /* Greek_pi π GREEK SMALL LETTER PI */ + { 0x07f1, 0x03c1 }, /* Greek_rho ρ GREEK SMALL LETTER RHO */ + { 0x07f2, 0x03c3 }, /* Greek_sigma σ GREEK SMALL LETTER SIGMA */ + { 0x07f3, 0x03c2 }, /* Greek_finalsmallsigma ς GREEK SMALL LETTER FINAL SIGMA */ + { 0x07f4, 0x03c4 }, /* Greek_tau τ GREEK SMALL LETTER TAU */ + { 0x07f5, 0x03c5 }, /* Greek_upsilon υ GREEK SMALL LETTER UPSILON */ + { 0x07f6, 0x03c6 }, /* Greek_phi φ GREEK SMALL LETTER PHI */ + { 0x07f7, 0x03c7 }, /* Greek_chi χ GREEK SMALL LETTER CHI */ + { 0x07f8, 0x03c8 }, /* Greek_psi ψ GREEK SMALL LETTER PSI */ + { 0x07f9, 0x03c9 }, /* Greek_omega ω GREEK SMALL LETTER OMEGA */ +/* 0x08a1 leftradical ? ??? */ +/* 0x08a2 topleftradical ? ??? */ +/* 0x08a3 horizconnector ? ??? */ + { 0x08a4, 0x2320 }, /* topintegral ⌠ TOP HALF INTEGRAL */ + { 0x08a5, 0x2321 }, /* botintegral ⌡ BOTTOM HALF INTEGRAL */ + { 0x08a6, 0x2502 }, /* vertconnector │ BOX DRAWINGS LIGHT VERTICAL */ +/* 0x08a7 topleftsqbracket ? ??? */ +/* 0x08a8 botleftsqbracket ? ??? */ +/* 0x08a9 toprightsqbracket ? ??? */ +/* 0x08aa botrightsqbracket ? ??? */ +/* 0x08ab topleftparens ? ??? */ +/* 0x08ac botleftparens ? ??? */ +/* 0x08ad toprightparens ? ??? */ +/* 0x08ae botrightparens ? ??? */ +/* 0x08af leftmiddlecurlybrace ? ??? */ +/* 0x08b0 rightmiddlecurlybrace ? ??? */ +/* 0x08b1 topleftsummation ? ??? */ +/* 0x08b2 botleftsummation ? ??? */ +/* 0x08b3 topvertsummationconnector ? ??? */ +/* 0x08b4 botvertsummationconnector ? ??? */ +/* 0x08b5 toprightsummation ? ??? */ +/* 0x08b6 botrightsummation ? ??? */ +/* 0x08b7 rightmiddlesummation ? ??? */ + { 0x08bc, 0x2264 }, /* lessthanequal ≤ LESS-THAN OR EQUAL TO */ + { 0x08bd, 0x2260 }, /* notequal ≠ NOT EQUAL TO */ + { 0x08be, 0x2265 }, /* greaterthanequal ≥ GREATER-THAN OR EQUAL TO */ + { 0x08bf, 0x222b }, /* integral ∫ INTEGRAL */ + { 0x08c0, 0x2234 }, /* therefore ∴ THEREFORE */ + { 0x08c1, 0x221d }, /* variation ∝ PROPORTIONAL TO */ + { 0x08c2, 0x221e }, /* infinity ∞ INFINITY */ + { 0x08c5, 0x2207 }, /* nabla ∇ NABLA */ + { 0x08c8, 0x2245 }, /* approximate ≅ APPROXIMATELY EQUAL TO */ +/* 0x08c9 similarequal ? ??? */ + { 0x08cd, 0x21d4 }, /* ifonlyif ⇔ LEFT RIGHT DOUBLE ARROW */ + { 0x08ce, 0x21d2 }, /* implies ⇒ RIGHTWARDS DOUBLE ARROW */ + { 0x08cf, 0x2261 }, /* identical ≡ IDENTICAL TO */ + { 0x08d6, 0x221a }, /* radical √ SQUARE ROOT */ + { 0x08da, 0x2282 }, /* includedin ⊂ SUBSET OF */ + { 0x08db, 0x2283 }, /* includes ⊃ SUPERSET OF */ + { 0x08dc, 0x2229 }, /* intersection ∩ INTERSECTION */ + { 0x08dd, 0x222a }, /* union ∪ UNION */ + { 0x08de, 0x2227 }, /* logicaland ∧ LOGICAL AND */ + { 0x08df, 0x2228 }, /* logicalor ∨ LOGICAL OR */ + { 0x08ef, 0x2202 }, /* partialderivative ∂ PARTIAL DIFFERENTIAL */ + { 0x08f6, 0x0192 }, /* function ƒ LATIN SMALL LETTER F WITH HOOK */ + { 0x08fb, 0x2190 }, /* leftarrow ← LEFTWARDS ARROW */ + { 0x08fc, 0x2191 }, /* uparrow ↑ UPWARDS ARROW */ + { 0x08fd, 0x2192 }, /* rightarrow → RIGHTWARDS ARROW */ + { 0x08fe, 0x2193 }, /* downarrow ↓ DOWNWARDS ARROW */ + { 0x09df, 0x2422 }, /* blank ␢ BLANK SYMBOL */ + { 0x09e0, 0x25c6 }, /* soliddiamond ◆ BLACK DIAMOND */ + { 0x09e1, 0x2592 }, /* checkerboard ▒ MEDIUM SHADE */ + { 0x09e2, 0x2409 }, /* ht ␉ SYMBOL FOR HORIZONTAL TABULATION */ + { 0x09e3, 0x240c }, /* ff ␌ SYMBOL FOR FORM FEED */ + { 0x09e4, 0x240d }, /* cr ␍ SYMBOL FOR CARRIAGE RETURN */ + { 0x09e5, 0x240a }, /* lf ␊ SYMBOL FOR LINE FEED */ + { 0x09e8, 0x2424 }, /* nl ␤ SYMBOL FOR NEWLINE */ + { 0x09e9, 0x240b }, /* vt ␋ SYMBOL FOR VERTICAL TABULATION */ + { 0x09ea, 0x2518 }, /* lowrightcorner ┘ BOX DRAWINGS LIGHT UP AND LEFT */ + { 0x09eb, 0x2510 }, /* uprightcorner ┐ BOX DRAWINGS LIGHT DOWN AND LEFT */ + { 0x09ec, 0x250c }, /* upleftcorner ┌ BOX DRAWINGS LIGHT DOWN AND RIGHT */ + { 0x09ed, 0x2514 }, /* lowleftcorner └ BOX DRAWINGS LIGHT UP AND RIGHT */ + { 0x09ee, 0x253c }, /* crossinglines ┼ BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL */ +/* 0x09ef horizlinescan1 ? ??? */ +/* 0x09f0 horizlinescan3 ? ??? */ + { 0x09f1, 0x2500 }, /* horizlinescan5 ─ BOX DRAWINGS LIGHT HORIZONTAL */ +/* 0x09f2 horizlinescan7 ? ??? */ +/* 0x09f3 horizlinescan9 ? ??? */ + { 0x09f4, 0x251c }, /* leftt ├ BOX DRAWINGS LIGHT VERTICAL AND RIGHT */ + { 0x09f5, 0x2524 }, /* rightt ┤ BOX DRAWINGS LIGHT VERTICAL AND LEFT */ + { 0x09f6, 0x2534 }, /* bott ┴ BOX DRAWINGS LIGHT UP AND HORIZONTAL */ + { 0x09f7, 0x252c }, /* topt ┬ BOX DRAWINGS LIGHT DOWN AND HORIZONTAL */ + { 0x09f8, 0x2502 }, /* vertbar │ BOX DRAWINGS LIGHT VERTICAL */ + { 0x0aa1, 0x2003 }, /* emspace   EM SPACE */ + { 0x0aa2, 0x2002 }, /* enspace   EN SPACE */ + { 0x0aa3, 0x2004 }, /* em3space   THREE-PER-EM SPACE */ + { 0x0aa4, 0x2005 }, /* em4space   FOUR-PER-EM SPACE */ + { 0x0aa5, 0x2007 }, /* digitspace   FIGURE SPACE */ + { 0x0aa6, 0x2008 }, /* punctspace   PUNCTUATION SPACE */ + { 0x0aa7, 0x2009 }, /* thinspace   THIN SPACE */ + { 0x0aa8, 0x200a }, /* hairspace   HAIR SPACE */ + { 0x0aa9, 0x2014 }, /* emdash — EM DASH */ + { 0x0aaa, 0x2013 }, /* endash – EN DASH */ +/* 0x0aac signifblank ? ??? */ + { 0x0aae, 0x2026 }, /* ellipsis … HORIZONTAL ELLIPSIS */ +/* 0x0aaf doubbaselinedot ? ??? */ + { 0x0ab0, 0x2153 }, /* onethird ⅓ VULGAR FRACTION ONE THIRD */ + { 0x0ab1, 0x2154 }, /* twothirds ⅔ VULGAR FRACTION TWO THIRDS */ + { 0x0ab2, 0x2155 }, /* onefifth ⅕ VULGAR FRACTION ONE FIFTH */ + { 0x0ab3, 0x2156 }, /* twofifths ⅖ VULGAR FRACTION TWO FIFTHS */ + { 0x0ab4, 0x2157 }, /* threefifths ⅗ VULGAR FRACTION THREE FIFTHS */ + { 0x0ab5, 0x2158 }, /* fourfifths ⅘ VULGAR FRACTION FOUR FIFTHS */ + { 0x0ab6, 0x2159 }, /* onesixth ⅙ VULGAR FRACTION ONE SIXTH */ + { 0x0ab7, 0x215a }, /* fivesixths ⅚ VULGAR FRACTION FIVE SIXTHS */ + { 0x0ab8, 0x2105 }, /* careof ℅ CARE OF */ + { 0x0abb, 0x2012 }, /* figdash ‒ FIGURE DASH */ + { 0x0abc, 0x2329 }, /* leftanglebracket 〈 LEFT-POINTING ANGLE BRACKET */ + { 0x0abd, 0x002e }, /* decimalpoint . FULL STOP */ + { 0x0abe, 0x232a }, /* rightanglebracket 〉 RIGHT-POINTING ANGLE BRACKET */ +/* 0x0abf marker ? ??? */ + { 0x0ac3, 0x215b }, /* oneeighth ⅛ VULGAR FRACTION ONE EIGHTH */ + { 0x0ac4, 0x215c }, /* threeeighths ⅜ VULGAR FRACTION THREE EIGHTHS */ + { 0x0ac5, 0x215d }, /* fiveeighths ⅝ VULGAR FRACTION FIVE EIGHTHS */ + { 0x0ac6, 0x215e }, /* seveneighths ⅞ VULGAR FRACTION SEVEN EIGHTHS */ + { 0x0ac9, 0x2122 }, /* trademark ™ TRADE MARK SIGN */ + { 0x0aca, 0x2613 }, /* signaturemark ☓ SALTIRE */ +/* 0x0acb trademarkincircle ? ??? */ + { 0x0acc, 0x25c1 }, /* leftopentriangle ◁ WHITE LEFT-POINTING TRIANGLE */ + { 0x0acd, 0x25b7 }, /* rightopentriangle ▷ WHITE RIGHT-POINTING TRIANGLE */ + { 0x0ace, 0x25cb }, /* emopencircle ○ WHITE CIRCLE */ + { 0x0acf, 0x25a1 }, /* emopenrectangle □ WHITE SQUARE */ + { 0x0ad0, 0x2018 }, /* leftsinglequotemark ‘ LEFT SINGLE QUOTATION MARK */ + { 0x0ad1, 0x2019 }, /* rightsinglequotemark ’ RIGHT SINGLE QUOTATION MARK */ + { 0x0ad2, 0x201c }, /* leftdoublequotemark “ LEFT DOUBLE QUOTATION MARK */ + { 0x0ad3, 0x201d }, /* rightdoublequotemark ” RIGHT DOUBLE QUOTATION MARK */ + { 0x0ad4, 0x211e }, /* prescription ℞ PRESCRIPTION TAKE */ + { 0x0ad6, 0x2032 }, /* minutes ′ PRIME */ + { 0x0ad7, 0x2033 }, /* seconds ″ DOUBLE PRIME */ + { 0x0ad9, 0x271d }, /* latincross ✝ LATIN CROSS */ +/* 0x0ada hexagram ? ??? */ + { 0x0adb, 0x25ac }, /* filledrectbullet ▬ BLACK RECTANGLE */ + { 0x0adc, 0x25c0 }, /* filledlefttribullet ◀ BLACK LEFT-POINTING TRIANGLE */ + { 0x0add, 0x25b6 }, /* filledrighttribullet ▶ BLACK RIGHT-POINTING TRIANGLE */ + { 0x0ade, 0x25cf }, /* emfilledcircle ● BLACK CIRCLE */ + { 0x0adf, 0x25a0 }, /* emfilledrect ■ BLACK SQUARE */ + { 0x0ae0, 0x25e6 }, /* enopencircbullet ◦ WHITE BULLET */ + { 0x0ae1, 0x25ab }, /* enopensquarebullet ▫ WHITE SMALL SQUARE */ + { 0x0ae2, 0x25ad }, /* openrectbullet ▭ WHITE RECTANGLE */ + { 0x0ae3, 0x25b3 }, /* opentribulletup △ WHITE UP-POINTING TRIANGLE */ + { 0x0ae4, 0x25bd }, /* opentribulletdown ▽ WHITE DOWN-POINTING TRIANGLE */ + { 0x0ae5, 0x2606 }, /* openstar ☆ WHITE STAR */ + { 0x0ae6, 0x2022 }, /* enfilledcircbullet • BULLET */ + { 0x0ae7, 0x25aa }, /* enfilledsqbullet ▪ BLACK SMALL SQUARE */ + { 0x0ae8, 0x25b2 }, /* filledtribulletup ▲ BLACK UP-POINTING TRIANGLE */ + { 0x0ae9, 0x25bc }, /* filledtribulletdown ▼ BLACK DOWN-POINTING TRIANGLE */ + { 0x0aea, 0x261c }, /* leftpointer ☜ WHITE LEFT POINTING INDEX */ + { 0x0aeb, 0x261e }, /* rightpointer ☞ WHITE RIGHT POINTING INDEX */ + { 0x0aec, 0x2663 }, /* club ♣ BLACK CLUB SUIT */ + { 0x0aed, 0x2666 }, /* diamond ♦ BLACK DIAMOND SUIT */ + { 0x0aee, 0x2665 }, /* heart ♥ BLACK HEART SUIT */ + { 0x0af0, 0x2720 }, /* maltesecross ✠ MALTESE CROSS */ + { 0x0af1, 0x2020 }, /* dagger † DAGGER */ + { 0x0af2, 0x2021 }, /* doubledagger ‡ DOUBLE DAGGER */ + { 0x0af3, 0x2713 }, /* checkmark ✓ CHECK MARK */ + { 0x0af4, 0x2717 }, /* ballotcross ✗ BALLOT X */ + { 0x0af5, 0x266f }, /* musicalsharp ♯ MUSIC SHARP SIGN */ + { 0x0af6, 0x266d }, /* musicalflat ♭ MUSIC FLAT SIGN */ + { 0x0af7, 0x2642 }, /* malesymbol ♂ MALE SIGN */ + { 0x0af8, 0x2640 }, /* femalesymbol ♀ FEMALE SIGN */ + { 0x0af9, 0x260e }, /* telephone ☎ BLACK TELEPHONE */ + { 0x0afa, 0x2315 }, /* telephonerecorder ⌕ TELEPHONE RECORDER */ + { 0x0afb, 0x2117 }, /* phonographcopyright ℗ SOUND RECORDING COPYRIGHT */ + { 0x0afc, 0x2038 }, /* caret ‸ CARET */ + { 0x0afd, 0x201a }, /* singlelowquotemark ‚ SINGLE LOW-9 QUOTATION MARK */ + { 0x0afe, 0x201e }, /* doublelowquotemark „ DOUBLE LOW-9 QUOTATION MARK */ +/* 0x0aff cursor ? ??? */ + { 0x0ba3, 0x003c }, /* leftcaret < LESS-THAN SIGN */ + { 0x0ba6, 0x003e }, /* rightcaret > GREATER-THAN SIGN */ + { 0x0ba8, 0x2228 }, /* downcaret ∨ LOGICAL OR */ + { 0x0ba9, 0x2227 }, /* upcaret ∧ LOGICAL AND */ + { 0x0bc0, 0x00af }, /* overbar ¯ MACRON */ + { 0x0bc2, 0x22a4 }, /* downtack ⊤ DOWN TACK */ + { 0x0bc3, 0x2229 }, /* upshoe ∩ INTERSECTION */ + { 0x0bc4, 0x230a }, /* downstile ⌊ LEFT FLOOR */ + { 0x0bc6, 0x005f }, /* underbar _ LOW LINE */ + { 0x0bca, 0x2218 }, /* jot ∘ RING OPERATOR */ + { 0x0bcc, 0x2395 }, /* quad ⎕ APL FUNCTIONAL SYMBOL QUAD (Unicode 3.0) */ + { 0x0bce, 0x22a5 }, /* uptack ⊥ UP TACK */ + { 0x0bcf, 0x25cb }, /* circle ○ WHITE CIRCLE */ + { 0x0bd3, 0x2308 }, /* upstile ⌈ LEFT CEILING */ + { 0x0bd6, 0x222a }, /* downshoe ∪ UNION */ + { 0x0bd8, 0x2283 }, /* rightshoe ⊃ SUPERSET OF */ + { 0x0bda, 0x2282 }, /* leftshoe ⊂ SUBSET OF */ + { 0x0bdc, 0x22a3 }, /* lefttack ⊣ LEFT TACK */ + { 0x0bfc, 0x22a2 }, /* righttack ⊢ RIGHT TACK */ + { 0x0cdf, 0x2017 }, /* hebrew_doublelowline ‗ DOUBLE LOW LINE */ + { 0x0ce0, 0x05d0 }, /* hebrew_aleph א HEBREW LETTER ALEF */ + { 0x0ce1, 0x05d1 }, /* hebrew_bet ב HEBREW LETTER BET */ + { 0x0ce2, 0x05d2 }, /* hebrew_gimel ג HEBREW LETTER GIMEL */ + { 0x0ce3, 0x05d3 }, /* hebrew_dalet ד HEBREW LETTER DALET */ + { 0x0ce4, 0x05d4 }, /* hebrew_he ה HEBREW LETTER HE */ + { 0x0ce5, 0x05d5 }, /* hebrew_waw ו HEBREW LETTER VAV */ + { 0x0ce6, 0x05d6 }, /* hebrew_zain ז HEBREW LETTER ZAYIN */ + { 0x0ce7, 0x05d7 }, /* hebrew_chet ח HEBREW LETTER HET */ + { 0x0ce8, 0x05d8 }, /* hebrew_tet ט HEBREW LETTER TET */ + { 0x0ce9, 0x05d9 }, /* hebrew_yod י HEBREW LETTER YOD */ + { 0x0cea, 0x05da }, /* hebrew_finalkaph ך HEBREW LETTER FINAL KAF */ + { 0x0ceb, 0x05db }, /* hebrew_kaph כ HEBREW LETTER KAF */ + { 0x0cec, 0x05dc }, /* hebrew_lamed ל HEBREW LETTER LAMED */ + { 0x0ced, 0x05dd }, /* hebrew_finalmem ם HEBREW LETTER FINAL MEM */ + { 0x0cee, 0x05de }, /* hebrew_mem מ HEBREW LETTER MEM */ + { 0x0cef, 0x05df }, /* hebrew_finalnun ן HEBREW LETTER FINAL NUN */ + { 0x0cf0, 0x05e0 }, /* hebrew_nun ×  HEBREW LETTER NUN */ + { 0x0cf1, 0x05e1 }, /* hebrew_samech ס HEBREW LETTER SAMEKH */ + { 0x0cf2, 0x05e2 }, /* hebrew_ayin ×¢ HEBREW LETTER AYIN */ + { 0x0cf3, 0x05e3 }, /* hebrew_finalpe ×£ HEBREW LETTER FINAL PE */ + { 0x0cf4, 0x05e4 }, /* hebrew_pe פ HEBREW LETTER PE */ + { 0x0cf5, 0x05e5 }, /* hebrew_finalzade ×¥ HEBREW LETTER FINAL TSADI */ + { 0x0cf6, 0x05e6 }, /* hebrew_zade צ HEBREW LETTER TSADI */ + { 0x0cf7, 0x05e7 }, /* hebrew_qoph ק HEBREW LETTER QOF */ + { 0x0cf8, 0x05e8 }, /* hebrew_resh ר HEBREW LETTER RESH */ + { 0x0cf9, 0x05e9 }, /* hebrew_shin ש HEBREW LETTER SHIN */ + { 0x0cfa, 0x05ea }, /* hebrew_taw ת HEBREW LETTER TAV */ + { 0x0da1, 0x0e01 }, /* Thai_kokai ก THAI CHARACTER KO KAI */ + { 0x0da2, 0x0e02 }, /* Thai_khokhai ข THAI CHARACTER KHO KHAI */ + { 0x0da3, 0x0e03 }, /* Thai_khokhuat ฃ THAI CHARACTER KHO KHUAT */ + { 0x0da4, 0x0e04 }, /* Thai_khokhwai ค THAI CHARACTER KHO KHWAI */ + { 0x0da5, 0x0e05 }, /* Thai_khokhon ฅ THAI CHARACTER KHO KHON */ + { 0x0da6, 0x0e06 }, /* Thai_khorakhang ฆ THAI CHARACTER KHO RAKHANG */ + { 0x0da7, 0x0e07 }, /* Thai_ngongu ง THAI CHARACTER NGO NGU */ + { 0x0da8, 0x0e08 }, /* Thai_chochan จ THAI CHARACTER CHO CHAN */ + { 0x0da9, 0x0e09 }, /* Thai_choching ฉ THAI CHARACTER CHO CHING */ + { 0x0daa, 0x0e0a }, /* Thai_chochang ช THAI CHARACTER CHO CHANG */ + { 0x0dab, 0x0e0b }, /* Thai_soso ซ THAI CHARACTER SO SO */ + { 0x0dac, 0x0e0c }, /* Thai_chochoe ฌ THAI CHARACTER CHO CHOE */ + { 0x0dad, 0x0e0d }, /* Thai_yoying ญ THAI CHARACTER YO YING */ + { 0x0dae, 0x0e0e }, /* Thai_dochada ฎ THAI CHARACTER DO CHADA */ + { 0x0daf, 0x0e0f }, /* Thai_topatak ฏ THAI CHARACTER TO PATAK */ + { 0x0db0, 0x0e10 }, /* Thai_thothan ฐ THAI CHARACTER THO THAN */ + { 0x0db1, 0x0e11 }, /* Thai_thonangmontho ฑ THAI CHARACTER THO NANGMONTHO */ + { 0x0db2, 0x0e12 }, /* Thai_thophuthao ฒ THAI CHARACTER THO PHUTHAO */ + { 0x0db3, 0x0e13 }, /* Thai_nonen ณ THAI CHARACTER NO NEN */ + { 0x0db4, 0x0e14 }, /* Thai_dodek ด THAI CHARACTER DO DEK */ + { 0x0db5, 0x0e15 }, /* Thai_totao ต THAI CHARACTER TO TAO */ + { 0x0db6, 0x0e16 }, /* Thai_thothung ถ THAI CHARACTER THO THUNG */ + { 0x0db7, 0x0e17 }, /* Thai_thothahan ท THAI CHARACTER THO THAHAN */ + { 0x0db8, 0x0e18 }, /* Thai_thothong ธ THAI CHARACTER THO THONG */ + { 0x0db9, 0x0e19 }, /* Thai_nonu น THAI CHARACTER NO NU */ + { 0x0dba, 0x0e1a }, /* Thai_bobaimai บ THAI CHARACTER BO BAIMAI */ + { 0x0dbb, 0x0e1b }, /* Thai_popla ป THAI CHARACTER PO PLA */ + { 0x0dbc, 0x0e1c }, /* Thai_phophung ผ THAI CHARACTER PHO PHUNG */ + { 0x0dbd, 0x0e1d }, /* Thai_fofa ฝ THAI CHARACTER FO FA */ + { 0x0dbe, 0x0e1e }, /* Thai_phophan พ THAI CHARACTER PHO PHAN */ + { 0x0dbf, 0x0e1f }, /* Thai_fofan ฟ THAI CHARACTER FO FAN */ + { 0x0dc0, 0x0e20 }, /* Thai_phosamphao ภ THAI CHARACTER PHO SAMPHAO */ + { 0x0dc1, 0x0e21 }, /* Thai_moma ม THAI CHARACTER MO MA */ + { 0x0dc2, 0x0e22 }, /* Thai_yoyak ย THAI CHARACTER YO YAK */ + { 0x0dc3, 0x0e23 }, /* Thai_rorua ร THAI CHARACTER RO RUA */ + { 0x0dc4, 0x0e24 }, /* Thai_ru ฤ THAI CHARACTER RU */ + { 0x0dc5, 0x0e25 }, /* Thai_loling ล THAI CHARACTER LO LING */ + { 0x0dc6, 0x0e26 }, /* Thai_lu ฦ THAI CHARACTER LU */ + { 0x0dc7, 0x0e27 }, /* Thai_wowaen ว THAI CHARACTER WO WAEN */ + { 0x0dc8, 0x0e28 }, /* Thai_sosala ศ THAI CHARACTER SO SALA */ + { 0x0dc9, 0x0e29 }, /* Thai_sorusi ษ THAI CHARACTER SO RUSI */ + { 0x0dca, 0x0e2a }, /* Thai_sosua ส THAI CHARACTER SO SUA */ + { 0x0dcb, 0x0e2b }, /* Thai_hohip ห THAI CHARACTER HO HIP */ + { 0x0dcc, 0x0e2c }, /* Thai_lochula ฬ THAI CHARACTER LO CHULA */ + { 0x0dcd, 0x0e2d }, /* Thai_oang อ THAI CHARACTER O ANG */ + { 0x0dce, 0x0e2e }, /* Thai_honokhuk ฮ THAI CHARACTER HO NOKHUK */ + { 0x0dcf, 0x0e2f }, /* Thai_paiyannoi ฯ THAI CHARACTER PAIYANNOI */ + { 0x0dd0, 0x0e30 }, /* Thai_saraa ะ THAI CHARACTER SARA A */ + { 0x0dd1, 0x0e31 }, /* Thai_maihanakat ั THAI CHARACTER MAI HAN-AKAT */ + { 0x0dd2, 0x0e32 }, /* Thai_saraaa า THAI CHARACTER SARA AA */ + { 0x0dd3, 0x0e33 }, /* Thai_saraam ำ THAI CHARACTER SARA AM */ + { 0x0dd4, 0x0e34 }, /* Thai_sarai ิ THAI CHARACTER SARA I */ + { 0x0dd5, 0x0e35 }, /* Thai_saraii ี THAI CHARACTER SARA II */ + { 0x0dd6, 0x0e36 }, /* Thai_saraue ึ THAI CHARACTER SARA UE */ + { 0x0dd7, 0x0e37 }, /* Thai_sarauee ื THAI CHARACTER SARA UEE */ + { 0x0dd8, 0x0e38 }, /* Thai_sarau ุ THAI CHARACTER SARA U */ + { 0x0dd9, 0x0e39 }, /* Thai_sarauu ู THAI CHARACTER SARA UU */ + { 0x0dda, 0x0e3a }, /* Thai_phinthu ฺ THAI CHARACTER PHINTHU */ + { 0x0dde, 0x0e3e }, /* Thai_maihanakat_maitho ฾ ??? */ + { 0x0ddf, 0x0e3f }, /* Thai_baht ฿ THAI CURRENCY SYMBOL BAHT */ + { 0x0de0, 0x0e40 }, /* Thai_sarae เ THAI CHARACTER SARA E */ + { 0x0de1, 0x0e41 }, /* Thai_saraae แ THAI CHARACTER SARA AE */ + { 0x0de2, 0x0e42 }, /* Thai_sarao โ THAI CHARACTER SARA O */ + { 0x0de3, 0x0e43 }, /* Thai_saraaimaimuan ใ THAI CHARACTER SARA AI MAIMUAN */ + { 0x0de4, 0x0e44 }, /* Thai_saraaimaimalai ไ THAI CHARACTER SARA AI MAIMALAI */ + { 0x0de5, 0x0e45 }, /* Thai_lakkhangyao ๅ THAI CHARACTER LAKKHANGYAO */ + { 0x0de6, 0x0e46 }, /* Thai_maiyamok ๆ THAI CHARACTER MAIYAMOK */ + { 0x0de7, 0x0e47 }, /* Thai_maitaikhu ็ THAI CHARACTER MAITAIKHU */ + { 0x0de8, 0x0e48 }, /* Thai_maiek ่ THAI CHARACTER MAI EK */ + { 0x0de9, 0x0e49 }, /* Thai_maitho ้ THAI CHARACTER MAI THO */ + { 0x0dea, 0x0e4a }, /* Thai_maitri ๊ THAI CHARACTER MAI TRI */ + { 0x0deb, 0x0e4b }, /* Thai_maichattawa ๋ THAI CHARACTER MAI CHATTAWA */ + { 0x0dec, 0x0e4c }, /* Thai_thanthakhat ์ THAI CHARACTER THANTHAKHAT */ + { 0x0ded, 0x0e4d }, /* Thai_nikhahit ํ THAI CHARACTER NIKHAHIT */ + { 0x0df0, 0x0e50 }, /* Thai_leksun ๐ THAI DIGIT ZERO */ + { 0x0df1, 0x0e51 }, /* Thai_leknung ๑ THAI DIGIT ONE */ + { 0x0df2, 0x0e52 }, /* Thai_leksong ๒ THAI DIGIT TWO */ + { 0x0df3, 0x0e53 }, /* Thai_leksam ๓ THAI DIGIT THREE */ + { 0x0df4, 0x0e54 }, /* Thai_leksi ๔ THAI DIGIT FOUR */ + { 0x0df5, 0x0e55 }, /* Thai_lekha ๕ THAI DIGIT FIVE */ + { 0x0df6, 0x0e56 }, /* Thai_lekhok ๖ THAI DIGIT SIX */ + { 0x0df7, 0x0e57 }, /* Thai_lekchet ๗ THAI DIGIT SEVEN */ + { 0x0df8, 0x0e58 }, /* Thai_lekpaet ๘ THAI DIGIT EIGHT */ + { 0x0df9, 0x0e59 }, /* Thai_lekkao ๙ THAI DIGIT NINE */ + { 0x0ea1, 0x3131 }, /* Hangul_Kiyeog ㄱ HANGUL LETTER KIYEOK */ + { 0x0ea2, 0x3132 }, /* Hangul_SsangKiyeog ㄲ HANGUL LETTER SSANGKIYEOK */ + { 0x0ea3, 0x3133 }, /* Hangul_KiyeogSios ㄳ HANGUL LETTER KIYEOK-SIOS */ + { 0x0ea4, 0x3134 }, /* Hangul_Nieun ㄴ HANGUL LETTER NIEUN */ + { 0x0ea5, 0x3135 }, /* Hangul_NieunJieuj ㄵ HANGUL LETTER NIEUN-CIEUC */ + { 0x0ea6, 0x3136 }, /* Hangul_NieunHieuh ㄶ HANGUL LETTER NIEUN-HIEUH */ + { 0x0ea7, 0x3137 }, /* Hangul_Dikeud ㄷ HANGUL LETTER TIKEUT */ + { 0x0ea8, 0x3138 }, /* Hangul_SsangDikeud ㄸ HANGUL LETTER SSANGTIKEUT */ + { 0x0ea9, 0x3139 }, /* Hangul_Rieul ㄹ HANGUL LETTER RIEUL */ + { 0x0eaa, 0x313a }, /* Hangul_RieulKiyeog ㄺ HANGUL LETTER RIEUL-KIYEOK */ + { 0x0eab, 0x313b }, /* Hangul_RieulMieum ㄻ HANGUL LETTER RIEUL-MIEUM */ + { 0x0eac, 0x313c }, /* Hangul_RieulPieub ㄼ HANGUL LETTER RIEUL-PIEUP */ + { 0x0ead, 0x313d }, /* Hangul_RieulSios ㄽ HANGUL LETTER RIEUL-SIOS */ + { 0x0eae, 0x313e }, /* Hangul_RieulTieut ㄾ HANGUL LETTER RIEUL-THIEUTH */ + { 0x0eaf, 0x313f }, /* Hangul_RieulPhieuf ㄿ HANGUL LETTER RIEUL-PHIEUPH */ + { 0x0eb0, 0x3140 }, /* Hangul_RieulHieuh ㅀ HANGUL LETTER RIEUL-HIEUH */ + { 0x0eb1, 0x3141 }, /* Hangul_Mieum ㅁ HANGUL LETTER MIEUM */ + { 0x0eb2, 0x3142 }, /* Hangul_Pieub ㅂ HANGUL LETTER PIEUP */ + { 0x0eb3, 0x3143 }, /* Hangul_SsangPieub ㅃ HANGUL LETTER SSANGPIEUP */ + { 0x0eb4, 0x3144 }, /* Hangul_PieubSios ㅄ HANGUL LETTER PIEUP-SIOS */ + { 0x0eb5, 0x3145 }, /* Hangul_Sios ㅅ HANGUL LETTER SIOS */ + { 0x0eb6, 0x3146 }, /* Hangul_SsangSios ㅆ HANGUL LETTER SSANGSIOS */ + { 0x0eb7, 0x3147 }, /* Hangul_Ieung ㅇ HANGUL LETTER IEUNG */ + { 0x0eb8, 0x3148 }, /* Hangul_Jieuj ㅈ HANGUL LETTER CIEUC */ + { 0x0eb9, 0x3149 }, /* Hangul_SsangJieuj ㅉ HANGUL LETTER SSANGCIEUC */ + { 0x0eba, 0x314a }, /* Hangul_Cieuc ㅊ HANGUL LETTER CHIEUCH */ + { 0x0ebb, 0x314b }, /* Hangul_Khieuq ㅋ HANGUL LETTER KHIEUKH */ + { 0x0ebc, 0x314c }, /* Hangul_Tieut ㅌ HANGUL LETTER THIEUTH */ + { 0x0ebd, 0x314d }, /* Hangul_Phieuf ㅍ HANGUL LETTER PHIEUPH */ + { 0x0ebe, 0x314e }, /* Hangul_Hieuh ㅎ HANGUL LETTER HIEUH */ + { 0x0ebf, 0x314f }, /* Hangul_A ㅏ HANGUL LETTER A */ + { 0x0ec0, 0x3150 }, /* Hangul_AE ㅐ HANGUL LETTER AE */ + { 0x0ec1, 0x3151 }, /* Hangul_YA ㅑ HANGUL LETTER YA */ + { 0x0ec2, 0x3152 }, /* Hangul_YAE ㅒ HANGUL LETTER YAE */ + { 0x0ec3, 0x3153 }, /* Hangul_EO ㅓ HANGUL LETTER EO */ + { 0x0ec4, 0x3154 }, /* Hangul_E ㅔ HANGUL LETTER E */ + { 0x0ec5, 0x3155 }, /* Hangul_YEO ㅕ HANGUL LETTER YEO */ + { 0x0ec6, 0x3156 }, /* Hangul_YE ㅖ HANGUL LETTER YE */ + { 0x0ec7, 0x3157 }, /* Hangul_O ㅗ HANGUL LETTER O */ + { 0x0ec8, 0x3158 }, /* Hangul_WA ㅘ HANGUL LETTER WA */ + { 0x0ec9, 0x3159 }, /* Hangul_WAE ㅙ HANGUL LETTER WAE */ + { 0x0eca, 0x315a }, /* Hangul_OE ㅚ HANGUL LETTER OE */ + { 0x0ecb, 0x315b }, /* Hangul_YO ㅛ HANGUL LETTER YO */ + { 0x0ecc, 0x315c }, /* Hangul_U ㅜ HANGUL LETTER U */ + { 0x0ecd, 0x315d }, /* Hangul_WEO ㅝ HANGUL LETTER WEO */ + { 0x0ece, 0x315e }, /* Hangul_WE ㅞ HANGUL LETTER WE */ + { 0x0ecf, 0x315f }, /* Hangul_WI ㅟ HANGUL LETTER WI */ + { 0x0ed0, 0x3160 }, /* Hangul_YU ㅠ HANGUL LETTER YU */ + { 0x0ed1, 0x3161 }, /* Hangul_EU ㅡ HANGUL LETTER EU */ + { 0x0ed2, 0x3162 }, /* Hangul_YI ㅢ HANGUL LETTER YI */ + { 0x0ed3, 0x3163 }, /* Hangul_I ㅣ HANGUL LETTER I */ + { 0x0ed4, 0x11a8 }, /* Hangul_J_Kiyeog ᆨ HANGUL JONGSEONG KIYEOK */ + { 0x0ed5, 0x11a9 }, /* Hangul_J_SsangKiyeog ᆩ HANGUL JONGSEONG SSANGKIYEOK */ + { 0x0ed6, 0x11aa }, /* Hangul_J_KiyeogSios ᆪ HANGUL JONGSEONG KIYEOK-SIOS */ + { 0x0ed7, 0x11ab }, /* Hangul_J_Nieun ᆫ HANGUL JONGSEONG NIEUN */ + { 0x0ed8, 0x11ac }, /* Hangul_J_NieunJieuj ᆬ HANGUL JONGSEONG NIEUN-CIEUC */ + { 0x0ed9, 0x11ad }, /* Hangul_J_NieunHieuh ᆭ HANGUL JONGSEONG NIEUN-HIEUH */ + { 0x0eda, 0x11ae }, /* Hangul_J_Dikeud ᆮ HANGUL JONGSEONG TIKEUT */ + { 0x0edb, 0x11af }, /* Hangul_J_Rieul ᆯ HANGUL JONGSEONG RIEUL */ + { 0x0edc, 0x11b0 }, /* Hangul_J_RieulKiyeog ᆰ HANGUL JONGSEONG RIEUL-KIYEOK */ + { 0x0edd, 0x11b1 }, /* Hangul_J_RieulMieum ᆱ HANGUL JONGSEONG RIEUL-MIEUM */ + { 0x0ede, 0x11b2 }, /* Hangul_J_RieulPieub ᆲ HANGUL JONGSEONG RIEUL-PIEUP */ + { 0x0edf, 0x11b3 }, /* Hangul_J_RieulSios ᆳ HANGUL JONGSEONG RIEUL-SIOS */ + { 0x0ee0, 0x11b4 }, /* Hangul_J_RieulTieut ᆴ HANGUL JONGSEONG RIEUL-THIEUTH */ + { 0x0ee1, 0x11b5 }, /* Hangul_J_RieulPhieuf ᆵ HANGUL JONGSEONG RIEUL-PHIEUPH */ + { 0x0ee2, 0x11b6 }, /* Hangul_J_RieulHieuh ᆶ HANGUL JONGSEONG RIEUL-HIEUH */ + { 0x0ee3, 0x11b7 }, /* Hangul_J_Mieum ᆷ HANGUL JONGSEONG MIEUM */ + { 0x0ee4, 0x11b8 }, /* Hangul_J_Pieub ᆸ HANGUL JONGSEONG PIEUP */ + { 0x0ee5, 0x11b9 }, /* Hangul_J_PieubSios ᆹ HANGUL JONGSEONG PIEUP-SIOS */ + { 0x0ee6, 0x11ba }, /* Hangul_J_Sios ᆺ HANGUL JONGSEONG SIOS */ + { 0x0ee7, 0x11bb }, /* Hangul_J_SsangSios ᆻ HANGUL JONGSEONG SSANGSIOS */ + { 0x0ee8, 0x11bc }, /* Hangul_J_Ieung ᆼ HANGUL JONGSEONG IEUNG */ + { 0x0ee9, 0x11bd }, /* Hangul_J_Jieuj ᆽ HANGUL JONGSEONG CIEUC */ + { 0x0eea, 0x11be }, /* Hangul_J_Cieuc ᆾ HANGUL JONGSEONG CHIEUCH */ + { 0x0eeb, 0x11bf }, /* Hangul_J_Khieuq ᆿ HANGUL JONGSEONG KHIEUKH */ + { 0x0eec, 0x11c0 }, /* Hangul_J_Tieut ᇀ HANGUL JONGSEONG THIEUTH */ + { 0x0eed, 0x11c1 }, /* Hangul_J_Phieuf ᇁ HANGUL JONGSEONG PHIEUPH */ + { 0x0eee, 0x11c2 }, /* Hangul_J_Hieuh ᇂ HANGUL JONGSEONG HIEUH */ + { 0x0eef, 0x316d }, /* Hangul_RieulYeorinHieuh ㅭ HANGUL LETTER RIEUL-YEORINHIEUH */ + { 0x0ef0, 0x3171 }, /* Hangul_SunkyeongeumMieum ㅱ HANGUL LETTER KAPYEOUNMIEUM */ + { 0x0ef1, 0x3178 }, /* Hangul_SunkyeongeumPieub ㅸ HANGUL LETTER KAPYEOUNPIEUP */ + { 0x0ef2, 0x317f }, /* Hangul_PanSios ㅿ HANGUL LETTER PANSIOS */ +/* 0x0ef3 Hangul_KkogjiDalrinIeung ? ??? */ + { 0x0ef4, 0x3184 }, /* Hangul_SunkyeongeumPhieuf ㆄ HANGUL LETTER KAPYEOUNPHIEUPH */ + { 0x0ef5, 0x3186 }, /* Hangul_YeorinHieuh ㆆ HANGUL LETTER YEORINHIEUH */ + { 0x0ef6, 0x318d }, /* Hangul_AraeA ㆍ HANGUL LETTER ARAEA */ + { 0x0ef7, 0x318e }, /* Hangul_AraeAE ㆎ HANGUL LETTER ARAEAE */ + { 0x0ef8, 0x11eb }, /* Hangul_J_PanSios ᇫ HANGUL JONGSEONG PANSIOS */ +/* 0x0ef9 Hangul_J_KkogjiDalrinIeung ? ??? */ + { 0x0efa, 0x11f9 }, /* Hangul_J_YeorinHieuh ᇹ HANGUL JONGSEONG YEORINHIEUH */ + { 0x0eff, 0x20a9 }, /* Korean_Won ₩ WON SIGN */ + { 0x13bc, 0x0152 }, /* OE Œ LATIN CAPITAL LIGATURE OE */ + { 0x13bd, 0x0153 }, /* oe œ LATIN SMALL LIGATURE OE */ + { 0x13be, 0x0178 }, /* Ydiaeresis Ÿ LATIN CAPITAL LETTER Y WITH DIAERESIS */ + { 0x20a0, 0x20a0 }, /* EcuSign ₠ EURO-CURRENCY SIGN */ + { 0x20a1, 0x20a1 }, /* ColonSign ₡ COLON SIGN */ + { 0x20a2, 0x20a2 }, /* CruzeiroSign ₢ CRUZEIRO SIGN */ + { 0x20a3, 0x20a3 }, /* FFrancSign ₣ FRENCH FRANC SIGN */ + { 0x20a4, 0x20a4 }, /* LiraSign ₤ LIRA SIGN */ + { 0x20a5, 0x20a5 }, /* MillSign ₥ MILL SIGN */ + { 0x20a6, 0x20a6 }, /* NairaSign ₦ NAIRA SIGN */ + { 0x20a7, 0x20a7 }, /* PesetaSign ₧ PESETA SIGN */ + { 0x20a8, 0x20a8 }, /* RupeeSign ₨ RUPEE SIGN */ + { 0x20a9, 0x20a9 }, /* WonSign ₩ WON SIGN */ + { 0x20aa, 0x20aa }, /* NewSheqelSign ₪ NEW SHEQEL SIGN */ + { 0x20ab, 0x20ab }, /* DongSign ₫ DONG SIGN */ + { 0x20ac, 0x20ac }, /* EuroSign € EURO SIGN */ +}; + +static guint +keyval_to_unicode (guint keysym) +{ + int min = 0; + int max = sizeof(k2utab) / sizeof(k2utab[0]) - 1; + int mid; + + /* First check for Latin-1 characters (1:1 mapping) */ + if ((keysym >= 0x0020 && keysym <= 0x007e) || + (keysym >= 0x00a0 && keysym <= 0x00ff)) + return keysym; + + /* Also check for directly encoded 24-bit UCS characters */ + if ((keysym & 0xff000000) == 0x01000000) + return keysym & 0x00ffffff; + + /* binary search in table */ + while (max >= min) { + mid = (min + max) / 2; + if (k2utab[mid].keysym < keysym) + min = mid + 1; + else if (k2utab[mid].keysym > keysym) + max = mid - 1; + else { + /* found it */ + return k2utab[mid].ucs; + } + } + + /* No matching Unicode value found */ + return -1; +} + +#endif /* 0 */ + +struct u2k { + unsigned short keysym; + unsigned short ucs; +} u2ktab[] = { + { 0x0abd, 0x002e }, /* decimalpoint . FULL STOP */ + { 0x0ba3, 0x003c }, /* leftcaret < LESS-THAN SIGN */ + { 0x0ba6, 0x003e }, /* rightcaret > GREATER-THAN SIGN */ + { 0x0bc6, 0x005f }, /* underbar _ LOW LINE */ + { 0x0bc0, 0x00af }, /* overbar ¯ MACRON */ + { 0x03c0, 0x0100 }, /* Amacron Ā LATIN CAPITAL LETTER A WITH MACRON */ + { 0x03e0, 0x0101 }, /* amacron ā LATIN SMALL LETTER A WITH MACRON */ + { 0x01c3, 0x0102 }, /* Abreve Ă LATIN CAPITAL LETTER A WITH BREVE */ + { 0x01e3, 0x0103 }, /* abreve ă LATIN SMALL LETTER A WITH BREVE */ + { 0x01a1, 0x0104 }, /* Aogonek Ą LATIN CAPITAL LETTER A WITH OGONEK */ + { 0x01b1, 0x0105 }, /* aogonek ą LATIN SMALL LETTER A WITH OGONEK */ + { 0x01c6, 0x0106 }, /* Cacute Ć LATIN CAPITAL LETTER C WITH ACUTE */ + { 0x01e6, 0x0107 }, /* cacute ć LATIN SMALL LETTER C WITH ACUTE */ + { 0x02c6, 0x0108 }, /* Ccircumflex Ĉ LATIN CAPITAL LETTER C WITH CIRCUMFLEX */ + { 0x02e6, 0x0109 }, /* ccircumflex ĉ LATIN SMALL LETTER C WITH CIRCUMFLEX */ + { 0x02c5, 0x010a }, /* Cabovedot Ċ LATIN CAPITAL LETTER C WITH DOT ABOVE */ + { 0x02e5, 0x010b }, /* cabovedot ċ LATIN SMALL LETTER C WITH DOT ABOVE */ + { 0x01c8, 0x010c }, /* Ccaron Č LATIN CAPITAL LETTER C WITH CARON */ + { 0x01e8, 0x010d }, /* ccaron č LATIN SMALL LETTER C WITH CARON */ + { 0x01cf, 0x010e }, /* Dcaron Ď LATIN CAPITAL LETTER D WITH CARON */ + { 0x01ef, 0x010f }, /* dcaron ď LATIN SMALL LETTER D WITH CARON */ + { 0x01d0, 0x0110 }, /* Dstroke Đ LATIN CAPITAL LETTER D WITH STROKE */ + { 0x01f0, 0x0111 }, /* dstroke đ LATIN SMALL LETTER D WITH STROKE */ + { 0x03aa, 0x0112 }, /* Emacron Ē LATIN CAPITAL LETTER E WITH MACRON */ + { 0x03ba, 0x0113 }, /* emacron ē LATIN SMALL LETTER E WITH MACRON */ + { 0x03cc, 0x0116 }, /* Eabovedot Ė LATIN CAPITAL LETTER E WITH DOT ABOVE */ + { 0x03ec, 0x0117 }, /* eabovedot ė LATIN SMALL LETTER E WITH DOT ABOVE */ + { 0x01ca, 0x0118 }, /* Eogonek Ę LATIN CAPITAL LETTER E WITH OGONEK */ + { 0x01ea, 0x0119 }, /* eogonek ę LATIN SMALL LETTER E WITH OGONEK */ + { 0x01cc, 0x011a }, /* Ecaron Ě LATIN CAPITAL LETTER E WITH CARON */ + { 0x01ec, 0x011b }, /* ecaron ě LATIN SMALL LETTER E WITH CARON */ + { 0x02d8, 0x011c }, /* Gcircumflex Ĝ LATIN CAPITAL LETTER G WITH CIRCUMFLEX */ + { 0x02f8, 0x011d }, /* gcircumflex ĝ LATIN SMALL LETTER G WITH CIRCUMFLEX */ + { 0x02ab, 0x011e }, /* Gbreve Ğ LATIN CAPITAL LETTER G WITH BREVE */ + { 0x02bb, 0x011f }, /* gbreve ğ LATIN SMALL LETTER G WITH BREVE */ + { 0x02d5, 0x0120 }, /* Gabovedot Ä  LATIN CAPITAL LETTER G WITH DOT ABOVE */ + { 0x02f5, 0x0121 }, /* gabovedot Ä¡ LATIN SMALL LETTER G WITH DOT ABOVE */ + { 0x03ab, 0x0122 }, /* Gcedilla Ä¢ LATIN CAPITAL LETTER G WITH CEDILLA */ + { 0x03bb, 0x0123 }, /* gcedilla Ä£ LATIN SMALL LETTER G WITH CEDILLA */ + { 0x02a6, 0x0124 }, /* Hcircumflex Ĥ LATIN CAPITAL LETTER H WITH CIRCUMFLEX */ + { 0x02b6, 0x0125 }, /* hcircumflex Ä¥ LATIN SMALL LETTER H WITH CIRCUMFLEX */ + { 0x02a1, 0x0126 }, /* Hstroke Ħ LATIN CAPITAL LETTER H WITH STROKE */ + { 0x02b1, 0x0127 }, /* hstroke ħ LATIN SMALL LETTER H WITH STROKE */ + { 0x03a5, 0x0128 }, /* Itilde Ĩ LATIN CAPITAL LETTER I WITH TILDE */ + { 0x03b5, 0x0129 }, /* itilde Ä© LATIN SMALL LETTER I WITH TILDE */ + { 0x03cf, 0x012a }, /* Imacron Ī LATIN CAPITAL LETTER I WITH MACRON */ + { 0x03ef, 0x012b }, /* imacron Ä« LATIN SMALL LETTER I WITH MACRON */ + { 0x03c7, 0x012e }, /* Iogonek Ä® LATIN CAPITAL LETTER I WITH OGONEK */ + { 0x03e7, 0x012f }, /* iogonek į LATIN SMALL LETTER I WITH OGONEK */ + { 0x02a9, 0x0130 }, /* Iabovedot Ä° LATIN CAPITAL LETTER I WITH DOT ABOVE */ + { 0x02b9, 0x0131 }, /* idotless ı LATIN SMALL LETTER DOTLESS I */ + { 0x02ac, 0x0134 }, /* Jcircumflex Ä´ LATIN CAPITAL LETTER J WITH CIRCUMFLEX */ + { 0x02bc, 0x0135 }, /* jcircumflex ĵ LATIN SMALL LETTER J WITH CIRCUMFLEX */ + { 0x03d3, 0x0136 }, /* Kcedilla Ķ LATIN CAPITAL LETTER K WITH CEDILLA */ + { 0x03f3, 0x0137 }, /* kcedilla Ä· LATIN SMALL LETTER K WITH CEDILLA */ + { 0x03a2, 0x0138 }, /* kra ĸ LATIN SMALL LETTER KRA */ + { 0x01c5, 0x0139 }, /* Lacute Ĺ LATIN CAPITAL LETTER L WITH ACUTE */ + { 0x01e5, 0x013a }, /* lacute ĺ LATIN SMALL LETTER L WITH ACUTE */ + { 0x03a6, 0x013b }, /* Lcedilla Ä» LATIN CAPITAL LETTER L WITH CEDILLA */ + { 0x03b6, 0x013c }, /* lcedilla ļ LATIN SMALL LETTER L WITH CEDILLA */ + { 0x01a5, 0x013d }, /* Lcaron Ľ LATIN CAPITAL LETTER L WITH CARON */ + { 0x01b5, 0x013e }, /* lcaron ľ LATIN SMALL LETTER L WITH CARON */ + { 0x01a3, 0x0141 }, /* Lstroke Ł LATIN CAPITAL LETTER L WITH STROKE */ + { 0x01b3, 0x0142 }, /* lstroke ł LATIN SMALL LETTER L WITH STROKE */ + { 0x01d1, 0x0143 }, /* Nacute Ń LATIN CAPITAL LETTER N WITH ACUTE */ + { 0x01f1, 0x0144 }, /* nacute ń LATIN SMALL LETTER N WITH ACUTE */ + { 0x03d1, 0x0145 }, /* Ncedilla Ņ LATIN CAPITAL LETTER N WITH CEDILLA */ + { 0x03f1, 0x0146 }, /* ncedilla ņ LATIN SMALL LETTER N WITH CEDILLA */ + { 0x01d2, 0x0147 }, /* Ncaron Ň LATIN CAPITAL LETTER N WITH CARON */ + { 0x01f2, 0x0148 }, /* ncaron ň LATIN SMALL LETTER N WITH CARON */ + { 0x03bd, 0x014a }, /* ENG Ŋ LATIN CAPITAL LETTER ENG */ + { 0x03bf, 0x014b }, /* eng ŋ LATIN SMALL LETTER ENG */ + { 0x03d2, 0x014c }, /* Omacron Ō LATIN CAPITAL LETTER O WITH MACRON */ + { 0x03f2, 0x014d }, /* omacron ō LATIN SMALL LETTER O WITH MACRON */ + { 0x01d5, 0x0150 }, /* Odoubleacute Ő LATIN CAPITAL LETTER O WITH DOUBLE ACUTE */ + { 0x01f5, 0x0151 }, /* odoubleacute ő LATIN SMALL LETTER O WITH DOUBLE ACUTE */ + { 0x13bc, 0x0152 }, /* OE Œ LATIN CAPITAL LIGATURE OE */ + { 0x13bd, 0x0153 }, /* oe œ LATIN SMALL LIGATURE OE */ + { 0x01c0, 0x0154 }, /* Racute Ŕ LATIN CAPITAL LETTER R WITH ACUTE */ + { 0x01e0, 0x0155 }, /* racute ŕ LATIN SMALL LETTER R WITH ACUTE */ + { 0x03a3, 0x0156 }, /* Rcedilla Ŗ LATIN CAPITAL LETTER R WITH CEDILLA */ + { 0x03b3, 0x0157 }, /* rcedilla ŗ LATIN SMALL LETTER R WITH CEDILLA */ + { 0x01d8, 0x0158 }, /* Rcaron Ř LATIN CAPITAL LETTER R WITH CARON */ + { 0x01f8, 0x0159 }, /* rcaron ř LATIN SMALL LETTER R WITH CARON */ + { 0x01a6, 0x015a }, /* Sacute Ś LATIN CAPITAL LETTER S WITH ACUTE */ + { 0x01b6, 0x015b }, /* sacute ś LATIN SMALL LETTER S WITH ACUTE */ + { 0x02de, 0x015c }, /* Scircumflex Ŝ LATIN CAPITAL LETTER S WITH CIRCUMFLEX */ + { 0x02fe, 0x015d }, /* scircumflex ŝ LATIN SMALL LETTER S WITH CIRCUMFLEX */ + { 0x01aa, 0x015e }, /* Scedilla Ş LATIN CAPITAL LETTER S WITH CEDILLA */ + { 0x01ba, 0x015f }, /* scedilla ş LATIN SMALL LETTER S WITH CEDILLA */ + { 0x01a9, 0x0160 }, /* Scaron Å  LATIN CAPITAL LETTER S WITH CARON */ + { 0x01b9, 0x0161 }, /* scaron Å¡ LATIN SMALL LETTER S WITH CARON */ + { 0x01de, 0x0162 }, /* Tcedilla Å¢ LATIN CAPITAL LETTER T WITH CEDILLA */ + { 0x01fe, 0x0163 }, /* tcedilla Å£ LATIN SMALL LETTER T WITH CEDILLA */ + { 0x01ab, 0x0164 }, /* Tcaron Ť LATIN CAPITAL LETTER T WITH CARON */ + { 0x01bb, 0x0165 }, /* tcaron Å¥ LATIN SMALL LETTER T WITH CARON */ + { 0x03ac, 0x0166 }, /* Tslash Ŧ LATIN CAPITAL LETTER T WITH STROKE */ + { 0x03bc, 0x0167 }, /* tslash ŧ LATIN SMALL LETTER T WITH STROKE */ + { 0x03dd, 0x0168 }, /* Utilde Ũ LATIN CAPITAL LETTER U WITH TILDE */ + { 0x03fd, 0x0169 }, /* utilde Å© LATIN SMALL LETTER U WITH TILDE */ + { 0x03de, 0x016a }, /* Umacron Ū LATIN CAPITAL LETTER U WITH MACRON */ + { 0x03fe, 0x016b }, /* umacron Å« LATIN SMALL LETTER U WITH MACRON */ + { 0x02dd, 0x016c }, /* Ubreve Ŭ LATIN CAPITAL LETTER U WITH BREVE */ + { 0x02fd, 0x016d }, /* ubreve Å­ LATIN SMALL LETTER U WITH BREVE */ + { 0x01d9, 0x016e }, /* Uring Å® LATIN CAPITAL LETTER U WITH RING ABOVE */ + { 0x01f9, 0x016f }, /* uring ů LATIN SMALL LETTER U WITH RING ABOVE */ + { 0x01db, 0x0170 }, /* Udoubleacute Å° LATIN CAPITAL LETTER U WITH DOUBLE ACUTE */ + { 0x01fb, 0x0171 }, /* udoubleacute ű LATIN SMALL LETTER U WITH DOUBLE ACUTE */ + { 0x03d9, 0x0172 }, /* Uogonek Ų LATIN CAPITAL LETTER U WITH OGONEK */ + { 0x03f9, 0x0173 }, /* uogonek ų LATIN SMALL LETTER U WITH OGONEK */ + { 0x13be, 0x0178 }, /* Ydiaeresis Ÿ LATIN CAPITAL LETTER Y WITH DIAERESIS */ + { 0x01ac, 0x0179 }, /* Zacute Ź LATIN CAPITAL LETTER Z WITH ACUTE */ + { 0x01bc, 0x017a }, /* zacute ź LATIN SMALL LETTER Z WITH ACUTE */ + { 0x01af, 0x017b }, /* Zabovedot Å» LATIN CAPITAL LETTER Z WITH DOT ABOVE */ + { 0x01bf, 0x017c }, /* zabovedot ż LATIN SMALL LETTER Z WITH DOT ABOVE */ + { 0x01ae, 0x017d }, /* Zcaron Ž LATIN CAPITAL LETTER Z WITH CARON */ + { 0x01be, 0x017e }, /* zcaron ž LATIN SMALL LETTER Z WITH CARON */ + { 0x08f6, 0x0192 }, /* function ƒ LATIN SMALL LETTER F WITH HOOK */ + { 0x01b7, 0x02c7 }, /* caron ˇ CARON */ + { 0x01a2, 0x02d8 }, /* breve ˘ BREVE */ + { 0x01ff, 0x02d9 }, /* abovedot ˙ DOT ABOVE */ + { 0x01b2, 0x02db }, /* ogonek ˛ OGONEK */ + { 0x01bd, 0x02dd }, /* doubleacute ˝ DOUBLE ACUTE ACCENT */ + { 0x07ae, 0x0385 }, /* Greek_accentdieresis ΅ GREEK DIALYTIKA TONOS */ + { 0x07a1, 0x0386 }, /* Greek_ALPHAaccent Ά GREEK CAPITAL LETTER ALPHA WITH TONOS */ + { 0x07a2, 0x0388 }, /* Greek_EPSILONaccent Έ GREEK CAPITAL LETTER EPSILON WITH TONOS */ + { 0x07a3, 0x0389 }, /* Greek_ETAaccent Ή GREEK CAPITAL LETTER ETA WITH TONOS */ + { 0x07a4, 0x038a }, /* Greek_IOTAaccent Ί GREEK CAPITAL LETTER IOTA WITH TONOS */ + { 0x07a7, 0x038c }, /* Greek_OMICRONaccent Ό GREEK CAPITAL LETTER OMICRON WITH TONOS */ + { 0x07a8, 0x038e }, /* Greek_UPSILONaccent Ύ GREEK CAPITAL LETTER UPSILON WITH TONOS */ + { 0x07ab, 0x038f }, /* Greek_OMEGAaccent Ώ GREEK CAPITAL LETTER OMEGA WITH TONOS */ + { 0x07b6, 0x0390 }, /* Greek_iotaaccentdieresis ΐ GREEK SMALL LETTER IOTA WITH DIALYTIKA AND TONOS */ + { 0x07c1, 0x0391 }, /* Greek_ALPHA Α GREEK CAPITAL LETTER ALPHA */ + { 0x07c2, 0x0392 }, /* Greek_BETA Β GREEK CAPITAL LETTER BETA */ + { 0x07c3, 0x0393 }, /* Greek_GAMMA Γ GREEK CAPITAL LETTER GAMMA */ + { 0x07c4, 0x0394 }, /* Greek_DELTA Δ GREEK CAPITAL LETTER DELTA */ + { 0x07c5, 0x0395 }, /* Greek_EPSILON Ε GREEK CAPITAL LETTER EPSILON */ + { 0x07c6, 0x0396 }, /* Greek_ZETA Ζ GREEK CAPITAL LETTER ZETA */ + { 0x07c7, 0x0397 }, /* Greek_ETA Η GREEK CAPITAL LETTER ETA */ + { 0x07c8, 0x0398 }, /* Greek_THETA Θ GREEK CAPITAL LETTER THETA */ + { 0x07c9, 0x0399 }, /* Greek_IOTA Ι GREEK CAPITAL LETTER IOTA */ + { 0x07ca, 0x039a }, /* Greek_KAPPA Κ GREEK CAPITAL LETTER KAPPA */ + { 0x07cb, 0x039b }, /* Greek_LAMBDA Λ GREEK CAPITAL LETTER LAMDA */ + { 0x07cc, 0x039c }, /* Greek_MU Μ GREEK CAPITAL LETTER MU */ + { 0x07cd, 0x039d }, /* Greek_NU Ν GREEK CAPITAL LETTER NU */ + { 0x07ce, 0x039e }, /* Greek_XI Ξ GREEK CAPITAL LETTER XI */ + { 0x07cf, 0x039f }, /* Greek_OMICRON Ο GREEK CAPITAL LETTER OMICRON */ + { 0x07d0, 0x03a0 }, /* Greek_PI Π GREEK CAPITAL LETTER PI */ + { 0x07d1, 0x03a1 }, /* Greek_RHO Ρ GREEK CAPITAL LETTER RHO */ + { 0x07d2, 0x03a3 }, /* Greek_SIGMA Σ GREEK CAPITAL LETTER SIGMA */ + { 0x07d4, 0x03a4 }, /* Greek_TAU Τ GREEK CAPITAL LETTER TAU */ + { 0x07d5, 0x03a5 }, /* Greek_UPSILON Î¥ GREEK CAPITAL LETTER UPSILON */ + { 0x07d6, 0x03a6 }, /* Greek_PHI Φ GREEK CAPITAL LETTER PHI */ + { 0x07d7, 0x03a7 }, /* Greek_CHI Χ GREEK CAPITAL LETTER CHI */ + { 0x07d8, 0x03a8 }, /* Greek_PSI Ψ GREEK CAPITAL LETTER PSI */ + { 0x07d9, 0x03a9 }, /* Greek_OMEGA Ω GREEK CAPITAL LETTER OMEGA */ + { 0x07a5, 0x03aa }, /* Greek_IOTAdiaeresis Ϊ GREEK CAPITAL LETTER IOTA WITH DIALYTIKA */ + { 0x07a9, 0x03ab }, /* Greek_UPSILONdieresis Ϋ GREEK CAPITAL LETTER UPSILON WITH DIALYTIKA */ + { 0x07b1, 0x03ac }, /* Greek_alphaaccent ά GREEK SMALL LETTER ALPHA WITH TONOS */ + { 0x07b2, 0x03ad }, /* Greek_epsilonaccent έ GREEK SMALL LETTER EPSILON WITH TONOS */ + { 0x07b3, 0x03ae }, /* Greek_etaaccent ή GREEK SMALL LETTER ETA WITH TONOS */ + { 0x07b4, 0x03af }, /* Greek_iotaaccent ί GREEK SMALL LETTER IOTA WITH TONOS */ + { 0x07ba, 0x03b0 }, /* Greek_upsilonaccentdieresis ΰ GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND TONOS */ + { 0x07e1, 0x03b1 }, /* Greek_alpha α GREEK SMALL LETTER ALPHA */ + { 0x07e2, 0x03b2 }, /* Greek_beta β GREEK SMALL LETTER BETA */ + { 0x07e3, 0x03b3 }, /* Greek_gamma γ GREEK SMALL LETTER GAMMA */ + { 0x07e4, 0x03b4 }, /* Greek_delta δ GREEK SMALL LETTER DELTA */ + { 0x07e5, 0x03b5 }, /* Greek_epsilon ε GREEK SMALL LETTER EPSILON */ + { 0x07e6, 0x03b6 }, /* Greek_zeta ζ GREEK SMALL LETTER ZETA */ + { 0x07e7, 0x03b7 }, /* Greek_eta η GREEK SMALL LETTER ETA */ + { 0x07e8, 0x03b8 }, /* Greek_theta θ GREEK SMALL LETTER THETA */ + { 0x07e9, 0x03b9 }, /* Greek_iota ι GREEK SMALL LETTER IOTA */ + { 0x07ea, 0x03ba }, /* Greek_kappa κ GREEK SMALL LETTER KAPPA */ + { 0x07eb, 0x03bb }, /* Greek_lambda λ GREEK SMALL LETTER LAMDA */ + { 0x07ec, 0x03bc }, /* Greek_mu μ GREEK SMALL LETTER MU */ + { 0x07ed, 0x03bd }, /* Greek_nu ν GREEK SMALL LETTER NU */ + { 0x07ee, 0x03be }, /* Greek_xi ξ GREEK SMALL LETTER XI */ + { 0x07ef, 0x03bf }, /* Greek_omicron ο GREEK SMALL LETTER OMICRON */ + { 0x07f0, 0x03c0 }, /* Greek_pi π GREEK SMALL LETTER PI */ + { 0x07f1, 0x03c1 }, /* Greek_rho ρ GREEK SMALL LETTER RHO */ + { 0x07f3, 0x03c2 }, /* Greek_finalsmallsigma ς GREEK SMALL LETTER FINAL SIGMA */ + { 0x07f2, 0x03c3 }, /* Greek_sigma σ GREEK SMALL LETTER SIGMA */ + { 0x07f4, 0x03c4 }, /* Greek_tau τ GREEK SMALL LETTER TAU */ + { 0x07f5, 0x03c5 }, /* Greek_upsilon υ GREEK SMALL LETTER UPSILON */ + { 0x07f6, 0x03c6 }, /* Greek_phi φ GREEK SMALL LETTER PHI */ + { 0x07f7, 0x03c7 }, /* Greek_chi χ GREEK SMALL LETTER CHI */ + { 0x07f8, 0x03c8 }, /* Greek_psi ψ GREEK SMALL LETTER PSI */ + { 0x07f9, 0x03c9 }, /* Greek_omega ω GREEK SMALL LETTER OMEGA */ + { 0x07b5, 0x03ca }, /* Greek_iotadieresis ϊ GREEK SMALL LETTER IOTA WITH DIALYTIKA */ + { 0x07b9, 0x03cb }, /* Greek_upsilondieresis ϋ GREEK SMALL LETTER UPSILON WITH DIALYTIKA */ + { 0x07b7, 0x03cc }, /* Greek_omicronaccent ό GREEK SMALL LETTER OMICRON WITH TONOS */ + { 0x07b8, 0x03cd }, /* Greek_upsilonaccent ύ GREEK SMALL LETTER UPSILON WITH TONOS */ + { 0x07bb, 0x03ce }, /* Greek_omegaaccent ώ GREEK SMALL LETTER OMEGA WITH TONOS */ + { 0x06b3, 0x0401 }, /* Cyrillic_IO Ё CYRILLIC CAPITAL LETTER IO */ + { 0x06b1, 0x0402 }, /* Serbian_DJE Ђ CYRILLIC CAPITAL LETTER DJE */ + { 0x06b2, 0x0403 }, /* Macedonia_GJE Ѓ CYRILLIC CAPITAL LETTER GJE */ + { 0x06b4, 0x0404 }, /* Ukrainian_IE Є CYRILLIC CAPITAL LETTER UKRAINIAN IE */ + { 0x06b5, 0x0405 }, /* Macedonia_DSE Ѕ CYRILLIC CAPITAL LETTER DZE */ + { 0x06b6, 0x0406 }, /* Ukrainian_I І CYRILLIC CAPITAL LETTER BYELORUSSIAN-UKRAINIAN I */ + { 0x06b7, 0x0407 }, /* Ukrainian_YI Ї CYRILLIC CAPITAL LETTER YI */ + { 0x06b8, 0x0408 }, /* Cyrillic_JE Ј CYRILLIC CAPITAL LETTER JE */ + { 0x06b9, 0x0409 }, /* Cyrillic_LJE Љ CYRILLIC CAPITAL LETTER LJE */ + { 0x06ba, 0x040a }, /* Cyrillic_NJE Њ CYRILLIC CAPITAL LETTER NJE */ + { 0x06bb, 0x040b }, /* Serbian_TSHE Ћ CYRILLIC CAPITAL LETTER TSHE */ + { 0x06bc, 0x040c }, /* Macedonia_KJE Ќ CYRILLIC CAPITAL LETTER KJE */ + { 0x06be, 0x040e }, /* Byelorussian_SHORTU Ў CYRILLIC CAPITAL LETTER SHORT U */ + { 0x06bf, 0x040f }, /* Cyrillic_DZHE Џ CYRILLIC CAPITAL LETTER DZHE */ + { 0x06e1, 0x0410 }, /* Cyrillic_A А CYRILLIC CAPITAL LETTER A */ + { 0x06e2, 0x0411 }, /* Cyrillic_BE Б CYRILLIC CAPITAL LETTER BE */ + { 0x06f7, 0x0412 }, /* Cyrillic_VE В CYRILLIC CAPITAL LETTER VE */ + { 0x06e7, 0x0413 }, /* Cyrillic_GHE Г CYRILLIC CAPITAL LETTER GHE */ + { 0x06e4, 0x0414 }, /* Cyrillic_DE Д CYRILLIC CAPITAL LETTER DE */ + { 0x06e5, 0x0415 }, /* Cyrillic_IE Е CYRILLIC CAPITAL LETTER IE */ + { 0x06f6, 0x0416 }, /* Cyrillic_ZHE Ж CYRILLIC CAPITAL LETTER ZHE */ + { 0x06fa, 0x0417 }, /* Cyrillic_ZE З CYRILLIC CAPITAL LETTER ZE */ + { 0x06e9, 0x0418 }, /* Cyrillic_I И CYRILLIC CAPITAL LETTER I */ + { 0x06ea, 0x0419 }, /* Cyrillic_SHORTI Й CYRILLIC CAPITAL LETTER SHORT I */ + { 0x06eb, 0x041a }, /* Cyrillic_KA К CYRILLIC CAPITAL LETTER KA */ + { 0x06ec, 0x041b }, /* Cyrillic_EL Л CYRILLIC CAPITAL LETTER EL */ + { 0x06ed, 0x041c }, /* Cyrillic_EM М CYRILLIC CAPITAL LETTER EM */ + { 0x06ee, 0x041d }, /* Cyrillic_EN Н CYRILLIC CAPITAL LETTER EN */ + { 0x06ef, 0x041e }, /* Cyrillic_O О CYRILLIC CAPITAL LETTER O */ + { 0x06f0, 0x041f }, /* Cyrillic_PE П CYRILLIC CAPITAL LETTER PE */ + { 0x06f2, 0x0420 }, /* Cyrillic_ER Р CYRILLIC CAPITAL LETTER ER */ + { 0x06f3, 0x0421 }, /* Cyrillic_ES С CYRILLIC CAPITAL LETTER ES */ + { 0x06f4, 0x0422 }, /* Cyrillic_TE Т CYRILLIC CAPITAL LETTER TE */ + { 0x06f5, 0x0423 }, /* Cyrillic_U У CYRILLIC CAPITAL LETTER U */ + { 0x06e6, 0x0424 }, /* Cyrillic_EF Ф CYRILLIC CAPITAL LETTER EF */ + { 0x06e8, 0x0425 }, /* Cyrillic_HA Ð¥ CYRILLIC CAPITAL LETTER HA */ + { 0x06e3, 0x0426 }, /* Cyrillic_TSE Ц CYRILLIC CAPITAL LETTER TSE */ + { 0x06fe, 0x0427 }, /* Cyrillic_CHE Ч CYRILLIC CAPITAL LETTER CHE */ + { 0x06fb, 0x0428 }, /* Cyrillic_SHA Ш CYRILLIC CAPITAL LETTER SHA */ + { 0x06fd, 0x0429 }, /* Cyrillic_SHCHA Щ CYRILLIC CAPITAL LETTER SHCHA */ + { 0x06ff, 0x042a }, /* Cyrillic_HARDSIGN Ъ CYRILLIC CAPITAL LETTER HARD SIGN */ + { 0x06f9, 0x042b }, /* Cyrillic_YERU Ы CYRILLIC CAPITAL LETTER YERU */ + { 0x06f8, 0x042c }, /* Cyrillic_SOFTSIGN Ь CYRILLIC CAPITAL LETTER SOFT SIGN */ + { 0x06fc, 0x042d }, /* Cyrillic_E Э CYRILLIC CAPITAL LETTER E */ + { 0x06e0, 0x042e }, /* Cyrillic_YU Ю CYRILLIC CAPITAL LETTER YU */ + { 0x06f1, 0x042f }, /* Cyrillic_YA Я CYRILLIC CAPITAL LETTER YA */ + { 0x06c1, 0x0430 }, /* Cyrillic_a а CYRILLIC SMALL LETTER A */ + { 0x06c2, 0x0431 }, /* Cyrillic_be б CYRILLIC SMALL LETTER BE */ + { 0x06d7, 0x0432 }, /* Cyrillic_ve в CYRILLIC SMALL LETTER VE */ + { 0x06c7, 0x0433 }, /* Cyrillic_ghe г CYRILLIC SMALL LETTER GHE */ + { 0x06c4, 0x0434 }, /* Cyrillic_de д CYRILLIC SMALL LETTER DE */ + { 0x06c5, 0x0435 }, /* Cyrillic_ie е CYRILLIC SMALL LETTER IE */ + { 0x06d6, 0x0436 }, /* Cyrillic_zhe ж CYRILLIC SMALL LETTER ZHE */ + { 0x06da, 0x0437 }, /* Cyrillic_ze з CYRILLIC SMALL LETTER ZE */ + { 0x06c9, 0x0438 }, /* Cyrillic_i и CYRILLIC SMALL LETTER I */ + { 0x06ca, 0x0439 }, /* Cyrillic_shorti й CYRILLIC SMALL LETTER SHORT I */ + { 0x06cb, 0x043a }, /* Cyrillic_ka к CYRILLIC SMALL LETTER KA */ + { 0x06cc, 0x043b }, /* Cyrillic_el л CYRILLIC SMALL LETTER EL */ + { 0x06cd, 0x043c }, /* Cyrillic_em м CYRILLIC SMALL LETTER EM */ + { 0x06ce, 0x043d }, /* Cyrillic_en н CYRILLIC SMALL LETTER EN */ + { 0x06cf, 0x043e }, /* Cyrillic_o о CYRILLIC SMALL LETTER O */ + { 0x06d0, 0x043f }, /* Cyrillic_pe п CYRILLIC SMALL LETTER PE */ + { 0x06d2, 0x0440 }, /* Cyrillic_er р CYRILLIC SMALL LETTER ER */ + { 0x06d3, 0x0441 }, /* Cyrillic_es с CYRILLIC SMALL LETTER ES */ + { 0x06d4, 0x0442 }, /* Cyrillic_te т CYRILLIC SMALL LETTER TE */ + { 0x06d5, 0x0443 }, /* Cyrillic_u у CYRILLIC SMALL LETTER U */ + { 0x06c6, 0x0444 }, /* Cyrillic_ef ф CYRILLIC SMALL LETTER EF */ + { 0x06c8, 0x0445 }, /* Cyrillic_ha х CYRILLIC SMALL LETTER HA */ + { 0x06c3, 0x0446 }, /* Cyrillic_tse ц CYRILLIC SMALL LETTER TSE */ + { 0x06de, 0x0447 }, /* Cyrillic_che ч CYRILLIC SMALL LETTER CHE */ + { 0x06db, 0x0448 }, /* Cyrillic_sha ш CYRILLIC SMALL LETTER SHA */ + { 0x06dd, 0x0449 }, /* Cyrillic_shcha щ CYRILLIC SMALL LETTER SHCHA */ + { 0x06df, 0x044a }, /* Cyrillic_hardsign ъ CYRILLIC SMALL LETTER HARD SIGN */ + { 0x06d9, 0x044b }, /* Cyrillic_yeru ы CYRILLIC SMALL LETTER YERU */ + { 0x06d8, 0x044c }, /* Cyrillic_softsign ь CYRILLIC SMALL LETTER SOFT SIGN */ + { 0x06dc, 0x044d }, /* Cyrillic_e э CYRILLIC SMALL LETTER E */ + { 0x06c0, 0x044e }, /* Cyrillic_yu ю CYRILLIC SMALL LETTER YU */ + { 0x06d1, 0x044f }, /* Cyrillic_ya я CYRILLIC SMALL LETTER YA */ + { 0x06a3, 0x0451 }, /* Cyrillic_io ё CYRILLIC SMALL LETTER IO */ + { 0x06a1, 0x0452 }, /* Serbian_dje ђ CYRILLIC SMALL LETTER DJE */ + { 0x06a2, 0x0453 }, /* Macedonia_gje ѓ CYRILLIC SMALL LETTER GJE */ + { 0x06a4, 0x0454 }, /* Ukrainian_ie є CYRILLIC SMALL LETTER UKRAINIAN IE */ + { 0x06a5, 0x0455 }, /* Macedonia_dse ѕ CYRILLIC SMALL LETTER DZE */ + { 0x06a6, 0x0456 }, /* Ukrainian_i і CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I */ + { 0x06a7, 0x0457 }, /* Ukrainian_yi ї CYRILLIC SMALL LETTER YI */ + { 0x06a8, 0x0458 }, /* Cyrillic_je ј CYRILLIC SMALL LETTER JE */ + { 0x06a9, 0x0459 }, /* Cyrillic_lje љ CYRILLIC SMALL LETTER LJE */ + { 0x06aa, 0x045a }, /* Cyrillic_nje њ CYRILLIC SMALL LETTER NJE */ + { 0x06ab, 0x045b }, /* Serbian_tshe ћ CYRILLIC SMALL LETTER TSHE */ + { 0x06ac, 0x045c }, /* Macedonia_kje ќ CYRILLIC SMALL LETTER KJE */ + { 0x06ae, 0x045e }, /* Byelorussian_shortu ў CYRILLIC SMALL LETTER SHORT U */ + { 0x06af, 0x045f }, /* Cyrillic_dzhe џ CYRILLIC SMALL LETTER DZHE */ + { 0x0ce0, 0x05d0 }, /* hebrew_aleph א HEBREW LETTER ALEF */ + { 0x0ce1, 0x05d1 }, /* hebrew_bet ב HEBREW LETTER BET */ + { 0x0ce2, 0x05d2 }, /* hebrew_gimel ג HEBREW LETTER GIMEL */ + { 0x0ce3, 0x05d3 }, /* hebrew_dalet ד HEBREW LETTER DALET */ + { 0x0ce4, 0x05d4 }, /* hebrew_he ה HEBREW LETTER HE */ + { 0x0ce5, 0x05d5 }, /* hebrew_waw ו HEBREW LETTER VAV */ + { 0x0ce6, 0x05d6 }, /* hebrew_zain ז HEBREW LETTER ZAYIN */ + { 0x0ce7, 0x05d7 }, /* hebrew_chet ח HEBREW LETTER HET */ + { 0x0ce8, 0x05d8 }, /* hebrew_tet ט HEBREW LETTER TET */ + { 0x0ce9, 0x05d9 }, /* hebrew_yod י HEBREW LETTER YOD */ + { 0x0cea, 0x05da }, /* hebrew_finalkaph ך HEBREW LETTER FINAL KAF */ + { 0x0ceb, 0x05db }, /* hebrew_kaph כ HEBREW LETTER KAF */ + { 0x0cec, 0x05dc }, /* hebrew_lamed ל HEBREW LETTER LAMED */ + { 0x0ced, 0x05dd }, /* hebrew_finalmem ם HEBREW LETTER FINAL MEM */ + { 0x0cee, 0x05de }, /* hebrew_mem מ HEBREW LETTER MEM */ + { 0x0cef, 0x05df }, /* hebrew_finalnun ן HEBREW LETTER FINAL NUN */ + { 0x0cf0, 0x05e0 }, /* hebrew_nun ×  HEBREW LETTER NUN */ + { 0x0cf1, 0x05e1 }, /* hebrew_samech ס HEBREW LETTER SAMEKH */ + { 0x0cf2, 0x05e2 }, /* hebrew_ayin ×¢ HEBREW LETTER AYIN */ + { 0x0cf3, 0x05e3 }, /* hebrew_finalpe ×£ HEBREW LETTER FINAL PE */ + { 0x0cf4, 0x05e4 }, /* hebrew_pe פ HEBREW LETTER PE */ + { 0x0cf5, 0x05e5 }, /* hebrew_finalzade ×¥ HEBREW LETTER FINAL TSADI */ + { 0x0cf6, 0x05e6 }, /* hebrew_zade צ HEBREW LETTER TSADI */ + { 0x0cf7, 0x05e7 }, /* hebrew_qoph ק HEBREW LETTER QOF */ + { 0x0cf8, 0x05e8 }, /* hebrew_resh ר HEBREW LETTER RESH */ + { 0x0cf9, 0x05e9 }, /* hebrew_shin ש HEBREW LETTER SHIN */ + { 0x0cfa, 0x05ea }, /* hebrew_taw ת HEBREW LETTER TAV */ + { 0x05ac, 0x060c }, /* Arabic_comma ، ARABIC COMMA */ + { 0x05bb, 0x061b }, /* Arabic_semicolon ؛ ARABIC SEMICOLON */ + { 0x05bf, 0x061f }, /* Arabic_question_mark ؟ ARABIC QUESTION MARK */ + { 0x05c1, 0x0621 }, /* Arabic_hamza Ø¡ ARABIC LETTER HAMZA */ + { 0x05c2, 0x0622 }, /* Arabic_maddaonalef Ø¢ ARABIC LETTER ALEF WITH MADDA ABOVE */ + { 0x05c3, 0x0623 }, /* Arabic_hamzaonalef Ø£ ARABIC LETTER ALEF WITH HAMZA ABOVE */ + { 0x05c4, 0x0624 }, /* Arabic_hamzaonwaw ؤ ARABIC LETTER WAW WITH HAMZA ABOVE */ + { 0x05c5, 0x0625 }, /* Arabic_hamzaunderalef Ø¥ ARABIC LETTER ALEF WITH HAMZA BELOW */ + { 0x05c6, 0x0626 }, /* Arabic_hamzaonyeh ئ ARABIC LETTER YEH WITH HAMZA ABOVE */ + { 0x05c7, 0x0627 }, /* Arabic_alef ا ARABIC LETTER ALEF */ + { 0x05c8, 0x0628 }, /* Arabic_beh ب ARABIC LETTER BEH */ + { 0x05c9, 0x0629 }, /* Arabic_tehmarbuta Ø© ARABIC LETTER TEH MARBUTA */ + { 0x05ca, 0x062a }, /* Arabic_teh ت ARABIC LETTER TEH */ + { 0x05cb, 0x062b }, /* Arabic_theh Ø« ARABIC LETTER THEH */ + { 0x05cc, 0x062c }, /* Arabic_jeem ج ARABIC LETTER JEEM */ + { 0x05cd, 0x062d }, /* Arabic_hah Ø­ ARABIC LETTER HAH */ + { 0x05ce, 0x062e }, /* Arabic_khah Ø® ARABIC LETTER KHAH */ + { 0x05cf, 0x062f }, /* Arabic_dal د ARABIC LETTER DAL */ + { 0x05d0, 0x0630 }, /* Arabic_thal Ø° ARABIC LETTER THAL */ + { 0x05d1, 0x0631 }, /* Arabic_ra ر ARABIC LETTER REH */ + { 0x05d2, 0x0632 }, /* Arabic_zain ز ARABIC LETTER ZAIN */ + { 0x05d3, 0x0633 }, /* Arabic_seen س ARABIC LETTER SEEN */ + { 0x05d4, 0x0634 }, /* Arabic_sheen Ø´ ARABIC LETTER SHEEN */ + { 0x05d5, 0x0635 }, /* Arabic_sad ص ARABIC LETTER SAD */ + { 0x05d6, 0x0636 }, /* Arabic_dad ض ARABIC LETTER DAD */ + { 0x05d7, 0x0637 }, /* Arabic_tah Ø· ARABIC LETTER TAH */ + { 0x05d8, 0x0638 }, /* Arabic_zah ظ ARABIC LETTER ZAH */ + { 0x05d9, 0x0639 }, /* Arabic_ain ع ARABIC LETTER AIN */ + { 0x05da, 0x063a }, /* Arabic_ghain غ ARABIC LETTER GHAIN */ + { 0x05e0, 0x0640 }, /* Arabic_tatweel ـ ARABIC TATWEEL */ + { 0x05e1, 0x0641 }, /* Arabic_feh ف ARABIC LETTER FEH */ + { 0x05e2, 0x0642 }, /* Arabic_qaf ق ARABIC LETTER QAF */ + { 0x05e3, 0x0643 }, /* Arabic_kaf ك ARABIC LETTER KAF */ + { 0x05e4, 0x0644 }, /* Arabic_lam ل ARABIC LETTER LAM */ + { 0x05e5, 0x0645 }, /* Arabic_meem م ARABIC LETTER MEEM */ + { 0x05e6, 0x0646 }, /* Arabic_noon ن ARABIC LETTER NOON */ + { 0x05e7, 0x0647 }, /* Arabic_ha ه ARABIC LETTER HEH */ + { 0x05e8, 0x0648 }, /* Arabic_waw و ARABIC LETTER WAW */ + { 0x05e9, 0x0649 }, /* Arabic_alefmaksura ى ARABIC LETTER ALEF MAKSURA */ + { 0x05ea, 0x064a }, /* Arabic_yeh ي ARABIC LETTER YEH */ + { 0x05eb, 0x064b }, /* Arabic_fathatan ً ARABIC FATHATAN */ + { 0x05ec, 0x064c }, /* Arabic_dammatan ٌ ARABIC DAMMATAN */ + { 0x05ed, 0x064d }, /* Arabic_kasratan ٍ ARABIC KASRATAN */ + { 0x05ee, 0x064e }, /* Arabic_fatha َ ARABIC FATHA */ + { 0x05ef, 0x064f }, /* Arabic_damma ُ ARABIC DAMMA */ + { 0x05f0, 0x0650 }, /* Arabic_kasra ِ ARABIC KASRA */ + { 0x05f1, 0x0651 }, /* Arabic_shadda ّ ARABIC SHADDA */ + { 0x05f2, 0x0652 }, /* Arabic_sukun ْ ARABIC SUKUN */ + { 0x0da1, 0x0e01 }, /* Thai_kokai ก THAI CHARACTER KO KAI */ + { 0x0da2, 0x0e02 }, /* Thai_khokhai ข THAI CHARACTER KHO KHAI */ + { 0x0da3, 0x0e03 }, /* Thai_khokhuat ฃ THAI CHARACTER KHO KHUAT */ + { 0x0da4, 0x0e04 }, /* Thai_khokhwai ค THAI CHARACTER KHO KHWAI */ + { 0x0da5, 0x0e05 }, /* Thai_khokhon ฅ THAI CHARACTER KHO KHON */ + { 0x0da6, 0x0e06 }, /* Thai_khorakhang ฆ THAI CHARACTER KHO RAKHANG */ + { 0x0da7, 0x0e07 }, /* Thai_ngongu ง THAI CHARACTER NGO NGU */ + { 0x0da8, 0x0e08 }, /* Thai_chochan จ THAI CHARACTER CHO CHAN */ + { 0x0da9, 0x0e09 }, /* Thai_choching ฉ THAI CHARACTER CHO CHING */ + { 0x0daa, 0x0e0a }, /* Thai_chochang ช THAI CHARACTER CHO CHANG */ + { 0x0dab, 0x0e0b }, /* Thai_soso ซ THAI CHARACTER SO SO */ + { 0x0dac, 0x0e0c }, /* Thai_chochoe ฌ THAI CHARACTER CHO CHOE */ + { 0x0dad, 0x0e0d }, /* Thai_yoying ญ THAI CHARACTER YO YING */ + { 0x0dae, 0x0e0e }, /* Thai_dochada ฎ THAI CHARACTER DO CHADA */ + { 0x0daf, 0x0e0f }, /* Thai_topatak ฏ THAI CHARACTER TO PATAK */ + { 0x0db0, 0x0e10 }, /* Thai_thothan ฐ THAI CHARACTER THO THAN */ + { 0x0db1, 0x0e11 }, /* Thai_thonangmontho ฑ THAI CHARACTER THO NANGMONTHO */ + { 0x0db2, 0x0e12 }, /* Thai_thophuthao ฒ THAI CHARACTER THO PHUTHAO */ + { 0x0db3, 0x0e13 }, /* Thai_nonen ณ THAI CHARACTER NO NEN */ + { 0x0db4, 0x0e14 }, /* Thai_dodek ด THAI CHARACTER DO DEK */ + { 0x0db5, 0x0e15 }, /* Thai_totao ต THAI CHARACTER TO TAO */ + { 0x0db6, 0x0e16 }, /* Thai_thothung ถ THAI CHARACTER THO THUNG */ + { 0x0db7, 0x0e17 }, /* Thai_thothahan ท THAI CHARACTER THO THAHAN */ + { 0x0db8, 0x0e18 }, /* Thai_thothong ธ THAI CHARACTER THO THONG */ + { 0x0db9, 0x0e19 }, /* Thai_nonu น THAI CHARACTER NO NU */ + { 0x0dba, 0x0e1a }, /* Thai_bobaimai บ THAI CHARACTER BO BAIMAI */ + { 0x0dbb, 0x0e1b }, /* Thai_popla ป THAI CHARACTER PO PLA */ + { 0x0dbc, 0x0e1c }, /* Thai_phophung ผ THAI CHARACTER PHO PHUNG */ + { 0x0dbd, 0x0e1d }, /* Thai_fofa ฝ THAI CHARACTER FO FA */ + { 0x0dbe, 0x0e1e }, /* Thai_phophan พ THAI CHARACTER PHO PHAN */ + { 0x0dbf, 0x0e1f }, /* Thai_fofan ฟ THAI CHARACTER FO FAN */ + { 0x0dc0, 0x0e20 }, /* Thai_phosamphao ภ THAI CHARACTER PHO SAMPHAO */ + { 0x0dc1, 0x0e21 }, /* Thai_moma ม THAI CHARACTER MO MA */ + { 0x0dc2, 0x0e22 }, /* Thai_yoyak ย THAI CHARACTER YO YAK */ + { 0x0dc3, 0x0e23 }, /* Thai_rorua ร THAI CHARACTER RO RUA */ + { 0x0dc4, 0x0e24 }, /* Thai_ru ฤ THAI CHARACTER RU */ + { 0x0dc5, 0x0e25 }, /* Thai_loling ล THAI CHARACTER LO LING */ + { 0x0dc6, 0x0e26 }, /* Thai_lu ฦ THAI CHARACTER LU */ + { 0x0dc7, 0x0e27 }, /* Thai_wowaen ว THAI CHARACTER WO WAEN */ + { 0x0dc8, 0x0e28 }, /* Thai_sosala ศ THAI CHARACTER SO SALA */ + { 0x0dc9, 0x0e29 }, /* Thai_sorusi ษ THAI CHARACTER SO RUSI */ + { 0x0dca, 0x0e2a }, /* Thai_sosua ส THAI CHARACTER SO SUA */ + { 0x0dcb, 0x0e2b }, /* Thai_hohip ห THAI CHARACTER HO HIP */ + { 0x0dcc, 0x0e2c }, /* Thai_lochula ฬ THAI CHARACTER LO CHULA */ + { 0x0dcd, 0x0e2d }, /* Thai_oang อ THAI CHARACTER O ANG */ + { 0x0dce, 0x0e2e }, /* Thai_honokhuk ฮ THAI CHARACTER HO NOKHUK */ + { 0x0dcf, 0x0e2f }, /* Thai_paiyannoi ฯ THAI CHARACTER PAIYANNOI */ + { 0x0dd0, 0x0e30 }, /* Thai_saraa ะ THAI CHARACTER SARA A */ + { 0x0dd1, 0x0e31 }, /* Thai_maihanakat ั THAI CHARACTER MAI HAN-AKAT */ + { 0x0dd2, 0x0e32 }, /* Thai_saraaa า THAI CHARACTER SARA AA */ + { 0x0dd3, 0x0e33 }, /* Thai_saraam ำ THAI CHARACTER SARA AM */ + { 0x0dd4, 0x0e34 }, /* Thai_sarai ิ THAI CHARACTER SARA I */ + { 0x0dd5, 0x0e35 }, /* Thai_saraii ี THAI CHARACTER SARA II */ + { 0x0dd6, 0x0e36 }, /* Thai_saraue ึ THAI CHARACTER SARA UE */ + { 0x0dd7, 0x0e37 }, /* Thai_sarauee ื THAI CHARACTER SARA UEE */ + { 0x0dd8, 0x0e38 }, /* Thai_sarau ุ THAI CHARACTER SARA U */ + { 0x0dd9, 0x0e39 }, /* Thai_sarauu ู THAI CHARACTER SARA UU */ + { 0x0dda, 0x0e3a }, /* Thai_phinthu ฺ THAI CHARACTER PHINTHU */ + { 0x0ddf, 0x0e3f }, /* Thai_baht ฿ THAI CURRENCY SYMBOL BAHT */ + { 0x0de0, 0x0e40 }, /* Thai_sarae เ THAI CHARACTER SARA E */ + { 0x0de1, 0x0e41 }, /* Thai_saraae แ THAI CHARACTER SARA AE */ + { 0x0de2, 0x0e42 }, /* Thai_sarao โ THAI CHARACTER SARA O */ + { 0x0de3, 0x0e43 }, /* Thai_saraaimaimuan ใ THAI CHARACTER SARA AI MAIMUAN */ + { 0x0de4, 0x0e44 }, /* Thai_saraaimaimalai ไ THAI CHARACTER SARA AI MAIMALAI */ + { 0x0de5, 0x0e45 }, /* Thai_lakkhangyao ๅ THAI CHARACTER LAKKHANGYAO */ + { 0x0de6, 0x0e46 }, /* Thai_maiyamok ๆ THAI CHARACTER MAIYAMOK */ + { 0x0de7, 0x0e47 }, /* Thai_maitaikhu ็ THAI CHARACTER MAITAIKHU */ + { 0x0de8, 0x0e48 }, /* Thai_maiek ่ THAI CHARACTER MAI EK */ + { 0x0de9, 0x0e49 }, /* Thai_maitho ้ THAI CHARACTER MAI THO */ + { 0x0dea, 0x0e4a }, /* Thai_maitri ๊ THAI CHARACTER MAI TRI */ + { 0x0deb, 0x0e4b }, /* Thai_maichattawa ๋ THAI CHARACTER MAI CHATTAWA */ + { 0x0dec, 0x0e4c }, /* Thai_thanthakhat ์ THAI CHARACTER THANTHAKHAT */ + { 0x0ded, 0x0e4d }, /* Thai_nikhahit ํ THAI CHARACTER NIKHAHIT */ + { 0x0df0, 0x0e50 }, /* Thai_leksun ๐ THAI DIGIT ZERO */ + { 0x0df1, 0x0e51 }, /* Thai_leknung ๑ THAI DIGIT ONE */ + { 0x0df2, 0x0e52 }, /* Thai_leksong ๒ THAI DIGIT TWO */ + { 0x0df3, 0x0e53 }, /* Thai_leksam ๓ THAI DIGIT THREE */ + { 0x0df4, 0x0e54 }, /* Thai_leksi ๔ THAI DIGIT FOUR */ + { 0x0df5, 0x0e55 }, /* Thai_lekha ๕ THAI DIGIT FIVE */ + { 0x0df6, 0x0e56 }, /* Thai_lekhok ๖ THAI DIGIT SIX */ + { 0x0df7, 0x0e57 }, /* Thai_lekchet ๗ THAI DIGIT SEVEN */ + { 0x0df8, 0x0e58 }, /* Thai_lekpaet ๘ THAI DIGIT EIGHT */ + { 0x0df9, 0x0e59 }, /* Thai_lekkao ๙ THAI DIGIT NINE */ + { 0x0ed4, 0x11a8 }, /* Hangul_J_Kiyeog ᆨ HANGUL JONGSEONG KIYEOK */ + { 0x0ed5, 0x11a9 }, /* Hangul_J_SsangKiyeog ᆩ HANGUL JONGSEONG SSANGKIYEOK */ + { 0x0ed6, 0x11aa }, /* Hangul_J_KiyeogSios ᆪ HANGUL JONGSEONG KIYEOK-SIOS */ + { 0x0ed7, 0x11ab }, /* Hangul_J_Nieun ᆫ HANGUL JONGSEONG NIEUN */ + { 0x0ed8, 0x11ac }, /* Hangul_J_NieunJieuj ᆬ HANGUL JONGSEONG NIEUN-CIEUC */ + { 0x0ed9, 0x11ad }, /* Hangul_J_NieunHieuh ᆭ HANGUL JONGSEONG NIEUN-HIEUH */ + { 0x0eda, 0x11ae }, /* Hangul_J_Dikeud ᆮ HANGUL JONGSEONG TIKEUT */ + { 0x0edb, 0x11af }, /* Hangul_J_Rieul ᆯ HANGUL JONGSEONG RIEUL */ + { 0x0edc, 0x11b0 }, /* Hangul_J_RieulKiyeog ᆰ HANGUL JONGSEONG RIEUL-KIYEOK */ + { 0x0edd, 0x11b1 }, /* Hangul_J_RieulMieum ᆱ HANGUL JONGSEONG RIEUL-MIEUM */ + { 0x0ede, 0x11b2 }, /* Hangul_J_RieulPieub ᆲ HANGUL JONGSEONG RIEUL-PIEUP */ + { 0x0edf, 0x11b3 }, /* Hangul_J_RieulSios ᆳ HANGUL JONGSEONG RIEUL-SIOS */ + { 0x0ee0, 0x11b4 }, /* Hangul_J_RieulTieut ᆴ HANGUL JONGSEONG RIEUL-THIEUTH */ + { 0x0ee1, 0x11b5 }, /* Hangul_J_RieulPhieuf ᆵ HANGUL JONGSEONG RIEUL-PHIEUPH */ + { 0x0ee2, 0x11b6 }, /* Hangul_J_RieulHieuh ᆶ HANGUL JONGSEONG RIEUL-HIEUH */ + { 0x0ee3, 0x11b7 }, /* Hangul_J_Mieum ᆷ HANGUL JONGSEONG MIEUM */ + { 0x0ee4, 0x11b8 }, /* Hangul_J_Pieub ᆸ HANGUL JONGSEONG PIEUP */ + { 0x0ee5, 0x11b9 }, /* Hangul_J_PieubSios ᆹ HANGUL JONGSEONG PIEUP-SIOS */ + { 0x0ee6, 0x11ba }, /* Hangul_J_Sios ᆺ HANGUL JONGSEONG SIOS */ + { 0x0ee7, 0x11bb }, /* Hangul_J_SsangSios ᆻ HANGUL JONGSEONG SSANGSIOS */ + { 0x0ee8, 0x11bc }, /* Hangul_J_Ieung ᆼ HANGUL JONGSEONG IEUNG */ + { 0x0ee9, 0x11bd }, /* Hangul_J_Jieuj ᆽ HANGUL JONGSEONG CIEUC */ + { 0x0eea, 0x11be }, /* Hangul_J_Cieuc ᆾ HANGUL JONGSEONG CHIEUCH */ + { 0x0eeb, 0x11bf }, /* Hangul_J_Khieuq ᆿ HANGUL JONGSEONG KHIEUKH */ + { 0x0eec, 0x11c0 }, /* Hangul_J_Tieut ᇀ HANGUL JONGSEONG THIEUTH */ + { 0x0eed, 0x11c1 }, /* Hangul_J_Phieuf ᇁ HANGUL JONGSEONG PHIEUPH */ + { 0x0eee, 0x11c2 }, /* Hangul_J_Hieuh ᇂ HANGUL JONGSEONG HIEUH */ + { 0x0ef8, 0x11eb }, /* Hangul_J_PanSios ᇫ HANGUL JONGSEONG PANSIOS */ + { 0x0efa, 0x11f9 }, /* Hangul_J_YeorinHieuh ᇹ HANGUL JONGSEONG YEORINHIEUH */ + { 0x0aa2, 0x2002 }, /* enspace   EN SPACE */ + { 0x0aa1, 0x2003 }, /* emspace   EM SPACE */ + { 0x0aa3, 0x2004 }, /* em3space   THREE-PER-EM SPACE */ + { 0x0aa4, 0x2005 }, /* em4space   FOUR-PER-EM SPACE */ + { 0x0aa5, 0x2007 }, /* digitspace   FIGURE SPACE */ + { 0x0aa6, 0x2008 }, /* punctspace   PUNCTUATION SPACE */ + { 0x0aa7, 0x2009 }, /* thinspace   THIN SPACE */ + { 0x0aa8, 0x200a }, /* hairspace   HAIR SPACE */ + { 0x0abb, 0x2012 }, /* figdash ‒ FIGURE DASH */ + { 0x0aaa, 0x2013 }, /* endash – EN DASH */ + { 0x0aa9, 0x2014 }, /* emdash — EM DASH */ + { 0x07af, 0x2015 }, /* Greek_horizbar ― HORIZONTAL BAR */ + { 0x0cdf, 0x2017 }, /* hebrew_doublelowline ‗ DOUBLE LOW LINE */ + { 0x0ad0, 0x2018 }, /* leftsinglequotemark ‘ LEFT SINGLE QUOTATION MARK */ + { 0x0ad1, 0x2019 }, /* rightsinglequotemark ’ RIGHT SINGLE QUOTATION MARK */ + { 0x0afd, 0x201a }, /* singlelowquotemark ‚ SINGLE LOW-9 QUOTATION MARK */ + { 0x0ad2, 0x201c }, /* leftdoublequotemark “ LEFT DOUBLE QUOTATION MARK */ + { 0x0ad3, 0x201d }, /* rightdoublequotemark ” RIGHT DOUBLE QUOTATION MARK */ + { 0x0afe, 0x201e }, /* doublelowquotemark „ DOUBLE LOW-9 QUOTATION MARK */ + { 0x0af1, 0x2020 }, /* dagger † DAGGER */ + { 0x0af2, 0x2021 }, /* doubledagger ‡ DOUBLE DAGGER */ + { 0x0ae6, 0x2022 }, /* enfilledcircbullet • BULLET */ + { 0x0aae, 0x2026 }, /* ellipsis … HORIZONTAL ELLIPSIS */ + { 0x0ad6, 0x2032 }, /* minutes ′ PRIME */ + { 0x0ad7, 0x2033 }, /* seconds ″ DOUBLE PRIME */ + { 0x0afc, 0x2038 }, /* caret ‸ CARET */ + { 0x047e, 0x203e }, /* overline ‾ OVERLINE */ + { 0x20a0, 0x20a0 }, /* EcuSign ₠ EURO-CURRENCY SIGN */ + { 0x20a1, 0x20a1 }, /* ColonSign ₡ COLON SIGN */ + { 0x20a2, 0x20a2 }, /* CruzeiroSign ₢ CRUZEIRO SIGN */ + { 0x20a3, 0x20a3 }, /* FFrancSign ₣ FRENCH FRANC SIGN */ + { 0x20a4, 0x20a4 }, /* LiraSign ₤ LIRA SIGN */ + { 0x20a5, 0x20a5 }, /* MillSign ₥ MILL SIGN */ + { 0x20a6, 0x20a6 }, /* NairaSign ₦ NAIRA SIGN */ + { 0x20a7, 0x20a7 }, /* PesetaSign ₧ PESETA SIGN */ + { 0x20a8, 0x20a8 }, /* RupeeSign ₨ RUPEE SIGN */ + { 0x0eff, 0x20a9 }, /* Korean_Won ₩ WON SIGN */ + { 0x20a9, 0x20a9 }, /* WonSign ₩ WON SIGN */ + { 0x20aa, 0x20aa }, /* NewSheqelSign ₪ NEW SHEQEL SIGN */ + { 0x20ab, 0x20ab }, /* DongSign ₫ DONG SIGN */ + { 0x20ac, 0x20ac }, /* EuroSign € EURO SIGN */ + { 0x0ab8, 0x2105 }, /* careof ℅ CARE OF */ + { 0x06b0, 0x2116 }, /* numerosign № NUMERO SIGN */ + { 0x0afb, 0x2117 }, /* phonographcopyright ℗ SOUND RECORDING COPYRIGHT */ + { 0x0ad4, 0x211e }, /* prescription ℞ PRESCRIPTION TAKE */ + { 0x0ac9, 0x2122 }, /* trademark ™ TRADE MARK SIGN */ + { 0x0ab0, 0x2153 }, /* onethird ⅓ VULGAR FRACTION ONE THIRD */ + { 0x0ab1, 0x2154 }, /* twothirds ⅔ VULGAR FRACTION TWO THIRDS */ + { 0x0ab2, 0x2155 }, /* onefifth ⅕ VULGAR FRACTION ONE FIFTH */ + { 0x0ab3, 0x2156 }, /* twofifths ⅖ VULGAR FRACTION TWO FIFTHS */ + { 0x0ab4, 0x2157 }, /* threefifths ⅗ VULGAR FRACTION THREE FIFTHS */ + { 0x0ab5, 0x2158 }, /* fourfifths ⅘ VULGAR FRACTION FOUR FIFTHS */ + { 0x0ab6, 0x2159 }, /* onesixth ⅙ VULGAR FRACTION ONE SIXTH */ + { 0x0ab7, 0x215a }, /* fivesixths ⅚ VULGAR FRACTION FIVE SIXTHS */ + { 0x0ac3, 0x215b }, /* oneeighth ⅛ VULGAR FRACTION ONE EIGHTH */ + { 0x0ac4, 0x215c }, /* threeeighths ⅜ VULGAR FRACTION THREE EIGHTHS */ + { 0x0ac5, 0x215d }, /* fiveeighths ⅝ VULGAR FRACTION FIVE EIGHTHS */ + { 0x0ac6, 0x215e }, /* seveneighths ⅞ VULGAR FRACTION SEVEN EIGHTHS */ + { 0x08fb, 0x2190 }, /* leftarrow ← LEFTWARDS ARROW */ + { 0x08fc, 0x2191 }, /* uparrow ↑ UPWARDS ARROW */ + { 0x08fd, 0x2192 }, /* rightarrow → RIGHTWARDS ARROW */ + { 0x08fe, 0x2193 }, /* downarrow ↓ DOWNWARDS ARROW */ + { 0x08ce, 0x21d2 }, /* implies ⇒ RIGHTWARDS DOUBLE ARROW */ + { 0x08cd, 0x21d4 }, /* ifonlyif ⇔ LEFT RIGHT DOUBLE ARROW */ + { 0x08ef, 0x2202 }, /* partialderivative ∂ PARTIAL DIFFERENTIAL */ + { 0x08c5, 0x2207 }, /* nabla ∇ NABLA */ + { 0x0bca, 0x2218 }, /* jot ∘ RING OPERATOR */ + { 0x08d6, 0x221a }, /* radical √ SQUARE ROOT */ + { 0x08c1, 0x221d }, /* variation ∝ PROPORTIONAL TO */ + { 0x08c2, 0x221e }, /* infinity ∞ INFINITY */ + { 0x08de, 0x2227 }, /* logicaland ∧ LOGICAL AND */ + { 0x0ba9, 0x2227 }, /* upcaret ∧ LOGICAL AND */ + { 0x08df, 0x2228 }, /* logicalor ∨ LOGICAL OR */ + { 0x0ba8, 0x2228 }, /* downcaret ∨ LOGICAL OR */ + { 0x08dc, 0x2229 }, /* intersection ∩ INTERSECTION */ + { 0x0bc3, 0x2229 }, /* upshoe ∩ INTERSECTION */ + { 0x08dd, 0x222a }, /* union ∪ UNION */ + { 0x0bd6, 0x222a }, /* downshoe ∪ UNION */ + { 0x08bf, 0x222b }, /* integral ∫ INTEGRAL */ + { 0x08c0, 0x2234 }, /* therefore ∴ THEREFORE */ + { 0x08c8, 0x2245 }, /* approximate ≅ APPROXIMATELY EQUAL TO */ + { 0x08bd, 0x2260 }, /* notequal ≠ NOT EQUAL TO */ + { 0x08cf, 0x2261 }, /* identical ≡ IDENTICAL TO */ + { 0x08bc, 0x2264 }, /* lessthanequal ≤ LESS-THAN OR EQUAL TO */ + { 0x08be, 0x2265 }, /* greaterthanequal ≥ GREATER-THAN OR EQUAL TO */ + { 0x08da, 0x2282 }, /* includedin ⊂ SUBSET OF */ + { 0x0bda, 0x2282 }, /* leftshoe ⊂ SUBSET OF */ + { 0x08db, 0x2283 }, /* includes ⊃ SUPERSET OF */ + { 0x0bd8, 0x2283 }, /* rightshoe ⊃ SUPERSET OF */ + { 0x0bfc, 0x22a2 }, /* righttack ⊢ RIGHT TACK */ + { 0x0bdc, 0x22a3 }, /* lefttack ⊣ LEFT TACK */ + { 0x0bc2, 0x22a4 }, /* downtack ⊤ DOWN TACK */ + { 0x0bce, 0x22a5 }, /* uptack ⊥ UP TACK */ + { 0x0bd3, 0x2308 }, /* upstile ⌈ LEFT CEILING */ + { 0x0bc4, 0x230a }, /* downstile ⌊ LEFT FLOOR */ + { 0x0afa, 0x2315 }, /* telephonerecorder ⌕ TELEPHONE RECORDER */ + { 0x08a4, 0x2320 }, /* topintegral ⌠ TOP HALF INTEGRAL */ + { 0x08a5, 0x2321 }, /* botintegral ⌡ BOTTOM HALF INTEGRAL */ + { 0x0abc, 0x2329 }, /* leftanglebracket 〈 LEFT-POINTING ANGLE BRACKET */ + { 0x0abe, 0x232a }, /* rightanglebracket 〉 RIGHT-POINTING ANGLE BRACKET */ + { 0x0bcc, 0x2395 }, /* quad ⎕ APL FUNCTIONAL SYMBOL QUAD (Unicode 3.0) */ + { 0x09e2, 0x2409 }, /* ht ␉ SYMBOL FOR HORIZONTAL TABULATION */ + { 0x09e5, 0x240a }, /* lf ␊ SYMBOL FOR LINE FEED */ + { 0x09e9, 0x240b }, /* vt ␋ SYMBOL FOR VERTICAL TABULATION */ + { 0x09e3, 0x240c }, /* ff ␌ SYMBOL FOR FORM FEED */ + { 0x09e4, 0x240d }, /* cr ␍ SYMBOL FOR CARRIAGE RETURN */ + { 0x09df, 0x2422 }, /* blank ␢ BLANK SYMBOL */ + { 0x09e8, 0x2424 }, /* nl ␤ SYMBOL FOR NEWLINE */ + { 0x09f1, 0x2500 }, /* horizlinescan5 ─ BOX DRAWINGS LIGHT HORIZONTAL */ + { 0x08a6, 0x2502 }, /* vertconnector │ BOX DRAWINGS LIGHT VERTICAL */ + { 0x09f8, 0x2502 }, /* vertbar │ BOX DRAWINGS LIGHT VERTICAL */ + { 0x09ec, 0x250c }, /* upleftcorner ┌ BOX DRAWINGS LIGHT DOWN AND RIGHT */ + { 0x09eb, 0x2510 }, /* uprightcorner ┐ BOX DRAWINGS LIGHT DOWN AND LEFT */ + { 0x09ed, 0x2514 }, /* lowleftcorner └ BOX DRAWINGS LIGHT UP AND RIGHT */ + { 0x09ea, 0x2518 }, /* lowrightcorner ┘ BOX DRAWINGS LIGHT UP AND LEFT */ + { 0x09f4, 0x251c }, /* leftt ├ BOX DRAWINGS LIGHT VERTICAL AND RIGHT */ + { 0x09f5, 0x2524 }, /* rightt ┤ BOX DRAWINGS LIGHT VERTICAL AND LEFT */ + { 0x09f7, 0x252c }, /* topt ┬ BOX DRAWINGS LIGHT DOWN AND HORIZONTAL */ + { 0x09f6, 0x2534 }, /* bott ┴ BOX DRAWINGS LIGHT UP AND HORIZONTAL */ + { 0x09ee, 0x253c }, /* crossinglines ┼ BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL */ + { 0x09e1, 0x2592 }, /* checkerboard ▒ MEDIUM SHADE */ + { 0x0adf, 0x25a0 }, /* emfilledrect ■ BLACK SQUARE */ + { 0x0acf, 0x25a1 }, /* emopenrectangle □ WHITE SQUARE */ + { 0x0ae7, 0x25aa }, /* enfilledsqbullet ▪ BLACK SMALL SQUARE */ + { 0x0ae1, 0x25ab }, /* enopensquarebullet ▫ WHITE SMALL SQUARE */ + { 0x0adb, 0x25ac }, /* filledrectbullet ▬ BLACK RECTANGLE */ + { 0x0ae2, 0x25ad }, /* openrectbullet ▭ WHITE RECTANGLE */ + { 0x0ae8, 0x25b2 }, /* filledtribulletup ▲ BLACK UP-POINTING TRIANGLE */ + { 0x0ae3, 0x25b3 }, /* opentribulletup △ WHITE UP-POINTING TRIANGLE */ + { 0x0add, 0x25b6 }, /* filledrighttribullet ▶ BLACK RIGHT-POINTING TRIANGLE */ + { 0x0acd, 0x25b7 }, /* rightopentriangle ▷ WHITE RIGHT-POINTING TRIANGLE */ + { 0x0ae9, 0x25bc }, /* filledtribulletdown ▼ BLACK DOWN-POINTING TRIANGLE */ + { 0x0ae4, 0x25bd }, /* opentribulletdown ▽ WHITE DOWN-POINTING TRIANGLE */ + { 0x0adc, 0x25c0 }, /* filledlefttribullet ◀ BLACK LEFT-POINTING TRIANGLE */ + { 0x0acc, 0x25c1 }, /* leftopentriangle ◁ WHITE LEFT-POINTING TRIANGLE */ + { 0x09e0, 0x25c6 }, /* soliddiamond ◆ BLACK DIAMOND */ + { 0x0ace, 0x25cb }, /* emopencircle ○ WHITE CIRCLE */ + { 0x0bcf, 0x25cb }, /* circle ○ WHITE CIRCLE */ + { 0x0ade, 0x25cf }, /* emfilledcircle ● BLACK CIRCLE */ + { 0x0ae0, 0x25e6 }, /* enopencircbullet ◦ WHITE BULLET */ + { 0x0ae5, 0x2606 }, /* openstar ☆ WHITE STAR */ + { 0x0af9, 0x260e }, /* telephone ☎ BLACK TELEPHONE */ + { 0x0aca, 0x2613 }, /* signaturemark ☓ SALTIRE */ + { 0x0aea, 0x261c }, /* leftpointer ☜ WHITE LEFT POINTING INDEX */ + { 0x0aeb, 0x261e }, /* rightpointer ☞ WHITE RIGHT POINTING INDEX */ + { 0x0af8, 0x2640 }, /* femalesymbol ♀ FEMALE SIGN */ + { 0x0af7, 0x2642 }, /* malesymbol ♂ MALE SIGN */ + { 0x0aec, 0x2663 }, /* club ♣ BLACK CLUB SUIT */ + { 0x0aee, 0x2665 }, /* heart ♥ BLACK HEART SUIT */ + { 0x0aed, 0x2666 }, /* diamond ♦ BLACK DIAMOND SUIT */ + { 0x0af6, 0x266d }, /* musicalflat ♭ MUSIC FLAT SIGN */ + { 0x0af5, 0x266f }, /* musicalsharp ♯ MUSIC SHARP SIGN */ + { 0x0af3, 0x2713 }, /* checkmark ✓ CHECK MARK */ + { 0x0af4, 0x2717 }, /* ballotcross ✗ BALLOT X */ + { 0x0ad9, 0x271d }, /* latincross ✝ LATIN CROSS */ + { 0x0af0, 0x2720 }, /* maltesecross ✠ MALTESE CROSS */ + { 0x04a4, 0x3001 }, /* kana_comma 、 IDEOGRAPHIC COMMA */ + { 0x04a1, 0x3002 }, /* kana_fullstop 。 IDEOGRAPHIC FULL STOP */ + { 0x04a2, 0x300c }, /* kana_openingbracket 「 LEFT CORNER BRACKET */ + { 0x04a3, 0x300d }, /* kana_closingbracket 」 RIGHT CORNER BRACKET */ + { 0x04de, 0x309b }, /* voicedsound ゛ KATAKANA-HIRAGANA VOICED SOUND MARK */ + { 0x04df, 0x309c }, /* semivoicedsound ゜ KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK */ + { 0x04a7, 0x30a1 }, /* kana_a ァ KATAKANA LETTER SMALL A */ + { 0x04b1, 0x30a2 }, /* kana_A ア KATAKANA LETTER A */ + { 0x04a8, 0x30a3 }, /* kana_i ィ KATAKANA LETTER SMALL I */ + { 0x04b2, 0x30a4 }, /* kana_I イ KATAKANA LETTER I */ + { 0x04a9, 0x30a5 }, /* kana_u ゥ KATAKANA LETTER SMALL U */ + { 0x04b3, 0x30a6 }, /* kana_U ウ KATAKANA LETTER U */ + { 0x04aa, 0x30a7 }, /* kana_e ェ KATAKANA LETTER SMALL E */ + { 0x04b4, 0x30a8 }, /* kana_E エ KATAKANA LETTER E */ + { 0x04ab, 0x30a9 }, /* kana_o ォ KATAKANA LETTER SMALL O */ + { 0x04b5, 0x30aa }, /* kana_O オ KATAKANA LETTER O */ + { 0x04b6, 0x30ab }, /* kana_KA カ KATAKANA LETTER KA */ + { 0x04b7, 0x30ad }, /* kana_KI キ KATAKANA LETTER KI */ + { 0x04b8, 0x30af }, /* kana_KU ク KATAKANA LETTER KU */ + { 0x04b9, 0x30b1 }, /* kana_KE ケ KATAKANA LETTER KE */ + { 0x04ba, 0x30b3 }, /* kana_KO コ KATAKANA LETTER KO */ + { 0x04bb, 0x30b5 }, /* kana_SA サ KATAKANA LETTER SA */ + { 0x04bc, 0x30b7 }, /* kana_SHI シ KATAKANA LETTER SI */ + { 0x04bd, 0x30b9 }, /* kana_SU ス KATAKANA LETTER SU */ + { 0x04be, 0x30bb }, /* kana_SE セ KATAKANA LETTER SE */ + { 0x04bf, 0x30bd }, /* kana_SO ソ KATAKANA LETTER SO */ + { 0x04c0, 0x30bf }, /* kana_TA タ KATAKANA LETTER TA */ + { 0x04c1, 0x30c1 }, /* kana_CHI チ KATAKANA LETTER TI */ + { 0x04af, 0x30c3 }, /* kana_tsu ッ KATAKANA LETTER SMALL TU */ + { 0x04c2, 0x30c4 }, /* kana_TSU ツ KATAKANA LETTER TU */ + { 0x04c3, 0x30c6 }, /* kana_TE テ KATAKANA LETTER TE */ + { 0x04c4, 0x30c8 }, /* kana_TO ト KATAKANA LETTER TO */ + { 0x04c5, 0x30ca }, /* kana_NA ナ KATAKANA LETTER NA */ + { 0x04c6, 0x30cb }, /* kana_NI ニ KATAKANA LETTER NI */ + { 0x04c7, 0x30cc }, /* kana_NU ヌ KATAKANA LETTER NU */ + { 0x04c8, 0x30cd }, /* kana_NE ネ KATAKANA LETTER NE */ + { 0x04c9, 0x30ce }, /* kana_NO ノ KATAKANA LETTER NO */ + { 0x04ca, 0x30cf }, /* kana_HA ハ KATAKANA LETTER HA */ + { 0x04cb, 0x30d2 }, /* kana_HI ヒ KATAKANA LETTER HI */ + { 0x04cc, 0x30d5 }, /* kana_FU フ KATAKANA LETTER HU */ + { 0x04cd, 0x30d8 }, /* kana_HE ヘ KATAKANA LETTER HE */ + { 0x04ce, 0x30db }, /* kana_HO ホ KATAKANA LETTER HO */ + { 0x04cf, 0x30de }, /* kana_MA マ KATAKANA LETTER MA */ + { 0x04d0, 0x30df }, /* kana_MI ミ KATAKANA LETTER MI */ + { 0x04d1, 0x30e0 }, /* kana_MU ム KATAKANA LETTER MU */ + { 0x04d2, 0x30e1 }, /* kana_ME メ KATAKANA LETTER ME */ + { 0x04d3, 0x30e2 }, /* kana_MO モ KATAKANA LETTER MO */ + { 0x04ac, 0x30e3 }, /* kana_ya ャ KATAKANA LETTER SMALL YA */ + { 0x04d4, 0x30e4 }, /* kana_YA ヤ KATAKANA LETTER YA */ + { 0x04ad, 0x30e5 }, /* kana_yu ュ KATAKANA LETTER SMALL YU */ + { 0x04d5, 0x30e6 }, /* kana_YU ユ KATAKANA LETTER YU */ + { 0x04ae, 0x30e7 }, /* kana_yo ョ KATAKANA LETTER SMALL YO */ + { 0x04d6, 0x30e8 }, /* kana_YO ヨ KATAKANA LETTER YO */ + { 0x04d7, 0x30e9 }, /* kana_RA ラ KATAKANA LETTER RA */ + { 0x04d8, 0x30ea }, /* kana_RI リ KATAKANA LETTER RI */ + { 0x04d9, 0x30eb }, /* kana_RU ル KATAKANA LETTER RU */ + { 0x04da, 0x30ec }, /* kana_RE レ KATAKANA LETTER RE */ + { 0x04db, 0x30ed }, /* kana_RO ロ KATAKANA LETTER RO */ + { 0x04dc, 0x30ef }, /* kana_WA ワ KATAKANA LETTER WA */ + { 0x04a6, 0x30f2 }, /* kana_WO ヲ KATAKANA LETTER WO */ + { 0x04dd, 0x30f3 }, /* kana_N ン KATAKANA LETTER N */ + { 0x04a5, 0x30fb }, /* kana_conjunctive ・ KATAKANA MIDDLE DOT */ + { 0x04b0, 0x30fc }, /* prolongedsound ー KATAKANA-HIRAGANA PROLONGED SOUND MARK */ + { 0x0ea1, 0x3131 }, /* Hangul_Kiyeog ㄱ HANGUL LETTER KIYEOK */ + { 0x0ea2, 0x3132 }, /* Hangul_SsangKiyeog ㄲ HANGUL LETTER SSANGKIYEOK */ + { 0x0ea3, 0x3133 }, /* Hangul_KiyeogSios ㄳ HANGUL LETTER KIYEOK-SIOS */ + { 0x0ea4, 0x3134 }, /* Hangul_Nieun ㄴ HANGUL LETTER NIEUN */ + { 0x0ea5, 0x3135 }, /* Hangul_NieunJieuj ㄵ HANGUL LETTER NIEUN-CIEUC */ + { 0x0ea6, 0x3136 }, /* Hangul_NieunHieuh ㄶ HANGUL LETTER NIEUN-HIEUH */ + { 0x0ea7, 0x3137 }, /* Hangul_Dikeud ㄷ HANGUL LETTER TIKEUT */ + { 0x0ea8, 0x3138 }, /* Hangul_SsangDikeud ㄸ HANGUL LETTER SSANGTIKEUT */ + { 0x0ea9, 0x3139 }, /* Hangul_Rieul ㄹ HANGUL LETTER RIEUL */ + { 0x0eaa, 0x313a }, /* Hangul_RieulKiyeog ㄺ HANGUL LETTER RIEUL-KIYEOK */ + { 0x0eab, 0x313b }, /* Hangul_RieulMieum ㄻ HANGUL LETTER RIEUL-MIEUM */ + { 0x0eac, 0x313c }, /* Hangul_RieulPieub ㄼ HANGUL LETTER RIEUL-PIEUP */ + { 0x0ead, 0x313d }, /* Hangul_RieulSios ㄽ HANGUL LETTER RIEUL-SIOS */ + { 0x0eae, 0x313e }, /* Hangul_RieulTieut ㄾ HANGUL LETTER RIEUL-THIEUTH */ + { 0x0eaf, 0x313f }, /* Hangul_RieulPhieuf ㄿ HANGUL LETTER RIEUL-PHIEUPH */ + { 0x0eb0, 0x3140 }, /* Hangul_RieulHieuh ㅀ HANGUL LETTER RIEUL-HIEUH */ + { 0x0eb1, 0x3141 }, /* Hangul_Mieum ㅁ HANGUL LETTER MIEUM */ + { 0x0eb2, 0x3142 }, /* Hangul_Pieub ㅂ HANGUL LETTER PIEUP */ + { 0x0eb3, 0x3143 }, /* Hangul_SsangPieub ㅃ HANGUL LETTER SSANGPIEUP */ + { 0x0eb4, 0x3144 }, /* Hangul_PieubSios ㅄ HANGUL LETTER PIEUP-SIOS */ + { 0x0eb5, 0x3145 }, /* Hangul_Sios ㅅ HANGUL LETTER SIOS */ + { 0x0eb6, 0x3146 }, /* Hangul_SsangSios ㅆ HANGUL LETTER SSANGSIOS */ + { 0x0eb7, 0x3147 }, /* Hangul_Ieung ㅇ HANGUL LETTER IEUNG */ + { 0x0eb8, 0x3148 }, /* Hangul_Jieuj ㅈ HANGUL LETTER CIEUC */ + { 0x0eb9, 0x3149 }, /* Hangul_SsangJieuj ㅉ HANGUL LETTER SSANGCIEUC */ + { 0x0eba, 0x314a }, /* Hangul_Cieuc ㅊ HANGUL LETTER CHIEUCH */ + { 0x0ebb, 0x314b }, /* Hangul_Khieuq ㅋ HANGUL LETTER KHIEUKH */ + { 0x0ebc, 0x314c }, /* Hangul_Tieut ㅌ HANGUL LETTER THIEUTH */ + { 0x0ebd, 0x314d }, /* Hangul_Phieuf ㅍ HANGUL LETTER PHIEUPH */ + { 0x0ebe, 0x314e }, /* Hangul_Hieuh ㅎ HANGUL LETTER HIEUH */ + { 0x0ebf, 0x314f }, /* Hangul_A ㅏ HANGUL LETTER A */ + { 0x0ec0, 0x3150 }, /* Hangul_AE ㅐ HANGUL LETTER AE */ + { 0x0ec1, 0x3151 }, /* Hangul_YA ㅑ HANGUL LETTER YA */ + { 0x0ec2, 0x3152 }, /* Hangul_YAE ㅒ HANGUL LETTER YAE */ + { 0x0ec3, 0x3153 }, /* Hangul_EO ㅓ HANGUL LETTER EO */ + { 0x0ec4, 0x3154 }, /* Hangul_E ㅔ HANGUL LETTER E */ + { 0x0ec5, 0x3155 }, /* Hangul_YEO ㅕ HANGUL LETTER YEO */ + { 0x0ec6, 0x3156 }, /* Hangul_YE ㅖ HANGUL LETTER YE */ + { 0x0ec7, 0x3157 }, /* Hangul_O ㅗ HANGUL LETTER O */ + { 0x0ec8, 0x3158 }, /* Hangul_WA ㅘ HANGUL LETTER WA */ + { 0x0ec9, 0x3159 }, /* Hangul_WAE ㅙ HANGUL LETTER WAE */ + { 0x0eca, 0x315a }, /* Hangul_OE ㅚ HANGUL LETTER OE */ + { 0x0ecb, 0x315b }, /* Hangul_YO ㅛ HANGUL LETTER YO */ + { 0x0ecc, 0x315c }, /* Hangul_U ㅜ HANGUL LETTER U */ + { 0x0ecd, 0x315d }, /* Hangul_WEO ㅝ HANGUL LETTER WEO */ + { 0x0ece, 0x315e }, /* Hangul_WE ㅞ HANGUL LETTER WE */ + { 0x0ecf, 0x315f }, /* Hangul_WI ㅟ HANGUL LETTER WI */ + { 0x0ed0, 0x3160 }, /* Hangul_YU ㅠ HANGUL LETTER YU */ + { 0x0ed1, 0x3161 }, /* Hangul_EU ㅡ HANGUL LETTER EU */ + { 0x0ed2, 0x3162 }, /* Hangul_YI ㅢ HANGUL LETTER YI */ + { 0x0ed3, 0x3163 }, /* Hangul_I ㅣ HANGUL LETTER I */ + { 0x0eef, 0x316d }, /* Hangul_RieulYeorinHieuh ㅭ HANGUL LETTER RIEUL-YEORINHIEUH */ + { 0x0ef0, 0x3171 }, /* Hangul_SunkyeongeumMieum ㅱ HANGUL LETTER KAPYEOUNMIEUM */ + { 0x0ef1, 0x3178 }, /* Hangul_SunkyeongeumPieub ㅸ HANGUL LETTER KAPYEOUNPIEUP */ + { 0x0ef2, 0x317f }, /* Hangul_PanSios ㅿ HANGUL LETTER PANSIOS */ + { 0x0ef4, 0x3184 }, /* Hangul_SunkyeongeumPhieuf ㆄ HANGUL LETTER KAPYEOUNPHIEUPH */ + { 0x0ef5, 0x3186 }, /* Hangul_YeorinHieuh ㆆ HANGUL LETTER YEORINHIEUH */ + { 0x0ef6, 0x318d }, /* Hangul_AraeA ㆍ HANGUL LETTER ARAEA */ + { 0x0ef7, 0x318e }, /* Hangul_AraeAE ㆎ HANGUL LETTER ARAEAE */ +}; + +static guint +unicode_to_keyval (wchar_t ucs) +{ + int min = 0; + int max = sizeof(u2ktab) / sizeof(u2ktab[0]) - 1; + int mid; + + /* First check for Latin-1 characters (1:1 mapping) */ + if ((ucs >= 0x0020 && ucs <= 0x007e) || + (ucs >= 0x00a0 && ucs <= 0x00ff)) + return ucs; + + /* Binary search in table */ + while (max >= min) { + mid = (min + max) / 2; + if (u2ktab[mid].ucs < ucs) + min = mid + 1; + else if (u2ktab[mid].ucs > ucs) + max = mid - 1; + else { + /* found it */ + return u2ktab[mid].keysym; + } + } + + /* + * No matching keysym value found, return Unicode value plus 0x01000000 + * (a convention introduced in the UTF-8 work on xterm). + */ + return ucs | 0x01000000; +} + +static void +build_key_event_state (GdkEvent *event) +{ + event->key.state = 0; + if (GetKeyState (VK_SHIFT) < 0) + event->key.state |= GDK_SHIFT_MASK; + if (GetKeyState (VK_CAPITAL) & 0x1) + event->key.state |= GDK_LOCK_MASK; + if (!is_AltGr_key) + { + if (GetKeyState (VK_CONTROL) < 0) + { + event->key.state |= GDK_CONTROL_MASK; + if (event->key.keyval < ' ') + event->key.keyval += '@'; + } + else if (event->key.keyval < ' ') + { + event->key.state |= GDK_CONTROL_MASK; + event->key.keyval += '@'; + } + if (GetKeyState (VK_MENU) < 0) + event->key.state |= GDK_MOD1_MASK; + } +} + +static gint +build_pointer_event_state (MSG *xevent) +{ + gint state; + + state = 0; + if (xevent->wParam & MK_CONTROL) + state |= GDK_CONTROL_MASK; + if (xevent->wParam & MK_LBUTTON) + state |= GDK_BUTTON1_MASK; + if (xevent->wParam & MK_MBUTTON) + state |= GDK_BUTTON2_MASK; + if (xevent->wParam & MK_RBUTTON) + state |= GDK_BUTTON3_MASK; + if (xevent->wParam & MK_SHIFT) + state |= GDK_SHIFT_MASK; + if (GetKeyState (VK_MENU) < 0) + state |= GDK_MOD1_MASK; + if (GetKeyState (VK_CAPITAL) & 0x1) + state |= GDK_LOCK_MASK; + + return state; +} + + +static void +build_keypress_event (GdkWindowPrivate *window_private, + GdkEvent *event, + MSG *xevent) +{ + HIMC hIMC; + gint i, bytesleft, bytecount, ucount, ucleft, len; + guchar buf[100], *bp; + wchar_t wbuf[100], *wcp; + + event->key.type = GDK_KEY_PRESS; + event->key.time = xevent->time; + + if (xevent->message == WM_IME_COMPOSITION) + { + hIMC = ImmGetContext (xevent->hwnd); + + bytecount = ImmGetCompositionStringW (hIMC, GCS_RESULTSTR, + wbuf, sizeof (wbuf)); + ucount = bytecount / 2; + } + else + { + if (xevent->message == WM_CHAR) + { + bytecount = MIN ((xevent->lParam & 0xFFFF), sizeof (buf)); + for (i = 0; i < bytecount; i++) + buf[i] = xevent->wParam; + } + else /* WM_IME_CHAR */ + { + event->key.keyval = GDK_VoidSymbol; + if (xevent->wParam & 0xFF00) + { + /* Contrary to some versions of the documentation, + * the lead byte is the most significant byte. + */ + buf[0] = ((xevent->wParam >> 8) & 0xFF); + buf[1] = (xevent->wParam & 0xFF); + bytecount = 2; + } + else + { + buf[0] = (xevent->wParam & 0xFF); + bytecount = 1; + } + } + + /* Convert from the window's current code page + * to Unicode. Then convert to UTF-8. + * We don't handle the surrogate stuff. Should we? + */ + ucount = MultiByteToWideChar (window_private->charset_info.ciACP, + 0, buf, bytecount, + wbuf, sizeof (wbuf) / sizeof (wbuf[0])); + + } + if (ucount == 0) + event->key.keyval = GDK_VoidSymbol; + else if (xevent->message == WM_CHAR) + if (xevent->wParam < ' ') + event->key.keyval = xevent->wParam + '@'; + else + event->key.keyval = unicode_to_keyval (wbuf[0]); + else + event->key.keyval = GDK_VoidSymbol; + + build_key_event_state (event); + + ucleft = ucount; + len = 0; + wcp = wbuf; + while (ucleft-- > 0) + { + wchar_t c = *wcp++; + + if (c < 0x80) + len += 1; + else if (c < 0x800) + len += 2; + else + len += 3; + } + + event->key.string = g_malloc (len + 1); + event->key.length = len; + + ucleft = ucount; + wcp = wbuf; + bp = event->key.string; + while (ucleft-- > 0) + { + int first; + int i; + wchar_t c = *wcp++; + + if (c < 0x80) + { + first = 0; + len = 1; + } + else if (c < 0x800) + { + first = 0xc0; + len = 2; + } + else + { + first = 0xe0; + len = 3; + } + +#if 1 + /* Woo-hoo! */ + switch (len) + { + case 3: bp[2] = (c & 0x3f) | 0x80; c >>= 6; /* Fall through */ + case 2: bp[1] = (c & 0x3f) | 0x80; c >>= 6; /* Fall through */ + case 1: bp[0] = c | first; + } +#else + for (i = len - 1; i > 0; --i) + { + bp[i] = (c & 0x3f) | 0x80; + c >>= 6; + } + bp[0] = c | first; +#endif + + bp += len; + } + *bp = 0; +} + +static void +build_keyrelease_event (GdkWindowPrivate *window_private, + GdkEvent *event, + MSG *xevent) +{ + guchar buf; + wchar_t wbuf; + + event->key.type = GDK_KEY_RELEASE; + event->key.time = xevent->time; + + if (xevent->message == WM_CHAR) + if (xevent->wParam < ' ') + event->key.keyval = xevent->wParam + '@'; + else + { + buf = xevent->wParam; + MultiByteToWideChar (window_private->charset_info.ciACP, + 0, &buf, 1, &wbuf, 1); + + event->key.keyval = unicode_to_keyval (wbuf); + } + else + event->key.keyval = GDK_VoidSymbol; + build_key_event_state (event); + event->key.string = NULL; + event->key.length = 0; +} + +static void +print_event_state (gint state) +{ + if (state & GDK_SHIFT_MASK) + g_print ("SHIFT "); + if (state & GDK_LOCK_MASK) + g_print ("LOCK "); + if (state & GDK_CONTROL_MASK) + g_print ("CONTROL "); + if (state & GDK_MOD1_MASK) + g_print ("MOD1 "); + if (state & GDK_BUTTON1_MASK) + g_print ("BUTTON1 "); + if (state & GDK_BUTTON2_MASK) + g_print ("BUTTON2 "); + if (state & GDK_BUTTON3_MASK) + g_print ("BUTTON3 "); +} + +static void +print_event (GdkEvent *event) +{ + gchar *escaped, *kvname; + + switch (event->any.type) + { + case GDK_NOTHING: g_print ("GDK_NOTHING "); break; + case GDK_DELETE: g_print ("GDK_DELETE "); break; + case GDK_DESTROY: g_print ("GDK_DESTROY "); break; + case GDK_EXPOSE: g_print ("GDK_EXPOSE "); break; + case GDK_MOTION_NOTIFY: g_print ("GDK_MOTION_NOTIFY "); break; + case GDK_BUTTON_PRESS: g_print ("GDK_BUTTON_PRESS "); break; + case GDK_2BUTTON_PRESS: g_print ("GDK_2BUTTON_PRESS "); break; + case GDK_3BUTTON_PRESS: g_print ("GDK_3BUTTON_PRESS "); break; + case GDK_BUTTON_RELEASE: g_print ("GDK_BUTTON_RELEASE "); break; + case GDK_KEY_PRESS: g_print ("GDK_KEY_PRESS "); break; + case GDK_KEY_RELEASE: g_print ("GDK_KEY_RELEASE "); break; + case GDK_ENTER_NOTIFY: g_print ("GDK_ENTER_NOTIFY "); break; + case GDK_LEAVE_NOTIFY: g_print ("GDK_LEAVE_NOTIFY "); break; + case GDK_FOCUS_CHANGE: g_print ("GDK_FOCUS_CHANGE "); break; + case GDK_CONFIGURE: g_print ("GDK_CONFIGURE "); break; + case GDK_MAP: g_print ("GDK_MAP "); break; + case GDK_UNMAP: g_print ("GDK_UNMAP "); break; + case GDK_PROPERTY_NOTIFY: g_print ("GDK_PROPERTY_NOTIFY "); break; + case GDK_SELECTION_CLEAR: g_print ("GDK_SELECTION_CLEAR "); break; + case GDK_SELECTION_REQUEST: g_print ("GDK_SELECTION_REQUEST "); break; + case GDK_SELECTION_NOTIFY: g_print ("GDK_SELECTION_NOTIFY "); break; + case GDK_PROXIMITY_IN: g_print ("GDK_PROXIMITY_IN "); break; + case GDK_PROXIMITY_OUT: g_print ("GDK_PROXIMITY_OUT "); break; + case GDK_DRAG_ENTER: g_print ("GDK_DRAG_ENTER "); break; + case GDK_DRAG_LEAVE: g_print ("GDK_DRAG_LEAVE "); break; + case GDK_DRAG_MOTION: g_print ("GDK_DRAG_MOTION "); break; + case GDK_DRAG_STATUS: g_print ("GDK_DRAG_STATUS "); break; + case GDK_DROP_START: g_print ("GDK_DROP_START "); break; + case GDK_DROP_FINISHED: g_print ("GDK_DROP_FINISHED "); break; + case GDK_CLIENT_EVENT: g_print ("GDK_CLIENT_EVENT "); break; + case GDK_VISIBILITY_NOTIFY: g_print ("GDK_VISIBILITY_NOTIFY "); break; + case GDK_NO_EXPOSE: g_print ("GDK_NO_EXPOSE "); break; + } + g_print ("%#x ", GDK_DRAWABLE_XID (event->any.window)); + + switch (event->any.type) + { + case GDK_EXPOSE: + g_print ("%dx%d@+%d+%d %d", + event->expose.area.width, + event->expose.area.height, + event->expose.area.x, + event->expose.area.y, + event->expose.count); + break; + case GDK_MOTION_NOTIFY: + g_print ("(%.4g,%.4g) %s", + event->motion.x, event->motion.y, + event->motion.is_hint ? "HINT " : ""); + print_event_state (event->motion.state); + break; + case GDK_BUTTON_PRESS: + case GDK_2BUTTON_PRESS: + case GDK_3BUTTON_PRESS: + case GDK_BUTTON_RELEASE: + g_print ("%d (%.4g,%.4g) ", + event->button.button, + event->button.x, event->button.y); + print_event_state (event->button.state); + break; + case GDK_KEY_PRESS: + case GDK_KEY_RELEASE: + if (event->key.length == 0) + escaped = g_strdup (""); + else + escaped = g_strescape (event->key.string, NULL); + kvname = gdk_keyval_name (event->key.keyval); + g_print ("%s %d:\"%s\" ", + (kvname ? kvname : "??"), + event->key.length, + escaped); + g_free (escaped); + print_event_state (event->key.state); + break; + case GDK_ENTER_NOTIFY: + case GDK_LEAVE_NOTIFY: + g_print (" %s", + (event->crossing.detail == GDK_NOTIFY_INFERIOR ? "INFERIOR" : + (event->crossing.detail == GDK_NOTIFY_ANCESTOR ? "ANCESTOR" : + (event->crossing.detail == GDK_NOTIFY_NONLINEAR ? "NONLINEAR" : + "???")))); + break; + } + g_print ("\n"); +} + +static void +synthesize_crossing_events (GdkWindow *window, + MSG *xevent) +{ + GdkEvent *event; + + /* If we are not using TrackMouseEvent, generate a leave notify + * event if necessary + */ + if (p_TrackMouseEvent == NULL + && curWnd + && (WINDOW_PRIVATE(curWnd)->event_mask & GDK_LEAVE_NOTIFY_MASK)) + { + GDK_NOTE (EVENTS, g_print ("synthesizing LEAVE_NOTIFY event\n")); + + event = gdk_event_new (); + event->crossing.type = GDK_LEAVE_NOTIFY; + event->crossing.window = curWnd; + gdk_window_ref (event->crossing.window); + event->crossing.subwindow = NULL; + event->crossing.time = xevent->time; + event->crossing.x = curX; + event->crossing.y = curY; + event->crossing.x_root = curXroot; + event->crossing.y_root = curYroot; + event->crossing.mode = GDK_CROSSING_NORMAL; + if (IsChild (GDK_DRAWABLE_XID (curWnd), GDK_DRAWABLE_XID (window))) + event->crossing.detail = GDK_NOTIFY_INFERIOR; + else if (IsChild (GDK_DRAWABLE_XID (window), GDK_DRAWABLE_XID (curWnd))) + event->crossing.detail = GDK_NOTIFY_ANCESTOR; + else + event->crossing.detail = GDK_NOTIFY_NONLINEAR; + + event->crossing.focus = TRUE; /* ??? */ + event->crossing.state = 0; /* ??? */ + + gdk_event_queue_append (event); + GDK_NOTE (EVENTS, print_event (event)); + } + + if (WINDOW_PRIVATE(window)->event_mask & GDK_ENTER_NOTIFY_MASK) + { + GDK_NOTE (EVENTS, g_print ("synthesizing ENTER_NOTIFY event\n")); + + event = gdk_event_new (); + event->crossing.type = GDK_ENTER_NOTIFY; + event->crossing.window = window; + gdk_window_ref (event->crossing.window); + event->crossing.subwindow = NULL; + event->crossing.time = xevent->time; + event->crossing.x = LOWORD (xevent->lParam); + event->crossing.y = HIWORD (xevent->lParam); + event->crossing.x_root = (gfloat) xevent->pt.x; + event->crossing.y_root = (gfloat) xevent->pt.y; + event->crossing.mode = GDK_CROSSING_NORMAL; + if (curWnd + && IsChild (GDK_DRAWABLE_XID (curWnd), GDK_DRAWABLE_XID (window))) + event->crossing.detail = GDK_NOTIFY_ANCESTOR; + else if (curWnd + && IsChild (GDK_DRAWABLE_XID (window), GDK_DRAWABLE_XID (curWnd))) + event->crossing.detail = GDK_NOTIFY_INFERIOR; + else + event->crossing.detail = GDK_NOTIFY_NONLINEAR; + + event->crossing.focus = TRUE; /* ??? */ + event->crossing.state = 0; /* ??? */ + + gdk_event_queue_append (event); + + GDK_NOTE (EVENTS, print_event (event)); + + if (WINDOW_PRIVATE(window)->extension_events != 0 + && gdk_input_vtable.enter_event) + gdk_input_vtable.enter_event (&event->crossing, window); + + } + + if (curWnd) + gdk_window_unref (curWnd); + curWnd = window; + gdk_window_ref (curWnd); +#ifdef USE_TRACKMOUSEEVENT + if (p_TrackMouseEvent != NULL) + { + TRACKMOUSEEVENT tme; + + tme.cbSize = sizeof (TRACKMOUSEEVENT); + tme.dwFlags = TME_LEAVE; + tme.hwndTrack = GDK_DRAWABLE_XID (curWnd); + tme.dwHoverTime = HOVER_DEFAULT; + + (*p_TrackMouseEvent) (&tme); + } +#endif +} + +#ifndef NEW_PROPAGATION_CODE + +static GdkWindow * +key_propagate (GdkWindow *window, + MSG *xevent) +{ + gdk_window_unref (window); + window = WINDOW_PRIVATE(window)->parent; + gdk_window_ref (window); + + return window; +} + +static GdkWindow * +pointer_propagate (GdkWindow *window, + MSG *xevent) +{ + POINT pt; + + pt.x = LOWORD (xevent->lParam); + pt.y = HIWORD (xevent->lParam); + ClientToScreen (GDK_DRAWABLE_XID (window), &pt); + gdk_window_unref (window); + window = WINDOW_PRIVATE(window)->parent; + gdk_window_ref (window); + ScreenToClient (GDK_DRAWABLE_XID (window), &pt); + xevent->lParam = MAKELPARAM (pt.x, pt.y); + + return window; +} + +#endif /* !NEW_PROPAGATION_CODE */ + +static void +translate_mouse_coords (GdkWindow *window1, + GdkWindow *window2, + MSG *xevent) +{ + POINT pt; + + pt.x = LOWORD (xevent->lParam); + pt.y = HIWORD (xevent->lParam); + ClientToScreen (GDK_DRAWABLE_XID (window1), &pt); + ScreenToClient (GDK_DRAWABLE_XID (window2), &pt); + xevent->lParam = MAKELPARAM (pt.x, pt.y); + GDK_NOTE (EVENTS, g_print ("...new coords are (%d,%d)\n", pt.x, pt.y)); +} + +#ifdef NEW_PROPAGATION_CODE + +static gboolean +propagate (GdkWindow **window, + MSG *xevent, + GdkWindow *grab_window, + gboolean grab_owner_events, + gint grab_mask, + gboolean (*doesnt_want_it) (gint mask, + MSG *xevent)) +{ + if (grab_window != NULL && !grab_owner_events) + { + /* Event source is grabbed with owner_events FALSE */ + GDK_NOTE (EVENTS, g_print ("...grabbed, owner_events FALSE, ")); + if ((*doesnt_want_it) (grab_mask, xevent)) + { + GDK_NOTE (EVENTS, g_print ("...grabber doesn't want it\n")); + return FALSE; + } + else + { + GDK_NOTE (EVENTS, g_print ("...sending to grabber %#x\n", + GDK_DRAWABLE_XID (grab_window))); + gdk_window_unref (*window); + *window = grab_window; + gdk_window_ref (*window); + return TRUE; + } + } + while (TRUE) + { + if ((*doesnt_want_it) (WINDOW_PRIVATE(*window)->event_mask, xevent)) + { + /* Owner doesn't want it, propagate to parent. */ + if (WINDOW_PRIVATE(*window)->parent == (GdkWindow *) gdk_root_parent) + { + /* No parent; check if grabbed */ + if (grab_window != NULL) + { + /* Event source is grabbed with owner_events TRUE */ + GDK_NOTE (EVENTS, g_print ("...undelivered, but grabbed\n")); + if ((*doesnt_want_it) (grab_mask, xevent)) + { + /* Grabber doesn't want it either */ + GDK_NOTE (EVENTS, g_print ("...grabber doesn't want it\n")); + return FALSE; + } + else + { + /* Grabbed! */ + GDK_NOTE (EVENTS, g_print ("...sending to grabber %#x\n", + GDK_DRAWABLE_XID (grab_window))); + gdk_window_unref (*window); + *window = grab_window; + gdk_window_ref (*window); + return TRUE; + } + } + else + { + GDK_NOTE (EVENTS, g_print ("...undelivered\n")); + return FALSE; + } + } + else + { + gdk_window_unref (*window); + *window = WINDOW_PRIVATE(*window)->parent; + gdk_window_ref (*window); + GDK_NOTE (EVENTS, g_print ("...propagating to %#x\n", + GDK_DRAWABLE_XID (*window))); + /* The only branch where we actually continue the loop */ + } + } + else + return TRUE; + } +} + +static gboolean +doesnt_want_key (gint mask, + MSG *xevent) +{ + return (((xevent->message == WM_KEYUP + || xevent->message == WM_SYSKEYUP) + && !(mask & GDK_KEY_RELEASE_MASK)) + || + ((xevent->message == WM_KEYDOWN + || xevent->message == WM_SYSKEYDOWN) + && !(mask & GDK_KEY_PRESS_MASK))); +} + +static gboolean +doesnt_want_char (gint mask, + MSG *xevent) +{ + return !(mask & (GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK)); +} + +static gboolean +doesnt_want_button_press (gint mask, + MSG *xevent) +{ + return !(mask & GDK_BUTTON_PRESS_MASK); +} + +static gboolean +doesnt_want_button_release (gint mask, + MSG *xevent) +{ + return !(mask & GDK_BUTTON_RELEASE_MASK); +} + +static gboolean +doesnt_want_button_motion (gint mask, + MSG *xevent) +{ + return !((mask & GDK_POINTER_MOTION_MASK) + || ((xevent->wParam & (MK_LBUTTON|MK_MBUTTON|MK_RBUTTON)) + && (mask & GDK_BUTTON_MOTION_MASK)) + || ((xevent->wParam & MK_LBUTTON) + && (mask & GDK_BUTTON1_MOTION_MASK)) + || ((xevent->wParam & MK_MBUTTON) + && (mask & GDK_BUTTON2_MOTION_MASK)) + || ((xevent->wParam & MK_RBUTTON) + && (mask & GDK_BUTTON3_MOTION_MASK))); +} + +#endif + +static gboolean +gdk_event_translate (GdkEvent *event, + MSG *xevent, + gboolean *ret_val_flagp, + gint *ret_valp) +{ + GdkWindow *window, *orig_window; + GdkColormapPrivate *colormap_private; + HWND owner; + DWORD pidActWin; + DWORD pidThis; + DWORD dwStyle; + PAINTSTRUCT paintstruct; + HDC hdc; + HBRUSH hbr; + RECT rect; + POINT pt; + MINMAXINFO *lpmmi; + GdkEventMask mask; + GdkDrawablePrivate *pixmap_private; + HDC bgdc; + HGDIOBJ oldbitmap; + int button; + int i, j, n, k; + gchar buf[256]; + gchar *msgname; + gboolean return_val; + gboolean flag; + + return_val = FALSE; + + if (ret_val_flagp) + *ret_val_flagp = FALSE; + +#ifndef USE_DISPATCHMESSAGE + if (xevent->message == gdk_ping_msg) + { + /* Messages we post ourselves just to wakeup WaitMessage. */ + GDK_NOTE (EVENTS, g_print ("gdk_ping_msg\n")); + + return FALSE; + } + else if (xevent->message == g_pipe_readable_msg) + { + GDK_NOTE (EVENTS, g_print ("g_pipe_readable_msg: %d %d\n", + xevent->wParam, xevent->lParam)); + + g_io_channel_win32_pipe_readable (xevent->wParam, xevent->lParam); + return FALSE; + } +#endif + + window = gdk_window_lookup (xevent->hwnd); + orig_window = window; + + if (window != NULL) + gdk_window_ref (window); + else + { + /* Handle WM_QUIT here ? */ + if (xevent->message == WM_QUIT) + { + GDK_NOTE (EVENTS, g_print ("WM_QUIT: %d\n", xevent->wParam)); + exit (xevent->wParam); + } + else if (xevent->message == WM_MOVE + || xevent->message == WM_SIZE) + { + /* It's quite normal to get these messages before we have + * had time to register the window in our lookup table, or + * when the window is being destroyed and we already have + * removed it. Repost the same message to our queue so that + * we will get it later when we are prepared. + */ + PostMessage (xevent->hwnd, xevent->message, + xevent->wParam, xevent->lParam); + } + return FALSE; + } + + if (!GDK_DRAWABLE_DESTROYED (window)) + { + /* Check for filters for this window */ + GdkFilterReturn result; + result = gdk_event_apply_filters + (xevent, event, WINDOW_PRIVATE(window)->filters); + + if (result != GDK_FILTER_CONTINUE) + { + return (result == GDK_FILTER_TRANSLATE) ? TRUE : FALSE; + } + } + + if (xevent->message == gdk_selection_notify_msg) + { + GDK_NOTE (SELECTION, g_print ("gdk_selection_notify_msg: %#x\n", + xevent->hwnd)); + + event->selection.type = GDK_SELECTION_NOTIFY; + event->selection.window = window; + event->selection.selection = xevent->wParam; + event->selection.target = xevent->lParam; + event->selection.property = gdk_selection_property; + event->selection.time = xevent->time; + + return_val = !GDK_DRAWABLE_DESTROYED (window); + + /* Will pass through switch below without match */ + } + else if (xevent->message == gdk_selection_request_msg) + { + GDK_NOTE (SELECTION, g_print ("gdk_selection_request_msg: %#x\n", + xevent->hwnd)); + + event->selection.type = GDK_SELECTION_REQUEST; + event->selection.window = window; + event->selection.selection = gdk_clipboard_atom; + event->selection.target = GDK_TARGET_STRING; + event->selection.property = gdk_selection_property; + event->selection.requestor = (guint32) xevent->hwnd; + event->selection.time = xevent->time; + + return_val = !GDK_DRAWABLE_DESTROYED (window); + + /* Again, will pass through switch below without match */ + } + else if (xevent->message == gdk_selection_clear_msg) + { + GDK_NOTE (SELECTION, g_print ("gdk_selection_clear_msg: %#x\n", + xevent->hwnd)); + + event->selection.type = GDK_SELECTION_CLEAR; + event->selection.window = window; + event->selection.selection = xevent->wParam; + event->selection.time = xevent->time; + + return_val = GDK_DRAWABLE_DESTROYED (window); + + /* Once again, we will pass through switch below without match */ + } + else + { + GList *tmp_list; + GdkFilterReturn result = GDK_FILTER_CONTINUE; + + tmp_list = client_filters; + while (tmp_list) + { + GdkClientFilter *filter = tmp_list->data; + if (filter->type == xevent->message) + { + GDK_NOTE (EVENTS, g_print ("client filter matched\n")); + result = (*filter->function) (xevent, event, filter->data); + switch (result) + { + case GDK_FILTER_REMOVE: + return_val = FALSE; + break; + + case GDK_FILTER_TRANSLATE: + return_val = TRUE; + break; + + case GDK_FILTER_CONTINUE: + return_val = TRUE; + event->client.type = GDK_CLIENT_EVENT; + event->client.window = window; + event->client.message_type = xevent->message; + event->client.data_format = 0; + event->client.data.l[0] = xevent->wParam; + event->client.data.l[1] = xevent->lParam; + break; + } + goto bypass_switch; /* Ouch */ + } + tmp_list = tmp_list->next; + } + } + + switch (xevent->message) + { + case WM_INPUTLANGCHANGE: + GDK_NOTE (EVENTS, + g_print ("WM_INPUTLANGCHANGE: %#x charset %d locale %x\n", + xevent->hwnd, xevent->wParam, xevent->lParam)); + WINDOW_PRIVATE(window)->input_locale = (HKL) xevent->lParam; + TranslateCharsetInfo ((DWORD FAR *) xevent->wParam, + &WINDOW_PRIVATE(window)->charset_info, + TCI_SRCCHARSET); + break; + + case WM_SYSKEYUP: + case WM_SYSKEYDOWN: + GDK_NOTE (EVENTS, + g_print ("WM_SYSKEY%s: %#x key: %s %#x %#.08x\n", + (xevent->message == WM_SYSKEYUP ? "UP" : "DOWN"), + xevent->hwnd, + (GetKeyNameText (xevent->lParam, buf, + sizeof (buf)) > 0 ? + buf : ""), + xevent->wParam, + xevent->lParam)); + + /* Let the system handle Alt-Tab and Alt-Enter */ + if (xevent->wParam == VK_TAB + || xevent->wParam == VK_RETURN + || xevent->wParam == VK_F4) + break; + /* If posted without us having keyboard focus, ignore */ + if (!(xevent->lParam & 0x20000000)) + break; +#if 0 + /* don't generate events for just the Alt key */ + if (xevent->wParam == VK_MENU) + break; +#endif + /* Jump to code in common with WM_KEYUP and WM_KEYDOWN */ + goto keyup_or_down; + + case WM_KEYUP: + case WM_KEYDOWN: + GDK_NOTE (EVENTS, + g_print ("WM_KEY%s: %#x key: %s %#x %#.08x\n", + (xevent->message == WM_KEYUP ? "UP" : "DOWN"), + xevent->hwnd, + (GetKeyNameText (xevent->lParam, buf, + sizeof (buf)) > 0 ? + buf : ""), + xevent->wParam, + xevent->lParam)); + + ignore_WM_CHAR = TRUE; + keyup_or_down: + +#ifdef NEW_PROPAGATION_CODE + if (!propagate (&window, xevent, + k_grab_window, k_grab_owner_events, GDK_ALL_EVENTS_MASK, + doesnt_want_key)) + break; + event->key.window = window; +#else + if (k_grab_window != NULL && !k_grab_owner_events) + { + /* Keyboard is grabbed with owner_events FALSE */ + GDK_NOTE (EVENTS, g_print ("...grabbed, owner_events FALSE, " + "sending to %#x\n", + GDK_DRAWABLE_XID (k_grab_window))); + event->key.window = k_grab_window; + /* Continue with switch statement below */ + } + else if (((xevent->message == WM_KEYUP + || xevent->message == WM_SYSKEYUP) + && !(WINDOW_PRIVATE(window)->event_mask & GDK_KEY_RELEASE_MASK)) + || ((xevent->message == WM_KEYDOWN + || xevent->message == WM_SYSKEYDOWN) + && !(WINDOW_PRIVATE(window)->event_mask & GDK_KEY_PRESS_MASK))) + { + /* Owner doesn't want it, propagate to parent. */ + if (WINDOW_PRIVATE(window)->parent == (GdkWindow *) gdk_root_parent) + { + /* No parent; check if grabbed */ + if (k_grab_window != NULL) + { + /* Keyboard is grabbed with owner_events TRUE */ + GDK_NOTE (EVENTS, g_print ("...undelivered, but grabbed\n")); + event->key.window = k_grab_window; + /* Continue with switch statement below */ + } + else + break; + } + else + { + window = key_propagate (window, xevent); + /* Jump back up */ + goto keyup_or_down; + } + } + else + event->key.window = window; + + g_assert (event->key.window == window); +#endif + switch (xevent->wParam) + { + case VK_LBUTTON: + event->key.keyval = GDK_Pointer_Button1; break; + case VK_RBUTTON: + event->key.keyval = GDK_Pointer_Button3; break; + case VK_MBUTTON: + event->key.keyval = GDK_Pointer_Button2; break; + case VK_CANCEL: + event->key.keyval = GDK_Cancel; break; + case VK_BACK: + event->key.keyval = GDK_BackSpace; break; + case VK_TAB: + event->key.keyval = (GetKeyState(VK_SHIFT) < 0 ? + GDK_ISO_Left_Tab : GDK_Tab); + break; + case VK_CLEAR: + event->key.keyval = GDK_Clear; break; + case VK_RETURN: + event->key.keyval = GDK_Return; break; + case VK_SHIFT: + event->key.keyval = GDK_Shift_L; break; + case VK_CONTROL: + if (xevent->lParam & 0x01000000) + event->key.keyval = GDK_Control_R; + else + event->key.keyval = GDK_Control_L; + break; + case VK_MENU: + if (xevent->lParam & 0x01000000) + { + /* AltGr key comes in as Control+Right Alt */ + if (GetKeyState (VK_CONTROL) < 0) + { + ignore_WM_CHAR = FALSE; + is_AltGr_key = TRUE; + } + event->key.keyval = GDK_Alt_R; + } + else + event->key.keyval = GDK_Alt_L; + break; + case VK_PAUSE: + event->key.keyval = GDK_Pause; break; + case VK_CAPITAL: + event->key.keyval = GDK_Caps_Lock; break; + case VK_ESCAPE: + event->key.keyval = GDK_Escape; break; + case VK_PRIOR: + event->key.keyval = GDK_Prior; break; + case VK_NEXT: + event->key.keyval = GDK_Next; break; + case VK_END: + event->key.keyval = GDK_End; break; + case VK_HOME: + event->key.keyval = GDK_Home; break; + case VK_LEFT: + event->key.keyval = GDK_Left; break; + case VK_UP: + event->key.keyval = GDK_Up; break; + case VK_RIGHT: + event->key.keyval = GDK_Right; break; + case VK_DOWN: + event->key.keyval = GDK_Down; break; + case VK_SELECT: + event->key.keyval = GDK_Select; break; + case VK_PRINT: + event->key.keyval = GDK_Print; break; + case VK_EXECUTE: + event->key.keyval = GDK_Execute; break; + case VK_INSERT: + event->key.keyval = GDK_Insert; break; + case VK_DELETE: + event->key.keyval = GDK_Delete; break; + case VK_HELP: + event->key.keyval = GDK_Help; break; + case VK_NUMPAD0: + case VK_NUMPAD1: + case VK_NUMPAD2: + case VK_NUMPAD3: + case VK_NUMPAD4: + case VK_NUMPAD5: + case VK_NUMPAD6: + case VK_NUMPAD7: + case VK_NUMPAD8: + case VK_NUMPAD9: + /* Apparently applications work better if we just pass numpad digits + * on as real digits? So wait for the WM_CHAR instead. + */ + ignore_WM_CHAR = FALSE; + break; + case VK_MULTIPLY: + event->key.keyval = GDK_KP_Multiply; break; + case VK_ADD: + /* Pass it on as an ASCII plus in WM_CHAR. */ + ignore_WM_CHAR = FALSE; + break; + case VK_SEPARATOR: + event->key.keyval = GDK_KP_Separator; break; + case VK_SUBTRACT: + /* Pass it on as an ASCII minus in WM_CHAR. */ + ignore_WM_CHAR = FALSE; + break; + case VK_DECIMAL: + /* The keypad decimal key should also be passed on as the decimal + * sign ('.' or ',' depending on the Windows locale settings, + * apparently). So wait for the WM_CHAR here, also. + */ + ignore_WM_CHAR = FALSE; + break; + case VK_DIVIDE: + event->key.keyval = GDK_KP_Divide; break; + case VK_F1: + event->key.keyval = GDK_F1; break; + case VK_F2: + event->key.keyval = GDK_F2; break; + case VK_F3: + event->key.keyval = GDK_F3; break; + case VK_F4: + event->key.keyval = GDK_F4; break; + case VK_F5: + event->key.keyval = GDK_F5; break; + case VK_F6: + event->key.keyval = GDK_F6; break; + case VK_F7: + event->key.keyval = GDK_F7; break; + case VK_F8: + event->key.keyval = GDK_F8; break; + case VK_F9: + event->key.keyval = GDK_F9; break; + case VK_F10: + event->key.keyval = GDK_F10; break; + case VK_F11: + event->key.keyval = GDK_F11; break; + case VK_F12: + event->key.keyval = GDK_F12; break; + case VK_F13: + event->key.keyval = GDK_F13; break; + case VK_F14: + event->key.keyval = GDK_F14; break; + case VK_F15: + event->key.keyval = GDK_F15; break; + case VK_F16: + event->key.keyval = GDK_F16; break; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + if (!is_AltGr_key && (GetKeyState (VK_CONTROL) < 0 + || GetKeyState (VK_MENU) < 0)) + /* Control- or Alt-digits won't come in as a WM_CHAR, + * but beware of AltGr-digits, which are used for instance + * on Finnish keyboards. + */ + event->key.keyval = GDK_0 + (xevent->wParam - '0'); + else + ignore_WM_CHAR = FALSE; + break; + case VK_OEM_PLUS: /* On my Win98, the '+' key comes in + * as VK_OEM_PLUS + */ + if (!is_AltGr_key && (GetKeyState (VK_CONTROL) < 0 + || GetKeyState (VK_MENU) < 0)) + /* Control- or Alt-plus won't come in as WM_CHAR, + * but beware of AltGr-plus which is backslash on + * Finnish keyboards + */ + event->key.keyval = '+'; + else + ignore_WM_CHAR = FALSE; + break; + default: + if (xevent->message == WM_SYSKEYDOWN || xevent->message == WM_SYSKEYUP) + event->key.keyval = xevent->wParam; + else + ignore_WM_CHAR = FALSE; + break; + } + + if (!ignore_WM_CHAR) + break; + + is_AltGr_key = FALSE; + event->key.type = ((xevent->message == WM_KEYDOWN + || xevent->message == WM_SYSKEYDOWN) ? + GDK_KEY_PRESS : GDK_KEY_RELEASE); + event->key.time = xevent->time; + event->key.state = 0; + if (GetKeyState (VK_SHIFT) < 0) + event->key.state |= GDK_SHIFT_MASK; + if (GetKeyState (VK_CAPITAL) & 0x1) + event->key.state |= GDK_LOCK_MASK; + if (GetKeyState (VK_CONTROL) < 0) + event->key.state |= GDK_CONTROL_MASK; + if (xevent->wParam != VK_MENU && GetKeyState (VK_MENU) < 0) + event->key.state |= GDK_MOD1_MASK; + event->key.string = NULL; + event->key.length = 0; + return_val = !GDK_DRAWABLE_DESTROYED (window); + break; + + case WM_IME_COMPOSITION: + if (!use_IME_COMPOSITION) + break; + GDK_NOTE (EVENTS, g_print ("WM_IME_COMPOSITION: %#x %#x\n", + xevent->hwnd, xevent->lParam)); + if (xevent->lParam & GCS_RESULTSTR) + goto wm_char; + break; + + case WM_IME_CHAR: + GDK_NOTE (EVENTS, + g_print ("WM_IME_CHAR: %#x bytes: %#.04x\n", + xevent->hwnd, xevent->wParam)); + goto wm_char; + + case WM_CHAR: + GDK_NOTE (EVENTS, + g_print ("WM_CHAR: %#x char: %#x %#.08x %s\n", + xevent->hwnd, xevent->wParam, xevent->lParam, + (ignore_WM_CHAR ? "ignored" : ""))); + + if (ignore_WM_CHAR) + { + ignore_WM_CHAR = FALSE; + break; + } + + wm_char: +#ifdef NEW_PROPAGATION_CODE + if (!propagate (&window, xevent, + k_grab_window, k_grab_owner_events, GDK_ALL_EVENTS_MASK, + doesnt_want_char)) + break; + event->key.window = window; +#else + /* This doesn't handle the rather theorethical case that a window + * wants key presses but still wants releases to be propagated, + * for instance. Or is that so theorethical? + */ + if (k_grab_window != NULL && !k_grab_owner_events) + { + /* Keyboard is grabbed with owner_events FALSE */ + GDK_NOTE (EVENTS, + g_print ("...grabbed, owner_events FALSE, " + "sending to %#x\n", + GDK_DRAWABLE_XID (k_grab_window))); + event->key.window = k_grab_window; + } + else if (!(WINDOW_PRIVATE(window)->event_mask & (GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK))) + { + /* Owner doesn't want it, propagate to parent. */ + if (WINDOW_PRIVATE(window)->parent == (GdkWindow *) gdk_root_parent) + { + /* No parent; check if grabbed */ + if (k_grab_window != NULL) + { + GDK_NOTE (EVENTS, g_print ("...undelivered, but grabbed\n")); + event->key.window = k_grab_window; + } + else + break; + } + else + { + window = key_propagate (window, xevent); + /* Jump back up */ + goto wm_char; + } + } + else + event->key.window = window; + + g_assert (event->key.window == window); +#endif + return_val = !GDK_DRAWABLE_DESTROYED (window); + if (return_val && (event->key.window == k_grab_window + || (WINDOW_PRIVATE(window)->event_mask & GDK_KEY_RELEASE_MASK))) + { + if (window == k_grab_window + || (WINDOW_PRIVATE(window)->event_mask & GDK_KEY_PRESS_MASK)) + { + /* Append a GDK_KEY_PRESS event to the pushback list + * (from which it will be fetched before the release + * event). + */ + GdkEvent *event2 = gdk_event_new (); + build_keypress_event (WINDOW_PRIVATE(window), event2, xevent); + event2->key.window = window; + gdk_window_ref (window); + gdk_event_queue_append (event2); + GDK_NOTE (EVENTS, print_event (event2)); + } + /* Return the key release event. */ + build_keyrelease_event (WINDOW_PRIVATE(window), event, xevent); + } + else if (return_val + && (WINDOW_PRIVATE(window)->event_mask & GDK_KEY_PRESS_MASK)) + { + /* Return just the key press event. */ + build_keypress_event (WINDOW_PRIVATE(window), event, xevent); + } + else + return_val = FALSE; + +#if 0 /* Don't reset is_AltGr_key here. Othewise we can't type several + * AltGr-accessed chars while keeping the AltGr pressed down + * all the time. + */ + is_AltGr_key = FALSE; +#endif + break; + + case WM_LBUTTONDOWN: + button = 1; + goto buttondown0; + case WM_MBUTTONDOWN: + button = 2; + goto buttondown0; + case WM_RBUTTONDOWN: + button = 3; + + buttondown0: + GDK_NOTE (EVENTS, + g_print ("WM_%cBUTTONDOWN: %#x (%d,%d)\n", + " LMR"[button], + xevent->hwnd, + LOWORD (xevent->lParam), HIWORD (xevent->lParam))); + + if (WINDOW_PRIVATE(window)->extension_events != 0 + && gdk_input_ignore_core) + { + GDK_NOTE (EVENTS, g_print ("...ignored\n")); + break; + } + + if (window != curWnd) + synthesize_crossing_events (window, xevent); + + event->button.type = GDK_BUTTON_PRESS; +#ifdef NEW_PROPAGATION_CODE + if (!propagate (&window, xevent, + p_grab_window, p_grab_owner_events, p_grab_mask, + doesnt_want_button_press)) + break; + event->button.window = window; +#else + buttondown: + mask = WINDOW_PRIVATE(window)->event_mask; + + if (p_grab_window != NULL && !p_grab_owner_events) + { + /* Pointer is grabbed with owner_events FALSE */ + GDK_NOTE (EVENTS, g_print ("...grabbed, owner_events FALSE\n")); + + mask = p_grab_mask; + if (!(mask & GDK_BUTTON_PRESS_MASK)) + /* Grabber doesn't want it */ + break; + else + event->button.window = p_grab_window; + GDK_NOTE (EVENTS, g_print ("...sending to %#x\n", + GDK_DRAWABLE_XID (p_grab_window))); + } + else if (!(mask & GDK_BUTTON_PRESS_MASK)) + { + /* Owner doesn't want it, propagate to parent. */ + if (WINDOW_PRIVATE(window)->parent == (GdkWindow *) gdk_root_parent) + { + /* No parent; check if grabbed */ + if (p_grab_window != NULL) + { + /* Pointer is grabbed wíth owner_events TRUE */ + GDK_NOTE (EVENTS, g_print ("...undelivered, but grabbed\n")); + mask = p_grab_mask; + if (!(mask & GDK_BUTTON_PRESS_MASK)) + { + /* Grabber doesn't want it either */ + GDK_NOTE (EVENTS, g_print ("...grabber uninterested\n")); + break; + } + else + event->button.window = p_grab_window; + GDK_NOTE (EVENTS, g_print ("...sending to %#x\n", + GDK_DRAWABLE_XID (p_grab_window))); + } + else + break; + } + else + { + window = pointer_propagate (window, xevent); + /* Jump back up */ + goto buttondown; /* What did Dijkstra say? */ + } + } + else + event->button.window = window; + + g_assert (event->button.window == window); +#endif + /* Emulate X11's automatic active grab */ + if (!p_grab_window) + { + /* No explicit active grab, let's start one automatically */ + gint owner_events = + WINDOW_PRIVATE(window)->event_mask + & (GDK_BUTTON_PRESS_MASK|GDK_BUTTON_RELEASE_MASK); + + GDK_NOTE (EVENTS, g_print ("...automatic grab started\n")); + gdk_pointer_grab (window, + owner_events, + WINDOW_PRIVATE(window)->event_mask, + NULL, NULL, 0); + p_grab_automatic = TRUE; + } + + event->button.time = xevent->time; + if (window != orig_window) + translate_mouse_coords (orig_window, window, xevent); + event->button.x = curX = LOWORD (xevent->lParam); + event->button.y = curY = HIWORD (xevent->lParam); + event->button.x_root = xevent->pt.x; + event->button.y_root = xevent->pt.y; + event->button.pressure = 0.5; + event->button.xtilt = 0; + event->button.ytilt = 0; + event->button.state = build_pointer_event_state (xevent); + event->button.button = button; + event->button.source = GDK_SOURCE_MOUSE; + event->button.deviceid = GDK_CORE_POINTER; + + if ((event->button.time < (button_click_time[1] + TRIPLE_CLICK_TIME)) && + (event->button.window == button_window[1]) && + (event->button.button == button_number[1])) + { + gdk_synthesize_click (event, 3); + + button_click_time[1] = 0; + button_click_time[0] = 0; + button_window[1] = NULL; + button_window[0] = 0; + button_number[1] = -1; + button_number[0] = -1; + } + else if ((event->button.time < (button_click_time[0] + DOUBLE_CLICK_TIME)) && + (event->button.window == button_window[0]) && + (event->button.button == button_number[0])) + { + gdk_synthesize_click (event, 2); + + button_click_time[1] = button_click_time[0]; + button_click_time[0] = event->button.time; + button_window[1] = button_window[0]; + button_window[0] = event->button.window; + button_number[1] = button_number[0]; + button_number[0] = event->button.button; + } + else + { + button_click_time[1] = 0; + button_click_time[0] = event->button.time; + button_window[1] = NULL; + button_window[0] = event->button.window; + button_number[1] = -1; + button_number[0] = event->button.button; + } + return_val = !GDK_DRAWABLE_DESTROYED (window); + break; + + case WM_LBUTTONUP: + button = 1; + goto buttonup0; + case WM_MBUTTONUP: + button = 2; + goto buttonup0; + case WM_RBUTTONUP: + button = 3; + + buttonup0: + GDK_NOTE (EVENTS, + g_print ("WM_%cBUTTONUP: %#x (%d,%d)\n", + " LMR"[button], + xevent->hwnd, + LOWORD (xevent->lParam), HIWORD (xevent->lParam))); + + if (WINDOW_PRIVATE(window)->extension_events != 0 + && gdk_input_ignore_core) + { + GDK_NOTE (EVENTS, g_print ("...ignored\n")); + break; + } + + if (window != curWnd) + synthesize_crossing_events (window, xevent); + + event->button.type = GDK_BUTTON_RELEASE; +#ifdef NEW_PROPAGATION_CODE + if (!propagate (&window, xevent, + p_grab_window, p_grab_owner_events, p_grab_mask, + doesnt_want_button_release)) + goto maybe_ungrab; + event->button.window = window; +#else + buttonup: + mask = WINDOW_PRIVATE(window)->event_mask; + + if (p_grab_window != NULL && !p_grab_owner_events) + { + /* Pointer is grabbed with owner_events FALSE */ + GDK_NOTE (EVENTS, g_print ("...grabbed, owner_events FALSE\n")); + + mask = p_grab_mask; + if (!(mask & GDK_BUTTON_RELEASE_MASK)) + /* Grabber doesn't want it */ + goto maybe_ungrab; + else + event->button.window = p_grab_window; + GDK_NOTE (EVENTS, g_print ("...sending to %#x\n", + GDK_DRAWABLE_XID (p_grab_window))); + } + else if (!(mask & GDK_BUTTON_RELEASE_MASK)) + { + /* Owner doesn't want it, propagate to parent. */ + if (WINDOW_PRIVATE(window)->parent == (GdkWindow *) gdk_root_parent) + { + /* No parent; check if grabbed */ + if (p_grab_window != NULL) + { + /* Pointer is grabbed wíth owner_events TRUE */ + GDK_NOTE (EVENTS, g_print ("...undelivered, but grabbed\n")); + mask = p_grab_mask; + if (!(mask & GDK_BUTTON_RELEASE_MASK)) + { + /* Grabber doesn't want it either */ + GDK_NOTE (EVENTS, g_print ("...grabber uninterested\n")); + goto maybe_ungrab; + } + else + event->button.window = p_grab_window; + GDK_NOTE (EVENTS, + g_print ("...sending to %#x\n", + GDK_DRAWABLE_XID (p_grab_window))); + } + else + break; + } + else + { + window = pointer_propagate (window, xevent); + /* Jump back up */ + goto buttonup; + } + } + else + event->button.window = window; + + g_assert (event->button.window == window); +#endif + event->button.time = xevent->time; + if (window != orig_window) + translate_mouse_coords (orig_window, window, xevent); + event->button.x = LOWORD (xevent->lParam); + event->button.y = HIWORD (xevent->lParam); + event->button.x_root = xevent->pt.x; + event->button.y_root = xevent->pt.y; + event->button.pressure = 0.5; + event->button.xtilt = 0; + event->button.ytilt = 0; + event->button.state = build_pointer_event_state (xevent); + event->button.button = button; + event->button.source = GDK_SOURCE_MOUSE; + event->button.deviceid = GDK_CORE_POINTER; + + return_val = !GDK_DRAWABLE_DESTROYED (window); + + maybe_ungrab: + if (p_grab_window != NULL + && p_grab_automatic + && (event->button.state & (GDK_BUTTON1_MASK | GDK_BUTTON2_MASK | GDK_BUTTON3_MASK)) == 0) + gdk_pointer_ungrab (0); + break; + + case WM_MOUSEMOVE: + GDK_NOTE (EVENTS, + g_print ("WM_MOUSEMOVE: %#x %#x (%d,%d)\n", + xevent->hwnd, xevent->wParam, + LOWORD (xevent->lParam), HIWORD (xevent->lParam))); + + /* If we haven't moved, don't create any event. + * Windows sends WM_MOUSEMOVE messages after button presses + * even if the mouse doesn't move. This disturbs gtk. + */ + if (window == curWnd + && LOWORD (xevent->lParam) == curX + && HIWORD (xevent->lParam) == curY) + break; + + /* HB: only process mouse move messages if we own the active window. */ + GetWindowThreadProcessId(GetActiveWindow(), &pidActWin); + GetWindowThreadProcessId(xevent->hwnd, &pidThis); + if (pidActWin != pidThis) + break; + + if (window != curWnd) + synthesize_crossing_events (window, xevent); + + if (WINDOW_PRIVATE(window)->extension_events != 0 + && gdk_input_ignore_core) + { + GDK_NOTE (EVENTS, g_print ("...ignored\n")); + break; + } + + event->motion.type = GDK_MOTION_NOTIFY; +#ifdef NEW_PROPAGATION_CODE + if (!propagate (&window, xevent, + p_grab_window, p_grab_owner_events, p_grab_mask, + doesnt_want_button_motion)) + break; + event->motion.window = window; +#else + mousemotion: + mask = WINDOW_PRIVATE(window)->event_mask; + + if (p_grab_window != NULL && !p_grab_owner_events) + { + /* Pointer is grabbed with owner_events FALSE */ + GDK_NOTE (EVENTS, g_print ("...grabbed, owner_events FALSE\n")); + + mask = p_grab_mask; + if (!((mask & GDK_POINTER_MOTION_MASK) + || ((xevent->wParam & (MK_LBUTTON|MK_MBUTTON|MK_RBUTTON)) + && (mask & GDK_BUTTON_MOTION_MASK)) + || ((xevent->wParam & MK_LBUTTON) + && (mask & GDK_BUTTON1_MOTION_MASK)) + || ((xevent->wParam & MK_MBUTTON) + && (mask & GDK_BUTTON2_MOTION_MASK)) + || ((xevent->wParam & MK_RBUTTON) + && (mask & GDK_BUTTON3_MOTION_MASK)))) + /* Grabber doesn't want it */ + break; + else + event->motion.window = p_grab_window; + GDK_NOTE (EVENTS, g_print ("...sending to %#x\n", + GDK_DRAWABLE_XID (p_grab_window))); + } + else if (!((mask & GDK_POINTER_MOTION_MASK) + || ((xevent->wParam & (MK_LBUTTON|MK_MBUTTON|MK_RBUTTON)) + && (mask & GDK_BUTTON_MOTION_MASK)) + || ((xevent->wParam & MK_LBUTTON) + && (mask & GDK_BUTTON1_MOTION_MASK)) + || ((xevent->wParam & MK_MBUTTON) + && (mask & GDK_BUTTON2_MOTION_MASK)) + || ((xevent->wParam & MK_RBUTTON) + && (mask & GDK_BUTTON3_MOTION_MASK)))) + { + /* Owner doesn't want it, propagate to parent. */ + if (WINDOW_PRIVATE(window)->parent == (GdkWindow *) gdk_root_parent) + { + /* No parent; check if grabbed */ + if (p_grab_window != NULL) + { + /* Pointer is grabbed wíth owner_events TRUE */ + GDK_NOTE (EVENTS, g_print ("...undelivered, but grabbed\n")); + mask = p_grab_mask; + if (!((p_grab_mask & GDK_POINTER_MOTION_MASK) + || ((xevent->wParam & (MK_LBUTTON|MK_MBUTTON|MK_RBUTTON)) + && (mask & GDK_BUTTON_MOTION_MASK)) + || ((xevent->wParam & MK_LBUTTON) + && (mask & GDK_BUTTON1_MOTION_MASK)) + || ((xevent->wParam & MK_MBUTTON) + && (mask & GDK_BUTTON2_MOTION_MASK)) + || ((xevent->wParam & MK_RBUTTON) + && (mask & GDK_BUTTON3_MOTION_MASK)))) + { + /* Grabber doesn't want it either */ + GDK_NOTE (EVENTS, g_print ("...grabber uninterested\n")); + break; + } + else + event->motion.window = p_grab_window; + GDK_NOTE (EVENTS, + g_print ("...sending to %#x\n", + GDK_DRAWABLE_XID (p_grab_window))); + } + else + break; + } + else + { + window = pointer_propagate (window, xevent); + /* Jump back up */ + goto mousemotion; + } + } + else + event->motion.window = window; +#endif + event->motion.time = xevent->time; + if (window != orig_window) + translate_mouse_coords (orig_window, window, xevent); + event->motion.x = curX = LOWORD (xevent->lParam); + event->motion.y = curY = HIWORD (xevent->lParam); + event->motion.x_root = xevent->pt.x; + event->motion.y_root = xevent->pt.y; + curXroot = event->motion.x_root; + curYroot = event->motion.y_root; + event->motion.pressure = 0.5; + event->motion.xtilt = 0; + event->motion.ytilt = 0; + event->motion.state = build_pointer_event_state (xevent); + event->motion.is_hint = FALSE; + event->motion.source = GDK_SOURCE_MOUSE; + event->motion.deviceid = GDK_CORE_POINTER; + + return_val = !GDK_DRAWABLE_DESTROYED (window); + break; + + case WM_NCMOUSEMOVE: + GDK_NOTE (EVENTS, + g_print ("WM_NCMOUSEMOVE: %#x x,y: %d %d\n", + xevent->hwnd, + LOWORD (xevent->lParam), HIWORD (xevent->lParam))); + if (p_TrackMouseEvent == NULL + && curWnd != NULL + && (WINDOW_PRIVATE(curWnd)->event_mask & GDK_LEAVE_NOTIFY_MASK)) + { + GDK_NOTE (EVENTS, g_print ("...synthesizing LEAVE_NOTIFY event\n")); + + event->crossing.type = GDK_LEAVE_NOTIFY; + event->crossing.window = curWnd; + event->crossing.subwindow = NULL; + event->crossing.time = xevent->time; + event->crossing.x = curX; + event->crossing.y = curY; + event->crossing.x_root = curXroot; + event->crossing.y_root = curYroot; + event->crossing.mode = GDK_CROSSING_NORMAL; + event->crossing.detail = GDK_NOTIFY_NONLINEAR; + + event->crossing.focus = TRUE; /* ??? */ + event->crossing.state = 0; /* ??? */ + return_val = TRUE; + } + + if (curWnd) + { + gdk_window_unref (curWnd); + curWnd = NULL; + } + + break; + +#ifdef USE_TRACKMOUSEEVENT + case WM_MOUSELEAVE: + GDK_NOTE (EVENTS, g_print ("WM_MOUSELEAVE: %#x\n", xevent->hwnd)); + + if (!(WINDOW_PRIVATE(window)->event_mask & GDK_LEAVE_NOTIFY_MASK)) + break; + + event->crossing.type = GDK_LEAVE_NOTIFY; + event->crossing.window = window; + event->crossing.subwindow = NULL; + event->crossing.time = xevent->time; + event->crossing.x = curX; + event->crossing.y = curY; + event->crossing.x_root = curXroot; + event->crossing.y_root = curYroot; + event->crossing.mode = GDK_CROSSING_NORMAL; + if (curWnd + && IsChild (GDK_DRAWABLE_XID (curWnd), GDK_DRAWABLE_XID (window))) + event->crossing.detail = GDK_NOTIFY_INFERIOR; + else if (curWnd + && IsChild (GDK_DRAWABLE_XID (window), GDK_DRAWABLE_XID (curWnd))) + event->crossing.detail = GDK_NOTIFY_ANCESTOR; + else + event->crossing.detail = GDK_NOTIFY_NONLINEAR; + + event->crossing.focus = TRUE; /* ??? */ + event->crossing.state = 0; /* ??? */ + + if (curWnd) + { + gdk_window_unref (curWnd); + curWnd = NULL; + } + + return_val = !GDK_DRAWABLE_DESTROYED (window); + break; +#endif + + case WM_SETFOCUS: + case WM_KILLFOCUS: + GDK_NOTE (EVENTS, g_print ("WM_%sFOCUS: %#x\n", + (xevent->message == WM_SETFOCUS ? + "SET" : "KILL"), + xevent->hwnd)); + + if (!(WINDOW_PRIVATE(window)->event_mask & GDK_FOCUS_CHANGE_MASK)) + break; + + event->focus_change.type = GDK_FOCUS_CHANGE; + event->focus_change.window = window; + event->focus_change.in = (xevent->message == WM_SETFOCUS); + return_val = !GDK_DRAWABLE_DESTROYED (window); + break; + + case WM_ERASEBKGND: + GDK_NOTE (EVENTS, g_print ("WM_ERASEBKGND: %#x dc %#x\n", + xevent->hwnd, xevent->wParam)); + + if (GDK_DRAWABLE_DESTROYED (window)) + break; + + colormap_private = (GdkColormapPrivate *) WINDOW_PRIVATE(window)->drawable.colormap; + hdc = (HDC) xevent->wParam; + if (colormap_private + && colormap_private->xcolormap->rc_palette) + { + int k; + + if (SelectPalette (hdc, colormap_private->xcolormap->palette, + FALSE) == NULL) + g_warning ("WM_ERASEBKGND: SelectPalette failed"); + if ((k = RealizePalette (hdc)) == GDI_ERROR) + g_warning ("WM_ERASEBKGND: RealizePalette failed"); +#if 0 + g_print ("WM_ERASEBKGND: selected %#x, realized %d colors\n", + colormap_private->xcolormap->palette, k); +#endif + } + *ret_val_flagp = TRUE; + *ret_valp = 1; + + if (WINDOW_PRIVATE(window)->bg_type == GDK_WIN32_BG_TRANSPARENT) + break; + + if (WINDOW_PRIVATE(window)->bg_type == GDK_WIN32_BG_PARENT_RELATIVE) + { + /* If this window should have the same background as the + * parent, fetch the parent. (And if the same goes for + * the parent, fetch the grandparent, etc.) + */ + while (window + && WINDOW_PRIVATE(window)->bg_type == GDK_WIN32_BG_PARENT_RELATIVE) + { + gdk_window_unref (window); + window = WINDOW_PRIVATE(window)->parent; + gdk_window_ref (window); + } + } + + if (WINDOW_PRIVATE(window)->bg_type == GDK_WIN32_BG_PIXEL) + { + COLORREF bg; + GetClipBox (hdc, &rect); + GDK_NOTE (EVENTS, + g_print ("...%dx%d@+%d+%d BG_PIXEL %s\n", + rect.right - rect.left, + rect.bottom - rect.top, + rect.left, rect.top, + gdk_color_to_string (&WINDOW_PRIVATE(window)->bg_pixel))); + bg = GetNearestColor + (hdc, RGB (WINDOW_PRIVATE(window)->bg_pixel.red >> 8, + WINDOW_PRIVATE(window)->bg_pixel.green >> 8, + WINDOW_PRIVATE(window)->bg_pixel.blue >> 8)); + hbr = CreateSolidBrush (bg); +#if 0 + g_print ("...CreateSolidBrush (%.08x) = %.08x\n", bg, hbr); +#endif + if (!FillRect (hdc, &rect, hbr)) + g_warning ("WM_ERASEBKGND: FillRect failed"); + DeleteObject (hbr); + } + else if (WINDOW_PRIVATE(window)->bg_type == GDK_WIN32_BG_PIXMAP) + { + pixmap_private = + (GdkDrawablePrivate*) WINDOW_PRIVATE(window)->bg_pixmap; + GetClipBox (hdc, &rect); + + if (pixmap_private->width <= 8 + && pixmap_private->height <= 8) + { + GDK_NOTE (EVENTS, g_print ("...small pixmap, using brush\n")); + hbr = CreatePatternBrush (pixmap_private->xwindow); + if (!FillRect (hdc, &rect, hbr)) + g_warning ("WM_ERASEBKGND: FillRect failed"); + DeleteObject (hbr); + } + else + { + GDK_NOTE (EVENTS, + g_print ("...blitting pixmap %#x (%dx%d) " + "all over the place,\n" + "...clip box = %dx%d@+%d+%d\n", + pixmap_private->xwindow, + pixmap_private->width, pixmap_private->height, + rect.right - rect.left, rect.bottom - rect.top, + rect.left, rect.top)); + + if (!(bgdc = CreateCompatibleDC (hdc))) + { + g_warning ("WM_ERASEBKGND: CreateCompatibleDC failed"); + break; + } + if (!(oldbitmap = SelectObject (bgdc, pixmap_private->xwindow))) + { + g_warning ("WM_ERASEBKGND: SelectObject failed"); + DeleteDC (bgdc); + break; + } + i = 0; + while (i < rect.right) + { + j = 0; + while (j < rect.bottom) + { + if (i + pixmap_private->width >= rect.left + && j + pixmap_private->height >= rect.top) + { + if (!BitBlt (hdc, i, j, + pixmap_private->width, pixmap_private->height, + bgdc, 0, 0, SRCCOPY)) + { + g_warning ("WM_ERASEBKGND: BitBlt failed"); + goto loopexit; + } + } + j += pixmap_private->height; + } + i += pixmap_private->width; + } + loopexit: + SelectObject (bgdc, oldbitmap); + DeleteDC (bgdc); + } + } + else + { + GDK_NOTE (EVENTS, g_print ("...BLACK_BRUSH (?)\n")); + hbr = GetStockObject (BLACK_BRUSH); + GetClipBox (hdc, &rect); + if (!FillRect (hdc, &rect, hbr)) + g_warning ("WM_ERASEBKGND: FillRect failed"); + } + break; + + case WM_PAINT: + hdc = BeginPaint (xevent->hwnd, &paintstruct); + + GDK_NOTE (EVENTS, + g_print ("WM_PAINT: %#x %dx%d@+%d+%d %s dc %#x\n", + xevent->hwnd, + paintstruct.rcPaint.right - paintstruct.rcPaint.left, + paintstruct.rcPaint.bottom - paintstruct.rcPaint.top, + paintstruct.rcPaint.left, paintstruct.rcPaint.top, + (paintstruct.fErase ? "erase" : ""), + hdc)); + + EndPaint (xevent->hwnd, &paintstruct); + + if (!(WINDOW_PRIVATE(window)->event_mask & GDK_EXPOSURE_MASK)) + break; + + event->expose.type = GDK_EXPOSE; + event->expose.window = window; + event->expose.area.x = paintstruct.rcPaint.left; + event->expose.area.y = paintstruct.rcPaint.top; + event->expose.area.width = paintstruct.rcPaint.right - paintstruct.rcPaint.left; + event->expose.area.height = paintstruct.rcPaint.bottom - paintstruct.rcPaint.top; + event->expose.count = 0; + + return_val = !GDK_DRAWABLE_DESTROYED (window); + if (return_val) + { + GList *list = queued_events; + while (list != NULL ) + { + if ((((GdkEvent *)list->data)->any.type == GDK_EXPOSE) && + (((GdkEvent *)list->data)->any.window == window) && + !(((GdkEventPrivate *)list->data)->flags & GDK_EVENT_PENDING)) + ((GdkEvent *)list->data)->expose.count++; + + list = list->next; + } + } + break; + + case WM_SETCURSOR: + GDK_NOTE (EVENTS, g_print ("WM_SETCURSOR: %#x %#x %#x\n", + xevent->hwnd, + LOWORD (xevent->lParam), HIWORD (xevent->lParam))); + + if (LOWORD (xevent->lParam) != HTCLIENT) + break; + if (p_grab_window != NULL && p_grab_cursor != NULL) + { + GDK_NOTE (EVENTS, g_print ("...SetCursor(%#x)\n", p_grab_cursor)); + SetCursor (p_grab_cursor); + } + else if (!GDK_DRAWABLE_DESTROYED (window) + && WINDOW_PRIVATE(window)->xcursor) + { + GDK_NOTE (EVENTS, g_print ("...SetCursor(%#x)\n", + WINDOW_PRIVATE(window)->xcursor)); + SetCursor (WINDOW_PRIVATE(window)->xcursor); + } + + if (window != curWnd) + synthesize_crossing_events (window, xevent); + + *ret_val_flagp = TRUE; + *ret_valp = FALSE; + break; + + case WM_SHOWWINDOW: + GDK_NOTE (EVENTS, g_print ("WM_SHOWWINDOW: %#x %d\n", + xevent->hwnd, + xevent->wParam)); + + if (!(WINDOW_PRIVATE(window)->event_mask & GDK_STRUCTURE_MASK)) + break; + + event->any.type = (xevent->wParam ? GDK_MAP : GDK_UNMAP); + event->any.window = window; + + if (event->any.type == GDK_UNMAP + && p_grab_window == window) + gdk_pointer_ungrab (xevent->time); + + if (event->any.type == GDK_UNMAP + && k_grab_window == window) + gdk_keyboard_ungrab (xevent->time); + + return_val = !GDK_DRAWABLE_DESTROYED (window); + break; + + case WM_SIZE: + GDK_NOTE (EVENTS, + g_print ("WM_SIZE: %#x %s %dx%d\n", + xevent->hwnd, + (xevent->wParam == SIZE_MAXHIDE ? "MAXHIDE" : + (xevent->wParam == SIZE_MAXIMIZED ? "MAXIMIZED" : + (xevent->wParam == SIZE_MAXSHOW ? "MAXSHOW" : + (xevent->wParam == SIZE_MINIMIZED ? "MINIMIZED" : + (xevent->wParam == SIZE_RESTORED ? "RESTORED" : "?"))))), + LOWORD (xevent->lParam), HIWORD (xevent->lParam))); + + if (!(WINDOW_PRIVATE(window)->event_mask & GDK_STRUCTURE_MASK)) + break; + + if (xevent->wParam == SIZE_MINIMIZED) + { + event->any.type = GDK_UNMAP; + event->any.window = window; + + if (p_grab_window == window) + gdk_pointer_ungrab (xevent->time); + + if (k_grab_window == window) + gdk_keyboard_ungrab (xevent->time); + + return_val = !GDK_DRAWABLE_DESTROYED (window); + } + else if ((xevent->wParam == SIZE_RESTORED + || xevent->wParam == SIZE_MAXIMIZED) +#if 1 + && GDK_DRAWABLE_TYPE (window) != GDK_WINDOW_CHILD +#endif + ) + { + if (LOWORD (xevent->lParam) == 0) + break; + + event->configure.type = GDK_CONFIGURE; + event->configure.window = window; + pt.x = 0; + pt.y = 0; + ClientToScreen (xevent->hwnd, &pt); + event->configure.x = pt.x; + event->configure.y = pt.y; + event->configure.width = LOWORD (xevent->lParam); + event->configure.height = HIWORD (xevent->lParam); + WINDOW_PRIVATE(window)->x = event->configure.x; + WINDOW_PRIVATE(window)->y = event->configure.y; + WINDOW_PRIVATE(window)->drawable.width = event->configure.width; + WINDOW_PRIVATE(window)->drawable.height = event->configure.height; + if (WINDOW_PRIVATE(window)->resize_count > 1) + WINDOW_PRIVATE(window)->resize_count -= 1; + + return_val = !GDK_DRAWABLE_DESTROYED (window); + if (return_val + && WINDOW_PRIVATE(window)->extension_events != 0 + && gdk_input_vtable.configure_event) + gdk_input_vtable.configure_event (&event->configure, window); + } + break; + + case WM_GETMINMAXINFO: + GDK_NOTE (EVENTS, g_print ("WM_GETMINMAXINFO: %#x\n", xevent->hwnd)); + + lpmmi = (MINMAXINFO*) xevent->lParam; + if (WINDOW_PRIVATE(window)->hint_flags & GDK_HINT_MIN_SIZE) + { + lpmmi->ptMinTrackSize.x = WINDOW_PRIVATE(window)->hint_min_width; + lpmmi->ptMinTrackSize.y = WINDOW_PRIVATE(window)->hint_min_height; + } + if (WINDOW_PRIVATE(window)->hint_flags & GDK_HINT_MAX_SIZE) + { + lpmmi->ptMaxTrackSize.x = WINDOW_PRIVATE(window)->hint_max_width; + lpmmi->ptMaxTrackSize.y = WINDOW_PRIVATE(window)->hint_max_height; + + lpmmi->ptMaxSize.x = WINDOW_PRIVATE(window)->hint_max_width; + lpmmi->ptMaxSize.y = WINDOW_PRIVATE(window)->hint_max_height; + } + break; + + case WM_MOVE: + GDK_NOTE (EVENTS, g_print ("WM_MOVE: %#x (%d,%d)\n", + xevent->hwnd, + LOWORD (xevent->lParam), HIWORD (xevent->lParam))); + + if (!(WINDOW_PRIVATE(window)->event_mask & GDK_STRUCTURE_MASK)) + break; + + if (GDK_DRAWABLE_TYPE (window) != GDK_WINDOW_CHILD) + { + event->configure.type = GDK_CONFIGURE; + event->configure.window = window; + event->configure.x = LOWORD (xevent->lParam); + event->configure.y = HIWORD (xevent->lParam); + GetClientRect (xevent->hwnd, &rect); + event->configure.width = rect.right; + event->configure.height = rect.bottom; + WINDOW_PRIVATE(window)->x = event->configure.x; + WINDOW_PRIVATE(window)->y = event->configure.y; + WINDOW_PRIVATE(window)->drawable.width = event->configure.width; + WINDOW_PRIVATE(window)->drawable.height = event->configure.height; + + return_val = !GDK_DRAWABLE_DESTROYED (window); + } + break; + + case WM_CLOSE: + GDK_NOTE (EVENTS, g_print ("WM_CLOSE: %#x\n", xevent->hwnd)); + + event->any.type = GDK_DELETE; + event->any.window = window; + + return_val = !GDK_DRAWABLE_DESTROYED (window); + break; + +#if 0 + /* No, don't use delayed rendering after all. It works only if the + * delayed SetClipboardData is called from the WindowProc, it + * seems. (The #else part below is test code for that. It succeeds + * in setting the clipboard data. But if I call SetClipboardData + * in gdk_property_change (as a consequence of the + * GDK_SELECTION_REQUEST event), it fails. I deduce that this is + * because delayed rendering requires that SetClipboardData is + * called in the window procedure.) + */ + case WM_RENDERFORMAT: + case WM_RENDERALLFORMATS: + flag = FALSE; + GDK_NOTE (EVENTS, flag = TRUE); + GDK_NOTE (SELECTION, flag = TRUE); + if (flag) + g_print ("WM_%s: %#x %#x (%s)\n", + (xevent->message == WM_RENDERFORMAT ? "RENDERFORMAT" : + "RENDERALLFORMATS"), + xevent->hwnd, + xevent->wParam, + (xevent->wParam == CF_TEXT ? "CF_TEXT" : + (xevent->wParam == CF_DIB ? "CF_DIB" : + (xevent->wParam == CF_UNICODETEXT ? "CF_UNICODETEXT" : + (GetClipboardFormatName (xevent->wParam, buf, sizeof (buf)), buf))))); + +#if 0 + event->selection.type = GDK_SELECTION_REQUEST; + event->selection.window = window; + event->selection.selection = gdk_clipboard_atom; + if (xevent->wParam == CF_TEXT) + event->selection.target = GDK_TARGET_STRING; + else + { + GetClipboardFormatName (xevent->wParam, buf, sizeof (buf)); + event->selection.target = gdk_atom_intern (buf, FALSE); + } + event->selection.property = gdk_selection_property; + event->selection.requestor = (guint32) xevent->hwnd; + event->selection.time = xevent->time; + return_val = !GDK_DRAWABLE_DESTROYED (window); +#else + /* Test code, to see if SetClipboardData works when called from + * the window procedure. + */ + { + HGLOBAL hdata = GlobalAlloc (GMEM_MOVEABLE|GMEM_DDESHARE, 10); + char *ptr = GlobalLock (hdata); + strcpy (ptr, "Huhhaa"); + GlobalUnlock (hdata); + if (!SetClipboardData (CF_TEXT, hdata)) + g_print ("SetClipboardData failed: %d\n", GetLastError ()); + } + *ret_valp = 0; + *ret_val_flagp = TRUE; + return_val = FALSE; +#endif + break; +#endif /* No delayed rendering */ + + case WM_DESTROY: + GDK_NOTE (EVENTS, g_print ("WM_DESTROY: %#x\n", xevent->hwnd)); + + event->any.type = GDK_DESTROY; + event->any.window = window; + if (window != NULL && window == curWnd) + { + gdk_window_unref (curWnd); + curWnd = NULL; + } + + if (p_grab_window == window) + gdk_pointer_ungrab (xevent->time); + + if (k_grab_window == window) + gdk_keyboard_ungrab (xevent->time); + + return_val = !GDK_DRAWABLE_DESTROYED (window); + break; + +#ifdef HAVE_WINTAB + /* Handle WINTAB events here, as we know that gdkinput.c will + * use the fixed WT_DEFBASE as lcMsgBase, and we thus can use the + * constants as case labels. + */ + case WT_PACKET: + GDK_NOTE (EVENTS, g_print ("WT_PACKET: %d %#x\n", + xevent->wParam, xevent->lParam)); + goto wintab; + + case WT_CSRCHANGE: + GDK_NOTE (EVENTS, g_print ("WT_CSRCHANGE: %d %#x\n", + xevent->wParam, xevent->lParam)); + goto wintab; + + case WT_PROXIMITY: + GDK_NOTE (EVENTS, + g_print ("WT_PROXIMITY: %#x %d %d\n", + xevent->wParam, + LOWORD (xevent->lParam), HIWORD (xevent->lParam))); + /* Fall through */ + wintab: + return_val = gdk_input_vtable.other_event(event, xevent); + break; +#endif + } + +bypass_switch: + + if (return_val) + { + if (event->any.window) + gdk_window_ref (event->any.window); + if (((event->any.type == GDK_ENTER_NOTIFY) || + (event->any.type == GDK_LEAVE_NOTIFY)) && + (event->crossing.subwindow != NULL)) + gdk_window_ref (event->crossing.subwindow); + + GDK_NOTE (EVENTS, print_event (event)); + } + else + { + /* Mark this event as having no resources to be freed */ + event->any.window = NULL; + event->any.type = GDK_NOTHING; + } + + if (window) + gdk_window_unref (window); + + return return_val; +} + +static void +gdk_events_queue (void) +{ + GList *node; + GdkEvent *event; + MSG msg; + LRESULT lres; + + while (!gdk_event_queue_find_first() + && PeekMessage (&msg, NULL, 0, 0, PM_REMOVE)) + { + GDK_NOTE (EVENTS, g_print ("PeekMessage: %#x %#x\n", + msg.hwnd, msg.message)); + + if (paimmmpo == NULL + || (paimmmpo->lpVtbl->OnTranslateMessage) (paimmmpo, &msg) != S_OK) + TranslateMessage (&msg); + +#ifdef USE_DISPATCHMESSAGE + if (msg.message == g_pipe_readable_msg) + { + GDK_NOTE (EVENTS, g_print ("g_pipe_readable_msg: %d %d\n", + msg.wParam, msg.lParam)); + + g_io_channel_win32_pipe_readable (msg.wParam, msg.lParam); + + continue; + } + + DispatchMessage (&msg); +#else + event = gdk_event_new (); + + event->any.type = GDK_NOTHING; + event->any.window = NULL; + event->any.send_event = FALSE; + + ((GdkEventPrivate *)event)->flags |= GDK_EVENT_PENDING; + + gdk_event_queue_append (event); + node = queued_tail; + + if (gdk_event_translate (event, &msg, NULL, NULL)) + ((GdkEventPrivate *)event)->flags &= ~GDK_EVENT_PENDING; + else + { + if (paimmapp == NULL + || (paimmapp->lpVtbl->OnDefWindowProc) (paimmapp, msg.hwnd, + msg.message, + msg.wParam, msg.lParam, + &lres) == S_FALSE) + DefWindowProc (msg.hwnd, msg.message, msg.wParam, msg.lParam); + gdk_event_queue_remove_link (node); + g_list_free_1 (node); + gdk_event_free (event); + } +#endif + } +} + +static gboolean +gdk_event_prepare (gpointer source_data, + GTimeVal *current_time, + gint *timeout) +{ + MSG msg; + gboolean retval; + + GDK_THREADS_ENTER (); + + *timeout = -1; + + retval = (gdk_event_queue_find_first () != NULL) + || PeekMessage (&msg, NULL, 0, 0, PM_NOREMOVE); + + GDK_THREADS_LEAVE (); + + return retval; +} + +static gboolean +gdk_event_check (gpointer source_data, + GTimeVal *current_time) +{ + MSG msg; + gboolean retval; + + GDK_THREADS_ENTER (); + + if (event_poll_fd.revents & G_IO_IN) + retval = (gdk_event_queue_find_first () != NULL) + || PeekMessage (&msg, NULL, 0, 0, PM_NOREMOVE); + else + retval = FALSE; + + GDK_THREADS_LEAVE (); + + return retval; +} + +static GdkEvent* +gdk_event_unqueue (void) +{ + GdkEvent *event = NULL; + GList *tmp_list; + + tmp_list = gdk_event_queue_find_first (); + + if (tmp_list) + { + event = tmp_list->data; + gdk_event_queue_remove_link (tmp_list); + g_list_free_1 (tmp_list); + } + + return event; +} + +static gboolean +gdk_event_dispatch (gpointer source_data, + GTimeVal *current_time, + gpointer user_data) +{ + GdkEvent *event; + + GDK_THREADS_ENTER (); + + gdk_events_queue(); + event = gdk_event_unqueue(); + + if (event) + { + if (event_func) + (*event_func) (event, event_data); + + gdk_event_free (event); + } + + GDK_THREADS_LEAVE (); + + return TRUE; +} + +static void +gdk_synthesize_click (GdkEvent *event, + gint nclicks) +{ + GdkEvent temp_event; + + g_return_if_fail (event != NULL); + + temp_event = *event; + temp_event.type = (nclicks == 2) ? GDK_2BUTTON_PRESS : GDK_3BUTTON_PRESS; + + gdk_event_put (&temp_event); +} + +void +gdk_event_button_generate (GdkEvent *event) +{ + if ((event->button.time < (button_click_time[1] + TRIPLE_CLICK_TIME)) && + (event->button.window == button_window[1]) && + (event->button.button == button_number[1])) + { + gdk_synthesize_click (event, 3); + + button_click_time[1] = 0; + button_click_time[0] = 0; + button_window[1] = NULL; + button_window[0] = 0; + button_number[1] = -1; + button_number[0] = -1; + } + else if ((event->button.time < (button_click_time[0] + DOUBLE_CLICK_TIME)) && + (event->button.window == button_window[0]) && + (event->button.button == button_number[0])) + { + gdk_synthesize_click (event, 2); + + button_click_time[1] = button_click_time[0]; + button_click_time[0] = event->button.time; + button_window[1] = button_window[0]; + button_window[0] = event->button.window; + button_number[1] = button_number[0]; + button_number[0] = event->button.button; + } + else + { + button_click_time[1] = 0; + button_click_time[0] = event->button.time; + button_window[1] = NULL; + button_window[0] = event->button.window; + button_number[1] = -1; + button_number[0] = event->button.button; + } +} + +/* Sends a ClientMessage to all toplevel client windows */ +gboolean +gdk_event_send_client_message (GdkEvent *event, guint32 xid) +{ + /* XXX */ + return FALSE; +} + +void +gdk_event_send_clientmessage_toall (GdkEvent *event) +{ + /* XXX */ +} + diff --git a/gdk/win32/gdkfont-win32.c b/gdk/win32/gdkfont-win32.c new file mode 100644 index 000000000..3cee42da8 --- /dev/null +++ b/gdk/win32/gdkfont-win32.c @@ -0,0 +1,1501 @@ +/* GDK - The GIMP Drawing Kit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* + * Modified by the GTK+ Team and others 1997-1999. See the AUTHORS + * file for a list of people on the GTK+ Team. See the ChangeLog + * files for a list of changes. These files are distributed with + * GTK+ at ftp://ftp.gtk.org/pub/gtk/. + */ + +#include "config.h" + +#include +#include + +#include "gdkfont.h" +#include "gdkx.h" + +static GHashTable *font_name_hash = NULL; +static GHashTable *fontset_name_hash = NULL; + +static void +gdk_font_hash_insert (GdkFontType type, + GdkFont *font, + const gchar *font_name) +{ + GdkFontPrivate *private = (GdkFontPrivate *) font; + GHashTable **hashp = (type == GDK_FONT_FONT) ? + &font_name_hash : &fontset_name_hash; + + if (!*hashp) + *hashp = g_hash_table_new (g_str_hash, g_str_equal); + + private->names = g_slist_prepend (private->names, g_strdup (font_name)); + g_hash_table_insert (*hashp, private->names->data, font); +} + +static void +gdk_font_hash_remove (GdkFontType type, + GdkFont *font) +{ + GdkFontPrivate *private = (GdkFontPrivate *) font; + GSList *tmp_list; + GHashTable *hash = (type == GDK_FONT_FONT) ? + font_name_hash : fontset_name_hash; + + tmp_list = private->names; + while (tmp_list) + { + g_hash_table_remove (hash, tmp_list->data); + g_free (tmp_list->data); + + tmp_list = tmp_list->next; + } + + g_slist_free (private->names); + private->names = NULL; +} + +static GdkFont * +gdk_font_hash_lookup (GdkFontType type, + const gchar *font_name) +{ + GdkFont *result; + GHashTable *hash = (type == GDK_FONT_FONT) ? + font_name_hash : fontset_name_hash; + + if (!hash) + return NULL; + else + { + result = g_hash_table_lookup (hash, font_name); + if (result) + gdk_font_ref (result); + + return result; + } +} + +static const char * +charset_name (DWORD charset) +{ + switch (charset) + { + case ANSI_CHARSET: return "ansi"; + case DEFAULT_CHARSET: return "default"; + case SYMBOL_CHARSET: return "symbol"; + case SHIFTJIS_CHARSET: return "shiftjis"; + case HANGEUL_CHARSET: return "hangeul"; + case GB2312_CHARSET: return "gb2312"; + case CHINESEBIG5_CHARSET: return "big5"; + case JOHAB_CHARSET: return "johab"; + case HEBREW_CHARSET: return "hebrew"; + case ARABIC_CHARSET: return "arabic"; + case GREEK_CHARSET: return "greek"; + case TURKISH_CHARSET: return "turkish"; + case VIETNAMESE_CHARSET: return "vietnamese"; + case THAI_CHARSET: return "thai"; + case EASTEUROPE_CHARSET: return "easteurope"; + case RUSSIAN_CHARSET: return "russian"; + case MAC_CHARSET: return "mac"; + case BALTIC_CHARSET: return "baltic"; + } + return "unknown"; +} + +static gint num_fonts; +static gint font_names_size; +static gchar **xfontnames; + +static gchar * +logfont_to_xlfd (const LOGFONT *lfp, + int size, + int res, + int avg_width) +{ + const gchar *weight; + const gchar *registry, *encoding; + int point_size; + static int logpixelsy = 0; + gchar facename[LF_FACESIZE*3]; + gchar *p; + const gchar *q; + + if (logpixelsy == 0) + { + logpixelsy = GetDeviceCaps (gdk_DC, LOGPIXELSY); + } + + if (lfp->lfWeight >= FW_HEAVY) + weight = "heavy"; + else if (lfp->lfWeight >= FW_EXTRABOLD) + weight = "extrabold"; + else if (lfp->lfWeight >= FW_BOLD) + weight = "bold"; +#ifdef FW_DEMIBOLD + else if (lfp->lfWeight >= FW_DEMIBOLD) + weight = "demibold"; +#endif + else if (lfp->lfWeight >= FW_MEDIUM) + weight = "medium"; + else if (lfp->lfWeight >= FW_NORMAL) + weight = "normal"; + else if (lfp->lfWeight >= FW_LIGHT) + weight = "light"; + else if (lfp->lfWeight >= FW_EXTRALIGHT) + weight = "extralight"; + else if (lfp->lfWeight >= FW_THIN) + weight = "thin"; + else + weight = "regular"; + + switch (lfp->lfCharSet) + { + case ANSI_CHARSET: + registry = "iso8859"; + encoding = "1"; + break; + case SHIFTJIS_CHARSET: + registry = "jisx0208.1983"; + encoding = "0"; + break; + case HANGEUL_CHARSET: + registry = "ksc5601.1987"; + encoding = "0"; + break; + case GB2312_CHARSET: + registry = "gb2312.1980"; + encoding = "0"; + break; + case CHINESEBIG5_CHARSET: + registry = "big5"; + encoding = "0"; + break; + case GREEK_CHARSET: + registry = "iso8859"; + encoding = "7"; + break; + case TURKISH_CHARSET: + registry = "iso8859"; + encoding = "9"; + break; +#if 0 /* Not a good idea, I think, to use ISO8859-8 and -6 for the Windows + * hebrew and arabic codepages, they differ too much. + */ + case HEBREW_CHARSET: + registry = "iso8859"; + encoding = "8"; + break; + case ARABIC_CHARSET: + registry = "iso8859"; + encoding = "6"; + break; +#endif + default: + registry = "microsoft"; + encoding = charset_name (lfp->lfCharSet); + } + + point_size = (int) (((double) size/logpixelsy) * 720.); + + if (res == -1) + res = logpixelsy; + + /* Replace illegal characters with hex escapes. */ + p = facename; + q = lfp->lfFaceName; + while (*q) + { + if (*q == '-' || *q == '*' || *q == '?' || *q == '%') + p += sprintf (p, "%%%.02x", *q); + else + *p++ = *q; + q++; + } + *p = '\0'; + + return g_strdup_printf + ("-%s-%s-%s-%s-%s-%s-%d-%d-%d-%d-%s-%d-%s-%s", + "unknown", + facename, + weight, + (lfp->lfItalic ? + ((lfp->lfPitchAndFamily & 0xF0) == FF_ROMAN + || (lfp->lfPitchAndFamily & 0xF0) == FF_SCRIPT ? + "i" : "o") : "r"), + "normal", + "", + size, + point_size, + res, + res, + ((lfp->lfPitchAndFamily & 0x03) == FIXED_PITCH ? "m" : "p"), + avg_width, + registry, encoding); +} + +gchar * +gdk_font_xlfd_create (GdkFont *font) +{ + GdkFontPrivate *private; + GdkWin32SingleFont *singlefont; + GSList *list; + GString *string; + gchar *result; + LOGFONT logfont; + + g_return_val_if_fail (font != NULL, NULL); + + private = (GdkFontPrivate *) font; + + list = private->fonts; + string = g_string_new (""); + + while (list) + { + singlefont = (GdkWin32SingleFont *) list->data; + + if (GetObject (singlefont->xfont, sizeof (LOGFONT), &logfont) == 0) + { + g_warning ("gdk_win32_font_xlfd: GetObject failed"); + return NULL; + } + + string = + g_string_append (string, + logfont_to_xlfd (&logfont, logfont.lfHeight, -1, 0)); + list = list->next; + if (list) + string = g_string_append_c (string, ','); + } + result = string->str; + g_string_free (string, FALSE); + return result; +} + +void +gdk_font_xlfd_free (gchar *xlfd) +{ + g_free (xlfd); +} + +static gboolean +pattern_match (const gchar *pattern, + const gchar *string) +{ + const gchar *p = pattern, *n = string; + gchar c, c1; + + /* Common case first */ + if ((pattern[0] == '*' + && pattern[1] == '\0') + || (pattern[0] == '-' + && pattern[1] == '*' + && pattern[2] == '\0')) + return TRUE; + + while ((c = *p++) != '\0') + { + c = tolower (c); + + switch (c) + { + case '?': + if (*n == '\0') + return FALSE; + break; + + case '*': + for (c = *p++; c == '?' || c == '*'; c = *p++, ++n) + if (c == '?' && *n == '\0') + return FALSE; + + if (c == '\0') + return TRUE; + + c1 = tolower (c); + for (--p; *n != '\0'; ++n) + if (tolower (*n) == c1 + && pattern_match (p, n)) + return TRUE; + return FALSE; + + default: + if (c != tolower (*n)) + return FALSE; + } + + ++n; + } + + if (*n == '\0') + return TRUE; + + return FALSE; +} + +int CALLBACK +InnerEnumFontFamExProc (const LOGFONT *lfp, + const TEXTMETRIC *metrics, + DWORD fontType, + LPARAM lParam) +{ + int size; + gchar *xlfd; + + if (fontType == TRUETYPE_FONTTYPE) + { + size = 0; + } + else + { + size = lfp->lfHeight; + } + + xlfd = logfont_to_xlfd (lfp, size, 0, 0); + + if (!pattern_match ((gchar *) lParam, xlfd)) + { + g_free (xlfd); + return 1; + } + + num_fonts++; + if (num_fonts == font_names_size) + { + font_names_size *= 2; + xfontnames = g_realloc (xfontnames, font_names_size * sizeof (gchar *)); + } + xfontnames[num_fonts-1] = xlfd; + + return 1; +} + +int CALLBACK +EnumFontFamExProc (const LOGFONT *lfp, + const TEXTMETRIC *metrics, + DWORD fontType, + LPARAM lParam) +{ + if (fontType == TRUETYPE_FONTTYPE) + { + LOGFONT lf; + + lf = *lfp; + + EnumFontFamiliesEx (gdk_DC, &lf, InnerEnumFontFamExProc, lParam, 0); + } + else + InnerEnumFontFamExProc (lfp, metrics, fontType, lParam); + + return 1; +} + +gchar ** +gdk_font_list_new (const gchar *font_pattern, + gint *n_returned) +{ + LOGFONT logfont; + gchar **result; + + num_fonts = 0; + font_names_size = 100; + xfontnames = g_new (gchar *, font_names_size); + memset (&logfont, 0, sizeof (logfont)); + logfont.lfCharSet = DEFAULT_CHARSET; + EnumFontFamiliesEx (gdk_DC, &logfont, EnumFontFamExProc, + (LPARAM) font_pattern, 0); + + result = g_new (gchar *, num_fonts + 1); + memmove (result, xfontnames, num_fonts * sizeof (gchar *)); + result[num_fonts] = NULL; + g_free (xfontnames); + + *n_returned = num_fonts; + return result; +} + +void +gdk_font_list_free (gchar **font_list) +{ + g_strfreev (font_list); +} + +GdkWin32SingleFont* +gdk_font_load_internal (const gchar *font_name) +{ + GdkWin32SingleFont *singlefont; + HFONT hfont; + LOGFONT logfont; + CHARSETINFO csi; + DWORD fdwItalic, fdwUnderline, fdwStrikeOut, fdwCharSet, + fdwOutputPrecision, fdwClipPrecision, fdwQuality, fdwPitchAndFamily; + const char *lpszFace; + + int numfields, n1, n2, tries; + char foundry[32], family[100], weight[32], slant[32], set_width[32], + spacing[32], registry[32], encoding[32]; + char pixel_size[10], point_size[10], res_x[10], res_y[10], avg_width[10]; + int c; + char *p; + int nHeight, nWidth, nEscapement, nOrientation, fnWeight; + int logpixelsy; + + g_return_val_if_fail (font_name != NULL, NULL); + + GDK_NOTE (MISC, g_print ("gdk_font_load_internal: %s\n", font_name)); + + numfields = sscanf (font_name, + "-%30[^-]-%100[^-]-%30[^-]-%30[^-]-%30[^-]-%n", + foundry, + family, + weight, + slant, + set_width, + &n1); + if (numfields == 0) + { + /* Probably a plain Windows font name */ + nHeight = 0; + nWidth = 0; + nEscapement = 0; + nOrientation = 0; + fnWeight = FW_DONTCARE; + fdwItalic = FALSE; + fdwUnderline = FALSE; + fdwStrikeOut = FALSE; + fdwCharSet = ANSI_CHARSET; + fdwOutputPrecision = OUT_TT_PRECIS; + fdwClipPrecision = CLIP_DEFAULT_PRECIS; + fdwQuality = PROOF_QUALITY; + fdwPitchAndFamily = DEFAULT_PITCH; + lpszFace = font_name; + } + else if (numfields != 5) + { + g_warning ("gdk_font_load: font name %s illegal", font_name); + return NULL; + } + else + { + /* It must be a XLFD name */ + + /* Check for hex escapes in the font family, + * put in there by gtkfontsel. + */ + p = family; + while (*p) + { + if (*p == '%' && isxdigit (p[1]) && isxdigit (p[2])) + { + sscanf (p+1, "%2x", &c); + *p = c; + strcpy (p+1, p+3); + } + p++; + } + + /* Skip add_style which often is empty in the requested font name */ + while (font_name[n1] && font_name[n1] != '-') + n1++; + numfields++; + + numfields += sscanf (font_name + n1, + "-%8[^-]-%8[^-]-%8[^-]-%8[^-]-%30[^-]-%8[^-]-%30[^-]-%30[^-]%n", + pixel_size, + point_size, + res_x, + res_y, + spacing, + avg_width, + registry, + encoding, + &n2); + + if (numfields != 14 || font_name[n1 + n2] != '\0') + { + g_warning ("gdk_font_load: font name %s illegal", font_name); + return NULL; + } + + logpixelsy = GetDeviceCaps (gdk_DC, LOGPIXELSY); + + if (strcmp (pixel_size, "*") == 0) + if (strcmp (point_size, "*") == 0) + nHeight = 0; + else + nHeight = (int) (((double) atoi (point_size))/720.*logpixelsy); + else + nHeight = atoi (pixel_size); + + nWidth = 0; + nEscapement = 0; + nOrientation = 0; + + if (g_strcasecmp (weight, "thin") == 0) + fnWeight = FW_THIN; + else if (g_strcasecmp (weight, "extralight") == 0) + fnWeight = FW_EXTRALIGHT; + else if (g_strcasecmp (weight, "ultralight") == 0) +#ifdef FW_ULTRALIGHT + fnWeight = FW_ULTRALIGHT; +#else + fnWeight = FW_EXTRALIGHT; /* In fact, FW_ULTRALIGHT really is + * defined as FW_EXTRALIGHT anyway. + */ +#endif + else if (g_strcasecmp (weight, "light") == 0) + fnWeight = FW_LIGHT; + else if (g_strcasecmp (weight, "normal") == 0) + fnWeight = FW_NORMAL; + else if (g_strcasecmp (weight, "regular") == 0) + fnWeight = FW_REGULAR; + else if (g_strcasecmp (weight, "medium") == 0) + fnWeight = FW_MEDIUM; + else if (g_strcasecmp (weight, "semibold") == 0) + fnWeight = FW_SEMIBOLD; + else if (g_strcasecmp (weight, "demibold") == 0) +#ifdef FW_DEMIBOLD + fnWeight = FW_DEMIBOLD; +#else + fnWeight = FW_SEMIBOLD; /* As above */ +#endif + else if (g_strcasecmp (weight, "bold") == 0) + fnWeight = FW_BOLD; + else if (g_strcasecmp (weight, "extrabold") == 0) + fnWeight = FW_EXTRABOLD; + else if (g_strcasecmp (weight, "ultrabold") == 0) +#ifdef FW_ULTRABOLD + fnWeight = FW_ULTRABOLD; +#else + fnWeight = FW_EXTRABOLD; /* As above */ +#endif + else if (g_strcasecmp (weight, "heavy") == 0) + fnWeight = FW_HEAVY; + else if (g_strcasecmp (weight, "black") == 0) +#ifdef FW_BLACK + fnWeight = FW_BLACK; +#else + fnWeight = FW_HEAVY; /* As above */ +#endif + else + fnWeight = FW_DONTCARE; + + if (g_strcasecmp (slant, "italic") == 0 + || g_strcasecmp (slant, "oblique") == 0 + || g_strcasecmp (slant, "i") == 0 + || g_strcasecmp (slant, "o") == 0) + fdwItalic = TRUE; + else + fdwItalic = FALSE; + fdwUnderline = FALSE; + fdwStrikeOut = FALSE; + if (g_strcasecmp (registry, "iso8859") == 0) + if (strcmp (encoding, "1") == 0) + fdwCharSet = ANSI_CHARSET; + else if (strcmp (encoding, "2") == 0) + fdwCharSet = EASTEUROPE_CHARSET; + else if (strcmp (encoding, "7") == 0) + fdwCharSet = GREEK_CHARSET; + else if (strcmp (encoding, "8") == 0) + fdwCharSet = HEBREW_CHARSET; + else if (strcmp (encoding, "9") == 0) + fdwCharSet = TURKISH_CHARSET; + else + fdwCharSet = ANSI_CHARSET; /* XXX ??? */ + else if (g_strcasecmp (registry, "jisx0208.1983") == 0) + fdwCharSet = SHIFTJIS_CHARSET; + else if (g_strcasecmp (registry, "ksc5601.1987") == 0) + fdwCharSet = HANGEUL_CHARSET; + else if (g_strcasecmp (registry, "gb2312.1980") == 0) + fdwCharSet = GB2312_CHARSET; + else if (g_strcasecmp (registry, "big5") == 0) + fdwCharSet = CHINESEBIG5_CHARSET; + else if (g_strcasecmp (registry, "windows") == 0 + || g_strcasecmp (registry, "microsoft") == 0) + if (g_strcasecmp (encoding, "symbol") == 0) + fdwCharSet = SYMBOL_CHARSET; + else if (g_strcasecmp (encoding, "shiftjis") == 0) + fdwCharSet = SHIFTJIS_CHARSET; + else if (g_strcasecmp (encoding, "gb2312") == 0) + fdwCharSet = GB2312_CHARSET; + else if (g_strcasecmp (encoding, "hangeul") == 0) + fdwCharSet = HANGEUL_CHARSET; + else if (g_strcasecmp (encoding, "big5") == 0) + fdwCharSet = CHINESEBIG5_CHARSET; + else if (g_strcasecmp (encoding, "johab") == 0) + fdwCharSet = JOHAB_CHARSET; + else if (g_strcasecmp (encoding, "hebrew") == 0) + fdwCharSet = HEBREW_CHARSET; + else if (g_strcasecmp (encoding, "arabic") == 0) + fdwCharSet = ARABIC_CHARSET; + else if (g_strcasecmp (encoding, "greek") == 0) + fdwCharSet = GREEK_CHARSET; + else if (g_strcasecmp (encoding, "turkish") == 0) + fdwCharSet = TURKISH_CHARSET; + else if (g_strcasecmp (encoding, "easteurope") == 0) + fdwCharSet = EASTEUROPE_CHARSET; + else if (g_strcasecmp (encoding, "russian") == 0) + fdwCharSet = RUSSIAN_CHARSET; + else if (g_strcasecmp (encoding, "mac") == 0) + fdwCharSet = MAC_CHARSET; + else if (g_strcasecmp (encoding, "baltic") == 0) + fdwCharSet = BALTIC_CHARSET; + else if (g_strcasecmp (encoding, "cp1251") == 0) + fdwCharSet = RUSSIAN_CHARSET; + else + fdwCharSet = ANSI_CHARSET; /* XXX ??? */ + else + fdwCharSet = ANSI_CHARSET; /* XXX ??? */ + fdwOutputPrecision = OUT_TT_PRECIS; + fdwClipPrecision = CLIP_DEFAULT_PRECIS; + fdwQuality = PROOF_QUALITY; + if (g_strcasecmp (spacing, "m") == 0) + fdwPitchAndFamily = FIXED_PITCH; + else if (g_strcasecmp (spacing, "p") == 0) + fdwPitchAndFamily = VARIABLE_PITCH; + else + fdwPitchAndFamily = DEFAULT_PITCH; + lpszFace = family; + } + + for (tries = 0; ; tries++) + { + GDK_NOTE (MISC, g_print ("...trying CreateFont(%d,%d,%d,%d," + "%d,%d,%d,%d," + "%d,%d,%d," + "%d,%#.02x,\"%s\")\n", + nHeight, nWidth, nEscapement, nOrientation, + fnWeight, fdwItalic, fdwUnderline, fdwStrikeOut, + fdwCharSet, fdwOutputPrecision, fdwClipPrecision, + fdwQuality, fdwPitchAndFamily, lpszFace)); + if ((hfont = + CreateFont (nHeight, nWidth, nEscapement, nOrientation, + fnWeight, fdwItalic, fdwUnderline, fdwStrikeOut, + fdwCharSet, fdwOutputPrecision, fdwClipPrecision, + fdwQuality, fdwPitchAndFamily, lpszFace)) != NULL) + break; + + /* If we fail, try some similar fonts often found on Windows. */ + + if (tries == 0) + { + if (g_strcasecmp (family, "helvetica") == 0) + lpszFace = "arial"; + else if (g_strcasecmp (family, "new century schoolbook") == 0) + lpszFace = "century schoolbook"; + else if (g_strcasecmp (family, "courier") == 0) + lpszFace = "courier new"; + else if (g_strcasecmp (family, "lucida") == 0) + lpszFace = "lucida sans unicode"; + else if (g_strcasecmp (family, "lucidatypewriter") == 0) + lpszFace = "lucida console"; + else if (g_strcasecmp (family, "times") == 0) + lpszFace = "times new roman"; + } + else if (tries == 1) + { + if (g_strcasecmp (family, "courier") == 0) + { + lpszFace = ""; + fdwPitchAndFamily |= FF_MODERN; + } + else if (g_strcasecmp (family, "times new roman") == 0) + { + lpszFace = ""; + fdwPitchAndFamily |= FF_ROMAN; + } + else if (g_strcasecmp (family, "helvetica") == 0 + || g_strcasecmp (family, "lucida") == 0) + { + lpszFace = ""; + fdwPitchAndFamily |= FF_SWISS; + } + else + { + lpszFace = ""; + fdwPitchAndFamily = (fdwPitchAndFamily & 0x0F) | FF_DONTCARE; + } + } + else + break; + tries++; + } + + if (!hfont) + return NULL; + + singlefont = g_new (GdkWin32SingleFont, 1); + singlefont->xfont = hfont; + GetObject (singlefont->xfont, sizeof (logfont), &logfont); + TranslateCharsetInfo ((DWORD *) singlefont->charset, &csi, TCI_SRCCHARSET); + singlefont->codepage = csi.ciACP; + GetCPInfo (singlefont->codepage, &singlefont->cpinfo); + + return singlefont; +} + +GdkFont* +gdk_font_load (const gchar *font_name) +{ + GdkFont *font; + GdkFontPrivate *private; + GdkWin32SingleFont *singlefont; + HGDIOBJ oldfont; + HANDLE *f; + TEXTMETRIC textmetric; + + g_return_val_if_fail (font_name != NULL, NULL); + + font = gdk_font_hash_lookup (GDK_FONT_FONTSET, font_name); + if (font) + return font; + + singlefont = gdk_font_load_internal (font_name); + + private = g_new (GdkFontPrivate, 1); + font = (GdkFont*) private; + + private->ref_count = 1; + private->names = NULL; + private->fonts = g_slist_append (NULL, singlefont); + + /* Pretend all fonts are fontsets... Gtktext and gtkentry work better + * that way, they use wide chars, which is necessary for non-ASCII + * chars to work. (Yes, even Latin-1, as we use Unicode internally.) + */ + font->type = GDK_FONT_FONTSET; + oldfont = SelectObject (gdk_DC, singlefont->xfont); + GetTextMetrics (gdk_DC, &textmetric); + singlefont->charset = GetTextCharsetInfo (gdk_DC, &singlefont->fs, 0); + SelectObject (gdk_DC, oldfont); + font->ascent = textmetric.tmAscent; + font->descent = textmetric.tmDescent; + + GDK_NOTE (MISC, g_print ("... = %#x charset %s codepage %d " + "asc %d desc %d\n", + singlefont->xfont, + charset_name (singlefont->charset), + singlefont->codepage, + font->ascent, font->descent)); + + gdk_font_hash_insert (GDK_FONT_FONTSET, font, font_name); + + return font; +} + +GdkFont* +gdk_fontset_load (gchar *fontset_name) +{ + GdkFont *font; + GdkFontPrivate *private; + GdkWin32SingleFont *singlefont; + HGDIOBJ oldfont; + HANDLE *f; + TEXTMETRIC textmetric; + GSList *base_font_list = NULL; + gchar *fs; + gchar *b, *p, *s; + + g_return_val_if_fail (fontset_name != NULL, NULL); + + font = gdk_font_hash_lookup (GDK_FONT_FONTSET, fontset_name); + if (font) + return font; + + s = fs = g_strdup (fontset_name); + while (*s && isspace (*s)) + s++; + + g_return_val_if_fail (*s, NULL); + + private = g_new (GdkFontPrivate, 1); + font = (GdkFont*) private; + + private->ref_count = 1; + private->names = NULL; + private->fonts = NULL; + + font->type = GDK_FONT_FONTSET; + font->ascent = 0; + font->descent = 0; + + while (TRUE) + { + if ((p = strchr (s, ',')) != NULL) + b = p; + else + b = s + strlen (s); + + while (isspace (b[-1])) + b--; + *b = '\0'; + singlefont = gdk_font_load_internal (s); + if (singlefont) + { + GDK_NOTE + (MISC, g_print ("... = %#x charset %s codepage %d\n", + singlefont->xfont, + charset_name (singlefont->charset), + singlefont->codepage)); + private->fonts = g_slist_append (private->fonts, singlefont); + oldfont = SelectObject (gdk_DC, singlefont->xfont); + GetTextMetrics (gdk_DC, &textmetric); + singlefont->charset = + GetTextCharsetInfo (gdk_DC, &singlefont->fs, 0); + SelectObject (gdk_DC, oldfont); + font->ascent = MAX (font->ascent, textmetric.tmAscent); + font->descent = MAX (font->descent, textmetric.tmDescent); + } + if (p) + { + s = p + 1; + while (*s && isspace (*s)) + s++; + } + else + break; + if (!*s) + break; + } + + g_free (fs); + + gdk_font_hash_insert (GDK_FONT_FONTSET, font, fontset_name); + + return font; +} + +GdkFont* +gdk_font_ref (GdkFont *font) +{ + GdkFontPrivate *private; + + g_return_val_if_fail (font != NULL, NULL); + + private = (GdkFontPrivate*) font; + private->ref_count += 1; + + GDK_NOTE (MISC, + g_print ("gdk_font_ref %#x %d\n", + ((GdkWin32SingleFont *) private->fonts->data)->xfont, + private->ref_count)); + return font; +} + +void +gdk_font_unref (GdkFont *font) +{ + GdkFontPrivate *private; + GdkWin32SingleFont *singlefont; + GSList *list; + private = (GdkFontPrivate*) font; + + g_return_if_fail (font != NULL); + g_return_if_fail (private->ref_count > 0); + + private->ref_count -= 1; + + singlefont = (GdkWin32SingleFont *) private->fonts->data; + GDK_NOTE (MISC, g_print ("gdk_font_unref %#x %d%s\n", + singlefont->xfont, private->ref_count, + (private->ref_count == 0 ? " freeing" : ""))); + + if (private->ref_count == 0) + { + gdk_font_hash_remove (font->type, font); + + switch (font->type) + { + case GDK_FONT_FONT: + DeleteObject (singlefont->xfont); + break; + + case GDK_FONT_FONTSET: + list = private->fonts; + while (list) + { + singlefont = (GdkWin32SingleFont *) list->data; + DeleteObject (singlefont->xfont); + + list = list->next; + } + g_slist_free (private->fonts); + break; + + default: + g_assert_not_reached (); + } + g_free (font); + } +} + +gint +gdk_font_id (const GdkFont *font) +{ + const GdkFontPrivate *font_private; + + g_return_val_if_fail (font != NULL, 0); + + font_private = (const GdkFontPrivate*) font; + + if (font->type == GDK_FONT_FONT) + return (gint) ((GdkWin32SingleFont *) font_private->fonts->data)->xfont; + else + return 0; +} + +gint +gdk_font_equal (const GdkFont *fonta, + const GdkFont *fontb) +{ + const GdkFontPrivate *privatea; + const GdkFontPrivate *privateb; + + g_return_val_if_fail (fonta != NULL, FALSE); + g_return_val_if_fail (fontb != NULL, FALSE); + + privatea = (const GdkFontPrivate*) fonta; + privateb = (const GdkFontPrivate*) fontb; + + if (fonta->type == GDK_FONT_FONT && fontb->type == GDK_FONT_FONT) + return (((GdkWin32SingleFont *) privatea->fonts->data)->xfont + == ((GdkWin32SingleFont *) privateb->fonts->data)->xfont); + else if (fonta->type == GDK_FONT_FONTSET && fontb->type == GDK_FONT_FONTSET) + { + GSList *lista = privatea->fonts; + GSList *listb = privateb->fonts; + + while (lista && listb) + { + if (((GdkWin32SingleFont *) lista->data)->xfont + != ((GdkWin32SingleFont *) listb->data)->xfont) + return 0; + lista = lista->next; + listb = listb->next; + } + if (lista || listb) + return 0; + else + return 1; + } + else + return 0; +} + +gint +gdk_string_width (GdkFont *font, + const gchar *string) +{ + return gdk_text_width (font, string, strlen (string)); +} + +/* This table classifies Unicode characters according to the Microsoft + * Unicode subset numbering. This is from the table in "Developing + * International Software for Windows 95 and Windows NT". This is almost, + * but not quite, the same as the official Unicode block table in + * Blocks.txt from ftp.unicode.org. The bit number field is the bitfield + * number as in the FONTSIGNATURE struct's fsUsb field. + */ +static struct { + wchar_t low, high; + guint bit; + gchar *name; +} utab[] = +{ + { 0x0000, 0x007E, 0, "Basic Latin" }, + { 0x00A0, 0x00FF, 1, "Latin-1 Supplement" }, + { 0x0100, 0x017F, 2, "Latin Extended-A" }, + { 0x0180, 0x024F, 3, "Latin Extended-B" }, + { 0x0250, 0x02AF, 4, "IPA Extensions" }, + { 0x02B0, 0x02FF, 5, "Spacing Modifier Letters" }, + { 0x0300, 0x036F, 6, "Combining Diacritical Marks" }, + { 0x0370, 0x03CF, 7, "Basic Greek" }, + { 0x03D0, 0x03FF, 8, "Greek Symbols and Coptic" }, + { 0x0400, 0x04FF, 9, "Cyrillic" }, + { 0x0530, 0x058F, 10, "Armenian" }, + { 0x0590, 0x05CF, 12, "Hebrew Extended" }, + { 0x05D0, 0x05FF, 11, "Basic Hebrew" }, + { 0x0600, 0x0652, 13, "Basic Arabic" }, + { 0x0653, 0x06FF, 14, "Arabic Extended" }, + { 0x0900, 0x097F, 15, "Devanagari" }, + { 0x0980, 0x09FF, 16, "Bengali" }, + { 0x0A00, 0x0A7F, 17, "Gurmukhi" }, + { 0x0A80, 0x0AFF, 18, "Gujarati" }, + { 0x0B00, 0x0B7F, 19, "Oriya" }, + { 0x0B80, 0x0BFF, 20, "Tamil" }, + { 0x0C00, 0x0C7F, 21, "Telugu" }, + { 0x0C80, 0x0CFF, 22, "Kannada" }, + { 0x0D00, 0x0D7F, 23, "Malayalam" }, + { 0x0E00, 0x0E7F, 24, "Thai" }, + { 0x0E80, 0x0EFF, 25, "Lao" }, + { 0x10A0, 0x10CF, 27, "Georgian Extended" }, + { 0x10D0, 0x10FF, 26, "Basic Georgian" }, + { 0x1100, 0x11FF, 28, "Hangul Jamo" }, + { 0x1E00, 0x1EFF, 29, "Latin Extended Additional" }, + { 0x1F00, 0x1FFF, 30, "Greek Extended" }, + { 0x2000, 0x206F, 31, "General Punctuation" }, + { 0x2070, 0x209F, 32, "Superscripts and Subscripts" }, + { 0x20A0, 0x20CF, 33, "Currency Symbols" }, + { 0x20D0, 0x20FF, 34, "Combining Diacritical Marks for Symbols" }, + { 0x2100, 0x214F, 35, "Letterlike Symbols" }, + { 0x2150, 0x218F, 36, "Number Forms" }, + { 0x2190, 0x21FF, 37, "Arrows" }, + { 0x2200, 0x22FF, 38, "Mathematical Operators" }, + { 0x2300, 0x23FF, 39, "Miscellaneous Technical" }, + { 0x2400, 0x243F, 40, "Control Pictures" }, + { 0x2440, 0x245F, 41, "Optical Character Recognition" }, + { 0x2460, 0x24FF, 42, "Enclosed Alphanumerics" }, + { 0x2500, 0x257F, 43, "Box Drawing" }, + { 0x2580, 0x259F, 44, "Block Elements" }, + { 0x25A0, 0x25FF, 45, "Geometric Shapes" }, + { 0x2600, 0x26FF, 46, "Miscellaneous Symbols" }, + { 0x2700, 0x27BF, 47, "Dingbats" }, + { 0x3000, 0x303F, 48, "CJK Symbols and Punctuation" }, + { 0x3040, 0x309F, 49, "Hiragana" }, + { 0x30A0, 0x30FF, 50, "Katakana" }, + { 0x3100, 0x312F, 51, "Bopomofo" }, + { 0x3130, 0x318F, 52, "Hangul Compatibility Jamo" }, + { 0x3190, 0x319F, 53, "CJK Miscellaneous" }, + { 0x3200, 0x32FF, 54, "Enclosed CJK" }, + { 0x3300, 0x33FF, 55, "CJK Compatibility" }, + { 0x3400, 0x3D2D, 56, "Hangul" }, + { 0x3D2E, 0x44B7, 57, "Hangul Supplementary-A" }, + { 0x44B8, 0x4DFF, 58, "Hangul Supplementary-B" }, + { 0x4E00, 0x9FFF, 59, "CJK Unified Ideographs" }, + { 0xE000, 0xF8FF, 60, "Private Use Area" }, + { 0xF900, 0xFAFF, 61, "CJK Compatibility Ideographs" }, + { 0xFB00, 0xFB4F, 62, "Alphabetic Presentation Forms" }, + { 0xFB50, 0xFDFF, 63, "Arabic Presentation Forms-A" }, + { 0xFE20, 0xFE2F, 64, "Combining Half Marks" }, + { 0xFE30, 0xFE4F, 65, "CJK Compatibility Forms" }, + { 0xFE50, 0xFE6F, 66, "Small Form Variants" }, + { 0xFE70, 0xFEFE, 67, "Arabic Presentation Forms-B" }, + { 0xFEFF, 0xFEFF, 69, "Specials" }, + { 0xFF00, 0xFFEF, 68, "Halfwidth and Fullwidth Forms" }, + { 0xFFF0, 0xFFFD, 69, "Specials" } +}; + +/* Return the Unicode Subset bitfield number for a Unicode character */ + +static int +unicode_classify (wchar_t wc) +{ + int min = 0; + int max = sizeof (utab) / sizeof (utab[0]) - 1; + int mid; + + while (max >= min) + { + mid = (min + max) / 2; + if (utab[mid].high < wc) + min = mid + 1; + else if (wc < utab[mid].low) + max = mid - 1; + else if (utab[mid].low <= wc && wc <= utab[mid].high) + return utab[mid].bit; + else + return -1; + } +} + +void +gdk_wchar_text_handle (GdkFont *font, + const wchar_t *wcstr, + int wclen, + void (*handler)(GdkWin32SingleFont *, + const wchar_t *, + int, + void *), + void *arg) +{ + GdkFontPrivate *private; + GdkWin32SingleFont *singlefont; + GSList *list; + int i, block; + const wchar_t *start, *end, *wcp; + + wcp = wcstr; + end = wcp + wclen; + private = (GdkFontPrivate *) font; + + g_assert (private->ref_count > 0); + + while (wcp < end) + { + /* Split Unicode string into pieces of the same class */ + start = wcp; + block = unicode_classify (*wcp); + while (wcp + 1 < end && unicode_classify (wcp[1]) == block) + wcp++; + + /* Find a font in the fontset that can handle this class */ + list = private->fonts; + while (list) + { + singlefont = (GdkWin32SingleFont *) list->data; + + if (singlefont->fs.fsUsb[block/32] & (1 << (block % 32))) + break; + + list = list->next; + } + + if (!list) + singlefont = NULL; + + /* Call the callback function */ + (*handler) (singlefont, start, wcp+1 - start, arg); + wcp++; + } +} + +typedef struct +{ + SIZE total; + SIZE max; +} gdk_text_size_arg; + +static void +gdk_text_size_handler (GdkWin32SingleFont *singlefont, + const wchar_t *wcstr, + int wclen, + void *argp) +{ + SIZE this_size; + HGDIOBJ oldfont; + gdk_text_size_arg *arg = (gdk_text_size_arg *) argp; + + if (!singlefont) + return; + + if ((oldfont = SelectObject (gdk_DC, singlefont->xfont)) == NULL) + { + g_warning ("gdk_text_size_handler: SelectObject failed"); + return; + } + GetTextExtentPoint32W (gdk_DC, wcstr, wclen, &this_size); + SelectObject (gdk_DC, oldfont); + + arg->total.cx += this_size.cx; + arg->total.cy += this_size.cy; + arg->max.cx = MAX (this_size.cx, arg->max.cx); + arg->max.cy = MAX (this_size.cy, arg->max.cy); +} + +static gboolean +gdk_text_size (GdkFont *font, + const gchar *text, + gint text_length, + gdk_text_size_arg *arg) +{ + gint wlen; + wchar_t *wcstr; + + g_return_val_if_fail (font != NULL, FALSE); + g_return_val_if_fail (text != NULL, FALSE); + + if (text_length == 0) + return 0; + + g_assert (font->type == GDK_FONT_FONT || font->type == GDK_FONT_FONTSET); + + wcstr = g_new (wchar_t, text_length); + if ((wlen = gdk_nmbstowchar_ts (wcstr, text, text_length, text_length)) == -1) + g_warning ("gdk_text_size: gdk_nmbstowchar_ts failed"); + else + gdk_wchar_text_handle (font, wcstr, wlen, gdk_text_size_handler, arg); + + g_free (wcstr); + + return TRUE; +} + +gint +gdk_text_width (GdkFont *font, + const gchar *text, + gint text_length) +{ + gdk_text_size_arg arg; + + arg.total.cx = arg.total.cy = 0; + arg.max.cx = arg.max.cy = 0; + + if (!gdk_text_size (font, text, text_length, &arg)) + return -1; + + return arg.total.cx; +} + +gint +gdk_text_width_wc (GdkFont *font, + const GdkWChar *text, + gint text_length) +{ + gdk_text_size_arg arg; + wchar_t *wcstr; + gint i; + + g_return_val_if_fail (font != NULL, -1); + g_return_val_if_fail (text != NULL, -1); + + if (text_length == 0) + return 0; + + g_assert (font->type == GDK_FONT_FONT || font->type == GDK_FONT_FONTSET); + + if (sizeof (wchar_t) != sizeof (GdkWChar)) + { + wcstr = g_new (wchar_t, text_length); + for (i = 0; i < text_length; i++) + wcstr[i] = text[i]; + } + else + wcstr = (wchar_t *) text; + + arg.total.cx = arg.total.cy = 0; + arg.max.cx = arg.max.cy = 0; + + gdk_wchar_text_handle (font, wcstr, text_length, + gdk_text_size_handler, &arg); + + if (sizeof (wchar_t) != sizeof (GdkWChar)) + g_free (wcstr); + + return arg.total.cx; +} + +gint +gdk_char_width (GdkFont *font, + gchar character) +{ + if (((guchar) character) >= 128) + { + /* gtktext calls us with non-ASCII characters, sigh */ + GdkWChar wc = (guchar) character; + return gdk_text_width_wc (font, &wc, 1); + } + return gdk_text_width (font, &character, 1); +} + +gint +gdk_char_width_wc (GdkFont *font, + GdkWChar character) +{ + return gdk_text_width_wc (font, &character, 1); +} + +gint +gdk_string_measure (GdkFont *font, + const gchar *string) +{ + g_return_val_if_fail (font != NULL, -1); + g_return_val_if_fail (string != NULL, -1); + + return gdk_text_measure (font, string, strlen (string)); +} + +void +gdk_text_extents (GdkFont *font, + const gchar *text, + gint text_length, + gint *lbearing, + gint *rbearing, + gint *width, + gint *ascent, + gint *descent) +{ + gdk_text_size_arg arg; + gint wlen; + wchar_t *wcstr; + + g_return_if_fail (font != NULL); + g_return_if_fail (text != NULL); + + if (text_length == 0) + { + if (lbearing) + *lbearing = 0; + if (rbearing) + *rbearing = 0; + if (width) + *width = 0; + if (ascent) + *ascent = 0; + if (descent) + *descent = 0; + return; + } + + g_assert (font->type == GDK_FONT_FONT || font->type == GDK_FONT_FONTSET); + + arg.total.cx = arg.total.cy = 0; + arg.max.cx = arg.max.cy = 0; + + wcstr = g_new (wchar_t, text_length); + if ((wlen = gdk_nmbstowchar_ts (wcstr, text, text_length, text_length)) == -1) + g_warning ("gdk_text_extents: gdk_nmbstowchar_ts failed"); + else + gdk_wchar_text_handle (font, wcstr, wlen, gdk_text_size_handler, &arg); + + g_free (wcstr); + + /* XXX This is quite bogus */ + if (lbearing) + *lbearing = 0; + if (rbearing) + *rbearing = 0; + if (width) + *width = arg.total.cx; + if (ascent) + *ascent = arg.max.cy + 1; + if (descent) + *descent = font->descent + 1; +} + +void +gdk_text_extents_wc (GdkFont *font, + const GdkWChar *text, + gint text_length, + gint *lbearing, + gint *rbearing, + gint *width, + gint *ascent, + gint *descent) +{ + gdk_text_size_arg arg; + wchar_t *wcstr; + gint i; + + g_return_if_fail (font != NULL); + g_return_if_fail (text != NULL); + + if (text_length == 0) + { + if (lbearing) + *lbearing = 0; + if (rbearing) + *rbearing = 0; + if (width) + *width = 0; + if (ascent) + *ascent = 0; + if (descent) + *descent = 0; + return; + } + + g_assert (font->type == GDK_FONT_FONT || font->type == GDK_FONT_FONTSET); + + if (sizeof (wchar_t) != sizeof (GdkWChar)) + { + wcstr = g_new (wchar_t, text_length); + for (i = 0; i < text_length; i++) + wcstr[i] = text[i]; + } + else + wcstr = (wchar_t *) text; + + arg.total.cx = arg.total.cy = 0; + arg.max.cx = arg.max.cy = 0; + + gdk_wchar_text_handle (font, wcstr, text_length, + gdk_text_size_handler, &arg); + + if (sizeof (wchar_t) != sizeof (GdkWChar)) + g_free (wcstr); + + /* XXX This is quite bogus */ + if (lbearing) + *lbearing = 0; + if (rbearing) + *rbearing = 0; + if (width) + *width = arg.total.cx; + if (ascent) + *ascent = arg.max.cy + 1; + if (descent) + *descent = font->descent + 1; +} + +void +gdk_string_extents (GdkFont *font, + const gchar *string, + gint *lbearing, + gint *rbearing, + gint *width, + gint *ascent, + gint *descent) +{ + g_return_if_fail (font != NULL); + g_return_if_fail (string != NULL); + + gdk_text_extents (font, string, strlen (string), + lbearing, rbearing, width, ascent, descent); +} + + +gint +gdk_text_measure (GdkFont *font, + const gchar *text, + gint text_length) +{ + return gdk_text_width (font, text, text_length); /* ??? */ +} + +gint +gdk_char_measure (GdkFont *font, + gchar character) +{ + return gdk_text_measure (font, &character, 1); +} + +gint +gdk_string_height (GdkFont *font, + const gchar *string) +{ + g_return_val_if_fail (font != NULL, -1); + g_return_val_if_fail (string != NULL, -1); + + return gdk_text_height (font, string, strlen (string)); +} + +gint +gdk_text_height (GdkFont *font, + const gchar *text, + gint text_length) +{ + gdk_text_size_arg arg; + + arg.total.cx = arg.total.cy = 0; + arg.max.cx = arg.max.cy = 0; + + if (!gdk_text_size (font, text, text_length, &arg)) + return -1; + + return arg.max.cy; +} + +gint +gdk_char_height (GdkFont *font, + gchar character) +{ + return gdk_text_height (font, &character, 1); +} diff --git a/gdk/win32/gdkfont.c b/gdk/win32/gdkfont.c new file mode 100644 index 000000000..3cee42da8 --- /dev/null +++ b/gdk/win32/gdkfont.c @@ -0,0 +1,1501 @@ +/* GDK - The GIMP Drawing Kit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* + * Modified by the GTK+ Team and others 1997-1999. See the AUTHORS + * file for a list of people on the GTK+ Team. See the ChangeLog + * files for a list of changes. These files are distributed with + * GTK+ at ftp://ftp.gtk.org/pub/gtk/. + */ + +#include "config.h" + +#include +#include + +#include "gdkfont.h" +#include "gdkx.h" + +static GHashTable *font_name_hash = NULL; +static GHashTable *fontset_name_hash = NULL; + +static void +gdk_font_hash_insert (GdkFontType type, + GdkFont *font, + const gchar *font_name) +{ + GdkFontPrivate *private = (GdkFontPrivate *) font; + GHashTable **hashp = (type == GDK_FONT_FONT) ? + &font_name_hash : &fontset_name_hash; + + if (!*hashp) + *hashp = g_hash_table_new (g_str_hash, g_str_equal); + + private->names = g_slist_prepend (private->names, g_strdup (font_name)); + g_hash_table_insert (*hashp, private->names->data, font); +} + +static void +gdk_font_hash_remove (GdkFontType type, + GdkFont *font) +{ + GdkFontPrivate *private = (GdkFontPrivate *) font; + GSList *tmp_list; + GHashTable *hash = (type == GDK_FONT_FONT) ? + font_name_hash : fontset_name_hash; + + tmp_list = private->names; + while (tmp_list) + { + g_hash_table_remove (hash, tmp_list->data); + g_free (tmp_list->data); + + tmp_list = tmp_list->next; + } + + g_slist_free (private->names); + private->names = NULL; +} + +static GdkFont * +gdk_font_hash_lookup (GdkFontType type, + const gchar *font_name) +{ + GdkFont *result; + GHashTable *hash = (type == GDK_FONT_FONT) ? + font_name_hash : fontset_name_hash; + + if (!hash) + return NULL; + else + { + result = g_hash_table_lookup (hash, font_name); + if (result) + gdk_font_ref (result); + + return result; + } +} + +static const char * +charset_name (DWORD charset) +{ + switch (charset) + { + case ANSI_CHARSET: return "ansi"; + case DEFAULT_CHARSET: return "default"; + case SYMBOL_CHARSET: return "symbol"; + case SHIFTJIS_CHARSET: return "shiftjis"; + case HANGEUL_CHARSET: return "hangeul"; + case GB2312_CHARSET: return "gb2312"; + case CHINESEBIG5_CHARSET: return "big5"; + case JOHAB_CHARSET: return "johab"; + case HEBREW_CHARSET: return "hebrew"; + case ARABIC_CHARSET: return "arabic"; + case GREEK_CHARSET: return "greek"; + case TURKISH_CHARSET: return "turkish"; + case VIETNAMESE_CHARSET: return "vietnamese"; + case THAI_CHARSET: return "thai"; + case EASTEUROPE_CHARSET: return "easteurope"; + case RUSSIAN_CHARSET: return "russian"; + case MAC_CHARSET: return "mac"; + case BALTIC_CHARSET: return "baltic"; + } + return "unknown"; +} + +static gint num_fonts; +static gint font_names_size; +static gchar **xfontnames; + +static gchar * +logfont_to_xlfd (const LOGFONT *lfp, + int size, + int res, + int avg_width) +{ + const gchar *weight; + const gchar *registry, *encoding; + int point_size; + static int logpixelsy = 0; + gchar facename[LF_FACESIZE*3]; + gchar *p; + const gchar *q; + + if (logpixelsy == 0) + { + logpixelsy = GetDeviceCaps (gdk_DC, LOGPIXELSY); + } + + if (lfp->lfWeight >= FW_HEAVY) + weight = "heavy"; + else if (lfp->lfWeight >= FW_EXTRABOLD) + weight = "extrabold"; + else if (lfp->lfWeight >= FW_BOLD) + weight = "bold"; +#ifdef FW_DEMIBOLD + else if (lfp->lfWeight >= FW_DEMIBOLD) + weight = "demibold"; +#endif + else if (lfp->lfWeight >= FW_MEDIUM) + weight = "medium"; + else if (lfp->lfWeight >= FW_NORMAL) + weight = "normal"; + else if (lfp->lfWeight >= FW_LIGHT) + weight = "light"; + else if (lfp->lfWeight >= FW_EXTRALIGHT) + weight = "extralight"; + else if (lfp->lfWeight >= FW_THIN) + weight = "thin"; + else + weight = "regular"; + + switch (lfp->lfCharSet) + { + case ANSI_CHARSET: + registry = "iso8859"; + encoding = "1"; + break; + case SHIFTJIS_CHARSET: + registry = "jisx0208.1983"; + encoding = "0"; + break; + case HANGEUL_CHARSET: + registry = "ksc5601.1987"; + encoding = "0"; + break; + case GB2312_CHARSET: + registry = "gb2312.1980"; + encoding = "0"; + break; + case CHINESEBIG5_CHARSET: + registry = "big5"; + encoding = "0"; + break; + case GREEK_CHARSET: + registry = "iso8859"; + encoding = "7"; + break; + case TURKISH_CHARSET: + registry = "iso8859"; + encoding = "9"; + break; +#if 0 /* Not a good idea, I think, to use ISO8859-8 and -6 for the Windows + * hebrew and arabic codepages, they differ too much. + */ + case HEBREW_CHARSET: + registry = "iso8859"; + encoding = "8"; + break; + case ARABIC_CHARSET: + registry = "iso8859"; + encoding = "6"; + break; +#endif + default: + registry = "microsoft"; + encoding = charset_name (lfp->lfCharSet); + } + + point_size = (int) (((double) size/logpixelsy) * 720.); + + if (res == -1) + res = logpixelsy; + + /* Replace illegal characters with hex escapes. */ + p = facename; + q = lfp->lfFaceName; + while (*q) + { + if (*q == '-' || *q == '*' || *q == '?' || *q == '%') + p += sprintf (p, "%%%.02x", *q); + else + *p++ = *q; + q++; + } + *p = '\0'; + + return g_strdup_printf + ("-%s-%s-%s-%s-%s-%s-%d-%d-%d-%d-%s-%d-%s-%s", + "unknown", + facename, + weight, + (lfp->lfItalic ? + ((lfp->lfPitchAndFamily & 0xF0) == FF_ROMAN + || (lfp->lfPitchAndFamily & 0xF0) == FF_SCRIPT ? + "i" : "o") : "r"), + "normal", + "", + size, + point_size, + res, + res, + ((lfp->lfPitchAndFamily & 0x03) == FIXED_PITCH ? "m" : "p"), + avg_width, + registry, encoding); +} + +gchar * +gdk_font_xlfd_create (GdkFont *font) +{ + GdkFontPrivate *private; + GdkWin32SingleFont *singlefont; + GSList *list; + GString *string; + gchar *result; + LOGFONT logfont; + + g_return_val_if_fail (font != NULL, NULL); + + private = (GdkFontPrivate *) font; + + list = private->fonts; + string = g_string_new (""); + + while (list) + { + singlefont = (GdkWin32SingleFont *) list->data; + + if (GetObject (singlefont->xfont, sizeof (LOGFONT), &logfont) == 0) + { + g_warning ("gdk_win32_font_xlfd: GetObject failed"); + return NULL; + } + + string = + g_string_append (string, + logfont_to_xlfd (&logfont, logfont.lfHeight, -1, 0)); + list = list->next; + if (list) + string = g_string_append_c (string, ','); + } + result = string->str; + g_string_free (string, FALSE); + return result; +} + +void +gdk_font_xlfd_free (gchar *xlfd) +{ + g_free (xlfd); +} + +static gboolean +pattern_match (const gchar *pattern, + const gchar *string) +{ + const gchar *p = pattern, *n = string; + gchar c, c1; + + /* Common case first */ + if ((pattern[0] == '*' + && pattern[1] == '\0') + || (pattern[0] == '-' + && pattern[1] == '*' + && pattern[2] == '\0')) + return TRUE; + + while ((c = *p++) != '\0') + { + c = tolower (c); + + switch (c) + { + case '?': + if (*n == '\0') + return FALSE; + break; + + case '*': + for (c = *p++; c == '?' || c == '*'; c = *p++, ++n) + if (c == '?' && *n == '\0') + return FALSE; + + if (c == '\0') + return TRUE; + + c1 = tolower (c); + for (--p; *n != '\0'; ++n) + if (tolower (*n) == c1 + && pattern_match (p, n)) + return TRUE; + return FALSE; + + default: + if (c != tolower (*n)) + return FALSE; + } + + ++n; + } + + if (*n == '\0') + return TRUE; + + return FALSE; +} + +int CALLBACK +InnerEnumFontFamExProc (const LOGFONT *lfp, + const TEXTMETRIC *metrics, + DWORD fontType, + LPARAM lParam) +{ + int size; + gchar *xlfd; + + if (fontType == TRUETYPE_FONTTYPE) + { + size = 0; + } + else + { + size = lfp->lfHeight; + } + + xlfd = logfont_to_xlfd (lfp, size, 0, 0); + + if (!pattern_match ((gchar *) lParam, xlfd)) + { + g_free (xlfd); + return 1; + } + + num_fonts++; + if (num_fonts == font_names_size) + { + font_names_size *= 2; + xfontnames = g_realloc (xfontnames, font_names_size * sizeof (gchar *)); + } + xfontnames[num_fonts-1] = xlfd; + + return 1; +} + +int CALLBACK +EnumFontFamExProc (const LOGFONT *lfp, + const TEXTMETRIC *metrics, + DWORD fontType, + LPARAM lParam) +{ + if (fontType == TRUETYPE_FONTTYPE) + { + LOGFONT lf; + + lf = *lfp; + + EnumFontFamiliesEx (gdk_DC, &lf, InnerEnumFontFamExProc, lParam, 0); + } + else + InnerEnumFontFamExProc (lfp, metrics, fontType, lParam); + + return 1; +} + +gchar ** +gdk_font_list_new (const gchar *font_pattern, + gint *n_returned) +{ + LOGFONT logfont; + gchar **result; + + num_fonts = 0; + font_names_size = 100; + xfontnames = g_new (gchar *, font_names_size); + memset (&logfont, 0, sizeof (logfont)); + logfont.lfCharSet = DEFAULT_CHARSET; + EnumFontFamiliesEx (gdk_DC, &logfont, EnumFontFamExProc, + (LPARAM) font_pattern, 0); + + result = g_new (gchar *, num_fonts + 1); + memmove (result, xfontnames, num_fonts * sizeof (gchar *)); + result[num_fonts] = NULL; + g_free (xfontnames); + + *n_returned = num_fonts; + return result; +} + +void +gdk_font_list_free (gchar **font_list) +{ + g_strfreev (font_list); +} + +GdkWin32SingleFont* +gdk_font_load_internal (const gchar *font_name) +{ + GdkWin32SingleFont *singlefont; + HFONT hfont; + LOGFONT logfont; + CHARSETINFO csi; + DWORD fdwItalic, fdwUnderline, fdwStrikeOut, fdwCharSet, + fdwOutputPrecision, fdwClipPrecision, fdwQuality, fdwPitchAndFamily; + const char *lpszFace; + + int numfields, n1, n2, tries; + char foundry[32], family[100], weight[32], slant[32], set_width[32], + spacing[32], registry[32], encoding[32]; + char pixel_size[10], point_size[10], res_x[10], res_y[10], avg_width[10]; + int c; + char *p; + int nHeight, nWidth, nEscapement, nOrientation, fnWeight; + int logpixelsy; + + g_return_val_if_fail (font_name != NULL, NULL); + + GDK_NOTE (MISC, g_print ("gdk_font_load_internal: %s\n", font_name)); + + numfields = sscanf (font_name, + "-%30[^-]-%100[^-]-%30[^-]-%30[^-]-%30[^-]-%n", + foundry, + family, + weight, + slant, + set_width, + &n1); + if (numfields == 0) + { + /* Probably a plain Windows font name */ + nHeight = 0; + nWidth = 0; + nEscapement = 0; + nOrientation = 0; + fnWeight = FW_DONTCARE; + fdwItalic = FALSE; + fdwUnderline = FALSE; + fdwStrikeOut = FALSE; + fdwCharSet = ANSI_CHARSET; + fdwOutputPrecision = OUT_TT_PRECIS; + fdwClipPrecision = CLIP_DEFAULT_PRECIS; + fdwQuality = PROOF_QUALITY; + fdwPitchAndFamily = DEFAULT_PITCH; + lpszFace = font_name; + } + else if (numfields != 5) + { + g_warning ("gdk_font_load: font name %s illegal", font_name); + return NULL; + } + else + { + /* It must be a XLFD name */ + + /* Check for hex escapes in the font family, + * put in there by gtkfontsel. + */ + p = family; + while (*p) + { + if (*p == '%' && isxdigit (p[1]) && isxdigit (p[2])) + { + sscanf (p+1, "%2x", &c); + *p = c; + strcpy (p+1, p+3); + } + p++; + } + + /* Skip add_style which often is empty in the requested font name */ + while (font_name[n1] && font_name[n1] != '-') + n1++; + numfields++; + + numfields += sscanf (font_name + n1, + "-%8[^-]-%8[^-]-%8[^-]-%8[^-]-%30[^-]-%8[^-]-%30[^-]-%30[^-]%n", + pixel_size, + point_size, + res_x, + res_y, + spacing, + avg_width, + registry, + encoding, + &n2); + + if (numfields != 14 || font_name[n1 + n2] != '\0') + { + g_warning ("gdk_font_load: font name %s illegal", font_name); + return NULL; + } + + logpixelsy = GetDeviceCaps (gdk_DC, LOGPIXELSY); + + if (strcmp (pixel_size, "*") == 0) + if (strcmp (point_size, "*") == 0) + nHeight = 0; + else + nHeight = (int) (((double) atoi (point_size))/720.*logpixelsy); + else + nHeight = atoi (pixel_size); + + nWidth = 0; + nEscapement = 0; + nOrientation = 0; + + if (g_strcasecmp (weight, "thin") == 0) + fnWeight = FW_THIN; + else if (g_strcasecmp (weight, "extralight") == 0) + fnWeight = FW_EXTRALIGHT; + else if (g_strcasecmp (weight, "ultralight") == 0) +#ifdef FW_ULTRALIGHT + fnWeight = FW_ULTRALIGHT; +#else + fnWeight = FW_EXTRALIGHT; /* In fact, FW_ULTRALIGHT really is + * defined as FW_EXTRALIGHT anyway. + */ +#endif + else if (g_strcasecmp (weight, "light") == 0) + fnWeight = FW_LIGHT; + else if (g_strcasecmp (weight, "normal") == 0) + fnWeight = FW_NORMAL; + else if (g_strcasecmp (weight, "regular") == 0) + fnWeight = FW_REGULAR; + else if (g_strcasecmp (weight, "medium") == 0) + fnWeight = FW_MEDIUM; + else if (g_strcasecmp (weight, "semibold") == 0) + fnWeight = FW_SEMIBOLD; + else if (g_strcasecmp (weight, "demibold") == 0) +#ifdef FW_DEMIBOLD + fnWeight = FW_DEMIBOLD; +#else + fnWeight = FW_SEMIBOLD; /* As above */ +#endif + else if (g_strcasecmp (weight, "bold") == 0) + fnWeight = FW_BOLD; + else if (g_strcasecmp (weight, "extrabold") == 0) + fnWeight = FW_EXTRABOLD; + else if (g_strcasecmp (weight, "ultrabold") == 0) +#ifdef FW_ULTRABOLD + fnWeight = FW_ULTRABOLD; +#else + fnWeight = FW_EXTRABOLD; /* As above */ +#endif + else if (g_strcasecmp (weight, "heavy") == 0) + fnWeight = FW_HEAVY; + else if (g_strcasecmp (weight, "black") == 0) +#ifdef FW_BLACK + fnWeight = FW_BLACK; +#else + fnWeight = FW_HEAVY; /* As above */ +#endif + else + fnWeight = FW_DONTCARE; + + if (g_strcasecmp (slant, "italic") == 0 + || g_strcasecmp (slant, "oblique") == 0 + || g_strcasecmp (slant, "i") == 0 + || g_strcasecmp (slant, "o") == 0) + fdwItalic = TRUE; + else + fdwItalic = FALSE; + fdwUnderline = FALSE; + fdwStrikeOut = FALSE; + if (g_strcasecmp (registry, "iso8859") == 0) + if (strcmp (encoding, "1") == 0) + fdwCharSet = ANSI_CHARSET; + else if (strcmp (encoding, "2") == 0) + fdwCharSet = EASTEUROPE_CHARSET; + else if (strcmp (encoding, "7") == 0) + fdwCharSet = GREEK_CHARSET; + else if (strcmp (encoding, "8") == 0) + fdwCharSet = HEBREW_CHARSET; + else if (strcmp (encoding, "9") == 0) + fdwCharSet = TURKISH_CHARSET; + else + fdwCharSet = ANSI_CHARSET; /* XXX ??? */ + else if (g_strcasecmp (registry, "jisx0208.1983") == 0) + fdwCharSet = SHIFTJIS_CHARSET; + else if (g_strcasecmp (registry, "ksc5601.1987") == 0) + fdwCharSet = HANGEUL_CHARSET; + else if (g_strcasecmp (registry, "gb2312.1980") == 0) + fdwCharSet = GB2312_CHARSET; + else if (g_strcasecmp (registry, "big5") == 0) + fdwCharSet = CHINESEBIG5_CHARSET; + else if (g_strcasecmp (registry, "windows") == 0 + || g_strcasecmp (registry, "microsoft") == 0) + if (g_strcasecmp (encoding, "symbol") == 0) + fdwCharSet = SYMBOL_CHARSET; + else if (g_strcasecmp (encoding, "shiftjis") == 0) + fdwCharSet = SHIFTJIS_CHARSET; + else if (g_strcasecmp (encoding, "gb2312") == 0) + fdwCharSet = GB2312_CHARSET; + else if (g_strcasecmp (encoding, "hangeul") == 0) + fdwCharSet = HANGEUL_CHARSET; + else if (g_strcasecmp (encoding, "big5") == 0) + fdwCharSet = CHINESEBIG5_CHARSET; + else if (g_strcasecmp (encoding, "johab") == 0) + fdwCharSet = JOHAB_CHARSET; + else if (g_strcasecmp (encoding, "hebrew") == 0) + fdwCharSet = HEBREW_CHARSET; + else if (g_strcasecmp (encoding, "arabic") == 0) + fdwCharSet = ARABIC_CHARSET; + else if (g_strcasecmp (encoding, "greek") == 0) + fdwCharSet = GREEK_CHARSET; + else if (g_strcasecmp (encoding, "turkish") == 0) + fdwCharSet = TURKISH_CHARSET; + else if (g_strcasecmp (encoding, "easteurope") == 0) + fdwCharSet = EASTEUROPE_CHARSET; + else if (g_strcasecmp (encoding, "russian") == 0) + fdwCharSet = RUSSIAN_CHARSET; + else if (g_strcasecmp (encoding, "mac") == 0) + fdwCharSet = MAC_CHARSET; + else if (g_strcasecmp (encoding, "baltic") == 0) + fdwCharSet = BALTIC_CHARSET; + else if (g_strcasecmp (encoding, "cp1251") == 0) + fdwCharSet = RUSSIAN_CHARSET; + else + fdwCharSet = ANSI_CHARSET; /* XXX ??? */ + else + fdwCharSet = ANSI_CHARSET; /* XXX ??? */ + fdwOutputPrecision = OUT_TT_PRECIS; + fdwClipPrecision = CLIP_DEFAULT_PRECIS; + fdwQuality = PROOF_QUALITY; + if (g_strcasecmp (spacing, "m") == 0) + fdwPitchAndFamily = FIXED_PITCH; + else if (g_strcasecmp (spacing, "p") == 0) + fdwPitchAndFamily = VARIABLE_PITCH; + else + fdwPitchAndFamily = DEFAULT_PITCH; + lpszFace = family; + } + + for (tries = 0; ; tries++) + { + GDK_NOTE (MISC, g_print ("...trying CreateFont(%d,%d,%d,%d," + "%d,%d,%d,%d," + "%d,%d,%d," + "%d,%#.02x,\"%s\")\n", + nHeight, nWidth, nEscapement, nOrientation, + fnWeight, fdwItalic, fdwUnderline, fdwStrikeOut, + fdwCharSet, fdwOutputPrecision, fdwClipPrecision, + fdwQuality, fdwPitchAndFamily, lpszFace)); + if ((hfont = + CreateFont (nHeight, nWidth, nEscapement, nOrientation, + fnWeight, fdwItalic, fdwUnderline, fdwStrikeOut, + fdwCharSet, fdwOutputPrecision, fdwClipPrecision, + fdwQuality, fdwPitchAndFamily, lpszFace)) != NULL) + break; + + /* If we fail, try some similar fonts often found on Windows. */ + + if (tries == 0) + { + if (g_strcasecmp (family, "helvetica") == 0) + lpszFace = "arial"; + else if (g_strcasecmp (family, "new century schoolbook") == 0) + lpszFace = "century schoolbook"; + else if (g_strcasecmp (family, "courier") == 0) + lpszFace = "courier new"; + else if (g_strcasecmp (family, "lucida") == 0) + lpszFace = "lucida sans unicode"; + else if (g_strcasecmp (family, "lucidatypewriter") == 0) + lpszFace = "lucida console"; + else if (g_strcasecmp (family, "times") == 0) + lpszFace = "times new roman"; + } + else if (tries == 1) + { + if (g_strcasecmp (family, "courier") == 0) + { + lpszFace = ""; + fdwPitchAndFamily |= FF_MODERN; + } + else if (g_strcasecmp (family, "times new roman") == 0) + { + lpszFace = ""; + fdwPitchAndFamily |= FF_ROMAN; + } + else if (g_strcasecmp (family, "helvetica") == 0 + || g_strcasecmp (family, "lucida") == 0) + { + lpszFace = ""; + fdwPitchAndFamily |= FF_SWISS; + } + else + { + lpszFace = ""; + fdwPitchAndFamily = (fdwPitchAndFamily & 0x0F) | FF_DONTCARE; + } + } + else + break; + tries++; + } + + if (!hfont) + return NULL; + + singlefont = g_new (GdkWin32SingleFont, 1); + singlefont->xfont = hfont; + GetObject (singlefont->xfont, sizeof (logfont), &logfont); + TranslateCharsetInfo ((DWORD *) singlefont->charset, &csi, TCI_SRCCHARSET); + singlefont->codepage = csi.ciACP; + GetCPInfo (singlefont->codepage, &singlefont->cpinfo); + + return singlefont; +} + +GdkFont* +gdk_font_load (const gchar *font_name) +{ + GdkFont *font; + GdkFontPrivate *private; + GdkWin32SingleFont *singlefont; + HGDIOBJ oldfont; + HANDLE *f; + TEXTMETRIC textmetric; + + g_return_val_if_fail (font_name != NULL, NULL); + + font = gdk_font_hash_lookup (GDK_FONT_FONTSET, font_name); + if (font) + return font; + + singlefont = gdk_font_load_internal (font_name); + + private = g_new (GdkFontPrivate, 1); + font = (GdkFont*) private; + + private->ref_count = 1; + private->names = NULL; + private->fonts = g_slist_append (NULL, singlefont); + + /* Pretend all fonts are fontsets... Gtktext and gtkentry work better + * that way, they use wide chars, which is necessary for non-ASCII + * chars to work. (Yes, even Latin-1, as we use Unicode internally.) + */ + font->type = GDK_FONT_FONTSET; + oldfont = SelectObject (gdk_DC, singlefont->xfont); + GetTextMetrics (gdk_DC, &textmetric); + singlefont->charset = GetTextCharsetInfo (gdk_DC, &singlefont->fs, 0); + SelectObject (gdk_DC, oldfont); + font->ascent = textmetric.tmAscent; + font->descent = textmetric.tmDescent; + + GDK_NOTE (MISC, g_print ("... = %#x charset %s codepage %d " + "asc %d desc %d\n", + singlefont->xfont, + charset_name (singlefont->charset), + singlefont->codepage, + font->ascent, font->descent)); + + gdk_font_hash_insert (GDK_FONT_FONTSET, font, font_name); + + return font; +} + +GdkFont* +gdk_fontset_load (gchar *fontset_name) +{ + GdkFont *font; + GdkFontPrivate *private; + GdkWin32SingleFont *singlefont; + HGDIOBJ oldfont; + HANDLE *f; + TEXTMETRIC textmetric; + GSList *base_font_list = NULL; + gchar *fs; + gchar *b, *p, *s; + + g_return_val_if_fail (fontset_name != NULL, NULL); + + font = gdk_font_hash_lookup (GDK_FONT_FONTSET, fontset_name); + if (font) + return font; + + s = fs = g_strdup (fontset_name); + while (*s && isspace (*s)) + s++; + + g_return_val_if_fail (*s, NULL); + + private = g_new (GdkFontPrivate, 1); + font = (GdkFont*) private; + + private->ref_count = 1; + private->names = NULL; + private->fonts = NULL; + + font->type = GDK_FONT_FONTSET; + font->ascent = 0; + font->descent = 0; + + while (TRUE) + { + if ((p = strchr (s, ',')) != NULL) + b = p; + else + b = s + strlen (s); + + while (isspace (b[-1])) + b--; + *b = '\0'; + singlefont = gdk_font_load_internal (s); + if (singlefont) + { + GDK_NOTE + (MISC, g_print ("... = %#x charset %s codepage %d\n", + singlefont->xfont, + charset_name (singlefont->charset), + singlefont->codepage)); + private->fonts = g_slist_append (private->fonts, singlefont); + oldfont = SelectObject (gdk_DC, singlefont->xfont); + GetTextMetrics (gdk_DC, &textmetric); + singlefont->charset = + GetTextCharsetInfo (gdk_DC, &singlefont->fs, 0); + SelectObject (gdk_DC, oldfont); + font->ascent = MAX (font->ascent, textmetric.tmAscent); + font->descent = MAX (font->descent, textmetric.tmDescent); + } + if (p) + { + s = p + 1; + while (*s && isspace (*s)) + s++; + } + else + break; + if (!*s) + break; + } + + g_free (fs); + + gdk_font_hash_insert (GDK_FONT_FONTSET, font, fontset_name); + + return font; +} + +GdkFont* +gdk_font_ref (GdkFont *font) +{ + GdkFontPrivate *private; + + g_return_val_if_fail (font != NULL, NULL); + + private = (GdkFontPrivate*) font; + private->ref_count += 1; + + GDK_NOTE (MISC, + g_print ("gdk_font_ref %#x %d\n", + ((GdkWin32SingleFont *) private->fonts->data)->xfont, + private->ref_count)); + return font; +} + +void +gdk_font_unref (GdkFont *font) +{ + GdkFontPrivate *private; + GdkWin32SingleFont *singlefont; + GSList *list; + private = (GdkFontPrivate*) font; + + g_return_if_fail (font != NULL); + g_return_if_fail (private->ref_count > 0); + + private->ref_count -= 1; + + singlefont = (GdkWin32SingleFont *) private->fonts->data; + GDK_NOTE (MISC, g_print ("gdk_font_unref %#x %d%s\n", + singlefont->xfont, private->ref_count, + (private->ref_count == 0 ? " freeing" : ""))); + + if (private->ref_count == 0) + { + gdk_font_hash_remove (font->type, font); + + switch (font->type) + { + case GDK_FONT_FONT: + DeleteObject (singlefont->xfont); + break; + + case GDK_FONT_FONTSET: + list = private->fonts; + while (list) + { + singlefont = (GdkWin32SingleFont *) list->data; + DeleteObject (singlefont->xfont); + + list = list->next; + } + g_slist_free (private->fonts); + break; + + default: + g_assert_not_reached (); + } + g_free (font); + } +} + +gint +gdk_font_id (const GdkFont *font) +{ + const GdkFontPrivate *font_private; + + g_return_val_if_fail (font != NULL, 0); + + font_private = (const GdkFontPrivate*) font; + + if (font->type == GDK_FONT_FONT) + return (gint) ((GdkWin32SingleFont *) font_private->fonts->data)->xfont; + else + return 0; +} + +gint +gdk_font_equal (const GdkFont *fonta, + const GdkFont *fontb) +{ + const GdkFontPrivate *privatea; + const GdkFontPrivate *privateb; + + g_return_val_if_fail (fonta != NULL, FALSE); + g_return_val_if_fail (fontb != NULL, FALSE); + + privatea = (const GdkFontPrivate*) fonta; + privateb = (const GdkFontPrivate*) fontb; + + if (fonta->type == GDK_FONT_FONT && fontb->type == GDK_FONT_FONT) + return (((GdkWin32SingleFont *) privatea->fonts->data)->xfont + == ((GdkWin32SingleFont *) privateb->fonts->data)->xfont); + else if (fonta->type == GDK_FONT_FONTSET && fontb->type == GDK_FONT_FONTSET) + { + GSList *lista = privatea->fonts; + GSList *listb = privateb->fonts; + + while (lista && listb) + { + if (((GdkWin32SingleFont *) lista->data)->xfont + != ((GdkWin32SingleFont *) listb->data)->xfont) + return 0; + lista = lista->next; + listb = listb->next; + } + if (lista || listb) + return 0; + else + return 1; + } + else + return 0; +} + +gint +gdk_string_width (GdkFont *font, + const gchar *string) +{ + return gdk_text_width (font, string, strlen (string)); +} + +/* This table classifies Unicode characters according to the Microsoft + * Unicode subset numbering. This is from the table in "Developing + * International Software for Windows 95 and Windows NT". This is almost, + * but not quite, the same as the official Unicode block table in + * Blocks.txt from ftp.unicode.org. The bit number field is the bitfield + * number as in the FONTSIGNATURE struct's fsUsb field. + */ +static struct { + wchar_t low, high; + guint bit; + gchar *name; +} utab[] = +{ + { 0x0000, 0x007E, 0, "Basic Latin" }, + { 0x00A0, 0x00FF, 1, "Latin-1 Supplement" }, + { 0x0100, 0x017F, 2, "Latin Extended-A" }, + { 0x0180, 0x024F, 3, "Latin Extended-B" }, + { 0x0250, 0x02AF, 4, "IPA Extensions" }, + { 0x02B0, 0x02FF, 5, "Spacing Modifier Letters" }, + { 0x0300, 0x036F, 6, "Combining Diacritical Marks" }, + { 0x0370, 0x03CF, 7, "Basic Greek" }, + { 0x03D0, 0x03FF, 8, "Greek Symbols and Coptic" }, + { 0x0400, 0x04FF, 9, "Cyrillic" }, + { 0x0530, 0x058F, 10, "Armenian" }, + { 0x0590, 0x05CF, 12, "Hebrew Extended" }, + { 0x05D0, 0x05FF, 11, "Basic Hebrew" }, + { 0x0600, 0x0652, 13, "Basic Arabic" }, + { 0x0653, 0x06FF, 14, "Arabic Extended" }, + { 0x0900, 0x097F, 15, "Devanagari" }, + { 0x0980, 0x09FF, 16, "Bengali" }, + { 0x0A00, 0x0A7F, 17, "Gurmukhi" }, + { 0x0A80, 0x0AFF, 18, "Gujarati" }, + { 0x0B00, 0x0B7F, 19, "Oriya" }, + { 0x0B80, 0x0BFF, 20, "Tamil" }, + { 0x0C00, 0x0C7F, 21, "Telugu" }, + { 0x0C80, 0x0CFF, 22, "Kannada" }, + { 0x0D00, 0x0D7F, 23, "Malayalam" }, + { 0x0E00, 0x0E7F, 24, "Thai" }, + { 0x0E80, 0x0EFF, 25, "Lao" }, + { 0x10A0, 0x10CF, 27, "Georgian Extended" }, + { 0x10D0, 0x10FF, 26, "Basic Georgian" }, + { 0x1100, 0x11FF, 28, "Hangul Jamo" }, + { 0x1E00, 0x1EFF, 29, "Latin Extended Additional" }, + { 0x1F00, 0x1FFF, 30, "Greek Extended" }, + { 0x2000, 0x206F, 31, "General Punctuation" }, + { 0x2070, 0x209F, 32, "Superscripts and Subscripts" }, + { 0x20A0, 0x20CF, 33, "Currency Symbols" }, + { 0x20D0, 0x20FF, 34, "Combining Diacritical Marks for Symbols" }, + { 0x2100, 0x214F, 35, "Letterlike Symbols" }, + { 0x2150, 0x218F, 36, "Number Forms" }, + { 0x2190, 0x21FF, 37, "Arrows" }, + { 0x2200, 0x22FF, 38, "Mathematical Operators" }, + { 0x2300, 0x23FF, 39, "Miscellaneous Technical" }, + { 0x2400, 0x243F, 40, "Control Pictures" }, + { 0x2440, 0x245F, 41, "Optical Character Recognition" }, + { 0x2460, 0x24FF, 42, "Enclosed Alphanumerics" }, + { 0x2500, 0x257F, 43, "Box Drawing" }, + { 0x2580, 0x259F, 44, "Block Elements" }, + { 0x25A0, 0x25FF, 45, "Geometric Shapes" }, + { 0x2600, 0x26FF, 46, "Miscellaneous Symbols" }, + { 0x2700, 0x27BF, 47, "Dingbats" }, + { 0x3000, 0x303F, 48, "CJK Symbols and Punctuation" }, + { 0x3040, 0x309F, 49, "Hiragana" }, + { 0x30A0, 0x30FF, 50, "Katakana" }, + { 0x3100, 0x312F, 51, "Bopomofo" }, + { 0x3130, 0x318F, 52, "Hangul Compatibility Jamo" }, + { 0x3190, 0x319F, 53, "CJK Miscellaneous" }, + { 0x3200, 0x32FF, 54, "Enclosed CJK" }, + { 0x3300, 0x33FF, 55, "CJK Compatibility" }, + { 0x3400, 0x3D2D, 56, "Hangul" }, + { 0x3D2E, 0x44B7, 57, "Hangul Supplementary-A" }, + { 0x44B8, 0x4DFF, 58, "Hangul Supplementary-B" }, + { 0x4E00, 0x9FFF, 59, "CJK Unified Ideographs" }, + { 0xE000, 0xF8FF, 60, "Private Use Area" }, + { 0xF900, 0xFAFF, 61, "CJK Compatibility Ideographs" }, + { 0xFB00, 0xFB4F, 62, "Alphabetic Presentation Forms" }, + { 0xFB50, 0xFDFF, 63, "Arabic Presentation Forms-A" }, + { 0xFE20, 0xFE2F, 64, "Combining Half Marks" }, + { 0xFE30, 0xFE4F, 65, "CJK Compatibility Forms" }, + { 0xFE50, 0xFE6F, 66, "Small Form Variants" }, + { 0xFE70, 0xFEFE, 67, "Arabic Presentation Forms-B" }, + { 0xFEFF, 0xFEFF, 69, "Specials" }, + { 0xFF00, 0xFFEF, 68, "Halfwidth and Fullwidth Forms" }, + { 0xFFF0, 0xFFFD, 69, "Specials" } +}; + +/* Return the Unicode Subset bitfield number for a Unicode character */ + +static int +unicode_classify (wchar_t wc) +{ + int min = 0; + int max = sizeof (utab) / sizeof (utab[0]) - 1; + int mid; + + while (max >= min) + { + mid = (min + max) / 2; + if (utab[mid].high < wc) + min = mid + 1; + else if (wc < utab[mid].low) + max = mid - 1; + else if (utab[mid].low <= wc && wc <= utab[mid].high) + return utab[mid].bit; + else + return -1; + } +} + +void +gdk_wchar_text_handle (GdkFont *font, + const wchar_t *wcstr, + int wclen, + void (*handler)(GdkWin32SingleFont *, + const wchar_t *, + int, + void *), + void *arg) +{ + GdkFontPrivate *private; + GdkWin32SingleFont *singlefont; + GSList *list; + int i, block; + const wchar_t *start, *end, *wcp; + + wcp = wcstr; + end = wcp + wclen; + private = (GdkFontPrivate *) font; + + g_assert (private->ref_count > 0); + + while (wcp < end) + { + /* Split Unicode string into pieces of the same class */ + start = wcp; + block = unicode_classify (*wcp); + while (wcp + 1 < end && unicode_classify (wcp[1]) == block) + wcp++; + + /* Find a font in the fontset that can handle this class */ + list = private->fonts; + while (list) + { + singlefont = (GdkWin32SingleFont *) list->data; + + if (singlefont->fs.fsUsb[block/32] & (1 << (block % 32))) + break; + + list = list->next; + } + + if (!list) + singlefont = NULL; + + /* Call the callback function */ + (*handler) (singlefont, start, wcp+1 - start, arg); + wcp++; + } +} + +typedef struct +{ + SIZE total; + SIZE max; +} gdk_text_size_arg; + +static void +gdk_text_size_handler (GdkWin32SingleFont *singlefont, + const wchar_t *wcstr, + int wclen, + void *argp) +{ + SIZE this_size; + HGDIOBJ oldfont; + gdk_text_size_arg *arg = (gdk_text_size_arg *) argp; + + if (!singlefont) + return; + + if ((oldfont = SelectObject (gdk_DC, singlefont->xfont)) == NULL) + { + g_warning ("gdk_text_size_handler: SelectObject failed"); + return; + } + GetTextExtentPoint32W (gdk_DC, wcstr, wclen, &this_size); + SelectObject (gdk_DC, oldfont); + + arg->total.cx += this_size.cx; + arg->total.cy += this_size.cy; + arg->max.cx = MAX (this_size.cx, arg->max.cx); + arg->max.cy = MAX (this_size.cy, arg->max.cy); +} + +static gboolean +gdk_text_size (GdkFont *font, + const gchar *text, + gint text_length, + gdk_text_size_arg *arg) +{ + gint wlen; + wchar_t *wcstr; + + g_return_val_if_fail (font != NULL, FALSE); + g_return_val_if_fail (text != NULL, FALSE); + + if (text_length == 0) + return 0; + + g_assert (font->type == GDK_FONT_FONT || font->type == GDK_FONT_FONTSET); + + wcstr = g_new (wchar_t, text_length); + if ((wlen = gdk_nmbstowchar_ts (wcstr, text, text_length, text_length)) == -1) + g_warning ("gdk_text_size: gdk_nmbstowchar_ts failed"); + else + gdk_wchar_text_handle (font, wcstr, wlen, gdk_text_size_handler, arg); + + g_free (wcstr); + + return TRUE; +} + +gint +gdk_text_width (GdkFont *font, + const gchar *text, + gint text_length) +{ + gdk_text_size_arg arg; + + arg.total.cx = arg.total.cy = 0; + arg.max.cx = arg.max.cy = 0; + + if (!gdk_text_size (font, text, text_length, &arg)) + return -1; + + return arg.total.cx; +} + +gint +gdk_text_width_wc (GdkFont *font, + const GdkWChar *text, + gint text_length) +{ + gdk_text_size_arg arg; + wchar_t *wcstr; + gint i; + + g_return_val_if_fail (font != NULL, -1); + g_return_val_if_fail (text != NULL, -1); + + if (text_length == 0) + return 0; + + g_assert (font->type == GDK_FONT_FONT || font->type == GDK_FONT_FONTSET); + + if (sizeof (wchar_t) != sizeof (GdkWChar)) + { + wcstr = g_new (wchar_t, text_length); + for (i = 0; i < text_length; i++) + wcstr[i] = text[i]; + } + else + wcstr = (wchar_t *) text; + + arg.total.cx = arg.total.cy = 0; + arg.max.cx = arg.max.cy = 0; + + gdk_wchar_text_handle (font, wcstr, text_length, + gdk_text_size_handler, &arg); + + if (sizeof (wchar_t) != sizeof (GdkWChar)) + g_free (wcstr); + + return arg.total.cx; +} + +gint +gdk_char_width (GdkFont *font, + gchar character) +{ + if (((guchar) character) >= 128) + { + /* gtktext calls us with non-ASCII characters, sigh */ + GdkWChar wc = (guchar) character; + return gdk_text_width_wc (font, &wc, 1); + } + return gdk_text_width (font, &character, 1); +} + +gint +gdk_char_width_wc (GdkFont *font, + GdkWChar character) +{ + return gdk_text_width_wc (font, &character, 1); +} + +gint +gdk_string_measure (GdkFont *font, + const gchar *string) +{ + g_return_val_if_fail (font != NULL, -1); + g_return_val_if_fail (string != NULL, -1); + + return gdk_text_measure (font, string, strlen (string)); +} + +void +gdk_text_extents (GdkFont *font, + const gchar *text, + gint text_length, + gint *lbearing, + gint *rbearing, + gint *width, + gint *ascent, + gint *descent) +{ + gdk_text_size_arg arg; + gint wlen; + wchar_t *wcstr; + + g_return_if_fail (font != NULL); + g_return_if_fail (text != NULL); + + if (text_length == 0) + { + if (lbearing) + *lbearing = 0; + if (rbearing) + *rbearing = 0; + if (width) + *width = 0; + if (ascent) + *ascent = 0; + if (descent) + *descent = 0; + return; + } + + g_assert (font->type == GDK_FONT_FONT || font->type == GDK_FONT_FONTSET); + + arg.total.cx = arg.total.cy = 0; + arg.max.cx = arg.max.cy = 0; + + wcstr = g_new (wchar_t, text_length); + if ((wlen = gdk_nmbstowchar_ts (wcstr, text, text_length, text_length)) == -1) + g_warning ("gdk_text_extents: gdk_nmbstowchar_ts failed"); + else + gdk_wchar_text_handle (font, wcstr, wlen, gdk_text_size_handler, &arg); + + g_free (wcstr); + + /* XXX This is quite bogus */ + if (lbearing) + *lbearing = 0; + if (rbearing) + *rbearing = 0; + if (width) + *width = arg.total.cx; + if (ascent) + *ascent = arg.max.cy + 1; + if (descent) + *descent = font->descent + 1; +} + +void +gdk_text_extents_wc (GdkFont *font, + const GdkWChar *text, + gint text_length, + gint *lbearing, + gint *rbearing, + gint *width, + gint *ascent, + gint *descent) +{ + gdk_text_size_arg arg; + wchar_t *wcstr; + gint i; + + g_return_if_fail (font != NULL); + g_return_if_fail (text != NULL); + + if (text_length == 0) + { + if (lbearing) + *lbearing = 0; + if (rbearing) + *rbearing = 0; + if (width) + *width = 0; + if (ascent) + *ascent = 0; + if (descent) + *descent = 0; + return; + } + + g_assert (font->type == GDK_FONT_FONT || font->type == GDK_FONT_FONTSET); + + if (sizeof (wchar_t) != sizeof (GdkWChar)) + { + wcstr = g_new (wchar_t, text_length); + for (i = 0; i < text_length; i++) + wcstr[i] = text[i]; + } + else + wcstr = (wchar_t *) text; + + arg.total.cx = arg.total.cy = 0; + arg.max.cx = arg.max.cy = 0; + + gdk_wchar_text_handle (font, wcstr, text_length, + gdk_text_size_handler, &arg); + + if (sizeof (wchar_t) != sizeof (GdkWChar)) + g_free (wcstr); + + /* XXX This is quite bogus */ + if (lbearing) + *lbearing = 0; + if (rbearing) + *rbearing = 0; + if (width) + *width = arg.total.cx; + if (ascent) + *ascent = arg.max.cy + 1; + if (descent) + *descent = font->descent + 1; +} + +void +gdk_string_extents (GdkFont *font, + const gchar *string, + gint *lbearing, + gint *rbearing, + gint *width, + gint *ascent, + gint *descent) +{ + g_return_if_fail (font != NULL); + g_return_if_fail (string != NULL); + + gdk_text_extents (font, string, strlen (string), + lbearing, rbearing, width, ascent, descent); +} + + +gint +gdk_text_measure (GdkFont *font, + const gchar *text, + gint text_length) +{ + return gdk_text_width (font, text, text_length); /* ??? */ +} + +gint +gdk_char_measure (GdkFont *font, + gchar character) +{ + return gdk_text_measure (font, &character, 1); +} + +gint +gdk_string_height (GdkFont *font, + const gchar *string) +{ + g_return_val_if_fail (font != NULL, -1); + g_return_val_if_fail (string != NULL, -1); + + return gdk_text_height (font, string, strlen (string)); +} + +gint +gdk_text_height (GdkFont *font, + const gchar *text, + gint text_length) +{ + gdk_text_size_arg arg; + + arg.total.cx = arg.total.cy = 0; + arg.max.cx = arg.max.cy = 0; + + if (!gdk_text_size (font, text, text_length, &arg)) + return -1; + + return arg.max.cy; +} + +gint +gdk_char_height (GdkFont *font, + gchar character) +{ + return gdk_text_height (font, &character, 1); +} diff --git a/gdk/win32/gdkgc-win32.c b/gdk/win32/gdkgc-win32.c new file mode 100644 index 000000000..407335a7a --- /dev/null +++ b/gdk/win32/gdkgc-win32.c @@ -0,0 +1,1392 @@ +/* GDK - The GIMP Drawing Kit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* + * Modified by the GTK+ Team and others 1997-1999. See the AUTHORS + * file for a list of people on the GTK+ Team. See the ChangeLog + * files for a list of changes. These files are distributed with + * GTK+ at ftp://ftp.gtk.org/pub/gtk/. + */ + +#include "config.h" + +#include + +#include "gdkgc.h" +#include "gdkfont.h" +#include "gdkpixmap.h" +#include "gdkprivate.h" +#include "gdkx.h" + +GdkGC* +gdk_gc_new (GdkWindow *window) +{ + return gdk_gc_new_with_values (window, NULL, 0); +} + +GdkGC* +gdk_gc_new_with_values (GdkWindow *window, + GdkGCValues *values, + GdkGCValuesMask values_mask) +{ + GdkGC *gc; + GdkGCPrivate *private; + static GdkColor black; + static GdkColor white; + static gboolean beenhere = FALSE; + + if (!beenhere) + { + gdk_color_black (gdk_colormap_get_system (), &black); + gdk_color_white (gdk_colormap_get_system (), &white); + beenhere = TRUE; + } + + g_return_val_if_fail (window != NULL, NULL); + + if (GDK_DRAWABLE_DESTROYED (window)) + return NULL; + + private = g_new (GdkGCPrivate, 1); + gc = (GdkGC*) private; + + private->ref_count = 1; + private->rop2 = R2_COPYPEN; + private->fill_style = GDK_SOLID; + private->values_mask = values_mask; + private->values_mask |= GDK_GC_FUNCTION | GDK_GC_FILL; + + GDK_NOTE (MISC, g_print ("gdk_gc_new: {")); + + if (values_mask & GDK_GC_FOREGROUND) + { + private->foreground = values->foreground; + } + else + private->foreground = black; + + if (values_mask & GDK_GC_BACKGROUND) + { + private->background = values->background; + } + else + private->background = white; + + if ((values_mask & GDK_GC_FONT) && (values->font->type == GDK_FONT_FONT + || values->font->type == GDK_FONT_FONTSET)) + { + private->font = values->font; + gdk_font_ref (private->font); + GDK_NOTE (MISC, g_print (" font")); + } + else + private->font = NULL; + + if (values_mask & GDK_GC_FUNCTION) + { + switch (values->function) + { + case GDK_COPY: + private->rop2 = R2_COPYPEN; break; + case GDK_INVERT: + private->rop2 = R2_NOT; break; + case GDK_XOR: + private->rop2 = R2_XORPEN; break; + case GDK_CLEAR: + private->rop2 = R2_BLACK; break; + case GDK_AND: + private->rop2 = R2_MASKPEN; break; + case GDK_AND_REVERSE: + private->rop2 = R2_MASKPENNOT; break; + case GDK_AND_INVERT: + private->rop2 = R2_MASKNOTPEN; break; + case GDK_NOOP: + private->rop2 = R2_NOP; break; + case GDK_OR: + private->rop2 = R2_MERGEPEN; break; + case GDK_EQUIV: + private->rop2 = R2_NOTXORPEN; break; + case GDK_OR_REVERSE: + private->rop2 = R2_MERGEPENNOT; break; + case GDK_COPY_INVERT: + private->rop2 = R2_NOTCOPYPEN; break; + case GDK_OR_INVERT: + private->rop2 = R2_MERGENOTPEN; break; + case GDK_NAND: + private->rop2 = R2_NOTMASKPEN; break; + case GDK_SET: + private->rop2 = R2_WHITE; break; + } + GDK_NOTE (MISC, g_print (" function=%d", private->rop2)); + } + + if (values_mask & GDK_GC_FILL) + { + private->fill_style = values->fill; + GDK_NOTE (MISC, g_print (" fill=%d", private->fill_style)); + } + + if (values_mask & GDK_GC_TILE) + { + private->tile = values->tile; + gdk_pixmap_ref (private->tile); + GDK_NOTE (MISC, g_print (" tile=%#x", GDK_DRAWABLE_XID (private->tile))); + } + else + private->tile = NULL; + + if (values_mask & GDK_GC_STIPPLE) + { + private->stipple = values->stipple; + gdk_pixmap_ref (private->stipple); + GDK_NOTE (MISC, g_print (" stipple=%#x", GDK_DRAWABLE_XID (private->stipple))); + } + else + private->stipple = NULL; + + if (values_mask & GDK_GC_CLIP_MASK) + { + private->clip_region = + BitmapToRegion ((HBITMAP) GDK_DRAWABLE_XID (values->clip_mask)); + GDK_NOTE (MISC, g_print (" clip=%#x", private->clip_region)); + } + else + private->clip_region = NULL; + + if (values_mask & GDK_GC_SUBWINDOW) + { + private->subwindow_mode = values->subwindow_mode; + GDK_NOTE (MISC, g_print (" subw=%d", private->subwindow_mode)); + } + + if (values_mask & GDK_GC_TS_X_ORIGIN) + { + private->ts_x_origin = values->ts_x_origin; + GDK_NOTE (MISC, g_print (" ts_x=%d", private->ts_x_origin)); + } + + if (values_mask & GDK_GC_TS_Y_ORIGIN) + { + private->ts_y_origin = values->ts_y_origin; + GDK_NOTE (MISC, g_print (" ts_y=%d", private->ts_y_origin)); + } + + if (values_mask & GDK_GC_CLIP_X_ORIGIN) + { + private->clip_x_origin = values->clip_x_origin; + GDK_NOTE (MISC, g_print (" clip_x=%d", private->clip_x_origin)); + } + + if (values_mask & GDK_GC_CLIP_Y_ORIGIN) + { + private->clip_y_origin = values->clip_y_origin; + GDK_NOTE (MISC, g_print (" clip_y=%d", private->clip_y_origin)); + } + + if (values_mask & GDK_GC_EXPOSURES) + { + private->graphics_exposures = values->graphics_exposures; + GDK_NOTE (MISC, g_print (" exp=%d", private->graphics_exposures)); + } + + private->pen_style = PS_GEOMETRIC; + private->pen_width = 1; + + if (values_mask & (GDK_GC_LINE_WIDTH | GDK_GC_LINE_STYLE)) + { + if (values_mask & GDK_GC_LINE_WIDTH) + { + private->pen_width = values->line_width; + GDK_NOTE (MISC, g_print (" pw=%d", private->pen_width)); + } + if (values_mask & GDK_GC_LINE_STYLE) + { + switch (values->line_style) + { + case GDK_LINE_SOLID: + private->pen_style |= PS_SOLID; break; + case GDK_LINE_ON_OFF_DASH: + case GDK_LINE_DOUBLE_DASH: /* ??? */ + private->pen_style |= PS_DASH; break; + } + GDK_NOTE (MISC, g_print (" ps=%#x", private->pen_style)); + } + } + + if (values_mask & GDK_GC_CAP_STYLE) + { + switch (values->cap_style) + { + case GDK_CAP_NOT_LAST: /* ??? */ + case GDK_CAP_BUTT: + private->pen_style |= PS_ENDCAP_FLAT; break; + case GDK_CAP_ROUND: + private->pen_style |= PS_ENDCAP_ROUND; break; + case GDK_CAP_PROJECTING: + private->pen_style |= PS_ENDCAP_SQUARE; break; + } + GDK_NOTE (MISC, g_print (" ps=%#x", private->pen_style)); + } + + if (values_mask & GDK_GC_JOIN_STYLE) + { + switch (values->join_style) + { + case GDK_JOIN_MITER: + private->pen_style |= PS_JOIN_MITER; + break; + case GDK_JOIN_ROUND: + private->pen_style |= PS_JOIN_ROUND; + break; + case GDK_JOIN_BEVEL: + private->pen_style |= PS_JOIN_BEVEL; + break; + } + GDK_NOTE (MISC, g_print (" ps=%#x", private->pen_style)); + } + + private->hwnd = NULL; + private->xgc = NULL; + + GDK_NOTE (MISC, g_print ("} = %p\n", private)); + + return gc; +} + +void +gdk_gc_destroy (GdkGC *gc) +{ + gdk_gc_unref (gc); +} + +GdkGC * +gdk_gc_ref (GdkGC *gc) +{ + GdkGCPrivate *private = (GdkGCPrivate*) gc; + + g_return_val_if_fail (gc != NULL, NULL); + private->ref_count += 1; + + return gc; +} + +void +gdk_gc_unref (GdkGC *gc) +{ + GdkGCPrivate *private = (GdkGCPrivate*) gc; + + g_return_if_fail (gc != NULL); + + if (private->ref_count > 1) + private->ref_count -= 1; + else + { + if (private->values_mask & GDK_GC_FONT) + gdk_font_unref (private->font); + + if (private->values_mask & GDK_GC_TILE) + gdk_pixmap_unref (private->tile); + + if (private->values_mask & GDK_GC_STIPPLE) + gdk_pixmap_unref (private->stipple); + + if (private->values_mask & GDK_GC_CLIP_MASK) + DeleteObject (private->clip_region); + + g_free (gc); + } +} + +void +gdk_gc_get_values (GdkGC *gc, + GdkGCValues *values) +{ + GdkGCPrivate *private; + + g_return_if_fail (gc != NULL); + g_return_if_fail (values != NULL); + + private = (GdkGCPrivate*) gc; + + values->foreground = private->foreground; + values->background = private->background; + values->font = private->font; + + switch (private->rop2) + { + case R2_COPYPEN: + values->function = GDK_COPY; break; + case R2_NOT: + values->function = GDK_INVERT; break; + case R2_XORPEN: + values->function = GDK_XOR; break; + case R2_BLACK: + values->function = GDK_CLEAR; break; + case R2_MASKPEN: + values->function = GDK_AND; break; + case R2_MASKPENNOT: + values->function = GDK_AND_REVERSE; break; + case R2_MASKNOTPEN: + values->function = GDK_AND_INVERT; break; + case R2_NOP: + values->function = GDK_NOOP; break; + case R2_MERGEPEN: + values->function = GDK_OR; break; + case R2_NOTXORPEN: + values->function = GDK_EQUIV; break; + case R2_MERGEPENNOT: + values->function = GDK_OR_REVERSE; break; + case R2_NOTCOPYPEN: + values->function = GDK_COPY_INVERT; break; + case R2_MERGENOTPEN: + values->function = GDK_OR_INVERT; break; + case R2_NOTMASKPEN: + values->function = GDK_NAND; break; + case R2_WHITE: + values->function = GDK_SET; break; + } + + values->fill = private->fill_style; + + values->tile = private->tile; + values->stipple = private->stipple; + if (private->clip_region != NULL) + { + RECT rect; + HBRUSH hbr; + HDC hdc; + HGDIOBJ oldbitmap; + GdkPixmap *pixmap; + + GetRgnBox (private->clip_region, &rect); + pixmap = + gdk_pixmap_new (NULL, rect.right - rect.left, rect.bottom - rect.top, + 1); + hbr = GetStockObject (WHITE_BRUSH); + if ((hdc = CreateCompatibleDC (NULL)) == NULL) + g_warning ("gdk_gc_get_values: CreateCompatibleDC failed"); + if ((oldbitmap = + SelectObject (hdc, GDK_DRAWABLE_XID (pixmap))) == NULL) + g_warning ("gdk_gc_get_values: SelectObject #1 failed"); + hbr = GetStockObject (BLACK_BRUSH); + if (!FillRect (hdc, &rect, hbr)) + g_warning ("gdk_gc_get_values: FillRect failed"); + hbr = GetStockObject (WHITE_BRUSH); + if (!FillRgn (hdc, private->clip_region, hbr)) + g_warning ("gdk_gc_get_values: FillRgn failed"); + if (SelectObject (hdc, oldbitmap) == NULL) + g_warning ("gdk_gc_get_values: SelectObject #2 failed"); + DeleteDC (hdc); + values->clip_mask = pixmap; + } + else + values->clip_mask = NULL; + values->subwindow_mode = private->subwindow_mode; + values->ts_x_origin = private->ts_x_origin; + values->ts_y_origin = private->ts_y_origin; + values->clip_x_origin = private->clip_x_origin; + values->clip_y_origin = private->clip_y_origin; + values->graphics_exposures = private->graphics_exposures; + values->line_width = private->pen_width; + + if (private->pen_style & PS_SOLID) + values->line_style = GDK_LINE_SOLID; + else if (private->pen_style & PS_DASH) + values->line_style = GDK_LINE_ON_OFF_DASH; + else + values->line_style = GDK_LINE_SOLID; + + /* PS_ENDCAP_ROUND is zero */ + if (private->pen_style & PS_ENDCAP_FLAT) + values->cap_style = GDK_CAP_BUTT; + else if (private->pen_style & PS_ENDCAP_SQUARE) + values->cap_style = GDK_CAP_PROJECTING; + else + values->cap_style = GDK_CAP_ROUND; + + /* PS_JOIN_ROUND is zero */ + if (private->pen_style & PS_JOIN_MITER) + values->join_style = GDK_JOIN_MITER; + else if (private->pen_style & PS_JOIN_BEVEL) + values->join_style = GDK_JOIN_BEVEL; + else + values->join_style = GDK_JOIN_ROUND; +} + +void +gdk_gc_set_foreground (GdkGC *gc, + GdkColor *color) +{ + GdkGCPrivate *private; + + g_return_if_fail (gc != NULL); + g_return_if_fail (color != NULL); + + private = (GdkGCPrivate*) gc; + { + GDK_NOTE (MISC, g_print ("gdk_gc_set_foreground: (%d) %s\n", + private, gdk_color_to_string (color))); + private->foreground = *color; + private->values_mask |= GDK_GC_FOREGROUND; + } +} + +void +gdk_gc_set_background (GdkGC *gc, + GdkColor *color) +{ + GdkGCPrivate *private; + + g_return_if_fail (gc != NULL); + g_return_if_fail (color != NULL); + + private = (GdkGCPrivate*) gc; + + GDK_NOTE (MISC, g_print ("gdk_gc_set_backround: (%d) %s\n", + private, gdk_color_to_string(color))); + private->background = *color; + private->values_mask |= GDK_GC_BACKGROUND; +} + +void +gdk_gc_set_font (GdkGC *gc, + GdkFont *font) +{ + GdkGCPrivate *gc_private; + GdkFontPrivate *font_private; + gchar *xlfd; + + g_return_if_fail (gc != NULL); + g_return_if_fail (font != NULL); + + if (font->type == GDK_FONT_FONT + || font->type == GDK_FONT_FONTSET) + { + gc_private = (GdkGCPrivate*) gc; + + GDK_NOTE (MISC, (xlfd = gdk_font_xlfd_create (font), + g_print ("gdk_gc_set_font: (%d) %s\n", + gc_private, xlfd), + gdk_font_xlfd_free (xlfd))); + + if (gc_private->font != NULL) + gdk_font_unref (gc_private->font); + gc_private->font = font; + gdk_font_ref (gc_private->font); + gc_private->values_mask |= GDK_GC_FONT; + } +} + +void +gdk_gc_set_function (GdkGC *gc, + GdkFunction function) +{ + GdkGCPrivate *private; + + g_return_if_fail (gc != NULL); + + private = (GdkGCPrivate*) gc; + + GDK_NOTE (MISC, g_print ("gdk_gc_set_function: (%d) %d\n", private, function)); + + switch (function) + { + case GDK_COPY: + private->rop2 = R2_COPYPEN; break; + case GDK_INVERT: + private->rop2 = R2_NOT; break; + case GDK_XOR: + private->rop2 = R2_XORPEN; break; + case GDK_CLEAR: + private->rop2 = R2_BLACK; break; + case GDK_AND: + private->rop2 = R2_MASKPEN; break; + case GDK_AND_REVERSE: + private->rop2 = R2_MASKPENNOT; break; + case GDK_AND_INVERT: + private->rop2 = R2_MASKNOTPEN; break; + case GDK_NOOP: + private->rop2 = R2_NOP; break; + case GDK_OR: + private->rop2 = R2_MERGEPEN; break; + case GDK_EQUIV: + private->rop2 = R2_NOTXORPEN; break; + case GDK_OR_REVERSE: + private->rop2 = R2_MERGEPENNOT; break; + case GDK_COPY_INVERT: + private->rop2 = R2_NOTCOPYPEN; break; + case GDK_OR_INVERT: + private->rop2 = R2_MERGENOTPEN; break; + case GDK_NAND: + private->rop2 = R2_NOTMASKPEN; break; + case GDK_SET: + private->rop2 = R2_WHITE; break; + } + private->values_mask |= GDK_GC_FUNCTION; +} + +void +gdk_gc_set_fill (GdkGC *gc, + GdkFill fill) +{ + GdkGCPrivate *private; + + g_return_if_fail (gc != NULL); + + private = (GdkGCPrivate*) gc; + + private->fill_style = fill; + private->values_mask |= GDK_GC_FILL; +} + +void +gdk_gc_set_tile (GdkGC *gc, + GdkPixmap *tile) +{ + GdkGCPrivate *private; + HBITMAP pixmap; + + g_return_if_fail (gc != NULL); + + private = (GdkGCPrivate*) gc; + + pixmap = NULL; + + if (tile) + pixmap = GDK_DRAWABLE_XID (tile); + + if (private->tile != NULL) + gdk_pixmap_unref (private->tile); + private->tile = tile; + if (tile) + gdk_pixmap_ref (tile); + if (pixmap != NULL) + private->values_mask |= GDK_GC_TILE; + else + private->values_mask &= ~GDK_GC_TILE; +} + +void +gdk_gc_set_stipple (GdkGC *gc, + GdkPixmap *stipple) +{ + GdkGCPrivate *private; + HBITMAP pixmap; + + g_return_if_fail (gc != NULL); + + private = (GdkGCPrivate*) gc; + + pixmap = NULL; + + if (stipple) + pixmap = GDK_DRAWABLE_XID (stipple); + + if (private->stipple != NULL) + gdk_pixmap_unref (private->stipple); + private->stipple = stipple; + if (stipple) + gdk_pixmap_ref (stipple); + if (pixmap != NULL) + private->values_mask |= GDK_GC_STIPPLE; + else + private->values_mask &= ~GDK_GC_STIPPLE; +} + +void +gdk_gc_set_ts_origin (GdkGC *gc, + gint x, + gint y) +{ + GdkGCPrivate *private; + + g_return_if_fail (gc != NULL); + + private = (GdkGCPrivate*) gc; + + private->ts_x_origin = x; + private->ts_y_origin = y; + private->values_mask |= GDK_GC_TS_X_ORIGIN |GDK_GC_TS_Y_ORIGIN; +} + +void +gdk_gc_set_clip_origin (GdkGC *gc, + gint x, + gint y) +{ + GdkGCPrivate *private; + + g_return_if_fail (gc != NULL); + + private = (GdkGCPrivate*) gc; + + GDK_NOTE (MISC, g_print ("gdk_gc_set_clip_origin: (%d) +%d+%d\n", + private, x, y)); + + private->clip_x_origin = x; + private->clip_y_origin = y; + private->values_mask |= GDK_GC_CLIP_X_ORIGIN |GDK_GC_CLIP_Y_ORIGIN; +} + +void +gdk_gc_set_clip_mask (GdkGC *gc, + GdkBitmap *mask) +{ + GdkGCPrivate *private; + HBITMAP xmask; + + g_return_if_fail (gc != NULL); + + if (mask) + { + if (GDK_DRAWABLE_DESTROYED (mask)) + return; + xmask = GDK_DRAWABLE_XID (mask); + } + else + xmask = NULL; + + private = (GdkGCPrivate*) gc; + + GDK_NOTE (MISC, g_print ("gdk_gc_set_clip_mask: (%d) %#x\n", private, xmask)); + + if (private->clip_region != NULL) + if (!DeleteObject (private->clip_region)) + g_warning ("gdk_gc_set_clip_mask: DeleteObject failed"); + if (xmask != NULL) + { + private->clip_region = BitmapToRegion (xmask); + { + RECT rect; + GetRgnBox (private->clip_region, &rect); + GDK_NOTE (MISC, g_print ("...box = %dx%d@+%d+%d\n", + rect.right - rect.left, rect.bottom - rect.top, + rect.left, rect.top)); + } +#if 0 + /* Test code that sets clip region to whole of mask */ + { + BITMAP bm; + GetObject (xmask, sizeof (bm), &bm); + private->clip_region = CreateRectRgn (0, 0, bm.bmWidth, bm.bmHeight); + } +#endif + private->values_mask |= GDK_GC_CLIP_MASK; + } + else + { + private->values_mask &= ~GDK_GC_CLIP_MASK; + private->clip_region = NULL; + } +} + +void +gdk_gc_set_clip_rectangle (GdkGC *gc, + GdkRectangle *rectangle) +{ + GdkGCPrivate *private; + + g_return_if_fail (gc != NULL); + + private = (GdkGCPrivate*) gc; + + if (private->clip_region != NULL) + if (!DeleteObject (private->clip_region)) + g_warning ("gdk_gc_set_clip_rectangle: DeleteObject failed"); + if (rectangle) + { + GDK_NOTE (MISC, + g_print ("gdk_gc_set_clip_rectangle: (%d) %dx%d@+%d+%d\n", + private, + rectangle->width, rectangle->height, + rectangle->x, rectangle->y)); + if ((private->clip_region = + CreateRectRgn (rectangle->x, rectangle->y, + rectangle->x + rectangle->width, + rectangle->y + rectangle->height)) == NULL) + g_warning ("gdk_gc_set_clip_rectangle: CreateRectRgn failed"); + + private->values_mask |= GDK_GC_CLIP_MASK; + } + else + { + GDK_NOTE (MISC, g_print ("gdk_gc_set_clip_rectangle: (%d) None\n", + private)); + private->clip_region = NULL; + private->values_mask &= ~GDK_GC_CLIP_MASK; + } + private->values_mask &= ~(GDK_GC_CLIP_X_ORIGIN |GDK_GC_CLIP_Y_ORIGIN); +} + +void +gdk_gc_set_clip_region (GdkGC *gc, + GdkRegion *region) +{ + GdkGCPrivate *private; + + g_return_if_fail (gc != NULL); + + private = (GdkGCPrivate*) gc; + + GDK_NOTE (MISC, g_print ("gdk_gc_set_clip_region: (%d) %s\n", + private, (region != NULL ? "xxx" : "None"))); + + if (private->clip_region != NULL) + if (!DeleteObject (private->clip_region)) + g_warning ("gdk_gc_set_clip_region: DeleteObject failed"); + if (region) + { + GdkRegionPrivate *region_private; + + region_private = (GdkRegionPrivate*) region; + private->clip_region = CreateRectRgn (1, 1, 0, 0); + CombineRgn (private->clip_region, region_private->xregion, NULL, RGN_COPY); + private->values_mask |= GDK_GC_CLIP_MASK; + } + else + { + private->clip_region = NULL; + private->values_mask &= ~GDK_GC_CLIP_MASK; + } +} + +void +gdk_gc_set_subwindow (GdkGC *gc, + GdkSubwindowMode mode) +{ + GdkGCPrivate *private; + + g_return_if_fail (gc != NULL); + + private = (GdkGCPrivate*) gc; + + private->subwindow_mode = mode; + private->values_mask |= GDK_GC_SUBWINDOW; +} + +void +gdk_gc_set_exposures (GdkGC *gc, + gint exposures) +{ + GdkGCPrivate *private; + + g_return_if_fail (gc != NULL); + + private = (GdkGCPrivate*) gc; + + private->graphics_exposures = exposures; + private->values_mask |= GDK_GC_EXPOSURES;; +} + +void +gdk_gc_set_line_attributes (GdkGC *gc, + gint line_width, + GdkLineStyle line_style, + GdkCapStyle cap_style, + GdkJoinStyle join_style) +{ + GdkGCPrivate *private; + int xline_style; + int xcap_style; + int xjoin_style; + + g_return_if_fail (gc != NULL); + + private = (GdkGCPrivate*) gc; + + GDK_NOTE (MISC, + g_print ("gdk_gc_set_line_attributes: (%d) %d %s %s %s\n", + private, line_width, + (line_style == GDK_LINE_SOLID ? "SOLID" : + (line_style == GDK_LINE_ON_OFF_DASH ? "ON_OFF_DASH" : + (line_style == GDK_LINE_DOUBLE_DASH ? "DOUBLE_DASH" : + "???"))), + (cap_style == GDK_CAP_BUTT ? "BUTT" : + (cap_style == GDK_CAP_ROUND ? "ROUND" : + (cap_style == GDK_CAP_PROJECTING ? "PROJECTING" : + "???"))), + (join_style == GDK_JOIN_MITER ? "MITER" : + (join_style == GDK_JOIN_ROUND ? "ROUND" : + (join_style == GDK_JOIN_BEVEL ? "BEVEL" : + "???"))))); + + private->pen_width = line_width; + + /* Mask old style bits away */ + private->pen_style &= ~(PS_STYLE_MASK|PS_ENDCAP_MASK|PS_JOIN_MASK); + + /* Add new bits */ + switch (line_style) + { + case GDK_LINE_SOLID: + private->pen_style |= PS_SOLID; break; + case GDK_LINE_ON_OFF_DASH: + case GDK_LINE_DOUBLE_DASH: /* ??? */ + private->pen_style |= PS_DASH; break; + } + + switch (cap_style) + { + case GDK_CAP_NOT_LAST: + /* ??? */ + break; + case GDK_CAP_BUTT: + private->pen_style |= PS_ENDCAP_FLAT; break; + case GDK_CAP_ROUND: + private->pen_style |= PS_ENDCAP_ROUND; break; + case GDK_CAP_PROJECTING: + private->pen_style |= PS_ENDCAP_SQUARE; break; + } + + switch (join_style) + { + case GDK_JOIN_MITER: + private->pen_style |= PS_JOIN_MITER; + break; + case GDK_JOIN_ROUND: + private->pen_style |= PS_JOIN_ROUND; + break; + case GDK_JOIN_BEVEL: + private->pen_style |= PS_JOIN_BEVEL; + break; + } +} + +void +gdk_gc_set_dashes (GdkGC *gc, + gint dash_offset, + gchar dash_list[], + gint n) +{ + GdkGCPrivate *private; + + g_return_if_fail (gc != NULL); + g_return_if_fail (dash_list != NULL); + + /* XXX ??? */ + + private = (GdkGCPrivate *) gc; + + private->pen_style &= ~(PS_STYLE_MASK); + private->pen_style |= PS_DASH; +} + +void +gdk_gc_copy (GdkGC *dst_gc, GdkGC *src_gc) +{ + GdkGCPrivate *dst_private, *src_private; + + src_private = (GdkGCPrivate *) src_gc; + dst_private = (GdkGCPrivate *) dst_gc; + + *dst_private = *src_private; +} + +HDC +gdk_gc_predraw (GdkDrawablePrivate *drawable_private, + GdkGCPrivate *gc_private) +{ + GdkColormapPrivate *colormap_private = + (GdkColormapPrivate *) drawable_private->colormap; + COLORREF bg; + COLORREF fg; + LOGBRUSH logbrush; + HPEN hpen; + HBRUSH hbr; + + g_assert (gc_private->xgc == NULL); + + if (drawable_private->window_type == GDK_DRAWABLE_PIXMAP) + { + if ((gc_private->xgc = CreateCompatibleDC (NULL)) == NULL) + g_warning ("gdk_gc_predraw: CreateCompatibleDC failed"); + + if ((gc_private->saved_dc = SaveDC (gc_private->xgc)) == 0) + g_warning ("gdk_gc_predraw: SaveDC #1 failed"); + + if (SelectObject (gc_private->xgc, drawable_private->xwindow) == NULL) + g_warning ("gdk_gc_predraw: SelectObject #1 failed"); + } + else + { + if ((gc_private->xgc = GetDC (drawable_private->xwindow)) == NULL) + g_warning ("gdk_gc_predraw: GetDC failed"); + + if ((gc_private->saved_dc = SaveDC (gc_private->xgc)) == 0) + g_warning ("gdk_gc_predraw: SaveDC #2 failed"); + } + + gc_private->hwnd = drawable_private->xwindow; + + if (colormap_private == NULL) + { + /* A 1 bit deep bitmap */ + struct + { + WORD palVersion; + WORD palNumEntries; + PALETTEENTRY palPalEntry[2]; + } logpal; + static HPALETTE hpal = NULL; + + if (hpal == NULL) + { + /* Create a b&w palette */ + logpal.palVersion = 0x300; + logpal.palNumEntries = 2; + logpal.palPalEntry[0].peRed = + logpal.palPalEntry[0].peGreen = + logpal.palPalEntry[0].peBlue = 0x00; + logpal.palPalEntry[0].peFlags = 0x00; + logpal.palPalEntry[1].peRed = + logpal.palPalEntry[1].peGreen = + logpal.palPalEntry[1].peBlue = 0xFF; + logpal.palPalEntry[1].peFlags = 0x00; + if ((hpal = CreatePalette ((LOGPALETTE *) &logpal)) == NULL) + g_warning ("gdk_gc_predraw: CreatePalette failed"); + } + SelectPalette (gc_private->xgc, hpal, FALSE); + RealizePalette (gc_private->xgc); + fg = PALETTEINDEX (gc_private->foreground.pixel); + } + else if (colormap_private != NULL + && colormap_private->xcolormap->rc_palette) + { + int k; + if (SelectPalette (gc_private->xgc, + colormap_private->xcolormap->palette, FALSE) == NULL) + g_warning ("gdk_gc_predraw: SelectPalette failed"); + if (TRUE || colormap_private->xcolormap->stale) + { + if ((k = RealizePalette (gc_private->xgc)) == GDI_ERROR) + g_warning ("gdk_gc_predraw: RealizePalette failed"); + colormap_private->xcolormap->stale = FALSE; + } +#if 0 + g_print ("Selected palette %#x for gc %#x, realized %d colors\n", + colormap_private->xcolormap->palette, gc_private->xgc, k); +#endif + fg = PALETTEINDEX (gc_private->foreground.pixel); + } + else + { + COLORREF foreground = RGB (gc_private->foreground.red >> 8, + gc_private->foreground.green >> 8, + gc_private->foreground.blue >> 8); + fg = GetNearestColor (gc_private->xgc, foreground); + } + logbrush.lbStyle = BS_SOLID; + logbrush.lbColor = fg; + if ((hpen = ExtCreatePen (gc_private->pen_style, gc_private->pen_width, + &logbrush, 0, NULL)) == NULL) + g_warning ("gdk_gc_predraw: CreatePen failed"); + + if (SelectObject (gc_private->xgc, hpen) == NULL) + g_warning ("gdk_gc_predraw: SelectObject #2 failed"); + + if (SetTextColor (gc_private->xgc, fg) == CLR_INVALID) + g_warning ("gdk_gc_predraw: SetTextColor failed"); + +#if 0 + switch (gc_private->fill_style) + { + case GDK_STIPPLED: + { + GdkPixmap *stipple = gc_private->stipple; + GdkPixmapPrivate *stipple_private = (GdkPixmapPrivate *) stipple; + HBITMAP hbm = stipple_private->xwindow; + if (NULL == (hbr = CreatePatternBrush (hbm))) + g_warning ("gdk_gc_predraw: CreatePatternBrush failed"); + +#ifdef NATIVE_WIN16 + SetBrushOrg (gc_private->xgc, gc_private->ts_x_origin, + gc_private->ts_y_origin); +#else + SetBrushOrgEx(gc_private->xgc, gc_private->ts_x_origin, + gc_private->ts_y_origin, NULL); +#endif + } + break; + case GDK_SOLID: + default: + if ((hbr = CreateSolidBrush (fg)) == NULL) + g_warning ("gdk_gc_predraw: CreateSolidBrush failed"); + break; + } +#else + if ((hbr = CreateSolidBrush (fg)) == NULL) + g_warning ("gdk_gc_predraw: CreateSolidBrush failed"); +#endif + if (SelectObject (gc_private->xgc, hbr) == NULL) + g_warning ("gdk_gc_predraw: SelectObject #3 failed"); + + if (gc_private->values_mask & GDK_GC_BACKGROUND) + { + if (colormap_private == NULL) + { + /* a bitmap */ + bg = PALETTEINDEX (gc_private->background.pixel); + } + else if (colormap_private != NULL + && colormap_private->xcolormap->rc_palette) + { + bg = PALETTEINDEX (gc_private->background.pixel); + } + else + { + COLORREF background = RGB (gc_private->background.red >> 8, + gc_private->background.green >> 8, + gc_private->background.blue >> 8); + bg = GetNearestColor (gc_private->xgc, background); + } + if (SetBkColor (gc_private->xgc, bg) == CLR_INVALID) + g_warning ("gdk_gc_predraw: SetBkColor failed"); + } + + if (SetBkMode (gc_private->xgc, TRANSPARENT) == 0) + g_warning ("gdk_gc_predraw: SetBkMode failed"); + + if (SetTextAlign (gc_private->xgc, TA_BASELINE) == GDI_ERROR) + g_warning ("gdk_gc_predraw: SetTextAlign failed"); + + if (gc_private->values_mask & GDK_GC_FUNCTION) + if (SetROP2 (gc_private->xgc, gc_private->rop2) == 0) + g_warning ("gdk_gc_predraw: SetROP2 failed"); + + if (gc_private->values_mask & GDK_GC_CLIP_MASK + && gc_private->clip_region != NULL) + { + if (gc_private->values_mask & (GDK_GC_CLIP_X_ORIGIN | GDK_GC_CLIP_Y_ORIGIN)) + OffsetRgn (gc_private->clip_region, + gc_private->clip_x_origin, gc_private->clip_y_origin); + SelectClipRgn (gc_private->xgc, gc_private->clip_region); + } + + return gc_private->xgc; +} + +void +gdk_gc_postdraw (GdkDrawablePrivate *drawable_private, + GdkGCPrivate *gc_private) +{ + HGDIOBJ hpen; + HGDIOBJ hbr; + GdkColormapPrivate *colormap_private = + (GdkColormapPrivate *) drawable_private->colormap; + + if ((hpen = GetCurrentObject (gc_private->xgc, OBJ_PEN)) == NULL) + g_warning ("gdk_gc_postdraw: GetCurrentObject #1 failed"); + + if ((hbr = GetCurrentObject (gc_private->xgc, OBJ_BRUSH)) == NULL) + g_warning ("gdk_gc_postdraw: GetCurrentObject #2 failed"); + + if (!RestoreDC (gc_private->xgc, gc_private->saved_dc)) + g_warning ("gdk_gc_postdraw: RestoreDC failed"); +#if 0 + if (colormap_private != NULL + && colormap_private->xcolormap->rc_palette + && colormap_private->xcolormap->stale) + { + SelectPalette (gc_private->xgc, GetStockObject (DEFAULT_PALETTE), FALSE); + if (!UnrealizeObject (colormap_private->xcolormap->palette)) + g_warning ("gdk_gc_postraw: UnrealizeObject failed"); + } +#endif + if (drawable_private->window_type == GDK_DRAWABLE_PIXMAP) + { + if (!DeleteDC (gc_private->xgc)) + g_warning ("gdk_gc_postdraw: DeleteDC failed"); + } + else + { + ReleaseDC (gc_private->hwnd, gc_private->xgc); + } + + if (hpen != NULL) + if (!DeleteObject (hpen)) + g_warning ("gdk_gc_postdraw: DeleteObject #1 failed"); + + if (hbr != NULL) + if (!DeleteObject (hbr)) + g_warning ("gdk_gc_postdraw: DeleteObject #2 failed"); + + gc_private->xgc = NULL; +} + +/* This function originally from Jean-Edouard Lachand-Robert, and + * available at www.codeguru.com. Simplified for our needs, now + * handles just one-bit deep bitmaps (in Window parlance, ie those + * that GDK calls bitmaps (and not pixmaps), with zero pixels being + * transparent. + */ + +/* + * BitmapToRegion : Create a region from the "non-transparent" pixels of + * a bitmap + * Author : Jean-Edouard Lachand-Robert + * (http://www.geocities.com/Paris/LeftBank/1160/resume.htm), June 1998. + */ + +HRGN +BitmapToRegion (HBITMAP hBmp) +{ + HRGN hRgn = NULL; + HDC hMemDC; + BITMAP bm; + + struct + { + BITMAPINFOHEADER bmiHeader; +#if 1 + WORD bmiColors[2]; +#else + RGBQUAD bmiColors[2]; +#endif + } bmi; + VOID *pbits8; + HBITMAP hbm8; + struct + { + WORD palVersion; + WORD palNumEntries; + PALETTEENTRY palPalEntry[2]; + } logpal; + static HPALETTE bwPalette = NULL; + + HBITMAP holdBmp; + HDC hDC; + + BITMAP bm8; + HBITMAP holdBmp2; + DWORD maxRects; + RGNDATA *pData; + BYTE *p8; + int x, y; + HRGN h; + + /* Create a B&W palette */ + if (bwPalette == NULL) + { + /* Create a b&w palette */ + logpal.palVersion = 0x300; + logpal.palNumEntries = 2; + logpal.palPalEntry[0].peRed = + logpal.palPalEntry[0].peGreen = + logpal.palPalEntry[0].peBlue = 0; + logpal.palPalEntry[0].peFlags = 0; + logpal.palPalEntry[1].peRed = + logpal.palPalEntry[1].peGreen = + logpal.palPalEntry[1].peBlue = 0xFF; + logpal.palPalEntry[1].peFlags = 0; + if ((bwPalette = CreatePalette ((LOGPALETTE *) &logpal)) == NULL) + g_warning ("BitmapToRegion: CreatePalette failed"); + } + + /* Create a memory DC inside which we will scan the bitmap content */ + hMemDC = CreateCompatibleDC (NULL); + if (!hMemDC) + { + g_warning ("BitmapToRegion: CreateCompatibleDC #1 failed"); + return NULL; + } + + SelectPalette (hMemDC, bwPalette, FALSE); + RealizePalette (hMemDC); + + /* Get bitmap size */ + GetObject(hBmp, sizeof(bm), &bm); + + /* Create a 8 bits depth bitmap and select it into the memory DC */ + bmi.bmiHeader.biSize = sizeof (BITMAPINFOHEADER); + bmi.bmiHeader.biWidth = bm.bmWidth; + bmi.bmiHeader.biHeight = bm.bmHeight; + bmi.bmiHeader.biPlanes = 1; + bmi.bmiHeader.biBitCount = 8; + bmi.bmiHeader.biCompression = BI_RGB; + bmi.bmiHeader.biSizeImage = 0; + bmi.bmiHeader.biXPelsPerMeter = 0; + bmi.bmiHeader.biYPelsPerMeter = 0; + bmi.bmiHeader.biClrUsed = 2; + bmi.bmiHeader.biClrImportant = 2; +#if 1 + bmi.bmiColors[0] = 0; + bmi.bmiColors[1] = 1; + hbm8 = CreateDIBSection (hMemDC, (BITMAPINFO *)&bmi, + DIB_PAL_COLORS, &pbits8, NULL, 0); +#else + bmi.bmiColors[0].rgbBlue = + bmi.bmiColors[0].rgbGreen = + bmi.bmiColors[0].rgbRed = 0x00; + bmi.bmiColors[0].rgbReserved = 0x00; + + bmi.bmiColors[1].rgbBlue = + bmi.bmiColors[1].rgbGreen = + bmi.bmiColors[1].rgbRed = 0xFF; + bmi.bmiColors[0].rgbReserved = 0x00; + + hbm8 = CreateDIBSection (hMemDC, (BITMAPINFO *)&bmi, + DIB_RGB_COLORS, &pbits8, NULL, 0); +#endif + if (!hbm8) + { + g_warning ("BitmapToRegion: CreateDIBSection failed"); + DeleteDC (hMemDC); + return NULL; + } + + holdBmp = (HBITMAP) SelectObject (hMemDC, hbm8); + + /* Create a DC just to copy the bitmap into the memory DC*/ + hDC = CreateCompatibleDC (hMemDC); + if (!hDC) + { + g_warning ("BitmapToRegion: CreateCompatibleDC #2 failed"); + SelectObject (hMemDC, holdBmp); + DeleteObject (hbm8); + DeleteDC (hMemDC); + return NULL; + } + + /* Get how many bytes per row we have for the bitmap bits */ + GetObject (hbm8, sizeof (bm8), &bm8); + + /* Hans Breuer found a fix to the long-standing erroneous behaviour + * on NT 4.0: There seems to be a bug in Win NT 4.0 GDI: scanlines + * in bitmaps are dword aligned on both Win95 and NT. In the case of + * a bitmap with 22 bytes worth of width, GetObject above returns + * with bmWidth == 22. On Win95 bmWidthBytes == 24, as it should be, + * but on NT is it 22. We need to correct this here. + */ + bm8.bmWidthBytes = (((bm8.bmWidthBytes-1)/4)+1)*4; /* dword aligned!! */ + + /* Copy the bitmap into the memory DC*/ + holdBmp2 = (HBITMAP) SelectObject (hDC, hBmp); + + if (!BitBlt (hMemDC, 0, 0, bm.bmWidth, bm.bmHeight, hDC, 0, 0, SRCCOPY)) + { + g_warning ("BitmapToRegion: BitBlt failed"); + SelectObject (hDC, holdBmp2); + SelectObject (hMemDC, holdBmp); + DeleteObject (hbm8); + DeleteDC (hMemDC); + return NULL; + } + SelectObject (hDC, holdBmp2); + DeleteDC (hDC); + + /* For better performances, we will use the ExtCreateRegion() + * function to create the region. This function take a RGNDATA + * structure on entry. We will add rectangles by amount of + * ALLOC_UNIT number in this structure. + */ + #define ALLOC_UNIT 100 + maxRects = ALLOC_UNIT; + + pData = g_malloc (sizeof (RGNDATAHEADER) + (sizeof (RECT) * maxRects)); + pData->rdh.dwSize = sizeof (RGNDATAHEADER); + pData->rdh.iType = RDH_RECTANGLES; + pData->rdh.nCount = pData->rdh.nRgnSize = 0; + SetRect (&pData->rdh.rcBound, MAXLONG, MAXLONG, 0, 0); + + /* Scan each bitmap from bottom to top (the bitmap is inverted vertically)*/ + p8 = (BYTE *) pbits8 + (bm8.bmHeight - 1) * bm8.bmWidthBytes; + for (y = 0; y < bm.bmHeight; y++) + { + /* Scan each bitmap row from left to right*/ + for (x = 0; x < bm.bmWidth; x++) + { + /* Search for a continuous range of "non transparent pixels"*/ + int x0 = x; + BYTE *p = p8 + x; + while (x < bm.bmWidth) + { + if (*p == 0) + /* This pixel is "transparent"*/ + break; + p++; + x++; + } + + if (x > x0) + { + RECT *pr; + /* Add the pixels (x0, y) to (x, y+1) as a new rectangle + * in the region + */ + if (pData->rdh.nCount >= maxRects) + { + maxRects += ALLOC_UNIT; + pData = g_realloc (pData, sizeof(RGNDATAHEADER) + + (sizeof(RECT) * maxRects)); + } + pr = (RECT *) &pData->Buffer; + SetRect (&pr[pData->rdh.nCount], x0, y, x, y+1); + if (x0 < pData->rdh.rcBound.left) + pData->rdh.rcBound.left = x0; + if (y < pData->rdh.rcBound.top) + pData->rdh.rcBound.top = y; + if (x > pData->rdh.rcBound.right) + pData->rdh.rcBound.right = x; + if (y+1 > pData->rdh.rcBound.bottom) + pData->rdh.rcBound.bottom = y+1; + pData->rdh.nCount++; + + /* On Windows98, ExtCreateRegion() may fail if the + * number of rectangles is too large (ie: > + * 4000). Therefore, we have to create the region by + * multiple steps. + */ + if (pData->rdh.nCount == 2000) + { + HRGN h = ExtCreateRegion (NULL, sizeof(RGNDATAHEADER) + (sizeof(RECT) * maxRects), pData); + if (hRgn) + { + CombineRgn(hRgn, hRgn, h, RGN_OR); + DeleteObject(h); + } + else + hRgn = h; + pData->rdh.nCount = 0; + SetRect (&pData->rdh.rcBound, MAXLONG, MAXLONG, 0, 0); + } + } + } + + /* Go to next row (remember, the bitmap is inverted vertically)*/ + p8 -= bm8.bmWidthBytes; + } + + /* Create or extend the region with the remaining rectangles*/ + h = ExtCreateRegion (NULL, sizeof (RGNDATAHEADER) + + (sizeof (RECT) * maxRects), pData); + if (hRgn) + { + CombineRgn (hRgn, hRgn, h, RGN_OR); + DeleteObject (h); + } + else + hRgn = h; + + /* Clean up*/ + SelectObject(hMemDC, holdBmp); + DeleteObject (hbm8); + DeleteDC (hMemDC); + + return hRgn; +} diff --git a/gdk/win32/gdkgc.c b/gdk/win32/gdkgc.c new file mode 100644 index 000000000..407335a7a --- /dev/null +++ b/gdk/win32/gdkgc.c @@ -0,0 +1,1392 @@ +/* GDK - The GIMP Drawing Kit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* + * Modified by the GTK+ Team and others 1997-1999. See the AUTHORS + * file for a list of people on the GTK+ Team. See the ChangeLog + * files for a list of changes. These files are distributed with + * GTK+ at ftp://ftp.gtk.org/pub/gtk/. + */ + +#include "config.h" + +#include + +#include "gdkgc.h" +#include "gdkfont.h" +#include "gdkpixmap.h" +#include "gdkprivate.h" +#include "gdkx.h" + +GdkGC* +gdk_gc_new (GdkWindow *window) +{ + return gdk_gc_new_with_values (window, NULL, 0); +} + +GdkGC* +gdk_gc_new_with_values (GdkWindow *window, + GdkGCValues *values, + GdkGCValuesMask values_mask) +{ + GdkGC *gc; + GdkGCPrivate *private; + static GdkColor black; + static GdkColor white; + static gboolean beenhere = FALSE; + + if (!beenhere) + { + gdk_color_black (gdk_colormap_get_system (), &black); + gdk_color_white (gdk_colormap_get_system (), &white); + beenhere = TRUE; + } + + g_return_val_if_fail (window != NULL, NULL); + + if (GDK_DRAWABLE_DESTROYED (window)) + return NULL; + + private = g_new (GdkGCPrivate, 1); + gc = (GdkGC*) private; + + private->ref_count = 1; + private->rop2 = R2_COPYPEN; + private->fill_style = GDK_SOLID; + private->values_mask = values_mask; + private->values_mask |= GDK_GC_FUNCTION | GDK_GC_FILL; + + GDK_NOTE (MISC, g_print ("gdk_gc_new: {")); + + if (values_mask & GDK_GC_FOREGROUND) + { + private->foreground = values->foreground; + } + else + private->foreground = black; + + if (values_mask & GDK_GC_BACKGROUND) + { + private->background = values->background; + } + else + private->background = white; + + if ((values_mask & GDK_GC_FONT) && (values->font->type == GDK_FONT_FONT + || values->font->type == GDK_FONT_FONTSET)) + { + private->font = values->font; + gdk_font_ref (private->font); + GDK_NOTE (MISC, g_print (" font")); + } + else + private->font = NULL; + + if (values_mask & GDK_GC_FUNCTION) + { + switch (values->function) + { + case GDK_COPY: + private->rop2 = R2_COPYPEN; break; + case GDK_INVERT: + private->rop2 = R2_NOT; break; + case GDK_XOR: + private->rop2 = R2_XORPEN; break; + case GDK_CLEAR: + private->rop2 = R2_BLACK; break; + case GDK_AND: + private->rop2 = R2_MASKPEN; break; + case GDK_AND_REVERSE: + private->rop2 = R2_MASKPENNOT; break; + case GDK_AND_INVERT: + private->rop2 = R2_MASKNOTPEN; break; + case GDK_NOOP: + private->rop2 = R2_NOP; break; + case GDK_OR: + private->rop2 = R2_MERGEPEN; break; + case GDK_EQUIV: + private->rop2 = R2_NOTXORPEN; break; + case GDK_OR_REVERSE: + private->rop2 = R2_MERGEPENNOT; break; + case GDK_COPY_INVERT: + private->rop2 = R2_NOTCOPYPEN; break; + case GDK_OR_INVERT: + private->rop2 = R2_MERGENOTPEN; break; + case GDK_NAND: + private->rop2 = R2_NOTMASKPEN; break; + case GDK_SET: + private->rop2 = R2_WHITE; break; + } + GDK_NOTE (MISC, g_print (" function=%d", private->rop2)); + } + + if (values_mask & GDK_GC_FILL) + { + private->fill_style = values->fill; + GDK_NOTE (MISC, g_print (" fill=%d", private->fill_style)); + } + + if (values_mask & GDK_GC_TILE) + { + private->tile = values->tile; + gdk_pixmap_ref (private->tile); + GDK_NOTE (MISC, g_print (" tile=%#x", GDK_DRAWABLE_XID (private->tile))); + } + else + private->tile = NULL; + + if (values_mask & GDK_GC_STIPPLE) + { + private->stipple = values->stipple; + gdk_pixmap_ref (private->stipple); + GDK_NOTE (MISC, g_print (" stipple=%#x", GDK_DRAWABLE_XID (private->stipple))); + } + else + private->stipple = NULL; + + if (values_mask & GDK_GC_CLIP_MASK) + { + private->clip_region = + BitmapToRegion ((HBITMAP) GDK_DRAWABLE_XID (values->clip_mask)); + GDK_NOTE (MISC, g_print (" clip=%#x", private->clip_region)); + } + else + private->clip_region = NULL; + + if (values_mask & GDK_GC_SUBWINDOW) + { + private->subwindow_mode = values->subwindow_mode; + GDK_NOTE (MISC, g_print (" subw=%d", private->subwindow_mode)); + } + + if (values_mask & GDK_GC_TS_X_ORIGIN) + { + private->ts_x_origin = values->ts_x_origin; + GDK_NOTE (MISC, g_print (" ts_x=%d", private->ts_x_origin)); + } + + if (values_mask & GDK_GC_TS_Y_ORIGIN) + { + private->ts_y_origin = values->ts_y_origin; + GDK_NOTE (MISC, g_print (" ts_y=%d", private->ts_y_origin)); + } + + if (values_mask & GDK_GC_CLIP_X_ORIGIN) + { + private->clip_x_origin = values->clip_x_origin; + GDK_NOTE (MISC, g_print (" clip_x=%d", private->clip_x_origin)); + } + + if (values_mask & GDK_GC_CLIP_Y_ORIGIN) + { + private->clip_y_origin = values->clip_y_origin; + GDK_NOTE (MISC, g_print (" clip_y=%d", private->clip_y_origin)); + } + + if (values_mask & GDK_GC_EXPOSURES) + { + private->graphics_exposures = values->graphics_exposures; + GDK_NOTE (MISC, g_print (" exp=%d", private->graphics_exposures)); + } + + private->pen_style = PS_GEOMETRIC; + private->pen_width = 1; + + if (values_mask & (GDK_GC_LINE_WIDTH | GDK_GC_LINE_STYLE)) + { + if (values_mask & GDK_GC_LINE_WIDTH) + { + private->pen_width = values->line_width; + GDK_NOTE (MISC, g_print (" pw=%d", private->pen_width)); + } + if (values_mask & GDK_GC_LINE_STYLE) + { + switch (values->line_style) + { + case GDK_LINE_SOLID: + private->pen_style |= PS_SOLID; break; + case GDK_LINE_ON_OFF_DASH: + case GDK_LINE_DOUBLE_DASH: /* ??? */ + private->pen_style |= PS_DASH; break; + } + GDK_NOTE (MISC, g_print (" ps=%#x", private->pen_style)); + } + } + + if (values_mask & GDK_GC_CAP_STYLE) + { + switch (values->cap_style) + { + case GDK_CAP_NOT_LAST: /* ??? */ + case GDK_CAP_BUTT: + private->pen_style |= PS_ENDCAP_FLAT; break; + case GDK_CAP_ROUND: + private->pen_style |= PS_ENDCAP_ROUND; break; + case GDK_CAP_PROJECTING: + private->pen_style |= PS_ENDCAP_SQUARE; break; + } + GDK_NOTE (MISC, g_print (" ps=%#x", private->pen_style)); + } + + if (values_mask & GDK_GC_JOIN_STYLE) + { + switch (values->join_style) + { + case GDK_JOIN_MITER: + private->pen_style |= PS_JOIN_MITER; + break; + case GDK_JOIN_ROUND: + private->pen_style |= PS_JOIN_ROUND; + break; + case GDK_JOIN_BEVEL: + private->pen_style |= PS_JOIN_BEVEL; + break; + } + GDK_NOTE (MISC, g_print (" ps=%#x", private->pen_style)); + } + + private->hwnd = NULL; + private->xgc = NULL; + + GDK_NOTE (MISC, g_print ("} = %p\n", private)); + + return gc; +} + +void +gdk_gc_destroy (GdkGC *gc) +{ + gdk_gc_unref (gc); +} + +GdkGC * +gdk_gc_ref (GdkGC *gc) +{ + GdkGCPrivate *private = (GdkGCPrivate*) gc; + + g_return_val_if_fail (gc != NULL, NULL); + private->ref_count += 1; + + return gc; +} + +void +gdk_gc_unref (GdkGC *gc) +{ + GdkGCPrivate *private = (GdkGCPrivate*) gc; + + g_return_if_fail (gc != NULL); + + if (private->ref_count > 1) + private->ref_count -= 1; + else + { + if (private->values_mask & GDK_GC_FONT) + gdk_font_unref (private->font); + + if (private->values_mask & GDK_GC_TILE) + gdk_pixmap_unref (private->tile); + + if (private->values_mask & GDK_GC_STIPPLE) + gdk_pixmap_unref (private->stipple); + + if (private->values_mask & GDK_GC_CLIP_MASK) + DeleteObject (private->clip_region); + + g_free (gc); + } +} + +void +gdk_gc_get_values (GdkGC *gc, + GdkGCValues *values) +{ + GdkGCPrivate *private; + + g_return_if_fail (gc != NULL); + g_return_if_fail (values != NULL); + + private = (GdkGCPrivate*) gc; + + values->foreground = private->foreground; + values->background = private->background; + values->font = private->font; + + switch (private->rop2) + { + case R2_COPYPEN: + values->function = GDK_COPY; break; + case R2_NOT: + values->function = GDK_INVERT; break; + case R2_XORPEN: + values->function = GDK_XOR; break; + case R2_BLACK: + values->function = GDK_CLEAR; break; + case R2_MASKPEN: + values->function = GDK_AND; break; + case R2_MASKPENNOT: + values->function = GDK_AND_REVERSE; break; + case R2_MASKNOTPEN: + values->function = GDK_AND_INVERT; break; + case R2_NOP: + values->function = GDK_NOOP; break; + case R2_MERGEPEN: + values->function = GDK_OR; break; + case R2_NOTXORPEN: + values->function = GDK_EQUIV; break; + case R2_MERGEPENNOT: + values->function = GDK_OR_REVERSE; break; + case R2_NOTCOPYPEN: + values->function = GDK_COPY_INVERT; break; + case R2_MERGENOTPEN: + values->function = GDK_OR_INVERT; break; + case R2_NOTMASKPEN: + values->function = GDK_NAND; break; + case R2_WHITE: + values->function = GDK_SET; break; + } + + values->fill = private->fill_style; + + values->tile = private->tile; + values->stipple = private->stipple; + if (private->clip_region != NULL) + { + RECT rect; + HBRUSH hbr; + HDC hdc; + HGDIOBJ oldbitmap; + GdkPixmap *pixmap; + + GetRgnBox (private->clip_region, &rect); + pixmap = + gdk_pixmap_new (NULL, rect.right - rect.left, rect.bottom - rect.top, + 1); + hbr = GetStockObject (WHITE_BRUSH); + if ((hdc = CreateCompatibleDC (NULL)) == NULL) + g_warning ("gdk_gc_get_values: CreateCompatibleDC failed"); + if ((oldbitmap = + SelectObject (hdc, GDK_DRAWABLE_XID (pixmap))) == NULL) + g_warning ("gdk_gc_get_values: SelectObject #1 failed"); + hbr = GetStockObject (BLACK_BRUSH); + if (!FillRect (hdc, &rect, hbr)) + g_warning ("gdk_gc_get_values: FillRect failed"); + hbr = GetStockObject (WHITE_BRUSH); + if (!FillRgn (hdc, private->clip_region, hbr)) + g_warning ("gdk_gc_get_values: FillRgn failed"); + if (SelectObject (hdc, oldbitmap) == NULL) + g_warning ("gdk_gc_get_values: SelectObject #2 failed"); + DeleteDC (hdc); + values->clip_mask = pixmap; + } + else + values->clip_mask = NULL; + values->subwindow_mode = private->subwindow_mode; + values->ts_x_origin = private->ts_x_origin; + values->ts_y_origin = private->ts_y_origin; + values->clip_x_origin = private->clip_x_origin; + values->clip_y_origin = private->clip_y_origin; + values->graphics_exposures = private->graphics_exposures; + values->line_width = private->pen_width; + + if (private->pen_style & PS_SOLID) + values->line_style = GDK_LINE_SOLID; + else if (private->pen_style & PS_DASH) + values->line_style = GDK_LINE_ON_OFF_DASH; + else + values->line_style = GDK_LINE_SOLID; + + /* PS_ENDCAP_ROUND is zero */ + if (private->pen_style & PS_ENDCAP_FLAT) + values->cap_style = GDK_CAP_BUTT; + else if (private->pen_style & PS_ENDCAP_SQUARE) + values->cap_style = GDK_CAP_PROJECTING; + else + values->cap_style = GDK_CAP_ROUND; + + /* PS_JOIN_ROUND is zero */ + if (private->pen_style & PS_JOIN_MITER) + values->join_style = GDK_JOIN_MITER; + else if (private->pen_style & PS_JOIN_BEVEL) + values->join_style = GDK_JOIN_BEVEL; + else + values->join_style = GDK_JOIN_ROUND; +} + +void +gdk_gc_set_foreground (GdkGC *gc, + GdkColor *color) +{ + GdkGCPrivate *private; + + g_return_if_fail (gc != NULL); + g_return_if_fail (color != NULL); + + private = (GdkGCPrivate*) gc; + { + GDK_NOTE (MISC, g_print ("gdk_gc_set_foreground: (%d) %s\n", + private, gdk_color_to_string (color))); + private->foreground = *color; + private->values_mask |= GDK_GC_FOREGROUND; + } +} + +void +gdk_gc_set_background (GdkGC *gc, + GdkColor *color) +{ + GdkGCPrivate *private; + + g_return_if_fail (gc != NULL); + g_return_if_fail (color != NULL); + + private = (GdkGCPrivate*) gc; + + GDK_NOTE (MISC, g_print ("gdk_gc_set_backround: (%d) %s\n", + private, gdk_color_to_string(color))); + private->background = *color; + private->values_mask |= GDK_GC_BACKGROUND; +} + +void +gdk_gc_set_font (GdkGC *gc, + GdkFont *font) +{ + GdkGCPrivate *gc_private; + GdkFontPrivate *font_private; + gchar *xlfd; + + g_return_if_fail (gc != NULL); + g_return_if_fail (font != NULL); + + if (font->type == GDK_FONT_FONT + || font->type == GDK_FONT_FONTSET) + { + gc_private = (GdkGCPrivate*) gc; + + GDK_NOTE (MISC, (xlfd = gdk_font_xlfd_create (font), + g_print ("gdk_gc_set_font: (%d) %s\n", + gc_private, xlfd), + gdk_font_xlfd_free (xlfd))); + + if (gc_private->font != NULL) + gdk_font_unref (gc_private->font); + gc_private->font = font; + gdk_font_ref (gc_private->font); + gc_private->values_mask |= GDK_GC_FONT; + } +} + +void +gdk_gc_set_function (GdkGC *gc, + GdkFunction function) +{ + GdkGCPrivate *private; + + g_return_if_fail (gc != NULL); + + private = (GdkGCPrivate*) gc; + + GDK_NOTE (MISC, g_print ("gdk_gc_set_function: (%d) %d\n", private, function)); + + switch (function) + { + case GDK_COPY: + private->rop2 = R2_COPYPEN; break; + case GDK_INVERT: + private->rop2 = R2_NOT; break; + case GDK_XOR: + private->rop2 = R2_XORPEN; break; + case GDK_CLEAR: + private->rop2 = R2_BLACK; break; + case GDK_AND: + private->rop2 = R2_MASKPEN; break; + case GDK_AND_REVERSE: + private->rop2 = R2_MASKPENNOT; break; + case GDK_AND_INVERT: + private->rop2 = R2_MASKNOTPEN; break; + case GDK_NOOP: + private->rop2 = R2_NOP; break; + case GDK_OR: + private->rop2 = R2_MERGEPEN; break; + case GDK_EQUIV: + private->rop2 = R2_NOTXORPEN; break; + case GDK_OR_REVERSE: + private->rop2 = R2_MERGEPENNOT; break; + case GDK_COPY_INVERT: + private->rop2 = R2_NOTCOPYPEN; break; + case GDK_OR_INVERT: + private->rop2 = R2_MERGENOTPEN; break; + case GDK_NAND: + private->rop2 = R2_NOTMASKPEN; break; + case GDK_SET: + private->rop2 = R2_WHITE; break; + } + private->values_mask |= GDK_GC_FUNCTION; +} + +void +gdk_gc_set_fill (GdkGC *gc, + GdkFill fill) +{ + GdkGCPrivate *private; + + g_return_if_fail (gc != NULL); + + private = (GdkGCPrivate*) gc; + + private->fill_style = fill; + private->values_mask |= GDK_GC_FILL; +} + +void +gdk_gc_set_tile (GdkGC *gc, + GdkPixmap *tile) +{ + GdkGCPrivate *private; + HBITMAP pixmap; + + g_return_if_fail (gc != NULL); + + private = (GdkGCPrivate*) gc; + + pixmap = NULL; + + if (tile) + pixmap = GDK_DRAWABLE_XID (tile); + + if (private->tile != NULL) + gdk_pixmap_unref (private->tile); + private->tile = tile; + if (tile) + gdk_pixmap_ref (tile); + if (pixmap != NULL) + private->values_mask |= GDK_GC_TILE; + else + private->values_mask &= ~GDK_GC_TILE; +} + +void +gdk_gc_set_stipple (GdkGC *gc, + GdkPixmap *stipple) +{ + GdkGCPrivate *private; + HBITMAP pixmap; + + g_return_if_fail (gc != NULL); + + private = (GdkGCPrivate*) gc; + + pixmap = NULL; + + if (stipple) + pixmap = GDK_DRAWABLE_XID (stipple); + + if (private->stipple != NULL) + gdk_pixmap_unref (private->stipple); + private->stipple = stipple; + if (stipple) + gdk_pixmap_ref (stipple); + if (pixmap != NULL) + private->values_mask |= GDK_GC_STIPPLE; + else + private->values_mask &= ~GDK_GC_STIPPLE; +} + +void +gdk_gc_set_ts_origin (GdkGC *gc, + gint x, + gint y) +{ + GdkGCPrivate *private; + + g_return_if_fail (gc != NULL); + + private = (GdkGCPrivate*) gc; + + private->ts_x_origin = x; + private->ts_y_origin = y; + private->values_mask |= GDK_GC_TS_X_ORIGIN |GDK_GC_TS_Y_ORIGIN; +} + +void +gdk_gc_set_clip_origin (GdkGC *gc, + gint x, + gint y) +{ + GdkGCPrivate *private; + + g_return_if_fail (gc != NULL); + + private = (GdkGCPrivate*) gc; + + GDK_NOTE (MISC, g_print ("gdk_gc_set_clip_origin: (%d) +%d+%d\n", + private, x, y)); + + private->clip_x_origin = x; + private->clip_y_origin = y; + private->values_mask |= GDK_GC_CLIP_X_ORIGIN |GDK_GC_CLIP_Y_ORIGIN; +} + +void +gdk_gc_set_clip_mask (GdkGC *gc, + GdkBitmap *mask) +{ + GdkGCPrivate *private; + HBITMAP xmask; + + g_return_if_fail (gc != NULL); + + if (mask) + { + if (GDK_DRAWABLE_DESTROYED (mask)) + return; + xmask = GDK_DRAWABLE_XID (mask); + } + else + xmask = NULL; + + private = (GdkGCPrivate*) gc; + + GDK_NOTE (MISC, g_print ("gdk_gc_set_clip_mask: (%d) %#x\n", private, xmask)); + + if (private->clip_region != NULL) + if (!DeleteObject (private->clip_region)) + g_warning ("gdk_gc_set_clip_mask: DeleteObject failed"); + if (xmask != NULL) + { + private->clip_region = BitmapToRegion (xmask); + { + RECT rect; + GetRgnBox (private->clip_region, &rect); + GDK_NOTE (MISC, g_print ("...box = %dx%d@+%d+%d\n", + rect.right - rect.left, rect.bottom - rect.top, + rect.left, rect.top)); + } +#if 0 + /* Test code that sets clip region to whole of mask */ + { + BITMAP bm; + GetObject (xmask, sizeof (bm), &bm); + private->clip_region = CreateRectRgn (0, 0, bm.bmWidth, bm.bmHeight); + } +#endif + private->values_mask |= GDK_GC_CLIP_MASK; + } + else + { + private->values_mask &= ~GDK_GC_CLIP_MASK; + private->clip_region = NULL; + } +} + +void +gdk_gc_set_clip_rectangle (GdkGC *gc, + GdkRectangle *rectangle) +{ + GdkGCPrivate *private; + + g_return_if_fail (gc != NULL); + + private = (GdkGCPrivate*) gc; + + if (private->clip_region != NULL) + if (!DeleteObject (private->clip_region)) + g_warning ("gdk_gc_set_clip_rectangle: DeleteObject failed"); + if (rectangle) + { + GDK_NOTE (MISC, + g_print ("gdk_gc_set_clip_rectangle: (%d) %dx%d@+%d+%d\n", + private, + rectangle->width, rectangle->height, + rectangle->x, rectangle->y)); + if ((private->clip_region = + CreateRectRgn (rectangle->x, rectangle->y, + rectangle->x + rectangle->width, + rectangle->y + rectangle->height)) == NULL) + g_warning ("gdk_gc_set_clip_rectangle: CreateRectRgn failed"); + + private->values_mask |= GDK_GC_CLIP_MASK; + } + else + { + GDK_NOTE (MISC, g_print ("gdk_gc_set_clip_rectangle: (%d) None\n", + private)); + private->clip_region = NULL; + private->values_mask &= ~GDK_GC_CLIP_MASK; + } + private->values_mask &= ~(GDK_GC_CLIP_X_ORIGIN |GDK_GC_CLIP_Y_ORIGIN); +} + +void +gdk_gc_set_clip_region (GdkGC *gc, + GdkRegion *region) +{ + GdkGCPrivate *private; + + g_return_if_fail (gc != NULL); + + private = (GdkGCPrivate*) gc; + + GDK_NOTE (MISC, g_print ("gdk_gc_set_clip_region: (%d) %s\n", + private, (region != NULL ? "xxx" : "None"))); + + if (private->clip_region != NULL) + if (!DeleteObject (private->clip_region)) + g_warning ("gdk_gc_set_clip_region: DeleteObject failed"); + if (region) + { + GdkRegionPrivate *region_private; + + region_private = (GdkRegionPrivate*) region; + private->clip_region = CreateRectRgn (1, 1, 0, 0); + CombineRgn (private->clip_region, region_private->xregion, NULL, RGN_COPY); + private->values_mask |= GDK_GC_CLIP_MASK; + } + else + { + private->clip_region = NULL; + private->values_mask &= ~GDK_GC_CLIP_MASK; + } +} + +void +gdk_gc_set_subwindow (GdkGC *gc, + GdkSubwindowMode mode) +{ + GdkGCPrivate *private; + + g_return_if_fail (gc != NULL); + + private = (GdkGCPrivate*) gc; + + private->subwindow_mode = mode; + private->values_mask |= GDK_GC_SUBWINDOW; +} + +void +gdk_gc_set_exposures (GdkGC *gc, + gint exposures) +{ + GdkGCPrivate *private; + + g_return_if_fail (gc != NULL); + + private = (GdkGCPrivate*) gc; + + private->graphics_exposures = exposures; + private->values_mask |= GDK_GC_EXPOSURES;; +} + +void +gdk_gc_set_line_attributes (GdkGC *gc, + gint line_width, + GdkLineStyle line_style, + GdkCapStyle cap_style, + GdkJoinStyle join_style) +{ + GdkGCPrivate *private; + int xline_style; + int xcap_style; + int xjoin_style; + + g_return_if_fail (gc != NULL); + + private = (GdkGCPrivate*) gc; + + GDK_NOTE (MISC, + g_print ("gdk_gc_set_line_attributes: (%d) %d %s %s %s\n", + private, line_width, + (line_style == GDK_LINE_SOLID ? "SOLID" : + (line_style == GDK_LINE_ON_OFF_DASH ? "ON_OFF_DASH" : + (line_style == GDK_LINE_DOUBLE_DASH ? "DOUBLE_DASH" : + "???"))), + (cap_style == GDK_CAP_BUTT ? "BUTT" : + (cap_style == GDK_CAP_ROUND ? "ROUND" : + (cap_style == GDK_CAP_PROJECTING ? "PROJECTING" : + "???"))), + (join_style == GDK_JOIN_MITER ? "MITER" : + (join_style == GDK_JOIN_ROUND ? "ROUND" : + (join_style == GDK_JOIN_BEVEL ? "BEVEL" : + "???"))))); + + private->pen_width = line_width; + + /* Mask old style bits away */ + private->pen_style &= ~(PS_STYLE_MASK|PS_ENDCAP_MASK|PS_JOIN_MASK); + + /* Add new bits */ + switch (line_style) + { + case GDK_LINE_SOLID: + private->pen_style |= PS_SOLID; break; + case GDK_LINE_ON_OFF_DASH: + case GDK_LINE_DOUBLE_DASH: /* ??? */ + private->pen_style |= PS_DASH; break; + } + + switch (cap_style) + { + case GDK_CAP_NOT_LAST: + /* ??? */ + break; + case GDK_CAP_BUTT: + private->pen_style |= PS_ENDCAP_FLAT; break; + case GDK_CAP_ROUND: + private->pen_style |= PS_ENDCAP_ROUND; break; + case GDK_CAP_PROJECTING: + private->pen_style |= PS_ENDCAP_SQUARE; break; + } + + switch (join_style) + { + case GDK_JOIN_MITER: + private->pen_style |= PS_JOIN_MITER; + break; + case GDK_JOIN_ROUND: + private->pen_style |= PS_JOIN_ROUND; + break; + case GDK_JOIN_BEVEL: + private->pen_style |= PS_JOIN_BEVEL; + break; + } +} + +void +gdk_gc_set_dashes (GdkGC *gc, + gint dash_offset, + gchar dash_list[], + gint n) +{ + GdkGCPrivate *private; + + g_return_if_fail (gc != NULL); + g_return_if_fail (dash_list != NULL); + + /* XXX ??? */ + + private = (GdkGCPrivate *) gc; + + private->pen_style &= ~(PS_STYLE_MASK); + private->pen_style |= PS_DASH; +} + +void +gdk_gc_copy (GdkGC *dst_gc, GdkGC *src_gc) +{ + GdkGCPrivate *dst_private, *src_private; + + src_private = (GdkGCPrivate *) src_gc; + dst_private = (GdkGCPrivate *) dst_gc; + + *dst_private = *src_private; +} + +HDC +gdk_gc_predraw (GdkDrawablePrivate *drawable_private, + GdkGCPrivate *gc_private) +{ + GdkColormapPrivate *colormap_private = + (GdkColormapPrivate *) drawable_private->colormap; + COLORREF bg; + COLORREF fg; + LOGBRUSH logbrush; + HPEN hpen; + HBRUSH hbr; + + g_assert (gc_private->xgc == NULL); + + if (drawable_private->window_type == GDK_DRAWABLE_PIXMAP) + { + if ((gc_private->xgc = CreateCompatibleDC (NULL)) == NULL) + g_warning ("gdk_gc_predraw: CreateCompatibleDC failed"); + + if ((gc_private->saved_dc = SaveDC (gc_private->xgc)) == 0) + g_warning ("gdk_gc_predraw: SaveDC #1 failed"); + + if (SelectObject (gc_private->xgc, drawable_private->xwindow) == NULL) + g_warning ("gdk_gc_predraw: SelectObject #1 failed"); + } + else + { + if ((gc_private->xgc = GetDC (drawable_private->xwindow)) == NULL) + g_warning ("gdk_gc_predraw: GetDC failed"); + + if ((gc_private->saved_dc = SaveDC (gc_private->xgc)) == 0) + g_warning ("gdk_gc_predraw: SaveDC #2 failed"); + } + + gc_private->hwnd = drawable_private->xwindow; + + if (colormap_private == NULL) + { + /* A 1 bit deep bitmap */ + struct + { + WORD palVersion; + WORD palNumEntries; + PALETTEENTRY palPalEntry[2]; + } logpal; + static HPALETTE hpal = NULL; + + if (hpal == NULL) + { + /* Create a b&w palette */ + logpal.palVersion = 0x300; + logpal.palNumEntries = 2; + logpal.palPalEntry[0].peRed = + logpal.palPalEntry[0].peGreen = + logpal.palPalEntry[0].peBlue = 0x00; + logpal.palPalEntry[0].peFlags = 0x00; + logpal.palPalEntry[1].peRed = + logpal.palPalEntry[1].peGreen = + logpal.palPalEntry[1].peBlue = 0xFF; + logpal.palPalEntry[1].peFlags = 0x00; + if ((hpal = CreatePalette ((LOGPALETTE *) &logpal)) == NULL) + g_warning ("gdk_gc_predraw: CreatePalette failed"); + } + SelectPalette (gc_private->xgc, hpal, FALSE); + RealizePalette (gc_private->xgc); + fg = PALETTEINDEX (gc_private->foreground.pixel); + } + else if (colormap_private != NULL + && colormap_private->xcolormap->rc_palette) + { + int k; + if (SelectPalette (gc_private->xgc, + colormap_private->xcolormap->palette, FALSE) == NULL) + g_warning ("gdk_gc_predraw: SelectPalette failed"); + if (TRUE || colormap_private->xcolormap->stale) + { + if ((k = RealizePalette (gc_private->xgc)) == GDI_ERROR) + g_warning ("gdk_gc_predraw: RealizePalette failed"); + colormap_private->xcolormap->stale = FALSE; + } +#if 0 + g_print ("Selected palette %#x for gc %#x, realized %d colors\n", + colormap_private->xcolormap->palette, gc_private->xgc, k); +#endif + fg = PALETTEINDEX (gc_private->foreground.pixel); + } + else + { + COLORREF foreground = RGB (gc_private->foreground.red >> 8, + gc_private->foreground.green >> 8, + gc_private->foreground.blue >> 8); + fg = GetNearestColor (gc_private->xgc, foreground); + } + logbrush.lbStyle = BS_SOLID; + logbrush.lbColor = fg; + if ((hpen = ExtCreatePen (gc_private->pen_style, gc_private->pen_width, + &logbrush, 0, NULL)) == NULL) + g_warning ("gdk_gc_predraw: CreatePen failed"); + + if (SelectObject (gc_private->xgc, hpen) == NULL) + g_warning ("gdk_gc_predraw: SelectObject #2 failed"); + + if (SetTextColor (gc_private->xgc, fg) == CLR_INVALID) + g_warning ("gdk_gc_predraw: SetTextColor failed"); + +#if 0 + switch (gc_private->fill_style) + { + case GDK_STIPPLED: + { + GdkPixmap *stipple = gc_private->stipple; + GdkPixmapPrivate *stipple_private = (GdkPixmapPrivate *) stipple; + HBITMAP hbm = stipple_private->xwindow; + if (NULL == (hbr = CreatePatternBrush (hbm))) + g_warning ("gdk_gc_predraw: CreatePatternBrush failed"); + +#ifdef NATIVE_WIN16 + SetBrushOrg (gc_private->xgc, gc_private->ts_x_origin, + gc_private->ts_y_origin); +#else + SetBrushOrgEx(gc_private->xgc, gc_private->ts_x_origin, + gc_private->ts_y_origin, NULL); +#endif + } + break; + case GDK_SOLID: + default: + if ((hbr = CreateSolidBrush (fg)) == NULL) + g_warning ("gdk_gc_predraw: CreateSolidBrush failed"); + break; + } +#else + if ((hbr = CreateSolidBrush (fg)) == NULL) + g_warning ("gdk_gc_predraw: CreateSolidBrush failed"); +#endif + if (SelectObject (gc_private->xgc, hbr) == NULL) + g_warning ("gdk_gc_predraw: SelectObject #3 failed"); + + if (gc_private->values_mask & GDK_GC_BACKGROUND) + { + if (colormap_private == NULL) + { + /* a bitmap */ + bg = PALETTEINDEX (gc_private->background.pixel); + } + else if (colormap_private != NULL + && colormap_private->xcolormap->rc_palette) + { + bg = PALETTEINDEX (gc_private->background.pixel); + } + else + { + COLORREF background = RGB (gc_private->background.red >> 8, + gc_private->background.green >> 8, + gc_private->background.blue >> 8); + bg = GetNearestColor (gc_private->xgc, background); + } + if (SetBkColor (gc_private->xgc, bg) == CLR_INVALID) + g_warning ("gdk_gc_predraw: SetBkColor failed"); + } + + if (SetBkMode (gc_private->xgc, TRANSPARENT) == 0) + g_warning ("gdk_gc_predraw: SetBkMode failed"); + + if (SetTextAlign (gc_private->xgc, TA_BASELINE) == GDI_ERROR) + g_warning ("gdk_gc_predraw: SetTextAlign failed"); + + if (gc_private->values_mask & GDK_GC_FUNCTION) + if (SetROP2 (gc_private->xgc, gc_private->rop2) == 0) + g_warning ("gdk_gc_predraw: SetROP2 failed"); + + if (gc_private->values_mask & GDK_GC_CLIP_MASK + && gc_private->clip_region != NULL) + { + if (gc_private->values_mask & (GDK_GC_CLIP_X_ORIGIN | GDK_GC_CLIP_Y_ORIGIN)) + OffsetRgn (gc_private->clip_region, + gc_private->clip_x_origin, gc_private->clip_y_origin); + SelectClipRgn (gc_private->xgc, gc_private->clip_region); + } + + return gc_private->xgc; +} + +void +gdk_gc_postdraw (GdkDrawablePrivate *drawable_private, + GdkGCPrivate *gc_private) +{ + HGDIOBJ hpen; + HGDIOBJ hbr; + GdkColormapPrivate *colormap_private = + (GdkColormapPrivate *) drawable_private->colormap; + + if ((hpen = GetCurrentObject (gc_private->xgc, OBJ_PEN)) == NULL) + g_warning ("gdk_gc_postdraw: GetCurrentObject #1 failed"); + + if ((hbr = GetCurrentObject (gc_private->xgc, OBJ_BRUSH)) == NULL) + g_warning ("gdk_gc_postdraw: GetCurrentObject #2 failed"); + + if (!RestoreDC (gc_private->xgc, gc_private->saved_dc)) + g_warning ("gdk_gc_postdraw: RestoreDC failed"); +#if 0 + if (colormap_private != NULL + && colormap_private->xcolormap->rc_palette + && colormap_private->xcolormap->stale) + { + SelectPalette (gc_private->xgc, GetStockObject (DEFAULT_PALETTE), FALSE); + if (!UnrealizeObject (colormap_private->xcolormap->palette)) + g_warning ("gdk_gc_postraw: UnrealizeObject failed"); + } +#endif + if (drawable_private->window_type == GDK_DRAWABLE_PIXMAP) + { + if (!DeleteDC (gc_private->xgc)) + g_warning ("gdk_gc_postdraw: DeleteDC failed"); + } + else + { + ReleaseDC (gc_private->hwnd, gc_private->xgc); + } + + if (hpen != NULL) + if (!DeleteObject (hpen)) + g_warning ("gdk_gc_postdraw: DeleteObject #1 failed"); + + if (hbr != NULL) + if (!DeleteObject (hbr)) + g_warning ("gdk_gc_postdraw: DeleteObject #2 failed"); + + gc_private->xgc = NULL; +} + +/* This function originally from Jean-Edouard Lachand-Robert, and + * available at www.codeguru.com. Simplified for our needs, now + * handles just one-bit deep bitmaps (in Window parlance, ie those + * that GDK calls bitmaps (and not pixmaps), with zero pixels being + * transparent. + */ + +/* + * BitmapToRegion : Create a region from the "non-transparent" pixels of + * a bitmap + * Author : Jean-Edouard Lachand-Robert + * (http://www.geocities.com/Paris/LeftBank/1160/resume.htm), June 1998. + */ + +HRGN +BitmapToRegion (HBITMAP hBmp) +{ + HRGN hRgn = NULL; + HDC hMemDC; + BITMAP bm; + + struct + { + BITMAPINFOHEADER bmiHeader; +#if 1 + WORD bmiColors[2]; +#else + RGBQUAD bmiColors[2]; +#endif + } bmi; + VOID *pbits8; + HBITMAP hbm8; + struct + { + WORD palVersion; + WORD palNumEntries; + PALETTEENTRY palPalEntry[2]; + } logpal; + static HPALETTE bwPalette = NULL; + + HBITMAP holdBmp; + HDC hDC; + + BITMAP bm8; + HBITMAP holdBmp2; + DWORD maxRects; + RGNDATA *pData; + BYTE *p8; + int x, y; + HRGN h; + + /* Create a B&W palette */ + if (bwPalette == NULL) + { + /* Create a b&w palette */ + logpal.palVersion = 0x300; + logpal.palNumEntries = 2; + logpal.palPalEntry[0].peRed = + logpal.palPalEntry[0].peGreen = + logpal.palPalEntry[0].peBlue = 0; + logpal.palPalEntry[0].peFlags = 0; + logpal.palPalEntry[1].peRed = + logpal.palPalEntry[1].peGreen = + logpal.palPalEntry[1].peBlue = 0xFF; + logpal.palPalEntry[1].peFlags = 0; + if ((bwPalette = CreatePalette ((LOGPALETTE *) &logpal)) == NULL) + g_warning ("BitmapToRegion: CreatePalette failed"); + } + + /* Create a memory DC inside which we will scan the bitmap content */ + hMemDC = CreateCompatibleDC (NULL); + if (!hMemDC) + { + g_warning ("BitmapToRegion: CreateCompatibleDC #1 failed"); + return NULL; + } + + SelectPalette (hMemDC, bwPalette, FALSE); + RealizePalette (hMemDC); + + /* Get bitmap size */ + GetObject(hBmp, sizeof(bm), &bm); + + /* Create a 8 bits depth bitmap and select it into the memory DC */ + bmi.bmiHeader.biSize = sizeof (BITMAPINFOHEADER); + bmi.bmiHeader.biWidth = bm.bmWidth; + bmi.bmiHeader.biHeight = bm.bmHeight; + bmi.bmiHeader.biPlanes = 1; + bmi.bmiHeader.biBitCount = 8; + bmi.bmiHeader.biCompression = BI_RGB; + bmi.bmiHeader.biSizeImage = 0; + bmi.bmiHeader.biXPelsPerMeter = 0; + bmi.bmiHeader.biYPelsPerMeter = 0; + bmi.bmiHeader.biClrUsed = 2; + bmi.bmiHeader.biClrImportant = 2; +#if 1 + bmi.bmiColors[0] = 0; + bmi.bmiColors[1] = 1; + hbm8 = CreateDIBSection (hMemDC, (BITMAPINFO *)&bmi, + DIB_PAL_COLORS, &pbits8, NULL, 0); +#else + bmi.bmiColors[0].rgbBlue = + bmi.bmiColors[0].rgbGreen = + bmi.bmiColors[0].rgbRed = 0x00; + bmi.bmiColors[0].rgbReserved = 0x00; + + bmi.bmiColors[1].rgbBlue = + bmi.bmiColors[1].rgbGreen = + bmi.bmiColors[1].rgbRed = 0xFF; + bmi.bmiColors[0].rgbReserved = 0x00; + + hbm8 = CreateDIBSection (hMemDC, (BITMAPINFO *)&bmi, + DIB_RGB_COLORS, &pbits8, NULL, 0); +#endif + if (!hbm8) + { + g_warning ("BitmapToRegion: CreateDIBSection failed"); + DeleteDC (hMemDC); + return NULL; + } + + holdBmp = (HBITMAP) SelectObject (hMemDC, hbm8); + + /* Create a DC just to copy the bitmap into the memory DC*/ + hDC = CreateCompatibleDC (hMemDC); + if (!hDC) + { + g_warning ("BitmapToRegion: CreateCompatibleDC #2 failed"); + SelectObject (hMemDC, holdBmp); + DeleteObject (hbm8); + DeleteDC (hMemDC); + return NULL; + } + + /* Get how many bytes per row we have for the bitmap bits */ + GetObject (hbm8, sizeof (bm8), &bm8); + + /* Hans Breuer found a fix to the long-standing erroneous behaviour + * on NT 4.0: There seems to be a bug in Win NT 4.0 GDI: scanlines + * in bitmaps are dword aligned on both Win95 and NT. In the case of + * a bitmap with 22 bytes worth of width, GetObject above returns + * with bmWidth == 22. On Win95 bmWidthBytes == 24, as it should be, + * but on NT is it 22. We need to correct this here. + */ + bm8.bmWidthBytes = (((bm8.bmWidthBytes-1)/4)+1)*4; /* dword aligned!! */ + + /* Copy the bitmap into the memory DC*/ + holdBmp2 = (HBITMAP) SelectObject (hDC, hBmp); + + if (!BitBlt (hMemDC, 0, 0, bm.bmWidth, bm.bmHeight, hDC, 0, 0, SRCCOPY)) + { + g_warning ("BitmapToRegion: BitBlt failed"); + SelectObject (hDC, holdBmp2); + SelectObject (hMemDC, holdBmp); + DeleteObject (hbm8); + DeleteDC (hMemDC); + return NULL; + } + SelectObject (hDC, holdBmp2); + DeleteDC (hDC); + + /* For better performances, we will use the ExtCreateRegion() + * function to create the region. This function take a RGNDATA + * structure on entry. We will add rectangles by amount of + * ALLOC_UNIT number in this structure. + */ + #define ALLOC_UNIT 100 + maxRects = ALLOC_UNIT; + + pData = g_malloc (sizeof (RGNDATAHEADER) + (sizeof (RECT) * maxRects)); + pData->rdh.dwSize = sizeof (RGNDATAHEADER); + pData->rdh.iType = RDH_RECTANGLES; + pData->rdh.nCount = pData->rdh.nRgnSize = 0; + SetRect (&pData->rdh.rcBound, MAXLONG, MAXLONG, 0, 0); + + /* Scan each bitmap from bottom to top (the bitmap is inverted vertically)*/ + p8 = (BYTE *) pbits8 + (bm8.bmHeight - 1) * bm8.bmWidthBytes; + for (y = 0; y < bm.bmHeight; y++) + { + /* Scan each bitmap row from left to right*/ + for (x = 0; x < bm.bmWidth; x++) + { + /* Search for a continuous range of "non transparent pixels"*/ + int x0 = x; + BYTE *p = p8 + x; + while (x < bm.bmWidth) + { + if (*p == 0) + /* This pixel is "transparent"*/ + break; + p++; + x++; + } + + if (x > x0) + { + RECT *pr; + /* Add the pixels (x0, y) to (x, y+1) as a new rectangle + * in the region + */ + if (pData->rdh.nCount >= maxRects) + { + maxRects += ALLOC_UNIT; + pData = g_realloc (pData, sizeof(RGNDATAHEADER) + + (sizeof(RECT) * maxRects)); + } + pr = (RECT *) &pData->Buffer; + SetRect (&pr[pData->rdh.nCount], x0, y, x, y+1); + if (x0 < pData->rdh.rcBound.left) + pData->rdh.rcBound.left = x0; + if (y < pData->rdh.rcBound.top) + pData->rdh.rcBound.top = y; + if (x > pData->rdh.rcBound.right) + pData->rdh.rcBound.right = x; + if (y+1 > pData->rdh.rcBound.bottom) + pData->rdh.rcBound.bottom = y+1; + pData->rdh.nCount++; + + /* On Windows98, ExtCreateRegion() may fail if the + * number of rectangles is too large (ie: > + * 4000). Therefore, we have to create the region by + * multiple steps. + */ + if (pData->rdh.nCount == 2000) + { + HRGN h = ExtCreateRegion (NULL, sizeof(RGNDATAHEADER) + (sizeof(RECT) * maxRects), pData); + if (hRgn) + { + CombineRgn(hRgn, hRgn, h, RGN_OR); + DeleteObject(h); + } + else + hRgn = h; + pData->rdh.nCount = 0; + SetRect (&pData->rdh.rcBound, MAXLONG, MAXLONG, 0, 0); + } + } + } + + /* Go to next row (remember, the bitmap is inverted vertically)*/ + p8 -= bm8.bmWidthBytes; + } + + /* Create or extend the region with the remaining rectangles*/ + h = ExtCreateRegion (NULL, sizeof (RGNDATAHEADER) + + (sizeof (RECT) * maxRects), pData); + if (hRgn) + { + CombineRgn (hRgn, hRgn, h, RGN_OR); + DeleteObject (h); + } + else + hRgn = h; + + /* Clean up*/ + SelectObject(hMemDC, holdBmp); + DeleteObject (hbm8); + DeleteDC (hMemDC); + + return hRgn; +} diff --git a/gdk/win32/gdkglobals-win32.c b/gdk/win32/gdkglobals-win32.c new file mode 100644 index 000000000..4f9f498a7 --- /dev/null +++ b/gdk/win32/gdkglobals-win32.c @@ -0,0 +1,51 @@ +/* GDK - The GIMP Drawing Kit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* + * Modified by the GTK+ Team and others 1997-1999. See the AUTHORS + * file for a list of people on the GTK+ Team. See the ChangeLog + * files for a list of changes. These files are distributed with + * GTK+ at ftp://ftp.gtk.org/pub/gtk/. + */ + +#include "gdktypes.h" +#include "gdkprivate.h" + +guint gdk_debug_flags = 0; +HWND gdk_root_window = NULL; +HWND gdk_leader_window; +GDKVAR GdkWindowPrivate *gdk_root_parent = NULL; +HDC gdk_DC; +HINSTANCE gdk_DLLInstance; +HINSTANCE gdk_ProgInstance; +UINT gdk_selection_notify_msg; +UINT gdk_selection_request_msg; +UINT gdk_selection_clear_msg; +GdkAtom gdk_clipboard_atom; +GdkAtom gdk_win32_dropfiles_atom; +GdkAtom gdk_ole2_dnd_atom; +Atom gdk_selection_property; +gchar *gdk_progclass = NULL; +gint gdk_error_code; +gint gdk_error_warnings = TRUE; +gint gdk_null_window_warnings = TRUE; + +GMutex *gdk_threads_mutex = NULL; + +DWORD windows_version = 0; diff --git a/gdk/win32/gdkglobals.c b/gdk/win32/gdkglobals.c new file mode 100644 index 000000000..4f9f498a7 --- /dev/null +++ b/gdk/win32/gdkglobals.c @@ -0,0 +1,51 @@ +/* GDK - The GIMP Drawing Kit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* + * Modified by the GTK+ Team and others 1997-1999. See the AUTHORS + * file for a list of people on the GTK+ Team. See the ChangeLog + * files for a list of changes. These files are distributed with + * GTK+ at ftp://ftp.gtk.org/pub/gtk/. + */ + +#include "gdktypes.h" +#include "gdkprivate.h" + +guint gdk_debug_flags = 0; +HWND gdk_root_window = NULL; +HWND gdk_leader_window; +GDKVAR GdkWindowPrivate *gdk_root_parent = NULL; +HDC gdk_DC; +HINSTANCE gdk_DLLInstance; +HINSTANCE gdk_ProgInstance; +UINT gdk_selection_notify_msg; +UINT gdk_selection_request_msg; +UINT gdk_selection_clear_msg; +GdkAtom gdk_clipboard_atom; +GdkAtom gdk_win32_dropfiles_atom; +GdkAtom gdk_ole2_dnd_atom; +Atom gdk_selection_property; +gchar *gdk_progclass = NULL; +gint gdk_error_code; +gint gdk_error_warnings = TRUE; +gint gdk_null_window_warnings = TRUE; + +GMutex *gdk_threads_mutex = NULL; + +DWORD windows_version = 0; diff --git a/gdk/win32/gdkim-win32.c b/gdk/win32/gdkim-win32.c new file mode 100644 index 000000000..a9083b96e --- /dev/null +++ b/gdk/win32/gdkim-win32.c @@ -0,0 +1,394 @@ +/* GDK - The GIMP Drawing Kit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* + * Modified by the GTK+ Team and others 1997-1999. See the AUTHORS + * file for a list of people on the GTK+ Team. See the ChangeLog + * files for a list of changes. These files are distributed with + * GTK+ at ftp://ftp.gtk.org/pub/gtk/. + */ + +#if HAVE_CONFIG_H +# include +#endif + +#include +#include + +#include "gdkim.h" +#include "gdkpixmap.h" +#include "gdkprivate.h" +#include "gdki18n.h" +#include "gdkx.h" + +/* + *-------------------------------------------------------------- + * gdk_set_locale + * + * Arguments: + * + * Results: + * + * Side effects: + * + *-------------------------------------------------------------- + */ + +gchar* +gdk_set_locale (void) +{ + gchar *current_locale; + + if (!setlocale (LC_ALL,"")) + g_warning ("locale not supported by C library"); + + current_locale = setlocale (LC_ALL, NULL); + + return current_locale; +} + +void +gdk_im_begin (GdkIC *ic, GdkWindow* window) +{ +} + +void +gdk_im_end (void) +{ +} + +GdkIMStyle +gdk_im_decide_style (GdkIMStyle supported_style) +{ + return GDK_IM_PREEDIT_NONE | GDK_IM_STATUS_NONE; +} + +GdkIMStyle +gdk_im_set_best_style (GdkIMStyle style) +{ + return GDK_IM_PREEDIT_NONE | GDK_IM_STATUS_NONE; +} + +gint +gdk_im_ready (void) +{ + return FALSE; +} + +GdkIC * +gdk_ic_new (GdkICAttr *attr, GdkICAttributesType mask) +{ + return NULL; +} + +void +gdk_ic_destroy (GdkIC *ic) +{ +} + +GdkIMStyle +gdk_ic_get_style (GdkIC *ic) +{ + return GDK_IM_PREEDIT_NONE | GDK_IM_STATUS_NONE; +} + +void +gdk_ic_set_values (GdkIC *ic, ...) +{ +} + +void +gdk_ic_get_values (GdkIC *ic, ...) +{ +} + +GdkICAttributesType +gdk_ic_set_attr (GdkIC *ic, GdkICAttr *attr, GdkICAttributesType mask) +{ + return 0; +} + +GdkICAttributesType +gdk_ic_get_attr (GdkIC *ic, GdkICAttr *attr, GdkICAttributesType mask) +{ + return 0; +} + +GdkEventMask +gdk_ic_get_events (GdkIC *ic) +{ + return 0; +} + +/* + * gdk_wcstombs + * + * Returns a multi-byte string converted from the specified array + * of wide characters. The string is newly allocated. The array of + * wide characters must be null-terminated. If the conversion is + * failed, it returns NULL. + * + * On Win32, we always use UTF-8. + */ +gchar * +gdk_wcstombs (const GdkWChar *src) +{ + gint len; + const GdkWChar *wcp; + guchar *mbstr, *bp; + + wcp = src; + len = 0; + while (*wcp) + { + const GdkWChar c = *wcp++; + + if (c < 0x80) + len += 1; + else if (c < 0x800) + len += 2; + else if (c < 0x10000) + len += 3; + else if (c < 0x200000) + len += 4; + else if (c < 0x4000000) + len += 5; + else + len += 6; + } + + mbstr = g_malloc (len + 1); + + wcp = src; + bp = mbstr; + while (*wcp) + { + int first; + int i; + GdkWChar c = *wcp++; + + if (c < 0x80) + { + first = 0; + len = 1; + } + else if (c < 0x800) + { + first = 0xc0; + len = 2; + } + else if (c < 0x10000) + { + first = 0xe0; + len = 3; + } + else if (c < 0x200000) + { + first = 0xf0; + len = 4; + } + else if (c < 0x4000000) + { + first = 0xf8; + len = 5; + } + else + { + first = 0xfc; + len = 6; + } + + /* Woo-hoo! */ + switch (len) + { + case 6: bp[5] = (c & 0x3f) | 0x80; c >>= 6; /* Fall through */ + case 5: bp[4] = (c & 0x3f) | 0x80; c >>= 6; /* Fall through */ + case 4: bp[3] = (c & 0x3f) | 0x80; c >>= 6; /* Fall through */ + case 3: bp[2] = (c & 0x3f) | 0x80; c >>= 6; /* Fall through */ + case 2: bp[1] = (c & 0x3f) | 0x80; c >>= 6; /* Fall through */ + case 1: bp[0] = c | first; + } + + bp += len; + } + *bp = 0; + return mbstr; +} + + +/* + * gdk_mbstowcs + * + * Converts the specified string into GDK wide characters, and, + * returns the number of wide characters written. The string 'src' + * must be null-terminated. If the conversion is failed, it returns + * -1. + * + * On Win32, thr string is assumed to be in UTF-8. Also note that + * GdkWChar is 32 bits, while wchar_t, and the wide characters the + * Windows API uses, are 16 bits! + */ + +/* First a helper function for not zero-terminated strings */ +gint +gdk_nmbstowcs (GdkWChar *dest, + const gchar *src, + gint src_len, + gint dest_max) +{ + guchar *cp, *end; + gint n; + + cp = (guchar *) src; + end = cp + src_len; + n = 0; + while (cp != end && dest != dest + dest_max) + { + gint i, mask = 0, len; + guchar c = *cp; + + if (c < 0x80) + { + len = 1; + mask = 0x7f; + } + else if ((c & 0xe0) == 0xc0) + { + len = 2; + mask = 0x1f; + } + else if ((c & 0xf0) == 0xe0) + { + len = 3; + mask = 0x0f; + } + else if ((c & 0xf8) == 0xf0) + { + len = 4; + mask = 0x07; + } + else if ((c & 0xfc) == 0xf8) + { + len = 5; + mask = 0x03; + } + else if ((c & 0xfc) == 0xfc) + { + len = 6; + mask = 0x01; + } + else + return -1; + + if (cp + len > end) + return -1; + + *dest = (cp[0] & mask); + for (i = 1; i < len; i++) + { + if ((cp[i] & 0xc0) != 0x80) + return -1; + *dest <<= 6; + *dest |= (cp[i] & 0x3f); + } + if (*dest == -1) + return -1; + + cp += len; + dest++; + n++; + } + if (cp != end) + return -1; + + return n; +} + +gint +gdk_mbstowcs (GdkWChar *dest, + const gchar *src, + gint dest_max) +{ + return gdk_nmbstowcs (dest, src, strlen (src), dest_max); +} + + +/* A version that converts to wchar_t wide chars */ + +gint +gdk_nmbstowchar_ts (wchar_t *dest, + const gchar *src, + gint src_len, + gint dest_max) +{ + wchar_t *wcp; + guchar *cp, *end; + gint n; + + wcp = dest; + cp = (guchar *) src; + end = cp + src_len; + n = 0; + while (cp != end && wcp != dest + dest_max) + { + gint i, mask = 0, len; + guchar c = *cp; + + if (c < 0x80) + { + len = 1; + mask = 0x7f; + } + else if ((c & 0xe0) == 0xc0) + { + len = 2; + mask = 0x1f; + } + else if ((c & 0xf0) == 0xe0) + { + len = 3; + mask = 0x0f; + } + else /* Other lengths are not possible with 16-bit wchar_t! */ + return -1; + + if (cp + len > end) + return -1; + + *wcp = (cp[0] & mask); + for (i = 1; i < len; i++) + { + if ((cp[i] & 0xc0) != 0x80) + return -1; + *wcp <<= 6; + *wcp |= (cp[i] & 0x3f); + } + if (*wcp == 0xFFFF) + return -1; + + cp += len; + wcp++; + n++; + } + if (cp != end) + return -1; + + return n; +} + diff --git a/gdk/win32/gdkim.c b/gdk/win32/gdkim.c new file mode 100644 index 000000000..a9083b96e --- /dev/null +++ b/gdk/win32/gdkim.c @@ -0,0 +1,394 @@ +/* GDK - The GIMP Drawing Kit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* + * Modified by the GTK+ Team and others 1997-1999. See the AUTHORS + * file for a list of people on the GTK+ Team. See the ChangeLog + * files for a list of changes. These files are distributed with + * GTK+ at ftp://ftp.gtk.org/pub/gtk/. + */ + +#if HAVE_CONFIG_H +# include +#endif + +#include +#include + +#include "gdkim.h" +#include "gdkpixmap.h" +#include "gdkprivate.h" +#include "gdki18n.h" +#include "gdkx.h" + +/* + *-------------------------------------------------------------- + * gdk_set_locale + * + * Arguments: + * + * Results: + * + * Side effects: + * + *-------------------------------------------------------------- + */ + +gchar* +gdk_set_locale (void) +{ + gchar *current_locale; + + if (!setlocale (LC_ALL,"")) + g_warning ("locale not supported by C library"); + + current_locale = setlocale (LC_ALL, NULL); + + return current_locale; +} + +void +gdk_im_begin (GdkIC *ic, GdkWindow* window) +{ +} + +void +gdk_im_end (void) +{ +} + +GdkIMStyle +gdk_im_decide_style (GdkIMStyle supported_style) +{ + return GDK_IM_PREEDIT_NONE | GDK_IM_STATUS_NONE; +} + +GdkIMStyle +gdk_im_set_best_style (GdkIMStyle style) +{ + return GDK_IM_PREEDIT_NONE | GDK_IM_STATUS_NONE; +} + +gint +gdk_im_ready (void) +{ + return FALSE; +} + +GdkIC * +gdk_ic_new (GdkICAttr *attr, GdkICAttributesType mask) +{ + return NULL; +} + +void +gdk_ic_destroy (GdkIC *ic) +{ +} + +GdkIMStyle +gdk_ic_get_style (GdkIC *ic) +{ + return GDK_IM_PREEDIT_NONE | GDK_IM_STATUS_NONE; +} + +void +gdk_ic_set_values (GdkIC *ic, ...) +{ +} + +void +gdk_ic_get_values (GdkIC *ic, ...) +{ +} + +GdkICAttributesType +gdk_ic_set_attr (GdkIC *ic, GdkICAttr *attr, GdkICAttributesType mask) +{ + return 0; +} + +GdkICAttributesType +gdk_ic_get_attr (GdkIC *ic, GdkICAttr *attr, GdkICAttributesType mask) +{ + return 0; +} + +GdkEventMask +gdk_ic_get_events (GdkIC *ic) +{ + return 0; +} + +/* + * gdk_wcstombs + * + * Returns a multi-byte string converted from the specified array + * of wide characters. The string is newly allocated. The array of + * wide characters must be null-terminated. If the conversion is + * failed, it returns NULL. + * + * On Win32, we always use UTF-8. + */ +gchar * +gdk_wcstombs (const GdkWChar *src) +{ + gint len; + const GdkWChar *wcp; + guchar *mbstr, *bp; + + wcp = src; + len = 0; + while (*wcp) + { + const GdkWChar c = *wcp++; + + if (c < 0x80) + len += 1; + else if (c < 0x800) + len += 2; + else if (c < 0x10000) + len += 3; + else if (c < 0x200000) + len += 4; + else if (c < 0x4000000) + len += 5; + else + len += 6; + } + + mbstr = g_malloc (len + 1); + + wcp = src; + bp = mbstr; + while (*wcp) + { + int first; + int i; + GdkWChar c = *wcp++; + + if (c < 0x80) + { + first = 0; + len = 1; + } + else if (c < 0x800) + { + first = 0xc0; + len = 2; + } + else if (c < 0x10000) + { + first = 0xe0; + len = 3; + } + else if (c < 0x200000) + { + first = 0xf0; + len = 4; + } + else if (c < 0x4000000) + { + first = 0xf8; + len = 5; + } + else + { + first = 0xfc; + len = 6; + } + + /* Woo-hoo! */ + switch (len) + { + case 6: bp[5] = (c & 0x3f) | 0x80; c >>= 6; /* Fall through */ + case 5: bp[4] = (c & 0x3f) | 0x80; c >>= 6; /* Fall through */ + case 4: bp[3] = (c & 0x3f) | 0x80; c >>= 6; /* Fall through */ + case 3: bp[2] = (c & 0x3f) | 0x80; c >>= 6; /* Fall through */ + case 2: bp[1] = (c & 0x3f) | 0x80; c >>= 6; /* Fall through */ + case 1: bp[0] = c | first; + } + + bp += len; + } + *bp = 0; + return mbstr; +} + + +/* + * gdk_mbstowcs + * + * Converts the specified string into GDK wide characters, and, + * returns the number of wide characters written. The string 'src' + * must be null-terminated. If the conversion is failed, it returns + * -1. + * + * On Win32, thr string is assumed to be in UTF-8. Also note that + * GdkWChar is 32 bits, while wchar_t, and the wide characters the + * Windows API uses, are 16 bits! + */ + +/* First a helper function for not zero-terminated strings */ +gint +gdk_nmbstowcs (GdkWChar *dest, + const gchar *src, + gint src_len, + gint dest_max) +{ + guchar *cp, *end; + gint n; + + cp = (guchar *) src; + end = cp + src_len; + n = 0; + while (cp != end && dest != dest + dest_max) + { + gint i, mask = 0, len; + guchar c = *cp; + + if (c < 0x80) + { + len = 1; + mask = 0x7f; + } + else if ((c & 0xe0) == 0xc0) + { + len = 2; + mask = 0x1f; + } + else if ((c & 0xf0) == 0xe0) + { + len = 3; + mask = 0x0f; + } + else if ((c & 0xf8) == 0xf0) + { + len = 4; + mask = 0x07; + } + else if ((c & 0xfc) == 0xf8) + { + len = 5; + mask = 0x03; + } + else if ((c & 0xfc) == 0xfc) + { + len = 6; + mask = 0x01; + } + else + return -1; + + if (cp + len > end) + return -1; + + *dest = (cp[0] & mask); + for (i = 1; i < len; i++) + { + if ((cp[i] & 0xc0) != 0x80) + return -1; + *dest <<= 6; + *dest |= (cp[i] & 0x3f); + } + if (*dest == -1) + return -1; + + cp += len; + dest++; + n++; + } + if (cp != end) + return -1; + + return n; +} + +gint +gdk_mbstowcs (GdkWChar *dest, + const gchar *src, + gint dest_max) +{ + return gdk_nmbstowcs (dest, src, strlen (src), dest_max); +} + + +/* A version that converts to wchar_t wide chars */ + +gint +gdk_nmbstowchar_ts (wchar_t *dest, + const gchar *src, + gint src_len, + gint dest_max) +{ + wchar_t *wcp; + guchar *cp, *end; + gint n; + + wcp = dest; + cp = (guchar *) src; + end = cp + src_len; + n = 0; + while (cp != end && wcp != dest + dest_max) + { + gint i, mask = 0, len; + guchar c = *cp; + + if (c < 0x80) + { + len = 1; + mask = 0x7f; + } + else if ((c & 0xe0) == 0xc0) + { + len = 2; + mask = 0x1f; + } + else if ((c & 0xf0) == 0xe0) + { + len = 3; + mask = 0x0f; + } + else /* Other lengths are not possible with 16-bit wchar_t! */ + return -1; + + if (cp + len > end) + return -1; + + *wcp = (cp[0] & mask); + for (i = 1; i < len; i++) + { + if ((cp[i] & 0xc0) != 0x80) + return -1; + *wcp <<= 6; + *wcp |= (cp[i] & 0x3f); + } + if (*wcp == 0xFFFF) + return -1; + + cp += len; + wcp++; + n++; + } + if (cp != end) + return -1; + + return n; +} + diff --git a/gdk/win32/gdkinput-win32.c b/gdk/win32/gdkinput-win32.c new file mode 100644 index 000000000..2335e989c --- /dev/null +++ b/gdk/win32/gdkinput-win32.c @@ -0,0 +1,1685 @@ +/* GDK - The GIMP Drawing Kit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * Copyright (C) 1999 Tor Lillqvist + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* + * Modified by the GTK+ Team and others 1997-1999. See the AUTHORS + * file for a list of people on the GTK+ Team. See the ChangeLog + * files for a list of changes. These files are distributed with + * GTK+ at ftp://ftp.gtk.org/pub/gtk/. + */ + +#include "config.h" + +#include +#include +#include + +#include "gdk.h" +#include "gdkinput.h" +#include "gdkprivate.h" +#include "gdkx.h" + +#ifdef HAVE_WINTAB +#include +#define PACKETDATA (PK_CONTEXT | PK_CURSOR | PK_BUTTONS | PK_X | PK_Y | PK_NORMAL_PRESSURE | PK_ORIENTATION) +#define PACKETMODE (PK_BUTTONS) +#include +#endif + +#include "gdkinputprivate.h" + +struct _GdkDevicePrivate { + GdkDeviceInfo info; + + /* information about the axes */ + GdkAxisInfo *axes; + + /* reverse lookup on axis use type */ + gint axis_for_use[GDK_AXIS_LAST]; + + /* true if we need to select a different set of events, but + * can't because this is the core pointer + */ + gint needs_update; + + /* State of buttons */ + gint button_state; + + gint *last_axis_data; + gint last_buttons; +#ifdef HAVE_WINTAB + /* WINTAB stuff: */ + HCTX hctx; + /* Cursor number */ + UINT cursor; + /* The cursor's CSR_PKTDATA */ + WTPKT pktdata; + /* CSR_NPBTNMARKS */ + UINT npbtnmarks[2]; + /* Azimuth and altitude axis */ + AXIS orientation_axes[2]; +#endif +}; + +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif + +/* If USE_SYSCONTEXT is on, we open the Wintab device (hmm, what if + * there are several?) as a system pointing device, i.e. it controls + * the normal Windows cursor. This seems much more natural. + */ +#define USE_SYSCONTEXT 1 /* The code for the other choice is not + * good at all. + */ + +#ifdef HAVE_WINTAB +#define DEBUG_WINTAB 1 +#endif + +#define TWOPI (2.*M_PI) + +#define PING() g_print("%s: %d\n",__FILE__,__LINE__) + +/* Forward declarations */ + +static gint gdk_input_enable_window (GdkWindow *window, + GdkDevicePrivate *gdkdev); +static gint gdk_input_disable_window (GdkWindow *window, + GdkDevicePrivate *gdkdev); +static void gdk_input_none_get_pointer (GdkWindow *window, + guint32 deviceid, + gdouble *x, + gdouble *y, + gdouble *pressure, + gdouble *xtilt, + gdouble *ytilt, + GdkModifierType *mask); + +static GdkDevicePrivate *gdk_input_find_device (guint32 deviceid); + +#ifdef HAVE_WINTAB + +static gint gdk_input_win32_set_mode (guint32 deviceid, + GdkInputMode mode); +static void gdk_input_win32_get_pointer (GdkWindow *window, + guint32 deviceid, + gdouble *x, + gdouble *y, + gdouble *pressure, + gdouble *xtilt, + gdouble *ytilt, + GdkModifierType *mask); +static gint gdk_input_win32_grab_pointer (GdkWindow * window, + gint owner_events, + GdkEventMask event_mask, + GdkWindow *confine_to, + guint32 time); +static void gdk_input_win32_ungrab_pointer (guint32 time); +static void gdk_input_win32_configure_event (GdkEventConfigure *event, + GdkWindow *window); +static void gdk_input_win32_enter_event (GdkEventCrossing *xevent, + GdkWindow *window); +static gint gdk_input_win32_other_event (GdkEvent *event, + MSG *xevent); +static gint gdk_input_win32_enable_window (GdkWindow *window, + GdkDevicePrivate *gdkdev); +static gint gdk_input_win32_disable_window (GdkWindow *window, + GdkDevicePrivate *gdkdev); + +static GdkInputWindow *gdk_input_window_find (GdkWindow *window); +#if !USE_SYSCONTEXT +static GdkInputWindow *gdk_input_window_find_within (GdkWindow *window); +#endif +static GdkDevicePrivate *gdk_input_find_dev_from_ctx (HCTX hctx, + UINT id); +#endif /* HAVE_WINTAB */ + +/* Local variables */ + +static GList *gdk_input_devices; +static GList *gdk_input_windows; +static GList *wintab_contexts; + +static gint gdk_input_root_width; +static gint gdk_input_root_height; + +static GdkWindow *wintab_window; + +static guint32 last_moved_cursor_id; + +static GdkAxisUse gdk_input_core_axes[] = { GDK_AXIS_X, GDK_AXIS_Y }; + +static GdkDeviceInfo gdk_input_core_info = +{ + GDK_CORE_POINTER, + "Core Pointer", + GDK_SOURCE_MOUSE, + GDK_MODE_SCREEN, + TRUE, + 2, + gdk_input_core_axes +}; + +/* Global variables */ + +GdkInputVTable gdk_input_vtable; +gint gdk_input_ignore_core; +gint gdk_input_ignore_wintab = FALSE; + +#if DEBUG_WINTAB + +static void +print_lc(LOGCONTEXT *lc) +{ + g_print ("lcName = %s\n", lc->lcName); + g_print ("lcOptions ="); + if (lc->lcOptions & CXO_SYSTEM) g_print (" CXO_SYSTEM"); + if (lc->lcOptions & CXO_PEN) g_print (" CXO_PEN"); + if (lc->lcOptions & CXO_MESSAGES) g_print (" CXO_MESSAGES"); + if (lc->lcOptions & CXO_MARGIN) g_print (" CXO_MARGIN"); + if (lc->lcOptions & CXO_MGNINSIDE) g_print (" CXO_MGNINSIDE"); + if (lc->lcOptions & CXO_CSRMESSAGES) g_print (" CXO_CSRMESSAGES"); + if (lc->lcOptions & CXO_CSRMESSAGES) g_print (" CXO_CSRMESSAGES"); + g_print ("\n"); + g_print ("lcStatus ="); + if (lc->lcStatus & CXS_DISABLED) g_print (" CXS_DISABLED"); + if (lc->lcStatus & CXS_OBSCURED) g_print (" CXS_OBSCURED"); + if (lc->lcStatus & CXS_ONTOP) g_print (" CXS_ONTOP"); + g_print ("\n"); + g_print ("lcLocks ="); + if (lc->lcLocks & CXL_INSIZE) g_print (" CXL_INSIZE"); + if (lc->lcLocks & CXL_INASPECT) g_print (" CXL_INASPECT"); + if (lc->lcLocks & CXL_SENSITIVITY) g_print (" CXL_SENSITIVITY"); + if (lc->lcLocks & CXL_MARGIN) g_print (" CXL_MARGIN"); + g_print ("\n"); + g_print ("lcMsgBase = %#x, lcDevice = %#x, lcPktRate = %d\n", + lc->lcMsgBase, lc->lcDevice, lc->lcPktRate); + g_print ("lcPktData ="); + if (lc->lcPktData & PK_CONTEXT) g_print (" PK_CONTEXT"); + if (lc->lcPktData & PK_STATUS) g_print (" PK_STATUS"); + if (lc->lcPktData & PK_TIME) g_print (" PK_TIME"); + if (lc->lcPktData & PK_CHANGED) g_print (" PK_CHANGED"); + if (lc->lcPktData & PK_SERIAL_NUMBER) g_print (" PK_SERIAL_NUMBER"); + if (lc->lcPktData & PK_CURSOR) g_print (" PK_CURSOR"); + if (lc->lcPktData & PK_BUTTONS) g_print (" PK_BUTTONS"); + if (lc->lcPktData & PK_X) g_print (" PK_X"); + if (lc->lcPktData & PK_Y) g_print (" PK_Y"); + if (lc->lcPktData & PK_Z) g_print (" PK_Z"); + if (lc->lcPktData & PK_NORMAL_PRESSURE) g_print (" PK_NORMAL_PRESSURE"); + if (lc->lcPktData & PK_TANGENT_PRESSURE) g_print (" PK_TANGENT_PRESSURE"); + if (lc->lcPktData & PK_ORIENTATION) g_print (" PK_ORIENTATION"); + if (lc->lcPktData & PK_ROTATION) g_print (" PK_ROTATION"); + g_print ("\n"); + g_print ("lcPktMode ="); + if (lc->lcPktMode & PK_CONTEXT) g_print (" PK_CONTEXT"); + if (lc->lcPktMode & PK_STATUS) g_print (" PK_STATUS"); + if (lc->lcPktMode & PK_TIME) g_print (" PK_TIME"); + if (lc->lcPktMode & PK_CHANGED) g_print (" PK_CHANGED"); + if (lc->lcPktMode & PK_SERIAL_NUMBER) g_print (" PK_SERIAL_NUMBER"); + if (lc->lcPktMode & PK_CURSOR) g_print (" PK_CURSOR"); + if (lc->lcPktMode & PK_BUTTONS) g_print (" PK_BUTTONS"); + if (lc->lcPktMode & PK_X) g_print (" PK_X"); + if (lc->lcPktMode & PK_Y) g_print (" PK_Y"); + if (lc->lcPktMode & PK_Z) g_print (" PK_Z"); + if (lc->lcPktMode & PK_NORMAL_PRESSURE) g_print (" PK_NORMAL_PRESSURE"); + if (lc->lcPktMode & PK_TANGENT_PRESSURE) g_print (" PK_TANGENT_PRESSURE"); + if (lc->lcPktMode & PK_ORIENTATION) g_print (" PK_ORIENTATION"); + if (lc->lcPktMode & PK_ROTATION) g_print (" PK_ROTATION"); + g_print ("\n"); + g_print ("lcMoveMask ="); + if (lc->lcMoveMask & PK_CONTEXT) g_print (" PK_CONTEXT"); + if (lc->lcMoveMask & PK_STATUS) g_print (" PK_STATUS"); + if (lc->lcMoveMask & PK_TIME) g_print (" PK_TIME"); + if (lc->lcMoveMask & PK_CHANGED) g_print (" PK_CHANGED"); + if (lc->lcMoveMask & PK_SERIAL_NUMBER) g_print (" PK_SERIAL_NUMBER"); + if (lc->lcMoveMask & PK_CURSOR) g_print (" PK_CURSOR"); + if (lc->lcMoveMask & PK_BUTTONS) g_print (" PK_BUTTONS"); + if (lc->lcMoveMask & PK_X) g_print (" PK_X"); + if (lc->lcMoveMask & PK_Y) g_print (" PK_Y"); + if (lc->lcMoveMask & PK_Z) g_print (" PK_Z"); + if (lc->lcMoveMask & PK_NORMAL_PRESSURE) g_print (" PK_NORMAL_PRESSURE"); + if (lc->lcMoveMask & PK_TANGENT_PRESSURE) g_print (" PK_TANGENT_PRESSURE"); + if (lc->lcMoveMask & PK_ORIENTATION) g_print (" PK_ORIENTATION"); + if (lc->lcMoveMask & PK_ROTATION) g_print (" PK_ROTATION"); + g_print ("\n"); + g_print ("lcBtnDnMask = %#x, lcBtnUpMask = %#x\n", + lc->lcBtnDnMask, lc->lcBtnUpMask); + g_print ("lcInOrgX = %d, lcInOrgY = %d, lcInOrgZ = %d\n", + lc->lcInOrgX, lc->lcInOrgY, lc->lcInOrgZ); + g_print ("lcInExtX = %d, lcInExtY = %d, lcInExtZ = %d\n", + lc->lcInExtX, lc->lcInExtY, lc->lcInExtZ); + g_print ("lcOutOrgX = %d, lcOutOrgY = %d, lcOutOrgZ = %d\n", + lc->lcOutOrgX, lc->lcOutOrgY, lc->lcOutOrgZ); + g_print ("lcOutExtX = %d, lcOutExtY = %d, lcOutExtZ = %d\n", + lc->lcOutExtX, lc->lcOutExtY, lc->lcOutExtZ); + g_print ("lcSensX = %g, lcSensY = %g, lcSensZ = %g\n", + lc->lcSensX / 65536., lc->lcSensY / 65536., lc->lcSensZ / 65536.); + g_print ("lcSysMode = %d\n", lc->lcSysMode); + g_print ("lcSysOrgX = %d, lcSysOrgY = %d\n", + lc->lcSysOrgX, lc->lcSysOrgY); + g_print ("lcSysExtX = %d, lcSysExtY = %d\n", + lc->lcSysExtX, lc->lcSysExtY); + g_print ("lcSysSensX = %g, lcSysSensY = %g\n", + lc->lcSysSensX / 65536., lc->lcSysSensY / 65536.); +} + +#endif + +void +gdk_input_init (void) +{ + guint32 deviceid_counter = 0; +#ifdef HAVE_WINTAB + GdkDevicePrivate *gdkdev; + GdkDrawablePrivate *window_private; + GdkWindowAttr wa; + WORD specversion; + LOGCONTEXT defcontext; + HCTX *hctx; + UINT ndevices, ncursors, ncsrtypes, firstcsr, hardware; + BOOL active; + AXIS axis_x, axis_y, axis_npressure, axis_or[3]; + int i, j, k; + int devix, cursorix; + char devname[100], csrname[100]; + + gdk_input_devices = NULL; + wintab_contexts = NULL; + + if (!gdk_input_ignore_wintab && + WTInfo (0, 0, NULL)) + { + WTInfo (WTI_INTERFACE, IFC_SPECVERSION, &specversion); + GDK_NOTE (MISC, g_print ("Wintab interface version %d.%d\n", + HIBYTE (specversion), LOBYTE (specversion))); +#if USE_SYSCONTEXT + WTInfo (WTI_DEFSYSCTX, 0, &defcontext); +#if DEBUG_WINTAB + GDK_NOTE (MISC, (g_print("DEFSYSCTX:\n"), print_lc(&defcontext))); +#endif +#else + WTInfo (WTI_DEFCONTEXT, 0, &defcontext); +#if DEBUG_WINTAB + GDK_NOTE (MISC, (g_print("DEFCONTEXT:\n"), print_lc(&defcontext))); +#endif +#endif + WTInfo (WTI_INTERFACE, IFC_NDEVICES, &ndevices); + WTInfo (WTI_INTERFACE, IFC_NCURSORS, &ncursors); +#if DEBUG_WINTAB + GDK_NOTE (MISC, g_print ("NDEVICES: %d, NCURSORS: %d\n", + ndevices, ncursors)); +#endif + /* Create a dummy window to receive wintab events */ + wa.wclass = GDK_INPUT_OUTPUT; + wa.event_mask = GDK_ALL_EVENTS_MASK; + wa.width = 2; + wa.height = 2; + wa.x = -100; + wa.y = -100; + wa.window_type = GDK_WINDOW_TOPLEVEL; + if ((wintab_window = gdk_window_new (NULL, &wa, GDK_WA_X|GDK_WA_Y)) == NULL) + { + g_warning ("gdk_input_init: gdk_window_new failed"); + return; + } + gdk_window_ref (wintab_window); + window_private = (GdkDrawablePrivate *) wintab_window; + + for (devix = 0; devix < ndevices; devix++) + { + LOGCONTEXT lc; + + WTInfo (WTI_DEVICES + devix, DVC_NAME, devname); + + WTInfo (WTI_DEVICES + devix, DVC_NCSRTYPES, &ncsrtypes); + WTInfo (WTI_DEVICES + devix, DVC_FIRSTCSR, &firstcsr); + WTInfo (WTI_DEVICES + devix, DVC_HARDWARE, &hardware); + WTInfo (WTI_DEVICES + devix, DVC_X, &axis_x); + WTInfo (WTI_DEVICES + devix, DVC_Y, &axis_y); + WTInfo (WTI_DEVICES + devix, DVC_NPRESSURE, &axis_npressure); + WTInfo (WTI_DEVICES + devix, DVC_ORIENTATION, axis_or); + + if (HIBYTE (specversion) > 1 || LOBYTE (specversion) >= 1) + { + WTInfo (WTI_DDCTXS + devix, CTX_NAME, lc.lcName); + WTInfo (WTI_DDCTXS + devix, CTX_OPTIONS, &lc.lcOptions); + lc.lcOptions |= CXO_MESSAGES; +#if USE_SYSCONTEXT + lc.lcOptions |= CXO_SYSTEM; +#endif + lc.lcStatus = 0; + WTInfo (WTI_DDCTXS + devix, CTX_LOCKS, &lc.lcLocks); + lc.lcMsgBase = WT_DEFBASE; + lc.lcDevice = devix; + lc.lcPktRate = 50; + lc.lcPktData = PACKETDATA; + lc.lcPktMode = PK_BUTTONS; /* We want buttons in relative mode */ + lc.lcMoveMask = PACKETDATA; + lc.lcBtnDnMask = lc.lcBtnUpMask = ~0; + WTInfo (WTI_DDCTXS + devix, CTX_INORGX, &lc.lcInOrgX); + WTInfo (WTI_DDCTXS + devix, CTX_INORGY, &lc.lcInOrgY); + WTInfo (WTI_DDCTXS + devix, CTX_INORGZ, &lc.lcInOrgZ); + WTInfo (WTI_DDCTXS + devix, CTX_INEXTX, &lc.lcInExtX); + WTInfo (WTI_DDCTXS + devix, CTX_INEXTY, &lc.lcInExtY); + WTInfo (WTI_DDCTXS + devix, CTX_INEXTZ, &lc.lcInExtZ); + lc.lcOutOrgX = axis_x.axMin; + lc.lcOutOrgY = axis_y.axMin; + lc.lcOutExtX = axis_x.axMax - axis_x.axMin; + lc.lcOutExtY = axis_y.axMax - axis_y.axMin; + lc.lcOutExtY = -lc.lcOutExtY; /* We want Y growing downward */ + WTInfo (WTI_DDCTXS + devix, CTX_SENSX, &lc.lcSensX); + WTInfo (WTI_DDCTXS + devix, CTX_SENSY, &lc.lcSensY); + WTInfo (WTI_DDCTXS + devix, CTX_SENSZ, &lc.lcSensZ); + WTInfo (WTI_DDCTXS + devix, CTX_SYSMODE, &lc.lcSysMode); + lc.lcSysOrgX = lc.lcSysOrgY = 0; + WTInfo (WTI_DDCTXS + devix, CTX_SYSEXTX, &lc.lcSysExtX); + WTInfo (WTI_DDCTXS + devix, CTX_SYSEXTY, &lc.lcSysExtY); + WTInfo (WTI_DDCTXS + devix, CTX_SYSSENSX, &lc.lcSysSensX); + WTInfo (WTI_DDCTXS + devix, CTX_SYSSENSY, &lc.lcSysSensY); + } + else + { + lc = defcontext; + lc.lcOptions |= CXO_MESSAGES; + lc.lcMsgBase = WT_DEFBASE; + lc.lcPktRate = 50; + lc.lcPktData = PACKETDATA; + lc.lcPktMode = PACKETMODE; + lc.lcMoveMask = PACKETDATA; + lc.lcBtnUpMask = lc.lcBtnDnMask = ~0; +#if 0 + lc.lcOutExtY = -lc.lcOutExtY; /* Y grows downward */ +#else + lc.lcOutOrgX = axis_x.axMin; + lc.lcOutOrgY = axis_y.axMin; + lc.lcOutExtX = axis_x.axMax - axis_x.axMin; + lc.lcOutExtY = axis_y.axMax - axis_y.axMin; + lc.lcOutExtY = -lc.lcOutExtY; /* We want Y growing downward */ +#endif + } +#if DEBUG_WINTAB + GDK_NOTE (MISC, (g_print("context for device %d:\n", devix), + print_lc(&lc))); +#endif + hctx = g_new (HCTX, 1); + if ((*hctx = WTOpen (window_private->xwindow, &lc, TRUE)) == NULL) + { + g_warning ("gdk_input_init: WTOpen failed"); + return; + } + GDK_NOTE (MISC, g_print ("opened Wintab device %d %#x\n", + devix, *hctx)); + + wintab_contexts = g_list_append (wintab_contexts, hctx); +#if 0 + WTEnable (*hctx, TRUE); +#endif + WTOverlap (*hctx, TRUE); + +#if DEBUG_WINTAB + GDK_NOTE (MISC, (g_print("context for device %d after WTOpen:\n", devix), + print_lc(&lc))); +#endif + for (cursorix = firstcsr; cursorix < firstcsr + ncsrtypes; cursorix++) + { + active = FALSE; + WTInfo (WTI_CURSORS + cursorix, CSR_ACTIVE, &active); + if (!active) + continue; + gdkdev = g_new (GdkDevicePrivate, 1); + WTInfo (WTI_CURSORS + cursorix, CSR_NAME, csrname); + gdkdev->info.name = g_strconcat (devname, " ", csrname, NULL); + gdkdev->info.deviceid = deviceid_counter++; + gdkdev->info.source = GDK_SOURCE_PEN; + gdkdev->info.mode = GDK_MODE_SCREEN; +#if USE_SYSCONTEXT + gdkdev->info.has_cursor = TRUE; +#else + gdkdev->info.has_cursor = FALSE; +#endif + gdkdev->hctx = *hctx; + gdkdev->cursor = cursorix; + WTInfo (WTI_CURSORS + cursorix, CSR_PKTDATA, &gdkdev->pktdata); + gdkdev->info.num_axes = 0; + if (gdkdev->pktdata & PK_X) + gdkdev->info.num_axes++; + if (gdkdev->pktdata & PK_Y) + gdkdev->info.num_axes++; + if (gdkdev->pktdata & PK_NORMAL_PRESSURE) + gdkdev->info.num_axes++; + /* The wintab driver for the Wacom ArtPad II reports + * PK_ORIENTATION in CSR_PKTDATA, but the tablet doesn't + * actually sense tilt. Catch this by noticing that the + * orientation axis's azimuth resolution is zero. + */ + if ((gdkdev->pktdata & PK_ORIENTATION) + && axis_or[0].axResolution == 0) + gdkdev->pktdata &= ~PK_ORIENTATION; + + if (gdkdev->pktdata & PK_ORIENTATION) + gdkdev->info.num_axes += 2; /* x and y tilt */ + WTInfo (WTI_CURSORS + cursorix, CSR_NPBTNMARKS, &gdkdev->npbtnmarks); + gdkdev->axes = g_new (GdkAxisInfo, gdkdev->info.num_axes); + gdkdev->info.axes = g_new (GdkAxisUse, gdkdev->info.num_axes); + gdkdev->last_axis_data = g_new (gint, gdkdev->info.num_axes); + + for (k = 0; k < GDK_AXIS_LAST; k++) + gdkdev->axis_for_use[k] = -1; + + k = 0; + if (gdkdev->pktdata & PK_X) + { + gdkdev->axes[k].xresolution = + gdkdev->axes[k].resolution = axis_x.axResolution / 65535.; + gdkdev->axes[k].xmin_value = + gdkdev->axes[k].min_value = axis_x.axMin; + gdkdev->axes[k].xmax_value = + gdkdev->axes[k].max_value = axis_x.axMax; + gdkdev->info.axes[k] = GDK_AXIS_X; + gdkdev->axis_for_use[GDK_AXIS_X] = k; + k++; + } + if (gdkdev->pktdata & PK_Y) + { + gdkdev->axes[k].xresolution = + gdkdev->axes[k].resolution = axis_y.axResolution / 65535.; + gdkdev->axes[k].xmin_value = + gdkdev->axes[k].min_value = axis_y.axMin; + gdkdev->axes[k].xmax_value = + gdkdev->axes[k].max_value = axis_y.axMax; + gdkdev->info.axes[k] = GDK_AXIS_Y; + gdkdev->axis_for_use[GDK_AXIS_Y] = k; + k++; + } + if (gdkdev->pktdata & PK_NORMAL_PRESSURE) + { + gdkdev->axes[k].xresolution = + gdkdev->axes[k].resolution = axis_npressure.axResolution / 65535.; + gdkdev->axes[k].xmin_value = + gdkdev->axes[k].min_value = axis_npressure.axMin; + gdkdev->axes[k].xmax_value = + gdkdev->axes[k].max_value = axis_npressure.axMax; + gdkdev->info.axes[k] = GDK_AXIS_PRESSURE; + gdkdev->axis_for_use[GDK_AXIS_PRESSURE] = k; + k++; + } + if (gdkdev->pktdata & PK_ORIENTATION) + { + GdkAxisUse axis; + + gdkdev->orientation_axes[0] = axis_or[0]; + gdkdev->orientation_axes[1] = axis_or[1]; + for (axis = GDK_AXIS_XTILT; axis <= GDK_AXIS_YTILT; axis++) + { + /* Wintab gives us aximuth and altitude, which + * we convert to x and y tilt in the -1000..1000 range + */ + gdkdev->axes[k].xresolution = + gdkdev->axes[k].resolution = 1000; + gdkdev->axes[k].xmin_value = + gdkdev->axes[k].min_value = -1000; + gdkdev->axes[k].xmax_value = + gdkdev->axes[k].max_value = 1000; + gdkdev->info.axes[k] = axis; + gdkdev->axis_for_use[axis] = k; + k++; + } + } + gdkdev->info.num_keys = 0; + gdkdev->info.keys = NULL; + GDK_NOTE (EVENTS, + (g_print ("device: %d (%d) %s axes: %d\n", + gdkdev->info.deviceid, cursorix, + gdkdev->info.name, + gdkdev->info.num_axes), + g_print ("axes: X:%d, Y:%d, PRESSURE:%d, " + "XTILT:%d, YTILT:%d\n", + gdkdev->axis_for_use[GDK_AXIS_X], + gdkdev->axis_for_use[GDK_AXIS_Y], + gdkdev->axis_for_use[GDK_AXIS_PRESSURE], + gdkdev->axis_for_use[GDK_AXIS_XTILT], + gdkdev->axis_for_use[GDK_AXIS_YTILT]))); + for (i = 0; i < gdkdev->info.num_axes; i++) + GDK_NOTE (EVENTS, + g_print ("...axis %d: %d--%d@%d (%d--%d@%d)\n", + i, + gdkdev->axes[i].xmin_value, + gdkdev->axes[i].xmax_value, + gdkdev->axes[i].xresolution, + gdkdev->axes[i].min_value, + gdkdev->axes[i].max_value, + gdkdev->axes[i].resolution)); + gdk_input_devices = g_list_append (gdk_input_devices, + gdkdev); + } + } + } +#endif /* HAVE_WINTAB */ + + if (deviceid_counter > 0) + { +#ifdef HAVE_WINTAB + gdk_input_vtable.set_mode = gdk_input_win32_set_mode; + gdk_input_vtable.set_axes = NULL; + gdk_input_vtable.set_key = NULL; + gdk_input_vtable.motion_events = NULL; + gdk_input_vtable.get_pointer = gdk_input_win32_get_pointer; + gdk_input_vtable.grab_pointer = gdk_input_win32_grab_pointer; + gdk_input_vtable.ungrab_pointer = gdk_input_win32_ungrab_pointer; + gdk_input_vtable.configure_event = gdk_input_win32_configure_event; + gdk_input_vtable.enter_event = gdk_input_win32_enter_event; + gdk_input_vtable.other_event = gdk_input_win32_other_event; + gdk_input_vtable.enable_window = gdk_input_win32_enable_window; + gdk_input_vtable.disable_window = gdk_input_win32_disable_window; + + gdk_input_root_width = gdk_screen_width (); + gdk_input_root_height = gdk_screen_height (); + gdk_input_ignore_core = FALSE; +#else + g_assert_not_reached (); +#endif + } + else + { + gdk_input_vtable.set_mode = NULL; + gdk_input_vtable.set_axes = NULL; + gdk_input_vtable.set_key = NULL; + gdk_input_vtable.motion_events = NULL; + gdk_input_vtable.get_pointer = gdk_input_none_get_pointer; + gdk_input_vtable.grab_pointer = NULL; + gdk_input_vtable.ungrab_pointer = NULL; + gdk_input_vtable.configure_event = NULL; + gdk_input_vtable.enter_event = NULL; + gdk_input_vtable.other_event = NULL; + gdk_input_vtable.enable_window = NULL; + gdk_input_vtable.disable_window = NULL; + gdk_input_ignore_core = FALSE; + } + + gdk_input_devices = g_list_append (gdk_input_devices, &gdk_input_core_info); +} + +gint +gdk_input_set_mode (guint32 deviceid, + GdkInputMode mode) +{ + if (deviceid == GDK_CORE_POINTER) + return FALSE; + + if (gdk_input_vtable.set_mode) + return gdk_input_vtable.set_mode (deviceid, mode); + else + return FALSE; +} + +void +gdk_input_set_axes (guint32 deviceid, + GdkAxisUse *axes) +{ + int i; + GdkDevicePrivate *gdkdev = gdk_input_find_device (deviceid); + g_return_if_fail (gdkdev != NULL); + + if (deviceid == GDK_CORE_POINTER) + return; + + for (i = GDK_AXIS_IGNORE; i < GDK_AXIS_LAST; i++) + { + gdkdev->axis_for_use[i] = -1; + } + + for (i = 0; i < gdkdev->info.num_axes; i++) + { + gdkdev->info.axes[i] = axes[i]; + gdkdev->axis_for_use[axes[i]] = i; + } +} + +static void +gdk_input_none_get_pointer (GdkWindow *window, + guint32 deviceid, + gdouble *x, + gdouble *y, + gdouble *pressure, + gdouble *xtilt, + gdouble *ytilt, + GdkModifierType *mask) +{ + gint x_int, y_int; + + gdk_window_get_pointer (window, &x_int, &y_int, mask); + + if (x) + *x = x_int; + if (y) + *y = y_int; + if (pressure) + *pressure = 0.5; + if (xtilt) + *xtilt = 0; + if (ytilt) + *ytilt = 0; +} + +#ifdef HAVE_WINTAB + +static void +gdk_input_translate_coordinates (GdkDevicePrivate *gdkdev, + GdkInputWindow *input_window, + gint *axis_data, + gdouble *x, + gdouble *y, + gdouble *pressure, + gdouble *xtilt, + gdouble *ytilt) +{ + GdkDrawablePrivate *window_private; + gint x_axis, y_axis, pressure_axis, xtilt_axis, ytilt_axis; + gdouble device_width, device_height; + gdouble x_offset, y_offset, x_scale, y_scale; + + window_private = (GdkDrawablePrivate *) input_window->window; + + x_axis = gdkdev->axis_for_use[GDK_AXIS_X]; + y_axis = gdkdev->axis_for_use[GDK_AXIS_Y]; + pressure_axis = gdkdev->axis_for_use[GDK_AXIS_PRESSURE]; + xtilt_axis = gdkdev->axis_for_use[GDK_AXIS_XTILT]; + ytilt_axis = gdkdev->axis_for_use[GDK_AXIS_YTILT]; + + device_width = gdkdev->axes[x_axis].max_value - + gdkdev->axes[x_axis].min_value; + device_height = gdkdev->axes[y_axis].max_value - + gdkdev->axes[y_axis].min_value; + + if (gdkdev->info.mode == GDK_MODE_SCREEN) + { + x_scale = gdk_input_root_width / device_width; + y_scale = gdk_input_root_height / device_height; + + x_offset = -input_window->root_x; + y_offset = -input_window->root_y; + } + else /* GDK_MODE_WINDOW */ + { + double device_aspect = (device_height*gdkdev->axes[y_axis].resolution) / + (device_width*gdkdev->axes[x_axis].resolution); + + if (device_aspect * window_private->width >= window_private->height) + { + /* device taller than window */ + x_scale = window_private->width / device_width; + y_scale = (x_scale * gdkdev->axes[x_axis].resolution) + / gdkdev->axes[y_axis].resolution; + + x_offset = 0; + y_offset = -(device_height * y_scale - + window_private->height)/2; + } + else + { + /* window taller than device */ + y_scale = window_private->height / device_height; + x_scale = (y_scale * gdkdev->axes[y_axis].resolution) + / gdkdev->axes[x_axis].resolution; + + y_offset = 0; + x_offset = -(device_width * x_scale - window_private->width)/2; + } + } + + if (x) + *x = x_offset + x_scale*axis_data[x_axis]; + if (y) + *y = y_offset + y_scale*axis_data[y_axis]; + + if (pressure) + { + if (pressure_axis != -1) + *pressure = ((double)axis_data[pressure_axis] + - gdkdev->axes[pressure_axis].min_value) + / (gdkdev->axes[pressure_axis].max_value + - gdkdev->axes[pressure_axis].min_value); + else + *pressure = 0.5; + } + + if (xtilt) + { + if (xtilt_axis != -1) + { + *xtilt = 2. * (double)(axis_data[xtilt_axis] - + (gdkdev->axes[xtilt_axis].min_value + + gdkdev->axes[xtilt_axis].max_value)/2) / + (gdkdev->axes[xtilt_axis].max_value - + gdkdev->axes[xtilt_axis].min_value); + } + else + *xtilt = 0; + } + + if (ytilt) + { + if (ytilt_axis != -1) + { + *ytilt = 2. * (double)(axis_data[ytilt_axis] - + (gdkdev->axes[ytilt_axis].min_value + + gdkdev->axes[ytilt_axis].max_value)/2) / + (gdkdev->axes[ytilt_axis].max_value - + gdkdev->axes[ytilt_axis].min_value); + } + else + *ytilt = 0; + } +} + +static void +gdk_input_win32_get_pointer (GdkWindow *window, + guint32 deviceid, + gdouble *x, + gdouble *y, + gdouble *pressure, + gdouble *xtilt, + gdouble *ytilt, + GdkModifierType *mask) +{ + GdkDevicePrivate *gdkdev; + GdkInputWindow *input_window; + gint x_int, y_int; + gint i; + + if (deviceid == GDK_CORE_POINTER) + { + gdk_window_get_pointer (window, &x_int, &y_int, mask); + if (x) + *x = x_int; + if (y) + *y = y_int; + if (pressure) + *pressure = 0.5; + if (xtilt) + *xtilt = 0; + if (ytilt) + *ytilt = 0; + } + else + { + if (mask) + gdk_window_get_pointer (window, NULL, NULL, mask); + + gdkdev = gdk_input_find_device (deviceid); + g_return_if_fail (gdkdev != NULL); + + input_window = gdk_input_window_find (window); + g_return_if_fail (input_window != NULL); + + gdk_input_translate_coordinates (gdkdev, input_window, + gdkdev->last_axis_data, + x, y, pressure, + xtilt, ytilt); + if (mask) + { + *mask &= 0xFF; + *mask |= ((gdkdev->last_buttons & 0x1F) << 8); + } + } +} + +static void +gdk_input_get_root_relative_geometry (HWND w, + int *x_ret, + int *y_ret) +{ + RECT rect; + + GetWindowRect (w, &rect); + + if (x_ret) + *x_ret = rect.left; + if (y_ret) + *y_ret = rect.top; +} + +static gint +gdk_input_win32_set_mode (guint32 deviceid, + GdkInputMode mode) +{ + GList *tmp_list; + GdkDevicePrivate *gdkdev; + GdkInputMode old_mode; + GdkInputWindow *input_window; + + if (deviceid == GDK_CORE_POINTER) + return FALSE; + + gdkdev = gdk_input_find_device (deviceid); + g_return_val_if_fail (gdkdev != NULL, FALSE); + old_mode = gdkdev->info.mode; + + if (old_mode == mode) + return TRUE; + + gdkdev->info.mode = mode; + + if (mode == GDK_MODE_WINDOW) + { + gdkdev->info.has_cursor = FALSE; + for (tmp_list = gdk_input_windows; tmp_list; tmp_list = tmp_list->next) + { + input_window = (GdkInputWindow *)tmp_list->data; + if (input_window->mode != GDK_EXTENSION_EVENTS_CURSOR) + gdk_input_win32_enable_window (input_window->window, gdkdev); + else + if (old_mode != GDK_MODE_DISABLED) + gdk_input_win32_disable_window (input_window->window, gdkdev); + } + } + else if (mode == GDK_MODE_SCREEN) + { + gdkdev->info.has_cursor = TRUE; + for (tmp_list = gdk_input_windows; tmp_list; tmp_list = tmp_list->next) + gdk_input_win32_enable_window (((GdkInputWindow *)tmp_list->data)->window, + gdkdev); + } + else /* mode == GDK_MODE_DISABLED */ + { + for (tmp_list = gdk_input_windows; tmp_list; tmp_list = tmp_list->next) + { + input_window = (GdkInputWindow *)tmp_list->data; + if (old_mode != GDK_MODE_WINDOW || + input_window->mode != GDK_EXTENSION_EVENTS_CURSOR) + gdk_input_win32_disable_window (input_window->window, gdkdev); + } + } + + return TRUE; +} + +static void +gdk_input_win32_configure_event (GdkEventConfigure *event, + GdkWindow *window) +{ + GdkInputWindow *input_window; + gint root_x, root_y; + + input_window = gdk_input_window_find (window); + g_return_if_fail (window != NULL); + + gdk_input_get_root_relative_geometry + (GDK_DRAWABLE_XID (window), &root_x, &root_y); + + input_window->root_x = root_x; + input_window->root_y = root_y; +} + +static void +gdk_input_win32_enter_event (GdkEventCrossing *event, + GdkWindow *window) +{ + GdkInputWindow *input_window; + gint root_x, root_y; + + input_window = gdk_input_window_find (window); + g_return_if_fail (window != NULL); + + gdk_input_get_root_relative_geometry + (GDK_DRAWABLE_XID (window), &root_x, &root_y); + + input_window->root_x = root_x; + input_window->root_y = root_y; +} + +static void +decode_tilt (gint *axis_data, + AXIS *axes, + PACKET *packet) +{ + /* As I don't have a tilt-sensing tablet, + * I cannot test this code. + */ + + double az, el; + + az = TWOPI * packet->pkOrientation.orAzimuth / + (axes[0].axResolution / 65536.); + el = TWOPI * packet->pkOrientation.orAltitude / + (axes[1].axResolution / 65536.); + + /* X tilt */ + axis_data[0] = cos (az) * cos (el) * 1000; + /* Y tilt */ + axis_data[1] = sin (az) * cos (el) * 1000; +} + +static GdkDevicePrivate * +gdk_input_find_dev_from_ctx (HCTX hctx, + UINT cursor) +{ + GList *tmp_list = gdk_input_devices; + GdkDevicePrivate *gdkdev; + + while (tmp_list) + { + gdkdev = (GdkDevicePrivate *) (tmp_list->data); + if (gdkdev->hctx == hctx && gdkdev->cursor == cursor) + return gdkdev; + tmp_list = tmp_list->next; + } + return NULL; +} +static gint +gdk_input_win32_other_event (GdkEvent *event, + MSG *xevent) +{ + GdkWindow *current_window; + GdkInputWindow *input_window; + GdkWindow *window; + GdkWindowPrivate *window_private; + GdkDevicePrivate *gdkdev; + GdkEventMask masktest; + POINT pt; + PACKET packet; + gint return_val; + gint k; + gint x, y; + + if (event->any.window != wintab_window) + g_warning ("gdk_input_win32_other_event: not wintab_window?"); + +#if USE_SYSCONTEXT + window = gdk_window_at_pointer (&x, &y); + if (window == NULL) + window = (GdkWindow *) gdk_root_parent; + + gdk_window_ref (window); + + window_private = (GdkWindowPrivate *) window; + + GDK_NOTE (EVENTS, + g_print ("gdk_input_win32_other_event: window=%#x (%d,%d)\n", + GDK_DRAWABLE_XID (window), x, y)); + +#else + /* ??? This code is pretty bogus */ + current_window = gdk_window_lookup (GetActiveWindow ()); + if (current_window == NULL) + return FALSE; + + input_window = gdk_input_window_find_within (current_window); + if (input_window == NULL) + return FALSE; +#endif + + if (xevent->message == WT_PACKET) + { + if (!WTPacket ((HCTX) xevent->lParam, xevent->wParam, &packet)) + return FALSE; + } + + switch (xevent->message) + { + case WT_PACKET: + if (window_private == gdk_root_parent) + { + GDK_NOTE (EVENTS, g_print ("...is root\n")); + return FALSE; + } + + if ((gdkdev = gdk_input_find_dev_from_ctx ((HCTX) xevent->lParam, + packet.pkCursor)) == NULL) + return FALSE; + + if (gdkdev->info.mode == GDK_MODE_DISABLED) + return FALSE; + + k = 0; + if (gdkdev->pktdata & PK_X) + gdkdev->last_axis_data[k++] = packet.pkX; + if (gdkdev->pktdata & PK_Y) + gdkdev->last_axis_data[k++] = packet.pkY; + if (gdkdev->pktdata & PK_NORMAL_PRESSURE) + gdkdev->last_axis_data[k++] = packet.pkNormalPressure; + if (gdkdev->pktdata & PK_ORIENTATION) + { + decode_tilt (gdkdev->last_axis_data + k, + gdkdev->orientation_axes, &packet); + k += 2; + } + + g_assert (k == gdkdev->info.num_axes); + + if (HIWORD (packet.pkButtons) != TBN_NONE) + { + /* Gdk buttons are numbered 1.. */ + event->button.button = 1 + LOWORD (packet.pkButtons); + + if (HIWORD (packet.pkButtons) == TBN_UP) + { + event->any.type = GDK_BUTTON_RELEASE; + masktest = GDK_BUTTON_RELEASE_MASK; + gdkdev->button_state &= ~(1 << LOWORD (packet.pkButtons)); + } + else + { + event->any.type = GDK_BUTTON_PRESS; + masktest = GDK_BUTTON_PRESS_MASK; + gdkdev->button_state |= 1 << LOWORD (packet.pkButtons); + } + } + else + { + event->any.type = GDK_MOTION_NOTIFY; + masktest = GDK_POINTER_MOTION_MASK; + if (gdkdev->button_state & (1 << 0)) + masktest |= GDK_BUTTON_MOTION_MASK | GDK_BUTTON1_MOTION_MASK; + if (gdkdev->button_state & (1 << 1)) + masktest |= GDK_BUTTON_MOTION_MASK | GDK_BUTTON2_MOTION_MASK; + if (gdkdev->button_state & (1 << 2)) + masktest |= GDK_BUTTON_MOTION_MASK | GDK_BUTTON3_MOTION_MASK; + } + + /* Now we can check if the window wants the event, and + * propagate if necessary. + */ + dijkstra: + if (!window_private->extension_events_selected + || !(window_private->extension_events & masktest)) + { + GDK_NOTE (EVENTS, g_print ("...not selected\n")); + + if (window_private->parent == (GdkWindow *) gdk_root_parent) + return FALSE; + + pt.x = x; + pt.y = y; + ClientToScreen (GDK_DRAWABLE_XID (window), &pt); + gdk_window_unref (window); + window = window_private->parent; + gdk_window_ref (window); + window_private = (GdkWindowPrivate *) window; + ScreenToClient (GDK_DRAWABLE_XID (window), &pt); + x = pt.x; + y = pt.y; + GDK_NOTE (EVENTS, g_print ("...propagating to %#x, (%d,%d)\n", + GDK_DRAWABLE_XID (window), x, y)); + goto dijkstra; + } + + input_window = gdk_input_window_find (window); + + g_assert (input_window != NULL); + + if (gdkdev->info.mode == GDK_MODE_WINDOW + && input_window->mode == GDK_EXTENSION_EVENTS_CURSOR) + return FALSE; + + event->any.window = window; + + if (event->any.type == GDK_BUTTON_PRESS + || event->any.type == GDK_BUTTON_RELEASE) + { + event->button.time = xevent->time; + event->button.source = gdkdev->info.source; + last_moved_cursor_id = + event->button.deviceid = gdkdev->info.deviceid; + +#if 0 +#if USE_SYSCONTEXT + /* Buttons 1 to 3 will come in as WM_[LMR]BUTTON{DOWN,UP} */ + if (event->button.button <= 3) + return FALSE; +#endif +#endif + gdk_input_translate_coordinates (gdkdev, input_window, + gdkdev->last_axis_data, + &event->button.x, &event->button.y, + &event->button.pressure, + &event->button.xtilt, + &event->button.ytilt); + + event->button.state = ((gdkdev->button_state << 8) + & (GDK_BUTTON1_MASK | GDK_BUTTON2_MASK + | GDK_BUTTON3_MASK | GDK_BUTTON4_MASK + | GDK_BUTTON5_MASK)); + GDK_NOTE (EVENTS, g_print ("WINTAB button %s: %d %d %g,%g %g %g,%g\n", + (event->button.type == GDK_BUTTON_PRESS ? + "press" : "release"), + event->button.deviceid, + event->button.button, + event->button.x, event->button.y, + event->button.pressure, + event->button.xtilt, event->button.ytilt)); + } + else + { + event->motion.time = xevent->time; + last_moved_cursor_id = + event->motion.deviceid = gdkdev->info.deviceid; + event->motion.is_hint = FALSE; + event->motion.source = gdkdev->info.source; + + gdk_input_translate_coordinates (gdkdev, input_window, + gdkdev->last_axis_data, + &event->motion.x, &event->motion.y, + &event->motion.pressure, + &event->motion.xtilt, + &event->motion.ytilt); + + event->motion.state = ((gdkdev->button_state << 8) + & (GDK_BUTTON1_MASK | GDK_BUTTON2_MASK + | GDK_BUTTON3_MASK | GDK_BUTTON4_MASK + | GDK_BUTTON5_MASK)); + + GDK_NOTE (EVENTS, g_print ("WINTAB motion: %d %g,%g %g %g,%g\n", + event->motion.deviceid, + event->motion.x, event->motion.y, + event->motion.pressure, + event->motion.xtilt, event->motion.ytilt)); + + /* Check for missing release or press events for the normal + * pressure button. At least on my ArtPadII I sometimes miss a + * release event? + */ + if ((gdkdev->pktdata & PK_NORMAL_PRESSURE + && (event->motion.state & GDK_BUTTON1_MASK) + && packet.pkNormalPressure <= MAX (0, gdkdev->npbtnmarks[0] - 2)) + || (gdkdev->pktdata & PK_NORMAL_PRESSURE + && !(event->motion.state & GDK_BUTTON1_MASK) + && packet.pkNormalPressure > gdkdev->npbtnmarks[1] + 2)) + { + GdkEvent *event2 = gdk_event_copy (event); + if (event->motion.state & GDK_BUTTON1_MASK) + { + event2->button.type = GDK_BUTTON_RELEASE; + gdkdev->button_state &= ~1; + } + else + { + event2->button.type = GDK_BUTTON_PRESS; + gdkdev->button_state |= 1; + } + event2->button.state = ((gdkdev->button_state << 8) + & (GDK_BUTTON1_MASK | GDK_BUTTON2_MASK + | GDK_BUTTON3_MASK | GDK_BUTTON4_MASK + | GDK_BUTTON5_MASK)); + event2->button.button = 1; + GDK_NOTE (EVENTS, g_print ("WINTAB synthesized button %s: %d %d %g,%g %g\n", + (event2->button.type == GDK_BUTTON_PRESS ? + "press" : "release"), + event2->button.deviceid, + event2->button.button, + event2->button.x, event2->button.y, + event2->button.pressure)); + gdk_event_queue_append (event2); + } + } + return TRUE; + + case WT_PROXIMITY: + if (LOWORD (xevent->lParam) == 0) + { + event->proximity.type = GDK_PROXIMITY_OUT; + gdk_input_ignore_core = FALSE; + } + else + { + event->proximity.type = GDK_PROXIMITY_IN; + gdk_input_ignore_core = TRUE; + } + event->proximity.time = xevent->time; + event->proximity.source = GDK_SOURCE_PEN; + event->proximity.deviceid = last_moved_cursor_id; + + GDK_NOTE (EVENTS, g_print ("WINTAB proximity %s: %d\n", + (event->proximity.type == GDK_PROXIMITY_IN ? + "in" : "out"), + event->proximity.deviceid)); + return TRUE; + } + return FALSE; +} + +static gint +gdk_input_win32_enable_window (GdkWindow *window, + GdkDevicePrivate *gdkdev) +{ + GdkWindowPrivate *window_private = (GdkWindowPrivate *) window; + + window_private->extension_events_selected = TRUE; + return TRUE; +} + +static gint +gdk_input_win32_disable_window (GdkWindow *window, + GdkDevicePrivate *gdkdev) +{ + GdkWindowPrivate *window_private = (GdkWindowPrivate *) window; + + window_private->extension_events_selected = FALSE; + return TRUE; +} + +static gint +gdk_input_win32_grab_pointer (GdkWindow *window, + gint owner_events, + GdkEventMask event_mask, + GdkWindow *confine_to, + guint32 time) +{ + GdkInputWindow *input_window, *new_window; + gboolean need_ungrab; + GdkDevicePrivate *gdkdev; + GList *tmp_list; + gint result; + + tmp_list = gdk_input_windows; + new_window = NULL; + need_ungrab = FALSE; + + GDK_NOTE (MISC, g_print ("gdk_input_win32_grab_pointer: %#x %d %#x\n", + GDK_DRAWABLE_XID (window), + owner_events, + (confine_to ? GDK_DRAWABLE_XID (confine_to) : 0))); + + while (tmp_list) + { + input_window = (GdkInputWindow *)tmp_list->data; + + if (input_window->window == window) + new_window = input_window; + else if (input_window->grabbed) + { + input_window->grabbed = FALSE; + need_ungrab = TRUE; + } + + tmp_list = tmp_list->next; + } + + if (new_window) + { + new_window->grabbed = TRUE; + + tmp_list = gdk_input_devices; + while (tmp_list) + { + gdkdev = (GdkDevicePrivate *)tmp_list->data; + if (gdkdev->info.deviceid != GDK_CORE_POINTER) + { +#if 0 + /* XXX */ + gdk_input_find_events (window, gdkdev, + event_mask, + event_classes, &num_classes); + result = XGrabDevice (GDK_DISPLAY(), gdkdev->xdevice, + GDK_WINDOW_XWINDOW (window), + owner_events, num_classes, event_classes, + GrabModeAsync, GrabModeAsync, time); + + /* FIXME: if failure occurs on something other than the first + device, things will be badly inconsistent */ + if (result != Success) + return result; +#endif + } + tmp_list = tmp_list->next; + } + } + else + { + tmp_list = gdk_input_devices; + while (tmp_list) + { + gdkdev = (GdkDevicePrivate *)tmp_list->data; + if (gdkdev->info.deviceid != GDK_CORE_POINTER && + ((gdkdev->button_state != 0) || need_ungrab)) + { +#if 0 + /* XXX */ + XUngrabDevice (gdk_display, gdkdev->xdevice, time); +#endif + gdkdev->button_state = 0; + } + + tmp_list = tmp_list->next; + } + } + + return Success; + +} + +static void +gdk_input_win32_ungrab_pointer (guint32 time) +{ + GdkInputWindow *input_window; + GdkDevicePrivate *gdkdev; + GList *tmp_list; + + GDK_NOTE (MISC, g_print ("gdk_input_win32_ungrab_pointer\n")); + + tmp_list = gdk_input_windows; + while (tmp_list) + { + input_window = (GdkInputWindow *)tmp_list->data; + if (input_window->grabbed) + break; + tmp_list = tmp_list->next; + } + + if (tmp_list) /* we found a grabbed window */ + { + input_window->grabbed = FALSE; + + tmp_list = gdk_input_devices; + while (tmp_list) + { + gdkdev = (GdkDevicePrivate *)tmp_list->data; +#if 0 + /* XXX */ + if (gdkdev->info.deviceid != GDK_CORE_POINTER && gdkdev->xdevice) + XUngrabDevice (gdk_display, gdkdev->xdevice, time); +#endif + tmp_list = tmp_list->next; + } + } +} + +#endif /* HAVE_WINTAB */ + +GList * +gdk_input_list_devices (void) +{ + return gdk_input_devices; +} + +void +gdk_input_set_source (guint32 deviceid, + GdkInputSource source) +{ + GdkDevicePrivate *gdkdev = gdk_input_find_device (deviceid); + g_return_if_fail (gdkdev != NULL); + + gdkdev->info.source = source; +} + +void gdk_input_set_key (guint32 deviceid, + guint index, + guint keyval, + GdkModifierType modifiers) +{ + if (deviceid != GDK_CORE_POINTER && gdk_input_vtable.set_key) + gdk_input_vtable.set_key (deviceid, index, keyval, modifiers); +} + +GdkTimeCoord * +gdk_input_motion_events (GdkWindow *window, + guint32 deviceid, + guint32 start, + guint32 stop, + gint *nevents_return) +{ + g_return_val_if_fail (window != NULL, NULL); + if (GDK_DRAWABLE_DESTROYED (window)) + return NULL; + + *nevents_return = 0; + return NULL; /* ??? */ +} + +static gint +gdk_input_enable_window (GdkWindow *window, GdkDevicePrivate *gdkdev) +{ + if (gdk_input_vtable.enable_window) + return gdk_input_vtable.enable_window (window, gdkdev); + else + return TRUE; +} + +static gint +gdk_input_disable_window (GdkWindow *window, GdkDevicePrivate *gdkdev) +{ + if (gdk_input_vtable.disable_window) + return gdk_input_vtable.disable_window(window,gdkdev); + else + return TRUE; +} + + +static GdkInputWindow * +gdk_input_window_find (GdkWindow *window) +{ + GList *tmp_list; + + for (tmp_list=gdk_input_windows; tmp_list; tmp_list=tmp_list->next) + if (((GdkInputWindow *)(tmp_list->data))->window == window) + return (GdkInputWindow *)(tmp_list->data); + + return NULL; /* Not found */ +} + +#if !USE_SYSCONTEXT + +static GdkInputWindow * +gdk_input_window_find_within (GdkWindow *window) +{ + GList *tmp_list; + GdkWindowPrivate *window_private; + GdkWindowPrivate *tmp_private; + GdkInputWindow *candidate = NULL; + + window_private = (GdkWindowPrivate *) window; + + for (tmp_list=gdk_input_windows; tmp_list; tmp_list=tmp_list->next) + { + (GdkWindowPrivate *) tmp_private = + (GdkWindowPrivate *) (((GdkInputWindow *)(tmp_list->data))->window); + if (tmp_private == window_private + || IsChild (window_private->xwindow, tmp_private->xwindow)) + { + if (candidate) + return NULL; /* Multiple hits */ + candidate = (GdkInputWindow *)(tmp_list->data); + } + } + + return candidate; +} + +#endif + +/* FIXME: this routine currently needs to be called between creation + and the corresponding configure event (because it doesn't get the + root_relative_geometry). This should work with + gtk_window_set_extension_events, but will likely fail in other + cases */ + +void +gdk_input_set_extension_events (GdkWindow *window, + gint mask, + GdkExtensionMode mode) +{ + GdkWindowPrivate *window_private; + GList *tmp_list; + GdkInputWindow *iw; + + g_return_if_fail (window != NULL); + if (GDK_DRAWABLE_DESTROYED (window)) + return; + window_private = (GdkWindowPrivate *) window; + + if (mode == GDK_EXTENSION_EVENTS_NONE) + mask = 0; + + if (mask != 0) + { + iw = g_new (GdkInputWindow,1); + + iw->window = window; + iw->mode = mode; + + iw->grabbed = FALSE; + + gdk_input_windows = g_list_append (gdk_input_windows, iw); + window_private->extension_events = mask; + + /* Add enter window events to the event mask */ + gdk_window_set_events (window, + gdk_window_get_events (window) | + GDK_ENTER_NOTIFY_MASK); + } + else + { + iw = gdk_input_window_find (window); + if (iw) + { + gdk_input_windows = g_list_remove (gdk_input_windows, iw); + g_free (iw); + } + + window_private->extension_events = 0; + } + + for (tmp_list = gdk_input_devices; tmp_list; tmp_list = tmp_list->next) + { + GdkDevicePrivate *gdkdev = (GdkDevicePrivate *)(tmp_list->data); + + if (gdkdev->info.deviceid != GDK_CORE_POINTER) + { + if (mask != 0 && gdkdev->info.mode != GDK_MODE_DISABLED + && (gdkdev->info.has_cursor || mode == GDK_EXTENSION_EVENTS_ALL)) + gdk_input_enable_window (window, gdkdev); + else + gdk_input_disable_window (window, gdkdev); + } + } +} + +void +gdk_input_window_destroy (GdkWindow *window) +{ + GdkInputWindow *input_window; + + input_window = gdk_input_window_find (window); + g_return_if_fail (input_window != NULL); + + gdk_input_windows = g_list_remove (gdk_input_windows,input_window); + g_free (input_window); +} + +void +gdk_input_exit (void) +{ +#ifdef HAVE_WINTAB + GList *tmp_list; + GdkDevicePrivate *gdkdev; + + for (tmp_list = gdk_input_devices; tmp_list; tmp_list = tmp_list->next) + { + gdkdev = (GdkDevicePrivate *)(tmp_list->data); + if (gdkdev->info.deviceid != GDK_CORE_POINTER) + { + gdk_input_win32_set_mode (gdkdev->info.deviceid, GDK_MODE_DISABLED); + g_free (gdkdev->info.name); + g_free (gdkdev->last_axis_data); + g_free (gdkdev->info.axes); + g_free (gdkdev->info.keys); + g_free (gdkdev->axes); + g_free (gdkdev); + } + } + + g_list_free (gdk_input_devices); + + for (tmp_list = gdk_input_windows; tmp_list; tmp_list = tmp_list->next) + { + g_free (tmp_list->data); + } + g_list_free (gdk_input_windows); + gdk_input_windows = NULL; + + gdk_window_unref (wintab_window); + wintab_window = NULL; + +#if 1 + for (tmp_list = wintab_contexts; tmp_list; tmp_list = tmp_list->next) + { + HCTX *hctx = (HCTX *) tmp_list->data; + BOOL result; + +#ifdef _MSC_VER + /* For some reason WTEnable and/or WTClose tend to crash here. + * Protect with __try/__except to avoid a message box. + * When compiling with gcc, we cannot use __try/__except, so + * don't call WTClose. I think this means that we'll + * eventually run out of Wintab contexts, sigh. + */ + __try { +#if 0 + WTEnable (*hctx, FALSE); +#endif + result = WTClose (*hctx); + } + __except (/* GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ? */ + EXCEPTION_EXECUTE_HANDLER /*: + EXCEPTION_CONTINUE_SEARCH */) { + result = FALSE; + } + if (!result) + g_warning ("gdk_input_exit: Closing Wintab context %#x failed", *hctx); +#endif /* _MSC_VER */ + g_free (hctx); + } +#endif + g_list_free (wintab_contexts); + wintab_contexts = NULL; +#endif +} + +static GdkDevicePrivate * +gdk_input_find_device (guint32 id) +{ + GList *tmp_list = gdk_input_devices; + GdkDevicePrivate *gdkdev; + + while (tmp_list) + { + gdkdev = (GdkDevicePrivate *) (tmp_list->data); + if (gdkdev->info.deviceid == id) + return gdkdev; + tmp_list = tmp_list->next; + } + return NULL; +} + +void +gdk_input_window_get_pointer (GdkWindow *window, + guint32 deviceid, + gdouble *x, + gdouble *y, + gdouble *pressure, + gdouble *xtilt, + gdouble *ytilt, + GdkModifierType *mask) +{ + if (gdk_input_vtable.get_pointer) + gdk_input_vtable.get_pointer (window, deviceid, x, y, pressure, + xtilt, ytilt, mask); +} diff --git a/gdk/win32/gdkinput.c b/gdk/win32/gdkinput.c new file mode 100644 index 000000000..2335e989c --- /dev/null +++ b/gdk/win32/gdkinput.c @@ -0,0 +1,1685 @@ +/* GDK - The GIMP Drawing Kit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * Copyright (C) 1999 Tor Lillqvist + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* + * Modified by the GTK+ Team and others 1997-1999. See the AUTHORS + * file for a list of people on the GTK+ Team. See the ChangeLog + * files for a list of changes. These files are distributed with + * GTK+ at ftp://ftp.gtk.org/pub/gtk/. + */ + +#include "config.h" + +#include +#include +#include + +#include "gdk.h" +#include "gdkinput.h" +#include "gdkprivate.h" +#include "gdkx.h" + +#ifdef HAVE_WINTAB +#include +#define PACKETDATA (PK_CONTEXT | PK_CURSOR | PK_BUTTONS | PK_X | PK_Y | PK_NORMAL_PRESSURE | PK_ORIENTATION) +#define PACKETMODE (PK_BUTTONS) +#include +#endif + +#include "gdkinputprivate.h" + +struct _GdkDevicePrivate { + GdkDeviceInfo info; + + /* information about the axes */ + GdkAxisInfo *axes; + + /* reverse lookup on axis use type */ + gint axis_for_use[GDK_AXIS_LAST]; + + /* true if we need to select a different set of events, but + * can't because this is the core pointer + */ + gint needs_update; + + /* State of buttons */ + gint button_state; + + gint *last_axis_data; + gint last_buttons; +#ifdef HAVE_WINTAB + /* WINTAB stuff: */ + HCTX hctx; + /* Cursor number */ + UINT cursor; + /* The cursor's CSR_PKTDATA */ + WTPKT pktdata; + /* CSR_NPBTNMARKS */ + UINT npbtnmarks[2]; + /* Azimuth and altitude axis */ + AXIS orientation_axes[2]; +#endif +}; + +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif + +/* If USE_SYSCONTEXT is on, we open the Wintab device (hmm, what if + * there are several?) as a system pointing device, i.e. it controls + * the normal Windows cursor. This seems much more natural. + */ +#define USE_SYSCONTEXT 1 /* The code for the other choice is not + * good at all. + */ + +#ifdef HAVE_WINTAB +#define DEBUG_WINTAB 1 +#endif + +#define TWOPI (2.*M_PI) + +#define PING() g_print("%s: %d\n",__FILE__,__LINE__) + +/* Forward declarations */ + +static gint gdk_input_enable_window (GdkWindow *window, + GdkDevicePrivate *gdkdev); +static gint gdk_input_disable_window (GdkWindow *window, + GdkDevicePrivate *gdkdev); +static void gdk_input_none_get_pointer (GdkWindow *window, + guint32 deviceid, + gdouble *x, + gdouble *y, + gdouble *pressure, + gdouble *xtilt, + gdouble *ytilt, + GdkModifierType *mask); + +static GdkDevicePrivate *gdk_input_find_device (guint32 deviceid); + +#ifdef HAVE_WINTAB + +static gint gdk_input_win32_set_mode (guint32 deviceid, + GdkInputMode mode); +static void gdk_input_win32_get_pointer (GdkWindow *window, + guint32 deviceid, + gdouble *x, + gdouble *y, + gdouble *pressure, + gdouble *xtilt, + gdouble *ytilt, + GdkModifierType *mask); +static gint gdk_input_win32_grab_pointer (GdkWindow * window, + gint owner_events, + GdkEventMask event_mask, + GdkWindow *confine_to, + guint32 time); +static void gdk_input_win32_ungrab_pointer (guint32 time); +static void gdk_input_win32_configure_event (GdkEventConfigure *event, + GdkWindow *window); +static void gdk_input_win32_enter_event (GdkEventCrossing *xevent, + GdkWindow *window); +static gint gdk_input_win32_other_event (GdkEvent *event, + MSG *xevent); +static gint gdk_input_win32_enable_window (GdkWindow *window, + GdkDevicePrivate *gdkdev); +static gint gdk_input_win32_disable_window (GdkWindow *window, + GdkDevicePrivate *gdkdev); + +static GdkInputWindow *gdk_input_window_find (GdkWindow *window); +#if !USE_SYSCONTEXT +static GdkInputWindow *gdk_input_window_find_within (GdkWindow *window); +#endif +static GdkDevicePrivate *gdk_input_find_dev_from_ctx (HCTX hctx, + UINT id); +#endif /* HAVE_WINTAB */ + +/* Local variables */ + +static GList *gdk_input_devices; +static GList *gdk_input_windows; +static GList *wintab_contexts; + +static gint gdk_input_root_width; +static gint gdk_input_root_height; + +static GdkWindow *wintab_window; + +static guint32 last_moved_cursor_id; + +static GdkAxisUse gdk_input_core_axes[] = { GDK_AXIS_X, GDK_AXIS_Y }; + +static GdkDeviceInfo gdk_input_core_info = +{ + GDK_CORE_POINTER, + "Core Pointer", + GDK_SOURCE_MOUSE, + GDK_MODE_SCREEN, + TRUE, + 2, + gdk_input_core_axes +}; + +/* Global variables */ + +GdkInputVTable gdk_input_vtable; +gint gdk_input_ignore_core; +gint gdk_input_ignore_wintab = FALSE; + +#if DEBUG_WINTAB + +static void +print_lc(LOGCONTEXT *lc) +{ + g_print ("lcName = %s\n", lc->lcName); + g_print ("lcOptions ="); + if (lc->lcOptions & CXO_SYSTEM) g_print (" CXO_SYSTEM"); + if (lc->lcOptions & CXO_PEN) g_print (" CXO_PEN"); + if (lc->lcOptions & CXO_MESSAGES) g_print (" CXO_MESSAGES"); + if (lc->lcOptions & CXO_MARGIN) g_print (" CXO_MARGIN"); + if (lc->lcOptions & CXO_MGNINSIDE) g_print (" CXO_MGNINSIDE"); + if (lc->lcOptions & CXO_CSRMESSAGES) g_print (" CXO_CSRMESSAGES"); + if (lc->lcOptions & CXO_CSRMESSAGES) g_print (" CXO_CSRMESSAGES"); + g_print ("\n"); + g_print ("lcStatus ="); + if (lc->lcStatus & CXS_DISABLED) g_print (" CXS_DISABLED"); + if (lc->lcStatus & CXS_OBSCURED) g_print (" CXS_OBSCURED"); + if (lc->lcStatus & CXS_ONTOP) g_print (" CXS_ONTOP"); + g_print ("\n"); + g_print ("lcLocks ="); + if (lc->lcLocks & CXL_INSIZE) g_print (" CXL_INSIZE"); + if (lc->lcLocks & CXL_INASPECT) g_print (" CXL_INASPECT"); + if (lc->lcLocks & CXL_SENSITIVITY) g_print (" CXL_SENSITIVITY"); + if (lc->lcLocks & CXL_MARGIN) g_print (" CXL_MARGIN"); + g_print ("\n"); + g_print ("lcMsgBase = %#x, lcDevice = %#x, lcPktRate = %d\n", + lc->lcMsgBase, lc->lcDevice, lc->lcPktRate); + g_print ("lcPktData ="); + if (lc->lcPktData & PK_CONTEXT) g_print (" PK_CONTEXT"); + if (lc->lcPktData & PK_STATUS) g_print (" PK_STATUS"); + if (lc->lcPktData & PK_TIME) g_print (" PK_TIME"); + if (lc->lcPktData & PK_CHANGED) g_print (" PK_CHANGED"); + if (lc->lcPktData & PK_SERIAL_NUMBER) g_print (" PK_SERIAL_NUMBER"); + if (lc->lcPktData & PK_CURSOR) g_print (" PK_CURSOR"); + if (lc->lcPktData & PK_BUTTONS) g_print (" PK_BUTTONS"); + if (lc->lcPktData & PK_X) g_print (" PK_X"); + if (lc->lcPktData & PK_Y) g_print (" PK_Y"); + if (lc->lcPktData & PK_Z) g_print (" PK_Z"); + if (lc->lcPktData & PK_NORMAL_PRESSURE) g_print (" PK_NORMAL_PRESSURE"); + if (lc->lcPktData & PK_TANGENT_PRESSURE) g_print (" PK_TANGENT_PRESSURE"); + if (lc->lcPktData & PK_ORIENTATION) g_print (" PK_ORIENTATION"); + if (lc->lcPktData & PK_ROTATION) g_print (" PK_ROTATION"); + g_print ("\n"); + g_print ("lcPktMode ="); + if (lc->lcPktMode & PK_CONTEXT) g_print (" PK_CONTEXT"); + if (lc->lcPktMode & PK_STATUS) g_print (" PK_STATUS"); + if (lc->lcPktMode & PK_TIME) g_print (" PK_TIME"); + if (lc->lcPktMode & PK_CHANGED) g_print (" PK_CHANGED"); + if (lc->lcPktMode & PK_SERIAL_NUMBER) g_print (" PK_SERIAL_NUMBER"); + if (lc->lcPktMode & PK_CURSOR) g_print (" PK_CURSOR"); + if (lc->lcPktMode & PK_BUTTONS) g_print (" PK_BUTTONS"); + if (lc->lcPktMode & PK_X) g_print (" PK_X"); + if (lc->lcPktMode & PK_Y) g_print (" PK_Y"); + if (lc->lcPktMode & PK_Z) g_print (" PK_Z"); + if (lc->lcPktMode & PK_NORMAL_PRESSURE) g_print (" PK_NORMAL_PRESSURE"); + if (lc->lcPktMode & PK_TANGENT_PRESSURE) g_print (" PK_TANGENT_PRESSURE"); + if (lc->lcPktMode & PK_ORIENTATION) g_print (" PK_ORIENTATION"); + if (lc->lcPktMode & PK_ROTATION) g_print (" PK_ROTATION"); + g_print ("\n"); + g_print ("lcMoveMask ="); + if (lc->lcMoveMask & PK_CONTEXT) g_print (" PK_CONTEXT"); + if (lc->lcMoveMask & PK_STATUS) g_print (" PK_STATUS"); + if (lc->lcMoveMask & PK_TIME) g_print (" PK_TIME"); + if (lc->lcMoveMask & PK_CHANGED) g_print (" PK_CHANGED"); + if (lc->lcMoveMask & PK_SERIAL_NUMBER) g_print (" PK_SERIAL_NUMBER"); + if (lc->lcMoveMask & PK_CURSOR) g_print (" PK_CURSOR"); + if (lc->lcMoveMask & PK_BUTTONS) g_print (" PK_BUTTONS"); + if (lc->lcMoveMask & PK_X) g_print (" PK_X"); + if (lc->lcMoveMask & PK_Y) g_print (" PK_Y"); + if (lc->lcMoveMask & PK_Z) g_print (" PK_Z"); + if (lc->lcMoveMask & PK_NORMAL_PRESSURE) g_print (" PK_NORMAL_PRESSURE"); + if (lc->lcMoveMask & PK_TANGENT_PRESSURE) g_print (" PK_TANGENT_PRESSURE"); + if (lc->lcMoveMask & PK_ORIENTATION) g_print (" PK_ORIENTATION"); + if (lc->lcMoveMask & PK_ROTATION) g_print (" PK_ROTATION"); + g_print ("\n"); + g_print ("lcBtnDnMask = %#x, lcBtnUpMask = %#x\n", + lc->lcBtnDnMask, lc->lcBtnUpMask); + g_print ("lcInOrgX = %d, lcInOrgY = %d, lcInOrgZ = %d\n", + lc->lcInOrgX, lc->lcInOrgY, lc->lcInOrgZ); + g_print ("lcInExtX = %d, lcInExtY = %d, lcInExtZ = %d\n", + lc->lcInExtX, lc->lcInExtY, lc->lcInExtZ); + g_print ("lcOutOrgX = %d, lcOutOrgY = %d, lcOutOrgZ = %d\n", + lc->lcOutOrgX, lc->lcOutOrgY, lc->lcOutOrgZ); + g_print ("lcOutExtX = %d, lcOutExtY = %d, lcOutExtZ = %d\n", + lc->lcOutExtX, lc->lcOutExtY, lc->lcOutExtZ); + g_print ("lcSensX = %g, lcSensY = %g, lcSensZ = %g\n", + lc->lcSensX / 65536., lc->lcSensY / 65536., lc->lcSensZ / 65536.); + g_print ("lcSysMode = %d\n", lc->lcSysMode); + g_print ("lcSysOrgX = %d, lcSysOrgY = %d\n", + lc->lcSysOrgX, lc->lcSysOrgY); + g_print ("lcSysExtX = %d, lcSysExtY = %d\n", + lc->lcSysExtX, lc->lcSysExtY); + g_print ("lcSysSensX = %g, lcSysSensY = %g\n", + lc->lcSysSensX / 65536., lc->lcSysSensY / 65536.); +} + +#endif + +void +gdk_input_init (void) +{ + guint32 deviceid_counter = 0; +#ifdef HAVE_WINTAB + GdkDevicePrivate *gdkdev; + GdkDrawablePrivate *window_private; + GdkWindowAttr wa; + WORD specversion; + LOGCONTEXT defcontext; + HCTX *hctx; + UINT ndevices, ncursors, ncsrtypes, firstcsr, hardware; + BOOL active; + AXIS axis_x, axis_y, axis_npressure, axis_or[3]; + int i, j, k; + int devix, cursorix; + char devname[100], csrname[100]; + + gdk_input_devices = NULL; + wintab_contexts = NULL; + + if (!gdk_input_ignore_wintab && + WTInfo (0, 0, NULL)) + { + WTInfo (WTI_INTERFACE, IFC_SPECVERSION, &specversion); + GDK_NOTE (MISC, g_print ("Wintab interface version %d.%d\n", + HIBYTE (specversion), LOBYTE (specversion))); +#if USE_SYSCONTEXT + WTInfo (WTI_DEFSYSCTX, 0, &defcontext); +#if DEBUG_WINTAB + GDK_NOTE (MISC, (g_print("DEFSYSCTX:\n"), print_lc(&defcontext))); +#endif +#else + WTInfo (WTI_DEFCONTEXT, 0, &defcontext); +#if DEBUG_WINTAB + GDK_NOTE (MISC, (g_print("DEFCONTEXT:\n"), print_lc(&defcontext))); +#endif +#endif + WTInfo (WTI_INTERFACE, IFC_NDEVICES, &ndevices); + WTInfo (WTI_INTERFACE, IFC_NCURSORS, &ncursors); +#if DEBUG_WINTAB + GDK_NOTE (MISC, g_print ("NDEVICES: %d, NCURSORS: %d\n", + ndevices, ncursors)); +#endif + /* Create a dummy window to receive wintab events */ + wa.wclass = GDK_INPUT_OUTPUT; + wa.event_mask = GDK_ALL_EVENTS_MASK; + wa.width = 2; + wa.height = 2; + wa.x = -100; + wa.y = -100; + wa.window_type = GDK_WINDOW_TOPLEVEL; + if ((wintab_window = gdk_window_new (NULL, &wa, GDK_WA_X|GDK_WA_Y)) == NULL) + { + g_warning ("gdk_input_init: gdk_window_new failed"); + return; + } + gdk_window_ref (wintab_window); + window_private = (GdkDrawablePrivate *) wintab_window; + + for (devix = 0; devix < ndevices; devix++) + { + LOGCONTEXT lc; + + WTInfo (WTI_DEVICES + devix, DVC_NAME, devname); + + WTInfo (WTI_DEVICES + devix, DVC_NCSRTYPES, &ncsrtypes); + WTInfo (WTI_DEVICES + devix, DVC_FIRSTCSR, &firstcsr); + WTInfo (WTI_DEVICES + devix, DVC_HARDWARE, &hardware); + WTInfo (WTI_DEVICES + devix, DVC_X, &axis_x); + WTInfo (WTI_DEVICES + devix, DVC_Y, &axis_y); + WTInfo (WTI_DEVICES + devix, DVC_NPRESSURE, &axis_npressure); + WTInfo (WTI_DEVICES + devix, DVC_ORIENTATION, axis_or); + + if (HIBYTE (specversion) > 1 || LOBYTE (specversion) >= 1) + { + WTInfo (WTI_DDCTXS + devix, CTX_NAME, lc.lcName); + WTInfo (WTI_DDCTXS + devix, CTX_OPTIONS, &lc.lcOptions); + lc.lcOptions |= CXO_MESSAGES; +#if USE_SYSCONTEXT + lc.lcOptions |= CXO_SYSTEM; +#endif + lc.lcStatus = 0; + WTInfo (WTI_DDCTXS + devix, CTX_LOCKS, &lc.lcLocks); + lc.lcMsgBase = WT_DEFBASE; + lc.lcDevice = devix; + lc.lcPktRate = 50; + lc.lcPktData = PACKETDATA; + lc.lcPktMode = PK_BUTTONS; /* We want buttons in relative mode */ + lc.lcMoveMask = PACKETDATA; + lc.lcBtnDnMask = lc.lcBtnUpMask = ~0; + WTInfo (WTI_DDCTXS + devix, CTX_INORGX, &lc.lcInOrgX); + WTInfo (WTI_DDCTXS + devix, CTX_INORGY, &lc.lcInOrgY); + WTInfo (WTI_DDCTXS + devix, CTX_INORGZ, &lc.lcInOrgZ); + WTInfo (WTI_DDCTXS + devix, CTX_INEXTX, &lc.lcInExtX); + WTInfo (WTI_DDCTXS + devix, CTX_INEXTY, &lc.lcInExtY); + WTInfo (WTI_DDCTXS + devix, CTX_INEXTZ, &lc.lcInExtZ); + lc.lcOutOrgX = axis_x.axMin; + lc.lcOutOrgY = axis_y.axMin; + lc.lcOutExtX = axis_x.axMax - axis_x.axMin; + lc.lcOutExtY = axis_y.axMax - axis_y.axMin; + lc.lcOutExtY = -lc.lcOutExtY; /* We want Y growing downward */ + WTInfo (WTI_DDCTXS + devix, CTX_SENSX, &lc.lcSensX); + WTInfo (WTI_DDCTXS + devix, CTX_SENSY, &lc.lcSensY); + WTInfo (WTI_DDCTXS + devix, CTX_SENSZ, &lc.lcSensZ); + WTInfo (WTI_DDCTXS + devix, CTX_SYSMODE, &lc.lcSysMode); + lc.lcSysOrgX = lc.lcSysOrgY = 0; + WTInfo (WTI_DDCTXS + devix, CTX_SYSEXTX, &lc.lcSysExtX); + WTInfo (WTI_DDCTXS + devix, CTX_SYSEXTY, &lc.lcSysExtY); + WTInfo (WTI_DDCTXS + devix, CTX_SYSSENSX, &lc.lcSysSensX); + WTInfo (WTI_DDCTXS + devix, CTX_SYSSENSY, &lc.lcSysSensY); + } + else + { + lc = defcontext; + lc.lcOptions |= CXO_MESSAGES; + lc.lcMsgBase = WT_DEFBASE; + lc.lcPktRate = 50; + lc.lcPktData = PACKETDATA; + lc.lcPktMode = PACKETMODE; + lc.lcMoveMask = PACKETDATA; + lc.lcBtnUpMask = lc.lcBtnDnMask = ~0; +#if 0 + lc.lcOutExtY = -lc.lcOutExtY; /* Y grows downward */ +#else + lc.lcOutOrgX = axis_x.axMin; + lc.lcOutOrgY = axis_y.axMin; + lc.lcOutExtX = axis_x.axMax - axis_x.axMin; + lc.lcOutExtY = axis_y.axMax - axis_y.axMin; + lc.lcOutExtY = -lc.lcOutExtY; /* We want Y growing downward */ +#endif + } +#if DEBUG_WINTAB + GDK_NOTE (MISC, (g_print("context for device %d:\n", devix), + print_lc(&lc))); +#endif + hctx = g_new (HCTX, 1); + if ((*hctx = WTOpen (window_private->xwindow, &lc, TRUE)) == NULL) + { + g_warning ("gdk_input_init: WTOpen failed"); + return; + } + GDK_NOTE (MISC, g_print ("opened Wintab device %d %#x\n", + devix, *hctx)); + + wintab_contexts = g_list_append (wintab_contexts, hctx); +#if 0 + WTEnable (*hctx, TRUE); +#endif + WTOverlap (*hctx, TRUE); + +#if DEBUG_WINTAB + GDK_NOTE (MISC, (g_print("context for device %d after WTOpen:\n", devix), + print_lc(&lc))); +#endif + for (cursorix = firstcsr; cursorix < firstcsr + ncsrtypes; cursorix++) + { + active = FALSE; + WTInfo (WTI_CURSORS + cursorix, CSR_ACTIVE, &active); + if (!active) + continue; + gdkdev = g_new (GdkDevicePrivate, 1); + WTInfo (WTI_CURSORS + cursorix, CSR_NAME, csrname); + gdkdev->info.name = g_strconcat (devname, " ", csrname, NULL); + gdkdev->info.deviceid = deviceid_counter++; + gdkdev->info.source = GDK_SOURCE_PEN; + gdkdev->info.mode = GDK_MODE_SCREEN; +#if USE_SYSCONTEXT + gdkdev->info.has_cursor = TRUE; +#else + gdkdev->info.has_cursor = FALSE; +#endif + gdkdev->hctx = *hctx; + gdkdev->cursor = cursorix; + WTInfo (WTI_CURSORS + cursorix, CSR_PKTDATA, &gdkdev->pktdata); + gdkdev->info.num_axes = 0; + if (gdkdev->pktdata & PK_X) + gdkdev->info.num_axes++; + if (gdkdev->pktdata & PK_Y) + gdkdev->info.num_axes++; + if (gdkdev->pktdata & PK_NORMAL_PRESSURE) + gdkdev->info.num_axes++; + /* The wintab driver for the Wacom ArtPad II reports + * PK_ORIENTATION in CSR_PKTDATA, but the tablet doesn't + * actually sense tilt. Catch this by noticing that the + * orientation axis's azimuth resolution is zero. + */ + if ((gdkdev->pktdata & PK_ORIENTATION) + && axis_or[0].axResolution == 0) + gdkdev->pktdata &= ~PK_ORIENTATION; + + if (gdkdev->pktdata & PK_ORIENTATION) + gdkdev->info.num_axes += 2; /* x and y tilt */ + WTInfo (WTI_CURSORS + cursorix, CSR_NPBTNMARKS, &gdkdev->npbtnmarks); + gdkdev->axes = g_new (GdkAxisInfo, gdkdev->info.num_axes); + gdkdev->info.axes = g_new (GdkAxisUse, gdkdev->info.num_axes); + gdkdev->last_axis_data = g_new (gint, gdkdev->info.num_axes); + + for (k = 0; k < GDK_AXIS_LAST; k++) + gdkdev->axis_for_use[k] = -1; + + k = 0; + if (gdkdev->pktdata & PK_X) + { + gdkdev->axes[k].xresolution = + gdkdev->axes[k].resolution = axis_x.axResolution / 65535.; + gdkdev->axes[k].xmin_value = + gdkdev->axes[k].min_value = axis_x.axMin; + gdkdev->axes[k].xmax_value = + gdkdev->axes[k].max_value = axis_x.axMax; + gdkdev->info.axes[k] = GDK_AXIS_X; + gdkdev->axis_for_use[GDK_AXIS_X] = k; + k++; + } + if (gdkdev->pktdata & PK_Y) + { + gdkdev->axes[k].xresolution = + gdkdev->axes[k].resolution = axis_y.axResolution / 65535.; + gdkdev->axes[k].xmin_value = + gdkdev->axes[k].min_value = axis_y.axMin; + gdkdev->axes[k].xmax_value = + gdkdev->axes[k].max_value = axis_y.axMax; + gdkdev->info.axes[k] = GDK_AXIS_Y; + gdkdev->axis_for_use[GDK_AXIS_Y] = k; + k++; + } + if (gdkdev->pktdata & PK_NORMAL_PRESSURE) + { + gdkdev->axes[k].xresolution = + gdkdev->axes[k].resolution = axis_npressure.axResolution / 65535.; + gdkdev->axes[k].xmin_value = + gdkdev->axes[k].min_value = axis_npressure.axMin; + gdkdev->axes[k].xmax_value = + gdkdev->axes[k].max_value = axis_npressure.axMax; + gdkdev->info.axes[k] = GDK_AXIS_PRESSURE; + gdkdev->axis_for_use[GDK_AXIS_PRESSURE] = k; + k++; + } + if (gdkdev->pktdata & PK_ORIENTATION) + { + GdkAxisUse axis; + + gdkdev->orientation_axes[0] = axis_or[0]; + gdkdev->orientation_axes[1] = axis_or[1]; + for (axis = GDK_AXIS_XTILT; axis <= GDK_AXIS_YTILT; axis++) + { + /* Wintab gives us aximuth and altitude, which + * we convert to x and y tilt in the -1000..1000 range + */ + gdkdev->axes[k].xresolution = + gdkdev->axes[k].resolution = 1000; + gdkdev->axes[k].xmin_value = + gdkdev->axes[k].min_value = -1000; + gdkdev->axes[k].xmax_value = + gdkdev->axes[k].max_value = 1000; + gdkdev->info.axes[k] = axis; + gdkdev->axis_for_use[axis] = k; + k++; + } + } + gdkdev->info.num_keys = 0; + gdkdev->info.keys = NULL; + GDK_NOTE (EVENTS, + (g_print ("device: %d (%d) %s axes: %d\n", + gdkdev->info.deviceid, cursorix, + gdkdev->info.name, + gdkdev->info.num_axes), + g_print ("axes: X:%d, Y:%d, PRESSURE:%d, " + "XTILT:%d, YTILT:%d\n", + gdkdev->axis_for_use[GDK_AXIS_X], + gdkdev->axis_for_use[GDK_AXIS_Y], + gdkdev->axis_for_use[GDK_AXIS_PRESSURE], + gdkdev->axis_for_use[GDK_AXIS_XTILT], + gdkdev->axis_for_use[GDK_AXIS_YTILT]))); + for (i = 0; i < gdkdev->info.num_axes; i++) + GDK_NOTE (EVENTS, + g_print ("...axis %d: %d--%d@%d (%d--%d@%d)\n", + i, + gdkdev->axes[i].xmin_value, + gdkdev->axes[i].xmax_value, + gdkdev->axes[i].xresolution, + gdkdev->axes[i].min_value, + gdkdev->axes[i].max_value, + gdkdev->axes[i].resolution)); + gdk_input_devices = g_list_append (gdk_input_devices, + gdkdev); + } + } + } +#endif /* HAVE_WINTAB */ + + if (deviceid_counter > 0) + { +#ifdef HAVE_WINTAB + gdk_input_vtable.set_mode = gdk_input_win32_set_mode; + gdk_input_vtable.set_axes = NULL; + gdk_input_vtable.set_key = NULL; + gdk_input_vtable.motion_events = NULL; + gdk_input_vtable.get_pointer = gdk_input_win32_get_pointer; + gdk_input_vtable.grab_pointer = gdk_input_win32_grab_pointer; + gdk_input_vtable.ungrab_pointer = gdk_input_win32_ungrab_pointer; + gdk_input_vtable.configure_event = gdk_input_win32_configure_event; + gdk_input_vtable.enter_event = gdk_input_win32_enter_event; + gdk_input_vtable.other_event = gdk_input_win32_other_event; + gdk_input_vtable.enable_window = gdk_input_win32_enable_window; + gdk_input_vtable.disable_window = gdk_input_win32_disable_window; + + gdk_input_root_width = gdk_screen_width (); + gdk_input_root_height = gdk_screen_height (); + gdk_input_ignore_core = FALSE; +#else + g_assert_not_reached (); +#endif + } + else + { + gdk_input_vtable.set_mode = NULL; + gdk_input_vtable.set_axes = NULL; + gdk_input_vtable.set_key = NULL; + gdk_input_vtable.motion_events = NULL; + gdk_input_vtable.get_pointer = gdk_input_none_get_pointer; + gdk_input_vtable.grab_pointer = NULL; + gdk_input_vtable.ungrab_pointer = NULL; + gdk_input_vtable.configure_event = NULL; + gdk_input_vtable.enter_event = NULL; + gdk_input_vtable.other_event = NULL; + gdk_input_vtable.enable_window = NULL; + gdk_input_vtable.disable_window = NULL; + gdk_input_ignore_core = FALSE; + } + + gdk_input_devices = g_list_append (gdk_input_devices, &gdk_input_core_info); +} + +gint +gdk_input_set_mode (guint32 deviceid, + GdkInputMode mode) +{ + if (deviceid == GDK_CORE_POINTER) + return FALSE; + + if (gdk_input_vtable.set_mode) + return gdk_input_vtable.set_mode (deviceid, mode); + else + return FALSE; +} + +void +gdk_input_set_axes (guint32 deviceid, + GdkAxisUse *axes) +{ + int i; + GdkDevicePrivate *gdkdev = gdk_input_find_device (deviceid); + g_return_if_fail (gdkdev != NULL); + + if (deviceid == GDK_CORE_POINTER) + return; + + for (i = GDK_AXIS_IGNORE; i < GDK_AXIS_LAST; i++) + { + gdkdev->axis_for_use[i] = -1; + } + + for (i = 0; i < gdkdev->info.num_axes; i++) + { + gdkdev->info.axes[i] = axes[i]; + gdkdev->axis_for_use[axes[i]] = i; + } +} + +static void +gdk_input_none_get_pointer (GdkWindow *window, + guint32 deviceid, + gdouble *x, + gdouble *y, + gdouble *pressure, + gdouble *xtilt, + gdouble *ytilt, + GdkModifierType *mask) +{ + gint x_int, y_int; + + gdk_window_get_pointer (window, &x_int, &y_int, mask); + + if (x) + *x = x_int; + if (y) + *y = y_int; + if (pressure) + *pressure = 0.5; + if (xtilt) + *xtilt = 0; + if (ytilt) + *ytilt = 0; +} + +#ifdef HAVE_WINTAB + +static void +gdk_input_translate_coordinates (GdkDevicePrivate *gdkdev, + GdkInputWindow *input_window, + gint *axis_data, + gdouble *x, + gdouble *y, + gdouble *pressure, + gdouble *xtilt, + gdouble *ytilt) +{ + GdkDrawablePrivate *window_private; + gint x_axis, y_axis, pressure_axis, xtilt_axis, ytilt_axis; + gdouble device_width, device_height; + gdouble x_offset, y_offset, x_scale, y_scale; + + window_private = (GdkDrawablePrivate *) input_window->window; + + x_axis = gdkdev->axis_for_use[GDK_AXIS_X]; + y_axis = gdkdev->axis_for_use[GDK_AXIS_Y]; + pressure_axis = gdkdev->axis_for_use[GDK_AXIS_PRESSURE]; + xtilt_axis = gdkdev->axis_for_use[GDK_AXIS_XTILT]; + ytilt_axis = gdkdev->axis_for_use[GDK_AXIS_YTILT]; + + device_width = gdkdev->axes[x_axis].max_value - + gdkdev->axes[x_axis].min_value; + device_height = gdkdev->axes[y_axis].max_value - + gdkdev->axes[y_axis].min_value; + + if (gdkdev->info.mode == GDK_MODE_SCREEN) + { + x_scale = gdk_input_root_width / device_width; + y_scale = gdk_input_root_height / device_height; + + x_offset = -input_window->root_x; + y_offset = -input_window->root_y; + } + else /* GDK_MODE_WINDOW */ + { + double device_aspect = (device_height*gdkdev->axes[y_axis].resolution) / + (device_width*gdkdev->axes[x_axis].resolution); + + if (device_aspect * window_private->width >= window_private->height) + { + /* device taller than window */ + x_scale = window_private->width / device_width; + y_scale = (x_scale * gdkdev->axes[x_axis].resolution) + / gdkdev->axes[y_axis].resolution; + + x_offset = 0; + y_offset = -(device_height * y_scale - + window_private->height)/2; + } + else + { + /* window taller than device */ + y_scale = window_private->height / device_height; + x_scale = (y_scale * gdkdev->axes[y_axis].resolution) + / gdkdev->axes[x_axis].resolution; + + y_offset = 0; + x_offset = -(device_width * x_scale - window_private->width)/2; + } + } + + if (x) + *x = x_offset + x_scale*axis_data[x_axis]; + if (y) + *y = y_offset + y_scale*axis_data[y_axis]; + + if (pressure) + { + if (pressure_axis != -1) + *pressure = ((double)axis_data[pressure_axis] + - gdkdev->axes[pressure_axis].min_value) + / (gdkdev->axes[pressure_axis].max_value + - gdkdev->axes[pressure_axis].min_value); + else + *pressure = 0.5; + } + + if (xtilt) + { + if (xtilt_axis != -1) + { + *xtilt = 2. * (double)(axis_data[xtilt_axis] - + (gdkdev->axes[xtilt_axis].min_value + + gdkdev->axes[xtilt_axis].max_value)/2) / + (gdkdev->axes[xtilt_axis].max_value - + gdkdev->axes[xtilt_axis].min_value); + } + else + *xtilt = 0; + } + + if (ytilt) + { + if (ytilt_axis != -1) + { + *ytilt = 2. * (double)(axis_data[ytilt_axis] - + (gdkdev->axes[ytilt_axis].min_value + + gdkdev->axes[ytilt_axis].max_value)/2) / + (gdkdev->axes[ytilt_axis].max_value - + gdkdev->axes[ytilt_axis].min_value); + } + else + *ytilt = 0; + } +} + +static void +gdk_input_win32_get_pointer (GdkWindow *window, + guint32 deviceid, + gdouble *x, + gdouble *y, + gdouble *pressure, + gdouble *xtilt, + gdouble *ytilt, + GdkModifierType *mask) +{ + GdkDevicePrivate *gdkdev; + GdkInputWindow *input_window; + gint x_int, y_int; + gint i; + + if (deviceid == GDK_CORE_POINTER) + { + gdk_window_get_pointer (window, &x_int, &y_int, mask); + if (x) + *x = x_int; + if (y) + *y = y_int; + if (pressure) + *pressure = 0.5; + if (xtilt) + *xtilt = 0; + if (ytilt) + *ytilt = 0; + } + else + { + if (mask) + gdk_window_get_pointer (window, NULL, NULL, mask); + + gdkdev = gdk_input_find_device (deviceid); + g_return_if_fail (gdkdev != NULL); + + input_window = gdk_input_window_find (window); + g_return_if_fail (input_window != NULL); + + gdk_input_translate_coordinates (gdkdev, input_window, + gdkdev->last_axis_data, + x, y, pressure, + xtilt, ytilt); + if (mask) + { + *mask &= 0xFF; + *mask |= ((gdkdev->last_buttons & 0x1F) << 8); + } + } +} + +static void +gdk_input_get_root_relative_geometry (HWND w, + int *x_ret, + int *y_ret) +{ + RECT rect; + + GetWindowRect (w, &rect); + + if (x_ret) + *x_ret = rect.left; + if (y_ret) + *y_ret = rect.top; +} + +static gint +gdk_input_win32_set_mode (guint32 deviceid, + GdkInputMode mode) +{ + GList *tmp_list; + GdkDevicePrivate *gdkdev; + GdkInputMode old_mode; + GdkInputWindow *input_window; + + if (deviceid == GDK_CORE_POINTER) + return FALSE; + + gdkdev = gdk_input_find_device (deviceid); + g_return_val_if_fail (gdkdev != NULL, FALSE); + old_mode = gdkdev->info.mode; + + if (old_mode == mode) + return TRUE; + + gdkdev->info.mode = mode; + + if (mode == GDK_MODE_WINDOW) + { + gdkdev->info.has_cursor = FALSE; + for (tmp_list = gdk_input_windows; tmp_list; tmp_list = tmp_list->next) + { + input_window = (GdkInputWindow *)tmp_list->data; + if (input_window->mode != GDK_EXTENSION_EVENTS_CURSOR) + gdk_input_win32_enable_window (input_window->window, gdkdev); + else + if (old_mode != GDK_MODE_DISABLED) + gdk_input_win32_disable_window (input_window->window, gdkdev); + } + } + else if (mode == GDK_MODE_SCREEN) + { + gdkdev->info.has_cursor = TRUE; + for (tmp_list = gdk_input_windows; tmp_list; tmp_list = tmp_list->next) + gdk_input_win32_enable_window (((GdkInputWindow *)tmp_list->data)->window, + gdkdev); + } + else /* mode == GDK_MODE_DISABLED */ + { + for (tmp_list = gdk_input_windows; tmp_list; tmp_list = tmp_list->next) + { + input_window = (GdkInputWindow *)tmp_list->data; + if (old_mode != GDK_MODE_WINDOW || + input_window->mode != GDK_EXTENSION_EVENTS_CURSOR) + gdk_input_win32_disable_window (input_window->window, gdkdev); + } + } + + return TRUE; +} + +static void +gdk_input_win32_configure_event (GdkEventConfigure *event, + GdkWindow *window) +{ + GdkInputWindow *input_window; + gint root_x, root_y; + + input_window = gdk_input_window_find (window); + g_return_if_fail (window != NULL); + + gdk_input_get_root_relative_geometry + (GDK_DRAWABLE_XID (window), &root_x, &root_y); + + input_window->root_x = root_x; + input_window->root_y = root_y; +} + +static void +gdk_input_win32_enter_event (GdkEventCrossing *event, + GdkWindow *window) +{ + GdkInputWindow *input_window; + gint root_x, root_y; + + input_window = gdk_input_window_find (window); + g_return_if_fail (window != NULL); + + gdk_input_get_root_relative_geometry + (GDK_DRAWABLE_XID (window), &root_x, &root_y); + + input_window->root_x = root_x; + input_window->root_y = root_y; +} + +static void +decode_tilt (gint *axis_data, + AXIS *axes, + PACKET *packet) +{ + /* As I don't have a tilt-sensing tablet, + * I cannot test this code. + */ + + double az, el; + + az = TWOPI * packet->pkOrientation.orAzimuth / + (axes[0].axResolution / 65536.); + el = TWOPI * packet->pkOrientation.orAltitude / + (axes[1].axResolution / 65536.); + + /* X tilt */ + axis_data[0] = cos (az) * cos (el) * 1000; + /* Y tilt */ + axis_data[1] = sin (az) * cos (el) * 1000; +} + +static GdkDevicePrivate * +gdk_input_find_dev_from_ctx (HCTX hctx, + UINT cursor) +{ + GList *tmp_list = gdk_input_devices; + GdkDevicePrivate *gdkdev; + + while (tmp_list) + { + gdkdev = (GdkDevicePrivate *) (tmp_list->data); + if (gdkdev->hctx == hctx && gdkdev->cursor == cursor) + return gdkdev; + tmp_list = tmp_list->next; + } + return NULL; +} +static gint +gdk_input_win32_other_event (GdkEvent *event, + MSG *xevent) +{ + GdkWindow *current_window; + GdkInputWindow *input_window; + GdkWindow *window; + GdkWindowPrivate *window_private; + GdkDevicePrivate *gdkdev; + GdkEventMask masktest; + POINT pt; + PACKET packet; + gint return_val; + gint k; + gint x, y; + + if (event->any.window != wintab_window) + g_warning ("gdk_input_win32_other_event: not wintab_window?"); + +#if USE_SYSCONTEXT + window = gdk_window_at_pointer (&x, &y); + if (window == NULL) + window = (GdkWindow *) gdk_root_parent; + + gdk_window_ref (window); + + window_private = (GdkWindowPrivate *) window; + + GDK_NOTE (EVENTS, + g_print ("gdk_input_win32_other_event: window=%#x (%d,%d)\n", + GDK_DRAWABLE_XID (window), x, y)); + +#else + /* ??? This code is pretty bogus */ + current_window = gdk_window_lookup (GetActiveWindow ()); + if (current_window == NULL) + return FALSE; + + input_window = gdk_input_window_find_within (current_window); + if (input_window == NULL) + return FALSE; +#endif + + if (xevent->message == WT_PACKET) + { + if (!WTPacket ((HCTX) xevent->lParam, xevent->wParam, &packet)) + return FALSE; + } + + switch (xevent->message) + { + case WT_PACKET: + if (window_private == gdk_root_parent) + { + GDK_NOTE (EVENTS, g_print ("...is root\n")); + return FALSE; + } + + if ((gdkdev = gdk_input_find_dev_from_ctx ((HCTX) xevent->lParam, + packet.pkCursor)) == NULL) + return FALSE; + + if (gdkdev->info.mode == GDK_MODE_DISABLED) + return FALSE; + + k = 0; + if (gdkdev->pktdata & PK_X) + gdkdev->last_axis_data[k++] = packet.pkX; + if (gdkdev->pktdata & PK_Y) + gdkdev->last_axis_data[k++] = packet.pkY; + if (gdkdev->pktdata & PK_NORMAL_PRESSURE) + gdkdev->last_axis_data[k++] = packet.pkNormalPressure; + if (gdkdev->pktdata & PK_ORIENTATION) + { + decode_tilt (gdkdev->last_axis_data + k, + gdkdev->orientation_axes, &packet); + k += 2; + } + + g_assert (k == gdkdev->info.num_axes); + + if (HIWORD (packet.pkButtons) != TBN_NONE) + { + /* Gdk buttons are numbered 1.. */ + event->button.button = 1 + LOWORD (packet.pkButtons); + + if (HIWORD (packet.pkButtons) == TBN_UP) + { + event->any.type = GDK_BUTTON_RELEASE; + masktest = GDK_BUTTON_RELEASE_MASK; + gdkdev->button_state &= ~(1 << LOWORD (packet.pkButtons)); + } + else + { + event->any.type = GDK_BUTTON_PRESS; + masktest = GDK_BUTTON_PRESS_MASK; + gdkdev->button_state |= 1 << LOWORD (packet.pkButtons); + } + } + else + { + event->any.type = GDK_MOTION_NOTIFY; + masktest = GDK_POINTER_MOTION_MASK; + if (gdkdev->button_state & (1 << 0)) + masktest |= GDK_BUTTON_MOTION_MASK | GDK_BUTTON1_MOTION_MASK; + if (gdkdev->button_state & (1 << 1)) + masktest |= GDK_BUTTON_MOTION_MASK | GDK_BUTTON2_MOTION_MASK; + if (gdkdev->button_state & (1 << 2)) + masktest |= GDK_BUTTON_MOTION_MASK | GDK_BUTTON3_MOTION_MASK; + } + + /* Now we can check if the window wants the event, and + * propagate if necessary. + */ + dijkstra: + if (!window_private->extension_events_selected + || !(window_private->extension_events & masktest)) + { + GDK_NOTE (EVENTS, g_print ("...not selected\n")); + + if (window_private->parent == (GdkWindow *) gdk_root_parent) + return FALSE; + + pt.x = x; + pt.y = y; + ClientToScreen (GDK_DRAWABLE_XID (window), &pt); + gdk_window_unref (window); + window = window_private->parent; + gdk_window_ref (window); + window_private = (GdkWindowPrivate *) window; + ScreenToClient (GDK_DRAWABLE_XID (window), &pt); + x = pt.x; + y = pt.y; + GDK_NOTE (EVENTS, g_print ("...propagating to %#x, (%d,%d)\n", + GDK_DRAWABLE_XID (window), x, y)); + goto dijkstra; + } + + input_window = gdk_input_window_find (window); + + g_assert (input_window != NULL); + + if (gdkdev->info.mode == GDK_MODE_WINDOW + && input_window->mode == GDK_EXTENSION_EVENTS_CURSOR) + return FALSE; + + event->any.window = window; + + if (event->any.type == GDK_BUTTON_PRESS + || event->any.type == GDK_BUTTON_RELEASE) + { + event->button.time = xevent->time; + event->button.source = gdkdev->info.source; + last_moved_cursor_id = + event->button.deviceid = gdkdev->info.deviceid; + +#if 0 +#if USE_SYSCONTEXT + /* Buttons 1 to 3 will come in as WM_[LMR]BUTTON{DOWN,UP} */ + if (event->button.button <= 3) + return FALSE; +#endif +#endif + gdk_input_translate_coordinates (gdkdev, input_window, + gdkdev->last_axis_data, + &event->button.x, &event->button.y, + &event->button.pressure, + &event->button.xtilt, + &event->button.ytilt); + + event->button.state = ((gdkdev->button_state << 8) + & (GDK_BUTTON1_MASK | GDK_BUTTON2_MASK + | GDK_BUTTON3_MASK | GDK_BUTTON4_MASK + | GDK_BUTTON5_MASK)); + GDK_NOTE (EVENTS, g_print ("WINTAB button %s: %d %d %g,%g %g %g,%g\n", + (event->button.type == GDK_BUTTON_PRESS ? + "press" : "release"), + event->button.deviceid, + event->button.button, + event->button.x, event->button.y, + event->button.pressure, + event->button.xtilt, event->button.ytilt)); + } + else + { + event->motion.time = xevent->time; + last_moved_cursor_id = + event->motion.deviceid = gdkdev->info.deviceid; + event->motion.is_hint = FALSE; + event->motion.source = gdkdev->info.source; + + gdk_input_translate_coordinates (gdkdev, input_window, + gdkdev->last_axis_data, + &event->motion.x, &event->motion.y, + &event->motion.pressure, + &event->motion.xtilt, + &event->motion.ytilt); + + event->motion.state = ((gdkdev->button_state << 8) + & (GDK_BUTTON1_MASK | GDK_BUTTON2_MASK + | GDK_BUTTON3_MASK | GDK_BUTTON4_MASK + | GDK_BUTTON5_MASK)); + + GDK_NOTE (EVENTS, g_print ("WINTAB motion: %d %g,%g %g %g,%g\n", + event->motion.deviceid, + event->motion.x, event->motion.y, + event->motion.pressure, + event->motion.xtilt, event->motion.ytilt)); + + /* Check for missing release or press events for the normal + * pressure button. At least on my ArtPadII I sometimes miss a + * release event? + */ + if ((gdkdev->pktdata & PK_NORMAL_PRESSURE + && (event->motion.state & GDK_BUTTON1_MASK) + && packet.pkNormalPressure <= MAX (0, gdkdev->npbtnmarks[0] - 2)) + || (gdkdev->pktdata & PK_NORMAL_PRESSURE + && !(event->motion.state & GDK_BUTTON1_MASK) + && packet.pkNormalPressure > gdkdev->npbtnmarks[1] + 2)) + { + GdkEvent *event2 = gdk_event_copy (event); + if (event->motion.state & GDK_BUTTON1_MASK) + { + event2->button.type = GDK_BUTTON_RELEASE; + gdkdev->button_state &= ~1; + } + else + { + event2->button.type = GDK_BUTTON_PRESS; + gdkdev->button_state |= 1; + } + event2->button.state = ((gdkdev->button_state << 8) + & (GDK_BUTTON1_MASK | GDK_BUTTON2_MASK + | GDK_BUTTON3_MASK | GDK_BUTTON4_MASK + | GDK_BUTTON5_MASK)); + event2->button.button = 1; + GDK_NOTE (EVENTS, g_print ("WINTAB synthesized button %s: %d %d %g,%g %g\n", + (event2->button.type == GDK_BUTTON_PRESS ? + "press" : "release"), + event2->button.deviceid, + event2->button.button, + event2->button.x, event2->button.y, + event2->button.pressure)); + gdk_event_queue_append (event2); + } + } + return TRUE; + + case WT_PROXIMITY: + if (LOWORD (xevent->lParam) == 0) + { + event->proximity.type = GDK_PROXIMITY_OUT; + gdk_input_ignore_core = FALSE; + } + else + { + event->proximity.type = GDK_PROXIMITY_IN; + gdk_input_ignore_core = TRUE; + } + event->proximity.time = xevent->time; + event->proximity.source = GDK_SOURCE_PEN; + event->proximity.deviceid = last_moved_cursor_id; + + GDK_NOTE (EVENTS, g_print ("WINTAB proximity %s: %d\n", + (event->proximity.type == GDK_PROXIMITY_IN ? + "in" : "out"), + event->proximity.deviceid)); + return TRUE; + } + return FALSE; +} + +static gint +gdk_input_win32_enable_window (GdkWindow *window, + GdkDevicePrivate *gdkdev) +{ + GdkWindowPrivate *window_private = (GdkWindowPrivate *) window; + + window_private->extension_events_selected = TRUE; + return TRUE; +} + +static gint +gdk_input_win32_disable_window (GdkWindow *window, + GdkDevicePrivate *gdkdev) +{ + GdkWindowPrivate *window_private = (GdkWindowPrivate *) window; + + window_private->extension_events_selected = FALSE; + return TRUE; +} + +static gint +gdk_input_win32_grab_pointer (GdkWindow *window, + gint owner_events, + GdkEventMask event_mask, + GdkWindow *confine_to, + guint32 time) +{ + GdkInputWindow *input_window, *new_window; + gboolean need_ungrab; + GdkDevicePrivate *gdkdev; + GList *tmp_list; + gint result; + + tmp_list = gdk_input_windows; + new_window = NULL; + need_ungrab = FALSE; + + GDK_NOTE (MISC, g_print ("gdk_input_win32_grab_pointer: %#x %d %#x\n", + GDK_DRAWABLE_XID (window), + owner_events, + (confine_to ? GDK_DRAWABLE_XID (confine_to) : 0))); + + while (tmp_list) + { + input_window = (GdkInputWindow *)tmp_list->data; + + if (input_window->window == window) + new_window = input_window; + else if (input_window->grabbed) + { + input_window->grabbed = FALSE; + need_ungrab = TRUE; + } + + tmp_list = tmp_list->next; + } + + if (new_window) + { + new_window->grabbed = TRUE; + + tmp_list = gdk_input_devices; + while (tmp_list) + { + gdkdev = (GdkDevicePrivate *)tmp_list->data; + if (gdkdev->info.deviceid != GDK_CORE_POINTER) + { +#if 0 + /* XXX */ + gdk_input_find_events (window, gdkdev, + event_mask, + event_classes, &num_classes); + result = XGrabDevice (GDK_DISPLAY(), gdkdev->xdevice, + GDK_WINDOW_XWINDOW (window), + owner_events, num_classes, event_classes, + GrabModeAsync, GrabModeAsync, time); + + /* FIXME: if failure occurs on something other than the first + device, things will be badly inconsistent */ + if (result != Success) + return result; +#endif + } + tmp_list = tmp_list->next; + } + } + else + { + tmp_list = gdk_input_devices; + while (tmp_list) + { + gdkdev = (GdkDevicePrivate *)tmp_list->data; + if (gdkdev->info.deviceid != GDK_CORE_POINTER && + ((gdkdev->button_state != 0) || need_ungrab)) + { +#if 0 + /* XXX */ + XUngrabDevice (gdk_display, gdkdev->xdevice, time); +#endif + gdkdev->button_state = 0; + } + + tmp_list = tmp_list->next; + } + } + + return Success; + +} + +static void +gdk_input_win32_ungrab_pointer (guint32 time) +{ + GdkInputWindow *input_window; + GdkDevicePrivate *gdkdev; + GList *tmp_list; + + GDK_NOTE (MISC, g_print ("gdk_input_win32_ungrab_pointer\n")); + + tmp_list = gdk_input_windows; + while (tmp_list) + { + input_window = (GdkInputWindow *)tmp_list->data; + if (input_window->grabbed) + break; + tmp_list = tmp_list->next; + } + + if (tmp_list) /* we found a grabbed window */ + { + input_window->grabbed = FALSE; + + tmp_list = gdk_input_devices; + while (tmp_list) + { + gdkdev = (GdkDevicePrivate *)tmp_list->data; +#if 0 + /* XXX */ + if (gdkdev->info.deviceid != GDK_CORE_POINTER && gdkdev->xdevice) + XUngrabDevice (gdk_display, gdkdev->xdevice, time); +#endif + tmp_list = tmp_list->next; + } + } +} + +#endif /* HAVE_WINTAB */ + +GList * +gdk_input_list_devices (void) +{ + return gdk_input_devices; +} + +void +gdk_input_set_source (guint32 deviceid, + GdkInputSource source) +{ + GdkDevicePrivate *gdkdev = gdk_input_find_device (deviceid); + g_return_if_fail (gdkdev != NULL); + + gdkdev->info.source = source; +} + +void gdk_input_set_key (guint32 deviceid, + guint index, + guint keyval, + GdkModifierType modifiers) +{ + if (deviceid != GDK_CORE_POINTER && gdk_input_vtable.set_key) + gdk_input_vtable.set_key (deviceid, index, keyval, modifiers); +} + +GdkTimeCoord * +gdk_input_motion_events (GdkWindow *window, + guint32 deviceid, + guint32 start, + guint32 stop, + gint *nevents_return) +{ + g_return_val_if_fail (window != NULL, NULL); + if (GDK_DRAWABLE_DESTROYED (window)) + return NULL; + + *nevents_return = 0; + return NULL; /* ??? */ +} + +static gint +gdk_input_enable_window (GdkWindow *window, GdkDevicePrivate *gdkdev) +{ + if (gdk_input_vtable.enable_window) + return gdk_input_vtable.enable_window (window, gdkdev); + else + return TRUE; +} + +static gint +gdk_input_disable_window (GdkWindow *window, GdkDevicePrivate *gdkdev) +{ + if (gdk_input_vtable.disable_window) + return gdk_input_vtable.disable_window(window,gdkdev); + else + return TRUE; +} + + +static GdkInputWindow * +gdk_input_window_find (GdkWindow *window) +{ + GList *tmp_list; + + for (tmp_list=gdk_input_windows; tmp_list; tmp_list=tmp_list->next) + if (((GdkInputWindow *)(tmp_list->data))->window == window) + return (GdkInputWindow *)(tmp_list->data); + + return NULL; /* Not found */ +} + +#if !USE_SYSCONTEXT + +static GdkInputWindow * +gdk_input_window_find_within (GdkWindow *window) +{ + GList *tmp_list; + GdkWindowPrivate *window_private; + GdkWindowPrivate *tmp_private; + GdkInputWindow *candidate = NULL; + + window_private = (GdkWindowPrivate *) window; + + for (tmp_list=gdk_input_windows; tmp_list; tmp_list=tmp_list->next) + { + (GdkWindowPrivate *) tmp_private = + (GdkWindowPrivate *) (((GdkInputWindow *)(tmp_list->data))->window); + if (tmp_private == window_private + || IsChild (window_private->xwindow, tmp_private->xwindow)) + { + if (candidate) + return NULL; /* Multiple hits */ + candidate = (GdkInputWindow *)(tmp_list->data); + } + } + + return candidate; +} + +#endif + +/* FIXME: this routine currently needs to be called between creation + and the corresponding configure event (because it doesn't get the + root_relative_geometry). This should work with + gtk_window_set_extension_events, but will likely fail in other + cases */ + +void +gdk_input_set_extension_events (GdkWindow *window, + gint mask, + GdkExtensionMode mode) +{ + GdkWindowPrivate *window_private; + GList *tmp_list; + GdkInputWindow *iw; + + g_return_if_fail (window != NULL); + if (GDK_DRAWABLE_DESTROYED (window)) + return; + window_private = (GdkWindowPrivate *) window; + + if (mode == GDK_EXTENSION_EVENTS_NONE) + mask = 0; + + if (mask != 0) + { + iw = g_new (GdkInputWindow,1); + + iw->window = window; + iw->mode = mode; + + iw->grabbed = FALSE; + + gdk_input_windows = g_list_append (gdk_input_windows, iw); + window_private->extension_events = mask; + + /* Add enter window events to the event mask */ + gdk_window_set_events (window, + gdk_window_get_events (window) | + GDK_ENTER_NOTIFY_MASK); + } + else + { + iw = gdk_input_window_find (window); + if (iw) + { + gdk_input_windows = g_list_remove (gdk_input_windows, iw); + g_free (iw); + } + + window_private->extension_events = 0; + } + + for (tmp_list = gdk_input_devices; tmp_list; tmp_list = tmp_list->next) + { + GdkDevicePrivate *gdkdev = (GdkDevicePrivate *)(tmp_list->data); + + if (gdkdev->info.deviceid != GDK_CORE_POINTER) + { + if (mask != 0 && gdkdev->info.mode != GDK_MODE_DISABLED + && (gdkdev->info.has_cursor || mode == GDK_EXTENSION_EVENTS_ALL)) + gdk_input_enable_window (window, gdkdev); + else + gdk_input_disable_window (window, gdkdev); + } + } +} + +void +gdk_input_window_destroy (GdkWindow *window) +{ + GdkInputWindow *input_window; + + input_window = gdk_input_window_find (window); + g_return_if_fail (input_window != NULL); + + gdk_input_windows = g_list_remove (gdk_input_windows,input_window); + g_free (input_window); +} + +void +gdk_input_exit (void) +{ +#ifdef HAVE_WINTAB + GList *tmp_list; + GdkDevicePrivate *gdkdev; + + for (tmp_list = gdk_input_devices; tmp_list; tmp_list = tmp_list->next) + { + gdkdev = (GdkDevicePrivate *)(tmp_list->data); + if (gdkdev->info.deviceid != GDK_CORE_POINTER) + { + gdk_input_win32_set_mode (gdkdev->info.deviceid, GDK_MODE_DISABLED); + g_free (gdkdev->info.name); + g_free (gdkdev->last_axis_data); + g_free (gdkdev->info.axes); + g_free (gdkdev->info.keys); + g_free (gdkdev->axes); + g_free (gdkdev); + } + } + + g_list_free (gdk_input_devices); + + for (tmp_list = gdk_input_windows; tmp_list; tmp_list = tmp_list->next) + { + g_free (tmp_list->data); + } + g_list_free (gdk_input_windows); + gdk_input_windows = NULL; + + gdk_window_unref (wintab_window); + wintab_window = NULL; + +#if 1 + for (tmp_list = wintab_contexts; tmp_list; tmp_list = tmp_list->next) + { + HCTX *hctx = (HCTX *) tmp_list->data; + BOOL result; + +#ifdef _MSC_VER + /* For some reason WTEnable and/or WTClose tend to crash here. + * Protect with __try/__except to avoid a message box. + * When compiling with gcc, we cannot use __try/__except, so + * don't call WTClose. I think this means that we'll + * eventually run out of Wintab contexts, sigh. + */ + __try { +#if 0 + WTEnable (*hctx, FALSE); +#endif + result = WTClose (*hctx); + } + __except (/* GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ? */ + EXCEPTION_EXECUTE_HANDLER /*: + EXCEPTION_CONTINUE_SEARCH */) { + result = FALSE; + } + if (!result) + g_warning ("gdk_input_exit: Closing Wintab context %#x failed", *hctx); +#endif /* _MSC_VER */ + g_free (hctx); + } +#endif + g_list_free (wintab_contexts); + wintab_contexts = NULL; +#endif +} + +static GdkDevicePrivate * +gdk_input_find_device (guint32 id) +{ + GList *tmp_list = gdk_input_devices; + GdkDevicePrivate *gdkdev; + + while (tmp_list) + { + gdkdev = (GdkDevicePrivate *) (tmp_list->data); + if (gdkdev->info.deviceid == id) + return gdkdev; + tmp_list = tmp_list->next; + } + return NULL; +} + +void +gdk_input_window_get_pointer (GdkWindow *window, + guint32 deviceid, + gdouble *x, + gdouble *y, + gdouble *pressure, + gdouble *xtilt, + gdouble *ytilt, + GdkModifierType *mask) +{ + if (gdk_input_vtable.get_pointer) + gdk_input_vtable.get_pointer (window, deviceid, x, y, pressure, + xtilt, ytilt, mask); +} diff --git a/gdk/win32/gdkmain-win32.c b/gdk/win32/gdkmain-win32.c new file mode 100644 index 000000000..e8fa5af5d --- /dev/null +++ b/gdk/win32/gdkmain-win32.c @@ -0,0 +1,2115 @@ +/* GDK - The GIMP Drawing Kit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * Copyright (C) 1998-1999 Tor Lillqvist + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* + * Modified by the GTK+ Team and others 1997-1999. See the AUTHORS + * file for a list of people on the GTK+ Team. See the ChangeLog + * files for a list of changes. These files are distributed with + * GTK+ at ftp://ftp.gtk.org/pub/gtk/. + */ + +#include "config.h" + +#include +#include +#include +#include +#include + +#include "gdk.h" +#include "gdkprivate.h" +#include "gdkinputprivate.h" +#include "gdkkeysyms.h" + +#include + +static void gdkx_XConvertCase (KeySym symbol, + KeySym *lower, + KeySym *upper); +static void gdk_exit_func (void); + + +/* Private variable declarations + */ +static int gdk_initialized = 0; /* 1 if the library is initialized, + * 0 otherwise. + */ +#ifdef G_ENABLE_DEBUG +static const GDebugKey gdk_debug_keys[] = { + {"events", GDK_DEBUG_EVENTS}, + {"misc", GDK_DEBUG_MISC}, + {"dnd", GDK_DEBUG_DND}, + {"color-context", GDK_DEBUG_COLOR_CONTEXT}, + {"xim", GDK_DEBUG_XIM}, + {"selection", GDK_DEBUG_SELECTION} +}; + +static const int gdk_ndebug_keys = sizeof(gdk_debug_keys)/sizeof(GDebugKey); + +#endif /* G_ENABLE_DEBUG */ + +int __stdcall +DllMain(HINSTANCE hinstDLL, + DWORD dwReason, + LPVOID reserved) +{ + gdk_DLLInstance = hinstDLL; + + return TRUE; +} + +/* + *-------------------------------------------------------------- + * gdk_init + * + * Initialize the library for use. + * + * Arguments: + * "argc" is the number of arguments. + * "argv" is an array of strings. + * + * Results: + * "argc" and "argv" are modified to reflect any arguments + * which were not handled. (Such arguments should either + * be handled by the application or dismissed). + * + * Side effects: + * The library is initialized. + * + *-------------------------------------------------------------- + */ + +gboolean +gdk_init_check (int *argc, + char ***argv) +{ + gint i, j, k; + + if (gdk_initialized) + return TRUE; + + if (g_thread_supported ()) + gdk_threads_mutex = g_mutex_new (); + +#ifdef G_ENABLE_DEBUG + { + gchar *debug_string = getenv("GDK_DEBUG"); + if (debug_string != NULL) + gdk_debug_flags = g_parse_debug_string (debug_string, + (GDebugKey *) gdk_debug_keys, + gdk_ndebug_keys); + } +#endif /* G_ENABLE_DEBUG */ + + if (getenv ("GDK_IGNORE_WINTAB") != NULL) + gdk_input_ignore_wintab = TRUE; + + if (getenv ("GDK_EVENT_FUNC_FROM_WINDOW_PROC") != NULL) + gdk_event_func_from_window_proc = TRUE; + + if (argc && argv) + { + if (*argc > 0) + { + gchar *d; + + d = strrchr((*argv)[0], G_DIR_SEPARATOR); + if (d != NULL) + g_set_prgname (d + 1); + else + g_set_prgname ((*argv)[0]); + } + + for (i = 1; i < *argc;) + { +#ifdef G_ENABLE_DEBUG + if ((strcmp ("--gdk-debug", (*argv)[i]) == 0) || + (strncmp ("--gdk-debug=", (*argv)[i], 12) == 0)) + { + gchar *equal_pos = strchr ((*argv)[i], '='); + + if (equal_pos != NULL) + { + gdk_debug_flags |= g_parse_debug_string (equal_pos+1, + (GDebugKey *) gdk_debug_keys, + gdk_ndebug_keys); + } + else if ((i + 1) < *argc && (*argv)[i + 1]) + { + gdk_debug_flags |= g_parse_debug_string ((*argv)[i+1], + (GDebugKey *) gdk_debug_keys, + gdk_ndebug_keys); + (*argv)[i] = NULL; + i += 1; + } + (*argv)[i] = NULL; + } + else if ((strcmp ("--gdk-no-debug", (*argv)[i]) == 0) || + (strncmp ("--gdk-no-debug=", (*argv)[i], 15) == 0)) + { + gchar *equal_pos = strchr ((*argv)[i], '='); + + if (equal_pos != NULL) + { + gdk_debug_flags &= ~g_parse_debug_string (equal_pos+1, + (GDebugKey *) gdk_debug_keys, + gdk_ndebug_keys); + } + else if ((i + 1) < *argc && (*argv)[i + 1]) + { + gdk_debug_flags &= ~g_parse_debug_string ((*argv)[i+1], + (GDebugKey *) gdk_debug_keys, + gdk_ndebug_keys); + (*argv)[i] = NULL; + i += 1; + } + (*argv)[i] = NULL; + } + else +#endif /* G_ENABLE_DEBUG */ + if (strcmp ("--sync", (*argv)[i]) == 0) + { + (*argv)[i] = NULL; + GdiSetBatchLimit (1); + } + else if (strcmp ("--name", (*argv)[i]) == 0) + { + if ((i + 1) < *argc && (*argv)[i + 1]) + { + (*argv)[i++] = NULL; + g_set_prgname ((*argv)[i]); + (*argv)[i] = NULL; + } + } + else if (strcmp ("--gdk-no-wintab", (*argv)[i]) == 0 + || strcmp ("--gdk-ignore-wintab", (*argv)[i]) == 0) + { + (*argv)[i] = NULL; + gdk_input_ignore_wintab = TRUE; + } + else if (strcmp ("--gdk-event-func-from-window-proc", (*argv)[i]) == 0) + { + (*argv)[i] = NULL; + gdk_event_func_from_window_proc = TRUE; + } + i += 1; + } + + for (i = 1; i < *argc; i++) + { + for (k = i; k < *argc; k++) + if ((*argv)[k] != NULL) + break; + + if (k > i) + { + k -= i; + for (j = i + k; j < *argc; j++) + (*argv)[j-k] = (*argv)[j]; + *argc -= k; + } + } + } + else + { + g_set_prgname (""); + } + + gdk_ProgInstance = GetModuleHandle (NULL); + gdk_DC = CreateDC ("DISPLAY", NULL, NULL, NULL); + gdk_root_window = GetDesktopWindow (); + windows_version = GetVersion (); + + CoInitialize (NULL); + + gdk_selection_request_msg = RegisterWindowMessage ("gdk-selection-request"); + gdk_selection_notify_msg = RegisterWindowMessage ("gdk-selection-notify"); + gdk_selection_clear_msg = RegisterWindowMessage ("gdk-selection-clear"); + + gdk_selection_property = gdk_atom_intern ("GDK_SELECTION", FALSE); + gdk_clipboard_atom = gdk_atom_intern ("CLIPBOARD", FALSE); + gdk_win32_dropfiles_atom = gdk_atom_intern ("DROPFILES_DND", FALSE); + gdk_ole2_dnd_atom = gdk_atom_intern ("OLE2_DND", FALSE); + + gdk_progclass = g_basename (g_get_prgname ()); + gdk_progclass[0] = toupper (gdk_progclass[0]); + + g_atexit (gdk_exit_func); + + gdk_events_init (); + gdk_visual_init (); + gdk_window_init (); + gdk_image_init (); + gdk_input_init (); + gdk_selection_init (); + gdk_dnd_init (); + + gdk_initialized = 1; + + return TRUE; +} + +void +gdk_init (int *argc, char ***argv) +{ + if (!gdk_init_check (argc, argv)) + { + g_warning ("cannot initialize GDK"); + exit(1); + } +} + +/* + *-------------------------------------------------------------- + * gdk_exit + * + * Restores the library to an un-itialized state and exits + * the program using the "exit" system call. + * + * Arguments: + * "errorcode" is the error value to pass to "exit". + * + * Results: + * Allocated structures are freed and the program exits + * cleanly. + * + * Side effects: + * + *-------------------------------------------------------------- + */ + +void +gdk_exit (gint errorcode) +{ + /* de-initialisation is done by the gdk_exit_func(), + no need to do this here (Alex J.) */ + exit (errorcode); +} + +void +gdk_set_use_xshm (gint use_xshm) +{ + /* Always on */ +} + +gint +gdk_get_use_xshm (void) +{ + return TRUE; +} + +/* + *-------------------------------------------------------------- + * gdk_screen_width + * + * Return the width of the screen. + * + * Arguments: + * + * Results: + * + * Side effects: + * + *-------------------------------------------------------------- + */ + +gint +gdk_screen_width (void) +{ + gint return_val; + + return_val = gdk_root_parent->drawable.width; + + return return_val; +} + +/* + *-------------------------------------------------------------- + * gdk_screen_height + * + * Return the height of the screen. + * + * Arguments: + * + * Results: + * + * Side effects: + * + *-------------------------------------------------------------- + */ + +gint +gdk_screen_height (void) +{ + gint return_val; + + return_val = gdk_root_parent->drawable.height; + + return return_val; +} + +/* + *-------------------------------------------------------------- + * gdk_screen_width_mm + * + * Return the width of the screen in millimetres. + * + * Arguments: + * + * Results: + * + * Side effects: + * + *-------------------------------------------------------------- + */ + +gint +gdk_screen_width_mm (void) +{ + HDC hdc; + gint return_val; + + hdc = GetDC (NULL); + return_val = GetDeviceCaps (hdc, HORZSIZE); + ReleaseDC (NULL, hdc); + + return return_val; +} + +/* + *-------------------------------------------------------------- + * gdk_screen_height + * + * Return the height of the screen in millimetres. + * + * Arguments: + * + * Results: + * + * Side effects: + * + *-------------------------------------------------------------- + */ + +gint +gdk_screen_height_mm (void) +{ + HDC hdc; + gint return_val; + + hdc = GetDC (NULL); + return_val = GetDeviceCaps (hdc, VERTSIZE); + ReleaseDC (NULL, hdc); + + return return_val; +} + +void +gdk_key_repeat_disable (void) +{ + /* XXX */ +} + +void +gdk_key_repeat_restore (void) +{ + /* XXX */ +} + + +/* + *-------------------------------------------------------------- + * gdk_flush + * + * Flushes the Xlib output buffer and then waits + * until all requests have been received and processed + * by the X server. The only real use for this function + * is in dealing with XShm. + * + * Arguments: + * + * Results: + * + * Side effects: + * + *-------------------------------------------------------------- + */ + +void +gdk_flush (void) +{ + GdiFlush (); +} + +void +gdk_beep (void) +{ + Beep(1000, 50); +} + +/* + *-------------------------------------------------------------- + * gdk_exit_func + * + * This is the "atexit" function that makes sure the + * library gets a chance to cleanup. + * + * Arguments: + * + * Results: + * + * Side effects: + * The library is un-initialized and the program exits. + * + *-------------------------------------------------------------- + */ + +static void +gdk_exit_func (void) +{ + static gboolean in_gdk_exit_func = FALSE; + + GDK_NOTE (MISC, g_print ("gdk_exit_func\n")); + /* This is to avoid an infinite loop if a program segfaults in + an atexit() handler (and yes, it does happen, especially if a program + has trounced over memory too badly for even g_message to work) */ + if (in_gdk_exit_func == TRUE) + return; + in_gdk_exit_func = TRUE; + + if (gdk_initialized) + { + gdk_image_exit (); + gdk_input_exit (); + gdk_key_repeat_restore (); + gdk_dnd_exit (); + + CoUninitialize (); + + DeleteDC (gdk_DC); + gdk_DC = NULL; + gdk_initialized = 0; + } +} + +gchar * +gdk_get_display(void) +{ + return "local:"; +} + +/************************************************************* + * gdk_error_trap_push: + * Push an error trap. X errors will be trapped until + * the corresponding gdk_error_pop(), which will return + * the error code, if any. + * arguments: + * + * results: + *************************************************************/ + +void +gdk_error_trap_push (void) +{ + /* ??? */ +} + +/************************************************************* + * gdk_error_trap_pop: + * Pop an error trap added with gdk_error_push() + * arguments: + * + * results: + * 0, if no error occured, otherwise the error code. + *************************************************************/ + +gint +gdk_error_trap_pop (void) +{ + /* ??? */ + return 0; +} + +static void +gdkx_XConvertCase (KeySym symbol, + KeySym *lower, + KeySym *upper) +{ + register KeySym sym = symbol; + + g_return_if_fail (lower != NULL); + g_return_if_fail (upper != NULL); + + *lower = sym; + *upper = sym; + + switch (sym >> 8) + { +#if defined (GDK_A) && defined (GDK_Ooblique) + case 0: /* Latin 1 */ + if ((sym >= GDK_A) && (sym <= GDK_Z)) + *lower += (GDK_a - GDK_A); + else if ((sym >= GDK_a) && (sym <= GDK_z)) + *upper -= (GDK_a - GDK_A); + else if ((sym >= GDK_Agrave) && (sym <= GDK_Odiaeresis)) + *lower += (GDK_agrave - GDK_Agrave); + else if ((sym >= GDK_agrave) && (sym <= GDK_odiaeresis)) + *upper -= (GDK_agrave - GDK_Agrave); + else if ((sym >= GDK_Ooblique) && (sym <= GDK_Thorn)) + *lower += (GDK_oslash - GDK_Ooblique); + else if ((sym >= GDK_oslash) && (sym <= GDK_thorn)) + *upper -= (GDK_oslash - GDK_Ooblique); + break; +#endif /* LATIN1 */ + +#if defined (GDK_Aogonek) && defined (GDK_tcedilla) + case 1: /* Latin 2 */ + /* Assume the KeySym is a legal value (ignore discontinuities) */ + if (sym == GDK_Aogonek) + *lower = GDK_aogonek; + else if (sym >= GDK_Lstroke && sym <= GDK_Sacute) + *lower += (GDK_lstroke - GDK_Lstroke); + else if (sym >= GDK_Scaron && sym <= GDK_Zacute) + *lower += (GDK_scaron - GDK_Scaron); + else if (sym >= GDK_Zcaron && sym <= GDK_Zabovedot) + *lower += (GDK_zcaron - GDK_Zcaron); + else if (sym == GDK_aogonek) + *upper = GDK_Aogonek; + else if (sym >= GDK_lstroke && sym <= GDK_sacute) + *upper -= (GDK_lstroke - GDK_Lstroke); + else if (sym >= GDK_scaron && sym <= GDK_zacute) + *upper -= (GDK_scaron - GDK_Scaron); + else if (sym >= GDK_zcaron && sym <= GDK_zabovedot) + *upper -= (GDK_zcaron - GDK_Zcaron); + else if (sym >= GDK_Racute && sym <= GDK_Tcedilla) + *lower += (GDK_racute - GDK_Racute); + else if (sym >= GDK_racute && sym <= GDK_tcedilla) + *upper -= (GDK_racute - GDK_Racute); + break; +#endif /* LATIN2 */ + +#if defined (GDK_Hstroke) && defined (GDK_Cabovedot) + case 2: /* Latin 3 */ + /* Assume the KeySym is a legal value (ignore discontinuities) */ + if (sym >= GDK_Hstroke && sym <= GDK_Hcircumflex) + *lower += (GDK_hstroke - GDK_Hstroke); + else if (sym >= GDK_Gbreve && sym <= GDK_Jcircumflex) + *lower += (GDK_gbreve - GDK_Gbreve); + else if (sym >= GDK_hstroke && sym <= GDK_hcircumflex) + *upper -= (GDK_hstroke - GDK_Hstroke); + else if (sym >= GDK_gbreve && sym <= GDK_jcircumflex) + *upper -= (GDK_gbreve - GDK_Gbreve); + else if (sym >= GDK_Cabovedot && sym <= GDK_Scircumflex) + *lower += (GDK_cabovedot - GDK_Cabovedot); + else if (sym >= GDK_cabovedot && sym <= GDK_scircumflex) + *upper -= (GDK_cabovedot - GDK_Cabovedot); + break; +#endif /* LATIN3 */ + +#if defined (GDK_Rcedilla) && defined (GDK_Amacron) + case 3: /* Latin 4 */ + /* Assume the KeySym is a legal value (ignore discontinuities) */ + if (sym >= GDK_Rcedilla && sym <= GDK_Tslash) + *lower += (GDK_rcedilla - GDK_Rcedilla); + else if (sym >= GDK_rcedilla && sym <= GDK_tslash) + *upper -= (GDK_rcedilla - GDK_Rcedilla); + else if (sym == GDK_ENG) + *lower = GDK_eng; + else if (sym == GDK_eng) + *upper = GDK_ENG; + else if (sym >= GDK_Amacron && sym <= GDK_Umacron) + *lower += (GDK_amacron - GDK_Amacron); + else if (sym >= GDK_amacron && sym <= GDK_umacron) + *upper -= (GDK_amacron - GDK_Amacron); + break; +#endif /* LATIN4 */ + +#if defined (GDK_Serbian_DJE) && defined (GDK_Cyrillic_yu) + case 6: /* Cyrillic */ + /* Assume the KeySym is a legal value (ignore discontinuities) */ + if (sym >= GDK_Serbian_DJE && sym <= GDK_Serbian_DZE) + *lower -= (GDK_Serbian_DJE - GDK_Serbian_dje); + else if (sym >= GDK_Serbian_dje && sym <= GDK_Serbian_dze) + *upper += (GDK_Serbian_DJE - GDK_Serbian_dje); + else if (sym >= GDK_Cyrillic_YU && sym <= GDK_Cyrillic_HARDSIGN) + *lower -= (GDK_Cyrillic_YU - GDK_Cyrillic_yu); + else if (sym >= GDK_Cyrillic_yu && sym <= GDK_Cyrillic_hardsign) + *upper += (GDK_Cyrillic_YU - GDK_Cyrillic_yu); + break; +#endif /* CYRILLIC */ + +#if defined (GDK_Greek_ALPHAaccent) && defined (GDK_Greek_finalsmallsigma) + case 7: /* Greek */ + /* Assume the KeySym is a legal value (ignore discontinuities) */ + if (sym >= GDK_Greek_ALPHAaccent && sym <= GDK_Greek_OMEGAaccent) + *lower += (GDK_Greek_alphaaccent - GDK_Greek_ALPHAaccent); + else if (sym >= GDK_Greek_alphaaccent && sym <= GDK_Greek_omegaaccent && + sym != GDK_Greek_iotaaccentdieresis && + sym != GDK_Greek_upsilonaccentdieresis) + *upper -= (GDK_Greek_alphaaccent - GDK_Greek_ALPHAaccent); + else if (sym >= GDK_Greek_ALPHA && sym <= GDK_Greek_OMEGA) + *lower += (GDK_Greek_alpha - GDK_Greek_ALPHA); + else if (sym >= GDK_Greek_alpha && sym <= GDK_Greek_omega && + sym != GDK_Greek_finalsmallsigma) + *upper -= (GDK_Greek_alpha - GDK_Greek_ALPHA); + break; +#endif /* GREEK */ + } +} + +static struct gdk_key { + guint keyval; + const char *name; +} gdk_keys_by_keyval[] = { + { 0x000020, "space" }, + { 0x000021, "exclam" }, + { 0x000022, "quotedbl" }, + { 0x000023, "numbersign" }, + { 0x000024, "dollar" }, + { 0x000025, "percent" }, + { 0x000026, "ampersand" }, + { 0x000027, "apostrophe" }, + { 0x000027, "quoteright" }, + { 0x000028, "parenleft" }, + { 0x000029, "parenright" }, + { 0x00002a, "asterisk" }, + { 0x00002b, "plus" }, + { 0x00002c, "comma" }, + { 0x00002d, "minus" }, + { 0x00002e, "period" }, + { 0x00002f, "slash" }, + { 0x000030, "0" }, + { 0x000031, "1" }, + { 0x000032, "2" }, + { 0x000033, "3" }, + { 0x000034, "4" }, + { 0x000035, "5" }, + { 0x000036, "6" }, + { 0x000037, "7" }, + { 0x000038, "8" }, + { 0x000039, "9" }, + { 0x00003a, "colon" }, + { 0x00003b, "semicolon" }, + { 0x00003c, "less" }, + { 0x00003d, "equal" }, + { 0x00003e, "greater" }, + { 0x00003f, "question" }, + { 0x000040, "at" }, + { 0x000041, "A" }, + { 0x000042, "B" }, + { 0x000043, "C" }, + { 0x000044, "D" }, + { 0x000045, "E" }, + { 0x000046, "F" }, + { 0x000047, "G" }, + { 0x000048, "H" }, + { 0x000049, "I" }, + { 0x00004a, "J" }, + { 0x00004b, "K" }, + { 0x00004c, "L" }, + { 0x00004d, "M" }, + { 0x00004e, "N" }, + { 0x00004f, "O" }, + { 0x000050, "P" }, + { 0x000051, "Q" }, + { 0x000052, "R" }, + { 0x000053, "S" }, + { 0x000054, "T" }, + { 0x000055, "U" }, + { 0x000056, "V" }, + { 0x000057, "W" }, + { 0x000058, "X" }, + { 0x000059, "Y" }, + { 0x00005a, "Z" }, + { 0x00005b, "bracketleft" }, + { 0x00005c, "backslash" }, + { 0x00005d, "bracketright" }, + { 0x00005e, "asciicircum" }, + { 0x00005f, "underscore" }, + { 0x000060, "grave" }, + { 0x000060, "quoteleft" }, + { 0x000061, "a" }, + { 0x000062, "b" }, + { 0x000063, "c" }, + { 0x000064, "d" }, + { 0x000065, "e" }, + { 0x000066, "f" }, + { 0x000067, "g" }, + { 0x000068, "h" }, + { 0x000069, "i" }, + { 0x00006a, "j" }, + { 0x00006b, "k" }, + { 0x00006c, "l" }, + { 0x00006d, "m" }, + { 0x00006e, "n" }, + { 0x00006f, "o" }, + { 0x000070, "p" }, + { 0x000071, "q" }, + { 0x000072, "r" }, + { 0x000073, "s" }, + { 0x000074, "t" }, + { 0x000075, "u" }, + { 0x000076, "v" }, + { 0x000077, "w" }, + { 0x000078, "x" }, + { 0x000079, "y" }, + { 0x00007a, "z" }, + { 0x00007b, "braceleft" }, + { 0x00007c, "bar" }, + { 0x00007d, "braceright" }, + { 0x00007e, "asciitilde" }, + { 0x0000a0, "nobreakspace" }, + { 0x0000a1, "exclamdown" }, + { 0x0000a2, "cent" }, + { 0x0000a3, "sterling" }, + { 0x0000a4, "currency" }, + { 0x0000a5, "yen" }, + { 0x0000a6, "brokenbar" }, + { 0x0000a7, "section" }, + { 0x0000a8, "diaeresis" }, + { 0x0000a9, "copyright" }, + { 0x0000aa, "ordfeminine" }, + { 0x0000ab, "guillemotleft" }, + { 0x0000ac, "notsign" }, + { 0x0000ad, "hyphen" }, + { 0x0000ae, "registered" }, + { 0x0000af, "macron" }, + { 0x0000b0, "degree" }, + { 0x0000b1, "plusminus" }, + { 0x0000b2, "twosuperior" }, + { 0x0000b3, "threesuperior" }, + { 0x0000b4, "acute" }, + { 0x0000b5, "mu" }, + { 0x0000b6, "paragraph" }, + { 0x0000b7, "periodcentered" }, + { 0x0000b8, "cedilla" }, + { 0x0000b9, "onesuperior" }, + { 0x0000ba, "masculine" }, + { 0x0000bb, "guillemotright" }, + { 0x0000bc, "onequarter" }, + { 0x0000bd, "onehalf" }, + { 0x0000be, "threequarters" }, + { 0x0000bf, "questiondown" }, + { 0x0000c0, "Agrave" }, + { 0x0000c1, "Aacute" }, + { 0x0000c2, "Acircumflex" }, + { 0x0000c3, "Atilde" }, + { 0x0000c4, "Adiaeresis" }, + { 0x0000c5, "Aring" }, + { 0x0000c6, "AE" }, + { 0x0000c7, "Ccedilla" }, + { 0x0000c8, "Egrave" }, + { 0x0000c9, "Eacute" }, + { 0x0000ca, "Ecircumflex" }, + { 0x0000cb, "Ediaeresis" }, + { 0x0000cc, "Igrave" }, + { 0x0000cd, "Iacute" }, + { 0x0000ce, "Icircumflex" }, + { 0x0000cf, "Idiaeresis" }, + { 0x0000d0, "ETH" }, + { 0x0000d0, "Eth" }, + { 0x0000d1, "Ntilde" }, + { 0x0000d2, "Ograve" }, + { 0x0000d3, "Oacute" }, + { 0x0000d4, "Ocircumflex" }, + { 0x0000d5, "Otilde" }, + { 0x0000d6, "Odiaeresis" }, + { 0x0000d7, "multiply" }, + { 0x0000d8, "Ooblique" }, + { 0x0000d9, "Ugrave" }, + { 0x0000da, "Uacute" }, + { 0x0000db, "Ucircumflex" }, + { 0x0000dc, "Udiaeresis" }, + { 0x0000dd, "Yacute" }, + { 0x0000de, "THORN" }, + { 0x0000de, "Thorn" }, + { 0x0000df, "ssharp" }, + { 0x0000e0, "agrave" }, + { 0x0000e1, "aacute" }, + { 0x0000e2, "acircumflex" }, + { 0x0000e3, "atilde" }, + { 0x0000e4, "adiaeresis" }, + { 0x0000e5, "aring" }, + { 0x0000e6, "ae" }, + { 0x0000e7, "ccedilla" }, + { 0x0000e8, "egrave" }, + { 0x0000e9, "eacute" }, + { 0x0000ea, "ecircumflex" }, + { 0x0000eb, "ediaeresis" }, + { 0x0000ec, "igrave" }, + { 0x0000ed, "iacute" }, + { 0x0000ee, "icircumflex" }, + { 0x0000ef, "idiaeresis" }, + { 0x0000f0, "eth" }, + { 0x0000f1, "ntilde" }, + { 0x0000f2, "ograve" }, + { 0x0000f3, "oacute" }, + { 0x0000f4, "ocircumflex" }, + { 0x0000f5, "otilde" }, + { 0x0000f6, "odiaeresis" }, + { 0x0000f7, "division" }, + { 0x0000f8, "oslash" }, + { 0x0000f9, "ugrave" }, + { 0x0000fa, "uacute" }, + { 0x0000fb, "ucircumflex" }, + { 0x0000fc, "udiaeresis" }, + { 0x0000fd, "yacute" }, + { 0x0000fe, "thorn" }, + { 0x0000ff, "ydiaeresis" }, + { 0x0001a1, "Aogonek" }, + { 0x0001a2, "breve" }, + { 0x0001a3, "Lstroke" }, + { 0x0001a5, "Lcaron" }, + { 0x0001a6, "Sacute" }, + { 0x0001a9, "Scaron" }, + { 0x0001aa, "Scedilla" }, + { 0x0001ab, "Tcaron" }, + { 0x0001ac, "Zacute" }, + { 0x0001ae, "Zcaron" }, + { 0x0001af, "Zabovedot" }, + { 0x0001b1, "aogonek" }, + { 0x0001b2, "ogonek" }, + { 0x0001b3, "lstroke" }, + { 0x0001b5, "lcaron" }, + { 0x0001b6, "sacute" }, + { 0x0001b7, "caron" }, + { 0x0001b9, "scaron" }, + { 0x0001ba, "scedilla" }, + { 0x0001bb, "tcaron" }, + { 0x0001bc, "zacute" }, + { 0x0001bd, "doubleacute" }, + { 0x0001be, "zcaron" }, + { 0x0001bf, "zabovedot" }, + { 0x0001c0, "Racute" }, + { 0x0001c3, "Abreve" }, + { 0x0001c5, "Lacute" }, + { 0x0001c6, "Cacute" }, + { 0x0001c8, "Ccaron" }, + { 0x0001ca, "Eogonek" }, + { 0x0001cc, "Ecaron" }, + { 0x0001cf, "Dcaron" }, + { 0x0001d0, "Dstroke" }, + { 0x0001d1, "Nacute" }, + { 0x0001d2, "Ncaron" }, + { 0x0001d5, "Odoubleacute" }, + { 0x0001d8, "Rcaron" }, + { 0x0001d9, "Uring" }, + { 0x0001db, "Udoubleacute" }, + { 0x0001de, "Tcedilla" }, + { 0x0001e0, "racute" }, + { 0x0001e3, "abreve" }, + { 0x0001e5, "lacute" }, + { 0x0001e6, "cacute" }, + { 0x0001e8, "ccaron" }, + { 0x0001ea, "eogonek" }, + { 0x0001ec, "ecaron" }, + { 0x0001ef, "dcaron" }, + { 0x0001f0, "dstroke" }, + { 0x0001f1, "nacute" }, + { 0x0001f2, "ncaron" }, + { 0x0001f5, "odoubleacute" }, + { 0x0001f8, "rcaron" }, + { 0x0001f9, "uring" }, + { 0x0001fb, "udoubleacute" }, + { 0x0001fe, "tcedilla" }, + { 0x0001ff, "abovedot" }, + { 0x0002a1, "Hstroke" }, + { 0x0002a6, "Hcircumflex" }, + { 0x0002a9, "Iabovedot" }, + { 0x0002ab, "Gbreve" }, + { 0x0002ac, "Jcircumflex" }, + { 0x0002b1, "hstroke" }, + { 0x0002b6, "hcircumflex" }, + { 0x0002b9, "idotless" }, + { 0x0002bb, "gbreve" }, + { 0x0002bc, "jcircumflex" }, + { 0x0002c5, "Cabovedot" }, + { 0x0002c6, "Ccircumflex" }, + { 0x0002d5, "Gabovedot" }, + { 0x0002d8, "Gcircumflex" }, + { 0x0002dd, "Ubreve" }, + { 0x0002de, "Scircumflex" }, + { 0x0002e5, "cabovedot" }, + { 0x0002e6, "ccircumflex" }, + { 0x0002f5, "gabovedot" }, + { 0x0002f8, "gcircumflex" }, + { 0x0002fd, "ubreve" }, + { 0x0002fe, "scircumflex" }, + { 0x0003a2, "kappa" }, + { 0x0003a2, "kra" }, + { 0x0003a3, "Rcedilla" }, + { 0x0003a5, "Itilde" }, + { 0x0003a6, "Lcedilla" }, + { 0x0003aa, "Emacron" }, + { 0x0003ab, "Gcedilla" }, + { 0x0003ac, "Tslash" }, + { 0x0003b3, "rcedilla" }, + { 0x0003b5, "itilde" }, + { 0x0003b6, "lcedilla" }, + { 0x0003ba, "emacron" }, + { 0x0003bb, "gcedilla" }, + { 0x0003bc, "tslash" }, + { 0x0003bd, "ENG" }, + { 0x0003bf, "eng" }, + { 0x0003c0, "Amacron" }, + { 0x0003c7, "Iogonek" }, + { 0x0003cc, "Eabovedot" }, + { 0x0003cf, "Imacron" }, + { 0x0003d1, "Ncedilla" }, + { 0x0003d2, "Omacron" }, + { 0x0003d3, "Kcedilla" }, + { 0x0003d9, "Uogonek" }, + { 0x0003dd, "Utilde" }, + { 0x0003de, "Umacron" }, + { 0x0003e0, "amacron" }, + { 0x0003e7, "iogonek" }, + { 0x0003ec, "eabovedot" }, + { 0x0003ef, "imacron" }, + { 0x0003f1, "ncedilla" }, + { 0x0003f2, "omacron" }, + { 0x0003f3, "kcedilla" }, + { 0x0003f9, "uogonek" }, + { 0x0003fd, "utilde" }, + { 0x0003fe, "umacron" }, + { 0x00047e, "overline" }, + { 0x0004a1, "kana_fullstop" }, + { 0x0004a2, "kana_openingbracket" }, + { 0x0004a3, "kana_closingbracket" }, + { 0x0004a4, "kana_comma" }, + { 0x0004a5, "kana_conjunctive" }, + { 0x0004a5, "kana_middledot" }, + { 0x0004a6, "kana_WO" }, + { 0x0004a7, "kana_a" }, + { 0x0004a8, "kana_i" }, + { 0x0004a9, "kana_u" }, + { 0x0004aa, "kana_e" }, + { 0x0004ab, "kana_o" }, + { 0x0004ac, "kana_ya" }, + { 0x0004ad, "kana_yu" }, + { 0x0004ae, "kana_yo" }, + { 0x0004af, "kana_tsu" }, + { 0x0004af, "kana_tu" }, + { 0x0004b0, "prolongedsound" }, + { 0x0004b1, "kana_A" }, + { 0x0004b2, "kana_I" }, + { 0x0004b3, "kana_U" }, + { 0x0004b4, "kana_E" }, + { 0x0004b5, "kana_O" }, + { 0x0004b6, "kana_KA" }, + { 0x0004b7, "kana_KI" }, + { 0x0004b8, "kana_KU" }, + { 0x0004b9, "kana_KE" }, + { 0x0004ba, "kana_KO" }, + { 0x0004bb, "kana_SA" }, + { 0x0004bc, "kana_SHI" }, + { 0x0004bd, "kana_SU" }, + { 0x0004be, "kana_SE" }, + { 0x0004bf, "kana_SO" }, + { 0x0004c0, "kana_TA" }, + { 0x0004c1, "kana_CHI" }, + { 0x0004c1, "kana_TI" }, + { 0x0004c2, "kana_TSU" }, + { 0x0004c2, "kana_TU" }, + { 0x0004c3, "kana_TE" }, + { 0x0004c4, "kana_TO" }, + { 0x0004c5, "kana_NA" }, + { 0x0004c6, "kana_NI" }, + { 0x0004c7, "kana_NU" }, + { 0x0004c8, "kana_NE" }, + { 0x0004c9, "kana_NO" }, + { 0x0004ca, "kana_HA" }, + { 0x0004cb, "kana_HI" }, + { 0x0004cc, "kana_FU" }, + { 0x0004cc, "kana_HU" }, + { 0x0004cd, "kana_HE" }, + { 0x0004ce, "kana_HO" }, + { 0x0004cf, "kana_MA" }, + { 0x0004d0, "kana_MI" }, + { 0x0004d1, "kana_MU" }, + { 0x0004d2, "kana_ME" }, + { 0x0004d3, "kana_MO" }, + { 0x0004d4, "kana_YA" }, + { 0x0004d5, "kana_YU" }, + { 0x0004d6, "kana_YO" }, + { 0x0004d7, "kana_RA" }, + { 0x0004d8, "kana_RI" }, + { 0x0004d9, "kana_RU" }, + { 0x0004da, "kana_RE" }, + { 0x0004db, "kana_RO" }, + { 0x0004dc, "kana_WA" }, + { 0x0004dd, "kana_N" }, + { 0x0004de, "voicedsound" }, + { 0x0004df, "semivoicedsound" }, + { 0x0005ac, "Arabic_comma" }, + { 0x0005bb, "Arabic_semicolon" }, + { 0x0005bf, "Arabic_question_mark" }, + { 0x0005c1, "Arabic_hamza" }, + { 0x0005c2, "Arabic_maddaonalef" }, + { 0x0005c3, "Arabic_hamzaonalef" }, + { 0x0005c4, "Arabic_hamzaonwaw" }, + { 0x0005c5, "Arabic_hamzaunderalef" }, + { 0x0005c6, "Arabic_hamzaonyeh" }, + { 0x0005c7, "Arabic_alef" }, + { 0x0005c8, "Arabic_beh" }, + { 0x0005c9, "Arabic_tehmarbuta" }, + { 0x0005ca, "Arabic_teh" }, + { 0x0005cb, "Arabic_theh" }, + { 0x0005cc, "Arabic_jeem" }, + { 0x0005cd, "Arabic_hah" }, + { 0x0005ce, "Arabic_khah" }, + { 0x0005cf, "Arabic_dal" }, + { 0x0005d0, "Arabic_thal" }, + { 0x0005d1, "Arabic_ra" }, + { 0x0005d2, "Arabic_zain" }, + { 0x0005d3, "Arabic_seen" }, + { 0x0005d4, "Arabic_sheen" }, + { 0x0005d5, "Arabic_sad" }, + { 0x0005d6, "Arabic_dad" }, + { 0x0005d7, "Arabic_tah" }, + { 0x0005d8, "Arabic_zah" }, + { 0x0005d9, "Arabic_ain" }, + { 0x0005da, "Arabic_ghain" }, + { 0x0005e0, "Arabic_tatweel" }, + { 0x0005e1, "Arabic_feh" }, + { 0x0005e2, "Arabic_qaf" }, + { 0x0005e3, "Arabic_kaf" }, + { 0x0005e4, "Arabic_lam" }, + { 0x0005e5, "Arabic_meem" }, + { 0x0005e6, "Arabic_noon" }, + { 0x0005e7, "Arabic_ha" }, + { 0x0005e7, "Arabic_heh" }, + { 0x0005e8, "Arabic_waw" }, + { 0x0005e9, "Arabic_alefmaksura" }, + { 0x0005ea, "Arabic_yeh" }, + { 0x0005eb, "Arabic_fathatan" }, + { 0x0005ec, "Arabic_dammatan" }, + { 0x0005ed, "Arabic_kasratan" }, + { 0x0005ee, "Arabic_fatha" }, + { 0x0005ef, "Arabic_damma" }, + { 0x0005f0, "Arabic_kasra" }, + { 0x0005f1, "Arabic_shadda" }, + { 0x0005f2, "Arabic_sukun" }, + { 0x0006a1, "Serbian_dje" }, + { 0x0006a2, "Macedonia_gje" }, + { 0x0006a3, "Cyrillic_io" }, + { 0x0006a4, "Ukrainian_ie" }, + { 0x0006a4, "Ukranian_je" }, + { 0x0006a5, "Macedonia_dse" }, + { 0x0006a6, "Ukrainian_i" }, + { 0x0006a6, "Ukranian_i" }, + { 0x0006a7, "Ukrainian_yi" }, + { 0x0006a7, "Ukranian_yi" }, + { 0x0006a8, "Cyrillic_je" }, + { 0x0006a8, "Serbian_je" }, + { 0x0006a9, "Cyrillic_lje" }, + { 0x0006a9, "Serbian_lje" }, + { 0x0006aa, "Cyrillic_nje" }, + { 0x0006aa, "Serbian_nje" }, + { 0x0006ab, "Serbian_tshe" }, + { 0x0006ac, "Macedonia_kje" }, + { 0x0006ae, "Byelorussian_shortu" }, + { 0x0006af, "Cyrillic_dzhe" }, + { 0x0006af, "Serbian_dze" }, + { 0x0006b0, "numerosign" }, + { 0x0006b1, "Serbian_DJE" }, + { 0x0006b2, "Macedonia_GJE" }, + { 0x0006b3, "Cyrillic_IO" }, + { 0x0006b4, "Ukrainian_IE" }, + { 0x0006b4, "Ukranian_JE" }, + { 0x0006b5, "Macedonia_DSE" }, + { 0x0006b6, "Ukrainian_I" }, + { 0x0006b6, "Ukranian_I" }, + { 0x0006b7, "Ukrainian_YI" }, + { 0x0006b7, "Ukranian_YI" }, + { 0x0006b8, "Cyrillic_JE" }, + { 0x0006b8, "Serbian_JE" }, + { 0x0006b9, "Cyrillic_LJE" }, + { 0x0006b9, "Serbian_LJE" }, + { 0x0006ba, "Cyrillic_NJE" }, + { 0x0006ba, "Serbian_NJE" }, + { 0x0006bb, "Serbian_TSHE" }, + { 0x0006bc, "Macedonia_KJE" }, + { 0x0006be, "Byelorussian_SHORTU" }, + { 0x0006bf, "Cyrillic_DZHE" }, + { 0x0006bf, "Serbian_DZE" }, + { 0x0006c0, "Cyrillic_yu" }, + { 0x0006c1, "Cyrillic_a" }, + { 0x0006c2, "Cyrillic_be" }, + { 0x0006c3, "Cyrillic_tse" }, + { 0x0006c4, "Cyrillic_de" }, + { 0x0006c5, "Cyrillic_ie" }, + { 0x0006c6, "Cyrillic_ef" }, + { 0x0006c7, "Cyrillic_ghe" }, + { 0x0006c8, "Cyrillic_ha" }, + { 0x0006c9, "Cyrillic_i" }, + { 0x0006ca, "Cyrillic_shorti" }, + { 0x0006cb, "Cyrillic_ka" }, + { 0x0006cc, "Cyrillic_el" }, + { 0x0006cd, "Cyrillic_em" }, + { 0x0006ce, "Cyrillic_en" }, + { 0x0006cf, "Cyrillic_o" }, + { 0x0006d0, "Cyrillic_pe" }, + { 0x0006d1, "Cyrillic_ya" }, + { 0x0006d2, "Cyrillic_er" }, + { 0x0006d3, "Cyrillic_es" }, + { 0x0006d4, "Cyrillic_te" }, + { 0x0006d5, "Cyrillic_u" }, + { 0x0006d6, "Cyrillic_zhe" }, + { 0x0006d7, "Cyrillic_ve" }, + { 0x0006d8, "Cyrillic_softsign" }, + { 0x0006d9, "Cyrillic_yeru" }, + { 0x0006da, "Cyrillic_ze" }, + { 0x0006db, "Cyrillic_sha" }, + { 0x0006dc, "Cyrillic_e" }, + { 0x0006dd, "Cyrillic_shcha" }, + { 0x0006de, "Cyrillic_che" }, + { 0x0006df, "Cyrillic_hardsign" }, + { 0x0006e0, "Cyrillic_YU" }, + { 0x0006e1, "Cyrillic_A" }, + { 0x0006e2, "Cyrillic_BE" }, + { 0x0006e3, "Cyrillic_TSE" }, + { 0x0006e4, "Cyrillic_DE" }, + { 0x0006e5, "Cyrillic_IE" }, + { 0x0006e6, "Cyrillic_EF" }, + { 0x0006e7, "Cyrillic_GHE" }, + { 0x0006e8, "Cyrillic_HA" }, + { 0x0006e9, "Cyrillic_I" }, + { 0x0006ea, "Cyrillic_SHORTI" }, + { 0x0006eb, "Cyrillic_KA" }, + { 0x0006ec, "Cyrillic_EL" }, + { 0x0006ed, "Cyrillic_EM" }, + { 0x0006ee, "Cyrillic_EN" }, + { 0x0006ef, "Cyrillic_O" }, + { 0x0006f0, "Cyrillic_PE" }, + { 0x0006f1, "Cyrillic_YA" }, + { 0x0006f2, "Cyrillic_ER" }, + { 0x0006f3, "Cyrillic_ES" }, + { 0x0006f4, "Cyrillic_TE" }, + { 0x0006f5, "Cyrillic_U" }, + { 0x0006f6, "Cyrillic_ZHE" }, + { 0x0006f7, "Cyrillic_VE" }, + { 0x0006f8, "Cyrillic_SOFTSIGN" }, + { 0x0006f9, "Cyrillic_YERU" }, + { 0x0006fa, "Cyrillic_ZE" }, + { 0x0006fb, "Cyrillic_SHA" }, + { 0x0006fc, "Cyrillic_E" }, + { 0x0006fd, "Cyrillic_SHCHA" }, + { 0x0006fe, "Cyrillic_CHE" }, + { 0x0006ff, "Cyrillic_HARDSIGN" }, + { 0x0007a1, "Greek_ALPHAaccent" }, + { 0x0007a2, "Greek_EPSILONaccent" }, + { 0x0007a3, "Greek_ETAaccent" }, + { 0x0007a4, "Greek_IOTAaccent" }, + { 0x0007a5, "Greek_IOTAdiaeresis" }, + { 0x0007a7, "Greek_OMICRONaccent" }, + { 0x0007a8, "Greek_UPSILONaccent" }, + { 0x0007a9, "Greek_UPSILONdieresis" }, + { 0x0007ab, "Greek_OMEGAaccent" }, + { 0x0007ae, "Greek_accentdieresis" }, + { 0x0007af, "Greek_horizbar" }, + { 0x0007b1, "Greek_alphaaccent" }, + { 0x0007b2, "Greek_epsilonaccent" }, + { 0x0007b3, "Greek_etaaccent" }, + { 0x0007b4, "Greek_iotaaccent" }, + { 0x0007b5, "Greek_iotadieresis" }, + { 0x0007b6, "Greek_iotaaccentdieresis" }, + { 0x0007b7, "Greek_omicronaccent" }, + { 0x0007b8, "Greek_upsilonaccent" }, + { 0x0007b9, "Greek_upsilondieresis" }, + { 0x0007ba, "Greek_upsilonaccentdieresis" }, + { 0x0007bb, "Greek_omegaaccent" }, + { 0x0007c1, "Greek_ALPHA" }, + { 0x0007c2, "Greek_BETA" }, + { 0x0007c3, "Greek_GAMMA" }, + { 0x0007c4, "Greek_DELTA" }, + { 0x0007c5, "Greek_EPSILON" }, + { 0x0007c6, "Greek_ZETA" }, + { 0x0007c7, "Greek_ETA" }, + { 0x0007c8, "Greek_THETA" }, + { 0x0007c9, "Greek_IOTA" }, + { 0x0007ca, "Greek_KAPPA" }, + { 0x0007cb, "Greek_LAMBDA" }, + { 0x0007cb, "Greek_LAMDA" }, + { 0x0007cc, "Greek_MU" }, + { 0x0007cd, "Greek_NU" }, + { 0x0007ce, "Greek_XI" }, + { 0x0007cf, "Greek_OMICRON" }, + { 0x0007d0, "Greek_PI" }, + { 0x0007d1, "Greek_RHO" }, + { 0x0007d2, "Greek_SIGMA" }, + { 0x0007d4, "Greek_TAU" }, + { 0x0007d5, "Greek_UPSILON" }, + { 0x0007d6, "Greek_PHI" }, + { 0x0007d7, "Greek_CHI" }, + { 0x0007d8, "Greek_PSI" }, + { 0x0007d9, "Greek_OMEGA" }, + { 0x0007e1, "Greek_alpha" }, + { 0x0007e2, "Greek_beta" }, + { 0x0007e3, "Greek_gamma" }, + { 0x0007e4, "Greek_delta" }, + { 0x0007e5, "Greek_epsilon" }, + { 0x0007e6, "Greek_zeta" }, + { 0x0007e7, "Greek_eta" }, + { 0x0007e8, "Greek_theta" }, + { 0x0007e9, "Greek_iota" }, + { 0x0007ea, "Greek_kappa" }, + { 0x0007eb, "Greek_lambda" }, + { 0x0007eb, "Greek_lamda" }, + { 0x0007ec, "Greek_mu" }, + { 0x0007ed, "Greek_nu" }, + { 0x0007ee, "Greek_xi" }, + { 0x0007ef, "Greek_omicron" }, + { 0x0007f0, "Greek_pi" }, + { 0x0007f1, "Greek_rho" }, + { 0x0007f2, "Greek_sigma" }, + { 0x0007f3, "Greek_finalsmallsigma" }, + { 0x0007f4, "Greek_tau" }, + { 0x0007f5, "Greek_upsilon" }, + { 0x0007f6, "Greek_phi" }, + { 0x0007f7, "Greek_chi" }, + { 0x0007f8, "Greek_psi" }, + { 0x0007f9, "Greek_omega" }, + { 0x0008a1, "leftradical" }, + { 0x0008a2, "topleftradical" }, + { 0x0008a3, "horizconnector" }, + { 0x0008a4, "topintegral" }, + { 0x0008a5, "botintegral" }, + { 0x0008a6, "vertconnector" }, + { 0x0008a7, "topleftsqbracket" }, + { 0x0008a8, "botleftsqbracket" }, + { 0x0008a9, "toprightsqbracket" }, + { 0x0008aa, "botrightsqbracket" }, + { 0x0008ab, "topleftparens" }, + { 0x0008ac, "botleftparens" }, + { 0x0008ad, "toprightparens" }, + { 0x0008ae, "botrightparens" }, + { 0x0008af, "leftmiddlecurlybrace" }, + { 0x0008b0, "rightmiddlecurlybrace" }, + { 0x0008b1, "topleftsummation" }, + { 0x0008b2, "botleftsummation" }, + { 0x0008b3, "topvertsummationconnector" }, + { 0x0008b4, "botvertsummationconnector" }, + { 0x0008b5, "toprightsummation" }, + { 0x0008b6, "botrightsummation" }, + { 0x0008b7, "rightmiddlesummation" }, + { 0x0008bc, "lessthanequal" }, + { 0x0008bd, "notequal" }, + { 0x0008be, "greaterthanequal" }, + { 0x0008bf, "integral" }, + { 0x0008c0, "therefore" }, + { 0x0008c1, "variation" }, + { 0x0008c2, "infinity" }, + { 0x0008c5, "nabla" }, + { 0x0008c8, "approximate" }, + { 0x0008c9, "similarequal" }, + { 0x0008cd, "ifonlyif" }, + { 0x0008ce, "implies" }, + { 0x0008cf, "identical" }, + { 0x0008d6, "radical" }, + { 0x0008da, "includedin" }, + { 0x0008db, "includes" }, + { 0x0008dc, "intersection" }, + { 0x0008dd, "union" }, + { 0x0008de, "logicaland" }, + { 0x0008df, "logicalor" }, + { 0x0008ef, "partialderivative" }, + { 0x0008f6, "function" }, + { 0x0008fb, "leftarrow" }, + { 0x0008fc, "uparrow" }, + { 0x0008fd, "rightarrow" }, + { 0x0008fe, "downarrow" }, + { 0x0009df, "blank" }, + { 0x0009e0, "soliddiamond" }, + { 0x0009e1, "checkerboard" }, + { 0x0009e2, "ht" }, + { 0x0009e3, "ff" }, + { 0x0009e4, "cr" }, + { 0x0009e5, "lf" }, + { 0x0009e8, "nl" }, + { 0x0009e9, "vt" }, + { 0x0009ea, "lowrightcorner" }, + { 0x0009eb, "uprightcorner" }, + { 0x0009ec, "upleftcorner" }, + { 0x0009ed, "lowleftcorner" }, + { 0x0009ee, "crossinglines" }, + { 0x0009ef, "horizlinescan1" }, + { 0x0009f0, "horizlinescan3" }, + { 0x0009f1, "horizlinescan5" }, + { 0x0009f2, "horizlinescan7" }, + { 0x0009f3, "horizlinescan9" }, + { 0x0009f4, "leftt" }, + { 0x0009f5, "rightt" }, + { 0x0009f6, "bott" }, + { 0x0009f7, "topt" }, + { 0x0009f8, "vertbar" }, + { 0x000aa1, "emspace" }, + { 0x000aa2, "enspace" }, + { 0x000aa3, "em3space" }, + { 0x000aa4, "em4space" }, + { 0x000aa5, "digitspace" }, + { 0x000aa6, "punctspace" }, + { 0x000aa7, "thinspace" }, + { 0x000aa8, "hairspace" }, + { 0x000aa9, "emdash" }, + { 0x000aaa, "endash" }, + { 0x000aac, "signifblank" }, + { 0x000aae, "ellipsis" }, + { 0x000aaf, "doubbaselinedot" }, + { 0x000ab0, "onethird" }, + { 0x000ab1, "twothirds" }, + { 0x000ab2, "onefifth" }, + { 0x000ab3, "twofifths" }, + { 0x000ab4, "threefifths" }, + { 0x000ab5, "fourfifths" }, + { 0x000ab6, "onesixth" }, + { 0x000ab7, "fivesixths" }, + { 0x000ab8, "careof" }, + { 0x000abb, "figdash" }, + { 0x000abc, "leftanglebracket" }, + { 0x000abd, "decimalpoint" }, + { 0x000abe, "rightanglebracket" }, + { 0x000abf, "marker" }, + { 0x000ac3, "oneeighth" }, + { 0x000ac4, "threeeighths" }, + { 0x000ac5, "fiveeighths" }, + { 0x000ac6, "seveneighths" }, + { 0x000ac9, "trademark" }, + { 0x000aca, "signaturemark" }, + { 0x000acb, "trademarkincircle" }, + { 0x000acc, "leftopentriangle" }, + { 0x000acd, "rightopentriangle" }, + { 0x000ace, "emopencircle" }, + { 0x000acf, "emopenrectangle" }, + { 0x000ad0, "leftsinglequotemark" }, + { 0x000ad1, "rightsinglequotemark" }, + { 0x000ad2, "leftdoublequotemark" }, + { 0x000ad3, "rightdoublequotemark" }, + { 0x000ad4, "prescription" }, + { 0x000ad6, "minutes" }, + { 0x000ad7, "seconds" }, + { 0x000ad9, "latincross" }, + { 0x000ada, "hexagram" }, + { 0x000adb, "filledrectbullet" }, + { 0x000adc, "filledlefttribullet" }, + { 0x000add, "filledrighttribullet" }, + { 0x000ade, "emfilledcircle" }, + { 0x000adf, "emfilledrect" }, + { 0x000ae0, "enopencircbullet" }, + { 0x000ae1, "enopensquarebullet" }, + { 0x000ae2, "openrectbullet" }, + { 0x000ae3, "opentribulletup" }, + { 0x000ae4, "opentribulletdown" }, + { 0x000ae5, "openstar" }, + { 0x000ae6, "enfilledcircbullet" }, + { 0x000ae7, "enfilledsqbullet" }, + { 0x000ae8, "filledtribulletup" }, + { 0x000ae9, "filledtribulletdown" }, + { 0x000aea, "leftpointer" }, + { 0x000aeb, "rightpointer" }, + { 0x000aec, "club" }, + { 0x000aed, "diamond" }, + { 0x000aee, "heart" }, + { 0x000af0, "maltesecross" }, + { 0x000af1, "dagger" }, + { 0x000af2, "doubledagger" }, + { 0x000af3, "checkmark" }, + { 0x000af4, "ballotcross" }, + { 0x000af5, "musicalsharp" }, + { 0x000af6, "musicalflat" }, + { 0x000af7, "malesymbol" }, + { 0x000af8, "femalesymbol" }, + { 0x000af9, "telephone" }, + { 0x000afa, "telephonerecorder" }, + { 0x000afb, "phonographcopyright" }, + { 0x000afc, "caret" }, + { 0x000afd, "singlelowquotemark" }, + { 0x000afe, "doublelowquotemark" }, + { 0x000aff, "cursor" }, + { 0x000ba3, "leftcaret" }, + { 0x000ba6, "rightcaret" }, + { 0x000ba8, "downcaret" }, + { 0x000ba9, "upcaret" }, + { 0x000bc0, "overbar" }, + { 0x000bc2, "downtack" }, + { 0x000bc3, "upshoe" }, + { 0x000bc4, "downstile" }, + { 0x000bc6, "underbar" }, + { 0x000bca, "jot" }, + { 0x000bcc, "quad" }, + { 0x000bce, "uptack" }, + { 0x000bcf, "circle" }, + { 0x000bd3, "upstile" }, + { 0x000bd6, "downshoe" }, + { 0x000bd8, "rightshoe" }, + { 0x000bda, "leftshoe" }, + { 0x000bdc, "lefttack" }, + { 0x000bfc, "righttack" }, + { 0x000cdf, "hebrew_doublelowline" }, + { 0x000ce0, "hebrew_aleph" }, + { 0x000ce1, "hebrew_bet" }, + { 0x000ce1, "hebrew_beth" }, + { 0x000ce2, "hebrew_gimel" }, + { 0x000ce2, "hebrew_gimmel" }, + { 0x000ce3, "hebrew_dalet" }, + { 0x000ce3, "hebrew_daleth" }, + { 0x000ce4, "hebrew_he" }, + { 0x000ce5, "hebrew_waw" }, + { 0x000ce6, "hebrew_zain" }, + { 0x000ce6, "hebrew_zayin" }, + { 0x000ce7, "hebrew_chet" }, + { 0x000ce7, "hebrew_het" }, + { 0x000ce8, "hebrew_tet" }, + { 0x000ce8, "hebrew_teth" }, + { 0x000ce9, "hebrew_yod" }, + { 0x000cea, "hebrew_finalkaph" }, + { 0x000ceb, "hebrew_kaph" }, + { 0x000cec, "hebrew_lamed" }, + { 0x000ced, "hebrew_finalmem" }, + { 0x000cee, "hebrew_mem" }, + { 0x000cef, "hebrew_finalnun" }, + { 0x000cf0, "hebrew_nun" }, + { 0x000cf1, "hebrew_samech" }, + { 0x000cf1, "hebrew_samekh" }, + { 0x000cf2, "hebrew_ayin" }, + { 0x000cf3, "hebrew_finalpe" }, + { 0x000cf4, "hebrew_pe" }, + { 0x000cf5, "hebrew_finalzade" }, + { 0x000cf5, "hebrew_finalzadi" }, + { 0x000cf6, "hebrew_zade" }, + { 0x000cf6, "hebrew_zadi" }, + { 0x000cf7, "hebrew_kuf" }, + { 0x000cf7, "hebrew_qoph" }, + { 0x000cf8, "hebrew_resh" }, + { 0x000cf9, "hebrew_shin" }, + { 0x000cfa, "hebrew_taf" }, + { 0x000cfa, "hebrew_taw" }, + { 0x000da1, "Thai_kokai" }, + { 0x000da2, "Thai_khokhai" }, + { 0x000da3, "Thai_khokhuat" }, + { 0x000da4, "Thai_khokhwai" }, + { 0x000da5, "Thai_khokhon" }, + { 0x000da6, "Thai_khorakhang" }, + { 0x000da7, "Thai_ngongu" }, + { 0x000da8, "Thai_chochan" }, + { 0x000da9, "Thai_choching" }, + { 0x000daa, "Thai_chochang" }, + { 0x000dab, "Thai_soso" }, + { 0x000dac, "Thai_chochoe" }, + { 0x000dad, "Thai_yoying" }, + { 0x000dae, "Thai_dochada" }, + { 0x000daf, "Thai_topatak" }, + { 0x000db0, "Thai_thothan" }, + { 0x000db1, "Thai_thonangmontho" }, + { 0x000db2, "Thai_thophuthao" }, + { 0x000db3, "Thai_nonen" }, + { 0x000db4, "Thai_dodek" }, + { 0x000db5, "Thai_totao" }, + { 0x000db6, "Thai_thothung" }, + { 0x000db7, "Thai_thothahan" }, + { 0x000db8, "Thai_thothong" }, + { 0x000db9, "Thai_nonu" }, + { 0x000dba, "Thai_bobaimai" }, + { 0x000dbb, "Thai_popla" }, + { 0x000dbc, "Thai_phophung" }, + { 0x000dbd, "Thai_fofa" }, + { 0x000dbe, "Thai_phophan" }, + { 0x000dbf, "Thai_fofan" }, + { 0x000dc0, "Thai_phosamphao" }, + { 0x000dc1, "Thai_moma" }, + { 0x000dc2, "Thai_yoyak" }, + { 0x000dc3, "Thai_rorua" }, + { 0x000dc4, "Thai_ru" }, + { 0x000dc5, "Thai_loling" }, + { 0x000dc6, "Thai_lu" }, + { 0x000dc7, "Thai_wowaen" }, + { 0x000dc8, "Thai_sosala" }, + { 0x000dc9, "Thai_sorusi" }, + { 0x000dca, "Thai_sosua" }, + { 0x000dcb, "Thai_hohip" }, + { 0x000dcc, "Thai_lochula" }, + { 0x000dcd, "Thai_oang" }, + { 0x000dce, "Thai_honokhuk" }, + { 0x000dcf, "Thai_paiyannoi" }, + { 0x000dd0, "Thai_saraa" }, + { 0x000dd1, "Thai_maihanakat" }, + { 0x000dd2, "Thai_saraaa" }, + { 0x000dd3, "Thai_saraam" }, + { 0x000dd4, "Thai_sarai" }, + { 0x000dd5, "Thai_saraii" }, + { 0x000dd6, "Thai_saraue" }, + { 0x000dd7, "Thai_sarauee" }, + { 0x000dd8, "Thai_sarau" }, + { 0x000dd9, "Thai_sarauu" }, + { 0x000dda, "Thai_phinthu" }, + { 0x000dde, "Thai_maihanakat_maitho" }, + { 0x000ddf, "Thai_baht" }, + { 0x000de0, "Thai_sarae" }, + { 0x000de1, "Thai_saraae" }, + { 0x000de2, "Thai_sarao" }, + { 0x000de3, "Thai_saraaimaimuan" }, + { 0x000de4, "Thai_saraaimaimalai" }, + { 0x000de5, "Thai_lakkhangyao" }, + { 0x000de6, "Thai_maiyamok" }, + { 0x000de7, "Thai_maitaikhu" }, + { 0x000de8, "Thai_maiek" }, + { 0x000de9, "Thai_maitho" }, + { 0x000dea, "Thai_maitri" }, + { 0x000deb, "Thai_maichattawa" }, + { 0x000dec, "Thai_thanthakhat" }, + { 0x000ded, "Thai_nikhahit" }, + { 0x000df0, "Thai_leksun" }, + { 0x000df1, "Thai_leknung" }, + { 0x000df2, "Thai_leksong" }, + { 0x000df3, "Thai_leksam" }, + { 0x000df4, "Thai_leksi" }, + { 0x000df5, "Thai_lekha" }, + { 0x000df6, "Thai_lekhok" }, + { 0x000df7, "Thai_lekchet" }, + { 0x000df8, "Thai_lekpaet" }, + { 0x000df9, "Thai_lekkao" }, + { 0x000ea1, "Hangul_Kiyeog" }, + { 0x000ea2, "Hangul_SsangKiyeog" }, + { 0x000ea3, "Hangul_KiyeogSios" }, + { 0x000ea4, "Hangul_Nieun" }, + { 0x000ea5, "Hangul_NieunJieuj" }, + { 0x000ea6, "Hangul_NieunHieuh" }, + { 0x000ea7, "Hangul_Dikeud" }, + { 0x000ea8, "Hangul_SsangDikeud" }, + { 0x000ea9, "Hangul_Rieul" }, + { 0x000eaa, "Hangul_RieulKiyeog" }, + { 0x000eab, "Hangul_RieulMieum" }, + { 0x000eac, "Hangul_RieulPieub" }, + { 0x000ead, "Hangul_RieulSios" }, + { 0x000eae, "Hangul_RieulTieut" }, + { 0x000eaf, "Hangul_RieulPhieuf" }, + { 0x000eb0, "Hangul_RieulHieuh" }, + { 0x000eb1, "Hangul_Mieum" }, + { 0x000eb2, "Hangul_Pieub" }, + { 0x000eb3, "Hangul_SsangPieub" }, + { 0x000eb4, "Hangul_PieubSios" }, + { 0x000eb5, "Hangul_Sios" }, + { 0x000eb6, "Hangul_SsangSios" }, + { 0x000eb7, "Hangul_Ieung" }, + { 0x000eb8, "Hangul_Jieuj" }, + { 0x000eb9, "Hangul_SsangJieuj" }, + { 0x000eba, "Hangul_Cieuc" }, + { 0x000ebb, "Hangul_Khieuq" }, + { 0x000ebc, "Hangul_Tieut" }, + { 0x000ebd, "Hangul_Phieuf" }, + { 0x000ebe, "Hangul_Hieuh" }, + { 0x000ebf, "Hangul_A" }, + { 0x000ec0, "Hangul_AE" }, + { 0x000ec1, "Hangul_YA" }, + { 0x000ec2, "Hangul_YAE" }, + { 0x000ec3, "Hangul_EO" }, + { 0x000ec4, "Hangul_E" }, + { 0x000ec5, "Hangul_YEO" }, + { 0x000ec6, "Hangul_YE" }, + { 0x000ec7, "Hangul_O" }, + { 0x000ec8, "Hangul_WA" }, + { 0x000ec9, "Hangul_WAE" }, + { 0x000eca, "Hangul_OE" }, + { 0x000ecb, "Hangul_YO" }, + { 0x000ecc, "Hangul_U" }, + { 0x000ecd, "Hangul_WEO" }, + { 0x000ece, "Hangul_WE" }, + { 0x000ecf, "Hangul_WI" }, + { 0x000ed0, "Hangul_YU" }, + { 0x000ed1, "Hangul_EU" }, + { 0x000ed2, "Hangul_YI" }, + { 0x000ed3, "Hangul_I" }, + { 0x000ed4, "Hangul_J_Kiyeog" }, + { 0x000ed5, "Hangul_J_SsangKiyeog" }, + { 0x000ed6, "Hangul_J_KiyeogSios" }, + { 0x000ed7, "Hangul_J_Nieun" }, + { 0x000ed8, "Hangul_J_NieunJieuj" }, + { 0x000ed9, "Hangul_J_NieunHieuh" }, + { 0x000eda, "Hangul_J_Dikeud" }, + { 0x000edb, "Hangul_J_Rieul" }, + { 0x000edc, "Hangul_J_RieulKiyeog" }, + { 0x000edd, "Hangul_J_RieulMieum" }, + { 0x000ede, "Hangul_J_RieulPieub" }, + { 0x000edf, "Hangul_J_RieulSios" }, + { 0x000ee0, "Hangul_J_RieulTieut" }, + { 0x000ee1, "Hangul_J_RieulPhieuf" }, + { 0x000ee2, "Hangul_J_RieulHieuh" }, + { 0x000ee3, "Hangul_J_Mieum" }, + { 0x000ee4, "Hangul_J_Pieub" }, + { 0x000ee5, "Hangul_J_PieubSios" }, + { 0x000ee6, "Hangul_J_Sios" }, + { 0x000ee7, "Hangul_J_SsangSios" }, + { 0x000ee8, "Hangul_J_Ieung" }, + { 0x000ee9, "Hangul_J_Jieuj" }, + { 0x000eea, "Hangul_J_Cieuc" }, + { 0x000eeb, "Hangul_J_Khieuq" }, + { 0x000eec, "Hangul_J_Tieut" }, + { 0x000eed, "Hangul_J_Phieuf" }, + { 0x000eee, "Hangul_J_Hieuh" }, + { 0x000eef, "Hangul_RieulYeorinHieuh" }, + { 0x000ef0, "Hangul_SunkyeongeumMieum" }, + { 0x000ef1, "Hangul_SunkyeongeumPieub" }, + { 0x000ef2, "Hangul_PanSios" }, + { 0x000ef3, "Hangul_KkogjiDalrinIeung" }, + { 0x000ef4, "Hangul_SunkyeongeumPhieuf" }, + { 0x000ef5, "Hangul_YeorinHieuh" }, + { 0x000ef6, "Hangul_AraeA" }, + { 0x000ef7, "Hangul_AraeAE" }, + { 0x000ef8, "Hangul_J_PanSios" }, + { 0x000ef9, "Hangul_J_KkogjiDalrinIeung" }, + { 0x000efa, "Hangul_J_YeorinHieuh" }, + { 0x000eff, "Korean_Won" }, + { 0x0013bc, "OE" }, + { 0x0013bd, "oe" }, + { 0x0013be, "Ydiaeresis" }, + { 0x0020a0, "EcuSign" }, + { 0x0020a1, "ColonSign" }, + { 0x0020a2, "CruzeiroSign" }, + { 0x0020a3, "FFrancSign" }, + { 0x0020a4, "LiraSign" }, + { 0x0020a5, "MillSign" }, + { 0x0020a6, "NairaSign" }, + { 0x0020a7, "PesetaSign" }, + { 0x0020a8, "RupeeSign" }, + { 0x0020a9, "WonSign" }, + { 0x0020aa, "NewSheqelSign" }, + { 0x0020ab, "DongSign" }, + { 0x0020ac, "EuroSign" }, + { 0x00fd01, "3270_Duplicate" }, + { 0x00fd02, "3270_FieldMark" }, + { 0x00fd03, "3270_Right2" }, + { 0x00fd04, "3270_Left2" }, + { 0x00fd05, "3270_BackTab" }, + { 0x00fd06, "3270_EraseEOF" }, + { 0x00fd07, "3270_EraseInput" }, + { 0x00fd08, "3270_Reset" }, + { 0x00fd09, "3270_Quit" }, + { 0x00fd0a, "3270_PA1" }, + { 0x00fd0b, "3270_PA2" }, + { 0x00fd0c, "3270_PA3" }, + { 0x00fd0d, "3270_Test" }, + { 0x00fd0e, "3270_Attn" }, + { 0x00fd0f, "3270_CursorBlink" }, + { 0x00fd10, "3270_AltCursor" }, + { 0x00fd11, "3270_KeyClick" }, + { 0x00fd12, "3270_Jump" }, + { 0x00fd13, "3270_Ident" }, + { 0x00fd14, "3270_Rule" }, + { 0x00fd15, "3270_Copy" }, + { 0x00fd16, "3270_Play" }, + { 0x00fd17, "3270_Setup" }, + { 0x00fd18, "3270_Record" }, + { 0x00fd19, "3270_ChangeScreen" }, + { 0x00fd1a, "3270_DeleteWord" }, + { 0x00fd1b, "3270_ExSelect" }, + { 0x00fd1c, "3270_CursorSelect" }, + { 0x00fd1d, "3270_PrintScreen" }, + { 0x00fd1e, "3270_Enter" }, + { 0x00fe01, "ISO_Lock" }, + { 0x00fe02, "ISO_Level2_Latch" }, + { 0x00fe03, "ISO_Level3_Shift" }, + { 0x00fe04, "ISO_Level3_Latch" }, + { 0x00fe05, "ISO_Level3_Lock" }, + { 0x00fe06, "ISO_Group_Latch" }, + { 0x00fe07, "ISO_Group_Lock" }, + { 0x00fe08, "ISO_Next_Group" }, + { 0x00fe09, "ISO_Next_Group_Lock" }, + { 0x00fe0a, "ISO_Prev_Group" }, + { 0x00fe0b, "ISO_Prev_Group_Lock" }, + { 0x00fe0c, "ISO_First_Group" }, + { 0x00fe0d, "ISO_First_Group_Lock" }, + { 0x00fe0e, "ISO_Last_Group" }, + { 0x00fe0f, "ISO_Last_Group_Lock" }, + { 0x00fe20, "ISO_Left_Tab" }, + { 0x00fe21, "ISO_Move_Line_Up" }, + { 0x00fe22, "ISO_Move_Line_Down" }, + { 0x00fe23, "ISO_Partial_Line_Up" }, + { 0x00fe24, "ISO_Partial_Line_Down" }, + { 0x00fe25, "ISO_Partial_Space_Left" }, + { 0x00fe26, "ISO_Partial_Space_Right" }, + { 0x00fe27, "ISO_Set_Margin_Left" }, + { 0x00fe28, "ISO_Set_Margin_Right" }, + { 0x00fe29, "ISO_Release_Margin_Left" }, + { 0x00fe2a, "ISO_Release_Margin_Right" }, + { 0x00fe2b, "ISO_Release_Both_Margins" }, + { 0x00fe2c, "ISO_Fast_Cursor_Left" }, + { 0x00fe2d, "ISO_Fast_Cursor_Right" }, + { 0x00fe2e, "ISO_Fast_Cursor_Up" }, + { 0x00fe2f, "ISO_Fast_Cursor_Down" }, + { 0x00fe30, "ISO_Continuous_Underline" }, + { 0x00fe31, "ISO_Discontinuous_Underline" }, + { 0x00fe32, "ISO_Emphasize" }, + { 0x00fe33, "ISO_Center_Object" }, + { 0x00fe34, "ISO_Enter" }, + { 0x00fe50, "dead_grave" }, + { 0x00fe51, "dead_acute" }, + { 0x00fe52, "dead_circumflex" }, + { 0x00fe53, "dead_tilde" }, + { 0x00fe54, "dead_macron" }, + { 0x00fe55, "dead_breve" }, + { 0x00fe56, "dead_abovedot" }, + { 0x00fe57, "dead_diaeresis" }, + { 0x00fe58, "dead_abovering" }, + { 0x00fe59, "dead_doubleacute" }, + { 0x00fe5a, "dead_caron" }, + { 0x00fe5b, "dead_cedilla" }, + { 0x00fe5c, "dead_ogonek" }, + { 0x00fe5d, "dead_iota" }, + { 0x00fe5e, "dead_voiced_sound" }, + { 0x00fe5f, "dead_semivoiced_sound" }, + { 0x00fe60, "dead_belowdot" }, + { 0x00fe70, "AccessX_Enable" }, + { 0x00fe71, "AccessX_Feedback_Enable" }, + { 0x00fe72, "RepeatKeys_Enable" }, + { 0x00fe73, "SlowKeys_Enable" }, + { 0x00fe74, "BounceKeys_Enable" }, + { 0x00fe75, "StickyKeys_Enable" }, + { 0x00fe76, "MouseKeys_Enable" }, + { 0x00fe77, "MouseKeys_Accel_Enable" }, + { 0x00fe78, "Overlay1_Enable" }, + { 0x00fe79, "Overlay2_Enable" }, + { 0x00fe7a, "AudibleBell_Enable" }, + { 0x00fed0, "First_Virtual_Screen" }, + { 0x00fed1, "Prev_Virtual_Screen" }, + { 0x00fed2, "Next_Virtual_Screen" }, + { 0x00fed4, "Last_Virtual_Screen" }, + { 0x00fed5, "Terminate_Server" }, + { 0x00fee0, "Pointer_Left" }, + { 0x00fee1, "Pointer_Right" }, + { 0x00fee2, "Pointer_Up" }, + { 0x00fee3, "Pointer_Down" }, + { 0x00fee4, "Pointer_UpLeft" }, + { 0x00fee5, "Pointer_UpRight" }, + { 0x00fee6, "Pointer_DownLeft" }, + { 0x00fee7, "Pointer_DownRight" }, + { 0x00fee8, "Pointer_Button_Dflt" }, + { 0x00fee9, "Pointer_Button1" }, + { 0x00feea, "Pointer_Button2" }, + { 0x00feeb, "Pointer_Button3" }, + { 0x00feec, "Pointer_Button4" }, + { 0x00feed, "Pointer_Button5" }, + { 0x00feee, "Pointer_DblClick_Dflt" }, + { 0x00feef, "Pointer_DblClick1" }, + { 0x00fef0, "Pointer_DblClick2" }, + { 0x00fef1, "Pointer_DblClick3" }, + { 0x00fef2, "Pointer_DblClick4" }, + { 0x00fef3, "Pointer_DblClick5" }, + { 0x00fef4, "Pointer_Drag_Dflt" }, + { 0x00fef5, "Pointer_Drag1" }, + { 0x00fef6, "Pointer_Drag2" }, + { 0x00fef7, "Pointer_Drag3" }, + { 0x00fef8, "Pointer_Drag4" }, + { 0x00fef9, "Pointer_EnableKeys" }, + { 0x00fefa, "Pointer_Accelerate" }, + { 0x00fefb, "Pointer_DfltBtnNext" }, + { 0x00fefc, "Pointer_DfltBtnPrev" }, + { 0x00fefd, "Pointer_Drag5" }, + { 0x00ff08, "BackSpace" }, + { 0x00ff09, "Tab" }, + { 0x00ff0a, "Linefeed" }, + { 0x00ff0b, "Clear" }, + { 0x00ff0d, "Return" }, + { 0x00ff13, "Pause" }, + { 0x00ff14, "Scroll_Lock" }, + { 0x00ff15, "Sys_Req" }, + { 0x00ff1b, "Escape" }, + { 0x00ff20, "Multi_key" }, + { 0x00ff21, "Kanji" }, + { 0x00ff22, "Muhenkan" }, + { 0x00ff23, "Henkan" }, + { 0x00ff23, "Henkan_Mode" }, + { 0x00ff24, "Romaji" }, + { 0x00ff25, "Hiragana" }, + { 0x00ff26, "Katakana" }, + { 0x00ff27, "Hiragana_Katakana" }, + { 0x00ff28, "Zenkaku" }, + { 0x00ff29, "Hankaku" }, + { 0x00ff2a, "Zenkaku_Hankaku" }, + { 0x00ff2b, "Touroku" }, + { 0x00ff2c, "Massyo" }, + { 0x00ff2d, "Kana_Lock" }, + { 0x00ff2e, "Kana_Shift" }, + { 0x00ff2f, "Eisu_Shift" }, + { 0x00ff30, "Eisu_toggle" }, + { 0x00ff31, "Hangul" }, + { 0x00ff32, "Hangul_Start" }, + { 0x00ff33, "Hangul_End" }, + { 0x00ff34, "Hangul_Hanja" }, + { 0x00ff35, "Hangul_Jamo" }, + { 0x00ff36, "Hangul_Romaja" }, + { 0x00ff37, "Codeinput" }, + { 0x00ff38, "Hangul_Jeonja" }, + { 0x00ff39, "Hangul_Banja" }, + { 0x00ff3a, "Hangul_PreHanja" }, + { 0x00ff3b, "Hangul_PostHanja" }, + { 0x00ff3c, "SingleCandidate" }, + { 0x00ff3d, "MultipleCandidate" }, + { 0x00ff3e, "PreviousCandidate" }, + { 0x00ff3f, "Hangul_Special" }, + { 0x00ff50, "Home" }, + { 0x00ff51, "Left" }, + { 0x00ff52, "Up" }, + { 0x00ff53, "Right" }, + { 0x00ff54, "Down" }, + { 0x00ff55, "Page_Up" }, + { 0x00ff55, "Prior" }, + { 0x00ff56, "Next" }, + { 0x00ff56, "Page_Down" }, + { 0x00ff57, "End" }, + { 0x00ff58, "Begin" }, + { 0x00ff60, "Select" }, + { 0x00ff61, "Print" }, + { 0x00ff62, "Execute" }, + { 0x00ff63, "Insert" }, + { 0x00ff65, "Undo" }, + { 0x00ff66, "Redo" }, + { 0x00ff67, "Menu" }, + { 0x00ff68, "Find" }, + { 0x00ff69, "Cancel" }, + { 0x00ff6a, "Help" }, + { 0x00ff6b, "Break" }, + { 0x00ff7e, "Arabic_switch" }, + { 0x00ff7e, "Greek_switch" }, + { 0x00ff7e, "Hangul_switch" }, + { 0x00ff7e, "Hebrew_switch" }, + { 0x00ff7e, "ISO_Group_Shift" }, + { 0x00ff7e, "Mode_switch" }, + { 0x00ff7e, "kana_switch" }, + { 0x00ff7e, "script_switch" }, + { 0x00ff7f, "Num_Lock" }, + { 0x00ff80, "KP_Space" }, + { 0x00ff89, "KP_Tab" }, + { 0x00ff8d, "KP_Enter" }, + { 0x00ff91, "KP_F1" }, + { 0x00ff92, "KP_F2" }, + { 0x00ff93, "KP_F3" }, + { 0x00ff94, "KP_F4" }, + { 0x00ff95, "KP_Home" }, + { 0x00ff96, "KP_Left" }, + { 0x00ff97, "KP_Up" }, + { 0x00ff98, "KP_Right" }, + { 0x00ff99, "KP_Down" }, + { 0x00ff9a, "KP_Page_Up" }, + { 0x00ff9a, "KP_Prior" }, + { 0x00ff9b, "KP_Next" }, + { 0x00ff9b, "KP_Page_Down" }, + { 0x00ff9c, "KP_End" }, + { 0x00ff9d, "KP_Begin" }, + { 0x00ff9e, "KP_Insert" }, + { 0x00ff9f, "KP_Delete" }, + { 0x00ffaa, "KP_Multiply" }, + { 0x00ffab, "KP_Add" }, + { 0x00ffac, "KP_Separator" }, + { 0x00ffad, "KP_Subtract" }, + { 0x00ffae, "KP_Decimal" }, + { 0x00ffaf, "KP_Divide" }, + { 0x00ffb0, "KP_0" }, + { 0x00ffb1, "KP_1" }, + { 0x00ffb2, "KP_2" }, + { 0x00ffb3, "KP_3" }, + { 0x00ffb4, "KP_4" }, + { 0x00ffb5, "KP_5" }, + { 0x00ffb6, "KP_6" }, + { 0x00ffb7, "KP_7" }, + { 0x00ffb8, "KP_8" }, + { 0x00ffb9, "KP_9" }, + { 0x00ffbd, "KP_Equal" }, + { 0x00ffbe, "F1" }, + { 0x00ffbf, "F2" }, + { 0x00ffc0, "F3" }, + { 0x00ffc1, "F4" }, + { 0x00ffc2, "F5" }, + { 0x00ffc3, "F6" }, + { 0x00ffc4, "F7" }, + { 0x00ffc5, "F8" }, + { 0x00ffc6, "F9" }, + { 0x00ffc7, "F10" }, + { 0x00ffc8, "F11" }, + { 0x00ffc9, "F12" }, + { 0x00ffca, "F13" }, + { 0x00ffcb, "F14" }, + { 0x00ffcc, "F15" }, + { 0x00ffcd, "F16" }, + { 0x00ffce, "F17" }, + { 0x00ffcf, "F18" }, + { 0x00ffd0, "F19" }, + { 0x00ffd1, "F20" }, + { 0x00ffd2, "F21" }, + { 0x00ffd3, "F22" }, + { 0x00ffd4, "F23" }, + { 0x00ffd5, "F24" }, + { 0x00ffd6, "F25" }, + { 0x00ffd7, "F26" }, + { 0x00ffd8, "F27" }, + { 0x00ffd9, "F28" }, + { 0x00ffda, "F29" }, + { 0x00ffdb, "F30" }, + { 0x00ffdc, "F31" }, + { 0x00ffdd, "F32" }, + { 0x00ffde, "F33" }, + { 0x00ffdf, "F34" }, + { 0x00ffe0, "F35" }, + { 0x00ffe1, "Shift_L" }, + { 0x00ffe2, "Shift_R" }, + { 0x00ffe3, "Control_L" }, + { 0x00ffe4, "Control_R" }, + { 0x00ffe5, "Caps_Lock" }, + { 0x00ffe6, "Shift_Lock" }, + { 0x00ffe7, "Meta_L" }, + { 0x00ffe8, "Meta_R" }, + { 0x00ffe9, "Alt_L" }, + { 0x00ffea, "Alt_R" }, + { 0x00ffeb, "Super_L" }, + { 0x00ffec, "Super_R" }, + { 0x00ffed, "Hyper_L" }, + { 0x00ffee, "Hyper_R" }, + { 0x00ffff, "Delete" }, + { 0xffffff, "VoidSymbol" }, +}; + +#define GDK_NUM_KEYS (sizeof (gdk_keys_by_keyval) / sizeof (gdk_keys_by_keyval[0])) + +static struct gdk_key *gdk_keys_by_name = NULL; + +static int +gdk_keys_keyval_compare (const void *pkey, const void *pbase) +{ + return (*(int *) pkey) - ((struct gdk_key *) pbase)->keyval; +} + +gchar* +gdk_keyval_name (guint keyval) +{ + struct gdk_key *found = + bsearch (&keyval, gdk_keys_by_keyval, + GDK_NUM_KEYS, sizeof (struct gdk_key), + gdk_keys_keyval_compare); + if (found != NULL) + return (gchar *) found->name; + else + return NULL; +} + +static int +gdk_key_compare_by_name (const void *a, const void *b) +{ + return strcmp (((const struct gdk_key *) a)->name, ((const struct gdk_key *) b)->name); +} + +static int +gdk_keys_name_compare (const void *pkey, const void *pbase) +{ + return strcmp ((const char *) pkey, ((const struct gdk_key *) pbase)->name); +} + +guint +gdk_keyval_from_name (const gchar *keyval_name) +{ + struct gdk_key *found; + + g_return_val_if_fail (keyval_name != NULL, 0); + + if (gdk_keys_by_name == NULL) + { + gdk_keys_by_name = g_new (struct gdk_key, GDK_NUM_KEYS); + + memcpy (gdk_keys_by_name, gdk_keys_by_keyval, + GDK_NUM_KEYS * sizeof (struct gdk_key)); + + qsort (gdk_keys_by_name, GDK_NUM_KEYS, sizeof (struct gdk_key), + gdk_key_compare_by_name); + } + + found = bsearch (keyval_name, gdk_keys_by_name, + GDK_NUM_KEYS, sizeof (struct gdk_key), + gdk_keys_name_compare); + if (found != NULL) + return found->keyval; + else + return GDK_VoidSymbol; +} + +guint +gdk_keyval_to_upper (guint keyval) +{ + if (keyval) + { + KeySym lower_val = 0; + KeySym upper_val = 0; + + gdkx_XConvertCase (keyval, &lower_val, &upper_val); + return upper_val; + } + return 0; +} + +guint +gdk_keyval_to_lower (guint keyval) +{ + if (keyval) + { + KeySym lower_val = 0; + KeySym upper_val = 0; + + gdkx_XConvertCase (keyval, &lower_val, &upper_val); + return lower_val; + } + return 0; +} + +gboolean +gdk_keyval_is_upper (guint keyval) +{ + if (keyval) + { + KeySym lower_val = 0; + KeySym upper_val = 0; + + gdkx_XConvertCase (keyval, &lower_val, &upper_val); + return upper_val == keyval; + } + return TRUE; +} + +gboolean +gdk_keyval_is_lower (guint keyval) +{ + if (keyval) + { + KeySym lower_val = 0; + KeySym upper_val = 0; + + gdkx_XConvertCase (keyval, &lower_val, &upper_val); + return lower_val == keyval; + } + return TRUE; +} + + +void +gdk_threads_enter () +{ + GDK_THREADS_ENTER (); +} + +void +gdk_threads_leave () +{ + GDK_THREADS_LEAVE (); +} diff --git a/gdk/win32/gdkpixmap-win32.c b/gdk/win32/gdkpixmap-win32.c new file mode 100644 index 000000000..a78fca935 --- /dev/null +++ b/gdk/win32/gdkpixmap-win32.c @@ -0,0 +1,1002 @@ +/* GDK - The GIMP Drawing Kit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * Copyright (C) 1998-1999 Tor Lillqvist + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* + * Modified by the GTK+ Team and others 1997-1999. See the AUTHORS + * file for a list of people on the GTK+ Team. See the ChangeLog + * files for a list of changes. These files are distributed with + * GTK+ at ftp://ftp.gtk.org/pub/gtk/. + */ + +#include "config.h" + +#include +#include +#include + +#include "gdkpixmap.h" +#include "gdkprivate.h" +#include "gdkx.h" + +typedef struct +{ + gchar *color_string; + GdkColor color; + gint transparent; +} _GdkPixmapColor; + +typedef struct +{ + guint ncolors; + GdkColormap *colormap; + gulong pixels[1]; +} _GdkPixmapInfo; + +GdkPixmap* +gdk_pixmap_new (GdkWindow *window, + gint width, + gint height, + gint depth) +{ + GdkPixmap *pixmap; + GdkDrawablePrivate *private; + GdkWindowPrivate *window_private; + struct { + BITMAPINFOHEADER bmiHeader; + union { + WORD bmiIndices[256]; + DWORD bmiMasks[3]; + RGBQUAD bmiColors[256]; + } u; + } bmi; + UINT iUsage; + HDC hdc; + GdkVisual *visual; + guchar *bits; + gint i; + + g_return_val_if_fail (window == NULL || GDK_IS_WINDOW (window), NULL); + g_return_val_if_fail ((window != NULL) || (depth != -1), NULL); + g_return_val_if_fail ((width != 0) && (height != 0), NULL); + + if (!window) + window = (GdkWindow*) gdk_root_parent; + + if (GDK_DRAWABLE_DESTROYED (window)) + return NULL; + window_private = (GdkWindowPrivate*) window; + + if (depth == -1) + depth = gdk_drawable_get_visual (window)->depth; + + GDK_NOTE (MISC, g_print ("gdk_pixmap_new: %dx%dx%d\n", + width, height, depth)); + + private = g_new0 (GdkDrawablePrivate, 1); + pixmap = (GdkPixmap*) private; + + private->window_type = GDK_DRAWABLE_PIXMAP; + + visual = gdk_drawable_get_visual (window); + + if ((hdc = GetDC (GDK_DRAWABLE_XID (window))) == NULL) + { + g_warning ("gdk_pixmap_new: GetDC failed"); + g_free (private); + return NULL; + } + + bmi.bmiHeader.biSize = sizeof (BITMAPINFOHEADER); + bmi.bmiHeader.biWidth = width; + bmi.bmiHeader.biHeight = -height; + bmi.bmiHeader.biPlanes = 1; + if (depth == 15) + bmi.bmiHeader.biBitCount = 16; + else + bmi.bmiHeader.biBitCount = depth; +#if 1 + if (depth == 16) + bmi.bmiHeader.biCompression = BI_BITFIELDS; + else +#endif + bmi.bmiHeader.biCompression = BI_RGB; + bmi.bmiHeader.biSizeImage = 0; + bmi.bmiHeader.biXPelsPerMeter = + bmi.bmiHeader.biYPelsPerMeter = 0; + bmi.bmiHeader.biClrUsed = 0; + bmi.bmiHeader.biClrImportant = 0; + + iUsage = DIB_RGB_COLORS; + if (depth == 1) + { + bmi.u.bmiColors[0].rgbBlue = + bmi.u.bmiColors[0].rgbGreen = + bmi.u.bmiColors[0].rgbRed = 0x00; + bmi.u.bmiColors[0].rgbReserved = 0x00; + + bmi.u.bmiColors[1].rgbBlue = + bmi.u.bmiColors[1].rgbGreen = + bmi.u.bmiColors[1].rgbRed = 0xFF; + bmi.u.bmiColors[1].rgbReserved = 0x00; + private->colormap = NULL; + } + else + { + private->colormap = window_private->drawable.colormap; + if (private->colormap == NULL) + private->colormap = gdk_colormap_get_system (); + + if (depth == 8) + { + iUsage = DIB_PAL_COLORS; + for (i = 0; i < 256; i++) + bmi.u.bmiIndices[i] = i; + } + else + { + if (depth != visual->depth) + g_warning ("gdk_pixmap_new: depth %d doesn't match display depth %d", + depth, visual->depth); +#if 1 + if (depth == 16) + { + bmi.u.bmiMasks[0] = visual->red_mask; + bmi.u.bmiMasks[1] = visual->green_mask; + bmi.u.bmiMasks[2] = visual->blue_mask; + } +#endif + } + } + if ((private->xwindow = + CreateDIBSection (hdc, (BITMAPINFO *) &bmi, + iUsage, (PVOID *) &bits, NULL, 0)) == NULL) + { + g_warning ("gdk_pixmap_new: CreateDIBSection failed: %d", GetLastError ()); + ReleaseDC (GDK_DRAWABLE_XID (window), hdc); + g_free (private); + return NULL; + } + ReleaseDC (GDK_DRAWABLE_XID (window), hdc); + + GDK_NOTE (MISC, g_print ("... = %#x\n", private->xwindow)); + + private->width = width; + private->height = height; + private->ref_count = 1; + private->destroyed = 0; + + gdk_xid_table_insert (&private->xwindow, pixmap); + + return pixmap; +} + +GdkPixmap * +gdk_pixmap_create_on_shared_image (GdkImage **image_return, + GdkWindow *window, + GdkVisual *visual, + gint width, + gint height, + gint depth) +{ + GdkPixmap *pixmap; + GdkImagePrivate *image_private; + GdkDrawablePrivate *private; + GdkWindowPrivate *window_private; + + g_return_val_if_fail (window != NULL, NULL); + + window_private = (GdkWindowPrivate *) window; + + if (depth == 1) + *image_return = gdk_image_bitmap_new (GDK_IMAGE_SHARED_PIXMAP, visual, width, height); + else + { + g_return_val_if_fail (depth == visual->depth, NULL); + *image_return = gdk_image_new (GDK_IMAGE_SHARED_PIXMAP, visual, width, height); + } + + g_return_val_if_fail (*image_return != NULL, NULL); + + image_private = (GdkImagePrivate *) *image_return; + + private = g_new0 (GdkDrawablePrivate, 1); + pixmap = (GdkPixmap*) private; + + private->xwindow = image_private->ximage; + private->window_type = GDK_DRAWABLE_PIXMAP; + private->colormap = window_private->drawable.colormap; + private->width = width; + private->height = height; + private->ref_count = 1; + private->destroyed = 0; + + gdk_xid_table_insert (&private->xwindow, pixmap); + + GDK_NOTE (MISC, + g_print ("gdk_pixmap_create_on_shared_image: %dx%dx%d = %#x\n", + width, height, depth, private->xwindow)); + + return pixmap; +} + +static unsigned char mirror[256] = { + 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, + 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0, + 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8, + 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8, + 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4, + 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4, + 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec, + 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc, + 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2, + 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2, + 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea, + 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa, + 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6, + 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6, + 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee, + 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe, + 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1, + 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1, + 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9, + 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9, + 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5, + 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5, + 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed, + 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd, + 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3, + 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3, + 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb, + 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb, + 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7, + 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7, + 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef, + 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff +}; + +GdkPixmap * +gdk_bitmap_create_from_data (GdkWindow *window, + const gchar *data, + gint width, + gint height) +{ + GdkPixmap *pixmap; + GdkDrawablePrivate *private; + gint i, j, bpl, aligned_bpl; + guchar *bits; + + g_return_val_if_fail (data != NULL, NULL); + g_return_val_if_fail ((width != 0) && (height != 0), NULL); + g_return_val_if_fail (window == NULL || GDK_IS_WINDOW (window), NULL); + + if (!window) + window = (GdkWindow*) gdk_root_parent; + + if (GDK_DRAWABLE_DESTROYED (window)) + return NULL; + + private = g_new0 (GdkDrawablePrivate, 1); + pixmap = (GdkPixmap*) private; + + private->window_type = GDK_DRAWABLE_PIXMAP; + private->width = width; + private->height = height; + private->ref_count = 1; + private->destroyed = FALSE; + + bpl = ((width - 1) / 8 + 1); + aligned_bpl = ((bpl - 1) / 2 + 1) * 2; + bits = g_malloc (aligned_bpl * height); + for (i = 0; i < height; i++) + for (j = 0; j < bpl; j++) + bits[i*aligned_bpl + j] = mirror[(guchar) data[i*bpl + j]]; + private->xwindow = CreateBitmap (width, height, 1, 1, bits); + + GDK_NOTE (MISC, g_print ("gdk_bitmap_create_from_data: %dx%d = %#x\n", + width, height, private->xwindow)); + + g_free (bits); + + private->colormap = NULL; + gdk_xid_table_insert (&private->xwindow, pixmap); + + return pixmap; +} + +GdkPixmap* +gdk_pixmap_create_from_data (GdkWindow *window, + const gchar *data, + gint width, + gint height, + gint depth, + GdkColor *fg, + GdkColor *bg) +{ + /* Oh wow. I struggled with dozens of lines of code trying to get + * this right using a monochrome Win32 bitmap created from data, and + * a colour DIB section as the result, trying setting pens, + * background colors, whatnot and BitBlt:ing. Nope. Then finally I + * realized it's much easier to do it using gdk...: + */ + + GdkPixmap *result = gdk_pixmap_new (window, width, height, depth); + GdkPixmap *source = gdk_bitmap_create_from_data (window, data, width, height); + GdkGC *gc = gdk_gc_new (result); + gdk_gc_set_foreground (gc, fg); + gdk_gc_set_background (gc, bg); + gdk_draw_pixmap (result, gc, source, 0, 0, 0, 0, width, height); + gdk_pixmap_unref (source); + gdk_gc_unref (gc); + + GDK_NOTE (MISC, g_print ("gdk_pixmap_create_from_data: %dx%dx%d = %#x\n", + width, height, depth, + GDK_DRAWABLE_XID (result))); + return result; +} + +static gint +gdk_pixmap_seek_string (FILE *infile, + const gchar *str, + gint skip_comments) +{ + char instr[1024]; + + while (!feof (infile)) + { + fscanf (infile, "%1023s", instr); + if (skip_comments == TRUE && strcmp (instr, "/*") == 0) + { + fscanf (infile, "%1023s", instr); + while (!feof (infile) && strcmp (instr, "*/") != 0) + fscanf (infile, "%1023s", instr); + fscanf(infile, "%1023s", instr); + } + if (strcmp (instr, str)==0) + return TRUE; + } + + return FALSE; +} + +static gint +gdk_pixmap_seek_char (FILE *infile, + gchar c) +{ + gint b, oldb; + + while ((b = getc(infile)) != EOF) + { + if (c != b && b == '/') + { + b = getc (infile); + if (b == EOF) + return FALSE; + else if (b == '*') /* we have a comment */ + { + b = -1; + do + { + oldb = b; + b = getc (infile); + if (b == EOF) + return FALSE; + } + while (!(oldb == '*' && b == '/')); + } + } + else if (c == b) + return TRUE; + } + return FALSE; +} + +static gint +gdk_pixmap_read_string (FILE *infile, + gchar **buffer, + guint *buffer_size) +{ + gint c; + guint cnt = 0, bufsiz, ret = FALSE; + gchar *buf; + + buf = *buffer; + bufsiz = *buffer_size; + if (buf == NULL) + { + bufsiz = 10 * sizeof (gchar); + buf = g_new(gchar, bufsiz); + } + + do + c = getc (infile); + while (c != EOF && c != '"'); + + if (c != '"') + goto out; + + while ((c = getc(infile)) != EOF) + { + if (cnt == bufsiz) + { + guint new_size = bufsiz * 2; + if (new_size > bufsiz) + bufsiz = new_size; + else + goto out; + + buf = (gchar *) g_realloc (buf, bufsiz); + buf[bufsiz-1] = '\0'; + } + + if (c != '"') + buf[cnt++] = c; + else + { + buf[cnt] = 0; + ret = TRUE; + break; + } + } + + out: + buf[bufsiz-1] = '\0'; /* ensure null termination for errors */ + *buffer = buf; + *buffer_size = bufsiz; + return ret; +} + +static gchar* +gdk_pixmap_skip_whitespaces (gchar *buffer) +{ + gint32 index = 0; + + while (buffer[index] != 0 && (buffer[index] == 0x20 || buffer[index] == 0x09)) + index++; + + return &buffer[index]; +} + +static gchar* +gdk_pixmap_skip_string (gchar *buffer) +{ + gint32 index = 0; + + while (buffer[index] != 0 && buffer[index] != 0x20 && buffer[index] != 0x09) + index++; + + return &buffer[index]; +} + +#define MAX_COLOR_LEN 120 + +static gchar* +gdk_pixmap_extract_color (gchar *buffer) +{ + gint counter, numnames; + gchar *ptr = NULL, ch, temp[128]; + gchar color[MAX_COLOR_LEN], *retcol; + gint space; + + counter = 0; + while (ptr == NULL) + { + if (buffer[counter] == 'c') + { + ch = buffer[counter + 1]; + if (ch == 0x20 || ch == 0x09) + ptr = &buffer[counter + 1]; + } + else if (buffer[counter] == 0) + return NULL; + + counter++; + } + + ptr = gdk_pixmap_skip_whitespaces (ptr); + + if (ptr[0] == 0) + return NULL; + else if (ptr[0] == '#') + { + counter = 1; + while (ptr[counter] != 0 && + ((ptr[counter] >= '0' && ptr[counter] <= '9') || + (ptr[counter] >= 'a' && ptr[counter] <= 'f') || + (ptr[counter] >= 'A' && ptr[counter] <= 'F'))) + counter++; + + retcol = g_new (gchar, counter+1); + strncpy (retcol, ptr, counter); + + retcol[counter] = 0; + + return retcol; + } + + color[0] = 0; + numnames = 0; + + space = MAX_COLOR_LEN - 1; + while (space > 0) + { + sscanf (ptr, "%127s", temp); + + if (((gint)ptr[0] == 0) || + (strcmp ("s", temp) == 0) || (strcmp ("m", temp) == 0) || + (strcmp ("g", temp) == 0) || (strcmp ("g4", temp) == 0)) + { + break; + } + else + { + if (numnames > 0) + { + space -= 1; + strcat (color, " "); + } + strncat (color, temp, space); + space -= MIN (space, strlen (temp)); + ptr = gdk_pixmap_skip_string (ptr); + ptr = gdk_pixmap_skip_whitespaces (ptr); + numnames++; + } + } + + retcol = g_strdup (color); + return retcol; +} + + +enum buffer_op +{ + op_header, + op_cmap, + op_body +}; + + +static void +gdk_xpm_destroy_notify (gpointer data) +{ + _GdkPixmapInfo *info = (_GdkPixmapInfo *)data; + GdkColor color; + int i; + + for (i=0; incolors; i++) + { + color.pixel = info->pixels[i]; + gdk_colormap_free_colors (info->colormap, &color, 1); + } + + gdk_colormap_unref (info->colormap); + g_free (info); +} + +static GdkPixmap * +_gdk_pixmap_create_from_xpm (GdkWindow *window, + GdkColormap *colormap, + GdkBitmap **mask, + GdkColor *transparent_color, + gchar * (*get_buf) (enum buffer_op op, + gpointer handle), + gpointer handle) +{ + GdkPixmap *pixmap = NULL; + GdkImage *image = NULL; + GdkVisual *visual; + GdkGC *gc = NULL; + GdkColor tmp_color; + gint width, height, num_cols, cpp, n, ns, cnt, xcnt, ycnt, wbytes; + gchar *buffer, pixel_str[32]; + gchar *name_buf; + _GdkPixmapColor *color = NULL, *fallbackcolor = NULL; + _GdkPixmapColor *colors = NULL; + gulong index; + GHashTable *color_hash = NULL; + _GdkPixmapInfo *color_info = NULL; + + if ((window == NULL) && (colormap == NULL)) + g_warning ("Creating pixmap from xpm with NULL window and colormap"); + + if (window == NULL) + window = (GdkWindow *) gdk_root_parent; + + if (colormap == NULL) + { + colormap = gdk_window_get_colormap (window); + visual = gdk_window_get_visual (window); + } + else + visual = ((GdkColormapPrivate *)colormap)->visual; + + buffer = (*get_buf) (op_header, handle); + if (buffer == NULL) + return NULL; + + sscanf (buffer,"%d %d %d %d", &width, &height, &num_cols, &cpp); + if (cpp >= 32) + { + g_warning ("Pixmap has more than 31 characters per color"); + return NULL; + } + + color_hash = g_hash_table_new (g_str_hash, g_str_equal); + + if (transparent_color == NULL) + { + gdk_color_white (colormap, &tmp_color); + transparent_color = &tmp_color; + } + + /* For pseudo-color and grayscale visuals, we have to remember + * the colors we allocated, so we can free them later. + */ + if ((visual->type == GDK_VISUAL_PSEUDO_COLOR) || + (visual->type == GDK_VISUAL_GRAYSCALE)) + { + color_info = g_malloc (sizeof (_GdkPixmapInfo) + + sizeof(gulong) * (num_cols - 1)); + color_info->ncolors = num_cols; + color_info->colormap = colormap; + gdk_colormap_ref (colormap); + } + + name_buf = g_new (gchar, num_cols * (cpp+1)); + colors = g_new (_GdkPixmapColor, num_cols); + + for (cnt = 0; cnt < num_cols; cnt++) + { + gchar *color_name; + + buffer = (*get_buf) (op_cmap, handle); + if (buffer == NULL) + goto error; + + color = &colors[cnt]; + color->color_string = &name_buf [cnt * (cpp + 1)]; + strncpy (color->color_string, buffer, cpp); + color->color_string[cpp] = 0; + buffer += strlen (color->color_string); + color->transparent = FALSE; + + color_name = gdk_pixmap_extract_color (buffer); + + if (color_name == NULL || + gdk_color_parse (color_name, &color->color) == FALSE) + { + color->color = *transparent_color; + color->transparent = TRUE; + } + + g_free (color_name); + + /* FIXME: The remaining slowness appears to happen in this + function. */ + gdk_color_alloc (colormap, &color->color); + + if (color_info) + color_info->pixels[cnt] = color->color.pixel; + + g_hash_table_insert (color_hash, color->color_string, color); + if (cnt == 0) + fallbackcolor = color; + } + + index = 0; + image = gdk_image_new (GDK_IMAGE_FASTEST, visual, width, height); + + if (mask) + { + /* The pixmap mask is just a bits pattern. + * Color 0 is used for background and 1 for foreground. + * We don't care about the colormap, we just need 0 and 1. + */ + GdkColor mask_pattern; + + *mask = gdk_pixmap_new (window, width, height, 1); + gc = gdk_gc_new (*mask); + + mask_pattern.pixel = 0; + gdk_gc_set_foreground (gc, &mask_pattern); + gdk_draw_rectangle (*mask, gc, TRUE, 0, 0, -1, -1); + + mask_pattern.pixel = 1; + gdk_gc_set_foreground (gc, &mask_pattern); + } + + wbytes = width * cpp; + for (ycnt = 0; ycnt < height; ycnt++) + { + buffer = (*get_buf) (op_body, handle); + + /* FIXME: this slows things down a little - it could be + * integrated into the strncpy below, perhaps. OTOH, strlen + * is fast. + */ + if ((buffer == NULL) || strlen (buffer) < wbytes) + continue; + + for (n = 0, cnt = 0, xcnt = 0; n < wbytes; n += cpp, xcnt++) + { + strncpy (pixel_str, &buffer[n], cpp); + pixel_str[cpp] = 0; + ns = 0; + + color = g_hash_table_lookup (color_hash, pixel_str); + + if (!color) /* screwed up XPM file */ + color = fallbackcolor; + + gdk_image_put_pixel (image, xcnt, ycnt, color->color.pixel); + + if (mask && color->transparent) + { + if (cnt < xcnt) + gdk_draw_line (*mask, gc, cnt, ycnt, xcnt - 1, ycnt); + cnt = xcnt + 1; + } + } + + if (mask && (cnt < xcnt)) + gdk_draw_line (*mask, gc, cnt, ycnt, xcnt - 1, ycnt); + } + + error: + + if (mask) + gdk_gc_destroy (gc); + + if (image != NULL) + { + pixmap = gdk_pixmap_new (window, width, height, visual->depth); + + if (color_info) + gdk_drawable_set_data (pixmap, "gdk-xpm", color_info, + gdk_xpm_destroy_notify); + + gc = gdk_gc_new (pixmap); + gdk_gc_set_foreground (gc, transparent_color); + gdk_draw_image (pixmap, gc, image, 0, 0, 0, 0, image->width, image->height); + gdk_gc_destroy (gc); + gdk_image_destroy (image); + } + else if (color_info) + gdk_xpm_destroy_notify (color_info); + + if (color_hash != NULL) + g_hash_table_destroy (color_hash); + + if (colors != NULL) + g_free (colors); + + if (name_buf != NULL) + g_free (name_buf); + + return pixmap; +} + + +struct file_handle +{ + FILE *infile; + gchar *buffer; + guint buffer_size; +}; + + +static gchar * +file_buffer (enum buffer_op op, gpointer handle) +{ + struct file_handle *h = handle; + + switch (op) + { + case op_header: + if (gdk_pixmap_seek_string (h->infile, "XPM", FALSE) != TRUE) + break; + + if (gdk_pixmap_seek_char (h->infile,'{') != TRUE) + break; + /* Fall through to the next gdk_pixmap_seek_char. */ + + case op_cmap: + gdk_pixmap_seek_char (h->infile, '"'); + fseek (h->infile, -1, SEEK_CUR); + /* Fall through to the gdk_pixmap_read_string. */ + + case op_body: + gdk_pixmap_read_string (h->infile, &h->buffer, &h->buffer_size); + return h->buffer; + } + return 0; +} + +GdkPixmap* +gdk_pixmap_colormap_create_from_xpm (GdkWindow *window, + GdkColormap *colormap, + GdkBitmap **mask, + GdkColor *transparent_color, + const gchar *filename) +{ + struct file_handle h; + GdkPixmap *pixmap = NULL; + + memset (&h, 0, sizeof (h)); + h.infile = fopen (filename, "rb"); + if (h.infile != NULL) + { + pixmap = _gdk_pixmap_create_from_xpm (window, colormap, mask, + transparent_color, + file_buffer, &h); + fclose (h.infile); + g_free (h.buffer); + } + + return pixmap; +} + +GdkPixmap* +gdk_pixmap_create_from_xpm (GdkWindow *window, + GdkBitmap **mask, + GdkColor *transparent_color, + const gchar *filename) +{ + return gdk_pixmap_colormap_create_from_xpm (window, NULL, mask, + transparent_color, filename); +} + +struct mem_handle +{ + gchar **data; + int offset; +}; + + +static gchar * +mem_buffer (enum buffer_op op, gpointer handle) +{ + struct mem_handle *h = handle; + switch (op) + { + case op_header: + case op_cmap: + case op_body: + if (h->data[h->offset]) + return h->data[h->offset ++]; + } + return 0; +} + +GdkPixmap* +gdk_pixmap_colormap_create_from_xpm_d (GdkWindow *window, + GdkColormap *colormap, + GdkBitmap **mask, + GdkColor *transparent_color, + gchar **data) +{ + struct mem_handle h; + GdkPixmap *pixmap = NULL; + + memset (&h, 0, sizeof (h)); + h.data = data; + pixmap = _gdk_pixmap_create_from_xpm (window, colormap, mask, + transparent_color, + mem_buffer, &h); + return pixmap; +} + +GdkPixmap* +gdk_pixmap_create_from_xpm_d (GdkWindow *window, + GdkBitmap **mask, + GdkColor *transparent_color, + gchar **data) +{ + return gdk_pixmap_colormap_create_from_xpm_d (window, NULL, mask, + transparent_color, data); +} + +GdkPixmap* +gdk_pixmap_foreign_new (guint32 anid) +{ + GdkPixmap *pixmap; + GdkDrawablePrivate *private; + GdkWindowPrivate *window_private; + HBITMAP xpixmap; + SIZE size; + unsigned int x_ret, y_ret, w_ret, h_ret, bw_ret, depth_ret; + + /* check to make sure we were passed something at + least a little sane */ + g_return_val_if_fail((anid != 0), NULL); + + /* set the pixmap to the passed in value */ + xpixmap = (HBITMAP) anid; + /* get the root window */ + window_private = gdk_root_parent; + + /* get information about the BITMAP to fill in the structure for + the gdk window */ + GetBitmapDimensionEx (xpixmap, &size); + w_ret = size.cx; + h_ret = size.cy; + + /* allocate a new gdk pixmap */ + private = g_new (GdkDrawablePrivate, 1); + pixmap = (GdkPixmap *)private; + + private->window_type = GDK_DRAWABLE_PIXMAP; + private->xwindow = xpixmap; + private->colormap = NULL; + private->width = w_ret; + private->height = h_ret; + private->ref_count = 1; + private->destroyed = 0; + + gdk_xid_table_insert(&private->xwindow, pixmap); + + return pixmap; +} + +GdkPixmap* +gdk_pixmap_ref (GdkPixmap *pixmap) +{ + GdkDrawablePrivate *private = (GdkDrawablePrivate *)pixmap; + g_return_val_if_fail (pixmap != NULL, NULL); + g_return_val_if_fail (GDK_IS_PIXMAP (private), NULL); + + private->ref_count += 1; + return pixmap; +} + +void +gdk_pixmap_unref (GdkPixmap *pixmap) +{ + GdkDrawablePrivate *private = (GdkDrawablePrivate *)pixmap; + g_return_if_fail (pixmap != NULL); + g_return_if_fail (GDK_IS_PIXMAP (private)); + g_return_if_fail (private->ref_count > 0); + + private->ref_count -= 1; + + GDK_NOTE (MISC, g_print ("gdk_pixmap_unref: %#x %d%s\n", + private->xwindow, private->ref_count, + (private->ref_count == 0 ? " freeing" : ""))); + + if (private->ref_count == 0) + { + if (!DeleteObject (private->xwindow)) + g_warning ("gdk_pixmap_unref: DeleteObject failed"); + gdk_xid_table_remove (private->xwindow); + g_dataset_destroy (private); + g_free (private); + } +} + +GdkBitmap * +gdk_bitmap_ref (GdkBitmap *bitmap) +{ + return (GdkBitmap *)gdk_pixmap_ref ((GdkPixmap *)bitmap); +} + +void +gdk_bitmap_unref (GdkBitmap *bitmap) +{ + gdk_pixmap_unref ((GdkPixmap *)bitmap); +} diff --git a/gdk/win32/gdkpixmap.c b/gdk/win32/gdkpixmap.c new file mode 100644 index 000000000..a78fca935 --- /dev/null +++ b/gdk/win32/gdkpixmap.c @@ -0,0 +1,1002 @@ +/* GDK - The GIMP Drawing Kit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * Copyright (C) 1998-1999 Tor Lillqvist + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* + * Modified by the GTK+ Team and others 1997-1999. See the AUTHORS + * file for a list of people on the GTK+ Team. See the ChangeLog + * files for a list of changes. These files are distributed with + * GTK+ at ftp://ftp.gtk.org/pub/gtk/. + */ + +#include "config.h" + +#include +#include +#include + +#include "gdkpixmap.h" +#include "gdkprivate.h" +#include "gdkx.h" + +typedef struct +{ + gchar *color_string; + GdkColor color; + gint transparent; +} _GdkPixmapColor; + +typedef struct +{ + guint ncolors; + GdkColormap *colormap; + gulong pixels[1]; +} _GdkPixmapInfo; + +GdkPixmap* +gdk_pixmap_new (GdkWindow *window, + gint width, + gint height, + gint depth) +{ + GdkPixmap *pixmap; + GdkDrawablePrivate *private; + GdkWindowPrivate *window_private; + struct { + BITMAPINFOHEADER bmiHeader; + union { + WORD bmiIndices[256]; + DWORD bmiMasks[3]; + RGBQUAD bmiColors[256]; + } u; + } bmi; + UINT iUsage; + HDC hdc; + GdkVisual *visual; + guchar *bits; + gint i; + + g_return_val_if_fail (window == NULL || GDK_IS_WINDOW (window), NULL); + g_return_val_if_fail ((window != NULL) || (depth != -1), NULL); + g_return_val_if_fail ((width != 0) && (height != 0), NULL); + + if (!window) + window = (GdkWindow*) gdk_root_parent; + + if (GDK_DRAWABLE_DESTROYED (window)) + return NULL; + window_private = (GdkWindowPrivate*) window; + + if (depth == -1) + depth = gdk_drawable_get_visual (window)->depth; + + GDK_NOTE (MISC, g_print ("gdk_pixmap_new: %dx%dx%d\n", + width, height, depth)); + + private = g_new0 (GdkDrawablePrivate, 1); + pixmap = (GdkPixmap*) private; + + private->window_type = GDK_DRAWABLE_PIXMAP; + + visual = gdk_drawable_get_visual (window); + + if ((hdc = GetDC (GDK_DRAWABLE_XID (window))) == NULL) + { + g_warning ("gdk_pixmap_new: GetDC failed"); + g_free (private); + return NULL; + } + + bmi.bmiHeader.biSize = sizeof (BITMAPINFOHEADER); + bmi.bmiHeader.biWidth = width; + bmi.bmiHeader.biHeight = -height; + bmi.bmiHeader.biPlanes = 1; + if (depth == 15) + bmi.bmiHeader.biBitCount = 16; + else + bmi.bmiHeader.biBitCount = depth; +#if 1 + if (depth == 16) + bmi.bmiHeader.biCompression = BI_BITFIELDS; + else +#endif + bmi.bmiHeader.biCompression = BI_RGB; + bmi.bmiHeader.biSizeImage = 0; + bmi.bmiHeader.biXPelsPerMeter = + bmi.bmiHeader.biYPelsPerMeter = 0; + bmi.bmiHeader.biClrUsed = 0; + bmi.bmiHeader.biClrImportant = 0; + + iUsage = DIB_RGB_COLORS; + if (depth == 1) + { + bmi.u.bmiColors[0].rgbBlue = + bmi.u.bmiColors[0].rgbGreen = + bmi.u.bmiColors[0].rgbRed = 0x00; + bmi.u.bmiColors[0].rgbReserved = 0x00; + + bmi.u.bmiColors[1].rgbBlue = + bmi.u.bmiColors[1].rgbGreen = + bmi.u.bmiColors[1].rgbRed = 0xFF; + bmi.u.bmiColors[1].rgbReserved = 0x00; + private->colormap = NULL; + } + else + { + private->colormap = window_private->drawable.colormap; + if (private->colormap == NULL) + private->colormap = gdk_colormap_get_system (); + + if (depth == 8) + { + iUsage = DIB_PAL_COLORS; + for (i = 0; i < 256; i++) + bmi.u.bmiIndices[i] = i; + } + else + { + if (depth != visual->depth) + g_warning ("gdk_pixmap_new: depth %d doesn't match display depth %d", + depth, visual->depth); +#if 1 + if (depth == 16) + { + bmi.u.bmiMasks[0] = visual->red_mask; + bmi.u.bmiMasks[1] = visual->green_mask; + bmi.u.bmiMasks[2] = visual->blue_mask; + } +#endif + } + } + if ((private->xwindow = + CreateDIBSection (hdc, (BITMAPINFO *) &bmi, + iUsage, (PVOID *) &bits, NULL, 0)) == NULL) + { + g_warning ("gdk_pixmap_new: CreateDIBSection failed: %d", GetLastError ()); + ReleaseDC (GDK_DRAWABLE_XID (window), hdc); + g_free (private); + return NULL; + } + ReleaseDC (GDK_DRAWABLE_XID (window), hdc); + + GDK_NOTE (MISC, g_print ("... = %#x\n", private->xwindow)); + + private->width = width; + private->height = height; + private->ref_count = 1; + private->destroyed = 0; + + gdk_xid_table_insert (&private->xwindow, pixmap); + + return pixmap; +} + +GdkPixmap * +gdk_pixmap_create_on_shared_image (GdkImage **image_return, + GdkWindow *window, + GdkVisual *visual, + gint width, + gint height, + gint depth) +{ + GdkPixmap *pixmap; + GdkImagePrivate *image_private; + GdkDrawablePrivate *private; + GdkWindowPrivate *window_private; + + g_return_val_if_fail (window != NULL, NULL); + + window_private = (GdkWindowPrivate *) window; + + if (depth == 1) + *image_return = gdk_image_bitmap_new (GDK_IMAGE_SHARED_PIXMAP, visual, width, height); + else + { + g_return_val_if_fail (depth == visual->depth, NULL); + *image_return = gdk_image_new (GDK_IMAGE_SHARED_PIXMAP, visual, width, height); + } + + g_return_val_if_fail (*image_return != NULL, NULL); + + image_private = (GdkImagePrivate *) *image_return; + + private = g_new0 (GdkDrawablePrivate, 1); + pixmap = (GdkPixmap*) private; + + private->xwindow = image_private->ximage; + private->window_type = GDK_DRAWABLE_PIXMAP; + private->colormap = window_private->drawable.colormap; + private->width = width; + private->height = height; + private->ref_count = 1; + private->destroyed = 0; + + gdk_xid_table_insert (&private->xwindow, pixmap); + + GDK_NOTE (MISC, + g_print ("gdk_pixmap_create_on_shared_image: %dx%dx%d = %#x\n", + width, height, depth, private->xwindow)); + + return pixmap; +} + +static unsigned char mirror[256] = { + 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, + 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0, + 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8, + 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8, + 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4, + 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4, + 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec, + 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc, + 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2, + 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2, + 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea, + 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa, + 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6, + 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6, + 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee, + 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe, + 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1, + 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1, + 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9, + 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9, + 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5, + 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5, + 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed, + 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd, + 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3, + 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3, + 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb, + 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb, + 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7, + 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7, + 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef, + 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff +}; + +GdkPixmap * +gdk_bitmap_create_from_data (GdkWindow *window, + const gchar *data, + gint width, + gint height) +{ + GdkPixmap *pixmap; + GdkDrawablePrivate *private; + gint i, j, bpl, aligned_bpl; + guchar *bits; + + g_return_val_if_fail (data != NULL, NULL); + g_return_val_if_fail ((width != 0) && (height != 0), NULL); + g_return_val_if_fail (window == NULL || GDK_IS_WINDOW (window), NULL); + + if (!window) + window = (GdkWindow*) gdk_root_parent; + + if (GDK_DRAWABLE_DESTROYED (window)) + return NULL; + + private = g_new0 (GdkDrawablePrivate, 1); + pixmap = (GdkPixmap*) private; + + private->window_type = GDK_DRAWABLE_PIXMAP; + private->width = width; + private->height = height; + private->ref_count = 1; + private->destroyed = FALSE; + + bpl = ((width - 1) / 8 + 1); + aligned_bpl = ((bpl - 1) / 2 + 1) * 2; + bits = g_malloc (aligned_bpl * height); + for (i = 0; i < height; i++) + for (j = 0; j < bpl; j++) + bits[i*aligned_bpl + j] = mirror[(guchar) data[i*bpl + j]]; + private->xwindow = CreateBitmap (width, height, 1, 1, bits); + + GDK_NOTE (MISC, g_print ("gdk_bitmap_create_from_data: %dx%d = %#x\n", + width, height, private->xwindow)); + + g_free (bits); + + private->colormap = NULL; + gdk_xid_table_insert (&private->xwindow, pixmap); + + return pixmap; +} + +GdkPixmap* +gdk_pixmap_create_from_data (GdkWindow *window, + const gchar *data, + gint width, + gint height, + gint depth, + GdkColor *fg, + GdkColor *bg) +{ + /* Oh wow. I struggled with dozens of lines of code trying to get + * this right using a monochrome Win32 bitmap created from data, and + * a colour DIB section as the result, trying setting pens, + * background colors, whatnot and BitBlt:ing. Nope. Then finally I + * realized it's much easier to do it using gdk...: + */ + + GdkPixmap *result = gdk_pixmap_new (window, width, height, depth); + GdkPixmap *source = gdk_bitmap_create_from_data (window, data, width, height); + GdkGC *gc = gdk_gc_new (result); + gdk_gc_set_foreground (gc, fg); + gdk_gc_set_background (gc, bg); + gdk_draw_pixmap (result, gc, source, 0, 0, 0, 0, width, height); + gdk_pixmap_unref (source); + gdk_gc_unref (gc); + + GDK_NOTE (MISC, g_print ("gdk_pixmap_create_from_data: %dx%dx%d = %#x\n", + width, height, depth, + GDK_DRAWABLE_XID (result))); + return result; +} + +static gint +gdk_pixmap_seek_string (FILE *infile, + const gchar *str, + gint skip_comments) +{ + char instr[1024]; + + while (!feof (infile)) + { + fscanf (infile, "%1023s", instr); + if (skip_comments == TRUE && strcmp (instr, "/*") == 0) + { + fscanf (infile, "%1023s", instr); + while (!feof (infile) && strcmp (instr, "*/") != 0) + fscanf (infile, "%1023s", instr); + fscanf(infile, "%1023s", instr); + } + if (strcmp (instr, str)==0) + return TRUE; + } + + return FALSE; +} + +static gint +gdk_pixmap_seek_char (FILE *infile, + gchar c) +{ + gint b, oldb; + + while ((b = getc(infile)) != EOF) + { + if (c != b && b == '/') + { + b = getc (infile); + if (b == EOF) + return FALSE; + else if (b == '*') /* we have a comment */ + { + b = -1; + do + { + oldb = b; + b = getc (infile); + if (b == EOF) + return FALSE; + } + while (!(oldb == '*' && b == '/')); + } + } + else if (c == b) + return TRUE; + } + return FALSE; +} + +static gint +gdk_pixmap_read_string (FILE *infile, + gchar **buffer, + guint *buffer_size) +{ + gint c; + guint cnt = 0, bufsiz, ret = FALSE; + gchar *buf; + + buf = *buffer; + bufsiz = *buffer_size; + if (buf == NULL) + { + bufsiz = 10 * sizeof (gchar); + buf = g_new(gchar, bufsiz); + } + + do + c = getc (infile); + while (c != EOF && c != '"'); + + if (c != '"') + goto out; + + while ((c = getc(infile)) != EOF) + { + if (cnt == bufsiz) + { + guint new_size = bufsiz * 2; + if (new_size > bufsiz) + bufsiz = new_size; + else + goto out; + + buf = (gchar *) g_realloc (buf, bufsiz); + buf[bufsiz-1] = '\0'; + } + + if (c != '"') + buf[cnt++] = c; + else + { + buf[cnt] = 0; + ret = TRUE; + break; + } + } + + out: + buf[bufsiz-1] = '\0'; /* ensure null termination for errors */ + *buffer = buf; + *buffer_size = bufsiz; + return ret; +} + +static gchar* +gdk_pixmap_skip_whitespaces (gchar *buffer) +{ + gint32 index = 0; + + while (buffer[index] != 0 && (buffer[index] == 0x20 || buffer[index] == 0x09)) + index++; + + return &buffer[index]; +} + +static gchar* +gdk_pixmap_skip_string (gchar *buffer) +{ + gint32 index = 0; + + while (buffer[index] != 0 && buffer[index] != 0x20 && buffer[index] != 0x09) + index++; + + return &buffer[index]; +} + +#define MAX_COLOR_LEN 120 + +static gchar* +gdk_pixmap_extract_color (gchar *buffer) +{ + gint counter, numnames; + gchar *ptr = NULL, ch, temp[128]; + gchar color[MAX_COLOR_LEN], *retcol; + gint space; + + counter = 0; + while (ptr == NULL) + { + if (buffer[counter] == 'c') + { + ch = buffer[counter + 1]; + if (ch == 0x20 || ch == 0x09) + ptr = &buffer[counter + 1]; + } + else if (buffer[counter] == 0) + return NULL; + + counter++; + } + + ptr = gdk_pixmap_skip_whitespaces (ptr); + + if (ptr[0] == 0) + return NULL; + else if (ptr[0] == '#') + { + counter = 1; + while (ptr[counter] != 0 && + ((ptr[counter] >= '0' && ptr[counter] <= '9') || + (ptr[counter] >= 'a' && ptr[counter] <= 'f') || + (ptr[counter] >= 'A' && ptr[counter] <= 'F'))) + counter++; + + retcol = g_new (gchar, counter+1); + strncpy (retcol, ptr, counter); + + retcol[counter] = 0; + + return retcol; + } + + color[0] = 0; + numnames = 0; + + space = MAX_COLOR_LEN - 1; + while (space > 0) + { + sscanf (ptr, "%127s", temp); + + if (((gint)ptr[0] == 0) || + (strcmp ("s", temp) == 0) || (strcmp ("m", temp) == 0) || + (strcmp ("g", temp) == 0) || (strcmp ("g4", temp) == 0)) + { + break; + } + else + { + if (numnames > 0) + { + space -= 1; + strcat (color, " "); + } + strncat (color, temp, space); + space -= MIN (space, strlen (temp)); + ptr = gdk_pixmap_skip_string (ptr); + ptr = gdk_pixmap_skip_whitespaces (ptr); + numnames++; + } + } + + retcol = g_strdup (color); + return retcol; +} + + +enum buffer_op +{ + op_header, + op_cmap, + op_body +}; + + +static void +gdk_xpm_destroy_notify (gpointer data) +{ + _GdkPixmapInfo *info = (_GdkPixmapInfo *)data; + GdkColor color; + int i; + + for (i=0; incolors; i++) + { + color.pixel = info->pixels[i]; + gdk_colormap_free_colors (info->colormap, &color, 1); + } + + gdk_colormap_unref (info->colormap); + g_free (info); +} + +static GdkPixmap * +_gdk_pixmap_create_from_xpm (GdkWindow *window, + GdkColormap *colormap, + GdkBitmap **mask, + GdkColor *transparent_color, + gchar * (*get_buf) (enum buffer_op op, + gpointer handle), + gpointer handle) +{ + GdkPixmap *pixmap = NULL; + GdkImage *image = NULL; + GdkVisual *visual; + GdkGC *gc = NULL; + GdkColor tmp_color; + gint width, height, num_cols, cpp, n, ns, cnt, xcnt, ycnt, wbytes; + gchar *buffer, pixel_str[32]; + gchar *name_buf; + _GdkPixmapColor *color = NULL, *fallbackcolor = NULL; + _GdkPixmapColor *colors = NULL; + gulong index; + GHashTable *color_hash = NULL; + _GdkPixmapInfo *color_info = NULL; + + if ((window == NULL) && (colormap == NULL)) + g_warning ("Creating pixmap from xpm with NULL window and colormap"); + + if (window == NULL) + window = (GdkWindow *) gdk_root_parent; + + if (colormap == NULL) + { + colormap = gdk_window_get_colormap (window); + visual = gdk_window_get_visual (window); + } + else + visual = ((GdkColormapPrivate *)colormap)->visual; + + buffer = (*get_buf) (op_header, handle); + if (buffer == NULL) + return NULL; + + sscanf (buffer,"%d %d %d %d", &width, &height, &num_cols, &cpp); + if (cpp >= 32) + { + g_warning ("Pixmap has more than 31 characters per color"); + return NULL; + } + + color_hash = g_hash_table_new (g_str_hash, g_str_equal); + + if (transparent_color == NULL) + { + gdk_color_white (colormap, &tmp_color); + transparent_color = &tmp_color; + } + + /* For pseudo-color and grayscale visuals, we have to remember + * the colors we allocated, so we can free them later. + */ + if ((visual->type == GDK_VISUAL_PSEUDO_COLOR) || + (visual->type == GDK_VISUAL_GRAYSCALE)) + { + color_info = g_malloc (sizeof (_GdkPixmapInfo) + + sizeof(gulong) * (num_cols - 1)); + color_info->ncolors = num_cols; + color_info->colormap = colormap; + gdk_colormap_ref (colormap); + } + + name_buf = g_new (gchar, num_cols * (cpp+1)); + colors = g_new (_GdkPixmapColor, num_cols); + + for (cnt = 0; cnt < num_cols; cnt++) + { + gchar *color_name; + + buffer = (*get_buf) (op_cmap, handle); + if (buffer == NULL) + goto error; + + color = &colors[cnt]; + color->color_string = &name_buf [cnt * (cpp + 1)]; + strncpy (color->color_string, buffer, cpp); + color->color_string[cpp] = 0; + buffer += strlen (color->color_string); + color->transparent = FALSE; + + color_name = gdk_pixmap_extract_color (buffer); + + if (color_name == NULL || + gdk_color_parse (color_name, &color->color) == FALSE) + { + color->color = *transparent_color; + color->transparent = TRUE; + } + + g_free (color_name); + + /* FIXME: The remaining slowness appears to happen in this + function. */ + gdk_color_alloc (colormap, &color->color); + + if (color_info) + color_info->pixels[cnt] = color->color.pixel; + + g_hash_table_insert (color_hash, color->color_string, color); + if (cnt == 0) + fallbackcolor = color; + } + + index = 0; + image = gdk_image_new (GDK_IMAGE_FASTEST, visual, width, height); + + if (mask) + { + /* The pixmap mask is just a bits pattern. + * Color 0 is used for background and 1 for foreground. + * We don't care about the colormap, we just need 0 and 1. + */ + GdkColor mask_pattern; + + *mask = gdk_pixmap_new (window, width, height, 1); + gc = gdk_gc_new (*mask); + + mask_pattern.pixel = 0; + gdk_gc_set_foreground (gc, &mask_pattern); + gdk_draw_rectangle (*mask, gc, TRUE, 0, 0, -1, -1); + + mask_pattern.pixel = 1; + gdk_gc_set_foreground (gc, &mask_pattern); + } + + wbytes = width * cpp; + for (ycnt = 0; ycnt < height; ycnt++) + { + buffer = (*get_buf) (op_body, handle); + + /* FIXME: this slows things down a little - it could be + * integrated into the strncpy below, perhaps. OTOH, strlen + * is fast. + */ + if ((buffer == NULL) || strlen (buffer) < wbytes) + continue; + + for (n = 0, cnt = 0, xcnt = 0; n < wbytes; n += cpp, xcnt++) + { + strncpy (pixel_str, &buffer[n], cpp); + pixel_str[cpp] = 0; + ns = 0; + + color = g_hash_table_lookup (color_hash, pixel_str); + + if (!color) /* screwed up XPM file */ + color = fallbackcolor; + + gdk_image_put_pixel (image, xcnt, ycnt, color->color.pixel); + + if (mask && color->transparent) + { + if (cnt < xcnt) + gdk_draw_line (*mask, gc, cnt, ycnt, xcnt - 1, ycnt); + cnt = xcnt + 1; + } + } + + if (mask && (cnt < xcnt)) + gdk_draw_line (*mask, gc, cnt, ycnt, xcnt - 1, ycnt); + } + + error: + + if (mask) + gdk_gc_destroy (gc); + + if (image != NULL) + { + pixmap = gdk_pixmap_new (window, width, height, visual->depth); + + if (color_info) + gdk_drawable_set_data (pixmap, "gdk-xpm", color_info, + gdk_xpm_destroy_notify); + + gc = gdk_gc_new (pixmap); + gdk_gc_set_foreground (gc, transparent_color); + gdk_draw_image (pixmap, gc, image, 0, 0, 0, 0, image->width, image->height); + gdk_gc_destroy (gc); + gdk_image_destroy (image); + } + else if (color_info) + gdk_xpm_destroy_notify (color_info); + + if (color_hash != NULL) + g_hash_table_destroy (color_hash); + + if (colors != NULL) + g_free (colors); + + if (name_buf != NULL) + g_free (name_buf); + + return pixmap; +} + + +struct file_handle +{ + FILE *infile; + gchar *buffer; + guint buffer_size; +}; + + +static gchar * +file_buffer (enum buffer_op op, gpointer handle) +{ + struct file_handle *h = handle; + + switch (op) + { + case op_header: + if (gdk_pixmap_seek_string (h->infile, "XPM", FALSE) != TRUE) + break; + + if (gdk_pixmap_seek_char (h->infile,'{') != TRUE) + break; + /* Fall through to the next gdk_pixmap_seek_char. */ + + case op_cmap: + gdk_pixmap_seek_char (h->infile, '"'); + fseek (h->infile, -1, SEEK_CUR); + /* Fall through to the gdk_pixmap_read_string. */ + + case op_body: + gdk_pixmap_read_string (h->infile, &h->buffer, &h->buffer_size); + return h->buffer; + } + return 0; +} + +GdkPixmap* +gdk_pixmap_colormap_create_from_xpm (GdkWindow *window, + GdkColormap *colormap, + GdkBitmap **mask, + GdkColor *transparent_color, + const gchar *filename) +{ + struct file_handle h; + GdkPixmap *pixmap = NULL; + + memset (&h, 0, sizeof (h)); + h.infile = fopen (filename, "rb"); + if (h.infile != NULL) + { + pixmap = _gdk_pixmap_create_from_xpm (window, colormap, mask, + transparent_color, + file_buffer, &h); + fclose (h.infile); + g_free (h.buffer); + } + + return pixmap; +} + +GdkPixmap* +gdk_pixmap_create_from_xpm (GdkWindow *window, + GdkBitmap **mask, + GdkColor *transparent_color, + const gchar *filename) +{ + return gdk_pixmap_colormap_create_from_xpm (window, NULL, mask, + transparent_color, filename); +} + +struct mem_handle +{ + gchar **data; + int offset; +}; + + +static gchar * +mem_buffer (enum buffer_op op, gpointer handle) +{ + struct mem_handle *h = handle; + switch (op) + { + case op_header: + case op_cmap: + case op_body: + if (h->data[h->offset]) + return h->data[h->offset ++]; + } + return 0; +} + +GdkPixmap* +gdk_pixmap_colormap_create_from_xpm_d (GdkWindow *window, + GdkColormap *colormap, + GdkBitmap **mask, + GdkColor *transparent_color, + gchar **data) +{ + struct mem_handle h; + GdkPixmap *pixmap = NULL; + + memset (&h, 0, sizeof (h)); + h.data = data; + pixmap = _gdk_pixmap_create_from_xpm (window, colormap, mask, + transparent_color, + mem_buffer, &h); + return pixmap; +} + +GdkPixmap* +gdk_pixmap_create_from_xpm_d (GdkWindow *window, + GdkBitmap **mask, + GdkColor *transparent_color, + gchar **data) +{ + return gdk_pixmap_colormap_create_from_xpm_d (window, NULL, mask, + transparent_color, data); +} + +GdkPixmap* +gdk_pixmap_foreign_new (guint32 anid) +{ + GdkPixmap *pixmap; + GdkDrawablePrivate *private; + GdkWindowPrivate *window_private; + HBITMAP xpixmap; + SIZE size; + unsigned int x_ret, y_ret, w_ret, h_ret, bw_ret, depth_ret; + + /* check to make sure we were passed something at + least a little sane */ + g_return_val_if_fail((anid != 0), NULL); + + /* set the pixmap to the passed in value */ + xpixmap = (HBITMAP) anid; + /* get the root window */ + window_private = gdk_root_parent; + + /* get information about the BITMAP to fill in the structure for + the gdk window */ + GetBitmapDimensionEx (xpixmap, &size); + w_ret = size.cx; + h_ret = size.cy; + + /* allocate a new gdk pixmap */ + private = g_new (GdkDrawablePrivate, 1); + pixmap = (GdkPixmap *)private; + + private->window_type = GDK_DRAWABLE_PIXMAP; + private->xwindow = xpixmap; + private->colormap = NULL; + private->width = w_ret; + private->height = h_ret; + private->ref_count = 1; + private->destroyed = 0; + + gdk_xid_table_insert(&private->xwindow, pixmap); + + return pixmap; +} + +GdkPixmap* +gdk_pixmap_ref (GdkPixmap *pixmap) +{ + GdkDrawablePrivate *private = (GdkDrawablePrivate *)pixmap; + g_return_val_if_fail (pixmap != NULL, NULL); + g_return_val_if_fail (GDK_IS_PIXMAP (private), NULL); + + private->ref_count += 1; + return pixmap; +} + +void +gdk_pixmap_unref (GdkPixmap *pixmap) +{ + GdkDrawablePrivate *private = (GdkDrawablePrivate *)pixmap; + g_return_if_fail (pixmap != NULL); + g_return_if_fail (GDK_IS_PIXMAP (private)); + g_return_if_fail (private->ref_count > 0); + + private->ref_count -= 1; + + GDK_NOTE (MISC, g_print ("gdk_pixmap_unref: %#x %d%s\n", + private->xwindow, private->ref_count, + (private->ref_count == 0 ? " freeing" : ""))); + + if (private->ref_count == 0) + { + if (!DeleteObject (private->xwindow)) + g_warning ("gdk_pixmap_unref: DeleteObject failed"); + gdk_xid_table_remove (private->xwindow); + g_dataset_destroy (private); + g_free (private); + } +} + +GdkBitmap * +gdk_bitmap_ref (GdkBitmap *bitmap) +{ + return (GdkBitmap *)gdk_pixmap_ref ((GdkPixmap *)bitmap); +} + +void +gdk_bitmap_unref (GdkBitmap *bitmap) +{ + gdk_pixmap_unref ((GdkPixmap *)bitmap); +} diff --git a/gdk/win32/gdkprivate-win32.h b/gdk/win32/gdkprivate-win32.h new file mode 100644 index 000000000..30b276d42 --- /dev/null +++ b/gdk/win32/gdkprivate-win32.h @@ -0,0 +1,459 @@ +/* GDK - The GIMP Drawing Kit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* + * Modified by the GTK+ Team and others 1997-1999. See the AUTHORS + * file for a list of people on the GTK+ Team. See the ChangeLog + * files for a list of changes. These files are distributed with + * GTK+ at ftp://ftp.gtk.org/pub/gtk/. + */ + +#ifndef __GDK_PRIVATE_H__ +#define __GDK_PRIVATE_H__ + +#define STRICT /* We want strict type checks */ +#include +#include + +/* Make up for some minor mingw32 lossage */ + +/* PS_JOIN_MASK is missing from the mingw32 headers */ +#ifndef PS_JOIN_MASK +#define PS_JOIN_MASK (PS_JOIN_BEVEL|PS_JOIN_MITER|PS_JOIN_ROUND) +#endif + +/* CLR_INVALID is missing */ +#ifndef CLR_INVALID +#define CLR_INVALID CLR_NONE +#endif + +/* Some charsets are missing */ +#ifndef JOHAB_CHARSET +#define JOHAB_CHARSET 130 +#endif +#ifndef VIETNAMESE_CHARSET +#define VIETNAMESE_CHARSET 163 +#endif + +#ifndef VM_OEM_PLUS +#define VK_OEM_PLUS 0xBB +#endif + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define GDK_DRAWABLE_TYPE(d) (((GdkDrawablePrivate *)d)->window_type) +#define GDK_IS_WINDOW(d) (GDK_DRAWABLE_TYPE(d) <= GDK_WINDOW_TEMP || \ + GDK_DRAWABLE_TYPE(d) == GDK_WINDOW_FOREIGN) +#define GDK_IS_PIXMAP(d) (GDK_DRAWABLE_TYPE(d) == GDK_DRAWABLE_PIXMAP) +#define GDK_DRAWABLE_DESTROYED(d) (((GdkDrawablePrivate *)d)->destroyed) + +#define gdk_window_lookup(xid) ((GdkWindow*) gdk_xid_table_lookup (xid)) +#define gdk_pixmap_lookup(xid) ((GdkPixmap*) gdk_xid_table_lookup (xid)) + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* Define corresponding Windows types for some X11 types, just for laziness. + */ + +typedef HANDLE XID; +typedef PALETTEENTRY XColor; +typedef HDC GC; +typedef ATOM Atom; +typedef HCURSOR Cursor; +typedef guint VisualID; +typedef DWORD KeySym; +typedef int Status; + +/* Define some of the X11 constants also here, again just for laziness */ + +/* Generic null resource */ +#define None 0 + +/* Error codes */ +#define Success 0 + +/* Grabbing status */ +#define GrabSuccess 0 +#define AlreadyGrabbed 2 + +/* For CreateColormap */ +#define AllocNone 0 +#define AllocAll 1 + +/* Some structs are somewhat useful to emulate internally, just to + keep the code less #ifdefed. */ +typedef struct { + HPALETTE palette; /* Palette handle used when drawing. */ + guint size; /* Number of entries in the palette. */ + gboolean stale; /* 1 if palette needs to be realized, + * otherwise 0. */ + gboolean *in_use; + gboolean rc_palette; /* If RC_PALETTE is on in the RASTERCAPS */ + gulong sizepalette; /* SIZEPALETTE if rc_palette */ +} ColormapStruct, *Colormap; + +typedef struct { + gint map_entries; + guint visualid; + guint bitspixel; +} Visual; + +typedef struct { + Colormap colormap; + unsigned long red_max; + unsigned long red_mult; + unsigned long green_max; + unsigned long green_mult; + unsigned long blue_max; + unsigned long blue_mult; + unsigned long base_pixel; +} XStandardColormap; + +typedef struct _GdkDrawablePrivate GdkDrawablePrivate; +/* typedef struct _GdkDrawablePrivate GdkPixmapPrivate; */ +typedef struct _GdkWindowPrivate GdkWindowPrivate; +typedef struct _GdkImagePrivate GdkImagePrivate; +typedef struct _GdkGCPrivate GdkGCPrivate; +typedef struct _GdkColormapPrivate GdkColormapPrivate; +typedef struct _GdkColorInfo GdkColorInfo; +typedef struct _GdkVisualPrivate GdkVisualPrivate; +typedef struct _GdkFontPrivate GdkFontPrivate; +typedef struct _GdkCursorPrivate GdkCursorPrivate; +typedef struct _GdkEventFilter GdkEventFilter; +typedef struct _GdkClientFilter GdkClientFilter; +typedef struct _GdkRegionPrivate GdkRegionPrivate; + +struct _GdkDrawablePrivate +{ + GdkDrawable drawable; + + guint8 window_type; + guint ref_count; + + guint16 width; + guint16 height; + + HANDLE xwindow; + GdkColormap *colormap; + + guint destroyed : 2; +}; + +struct _GdkWindowPrivate +{ + GdkDrawablePrivate drawable; + + GdkWindow *parent; + gint16 x; + gint16 y; + guint8 resize_count; + guint mapped : 1; + guint guffaw_gravity : 1; + + /* We must keep the event mask here to filter them ourselves */ + gint event_mask; + + /* Values for bg_type */ +#define GDK_WIN32_BG_NORMAL 0 +#define GDK_WIN32_BG_PIXEL 1 +#define GDK_WIN32_BG_PIXMAP 2 +#define GDK_WIN32_BG_PARENT_RELATIVE 3 +#define GDK_WIN32_BG_TRANSPARENT 4 + + /* We draw the background ourselves at WM_ERASEBKGND */ + guchar bg_type; + GdkColor bg_pixel; + GdkPixmap *bg_pixmap; + + HCURSOR xcursor; + + /* Window size hints */ + gint hint_flags; + gint hint_x, hint_y; + gint hint_min_width, hint_min_height; + gint hint_max_width, hint_max_height; + + gint extension_events; + gboolean extension_events_selected; + + GList *filters; + GList *children; + + HKL input_locale; + CHARSETINFO charset_info; +}; + +struct _GdkImagePrivate +{ + GdkImage image; + HBITMAP ximage; + gpointer x_shm_info; + + void (*image_put) (GdkDrawable *window, + GdkGC *gc, + GdkImage *image, + gint xsrc, + gint ysrc, + gint xdest, + gint ydest, + gint width, + gint height); +}; + +struct _GdkGCPrivate +{ + GdkGC gc; + GC xgc; + /* A Windows Device Context (DC) is not equivalent to an X11 + * GC. We can use a DC only in the window for which it was + * allocated, or (in the case of a memory DC) with the bitmap that + * has been selected into it. Thus, we have to release and + * reallocate a DC each time the GdkGC is used to paint into a new + * window or pixmap. We thus keep all the necessary values in the + * GdkGCPrivate struct. + */ + GdkGCValuesMask values_mask; + GdkColor foreground; + GdkColor background; + GdkFont *font; + gint rop2; + GdkFill fill_style; + GdkPixmap *tile; + GdkPixmap *stipple; + HRGN clip_region; + GdkSubwindowMode subwindow_mode; + gint ts_x_origin; + gint ts_y_origin; + gint clip_x_origin; + gint clip_y_origin; + gint graphics_exposures; + gint pen_width; + DWORD pen_style; + HANDLE hwnd; /* If a DC is allocated, for which window + or what bitmap is selected into it */ + int saved_dc; + guint ref_count; +}; + +typedef enum { + GDK_COLOR_WRITEABLE = 1 << 0 +} GdkColorInfoFlags; + +struct _GdkColorInfo +{ + GdkColorInfoFlags flags; + guint ref_count; +}; + +struct _GdkColormapPrivate +{ + GdkColormap colormap; + Colormap xcolormap; + GdkVisual *visual; + gint private_val; + + GHashTable *hash; + GdkColorInfo *info; + time_t last_sync_time; + + guint ref_count; +}; + +struct _GdkVisualPrivate +{ + GdkVisual visual; + Visual *xvisual; +}; + +typedef struct +{ + HFONT xfont; + DWORD charset; + UINT codepage; + CPINFO cpinfo; + FONTSIGNATURE fs; +} GdkWin32SingleFont; + +struct _GdkFontPrivate +{ + GdkFont font; + guint ref_count; + + GSList *fonts; + GSList *names; +}; + +struct _GdkCursorPrivate +{ + GdkCursor cursor; + Cursor xcursor; +}; + +struct _GdkEventFilter { + GdkFilterFunc function; + gpointer data; +}; + +struct _GdkClientFilter { + GdkAtom type; + GdkFilterFunc function; + gpointer data; +}; + +struct _GdkRegionPrivate +{ + GdkRegion region; + HRGN xregion; +}; + +typedef enum { + GDK_DEBUG_MISC = 1 << 0, + GDK_DEBUG_EVENTS = 1 << 1, + GDK_DEBUG_DND = 1 << 2, + GDK_DEBUG_COLOR_CONTEXT = 1 << 3, + GDK_DEBUG_XIM = 1 << 4, + GDK_DEBUG_SELECTION = 1 << 5 +} GdkDebugFlag; + +void gdk_events_init (void); +void gdk_window_init (void); +void gdk_visual_init (void); +void gdk_selection_init (void); +void gdk_dnd_init (void); +void gdk_dnd_exit (void); +void gdk_image_init (void); +void gdk_image_exit (void); + +GdkColormap* gdk_colormap_lookup (Colormap xcolormap); +GdkVisual* gdk_visual_lookup (Visual *xvisual); + +void gdk_window_add_colormap_windows (GdkWindow *window); +void gdk_window_destroy_notify (GdkWindow *window); + +void gdk_xid_table_insert (XID *xid, + gpointer data); +void gdk_xid_table_remove (XID xid); +gpointer gdk_xid_table_lookup (XID xid); + +/* Internal functions */ + +HDC gdk_gc_predraw (GdkDrawablePrivate *drawable_private, + GdkGCPrivate *gc_private); +void gdk_gc_postdraw (GdkDrawablePrivate *drawable_private, + GdkGCPrivate *gc_private); +HRGN BitmapToRegion (HBITMAP hBmp); + +void gdk_sel_prop_store (GdkWindow *owner, + GdkAtom type, + gint format, + guchar *data, + gint length); + +void gdk_event_queue_append (GdkEvent *event); + +gint gdk_nmbstowcs (GdkWChar *dest, + const gchar *src, + gint src_len, + gint dest_max); +gint gdk_nmbstowchar_ts (wchar_t *dest, + const gchar *src, + gint src_len, + gint dest_max); + +void gdk_wchar_text_handle (GdkFont *font, + const wchar_t *wcstr, + int wclen, + void (*handler)(GdkWin32SingleFont *, + const wchar_t *, + int, + void *), + void *arg); + +/* Please see gdkwindow.c for comments on how to use */ +HWND gdk_window_xid_at(HWND base, gint bx, gint by, gint x, gint y, GList *excludes, gboolean excl_child); +HWND gdk_window_xid_at_coords(gint x, gint y, GList *excludes, gboolean excl_child); + +extern gint gdk_debug_level; +extern gint gdk_show_events; +extern gint gdk_stack_trace; +extern HWND gdk_root_window; +extern HWND gdk_leader_window; +GDKVAR GdkWindowPrivate *gdk_root_parent; +GDKVAR Atom gdk_selection_property; +GDKVAR gchar *gdk_progclass; +GDKVAR gint gdk_error_code; +GDKVAR gint gdk_error_warnings; +GDKVAR gint gdk_null_window_warnings; +extern gint gdk_event_func_from_window_proc; + +extern HDC gdk_DC; +extern HINSTANCE gdk_DLLInstance; +extern HINSTANCE gdk_ProgInstance; + +extern UINT gdk_selection_notify_msg; +extern UINT gdk_selection_request_msg; +extern UINT gdk_selection_clear_msg; +extern GdkAtom gdk_clipboard_atom; +extern GdkAtom gdk_win32_dropfiles_atom; +extern GdkAtom gdk_ole2_dnd_atom; + +extern LRESULT CALLBACK gdk_WindowProc (HWND, UINT, WPARAM, LPARAM); + +extern DWORD windows_version; + +/* Debugging support */ + +#ifdef G_ENABLE_DEBUG + +#define GDK_NOTE(type,action) G_STMT_START { \ + if (gdk_debug_flags & GDK_DEBUG_##type) \ + { action; }; } G_STMT_END + +#else /* !G_ENABLE_DEBUG */ + +#define GDK_NOTE(type,action) + +#endif /* G_ENABLE_DEBUG */ + +GDKVAR guint gdk_debug_flags; + +/* Internal functions for debug output etc. */ + +char *gdk_color_to_string (GdkColor *); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GDK_PRIVATE_H__ */ diff --git a/gdk/win32/gdkprivate.h b/gdk/win32/gdkprivate.h new file mode 100644 index 000000000..30b276d42 --- /dev/null +++ b/gdk/win32/gdkprivate.h @@ -0,0 +1,459 @@ +/* GDK - The GIMP Drawing Kit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* + * Modified by the GTK+ Team and others 1997-1999. See the AUTHORS + * file for a list of people on the GTK+ Team. See the ChangeLog + * files for a list of changes. These files are distributed with + * GTK+ at ftp://ftp.gtk.org/pub/gtk/. + */ + +#ifndef __GDK_PRIVATE_H__ +#define __GDK_PRIVATE_H__ + +#define STRICT /* We want strict type checks */ +#include +#include + +/* Make up for some minor mingw32 lossage */ + +/* PS_JOIN_MASK is missing from the mingw32 headers */ +#ifndef PS_JOIN_MASK +#define PS_JOIN_MASK (PS_JOIN_BEVEL|PS_JOIN_MITER|PS_JOIN_ROUND) +#endif + +/* CLR_INVALID is missing */ +#ifndef CLR_INVALID +#define CLR_INVALID CLR_NONE +#endif + +/* Some charsets are missing */ +#ifndef JOHAB_CHARSET +#define JOHAB_CHARSET 130 +#endif +#ifndef VIETNAMESE_CHARSET +#define VIETNAMESE_CHARSET 163 +#endif + +#ifndef VM_OEM_PLUS +#define VK_OEM_PLUS 0xBB +#endif + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define GDK_DRAWABLE_TYPE(d) (((GdkDrawablePrivate *)d)->window_type) +#define GDK_IS_WINDOW(d) (GDK_DRAWABLE_TYPE(d) <= GDK_WINDOW_TEMP || \ + GDK_DRAWABLE_TYPE(d) == GDK_WINDOW_FOREIGN) +#define GDK_IS_PIXMAP(d) (GDK_DRAWABLE_TYPE(d) == GDK_DRAWABLE_PIXMAP) +#define GDK_DRAWABLE_DESTROYED(d) (((GdkDrawablePrivate *)d)->destroyed) + +#define gdk_window_lookup(xid) ((GdkWindow*) gdk_xid_table_lookup (xid)) +#define gdk_pixmap_lookup(xid) ((GdkPixmap*) gdk_xid_table_lookup (xid)) + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* Define corresponding Windows types for some X11 types, just for laziness. + */ + +typedef HANDLE XID; +typedef PALETTEENTRY XColor; +typedef HDC GC; +typedef ATOM Atom; +typedef HCURSOR Cursor; +typedef guint VisualID; +typedef DWORD KeySym; +typedef int Status; + +/* Define some of the X11 constants also here, again just for laziness */ + +/* Generic null resource */ +#define None 0 + +/* Error codes */ +#define Success 0 + +/* Grabbing status */ +#define GrabSuccess 0 +#define AlreadyGrabbed 2 + +/* For CreateColormap */ +#define AllocNone 0 +#define AllocAll 1 + +/* Some structs are somewhat useful to emulate internally, just to + keep the code less #ifdefed. */ +typedef struct { + HPALETTE palette; /* Palette handle used when drawing. */ + guint size; /* Number of entries in the palette. */ + gboolean stale; /* 1 if palette needs to be realized, + * otherwise 0. */ + gboolean *in_use; + gboolean rc_palette; /* If RC_PALETTE is on in the RASTERCAPS */ + gulong sizepalette; /* SIZEPALETTE if rc_palette */ +} ColormapStruct, *Colormap; + +typedef struct { + gint map_entries; + guint visualid; + guint bitspixel; +} Visual; + +typedef struct { + Colormap colormap; + unsigned long red_max; + unsigned long red_mult; + unsigned long green_max; + unsigned long green_mult; + unsigned long blue_max; + unsigned long blue_mult; + unsigned long base_pixel; +} XStandardColormap; + +typedef struct _GdkDrawablePrivate GdkDrawablePrivate; +/* typedef struct _GdkDrawablePrivate GdkPixmapPrivate; */ +typedef struct _GdkWindowPrivate GdkWindowPrivate; +typedef struct _GdkImagePrivate GdkImagePrivate; +typedef struct _GdkGCPrivate GdkGCPrivate; +typedef struct _GdkColormapPrivate GdkColormapPrivate; +typedef struct _GdkColorInfo GdkColorInfo; +typedef struct _GdkVisualPrivate GdkVisualPrivate; +typedef struct _GdkFontPrivate GdkFontPrivate; +typedef struct _GdkCursorPrivate GdkCursorPrivate; +typedef struct _GdkEventFilter GdkEventFilter; +typedef struct _GdkClientFilter GdkClientFilter; +typedef struct _GdkRegionPrivate GdkRegionPrivate; + +struct _GdkDrawablePrivate +{ + GdkDrawable drawable; + + guint8 window_type; + guint ref_count; + + guint16 width; + guint16 height; + + HANDLE xwindow; + GdkColormap *colormap; + + guint destroyed : 2; +}; + +struct _GdkWindowPrivate +{ + GdkDrawablePrivate drawable; + + GdkWindow *parent; + gint16 x; + gint16 y; + guint8 resize_count; + guint mapped : 1; + guint guffaw_gravity : 1; + + /* We must keep the event mask here to filter them ourselves */ + gint event_mask; + + /* Values for bg_type */ +#define GDK_WIN32_BG_NORMAL 0 +#define GDK_WIN32_BG_PIXEL 1 +#define GDK_WIN32_BG_PIXMAP 2 +#define GDK_WIN32_BG_PARENT_RELATIVE 3 +#define GDK_WIN32_BG_TRANSPARENT 4 + + /* We draw the background ourselves at WM_ERASEBKGND */ + guchar bg_type; + GdkColor bg_pixel; + GdkPixmap *bg_pixmap; + + HCURSOR xcursor; + + /* Window size hints */ + gint hint_flags; + gint hint_x, hint_y; + gint hint_min_width, hint_min_height; + gint hint_max_width, hint_max_height; + + gint extension_events; + gboolean extension_events_selected; + + GList *filters; + GList *children; + + HKL input_locale; + CHARSETINFO charset_info; +}; + +struct _GdkImagePrivate +{ + GdkImage image; + HBITMAP ximage; + gpointer x_shm_info; + + void (*image_put) (GdkDrawable *window, + GdkGC *gc, + GdkImage *image, + gint xsrc, + gint ysrc, + gint xdest, + gint ydest, + gint width, + gint height); +}; + +struct _GdkGCPrivate +{ + GdkGC gc; + GC xgc; + /* A Windows Device Context (DC) is not equivalent to an X11 + * GC. We can use a DC only in the window for which it was + * allocated, or (in the case of a memory DC) with the bitmap that + * has been selected into it. Thus, we have to release and + * reallocate a DC each time the GdkGC is used to paint into a new + * window or pixmap. We thus keep all the necessary values in the + * GdkGCPrivate struct. + */ + GdkGCValuesMask values_mask; + GdkColor foreground; + GdkColor background; + GdkFont *font; + gint rop2; + GdkFill fill_style; + GdkPixmap *tile; + GdkPixmap *stipple; + HRGN clip_region; + GdkSubwindowMode subwindow_mode; + gint ts_x_origin; + gint ts_y_origin; + gint clip_x_origin; + gint clip_y_origin; + gint graphics_exposures; + gint pen_width; + DWORD pen_style; + HANDLE hwnd; /* If a DC is allocated, for which window + or what bitmap is selected into it */ + int saved_dc; + guint ref_count; +}; + +typedef enum { + GDK_COLOR_WRITEABLE = 1 << 0 +} GdkColorInfoFlags; + +struct _GdkColorInfo +{ + GdkColorInfoFlags flags; + guint ref_count; +}; + +struct _GdkColormapPrivate +{ + GdkColormap colormap; + Colormap xcolormap; + GdkVisual *visual; + gint private_val; + + GHashTable *hash; + GdkColorInfo *info; + time_t last_sync_time; + + guint ref_count; +}; + +struct _GdkVisualPrivate +{ + GdkVisual visual; + Visual *xvisual; +}; + +typedef struct +{ + HFONT xfont; + DWORD charset; + UINT codepage; + CPINFO cpinfo; + FONTSIGNATURE fs; +} GdkWin32SingleFont; + +struct _GdkFontPrivate +{ + GdkFont font; + guint ref_count; + + GSList *fonts; + GSList *names; +}; + +struct _GdkCursorPrivate +{ + GdkCursor cursor; + Cursor xcursor; +}; + +struct _GdkEventFilter { + GdkFilterFunc function; + gpointer data; +}; + +struct _GdkClientFilter { + GdkAtom type; + GdkFilterFunc function; + gpointer data; +}; + +struct _GdkRegionPrivate +{ + GdkRegion region; + HRGN xregion; +}; + +typedef enum { + GDK_DEBUG_MISC = 1 << 0, + GDK_DEBUG_EVENTS = 1 << 1, + GDK_DEBUG_DND = 1 << 2, + GDK_DEBUG_COLOR_CONTEXT = 1 << 3, + GDK_DEBUG_XIM = 1 << 4, + GDK_DEBUG_SELECTION = 1 << 5 +} GdkDebugFlag; + +void gdk_events_init (void); +void gdk_window_init (void); +void gdk_visual_init (void); +void gdk_selection_init (void); +void gdk_dnd_init (void); +void gdk_dnd_exit (void); +void gdk_image_init (void); +void gdk_image_exit (void); + +GdkColormap* gdk_colormap_lookup (Colormap xcolormap); +GdkVisual* gdk_visual_lookup (Visual *xvisual); + +void gdk_window_add_colormap_windows (GdkWindow *window); +void gdk_window_destroy_notify (GdkWindow *window); + +void gdk_xid_table_insert (XID *xid, + gpointer data); +void gdk_xid_table_remove (XID xid); +gpointer gdk_xid_table_lookup (XID xid); + +/* Internal functions */ + +HDC gdk_gc_predraw (GdkDrawablePrivate *drawable_private, + GdkGCPrivate *gc_private); +void gdk_gc_postdraw (GdkDrawablePrivate *drawable_private, + GdkGCPrivate *gc_private); +HRGN BitmapToRegion (HBITMAP hBmp); + +void gdk_sel_prop_store (GdkWindow *owner, + GdkAtom type, + gint format, + guchar *data, + gint length); + +void gdk_event_queue_append (GdkEvent *event); + +gint gdk_nmbstowcs (GdkWChar *dest, + const gchar *src, + gint src_len, + gint dest_max); +gint gdk_nmbstowchar_ts (wchar_t *dest, + const gchar *src, + gint src_len, + gint dest_max); + +void gdk_wchar_text_handle (GdkFont *font, + const wchar_t *wcstr, + int wclen, + void (*handler)(GdkWin32SingleFont *, + const wchar_t *, + int, + void *), + void *arg); + +/* Please see gdkwindow.c for comments on how to use */ +HWND gdk_window_xid_at(HWND base, gint bx, gint by, gint x, gint y, GList *excludes, gboolean excl_child); +HWND gdk_window_xid_at_coords(gint x, gint y, GList *excludes, gboolean excl_child); + +extern gint gdk_debug_level; +extern gint gdk_show_events; +extern gint gdk_stack_trace; +extern HWND gdk_root_window; +extern HWND gdk_leader_window; +GDKVAR GdkWindowPrivate *gdk_root_parent; +GDKVAR Atom gdk_selection_property; +GDKVAR gchar *gdk_progclass; +GDKVAR gint gdk_error_code; +GDKVAR gint gdk_error_warnings; +GDKVAR gint gdk_null_window_warnings; +extern gint gdk_event_func_from_window_proc; + +extern HDC gdk_DC; +extern HINSTANCE gdk_DLLInstance; +extern HINSTANCE gdk_ProgInstance; + +extern UINT gdk_selection_notify_msg; +extern UINT gdk_selection_request_msg; +extern UINT gdk_selection_clear_msg; +extern GdkAtom gdk_clipboard_atom; +extern GdkAtom gdk_win32_dropfiles_atom; +extern GdkAtom gdk_ole2_dnd_atom; + +extern LRESULT CALLBACK gdk_WindowProc (HWND, UINT, WPARAM, LPARAM); + +extern DWORD windows_version; + +/* Debugging support */ + +#ifdef G_ENABLE_DEBUG + +#define GDK_NOTE(type,action) G_STMT_START { \ + if (gdk_debug_flags & GDK_DEBUG_##type) \ + { action; }; } G_STMT_END + +#else /* !G_ENABLE_DEBUG */ + +#define GDK_NOTE(type,action) + +#endif /* G_ENABLE_DEBUG */ + +GDKVAR guint gdk_debug_flags; + +/* Internal functions for debug output etc. */ + +char *gdk_color_to_string (GdkColor *); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GDK_PRIVATE_H__ */ diff --git a/gdk/win32/gdkproperty-win32.c b/gdk/win32/gdkproperty-win32.c new file mode 100644 index 000000000..86ee08722 --- /dev/null +++ b/gdk/win32/gdkproperty-win32.c @@ -0,0 +1,228 @@ +/* GDK - The GIMP Drawing Kit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* + * Modified by the GTK+ Team and others 1997-1999. See the AUTHORS + * file for a list of people on the GTK+ Team. See the ChangeLog + * files for a list of changes. These files are distributed with + * GTK+ at ftp://ftp.gtk.org/pub/gtk/. + */ + +#include "config.h" + +#include + +#include "gdkproperty.h" +#include "gdkselection.h" +#include "gdkprivate.h" +#include "gdkx.h" + +GdkAtom +gdk_atom_intern (const gchar *atom_name, + gint only_if_exists) +{ + GdkAtom retval; + static GHashTable *atom_hash = NULL; + + if (!atom_hash) + atom_hash = g_hash_table_new (g_str_hash, g_str_equal); + + retval = GPOINTER_TO_UINT (g_hash_table_lookup (atom_hash, atom_name)); + if (!retval) + { + if (strcmp (atom_name, "PRIMARY") == 0) + retval = GDK_SELECTION_PRIMARY; + else if (strcmp (atom_name, "SECONDARY") == 0) + retval = GDK_SELECTION_SECONDARY; + else if (strcmp (atom_name, "ATOM") == 0) + retval = GDK_SELECTION_TYPE_ATOM; + else if (strcmp (atom_name, "BITMAP") == 0) + retval = GDK_SELECTION_TYPE_BITMAP; + else if (strcmp (atom_name, "COLORMAP") == 0) + retval = GDK_SELECTION_TYPE_COLORMAP; + else if (strcmp (atom_name, "DRAWABLE") == 0) + retval = GDK_SELECTION_TYPE_DRAWABLE; + else if (strcmp (atom_name, "INTEGER") == 0) + retval = GDK_SELECTION_TYPE_INTEGER; + else if (strcmp (atom_name, "PIXMAP") == 0) + retval = GDK_SELECTION_TYPE_PIXMAP; + else if (strcmp (atom_name, "WINDOW") == 0) + retval = GDK_SELECTION_TYPE_WINDOW; + else if (strcmp (atom_name, "STRING") == 0) + retval = GDK_SELECTION_TYPE_STRING; + else + { + retval = GlobalFindAtom (atom_name); + if (only_if_exists && retval == 0) + retval = 0; + else + retval = GlobalAddAtom (atom_name); + } + g_hash_table_insert (atom_hash, + g_strdup (atom_name), + GUINT_TO_POINTER (retval)); + } + + return retval; +} + +gchar * +gdk_atom_name (GdkAtom atom) +{ + gchar name[256]; + + switch (atom) + { + case GDK_SELECTION_PRIMARY: return g_strdup ("PRIMARY"); + case GDK_SELECTION_SECONDARY: return g_strdup ("SECONDARY"); + case GDK_SELECTION_TYPE_ATOM: return g_strdup ("ATOM"); + case GDK_SELECTION_TYPE_BITMAP: return g_strdup ("BITMAP"); + case GDK_SELECTION_TYPE_COLORMAP: return g_strdup ("COLORMAP"); + case GDK_SELECTION_TYPE_DRAWABLE: return g_strdup ("DRAWABLE"); + case GDK_SELECTION_TYPE_INTEGER: return g_strdup ("INTEGER"); + case GDK_SELECTION_TYPE_PIXMAP: return g_strdup ("PIXMAP"); + case GDK_SELECTION_TYPE_WINDOW: return g_strdup ("WINDOW"); + case GDK_SELECTION_TYPE_STRING: return g_strdup ("STRING"); + } + if (atom < 0xC000) + return g_strdup_printf ("#%x", atom); + else if (GlobalGetAtomName (atom, name, sizeof (name)) == 0) + return NULL; + return g_strdup (name); +} + +gint +gdk_property_get (GdkWindow *window, + GdkAtom property, + GdkAtom type, + gulong offset, + gulong length, + gint pdelete, + GdkAtom *actual_property_type, + gint *actual_format_type, + gint *actual_length, + guchar **data) +{ + g_warning ("gdk_property_get: Not implemented"); + + return FALSE; +} + +void +gdk_property_change (GdkWindow *window, + GdkAtom property, + GdkAtom type, + gint format, + GdkPropMode mode, + guchar *data, + gint nelements) +{ + HGLOBAL hdata; + gint i, length; + gchar *prop_name, *type_name; + guchar *ptr; + + if (GDK_DRAWABLE_DESTROYED (window)) + return; + + GDK_NOTE (SELECTION, + (prop_name = gdk_atom_name (property), + type_name = gdk_atom_name (type), + g_print ("gdk_property_change: %#x %#x (%s) %#x (%s) %s %d*%d bytes %.10s\n", + GDK_DRAWABLE_XID (window), property, prop_name, + type, type_name, + (mode == GDK_PROP_MODE_REPLACE ? "REPLACE" : + (mode == GDK_PROP_MODE_PREPEND ? "PREPEND" : + (mode == GDK_PROP_MODE_APPEND ? "APPEND" : + "???"))), + format, nelements, data), + g_free (prop_name), + g_free (type_name))); + + if (property == gdk_selection_property + && type == GDK_TARGET_STRING + && format == 8 + && mode == GDK_PROP_MODE_REPLACE) + { + length = nelements; + ptr = data; + for (i = 0; i < nelements; i++) + if (*ptr++ == '\n') + length++; +#if 1 + GDK_NOTE (SELECTION, g_print ("...OpenClipboard(%#x)\n", + GDK_DRAWABLE_XID (window))); + if (!OpenClipboard (GDK_DRAWABLE_XID (window))) + { + g_warning ("gdk_property_change: OpenClipboard failed"); + return; + } +#endif + hdata = GlobalAlloc (GMEM_MOVEABLE|GMEM_DDESHARE, length + 1); + ptr = GlobalLock (hdata); + GDK_NOTE (SELECTION, g_print ("...hdata=%#x, ptr=%#x\n", hdata, ptr)); + + for (i = 0; i < nelements; i++) + { + if (*data == '\n') + *ptr++ = '\r'; + *ptr++ = *data++; + } + *ptr++ = '\0'; + GlobalUnlock (hdata); + GDK_NOTE (SELECTION, g_print ("...SetClipboardData(CF_TEXT, %#x)\n", + hdata)); + if (!SetClipboardData(CF_TEXT, hdata)) + g_warning ("gdk_property_change: SetClipboardData failed: %d", + GetLastError ()); +#if 1 + GDK_NOTE (SELECTION, g_print ("...CloseClipboard()\n")); + if (!CloseClipboard ()) + { + g_warning ("gdk_property_change: CloseClipboard failed"); + return; + } +#endif + } + else + g_warning ("gdk_property_change: General case not implemented"); +} + +void +gdk_property_delete (GdkWindow *window, + GdkAtom property) +{ + gchar *prop_name, *type_name; + extern void gdk_selection_property_delete (GdkWindow *); + + if (GDK_DRAWABLE_DESTROYED (window)) + return; + + GDK_NOTE (SELECTION, + (prop_name = gdk_atom_name (property), + g_print ("gdk_property_delete: %#x %#x (%s)\n", + (window ? GDK_DRAWABLE_XID (window) : 0), + property, prop_name), + g_free (prop_name))); + + if (property == gdk_selection_property) + gdk_selection_property_delete (window); + else + g_warning ("gdk_property_delete: General case not implemented"); +} diff --git a/gdk/win32/gdkproperty.c b/gdk/win32/gdkproperty.c new file mode 100644 index 000000000..86ee08722 --- /dev/null +++ b/gdk/win32/gdkproperty.c @@ -0,0 +1,228 @@ +/* GDK - The GIMP Drawing Kit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* + * Modified by the GTK+ Team and others 1997-1999. See the AUTHORS + * file for a list of people on the GTK+ Team. See the ChangeLog + * files for a list of changes. These files are distributed with + * GTK+ at ftp://ftp.gtk.org/pub/gtk/. + */ + +#include "config.h" + +#include + +#include "gdkproperty.h" +#include "gdkselection.h" +#include "gdkprivate.h" +#include "gdkx.h" + +GdkAtom +gdk_atom_intern (const gchar *atom_name, + gint only_if_exists) +{ + GdkAtom retval; + static GHashTable *atom_hash = NULL; + + if (!atom_hash) + atom_hash = g_hash_table_new (g_str_hash, g_str_equal); + + retval = GPOINTER_TO_UINT (g_hash_table_lookup (atom_hash, atom_name)); + if (!retval) + { + if (strcmp (atom_name, "PRIMARY") == 0) + retval = GDK_SELECTION_PRIMARY; + else if (strcmp (atom_name, "SECONDARY") == 0) + retval = GDK_SELECTION_SECONDARY; + else if (strcmp (atom_name, "ATOM") == 0) + retval = GDK_SELECTION_TYPE_ATOM; + else if (strcmp (atom_name, "BITMAP") == 0) + retval = GDK_SELECTION_TYPE_BITMAP; + else if (strcmp (atom_name, "COLORMAP") == 0) + retval = GDK_SELECTION_TYPE_COLORMAP; + else if (strcmp (atom_name, "DRAWABLE") == 0) + retval = GDK_SELECTION_TYPE_DRAWABLE; + else if (strcmp (atom_name, "INTEGER") == 0) + retval = GDK_SELECTION_TYPE_INTEGER; + else if (strcmp (atom_name, "PIXMAP") == 0) + retval = GDK_SELECTION_TYPE_PIXMAP; + else if (strcmp (atom_name, "WINDOW") == 0) + retval = GDK_SELECTION_TYPE_WINDOW; + else if (strcmp (atom_name, "STRING") == 0) + retval = GDK_SELECTION_TYPE_STRING; + else + { + retval = GlobalFindAtom (atom_name); + if (only_if_exists && retval == 0) + retval = 0; + else + retval = GlobalAddAtom (atom_name); + } + g_hash_table_insert (atom_hash, + g_strdup (atom_name), + GUINT_TO_POINTER (retval)); + } + + return retval; +} + +gchar * +gdk_atom_name (GdkAtom atom) +{ + gchar name[256]; + + switch (atom) + { + case GDK_SELECTION_PRIMARY: return g_strdup ("PRIMARY"); + case GDK_SELECTION_SECONDARY: return g_strdup ("SECONDARY"); + case GDK_SELECTION_TYPE_ATOM: return g_strdup ("ATOM"); + case GDK_SELECTION_TYPE_BITMAP: return g_strdup ("BITMAP"); + case GDK_SELECTION_TYPE_COLORMAP: return g_strdup ("COLORMAP"); + case GDK_SELECTION_TYPE_DRAWABLE: return g_strdup ("DRAWABLE"); + case GDK_SELECTION_TYPE_INTEGER: return g_strdup ("INTEGER"); + case GDK_SELECTION_TYPE_PIXMAP: return g_strdup ("PIXMAP"); + case GDK_SELECTION_TYPE_WINDOW: return g_strdup ("WINDOW"); + case GDK_SELECTION_TYPE_STRING: return g_strdup ("STRING"); + } + if (atom < 0xC000) + return g_strdup_printf ("#%x", atom); + else if (GlobalGetAtomName (atom, name, sizeof (name)) == 0) + return NULL; + return g_strdup (name); +} + +gint +gdk_property_get (GdkWindow *window, + GdkAtom property, + GdkAtom type, + gulong offset, + gulong length, + gint pdelete, + GdkAtom *actual_property_type, + gint *actual_format_type, + gint *actual_length, + guchar **data) +{ + g_warning ("gdk_property_get: Not implemented"); + + return FALSE; +} + +void +gdk_property_change (GdkWindow *window, + GdkAtom property, + GdkAtom type, + gint format, + GdkPropMode mode, + guchar *data, + gint nelements) +{ + HGLOBAL hdata; + gint i, length; + gchar *prop_name, *type_name; + guchar *ptr; + + if (GDK_DRAWABLE_DESTROYED (window)) + return; + + GDK_NOTE (SELECTION, + (prop_name = gdk_atom_name (property), + type_name = gdk_atom_name (type), + g_print ("gdk_property_change: %#x %#x (%s) %#x (%s) %s %d*%d bytes %.10s\n", + GDK_DRAWABLE_XID (window), property, prop_name, + type, type_name, + (mode == GDK_PROP_MODE_REPLACE ? "REPLACE" : + (mode == GDK_PROP_MODE_PREPEND ? "PREPEND" : + (mode == GDK_PROP_MODE_APPEND ? "APPEND" : + "???"))), + format, nelements, data), + g_free (prop_name), + g_free (type_name))); + + if (property == gdk_selection_property + && type == GDK_TARGET_STRING + && format == 8 + && mode == GDK_PROP_MODE_REPLACE) + { + length = nelements; + ptr = data; + for (i = 0; i < nelements; i++) + if (*ptr++ == '\n') + length++; +#if 1 + GDK_NOTE (SELECTION, g_print ("...OpenClipboard(%#x)\n", + GDK_DRAWABLE_XID (window))); + if (!OpenClipboard (GDK_DRAWABLE_XID (window))) + { + g_warning ("gdk_property_change: OpenClipboard failed"); + return; + } +#endif + hdata = GlobalAlloc (GMEM_MOVEABLE|GMEM_DDESHARE, length + 1); + ptr = GlobalLock (hdata); + GDK_NOTE (SELECTION, g_print ("...hdata=%#x, ptr=%#x\n", hdata, ptr)); + + for (i = 0; i < nelements; i++) + { + if (*data == '\n') + *ptr++ = '\r'; + *ptr++ = *data++; + } + *ptr++ = '\0'; + GlobalUnlock (hdata); + GDK_NOTE (SELECTION, g_print ("...SetClipboardData(CF_TEXT, %#x)\n", + hdata)); + if (!SetClipboardData(CF_TEXT, hdata)) + g_warning ("gdk_property_change: SetClipboardData failed: %d", + GetLastError ()); +#if 1 + GDK_NOTE (SELECTION, g_print ("...CloseClipboard()\n")); + if (!CloseClipboard ()) + { + g_warning ("gdk_property_change: CloseClipboard failed"); + return; + } +#endif + } + else + g_warning ("gdk_property_change: General case not implemented"); +} + +void +gdk_property_delete (GdkWindow *window, + GdkAtom property) +{ + gchar *prop_name, *type_name; + extern void gdk_selection_property_delete (GdkWindow *); + + if (GDK_DRAWABLE_DESTROYED (window)) + return; + + GDK_NOTE (SELECTION, + (prop_name = gdk_atom_name (property), + g_print ("gdk_property_delete: %#x %#x (%s)\n", + (window ? GDK_DRAWABLE_XID (window) : 0), + property, prop_name), + g_free (prop_name))); + + if (property == gdk_selection_property) + gdk_selection_property_delete (window); + else + g_warning ("gdk_property_delete: General case not implemented"); +} diff --git a/gdk/win32/gdkregion-win32.c b/gdk/win32/gdkregion-win32.c new file mode 100644 index 000000000..7a0acf5fa --- /dev/null +++ b/gdk/win32/gdkregion-win32.c @@ -0,0 +1,367 @@ +/* GDK - The GIMP Drawing Kit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* + * Modified by the GTK+ Team and others 1997-1999. See the AUTHORS + * file for a list of people on the GTK+ Team. See the ChangeLog + * files for a list of changes. These files are distributed with + * GTK+ at ftp://ftp.gtk.org/pub/gtk/. + */ + +#include "config.h" + +#include "gdk.h" +#include "gdkprivate.h" + + +GdkRegion* +gdk_region_new (void) +{ + GdkRegionPrivate *private; + GdkRegion *region; + HRGN xregion; + RECT emptyRect; + + /* Create an empty region */ + SetRectEmpty (&emptyRect); + xregion = CreateRectRgnIndirect (&emptyRect); + private = g_new (GdkRegionPrivate, 1); + private->xregion = xregion; + region = (GdkRegion*) private; + region->user_data = NULL; + + return region; +} + +void +gdk_region_destroy (GdkRegion *region) +{ + GdkRegionPrivate *private; + + g_return_if_fail (region != NULL); + + private = (GdkRegionPrivate *) region; + DeleteObject (private->xregion); + g_free (private); +} + +gboolean +gdk_region_empty (GdkRegion *region) +{ + GdkRegionPrivate *private; + RECT rect; + + g_return_val_if_fail (region != NULL, 0); + + private = (GdkRegionPrivate *) region; + + return (GetRgnBox (private->xregion, &rect) == NULLREGION); +} + +gboolean +gdk_region_equal (GdkRegion *region1, + GdkRegion *region2) +{ + GdkRegionPrivate *private1; + GdkRegionPrivate *private2; + + g_return_val_if_fail (region1 != NULL, 0); + g_return_val_if_fail (region2 != NULL, 0); + + private1 = (GdkRegionPrivate *) region1; + private2 = (GdkRegionPrivate *) region2; + + return EqualRgn (private1->xregion, private2->xregion); +} + +void +gdk_region_get_clipbox(GdkRegion *region, + GdkRectangle *rectangle) +{ + GdkRegionPrivate *rp; + RECT r; + + g_return_if_fail(region != NULL); + g_return_if_fail(rectangle != NULL); + + rp = (GdkRegionPrivate *)region; + + GetRgnBox (rp->xregion, &r); + rectangle->x = r.left; + rectangle->y = r.top; + rectangle->width = r.right - r.left; + rectangle->height = r.bottom - r.top; +} + +gboolean +gdk_region_point_in (GdkRegion *region, + gint x, + gint y) +{ + GdkRegionPrivate *private; + + g_return_val_if_fail (region != NULL, 0); + + private = (GdkRegionPrivate *) region; + + return PtInRegion (private->xregion, x, y); +} + +GdkOverlapType +gdk_region_rect_in (GdkRegion *region, + GdkRectangle *rect) +{ + GdkRegionPrivate *private; + RECT r; + int res; + + g_return_val_if_fail (region != NULL, 0); + + private = (GdkRegionPrivate *) region; + + r.left = rect->x; + r.top = rect->y; + r.right = rect->x + rect->width; + r.bottom = rect->y + rect->height; + + if (RectInRegion (private->xregion, &r)) + return GDK_OVERLAP_RECTANGLE_PART; + + return GDK_OVERLAP_RECTANGLE_OUT; /*what else ? */ +} + +GdkRegion * +gdk_region_polygon (GdkPoint *points, + gint npoints, + GdkFillRule fill_rule) +{ + GdkRegionPrivate *private; + GdkRegion *region; + HRGN xregion; + POINT *pts; + gint xfill_rule = ALTERNATE; + gint i; + + g_return_val_if_fail (points != NULL, NULL); + g_return_val_if_fail (npoints != 0, NULL); /* maybe we should check for at least three points */ + + switch (fill_rule) + { + case GDK_EVEN_ODD_RULE: + xfill_rule = ALTERNATE; + break; + + case GDK_WINDING_RULE: + xfill_rule = WINDING; + break; + } + + pts = g_malloc (npoints * sizeof (*pts)); + for (i = 0; i < npoints; i++) + { + pts[i].x = points[i].x; + pts[i].y = points[i].y; + } + xregion = CreatePolygonRgn (pts, npoints, xfill_rule); + g_free (pts); + + private = g_new (GdkRegionPrivate, 1); + private->xregion = xregion; + region = (GdkRegion *) private; + region->user_data = NULL; + + return region; +} + +void +gdk_region_offset (GdkRegion *region, + gint dx, + gint dy) +{ + GdkRegionPrivate *private; + + g_return_if_fail (region != NULL); + + private = (GdkRegionPrivate *) region; + + OffsetRgn (private->xregion, dx, dy); +} + +void +gdk_region_shrink (GdkRegion *region, + gint dx, + gint dy) +{ + GdkRegionPrivate *private; + HRGN shrunken_bbox; + RECT r; + + g_return_if_fail (region != NULL); + + private = (GdkRegionPrivate *) region; + + if (dx > 0 || dy > 0) + { + /* We want to shrink it in one or both dimensions. + * Is it correct just to intersect it with a smaller bounding box? + * XXX + */ + GetRgnBox (private->xregion, &r); + if (dx > 0) + { + r.left += dx - dx/2; + r.right -= dx/2; + } + if (dy > 0) + { + r.top += dy - dy/2; + r.bottom -= dy/2; + } + + shrunken_bbox = CreateRectRgnIndirect (&r); + CombineRgn (private->xregion, private->xregion, + shrunken_bbox, RGN_AND); + DeleteObject (shrunken_bbox); + } + else + { + /* Do nothing if the regions is expanded? XXX */ + } +} + +GdkRegion* +gdk_region_union_with_rect (GdkRegion *region, + GdkRectangle *rect) +{ + GdkRegionPrivate *private; + GdkRegion *res; + GdkRegionPrivate *res_private; + RECT xrect; + HRGN rectangle; + + g_return_val_if_fail (region != NULL, NULL); + + private = (GdkRegionPrivate *) region; + + xrect.left = rect->x; + xrect.top = rect->y; + xrect.right = rect->x + rect->width; + xrect.bottom = rect->y + rect->height; + + res = gdk_region_new (); + res_private = (GdkRegionPrivate *) res; + + rectangle = CreateRectRgnIndirect (&xrect); + CombineRgn (res_private->xregion, private->xregion, + rectangle, RGN_OR); + DeleteObject (rectangle); + return res; +} + +GdkRegion* +gdk_regions_intersect (GdkRegion *source1, + GdkRegion *source2) +{ + GdkRegionPrivate *private1; + GdkRegionPrivate *private2; + GdkRegion *res; + GdkRegionPrivate *res_private; + + g_return_val_if_fail (source1 != NULL, NULL); + g_return_val_if_fail (source2 != NULL, NULL); + + private1 = (GdkRegionPrivate *) source1; + private2 = (GdkRegionPrivate *) source2; + + res = gdk_region_new (); + res_private = (GdkRegionPrivate *) res; + + CombineRgn (res_private->xregion, private1->xregion, private2->xregion, + RGN_AND); + return res; +} + +GdkRegion* +gdk_regions_union (GdkRegion *source1, + GdkRegion *source2) +{ + GdkRegionPrivate *private1; + GdkRegionPrivate *private2; + GdkRegion *res; + GdkRegionPrivate *res_private; + + g_return_val_if_fail (source1 != NULL, NULL); + g_return_val_if_fail (source2 != NULL, NULL); + + private1 = (GdkRegionPrivate *) source1; + private2 = (GdkRegionPrivate *) source2; + + res = gdk_region_new (); + res_private = (GdkRegionPrivate *) res; + + CombineRgn (res_private->xregion, private1->xregion, private2->xregion, + RGN_OR); + return res; +} + +GdkRegion* +gdk_regions_subtract (GdkRegion *source1, + GdkRegion *source2) +{ + GdkRegionPrivate *private1; + GdkRegionPrivate *private2; + GdkRegion *res; + GdkRegionPrivate *res_private; + + g_return_val_if_fail (source1 != NULL, NULL); + g_return_val_if_fail (source2 != NULL, NULL); + + private1 = (GdkRegionPrivate *) source1; + private2 = (GdkRegionPrivate *) source2; + + res = gdk_region_new (); + res_private = (GdkRegionPrivate *) res; + + CombineRgn (res_private->xregion, private1->xregion, private2->xregion, + RGN_DIFF); + return res; +} + +GdkRegion* +gdk_regions_xor (GdkRegion *source1, + GdkRegion *source2) +{ + GdkRegionPrivate *private1; + GdkRegionPrivate *private2; + GdkRegion *res; + GdkRegionPrivate *res_private; + + g_return_val_if_fail (source1 != NULL, NULL); + g_return_val_if_fail (source2 != NULL, NULL); + + private1 = (GdkRegionPrivate *) source1; + private2 = (GdkRegionPrivate *) source2; + + res = gdk_region_new (); + res_private = (GdkRegionPrivate *) res; + + CombineRgn (res_private->xregion, private1->xregion, private2->xregion, + RGN_XOR); + return res; +} diff --git a/gdk/win32/gdkregion.c b/gdk/win32/gdkregion.c new file mode 100644 index 000000000..7a0acf5fa --- /dev/null +++ b/gdk/win32/gdkregion.c @@ -0,0 +1,367 @@ +/* GDK - The GIMP Drawing Kit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* + * Modified by the GTK+ Team and others 1997-1999. See the AUTHORS + * file for a list of people on the GTK+ Team. See the ChangeLog + * files for a list of changes. These files are distributed with + * GTK+ at ftp://ftp.gtk.org/pub/gtk/. + */ + +#include "config.h" + +#include "gdk.h" +#include "gdkprivate.h" + + +GdkRegion* +gdk_region_new (void) +{ + GdkRegionPrivate *private; + GdkRegion *region; + HRGN xregion; + RECT emptyRect; + + /* Create an empty region */ + SetRectEmpty (&emptyRect); + xregion = CreateRectRgnIndirect (&emptyRect); + private = g_new (GdkRegionPrivate, 1); + private->xregion = xregion; + region = (GdkRegion*) private; + region->user_data = NULL; + + return region; +} + +void +gdk_region_destroy (GdkRegion *region) +{ + GdkRegionPrivate *private; + + g_return_if_fail (region != NULL); + + private = (GdkRegionPrivate *) region; + DeleteObject (private->xregion); + g_free (private); +} + +gboolean +gdk_region_empty (GdkRegion *region) +{ + GdkRegionPrivate *private; + RECT rect; + + g_return_val_if_fail (region != NULL, 0); + + private = (GdkRegionPrivate *) region; + + return (GetRgnBox (private->xregion, &rect) == NULLREGION); +} + +gboolean +gdk_region_equal (GdkRegion *region1, + GdkRegion *region2) +{ + GdkRegionPrivate *private1; + GdkRegionPrivate *private2; + + g_return_val_if_fail (region1 != NULL, 0); + g_return_val_if_fail (region2 != NULL, 0); + + private1 = (GdkRegionPrivate *) region1; + private2 = (GdkRegionPrivate *) region2; + + return EqualRgn (private1->xregion, private2->xregion); +} + +void +gdk_region_get_clipbox(GdkRegion *region, + GdkRectangle *rectangle) +{ + GdkRegionPrivate *rp; + RECT r; + + g_return_if_fail(region != NULL); + g_return_if_fail(rectangle != NULL); + + rp = (GdkRegionPrivate *)region; + + GetRgnBox (rp->xregion, &r); + rectangle->x = r.left; + rectangle->y = r.top; + rectangle->width = r.right - r.left; + rectangle->height = r.bottom - r.top; +} + +gboolean +gdk_region_point_in (GdkRegion *region, + gint x, + gint y) +{ + GdkRegionPrivate *private; + + g_return_val_if_fail (region != NULL, 0); + + private = (GdkRegionPrivate *) region; + + return PtInRegion (private->xregion, x, y); +} + +GdkOverlapType +gdk_region_rect_in (GdkRegion *region, + GdkRectangle *rect) +{ + GdkRegionPrivate *private; + RECT r; + int res; + + g_return_val_if_fail (region != NULL, 0); + + private = (GdkRegionPrivate *) region; + + r.left = rect->x; + r.top = rect->y; + r.right = rect->x + rect->width; + r.bottom = rect->y + rect->height; + + if (RectInRegion (private->xregion, &r)) + return GDK_OVERLAP_RECTANGLE_PART; + + return GDK_OVERLAP_RECTANGLE_OUT; /*what else ? */ +} + +GdkRegion * +gdk_region_polygon (GdkPoint *points, + gint npoints, + GdkFillRule fill_rule) +{ + GdkRegionPrivate *private; + GdkRegion *region; + HRGN xregion; + POINT *pts; + gint xfill_rule = ALTERNATE; + gint i; + + g_return_val_if_fail (points != NULL, NULL); + g_return_val_if_fail (npoints != 0, NULL); /* maybe we should check for at least three points */ + + switch (fill_rule) + { + case GDK_EVEN_ODD_RULE: + xfill_rule = ALTERNATE; + break; + + case GDK_WINDING_RULE: + xfill_rule = WINDING; + break; + } + + pts = g_malloc (npoints * sizeof (*pts)); + for (i = 0; i < npoints; i++) + { + pts[i].x = points[i].x; + pts[i].y = points[i].y; + } + xregion = CreatePolygonRgn (pts, npoints, xfill_rule); + g_free (pts); + + private = g_new (GdkRegionPrivate, 1); + private->xregion = xregion; + region = (GdkRegion *) private; + region->user_data = NULL; + + return region; +} + +void +gdk_region_offset (GdkRegion *region, + gint dx, + gint dy) +{ + GdkRegionPrivate *private; + + g_return_if_fail (region != NULL); + + private = (GdkRegionPrivate *) region; + + OffsetRgn (private->xregion, dx, dy); +} + +void +gdk_region_shrink (GdkRegion *region, + gint dx, + gint dy) +{ + GdkRegionPrivate *private; + HRGN shrunken_bbox; + RECT r; + + g_return_if_fail (region != NULL); + + private = (GdkRegionPrivate *) region; + + if (dx > 0 || dy > 0) + { + /* We want to shrink it in one or both dimensions. + * Is it correct just to intersect it with a smaller bounding box? + * XXX + */ + GetRgnBox (private->xregion, &r); + if (dx > 0) + { + r.left += dx - dx/2; + r.right -= dx/2; + } + if (dy > 0) + { + r.top += dy - dy/2; + r.bottom -= dy/2; + } + + shrunken_bbox = CreateRectRgnIndirect (&r); + CombineRgn (private->xregion, private->xregion, + shrunken_bbox, RGN_AND); + DeleteObject (shrunken_bbox); + } + else + { + /* Do nothing if the regions is expanded? XXX */ + } +} + +GdkRegion* +gdk_region_union_with_rect (GdkRegion *region, + GdkRectangle *rect) +{ + GdkRegionPrivate *private; + GdkRegion *res; + GdkRegionPrivate *res_private; + RECT xrect; + HRGN rectangle; + + g_return_val_if_fail (region != NULL, NULL); + + private = (GdkRegionPrivate *) region; + + xrect.left = rect->x; + xrect.top = rect->y; + xrect.right = rect->x + rect->width; + xrect.bottom = rect->y + rect->height; + + res = gdk_region_new (); + res_private = (GdkRegionPrivate *) res; + + rectangle = CreateRectRgnIndirect (&xrect); + CombineRgn (res_private->xregion, private->xregion, + rectangle, RGN_OR); + DeleteObject (rectangle); + return res; +} + +GdkRegion* +gdk_regions_intersect (GdkRegion *source1, + GdkRegion *source2) +{ + GdkRegionPrivate *private1; + GdkRegionPrivate *private2; + GdkRegion *res; + GdkRegionPrivate *res_private; + + g_return_val_if_fail (source1 != NULL, NULL); + g_return_val_if_fail (source2 != NULL, NULL); + + private1 = (GdkRegionPrivate *) source1; + private2 = (GdkRegionPrivate *) source2; + + res = gdk_region_new (); + res_private = (GdkRegionPrivate *) res; + + CombineRgn (res_private->xregion, private1->xregion, private2->xregion, + RGN_AND); + return res; +} + +GdkRegion* +gdk_regions_union (GdkRegion *source1, + GdkRegion *source2) +{ + GdkRegionPrivate *private1; + GdkRegionPrivate *private2; + GdkRegion *res; + GdkRegionPrivate *res_private; + + g_return_val_if_fail (source1 != NULL, NULL); + g_return_val_if_fail (source2 != NULL, NULL); + + private1 = (GdkRegionPrivate *) source1; + private2 = (GdkRegionPrivate *) source2; + + res = gdk_region_new (); + res_private = (GdkRegionPrivate *) res; + + CombineRgn (res_private->xregion, private1->xregion, private2->xregion, + RGN_OR); + return res; +} + +GdkRegion* +gdk_regions_subtract (GdkRegion *source1, + GdkRegion *source2) +{ + GdkRegionPrivate *private1; + GdkRegionPrivate *private2; + GdkRegion *res; + GdkRegionPrivate *res_private; + + g_return_val_if_fail (source1 != NULL, NULL); + g_return_val_if_fail (source2 != NULL, NULL); + + private1 = (GdkRegionPrivate *) source1; + private2 = (GdkRegionPrivate *) source2; + + res = gdk_region_new (); + res_private = (GdkRegionPrivate *) res; + + CombineRgn (res_private->xregion, private1->xregion, private2->xregion, + RGN_DIFF); + return res; +} + +GdkRegion* +gdk_regions_xor (GdkRegion *source1, + GdkRegion *source2) +{ + GdkRegionPrivate *private1; + GdkRegionPrivate *private2; + GdkRegion *res; + GdkRegionPrivate *res_private; + + g_return_val_if_fail (source1 != NULL, NULL); + g_return_val_if_fail (source2 != NULL, NULL); + + private1 = (GdkRegionPrivate *) source1; + private2 = (GdkRegionPrivate *) source2; + + res = gdk_region_new (); + res_private = (GdkRegionPrivate *) res; + + CombineRgn (res_private->xregion, private1->xregion, private2->xregion, + RGN_XOR); + return res; +} diff --git a/gdk/win32/gdkselection-win32.c b/gdk/win32/gdkselection-win32.c new file mode 100644 index 000000000..033867289 --- /dev/null +++ b/gdk/win32/gdkselection-win32.c @@ -0,0 +1,403 @@ +/* GDK - The GIMP Drawing Kit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* + * Modified by the GTK+ Team and others 1997-1999. See the AUTHORS + * file for a list of people on the GTK+ Team. See the ChangeLog + * files for a list of changes. These files are distributed with + * GTK+ at ftp://ftp.gtk.org/pub/gtk/. + */ + +#include "config.h" + +#include + +#include +#include "gdkx.h" + +/* We emulate the GDK_SELECTION window properties by storing + * it's data in a per-window hashtable. + */ + +typedef struct { + guchar *data; + gint length; + gint format; + GdkAtom type; +} GdkSelProp; + +static GHashTable *sel_prop_table = NULL; + +void +gdk_selection_init (void) +{ + if (sel_prop_table == NULL) + sel_prop_table = g_hash_table_new (g_int_hash, g_int_equal); +} + +void +gdk_sel_prop_store (GdkWindow *owner, + GdkAtom type, + gint format, + guchar *data, + gint length) +{ + GdkSelProp *prop; + + prop = g_hash_table_lookup (sel_prop_table, &GDK_DRAWABLE_XID (owner)); + if (prop != NULL) + { + g_free (prop->data); + g_hash_table_remove (sel_prop_table, &GDK_DRAWABLE_XID (owner)); + } + prop = g_new (GdkSelProp, 1); + prop->data = data; + prop->length = length; + prop->format = format; + prop->type = type; + g_hash_table_insert (sel_prop_table, &GDK_DRAWABLE_XID (owner), prop); +} + +gint +gdk_selection_owner_set (GdkWindow *owner, + GdkAtom selection, + guint32 time, + gint send_event) +{ + gchar *sel_name; + HWND xwindow; + + GDK_NOTE (SELECTION, + (sel_name = gdk_atom_name (selection), + g_print ("gdk_selection_owner_set: %#x %#x (%s)\n", + (owner ? GDK_DRAWABLE_XID (owner) : 0), + selection, sel_name), + g_free (sel_name))); + + if (selection != gdk_clipboard_atom) + return FALSE; + + if (owner != NULL) + xwindow = GDK_DRAWABLE_XID (owner); + else + xwindow = NULL; + + GDK_NOTE (SELECTION, g_print ("...OpenClipboard(%#x)\n", xwindow)); + if (!OpenClipboard (xwindow)) + { + g_warning ("gdk_selection_owner_set: OpenClipboard failed"); + return FALSE; + } + GDK_NOTE (SELECTION, g_print ("...EmptyClipboard()\n")); + if (!EmptyClipboard ()) + { + g_warning ("gdk_selection_owner_set: EmptyClipboard failed"); + CloseClipboard (); + return FALSE; + } +#if 0 + /* No delayed rendering */ + if (xwindow != NULL) + SetClipboardData (CF_TEXT, NULL); +#endif + GDK_NOTE (SELECTION, g_print ("...CloseClipboard()\n")); + if (!CloseClipboard ()) + { + g_warning ("gdk_selection_owner_set: CloseClipboard failed"); + return FALSE; + } + if (owner != NULL) + { + /* Send ourselves an ersatz selection request message so that + * gdk_property_change will be called to store the clipboard data. + */ + SendMessage (xwindow, gdk_selection_request_msg, + selection, 0); + } + + return TRUE; +} + +GdkWindow* +gdk_selection_owner_get (GdkAtom selection) +{ + GdkWindow *window; + gchar *sel_name; + +#if 1 + /* XXX Hmm, gtk selections seem to work best with this. This causes + * gtk to always get the clipboard contents from Windows, and not + * from the editable's own stashed-away copy. + */ + return NULL; +#else + if (selection != gdk_clipboard_atom) + window = NULL; + else + window = gdk_window_lookup (GetClipboardOwner ()); + +#endif + + GDK_NOTE (SELECTION, + (sel_name = gdk_atom_name (selection), + g_print ("gdk_selection_owner_get: %#x (%s) = %#x\n", + selection, sel_name, + (window ? GDK_DRAWABLE_XID (window) : 0)), + g_free (sel_name))); + + return window; +} + +void +gdk_selection_convert (GdkWindow *requestor, + GdkAtom selection, + GdkAtom target, + guint32 time) +{ + HGLOBAL hdata; + GdkSelProp *prop; + guchar *ptr, *data, *datap, *p; + guint i, length, slength; + gchar *sel_name, *tgt_name; + + g_return_if_fail (requestor != NULL); + if (GDK_DRAWABLE_DESTROYED (requestor)) + return; + + GDK_NOTE (SELECTION, + (sel_name = gdk_atom_name (selection), + tgt_name = gdk_atom_name (target), + g_print ("gdk_selection_convert: %#x %#x (%s) %#x (%s)\n", + GDK_DRAWABLE_XID (requestor), selection, sel_name, target, tgt_name), + g_free (sel_name), + g_free (tgt_name))); + + if (selection == gdk_clipboard_atom) + { + /* Converting the CLIPBOARD selection means he wants the + * contents of the clipboard. Get the clipboard data, + * and store it for later. + */ + GDK_NOTE (SELECTION, g_print ("...OpenClipboard(%#x)\n", + GDK_DRAWABLE_XID (requestor))); + if (!OpenClipboard (GDK_DRAWABLE_XID (requestor))) + { + g_warning ("gdk_selection_convert: OpenClipboard failed"); + return; + } + + GDK_NOTE (SELECTION, g_print ("...GetClipboardData(CF_TEXT)\n")); + if ((hdata = GetClipboardData (CF_TEXT)) != NULL) + { + if ((ptr = GlobalLock (hdata)) != NULL) + { + length = GlobalSize (hdata); + + GDK_NOTE (SELECTION, g_print ("...got data: %d bytes: %.10s\n", + length, ptr)); + + slength = 0; + p = ptr; + for (i = 0; i < length; i++) + { + if (*p == '\0') + break; + else if (*p != '\r') + slength++; + p++; + } + + data = datap = g_malloc (slength + 1); + p = ptr; + for (i = 0; i < length; i++) + { + if (*p == '\0') + break; + else if (*p != '\r') + *datap++ = *p; + p++; + } + *datap++ = '\0'; + gdk_sel_prop_store (requestor, GDK_TARGET_STRING, 8, + data, strlen (data) + 1); + + GlobalUnlock (hdata); + } + } + GDK_NOTE (SELECTION, g_print ("...CloseClipboard()\n")); + CloseClipboard (); + + + /* Send ourselves an ersatz selection notify message so that we actually + * fetch the data. + */ + SendMessage (GDK_DRAWABLE_XID (requestor), gdk_selection_notify_msg, selection, target); + } + else if (selection == gdk_win32_dropfiles_atom) + { + /* This means he wants the names of the dropped files. + * gdk_dropfiles_filter already has stored the text/uri-list + * data, tempoarily on gdk_root_parent's selection "property". + */ + GdkSelProp *prop; + + prop = g_hash_table_lookup (sel_prop_table, &gdk_root_parent->drawable.xwindow); + + if (prop != NULL) + { + g_hash_table_remove (sel_prop_table, &gdk_root_parent->drawable.xwindow); + gdk_sel_prop_store (requestor, prop->type, prop->format, + prop->data, prop->length); + g_free (prop); + SendMessage (GDK_DRAWABLE_XID (requestor), gdk_selection_notify_msg, selection, target); + } + } + else + { + g_warning ("gdk_selection_convert: General case not implemented"); + } +} + +gint +gdk_selection_property_get (GdkWindow *requestor, + guchar **data, + GdkAtom *ret_type, + gint *ret_format) +{ + GdkSelProp *prop; + + g_return_val_if_fail (requestor != NULL, 0); + g_return_val_if_fail (GDK_IS_WINDOW (requestor), 0); + + if (GDK_DRAWABLE_DESTROYED (requestor)) + return 0; + + GDK_NOTE (SELECTION, g_print ("gdk_selection_property_get: %#x\n", + GDK_DRAWABLE_XID (requestor))); + + prop = g_hash_table_lookup (sel_prop_table, &GDK_DRAWABLE_XID (requestor)); + + if (prop == NULL) + { + *data = NULL; + return 0; + } + *data = g_malloc (prop->length); + if (prop->length > 0) + memmove (*data, prop->data, prop->length); + if (ret_type) + *ret_type = prop->type; + if (ret_format) + *ret_format = prop->format; + + return prop->length; +} + +void +gdk_selection_property_delete (GdkWindow *window) +{ + GdkSelProp *prop; + + prop = g_hash_table_lookup (sel_prop_table, &GDK_DRAWABLE_XID (window)); + if (prop != NULL) + { + g_free (prop->data); + g_hash_table_remove (sel_prop_table, &GDK_DRAWABLE_XID (window)); + } + else + g_warning ("huh?"); +} + +void +gdk_selection_send_notify (guint32 requestor, + GdkAtom selection, + GdkAtom target, + GdkAtom property, + guint32 time) +{ + gchar *sel_name, *tgt_name, *prop_name; + + GDK_NOTE (SELECTION, + (sel_name = gdk_atom_name (selection), + tgt_name = gdk_atom_name (target), + prop_name = gdk_atom_name (property), + g_print ("gdk_selection_send_notify: %#x %#x (%s) %#x (%s) %#x (%s)\n", + requestor, + selection, sel_name, + target, tgt_name, + property, prop_name), + g_free (sel_name), + g_free (tgt_name), + g_free (prop_name))); + + /* Send ourselves a selection clear message so that gtk thinks we don't + * have the selection, and will claim it anew when needed, and + * we thus get a chance to store data in the Windows clipboard. + * Otherwise, if a gtkeditable does a copy to clipboard several times + * only the first one actually gets copied to the Windows clipboard, + * as only he first one causes a call to gdk_property_change. + * + * Hmm, there is something fishy with this. Cut and paste inside the + * same app didn't work, the gtkeditable immediately forgot the + * clipboard contents in gtk_editable_selection_clear as a result of + * this message. OTOH, when I changed gdk_selection_owner_get to + * always return NULL, it works. Sigh. + */ + + SendMessage ((HWND) requestor, gdk_selection_clear_msg, selection, 0); +} + +gint +gdk_text_property_to_text_list (GdkAtom encoding, + gint format, + guchar *text, + gint length, + gchar ***list) +{ + GDK_NOTE (SELECTION, + g_print ("gdk_text_property_to_text_list not implemented\n")); + + return 0; +} + +void +gdk_free_text_list (gchar **list) +{ + g_return_if_fail (list != NULL); + + /* ??? */ +} + +gint +gdk_string_to_compound_text (gchar *str, + GdkAtom *encoding, + gint *format, + guchar **ctext, + gint *length) +{ + g_warning ("gdk_string_to_compound_text: Not implemented"); + + return 0; +} + +void +gdk_free_compound_text (guchar *ctext) +{ + g_warning ("gdk_free_compound_text: Not implemented"); +} diff --git a/gdk/win32/gdkselection.c b/gdk/win32/gdkselection.c new file mode 100644 index 000000000..033867289 --- /dev/null +++ b/gdk/win32/gdkselection.c @@ -0,0 +1,403 @@ +/* GDK - The GIMP Drawing Kit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* + * Modified by the GTK+ Team and others 1997-1999. See the AUTHORS + * file for a list of people on the GTK+ Team. See the ChangeLog + * files for a list of changes. These files are distributed with + * GTK+ at ftp://ftp.gtk.org/pub/gtk/. + */ + +#include "config.h" + +#include + +#include +#include "gdkx.h" + +/* We emulate the GDK_SELECTION window properties by storing + * it's data in a per-window hashtable. + */ + +typedef struct { + guchar *data; + gint length; + gint format; + GdkAtom type; +} GdkSelProp; + +static GHashTable *sel_prop_table = NULL; + +void +gdk_selection_init (void) +{ + if (sel_prop_table == NULL) + sel_prop_table = g_hash_table_new (g_int_hash, g_int_equal); +} + +void +gdk_sel_prop_store (GdkWindow *owner, + GdkAtom type, + gint format, + guchar *data, + gint length) +{ + GdkSelProp *prop; + + prop = g_hash_table_lookup (sel_prop_table, &GDK_DRAWABLE_XID (owner)); + if (prop != NULL) + { + g_free (prop->data); + g_hash_table_remove (sel_prop_table, &GDK_DRAWABLE_XID (owner)); + } + prop = g_new (GdkSelProp, 1); + prop->data = data; + prop->length = length; + prop->format = format; + prop->type = type; + g_hash_table_insert (sel_prop_table, &GDK_DRAWABLE_XID (owner), prop); +} + +gint +gdk_selection_owner_set (GdkWindow *owner, + GdkAtom selection, + guint32 time, + gint send_event) +{ + gchar *sel_name; + HWND xwindow; + + GDK_NOTE (SELECTION, + (sel_name = gdk_atom_name (selection), + g_print ("gdk_selection_owner_set: %#x %#x (%s)\n", + (owner ? GDK_DRAWABLE_XID (owner) : 0), + selection, sel_name), + g_free (sel_name))); + + if (selection != gdk_clipboard_atom) + return FALSE; + + if (owner != NULL) + xwindow = GDK_DRAWABLE_XID (owner); + else + xwindow = NULL; + + GDK_NOTE (SELECTION, g_print ("...OpenClipboard(%#x)\n", xwindow)); + if (!OpenClipboard (xwindow)) + { + g_warning ("gdk_selection_owner_set: OpenClipboard failed"); + return FALSE; + } + GDK_NOTE (SELECTION, g_print ("...EmptyClipboard()\n")); + if (!EmptyClipboard ()) + { + g_warning ("gdk_selection_owner_set: EmptyClipboard failed"); + CloseClipboard (); + return FALSE; + } +#if 0 + /* No delayed rendering */ + if (xwindow != NULL) + SetClipboardData (CF_TEXT, NULL); +#endif + GDK_NOTE (SELECTION, g_print ("...CloseClipboard()\n")); + if (!CloseClipboard ()) + { + g_warning ("gdk_selection_owner_set: CloseClipboard failed"); + return FALSE; + } + if (owner != NULL) + { + /* Send ourselves an ersatz selection request message so that + * gdk_property_change will be called to store the clipboard data. + */ + SendMessage (xwindow, gdk_selection_request_msg, + selection, 0); + } + + return TRUE; +} + +GdkWindow* +gdk_selection_owner_get (GdkAtom selection) +{ + GdkWindow *window; + gchar *sel_name; + +#if 1 + /* XXX Hmm, gtk selections seem to work best with this. This causes + * gtk to always get the clipboard contents from Windows, and not + * from the editable's own stashed-away copy. + */ + return NULL; +#else + if (selection != gdk_clipboard_atom) + window = NULL; + else + window = gdk_window_lookup (GetClipboardOwner ()); + +#endif + + GDK_NOTE (SELECTION, + (sel_name = gdk_atom_name (selection), + g_print ("gdk_selection_owner_get: %#x (%s) = %#x\n", + selection, sel_name, + (window ? GDK_DRAWABLE_XID (window) : 0)), + g_free (sel_name))); + + return window; +} + +void +gdk_selection_convert (GdkWindow *requestor, + GdkAtom selection, + GdkAtom target, + guint32 time) +{ + HGLOBAL hdata; + GdkSelProp *prop; + guchar *ptr, *data, *datap, *p; + guint i, length, slength; + gchar *sel_name, *tgt_name; + + g_return_if_fail (requestor != NULL); + if (GDK_DRAWABLE_DESTROYED (requestor)) + return; + + GDK_NOTE (SELECTION, + (sel_name = gdk_atom_name (selection), + tgt_name = gdk_atom_name (target), + g_print ("gdk_selection_convert: %#x %#x (%s) %#x (%s)\n", + GDK_DRAWABLE_XID (requestor), selection, sel_name, target, tgt_name), + g_free (sel_name), + g_free (tgt_name))); + + if (selection == gdk_clipboard_atom) + { + /* Converting the CLIPBOARD selection means he wants the + * contents of the clipboard. Get the clipboard data, + * and store it for later. + */ + GDK_NOTE (SELECTION, g_print ("...OpenClipboard(%#x)\n", + GDK_DRAWABLE_XID (requestor))); + if (!OpenClipboard (GDK_DRAWABLE_XID (requestor))) + { + g_warning ("gdk_selection_convert: OpenClipboard failed"); + return; + } + + GDK_NOTE (SELECTION, g_print ("...GetClipboardData(CF_TEXT)\n")); + if ((hdata = GetClipboardData (CF_TEXT)) != NULL) + { + if ((ptr = GlobalLock (hdata)) != NULL) + { + length = GlobalSize (hdata); + + GDK_NOTE (SELECTION, g_print ("...got data: %d bytes: %.10s\n", + length, ptr)); + + slength = 0; + p = ptr; + for (i = 0; i < length; i++) + { + if (*p == '\0') + break; + else if (*p != '\r') + slength++; + p++; + } + + data = datap = g_malloc (slength + 1); + p = ptr; + for (i = 0; i < length; i++) + { + if (*p == '\0') + break; + else if (*p != '\r') + *datap++ = *p; + p++; + } + *datap++ = '\0'; + gdk_sel_prop_store (requestor, GDK_TARGET_STRING, 8, + data, strlen (data) + 1); + + GlobalUnlock (hdata); + } + } + GDK_NOTE (SELECTION, g_print ("...CloseClipboard()\n")); + CloseClipboard (); + + + /* Send ourselves an ersatz selection notify message so that we actually + * fetch the data. + */ + SendMessage (GDK_DRAWABLE_XID (requestor), gdk_selection_notify_msg, selection, target); + } + else if (selection == gdk_win32_dropfiles_atom) + { + /* This means he wants the names of the dropped files. + * gdk_dropfiles_filter already has stored the text/uri-list + * data, tempoarily on gdk_root_parent's selection "property". + */ + GdkSelProp *prop; + + prop = g_hash_table_lookup (sel_prop_table, &gdk_root_parent->drawable.xwindow); + + if (prop != NULL) + { + g_hash_table_remove (sel_prop_table, &gdk_root_parent->drawable.xwindow); + gdk_sel_prop_store (requestor, prop->type, prop->format, + prop->data, prop->length); + g_free (prop); + SendMessage (GDK_DRAWABLE_XID (requestor), gdk_selection_notify_msg, selection, target); + } + } + else + { + g_warning ("gdk_selection_convert: General case not implemented"); + } +} + +gint +gdk_selection_property_get (GdkWindow *requestor, + guchar **data, + GdkAtom *ret_type, + gint *ret_format) +{ + GdkSelProp *prop; + + g_return_val_if_fail (requestor != NULL, 0); + g_return_val_if_fail (GDK_IS_WINDOW (requestor), 0); + + if (GDK_DRAWABLE_DESTROYED (requestor)) + return 0; + + GDK_NOTE (SELECTION, g_print ("gdk_selection_property_get: %#x\n", + GDK_DRAWABLE_XID (requestor))); + + prop = g_hash_table_lookup (sel_prop_table, &GDK_DRAWABLE_XID (requestor)); + + if (prop == NULL) + { + *data = NULL; + return 0; + } + *data = g_malloc (prop->length); + if (prop->length > 0) + memmove (*data, prop->data, prop->length); + if (ret_type) + *ret_type = prop->type; + if (ret_format) + *ret_format = prop->format; + + return prop->length; +} + +void +gdk_selection_property_delete (GdkWindow *window) +{ + GdkSelProp *prop; + + prop = g_hash_table_lookup (sel_prop_table, &GDK_DRAWABLE_XID (window)); + if (prop != NULL) + { + g_free (prop->data); + g_hash_table_remove (sel_prop_table, &GDK_DRAWABLE_XID (window)); + } + else + g_warning ("huh?"); +} + +void +gdk_selection_send_notify (guint32 requestor, + GdkAtom selection, + GdkAtom target, + GdkAtom property, + guint32 time) +{ + gchar *sel_name, *tgt_name, *prop_name; + + GDK_NOTE (SELECTION, + (sel_name = gdk_atom_name (selection), + tgt_name = gdk_atom_name (target), + prop_name = gdk_atom_name (property), + g_print ("gdk_selection_send_notify: %#x %#x (%s) %#x (%s) %#x (%s)\n", + requestor, + selection, sel_name, + target, tgt_name, + property, prop_name), + g_free (sel_name), + g_free (tgt_name), + g_free (prop_name))); + + /* Send ourselves a selection clear message so that gtk thinks we don't + * have the selection, and will claim it anew when needed, and + * we thus get a chance to store data in the Windows clipboard. + * Otherwise, if a gtkeditable does a copy to clipboard several times + * only the first one actually gets copied to the Windows clipboard, + * as only he first one causes a call to gdk_property_change. + * + * Hmm, there is something fishy with this. Cut and paste inside the + * same app didn't work, the gtkeditable immediately forgot the + * clipboard contents in gtk_editable_selection_clear as a result of + * this message. OTOH, when I changed gdk_selection_owner_get to + * always return NULL, it works. Sigh. + */ + + SendMessage ((HWND) requestor, gdk_selection_clear_msg, selection, 0); +} + +gint +gdk_text_property_to_text_list (GdkAtom encoding, + gint format, + guchar *text, + gint length, + gchar ***list) +{ + GDK_NOTE (SELECTION, + g_print ("gdk_text_property_to_text_list not implemented\n")); + + return 0; +} + +void +gdk_free_text_list (gchar **list) +{ + g_return_if_fail (list != NULL); + + /* ??? */ +} + +gint +gdk_string_to_compound_text (gchar *str, + GdkAtom *encoding, + gint *format, + guchar **ctext, + gint *length) +{ + g_warning ("gdk_string_to_compound_text: Not implemented"); + + return 0; +} + +void +gdk_free_compound_text (guchar *ctext) +{ + g_warning ("gdk_free_compound_text: Not implemented"); +} diff --git a/gdk/win32/gdkvisual-win32.c b/gdk/win32/gdkvisual-win32.c new file mode 100644 index 000000000..635c51551 --- /dev/null +++ b/gdk/win32/gdkvisual-win32.c @@ -0,0 +1,346 @@ +/* GDK - The GIMP Drawing Kit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* + * Modified by the GTK+ Team and others 1997-1999. See the AUTHORS + * file for a list of people on the GTK+ Team. See the ChangeLog + * files for a list of changes. These files are distributed with + * GTK+ at ftp://ftp.gtk.org/pub/gtk/. + */ + +#include "config.h" + +#include "gdkvisual.h" +#include "gdkprivate.h" + +static void gdk_visual_decompose_mask (gulong mask, + gint *shift, + gint *prec); + +static GdkVisualPrivate *system_visual; + +static gint available_depths[1]; + +static GdkVisualType available_types[1]; + +#ifdef G_ENABLE_DEBUG + +static const gchar* visual_names[] = +{ + "static gray", + "grayscale", + "static color", + "pseudo color", + "true color", + "direct color", +}; + +#endif /* G_ENABLE_DEBUG */ + +void +gdk_visual_init (void) +{ + struct + { + BITMAPINFOHEADER bi; + union + { + RGBQUAD colors[256]; + DWORD fields[256]; + } u; + } bmi; + HBITMAP hbm; + + int rastercaps, numcolors, sizepalette, bitspixel; + + system_visual = g_new (GdkVisualPrivate, 1); + + bitspixel = GetDeviceCaps (gdk_DC, BITSPIXEL); + rastercaps = GetDeviceCaps (gdk_DC, RASTERCAPS); + system_visual->xvisual = g_new (Visual, 1); + system_visual->xvisual->visualid = 0; + system_visual->xvisual->bitspixel = bitspixel; + + if (rastercaps & RC_PALETTE) + { + system_visual->visual.type = GDK_VISUAL_PSEUDO_COLOR; + numcolors = GetDeviceCaps (gdk_DC, NUMCOLORS); + sizepalette = GetDeviceCaps (gdk_DC, SIZEPALETTE); + system_visual->xvisual->map_entries = sizepalette; + } + else if (bitspixel == 1) + { + system_visual->visual.type = GDK_VISUAL_STATIC_GRAY; + system_visual->xvisual->map_entries = 2; + } + else if (bitspixel == 4) + { + system_visual->visual.type = GDK_VISUAL_STATIC_COLOR; + system_visual->xvisual->map_entries = 16; + } + else if (bitspixel == 8) + { + system_visual->visual.type = GDK_VISUAL_STATIC_COLOR; + system_visual->xvisual->map_entries = 256; + } + else if (bitspixel == 16) + { + system_visual->visual.type = GDK_VISUAL_TRUE_COLOR; +#if 1 + /* This code by Mike Enright, + * see http://www.users.cts.com/sd/m/menright/display.html + */ + memset (&bmi, 0, sizeof (bmi)); + bmi.bi.biSize = sizeof (bmi.bi); + + hbm = CreateCompatibleBitmap (gdk_DC, 1, 1); + GetDIBits (gdk_DC, hbm, 0, 1, NULL, + (BITMAPINFO *) &bmi, DIB_RGB_COLORS); + GetDIBits (gdk_DC, hbm, 0, 1, NULL, + (BITMAPINFO *) &bmi, DIB_RGB_COLORS); + DeleteObject (hbm); + + if (bmi.bi.biCompression != BI_BITFIELDS) + { + /* Either BI_RGB or BI_RLE_something + * .... or perhaps (!!) something else. + * Theoretically biCompression might be + * mmioFourCC('c','v','i','d') but I doubt it. + */ + if (bmi.bi.biCompression == BI_RGB) + { + /* It's 555 */ + bitspixel = 15; + system_visual->visual.red_mask = 0x00007C00; + system_visual->visual.green_mask = 0x000003E0; + system_visual->visual.blue_mask = 0x0000001F; + } + else + { + g_assert_not_reached (); + } + } + else + { + DWORD allmasks = + bmi.u.fields[0] | bmi.u.fields[1] | bmi.u.fields[2]; + int k = 0; + while (allmasks) + { + if (allmasks&1) + k++; + allmasks/=2; + } + bitspixel = k; + system_visual->visual.red_mask = bmi.u.fields[0]; + system_visual->visual.green_mask = bmi.u.fields[1]; + system_visual->visual.blue_mask = bmi.u.fields[2]; + } +#else + /* Old, incorrect (but still working) code. */ +#if 0 + system_visual->visual.red_mask = 0x0000F800; + system_visual->visual.green_mask = 0x000007E0; + system_visual->visual.blue_mask = 0x0000001F; +#else + system_visual->visual.red_mask = 0x00007C00; + system_visual->visual.green_mask = 0x000003E0; + system_visual->visual.blue_mask = 0x0000001F; +#endif +#endif + } + else if (bitspixel == 24 || bitspixel == 32) + { + bitspixel = 24; + system_visual->visual.type = GDK_VISUAL_TRUE_COLOR; + system_visual->visual.red_mask = 0x00FF0000; + system_visual->visual.green_mask = 0x0000FF00; + system_visual->visual.blue_mask = 0x000000FF; + } + else + g_error ("gdk_visual_init: unsupported BITSPIXEL: %d\n", bitspixel); + + system_visual->visual.depth = bitspixel; + system_visual->visual.byte_order = GDK_LSB_FIRST; + system_visual->visual.bits_per_rgb = 42; /* Not used? */ + + if ((system_visual->visual.type == GDK_VISUAL_TRUE_COLOR) || + (system_visual->visual.type == GDK_VISUAL_DIRECT_COLOR)) + { + gdk_visual_decompose_mask (system_visual->visual.red_mask, + &system_visual->visual.red_shift, + &system_visual->visual.red_prec); + + gdk_visual_decompose_mask (system_visual->visual.green_mask, + &system_visual->visual.green_shift, + &system_visual->visual.green_prec); + + gdk_visual_decompose_mask (system_visual->visual.blue_mask, + &system_visual->visual.blue_shift, + &system_visual->visual.blue_prec); + system_visual->xvisual->map_entries = + 1 << (MAX (system_visual->visual.red_prec, + MAX (system_visual->visual.green_prec, + system_visual->visual.blue_prec))); + } + else + { + system_visual->visual.red_mask = 0; + system_visual->visual.red_shift = 0; + system_visual->visual.red_prec = 0; + + system_visual->visual.green_mask = 0; + system_visual->visual.green_shift = 0; + system_visual->visual.green_prec = 0; + + system_visual->visual.blue_mask = 0; + system_visual->visual.blue_shift = 0; + system_visual->visual.blue_prec = 0; + } + system_visual->visual.colormap_size = system_visual->xvisual->map_entries; + + available_depths[0] = system_visual->visual.depth; + available_types[0] = system_visual->visual.type; +} + +GdkVisual* +gdk_visual_ref (GdkVisual *visual) +{ + return visual; +} + +void +gdk_visual_unref (GdkVisual *visual) +{ + return; +} + +gint +gdk_visual_get_best_depth (void) +{ + return available_depths[0]; +} + +GdkVisualType +gdk_visual_get_best_type (void) +{ + return available_types[0]; +} + +GdkVisual* +gdk_visual_get_system (void) +{ + return ((GdkVisual*) system_visual); +} + +GdkVisual* +gdk_visual_get_best (void) +{ + return ((GdkVisual*) system_visual); +} + +GdkVisual* +gdk_visual_get_best_with_depth (gint depth) +{ + if (depth == system_visual->visual.depth) + return (GdkVisual*) system_visual; + else + return NULL; +} + +GdkVisual* +gdk_visual_get_best_with_type (GdkVisualType visual_type) +{ + if (visual_type == system_visual->visual.type) + return (GdkVisual*) system_visual; + else + return NULL; +} + +GdkVisual* +gdk_visual_get_best_with_both (gint depth, + GdkVisualType visual_type) +{ + if ((depth == system_visual->visual.depth) && + (visual_type == system_visual->visual.type)) + return (GdkVisual*) system_visual; + else + return NULL; +} + +void +gdk_query_depths (gint **depths, + gint *count) +{ + *count = 1; + *depths = available_depths; +} + +void +gdk_query_visual_types (GdkVisualType **visual_types, + gint *count) +{ + *count = 1; + *visual_types = available_types; +} + +GList* +gdk_list_visuals (void) +{ + return g_list_append (NULL, (gpointer) system_visual); +} + +GdkVisual* +gdk_visual_lookup (Visual *xvisual) +{ + if (system_visual->xvisual == xvisual) + return (GdkVisual *) system_visual; + else + return NULL; +} + +GdkVisual* +gdkx_visual_get (VisualID xvisualid) +{ + if (xvisualid == system_visual->xvisual->visualid) + return (GdkVisual*) system_visual; + else + return NULL; +} + +static void +gdk_visual_decompose_mask (gulong mask, + gint *shift, + gint *prec) +{ + *shift = 0; + *prec = 0; + + while (!(mask & 0x1)) + { + (*shift)++; + mask >>= 1; + } + + while (mask & 0x1) + { + (*prec)++; + mask >>= 1; + } +} diff --git a/gdk/win32/gdkvisual.c b/gdk/win32/gdkvisual.c new file mode 100644 index 000000000..635c51551 --- /dev/null +++ b/gdk/win32/gdkvisual.c @@ -0,0 +1,346 @@ +/* GDK - The GIMP Drawing Kit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* + * Modified by the GTK+ Team and others 1997-1999. See the AUTHORS + * file for a list of people on the GTK+ Team. See the ChangeLog + * files for a list of changes. These files are distributed with + * GTK+ at ftp://ftp.gtk.org/pub/gtk/. + */ + +#include "config.h" + +#include "gdkvisual.h" +#include "gdkprivate.h" + +static void gdk_visual_decompose_mask (gulong mask, + gint *shift, + gint *prec); + +static GdkVisualPrivate *system_visual; + +static gint available_depths[1]; + +static GdkVisualType available_types[1]; + +#ifdef G_ENABLE_DEBUG + +static const gchar* visual_names[] = +{ + "static gray", + "grayscale", + "static color", + "pseudo color", + "true color", + "direct color", +}; + +#endif /* G_ENABLE_DEBUG */ + +void +gdk_visual_init (void) +{ + struct + { + BITMAPINFOHEADER bi; + union + { + RGBQUAD colors[256]; + DWORD fields[256]; + } u; + } bmi; + HBITMAP hbm; + + int rastercaps, numcolors, sizepalette, bitspixel; + + system_visual = g_new (GdkVisualPrivate, 1); + + bitspixel = GetDeviceCaps (gdk_DC, BITSPIXEL); + rastercaps = GetDeviceCaps (gdk_DC, RASTERCAPS); + system_visual->xvisual = g_new (Visual, 1); + system_visual->xvisual->visualid = 0; + system_visual->xvisual->bitspixel = bitspixel; + + if (rastercaps & RC_PALETTE) + { + system_visual->visual.type = GDK_VISUAL_PSEUDO_COLOR; + numcolors = GetDeviceCaps (gdk_DC, NUMCOLORS); + sizepalette = GetDeviceCaps (gdk_DC, SIZEPALETTE); + system_visual->xvisual->map_entries = sizepalette; + } + else if (bitspixel == 1) + { + system_visual->visual.type = GDK_VISUAL_STATIC_GRAY; + system_visual->xvisual->map_entries = 2; + } + else if (bitspixel == 4) + { + system_visual->visual.type = GDK_VISUAL_STATIC_COLOR; + system_visual->xvisual->map_entries = 16; + } + else if (bitspixel == 8) + { + system_visual->visual.type = GDK_VISUAL_STATIC_COLOR; + system_visual->xvisual->map_entries = 256; + } + else if (bitspixel == 16) + { + system_visual->visual.type = GDK_VISUAL_TRUE_COLOR; +#if 1 + /* This code by Mike Enright, + * see http://www.users.cts.com/sd/m/menright/display.html + */ + memset (&bmi, 0, sizeof (bmi)); + bmi.bi.biSize = sizeof (bmi.bi); + + hbm = CreateCompatibleBitmap (gdk_DC, 1, 1); + GetDIBits (gdk_DC, hbm, 0, 1, NULL, + (BITMAPINFO *) &bmi, DIB_RGB_COLORS); + GetDIBits (gdk_DC, hbm, 0, 1, NULL, + (BITMAPINFO *) &bmi, DIB_RGB_COLORS); + DeleteObject (hbm); + + if (bmi.bi.biCompression != BI_BITFIELDS) + { + /* Either BI_RGB or BI_RLE_something + * .... or perhaps (!!) something else. + * Theoretically biCompression might be + * mmioFourCC('c','v','i','d') but I doubt it. + */ + if (bmi.bi.biCompression == BI_RGB) + { + /* It's 555 */ + bitspixel = 15; + system_visual->visual.red_mask = 0x00007C00; + system_visual->visual.green_mask = 0x000003E0; + system_visual->visual.blue_mask = 0x0000001F; + } + else + { + g_assert_not_reached (); + } + } + else + { + DWORD allmasks = + bmi.u.fields[0] | bmi.u.fields[1] | bmi.u.fields[2]; + int k = 0; + while (allmasks) + { + if (allmasks&1) + k++; + allmasks/=2; + } + bitspixel = k; + system_visual->visual.red_mask = bmi.u.fields[0]; + system_visual->visual.green_mask = bmi.u.fields[1]; + system_visual->visual.blue_mask = bmi.u.fields[2]; + } +#else + /* Old, incorrect (but still working) code. */ +#if 0 + system_visual->visual.red_mask = 0x0000F800; + system_visual->visual.green_mask = 0x000007E0; + system_visual->visual.blue_mask = 0x0000001F; +#else + system_visual->visual.red_mask = 0x00007C00; + system_visual->visual.green_mask = 0x000003E0; + system_visual->visual.blue_mask = 0x0000001F; +#endif +#endif + } + else if (bitspixel == 24 || bitspixel == 32) + { + bitspixel = 24; + system_visual->visual.type = GDK_VISUAL_TRUE_COLOR; + system_visual->visual.red_mask = 0x00FF0000; + system_visual->visual.green_mask = 0x0000FF00; + system_visual->visual.blue_mask = 0x000000FF; + } + else + g_error ("gdk_visual_init: unsupported BITSPIXEL: %d\n", bitspixel); + + system_visual->visual.depth = bitspixel; + system_visual->visual.byte_order = GDK_LSB_FIRST; + system_visual->visual.bits_per_rgb = 42; /* Not used? */ + + if ((system_visual->visual.type == GDK_VISUAL_TRUE_COLOR) || + (system_visual->visual.type == GDK_VISUAL_DIRECT_COLOR)) + { + gdk_visual_decompose_mask (system_visual->visual.red_mask, + &system_visual->visual.red_shift, + &system_visual->visual.red_prec); + + gdk_visual_decompose_mask (system_visual->visual.green_mask, + &system_visual->visual.green_shift, + &system_visual->visual.green_prec); + + gdk_visual_decompose_mask (system_visual->visual.blue_mask, + &system_visual->visual.blue_shift, + &system_visual->visual.blue_prec); + system_visual->xvisual->map_entries = + 1 << (MAX (system_visual->visual.red_prec, + MAX (system_visual->visual.green_prec, + system_visual->visual.blue_prec))); + } + else + { + system_visual->visual.red_mask = 0; + system_visual->visual.red_shift = 0; + system_visual->visual.red_prec = 0; + + system_visual->visual.green_mask = 0; + system_visual->visual.green_shift = 0; + system_visual->visual.green_prec = 0; + + system_visual->visual.blue_mask = 0; + system_visual->visual.blue_shift = 0; + system_visual->visual.blue_prec = 0; + } + system_visual->visual.colormap_size = system_visual->xvisual->map_entries; + + available_depths[0] = system_visual->visual.depth; + available_types[0] = system_visual->visual.type; +} + +GdkVisual* +gdk_visual_ref (GdkVisual *visual) +{ + return visual; +} + +void +gdk_visual_unref (GdkVisual *visual) +{ + return; +} + +gint +gdk_visual_get_best_depth (void) +{ + return available_depths[0]; +} + +GdkVisualType +gdk_visual_get_best_type (void) +{ + return available_types[0]; +} + +GdkVisual* +gdk_visual_get_system (void) +{ + return ((GdkVisual*) system_visual); +} + +GdkVisual* +gdk_visual_get_best (void) +{ + return ((GdkVisual*) system_visual); +} + +GdkVisual* +gdk_visual_get_best_with_depth (gint depth) +{ + if (depth == system_visual->visual.depth) + return (GdkVisual*) system_visual; + else + return NULL; +} + +GdkVisual* +gdk_visual_get_best_with_type (GdkVisualType visual_type) +{ + if (visual_type == system_visual->visual.type) + return (GdkVisual*) system_visual; + else + return NULL; +} + +GdkVisual* +gdk_visual_get_best_with_both (gint depth, + GdkVisualType visual_type) +{ + if ((depth == system_visual->visual.depth) && + (visual_type == system_visual->visual.type)) + return (GdkVisual*) system_visual; + else + return NULL; +} + +void +gdk_query_depths (gint **depths, + gint *count) +{ + *count = 1; + *depths = available_depths; +} + +void +gdk_query_visual_types (GdkVisualType **visual_types, + gint *count) +{ + *count = 1; + *visual_types = available_types; +} + +GList* +gdk_list_visuals (void) +{ + return g_list_append (NULL, (gpointer) system_visual); +} + +GdkVisual* +gdk_visual_lookup (Visual *xvisual) +{ + if (system_visual->xvisual == xvisual) + return (GdkVisual *) system_visual; + else + return NULL; +} + +GdkVisual* +gdkx_visual_get (VisualID xvisualid) +{ + if (xvisualid == system_visual->xvisual->visualid) + return (GdkVisual*) system_visual; + else + return NULL; +} + +static void +gdk_visual_decompose_mask (gulong mask, + gint *shift, + gint *prec) +{ + *shift = 0; + *prec = 0; + + while (!(mask & 0x1)) + { + (*shift)++; + mask >>= 1; + } + + while (mask & 0x1) + { + (*prec)++; + mask >>= 1; + } +} diff --git a/gdk/win32/gdkwindow-win32.c b/gdk/win32/gdkwindow-win32.c new file mode 100644 index 000000000..d8b5177ac --- /dev/null +++ b/gdk/win32/gdkwindow-win32.c @@ -0,0 +1,2407 @@ +/* GDK - The GIMP Drawing Kit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * Copyright (C) 1998-1999 Tor Lillqvist + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* + * Modified by the GTK+ Team and others 1997-1999. See the AUTHORS + * file for a list of people on the GTK+ Team. See the ChangeLog + * files for a list of changes. These files are distributed with + * GTK+ at ftp://ftp.gtk.org/pub/gtk/. + */ + +#include "config.h" + +#include +#include + +#include "gdkevents.h" +#include "gdkpixmap.h" +#include "gdkwindow.h" +#include "gdkprivate.h" +#include "gdkinputprivate.h" +#include "gdkx.h" + +/* The Win API function AdjustWindowRect may return negative values + * resulting in obscured title bars. This helper function is coreccting it. + */ +BOOL +SafeAdjustWindowRectEx (RECT* lpRect, + DWORD dwStyle, + BOOL bMenu, + DWORD dwExStyle) +{ + if (!AdjustWindowRectEx(lpRect, dwStyle, bMenu, dwExStyle)) + return FALSE; + if (lpRect->left < 0) + { + lpRect->right -= lpRect->left; + lpRect->left = 0; + } + if (lpRect->top < 0) + { + lpRect->bottom -= lpRect->top; + lpRect->top = 0; + } + return TRUE; +} + +/* Forward declarations */ +static gboolean gdk_window_gravity_works (void); +static void gdk_window_set_static_win_gravity (GdkWindow *window, + gboolean on); + +/* + * The following fucntion by The Rasterman + * This function returns the X Window ID in which the x y location is in + * (x and y being relative to the root window), excluding any windows listed + * in the GList excludes (this is a list of X Window ID's - gpointer being + * the Window ID). + * + * This is primarily designed for internal gdk use - for DND for example + * when using a shaped icon window as the drag object - you exclude the + * X Window ID of the "icon" (perhaps more if excludes may be needed) and + * You can get back an X Window ID as to what X Window ID is infact under + * those X,Y co-ordinates. + */ +HWND +gdk_window_xid_at_coords (gint x, + gint y, + GList *excludes, + gboolean excl_child) +{ + POINT pt; + gboolean warned = FALSE; + + pt.x = x; + pt.y = y; + /* This is probably not correct, just a quick hack */ + + if (!warned) + { + g_warning ("gdk_window_xid_at_coords probably not implemented correctly"); + warned = TRUE; + } + + /* XXX */ + return WindowFromPoint (pt); +} + +void +gdk_window_init (void) +{ + RECT r; + guint width; + guint height; + + SystemParametersInfo(SPI_GETWORKAREA, 0, &r, 0); + width = r.right - r.left; + height = r.bottom - r.top; + + gdk_root_parent = g_new (GdkWindowPrivate, 1); + gdk_root_parent->drawable.xwindow = gdk_root_window; + gdk_root_parent->drawable.window_type = GDK_WINDOW_ROOT; + gdk_root_parent->drawable.drawable.user_data = NULL; + gdk_root_parent->drawable.width = width; + gdk_root_parent->drawable.height = height; + gdk_root_parent->drawable.ref_count = 1; + gdk_root_parent->drawable.colormap = NULL; + gdk_root_parent->children = NULL; + + gdk_xid_table_insert (&gdk_root_window, gdk_root_parent); +} + +/* RegisterGdkClass + * is a wrapper function for RegisterWindowClassEx. + * It creates at least one unique class for every + * GdkWindowType. If support for single window-specific icons + * is ever needed (e.g Dialog specific), every such window should + * get its own class + */ +ATOM +RegisterGdkClass(GdkWindowType wtype) +{ + static ATOM klassTOPLEVEL = 0; + static ATOM klassDIALOG = 0; + static ATOM klassCHILD = 0; + static ATOM klassTEMP = 0; + static HICON hAppIcon = NULL; + static WNDCLASSEX wcl; + ATOM klass = 0; + + wcl.cbSize = sizeof(WNDCLASSEX); + wcl.style = 0; /* DON'T set CS_REDRAW. It causes total redraw + * on WM_SIZE and WM_MOVE. Flicker, Performance! + */ + wcl.lpfnWndProc = gdk_WindowProc; + wcl.cbClsExtra = 0; + wcl.cbWndExtra = 0; + wcl.hInstance = gdk_ProgInstance; + wcl.hIcon = 0; + /* initialize once! */ + if (0 == hAppIcon) + { + gchar sLoc [_MAX_PATH+1]; + HINSTANCE hInst = GetModuleHandle(NULL); + + if (0 != GetModuleFileName(hInst, sLoc, _MAX_PATH)) + { + hAppIcon = ExtractIcon(hInst, sLoc, 0); + if (0 == hAppIcon) + { + char *gdklibname = g_strdup_printf ("gdk-%s.dll", GDK_VERSION); + + hAppIcon = ExtractIcon(hInst, gdklibname, 0); + g_free (gdklibname); + } + + if (0 == hAppIcon) + hAppIcon = LoadIcon (NULL, IDI_APPLICATION); + } + } + + wcl.lpszMenuName = NULL; + wcl.hIconSm = 0; + + /* initialize once per class */ +#define ONCE_PER_CLASS() \ + wcl.hIcon = CopyIcon (hAppIcon); \ + wcl.hIconSm = CopyIcon (hAppIcon); \ + wcl.hbrBackground = CreateSolidBrush( RGB(0,0,0)); \ + wcl.hCursor = LoadCursor (NULL, IDC_ARROW); + + switch (wtype) + { + case GDK_WINDOW_TOPLEVEL: + if (0 == klassTOPLEVEL) + { + wcl.lpszClassName = "gdkWindowToplevel"; + + ONCE_PER_CLASS(); + klassTOPLEVEL = RegisterClassEx(&wcl); + } + klass = klassTOPLEVEL; + break; + case GDK_WINDOW_CHILD: + if (0 == klassCHILD) + { + wcl.lpszClassName = "gdkWindowChild"; + + wcl.style |= CS_PARENTDC; /* MSDN: ... enhances system performance. */ + ONCE_PER_CLASS(); + klassCHILD = RegisterClassEx(&wcl); + } + klass = klassCHILD; + break; + case GDK_WINDOW_DIALOG: + if (0 == klassDIALOG) + { + wcl.lpszClassName = "gdkWindowDialog"; + wcl.style |= CS_SAVEBITS; + ONCE_PER_CLASS(); + klassDIALOG = RegisterClassEx(&wcl); + } + klass = klassDIALOG; + break; + case GDK_WINDOW_TEMP: + if (0 == klassTEMP) + { + wcl.lpszClassName = "gdkWindowTemp"; + wcl.style |= CS_SAVEBITS; + ONCE_PER_CLASS(); + klassTEMP = RegisterClassEx(&wcl); + } + klass = klassTEMP; + break; + case GDK_WINDOW_ROOT: + g_error ("cannot make windows of type GDK_WINDOW_ROOT"); + break; + case GDK_DRAWABLE_PIXMAP: + g_error ("cannot make windows of type GDK_DRAWABLE_PIXMAP (use gdk_pixmap_new)"); + break; + } + + return klass; +} /* RegisterGdkClass */ + + +GdkWindow* +gdk_window_new (GdkWindow *parent, + GdkWindowAttr *attributes, + gint attributes_mask) +{ + GdkWindow *window; + GdkWindowPrivate *private; + GdkWindowPrivate *parent_private; + GdkVisual *visual; + HANDLE xparent; + Visual *xvisual; + ATOM klass = 0; + DWORD dwStyle, dwExStyle; + RECT rect; + UINT acp; + int width, height; + int x, y; + char *title; + gint titlelen; + wchar_t *wctitle; + gint wlen; + char *mbtitle; + + g_return_val_if_fail (attributes != NULL, NULL); + + if (!parent) + parent = (GdkWindow*) gdk_root_parent; + + parent_private = (GdkWindowPrivate*) parent; + if (GDK_DRAWABLE_DESTROYED (parent)) + return NULL; + + xparent = parent_private->drawable.xwindow; + + private = g_new (GdkWindowPrivate, 1); + window = (GdkWindow*) private; + + private->parent = parent; + + private->drawable.destroyed = FALSE; + private->mapped = FALSE; + private->guffaw_gravity = FALSE; + private->resize_count = 0; + private->drawable.ref_count = 1; + + private->x = (attributes_mask & GDK_WA_X) ? attributes->x : 0; + private->y = (attributes_mask & GDK_WA_Y) ? attributes->y : 0; + + private->drawable.width = (attributes->width > 1) ? (attributes->width) : (1); + private->drawable.height = (attributes->height > 1) ? (attributes->height) : (1); + private->drawable.window_type = attributes->window_type; + private->extension_events = 0; + private->extension_events_selected = FALSE; + + private->filters = NULL; + private->children = NULL; + + window->user_data = NULL; + + if (attributes_mask & GDK_WA_VISUAL) + visual = attributes->visual; + else + visual = gdk_visual_get_system (); + xvisual = ((GdkVisualPrivate*) visual)->xvisual; + + if (attributes_mask & GDK_WA_TITLE) + title = attributes->title; + else + title = g_get_prgname (); + + private->event_mask = GDK_STRUCTURE_MASK | attributes->event_mask; + private->bg_type = GDK_WIN32_BG_NORMAL; + private->hint_flags = 0; + private->xcursor = NULL; + + if (parent_private && parent_private->guffaw_gravity) + { + /* XXX ??? */ + } + + if (attributes->wclass == GDK_INPUT_OUTPUT) + { + dwExStyle = 0; + if (attributes_mask & GDK_WA_COLORMAP) + private->drawable.colormap = attributes->colormap; + else + private->drawable.colormap = gdk_colormap_get_system (); + } + else + { + dwExStyle = WS_EX_TRANSPARENT; + private->drawable.colormap = NULL; + private->bg_type = GDK_WIN32_BG_TRANSPARENT; + private->bg_pixmap = NULL; + } + + if (attributes_mask & GDK_WA_X) + x = attributes->x; + else + x = CW_USEDEFAULT; + + if (attributes_mask & GDK_WA_Y) + y = attributes->y; + else if (attributes_mask & GDK_WA_X) + y = 100; /* ??? We must put it somewhere... */ + else + y = 500; /* x is CW_USEDEFAULT, y doesn't matter then */ + + if (parent_private) + parent_private->children = g_list_prepend (parent_private->children, window); + + switch (private->drawable.window_type) + { + case GDK_WINDOW_TOPLEVEL: + dwStyle = WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN; + xparent = gdk_root_window; + break; + case GDK_WINDOW_CHILD: + dwStyle = WS_CHILDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS; + break; + case GDK_WINDOW_DIALOG: + dwStyle = WS_OVERLAPPED | WS_MINIMIZEBOX | WS_SYSMENU | WS_CAPTION | WS_THICKFRAME | WS_CLIPCHILDREN; + dwExStyle |= WS_EX_TOPMOST; /* //HB: want this? */ + xparent = gdk_root_window; + break; + case GDK_WINDOW_TEMP: + dwStyle = WS_POPUP | WS_CLIPCHILDREN | WS_CLIPSIBLINGS; + dwExStyle |= WS_EX_TOOLWINDOW; + break; + case GDK_WINDOW_ROOT: + g_error ("cannot make windows of type GDK_WINDOW_ROOT"); + break; + case GDK_DRAWABLE_PIXMAP: + g_error ("cannot make windows of type GDK_DRAWABLE_PIXMAP (use gdk_pixmap_new)"); + break; + } + + klass = RegisterGdkClass (private->drawable.window_type); + if (!klass) + g_error ("RegisterClassEx failed"); + + if (private->drawable.window_type != GDK_WINDOW_CHILD) + { + if (x == CW_USEDEFAULT) + { + rect.left = 100; + rect.top = 100; + } + else + { + rect.left = x; + rect.top = y; + } + + rect.right = rect.left + private->drawable.width; + rect.bottom = rect.top + private->drawable.height; + + if (!SafeAdjustWindowRectEx (&rect, dwStyle, FALSE, dwExStyle)) + g_warning ("gdk_window_new: AdjustWindowRectEx failed"); + + if (x != CW_USEDEFAULT) + { + x = rect.left; + y = rect.top; + } + width = rect.right - rect.left; + height = rect.bottom - rect.top; + } + else + { + width = private->drawable.width; + height = private->drawable.height; + } + + acp = GetACP (); + private->input_locale = GetKeyboardLayout (0); + TranslateCharsetInfo ((DWORD FAR *) acp, + &private->charset_info, + TCI_SRCCODEPAGE); + + titlelen = strlen (title); + wctitle = g_new (wchar_t, titlelen + 1); + mbtitle = g_new (char, 3*titlelen + 1); + wlen = gdk_nmbstowchar_ts (wctitle, title, titlelen, titlelen); + wctitle[wlen] = 0; + WideCharToMultiByte (GetACP (), 0, wctitle, -1, + mbtitle, 3*titlelen, NULL, NULL); + + private->drawable.xwindow = + CreateWindowEx (dwExStyle, + MAKEINTRESOURCE(klass), + mbtitle, + dwStyle, + x, y, + width, height, + xparent, + NULL, + gdk_ProgInstance, + NULL); + + GDK_NOTE (MISC, + g_print ("gdk_window_create: %s %s %dx%d@+%d+%d %#x = %#x\n" + "...locale %#x codepage %d\n", + (private->drawable.window_type == GDK_WINDOW_TOPLEVEL ? "TOPLEVEL" : + (private->drawable.window_type == GDK_WINDOW_CHILD ? "CHILD" : + (private->drawable.window_type == GDK_WINDOW_DIALOG ? "DIALOG" : + (private->drawable.window_type == GDK_WINDOW_TEMP ? "TEMP" : + "???")))), + mbtitle, + width, height, (x == CW_USEDEFAULT ? -9999 : x), y, + xparent, + private->drawable.xwindow, + private->input_locale, + private->charset_info.ciACP)); + + g_free (mbtitle); + g_free (wctitle); + + if (private->drawable.xwindow == NULL) + { + g_warning ("gdk_window_create: CreateWindowEx failed"); + g_free (private); + return NULL; + } + + gdk_window_ref (window); + gdk_xid_table_insert (&private->drawable.xwindow, window); + + if (private->drawable.colormap) + gdk_colormap_ref (private->drawable.colormap); + + gdk_window_set_cursor (window, ((attributes_mask & GDK_WA_CURSOR) ? + (attributes->cursor) : + NULL)); + + return window; +} + +GdkWindow * +gdk_window_foreign_new (guint32 anid) +{ + GdkWindow *window; + GdkWindowPrivate *private; + GdkWindowPrivate *parent_private; + HANDLE parent; + RECT rect; + POINT point; + + private = g_new (GdkWindowPrivate, 1); + window = (GdkWindow*) private; + + parent = GetParent ((HWND) anid); + private->parent = gdk_xid_table_lookup (parent); + + parent_private = (GdkWindowPrivate *)private->parent; + + if (parent_private) + parent_private->children = g_list_prepend (parent_private->children, window); + + private->drawable.xwindow = (HWND) anid; + GetClientRect ((HWND) anid, &rect); + point.x = rect.left; + point.y = rect.right; + ClientToScreen ((HWND) anid, &point); + if (parent != GetDesktopWindow ()) + ScreenToClient (parent, &point); + private->x = point.x; + private->y = point.y; + private->drawable.width = rect.right - rect.left; + private->drawable.height = rect.bottom - rect.top; + private->resize_count = 0; + private->drawable.ref_count = 1; + private->drawable.window_type = GDK_WINDOW_FOREIGN; + private->drawable.destroyed = FALSE; + private->mapped = IsWindowVisible (private->drawable.xwindow); + private->guffaw_gravity = FALSE; + private->extension_events = 0; + private->extension_events_selected = FALSE; + + private->drawable.colormap = NULL; + + private->filters = NULL; + private->children = NULL; + + window->user_data = NULL; + + gdk_window_ref (window); + gdk_xid_table_insert (&private->drawable.xwindow, window); + + return window; +} + +/* Call this function when you want a window and all its children to + * disappear. When xdestroy is true, a request to destroy the XWindow + * is sent out. When it is false, it is assumed that the XWindow has + * been or will be destroyed by destroying some ancestor of this + * window. + */ +static void +gdk_window_internal_destroy (GdkWindow *window, + gboolean xdestroy, + gboolean our_destroy) +{ + GdkWindowPrivate *private; + GdkWindowPrivate *temp_private; + GdkWindow *temp_window; + GList *children; + GList *tmp; + + g_return_if_fail (window != NULL); + + private = (GdkWindowPrivate*) window; + + GDK_NOTE (MISC, g_print ("gdk_window_internal_destroy %#x\n", + private->drawable.xwindow)); + + switch (private->drawable.window_type) + { + case GDK_WINDOW_TOPLEVEL: + case GDK_WINDOW_CHILD: + case GDK_WINDOW_DIALOG: + case GDK_WINDOW_TEMP: + case GDK_WINDOW_FOREIGN: + if (!private->drawable.destroyed) + { + if (private->parent) + { + GdkWindowPrivate *parent_private = (GdkWindowPrivate *)private->parent; + if (parent_private->children) + parent_private->children = g_list_remove (parent_private->children, window); + } + + if (GDK_DRAWABLE_TYPE (window) != GDK_WINDOW_FOREIGN) + { + children = tmp = private->children; + private->children = NULL; + + while (tmp) + { + temp_window = tmp->data; + tmp = tmp->next; + + temp_private = (GdkWindowPrivate*) temp_window; + if (temp_private) + gdk_window_internal_destroy (temp_window, FALSE, + our_destroy); + } + + g_list_free (children); + } + + if (private->extension_events != 0) + gdk_input_window_destroy (window); + + if (private->filters) + { + tmp = private->filters; + + while (tmp) + { + g_free (tmp->data); + tmp = tmp->next; + } + + g_list_free (private->filters); + private->filters = NULL; + } + + if (private->drawable.window_type == GDK_WINDOW_FOREIGN) + { + if (our_destroy && (private->parent != NULL)) + { + /* It's somebody elses window, but in our hierarchy, + * so reparent it to the root window, and then send + * it a delete event, as if we were a WM + */ + gdk_window_hide (window); + gdk_window_reparent (window, NULL, 0, 0); + + /* Is this too drastic? Many (most?) applications + * quit if any window receives WM_QUIT I think. + * OTOH, I don't think foreign windows are much + * used, so the question is maybe academic. + */ + PostMessage (private->drawable.xwindow, WM_QUIT, 0, 0); + } + } + else if (xdestroy) + DestroyWindow (private->drawable.xwindow); + + if (private->drawable.colormap) + gdk_colormap_unref (private->drawable.colormap); + + private->mapped = FALSE; + private->drawable.destroyed = TRUE; + } + break; + + case GDK_WINDOW_ROOT: + g_error ("attempted to destroy root window"); + break; + + case GDK_DRAWABLE_PIXMAP: + g_error ("called gdk_window_destroy on a pixmap (use gdk_pixmap_unref)"); + break; + } +} + +/* Like internal_destroy, but also destroys the reference created by + gdk_window_new. */ + +void +gdk_window_destroy (GdkWindow *window) +{ + gdk_window_internal_destroy (window, TRUE, TRUE); + gdk_window_unref (window); +} + +/* This function is called when the XWindow is really gone. */ + +void +gdk_window_destroy_notify (GdkWindow *window) +{ + g_return_if_fail (window != NULL); + + GDK_NOTE (EVENTS, g_print ("gdk_window_destroy_notify: %#x %d\n", + GDK_DRAWABLE_XID (window), GDK_DRAWABLE_DESTROYED (window))); + + if (!GDK_DRAWABLE_DESTROYED (window)) + { + if (GDK_DRAWABLE_TYPE(window) != GDK_WINDOW_FOREIGN) + g_warning ("GdkWindow %#lx unexpectedly destroyed", GDK_DRAWABLE_XID (window)); + + gdk_window_internal_destroy (window, FALSE, FALSE); + } + + gdk_xid_table_remove (GDK_DRAWABLE_XID (window)); + gdk_window_unref (window); +} + +GdkWindow* +gdk_window_ref (GdkWindow *window) +{ + GdkWindowPrivate *private = (GdkWindowPrivate *)window; + g_return_val_if_fail (window != NULL, NULL); + + private->drawable.ref_count += 1; + + GDK_NOTE (MISC, g_print ("gdk_window_ref %#x %d\n", + GDK_DRAWABLE_XID (window), + private->drawable.ref_count)); + + return window; +} + +void +gdk_window_unref (GdkWindow *window) +{ + GdkWindowPrivate *private = (GdkWindowPrivate *)window; + g_return_if_fail (window != NULL); + + private->drawable.ref_count -= 1; + + GDK_NOTE (MISC, g_print ("gdk_window_unref %#x %d%s\n", + private->drawable.xwindow, + private->drawable.ref_count, + (private->drawable.ref_count == 0 ? " freeing" : ""))); + + if (private->drawable.ref_count == 0) + { + if (private->bg_type == GDK_WIN32_BG_PIXMAP + && private->bg_pixmap != NULL) + gdk_pixmap_unref (private->bg_pixmap); + + if (!private->drawable.destroyed) + { + if (private->drawable.window_type == GDK_WINDOW_FOREIGN) + gdk_xid_table_remove (private->drawable.xwindow); + else + g_warning ("losing last reference to undestroyed window"); + } + g_dataset_destroy (window); + g_free (window); + } +} + +void +gdk_window_show (GdkWindow *window) +{ + GdkWindowPrivate *private; + + g_return_if_fail (window != NULL); + + private = (GdkWindowPrivate*) window; + if (!private->drawable.destroyed) + { + GDK_NOTE (MISC, g_print ("gdk_window_show: %#x\n", + private->drawable.xwindow)); + + private->mapped = TRUE; + if (private->drawable.window_type == GDK_WINDOW_TEMP) + { + ShowWindow (private->drawable.xwindow, SW_SHOWNOACTIVATE); + SetWindowPos (private->drawable.xwindow, HWND_TOPMOST, 0, 0, 0, 0, + SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE); +#if 0 + ShowWindow (private->drawable.xwindow, SW_HIDE); /* Don't put on toolbar */ +#endif + } + else + { + ShowWindow (private->drawable.xwindow, SW_SHOWNORMAL); + ShowWindow (private->drawable.xwindow, SW_RESTORE); + SetForegroundWindow (private->drawable.xwindow); + BringWindowToTop (private->drawable.xwindow); +#if 0 + ShowOwnedPopups (private->drawable.xwindow, TRUE); +#endif + } + } +} + +void +gdk_window_hide (GdkWindow *window) +{ + GdkWindowPrivate *private; + + g_return_if_fail (window != NULL); + + private = (GdkWindowPrivate*) window; + if (!private->drawable.destroyed) + { + GDK_NOTE (MISC, g_print ("gdk_window_hide: %#x\n", + private->drawable.xwindow)); + + private->mapped = FALSE; + if (private->drawable.window_type == GDK_WINDOW_TOPLEVEL) + ShowOwnedPopups (private->drawable.xwindow, FALSE); +#if 1 + ShowWindow (private->drawable.xwindow, SW_HIDE); +#elif 0 + ShowWindow (private->drawable.xwindow, SW_MINIMIZE); +#else + CloseWindow (private->drawable.xwindow); +#endif + } +} + +void +gdk_window_withdraw (GdkWindow *window) +{ + GdkWindowPrivate *private; + + g_return_if_fail (window != NULL); + + private = (GdkWindowPrivate*) window; + if (!private->drawable.destroyed) + { + GDK_NOTE (MISC, g_print ("gdk_window_withdraw: %#x\n", + private->drawable.xwindow)); + + gdk_window_hide (window); /* XXX */ + } +} + +void +gdk_window_move (GdkWindow *window, + gint x, + gint y) +{ + GdkWindowPrivate *private; + + g_return_if_fail (window != NULL); + + private = (GdkWindowPrivate*) window; + if (!private->drawable.destroyed) + { + RECT rect; + + GDK_NOTE (MISC, g_print ("gdk_window_move: %#x +%d+%d\n", + private->drawable.xwindow, x, y)); + + GetClientRect (private->drawable.xwindow, &rect); + + if (private->drawable.window_type != GDK_WINDOW_CHILD) + { + POINT ptTL, ptBR; + DWORD dwStyle; + DWORD dwExStyle; + + ptTL.x = 0; + ptTL.y = 0; + ClientToScreen (private->drawable.xwindow, &ptTL); + rect.left = x; + rect.top = y; + + ptBR.x = rect.right; + ptBR.y = rect.bottom; + ClientToScreen (private->drawable.xwindow, &ptBR); + rect.right = x + ptBR.x - ptTL.x; + rect.bottom = y + ptBR.y - ptTL.y; + + dwStyle = GetWindowLong (private->drawable.xwindow, GWL_STYLE); + dwExStyle = GetWindowLong (private->drawable.xwindow, GWL_EXSTYLE); + if (!SafeAdjustWindowRectEx (&rect, dwStyle, FALSE, dwExStyle)) + g_warning ("gdk_window_move: AdjustWindowRectEx failed"); + + x = rect.left; + y = rect.top; + } + else + { + private->x = x; + private->y = y; + } + GDK_NOTE (MISC, g_print ("...MoveWindow(%#x,%dx%d@+%d+%d)\n", + private->drawable.xwindow, + rect.right - rect.left, rect.bottom - rect.top, + x, y)); + if (!MoveWindow (private->drawable.xwindow, + x, y, rect.right - rect.left, rect.bottom - rect.top, + TRUE)) + g_warning ("gdk_window_move: MoveWindow failed"); + } +} + +void +gdk_window_resize (GdkWindow *window, + gint width, + gint height) +{ + GdkWindowPrivate *private; + + g_return_if_fail (window != NULL); + + if ((gint16) width < 1) + width = 1; + if ((gint16) height < 1) + height = 1; + + private = (GdkWindowPrivate*) window; + + if (!private->drawable.destroyed && + ((private->resize_count > 0) || + (private->drawable.width != (guint16) width) || + (private->drawable.height != (guint16) height))) + { + int x, y; + + GDK_NOTE (MISC, g_print ("gdk_window_resize: %#x %dx%d\n", + private->drawable.xwindow, width, height)); + + if (private->drawable.window_type != GDK_WINDOW_CHILD) + { + POINT pt; + RECT rect; + DWORD dwStyle; + DWORD dwExStyle; + + pt.x = 0; + pt.y = 0; + ClientToScreen (private->drawable.xwindow, &pt); + rect.left = pt.x; + rect.top = pt.y; + rect.right = pt.x + width; + rect.bottom = pt.y + height; + + dwStyle = GetWindowLong (private->drawable.xwindow, GWL_STYLE); + dwExStyle = GetWindowLong (private->drawable.xwindow, GWL_EXSTYLE); + if (!AdjustWindowRectEx (&rect, dwStyle, FALSE, dwExStyle)) + g_warning ("gdk_window_resize: AdjustWindowRectEx failed"); + + x = rect.left; + y = rect.top; + width = rect.right - rect.left; + height = rect.bottom - rect.top; + } + else + { + x = private->x; + y = private->y; + private->drawable.width = width; + private->drawable.height = height; + } + + private->resize_count += 1; + + GDK_NOTE (MISC, g_print ("...MoveWindow(%#x,%dx%d@+%d+%d)\n", + private->drawable.xwindow, width, height, x, y)); + if (!MoveWindow (private->drawable.xwindow, + x, y, width, height, + TRUE)) + g_warning ("gdk_window_resize: MoveWindow failed"); + } +} + +void +gdk_window_move_resize (GdkWindow *window, + gint x, + gint y, + gint width, + gint height) +{ + GdkWindowPrivate *private; + + g_return_if_fail (window != NULL); + + if ((gint16) width < 1) + width = 1; + if ((gint16) height < 1) + height = 1; + + private = (GdkWindowPrivate*) window; + if (!private->drawable.destroyed) + { + RECT rect; + DWORD dwStyle; + DWORD dwExStyle; + + GDK_NOTE (MISC, g_print ("gdk_window_move_resize: %#x %dx%d@+%d+%d\n", + private->drawable.xwindow, width, height, x, y)); + + rect.left = x; + rect.top = y; + rect.right = x + width; + rect.bottom = y + height; + + dwStyle = GetWindowLong (private->drawable.xwindow, GWL_STYLE); + dwExStyle = GetWindowLong (private->drawable.xwindow, GWL_EXSTYLE); + if (!AdjustWindowRectEx (&rect, dwStyle, FALSE, dwExStyle)) + g_warning ("gdk_window_move_resize: AdjustWindowRectEx failed"); + + if (private->drawable.window_type == GDK_WINDOW_CHILD) + { + private->x = x; + private->y = y; + private->drawable.width = width; + private->drawable.height = height; + } + GDK_NOTE (MISC, g_print ("...MoveWindow(%#x,%dx%d@+%d+%d)\n", + private->drawable.xwindow, + rect.right - rect.left, rect.bottom - rect.top, + rect.left, rect.top)); + if (!MoveWindow (private->drawable.xwindow, + rect.left, rect.top, + rect.right - rect.left, rect.bottom - rect.top, + TRUE)) + g_warning ("gdk_window_move_resize: MoveWindow failed"); + + if (private->guffaw_gravity) + { + GList *tmp_list = private->children; + while (tmp_list) + { + GdkWindowPrivate *child_private = tmp_list->data; + + child_private->x -= x - private->x; + child_private->y -= y - private->y; + + tmp_list = tmp_list->next; + } + } + + } +} + +void +gdk_window_reparent (GdkWindow *window, + GdkWindow *new_parent, + gint x, + gint y) +{ + GdkWindowPrivate *window_private; + GdkWindowPrivate *parent_private; + GdkWindowPrivate *old_parent_private; + + g_return_if_fail (window != NULL); + + if (!new_parent) + new_parent = (GdkWindow*) gdk_root_parent; + + window_private = (GdkWindowPrivate*) window; + old_parent_private = (GdkWindowPrivate*)window_private->parent; + parent_private = (GdkWindowPrivate*) new_parent; + + if (!window_private->drawable.destroyed && !parent_private->drawable.destroyed) + { + GDK_NOTE (MISC, g_print ("gdk_window_reparent: %#x %#x\n", + window_private->drawable.xwindow, + parent_private->drawable.xwindow)); + if (!SetParent (window_private->drawable.xwindow, parent_private->drawable.xwindow)) + g_warning ("gdk_window_reparent: SetParent failed"); + + if (!MoveWindow (window_private->drawable.xwindow, + x, y, + window_private->drawable.width, window_private->drawable.height, + TRUE)) + g_warning ("gdk_window_reparent: MoveWindow failed"); + } + + window_private->parent = new_parent; + + if (old_parent_private) + old_parent_private->children = g_list_remove (old_parent_private->children, window); + + if ((old_parent_private && + (!old_parent_private->guffaw_gravity != !parent_private->guffaw_gravity)) || + (!old_parent_private && parent_private->guffaw_gravity)) + gdk_window_set_static_win_gravity (window, parent_private->guffaw_gravity); + + parent_private->children = g_list_prepend (parent_private->children, window); +} + +void +gdk_window_clear (GdkWindow *window) +{ + g_return_if_fail (window != NULL); + g_return_if_fail (GDK_IS_WINDOW (window)); + + if (!GDK_DRAWABLE_DESTROYED (window)) + gdk_window_clear_area (window, 0, 0, -1, -1); +} + + +void +gdk_window_clear_area (GdkWindow *window, + gint x, + gint y, + gint width, + gint height) +{ + g_return_if_fail (window != NULL); + g_return_if_fail (GDK_IS_WINDOW (window)); + + if (!GDK_DRAWABLE_DESTROYED (window)) + { + HDC hdc; + + if (width == -1) + width = G_MAXSHORT/2; /* Yeah, right */ + if (height == -1) + height = G_MAXSHORT/2; + GDK_NOTE (MISC, g_print ("gdk_window_clear_area: %#x %dx%d@+%d+%d\n", + GDK_DRAWABLE_XID (window), width, height, x, y)); + hdc = GetDC (GDK_DRAWABLE_XID (window)); + IntersectClipRect (hdc, x, y, x + width, y + height); + SendMessage (GDK_DRAWABLE_XID (window), WM_ERASEBKGND, (WPARAM) hdc, 0); + ReleaseDC (GDK_DRAWABLE_XID (window), hdc); + } +} + +void +gdk_window_clear_area_e (GdkWindow *window, + gint x, + gint y, + gint width, + gint height) +{ + g_return_if_fail (window != NULL); + g_return_if_fail (GDK_IS_WINDOW (window)); + + if (!GDK_DRAWABLE_DESTROYED (window)) + { + RECT rect; + + GDK_NOTE (MISC, g_print ("gdk_window_clear_area_e: %#x %dx%d@+%d+%d\n", + GDK_DRAWABLE_XID (window), width, height, x, y)); + + rect.left = x; + rect.right = x + width; + rect.top = y; + rect.bottom = y + height; + if (!InvalidateRect (GDK_DRAWABLE_XID (window), &rect, TRUE)) + g_warning ("gdk_window_clear_area_e: InvalidateRect failed"); + UpdateWindow (GDK_DRAWABLE_XID (window)); + } +} + +void +gdk_window_raise (GdkWindow *window) +{ + g_return_if_fail (window != NULL); + g_return_if_fail (GDK_IS_WINDOW (window)); + + if (!GDK_DRAWABLE_DESTROYED (window)) + { + GDK_NOTE (MISC, g_print ("gdk_window_raise: %#x\n", + GDK_DRAWABLE_XID (window))); + + if (!BringWindowToTop (GDK_DRAWABLE_XID (window))) + g_warning ("gdk_window_raise: BringWindowToTop failed"); + } +} + +void +gdk_window_lower (GdkWindow *window) +{ + g_return_if_fail (window != NULL); + g_return_if_fail (GDK_IS_WINDOW (window)); + + if (!GDK_DRAWABLE_DESTROYED (window)) + { + GDK_NOTE (MISC, g_print ("gdk_window_lower: %#x\n", + GDK_DRAWABLE_XID (window))); + + if (!SetWindowPos (GDK_DRAWABLE_XID (window), HWND_BOTTOM, 0, 0, 0, 0, + SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE)) + g_warning ("gdk_window_lower: SetWindowPos failed"); + } +} + +void +gdk_window_set_user_data (GdkWindow *window, + gpointer user_data) +{ + g_return_if_fail (window != NULL); + + window->user_data = user_data; +} + +void +gdk_window_set_hints (GdkWindow *window, + gint x, + gint y, + gint min_width, + gint min_height, + gint max_width, + gint max_height, + gint flags) +{ + GdkWindowPrivate *private; + WINDOWPLACEMENT size_hints; + RECT rect; + DWORD dwStyle; + DWORD dwExStyle; + int diff; + + g_return_if_fail (window != NULL); + g_return_if_fail (GDK_IS_WINDOW (window)); + + if (GDK_DRAWABLE_DESTROYED (window)) + return; + + private = (GdkWindowPrivate*) window; + + GDK_NOTE (MISC, g_print ("gdk_window_set_hints: %#x %dx%d..%dx%d @+%d+%d\n", + private->drawable.xwindow, + min_width, min_height, max_width, max_height, + x, y)); + + private->hint_flags = flags; + size_hints.length = sizeof (size_hints); + + if (flags) + { + if (flags & GDK_HINT_POS) + if (!GetWindowPlacement (private->drawable.xwindow, &size_hints)) + g_warning ("gdk_window_set_hints: GetWindowPlacement failed"); + else + { + GDK_NOTE (MISC, g_print ("...rcNormalPosition:" + " (%d,%d)--(%d,%d)\n", + size_hints.rcNormalPosition.left, + size_hints.rcNormalPosition.top, + size_hints.rcNormalPosition.right, + size_hints.rcNormalPosition.bottom)); + /* What are the corresponding window coordinates for client + * area coordinates x, y + */ + rect.left = x; + rect.top = y; + rect.right = rect.left + 200; /* dummy */ + rect.bottom = rect.top + 200; + dwStyle = GetWindowLong (private->drawable.xwindow, GWL_STYLE); + dwExStyle = GetWindowLong (private->drawable.xwindow, GWL_EXSTYLE); + AdjustWindowRectEx (&rect, dwStyle, FALSE, dwExStyle); + size_hints.flags = 0; + size_hints.showCmd = SW_SHOWNA; + + /* Set the normal position hint to that location, with unchanged + * width and height. + */ + diff = size_hints.rcNormalPosition.left - rect.left; + size_hints.rcNormalPosition.left = rect.left; + size_hints.rcNormalPosition.right -= diff; + diff = size_hints.rcNormalPosition.top - rect.top; + size_hints.rcNormalPosition.top = rect.top; + size_hints.rcNormalPosition.bottom -= diff; + GDK_NOTE (MISC, g_print ("...setting: (%d,%d)--(%d,%d)\n", + size_hints.rcNormalPosition.left, + size_hints.rcNormalPosition.top, + size_hints.rcNormalPosition.right, + size_hints.rcNormalPosition.bottom)); + if (!SetWindowPlacement (private->drawable.xwindow, &size_hints)) + g_warning ("gdk_window_set_hints: SetWindowPlacement failed"); + private->hint_x = rect.left; + private->hint_y = rect.top; + } + + if (flags & GDK_HINT_MIN_SIZE) + { + rect.left = 0; + rect.top = 0; + rect.right = min_width; + rect.bottom = min_height; + dwStyle = GetWindowLong (private->drawable.xwindow, GWL_STYLE); + dwExStyle = GetWindowLong (private->drawable.xwindow, GWL_EXSTYLE); + AdjustWindowRectEx (&rect, dwStyle, FALSE, dwExStyle); + private->hint_min_width = rect.right - rect.left; + private->hint_min_height = rect.bottom - rect.top; + + /* Also chek if he current size of the window is in bounds. */ + GetClientRect (private->drawable.xwindow, &rect); + if (rect.right < min_width && rect.bottom < min_height) + gdk_window_resize (window, min_width, min_height); + else if (rect.right < min_width) + gdk_window_resize (window, min_width, rect.bottom); + else if (rect.bottom < min_height) + gdk_window_resize (window, rect.right, min_height); + } + if (flags & GDK_HINT_MAX_SIZE) + { + rect.left = 0; + rect.top = 0; + rect.right = max_width; + rect.bottom = max_height; + dwStyle = GetWindowLong (private->drawable.xwindow, GWL_STYLE); + dwExStyle = GetWindowLong (private->drawable.xwindow, GWL_EXSTYLE); + AdjustWindowRectEx (&rect, dwStyle, FALSE, dwExStyle); + private->hint_max_width = rect.right - rect.left; + private->hint_max_height = rect.bottom - rect.top; + /* Again, check if the window is too large currently. */ + GetClientRect (private->drawable.xwindow, &rect); + if (rect.right > max_width && rect.bottom > max_height) + gdk_window_resize (window, max_width, max_height); + else if (rect.right > max_width) + gdk_window_resize (window, max_width, rect.bottom); + else if (rect.bottom > max_height) + gdk_window_resize (window, rect.right, max_height); + } + } +} + +void +gdk_window_set_geometry_hints (GdkWindow *window, + GdkGeometry *geometry, + GdkWindowHints geom_mask) +{ + GdkWindowPrivate *private; + WINDOWPLACEMENT size_hints; + RECT rect; + DWORD dwStyle; + DWORD dwExStyle; + int diff; + + g_return_if_fail (window != NULL); + g_return_if_fail (GDK_IS_WINDOW (window)); + + if (GDK_DRAWABLE_DESTROYED (window)) + return; + + private = (GdkWindowPrivate*) window; + + size_hints.length = sizeof (size_hints); + + private->hint_flags = geom_mask; + + if (geom_mask & GDK_HINT_POS) + ; /* XXX */ + + if (geom_mask & GDK_HINT_MIN_SIZE) + { + rect.left = 0; + rect.top = 0; + rect.right = geometry->min_width; + rect.bottom = geometry->min_height; + dwStyle = GetWindowLong (private->drawable.xwindow, GWL_STYLE); + dwExStyle = GetWindowLong (private->drawable.xwindow, GWL_EXSTYLE); + AdjustWindowRectEx (&rect, dwStyle, FALSE, dwExStyle); + private->hint_min_width = rect.right - rect.left; + private->hint_min_height = rect.bottom - rect.top; + + /* Also check if he current size of the window is in bounds */ + GetClientRect (private->drawable.xwindow, &rect); + if (rect.right < geometry->min_width + && rect.bottom < geometry->min_height) + gdk_window_resize (window, geometry->min_width, geometry->min_height); + else if (rect.right < geometry->min_width) + gdk_window_resize (window, geometry->min_width, rect.bottom); + else if (rect.bottom < geometry->min_height) + gdk_window_resize (window, rect.right, geometry->min_height); + } + + if (geom_mask & GDK_HINT_MAX_SIZE) + { + rect.left = 0; + rect.top = 0; + rect.right = geometry->max_width; + rect.bottom = geometry->max_height; + dwStyle = GetWindowLong (private->drawable.xwindow, GWL_STYLE); + dwExStyle = GetWindowLong (private->drawable.xwindow, GWL_EXSTYLE); + AdjustWindowRectEx (&rect, dwStyle, FALSE, dwExStyle); + private->hint_max_width = rect.right - rect.left; + private->hint_max_height = rect.bottom - rect.top; + + /* Again, check if the window is too large currently. */ + GetClientRect (private->drawable.xwindow, &rect); + if (rect.right > geometry->max_width + && rect.bottom > geometry->max_height) + gdk_window_resize (window, geometry->max_width, geometry->max_height); + else if (rect.right > geometry->max_width) + gdk_window_resize (window, geometry->max_width, rect.bottom); + else if (rect.bottom > geometry->max_height) + gdk_window_resize (window, rect.right, geometry->max_height); + } + + /* I don't know what to do when called with zero base_width and height. */ + if (geom_mask & GDK_HINT_BASE_SIZE + && geometry->base_width > 0 + && geometry->base_height > 0) + if (!GetWindowPlacement (private->drawable.xwindow, &size_hints)) + g_warning ("gdk_window_set_hints: GetWindowPlacement failed"); + else + { + GDK_NOTE (MISC, g_print ("gdk_window_set_geometry_hints:" + " rcNormalPosition: (%d,%d)--(%d,%d)\n", + size_hints.rcNormalPosition.left, + size_hints.rcNormalPosition.top, + size_hints.rcNormalPosition.right, + size_hints.rcNormalPosition.bottom)); + size_hints.rcNormalPosition.right = + size_hints.rcNormalPosition.left + geometry->base_width; + size_hints.rcNormalPosition.bottom = + size_hints.rcNormalPosition.top + geometry->base_height; + GDK_NOTE (MISC, g_print ("...setting: rcNormal: (%d,%d)--(%d,%d)\n", + size_hints.rcNormalPosition.left, + size_hints.rcNormalPosition.top, + size_hints.rcNormalPosition.right, + size_hints.rcNormalPosition.bottom)); + if (!SetWindowPlacement (private->drawable.xwindow, &size_hints)) + g_warning ("gdk_window_set_hints: SetWindowPlacement failed"); + } + + if (geom_mask & GDK_HINT_RESIZE_INC) + { + /* XXX */ + } + + if (geom_mask & GDK_HINT_ASPECT) + { + /* XXX */ + } +} + +void +gdk_window_set_title (GdkWindow *window, + const gchar *title) +{ + gint titlelen; + wchar_t *wcstr; + gint wlen; + char *mbstr; + + g_return_if_fail (window != NULL); + g_return_if_fail (GDK_IS_WINDOW (window)); + + GDK_NOTE (MISC, g_print ("gdk_window_set_title: %#x %s\n", + GDK_DRAWABLE_XID (window), title)); + if (!GDK_DRAWABLE_DESTROYED (window)) + { + /* As the title most is in UTF-8 we must translate it + * to the system codepage. + */ + titlelen = strlen (title); + wcstr = g_new (wchar_t, titlelen + 1); + mbstr = g_new (char, 3*titlelen + 1); + wlen = gdk_nmbstowchar_ts (wcstr, title, titlelen, titlelen); + wcstr[wlen] = 0; + WideCharToMultiByte (GetACP (), 0, wcstr, -1, + mbstr, 3*titlelen, NULL, NULL); + + if (!SetWindowText (GDK_DRAWABLE_XID (window), mbstr)) + g_warning ("gdk_window_set_title: SetWindowText failed"); + + g_free (mbstr); + g_free (wcstr); + } +} + +void +gdk_window_set_role (GdkWindow *window, + const gchar *role) +{ + g_return_if_fail (window != NULL); + g_return_if_fail (GDK_IS_WINDOW (window)); + + GDK_NOTE (MISC, g_print ("gdk_window_set_role: %#x %s\n", + GDK_DRAWABLE_XID (window), (role ? role : "NULL"))); + /* XXX */ +} + +void +gdk_window_set_transient_for (GdkWindow *window, + GdkWindow *parent) +{ + g_return_if_fail (window != NULL); + g_return_if_fail (GDK_IS_WINDOW (window)); + + GDK_NOTE (MISC, g_print ("gdk_window_set_transient_for: %#x %#x\n", + GDK_DRAWABLE_XID (window), + GDK_DRAWABLE_XID (parent))); + /* XXX */ +} + +void +gdk_window_set_background (GdkWindow *window, + GdkColor *color) +{ + GdkWindowPrivate *private; + + g_return_if_fail (window != NULL); + g_return_if_fail (GDK_IS_WINDOW (window)); + + private = (GdkWindowPrivate*) window; + if (!GDK_DRAWABLE_DESTROYED (window)) + { + GDK_NOTE (MISC, g_print ("gdk_window_set_background: %#x %s\n", + private->drawable.xwindow, + gdk_color_to_string (color))); + + if (private->bg_type == GDK_WIN32_BG_PIXMAP) + { + if (private->bg_pixmap != NULL) + { + gdk_pixmap_unref (private->bg_pixmap); + private->bg_pixmap = NULL; + } + private->bg_type = GDK_WIN32_BG_NORMAL; + } + private->bg_type = GDK_WIN32_BG_PIXEL; + private->bg_pixel = *color; + } +} + +void +gdk_window_set_back_pixmap (GdkWindow *window, + GdkPixmap *pixmap, + gint parent_relative) +{ + GdkWindowPrivate *private; + + g_return_if_fail (window != NULL); + g_return_if_fail (GDK_IS_WINDOW (window)); + + private = (GdkWindowPrivate*) window; + + if (!GDK_DRAWABLE_DESTROYED (window)) + { + if (private->bg_type == GDK_WIN32_BG_PIXMAP) + { + if (private->bg_pixmap != NULL) + { + gdk_pixmap_unref (private->bg_pixmap); + private->bg_pixmap = NULL; + } + private->bg_type = GDK_WIN32_BG_NORMAL; + } + if (parent_relative) + { + private->bg_type = GDK_WIN32_BG_PARENT_RELATIVE; + } + else if (!pixmap) + { + + } + else + { + /* We must cache the pixmap in the WindowPrivate and + * paint it each time we get WM_ERASEBKGND + */ + private->bg_type = GDK_WIN32_BG_PIXMAP; + private->bg_pixmap = pixmap; + gdk_pixmap_ref (pixmap); + } + } +} + +void +gdk_window_set_cursor (GdkWindow *window, + GdkCursor *cursor) +{ + GdkWindowPrivate *window_private; + GdkCursorPrivate *cursor_private; + HCURSOR xcursor; + + g_return_if_fail (window != NULL); + g_return_if_fail (GDK_IS_WINDOW (window)); + + window_private = (GdkWindowPrivate*) window; + cursor_private = (GdkCursorPrivate*) cursor; + + if (!GDK_DRAWABLE_DESTROYED (window)) + { + if (!cursor) + xcursor = LoadCursor (NULL, IDC_ARROW); + else + xcursor = cursor_private->xcursor; + + GDK_NOTE (MISC, g_print ("gdk_window_set_cursor: %#x %#x\n", + window_private->drawable.xwindow, xcursor)); + window_private->xcursor = xcursor; + } +} + +void +gdk_window_get_user_data (GdkWindow *window, + gpointer *data) +{ + g_return_if_fail (window != NULL); + + *data = window->user_data; +} + +void +gdk_window_get_geometry (GdkWindow *window, + gint *x, + gint *y, + gint *width, + gint *height, + gint *depth) +{ + g_return_if_fail (window == NULL || GDK_IS_WINDOW (window)); + + if (!window) + window = (GdkWindow*) gdk_root_parent; + + if (!GDK_DRAWABLE_DESTROYED (window)) + { + RECT rect; + + if (!GetClientRect (GDK_DRAWABLE_XID (window), &rect)) + g_warning ("gdk_window_get_geometry: GetClientRect failed"); + + if (x) + *x = rect.left; + if (y) + *y = rect.top; + if (width) + *width = rect.right - rect.left; + if (height) + *height = rect.bottom - rect.top; + if (depth) + *depth = gdk_drawable_get_visual (window)->depth; + } +} + +void +gdk_window_get_position (GdkWindow *window, + gint *x, + gint *y) +{ + GdkWindowPrivate *window_private; + + g_return_if_fail (window != NULL); + g_return_if_fail (GDK_IS_WINDOW (window)); + + window_private = (GdkWindowPrivate*) window; + + if (x) + *x = window_private->x; + if (y) + *y = window_private->y; +} + +gint +gdk_window_get_origin (GdkWindow *window, + gint *x, + gint *y) +{ + gint return_val; + gint tx = 0; + gint ty = 0; + + g_return_val_if_fail (window != NULL, 0); + + if (!GDK_DRAWABLE_DESTROYED (window)) + { + POINT pt; + + pt.x = 0; + pt.y = 0; + ClientToScreen (GDK_DRAWABLE_XID (window), &pt); + tx = pt.x; + ty = pt.y; + return_val = 1; + } + else + return_val = 0; + + if (x) + *x = tx; + if (y) + *y = ty; + + GDK_NOTE (MISC, g_print ("gdk_window_get_origin: %#x: +%d+%d\n", + GDK_DRAWABLE_XID (window), tx, ty)); + return return_val; +} + +gboolean +gdk_window_get_deskrelative_origin (GdkWindow *window, + gint *x, + gint *y) +{ + return gdk_window_get_origin (window, x, y); +} + +void +gdk_window_get_root_origin (GdkWindow *window, + gint *x, + gint *y) +{ + GdkWindowPrivate *private; + POINT pt; + + g_return_if_fail (window != NULL); + g_return_if_fail (GDK_IS_WINDOW (window)); + + private = (GdkWindowPrivate*) window; + if (x) + *x = 0; + if (y) + *y = 0; + if (GDK_DRAWABLE_DESTROYED (window)) + return; + + while (private->parent && ((GdkWindowPrivate*) private->parent)->parent) + private = (GdkWindowPrivate*) private->parent; + if (private->drawable.destroyed) + return; + + pt.x = 0; + pt.y = 0; + ClientToScreen (private->drawable.xwindow, &pt); + if (x) + *x = pt.x; + if (y) + *y = pt.y; + + GDK_NOTE (MISC, g_print ("gdk_window_get_root_origin: %#x: (%#x) +%d+%d\n", + GDK_DRAWABLE_XID (window), + private->drawable.xwindow, pt.x, pt.y)); +} + +GdkWindow* +gdk_window_get_pointer (GdkWindow *window, + gint *x, + gint *y, + GdkModifierType *mask) +{ + GdkWindow *return_val; + POINT pointc, point; + HWND hwnd, hwndc; + + g_return_val_if_fail (window == NULL || GDK_IS_WINDOW (window), NULL); + + if (!window) + window = (GdkWindow*) gdk_root_parent; + + return_val = NULL; + GetCursorPos (&pointc); + point = pointc; + ScreenToClient (GDK_DRAWABLE_XID (window), &point); + + if (x) + *x = point.x; + if (y) + *y = point.y; + + hwnd = WindowFromPoint (point); + point = pointc; + ScreenToClient (hwnd, &point); + + do { + hwndc = ChildWindowFromPoint (hwnd, point); + ClientToScreen (hwnd, &point); + ScreenToClient (hwndc, &point); + } while (hwndc != hwnd && (hwnd = hwndc, 1)); /* Ouch! */ + + return_val = gdk_window_lookup (hwnd); + + if (mask) + { + BYTE kbd[256]; + + GetKeyboardState (kbd); + *mask = 0; + if (kbd[VK_SHIFT] & 0x80) + *mask |= GDK_SHIFT_MASK; + if (kbd[VK_CAPITAL] & 0x80) + *mask |= GDK_LOCK_MASK; + if (kbd[VK_CONTROL] & 0x80) + *mask |= GDK_CONTROL_MASK; + if (kbd[VK_MENU] & 0x80) + *mask |= GDK_MOD1_MASK; + if (kbd[VK_LBUTTON] & 0x80) + *mask |= GDK_BUTTON1_MASK; + if (kbd[VK_MBUTTON] & 0x80) + *mask |= GDK_BUTTON2_MASK; + if (kbd[VK_RBUTTON] & 0x80) + *mask |= GDK_BUTTON3_MASK; + } + + return return_val; +} + +GdkWindow* +gdk_window_at_pointer (gint *win_x, + gint *win_y) +{ + GdkWindow *window; + POINT point, pointc; + HWND hwnd, hwndc; + RECT rect; + + GetCursorPos (&pointc); + point = pointc; + hwnd = WindowFromPoint (point); + + if (hwnd == NULL) + { + window = (GdkWindow *) gdk_root_parent; + if (win_x) + *win_x = pointc.x; + if (win_y) + *win_y = pointc.y; + return window; + } + + ScreenToClient (hwnd, &point); + + do { + hwndc = ChildWindowFromPoint (hwnd, point); + ClientToScreen (hwnd, &point); + ScreenToClient (hwndc, &point); + } while (hwndc != hwnd && (hwnd = hwndc, 1)); + + window = gdk_window_lookup (hwnd); + + if (window && (win_x || win_y)) + { + GetClientRect (hwnd, &rect); + if (win_x) + *win_x = point.x - rect.left; + if (win_y) + *win_y = point.y - rect.top; + } + + GDK_NOTE (MISC, g_print ("gdk_window_at_pointer: +%d+%d %#x%s\n", + point.x, point.y, hwnd, + (window == NULL ? " NULL" : ""))); + + return window; +} + +GdkWindow* +gdk_window_get_parent (GdkWindow *window) +{ + g_return_val_if_fail (window != NULL, NULL); + g_return_val_if_fail (GDK_IS_WINDOW (window), NULL); + + return ((GdkWindowPrivate*) window)->parent; +} + +GdkWindow* +gdk_window_get_toplevel (GdkWindow *window) +{ + g_return_val_if_fail (window != NULL, NULL); + g_return_val_if_fail (GDK_IS_WINDOW (window), NULL); + + while (GDK_DRAWABLE_TYPE (window) == GDK_WINDOW_CHILD) + window = ((GdkWindowPrivate*) window)->parent; + + return window; +} + +GList* +gdk_window_get_children (GdkWindow *window) +{ + GdkWindowPrivate *private; + GList *children; + + g_return_val_if_fail (window != NULL, NULL); + g_return_val_if_fail (GDK_IS_WINDOW (window), NULL); + + if (GDK_DRAWABLE_DESTROYED (window)) + return NULL; + + /* XXX ??? */ + g_warning ("gdk_window_get_children not implemented"); + children = NULL; + + return children; +} + +GdkEventMask +gdk_window_get_events (GdkWindow *window) +{ + GdkWindowPrivate *private; + + g_return_val_if_fail (window != NULL, 0); + g_return_val_if_fail (GDK_IS_WINDOW (window), 0); + + private = (GdkWindowPrivate*) window; + if (GDK_DRAWABLE_DESTROYED (window)) + return 0; + + return private->event_mask; +} + +void +gdk_window_set_events (GdkWindow *window, + GdkEventMask event_mask) +{ + GdkWindowPrivate *private; + + g_return_if_fail (window != NULL); + g_return_if_fail (GDK_IS_WINDOW (window)); + + private = (GdkWindowPrivate*) window; + if (GDK_DRAWABLE_DESTROYED (window)) + return; + + private->event_mask = event_mask; +} + +void +gdk_window_add_colormap_windows (GdkWindow *window) +{ + g_warning ("gdk_window_add_colormap_windows not implemented"); +} + +void +gdk_window_shape_combine_mask (GdkWindow *window, + GdkBitmap *mask, + gint x, gint y) +{ + g_return_if_fail (window != NULL); + g_return_if_fail (GDK_IS_WINDOW (window)); + + if (!mask) + { + GDK_NOTE (MISC, g_print ("gdk_window_shape_combine_mask: %#x none\n", + GDK_DRAWABLE_XID (window))); + SetWindowRgn (GDK_DRAWABLE_XID (window), NULL, TRUE); + } + else + { + GdkDrawablePrivate *pixmap_private; + HRGN hrgn; + DWORD dwStyle; + DWORD dwExStyle; + RECT rect; + + /* Convert mask bitmap to region */ + pixmap_private = (GdkDrawablePrivate*) mask; + hrgn = BitmapToRegion (pixmap_private->xwindow); + + GDK_NOTE (MISC, g_print ("gdk_window_shape_combine_mask: %#x %#x\n", + GDK_DRAWABLE_XID (window), + pixmap_private->xwindow)); + + /* SetWindowRgn wants window (not client) coordinates */ + dwStyle = GetWindowLong (GDK_DRAWABLE_XID (window), GWL_STYLE); + dwExStyle = GetWindowLong (GDK_DRAWABLE_XID (window), GWL_EXSTYLE); + GetClientRect (GDK_DRAWABLE_XID (window), &rect); + AdjustWindowRectEx (&rect, dwStyle, FALSE, dwExStyle); + OffsetRgn (hrgn, -rect.left, -rect.top); + + OffsetRgn (hrgn, x, y); + + /* If this is a top-level window, add the title bar to the region */ + if (GDK_DRAWABLE_TYPE (window) == GDK_WINDOW_TOPLEVEL) + { + CombineRgn (hrgn, hrgn, + CreateRectRgn (0, 0, rect.right - rect.left, -rect.top), + RGN_OR); + } + + SetWindowRgn (GDK_DRAWABLE_XID (window), hrgn, TRUE); + } +} + +void +gdk_window_add_filter (GdkWindow *window, + GdkFilterFunc function, + gpointer data) +{ + GdkWindowPrivate *private; + GList *tmp_list; + GdkEventFilter *filter; + + g_return_if_fail (window != NULL); + g_return_if_fail (GDK_IS_WINDOW (window)); + + private = (GdkWindowPrivate*) window; + if (private && GDK_DRAWABLE_DESTROYED (window)) + return; + + tmp_list = private->filters; + + while (tmp_list) + { + filter = (GdkEventFilter *)tmp_list->data; + if ((filter->function == function) && (filter->data == data)) + return; + tmp_list = tmp_list->next; + } + + filter = g_new (GdkEventFilter, 1); + filter->function = function; + filter->data = data; + + private->filters = g_list_append (private->filters, filter); +} + +void +gdk_window_remove_filter (GdkWindow *window, + GdkFilterFunc function, + gpointer data) +{ + GdkWindowPrivate *private; + GList *tmp_list, *node; + GdkEventFilter *filter; + + g_return_if_fail (window != NULL); + g_return_if_fail (GDK_IS_WINDOW (window)); + + private = (GdkWindowPrivate*) window; + + tmp_list = private->filters; + + while (tmp_list) + { + filter = (GdkEventFilter *)tmp_list->data; + node = tmp_list; + tmp_list = tmp_list->next; + + if ((filter->function == function) && (filter->data == data)) + { + private->filters = g_list_remove_link (private->filters, node); + + g_list_free_1 (node); + g_free (filter); + + return; + } + } +} + +void +gdk_window_set_override_redirect (GdkWindow *window, + gboolean override_redirect) +{ + g_return_if_fail (window != NULL); + g_return_if_fail (GDK_IS_WINDOW (window)); + + g_warning ("gdk_window_set_override_redirect not implemented"); +} + +void +gdk_window_set_icon (GdkWindow *window, + GdkWindow *icon_window, + GdkPixmap *pixmap, + GdkBitmap *mask) +{ + g_return_if_fail (window != NULL); + g_return_if_fail (GDK_IS_WINDOW (window)); + + if (GDK_DRAWABLE_DESTROYED (window)) + return; + + g_warning ("gdk_window_set_icon not implemented"); +} + +void +gdk_window_set_icon_name (GdkWindow *window, + gchar *name) +{ + g_return_if_fail (window != NULL); + g_return_if_fail (GDK_IS_WINDOW (window)); + + if (GDK_DRAWABLE_DESTROYED (window)) + return; + + if (!SetWindowText (GDK_DRAWABLE_XID (window), name)) + g_warning ("gdk_window_set_icon_name: SetWindowText failed"); +} + +void +gdk_window_set_group (GdkWindow *window, + GdkWindow *leader) +{ + g_return_if_fail (window != NULL); + g_return_if_fail (GDK_IS_WINDOW (window)); + g_return_if_fail (leader != NULL); + g_return_if_fail (GDK_IS_WINDOW (leader)); + + if (GDK_DRAWABLE_DESTROYED (window) || GDK_DRAWABLE_DESTROYED (leader)) + return; + + g_warning ("gdk_window_set_group not implemented"); +} + +void +gdk_window_set_decorations (GdkWindow *window, + GdkWMDecoration decorations) +{ + LONG style, exstyle; + + g_return_if_fail (window != NULL); + g_return_if_fail (GDK_IS_WINDOW (window)); + + style = GetWindowLong (GDK_DRAWABLE_XID (window), GWL_STYLE); + exstyle = GetWindowLong (GDK_DRAWABLE_XID (window), GWL_EXSTYLE); + + style &= (WS_OVERLAPPED|WS_POPUP|WS_CHILD|WS_MINIMIZE|WS_VISIBLE|WS_DISABLED + |WS_CLIPSIBLINGS|WS_CLIPCHILDREN|WS_MAXIMIZE); + + exstyle &= (WS_EX_TOPMOST|WS_EX_TRANSPARENT); + + if (decorations & GDK_DECOR_ALL) + style |= (WS_CAPTION|WS_SYSMENU|WS_THICKFRAME|WS_MINIMIZEBOX|WS_MAXIMIZEBOX); + if (decorations & GDK_DECOR_BORDER) + style |= (WS_BORDER); + if (decorations & GDK_DECOR_RESIZEH) + style |= (WS_THICKFRAME); + if (decorations & GDK_DECOR_TITLE) + style |= (WS_CAPTION); + if (decorations & GDK_DECOR_MENU) + style |= (WS_SYSMENU); + if (decorations & GDK_DECOR_MINIMIZE) + style |= (WS_MINIMIZEBOX); + if (decorations & GDK_DECOR_MAXIMIZE) + style |= (WS_MAXIMIZEBOX); + + SetWindowLong (GDK_DRAWABLE_XID (window), GWL_STYLE, style); +} + +void +gdk_window_set_functions (GdkWindow *window, + GdkWMFunction functions) +{ + LONG style, exstyle; + + g_return_if_fail (window != NULL); + g_return_if_fail (GDK_IS_WINDOW (window)); + + style = GetWindowLong (GDK_DRAWABLE_XID (window), GWL_STYLE); + exstyle = GetWindowLong (GDK_DRAWABLE_XID (window), GWL_EXSTYLE); + + style &= (WS_OVERLAPPED|WS_POPUP|WS_CHILD|WS_MINIMIZE|WS_VISIBLE|WS_DISABLED + |WS_CLIPSIBLINGS|WS_CLIPCHILDREN|WS_MAXIMIZE|WS_CAPTION|WS_BORDER + |WS_SYSMENU); + + exstyle &= (WS_EX_TOPMOST|WS_EX_TRANSPARENT); + + if (functions & GDK_FUNC_ALL) + style |= (WS_THICKFRAME|WS_MINIMIZEBOX|WS_MAXIMIZEBOX); + if (functions & GDK_FUNC_RESIZE) + style |= (WS_THICKFRAME); + if (functions & GDK_FUNC_MOVE) + style |= (WS_THICKFRAME); + if (functions & GDK_FUNC_MINIMIZE) + style |= (WS_MINIMIZEBOX); + if (functions & GDK_FUNC_MAXIMIZE) + style |= (WS_MAXIMIZEBOX); + + SetWindowLong (GDK_DRAWABLE_XID (window), GWL_STYLE, style); +} + +GList * +gdk_window_get_toplevels (void) +{ + GList *new_list = NULL; + GList *tmp_list; + + tmp_list = gdk_root_parent->children; + while (tmp_list) + { + new_list = g_list_prepend (new_list, tmp_list->data); + tmp_list = tmp_list->next; + } + + return new_list; +} + +/* + * propagate the shapes from all child windows of a GDK window to the parent + * window. Shamelessly ripped from Enlightenment's code + * + * - Raster + */ + +static void +QueryTree (HWND hwnd, + HWND **children, + gint *nchildren) +{ + guint i, n; + HWND child; + + n = 0; + do { + if (n == 0) + child = GetWindow (hwnd, GW_CHILD); + else + child = GetWindow (child, GW_HWNDNEXT); + if (child != NULL) + n++; + } while (child != NULL); + + if (n > 0) + { + *children = g_new (HWND, n); + for (i = 0; i < n; i++) + { + if (i == 0) + child = GetWindow (hwnd, GW_CHILD); + else + child = GetWindow (child, GW_HWNDNEXT); + *children[i] = child; + } + } +} + +static void +gdk_propagate_shapes (HANDLE win, + gboolean merge) +{ + RECT emptyRect; + HRGN region, childRegion; + RECT rect; + HWND *list = NULL; + gint i, num; + + SetRectEmpty (&emptyRect); + region = CreateRectRgnIndirect (&emptyRect); + if (merge) + GetWindowRgn (win, region); + + QueryTree (win, &list, &num); + if (list != NULL) + { + WINDOWPLACEMENT placement; + + placement.length = sizeof (WINDOWPLACEMENT); + /* go through all child windows and combine regions */ + for (i = 0; i < num; i++) + { + GetWindowPlacement (list[i], &placement); + if (placement.showCmd = SW_SHOWNORMAL) + { + childRegion = CreateRectRgnIndirect (&emptyRect); + GetWindowRgn (list[i], childRegion); + CombineRgn (region, region, childRegion, RGN_OR); + DeleteObject (childRegion); + } + } + SetWindowRgn (win, region, TRUE); + } + else + DeleteObject (region); +} + +void +gdk_window_set_child_shapes (GdkWindow *window) +{ + g_return_if_fail (window != NULL); + g_return_if_fail (GDK_IS_WINDOW (window)); + + if (GDK_DRAWABLE_DESTROYED (window)) + return; + + gdk_propagate_shapes (GDK_DRAWABLE_XID (window), FALSE); +} + +void +gdk_window_merge_child_shapes (GdkWindow *window) +{ + g_return_if_fail (window != NULL); + g_return_if_fail (GDK_IS_WINDOW (window)); + + if (GDK_DRAWABLE_DESTROYED (window)) + return; + + gdk_propagate_shapes (GDK_DRAWABLE_XID (window), TRUE); +} + +/************************************************************* + * gdk_window_is_visible: + * Check if the given window is mapped. + * arguments: + * window: + * results: + * is the window mapped + *************************************************************/ + +gboolean +gdk_window_is_visible (GdkWindow *window) +{ + GdkWindowPrivate *private = (GdkWindowPrivate *)window; + + g_return_val_if_fail (window != NULL, FALSE); + g_return_val_if_fail (GDK_IS_WINDOW (window), FALSE); + + return private->mapped; +} + +/************************************************************* + * gdk_window_is_viewable: + * Check if the window and all ancestors of the window + * are mapped. (This is not necessarily "viewable" in + * the X sense, since we only check as far as we have + * GDK window parents, not to the root window) + * arguments: + * window: + * results: + * is the window viewable + *************************************************************/ + +gboolean +gdk_window_is_viewable (GdkWindow *window) +{ + GdkWindowPrivate *private = (GdkWindowPrivate *)window; + + g_return_val_if_fail (window != NULL, FALSE); + g_return_val_if_fail (GDK_IS_WINDOW (window), FALSE); + + while (private && + (private != gdk_root_parent) && + (private->drawable.window_type != GDK_WINDOW_FOREIGN)) + { + if (!private->mapped) + return FALSE; + + private = (GdkWindowPrivate *)private->parent; + } + + return TRUE; +} + +/* Support for windows that can be guffaw-scrolled + * (See http://www.gtk.org/~otaylor/whitepapers/guffaw-scrolling.txt) + */ + +static gboolean +gdk_window_gravity_works (void) +{ + enum { UNKNOWN, NO, YES }; + static gint gravity_works = UNKNOWN; + + if (gravity_works == UNKNOWN) + { + GdkWindowAttr attr; + GdkWindow *parent; + GdkWindow *child; + gint y; + + attr.window_type = GDK_WINDOW_TEMP; + attr.wclass = GDK_INPUT_OUTPUT; + attr.x = 0; + attr.y = 0; + attr.width = 100; + attr.height = 100; + attr.event_mask = 0; + + parent = gdk_window_new (NULL, &attr, GDK_WA_X | GDK_WA_Y); + + attr.window_type = GDK_WINDOW_CHILD; + child = gdk_window_new (parent, &attr, GDK_WA_X | GDK_WA_Y); + + gdk_window_set_static_win_gravity (child, TRUE); + + gdk_window_resize (parent, 100, 110); + gdk_window_move (parent, 0, -10); + gdk_window_move_resize (parent, 0, 0, 100, 100); + + gdk_window_resize (parent, 100, 110); + gdk_window_move (parent, 0, -10); + gdk_window_move_resize (parent, 0, 0, 100, 100); + + gdk_window_get_geometry (child, NULL, &y, NULL, NULL, NULL); + + gdk_window_destroy (parent); + gdk_window_destroy (child); + + gravity_works = ((y == -20) ? YES : NO); + } + + return (gravity_works == YES); +} + +static void +gdk_window_set_static_bit_gravity (GdkWindow *window, gboolean on) +{ + g_return_if_fail (window != NULL); + + GDK_NOTE (MISC, g_print ("gdk_window_set_static_bit_gravity: Not implemented\n")); +} + +static void +gdk_window_set_static_win_gravity (GdkWindow *window, gboolean on) +{ + g_return_if_fail (window != NULL); + + GDK_NOTE (MISC, + g_print ("gdk_window_set_static_win_gravity: Not implemented\n")); +} + +/************************************************************* + * gdk_window_set_static_gravities: + * Set the bit gravity of the given window to static, + * and flag it so all children get static subwindow + * gravity. + * arguments: + * window: window for which to set static gravity + * use_static: Whether to turn static gravity on or off. + * results: + * Does the XServer support static gravity? + *************************************************************/ + +gboolean +gdk_window_set_static_gravities (GdkWindow *window, + gboolean use_static) +{ + GdkWindowPrivate *private = (GdkWindowPrivate *)window; + GList *tmp_list; + + g_return_val_if_fail (window != NULL, FALSE); + g_return_val_if_fail (GDK_IS_WINDOW (window), FALSE); + + if (!use_static == !private->guffaw_gravity) + return TRUE; + + if (use_static && !gdk_window_gravity_works ()) + return FALSE; + + private->guffaw_gravity = use_static; + + if (!GDK_DRAWABLE_DESTROYED (window)) + { + gdk_window_set_static_bit_gravity (window, use_static); + + tmp_list = private->children; + while (tmp_list) + { + gdk_window_set_static_win_gravity (window, use_static); + + tmp_list = tmp_list->next; + } + } + + return TRUE; +} diff --git a/gdk/win32/gdkwindow.c b/gdk/win32/gdkwindow.c new file mode 100644 index 000000000..d8b5177ac --- /dev/null +++ b/gdk/win32/gdkwindow.c @@ -0,0 +1,2407 @@ +/* GDK - The GIMP Drawing Kit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * Copyright (C) 1998-1999 Tor Lillqvist + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* + * Modified by the GTK+ Team and others 1997-1999. See the AUTHORS + * file for a list of people on the GTK+ Team. See the ChangeLog + * files for a list of changes. These files are distributed with + * GTK+ at ftp://ftp.gtk.org/pub/gtk/. + */ + +#include "config.h" + +#include +#include + +#include "gdkevents.h" +#include "gdkpixmap.h" +#include "gdkwindow.h" +#include "gdkprivate.h" +#include "gdkinputprivate.h" +#include "gdkx.h" + +/* The Win API function AdjustWindowRect may return negative values + * resulting in obscured title bars. This helper function is coreccting it. + */ +BOOL +SafeAdjustWindowRectEx (RECT* lpRect, + DWORD dwStyle, + BOOL bMenu, + DWORD dwExStyle) +{ + if (!AdjustWindowRectEx(lpRect, dwStyle, bMenu, dwExStyle)) + return FALSE; + if (lpRect->left < 0) + { + lpRect->right -= lpRect->left; + lpRect->left = 0; + } + if (lpRect->top < 0) + { + lpRect->bottom -= lpRect->top; + lpRect->top = 0; + } + return TRUE; +} + +/* Forward declarations */ +static gboolean gdk_window_gravity_works (void); +static void gdk_window_set_static_win_gravity (GdkWindow *window, + gboolean on); + +/* + * The following fucntion by The Rasterman + * This function returns the X Window ID in which the x y location is in + * (x and y being relative to the root window), excluding any windows listed + * in the GList excludes (this is a list of X Window ID's - gpointer being + * the Window ID). + * + * This is primarily designed for internal gdk use - for DND for example + * when using a shaped icon window as the drag object - you exclude the + * X Window ID of the "icon" (perhaps more if excludes may be needed) and + * You can get back an X Window ID as to what X Window ID is infact under + * those X,Y co-ordinates. + */ +HWND +gdk_window_xid_at_coords (gint x, + gint y, + GList *excludes, + gboolean excl_child) +{ + POINT pt; + gboolean warned = FALSE; + + pt.x = x; + pt.y = y; + /* This is probably not correct, just a quick hack */ + + if (!warned) + { + g_warning ("gdk_window_xid_at_coords probably not implemented correctly"); + warned = TRUE; + } + + /* XXX */ + return WindowFromPoint (pt); +} + +void +gdk_window_init (void) +{ + RECT r; + guint width; + guint height; + + SystemParametersInfo(SPI_GETWORKAREA, 0, &r, 0); + width = r.right - r.left; + height = r.bottom - r.top; + + gdk_root_parent = g_new (GdkWindowPrivate, 1); + gdk_root_parent->drawable.xwindow = gdk_root_window; + gdk_root_parent->drawable.window_type = GDK_WINDOW_ROOT; + gdk_root_parent->drawable.drawable.user_data = NULL; + gdk_root_parent->drawable.width = width; + gdk_root_parent->drawable.height = height; + gdk_root_parent->drawable.ref_count = 1; + gdk_root_parent->drawable.colormap = NULL; + gdk_root_parent->children = NULL; + + gdk_xid_table_insert (&gdk_root_window, gdk_root_parent); +} + +/* RegisterGdkClass + * is a wrapper function for RegisterWindowClassEx. + * It creates at least one unique class for every + * GdkWindowType. If support for single window-specific icons + * is ever needed (e.g Dialog specific), every such window should + * get its own class + */ +ATOM +RegisterGdkClass(GdkWindowType wtype) +{ + static ATOM klassTOPLEVEL = 0; + static ATOM klassDIALOG = 0; + static ATOM klassCHILD = 0; + static ATOM klassTEMP = 0; + static HICON hAppIcon = NULL; + static WNDCLASSEX wcl; + ATOM klass = 0; + + wcl.cbSize = sizeof(WNDCLASSEX); + wcl.style = 0; /* DON'T set CS_REDRAW. It causes total redraw + * on WM_SIZE and WM_MOVE. Flicker, Performance! + */ + wcl.lpfnWndProc = gdk_WindowProc; + wcl.cbClsExtra = 0; + wcl.cbWndExtra = 0; + wcl.hInstance = gdk_ProgInstance; + wcl.hIcon = 0; + /* initialize once! */ + if (0 == hAppIcon) + { + gchar sLoc [_MAX_PATH+1]; + HINSTANCE hInst = GetModuleHandle(NULL); + + if (0 != GetModuleFileName(hInst, sLoc, _MAX_PATH)) + { + hAppIcon = ExtractIcon(hInst, sLoc, 0); + if (0 == hAppIcon) + { + char *gdklibname = g_strdup_printf ("gdk-%s.dll", GDK_VERSION); + + hAppIcon = ExtractIcon(hInst, gdklibname, 0); + g_free (gdklibname); + } + + if (0 == hAppIcon) + hAppIcon = LoadIcon (NULL, IDI_APPLICATION); + } + } + + wcl.lpszMenuName = NULL; + wcl.hIconSm = 0; + + /* initialize once per class */ +#define ONCE_PER_CLASS() \ + wcl.hIcon = CopyIcon (hAppIcon); \ + wcl.hIconSm = CopyIcon (hAppIcon); \ + wcl.hbrBackground = CreateSolidBrush( RGB(0,0,0)); \ + wcl.hCursor = LoadCursor (NULL, IDC_ARROW); + + switch (wtype) + { + case GDK_WINDOW_TOPLEVEL: + if (0 == klassTOPLEVEL) + { + wcl.lpszClassName = "gdkWindowToplevel"; + + ONCE_PER_CLASS(); + klassTOPLEVEL = RegisterClassEx(&wcl); + } + klass = klassTOPLEVEL; + break; + case GDK_WINDOW_CHILD: + if (0 == klassCHILD) + { + wcl.lpszClassName = "gdkWindowChild"; + + wcl.style |= CS_PARENTDC; /* MSDN: ... enhances system performance. */ + ONCE_PER_CLASS(); + klassCHILD = RegisterClassEx(&wcl); + } + klass = klassCHILD; + break; + case GDK_WINDOW_DIALOG: + if (0 == klassDIALOG) + { + wcl.lpszClassName = "gdkWindowDialog"; + wcl.style |= CS_SAVEBITS; + ONCE_PER_CLASS(); + klassDIALOG = RegisterClassEx(&wcl); + } + klass = klassDIALOG; + break; + case GDK_WINDOW_TEMP: + if (0 == klassTEMP) + { + wcl.lpszClassName = "gdkWindowTemp"; + wcl.style |= CS_SAVEBITS; + ONCE_PER_CLASS(); + klassTEMP = RegisterClassEx(&wcl); + } + klass = klassTEMP; + break; + case GDK_WINDOW_ROOT: + g_error ("cannot make windows of type GDK_WINDOW_ROOT"); + break; + case GDK_DRAWABLE_PIXMAP: + g_error ("cannot make windows of type GDK_DRAWABLE_PIXMAP (use gdk_pixmap_new)"); + break; + } + + return klass; +} /* RegisterGdkClass */ + + +GdkWindow* +gdk_window_new (GdkWindow *parent, + GdkWindowAttr *attributes, + gint attributes_mask) +{ + GdkWindow *window; + GdkWindowPrivate *private; + GdkWindowPrivate *parent_private; + GdkVisual *visual; + HANDLE xparent; + Visual *xvisual; + ATOM klass = 0; + DWORD dwStyle, dwExStyle; + RECT rect; + UINT acp; + int width, height; + int x, y; + char *title; + gint titlelen; + wchar_t *wctitle; + gint wlen; + char *mbtitle; + + g_return_val_if_fail (attributes != NULL, NULL); + + if (!parent) + parent = (GdkWindow*) gdk_root_parent; + + parent_private = (GdkWindowPrivate*) parent; + if (GDK_DRAWABLE_DESTROYED (parent)) + return NULL; + + xparent = parent_private->drawable.xwindow; + + private = g_new (GdkWindowPrivate, 1); + window = (GdkWindow*) private; + + private->parent = parent; + + private->drawable.destroyed = FALSE; + private->mapped = FALSE; + private->guffaw_gravity = FALSE; + private->resize_count = 0; + private->drawable.ref_count = 1; + + private->x = (attributes_mask & GDK_WA_X) ? attributes->x : 0; + private->y = (attributes_mask & GDK_WA_Y) ? attributes->y : 0; + + private->drawable.width = (attributes->width > 1) ? (attributes->width) : (1); + private->drawable.height = (attributes->height > 1) ? (attributes->height) : (1); + private->drawable.window_type = attributes->window_type; + private->extension_events = 0; + private->extension_events_selected = FALSE; + + private->filters = NULL; + private->children = NULL; + + window->user_data = NULL; + + if (attributes_mask & GDK_WA_VISUAL) + visual = attributes->visual; + else + visual = gdk_visual_get_system (); + xvisual = ((GdkVisualPrivate*) visual)->xvisual; + + if (attributes_mask & GDK_WA_TITLE) + title = attributes->title; + else + title = g_get_prgname (); + + private->event_mask = GDK_STRUCTURE_MASK | attributes->event_mask; + private->bg_type = GDK_WIN32_BG_NORMAL; + private->hint_flags = 0; + private->xcursor = NULL; + + if (parent_private && parent_private->guffaw_gravity) + { + /* XXX ??? */ + } + + if (attributes->wclass == GDK_INPUT_OUTPUT) + { + dwExStyle = 0; + if (attributes_mask & GDK_WA_COLORMAP) + private->drawable.colormap = attributes->colormap; + else + private->drawable.colormap = gdk_colormap_get_system (); + } + else + { + dwExStyle = WS_EX_TRANSPARENT; + private->drawable.colormap = NULL; + private->bg_type = GDK_WIN32_BG_TRANSPARENT; + private->bg_pixmap = NULL; + } + + if (attributes_mask & GDK_WA_X) + x = attributes->x; + else + x = CW_USEDEFAULT; + + if (attributes_mask & GDK_WA_Y) + y = attributes->y; + else if (attributes_mask & GDK_WA_X) + y = 100; /* ??? We must put it somewhere... */ + else + y = 500; /* x is CW_USEDEFAULT, y doesn't matter then */ + + if (parent_private) + parent_private->children = g_list_prepend (parent_private->children, window); + + switch (private->drawable.window_type) + { + case GDK_WINDOW_TOPLEVEL: + dwStyle = WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN; + xparent = gdk_root_window; + break; + case GDK_WINDOW_CHILD: + dwStyle = WS_CHILDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS; + break; + case GDK_WINDOW_DIALOG: + dwStyle = WS_OVERLAPPED | WS_MINIMIZEBOX | WS_SYSMENU | WS_CAPTION | WS_THICKFRAME | WS_CLIPCHILDREN; + dwExStyle |= WS_EX_TOPMOST; /* //HB: want this? */ + xparent = gdk_root_window; + break; + case GDK_WINDOW_TEMP: + dwStyle = WS_POPUP | WS_CLIPCHILDREN | WS_CLIPSIBLINGS; + dwExStyle |= WS_EX_TOOLWINDOW; + break; + case GDK_WINDOW_ROOT: + g_error ("cannot make windows of type GDK_WINDOW_ROOT"); + break; + case GDK_DRAWABLE_PIXMAP: + g_error ("cannot make windows of type GDK_DRAWABLE_PIXMAP (use gdk_pixmap_new)"); + break; + } + + klass = RegisterGdkClass (private->drawable.window_type); + if (!klass) + g_error ("RegisterClassEx failed"); + + if (private->drawable.window_type != GDK_WINDOW_CHILD) + { + if (x == CW_USEDEFAULT) + { + rect.left = 100; + rect.top = 100; + } + else + { + rect.left = x; + rect.top = y; + } + + rect.right = rect.left + private->drawable.width; + rect.bottom = rect.top + private->drawable.height; + + if (!SafeAdjustWindowRectEx (&rect, dwStyle, FALSE, dwExStyle)) + g_warning ("gdk_window_new: AdjustWindowRectEx failed"); + + if (x != CW_USEDEFAULT) + { + x = rect.left; + y = rect.top; + } + width = rect.right - rect.left; + height = rect.bottom - rect.top; + } + else + { + width = private->drawable.width; + height = private->drawable.height; + } + + acp = GetACP (); + private->input_locale = GetKeyboardLayout (0); + TranslateCharsetInfo ((DWORD FAR *) acp, + &private->charset_info, + TCI_SRCCODEPAGE); + + titlelen = strlen (title); + wctitle = g_new (wchar_t, titlelen + 1); + mbtitle = g_new (char, 3*titlelen + 1); + wlen = gdk_nmbstowchar_ts (wctitle, title, titlelen, titlelen); + wctitle[wlen] = 0; + WideCharToMultiByte (GetACP (), 0, wctitle, -1, + mbtitle, 3*titlelen, NULL, NULL); + + private->drawable.xwindow = + CreateWindowEx (dwExStyle, + MAKEINTRESOURCE(klass), + mbtitle, + dwStyle, + x, y, + width, height, + xparent, + NULL, + gdk_ProgInstance, + NULL); + + GDK_NOTE (MISC, + g_print ("gdk_window_create: %s %s %dx%d@+%d+%d %#x = %#x\n" + "...locale %#x codepage %d\n", + (private->drawable.window_type == GDK_WINDOW_TOPLEVEL ? "TOPLEVEL" : + (private->drawable.window_type == GDK_WINDOW_CHILD ? "CHILD" : + (private->drawable.window_type == GDK_WINDOW_DIALOG ? "DIALOG" : + (private->drawable.window_type == GDK_WINDOW_TEMP ? "TEMP" : + "???")))), + mbtitle, + width, height, (x == CW_USEDEFAULT ? -9999 : x), y, + xparent, + private->drawable.xwindow, + private->input_locale, + private->charset_info.ciACP)); + + g_free (mbtitle); + g_free (wctitle); + + if (private->drawable.xwindow == NULL) + { + g_warning ("gdk_window_create: CreateWindowEx failed"); + g_free (private); + return NULL; + } + + gdk_window_ref (window); + gdk_xid_table_insert (&private->drawable.xwindow, window); + + if (private->drawable.colormap) + gdk_colormap_ref (private->drawable.colormap); + + gdk_window_set_cursor (window, ((attributes_mask & GDK_WA_CURSOR) ? + (attributes->cursor) : + NULL)); + + return window; +} + +GdkWindow * +gdk_window_foreign_new (guint32 anid) +{ + GdkWindow *window; + GdkWindowPrivate *private; + GdkWindowPrivate *parent_private; + HANDLE parent; + RECT rect; + POINT point; + + private = g_new (GdkWindowPrivate, 1); + window = (GdkWindow*) private; + + parent = GetParent ((HWND) anid); + private->parent = gdk_xid_table_lookup (parent); + + parent_private = (GdkWindowPrivate *)private->parent; + + if (parent_private) + parent_private->children = g_list_prepend (parent_private->children, window); + + private->drawable.xwindow = (HWND) anid; + GetClientRect ((HWND) anid, &rect); + point.x = rect.left; + point.y = rect.right; + ClientToScreen ((HWND) anid, &point); + if (parent != GetDesktopWindow ()) + ScreenToClient (parent, &point); + private->x = point.x; + private->y = point.y; + private->drawable.width = rect.right - rect.left; + private->drawable.height = rect.bottom - rect.top; + private->resize_count = 0; + private->drawable.ref_count = 1; + private->drawable.window_type = GDK_WINDOW_FOREIGN; + private->drawable.destroyed = FALSE; + private->mapped = IsWindowVisible (private->drawable.xwindow); + private->guffaw_gravity = FALSE; + private->extension_events = 0; + private->extension_events_selected = FALSE; + + private->drawable.colormap = NULL; + + private->filters = NULL; + private->children = NULL; + + window->user_data = NULL; + + gdk_window_ref (window); + gdk_xid_table_insert (&private->drawable.xwindow, window); + + return window; +} + +/* Call this function when you want a window and all its children to + * disappear. When xdestroy is true, a request to destroy the XWindow + * is sent out. When it is false, it is assumed that the XWindow has + * been or will be destroyed by destroying some ancestor of this + * window. + */ +static void +gdk_window_internal_destroy (GdkWindow *window, + gboolean xdestroy, + gboolean our_destroy) +{ + GdkWindowPrivate *private; + GdkWindowPrivate *temp_private; + GdkWindow *temp_window; + GList *children; + GList *tmp; + + g_return_if_fail (window != NULL); + + private = (GdkWindowPrivate*) window; + + GDK_NOTE (MISC, g_print ("gdk_window_internal_destroy %#x\n", + private->drawable.xwindow)); + + switch (private->drawable.window_type) + { + case GDK_WINDOW_TOPLEVEL: + case GDK_WINDOW_CHILD: + case GDK_WINDOW_DIALOG: + case GDK_WINDOW_TEMP: + case GDK_WINDOW_FOREIGN: + if (!private->drawable.destroyed) + { + if (private->parent) + { + GdkWindowPrivate *parent_private = (GdkWindowPrivate *)private->parent; + if (parent_private->children) + parent_private->children = g_list_remove (parent_private->children, window); + } + + if (GDK_DRAWABLE_TYPE (window) != GDK_WINDOW_FOREIGN) + { + children = tmp = private->children; + private->children = NULL; + + while (tmp) + { + temp_window = tmp->data; + tmp = tmp->next; + + temp_private = (GdkWindowPrivate*) temp_window; + if (temp_private) + gdk_window_internal_destroy (temp_window, FALSE, + our_destroy); + } + + g_list_free (children); + } + + if (private->extension_events != 0) + gdk_input_window_destroy (window); + + if (private->filters) + { + tmp = private->filters; + + while (tmp) + { + g_free (tmp->data); + tmp = tmp->next; + } + + g_list_free (private->filters); + private->filters = NULL; + } + + if (private->drawable.window_type == GDK_WINDOW_FOREIGN) + { + if (our_destroy && (private->parent != NULL)) + { + /* It's somebody elses window, but in our hierarchy, + * so reparent it to the root window, and then send + * it a delete event, as if we were a WM + */ + gdk_window_hide (window); + gdk_window_reparent (window, NULL, 0, 0); + + /* Is this too drastic? Many (most?) applications + * quit if any window receives WM_QUIT I think. + * OTOH, I don't think foreign windows are much + * used, so the question is maybe academic. + */ + PostMessage (private->drawable.xwindow, WM_QUIT, 0, 0); + } + } + else if (xdestroy) + DestroyWindow (private->drawable.xwindow); + + if (private->drawable.colormap) + gdk_colormap_unref (private->drawable.colormap); + + private->mapped = FALSE; + private->drawable.destroyed = TRUE; + } + break; + + case GDK_WINDOW_ROOT: + g_error ("attempted to destroy root window"); + break; + + case GDK_DRAWABLE_PIXMAP: + g_error ("called gdk_window_destroy on a pixmap (use gdk_pixmap_unref)"); + break; + } +} + +/* Like internal_destroy, but also destroys the reference created by + gdk_window_new. */ + +void +gdk_window_destroy (GdkWindow *window) +{ + gdk_window_internal_destroy (window, TRUE, TRUE); + gdk_window_unref (window); +} + +/* This function is called when the XWindow is really gone. */ + +void +gdk_window_destroy_notify (GdkWindow *window) +{ + g_return_if_fail (window != NULL); + + GDK_NOTE (EVENTS, g_print ("gdk_window_destroy_notify: %#x %d\n", + GDK_DRAWABLE_XID (window), GDK_DRAWABLE_DESTROYED (window))); + + if (!GDK_DRAWABLE_DESTROYED (window)) + { + if (GDK_DRAWABLE_TYPE(window) != GDK_WINDOW_FOREIGN) + g_warning ("GdkWindow %#lx unexpectedly destroyed", GDK_DRAWABLE_XID (window)); + + gdk_window_internal_destroy (window, FALSE, FALSE); + } + + gdk_xid_table_remove (GDK_DRAWABLE_XID (window)); + gdk_window_unref (window); +} + +GdkWindow* +gdk_window_ref (GdkWindow *window) +{ + GdkWindowPrivate *private = (GdkWindowPrivate *)window; + g_return_val_if_fail (window != NULL, NULL); + + private->drawable.ref_count += 1; + + GDK_NOTE (MISC, g_print ("gdk_window_ref %#x %d\n", + GDK_DRAWABLE_XID (window), + private->drawable.ref_count)); + + return window; +} + +void +gdk_window_unref (GdkWindow *window) +{ + GdkWindowPrivate *private = (GdkWindowPrivate *)window; + g_return_if_fail (window != NULL); + + private->drawable.ref_count -= 1; + + GDK_NOTE (MISC, g_print ("gdk_window_unref %#x %d%s\n", + private->drawable.xwindow, + private->drawable.ref_count, + (private->drawable.ref_count == 0 ? " freeing" : ""))); + + if (private->drawable.ref_count == 0) + { + if (private->bg_type == GDK_WIN32_BG_PIXMAP + && private->bg_pixmap != NULL) + gdk_pixmap_unref (private->bg_pixmap); + + if (!private->drawable.destroyed) + { + if (private->drawable.window_type == GDK_WINDOW_FOREIGN) + gdk_xid_table_remove (private->drawable.xwindow); + else + g_warning ("losing last reference to undestroyed window"); + } + g_dataset_destroy (window); + g_free (window); + } +} + +void +gdk_window_show (GdkWindow *window) +{ + GdkWindowPrivate *private; + + g_return_if_fail (window != NULL); + + private = (GdkWindowPrivate*) window; + if (!private->drawable.destroyed) + { + GDK_NOTE (MISC, g_print ("gdk_window_show: %#x\n", + private->drawable.xwindow)); + + private->mapped = TRUE; + if (private->drawable.window_type == GDK_WINDOW_TEMP) + { + ShowWindow (private->drawable.xwindow, SW_SHOWNOACTIVATE); + SetWindowPos (private->drawable.xwindow, HWND_TOPMOST, 0, 0, 0, 0, + SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE); +#if 0 + ShowWindow (private->drawable.xwindow, SW_HIDE); /* Don't put on toolbar */ +#endif + } + else + { + ShowWindow (private->drawable.xwindow, SW_SHOWNORMAL); + ShowWindow (private->drawable.xwindow, SW_RESTORE); + SetForegroundWindow (private->drawable.xwindow); + BringWindowToTop (private->drawable.xwindow); +#if 0 + ShowOwnedPopups (private->drawable.xwindow, TRUE); +#endif + } + } +} + +void +gdk_window_hide (GdkWindow *window) +{ + GdkWindowPrivate *private; + + g_return_if_fail (window != NULL); + + private = (GdkWindowPrivate*) window; + if (!private->drawable.destroyed) + { + GDK_NOTE (MISC, g_print ("gdk_window_hide: %#x\n", + private->drawable.xwindow)); + + private->mapped = FALSE; + if (private->drawable.window_type == GDK_WINDOW_TOPLEVEL) + ShowOwnedPopups (private->drawable.xwindow, FALSE); +#if 1 + ShowWindow (private->drawable.xwindow, SW_HIDE); +#elif 0 + ShowWindow (private->drawable.xwindow, SW_MINIMIZE); +#else + CloseWindow (private->drawable.xwindow); +#endif + } +} + +void +gdk_window_withdraw (GdkWindow *window) +{ + GdkWindowPrivate *private; + + g_return_if_fail (window != NULL); + + private = (GdkWindowPrivate*) window; + if (!private->drawable.destroyed) + { + GDK_NOTE (MISC, g_print ("gdk_window_withdraw: %#x\n", + private->drawable.xwindow)); + + gdk_window_hide (window); /* XXX */ + } +} + +void +gdk_window_move (GdkWindow *window, + gint x, + gint y) +{ + GdkWindowPrivate *private; + + g_return_if_fail (window != NULL); + + private = (GdkWindowPrivate*) window; + if (!private->drawable.destroyed) + { + RECT rect; + + GDK_NOTE (MISC, g_print ("gdk_window_move: %#x +%d+%d\n", + private->drawable.xwindow, x, y)); + + GetClientRect (private->drawable.xwindow, &rect); + + if (private->drawable.window_type != GDK_WINDOW_CHILD) + { + POINT ptTL, ptBR; + DWORD dwStyle; + DWORD dwExStyle; + + ptTL.x = 0; + ptTL.y = 0; + ClientToScreen (private->drawable.xwindow, &ptTL); + rect.left = x; + rect.top = y; + + ptBR.x = rect.right; + ptBR.y = rect.bottom; + ClientToScreen (private->drawable.xwindow, &ptBR); + rect.right = x + ptBR.x - ptTL.x; + rect.bottom = y + ptBR.y - ptTL.y; + + dwStyle = GetWindowLong (private->drawable.xwindow, GWL_STYLE); + dwExStyle = GetWindowLong (private->drawable.xwindow, GWL_EXSTYLE); + if (!SafeAdjustWindowRectEx (&rect, dwStyle, FALSE, dwExStyle)) + g_warning ("gdk_window_move: AdjustWindowRectEx failed"); + + x = rect.left; + y = rect.top; + } + else + { + private->x = x; + private->y = y; + } + GDK_NOTE (MISC, g_print ("...MoveWindow(%#x,%dx%d@+%d+%d)\n", + private->drawable.xwindow, + rect.right - rect.left, rect.bottom - rect.top, + x, y)); + if (!MoveWindow (private->drawable.xwindow, + x, y, rect.right - rect.left, rect.bottom - rect.top, + TRUE)) + g_warning ("gdk_window_move: MoveWindow failed"); + } +} + +void +gdk_window_resize (GdkWindow *window, + gint width, + gint height) +{ + GdkWindowPrivate *private; + + g_return_if_fail (window != NULL); + + if ((gint16) width < 1) + width = 1; + if ((gint16) height < 1) + height = 1; + + private = (GdkWindowPrivate*) window; + + if (!private->drawable.destroyed && + ((private->resize_count > 0) || + (private->drawable.width != (guint16) width) || + (private->drawable.height != (guint16) height))) + { + int x, y; + + GDK_NOTE (MISC, g_print ("gdk_window_resize: %#x %dx%d\n", + private->drawable.xwindow, width, height)); + + if (private->drawable.window_type != GDK_WINDOW_CHILD) + { + POINT pt; + RECT rect; + DWORD dwStyle; + DWORD dwExStyle; + + pt.x = 0; + pt.y = 0; + ClientToScreen (private->drawable.xwindow, &pt); + rect.left = pt.x; + rect.top = pt.y; + rect.right = pt.x + width; + rect.bottom = pt.y + height; + + dwStyle = GetWindowLong (private->drawable.xwindow, GWL_STYLE); + dwExStyle = GetWindowLong (private->drawable.xwindow, GWL_EXSTYLE); + if (!AdjustWindowRectEx (&rect, dwStyle, FALSE, dwExStyle)) + g_warning ("gdk_window_resize: AdjustWindowRectEx failed"); + + x = rect.left; + y = rect.top; + width = rect.right - rect.left; + height = rect.bottom - rect.top; + } + else + { + x = private->x; + y = private->y; + private->drawable.width = width; + private->drawable.height = height; + } + + private->resize_count += 1; + + GDK_NOTE (MISC, g_print ("...MoveWindow(%#x,%dx%d@+%d+%d)\n", + private->drawable.xwindow, width, height, x, y)); + if (!MoveWindow (private->drawable.xwindow, + x, y, width, height, + TRUE)) + g_warning ("gdk_window_resize: MoveWindow failed"); + } +} + +void +gdk_window_move_resize (GdkWindow *window, + gint x, + gint y, + gint width, + gint height) +{ + GdkWindowPrivate *private; + + g_return_if_fail (window != NULL); + + if ((gint16) width < 1) + width = 1; + if ((gint16) height < 1) + height = 1; + + private = (GdkWindowPrivate*) window; + if (!private->drawable.destroyed) + { + RECT rect; + DWORD dwStyle; + DWORD dwExStyle; + + GDK_NOTE (MISC, g_print ("gdk_window_move_resize: %#x %dx%d@+%d+%d\n", + private->drawable.xwindow, width, height, x, y)); + + rect.left = x; + rect.top = y; + rect.right = x + width; + rect.bottom = y + height; + + dwStyle = GetWindowLong (private->drawable.xwindow, GWL_STYLE); + dwExStyle = GetWindowLong (private->drawable.xwindow, GWL_EXSTYLE); + if (!AdjustWindowRectEx (&rect, dwStyle, FALSE, dwExStyle)) + g_warning ("gdk_window_move_resize: AdjustWindowRectEx failed"); + + if (private->drawable.window_type == GDK_WINDOW_CHILD) + { + private->x = x; + private->y = y; + private->drawable.width = width; + private->drawable.height = height; + } + GDK_NOTE (MISC, g_print ("...MoveWindow(%#x,%dx%d@+%d+%d)\n", + private->drawable.xwindow, + rect.right - rect.left, rect.bottom - rect.top, + rect.left, rect.top)); + if (!MoveWindow (private->drawable.xwindow, + rect.left, rect.top, + rect.right - rect.left, rect.bottom - rect.top, + TRUE)) + g_warning ("gdk_window_move_resize: MoveWindow failed"); + + if (private->guffaw_gravity) + { + GList *tmp_list = private->children; + while (tmp_list) + { + GdkWindowPrivate *child_private = tmp_list->data; + + child_private->x -= x - private->x; + child_private->y -= y - private->y; + + tmp_list = tmp_list->next; + } + } + + } +} + +void +gdk_window_reparent (GdkWindow *window, + GdkWindow *new_parent, + gint x, + gint y) +{ + GdkWindowPrivate *window_private; + GdkWindowPrivate *parent_private; + GdkWindowPrivate *old_parent_private; + + g_return_if_fail (window != NULL); + + if (!new_parent) + new_parent = (GdkWindow*) gdk_root_parent; + + window_private = (GdkWindowPrivate*) window; + old_parent_private = (GdkWindowPrivate*)window_private->parent; + parent_private = (GdkWindowPrivate*) new_parent; + + if (!window_private->drawable.destroyed && !parent_private->drawable.destroyed) + { + GDK_NOTE (MISC, g_print ("gdk_window_reparent: %#x %#x\n", + window_private->drawable.xwindow, + parent_private->drawable.xwindow)); + if (!SetParent (window_private->drawable.xwindow, parent_private->drawable.xwindow)) + g_warning ("gdk_window_reparent: SetParent failed"); + + if (!MoveWindow (window_private->drawable.xwindow, + x, y, + window_private->drawable.width, window_private->drawable.height, + TRUE)) + g_warning ("gdk_window_reparent: MoveWindow failed"); + } + + window_private->parent = new_parent; + + if (old_parent_private) + old_parent_private->children = g_list_remove (old_parent_private->children, window); + + if ((old_parent_private && + (!old_parent_private->guffaw_gravity != !parent_private->guffaw_gravity)) || + (!old_parent_private && parent_private->guffaw_gravity)) + gdk_window_set_static_win_gravity (window, parent_private->guffaw_gravity); + + parent_private->children = g_list_prepend (parent_private->children, window); +} + +void +gdk_window_clear (GdkWindow *window) +{ + g_return_if_fail (window != NULL); + g_return_if_fail (GDK_IS_WINDOW (window)); + + if (!GDK_DRAWABLE_DESTROYED (window)) + gdk_window_clear_area (window, 0, 0, -1, -1); +} + + +void +gdk_window_clear_area (GdkWindow *window, + gint x, + gint y, + gint width, + gint height) +{ + g_return_if_fail (window != NULL); + g_return_if_fail (GDK_IS_WINDOW (window)); + + if (!GDK_DRAWABLE_DESTROYED (window)) + { + HDC hdc; + + if (width == -1) + width = G_MAXSHORT/2; /* Yeah, right */ + if (height == -1) + height = G_MAXSHORT/2; + GDK_NOTE (MISC, g_print ("gdk_window_clear_area: %#x %dx%d@+%d+%d\n", + GDK_DRAWABLE_XID (window), width, height, x, y)); + hdc = GetDC (GDK_DRAWABLE_XID (window)); + IntersectClipRect (hdc, x, y, x + width, y + height); + SendMessage (GDK_DRAWABLE_XID (window), WM_ERASEBKGND, (WPARAM) hdc, 0); + ReleaseDC (GDK_DRAWABLE_XID (window), hdc); + } +} + +void +gdk_window_clear_area_e (GdkWindow *window, + gint x, + gint y, + gint width, + gint height) +{ + g_return_if_fail (window != NULL); + g_return_if_fail (GDK_IS_WINDOW (window)); + + if (!GDK_DRAWABLE_DESTROYED (window)) + { + RECT rect; + + GDK_NOTE (MISC, g_print ("gdk_window_clear_area_e: %#x %dx%d@+%d+%d\n", + GDK_DRAWABLE_XID (window), width, height, x, y)); + + rect.left = x; + rect.right = x + width; + rect.top = y; + rect.bottom = y + height; + if (!InvalidateRect (GDK_DRAWABLE_XID (window), &rect, TRUE)) + g_warning ("gdk_window_clear_area_e: InvalidateRect failed"); + UpdateWindow (GDK_DRAWABLE_XID (window)); + } +} + +void +gdk_window_raise (GdkWindow *window) +{ + g_return_if_fail (window != NULL); + g_return_if_fail (GDK_IS_WINDOW (window)); + + if (!GDK_DRAWABLE_DESTROYED (window)) + { + GDK_NOTE (MISC, g_print ("gdk_window_raise: %#x\n", + GDK_DRAWABLE_XID (window))); + + if (!BringWindowToTop (GDK_DRAWABLE_XID (window))) + g_warning ("gdk_window_raise: BringWindowToTop failed"); + } +} + +void +gdk_window_lower (GdkWindow *window) +{ + g_return_if_fail (window != NULL); + g_return_if_fail (GDK_IS_WINDOW (window)); + + if (!GDK_DRAWABLE_DESTROYED (window)) + { + GDK_NOTE (MISC, g_print ("gdk_window_lower: %#x\n", + GDK_DRAWABLE_XID (window))); + + if (!SetWindowPos (GDK_DRAWABLE_XID (window), HWND_BOTTOM, 0, 0, 0, 0, + SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE)) + g_warning ("gdk_window_lower: SetWindowPos failed"); + } +} + +void +gdk_window_set_user_data (GdkWindow *window, + gpointer user_data) +{ + g_return_if_fail (window != NULL); + + window->user_data = user_data; +} + +void +gdk_window_set_hints (GdkWindow *window, + gint x, + gint y, + gint min_width, + gint min_height, + gint max_width, + gint max_height, + gint flags) +{ + GdkWindowPrivate *private; + WINDOWPLACEMENT size_hints; + RECT rect; + DWORD dwStyle; + DWORD dwExStyle; + int diff; + + g_return_if_fail (window != NULL); + g_return_if_fail (GDK_IS_WINDOW (window)); + + if (GDK_DRAWABLE_DESTROYED (window)) + return; + + private = (GdkWindowPrivate*) window; + + GDK_NOTE (MISC, g_print ("gdk_window_set_hints: %#x %dx%d..%dx%d @+%d+%d\n", + private->drawable.xwindow, + min_width, min_height, max_width, max_height, + x, y)); + + private->hint_flags = flags; + size_hints.length = sizeof (size_hints); + + if (flags) + { + if (flags & GDK_HINT_POS) + if (!GetWindowPlacement (private->drawable.xwindow, &size_hints)) + g_warning ("gdk_window_set_hints: GetWindowPlacement failed"); + else + { + GDK_NOTE (MISC, g_print ("...rcNormalPosition:" + " (%d,%d)--(%d,%d)\n", + size_hints.rcNormalPosition.left, + size_hints.rcNormalPosition.top, + size_hints.rcNormalPosition.right, + size_hints.rcNormalPosition.bottom)); + /* What are the corresponding window coordinates for client + * area coordinates x, y + */ + rect.left = x; + rect.top = y; + rect.right = rect.left + 200; /* dummy */ + rect.bottom = rect.top + 200; + dwStyle = GetWindowLong (private->drawable.xwindow, GWL_STYLE); + dwExStyle = GetWindowLong (private->drawable.xwindow, GWL_EXSTYLE); + AdjustWindowRectEx (&rect, dwStyle, FALSE, dwExStyle); + size_hints.flags = 0; + size_hints.showCmd = SW_SHOWNA; + + /* Set the normal position hint to that location, with unchanged + * width and height. + */ + diff = size_hints.rcNormalPosition.left - rect.left; + size_hints.rcNormalPosition.left = rect.left; + size_hints.rcNormalPosition.right -= diff; + diff = size_hints.rcNormalPosition.top - rect.top; + size_hints.rcNormalPosition.top = rect.top; + size_hints.rcNormalPosition.bottom -= diff; + GDK_NOTE (MISC, g_print ("...setting: (%d,%d)--(%d,%d)\n", + size_hints.rcNormalPosition.left, + size_hints.rcNormalPosition.top, + size_hints.rcNormalPosition.right, + size_hints.rcNormalPosition.bottom)); + if (!SetWindowPlacement (private->drawable.xwindow, &size_hints)) + g_warning ("gdk_window_set_hints: SetWindowPlacement failed"); + private->hint_x = rect.left; + private->hint_y = rect.top; + } + + if (flags & GDK_HINT_MIN_SIZE) + { + rect.left = 0; + rect.top = 0; + rect.right = min_width; + rect.bottom = min_height; + dwStyle = GetWindowLong (private->drawable.xwindow, GWL_STYLE); + dwExStyle = GetWindowLong (private->drawable.xwindow, GWL_EXSTYLE); + AdjustWindowRectEx (&rect, dwStyle, FALSE, dwExStyle); + private->hint_min_width = rect.right - rect.left; + private->hint_min_height = rect.bottom - rect.top; + + /* Also chek if he current size of the window is in bounds. */ + GetClientRect (private->drawable.xwindow, &rect); + if (rect.right < min_width && rect.bottom < min_height) + gdk_window_resize (window, min_width, min_height); + else if (rect.right < min_width) + gdk_window_resize (window, min_width, rect.bottom); + else if (rect.bottom < min_height) + gdk_window_resize (window, rect.right, min_height); + } + if (flags & GDK_HINT_MAX_SIZE) + { + rect.left = 0; + rect.top = 0; + rect.right = max_width; + rect.bottom = max_height; + dwStyle = GetWindowLong (private->drawable.xwindow, GWL_STYLE); + dwExStyle = GetWindowLong (private->drawable.xwindow, GWL_EXSTYLE); + AdjustWindowRectEx (&rect, dwStyle, FALSE, dwExStyle); + private->hint_max_width = rect.right - rect.left; + private->hint_max_height = rect.bottom - rect.top; + /* Again, check if the window is too large currently. */ + GetClientRect (private->drawable.xwindow, &rect); + if (rect.right > max_width && rect.bottom > max_height) + gdk_window_resize (window, max_width, max_height); + else if (rect.right > max_width) + gdk_window_resize (window, max_width, rect.bottom); + else if (rect.bottom > max_height) + gdk_window_resize (window, rect.right, max_height); + } + } +} + +void +gdk_window_set_geometry_hints (GdkWindow *window, + GdkGeometry *geometry, + GdkWindowHints geom_mask) +{ + GdkWindowPrivate *private; + WINDOWPLACEMENT size_hints; + RECT rect; + DWORD dwStyle; + DWORD dwExStyle; + int diff; + + g_return_if_fail (window != NULL); + g_return_if_fail (GDK_IS_WINDOW (window)); + + if (GDK_DRAWABLE_DESTROYED (window)) + return; + + private = (GdkWindowPrivate*) window; + + size_hints.length = sizeof (size_hints); + + private->hint_flags = geom_mask; + + if (geom_mask & GDK_HINT_POS) + ; /* XXX */ + + if (geom_mask & GDK_HINT_MIN_SIZE) + { + rect.left = 0; + rect.top = 0; + rect.right = geometry->min_width; + rect.bottom = geometry->min_height; + dwStyle = GetWindowLong (private->drawable.xwindow, GWL_STYLE); + dwExStyle = GetWindowLong (private->drawable.xwindow, GWL_EXSTYLE); + AdjustWindowRectEx (&rect, dwStyle, FALSE, dwExStyle); + private->hint_min_width = rect.right - rect.left; + private->hint_min_height = rect.bottom - rect.top; + + /* Also check if he current size of the window is in bounds */ + GetClientRect (private->drawable.xwindow, &rect); + if (rect.right < geometry->min_width + && rect.bottom < geometry->min_height) + gdk_window_resize (window, geometry->min_width, geometry->min_height); + else if (rect.right < geometry->min_width) + gdk_window_resize (window, geometry->min_width, rect.bottom); + else if (rect.bottom < geometry->min_height) + gdk_window_resize (window, rect.right, geometry->min_height); + } + + if (geom_mask & GDK_HINT_MAX_SIZE) + { + rect.left = 0; + rect.top = 0; + rect.right = geometry->max_width; + rect.bottom = geometry->max_height; + dwStyle = GetWindowLong (private->drawable.xwindow, GWL_STYLE); + dwExStyle = GetWindowLong (private->drawable.xwindow, GWL_EXSTYLE); + AdjustWindowRectEx (&rect, dwStyle, FALSE, dwExStyle); + private->hint_max_width = rect.right - rect.left; + private->hint_max_height = rect.bottom - rect.top; + + /* Again, check if the window is too large currently. */ + GetClientRect (private->drawable.xwindow, &rect); + if (rect.right > geometry->max_width + && rect.bottom > geometry->max_height) + gdk_window_resize (window, geometry->max_width, geometry->max_height); + else if (rect.right > geometry->max_width) + gdk_window_resize (window, geometry->max_width, rect.bottom); + else if (rect.bottom > geometry->max_height) + gdk_window_resize (window, rect.right, geometry->max_height); + } + + /* I don't know what to do when called with zero base_width and height. */ + if (geom_mask & GDK_HINT_BASE_SIZE + && geometry->base_width > 0 + && geometry->base_height > 0) + if (!GetWindowPlacement (private->drawable.xwindow, &size_hints)) + g_warning ("gdk_window_set_hints: GetWindowPlacement failed"); + else + { + GDK_NOTE (MISC, g_print ("gdk_window_set_geometry_hints:" + " rcNormalPosition: (%d,%d)--(%d,%d)\n", + size_hints.rcNormalPosition.left, + size_hints.rcNormalPosition.top, + size_hints.rcNormalPosition.right, + size_hints.rcNormalPosition.bottom)); + size_hints.rcNormalPosition.right = + size_hints.rcNormalPosition.left + geometry->base_width; + size_hints.rcNormalPosition.bottom = + size_hints.rcNormalPosition.top + geometry->base_height; + GDK_NOTE (MISC, g_print ("...setting: rcNormal: (%d,%d)--(%d,%d)\n", + size_hints.rcNormalPosition.left, + size_hints.rcNormalPosition.top, + size_hints.rcNormalPosition.right, + size_hints.rcNormalPosition.bottom)); + if (!SetWindowPlacement (private->drawable.xwindow, &size_hints)) + g_warning ("gdk_window_set_hints: SetWindowPlacement failed"); + } + + if (geom_mask & GDK_HINT_RESIZE_INC) + { + /* XXX */ + } + + if (geom_mask & GDK_HINT_ASPECT) + { + /* XXX */ + } +} + +void +gdk_window_set_title (GdkWindow *window, + const gchar *title) +{ + gint titlelen; + wchar_t *wcstr; + gint wlen; + char *mbstr; + + g_return_if_fail (window != NULL); + g_return_if_fail (GDK_IS_WINDOW (window)); + + GDK_NOTE (MISC, g_print ("gdk_window_set_title: %#x %s\n", + GDK_DRAWABLE_XID (window), title)); + if (!GDK_DRAWABLE_DESTROYED (window)) + { + /* As the title most is in UTF-8 we must translate it + * to the system codepage. + */ + titlelen = strlen (title); + wcstr = g_new (wchar_t, titlelen + 1); + mbstr = g_new (char, 3*titlelen + 1); + wlen = gdk_nmbstowchar_ts (wcstr, title, titlelen, titlelen); + wcstr[wlen] = 0; + WideCharToMultiByte (GetACP (), 0, wcstr, -1, + mbstr, 3*titlelen, NULL, NULL); + + if (!SetWindowText (GDK_DRAWABLE_XID (window), mbstr)) + g_warning ("gdk_window_set_title: SetWindowText failed"); + + g_free (mbstr); + g_free (wcstr); + } +} + +void +gdk_window_set_role (GdkWindow *window, + const gchar *role) +{ + g_return_if_fail (window != NULL); + g_return_if_fail (GDK_IS_WINDOW (window)); + + GDK_NOTE (MISC, g_print ("gdk_window_set_role: %#x %s\n", + GDK_DRAWABLE_XID (window), (role ? role : "NULL"))); + /* XXX */ +} + +void +gdk_window_set_transient_for (GdkWindow *window, + GdkWindow *parent) +{ + g_return_if_fail (window != NULL); + g_return_if_fail (GDK_IS_WINDOW (window)); + + GDK_NOTE (MISC, g_print ("gdk_window_set_transient_for: %#x %#x\n", + GDK_DRAWABLE_XID (window), + GDK_DRAWABLE_XID (parent))); + /* XXX */ +} + +void +gdk_window_set_background (GdkWindow *window, + GdkColor *color) +{ + GdkWindowPrivate *private; + + g_return_if_fail (window != NULL); + g_return_if_fail (GDK_IS_WINDOW (window)); + + private = (GdkWindowPrivate*) window; + if (!GDK_DRAWABLE_DESTROYED (window)) + { + GDK_NOTE (MISC, g_print ("gdk_window_set_background: %#x %s\n", + private->drawable.xwindow, + gdk_color_to_string (color))); + + if (private->bg_type == GDK_WIN32_BG_PIXMAP) + { + if (private->bg_pixmap != NULL) + { + gdk_pixmap_unref (private->bg_pixmap); + private->bg_pixmap = NULL; + } + private->bg_type = GDK_WIN32_BG_NORMAL; + } + private->bg_type = GDK_WIN32_BG_PIXEL; + private->bg_pixel = *color; + } +} + +void +gdk_window_set_back_pixmap (GdkWindow *window, + GdkPixmap *pixmap, + gint parent_relative) +{ + GdkWindowPrivate *private; + + g_return_if_fail (window != NULL); + g_return_if_fail (GDK_IS_WINDOW (window)); + + private = (GdkWindowPrivate*) window; + + if (!GDK_DRAWABLE_DESTROYED (window)) + { + if (private->bg_type == GDK_WIN32_BG_PIXMAP) + { + if (private->bg_pixmap != NULL) + { + gdk_pixmap_unref (private->bg_pixmap); + private->bg_pixmap = NULL; + } + private->bg_type = GDK_WIN32_BG_NORMAL; + } + if (parent_relative) + { + private->bg_type = GDK_WIN32_BG_PARENT_RELATIVE; + } + else if (!pixmap) + { + + } + else + { + /* We must cache the pixmap in the WindowPrivate and + * paint it each time we get WM_ERASEBKGND + */ + private->bg_type = GDK_WIN32_BG_PIXMAP; + private->bg_pixmap = pixmap; + gdk_pixmap_ref (pixmap); + } + } +} + +void +gdk_window_set_cursor (GdkWindow *window, + GdkCursor *cursor) +{ + GdkWindowPrivate *window_private; + GdkCursorPrivate *cursor_private; + HCURSOR xcursor; + + g_return_if_fail (window != NULL); + g_return_if_fail (GDK_IS_WINDOW (window)); + + window_private = (GdkWindowPrivate*) window; + cursor_private = (GdkCursorPrivate*) cursor; + + if (!GDK_DRAWABLE_DESTROYED (window)) + { + if (!cursor) + xcursor = LoadCursor (NULL, IDC_ARROW); + else + xcursor = cursor_private->xcursor; + + GDK_NOTE (MISC, g_print ("gdk_window_set_cursor: %#x %#x\n", + window_private->drawable.xwindow, xcursor)); + window_private->xcursor = xcursor; + } +} + +void +gdk_window_get_user_data (GdkWindow *window, + gpointer *data) +{ + g_return_if_fail (window != NULL); + + *data = window->user_data; +} + +void +gdk_window_get_geometry (GdkWindow *window, + gint *x, + gint *y, + gint *width, + gint *height, + gint *depth) +{ + g_return_if_fail (window == NULL || GDK_IS_WINDOW (window)); + + if (!window) + window = (GdkWindow*) gdk_root_parent; + + if (!GDK_DRAWABLE_DESTROYED (window)) + { + RECT rect; + + if (!GetClientRect (GDK_DRAWABLE_XID (window), &rect)) + g_warning ("gdk_window_get_geometry: GetClientRect failed"); + + if (x) + *x = rect.left; + if (y) + *y = rect.top; + if (width) + *width = rect.right - rect.left; + if (height) + *height = rect.bottom - rect.top; + if (depth) + *depth = gdk_drawable_get_visual (window)->depth; + } +} + +void +gdk_window_get_position (GdkWindow *window, + gint *x, + gint *y) +{ + GdkWindowPrivate *window_private; + + g_return_if_fail (window != NULL); + g_return_if_fail (GDK_IS_WINDOW (window)); + + window_private = (GdkWindowPrivate*) window; + + if (x) + *x = window_private->x; + if (y) + *y = window_private->y; +} + +gint +gdk_window_get_origin (GdkWindow *window, + gint *x, + gint *y) +{ + gint return_val; + gint tx = 0; + gint ty = 0; + + g_return_val_if_fail (window != NULL, 0); + + if (!GDK_DRAWABLE_DESTROYED (window)) + { + POINT pt; + + pt.x = 0; + pt.y = 0; + ClientToScreen (GDK_DRAWABLE_XID (window), &pt); + tx = pt.x; + ty = pt.y; + return_val = 1; + } + else + return_val = 0; + + if (x) + *x = tx; + if (y) + *y = ty; + + GDK_NOTE (MISC, g_print ("gdk_window_get_origin: %#x: +%d+%d\n", + GDK_DRAWABLE_XID (window), tx, ty)); + return return_val; +} + +gboolean +gdk_window_get_deskrelative_origin (GdkWindow *window, + gint *x, + gint *y) +{ + return gdk_window_get_origin (window, x, y); +} + +void +gdk_window_get_root_origin (GdkWindow *window, + gint *x, + gint *y) +{ + GdkWindowPrivate *private; + POINT pt; + + g_return_if_fail (window != NULL); + g_return_if_fail (GDK_IS_WINDOW (window)); + + private = (GdkWindowPrivate*) window; + if (x) + *x = 0; + if (y) + *y = 0; + if (GDK_DRAWABLE_DESTROYED (window)) + return; + + while (private->parent && ((GdkWindowPrivate*) private->parent)->parent) + private = (GdkWindowPrivate*) private->parent; + if (private->drawable.destroyed) + return; + + pt.x = 0; + pt.y = 0; + ClientToScreen (private->drawable.xwindow, &pt); + if (x) + *x = pt.x; + if (y) + *y = pt.y; + + GDK_NOTE (MISC, g_print ("gdk_window_get_root_origin: %#x: (%#x) +%d+%d\n", + GDK_DRAWABLE_XID (window), + private->drawable.xwindow, pt.x, pt.y)); +} + +GdkWindow* +gdk_window_get_pointer (GdkWindow *window, + gint *x, + gint *y, + GdkModifierType *mask) +{ + GdkWindow *return_val; + POINT pointc, point; + HWND hwnd, hwndc; + + g_return_val_if_fail (window == NULL || GDK_IS_WINDOW (window), NULL); + + if (!window) + window = (GdkWindow*) gdk_root_parent; + + return_val = NULL; + GetCursorPos (&pointc); + point = pointc; + ScreenToClient (GDK_DRAWABLE_XID (window), &point); + + if (x) + *x = point.x; + if (y) + *y = point.y; + + hwnd = WindowFromPoint (point); + point = pointc; + ScreenToClient (hwnd, &point); + + do { + hwndc = ChildWindowFromPoint (hwnd, point); + ClientToScreen (hwnd, &point); + ScreenToClient (hwndc, &point); + } while (hwndc != hwnd && (hwnd = hwndc, 1)); /* Ouch! */ + + return_val = gdk_window_lookup (hwnd); + + if (mask) + { + BYTE kbd[256]; + + GetKeyboardState (kbd); + *mask = 0; + if (kbd[VK_SHIFT] & 0x80) + *mask |= GDK_SHIFT_MASK; + if (kbd[VK_CAPITAL] & 0x80) + *mask |= GDK_LOCK_MASK; + if (kbd[VK_CONTROL] & 0x80) + *mask |= GDK_CONTROL_MASK; + if (kbd[VK_MENU] & 0x80) + *mask |= GDK_MOD1_MASK; + if (kbd[VK_LBUTTON] & 0x80) + *mask |= GDK_BUTTON1_MASK; + if (kbd[VK_MBUTTON] & 0x80) + *mask |= GDK_BUTTON2_MASK; + if (kbd[VK_RBUTTON] & 0x80) + *mask |= GDK_BUTTON3_MASK; + } + + return return_val; +} + +GdkWindow* +gdk_window_at_pointer (gint *win_x, + gint *win_y) +{ + GdkWindow *window; + POINT point, pointc; + HWND hwnd, hwndc; + RECT rect; + + GetCursorPos (&pointc); + point = pointc; + hwnd = WindowFromPoint (point); + + if (hwnd == NULL) + { + window = (GdkWindow *) gdk_root_parent; + if (win_x) + *win_x = pointc.x; + if (win_y) + *win_y = pointc.y; + return window; + } + + ScreenToClient (hwnd, &point); + + do { + hwndc = ChildWindowFromPoint (hwnd, point); + ClientToScreen (hwnd, &point); + ScreenToClient (hwndc, &point); + } while (hwndc != hwnd && (hwnd = hwndc, 1)); + + window = gdk_window_lookup (hwnd); + + if (window && (win_x || win_y)) + { + GetClientRect (hwnd, &rect); + if (win_x) + *win_x = point.x - rect.left; + if (win_y) + *win_y = point.y - rect.top; + } + + GDK_NOTE (MISC, g_print ("gdk_window_at_pointer: +%d+%d %#x%s\n", + point.x, point.y, hwnd, + (window == NULL ? " NULL" : ""))); + + return window; +} + +GdkWindow* +gdk_window_get_parent (GdkWindow *window) +{ + g_return_val_if_fail (window != NULL, NULL); + g_return_val_if_fail (GDK_IS_WINDOW (window), NULL); + + return ((GdkWindowPrivate*) window)->parent; +} + +GdkWindow* +gdk_window_get_toplevel (GdkWindow *window) +{ + g_return_val_if_fail (window != NULL, NULL); + g_return_val_if_fail (GDK_IS_WINDOW (window), NULL); + + while (GDK_DRAWABLE_TYPE (window) == GDK_WINDOW_CHILD) + window = ((GdkWindowPrivate*) window)->parent; + + return window; +} + +GList* +gdk_window_get_children (GdkWindow *window) +{ + GdkWindowPrivate *private; + GList *children; + + g_return_val_if_fail (window != NULL, NULL); + g_return_val_if_fail (GDK_IS_WINDOW (window), NULL); + + if (GDK_DRAWABLE_DESTROYED (window)) + return NULL; + + /* XXX ??? */ + g_warning ("gdk_window_get_children not implemented"); + children = NULL; + + return children; +} + +GdkEventMask +gdk_window_get_events (GdkWindow *window) +{ + GdkWindowPrivate *private; + + g_return_val_if_fail (window != NULL, 0); + g_return_val_if_fail (GDK_IS_WINDOW (window), 0); + + private = (GdkWindowPrivate*) window; + if (GDK_DRAWABLE_DESTROYED (window)) + return 0; + + return private->event_mask; +} + +void +gdk_window_set_events (GdkWindow *window, + GdkEventMask event_mask) +{ + GdkWindowPrivate *private; + + g_return_if_fail (window != NULL); + g_return_if_fail (GDK_IS_WINDOW (window)); + + private = (GdkWindowPrivate*) window; + if (GDK_DRAWABLE_DESTROYED (window)) + return; + + private->event_mask = event_mask; +} + +void +gdk_window_add_colormap_windows (GdkWindow *window) +{ + g_warning ("gdk_window_add_colormap_windows not implemented"); +} + +void +gdk_window_shape_combine_mask (GdkWindow *window, + GdkBitmap *mask, + gint x, gint y) +{ + g_return_if_fail (window != NULL); + g_return_if_fail (GDK_IS_WINDOW (window)); + + if (!mask) + { + GDK_NOTE (MISC, g_print ("gdk_window_shape_combine_mask: %#x none\n", + GDK_DRAWABLE_XID (window))); + SetWindowRgn (GDK_DRAWABLE_XID (window), NULL, TRUE); + } + else + { + GdkDrawablePrivate *pixmap_private; + HRGN hrgn; + DWORD dwStyle; + DWORD dwExStyle; + RECT rect; + + /* Convert mask bitmap to region */ + pixmap_private = (GdkDrawablePrivate*) mask; + hrgn = BitmapToRegion (pixmap_private->xwindow); + + GDK_NOTE (MISC, g_print ("gdk_window_shape_combine_mask: %#x %#x\n", + GDK_DRAWABLE_XID (window), + pixmap_private->xwindow)); + + /* SetWindowRgn wants window (not client) coordinates */ + dwStyle = GetWindowLong (GDK_DRAWABLE_XID (window), GWL_STYLE); + dwExStyle = GetWindowLong (GDK_DRAWABLE_XID (window), GWL_EXSTYLE); + GetClientRect (GDK_DRAWABLE_XID (window), &rect); + AdjustWindowRectEx (&rect, dwStyle, FALSE, dwExStyle); + OffsetRgn (hrgn, -rect.left, -rect.top); + + OffsetRgn (hrgn, x, y); + + /* If this is a top-level window, add the title bar to the region */ + if (GDK_DRAWABLE_TYPE (window) == GDK_WINDOW_TOPLEVEL) + { + CombineRgn (hrgn, hrgn, + CreateRectRgn (0, 0, rect.right - rect.left, -rect.top), + RGN_OR); + } + + SetWindowRgn (GDK_DRAWABLE_XID (window), hrgn, TRUE); + } +} + +void +gdk_window_add_filter (GdkWindow *window, + GdkFilterFunc function, + gpointer data) +{ + GdkWindowPrivate *private; + GList *tmp_list; + GdkEventFilter *filter; + + g_return_if_fail (window != NULL); + g_return_if_fail (GDK_IS_WINDOW (window)); + + private = (GdkWindowPrivate*) window; + if (private && GDK_DRAWABLE_DESTROYED (window)) + return; + + tmp_list = private->filters; + + while (tmp_list) + { + filter = (GdkEventFilter *)tmp_list->data; + if ((filter->function == function) && (filter->data == data)) + return; + tmp_list = tmp_list->next; + } + + filter = g_new (GdkEventFilter, 1); + filter->function = function; + filter->data = data; + + private->filters = g_list_append (private->filters, filter); +} + +void +gdk_window_remove_filter (GdkWindow *window, + GdkFilterFunc function, + gpointer data) +{ + GdkWindowPrivate *private; + GList *tmp_list, *node; + GdkEventFilter *filter; + + g_return_if_fail (window != NULL); + g_return_if_fail (GDK_IS_WINDOW (window)); + + private = (GdkWindowPrivate*) window; + + tmp_list = private->filters; + + while (tmp_list) + { + filter = (GdkEventFilter *)tmp_list->data; + node = tmp_list; + tmp_list = tmp_list->next; + + if ((filter->function == function) && (filter->data == data)) + { + private->filters = g_list_remove_link (private->filters, node); + + g_list_free_1 (node); + g_free (filter); + + return; + } + } +} + +void +gdk_window_set_override_redirect (GdkWindow *window, + gboolean override_redirect) +{ + g_return_if_fail (window != NULL); + g_return_if_fail (GDK_IS_WINDOW (window)); + + g_warning ("gdk_window_set_override_redirect not implemented"); +} + +void +gdk_window_set_icon (GdkWindow *window, + GdkWindow *icon_window, + GdkPixmap *pixmap, + GdkBitmap *mask) +{ + g_return_if_fail (window != NULL); + g_return_if_fail (GDK_IS_WINDOW (window)); + + if (GDK_DRAWABLE_DESTROYED (window)) + return; + + g_warning ("gdk_window_set_icon not implemented"); +} + +void +gdk_window_set_icon_name (GdkWindow *window, + gchar *name) +{ + g_return_if_fail (window != NULL); + g_return_if_fail (GDK_IS_WINDOW (window)); + + if (GDK_DRAWABLE_DESTROYED (window)) + return; + + if (!SetWindowText (GDK_DRAWABLE_XID (window), name)) + g_warning ("gdk_window_set_icon_name: SetWindowText failed"); +} + +void +gdk_window_set_group (GdkWindow *window, + GdkWindow *leader) +{ + g_return_if_fail (window != NULL); + g_return_if_fail (GDK_IS_WINDOW (window)); + g_return_if_fail (leader != NULL); + g_return_if_fail (GDK_IS_WINDOW (leader)); + + if (GDK_DRAWABLE_DESTROYED (window) || GDK_DRAWABLE_DESTROYED (leader)) + return; + + g_warning ("gdk_window_set_group not implemented"); +} + +void +gdk_window_set_decorations (GdkWindow *window, + GdkWMDecoration decorations) +{ + LONG style, exstyle; + + g_return_if_fail (window != NULL); + g_return_if_fail (GDK_IS_WINDOW (window)); + + style = GetWindowLong (GDK_DRAWABLE_XID (window), GWL_STYLE); + exstyle = GetWindowLong (GDK_DRAWABLE_XID (window), GWL_EXSTYLE); + + style &= (WS_OVERLAPPED|WS_POPUP|WS_CHILD|WS_MINIMIZE|WS_VISIBLE|WS_DISABLED + |WS_CLIPSIBLINGS|WS_CLIPCHILDREN|WS_MAXIMIZE); + + exstyle &= (WS_EX_TOPMOST|WS_EX_TRANSPARENT); + + if (decorations & GDK_DECOR_ALL) + style |= (WS_CAPTION|WS_SYSMENU|WS_THICKFRAME|WS_MINIMIZEBOX|WS_MAXIMIZEBOX); + if (decorations & GDK_DECOR_BORDER) + style |= (WS_BORDER); + if (decorations & GDK_DECOR_RESIZEH) + style |= (WS_THICKFRAME); + if (decorations & GDK_DECOR_TITLE) + style |= (WS_CAPTION); + if (decorations & GDK_DECOR_MENU) + style |= (WS_SYSMENU); + if (decorations & GDK_DECOR_MINIMIZE) + style |= (WS_MINIMIZEBOX); + if (decorations & GDK_DECOR_MAXIMIZE) + style |= (WS_MAXIMIZEBOX); + + SetWindowLong (GDK_DRAWABLE_XID (window), GWL_STYLE, style); +} + +void +gdk_window_set_functions (GdkWindow *window, + GdkWMFunction functions) +{ + LONG style, exstyle; + + g_return_if_fail (window != NULL); + g_return_if_fail (GDK_IS_WINDOW (window)); + + style = GetWindowLong (GDK_DRAWABLE_XID (window), GWL_STYLE); + exstyle = GetWindowLong (GDK_DRAWABLE_XID (window), GWL_EXSTYLE); + + style &= (WS_OVERLAPPED|WS_POPUP|WS_CHILD|WS_MINIMIZE|WS_VISIBLE|WS_DISABLED + |WS_CLIPSIBLINGS|WS_CLIPCHILDREN|WS_MAXIMIZE|WS_CAPTION|WS_BORDER + |WS_SYSMENU); + + exstyle &= (WS_EX_TOPMOST|WS_EX_TRANSPARENT); + + if (functions & GDK_FUNC_ALL) + style |= (WS_THICKFRAME|WS_MINIMIZEBOX|WS_MAXIMIZEBOX); + if (functions & GDK_FUNC_RESIZE) + style |= (WS_THICKFRAME); + if (functions & GDK_FUNC_MOVE) + style |= (WS_THICKFRAME); + if (functions & GDK_FUNC_MINIMIZE) + style |= (WS_MINIMIZEBOX); + if (functions & GDK_FUNC_MAXIMIZE) + style |= (WS_MAXIMIZEBOX); + + SetWindowLong (GDK_DRAWABLE_XID (window), GWL_STYLE, style); +} + +GList * +gdk_window_get_toplevels (void) +{ + GList *new_list = NULL; + GList *tmp_list; + + tmp_list = gdk_root_parent->children; + while (tmp_list) + { + new_list = g_list_prepend (new_list, tmp_list->data); + tmp_list = tmp_list->next; + } + + return new_list; +} + +/* + * propagate the shapes from all child windows of a GDK window to the parent + * window. Shamelessly ripped from Enlightenment's code + * + * - Raster + */ + +static void +QueryTree (HWND hwnd, + HWND **children, + gint *nchildren) +{ + guint i, n; + HWND child; + + n = 0; + do { + if (n == 0) + child = GetWindow (hwnd, GW_CHILD); + else + child = GetWindow (child, GW_HWNDNEXT); + if (child != NULL) + n++; + } while (child != NULL); + + if (n > 0) + { + *children = g_new (HWND, n); + for (i = 0; i < n; i++) + { + if (i == 0) + child = GetWindow (hwnd, GW_CHILD); + else + child = GetWindow (child, GW_HWNDNEXT); + *children[i] = child; + } + } +} + +static void +gdk_propagate_shapes (HANDLE win, + gboolean merge) +{ + RECT emptyRect; + HRGN region, childRegion; + RECT rect; + HWND *list = NULL; + gint i, num; + + SetRectEmpty (&emptyRect); + region = CreateRectRgnIndirect (&emptyRect); + if (merge) + GetWindowRgn (win, region); + + QueryTree (win, &list, &num); + if (list != NULL) + { + WINDOWPLACEMENT placement; + + placement.length = sizeof (WINDOWPLACEMENT); + /* go through all child windows and combine regions */ + for (i = 0; i < num; i++) + { + GetWindowPlacement (list[i], &placement); + if (placement.showCmd = SW_SHOWNORMAL) + { + childRegion = CreateRectRgnIndirect (&emptyRect); + GetWindowRgn (list[i], childRegion); + CombineRgn (region, region, childRegion, RGN_OR); + DeleteObject (childRegion); + } + } + SetWindowRgn (win, region, TRUE); + } + else + DeleteObject (region); +} + +void +gdk_window_set_child_shapes (GdkWindow *window) +{ + g_return_if_fail (window != NULL); + g_return_if_fail (GDK_IS_WINDOW (window)); + + if (GDK_DRAWABLE_DESTROYED (window)) + return; + + gdk_propagate_shapes (GDK_DRAWABLE_XID (window), FALSE); +} + +void +gdk_window_merge_child_shapes (GdkWindow *window) +{ + g_return_if_fail (window != NULL); + g_return_if_fail (GDK_IS_WINDOW (window)); + + if (GDK_DRAWABLE_DESTROYED (window)) + return; + + gdk_propagate_shapes (GDK_DRAWABLE_XID (window), TRUE); +} + +/************************************************************* + * gdk_window_is_visible: + * Check if the given window is mapped. + * arguments: + * window: + * results: + * is the window mapped + *************************************************************/ + +gboolean +gdk_window_is_visible (GdkWindow *window) +{ + GdkWindowPrivate *private = (GdkWindowPrivate *)window; + + g_return_val_if_fail (window != NULL, FALSE); + g_return_val_if_fail (GDK_IS_WINDOW (window), FALSE); + + return private->mapped; +} + +/************************************************************* + * gdk_window_is_viewable: + * Check if the window and all ancestors of the window + * are mapped. (This is not necessarily "viewable" in + * the X sense, since we only check as far as we have + * GDK window parents, not to the root window) + * arguments: + * window: + * results: + * is the window viewable + *************************************************************/ + +gboolean +gdk_window_is_viewable (GdkWindow *window) +{ + GdkWindowPrivate *private = (GdkWindowPrivate *)window; + + g_return_val_if_fail (window != NULL, FALSE); + g_return_val_if_fail (GDK_IS_WINDOW (window), FALSE); + + while (private && + (private != gdk_root_parent) && + (private->drawable.window_type != GDK_WINDOW_FOREIGN)) + { + if (!private->mapped) + return FALSE; + + private = (GdkWindowPrivate *)private->parent; + } + + return TRUE; +} + +/* Support for windows that can be guffaw-scrolled + * (See http://www.gtk.org/~otaylor/whitepapers/guffaw-scrolling.txt) + */ + +static gboolean +gdk_window_gravity_works (void) +{ + enum { UNKNOWN, NO, YES }; + static gint gravity_works = UNKNOWN; + + if (gravity_works == UNKNOWN) + { + GdkWindowAttr attr; + GdkWindow *parent; + GdkWindow *child; + gint y; + + attr.window_type = GDK_WINDOW_TEMP; + attr.wclass = GDK_INPUT_OUTPUT; + attr.x = 0; + attr.y = 0; + attr.width = 100; + attr.height = 100; + attr.event_mask = 0; + + parent = gdk_window_new (NULL, &attr, GDK_WA_X | GDK_WA_Y); + + attr.window_type = GDK_WINDOW_CHILD; + child = gdk_window_new (parent, &attr, GDK_WA_X | GDK_WA_Y); + + gdk_window_set_static_win_gravity (child, TRUE); + + gdk_window_resize (parent, 100, 110); + gdk_window_move (parent, 0, -10); + gdk_window_move_resize (parent, 0, 0, 100, 100); + + gdk_window_resize (parent, 100, 110); + gdk_window_move (parent, 0, -10); + gdk_window_move_resize (parent, 0, 0, 100, 100); + + gdk_window_get_geometry (child, NULL, &y, NULL, NULL, NULL); + + gdk_window_destroy (parent); + gdk_window_destroy (child); + + gravity_works = ((y == -20) ? YES : NO); + } + + return (gravity_works == YES); +} + +static void +gdk_window_set_static_bit_gravity (GdkWindow *window, gboolean on) +{ + g_return_if_fail (window != NULL); + + GDK_NOTE (MISC, g_print ("gdk_window_set_static_bit_gravity: Not implemented\n")); +} + +static void +gdk_window_set_static_win_gravity (GdkWindow *window, gboolean on) +{ + g_return_if_fail (window != NULL); + + GDK_NOTE (MISC, + g_print ("gdk_window_set_static_win_gravity: Not implemented\n")); +} + +/************************************************************* + * gdk_window_set_static_gravities: + * Set the bit gravity of the given window to static, + * and flag it so all children get static subwindow + * gravity. + * arguments: + * window: window for which to set static gravity + * use_static: Whether to turn static gravity on or off. + * results: + * Does the XServer support static gravity? + *************************************************************/ + +gboolean +gdk_window_set_static_gravities (GdkWindow *window, + gboolean use_static) +{ + GdkWindowPrivate *private = (GdkWindowPrivate *)window; + GList *tmp_list; + + g_return_val_if_fail (window != NULL, FALSE); + g_return_val_if_fail (GDK_IS_WINDOW (window), FALSE); + + if (!use_static == !private->guffaw_gravity) + return TRUE; + + if (use_static && !gdk_window_gravity_works ()) + return FALSE; + + private->guffaw_gravity = use_static; + + if (!GDK_DRAWABLE_DESTROYED (window)) + { + gdk_window_set_static_bit_gravity (window, use_static); + + tmp_list = private->children; + while (tmp_list) + { + gdk_window_set_static_win_gravity (window, use_static); + + tmp_list = tmp_list->next; + } + } + + return TRUE; +} -- 2.43.2