--- /dev/null
+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
--- /dev/null
+/* 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+#include <io.h>
+
+#include "gdk.h"
+#include "gdkprivate.h"
+#include "gdkinputprivate.h"
+#include "gdkkeysyms.h"
+
+#include <objbase.h>
+
+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 ("<unknown>");
+ }
+
+ 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 ();
+}
--- /dev/null
+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
--- /dev/null
+/* 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 <string.h>
+
+/* #define OLE2_DND */
+
+#define INITGUID
+
+#include "gdkdnd.h"
+#include "gdkproperty.h"
+#include "gdkprivate.h"
+#include "gdkx.h"
+
+#ifdef OLE2_DND
+#include <ole2.h>
+#else
+#include <objbase.h>
+#endif
+
+#ifdef _MSC_VER /* These aren't in mingw32 */
+#include <shlobj.h>
+#include <shlguid.h>
+#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 <gdk/gdk.h>
+
+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;
+}
--- /dev/null
+/* 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 <string.h>
+
+/* #define OLE2_DND */
+
+#define INITGUID
+
+#include "gdkdnd.h"
+#include "gdkproperty.h"
+#include "gdkprivate.h"
+#include "gdkx.h"
+
+#ifdef OLE2_DND
+#include <ole2.h>
+#else
+#include <objbase.h>
+#endif
+
+#ifdef _MSC_VER /* These aren't in mingw32 */
+#include <shlobj.h>
+#include <shlguid.h>
+#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 <gdk/gdk.h>
+
+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;
+}
--- /dev/null
+/* 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 <math.h>
+
+#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);
+}
--- /dev/null
+/* 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 <math.h>
+
+#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);
+}
--- /dev/null
+/* 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 <stdio.h>
+
+#include <windows.h>
+
+#include <objbase.h>
+#include <imm.h>
+
+#ifdef HAVE_DIMM_H
+#include <dimm.h>
+#else
+#include "surrogate-dimm.h"
+#endif
+
+#ifdef HAVE_WINTAB
+#include <wintab.h>
+#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 <colanton@aris.ss.uci.edu> 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 <mkuhn@acm.org> 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 */
+}
+
--- /dev/null
+/* 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 <stdio.h>
+
+#include <windows.h>
+
+#include <objbase.h>
+#include <imm.h>
+
+#ifdef HAVE_DIMM_H
+#include <dimm.h>
+#else
+#include "surrogate-dimm.h"
+#endif
+
+#ifdef HAVE_WINTAB
+#include <wintab.h>
+#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 <colanton@aris.ss.uci.edu> 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 <mkuhn@acm.org> 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 */
+}
+
--- /dev/null
+/* 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 <stdio.h>
+#include <ctype.h>
+
+#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);
+}
--- /dev/null
+/* 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 <stdio.h>
+#include <ctype.h>
+
+#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);
+}
--- /dev/null
+/* 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 <string.h>
+
+#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;
+}
--- /dev/null
+/* 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 <string.h>
+
+#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;
+}
--- /dev/null
+/* 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;
--- /dev/null
+/* 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;
--- /dev/null
+/* 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 <config.h>
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+
+#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;
+}
+
--- /dev/null
+/* 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 <config.h>
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+
+#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;
+}
+
--- /dev/null
+/* 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 <stdlib.h>
+#include <stdio.h>
+#include <math.h>
+
+#include "gdk.h"
+#include "gdkinput.h"
+#include "gdkprivate.h"
+#include "gdkx.h"
+
+#ifdef HAVE_WINTAB
+#include <wintab.h>
+#define PACKETDATA (PK_CONTEXT | PK_CURSOR | PK_BUTTONS | PK_X | PK_Y | PK_NORMAL_PRESSURE | PK_ORIENTATION)
+#define PACKETMODE (PK_BUTTONS)
+#include <pktdef.h>
+#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);
+}
--- /dev/null
+/* 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 <stdlib.h>
+#include <stdio.h>
+#include <math.h>
+
+#include "gdk.h"
+#include "gdkinput.h"
+#include "gdkprivate.h"
+#include "gdkx.h"
+
+#ifdef HAVE_WINTAB
+#include <wintab.h>
+#define PACKETDATA (PK_CONTEXT | PK_CURSOR | PK_BUTTONS | PK_X | PK_Y | PK_NORMAL_PRESSURE | PK_ORIENTATION)
+#define PACKETMODE (PK_BUTTONS)
+#include <pktdef.h>
+#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);
+}
--- /dev/null
+/* 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+#include <io.h>
+
+#include "gdk.h"
+#include "gdkprivate.h"
+#include "gdkinputprivate.h"
+#include "gdkkeysyms.h"
+
+#include <objbase.h>
+
+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 ("<unknown>");
+ }
+
+ 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 ();
+}
--- /dev/null
+/* 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 <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#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; i<info->ncolors; 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);
+}
--- /dev/null
+/* 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 <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#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; i<info->ncolors; 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);
+}
--- /dev/null
+/* 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 <windows.h>
+#include <commctrl.h>
+
+/* 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 <time.h>
+
+#include <gdk/gdktypes.h>
+
+#include <gdk/gdkcursor.h>
+#include <gdk/gdkevents.h>
+#include <gdk/gdkfont.h>
+#include <gdk/gdkgc.h>
+#include <gdk/gdkim.h>
+#include <gdk/gdkimage.h>
+#include <gdk/gdkregion.h>
+#include <gdk/gdkvisual.h>
+#include <gdk/gdkwindow.h>
+
+#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__ */
--- /dev/null
+/* 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 <windows.h>
+#include <commctrl.h>
+
+/* 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 <time.h>
+
+#include <gdk/gdktypes.h>
+
+#include <gdk/gdkcursor.h>
+#include <gdk/gdkevents.h>
+#include <gdk/gdkfont.h>
+#include <gdk/gdkgc.h>
+#include <gdk/gdkim.h>
+#include <gdk/gdkimage.h>
+#include <gdk/gdkregion.h>
+#include <gdk/gdkvisual.h>
+#include <gdk/gdkwindow.h>
+
+#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__ */
--- /dev/null
+/* 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 <string.h>
+
+#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");
+}
--- /dev/null
+/* 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 <string.h>
+
+#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");
+}
--- /dev/null
+/* 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;
+}
--- /dev/null
+/* 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;
+}
--- /dev/null
+/* 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 <string.h>
+
+#include <gdk/gdk.h>
+#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");
+}
--- /dev/null
+/* 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 <string.h>
+
+#include <gdk/gdk.h>
+#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");
+}
--- /dev/null
+/* 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;
+ }
+}
--- /dev/null
+/* 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;
+ }
+}
--- /dev/null
+/* 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 <stdlib.h>
+#include <stdio.h>
+
+#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 <raster@redhat.com>
+ * 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_<H,V>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;
+}
--- /dev/null
+/* 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 <stdlib.h>
+#include <stdio.h>
+
+#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 <raster@redhat.com>
+ * 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_<H,V>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;
+}