diff options
author | Tor Lillqvist <tml@src.gnome.org> | 1999-03-05 19:53:56 +0000 |
---|---|---|
committer | Tor Lillqvist <tml@src.gnome.org> | 1999-03-05 19:53:56 +0000 |
commit | 9f3b82e178d58786d754d814512db515b6c2f155 (patch) | |
tree | 1e92fa1cf0c05f5dad6744c0d802c20c16fb4962 /gdk | |
parent | ced58eb136565ad03326277a5248467dd9fe8eb3 (diff) | |
download | gdk-pixbuf-9f3b82e178d58786d754d814512db515b6c2f155.tar.gz |
Win32 version of GDK source files and resource files (cursors and icons).
Diffstat (limited to 'gdk')
127 files changed, 46985 insertions, 0 deletions
diff --git a/gdk/win32/gdk.c b/gdk/win32/gdk.c new file mode 100644 index 000000000..0586516e2 --- /dev/null +++ b/gdk/win32/gdk.c @@ -0,0 +1,2237 @@ +/* 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 "gdkinput.h" +#include "gdkx.h" +#include "gdkkeysyms.h" +#include "gdki18n.h" + +static void gdkx_XConvertCase (KeySym symbol, + KeySym *lower, + KeySym *upper); +#define XConvertCase gdkx_XConvertCase + +static void gdk_exit_func (void); + +static RETSIGTYPE gdk_signal (int signum); + + +/* Private variable declarations + */ +static int gdk_initialized = 0; /* 1 if the library is initialized, + * 0 otherwise. + */ +static guint start; /* We use the millisecond + * timestamps from GetTickCount + */ +static gboolean timerp = TRUE; /* If TRUE use timeouts when waiting + * for Windows messages + */ +static guint32 timer_val = 20; /* Timeout in milliseconds. + */ + +#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) +{ + HRESULT hres; + gint i, j, k; + + if (gdk_initialized) + return TRUE; + + if (g_thread_supported ()) + gdk_threads_mutex = g_mutex_new (); + + start = GetTickCount (); + +#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 (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; + } + 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_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]); + + gdk_root_window = HWND_DESKTOP; + + 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 (int 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_time_get + * + * Get the number of milliseconds since the library was + * initialized. + * + * Arguments: + * + * Results: + * The time since the library was initialized is returned. + * This time value is accurate to milliseconds even though + * a more accurate time down to the microsecond could be + * returned. + * + * Side effects: + * + *-------------------------------------------------------------- + */ + +guint32 +gdk_time_get (void) +{ + guint32 milliseconds; + guint32 end = GetTickCount (); + + if (end < start) + milliseconds = 0xFFFFFFFF - (start - end) + 1; + else + milliseconds = end - start; + + return milliseconds; +} + +/* + *-------------------------------------------------------------- + * gdk_timer_get + * + * Returns the current timer. + * + * Arguments: + * + * Results: + * Returns the current timer interval. This interval is + * in units of milliseconds. + * + * Side effects: + * + *-------------------------------------------------------------- + */ + +guint32 +gdk_timer_get (void) +{ + return timer_val; +} + +/* + *-------------------------------------------------------------- + * gdk_timer_set + * + * Sets the timer interval. + * + * Arguments: + * "milliseconds" is the new value for the timer. + * + * Results: + * + * Side effects: + * Calls to "gdk_event_get" will last for a maximum + * of time of "milliseconds". However, a value of 0 + * milliseconds will cause "gdk_event_get" to block + * indefinately until an event is received. + * + *-------------------------------------------------------------- + */ + +void +gdk_timer_set (guint32 milliseconds) +{ + timer_val = milliseconds; +#ifdef USE_PEEKNAMEDPIPE + /* When using PeekNamedPipe, can't have too long timeouts. + */ + if (timer_val > 10) + timer_val = 10; + else if (timer_val == 0) + timer_val = 0; +#endif +} + +void +gdk_timer_enable (void) +{ + timerp = TRUE; +} + +void +gdk_timer_disable (void) +{ +#ifdef USE_PEEKNAMEDPIPE + /* Can't disable timeouts when using PeekNamedPipe */ +#else + timerp = FALSE; +#endif +} + +/* + *-------------------------------------------------------------- + * 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.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.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 (); + 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" }, + { 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" }, + { 0x00FF3C, "SingleCandidate" }, + { 0x00FF3D, "MultipleCandidate" }, + { 0x00FF3D, "Zen_Koho" }, + { 0x00FF3E, "Mae_Koho" }, + { 0x00FF3E, "PreviousCandidate" }, + { 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" }, + { 0x00FFC8, "L1" }, + { 0x00FFC9, "F12" }, + { 0x00FFC9, "L2" }, + { 0x00FFCA, "F13" }, + { 0x00FFCA, "L3" }, + { 0x00FFCB, "F14" }, + { 0x00FFCB, "L4" }, + { 0x00FFCC, "F15" }, + { 0x00FFCC, "L5" }, + { 0x00FFCD, "F16" }, + { 0x00FFCD, "L6" }, + { 0x00FFCE, "F17" }, + { 0x00FFCE, "L7" }, + { 0x00FFCF, "F18" }, + { 0x00FFCF, "L8" }, + { 0x00FFD0, "F19" }, + { 0x00FFD0, "L9" }, + { 0x00FFD1, "F20" }, + { 0x00FFD1, "L10" }, + { 0x00FFD2, "F21" }, + { 0x00FFD2, "R1" }, + { 0x00FFD3, "F22" }, + { 0x00FFD3, "R2" }, + { 0x00FFD4, "F23" }, + { 0x00FFD4, "R3" }, + { 0x00FFD5, "F24" }, + { 0x00FFD5, "R4" }, + { 0x00FFD6, "F25" }, + { 0x00FFD6, "R5" }, + { 0x00FFD7, "F26" }, + { 0x00FFD7, "R6" }, + { 0x00FFD8, "F27" }, + { 0x00FFD8, "R7" }, + { 0x00FFD9, "F28" }, + { 0x00FFD9, "R8" }, + { 0x00FFDA, "F29" }, + { 0x00FFDA, "R9" }, + { 0x00FFDB, "F30" }, + { 0x00FFDB, "R10" }, + { 0x00FFDC, "F31" }, + { 0x00FFDC, "R11" }, + { 0x00FFDD, "F32" }, + { 0x00FFDD, "R12" }, + { 0x00FFDE, "F33" }, + { 0x00FFDE, "R13" }, + { 0x00FFDF, "F34" }, + { 0x00FFDF, "R14" }, + { 0x00FFE0, "F35" }, + { 0x00FFE0, "R15" }, + { 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" }, + { 0x00ff31, "Hangul" }, + { 0x00ff32, "Hangul_Start" }, + { 0x00ff33, "Hangul_End" }, + { 0x00ff34, "Hangul_Hanja" }, + { 0x00ff35, "Hangul_Jamo" }, + { 0x00ff36, "Hangul_Romaja" }, + { 0x00ff37, "Hangul_Codeinput" }, + { 0x00ff38, "Hangul_Jeonja" }, + { 0x00ff39, "Hangul_Banja" }, + { 0x00ff3a, "Hangul_PreHanja" }, + { 0x00ff3b, "Hangul_PostHanja" }, + { 0x00ff3c, "Hangul_SingleCandidate" }, + { 0x00ff3d, "Hangul_MultipleCandidate" }, + { 0x00ff3e, "Hangul_PreviousCandidate" }, + { 0x00ff3f, "Hangul_Special" }, + { 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; +} + +const 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 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; + + 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; + + 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; + + 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; + + XConvertCase (keyval, &lower_val, &upper_val); + return lower_val == keyval; + } + return TRUE; +} + + +void +gdk_threads_enter () +{ + GDK_THREADS_ENTER (); +} + +void +gdk_threads_leave () +{ + GDK_THREADS_LEAVE (); +} diff --git a/gdk/win32/gdk.h b/gdk/win32/gdk.h new file mode 100644 index 000000000..86335c182 --- /dev/null +++ b/gdk/win32/gdk.h @@ -0,0 +1,1033 @@ +/* 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_H__ +#define __GDK_H__ + + +#include <gdk/gdktypes.h> + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +/* Initialization, exit and events + */ +#define GDK_PRIORITY_EVENTS (G_PRIORITY_DEFAULT) +void gdk_init (gint *argc, + gchar ***argv); +gboolean gdk_init_check (gint *argc, + gchar ***argv); +void gdk_exit (gint error_code); +gchar* gdk_set_locale (void); + +/* Push and pop error handlers for X errors + */ +void gdk_error_trap_push (void); +gint gdk_error_trap_pop (void); + + +gboolean gdk_events_pending (void); +GdkEvent* gdk_event_get (void); + +GdkEvent* gdk_event_peek (void); +GdkEvent* gdk_event_get_graphics_expose (GdkWindow *window); +void gdk_event_put (GdkEvent *event); + +GdkEvent* gdk_event_copy (GdkEvent *event); +void gdk_event_free (GdkEvent *event); +guint32 gdk_event_get_time (GdkEvent *event); + +void gdk_event_handler_set (GdkEventFunc func, + gpointer data, + GDestroyNotify notify); + +void gdk_set_show_events (gint show_events); +void gdk_set_use_xshm (gint use_xshm); + +gint gdk_get_show_events (void); +gint gdk_get_use_xshm (void); +gchar* gdk_get_display (void); + +guint32 gdk_time_get (void); +guint32 gdk_timer_get (void); +void gdk_timer_set (guint32 milliseconds); +void gdk_timer_enable (void); +void gdk_timer_disable (void); + +gint gdk_input_add_full (gint source, + GdkInputCondition condition, + GdkInputFunction function, + gpointer data, + GdkDestroyNotify destroy); +gint gdk_input_add (gint source, + GdkInputCondition condition, + GdkInputFunction function, + gpointer data); +void gdk_input_remove (gint tag); + +gint gdk_pointer_grab (GdkWindow * window, + gint owner_events, + GdkEventMask event_mask, + GdkWindow * confine_to, + GdkCursor * cursor, + guint32 time); +void gdk_pointer_ungrab (guint32 time); + +gint gdk_keyboard_grab (GdkWindow * window, + gint owner_events, + guint32 time); +void gdk_keyboard_ungrab (guint32 time); + +gint gdk_pointer_is_grabbed (void); + +gint gdk_screen_width (void); +gint gdk_screen_height (void); + +gint gdk_screen_width_mm (void); +gint gdk_screen_height_mm (void); + +void gdk_flush (void); +void gdk_beep (void); + +void gdk_key_repeat_disable (void); +void gdk_key_repeat_restore (void); + + +/* Visuals + */ +gint gdk_visual_get_best_depth (void); +GdkVisualType gdk_visual_get_best_type (void); +GdkVisual* gdk_visual_get_system (void); +GdkVisual* gdk_visual_get_best (void); +GdkVisual* gdk_visual_get_best_with_depth (gint depth); +GdkVisual* gdk_visual_get_best_with_type (GdkVisualType visual_type); +GdkVisual* gdk_visual_get_best_with_both (gint depth, + GdkVisualType visual_type); + +/* Actually, these are no-ops... */ +GdkVisual* gdk_visual_ref (GdkVisual *visual); +void gdk_visual_unref (GdkVisual *visual); + +void gdk_query_depths (gint **depths, + gint *count); +void gdk_query_visual_types (GdkVisualType **visual_types, + gint *count); + +GList* gdk_list_visuals (void); + + +/* Windows + */ +GdkWindow* gdk_window_new (GdkWindow *parent, + GdkWindowAttr *attributes, + gint attributes_mask); + +void gdk_window_destroy (GdkWindow *window); +GdkWindow* gdk_window_ref (GdkWindow *window); +void gdk_window_unref (GdkWindow *window); + +GdkWindow* gdk_window_at_pointer (gint *win_x, + gint *win_y); +void gdk_window_show (GdkWindow *window); +void gdk_window_hide (GdkWindow *window); +void gdk_window_withdraw (GdkWindow *window); +void gdk_window_move (GdkWindow *window, + gint x, + gint y); +void gdk_window_resize (GdkWindow *window, + gint width, + gint height); +void gdk_window_move_resize (GdkWindow *window, + gint x, + gint y, + gint width, + gint height); +void gdk_window_reparent (GdkWindow *window, + GdkWindow *new_parent, + gint x, + gint y); +void gdk_window_clear (GdkWindow *window); +void gdk_window_clear_area (GdkWindow *window, + gint x, + gint y, + gint width, + gint height); +void gdk_window_clear_area_e(GdkWindow *window, + gint x, + gint y, + gint width, + gint height); +void gdk_window_copy_area (GdkWindow *window, + GdkGC *gc, + gint x, + gint y, + GdkWindow *source_window, + gint source_x, + gint source_y, + gint width, + gint height); +void gdk_window_raise (GdkWindow *window); +void gdk_window_lower (GdkWindow *window); + +void gdk_window_set_user_data (GdkWindow *window, + gpointer user_data); +void gdk_window_set_override_redirect(GdkWindow *window, + gboolean override_redirect); + +void gdk_window_add_filter (GdkWindow *window, + GdkFilterFunc function, + gpointer data); +void gdk_window_remove_filter (GdkWindow *window, + GdkFilterFunc function, + gpointer data); + +/* + * This allows for making shaped (partially transparent) windows + * - cool feature, needed for Drag and Drag for example. + * The shape_mask can be the mask + * from gdk_pixmap_create_from_xpm. Stefan Wille + */ +void gdk_window_shape_combine_mask (GdkWindow *window, + GdkBitmap *shape_mask, + gint offset_x, + gint offset_y); +/* + * This routine allows you to quickly take the shapes of all the child windows + * of a window and use their shapes as the shape mask for this window - useful + * for container windows that dont want to look like a big box + * + * - Raster + */ +void gdk_window_set_child_shapes (GdkWindow *window); + +/* + * This routine allows you to merge (ie ADD) child shapes to your + * own window's shape keeping its current shape and ADDING the child + * shapes to it. + * + * - Raster + */ +void gdk_window_merge_child_shapes (GdkWindow *window); + +/* + * Check if a window has been shown, and whether all it's + * parents up to a toplevel have been shown, respectively. + * Note that a window that is_viewable below is not necessarily + * viewable in the X sense. + */ +gboolean gdk_window_is_visible (GdkWindow *window); +gboolean gdk_window_is_viewable (GdkWindow *window); + +/* Set static bit gravity on the parent, and static + * window gravity on all children. + */ +gboolean gdk_window_set_static_gravities (GdkWindow *window, + gboolean use_static); +/* + * The following function adds a global filter for all client + * messages of type message_type + */ +void gdk_add_client_message_filter (GdkAtom message_type, + GdkFilterFunc func, + gpointer data); + +/* Drag and Drop */ + +GdkDragContext * gdk_drag_context_new (void); +void gdk_drag_context_ref (GdkDragContext *context); +void gdk_drag_context_unref (GdkDragContext *context); + +/* Destination side */ + +void gdk_drag_status (GdkDragContext *context, + GdkDragAction action, + guint32 time); +void gdk_drop_reply (GdkDragContext *context, + gboolean ok, + guint32 time); +void gdk_drop_finish (GdkDragContext *context, + gboolean success, + guint32 time); +GdkAtom gdk_drag_get_selection (GdkDragContext *context); + +/* Source side */ + +GdkDragContext * gdk_drag_begin (GdkWindow *window, + GList *targets); +guint32 gdk_drag_get_protocol (guint32 xid, + GdkDragProtocol *protocol); +void gdk_drag_find_window (GdkDragContext *context, + GdkWindow *drag_window, + gint x_root, + gint y_root, + GdkWindow **dest_window, + GdkDragProtocol *protocol); +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); +void gdk_drag_drop (GdkDragContext *context, + guint32 time); +void gdk_drag_abort (GdkDragContext *context, + guint32 time); + +GdkAtom gdk_drag_get_selection (GdkDragContext *context); + +/* GdkWindow */ + +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); +void gdk_window_set_geometry_hints (GdkWindow *window, + GdkGeometry *geometry, + GdkWindowHints flags); +void gdk_set_sm_client_id (const gchar *sm_client_id); + + +void gdk_window_set_title (GdkWindow *window, + const gchar *title); +void gdk_window_set_role (GdkWindow *window, + const gchar *role); +void gdk_window_set_transient_for (GdkWindow *window, + GdkWindow *leader); +void gdk_window_set_background (GdkWindow *window, + GdkColor *color); +void gdk_window_set_back_pixmap (GdkWindow *window, + GdkPixmap *pixmap, + gint parent_relative); +void gdk_window_set_cursor (GdkWindow *window, + GdkCursor *cursor); +void gdk_window_set_colormap (GdkWindow *window, + GdkColormap *colormap); +void gdk_window_get_user_data (GdkWindow *window, + gpointer *data); +void gdk_window_get_geometry (GdkWindow *window, + gint *x, + gint *y, + gint *width, + gint *height, + gint *depth); +void gdk_window_get_position (GdkWindow *window, + gint *x, + gint *y); +void gdk_window_get_size (GdkWindow *window, + gint *width, + gint *height); +GdkVisual* gdk_window_get_visual (GdkWindow *window); +GdkColormap* gdk_window_get_colormap (GdkWindow *window); +GdkWindowType gdk_window_get_type (GdkWindow *window); +gint gdk_window_get_origin (GdkWindow *window, + gint *x, + gint *y); +gboolean gdk_window_get_deskrelative_origin (GdkWindow *window, + gint *x, + gint *y); +void gdk_window_get_root_origin (GdkWindow *window, + gint *x, + gint *y); +GdkWindow* gdk_window_get_pointer (GdkWindow *window, + gint *x, + gint *y, + GdkModifierType *mask); +GdkWindow* gdk_window_get_parent (GdkWindow *window); +GdkWindow* gdk_window_get_toplevel (GdkWindow *window); +GList* gdk_window_get_children (GdkWindow *window); +GdkEventMask gdk_window_get_events (GdkWindow *window); +void gdk_window_set_events (GdkWindow *window, + GdkEventMask event_mask); + +void gdk_window_set_icon (GdkWindow *window, + GdkWindow *icon_window, + GdkPixmap *pixmap, + GdkBitmap *mask); +void gdk_window_set_icon_name (GdkWindow *window, + gchar *name); +void gdk_window_set_group (GdkWindow *window, + GdkWindow *leader); +void gdk_window_set_decorations (GdkWindow *window, + GdkWMDecoration decorations); +void gdk_window_set_functions (GdkWindow *window, + GdkWMFunction functions); +GList * gdk_window_get_toplevels (void); + +void gdk_window_register_dnd (GdkWindow *window); + +void gdk_drawable_set_data (GdkDrawable *drawable, + const gchar *key, + gpointer data, + GDestroyNotify destroy_func); + + +/* Cursors + */ +GdkCursor* gdk_cursor_new (GdkCursorType cursor_type); +GdkCursor* gdk_cursor_new_from_pixmap (GdkPixmap *source, + GdkPixmap *mask, + GdkColor *fg, + GdkColor *bg, + gint x, + gint y); +void gdk_cursor_destroy (GdkCursor *cursor); + + +/* GCs + */ +GdkGC* gdk_gc_new (GdkWindow *window); +GdkGC* gdk_gc_new_with_values (GdkWindow *window, + GdkGCValues *values, + GdkGCValuesMask values_mask); +GdkGC* gdk_gc_ref (GdkGC *gc); +void gdk_gc_unref (GdkGC *gc); +void gdk_gc_destroy (GdkGC *gc); +void gdk_gc_get_values (GdkGC *gc, + GdkGCValues *values); +void gdk_gc_set_foreground (GdkGC *gc, + GdkColor *color); +void gdk_gc_set_background (GdkGC *gc, + GdkColor *color); +void gdk_gc_set_font (GdkGC *gc, + GdkFont *font); +void gdk_gc_set_function (GdkGC *gc, + GdkFunction function); +void gdk_gc_set_fill (GdkGC *gc, + GdkFill fill); +void gdk_gc_set_tile (GdkGC *gc, + GdkPixmap *tile); +void gdk_gc_set_stipple (GdkGC *gc, + GdkPixmap *stipple); +void gdk_gc_set_ts_origin (GdkGC *gc, + gint x, + gint y); +void gdk_gc_set_clip_origin (GdkGC *gc, + gint x, + gint y); +void gdk_gc_set_clip_mask (GdkGC *gc, + GdkBitmap *mask); +void gdk_gc_set_clip_rectangle (GdkGC *gc, + GdkRectangle *rectangle); +void gdk_gc_set_clip_region (GdkGC *gc, + GdkRegion *region); +void gdk_gc_set_subwindow (GdkGC *gc, + GdkSubwindowMode mode); +void gdk_gc_set_exposures (GdkGC *gc, + gint exposures); +void gdk_gc_set_line_attributes (GdkGC *gc, + gint line_width, + GdkLineStyle line_style, + GdkCapStyle cap_style, + GdkJoinStyle join_style); +void gdk_gc_set_dashes (GdkGC *gc, + gint dash_offset, + gchar dash_list[], + gint n); +void gdk_gc_copy (GdkGC *dst_gc, + GdkGC *src_gc); + + +/* Pixmaps + */ +GdkPixmap* gdk_pixmap_new (GdkWindow *window, + gint width, + gint height, + gint depth); +GdkPixmap* gdk_pixmap_create_on_shared_image + (GdkImage **image_return, + GdkWindow *window, + GdkVisual *visual, + gint width, + gint height, + gint depth); +GdkBitmap* gdk_bitmap_create_from_data (GdkWindow *window, + const gchar *data, + gint width, + gint height); +GdkPixmap* gdk_pixmap_create_from_data (GdkWindow *window, + const gchar *data, + gint width, + gint height, + gint depth, + GdkColor *fg, + GdkColor *bg); +GdkPixmap* gdk_pixmap_create_from_xpm (GdkWindow *window, + GdkBitmap **mask, + GdkColor *transparent_color, + const gchar *filename); +GdkPixmap* gdk_pixmap_colormap_create_from_xpm + (GdkWindow *window, + GdkColormap *colormap, + GdkBitmap **mask, + GdkColor *transparent_color, + const gchar *filename); +GdkPixmap* gdk_pixmap_create_from_xpm_d (GdkWindow *window, + GdkBitmap **mask, + GdkColor *transparent_color, + gchar **data); +GdkPixmap* gdk_pixmap_colormap_create_from_xpm_d + (GdkWindow *window, + GdkColormap *colormap, + GdkBitmap **mask, + GdkColor *transparent_color, + gchar **data); +GdkPixmap *gdk_pixmap_ref (GdkPixmap *pixmap); +void gdk_pixmap_unref (GdkPixmap *pixmap); + +GdkBitmap *gdk_bitmap_ref (GdkBitmap *pixmap); +void gdk_bitmap_unref (GdkBitmap *pixmap); + + +/* Images + */ +GdkImage* gdk_image_new_bitmap(GdkVisual *visual, + gpointer data, + gint width, + gint height); +GdkImage* gdk_image_new (GdkImageType type, + GdkVisual *visual, + gint width, + gint height); +GdkImage* gdk_image_bitmap_new(GdkImageType type, + GdkVisual *visual, + gint width, + gint height); +GdkImage* gdk_image_get (GdkWindow *window, + gint x, + gint y, + gint width, + gint height); +void gdk_image_put_pixel (GdkImage *image, + gint x, + gint y, + guint32 pixel); +guint32 gdk_image_get_pixel (GdkImage *image, + gint x, + gint y); +void gdk_image_destroy (GdkImage *image); + + +/* Color + */ +GdkColormap* gdk_colormap_new (GdkVisual *visual, + gint allocate); +GdkColormap* gdk_colormap_ref (GdkColormap *cmap); +void gdk_colormap_unref (GdkColormap *cmap); + +GdkColormap* gdk_colormap_get_system (void); +gint gdk_colormap_get_system_size (void); + +void gdk_colormap_change (GdkColormap *colormap, + gint ncolors); + + +gint gdk_colormap_alloc_colors (GdkColormap *colormap, + GdkColor *colors, + gint ncolors, + gboolean writeable, + gboolean best_match, + gboolean *success); +gboolean gdk_colormap_alloc_color (GdkColormap *colormap, + GdkColor *color, + gboolean writeable, + gboolean best_match); +void gdk_colormap_free_colors (GdkColormap *colormap, + GdkColor *colors, + gint ncolors); + +GdkVisual *gdk_colormap_get_visual (GdkColormap *colormap); + +GdkColor *gdk_color_copy (GdkColor *color); +void gdk_color_free (GdkColor *color); + +gint gdk_color_parse (const gchar *spec, + GdkColor *color); +guint gdk_color_hash (const GdkColor *colora); +gint gdk_color_equal (const GdkColor *colora, + const GdkColor *colorb); + + +/* The following functions are deprecated */ +void gdk_colors_store (GdkColormap *colormap, + GdkColor *colors, + gint ncolors); +gint gdk_colors_alloc (GdkColormap *colormap, + gint contiguous, + gulong *planes, + gint nplanes, + gulong *pixels, + gint npixels); +void gdk_colors_free (GdkColormap *colormap, + gulong *pixels, + gint npixels, + gulong planes); +gint gdk_color_white (GdkColormap *colormap, + GdkColor *color); +gint gdk_color_black (GdkColormap *colormap, + GdkColor *color); +gint gdk_color_alloc (GdkColormap *colormap, + GdkColor *color); +gint gdk_color_change (GdkColormap *colormap, + GdkColor *color); + + +/* Fonts + */ +GdkFont* gdk_font_load (const gchar *font_name); +GdkFont* gdk_fontset_load (gchar *fontset_name); +GdkFont* gdk_font_ref (GdkFont *font); +void gdk_font_unref (GdkFont *font); +gint gdk_font_id (const GdkFont *font); +gint gdk_font_equal (const GdkFont *fonta, + const GdkFont *fontb); +gint gdk_string_width (GdkFont *font, + const gchar *string); +gint gdk_text_width (GdkFont *font, + const gchar *text, + gint text_length); +gint gdk_text_width_wc (GdkFont *font, + const GdkWChar *text, + gint text_length); +gint gdk_char_width (GdkFont *font, + gchar character); +gint gdk_char_width_wc (GdkFont *font, + GdkWChar character); +gint gdk_string_measure (GdkFont *font, + const gchar *string); +gint gdk_text_measure (GdkFont *font, + const gchar *text, + gint text_length); +gint gdk_char_measure (GdkFont *font, + gchar character); +gint gdk_string_height (GdkFont *font, + const gchar *string); +gint gdk_text_height (GdkFont *font, + const gchar *text, + gint text_length); +gint gdk_char_height (GdkFont *font, + gchar character); + +void gdk_text_extents (GdkFont *font, + const gchar *text, + gint text_length, + gint *lbearing, + gint *rbearing, + gint *width, + gint *ascent, + gint *descent); +void gdk_text_extents_wc (GdkFont *font, + const GdkWChar *text, + gint text_length, + gint *lbearing, + gint *rbearing, + gint *width, + gint *ascent, + gint *descent); +void gdk_string_extents (GdkFont *font, + const gchar *string, + gint *lbearing, + gint *rbearing, + gint *width, + gint *ascent, + gint *descent); + +/* Drawing + */ +void gdk_draw_point (GdkDrawable *drawable, + GdkGC *gc, + gint x, + gint y); +void gdk_draw_line (GdkDrawable *drawable, + GdkGC *gc, + gint x1, + gint y1, + gint x2, + gint y2); +void gdk_draw_rectangle (GdkDrawable *drawable, + GdkGC *gc, + gint filled, + gint x, + gint y, + gint width, + gint height); +void gdk_draw_arc (GdkDrawable *drawable, + GdkGC *gc, + gint filled, + gint x, + gint y, + gint width, + gint height, + gint angle1, + gint angle2); +void gdk_draw_polygon (GdkDrawable *drawable, + GdkGC *gc, + gint filled, + GdkPoint *points, + gint npoints); +void gdk_draw_string (GdkDrawable *drawable, + GdkFont *font, + GdkGC *gc, + gint x, + gint y, + const gchar *string); +void gdk_draw_text (GdkDrawable *drawable, + GdkFont *font, + GdkGC *gc, + gint x, + gint y, + const gchar *text, + gint text_length); +void gdk_draw_text_wc (GdkDrawable *drawable, + GdkFont *font, + GdkGC *gc, + gint x, + gint y, + const GdkWChar *text, + gint text_length); +void gdk_draw_pixmap (GdkDrawable *drawable, + GdkGC *gc, + GdkDrawable *src, + gint xsrc, + gint ysrc, + gint xdest, + gint ydest, + gint width, + gint height); +void gdk_draw_bitmap (GdkDrawable *drawable, + GdkGC *gc, + GdkDrawable *src, + gint xsrc, + gint ysrc, + gint xdest, + gint ydest, + gint width, + gint height); +void gdk_draw_image (GdkDrawable *drawable, + GdkGC *gc, + GdkImage *image, + gint xsrc, + gint ysrc, + gint xdest, + gint ydest, + gint width, + gint height); +void gdk_draw_points (GdkDrawable *drawable, + GdkGC *gc, + GdkPoint *points, + gint npoints); +void gdk_draw_segments (GdkDrawable *drawable, + GdkGC *gc, + GdkSegment *segs, + gint nsegs); +void gdk_draw_lines (GdkDrawable *drawable, + GdkGC *gc, + GdkPoint *points, + gint npoints); + + + + +/* Selections + */ +gint gdk_selection_owner_set (GdkWindow *owner, + GdkAtom selection, + guint32 time, + gint send_event); +GdkWindow* gdk_selection_owner_get (GdkAtom selection); +void gdk_selection_convert (GdkWindow *requestor, + GdkAtom selection, + GdkAtom target, + guint32 time); +gint gdk_selection_property_get (GdkWindow *requestor, + guchar **data, + GdkAtom *prop_type, + gint *prop_format); +void gdk_selection_send_notify (guint32 requestor, + GdkAtom selection, + GdkAtom target, + GdkAtom property, + guint32 time); + +gint gdk_text_property_to_text_list (GdkAtom encoding, gint format, + guchar *text, gint length, + gchar ***list); +void gdk_free_text_list (gchar **list); +gint gdk_string_to_compound_text (gchar *str, + GdkAtom *encoding, gint *format, + guchar **ctext, gint *length); +void gdk_free_compound_text (guchar *ctext); + +/* Properties + */ +GdkAtom gdk_atom_intern (const gchar *atom_name, + gint only_if_exists); +gchar* gdk_atom_name (GdkAtom atom); +gint gdk_property_get (GdkWindow *window, + GdkAtom property, + GdkAtom type, + gulong offset, + gulong length, + gint pdelete, + GdkAtom *actual_property_type, + gint *actual_format, + gint *actual_length, + guchar **data); + +void gdk_property_change (GdkWindow *window, + GdkAtom property, + GdkAtom type, + gint format, + GdkPropMode mode, + guchar *data, + gint nelements); +void gdk_property_delete (GdkWindow *window, + GdkAtom property); + + +/* Rectangle utilities + */ +gint gdk_rectangle_intersect (GdkRectangle *src1, + GdkRectangle *src2, + GdkRectangle *dest); +void gdk_rectangle_union (GdkRectangle *src1, + GdkRectangle *src2, + GdkRectangle *dest); + +/* XInput support + */ + +void gdk_input_init (void); +void gdk_input_exit (void); +GList *gdk_input_list_devices (void); +void gdk_input_set_extension_events (GdkWindow *window, + gint mask, + GdkExtensionMode mode); +void gdk_input_set_source (guint32 deviceid, + GdkInputSource source); +gint gdk_input_set_mode (guint32 deviceid, + GdkInputMode mode); +void gdk_input_set_axes (guint32 deviceid, + GdkAxisUse *axes); +void gdk_input_set_key (guint32 deviceid, + guint index, + guint keyval, + GdkModifierType modifiers); +void gdk_input_window_get_pointer (GdkWindow *window, + guint32 deviceid, + gdouble *x, + gdouble *y, + gdouble *pressure, + gdouble *xtilt, + gdouble *ytilt, + GdkModifierType *mask); + +GdkTimeCoord *gdk_input_motion_events (GdkWindow *window, + guint32 deviceid, + guint32 start, + guint32 stop, + gint *nevents_return); + +/* International Input Method Support Functions + */ + +gint gdk_im_ready (void); + +void gdk_im_begin (GdkIC *ic, + GdkWindow *window); +void gdk_im_end (void); +GdkIMStyle gdk_im_decide_style (GdkIMStyle supported_style); +GdkIMStyle gdk_im_set_best_style (GdkIMStyle best_allowed_style); + +GdkIC* gdk_ic_new (GdkICAttr *attr, + GdkICAttributesType mask); +void gdk_ic_destroy (GdkIC *ic); +GdkIMStyle gdk_ic_get_style (GdkIC *ic); +GdkEventMask gdk_ic_get_events (GdkIC *ic); + +GdkICAttr* gdk_ic_attr_new (void); +void gdk_ic_attr_destroy (GdkICAttr *attr); + +GdkICAttributesType gdk_ic_set_attr (GdkIC *ic, + GdkICAttr *attr, + GdkICAttributesType mask); +GdkICAttributesType gdk_ic_get_attr (GdkIC *ic, + GdkICAttr *attr, + GdkICAttributesType mask); + +/* Conversion functions between wide char and multibyte strings. + */ +gchar *gdk_wcstombs (const GdkWChar *src); +gint gdk_mbstowcs (GdkWChar *dest, + const gchar *src, + gint dest_max); + + +/* Color Context */ + +GdkColorContext *gdk_color_context_new (GdkVisual *visual, + GdkColormap *colormap); + +GdkColorContext *gdk_color_context_new_mono (GdkVisual *visual, + GdkColormap *colormap); + +void gdk_color_context_free (GdkColorContext *cc); + +gulong gdk_color_context_get_pixel (GdkColorContext *cc, + gushort red, + gushort green, + gushort blue, + gint *failed); +void gdk_color_context_get_pixels (GdkColorContext *cc, + gushort *reds, + gushort *greens, + gushort *blues, + gint ncolors, + gulong *colors, + gint *nallocated); +void gdk_color_context_get_pixels_incremental (GdkColorContext *cc, + gushort *reds, + gushort *greens, + gushort *blues, + gint ncolors, + gint *used, + gulong *colors, + gint *nallocated); + +gint gdk_color_context_query_color (GdkColorContext *cc, + GdkColor *color); +gint gdk_color_context_query_colors (GdkColorContext *cc, + GdkColor *colors, + gint num_colors); + +gint gdk_color_context_add_palette (GdkColorContext *cc, + GdkColor *palette, + gint num_palette); + +void gdk_color_context_init_dither (GdkColorContext *cc); +void gdk_color_context_free_dither (GdkColorContext *cc); + +gulong gdk_color_context_get_pixel_from_palette (GdkColorContext *cc, + gushort *red, + gushort *green, + gushort *blue, + gint *failed); +guchar gdk_color_context_get_index_from_palette (GdkColorContext *cc, + gint *red, + gint *green, + gint *blue, + gint *failed); +/* Regions + */ + +GdkRegion* gdk_region_new (void); +void gdk_region_destroy (GdkRegion *region); + +void gdk_region_get_clipbox(GdkRegion *region, + GdkRectangle *rectangle); + +gboolean gdk_region_empty (GdkRegion *region); +gboolean gdk_region_equal (GdkRegion *region1, + GdkRegion *region2); +gboolean gdk_region_point_in (GdkRegion *region, + int x, + int y); +GdkOverlapType gdk_region_rect_in (GdkRegion *region, + GdkRectangle *rect); + +GdkRegion* gdk_region_polygon (GdkPoint *points, + gint npoints, + GdkFillRule fill_rule); + +void gdk_region_offset (GdkRegion *region, + gint dx, + gint dy); +void gdk_region_shrink (GdkRegion *region, + gint dx, + gint dy); + +GdkRegion* gdk_region_union_with_rect (GdkRegion *region, + GdkRectangle *rect); +GdkRegion* gdk_regions_intersect (GdkRegion *source1, + GdkRegion *source2); +GdkRegion* gdk_regions_union (GdkRegion *source1, + GdkRegion *source2); +GdkRegion* gdk_regions_subtract (GdkRegion *source1, + GdkRegion *source2); +GdkRegion* gdk_regions_xor (GdkRegion *source1, + GdkRegion *source2); + +/* Miscellaneous */ +void gdk_event_send_clientmessage_toall (GdkEvent *event); +gboolean gdk_event_send_client_message (GdkEvent *event, + guint32 xid); + +/* Key values + */ +const gchar* gdk_keyval_name (guint keyval); +guint gdk_keyval_from_name (const gchar *keyval_name); +guint gdk_keyval_to_upper (guint keyval); +guint gdk_keyval_to_lower (guint keyval); +gboolean gdk_keyval_is_upper (guint keyval); +gboolean gdk_keyval_is_lower (guint keyval); + +/* Threading + */ + +GDKVAR GMutex *gdk_threads_mutex; + +void gdk_threads_enter (void); +void gdk_threads_leave (void); + +#ifdef G_THREADS_ENABLED +# define GDK_THREADS_ENTER() G_STMT_START { \ + if (gdk_threads_mutex) \ + g_mutex_lock (gdk_threads_mutex); \ + } G_STMT_END +# define GDK_THREADS_LEAVE() G_STMT_START { \ + if (gdk_threads_mutex) \ + g_mutex_unlock (gdk_threads_mutex); \ + } G_STMT_END +#else /* !G_THREADS_ENABLED */ +# define GDK_THREADS_ENTER() +# define GDK_THREADS_LEAVE() +#endif /* !G_THREADS_ENABLED */ + +#include <gdk/gdkrgb.h> + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GDK_H__ */ diff --git a/gdk/win32/gdkcc.c b/gdk/win32/gdkcc.c new file mode 100644 index 000000000..8bbb7b3c5 --- /dev/null +++ b/gdk/win32/gdkcc.c @@ -0,0 +1,1610 @@ +/* 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. + */ + +/* Color Context module + * Copyright 1994,1995 John L. Cwikla + * Copyright (C) 1997 by Ripley Software Development + * Copyright (C) 1997 by Federico Mena (port to Gtk/Gdk) + */ + +/* Copyright 1994,1995 John L. Cwikla + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appears in all copies and that + * both that copyright notice and this permission notice appear in + * supporting documentation, and that the name of John L. Cwikla or + * Wolfram Research, Inc not be used in advertising or publicity + * pertaining to distribution of the software without specific, written + * prior permission. John L. Cwikla and Wolfram Research, Inc make no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + * + * John L. Cwikla and Wolfram Research, Inc disclaim all warranties with + * regard to this software, including all implied warranties of + * merchantability and fitness, in no event shall John L. Cwikla or + * Wolfram Research, Inc be liable for any special, indirect or + * consequential damages or any damages whatsoever resulting from loss of + * use, data or profits, whether in an action of contract, negligence or + * other tortious action, arising out of or in connection with the use or + * performance of this software. + * + * Author: + * John L. Cwikla + * X Programmer + * Wolfram Research Inc. + * + * cwikla@wri.com + */ + +/* + * 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 <string.h> +#include "gdk.h" +#include "gdkprivate.h" +#include "gdkx.h" + +#define MAX_IMAGE_COLORS 256 + + +static guint +hash_color (gconstpointer key) +{ + const GdkColor *color = key; + + return (color->red * 33023 + color->green * 30013 + color->blue * 27011); +} + +static gint +compare_colors (gconstpointer a, + gconstpointer b) +{ + const GdkColor *aa = a; + const GdkColor *bb = b; + + return ((aa->red == bb->red) && (aa->green == bb->green) && (aa->blue == bb->blue)); +} + +static void +free_hash_entry (gpointer key, + gpointer value, + gpointer user_data) +{ + g_free (key); /* key and value are the same GdkColor */ +} + +static int +pixel_sort (const void *a, const void *b) +{ + return ((GdkColor *) a)->pixel - ((GdkColor *) b)->pixel; +} + +/* XXX: This function does an XQueryColors() the hard way, because there is + * no corresponding function in Gdk. + */ + +static void +my_x_query_colors (GdkColormap *colormap, + GdkColor *colors, + gint ncolors) +{ + XColor *xcolors; + gint i; + + for (i = 0; i < ncolors; i++) + { + PALETTEENTRY palentry; + + GetPaletteEntries (GDK_COLORMAP_XCOLORMAP (colormap)->palette, colors[i].pixel, 1, &palentry); + colors[i].red = (palentry.peRed * 65536) / 255; + colors[i].green = (palentry.peGreen * 65536) / 255; + colors[i].blue = (palentry.peBlue * 65536) / 255; + } +} + +static void +query_colors (GdkColorContext *cc) +{ + gint i; + GdkColorContextPrivate *ccp = (GdkColorContextPrivate *) cc; + cc->cmap = g_new (GdkColor, cc->num_colors); + + for (i = 0; i < cc->num_colors; i++) + cc->cmap[i].pixel = cc->clut ? cc->clut[i] : ccp->std_cmap.base_pixel + i; + + my_x_query_colors (cc->colormap, cc->cmap, cc->num_colors); + + qsort (cc->cmap, cc->num_colors, sizeof (GdkColor), pixel_sort); +} + +static void +init_bw (GdkColorContext *cc) +{ + GdkColor color; + + g_warning ("init_bw: failed to allocate colors, falling back to black and white"); + + cc->mode = GDK_CC_MODE_BW; + + color.red = color.green = color.blue = 0; + + if (!gdk_color_alloc (cc->colormap, &color)) + cc->black_pixel = 0; + else + cc->black_pixel = color.pixel; + + color.red = color.green = color.blue = 0xffff; + + if (!gdk_color_alloc (cc->colormap, &color)) + cc->white_pixel = cc->black_pixel ? 0 : 1; + else + cc->white_pixel = color.pixel; + + cc->num_colors = 2; +} + +static void +init_gray (GdkColorContext *cc) +{ + GdkColorContextPrivate *ccp = (GdkColorContextPrivate *) cc; + GdkColor *clrs, *cstart; + gint i; + gdouble dinc; + + cc->num_colors = 256; /* Bogus, but will never get here anyway? */ + cc->clut = g_new (gulong, cc->num_colors); + cstart = g_new (GdkColor, cc->num_colors); + + retrygray: + + dinc = 65535.0 / (cc->num_colors - 1); + + clrs = cstart; + + for (i = 0; i < cc->num_colors; i++) + { + clrs->red = clrs->green = clrs->blue = dinc * i; + + if (!gdk_color_alloc (cc->colormap, clrs)) + { + gdk_colors_free (cc->colormap, cc->clut, i, 0); + + cc->num_colors /= 2; + + if (cc->num_colors > 1) + goto retrygray; + else + { + g_free (cc->clut); + cc->clut = NULL; + init_bw (cc); + g_free (cstart); + return; + } + } + + cc->clut[i] = clrs++->pixel; + } + + g_free (cstart); + + /* XXX: is this the right thing to do? */ + ccp->std_cmap.colormap = GDK_COLORMAP_XCOLORMAP (cc->colormap); + ccp->std_cmap.base_pixel = 0; + ccp->std_cmap.red_max = cc->num_colors - 1; + ccp->std_cmap.green_max = 0; + ccp->std_cmap.blue_max = 0; + ccp->std_cmap.red_mult = 1; + ccp->std_cmap.green_mult = 0; + ccp->std_cmap.blue_mult = 0; + + cc->white_pixel = 255; + cc->black_pixel = 0; + + query_colors (cc); + + cc->mode = GDK_CC_MODE_MY_GRAY; +} + +static void +init_color (GdkColorContext *cc) +{ + GdkColorContextPrivate *ccp = (GdkColorContextPrivate *) cc; + gint cubeval; + + cubeval = 1; + while ((cubeval * cubeval * cubeval) < GDK_VISUAL_XVISUAL (cc->visual)->map_entries) + cubeval++; + cubeval--; + + cc->num_colors = cubeval * cubeval * cubeval; + + ccp->std_cmap.red_max = cubeval - 1; + ccp->std_cmap.green_max = cubeval - 1; + ccp->std_cmap.blue_max = cubeval - 1; + ccp->std_cmap.red_mult = cubeval * cubeval; + ccp->std_cmap.green_mult = cubeval; + ccp->std_cmap.blue_mult = 1; + ccp->std_cmap.base_pixel = 0; + + cc->white_pixel = 255; /* ??? */ + cc->black_pixel = 0; /* ??? */ + + /* a CLUT for storing allocated pixel indices */ + + cc->max_colors = cc->num_colors; + cc->clut = g_new (gulong, cc->max_colors); + + for (cubeval = 0; cubeval < cc->max_colors; cubeval++) + cc->clut[cubeval] = cubeval; + + query_colors (cc); + + cc->mode = GDK_CC_MODE_STD_CMAP; +} + + +static void +init_true_color (GdkColorContext *cc) +{ + GdkColorContextPrivate *ccp = (GdkColorContextPrivate *) cc; + gulong rmask, gmask, bmask; + + cc->mode = GDK_CC_MODE_TRUE; + + /* Red */ + + rmask = cc->masks.red = cc->visual->red_mask; + + cc->shifts.red = 0; + cc->bits.red = 0; + + while (!(rmask & 1)) + { + rmask >>= 1; + cc->shifts.red++; + } + + while (rmask & 1) + { + rmask >>= 1; + cc->bits.red++; + } + + /* Green */ + + gmask = cc->masks.green = cc->visual->green_mask; + + cc->shifts.green = 0; + cc->bits.green = 0; + + while (!(gmask & 1)) + { + gmask >>= 1; + cc->shifts.green++; + } + + while (gmask & 1) + { + gmask >>= 1; + cc->bits.green++; + } + + /* Blue */ + + bmask = cc->masks.blue = cc->visual->blue_mask; + + cc->shifts.blue = 0; + cc->bits.blue = 0; + + while (!(bmask & 1)) + { + bmask >>= 1; + cc->shifts.blue++; + } + + while (bmask & 1) + { + bmask >>= 1; + cc->bits.blue++; + } + + cc->num_colors = (cc->visual->red_mask | cc->visual->green_mask | cc->visual->blue_mask) + 1; + + cc->white_pixel = 0xffffff; + cc->black_pixel = 0; +} + +static void +init_palette (GdkColorContext *cc) +{ + /* restore correct mode for this cc */ + + switch (cc->visual->type) + { + case GDK_VISUAL_STATIC_GRAY: + case GDK_VISUAL_GRAYSCALE: + if (GDK_VISUAL_XVISUAL (cc->visual)->map_entries == 2) + cc->mode = GDK_CC_MODE_BW; + else + cc->mode = GDK_CC_MODE_MY_GRAY; + break; + + case GDK_VISUAL_TRUE_COLOR: + cc->mode = GDK_CC_MODE_TRUE; + break; + + case GDK_VISUAL_STATIC_COLOR: + case GDK_VISUAL_PSEUDO_COLOR: + cc->mode = GDK_CC_MODE_STD_CMAP; + break; + + default: + cc->mode = GDK_CC_MODE_UNDEFINED; + break; + } + + /* previous palette */ + + if (cc->num_palette) + g_free (cc->palette); + + if (cc->fast_dither) + g_free (cc->fast_dither); + + /* clear hash table if present */ + + if (cc->color_hash) + { + /* XXX: quick-and-dirty way to remove everything */ + + g_hash_table_destroy (cc->color_hash); + cc->color_hash = g_hash_table_new (hash_color, compare_colors); + } + + cc->palette = NULL; + cc->num_palette = 0; + cc->fast_dither = NULL; +} + +GdkColorContext * +gdk_color_context_new (GdkVisual *visual, + GdkColormap *colormap) +{ + GdkColorContextPrivate *ccp; + gint use_private_colormap = FALSE; /* XXX: maybe restore full functionality later? */ + GdkColorContext *cc; + gint retry_count; + GdkColormap *default_colormap; + + g_assert (visual != NULL); + g_assert (colormap != NULL); + + ccp = g_new (GdkColorContextPrivate, 1); + cc = (GdkColorContext *) ccp; + cc->visual = visual; + cc->colormap = colormap; + cc->clut = NULL; + cc->cmap = NULL; + cc->mode = GDK_CC_MODE_UNDEFINED; + cc->need_to_free_colormap = FALSE; + + cc->color_hash = NULL; + cc->palette = NULL; + cc->num_palette = 0; + cc->fast_dither = NULL; + + default_colormap = gdk_colormap_get_system (); + + retry_count = 0; + + while (retry_count < 2) + { + /* Only create a private colormap if the visual found isn't equal + * to the default visual and we don't have a private colormap, + * -or- if we are instructed to create a private colormap (which + * never is the case for XmHTML). + */ + + if (use_private_colormap + || ((cc->visual != gdk_visual_get_system ()) /* default visual? */ + && (GDK_COLORMAP_XCOLORMAP (colormap) == GDK_COLORMAP_XCOLORMAP (default_colormap)))) + { + g_warning ("gdk_color_context_new: non-default visual detected, " + "using private colormap"); + + cc->colormap = gdk_colormap_new (cc->visual, FALSE); + + cc->need_to_free_colormap = (GDK_COLORMAP_XCOLORMAP (colormap) + != GDK_COLORMAP_XCOLORMAP (default_colormap)); + } + + switch (visual->type) + { + case GDK_VISUAL_STATIC_GRAY: + case GDK_VISUAL_GRAYSCALE: + GDK_NOTE (COLOR_CONTEXT, + g_message ("gdk_color_context_new: visual class is %s\n", + (visual->type == GDK_VISUAL_STATIC_GRAY) ? + "GDK_VISUAL_STATIC_GRAY" : + "GDK_VISUAL_GRAYSCALE")); + + if (GDK_VISUAL_XVISUAL (cc->visual)->map_entries == 2) + init_bw (cc); + else + init_gray (cc); + break; + + case GDK_VISUAL_TRUE_COLOR: /* shifts */ + GDK_NOTE (COLOR_CONTEXT, + g_message ("gdk_color_context_new: visual class is GDK_VISUAL_TRUE_COLOR\n")); + + init_true_color (cc); + break; + + case GDK_VISUAL_STATIC_COLOR: + case GDK_VISUAL_PSEUDO_COLOR: + GDK_NOTE (COLOR_CONTEXT, + g_message ("gdk_color_context_new: visual class is %s\n", + (visual->type == GDK_VISUAL_STATIC_COLOR) ? + "GDK_VISUAL_STATIC_COLOR" : + "GDK_VISUAL_PSEUDO_COLOR")); + + init_color (cc); + break; + + default: + g_assert_not_reached (); + } + + if ((cc->mode == GDK_CC_MODE_BW) && (cc->visual->depth > 1)) + { + use_private_colormap = TRUE; + retry_count++; + } + else + break; + } + + /* no. of colors allocated yet */ + + cc->num_allocated = 0; + + GDK_NOTE (COLOR_CONTEXT, + g_message ("gdk_color_context_new: screen depth is %i, no. of colors is %i\n", + cc->visual->depth, cc->num_colors)); + + /* check if we need to initialize a hash table */ + + if ((cc->mode == GDK_CC_MODE_STD_CMAP) || (cc->mode == GDK_CC_MODE_UNDEFINED)) + cc->color_hash = g_hash_table_new (hash_color, compare_colors); + + return (GdkColorContext *) cc; +} + +GdkColorContext * +gdk_color_context_new_mono (GdkVisual *visual, + GdkColormap *colormap) +{ + GdkColorContextPrivate *ccp; + GdkColorContext *cc; + + g_assert (visual != NULL); + g_assert (colormap != NULL); + + cc = g_new (GdkColorContext, 1); + ccp = (GdkColorContextPrivate *) cc; + cc->visual = visual; + cc->colormap = colormap; + cc->clut = NULL; + cc->cmap = NULL; + cc->mode = GDK_CC_MODE_UNDEFINED; + cc->need_to_free_colormap = FALSE; + + init_bw (cc); + + return (GdkColorContext *) cc; +} + +/* This doesn't currently free black/white, hmm... */ + +void +gdk_color_context_free (GdkColorContext *cc) +{ + g_assert (cc != NULL); + + if ((cc->visual->type == GDK_VISUAL_STATIC_COLOR) + || (cc->visual->type == GDK_VISUAL_PSEUDO_COLOR)) + { + gdk_colors_free (cc->colormap, cc->clut, cc->num_allocated, 0); + g_free (cc->clut); + } + else if (cc->clut != NULL) + { + gdk_colors_free (cc->colormap, cc->clut, cc->num_colors, 0); + g_free (cc->clut); + } + + if (cc->cmap != NULL) + g_free (cc->cmap); + + if (cc->need_to_free_colormap) + gdk_colormap_unref (cc->colormap); + + /* free any palette that has been associated with this GdkColorContext */ + + init_palette (cc); + + if (cc->color_hash) + { + g_hash_table_foreach (cc->color_hash, + free_hash_entry, + NULL); + g_hash_table_destroy (cc->color_hash); + } + + g_free (cc); +} + +gulong +gdk_color_context_get_pixel (GdkColorContext *cc, + gushort red, + gushort green, + gushort blue, + gint *failed) +{ + GdkColorContextPrivate *ccp = (GdkColorContextPrivate *) cc; + g_assert (cc != NULL); + g_assert (failed != NULL); + + *failed = FALSE; + + switch (cc->mode) + { + case GDK_CC_MODE_BW: + { + gdouble value; + + value = (red / 65535.0 * 0.30 + + green / 65535.0 * 0.59 + + blue / 65535.0 * 0.11); + + if (value > 0.5) + return cc->white_pixel; + + return cc->black_pixel; + } + + case GDK_CC_MODE_MY_GRAY: + { + gulong ired, igreen, iblue; + + red = red * 0.30 + green * 0.59 + blue * 0.11; + green = 0; + blue = 0; + + if ((ired = red * (ccp->std_cmap.red_max + 1) / 0xffff) > ccp->std_cmap.red_max) + ired = ccp->std_cmap.red_max; + + ired *= ccp->std_cmap.red_mult; + + if ((igreen = green * (ccp->std_cmap.green_max + 1) / 0xffff) > ccp->std_cmap.green_max) + igreen = ccp->std_cmap.green_max; + + igreen *= ccp->std_cmap.green_mult; + + if ((iblue = blue * (ccp->std_cmap.blue_max + 1) / 0xffff) > ccp->std_cmap.blue_max) + iblue = ccp->std_cmap.blue_max; + + iblue *= ccp->std_cmap.blue_mult; + + if (cc->clut != NULL) + return cc->clut[ccp->std_cmap.base_pixel + ired + igreen + iblue]; + + return ccp->std_cmap.base_pixel + ired + igreen + iblue; + } + + case GDK_CC_MODE_TRUE: + { + gulong ired, igreen, iblue; + + if (cc->clut == NULL) + { + red >>= 16 - cc->bits.red; + green >>= 16 - cc->bits.green; + blue >>= 16 - cc->bits.blue; + + ired = (red << cc->shifts.red) & cc->masks.red; + igreen = (green << cc->shifts.green) & cc->masks.green; + iblue = (blue << cc->shifts.blue) & cc->masks.blue; + + return ired | igreen | iblue; + } + + ired = cc->clut[red * cc->max_entry / 65535] & cc->masks.red; + igreen = cc->clut[green * cc->max_entry / 65535] & cc->masks.green; + iblue = cc->clut[blue * cc->max_entry / 65535] & cc->masks.blue; + + return ired | igreen | iblue; + } + + case GDK_CC_MODE_PALETTE: + return gdk_color_context_get_pixel_from_palette (cc, &red, &green, &blue, failed); + + case GDK_CC_MODE_STD_CMAP: + default: + { + GdkColor color; + GdkColor *result; + + color.red = red; + color.green = green; + color.blue = blue; + + result = g_hash_table_lookup (cc->color_hash, &color); + + if (!result) + { + color.red = red; + color.green = green; + color.blue = blue; + color.pixel = 0; + + if (!gdk_color_alloc (cc->colormap, &color)) + *failed = TRUE; + else + { + GdkColor *cnew; + + /* XXX: the following comment comes directly from + * XCC.c. I don't know if it is relevant for + * gdk_color_alloc() as it is for XAllocColor() + * - Federico + */ + /* + * I can't figure this out entirely, but it *is* possible + * that XAllocColor succeeds, even if the number of + * allocations we've made exceeds the number of available + * colors in the current colormap. And therefore it + * might be necessary for us to resize the CLUT. + */ + + if (cc->num_allocated == cc->max_colors) + { + cc->max_colors *= 2; + + GDK_NOTE (COLOR_CONTEXT, + g_message ("gdk_color_context_get_pixel: " + "resizing CLUT to %i entries\n", + cc->max_colors)); + + cc->clut = g_realloc (cc->clut, + cc->max_colors * sizeof (gulong)); + } + + /* Key and value are the same color structure */ + + cnew = g_new (GdkColor, 1); + *cnew = color; + g_hash_table_insert (cc->color_hash, cnew, cnew); + + cc->clut[cc->num_allocated] = color.pixel; + cc->num_allocated++; + return color.pixel; + } + } + + return result->pixel; + } + } +} + +void +gdk_color_context_get_pixels (GdkColorContext *cc, + gushort *reds, + gushort *greens, + gushort *blues, + gint ncolors, + gulong *colors, + gint *nallocated) +{ + gint i, k, idx; + gint cmapsize, ncols = 0, nopen = 0, counter = 0; + gint bad_alloc = FALSE; + gint failed[MAX_IMAGE_COLORS], allocated[MAX_IMAGE_COLORS]; + GdkColor defs[MAX_IMAGE_COLORS], cmap[MAX_IMAGE_COLORS]; +#ifdef G_ENABLE_DEBUG + gint exact_col = 0, subst_col = 0, close_col = 0, black_col = 0; +#endif + g_assert (cc != NULL); + g_assert (reds != NULL); + g_assert (greens != NULL); + g_assert (blues != NULL); + g_assert (colors != NULL); + g_assert (nallocated != NULL); + + memset (defs, 0, MAX_IMAGE_COLORS * sizeof (GdkColor)); + memset (failed, 0, MAX_IMAGE_COLORS * sizeof (gint)); + memset (allocated, 0, MAX_IMAGE_COLORS * sizeof (gint)); + + /* Will only have a value if used by the progressive image loader */ + + ncols = *nallocated; + + *nallocated = 0; + + /* First allocate all pixels */ + + for (i = 0; i < ncolors; i++) + { + /* colors[i] is only zero if the pixel at that location hasn't + * been allocated yet. This is a sanity check required for proper + * color allocation by the progressive image loader + */ + + if (colors[i] == 0) + { + defs[i].red = reds[i]; + defs[i].green = greens[i]; + defs[i].blue = blues[i]; + + colors[i] = gdk_color_context_get_pixel (cc, reds[i], greens[i], blues[i], + &bad_alloc); + + /* successfully allocated, store it */ + + if (!bad_alloc) + { + defs[i].pixel = colors[i]; + allocated[ncols++] = colors[i]; + } + else + failed[nopen++] = i; + } + } + + *nallocated = ncols; + + /* all colors available, all done */ + + if ((ncols == ncolors) || (nopen == 0)) + { + GDK_NOTE (COLOR_CONTEXT, + g_message ("gdk_color_context_get_pixels: got all %i colors; " + "(%i colors allocated so far)\n", ncolors, cc->num_allocated)); + + return; + } + + /* The fun part. We now try to allocate the colors we couldn't allocate + * directly. The first step will map a color onto its nearest color + * that has been allocated (either by us or someone else). If any colors + * remain unallocated, we map these onto the colors that we have allocated + * ourselves. + */ + + /* read up to MAX_IMAGE_COLORS colors of the current colormap */ + + cmapsize = MIN (cc->num_colors, MAX_IMAGE_COLORS); + + /* see if the colormap has any colors to read */ + + if (cmapsize < 0) + { + g_warning ("gdk_color_context_get_pixels: oops! no colors available, " + "your images will look *really* ugly."); + + return; + } + +#ifdef G_ENABLE_DEBUG + exact_col = ncols; +#endif + + /* initialize pixels */ + + for (i = 0; i < cmapsize; i++) + { + cmap[i].pixel = i; + cmap[i].red = cmap[i].green = cmap[i].blue = 0; + } + + /* read the colormap */ + + my_x_query_colors (cc->colormap, cmap, cmapsize); + + /* get a close match for any unallocated colors */ + + counter = nopen; + nopen = 0; + idx = 0; + + do + { + gint d, j, mdist, close, ri, gi, bi; + gint rd, gd, bd; + + i = failed[idx]; + + mdist = 0x1000000; + close = -1; + + /* Store these vals. Small performance increase as this skips three + * indexing operations in the loop code. + */ + + ri = reds[i]; + gi = greens[i]; + bi = blues[i]; + + /* Walk all colors in the colormap and see which one is the + * closest. Uses plain least squares. + */ + + for (j = 0; (j < cmapsize) && (mdist != 0); j++) + { + /* Don't replace these by shifts; the sign may get clobbered */ + + rd = (ri - cmap[j].red) / 256; + gd = (gi - cmap[j].green) / 256; + bd = (bi - cmap[j].blue) / 256; + + d = rd * rd + gd * gd + bd * bd; + + if (d < mdist) + { + close = j; + mdist = d; + } + } + + if (close != -1) + { + rd = cmap[close].red; + gd = cmap[close].green; + bd = cmap[close].blue; + + /* allocate */ + + colors[i] = gdk_color_context_get_pixel (cc, rd, gd, bd, &bad_alloc); + + /* store */ + + if (!bad_alloc) + { + defs[i] = cmap[close]; + defs[i].pixel = colors[i]; + allocated[ncols++] = colors[i]; +#ifdef G_ENABLE_DEBUG + close_col++; +#endif + } else + failed[nopen++] = i; + } else + failed[nopen++] = i; + /* deal with in next stage if allocation failed */ + } + while (++idx < counter); + + *nallocated = ncols; + + /* This is the maximum no. of allocated colors. See also the nopen == 0 + * note above. + */ + + if ((ncols == ncolors) || (nopen == 0)) + { + GDK_NOTE (COLOR_CONTEXT, + g_message ("gdk_color_context_get_pixels: got %i colors, %i exact and " + "%i close (%i colors allocated so far)\n", + ncolors, exact_col, close_col, cc->num_allocated)); + + return; + } + + /* Now map any remaining unallocated pixels into the colors we did get */ + + idx = 0; + + do + { + gint d, mdist, close, ri, gi, bi; + gint j, rd, gd, bd; + + i = failed[idx]; + + mdist = 0x1000000; + close = -1; + + /* store */ + + ri = reds[i]; + gi = greens[i]; + bi = blues[i]; + + /* search allocated colors */ + + for (j = 0; (j < ncols) && (mdist != 0); j++) + { + k = allocated[j]; + + /* Don't replace these by shifts; the sign may get clobbered */ + + rd = (ri - defs[k].red) / 256; + gd = (gi - defs[k].green) / 256; + bd = (bi - defs[k].blue) / 256; + + d = rd * rd + gd * gd + bd * bd; + + if (d < mdist) + { + close = k; + mdist = d; + } + } + + if (close < 0) + { + /* too bad, map to black */ + + defs[i].pixel = cc->black_pixel; + defs[i].red = defs[i].green = defs[i].blue = 0; +#ifdef G_ENABLE_DEBUG + black_col++; +#endif + } + else + { + defs[i] = defs[close]; +#ifdef G_ENABLE_DEBUG + subst_col++; +#endif + } + + colors[i] = defs[i].pixel; + } + while (++idx < nopen); + + GDK_NOTE (COLOR_CONTEXT, + g_message ("gdk_color_context_get_pixels: got %i colors, %i exact, %i close, " + "%i substituted, %i to black (%i colors allocated so far)\n", + ncolors, exact_col, close_col, subst_col, black_col, cc->num_allocated)); +} + +void +gdk_color_context_get_pixels_incremental (GdkColorContext *cc, + gushort *reds, + gushort *greens, + gushort *blues, + gint ncolors, + gint *used, + gulong *colors, + gint *nallocated) +{ + gint i, k, idx; + gint cmapsize, ncols = 0, nopen = 0, counter = 0; + gint bad_alloc = FALSE; + gint failed[MAX_IMAGE_COLORS], allocated[MAX_IMAGE_COLORS]; + GdkColor defs[MAX_IMAGE_COLORS], cmap[MAX_IMAGE_COLORS]; +#ifdef G_ENABLE_DEBUG + gint exact_col = 0, subst_col = 0, close_col = 0, black_col = 0; +#endif + + g_assert (cc != NULL); + g_assert (reds != NULL); + g_assert (greens != NULL); + g_assert (blues != NULL); + g_assert (used != NULL); + g_assert (colors != NULL); + g_assert (nallocated != NULL); + + memset (defs, 0, MAX_IMAGE_COLORS * sizeof (GdkColor)); + memset (failed, 0, MAX_IMAGE_COLORS * sizeof (gint)); + memset (allocated, 0, MAX_IMAGE_COLORS * sizeof (gint)); + + /* Will only have a value if used by the progressive image loader */ + + ncols = *nallocated; + + *nallocated = 0; + + /* First allocate all pixels */ + + for (i = 0; i < ncolors; i++) + { + /* used[i] is only -1 if the pixel at that location hasn't + * been allocated yet. This is a sanity check required for proper + * color allocation by the progressive image loader. + * When colors[i] == 0 it indicates the slot is available for + * allocation. + */ + + if (used[i] != FALSE) + { + if (colors[i] == 0) + { + defs[i].red = reds[i]; + defs[i].green = greens[i]; + defs[i].blue = blues[i]; + + colors[i] = gdk_color_context_get_pixel (cc, reds[i], greens[i], blues[i], &bad_alloc); + + /* successfully allocated, store it */ + + if (!bad_alloc) + { + defs[i].pixel = colors[i]; + allocated[ncols++] = colors[i]; + } + else + failed[nopen++] = i; + } +#ifdef DEBUG + else + GDK_NOTE (COLOR_CONTEXT, + g_message ("gdk_color_context_get_pixels_incremental: " + "pixel at slot %i already allocated, skipping\n", i)); +#endif + } + } + + *nallocated = ncols; + + if ((ncols == ncolors) || (nopen == 0)) + { + GDK_NOTE (COLOR_CONTEXT, + g_message ("gdk_color_context_get_pixels_incremental: got all %i colors " + "(%i colors allocated so far)\n", + ncolors, cc->num_allocated)); + + return; + } + + cmapsize = MIN (cc->num_colors, MAX_IMAGE_COLORS); + + if (cmapsize < 0) + { + g_warning ("gdk_color_context_get_pixels_incremental: oops! " + "No colors available images will look *really* ugly."); + return; + } + +#ifdef G_ENABLE_DEBUG + exact_col = ncols; +#endif + + /* initialize pixels */ + + for (i = 0; i < cmapsize; i++) + { + cmap[i].pixel = i; + cmap[i].red = cmap[i].green = cmap[i].blue = 0; + } + + /* read */ + + my_x_query_colors (cc->colormap, cmap, cmapsize); + + /* now match any unallocated colors */ + + counter = nopen; + nopen = 0; + idx = 0; + + do + { + gint d, j, mdist, close, ri, gi, bi; + gint rd, gd, bd; + + i = failed[idx]; + + mdist = 0x1000000; + close = -1; + + /* store */ + + ri = reds[i]; + gi = greens[i]; + bi = blues[i]; + + for (j = 0; (j < cmapsize) && (mdist != 0); j++) + { + /* Don't replace these by shifts; the sign may get clobbered */ + + rd = (ri - cmap[j].red) / 256; + gd = (gi - cmap[j].green) / 256; + bd = (bi - cmap[j].blue) / 256; + + d = rd * rd + gd * gd + bd * bd; + + if (d < mdist) + { + close = j; + mdist = d; + } + } + + if (close != -1) + { + rd = cmap[close].red; + gd = cmap[close].green; + bd = cmap[close].blue; + + /* allocate */ + + colors[i] = gdk_color_context_get_pixel (cc, rd, gd, bd, &bad_alloc); + + /* store */ + + if (!bad_alloc) + { + defs[i] = cmap[close]; + defs[i].pixel = colors[i]; + allocated[ncols++] = colors[i]; +#ifdef G_ENABLE_DEBUG + close_col++; +#endif + } + else + failed[nopen++] = i; + } + else + failed[nopen++] = i; + /* deal with in next stage if allocation failed */ + } + while (++idx < counter); + + *nallocated = ncols; + + if ((ncols == ncolors) || (nopen == 0)) + { + GDK_NOTE (COLOR_CONTEXT, + g_message ("gdk_color_context_get_pixels_incremental: " + "got %i colors, %i exact and %i close " + "(%i colors allocated so far)\n", + ncolors, exact_col, close_col, cc->num_allocated)); + + return; + } + + /* map remaining unallocated pixels into colors we did get */ + + idx = 0; + + do + { + gint d, mdist, close, ri, gi, bi; + gint j, rd, gd, bd; + + i = failed[idx]; + + mdist = 0x1000000; + close = -1; + + ri = reds[i]; + gi = greens[i]; + bi = blues[i]; + + /* search allocated colors */ + + for (j = 0; (j < ncols) && (mdist != 0); j++) + { + k = allocated[j]; + + /* downscale */ + /* Don't replace these by shifts; the sign may get clobbered */ + + rd = (ri - defs[k].red) / 256; + gd = (gi - defs[k].green) / 256; + bd = (bi - defs[k].blue) / 256; + + d = rd * rd + gd * gd + bd * bd; + + if (d < mdist) + { + close = k; + mdist = d; + } + } + + if (close < 0) + { + /* too bad, map to black */ + + defs[i].pixel = cc->black_pixel; + defs[i].red = defs[i].green = defs[i].blue = 0; +#ifdef G_ENABLE_DEBUG + black_col++; +#endif + } + else + { + defs[i] = defs[close]; +#ifdef G_ENABLE_DEBUG + subst_col++; +#endif + } + + colors[i] = defs[i].pixel; + } + while (++idx < nopen); + + GDK_NOTE (COLOR_CONTEXT, + g_message ("gdk_color_context_get_pixels_incremental: " + "got %i colors, %i exact, %i close, %i substituted, %i to black " + "(%i colors allocated so far)\n", + ncolors, exact_col, close_col, subst_col, black_col, cc->num_allocated)); +} + +gint +gdk_color_context_query_color (GdkColorContext *cc, + GdkColor *color) +{ + return gdk_color_context_query_colors (cc, color, 1); +} + +gint +gdk_color_context_query_colors (GdkColorContext *cc, + GdkColor *colors, + gint num_colors) +{ + gint i; + GdkColor *tc; + + g_assert (cc != NULL); + g_assert (colors != NULL); + + switch (cc->mode) + { + case GDK_CC_MODE_BW: + for (i = 0, tc = colors; i < num_colors; i++, tc++) + { + if (tc->pixel == cc->white_pixel) + tc->red = tc->green = tc->blue = 65535; + else + tc->red = tc->green = tc->blue = 0; + } + break; + + case GDK_CC_MODE_TRUE: + if (cc->clut == NULL) + for (i = 0, tc = colors; i < num_colors; i++, tc++) + { + tc->red = ((tc->pixel & cc->masks.red) >> cc->shifts.red) << (16 - cc->bits.red); + tc->green = ((tc->pixel & cc->masks.green) >> cc->shifts.green) << (16 - cc->bits.green); + tc->blue = ((tc->pixel & cc->masks.blue) >> cc->shifts.blue) << (16 - cc->bits.blue); + } + else + { + my_x_query_colors (cc->colormap, colors, num_colors); + return 1; + } + break; + + case GDK_CC_MODE_STD_CMAP: + default: + if (cc->cmap == NULL) + { + my_x_query_colors (cc->colormap, colors, num_colors); + return 1; + } + else + { + gint first, last, half; + gulong half_pixel; + + for (i = 0, tc = colors; i < num_colors; i++) + { + first = 0; + last = cc->num_colors - 1; + + while (first <= last) + { + half = (first + last) / 2; + half_pixel = cc->cmap[half].pixel; + + if (tc->pixel == half_pixel) + { + tc->red = cc->cmap[half].red; + tc->green = cc->cmap[half].green; + tc->blue = cc->cmap[half].blue; + first = last + 1; /* false break */ + } + else + { + if (tc->pixel > half_pixel) + first = half + 1; + else + last = half - 1; + } + } + } + return 1; + } + break; + } + return 1; +} + +gint +gdk_color_context_add_palette (GdkColorContext *cc, + GdkColor *palette, + gint num_palette) +{ + gint i, j, erg; + gushort r, g, b; + gulong pixel[1]; + + g_assert (cc != NULL); + + /* initialize this palette (will also erase previous palette as well) */ + + init_palette (cc); + + /* restore previous mode if we aren't adding a new palette */ + + if (num_palette == 0) + { + /* GDK_CC_MODE_STD_CMAP uses a hash table, so we'd better initialize one */ + + /* XXX: here, the hash table is already initialized */ + + return 0; + } + + /* Initialize a hash table for this palette (we need one for allocating + * the pixels in the palette using the current settings) + */ + + if (cc->color_hash == NULL) + cc->color_hash = g_hash_table_new (hash_color, compare_colors); + + /* copy incoming palette */ + + cc->palette = g_new0(GdkColor, num_palette); + + j = 0; + + for (i = 0; i < num_palette; i++) + { + erg = 0; + pixel[0] = 0; + + /* try to allocate this color */ + + r = palette[i].red; + g = palette[i].green; + b = palette[i].blue; + + gdk_color_context_get_pixels (cc, &r, &g, &b, 1, pixel, &erg); + + /* only store if we succeed */ + + if (erg) + { + /* store in palette */ + + cc->palette[j].red = r; + cc->palette[j].green = g; + cc->palette[j].blue = b; + cc->palette[j].pixel = pixel[0]; + + /* move to next slot */ + + j++; + } + } + + /* resize to fit */ + + if (j != num_palette) + cc->palette = g_realloc (cc->palette, j * sizeof (GdkColor)); + + /* clear the hash table, we don't use it when dithering */ + + if (cc->color_hash) + { + g_hash_table_destroy (cc->color_hash); + cc->color_hash = NULL; + } + + /* store real palette size */ + + cc->num_palette = j; + + /* switch to palette mode */ + + cc->mode = GDK_CC_MODE_PALETTE; + + /* sort palette */ + + qsort (cc->palette, cc->num_palette, sizeof (GdkColor), pixel_sort); + + cc->fast_dither = NULL; + + return j; +} + +void +gdk_color_context_init_dither (GdkColorContext *cc) +{ + gint rr, gg, bb, err, erg, erb; + gint success = FALSE; + + g_assert (cc != NULL); + + /* now we can initialize the fast dither matrix */ + + if (cc->fast_dither == NULL) + cc->fast_dither = g_new (GdkColorContextDither, 1); + + /* Fill it. We ignore unsuccessful allocations, they are just mapped + * to black instead */ + + for (rr = 0; rr < 32; rr++) + for (gg = 0; gg < 32; gg++) + for (bb = 0; bb < 32; bb++) + { + err = (rr << 3) | (rr >> 2); + erg = (gg << 3) | (gg >> 2); + erb = (bb << 3) | (bb >> 2); + + cc->fast_dither->fast_rgb[rr][gg][bb] = + gdk_color_context_get_index_from_palette (cc, &err, &erg, &erb, &success); + cc->fast_dither->fast_err[rr][gg][bb] = err; + cc->fast_dither->fast_erg[rr][gg][bb] = erg; + cc->fast_dither->fast_erb[rr][gg][bb] = erb; + } +} + +void +gdk_color_context_free_dither (GdkColorContext *cc) +{ + g_assert (cc != NULL); + + if (cc->fast_dither) + g_free (cc->fast_dither); + + cc->fast_dither = NULL; +} + +gulong +gdk_color_context_get_pixel_from_palette (GdkColorContext *cc, + gushort *red, + gushort *green, + gushort *blue, + gint *failed) +{ + gulong pixel = 0; + gint dif, dr, dg, db, j = -1; + gint mindif = 0x7fffffff; + gint err = 0, erg = 0, erb = 0; + gint i; + + g_assert (cc != NULL); + g_assert (red != NULL); + g_assert (green != NULL); + g_assert (blue != NULL); + g_assert (failed != NULL); + + *failed = FALSE; + + for (i = 0; i < cc->num_palette; i++) + { + dr = *red - cc->palette[i].red; + dg = *green - cc->palette[i].green; + db = *blue - cc->palette[i].blue; + + dif = dr * dr + dg * dg + db * db; + + if (dif < mindif) + { + mindif = dif; + j = i; + pixel = cc->palette[i].pixel; + err = dr; + erg = dg; + erb = db; + + if (mindif == 0) + break; + } + } + + /* we failed to map onto a color */ + + if (j == -1) + *failed = TRUE; + else + { + *red = ABS (err); + *green = ABS (erg); + *blue = ABS (erb); + } + + return pixel; +} + +guchar +gdk_color_context_get_index_from_palette (GdkColorContext *cc, + gint *red, + gint *green, + gint *blue, + gint *failed) +{ + gint dif, dr, dg, db, j = -1; + gint mindif = 0x7fffffff; + gint err = 0, erg = 0, erb = 0; + gint i; + + g_assert (cc != NULL); + g_assert (red != NULL); + g_assert (green != NULL); + g_assert (blue != NULL); + g_assert (failed != NULL); + + *failed = FALSE; + + for (i = 0; i < cc->num_palette; i++) + { + dr = *red - cc->palette[i].red; + dg = *green - cc->palette[i].green; + db = *blue - cc->palette[i].blue; + + dif = dr * dr + dg * dg + db * db; + + if (dif < mindif) + { + mindif = dif; + j = i; + err = dr; + erg = dg; + erb = db; + + if (mindif == 0) + break; + } + } + + /* we failed to map onto a color */ + + if (j == -1) + { + *failed = TRUE; + j = 0; + } + else + { + /* return error fractions */ + + *red = err; + *green = erg; + *blue = erb; + } + + return j; +} diff --git a/gdk/win32/gdkcolor-win32.c b/gdk/win32/gdkcolor-win32.c new file mode 100644 index 000000000..4b81f24d5 --- /dev/null +++ b/gdk/win32/gdkcolor-win32.c @@ -0,0 +1,2443 @@ +/* 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 <stdlib.h> +#include <string.h> +#include <time.h> + +#include "gdk.h" +#include "gdkprivate.h" +#include "gdkx.h" + +#ifdef _MSC_VER +#define strcasecmp stricmp +#endif + +static gint gdk_colormap_match_color (GdkColormap *cmap, + GdkColor *color, + const gchar *available); +static void gdk_colormap_add (GdkColormap *cmap); +static void gdk_colormap_remove (GdkColormap *cmap); +static guint gdk_colormap_hash (Colormap *cmap); +static gint gdk_colormap_cmp (Colormap *a, + Colormap *b); +static void gdk_colormap_real_destroy (GdkColormap *colormap); + +static GHashTable *colormap_hash = NULL; + +static Status +alloc_color_cells(Colormap colormap, + gboolean contig, + unsigned long plane_masks_return[], + unsigned int nplanes, + unsigned long pixels_return[], + unsigned int npixels) +{ + unsigned int i, nfree, iret; + + nfree = 0; + for (i = 0; i < colormap->size && nfree < npixels; i++) + if (!colormap->in_use[i]) + nfree++; + + if (colormap->size + npixels - nfree > colormap->sizepalette) + { + g_warning ("alloc_color_cells: too large palette: %d", + colormap->size + npixels); + return FALSE; + } + + iret = 0; + for (i = 0; i < colormap->size && iret < npixels; i++) + if (!colormap->in_use[i]) + { + colormap->in_use[i] = TRUE; + pixels_return[iret] = i; + iret++; + } + + if (nfree < npixels) + { + int nmore = npixels - nfree; + + /* I don't understand why, if the code below in #if 0 is + enabled, gdkrgb fails miserably. The palette doesn't get + realized correctly. There doesn't seem to be any harm done by + keeping this code out, either. */ +#ifdef SOME_STRANGE_BUG + if (!ResizePalette (colormap->palette, colormap->size + nmore)) + { + g_warning ("alloc_color_cells: ResizePalette to %d failed", + colormap->size + nmore); + return FALSE; + } + g_print("alloc_color_cells: %#x to %d\n", + colormap->palette, colormap->size + nmore); +#endif + for (i = colormap->size; i < colormap->size + nmore; i++) + { + pixels_return[iret] = i; + iret++; + colormap->in_use[i] = TRUE; + } +#ifdef SOME_STRANGE_BUG + colormap->size += nmore; +#endif + } + return TRUE; +} + +/* The following functions are from Tk8.0, but heavily modified. + Here are tk's licensing terms. I hope these terms don't conflict + with the GNU Library General Public License? They shouldn't, as + they are looser that the GLPL, yes? */ + +/* +This software is copyrighted by the Regents of the University of +California, Sun Microsystems, Inc., and other parties. The following +terms apply to all files associated with the software unless explicitly +disclaimed in individual files. + +The authors hereby grant permission to use, copy, modify, distribute, +and license this software and its documentation for any purpose, provided +that existing copyright notices are retained in all copies and that this +notice is included verbatim in any distributions. No written agreement, +license, or royalty fee is required for any of the authorized uses. +Modifications to this software may be copyrighted by their authors +and need not follow the licensing terms described here, provided that +the new terms are clearly indicated on the first page of each file where +they apply. + +IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY +FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY +DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE +IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE +NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR +MODIFICATIONS. + +GOVERNMENT USE: If you are acquiring this software on behalf of the +U.S. government, the Government shall have only "Restricted Rights" +in the software and related documentation as defined in the Federal +Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you +are acquiring the software on behalf of the Department of Defense, the +software shall be classified as "Commercial Computer Software" and the +Government shall have only "Restricted Rights" as defined in Clause +252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the +authors grant the U.S. Government and others acting in its behalf +permission to use and distribute the software in accordance with the +terms specified in this license. +*/ +/* + *---------------------------------------------------------------------- + * + * XAllocColor -- + * + * Find the closest available color to the specified XColor. + * + * Results: + * Updates the color argument and returns 1 on success. Otherwise + * returns 0. + * + * Side effects: + * Allocates a new color in the palette. + * + *---------------------------------------------------------------------- + */ + +static int +alloc_color(Colormap colormap, + XColor *color, + guint *pixelp) +{ + PALETTEENTRY entry, closeEntry; + HDC hdc; + unsigned int i; + + entry = *color; + entry.peFlags = 0; + + if (colormap->rc_palette) + { + COLORREF newPixel, closePixel; + UINT index; + + /* + * Find the nearest existing palette entry. + */ + + newPixel = RGB (entry.peRed, entry.peGreen, entry.peBlue); + index = GetNearestPaletteIndex (colormap->palette, newPixel); + GetPaletteEntries (colormap->palette, index, 1, &closeEntry); + closePixel = RGB (closeEntry.peRed, closeEntry.peGreen, + closeEntry.peBlue); + + if (newPixel != closePixel) + { + /* Not a perfect match. */ + if (!colormap->in_use[index]) + { + /* It was a free'd entry anyway, so we can use it, and + set it to the correct color. */ + if (SetPaletteEntries (colormap->palette, index, 1, &entry) == 0) + g_warning ("alloc_color: SetPaletteEntries #1 failed"); + } + else + { + /* The close entry found is in use, so search for a + unused slot. */ + + for (i = 0; i < colormap->size; i++) + if (!colormap->in_use[i]) + { + /* A free slot, use it. */ + if (SetPaletteEntries (colormap->palette, + index, 1, &entry) == 0) + g_warning ("alloc_color: SetPaletteEntries #2 failed"); + index = i; + break; + } + if (i == colormap->size) + { + /* No free slots found. If the palette isn't maximal + yet, grow it. */ + if (colormap->size == colormap->sizepalette) + { + /* The palette is maximal, and no free slots available, + so use the close entry, then, dammit. */ + *color = closeEntry; + } + else + { + /* There is room to grow the palette. */ + index = colormap->size; + colormap->size++; + if (!ResizePalette (colormap->palette, colormap->size)) + g_warning ("alloc_color: ResizePalette to %d failed", + colormap->size); + if (SetPaletteEntries (colormap->palette, index, 1, &entry) == 0) + g_warning ("alloc_color: SetPaletteEntries #3 failed"); + } + } + } + colormap->stale = TRUE; + } + else + { + /* We got a match, so use it. */ + } + + *pixelp = index; + colormap->in_use[index] = TRUE; +#if 0 + g_print("alloc_color from %#x: index %d for %02x %02x %02x\n", + colormap->palette, index, + entry.peRed, entry.peGreen, entry.peBlue); +#endif + } + else + { + /* + * Determine what color will actually be used on non-colormap systems. + */ + *pixelp = GetNearestColor (gdk_DC, RGB(entry.peRed, entry.peGreen, entry.peBlue)); + + color->peRed = GetRValue (*pixelp); + color->peGreen = GetGValue (*pixelp); + color->peBlue = GetBValue (*pixelp); + } + + return 1; +} + +/* + *---------------------------------------------------------------------- + * + * XFreeColors -- + * + * Deallocate a block of colors. + * + * Results: + * None. + * + * Side effects: + * Removes entries for the current palette and compacts the + * remaining set. + * + *---------------------------------------------------------------------- + */ + +static void +XFreeColors(Colormap colormap, + gulong *pixels, + gint npixels, + gulong planes) +{ + gint i; + PALETTEENTRY entries[256]; + + /* + * We don't have to do anything for non-palette devices. + */ + + if (colormap->rc_palette) + { + int npal; + int lowestpixel = 256; + int highestpixel = -1; + + npal = GetPaletteEntries (colormap->palette, 0, 256, entries); + for (i = 0; i < npixels; i++) + { + int pixel = pixels[i]; + + if (pixel < lowestpixel) + lowestpixel = pixel; + if (pixel > highestpixel) + highestpixel = pixel; + + colormap->in_use[pixel] = FALSE; + + entries[pixel] = entries[0]; + } +#if 0 + if (SetPaletteEntries (colormap->palette, lowestpixel, + highestpixel - lowestpixel + 1, + entries + lowestpixel) == 0) + g_warning ("XFreeColors: SetPaletteEntries failed"); +#endif + colormap->stale = TRUE; +#if 0 + g_print("XFreeColors %#x lowestpixel = %d, highestpixel = %d\n", + colormap->palette, lowestpixel, highestpixel); +#endif + } +} + +/* + *---------------------------------------------------------------------- + * + * XCreateColormap -- + * + * Allocate a new colormap. + * + * Results: + * Returns a newly allocated colormap. + * + * Side effects: + * Allocates an empty palette and color list. + * + *---------------------------------------------------------------------- + */ + +static Colormap +create_colormap (HWND w, + Visual *visual, + int alloc) +{ + char logPalBuf[sizeof(LOGPALETTE) + 256 * sizeof(PALETTEENTRY)]; + LOGPALETTE *logPalettePtr; + PALETTEENTRY *entryPtr; + Colormap colormap; + guint i; + HPALETTE sysPal; + HDC hdc; + + /* Should the alloc parameter do something? */ + + + /* Allocate a starting palette with all of the reserved colors. */ + + logPalettePtr = (LOGPALETTE *) logPalBuf; + logPalettePtr->palVersion = 0x300; + sysPal = (HPALETTE) GetStockObject (DEFAULT_PALETTE); + logPalettePtr->palNumEntries = + GetPaletteEntries (sysPal, 0, 256, logPalettePtr->palPalEntry); + + colormap = (Colormap) g_new (ColormapStruct, 1); + colormap->size = logPalettePtr->palNumEntries; + colormap->stale = TRUE; + colormap->palette = CreatePalette (logPalettePtr); + hdc = GetDC (NULL); + colormap->rc_palette = ((GetDeviceCaps (hdc, RASTERCAPS) & RC_PALETTE) != 0); + if (colormap->rc_palette) + { + colormap->sizepalette = GetDeviceCaps (hdc, SIZEPALETTE); + colormap->in_use = g_new (gboolean, colormap->sizepalette); + /* Mark static colors in use. */ + for (i = 0; i < logPalettePtr->palNumEntries; i++) + colormap->in_use[i] = TRUE; + /* Mark rest not in use */ + for (i = logPalettePtr->palNumEntries; i < colormap->sizepalette; i++) + colormap->in_use[i] = FALSE; + } + ReleaseDC (NULL, hdc); + + return colormap; +} + +/* + *---------------------------------------------------------------------- + * + * XFreeColormap -- + * + * Frees the resources associated with the given colormap. + * + * Results: + * None. + * + * Side effects: + * Deletes the palette associated with the colormap. Note that + * the palette must not be selected into a device context when + * this occurs. + * + *---------------------------------------------------------------------- + */ + +static void +XFreeColormap(Colormap colormap) + +{ + if (!DeleteObject (colormap->palette)) + { + g_error ("Unable to free colormap, palette is still selected."); + } + g_free (colormap); +} + +typedef struct { + char *name; + unsigned char red; + unsigned char green; + unsigned char blue; +} XColorEntry; + +static XColorEntry xColors[] = { + { "alice blue", 240, 248, 255 }, + { "AliceBlue", 240, 248, 255 }, + { "antique white", 250, 235, 215 }, + { "AntiqueWhite", 250, 235, 215 }, + { "AntiqueWhite1", 255, 239, 219 }, + { "AntiqueWhite2", 238, 223, 204 }, + { "AntiqueWhite3", 205, 192, 176 }, + { "AntiqueWhite4", 139, 131, 120 }, + { "aquamarine", 127, 255, 212 }, + { "aquamarine1", 127, 255, 212 }, + { "aquamarine2", 118, 238, 198 }, + { "aquamarine3", 102, 205, 170 }, + { "aquamarine4", 69, 139, 116 }, + { "azure", 240, 255, 255 }, + { "azure1", 240, 255, 255 }, + { "azure2", 224, 238, 238 }, + { "azure3", 193, 205, 205 }, + { "azure4", 131, 139, 139 }, + { "beige", 245, 245, 220 }, + { "bisque", 255, 228, 196 }, + { "bisque1", 255, 228, 196 }, + { "bisque2", 238, 213, 183 }, + { "bisque3", 205, 183, 158 }, + { "bisque4", 139, 125, 107 }, + { "black", 0, 0, 0 }, + { "blanched almond", 255, 235, 205 }, + { "BlanchedAlmond", 255, 235, 205 }, + { "blue", 0, 0, 255 }, + { "blue violet", 138, 43, 226 }, + { "blue1", 0, 0, 255 }, + { "blue2", 0, 0, 238 }, + { "blue3", 0, 0, 205 }, + { "blue4", 0, 0, 139 }, + { "BlueViolet", 138, 43, 226 }, + { "brown", 165, 42, 42 }, + { "brown1", 255, 64, 64 }, + { "brown2", 238, 59, 59 }, + { "brown3", 205, 51, 51 }, + { "brown4", 139, 35, 35 }, + { "burlywood", 222, 184, 135 }, + { "burlywood1", 255, 211, 155 }, + { "burlywood2", 238, 197, 145 }, + { "burlywood3", 205, 170, 125 }, + { "burlywood4", 139, 115, 85 }, + { "cadet blue", 95, 158, 160 }, + { "CadetBlue", 95, 158, 160 }, + { "CadetBlue1", 152, 245, 255 }, + { "CadetBlue2", 142, 229, 238 }, + { "CadetBlue3", 122, 197, 205 }, + { "CadetBlue4", 83, 134, 139 }, + { "chartreuse", 127, 255, 0 }, + { "chartreuse1", 127, 255, 0 }, + { "chartreuse2", 118, 238, 0 }, + { "chartreuse3", 102, 205, 0 }, + { "chartreuse4", 69, 139, 0 }, + { "chocolate", 210, 105, 30 }, + { "chocolate1", 255, 127, 36 }, + { "chocolate2", 238, 118, 33 }, + { "chocolate3", 205, 102, 29 }, + { "chocolate4", 139, 69, 19 }, + { "coral", 255, 127, 80 }, + { "coral1", 255, 114, 86 }, + { "coral2", 238, 106, 80 }, + { "coral3", 205, 91, 69 }, + { "coral4", 139, 62, 47 }, + { "cornflower blue", 100, 149, 237 }, + { "CornflowerBlue", 100, 149, 237 }, + { "cornsilk", 255, 248, 220 }, + { "cornsilk1", 255, 248, 220 }, + { "cornsilk2", 238, 232, 205 }, + { "cornsilk3", 205, 200, 177 }, + { "cornsilk4", 139, 136, 120 }, + { "cyan", 0, 255, 255 }, + { "cyan1", 0, 255, 255 }, + { "cyan2", 0, 238, 238 }, + { "cyan3", 0, 205, 205 }, + { "cyan4", 0, 139, 139 }, + { "dark blue", 0, 0, 139 }, + { "dark cyan", 0, 139, 139 }, + { "dark goldenrod", 184, 134, 11 }, + { "dark gray", 169, 169, 169 }, + { "dark green", 0, 100, 0 }, + { "dark grey", 169, 169, 169 }, + { "dark khaki", 189, 183, 107 }, + { "dark magenta", 139, 0, 139 }, + { "dark olive green", 85, 107, 47 }, + { "dark orange", 255, 140, 0 }, + { "dark orchid", 153, 50, 204 }, + { "dark red", 139, 0, 0 }, + { "dark salmon", 233, 150, 122 }, + { "dark sea green", 143, 188, 143 }, + { "dark slate blue", 72, 61, 139 }, + { "dark slate gray", 47, 79, 79 }, + { "dark slate grey", 47, 79, 79 }, + { "dark turquoise", 0, 206, 209 }, + { "dark violet", 148, 0, 211 }, + { "DarkBlue", 0, 0, 139 }, + { "DarkCyan", 0, 139, 139 }, + { "DarkGoldenrod", 184, 134, 11 }, + { "DarkGoldenrod1", 255, 185, 15 }, + { "DarkGoldenrod2", 238, 173, 14 }, + { "DarkGoldenrod3", 205, 149, 12 }, + { "DarkGoldenrod4", 139, 101, 8 }, + { "DarkGray", 169, 169, 169 }, + { "DarkGreen", 0, 100, 0 }, + { "DarkGrey", 169, 169, 169 }, + { "DarkKhaki", 189, 183, 107 }, + { "DarkMagenta", 139, 0, 139 }, + { "DarkOliveGreen", 85, 107, 47 }, + { "DarkOliveGreen1", 202, 255, 112 }, + { "DarkOliveGreen2", 188, 238, 104 }, + { "DarkOliveGreen3", 162, 205, 90 }, + { "DarkOliveGreen4", 110, 139, 61 }, + { "DarkOrange", 255, 140, 0 }, + { "DarkOrange1", 255, 127, 0 }, + { "DarkOrange2", 238, 118, 0 }, + { "DarkOrange3", 205, 102, 0 }, + { "DarkOrange4", 139, 69, 0 }, + { "DarkOrchid", 153, 50, 204 }, + { "DarkOrchid1", 191, 62, 255 }, + { "DarkOrchid2", 178, 58, 238 }, + { "DarkOrchid3", 154, 50, 205 }, + { "DarkOrchid4", 104, 34, 139 }, + { "DarkRed", 139, 0, 0 }, + { "DarkSalmon", 233, 150, 122 }, + { "DarkSeaGreen", 143, 188, 143 }, + { "DarkSeaGreen1", 193, 255, 193 }, + { "DarkSeaGreen2", 180, 238, 180 }, + { "DarkSeaGreen3", 155, 205, 155 }, + { "DarkSeaGreen4", 105, 139, 105 }, + { "DarkSlateBlue", 72, 61, 139 }, + { "DarkSlateGray", 47, 79, 79 }, + { "DarkSlateGray1", 151, 255, 255 }, + { "DarkSlateGray2", 141, 238, 238 }, + { "DarkSlateGray3", 121, 205, 205 }, + { "DarkSlateGray4", 82, 139, 139 }, + { "DarkSlateGrey", 47, 79, 79 }, + { "DarkTurquoise", 0, 206, 209 }, + { "DarkViolet", 148, 0, 211 }, + { "deep pink", 255, 20, 147 }, + { "deep sky blue", 0, 191, 255 }, + { "DeepPink", 255, 20, 147 }, + { "DeepPink1", 255, 20, 147 }, + { "DeepPink2", 238, 18, 137 }, + { "DeepPink3", 205, 16, 118 }, + { "DeepPink4", 139, 10, 80 }, + { "DeepSkyBlue", 0, 191, 255 }, + { "DeepSkyBlue1", 0, 191, 255 }, + { "DeepSkyBlue2", 0, 178, 238 }, + { "DeepSkyBlue3", 0, 154, 205 }, + { "DeepSkyBlue4", 0, 104, 139 }, + { "dim gray", 105, 105, 105 }, + { "dim grey", 105, 105, 105 }, + { "DimGray", 105, 105, 105 }, + { "DimGrey", 105, 105, 105 }, + { "dodger blue", 30, 144, 255 }, + { "DodgerBlue", 30, 144, 255 }, + { "DodgerBlue1", 30, 144, 255 }, + { "DodgerBlue2", 28, 134, 238 }, + { "DodgerBlue3", 24, 116, 205 }, + { "DodgerBlue4", 16, 78, 139 }, + { "firebrick", 178, 34, 34 }, + { "firebrick1", 255, 48, 48 }, + { "firebrick2", 238, 44, 44 }, + { "firebrick3", 205, 38, 38 }, + { "firebrick4", 139, 26, 26 }, + { "floral white", 255, 250, 240 }, + { "FloralWhite", 255, 250, 240 }, + { "forest green", 34, 139, 34 }, + { "ForestGreen", 34, 139, 34 }, + { "gainsboro", 220, 220, 220 }, + { "ghost white", 248, 248, 255 }, + { "GhostWhite", 248, 248, 255 }, + { "gold", 255, 215, 0 }, + { "gold1", 255, 215, 0 }, + { "gold2", 238, 201, 0 }, + { "gold3", 205, 173, 0 }, + { "gold4", 139, 117, 0 }, + { "goldenrod", 218, 165, 32 }, + { "goldenrod1", 255, 193, 37 }, + { "goldenrod2", 238, 180, 34 }, + { "goldenrod3", 205, 155, 29 }, + { "goldenrod4", 139, 105, 20 }, + { "gray", 190, 190, 190 }, + { "gray0", 0, 0, 0 }, + { "gray1", 3, 3, 3 }, + { "gray10", 26, 26, 26 }, + { "gray100", 255, 255, 255 }, + { "gray11", 28, 28, 28 }, + { "gray12", 31, 31, 31 }, + { "gray13", 33, 33, 33 }, + { "gray14", 36, 36, 36 }, + { "gray15", 38, 38, 38 }, + { "gray16", 41, 41, 41 }, + { "gray17", 43, 43, 43 }, + { "gray18", 46, 46, 46 }, + { "gray19", 48, 48, 48 }, + { "gray2", 5, 5, 5 }, + { "gray20", 51, 51, 51 }, + { "gray21", 54, 54, 54 }, + { "gray22", 56, 56, 56 }, + { "gray23", 59, 59, 59 }, + { "gray24", 61, 61, 61 }, + { "gray25", 64, 64, 64 }, + { "gray26", 66, 66, 66 }, + { "gray27", 69, 69, 69 }, + { "gray28", 71, 71, 71 }, + { "gray29", 74, 74, 74 }, + { "gray3", 8, 8, 8 }, + { "gray30", 77, 77, 77 }, + { "gray31", 79, 79, 79 }, + { "gray32", 82, 82, 82 }, + { "gray33", 84, 84, 84 }, + { "gray34", 87, 87, 87 }, + { "gray35", 89, 89, 89 }, + { "gray36", 92, 92, 92 }, + { "gray37", 94, 94, 94 }, + { "gray38", 97, 97, 97 }, + { "gray39", 99, 99, 99 }, + { "gray4", 10, 10, 10 }, + { "gray40", 102, 102, 102 }, + { "gray41", 105, 105, 105 }, + { "gray42", 107, 107, 107 }, + { "gray43", 110, 110, 110 }, + { "gray44", 112, 112, 112 }, + { "gray45", 115, 115, 115 }, + { "gray46", 117, 117, 117 }, + { "gray47", 120, 120, 120 }, + { "gray48", 122, 122, 122 }, + { "gray49", 125, 125, 125 }, + { "gray5", 13, 13, 13 }, + { "gray50", 127, 127, 127 }, + { "gray51", 130, 130, 130 }, + { "gray52", 133, 133, 133 }, + { "gray53", 135, 135, 135 }, + { "gray54", 138, 138, 138 }, + { "gray55", 140, 140, 140 }, + { "gray56", 143, 143, 143 }, + { "gray57", 145, 145, 145 }, + { "gray58", 148, 148, 148 }, + { "gray59", 150, 150, 150 }, + { "gray6", 15, 15, 15 }, + { "gray60", 153, 153, 153 }, + { "gray61", 156, 156, 156 }, + { "gray62", 158, 158, 158 }, + { "gray63", 161, 161, 161 }, + { "gray64", 163, 163, 163 }, + { "gray65", 166, 166, 166 }, + { "gray66", 168, 168, 168 }, + { "gray67", 171, 171, 171 }, + { "gray68", 173, 173, 173 }, + { "gray69", 176, 176, 176 }, + { "gray7", 18, 18, 18 }, + { "gray70", 179, 179, 179 }, + { "gray71", 181, 181, 181 }, + { "gray72", 184, 184, 184 }, + { "gray73", 186, 186, 186 }, + { "gray74", 189, 189, 189 }, + { "gray75", 191, 191, 191 }, + { "gray76", 194, 194, 194 }, + { "gray77", 196, 196, 196 }, + { "gray78", 199, 199, 199 }, + { "gray79", 201, 201, 201 }, + { "gray8", 20, 20, 20 }, + { "gray80", 204, 204, 204 }, + { "gray81", 207, 207, 207 }, + { "gray82", 209, 209, 209 }, + { "gray83", 212, 212, 212 }, + { "gray84", 214, 214, 214 }, + { "gray85", 217, 217, 217 }, + { "gray86", 219, 219, 219 }, + { "gray87", 222, 222, 222 }, + { "gray88", 224, 224, 224 }, + { "gray89", 227, 227, 227 }, + { "gray9", 23, 23, 23 }, + { "gray90", 229, 229, 229 }, + { "gray91", 232, 232, 232 }, + { "gray92", 235, 235, 235 }, + { "gray93", 237, 237, 237 }, + { "gray94", 240, 240, 240 }, + { "gray95", 242, 242, 242 }, + { "gray96", 245, 245, 245 }, + { "gray97", 247, 247, 247 }, + { "gray98", 250, 250, 250 }, + { "gray99", 252, 252, 252 }, + { "green", 0, 255, 0 }, + { "green yellow", 173, 255, 47 }, + { "green1", 0, 255, 0 }, + { "green2", 0, 238, 0 }, + { "green3", 0, 205, 0 }, + { "green4", 0, 139, 0 }, + { "GreenYellow", 173, 255, 47 }, + { "grey", 190, 190, 190 }, + { "grey0", 0, 0, 0 }, + { "grey1", 3, 3, 3 }, + { "grey10", 26, 26, 26 }, + { "grey100", 255, 255, 255 }, + { "grey11", 28, 28, 28 }, + { "grey12", 31, 31, 31 }, + { "grey13", 33, 33, 33 }, + { "grey14", 36, 36, 36 }, + { "grey15", 38, 38, 38 }, + { "grey16", 41, 41, 41 }, + { "grey17", 43, 43, 43 }, + { "grey18", 46, 46, 46 }, + { "grey19", 48, 48, 48 }, + { "grey2", 5, 5, 5 }, + { "grey20", 51, 51, 51 }, + { "grey21", 54, 54, 54 }, + { "grey22", 56, 56, 56 }, + { "grey23", 59, 59, 59 }, + { "grey24", 61, 61, 61 }, + { "grey25", 64, 64, 64 }, + { "grey26", 66, 66, 66 }, + { "grey27", 69, 69, 69 }, + { "grey28", 71, 71, 71 }, + { "grey29", 74, 74, 74 }, + { "grey3", 8, 8, 8 }, + { "grey30", 77, 77, 77 }, + { "grey31", 79, 79, 79 }, + { "grey32", 82, 82, 82 }, + { "grey33", 84, 84, 84 }, + { "grey34", 87, 87, 87 }, + { "grey35", 89, 89, 89 }, + { "grey36", 92, 92, 92 }, + { "grey37", 94, 94, 94 }, + { "grey38", 97, 97, 97 }, + { "grey39", 99, 99, 99 }, + { "grey4", 10, 10, 10 }, + { "grey40", 102, 102, 102 }, + { "grey41", 105, 105, 105 }, + { "grey42", 107, 107, 107 }, + { "grey43", 110, 110, 110 }, + { "grey44", 112, 112, 112 }, + { "grey45", 115, 115, 115 }, + { "grey46", 117, 117, 117 }, + { "grey47", 120, 120, 120 }, + { "grey48", 122, 122, 122 }, + { "grey49", 125, 125, 125 }, + { "grey5", 13, 13, 13 }, + { "grey50", 127, 127, 127 }, + { "grey51", 130, 130, 130 }, + { "grey52", 133, 133, 133 }, + { "grey53", 135, 135, 135 }, + { "grey54", 138, 138, 138 }, + { "grey55", 140, 140, 140 }, + { "grey56", 143, 143, 143 }, + { "grey57", 145, 145, 145 }, + { "grey58", 148, 148, 148 }, + { "grey59", 150, 150, 150 }, + { "grey6", 15, 15, 15 }, + { "grey60", 153, 153, 153 }, + { "grey61", 156, 156, 156 }, + { "grey62", 158, 158, 158 }, + { "grey63", 161, 161, 161 }, + { "grey64", 163, 163, 163 }, + { "grey65", 166, 166, 166 }, + { "grey66", 168, 168, 168 }, + { "grey67", 171, 171, 171 }, + { "grey68", 173, 173, 173 }, + { "grey69", 176, 176, 176 }, + { "grey7", 18, 18, 18 }, + { "grey70", 179, 179, 179 }, + { "grey71", 181, 181, 181 }, + { "grey72", 184, 184, 184 }, + { "grey73", 186, 186, 186 }, + { "grey74", 189, 189, 189 }, + { "grey75", 191, 191, 191 }, + { "grey76", 194, 194, 194 }, + { "grey77", 196, 196, 196 }, + { "grey78", 199, 199, 199 }, + { "grey79", 201, 201, 201 }, + { "grey8", 20, 20, 20 }, + { "grey80", 204, 204, 204 }, + { "grey81", 207, 207, 207 }, + { "grey82", 209, 209, 209 }, + { "grey83", 212, 212, 212 }, + { "grey84", 214, 214, 214 }, + { "grey85", 217, 217, 217 }, + { "grey86", 219, 219, 219 }, + { "grey87", 222, 222, 222 }, + { "grey88", 224, 224, 224 }, + { "grey89", 227, 227, 227 }, + { "grey9", 23, 23, 23 }, + { "grey90", 229, 229, 229 }, + { "grey91", 232, 232, 232 }, + { "grey92", 235, 235, 235 }, + { "grey93", 237, 237, 237 }, + { "grey94", 240, 240, 240 }, + { "grey95", 242, 242, 242 }, + { "grey96", 245, 245, 245 }, + { "grey97", 247, 247, 247 }, + { "grey98", 250, 250, 250 }, + { "grey99", 252, 252, 252 }, + { "honeydew", 240, 255, 240 }, + { "honeydew1", 240, 255, 240 }, + { "honeydew2", 224, 238, 224 }, + { "honeydew3", 193, 205, 193 }, + { "honeydew4", 131, 139, 131 }, + { "hot pink", 255, 105, 180 }, + { "HotPink", 255, 105, 180 }, + { "HotPink1", 255, 110, 180 }, + { "HotPink2", 238, 106, 167 }, + { "HotPink3", 205, 96, 144 }, + { "HotPink4", 139, 58, 98 }, + { "indian red", 205, 92, 92 }, + { "IndianRed", 205, 92, 92 }, + { "IndianRed1", 255, 106, 106 }, + { "IndianRed2", 238, 99, 99 }, + { "IndianRed3", 205, 85, 85 }, + { "IndianRed4", 139, 58, 58 }, + { "ivory", 255, 255, 240 }, + { "ivory1", 255, 255, 240 }, + { "ivory2", 238, 238, 224 }, + { "ivory3", 205, 205, 193 }, + { "ivory4", 139, 139, 131 }, + { "khaki", 240, 230, 140 }, + { "khaki1", 255, 246, 143 }, + { "khaki2", 238, 230, 133 }, + { "khaki3", 205, 198, 115 }, + { "khaki4", 139, 134, 78 }, + { "lavender", 230, 230, 250 }, + { "lavender blush", 255, 240, 245 }, + { "LavenderBlush", 255, 240, 245 }, + { "LavenderBlush1", 255, 240, 245 }, + { "LavenderBlush2", 238, 224, 229 }, + { "LavenderBlush3", 205, 193, 197 }, + { "LavenderBlush4", 139, 131, 134 }, + { "lawn green", 124, 252, 0 }, + { "LawnGreen", 124, 252, 0 }, + { "lemon chiffon", 255, 250, 205 }, + { "LemonChiffon", 255, 250, 205 }, + { "LemonChiffon1", 255, 250, 205 }, + { "LemonChiffon2", 238, 233, 191 }, + { "LemonChiffon3", 205, 201, 165 }, + { "LemonChiffon4", 139, 137, 112 }, + { "light blue", 173, 216, 230 }, + { "light coral", 240, 128, 128 }, + { "light cyan", 224, 255, 255 }, + { "light goldenrod", 238, 221, 130 }, + { "light goldenrod yellow", 250, 250, 210 }, + { "light gray", 211, 211, 211 }, + { "light green", 144, 238, 144 }, + { "light grey", 211, 211, 211 }, + { "light pink", 255, 182, 193 }, + { "light salmon", 255, 160, 122 }, + { "light sea green", 32, 178, 170 }, + { "light sky blue", 135, 206, 250 }, + { "light slate blue", 132, 112, 255 }, + { "light slate gray", 119, 136, 153 }, + { "light slate grey", 119, 136, 153 }, + { "light steel blue", 176, 196, 222 }, + { "light yellow", 255, 255, 224 }, + { "LightBlue", 173, 216, 230 }, + { "LightBlue1", 191, 239, 255 }, + { "LightBlue2", 178, 223, 238 }, + { "LightBlue3", 154, 192, 205 }, + { "LightBlue4", 104, 131, 139 }, + { "LightCoral", 240, 128, 128 }, + { "LightCyan", 224, 255, 255 }, + { "LightCyan1", 224, 255, 255 }, + { "LightCyan2", 209, 238, 238 }, + { "LightCyan3", 180, 205, 205 }, + { "LightCyan4", 122, 139, 139 }, + { "LightGoldenrod", 238, 221, 130 }, + { "LightGoldenrod1", 255, 236, 139 }, + { "LightGoldenrod2", 238, 220, 130 }, + { "LightGoldenrod3", 205, 190, 112 }, + { "LightGoldenrod4", 139, 129, 76 }, + { "LightGoldenrodYellow", 250, 250, 210 }, + { "LightGray", 211, 211, 211 }, + { "LightGreen", 144, 238, 144 }, + { "LightGrey", 211, 211, 211 }, + { "LightPink", 255, 182, 193 }, + { "LightPink1", 255, 174, 185 }, + { "LightPink2", 238, 162, 173 }, + { "LightPink3", 205, 140, 149 }, + { "LightPink4", 139, 95, 101 }, + { "LightSalmon", 255, 160, 122 }, + { "LightSalmon1", 255, 160, 122 }, + { "LightSalmon2", 238, 149, 114 }, + { "LightSalmon3", 205, 129, 98 }, + { "LightSalmon4", 139, 87, 66 }, + { "LightSeaGreen", 32, 178, 170 }, + { "LightSkyBlue", 135, 206, 250 }, + { "LightSkyBlue1", 176, 226, 255 }, + { "LightSkyBlue2", 164, 211, 238 }, + { "LightSkyBlue3", 141, 182, 205 }, + { "LightSkyBlue4", 96, 123, 139 }, + { "LightSlateBlue", 132, 112, 255 }, + { "LightSlateGray", 119, 136, 153 }, + { "LightSlateGrey", 119, 136, 153 }, + { "LightSteelBlue", 176, 196, 222 }, + { "LightSteelBlue1", 202, 225, 255 }, + { "LightSteelBlue2", 188, 210, 238 }, + { "LightSteelBlue3", 162, 181, 205 }, + { "LightSteelBlue4", 110, 123, 139 }, + { "LightYellow", 255, 255, 224 }, + { "LightYellow1", 255, 255, 224 }, + { "LightYellow2", 238, 238, 209 }, + { "LightYellow3", 205, 205, 180 }, + { "LightYellow4", 139, 139, 122 }, + { "lime green", 50, 205, 50 }, + { "LimeGreen", 50, 205, 50 }, + { "linen", 250, 240, 230 }, + { "magenta", 255, 0, 255 }, + { "magenta1", 255, 0, 255 }, + { "magenta2", 238, 0, 238 }, + { "magenta3", 205, 0, 205 }, + { "magenta4", 139, 0, 139 }, + { "maroon", 176, 48, 96 }, + { "maroon1", 255, 52, 179 }, + { "maroon2", 238, 48, 167 }, + { "maroon3", 205, 41, 144 }, + { "maroon4", 139, 28, 98 }, + { "medium aquamarine", 102, 205, 170 }, + { "medium blue", 0, 0, 205 }, + { "medium orchid", 186, 85, 211 }, + { "medium purple", 147, 112, 219 }, + { "medium sea green", 60, 179, 113 }, + { "medium slate blue", 123, 104, 238 }, + { "medium spring green", 0, 250, 154 }, + { "medium turquoise", 72, 209, 204 }, + { "medium violet red", 199, 21, 133 }, + { "MediumAquamarine", 102, 205, 170 }, + { "MediumBlue", 0, 0, 205 }, + { "MediumOrchid", 186, 85, 211 }, + { "MediumOrchid1", 224, 102, 255 }, + { "MediumOrchid2", 209, 95, 238 }, + { "MediumOrchid3", 180, 82, 205 }, + { "MediumOrchid4", 122, 55, 139 }, + { "MediumPurple", 147, 112, 219 }, + { "MediumPurple1", 171, 130, 255 }, + { "MediumPurple2", 159, 121, 238 }, + { "MediumPurple3", 137, 104, 205 }, + { "MediumPurple4", 93, 71, 139 }, + { "MediumSeaGreen", 60, 179, 113 }, + { "MediumSlateBlue", 123, 104, 238 }, + { "MediumSpringGreen", 0, 250, 154 }, + { "MediumTurquoise", 72, 209, 204 }, + { "MediumVioletRed", 199, 21, 133 }, + { "midnight blue", 25, 25, 112 }, + { "MidnightBlue", 25, 25, 112 }, + { "mint cream", 245, 255, 250 }, + { "MintCream", 245, 255, 250 }, + { "misty rose", 255, 228, 225 }, + { "MistyRose", 255, 228, 225 }, + { "MistyRose1", 255, 228, 225 }, + { "MistyRose2", 238, 213, 210 }, + { "MistyRose3", 205, 183, 181 }, + { "MistyRose4", 139, 125, 123 }, + { "moccasin", 255, 228, 181 }, + { "navajo white", 255, 222, 173 }, + { "NavajoWhite", 255, 222, 173 }, + { "NavajoWhite1", 255, 222, 173 }, + { "NavajoWhite2", 238, 207, 161 }, + { "NavajoWhite3", 205, 179, 139 }, + { "NavajoWhite4", 139, 121, 94 }, + { "navy", 0, 0, 128 }, + { "navy blue", 0, 0, 128 }, + { "NavyBlue", 0, 0, 128 }, + { "old lace", 253, 245, 230 }, + { "OldLace", 253, 245, 230 }, + { "olive drab", 107, 142, 35 }, + { "OliveDrab", 107, 142, 35 }, + { "OliveDrab1", 192, 255, 62 }, + { "OliveDrab2", 179, 238, 58 }, + { "OliveDrab3", 154, 205, 50 }, + { "OliveDrab4", 105, 139, 34 }, + { "orange", 255, 165, 0 }, + { "orange red", 255, 69, 0 }, + { "orange1", 255, 165, 0 }, + { "orange2", 238, 154, 0 }, + { "orange3", 205, 133, 0 }, + { "orange4", 139, 90, 0 }, + { "OrangeRed", 255, 69, 0 }, + { "OrangeRed1", 255, 69, 0 }, + { "OrangeRed2", 238, 64, 0 }, + { "OrangeRed3", 205, 55, 0 }, + { "OrangeRed4", 139, 37, 0 }, + { "orchid", 218, 112, 214 }, + { "orchid1", 255, 131, 250 }, + { "orchid2", 238, 122, 233 }, + { "orchid3", 205, 105, 201 }, + { "orchid4", 139, 71, 137 }, + { "pale goldenrod", 238, 232, 170 }, + { "pale green", 152, 251, 152 }, + { "pale turquoise", 175, 238, 238 }, + { "pale violet red", 219, 112, 147 }, + { "PaleGoldenrod", 238, 232, 170 }, + { "PaleGreen", 152, 251, 152 }, + { "PaleGreen1", 154, 255, 154 }, + { "PaleGreen2", 144, 238, 144 }, + { "PaleGreen3", 124, 205, 124 }, + { "PaleGreen4", 84, 139, 84 }, + { "PaleTurquoise", 175, 238, 238 }, + { "PaleTurquoise1", 187, 255, 255 }, + { "PaleTurquoise2", 174, 238, 238 }, + { "PaleTurquoise3", 150, 205, 205 }, + { "PaleTurquoise4", 102, 139, 139 }, + { "PaleVioletRed", 219, 112, 147 }, + { "PaleVioletRed1", 255, 130, 171 }, + { "PaleVioletRed2", 238, 121, 159 }, + { "PaleVioletRed3", 205, 104, 137 }, + { "PaleVioletRed4", 139, 71, 93 }, + { "papaya whip", 255, 239, 213 }, + { "PapayaWhip", 255, 239, 213 }, + { "peach puff", 255, 218, 185 }, + { "PeachPuff", 255, 218, 185 }, + { "PeachPuff1", 255, 218, 185 }, + { "PeachPuff2", 238, 203, 173 }, + { "PeachPuff3", 205, 175, 149 }, + { "PeachPuff4", 139, 119, 101 }, + { "peru", 205, 133, 63 }, + { "pink", 255, 192, 203 }, + { "pink1", 255, 181, 197 }, + { "pink2", 238, 169, 184 }, + { "pink3", 205, 145, 158 }, + { "pink4", 139, 99, 108 }, + { "plum", 221, 160, 221 }, + { "plum1", 255, 187, 255 }, + { "plum2", 238, 174, 238 }, + { "plum3", 205, 150, 205 }, + { "plum4", 139, 102, 139 }, + { "powder blue", 176, 224, 230 }, + { "PowderBlue", 176, 224, 230 }, + { "purple", 160, 32, 240 }, + { "purple1", 155, 48, 255 }, + { "purple2", 145, 44, 238 }, + { "purple3", 125, 38, 205 }, + { "purple4", 85, 26, 139 }, + { "red", 255, 0, 0 }, + { "red1", 255, 0, 0 }, + { "red2", 238, 0, 0 }, + { "red3", 205, 0, 0 }, + { "red4", 139, 0, 0 }, + { "rosy brown", 188, 143, 143 }, + { "RosyBrown", 188, 143, 143 }, + { "RosyBrown1", 255, 193, 193 }, + { "RosyBrown2", 238, 180, 180 }, + { "RosyBrown3", 205, 155, 155 }, + { "RosyBrown4", 139, 105, 105 }, + { "royal blue", 65, 105, 225 }, + { "RoyalBlue", 65, 105, 225 }, + { "RoyalBlue1", 72, 118, 255 }, + { "RoyalBlue2", 67, 110, 238 }, + { "RoyalBlue3", 58, 95, 205 }, + { "RoyalBlue4", 39, 64, 139 }, + { "saddle brown", 139, 69, 19 }, + { "SaddleBrown", 139, 69, 19 }, + { "salmon", 250, 128, 114 }, + { "salmon1", 255, 140, 105 }, + { "salmon2", 238, 130, 98 }, + { "salmon3", 205, 112, 84 }, + { "salmon4", 139, 76, 57 }, + { "sandy brown", 244, 164, 96 }, + { "SandyBrown", 244, 164, 96 }, + { "sea green", 46, 139, 87 }, + { "SeaGreen", 46, 139, 87 }, + { "SeaGreen1", 84, 255, 159 }, + { "SeaGreen2", 78, 238, 148 }, + { "SeaGreen3", 67, 205, 128 }, + { "SeaGreen4", 46, 139, 87 }, + { "seashell", 255, 245, 238 }, + { "seashell1", 255, 245, 238 }, + { "seashell2", 238, 229, 222 }, + { "seashell3", 205, 197, 191 }, + { "seashell4", 139, 134, 130 }, + { "sienna", 160, 82, 45 }, + { "sienna1", 255, 130, 71 }, + { "sienna2", 238, 121, 66 }, + { "sienna3", 205, 104, 57 }, + { "sienna4", 139, 71, 38 }, + { "sky blue", 135, 206, 235 }, + { "SkyBlue", 135, 206, 235 }, + { "SkyBlue1", 135, 206, 255 }, + { "SkyBlue2", 126, 192, 238 }, + { "SkyBlue3", 108, 166, 205 }, + { "SkyBlue4", 74, 112, 139 }, + { "slate blue", 106, 90, 205 }, + { "slate gray", 112, 128, 144 }, + { "slate grey", 112, 128, 144 }, + { "SlateBlue", 106, 90, 205 }, + { "SlateBlue1", 131, 111, 255 }, + { "SlateBlue2", 122, 103, 238 }, + { "SlateBlue3", 105, 89, 205 }, + { "SlateBlue4", 71, 60, 139 }, + { "SlateGray", 112, 128, 144 }, + { "SlateGray1", 198, 226, 255 }, + { "SlateGray2", 185, 211, 238 }, + { "SlateGray3", 159, 182, 205 }, + { "SlateGray4", 108, 123, 139 }, + { "SlateGrey", 112, 128, 144 }, + { "snow", 255, 250, 250 }, + { "snow1", 255, 250, 250 }, + { "snow2", 238, 233, 233 }, + { "snow3", 205, 201, 201 }, + { "snow4", 139, 137, 137 }, + { "spring green", 0, 255, 127 }, + { "SpringGreen", 0, 255, 127 }, + { "SpringGreen1", 0, 255, 127 }, + { "SpringGreen2", 0, 238, 118 }, + { "SpringGreen3", 0, 205, 102 }, + { "SpringGreen4", 0, 139, 69 }, + { "steel blue", 70, 130, 180 }, + { "SteelBlue", 70, 130, 180 }, + { "SteelBlue1", 99, 184, 255 }, + { "SteelBlue2", 92, 172, 238 }, + { "SteelBlue3", 79, 148, 205 }, + { "SteelBlue4", 54, 100, 139 }, + { "tan", 210, 180, 140 }, + { "tan1", 255, 165, 79 }, + { "tan2", 238, 154, 73 }, + { "tan3", 205, 133, 63 }, + { "tan4", 139, 90, 43 }, + { "thistle", 216, 191, 216 }, + { "thistle1", 255, 225, 255 }, + { "thistle2", 238, 210, 238 }, + { "thistle3", 205, 181, 205 }, + { "thistle4", 139, 123, 139 }, + { "tomato", 255, 99, 71 }, + { "tomato1", 255, 99, 71 }, + { "tomato2", 238, 92, 66 }, + { "tomato3", 205, 79, 57 }, + { "tomato4", 139, 54, 38 }, + { "turquoise", 64, 224, 208 }, + { "turquoise1", 0, 245, 255 }, + { "turquoise2", 0, 229, 238 }, + { "turquoise3", 0, 197, 205 }, + { "turquoise4", 0, 134, 139 }, + { "violet", 238, 130, 238 }, + { "violet red", 208, 32, 144 }, + { "VioletRed", 208, 32, 144 }, + { "VioletRed1", 255, 62, 150 }, + { "VioletRed2", 238, 58, 140 }, + { "VioletRed3", 205, 50, 120 }, + { "VioletRed4", 139, 34, 82 }, + { "wheat", 245, 222, 179 }, + { "wheat1", 255, 231, 186 }, + { "wheat2", 238, 216, 174 }, + { "wheat3", 205, 186, 150 }, + { "wheat4", 139, 126, 102 }, + { "white", 255, 255, 255 }, + { "white smoke", 245, 245, 245 }, + { "WhiteSmoke", 245, 245, 245 }, + { "yellow", 255, 255, 0 }, + { "yellow green", 154, 205, 50 }, + { "yellow1", 255, 255, 0 }, + { "yellow2", 238, 238, 0 }, + { "yellow3", 205, 205, 0 }, + { "yellow4", 139, 139, 0 }, + { "YellowGreen", 154, 205, 50 } +}; + +#define numXColors (sizeof (xColors) / sizeof (*xColors)) + +/* + *---------------------------------------------------------------------- + * + * FindColor -- + * + * This routine finds the color entry that corresponds to the + * specified color. + * + * Results: + * Returns non-zero on success. The RGB values of the XColor + * will be initialized to the proper values on success. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +static int +compare_xcolor_entries (const void *a, const void *b) +{ + return strcasecmp ((const char *) a, ((const XColorEntry *) b)->name); +} + +static int +FindColor(const char *name, + GdkColor *colorPtr) +{ + XColorEntry *found; + + found = bsearch (name, xColors, numXColors, sizeof (XColorEntry), + compare_xcolor_entries); + if (found == NULL) + return 0; + + colorPtr->red = (found->red * 65535) / 255; + colorPtr->green = (found->green * 65535) / 255; + colorPtr->blue = (found->blue * 65535) / 255; + return 1; +} + +/* + *---------------------------------------------------------------------- + * + * parse_color -- + * + * Partial implementation of X color name parsing interface. + * + * Results: + * Returns non-zero on success. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +gboolean +parse_color(Colormap map, + const char *spec, + GdkColor *colorPtr) +{ + if (spec[0] == '#') { + char fmt[16]; + int i, red, green, blue; + + if ((i = strlen(spec+1))%3) { + return 0; + } + i /= 3; + + sprintf(fmt, "%%%dx%%%dx%%%dx", i, i, i); + if (sscanf(spec+1, fmt, &red, &green, &blue) != 3) { + return 0; + } + if (i == 4) + { + colorPtr->red = red; + colorPtr->green = green; + colorPtr->blue = blue; + } + else if (i == 1) + { + colorPtr->red = (red * 65535) / 15; + colorPtr->green = (green * 65535) / 15; + colorPtr->blue = (blue * 65535) / 15; + } + else if (i == 2) + { + colorPtr->red = (red * 65535) / 255; + colorPtr->green = (green * 65535) / 255; + colorPtr->blue = (blue * 65535) / 255; + } + else /* if (i == 3) */ + { + colorPtr->red = (red * 65535) / 4095; + colorPtr->green = (green * 65535) / 4095; + colorPtr->blue = (blue * 65535) / 4095; + } + } else { + if (!FindColor(spec, colorPtr)) { + return 0; + } + } + return 1; +} + +/* End of code from Tk8.0 */ + +static Colormap +DefaultColormap () +{ + static Colormap colormap; + gint i; + + if (colormap) + return colormap; + + colormap = create_colormap ( NULL, NULL, AllocNone); + return colormap; +} + + +GdkColormap* +gdk_colormap_new (GdkVisual *visual, + gint private_cmap) +{ + GdkColormap *colormap; + GdkColormapPrivate *private; + Visual *xvisual; + int size; + unsigned int i; + + g_return_val_if_fail (visual != NULL, NULL); + + private = g_new (GdkColormapPrivate, 1); + colormap = (GdkColormap*) private; + + private->visual = visual; + private->ref_count = 1; + + private->hash = NULL; + private->last_sync_time = 0; + private->info = NULL; + + xvisual = ((GdkVisualPrivate*) visual)->xvisual; + + colormap->size = visual->colormap_size; + colormap->colors = g_new (GdkColor, colormap->size); + + switch (visual->type) + { + case GDK_VISUAL_GRAYSCALE: + case GDK_VISUAL_PSEUDO_COLOR: + private->info = g_new0 (GdkColorInfo, colormap->size); + colormap->colors = g_new (GdkColor, colormap->size); + + private->hash = g_hash_table_new ((GHashFunc) gdk_color_hash, + (GCompareFunc) gdk_color_equal); + + private->private_val = private_cmap; + private->xcolormap = create_colormap (gdk_root_window, xvisual, + (private_cmap) ? (AllocAll) : (AllocNone)); + + if (private_cmap) + { + PALETTEENTRY pal[256]; + guint npal; + + npal = GetPaletteEntries (private->xcolormap->palette, 0, colormap->size, pal); + for (i = 0; i < colormap->size; i++) + { + colormap->colors[i].pixel = i; + if (i >= npal) + { + colormap->colors[i].red = + colormap->colors[i].green = + colormap->colors[i].blue = 0; + } + else + { + colormap->colors[i].red = (pal[i].peRed * 65535) / 255; + colormap->colors[i].green = (pal[i].peGreen * 65525) / 255; + colormap->colors[i].blue = (pal[i].peBlue * 65535) / 255; + } + } + gdk_colormap_change (colormap, colormap->size); + } + break; + + case GDK_VISUAL_STATIC_GRAY: + case GDK_VISUAL_STATIC_COLOR: + case GDK_VISUAL_TRUE_COLOR: + private->private_val = FALSE; + private->xcolormap = create_colormap (gdk_root_window, + xvisual, AllocNone); + break; + } + + gdk_colormap_add (colormap); + + return colormap; +} + +static void +gdk_colormap_real_destroy (GdkColormap *colormap) +{ + GdkColormapPrivate *private = (GdkColormapPrivate*) colormap; + + g_return_if_fail (colormap != NULL); + g_return_if_fail (private->ref_count == 0); + + gdk_colormap_remove (colormap); + XFreeColormap (private->xcolormap); + + if (private->hash) + g_hash_table_destroy (private->hash); + + g_free (private->info); + g_free (colormap->colors); + g_free (colormap); +} + +GdkColormap* +gdk_colormap_ref (GdkColormap *cmap) +{ + GdkColormapPrivate *private = (GdkColormapPrivate *)cmap; + + g_return_val_if_fail (cmap != NULL, NULL); + + private->ref_count += 1; + return cmap; +} + +void +gdk_colormap_unref (GdkColormap *cmap) +{ + GdkColormapPrivate *private = (GdkColormapPrivate *)cmap; + + g_return_if_fail (cmap != NULL); + g_return_if_fail (private->ref_count > 0); + + private->ref_count -= 1; + if (private->ref_count == 0) + gdk_colormap_real_destroy (cmap); +} + +#define MIN_SYNC_TIME 2 + +GdkVisual * +gdk_colormap_get_visual (GdkColormap *colormap) +{ + GdkColormapPrivate *private; + + g_return_val_if_fail (colormap != NULL, NULL); + + private = (GdkColormapPrivate *)colormap; + + return private->visual; +} + +void +gdk_colormap_sync (GdkColormap *colormap, + gboolean force) +{ + time_t current_time; + GdkColormapPrivate *private = (GdkColormapPrivate *)colormap; + XColor *xpalette; + gint nlookup; + gint i; + + g_return_if_fail (colormap != NULL); + + current_time = time (NULL); + if (!force && ((current_time - private->last_sync_time) < MIN_SYNC_TIME)) + return; + + private->last_sync_time = current_time; + + nlookup = 0; + xpalette = g_new (XColor, colormap->size); + + nlookup = GetPaletteEntries (private->xcolormap->palette, + 0, colormap->size, xpalette); + + for (i = 0; i < nlookup; i++) + { + colormap->colors[i].pixel = i; + colormap->colors[i].red = (xpalette[i].peRed * 65535) / 255; + colormap->colors[i].green = (xpalette[i].peGreen * 65535) / 255; + colormap->colors[i].blue = (xpalette[i].peBlue * 65535) / 255; + } + + g_free (xpalette); +} + + +GdkColormap* +gdk_colormap_get_system (void) +{ + static GdkColormap *colormap = NULL; + GdkColormapPrivate *private; + gint i; + + if (!colormap) + { + private = g_new (GdkColormapPrivate, 1); + colormap = (GdkColormap*) private; + + private->xcolormap = DefaultColormap (); + private->visual = gdk_visual_get_system (); + private->private_val = FALSE; + private->ref_count = 1; + + private->hash = NULL; + private->last_sync_time = 0; + private->info = NULL; + + colormap->colors = NULL; + colormap->size = private->visual->colormap_size; + + if ((private->visual->type == GDK_VISUAL_GRAYSCALE) || + (private->visual->type == GDK_VISUAL_PSEUDO_COLOR)) + { + private->info = g_new0 (GdkColorInfo, colormap->size); + colormap->colors = g_new (GdkColor, colormap->size); + + private->hash = g_hash_table_new ((GHashFunc) gdk_color_hash, + (GCompareFunc) gdk_color_equal); + + gdk_colormap_sync (colormap, TRUE); + } + gdk_colormap_add (colormap); + } + + return colormap; +} + +gint +gdk_colormap_get_system_size (void) +{ + gint bitspixel; + + bitspixel = GetDeviceCaps (gdk_DC, BITSPIXEL); + + if (bitspixel == 1) + return 2; + else if (bitspixel == 4) + return 16; + else if (bitspixel == 8) + return 256; + else if (bitspixel == 12) + return 32; + else if (bitspixel == 16) + return 64; + else /* if (bitspixel >= 24) */ + return 256; +} + +void +gdk_colormap_change (GdkColormap *colormap, + gint ncolors) +{ + GdkColormapPrivate *private; + GdkVisual *visual; + XColor *palette; + gint shift; + int max_colors; + int size; + int i; + + g_return_if_fail (colormap != NULL); + + palette = g_new (XColor, ncolors); + + private = (GdkColormapPrivate*) colormap; + switch (private->visual->type) + { + case GDK_VISUAL_GRAYSCALE: + case GDK_VISUAL_PSEUDO_COLOR: + for (i = 0; i < ncolors; i++) + { + palette[i].peRed = (colormap->colors[i].red >> 8); + palette[i].peGreen = (colormap->colors[i].green >> 8); + palette[i].peBlue = (colormap->colors[i].blue >> 8); + palette[i].peFlags = 0; + } + + if (SetPaletteEntries (private->xcolormap->palette, + 0, ncolors, palette) == 0) + g_warning ("gdk_colormap_change: SetPaletteEntries failed"); + private->xcolormap->stale = TRUE; + break; + + default: + break; + } + + g_free (palette); +} + +void +gdk_colors_store (GdkColormap *colormap, + GdkColor *colors, + gint ncolors) +{ + gint i; + + for (i = 0; i < ncolors; i++) + { + colormap->colors[i].pixel = colors[i].pixel; + colormap->colors[i].red = colors[i].red; + colormap->colors[i].green = colors[i].green; + colormap->colors[i].blue = colors[i].blue; + } + + gdk_colormap_change (colormap, ncolors); +} + +gboolean +gdk_colors_alloc (GdkColormap *colormap, + gint contiguous, + gulong *planes, + gint nplanes, + gulong *pixels, + gint npixels) +{ + GdkColormapPrivate *private; + gint return_val; + gint i; + + g_return_val_if_fail (colormap != NULL, 0); + + private = (GdkColormapPrivate*) colormap; + + return_val = alloc_color_cells (private->xcolormap, contiguous, + planes, nplanes, pixels, npixels); + + if (return_val) + { + for (i=0; i<npixels; i++) + { + private->info[pixels[i]].ref_count++; + private->info[pixels[i]].flags |= GDK_COLOR_WRITEABLE; + } + } + + return return_val; +} + +/* This is almost identical to gdk_colormap_free_colors. + * Keep them in sync! + */ +void +gdk_colors_free (GdkColormap *colormap, + gulong *in_pixels, + gint in_npixels, + gulong planes) +{ + GdkColormapPrivate *private; + gulong *pixels; + gint npixels = 0; + gint i; + + g_return_if_fail (colormap != NULL); + g_return_if_fail (in_pixels != NULL); + + private = (GdkColormapPrivate*) colormap; + + if ((private->visual->type != GDK_VISUAL_PSEUDO_COLOR) && + (private->visual->type != GDK_VISUAL_GRAYSCALE)) + return; + + pixels = g_new (gulong, in_npixels); + + for (i=0; i<in_npixels; i++) + { + gulong pixel = in_pixels[i]; + + if (private->info[pixel].ref_count) + { + private->info[pixel].ref_count--; + + if (private->info[pixel].ref_count == 0) + { + pixels[npixels++] = pixel; + if (!(private->info[pixel].flags & GDK_COLOR_WRITEABLE)) + g_hash_table_remove (private->hash, &colormap->colors[in_pixels[i]]); + private->info[pixel].flags = 0; + } + } + } + + + if (npixels) + XFreeColors (private->xcolormap, pixels, npixels, planes); + + g_free (pixels); +} + +/* + *-------------------------------------------------------------- + * gdk_color_copy + * + * Copy a color structure into new storage. + * + * Arguments: + * "color" is the color struct to copy. + * + * Results: + * A new color structure. Free it with gdk_color_free. + * + *-------------------------------------------------------------- + */ + +static GMemChunk *color_chunk; + +GdkColor* +gdk_color_copy (GdkColor *color) +{ + GdkColor *new_color; + + g_return_val_if_fail (color != NULL, NULL); + + if (color_chunk == NULL) + color_chunk = g_mem_chunk_new ("colors", + sizeof (GdkColor), + 4096, + G_ALLOC_AND_FREE); + + new_color = g_chunk_new (GdkColor, color_chunk); + *new_color = *color; + return new_color; +} + +/* + *-------------------------------------------------------------- + * gdk_color_free + * + * Free a color structure obtained from gdk_color_copy. Do not use + * with other color structures. + * + * Arguments: + * "color" is the color struct to free. + * + *-------------------------------------------------------------- */ + +void +gdk_color_free (GdkColor *color) +{ + g_assert (color_chunk != NULL); + g_return_if_fail (color != NULL); + + g_mem_chunk_free (color_chunk, color); +} + +gint +gdk_color_white (GdkColormap *colormap, + GdkColor *color) +{ + gint return_val; + + g_return_val_if_fail (colormap != NULL, FALSE); + + if (color) + { + color->red = 65535; + color->green = 65535; + color->blue = 65535; + + return_val = gdk_color_alloc (colormap, color); + } + else + return_val = FALSE; + + return return_val; +} + +gint +gdk_color_black (GdkColormap *colormap, + GdkColor *color) +{ + gint return_val; + + g_return_val_if_fail (colormap != NULL, FALSE); + + if (color) + { + color->red = 0; + color->green = 0; + color->blue = 0; + + return_val = gdk_color_alloc (colormap, color); + } + else + return_val = FALSE; + + return return_val; +} + +gboolean +gdk_color_parse (const gchar *spec, + GdkColor *color) +{ + Colormap xcolormap; + XColor xcolor; + gboolean return_val; + + g_return_val_if_fail (spec != NULL, FALSE); + g_return_val_if_fail (color != NULL, FALSE); + + xcolormap = DefaultColormap (); + + if (parse_color (xcolormap, spec, color)) + return_val = TRUE; + else + return_val = FALSE; + + return return_val; +} + +/******************** + * Color allocation * + ********************/ + +/* Try to allocate a single color using alloc_color. If it succeeds, + * cache the result in our colormap, and store in ret. + */ +static gboolean +gdk_colormap_alloc1 (GdkColormap *colormap, + GdkColor *color, + GdkColor *ret) +{ + GdkColormapPrivate *private; + XColor xcolor; + + private = (GdkColormapPrivate*) colormap; + + xcolor.peRed = color->red >> 8; + xcolor.peGreen = color->green >> 8; + xcolor.peBlue = color->blue >> 8; + + if (alloc_color (private->xcolormap, &xcolor, &ret->pixel)) + { + ret->red = (xcolor.peRed * 65535) / 255; + ret->green = (xcolor.peGreen * 65535) / 255;; + ret->blue = (xcolor.peBlue * 65535) / 255; + + if ((guint) ret->pixel < colormap->size) + { + if (private->info[ret->pixel].ref_count) /* got a duplicate */ + { + /* XXX */ + } + else + { + colormap->colors[ret->pixel] = *color; + private->info[ret->pixel].ref_count = 1; + + g_hash_table_insert (private->hash, + &colormap->colors[ret->pixel], + &colormap->colors[ret->pixel]); + } + } + return TRUE; + } + else + { + return FALSE; + } +} + +static gint +gdk_colormap_alloc_colors_writeable (GdkColormap *colormap, + GdkColor *colors, + gint ncolors, + gboolean writeable, + gboolean best_match, + gboolean *success) +{ + GdkColormapPrivate *private; + gulong *pixels; + Status status; + gint i, index; + + private = (GdkColormapPrivate*) colormap; + + if (private->private_val) + { + index = 0; + for (i=0; i<ncolors; i++) + { + while ((index < colormap->size) && (private->info[index].ref_count != 0)) + index++; + + if (index < colormap->size) + { + colors[i].pixel = index; + success[i] = TRUE; + private->info[index].ref_count++; + private->info[i].flags |= GDK_COLOR_WRITEABLE; + } + else + break; + } + return i; + } + else + { + pixels = g_new (gulong, ncolors); + + /* Allocation of a writeable color cells */ + status = alloc_color_cells (private->xcolormap, FALSE, NULL, + 0, pixels, ncolors); + if (status) + { + for (i=0; i<ncolors; i++) + { + colors[i].pixel = pixels[i]; + private->info[pixels[i]].ref_count++; + private->info[pixels[i]].flags |= GDK_COLOR_WRITEABLE; + } + } + + g_free (pixels); + + return status ? ncolors : 0; + } +} + +static gint +gdk_colormap_alloc_colors_private (GdkColormap *colormap, + GdkColor *colors, + gint ncolors, + gboolean writeable, + gboolean best_match, + gboolean *success) +{ + GdkColormapPrivate *private; + gint i, index; + XColor *store = g_new (XColor, ncolors); + gint nstore = 0; + gint nremaining = 0; + + private = (GdkColormapPrivate*) colormap; + index = -1; + + /* First, store the colors we have room for */ + + index = 0; + for (i=0; i<ncolors; i++) + { + if (!success[i]) + { + while ((index < colormap->size) && (private->info[index].ref_count != 0)) + index++; + + if (index < colormap->size) + { + store[nstore].peRed = colors[i].red >> 8; + store[nstore].peBlue = colors[i].blue >> 8; + store[nstore].peGreen = colors[i].green >> 8; + nstore++; + + success[i] = TRUE; + + colors[i].pixel = index; + private->info[index].ref_count++; + } + else + nremaining++; + } + } + + if (SetPaletteEntries (private->xcolormap->palette, + 0, nstore, store) == 0) + g_warning ("gdk_colormap_alloc_colors_private: SetPaletteEntries failed"); + private->xcolormap->stale = TRUE; + + g_free (store); + + if (nremaining > 0 && best_match) + { + /* Get best matches for remaining colors */ + + gchar *available = g_new (gchar, colormap->size); + for (i = 0; i < colormap->size; i++) + available[i] = TRUE; + + for (i=0; i<ncolors; i++) + { + if (!success[i]) + { + index = gdk_colormap_match_color (colormap, + &colors[i], + available); + if (index != -1) + { + colors[i] = colormap->colors[index]; + private->info[index].ref_count++; + success[i] = TRUE; + nremaining--; + } + } + } + g_free (available); + } + + return (ncolors - nremaining); +} + +static gint +gdk_colormap_alloc_colors_shared (GdkColormap *colormap, + GdkColor *colors, + gint ncolors, + gboolean writeable, + gboolean best_match, + gboolean *success) +{ + GdkColormapPrivate *private; + gint i, index; + gint nremaining = 0; + gint nfailed = 0; + + private = (GdkColormapPrivate*) colormap; + index = -1; + + for (i=0; i<ncolors; i++) + { + if (!success[i]) + { + if (gdk_colormap_alloc1 (colormap, &colors[i], &colors[i])) + success[i] = TRUE; + else + nremaining++; + } + } + + + if (nremaining > 0 && best_match) + { + gchar *available = g_new (gchar, colormap->size); + for (i = 0; i < colormap->size; i++) + available[i] = ((private->info[i].ref_count == 0) || + !(private->info[i].flags && GDK_COLOR_WRITEABLE)); + gdk_colormap_sync (colormap, FALSE); + + while (nremaining > 0) + { + for (i=0; i<ncolors; i++) + { + if (!success[i]) + { + index = gdk_colormap_match_color (colormap, &colors[i], available); + if (index != -1) + { + if (private->info[index].ref_count) + { + private->info[index].ref_count++; + colors[i] = colormap->colors[index]; + success[i] = TRUE; + nremaining--; + } + else + { + if (gdk_colormap_alloc1 (colormap, + &colormap->colors[index], + &colors[i])) + { + success[i] = TRUE; + nremaining--; + break; + } + else + { + available[index] = FALSE; + } + } + } + else + { + nfailed++; + nremaining--; + success[i] = 2; /* flag as permanent failure */ + } + } + } + } + g_free (available); + } + + /* Change back the values we flagged as permanent failures */ + if (nfailed > 0) + { + for (i=0; i<ncolors; i++) + if (success[i] == 2) + success[i] = FALSE; + nremaining = nfailed; + } + + return (ncolors - nremaining); +} + +static gint +gdk_colormap_alloc_colors_pseudocolor (GdkColormap *colormap, + GdkColor *colors, + gint ncolors, + gboolean writeable, + gboolean best_match, + gboolean *success) +{ + GdkColormapPrivate *private; + GdkColor *lookup_color; + gint i; + gint nremaining = 0; + + private = (GdkColormapPrivate*) colormap; + + /* Check for an exact match among previously allocated colors */ + + for (i=0; i<ncolors; i++) + { + if (!success[i]) + { + lookup_color = g_hash_table_lookup (private->hash, &colors[i]); + if (lookup_color) + { + private->info[lookup_color->pixel].ref_count++; + colors[i].pixel = lookup_color->pixel; + success[i] = TRUE; + } + else + nremaining++; + } + } + + /* If that failed, we try to allocate a new color, or approxmiate + * with what we can get if best_match is TRUE. + */ + if (nremaining > 0) + { + if (private->private_val) + return gdk_colormap_alloc_colors_private (colormap, colors, ncolors, writeable, best_match, success); + else + return gdk_colormap_alloc_colors_shared (colormap, colors, ncolors, writeable, best_match, success); + } + else + return 0; +} + +gint +gdk_colormap_alloc_colors (GdkColormap *colormap, + GdkColor *colors, + gint ncolors, + gboolean writeable, + gboolean best_match, + gboolean *success) +{ + GdkColormapPrivate *private; + GdkVisual *visual; + gint i; + gint nremaining = 0; + XColor xcolor; + + g_return_val_if_fail (colormap != NULL, FALSE); + g_return_val_if_fail (colors != NULL, FALSE); + + private = (GdkColormapPrivate*) colormap; + + for (i=0; i<ncolors; i++) + { + success[i] = FALSE; + } + + switch (private->visual->type) + { + case GDK_VISUAL_PSEUDO_COLOR: + case GDK_VISUAL_GRAYSCALE: + if (writeable) + return gdk_colormap_alloc_colors_writeable (colormap, colors, ncolors, + writeable, best_match, success); + else + return gdk_colormap_alloc_colors_pseudocolor (colormap, colors, ncolors, + writeable, best_match, success); + break; + + case GDK_VISUAL_TRUE_COLOR: + visual = private->visual; + + for (i=0; i<ncolors; i++) + { + colors[i].pixel = (((colors[i].red >> (16 - visual->red_prec)) << visual->red_shift) + + ((colors[i].green >> (16 - visual->green_prec)) << visual->green_shift) + + ((colors[i].blue >> (16 - visual->blue_prec)) << visual->blue_shift)); + success[i] = TRUE; + } + break; + + case GDK_VISUAL_STATIC_GRAY: + case GDK_VISUAL_STATIC_COLOR: + for (i=0; i<ncolors; i++) + { + xcolor.peRed = colors[i].red >> 8; + xcolor.peGreen = colors[i].green >> 8; + xcolor.peBlue = colors[i].blue >> 8; + if (alloc_color (private->xcolormap, &xcolor, &colors[i].pixel)) + success[i] = TRUE; + else + nremaining++; + } + break; + } + return nremaining; +} + +gboolean +gdk_colormap_alloc_color (GdkColormap *colormap, + GdkColor *color, + gboolean writeable, + gboolean best_match) +{ + gboolean success; + + GDK_NOTE (MISC, g_print ("gdk_colormap_alloc_color: (%.04x,%.04x,%.04x)", + color->red, color->green, color->blue)); + + gdk_colormap_alloc_colors (colormap, color, 1, writeable, best_match, + &success); + GDK_NOTE (MISC, g_print (" -> %.08x\n", color->pixel)); + + return success; +} + +/* This is almost identical to gdk_colors_free. + * Keep them in sync! + */ +void +gdk_colormap_free_colors (GdkColormap *colormap, + GdkColor *colors, + gint ncolors) +{ + GdkColormapPrivate *private; + gulong *pixels; + gint npixels = 0; + gint i; + + g_return_if_fail (colormap != NULL); + g_return_if_fail (colors != NULL); + + private = (GdkColormapPrivate*) colormap; + + if ((private->visual->type != GDK_VISUAL_PSEUDO_COLOR) && + (private->visual->type != GDK_VISUAL_GRAYSCALE)) + return; + + pixels = g_new (gulong, ncolors); + + for (i=0; i<ncolors; i++) + { + gulong pixel = colors[i].pixel; + + if (private->info[pixel].ref_count) + { + private->info[pixel].ref_count--; + + if (private->info[pixel].ref_count == 0) + { + pixels[npixels++] = pixel; + if (!(private->info[pixel].flags & GDK_COLOR_WRITEABLE)) + g_hash_table_remove (private->hash, &colors[i]); + private->info[pixel].flags = 0; + } + } + } + if (npixels) + XFreeColors (private->xcolormap, pixels, npixels, 0); + g_free (pixels); +} + +gboolean +gdk_color_alloc (GdkColormap *colormap, + GdkColor *color) +{ + gboolean success; + + GDK_NOTE (MISC, g_print ("gdk_color_alloc: (%.04x,%.04x,%.04x)", + color->red, color->green, color->blue)); + + gdk_colormap_alloc_colors (colormap, color, 1, FALSE, TRUE, &success); + + GDK_NOTE (MISC, g_print (" -> %.08x\n", color->pixel)); + + return success; +} + +gboolean +gdk_color_change (GdkColormap *colormap, + GdkColor *color) +{ + GdkColormapPrivate *private; + XColor xcolor; + + g_return_val_if_fail (colormap != NULL, FALSE); + g_return_val_if_fail (color != NULL, FALSE); + + private = (GdkColormapPrivate*) colormap; + + xcolor.peRed = color->red >> 8; + xcolor.peGreen = color->green >> 8; + xcolor.peBlue = color->blue >> 8; + + if (SetPaletteEntries (private->xcolormap->palette, + color->pixel, 1, &xcolor) == 0) + g_warning ("gdk_color_change: SetPaletteEntries failed"); + private->xcolormap->stale = TRUE; + + return TRUE; +} + +guint +gdk_color_hash (const GdkColor *colora) +{ + return ((colora->red) + + (colora->green << 11) + + (colora->blue << 22) + + (colora->blue >> 6)); +} + +gint +gdk_color_equal (const GdkColor *colora, + const GdkColor *colorb) +{ + g_return_val_if_fail (colora != NULL, FALSE); + g_return_val_if_fail (colorb != NULL, FALSE); + + return ((colora->red == colorb->red) && + (colora->green == colorb->green) && + (colora->blue == colorb->blue)); +} + +static gint +gdk_colormap_match_color (GdkColormap *cmap, + GdkColor *color, + const gchar *available) +{ + GdkColor *colors; + guint sum, max; + gint rdiff, gdiff, bdiff; + gint i, index; + + g_return_val_if_fail (cmap != NULL, 0); + g_return_val_if_fail (color != NULL, 0); + + colors = cmap->colors; + max = 3 * (65536); + index = -1; + + for (i = 0; i < cmap->size; i++) + { + if ((!available) || (available && available[i])) + { + rdiff = (color->red - colors[i].red); + gdiff = (color->green - colors[i].green); + bdiff = (color->blue - colors[i].blue); + + sum = ABS (rdiff) + ABS (gdiff) + ABS (bdiff); + + if (sum < max) + { + index = i; + max = sum; + } + } + } + + return index; +} + +GdkColormap* +gdk_colormap_lookup (Colormap xcolormap) +{ + GdkColormap *cmap; + + if (!colormap_hash) + return NULL; + + cmap = g_hash_table_lookup (colormap_hash, &xcolormap); + return cmap; +} + +static void +gdk_colormap_add (GdkColormap *cmap) +{ + GdkColormapPrivate *private; + + if (!colormap_hash) + colormap_hash = g_hash_table_new ((GHashFunc) gdk_colormap_hash, + (GCompareFunc) gdk_colormap_cmp); + + private = (GdkColormapPrivate*) cmap; + + g_hash_table_insert (colormap_hash, &private->xcolormap, cmap); +} + +static void +gdk_colormap_remove (GdkColormap *cmap) +{ + GdkColormapPrivate *private; + + if (!colormap_hash) + colormap_hash = g_hash_table_new ((GHashFunc) gdk_colormap_hash, + (GCompareFunc) gdk_colormap_cmp); + + private = (GdkColormapPrivate*) cmap; + + g_hash_table_remove (colormap_hash, &private->xcolormap); +} + +static guint +gdk_colormap_hash (Colormap *cmap) +{ + return (guint) *cmap; +} + +static gint +gdk_colormap_cmp (Colormap *a, + Colormap *b) +{ + return (*a == *b); +} + +char * +gdk_color_to_string (GdkColor *color) +{ + static char buf[100]; + + sprintf (buf, "(%.04x,%.04x,%.04x): %.06x", + color->red, color->green, color->blue, color->pixel); + + return buf; +} diff --git a/gdk/win32/gdkcolor.c b/gdk/win32/gdkcolor.c new file mode 100644 index 000000000..4b81f24d5 --- /dev/null +++ b/gdk/win32/gdkcolor.c @@ -0,0 +1,2443 @@ +/* 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 <stdlib.h> +#include <string.h> +#include <time.h> + +#include "gdk.h" +#include "gdkprivate.h" +#include "gdkx.h" + +#ifdef _MSC_VER +#define strcasecmp stricmp +#endif + +static gint gdk_colormap_match_color (GdkColormap *cmap, + GdkColor *color, + const gchar *available); +static void gdk_colormap_add (GdkColormap *cmap); +static void gdk_colormap_remove (GdkColormap *cmap); +static guint gdk_colormap_hash (Colormap *cmap); +static gint gdk_colormap_cmp (Colormap *a, + Colormap *b); +static void gdk_colormap_real_destroy (GdkColormap *colormap); + +static GHashTable *colormap_hash = NULL; + +static Status +alloc_color_cells(Colormap colormap, + gboolean contig, + unsigned long plane_masks_return[], + unsigned int nplanes, + unsigned long pixels_return[], + unsigned int npixels) +{ + unsigned int i, nfree, iret; + + nfree = 0; + for (i = 0; i < colormap->size && nfree < npixels; i++) + if (!colormap->in_use[i]) + nfree++; + + if (colormap->size + npixels - nfree > colormap->sizepalette) + { + g_warning ("alloc_color_cells: too large palette: %d", + colormap->size + npixels); + return FALSE; + } + + iret = 0; + for (i = 0; i < colormap->size && iret < npixels; i++) + if (!colormap->in_use[i]) + { + colormap->in_use[i] = TRUE; + pixels_return[iret] = i; + iret++; + } + + if (nfree < npixels) + { + int nmore = npixels - nfree; + + /* I don't understand why, if the code below in #if 0 is + enabled, gdkrgb fails miserably. The palette doesn't get + realized correctly. There doesn't seem to be any harm done by + keeping this code out, either. */ +#ifdef SOME_STRANGE_BUG + if (!ResizePalette (colormap->palette, colormap->size + nmore)) + { + g_warning ("alloc_color_cells: ResizePalette to %d failed", + colormap->size + nmore); + return FALSE; + } + g_print("alloc_color_cells: %#x to %d\n", + colormap->palette, colormap->size + nmore); +#endif + for (i = colormap->size; i < colormap->size + nmore; i++) + { + pixels_return[iret] = i; + iret++; + colormap->in_use[i] = TRUE; + } +#ifdef SOME_STRANGE_BUG + colormap->size += nmore; +#endif + } + return TRUE; +} + +/* The following functions are from Tk8.0, but heavily modified. + Here are tk's licensing terms. I hope these terms don't conflict + with the GNU Library General Public License? They shouldn't, as + they are looser that the GLPL, yes? */ + +/* +This software is copyrighted by the Regents of the University of +California, Sun Microsystems, Inc., and other parties. The following +terms apply to all files associated with the software unless explicitly +disclaimed in individual files. + +The authors hereby grant permission to use, copy, modify, distribute, +and license this software and its documentation for any purpose, provided +that existing copyright notices are retained in all copies and that this +notice is included verbatim in any distributions. No written agreement, +license, or royalty fee is required for any of the authorized uses. +Modifications to this software may be copyrighted by their authors +and need not follow the licensing terms described here, provided that +the new terms are clearly indicated on the first page of each file where +they apply. + +IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY +FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY +DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE +IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE +NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR +MODIFICATIONS. + +GOVERNMENT USE: If you are acquiring this software on behalf of the +U.S. government, the Government shall have only "Restricted Rights" +in the software and related documentation as defined in the Federal +Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you +are acquiring the software on behalf of the Department of Defense, the +software shall be classified as "Commercial Computer Software" and the +Government shall have only "Restricted Rights" as defined in Clause +252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the +authors grant the U.S. Government and others acting in its behalf +permission to use and distribute the software in accordance with the +terms specified in this license. +*/ +/* + *---------------------------------------------------------------------- + * + * XAllocColor -- + * + * Find the closest available color to the specified XColor. + * + * Results: + * Updates the color argument and returns 1 on success. Otherwise + * returns 0. + * + * Side effects: + * Allocates a new color in the palette. + * + *---------------------------------------------------------------------- + */ + +static int +alloc_color(Colormap colormap, + XColor *color, + guint *pixelp) +{ + PALETTEENTRY entry, closeEntry; + HDC hdc; + unsigned int i; + + entry = *color; + entry.peFlags = 0; + + if (colormap->rc_palette) + { + COLORREF newPixel, closePixel; + UINT index; + + /* + * Find the nearest existing palette entry. + */ + + newPixel = RGB (entry.peRed, entry.peGreen, entry.peBlue); + index = GetNearestPaletteIndex (colormap->palette, newPixel); + GetPaletteEntries (colormap->palette, index, 1, &closeEntry); + closePixel = RGB (closeEntry.peRed, closeEntry.peGreen, + closeEntry.peBlue); + + if (newPixel != closePixel) + { + /* Not a perfect match. */ + if (!colormap->in_use[index]) + { + /* It was a free'd entry anyway, so we can use it, and + set it to the correct color. */ + if (SetPaletteEntries (colormap->palette, index, 1, &entry) == 0) + g_warning ("alloc_color: SetPaletteEntries #1 failed"); + } + else + { + /* The close entry found is in use, so search for a + unused slot. */ + + for (i = 0; i < colormap->size; i++) + if (!colormap->in_use[i]) + { + /* A free slot, use it. */ + if (SetPaletteEntries (colormap->palette, + index, 1, &entry) == 0) + g_warning ("alloc_color: SetPaletteEntries #2 failed"); + index = i; + break; + } + if (i == colormap->size) + { + /* No free slots found. If the palette isn't maximal + yet, grow it. */ + if (colormap->size == colormap->sizepalette) + { + /* The palette is maximal, and no free slots available, + so use the close entry, then, dammit. */ + *color = closeEntry; + } + else + { + /* There is room to grow the palette. */ + index = colormap->size; + colormap->size++; + if (!ResizePalette (colormap->palette, colormap->size)) + g_warning ("alloc_color: ResizePalette to %d failed", + colormap->size); + if (SetPaletteEntries (colormap->palette, index, 1, &entry) == 0) + g_warning ("alloc_color: SetPaletteEntries #3 failed"); + } + } + } + colormap->stale = TRUE; + } + else + { + /* We got a match, so use it. */ + } + + *pixelp = index; + colormap->in_use[index] = TRUE; +#if 0 + g_print("alloc_color from %#x: index %d for %02x %02x %02x\n", + colormap->palette, index, + entry.peRed, entry.peGreen, entry.peBlue); +#endif + } + else + { + /* + * Determine what color will actually be used on non-colormap systems. + */ + *pixelp = GetNearestColor (gdk_DC, RGB(entry.peRed, entry.peGreen, entry.peBlue)); + + color->peRed = GetRValue (*pixelp); + color->peGreen = GetGValue (*pixelp); + color->peBlue = GetBValue (*pixelp); + } + + return 1; +} + +/* + *---------------------------------------------------------------------- + * + * XFreeColors -- + * + * Deallocate a block of colors. + * + * Results: + * None. + * + * Side effects: + * Removes entries for the current palette and compacts the + * remaining set. + * + *---------------------------------------------------------------------- + */ + +static void +XFreeColors(Colormap colormap, + gulong *pixels, + gint npixels, + gulong planes) +{ + gint i; + PALETTEENTRY entries[256]; + + /* + * We don't have to do anything for non-palette devices. + */ + + if (colormap->rc_palette) + { + int npal; + int lowestpixel = 256; + int highestpixel = -1; + + npal = GetPaletteEntries (colormap->palette, 0, 256, entries); + for (i = 0; i < npixels; i++) + { + int pixel = pixels[i]; + + if (pixel < lowestpixel) + lowestpixel = pixel; + if (pixel > highestpixel) + highestpixel = pixel; + + colormap->in_use[pixel] = FALSE; + + entries[pixel] = entries[0]; + } +#if 0 + if (SetPaletteEntries (colormap->palette, lowestpixel, + highestpixel - lowestpixel + 1, + entries + lowestpixel) == 0) + g_warning ("XFreeColors: SetPaletteEntries failed"); +#endif + colormap->stale = TRUE; +#if 0 + g_print("XFreeColors %#x lowestpixel = %d, highestpixel = %d\n", + colormap->palette, lowestpixel, highestpixel); +#endif + } +} + +/* + *---------------------------------------------------------------------- + * + * XCreateColormap -- + * + * Allocate a new colormap. + * + * Results: + * Returns a newly allocated colormap. + * + * Side effects: + * Allocates an empty palette and color list. + * + *---------------------------------------------------------------------- + */ + +static Colormap +create_colormap (HWND w, + Visual *visual, + int alloc) +{ + char logPalBuf[sizeof(LOGPALETTE) + 256 * sizeof(PALETTEENTRY)]; + LOGPALETTE *logPalettePtr; + PALETTEENTRY *entryPtr; + Colormap colormap; + guint i; + HPALETTE sysPal; + HDC hdc; + + /* Should the alloc parameter do something? */ + + + /* Allocate a starting palette with all of the reserved colors. */ + + logPalettePtr = (LOGPALETTE *) logPalBuf; + logPalettePtr->palVersion = 0x300; + sysPal = (HPALETTE) GetStockObject (DEFAULT_PALETTE); + logPalettePtr->palNumEntries = + GetPaletteEntries (sysPal, 0, 256, logPalettePtr->palPalEntry); + + colormap = (Colormap) g_new (ColormapStruct, 1); + colormap->size = logPalettePtr->palNumEntries; + colormap->stale = TRUE; + colormap->palette = CreatePalette (logPalettePtr); + hdc = GetDC (NULL); + colormap->rc_palette = ((GetDeviceCaps (hdc, RASTERCAPS) & RC_PALETTE) != 0); + if (colormap->rc_palette) + { + colormap->sizepalette = GetDeviceCaps (hdc, SIZEPALETTE); + colormap->in_use = g_new (gboolean, colormap->sizepalette); + /* Mark static colors in use. */ + for (i = 0; i < logPalettePtr->palNumEntries; i++) + colormap->in_use[i] = TRUE; + /* Mark rest not in use */ + for (i = logPalettePtr->palNumEntries; i < colormap->sizepalette; i++) + colormap->in_use[i] = FALSE; + } + ReleaseDC (NULL, hdc); + + return colormap; +} + +/* + *---------------------------------------------------------------------- + * + * XFreeColormap -- + * + * Frees the resources associated with the given colormap. + * + * Results: + * None. + * + * Side effects: + * Deletes the palette associated with the colormap. Note that + * the palette must not be selected into a device context when + * this occurs. + * + *---------------------------------------------------------------------- + */ + +static void +XFreeColormap(Colormap colormap) + +{ + if (!DeleteObject (colormap->palette)) + { + g_error ("Unable to free colormap, palette is still selected."); + } + g_free (colormap); +} + +typedef struct { + char *name; + unsigned char red; + unsigned char green; + unsigned char blue; +} XColorEntry; + +static XColorEntry xColors[] = { + { "alice blue", 240, 248, 255 }, + { "AliceBlue", 240, 248, 255 }, + { "antique white", 250, 235, 215 }, + { "AntiqueWhite", 250, 235, 215 }, + { "AntiqueWhite1", 255, 239, 219 }, + { "AntiqueWhite2", 238, 223, 204 }, + { "AntiqueWhite3", 205, 192, 176 }, + { "AntiqueWhite4", 139, 131, 120 }, + { "aquamarine", 127, 255, 212 }, + { "aquamarine1", 127, 255, 212 }, + { "aquamarine2", 118, 238, 198 }, + { "aquamarine3", 102, 205, 170 }, + { "aquamarine4", 69, 139, 116 }, + { "azure", 240, 255, 255 }, + { "azure1", 240, 255, 255 }, + { "azure2", 224, 238, 238 }, + { "azure3", 193, 205, 205 }, + { "azure4", 131, 139, 139 }, + { "beige", 245, 245, 220 }, + { "bisque", 255, 228, 196 }, + { "bisque1", 255, 228, 196 }, + { "bisque2", 238, 213, 183 }, + { "bisque3", 205, 183, 158 }, + { "bisque4", 139, 125, 107 }, + { "black", 0, 0, 0 }, + { "blanched almond", 255, 235, 205 }, + { "BlanchedAlmond", 255, 235, 205 }, + { "blue", 0, 0, 255 }, + { "blue violet", 138, 43, 226 }, + { "blue1", 0, 0, 255 }, + { "blue2", 0, 0, 238 }, + { "blue3", 0, 0, 205 }, + { "blue4", 0, 0, 139 }, + { "BlueViolet", 138, 43, 226 }, + { "brown", 165, 42, 42 }, + { "brown1", 255, 64, 64 }, + { "brown2", 238, 59, 59 }, + { "brown3", 205, 51, 51 }, + { "brown4", 139, 35, 35 }, + { "burlywood", 222, 184, 135 }, + { "burlywood1", 255, 211, 155 }, + { "burlywood2", 238, 197, 145 }, + { "burlywood3", 205, 170, 125 }, + { "burlywood4", 139, 115, 85 }, + { "cadet blue", 95, 158, 160 }, + { "CadetBlue", 95, 158, 160 }, + { "CadetBlue1", 152, 245, 255 }, + { "CadetBlue2", 142, 229, 238 }, + { "CadetBlue3", 122, 197, 205 }, + { "CadetBlue4", 83, 134, 139 }, + { "chartreuse", 127, 255, 0 }, + { "chartreuse1", 127, 255, 0 }, + { "chartreuse2", 118, 238, 0 }, + { "chartreuse3", 102, 205, 0 }, + { "chartreuse4", 69, 139, 0 }, + { "chocolate", 210, 105, 30 }, + { "chocolate1", 255, 127, 36 }, + { "chocolate2", 238, 118, 33 }, + { "chocolate3", 205, 102, 29 }, + { "chocolate4", 139, 69, 19 }, + { "coral", 255, 127, 80 }, + { "coral1", 255, 114, 86 }, + { "coral2", 238, 106, 80 }, + { "coral3", 205, 91, 69 }, + { "coral4", 139, 62, 47 }, + { "cornflower blue", 100, 149, 237 }, + { "CornflowerBlue", 100, 149, 237 }, + { "cornsilk", 255, 248, 220 }, + { "cornsilk1", 255, 248, 220 }, + { "cornsilk2", 238, 232, 205 }, + { "cornsilk3", 205, 200, 177 }, + { "cornsilk4", 139, 136, 120 }, + { "cyan", 0, 255, 255 }, + { "cyan1", 0, 255, 255 }, + { "cyan2", 0, 238, 238 }, + { "cyan3", 0, 205, 205 }, + { "cyan4", 0, 139, 139 }, + { "dark blue", 0, 0, 139 }, + { "dark cyan", 0, 139, 139 }, + { "dark goldenrod", 184, 134, 11 }, + { "dark gray", 169, 169, 169 }, + { "dark green", 0, 100, 0 }, + { "dark grey", 169, 169, 169 }, + { "dark khaki", 189, 183, 107 }, + { "dark magenta", 139, 0, 139 }, + { "dark olive green", 85, 107, 47 }, + { "dark orange", 255, 140, 0 }, + { "dark orchid", 153, 50, 204 }, + { "dark red", 139, 0, 0 }, + { "dark salmon", 233, 150, 122 }, + { "dark sea green", 143, 188, 143 }, + { "dark slate blue", 72, 61, 139 }, + { "dark slate gray", 47, 79, 79 }, + { "dark slate grey", 47, 79, 79 }, + { "dark turquoise", 0, 206, 209 }, + { "dark violet", 148, 0, 211 }, + { "DarkBlue", 0, 0, 139 }, + { "DarkCyan", 0, 139, 139 }, + { "DarkGoldenrod", 184, 134, 11 }, + { "DarkGoldenrod1", 255, 185, 15 }, + { "DarkGoldenrod2", 238, 173, 14 }, + { "DarkGoldenrod3", 205, 149, 12 }, + { "DarkGoldenrod4", 139, 101, 8 }, + { "DarkGray", 169, 169, 169 }, + { "DarkGreen", 0, 100, 0 }, + { "DarkGrey", 169, 169, 169 }, + { "DarkKhaki", 189, 183, 107 }, + { "DarkMagenta", 139, 0, 139 }, + { "DarkOliveGreen", 85, 107, 47 }, + { "DarkOliveGreen1", 202, 255, 112 }, + { "DarkOliveGreen2", 188, 238, 104 }, + { "DarkOliveGreen3", 162, 205, 90 }, + { "DarkOliveGreen4", 110, 139, 61 }, + { "DarkOrange", 255, 140, 0 }, + { "DarkOrange1", 255, 127, 0 }, + { "DarkOrange2", 238, 118, 0 }, + { "DarkOrange3", 205, 102, 0 }, + { "DarkOrange4", 139, 69, 0 }, + { "DarkOrchid", 153, 50, 204 }, + { "DarkOrchid1", 191, 62, 255 }, + { "DarkOrchid2", 178, 58, 238 }, + { "DarkOrchid3", 154, 50, 205 }, + { "DarkOrchid4", 104, 34, 139 }, + { "DarkRed", 139, 0, 0 }, + { "DarkSalmon", 233, 150, 122 }, + { "DarkSeaGreen", 143, 188, 143 }, + { "DarkSeaGreen1", 193, 255, 193 }, + { "DarkSeaGreen2", 180, 238, 180 }, + { "DarkSeaGreen3", 155, 205, 155 }, + { "DarkSeaGreen4", 105, 139, 105 }, + { "DarkSlateBlue", 72, 61, 139 }, + { "DarkSlateGray", 47, 79, 79 }, + { "DarkSlateGray1", 151, 255, 255 }, + { "DarkSlateGray2", 141, 238, 238 }, + { "DarkSlateGray3", 121, 205, 205 }, + { "DarkSlateGray4", 82, 139, 139 }, + { "DarkSlateGrey", 47, 79, 79 }, + { "DarkTurquoise", 0, 206, 209 }, + { "DarkViolet", 148, 0, 211 }, + { "deep pink", 255, 20, 147 }, + { "deep sky blue", 0, 191, 255 }, + { "DeepPink", 255, 20, 147 }, + { "DeepPink1", 255, 20, 147 }, + { "DeepPink2", 238, 18, 137 }, + { "DeepPink3", 205, 16, 118 }, + { "DeepPink4", 139, 10, 80 }, + { "DeepSkyBlue", 0, 191, 255 }, + { "DeepSkyBlue1", 0, 191, 255 }, + { "DeepSkyBlue2", 0, 178, 238 }, + { "DeepSkyBlue3", 0, 154, 205 }, + { "DeepSkyBlue4", 0, 104, 139 }, + { "dim gray", 105, 105, 105 }, + { "dim grey", 105, 105, 105 }, + { "DimGray", 105, 105, 105 }, + { "DimGrey", 105, 105, 105 }, + { "dodger blue", 30, 144, 255 }, + { "DodgerBlue", 30, 144, 255 }, + { "DodgerBlue1", 30, 144, 255 }, + { "DodgerBlue2", 28, 134, 238 }, + { "DodgerBlue3", 24, 116, 205 }, + { "DodgerBlue4", 16, 78, 139 }, + { "firebrick", 178, 34, 34 }, + { "firebrick1", 255, 48, 48 }, + { "firebrick2", 238, 44, 44 }, + { "firebrick3", 205, 38, 38 }, + { "firebrick4", 139, 26, 26 }, + { "floral white", 255, 250, 240 }, + { "FloralWhite", 255, 250, 240 }, + { "forest green", 34, 139, 34 }, + { "ForestGreen", 34, 139, 34 }, + { "gainsboro", 220, 220, 220 }, + { "ghost white", 248, 248, 255 }, + { "GhostWhite", 248, 248, 255 }, + { "gold", 255, 215, 0 }, + { "gold1", 255, 215, 0 }, + { "gold2", 238, 201, 0 }, + { "gold3", 205, 173, 0 }, + { "gold4", 139, 117, 0 }, + { "goldenrod", 218, 165, 32 }, + { "goldenrod1", 255, 193, 37 }, + { "goldenrod2", 238, 180, 34 }, + { "goldenrod3", 205, 155, 29 }, + { "goldenrod4", 139, 105, 20 }, + { "gray", 190, 190, 190 }, + { "gray0", 0, 0, 0 }, + { "gray1", 3, 3, 3 }, + { "gray10", 26, 26, 26 }, + { "gray100", 255, 255, 255 }, + { "gray11", 28, 28, 28 }, + { "gray12", 31, 31, 31 }, + { "gray13", 33, 33, 33 }, + { "gray14", 36, 36, 36 }, + { "gray15", 38, 38, 38 }, + { "gray16", 41, 41, 41 }, + { "gray17", 43, 43, 43 }, + { "gray18", 46, 46, 46 }, + { "gray19", 48, 48, 48 }, + { "gray2", 5, 5, 5 }, + { "gray20", 51, 51, 51 }, + { "gray21", 54, 54, 54 }, + { "gray22", 56, 56, 56 }, + { "gray23", 59, 59, 59 }, + { "gray24", 61, 61, 61 }, + { "gray25", 64, 64, 64 }, + { "gray26", 66, 66, 66 }, + { "gray27", 69, 69, 69 }, + { "gray28", 71, 71, 71 }, + { "gray29", 74, 74, 74 }, + { "gray3", 8, 8, 8 }, + { "gray30", 77, 77, 77 }, + { "gray31", 79, 79, 79 }, + { "gray32", 82, 82, 82 }, + { "gray33", 84, 84, 84 }, + { "gray34", 87, 87, 87 }, + { "gray35", 89, 89, 89 }, + { "gray36", 92, 92, 92 }, + { "gray37", 94, 94, 94 }, + { "gray38", 97, 97, 97 }, + { "gray39", 99, 99, 99 }, + { "gray4", 10, 10, 10 }, + { "gray40", 102, 102, 102 }, + { "gray41", 105, 105, 105 }, + { "gray42", 107, 107, 107 }, + { "gray43", 110, 110, 110 }, + { "gray44", 112, 112, 112 }, + { "gray45", 115, 115, 115 }, + { "gray46", 117, 117, 117 }, + { "gray47", 120, 120, 120 }, + { "gray48", 122, 122, 122 }, + { "gray49", 125, 125, 125 }, + { "gray5", 13, 13, 13 }, + { "gray50", 127, 127, 127 }, + { "gray51", 130, 130, 130 }, + { "gray52", 133, 133, 133 }, + { "gray53", 135, 135, 135 }, + { "gray54", 138, 138, 138 }, + { "gray55", 140, 140, 140 }, + { "gray56", 143, 143, 143 }, + { "gray57", 145, 145, 145 }, + { "gray58", 148, 148, 148 }, + { "gray59", 150, 150, 150 }, + { "gray6", 15, 15, 15 }, + { "gray60", 153, 153, 153 }, + { "gray61", 156, 156, 156 }, + { "gray62", 158, 158, 158 }, + { "gray63", 161, 161, 161 }, + { "gray64", 163, 163, 163 }, + { "gray65", 166, 166, 166 }, + { "gray66", 168, 168, 168 }, + { "gray67", 171, 171, 171 }, + { "gray68", 173, 173, 173 }, + { "gray69", 176, 176, 176 }, + { "gray7", 18, 18, 18 }, + { "gray70", 179, 179, 179 }, + { "gray71", 181, 181, 181 }, + { "gray72", 184, 184, 184 }, + { "gray73", 186, 186, 186 }, + { "gray74", 189, 189, 189 }, + { "gray75", 191, 191, 191 }, + { "gray76", 194, 194, 194 }, + { "gray77", 196, 196, 196 }, + { "gray78", 199, 199, 199 }, + { "gray79", 201, 201, 201 }, + { "gray8", 20, 20, 20 }, + { "gray80", 204, 204, 204 }, + { "gray81", 207, 207, 207 }, + { "gray82", 209, 209, 209 }, + { "gray83", 212, 212, 212 }, + { "gray84", 214, 214, 214 }, + { "gray85", 217, 217, 217 }, + { "gray86", 219, 219, 219 }, + { "gray87", 222, 222, 222 }, + { "gray88", 224, 224, 224 }, + { "gray89", 227, 227, 227 }, + { "gray9", 23, 23, 23 }, + { "gray90", 229, 229, 229 }, + { "gray91", 232, 232, 232 }, + { "gray92", 235, 235, 235 }, + { "gray93", 237, 237, 237 }, + { "gray94", 240, 240, 240 }, + { "gray95", 242, 242, 242 }, + { "gray96", 245, 245, 245 }, + { "gray97", 247, 247, 247 }, + { "gray98", 250, 250, 250 }, + { "gray99", 252, 252, 252 }, + { "green", 0, 255, 0 }, + { "green yellow", 173, 255, 47 }, + { "green1", 0, 255, 0 }, + { "green2", 0, 238, 0 }, + { "green3", 0, 205, 0 }, + { "green4", 0, 139, 0 }, + { "GreenYellow", 173, 255, 47 }, + { "grey", 190, 190, 190 }, + { "grey0", 0, 0, 0 }, + { "grey1", 3, 3, 3 }, + { "grey10", 26, 26, 26 }, + { "grey100", 255, 255, 255 }, + { "grey11", 28, 28, 28 }, + { "grey12", 31, 31, 31 }, + { "grey13", 33, 33, 33 }, + { "grey14", 36, 36, 36 }, + { "grey15", 38, 38, 38 }, + { "grey16", 41, 41, 41 }, + { "grey17", 43, 43, 43 }, + { "grey18", 46, 46, 46 }, + { "grey19", 48, 48, 48 }, + { "grey2", 5, 5, 5 }, + { "grey20", 51, 51, 51 }, + { "grey21", 54, 54, 54 }, + { "grey22", 56, 56, 56 }, + { "grey23", 59, 59, 59 }, + { "grey24", 61, 61, 61 }, + { "grey25", 64, 64, 64 }, + { "grey26", 66, 66, 66 }, + { "grey27", 69, 69, 69 }, + { "grey28", 71, 71, 71 }, + { "grey29", 74, 74, 74 }, + { "grey3", 8, 8, 8 }, + { "grey30", 77, 77, 77 }, + { "grey31", 79, 79, 79 }, + { "grey32", 82, 82, 82 }, + { "grey33", 84, 84, 84 }, + { "grey34", 87, 87, 87 }, + { "grey35", 89, 89, 89 }, + { "grey36", 92, 92, 92 }, + { "grey37", 94, 94, 94 }, + { "grey38", 97, 97, 97 }, + { "grey39", 99, 99, 99 }, + { "grey4", 10, 10, 10 }, + { "grey40", 102, 102, 102 }, + { "grey41", 105, 105, 105 }, + { "grey42", 107, 107, 107 }, + { "grey43", 110, 110, 110 }, + { "grey44", 112, 112, 112 }, + { "grey45", 115, 115, 115 }, + { "grey46", 117, 117, 117 }, + { "grey47", 120, 120, 120 }, + { "grey48", 122, 122, 122 }, + { "grey49", 125, 125, 125 }, + { "grey5", 13, 13, 13 }, + { "grey50", 127, 127, 127 }, + { "grey51", 130, 130, 130 }, + { "grey52", 133, 133, 133 }, + { "grey53", 135, 135, 135 }, + { "grey54", 138, 138, 138 }, + { "grey55", 140, 140, 140 }, + { "grey56", 143, 143, 143 }, + { "grey57", 145, 145, 145 }, + { "grey58", 148, 148, 148 }, + { "grey59", 150, 150, 150 }, + { "grey6", 15, 15, 15 }, + { "grey60", 153, 153, 153 }, + { "grey61", 156, 156, 156 }, + { "grey62", 158, 158, 158 }, + { "grey63", 161, 161, 161 }, + { "grey64", 163, 163, 163 }, + { "grey65", 166, 166, 166 }, + { "grey66", 168, 168, 168 }, + { "grey67", 171, 171, 171 }, + { "grey68", 173, 173, 173 }, + { "grey69", 176, 176, 176 }, + { "grey7", 18, 18, 18 }, + { "grey70", 179, 179, 179 }, + { "grey71", 181, 181, 181 }, + { "grey72", 184, 184, 184 }, + { "grey73", 186, 186, 186 }, + { "grey74", 189, 189, 189 }, + { "grey75", 191, 191, 191 }, + { "grey76", 194, 194, 194 }, + { "grey77", 196, 196, 196 }, + { "grey78", 199, 199, 199 }, + { "grey79", 201, 201, 201 }, + { "grey8", 20, 20, 20 }, + { "grey80", 204, 204, 204 }, + { "grey81", 207, 207, 207 }, + { "grey82", 209, 209, 209 }, + { "grey83", 212, 212, 212 }, + { "grey84", 214, 214, 214 }, + { "grey85", 217, 217, 217 }, + { "grey86", 219, 219, 219 }, + { "grey87", 222, 222, 222 }, + { "grey88", 224, 224, 224 }, + { "grey89", 227, 227, 227 }, + { "grey9", 23, 23, 23 }, + { "grey90", 229, 229, 229 }, + { "grey91", 232, 232, 232 }, + { "grey92", 235, 235, 235 }, + { "grey93", 237, 237, 237 }, + { "grey94", 240, 240, 240 }, + { "grey95", 242, 242, 242 }, + { "grey96", 245, 245, 245 }, + { "grey97", 247, 247, 247 }, + { "grey98", 250, 250, 250 }, + { "grey99", 252, 252, 252 }, + { "honeydew", 240, 255, 240 }, + { "honeydew1", 240, 255, 240 }, + { "honeydew2", 224, 238, 224 }, + { "honeydew3", 193, 205, 193 }, + { "honeydew4", 131, 139, 131 }, + { "hot pink", 255, 105, 180 }, + { "HotPink", 255, 105, 180 }, + { "HotPink1", 255, 110, 180 }, + { "HotPink2", 238, 106, 167 }, + { "HotPink3", 205, 96, 144 }, + { "HotPink4", 139, 58, 98 }, + { "indian red", 205, 92, 92 }, + { "IndianRed", 205, 92, 92 }, + { "IndianRed1", 255, 106, 106 }, + { "IndianRed2", 238, 99, 99 }, + { "IndianRed3", 205, 85, 85 }, + { "IndianRed4", 139, 58, 58 }, + { "ivory", 255, 255, 240 }, + { "ivory1", 255, 255, 240 }, + { "ivory2", 238, 238, 224 }, + { "ivory3", 205, 205, 193 }, + { "ivory4", 139, 139, 131 }, + { "khaki", 240, 230, 140 }, + { "khaki1", 255, 246, 143 }, + { "khaki2", 238, 230, 133 }, + { "khaki3", 205, 198, 115 }, + { "khaki4", 139, 134, 78 }, + { "lavender", 230, 230, 250 }, + { "lavender blush", 255, 240, 245 }, + { "LavenderBlush", 255, 240, 245 }, + { "LavenderBlush1", 255, 240, 245 }, + { "LavenderBlush2", 238, 224, 229 }, + { "LavenderBlush3", 205, 193, 197 }, + { "LavenderBlush4", 139, 131, 134 }, + { "lawn green", 124, 252, 0 }, + { "LawnGreen", 124, 252, 0 }, + { "lemon chiffon", 255, 250, 205 }, + { "LemonChiffon", 255, 250, 205 }, + { "LemonChiffon1", 255, 250, 205 }, + { "LemonChiffon2", 238, 233, 191 }, + { "LemonChiffon3", 205, 201, 165 }, + { "LemonChiffon4", 139, 137, 112 }, + { "light blue", 173, 216, 230 }, + { "light coral", 240, 128, 128 }, + { "light cyan", 224, 255, 255 }, + { "light goldenrod", 238, 221, 130 }, + { "light goldenrod yellow", 250, 250, 210 }, + { "light gray", 211, 211, 211 }, + { "light green", 144, 238, 144 }, + { "light grey", 211, 211, 211 }, + { "light pink", 255, 182, 193 }, + { "light salmon", 255, 160, 122 }, + { "light sea green", 32, 178, 170 }, + { "light sky blue", 135, 206, 250 }, + { "light slate blue", 132, 112, 255 }, + { "light slate gray", 119, 136, 153 }, + { "light slate grey", 119, 136, 153 }, + { "light steel blue", 176, 196, 222 }, + { "light yellow", 255, 255, 224 }, + { "LightBlue", 173, 216, 230 }, + { "LightBlue1", 191, 239, 255 }, + { "LightBlue2", 178, 223, 238 }, + { "LightBlue3", 154, 192, 205 }, + { "LightBlue4", 104, 131, 139 }, + { "LightCoral", 240, 128, 128 }, + { "LightCyan", 224, 255, 255 }, + { "LightCyan1", 224, 255, 255 }, + { "LightCyan2", 209, 238, 238 }, + { "LightCyan3", 180, 205, 205 }, + { "LightCyan4", 122, 139, 139 }, + { "LightGoldenrod", 238, 221, 130 }, + { "LightGoldenrod1", 255, 236, 139 }, + { "LightGoldenrod2", 238, 220, 130 }, + { "LightGoldenrod3", 205, 190, 112 }, + { "LightGoldenrod4", 139, 129, 76 }, + { "LightGoldenrodYellow", 250, 250, 210 }, + { "LightGray", 211, 211, 211 }, + { "LightGreen", 144, 238, 144 }, + { "LightGrey", 211, 211, 211 }, + { "LightPink", 255, 182, 193 }, + { "LightPink1", 255, 174, 185 }, + { "LightPink2", 238, 162, 173 }, + { "LightPink3", 205, 140, 149 }, + { "LightPink4", 139, 95, 101 }, + { "LightSalmon", 255, 160, 122 }, + { "LightSalmon1", 255, 160, 122 }, + { "LightSalmon2", 238, 149, 114 }, + { "LightSalmon3", 205, 129, 98 }, + { "LightSalmon4", 139, 87, 66 }, + { "LightSeaGreen", 32, 178, 170 }, + { "LightSkyBlue", 135, 206, 250 }, + { "LightSkyBlue1", 176, 226, 255 }, + { "LightSkyBlue2", 164, 211, 238 }, + { "LightSkyBlue3", 141, 182, 205 }, + { "LightSkyBlue4", 96, 123, 139 }, + { "LightSlateBlue", 132, 112, 255 }, + { "LightSlateGray", 119, 136, 153 }, + { "LightSlateGrey", 119, 136, 153 }, + { "LightSteelBlue", 176, 196, 222 }, + { "LightSteelBlue1", 202, 225, 255 }, + { "LightSteelBlue2", 188, 210, 238 }, + { "LightSteelBlue3", 162, 181, 205 }, + { "LightSteelBlue4", 110, 123, 139 }, + { "LightYellow", 255, 255, 224 }, + { "LightYellow1", 255, 255, 224 }, + { "LightYellow2", 238, 238, 209 }, + { "LightYellow3", 205, 205, 180 }, + { "LightYellow4", 139, 139, 122 }, + { "lime green", 50, 205, 50 }, + { "LimeGreen", 50, 205, 50 }, + { "linen", 250, 240, 230 }, + { "magenta", 255, 0, 255 }, + { "magenta1", 255, 0, 255 }, + { "magenta2", 238, 0, 238 }, + { "magenta3", 205, 0, 205 }, + { "magenta4", 139, 0, 139 }, + { "maroon", 176, 48, 96 }, + { "maroon1", 255, 52, 179 }, + { "maroon2", 238, 48, 167 }, + { "maroon3", 205, 41, 144 }, + { "maroon4", 139, 28, 98 }, + { "medium aquamarine", 102, 205, 170 }, + { "medium blue", 0, 0, 205 }, + { "medium orchid", 186, 85, 211 }, + { "medium purple", 147, 112, 219 }, + { "medium sea green", 60, 179, 113 }, + { "medium slate blue", 123, 104, 238 }, + { "medium spring green", 0, 250, 154 }, + { "medium turquoise", 72, 209, 204 }, + { "medium violet red", 199, 21, 133 }, + { "MediumAquamarine", 102, 205, 170 }, + { "MediumBlue", 0, 0, 205 }, + { "MediumOrchid", 186, 85, 211 }, + { "MediumOrchid1", 224, 102, 255 }, + { "MediumOrchid2", 209, 95, 238 }, + { "MediumOrchid3", 180, 82, 205 }, + { "MediumOrchid4", 122, 55, 139 }, + { "MediumPurple", 147, 112, 219 }, + { "MediumPurple1", 171, 130, 255 }, + { "MediumPurple2", 159, 121, 238 }, + { "MediumPurple3", 137, 104, 205 }, + { "MediumPurple4", 93, 71, 139 }, + { "MediumSeaGreen", 60, 179, 113 }, + { "MediumSlateBlue", 123, 104, 238 }, + { "MediumSpringGreen", 0, 250, 154 }, + { "MediumTurquoise", 72, 209, 204 }, + { "MediumVioletRed", 199, 21, 133 }, + { "midnight blue", 25, 25, 112 }, + { "MidnightBlue", 25, 25, 112 }, + { "mint cream", 245, 255, 250 }, + { "MintCream", 245, 255, 250 }, + { "misty rose", 255, 228, 225 }, + { "MistyRose", 255, 228, 225 }, + { "MistyRose1", 255, 228, 225 }, + { "MistyRose2", 238, 213, 210 }, + { "MistyRose3", 205, 183, 181 }, + { "MistyRose4", 139, 125, 123 }, + { "moccasin", 255, 228, 181 }, + { "navajo white", 255, 222, 173 }, + { "NavajoWhite", 255, 222, 173 }, + { "NavajoWhite1", 255, 222, 173 }, + { "NavajoWhite2", 238, 207, 161 }, + { "NavajoWhite3", 205, 179, 139 }, + { "NavajoWhite4", 139, 121, 94 }, + { "navy", 0, 0, 128 }, + { "navy blue", 0, 0, 128 }, + { "NavyBlue", 0, 0, 128 }, + { "old lace", 253, 245, 230 }, + { "OldLace", 253, 245, 230 }, + { "olive drab", 107, 142, 35 }, + { "OliveDrab", 107, 142, 35 }, + { "OliveDrab1", 192, 255, 62 }, + { "OliveDrab2", 179, 238, 58 }, + { "OliveDrab3", 154, 205, 50 }, + { "OliveDrab4", 105, 139, 34 }, + { "orange", 255, 165, 0 }, + { "orange red", 255, 69, 0 }, + { "orange1", 255, 165, 0 }, + { "orange2", 238, 154, 0 }, + { "orange3", 205, 133, 0 }, + { "orange4", 139, 90, 0 }, + { "OrangeRed", 255, 69, 0 }, + { "OrangeRed1", 255, 69, 0 }, + { "OrangeRed2", 238, 64, 0 }, + { "OrangeRed3", 205, 55, 0 }, + { "OrangeRed4", 139, 37, 0 }, + { "orchid", 218, 112, 214 }, + { "orchid1", 255, 131, 250 }, + { "orchid2", 238, 122, 233 }, + { "orchid3", 205, 105, 201 }, + { "orchid4", 139, 71, 137 }, + { "pale goldenrod", 238, 232, 170 }, + { "pale green", 152, 251, 152 }, + { "pale turquoise", 175, 238, 238 }, + { "pale violet red", 219, 112, 147 }, + { "PaleGoldenrod", 238, 232, 170 }, + { "PaleGreen", 152, 251, 152 }, + { "PaleGreen1", 154, 255, 154 }, + { "PaleGreen2", 144, 238, 144 }, + { "PaleGreen3", 124, 205, 124 }, + { "PaleGreen4", 84, 139, 84 }, + { "PaleTurquoise", 175, 238, 238 }, + { "PaleTurquoise1", 187, 255, 255 }, + { "PaleTurquoise2", 174, 238, 238 }, + { "PaleTurquoise3", 150, 205, 205 }, + { "PaleTurquoise4", 102, 139, 139 }, + { "PaleVioletRed", 219, 112, 147 }, + { "PaleVioletRed1", 255, 130, 171 }, + { "PaleVioletRed2", 238, 121, 159 }, + { "PaleVioletRed3", 205, 104, 137 }, + { "PaleVioletRed4", 139, 71, 93 }, + { "papaya whip", 255, 239, 213 }, + { "PapayaWhip", 255, 239, 213 }, + { "peach puff", 255, 218, 185 }, + { "PeachPuff", 255, 218, 185 }, + { "PeachPuff1", 255, 218, 185 }, + { "PeachPuff2", 238, 203, 173 }, + { "PeachPuff3", 205, 175, 149 }, + { "PeachPuff4", 139, 119, 101 }, + { "peru", 205, 133, 63 }, + { "pink", 255, 192, 203 }, + { "pink1", 255, 181, 197 }, + { "pink2", 238, 169, 184 }, + { "pink3", 205, 145, 158 }, + { "pink4", 139, 99, 108 }, + { "plum", 221, 160, 221 }, + { "plum1", 255, 187, 255 }, + { "plum2", 238, 174, 238 }, + { "plum3", 205, 150, 205 }, + { "plum4", 139, 102, 139 }, + { "powder blue", 176, 224, 230 }, + { "PowderBlue", 176, 224, 230 }, + { "purple", 160, 32, 240 }, + { "purple1", 155, 48, 255 }, + { "purple2", 145, 44, 238 }, + { "purple3", 125, 38, 205 }, + { "purple4", 85, 26, 139 }, + { "red", 255, 0, 0 }, + { "red1", 255, 0, 0 }, + { "red2", 238, 0, 0 }, + { "red3", 205, 0, 0 }, + { "red4", 139, 0, 0 }, + { "rosy brown", 188, 143, 143 }, + { "RosyBrown", 188, 143, 143 }, + { "RosyBrown1", 255, 193, 193 }, + { "RosyBrown2", 238, 180, 180 }, + { "RosyBrown3", 205, 155, 155 }, + { "RosyBrown4", 139, 105, 105 }, + { "royal blue", 65, 105, 225 }, + { "RoyalBlue", 65, 105, 225 }, + { "RoyalBlue1", 72, 118, 255 }, + { "RoyalBlue2", 67, 110, 238 }, + { "RoyalBlue3", 58, 95, 205 }, + { "RoyalBlue4", 39, 64, 139 }, + { "saddle brown", 139, 69, 19 }, + { "SaddleBrown", 139, 69, 19 }, + { "salmon", 250, 128, 114 }, + { "salmon1", 255, 140, 105 }, + { "salmon2", 238, 130, 98 }, + { "salmon3", 205, 112, 84 }, + { "salmon4", 139, 76, 57 }, + { "sandy brown", 244, 164, 96 }, + { "SandyBrown", 244, 164, 96 }, + { "sea green", 46, 139, 87 }, + { "SeaGreen", 46, 139, 87 }, + { "SeaGreen1", 84, 255, 159 }, + { "SeaGreen2", 78, 238, 148 }, + { "SeaGreen3", 67, 205, 128 }, + { "SeaGreen4", 46, 139, 87 }, + { "seashell", 255, 245, 238 }, + { "seashell1", 255, 245, 238 }, + { "seashell2", 238, 229, 222 }, + { "seashell3", 205, 197, 191 }, + { "seashell4", 139, 134, 130 }, + { "sienna", 160, 82, 45 }, + { "sienna1", 255, 130, 71 }, + { "sienna2", 238, 121, 66 }, + { "sienna3", 205, 104, 57 }, + { "sienna4", 139, 71, 38 }, + { "sky blue", 135, 206, 235 }, + { "SkyBlue", 135, 206, 235 }, + { "SkyBlue1", 135, 206, 255 }, + { "SkyBlue2", 126, 192, 238 }, + { "SkyBlue3", 108, 166, 205 }, + { "SkyBlue4", 74, 112, 139 }, + { "slate blue", 106, 90, 205 }, + { "slate gray", 112, 128, 144 }, + { "slate grey", 112, 128, 144 }, + { "SlateBlue", 106, 90, 205 }, + { "SlateBlue1", 131, 111, 255 }, + { "SlateBlue2", 122, 103, 238 }, + { "SlateBlue3", 105, 89, 205 }, + { "SlateBlue4", 71, 60, 139 }, + { "SlateGray", 112, 128, 144 }, + { "SlateGray1", 198, 226, 255 }, + { "SlateGray2", 185, 211, 238 }, + { "SlateGray3", 159, 182, 205 }, + { "SlateGray4", 108, 123, 139 }, + { "SlateGrey", 112, 128, 144 }, + { "snow", 255, 250, 250 }, + { "snow1", 255, 250, 250 }, + { "snow2", 238, 233, 233 }, + { "snow3", 205, 201, 201 }, + { "snow4", 139, 137, 137 }, + { "spring green", 0, 255, 127 }, + { "SpringGreen", 0, 255, 127 }, + { "SpringGreen1", 0, 255, 127 }, + { "SpringGreen2", 0, 238, 118 }, + { "SpringGreen3", 0, 205, 102 }, + { "SpringGreen4", 0, 139, 69 }, + { "steel blue", 70, 130, 180 }, + { "SteelBlue", 70, 130, 180 }, + { "SteelBlue1", 99, 184, 255 }, + { "SteelBlue2", 92, 172, 238 }, + { "SteelBlue3", 79, 148, 205 }, + { "SteelBlue4", 54, 100, 139 }, + { "tan", 210, 180, 140 }, + { "tan1", 255, 165, 79 }, + { "tan2", 238, 154, 73 }, + { "tan3", 205, 133, 63 }, + { "tan4", 139, 90, 43 }, + { "thistle", 216, 191, 216 }, + { "thistle1", 255, 225, 255 }, + { "thistle2", 238, 210, 238 }, + { "thistle3", 205, 181, 205 }, + { "thistle4", 139, 123, 139 }, + { "tomato", 255, 99, 71 }, + { "tomato1", 255, 99, 71 }, + { "tomato2", 238, 92, 66 }, + { "tomato3", 205, 79, 57 }, + { "tomato4", 139, 54, 38 }, + { "turquoise", 64, 224, 208 }, + { "turquoise1", 0, 245, 255 }, + { "turquoise2", 0, 229, 238 }, + { "turquoise3", 0, 197, 205 }, + { "turquoise4", 0, 134, 139 }, + { "violet", 238, 130, 238 }, + { "violet red", 208, 32, 144 }, + { "VioletRed", 208, 32, 144 }, + { "VioletRed1", 255, 62, 150 }, + { "VioletRed2", 238, 58, 140 }, + { "VioletRed3", 205, 50, 120 }, + { "VioletRed4", 139, 34, 82 }, + { "wheat", 245, 222, 179 }, + { "wheat1", 255, 231, 186 }, + { "wheat2", 238, 216, 174 }, + { "wheat3", 205, 186, 150 }, + { "wheat4", 139, 126, 102 }, + { "white", 255, 255, 255 }, + { "white smoke", 245, 245, 245 }, + { "WhiteSmoke", 245, 245, 245 }, + { "yellow", 255, 255, 0 }, + { "yellow green", 154, 205, 50 }, + { "yellow1", 255, 255, 0 }, + { "yellow2", 238, 238, 0 }, + { "yellow3", 205, 205, 0 }, + { "yellow4", 139, 139, 0 }, + { "YellowGreen", 154, 205, 50 } +}; + +#define numXColors (sizeof (xColors) / sizeof (*xColors)) + +/* + *---------------------------------------------------------------------- + * + * FindColor -- + * + * This routine finds the color entry that corresponds to the + * specified color. + * + * Results: + * Returns non-zero on success. The RGB values of the XColor + * will be initialized to the proper values on success. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +static int +compare_xcolor_entries (const void *a, const void *b) +{ + return strcasecmp ((const char *) a, ((const XColorEntry *) b)->name); +} + +static int +FindColor(const char *name, + GdkColor *colorPtr) +{ + XColorEntry *found; + + found = bsearch (name, xColors, numXColors, sizeof (XColorEntry), + compare_xcolor_entries); + if (found == NULL) + return 0; + + colorPtr->red = (found->red * 65535) / 255; + colorPtr->green = (found->green * 65535) / 255; + colorPtr->blue = (found->blue * 65535) / 255; + return 1; +} + +/* + *---------------------------------------------------------------------- + * + * parse_color -- + * + * Partial implementation of X color name parsing interface. + * + * Results: + * Returns non-zero on success. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +gboolean +parse_color(Colormap map, + const char *spec, + GdkColor *colorPtr) +{ + if (spec[0] == '#') { + char fmt[16]; + int i, red, green, blue; + + if ((i = strlen(spec+1))%3) { + return 0; + } + i /= 3; + + sprintf(fmt, "%%%dx%%%dx%%%dx", i, i, i); + if (sscanf(spec+1, fmt, &red, &green, &blue) != 3) { + return 0; + } + if (i == 4) + { + colorPtr->red = red; + colorPtr->green = green; + colorPtr->blue = blue; + } + else if (i == 1) + { + colorPtr->red = (red * 65535) / 15; + colorPtr->green = (green * 65535) / 15; + colorPtr->blue = (blue * 65535) / 15; + } + else if (i == 2) + { + colorPtr->red = (red * 65535) / 255; + colorPtr->green = (green * 65535) / 255; + colorPtr->blue = (blue * 65535) / 255; + } + else /* if (i == 3) */ + { + colorPtr->red = (red * 65535) / 4095; + colorPtr->green = (green * 65535) / 4095; + colorPtr->blue = (blue * 65535) / 4095; + } + } else { + if (!FindColor(spec, colorPtr)) { + return 0; + } + } + return 1; +} + +/* End of code from Tk8.0 */ + +static Colormap +DefaultColormap () +{ + static Colormap colormap; + gint i; + + if (colormap) + return colormap; + + colormap = create_colormap ( NULL, NULL, AllocNone); + return colormap; +} + + +GdkColormap* +gdk_colormap_new (GdkVisual *visual, + gint private_cmap) +{ + GdkColormap *colormap; + GdkColormapPrivate *private; + Visual *xvisual; + int size; + unsigned int i; + + g_return_val_if_fail (visual != NULL, NULL); + + private = g_new (GdkColormapPrivate, 1); + colormap = (GdkColormap*) private; + + private->visual = visual; + private->ref_count = 1; + + private->hash = NULL; + private->last_sync_time = 0; + private->info = NULL; + + xvisual = ((GdkVisualPrivate*) visual)->xvisual; + + colormap->size = visual->colormap_size; + colormap->colors = g_new (GdkColor, colormap->size); + + switch (visual->type) + { + case GDK_VISUAL_GRAYSCALE: + case GDK_VISUAL_PSEUDO_COLOR: + private->info = g_new0 (GdkColorInfo, colormap->size); + colormap->colors = g_new (GdkColor, colormap->size); + + private->hash = g_hash_table_new ((GHashFunc) gdk_color_hash, + (GCompareFunc) gdk_color_equal); + + private->private_val = private_cmap; + private->xcolormap = create_colormap (gdk_root_window, xvisual, + (private_cmap) ? (AllocAll) : (AllocNone)); + + if (private_cmap) + { + PALETTEENTRY pal[256]; + guint npal; + + npal = GetPaletteEntries (private->xcolormap->palette, 0, colormap->size, pal); + for (i = 0; i < colormap->size; i++) + { + colormap->colors[i].pixel = i; + if (i >= npal) + { + colormap->colors[i].red = + colormap->colors[i].green = + colormap->colors[i].blue = 0; + } + else + { + colormap->colors[i].red = (pal[i].peRed * 65535) / 255; + colormap->colors[i].green = (pal[i].peGreen * 65525) / 255; + colormap->colors[i].blue = (pal[i].peBlue * 65535) / 255; + } + } + gdk_colormap_change (colormap, colormap->size); + } + break; + + case GDK_VISUAL_STATIC_GRAY: + case GDK_VISUAL_STATIC_COLOR: + case GDK_VISUAL_TRUE_COLOR: + private->private_val = FALSE; + private->xcolormap = create_colormap (gdk_root_window, + xvisual, AllocNone); + break; + } + + gdk_colormap_add (colormap); + + return colormap; +} + +static void +gdk_colormap_real_destroy (GdkColormap *colormap) +{ + GdkColormapPrivate *private = (GdkColormapPrivate*) colormap; + + g_return_if_fail (colormap != NULL); + g_return_if_fail (private->ref_count == 0); + + gdk_colormap_remove (colormap); + XFreeColormap (private->xcolormap); + + if (private->hash) + g_hash_table_destroy (private->hash); + + g_free (private->info); + g_free (colormap->colors); + g_free (colormap); +} + +GdkColormap* +gdk_colormap_ref (GdkColormap *cmap) +{ + GdkColormapPrivate *private = (GdkColormapPrivate *)cmap; + + g_return_val_if_fail (cmap != NULL, NULL); + + private->ref_count += 1; + return cmap; +} + +void +gdk_colormap_unref (GdkColormap *cmap) +{ + GdkColormapPrivate *private = (GdkColormapPrivate *)cmap; + + g_return_if_fail (cmap != NULL); + g_return_if_fail (private->ref_count > 0); + + private->ref_count -= 1; + if (private->ref_count == 0) + gdk_colormap_real_destroy (cmap); +} + +#define MIN_SYNC_TIME 2 + +GdkVisual * +gdk_colormap_get_visual (GdkColormap *colormap) +{ + GdkColormapPrivate *private; + + g_return_val_if_fail (colormap != NULL, NULL); + + private = (GdkColormapPrivate *)colormap; + + return private->visual; +} + +void +gdk_colormap_sync (GdkColormap *colormap, + gboolean force) +{ + time_t current_time; + GdkColormapPrivate *private = (GdkColormapPrivate *)colormap; + XColor *xpalette; + gint nlookup; + gint i; + + g_return_if_fail (colormap != NULL); + + current_time = time (NULL); + if (!force && ((current_time - private->last_sync_time) < MIN_SYNC_TIME)) + return; + + private->last_sync_time = current_time; + + nlookup = 0; + xpalette = g_new (XColor, colormap->size); + + nlookup = GetPaletteEntries (private->xcolormap->palette, + 0, colormap->size, xpalette); + + for (i = 0; i < nlookup; i++) + { + colormap->colors[i].pixel = i; + colormap->colors[i].red = (xpalette[i].peRed * 65535) / 255; + colormap->colors[i].green = (xpalette[i].peGreen * 65535) / 255; + colormap->colors[i].blue = (xpalette[i].peBlue * 65535) / 255; + } + + g_free (xpalette); +} + + +GdkColormap* +gdk_colormap_get_system (void) +{ + static GdkColormap *colormap = NULL; + GdkColormapPrivate *private; + gint i; + + if (!colormap) + { + private = g_new (GdkColormapPrivate, 1); + colormap = (GdkColormap*) private; + + private->xcolormap = DefaultColormap (); + private->visual = gdk_visual_get_system (); + private->private_val = FALSE; + private->ref_count = 1; + + private->hash = NULL; + private->last_sync_time = 0; + private->info = NULL; + + colormap->colors = NULL; + colormap->size = private->visual->colormap_size; + + if ((private->visual->type == GDK_VISUAL_GRAYSCALE) || + (private->visual->type == GDK_VISUAL_PSEUDO_COLOR)) + { + private->info = g_new0 (GdkColorInfo, colormap->size); + colormap->colors = g_new (GdkColor, colormap->size); + + private->hash = g_hash_table_new ((GHashFunc) gdk_color_hash, + (GCompareFunc) gdk_color_equal); + + gdk_colormap_sync (colormap, TRUE); + } + gdk_colormap_add (colormap); + } + + return colormap; +} + +gint +gdk_colormap_get_system_size (void) +{ + gint bitspixel; + + bitspixel = GetDeviceCaps (gdk_DC, BITSPIXEL); + + if (bitspixel == 1) + return 2; + else if (bitspixel == 4) + return 16; + else if (bitspixel == 8) + return 256; + else if (bitspixel == 12) + return 32; + else if (bitspixel == 16) + return 64; + else /* if (bitspixel >= 24) */ + return 256; +} + +void +gdk_colormap_change (GdkColormap *colormap, + gint ncolors) +{ + GdkColormapPrivate *private; + GdkVisual *visual; + XColor *palette; + gint shift; + int max_colors; + int size; + int i; + + g_return_if_fail (colormap != NULL); + + palette = g_new (XColor, ncolors); + + private = (GdkColormapPrivate*) colormap; + switch (private->visual->type) + { + case GDK_VISUAL_GRAYSCALE: + case GDK_VISUAL_PSEUDO_COLOR: + for (i = 0; i < ncolors; i++) + { + palette[i].peRed = (colormap->colors[i].red >> 8); + palette[i].peGreen = (colormap->colors[i].green >> 8); + palette[i].peBlue = (colormap->colors[i].blue >> 8); + palette[i].peFlags = 0; + } + + if (SetPaletteEntries (private->xcolormap->palette, + 0, ncolors, palette) == 0) + g_warning ("gdk_colormap_change: SetPaletteEntries failed"); + private->xcolormap->stale = TRUE; + break; + + default: + break; + } + + g_free (palette); +} + +void +gdk_colors_store (GdkColormap *colormap, + GdkColor *colors, + gint ncolors) +{ + gint i; + + for (i = 0; i < ncolors; i++) + { + colormap->colors[i].pixel = colors[i].pixel; + colormap->colors[i].red = colors[i].red; + colormap->colors[i].green = colors[i].green; + colormap->colors[i].blue = colors[i].blue; + } + + gdk_colormap_change (colormap, ncolors); +} + +gboolean +gdk_colors_alloc (GdkColormap *colormap, + gint contiguous, + gulong *planes, + gint nplanes, + gulong *pixels, + gint npixels) +{ + GdkColormapPrivate *private; + gint return_val; + gint i; + + g_return_val_if_fail (colormap != NULL, 0); + + private = (GdkColormapPrivate*) colormap; + + return_val = alloc_color_cells (private->xcolormap, contiguous, + planes, nplanes, pixels, npixels); + + if (return_val) + { + for (i=0; i<npixels; i++) + { + private->info[pixels[i]].ref_count++; + private->info[pixels[i]].flags |= GDK_COLOR_WRITEABLE; + } + } + + return return_val; +} + +/* This is almost identical to gdk_colormap_free_colors. + * Keep them in sync! + */ +void +gdk_colors_free (GdkColormap *colormap, + gulong *in_pixels, + gint in_npixels, + gulong planes) +{ + GdkColormapPrivate *private; + gulong *pixels; + gint npixels = 0; + gint i; + + g_return_if_fail (colormap != NULL); + g_return_if_fail (in_pixels != NULL); + + private = (GdkColormapPrivate*) colormap; + + if ((private->visual->type != GDK_VISUAL_PSEUDO_COLOR) && + (private->visual->type != GDK_VISUAL_GRAYSCALE)) + return; + + pixels = g_new (gulong, in_npixels); + + for (i=0; i<in_npixels; i++) + { + gulong pixel = in_pixels[i]; + + if (private->info[pixel].ref_count) + { + private->info[pixel].ref_count--; + + if (private->info[pixel].ref_count == 0) + { + pixels[npixels++] = pixel; + if (!(private->info[pixel].flags & GDK_COLOR_WRITEABLE)) + g_hash_table_remove (private->hash, &colormap->colors[in_pixels[i]]); + private->info[pixel].flags = 0; + } + } + } + + + if (npixels) + XFreeColors (private->xcolormap, pixels, npixels, planes); + + g_free (pixels); +} + +/* + *-------------------------------------------------------------- + * gdk_color_copy + * + * Copy a color structure into new storage. + * + * Arguments: + * "color" is the color struct to copy. + * + * Results: + * A new color structure. Free it with gdk_color_free. + * + *-------------------------------------------------------------- + */ + +static GMemChunk *color_chunk; + +GdkColor* +gdk_color_copy (GdkColor *color) +{ + GdkColor *new_color; + + g_return_val_if_fail (color != NULL, NULL); + + if (color_chunk == NULL) + color_chunk = g_mem_chunk_new ("colors", + sizeof (GdkColor), + 4096, + G_ALLOC_AND_FREE); + + new_color = g_chunk_new (GdkColor, color_chunk); + *new_color = *color; + return new_color; +} + +/* + *-------------------------------------------------------------- + * gdk_color_free + * + * Free a color structure obtained from gdk_color_copy. Do not use + * with other color structures. + * + * Arguments: + * "color" is the color struct to free. + * + *-------------------------------------------------------------- */ + +void +gdk_color_free (GdkColor *color) +{ + g_assert (color_chunk != NULL); + g_return_if_fail (color != NULL); + + g_mem_chunk_free (color_chunk, color); +} + +gint +gdk_color_white (GdkColormap *colormap, + GdkColor *color) +{ + gint return_val; + + g_return_val_if_fail (colormap != NULL, FALSE); + + if (color) + { + color->red = 65535; + color->green = 65535; + color->blue = 65535; + + return_val = gdk_color_alloc (colormap, color); + } + else + return_val = FALSE; + + return return_val; +} + +gint +gdk_color_black (GdkColormap *colormap, + GdkColor *color) +{ + gint return_val; + + g_return_val_if_fail (colormap != NULL, FALSE); + + if (color) + { + color->red = 0; + color->green = 0; + color->blue = 0; + + return_val = gdk_color_alloc (colormap, color); + } + else + return_val = FALSE; + + return return_val; +} + +gboolean +gdk_color_parse (const gchar *spec, + GdkColor *color) +{ + Colormap xcolormap; + XColor xcolor; + gboolean return_val; + + g_return_val_if_fail (spec != NULL, FALSE); + g_return_val_if_fail (color != NULL, FALSE); + + xcolormap = DefaultColormap (); + + if (parse_color (xcolormap, spec, color)) + return_val = TRUE; + else + return_val = FALSE; + + return return_val; +} + +/******************** + * Color allocation * + ********************/ + +/* Try to allocate a single color using alloc_color. If it succeeds, + * cache the result in our colormap, and store in ret. + */ +static gboolean +gdk_colormap_alloc1 (GdkColormap *colormap, + GdkColor *color, + GdkColor *ret) +{ + GdkColormapPrivate *private; + XColor xcolor; + + private = (GdkColormapPrivate*) colormap; + + xcolor.peRed = color->red >> 8; + xcolor.peGreen = color->green >> 8; + xcolor.peBlue = color->blue >> 8; + + if (alloc_color (private->xcolormap, &xcolor, &ret->pixel)) + { + ret->red = (xcolor.peRed * 65535) / 255; + ret->green = (xcolor.peGreen * 65535) / 255;; + ret->blue = (xcolor.peBlue * 65535) / 255; + + if ((guint) ret->pixel < colormap->size) + { + if (private->info[ret->pixel].ref_count) /* got a duplicate */ + { + /* XXX */ + } + else + { + colormap->colors[ret->pixel] = *color; + private->info[ret->pixel].ref_count = 1; + + g_hash_table_insert (private->hash, + &colormap->colors[ret->pixel], + &colormap->colors[ret->pixel]); + } + } + return TRUE; + } + else + { + return FALSE; + } +} + +static gint +gdk_colormap_alloc_colors_writeable (GdkColormap *colormap, + GdkColor *colors, + gint ncolors, + gboolean writeable, + gboolean best_match, + gboolean *success) +{ + GdkColormapPrivate *private; + gulong *pixels; + Status status; + gint i, index; + + private = (GdkColormapPrivate*) colormap; + + if (private->private_val) + { + index = 0; + for (i=0; i<ncolors; i++) + { + while ((index < colormap->size) && (private->info[index].ref_count != 0)) + index++; + + if (index < colormap->size) + { + colors[i].pixel = index; + success[i] = TRUE; + private->info[index].ref_count++; + private->info[i].flags |= GDK_COLOR_WRITEABLE; + } + else + break; + } + return i; + } + else + { + pixels = g_new (gulong, ncolors); + + /* Allocation of a writeable color cells */ + status = alloc_color_cells (private->xcolormap, FALSE, NULL, + 0, pixels, ncolors); + if (status) + { + for (i=0; i<ncolors; i++) + { + colors[i].pixel = pixels[i]; + private->info[pixels[i]].ref_count++; + private->info[pixels[i]].flags |= GDK_COLOR_WRITEABLE; + } + } + + g_free (pixels); + + return status ? ncolors : 0; + } +} + +static gint +gdk_colormap_alloc_colors_private (GdkColormap *colormap, + GdkColor *colors, + gint ncolors, + gboolean writeable, + gboolean best_match, + gboolean *success) +{ + GdkColormapPrivate *private; + gint i, index; + XColor *store = g_new (XColor, ncolors); + gint nstore = 0; + gint nremaining = 0; + + private = (GdkColormapPrivate*) colormap; + index = -1; + + /* First, store the colors we have room for */ + + index = 0; + for (i=0; i<ncolors; i++) + { + if (!success[i]) + { + while ((index < colormap->size) && (private->info[index].ref_count != 0)) + index++; + + if (index < colormap->size) + { + store[nstore].peRed = colors[i].red >> 8; + store[nstore].peBlue = colors[i].blue >> 8; + store[nstore].peGreen = colors[i].green >> 8; + nstore++; + + success[i] = TRUE; + + colors[i].pixel = index; + private->info[index].ref_count++; + } + else + nremaining++; + } + } + + if (SetPaletteEntries (private->xcolormap->palette, + 0, nstore, store) == 0) + g_warning ("gdk_colormap_alloc_colors_private: SetPaletteEntries failed"); + private->xcolormap->stale = TRUE; + + g_free (store); + + if (nremaining > 0 && best_match) + { + /* Get best matches for remaining colors */ + + gchar *available = g_new (gchar, colormap->size); + for (i = 0; i < colormap->size; i++) + available[i] = TRUE; + + for (i=0; i<ncolors; i++) + { + if (!success[i]) + { + index = gdk_colormap_match_color (colormap, + &colors[i], + available); + if (index != -1) + { + colors[i] = colormap->colors[index]; + private->info[index].ref_count++; + success[i] = TRUE; + nremaining--; + } + } + } + g_free (available); + } + + return (ncolors - nremaining); +} + +static gint +gdk_colormap_alloc_colors_shared (GdkColormap *colormap, + GdkColor *colors, + gint ncolors, + gboolean writeable, + gboolean best_match, + gboolean *success) +{ + GdkColormapPrivate *private; + gint i, index; + gint nremaining = 0; + gint nfailed = 0; + + private = (GdkColormapPrivate*) colormap; + index = -1; + + for (i=0; i<ncolors; i++) + { + if (!success[i]) + { + if (gdk_colormap_alloc1 (colormap, &colors[i], &colors[i])) + success[i] = TRUE; + else + nremaining++; + } + } + + + if (nremaining > 0 && best_match) + { + gchar *available = g_new (gchar, colormap->size); + for (i = 0; i < colormap->size; i++) + available[i] = ((private->info[i].ref_count == 0) || + !(private->info[i].flags && GDK_COLOR_WRITEABLE)); + gdk_colormap_sync (colormap, FALSE); + + while (nremaining > 0) + { + for (i=0; i<ncolors; i++) + { + if (!success[i]) + { + index = gdk_colormap_match_color (colormap, &colors[i], available); + if (index != -1) + { + if (private->info[index].ref_count) + { + private->info[index].ref_count++; + colors[i] = colormap->colors[index]; + success[i] = TRUE; + nremaining--; + } + else + { + if (gdk_colormap_alloc1 (colormap, + &colormap->colors[index], + &colors[i])) + { + success[i] = TRUE; + nremaining--; + break; + } + else + { + available[index] = FALSE; + } + } + } + else + { + nfailed++; + nremaining--; + success[i] = 2; /* flag as permanent failure */ + } + } + } + } + g_free (available); + } + + /* Change back the values we flagged as permanent failures */ + if (nfailed > 0) + { + for (i=0; i<ncolors; i++) + if (success[i] == 2) + success[i] = FALSE; + nremaining = nfailed; + } + + return (ncolors - nremaining); +} + +static gint +gdk_colormap_alloc_colors_pseudocolor (GdkColormap *colormap, + GdkColor *colors, + gint ncolors, + gboolean writeable, + gboolean best_match, + gboolean *success) +{ + GdkColormapPrivate *private; + GdkColor *lookup_color; + gint i; + gint nremaining = 0; + + private = (GdkColormapPrivate*) colormap; + + /* Check for an exact match among previously allocated colors */ + + for (i=0; i<ncolors; i++) + { + if (!success[i]) + { + lookup_color = g_hash_table_lookup (private->hash, &colors[i]); + if (lookup_color) + { + private->info[lookup_color->pixel].ref_count++; + colors[i].pixel = lookup_color->pixel; + success[i] = TRUE; + } + else + nremaining++; + } + } + + /* If that failed, we try to allocate a new color, or approxmiate + * with what we can get if best_match is TRUE. + */ + if (nremaining > 0) + { + if (private->private_val) + return gdk_colormap_alloc_colors_private (colormap, colors, ncolors, writeable, best_match, success); + else + return gdk_colormap_alloc_colors_shared (colormap, colors, ncolors, writeable, best_match, success); + } + else + return 0; +} + +gint +gdk_colormap_alloc_colors (GdkColormap *colormap, + GdkColor *colors, + gint ncolors, + gboolean writeable, + gboolean best_match, + gboolean *success) +{ + GdkColormapPrivate *private; + GdkVisual *visual; + gint i; + gint nremaining = 0; + XColor xcolor; + + g_return_val_if_fail (colormap != NULL, FALSE); + g_return_val_if_fail (colors != NULL, FALSE); + + private = (GdkColormapPrivate*) colormap; + + for (i=0; i<ncolors; i++) + { + success[i] = FALSE; + } + + switch (private->visual->type) + { + case GDK_VISUAL_PSEUDO_COLOR: + case GDK_VISUAL_GRAYSCALE: + if (writeable) + return gdk_colormap_alloc_colors_writeable (colormap, colors, ncolors, + writeable, best_match, success); + else + return gdk_colormap_alloc_colors_pseudocolor (colormap, colors, ncolors, + writeable, best_match, success); + break; + + case GDK_VISUAL_TRUE_COLOR: + visual = private->visual; + + for (i=0; i<ncolors; i++) + { + colors[i].pixel = (((colors[i].red >> (16 - visual->red_prec)) << visual->red_shift) + + ((colors[i].green >> (16 - visual->green_prec)) << visual->green_shift) + + ((colors[i].blue >> (16 - visual->blue_prec)) << visual->blue_shift)); + success[i] = TRUE; + } + break; + + case GDK_VISUAL_STATIC_GRAY: + case GDK_VISUAL_STATIC_COLOR: + for (i=0; i<ncolors; i++) + { + xcolor.peRed = colors[i].red >> 8; + xcolor.peGreen = colors[i].green >> 8; + xcolor.peBlue = colors[i].blue >> 8; + if (alloc_color (private->xcolormap, &xcolor, &colors[i].pixel)) + success[i] = TRUE; + else + nremaining++; + } + break; + } + return nremaining; +} + +gboolean +gdk_colormap_alloc_color (GdkColormap *colormap, + GdkColor *color, + gboolean writeable, + gboolean best_match) +{ + gboolean success; + + GDK_NOTE (MISC, g_print ("gdk_colormap_alloc_color: (%.04x,%.04x,%.04x)", + color->red, color->green, color->blue)); + + gdk_colormap_alloc_colors (colormap, color, 1, writeable, best_match, + &success); + GDK_NOTE (MISC, g_print (" -> %.08x\n", color->pixel)); + + return success; +} + +/* This is almost identical to gdk_colors_free. + * Keep them in sync! + */ +void +gdk_colormap_free_colors (GdkColormap *colormap, + GdkColor *colors, + gint ncolors) +{ + GdkColormapPrivate *private; + gulong *pixels; + gint npixels = 0; + gint i; + + g_return_if_fail (colormap != NULL); + g_return_if_fail (colors != NULL); + + private = (GdkColormapPrivate*) colormap; + + if ((private->visual->type != GDK_VISUAL_PSEUDO_COLOR) && + (private->visual->type != GDK_VISUAL_GRAYSCALE)) + return; + + pixels = g_new (gulong, ncolors); + + for (i=0; i<ncolors; i++) + { + gulong pixel = colors[i].pixel; + + if (private->info[pixel].ref_count) + { + private->info[pixel].ref_count--; + + if (private->info[pixel].ref_count == 0) + { + pixels[npixels++] = pixel; + if (!(private->info[pixel].flags & GDK_COLOR_WRITEABLE)) + g_hash_table_remove (private->hash, &colors[i]); + private->info[pixel].flags = 0; + } + } + } + if (npixels) + XFreeColors (private->xcolormap, pixels, npixels, 0); + g_free (pixels); +} + +gboolean +gdk_color_alloc (GdkColormap *colormap, + GdkColor *color) +{ + gboolean success; + + GDK_NOTE (MISC, g_print ("gdk_color_alloc: (%.04x,%.04x,%.04x)", + color->red, color->green, color->blue)); + + gdk_colormap_alloc_colors (colormap, color, 1, FALSE, TRUE, &success); + + GDK_NOTE (MISC, g_print (" -> %.08x\n", color->pixel)); + + return success; +} + +gboolean +gdk_color_change (GdkColormap *colormap, + GdkColor *color) +{ + GdkColormapPrivate *private; + XColor xcolor; + + g_return_val_if_fail (colormap != NULL, FALSE); + g_return_val_if_fail (color != NULL, FALSE); + + private = (GdkColormapPrivate*) colormap; + + xcolor.peRed = color->red >> 8; + xcolor.peGreen = color->green >> 8; + xcolor.peBlue = color->blue >> 8; + + if (SetPaletteEntries (private->xcolormap->palette, + color->pixel, 1, &xcolor) == 0) + g_warning ("gdk_color_change: SetPaletteEntries failed"); + private->xcolormap->stale = TRUE; + + return TRUE; +} + +guint +gdk_color_hash (const GdkColor *colora) +{ + return ((colora->red) + + (colora->green << 11) + + (colora->blue << 22) + + (colora->blue >> 6)); +} + +gint +gdk_color_equal (const GdkColor *colora, + const GdkColor *colorb) +{ + g_return_val_if_fail (colora != NULL, FALSE); + g_return_val_if_fail (colorb != NULL, FALSE); + + return ((colora->red == colorb->red) && + (colora->green == colorb->green) && + (colora->blue == colorb->blue)); +} + +static gint +gdk_colormap_match_color (GdkColormap *cmap, + GdkColor *color, + const gchar *available) +{ + GdkColor *colors; + guint sum, max; + gint rdiff, gdiff, bdiff; + gint i, index; + + g_return_val_if_fail (cmap != NULL, 0); + g_return_val_if_fail (color != NULL, 0); + + colors = cmap->colors; + max = 3 * (65536); + index = -1; + + for (i = 0; i < cmap->size; i++) + { + if ((!available) || (available && available[i])) + { + rdiff = (color->red - colors[i].red); + gdiff = (color->green - colors[i].green); + bdiff = (color->blue - colors[i].blue); + + sum = ABS (rdiff) + ABS (gdiff) + ABS (bdiff); + + if (sum < max) + { + index = i; + max = sum; + } + } + } + + return index; +} + +GdkColormap* +gdk_colormap_lookup (Colormap xcolormap) +{ + GdkColormap *cmap; + + if (!colormap_hash) + return NULL; + + cmap = g_hash_table_lookup (colormap_hash, &xcolormap); + return cmap; +} + +static void +gdk_colormap_add (GdkColormap *cmap) +{ + GdkColormapPrivate *private; + + if (!colormap_hash) + colormap_hash = g_hash_table_new ((GHashFunc) gdk_colormap_hash, + (GCompareFunc) gdk_colormap_cmp); + + private = (GdkColormapPrivate*) cmap; + + g_hash_table_insert (colormap_hash, &private->xcolormap, cmap); +} + +static void +gdk_colormap_remove (GdkColormap *cmap) +{ + GdkColormapPrivate *private; + + if (!colormap_hash) + colormap_hash = g_hash_table_new ((GHashFunc) gdk_colormap_hash, + (GCompareFunc) gdk_colormap_cmp); + + private = (GdkColormapPrivate*) cmap; + + g_hash_table_remove (colormap_hash, &private->xcolormap); +} + +static guint +gdk_colormap_hash (Colormap *cmap) +{ + return (guint) *cmap; +} + +static gint +gdk_colormap_cmp (Colormap *a, + Colormap *b) +{ + return (*a == *b); +} + +char * +gdk_color_to_string (GdkColor *color) +{ + static char buf[100]; + + sprintf (buf, "(%.04x,%.04x,%.04x): %.06x", + color->red, color->green, color->blue, color->pixel); + + return buf; +} diff --git a/gdk/win32/gdkcursor-win32.c b/gdk/win32/gdkcursor-win32.c new file mode 100644 index 000000000..8a293d1a5 --- /dev/null +++ b/gdk/win32/gdkcursor-win32.c @@ -0,0 +1,226 @@ +/* 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. + */ + +#include "config.h" + +#include "gdk.h" +#include "gdkprivate.h" + +static const struct { const char *name; int type; } cursors[] = { + { "x_cursor", 0 }, + { "arrow", 2 }, + { "based_arrow_down", 4 }, + { "based_arrow_up", 6 }, + { "boat", 8 }, + { "bogosity", 10 }, + { "bottom_left_corner", 12 }, + { "bottom_right_corner", 14 }, + { "bottom_side", 16 }, + { "bottom_tee", 18 }, + { "box_spiral", 20 }, + { "center_ptr", 22 }, + { "circle", 24 }, + { "clock", 26 }, + { "coffee_mug", 28 }, + { "cross", 30 }, + { "cross_reverse", 32 }, + { "crosshair", 34 }, + { "diamond_cross", 36 }, + { "dot", 38 }, + { "dotbox", 40 }, + { "double_arrow", 42 }, + { "draft_large", 44 }, + { "draft_small", 46 }, + { "draped_box", 48 }, + { "exchange", 50 }, + { "fleur", 52 }, + { "gobbler", 54 }, + { "gumby", 56 }, + { "hand1", 58 }, + { "hand2", 60 }, + { "heart", 62 }, + { "icon", 64 }, + { "iron_cross", 66 }, + { "left_ptr", 68 }, + { "left_side", 70 }, + { "left_tee", 72 }, + { "leftbutton", 74 }, + { "ll_angle", 76 }, + { "lr_angle", 78 }, + { "man", 80 }, + { "middlebutton", 82 }, + { "mouse", 84 }, + { "pencil", 86 }, + { "pirate", 88 }, + { "plus", 90 }, + { "question_arrow", 92 }, + { "right_ptr", 94 }, + { "right_side", 96 }, + { "right_tee", 98 }, + { "rightbutton", 100 }, + { "rtl_logo", 102 }, + { "sailboat", 104 }, + { "sb_down_arrow", 106 }, + { "sb_h_double_arrow", 108 }, + { "sb_left_arrow", 110 }, + { "sb_right_arrow", 112 }, + { "sb_up_arrow", 114 }, + { "sb_v_double_arrow", 116 }, + { "shuttle", 118 }, + { "sizing", 120 }, + { "spider", 122 }, + { "spraycan", 124 }, + { "star", 126 }, + { "target", 128 }, + { "tcross", 130 }, + { "top_left_arrow", 132 }, + { "top_left_corner", 134 }, + { "top_right_corner", 136 }, + { "top_side", 138 }, + { "top_tee", 140 }, + { "trek", 142 }, + { "ul_angle", 144 }, + { "umbrella", 146 }, + { "ur_angle", 148 }, + { "watch", 150 }, + { "xterm", 152 }, + { NULL, 0 } +}; + +GdkCursor* +gdk_cursor_new (GdkCursorType cursor_type) +{ + GdkCursorPrivate *private; + GdkCursor *cursor; + HCURSOR xcursor; + + int i; + + for (i = 0; cursors[i].name != NULL && cursors[i].type != cursor_type; i++) + ; + if (cursors[i].name != NULL) + { + xcursor = LoadCursor (gdk_DLLInstance, cursors[i].name); + if (xcursor == NULL) + g_warning ("gdk_cursor_new: LoadCursor failed"); + GDK_NOTE (MISC, g_print ("gdk_cursor_new: %#x %d\n", + xcursor, cursor_type)); + } + else + { + g_warning ("gdk_cursor_new: no cursor %d found", + cursor_type); + xcursor = NULL; + } + + private = g_new (GdkCursorPrivate, 1); + private->xcursor = xcursor; + cursor = (GdkCursor*) private; + cursor->type = cursor_type; + + return cursor; +} + +GdkCursor* +gdk_cursor_new_from_pixmap (GdkPixmap *source, GdkPixmap *mask, GdkColor *fg, GdkColor *bg, gint x, gint y) +{ +#if 0 /* I don't understand cursors, sigh */ + GdkCursorPrivate *private; + GdkCursor *cursor; + GdkPixmap *s2; + GdkPixmapPrivate *source_private, *mask_private; + GdkPixmapPrivate *s2_private; + GdkGC *gc; + ICONINFO iconinfo; + HCURSOR xcursor; + HBITMAP invmask; + HDC hdc1, hdc2; + HGDIOBJ oldbm1, oldbm2; + + source_private = (GdkPixmapPrivate *) source; + mask_private = (GdkPixmapPrivate *) mask; + + s2 = gdk_pixmap_new (source, source_private->width, source_private->height, 1); + gc = gdk_gc_new (s2); + gdk_gc_set_foreground (gc, fg); + gdk_gc_set_background (gc, bg); + gdk_draw_pixmap (s2, gc, source, 0, 0, 0, 0, + source_private->width, source_private->height); + gdk_gc_unref (gc); + + iconinfo.fIcon = FALSE; + iconinfo.xHotspot = x; + iconinfo.yHotspot = y; +#if 1 + invmask = CreateBitmap (mask_private->width, mask_private->height, 1, 1, NULL); + hdc1 = CreateCompatibleDC (gdk_DC); + oldbm1 = SelectObject (hdc1, invmask); + hdc2 = CreateCompatibleDC (gdk_DC); + oldbm2 = SelectObject (hdc2, mask_private->xwindow); + BitBlt (hdc1, 0, 0, mask_private->width, mask_private->height, hdc2, 0, 0, NOTSRCCOPY); + SelectObject (hdc2, oldbm2); + DeleteDC (hdc2); + SelectObject (hdc1, oldbm1); + DeleteDC (hdc1); + iconinfo.hbmMask = invmask; +#else + iconinfo.hbmMask = mask_private->xwindow;; +#endif + iconinfo.hbmColor = ((GdkPixmapPrivate *) s2)->xwindow; + + if ((xcursor = CreateIconIndirect (&iconinfo)) == NULL) + { + g_warning ("gdk_cursor_new_from_private: CreateIconIndirect failed"); + gdk_pixmap_unref (s2); + return gdk_cursor_new (GDK_PIRATE); + } + + GDK_NOTE (MISC, + g_print ("gdk_cursor_new_from_private: %#x (%dx%d) %#x (%dx%d) = %#x\n", + source_private->xwindow, + source_private->width, source_private->height, + mask_private->xwindow, + mask_private->width, mask_private->height, + xcursor)); + + gdk_pixmap_unref (s2); + private = g_new (GdkCursorPrivate, 1); + private->xcursor = xcursor; + cursor = (GdkCursor*) private; + cursor->type = GDK_CURSOR_IS_PIXMAP; + + return cursor; +#else /* Just return some cursor ;-) */ + return gdk_cursor_new (GDK_PIRATE); +#endif +} + +void +gdk_cursor_destroy (GdkCursor *cursor) +{ + GdkCursorPrivate *private; + + g_return_if_fail (cursor != NULL); + private = (GdkCursorPrivate *) cursor; + + if (cursor->type == GDK_CURSOR_IS_PIXMAP) + DestroyIcon (private->xcursor); + + g_free (private); +} diff --git a/gdk/win32/gdkcursor.c b/gdk/win32/gdkcursor.c new file mode 100644 index 000000000..8a293d1a5 --- /dev/null +++ b/gdk/win32/gdkcursor.c @@ -0,0 +1,226 @@ +/* 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. + */ + +#include "config.h" + +#include "gdk.h" +#include "gdkprivate.h" + +static const struct { const char *name; int type; } cursors[] = { + { "x_cursor", 0 }, + { "arrow", 2 }, + { "based_arrow_down", 4 }, + { "based_arrow_up", 6 }, + { "boat", 8 }, + { "bogosity", 10 }, + { "bottom_left_corner", 12 }, + { "bottom_right_corner", 14 }, + { "bottom_side", 16 }, + { "bottom_tee", 18 }, + { "box_spiral", 20 }, + { "center_ptr", 22 }, + { "circle", 24 }, + { "clock", 26 }, + { "coffee_mug", 28 }, + { "cross", 30 }, + { "cross_reverse", 32 }, + { "crosshair", 34 }, + { "diamond_cross", 36 }, + { "dot", 38 }, + { "dotbox", 40 }, + { "double_arrow", 42 }, + { "draft_large", 44 }, + { "draft_small", 46 }, + { "draped_box", 48 }, + { "exchange", 50 }, + { "fleur", 52 }, + { "gobbler", 54 }, + { "gumby", 56 }, + { "hand1", 58 }, + { "hand2", 60 }, + { "heart", 62 }, + { "icon", 64 }, + { "iron_cross", 66 }, + { "left_ptr", 68 }, + { "left_side", 70 }, + { "left_tee", 72 }, + { "leftbutton", 74 }, + { "ll_angle", 76 }, + { "lr_angle", 78 }, + { "man", 80 }, + { "middlebutton", 82 }, + { "mouse", 84 }, + { "pencil", 86 }, + { "pirate", 88 }, + { "plus", 90 }, + { "question_arrow", 92 }, + { "right_ptr", 94 }, + { "right_side", 96 }, + { "right_tee", 98 }, + { "rightbutton", 100 }, + { "rtl_logo", 102 }, + { "sailboat", 104 }, + { "sb_down_arrow", 106 }, + { "sb_h_double_arrow", 108 }, + { "sb_left_arrow", 110 }, + { "sb_right_arrow", 112 }, + { "sb_up_arrow", 114 }, + { "sb_v_double_arrow", 116 }, + { "shuttle", 118 }, + { "sizing", 120 }, + { "spider", 122 }, + { "spraycan", 124 }, + { "star", 126 }, + { "target", 128 }, + { "tcross", 130 }, + { "top_left_arrow", 132 }, + { "top_left_corner", 134 }, + { "top_right_corner", 136 }, + { "top_side", 138 }, + { "top_tee", 140 }, + { "trek", 142 }, + { "ul_angle", 144 }, + { "umbrella", 146 }, + { "ur_angle", 148 }, + { "watch", 150 }, + { "xterm", 152 }, + { NULL, 0 } +}; + +GdkCursor* +gdk_cursor_new (GdkCursorType cursor_type) +{ + GdkCursorPrivate *private; + GdkCursor *cursor; + HCURSOR xcursor; + + int i; + + for (i = 0; cursors[i].name != NULL && cursors[i].type != cursor_type; i++) + ; + if (cursors[i].name != NULL) + { + xcursor = LoadCursor (gdk_DLLInstance, cursors[i].name); + if (xcursor == NULL) + g_warning ("gdk_cursor_new: LoadCursor failed"); + GDK_NOTE (MISC, g_print ("gdk_cursor_new: %#x %d\n", + xcursor, cursor_type)); + } + else + { + g_warning ("gdk_cursor_new: no cursor %d found", + cursor_type); + xcursor = NULL; + } + + private = g_new (GdkCursorPrivate, 1); + private->xcursor = xcursor; + cursor = (GdkCursor*) private; + cursor->type = cursor_type; + + return cursor; +} + +GdkCursor* +gdk_cursor_new_from_pixmap (GdkPixmap *source, GdkPixmap *mask, GdkColor *fg, GdkColor *bg, gint x, gint y) +{ +#if 0 /* I don't understand cursors, sigh */ + GdkCursorPrivate *private; + GdkCursor *cursor; + GdkPixmap *s2; + GdkPixmapPrivate *source_private, *mask_private; + GdkPixmapPrivate *s2_private; + GdkGC *gc; + ICONINFO iconinfo; + HCURSOR xcursor; + HBITMAP invmask; + HDC hdc1, hdc2; + HGDIOBJ oldbm1, oldbm2; + + source_private = (GdkPixmapPrivate *) source; + mask_private = (GdkPixmapPrivate *) mask; + + s2 = gdk_pixmap_new (source, source_private->width, source_private->height, 1); + gc = gdk_gc_new (s2); + gdk_gc_set_foreground (gc, fg); + gdk_gc_set_background (gc, bg); + gdk_draw_pixmap (s2, gc, source, 0, 0, 0, 0, + source_private->width, source_private->height); + gdk_gc_unref (gc); + + iconinfo.fIcon = FALSE; + iconinfo.xHotspot = x; + iconinfo.yHotspot = y; +#if 1 + invmask = CreateBitmap (mask_private->width, mask_private->height, 1, 1, NULL); + hdc1 = CreateCompatibleDC (gdk_DC); + oldbm1 = SelectObject (hdc1, invmask); + hdc2 = CreateCompatibleDC (gdk_DC); + oldbm2 = SelectObject (hdc2, mask_private->xwindow); + BitBlt (hdc1, 0, 0, mask_private->width, mask_private->height, hdc2, 0, 0, NOTSRCCOPY); + SelectObject (hdc2, oldbm2); + DeleteDC (hdc2); + SelectObject (hdc1, oldbm1); + DeleteDC (hdc1); + iconinfo.hbmMask = invmask; +#else + iconinfo.hbmMask = mask_private->xwindow;; +#endif + iconinfo.hbmColor = ((GdkPixmapPrivate *) s2)->xwindow; + + if ((xcursor = CreateIconIndirect (&iconinfo)) == NULL) + { + g_warning ("gdk_cursor_new_from_private: CreateIconIndirect failed"); + gdk_pixmap_unref (s2); + return gdk_cursor_new (GDK_PIRATE); + } + + GDK_NOTE (MISC, + g_print ("gdk_cursor_new_from_private: %#x (%dx%d) %#x (%dx%d) = %#x\n", + source_private->xwindow, + source_private->width, source_private->height, + mask_private->xwindow, + mask_private->width, mask_private->height, + xcursor)); + + gdk_pixmap_unref (s2); + private = g_new (GdkCursorPrivate, 1); + private->xcursor = xcursor; + cursor = (GdkCursor*) private; + cursor->type = GDK_CURSOR_IS_PIXMAP; + + return cursor; +#else /* Just return some cursor ;-) */ + return gdk_cursor_new (GDK_PIRATE); +#endif +} + +void +gdk_cursor_destroy (GdkCursor *cursor) +{ + GdkCursorPrivate *private; + + g_return_if_fail (cursor != NULL); + private = (GdkCursorPrivate *) cursor; + + if (cursor->type == GDK_CURSOR_IS_PIXMAP) + DestroyIcon (private->xcursor); + + g_free (private); +} diff --git a/gdk/win32/gdkdnd-win32.c b/gdk/win32/gdkdnd-win32.c new file mode 100644 index 000000000..3cd3716d5 --- /dev/null +++ b/gdk/win32/gdkdnd-win32.c @@ -0,0 +1,863 @@ +/* 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" + +#define INITGUID + +#include <string.h> +#include "gdk.h" +#include "gdkx.h" +#include "gdk/gdkprivate.h" +#include <ole2.h> +#include <shlobj.h> +#include <shlguid.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 + +HRESULT STDMETHODCALLTYPE + m_query_interface_target (IDropTarget __RPC_FAR *This, + /* [in] */ REFIID riid, + /* [iid_is][out] */ void __RPC_FAR *__RPC_FAR *ppvObject); + +ULONG STDMETHODCALLTYPE + m_add_ref_target (IDropTarget __RPC_FAR *This); + +ULONG STDMETHODCALLTYPE + m_release_target (IDropTarget __RPC_FAR *This); + +HRESULT STDMETHODCALLTYPE + m_drag_enter (IDropTarget __RPC_FAR *This, + /* [unique][in] */ IDataObject __RPC_FAR *pDataObj, + /* [in] */ DWORD grfKeyState, + /* [in] */ POINTL pt, + /* [out][in] */ DWORD __RPC_FAR *pdwEffect); + +HRESULT STDMETHODCALLTYPE + m_drag_over (IDropTarget __RPC_FAR *This, + /* [in] */ DWORD grfKeyState, + /* [in] */ POINTL pt, + /* [out][in] */ DWORD __RPC_FAR *pdwEffect); + +HRESULT STDMETHODCALLTYPE + m_drag_leave (IDropTarget __RPC_FAR *This); + +HRESULT STDMETHODCALLTYPE + m_drop (IDropTarget __RPC_FAR *This, + /* [unique][in] */ IDataObject __RPC_FAR *pDataObj, + /* [in] */ DWORD grfKeyState, + /* [in] */ POINTL pt, + /* [out][in] */ DWORD __RPC_FAR *pdwEffect); + +HRESULT STDMETHODCALLTYPE + m_query_interface_source (IDropSource __RPC_FAR *This, + /* [in] */ REFIID riid, + /* [iid_is][out] */ void __RPC_FAR *__RPC_FAR *ppvObject); + +ULONG STDMETHODCALLTYPE + m_add_ref_source (IDropSource __RPC_FAR *This); + +ULONG STDMETHODCALLTYPE + m_release_source (IDropSource __RPC_FAR *This); + +HRESULT STDMETHODCALLTYPE + m_query_continue_drag (IDropSource __RPC_FAR *This, + /* [in] */ BOOL fEscapePressed, + /* [in] */ DWORD grfKeyState); +HRESULT STDMETHODCALLTYPE + m_give_feedback (IDropSource __RPC_FAR *This, + /* [in] */ DWORD dwEffect); + +#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; +} + +#if OLE2_DND + +typedef struct { + IDropTarget idt; + GdkDragContext *context; +} target_drag_context; + +typedef struct { + IDropSource ids; + GdkDragContext *context; +} source_drag_context; + +HRESULT STDMETHODCALLTYPE +m_query_interface_target (IDropTarget __RPC_FAR *This, + /* [in] */ REFIID riid, + /* [iid_is][out] */ void __RPC_FAR *__RPC_FAR *ppvObject) +{ + GDK_NOTE (DND, g_print ("m_query_interface_target\n")); + + *ppvObject = NULL; + + g_print ("riid = %.08x-%.04x-%.04x-%.02x%.02x-%.02x%.02x%.02x%.02x%.02x%.02x", + ((gulong *) riid)[0], + ((gushort *) riid)[2], + ((gushort *) riid)[3], + ((guchar *) riid)[8], + ((guchar *) riid)[9], + ((guchar *) riid)[10], + ((guchar *) riid)[11], + ((guchar *) riid)[12], + ((guchar *) riid)[13], + ((guchar *) riid)[14], + ((guchar *) riid)[15]); + if (IsEqualGUID (riid, &IID_IUnknown)) + { + m_add_ref_target (This); + *ppvObject = This; + g_print ("...IUnknown\n"); + return S_OK; + } + else if (IsEqualGUID (riid, &IID_IDropTarget)) + { + m_add_ref_target (This); + *ppvObject = This; + g_print ("...IDropTarget\n"); + return S_OK; + } + else + { + g_print ("...Huh?\n"); + return E_NOINTERFACE; + } +} + +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; +} + +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; +} + +HRESULT STDMETHODCALLTYPE +m_drag_enter (IDropTarget __RPC_FAR *This, + /* [unique][in] */ IDataObject __RPC_FAR *pDataObj, + /* [in] */ DWORD grfKeyState, + /* [in] */ POINTL pt, + /* [out][in] */ DWORD __RPC_FAR *pdwEffect) +{ + GDK_NOTE (DND, g_print ("m_drag_enter\n")); + return E_UNEXPECTED; +} + +HRESULT STDMETHODCALLTYPE +m_drag_over (IDropTarget __RPC_FAR *This, + /* [in] */ DWORD grfKeyState, + /* [in] */ POINTL pt, + /* [out][in] */ DWORD __RPC_FAR *pdwEffect) +{ + GDK_NOTE (DND, g_print ("m_drag_over\n")); + return E_UNEXPECTED; +} + +HRESULT STDMETHODCALLTYPE +m_drag_leave (IDropTarget __RPC_FAR *This) +{ + GDK_NOTE (DND, g_print ("m_drag_leave\n")); + return E_UNEXPECTED; +} + +HRESULT STDMETHODCALLTYPE +m_drop (IDropTarget __RPC_FAR *This, + /* [unique][in] */ IDataObject __RPC_FAR *pDataObj, + /* [in] */ DWORD grfKeyState, + /* [in] */ POINTL pt, + /* [out][in] */ DWORD __RPC_FAR *pdwEffect) +{ + GDK_NOTE (DND, g_print ("m_drop\n")); + return E_UNEXPECTED; +} + +HRESULT STDMETHODCALLTYPE +m_query_interface_source (IDropSource __RPC_FAR *This, + /* [in] */ REFIID riid, + /* [iid_is][out] */ void __RPC_FAR *__RPC_FAR *ppvObject) +{ + GDK_NOTE (DND, g_print ("m_query_interface_source\n")); + + *ppvObject = NULL; + + g_print ("riid = %.02x%.02x%.02x%.02x-%.02x%.02x-%.02x%.02x-%.02x%.02x-%.02x%.02x%.02x%.02x%.02x%.02x", + ((guchar *) riid)[0], + ((guchar *) riid)[1], + ((guchar *) riid)[2], + ((guchar *) riid)[3], + ((guchar *) riid)[4], + ((guchar *) riid)[5], + ((guchar *) riid)[6], + ((guchar *) riid)[7], + ((guchar *) riid)[8], + ((guchar *) riid)[9], + ((guchar *) riid)[10], + ((guchar *) riid)[11], + ((guchar *) riid)[12], + ((guchar *) riid)[13], + ((guchar *) riid)[14], + ((guchar *) riid)[15]); + if (IsEqualGUID (riid, &IID_IUnknown)) + { + m_add_ref_source (This); + *ppvObject = This; + g_print ("...IUnknown\n"); + return S_OK; + } + else if (IsEqualGUID (riid, &IID_IDropSource)) + { + m_add_ref_source (This); + *ppvObject = This; + g_print ("...IDropSource\n"); + return S_OK; + } + else + { + g_print ("...Huh?\n"); + return E_NOINTERFACE; + } +} + +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; +} + +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; +} + +HRESULT STDMETHODCALLTYPE +m_query_continue_drag (IDropSource __RPC_FAR *This, + /* [in] */ BOOL fEscapePressed, + /* [in] */ DWORD grfKeyState) +{ + GDK_NOTE (DND, g_print ("m_query_continue_drag\n")); + return E_UNEXPECTED; +} + +HRESULT STDMETHODCALLTYPE +m_give_feedback (IDropSource __RPC_FAR *This, + /* [in] */ DWORD dwEffect) +{ + GDK_NOTE (DND, g_print ("m_give_feedback\n")); + 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 +}; + +target_drag_context * +target_context_new (void) +{ + target_drag_context *result; + + result = g_new0 (target_drag_context, 1); + + result->idt.lpVtbl = &idt_vtbl; + + result->context = gdk_drag_context_new (); + + return result; +} + +source_drag_context * +source_context_new (void) +{ + source_drag_context *result; + + result = g_new0 (source_drag_context, 1); + + result->ids.lpVtbl = &ids_vtbl; + + result->context = gdk_drag_context_new (); + + return result; +} + +#endif /* OLE2_DND */ + +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 + +/* 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); +} + +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; + + hres = OleInitialize (NULL); + + if (! SUCCEEDED (hres)) + g_error ("OleInitialize failed"); +} + +void +gdk_dnd_exit (void) +{ + OleUninitialize (); +} + +/* 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; + GdkDragContext *new_context; + + g_return_val_if_fail (window != NULL, NULL); + + GDK_NOTE (DND, g_print ("gdk_drag_begin\n")); + + new_context = gdk_drag_context_new (); + new_context->is_source = TRUE; + new_context->source_window = window; + gdk_window_ref (window); + + tmp_list = g_list_last (targets); + new_context->targets = NULL; + while (tmp_list) + { + new_context->targets = g_list_prepend (new_context->targets, + tmp_list->data); + tmp_list = tmp_list->prev; + } + + new_context->actions = 0; + + return new_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; + GdkWindowPrivate *drag_window_private = (GdkWindowPrivate *) 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) +{ +} + + +void +gdk_window_register_dnd (GdkWindow *window) +{ + GdkWindowPrivate *private = (GdkWindowPrivate *) window; +#if 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); + +#if 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"); + } +#endif +} + +/************************************************************* + * gdk_drag_get_selection: + * Returns the selection atom for the current source window + * arguments: + * + * results: + *************************************************************/ + +GdkAtom +gdk_drag_get_selection (GdkDragContext *context) +{ + if (context->protocol == GDK_DRAG_PROTO_WIN32_DROPFILES) + return gdk_win32_dropfiles_atom; + else if (context->protocol == GDK_DRAG_PROTO_OLE2) + return gdk_ole2_dnd_atom; + else + return GDK_NONE; +} diff --git a/gdk/win32/gdkdnd.c b/gdk/win32/gdkdnd.c new file mode 100644 index 000000000..3cd3716d5 --- /dev/null +++ b/gdk/win32/gdkdnd.c @@ -0,0 +1,863 @@ +/* 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" + +#define INITGUID + +#include <string.h> +#include "gdk.h" +#include "gdkx.h" +#include "gdk/gdkprivate.h" +#include <ole2.h> +#include <shlobj.h> +#include <shlguid.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 + +HRESULT STDMETHODCALLTYPE + m_query_interface_target (IDropTarget __RPC_FAR *This, + /* [in] */ REFIID riid, + /* [iid_is][out] */ void __RPC_FAR *__RPC_FAR *ppvObject); + +ULONG STDMETHODCALLTYPE + m_add_ref_target (IDropTarget __RPC_FAR *This); + +ULONG STDMETHODCALLTYPE + m_release_target (IDropTarget __RPC_FAR *This); + +HRESULT STDMETHODCALLTYPE + m_drag_enter (IDropTarget __RPC_FAR *This, + /* [unique][in] */ IDataObject __RPC_FAR *pDataObj, + /* [in] */ DWORD grfKeyState, + /* [in] */ POINTL pt, + /* [out][in] */ DWORD __RPC_FAR *pdwEffect); + +HRESULT STDMETHODCALLTYPE + m_drag_over (IDropTarget __RPC_FAR *This, + /* [in] */ DWORD grfKeyState, + /* [in] */ POINTL pt, + /* [out][in] */ DWORD __RPC_FAR *pdwEffect); + +HRESULT STDMETHODCALLTYPE + m_drag_leave (IDropTarget __RPC_FAR *This); + +HRESULT STDMETHODCALLTYPE + m_drop (IDropTarget __RPC_FAR *This, + /* [unique][in] */ IDataObject __RPC_FAR *pDataObj, + /* [in] */ DWORD grfKeyState, + /* [in] */ POINTL pt, + /* [out][in] */ DWORD __RPC_FAR *pdwEffect); + +HRESULT STDMETHODCALLTYPE + m_query_interface_source (IDropSource __RPC_FAR *This, + /* [in] */ REFIID riid, + /* [iid_is][out] */ void __RPC_FAR *__RPC_FAR *ppvObject); + +ULONG STDMETHODCALLTYPE + m_add_ref_source (IDropSource __RPC_FAR *This); + +ULONG STDMETHODCALLTYPE + m_release_source (IDropSource __RPC_FAR *This); + +HRESULT STDMETHODCALLTYPE + m_query_continue_drag (IDropSource __RPC_FAR *This, + /* [in] */ BOOL fEscapePressed, + /* [in] */ DWORD grfKeyState); +HRESULT STDMETHODCALLTYPE + m_give_feedback (IDropSource __RPC_FAR *This, + /* [in] */ DWORD dwEffect); + +#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; +} + +#if OLE2_DND + +typedef struct { + IDropTarget idt; + GdkDragContext *context; +} target_drag_context; + +typedef struct { + IDropSource ids; + GdkDragContext *context; +} source_drag_context; + +HRESULT STDMETHODCALLTYPE +m_query_interface_target (IDropTarget __RPC_FAR *This, + /* [in] */ REFIID riid, + /* [iid_is][out] */ void __RPC_FAR *__RPC_FAR *ppvObject) +{ + GDK_NOTE (DND, g_print ("m_query_interface_target\n")); + + *ppvObject = NULL; + + g_print ("riid = %.08x-%.04x-%.04x-%.02x%.02x-%.02x%.02x%.02x%.02x%.02x%.02x", + ((gulong *) riid)[0], + ((gushort *) riid)[2], + ((gushort *) riid)[3], + ((guchar *) riid)[8], + ((guchar *) riid)[9], + ((guchar *) riid)[10], + ((guchar *) riid)[11], + ((guchar *) riid)[12], + ((guchar *) riid)[13], + ((guchar *) riid)[14], + ((guchar *) riid)[15]); + if (IsEqualGUID (riid, &IID_IUnknown)) + { + m_add_ref_target (This); + *ppvObject = This; + g_print ("...IUnknown\n"); + return S_OK; + } + else if (IsEqualGUID (riid, &IID_IDropTarget)) + { + m_add_ref_target (This); + *ppvObject = This; + g_print ("...IDropTarget\n"); + return S_OK; + } + else + { + g_print ("...Huh?\n"); + return E_NOINTERFACE; + } +} + +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; +} + +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; +} + +HRESULT STDMETHODCALLTYPE +m_drag_enter (IDropTarget __RPC_FAR *This, + /* [unique][in] */ IDataObject __RPC_FAR *pDataObj, + /* [in] */ DWORD grfKeyState, + /* [in] */ POINTL pt, + /* [out][in] */ DWORD __RPC_FAR *pdwEffect) +{ + GDK_NOTE (DND, g_print ("m_drag_enter\n")); + return E_UNEXPECTED; +} + +HRESULT STDMETHODCALLTYPE +m_drag_over (IDropTarget __RPC_FAR *This, + /* [in] */ DWORD grfKeyState, + /* [in] */ POINTL pt, + /* [out][in] */ DWORD __RPC_FAR *pdwEffect) +{ + GDK_NOTE (DND, g_print ("m_drag_over\n")); + return E_UNEXPECTED; +} + +HRESULT STDMETHODCALLTYPE +m_drag_leave (IDropTarget __RPC_FAR *This) +{ + GDK_NOTE (DND, g_print ("m_drag_leave\n")); + return E_UNEXPECTED; +} + +HRESULT STDMETHODCALLTYPE +m_drop (IDropTarget __RPC_FAR *This, + /* [unique][in] */ IDataObject __RPC_FAR *pDataObj, + /* [in] */ DWORD grfKeyState, + /* [in] */ POINTL pt, + /* [out][in] */ DWORD __RPC_FAR *pdwEffect) +{ + GDK_NOTE (DND, g_print ("m_drop\n")); + return E_UNEXPECTED; +} + +HRESULT STDMETHODCALLTYPE +m_query_interface_source (IDropSource __RPC_FAR *This, + /* [in] */ REFIID riid, + /* [iid_is][out] */ void __RPC_FAR *__RPC_FAR *ppvObject) +{ + GDK_NOTE (DND, g_print ("m_query_interface_source\n")); + + *ppvObject = NULL; + + g_print ("riid = %.02x%.02x%.02x%.02x-%.02x%.02x-%.02x%.02x-%.02x%.02x-%.02x%.02x%.02x%.02x%.02x%.02x", + ((guchar *) riid)[0], + ((guchar *) riid)[1], + ((guchar *) riid)[2], + ((guchar *) riid)[3], + ((guchar *) riid)[4], + ((guchar *) riid)[5], + ((guchar *) riid)[6], + ((guchar *) riid)[7], + ((guchar *) riid)[8], + ((guchar *) riid)[9], + ((guchar *) riid)[10], + ((guchar *) riid)[11], + ((guchar *) riid)[12], + ((guchar *) riid)[13], + ((guchar *) riid)[14], + ((guchar *) riid)[15]); + if (IsEqualGUID (riid, &IID_IUnknown)) + { + m_add_ref_source (This); + *ppvObject = This; + g_print ("...IUnknown\n"); + return S_OK; + } + else if (IsEqualGUID (riid, &IID_IDropSource)) + { + m_add_ref_source (This); + *ppvObject = This; + g_print ("...IDropSource\n"); + return S_OK; + } + else + { + g_print ("...Huh?\n"); + return E_NOINTERFACE; + } +} + +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; +} + +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; +} + +HRESULT STDMETHODCALLTYPE +m_query_continue_drag (IDropSource __RPC_FAR *This, + /* [in] */ BOOL fEscapePressed, + /* [in] */ DWORD grfKeyState) +{ + GDK_NOTE (DND, g_print ("m_query_continue_drag\n")); + return E_UNEXPECTED; +} + +HRESULT STDMETHODCALLTYPE +m_give_feedback (IDropSource __RPC_FAR *This, + /* [in] */ DWORD dwEffect) +{ + GDK_NOTE (DND, g_print ("m_give_feedback\n")); + 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 +}; + +target_drag_context * +target_context_new (void) +{ + target_drag_context *result; + + result = g_new0 (target_drag_context, 1); + + result->idt.lpVtbl = &idt_vtbl; + + result->context = gdk_drag_context_new (); + + return result; +} + +source_drag_context * +source_context_new (void) +{ + source_drag_context *result; + + result = g_new0 (source_drag_context, 1); + + result->ids.lpVtbl = &ids_vtbl; + + result->context = gdk_drag_context_new (); + + return result; +} + +#endif /* OLE2_DND */ + +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 + +/* 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); +} + +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; + + hres = OleInitialize (NULL); + + if (! SUCCEEDED (hres)) + g_error ("OleInitialize failed"); +} + +void +gdk_dnd_exit (void) +{ + OleUninitialize (); +} + +/* 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; + GdkDragContext *new_context; + + g_return_val_if_fail (window != NULL, NULL); + + GDK_NOTE (DND, g_print ("gdk_drag_begin\n")); + + new_context = gdk_drag_context_new (); + new_context->is_source = TRUE; + new_context->source_window = window; + gdk_window_ref (window); + + tmp_list = g_list_last (targets); + new_context->targets = NULL; + while (tmp_list) + { + new_context->targets = g_list_prepend (new_context->targets, + tmp_list->data); + tmp_list = tmp_list->prev; + } + + new_context->actions = 0; + + return new_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; + GdkWindowPrivate *drag_window_private = (GdkWindowPrivate *) 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) +{ +} + + +void +gdk_window_register_dnd (GdkWindow *window) +{ + GdkWindowPrivate *private = (GdkWindowPrivate *) window; +#if 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); + +#if 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"); + } +#endif +} + +/************************************************************* + * gdk_drag_get_selection: + * Returns the selection atom for the current source window + * arguments: + * + * results: + *************************************************************/ + +GdkAtom +gdk_drag_get_selection (GdkDragContext *context) +{ + if (context->protocol == GDK_DRAG_PROTO_WIN32_DROPFILES) + return gdk_win32_dropfiles_atom; + else if (context->protocol == GDK_DRAG_PROTO_OLE2) + return gdk_ole2_dnd_atom; + else + return GDK_NONE; +} diff --git a/gdk/win32/gdkdraw.c b/gdk/win32/gdkdraw.c new file mode 100644 index 000000000..700bdb5db --- /dev/null +++ b/gdk/win32/gdkdraw.c @@ -0,0 +1,655 @@ +/* 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 "gdk.h" +#include "gdkprivate.h" + +#ifndef M_TWOPI +#define M_TWOPI (2.0 * 3.14159265358979323846) +#endif + +void +gdk_draw_point (GdkDrawable *drawable, + GdkGC *gc, + gint x, + gint y) +{ + GdkWindowPrivate *drawable_private; + GdkGCPrivate *gc_private; + HDC hdc; + HBRUSH hbr; + RECT rect; + + g_return_if_fail (drawable != NULL); + g_return_if_fail (gc != NULL); + + drawable_private = (GdkWindowPrivate*) drawable; + if (drawable_private->destroyed) + return; + gc_private = (GdkGCPrivate*) gc; + + hdc = gdk_gc_predraw (drawable_private, gc_private); + hbr = GetCurrentObject (hdc, OBJ_BRUSH); + /* We use FillRect because SetPixel wants the COLORREF directly, + * and doesn't use the current brush, which is what we want. + */ + rect.left = x; + rect.top = y; + rect.right = rect.left + 1; + rect.bottom = rect.top + 1; + FillRect (hdc, &rect, hbr); + + gdk_gc_postdraw (drawable_private, gc_private); +} + +void +gdk_draw_line (GdkDrawable *drawable, + GdkGC *gc, + gint x1, + gint y1, + gint x2, + gint y2) +{ + GdkWindowPrivate *drawable_private; + GdkGCPrivate *gc_private; + HDC hdc; + + g_return_if_fail (drawable != NULL); + g_return_if_fail (gc != NULL); + + drawable_private = (GdkWindowPrivate*) drawable; + if (drawable_private->destroyed) + return; + 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 it hopefully + * doesn't matter? + */ + if (gc_private->pen_width == 1) + 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) +{ + GdkWindowPrivate *drawable_private; + GdkGCPrivate *gc_private; + HDC hdc; + LOGBRUSH lb; + HPEN hpen; + HBRUSH hbr; + HGDIOBJ oldpen, oldbrush; + + g_return_if_fail (drawable != NULL); + g_return_if_fail (gc != NULL); + + drawable_private = (GdkWindowPrivate*) drawable; + if (drawable_private->destroyed) + return; + 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) +{ + GdkWindowPrivate *drawable_private; + GdkGCPrivate *gc_private; + HDC hdc; + int nXStartArc, nYStartArc, nXEndArc, nYEndArc; + + g_return_if_fail (drawable != NULL); + g_return_if_fail (gc != NULL); + + drawable_private = (GdkWindowPrivate*) drawable; + if (drawable_private->destroyed) + return; + 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); + + nXStartArc = x + width/2 + (int) (sin(angle1/64.*M_TWOPI)*width); + nYStartArc = y + height/2 + (int) (cos(angle1/64.*M_TWOPI)*height); + nXEndArc = x + width/2 + (int) (sin(angle2/64.*M_TWOPI)*width); + nYEndArc = y + height/2 + (int) (cos(angle2/64.*M_TWOPI)*height); + + if (filled) + { + if (!Pie (hdc, x, y, x+width, y+height, + nXStartArc, nYStartArc, nXEndArc, nYEndArc)) + g_warning ("gdk_draw_arc: Pie failed"); + } + else + { + if (!Arc (hdc, x, y, x+width, y+height, + nXStartArc, nYStartArc, nXEndArc, nYEndArc)) + g_warning ("gdk_draw_arc: Arc failed"); + } + gdk_gc_postdraw (drawable_private, gc_private); +} + +void +gdk_draw_polygon (GdkDrawable *drawable, + GdkGC *gc, + gint filled, + GdkPoint *points, + gint npoints) +{ + GdkWindowPrivate *drawable_private; + GdkGCPrivate *gc_private; + HDC hdc; + POINT *pts; + int i; + + g_return_if_fail (drawable != NULL); + g_return_if_fail (gc != NULL); + + drawable_private = (GdkWindowPrivate*) drawable; + if (drawable_private->destroyed) + return; + gc_private = (GdkGCPrivate*) gc; + + hdc = gdk_gc_predraw (drawable_private, gc_private); + pts = g_malloc ((npoints+1) * sizeof (POINT)); + + GDK_NOTE (MISC, g_print ("gdk_draw_polygon: %#x (%d) %d\n", + drawable_private->xwindow, gc_private, + npoints)); + + 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); +} + +/* 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)); +} + +/* gdk_draw_text + * + * Modified by Li-Da Lho to draw 16 bits and Multibyte strings + * + * Interface changed: add "GdkFont *font" to specify font or fontset explicitely + */ +void +gdk_draw_text (GdkDrawable *drawable, + GdkFont *font, + GdkGC *gc, + gint x, + gint y, + const gchar *text, + gint text_length) +{ + GdkWindowPrivate *drawable_private; + GdkFontPrivate *font_private; + GdkGCPrivate *gc_private; + HDC hdc; + HFONT xfont; + HGDIOBJ oldfont; + + g_return_if_fail (drawable != NULL); + g_return_if_fail (font != NULL); + g_return_if_fail (gc != NULL); + g_return_if_fail (text != NULL); + + drawable_private = (GdkWindowPrivate*) drawable; + if (drawable_private->destroyed) + return; + gc_private = (GdkGCPrivate*) gc; + font_private = (GdkFontPrivate*) font; + + if (font->type == GDK_FONT_FONT) + { + hdc = gdk_gc_predraw (drawable_private, gc_private); + xfont = (HFONT) font_private->xfont; + + GDK_NOTE (MISC, g_print ("gdk_draw_text: %#x (%d) %#x " + "+%d+%d font: %#x \"%.*s\" length: %d\n", + drawable_private->xwindow, + gc_private, gc_private->xgc, + x, y, xfont, + (text_length > 10 ? 10 : text_length), + text, text_length)); + + if ((oldfont = SelectObject (hdc, xfont)) == NULL) + g_warning ("gdk_draw_text: SelectObject failed"); + if (!TextOutA (hdc, x, y, text, text_length)) + g_warning ("gdk_draw_text: TextOutA failed"); + SelectObject (hdc, oldfont); + gdk_gc_postdraw (drawable_private, gc_private); + } + else + g_error ("undefined font type"); +} + +void +gdk_draw_text_wc (GdkDrawable *drawable, + GdkFont *font, + GdkGC *gc, + gint x, + gint y, + const GdkWChar *text, + gint text_length) +{ + GdkWindowPrivate *drawable_private; + GdkFontPrivate *font_private; + GdkGCPrivate *gc_private; + gint i; + wchar_t *wcstr; + + g_return_if_fail (drawable != NULL); + g_return_if_fail (font != NULL); + g_return_if_fail (gc != NULL); + g_return_if_fail (text != NULL); + + drawable_private = (GdkWindowPrivate*) drawable; + if (drawable_private->destroyed) + return; + gc_private = (GdkGCPrivate*) gc; + font_private = (GdkFontPrivate*) font; + + if (font->type == GDK_FONT_FONT) + { + HDC hdc; + HFONT xfont; + HGDIOBJ oldfont; + + hdc = gdk_gc_predraw (drawable_private, gc_private); + xfont = (HFONT) font_private->xfont; + + GDK_NOTE (MISC, g_print ("gdk_draw_text_wc: %#x (%d) %#x " + "+%d+%d font: %#x length: %d\n", + drawable_private->xwindow, + gc_private, gc_private->xgc, + x, y, xfont, + text_length)); + + if ((oldfont = SelectObject (hdc, xfont)) == NULL) + g_warning ("gdk_draw_text: SelectObject failed"); + wcstr = g_new (wchar_t, text_length); + for (i = 0; i < text_length; i++) + wcstr[i] = text[i]; + if (!TextOutW (hdc, x, y, wcstr, text_length)) + g_warning ("gdk_draw_text: TextOutW failed"); + g_free (wcstr); + SelectObject (hdc, oldfont); + gdk_gc_postdraw (drawable_private, gc_private); + } + else + g_error ("undefined font type"); +} + +void +gdk_draw_pixmap (GdkDrawable *drawable, + GdkGC *gc, + GdkPixmap *src, + gint xsrc, + gint ysrc, + gint xdest, + gint ydest, + gint width, + gint height) +{ + GdkWindowPrivate *drawable_private; + GdkWindowPrivate *src_private; + GdkGCPrivate *gc_private; + HDC hdc; + HDC srcdc; + HGDIOBJ hgdiobj; + + g_return_if_fail (drawable != NULL); + g_return_if_fail (src != NULL); + g_return_if_fail (gc != NULL); + + drawable_private = (GdkWindowPrivate*) drawable; + src_private = (GdkWindowPrivate*) src; + if (drawable_private->destroyed || src_private->destroyed) + return; + gc_private = (GdkGCPrivate*) gc; + + if (width == -1) + width = src_private->width; + if (height == -1) + height = src_private->height; + + hdc = gdk_gc_predraw (drawable_private, gc_private); + + GDK_NOTE (MISC, g_print ("gdk_draw_pixmap: dest: %#x destdc: (%d) %#x " + "src: %#x %dx%d@+%d+%d\n", + drawable_private->xwindow, gc_private, hdc, + src_private->xwindow, + width, height, xdest, ydest)); + + /* Strangely enough, this function is called also to bitblt + * from a window. + */ + if (src_private->window_type == GDK_WINDOW_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 ((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) +{ + GdkWindowPrivate *drawable_private; + GdkGCPrivate *gc_private; + HDC hdc; + HBRUSH hbr; + int i; + + g_return_if_fail (drawable != NULL); + g_return_if_fail ((points != NULL) && (npoints > 0)); + g_return_if_fail (gc != NULL); + + drawable_private = (GdkWindowPrivate*) drawable; + if (drawable_private->destroyed) + return; + gc_private = (GdkGCPrivate*) gc; + + hdc = gdk_gc_predraw (drawable_private, gc_private); + hbr = GetCurrentObject (hdc, OBJ_BRUSH); + + for (i = 0; i < npoints; i++) + { + RECT rect; + + rect.left = points[i].x; + rect.top = points[i].y; + rect.right = rect.left + 1; + rect.bottom = rect.top + 1; + if (!FillRect (hdc, &rect, hbr)) + g_warning ("gdk_draw_points: FillRect failed"); + } + gdk_gc_postdraw (drawable_private, gc_private); +} + +void +gdk_draw_segments (GdkDrawable *drawable, + GdkGC *gc, + GdkSegment *segs, + gint nsegs) +{ + GdkWindowPrivate *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); + + drawable_private = (GdkWindowPrivate*) drawable; + if (drawable_private->destroyed) + return; + gc_private = (GdkGCPrivate*) gc; + + hdc = gdk_gc_predraw (drawable_private, gc_private); + + for (i = 0; i < nsegs; i++) + { + MoveToEx (hdc, segs[i].x1, segs[i].y1, NULL); + 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) +{ + GdkWindowPrivate *drawable_private; + GdkGCPrivate *gc_private; + HDC hdc; + POINT *pts; + int i; + + if (npoints <= 0) + return; + + g_return_if_fail (drawable != NULL); + g_return_if_fail (points != NULL); + g_return_if_fail (gc != NULL); + + drawable_private = (GdkWindowPrivate*) 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 failed"); + + g_free (pts); + + /* Draw end pixel */ + if (gc_private->pen_width == 1) + { + MoveToEx (hdc, points[npoints-1].x, points[npoints-1].y, NULL); + if (!LineTo (hdc, points[npoints-1].x + 1, points[npoints-1].y)) + g_warning ("gdk_draw_lines: LineTo failed"); + } +#else + MoveToEx (hdc, points[0].x, points[0].y, NULL); + for (i = 1; i < npoints; i++) + if (!LineTo (hdc, points[i].x, points[i].y)) + g_warning ("gdk_draw_lines: LineTo #1 failed"); + + /* Draw end pixel */ + if (gc_private->pen_width == 1) + if (!LineTo (hdc, points[npoints-1].x + 1, points[npoints-1].y)) + g_warning ("gdk_draw_lines: LineTo #2 failed"); +#endif + gdk_gc_postdraw (drawable_private, gc_private); +} diff --git a/gdk/win32/gdkdrawable-win32.c b/gdk/win32/gdkdrawable-win32.c new file mode 100644 index 000000000..700bdb5db --- /dev/null +++ b/gdk/win32/gdkdrawable-win32.c @@ -0,0 +1,655 @@ +/* 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 "gdk.h" +#include "gdkprivate.h" + +#ifndef M_TWOPI +#define M_TWOPI (2.0 * 3.14159265358979323846) +#endif + +void +gdk_draw_point (GdkDrawable *drawable, + GdkGC *gc, + gint x, + gint y) +{ + GdkWindowPrivate *drawable_private; + GdkGCPrivate *gc_private; + HDC hdc; + HBRUSH hbr; + RECT rect; + + g_return_if_fail (drawable != NULL); + g_return_if_fail (gc != NULL); + + drawable_private = (GdkWindowPrivate*) drawable; + if (drawable_private->destroyed) + return; + gc_private = (GdkGCPrivate*) gc; + + hdc = gdk_gc_predraw (drawable_private, gc_private); + hbr = GetCurrentObject (hdc, OBJ_BRUSH); + /* We use FillRect because SetPixel wants the COLORREF directly, + * and doesn't use the current brush, which is what we want. + */ + rect.left = x; + rect.top = y; + rect.right = rect.left + 1; + rect.bottom = rect.top + 1; + FillRect (hdc, &rect, hbr); + + gdk_gc_postdraw (drawable_private, gc_private); +} + +void +gdk_draw_line (GdkDrawable *drawable, + GdkGC *gc, + gint x1, + gint y1, + gint x2, + gint y2) +{ + GdkWindowPrivate *drawable_private; + GdkGCPrivate *gc_private; + HDC hdc; + + g_return_if_fail (drawable != NULL); + g_return_if_fail (gc != NULL); + + drawable_private = (GdkWindowPrivate*) drawable; + if (drawable_private->destroyed) + return; + 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 it hopefully + * doesn't matter? + */ + if (gc_private->pen_width == 1) + 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) +{ + GdkWindowPrivate *drawable_private; + GdkGCPrivate *gc_private; + HDC hdc; + LOGBRUSH lb; + HPEN hpen; + HBRUSH hbr; + HGDIOBJ oldpen, oldbrush; + + g_return_if_fail (drawable != NULL); + g_return_if_fail (gc != NULL); + + drawable_private = (GdkWindowPrivate*) drawable; + if (drawable_private->destroyed) + return; + 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) +{ + GdkWindowPrivate *drawable_private; + GdkGCPrivate *gc_private; + HDC hdc; + int nXStartArc, nYStartArc, nXEndArc, nYEndArc; + + g_return_if_fail (drawable != NULL); + g_return_if_fail (gc != NULL); + + drawable_private = (GdkWindowPrivate*) drawable; + if (drawable_private->destroyed) + return; + 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); + + nXStartArc = x + width/2 + (int) (sin(angle1/64.*M_TWOPI)*width); + nYStartArc = y + height/2 + (int) (cos(angle1/64.*M_TWOPI)*height); + nXEndArc = x + width/2 + (int) (sin(angle2/64.*M_TWOPI)*width); + nYEndArc = y + height/2 + (int) (cos(angle2/64.*M_TWOPI)*height); + + if (filled) + { + if (!Pie (hdc, x, y, x+width, y+height, + nXStartArc, nYStartArc, nXEndArc, nYEndArc)) + g_warning ("gdk_draw_arc: Pie failed"); + } + else + { + if (!Arc (hdc, x, y, x+width, y+height, + nXStartArc, nYStartArc, nXEndArc, nYEndArc)) + g_warning ("gdk_draw_arc: Arc failed"); + } + gdk_gc_postdraw (drawable_private, gc_private); +} + +void +gdk_draw_polygon (GdkDrawable *drawable, + GdkGC *gc, + gint filled, + GdkPoint *points, + gint npoints) +{ + GdkWindowPrivate *drawable_private; + GdkGCPrivate *gc_private; + HDC hdc; + POINT *pts; + int i; + + g_return_if_fail (drawable != NULL); + g_return_if_fail (gc != NULL); + + drawable_private = (GdkWindowPrivate*) drawable; + if (drawable_private->destroyed) + return; + gc_private = (GdkGCPrivate*) gc; + + hdc = gdk_gc_predraw (drawable_private, gc_private); + pts = g_malloc ((npoints+1) * sizeof (POINT)); + + GDK_NOTE (MISC, g_print ("gdk_draw_polygon: %#x (%d) %d\n", + drawable_private->xwindow, gc_private, + npoints)); + + 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); +} + +/* 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)); +} + +/* gdk_draw_text + * + * Modified by Li-Da Lho to draw 16 bits and Multibyte strings + * + * Interface changed: add "GdkFont *font" to specify font or fontset explicitely + */ +void +gdk_draw_text (GdkDrawable *drawable, + GdkFont *font, + GdkGC *gc, + gint x, + gint y, + const gchar *text, + gint text_length) +{ + GdkWindowPrivate *drawable_private; + GdkFontPrivate *font_private; + GdkGCPrivate *gc_private; + HDC hdc; + HFONT xfont; + HGDIOBJ oldfont; + + g_return_if_fail (drawable != NULL); + g_return_if_fail (font != NULL); + g_return_if_fail (gc != NULL); + g_return_if_fail (text != NULL); + + drawable_private = (GdkWindowPrivate*) drawable; + if (drawable_private->destroyed) + return; + gc_private = (GdkGCPrivate*) gc; + font_private = (GdkFontPrivate*) font; + + if (font->type == GDK_FONT_FONT) + { + hdc = gdk_gc_predraw (drawable_private, gc_private); + xfont = (HFONT) font_private->xfont; + + GDK_NOTE (MISC, g_print ("gdk_draw_text: %#x (%d) %#x " + "+%d+%d font: %#x \"%.*s\" length: %d\n", + drawable_private->xwindow, + gc_private, gc_private->xgc, + x, y, xfont, + (text_length > 10 ? 10 : text_length), + text, text_length)); + + if ((oldfont = SelectObject (hdc, xfont)) == NULL) + g_warning ("gdk_draw_text: SelectObject failed"); + if (!TextOutA (hdc, x, y, text, text_length)) + g_warning ("gdk_draw_text: TextOutA failed"); + SelectObject (hdc, oldfont); + gdk_gc_postdraw (drawable_private, gc_private); + } + else + g_error ("undefined font type"); +} + +void +gdk_draw_text_wc (GdkDrawable *drawable, + GdkFont *font, + GdkGC *gc, + gint x, + gint y, + const GdkWChar *text, + gint text_length) +{ + GdkWindowPrivate *drawable_private; + GdkFontPrivate *font_private; + GdkGCPrivate *gc_private; + gint i; + wchar_t *wcstr; + + g_return_if_fail (drawable != NULL); + g_return_if_fail (font != NULL); + g_return_if_fail (gc != NULL); + g_return_if_fail (text != NULL); + + drawable_private = (GdkWindowPrivate*) drawable; + if (drawable_private->destroyed) + return; + gc_private = (GdkGCPrivate*) gc; + font_private = (GdkFontPrivate*) font; + + if (font->type == GDK_FONT_FONT) + { + HDC hdc; + HFONT xfont; + HGDIOBJ oldfont; + + hdc = gdk_gc_predraw (drawable_private, gc_private); + xfont = (HFONT) font_private->xfont; + + GDK_NOTE (MISC, g_print ("gdk_draw_text_wc: %#x (%d) %#x " + "+%d+%d font: %#x length: %d\n", + drawable_private->xwindow, + gc_private, gc_private->xgc, + x, y, xfont, + text_length)); + + if ((oldfont = SelectObject (hdc, xfont)) == NULL) + g_warning ("gdk_draw_text: SelectObject failed"); + wcstr = g_new (wchar_t, text_length); + for (i = 0; i < text_length; i++) + wcstr[i] = text[i]; + if (!TextOutW (hdc, x, y, wcstr, text_length)) + g_warning ("gdk_draw_text: TextOutW failed"); + g_free (wcstr); + SelectObject (hdc, oldfont); + gdk_gc_postdraw (drawable_private, gc_private); + } + else + g_error ("undefined font type"); +} + +void +gdk_draw_pixmap (GdkDrawable *drawable, + GdkGC *gc, + GdkPixmap *src, + gint xsrc, + gint ysrc, + gint xdest, + gint ydest, + gint width, + gint height) +{ + GdkWindowPrivate *drawable_private; + GdkWindowPrivate *src_private; + GdkGCPrivate *gc_private; + HDC hdc; + HDC srcdc; + HGDIOBJ hgdiobj; + + g_return_if_fail (drawable != NULL); + g_return_if_fail (src != NULL); + g_return_if_fail (gc != NULL); + + drawable_private = (GdkWindowPrivate*) drawable; + src_private = (GdkWindowPrivate*) src; + if (drawable_private->destroyed || src_private->destroyed) + return; + gc_private = (GdkGCPrivate*) gc; + + if (width == -1) + width = src_private->width; + if (height == -1) + height = src_private->height; + + hdc = gdk_gc_predraw (drawable_private, gc_private); + + GDK_NOTE (MISC, g_print ("gdk_draw_pixmap: dest: %#x destdc: (%d) %#x " + "src: %#x %dx%d@+%d+%d\n", + drawable_private->xwindow, gc_private, hdc, + src_private->xwindow, + width, height, xdest, ydest)); + + /* Strangely enough, this function is called also to bitblt + * from a window. + */ + if (src_private->window_type == GDK_WINDOW_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 ((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) +{ + GdkWindowPrivate *drawable_private; + GdkGCPrivate *gc_private; + HDC hdc; + HBRUSH hbr; + int i; + + g_return_if_fail (drawable != NULL); + g_return_if_fail ((points != NULL) && (npoints > 0)); + g_return_if_fail (gc != NULL); + + drawable_private = (GdkWindowPrivate*) drawable; + if (drawable_private->destroyed) + return; + gc_private = (GdkGCPrivate*) gc; + + hdc = gdk_gc_predraw (drawable_private, gc_private); + hbr = GetCurrentObject (hdc, OBJ_BRUSH); + + for (i = 0; i < npoints; i++) + { + RECT rect; + + rect.left = points[i].x; + rect.top = points[i].y; + rect.right = rect.left + 1; + rect.bottom = rect.top + 1; + if (!FillRect (hdc, &rect, hbr)) + g_warning ("gdk_draw_points: FillRect failed"); + } + gdk_gc_postdraw (drawable_private, gc_private); +} + +void +gdk_draw_segments (GdkDrawable *drawable, + GdkGC *gc, + GdkSegment *segs, + gint nsegs) +{ + GdkWindowPrivate *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); + + drawable_private = (GdkWindowPrivate*) drawable; + if (drawable_private->destroyed) + return; + gc_private = (GdkGCPrivate*) gc; + + hdc = gdk_gc_predraw (drawable_private, gc_private); + + for (i = 0; i < nsegs; i++) + { + MoveToEx (hdc, segs[i].x1, segs[i].y1, NULL); + 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) +{ + GdkWindowPrivate *drawable_private; + GdkGCPrivate *gc_private; + HDC hdc; + POINT *pts; + int i; + + if (npoints <= 0) + return; + + g_return_if_fail (drawable != NULL); + g_return_if_fail (points != NULL); + g_return_if_fail (gc != NULL); + + drawable_private = (GdkWindowPrivate*) 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 failed"); + + g_free (pts); + + /* Draw end pixel */ + if (gc_private->pen_width == 1) + { + MoveToEx (hdc, points[npoints-1].x, points[npoints-1].y, NULL); + if (!LineTo (hdc, points[npoints-1].x + 1, points[npoints-1].y)) + g_warning ("gdk_draw_lines: LineTo failed"); + } +#else + MoveToEx (hdc, points[0].x, points[0].y, NULL); + for (i = 1; i < npoints; i++) + if (!LineTo (hdc, points[i].x, points[i].y)) + g_warning ("gdk_draw_lines: LineTo #1 failed"); + + /* Draw end pixel */ + if (gc_private->pen_width == 1) + if (!LineTo (hdc, points[npoints-1].x + 1, points[npoints-1].y)) + g_warning ("gdk_draw_lines: LineTo #2 failed"); +#endif + gdk_gc_postdraw (drawable_private, gc_private); +} diff --git a/gdk/win32/gdkevents-win32.c b/gdk/win32/gdkevents-win32.c new file mode 100644 index 000000000..02c947447 --- /dev/null +++ b/gdk/win32/gdkevents-win32.c @@ -0,0 +1,2963 @@ +/* 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 "gdk.h" +#include "gdkx.h" +#include "gdkprivate.h" +#include "gdkinput.h" +#include "gdkkeysyms.h" + +#define PING() printf("%s: %d\n",__FILE__,__LINE__),fflush(stdout) + +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 + +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 gint gdk_event_apply_filters(MSG *xevent, + GdkEvent *event, + GList *filters); +static gint 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 GdkWindowPrivate *p_grab_window = NULL; /* Window that currently + * holds the pointer grab + */ + +static GdkWindowPrivate *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_event_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; + +LRESULT CALLBACK +gdk_WindowProc(HWND hwnd, + UINT message, + WPARAM wParam, + LPARAM lParam) +{ + GdkEvent event; + GdkEvent *eventp; + MSG msg; + DWORD pos; + gint ret_val; + gboolean ret_val_flag; + + GDK_NOTE (EVENTS, g_print ("gdk_WindowProc: %#x\n", 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); + + if (gdk_event_translate (&event, &msg, &ret_val_flag, &ret_val)) + { +#if 1 + /* Compress configure events */ + if (event.any.type == GDK_CONFIGURE) + { + 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; + } + } +#endif + eventp = gdk_event_new (); + *eventp = event; + + 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 + return DefWindowProc (hwnd, message, wParam, lParam); +} + +/********************************************* + * 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) +{ + if (g_pipe_readable_msg == 0) + g_pipe_readable_msg = RegisterWindowMessage ("g-pipe-readable"); + + 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; + + gdk_ping_msg = RegisterWindowMessage ("gdk-ping"); +} + +/* + *-------------------------------------------------------------- + * 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 +} + +/************************ + * Exposure compression * + ************************/ + +/* I don't bother with exposure compression on Win32. Windows compresses + * WM_PAINT events by itself. + */ + +/************************************************************* + * 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; + + 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: + new_event->key.string = g_strdup (event->key.string); + 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) +{ + GdkWindowPrivate *window_private; + HWND xwindow; + HWND xconfine_to; + HCURSOR xcursor; + GdkWindowPrivate *confine_to_private; + GdkCursorPrivate *cursor_private; + gint return_val; + + g_return_val_if_fail (window != NULL, 0); + + window_private = (GdkWindowPrivate*) window; + confine_to_private = (GdkWindowPrivate*) confine_to; + cursor_private = (GdkCursorPrivate*) cursor; + + xwindow = window_private->xwindow; + + if (!confine_to || confine_to_private->destroyed) + xconfine_to = NULL; + else + xconfine_to = confine_to_private->xwindow; + + 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 (!window_private->destroyed) + { + GDK_NOTE (EVENTS, g_print ("gdk_pointer_grab: %#x %s %#x\n", + xwindow, + (owner_events ? "TRUE" : "FALSE"), + xcursor)); + p_grab_event_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_private; + 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) +{ + GdkWindowPrivate *window_private; + gint return_val; + + g_return_val_if_fail (window != NULL, 0); + + window_private = (GdkWindowPrivate*) window; + + GDK_NOTE (EVENTS, g_print ("gdk_keyboard_grab %#x\n", + window_private->xwindow)); + + if (!window_private->destroyed) + { + k_grab_owner_events = owner_events != 0; + return_val = GrabSuccess; + } + else + return_val = AlreadyGrabbed; + + if (return_val == GrabSuccess) + k_grab_window = window_private; + + 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 gint +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); +} + +static void +synthesize_crossing_events (GdkWindow *window, + MSG *xevent) +{ + GdkEvent *event; + GdkWindowPrivate *window_private = (GdkWindowPrivate *) window; + GdkWindowPrivate *curWnd_private = (GdkWindowPrivate *) curWnd; + + if (curWnd && (curWnd_private->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; + event->crossing.detail = GDK_NOTIFY_UNKNOWN; + + event->crossing.focus = TRUE; /* ??? */ + event->crossing.state = 0; /* ??? */ + + gdk_event_queue_append (event); + } + + if (window_private && (window_private->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; + event->crossing.detail = GDK_NOTIFY_UNKNOWN; + + event->crossing.focus = TRUE; /* ??? */ + event->crossing.state = 0; /* ??? */ + + gdk_event_queue_append (event); + + if (window_private->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); +} + +static gint +gdk_event_translate (GdkEvent *event, + MSG *xevent, + gboolean *ret_val_flagp, + gint *ret_valp) +{ + GdkWindow *window; + GdkWindowPrivate *window_private; + + GdkColormapPrivate *colormap_private; + HWND owner; + DWORD dwStyle; + PAINTSTRUCT paintstruct; + HDC hdc; + HBRUSH hbr; + RECT rect; + POINT pt; + GdkWindowPrivate *curWnd_private; + GdkEventMask mask; + int button; + int i, j; + gchar buf[256]; + gint charcount; + gint return_val; + gboolean flag; + + return_val = FALSE; + + if (ret_val_flagp) + *ret_val_flagp = FALSE; + + if (xevent->message == gdk_ping_msg) + { + /* Messages we post ourselves just to wakeup WaitMessage. */ + return FALSE; + } + + window = gdk_window_lookup (xevent->hwnd); + window_private = (GdkWindowPrivate *) window; + + 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; + } + + 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); + } + else if (xevent->message == WM_NCCREATE + || xevent->message == WM_CREATE + || xevent->message == WM_GETMINMAXINFO + || xevent->message == WM_NCCALCSIZE + || xevent->message == WM_NCDESTROY + || xevent->message == WM_DESTROY) + { + /* Nothing */ + } + return FALSE; + } + + event->any.window = window; + + if (window_private && window_private->destroyed) + { + } + else + { + /* Check for filters for this window */ + GdkFilterReturn result; + result = gdk_event_apply_filters (xevent, event, + window_private + ?window_private->filters + :gdk_default_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 = window_private && !window_private->destroyed; + + /* 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 = window_private && !window_private->destroyed; + + /* 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 = window_private && !window_private->destroyed; + + /* 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_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: + 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", k_grab_window->xwindow)); + event->key.window = (GdkWindow *) k_grab_window; + } + else if (window_private + && (((xevent->message == WM_KEYUP + || xevent->message == WM_SYSKEYUP) + && !(window_private->event_mask & GDK_KEY_RELEASE_MASK)) + || ((xevent->message == WM_KEYDOWN + || xevent->message == WM_SYSKEYDOWN) + && !(window_private->event_mask & GDK_KEY_PRESS_MASK)))) + { + /* Owner window doesn't want it */ + if (k_grab_window != NULL + && k_grab_owner_events) + { + /* Keyboard is grabbed with owner_events TRUE */ + GDK_NOTE (EVENTS, + g_print ("grabbed, owner_events TRUE, doesn't want it, " + "sending to %#x\n", k_grab_window->xwindow)); + event->key.window = (GdkWindow *) k_grab_window; + } + else + { + /* Owner doesn't want it, neither is it grabbed, so + * propagate to parent. + */ + if (window_private->parent == (GdkWindow *) &gdk_root_parent) + break; + gdk_window_unref (window); + window = window_private->parent; + gdk_window_ref (window); + window_private = (GdkWindowPrivate *) window; + GDK_NOTE (EVENTS, + g_print ("not wanted, not grabbed, " + "sending to %#x\n", window_private->xwindow)); + goto keyup_or_down; + } + } + + 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 = 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: + event->key.keyval = GDK_KP_Add; break; + case VK_SEPARATOR: + event->key.keyval = GDK_KP_Separator; break; + case VK_SUBTRACT: + event->key.keyval = GDK_KP_Subtract; break; + case VK_DECIMAL: +#if 0 + event->key.keyval = GDK_KP_Decimal; break; +#else + /* 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; +#endif + 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; + default: + if (xevent->message == WM_SYSKEYDOWN || xevent->message == WM_SYSKEYUP) + { + event->key.keyval = xevent->wParam; + } + else + { + ignore_WM_CHAR = FALSE; + event->key.keyval = GDK_VoidSymbol; + } + 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.window = window; + 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.length = 0; + return_val = window_private && !window_private->destroyed; + event->key.string = NULL; + break; + + 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: + /* This doesn't handle the rather theorethical case that a window + * wants key presses but still wants releases to be propagated, + * for instance. + */ + 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", k_grab_window->xwindow)); + event->key.window = (GdkWindow *) k_grab_window; + } + else if (window_private + && !(window_private->event_mask & (GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK))) + { + /* Owner window doesn't want it */ + if (k_grab_window != NULL + && k_grab_owner_events) + { + /* Keyboard is grabbed with owner_events TRUE */ + GDK_NOTE (EVENTS, + g_print ("grabbed, owner_events TRUE, doesn't want it, " + "sending to %#x\n", k_grab_window->xwindow)); + event->key.window = (GdkWindow *) k_grab_window; + } + else + { + /* Owner doesn't want it, neither is it grabbed, so + * propagate to parent. + */ + if (window_private->parent == (GdkWindow *) &gdk_root_parent) + g_assert_not_reached (); /* Should've been handled above */ + + gdk_window_unref (window); + window = window_private->parent; + gdk_window_ref (window); + window_private = (GdkWindowPrivate *) window; + GDK_NOTE (EVENTS, + g_print ("not wanted, not grabbed, sending to %#x\n", + window_private->xwindow)); + goto wm_char; + } + } + + return_val = window_private && !window_private->destroyed; + if (return_val && (window_private->event_mask & GDK_KEY_RELEASE_MASK)) + { + /* Return the release event, and maybe append the press + * event to the queued_events list (from which it will vbe + * fetched before the release event). + */ + event->key.type = GDK_KEY_RELEASE; + event->key.keyval = xevent->wParam; + event->key.window = window; + 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 (is_AltGr_key) + ; + else 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 (!is_AltGr_key && GetKeyState (VK_MENU) < 0) + event->key.state |= GDK_MOD1_MASK; + event->key.string = g_strdup (" "); + event->key.length = 1; + event->key.string[0] = xevent->wParam; /* ??? */ + + if (window_private->event_mask & GDK_KEY_PRESS_MASK) + { + /* Append also a GDK_KEY_PRESS event to the pushback list. */ + GdkEvent *event2 = gdk_event_copy (event); + event2->key.type = GDK_KEY_PRESS; + charcount = xevent->lParam & 0xFFFF; + if (charcount > sizeof (buf)- 1) + charcount = sizeof (buf) - 1; + g_free (event2->key.string); + event2->key.string = g_malloc (charcount); + for (i = 0; i < charcount; i++) + event2->key.string[i] = event->key.keyval; + event2->key.length = charcount; + + gdk_event_queue_append (event2); + } + } + else if (return_val && (window_private->event_mask & GDK_KEY_PRESS_MASK)) + { + /* Return just the GDK_KEY_PRESS event. */ + event->key.type = GDK_KEY_PRESS; + charcount = xevent->lParam & 0xFFFF; + if (charcount > sizeof (buf)- 1) + charcount = sizeof (buf) - 1; + event->key.keyval = xevent->wParam; + event->key.window = window; + 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 (is_AltGr_key) + ; + else 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 (!is_AltGr_key && GetKeyState (VK_MENU) < 0) + event->key.state |= GDK_MOD1_MASK; + event->key.string = g_malloc (charcount); + for (i = 0; i < charcount; i++) + event->key.string[i] = event->key.keyval; + event->key.length = charcount; + } + else + return_val = FALSE; + is_AltGr_key = FALSE; + break; + + case WM_LBUTTONDOWN: + button = 1; + goto buttondown0; + case WM_MBUTTONDOWN: + button = 2; + goto buttondown0; + case WM_RBUTTONDOWN: + button = 3; + + /* Print debugging info. + */ + buttondown0: + GDK_NOTE (EVENTS, + g_print ("WM_%cBUTTONDOWN: %#x x,y: %d %d button: %d\n", + " LMR"[button], + xevent->hwnd, + LOWORD (xevent->lParam), HIWORD (xevent->lParam), + button)); + + if (window_private + && (window_private->extension_events != 0) + && gdk_input_ignore_core) + { + GDK_NOTE (EVENTS, g_print ("... ignored\n")); + break; + } + + buttondown: + event->button.type = GDK_BUTTON_PRESS; + event->button.window = window; + if (window_private) + mask = window_private->event_mask; + else + mask = 0; /* ??? */ + + 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_event_mask; + if (!(mask & GDK_BUTTON_PRESS_MASK)) + /* Grabber doesn't want it */ + break; + else + event->button.window = (GdkWindow *) p_grab_window; + GDK_NOTE (EVENTS, g_print ("sending to %#x\n", + p_grab_window->xwindow)); + } + else if (window_private + && !(mask & GDK_BUTTON_PRESS_MASK)) + { + /* Owner window doesn't want it */ + if (p_grab_window != NULL + && p_grab_owner_events) + { + /* Pointer is grabbed wíth owner_events TRUE */ + GDK_NOTE (EVENTS, g_print ("grabbed, owner_events TRUE, doesn't want it\n")); + mask = p_grab_event_mask; + if (!(mask & GDK_BUTTON_PRESS_MASK)) + /* Grabber doesn't want it either */ + break; + else + event->button.window = (GdkWindow *) p_grab_window; + GDK_NOTE (EVENTS, g_print ("sending to %#x\n", + p_grab_window->xwindow)); + } + else + { + /* Owner doesn't want it, neither is it grabbed, so + * propagate to parent. + */ + /* Yes, this code is duplicated twice below. So shoot me. */ + if (window_private->parent == (GdkWindow *) &gdk_root_parent) + break; + pt.x = LOWORD (xevent->lParam); + pt.y = HIWORD (xevent->lParam); + ClientToScreen (window_private->xwindow, &pt); + gdk_window_unref (window); + window = window_private->parent; + gdk_window_ref (window); + window_private = (GdkWindowPrivate *) window; + ScreenToClient (window_private->xwindow, &pt); + xevent->lParam = MAKELPARAM (pt.x, pt.y); + goto buttondown; /* What did Dijkstra say? */ + } + } + + /* Emulate X11's automatic active grab */ + if (!p_grab_window) + { + /* No explicit active grab, let's start one automatically */ + GDK_NOTE (EVENTS, g_print ("automatic grab started\n")); + gdk_pointer_grab (window, TRUE, window_private->event_mask, + NULL, NULL, 0); + p_grab_automatic = TRUE; + } + + if (window != curWnd) + synthesize_crossing_events (window, xevent); + + event->button.time = xevent->time; + event->button.x = LOWORD (xevent->lParam); + event->button.y = HIWORD (xevent->lParam); + event->button.x_root = (gfloat)xevent->pt.x; + event->button.y_root = (gfloat)xevent->pt.y; + event->button.pressure = 0.5; + event->button.xtilt = 0; + event->button.ytilt = 0; + event->button.state = 0; + if (xevent->wParam & MK_CONTROL) + event->button.state |= GDK_CONTROL_MASK; + if (xevent->wParam & MK_LBUTTON) + event->button.state |= GDK_BUTTON1_MASK; + if (xevent->wParam & MK_MBUTTON) + event->button.state |= GDK_BUTTON2_MASK; + if (xevent->wParam & MK_RBUTTON) + event->button.state |= GDK_BUTTON3_MASK; + if (xevent->wParam & MK_SHIFT) + event->button.state |= GDK_SHIFT_MASK; + if (GetKeyState (VK_MENU) < 0) + event->button.state |= GDK_MOD1_MASK; + if (GetKeyState (VK_CAPITAL) & 0x1) + event->button.state |= GDK_LOCK_MASK; + 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 = window_private && !window_private->destroyed; + if (return_val + && p_grab_window != NULL + && event->any.window == (GdkWindow *) p_grab_window + && p_grab_window != window_private) + { + /* Translate coordinates to grabber */ + pt.x = event->button.x; + pt.y = event->button.y; + ClientToScreen (window_private->xwindow, &pt); + ScreenToClient (p_grab_window->xwindow, &pt); + event->button.x = pt.x; + event->button.y = pt.y; + GDK_NOTE (EVENTS, g_print ("New coords are +%d+%d\n", pt.x, pt.y)); + } + break; + + case WM_LBUTTONUP: + button = 1; + goto buttonup0; + case WM_MBUTTONUP: + button = 2; + goto buttonup0; + case WM_RBUTTONUP: + button = 3; + + /* Print debugging info. + */ + buttonup0: + GDK_NOTE (EVENTS, + g_print ("WM_%cBUTTONUP: %#x x,y: %d %d button: %d\n", + " LMR"[button], + xevent->hwnd, + LOWORD (xevent->lParam), HIWORD (xevent->lParam), + button)); + + if (window_private + && (window_private->extension_events != 0) + && gdk_input_ignore_core) + { + GDK_NOTE (EVENTS, g_print ("... ignored\n")); + break; + } + + buttonup: + event->button.type = GDK_BUTTON_RELEASE; + event->button.window = window; + if (window_private) + mask = window_private->event_mask; + else + mask = 0; + + 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_event_mask; + if (!(mask & GDK_BUTTON_RELEASE_MASK)) + /* Grabber doesn't want it */ + break; + else + event->button.window = (GdkWindow *) p_grab_window; + GDK_NOTE (EVENTS, g_print ("sending to %#x\n", + p_grab_window->xwindow)); + } + else if (window_private + && !(mask & GDK_BUTTON_RELEASE_MASK)) + { + /* Owner window doesn't want it */ + if (p_grab_window != NULL + && p_grab_owner_events) + { + /* Pointer is grabbed wíth owner_events TRUE */ + GDK_NOTE (EVENTS, g_print ("grabbed, owner_events TRUE, doesn't want it\n")); + mask = p_grab_event_mask; + if (!(mask & GDK_BUTTON_RELEASE_MASK)) + /* Grabber doesn't want it */ + break; + else + event->button.window = (GdkWindow *) p_grab_window; + GDK_NOTE (EVENTS, g_print ("sending to %#x\n", + p_grab_window->xwindow)); + } + else + { + /* Owner doesn't want it, neither is it grabbed, so + * propagate to parent. + */ + if (window_private->parent == (GdkWindow *) &gdk_root_parent) + break; + pt.x = LOWORD (xevent->lParam); + pt.y = HIWORD (xevent->lParam); + ClientToScreen (window_private->xwindow, &pt); + gdk_window_unref (window); + window = window_private->parent; + gdk_window_ref (window); + window_private = (GdkWindowPrivate *) window; + ScreenToClient (window_private->xwindow, &pt); + xevent->lParam = MAKELPARAM (pt.x, pt.y); + goto buttonup; + } + } + + if (window != curWnd) + synthesize_crossing_events (window, xevent); + + event->button.time = xevent->time; + event->button.x = LOWORD (xevent->lParam); + event->button.y = HIWORD (xevent->lParam); + event->button.x_root = (gfloat)xevent->pt.x; + event->button.y_root = (gfloat)xevent->pt.y; + event->button.pressure = 0.5; + event->button.xtilt = 0; + event->button.ytilt = 0; + event->button.state = 0; + if (xevent->wParam & MK_CONTROL) + event->button.state |= GDK_CONTROL_MASK; + if (xevent->wParam & MK_LBUTTON) + event->button.state |= GDK_BUTTON1_MASK; + if (xevent->wParam & MK_MBUTTON) + event->button.state |= GDK_BUTTON2_MASK; + if (xevent->wParam & MK_RBUTTON) + event->button.state |= GDK_BUTTON3_MASK; + if (xevent->wParam & MK_SHIFT) + event->button.state |= GDK_SHIFT_MASK; + event->button.button = button; + event->button.source = GDK_SOURCE_MOUSE; + event->button.deviceid = GDK_CORE_POINTER; + return_val = window_private && !window_private->destroyed; + if (return_val + && p_grab_window != NULL + && event->any.window == (GdkWindow *) p_grab_window + && p_grab_window != window_private) + { + /* Translate coordinates to grabber */ + pt.x = event->button.x; + pt.y = event->button.y; + ClientToScreen (window_private->xwindow, &pt); + ScreenToClient (p_grab_window->xwindow, &pt); + event->button.x = pt.x; + event->button.y = pt.y; + GDK_NOTE (EVENTS, g_print ("New coords are +%d+%d\n", pt.x, pt.y)); + } + 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: + /* Print debugging info. + */ + GDK_NOTE (EVENTS, + g_print ("WM_MOUSEMOVE: %#x %#x +%d+%d\n", + xevent->hwnd, xevent->wParam, + LOWORD (xevent->lParam), HIWORD (xevent->lParam))); + +#if 0 + /* Try hard not to generate events for windows that shouldn't + get any. This is hard because we don't want pushbuttons to + highlight when the cursor moves over them if the window is + inactive. We dont want tooltips windows to be active. OTOH, + also menus are popup windows, but they definitely should + get events. Aw shit. Skip this. + */ + dwStyle = GetWindowLong (xevent->hwnd, GWL_STYLE); + if (active == NULL || + !(active == xevent->hwnd + || (dwStyle & WS_POPUP) + || IsChild (active, xevent->hwnd))) + break; +#else + { /* HB: only process mouse move messages + * if we own the active window. + */ + DWORD ProcessID_ActWin; + DWORD ProcessID_this; + + GetWindowThreadProcessId(GetActiveWindow(), &ProcessID_ActWin); + GetWindowThreadProcessId(xevent->hwnd, &ProcessID_this); + if (ProcessID_ActWin != ProcessID_this) + break; + } +#endif + if (window != curWnd) + synthesize_crossing_events (window, xevent); + + if (window_private + && (window_private->extension_events != 0) + && gdk_input_ignore_core) + { + GDK_NOTE (EVENTS, g_print ("... ignored\n")); + break; + } + + mousemotion: + event->motion.type = GDK_MOTION_NOTIFY; + event->motion.window = window; + if (window_private) + mask = window_private->event_mask; + else + mask = 0; + + if (p_grab_window + && !p_grab_owner_events) + { + /* Pointer is grabbed with owner_events FALSE */ + GDK_NOTE (EVENTS, + g_print ("grabbed, owner_events FALSE\n")); + mask = p_grab_event_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)))) + break; + else + event->motion.window = (GdkWindow *) p_grab_window; + GDK_NOTE (EVENTS, g_print ("sending to %#x\n", + p_grab_window->xwindow)); + } + else if (window_private + && !((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 window doesn't want it */ + if (p_grab_window != NULL + && p_grab_owner_events) + { + /* Pointer is grabbed wíth owner_events TRUE */ + GDK_NOTE (EVENTS, g_print ("grabbed, owner_events TRUE, doesn't want it\n")); + mask = p_grab_event_mask; + if (!((p_grab_event_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 */ + break; + else + event->motion.window = (GdkWindow *) p_grab_window; + GDK_NOTE (EVENTS, g_print ("sending to %#x\n", + p_grab_window->xwindow)); + } + else + { + /* Owner doesn't want it, neither is it grabbed, so + * propagate to parent. + */ + if (window_private->parent == (GdkWindow *) &gdk_root_parent) + break; + pt.x = LOWORD (xevent->lParam); + pt.y = HIWORD (xevent->lParam); + ClientToScreen (window_private->xwindow, &pt); + gdk_window_unref (window); + window = window_private->parent; + gdk_window_ref (window); + window_private = (GdkWindowPrivate *) window; + ScreenToClient (window_private->xwindow, &pt); + xevent->lParam = MAKELPARAM (pt.x, pt.y); + GDK_NOTE (EVENTS, g_print ("propagating to %#x\n", + window_private->xwindow)); + goto mousemotion; + } + } + + event->motion.time = xevent->time; + 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->button.state = 0; + if (xevent->wParam & MK_CONTROL) + event->button.state |= GDK_CONTROL_MASK; + if (xevent->wParam & MK_LBUTTON) + event->button.state |= GDK_BUTTON1_MASK; + if (xevent->wParam & MK_MBUTTON) + event->button.state |= GDK_BUTTON2_MASK; + if (xevent->wParam & MK_RBUTTON) + event->button.state |= GDK_BUTTON3_MASK; + if (xevent->wParam & MK_SHIFT) + event->button.state |= GDK_SHIFT_MASK; + if (mask & GDK_POINTER_MOTION_HINT_MASK) + event->motion.is_hint = NotifyHint; + else + event->motion.is_hint = NotifyNormal; + event->motion.source = GDK_SOURCE_MOUSE; + event->motion.deviceid = GDK_CORE_POINTER; + + return_val = window_private && !window_private->destroyed; + if (return_val + && p_grab_window != NULL + && event->any.window == (GdkWindow *) p_grab_window + && p_grab_window != window_private) + { + /* Translate coordinates to grabber */ + pt.x = event->motion.x; + pt.y = event->motion.y; + ClientToScreen (window_private->xwindow, &pt); + ScreenToClient (p_grab_window->xwindow, &pt); + event->motion.x = pt.x; + event->motion.y = pt.y; + GDK_NOTE (EVENTS, g_print ("New coords are +%d+%d\n", pt.x, pt.y)); + } + break; + + case WM_NCMOUSEMOVE: + /* Print debugging info. */ + GDK_NOTE (EVENTS, + g_print ("WM_NCMOUSEMOVE: %#x x,y: %d %d\n", + xevent->hwnd, + LOWORD (xevent->lParam), HIWORD (xevent->lParam))); +#if 0 + if (active == NULL || active != xevent->hwnd) + break; +#endif + curWnd_private = (GdkWindowPrivate *) curWnd; + if (curWnd != NULL + && (curWnd_private->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_UNKNOWN; + + event->crossing.focus = TRUE; /* ??? */ + event->crossing.state = 0; /* ??? */ + gdk_window_unref (curWnd); + curWnd = NULL; + + return_val = TRUE; + } + break; + + case WM_SETFOCUS: + case WM_KILLFOCUS: + if (window_private + && !(window_private->event_mask & GDK_FOCUS_CHANGE_MASK)) + break; + + GDK_NOTE (EVENTS, g_print ("WM_%sFOCUS: %#x\n", + (xevent->message == WM_SETFOCUS ? "SET" : "KILL"), + xevent->hwnd)); + + event->focus_change.type = GDK_FOCUS_CHANGE; + event->focus_change.window = window; + event->focus_change.in = (xevent->message == WM_SETFOCUS); + return_val = window_private && !window_private->destroyed; + break; +#if 0 + case WM_ACTIVATE: + GDK_NOTE (EVENTS, g_print ("WM_ACTIVATE: %#x %d\n", + xevent->hwnd, LOWORD (xevent->wParam))); + if (LOWORD (xevent->wParam) == WA_INACTIVE) + active = (HWND) xevent->lParam; + else + active = xevent->hwnd; + break; +#endif + case WM_ERASEBKGND: + GDK_NOTE (EVENTS, g_print ("WM_ERASEBKGND: %#x dc %#x\n", + xevent->hwnd, xevent->wParam)); + + if (!window_private || window_private->destroyed) + break; + colormap_private = (GdkColormapPrivate *) window_private->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->bg_type == GDK_WIN32_BG_TRANSPARENT) + break; + + if (window_private->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_private + && window_private->bg_type == GDK_WIN32_BG_PARENT_RELATIVE) + window_private = (GdkWindowPrivate *) window_private->parent; + } + + if (window_private->bg_type == GDK_WIN32_BG_PIXEL) + { + COLORREF bg; + GDK_NOTE (EVENTS, g_print ("... BG_PIXEL %s\n", + gdk_color_to_string (&window_private->bg_pixel))); + GetClipBox (hdc, &rect); +#ifdef MULTIPLE_WINDOW_CLASSES + bg = PALETTEINDEX (window_private->bg_pixel.pixel); +#else + bg = GetNearestColor (hdc, RGB (window_private->bg_pixel.red >> 8, + window_private->bg_pixel.green >> 8, + window_private->bg_pixel.blue >> 8)); +#endif + 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->bg_type == GDK_WIN32_BG_PIXMAP) + { + GdkPixmapPrivate *pixmap_private; + HDC bgdc; + HGDIOBJ oldbitmap; + + pixmap_private = (GdkPixmapPrivate *) window_private->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")); +#ifdef MULTIPLE_WINDOW_CLASSES + hbr = (HBRUSH) GetClassLong (window_private->xwindow, + GCL_HBRBACKGROUND); +#else + hbr = GetStockObject (BLACK_BRUSH); +#endif + GetClipBox (hdc, &rect); + if (!FillRect (hdc, &rect, hbr)) + g_warning ("WM_ERASEBKGND: FillRect failed"); + } + break; + + case WM_PAINT: + GDK_NOTE (EVENTS, g_print ("WM_PAINT: %#x\n", xevent->hwnd)); + hdc = BeginPaint (xevent->hwnd, &paintstruct); + + /* Print debugging info. + */ + 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_private->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 = 1; + + return_val = window_private && !window_private->destroyed; + break; + +#ifndef MULTIPLE_WINDOW_CLASSES + case WM_SETCURSOR: + GDK_NOTE (EVENTS, g_print ("WM_SETCURSOR: %#x %#x %#x\n", + xevent->hwnd, + LOWORD (xevent->lParam), HIWORD (xevent->lParam))); + + return_val = FALSE; + if (LOWORD (xevent->lParam) != HTCLIENT) + break; + if (p_grab_window != NULL && p_grab_cursor != NULL) + SetCursor (p_grab_cursor); + else if (window_private + && !window_private->destroyed + && window_private->xcursor) + SetCursor (window_private->xcursor); + *ret_val_flagp = TRUE; + *ret_valp = FALSE; + break; +#endif + +#if 0 + case WM_QUERYOPEN: + GDK_NOTE (EVENTS, g_print ("WM_QUERYOPEN: %#x\n", + xevent->hwnd)); + *ret_val_flagp = TRUE; + *ret_valp = TRUE; + + if (window_private + && !(window_private->event_mask & GDK_STRUCTURE_MASK)) + break; + + event->any.type = GDK_MAP; + event->any.window = window; + + return_val = window_private && !window_private->destroyed; + break; +#endif + +#if 1 + case WM_SHOWWINDOW: + /* Print debugging info. + */ + GDK_NOTE (EVENTS, g_print ("WM_SHOWWINDOW: %#x %d\n", + xevent->hwnd, + xevent->wParam)); + + if (window_private + && !(window_private->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_private) + gdk_pointer_ungrab (xevent->time); + + if (event->any.type == GDK_UNMAP + && k_grab_window == window_private) + gdk_keyboard_ungrab (xevent->time); + + return_val = window_private && !window_private->destroyed; + break; +#endif + case WM_SIZE: + /* Print debugging info. + */ + 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_private->event_mask & GDK_STRUCTURE_MASK)) + break; + if (window_private != NULL + && xevent->wParam == SIZE_MINIMIZED) + { +#if 1 + event->any.type = GDK_UNMAP; + event->any.window = window; + + if (p_grab_window == window_private) + gdk_pointer_ungrab (xevent->time); + + if (k_grab_window == window_private) + gdk_keyboard_ungrab (xevent->time); + + return_val = !window_private->destroyed; +#endif + } + else if (window_private != NULL + && (xevent->wParam == SIZE_RESTORED + || xevent->wParam == SIZE_MAXIMIZED) +#if 1 + && window_private->window_type != 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->x = event->configure.x; + window_private->y = event->configure.y; + window_private->width = event->configure.width; + window_private->height = event->configure.height; + if (window_private->resize_count > 1) + window_private->resize_count -= 1; + + return_val = !window_private->destroyed; + if (return_val + && window_private->extension_events != 0 + && gdk_input_vtable.configure_event) + gdk_input_vtable.configure_event (&event->configure, window); + } + break; + + case WM_SIZING: + GDK_NOTE (EVENTS, g_print ("WM_SIZING: %#x\n", xevent->hwnd)); + if (ret_val_flagp == NULL) + g_warning ("ret_val_flagp is NULL but we got a WM_SIZING?"); + else if (window_private != NULL + && window_private->hint_flags & + (GDK_HINT_MIN_SIZE | GDK_HINT_MAX_SIZE)) + { + LPRECT lprc = (LPRECT) xevent->lParam; + + if (window_private->hint_flags & GDK_HINT_MIN_SIZE) + { + gint w = lprc->right - lprc->left; + gint h = lprc->bottom - lprc->top; + + if (w < window_private->hint_min_width) + { + if (xevent->wParam == WMSZ_BOTTOMLEFT + || xevent->wParam == WMSZ_LEFT + || xevent->wParam == WMSZ_TOPLEFT) + lprc->left = lprc->right - window_private->hint_min_width; + else + lprc->right = lprc->left + window_private->hint_min_width; + *ret_val_flagp = TRUE; + *ret_valp = TRUE; + } + if (h < window_private->hint_min_height) + { + if (xevent->wParam == WMSZ_BOTTOMLEFT + || xevent->wParam == WMSZ_BOTTOM + || xevent->wParam == WMSZ_BOTTOMRIGHT) + lprc->bottom = lprc->top + window_private->hint_min_height; + else + lprc->top = lprc->bottom - window_private->hint_min_height; + *ret_val_flagp = TRUE; + *ret_valp = TRUE; + } + } + if (window_private->hint_flags & GDK_HINT_MAX_SIZE) + { + gint w = lprc->right - lprc->left; + gint h = lprc->bottom - lprc->top; + + if (w > window_private->hint_max_width) + { + if (xevent->wParam == WMSZ_BOTTOMLEFT + || xevent->wParam == WMSZ_LEFT + || xevent->wParam == WMSZ_TOPLEFT) + lprc->left = lprc->right - window_private->hint_max_width; + else + lprc->right = lprc->left + window_private->hint_max_width; + *ret_val_flagp = TRUE; + *ret_valp = TRUE; + } + if (h > window_private->hint_max_height) + { + if (xevent->wParam == WMSZ_BOTTOMLEFT + || xevent->wParam == WMSZ_BOTTOM + || xevent->wParam == WMSZ_BOTTOMRIGHT) + lprc->bottom = lprc->top + window_private->hint_max_height; + else + lprc->top = lprc->bottom - window_private->hint_max_height; + *ret_val_flagp = TRUE; + *ret_valp = TRUE; + } + } + } + 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_private->event_mask & GDK_STRUCTURE_MASK)) + break; + if (window_private != NULL + && window_private->window_type != 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->x = event->configure.x; + window_private->y = event->configure.y; + window_private->width = event->configure.width; + window_private->height = event->configure.height; + + return_val = !window_private->destroyed; + } + 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 = window_private && !window_private->destroyed; + 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 = window_private && !window_private->destroyed; +#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_private) + gdk_pointer_ungrab (xevent->time); + + if (k_grab_window == window_private) + gdk_keyboard_ungrab (xevent->time); + + return_val = window_private && !window_private->destroyed; + break; + + /* 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))); + wintab: + return_val = gdk_input_vtable.other_event(event, xevent); + break; + } + +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); + } + 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; + + GDK_NOTE (EVENTS, g_print ("gdk_events_queue: %s\n", + (queued_events ? "yes" : "none"))); + + while (!gdk_event_queue_find_first() + && PeekMessage (&msg, NULL, 0, 0, PM_REMOVE)) + { + GDK_NOTE (EVENTS, g_print ("gdk_events_queue: got event\n")); + TranslateMessage (&msg); + + 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 + { + DefWindowProc (msg.hwnd, msg.message, msg.wParam, msg.lParam); + gdk_event_queue_remove_link (node); + g_list_free_1 (node); + gdk_event_free (event); + } + } +} + +static gboolean +gdk_event_prepare (gpointer source_data, + GTimeVal *current_time, + gint *timeout) +{ + MSG msg; + gboolean retval; + + GDK_THREADS_ENTER (); + + *timeout = -1; + + GDK_NOTE (EVENTS, g_print ("gdk_event_prepare\n")); + + 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_NOTE (EVENTS, g_print ("gdk_event_check\n")); + + 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_NOTE (EVENTS, g_print ("gdk_event_dispatch\n")); + + 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); +} + +/* Sends a ClientMessage to all toplevel client windows */ +gboolean +gdk_event_send_client_message (GdkEvent *event, guint32 xid) +{ + /* XXX */ + return FALSE; +} + +void +gdk_event_send_clientmessage_toall (GdkEvent *event) +{ + /* XXX */ +} + diff --git a/gdk/win32/gdkevents.c b/gdk/win32/gdkevents.c new file mode 100644 index 000000000..02c947447 --- /dev/null +++ b/gdk/win32/gdkevents.c @@ -0,0 +1,2963 @@ +/* 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 "gdk.h" +#include "gdkx.h" +#include "gdkprivate.h" +#include "gdkinput.h" +#include "gdkkeysyms.h" + +#define PING() printf("%s: %d\n",__FILE__,__LINE__),fflush(stdout) + +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 + +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 gint gdk_event_apply_filters(MSG *xevent, + GdkEvent *event, + GList *filters); +static gint 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 GdkWindowPrivate *p_grab_window = NULL; /* Window that currently + * holds the pointer grab + */ + +static GdkWindowPrivate *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_event_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; + +LRESULT CALLBACK +gdk_WindowProc(HWND hwnd, + UINT message, + WPARAM wParam, + LPARAM lParam) +{ + GdkEvent event; + GdkEvent *eventp; + MSG msg; + DWORD pos; + gint ret_val; + gboolean ret_val_flag; + + GDK_NOTE (EVENTS, g_print ("gdk_WindowProc: %#x\n", 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); + + if (gdk_event_translate (&event, &msg, &ret_val_flag, &ret_val)) + { +#if 1 + /* Compress configure events */ + if (event.any.type == GDK_CONFIGURE) + { + 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; + } + } +#endif + eventp = gdk_event_new (); + *eventp = event; + + 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 + return DefWindowProc (hwnd, message, wParam, lParam); +} + +/********************************************* + * 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) +{ + if (g_pipe_readable_msg == 0) + g_pipe_readable_msg = RegisterWindowMessage ("g-pipe-readable"); + + 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; + + gdk_ping_msg = RegisterWindowMessage ("gdk-ping"); +} + +/* + *-------------------------------------------------------------- + * 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 +} + +/************************ + * Exposure compression * + ************************/ + +/* I don't bother with exposure compression on Win32. Windows compresses + * WM_PAINT events by itself. + */ + +/************************************************************* + * 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; + + 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: + new_event->key.string = g_strdup (event->key.string); + 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) +{ + GdkWindowPrivate *window_private; + HWND xwindow; + HWND xconfine_to; + HCURSOR xcursor; + GdkWindowPrivate *confine_to_private; + GdkCursorPrivate *cursor_private; + gint return_val; + + g_return_val_if_fail (window != NULL, 0); + + window_private = (GdkWindowPrivate*) window; + confine_to_private = (GdkWindowPrivate*) confine_to; + cursor_private = (GdkCursorPrivate*) cursor; + + xwindow = window_private->xwindow; + + if (!confine_to || confine_to_private->destroyed) + xconfine_to = NULL; + else + xconfine_to = confine_to_private->xwindow; + + 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 (!window_private->destroyed) + { + GDK_NOTE (EVENTS, g_print ("gdk_pointer_grab: %#x %s %#x\n", + xwindow, + (owner_events ? "TRUE" : "FALSE"), + xcursor)); + p_grab_event_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_private; + 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) +{ + GdkWindowPrivate *window_private; + gint return_val; + + g_return_val_if_fail (window != NULL, 0); + + window_private = (GdkWindowPrivate*) window; + + GDK_NOTE (EVENTS, g_print ("gdk_keyboard_grab %#x\n", + window_private->xwindow)); + + if (!window_private->destroyed) + { + k_grab_owner_events = owner_events != 0; + return_val = GrabSuccess; + } + else + return_val = AlreadyGrabbed; + + if (return_val == GrabSuccess) + k_grab_window = window_private; + + 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 gint +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); +} + +static void +synthesize_crossing_events (GdkWindow *window, + MSG *xevent) +{ + GdkEvent *event; + GdkWindowPrivate *window_private = (GdkWindowPrivate *) window; + GdkWindowPrivate *curWnd_private = (GdkWindowPrivate *) curWnd; + + if (curWnd && (curWnd_private->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; + event->crossing.detail = GDK_NOTIFY_UNKNOWN; + + event->crossing.focus = TRUE; /* ??? */ + event->crossing.state = 0; /* ??? */ + + gdk_event_queue_append (event); + } + + if (window_private && (window_private->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; + event->crossing.detail = GDK_NOTIFY_UNKNOWN; + + event->crossing.focus = TRUE; /* ??? */ + event->crossing.state = 0; /* ??? */ + + gdk_event_queue_append (event); + + if (window_private->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); +} + +static gint +gdk_event_translate (GdkEvent *event, + MSG *xevent, + gboolean *ret_val_flagp, + gint *ret_valp) +{ + GdkWindow *window; + GdkWindowPrivate *window_private; + + GdkColormapPrivate *colormap_private; + HWND owner; + DWORD dwStyle; + PAINTSTRUCT paintstruct; + HDC hdc; + HBRUSH hbr; + RECT rect; + POINT pt; + GdkWindowPrivate *curWnd_private; + GdkEventMask mask; + int button; + int i, j; + gchar buf[256]; + gint charcount; + gint return_val; + gboolean flag; + + return_val = FALSE; + + if (ret_val_flagp) + *ret_val_flagp = FALSE; + + if (xevent->message == gdk_ping_msg) + { + /* Messages we post ourselves just to wakeup WaitMessage. */ + return FALSE; + } + + window = gdk_window_lookup (xevent->hwnd); + window_private = (GdkWindowPrivate *) window; + + 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; + } + + 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); + } + else if (xevent->message == WM_NCCREATE + || xevent->message == WM_CREATE + || xevent->message == WM_GETMINMAXINFO + || xevent->message == WM_NCCALCSIZE + || xevent->message == WM_NCDESTROY + || xevent->message == WM_DESTROY) + { + /* Nothing */ + } + return FALSE; + } + + event->any.window = window; + + if (window_private && window_private->destroyed) + { + } + else + { + /* Check for filters for this window */ + GdkFilterReturn result; + result = gdk_event_apply_filters (xevent, event, + window_private + ?window_private->filters + :gdk_default_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 = window_private && !window_private->destroyed; + + /* 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 = window_private && !window_private->destroyed; + + /* 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 = window_private && !window_private->destroyed; + + /* 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_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: + 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", k_grab_window->xwindow)); + event->key.window = (GdkWindow *) k_grab_window; + } + else if (window_private + && (((xevent->message == WM_KEYUP + || xevent->message == WM_SYSKEYUP) + && !(window_private->event_mask & GDK_KEY_RELEASE_MASK)) + || ((xevent->message == WM_KEYDOWN + || xevent->message == WM_SYSKEYDOWN) + && !(window_private->event_mask & GDK_KEY_PRESS_MASK)))) + { + /* Owner window doesn't want it */ + if (k_grab_window != NULL + && k_grab_owner_events) + { + /* Keyboard is grabbed with owner_events TRUE */ + GDK_NOTE (EVENTS, + g_print ("grabbed, owner_events TRUE, doesn't want it, " + "sending to %#x\n", k_grab_window->xwindow)); + event->key.window = (GdkWindow *) k_grab_window; + } + else + { + /* Owner doesn't want it, neither is it grabbed, so + * propagate to parent. + */ + if (window_private->parent == (GdkWindow *) &gdk_root_parent) + break; + gdk_window_unref (window); + window = window_private->parent; + gdk_window_ref (window); + window_private = (GdkWindowPrivate *) window; + GDK_NOTE (EVENTS, + g_print ("not wanted, not grabbed, " + "sending to %#x\n", window_private->xwindow)); + goto keyup_or_down; + } + } + + 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 = 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: + event->key.keyval = GDK_KP_Add; break; + case VK_SEPARATOR: + event->key.keyval = GDK_KP_Separator; break; + case VK_SUBTRACT: + event->key.keyval = GDK_KP_Subtract; break; + case VK_DECIMAL: +#if 0 + event->key.keyval = GDK_KP_Decimal; break; +#else + /* 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; +#endif + 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; + default: + if (xevent->message == WM_SYSKEYDOWN || xevent->message == WM_SYSKEYUP) + { + event->key.keyval = xevent->wParam; + } + else + { + ignore_WM_CHAR = FALSE; + event->key.keyval = GDK_VoidSymbol; + } + 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.window = window; + 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.length = 0; + return_val = window_private && !window_private->destroyed; + event->key.string = NULL; + break; + + 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: + /* This doesn't handle the rather theorethical case that a window + * wants key presses but still wants releases to be propagated, + * for instance. + */ + 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", k_grab_window->xwindow)); + event->key.window = (GdkWindow *) k_grab_window; + } + else if (window_private + && !(window_private->event_mask & (GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK))) + { + /* Owner window doesn't want it */ + if (k_grab_window != NULL + && k_grab_owner_events) + { + /* Keyboard is grabbed with owner_events TRUE */ + GDK_NOTE (EVENTS, + g_print ("grabbed, owner_events TRUE, doesn't want it, " + "sending to %#x\n", k_grab_window->xwindow)); + event->key.window = (GdkWindow *) k_grab_window; + } + else + { + /* Owner doesn't want it, neither is it grabbed, so + * propagate to parent. + */ + if (window_private->parent == (GdkWindow *) &gdk_root_parent) + g_assert_not_reached (); /* Should've been handled above */ + + gdk_window_unref (window); + window = window_private->parent; + gdk_window_ref (window); + window_private = (GdkWindowPrivate *) window; + GDK_NOTE (EVENTS, + g_print ("not wanted, not grabbed, sending to %#x\n", + window_private->xwindow)); + goto wm_char; + } + } + + return_val = window_private && !window_private->destroyed; + if (return_val && (window_private->event_mask & GDK_KEY_RELEASE_MASK)) + { + /* Return the release event, and maybe append the press + * event to the queued_events list (from which it will vbe + * fetched before the release event). + */ + event->key.type = GDK_KEY_RELEASE; + event->key.keyval = xevent->wParam; + event->key.window = window; + 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 (is_AltGr_key) + ; + else 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 (!is_AltGr_key && GetKeyState (VK_MENU) < 0) + event->key.state |= GDK_MOD1_MASK; + event->key.string = g_strdup (" "); + event->key.length = 1; + event->key.string[0] = xevent->wParam; /* ??? */ + + if (window_private->event_mask & GDK_KEY_PRESS_MASK) + { + /* Append also a GDK_KEY_PRESS event to the pushback list. */ + GdkEvent *event2 = gdk_event_copy (event); + event2->key.type = GDK_KEY_PRESS; + charcount = xevent->lParam & 0xFFFF; + if (charcount > sizeof (buf)- 1) + charcount = sizeof (buf) - 1; + g_free (event2->key.string); + event2->key.string = g_malloc (charcount); + for (i = 0; i < charcount; i++) + event2->key.string[i] = event->key.keyval; + event2->key.length = charcount; + + gdk_event_queue_append (event2); + } + } + else if (return_val && (window_private->event_mask & GDK_KEY_PRESS_MASK)) + { + /* Return just the GDK_KEY_PRESS event. */ + event->key.type = GDK_KEY_PRESS; + charcount = xevent->lParam & 0xFFFF; + if (charcount > sizeof (buf)- 1) + charcount = sizeof (buf) - 1; + event->key.keyval = xevent->wParam; + event->key.window = window; + 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 (is_AltGr_key) + ; + else 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 (!is_AltGr_key && GetKeyState (VK_MENU) < 0) + event->key.state |= GDK_MOD1_MASK; + event->key.string = g_malloc (charcount); + for (i = 0; i < charcount; i++) + event->key.string[i] = event->key.keyval; + event->key.length = charcount; + } + else + return_val = FALSE; + is_AltGr_key = FALSE; + break; + + case WM_LBUTTONDOWN: + button = 1; + goto buttondown0; + case WM_MBUTTONDOWN: + button = 2; + goto buttondown0; + case WM_RBUTTONDOWN: + button = 3; + + /* Print debugging info. + */ + buttondown0: + GDK_NOTE (EVENTS, + g_print ("WM_%cBUTTONDOWN: %#x x,y: %d %d button: %d\n", + " LMR"[button], + xevent->hwnd, + LOWORD (xevent->lParam), HIWORD (xevent->lParam), + button)); + + if (window_private + && (window_private->extension_events != 0) + && gdk_input_ignore_core) + { + GDK_NOTE (EVENTS, g_print ("... ignored\n")); + break; + } + + buttondown: + event->button.type = GDK_BUTTON_PRESS; + event->button.window = window; + if (window_private) + mask = window_private->event_mask; + else + mask = 0; /* ??? */ + + 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_event_mask; + if (!(mask & GDK_BUTTON_PRESS_MASK)) + /* Grabber doesn't want it */ + break; + else + event->button.window = (GdkWindow *) p_grab_window; + GDK_NOTE (EVENTS, g_print ("sending to %#x\n", + p_grab_window->xwindow)); + } + else if (window_private + && !(mask & GDK_BUTTON_PRESS_MASK)) + { + /* Owner window doesn't want it */ + if (p_grab_window != NULL + && p_grab_owner_events) + { + /* Pointer is grabbed wíth owner_events TRUE */ + GDK_NOTE (EVENTS, g_print ("grabbed, owner_events TRUE, doesn't want it\n")); + mask = p_grab_event_mask; + if (!(mask & GDK_BUTTON_PRESS_MASK)) + /* Grabber doesn't want it either */ + break; + else + event->button.window = (GdkWindow *) p_grab_window; + GDK_NOTE (EVENTS, g_print ("sending to %#x\n", + p_grab_window->xwindow)); + } + else + { + /* Owner doesn't want it, neither is it grabbed, so + * propagate to parent. + */ + /* Yes, this code is duplicated twice below. So shoot me. */ + if (window_private->parent == (GdkWindow *) &gdk_root_parent) + break; + pt.x = LOWORD (xevent->lParam); + pt.y = HIWORD (xevent->lParam); + ClientToScreen (window_private->xwindow, &pt); + gdk_window_unref (window); + window = window_private->parent; + gdk_window_ref (window); + window_private = (GdkWindowPrivate *) window; + ScreenToClient (window_private->xwindow, &pt); + xevent->lParam = MAKELPARAM (pt.x, pt.y); + goto buttondown; /* What did Dijkstra say? */ + } + } + + /* Emulate X11's automatic active grab */ + if (!p_grab_window) + { + /* No explicit active grab, let's start one automatically */ + GDK_NOTE (EVENTS, g_print ("automatic grab started\n")); + gdk_pointer_grab (window, TRUE, window_private->event_mask, + NULL, NULL, 0); + p_grab_automatic = TRUE; + } + + if (window != curWnd) + synthesize_crossing_events (window, xevent); + + event->button.time = xevent->time; + event->button.x = LOWORD (xevent->lParam); + event->button.y = HIWORD (xevent->lParam); + event->button.x_root = (gfloat)xevent->pt.x; + event->button.y_root = (gfloat)xevent->pt.y; + event->button.pressure = 0.5; + event->button.xtilt = 0; + event->button.ytilt = 0; + event->button.state = 0; + if (xevent->wParam & MK_CONTROL) + event->button.state |= GDK_CONTROL_MASK; + if (xevent->wParam & MK_LBUTTON) + event->button.state |= GDK_BUTTON1_MASK; + if (xevent->wParam & MK_MBUTTON) + event->button.state |= GDK_BUTTON2_MASK; + if (xevent->wParam & MK_RBUTTON) + event->button.state |= GDK_BUTTON3_MASK; + if (xevent->wParam & MK_SHIFT) + event->button.state |= GDK_SHIFT_MASK; + if (GetKeyState (VK_MENU) < 0) + event->button.state |= GDK_MOD1_MASK; + if (GetKeyState (VK_CAPITAL) & 0x1) + event->button.state |= GDK_LOCK_MASK; + 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 = window_private && !window_private->destroyed; + if (return_val + && p_grab_window != NULL + && event->any.window == (GdkWindow *) p_grab_window + && p_grab_window != window_private) + { + /* Translate coordinates to grabber */ + pt.x = event->button.x; + pt.y = event->button.y; + ClientToScreen (window_private->xwindow, &pt); + ScreenToClient (p_grab_window->xwindow, &pt); + event->button.x = pt.x; + event->button.y = pt.y; + GDK_NOTE (EVENTS, g_print ("New coords are +%d+%d\n", pt.x, pt.y)); + } + break; + + case WM_LBUTTONUP: + button = 1; + goto buttonup0; + case WM_MBUTTONUP: + button = 2; + goto buttonup0; + case WM_RBUTTONUP: + button = 3; + + /* Print debugging info. + */ + buttonup0: + GDK_NOTE (EVENTS, + g_print ("WM_%cBUTTONUP: %#x x,y: %d %d button: %d\n", + " LMR"[button], + xevent->hwnd, + LOWORD (xevent->lParam), HIWORD (xevent->lParam), + button)); + + if (window_private + && (window_private->extension_events != 0) + && gdk_input_ignore_core) + { + GDK_NOTE (EVENTS, g_print ("... ignored\n")); + break; + } + + buttonup: + event->button.type = GDK_BUTTON_RELEASE; + event->button.window = window; + if (window_private) + mask = window_private->event_mask; + else + mask = 0; + + 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_event_mask; + if (!(mask & GDK_BUTTON_RELEASE_MASK)) + /* Grabber doesn't want it */ + break; + else + event->button.window = (GdkWindow *) p_grab_window; + GDK_NOTE (EVENTS, g_print ("sending to %#x\n", + p_grab_window->xwindow)); + } + else if (window_private + && !(mask & GDK_BUTTON_RELEASE_MASK)) + { + /* Owner window doesn't want it */ + if (p_grab_window != NULL + && p_grab_owner_events) + { + /* Pointer is grabbed wíth owner_events TRUE */ + GDK_NOTE (EVENTS, g_print ("grabbed, owner_events TRUE, doesn't want it\n")); + mask = p_grab_event_mask; + if (!(mask & GDK_BUTTON_RELEASE_MASK)) + /* Grabber doesn't want it */ + break; + else + event->button.window = (GdkWindow *) p_grab_window; + GDK_NOTE (EVENTS, g_print ("sending to %#x\n", + p_grab_window->xwindow)); + } + else + { + /* Owner doesn't want it, neither is it grabbed, so + * propagate to parent. + */ + if (window_private->parent == (GdkWindow *) &gdk_root_parent) + break; + pt.x = LOWORD (xevent->lParam); + pt.y = HIWORD (xevent->lParam); + ClientToScreen (window_private->xwindow, &pt); + gdk_window_unref (window); + window = window_private->parent; + gdk_window_ref (window); + window_private = (GdkWindowPrivate *) window; + ScreenToClient (window_private->xwindow, &pt); + xevent->lParam = MAKELPARAM (pt.x, pt.y); + goto buttonup; + } + } + + if (window != curWnd) + synthesize_crossing_events (window, xevent); + + event->button.time = xevent->time; + event->button.x = LOWORD (xevent->lParam); + event->button.y = HIWORD (xevent->lParam); + event->button.x_root = (gfloat)xevent->pt.x; + event->button.y_root = (gfloat)xevent->pt.y; + event->button.pressure = 0.5; + event->button.xtilt = 0; + event->button.ytilt = 0; + event->button.state = 0; + if (xevent->wParam & MK_CONTROL) + event->button.state |= GDK_CONTROL_MASK; + if (xevent->wParam & MK_LBUTTON) + event->button.state |= GDK_BUTTON1_MASK; + if (xevent->wParam & MK_MBUTTON) + event->button.state |= GDK_BUTTON2_MASK; + if (xevent->wParam & MK_RBUTTON) + event->button.state |= GDK_BUTTON3_MASK; + if (xevent->wParam & MK_SHIFT) + event->button.state |= GDK_SHIFT_MASK; + event->button.button = button; + event->button.source = GDK_SOURCE_MOUSE; + event->button.deviceid = GDK_CORE_POINTER; + return_val = window_private && !window_private->destroyed; + if (return_val + && p_grab_window != NULL + && event->any.window == (GdkWindow *) p_grab_window + && p_grab_window != window_private) + { + /* Translate coordinates to grabber */ + pt.x = event->button.x; + pt.y = event->button.y; + ClientToScreen (window_private->xwindow, &pt); + ScreenToClient (p_grab_window->xwindow, &pt); + event->button.x = pt.x; + event->button.y = pt.y; + GDK_NOTE (EVENTS, g_print ("New coords are +%d+%d\n", pt.x, pt.y)); + } + 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: + /* Print debugging info. + */ + GDK_NOTE (EVENTS, + g_print ("WM_MOUSEMOVE: %#x %#x +%d+%d\n", + xevent->hwnd, xevent->wParam, + LOWORD (xevent->lParam), HIWORD (xevent->lParam))); + +#if 0 + /* Try hard not to generate events for windows that shouldn't + get any. This is hard because we don't want pushbuttons to + highlight when the cursor moves over them if the window is + inactive. We dont want tooltips windows to be active. OTOH, + also menus are popup windows, but they definitely should + get events. Aw shit. Skip this. + */ + dwStyle = GetWindowLong (xevent->hwnd, GWL_STYLE); + if (active == NULL || + !(active == xevent->hwnd + || (dwStyle & WS_POPUP) + || IsChild (active, xevent->hwnd))) + break; +#else + { /* HB: only process mouse move messages + * if we own the active window. + */ + DWORD ProcessID_ActWin; + DWORD ProcessID_this; + + GetWindowThreadProcessId(GetActiveWindow(), &ProcessID_ActWin); + GetWindowThreadProcessId(xevent->hwnd, &ProcessID_this); + if (ProcessID_ActWin != ProcessID_this) + break; + } +#endif + if (window != curWnd) + synthesize_crossing_events (window, xevent); + + if (window_private + && (window_private->extension_events != 0) + && gdk_input_ignore_core) + { + GDK_NOTE (EVENTS, g_print ("... ignored\n")); + break; + } + + mousemotion: + event->motion.type = GDK_MOTION_NOTIFY; + event->motion.window = window; + if (window_private) + mask = window_private->event_mask; + else + mask = 0; + + if (p_grab_window + && !p_grab_owner_events) + { + /* Pointer is grabbed with owner_events FALSE */ + GDK_NOTE (EVENTS, + g_print ("grabbed, owner_events FALSE\n")); + mask = p_grab_event_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)))) + break; + else + event->motion.window = (GdkWindow *) p_grab_window; + GDK_NOTE (EVENTS, g_print ("sending to %#x\n", + p_grab_window->xwindow)); + } + else if (window_private + && !((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 window doesn't want it */ + if (p_grab_window != NULL + && p_grab_owner_events) + { + /* Pointer is grabbed wíth owner_events TRUE */ + GDK_NOTE (EVENTS, g_print ("grabbed, owner_events TRUE, doesn't want it\n")); + mask = p_grab_event_mask; + if (!((p_grab_event_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 */ + break; + else + event->motion.window = (GdkWindow *) p_grab_window; + GDK_NOTE (EVENTS, g_print ("sending to %#x\n", + p_grab_window->xwindow)); + } + else + { + /* Owner doesn't want it, neither is it grabbed, so + * propagate to parent. + */ + if (window_private->parent == (GdkWindow *) &gdk_root_parent) + break; + pt.x = LOWORD (xevent->lParam); + pt.y = HIWORD (xevent->lParam); + ClientToScreen (window_private->xwindow, &pt); + gdk_window_unref (window); + window = window_private->parent; + gdk_window_ref (window); + window_private = (GdkWindowPrivate *) window; + ScreenToClient (window_private->xwindow, &pt); + xevent->lParam = MAKELPARAM (pt.x, pt.y); + GDK_NOTE (EVENTS, g_print ("propagating to %#x\n", + window_private->xwindow)); + goto mousemotion; + } + } + + event->motion.time = xevent->time; + 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->button.state = 0; + if (xevent->wParam & MK_CONTROL) + event->button.state |= GDK_CONTROL_MASK; + if (xevent->wParam & MK_LBUTTON) + event->button.state |= GDK_BUTTON1_MASK; + if (xevent->wParam & MK_MBUTTON) + event->button.state |= GDK_BUTTON2_MASK; + if (xevent->wParam & MK_RBUTTON) + event->button.state |= GDK_BUTTON3_MASK; + if (xevent->wParam & MK_SHIFT) + event->button.state |= GDK_SHIFT_MASK; + if (mask & GDK_POINTER_MOTION_HINT_MASK) + event->motion.is_hint = NotifyHint; + else + event->motion.is_hint = NotifyNormal; + event->motion.source = GDK_SOURCE_MOUSE; + event->motion.deviceid = GDK_CORE_POINTER; + + return_val = window_private && !window_private->destroyed; + if (return_val + && p_grab_window != NULL + && event->any.window == (GdkWindow *) p_grab_window + && p_grab_window != window_private) + { + /* Translate coordinates to grabber */ + pt.x = event->motion.x; + pt.y = event->motion.y; + ClientToScreen (window_private->xwindow, &pt); + ScreenToClient (p_grab_window->xwindow, &pt); + event->motion.x = pt.x; + event->motion.y = pt.y; + GDK_NOTE (EVENTS, g_print ("New coords are +%d+%d\n", pt.x, pt.y)); + } + break; + + case WM_NCMOUSEMOVE: + /* Print debugging info. */ + GDK_NOTE (EVENTS, + g_print ("WM_NCMOUSEMOVE: %#x x,y: %d %d\n", + xevent->hwnd, + LOWORD (xevent->lParam), HIWORD (xevent->lParam))); +#if 0 + if (active == NULL || active != xevent->hwnd) + break; +#endif + curWnd_private = (GdkWindowPrivate *) curWnd; + if (curWnd != NULL + && (curWnd_private->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_UNKNOWN; + + event->crossing.focus = TRUE; /* ??? */ + event->crossing.state = 0; /* ??? */ + gdk_window_unref (curWnd); + curWnd = NULL; + + return_val = TRUE; + } + break; + + case WM_SETFOCUS: + case WM_KILLFOCUS: + if (window_private + && !(window_private->event_mask & GDK_FOCUS_CHANGE_MASK)) + break; + + GDK_NOTE (EVENTS, g_print ("WM_%sFOCUS: %#x\n", + (xevent->message == WM_SETFOCUS ? "SET" : "KILL"), + xevent->hwnd)); + + event->focus_change.type = GDK_FOCUS_CHANGE; + event->focus_change.window = window; + event->focus_change.in = (xevent->message == WM_SETFOCUS); + return_val = window_private && !window_private->destroyed; + break; +#if 0 + case WM_ACTIVATE: + GDK_NOTE (EVENTS, g_print ("WM_ACTIVATE: %#x %d\n", + xevent->hwnd, LOWORD (xevent->wParam))); + if (LOWORD (xevent->wParam) == WA_INACTIVE) + active = (HWND) xevent->lParam; + else + active = xevent->hwnd; + break; +#endif + case WM_ERASEBKGND: + GDK_NOTE (EVENTS, g_print ("WM_ERASEBKGND: %#x dc %#x\n", + xevent->hwnd, xevent->wParam)); + + if (!window_private || window_private->destroyed) + break; + colormap_private = (GdkColormapPrivate *) window_private->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->bg_type == GDK_WIN32_BG_TRANSPARENT) + break; + + if (window_private->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_private + && window_private->bg_type == GDK_WIN32_BG_PARENT_RELATIVE) + window_private = (GdkWindowPrivate *) window_private->parent; + } + + if (window_private->bg_type == GDK_WIN32_BG_PIXEL) + { + COLORREF bg; + GDK_NOTE (EVENTS, g_print ("... BG_PIXEL %s\n", + gdk_color_to_string (&window_private->bg_pixel))); + GetClipBox (hdc, &rect); +#ifdef MULTIPLE_WINDOW_CLASSES + bg = PALETTEINDEX (window_private->bg_pixel.pixel); +#else + bg = GetNearestColor (hdc, RGB (window_private->bg_pixel.red >> 8, + window_private->bg_pixel.green >> 8, + window_private->bg_pixel.blue >> 8)); +#endif + 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->bg_type == GDK_WIN32_BG_PIXMAP) + { + GdkPixmapPrivate *pixmap_private; + HDC bgdc; + HGDIOBJ oldbitmap; + + pixmap_private = (GdkPixmapPrivate *) window_private->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")); +#ifdef MULTIPLE_WINDOW_CLASSES + hbr = (HBRUSH) GetClassLong (window_private->xwindow, + GCL_HBRBACKGROUND); +#else + hbr = GetStockObject (BLACK_BRUSH); +#endif + GetClipBox (hdc, &rect); + if (!FillRect (hdc, &rect, hbr)) + g_warning ("WM_ERASEBKGND: FillRect failed"); + } + break; + + case WM_PAINT: + GDK_NOTE (EVENTS, g_print ("WM_PAINT: %#x\n", xevent->hwnd)); + hdc = BeginPaint (xevent->hwnd, &paintstruct); + + /* Print debugging info. + */ + 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_private->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 = 1; + + return_val = window_private && !window_private->destroyed; + break; + +#ifndef MULTIPLE_WINDOW_CLASSES + case WM_SETCURSOR: + GDK_NOTE (EVENTS, g_print ("WM_SETCURSOR: %#x %#x %#x\n", + xevent->hwnd, + LOWORD (xevent->lParam), HIWORD (xevent->lParam))); + + return_val = FALSE; + if (LOWORD (xevent->lParam) != HTCLIENT) + break; + if (p_grab_window != NULL && p_grab_cursor != NULL) + SetCursor (p_grab_cursor); + else if (window_private + && !window_private->destroyed + && window_private->xcursor) + SetCursor (window_private->xcursor); + *ret_val_flagp = TRUE; + *ret_valp = FALSE; + break; +#endif + +#if 0 + case WM_QUERYOPEN: + GDK_NOTE (EVENTS, g_print ("WM_QUERYOPEN: %#x\n", + xevent->hwnd)); + *ret_val_flagp = TRUE; + *ret_valp = TRUE; + + if (window_private + && !(window_private->event_mask & GDK_STRUCTURE_MASK)) + break; + + event->any.type = GDK_MAP; + event->any.window = window; + + return_val = window_private && !window_private->destroyed; + break; +#endif + +#if 1 + case WM_SHOWWINDOW: + /* Print debugging info. + */ + GDK_NOTE (EVENTS, g_print ("WM_SHOWWINDOW: %#x %d\n", + xevent->hwnd, + xevent->wParam)); + + if (window_private + && !(window_private->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_private) + gdk_pointer_ungrab (xevent->time); + + if (event->any.type == GDK_UNMAP + && k_grab_window == window_private) + gdk_keyboard_ungrab (xevent->time); + + return_val = window_private && !window_private->destroyed; + break; +#endif + case WM_SIZE: + /* Print debugging info. + */ + 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_private->event_mask & GDK_STRUCTURE_MASK)) + break; + if (window_private != NULL + && xevent->wParam == SIZE_MINIMIZED) + { +#if 1 + event->any.type = GDK_UNMAP; + event->any.window = window; + + if (p_grab_window == window_private) + gdk_pointer_ungrab (xevent->time); + + if (k_grab_window == window_private) + gdk_keyboard_ungrab (xevent->time); + + return_val = !window_private->destroyed; +#endif + } + else if (window_private != NULL + && (xevent->wParam == SIZE_RESTORED + || xevent->wParam == SIZE_MAXIMIZED) +#if 1 + && window_private->window_type != 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->x = event->configure.x; + window_private->y = event->configure.y; + window_private->width = event->configure.width; + window_private->height = event->configure.height; + if (window_private->resize_count > 1) + window_private->resize_count -= 1; + + return_val = !window_private->destroyed; + if (return_val + && window_private->extension_events != 0 + && gdk_input_vtable.configure_event) + gdk_input_vtable.configure_event (&event->configure, window); + } + break; + + case WM_SIZING: + GDK_NOTE (EVENTS, g_print ("WM_SIZING: %#x\n", xevent->hwnd)); + if (ret_val_flagp == NULL) + g_warning ("ret_val_flagp is NULL but we got a WM_SIZING?"); + else if (window_private != NULL + && window_private->hint_flags & + (GDK_HINT_MIN_SIZE | GDK_HINT_MAX_SIZE)) + { + LPRECT lprc = (LPRECT) xevent->lParam; + + if (window_private->hint_flags & GDK_HINT_MIN_SIZE) + { + gint w = lprc->right - lprc->left; + gint h = lprc->bottom - lprc->top; + + if (w < window_private->hint_min_width) + { + if (xevent->wParam == WMSZ_BOTTOMLEFT + || xevent->wParam == WMSZ_LEFT + || xevent->wParam == WMSZ_TOPLEFT) + lprc->left = lprc->right - window_private->hint_min_width; + else + lprc->right = lprc->left + window_private->hint_min_width; + *ret_val_flagp = TRUE; + *ret_valp = TRUE; + } + if (h < window_private->hint_min_height) + { + if (xevent->wParam == WMSZ_BOTTOMLEFT + || xevent->wParam == WMSZ_BOTTOM + || xevent->wParam == WMSZ_BOTTOMRIGHT) + lprc->bottom = lprc->top + window_private->hint_min_height; + else + lprc->top = lprc->bottom - window_private->hint_min_height; + *ret_val_flagp = TRUE; + *ret_valp = TRUE; + } + } + if (window_private->hint_flags & GDK_HINT_MAX_SIZE) + { + gint w = lprc->right - lprc->left; + gint h = lprc->bottom - lprc->top; + + if (w > window_private->hint_max_width) + { + if (xevent->wParam == WMSZ_BOTTOMLEFT + || xevent->wParam == WMSZ_LEFT + || xevent->wParam == WMSZ_TOPLEFT) + lprc->left = lprc->right - window_private->hint_max_width; + else + lprc->right = lprc->left + window_private->hint_max_width; + *ret_val_flagp = TRUE; + *ret_valp = TRUE; + } + if (h > window_private->hint_max_height) + { + if (xevent->wParam == WMSZ_BOTTOMLEFT + || xevent->wParam == WMSZ_BOTTOM + || xevent->wParam == WMSZ_BOTTOMRIGHT) + lprc->bottom = lprc->top + window_private->hint_max_height; + else + lprc->top = lprc->bottom - window_private->hint_max_height; + *ret_val_flagp = TRUE; + *ret_valp = TRUE; + } + } + } + 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_private->event_mask & GDK_STRUCTURE_MASK)) + break; + if (window_private != NULL + && window_private->window_type != 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->x = event->configure.x; + window_private->y = event->configure.y; + window_private->width = event->configure.width; + window_private->height = event->configure.height; + + return_val = !window_private->destroyed; + } + 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 = window_private && !window_private->destroyed; + 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 = window_private && !window_private->destroyed; +#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_private) + gdk_pointer_ungrab (xevent->time); + + if (k_grab_window == window_private) + gdk_keyboard_ungrab (xevent->time); + + return_val = window_private && !window_private->destroyed; + break; + + /* 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))); + wintab: + return_val = gdk_input_vtable.other_event(event, xevent); + break; + } + +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); + } + 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; + + GDK_NOTE (EVENTS, g_print ("gdk_events_queue: %s\n", + (queued_events ? "yes" : "none"))); + + while (!gdk_event_queue_find_first() + && PeekMessage (&msg, NULL, 0, 0, PM_REMOVE)) + { + GDK_NOTE (EVENTS, g_print ("gdk_events_queue: got event\n")); + TranslateMessage (&msg); + + 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 + { + DefWindowProc (msg.hwnd, msg.message, msg.wParam, msg.lParam); + gdk_event_queue_remove_link (node); + g_list_free_1 (node); + gdk_event_free (event); + } + } +} + +static gboolean +gdk_event_prepare (gpointer source_data, + GTimeVal *current_time, + gint *timeout) +{ + MSG msg; + gboolean retval; + + GDK_THREADS_ENTER (); + + *timeout = -1; + + GDK_NOTE (EVENTS, g_print ("gdk_event_prepare\n")); + + 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_NOTE (EVENTS, g_print ("gdk_event_check\n")); + + 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_NOTE (EVENTS, g_print ("gdk_event_dispatch\n")); + + 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); +} + +/* Sends a ClientMessage to all toplevel client windows */ +gboolean +gdk_event_send_client_message (GdkEvent *event, guint32 xid) +{ + /* XXX */ + return FALSE; +} + +void +gdk_event_send_clientmessage_toall (GdkEvent *event) +{ + /* XXX */ +} + diff --git a/gdk/win32/gdkfont-win32.c b/gdk/win32/gdkfont-win32.c new file mode 100644 index 000000000..cfe9382fe --- /dev/null +++ b/gdk/win32/gdkfont-win32.c @@ -0,0 +1,697 @@ +/* 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 "gdk.h" +#include "gdkprivate.h" + +GdkFont* +gdk_font_load (const gchar *font_name) +{ + GdkFont *font; + GdkFontPrivate *private; + LOGFONT logfont; + HGDIOBJ oldfont; + TEXTMETRIC textmetric; + HANDLE *f; + 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; + + private = g_new (GdkFontPrivate, 1); + font = (GdkFont*) private; + + 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); + g_free (font); + 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); + g_free (font); + 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) + fnWeight = FW_ULTRALIGHT; + 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) + fnWeight = FW_DEMIBOLD; + 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) + fnWeight = FW_ULTRABOLD; + else if (g_strcasecmp (weight, "heavy") == 0) + fnWeight = FW_HEAVY; + else if (g_strcasecmp (weight, "black") == 0) + fnWeight = FW_BLACK; + 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 + fdwCharSet = ANSI_CHARSET; /* XXX ??? */ + else if (g_strcasecmp (registry, "windows") == 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, "chinesebig5") == 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 + 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 ("gdk_font_load: 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 ((private->xfont = + 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 (!private->xfont) + { + g_warning ("gdk_font_load: font %s not found", font_name); + g_free (font); + return NULL; + } + + private->ref_count = 1; + font->type = GDK_FONT_FONT; + GetObject (private->xfont, sizeof (logfont), &logfont); + oldfont = SelectObject (gdk_DC, private->xfont); + GetTextMetrics (gdk_DC, &textmetric); + SelectObject (gdk_DC, oldfont); + font->ascent = textmetric.tmAscent; + font->descent = textmetric.tmDescent; + + GDK_NOTE (MISC, g_print ("gdk_font_load: %s = %#x asc %d desc %d\n", + font_name, private->xfont, + font->ascent, font->descent)); + + /* This memory is leaked, so shoot me. */ + f = g_new (HANDLE, 1); + *f = (HANDLE) ((guint) private->xfont + HFONT_DITHER); + gdk_xid_table_insert (f, font); + + return font; +} + +GdkFont* +gdk_fontset_load (gchar *fontset_name) +{ + g_warning ("gdk_fontset_load: Not implemented"); + return NULL; +} + +GdkFont* +gdk_font_ref (GdkFont *font) +{ + GdkFontPrivate *private; + + g_return_val_if_fail (font != NULL, NULL); + + private = (GdkFontPrivate*) font; + private->ref_count += 1; + return font; +} + +void +gdk_font_unref (GdkFont *font) +{ + GdkFontPrivate *private; + + g_return_if_fail (font != NULL); + + private = (GdkFontPrivate*) font; + + private->ref_count -= 1; + if (private->ref_count == 0) + { + switch (font->type) + { + case GDK_FONT_FONT: + GDK_NOTE (MISC, g_print ("gdk_font_unref %#x\n", private->xfont)); + + gdk_xid_table_remove ((HANDLE) ((guint) private->xfont + HFONT_DITHER)); + DeleteObject (private->xfont); + 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) font_private->xfont; + + g_assert_not_reached (); + 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 (privatea->xfont == privateb->xfont); + + g_assert_not_reached (); + return 0; +} + +gint +gdk_string_width (GdkFont *font, + const gchar *string) +{ + return gdk_text_width (font, string, strlen (string)); +} + +gint +gdk_text_width (GdkFont *font, + const gchar *text, + gint text_length) +{ + GdkFontPrivate *private; + HGDIOBJ oldfont; + SIZE size; + gint width; + + g_return_val_if_fail (font != NULL, -1); + g_return_val_if_fail (text != NULL, -1); + + private = (GdkFontPrivate*) font; + + switch (font->type) + { + case GDK_FONT_FONT: + oldfont = SelectObject (gdk_DC, private->xfont); + GetTextExtentPoint32A (gdk_DC, text, text_length, &size); + SelectObject (gdk_DC, oldfont); + width = size.cx; + break; + + default: + g_assert_not_reached (); + } + return width; +} + +gint +gdk_text_width_wc (GdkFont *font, + const GdkWChar *text, + gint text_length) +{ + GdkFontPrivate *private; + HGDIOBJ oldfont; + SIZE size; + wchar_t *wcstr; + gint i, width; + + g_return_val_if_fail (font != NULL, -1); + g_return_val_if_fail (text != NULL, -1); + + private = (GdkFontPrivate*) font; + + switch (font->type) + { + case GDK_FONT_FONT: + wcstr = g_new (wchar_t, text_length); + for (i = 0; i < text_length; i++) + wcstr[i] = text[i]; + oldfont = SelectObject (gdk_DC, private->xfont); + GetTextExtentPoint32W (gdk_DC, wcstr, text_length, &size); + g_free (wcstr); + SelectObject (gdk_DC, oldfont); + width = size.cx; + break; + + default: + width = 0; + } + return width; +} + +gint +gdk_char_width (GdkFont *font, + gchar character) +{ + 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) +{ + GdkFontPrivate *private; + HGDIOBJ oldfont; + SIZE size; + + g_return_if_fail (font != NULL); + g_return_if_fail (text != NULL); + + private = (GdkFontPrivate*) font; + + switch (font->type) + { + case GDK_FONT_FONT: + oldfont = SelectObject (gdk_DC, private->xfont); + GetTextExtentPoint32A (gdk_DC, text, text_length, &size); + SelectObject (gdk_DC, oldfont); + /* XXX This is all quite bogus */ + if (lbearing) + *lbearing = 0; + if (rbearing) + *rbearing = 0; + if (width) + *width = size.cx; + if (ascent) + *ascent = size.cy + 1; + if (descent) + *descent = font->descent + 1; + break; + + default: + g_assert_not_reached (); + } +} + +void +gdk_text_extents_wc (GdkFont *font, + const GdkWChar *text, + gint text_length, + gint *lbearing, + gint *rbearing, + gint *width, + gint *ascent, + gint *descent) +{ + GdkFontPrivate *private; + HGDIOBJ oldfont; + SIZE size; + wchar_t *wcstr; + gint i; + + g_return_if_fail (font != NULL); + g_return_if_fail (text != NULL); + + private = (GdkFontPrivate*) font; + + switch (font->type) + { + case GDK_FONT_FONT: + wcstr = g_new (wchar_t, text_length); + for (i = 0; i < text_length; i++) + wcstr[i] = text[i]; + oldfont = SelectObject (gdk_DC, private->xfont); + GetTextExtentPoint32W (gdk_DC, wcstr, text_length, &size); + g_free (wcstr); + SelectObject (gdk_DC, oldfont); + + /* XXX This is all quite bogus */ + if (lbearing) + *lbearing = 0; + if (rbearing) + *rbearing = 0; + if (width) + *width = size.cx; + if (ascent) + *ascent = size.cy + 1; + if (descent) + *descent = font->descent + 1; + break; + + default: + g_assert_not_reached (); + } +} + +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) +{ + GdkFontPrivate *private; + gint width; + + g_return_val_if_fail (font != NULL, -1); + g_return_val_if_fail (text != NULL, -1); + + private = (GdkFontPrivate*) font; + + switch (font->type) + { + case GDK_FONT_FONT: + return gdk_text_width (font, text, text_length); /* ??? */ + break; + + default: + g_assert_not_reached (); + } + return 0; +} + +gint +gdk_char_measure (GdkFont *font, + gchar character) +{ + g_return_val_if_fail (font != NULL, -1); + + 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) +{ + GdkFontPrivate *private; + HGDIOBJ oldfont; + SIZE size; + gint height; + + g_return_val_if_fail (font != NULL, -1); + g_return_val_if_fail (text != NULL, -1); + + private = (GdkFontPrivate*) font; + + switch (font->type) + { + case GDK_FONT_FONT: + oldfont = SelectObject (gdk_DC, private->xfont); + GetTextExtentPoint32 (gdk_DC, text, text_length, &size); + SelectObject (gdk_DC, oldfont); + height = size.cy; + break; + + default: + g_error ("font->type = %d", font->type); + } + return height; +} + +gint +gdk_char_height (GdkFont *font, + gchar character) +{ + g_return_val_if_fail (font != NULL, -1); + + return gdk_text_height (font, &character, 1); +} diff --git a/gdk/win32/gdkfont.c b/gdk/win32/gdkfont.c new file mode 100644 index 000000000..cfe9382fe --- /dev/null +++ b/gdk/win32/gdkfont.c @@ -0,0 +1,697 @@ +/* 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 "gdk.h" +#include "gdkprivate.h" + +GdkFont* +gdk_font_load (const gchar *font_name) +{ + GdkFont *font; + GdkFontPrivate *private; + LOGFONT logfont; + HGDIOBJ oldfont; + TEXTMETRIC textmetric; + HANDLE *f; + 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; + + private = g_new (GdkFontPrivate, 1); + font = (GdkFont*) private; + + 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); + g_free (font); + 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); + g_free (font); + 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) + fnWeight = FW_ULTRALIGHT; + 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) + fnWeight = FW_DEMIBOLD; + 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) + fnWeight = FW_ULTRABOLD; + else if (g_strcasecmp (weight, "heavy") == 0) + fnWeight = FW_HEAVY; + else if (g_strcasecmp (weight, "black") == 0) + fnWeight = FW_BLACK; + 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 + fdwCharSet = ANSI_CHARSET; /* XXX ??? */ + else if (g_strcasecmp (registry, "windows") == 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, "chinesebig5") == 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 + 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 ("gdk_font_load: 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 ((private->xfont = + 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 (!private->xfont) + { + g_warning ("gdk_font_load: font %s not found", font_name); + g_free (font); + return NULL; + } + + private->ref_count = 1; + font->type = GDK_FONT_FONT; + GetObject (private->xfont, sizeof (logfont), &logfont); + oldfont = SelectObject (gdk_DC, private->xfont); + GetTextMetrics (gdk_DC, &textmetric); + SelectObject (gdk_DC, oldfont); + font->ascent = textmetric.tmAscent; + font->descent = textmetric.tmDescent; + + GDK_NOTE (MISC, g_print ("gdk_font_load: %s = %#x asc %d desc %d\n", + font_name, private->xfont, + font->ascent, font->descent)); + + /* This memory is leaked, so shoot me. */ + f = g_new (HANDLE, 1); + *f = (HANDLE) ((guint) private->xfont + HFONT_DITHER); + gdk_xid_table_insert (f, font); + + return font; +} + +GdkFont* +gdk_fontset_load (gchar *fontset_name) +{ + g_warning ("gdk_fontset_load: Not implemented"); + return NULL; +} + +GdkFont* +gdk_font_ref (GdkFont *font) +{ + GdkFontPrivate *private; + + g_return_val_if_fail (font != NULL, NULL); + + private = (GdkFontPrivate*) font; + private->ref_count += 1; + return font; +} + +void +gdk_font_unref (GdkFont *font) +{ + GdkFontPrivate *private; + + g_return_if_fail (font != NULL); + + private = (GdkFontPrivate*) font; + + private->ref_count -= 1; + if (private->ref_count == 0) + { + switch (font->type) + { + case GDK_FONT_FONT: + GDK_NOTE (MISC, g_print ("gdk_font_unref %#x\n", private->xfont)); + + gdk_xid_table_remove ((HANDLE) ((guint) private->xfont + HFONT_DITHER)); + DeleteObject (private->xfont); + 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) font_private->xfont; + + g_assert_not_reached (); + 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 (privatea->xfont == privateb->xfont); + + g_assert_not_reached (); + return 0; +} + +gint +gdk_string_width (GdkFont *font, + const gchar *string) +{ + return gdk_text_width (font, string, strlen (string)); +} + +gint +gdk_text_width (GdkFont *font, + const gchar *text, + gint text_length) +{ + GdkFontPrivate *private; + HGDIOBJ oldfont; + SIZE size; + gint width; + + g_return_val_if_fail (font != NULL, -1); + g_return_val_if_fail (text != NULL, -1); + + private = (GdkFontPrivate*) font; + + switch (font->type) + { + case GDK_FONT_FONT: + oldfont = SelectObject (gdk_DC, private->xfont); + GetTextExtentPoint32A (gdk_DC, text, text_length, &size); + SelectObject (gdk_DC, oldfont); + width = size.cx; + break; + + default: + g_assert_not_reached (); + } + return width; +} + +gint +gdk_text_width_wc (GdkFont *font, + const GdkWChar *text, + gint text_length) +{ + GdkFontPrivate *private; + HGDIOBJ oldfont; + SIZE size; + wchar_t *wcstr; + gint i, width; + + g_return_val_if_fail (font != NULL, -1); + g_return_val_if_fail (text != NULL, -1); + + private = (GdkFontPrivate*) font; + + switch (font->type) + { + case GDK_FONT_FONT: + wcstr = g_new (wchar_t, text_length); + for (i = 0; i < text_length; i++) + wcstr[i] = text[i]; + oldfont = SelectObject (gdk_DC, private->xfont); + GetTextExtentPoint32W (gdk_DC, wcstr, text_length, &size); + g_free (wcstr); + SelectObject (gdk_DC, oldfont); + width = size.cx; + break; + + default: + width = 0; + } + return width; +} + +gint +gdk_char_width (GdkFont *font, + gchar character) +{ + 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) +{ + GdkFontPrivate *private; + HGDIOBJ oldfont; + SIZE size; + + g_return_if_fail (font != NULL); + g_return_if_fail (text != NULL); + + private = (GdkFontPrivate*) font; + + switch (font->type) + { + case GDK_FONT_FONT: + oldfont = SelectObject (gdk_DC, private->xfont); + GetTextExtentPoint32A (gdk_DC, text, text_length, &size); + SelectObject (gdk_DC, oldfont); + /* XXX This is all quite bogus */ + if (lbearing) + *lbearing = 0; + if (rbearing) + *rbearing = 0; + if (width) + *width = size.cx; + if (ascent) + *ascent = size.cy + 1; + if (descent) + *descent = font->descent + 1; + break; + + default: + g_assert_not_reached (); + } +} + +void +gdk_text_extents_wc (GdkFont *font, + const GdkWChar *text, + gint text_length, + gint *lbearing, + gint *rbearing, + gint *width, + gint *ascent, + gint *descent) +{ + GdkFontPrivate *private; + HGDIOBJ oldfont; + SIZE size; + wchar_t *wcstr; + gint i; + + g_return_if_fail (font != NULL); + g_return_if_fail (text != NULL); + + private = (GdkFontPrivate*) font; + + switch (font->type) + { + case GDK_FONT_FONT: + wcstr = g_new (wchar_t, text_length); + for (i = 0; i < text_length; i++) + wcstr[i] = text[i]; + oldfont = SelectObject (gdk_DC, private->xfont); + GetTextExtentPoint32W (gdk_DC, wcstr, text_length, &size); + g_free (wcstr); + SelectObject (gdk_DC, oldfont); + + /* XXX This is all quite bogus */ + if (lbearing) + *lbearing = 0; + if (rbearing) + *rbearing = 0; + if (width) + *width = size.cx; + if (ascent) + *ascent = size.cy + 1; + if (descent) + *descent = font->descent + 1; + break; + + default: + g_assert_not_reached (); + } +} + +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) +{ + GdkFontPrivate *private; + gint width; + + g_return_val_if_fail (font != NULL, -1); + g_return_val_if_fail (text != NULL, -1); + + private = (GdkFontPrivate*) font; + + switch (font->type) + { + case GDK_FONT_FONT: + return gdk_text_width (font, text, text_length); /* ??? */ + break; + + default: + g_assert_not_reached (); + } + return 0; +} + +gint +gdk_char_measure (GdkFont *font, + gchar character) +{ + g_return_val_if_fail (font != NULL, -1); + + 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) +{ + GdkFontPrivate *private; + HGDIOBJ oldfont; + SIZE size; + gint height; + + g_return_val_if_fail (font != NULL, -1); + g_return_val_if_fail (text != NULL, -1); + + private = (GdkFontPrivate*) font; + + switch (font->type) + { + case GDK_FONT_FONT: + oldfont = SelectObject (gdk_DC, private->xfont); + GetTextExtentPoint32 (gdk_DC, text, text_length, &size); + SelectObject (gdk_DC, oldfont); + height = size.cy; + break; + + default: + g_error ("font->type = %d", font->type); + } + return height; +} + +gint +gdk_char_height (GdkFont *font, + gchar character) +{ + g_return_val_if_fail (font != NULL, -1); + + return gdk_text_height (font, &character, 1); +} diff --git a/gdk/win32/gdkgc-win32.c b/gdk/win32/gdkgc-win32.c new file mode 100644 index 000000000..6697090f7 --- /dev/null +++ b/gdk/win32/gdkgc-win32.c @@ -0,0 +1,1373 @@ +/* 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.h" +#include "gdkprivate.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) +{ + GdkWindowPrivate *window_private; + 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); + + window_private = (GdkWindowPrivate*) window; + if (window_private->destroyed) + 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)) + { + private->font = (HFONT) ((GdkFontPrivate*) values->font)->xfont; + GDK_NOTE (MISC, g_print (" font=%#x", private->font)); + } + + 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", ((GdkPixmapPrivate *)private->tile)->xwindow)); + } + else + private->tile = NULL; + + if (values_mask & GDK_GC_STIPPLE) + { + private->stipple = values->tile; + gdk_pixmap_ref (private->stipple); + GDK_NOTE (MISC, g_print (" stipple=%#x", ((GdkPixmapPrivate *)private->stipple)->xwindow)); + } + else + private->stipple = NULL; + + if (values_mask & GDK_GC_CLIP_MASK) + { + private->clip_region = + BitmapToRegion (((GdkPixmapPrivate *)values->clip_mask)->xwindow); + 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) + { +#if 0 + if (!DeleteObject (private->font)) + g_warning ("gdk_gc_unref: DeleteObject #3 failed"); +#endif + } + + 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); + } + memset (gc, 0, sizeof (GdkGCPrivate)); + 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 = gdk_font_lookup (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, ((GdkPixmapPrivate *) pixmap)->xwindow)) == 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; + + g_return_if_fail (gc != NULL); + g_return_if_fail (font != NULL); + + if (font->type == GDK_FONT_FONT) + { + gc_private = (GdkGCPrivate*) gc; + font_private = (GdkFontPrivate*) font; + + GDK_NOTE (MISC, g_print ("gdk_gc_set_font: (%d) %#x\n", + gc_private, font_private->xfont)); + + gc_private->font = font_private->xfont; + 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; + + 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; + GdkPixmapPrivate *pixmap_private; + HBITMAP pixmap; + + g_return_if_fail (gc != NULL); + + private = (GdkGCPrivate*) gc; + + pixmap = NULL; + + if (tile) + { + pixmap_private = (GdkPixmapPrivate*) tile; + pixmap = pixmap_private->xwindow; + } + + 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; + GdkPixmapPrivate *pixmap_private; + HBITMAP pixmap; + + g_return_if_fail (gc != NULL); + + private = (GdkGCPrivate*) gc; + + pixmap = NULL; + + if (stipple) + { + pixmap_private = (GdkPixmapPrivate*) stipple; + pixmap = pixmap_private->xwindow; + } + + 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) + { + GdkWindowPrivate *mask_private; + + mask_private = (GdkWindowPrivate*) mask; + if (mask_private->destroyed) + return; + xmask = mask_private->xwindow; + } + 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 ??? */ + g_warning ("gdk_gc_set_dashes: Not implemented"); +} + +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 (GdkWindowPrivate *window_private, + GdkGCPrivate *gc_private) +{ + GdkColormapPrivate *colormap_private = + (GdkColormapPrivate *) window_private->colormap; + COLORREF bg; + COLORREF fg; + LOGBRUSH logbrush; + HPEN hpen; + HBRUSH hbr; + + g_assert (gc_private->xgc == NULL); + + if (window_private->window_type == GDK_WINDOW_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, window_private->xwindow) == NULL) + g_warning ("gdk_gc_predraw: SelectObject #1 failed"); + } + else + { + if ((gc_private->xgc = GetDC (window_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 = window_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 ((hbr = CreateSolidBrush (fg)) == NULL) + g_warning ("gdk_gc_predraw: CreateSolidBrush failed"); + + 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_FONT) + if (SelectObject (gc_private->xgc, gc_private->font) == NULL) + g_warning ("gdk_gc_predraw: SelectObject #4 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 (GdkWindowPrivate *window_private, + GdkGCPrivate *gc_private) +{ + HGDIOBJ hpen; + HGDIOBJ hbr; + GdkColormapPrivate *colormap_private = + (GdkColormapPrivate *) window_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 (window_private->window_type == GDK_WINDOW_PIXMAP) + { + if (!DeleteDC (gc_private->xgc)) + g_warning ("gdk_gc_postdraw: DeleteDC failed"); + } + else + { + ReleaseDC (gc_private->hwnd, gc_private->xgc); + } + + if (hpen != NULL) + if (!DeleteObject (hpen)) + g_warning ("gdk_gc_postdraw: DeleteObject #1 failed"); + + if (hbr != NULL) + if (!DeleteObject (hbr)) + g_warning ("gdk_gc_postdraw: DeleteObject #2 failed"); + + gc_private->xgc = NULL; +} + +/* This function originally from Jean-Edouard Lachand-Robert, and + * available at www.codeguru.com. Simplified for our needs, now + * handles just one-bit deep bitmaps (in Window parlance, ie those + * that GDK calls bitmaps (and not pixmaps), with zero pixels being + * transparent. + */ + +/* + * BitmapToRegion : Create a region from the "non-transparent" pixels of + * a bitmap + * Author : Jean-Edouard Lachand-Robert + * (http://www.geocities.com/Paris/LeftBank/1160/resume.htm), June 1998. + */ + +HRGN +BitmapToRegion (HBITMAP hBmp) +{ + HRGN hRgn = NULL; + HDC hMemDC; + BITMAP bm; + + struct + { + BITMAPINFOHEADER bmiHeader; +#if 1 + WORD bmiColors[2]; +#else + RGBQUAD bmiColors[2]; +#endif + } bmi; + VOID *pbits8; + HBITMAP hbm8; + struct + { + WORD palVersion; + WORD palNumEntries; + PALETTEENTRY palPalEntry[2]; + } logpal; + static HPALETTE bwPalette = NULL; + + HBITMAP holdBmp; + HDC hDC; + + BITMAP bm8; + HBITMAP holdBmp2; + DWORD maxRects; + RGNDATA *pData; + BYTE *p8; + int x, y; + HRGN h; + + /* Create a B&W palette */ + if (bwPalette == NULL) + { + /* Create a b&w palette */ + logpal.palVersion = 0x300; + logpal.palNumEntries = 2; + logpal.palPalEntry[0].peRed = + logpal.palPalEntry[0].peGreen = + logpal.palPalEntry[0].peBlue = 0; + logpal.palPalEntry[0].peFlags = 0; + logpal.palPalEntry[1].peRed = + logpal.palPalEntry[1].peGreen = + logpal.palPalEntry[1].peBlue = 0xFF; + logpal.palPalEntry[1].peFlags = 0; + if ((bwPalette = CreatePalette ((LOGPALETTE *) &logpal)) == NULL) + g_warning ("BitmapToRegion: CreatePalette failed"); + } + + /* Create a memory DC inside which we will scan the bitmap content */ + hMemDC = CreateCompatibleDC (NULL); + if (!hMemDC) + { + g_warning ("BitmapToRegion: CreateCompatibleDC #1 failed"); + return NULL; + } + + SelectPalette (hMemDC, bwPalette, FALSE); + RealizePalette (hMemDC); + + /* Get bitmap size */ + GetObject(hBmp, sizeof(bm), &bm); + + /* Create a 8 bits depth bitmap and select it into the memory DC */ + bmi.bmiHeader.biSize = sizeof (BITMAPINFOHEADER); + bmi.bmiHeader.biWidth = bm.bmWidth; + bmi.bmiHeader.biHeight = bm.bmHeight; + bmi.bmiHeader.biPlanes = 1; + bmi.bmiHeader.biBitCount = 8; + bmi.bmiHeader.biCompression = BI_RGB; + bmi.bmiHeader.biSizeImage = 0; + bmi.bmiHeader.biXPelsPerMeter = 0; + bmi.bmiHeader.biYPelsPerMeter = 0; + bmi.bmiHeader.biClrUsed = 2; + bmi.bmiHeader.biClrImportant = 2; +#if 1 + bmi.bmiColors[0] = 0; + bmi.bmiColors[1] = 1; + hbm8 = CreateDIBSection (hMemDC, (BITMAPINFO *)&bmi, + DIB_PAL_COLORS, &pbits8, NULL, 0); +#else + bmi.bmiColors[0].rgbBlue = + bmi.bmiColors[0].rgbGreen = + bmi.bmiColors[0].rgbRed = 0x00; + bmi.bmiColors[0].rgbReserved = 0x00; + + bmi.bmiColors[1].rgbBlue = + bmi.bmiColors[1].rgbGreen = + bmi.bmiColors[1].rgbRed = 0xFF; + bmi.bmiColors[0].rgbReserved = 0x00; + + hbm8 = CreateDIBSection (hMemDC, (BITMAPINFO *)&bmi, + DIB_RGB_COLORS, &pbits8, NULL, 0); +#endif + if (!hbm8) + { + g_warning ("BitmapToRegion: CreateDIBSection failed"); + DeleteDC (hMemDC); + return NULL; + } + + holdBmp = (HBITMAP) SelectObject (hMemDC, hbm8); + + /* Create a DC just to copy the bitmap into the memory DC*/ + hDC = CreateCompatibleDC (hMemDC); + if (!hDC) + { + g_warning ("BitmapToRegion: CreateCompatibleDC #2 failed"); + SelectObject (hMemDC, holdBmp); + DeleteObject (hbm8); + DeleteDC (hMemDC); + return NULL; + } + + /* Get how many bytes per row we have for the bitmap bits */ + GetObject (hbm8, sizeof (bm8), &bm8); + + /* Hans Breuer found a fix to the long-standing erroneous behaviour + * on NT 4.0: There seems to be a bug in Win NT 4.0 GDI: scanlines + * in bitmaps are dword aligned on both Win95 and NT. In the case of + * a bitmap with 22 bytes worth of width, GetObject above returns + * with bmWidth == 22. On Win95 bmWidthBytes == 24, as it should be, + * but on NT is it 22. We need to correct this here. + */ + bm8.bmWidthBytes = (((bm8.bmWidthBytes-1)/4)+1)*4; /* dword aligned!! */ + + /* Copy the bitmap into the memory DC*/ + holdBmp2 = (HBITMAP) SelectObject (hDC, hBmp); + + if (!BitBlt (hMemDC, 0, 0, bm.bmWidth, bm.bmHeight, hDC, 0, 0, SRCCOPY)) + { + g_warning ("BitmapToRegion: BitBlt failed"); + SelectObject (hDC, holdBmp2); + SelectObject (hMemDC, holdBmp); + DeleteObject (hbm8); + DeleteDC (hMemDC); + return NULL; + } + SelectObject (hDC, holdBmp2); + DeleteDC (hDC); + + /* For better performances, we will use the ExtCreateRegion() + * function to create the region. This function take a RGNDATA + * structure on entry. We will add rectangles by amount of + * ALLOC_UNIT number in this structure. + */ + #define ALLOC_UNIT 100 + maxRects = ALLOC_UNIT; + + pData = g_malloc (sizeof (RGNDATAHEADER) + (sizeof (RECT) * maxRects)); + pData->rdh.dwSize = sizeof (RGNDATAHEADER); + pData->rdh.iType = RDH_RECTANGLES; + pData->rdh.nCount = pData->rdh.nRgnSize = 0; + SetRect (&pData->rdh.rcBound, MAXLONG, MAXLONG, 0, 0); + + /* Scan each bitmap from bottom to top (the bitmap is inverted vertically)*/ + p8 = (BYTE *) pbits8 + (bm8.bmHeight - 1) * bm8.bmWidthBytes; + for (y = 0; y < bm.bmHeight; y++) + { + /* Scan each bitmap row from left to right*/ + for (x = 0; x < bm.bmWidth; x++) + { + /* Search for a continuous range of "non transparent pixels"*/ + int x0 = x; + BYTE *p = p8 + x; + while (x < bm.bmWidth) + { + if (*p == 0) + /* This pixel is "transparent"*/ + break; + p++; + x++; + } + + if (x > x0) + { + RECT *pr; + /* Add the pixels (x0, y) to (x, y+1) as a new rectangle + * in the region + */ + if (pData->rdh.nCount >= maxRects) + { + maxRects += ALLOC_UNIT; + pData = g_realloc (pData, sizeof(RGNDATAHEADER) + + (sizeof(RECT) * maxRects)); + } + pr = (RECT *) &pData->Buffer; + SetRect (&pr[pData->rdh.nCount], x0, y, x, y+1); + if (x0 < pData->rdh.rcBound.left) + pData->rdh.rcBound.left = x0; + if (y < pData->rdh.rcBound.top) + pData->rdh.rcBound.top = y; + if (x > pData->rdh.rcBound.right) + pData->rdh.rcBound.right = x; + if (y+1 > pData->rdh.rcBound.bottom) + pData->rdh.rcBound.bottom = y+1; + pData->rdh.nCount++; + + /* On Windows98, ExtCreateRegion() may fail if the + * number of rectangles is too large (ie: > + * 4000). Therefore, we have to create the region by + * multiple steps. + */ + if (pData->rdh.nCount == 2000) + { + HRGN h = ExtCreateRegion (NULL, sizeof(RGNDATAHEADER) + (sizeof(RECT) * maxRects), pData); + if (hRgn) + { + CombineRgn(hRgn, hRgn, h, RGN_OR); + DeleteObject(h); + } + else + hRgn = h; + pData->rdh.nCount = 0; + SetRect (&pData->rdh.rcBound, MAXLONG, MAXLONG, 0, 0); + } + } + } + + /* Go to next row (remember, the bitmap is inverted vertically)*/ + p8 -= bm8.bmWidthBytes; + } + + /* Create or extend the region with the remaining rectangles*/ + h = ExtCreateRegion (NULL, sizeof (RGNDATAHEADER) + + (sizeof (RECT) * maxRects), pData); + if (hRgn) + { + CombineRgn (hRgn, hRgn, h, RGN_OR); + DeleteObject (h); + } + else + hRgn = h; + + /* Clean up*/ + SelectObject(hMemDC, holdBmp); + DeleteObject (hbm8); + DeleteDC (hMemDC); + + return hRgn; +} diff --git a/gdk/win32/gdkgc.c b/gdk/win32/gdkgc.c new file mode 100644 index 000000000..6697090f7 --- /dev/null +++ b/gdk/win32/gdkgc.c @@ -0,0 +1,1373 @@ +/* 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.h" +#include "gdkprivate.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) +{ + GdkWindowPrivate *window_private; + 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); + + window_private = (GdkWindowPrivate*) window; + if (window_private->destroyed) + 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)) + { + private->font = (HFONT) ((GdkFontPrivate*) values->font)->xfont; + GDK_NOTE (MISC, g_print (" font=%#x", private->font)); + } + + 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", ((GdkPixmapPrivate *)private->tile)->xwindow)); + } + else + private->tile = NULL; + + if (values_mask & GDK_GC_STIPPLE) + { + private->stipple = values->tile; + gdk_pixmap_ref (private->stipple); + GDK_NOTE (MISC, g_print (" stipple=%#x", ((GdkPixmapPrivate *)private->stipple)->xwindow)); + } + else + private->stipple = NULL; + + if (values_mask & GDK_GC_CLIP_MASK) + { + private->clip_region = + BitmapToRegion (((GdkPixmapPrivate *)values->clip_mask)->xwindow); + 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) + { +#if 0 + if (!DeleteObject (private->font)) + g_warning ("gdk_gc_unref: DeleteObject #3 failed"); +#endif + } + + 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); + } + memset (gc, 0, sizeof (GdkGCPrivate)); + 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 = gdk_font_lookup (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, ((GdkPixmapPrivate *) pixmap)->xwindow)) == 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; + + g_return_if_fail (gc != NULL); + g_return_if_fail (font != NULL); + + if (font->type == GDK_FONT_FONT) + { + gc_private = (GdkGCPrivate*) gc; + font_private = (GdkFontPrivate*) font; + + GDK_NOTE (MISC, g_print ("gdk_gc_set_font: (%d) %#x\n", + gc_private, font_private->xfont)); + + gc_private->font = font_private->xfont; + 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; + + 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; + GdkPixmapPrivate *pixmap_private; + HBITMAP pixmap; + + g_return_if_fail (gc != NULL); + + private = (GdkGCPrivate*) gc; + + pixmap = NULL; + + if (tile) + { + pixmap_private = (GdkPixmapPrivate*) tile; + pixmap = pixmap_private->xwindow; + } + + 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; + GdkPixmapPrivate *pixmap_private; + HBITMAP pixmap; + + g_return_if_fail (gc != NULL); + + private = (GdkGCPrivate*) gc; + + pixmap = NULL; + + if (stipple) + { + pixmap_private = (GdkPixmapPrivate*) stipple; + pixmap = pixmap_private->xwindow; + } + + 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) + { + GdkWindowPrivate *mask_private; + + mask_private = (GdkWindowPrivate*) mask; + if (mask_private->destroyed) + return; + xmask = mask_private->xwindow; + } + 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 ??? */ + g_warning ("gdk_gc_set_dashes: Not implemented"); +} + +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 (GdkWindowPrivate *window_private, + GdkGCPrivate *gc_private) +{ + GdkColormapPrivate *colormap_private = + (GdkColormapPrivate *) window_private->colormap; + COLORREF bg; + COLORREF fg; + LOGBRUSH logbrush; + HPEN hpen; + HBRUSH hbr; + + g_assert (gc_private->xgc == NULL); + + if (window_private->window_type == GDK_WINDOW_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, window_private->xwindow) == NULL) + g_warning ("gdk_gc_predraw: SelectObject #1 failed"); + } + else + { + if ((gc_private->xgc = GetDC (window_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 = window_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 ((hbr = CreateSolidBrush (fg)) == NULL) + g_warning ("gdk_gc_predraw: CreateSolidBrush failed"); + + 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_FONT) + if (SelectObject (gc_private->xgc, gc_private->font) == NULL) + g_warning ("gdk_gc_predraw: SelectObject #4 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 (GdkWindowPrivate *window_private, + GdkGCPrivate *gc_private) +{ + HGDIOBJ hpen; + HGDIOBJ hbr; + GdkColormapPrivate *colormap_private = + (GdkColormapPrivate *) window_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 (window_private->window_type == GDK_WINDOW_PIXMAP) + { + if (!DeleteDC (gc_private->xgc)) + g_warning ("gdk_gc_postdraw: DeleteDC failed"); + } + else + { + ReleaseDC (gc_private->hwnd, gc_private->xgc); + } + + if (hpen != NULL) + if (!DeleteObject (hpen)) + g_warning ("gdk_gc_postdraw: DeleteObject #1 failed"); + + if (hbr != NULL) + if (!DeleteObject (hbr)) + g_warning ("gdk_gc_postdraw: DeleteObject #2 failed"); + + gc_private->xgc = NULL; +} + +/* This function originally from Jean-Edouard Lachand-Robert, and + * available at www.codeguru.com. Simplified for our needs, now + * handles just one-bit deep bitmaps (in Window parlance, ie those + * that GDK calls bitmaps (and not pixmaps), with zero pixels being + * transparent. + */ + +/* + * BitmapToRegion : Create a region from the "non-transparent" pixels of + * a bitmap + * Author : Jean-Edouard Lachand-Robert + * (http://www.geocities.com/Paris/LeftBank/1160/resume.htm), June 1998. + */ + +HRGN +BitmapToRegion (HBITMAP hBmp) +{ + HRGN hRgn = NULL; + HDC hMemDC; + BITMAP bm; + + struct + { + BITMAPINFOHEADER bmiHeader; +#if 1 + WORD bmiColors[2]; +#else + RGBQUAD bmiColors[2]; +#endif + } bmi; + VOID *pbits8; + HBITMAP hbm8; + struct + { + WORD palVersion; + WORD palNumEntries; + PALETTEENTRY palPalEntry[2]; + } logpal; + static HPALETTE bwPalette = NULL; + + HBITMAP holdBmp; + HDC hDC; + + BITMAP bm8; + HBITMAP holdBmp2; + DWORD maxRects; + RGNDATA *pData; + BYTE *p8; + int x, y; + HRGN h; + + /* Create a B&W palette */ + if (bwPalette == NULL) + { + /* Create a b&w palette */ + logpal.palVersion = 0x300; + logpal.palNumEntries = 2; + logpal.palPalEntry[0].peRed = + logpal.palPalEntry[0].peGreen = + logpal.palPalEntry[0].peBlue = 0; + logpal.palPalEntry[0].peFlags = 0; + logpal.palPalEntry[1].peRed = + logpal.palPalEntry[1].peGreen = + logpal.palPalEntry[1].peBlue = 0xFF; + logpal.palPalEntry[1].peFlags = 0; + if ((bwPalette = CreatePalette ((LOGPALETTE *) &logpal)) == NULL) + g_warning ("BitmapToRegion: CreatePalette failed"); + } + + /* Create a memory DC inside which we will scan the bitmap content */ + hMemDC = CreateCompatibleDC (NULL); + if (!hMemDC) + { + g_warning ("BitmapToRegion: CreateCompatibleDC #1 failed"); + return NULL; + } + + SelectPalette (hMemDC, bwPalette, FALSE); + RealizePalette (hMemDC); + + /* Get bitmap size */ + GetObject(hBmp, sizeof(bm), &bm); + + /* Create a 8 bits depth bitmap and select it into the memory DC */ + bmi.bmiHeader.biSize = sizeof (BITMAPINFOHEADER); + bmi.bmiHeader.biWidth = bm.bmWidth; + bmi.bmiHeader.biHeight = bm.bmHeight; + bmi.bmiHeader.biPlanes = 1; + bmi.bmiHeader.biBitCount = 8; + bmi.bmiHeader.biCompression = BI_RGB; + bmi.bmiHeader.biSizeImage = 0; + bmi.bmiHeader.biXPelsPerMeter = 0; + bmi.bmiHeader.biYPelsPerMeter = 0; + bmi.bmiHeader.biClrUsed = 2; + bmi.bmiHeader.biClrImportant = 2; +#if 1 + bmi.bmiColors[0] = 0; + bmi.bmiColors[1] = 1; + hbm8 = CreateDIBSection (hMemDC, (BITMAPINFO *)&bmi, + DIB_PAL_COLORS, &pbits8, NULL, 0); +#else + bmi.bmiColors[0].rgbBlue = + bmi.bmiColors[0].rgbGreen = + bmi.bmiColors[0].rgbRed = 0x00; + bmi.bmiColors[0].rgbReserved = 0x00; + + bmi.bmiColors[1].rgbBlue = + bmi.bmiColors[1].rgbGreen = + bmi.bmiColors[1].rgbRed = 0xFF; + bmi.bmiColors[0].rgbReserved = 0x00; + + hbm8 = CreateDIBSection (hMemDC, (BITMAPINFO *)&bmi, + DIB_RGB_COLORS, &pbits8, NULL, 0); +#endif + if (!hbm8) + { + g_warning ("BitmapToRegion: CreateDIBSection failed"); + DeleteDC (hMemDC); + return NULL; + } + + holdBmp = (HBITMAP) SelectObject (hMemDC, hbm8); + + /* Create a DC just to copy the bitmap into the memory DC*/ + hDC = CreateCompatibleDC (hMemDC); + if (!hDC) + { + g_warning ("BitmapToRegion: CreateCompatibleDC #2 failed"); + SelectObject (hMemDC, holdBmp); + DeleteObject (hbm8); + DeleteDC (hMemDC); + return NULL; + } + + /* Get how many bytes per row we have for the bitmap bits */ + GetObject (hbm8, sizeof (bm8), &bm8); + + /* Hans Breuer found a fix to the long-standing erroneous behaviour + * on NT 4.0: There seems to be a bug in Win NT 4.0 GDI: scanlines + * in bitmaps are dword aligned on both Win95 and NT. In the case of + * a bitmap with 22 bytes worth of width, GetObject above returns + * with bmWidth == 22. On Win95 bmWidthBytes == 24, as it should be, + * but on NT is it 22. We need to correct this here. + */ + bm8.bmWidthBytes = (((bm8.bmWidthBytes-1)/4)+1)*4; /* dword aligned!! */ + + /* Copy the bitmap into the memory DC*/ + holdBmp2 = (HBITMAP) SelectObject (hDC, hBmp); + + if (!BitBlt (hMemDC, 0, 0, bm.bmWidth, bm.bmHeight, hDC, 0, 0, SRCCOPY)) + { + g_warning ("BitmapToRegion: BitBlt failed"); + SelectObject (hDC, holdBmp2); + SelectObject (hMemDC, holdBmp); + DeleteObject (hbm8); + DeleteDC (hMemDC); + return NULL; + } + SelectObject (hDC, holdBmp2); + DeleteDC (hDC); + + /* For better performances, we will use the ExtCreateRegion() + * function to create the region. This function take a RGNDATA + * structure on entry. We will add rectangles by amount of + * ALLOC_UNIT number in this structure. + */ + #define ALLOC_UNIT 100 + maxRects = ALLOC_UNIT; + + pData = g_malloc (sizeof (RGNDATAHEADER) + (sizeof (RECT) * maxRects)); + pData->rdh.dwSize = sizeof (RGNDATAHEADER); + pData->rdh.iType = RDH_RECTANGLES; + pData->rdh.nCount = pData->rdh.nRgnSize = 0; + SetRect (&pData->rdh.rcBound, MAXLONG, MAXLONG, 0, 0); + + /* Scan each bitmap from bottom to top (the bitmap is inverted vertically)*/ + p8 = (BYTE *) pbits8 + (bm8.bmHeight - 1) * bm8.bmWidthBytes; + for (y = 0; y < bm.bmHeight; y++) + { + /* Scan each bitmap row from left to right*/ + for (x = 0; x < bm.bmWidth; x++) + { + /* Search for a continuous range of "non transparent pixels"*/ + int x0 = x; + BYTE *p = p8 + x; + while (x < bm.bmWidth) + { + if (*p == 0) + /* This pixel is "transparent"*/ + break; + p++; + x++; + } + + if (x > x0) + { + RECT *pr; + /* Add the pixels (x0, y) to (x, y+1) as a new rectangle + * in the region + */ + if (pData->rdh.nCount >= maxRects) + { + maxRects += ALLOC_UNIT; + pData = g_realloc (pData, sizeof(RGNDATAHEADER) + + (sizeof(RECT) * maxRects)); + } + pr = (RECT *) &pData->Buffer; + SetRect (&pr[pData->rdh.nCount], x0, y, x, y+1); + if (x0 < pData->rdh.rcBound.left) + pData->rdh.rcBound.left = x0; + if (y < pData->rdh.rcBound.top) + pData->rdh.rcBound.top = y; + if (x > pData->rdh.rcBound.right) + pData->rdh.rcBound.right = x; + if (y+1 > pData->rdh.rcBound.bottom) + pData->rdh.rcBound.bottom = y+1; + pData->rdh.nCount++; + + /* On Windows98, ExtCreateRegion() may fail if the + * number of rectangles is too large (ie: > + * 4000). Therefore, we have to create the region by + * multiple steps. + */ + if (pData->rdh.nCount == 2000) + { + HRGN h = ExtCreateRegion (NULL, sizeof(RGNDATAHEADER) + (sizeof(RECT) * maxRects), pData); + if (hRgn) + { + CombineRgn(hRgn, hRgn, h, RGN_OR); + DeleteObject(h); + } + else + hRgn = h; + pData->rdh.nCount = 0; + SetRect (&pData->rdh.rcBound, MAXLONG, MAXLONG, 0, 0); + } + } + } + + /* Go to next row (remember, the bitmap is inverted vertically)*/ + p8 -= bm8.bmWidthBytes; + } + + /* Create or extend the region with the remaining rectangles*/ + h = ExtCreateRegion (NULL, sizeof (RGNDATAHEADER) + + (sizeof (RECT) * maxRects), pData); + if (hRgn) + { + CombineRgn (hRgn, hRgn, h, RGN_OR); + DeleteObject (h); + } + else + hRgn = h; + + /* Clean up*/ + SelectObject(hMemDC, holdBmp); + DeleteObject (hbm8); + DeleteDC (hMemDC); + + return hRgn; +} diff --git a/gdk/win32/gdkglobals-win32.c b/gdk/win32/gdkglobals-win32.c new file mode 100644 index 000000000..d89aa0ba7 --- /dev/null +++ b/gdk/win32/gdkglobals-win32.c @@ -0,0 +1,94 @@ +/* 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> +#if !defined (X_DISPLAY_MISSING) +#include <X11/Xlib.h> +#endif +#include "gdk.h" +#include "gdkprivate.h" + +guint gdk_debug_flags = 0; +HWND gdk_root_window; +HWND gdk_leader_window; +GdkWindowPrivate gdk_root_parent = { { NULL, }, NULL, }; +#if !defined(X_DISPLAY_MISSING) +gchar *gdk_display_name = NULL; +gint gdk_use_xshm = TRUE; +Atom gdk_wm_delete_window; +Atom gdk_wm_take_focus; +Atom gdk_wm_protocols; +Atom gdk_wm_window_protocols[2]; +GdkDndCursorInfo gdk_dnd_cursorinfo = {None, None, NULL, NULL, + {0,0}, {0,0}, NULL}; +GdkDndGlobals gdk_dnd = {None,None,None, + None,None,None, + None, + &gdk_dnd_cursorinfo, + NULL, + 0, + FALSE, FALSE, FALSE, + None, + {0,0}, + {0,0}, {0,0}, + {0,0,0,0}, NULL, None, 0}; +#elif defined (WINDOWS_DISPLAY) + +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; + +#endif /* WINDOWS_DISPLAY */ + +Atom gdk_selection_property; +gchar *gdk_progclass = NULL; +gint gdk_error_code; +gint gdk_error_warnings = TRUE; +gint gdk_null_window_warnings = TRUE; +GList *gdk_default_filters = NULL; + +gboolean gdk_xim_using; /* using XIM Protocol if TRUE */ +GdkWindow *gdk_xim_window; /* currently using Widow */ + +GdkWindowPrivate *gdk_xgrab_window = NULL; /* Window that currently holds the + * x pointer grab + */ + +GMutex *gdk_threads_mutex = NULL; /* Global GDK lock */ + +#ifdef USE_XIM +GdkICPrivate *gdk_xim_ic; /* currently using IC */ +GdkWindow *gdk_xim_window; /* currently using Window */ +#endif diff --git a/gdk/win32/gdkglobals.c b/gdk/win32/gdkglobals.c new file mode 100644 index 000000000..d89aa0ba7 --- /dev/null +++ b/gdk/win32/gdkglobals.c @@ -0,0 +1,94 @@ +/* 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> +#if !defined (X_DISPLAY_MISSING) +#include <X11/Xlib.h> +#endif +#include "gdk.h" +#include "gdkprivate.h" + +guint gdk_debug_flags = 0; +HWND gdk_root_window; +HWND gdk_leader_window; +GdkWindowPrivate gdk_root_parent = { { NULL, }, NULL, }; +#if !defined(X_DISPLAY_MISSING) +gchar *gdk_display_name = NULL; +gint gdk_use_xshm = TRUE; +Atom gdk_wm_delete_window; +Atom gdk_wm_take_focus; +Atom gdk_wm_protocols; +Atom gdk_wm_window_protocols[2]; +GdkDndCursorInfo gdk_dnd_cursorinfo = {None, None, NULL, NULL, + {0,0}, {0,0}, NULL}; +GdkDndGlobals gdk_dnd = {None,None,None, + None,None,None, + None, + &gdk_dnd_cursorinfo, + NULL, + 0, + FALSE, FALSE, FALSE, + None, + {0,0}, + {0,0}, {0,0}, + {0,0,0,0}, NULL, None, 0}; +#elif defined (WINDOWS_DISPLAY) + +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; + +#endif /* WINDOWS_DISPLAY */ + +Atom gdk_selection_property; +gchar *gdk_progclass = NULL; +gint gdk_error_code; +gint gdk_error_warnings = TRUE; +gint gdk_null_window_warnings = TRUE; +GList *gdk_default_filters = NULL; + +gboolean gdk_xim_using; /* using XIM Protocol if TRUE */ +GdkWindow *gdk_xim_window; /* currently using Widow */ + +GdkWindowPrivate *gdk_xgrab_window = NULL; /* Window that currently holds the + * x pointer grab + */ + +GMutex *gdk_threads_mutex = NULL; /* Global GDK lock */ + +#ifdef USE_XIM +GdkICPrivate *gdk_xim_ic; /* currently using IC */ +GdkWindow *gdk_xim_window; /* currently using Window */ +#endif diff --git a/gdk/win32/gdkim-win32.c b/gdk/win32/gdkim-win32.c new file mode 100644 index 000000000..e3f6e09c6 --- /dev/null +++ b/gdk/win32/gdkim-win32.c @@ -0,0 +1,248 @@ +/* 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> +# if STDC_HEADERS +# include <string.h> +# endif +#endif + +#include "gdk.h" +#include "gdkprivate.h" +#include "gdki18n.h" +#include "gdkx.h" + +/* If this variable is FALSE, it indicates that we should + * avoid trying to use multibyte conversion functions and + * assume everything is 1-byte per character + */ +static gboolean gdk_use_mb; + +/* + *-------------------------------------------------------------- + * gdk_set_locale + * + * Arguments: + * + * Results: + * + * Side effects: + * + *-------------------------------------------------------------- + */ + +gchar* +gdk_set_locale (void) +{ + wchar_t result; + gchar *current_locale; + + gdk_use_mb = FALSE; + + if (!setlocale (LC_ALL,"")) + g_warning ("locale not supported by C library"); + + current_locale = setlocale (LC_ALL, NULL); + + if (MB_CUR_MAX > 1) + gdk_use_mb = TRUE; + + GDK_NOTE (XIM, g_message ("%s multi-byte string functions.", + gdk_use_mb ? "Using" : "Not using")); + + 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. + */ +gchar * +gdk_wcstombs (const GdkWChar *src) +{ + gchar *mbstr; + + if (gdk_use_mb) + { + gint i, wcsl, mbsl; + wchar_t *src_alt; + + for (wcsl = 0; src[wcsl]; wcsl++) + ; + src_alt = g_new (wchar_t, wcsl+1); + for (i = wcsl; i >= 0; i--) + src_alt[i] = src[i]; + mbsl = WideCharToMultiByte (CP_ACP, 0, src_alt, wcsl, + NULL, 0, NULL, NULL); + mbstr = g_new (guchar, mbsl + 1); + if (!WideCharToMultiByte (CP_ACP, 0, src_alt, wcsl, + mbstr, mbsl, NULL, NULL)) + { + g_warning ("gdk_wcstombs: WideCharToMultiByte failed"); + g_free (mbstr); + g_free (src_alt); + return NULL; + } + mbstr[mbsl] = '\0'; + g_free (src_alt); + return mbstr; + } + else + { + gint length = 0; + gint i; + + while (src[length] != 0) + length++; + + mbstr = g_new (gchar, length + 1); + + for (i=0; i<length+1; i++) + mbstr[i] = src[i]; + } + + return mbstr; +} + + +/* + * gdk_mbstowcs + * + * Converts the specified string into 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. + */ +gint +gdk_mbstowcs (GdkWChar *dest, const gchar *src, gint dest_max) +{ + if (gdk_use_mb) + { + gint i, wcsl; + wchar_t *wcstr; + + wcsl = MultiByteToWideChar (CP_ACP, 0, src, -1, NULL, 0); + wcstr = g_new (wchar_t, wcsl + 1); + if (!MultiByteToWideChar (CP_ACP, 0, src, -1, wcstr, wcsl)) + { + g_warning ("gdk_mbstowcs: MultiByteToWideChar failed"); + g_free (wcstr); + return -1; + } + if (wcsl > dest_max) + wcsl = dest_max; + for (i = 0; i < wcsl; i++) + dest[i] = wcstr[i]; + + return wcsl; + } + else + { + gint i; + + for (i=0; i<dest_max && src[i]; i++) + dest[i] = src[i]; + + return i; + } +} diff --git a/gdk/win32/gdkim.c b/gdk/win32/gdkim.c new file mode 100644 index 000000000..e3f6e09c6 --- /dev/null +++ b/gdk/win32/gdkim.c @@ -0,0 +1,248 @@ +/* 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> +# if STDC_HEADERS +# include <string.h> +# endif +#endif + +#include "gdk.h" +#include "gdkprivate.h" +#include "gdki18n.h" +#include "gdkx.h" + +/* If this variable is FALSE, it indicates that we should + * avoid trying to use multibyte conversion functions and + * assume everything is 1-byte per character + */ +static gboolean gdk_use_mb; + +/* + *-------------------------------------------------------------- + * gdk_set_locale + * + * Arguments: + * + * Results: + * + * Side effects: + * + *-------------------------------------------------------------- + */ + +gchar* +gdk_set_locale (void) +{ + wchar_t result; + gchar *current_locale; + + gdk_use_mb = FALSE; + + if (!setlocale (LC_ALL,"")) + g_warning ("locale not supported by C library"); + + current_locale = setlocale (LC_ALL, NULL); + + if (MB_CUR_MAX > 1) + gdk_use_mb = TRUE; + + GDK_NOTE (XIM, g_message ("%s multi-byte string functions.", + gdk_use_mb ? "Using" : "Not using")); + + 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. + */ +gchar * +gdk_wcstombs (const GdkWChar *src) +{ + gchar *mbstr; + + if (gdk_use_mb) + { + gint i, wcsl, mbsl; + wchar_t *src_alt; + + for (wcsl = 0; src[wcsl]; wcsl++) + ; + src_alt = g_new (wchar_t, wcsl+1); + for (i = wcsl; i >= 0; i--) + src_alt[i] = src[i]; + mbsl = WideCharToMultiByte (CP_ACP, 0, src_alt, wcsl, + NULL, 0, NULL, NULL); + mbstr = g_new (guchar, mbsl + 1); + if (!WideCharToMultiByte (CP_ACP, 0, src_alt, wcsl, + mbstr, mbsl, NULL, NULL)) + { + g_warning ("gdk_wcstombs: WideCharToMultiByte failed"); + g_free (mbstr); + g_free (src_alt); + return NULL; + } + mbstr[mbsl] = '\0'; + g_free (src_alt); + return mbstr; + } + else + { + gint length = 0; + gint i; + + while (src[length] != 0) + length++; + + mbstr = g_new (gchar, length + 1); + + for (i=0; i<length+1; i++) + mbstr[i] = src[i]; + } + + return mbstr; +} + + +/* + * gdk_mbstowcs + * + * Converts the specified string into 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. + */ +gint +gdk_mbstowcs (GdkWChar *dest, const gchar *src, gint dest_max) +{ + if (gdk_use_mb) + { + gint i, wcsl; + wchar_t *wcstr; + + wcsl = MultiByteToWideChar (CP_ACP, 0, src, -1, NULL, 0); + wcstr = g_new (wchar_t, wcsl + 1); + if (!MultiByteToWideChar (CP_ACP, 0, src, -1, wcstr, wcsl)) + { + g_warning ("gdk_mbstowcs: MultiByteToWideChar failed"); + g_free (wcstr); + return -1; + } + if (wcsl > dest_max) + wcsl = dest_max; + for (i = 0; i < wcsl; i++) + dest[i] = wcstr[i]; + + return wcsl; + } + else + { + gint i; + + for (i=0; i<dest_max && src[i]; i++) + dest[i] = src[i]; + + return i; + } +} diff --git a/gdk/win32/gdkimage-win32.c b/gdk/win32/gdkimage-win32.c new file mode 100644 index 000000000..371960916 --- /dev/null +++ b/gdk/win32/gdkimage-win32.c @@ -0,0 +1,760 @@ +/* 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" + +static void gdk_image_put_normal (GdkDrawable *drawable, + GdkGC *gc, + GdkImage *image, + gint xsrc, + gint ysrc, + gint xdest, + gint ydest, + gint width, + gint height); +static GList *image_list = NULL; + +void +gdk_image_exit (void) +{ + GdkImage *image; + + while (image_list) + { + image = image_list->data; + gdk_image_destroy (image); + } +} + +GdkImage * +gdk_image_new_bitmap (GdkVisual *visual, gpointer data, gint w, gint h) +/* + * Desc: create a new bitmap image + */ +{ + Visual *xvisual; + GdkImage *image; + GdkImagePrivate *private; + struct { + BITMAPINFOHEADER bmiHeader; + union { + WORD bmiIndices[2]; + RGBQUAD bmiColors[2]; + } u; + } bmi; + char *bits; + int bpl = (w-1)/8 + 1; + int bpl32 = ((w-1)/32 + 1)*4; + + private = g_new(GdkImagePrivate, 1); + image = (GdkImage *) private; + private->image_put = gdk_image_put_normal; + image->type = GDK_IMAGE_NORMAL; + image->visual = visual; + image->width = w; + image->height = h; + image->depth = 1; + xvisual = ((GdkVisualPrivate*) visual)->xvisual; + + GDK_NOTE (MISC, g_print ("gdk_image_new_bitmap: %dx%d\n", w, h)); + + bmi.bmiHeader.biSize = sizeof (BITMAPINFOHEADER); + bmi.bmiHeader.biWidth = w; + bmi.bmiHeader.biHeight = -h; + bmi.bmiHeader.biPlanes = 1; + bmi.bmiHeader.biBitCount = 1; + bmi.bmiHeader.biCompression = BI_RGB; + bmi.bmiHeader.biSizeImage = 0; + bmi.bmiHeader.biXPelsPerMeter = + bmi.bmiHeader.biYPelsPerMeter = 0; + bmi.bmiHeader.biClrUsed = 0; + bmi.bmiHeader.biClrImportant = 0; + + 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->ximage = CreateDIBSection (gdk_DC, (BITMAPINFO *) &bmi, + DIB_RGB_COLORS, &bits, NULL, 0); + if (bpl != bpl32) + { + /* Win32 expects scanlines in DIBs to be 32 bit aligned */ + int i; + for (i = 0; i < h; i++) + memmove (bits + i*bpl32, ((char *) data) + i*bpl, bpl); + } + else + memmove (bits, data, bpl*h); + image->mem = bits; + image->bpl = bpl32; + image->byte_order = GDK_MSB_FIRST; + + image->bpp = 1; + return(image); +} /* gdk_image_new_bitmap() */ + +void +gdk_image_init (void) +{ +} + +static GdkImage* +gdk_image_new_with_depth (GdkImageType type, + GdkVisual *visual, + gint width, + gint height, + gint depth) +{ + GdkImage *image; + GdkImagePrivate *private; + Visual *xvisual; + struct { + BITMAPINFOHEADER bmiHeader; + union { + WORD bmiIndices[256]; + DWORD bmiMasks[3]; + RGBQUAD bmiColors[256]; + } u; + } bmi; + UINT iUsage; + int i; + + GDK_NOTE (MISC, g_print ("gdk_image_new_with_depth: %dx%dx%d\n", + width, height, depth)); + + switch (type) + { + case GDK_IMAGE_FASTEST: + image = gdk_image_new_with_depth (GDK_IMAGE_SHARED, visual, + width, height, depth); + + if (!image) + image = gdk_image_new_with_depth (GDK_IMAGE_NORMAL, visual, + width, height, depth); + break; + + default: + private = g_new (GdkImagePrivate, 1); + image = (GdkImage*) private; + + private->image_put = NULL; + + image->type = type; + image->visual = visual; + image->width = width; + image->height = height; + image->depth = depth; + + xvisual = ((GdkVisualPrivate*) visual)->xvisual; + + switch (type) + { + case GDK_IMAGE_SHARED: + case GDK_IMAGE_SHARED_PIXMAP: + /* Fall through, Windows images are always shared */ + case GDK_IMAGE_NORMAL: + private->image_put = gdk_image_put_normal; + + 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; + + if (image->visual->type == GDK_VISUAL_PSEUDO_COLOR) + { + iUsage = DIB_PAL_COLORS; + for (i = 0; i < 256; i++) + bmi.u.bmiIndices[i] = i; + } + else + { + 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; + + } +#if 1 + else 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 + iUsage = DIB_RGB_COLORS; + } + + private->ximage = + CreateDIBSection (gdk_DC, (BITMAPINFO *) &bmi, iUsage, + &image->mem, NULL, 0); + + if (private->ximage == NULL) + { + g_warning ("gdk_image_new_with_depth: CreateDIBSection failed"); + g_free (image); + return NULL; + } + + switch (depth) + { + case 1: + case 8: + image->bpp = 1; + break; + case 15: + case 16: + image->bpp = 2; + break; + case 24: + image->bpp = 3; + break; + case 32: + image->bpp = 4; + break; + default: + g_warning ("gdk_image_new_with_depth: depth = %d", depth); + g_assert_not_reached (); + } + image->byte_order = GDK_LSB_FIRST; + if (depth == 1) + image->bpl = ((width-1)/32 + 1)*4; + else + image->bpl = ((width*image->bpp - 1)/4 + 1)*4; + + GDK_NOTE (MISC, g_print ("... = %#x mem = %#x, bpl = %d\n", + private->ximage, image->mem, image->bpl)); + + break; + + case GDK_IMAGE_FASTEST: + g_assert_not_reached (); + } + + break; + } + + return image; +} + +GdkImage* +gdk_image_new (GdkImageType type, + GdkVisual *visual, + gint width, + gint height) +{ + return gdk_image_new_with_depth (type, visual, width, height, visual->depth); +} + +GdkImage* +gdk_image_bitmap_new (GdkImageType type, + GdkVisual *visual, + gint width, + gint height) +{ + return gdk_image_new_with_depth (type, visual, width, height, 1); +} + +GdkImage* +gdk_image_get (GdkWindow *window, + gint x, + gint y, + gint width, + gint height) +{ + GdkImage *image; + GdkImagePrivate *private; + GdkWindowPrivate *win_private; + HDC hdc, memdc; + struct { + BITMAPINFOHEADER bmiHeader; + union { + WORD bmiIndices[256]; + DWORD bmiMasks[3]; + RGBQUAD bmiColors[256]; + } u; + } bmi; + HGDIOBJ oldbitmap1, oldbitmap2; + UINT iUsage; + BITMAP bm; + int i; + + g_return_val_if_fail (window != NULL, NULL); + + win_private = (GdkWindowPrivate *) window; + if (win_private->destroyed) + return NULL; + + GDK_NOTE (MISC, g_print ("gdk_image_get: %#x %dx%d@+%d+%d\n", + win_private->xwindow, width, height, x, y)); + + private = g_new (GdkImagePrivate, 1); + image = (GdkImage*) private; + + private->image_put = gdk_image_put_normal; + + image->type = GDK_IMAGE_NORMAL; + image->visual = gdk_window_get_visual (window); + image->width = width; + image->height = height; + + /* This function is called both to blit from a window and from + * a pixmap. + */ + if (win_private->window_type == GDK_WINDOW_PIXMAP) + { + if ((hdc = CreateCompatibleDC (NULL)) == NULL) + { + g_warning ("gdk_image_get: CreateCompatibleDC #1 failed"); + g_free (image); + return NULL; + } + if ((oldbitmap1 = SelectObject (hdc, win_private->xwindow)) == NULL) + { + g_warning ("gdk_image_get: SelectObject #1 failed"); + DeleteDC (hdc); + g_free (image); + return NULL; + } + GetObject (win_private->xwindow, sizeof (BITMAP), &bm); + GDK_NOTE (MISC, + g_print ("gdk_image_get: bmWidth = %d, bmHeight = %d, bmWidthBytes = %d, bmBitsPixel = %d\n", + bm.bmWidth, bm.bmHeight, bm.bmWidthBytes, bm.bmBitsPixel)); + image->depth = bm.bmBitsPixel; + if (image->depth <= 8) + { + iUsage = DIB_PAL_COLORS; + for (i = 0; i < 256; i++) + bmi.u.bmiIndices[i] = i; + } + else + iUsage = DIB_RGB_COLORS; + } + else + { + if ((hdc = GetDC (win_private->xwindow)) == NULL) + { + g_warning ("gdk_image_get: GetDC failed"); + g_free (image); + return NULL; + } + image->depth = gdk_visual_get_system ()->depth; + if (image->visual->type == GDK_VISUAL_PSEUDO_COLOR) + { + iUsage = DIB_PAL_COLORS; + for (i = 0; i < 256; i++) + bmi.u.bmiIndices[i] = i; + } + else + iUsage = DIB_RGB_COLORS; + } + + if ((memdc = CreateCompatibleDC (hdc)) == NULL) + { + g_warning ("gdk_image_get: CreateCompatibleDC #2 failed"); + if (win_private->window_type == GDK_WINDOW_PIXMAP) + { + SelectObject (hdc, oldbitmap1); + DeleteDC (hdc); + } + else + { + ReleaseDC (win_private->xwindow, hdc); + } + g_free (image); + return NULL; + } + + bmi.bmiHeader.biSize = sizeof (BITMAPINFOHEADER); + bmi.bmiHeader.biWidth = width; + bmi.bmiHeader.biHeight = -height; + bmi.bmiHeader.biPlanes = 1; + bmi.bmiHeader.biBitCount = image->depth; + bmi.bmiHeader.biCompression = BI_RGB; + bmi.bmiHeader.biSizeImage = 0; + bmi.bmiHeader.biXPelsPerMeter = + bmi.bmiHeader.biYPelsPerMeter = 0; + bmi.bmiHeader.biClrUsed = 0; + bmi.bmiHeader.biClrImportant = 0; + + if ((private->ximage = + CreateDIBSection (hdc, (BITMAPINFO *) &bmi, iUsage, + &image->mem, NULL, 0)) == NULL) + { + g_warning ("gdk_image_get: CreateDIBSection failed"); + DeleteDC (memdc); + if (win_private->window_type == GDK_WINDOW_PIXMAP) + { + SelectObject (hdc, oldbitmap1); + DeleteDC (hdc); + } + else + { + ReleaseDC (win_private->xwindow, hdc); + } + g_free (image); + return NULL; + } + + if ((oldbitmap2 = SelectObject (memdc, private->ximage)) == NULL) + { + g_warning ("gdk_image_get: SelectObject #2 failed"); + DeleteObject (private->ximage); + DeleteDC (memdc); + if (win_private->window_type == GDK_WINDOW_PIXMAP) + { + SelectObject (hdc, oldbitmap1); + DeleteDC (hdc); + } + else + { + ReleaseDC (win_private->xwindow, hdc); + } + g_free (image); + return NULL; + } + + if (!BitBlt (memdc, 0, 0, width, height, hdc, x, y, SRCCOPY)) + { + g_warning ("gdk_image_get: BitBlt failed"); + SelectObject (memdc, oldbitmap2); + DeleteObject (private->ximage); + DeleteDC (memdc); + if (win_private->window_type == GDK_WINDOW_PIXMAP) + { + SelectObject (hdc, oldbitmap1); + DeleteDC (hdc); + } + else + { + ReleaseDC (win_private->xwindow, hdc); + } + g_free (image); + return NULL; + } + + if (SelectObject (memdc, oldbitmap2) == NULL) + g_warning ("gdk_image_get: SelectObject #3 failed"); + + if (!DeleteDC (memdc)) + g_warning ("gdk_image_get: DeleteDC failed"); + + if (win_private->window_type == GDK_WINDOW_PIXMAP) + { + SelectObject (hdc, oldbitmap1); + DeleteDC (hdc); + } + else + { + ReleaseDC (win_private->xwindow, hdc); + } + + switch (image->depth) + { + case 1: + case 8: + image->bpp = 1; + break; + case 15: + case 16: + image->bpp = 2; + break; + case 24: + image->bpp = 3; + break; + case 32: + image->bpp = 4; + break; + default: + g_warning ("gdk_image_get: image->depth = %d", image->depth); + g_assert_not_reached (); + } + image->byte_order = GDK_LSB_FIRST; + if (image->depth == 1) + image->bpl = (width - 1)/8 + 1; + else + image->bpl = ((width*image->bpp - 1)/4 + 1)*4; + + GDK_NOTE (MISC, g_print ("... = %#x mem = %#x, bpl = %d\n", + private->ximage, image->mem, image->bpl)); + + return image; +} + +guint32 +gdk_image_get_pixel (GdkImage *image, + gint x, + gint y) +{ + guint32 pixel; + GdkImagePrivate *private; + + g_return_val_if_fail (image != NULL, 0); + + private = (GdkImagePrivate *) image; + + g_return_val_if_fail (x >= 0 && x < image->width + && y >= 0 && y < image->height, 0); + + if (image->depth == 1) + pixel = (((char *) image->mem)[y * image->bpl + (x >> 3)] & (1 << (7 - (x & 0x7)))) != 0; + else + { + guchar *pixelp = (guchar *) image->mem + y * image->bpl + x * image->bpp; + + switch (image->bpp) + { + case 1: + pixel = *pixelp; + break; + + /* Windows is always LSB, no need to check image->byte_order. */ + case 2: + pixel = pixelp[0] | (pixelp[1] << 8); + break; + + case 3: + pixel = pixelp[0] | (pixelp[1] << 8) | (pixelp[2] << 16); + break; + + case 4: + pixel = pixelp[0] | (pixelp[1] << 8) | (pixelp[2] << 16); + break; + } + } + + return pixel; +} + +void +gdk_image_put_pixel (GdkImage *image, + gint x, + gint y, + guint32 pixel) +{ + GdkImagePrivate *private; + + g_return_if_fail (image != NULL); + + private = (GdkImagePrivate *) image; + + g_return_if_fail (x >= 0 && x < image->width && y >= 0 && y < image->height); + + if (image->depth == 1) + if (pixel & 1) + ((guchar *) image->mem)[y * image->bpl + (x >> 3)] |= (1 << (7 - (x & 0x7))); + else + ((guchar *) image->mem)[y * image->bpl + (x >> 3)] &= ~(1 << (7 - (x & 0x7))); + else + { + guchar *pixelp = (guchar *) image->mem + y * image->bpl + x * image->bpp; + + /* Windows is always LSB, no need to check image->byte_order. */ + switch (image->bpp) + { + case 4: + pixelp[3] = 0; + case 3: + pixelp[2] = ((pixel >> 16) & 0xFF); + case 2: + pixelp[1] = ((pixel >> 8) & 0xFF); + case 1: + pixelp[0] = (pixel & 0xFF); + } + } +} + +void +gdk_image_destroy (GdkImage *image) +{ + GdkImagePrivate *private; + + g_return_if_fail (image != NULL); + + private = (GdkImagePrivate*) image; + + GDK_NOTE (MISC, g_print ("gdk_image_destroy: %#x%s\n", + private->ximage, + (image->type == GDK_IMAGE_SHARED_PIXMAP ? + " (shared pixmap)" : ""))); + + switch (image->type) + { + case GDK_IMAGE_NORMAL: + case GDK_IMAGE_SHARED_PIXMAP: + break; /* The Windows bitmap has already been + * (or will be) deleted when freeing + * the corresponding pixmap. + */ + + case GDK_IMAGE_SHARED: /* All images are shared in Windows */ + DeleteObject (private->ximage); + break; + + case GDK_IMAGE_FASTEST: + g_assert_not_reached (); + } + + g_free (image); +} + +static void +gdk_image_put_normal (GdkDrawable *drawable, + GdkGC *gc, + GdkImage *image, + gint xsrc, + gint ysrc, + gint xdest, + gint ydest, + gint width, + gint height) +{ + GdkWindowPrivate *drawable_private; + GdkImagePrivate *image_private; + GdkGCPrivate *gc_private; + HDC hdc; + GdkColormapPrivate *colormap_private; + + g_return_if_fail (drawable != NULL); + g_return_if_fail (image != NULL); + g_return_if_fail (gc != NULL); + + drawable_private = (GdkWindowPrivate*) drawable; + if (drawable_private->destroyed) + return; + image_private = (GdkImagePrivate*) image; + gc_private = (GdkGCPrivate*) gc; + + /* The image can in fact be "shared", so don't test */ + + hdc = gdk_gc_predraw (drawable_private, gc_private); + colormap_private = (GdkColormapPrivate *) drawable_private->colormap; + if (colormap_private && colormap_private->xcolormap->rc_palette) + { + DIBSECTION ds; + static struct { + BITMAPINFOHEADER bmiHeader; + WORD bmiIndices[256]; + } bmi; + static gboolean bmi_inited = FALSE; + int i; + + if (!bmi_inited) + { + for (i = 0; i < 256; i++) + bmi.bmiIndices[i] = i; + bmi_inited = TRUE; + } + + if (GetObject (image_private->ximage, sizeof (DIBSECTION), + &ds) != sizeof (DIBSECTION)) + { + g_warning ("gdk_image_put_normal: GetObject failed"); + } +#if 0 + g_print("xdest = %d, ydest = %d, xsrc = %d, ysrc = %d, width = %d, height = %d\n", + xdest, ydest, xsrc, ysrc, width, height); + g_print("bmWidth = %d, bmHeight = %d, bmBitsPixel = %d, bmBits = %p\n", + ds.dsBm.bmWidth, ds.dsBm.bmHeight, ds.dsBm.bmBitsPixel, ds.dsBm.bmBits); + g_print("biWidth = %d, biHeight = %d, biBitCount = %d, biClrUsed = %d\n", + ds.dsBmih.biWidth, ds.dsBmih.biHeight, ds.dsBmih.biBitCount, ds.dsBmih.biClrUsed); +#endif + bmi.bmiHeader = ds.dsBmih; + /* I have spent hours on getting the parameters to + * SetDIBitsToDevice right. I wonder what drugs the guys in + * Redmond were on when they designed this API. + */ + if (SetDIBitsToDevice (hdc, + xdest, ydest, + width, height, + xsrc, (-ds.dsBmih.biHeight)-height-ysrc, + 0, -ds.dsBmih.biHeight, + ds.dsBm.bmBits, + (CONST BITMAPINFO *) &bmi, + DIB_PAL_COLORS) == 0) + g_warning ("SetDIBitsToDevice failed"); + } + else + { + HDC memdc; + HGDIOBJ oldbitmap; + + if ((memdc = CreateCompatibleDC (hdc)) == NULL) + { + g_warning ("gdk_image_put_normal: CreateCompatibleDC failed"); + gdk_gc_postdraw (drawable_private, gc_private); + return; + } + + if ((oldbitmap = SelectObject (memdc, image_private->ximage)) == NULL) + { + g_warning ("gdk_image_put_normal: SelectObject #1 failed"); + gdk_gc_postdraw (drawable_private, gc_private); + return; + } + if (!BitBlt (hdc, xdest, ydest, width, height, + memdc, xsrc, ysrc, SRCCOPY)) + g_warning ("gdk_image_put_normal: BitBlt failed"); + + if (SelectObject (memdc, oldbitmap) == NULL) + g_warning ("gdk_image_put_normal: SelectObject #2 failed"); + + if (!DeleteDC (memdc)) + g_warning ("gdk_image_put_normal: DeleteDC failed"); + } + gdk_gc_postdraw (drawable_private, gc_private); +} diff --git a/gdk/win32/gdkimage.c b/gdk/win32/gdkimage.c new file mode 100644 index 000000000..371960916 --- /dev/null +++ b/gdk/win32/gdkimage.c @@ -0,0 +1,760 @@ +/* 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" + +static void gdk_image_put_normal (GdkDrawable *drawable, + GdkGC *gc, + GdkImage *image, + gint xsrc, + gint ysrc, + gint xdest, + gint ydest, + gint width, + gint height); +static GList *image_list = NULL; + +void +gdk_image_exit (void) +{ + GdkImage *image; + + while (image_list) + { + image = image_list->data; + gdk_image_destroy (image); + } +} + +GdkImage * +gdk_image_new_bitmap (GdkVisual *visual, gpointer data, gint w, gint h) +/* + * Desc: create a new bitmap image + */ +{ + Visual *xvisual; + GdkImage *image; + GdkImagePrivate *private; + struct { + BITMAPINFOHEADER bmiHeader; + union { + WORD bmiIndices[2]; + RGBQUAD bmiColors[2]; + } u; + } bmi; + char *bits; + int bpl = (w-1)/8 + 1; + int bpl32 = ((w-1)/32 + 1)*4; + + private = g_new(GdkImagePrivate, 1); + image = (GdkImage *) private; + private->image_put = gdk_image_put_normal; + image->type = GDK_IMAGE_NORMAL; + image->visual = visual; + image->width = w; + image->height = h; + image->depth = 1; + xvisual = ((GdkVisualPrivate*) visual)->xvisual; + + GDK_NOTE (MISC, g_print ("gdk_image_new_bitmap: %dx%d\n", w, h)); + + bmi.bmiHeader.biSize = sizeof (BITMAPINFOHEADER); + bmi.bmiHeader.biWidth = w; + bmi.bmiHeader.biHeight = -h; + bmi.bmiHeader.biPlanes = 1; + bmi.bmiHeader.biBitCount = 1; + bmi.bmiHeader.biCompression = BI_RGB; + bmi.bmiHeader.biSizeImage = 0; + bmi.bmiHeader.biXPelsPerMeter = + bmi.bmiHeader.biYPelsPerMeter = 0; + bmi.bmiHeader.biClrUsed = 0; + bmi.bmiHeader.biClrImportant = 0; + + 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->ximage = CreateDIBSection (gdk_DC, (BITMAPINFO *) &bmi, + DIB_RGB_COLORS, &bits, NULL, 0); + if (bpl != bpl32) + { + /* Win32 expects scanlines in DIBs to be 32 bit aligned */ + int i; + for (i = 0; i < h; i++) + memmove (bits + i*bpl32, ((char *) data) + i*bpl, bpl); + } + else + memmove (bits, data, bpl*h); + image->mem = bits; + image->bpl = bpl32; + image->byte_order = GDK_MSB_FIRST; + + image->bpp = 1; + return(image); +} /* gdk_image_new_bitmap() */ + +void +gdk_image_init (void) +{ +} + +static GdkImage* +gdk_image_new_with_depth (GdkImageType type, + GdkVisual *visual, + gint width, + gint height, + gint depth) +{ + GdkImage *image; + GdkImagePrivate *private; + Visual *xvisual; + struct { + BITMAPINFOHEADER bmiHeader; + union { + WORD bmiIndices[256]; + DWORD bmiMasks[3]; + RGBQUAD bmiColors[256]; + } u; + } bmi; + UINT iUsage; + int i; + + GDK_NOTE (MISC, g_print ("gdk_image_new_with_depth: %dx%dx%d\n", + width, height, depth)); + + switch (type) + { + case GDK_IMAGE_FASTEST: + image = gdk_image_new_with_depth (GDK_IMAGE_SHARED, visual, + width, height, depth); + + if (!image) + image = gdk_image_new_with_depth (GDK_IMAGE_NORMAL, visual, + width, height, depth); + break; + + default: + private = g_new (GdkImagePrivate, 1); + image = (GdkImage*) private; + + private->image_put = NULL; + + image->type = type; + image->visual = visual; + image->width = width; + image->height = height; + image->depth = depth; + + xvisual = ((GdkVisualPrivate*) visual)->xvisual; + + switch (type) + { + case GDK_IMAGE_SHARED: + case GDK_IMAGE_SHARED_PIXMAP: + /* Fall through, Windows images are always shared */ + case GDK_IMAGE_NORMAL: + private->image_put = gdk_image_put_normal; + + 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; + + if (image->visual->type == GDK_VISUAL_PSEUDO_COLOR) + { + iUsage = DIB_PAL_COLORS; + for (i = 0; i < 256; i++) + bmi.u.bmiIndices[i] = i; + } + else + { + 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; + + } +#if 1 + else 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 + iUsage = DIB_RGB_COLORS; + } + + private->ximage = + CreateDIBSection (gdk_DC, (BITMAPINFO *) &bmi, iUsage, + &image->mem, NULL, 0); + + if (private->ximage == NULL) + { + g_warning ("gdk_image_new_with_depth: CreateDIBSection failed"); + g_free (image); + return NULL; + } + + switch (depth) + { + case 1: + case 8: + image->bpp = 1; + break; + case 15: + case 16: + image->bpp = 2; + break; + case 24: + image->bpp = 3; + break; + case 32: + image->bpp = 4; + break; + default: + g_warning ("gdk_image_new_with_depth: depth = %d", depth); + g_assert_not_reached (); + } + image->byte_order = GDK_LSB_FIRST; + if (depth == 1) + image->bpl = ((width-1)/32 + 1)*4; + else + image->bpl = ((width*image->bpp - 1)/4 + 1)*4; + + GDK_NOTE (MISC, g_print ("... = %#x mem = %#x, bpl = %d\n", + private->ximage, image->mem, image->bpl)); + + break; + + case GDK_IMAGE_FASTEST: + g_assert_not_reached (); + } + + break; + } + + return image; +} + +GdkImage* +gdk_image_new (GdkImageType type, + GdkVisual *visual, + gint width, + gint height) +{ + return gdk_image_new_with_depth (type, visual, width, height, visual->depth); +} + +GdkImage* +gdk_image_bitmap_new (GdkImageType type, + GdkVisual *visual, + gint width, + gint height) +{ + return gdk_image_new_with_depth (type, visual, width, height, 1); +} + +GdkImage* +gdk_image_get (GdkWindow *window, + gint x, + gint y, + gint width, + gint height) +{ + GdkImage *image; + GdkImagePrivate *private; + GdkWindowPrivate *win_private; + HDC hdc, memdc; + struct { + BITMAPINFOHEADER bmiHeader; + union { + WORD bmiIndices[256]; + DWORD bmiMasks[3]; + RGBQUAD bmiColors[256]; + } u; + } bmi; + HGDIOBJ oldbitmap1, oldbitmap2; + UINT iUsage; + BITMAP bm; + int i; + + g_return_val_if_fail (window != NULL, NULL); + + win_private = (GdkWindowPrivate *) window; + if (win_private->destroyed) + return NULL; + + GDK_NOTE (MISC, g_print ("gdk_image_get: %#x %dx%d@+%d+%d\n", + win_private->xwindow, width, height, x, y)); + + private = g_new (GdkImagePrivate, 1); + image = (GdkImage*) private; + + private->image_put = gdk_image_put_normal; + + image->type = GDK_IMAGE_NORMAL; + image->visual = gdk_window_get_visual (window); + image->width = width; + image->height = height; + + /* This function is called both to blit from a window and from + * a pixmap. + */ + if (win_private->window_type == GDK_WINDOW_PIXMAP) + { + if ((hdc = CreateCompatibleDC (NULL)) == NULL) + { + g_warning ("gdk_image_get: CreateCompatibleDC #1 failed"); + g_free (image); + return NULL; + } + if ((oldbitmap1 = SelectObject (hdc, win_private->xwindow)) == NULL) + { + g_warning ("gdk_image_get: SelectObject #1 failed"); + DeleteDC (hdc); + g_free (image); + return NULL; + } + GetObject (win_private->xwindow, sizeof (BITMAP), &bm); + GDK_NOTE (MISC, + g_print ("gdk_image_get: bmWidth = %d, bmHeight = %d, bmWidthBytes = %d, bmBitsPixel = %d\n", + bm.bmWidth, bm.bmHeight, bm.bmWidthBytes, bm.bmBitsPixel)); + image->depth = bm.bmBitsPixel; + if (image->depth <= 8) + { + iUsage = DIB_PAL_COLORS; + for (i = 0; i < 256; i++) + bmi.u.bmiIndices[i] = i; + } + else + iUsage = DIB_RGB_COLORS; + } + else + { + if ((hdc = GetDC (win_private->xwindow)) == NULL) + { + g_warning ("gdk_image_get: GetDC failed"); + g_free (image); + return NULL; + } + image->depth = gdk_visual_get_system ()->depth; + if (image->visual->type == GDK_VISUAL_PSEUDO_COLOR) + { + iUsage = DIB_PAL_COLORS; + for (i = 0; i < 256; i++) + bmi.u.bmiIndices[i] = i; + } + else + iUsage = DIB_RGB_COLORS; + } + + if ((memdc = CreateCompatibleDC (hdc)) == NULL) + { + g_warning ("gdk_image_get: CreateCompatibleDC #2 failed"); + if (win_private->window_type == GDK_WINDOW_PIXMAP) + { + SelectObject (hdc, oldbitmap1); + DeleteDC (hdc); + } + else + { + ReleaseDC (win_private->xwindow, hdc); + } + g_free (image); + return NULL; + } + + bmi.bmiHeader.biSize = sizeof (BITMAPINFOHEADER); + bmi.bmiHeader.biWidth = width; + bmi.bmiHeader.biHeight = -height; + bmi.bmiHeader.biPlanes = 1; + bmi.bmiHeader.biBitCount = image->depth; + bmi.bmiHeader.biCompression = BI_RGB; + bmi.bmiHeader.biSizeImage = 0; + bmi.bmiHeader.biXPelsPerMeter = + bmi.bmiHeader.biYPelsPerMeter = 0; + bmi.bmiHeader.biClrUsed = 0; + bmi.bmiHeader.biClrImportant = 0; + + if ((private->ximage = + CreateDIBSection (hdc, (BITMAPINFO *) &bmi, iUsage, + &image->mem, NULL, 0)) == NULL) + { + g_warning ("gdk_image_get: CreateDIBSection failed"); + DeleteDC (memdc); + if (win_private->window_type == GDK_WINDOW_PIXMAP) + { + SelectObject (hdc, oldbitmap1); + DeleteDC (hdc); + } + else + { + ReleaseDC (win_private->xwindow, hdc); + } + g_free (image); + return NULL; + } + + if ((oldbitmap2 = SelectObject (memdc, private->ximage)) == NULL) + { + g_warning ("gdk_image_get: SelectObject #2 failed"); + DeleteObject (private->ximage); + DeleteDC (memdc); + if (win_private->window_type == GDK_WINDOW_PIXMAP) + { + SelectObject (hdc, oldbitmap1); + DeleteDC (hdc); + } + else + { + ReleaseDC (win_private->xwindow, hdc); + } + g_free (image); + return NULL; + } + + if (!BitBlt (memdc, 0, 0, width, height, hdc, x, y, SRCCOPY)) + { + g_warning ("gdk_image_get: BitBlt failed"); + SelectObject (memdc, oldbitmap2); + DeleteObject (private->ximage); + DeleteDC (memdc); + if (win_private->window_type == GDK_WINDOW_PIXMAP) + { + SelectObject (hdc, oldbitmap1); + DeleteDC (hdc); + } + else + { + ReleaseDC (win_private->xwindow, hdc); + } + g_free (image); + return NULL; + } + + if (SelectObject (memdc, oldbitmap2) == NULL) + g_warning ("gdk_image_get: SelectObject #3 failed"); + + if (!DeleteDC (memdc)) + g_warning ("gdk_image_get: DeleteDC failed"); + + if (win_private->window_type == GDK_WINDOW_PIXMAP) + { + SelectObject (hdc, oldbitmap1); + DeleteDC (hdc); + } + else + { + ReleaseDC (win_private->xwindow, hdc); + } + + switch (image->depth) + { + case 1: + case 8: + image->bpp = 1; + break; + case 15: + case 16: + image->bpp = 2; + break; + case 24: + image->bpp = 3; + break; + case 32: + image->bpp = 4; + break; + default: + g_warning ("gdk_image_get: image->depth = %d", image->depth); + g_assert_not_reached (); + } + image->byte_order = GDK_LSB_FIRST; + if (image->depth == 1) + image->bpl = (width - 1)/8 + 1; + else + image->bpl = ((width*image->bpp - 1)/4 + 1)*4; + + GDK_NOTE (MISC, g_print ("... = %#x mem = %#x, bpl = %d\n", + private->ximage, image->mem, image->bpl)); + + return image; +} + +guint32 +gdk_image_get_pixel (GdkImage *image, + gint x, + gint y) +{ + guint32 pixel; + GdkImagePrivate *private; + + g_return_val_if_fail (image != NULL, 0); + + private = (GdkImagePrivate *) image; + + g_return_val_if_fail (x >= 0 && x < image->width + && y >= 0 && y < image->height, 0); + + if (image->depth == 1) + pixel = (((char *) image->mem)[y * image->bpl + (x >> 3)] & (1 << (7 - (x & 0x7)))) != 0; + else + { + guchar *pixelp = (guchar *) image->mem + y * image->bpl + x * image->bpp; + + switch (image->bpp) + { + case 1: + pixel = *pixelp; + break; + + /* Windows is always LSB, no need to check image->byte_order. */ + case 2: + pixel = pixelp[0] | (pixelp[1] << 8); + break; + + case 3: + pixel = pixelp[0] | (pixelp[1] << 8) | (pixelp[2] << 16); + break; + + case 4: + pixel = pixelp[0] | (pixelp[1] << 8) | (pixelp[2] << 16); + break; + } + } + + return pixel; +} + +void +gdk_image_put_pixel (GdkImage *image, + gint x, + gint y, + guint32 pixel) +{ + GdkImagePrivate *private; + + g_return_if_fail (image != NULL); + + private = (GdkImagePrivate *) image; + + g_return_if_fail (x >= 0 && x < image->width && y >= 0 && y < image->height); + + if (image->depth == 1) + if (pixel & 1) + ((guchar *) image->mem)[y * image->bpl + (x >> 3)] |= (1 << (7 - (x & 0x7))); + else + ((guchar *) image->mem)[y * image->bpl + (x >> 3)] &= ~(1 << (7 - (x & 0x7))); + else + { + guchar *pixelp = (guchar *) image->mem + y * image->bpl + x * image->bpp; + + /* Windows is always LSB, no need to check image->byte_order. */ + switch (image->bpp) + { + case 4: + pixelp[3] = 0; + case 3: + pixelp[2] = ((pixel >> 16) & 0xFF); + case 2: + pixelp[1] = ((pixel >> 8) & 0xFF); + case 1: + pixelp[0] = (pixel & 0xFF); + } + } +} + +void +gdk_image_destroy (GdkImage *image) +{ + GdkImagePrivate *private; + + g_return_if_fail (image != NULL); + + private = (GdkImagePrivate*) image; + + GDK_NOTE (MISC, g_print ("gdk_image_destroy: %#x%s\n", + private->ximage, + (image->type == GDK_IMAGE_SHARED_PIXMAP ? + " (shared pixmap)" : ""))); + + switch (image->type) + { + case GDK_IMAGE_NORMAL: + case GDK_IMAGE_SHARED_PIXMAP: + break; /* The Windows bitmap has already been + * (or will be) deleted when freeing + * the corresponding pixmap. + */ + + case GDK_IMAGE_SHARED: /* All images are shared in Windows */ + DeleteObject (private->ximage); + break; + + case GDK_IMAGE_FASTEST: + g_assert_not_reached (); + } + + g_free (image); +} + +static void +gdk_image_put_normal (GdkDrawable *drawable, + GdkGC *gc, + GdkImage *image, + gint xsrc, + gint ysrc, + gint xdest, + gint ydest, + gint width, + gint height) +{ + GdkWindowPrivate *drawable_private; + GdkImagePrivate *image_private; + GdkGCPrivate *gc_private; + HDC hdc; + GdkColormapPrivate *colormap_private; + + g_return_if_fail (drawable != NULL); + g_return_if_fail (image != NULL); + g_return_if_fail (gc != NULL); + + drawable_private = (GdkWindowPrivate*) drawable; + if (drawable_private->destroyed) + return; + image_private = (GdkImagePrivate*) image; + gc_private = (GdkGCPrivate*) gc; + + /* The image can in fact be "shared", so don't test */ + + hdc = gdk_gc_predraw (drawable_private, gc_private); + colormap_private = (GdkColormapPrivate *) drawable_private->colormap; + if (colormap_private && colormap_private->xcolormap->rc_palette) + { + DIBSECTION ds; + static struct { + BITMAPINFOHEADER bmiHeader; + WORD bmiIndices[256]; + } bmi; + static gboolean bmi_inited = FALSE; + int i; + + if (!bmi_inited) + { + for (i = 0; i < 256; i++) + bmi.bmiIndices[i] = i; + bmi_inited = TRUE; + } + + if (GetObject (image_private->ximage, sizeof (DIBSECTION), + &ds) != sizeof (DIBSECTION)) + { + g_warning ("gdk_image_put_normal: GetObject failed"); + } +#if 0 + g_print("xdest = %d, ydest = %d, xsrc = %d, ysrc = %d, width = %d, height = %d\n", + xdest, ydest, xsrc, ysrc, width, height); + g_print("bmWidth = %d, bmHeight = %d, bmBitsPixel = %d, bmBits = %p\n", + ds.dsBm.bmWidth, ds.dsBm.bmHeight, ds.dsBm.bmBitsPixel, ds.dsBm.bmBits); + g_print("biWidth = %d, biHeight = %d, biBitCount = %d, biClrUsed = %d\n", + ds.dsBmih.biWidth, ds.dsBmih.biHeight, ds.dsBmih.biBitCount, ds.dsBmih.biClrUsed); +#endif + bmi.bmiHeader = ds.dsBmih; + /* I have spent hours on getting the parameters to + * SetDIBitsToDevice right. I wonder what drugs the guys in + * Redmond were on when they designed this API. + */ + if (SetDIBitsToDevice (hdc, + xdest, ydest, + width, height, + xsrc, (-ds.dsBmih.biHeight)-height-ysrc, + 0, -ds.dsBmih.biHeight, + ds.dsBm.bmBits, + (CONST BITMAPINFO *) &bmi, + DIB_PAL_COLORS) == 0) + g_warning ("SetDIBitsToDevice failed"); + } + else + { + HDC memdc; + HGDIOBJ oldbitmap; + + if ((memdc = CreateCompatibleDC (hdc)) == NULL) + { + g_warning ("gdk_image_put_normal: CreateCompatibleDC failed"); + gdk_gc_postdraw (drawable_private, gc_private); + return; + } + + if ((oldbitmap = SelectObject (memdc, image_private->ximage)) == NULL) + { + g_warning ("gdk_image_put_normal: SelectObject #1 failed"); + gdk_gc_postdraw (drawable_private, gc_private); + return; + } + if (!BitBlt (hdc, xdest, ydest, width, height, + memdc, xsrc, ysrc, SRCCOPY)) + g_warning ("gdk_image_put_normal: BitBlt failed"); + + if (SelectObject (memdc, oldbitmap) == NULL) + g_warning ("gdk_image_put_normal: SelectObject #2 failed"); + + if (!DeleteDC (memdc)) + g_warning ("gdk_image_put_normal: DeleteDC failed"); + } + gdk_gc_postdraw (drawable_private, gc_private); +} diff --git a/gdk/win32/gdkinput-win32.c b/gdk/win32/gdkinput-win32.c new file mode 100644 index 000000000..fcd3c109f --- /dev/null +++ b/gdk/win32/gdkinput-win32.c @@ -0,0 +1,1524 @@ +/* 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 "gdkx.h" +#include "gdkprivate.h" + +#include "gdkinput.h" + +#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. + */ + +#define TWOPI (2.*M_PI) + +#define PING() g_print("%s: %d\n",__FILE__,__LINE__) + +/* Forward declarations */ + +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 void gdk_input_none_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); +static GdkInputWindow *gdk_input_window_find_within (GdkWindow *window); +static GdkDevicePrivate *gdk_input_find_device (guint32 deviceid); +static GdkDevicePrivate *gdk_input_find_dev_from_ctx (HCTX hctx, + UINT id); + +/* 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 0 + +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) +{ + GdkDevicePrivate *gdkdev; + GdkWindowPrivate *window_private; + GdkWindowAttr wa; + WORD specversion; + LOGCONTEXT defcontext; + HCTX *hctx; + UINT ndevices, ncursors, ncsrtypes, firstcsr, hardware; + AXIS axis_x, axis_y, axis_npressure, axis_orientation[3]; + int i, j, k; + char devname[100], csrname[100]; + guint32 deviceid_counter = 0; + + gdk_input_devices = NULL; + wintab_contexts = NULL; + + if (!gdk_input_ignore_wintab && + WTInfo (0, 0, NULL)) + { + WTInfo (WTI_INTERFACE, IFC_SPECVERSION, &specversion); + +#if USE_SYSCONTEXT + WTInfo (WTI_DEFSYSCTX, 0, &defcontext); +#else + WTInfo (WTI_DEFCONTEXT, 0, &defcontext); +#endif +#if 0 + g_print("DEFCONTEXT:\n"); print_lc(&defcontext); +#endif + WTInfo (WTI_INTERFACE, IFC_NDEVICES, &ndevices); + WTInfo (WTI_INTERFACE, IFC_NCURSORS, &ncursors); + + /* 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 = (GdkWindowPrivate *) wintab_window; + + for (i = 0; i < ndevices; i++) + { + LOGCONTEXT lc; + + WTInfo (WTI_DEVICES + i, DVC_NAME, devname); + + WTInfo (WTI_DEVICES + i, DVC_NCSRTYPES, &ncsrtypes); + WTInfo (WTI_DEVICES + i, DVC_FIRSTCSR, &firstcsr); + WTInfo (WTI_DEVICES + i, DVC_HARDWARE, &hardware); + WTInfo (WTI_DEVICES + i, DVC_X, &axis_x); + WTInfo (WTI_DEVICES + i, DVC_Y, &axis_y); + WTInfo (WTI_DEVICES + i, DVC_NPRESSURE, &axis_npressure); + WTInfo (WTI_DEVICES + i, DVC_ORIENTATION, axis_orientation); + + if (HIBYTE (specversion) > 1 || LOBYTE (specversion) >= 1) + { + WTInfo (WTI_DDCTXS + i, CTX_NAME, lc.lcName); + WTInfo (WTI_DDCTXS + i, CTX_OPTIONS, &lc.lcOptions); + lc.lcOptions |= CXO_MESSAGES; + lc.lcStatus = 0; + WTInfo (WTI_DDCTXS + i, CTX_LOCKS, &lc.lcLocks); + lc.lcMsgBase = WT_DEFBASE; + lc.lcDevice = i; + lc.lcPktRate = 20; + lc.lcPktData = PACKETDATA; + lc.lcPktMode = PK_BUTTONS; /* We want buttons in relative mode */ + lc.lcMoveMask = PACKETDATA; + lc.lcBtnDnMask = lc.lcBtnUpMask = ~0; + WTInfo (WTI_DDCTXS + i, CTX_INORGX, &lc.lcInOrgX); + WTInfo (WTI_DDCTXS + i, CTX_INORGY, &lc.lcInOrgY); + WTInfo (WTI_DDCTXS + i, CTX_INORGZ, &lc.lcInOrgZ); + WTInfo (WTI_DDCTXS + i, CTX_INEXTX, &lc.lcInExtX); + WTInfo (WTI_DDCTXS + i, CTX_INEXTY, &lc.lcInExtY); + WTInfo (WTI_DDCTXS + i, 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 + i, CTX_SENSX, &lc.lcSensX); + WTInfo (WTI_DDCTXS + i, CTX_SENSY, &lc.lcSensY); + WTInfo (WTI_DDCTXS + i, CTX_SENSZ, &lc.lcSensZ); + WTInfo (WTI_DDCTXS + i, CTX_SYSMODE, &lc.lcSysMode); + lc.lcSysOrgX = lc.lcSysOrgY = 0; + WTInfo (WTI_DDCTXS + i, CTX_SYSEXTX, &lc.lcSysExtX); + WTInfo (WTI_DDCTXS + i, CTX_SYSEXTY, &lc.lcSysExtY); + WTInfo (WTI_DDCTXS + i, CTX_SYSSENSX, &lc.lcSysSensX); + WTInfo (WTI_DDCTXS + i, CTX_SYSSENSY, &lc.lcSysSensY); + } + else + { + lc = defcontext; + lc.lcOptions |= CXO_MESSAGES; + lc.lcMsgBase = WT_DEFBASE; + lc.lcPktRate = 20; /* Slow down the packets a bit */ + 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 0 + g_print("context for device %d:\n", i); 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 ("gdk_input_init: opened Wintab device %d %#x\n", + i, *hctx)); + + wintab_contexts = g_list_append (wintab_contexts, hctx); +#if 0 + WTEnable (*hctx, TRUE); +#endif + WTOverlap (*hctx, TRUE); + +#if 0 + g_print("context for device %d after WTOpen:\n", i); print_lc(&lc); +#endif + for (j = firstcsr; j < firstcsr + ncsrtypes; j++) + { + gdkdev = g_new (GdkDevicePrivate, 1); + WTInfo (WTI_CURSORS + j, 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 = j; + WTInfo (WTI_CURSORS + j, 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++; + if (gdkdev->pktdata & PK_ORIENTATION) + gdkdev->info.num_axes += 2; /* x and y tilt */ + WTInfo (WTI_CURSORS + j, 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_orientation[0]; + gdkdev->orientation_axes[1] = axis_orientation[1]; + for (axis = GDK_AXIS_XTILT; axis <= GDK_AXIS_YTILT; axis++) + { + 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 ("gdk_input_init: device: %d axes: %d\n", + gdkdev->info.deviceid, + gdkdev->info.num_axes)); + gdk_input_devices = g_list_append (gdk_input_devices, + gdkdev); + } + } + 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 + { + 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); +} + +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 void +gdk_input_translate_coordinates (GdkDevicePrivate *gdkdev, + GdkInputWindow *input_window, + gint *axis_data, + gdouble *x, + gdouble *y, + gdouble *pressure, + gdouble *xtilt, + gdouble *ytilt) +{ + GdkWindowPrivate *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 = (GdkWindowPrivate *) 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; + } +} + +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_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_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; +} + +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_WINDOW_XWINDOW (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_WINDOW_XWINDOW (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 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", window_private->xwindow, 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 (window_private->xwindow, &pt); + gdk_window_unref (window); + window = window_private->parent; + gdk_window_ref (window); + window_private = (GdkWindowPrivate *) window; + ScreenToClient (window_private->xwindow, &pt); + x = pt.x; + y = pt.y; + GDK_NOTE (EVENTS, g_print ("...propagating to %#x, (%d,%d)\n", window_private->xwindow, 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\n", + (event->button.type == GDK_BUTTON_PRESS ? + "press" : "release"), + event->button.deviceid, + event->button.button, + event->button.x, event->button.y, + event->button.pressure)); + } + 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\n", + event->motion.deviceid, + event->motion.x, event->motion.y, + event->motion.pressure)); + + /* 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; + + 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 + 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 + 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; + + 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 + if (gdkdev->info.deviceid != GDK_CORE_POINTER && gdkdev->xdevice) + XUngrabDevice (gdk_display, gdkdev->xdevice, time); +#endif + tmp_list = tmp_list->next; + } + } +} + +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) +{ + GdkWindowPrivate *window_private; + GdkTimeCoord *coords; + int i; + + g_return_val_if_fail (window != NULL, NULL); + window_private = (GdkWindowPrivate *) window; + if (window_private->destroyed) + return NULL; + + *nevents_return = 0; + return NULL; /* ??? */ +} + +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 */ +} + +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; +} + +/* 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); + window_private = (GdkWindowPrivate *) window; + if (window_private->destroyed) + return; + + 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_win32_enable_window (window, gdkdev); + else + gdk_input_win32_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) +{ + 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); + +#if 1 + for (tmp_list = wintab_contexts; tmp_list; tmp_list = tmp_list->next) + { + HCTX *hctx = (HCTX *) tmp_list->data; + BOOL result; + + /* For some reason WTEnable and/or WTClose tend to crash here. + * Protect with __try/__except to avoid a message box. + */ + __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); + g_free (hctx); + } +#endif + g_list_free (wintab_contexts); +} + +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; +} + +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; +} + +void +gdk_input_window_get_pointer (GdkWindow *window, + guint32 deviceid, + gdouble *x, + gdouble *y, + gdouble *pressure, + gdouble *xtilt, + gdouble *ytilt, + GdkModifierType *mask) +{ + if (gdk_input_vtable.get_pointer) + gdk_input_vtable.get_pointer (window, deviceid, x, y, pressure, + xtilt, ytilt, mask); +} diff --git a/gdk/win32/gdkinput.c b/gdk/win32/gdkinput.c new file mode 100644 index 000000000..fcd3c109f --- /dev/null +++ b/gdk/win32/gdkinput.c @@ -0,0 +1,1524 @@ +/* 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 "gdkx.h" +#include "gdkprivate.h" + +#include "gdkinput.h" + +#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. + */ + +#define TWOPI (2.*M_PI) + +#define PING() g_print("%s: %d\n",__FILE__,__LINE__) + +/* Forward declarations */ + +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 void gdk_input_none_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); +static GdkInputWindow *gdk_input_window_find_within (GdkWindow *window); +static GdkDevicePrivate *gdk_input_find_device (guint32 deviceid); +static GdkDevicePrivate *gdk_input_find_dev_from_ctx (HCTX hctx, + UINT id); + +/* 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 0 + +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) +{ + GdkDevicePrivate *gdkdev; + GdkWindowPrivate *window_private; + GdkWindowAttr wa; + WORD specversion; + LOGCONTEXT defcontext; + HCTX *hctx; + UINT ndevices, ncursors, ncsrtypes, firstcsr, hardware; + AXIS axis_x, axis_y, axis_npressure, axis_orientation[3]; + int i, j, k; + char devname[100], csrname[100]; + guint32 deviceid_counter = 0; + + gdk_input_devices = NULL; + wintab_contexts = NULL; + + if (!gdk_input_ignore_wintab && + WTInfo (0, 0, NULL)) + { + WTInfo (WTI_INTERFACE, IFC_SPECVERSION, &specversion); + +#if USE_SYSCONTEXT + WTInfo (WTI_DEFSYSCTX, 0, &defcontext); +#else + WTInfo (WTI_DEFCONTEXT, 0, &defcontext); +#endif +#if 0 + g_print("DEFCONTEXT:\n"); print_lc(&defcontext); +#endif + WTInfo (WTI_INTERFACE, IFC_NDEVICES, &ndevices); + WTInfo (WTI_INTERFACE, IFC_NCURSORS, &ncursors); + + /* 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 = (GdkWindowPrivate *) wintab_window; + + for (i = 0; i < ndevices; i++) + { + LOGCONTEXT lc; + + WTInfo (WTI_DEVICES + i, DVC_NAME, devname); + + WTInfo (WTI_DEVICES + i, DVC_NCSRTYPES, &ncsrtypes); + WTInfo (WTI_DEVICES + i, DVC_FIRSTCSR, &firstcsr); + WTInfo (WTI_DEVICES + i, DVC_HARDWARE, &hardware); + WTInfo (WTI_DEVICES + i, DVC_X, &axis_x); + WTInfo (WTI_DEVICES + i, DVC_Y, &axis_y); + WTInfo (WTI_DEVICES + i, DVC_NPRESSURE, &axis_npressure); + WTInfo (WTI_DEVICES + i, DVC_ORIENTATION, axis_orientation); + + if (HIBYTE (specversion) > 1 || LOBYTE (specversion) >= 1) + { + WTInfo (WTI_DDCTXS + i, CTX_NAME, lc.lcName); + WTInfo (WTI_DDCTXS + i, CTX_OPTIONS, &lc.lcOptions); + lc.lcOptions |= CXO_MESSAGES; + lc.lcStatus = 0; + WTInfo (WTI_DDCTXS + i, CTX_LOCKS, &lc.lcLocks); + lc.lcMsgBase = WT_DEFBASE; + lc.lcDevice = i; + lc.lcPktRate = 20; + lc.lcPktData = PACKETDATA; + lc.lcPktMode = PK_BUTTONS; /* We want buttons in relative mode */ + lc.lcMoveMask = PACKETDATA; + lc.lcBtnDnMask = lc.lcBtnUpMask = ~0; + WTInfo (WTI_DDCTXS + i, CTX_INORGX, &lc.lcInOrgX); + WTInfo (WTI_DDCTXS + i, CTX_INORGY, &lc.lcInOrgY); + WTInfo (WTI_DDCTXS + i, CTX_INORGZ, &lc.lcInOrgZ); + WTInfo (WTI_DDCTXS + i, CTX_INEXTX, &lc.lcInExtX); + WTInfo (WTI_DDCTXS + i, CTX_INEXTY, &lc.lcInExtY); + WTInfo (WTI_DDCTXS + i, 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 + i, CTX_SENSX, &lc.lcSensX); + WTInfo (WTI_DDCTXS + i, CTX_SENSY, &lc.lcSensY); + WTInfo (WTI_DDCTXS + i, CTX_SENSZ, &lc.lcSensZ); + WTInfo (WTI_DDCTXS + i, CTX_SYSMODE, &lc.lcSysMode); + lc.lcSysOrgX = lc.lcSysOrgY = 0; + WTInfo (WTI_DDCTXS + i, CTX_SYSEXTX, &lc.lcSysExtX); + WTInfo (WTI_DDCTXS + i, CTX_SYSEXTY, &lc.lcSysExtY); + WTInfo (WTI_DDCTXS + i, CTX_SYSSENSX, &lc.lcSysSensX); + WTInfo (WTI_DDCTXS + i, CTX_SYSSENSY, &lc.lcSysSensY); + } + else + { + lc = defcontext; + lc.lcOptions |= CXO_MESSAGES; + lc.lcMsgBase = WT_DEFBASE; + lc.lcPktRate = 20; /* Slow down the packets a bit */ + 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 0 + g_print("context for device %d:\n", i); 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 ("gdk_input_init: opened Wintab device %d %#x\n", + i, *hctx)); + + wintab_contexts = g_list_append (wintab_contexts, hctx); +#if 0 + WTEnable (*hctx, TRUE); +#endif + WTOverlap (*hctx, TRUE); + +#if 0 + g_print("context for device %d after WTOpen:\n", i); print_lc(&lc); +#endif + for (j = firstcsr; j < firstcsr + ncsrtypes; j++) + { + gdkdev = g_new (GdkDevicePrivate, 1); + WTInfo (WTI_CURSORS + j, 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 = j; + WTInfo (WTI_CURSORS + j, 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++; + if (gdkdev->pktdata & PK_ORIENTATION) + gdkdev->info.num_axes += 2; /* x and y tilt */ + WTInfo (WTI_CURSORS + j, 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_orientation[0]; + gdkdev->orientation_axes[1] = axis_orientation[1]; + for (axis = GDK_AXIS_XTILT; axis <= GDK_AXIS_YTILT; axis++) + { + 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 ("gdk_input_init: device: %d axes: %d\n", + gdkdev->info.deviceid, + gdkdev->info.num_axes)); + gdk_input_devices = g_list_append (gdk_input_devices, + gdkdev); + } + } + 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 + { + 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); +} + +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 void +gdk_input_translate_coordinates (GdkDevicePrivate *gdkdev, + GdkInputWindow *input_window, + gint *axis_data, + gdouble *x, + gdouble *y, + gdouble *pressure, + gdouble *xtilt, + gdouble *ytilt) +{ + GdkWindowPrivate *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 = (GdkWindowPrivate *) 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; + } +} + +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_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_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; +} + +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_WINDOW_XWINDOW (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_WINDOW_XWINDOW (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 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", window_private->xwindow, 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 (window_private->xwindow, &pt); + gdk_window_unref (window); + window = window_private->parent; + gdk_window_ref (window); + window_private = (GdkWindowPrivate *) window; + ScreenToClient (window_private->xwindow, &pt); + x = pt.x; + y = pt.y; + GDK_NOTE (EVENTS, g_print ("...propagating to %#x, (%d,%d)\n", window_private->xwindow, 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\n", + (event->button.type == GDK_BUTTON_PRESS ? + "press" : "release"), + event->button.deviceid, + event->button.button, + event->button.x, event->button.y, + event->button.pressure)); + } + 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\n", + event->motion.deviceid, + event->motion.x, event->motion.y, + event->motion.pressure)); + + /* 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; + + 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 + 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 + 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; + + 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 + if (gdkdev->info.deviceid != GDK_CORE_POINTER && gdkdev->xdevice) + XUngrabDevice (gdk_display, gdkdev->xdevice, time); +#endif + tmp_list = tmp_list->next; + } + } +} + +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) +{ + GdkWindowPrivate *window_private; + GdkTimeCoord *coords; + int i; + + g_return_val_if_fail (window != NULL, NULL); + window_private = (GdkWindowPrivate *) window; + if (window_private->destroyed) + return NULL; + + *nevents_return = 0; + return NULL; /* ??? */ +} + +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 */ +} + +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; +} + +/* 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); + window_private = (GdkWindowPrivate *) window; + if (window_private->destroyed) + return; + + 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_win32_enable_window (window, gdkdev); + else + gdk_input_win32_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) +{ + 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); + +#if 1 + for (tmp_list = wintab_contexts; tmp_list; tmp_list = tmp_list->next) + { + HCTX *hctx = (HCTX *) tmp_list->data; + BOOL result; + + /* For some reason WTEnable and/or WTClose tend to crash here. + * Protect with __try/__except to avoid a message box. + */ + __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); + g_free (hctx); + } +#endif + g_list_free (wintab_contexts); +} + +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; +} + +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; +} + +void +gdk_input_window_get_pointer (GdkWindow *window, + guint32 deviceid, + gdouble *x, + gdouble *y, + gdouble *pressure, + gdouble *xtilt, + gdouble *ytilt, + GdkModifierType *mask) +{ + if (gdk_input_vtable.get_pointer) + gdk_input_vtable.get_pointer (window, deviceid, x, y, pressure, + xtilt, ytilt, mask); +} diff --git a/gdk/win32/gdkinput.h b/gdk/win32/gdkinput.h new file mode 100644 index 000000000..46e6b1f64 --- /dev/null +++ b/gdk/win32/gdkinput.h @@ -0,0 +1,156 @@ +/* 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_INPUT_H__ +#define __GDK_INPUT_H__ + +#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> + +typedef struct _GdkAxisInfo GdkAxisInfo; +typedef struct _GdkInputVTable GdkInputVTable; +typedef struct _GdkDevicePrivate GdkDevicePrivate; +typedef struct _GdkInputWindow GdkInputWindow; + +struct _GdkInputVTable { + gint (*set_mode) (guint32 deviceid, GdkInputMode mode); + void (*set_axes) (guint32 deviceid, GdkAxisUse *axes); + void (*set_key) (guint32 deviceid, + guint index, + guint keyval, + GdkModifierType modifiers); + + GdkTimeCoord* (*motion_events) (GdkWindow *window, + guint32 deviceid, + guint32 start, + guint32 stop, + gint *nevents_return); + void (*get_pointer) (GdkWindow *window, + guint32 deviceid, + gdouble *x, + gdouble *y, + gdouble *pressure, + gdouble *xtilt, + gdouble *ytilt, + GdkModifierType *mask); + gint (*grab_pointer) (GdkWindow * window, + gint owner_events, + GdkEventMask event_mask, + GdkWindow * confine_to, + guint32 time); + void (*ungrab_pointer) (guint32 time); + + void (*configure_event) (GdkEventConfigure *event, GdkWindow *window); + void (*enter_event) (GdkEventCrossing *event, GdkWindow *window); + gint (*other_event) (GdkEvent *event, MSG *xevent); + gint (*enable_window) (GdkWindow *window, GdkDevicePrivate *gdkdev); + gint (*disable_window) (GdkWindow *window, GdkDevicePrivate *gdkdev); +}; + +/* information about a device axis */ +struct _GdkAxisInfo +{ + /* reported x resolution */ + gint xresolution; + + /* reported x minimum/maximum values */ + gint xmin_value, xmax_value; + + /* calibrated resolution (for aspect ration) - only relative values + between axes used */ + gint resolution; + + /* calibrated minimum/maximum values */ + gint min_value, max_value; +}; + +#define GDK_INPUT_NUM_EVENTC 6 + +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; + + /* 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]; +}; + +struct _GdkInputWindow +{ + /* gdk window */ + GdkWindow *window; + + /* Extension mode (GDK_EXTENSION_EVENTS_ALL/CURSOR) */ + GdkExtensionMode mode; + + /* position relative to root window */ + gint16 root_x; + gint16 root_y; + + /* rectangles relative to window of windows obscuring this one */ + GdkRectangle *obscuring; + gint num_obscuring; + + /* Is there a pointer grab for this window ? */ + gint grabbed; +}; + +/* Global data */ + +extern GdkInputVTable gdk_input_vtable; +extern gint gdk_input_ignore_core; +extern gint gdk_input_ignore_wintab; + +/* Function declarations */ + +void gdk_input_window_destroy (GdkWindow *window); + +#endif /* __GDK_INPUT_H__ */ diff --git a/gdk/win32/gdkmain-win32.c b/gdk/win32/gdkmain-win32.c new file mode 100644 index 000000000..0586516e2 --- /dev/null +++ b/gdk/win32/gdkmain-win32.c @@ -0,0 +1,2237 @@ +/* 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 "gdkinput.h" +#include "gdkx.h" +#include "gdkkeysyms.h" +#include "gdki18n.h" + +static void gdkx_XConvertCase (KeySym symbol, + KeySym *lower, + KeySym *upper); +#define XConvertCase gdkx_XConvertCase + +static void gdk_exit_func (void); + +static RETSIGTYPE gdk_signal (int signum); + + +/* Private variable declarations + */ +static int gdk_initialized = 0; /* 1 if the library is initialized, + * 0 otherwise. + */ +static guint start; /* We use the millisecond + * timestamps from GetTickCount + */ +static gboolean timerp = TRUE; /* If TRUE use timeouts when waiting + * for Windows messages + */ +static guint32 timer_val = 20; /* Timeout in milliseconds. + */ + +#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) +{ + HRESULT hres; + gint i, j, k; + + if (gdk_initialized) + return TRUE; + + if (g_thread_supported ()) + gdk_threads_mutex = g_mutex_new (); + + start = GetTickCount (); + +#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 (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; + } + 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_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]); + + gdk_root_window = HWND_DESKTOP; + + 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 (int 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_time_get + * + * Get the number of milliseconds since the library was + * initialized. + * + * Arguments: + * + * Results: + * The time since the library was initialized is returned. + * This time value is accurate to milliseconds even though + * a more accurate time down to the microsecond could be + * returned. + * + * Side effects: + * + *-------------------------------------------------------------- + */ + +guint32 +gdk_time_get (void) +{ + guint32 milliseconds; + guint32 end = GetTickCount (); + + if (end < start) + milliseconds = 0xFFFFFFFF - (start - end) + 1; + else + milliseconds = end - start; + + return milliseconds; +} + +/* + *-------------------------------------------------------------- + * gdk_timer_get + * + * Returns the current timer. + * + * Arguments: + * + * Results: + * Returns the current timer interval. This interval is + * in units of milliseconds. + * + * Side effects: + * + *-------------------------------------------------------------- + */ + +guint32 +gdk_timer_get (void) +{ + return timer_val; +} + +/* + *-------------------------------------------------------------- + * gdk_timer_set + * + * Sets the timer interval. + * + * Arguments: + * "milliseconds" is the new value for the timer. + * + * Results: + * + * Side effects: + * Calls to "gdk_event_get" will last for a maximum + * of time of "milliseconds". However, a value of 0 + * milliseconds will cause "gdk_event_get" to block + * indefinately until an event is received. + * + *-------------------------------------------------------------- + */ + +void +gdk_timer_set (guint32 milliseconds) +{ + timer_val = milliseconds; +#ifdef USE_PEEKNAMEDPIPE + /* When using PeekNamedPipe, can't have too long timeouts. + */ + if (timer_val > 10) + timer_val = 10; + else if (timer_val == 0) + timer_val = 0; +#endif +} + +void +gdk_timer_enable (void) +{ + timerp = TRUE; +} + +void +gdk_timer_disable (void) +{ +#ifdef USE_PEEKNAMEDPIPE + /* Can't disable timeouts when using PeekNamedPipe */ +#else + timerp = FALSE; +#endif +} + +/* + *-------------------------------------------------------------- + * 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.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.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 (); + 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" }, + { 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" }, + { 0x00FF3C, "SingleCandidate" }, + { 0x00FF3D, "MultipleCandidate" }, + { 0x00FF3D, "Zen_Koho" }, + { 0x00FF3E, "Mae_Koho" }, + { 0x00FF3E, "PreviousCandidate" }, + { 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" }, + { 0x00FFC8, "L1" }, + { 0x00FFC9, "F12" }, + { 0x00FFC9, "L2" }, + { 0x00FFCA, "F13" }, + { 0x00FFCA, "L3" }, + { 0x00FFCB, "F14" }, + { 0x00FFCB, "L4" }, + { 0x00FFCC, "F15" }, + { 0x00FFCC, "L5" }, + { 0x00FFCD, "F16" }, + { 0x00FFCD, "L6" }, + { 0x00FFCE, "F17" }, + { 0x00FFCE, "L7" }, + { 0x00FFCF, "F18" }, + { 0x00FFCF, "L8" }, + { 0x00FFD0, "F19" }, + { 0x00FFD0, "L9" }, + { 0x00FFD1, "F20" }, + { 0x00FFD1, "L10" }, + { 0x00FFD2, "F21" }, + { 0x00FFD2, "R1" }, + { 0x00FFD3, "F22" }, + { 0x00FFD3, "R2" }, + { 0x00FFD4, "F23" }, + { 0x00FFD4, "R3" }, + { 0x00FFD5, "F24" }, + { 0x00FFD5, "R4" }, + { 0x00FFD6, "F25" }, + { 0x00FFD6, "R5" }, + { 0x00FFD7, "F26" }, + { 0x00FFD7, "R6" }, + { 0x00FFD8, "F27" }, + { 0x00FFD8, "R7" }, + { 0x00FFD9, "F28" }, + { 0x00FFD9, "R8" }, + { 0x00FFDA, "F29" }, + { 0x00FFDA, "R9" }, + { 0x00FFDB, "F30" }, + { 0x00FFDB, "R10" }, + { 0x00FFDC, "F31" }, + { 0x00FFDC, "R11" }, + { 0x00FFDD, "F32" }, + { 0x00FFDD, "R12" }, + { 0x00FFDE, "F33" }, + { 0x00FFDE, "R13" }, + { 0x00FFDF, "F34" }, + { 0x00FFDF, "R14" }, + { 0x00FFE0, "F35" }, + { 0x00FFE0, "R15" }, + { 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" }, + { 0x00ff31, "Hangul" }, + { 0x00ff32, "Hangul_Start" }, + { 0x00ff33, "Hangul_End" }, + { 0x00ff34, "Hangul_Hanja" }, + { 0x00ff35, "Hangul_Jamo" }, + { 0x00ff36, "Hangul_Romaja" }, + { 0x00ff37, "Hangul_Codeinput" }, + { 0x00ff38, "Hangul_Jeonja" }, + { 0x00ff39, "Hangul_Banja" }, + { 0x00ff3a, "Hangul_PreHanja" }, + { 0x00ff3b, "Hangul_PostHanja" }, + { 0x00ff3c, "Hangul_SingleCandidate" }, + { 0x00ff3d, "Hangul_MultipleCandidate" }, + { 0x00ff3e, "Hangul_PreviousCandidate" }, + { 0x00ff3f, "Hangul_Special" }, + { 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; +} + +const 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 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; + + 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; + + 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; + + 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; + + XConvertCase (keyval, &lower_val, &upper_val); + return lower_val == keyval; + } + return TRUE; +} + + +void +gdk_threads_enter () +{ + GDK_THREADS_ENTER (); +} + +void +gdk_threads_leave () +{ + GDK_THREADS_LEAVE (); +} diff --git a/gdk/win32/gdkpixmap-win32.c b/gdk/win32/gdkpixmap-win32.c new file mode 100644 index 000000000..e8a6c0260 --- /dev/null +++ b/gdk/win32/gdkpixmap-win32.c @@ -0,0 +1,1059 @@ +/* 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 "gdk.h" +#include "gdkprivate.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; + GdkWindowPrivate *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) || (depth != -1), NULL); + g_return_val_if_fail ((width != 0) && (height != 0), NULL); + + if (!window) + window = (GdkWindow*) &gdk_root_parent; + + window_private = (GdkWindowPrivate*) window; + if (window_private->destroyed) + return NULL; + + if (depth == -1) + depth = gdk_window_get_visual (window)->depth; + + GDK_NOTE (MISC, g_print ("gdk_pixmap_new: %dx%dx%d\n", width, height, depth)); + + private = g_new0 (GdkWindowPrivate, 1); + pixmap = (GdkPixmap*) private; + + private->window_type = GDK_WINDOW_PIXMAP; + + visual = gdk_window_get_visual (window); + +#if 0 + if (depth == 1) + { + if ((private->xwindow = + CreateBitmap (width, height, 1, 1, NULL)) == NULL) + { + g_warning ("gdk_pixmap_new: CreateBitmap failed"); + g_free (private); + return NULL; + } + + private->colormap = NULL; + } + else + { + if (depth != visual->depth) + g_warning ("gdk_pixmap_new: depth %d doesn't match display depth %d", + depth, visual->depth); + + if ((hdc = GetDC (window_private->xwindow)) == NULL) + { + g_warning ("gdk_pixmap_new: GetDC failed"); + g_free (private); + return NULL; + } + + if ((private->xwindow = + CreateCompatibleBitmap (hdc, width, height)) == NULL) + { + g_warning ("gdk_pixmap_new: %dx%d CreateCompatibleBitmap failed", + width, height); + ReleaseDC (window_private->xwindow, hdc); + g_free (private); + return NULL; + } + + ReleaseDC (window_private->xwindow, hdc); + + private->colormap = window_private->colormap; + if (private->colormap == NULL) + private->colormap = gdk_colormap_get_system (); + } +#else + + if ((hdc = GetDC (window_private->xwindow)) == 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->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, &bits, NULL, 0)) == NULL) + { + g_warning ("gdk_pixmap_new: CreateDIBSection failed: %d", GetLastError ()); + ReleaseDC (window_private->xwindow, hdc); + g_free (private); + return NULL; + } + ReleaseDC (window_private->xwindow, hdc); + +#endif + + GDK_NOTE (MISC, g_print ("... = %#x\n", private->xwindow)); + + private->parent = NULL; + private->x = 0; + private->y = 0; + private->width = width; + private->height = height; + private->resize_count = 0; + 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; + GdkWindowPrivate *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 (GdkWindowPrivate, 1); + pixmap = (GdkPixmap*) private; + + private->xwindow = image_private->ximage; + private->window_type = GDK_WINDOW_PIXMAP; + private->colormap = window_private->colormap; + private->parent = NULL; + private->x = 0; + private->y = 0; + private->width = width; + private->height = height; + private->resize_count = 0; + 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; + GdkWindowPrivate *private; + GdkWindowPrivate *window_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); + + if (!window) + window = (GdkWindow*) &gdk_root_parent; + + window_private = (GdkWindowPrivate*) window; + if (window_private->destroyed) + return NULL; + + private = g_new0 (GdkWindowPrivate, 1); + pixmap = (GdkPixmap*) private; + + private->parent = NULL; + private->window_type = GDK_WINDOW_PIXMAP; + private->x = 0; + private->y = 0; + private->width = width; + private->height = height; + private->resize_count = 0; + 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, + ((GdkPixmapPrivate *) result)->xwindow)); + 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; + GdkWindowPrivate *window_private; + GdkWindowPrivate *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(GdkWindowPrivate, 1); + pixmap = (GdkPixmap *)private; + + private->window_type = GDK_WINDOW_PIXMAP; + private->xwindow = xpixmap; + private->colormap = NULL; + private->parent = NULL; + private->x = 0; + private->y = 0; + private->width = w_ret; + private->height = h_ret; + private->resize_count = 0; + private->ref_count = 1; + private->destroyed = 0; + + gdk_xid_table_insert(&private->xwindow, pixmap); + + return pixmap; +} + +GdkPixmap* +gdk_pixmap_ref (GdkPixmap *pixmap) +{ + GdkWindowPrivate *private = (GdkWindowPrivate *)pixmap; + g_return_val_if_fail (pixmap != NULL, NULL); + + private->ref_count += 1; + return pixmap; +} + +void +gdk_pixmap_unref (GdkPixmap *pixmap) +{ + GdkWindowPrivate *private = (GdkWindowPrivate *)pixmap; + g_return_if_fail(pixmap != NULL); + + private->ref_count -= 1; + + GDK_NOTE (MISC, g_print ("gdk_pixmap_unref: %#x %d%s\n", + private->xwindow, private->ref_count, + (private->ref_count == 0 ? " freeing" : ""))); + + if (private->ref_count == 0) + { + if (!DeleteObject (private->xwindow)) + g_warning ("gdk_pixmap_unref: DeleteObject failed"); + gdk_xid_table_remove (private->xwindow); + g_dataset_destroy (private); + g_free (private); + } +} + +GdkBitmap * +gdk_bitmap_ref (GdkBitmap *bitmap) +{ + return (GdkBitmap *)gdk_pixmap_ref ((GdkPixmap *)bitmap); +} + +void +gdk_bitmap_unref (GdkBitmap *bitmap) +{ + gdk_pixmap_unref ((GdkPixmap *)bitmap); +} diff --git a/gdk/win32/gdkpixmap.c b/gdk/win32/gdkpixmap.c new file mode 100644 index 000000000..e8a6c0260 --- /dev/null +++ b/gdk/win32/gdkpixmap.c @@ -0,0 +1,1059 @@ +/* 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 "gdk.h" +#include "gdkprivate.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; + GdkWindowPrivate *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) || (depth != -1), NULL); + g_return_val_if_fail ((width != 0) && (height != 0), NULL); + + if (!window) + window = (GdkWindow*) &gdk_root_parent; + + window_private = (GdkWindowPrivate*) window; + if (window_private->destroyed) + return NULL; + + if (depth == -1) + depth = gdk_window_get_visual (window)->depth; + + GDK_NOTE (MISC, g_print ("gdk_pixmap_new: %dx%dx%d\n", width, height, depth)); + + private = g_new0 (GdkWindowPrivate, 1); + pixmap = (GdkPixmap*) private; + + private->window_type = GDK_WINDOW_PIXMAP; + + visual = gdk_window_get_visual (window); + +#if 0 + if (depth == 1) + { + if ((private->xwindow = + CreateBitmap (width, height, 1, 1, NULL)) == NULL) + { + g_warning ("gdk_pixmap_new: CreateBitmap failed"); + g_free (private); + return NULL; + } + + private->colormap = NULL; + } + else + { + if (depth != visual->depth) + g_warning ("gdk_pixmap_new: depth %d doesn't match display depth %d", + depth, visual->depth); + + if ((hdc = GetDC (window_private->xwindow)) == NULL) + { + g_warning ("gdk_pixmap_new: GetDC failed"); + g_free (private); + return NULL; + } + + if ((private->xwindow = + CreateCompatibleBitmap (hdc, width, height)) == NULL) + { + g_warning ("gdk_pixmap_new: %dx%d CreateCompatibleBitmap failed", + width, height); + ReleaseDC (window_private->xwindow, hdc); + g_free (private); + return NULL; + } + + ReleaseDC (window_private->xwindow, hdc); + + private->colormap = window_private->colormap; + if (private->colormap == NULL) + private->colormap = gdk_colormap_get_system (); + } +#else + + if ((hdc = GetDC (window_private->xwindow)) == 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->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, &bits, NULL, 0)) == NULL) + { + g_warning ("gdk_pixmap_new: CreateDIBSection failed: %d", GetLastError ()); + ReleaseDC (window_private->xwindow, hdc); + g_free (private); + return NULL; + } + ReleaseDC (window_private->xwindow, hdc); + +#endif + + GDK_NOTE (MISC, g_print ("... = %#x\n", private->xwindow)); + + private->parent = NULL; + private->x = 0; + private->y = 0; + private->width = width; + private->height = height; + private->resize_count = 0; + 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; + GdkWindowPrivate *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 (GdkWindowPrivate, 1); + pixmap = (GdkPixmap*) private; + + private->xwindow = image_private->ximage; + private->window_type = GDK_WINDOW_PIXMAP; + private->colormap = window_private->colormap; + private->parent = NULL; + private->x = 0; + private->y = 0; + private->width = width; + private->height = height; + private->resize_count = 0; + 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; + GdkWindowPrivate *private; + GdkWindowPrivate *window_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); + + if (!window) + window = (GdkWindow*) &gdk_root_parent; + + window_private = (GdkWindowPrivate*) window; + if (window_private->destroyed) + return NULL; + + private = g_new0 (GdkWindowPrivate, 1); + pixmap = (GdkPixmap*) private; + + private->parent = NULL; + private->window_type = GDK_WINDOW_PIXMAP; + private->x = 0; + private->y = 0; + private->width = width; + private->height = height; + private->resize_count = 0; + 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, + ((GdkPixmapPrivate *) result)->xwindow)); + 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; + GdkWindowPrivate *window_private; + GdkWindowPrivate *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(GdkWindowPrivate, 1); + pixmap = (GdkPixmap *)private; + + private->window_type = GDK_WINDOW_PIXMAP; + private->xwindow = xpixmap; + private->colormap = NULL; + private->parent = NULL; + private->x = 0; + private->y = 0; + private->width = w_ret; + private->height = h_ret; + private->resize_count = 0; + private->ref_count = 1; + private->destroyed = 0; + + gdk_xid_table_insert(&private->xwindow, pixmap); + + return pixmap; +} + +GdkPixmap* +gdk_pixmap_ref (GdkPixmap *pixmap) +{ + GdkWindowPrivate *private = (GdkWindowPrivate *)pixmap; + g_return_val_if_fail (pixmap != NULL, NULL); + + private->ref_count += 1; + return pixmap; +} + +void +gdk_pixmap_unref (GdkPixmap *pixmap) +{ + GdkWindowPrivate *private = (GdkWindowPrivate *)pixmap; + g_return_if_fail(pixmap != NULL); + + private->ref_count -= 1; + + GDK_NOTE (MISC, g_print ("gdk_pixmap_unref: %#x %d%s\n", + private->xwindow, private->ref_count, + (private->ref_count == 0 ? " freeing" : ""))); + + if (private->ref_count == 0) + { + if (!DeleteObject (private->xwindow)) + g_warning ("gdk_pixmap_unref: DeleteObject failed"); + gdk_xid_table_remove (private->xwindow); + g_dataset_destroy (private); + g_free (private); + } +} + +GdkBitmap * +gdk_bitmap_ref (GdkBitmap *bitmap) +{ + return (GdkBitmap *)gdk_pixmap_ref ((GdkPixmap *)bitmap); +} + +void +gdk_bitmap_unref (GdkBitmap *bitmap) +{ + gdk_pixmap_unref ((GdkPixmap *)bitmap); +} diff --git a/gdk/win32/gdkprivate-win32.h b/gdk/win32/gdkprivate-win32.h new file mode 100644 index 000000000..e90da9668 --- /dev/null +++ b/gdk/win32/gdkprivate-win32.h @@ -0,0 +1,420 @@ +/* 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 <time.h> +#include <gdk/gdktypes.h> + +/* Define corresponding Windows types for some X11 types, just for laziness. + */ + +#include <glib.h> + +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 + +/* Notify modes */ +#define NotifyNormal 0 +#define NotifyHint 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; + +extern LRESULT CALLBACK +gdk_WindowProc (HWND, UINT, WPARAM, LPARAM); + +#define gdk_window_lookup(xid) ((GdkWindow*) gdk_xid_table_lookup (xid)) +#define gdk_pixmap_lookup(xid) ((GdkPixmap*) gdk_xid_table_lookup (xid)) + +/* HFONTs clash with HWNDs, so add dithering to HFONTs... (hack) */ +#define HFONT_DITHER 43 +#define gdk_font_lookup(xid) ((GdkFont*) gdk_xid_table_lookup ((HANDLE) ((guint) xid + HFONT_DITHER))) + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +typedef struct _GdkWindowPrivate GdkWindowPrivate; +typedef struct _GdkWindowPrivate GdkPixmapPrivate; +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 _GdkColorContextPrivate GdkColorContextPrivate; +typedef struct _GdkRegionPrivate GdkRegionPrivate; + + +struct _GdkWindowPrivate +{ + GdkWindow window; + GdkWindow *parent; + HANDLE xwindow; + gint16 x; + gint16 y; + guint16 width; + guint16 height; + guint8 resize_count; + guint8 window_type; + guint ref_count; + guint destroyed : 2; + 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; + GdkColormap *colormap; + GList *children; +}; + +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; + HFONT 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; +}; + +struct _GdkFontPrivate +{ + GdkFont font; + /* XFontStruct *xfont; */ + /* generic pointer point to XFontStruct or XFontSet */ + /* in Win32 a HFONT */ + gpointer xfont; + guint ref_count; +}; + +struct _GdkCursorPrivate +{ + GdkCursor cursor; + Cursor xcursor; +}; + +struct _GdkEventFilter { + GdkFilterFunc function; + gpointer data; +}; + +struct _GdkClientFilter { + GdkAtom type; + GdkFilterFunc function; + gpointer data; +}; + +#ifdef USE_XIM + +typedef struct _GdkICPrivate GdkICPrivate; + +struct _GdkICPrivate +{ + XIC xic; + GdkICAttr *attr; + GdkICAttributesType mask; +}; + +#endif /* USE_XIM */ + +struct _GdkColorContextPrivate +{ + GdkColorContext color_context; + XStandardColormap std_cmap; +}; + +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 (GdkWindowPrivate *window_private, + GdkGCPrivate *gc_private); +void gdk_gc_postdraw (GdkWindowPrivate *window_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); + +/* 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 gchar *gdk_display_name; +extern HWND gdk_root_window; +extern HWND gdk_leader_window; +GDKVAR GdkWindowPrivate gdk_root_parent; +GDKVAR Atom gdk_selection_property; +extern GdkWindow *selection_owner[]; +GDKVAR gchar *gdk_progclass; +GDKVAR gint gdk_error_code; +GDKVAR gint gdk_error_warnings; +GDKVAR gint gdk_null_window_warnings; +extern GList *gdk_default_filters; + +#ifdef USE_XIM +/* XIM support */ +gint gdk_im_open (void); +void gdk_im_close (void); +void gdk_ic_cleanup (void); + +extern GdkICPrivate *gdk_xim_ic; /* currently using IC */ +extern GdkWindow *gdk_xim_window; /* currently using Window */ +#endif /* USE_XIM */ + +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; + +/* 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 */ + +extern guint gdk_debug_flags; + +/* Internal functions for debug output etc. */ + +char *gdk_color_to_string (GdkColor *); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GDK_PRIVATE_H__ */ diff --git a/gdk/win32/gdkprivate.h b/gdk/win32/gdkprivate.h new file mode 100644 index 000000000..e90da9668 --- /dev/null +++ b/gdk/win32/gdkprivate.h @@ -0,0 +1,420 @@ +/* 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 <time.h> +#include <gdk/gdktypes.h> + +/* Define corresponding Windows types for some X11 types, just for laziness. + */ + +#include <glib.h> + +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 + +/* Notify modes */ +#define NotifyNormal 0 +#define NotifyHint 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; + +extern LRESULT CALLBACK +gdk_WindowProc (HWND, UINT, WPARAM, LPARAM); + +#define gdk_window_lookup(xid) ((GdkWindow*) gdk_xid_table_lookup (xid)) +#define gdk_pixmap_lookup(xid) ((GdkPixmap*) gdk_xid_table_lookup (xid)) + +/* HFONTs clash with HWNDs, so add dithering to HFONTs... (hack) */ +#define HFONT_DITHER 43 +#define gdk_font_lookup(xid) ((GdkFont*) gdk_xid_table_lookup ((HANDLE) ((guint) xid + HFONT_DITHER))) + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +typedef struct _GdkWindowPrivate GdkWindowPrivate; +typedef struct _GdkWindowPrivate GdkPixmapPrivate; +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 _GdkColorContextPrivate GdkColorContextPrivate; +typedef struct _GdkRegionPrivate GdkRegionPrivate; + + +struct _GdkWindowPrivate +{ + GdkWindow window; + GdkWindow *parent; + HANDLE xwindow; + gint16 x; + gint16 y; + guint16 width; + guint16 height; + guint8 resize_count; + guint8 window_type; + guint ref_count; + guint destroyed : 2; + 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; + GdkColormap *colormap; + GList *children; +}; + +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; + HFONT 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; +}; + +struct _GdkFontPrivate +{ + GdkFont font; + /* XFontStruct *xfont; */ + /* generic pointer point to XFontStruct or XFontSet */ + /* in Win32 a HFONT */ + gpointer xfont; + guint ref_count; +}; + +struct _GdkCursorPrivate +{ + GdkCursor cursor; + Cursor xcursor; +}; + +struct _GdkEventFilter { + GdkFilterFunc function; + gpointer data; +}; + +struct _GdkClientFilter { + GdkAtom type; + GdkFilterFunc function; + gpointer data; +}; + +#ifdef USE_XIM + +typedef struct _GdkICPrivate GdkICPrivate; + +struct _GdkICPrivate +{ + XIC xic; + GdkICAttr *attr; + GdkICAttributesType mask; +}; + +#endif /* USE_XIM */ + +struct _GdkColorContextPrivate +{ + GdkColorContext color_context; + XStandardColormap std_cmap; +}; + +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 (GdkWindowPrivate *window_private, + GdkGCPrivate *gc_private); +void gdk_gc_postdraw (GdkWindowPrivate *window_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); + +/* 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 gchar *gdk_display_name; +extern HWND gdk_root_window; +extern HWND gdk_leader_window; +GDKVAR GdkWindowPrivate gdk_root_parent; +GDKVAR Atom gdk_selection_property; +extern GdkWindow *selection_owner[]; +GDKVAR gchar *gdk_progclass; +GDKVAR gint gdk_error_code; +GDKVAR gint gdk_error_warnings; +GDKVAR gint gdk_null_window_warnings; +extern GList *gdk_default_filters; + +#ifdef USE_XIM +/* XIM support */ +gint gdk_im_open (void); +void gdk_im_close (void); +void gdk_ic_cleanup (void); + +extern GdkICPrivate *gdk_xim_ic; /* currently using IC */ +extern GdkWindow *gdk_xim_window; /* currently using Window */ +#endif /* USE_XIM */ + +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; + +/* 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 */ + +extern guint gdk_debug_flags; + +/* Internal functions for debug output etc. */ + +char *gdk_color_to_string (GdkColor *); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GDK_PRIVATE_H__ */ diff --git a/gdk/win32/gdkproperty-win32.c b/gdk/win32/gdkproperty-win32.c new file mode 100644 index 000000000..5cc68ecd6 --- /dev/null +++ b/gdk/win32/gdkproperty-win32.c @@ -0,0 +1,221 @@ +/* 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.h" +#include "gdkprivate.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) +{ + GdkWindowPrivate *private; + HGLOBAL hdata; + gint i, length; + gchar *prop_name, *type_name; + guchar *ptr; + + private = (GdkWindowPrivate*) window; + if (private->destroyed) + 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", + private->xwindow, 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 + if (!OpenClipboard (private->xwindow)) + { + 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); + if (!SetClipboardData(CF_TEXT, hdata)) + g_warning ("gdk_property_change: SetClipboardData failed: %d", + GetLastError ()); +#if 1 + 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) +{ + GdkWindowPrivate *private; + gchar *prop_name, *type_name; + extern void gdk_selection_property_delete (GdkWindowPrivate *); + + private = (GdkWindowPrivate*) window; + + GDK_NOTE (SELECTION, + (prop_name = gdk_atom_name (property), + g_print ("gdk_property_delete: %#x %#x (%s)\n", + (window ? private->xwindow : 0), property, prop_name), + g_free (prop_name))); + + if (property == gdk_selection_property) + gdk_selection_property_delete (private); + else + g_warning ("gdk_property_delete: General case not implemented"); +} diff --git a/gdk/win32/gdkproperty.c b/gdk/win32/gdkproperty.c new file mode 100644 index 000000000..5cc68ecd6 --- /dev/null +++ b/gdk/win32/gdkproperty.c @@ -0,0 +1,221 @@ +/* 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.h" +#include "gdkprivate.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) +{ + GdkWindowPrivate *private; + HGLOBAL hdata; + gint i, length; + gchar *prop_name, *type_name; + guchar *ptr; + + private = (GdkWindowPrivate*) window; + if (private->destroyed) + 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", + private->xwindow, 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 + if (!OpenClipboard (private->xwindow)) + { + 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); + if (!SetClipboardData(CF_TEXT, hdata)) + g_warning ("gdk_property_change: SetClipboardData failed: %d", + GetLastError ()); +#if 1 + 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) +{ + GdkWindowPrivate *private; + gchar *prop_name, *type_name; + extern void gdk_selection_property_delete (GdkWindowPrivate *); + + private = (GdkWindowPrivate*) window; + + GDK_NOTE (SELECTION, + (prop_name = gdk_atom_name (property), + g_print ("gdk_property_delete: %#x %#x (%s)\n", + (window ? private->xwindow : 0), property, prop_name), + g_free (prop_name))); + + if (property == gdk_selection_property) + gdk_selection_property_delete (private); + else + g_warning ("gdk_property_delete: General case not implemented"); +} diff --git a/gdk/win32/gdkrectangle.c b/gdk/win32/gdkrectangle.c new file mode 100644 index 000000000..8fd435aa9 --- /dev/null +++ b/gdk/win32/gdkrectangle.c @@ -0,0 +1,108 @@ +/* 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 "gdk.h" + + + +void +gdk_rectangle_union (GdkRectangle *src1, + GdkRectangle *src2, + GdkRectangle *dest) +{ + g_return_if_fail (src1 != NULL); + g_return_if_fail (src2 != NULL); + g_return_if_fail (dest != NULL); + + dest->x = MIN (src1->x, src2->x); + dest->y = MIN (src1->y, src2->y); + dest->width = MAX (src1->x + src1->width, src2->x + src2->width) - dest->x; + dest->height = MAX (src1->y + src1->height, src2->y + src2->height) - dest->y; +} + +gint +gdk_rectangle_intersect (GdkRectangle *src1, + GdkRectangle *src2, + GdkRectangle *dest) +{ + GdkRectangle *temp; + gint src1_x2, src1_y2; + gint src2_x2, src2_y2; + gint return_val; + + g_return_val_if_fail (src1 != NULL, FALSE); + g_return_val_if_fail (src2 != NULL, FALSE); + g_return_val_if_fail (dest != NULL, FALSE); + + return_val = FALSE; + + if (src2->x < src1->x) + { + temp = src1; + src1 = src2; + src2 = temp; + } + dest->x = src2->x; + + src1_x2 = src1->x + src1->width; + src2_x2 = src2->x + src2->width; + + if (src2->x < src1_x2) + { + if (src1_x2 < src2_x2) + dest->width = src1_x2 - dest->x; + else + dest->width = src2_x2 - dest->x; + + if (src2->y < src1->y) + { + temp = src1; + src1 = src2; + src2 = temp; + } + dest->y = src2->y; + + src1_y2 = src1->y + src1->height; + src2_y2 = src2->y + src2->height; + + if (src2->y < src1_y2) + { + return_val = TRUE; + + if (src1_y2 < src2_y2) + dest->height = src1_y2 - dest->y; + else + dest->height = src2_y2 - dest->y; + + if (dest->height == 0) + return_val = FALSE; + if (dest->width == 0) + return_val = FALSE; + } + } + + return return_val; +} diff --git a/gdk/win32/gdkregion-win32.c b/gdk/win32/gdkregion-win32.c new file mode 100644 index 000000000..4a37c3b10 --- /dev/null +++ b/gdk/win32/gdkregion-win32.c @@ -0,0 +1,350 @@ +/* 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; + + /* Create an empty region */ + xregion = CreateRectRgn (1, 1, 0, 0); + 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; + RECT r; + + g_return_if_fail (region != NULL); + + private = (GdkRegionPrivate *) region; + + /* Is it correct just to intersect it with a smaller bounding box? */ + GetRgnBox (private->xregion, &r); + + if (-dx > r.right - r.left) + { + r.left += dx/2; + r.right -= dx/2; + } + if (-dy > r.bottom - r.top) + { + r.top += dy/2; + r.bottom -= dy/2; + } + + CombineRgn (private->xregion, private->xregion, + CreateRectRgnIndirect (&r), RGN_AND); +} + +GdkRegion* +gdk_region_union_with_rect (GdkRegion *region, + GdkRectangle *rect) +{ + GdkRegionPrivate *private; + GdkRegion *res; + GdkRegionPrivate *res_private; + RECT xrect; + + 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; + + CombineRgn (res_private->xregion, private->xregion, + CreateRectRgnIndirect (&xrect), RGN_OR); + return res; +} + +GdkRegion* +gdk_regions_intersect (GdkRegion *source1, + GdkRegion *source2) +{ + GdkRegionPrivate *private1; + GdkRegionPrivate *private2; + GdkRegion *res; + GdkRegionPrivate *res_private; + + g_return_val_if_fail (source1 != NULL, NULL); + g_return_val_if_fail (source2 != NULL, NULL); + + private1 = (GdkRegionPrivate *) source1; + private2 = (GdkRegionPrivate *) source2; + + res = gdk_region_new (); + res_private = (GdkRegionPrivate *) res; + + CombineRgn (res_private->xregion, private1->xregion, private2->xregion, + RGN_AND); + return res; +} + +GdkRegion* +gdk_regions_union (GdkRegion *source1, + GdkRegion *source2) +{ + GdkRegionPrivate *private1; + GdkRegionPrivate *private2; + GdkRegion *res; + GdkRegionPrivate *res_private; + + g_return_val_if_fail (source1 != NULL, NULL); + g_return_val_if_fail (source2 != NULL, NULL); + + private1 = (GdkRegionPrivate *) source1; + private2 = (GdkRegionPrivate *) source2; + + res = gdk_region_new (); + res_private = (GdkRegionPrivate *) res; + + CombineRgn (res_private->xregion, private1->xregion, private2->xregion, + RGN_OR); + return res; +} + +GdkRegion* +gdk_regions_subtract (GdkRegion *source1, + GdkRegion *source2) +{ + GdkRegionPrivate *private1; + GdkRegionPrivate *private2; + GdkRegion *res; + GdkRegionPrivate *res_private; + + g_return_val_if_fail (source1 != NULL, NULL); + g_return_val_if_fail (source2 != NULL, NULL); + + private1 = (GdkRegionPrivate *) source1; + private2 = (GdkRegionPrivate *) source2; + + res = gdk_region_new (); + res_private = (GdkRegionPrivate *) res; + + CombineRgn (res_private->xregion, private1->xregion, private2->xregion, + RGN_DIFF); + return res; +} + +GdkRegion* +gdk_regions_xor (GdkRegion *source1, + GdkRegion *source2) +{ + GdkRegionPrivate *private1; + GdkRegionPrivate *private2; + GdkRegion *res; + GdkRegionPrivate *res_private; + + g_return_val_if_fail (source1 != NULL, NULL); + g_return_val_if_fail (source2 != NULL, NULL); + + private1 = (GdkRegionPrivate *) source1; + private2 = (GdkRegionPrivate *) source2; + + res = gdk_region_new (); + res_private = (GdkRegionPrivate *) res; + + CombineRgn (res_private->xregion, private1->xregion, private2->xregion, + RGN_XOR); + return res; +} diff --git a/gdk/win32/gdkregion.c b/gdk/win32/gdkregion.c new file mode 100644 index 000000000..4a37c3b10 --- /dev/null +++ b/gdk/win32/gdkregion.c @@ -0,0 +1,350 @@ +/* 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; + + /* Create an empty region */ + xregion = CreateRectRgn (1, 1, 0, 0); + 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; + RECT r; + + g_return_if_fail (region != NULL); + + private = (GdkRegionPrivate *) region; + + /* Is it correct just to intersect it with a smaller bounding box? */ + GetRgnBox (private->xregion, &r); + + if (-dx > r.right - r.left) + { + r.left += dx/2; + r.right -= dx/2; + } + if (-dy > r.bottom - r.top) + { + r.top += dy/2; + r.bottom -= dy/2; + } + + CombineRgn (private->xregion, private->xregion, + CreateRectRgnIndirect (&r), RGN_AND); +} + +GdkRegion* +gdk_region_union_with_rect (GdkRegion *region, + GdkRectangle *rect) +{ + GdkRegionPrivate *private; + GdkRegion *res; + GdkRegionPrivate *res_private; + RECT xrect; + + 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; + + CombineRgn (res_private->xregion, private->xregion, + CreateRectRgnIndirect (&xrect), RGN_OR); + return res; +} + +GdkRegion* +gdk_regions_intersect (GdkRegion *source1, + GdkRegion *source2) +{ + GdkRegionPrivate *private1; + GdkRegionPrivate *private2; + GdkRegion *res; + GdkRegionPrivate *res_private; + + g_return_val_if_fail (source1 != NULL, NULL); + g_return_val_if_fail (source2 != NULL, NULL); + + private1 = (GdkRegionPrivate *) source1; + private2 = (GdkRegionPrivate *) source2; + + res = gdk_region_new (); + res_private = (GdkRegionPrivate *) res; + + CombineRgn (res_private->xregion, private1->xregion, private2->xregion, + RGN_AND); + return res; +} + +GdkRegion* +gdk_regions_union (GdkRegion *source1, + GdkRegion *source2) +{ + GdkRegionPrivate *private1; + GdkRegionPrivate *private2; + GdkRegion *res; + GdkRegionPrivate *res_private; + + g_return_val_if_fail (source1 != NULL, NULL); + g_return_val_if_fail (source2 != NULL, NULL); + + private1 = (GdkRegionPrivate *) source1; + private2 = (GdkRegionPrivate *) source2; + + res = gdk_region_new (); + res_private = (GdkRegionPrivate *) res; + + CombineRgn (res_private->xregion, private1->xregion, private2->xregion, + RGN_OR); + return res; +} + +GdkRegion* +gdk_regions_subtract (GdkRegion *source1, + GdkRegion *source2) +{ + GdkRegionPrivate *private1; + GdkRegionPrivate *private2; + GdkRegion *res; + GdkRegionPrivate *res_private; + + g_return_val_if_fail (source1 != NULL, NULL); + g_return_val_if_fail (source2 != NULL, NULL); + + private1 = (GdkRegionPrivate *) source1; + private2 = (GdkRegionPrivate *) source2; + + res = gdk_region_new (); + res_private = (GdkRegionPrivate *) res; + + CombineRgn (res_private->xregion, private1->xregion, private2->xregion, + RGN_DIFF); + return res; +} + +GdkRegion* +gdk_regions_xor (GdkRegion *source1, + GdkRegion *source2) +{ + GdkRegionPrivate *private1; + GdkRegionPrivate *private2; + GdkRegion *res; + GdkRegionPrivate *res_private; + + g_return_val_if_fail (source1 != NULL, NULL); + g_return_val_if_fail (source2 != NULL, NULL); + + private1 = (GdkRegionPrivate *) source1; + private2 = (GdkRegionPrivate *) source2; + + res = gdk_region_new (); + res_private = (GdkRegionPrivate *) res; + + CombineRgn (res_private->xregion, private1->xregion, private2->xregion, + RGN_XOR); + return res; +} diff --git a/gdk/win32/gdkrgb.c b/gdk/win32/gdkrgb.c new file mode 100644 index 000000000..feb5ce5ce --- /dev/null +++ b/gdk/win32/gdkrgb.c @@ -0,0 +1,3205 @@ +/* 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. + */ + +/* For more information on GdkRgb, see http://www.levien.com/gdkrgb/ + + Raph Levien <raph@acm.org> + */ + +/* + * 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 <math.h> + +#if HAVE_CONFIG_H +# include <config.h> +# if STDC_HEADERS +# include <stdio.h> +# include <stdlib.h> +# include <string.h> +# endif +#else +# include <stdio.h> +# include <stdlib.h> +#endif + + +#define ENABLE_GRAYSCALE + +#include "config.h" +#ifdef GDK_RGB_STANDALONE + +/* Compiling as a standalone module (i.e. with Gtk 1.0) */ +/* gtk/gtk.h is already included in gdkrgbstub.c */ +#include "config.h" +#include <gdk/gdkprivate.h> + +#else + +/* Compiling as a part of Gtk 1.1 or later */ +#include "../config.h" +#include "gdk.h" +#include "gdkprivate.h" + +#endif + +#include "gdkrgb.h" + +typedef struct _GdkRgbInfo GdkRgbInfo; + +typedef void (*GdkRgbConvFunc) (GdkImage *image, + gint x0, gint y0, + gint width, gint height, + guchar *buf, int rowstride, + gint x_align, gint y_align, + GdkRgbCmap *cmap); + +/* Some of these fields should go, as they're not being used at all. + Globals should generally migrate into here - it's very likely that + we'll want to run more than one GdkRgbInfo context at the same time + (i.e. some but not all windows have privately installed + colormaps). */ + +struct _GdkRgbInfo +{ + GdkVisual *visual; + GdkColormap *cmap; + + gulong *color_pixels; + gulong *gray_pixels; + gulong *reserved_pixels; + + guint nred_shades; + guint ngreen_shades; + guint nblue_shades; + guint ngray_shades; + guint nreserved; + + guint bpp; + gint cmap_alloced; + gdouble gamma; + + /* Generally, the stage buffer is used to convert 32bit RGB, gray, + and indexed images into 24 bit packed RGB. */ + guchar *stage_buf; + + GdkRgbCmap *gray_cmap; + + gboolean dith_default; + + gboolean bitmap; /* set true if in 1 bit per pixel mode */ + GdkGC *own_gc; + + /* Convert functions */ + GdkRgbConvFunc conv; + GdkRgbConvFunc conv_d; + + GdkRgbConvFunc conv_32; + GdkRgbConvFunc conv_32_d; + + GdkRgbConvFunc conv_gray; + GdkRgbConvFunc conv_gray_d; + + GdkRgbConvFunc conv_indexed; + GdkRgbConvFunc conv_indexed_d; +}; + +static gboolean gdk_rgb_install_cmap = FALSE; +static gint gdk_rgb_min_colors = 5 * 5 * 5; +static gboolean gdk_rgb_verbose = FALSE; + +#define IMAGE_WIDTH 256 +#define STAGE_ROWSTRIDE (IMAGE_WIDTH * 3) +#define IMAGE_HEIGHT 64 +#define N_IMAGES 6 + +static GdkRgbInfo *image_info = NULL; +static GdkImage *static_image[N_IMAGES]; +static gint static_image_idx; + +static guchar *colorcube; +static guchar *colorcube_d; + +static gint +gdk_rgb_cmap_fail (const char *msg, GdkColormap *cmap, gulong *pixels) +{ + gulong free_pixels[256]; + gint n_free; + gint i; + +#ifdef VERBOSE + g_print ("%s", msg); +#endif + n_free = 0; + for (i = 0; i < 256; i++) + if (pixels[i] < 256) + free_pixels[n_free++] = pixels[i]; + if (n_free) + gdk_colors_free (cmap, free_pixels, n_free, 0); + return 0; +} + +static void +gdk_rgb_make_colorcube (gulong *pixels, gint nr, gint ng, gint nb) +{ + guchar rt[16], gt[16], bt[16]; + gint i; + + colorcube = g_new (guchar, 4096); + for (i = 0; i < 16; i++) + { + rt[i] = ng * nb * ((i * 17 * (nr - 1) + 128) >> 8); + gt[i] = nb * ((i * 17 * (ng - 1) + 128) >> 8); + bt[i] = ((i * 17 * (nb - 1) + 128) >> 8); + } + + for (i = 0; i < 4096; i++) + { + colorcube[i] = pixels[rt[i >> 8] + gt[(i >> 4) & 0x0f] + bt[i & 0x0f]]; +#ifdef VERBOSE + g_print ("%03x %02x %x %x %x\n", i, colorcube[i], rt[i >> 8], gt[(i >> 4) & 0x0f], bt[i & 0x0f]); +#endif + } +} + +/* this is the colorcube suitable for dithering */ +static void +gdk_rgb_make_colorcube_d (gulong *pixels, gint nr, gint ng, gint nb) +{ + gint r, g, b; + gint i; + + colorcube_d = g_new (guchar, 512); + for (i = 0; i < 512; i++) + { + r = MIN (nr - 1, i >> 6); + g = MIN (ng - 1, (i >> 3) & 7); + b = MIN (nb - 1, i & 7); + colorcube_d[i] = pixels[(r * ng + g) * nb + b]; + } +} + +/* Try installing a color cube of the specified size. + Make the colorcube and return TRUE on success */ +static gint +gdk_rgb_try_colormap (gint nr, gint ng, gint nb) +{ + gint r, g, b; + gint ri, gi, bi; + gint r0, g0, b0; + GdkColormap *cmap; + GdkColor color; + gulong pixels[256]; + gulong junk[256]; + gint i; + gint d2; + gint colors_needed; + gint idx; + gint best[256]; + + if (nr * ng * nb < gdk_rgb_min_colors) + return FALSE; + + if (image_info->cmap_alloced) + cmap = image_info->cmap; + else + cmap = gdk_colormap_get_system (); + + colors_needed = nr * ng * nb; + for (i = 0; i < 256; i++) + { + best[i] = 192; + pixels[i] = 256; + } + +#ifndef GAMMA + if (!gdk_rgb_install_cmap) + /* find color cube colors that are already present */ + for (i = 0; i < MIN (256, cmap->size); i++) + { + r = cmap->colors[i].red >> 8; + g = cmap->colors[i].green >> 8; + b = cmap->colors[i].blue >> 8; + ri = (r * (nr - 1) + 128) >> 8; + gi = (g * (ng - 1) + 128) >> 8; + bi = (b * (nb - 1) + 128) >> 8; + r0 = ri * 255 / (nr - 1); + g0 = gi * 255 / (ng - 1); + b0 = bi * 255 / (nb - 1); + idx = ((ri * nr) + gi) * nb + bi; + d2 = (r - r0) * (r - r0) + (g - g0) * (g - g0) + (b - b0) * (b - b0); + if (d2 < best[idx]) { + if (pixels[idx] < 256) + gdk_colors_free (cmap, pixels + idx, 1, 0); + else + colors_needed--; + color = cmap->colors[i]; + if (!gdk_color_alloc (cmap, &color)) + return gdk_rgb_cmap_fail ("error allocating system color\n", + cmap, pixels); + pixels[idx] = color.pixel; /* which is almost certainly i */ + best[idx] = d2; + } + } +#endif + + if (colors_needed) + { + if (!gdk_colors_alloc (cmap, 0, NULL, 0, junk, colors_needed)) + { + char tmp_str[80]; + + sprintf (tmp_str, + "%d %d %d colormap failed (in gdk_colors_alloc)\n", + nr, ng, nb); + return gdk_rgb_cmap_fail (tmp_str, cmap, pixels); + } + + gdk_colors_free (cmap, junk, colors_needed, 0); + } + + for (r = 0, i = 0; r < nr; r++) + for (g = 0; g < ng; g++) + for (b = 0; b < nb; b++, i++) + { + if (pixels[i] == 256) + { + color.red = r * 65535 / (nr - 1); + color.green = g * 65535 / (ng - 1); + color.blue = b * 65535 / (nb - 1); + +#ifdef GAMMA + color.red = 65535 * pow (color.red / 65535.0, 0.5); + color.green = 65535 * pow (color.green / 65535.0, 0.5); + color.blue = 65535 * pow (color.blue / 65535.0, 0.5); +#endif + + /* This should be a raw XAllocColor call */ + if (!gdk_color_alloc (cmap, &color)) + { + char tmp_str[80]; + + sprintf (tmp_str, "%d %d %d colormap failed\n", + nr, ng, nb); + return gdk_rgb_cmap_fail (tmp_str, + cmap, pixels); + } + pixels[i] = color.pixel; + } +#ifdef VERBOSE + g_print ("%d: %lx\n", i, pixels[i]); +#endif + } + + image_info->nred_shades = nr; + image_info->ngreen_shades = ng; + image_info->nblue_shades = nb; + gdk_rgb_make_colorcube (pixels, nr, ng, nb); + gdk_rgb_make_colorcube_d (pixels, nr, ng, nb); + return TRUE; +} + +/* Return TRUE on success. */ +static gboolean +gdk_rgb_do_colormaps (void) +{ + static const gint sizes[][3] = { + /* { 6, 7, 6 }, */ + { 6, 6, 6 }, + { 6, 6, 5 }, + { 6, 6, 4 }, + { 5, 5, 5 }, + { 5, 5, 4 }, + { 4, 4, 4 }, + { 4, 4, 3 }, + { 3, 3, 3 }, + { 2, 2, 2 } + }; + static const gint n_sizes = sizeof(sizes) / (3 * sizeof(gint)); + gint i; + + for (i = 0; i < n_sizes; i++) + if (gdk_rgb_try_colormap (sizes[i][0], sizes[i][1], sizes[i][2])) + return TRUE; + return FALSE; +} + +/* Make a 2 x 2 x 2 colorcube */ +static void +gdk_rgb_colorcube_222 (void) +{ + int i; + GdkColor color; + GdkColormap *cmap; + + if (image_info->cmap_alloced) + cmap = image_info->cmap; + else + cmap = gdk_colormap_get_system (); + + colorcube_d = g_new (guchar, 512); + + for (i = 0; i < 8; i++) + { + color.red = ((i & 4) >> 2) * 65535; + color.green = ((i & 2) >> 1) * 65535; + color.blue = (i & 1) * 65535; + gdk_color_alloc (cmap, &color); + colorcube_d[((i & 4) << 4) | ((i & 2) << 2) | (i & 1)] = color.pixel; + } +} + +void +gdk_rgb_set_verbose (gboolean verbose) +{ + gdk_rgb_verbose = verbose; +} + +void +gdk_rgb_set_install (gboolean install) +{ + gdk_rgb_install_cmap = install; +} + +void +gdk_rgb_set_min_colors (gint min_colors) +{ + gdk_rgb_min_colors = min_colors; +} + +/* Return a "score" based on the following criteria (in hex): + + x000 is the quality - 1 is 1bpp, 2 is 4bpp, + 4 is 8bpp, + 7 is 15bpp truecolor, 8 is 16bpp truecolor, + 9 is 24bpp truecolor. + 0x00 is the speed - 1 is the normal case, + 2 means faster than normal + 00x0 gets a point for being the system visual + 000x gets a point for being pseudocolor + + A caveat: in the 8bpp modes, being the system visual seems to be + quite important. Thus, all of the 8bpp modes should be ranked at + the same speed. +*/ +static guint32 +gdk_rgb_score_visual (GdkVisual *visual) +{ + guint32 quality, speed, sys, pseudo; + static const gchar* visual_names[] = + { + "static gray", + "grayscale", + "static color", + "pseudo color", + "true color", + "direct color", + }; + + + quality = 0; + speed = 1; + sys = 0; + if (visual->type == GDK_VISUAL_TRUE_COLOR || + visual->type == GDK_VISUAL_DIRECT_COLOR) + { + if (visual->depth == 24) + { + quality = 9; + /* Should test for MSB visual here, and set speed if so. */ + } + else if (visual->depth == 16) + quality = 8; + else if (visual->depth == 15) + quality = 7; + else if (visual->depth == 8) + quality = 4; + } + else if (visual->type == GDK_VISUAL_PSEUDO_COLOR || + visual->type == GDK_VISUAL_STATIC_COLOR) + { + if (visual->depth == 8) + quality = 4; + else if (visual->depth == 4) + quality = 2; + else if (visual->depth == 1) + quality = 1; + } + else if (visual->type == GDK_VISUAL_STATIC_GRAY +#ifdef ENABLE_GRAYSCALE + || visual->type == GDK_VISUAL_GRAYSCALE +#endif + ) + { + if (visual->depth == 8) + quality = 4; + else if (visual->depth == 4) + quality = 2; + else if (visual->depth == 1) + quality = 1; + } + + if (quality == 0) + return 0; + + sys = (visual == gdk_visual_get_system ()); + + pseudo = (visual->type == GDK_VISUAL_PSEUDO_COLOR || visual->type == GDK_VISUAL_TRUE_COLOR); + + if (gdk_rgb_verbose) + g_print ("Visual 0x%x, type = %s, depth = %d, %x:%x:%x%s; score=%x\n", + (gint)(((GdkVisualPrivate *)visual)->xvisual->visualid), + visual_names[visual->type], + visual->depth, + visual->red_mask, + visual->green_mask, + visual->blue_mask, + sys ? " (system)" : "", + (quality << 12) | (speed << 8) | (sys << 4) | pseudo); + + return (quality << 12) | (speed << 8) | (sys << 4) | pseudo; +} + +static void +gdk_rgb_choose_visual (void) +{ + GList *visuals; + guint32 score, best_score; + GdkVisual *visual, *best_visual; + + visuals = gdk_list_visuals (); + + best_visual = visuals->data; + best_score = gdk_rgb_score_visual (best_visual); + visuals = visuals->next; + while (visuals) + { + visual = visuals->data; + score = gdk_rgb_score_visual (visual); + if (score > best_score) + { + best_score = score; + best_visual = visual; + } + visuals = visuals->next; + } + + image_info->visual = best_visual; +} + +static void gdk_rgb_select_conv (GdkImage *image); + +static void +gdk_rgb_set_gray_cmap (GdkColormap *cmap) +{ + gint i; + GdkColor color; + gint status; + gulong pixels[256]; + gint r, g, b, gray; + + for (i = 0; i < 256; i++) + { + color.pixel = i; + color.red = i * 257; + color.green = i * 257; + color.blue = i * 257; + status = gdk_color_alloc (cmap, &color); + pixels[i] = color.pixel; +#ifdef VERBOSE + g_print ("allocating pixel %d, %x %x %x, result %d\n", + color.pixel, color.red, color.green, color.blue, status); +#endif + } + + /* Now, we make fake colorcubes - we ultimately just use the pseudocolor + methods. */ + + colorcube = g_new (guchar, 4096); + + for (i = 0; i < 4096; i++) + { + r = (i >> 4) & 0xf0; + r = r | r >> 4; + g = i & 0xf0; + g = g | g >> 4; + b = (i << 4 & 0xf0); + b = b | b >> 4; + gray = (g + ((r + b) >> 1)) >> 1; + colorcube[i] = pixels[gray]; + } +} + +void +gdk_rgb_init (void) +{ + gint i; + static const gint byte_order[1] = { 1 }; + + /* check endian sanity */ +#if G_BYTE_ORDER == G_BIG_ENDIAN + if (((char *)byte_order)[0] == 1) + g_error ("gdk_rgb_init: compiled for big endian, but this is a little endian machine.\n\n"); +#else + if (((char *)byte_order)[0] != 1) + g_error ("gdk_rgb_init: compiled for little endian, but this is a big endian machine.\n\n"); +#endif + + if (image_info == NULL) + { + image_info = g_new0 (GdkRgbInfo, 1); + + image_info->visual = NULL; + image_info->cmap = NULL; + + image_info->color_pixels = NULL; + image_info->gray_pixels = NULL; + image_info->reserved_pixels = NULL; + + image_info->nred_shades = 6; + image_info->ngreen_shades = 6; + image_info->nblue_shades = 4; + image_info->ngray_shades = 24; + image_info->nreserved = 0; + + image_info->bpp = 0; + image_info->cmap_alloced = FALSE; + image_info->gamma = 1.0; + + image_info->stage_buf = NULL; + + image_info->own_gc = NULL; + + gdk_rgb_choose_visual (); + + if ((image_info->visual->type == GDK_VISUAL_PSEUDO_COLOR || + image_info->visual->type == GDK_VISUAL_STATIC_COLOR) && + image_info->visual->depth < 8 && + image_info->visual->depth >= 3) + { + image_info->cmap = gdk_colormap_get_system (); + gdk_rgb_colorcube_222 (); + } + else if (image_info->visual->type == GDK_VISUAL_PSEUDO_COLOR) + { + if (gdk_rgb_install_cmap || + image_info->visual != gdk_visual_get_system ()) + { + image_info->cmap = gdk_colormap_new (image_info->visual, FALSE); + image_info->cmap_alloced = TRUE; + } + if (!gdk_rgb_do_colormaps ()) + { + image_info->cmap = gdk_colormap_new (image_info->visual, FALSE); + image_info->cmap_alloced = TRUE; + gdk_rgb_do_colormaps (); + } + if (gdk_rgb_verbose) + g_print ("color cube: %d x %d x %d\n", + image_info->nred_shades, + image_info->ngreen_shades, + image_info->nblue_shades); + + if (!image_info->cmap_alloced) + image_info->cmap = gdk_colormap_get_system (); + } +#ifdef ENABLE_GRAYSCALE + else if (image_info->visual->type == GDK_VISUAL_GRAYSCALE) + { + image_info->cmap = gdk_colormap_new (image_info->visual, FALSE); + gdk_rgb_set_gray_cmap (image_info->cmap); + image_info->cmap_alloced = TRUE; + } +#endif + else + { + /* Always install colormap in direct color. */ + if (image_info->visual->type != GDK_VISUAL_DIRECT_COLOR && + image_info->visual == gdk_visual_get_system ()) + image_info->cmap = gdk_colormap_get_system (); + else + { + image_info->cmap = gdk_colormap_new (image_info->visual, FALSE); + image_info->cmap_alloced = TRUE; + } + } + + image_info->bitmap = (image_info->visual->depth == 1); + + for (i = 0; i < N_IMAGES; i++) + if (image_info->bitmap) + /* Use malloc() instead of g_malloc since X will free() this mem */ + static_image[i] = gdk_image_new_bitmap (image_info->visual, + (gpointer) malloc (IMAGE_WIDTH * IMAGE_HEIGHT >> 3), + IMAGE_WIDTH, IMAGE_HEIGHT); + else + static_image[i] = gdk_image_new (GDK_IMAGE_FASTEST, + image_info->visual, + IMAGE_WIDTH, IMAGE_HEIGHT); + + image_info->bpp = static_image[0]->bpp; + + gdk_rgb_select_conv (static_image[0]); + + } +} + +/* convert an rgb value into an X pixel code */ +gulong +gdk_rgb_xpixel_from_rgb (guint32 rgb) +{ + gulong pixel = 0; + + if (image_info->bitmap) + { + return ((rgb & 0xff0000) >> 16) + + ((rgb & 0xff00) >> 7) + + (rgb & 0xff) > 510; + } + else if (image_info->visual->type == GDK_VISUAL_PSEUDO_COLOR) + pixel = colorcube[((rgb & 0xf00000) >> 12) | + ((rgb & 0xf000) >> 8) | + ((rgb & 0xf0) >> 4)]; + else if (image_info->visual->depth < 8 && + image_info->visual->type == GDK_VISUAL_STATIC_COLOR) + { + pixel = colorcube_d[((rgb & 0x800000) >> 17) | + ((rgb & 0x8000) >> 12) | + ((rgb & 0x80) >> 7)]; + } + else if (image_info->visual->type == GDK_VISUAL_TRUE_COLOR || + image_info->visual->type == GDK_VISUAL_DIRECT_COLOR) + { +#ifdef VERBOSE + g_print ("shift, prec: r %d %d g %d %d b %d %d\n", + image_info->visual->red_shift, + image_info->visual->red_prec, + image_info->visual->green_shift, + image_info->visual->green_prec, + image_info->visual->blue_shift, + image_info->visual->blue_prec); +#endif + + pixel = (((((rgb & 0xff0000) >> 16) >> + (8 - image_info->visual->red_prec)) << + image_info->visual->red_shift) + + ((((rgb & 0xff00) >> 8) >> + (8 - image_info->visual->green_prec)) << + image_info->visual->green_shift) + + (((rgb & 0xff) >> + (8 - image_info->visual->blue_prec)) << + image_info->visual->blue_shift)); + } + else if (image_info->visual->type == GDK_VISUAL_STATIC_GRAY || + image_info->visual->type == GDK_VISUAL_GRAYSCALE) + { + int gray = ((rgb & 0xff0000) >> 16) + + ((rgb & 0xff00) >> 7) + + (rgb & 0xff); + + return gray >> (10 - image_info->visual->depth); + } + + return pixel; +} + +void +gdk_rgb_gc_set_foreground (GdkGC *gc, guint32 rgb) +{ + GdkColor color; + + color.pixel = gdk_rgb_xpixel_from_rgb (rgb); + gdk_gc_set_foreground (gc, &color); +} + +void +gdk_rgb_gc_set_background (GdkGC *gc, guint32 rgb) +{ + GdkColor color; + + color.pixel = gdk_rgb_xpixel_from_rgb (rgb); + gdk_gc_set_background (gc, &color); +} + +#if G_BYTE_ORDER == G_LITTLE_ENDIAN +#define HAIRY_CONVERT_8 +#endif + +#ifdef HAIRY_CONVERT_8 +static void +gdk_rgb_convert_8 (GdkImage *image, + gint x0, gint y0, gint width, gint height, + guchar *buf, int rowstride, + gint x_align, gint y_align, GdkRgbCmap *cmap) +{ + int x, y; + gint bpl; + guchar *obuf, *obptr; + guchar *bptr, *bp2; + gint r, g, b; + + bptr = buf; + bpl = image->bpl; + obuf = ((guchar *)image->mem) + y0 * bpl + x0; + for (y = 0; y < height; y++) + { + bp2 = bptr; + obptr = obuf; + if (((unsigned long)obuf | (unsigned long) bp2) & 3) + { + for (x = 0; x < width; x++) + { + r = *bp2++; + g = *bp2++; + b = *bp2++; + obptr[0] = colorcube[((r & 0xf0) << 4) | + (g & 0xf0) | + (b >> 4)]; + obptr++; + } + } + else + { + for (x = 0; x < width - 3; x += 4) + { + guint32 r1b0g0r0; + guint32 g2r2b1g1; + guint32 b3g3r3b2; + + r1b0g0r0 = ((guint32 *)bp2)[0]; + g2r2b1g1 = ((guint32 *)bp2)[1]; + b3g3r3b2 = ((guint32 *)bp2)[2]; + ((guint32 *)obptr)[0] = + colorcube[((r1b0g0r0 & 0xf0) << 4) | + ((r1b0g0r0 & 0xf000) >> 8) | + ((r1b0g0r0 & 0xf00000) >> 20)] | + (colorcube[((r1b0g0r0 & 0xf0000000) >> 20) | + (g2r2b1g1 & 0xf0) | + ((g2r2b1g1 & 0xf000) >> 12)] << 8) | + (colorcube[((g2r2b1g1 & 0xf00000) >> 12) | + ((g2r2b1g1 & 0xf0000000) >> 24) | + ((b3g3r3b2 & 0xf0) >> 4)] << 16) | + (colorcube[((b3g3r3b2 & 0xf000) >> 4) | + ((b3g3r3b2 & 0xf00000) >> 16) | + (b3g3r3b2 >> 28)] << 24); + bp2 += 12; + obptr += 4; + } + for (; x < width; x++) + { + r = *bp2++; + g = *bp2++; + b = *bp2++; + obptr[0] = colorcube[((r & 0xf0) << 4) | + (g & 0xf0) | + (b >> 4)]; + obptr++; + } + } + bptr += rowstride; + obuf += bpl; + } +} +#else +static void +gdk_rgb_convert_8 (GdkImage *image, + gint x0, gint y0, gint width, gint height, + guchar *buf, int rowstride, + gint x_align, gint y_align, GdkRgbCmap *cmap) +{ + int x, y; + gint bpl; + guchar *obuf, *obptr; + guchar *bptr, *bp2; + gint r, g, b; + + bptr = buf; + bpl = image->bpl; + obuf = ((guchar *)image->mem) + y0 * bpl + x0; + for (y = 0; y < height; y++) + { + bp2 = bptr; + obptr = obuf; + for (x = 0; x < width; x++) + { + r = *bp2++; + g = *bp2++; + b = *bp2++; + obptr[0] = colorcube[((r & 0xf0) << 4) | + (g & 0xf0) | + (b >> 4)]; + obptr++; + } + bptr += rowstride; + obuf += bpl; + } +} +#endif + +#if 1 + +/* This dither table was generated by Raph Levien using patented + technology (US Patent 5,276,535). The dither table itself is in the + public domain. */ + +#define DM_WIDTH 128 +#define DM_WIDTH_SHIFT 7 +#define DM_HEIGHT 128 +static const guchar DM[128][128] = +{ + { 0, 41, 23, 5, 17, 39, 7, 15, 62, 23, 40, 51, 31, 47, 9, 32, 52, 27, 57, 25, 6, 61, 27, 52, 37, 7, 40, 63, 18, 36, 10, 42, 25, 62, 45, 34, 20, 42, 37, 14, 35, 29, 50, 10, 61, 2, 40, 8, 37, 12, 58, 22, 5, 41, 10, 39, 0, 60, 11, 46, 2, 55, 38, 17, 36, 59, 13, 54, 37, 56, 8, 29, 16, 13, 63, 22, 41, 55, 7, 20, 49, 14, 23, 55, 37, 23, 19, 36, 15, 49, 23, 63, 30, 14, 38, 27, 53, 13, 22, 41, 19, 31, 7, 19, 50, 30, 49, 16, 3, 32, 56, 40, 29, 34, 8, 48, 19, 45, 4, 51, 12, 46, 35, 49, 16, 42, 12, 62 }, + { 30, 57, 36, 54, 47, 34, 52, 27, 43, 4, 28, 7, 17, 36, 62, 13, 44, 7, 18, 48, 33, 21, 44, 14, 30, 47, 12, 33, 5, 55, 31, 58, 13, 30, 4, 17, 52, 10, 60, 26, 46, 0, 39, 27, 42, 22, 47, 25, 60, 32, 9, 38, 48, 17, 59, 30, 49, 18, 34, 25, 51, 19, 5, 48, 21, 8, 28, 46, 1, 32, 41, 19, 54, 47, 37, 18, 28, 11, 44, 30, 39, 56, 2, 33, 8, 42, 61, 28, 58, 8, 46, 9, 41, 4, 58, 7, 21, 48, 59, 10, 52, 14, 42, 57, 12, 25, 7, 53, 42, 24, 11, 50, 17, 59, 42, 2, 36, 60, 32, 17, 63, 29, 21, 7, 59, 32, 24, 39 }, + { 22, 8, 16, 32, 3, 25, 13, 57, 18, 45, 58, 39, 55, 20, 5, 42, 23, 34, 63, 1, 51, 10, 58, 4, 60, 23, 53, 27, 44, 21, 3, 48, 8, 50, 43, 54, 27, 32, 5, 55, 21, 58, 12, 53, 6, 36, 14, 50, 17, 29, 53, 15, 24, 52, 7, 36, 13, 42, 4, 53, 9, 35, 61, 26, 56, 32, 49, 15, 62, 23, 6, 60, 2, 31, 4, 48, 58, 38, 15, 61, 5, 25, 47, 28, 50, 15, 7, 40, 3, 32, 33, 52, 25, 50, 35, 42, 61, 3, 28, 36, 23, 63, 4, 33, 46, 62, 36, 23, 60, 6, 54, 28, 4, 37, 23, 55, 25, 8, 42, 54, 14, 6, 56, 38, 19, 52, 4, 46 }, + { 48, 53, 43, 12, 45, 63, 30, 37, 9, 34, 21, 1, 25, 47, 29, 58, 3, 54, 15, 39, 29, 17, 38, 35, 20, 43, 1, 49, 15, 59, 29, 39, 22, 35, 16, 23, 1, 47, 39, 18, 8, 44, 25, 31, 57, 19, 63, 4, 45, 3, 42, 61, 1, 31, 45, 20, 57, 29, 62, 21, 32, 41, 14, 44, 3, 39, 5, 34, 10, 43, 51, 35, 23, 52, 40, 10, 21, 1, 53, 18, 51, 43, 12, 62, 18, 54, 26, 51, 20, 57, 14, 1, 62, 16, 11, 18, 32, 39, 17, 44, 1, 48, 26, 37, 18, 2, 51, 14, 28, 45, 35, 18, 57, 13, 47, 11, 51, 20, 2, 39, 31, 47, 25, 1, 50, 11, 60, 7 }, + { 18, 28, 1, 56, 21, 10, 51, 2, 46, 54, 14, 61, 11, 50, 13, 38, 19, 31, 45, 9, 55, 24, 47, 5, 54, 9, 62, 11, 35, 8, 51, 14, 57, 6, 63, 40, 58, 14, 51, 28, 62, 34, 15, 48, 1, 41, 30, 35, 55, 21, 34, 11, 49, 37, 8, 52, 4, 23, 15, 43, 1, 58, 11, 23, 53, 16, 55, 26, 58, 18, 27, 12, 45, 14, 25, 63, 42, 33, 27, 35, 9, 31, 21, 38, 1, 44, 34, 12, 48, 38, 21, 44, 29, 47, 26, 53, 1, 46, 54, 8, 59, 29, 11, 55, 22, 41, 33, 20, 39, 1, 48, 9, 44, 32, 5, 62, 29, 44, 57, 23, 10, 58, 34, 43, 15, 37, 26, 33 }, + { 51, 38, 59, 24, 35, 42, 19, 60, 5, 32, 41, 26, 43, 33, 7, 53, 48, 11, 59, 23, 42, 2, 61, 30, 16, 40, 32, 24, 56, 41, 19, 33, 37, 26, 47, 9, 31, 22, 2, 45, 9, 54, 4, 37, 21, 52, 11, 23, 7, 57, 16, 25, 55, 18, 63, 27, 46, 39, 56, 10, 50, 37, 29, 47, 19, 63, 24, 9, 46, 2, 39, 60, 9, 57, 30, 7, 49, 11, 59, 3, 45, 57, 5, 60, 29, 22, 5, 60, 30, 9, 59, 18, 40, 6, 57, 36, 30, 12, 24, 34, 15, 40, 52, 6, 49, 9, 58, 4, 63, 12, 26, 61, 22, 53, 38, 16, 35, 14, 28, 50, 42, 17, 5, 28, 62, 20, 54, 12 }, + { 26, 6, 31, 15, 49, 6, 38, 27, 22, 49, 16, 56, 2, 62, 30, 21, 0, 36, 28, 6, 49, 32, 13, 52, 26, 50, 19, 46, 3, 26, 62, 0, 53, 12, 29, 3, 53, 41, 60, 24, 38, 13, 58, 16, 43, 9, 59, 39, 46, 28, 44, 40, 2, 33, 13, 41, 16, 6, 47, 31, 26, 17, 57, 6, 38, 0, 42, 36, 29, 52, 20, 31, 48, 0, 34, 56, 20, 36, 23, 54, 14, 41, 24, 37, 10, 55, 46, 25, 16, 45, 36, 4, 55, 23, 15, 8, 50, 62, 5, 56, 44, 20, 13, 28, 59, 31, 24, 47, 31, 52, 37, 17, 40, 0, 26, 49, 3, 60, 7, 33, 0, 61, 53, 40, 8, 45, 2, 41 }, + { 16, 63, 43, 4, 61, 24, 56, 13, 53, 8, 36, 12, 24, 41, 16, 46, 60, 26, 52, 39, 14, 57, 21, 37, 0, 45, 7, 59, 38, 17, 43, 10, 45, 20, 61, 43, 19, 11, 33, 17, 50, 32, 23, 61, 28, 49, 26, 0, 18, 51, 5, 60, 22, 58, 29, 0, 59, 34, 19, 62, 3, 52, 7, 44, 30, 59, 13, 50, 15, 62, 7, 17, 38, 22, 44, 15, 40, 4, 47, 28, 33, 17, 49, 16, 51, 40, 10, 56, 0, 53, 13, 49, 28, 38, 60, 21, 43, 19, 37, 27, 3, 51, 34, 39, 0, 45, 15, 43, 10, 21, 3, 55, 8, 33, 59, 10, 41, 18, 52, 24, 46, 20, 30, 13, 58, 22, 36, 57 }, + { 50, 34, 11, 47, 29, 17, 44, 0, 33, 63, 28, 46, 52, 5, 57, 10, 42, 18, 4, 63, 20, 8, 44, 10, 56, 34, 14, 29, 5, 54, 23, 59, 32, 49, 7, 34, 49, 27, 56, 0, 42, 7, 46, 3, 40, 6, 54, 32, 62, 13, 36, 10, 47, 8, 35, 49, 24, 51, 12, 40, 22, 35, 60, 12, 22, 51, 33, 4, 40, 25, 43, 55, 5, 54, 12, 61, 26, 51, 8, 62, 0, 53, 7, 63, 2, 32, 19, 34, 42, 24, 31, 63, 2, 10, 45, 33, 0, 48, 9, 61, 22, 47, 8, 62, 18, 56, 7, 54, 27, 57, 46, 30, 50, 19, 45, 30, 56, 36, 22, 47, 11, 38, 3, 51, 32, 48, 18, 9 }, + { 0, 21, 40, 19, 52, 9, 37, 48, 20, 40, 3, 18, 27, 38, 35, 22, 31, 56, 13, 35, 46, 28, 60, 40, 27, 18, 61, 50, 41, 30, 7, 36, 2, 25, 16, 57, 5, 15, 47, 29, 55, 19, 30, 52, 15, 34, 20, 12, 43, 30, 20, 54, 25, 44, 53, 12, 38, 5, 55, 27, 48, 15, 33, 27, 45, 8, 19, 28, 56, 11, 33, 49, 18, 36, 29, 2, 45, 16, 39, 19, 31, 43, 27, 35, 20, 52, 26, 6, 61, 11, 41, 17, 29, 51, 20, 56, 25, 32, 41, 17, 53, 31, 25, 14, 42, 23, 35, 16, 38, 6, 34, 12, 15, 62, 6, 21, 13, 1, 63, 9, 55, 27, 43, 25, 14, 4, 31, 55 }, + { 44, 29, 61, 2, 35, 58, 26, 15, 60, 10, 51, 59, 14, 55, 8, 50, 2, 44, 25, 51, 1, 33, 16, 4, 48, 36, 2, 21, 12, 57, 48, 13, 51, 55, 40, 28, 37, 62, 8, 39, 12, 63, 36, 10, 59, 24, 56, 47, 9, 50, 41, 1, 32, 17, 6, 21, 61, 30, 9, 43, 1, 54, 41, 2, 54, 37, 48, 61, 1, 46, 21, 3, 58, 24, 50, 32, 60, 10, 57, 25, 46, 12, 59, 4, 45, 13, 57, 47, 27, 39, 5, 58, 47, 14, 35, 4, 52, 13, 60, 6, 36, 10, 45, 55, 4, 50, 29, 2, 61, 50, 25, 58, 44, 24, 36, 42, 54, 28, 40, 32, 16, 56, 6, 62, 46, 39, 60, 23 }, + { 7, 48, 14, 54, 23, 40, 4, 45, 30, 22, 42, 32, 1, 44, 20, 29, 58, 8, 37, 19, 41, 54, 24, 58, 9, 53, 25, 46, 34, 16, 23, 38, 27, 11, 18, 1, 52, 21, 35, 22, 48, 5, 25, 45, 18, 38, 2, 27, 35, 4, 57, 15, 62, 39, 57, 28, 42, 16, 36, 60, 24, 18, 10, 63, 20, 5, 16, 23, 37, 14, 59, 27, 41, 8, 13, 42, 21, 35, 6, 50, 3, 38, 15, 48, 30, 39, 17, 3, 49, 14, 53, 33, 24, 7, 61, 44, 11, 39, 23, 49, 19, 58, 1, 32, 36, 12, 60, 41, 20, 13, 41, 4, 39, 1, 48, 8, 18, 51, 14, 44, 5, 37, 21, 34, 1, 26, 10, 37 }, + { 53, 36, 27, 9, 50, 12, 32, 55, 2, 57, 7, 17, 48, 34, 63, 15, 40, 26, 62, 11, 49, 6, 31, 39, 22, 42, 6, 63, 1, 39, 60, 4, 42, 61, 32, 45, 24, 44, 2, 60, 16, 41, 53, 1, 33, 61, 49, 17, 63, 23, 45, 26, 33, 3, 23, 46, 2, 50, 20, 4, 45, 34, 49, 30, 39, 58, 44, 31, 53, 34, 6, 52, 30, 47, 63, 1, 53, 22, 42, 31, 58, 23, 54, 22, 61, 8, 36, 59, 22, 35, 21, 1, 55, 40, 27, 16, 30, 54, 2, 29, 43, 16, 39, 63, 21, 46, 26, 10, 48, 32, 19, 53, 30, 56, 26, 60, 33, 4, 61, 23, 49, 59, 15, 53, 19, 58, 42, 16 }, + { 20, 5, 59, 46, 25, 62, 7, 19, 43, 25, 37, 61, 11, 24, 4, 54, 12, 52, 3, 32, 17, 61, 12, 47, 15, 55, 18, 31, 53, 28, 9, 50, 21, 6, 55, 9, 58, 14, 54, 26, 33, 7, 31, 58, 13, 21, 8, 42, 29, 6, 37, 11, 48, 52, 14, 60, 11, 39, 56, 32, 14, 58, 7, 26, 17, 4, 42, 8, 11, 47, 19, 38, 10, 17, 26, 37, 9, 55, 28, 13, 18, 40, 6, 33, 1, 43, 25, 11, 51, 7, 62, 43, 18, 37, 3, 57, 45, 9, 38, 58, 5, 52, 27, 7, 17, 53, 5, 57, 37, 2, 63, 9, 22, 15, 11, 38, 25, 45, 35, 0, 28, 10, 41, 30, 50, 8, 31, 57 }, + { 49, 33, 16, 38, 1, 42, 51, 34, 53, 14, 28, 49, 30, 56, 36, 23, 43, 20, 38, 56, 22, 45, 28, 0, 62, 35, 26, 44, 11, 19, 52, 35, 44, 15, 30, 38, 10, 31, 40, 4, 46, 50, 20, 40, 27, 44, 51, 14, 56, 53, 19, 59, 7, 29, 41, 19, 35, 25, 8, 52, 22, 44, 13, 53, 50, 32, 61, 24, 56, 25, 63, 0, 45, 57, 33, 59, 16, 46, 4, 62, 50, 11, 60, 37, 52, 19, 55, 29, 37, 46, 13, 26, 48, 10, 50, 34, 21, 63, 26, 13, 42, 33, 22, 55, 35, 28, 43, 15, 24, 51, 27, 34, 46, 49, 58, 3, 52, 9, 57, 19, 48, 55, 3, 35, 12, 45, 24, 3 }, + { 41, 11, 56, 28, 18, 31, 22, 10, 37, 6, 47, 13, 3, 41, 9, 46, 0, 48, 29, 6, 34, 10, 55, 37, 20, 8, 49, 3, 41, 59, 14, 25, 0, 63, 19, 47, 27, 51, 17, 57, 23, 10, 61, 6, 54, 3, 38, 31, 0, 22, 34, 43, 20, 55, 31, 0, 49, 63, 29, 38, 3, 62, 28, 40, 0, 22, 14, 35, 2, 48, 15, 43, 23, 14, 3, 29, 49, 20, 39, 34, 0, 44, 29, 9, 15, 47, 5, 42, 0, 31, 58, 5, 31, 61, 23, 15, 0, 47, 19, 50, 24, 3, 59, 11, 44, 0, 31, 59, 6, 42, 17, 60, 0, 39, 20, 31, 43, 17, 29, 40, 12, 25, 60, 22, 52, 15, 63, 29 }, + { 20, 52, 8, 44, 62, 4, 59, 49, 17, 63, 21, 39, 60, 18, 52, 27, 33, 59, 14, 51, 59, 43, 24, 5, 51, 30, 57, 17, 32, 5, 37, 56, 48, 34, 42, 3, 60, 5, 36, 13, 43, 37, 18, 34, 25, 12, 59, 24, 47, 36, 11, 50, 3, 38, 9, 58, 16, 5, 43, 18, 47, 10, 37, 18, 59, 46, 29, 52, 40, 12, 34, 28, 56, 36, 53, 7, 43, 8, 24, 52, 26, 17, 56, 43, 24, 32, 63, 20, 57, 16, 22, 52, 36, 8, 41, 56, 29, 32, 54, 7, 35, 57, 14, 48, 20, 62, 13, 39, 53, 29, 8, 45, 13, 29, 7, 61, 14, 54, 6, 63, 38, 32, 18, 43, 2, 39, 6, 47 }, + { 0, 58, 23, 35, 13, 46, 12, 39, 0, 31, 55, 24, 5, 35, 15, 61, 17, 5, 39, 25, 18, 2, 50, 33, 41, 13, 39, 23, 62, 46, 29, 12, 22, 8, 56, 25, 20, 49, 32, 62, 0, 56, 11, 46, 63, 42, 9, 16, 55, 5, 60, 15, 62, 26, 45, 21, 36, 51, 13, 57, 31, 24, 55, 6, 35, 9, 57, 5, 20, 60, 7, 51, 5, 19, 40, 25, 61, 32, 56, 12, 36, 48, 21, 2, 58, 12, 39, 28, 9, 50, 40, 12, 44, 18, 25, 49, 6, 38, 11, 62, 18, 46, 30, 9, 40, 25, 49, 19, 10, 36, 55, 22, 33, 52, 41, 18, 37, 27, 49, 21, 2, 46, 7, 53, 33, 61, 27, 35 }, + { 41, 31, 5, 39, 51, 26, 33, 57, 27, 41, 9, 44, 54, 29, 48, 7, 44, 36, 57, 10, 31, 63, 16, 45, 11, 60, 1, 47, 7, 20, 43, 3, 58, 36, 13, 52, 39, 7, 15, 28, 22, 48, 30, 21, 1, 29, 49, 44, 27, 17, 40, 30, 24, 42, 12, 53, 33, 7, 47, 20, 1, 42, 11, 49, 25, 43, 17, 32, 45, 27, 41, 21, 31, 62, 11, 49, 2, 15, 42, 5, 63, 7, 41, 27, 49, 6, 54, 23, 46, 34, 2, 28, 54, 3, 59, 12, 46, 17, 42, 28, 40, 1, 37, 51, 5, 55, 2, 34, 47, 16, 3, 62, 47, 5, 23, 56, 1, 44, 12, 34, 51, 16, 57, 11, 25, 17, 54, 13 }, + { 60, 26, 55, 18, 3, 60, 20, 6, 52, 15, 50, 19, 32, 11, 23, 53, 26, 21, 1, 47, 42, 27, 8, 58, 21, 27, 53, 36, 26, 54, 31, 50, 17, 30, 45, 1, 29, 59, 44, 53, 41, 4, 35, 58, 51, 19, 32, 4, 52, 34, 48, 8, 51, 5, 56, 2, 25, 61, 27, 38, 54, 27, 62, 21, 51, 1, 39, 62, 10, 50, 1, 58, 13, 47, 38, 18, 35, 54, 22, 51, 30, 19, 59, 34, 14, 32, 44, 4, 60, 15, 52, 62, 20, 43, 30, 35, 21, 60, 4, 52, 12, 24, 61, 18, 30, 42, 23, 61, 25, 50, 27, 38, 11, 59, 12, 35, 50, 30, 59, 24, 8, 42, 28, 37, 48, 9, 44, 21 }, + { 10, 47, 15, 50, 30, 43, 8, 45, 29, 2, 36, 59, 1, 58, 41, 3, 63, 31, 54, 20, 13, 55, 35, 38, 4, 44, 15, 9, 61, 2, 14, 38, 61, 10, 23, 54, 18, 12, 24, 2, 14, 55, 16, 8, 38, 14, 41, 60, 10, 23, 1, 58, 32, 17, 28, 37, 41, 15, 3, 60, 15, 33, 4, 36, 16, 59, 28, 14, 23, 55, 37, 18, 44, 28, 2, 57, 30, 10, 27, 46, 14, 38, 3, 53, 21, 61, 17, 35, 10, 41, 26, 7, 33, 9, 57, 1, 53, 37, 26, 20, 56, 48, 9, 33, 58, 16, 37, 7, 45, 1, 57, 15, 32, 26, 42, 23, 7, 20, 4, 54, 31, 62, 22, 1, 59, 30, 4, 51 }, + { 36, 2, 38, 11, 24, 36, 54, 22, 62, 47, 25, 8, 28, 45, 16, 38, 12, 43, 9, 37, 49, 3, 23, 52, 18, 30, 50, 33, 19, 42, 49, 26, 6, 40, 47, 35, 63, 38, 50, 33, 60, 26, 36, 47, 24, 57, 6, 26, 39, 63, 19, 44, 14, 46, 61, 9, 50, 30, 45, 23, 10, 50, 44, 8, 31, 54, 6, 46, 36, 4, 30, 54, 8, 52, 22, 41, 4, 60, 40, 0, 58, 24, 45, 10, 37, 1, 48, 30, 56, 17, 38, 48, 24, 47, 19, 39, 14, 8, 45, 32, 2, 34, 27, 44, 4, 52, 11, 56, 31, 21, 40, 19, 44, 51, 2, 63, 46, 58, 36, 43, 14, 5, 50, 38, 14, 56, 40, 23 }, + { 61, 46, 32, 63, 54, 1, 14, 34, 12, 40, 18, 49, 37, 10, 61, 30, 51, 24, 60, 7, 29, 40, 62, 11, 46, 58, 6, 56, 24, 10, 34, 52, 21, 59, 16, 3, 27, 5, 20, 46, 9, 40, 7, 62, 2, 30, 53, 15, 48, 10, 28, 35, 54, 6, 21, 34, 18, 55, 7, 40, 57, 19, 26, 60, 41, 13, 24, 51, 19, 61, 9, 25, 34, 15, 63, 11, 45, 17, 20, 47, 33, 8, 31, 62, 43, 26, 53, 7, 24, 59, 0, 13, 55, 4, 62, 27, 51, 31, 63, 15, 58, 7, 54, 14, 46, 22, 28, 43, 12, 63, 8, 54, 5, 17, 39, 33, 15, 10, 27, 17, 47, 34, 19, 45, 27, 12, 33, 17 }, + { 5, 28, 21, 7, 17, 48, 42, 58, 23, 4, 63, 14, 55, 21, 34, 5, 19, 0, 45, 17, 52, 15, 25, 32, 0, 22, 40, 13, 45, 62, 18, 0, 43, 11, 33, 55, 30, 42, 57, 19, 51, 31, 22, 43, 18, 45, 34, 0, 43, 31, 56, 3, 23, 40, 59, 0, 44, 13, 48, 35, 2, 32, 46, 0, 21, 48, 35, 3, 40, 32, 43, 59, 0, 48, 33, 26, 53, 36, 55, 12, 51, 16, 55, 5, 18, 29, 11, 39, 51, 19, 45, 31, 42, 21, 35, 6, 22, 47, 10, 38, 23, 50, 20, 36, 0, 60, 38, 4, 50, 35, 48, 34, 24, 57, 9, 53, 28, 48, 61, 0, 56, 24, 53, 3, 63, 6, 42, 57 }, + { 13, 53, 45, 40, 58, 27, 6, 16, 38, 51, 33, 30, 43, 2, 47, 56, 40, 50, 33, 57, 27, 5, 47, 42, 60, 36, 16, 54, 28, 4, 37, 57, 28, 51, 22, 8, 45, 14, 6, 39, 0, 54, 11, 59, 28, 12, 50, 21, 61, 13, 19, 38, 49, 11, 25, 37, 58, 29, 22, 63, 14, 56, 12, 53, 30, 63, 9, 57, 26, 12, 47, 16, 23, 39, 50, 6, 31, 2, 25, 6, 28, 41, 36, 22, 50, 57, 42, 3, 34, 8, 28, 61, 11, 50, 16, 54, 41, 0, 55, 43, 5, 29, 41, 63, 25, 16, 53, 18, 26, 10, 21, 0, 61, 30, 41, 22, 3, 38, 20, 39, 29, 8, 41, 16, 36, 52, 22, 19 }, + { 55, 34, 0, 25, 10, 32, 56, 44, 28, 0, 57, 7, 26, 53, 23, 8, 13, 35, 22, 12, 36, 60, 20, 8, 14, 29, 48, 2, 41, 49, 23, 13, 39, 7, 48, 58, 25, 53, 34, 62, 28, 16, 48, 4, 37, 56, 27, 5, 36, 52, 46, 7, 62, 33, 52, 11, 17, 53, 5, 28, 41, 24, 38, 17, 5, 39, 20, 45, 15, 56, 5, 38, 60, 8, 14, 57, 21, 48, 62, 39, 59, 13, 1, 60, 9, 32, 16, 63, 44, 25, 52, 15, 36, 2, 60, 29, 12, 33, 25, 17, 59, 45, 13, 8, 49, 32, 6, 40, 59, 29, 45, 37, 13, 47, 6, 55, 30, 45, 9, 52, 13, 59, 25, 47, 32, 1, 49, 30 }, + { 9, 39, 14, 61, 49, 37, 3, 20, 50, 13, 41, 19, 46, 17, 38, 59, 28, 62, 4, 44, 54, 1, 34, 51, 55, 7, 63, 32, 21, 8, 56, 31, 62, 19, 36, 1, 41, 17, 24, 12, 42, 35, 25, 52, 20, 8, 44, 59, 25, 2, 22, 42, 16, 29, 4, 46, 20, 36, 43, 9, 51, 8, 49, 26, 58, 33, 54, 1, 37, 29, 52, 20, 27, 45, 19, 35, 42, 16, 10, 32, 20, 49, 46, 27, 40, 4, 47, 22, 13, 55, 4, 47, 26, 44, 23, 40, 58, 19, 48, 13, 31, 2, 57, 34, 42, 19, 61, 32, 14, 55, 5, 51, 26, 19, 58, 16, 49, 14, 62, 5, 33, 44, 21, 7, 60, 26, 11, 41 }, + { 62, 24, 47, 29, 8, 19, 53, 11, 60, 24, 32, 61, 4, 55, 31, 2, 49, 16, 39, 9, 31, 24, 43, 17, 26, 38, 11, 25, 58, 43, 12, 35, 3, 46, 15, 32, 63, 4, 49, 56, 2, 60, 10, 32, 63, 17, 39, 12, 55, 30, 57, 9, 48, 55, 39, 24, 60, 2, 58, 31, 19, 61, 34, 3, 42, 11, 22, 46, 7, 61, 10, 42, 3, 55, 32, 1, 58, 28, 44, 54, 4, 34, 23, 15, 56, 20, 37, 58, 6, 30, 38, 18, 63, 9, 32, 5, 51, 3, 62, 37, 52, 18, 39, 23, 3, 51, 9, 47, 1, 23, 43, 15, 60, 35, 11, 40, 1, 36, 31, 26, 57, 2, 37, 54, 18, 44, 58, 16 }, + { 5, 51, 3, 33, 43, 62, 21, 42, 35, 9, 48, 15, 36, 10, 22, 42, 20, 46, 26, 56, 50, 12, 59, 3, 48, 19, 45, 53, 1, 27, 47, 17, 52, 24, 56, 11, 51, 21, 37, 30, 20, 46, 14, 41, 1, 47, 33, 7, 41, 17, 35, 27, 20, 1, 14, 54, 26, 33, 18, 47, 1, 44, 14, 59, 16, 52, 28, 18, 49, 31, 25, 34, 63, 13, 51, 24, 9, 50, 3, 23, 38, 63, 7, 52, 29, 46, 11, 33, 50, 22, 57, 36, 1, 57, 49, 17, 39, 28, 9, 35, 6, 27, 53, 15, 55, 30, 24, 58, 36, 41, 11, 52, 32, 3, 44, 25, 62, 23, 51, 15, 42, 22, 50, 10, 39, 4, 31, 35 }, + { 46, 22, 57, 17, 12, 39, 26, 5, 31, 59, 1, 45, 27, 62, 52, 7, 58, 33, 6, 18, 39, 22, 33, 41, 57, 5, 35, 18, 40, 16, 60, 5, 29, 42, 7, 39, 27, 44, 9, 47, 8, 26, 54, 22, 51, 29, 24, 49, 15, 61, 4, 51, 31, 63, 43, 6, 50, 8, 39, 12, 53, 37, 23, 30, 40, 6, 62, 43, 14, 53, 2, 49, 7, 36, 17, 41, 61, 37, 18, 56, 11, 18, 44, 35, 2, 19, 61, 0, 41, 14, 8, 30, 43, 12, 24, 46, 14, 54, 42, 21, 44, 61, 10, 46, 37, 11, 44, 7, 18, 63, 20, 29, 7, 49, 28, 54, 8, 43, 4, 48, 18, 63, 12, 29, 48, 24, 59, 20 }, + { 13, 36, 28, 54, 35, 2, 56, 46, 16, 49, 22, 40, 11, 34, 14, 43, 29, 12, 63, 48, 2, 61, 7, 15, 28, 30, 50, 9, 61, 33, 38, 23, 54, 13, 61, 33, 3, 59, 16, 35, 58, 40, 5, 38, 13, 57, 3, 58, 37, 21, 45, 12, 39, 7, 35, 30, 13, 56, 22, 62, 27, 6, 55, 10, 48, 21, 33, 2, 38, 23, 40, 20, 44, 29, 59, 4, 26, 12, 33, 47, 28, 53, 31, 13, 59, 41, 27, 49, 26, 54, 45, 16, 53, 21, 35, 7, 59, 26, 11, 56, 1, 24, 33, 4, 28, 62, 21, 49, 31, 2, 56, 39, 24, 58, 13, 17, 37, 21, 56, 10, 38, 0, 34, 55, 15, 43, 1, 52 }, + { 42, 9, 50, 6, 25, 60, 14, 38, 10, 29, 53, 18, 57, 3, 25, 51, 0, 53, 25, 17, 29, 37, 52, 46, 0, 62, 14, 37, 4, 50, 10, 44, 0, 46, 20, 25, 50, 19, 55, 0, 23, 31, 62, 34, 11, 45, 19, 32, 0, 53, 10, 59, 23, 47, 18, 60, 42, 28, 37, 3, 50, 15, 35, 44, 0, 51, 27, 60, 9, 57, 16, 58, 11, 22, 46, 15, 53, 48, 7, 42, 0, 60, 5, 49, 24, 54, 9, 17, 39, 5, 34, 62, 3, 40, 60, 31, 0, 47, 29, 16, 49, 39, 59, 17, 50, 0, 40, 13, 53, 38, 16, 46, 0, 42, 34, 60, 2, 53, 29, 31, 58, 46, 27, 6, 61, 8, 37, 28 }, + { 0, 63, 21, 40, 45, 18, 51, 23, 63, 34, 6, 43, 28, 38, 55, 19, 40, 35, 8, 41, 54, 10, 21, 32, 39, 23, 53, 26, 55, 28, 22, 63, 30, 34, 9, 48, 6, 38, 29, 43, 49, 6, 18, 52, 27, 61, 9, 43, 28, 42, 33, 26, 56, 3, 51, 23, 0, 48, 16, 45, 32, 25, 63, 20, 57, 17, 42, 12, 35, 47, 5, 31, 39, 56, 6, 30, 34, 21, 61, 25, 14, 40, 22, 38, 15, 6, 36, 56, 20, 60, 25, 12, 51, 27, 10, 56, 42, 20, 36, 63, 32, 6, 21, 41, 12, 34, 60, 26, 5, 48, 27, 10, 62, 19, 6, 47, 39, 14, 45, 7, 24, 17, 41, 32, 23, 51, 19, 56 }, + { 45, 31, 15, 59, 4, 33, 7, 47, 0, 41, 13, 61, 4, 47, 9, 23, 60, 14, 57, 31, 4, 45, 59, 6, 58, 10, 44, 20, 8, 42, 15, 6, 55, 17, 58, 31, 53, 12, 61, 10, 15, 57, 43, 2, 23, 35, 48, 14, 54, 6, 18, 49, 15, 38, 11, 34, 62, 9, 21, 58, 11, 41, 4, 31, 38, 8, 29, 55, 19, 36, 27, 52, 0, 25, 50, 43, 1, 39, 8, 55, 35, 51, 10, 30, 45, 62, 29, 2, 46, 10, 32, 48, 18, 38, 5, 22, 33, 8, 51, 3, 14, 44, 54, 25, 57, 30, 18, 52, 33, 22, 59, 28, 36, 52, 32, 21, 26, 50, 5, 55, 35, 60, 14, 54, 4, 40, 16, 33 }, + { 27, 3, 49, 10, 30, 40, 55, 27, 57, 24, 52, 21, 32, 17, 60, 30, 5, 44, 27, 49, 19, 34, 13, 24, 43, 36, 3, 49, 31, 59, 37, 48, 26, 41, 2, 41, 14, 36, 21, 32, 40, 26, 13, 49, 55, 5, 16, 40, 25, 60, 36, 1, 63, 29, 17, 44, 25, 40, 52, 5, 29, 47, 54, 13, 46, 24, 60, 4, 51, 22, 63, 14, 45, 18, 12, 62, 17, 57, 19, 42, 3, 26, 58, 48, 1, 21, 40, 52, 23, 37, 44, 1, 29, 58, 43, 50, 15, 61, 19, 45, 58, 28, 7, 48, 2, 46, 8, 42, 3, 55, 8, 50, 12, 4, 55, 10, 63, 33, 20, 40, 11, 3, 46, 20, 48, 26, 61, 11 }, + { 44, 56, 24, 36, 53, 19, 12, 37, 16, 44, 7, 36, 49, 54, 11, 37, 48, 21, 15, 1, 62, 25, 47, 56, 16, 18, 51, 12, 40, 1, 24, 11, 52, 16, 23, 59, 28, 1, 45, 53, 4, 60, 37, 21, 39, 30, 63, 20, 52, 10, 30, 45, 8, 41, 54, 4, 57, 7, 34, 55, 36, 18, 23, 59, 2, 48, 11, 32, 44, 1, 41, 8, 33, 54, 38, 23, 30, 46, 6, 29, 62, 18, 32, 16, 55, 34, 14, 11, 61, 7, 55, 16, 53, 13, 23, 2, 55, 37, 26, 10, 33, 23, 36, 16, 38, 22, 56, 15, 24, 43, 35, 17, 44, 40, 25, 46, 16, 1, 57, 25, 49, 36, 28, 62, 9, 35, 7, 53 }, + { 17, 38, 8, 61, 1, 50, 26, 62, 3, 31, 56, 15, 1, 26, 40, 2, 34, 51, 56, 36, 42, 9, 38, 2, 29, 60, 32, 57, 19, 62, 34, 47, 4, 57, 39, 7, 44, 63, 24, 18, 46, 28, 8, 54, 1, 34, 7, 46, 3, 37, 50, 23, 57, 21, 13, 46, 31, 20, 43, 15, 1, 61, 8, 33, 37, 17, 56, 26, 15, 49, 24, 59, 28, 3, 56, 9, 52, 32, 13, 49, 10, 43, 5, 45, 8, 25, 59, 42, 28, 33, 19, 40, 8, 63, 35, 47, 25, 4, 40, 52, 1, 60, 12, 53, 63, 9, 29, 60, 37, 19, 1, 62, 31, 20, 58, 12, 41, 30, 43, 9, 18, 52, 22, 1, 39, 30, 58, 21 }, + { 13, 47, 29, 18, 43, 34, 5, 48, 20, 42, 10, 45, 30, 58, 20, 63, 24, 11, 6, 28, 54, 14, 22, 52, 41, 7, 26, 5, 45, 15, 53, 13, 35, 27, 18, 50, 12, 33, 5, 56, 10, 17, 45, 24, 59, 15, 50, 26, 56, 13, 19, 5, 32, 52, 27, 36, 2, 61, 12, 26, 49, 40, 27, 52, 13, 50, 6, 39, 61, 34, 10, 37, 48, 20, 41, 27, 2, 36, 59, 24, 54, 33, 63, 20, 38, 50, 3, 17, 52, 4, 58, 27, 45, 21, 32, 11, 48, 17, 57, 20, 46, 38, 25, 43, 4, 34, 51, 6, 13, 45, 57, 26, 6, 48, 2, 35, 53, 23, 61, 34, 59, 6, 42, 56, 13, 51, 2, 41 }, + { 32, 5, 55, 23, 58, 14, 22, 52, 29, 15, 61, 25, 51, 8, 43, 13, 53, 41, 46, 20, 3, 33, 63, 11, 48, 21, 54, 38, 28, 3, 30, 43, 21, 62, 9, 31, 55, 22, 51, 29, 37, 62, 32, 12, 42, 29, 41, 9, 33, 44, 62, 28, 43, 1, 59, 19, 48, 30, 51, 39, 24, 4, 58, 19, 42, 29, 22, 43, 3, 18, 53, 5, 13, 50, 16, 60, 45, 21, 7, 40, 15, 0, 26, 53, 13, 31, 43, 24, 47, 31, 15, 49, 2, 41, 6, 59, 29, 42, 9, 30, 14, 7, 49, 18, 31, 47, 20, 39, 49, 32, 11, 41, 54, 15, 61, 18, 7, 38, 4, 13, 44, 28, 15, 32, 45, 19, 27, 49 }, + { 63, 34, 11, 39, 2, 45, 37, 8, 59, 39, 33, 4, 36, 17, 48, 5, 29, 18, 32, 61, 39, 50, 5, 27, 35, 0, 46, 12, 22, 49, 60, 6, 54, 0, 38, 49, 2, 42, 15, 40, 0, 47, 20, 51, 3, 57, 18, 61, 22, 0, 39, 16, 55, 12, 35, 8, 41, 22, 6, 59, 16, 45, 10, 36, 0, 62, 9, 54, 30, 58, 21, 43, 63, 31, 7, 35, 12, 48, 58, 28, 47, 37, 41, 9, 57, 20, 61, 0, 36, 11, 57, 35, 23, 52, 37, 18, 0, 62, 22, 55, 35, 62, 27, 54, 0, 15, 61, 28, 2, 59, 22, 9, 37, 27, 33, 51, 29, 48, 19, 50, 25, 37, 10, 57, 5, 37, 60, 8 }, + { 20, 25, 46, 52, 31, 60, 12, 55, 0, 19, 11, 46, 62, 35, 23, 38, 57, 0, 55, 10, 16, 30, 58, 44, 17, 59, 29, 63, 42, 8, 36, 20, 33, 46, 16, 61, 25, 35, 8, 54, 26, 7, 58, 22, 34, 6, 47, 14, 53, 31, 48, 9, 37, 25, 49, 63, 16, 55, 45, 14, 34, 63, 21, 53, 25, 33, 46, 16, 35, 7, 46, 29, 0, 39, 25, 55, 22, 34, 18, 4, 56, 11, 23, 51, 28, 6, 39, 14, 62, 44, 19, 8, 60, 12, 56, 28, 50, 34, 39, 5, 51, 3, 41, 12, 57, 35, 10, 53, 25, 17, 52, 30, 47, 0, 43, 14, 5, 57, 31, 55, 0, 63, 47, 23, 54, 24, 14, 43 }, + { 0, 57, 16, 6, 26, 19, 35, 28, 49, 42, 54, 26, 21, 1, 59, 27, 9, 47, 26, 44, 50, 22, 13, 40, 8, 37, 10, 34, 17, 56, 25, 58, 13, 27, 44, 9, 20, 58, 31, 17, 60, 36, 10, 41, 53, 25, 36, 39, 4, 24, 58, 17, 60, 4, 22, 38, 10, 32, 0, 50, 31, 7, 28, 47, 12, 57, 5, 26, 52, 23, 14, 40, 57, 17, 47, 5, 53, 1, 44, 31, 19, 60, 46, 2, 35, 48, 30, 54, 22, 5, 51, 39, 25, 31, 4, 43, 14, 9, 45, 16, 24, 44, 19, 29, 40, 23, 44, 7, 38, 42, 4, 63, 12, 54, 23, 59, 22, 42, 8, 15, 40, 21, 8, 34, 3, 41, 30, 50 }, + { 39, 10, 48, 33, 41, 54, 5, 47, 23, 13, 32, 7, 52, 44, 14, 39, 58, 18, 35, 6, 37, 2, 60, 24, 55, 19, 53, 2, 51, 32, 1, 41, 51, 4, 40, 29, 47, 3, 52, 44, 13, 49, 28, 16, 1, 62, 11, 27, 52, 35, 5, 42, 29, 47, 14, 56, 28, 53, 26, 38, 9, 56, 40, 3, 38, 15, 41, 60, 1, 37, 50, 25, 11, 28, 61, 19, 42, 62, 10, 52, 39, 6, 32, 14, 58, 17, 7, 26, 42, 34, 27, 10, 54, 40, 20, 63, 26, 53, 21, 61, 32, 7, 59, 48, 3, 56, 18, 31, 58, 14, 49, 21, 36, 16, 45, 9, 36, 24, 62, 45, 27, 31, 53, 17, 49, 12, 62, 18 }, + { 28, 59, 21, 58, 2, 16, 38, 9, 62, 3, 56, 41, 10, 31, 50, 4, 32, 52, 12, 63, 23, 46, 33, 31, 4, 48, 25, 43, 14, 23, 47, 11, 22, 55, 14, 60, 23, 37, 11, 39, 23, 2, 45, 56, 31, 43, 19, 55, 16, 46, 21, 51, 11, 33, 44, 2, 41, 18, 5, 52, 23, 44, 17, 60, 27, 49, 11, 32, 44, 10, 54, 2, 56, 33, 8, 38, 13, 29, 36, 16, 24, 63, 27, 51, 21, 43, 56, 12, 49, 3, 59, 48, 1, 15, 46, 7, 36, 2, 47, 11, 50, 27, 37, 13, 33, 8, 51, 46, 1, 34, 28, 40, 3, 33, 60, 29, 47, 1, 35, 11, 59, 42, 2, 60, 26, 46, 6, 35 }, + { 4, 43, 9, 29, 36, 63, 24, 44, 20, 50, 30, 17, 60, 22, 16, 43, 25, 3, 42, 19, 51, 15, 8, 54, 42, 15, 61, 5, 39, 57, 18, 61, 31, 48, 34, 2, 50, 19, 57, 5, 63, 33, 19, 38, 13, 27, 48, 7, 32, 61, 2, 26, 58, 6, 24, 50, 13, 61, 42, 20, 62, 2, 35, 20, 51, 4, 62, 18, 23, 58, 20, 31, 43, 15, 51, 45, 26, 50, 4, 55, 45, 3, 35, 9, 38, 1, 32, 61, 20, 45, 17, 33, 24, 57, 29, 51, 22, 58, 38, 30, 15, 1, 54, 21, 63, 43, 26, 12, 24, 56, 8, 60, 50, 19, 5, 52, 13, 54, 17, 50, 4, 16, 36, 12, 32, 56, 22, 54 }, + { 51, 25, 40, 53, 12, 49, 15, 57, 34, 7, 38, 47, 2, 36, 55, 8, 61, 30, 56, 7, 28, 59, 48, 11, 27, 35, 21, 45, 28, 36, 9, 38, 6, 16, 24, 63, 10, 32, 28, 43, 21, 53, 5, 60, 8, 57, 3, 45, 11, 37, 15, 54, 40, 20, 62, 36, 27, 34, 11, 48, 30, 15, 54, 8, 30, 42, 22, 34, 48, 13, 35, 63, 4, 37, 22, 2, 59, 9, 41, 23, 13, 41, 49, 18, 59, 24, 40, 5, 37, 30, 9, 61, 44, 6, 37, 11, 33, 17, 5, 55, 41, 60, 23, 39, 17, 5, 30, 62, 41, 16, 46, 25, 11, 56, 39, 26, 20, 38, 29, 39, 22, 52, 44, 20, 48, 1, 38, 14 }, + { 15, 33, 2, 18, 44, 6, 27, 0, 32, 61, 25, 12, 58, 28, 40, 20, 47, 13, 34, 43, 38, 1, 23, 62, 40, 0, 51, 10, 63, 3, 52, 26, 44, 30, 45, 6, 41, 54, 0, 51, 12, 30, 46, 24, 49, 22, 40, 33, 63, 23, 43, 30, 9, 47, 0, 17, 54, 7, 57, 3, 37, 47, 24, 46, 13, 55, 7, 52, 2, 42, 6, 26, 49, 18, 60, 34, 16, 57, 33, 20, 61, 30, 8, 54, 14, 46, 12, 53, 16, 55, 38, 13, 22, 53, 18, 59, 46, 27, 43, 19, 32, 10, 45, 6, 49, 36, 52, 2, 20, 55, 6, 39, 32, 15, 44, 3, 58, 10, 63, 6, 56, 30, 7, 58, 9, 40, 19, 63 }, + { 10, 47, 61, 23, 55, 31, 52, 42, 17, 45, 4, 51, 27, 6, 15, 53, 0, 49, 26, 10, 56, 18, 36, 6, 20, 58, 32, 30, 13, 49, 19, 56, 0, 59, 12, 53, 27, 17, 38, 25, 48, 9, 15, 36, 14, 30, 59, 17, 0, 50, 8, 58, 18, 56, 31, 45, 21, 41, 29, 19, 60, 6, 32, 59, 0, 36, 29, 39, 19, 59, 46, 12, 55, 30, 10, 47, 24, 3, 28, 48, 0, 55, 44, 27, 33, 4, 63, 29, 49, 0, 26, 50, 34, 2, 42, 14, 0, 62, 9, 56, 3, 52, 28, 34, 58, 9, 20, 48, 37, 32, 22, 53, 0, 62, 27, 49, 34, 46, 21, 33, 41, 14, 25, 37, 53, 29, 31, 45 }, + { 56, 28, 7, 37, 11, 36, 20, 9, 54, 14, 39, 19, 34, 63, 45, 37, 24, 17, 60, 31, 21, 45, 53, 29, 47, 15, 7, 55, 40, 23, 34, 14, 42, 20, 37, 35, 15, 59, 7, 62, 34, 40, 59, 1, 51, 42, 10, 28, 54, 21, 35, 5, 38, 13, 36, 4, 59, 12, 39, 53, 15, 43, 9, 21, 39, 62, 16, 56, 25, 9, 32, 38, 0, 41, 14, 51, 40, 53, 43, 11, 37, 17, 5, 22, 57, 39, 19, 7, 42, 21, 60, 10, 31, 63, 25, 52, 30, 49, 36, 25, 48, 17, 61, 14, 22, 42, 29, 13, 60, 11, 47, 18, 35, 41, 7, 23, 4, 16, 51, 11, 0, 48, 61, 3, 17, 50, 5, 24 }, + { 0, 42, 21, 49, 60, 3, 57, 40, 29, 48, 23, 56, 42, 11, 22, 5, 59, 39, 4, 50, 3, 41, 12, 57, 25, 50, 44, 18, 4, 46, 7, 62, 33, 50, 4, 56, 21, 32, 43, 18, 3, 23, 55, 34, 20, 4, 53, 38, 12, 46, 29, 52, 25, 61, 23, 51, 26, 46, 1, 34, 25, 57, 28, 51, 26, 11, 50, 3, 44, 28, 53, 21, 57, 27, 62, 6, 31, 19, 8, 63, 26, 59, 36, 47, 15, 29, 50, 25, 35, 47, 18, 41, 4, 48, 8, 40, 12, 23, 6, 44, 13, 40, 1, 31, 55, 0, 61, 43, 4, 50, 26, 58, 9, 53, 24, 61, 42, 55, 31, 43, 57, 20, 34, 27, 43, 8, 59, 39 }, + { 18, 51, 30, 13, 26, 16, 46, 22, 2, 59, 8, 30, 1, 48, 33, 51, 29, 9, 46, 16, 62, 14, 33, 2, 38, 9, 27, 60, 37, 26, 53, 17, 28, 10, 24, 46, 2, 49, 8, 57, 29, 45, 6, 26, 62, 44, 18, 25, 61, 3, 42, 14, 49, 10, 43, 6, 17, 32, 63, 10, 49, 4, 40, 14, 45, 33, 22, 37, 12, 61, 5, 17, 43, 7, 23, 37, 15, 58, 49, 13, 39, 21, 10, 52, 1, 62, 9, 56, 12, 2, 58, 28, 36, 16, 56, 28, 56, 35, 20, 63, 24, 37, 51, 8, 45, 25, 16, 33, 27, 38, 2, 44, 13, 30, 17, 36, 12, 26, 5, 18, 28, 47, 13, 60, 23, 45, 13, 33 }, + { 55, 4, 62, 34, 52, 38, 7, 63, 32, 37, 13, 53, 25, 62, 18, 12, 55, 41, 27, 35, 24, 49, 31, 52, 17, 63, 34, 1, 56, 12, 41, 2, 48, 58, 39, 16, 61, 27, 41, 52, 13, 19, 50, 39, 11, 31, 57, 6, 32, 40, 20, 55, 1, 28, 33, 57, 48, 8, 37, 22, 44, 18, 53, 1, 61, 5, 54, 16, 47, 36, 50, 24, 55, 34, 48, 45, 1, 30, 33, 46, 2, 50, 32, 42, 25, 34, 43, 21, 38, 52, 23, 45, 14, 54, 21, 4, 44, 16, 53, 29, 10, 47, 19, 57, 12, 54, 39, 10, 51, 15, 63, 21, 57, 40, 51, 1, 48, 57, 37, 62, 2, 38, 9, 52, 1, 35, 58, 22 }, + { 36, 46, 10, 42, 1, 27, 43, 15, 50, 21, 45, 16, 41, 3, 35, 44, 20, 1, 57, 11, 55, 7, 43, 8, 22, 42, 13, 46, 21, 39, 31, 60, 22, 5, 29, 44, 11, 35, 20, 4, 36, 58, 32, 15, 47, 2, 36, 48, 16, 60, 8, 35, 44, 63, 16, 2, 40, 26, 55, 14, 58, 35, 24, 31, 19, 42, 31, 58, 1, 29, 10, 40, 2, 19, 12, 54, 22, 61, 7, 24, 56, 5, 28, 16, 54, 3, 15, 58, 6, 30, 8, 62, 1, 43, 31, 47, 7, 59, 1, 38, 58, 4, 34, 27, 38, 5, 31, 59, 7, 46, 30, 3, 34, 6, 28, 59, 20, 8, 32, 15, 53, 24, 55, 31, 19, 49, 11, 26 }, + { 2, 24, 16, 58, 19, 55, 5, 35, 10, 61, 4, 28, 57, 24, 58, 7, 31, 47, 22, 38, 19, 28, 61, 36, 54, 5, 59, 29, 6, 52, 15, 11, 43, 36, 8, 54, 52, 1, 62, 25, 47, 9, 1, 60, 28, 53, 24, 14, 46, 27, 51, 22, 12, 24, 38, 53, 20, 11, 51, 3, 29, 7, 48, 63, 8, 49, 9, 21, 52, 14, 63, 32, 46, 60, 35, 4, 41, 16, 52, 35, 18, 42, 59, 7, 36, 61, 45, 27, 33, 51, 19, 39, 34, 11, 61, 18, 33, 41, 28, 15, 54, 22, 42, 3, 49, 21, 47, 18, 36, 23, 55, 19, 48, 24, 45, 10, 33, 44, 50, 40, 7, 35, 15, 41, 63, 6, 40, 54 }, + { 62, 41, 32, 8, 47, 28, 60, 24, 44, 30, 38, 49, 9, 33, 14, 40, 50, 14, 60, 2, 54, 40, 0, 20, 25, 39, 16, 49, 24, 35, 57, 47, 19, 61, 33, 18, 23, 37, 13, 55, 31, 43, 22, 41, 17, 8, 42, 58, 0, 37, 5, 56, 31, 54, 7, 30, 60, 33, 42, 17, 59, 39, 12, 27, 38, 17, 35, 41, 27, 45, 20, 7, 25, 15, 29, 58, 27, 47, 11, 40, 14, 54, 23, 46, 19, 31, 11, 40, 13, 49, 5, 58, 24, 51, 26, 6, 50, 20, 49, 9, 32, 46, 17, 60, 14, 63, 24, 1, 57, 41, 9, 43, 14, 62, 16, 52, 3, 27, 14, 22, 61, 45, 4, 28, 9, 47, 29, 17 }, + { 5, 50, 12, 53, 38, 18, 11, 51, 0, 55, 17, 6, 47, 54, 19, 63, 5, 26, 34, 45, 13, 30, 47, 58, 10, 48, 32, 3, 62, 9, 26, 0, 25, 14, 50, 3, 47, 30, 42, 16, 6, 63, 12, 49, 33, 55, 21, 10, 34, 63, 18, 41, 3, 47, 19, 43, 0, 49, 8, 28, 46, 20, 52, 0, 56, 24, 60, 3, 59, 5, 39, 57, 48, 52, 9, 38, 3, 21, 26, 60, 0, 32, 12, 38, 4, 48, 53, 0, 60, 15, 29, 44, 18, 10, 38, 57, 13, 60, 2, 26, 62, 7, 50, 29, 35, 8, 40, 53, 28, 12, 60, 33, 38, 5, 37, 29, 60, 39, 56, 0, 30, 18, 50, 34, 59, 25, 14, 44 }, + { 20, 31, 60, 22, 3, 49, 33, 25, 40, 13, 34, 59, 22, 36, 0, 28, 37, 56, 8, 18, 51, 16, 4, 45, 27, 12, 53, 42, 18, 44, 51, 31, 55, 40, 28, 58, 7, 60, 10, 51, 27, 37, 24, 56, 5, 26, 44, 29, 50, 23, 45, 11, 34, 15, 59, 27, 13, 23, 62, 37, 4, 57, 15, 32, 42, 6, 47, 11, 30, 43, 23, 13, 0, 36, 18, 44, 63, 51, 37, 29, 49, 20, 57, 27, 62, 9, 24, 35, 23, 53, 37, 3, 42, 55, 0, 36, 23, 39, 31, 43, 17, 37, 24, 11, 52, 43, 19, 32, 5, 50, 26, 0, 56, 21, 54, 11, 19, 6, 47, 25, 59, 42, 12, 54, 21, 3, 38, 57 }, + { 48, 0, 35, 27, 44, 14, 59, 7, 57, 46, 26, 2, 42, 12, 52, 43, 10, 27, 53, 42, 32, 62, 37, 21, 34, 61, 7, 23, 36, 4, 38, 12, 41, 5, 17, 45, 22, 27, 39, 21, 59, 0, 45, 18, 39, 62, 3, 38, 14, 7, 54, 26, 61, 39, 9, 52, 45, 36, 18, 50, 10, 34, 44, 22, 50, 14, 36, 55, 17, 34, 53, 62, 33, 26, 56, 6, 31, 12, 6, 53, 9, 44, 2, 50, 20, 40, 55, 17, 47, 7, 26, 63, 22, 32, 48, 16, 46, 8, 52, 12, 57, 41, 0, 56, 25, 3, 61, 14, 45, 35, 18, 44, 12, 46, 23, 42, 32, 51, 35, 10, 17, 36, 23, 1, 45, 52, 32, 10 }, + { 37, 15, 43, 8, 63, 39, 21, 31, 16, 37, 19, 62, 30, 46, 17, 60, 21, 48, 1, 23, 6, 25, 11, 56, 1, 40, 30, 58, 15, 54, 21, 59, 9, 63, 35, 56, 11, 51, 2, 46, 34, 14, 53, 7, 30, 11, 51, 19, 60, 40, 30, 1, 24, 50, 20, 32, 3, 56, 5, 25, 31, 13, 61, 2, 29, 60, 25, 20, 51, 2, 27, 8, 18, 42, 10, 45, 21, 34, 43, 17, 62, 29, 41, 14, 34, 6, 30, 43, 2, 57, 33, 13, 45, 12, 27, 62, 4, 55, 21, 35, 5, 27, 45, 33, 16, 47, 30, 54, 22, 10, 51, 27, 63, 7, 49, 1, 58, 22, 15, 43, 53, 7, 57, 39, 27, 12, 61, 24 }, + { 56, 51, 26, 56, 19, 2, 41, 54, 5, 52, 9, 48, 6, 23, 39, 4, 32, 15, 63, 35, 59, 49, 43, 15, 52, 19, 50, 9, 46, 33, 1, 29, 48, 20, 32, 1, 38, 33, 19, 54, 9, 32, 24, 48, 58, 35, 16, 48, 4, 52, 13, 57, 33, 5, 45, 59, 15, 29, 41, 55, 47, 39, 23, 53, 9, 40, 4, 57, 10, 44, 48, 40, 50, 14, 61, 24, 55, 1, 59, 22, 33, 8, 51, 25, 58, 46, 11, 59, 20, 41, 17, 51, 6, 56, 35, 25, 42, 30, 15, 58, 48, 18, 61, 9, 58, 39, 13, 2, 37, 59, 40, 2, 31, 16, 34, 41, 8, 30, 62, 3, 29, 48, 33, 5, 63, 16, 41, 7 }, + { 22, 4, 46, 11, 33, 51, 29, 10, 62, 24, 43, 27, 15, 58, 50, 25, 54, 44, 9, 38, 18, 3, 29, 57, 32, 5, 26, 43, 17, 61, 24, 52, 8, 42, 23, 53, 15, 61, 7, 28, 57, 43, 4, 40, 20, 2, 43, 25, 32, 35, 21, 43, 17, 48, 10, 22, 38, 54, 11, 21, 1, 58, 16, 30, 48, 18, 46, 32, 38, 13, 22, 4, 59, 35, 2, 51, 30, 39, 15, 47, 4, 56, 13, 37, 1, 28, 16, 52, 32, 9, 61, 29, 38, 19, 3, 52, 10, 48, 1, 32, 11, 40, 20, 36, 6, 22, 49, 29, 55, 6, 20, 56, 36, 52, 19, 60, 26, 46, 18, 54, 40, 13, 20, 46, 35, 19, 49, 29 }, + { 61, 17, 34, 53, 23, 6, 48, 35, 20, 40, 1, 56, 36, 29, 11, 34, 7, 41, 14, 30, 55, 20, 46, 8, 24, 38, 63, 2, 37, 10, 45, 14, 34, 49, 6, 13, 44, 25, 49, 41, 21, 12, 61, 15, 54, 29, 63, 12, 56, 8, 49, 2, 62, 36, 28, 61, 0, 25, 41, 63, 35, 8, 44, 6, 37, 62, 7, 21, 63, 28, 55, 31, 16, 24, 41, 19, 9, 57, 27, 36, 18, 42, 31, 62, 22, 55, 38, 4, 27, 47, 1, 40, 14, 54, 43, 20, 60, 23, 38, 63, 25, 51, 2, 53, 26, 63, 10, 42, 17, 34, 47, 25, 13, 5, 44, 11, 55, 2, 38, 27, 6, 60, 52, 25, 9, 55, 1, 40 }, + { 8, 30, 58, 3, 42, 61, 17, 38, 13, 59, 32, 10, 54, 3, 51, 20, 61, 26, 57, 2, 46, 33, 12, 60, 41, 13, 48, 29, 55, 20, 39, 27, 57, 18, 62, 29, 55, 2, 31, 16, 37, 50, 26, 36, 6, 46, 9, 41, 27, 57, 23, 39, 26, 6, 51, 12, 31, 46, 7, 16, 27, 52, 19, 56, 26, 12, 33, 53, 1, 41, 8, 57, 46, 7, 54, 32, 47, 5, 49, 11, 60, 23, 5, 48, 10, 43, 19, 63, 35, 24, 49, 21, 59, 5, 31, 37, 14, 44, 7, 42, 6, 30, 46, 13, 44, 32, 19, 50, 4, 58, 8, 30, 62, 38, 28, 53, 21, 36, 13, 50, 21, 33, 15, 2, 44, 31, 14, 47 }, + { 37, 13, 39, 16, 28, 9, 57, 0, 25, 49, 21, 45, 18, 47, 12, 42, 0, 49, 22, 39, 16, 53, 25, 36, 0, 52, 22, 16, 6, 60, 4, 51, 0, 26, 37, 47, 10, 36, 63, 5, 57, 0, 18, 59, 23, 33, 51, 19, 0, 44, 15, 11, 54, 17, 42, 35, 53, 18, 58, 33, 49, 4, 34, 42, 0, 50, 43, 25, 16, 49, 34, 20, 37, 28, 12, 63, 16, 38, 25, 44, 0, 40, 52, 17, 35, 3, 50, 14, 8, 53, 11, 36, 25, 45, 9, 62, 0, 54, 28, 17, 50, 55, 15, 24, 57, 0, 53, 34, 23, 41, 15, 45, 0, 49, 16, 4, 48, 9, 63, 45, 0, 42, 58, 37, 61, 22, 54, 26 }, + { 0, 50, 21, 47, 54, 36, 27, 45, 52, 4, 34, 15, 63, 29, 37, 59, 17, 31, 6, 61, 28, 5, 48, 18, 59, 27, 34, 56, 44, 31, 35, 12, 41, 59, 16, 3, 40, 20, 50, 22, 30, 40, 52, 10, 45, 3, 59, 22, 37, 61, 29, 46, 31, 58, 2, 22, 9, 43, 3, 39, 14, 61, 24, 54, 15, 29, 11, 60, 39, 17, 5, 61, 0, 44, 50, 3, 31, 14, 58, 21, 54, 28, 15, 45, 60, 26, 33, 58, 44, 22, 60, 2, 57, 34, 49, 27, 18, 34, 21, 59, 29, 4, 36, 41, 8, 39, 28, 11, 62, 26, 53, 20, 35, 24, 59, 32, 29, 39, 24, 31, 57, 23, 11, 28, 5, 36, 11, 59 }, + { 44, 32, 63, 5, 20, 12, 41, 7, 30, 61, 42, 8, 39, 5, 33, 8, 24, 53, 45, 11, 37, 58, 7, 44, 10, 50, 3, 40, 8, 22, 53, 19, 46, 9, 33, 52, 24, 58, 8, 44, 13, 47, 8, 34, 38, 30, 14, 47, 7, 34, 4, 55, 9, 19, 40, 49, 56, 26, 60, 21, 30, 45, 10, 19, 40, 58, 23, 36, 3, 52, 45, 23, 54, 13, 22, 42, 53, 45, 7, 33, 10, 36, 57, 6, 29, 12, 41, 0, 30, 15, 41, 30, 17, 7, 16, 53, 40, 56, 2, 39, 12, 61, 10, 52, 31, 60, 16, 45, 1, 37, 7, 61, 40, 10, 43, 17, 58, 7, 54, 14, 4, 51, 39, 49, 18, 56, 42, 20 }, + { 14, 6, 24, 36, 56, 49, 22, 60, 18, 14, 23, 51, 26, 57, 21, 52, 41, 14, 35, 50, 19, 31, 40, 23, 33, 14, 63, 17, 32, 47, 7, 62, 23, 30, 56, 11, 42, 27, 14, 60, 35, 19, 28, 61, 17, 55, 25, 39, 53, 17, 42, 21, 38, 63, 25, 5, 14, 36, 12, 50, 1, 37, 59, 32, 2, 51, 6, 56, 27, 32, 11, 30, 38, 26, 60, 8, 26, 19, 62, 39, 50, 2, 21, 39, 53, 23, 56, 19, 49, 39, 5, 46, 55, 23, 42, 4, 31, 11, 47, 26, 45, 22, 48, 18, 21, 5, 48, 25, 57, 14, 47, 30, 3, 56, 12, 50, 1, 42, 19, 47, 35, 17, 8, 30, 45, 25, 4, 51 }, + { 28, 58, 43, 1, 31, 8, 33, 2, 44, 55, 32, 1, 60, 12, 46, 27, 4, 62, 23, 1, 56, 13, 62, 2, 54, 36, 25, 51, 1, 57, 26, 42, 3, 49, 17, 38, 1, 48, 31, 4, 54, 3, 50, 24, 1, 49, 5, 63, 13, 27, 52, 1, 48, 13, 45, 33, 52, 30, 46, 20, 55, 28, 6, 48, 24, 38, 20, 47, 14, 62, 48, 9, 58, 4, 36, 30, 56, 1, 34, 12, 18, 63, 25, 48, 4, 16, 37, 7, 62, 10, 52, 28, 13, 50, 36, 63, 24, 51, 15, 58, 8, 33, 1, 38, 56, 35, 42, 9, 33, 51, 22, 18, 48, 32, 27, 37, 23, 61, 33, 11, 59, 29, 62, 1, 53, 10, 60, 33 }, + { 12, 39, 17, 52, 26, 46, 53, 38, 25, 11, 48, 36, 16, 43, 2, 35, 55, 17, 39, 29, 43, 9, 28, 45, 20, 5, 46, 12, 42, 28, 13, 52, 36, 6, 60, 22, 54, 17, 62, 39, 25, 42, 15, 55, 44, 20, 31, 10, 35, 57, 24, 32, 29, 6, 59, 18, 7, 62, 3, 41, 10, 44, 16, 54, 13, 62, 31, 9, 41, 1, 21, 43, 18, 47, 15, 40, 11, 49, 28, 55, 46, 30, 8, 43, 32, 61, 28, 47, 25, 34, 21, 61, 32, 1, 20, 9, 46, 6, 35, 19, 41, 54, 27, 63, 14, 3, 51, 20, 62, 2, 38, 55, 8, 21, 63, 6, 46, 9, 26, 51, 3, 24, 43, 34, 16, 41, 18, 48 }, + { 62, 23, 55, 9, 15, 62, 19, 13, 58, 40, 6, 30, 54, 19, 50, 31, 10, 44, 6, 59, 21, 47, 51, 15, 60, 39, 30, 54, 21, 61, 19, 33, 14, 29, 43, 11, 34, 45, 7, 21, 10, 56, 36, 6, 38, 11, 58, 42, 2, 47, 11, 60, 50, 16, 41, 28, 38, 23, 47, 17, 35, 63, 22, 33, 42, 5, 45, 17, 53, 35, 25, 56, 33, 6, 51, 19, 60, 23, 43, 15, 5, 40, 58, 13, 51, 1, 45, 11, 54, 3, 43, 8, 37, 48, 59, 29, 39, 21, 61, 43, 3, 31, 10, 44, 24, 29, 60, 12, 28, 40, 11, 25, 43, 52, 14, 41, 16, 57, 44, 20, 40, 55, 12, 21, 57, 27, 35, 2 }, + { 37, 6, 31, 42, 40, 4, 29, 50, 0, 20, 63, 28, 9, 58, 14, 24, 63, 26, 48, 16, 34, 4, 32, 38, 23, 11, 58, 4, 37, 9, 45, 5, 63, 48, 26, 57, 2, 28, 32, 51, 46, 29, 13, 62, 27, 46, 28, 18, 50, 15, 40, 4, 19, 34, 54, 0, 53, 9, 26, 58, 28, 5, 49, 0, 57, 27, 19, 60, 29, 8, 59, 12, 37, 63, 24, 46, 3, 37, 6, 52, 26, 32, 20, 36, 9, 22, 59, 18, 35, 51, 14, 57, 17, 24, 12, 44, 56, 0, 30, 13, 59, 20, 49, 17, 54, 43, 6, 34, 46, 17, 58, 36, 0, 34, 29, 54, 25, 2, 36, 15, 60, 6, 37, 46, 4, 50, 9, 45 }, + { 19, 59, 48, 3, 24, 60, 44, 22, 34, 51, 15, 45, 41, 5, 33, 47, 0, 37, 12, 55, 25, 54, 8, 57, 0, 47, 18, 34, 49, 15, 55, 24, 40, 20, 8, 35, 53, 13, 41, 18, 0, 59, 22, 33, 4, 52, 8, 60, 24, 36, 31, 56, 45, 26, 10, 43, 15, 56, 36, 4, 51, 14, 39, 30, 12, 55, 36, 2, 39, 49, 4, 44, 17, 0, 32, 13, 53, 35, 59, 17, 62, 0, 55, 24, 52, 38, 31, 6, 42, 19, 29, 40, 4, 54, 33, 5, 16, 27, 52, 37, 23, 55, 7, 37, 0, 39, 23, 49, 4, 53, 31, 15, 59, 10, 50, 4, 60, 34, 48, 7, 31, 49, 27, 14, 62, 22, 53, 29 }, + { 46, 21, 14, 51, 36, 17, 7, 57, 10, 32, 3, 37, 22, 60, 39, 18, 56, 20, 42, 3, 36, 10, 44, 26, 41, 29, 53, 27, 2, 39, 30, 52, 0, 59, 15, 48, 23, 61, 6, 58, 37, 12, 40, 49, 16, 39, 20, 44, 0, 62, 8, 21, 3, 59, 23, 32, 49, 31, 12, 44, 22, 59, 18, 50, 24, 7, 43, 52, 15, 23, 41, 26, 51, 28, 55, 39, 21, 27, 10, 42, 12, 45, 27, 47, 3, 15, 63, 26, 55, 0, 60, 26, 45, 18, 62, 38, 58, 49, 8, 47, 4, 33, 46, 29, 57, 13, 56, 16, 59, 21, 5, 47, 23, 39, 18, 44, 13, 22, 28, 53, 19, 0, 58, 32, 41, 7, 26, 13 }, + { 0, 56, 34, 28, 11, 55, 31, 47, 26, 41, 56, 13, 53, 28, 11, 49, 7, 52, 32, 61, 50, 22, 63, 17, 13, 56, 7, 19, 43, 62, 10, 21, 37, 32, 43, 4, 38, 19, 44, 25, 31, 54, 5, 23, 61, 30, 53, 12, 35, 22, 43, 53, 37, 48, 7, 62, 20, 2, 61, 41, 8, 34, 47, 9, 63, 34, 28, 10, 55, 33, 14, 57, 7, 47, 9, 61, 4, 49, 31, 50, 21, 38, 8, 16, 57, 44, 33, 5, 49, 36, 12, 50, 7, 34, 10, 25, 2, 22, 36, 15, 26, 61, 18, 9, 22, 46, 32, 8, 27, 37, 44, 30, 55, 3, 62, 24, 38, 56, 5, 45, 38, 24, 43, 10, 19, 54, 39, 61 }, + { 41, 30, 8, 63, 43, 23, 38, 3, 62, 19, 8, 49, 25, 1, 58, 30, 23, 40, 9, 28, 18, 40, 6, 38, 49, 22, 35, 59, 8, 27, 50, 5, 56, 17, 11, 50, 30, 9, 55, 2, 51, 19, 34, 47, 9, 41, 6, 26, 48, 57, 14, 28, 17, 12, 39, 13, 37, 46, 25, 19, 54, 27, 1, 37, 16, 45, 20, 60, 1, 48, 20, 38, 31, 22, 42, 15, 19, 44, 1, 61, 6, 34, 56, 40, 29, 10, 20, 46, 13, 22, 41, 23, 59, 42, 30, 51, 45, 13, 63, 53, 42, 12, 51, 38, 62, 2, 26, 41, 50, 1, 61, 10, 19, 42, 31, 8, 49, 32, 12, 63, 9, 52, 16, 56, 36, 2, 31, 16 }, + { 52, 5, 47, 20, 1, 53, 12, 50, 16, 35, 43, 21, 33, 43, 16, 44, 3, 59, 14, 46, 1, 30, 60, 33, 2, 45, 12, 42, 31, 47, 14, 33, 46, 25, 55, 27, 60, 36, 16, 42, 14, 46, 26, 1, 55, 15, 63, 32, 2, 38, 5, 47, 33, 61, 30, 52, 4, 57, 6, 38, 11, 43, 61, 24, 52, 3, 31, 22, 42, 10, 62, 3, 59, 11, 35, 57, 33, 54, 24, 14, 29, 48, 18, 2, 60, 41, 53, 24, 32, 62, 3, 53, 15, 1, 55, 17, 32, 40, 6, 31, 1, 40, 28, 5, 35, 52, 19, 63, 13, 33, 17, 41, 52, 26, 15, 57, 1, 20, 42, 17, 35, 27, 48, 5, 25, 50, 44, 11 }, + { 35, 25, 38, 57, 33, 17, 40, 6, 59, 27, 54, 5, 61, 10, 52, 26, 36, 19, 51, 35, 57, 48, 11, 20, 54, 25, 61, 16, 1, 58, 24, 61, 3, 39, 7, 47, 1, 22, 49, 28, 63, 10, 58, 32, 17, 36, 45, 19, 51, 29, 59, 10, 50, 1, 23, 42, 18, 29, 51, 21, 56, 32, 14, 5, 40, 58, 47, 13, 54, 35, 29, 45, 18, 52, 26, 2, 38, 8, 46, 36, 58, 11, 52, 35, 17, 28, 1, 58, 9, 39, 17, 28, 37, 48, 20, 9, 57, 24, 50, 19, 58, 16, 48, 25, 43, 11, 35, 6, 45, 24, 56, 4, 36, 7, 47, 35, 52, 28, 59, 30, 2, 61, 21, 33, 63, 12, 18, 59 }, + { 3, 49, 15, 10, 27, 61, 25, 45, 30, 0, 14, 47, 31, 38, 17, 62, 7, 55, 27, 4, 15, 24, 42, 52, 10, 34, 5, 51, 36, 18, 41, 11, 35, 21, 62, 13, 33, 57, 8, 35, 5, 40, 21, 43, 52, 3, 24, 56, 11, 16, 33, 25, 41, 20, 55, 8, 60, 35, 15, 48, 2, 57, 30, 49, 18, 25, 6, 39, 17, 57, 7, 25, 43, 5, 49, 16, 62, 22, 55, 4, 25, 43, 23, 7, 50, 11, 37, 48, 14, 51, 33, 57, 7, 27, 39, 46, 4, 29, 11, 43, 34, 56, 7, 60, 20, 54, 30, 57, 22, 49, 9, 33, 54, 14, 63, 23, 6, 43, 10, 40, 50, 13, 44, 8, 38, 33, 46, 23 }, + { 55, 39, 22, 50, 44, 4, 36, 9, 52, 23, 37, 59, 21, 2, 46, 13, 31, 41, 11, 45, 62, 29, 6, 37, 19, 48, 30, 23, 44, 7, 53, 28, 54, 16, 41, 29, 44, 18, 52, 24, 60, 15, 48, 7, 27, 59, 9, 34, 42, 54, 7, 63, 4, 46, 31, 27, 45, 0, 40, 26, 34, 17, 37, 10, 53, 29, 36, 50, 2, 27, 51, 11, 61, 37, 23, 41, 30, 7, 18, 50, 39, 14, 63, 32, 45, 61, 19, 30, 25, 44, 2, 47, 23, 63, 11, 34, 59, 37, 60, 3, 22, 14, 44, 30, 15, 0, 47, 15, 3, 38, 61, 20, 27, 45, 11, 39, 51, 16, 55, 3, 22, 54, 29, 58, 1, 57, 6, 29 }, + { 9, 17, 60, 2, 34, 56, 20, 62, 39, 12, 49, 6, 29, 56, 34, 48, 0, 58, 22, 38, 18, 43, 56, 0, 63, 14, 55, 3, 59, 31, 15, 45, 0, 49, 6, 58, 3, 38, 12, 45, 0, 37, 29, 57, 13, 39, 30, 49, 0, 23, 44, 36, 16, 57, 13, 54, 11, 24, 63, 9, 53, 7, 62, 42, 0, 59, 15, 23, 63, 34, 40, 16, 32, 0, 53, 12, 48, 28, 59, 33, 0, 53, 9, 27, 3, 22, 54, 5, 56, 9, 61, 13, 42, 14, 52, 19, 0, 21, 47, 27, 53, 36, 3, 50, 39, 58, 25, 40, 53, 28, 12, 50, 0, 59, 32, 2, 21, 34, 26, 46, 37, 7, 18, 47, 24, 14, 53, 42 }, + { 61, 32, 13, 54, 29, 7, 46, 13, 28, 57, 18, 41, 53, 15, 9, 39, 24, 49, 33, 3, 53, 9, 26, 32, 40, 28, 46, 39, 25, 9, 56, 21, 63, 37, 26, 22, 51, 27, 17, 56, 31, 53, 4, 43, 22, 46, 12, 18, 60, 40, 20, 26, 50, 21, 39, 5, 49, 33, 16, 44, 22, 46, 20, 32, 24, 45, 8, 43, 12, 46, 4, 48, 56, 20, 29, 58, 3, 40, 10, 42, 31, 21, 47, 41, 56, 38, 15, 42, 36, 27, 20, 33, 55, 3, 26, 44, 31, 54, 12, 35, 9, 63, 28, 10, 21, 32, 9, 60, 17, 8, 43, 29, 40, 16, 36, 48, 60, 7, 57, 14, 62, 31, 42, 15, 36, 40, 20, 26 }, + { 0, 37, 47, 23, 41, 18, 32, 48, 1, 35, 8, 25, 4, 26, 63, 20, 54, 8, 16, 61, 35, 23, 51, 15, 58, 7, 12, 20, 50, 34, 42, 4, 38, 10, 32, 47, 8, 60, 41, 20, 9, 25, 50, 19, 62, 1, 37, 56, 28, 8, 53, 11, 3, 58, 34, 43, 19, 60, 38, 4, 58, 31, 3, 51, 11, 55, 38, 30, 21, 58, 19, 26, 9, 44, 36, 13, 46, 20, 62, 24, 13, 60, 5, 28, 12, 34, 7, 59, 0, 53, 45, 6, 38, 30, 50, 7, 62, 16, 41, 5, 46, 18, 55, 42, 51, 5, 45, 23, 34, 48, 19, 58, 5, 25, 54, 19, 13, 41, 28, 21, 0, 49, 10, 60, 4, 51, 9, 45 }, + { 19, 28, 6, 58, 10, 51, 4, 22, 55, 42, 60, 45, 34, 51, 42, 5, 30, 45, 27, 40, 13, 47, 4, 49, 21, 38, 60, 29, 2, 57, 17, 27, 52, 19, 61, 14, 30, 34, 2, 44, 63, 33, 11, 35, 16, 51, 25, 6, 14, 47, 31, 61, 37, 29, 18, 8, 52, 2, 28, 54, 13, 41, 15, 62, 35, 18, 2, 60, 6, 33, 41, 61, 31, 6, 56, 17, 34, 50, 6, 52, 44, 35, 16, 51, 59, 24, 48, 18, 31, 40, 16, 49, 21, 60, 17, 39, 10, 49, 32, 57, 24, 39, 1, 25, 18, 62, 37, 12, 56, 1, 37, 11, 52, 44, 9, 30, 47, 4, 51, 40, 55, 25, 34, 27, 56, 30, 32, 54 }, + { 63, 40, 49, 15, 43, 26, 63, 38, 16, 20, 30, 12, 57, 14, 19, 60, 36, 12, 59, 2, 57, 17, 42, 31, 1, 44, 16, 35, 47, 11, 32, 48, 13, 43, 1, 39, 51, 12, 57, 23, 6, 40, 53, 3, 55, 31, 39, 60, 35, 44, 5, 15, 45, 1, 62, 41, 26, 14, 47, 22, 36, 27, 50, 9, 26, 47, 52, 28, 54, 16, 1, 13, 51, 39, 23, 63, 1, 30, 15, 26, 2, 57, 19, 37, 1, 44, 21, 50, 13, 63, 8, 24, 56, 1, 35, 25, 58, 20, 2, 28, 14, 51, 33, 59, 13, 30, 4, 49, 31, 24, 63, 26, 33, 3, 58, 38, 62, 24, 32, 8, 17, 45, 5, 48, 18, 3, 43, 11 }, + { 21, 4, 24, 34, 59, 1, 37, 11, 53, 5, 47, 2, 22, 40, 32, 1, 24, 50, 21, 29, 38, 25, 63, 8, 55, 24, 53, 6, 62, 23, 59, 3, 54, 20, 58, 24, 5, 46, 15, 38, 48, 14, 27, 42, 23, 7, 46, 10, 17, 58, 25, 52, 23, 32, 49, 12, 55, 30, 40, 7, 59, 1, 56, 21, 39, 4, 23, 15, 37, 46, 55, 42, 21, 4, 48, 8, 45, 54, 37, 55, 32, 8, 46, 10, 30, 54, 4, 41, 25, 29, 36, 48, 11, 43, 14, 47, 5, 43, 53, 36, 61, 10, 45, 6, 41, 54, 27, 43, 16, 55, 6, 46, 18, 42, 23, 15, 1, 45, 12, 60, 37, 22, 62, 12, 39, 59, 16, 52 }, + { 47, 35, 56, 7, 19, 46, 31, 50, 33, 24, 61, 35, 50, 7, 53, 44, 55, 6, 46, 10, 52, 5, 21, 43, 36, 10, 18, 41, 26, 37, 8, 29, 40, 36, 9, 49, 34, 26, 61, 21, 7, 59, 18, 62, 29, 54, 20, 32, 51, 0, 40, 10, 55, 6, 20, 36, 9, 61, 5, 51, 44, 19, 33, 43, 13, 57, 40, 63, 8, 24, 29, 10, 60, 34, 27, 40, 25, 18, 10, 42, 21, 49, 26, 62, 38, 12, 33, 61, 5, 57, 2, 19, 54, 28, 62, 22, 38, 31, 16, 7, 22, 47, 29, 17, 35, 8, 20, 51, 2, 40, 22, 50, 13, 61, 28, 53, 35, 20, 56, 30, 2, 53, 14, 41, 23, 34, 8, 31 }, + { 12, 2, 42, 29, 52, 13, 21, 8, 55, 14, 41, 17, 28, 58, 23, 11, 17, 36, 31, 62, 17, 34, 50, 14, 28, 61, 33, 52, 2, 51, 17, 45, 7, 25, 62, 30, 18, 55, 0, 42, 30, 35, 45, 1, 12, 48, 3, 63, 21, 36, 30, 48, 19, 59, 43, 27, 46, 17, 34, 25, 12, 29, 53, 6, 48, 31, 11, 34, 49, 3, 36, 50, 19, 47, 14, 61, 11, 36, 58, 4, 60, 14, 39, 22, 6, 52, 15, 35, 17, 46, 31, 42, 9, 34, 3, 52, 12, 60, 26, 56, 40, 2, 53, 23, 57, 38, 62, 14, 36, 59, 10, 31, 39, 6, 49, 9, 41, 26, 5, 48, 43, 27, 33, 58, 1, 50, 25, 57 }, + { 61, 37, 15, 61, 3, 39, 58, 43, 26, 0, 44, 10, 47, 3, 37, 63, 28, 43, 13, 39, 3, 57, 30, 59, 0, 48, 5, 43, 13, 22, 60, 33, 55, 15, 42, 4, 52, 10, 45, 13, 54, 4, 24, 49, 37, 26, 41, 14, 42, 9, 61, 13, 38, 23, 3, 53, 0, 58, 21, 42, 63, 10, 17, 61, 25, 0, 58, 28, 17, 44, 57, 12, 27, 0, 55, 5, 52, 28, 23, 47, 29, 0, 43, 17, 58, 28, 47, 23, 55, 10, 58, 23, 51, 40, 18, 33, 45, 0, 49, 8, 32, 61, 19, 48, 0, 26, 7, 47, 29, 18, 44, 0, 56, 34, 20, 59, 15, 51, 37, 18, 10, 52, 7, 20, 46, 9, 38, 17 }, + { 6, 27, 48, 23, 45, 29, 5, 18, 38, 62, 27, 56, 20, 32, 15, 9, 48, 0, 54, 22, 45, 20, 7, 41, 23, 39, 19, 27, 58, 31, 44, 0, 12, 50, 23, 56, 20, 39, 32, 59, 16, 52, 33, 9, 57, 22, 6, 58, 28, 50, 24, 2, 56, 35, 16, 45, 32, 38, 15, 54, 2, 38, 46, 22, 35, 45, 20, 5, 52, 25, 7, 35, 59, 32, 22, 43, 38, 3, 51, 16, 34, 53, 32, 50, 3, 40, 8, 43, 0, 39, 27, 4, 14, 61, 8, 55, 15, 41, 20, 44, 27, 13, 39, 11, 46, 42, 54, 33, 4, 52, 23, 61, 14, 25, 43, 2, 33, 11, 63, 29, 61, 17, 40, 55, 22, 62, 28, 44 }, + { 20, 54, 8, 56, 35, 10, 63, 31, 52, 12, 48, 6, 59, 41, 52, 33, 19, 58, 25, 49, 11, 37, 47, 12, 54, 15, 56, 35, 7, 47, 16, 53, 28, 34, 5, 37, 28, 8, 48, 3, 28, 38, 18, 61, 16, 43, 53, 32, 4, 17, 47, 27, 44, 8, 63, 10, 25, 49, 6, 37, 24, 52, 32, 3, 50, 12, 41, 56, 38, 14, 62, 20, 40, 16, 53, 31, 18, 63, 41, 9, 59, 7, 13, 25, 57, 20, 63, 26, 53, 18, 48, 62, 30, 46, 21, 25, 58, 29, 36, 4, 55, 34, 6, 60, 31, 16, 21, 12, 58, 38, 9, 29, 47, 7, 52, 30, 57, 44, 22, 0, 35, 45, 3, 31, 14, 36, 0, 51 }, + { 42, 14, 33, 24, 16, 49, 40, 2, 22, 33, 16, 36, 25, 1, 21, 61, 38, 8, 33, 4, 62, 26, 29, 60, 6, 46, 30, 11, 63, 4, 36, 40, 19, 57, 46, 11, 41, 63, 22, 25, 58, 10, 46, 2, 34, 27, 11, 38, 56, 34, 12, 53, 18, 33, 41, 51, 13, 28, 60, 20, 47, 14, 29, 59, 16, 62, 8, 22, 32, 47, 9, 49, 2, 44, 7, 12, 45, 6, 20, 27, 45, 24, 62, 42, 36, 11, 33, 15, 37, 7, 32, 10, 37, 1, 35, 50, 6, 11, 63, 24, 52, 15, 50, 24, 3, 37, 56, 27, 34, 22, 49, 16, 36, 62, 17, 39, 4, 15, 54, 24, 50, 8, 58, 26, 49, 54, 11, 30 }, + { 4, 59, 41, 1, 53, 12, 25, 45, 59, 7, 51, 39, 54, 14, 46, 4, 27, 53, 16, 44, 18, 51, 1, 32, 25, 2, 50, 40, 20, 54, 24, 9, 62, 2, 27, 60, 1, 17, 36, 50, 6, 40, 30, 55, 41, 19, 49, 1, 21, 60, 40, 5, 62, 1, 22, 30, 57, 4, 43, 31, 1, 55, 40, 7, 27, 37, 30, 54, 1, 19, 42, 30, 56, 26, 62, 49, 24, 57, 37, 56, 2, 39, 16, 5, 30, 55, 3, 49, 60, 23, 56, 44, 17, 52, 13, 42, 28, 48, 18, 45, 9, 37, 21, 41, 58, 10, 48, 1, 63, 5, 41, 57, 2, 24, 12, 48, 27, 42, 32, 46, 13, 38, 19, 34, 5, 41, 25, 60 }, + { 39, 28, 21, 46, 32, 57, 36, 9, 19, 42, 4, 29, 11, 43, 30, 49, 13, 42, 35, 56, 9, 39, 15, 52, 36, 61, 18, 26, 45, 14, 31, 48, 21, 43, 14, 33, 49, 54, 14, 44, 21, 62, 13, 23, 8, 62, 15, 51, 44, 7, 30, 37, 20, 42, 56, 7, 39, 18, 50, 11, 61, 9, 19, 43, 57, 2, 48, 11, 39, 60, 28, 4, 37, 17, 35, 1, 33, 11, 31, 14, 48, 19, 35, 51, 46, 21, 44, 29, 12, 41, 2, 22, 58, 26, 54, 4, 59, 38, 2, 33, 57, 1, 63, 13, 28, 51, 15, 40, 18, 45, 8, 30, 43, 37, 54, 19, 8, 59, 21, 6, 60, 29, 55, 10, 63, 15, 47, 17 }, + { 3, 50, 10, 62, 18, 5, 27, 49, 60, 23, 55, 18, 62, 24, 56, 10, 59, 28, 2, 23, 34, 59, 43, 20, 10, 42, 8, 49, 1, 37, 57, 6, 51, 29, 53, 7, 23, 31, 5, 32, 51, 0, 35, 54, 45, 31, 5, 26, 36, 24, 55, 15, 48, 29, 14, 48, 26, 60, 21, 41, 36, 26, 50, 33, 14, 44, 17, 24, 52, 15, 46, 23, 54, 6, 47, 21, 60, 50, 4, 53, 29, 61, 8, 23, 1, 60, 19, 6, 53, 16, 47, 34, 6, 39, 16, 31, 12, 20, 53, 22, 30, 43, 25, 46, 35, 6, 44, 32, 53, 26, 55, 19, 11, 59, 5, 33, 51, 1, 35, 53, 25, 3, 42, 23, 44, 32, 7, 53 }, + { 22, 44, 37, 6, 26, 51, 38, 0, 34, 13, 31, 46, 3, 37, 6, 19, 40, 21, 47, 63, 12, 5, 29, 55, 22, 58, 34, 28, 60, 22, 11, 41, 17, 38, 9, 44, 59, 39, 56, 19, 11, 47, 25, 15, 3, 39, 57, 17, 61, 11, 46, 3, 58, 9, 54, 35, 2, 34, 8, 45, 15, 56, 5, 23, 53, 33, 63, 35, 4, 59, 10, 51, 13, 61, 29, 41, 15, 25, 43, 19, 40, 10, 54, 33, 41, 12, 38, 51, 31, 26, 61, 9, 30, 45, 24, 62, 49, 40, 10, 61, 14, 49, 5, 17, 54, 20, 60, 23, 3, 13, 35, 50, 32, 23, 46, 27, 38, 63, 16, 12, 39, 48, 18, 51, 1, 27, 56, 35 }, + { 63, 15, 30, 55, 43, 14, 57, 17, 53, 44, 7, 48, 26, 50, 32, 60, 0, 53, 14, 31, 50, 24, 46, 0, 38, 13, 4, 52, 16, 45, 30, 59, 0, 25, 55, 35, 16, 10, 26, 42, 58, 29, 60, 38, 50, 22, 28, 47, 0, 50, 28, 19, 33, 39, 11, 44, 16, 52, 24, 59, 3, 38, 27, 51, 0, 21, 7, 42, 26, 34, 21, 40, 33, 18, 39, 3, 54, 38, 8, 59, 0, 44, 27, 15, 58, 28, 57, 9, 43, 0, 36, 50, 20, 59, 8, 34, 0, 27, 47, 7, 36, 19, 56, 32, 0, 38, 11, 29, 62, 47, 6, 61, 0, 41, 14, 56, 10, 23, 45, 31, 57, 8, 36, 13, 58, 38, 11, 19 }, + { 0, 34, 12, 47, 21, 2, 40, 30, 11, 25, 61, 20, 40, 15, 35, 22, 45, 36, 7, 41, 17, 57, 9, 48, 32, 62, 44, 24, 35, 3, 54, 13, 33, 63, 19, 4, 48, 22, 62, 2, 37, 8, 33, 6, 20, 52, 9, 32, 43, 13, 39, 63, 25, 4, 49, 23, 62, 32, 9, 30, 48, 18, 63, 12, 46, 29, 58, 13, 48, 8, 57, 31, 0, 51, 9, 58, 12, 22, 47, 29, 35, 22, 49, 5, 46, 4, 34, 20, 63, 24, 56, 11, 41, 3, 51, 19, 56, 35, 17, 58, 28, 42, 9, 45, 59, 26, 51, 42, 17, 36, 25, 15, 53, 21, 44, 3, 30, 55, 5, 50, 21, 28, 61, 32, 6, 49, 28, 46 }, + { 58, 42, 60, 4, 31, 59, 22, 63, 35, 38, 9, 54, 1, 57, 8, 51, 16, 58, 27, 53, 3, 38, 30, 15, 27, 6, 19, 56, 10, 50, 21, 36, 47, 5, 43, 28, 51, 32, 13, 46, 18, 54, 16, 43, 63, 12, 36, 59, 22, 34, 5, 52, 17, 59, 27, 41, 0, 19, 55, 37, 13, 43, 6, 34, 41, 10, 36, 55, 19, 44, 3, 16, 58, 27, 49, 25, 32, 62, 17, 55, 13, 63, 18, 52, 25, 37, 17, 48, 13, 32, 5, 46, 28, 37, 14, 43, 25, 5, 51, 39, 3, 52, 33, 22, 8, 40, 12, 4, 57, 9, 46, 39, 28, 58, 13, 62, 17, 42, 19, 36, 0, 47, 16, 43, 24, 21, 54, 13 }, + { 25, 9, 23, 50, 36, 8, 45, 14, 3, 51, 16, 28, 44, 12, 42, 29, 4, 26, 10, 47, 22, 61, 18, 54, 51, 39, 46, 13, 41, 26, 58, 7, 18, 39, 12, 57, 15, 1, 52, 27, 41, 23, 48, 1, 27, 45, 18, 2, 57, 26, 55, 8, 43, 31, 6, 58, 14, 51, 40, 5, 61, 31, 24, 54, 17, 60, 22, 1, 39, 30, 53, 45, 36, 13, 43, 5, 45, 2, 37, 6, 34, 42, 2, 39, 10, 62, 7, 54, 40, 18, 60, 15, 52, 21, 63, 8, 55, 46, 15, 30, 23, 13, 62, 16, 50, 24, 58, 31, 48, 21, 34, 2, 49, 7, 31, 37, 26, 48, 9, 61, 40, 11, 52, 2, 60, 40, 4, 37 }, + { 52, 28, 39, 16, 54, 19, 29, 55, 42, 20, 58, 33, 24, 63, 18, 55, 39, 62, 43, 34, 12, 40, 6, 35, 2, 25, 8, 62, 34, 1, 31, 42, 61, 27, 53, 24, 40, 61, 34, 8, 59, 4, 30, 56, 40, 6, 53, 42, 10, 48, 16, 37, 12, 46, 21, 36, 47, 11, 28, 45, 22, 10, 57, 2, 49, 31, 14, 44, 61, 11, 25, 6, 23, 63, 18, 36, 28, 56, 20, 51, 11, 48, 27, 56, 32, 22, 45, 30, 2, 42, 27, 39, 1, 44, 23, 31, 38, 22, 11, 61, 43, 54, 4, 47, 35, 2, 44, 16, 28, 54, 12, 62, 18, 43, 10, 52, 1, 58, 33, 15, 29, 56, 20, 34, 9, 30, 48, 17 }, + { 46, 2, 56, 11, 41, 1, 49, 6, 27, 47, 2, 48, 5, 32, 37, 3, 13, 19, 32, 1, 55, 28, 60, 17, 43, 59, 32, 20, 49, 16, 55, 23, 14, 46, 2, 36, 6, 30, 20, 49, 12, 47, 35, 14, 21, 60, 29, 14, 35, 24, 46, 1, 56, 29, 53, 8, 33, 23, 56, 1, 35, 46, 20, 39, 26, 4, 53, 28, 17, 38, 60, 34, 48, 9, 55, 15, 46, 7, 41, 31, 60, 24, 16, 36, 1, 59, 19, 52, 35, 6, 55, 11, 59, 33, 7, 57, 4, 29, 48, 1, 19, 26, 37, 30, 18, 63, 37, 6, 59, 1, 40, 24, 56, 33, 46, 22, 35, 7, 24, 53, 39, 5, 26, 45, 55, 18, 62, 7 }, + { 20, 60, 29, 34, 20, 62, 33, 52, 10, 36, 13, 60, 41, 21, 50, 27, 56, 49, 8, 51, 21, 45, 11, 48, 8, 23, 53, 3, 29, 44, 5, 52, 9, 32, 50, 17, 43, 56, 3, 38, 24, 10, 62, 25, 51, 9, 33, 49, 61, 7, 30, 62, 22, 19, 2, 42, 63, 5, 49, 18, 60, 15, 52, 7, 43, 56, 23, 50, 5, 50, 2, 20, 41, 30, 1, 52, 22, 61, 14, 26, 3, 43, 53, 7, 47, 28, 11, 14, 23, 58, 33, 25, 47, 13, 50, 17, 40, 54, 34, 60, 41, 6, 59, 14, 50, 7, 25, 55, 20, 42, 51, 8, 27, 4, 16, 60, 28, 50, 44, 3, 22, 49, 63, 12, 33, 1, 43, 31 }, + { 36, 5, 46, 8, 44, 24, 13, 39, 25, 57, 31, 18, 8, 52, 10, 45, 6, 30, 36, 24, 63, 4, 33, 26, 57, 40, 15, 56, 37, 12, 40, 25, 37, 58, 11, 63, 21, 45, 16, 60, 31, 53, 18, 33, 3, 45, 23, 0, 20, 54, 40, 15, 50, 38, 60, 16, 25, 42, 29, 38, 7, 41, 25, 62, 18, 33, 8, 35, 42, 16, 32, 56, 12, 39, 59, 19, 34, 9, 49, 38, 57, 12, 21, 50, 14, 40, 61, 44, 50, 9, 49, 19, 3, 29, 35, 62, 12, 24, 7, 18, 52, 32, 10, 46, 21, 41, 32, 11, 36, 29, 14, 34, 60, 38, 54, 11, 41, 14, 19, 57, 32, 16, 7, 41, 51, 25, 14, 57 }, + { 53, 18, 26, 50, 15, 58, 4, 63, 17, 43, 7, 40, 61, 35, 15, 41, 23, 60, 16, 38, 14, 42, 19, 50, 0, 31, 10, 46, 27, 63, 18, 60, 0, 20, 29, 39, 8, 26, 37, 5, 42, 0, 44, 39, 57, 17, 58, 41, 28, 37, 4, 32, 9, 44, 12, 31, 54, 10, 59, 14, 27, 53, 12, 36, 0, 47, 13, 63, 21, 58, 10, 24, 50, 27, 4, 26, 44, 53, 31, 0, 18, 42, 29, 33, 57, 4, 32, 26, 0, 38, 16, 61, 41, 53, 20, 0, 42, 44, 49, 27, 10, 56, 39, 0, 57, 15, 53, 49, 3, 61, 22, 47, 17, 5, 49, 26, 2, 63, 39, 10, 47, 27, 37, 23, 4, 59, 38, 10 }, + { 23, 39, 61, 3, 37, 28, 48, 31, 0, 34, 51, 23, 2, 26, 58, 0, 53, 11, 46, 1, 57, 29, 52, 14, 37, 61, 21, 35, 2, 49, 7, 34, 47, 55, 4, 33, 54, 13, 58, 52, 19, 50, 22, 7, 13, 29, 36, 11, 51, 17, 60, 25, 55, 4, 34, 51, 0, 35, 20, 48, 32, 3, 51, 30, 59, 28, 40, 3, 46, 29, 54, 43, 7, 62, 47, 11, 39, 4, 23, 46, 55, 8, 63, 5, 25, 37, 18, 46, 21, 56, 31, 5, 36, 8, 45, 58, 26, 15, 2, 36, 47, 21, 29, 44, 25, 34, 3, 27, 43, 10, 52, 0, 45, 30, 24, 36, 43, 18, 34, 59, 0, 52, 61, 15, 44, 19, 30, 49 }, + { 0, 27, 12, 43, 54, 9, 22, 53, 21, 46, 15, 55, 29, 47, 20, 33, 39, 28, 59, 35, 9, 44, 5, 24, 47, 7, 52, 17, 56, 22, 30, 42, 14, 26, 45, 18, 49, 1, 24, 34, 11, 27, 55, 32, 61, 47, 2, 56, 6, 44, 13, 47, 36, 27, 58, 22, 16, 47, 40, 4, 57, 38, 21, 45, 16, 9, 56, 26, 11, 38, 0, 22, 36, 17, 33, 57, 16, 30, 62, 15, 35, 40, 20, 45, 59, 10, 54, 8, 63, 13, 52, 27, 22, 57, 28, 12, 32, 51, 55, 22, 63, 4, 16, 54, 12, 62, 45, 19, 58, 13, 32, 40, 20, 56, 7, 57, 9, 54, 6, 29, 42, 21, 8, 55, 35, 47, 6, 41 }, + { 56, 33, 58, 32, 19, 35, 42, 6, 59, 11, 38, 5, 49, 12, 62, 7, 52, 17, 5, 25, 54, 20, 61, 31, 54, 27, 41, 11, 44, 5, 59, 12, 36, 51, 10, 61, 28, 41, 48, 9, 43, 63, 5, 40, 20, 8, 49, 26, 34, 21, 58, 1, 18, 45, 7, 39, 61, 26, 8, 50, 23, 10, 63, 5, 55, 37, 19, 49, 52, 15, 59, 47, 13, 54, 1, 25, 42, 58, 10, 48, 3, 27, 50, 1, 17, 48, 34, 41, 16, 40, 2, 45, 10, 39, 17, 61, 5, 38, 19, 9, 41, 31, 60, 38, 5, 23, 36, 8, 30, 55, 24, 63, 12, 48, 14, 51, 31, 20, 45, 25, 12, 50, 32, 2, 28, 11, 62, 14 }, + { 44, 16, 7, 48, 1, 62, 16, 50, 27, 33, 61, 25, 17, 44, 31, 14, 22, 43, 32, 48, 18, 40, 8, 36, 3, 16, 33, 62, 23, 38, 25, 53, 2, 21, 41, 6, 22, 15, 59, 29, 16, 37, 26, 15, 52, 42, 23, 15, 54, 39, 10, 30, 53, 11, 49, 24, 2, 43, 55, 17, 34, 44, 15, 31, 24, 44, 2, 32, 7, 35, 25, 5, 40, 45, 29, 51, 6, 21, 37, 52, 24, 60, 13, 31, 53, 23, 2, 28, 49, 24, 31, 60, 20, 51, 1, 34, 48, 14, 59, 33, 50, 1, 18, 33, 48, 60, 17, 51, 39, 6, 38, 2, 35, 29, 40, 23, 1, 62, 15, 53, 37, 17, 46, 57, 40, 51, 24, 22 }, + { 5, 37, 52, 24, 45, 13, 40, 3, 45, 9, 19, 42, 56, 4, 37, 46, 56, 2, 63, 11, 51, 1, 49, 13, 59, 45, 39, 1, 48, 15, 58, 9, 46, 31, 54, 35, 57, 38, 3, 46, 56, 4, 47, 57, 1, 30, 38, 63, 3, 46, 28, 63, 41, 14, 33, 62, 19, 32, 13, 28, 61, 1, 53, 42, 11, 60, 22, 62, 27, 42, 61, 31, 19, 8, 61, 12, 32, 55, 2, 18, 33, 12, 43, 36, 9, 62, 30, 55, 6, 58, 35, 7, 43, 29, 54, 23, 43, 30, 3, 25, 11, 45, 52, 28, 7, 14, 42, 1, 22, 50, 16, 53, 19, 59, 4, 46, 33, 41, 4, 35, 58, 5, 26, 13, 20, 2, 34, 54 }, + { 30, 63, 21, 10, 26, 55, 29, 59, 23, 39, 53, 1, 36, 24, 59, 27, 10, 34, 23, 38, 30, 60, 22, 42, 28, 19, 9, 57, 30, 19, 43, 33, 13, 63, 3, 19, 11, 50, 31, 20, 14, 34, 10, 35, 17, 59, 7, 31, 19, 25, 50, 5, 20, 57, 29, 6, 52, 41, 4, 46, 20, 37, 26, 17, 49, 6, 39, 18, 53, 14, 3, 49, 57, 23, 34, 48, 14, 41, 28, 38, 56, 6, 58, 25, 39, 19, 43, 15, 37, 11, 47, 18, 53, 4, 37, 9, 62, 21, 53, 40, 57, 24, 13, 40, 56, 26, 47, 31, 59, 25, 45, 27, 10, 43, 21, 61, 13, 27, 48, 9, 23, 43, 31, 62, 38, 59, 9, 47 }, + { 25, 4, 40, 60, 34, 6, 18, 36, 8, 57, 12, 30, 49, 14, 6, 54, 41, 16, 50, 6, 43, 15, 34, 4, 53, 24, 50, 35, 4, 51, 7, 55, 28, 24, 39, 44, 60, 7, 25, 62, 42, 53, 24, 61, 28, 45, 52, 12, 48, 37, 9, 35, 43, 3, 37, 48, 12, 58, 30, 52, 9, 59, 6, 57, 33, 29, 48, 4, 37, 45, 20, 34, 10, 39, 0, 60, 22, 45, 8, 63, 21, 42, 14, 49, 3, 56, 11, 46, 21, 61, 0, 42, 25, 13, 63, 17, 36, 8, 46, 16, 6, 35, 63, 0, 21, 37, 4, 57, 9, 34, 5, 61, 48, 32, 8, 37, 54, 17, 56, 30, 60, 0, 50, 16, 7, 29, 42, 17 }, + { 32, 50, 15, 48, 2, 43, 52, 25, 47, 16, 32, 63, 21, 52, 40, 19, 0, 61, 29, 58, 20, 56, 26, 46, 12, 55, 6, 22, 62, 32, 17, 40, 0, 49, 34, 8, 27, 32, 48, 0, 21, 39, 5, 44, 12, 6, 22, 40, 0, 57, 16, 60, 23, 17, 54, 22, 36, 15, 24, 39, 19, 34, 47, 23, 0, 54, 13, 51, 24, 9, 55, 16, 52, 27, 44, 20, 4, 54, 26, 49, 0, 30, 46, 16, 29, 51, 34, 4, 52, 28, 33, 15, 57, 39, 26, 49, 0, 56, 27, 31, 48, 20, 43, 29, 53, 11, 46, 19, 41, 13, 55, 18, 0, 57, 26, 51, 2, 44, 6, 38, 14, 40, 22, 45, 36, 53, 3, 57 }, + { 44, 12, 37, 28, 22, 57, 11, 38, 0, 51, 9, 41, 4, 29, 11, 47, 33, 45, 12, 26, 3, 36, 9, 63, 31, 16, 38, 44, 14, 47, 25, 61, 20, 58, 15, 47, 17, 57, 13, 36, 9, 51, 18, 29, 50, 36, 54, 20, 61, 27, 32, 13, 53, 44, 9, 27, 0, 63, 45, 2, 56, 10, 14, 43, 41, 28, 58, 11, 35, 60, 30, 41, 6, 63, 11, 51, 37, 32, 15, 10, 35, 53, 5, 61, 22, 7, 26, 59, 23, 9, 44, 48, 21, 3, 51, 32, 24, 41, 12, 61, 2, 55, 9, 15, 35, 58, 28, 15, 62, 30, 37, 23, 42, 29, 11, 17, 35, 24, 63, 20, 52, 28, 8, 55, 11, 23, 47, 19 }, + { 0, 56, 8, 53, 14, 31, 61, 20, 55, 28, 62, 18, 35, 60, 25, 57, 7, 23, 39, 54, 47, 17, 43, 0, 40, 59, 29, 2, 56, 10, 37, 5, 43, 11, 29, 52, 1, 23, 54, 41, 59, 30, 55, 1, 62, 15, 33, 4, 43, 10, 47, 39, 1, 31, 40, 60, 49, 33, 7, 55, 26, 50, 31, 61, 8, 18, 21, 32, 44, 1, 25, 47, 18, 36, 30, 23, 59, 7, 40, 59, 27, 19, 38, 32, 44, 54, 40, 17, 38, 60, 27, 6, 35, 55, 10, 14, 44, 5, 50, 17, 38, 26, 42, 50, 18, 3, 44, 52, 2, 49, 7, 52, 15, 46, 62, 39, 55, 10, 31, 48, 3, 58, 33, 18, 61, 34, 13, 59 }, + { 39, 27, 63, 20, 35, 41, 4, 45, 26, 5, 38, 13, 44, 2, 50, 17, 37, 52, 2, 13, 28, 58, 24, 51, 21, 8, 34, 48, 27, 42, 18, 51, 31, 56, 5, 36, 38, 44, 4, 17, 26, 11, 38, 23, 42, 8, 56, 39, 24, 51, 5, 56, 21, 59, 14, 6, 18, 42, 22, 35, 16, 37, 3, 25, 39, 46, 63, 5, 50, 17, 58, 8, 55, 3, 50, 12, 43, 17, 47, 2, 51, 9, 62, 12, 1, 35, 13, 50, 1, 37, 12, 51, 19, 29, 46, 59, 22, 58, 33, 45, 22, 60, 10, 32, 61, 39, 8, 33, 25, 36, 20, 60, 38, 4, 21, 5, 28, 45, 12, 18, 42, 11, 49, 1, 27, 40, 6, 30 }, + { 24, 16, 42, 1, 50, 10, 48, 17, 33, 43, 24, 48, 21, 55, 31, 42, 10, 21, 63, 35, 49, 6, 33, 13, 41, 53, 10, 20, 60, 6, 53, 26, 12, 41, 22, 60, 14, 28, 63, 33, 49, 3, 45, 16, 48, 26, 14, 46, 18, 30, 35, 26, 8, 50, 29, 51, 25, 57, 12, 47, 53, 9, 62, 20, 54, 2, 36, 15, 40, 28, 33, 13, 38, 24, 46, 1, 29, 56, 33, 20, 44, 24, 41, 26, 57, 20, 63, 8, 30, 55, 5, 41, 62, 8, 34, 2, 37, 10, 19, 6, 37, 1, 53, 23, 5, 27, 58, 22, 43, 12, 50, 26, 9, 34, 54, 32, 49, 1, 59, 37, 22, 46, 25, 36, 51, 15, 54, 46 }, + { 52, 7, 45, 33, 26, 58, 14, 60, 7, 54, 3, 58, 8, 34, 14, 5, 59, 30, 18, 44, 8, 22, 48, 62, 3, 26, 55, 38, 23, 16, 39, 1, 62, 24, 49, 9, 53, 19, 46, 7, 19, 60, 31, 58, 2, 34, 53, 7, 59, 2, 62, 42, 46, 19, 36, 11, 44, 4, 38, 28, 1, 43, 32, 51, 12, 29, 56, 22, 52, 2, 62, 49, 22, 60, 14, 35, 63, 5, 25, 57, 14, 53, 4, 46, 18, 31, 42, 22, 47, 20, 58, 31, 16, 43, 23, 54, 30, 42, 52, 57, 29, 49, 30, 13, 45, 48, 16, 55, 6, 63, 1, 44, 14, 58, 19, 47, 15, 24, 51, 34, 6, 55, 5, 63, 20, 41, 21, 9 }, + { 30, 62, 18, 55, 5, 23, 39, 29, 49, 30, 15, 36, 28, 46, 60, 25, 39, 46, 4, 32, 61, 40, 15, 30, 36, 45, 14, 2, 49, 33, 57, 45, 18, 32, 3, 45, 30, 2, 35, 52, 40, 27, 13, 21, 38, 63, 20, 28, 37, 23, 16, 10, 13, 55, 2, 62, 21, 32, 60, 17, 58, 23, 5, 40, 16, 48, 7, 45, 10, 26, 43, 19, 6, 31, 52, 21, 39, 16, 48, 9, 37, 28, 36, 55, 7, 48, 3, 59, 15, 45, 25, 1, 53, 13, 47, 7, 62, 15, 4, 25, 12, 41, 18, 60, 38, 11, 34, 19, 39, 31, 29, 56, 23, 42, 3, 27, 60, 41, 8, 16, 61, 29, 43, 9, 32, 2, 60, 34 }, + { 3, 38, 13, 37, 52, 44, 2, 19, 12, 42, 63, 19, 40, 1, 20, 50, 12, 55, 15, 56, 27, 1, 54, 11, 57, 18, 32, 63, 44, 4, 29, 13, 37, 61, 35, 16, 42, 57, 12, 22, 6, 55, 43, 10, 50, 5, 44, 11, 48, 52, 34, 58, 28, 41, 38, 30, 7, 52, 11, 49, 30, 14, 45, 27, 59, 34, 21, 38, 32, 58, 11, 36, 56, 42, 9, 41, 3, 54, 31, 42, 0, 60, 16, 11, 39, 24, 52, 33, 6, 36, 10, 40, 32, 60, 26, 20, 39, 28, 47, 34, 63, 8, 54, 3, 24, 56, 0, 51, 13, 47, 16, 40, 7, 35, 52, 11, 36, 4, 57, 30, 39, 13, 18, 50, 58, 28, 12, 48 }, + { 57, 24, 49, 21, 10, 31, 61, 36, 56, 0, 22, 53, 11, 56, 32, 7, 36, 27, 41, 9, 46, 19, 34, 42, 25, 7, 50, 9, 28, 21, 54, 8, 50, 7, 27, 59, 10, 25, 48, 62, 37, 0, 33, 58, 25, 18, 32, 61, 0, 15, 45, 5, 50, 3, 23, 55, 47, 17, 40, 6, 60, 34, 53, 8, 41, 0, 61, 13, 54, 4, 46, 28, 0, 17, 48, 27, 58, 13, 23, 61, 33, 21, 50, 30, 62, 8, 14, 29, 56, 27, 61, 49, 17, 2, 44, 11, 51, 0, 59, 17, 40, 20, 32, 47, 36, 21, 42, 28, 60, 4, 54, 10, 59, 17, 30, 62, 21, 43, 26, 48, 0, 56, 36, 25, 8, 44, 39, 17 }, + { 10, 42, 4, 59, 27, 47, 8, 23, 51, 32, 45, 6, 37, 26, 48, 43, 62, 0, 21, 53, 38, 12, 51, 5, 60, 47, 24, 37, 59, 15, 35, 47, 22, 55, 0, 50, 21, 40, 6, 29, 15, 52, 24, 8, 41, 55, 13, 29, 40, 56, 24, 31, 19, 33, 61, 15, 0, 35, 24, 42, 21, 2, 19, 57, 24, 15, 30, 50, 20, 25, 40, 16, 57, 34, 61, 8, 29, 45, 6, 49, 11, 47, 2, 44, 19, 57, 38, 50, 12, 42, 21, 4, 35, 52, 28, 56, 23, 36, 13, 45, 4, 52, 27, 14, 6, 62, 9, 45, 21, 37, 25, 46, 33, 49, 0, 44, 7, 53, 13, 19, 53, 31, 3, 47, 15, 56, 22, 51 }, + { 35, 28, 53, 32, 1, 16, 54, 40, 9, 17, 25, 58, 14, 59, 3, 22, 16, 51, 31, 5, 23, 58, 28, 17, 35, 20, 0, 42, 11, 52, 3, 31, 41, 17, 43, 13, 32, 54, 18, 60, 32, 45, 17, 49, 2, 36, 51, 22, 7, 36, 9, 63, 48, 12, 46, 26, 43, 28, 63, 13, 48, 37, 51, 33, 5, 47, 55, 9, 42, 63, 7, 51, 24, 12, 37, 19, 55, 34, 18, 38, 15, 28, 54, 34, 5, 43, 22, 0, 48, 14, 54, 24, 58, 9, 38, 5, 32, 55, 21, 30, 49, 9, 59, 43, 30, 51, 35, 26, 7, 53, 2, 22, 14, 27, 57, 18, 38, 24, 33, 45, 10, 41, 20, 60, 37, 5, 32, 0 }, + { 63, 19, 15, 40, 62, 35, 14, 28, 46, 61, 4, 49, 35, 10, 29, 54, 33, 8, 45, 62, 37, 1, 43, 55, 10, 52, 61, 30, 19, 40, 25, 62, 11, 38, 27, 58, 36, 3, 46, 8, 39, 4, 62, 28, 47, 20, 4, 54, 47, 27, 43, 1, 21, 38, 8, 58, 10, 54, 4, 56, 9, 26, 12, 39, 60, 27, 18, 37, 1, 31, 35, 5, 45, 50, 2, 43, 26, 1, 59, 23, 56, 40, 7, 26, 58, 17, 32, 63, 25, 39, 7, 31, 45, 19, 63, 15, 48, 8, 37, 61, 16, 34, 1, 56, 18, 3, 15, 58, 49, 32, 63, 41, 55, 5, 40, 22, 50, 6, 59, 2, 63, 23, 52, 11, 26, 61, 44, 23 }, + { 11, 56, 46, 6, 22, 43, 58, 3, 34, 21, 38, 30, 18, 44, 52, 13, 41, 57, 17, 28, 14, 49, 25, 7, 33, 39, 26, 6, 56, 48, 1, 20, 56, 5, 46, 9, 19, 51, 30, 25, 56, 21, 35, 14, 57, 42, 16, 33, 10, 57, 17, 59, 41, 25, 53, 37, 20, 40, 30, 18, 31, 62, 44, 22, 3, 44, 11, 48, 23, 53, 18, 60, 29, 22, 62, 15, 53, 47, 10, 41, 3, 19, 52, 36, 13, 46, 10, 35, 3, 61, 41, 16, 1, 50, 26, 42, 18, 46, 2, 25, 54, 20, 39, 23, 47, 31, 41, 12, 38, 17, 8, 19, 31, 48, 12, 61, 9, 54, 29, 35, 15, 38, 6, 43, 34, 14, 7, 47 }, + { 39, 2, 33, 26, 53, 8, 18, 50, 41, 12, 53, 1, 63, 24, 19, 39, 2, 24, 47, 10, 60, 38, 19, 63, 48, 4, 15, 45, 32, 14, 60, 36, 29, 53, 23, 63, 34, 12, 61, 1, 43, 11, 53, 30, 1, 26, 60, 45, 23, 39, 3, 29, 12, 50, 4, 16, 51, 3, 45, 36, 50, 1, 16, 54, 35, 14, 57, 30, 58, 9, 46, 14, 41, 10, 32, 38, 4, 30, 21, 51, 32, 63, 25, 1, 60, 27, 53, 18, 51, 22, 28, 55, 34, 12, 40, 3, 60, 29, 57, 41, 6, 44, 11, 53, 8, 61, 24, 57, 1, 28, 44, 59, 36, 3, 34, 25, 41, 31, 16, 44, 22, 47, 28, 58, 1, 49, 54, 29 }, + { 58, 25, 50, 13, 38, 30, 60, 24, 6, 57, 27, 42, 9, 45, 6, 61, 30, 50, 4, 34, 29, 3, 46, 13, 22, 42, 58, 28, 9, 39, 23, 44, 7, 15, 44, 2, 40, 15, 47, 41, 23, 37, 7, 59, 38, 11, 34, 6, 62, 14, 52, 35, 55, 19, 32, 61, 33, 24, 57, 6, 22, 59, 29, 7, 49, 25, 40, 3, 17, 39, 27, 52, 0, 55, 16, 57, 24, 61, 36, 6, 29, 12, 48, 39, 20, 44, 6, 40, 33, 5, 48, 10, 57, 36, 22, 51, 33, 9, 24, 12, 62, 29, 50, 35, 14, 43, 5, 33, 47, 52, 13, 23, 10, 51, 56, 16, 46, 1, 49, 4, 61, 9, 52, 18, 31, 21, 36, 17 }, + { 19, 42, 9, 48, 2, 44, 11, 37, 48, 20, 33, 16, 55, 35, 49, 15, 37, 20, 59, 16, 53, 22, 56, 31, 50, 11, 34, 54, 16, 51, 4, 49, 33, 53, 21, 28, 56, 24, 31, 9, 52, 16, 48, 24, 44, 13, 51, 20, 31, 49, 18, 6, 34, 2, 44, 14, 47, 8, 15, 43, 13, 41, 33, 52, 20, 61, 7, 51, 34, 62, 4, 20, 36, 33, 43, 8, 46, 13, 53, 17, 45, 42, 9, 31, 52, 11, 30, 56, 13, 59, 17, 44, 27, 6, 62, 11, 43, 17, 49, 38, 26, 2, 16, 27, 58, 21, 54, 18, 26, 5, 35, 61, 43, 27, 7, 39, 14, 58, 37, 55, 20, 33, 13, 40, 62, 10, 55, 5 }, + { 51, 14, 61, 29, 59, 20, 55, 31, 0, 49, 11, 60, 3, 26, 22, 56, 0, 40, 12, 43, 41, 8, 36, 0, 17, 57, 24, 2, 46, 26, 61, 18, 0, 38, 12, 59, 6, 49, 3, 57, 19, 63, 5, 33, 18, 54, 28, 56, 0, 43, 26, 46, 63, 27, 56, 22, 27, 54, 38, 28, 63, 24, 10, 45, 0, 31, 42, 21, 12, 25, 44, 49, 59, 6, 26, 50, 3, 34, 27, 59, 0, 35, 62, 16, 4, 58, 47, 0, 43, 24, 37, 2, 54, 20, 46, 31, 0, 56, 34, 5, 55, 45, 60, 37, 0, 40, 10, 38, 63, 46, 15, 20, 0, 53, 21, 62, 30, 11, 24, 27, 40, 0, 57, 26, 3, 45, 27, 35 }, +}; + +#else +#define DM_WIDTH 8 +#define DM_WIDTH_SHIFT 3 +#define DM_HEIGHT 8 +static const guchar DM[8][8] = +{ + { 0, 32, 8, 40, 2, 34, 10, 42 }, + { 48, 16, 56, 24, 50, 18, 58, 26 }, + { 12, 44, 4, 36, 14, 46, 6, 38 }, + { 60, 28, 52, 20, 62, 30, 54, 22 }, + { 3, 35, 11, 43, 1, 33, 9, 41 }, + { 51, 19, 59, 27, 49, 17, 57, 25 }, + { 15, 47, 7, 39, 13, 45, 5, 37 }, + { 63, 31, 55, 23, 61, 29, 53, 21 } +}; +#endif + +static guint32 *DM_565 = NULL; + +static void +gdk_rgb_preprocess_dm_565 (void) +{ + int i; + guint32 dith; + + if (DM_565 == NULL) + { + DM_565 = g_new (guint32, DM_WIDTH * DM_HEIGHT); + for (i = 0; i < DM_WIDTH * DM_HEIGHT; i++) + { + dith = DM[0][i] >> 3; + DM_565[i] = (dith << 20) | dith | (((7 - dith) >> 1) << 10); +#ifdef VERBOSE + g_print ("%i %x %x\n", i, dith, DM_565[i]); +#endif + } + } +} + +static void +gdk_rgb_convert_8_d666 (GdkImage *image, + gint x0, gint y0, gint width, gint height, + guchar *buf, int rowstride, + gint x_align, gint y_align, GdkRgbCmap *cmap) +{ + int x, y; + gint bpl; + guchar *obuf, *obptr; + guchar *bptr, *bp2; + gint r, g, b; + const guchar *dmp; + gint dith; + + bptr = buf; + bpl = image->bpl; + obuf = ((guchar *)image->mem) + y0 * bpl + x0; + for (y = 0; y < height; y++) + { + dmp = DM[(y_align + y) & (DM_HEIGHT - 1)]; + bp2 = bptr; + obptr = obuf; + for (x = 0; x < width; x++) + { + r = *bp2++; + g = *bp2++; + b = *bp2++; + dith = (dmp[(x_align + x) & (DM_WIDTH - 1)] << 2) | 7; + r = ((r * 5) + dith) >> 8; + g = ((g * 5) + (262 - dith)) >> 8; + b = ((b * 5) + dith) >> 8; + obptr[0] = colorcube_d[(r << 6) | (g << 3) | b]; + obptr++; + } + bptr += rowstride; + obuf += bpl; + } +} + +static void +gdk_rgb_convert_8_d (GdkImage *image, + gint x0, gint y0, gint width, gint height, + guchar *buf, int rowstride, + gint x_align, gint y_align, + GdkRgbCmap *cmap) +{ + int x, y; + gint bpl; + guchar *obuf, *obptr; + guchar *bptr, *bp2; + gint r, g, b; + const guchar *dmp; + gint dith; + gint rs, gs, bs; + + bptr = buf; + bpl = image->bpl; + rs = image_info->nred_shades - 1; + gs = image_info->ngreen_shades - 1; + bs = image_info->nblue_shades - 1; + obuf = ((guchar *)image->mem) + y0 * bpl + x0; + for (y = 0; y < height; y++) + { + dmp = DM[(y_align + y) & (DM_HEIGHT - 1)]; + bp2 = bptr; + obptr = obuf; + for (x = 0; x < width; x++) + { + r = *bp2++; + g = *bp2++; + b = *bp2++; + dith = (dmp[(x_align + x) & (DM_WIDTH - 1)] << 2) | 7; + r = ((r * rs) + dith) >> 8; + g = ((g * gs) + (262 - dith)) >> 8; + b = ((b * bs) + dith) >> 8; + obptr[0] = colorcube_d[(r << 6) | (g << 3) | b]; + obptr++; + } + bptr += rowstride; + obuf += bpl; + } +} + +static void +gdk_rgb_convert_8_indexed (GdkImage *image, + gint x0, gint y0, gint width, gint height, + guchar *buf, int rowstride, + gint x_align, gint y_align, GdkRgbCmap *cmap) +{ + int x, y; + gint bpl; + guchar *obuf, *obptr; + guchar *bptr, *bp2; + guchar c; + guchar *lut; + + lut = cmap->lut; + bptr = buf; + bpl = image->bpl; + obuf = ((guchar *)image->mem) + y0 * bpl + x0; + for (y = 0; y < height; y++) + { + bp2 = bptr; + obptr = obuf; + for (x = 0; x < width; x++) + { + c = *bp2++; + obptr[0] = lut[c]; + obptr++; + } + bptr += rowstride; + obuf += bpl; + } +} + +static void +gdk_rgb_convert_gray8 (GdkImage *image, + gint x0, gint y0, gint width, gint height, + guchar *buf, int rowstride, + gint x_align, gint y_align, GdkRgbCmap *cmap) +{ + int x, y; + gint bpl; + guchar *obuf, *obptr; + guchar *bptr, *bp2; + gint r, g, b; + + bptr = buf; + bpl = image->bpl; + obuf = ((guchar *)image->mem) + y0 * bpl + x0; + for (y = 0; y < height; y++) + { + bp2 = bptr; + obptr = obuf; + for (x = 0; x < width; x++) + { + r = *bp2++; + g = *bp2++; + b = *bp2++; + obptr[0] = (g + ((b + r) >> 1)) >> 1; + obptr++; + } + bptr += rowstride; + obuf += bpl; + } +} + +static void +gdk_rgb_convert_gray8_gray (GdkImage *image, + gint x0, gint y0, gint width, gint height, + guchar *buf, int rowstride, + gint x_align, gint y_align, GdkRgbCmap *cmap) +{ + int y; + gint bpl; + guchar *obuf; + guchar *bptr; + + bptr = buf; + bpl = image->bpl; + obuf = ((guchar *)image->mem) + y0 * bpl + x0; + for (y = 0; y < height; y++) + { + memcpy (obuf, bptr, width); + bptr += rowstride; + obuf += bpl; + } +} + +#if G_BYTE_ORDER == G_LITTLE_ENDIAN +#define HAIRY_CONVERT_565 +#endif + +#ifdef HAIRY_CONVERT_565 +/* Render a 24-bit RGB image in buf into the GdkImage, without dithering. + This assumes native byte ordering - what should really be done is to + check whether static_image->byte_order is consistent with the _ENDIAN + config flag, and if not, use a different function. + + This one is even faster than the one below - its inner loop loads 3 + words (i.e. 4 24-bit pixels), does a lot of shifting and masking, + then writes 2 words. */ +static void +gdk_rgb_convert_565 (GdkImage *image, + gint x0, gint y0, gint width, gint height, + guchar *buf, int rowstride, + gint x_align, gint y_align, GdkRgbCmap *cmap) +{ + int x, y; + guchar *obuf, *obptr; + gint bpl; + guchar *bptr, *bp2; + guchar r, g, b; + + bptr = buf; + bpl = image->bpl; + obuf = ((guchar *)image->mem) + y0 * bpl + x0 * 2; + for (y = 0; y < height; y++) + { + bp2 = bptr; + obptr = obuf; + if (((unsigned long)obuf | (unsigned long) bp2) & 3) + { + for (x = 0; x < width; x++) + { + r = *bp2++; + g = *bp2++; + b = *bp2++; + ((guint16 *)obptr)[0] = ((r & 0xf8) << 8) | + ((g & 0xfc) << 3) | + (b >> 3); + obptr += 2; + } + } + else + { + for (x = 0; x < width - 3; x += 4) + { + guint32 r1b0g0r0; + guint32 g2r2b1g1; + guint32 b3g3r3b2; + + r1b0g0r0 = ((guint32 *)bp2)[0]; + g2r2b1g1 = ((guint32 *)bp2)[1]; + b3g3r3b2 = ((guint32 *)bp2)[2]; + ((guint32 *)obptr)[0] = + ((r1b0g0r0 & 0xf8) << 8) | + ((r1b0g0r0 & 0xfc00) >> 5) | + ((r1b0g0r0 & 0xf80000) >> 19) | + (r1b0g0r0 & 0xf8000000) | + ((g2r2b1g1 & 0xfc) << 19) | + ((g2r2b1g1 & 0xf800) << 5); + ((guint32 *)obptr)[1] = + ((g2r2b1g1 & 0xf80000) >> 8) | + ((g2r2b1g1 & 0xfc000000) >> 21) | + ((b3g3r3b2 & 0xf8) >> 3) | + ((b3g3r3b2 & 0xf800) << 16) | + ((b3g3r3b2 & 0xfc0000) << 3) | + ((b3g3r3b2 & 0xf8000000) >> 11); + bp2 += 12; + obptr += 8; + } + for (; x < width; x++) + { + r = *bp2++; + g = *bp2++; + b = *bp2++; + ((guint16 *)obptr)[0] = ((r & 0xf8) << 8) | + ((g & 0xfc) << 3) | + (b >> 3); + obptr += 2; + } + } + bptr += rowstride; + obuf += bpl; + } +} +#else +/* Render a 24-bit RGB image in buf into the GdkImage, without dithering. + This assumes native byte ordering - what should really be done is to + check whether static_image->byte_order is consistent with the _ENDIAN + config flag, and if not, use a different function. + + This routine is faster than the one included with Gtk 1.0 for a number + of reasons: + + 1. Shifting instead of lookup tables (less memory traffic). + + 2. Much less register pressure, especially because shifts are + in the code. + + 3. A memcpy is avoided (i.e. the transfer function). + + 4. On big-endian architectures, byte swapping is avoided. + + That said, it wouldn't be hard to make it even faster - just make an + inner loop that reads 3 words (i.e. 4 24-bit pixels), does a lot of + shifting and masking, then writes 2 words. +*/ +static void +gdk_rgb_convert_565 (GdkImage *image, + gint x0, gint y0, gint width, gint height, + guchar *buf, int rowstride, + gint x_align, gint y_align, GdkRgbCmap *cmap) +{ + int x, y; + guchar *obuf; + gint bpl; + guchar *bptr, *bp2; + guchar r, g, b; + + bptr = buf; + bpl = image->bpl; + obuf = ((guchar *)image->mem) + y0 * bpl + x0 * 2; + for (y = 0; y < height; y++) + { + bp2 = bptr; + for (x = 0; x < width; x++) + { + r = *bp2++; + g = *bp2++; + b = *bp2++; + ((unsigned short *)obuf)[x] = ((r & 0xf8) << 8) | + ((g & 0xfc) << 3) | + (b >> 3); + } + bptr += rowstride; + obuf += bpl; + } +} +#endif + +#ifdef HAIRY_CONVERT_565 +static void +gdk_rgb_convert_565_gray (GdkImage *image, + gint x0, gint y0, gint width, gint height, + guchar *buf, int rowstride, + gint x_align, gint y_align, GdkRgbCmap *cmap) +{ + int x, y; + guchar *obuf, *obptr; + gint bpl; + guchar *bptr, *bp2; + guchar g; + + bptr = buf; + bpl = image->bpl; + obuf = ((guchar *)image->mem) + y0 * bpl + x0 * 2; + for (y = 0; y < height; y++) + { + bp2 = bptr; + obptr = obuf; + if (((unsigned long)obuf | (unsigned long) bp2) & 3) + { + for (x = 0; x < width; x++) + { + g = *bp2++; + ((guint16 *)obptr)[0] = ((g & 0xf8) << 8) | + ((g & 0xfc) << 3) | + (g >> 3); + obptr += 2; + } + } + else + { + for (x = 0; x < width - 3; x += 4) + { + guint32 g3g2g1g0; + + g3g2g1g0 = ((guint32 *)bp2)[0]; + ((guint32 *)obptr)[0] = + ((g3g2g1g0 & 0xf8) << 8) | + ((g3g2g1g0 & 0xfc) << 3) | + ((g3g2g1g0 & 0xf8) >> 3) | + (g3g2g1g0 & 0xf800) << 16 | + ((g3g2g1g0 & 0xfc00) << 11) | + ((g3g2g1g0 & 0xf800) << 5); + ((guint32 *)obptr)[1] = + ((g3g2g1g0 & 0xf80000) >> 8) | + ((g3g2g1g0 & 0xfc0000) >> 13) | + ((g3g2g1g0 & 0xf80000) >> 19) | + (g3g2g1g0 & 0xf8000000) | + ((g3g2g1g0 & 0xfc000000) >> 5) | + ((g3g2g1g0 & 0xf8000000) >> 11); + bp2 += 4; + obptr += 8; + } + for (; x < width; x++) + { + g = *bp2++; + ((guint16 *)obptr)[0] = ((g & 0xf8) << 8) | + ((g & 0xfc) << 3) | + (g >> 3); + obptr += 2; + } + } + bptr += rowstride; + obuf += bpl; + } +} +#else +static void +gdk_rgb_convert_565_gray (GdkImage *image, + gint x0, gint y0, gint width, gint height, + guchar *buf, int rowstride, + gint x_align, gint y_align, GdkRgbCmap *cmap) +{ + int x, y; + guchar *obuf; + gint bpl; + guchar *bptr, *bp2; + guchar g; + + bptr = buf; + bpl = image->bpl; + obuf = ((guchar *)image->mem) + y0 * bpl + x0 * 2; + for (y = 0; y < height; y++) + { + bp2 = bptr; + for (x = 0; x < width; x++) + { + g = *bp2++; + ((guint16 *)obuf)[x] = ((g & 0xf8) << 8) | + ((g & 0xfc) << 3) | + (g >> 3); + } + bptr += rowstride; + obuf += bpl; + } +} +#endif + +static void +gdk_rgb_convert_565_br (GdkImage *image, + gint x0, gint y0, gint width, gint height, + guchar *buf, int rowstride, + gint x_align, gint y_align, GdkRgbCmap *cmap) +{ + int x, y; + guchar *obuf; + gint bpl; + guchar *bptr, *bp2; + guchar r, g, b; + + bptr = buf; + bpl = image->bpl; + obuf = ((guchar *)image->mem) + y0 * bpl + x0 * 2; + for (y = 0; y < height; y++) + { + bp2 = bptr; + for (x = 0; x < width; x++) + { + r = *bp2++; + g = *bp2++; + b = *bp2++; + /* final word is: + g4 g3 g2 b7 b6 b5 b4 b3 r7 r6 r5 r4 r3 g7 g6 g5 + */ + ((unsigned short *)obuf)[x] = (r & 0xf8) | + ((g & 0xe0) >> 5) | + ((g & 0x1c) << 11) | + ((b & 0xf8) << 5); + } + bptr += rowstride; + obuf += bpl; + } +} + +/* Thanks to Ray Lehtiniemi for a patch that resulted in a ~25% speedup + in this mode. */ +#ifdef HAIRY_CONVERT_565 +static void +gdk_rgb_convert_565_d (GdkImage *image, + gint x0, gint y0, gint width, gint height, + guchar *buf, int rowstride, + gint x_align, gint y_align, GdkRgbCmap *cmap) +{ + /* Now this is what I'd call some highly tuned code! */ + int x, y; + guchar *obuf, *obptr; + gint bpl; + guchar *bptr, *bp2; + + width += x_align; + height += y_align; + + bptr = buf; + bpl = image->bpl; + obuf = ((guchar *)image->mem) + y0 * bpl + x0 * 2; + for (y = y_align; y < height; y++) + { + guint32 *dmp = DM_565 + ((y & (DM_HEIGHT - 1)) << DM_WIDTH_SHIFT); + bp2 = bptr; + obptr = obuf; + if (((unsigned long)obuf | (unsigned long) bp2) & 3) + { + for (x = x_align; x < width; x++) + { + gint32 rgb = *bp2++ << 20; + rgb += *bp2++ << 10; + rgb += *bp2++; + rgb += dmp[x & (DM_WIDTH - 1)]; + rgb += 0x10040100 + - ((rgb & 0x1e0001e0) >> 5) + - ((rgb & 0x00070000) >> 6); + + ((unsigned short *)obptr)[0] = + ((rgb & 0x0f800000) >> 12) | + ((rgb & 0x0003f000) >> 7) | + ((rgb & 0x000000f8) >> 3); + obptr += 2; + } + } + else + { + for (x = x_align; x < width - 3; x += 4) + { + guint32 r1b0g0r0; + guint32 g2r2b1g1; + guint32 b3g3r3b2; + guint32 rgb02, rgb13; + + r1b0g0r0 = ((guint32 *)bp2)[0]; + g2r2b1g1 = ((guint32 *)bp2)[1]; + b3g3r3b2 = ((guint32 *)bp2)[2]; + rgb02 = + ((r1b0g0r0 & 0xff) << 20) + + ((r1b0g0r0 & 0xff00) << 2) + + ((r1b0g0r0 & 0xff0000) >> 16) + + dmp[x & (DM_WIDTH - 1)]; + rgb02 += 0x10040100 + - ((rgb02 & 0x1e0001e0) >> 5) + - ((rgb02 & 0x00070000) >> 6); + rgb13 = + ((r1b0g0r0 & 0xff000000) >> 4) + + ((g2r2b1g1 & 0xff) << 10) + + ((g2r2b1g1 & 0xff00) >> 8) + + dmp[(x + 1) & (DM_WIDTH - 1)]; + rgb13 += 0x10040100 + - ((rgb13 & 0x1e0001e0) >> 5) + - ((rgb13 & 0x00070000) >> 6); + ((guint32 *)obptr)[0] = + ((rgb02 & 0x0f800000) >> 12) | + ((rgb02 & 0x0003f000) >> 7) | + ((rgb02 & 0x000000f8) >> 3) | + ((rgb13 & 0x0f800000) << 4) | + ((rgb13 & 0x0003f000) << 9) | + ((rgb13 & 0x000000f8) << 13); + rgb02 = + ((g2r2b1g1 & 0xff0000) << 4) + + ((g2r2b1g1 & 0xff000000) >> 14) + + (b3g3r3b2 & 0xff) + + dmp[(x + 2) & (DM_WIDTH - 1)]; + rgb02 += 0x10040100 + - ((rgb02 & 0x1e0001e0) >> 5) + - ((rgb02 & 0x00070000) >> 6); + rgb13 = + ((b3g3r3b2 & 0xff00) << 12) + + ((b3g3r3b2 & 0xff0000) >> 6) + + ((b3g3r3b2 & 0xff000000) >> 24) + + dmp[(x + 3) & (DM_WIDTH - 1)]; + rgb13 += 0x10040100 + - ((rgb13 & 0x1e0001e0) >> 5) + - ((rgb13 & 0x00070000) >> 6); + ((guint32 *)obptr)[1] = + ((rgb02 & 0x0f800000) >> 12) | + ((rgb02 & 0x0003f000) >> 7) | + ((rgb02 & 0x000000f8) >> 3) | + ((rgb13 & 0x0f800000) << 4) | + ((rgb13 & 0x0003f000) << 9) | + ((rgb13 & 0x000000f8) << 13); + bp2 += 12; + obptr += 8; + } + for (; x < width; x++) + { + gint32 rgb = *bp2++ << 20; + rgb += *bp2++ << 10; + rgb += *bp2++; + rgb += dmp[x & (DM_WIDTH - 1)]; + rgb += 0x10040100 + - ((rgb & 0x1e0001e0) >> 5) + - ((rgb & 0x00070000) >> 6); + + ((unsigned short *)obptr)[0] = + ((rgb & 0x0f800000) >> 12) | + ((rgb & 0x0003f000) >> 7) | + ((rgb & 0x000000f8) >> 3); + obptr += 2; + } + } + bptr += rowstride; + obuf += bpl; + } +} +#else +static void +gdk_rgb_convert_565_d (GdkImage *image, + gint x0, gint y0, gint width, gint height, + guchar *buf, int rowstride, + gint x_align, gint y_align, GdkRgbCmap *cmap) +{ + int x, y; + guchar *obuf; + gint bpl; + guchar *bptr; + + width += x_align; + height += y_align; + + bptr = buf; + bpl = image->bpl; + obuf = ((guchar *)image->mem) + y0 * bpl + (x0 - x_align) * 2; + + for (y = y_align; y < height; y++) + { + guint32 *dmp = DM_565 + ((y & (DM_HEIGHT - 1)) << DM_WIDTH_SHIFT); + guchar *bp2 = bptr; + + for (x = x_align; x < width; x++) + { + gint32 rgb = *bp2++ << 20; + rgb += *bp2++ << 10; + rgb += *bp2++; + rgb += dmp[x & (DM_WIDTH - 1)]; + rgb += 0x10040100 + - ((rgb & 0x1e0001e0) >> 5) + - ((rgb & 0x00070000) >> 6); + + ((unsigned short *)obuf)[x] = + ((rgb & 0x0f800000) >> 12) | + ((rgb & 0x0003f000) >> 7) | + ((rgb & 0x000000f8) >> 3); + } + + bptr += rowstride; + obuf += bpl; + } +} +#endif + +static void +gdk_rgb_convert_555 (GdkImage *image, + gint x0, gint y0, gint width, gint height, + guchar *buf, int rowstride, + gint x_align, gint y_align, GdkRgbCmap *cmap) +{ + int x, y; + guchar *obuf; + gint bpl; + guchar *bptr, *bp2; + guchar r, g, b; + + bptr = buf; + bpl = image->bpl; + obuf = ((guchar *)image->mem) + y0 * bpl + x0 * 2; + for (y = 0; y < height; y++) + { + bp2 = bptr; + for (x = 0; x < width; x++) + { + r = *bp2++; + g = *bp2++; + b = *bp2++; + ((unsigned short *)obuf)[x] = ((r & 0xf8) << 7) | + ((g & 0xf8) << 2) | + (b >> 3); + } + bptr += rowstride; + obuf += bpl; + } +} + +static void +gdk_rgb_convert_555_br (GdkImage *image, + gint x0, gint y0, gint width, gint height, + guchar *buf, int rowstride, + gint x_align, gint y_align, GdkRgbCmap *cmap) +{ + int x, y; + guchar *obuf; + gint bpl; + guchar *bptr, *bp2; + guchar r, g, b; + + bptr = buf; + bpl = image->bpl; + obuf = ((guchar *)image->mem) + y0 * bpl + x0 * 2; + for (y = 0; y < height; y++) + { + bp2 = bptr; + for (x = 0; x < width; x++) + { + r = *bp2++; + g = *bp2++; + b = *bp2++; + /* final word is: + g5 g4 g3 b7 b6 b5 b4 b3 0 r7 r6 r5 r4 r3 g7 g6 + */ + ((unsigned short *)obuf)[x] = ((r & 0xf8) >> 1) | + ((g & 0xc0) >> 6) | + ((g & 0x18) << 10) | + ((b & 0xf8) << 5); + } + bptr += rowstride; + obuf += bpl; + } +} + +static void +gdk_rgb_convert_888_msb (GdkImage *image, + gint x0, gint y0, gint width, gint height, + guchar *buf, int rowstride, + gint x_align, gint y_align, GdkRgbCmap *cmap) +{ + int y; + guchar *obuf; + gint bpl; + guchar *bptr; + + bptr = buf; + bpl = image->bpl; + obuf = ((guchar *)image->mem) + y0 * bpl + x0 * 3; + for (y = 0; y < height; y++) + { + memcpy (obuf, bptr, width + width + width); + bptr += rowstride; + obuf += bpl; + } +} + +/* todo: optimize this */ +#if G_BYTE_ORDER == G_LITTLE_ENDIAN +#define HAIRY_CONVERT_888 +#endif + +#ifdef HAIRY_CONVERT_888 +static void +gdk_rgb_convert_888_lsb (GdkImage *image, + gint x0, gint y0, gint width, gint height, + guchar *buf, int rowstride, + gint x_align, gint y_align, GdkRgbCmap *cmap) +{ + int x, y; + guchar *obuf, *obptr; + gint bpl; + guchar *bptr, *bp2; + int r, g, b; + + bptr = buf; + bpl = image->bpl; + obuf = ((guchar *)image->mem) + y0 * bpl + x0 * 3; + for (y = 0; y < height; y++) + { + bp2 = bptr; + obptr = obuf; + if (((unsigned long)obuf | (unsigned long) bp2) & 3) + { + for (x = 0; x < width; x++) + { + r = bp2[0]; + g = bp2[1]; + b = bp2[2]; + *obptr++ = b; + *obptr++ = g; + *obptr++ = r; + bp2 += 3; + } + } + else + { + for (x = 0; x < width - 3; x += 4) + { + guint32 r1b0g0r0; + guint32 g2r2b1g1; + guint32 b3g3r3b2; + + r1b0g0r0 = ((guint32 *)bp2)[0]; + g2r2b1g1 = ((guint32 *)bp2)[1]; + b3g3r3b2 = ((guint32 *)bp2)[2]; + ((guint32 *)obptr)[0] = + (r1b0g0r0 & 0xff00) | + ((r1b0g0r0 & 0xff0000) >> 16) | + (((g2r2b1g1 & 0xff00) | (r1b0g0r0 & 0xff)) << 16); + ((guint32 *)obptr)[1] = + (g2r2b1g1 & 0xff0000ff) | + ((r1b0g0r0 & 0xff000000) >> 16) | + ((b3g3r3b2 & 0xff) << 16); + ((guint32 *)obptr)[2] = + (((g2r2b1g1 & 0xff0000) | (b3g3r3b2 & 0xff000000)) >> 16) | + ((b3g3r3b2 & 0xff00) << 16) | + ((b3g3r3b2 & 0xff0000)); + bp2 += 12; + obptr += 12; + } + for (; x < width; x++) + { + r = bp2[0]; + g = bp2[1]; + b = bp2[2]; + *obptr++ = b; + *obptr++ = g; + *obptr++ = r; + bp2 += 3; + } + } + bptr += rowstride; + obuf += bpl; + } +} +#else +static void +gdk_rgb_convert_888_lsb (GdkImage *image, + gint x0, gint y0, gint width, gint height, + guchar *buf, int rowstride, + gint x_align, gint y_align, GdkRgbCmap *cmap) +{ + int x, y; + guchar *obuf; + gint bpl; + guchar *bptr, *bp2; + int r, g, b; + + bptr = buf; + bpl = image->bpl; + obuf = ((guchar *)image->mem) + y0 * bpl + x0 * 3; + for (y = 0; y < height; y++) + { + bp2 = bptr; + for (x = 0; x < width; x++) + { + r = bp2[0]; + g = bp2[1]; + b = bp2[2]; + obuf[x * 3] = b; + obuf[x * 3 + 1] = g; + obuf[x * 3 + 2] = r; + bp2 += 3; + } + bptr += rowstride; + obuf += bpl; + } +} +#endif + +/* convert 24-bit packed to 32-bit unpacked */ +/* todo: optimize this */ +static void +gdk_rgb_convert_0888 (GdkImage *image, + gint x0, gint y0, gint width, gint height, + guchar *buf, int rowstride, + gint x_align, gint y_align, GdkRgbCmap *cmap) +{ + int x, y; + guchar *obuf; + gint bpl; + guchar *bptr, *bp2; + int r, g, b; + + bptr = buf; + bpl = image->bpl; + obuf = ((guchar *)image->mem) + y0 * bpl + x0 * 4; + for (y = 0; y < height; y++) + { + bp2 = bptr; + for (x = 0; x < width; x++) + { + r = bp2[0]; + g = bp2[1]; + b = bp2[2]; + ((guint32 *)obuf)[x] = (r << 16) | (g << 8) | b; + bp2 += 3; + } + bptr += rowstride; + obuf += bpl; + } +} + +static void +gdk_rgb_convert_0888_br (GdkImage *image, + gint x0, gint y0, gint width, gint height, + guchar *buf, int rowstride, + gint x_align, gint y_align, GdkRgbCmap *cmap) +{ + int x, y; + guchar *obuf; + gint bpl; + guchar *bptr, *bp2; + int r, g, b; + + bptr = buf; + bpl = image->bpl; + obuf = ((guchar *)image->mem) + y0 * bpl + x0 * 4; + for (y = 0; y < height; y++) + { + bp2 = bptr; + for (x = 0; x < width; x++) + { + r = bp2[0]; + g = bp2[1]; + b = bp2[2]; + ((guint32 *)obuf)[x] = (b << 24) | (g << 16) | (r << 8); + bp2 += 3; + } + bptr += rowstride; + obuf += bpl; + } +} + +static void +gdk_rgb_convert_8880_br (GdkImage *image, + gint x0, gint y0, gint width, gint height, + guchar *buf, int rowstride, + gint x_align, gint y_align, GdkRgbCmap *cmap) +{ + int x, y; + guchar *obuf; + gint bpl; + guchar *bptr, *bp2; + int r, g, b; + + bptr = buf; + bpl = image->bpl; + obuf = ((guchar *)image->mem) + y0 * bpl + x0 * 4; + for (y = 0; y < height; y++) + { + bp2 = bptr; + for (x = 0; x < width; x++) + { + r = bp2[0]; + g = bp2[1]; + b = bp2[2]; + ((guint32 *)obuf)[x] = (b << 16) | (g << 8) | r; + bp2 += 3; + } + bptr += rowstride; + obuf += bpl; + } +} + +/* Generic truecolor/directcolor conversion function. Slow, but these + are oddball modes. */ +static void +gdk_rgb_convert_truecolor_lsb (GdkImage *image, + gint x0, gint y0, gint width, gint height, + guchar *buf, int rowstride, + gint x_align, gint y_align, + GdkRgbCmap *cmap) +{ + int x, y; + guchar *obuf, *obptr; + gint bpl; + guchar *bptr, *bp2; + gint r, g, b; + gint r_right, r_left; + gint g_right, g_left; + gint b_right, b_left; + gint bpp; + guint32 pixel; + gint i; + + r_right = 8 - image_info->visual->red_prec; + r_left = image_info->visual->red_shift; + g_right = 8 - image_info->visual->green_prec; + g_left = image_info->visual->green_shift; + b_right = 8 - image_info->visual->blue_prec; + b_left = image_info->visual->blue_shift; + bpp = image_info->bpp; + bptr = buf; + bpl = image->bpl; + obuf = ((guchar *)image->mem) + y0 * bpl + x0 * bpp; + for (y = 0; y < height; y++) + { + obptr = obuf; + bp2 = bptr; + for (x = 0; x < width; x++) + { + r = bp2[0]; + g = bp2[1]; + b = bp2[2]; + pixel = ((r >> r_right) << r_left) | + ((g >> g_right) << g_left) | + ((b >> b_right) << b_left); + for (i = 0; i < bpp; i++) + { + *obptr++ = pixel & 0xff; + pixel >>= 8; + } + bp2 += 3; + } + bptr += rowstride; + obuf += bpl; + } +} + +static void +gdk_rgb_convert_truecolor_lsb_d (GdkImage *image, + gint x0, gint y0, gint width, gint height, + guchar *buf, int rowstride, + gint x_align, gint y_align, + GdkRgbCmap *cmap) +{ + int x, y; + guchar *obuf, *obptr; + gint bpl; + guchar *bptr, *bp2; + gint r, g, b; + gint r_right, r_left, r_prec; + gint g_right, g_left, g_prec; + gint b_right, b_left, b_prec; + gint bpp; + guint32 pixel; + gint i; + gint dith; + gint r1, g1, b1; + const guchar *dmp; + + r_right = 8 - image_info->visual->red_prec; + r_left = image_info->visual->red_shift; + r_prec = image_info->visual->red_prec; + g_right = 8 - image_info->visual->green_prec; + g_left = image_info->visual->green_shift; + g_prec = image_info->visual->green_prec; + b_right = 8 - image_info->visual->blue_prec; + b_left = image_info->visual->blue_shift; + b_prec = image_info->visual->blue_prec; + bpp = image_info->bpp; + bptr = buf; + bpl = image->bpl; + obuf = ((guchar *)image->mem) + y0 * bpl + x0 * bpp; + for (y = 0; y < height; y++) + { + dmp = DM[(y_align + y) & (DM_HEIGHT - 1)]; + obptr = obuf; + bp2 = bptr; + for (x = 0; x < width; x++) + { + r = bp2[0]; + g = bp2[1]; + b = bp2[2]; + dith = dmp[(x_align + x) & (DM_WIDTH - 1)] << 2; + r1 = r + (dith >> r_prec); + g1 = g + ((252 - dith) >> g_prec); + b1 = b + (dith >> b_prec); + pixel = (((r1 - (r1 >> r_prec)) >> r_right) << r_left) | + (((g1 - (g1 >> g_prec)) >> g_right) << g_left) | + (((b1 - (b1 >> b_prec)) >> b_right) << b_left); + for (i = 0; i < bpp; i++) + { + *obptr++ = pixel & 0xff; + pixel >>= 8; + } + bp2 += 3; + } + bptr += rowstride; + obuf += bpl; + } +} + +static void +gdk_rgb_convert_truecolor_msb (GdkImage *image, + gint x0, gint y0, gint width, gint height, + guchar *buf, int rowstride, + gint x_align, gint y_align, + GdkRgbCmap *cmap) +{ + int x, y; + guchar *obuf, *obptr; + gint bpl; + guchar *bptr, *bp2; + gint r, g, b; + gint r_right, r_left; + gint g_right, g_left; + gint b_right, b_left; + gint bpp; + guint32 pixel; + gint shift, shift_init; + + r_right = 8 - image_info->visual->red_prec; + r_left = image_info->visual->red_shift; + g_right = 8 - image_info->visual->green_prec; + g_left = image_info->visual->green_shift; + b_right = 8 - image_info->visual->blue_prec; + b_left = image_info->visual->blue_shift; + bpp = image_info->bpp; + bptr = buf; + bpl = image->bpl; + obuf = ((guchar *)image->mem) + y0 * bpl + x0 * bpp; + shift_init = (bpp - 1) << 3; + for (y = 0; y < height; y++) + { + obptr = obuf; + bp2 = bptr; + for (x = 0; x < width; x++) + { + r = bp2[0]; + g = bp2[1]; + b = bp2[2]; + pixel = ((r >> r_right) << r_left) | + ((g >> g_right) << g_left) | + ((b >> b_right) << b_left); + for (shift = shift_init; shift >= 0; shift -= 8) + { + *obptr++ = (pixel >> shift) & 0xff; + } + bp2 += 3; + } + bptr += rowstride; + obuf += bpl; + } +} + +static void +gdk_rgb_convert_truecolor_msb_d (GdkImage *image, + gint x0, gint y0, gint width, gint height, + guchar *buf, int rowstride, + gint x_align, gint y_align, + GdkRgbCmap *cmap) +{ + int x, y; + guchar *obuf, *obptr; + gint bpl; + guchar *bptr, *bp2; + gint r, g, b; + gint r_right, r_left, r_prec; + gint g_right, g_left, g_prec; + gint b_right, b_left, b_prec; + gint bpp; + guint32 pixel; + gint shift, shift_init; + gint dith; + gint r1, g1, b1; + const guchar *dmp; + + r_right = 8 - image_info->visual->red_prec; + r_left = image_info->visual->red_shift; + r_prec = image_info->visual->red_prec; + g_right = 8 - image_info->visual->green_prec; + g_left = image_info->visual->green_shift; + g_prec = image_info->visual->green_prec; + b_right = 8 - image_info->visual->blue_prec; + b_left = image_info->visual->blue_shift; + b_prec = image_info->visual->blue_prec; + bpp = image_info->bpp; + bptr = buf; + bpl = image->bpl; + obuf = ((guchar *)image->mem) + y0 * bpl + x0 * bpp; + shift_init = (bpp - 1) << 3; + for (y = 0; y < height; y++) + { + dmp = DM[(y_align + y) & (DM_HEIGHT - 1)]; + obptr = obuf; + bp2 = bptr; + for (x = 0; x < width; x++) + { + r = bp2[0]; + g = bp2[1]; + b = bp2[2]; + dith = dmp[(x_align + x) & (DM_WIDTH - 1)] << 2; + r1 = r + (dith >> r_prec); + g1 = g + ((252 - dith) >> g_prec); + b1 = b + (dith >> b_prec); + pixel = (((r1 - (r1 >> r_prec)) >> r_right) << r_left) | + (((g1 - (g1 >> g_prec)) >> g_right) << g_left) | + (((b1 - (b1 >> b_prec)) >> b_right) << b_left); + for (shift = shift_init; shift >= 0; shift -= 8) + { + *obptr++ = (pixel >> shift) & 0xff; + } + bp2 += 3; + } + bptr += rowstride; + obuf += bpl; + } +} + +/* This actually works for depths from 3 to 7 */ +static void +gdk_rgb_convert_4 (GdkImage *image, + gint x0, gint y0, gint width, gint height, + guchar *buf, int rowstride, + gint x_align, gint y_align, + GdkRgbCmap *cmap) +{ + int x, y; + gint bpl; + guchar *obuf, *obptr; + guchar *bptr, *bp2; + gint r, g, b; + const guchar *dmp; + gint dith; + + bptr = buf; + bpl = image->bpl; + obuf = ((guchar *)image->mem) + y0 * bpl + x0; + for (y = 0; y < height; y++) + { + dmp = DM[(y_align + y) & (DM_HEIGHT - 1)]; + bp2 = bptr; + obptr = obuf; + for (x = 0; x < width; x += 1) + { + r = *bp2++; + g = *bp2++; + b = *bp2++; + dith = (dmp[(x_align + x) & (DM_WIDTH - 1)] << 2) | 3; + obptr[0] = colorcube_d[(((r + dith) & 0x100) >> 2) | + (((g + 258 - dith) & 0x100) >> 5) | + (((b + dith) & 0x100) >> 8)]; + obptr++; + } + bptr += rowstride; + obuf += bpl; + } +} + +/* This actually works for depths from 3 to 7 */ +static void +gdk_rgb_convert_gray4 (GdkImage *image, + gint x0, gint y0, gint width, gint height, + guchar *buf, int rowstride, + gint x_align, gint y_align, GdkRgbCmap *cmap) +{ + int x, y; + gint bpl; + guchar *obuf, *obptr; + guchar *bptr, *bp2; + gint r, g, b; + gint shift; + + bptr = buf; + bpl = image->bpl; + obuf = ((guchar *)image->mem) + y0 * bpl + x0; + shift = 9 - image_info->visual->depth; + for (y = 0; y < height; y++) + { + bp2 = bptr; + obptr = obuf; + for (x = 0; x < width; x++) + { + r = *bp2++; + g = *bp2++; + b = *bp2++; + obptr[0] = (g + ((b + r) >> 1)) >> shift; + obptr++; + } + bptr += rowstride; + obuf += bpl; + } +} + +static void +gdk_rgb_convert_gray4_pack (GdkImage *image, + gint x0, gint y0, gint width, gint height, + guchar *buf, int rowstride, + gint x_align, gint y_align, GdkRgbCmap *cmap) +{ + int x, y; + gint bpl; + guchar *obuf, *obptr; + guchar *bptr, *bp2; + gint r, g, b; + gint shift; + guchar pix0, pix1; + /* todo: this is hardcoded to big-endian. Make endian-agile. */ + + bptr = buf; + bpl = image->bpl; + obuf = ((guchar *)image->mem) + y0 * bpl + (x0 >> 1); + shift = 9 - image_info->visual->depth; + for (y = 0; y < height; y++) + { + bp2 = bptr; + obptr = obuf; + for (x = 0; x < width; x += 2) + { + r = *bp2++; + g = *bp2++; + b = *bp2++; + pix0 = (g + ((b + r) >> 1)) >> shift; + r = *bp2++; + g = *bp2++; + b = *bp2++; + pix1 = (g + ((b + r) >> 1)) >> shift; + obptr[0] = (pix0 << 4) | pix1; + obptr++; + } + if (width & 1) + { + r = *bp2++; + g = *bp2++; + b = *bp2++; + pix0 = (g + ((b + r) >> 1)) >> shift; + obptr[0] = (pix0 << 4); + } + bptr += rowstride; + obuf += bpl; + } +} + +/* This actually works for depths from 3 to 7 */ +static void +gdk_rgb_convert_gray4_d (GdkImage *image, + gint x0, gint y0, gint width, gint height, + guchar *buf, int rowstride, + gint x_align, gint y_align, GdkRgbCmap *cmap) +{ + int x, y; + gint bpl; + guchar *obuf, *obptr; + guchar *bptr, *bp2; + gint r, g, b; + const guchar *dmp; + gint prec, right; + gint gray; + + bptr = buf; + bpl = image->bpl; + obuf = ((guchar *)image->mem) + y0 * bpl + x0; + prec = image_info->visual->depth; + right = 8 - prec; + for (y = 0; y < height; y++) + { + bp2 = bptr; + obptr = obuf; + dmp = DM[(y_align + y) & (DM_HEIGHT - 1)]; + for (x = 0; x < width; x++) + { + r = *bp2++; + g = *bp2++; + b = *bp2++; + gray = (g + ((b + r) >> 1)) >> 1; + gray += (dmp[(x_align + x) & (DM_WIDTH - 1)] << 2) >> prec; + obptr[0] = (gray - (gray >> prec)) >> right; + obptr++; + } + bptr += rowstride; + obuf += bpl; + } +} + +static void +gdk_rgb_convert_gray4_d_pack (GdkImage *image, + gint x0, gint y0, gint width, gint height, + guchar *buf, int rowstride, + gint x_align, gint y_align, GdkRgbCmap *cmap) +{ + int x, y; + gint bpl; + guchar *obuf, *obptr; + guchar *bptr, *bp2; + gint r, g, b; + const guchar *dmp; + gint prec, right; + gint gray; + guchar pix0, pix1; + /* todo: this is hardcoded to big-endian. Make endian-agile. */ + + bptr = buf; + bpl = image->bpl; + obuf = ((guchar *)image->mem) + y0 * bpl + (x0 >> 1); + prec = image_info->visual->depth; + right = 8 - prec; + for (y = 0; y < height; y++) + { + bp2 = bptr; + obptr = obuf; + dmp = DM[(y_align + y) & (DM_HEIGHT - 1)]; + for (x = 0; x < width; x += 2) + { + r = *bp2++; + g = *bp2++; + b = *bp2++; + gray = (g + ((b + r) >> 1)) >> 1; + gray += (dmp[(x_align + x) & (DM_WIDTH - 1)] << 2) >> prec; + pix0 = (gray - (gray >> prec)) >> right; + r = *bp2++; + g = *bp2++; + b = *bp2++; + gray = (g + ((b + r) >> 1)) >> 1; + gray += (dmp[(x_align + x + 1) & (DM_WIDTH - 1)] << 2) >> prec; + pix1 = (gray - (gray >> prec)) >> right; + obptr[0] = (pix0 << 4) | pix1; + obptr++; + } + if (width & 1) + { + r = *bp2++; + g = *bp2++; + b = *bp2++; + gray = (g + ((b + r) >> 1)) >> 1; + gray += (dmp[(x_align + x + 1) & (DM_WIDTH - 1)] << 2) >> prec; + pix0 = (gray - (gray >> prec)) >> right; + obptr[0] = (pix0 << 4); + } + bptr += rowstride; + obuf += bpl; + } +} + +static void +gdk_rgb_convert_1 (GdkImage *image, + gint x0, gint y0, gint width, gint height, + guchar *buf, int rowstride, + gint x_align, gint y_align, + GdkRgbCmap *cmap) +{ + int x, y; + gint bpl; + guchar *obuf, *obptr; + guchar *bptr, *bp2; + gint r, g, b; + const guchar *dmp; + gint dith; + guchar byte; + + bptr = buf; + bpl = image->bpl; + obuf = ((guchar *)image->mem) + y0 * bpl + (x0 >> 3); + byte = 0; /* unnecessary, but it keeps gcc from complaining */ + for (y = 0; y < height; y++) + { + dmp = DM[(y_align + y) & (DM_HEIGHT - 1)]; + bp2 = bptr; + obptr = obuf; + for (x = 0; x < width; x++) + { + r = *bp2++; + g = *bp2++; + b = *bp2++; + dith = (dmp[(x_align + x) & (DM_WIDTH - 1)] << 4) | 4; + byte += byte + (r + g + g + b + dith > 1020); + if ((x & 7) == 7) + { + obptr[0] = byte; + obptr++; + } + } + if (x & 7) + obptr[0] = byte << (8 - (x & 7)); + bptr += rowstride; + obuf += bpl; + } +} + +/* Returns a pointer to the stage buffer. */ +static guchar * +gdk_rgb_ensure_stage (void) +{ + if (image_info->stage_buf == NULL) + image_info->stage_buf = g_malloc (IMAGE_HEIGHT * STAGE_ROWSTRIDE); + return image_info->stage_buf; +} + +/* This is slow. Speed me up, please. */ +static void +gdk_rgb_32_to_stage (guchar *buf, gint rowstride, gint width, gint height) +{ + gint x, y; + guchar *pi_start, *po_start; + guchar *pi, *po; + + pi_start = buf; + po_start = gdk_rgb_ensure_stage (); + for (y = 0; y < height; y++) + { + pi = pi_start; + po = po_start; + for (x = 0; x < width; x++) + { + *po++ = *pi++; + *po++ = *pi++; + *po++ = *pi++; + pi++; + } + pi_start += rowstride; + po_start += STAGE_ROWSTRIDE; + } +} + +/* Generic 32bit RGB conversion function - convert to 24bit packed, then + go from there. */ +static void +gdk_rgb_convert_32_generic (GdkImage *image, + gint x0, gint y0, gint width, gint height, + guchar *buf, gint rowstride, + gint x_align, gint y_align, GdkRgbCmap *cmap) +{ + gdk_rgb_32_to_stage (buf, rowstride, width, height); + + (*image_info->conv) (image, x0, y0, width, height, + image_info->stage_buf, STAGE_ROWSTRIDE, + x_align, y_align, cmap); +} + +/* Generic 32bit RGB conversion function - convert to 24bit packed, then + go from there. */ +static void +gdk_rgb_convert_32_generic_d (GdkImage *image, + gint x0, gint y0, gint width, gint height, + guchar *buf, gint rowstride, + gint x_align, gint y_align, GdkRgbCmap *cmap) +{ + gdk_rgb_32_to_stage (buf, rowstride, width, height); + + (*image_info->conv_d) (image, x0, y0, width, height, + image_info->stage_buf, STAGE_ROWSTRIDE, + x_align, y_align, cmap); +} + +/* This is slow. Speed me up, please. */ +static void +gdk_rgb_gray_to_stage (guchar *buf, gint rowstride, gint width, gint height) +{ + gint x, y; + guchar *pi_start, *po_start; + guchar *pi, *po; + guchar gray; + + pi_start = buf; + po_start = gdk_rgb_ensure_stage (); + for (y = 0; y < height; y++) + { + pi = pi_start; + po = po_start; + for (x = 0; x < width; x++) + { + gray = *pi++; + *po++ = gray; + *po++ = gray; + *po++ = gray; + } + pi_start += rowstride; + po_start += STAGE_ROWSTRIDE; + } +} + +/* Generic gray conversion function - convert to 24bit packed, then go + from there. */ +static void +gdk_rgb_convert_gray_generic (GdkImage *image, + gint x0, gint y0, gint width, gint height, + guchar *buf, gint rowstride, + gint x_align, gint y_align, GdkRgbCmap *cmap) +{ + gdk_rgb_gray_to_stage (buf, rowstride, width, height); + + (*image_info->conv) (image, x0, y0, width, height, + image_info->stage_buf, STAGE_ROWSTRIDE, + x_align, y_align, cmap); +} + +static void +gdk_rgb_convert_gray_generic_d (GdkImage *image, + gint x0, gint y0, gint width, gint height, + guchar *buf, gint rowstride, + gint x_align, gint y_align, GdkRgbCmap *cmap) +{ + gdk_rgb_gray_to_stage (buf, rowstride, width, height); + + (*image_info->conv_d) (image, x0, y0, width, height, + image_info->stage_buf, STAGE_ROWSTRIDE, + x_align, y_align, cmap); +} + +/* Render grayscale using indexed method. */ +static void +gdk_rgb_convert_gray_cmap (GdkImage *image, + gint x0, gint y0, gint width, gint height, + guchar *buf, gint rowstride, + gint x_align, gint y_align, GdkRgbCmap *cmap) +{ + (*image_info->conv_indexed) (image, x0, y0, width, height, + buf, rowstride, + x_align, y_align, image_info->gray_cmap); +} + +#if 0 +static void +gdk_rgb_convert_gray_cmap_d (GdkImage *image, + gint x0, gint y0, gint width, gint height, + guchar *buf, gint rowstride, + gint x_align, gint y_align, GdkRgbCmap *cmap) +{ + (*image_info->conv_indexed_d) (image, x0, y0, width, height, + buf, rowstride, + x_align, y_align, image_info->gray_cmap); +} +#endif + +/* This is slow. Speed me up, please. */ +static void +gdk_rgb_indexed_to_stage (guchar *buf, gint rowstride, gint width, gint height, + GdkRgbCmap *cmap) +{ + gint x, y; + guchar *pi_start, *po_start; + guchar *pi, *po; + gint rgb; + + pi_start = buf; + po_start = gdk_rgb_ensure_stage (); + for (y = 0; y < height; y++) + { + pi = pi_start; + po = po_start; + for (x = 0; x < width; x++) + { + rgb = cmap->colors[*pi++]; + *po++ = rgb >> 16; + *po++ = (rgb >> 8) & 0xff; + *po++ = rgb & 0xff; + } + pi_start += rowstride; + po_start += STAGE_ROWSTRIDE; + } +} + +/* Generic gray conversion function - convert to 24bit packed, then go + from there. */ +static void +gdk_rgb_convert_indexed_generic (GdkImage *image, + gint x0, gint y0, gint width, gint height, + guchar *buf, gint rowstride, + gint x_align, gint y_align, GdkRgbCmap *cmap) +{ + gdk_rgb_indexed_to_stage (buf, rowstride, width, height, cmap); + + (*image_info->conv) (image, x0, y0, width, height, + image_info->stage_buf, STAGE_ROWSTRIDE, + x_align, y_align, cmap); +} + +static void +gdk_rgb_convert_indexed_generic_d (GdkImage *image, + gint x0, gint y0, gint width, gint height, + guchar *buf, gint rowstride, + gint x_align, gint y_align, + GdkRgbCmap *cmap) +{ + gdk_rgb_indexed_to_stage (buf, rowstride, width, height, cmap); + + (*image_info->conv_d) (image, x0, y0, width, height, + image_info->stage_buf, STAGE_ROWSTRIDE, + x_align, y_align, cmap); +} + +/* Select a conversion function based on the visual and a + representative image. */ +static void +gdk_rgb_select_conv (GdkImage *image) +{ + GdkByteOrder byte_order; + gint depth, bpp, byterev; + GdkVisualType vtype; + guint32 red_mask, green_mask, blue_mask; + GdkRgbConvFunc conv, conv_d; + GdkRgbConvFunc conv_32, conv_32_d; + GdkRgbConvFunc conv_gray, conv_gray_d; + GdkRgbConvFunc conv_indexed, conv_indexed_d; + gboolean mask_rgb, mask_bgr; + + depth = image_info->visual->depth; +#if !defined (X_DISPLAY_MISSING) + bpp = ((GdkImagePrivate *)image)->ximage->bits_per_pixel; +#elif defined (WINDOWS_DISPLAY) + bpp = ((GdkVisualPrivate *) gdk_visual_get_system())->xvisual->bitspixel; +#endif + byte_order = image->byte_order; + if (gdk_rgb_verbose) + g_print ("Chose visual 0x%x, image bpp=%d, depth = %d %s first\n", + (gint)(((GdkVisualPrivate *)image_info->visual)->xvisual->visualid), + bpp, depth, byte_order == GDK_LSB_FIRST ? "lsb" : "msb"); + +#if G_BYTE_ORDER == G_BIG_ENDIAN + byterev = (byte_order == GDK_LSB_FIRST); +#else + byterev = (byte_order == GDK_MSB_FIRST); +#endif + + vtype = image_info->visual->type; + if (vtype == GDK_VISUAL_DIRECT_COLOR) + vtype = GDK_VISUAL_TRUE_COLOR; + + red_mask = image_info->visual->red_mask; + green_mask = image_info->visual->green_mask; + blue_mask = image_info->visual->blue_mask; + + mask_rgb = red_mask == 0xff0000 && green_mask == 0xff00 && blue_mask == 0xff; + mask_bgr = red_mask == 0xff && green_mask == 0xff00 && blue_mask == 0xff0000; + + conv = NULL; + conv_d = NULL; + + conv_32 = gdk_rgb_convert_32_generic; + conv_32_d = gdk_rgb_convert_32_generic_d; + + conv_gray = gdk_rgb_convert_gray_generic; + conv_gray_d = gdk_rgb_convert_gray_generic_d; + + conv_indexed = gdk_rgb_convert_indexed_generic; + conv_indexed_d = gdk_rgb_convert_indexed_generic_d; + + image_info->dith_default = FALSE; + + if (image_info->bitmap) + conv = gdk_rgb_convert_1; + else if (bpp == 16 && depth == 16 && !byterev && + red_mask == 0xf800 && green_mask == 0x7e0 && blue_mask == 0x1f) + { + conv = gdk_rgb_convert_565; + conv_d = gdk_rgb_convert_565_d; + conv_gray = gdk_rgb_convert_565_gray; + gdk_rgb_preprocess_dm_565 (); + } + else if (bpp == 16 && depth == 16 && + vtype == GDK_VISUAL_TRUE_COLOR && byterev && + red_mask == 0xf800 && green_mask == 0x7e0 && blue_mask == 0x1f) + conv = gdk_rgb_convert_565_br; + + else if (bpp == 16 && depth == 15 && + vtype == GDK_VISUAL_TRUE_COLOR && !byterev && + red_mask == 0x7c00 && green_mask == 0x3e0 && blue_mask == 0x1f) + conv = gdk_rgb_convert_555; + + else if (bpp == 16 && depth == 15 && + vtype == GDK_VISUAL_TRUE_COLOR && byterev && + red_mask == 0x7c00 && green_mask == 0x3e0 && blue_mask == 0x1f) + conv = gdk_rgb_convert_555_br; + + /* I'm not 100% sure about the 24bpp tests - but testing will show*/ + else if (bpp == 24 && depth == 24 && vtype == GDK_VISUAL_TRUE_COLOR && + ((mask_rgb && byte_order == GDK_LSB_FIRST) || + (mask_bgr && byte_order == GDK_MSB_FIRST))) + conv = gdk_rgb_convert_888_lsb; + else if (bpp == 24 && depth == 24 && vtype == GDK_VISUAL_TRUE_COLOR && + ((mask_rgb && byte_order == GDK_MSB_FIRST) || + (mask_bgr && byte_order == GDK_LSB_FIRST))) + conv = gdk_rgb_convert_888_msb; +#if G_BYTE_ORDER == G_BIG_ENDIAN + else if (bpp == 32 && depth == 24 && vtype == GDK_VISUAL_TRUE_COLOR && + (mask_rgb && byte_order == GDK_LSB_FIRST)) + conv = gdk_rgb_convert_0888_br; + else if (bpp == 32 && depth == 24 && vtype == GDK_VISUAL_TRUE_COLOR && + (mask_rgb && byte_order == GDK_MSB_FIRST)) + conv = gdk_rgb_convert_0888; + else if (bpp == 32 && depth == 24 && vtype == GDK_VISUAL_TRUE_COLOR && + (mask_bgr && byte_order == GDK_MSB_FIRST)) + conv = gdk_rgb_convert_8880_br; +#else + else if (bpp == 32 && depth == 24 && vtype == GDK_VISUAL_TRUE_COLOR && + (mask_rgb && byte_order == GDK_MSB_FIRST)) + conv = gdk_rgb_convert_0888_br; + else if (bpp == 32 && (depth == 24 || depth == 32) && vtype == GDK_VISUAL_TRUE_COLOR && + (mask_rgb && byte_order == GDK_LSB_FIRST)) + conv = gdk_rgb_convert_0888; + else if (bpp == 32 && depth == 24 && vtype == GDK_VISUAL_TRUE_COLOR && + (mask_bgr && byte_order == GDK_LSB_FIRST)) + conv = gdk_rgb_convert_8880_br; +#endif + + else if (vtype == GDK_VISUAL_TRUE_COLOR && byte_order == GDK_LSB_FIRST) + { + conv = gdk_rgb_convert_truecolor_lsb; + conv_d = gdk_rgb_convert_truecolor_lsb_d; + } + else if (vtype == GDK_VISUAL_TRUE_COLOR && byte_order == GDK_MSB_FIRST) + { + conv = gdk_rgb_convert_truecolor_msb; + conv_d = gdk_rgb_convert_truecolor_msb_d; + } + else if (bpp == 8 && depth == 8 && (vtype == GDK_VISUAL_PSEUDO_COLOR +#ifdef ENABLE_GRAYSCALE + || vtype == GDK_VISUAL_GRAYSCALE +#endif + )) + { + image_info->dith_default = TRUE; + conv = gdk_rgb_convert_8; + if (vtype != GDK_VISUAL_GRAYSCALE) + { + if (image_info->nred_shades == 6 && + image_info->ngreen_shades == 6 && + image_info->nblue_shades == 6) + conv_d = gdk_rgb_convert_8_d666; + else + conv_d = gdk_rgb_convert_8_d; + } + conv_indexed = gdk_rgb_convert_8_indexed; + conv_gray = gdk_rgb_convert_gray_cmap; + } + else if (bpp == 8 && depth == 8 && (vtype == GDK_VISUAL_STATIC_GRAY +#ifdef not_ENABLE_GRAYSCALE + || vtype == GDK_VISUAL_GRAYSCALE +#endif + )) + { + conv = gdk_rgb_convert_gray8; + conv_gray = gdk_rgb_convert_gray8_gray; + } + else if (bpp == 8 && depth < 8 && depth >= 2 && + (vtype == GDK_VISUAL_STATIC_GRAY + || vtype == GDK_VISUAL_GRAYSCALE)) + { + conv = gdk_rgb_convert_gray4; + conv_d = gdk_rgb_convert_gray4_d; + } + else if (bpp == 8 && depth < 8 && depth >= 3) + { + conv = gdk_rgb_convert_4; + } + else if (bpp == 4 && depth <= 4 && depth >= 2 && + (vtype == GDK_VISUAL_STATIC_GRAY + || vtype == GDK_VISUAL_GRAYSCALE)) + { + conv = gdk_rgb_convert_gray4_pack; + conv_d = gdk_rgb_convert_gray4_d_pack; + } + + if (conv_d == NULL) + conv_d = conv; + + image_info->conv = conv; + image_info->conv_d = conv_d; + + image_info->conv_32 = conv_32; + image_info->conv_32_d = conv_32_d; + + image_info->conv_gray = conv_gray; + image_info->conv_gray_d = conv_gray_d; + + image_info->conv_indexed = conv_indexed; + image_info->conv_indexed_d = conv_indexed_d; +} + +static gint horiz_idx; +static gint horiz_y = IMAGE_HEIGHT; +static gint vert_idx; +static gint vert_x = IMAGE_WIDTH; +static gint tile_idx; +static gint tile_x = IMAGE_WIDTH; +static gint tile_y1 = IMAGE_HEIGHT; +static gint tile_y2 = IMAGE_HEIGHT; + +#ifdef VERBOSE +static gint sincelast; +#endif + +/* Defining NO_FLUSH can cause inconsistent screen updates, but is useful + for performance evaluation. */ + +#undef NO_FLUSH + +static gint +gdk_rgb_alloc_scratch_image (void) +{ + if (static_image_idx == N_IMAGES) + { +#ifndef NO_FLUSH + gdk_flush (); +#endif +#ifdef VERBOSE + g_print ("flush, %d puts since last flush\n", sincelast); + sincelast = 0; +#endif + static_image_idx = 0; + horiz_y = IMAGE_HEIGHT; + vert_x = IMAGE_WIDTH; + tile_x = IMAGE_WIDTH; + tile_y1 = tile_y2 = IMAGE_HEIGHT; + } + return static_image_idx++; +} + +static GdkImage * +gdk_rgb_alloc_scratch (gint width, gint height, gint *x0, gint *y0) +{ + GdkImage *image; + gint idx; + + if (width >= (IMAGE_WIDTH >> 1)) + { + if (height >= (IMAGE_HEIGHT >> 1)) + { + idx = gdk_rgb_alloc_scratch_image (); + *x0 = 0; + *y0 = 0; + } + else + { + if (height + horiz_y > IMAGE_HEIGHT) + { + horiz_idx = gdk_rgb_alloc_scratch_image (); + horiz_y = 0; + } + idx = horiz_idx; + *x0 = 0; + *y0 = horiz_y; + horiz_y += height; + } + } + else + { + if (height >= (IMAGE_HEIGHT >> 1)) + { + if (width + vert_x > IMAGE_WIDTH) + { + vert_idx = gdk_rgb_alloc_scratch_image (); + vert_x = 0; + } + idx = vert_idx; + *x0 = vert_x; + *y0 = 0; + /* using 3 and -4 would be slightly more efficient on 32-bit machines + with > 1bpp displays */ + vert_x += (width + 7) & -8; + } + else + { + if (width + tile_x > IMAGE_WIDTH) + { + tile_y1 = tile_y2; + tile_x = 0; + } + if (height + tile_y1 > IMAGE_HEIGHT) + { + tile_idx = gdk_rgb_alloc_scratch_image (); + tile_x = 0; + tile_y1 = 0; + tile_y2 = 0; + } + if (height + tile_y1 > tile_y2) + tile_y2 = height + tile_y1; + idx = tile_idx; + *x0 = tile_x; + *y0 = tile_y1; + tile_x += (width + 7) & -8; + } + } + image = static_image[idx]; +#ifdef VERBOSE + g_print ("index %d, x %d, y %d (%d x %d)\n", idx, *x0, *y0, width, height); + sincelast++; +#endif + return image; +} + +static void +gdk_draw_rgb_image_core (GdkDrawable *drawable, + GdkGC *gc, + gint x, + gint y, + gint width, + gint height, + guchar *buf, + gint pixstride, + gint rowstride, + GdkRgbConvFunc conv, + GdkRgbCmap *cmap, + gint xdith, + gint ydith) +{ + gint y0, x0; + gint xs0, ys0; + GdkImage *image; + gint width1, height1; + guchar *buf_ptr; + + if (image_info->bitmap) + { + if (image_info->own_gc == NULL) + { + GdkColor color; + + image_info->own_gc = gdk_gc_new (drawable); + gdk_color_white (image_info->cmap, &color); + gdk_gc_set_foreground (image_info->own_gc, &color); + gdk_color_black (image_info->cmap, &color); + gdk_gc_set_background (image_info->own_gc, &color); + } + gc = image_info->own_gc; + } + for (y0 = 0; y0 < height; y0 += IMAGE_HEIGHT) + { + height1 = MIN (height - y0, IMAGE_HEIGHT); + for (x0 = 0; x0 < width; x0 += IMAGE_WIDTH) + { + width1 = MIN (width - x0, IMAGE_WIDTH); + buf_ptr = buf + y0 * rowstride + x0 * pixstride; + + image = gdk_rgb_alloc_scratch (width1, height1, &xs0, &ys0); + + conv (image, xs0, ys0, width1, height1, buf_ptr, rowstride, + x + x0 + xdith, y + y0 + ydith, cmap); + +#ifndef DONT_ACTUALLY_DRAW + gdk_draw_image (drawable, gc, + image, xs0, ys0, x + x0, y + y0, width1, height1); +#endif + } + } +} + + +void +gdk_draw_rgb_image (GdkDrawable *drawable, + GdkGC *gc, + gint x, + gint y, + gint width, + gint height, + GdkRgbDither dith, + guchar *rgb_buf, + gint rowstride) +{ + if (dith == GDK_RGB_DITHER_NONE || (dith == GDK_RGB_DITHER_NORMAL && + !image_info->dith_default)) + gdk_draw_rgb_image_core (drawable, gc, x, y, width, height, + rgb_buf, 3, rowstride, image_info->conv, NULL, + 0, 0); + else + gdk_draw_rgb_image_core (drawable, gc, x, y, width, height, + rgb_buf, 3, rowstride, image_info->conv_d, NULL, + 0, 0); +} + +void +gdk_draw_rgb_image_dithalign (GdkDrawable *drawable, + GdkGC *gc, + gint x, + gint y, + gint width, + gint height, + GdkRgbDither dith, + guchar *rgb_buf, + gint rowstride, + gint xdith, + gint ydith) +{ + if (dith == GDK_RGB_DITHER_NONE || (dith == GDK_RGB_DITHER_NORMAL && + !image_info->dith_default)) + gdk_draw_rgb_image_core (drawable, gc, x, y, width, height, + rgb_buf, 3, rowstride, image_info->conv, NULL, + xdith, ydith); + else + gdk_draw_rgb_image_core (drawable, gc, x, y, width, height, + rgb_buf, 3, rowstride, image_info->conv_d, NULL, + xdith, ydith); +} + +void +gdk_draw_rgb_32_image (GdkDrawable *drawable, + GdkGC *gc, + gint x, + gint y, + gint width, + gint height, + GdkRgbDither dith, + guchar *buf, + gint rowstride) +{ + if (dith == GDK_RGB_DITHER_NONE || (dith == GDK_RGB_DITHER_NORMAL && + !image_info->dith_default)) + gdk_draw_rgb_image_core (drawable, gc, x, y, width, height, + buf, 4, rowstride, + image_info->conv_32, NULL, 0, 0); + else + gdk_draw_rgb_image_core (drawable, gc, x, y, width, height, + buf, 4, rowstride, + image_info->conv_32_d, NULL, 0, 0); +} + +static void +gdk_rgb_make_gray_cmap (GdkRgbInfo *info) +{ + guint32 rgb[256]; + gint i; + + for (i = 0; i < 256; i++) + rgb[i] = (i << 16) | (i << 8) | i; + info->gray_cmap = gdk_rgb_cmap_new (rgb, 256); +} + +void +gdk_draw_gray_image (GdkDrawable *drawable, + GdkGC *gc, + gint x, + gint y, + gint width, + gint height, + GdkRgbDither dith, + guchar *buf, + gint rowstride) +{ + if (image_info->bpp == 1 && + image_info->gray_cmap == NULL && + (image_info->visual->type == GDK_VISUAL_PSEUDO_COLOR || + image_info->visual->type == GDK_VISUAL_GRAYSCALE)) + gdk_rgb_make_gray_cmap (image_info); + + if (dith == GDK_RGB_DITHER_NONE || (dith == GDK_RGB_DITHER_NORMAL && + !image_info->dith_default)) + gdk_draw_rgb_image_core (drawable, gc, x, y, width, height, + buf, 1, rowstride, + image_info->conv_gray, NULL, 0, 0); + else + gdk_draw_rgb_image_core (drawable, gc, x, y, width, height, + buf, 1, rowstride, + image_info->conv_gray_d, NULL, 0, 0); +} + +GdkRgbCmap * +gdk_rgb_cmap_new (guint32 *colors, gint n_colors) +{ + GdkRgbCmap *cmap; + int i, j; + guint32 rgb; + + g_return_val_if_fail (n_colors >= 0, NULL); + g_return_val_if_fail (n_colors <= 256, NULL); + cmap = g_new (GdkRgbCmap, 1); + memcpy (cmap->colors, colors, n_colors * sizeof(guint32)); + if (image_info->bpp == 1 && + (image_info->visual->type == GDK_VISUAL_PSEUDO_COLOR || + image_info->visual->type == GDK_VISUAL_GRAYSCALE)) + for (i = 0; i < n_colors; i++) + { + rgb = colors[i]; + j = ((rgb & 0xf00000) >> 12) | + ((rgb & 0xf000) >> 8) | + ((rgb & 0xf0) >> 4); +#ifdef VERBOSE + g_print ("%d %x %x %d\n", i, j, colorcube[j]); +#endif + cmap->lut[i] = colorcube[j]; + } + return cmap; +} + +void +gdk_rgb_cmap_free (GdkRgbCmap *cmap) +{ + g_free (cmap); +} + +void +gdk_draw_indexed_image (GdkDrawable *drawable, + GdkGC *gc, + gint x, + gint y, + gint width, + gint height, + GdkRgbDither dith, + guchar *buf, + gint rowstride, + GdkRgbCmap *cmap) +{ + if (dith == GDK_RGB_DITHER_NONE || (dith == GDK_RGB_DITHER_NORMAL && + !image_info->dith_default)) + gdk_draw_rgb_image_core (drawable, gc, x, y, width, height, + buf, 1, rowstride, + image_info->conv_indexed, cmap, 0, 0); + else + gdk_draw_rgb_image_core (drawable, gc, x, y, width, height, + buf, 1, rowstride, + image_info->conv_indexed_d, cmap, 0, 0); +} + +gboolean +gdk_rgb_ditherable (void) +{ + return (image_info->conv != image_info->conv_d); +} + +GdkColormap * +gdk_rgb_get_cmap (void) +{ + gdk_rgb_init (); + return image_info->cmap; +} + +GdkVisual * +gdk_rgb_get_visual (void) +{ + gdk_rgb_init (); + return image_info->visual; +} diff --git a/gdk/win32/gdkselection-win32.c b/gdk/win32/gdkselection-win32.c new file mode 100644 index 000000000..2c91ba2bb --- /dev/null +++ b/gdk/win32/gdkselection-win32.c @@ -0,0 +1,392 @@ +/* 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.h" +#include "gdkx.h" +#include "gdkprivate.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) +{ + GdkWindowPrivate *private = (GdkWindowPrivate *) owner; + GdkSelProp *prop; + + prop = g_hash_table_lookup (sel_prop_table, &private->xwindow); + if (prop != NULL) + { + g_free (prop->data); + g_hash_table_remove (sel_prop_table, &private->xwindow); + } + prop = g_new (GdkSelProp, 1); + prop->data = data; + prop->length = length; + prop->format = format; + prop->type = type; + g_hash_table_insert (sel_prop_table, &private->xwindow, prop); +} + + +gint +gdk_selection_owner_set (GdkWindow *owner, + GdkAtom selection, + guint32 time, + gint send_event) +{ + GdkWindowPrivate *private; + gchar *sel_name; + HWND xwindow; + + private = (GdkWindowPrivate *) owner; + + GDK_NOTE (SELECTION, + (sel_name = gdk_atom_name (selection), + g_print ("gdk_selection_owner_set: %#x %#x (%s)\n", + (private ? private->xwindow : 0), + selection, sel_name), + g_free (sel_name))); + + if (selection != gdk_clipboard_atom) + return FALSE; + + if (owner != NULL) + xwindow = private->xwindow; + else + xwindow = NULL; + + if (!OpenClipboard (xwindow)) + { + g_warning ("gdk_selection_owner_set: OpenClipboard failed"); + return FALSE; + } + 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 + 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 (private->xwindow, gdk_selection_request_msg, + selection, 0); + } + + return TRUE; +} + +GdkWindow* +gdk_selection_owner_get (GdkAtom selection) +{ + GdkWindow *window; + GdkWindowPrivate *private; + gchar *sel_name; + + if (selection != gdk_clipboard_atom) + window = NULL; + else + window = gdk_window_lookup (GetClipboardOwner ()); + + private = (GdkWindowPrivate *) window; + + GDK_NOTE (SELECTION, + (sel_name = gdk_atom_name (selection), + g_print ("gdk_selection_owner_get: %#x (%s) = %#x\n", + selection, sel_name, + (private ? private->xwindow : 0)), + g_free (sel_name))); + + return window; +} + +void +gdk_selection_convert (GdkWindow *requestor, + GdkAtom selection, + GdkAtom target, + guint32 time) +{ + GdkWindowPrivate *private; + HGLOBAL hdata; + GdkSelProp *prop; + guchar *ptr, *data, *datap, *p; + guint i, length, slength; + gchar *sel_name, *tgt_name; + + g_return_if_fail (requestor != NULL); + + private = (GdkWindowPrivate*) requestor; + + 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", + private->xwindow, 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. + */ + if (!OpenClipboard (private->xwindow)) + { + g_warning ("gdk_selection_convert: OpenClipboard failed"); + return; + } + + 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); + } + } + CloseClipboard (); + + + /* Send ourselves an ersatz selection notify message so that we actually + * fetch the data. + */ + SendMessage (private->xwindow, 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.xwindow); + + if (prop != NULL) + { + g_hash_table_remove (sel_prop_table, &gdk_root_parent.xwindow); + gdk_sel_prop_store (requestor, prop->type, prop->format, + prop->data, prop->length); + g_free (prop); + SendMessage (private->xwindow, 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) +{ + GdkWindowPrivate *private; + GdkSelProp *prop; + + g_return_val_if_fail (requestor != NULL, 0); + + private = (GdkWindowPrivate*) requestor; + if (private->destroyed) + return 0; + + GDK_NOTE (SELECTION, g_print ("gdk_selection_property_get: %#x\n", + private->xwindow)); + + prop = g_hash_table_lookup (sel_prop_table, &private->xwindow); + + 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 (GdkWindowPrivate *private) +{ + GdkSelProp *prop; + + prop = g_hash_table_lookup (sel_prop_table, &private->xwindow); + if (prop != NULL) + { + g_free (prop->data); + g_hash_table_remove (sel_prop_table, &private->xwindow); + } + 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 sot that gtk thinks we doen'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. + */ + + SendMessage ((HWND) requestor, gdk_selection_clear_msg, selection, 0); +} + +gint +gdk_text_property_to_text_list (GdkAtom encoding, + gint format, + guchar *text, + gint length, + gchar ***list) +{ + GDK_NOTE (SELECTION, + g_print ("gdk_text_property_to_text_list not implemented\n")); + + return 0; +} + +void +gdk_free_text_list (gchar **list) +{ + g_return_if_fail (list != NULL); + + /* ??? */ +} + +gint +gdk_string_to_compound_text (gchar *str, + GdkAtom *encoding, + gint *format, + guchar **ctext, + gint *length) +{ + g_warning ("gdk_string_to_compound_text: Not implemented"); + + return 0; +} + +void +gdk_free_compound_text (guchar *ctext) +{ + g_warning ("gdk_free_compound_text: Not implemented"); +} diff --git a/gdk/win32/gdkselection.c b/gdk/win32/gdkselection.c new file mode 100644 index 000000000..2c91ba2bb --- /dev/null +++ b/gdk/win32/gdkselection.c @@ -0,0 +1,392 @@ +/* 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.h" +#include "gdkx.h" +#include "gdkprivate.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) +{ + GdkWindowPrivate *private = (GdkWindowPrivate *) owner; + GdkSelProp *prop; + + prop = g_hash_table_lookup (sel_prop_table, &private->xwindow); + if (prop != NULL) + { + g_free (prop->data); + g_hash_table_remove (sel_prop_table, &private->xwindow); + } + prop = g_new (GdkSelProp, 1); + prop->data = data; + prop->length = length; + prop->format = format; + prop->type = type; + g_hash_table_insert (sel_prop_table, &private->xwindow, prop); +} + + +gint +gdk_selection_owner_set (GdkWindow *owner, + GdkAtom selection, + guint32 time, + gint send_event) +{ + GdkWindowPrivate *private; + gchar *sel_name; + HWND xwindow; + + private = (GdkWindowPrivate *) owner; + + GDK_NOTE (SELECTION, + (sel_name = gdk_atom_name (selection), + g_print ("gdk_selection_owner_set: %#x %#x (%s)\n", + (private ? private->xwindow : 0), + selection, sel_name), + g_free (sel_name))); + + if (selection != gdk_clipboard_atom) + return FALSE; + + if (owner != NULL) + xwindow = private->xwindow; + else + xwindow = NULL; + + if (!OpenClipboard (xwindow)) + { + g_warning ("gdk_selection_owner_set: OpenClipboard failed"); + return FALSE; + } + 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 + 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 (private->xwindow, gdk_selection_request_msg, + selection, 0); + } + + return TRUE; +} + +GdkWindow* +gdk_selection_owner_get (GdkAtom selection) +{ + GdkWindow *window; + GdkWindowPrivate *private; + gchar *sel_name; + + if (selection != gdk_clipboard_atom) + window = NULL; + else + window = gdk_window_lookup (GetClipboardOwner ()); + + private = (GdkWindowPrivate *) window; + + GDK_NOTE (SELECTION, + (sel_name = gdk_atom_name (selection), + g_print ("gdk_selection_owner_get: %#x (%s) = %#x\n", + selection, sel_name, + (private ? private->xwindow : 0)), + g_free (sel_name))); + + return window; +} + +void +gdk_selection_convert (GdkWindow *requestor, + GdkAtom selection, + GdkAtom target, + guint32 time) +{ + GdkWindowPrivate *private; + HGLOBAL hdata; + GdkSelProp *prop; + guchar *ptr, *data, *datap, *p; + guint i, length, slength; + gchar *sel_name, *tgt_name; + + g_return_if_fail (requestor != NULL); + + private = (GdkWindowPrivate*) requestor; + + 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", + private->xwindow, 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. + */ + if (!OpenClipboard (private->xwindow)) + { + g_warning ("gdk_selection_convert: OpenClipboard failed"); + return; + } + + 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); + } + } + CloseClipboard (); + + + /* Send ourselves an ersatz selection notify message so that we actually + * fetch the data. + */ + SendMessage (private->xwindow, 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.xwindow); + + if (prop != NULL) + { + g_hash_table_remove (sel_prop_table, &gdk_root_parent.xwindow); + gdk_sel_prop_store (requestor, prop->type, prop->format, + prop->data, prop->length); + g_free (prop); + SendMessage (private->xwindow, 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) +{ + GdkWindowPrivate *private; + GdkSelProp *prop; + + g_return_val_if_fail (requestor != NULL, 0); + + private = (GdkWindowPrivate*) requestor; + if (private->destroyed) + return 0; + + GDK_NOTE (SELECTION, g_print ("gdk_selection_property_get: %#x\n", + private->xwindow)); + + prop = g_hash_table_lookup (sel_prop_table, &private->xwindow); + + 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 (GdkWindowPrivate *private) +{ + GdkSelProp *prop; + + prop = g_hash_table_lookup (sel_prop_table, &private->xwindow); + if (prop != NULL) + { + g_free (prop->data); + g_hash_table_remove (sel_prop_table, &private->xwindow); + } + 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 sot that gtk thinks we doen'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. + */ + + SendMessage ((HWND) requestor, gdk_selection_clear_msg, selection, 0); +} + +gint +gdk_text_property_to_text_list (GdkAtom encoding, + gint format, + guchar *text, + gint length, + gchar ***list) +{ + GDK_NOTE (SELECTION, + g_print ("gdk_text_property_to_text_list not implemented\n")); + + return 0; +} + +void +gdk_free_text_list (gchar **list) +{ + g_return_if_fail (list != NULL); + + /* ??? */ +} + +gint +gdk_string_to_compound_text (gchar *str, + GdkAtom *encoding, + gint *format, + guchar **ctext, + gint *length) +{ + g_warning ("gdk_string_to_compound_text: Not implemented"); + + return 0; +} + +void +gdk_free_compound_text (guchar *ctext) +{ + g_warning ("gdk_free_compound_text: Not implemented"); +} diff --git a/gdk/win32/gdktypes.h b/gdk/win32/gdktypes.h new file mode 100644 index 000000000..4eeb65c63 --- /dev/null +++ b/gdk/win32/gdktypes.h @@ -0,0 +1,1279 @@ +/* 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_TYPES_H__ +#define __GDK_TYPES_H__ + + +/* GDK uses "glib". (And so does GTK). + */ +#include <glib.h> + +#ifdef NATIVE_WIN32 +#ifdef COMPILING_GDK +#define GDKVAR __declspec(dllexport) +#else +#define GDKVAR extern __declspec(dllimport) +#endif +#else +#define GDKVAR extern +#endif + +#define GDK_NONE 0L +#define GDK_CURRENT_TIME 0L +#define GDK_PARENT_RELATIVE 1L + +/* special deviceid for core pointer events */ +#define GDK_CORE_POINTER 0xfedc + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +/* Type definitions for the basic structures. + */ + +typedef gulong GdkAtom; +typedef struct _GdkColor GdkColor; +typedef struct _GdkColormap GdkColormap; +typedef struct _GdkVisual GdkVisual; +typedef struct _GdkWindowAttr GdkWindowAttr; +typedef struct _GdkWindow GdkWindow; +typedef struct _GdkWindow GdkPixmap; +typedef struct _GdkWindow GdkBitmap; +typedef struct _GdkWindow GdkDrawable; +typedef struct _GdkGeometry GdkGeometry; +typedef struct _GdkImage GdkImage; +typedef struct _GdkGCValues GdkGCValues; +typedef struct _GdkGC GdkGC; +typedef struct _GdkPoint GdkPoint; +typedef struct _GdkRectangle GdkRectangle; +typedef struct _GdkSegment GdkSegment; +typedef struct _GdkFont GdkFont; +typedef struct _GdkCursor GdkCursor; +typedef struct _GdkColorContextDither GdkColorContextDither; +typedef struct _GdkColorContext GdkColorContext; +typedef struct _GdkDragContext GdkDragContext; + +typedef struct _GdkEventAny GdkEventAny; +typedef struct _GdkEventExpose GdkEventExpose; +typedef struct _GdkEventNoExpose GdkEventNoExpose; +typedef struct _GdkEventVisibility GdkEventVisibility; +typedef struct _GdkEventMotion GdkEventMotion; +typedef struct _GdkEventButton GdkEventButton; +typedef struct _GdkEventKey GdkEventKey; +typedef struct _GdkEventFocus GdkEventFocus; +typedef struct _GdkEventCrossing GdkEventCrossing; +typedef struct _GdkEventConfigure GdkEventConfigure; +typedef struct _GdkEventProperty GdkEventProperty; +typedef struct _GdkEventSelection GdkEventSelection; +typedef struct _GdkEventProximity GdkEventProximity; +typedef struct _GdkEventClient GdkEventClient; + +typedef struct _GdkEventDND GdkEventDND; + +typedef union _GdkEvent GdkEvent; + +typedef struct _GdkDeviceKey GdkDeviceKey; +typedef struct _GdkDeviceInfo GdkDeviceInfo; +typedef struct _GdkTimeCoord GdkTimeCoord; +typedef struct _GdkRegion GdkRegion; +typedef void (*GdkEventFunc) (GdkEvent *event, + gpointer data); + +typedef struct _GdkIC GdkIC; +typedef struct _GdkICAttr GdkICAttr; + +typedef guint32 GdkWChar; + + +/* Types of windows. + * Root: There is only 1 root window and it is initialized + * at startup. Creating a window of type GDK_WINDOW_ROOT + * is an error. + * Toplevel: Windows which interact with the window manager. + * Child: Windows which are children of some other type of window. + * (Any other type of window). Most windows are child windows. + * Dialog: A special kind of toplevel window which interacts with + * the window manager slightly differently than a regular + * toplevel window. Dialog windows should be used for any + * transient window. + * Pixmap: Pixmaps are really just another kind of window which + * doesn't actually appear on the screen. It can't have + * children, either and is really just a convenience so + * that the drawing functions can work on both windows + * and pixmaps transparently. (ie. You shouldn't pass a + * pixmap to any procedure which accepts a window with the + * exception of the drawing functions). + * Foreign: A window that actually belongs to another application + */ +typedef enum +{ + GDK_WINDOW_ROOT, + GDK_WINDOW_TOPLEVEL, + GDK_WINDOW_CHILD, + GDK_WINDOW_DIALOG, + GDK_WINDOW_TEMP, + GDK_WINDOW_PIXMAP, + GDK_WINDOW_FOREIGN +} GdkWindowType; + +/* Classes of windows. + * InputOutput: Almost every window should be of this type. Such windows + * receive events and are also displayed on screen. + * InputOnly: Used only in special circumstances when events need to be + * stolen from another window or windows. Input only windows + * have no visible output, so they are handy for placing over + * top of a group of windows in order to grab the events (or + * filter the events) from those windows. + */ +typedef enum +{ + GDK_INPUT_OUTPUT, + GDK_INPUT_ONLY +} GdkWindowClass; + +/* Types of images. + * Normal: Normal X image type. These are slow as they involve passing + * the entire image through the X connection each time a draw + * request is required. + * Shared: Shared memory X image type. These are fast as the X server + * and the program actually use the same piece of memory. They + * should be used with care though as there is the possibility + * for both the X server and the program to be reading/writing + * the image simultaneously and producing undesired results. + * Shared Pixmap: Also a shared memory image, which also has a + * pixmap using the same memory. + */ +typedef enum +{ + GDK_IMAGE_NORMAL, + GDK_IMAGE_SHARED, + GDK_IMAGE_FASTEST, + GDK_IMAGE_SHARED_PIXMAP +} GdkImageType; + +/* Types of visuals. + * StaticGray: + * Grayscale: + * StaticColor: + * PseudoColor: + * TrueColor: + * DirectColor: + */ +typedef enum +{ + GDK_VISUAL_STATIC_GRAY, + GDK_VISUAL_GRAYSCALE, + GDK_VISUAL_STATIC_COLOR, + GDK_VISUAL_PSEUDO_COLOR, + GDK_VISUAL_TRUE_COLOR, + GDK_VISUAL_DIRECT_COLOR +} GdkVisualType; + +/* Types of font. + * GDK_FONT_FONT: the font is an XFontStruct. + * GDK_FONT_FONTSET: the font is an XFontSet used for I18N. + */ +typedef enum +{ + GDK_FONT_FONT, + GDK_FONT_FONTSET +} GdkFontType; + +/* Window attribute mask values. + * GDK_WA_TITLE: The "title" field is valid. + * GDK_WA_X: The "x" field is valid. + * GDK_WA_Y: The "y" field is valid. + * GDK_WA_CURSOR: The "cursor" field is valid. + * GDK_WA_COLORMAP: The "colormap" field is valid. + * GDK_WA_VISUAL: The "visual" field is valid. + */ +typedef enum +{ + GDK_WA_TITLE = 1 << 1, + GDK_WA_X = 1 << 2, + GDK_WA_Y = 1 << 3, + GDK_WA_CURSOR = 1 << 4, + GDK_WA_COLORMAP = 1 << 5, + GDK_WA_VISUAL = 1 << 6, + GDK_WA_WMCLASS = 1 << 7, + GDK_WA_NOREDIR = 1 << 8 +} GdkWindowAttributesType; + +/* Size restriction enumeration. + */ +typedef enum +{ + GDK_HINT_POS = 1 << 0, + GDK_HINT_MIN_SIZE = 1 << 1, + GDK_HINT_MAX_SIZE = 1 << 2, + GDK_HINT_BASE_SIZE = 1 << 3, + GDK_HINT_ASPECT = 1 << 4, + GDK_HINT_RESIZE_INC = 1 << 5 +} GdkWindowHints; + +/* GC function types. + * Copy: Overwrites destination pixels with the source pixels. + * Invert: Inverts the destination pixels. + * Xor: Xor's the destination pixels with the source pixels. + * Clear: set pixels to 0 + * And: source AND destination + * And Reverse: source AND (NOT destination) + * And Invert: (NOT source) AND destination + * Noop: destination + * Or: source OR destination + * Nor: (NOT source) AND (NOT destination) + * Equiv: (NOT source) XOR destination + * Xor Reverse: source OR (NOT destination) + * Copy Inverted: NOT source + * Xor Inverted: (NOT source) OR destination + * Nand: (NOT source) OR (NOT destination) + * Set: set pixels to 1 + */ +typedef enum +{ + GDK_COPY, + GDK_INVERT, + GDK_XOR, + GDK_CLEAR, + GDK_AND, + GDK_AND_REVERSE, + GDK_AND_INVERT, + GDK_NOOP, + GDK_OR, + GDK_EQUIV, + GDK_OR_REVERSE, + GDK_COPY_INVERT, + GDK_OR_INVERT, + GDK_NAND, + GDK_SET +} GdkFunction; + +/* GC fill types. + * Solid: + * Tiled: + * Stippled: + * OpaqueStippled: + */ +typedef enum +{ + GDK_SOLID, + GDK_TILED, + GDK_STIPPLED, + GDK_OPAQUE_STIPPLED +} GdkFill; + +/* GC fill rule for polygons + * EvenOddRule + * WindingRule + */ +typedef enum +{ + GDK_EVEN_ODD_RULE, + GDK_WINDING_RULE +} GdkFillRule; + +/* GC line styles + * Solid: + * OnOffDash: + * DoubleDash: + */ +typedef enum +{ + GDK_LINE_SOLID, + GDK_LINE_ON_OFF_DASH, + GDK_LINE_DOUBLE_DASH +} GdkLineStyle; + +/* GC cap styles + * CapNotLast: + * CapButt: + * CapRound: + * CapProjecting: + */ +typedef enum +{ + GDK_CAP_NOT_LAST, + GDK_CAP_BUTT, + GDK_CAP_ROUND, + GDK_CAP_PROJECTING +} GdkCapStyle; + +/* GC join styles + * JoinMiter: + * JoinRound: + * JoinBevel: + */ +typedef enum +{ + GDK_JOIN_MITER, + GDK_JOIN_ROUND, + GDK_JOIN_BEVEL +} GdkJoinStyle; + +/* Cursor types. + */ +typedef enum +{ +#include <gdk/gdkcursors.h> + GDK_LAST_CURSOR, + GDK_CURSOR_IS_PIXMAP = -1 +} GdkCursorType; + +typedef enum { + GDK_FILTER_CONTINUE, /* Event not handled, continue processesing */ + GDK_FILTER_TRANSLATE, /* Translated event stored */ + GDK_FILTER_REMOVE /* Terminate processing, removing event */ +} GdkFilterReturn; + +typedef enum { + GDK_VISIBILITY_UNOBSCURED, + GDK_VISIBILITY_PARTIAL, + GDK_VISIBILITY_FULLY_OBSCURED +} GdkVisibilityState; + +/* Event types. + * Nothing: No event occurred. + * Delete: A window delete event was sent by the window manager. + * The specified window should be deleted. + * Destroy: A window has been destroyed. + * Expose: Part of a window has been uncovered. + * NoExpose: Same as expose, but no expose event was generated. + * VisibilityNotify: A window has become fully/partially/not obscured. + * MotionNotify: The mouse has moved. + * ButtonPress: A mouse button was pressed. + * ButtonRelease: A mouse button was release. + * KeyPress: A key was pressed. + * KeyRelease: A key was released. + * EnterNotify: A window was entered. + * LeaveNotify: A window was exited. + * FocusChange: The focus window has changed. (The focus window gets + * keyboard events). + * Resize: A window has been resized. + * Map: A window has been mapped. (It is now visible on the screen). + * Unmap: A window has been unmapped. (It is no longer visible on + * the screen). + */ +typedef enum +{ + GDK_NOTHING = -1, + GDK_DELETE = 0, + GDK_DESTROY = 1, + GDK_EXPOSE = 2, + GDK_MOTION_NOTIFY = 3, + GDK_BUTTON_PRESS = 4, + GDK_2BUTTON_PRESS = 5, + GDK_3BUTTON_PRESS = 6, + GDK_BUTTON_RELEASE = 7, + GDK_KEY_PRESS = 8, + GDK_KEY_RELEASE = 9, + GDK_ENTER_NOTIFY = 10, + GDK_LEAVE_NOTIFY = 11, + GDK_FOCUS_CHANGE = 12, + GDK_CONFIGURE = 13, + GDK_MAP = 14, + GDK_UNMAP = 15, + GDK_PROPERTY_NOTIFY = 16, + GDK_SELECTION_CLEAR = 17, + GDK_SELECTION_REQUEST = 18, + GDK_SELECTION_NOTIFY = 19, + GDK_PROXIMITY_IN = 20, + GDK_PROXIMITY_OUT = 21, + GDK_DRAG_ENTER = 22, + GDK_DRAG_LEAVE = 23, + GDK_DRAG_MOTION = 24, + GDK_DRAG_STATUS = 25, + GDK_DROP_START = 26, + GDK_DROP_FINISHED = 27, + GDK_CLIENT_EVENT = 28, + GDK_VISIBILITY_NOTIFY = 29, + GDK_NO_EXPOSE = 30 +} GdkEventType; + +/* Event masks. (Used to select what types of events a window + * will receive). + */ +typedef enum +{ + GDK_EXPOSURE_MASK = 1 << 1, + GDK_POINTER_MOTION_MASK = 1 << 2, + GDK_POINTER_MOTION_HINT_MASK = 1 << 3, + GDK_BUTTON_MOTION_MASK = 1 << 4, + GDK_BUTTON1_MOTION_MASK = 1 << 5, + GDK_BUTTON2_MOTION_MASK = 1 << 6, + GDK_BUTTON3_MOTION_MASK = 1 << 7, + GDK_BUTTON_PRESS_MASK = 1 << 8, + GDK_BUTTON_RELEASE_MASK = 1 << 9, + GDK_KEY_PRESS_MASK = 1 << 10, + GDK_KEY_RELEASE_MASK = 1 << 11, + GDK_ENTER_NOTIFY_MASK = 1 << 12, + GDK_LEAVE_NOTIFY_MASK = 1 << 13, + GDK_FOCUS_CHANGE_MASK = 1 << 14, + GDK_STRUCTURE_MASK = 1 << 15, + GDK_PROPERTY_CHANGE_MASK = 1 << 16, + GDK_VISIBILITY_NOTIFY_MASK = 1 << 17, + GDK_PROXIMITY_IN_MASK = 1 << 18, + GDK_PROXIMITY_OUT_MASK = 1 << 19, + GDK_SUBSTRUCTURE_MASK = 1 << 20, + GDK_ALL_EVENTS_MASK = 0x0FFFFF +} GdkEventMask; + +/* Types of enter/leave notifications. + * Ancestor: + * Virtual: + * Inferior: + * Nonlinear: + * NonlinearVirtual: + * Unknown: An unknown type of enter/leave event occurred. + */ +typedef enum +{ + GDK_NOTIFY_ANCESTOR = 0, + GDK_NOTIFY_VIRTUAL = 1, + GDK_NOTIFY_INFERIOR = 2, + GDK_NOTIFY_NONLINEAR = 3, + GDK_NOTIFY_NONLINEAR_VIRTUAL = 4, + GDK_NOTIFY_UNKNOWN = 5 +} GdkNotifyType; + +/* Enter/leave event modes. + * NotifyNormal + * NotifyGrab + * NotifyUngrab + */ +typedef enum +{ + GDK_CROSSING_NORMAL, + GDK_CROSSING_GRAB, + GDK_CROSSING_UNGRAB +} GdkCrossingMode; + +/* Types of modifiers. + */ +typedef enum +{ + GDK_SHIFT_MASK = 1 << 0, + GDK_LOCK_MASK = 1 << 1, + GDK_CONTROL_MASK = 1 << 2, + GDK_MOD1_MASK = 1 << 3, + GDK_MOD2_MASK = 1 << 4, + GDK_MOD3_MASK = 1 << 5, + GDK_MOD4_MASK = 1 << 6, + GDK_MOD5_MASK = 1 << 7, + GDK_BUTTON1_MASK = 1 << 8, + GDK_BUTTON2_MASK = 1 << 9, + GDK_BUTTON3_MASK = 1 << 10, + GDK_BUTTON4_MASK = 1 << 11, + GDK_BUTTON5_MASK = 1 << 12, + GDK_RELEASE_MASK = 1 << 13, + GDK_MODIFIER_MASK = 0x3fff +} GdkModifierType; + +typedef enum +{ + GDK_CLIP_BY_CHILDREN = 0, + GDK_INCLUDE_INFERIORS = 1 +} GdkSubwindowMode; + +typedef enum +{ + GDK_INPUT_READ = 1 << 0, + GDK_INPUT_WRITE = 1 << 1, + GDK_INPUT_EXCEPTION = 1 << 2 +} GdkInputCondition; + +typedef enum +{ + GDK_OK = 0, + GDK_ERROR = -1, + GDK_ERROR_PARAM = -2, + GDK_ERROR_FILE = -3, + GDK_ERROR_MEM = -4 +} GdkStatus; + +typedef enum +{ + GDK_LSB_FIRST, + GDK_MSB_FIRST +} GdkByteOrder; + +typedef enum +{ + GDK_GC_FOREGROUND = 1 << 0, + GDK_GC_BACKGROUND = 1 << 1, + GDK_GC_FONT = 1 << 2, + GDK_GC_FUNCTION = 1 << 3, + GDK_GC_FILL = 1 << 4, + GDK_GC_TILE = 1 << 5, + GDK_GC_STIPPLE = 1 << 6, + GDK_GC_CLIP_MASK = 1 << 7, + GDK_GC_SUBWINDOW = 1 << 8, + GDK_GC_TS_X_ORIGIN = 1 << 9, + GDK_GC_TS_Y_ORIGIN = 1 << 10, + GDK_GC_CLIP_X_ORIGIN = 1 << 11, + GDK_GC_CLIP_Y_ORIGIN = 1 << 12, + GDK_GC_EXPOSURES = 1 << 13, + GDK_GC_LINE_WIDTH = 1 << 14, + GDK_GC_LINE_STYLE = 1 << 15, + GDK_GC_CAP_STYLE = 1 << 16, + GDK_GC_JOIN_STYLE = 1 << 17 +} GdkGCValuesMask; + +typedef enum +{ + GDK_SELECTION_PRIMARY = 1, + GDK_SELECTION_SECONDARY = 2 +} GdkSelection; + +typedef enum +{ + GDK_PROPERTY_NEW_VALUE, + GDK_PROPERTY_DELETE +} GdkPropertyState; + +typedef enum +{ + GDK_PROP_MODE_REPLACE, + GDK_PROP_MODE_PREPEND, + GDK_PROP_MODE_APPEND +} GdkPropMode; + +/* Enums for XInput support */ + +typedef enum +{ + GDK_SOURCE_MOUSE, + GDK_SOURCE_PEN, + GDK_SOURCE_ERASER, + GDK_SOURCE_CURSOR +} GdkInputSource; + +typedef enum +{ + GDK_MODE_DISABLED, + GDK_MODE_SCREEN, + GDK_MODE_WINDOW +} GdkInputMode; + +typedef enum +{ + GDK_AXIS_IGNORE, + GDK_AXIS_X, + GDK_AXIS_Y, + GDK_AXIS_PRESSURE, + GDK_AXIS_XTILT, + GDK_AXIS_YTILT, + GDK_AXIS_LAST +} GdkAxisUse; + +/* The next two types define enums for predefined atoms relating + to selections. In general, one will need to use gdk_intern_atom */ + +typedef enum +{ + GDK_TARGET_BITMAP = 5, + GDK_TARGET_COLORMAP = 7, + GDK_TARGET_DRAWABLE = 17, + GDK_TARGET_PIXMAP = 20, + GDK_TARGET_STRING = 31 +} GdkTarget; + +typedef enum +{ + GDK_SELECTION_TYPE_ATOM = 4, + GDK_SELECTION_TYPE_BITMAP = 5, + GDK_SELECTION_TYPE_COLORMAP = 7, + GDK_SELECTION_TYPE_DRAWABLE = 17, + GDK_SELECTION_TYPE_INTEGER = 19, + GDK_SELECTION_TYPE_PIXMAP = 20, + GDK_SELECTION_TYPE_WINDOW = 33, + GDK_SELECTION_TYPE_STRING = 31 +} GdkSelectionType; + +typedef enum +{ + GDK_EXTENSION_EVENTS_NONE, + GDK_EXTENSION_EVENTS_ALL, + GDK_EXTENSION_EVENTS_CURSOR +} GdkExtensionMode; + +typedef enum /*< flags >*/ +{ + GDK_IM_PREEDIT_AREA = 0x0001, + GDK_IM_PREEDIT_CALLBACKS = 0x0002, + GDK_IM_PREEDIT_POSITION = 0x0004, + GDK_IM_PREEDIT_NOTHING = 0x0008, + GDK_IM_PREEDIT_NONE = 0x0010, + GDK_IM_PREEDIT_MASK = 0x001f, + + GDK_IM_STATUS_AREA = 0x0100, + GDK_IM_STATUS_CALLBACKS = 0x0200, + GDK_IM_STATUS_NOTHING = 0x0400, + GDK_IM_STATUS_NONE = 0x0800, + GDK_IM_STATUS_MASK = 0x0f00 +} GdkIMStyle; + +typedef enum +{ + GDK_IC_STYLE = 1 << 0, + GDK_IC_CLIENT_WINDOW = 1 << 1, + GDK_IC_FOCUS_WINDOW = 1 << 2, + GDK_IC_FILTER_EVENTS = 1 << 3, + GDK_IC_SPOT_LOCATION = 1 << 4, + GDK_IC_LINE_SPACING = 1 << 5, + GDK_IC_CURSOR = 1 << 6, + + GDK_IC_PREEDIT_FONTSET = 1 << 10, + GDK_IC_PREEDIT_AREA = 1 << 11, + GDK_IC_PREEDIT_AREA_NEEDED = 1 << 12, + GDK_IC_PREEDIT_FOREGROUND = 1 << 13, + GDK_IC_PREEDIT_BACKGROUND = 1 << 14, + GDK_IC_PREEDIT_PIXMAP = 1 << 15, + GDK_IC_PREEDIT_COLORMAP = 1 << 16, + + GDK_IC_STATUS_FONTSET = 1 << 21, + GDK_IC_STATUS_AREA = 1 << 22, + GDK_IC_STATUS_AREA_NEEDED = 1 << 23, + GDK_IC_STATUS_FOREGROUND = 1 << 24, + GDK_IC_STATUS_BACKGROUND = 1 << 25, + GDK_IC_STATUS_PIXMAP = 1 << 26, + GDK_IC_STATUS_COLORMAP = 1 << 27, + + GDK_IC_ALL_REQ = GDK_IC_STYLE | + GDK_IC_CLIENT_WINDOW, + + GDK_IC_PREEDIT_AREA_REQ = GDK_IC_PREEDIT_AREA | + GDK_IC_PREEDIT_FONTSET, + GDK_IC_PREEDIT_POSITION_REQ = GDK_IC_PREEDIT_AREA | GDK_IC_SPOT_LOCATION | + GDK_IC_PREEDIT_FONTSET, + + GDK_IC_STATUS_AREA_REQ = GDK_IC_STATUS_AREA | + GDK_IC_STATUS_FONTSET +} GdkICAttributesType; + +/* The next two enumeration values current match the + * Motif constants. If this is changed, the implementation + * of gdk_window_set_decorations/gdk_window_set_functions + * will need to change as well. + */ +typedef enum +{ + GDK_DECOR_ALL = 1 << 0, + GDK_DECOR_BORDER = 1 << 1, + GDK_DECOR_RESIZEH = 1 << 2, + GDK_DECOR_TITLE = 1 << 3, + GDK_DECOR_MENU = 1 << 4, + GDK_DECOR_MINIMIZE = 1 << 5, + GDK_DECOR_MAXIMIZE = 1 << 6 +} GdkWMDecoration; + +typedef enum +{ + GDK_FUNC_ALL = 1 << 0, + GDK_FUNC_RESIZE = 1 << 1, + GDK_FUNC_MOVE = 1 << 2, + GDK_FUNC_MINIMIZE = 1 << 3, + GDK_FUNC_MAXIMIZE = 1 << 4, + GDK_FUNC_CLOSE = 1 << 5 +} GdkWMFunction; + +typedef void (*GdkInputFunction) (gpointer data, + gint source, + GdkInputCondition condition); + +typedef void (*GdkDestroyNotify) (gpointer data); + +/* Color Context modes. + * + * GDK_CC_MODE_UNDEFINED - unknown + * GDK_CC_MODE_BW - default B/W + * GDK_CC_MODE_STD_CMAP - has a standard colormap + * GDK_CC_MODE_TRUE - is a TrueColor/DirectColor visual + * GDK_CC_MODE_MY_GRAY - my grayramp + * GDK_CC_MODE_PALETTE - has a pre-allocated palette + */ + +typedef enum +{ + GDK_CC_MODE_UNDEFINED, + GDK_CC_MODE_BW, + GDK_CC_MODE_STD_CMAP, + GDK_CC_MODE_TRUE, + GDK_CC_MODE_MY_GRAY, + GDK_CC_MODE_PALETTE +} GdkColorContextMode; + +/* Types of overlapping between a rectangle and a region + * GDK_OVERLAP_RECTANGLE_IN: rectangle is in region + * GDK_OVERLAP_RECTANGLE_OUT: rectangle in not in region + * GDK_OVERLAP_RECTANGLE_PART: rectangle in partially in region + */ + +typedef enum +{ + GDK_OVERLAP_RECTANGLE_IN, + GDK_OVERLAP_RECTANGLE_OUT, + GDK_OVERLAP_RECTANGLE_PART +} GdkOverlapType; + +typedef enum { + GDK_ACTION_DEFAULT = 1 << 0, + GDK_ACTION_COPY = 1 << 1, + GDK_ACTION_MOVE = 1 << 2, + GDK_ACTION_LINK = 1 << 3, + GDK_ACTION_PRIVATE = 1 << 4, + GDK_ACTION_ASK = 1 << 5 +} GdkDragAction; + +typedef enum { + GDK_DRAG_PROTO_MOTIF, + GDK_DRAG_PROTO_XDND, + GDK_DRAG_PROTO_ROOTWIN, /* A root window with nobody claiming drags */ + GDK_DRAG_PROTO_WIN32_DROPFILES, /* The simple WM_DROPFILES dnd */ + GDK_DRAG_PROTO_OLE2, /* The complex OLE2 dnd */ + GDK_DRAG_PROTO_NONE /* Not a valid drag window */ +} GdkDragProtocol; + +/* The color type. + * A color consists of red, green and blue values in the + * range 0-65535 and a pixel value. The pixel value is highly + * dependent on the depth and colormap which this color will + * be used to draw into. Therefore, sharing colors between + * colormaps is a bad idea. + */ +struct _GdkColor +{ + gulong pixel; + gushort red; + gushort green; + gushort blue; +}; + +/* The colormap type. + * Colormaps consist of 256 colors. + */ +struct _GdkColormap +{ + gint size; + GdkColor *colors; +}; + +/* The visual type. + * "type" is the type of visual this is (PseudoColor, TrueColor, etc). + * "depth" is the bit depth of this visual. + * "colormap_size" is the size of a colormap for this visual. + * "bits_per_rgb" is the number of significant bits per red, green and blue. + * The red, green and blue masks, shifts and precisions refer + * to value needed to calculate pixel values in TrueColor and DirectColor + * visuals. The "mask" is the significant bits within the pixel. The + * "shift" is the number of bits left we must shift a primary for it + * to be in position (according to the "mask"). "prec" refers to how + * much precision the pixel value contains for a particular primary. + */ +struct _GdkVisual +{ + GdkVisualType type; + gint depth; + GdkByteOrder byte_order; + gint colormap_size; + gint bits_per_rgb; + + guint32 red_mask; + gint red_shift; + gint red_prec; + + guint32 green_mask; + gint green_shift; + gint green_prec; + + guint32 blue_mask; + gint blue_shift; + gint blue_prec; +}; + +struct _GdkWindowAttr +{ + gchar *title; + gint event_mask; + gint16 x, y; + gint16 width; + gint16 height; + GdkWindowClass wclass; + GdkVisual *visual; + GdkColormap *colormap; + GdkWindowType window_type; + GdkCursor *cursor; + gchar *wmclass_name; + gchar *wmclass_class; + gboolean override_redirect; +}; + +struct _GdkWindow +{ + gpointer user_data; +}; + +struct _GdkGeometry { + gint min_width; + gint min_height; + gint max_width; + gint max_height; + gint base_width; + gint base_height; + gint width_inc; + gint height_inc; + gdouble min_aspect; + gdouble max_aspect; + /* GdkGravity gravity; */ +}; + +struct _GdkImage +{ + GdkImageType type; + GdkVisual *visual; /* visual used to create the image */ + GdkByteOrder byte_order; + guint16 width; + guint16 height; + guint16 depth; + guint16 bpp; /* bytes per pixel */ + guint16 bpl; /* bytes per line */ + gpointer mem; +}; + +struct _GdkGCValues +{ + GdkColor foreground; + GdkColor background; + GdkFont *font; + GdkFunction function; + GdkFill fill; + GdkPixmap *tile; + GdkPixmap *stipple; + GdkPixmap *clip_mask; + GdkSubwindowMode subwindow_mode; + gint ts_x_origin; + gint ts_y_origin; + gint clip_x_origin; + gint clip_y_origin; + gint graphics_exposures; + gint line_width; + GdkLineStyle line_style; + GdkCapStyle cap_style; + GdkJoinStyle join_style; +}; + +struct _GdkGC +{ + gint dummy_var; +}; + +struct _GdkPoint +{ + gint16 x; + gint16 y; +}; + +struct _GdkRectangle +{ + gint16 x; + gint16 y; + guint16 width; + guint16 height; +}; + +struct _GdkSegment +{ + gint16 x1; + gint16 y1; + gint16 x2; + gint16 y2; +}; + +struct _GdkFont +{ + GdkFontType type; + gint ascent; + gint descent; +}; + +struct _GdkCursor +{ + GdkCursorType type; +}; + + +struct _GdkColorContextDither +{ + gint fast_rgb[32][32][32]; /* quick look-up table for faster rendering */ + gint fast_err[32][32][32]; /* internal RGB error information */ + gint fast_erg[32][32][32]; + gint fast_erb[32][32][32]; +}; + +struct _GdkColorContext +{ + GdkVisual *visual; + GdkColormap *colormap; + + gint num_colors; /* available no. of colors in colormap */ + gint max_colors; /* maximum no. of colors */ + gint num_allocated; /* no. of allocated colors */ + + GdkColorContextMode mode; + gint need_to_free_colormap; + GdkAtom std_cmap_atom; + + gulong *clut; /* color look-up table */ + GdkColor *cmap; /* colormap */ + + GHashTable *color_hash; /* hash table of allocated colors */ + GdkColor *palette; /* preallocated palette */ + gint num_palette; /* size of palette */ + + GdkColorContextDither *fast_dither; /* fast dither matrix */ + + struct + { + gint red; + gint green; + gint blue; + } shifts; + + struct + { + gulong red; + gulong green; + gulong blue; + } masks; + + struct + { + gint red; + gint green; + gint blue; + } bits; + + gulong max_entry; + + gulong black_pixel; + gulong white_pixel; +}; + +/* Types for XInput support */ + +struct _GdkDeviceKey +{ + guint keyval; + GdkModifierType modifiers; +}; + +struct _GdkDeviceInfo +{ + guint32 deviceid; + gchar *name; + GdkInputSource source; + GdkInputMode mode; + gint has_cursor; /* TRUE if the X pointer follows device motion */ + gint num_axes; + GdkAxisUse *axes; /* Specifies use for each axis */ + gint num_keys; + GdkDeviceKey *keys; +}; + +struct _GdkTimeCoord +{ + guint32 time; + gdouble x; + gdouble y; + gdouble pressure; + gdouble xtilt; + gdouble ytilt; +}; + +/* Structure that holds information about a drag in progress. + * this is used on both source and destination sides. + */ +struct _GdkDragContext { + GdkDragProtocol protocol; + + gboolean is_source; + + GdkWindow *source_window; + GdkWindow *dest_window; + + GList *targets; + GdkDragAction actions; + GdkDragAction suggested_action; + GdkDragAction action; + + guint32 start_time; +}; + +/* Event filtering */ + +typedef void GdkXEvent; /* Can be cast to XEvent */ + +typedef GdkFilterReturn (*GdkFilterFunc) (GdkXEvent *xevent, + GdkEvent *event, + gpointer data); + +struct _GdkEventAny +{ + GdkEventType type; + GdkWindow *window; + gint8 send_event; +}; + +struct _GdkEventExpose +{ + GdkEventType type; + GdkWindow *window; + gint8 send_event; + GdkRectangle area; + gint count; /* If non-zero, how many more events follow. */ +}; + +struct _GdkEventNoExpose +{ + GdkEventType type; + GdkWindow *window; + gint8 send_event; + /* XXX: does anyone need the X major_code or minor_code fields? */ +}; + +struct _GdkEventVisibility +{ + GdkEventType type; + GdkWindow *window; + gint8 send_event; + GdkVisibilityState state; +}; + +struct _GdkEventMotion +{ + GdkEventType type; + GdkWindow *window; + gint8 send_event; + guint32 time; + gdouble x; + gdouble y; + gdouble pressure; + gdouble xtilt; + gdouble ytilt; + guint state; + gint16 is_hint; + GdkInputSource source; + guint32 deviceid; + gdouble x_root, y_root; +}; + +struct _GdkEventButton +{ + GdkEventType type; + GdkWindow *window; + gint8 send_event; + guint32 time; + gdouble x; + gdouble y; + gdouble pressure; + gdouble xtilt; + gdouble ytilt; + guint state; + guint button; + GdkInputSource source; + guint32 deviceid; + gdouble x_root, y_root; +}; + +struct _GdkEventKey +{ + GdkEventType type; + GdkWindow *window; + gint8 send_event; + guint32 time; + guint state; + guint keyval; + gint length; + gchar *string; +}; + +struct _GdkEventCrossing +{ + GdkEventType type; + GdkWindow *window; + gint8 send_event; + GdkWindow *subwindow; + guint32 time; + gdouble x; + gdouble y; + gdouble x_root; + gdouble y_root; + GdkCrossingMode mode; + GdkNotifyType detail; + gboolean focus; + guint state; +}; + +struct _GdkEventFocus +{ + GdkEventType type; + GdkWindow *window; + gint8 send_event; + gint16 in; +}; + +struct _GdkEventConfigure +{ + GdkEventType type; + GdkWindow *window; + gint8 send_event; + gint16 x, y; + gint16 width; + gint16 height; +}; + +struct _GdkEventProperty +{ + GdkEventType type; + GdkWindow *window; + gint8 send_event; + GdkAtom atom; + guint32 time; + guint state; +}; + +struct _GdkEventSelection +{ + GdkEventType type; + GdkWindow *window; + gint8 send_event; + GdkAtom selection; + GdkAtom target; + GdkAtom property; + guint32 requestor; + guint32 time; +}; + +/* This event type will be used pretty rarely. It only is important + for XInput aware programs that are drawing their own cursor */ + +struct _GdkEventProximity +{ + GdkEventType type; + GdkWindow *window; + gint8 send_event; + guint32 time; + GdkInputSource source; + guint32 deviceid; +}; + +struct _GdkEventClient +{ + GdkEventType type; + GdkWindow *window; + gint8 send_event; + GdkAtom message_type; + gushort data_format; + union { + char b[20]; + short s[10]; + long l[5]; + } data; +}; + +/* Event types for DND */ + +struct _GdkEventDND { + GdkEventType type; + GdkWindow *window; + gint8 send_event; + GdkDragContext *context; + + guint32 time; + gshort x_root, y_root; +}; + +union _GdkEvent +{ + GdkEventType type; + GdkEventAny any; + GdkEventExpose expose; + GdkEventNoExpose no_expose; + GdkEventVisibility visibility; + GdkEventMotion motion; + GdkEventButton button; + GdkEventKey key; + GdkEventCrossing crossing; + GdkEventFocus focus_change; + GdkEventConfigure configure; + GdkEventProperty property; + GdkEventSelection selection; + GdkEventProximity proximity; + GdkEventClient client; + GdkEventDND dnd; +}; + +struct _GdkRegion +{ + gpointer user_data; +}; + +struct _GdkICAttr +{ + GdkIMStyle style; + GdkWindow *client_window; + GdkWindow *focus_window; + GdkEventMask filter_events; + GdkPoint spot_location; + gint line_spacing; + GdkCursor *cursor; + + GdkFont *preedit_fontset; + GdkRectangle preedit_area; + GdkRectangle preedit_area_needed; + GdkColor preedit_foreground; + GdkColor preedit_background; + GdkPixmap *preedit_pixmap; + GdkColormap *preedit_colormap; + + GdkFont *status_fontset; + GdkRectangle status_area; + GdkRectangle status_area_needed; + GdkColor status_foreground; + GdkColor status_background; + GdkPixmap *status_pixmap; + GdkColormap *status_colormap; +}; + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GDK_TYPES_H__ */ diff --git a/gdk/win32/gdkvisual-win32.c b/gdk/win32/gdkvisual-win32.c new file mode 100644 index 000000000..e207fde7b --- /dev/null +++ b/gdk/win32/gdkvisual-win32.c @@ -0,0 +1,527 @@ +/* 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" +#include "gdkx.h" + +static void gdk_visual_add (GdkVisual *visual); +static void gdk_visual_decompose_mask (gulong mask, + gint *shift, + gint *prec); +static guint gdk_visual_hash (Visual *key); +static gint gdk_visual_compare (Visual *a, + Visual *b); + + +static GdkVisualPrivate *system_visual; +static GdkVisualPrivate *visuals; +static gint nvisuals; + +static gint available_depths[7]; +static gint navailable_depths; + +static GdkVisualType available_types[6]; +static gint navailable_types; + +#ifdef G_ENABLE_DEBUG + +static const gchar* visual_names[] = +{ + "static gray", + "grayscale", + "static color", + "pseudo color", + "true color", + "direct color", +}; + +#endif /* G_ENABLE_DEBUG */ + +static GHashTable *visual_hash = NULL; + +void +gdk_visual_init (void) +{ + struct + { + BITMAPINFOHEADER bi; + union + { + RGBQUAD colors[256]; + DWORD fields[256]; + } u; + } bmi; + HBITMAP hbm; + + static const gint possible_depths[7] = { 32, 24, 16, 15, 8, 4, 1 }; + static const GdkVisualType possible_types[6] = + { + GDK_VISUAL_DIRECT_COLOR, + GDK_VISUAL_TRUE_COLOR, + GDK_VISUAL_PSEUDO_COLOR, + GDK_VISUAL_STATIC_COLOR, + GDK_VISUAL_GRAYSCALE, + GDK_VISUAL_STATIC_GRAY + }; + + static const gint npossible_depths = sizeof(possible_depths)/sizeof(gint); + static const gint npossible_types = sizeof(possible_types)/sizeof(GdkVisualType); + + int rastercaps, numcolors, sizepalette, colorres, bitspixel; + Visual *default_xvisual; + GdkVisualPrivate temp_visual; + int nxvisuals; + int i, j; + + nxvisuals = 1; + visuals = g_new (GdkVisualPrivate, nxvisuals); + + nvisuals = 0; + for (i = 0; i < nxvisuals; i++) + { + if (1) + { + bitspixel = GetDeviceCaps (gdk_DC, BITSPIXEL); + rastercaps = GetDeviceCaps (gdk_DC, RASTERCAPS); + default_xvisual = g_new (Visual, 1); + visuals[nvisuals].xvisual = default_xvisual; + visuals[nvisuals].xvisual->visualid = nvisuals; + visuals[nvisuals].xvisual->bitspixel = bitspixel; + + if (rastercaps & RC_PALETTE) + { + visuals[nvisuals].visual.type = GDK_VISUAL_PSEUDO_COLOR; + numcolors = GetDeviceCaps (gdk_DC, NUMCOLORS); + sizepalette = GetDeviceCaps (gdk_DC, SIZEPALETTE); + colorres = GetDeviceCaps (gdk_DC, COLORRES); + visuals[nvisuals].xvisual->map_entries = sizepalette; + } + else if (bitspixel == 1) + { + visuals[nvisuals].visual.type = GDK_VISUAL_STATIC_GRAY; + visuals[nvisuals].xvisual->map_entries = 2; + } + else if (bitspixel == 4) + { + visuals[nvisuals].visual.type = GDK_VISUAL_STATIC_COLOR; + visuals[nvisuals].xvisual->map_entries = 16; + } + else if (bitspixel == 8) + { + visuals[nvisuals].visual.type = GDK_VISUAL_STATIC_COLOR; + visuals[nvisuals].xvisual->map_entries = 256; + } + else if (bitspixel == 16) + { + visuals[nvisuals].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; + visuals[nvisuals].visual.red_mask = 0x00007C00; + visuals[nvisuals].visual.green_mask = 0x000003E0; + visuals[nvisuals].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; + visuals[nvisuals].visual.red_mask = bmi.u.fields[0]; + visuals[nvisuals].visual.green_mask = bmi.u.fields[1]; + visuals[nvisuals].visual.blue_mask = bmi.u.fields[2]; + } +#else + /* Old, incorrect (but still working) code. */ +#if 0 + visuals[nvisuals].visual.red_mask = 0x0000F800; + visuals[nvisuals].visual.green_mask = 0x000007E0; + visuals[nvisuals].visual.blue_mask = 0x0000001F; +#else + visuals[nvisuals].visual.red_mask = 0x00007C00; + visuals[nvisuals].visual.green_mask = 0x000003E0; + visuals[nvisuals].visual.blue_mask = 0x0000001F; +#endif +#endif + } + else if (bitspixel == 24 || bitspixel == 32) + { + visuals[nvisuals].visual.type = GDK_VISUAL_TRUE_COLOR; + visuals[nvisuals].visual.red_mask = 0x00FF0000; + visuals[nvisuals].visual.green_mask = 0x0000FF00; + visuals[nvisuals].visual.blue_mask = 0x000000FF; + } + else + g_error ("gdk_visual_init: unsupported BITSPIXEL: %d\n", bitspixel); + + visuals[nvisuals].visual.depth = bitspixel; + visuals[nvisuals].visual.byte_order = GDK_LSB_FIRST; + visuals[nvisuals].visual.bits_per_rgb = 42; /* Not used? */ + + if ((visuals[nvisuals].visual.type == GDK_VISUAL_TRUE_COLOR) || + (visuals[nvisuals].visual.type == GDK_VISUAL_DIRECT_COLOR)) + { + gdk_visual_decompose_mask (visuals[nvisuals].visual.red_mask, + &visuals[nvisuals].visual.red_shift, + &visuals[nvisuals].visual.red_prec); + + gdk_visual_decompose_mask (visuals[nvisuals].visual.green_mask, + &visuals[nvisuals].visual.green_shift, + &visuals[nvisuals].visual.green_prec); + + gdk_visual_decompose_mask (visuals[nvisuals].visual.blue_mask, + &visuals[nvisuals].visual.blue_shift, + &visuals[nvisuals].visual.blue_prec); + visuals[nvisuals].xvisual->map_entries = + 1 << (MAX (visuals[nvisuals].visual.red_prec, + MAX (visuals[nvisuals].visual.green_prec, + visuals[nvisuals].visual.blue_prec))); + } + else + { + visuals[nvisuals].visual.red_mask = 0; + visuals[nvisuals].visual.red_shift = 0; + visuals[nvisuals].visual.red_prec = 0; + + visuals[nvisuals].visual.green_mask = 0; + visuals[nvisuals].visual.green_shift = 0; + visuals[nvisuals].visual.green_prec = 0; + + visuals[nvisuals].visual.blue_mask = 0; + visuals[nvisuals].visual.blue_shift = 0; + visuals[nvisuals].visual.blue_prec = 0; + } + visuals[nvisuals].visual.colormap_size = visuals[nvisuals].xvisual->map_entries; + + nvisuals += 1; + } + } + + for (i = 0; i < nvisuals; i++) + { + for (j = i+1; j < nvisuals; j++) + { + if (visuals[j].visual.depth >= visuals[i].visual.depth) + { + if ((visuals[j].visual.depth == 8) && (visuals[i].visual.depth == 8)) + { + if (visuals[j].visual.type == GDK_VISUAL_PSEUDO_COLOR) + { + temp_visual = visuals[j]; + visuals[j] = visuals[i]; + visuals[i] = temp_visual; + } + else if ((visuals[i].visual.type != GDK_VISUAL_PSEUDO_COLOR) && + visuals[j].visual.type > visuals[i].visual.type) + { + temp_visual = visuals[j]; + visuals[j] = visuals[i]; + visuals[i] = temp_visual; + } + } + else if ((visuals[j].visual.depth > visuals[i].visual.depth) || + ((visuals[j].visual.depth == visuals[i].visual.depth) && + (visuals[j].visual.type > visuals[i].visual.type))) + { + temp_visual = visuals[j]; + visuals[j] = visuals[i]; + visuals[i] = temp_visual; + } + } + } + } + + for (i = 0; i < nvisuals; i++) + if (default_xvisual->visualid == visuals[i].xvisual->visualid) + { + system_visual = &visuals[i]; + break; + } + + navailable_depths = 0; + for (i = 0; i < npossible_depths; i++) + { + for (j = 0; j < nvisuals; j++) + { + if (visuals[j].visual.depth == possible_depths[i]) + { + available_depths[navailable_depths++] = visuals[j].visual.depth; + break; + } + } + } + + if (navailable_depths == 0) + g_error ("unable to find a usable depth"); + + navailable_types = 0; + for (i = 0; i < npossible_types; i++) + { + for (j = 0; j < nvisuals; j++) + { + if (visuals[j].visual.type == possible_types[i]) + { + available_types[navailable_types++] = visuals[j].visual.type; + break; + } + } + } + + for (i = 0; i < nvisuals; i++) + gdk_visual_add ((GdkVisual*) &visuals[i]); + + if (npossible_types == 0) + g_error ("unable to find a usable 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*) &(visuals[0])); +} + +GdkVisual* +gdk_visual_get_best_with_depth (gint depth) +{ + GdkVisual *return_val; + int i; + + return_val = NULL; + for (i = 0; i < nvisuals; i++) + if (depth == visuals[i].visual.depth) + { + return_val = (GdkVisual*) &(visuals[i]); + break; + } + + return return_val; +} + +GdkVisual* +gdk_visual_get_best_with_type (GdkVisualType visual_type) +{ + GdkVisual *return_val; + int i; + + return_val = NULL; + for (i = 0; i < nvisuals; i++) + if (visual_type == visuals[i].visual.type) + { + return_val = (GdkVisual*) &(visuals[i]); + break; + } + + return return_val; +} + +GdkVisual* +gdk_visual_get_best_with_both (gint depth, + GdkVisualType visual_type) +{ + GdkVisual *return_val; + int i; + + return_val = NULL; + for (i = 0; i < nvisuals; i++) + if ((depth == visuals[i].visual.depth) && + (visual_type == visuals[i].visual.type)) + { + return_val = (GdkVisual*) &(visuals[i]); + break; + } + + return return_val; +} + +void +gdk_query_depths (gint **depths, + gint *count) +{ + *count = navailable_depths; + *depths = available_depths; +} + +void +gdk_query_visual_types (GdkVisualType **visual_types, + gint *count) +{ + *count = navailable_types; + *visual_types = available_types; +} + +GList* +gdk_list_visuals (void) +{ + GList *list; + guint i; + + list = NULL; + for (i = 0; i < nvisuals; ++i) + list = g_list_append (list, (gpointer) &visuals[i]); + + return list; +} + +GdkVisual* +gdk_visual_lookup (Visual *xvisual) +{ + GdkVisual *visual; + + if (!visual_hash) + return NULL; + + visual = g_hash_table_lookup (visual_hash, xvisual); + return visual; +} + +GdkVisual* +gdkx_visual_get (VisualID xvisualid) +{ + int i; + + for (i = 0; i < nvisuals; i++) + if (xvisualid == visuals[i].xvisual->visualid) + return (GdkVisual*) &visuals[i]; + + return NULL; +} + +static void +gdk_visual_add (GdkVisual *visual) +{ + GdkVisualPrivate *private; + + if (!visual_hash) + visual_hash = g_hash_table_new ((GHashFunc) gdk_visual_hash, + (GCompareFunc) gdk_visual_compare); + + private = (GdkVisualPrivate*) visual; + + g_hash_table_insert (visual_hash, private->xvisual, visual); +} + +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; + } +} + +/* This hash stuff is pretty useless on Windows, as there is only + one visual... */ + +static guint +gdk_visual_hash (Visual *key) +{ + return key->visualid; +} + +static gint +gdk_visual_compare (Visual *a, + Visual *b) +{ + return (a->visualid == b->visualid); +} diff --git a/gdk/win32/gdkvisual.c b/gdk/win32/gdkvisual.c new file mode 100644 index 000000000..e207fde7b --- /dev/null +++ b/gdk/win32/gdkvisual.c @@ -0,0 +1,527 @@ +/* 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" +#include "gdkx.h" + +static void gdk_visual_add (GdkVisual *visual); +static void gdk_visual_decompose_mask (gulong mask, + gint *shift, + gint *prec); +static guint gdk_visual_hash (Visual *key); +static gint gdk_visual_compare (Visual *a, + Visual *b); + + +static GdkVisualPrivate *system_visual; +static GdkVisualPrivate *visuals; +static gint nvisuals; + +static gint available_depths[7]; +static gint navailable_depths; + +static GdkVisualType available_types[6]; +static gint navailable_types; + +#ifdef G_ENABLE_DEBUG + +static const gchar* visual_names[] = +{ + "static gray", + "grayscale", + "static color", + "pseudo color", + "true color", + "direct color", +}; + +#endif /* G_ENABLE_DEBUG */ + +static GHashTable *visual_hash = NULL; + +void +gdk_visual_init (void) +{ + struct + { + BITMAPINFOHEADER bi; + union + { + RGBQUAD colors[256]; + DWORD fields[256]; + } u; + } bmi; + HBITMAP hbm; + + static const gint possible_depths[7] = { 32, 24, 16, 15, 8, 4, 1 }; + static const GdkVisualType possible_types[6] = + { + GDK_VISUAL_DIRECT_COLOR, + GDK_VISUAL_TRUE_COLOR, + GDK_VISUAL_PSEUDO_COLOR, + GDK_VISUAL_STATIC_COLOR, + GDK_VISUAL_GRAYSCALE, + GDK_VISUAL_STATIC_GRAY + }; + + static const gint npossible_depths = sizeof(possible_depths)/sizeof(gint); + static const gint npossible_types = sizeof(possible_types)/sizeof(GdkVisualType); + + int rastercaps, numcolors, sizepalette, colorres, bitspixel; + Visual *default_xvisual; + GdkVisualPrivate temp_visual; + int nxvisuals; + int i, j; + + nxvisuals = 1; + visuals = g_new (GdkVisualPrivate, nxvisuals); + + nvisuals = 0; + for (i = 0; i < nxvisuals; i++) + { + if (1) + { + bitspixel = GetDeviceCaps (gdk_DC, BITSPIXEL); + rastercaps = GetDeviceCaps (gdk_DC, RASTERCAPS); + default_xvisual = g_new (Visual, 1); + visuals[nvisuals].xvisual = default_xvisual; + visuals[nvisuals].xvisual->visualid = nvisuals; + visuals[nvisuals].xvisual->bitspixel = bitspixel; + + if (rastercaps & RC_PALETTE) + { + visuals[nvisuals].visual.type = GDK_VISUAL_PSEUDO_COLOR; + numcolors = GetDeviceCaps (gdk_DC, NUMCOLORS); + sizepalette = GetDeviceCaps (gdk_DC, SIZEPALETTE); + colorres = GetDeviceCaps (gdk_DC, COLORRES); + visuals[nvisuals].xvisual->map_entries = sizepalette; + } + else if (bitspixel == 1) + { + visuals[nvisuals].visual.type = GDK_VISUAL_STATIC_GRAY; + visuals[nvisuals].xvisual->map_entries = 2; + } + else if (bitspixel == 4) + { + visuals[nvisuals].visual.type = GDK_VISUAL_STATIC_COLOR; + visuals[nvisuals].xvisual->map_entries = 16; + } + else if (bitspixel == 8) + { + visuals[nvisuals].visual.type = GDK_VISUAL_STATIC_COLOR; + visuals[nvisuals].xvisual->map_entries = 256; + } + else if (bitspixel == 16) + { + visuals[nvisuals].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; + visuals[nvisuals].visual.red_mask = 0x00007C00; + visuals[nvisuals].visual.green_mask = 0x000003E0; + visuals[nvisuals].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; + visuals[nvisuals].visual.red_mask = bmi.u.fields[0]; + visuals[nvisuals].visual.green_mask = bmi.u.fields[1]; + visuals[nvisuals].visual.blue_mask = bmi.u.fields[2]; + } +#else + /* Old, incorrect (but still working) code. */ +#if 0 + visuals[nvisuals].visual.red_mask = 0x0000F800; + visuals[nvisuals].visual.green_mask = 0x000007E0; + visuals[nvisuals].visual.blue_mask = 0x0000001F; +#else + visuals[nvisuals].visual.red_mask = 0x00007C00; + visuals[nvisuals].visual.green_mask = 0x000003E0; + visuals[nvisuals].visual.blue_mask = 0x0000001F; +#endif +#endif + } + else if (bitspixel == 24 || bitspixel == 32) + { + visuals[nvisuals].visual.type = GDK_VISUAL_TRUE_COLOR; + visuals[nvisuals].visual.red_mask = 0x00FF0000; + visuals[nvisuals].visual.green_mask = 0x0000FF00; + visuals[nvisuals].visual.blue_mask = 0x000000FF; + } + else + g_error ("gdk_visual_init: unsupported BITSPIXEL: %d\n", bitspixel); + + visuals[nvisuals].visual.depth = bitspixel; + visuals[nvisuals].visual.byte_order = GDK_LSB_FIRST; + visuals[nvisuals].visual.bits_per_rgb = 42; /* Not used? */ + + if ((visuals[nvisuals].visual.type == GDK_VISUAL_TRUE_COLOR) || + (visuals[nvisuals].visual.type == GDK_VISUAL_DIRECT_COLOR)) + { + gdk_visual_decompose_mask (visuals[nvisuals].visual.red_mask, + &visuals[nvisuals].visual.red_shift, + &visuals[nvisuals].visual.red_prec); + + gdk_visual_decompose_mask (visuals[nvisuals].visual.green_mask, + &visuals[nvisuals].visual.green_shift, + &visuals[nvisuals].visual.green_prec); + + gdk_visual_decompose_mask (visuals[nvisuals].visual.blue_mask, + &visuals[nvisuals].visual.blue_shift, + &visuals[nvisuals].visual.blue_prec); + visuals[nvisuals].xvisual->map_entries = + 1 << (MAX (visuals[nvisuals].visual.red_prec, + MAX (visuals[nvisuals].visual.green_prec, + visuals[nvisuals].visual.blue_prec))); + } + else + { + visuals[nvisuals].visual.red_mask = 0; + visuals[nvisuals].visual.red_shift = 0; + visuals[nvisuals].visual.red_prec = 0; + + visuals[nvisuals].visual.green_mask = 0; + visuals[nvisuals].visual.green_shift = 0; + visuals[nvisuals].visual.green_prec = 0; + + visuals[nvisuals].visual.blue_mask = 0; + visuals[nvisuals].visual.blue_shift = 0; + visuals[nvisuals].visual.blue_prec = 0; + } + visuals[nvisuals].visual.colormap_size = visuals[nvisuals].xvisual->map_entries; + + nvisuals += 1; + } + } + + for (i = 0; i < nvisuals; i++) + { + for (j = i+1; j < nvisuals; j++) + { + if (visuals[j].visual.depth >= visuals[i].visual.depth) + { + if ((visuals[j].visual.depth == 8) && (visuals[i].visual.depth == 8)) + { + if (visuals[j].visual.type == GDK_VISUAL_PSEUDO_COLOR) + { + temp_visual = visuals[j]; + visuals[j] = visuals[i]; + visuals[i] = temp_visual; + } + else if ((visuals[i].visual.type != GDK_VISUAL_PSEUDO_COLOR) && + visuals[j].visual.type > visuals[i].visual.type) + { + temp_visual = visuals[j]; + visuals[j] = visuals[i]; + visuals[i] = temp_visual; + } + } + else if ((visuals[j].visual.depth > visuals[i].visual.depth) || + ((visuals[j].visual.depth == visuals[i].visual.depth) && + (visuals[j].visual.type > visuals[i].visual.type))) + { + temp_visual = visuals[j]; + visuals[j] = visuals[i]; + visuals[i] = temp_visual; + } + } + } + } + + for (i = 0; i < nvisuals; i++) + if (default_xvisual->visualid == visuals[i].xvisual->visualid) + { + system_visual = &visuals[i]; + break; + } + + navailable_depths = 0; + for (i = 0; i < npossible_depths; i++) + { + for (j = 0; j < nvisuals; j++) + { + if (visuals[j].visual.depth == possible_depths[i]) + { + available_depths[navailable_depths++] = visuals[j].visual.depth; + break; + } + } + } + + if (navailable_depths == 0) + g_error ("unable to find a usable depth"); + + navailable_types = 0; + for (i = 0; i < npossible_types; i++) + { + for (j = 0; j < nvisuals; j++) + { + if (visuals[j].visual.type == possible_types[i]) + { + available_types[navailable_types++] = visuals[j].visual.type; + break; + } + } + } + + for (i = 0; i < nvisuals; i++) + gdk_visual_add ((GdkVisual*) &visuals[i]); + + if (npossible_types == 0) + g_error ("unable to find a usable 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*) &(visuals[0])); +} + +GdkVisual* +gdk_visual_get_best_with_depth (gint depth) +{ + GdkVisual *return_val; + int i; + + return_val = NULL; + for (i = 0; i < nvisuals; i++) + if (depth == visuals[i].visual.depth) + { + return_val = (GdkVisual*) &(visuals[i]); + break; + } + + return return_val; +} + +GdkVisual* +gdk_visual_get_best_with_type (GdkVisualType visual_type) +{ + GdkVisual *return_val; + int i; + + return_val = NULL; + for (i = 0; i < nvisuals; i++) + if (visual_type == visuals[i].visual.type) + { + return_val = (GdkVisual*) &(visuals[i]); + break; + } + + return return_val; +} + +GdkVisual* +gdk_visual_get_best_with_both (gint depth, + GdkVisualType visual_type) +{ + GdkVisual *return_val; + int i; + + return_val = NULL; + for (i = 0; i < nvisuals; i++) + if ((depth == visuals[i].visual.depth) && + (visual_type == visuals[i].visual.type)) + { + return_val = (GdkVisual*) &(visuals[i]); + break; + } + + return return_val; +} + +void +gdk_query_depths (gint **depths, + gint *count) +{ + *count = navailable_depths; + *depths = available_depths; +} + +void +gdk_query_visual_types (GdkVisualType **visual_types, + gint *count) +{ + *count = navailable_types; + *visual_types = available_types; +} + +GList* +gdk_list_visuals (void) +{ + GList *list; + guint i; + + list = NULL; + for (i = 0; i < nvisuals; ++i) + list = g_list_append (list, (gpointer) &visuals[i]); + + return list; +} + +GdkVisual* +gdk_visual_lookup (Visual *xvisual) +{ + GdkVisual *visual; + + if (!visual_hash) + return NULL; + + visual = g_hash_table_lookup (visual_hash, xvisual); + return visual; +} + +GdkVisual* +gdkx_visual_get (VisualID xvisualid) +{ + int i; + + for (i = 0; i < nvisuals; i++) + if (xvisualid == visuals[i].xvisual->visualid) + return (GdkVisual*) &visuals[i]; + + return NULL; +} + +static void +gdk_visual_add (GdkVisual *visual) +{ + GdkVisualPrivate *private; + + if (!visual_hash) + visual_hash = g_hash_table_new ((GHashFunc) gdk_visual_hash, + (GCompareFunc) gdk_visual_compare); + + private = (GdkVisualPrivate*) visual; + + g_hash_table_insert (visual_hash, private->xvisual, visual); +} + +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; + } +} + +/* This hash stuff is pretty useless on Windows, as there is only + one visual... */ + +static guint +gdk_visual_hash (Visual *key) +{ + return key->visualid; +} + +static gint +gdk_visual_compare (Visual *a, + Visual *b) +{ + return (a->visualid == b->visualid); +} diff --git a/gdk/win32/gdkwin32.h b/gdk/win32/gdkwin32.h new file mode 100644 index 000000000..508619114 --- /dev/null +++ b/gdk/win32/gdkwin32.h @@ -0,0 +1,59 @@ +/* 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_X_H__ +#define __GDK_X_H__ + +#include <gdk/gdk.h> +#include <gdk/gdkprivate.h> + +#include <time.h> +#include <locale.h> + +#define GDK_ROOT_WINDOW() ((guint32) HWND_DESKTOP) +#define GDK_ROOT_PARENT() ((GdkWindow *)&gdk_root_parent) +#define GDK_DISPLAY() NULL +#define GDK_WINDOW_XDISPLAY(win) NULL +#define GDK_WINDOW_XWINDOW(win) (((GdkWindowPrivate*) win)->xwindow) +#define GDK_IMAGE_XDISPLAY(image) NULL +#define GDK_IMAGE_XIMAGE(image) (((GdkImagePrivate*) image)->ximage) +#define GDK_GC_XDISPLAY(gc) NULL +#define GDK_GC_XGC(gc) (((GdkGCPrivate*) gc)->xgc) +#define GDK_COLORMAP_XDISPLAY(cmap) NULL +#define GDK_COLORMAP_XCOLORMAP(cmap) (((GdkColormapPrivate*) cmap)->xcolormap) +#define GDK_VISUAL_XVISUAL(vis) (((GdkVisualPrivate*) vis)->xvisual) +#define GDK_FONT_XDISPLAY(font) NULL +#define GDK_FONT_XFONT(font) (((GdkFontPrivate*) font)->xfont) + +GdkVisual* gdkx_visual_get (VisualID xvisualid); +/* XXX: Do not use this function until it is fixed. An X Colormap + * is useless unless we also have the visual. */ +GdkColormap* gdkx_colormap_get (Colormap xcolormap); +/* Functions to create GDK pixmaps and windows from their native equivalents */ +GdkPixmap *gdk_pixmap_foreign_new (guint32 anid); +GdkWindow *gdk_window_foreign_new (guint32 anid); + +#endif /* __GDK_X_H__ */ diff --git a/gdk/win32/gdkwin32id.c b/gdk/win32/gdkwin32id.c new file mode 100644 index 000000000..f6d7bf0f4 --- /dev/null +++ b/gdk/win32/gdkwin32id.c @@ -0,0 +1,87 @@ +/* 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" +#include <stdio.h> + +static guint gdk_xid_hash (XID *xid); +static gint gdk_xid_compare (XID *a, + XID *b); + + +static GHashTable *xid_ht = NULL; + + +void +gdk_xid_table_insert (XID *xid, + gpointer data) +{ + g_return_if_fail (xid != NULL); + + if (!xid_ht) + xid_ht = g_hash_table_new ((GHashFunc) gdk_xid_hash, + (GCompareFunc) gdk_xid_compare); + + g_hash_table_insert (xid_ht, xid, data); +} + +void +gdk_xid_table_remove (XID xid) +{ + if (!xid_ht) + xid_ht = g_hash_table_new ((GHashFunc) gdk_xid_hash, + (GCompareFunc) gdk_xid_compare); + + g_hash_table_remove (xid_ht, &xid); +} + +gpointer +gdk_xid_table_lookup (XID xid) +{ + gpointer data = NULL; + + if (xid_ht) + data = g_hash_table_lookup (xid_ht, &xid); + + return data; +} + + +static guint +gdk_xid_hash (XID *xid) +{ + return (guint) *xid; +} + +static gint +gdk_xid_compare (XID *a, + XID *b) +{ + return (*a == *b); +} diff --git a/gdk/win32/gdkwindow-win32.c b/gdk/win32/gdkwindow-win32.c new file mode 100644 index 000000000..02bbace8f --- /dev/null +++ b/gdk/win32/gdkwindow-win32.c @@ -0,0 +1,2560 @@ +/* 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 "gdk.h" +#include "gdkprivate.h" +#include "gdkinput.h" +#include <stdlib.h> +#include <stdio.h> + +/* The Win API function AdjustWindowRect may return negative values + * resulting in obscured title bars. This helper function is coreccting it. + */ +BOOL AdjustWindowRectEx2(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; +} +/* HB: now use it */ +#define AdjustWindowRectEx AdjustWindowRectEx2 + +/* 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) +{ + unsigned int width; + unsigned int height; +#if 0 + width = GetSystemMetrics (SM_CXSCREEN); + height = GetSystemMetrics (SM_CYSCREEN); +#else + { RECT r; /* //HB: don't obscure tray window (task bar) */ + SystemParametersInfo(SPI_GETWORKAREA, 0, &r, 0); + width = r.right - r.left; + height = r.bottom - r.top; + } +#endif + + gdk_root_parent.xwindow = gdk_root_window; + gdk_root_parent.window_type = GDK_WINDOW_ROOT; + gdk_root_parent.window.user_data = NULL; + gdk_root_parent.width = width; + gdk_root_parent.height = height; + gdk_root_parent.children = NULL; + gdk_root_parent.colormap = NULL; + gdk_root_parent.ref_count = 1; + + gdk_xid_table_insert (&gdk_root_window, &gdk_root_parent); +} + +GdkWindow* +gdk_window_new (GdkWindow *parent, + GdkWindowAttr *attributes, + gint attributes_mask) +{ + GdkWindow *window; + GdkWindowPrivate *private; + GdkWindowPrivate *parent_private; + GdkVisual *visual; + HANDLE xparent; + Visual *xvisual; +#ifdef MULTIPLE_WINDOW_CLASSES + WNDCLASSEX wcl; + ATOM klass; + char wcl_name_buf[20]; + static int wcl_cnt = 0; +#else + static WNDCLASSEX wcl; + static ATOM klass = 0; +#endif + static HICON hAppIcon = NULL; + DWORD dwStyle, dwExStyle; + RECT rect; + int width, height; + int x, y; + char *title; + + g_return_val_if_fail (attributes != NULL, NULL); + + if (!parent) + parent = (GdkWindow*) &gdk_root_parent; + + parent_private = (GdkWindowPrivate*) parent; + if (parent_private->destroyed) + return NULL; + + xparent = parent_private->xwindow; + + private = g_new (GdkWindowPrivate, 1); + window = (GdkWindow*) private; + + private->parent = parent; + + private->destroyed = FALSE; + private->mapped = FALSE; + private->guffaw_gravity = FALSE; + private->resize_count = 0; + private->ref_count = 1; + + if (attributes_mask & GDK_WA_X) + x = attributes->x; + else + x = 0; + + if (attributes_mask & GDK_WA_Y) + y = attributes->y; + else + y = 0; + + private->x = x; + private->y = y; + private->width = (attributes->width > 1) ? (attributes->width) : (1); + private->height = (attributes->height > 1) ? (attributes->height) : (1); + private->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; + +#ifndef MULTIPLE_WINDOW_CLASSES + if (klass == 0) + { +#endif + wcl.cbSize = sizeof (WNDCLASSEX); +#if 1 + wcl.style = CS_HREDRAW | CS_VREDRAW; +#else + wcl.style = 0; +#endif + wcl.lpfnWndProc = gdk_WindowProc; + wcl.cbClsExtra = 0; + wcl.cbWndExtra = 0; + wcl.hInstance = gdk_ProgInstance; + wcl.hCursor = LoadCursor (NULL, IDC_ARROW); + +#if 0 /* tml: orig -> generates SetClassLong errors in set background */ + wcl.hIcon = LoadIcon (NULL, IDI_APPLICATION); + wcl.hbrBackground = NULL; +#else + /* 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.hIcon = CopyIcon (hAppIcon); + wcl.hIconSm = CopyIcon (hAppIcon); + /* HB: starting with black to have something to release ... */ + wcl.hbrBackground = CreateSolidBrush( RGB(0,0,0)); +#endif + + wcl.lpszMenuName = NULL; +#ifdef MULTIPLE_WINDOW_CLASSES + sprintf (wcl_name_buf, "gdk-wcl-%d", wcl_cnt++); + wcl.lpszClassName = g_strdup (wcl_name_buf); + /* wcl.hIconSm = LoadIcon (NULL, IDI_APPLICATION); */ +#else + wcl.lpszClassName = "GDK-window-class"; + klass = RegisterClassEx (&wcl); + if (!klass) + g_error ("RegisterClassEx failed"); + } + + private->xcursor = NULL; +#endif + + if (parent_private && parent_private->guffaw_gravity) + { + /* XXX ??? */ + } + + if (attributes->wclass == GDK_INPUT_OUTPUT) + { + dwExStyle = 0; + if (attributes_mask & GDK_WA_COLORMAP) + private->colormap = attributes->colormap; + else + private->colormap = gdk_colormap_get_system (); + } + else + { + dwExStyle = WS_EX_TRANSPARENT; + private->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->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; + xparent = gdk_root_window; + break; + case GDK_WINDOW_TEMP: + dwStyle = WS_POPUP | WS_CLIPCHILDREN | WS_CLIPSIBLINGS; +#ifdef MULTIPLE_WINDOW_CLASSES + wcl.style |= CS_SAVEBITS; +#endif + dwExStyle |= WS_EX_TOOLWINDOW; + break; + case GDK_WINDOW_ROOT: + g_error ("cannot make windows of type GDK_WINDOW_ROOT"); + break; + case GDK_WINDOW_PIXMAP: + g_error ("cannot make windows of type GDK_WINDOW_PIXMAP (use gdk_pixmap_new)"); + break; + } + +#ifdef MULTIPLE_WINDOW_CLASSES + klass = RegisterClassEx (&wcl); + if (!klass) + g_error ("RegisterClassEx failed"); +#endif + + if (private->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->width; + rect.bottom = rect.top + private->height; + + if (!AdjustWindowRectEx (&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->width; + height = private->height; + } + + private->xwindow = + CreateWindowEx (dwExStyle, + wcl.lpszClassName, + title, + dwStyle, + x, y, + width, height, + xparent, + NULL, + gdk_ProgInstance, + NULL); + GDK_NOTE (MISC, + g_print ("gdk_window_create: %s %s %#x %dx%d@+%d+%d %#x = %#x\n", + (private->window_type == GDK_WINDOW_TOPLEVEL ? "TOPLEVEL" : + (private->window_type == GDK_WINDOW_CHILD ? "CHILD" : + (private->window_type == GDK_WINDOW_DIALOG ? "DIALOG" : + (private->window_type == GDK_WINDOW_TEMP ? "TEMP" : + "???")))), + title, + dwStyle, + width, height, (x == CW_USEDEFAULT ? -9999 : x), y, + xparent, + private->xwindow)); + + gdk_window_ref (window); + gdk_xid_table_insert (&private->xwindow, window); + + if (private->colormap) + gdk_colormap_ref (private->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->xwindow = (HWND) anid; + GetClientRect ((HWND) anid, &rect); + point.x = rect.left; + point.y = rect.right; + ClientToScreen ((HWND) anid, &point); + if (parent != HWND_DESKTOP) + ScreenToClient (parent, &point); + private->x = point.x; + private->y = point.y; + private->width = rect.right - rect.left; + private->height = rect.bottom - rect.top; + private->resize_count = 0; + private->ref_count = 1; + private->window_type = GDK_WINDOW_FOREIGN; + private->destroyed = FALSE; + private->mapped = IsWindowVisible (private->xwindow); + private->guffaw_gravity = FALSE; + private->extension_events = 0; + private->extension_events_selected = FALSE; + + private->colormap = NULL; + + private->filters = NULL; + private->children = NULL; + + window->user_data = NULL; + + gdk_window_ref (window); + gdk_xid_table_insert (&private->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->xwindow)); + + switch (private->window_type) + { + case GDK_WINDOW_TOPLEVEL: + case GDK_WINDOW_CHILD: + case GDK_WINDOW_DIALOG: + case GDK_WINDOW_TEMP: + case GDK_WINDOW_FOREIGN: + if (!private->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 (private->window_type != 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->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->xwindow, WM_QUIT, 0, 0); + } + } + else if (xdestroy) + DestroyWindow (private->xwindow); + + if (private->colormap) + gdk_colormap_unref (private->colormap); + + private->mapped = FALSE; + private->destroyed = TRUE; + } + break; + + case GDK_WINDOW_ROOT: + g_error ("attempted to destroy root window"); + break; + + case GDK_WINDOW_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) +{ + GdkWindowPrivate *private; + + g_return_if_fail (window != NULL); + + private = (GdkWindowPrivate*) window; + + GDK_NOTE (EVENTS, g_print ("gdk_window_destroy_notify: %#x %d\n", + private->xwindow, private->destroyed)); + + if (!private->destroyed) + { + if (private->window_type == GDK_WINDOW_FOREIGN) + gdk_window_internal_destroy (window, FALSE, FALSE); + else + g_warning ("GdkWindow %#lx unexpectedly destroyed", private->xwindow); + } + + gdk_xid_table_remove (private->xwindow); + gdk_window_unref (window); +} + +GdkWindow* +gdk_window_ref (GdkWindow *window) +{ + GdkWindowPrivate *private = (GdkWindowPrivate *)window; + g_return_val_if_fail (window != NULL, NULL); + + private->ref_count += 1; + + GDK_NOTE (MISC, g_print ("gdk_window_ref %#x %d\n", + private->xwindow, private->ref_count)); + + return window; +} + +void +gdk_window_unref (GdkWindow *window) +{ + GdkWindowPrivate *private = (GdkWindowPrivate *)window; + g_return_if_fail (window != NULL); + + private->ref_count -= 1; + + GDK_NOTE (MISC, g_print ("gdk_window_unref %#x %d%s\n", + private->xwindow, private->ref_count, + (private->ref_count == 0 ? " freeing" : ""))); + + if (private->ref_count == 0) + { + if (private->bg_type == GDK_WIN32_BG_PIXMAP && private->bg_pixmap != NULL) + gdk_pixmap_unref (private->bg_pixmap); + + if (!private->destroyed) + { + if (private->window_type == GDK_WINDOW_FOREIGN) + gdk_xid_table_remove (private->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->destroyed) + { + GDK_NOTE (MISC, g_print ("gdk_window_show: %#x\n", private->xwindow)); + + private->mapped = TRUE; + if (private->window_type == GDK_WINDOW_TEMP) + { + ShowWindow (private->xwindow, SW_SHOWNOACTIVATE); + SetWindowPos (private->xwindow, HWND_TOPMOST, 0, 0, 0, 0, + SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE); +#if 0 + ShowWindow (private->xwindow, SW_HIDE); /* Don't put on toolbar */ +#endif + } + else + { + ShowWindow (private->xwindow, SW_SHOWNORMAL); + ShowWindow (private->xwindow, SW_RESTORE); + SetForegroundWindow (private->xwindow); +#if 0 + ShowOwnedPopups (private->xwindow, TRUE); +#endif + } + } +} + +void +gdk_window_hide (GdkWindow *window) +{ + GdkWindowPrivate *private; + + g_return_if_fail (window != NULL); + + private = (GdkWindowPrivate*) window; + if (!private->destroyed) + { + GDK_NOTE (MISC, g_print ("gdk_window_hide: %#x\n", private->xwindow)); + + private->mapped = FALSE; + if (private->window_type == GDK_WINDOW_TOPLEVEL) + ShowOwnedPopups (private->xwindow, FALSE); +#if 1 + ShowWindow (private->xwindow, SW_HIDE); +#elif 0 + ShowWindow (private->xwindow, SW_MINIMIZE); +#else + CloseWindow (private->xwindow); +#endif + } +} + +void +gdk_window_withdraw (GdkWindow *window) +{ + GdkWindowPrivate *private; + + g_return_if_fail (window != NULL); + + private = (GdkWindowPrivate*) window; + if (!private->destroyed) + { + GDK_NOTE (MISC, g_print ("gdk_window_withdraw: %#x\n", private->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->destroyed) + { + RECT rect; + DWORD dwStyle; + DWORD dwExStyle; + + GDK_NOTE (MISC, g_print ("gdk_window_move: %#x +%d+%d\n", + private->xwindow, x, y)); + GetClientRect (private->xwindow, &rect); + + dwStyle = GetWindowLong (private->xwindow, GWL_STYLE); + dwExStyle = GetWindowLong (private->xwindow, GWL_EXSTYLE); + if (!AdjustWindowRectEx (&rect, dwStyle, FALSE, dwExStyle)) + g_warning ("gdk_window_move: AdjustWindowRectEx failed"); + if (private->window_type == GDK_WINDOW_CHILD) + { + private->x = x; + private->y = y; + } + GDK_NOTE (MISC, g_print ("...MoveWindow(%#x,%dx%d@+%d+%d)\n", + private->xwindow, + rect.right - rect.left, rect.bottom - rect.top, + x + rect.left, y + rect.top)); + if (!MoveWindow (private->xwindow, + x + rect.left, y + rect.top, + 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->destroyed && + ((private->resize_count > 0) || + (private->width != (guint16) width) || + (private->height != (guint16) height))) + { + RECT rect; + POINT pt; + DWORD dwStyle; + DWORD dwExStyle; + int x, y; + + GDK_NOTE (MISC, g_print ("gdk_window_resize: %#x %dx%d\n", + private->xwindow, width, height)); + + pt.x = 0; + pt.y = 0; + ClientToScreen (private->xwindow, &pt); + rect.left = pt.x; + rect.top = pt.y; + rect.right = pt.x + width; + rect.bottom = pt.y + height; + + dwStyle = GetWindowLong (private->xwindow, GWL_STYLE); + dwExStyle = GetWindowLong (private->xwindow, GWL_EXSTYLE); + if (!AdjustWindowRectEx (&rect, dwStyle, FALSE, dwExStyle)) + g_warning ("gdk_window_resize: AdjustWindowRectEx failed"); + if (private->window_type != GDK_WINDOW_CHILD) + { + x = rect.left; + y = rect.top; + } + else + { + x = private->x; + y = private->y; + } + + private->resize_count += 1; + + if (private->window_type == GDK_WINDOW_CHILD) + { + private->width = width; + private->height = height; + } + GDK_NOTE (MISC, g_print ("...MoveWindow(%#x,%dx%d@+%d+%d)\n", + private->xwindow, + rect.right - rect.left, rect.bottom - rect.top, + x, y)); + if (!MoveWindow (private->xwindow, + x, y, + rect.right - rect.left, rect.bottom - rect.top, + 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->destroyed) + { + RECT rect; + DWORD dwStyle; + DWORD dwExStyle; + + GDK_NOTE (MISC, g_print ("gdk_window_move_resize: %#x %dx%d@+%d+%d\n", + private->xwindow, width, height, x, y)); + + rect.left = x; + rect.top = y; + rect.right = x + width; + rect.bottom = y + height; + + dwStyle = GetWindowLong (private->xwindow, GWL_STYLE); + dwExStyle = GetWindowLong (private->xwindow, GWL_EXSTYLE); + if (!AdjustWindowRectEx (&rect, dwStyle, FALSE, dwExStyle)) + g_warning ("gdk_window_move_resize: AdjustWindowRectEx failed"); + + if (private->window_type == GDK_WINDOW_CHILD) + { + private->x = x; + private->y = y; + private->width = width; + private->height = height; + } + GDK_NOTE (MISC, g_print ("...MoveWindow(%#x,%dx%d@+%d+%d)\n", + private->xwindow, + rect.right - rect.left, rect.bottom - rect.top, + rect.left, rect.top)); + if (!MoveWindow (private->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->destroyed && !parent_private->destroyed) + { + GDK_NOTE (MISC, g_print ("gdk_window_reparent: %#x %#x\n", + window_private->xwindow, + parent_private->xwindow)); + if (!SetParent (window_private->xwindow, parent_private->xwindow)) + g_warning ("gdk_window_reparent: SetParent failed"); + + if (!MoveWindow (window_private->xwindow, + x, y, + window_private->width, window_private->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) +{ + GdkWindowPrivate *private; + + g_return_if_fail (window != NULL); + + private = (GdkWindowPrivate*) window; + + if (!private->destroyed) + { + gdk_window_clear_area (window, 0, 0, private->width, private->height); + } +} + + +void +gdk_window_clear_area (GdkWindow *window, + gint x, + gint y, + gint width, + gint height) +{ + GdkWindowPrivate *private; + + g_return_if_fail (window != NULL); + + private = (GdkWindowPrivate*) window; + + if (!private->destroyed) + { + 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", + private->xwindow, width, height, x, y)); + hdc = GetDC (private->xwindow); + IntersectClipRect (hdc, x, y, x + width, y + height); + SendMessage (private->xwindow, WM_ERASEBKGND, (WPARAM) hdc, 0); + ReleaseDC (private->xwindow, hdc); + } +} + +void +gdk_window_clear_area_e (GdkWindow *window, + gint x, + gint y, + gint width, + gint height) +{ + GdkWindowPrivate *private; + + g_return_if_fail (window != NULL); + + private = (GdkWindowPrivate*) window; + + if (!private->destroyed) + { + RECT rect; + + GDK_NOTE (MISC, g_print ("gdk_window_clear_area_e: %#x %dx%d@+%d+%d\n", + private->xwindow, width, height, x, y)); + + rect.left = x; + rect.right = x + width; + rect.top = y; + rect.bottom = y + height; + if (!InvalidateRect (private->xwindow, &rect, TRUE)) + g_warning ("gdk_window_clear_area_e: InvalidateRect failed"); + UpdateWindow (private->xwindow); + } +} + +void +gdk_window_copy_area (GdkWindow *window, + GdkGC *gc, + gint x, + gint y, + GdkWindow *source_window, + gint source_x, + gint source_y, + gint width, + gint height) +{ + GdkWindowPrivate *src_private; + GdkWindowPrivate *dest_private; + GdkGCPrivate *gc_private; + + g_return_if_fail (window != NULL); + g_return_if_fail (gc != NULL); + + if (source_window == NULL) + source_window = window; + + src_private = (GdkWindowPrivate*) source_window; + dest_private = (GdkWindowPrivate*) window; + gc_private = (GdkGCPrivate*) gc; + + if (!src_private->destroyed && !dest_private->destroyed) + { + HDC hdcDest, hdcSrc; + + if ((hdcDest = GetDC (dest_private->xwindow)) == NULL) + g_warning ("gdk_window_copy_area: GetDC failed"); + + if ((hdcSrc = GetDC (src_private->xwindow)) == NULL) + g_warning ("gdk_window_copy_area: GetDC failed"); + + if (!BitBlt (hdcDest, x, y, width, height, hdcSrc, source_x, source_y, SRCCOPY)) + g_warning ("gdk_window_copy_area: BitBlt failed"); + + ReleaseDC (dest_private->xwindow, hdcDest); + ReleaseDC (src_private->xwindow, hdcSrc); + } +} + +void +gdk_window_raise (GdkWindow *window) +{ + GdkWindowPrivate *private; + + g_return_if_fail (window != NULL); + + private = (GdkWindowPrivate*) window; + + if (!private->destroyed) + { + GDK_NOTE (MISC, g_print ("gdk_window_raise: %#x\n", private->xwindow)); + + if (!BringWindowToTop (private->xwindow)) + g_warning ("gdk_window_raise: BringWindowToTop failed"); + } +} + +void +gdk_window_lower (GdkWindow *window) +{ + GdkWindowPrivate *private; + + g_return_if_fail (window != NULL); + + private = (GdkWindowPrivate*) window; + + if (!private->destroyed) + { + GDK_NOTE (MISC, g_print ("gdk_window_lower: %#x\n", private->xwindow)); + + if (!SetWindowPos (private->xwindow, 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); + + private = (GdkWindowPrivate*) window; + if (private->destroyed) + return; + + GDK_NOTE (MISC, g_print ("gdk_window_set_hints: %#x %dx%d..%dx%d @+%d+%d\n", + private->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->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->xwindow, GWL_STYLE); + dwExStyle = GetWindowLong (private->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->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->xwindow, GWL_STYLE); + dwExStyle = GetWindowLong (private->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->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->xwindow, GWL_STYLE); + dwExStyle = GetWindowLong (private->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->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); + + private = (GdkWindowPrivate*) window; + if (private->destroyed) + return; + + 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->xwindow, GWL_STYLE); + dwExStyle = GetWindowLong (private->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->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->xwindow, GWL_STYLE); + dwExStyle = GetWindowLong (private->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->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->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->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) +{ + GdkWindowPrivate *private; + + g_return_if_fail (window != NULL); + + private = (GdkWindowPrivate*) window; + if (!private->destroyed) + { + if (!SetWindowText (private->xwindow, title)) + g_warning ("gdk_window_set_title: SetWindowText failed"); + } +} + +void +gdk_window_set_role (GdkWindow *window, + const gchar *role) +{ + GdkWindowPrivate *private; + + g_return_if_fail (window != NULL); + + private = (GdkWindowPrivate*) window; + + GDK_NOTE (MISC, g_print ("gdk_window_set_role: %#x %s\n", + private->xwindow, (role ? role : "NULL"))); + /* XXX */ +} + +void +gdk_window_set_transient_for (GdkWindow *window, + GdkWindow *parent) +{ + GdkWindowPrivate *private; + GdkWindowPrivate *parent_private; + + g_return_if_fail (window != NULL); + + private = (GdkWindowPrivate*) window; + parent_private = (GdkWindowPrivate*) parent; + + GDK_NOTE (MISC, g_print ("gdk_window_set_transient_for: %#x %#x\n", + private->xwindow, parent_private->xwindow)); + /* XXX */ +} + +void +gdk_window_set_background (GdkWindow *window, + GdkColor *color) +{ + GdkWindowPrivate *private; + + g_return_if_fail (window != NULL); + + private = (GdkWindowPrivate*) window; + if (!private->destroyed) + { + GdkColormapPrivate *colormap_private = + (GdkColormapPrivate *) private->colormap; + + GDK_NOTE (MISC, g_print ("gdk_window_set_background: %#x %s\n", + private->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; + } +#ifdef MULTIPLE_WINDOW_CLASSES + if (colormap_private != NULL + && colormap_private->xcolormap->rc_palette) + { + /* If we are on a palettized display we can't use the window + * class background brush, but must handle WM_ERASEBKGND. + * At least, I think so. + */ +#endif + private->bg_type = GDK_WIN32_BG_PIXEL; + private->bg_pixel = *color; +#ifdef MULTIPLE_WINDOW_CLASSES + } + else + { + /* Non-palettized display; just set the window class background + brush. */ + HBRUSH hbr; + HGDIOBJ oldbrush; + COLORREF background; + + background = RGB (color->red >> 8, + color->green >> 8, + color->blue >> 8); + + if ((hbr = CreateSolidBrush (GetNearestColor (gdk_DC, + background))) == NULL) + { + g_warning ("gdk_window_set_background: CreateSolidBrush failed"); + return; + } + + oldbrush = (HGDIOBJ) GetClassLong (private->xwindow, + GCL_HBRBACKGROUND); + + if (SetClassLong (private->xwindow, GCL_HBRBACKGROUND, + (LONG) hbr) == 0) + g_warning ("gdk_window_set_background: SetClassLong failed"); + + if (!DeleteObject (oldbrush)) + g_warning ("gdk_window_set_background: DeleteObject failed"); + } +#endif + } +} + +void +gdk_window_set_back_pixmap (GdkWindow *window, + GdkPixmap *pixmap, + gint parent_relative) +{ + GdkWindowPrivate *window_private; +#ifdef MULTIPLE_WINDOW_CLASSES + GdkPixmapPrivate *pixmap_private; +#endif + + g_return_if_fail (window != NULL); + + window_private = (GdkWindowPrivate*) window; +#ifdef MULTIPLE_WINDOW_CLASSES + pixmap_private = (GdkPixmapPrivate*) pixmap; +#endif + + if (!window_private->destroyed) + { + GdkColormapPrivate *colormap_private = + (GdkColormapPrivate *) window_private->colormap; + if (window_private->bg_type == GDK_WIN32_BG_PIXMAP) + { + if (window_private->bg_pixmap != NULL) + { + gdk_pixmap_unref (window_private->bg_pixmap); + window_private->bg_pixmap = NULL; + } + window_private->bg_type = GDK_WIN32_BG_NORMAL; + } + if (parent_relative) + { + window_private->bg_type = GDK_WIN32_BG_PARENT_RELATIVE; + } + else if (!pixmap) + { +#ifdef MULTIPLE_WINDOW_CLASSES + SetClassLong (window_private->xwindow, GCL_HBRBACKGROUND, + (LONG) GetStockObject (BLACK_BRUSH)); +#endif + } +#ifdef MULTIPLE_WINDOW_CLASSES + else if (colormap_private->xcolormap->rc_palette) + { + /* Must do the background painting in the + * WM_ERASEBKGND handler. + */ + window_private->bg_type = GDK_WIN32_BG_PIXMAP; + window_private->bg_pixmap = pixmap; + gdk_pixmap_ref (pixmap); + } + else if (pixmap_private->width <= 8 + && pixmap_private->height <= 8) + { + /* We can use small pixmaps directly as background brush */ + SetClassLong (window_private->xwindow, GCL_HBRBACKGROUND, + (LONG) CreatePatternBrush (pixmap_private->xwindow)); + } +#endif + else + { + /* We must cache the pixmap in the WindowPrivate and + * paint it each time we get WM_ERASEBKGND + */ + window_private->bg_type = GDK_WIN32_BG_PIXMAP; + window_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); + + window_private = (GdkWindowPrivate*) window; + cursor_private = (GdkCursorPrivate*) cursor; + + if (!window_private->destroyed) + { + 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->xwindow, xcursor)); +#ifdef MULTIPLE_WINDOW_CLASSES + if (!SetClassLong (window_private->xwindow, GCL_HCURSOR, (LONG) xcursor)) + g_warning ("gdk_window_set_cursor: SetClassLong failed"); +#else + window_private->xcursor = xcursor; +#endif + SetCursor (xcursor); + } +} + +void +gdk_window_set_colormap (GdkWindow *window, + GdkColormap *colormap) +{ + GdkWindowPrivate *window_private; + GdkColormapPrivate *colormap_private; + + g_return_if_fail (window != NULL); + g_return_if_fail (colormap != NULL); + + window_private = (GdkWindowPrivate*) window; + colormap_private = (GdkColormapPrivate*) colormap; + + if (!window_private->destroyed) + { + /* XXX ??? */ + GDK_NOTE (MISC, g_print ("gdk_window_set_colormap: %#x %#x\n", + window_private->xwindow, + colormap_private->xcolormap)); + if (window_private->colormap) + gdk_colormap_unref (window_private->colormap); + window_private->colormap = colormap; + gdk_colormap_ref (window_private->colormap); + + if (window_private->window_type != GDK_WINDOW_TOPLEVEL) + gdk_window_add_colormap_windows (window); + } +} + +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) +{ + GdkWindowPrivate *window_private; + + if (!window) + window = (GdkWindow*) &gdk_root_parent; + + window_private = (GdkWindowPrivate*) window; + + if (!window_private->destroyed) + { + RECT rect; + + if (!GetClientRect (window_private->xwindow, &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_window_get_visual (window)->depth; + } +} + +void +gdk_window_get_position (GdkWindow *window, + gint *x, + gint *y) +{ + GdkWindowPrivate *window_private; + + g_return_if_fail (window != NULL); + + window_private = (GdkWindowPrivate*) window; + + if (x) + *x = window_private->x; + if (y) + *y = window_private->y; +} + +void +gdk_window_get_size (GdkWindow *window, + gint *width, + gint *height) +{ + GdkWindowPrivate *window_private; + + g_return_if_fail (window != NULL); + + window_private = (GdkWindowPrivate*) window; + + if (width) + *width = window_private->width; + if (height) + *height = window_private->height; +} + +GdkVisual* +gdk_window_get_visual (GdkWindow *window) +{ + GdkWindowPrivate *window_private; + + g_return_val_if_fail (window != NULL, NULL); + + window_private = (GdkWindowPrivate*) window; + /* Huh? ->parent is never set for a pixmap. We should just return + * null immeditately + */ + while (window_private && (window_private->window_type == GDK_WINDOW_PIXMAP)) + window_private = (GdkWindowPrivate*) window_private->parent; + + if (window_private && !window_private->destroyed) + { + if (window_private->colormap == NULL) + { + return gdk_visual_get_system (); /* XXX ??? */ + } + else + return ((GdkColormapPrivate *)window_private->colormap)->visual; + } + + return NULL; +} + +GdkColormap* +gdk_window_get_colormap (GdkWindow *window) +{ + GdkWindowPrivate *window_private; + + g_return_val_if_fail (window != NULL, NULL); + window_private = (GdkWindowPrivate*) window; + + g_return_val_if_fail (window_private->window_type != GDK_WINDOW_PIXMAP, NULL); + if (!window_private->destroyed) + { + if (window_private->colormap == NULL) + { + return gdk_colormap_get_system (); /* XXX ??? */ + } + else + return window_private->colormap; + } + + return NULL; +} + +GdkWindowType +gdk_window_get_type (GdkWindow *window) +{ + GdkWindowPrivate *window_private; + + g_return_val_if_fail (window != NULL, (GdkWindowType) -1); + + window_private = (GdkWindowPrivate*) window; + return window_private->window_type; +} + +gint +gdk_window_get_origin (GdkWindow *window, + gint *x, + gint *y) +{ + GdkWindowPrivate *private; + gint return_val; + gint tx = 0; + gint ty = 0; + + g_return_val_if_fail (window != NULL, 0); + + private = (GdkWindowPrivate*) window; + + if (!private->destroyed) + { + POINT pt; + + pt.x = 0; + pt.y = 0; + ClientToScreen (private->xwindow, &pt); + tx = pt.x; + ty = pt.y; + return_val = 1; + } + else + return_val = 0; + + if (x) + *x = tx; + if (y) + *y = 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); + + private = (GdkWindowPrivate*) window; + if (x) + *x = 0; + if (y) + *y = 0; + if (private->destroyed) + return; + + while (private->parent && ((GdkWindowPrivate*) private->parent)->parent) + private = (GdkWindowPrivate*) private->parent; + if (private->destroyed) + return; + + pt.x = 0; + pt.y = 0; + ClientToScreen (private->xwindow, &pt); + if (x) + *x = pt.x; + if (y) + *y = pt.y; +} + +GdkWindow* +gdk_window_get_pointer (GdkWindow *window, + gint *x, + gint *y, + GdkModifierType *mask) +{ + GdkWindowPrivate *private; + GdkWindow *return_val; + POINT pointc, point; + HWND hwnd, hwndc; + + if (!window) + window = (GdkWindow*) &gdk_root_parent; + + private = (GdkWindowPrivate*) window; + + return_val = NULL; + GetCursorPos (&pointc); + point = pointc; + ScreenToClient (private->xwindow, &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) +{ + GdkWindowPrivate *private; + GdkWindow *window; + POINT point, pointc; + HWND hwnd, hwndc; + RECT rect; + + private = &gdk_root_parent; + + 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); + + return ((GdkWindowPrivate*) window)->parent; +} + +GdkWindow* +gdk_window_get_toplevel (GdkWindow *window) +{ + GdkWindowPrivate *private; + + g_return_val_if_fail (window != NULL, NULL); + + private = (GdkWindowPrivate*) window; + + while (private->window_type == GDK_WINDOW_CHILD) + { + window = ((GdkWindowPrivate*) window)->parent; + private = (GdkWindowPrivate*) window; + } + + return window; +} + +GList* +gdk_window_get_children (GdkWindow *window) +{ + GdkWindowPrivate *private; + GList *children; + + g_return_val_if_fail (window != NULL, NULL); + + private = (GdkWindowPrivate*) window; + if (private->destroyed) + return NULL; + + /* XXX ??? */ + g_warning ("gdk_window_get_children ???"); + children = NULL; + + return children; +} + +GdkEventMask +gdk_window_get_events (GdkWindow *window) +{ + GdkWindowPrivate *private; + GdkEventMask event_mask; + + g_return_val_if_fail (window != NULL, 0); + + private = (GdkWindowPrivate*) window; + if (private->destroyed) + return 0; + + event_mask = 0; + + event_mask = private->event_mask; + + return event_mask; +} + +void +gdk_window_set_events (GdkWindow *window, + GdkEventMask event_mask) +{ + GdkWindowPrivate *private; + + g_return_if_fail (window != NULL); + + private = (GdkWindowPrivate*) window; + if (private->destroyed) + return; + + private->event_mask = event_mask; +} + +void +gdk_window_add_colormap_windows (GdkWindow *window) +{ + g_warning ("gdk_window_add_colormap_windows not implemented"); /* XXX */ +} + +/* + * This needs the X11 shape extension. + * If not available, shaped windows will look + * ugly, but programs still work. Stefan Wille + */ +void +gdk_window_shape_combine_mask (GdkWindow *window, + GdkBitmap *mask, + gint x, gint y) +{ + GdkWindowPrivate *window_private; + + g_return_if_fail (window != NULL); + + window_private = (GdkWindowPrivate*) window; + + if (!mask) + { + GDK_NOTE (MISC, g_print ("gdk_window_shape_combine_mask: %#x none\n", + window_private->xwindow)); + SetWindowRgn (window_private->xwindow, NULL, TRUE); + } + else + { + GdkPixmapPrivate *pixmap_private; + HRGN hrgn; + DWORD dwStyle; + DWORD dwExStyle; + RECT rect; + + /* Convert mask bitmap to region */ + pixmap_private = (GdkPixmapPrivate*) mask; + hrgn = BitmapToRegion (pixmap_private->xwindow); + + GDK_NOTE (MISC, g_print ("gdk_window_shape_combine_mask: %#x %#x\n", + window_private->xwindow, + pixmap_private->xwindow)); + + /* SetWindowRgn wants window (not client) coordinates */ + dwStyle = GetWindowLong (window_private->xwindow, GWL_STYLE); + dwExStyle = GetWindowLong (window_private->xwindow, GWL_EXSTYLE); + GetClientRect (window_private->xwindow, &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 (window_private->window_type == GDK_WINDOW_TOPLEVEL) + { + CombineRgn (hrgn, hrgn, + CreateRectRgn (0, 0, rect.right - rect.left, -rect.top), + RGN_OR); + } + + SetWindowRgn (window_private->xwindow, hrgn, TRUE); + } +} + +void +gdk_window_add_filter (GdkWindow *window, + GdkFilterFunc function, + gpointer data) +{ + GdkWindowPrivate *private; + GList *tmp_list; + GdkEventFilter *filter; + + private = (GdkWindowPrivate*) window; + if (private && private->destroyed) + return; + + if (private) + tmp_list = private->filters; + else + tmp_list = gdk_default_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; + + if (private) + private->filters = g_list_append (private->filters, filter); + else + gdk_default_filters = g_list_append (gdk_default_filters, filter); +} + +void +gdk_window_remove_filter (GdkWindow *window, + GdkFilterFunc function, + gpointer data) +{ + GdkWindowPrivate *private; + GList *tmp_list, *node; + GdkEventFilter *filter; + + private = (GdkWindowPrivate*) window; + + if(private) + tmp_list = private->filters; + else + tmp_list = gdk_default_filters; + + while (tmp_list) + { + filter = (GdkEventFilter *)tmp_list->data; + node = tmp_list; + tmp_list = tmp_list->next; + + if ((filter->function == function) && (filter->data == data)) + { + if(private) + private->filters = g_list_remove_link (private->filters, node); + else + gdk_default_filters = g_list_remove_link (gdk_default_filters, tmp_list); + g_list_free_1 (node); + g_free (filter); + + return; + } + } +} + +void +gdk_window_set_override_redirect (GdkWindow *window, + gboolean override_redirect) +{ + g_warning ("gdk_window_set_override_redirect not implemented"); /* XXX */ +} + +void +gdk_window_set_icon (GdkWindow *window, + GdkWindow *icon_window, + GdkPixmap *pixmap, + GdkBitmap *mask) +{ + g_warning ("gdk_window_set_icon not implemented"); /* XXX */ +} + +void +gdk_window_set_icon_name (GdkWindow *window, + gchar *name) +{ + GdkWindowPrivate *window_private; + + g_return_if_fail (window != NULL); + window_private = (GdkWindowPrivate*) window; + if (window_private->destroyed) + return; + + if (!SetWindowText (window_private->xwindow, name)) + g_warning ("gdk_window_set_icon_name: SetWindowText failed"); +} + +void +gdk_window_set_group (GdkWindow *window, + GdkWindow *leader) +{ + g_warning ("gdk_window_set_group not implemented"); /* XXX */ +} + +void +gdk_window_set_decorations (GdkWindow *window, + GdkWMDecoration decorations) +{ + GdkWindowPrivate *window_private = (GdkWindowPrivate *) window; + LONG style, exstyle; + + style = GetWindowLong (window_private->xwindow, GWL_STYLE); + exstyle = GetWindowLong (window_private->xwindow, 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 (window_private->xwindow, GWL_STYLE, style); +} + +void +gdk_window_set_functions (GdkWindow *window, + GdkWMFunction functions) +{ + GdkWindowPrivate *window_private = (GdkWindowPrivate *) window; + LONG style, exstyle; + + style = GetWindowLong (window_private->xwindow, GWL_STYLE); + exstyle = GetWindowLong (window_private->xwindow, 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 (window_private->xwindow, 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 create/insert spans */ + 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); + } + } + SetWindowRgn (win, region, TRUE); + } +} + +void +gdk_window_set_child_shapes (GdkWindow *window) +{ + GdkWindowPrivate *private; + + g_return_if_fail (window != NULL); + + private = (GdkWindowPrivate*) window; + if (private->destroyed) + return; + + gdk_propagate_shapes ( private->xwindow, FALSE); +} + +void +gdk_window_merge_child_shapes (GdkWindow *window) +{ + GdkWindowPrivate *private; + + g_return_if_fail (window != NULL); + + private = (GdkWindowPrivate*) window; + if (private->destroyed) + return; + + gdk_propagate_shapes (private->xwindow, 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); + + 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); + + while (private && + (private != &gdk_root_parent) && + (private->window_type != GDK_WINDOW_FOREIGN)) + { + if (!private->mapped) + return FALSE; + + private = (GdkWindowPrivate *)private->parent; + } + + return TRUE; +} + +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); +} + + +/* 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) +{ + GdkWindowPrivate *private = (GdkWindowPrivate *)window; + + 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) +{ + GdkWindowPrivate *private = (GdkWindowPrivate *)window; + + 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); + + if (!use_static == !private->guffaw_gravity) + return TRUE; + + if (use_static && !gdk_window_gravity_works ()) + return FALSE; + + private->guffaw_gravity = use_static; + + gdk_window_set_static_bit_gravity (window, use_static); + + tmp_list = private->children; + while (tmp_list) + { + gdk_window_set_static_win_gravity (window, use_static); + + tmp_list = tmp_list->next; + } + + return TRUE; +} diff --git a/gdk/win32/gdkwindow.c b/gdk/win32/gdkwindow.c new file mode 100644 index 000000000..02bbace8f --- /dev/null +++ b/gdk/win32/gdkwindow.c @@ -0,0 +1,2560 @@ +/* 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 "gdk.h" +#include "gdkprivate.h" +#include "gdkinput.h" +#include <stdlib.h> +#include <stdio.h> + +/* The Win API function AdjustWindowRect may return negative values + * resulting in obscured title bars. This helper function is coreccting it. + */ +BOOL AdjustWindowRectEx2(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; +} +/* HB: now use it */ +#define AdjustWindowRectEx AdjustWindowRectEx2 + +/* 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) +{ + unsigned int width; + unsigned int height; +#if 0 + width = GetSystemMetrics (SM_CXSCREEN); + height = GetSystemMetrics (SM_CYSCREEN); +#else + { RECT r; /* //HB: don't obscure tray window (task bar) */ + SystemParametersInfo(SPI_GETWORKAREA, 0, &r, 0); + width = r.right - r.left; + height = r.bottom - r.top; + } +#endif + + gdk_root_parent.xwindow = gdk_root_window; + gdk_root_parent.window_type = GDK_WINDOW_ROOT; + gdk_root_parent.window.user_data = NULL; + gdk_root_parent.width = width; + gdk_root_parent.height = height; + gdk_root_parent.children = NULL; + gdk_root_parent.colormap = NULL; + gdk_root_parent.ref_count = 1; + + gdk_xid_table_insert (&gdk_root_window, &gdk_root_parent); +} + +GdkWindow* +gdk_window_new (GdkWindow *parent, + GdkWindowAttr *attributes, + gint attributes_mask) +{ + GdkWindow *window; + GdkWindowPrivate *private; + GdkWindowPrivate *parent_private; + GdkVisual *visual; + HANDLE xparent; + Visual *xvisual; +#ifdef MULTIPLE_WINDOW_CLASSES + WNDCLASSEX wcl; + ATOM klass; + char wcl_name_buf[20]; + static int wcl_cnt = 0; +#else + static WNDCLASSEX wcl; + static ATOM klass = 0; +#endif + static HICON hAppIcon = NULL; + DWORD dwStyle, dwExStyle; + RECT rect; + int width, height; + int x, y; + char *title; + + g_return_val_if_fail (attributes != NULL, NULL); + + if (!parent) + parent = (GdkWindow*) &gdk_root_parent; + + parent_private = (GdkWindowPrivate*) parent; + if (parent_private->destroyed) + return NULL; + + xparent = parent_private->xwindow; + + private = g_new (GdkWindowPrivate, 1); + window = (GdkWindow*) private; + + private->parent = parent; + + private->destroyed = FALSE; + private->mapped = FALSE; + private->guffaw_gravity = FALSE; + private->resize_count = 0; + private->ref_count = 1; + + if (attributes_mask & GDK_WA_X) + x = attributes->x; + else + x = 0; + + if (attributes_mask & GDK_WA_Y) + y = attributes->y; + else + y = 0; + + private->x = x; + private->y = y; + private->width = (attributes->width > 1) ? (attributes->width) : (1); + private->height = (attributes->height > 1) ? (attributes->height) : (1); + private->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; + +#ifndef MULTIPLE_WINDOW_CLASSES + if (klass == 0) + { +#endif + wcl.cbSize = sizeof (WNDCLASSEX); +#if 1 + wcl.style = CS_HREDRAW | CS_VREDRAW; +#else + wcl.style = 0; +#endif + wcl.lpfnWndProc = gdk_WindowProc; + wcl.cbClsExtra = 0; + wcl.cbWndExtra = 0; + wcl.hInstance = gdk_ProgInstance; + wcl.hCursor = LoadCursor (NULL, IDC_ARROW); + +#if 0 /* tml: orig -> generates SetClassLong errors in set background */ + wcl.hIcon = LoadIcon (NULL, IDI_APPLICATION); + wcl.hbrBackground = NULL; +#else + /* 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.hIcon = CopyIcon (hAppIcon); + wcl.hIconSm = CopyIcon (hAppIcon); + /* HB: starting with black to have something to release ... */ + wcl.hbrBackground = CreateSolidBrush( RGB(0,0,0)); +#endif + + wcl.lpszMenuName = NULL; +#ifdef MULTIPLE_WINDOW_CLASSES + sprintf (wcl_name_buf, "gdk-wcl-%d", wcl_cnt++); + wcl.lpszClassName = g_strdup (wcl_name_buf); + /* wcl.hIconSm = LoadIcon (NULL, IDI_APPLICATION); */ +#else + wcl.lpszClassName = "GDK-window-class"; + klass = RegisterClassEx (&wcl); + if (!klass) + g_error ("RegisterClassEx failed"); + } + + private->xcursor = NULL; +#endif + + if (parent_private && parent_private->guffaw_gravity) + { + /* XXX ??? */ + } + + if (attributes->wclass == GDK_INPUT_OUTPUT) + { + dwExStyle = 0; + if (attributes_mask & GDK_WA_COLORMAP) + private->colormap = attributes->colormap; + else + private->colormap = gdk_colormap_get_system (); + } + else + { + dwExStyle = WS_EX_TRANSPARENT; + private->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->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; + xparent = gdk_root_window; + break; + case GDK_WINDOW_TEMP: + dwStyle = WS_POPUP | WS_CLIPCHILDREN | WS_CLIPSIBLINGS; +#ifdef MULTIPLE_WINDOW_CLASSES + wcl.style |= CS_SAVEBITS; +#endif + dwExStyle |= WS_EX_TOOLWINDOW; + break; + case GDK_WINDOW_ROOT: + g_error ("cannot make windows of type GDK_WINDOW_ROOT"); + break; + case GDK_WINDOW_PIXMAP: + g_error ("cannot make windows of type GDK_WINDOW_PIXMAP (use gdk_pixmap_new)"); + break; + } + +#ifdef MULTIPLE_WINDOW_CLASSES + klass = RegisterClassEx (&wcl); + if (!klass) + g_error ("RegisterClassEx failed"); +#endif + + if (private->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->width; + rect.bottom = rect.top + private->height; + + if (!AdjustWindowRectEx (&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->width; + height = private->height; + } + + private->xwindow = + CreateWindowEx (dwExStyle, + wcl.lpszClassName, + title, + dwStyle, + x, y, + width, height, + xparent, + NULL, + gdk_ProgInstance, + NULL); + GDK_NOTE (MISC, + g_print ("gdk_window_create: %s %s %#x %dx%d@+%d+%d %#x = %#x\n", + (private->window_type == GDK_WINDOW_TOPLEVEL ? "TOPLEVEL" : + (private->window_type == GDK_WINDOW_CHILD ? "CHILD" : + (private->window_type == GDK_WINDOW_DIALOG ? "DIALOG" : + (private->window_type == GDK_WINDOW_TEMP ? "TEMP" : + "???")))), + title, + dwStyle, + width, height, (x == CW_USEDEFAULT ? -9999 : x), y, + xparent, + private->xwindow)); + + gdk_window_ref (window); + gdk_xid_table_insert (&private->xwindow, window); + + if (private->colormap) + gdk_colormap_ref (private->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->xwindow = (HWND) anid; + GetClientRect ((HWND) anid, &rect); + point.x = rect.left; + point.y = rect.right; + ClientToScreen ((HWND) anid, &point); + if (parent != HWND_DESKTOP) + ScreenToClient (parent, &point); + private->x = point.x; + private->y = point.y; + private->width = rect.right - rect.left; + private->height = rect.bottom - rect.top; + private->resize_count = 0; + private->ref_count = 1; + private->window_type = GDK_WINDOW_FOREIGN; + private->destroyed = FALSE; + private->mapped = IsWindowVisible (private->xwindow); + private->guffaw_gravity = FALSE; + private->extension_events = 0; + private->extension_events_selected = FALSE; + + private->colormap = NULL; + + private->filters = NULL; + private->children = NULL; + + window->user_data = NULL; + + gdk_window_ref (window); + gdk_xid_table_insert (&private->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->xwindow)); + + switch (private->window_type) + { + case GDK_WINDOW_TOPLEVEL: + case GDK_WINDOW_CHILD: + case GDK_WINDOW_DIALOG: + case GDK_WINDOW_TEMP: + case GDK_WINDOW_FOREIGN: + if (!private->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 (private->window_type != 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->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->xwindow, WM_QUIT, 0, 0); + } + } + else if (xdestroy) + DestroyWindow (private->xwindow); + + if (private->colormap) + gdk_colormap_unref (private->colormap); + + private->mapped = FALSE; + private->destroyed = TRUE; + } + break; + + case GDK_WINDOW_ROOT: + g_error ("attempted to destroy root window"); + break; + + case GDK_WINDOW_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) +{ + GdkWindowPrivate *private; + + g_return_if_fail (window != NULL); + + private = (GdkWindowPrivate*) window; + + GDK_NOTE (EVENTS, g_print ("gdk_window_destroy_notify: %#x %d\n", + private->xwindow, private->destroyed)); + + if (!private->destroyed) + { + if (private->window_type == GDK_WINDOW_FOREIGN) + gdk_window_internal_destroy (window, FALSE, FALSE); + else + g_warning ("GdkWindow %#lx unexpectedly destroyed", private->xwindow); + } + + gdk_xid_table_remove (private->xwindow); + gdk_window_unref (window); +} + +GdkWindow* +gdk_window_ref (GdkWindow *window) +{ + GdkWindowPrivate *private = (GdkWindowPrivate *)window; + g_return_val_if_fail (window != NULL, NULL); + + private->ref_count += 1; + + GDK_NOTE (MISC, g_print ("gdk_window_ref %#x %d\n", + private->xwindow, private->ref_count)); + + return window; +} + +void +gdk_window_unref (GdkWindow *window) +{ + GdkWindowPrivate *private = (GdkWindowPrivate *)window; + g_return_if_fail (window != NULL); + + private->ref_count -= 1; + + GDK_NOTE (MISC, g_print ("gdk_window_unref %#x %d%s\n", + private->xwindow, private->ref_count, + (private->ref_count == 0 ? " freeing" : ""))); + + if (private->ref_count == 0) + { + if (private->bg_type == GDK_WIN32_BG_PIXMAP && private->bg_pixmap != NULL) + gdk_pixmap_unref (private->bg_pixmap); + + if (!private->destroyed) + { + if (private->window_type == GDK_WINDOW_FOREIGN) + gdk_xid_table_remove (private->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->destroyed) + { + GDK_NOTE (MISC, g_print ("gdk_window_show: %#x\n", private->xwindow)); + + private->mapped = TRUE; + if (private->window_type == GDK_WINDOW_TEMP) + { + ShowWindow (private->xwindow, SW_SHOWNOACTIVATE); + SetWindowPos (private->xwindow, HWND_TOPMOST, 0, 0, 0, 0, + SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE); +#if 0 + ShowWindow (private->xwindow, SW_HIDE); /* Don't put on toolbar */ +#endif + } + else + { + ShowWindow (private->xwindow, SW_SHOWNORMAL); + ShowWindow (private->xwindow, SW_RESTORE); + SetForegroundWindow (private->xwindow); +#if 0 + ShowOwnedPopups (private->xwindow, TRUE); +#endif + } + } +} + +void +gdk_window_hide (GdkWindow *window) +{ + GdkWindowPrivate *private; + + g_return_if_fail (window != NULL); + + private = (GdkWindowPrivate*) window; + if (!private->destroyed) + { + GDK_NOTE (MISC, g_print ("gdk_window_hide: %#x\n", private->xwindow)); + + private->mapped = FALSE; + if (private->window_type == GDK_WINDOW_TOPLEVEL) + ShowOwnedPopups (private->xwindow, FALSE); +#if 1 + ShowWindow (private->xwindow, SW_HIDE); +#elif 0 + ShowWindow (private->xwindow, SW_MINIMIZE); +#else + CloseWindow (private->xwindow); +#endif + } +} + +void +gdk_window_withdraw (GdkWindow *window) +{ + GdkWindowPrivate *private; + + g_return_if_fail (window != NULL); + + private = (GdkWindowPrivate*) window; + if (!private->destroyed) + { + GDK_NOTE (MISC, g_print ("gdk_window_withdraw: %#x\n", private->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->destroyed) + { + RECT rect; + DWORD dwStyle; + DWORD dwExStyle; + + GDK_NOTE (MISC, g_print ("gdk_window_move: %#x +%d+%d\n", + private->xwindow, x, y)); + GetClientRect (private->xwindow, &rect); + + dwStyle = GetWindowLong (private->xwindow, GWL_STYLE); + dwExStyle = GetWindowLong (private->xwindow, GWL_EXSTYLE); + if (!AdjustWindowRectEx (&rect, dwStyle, FALSE, dwExStyle)) + g_warning ("gdk_window_move: AdjustWindowRectEx failed"); + if (private->window_type == GDK_WINDOW_CHILD) + { + private->x = x; + private->y = y; + } + GDK_NOTE (MISC, g_print ("...MoveWindow(%#x,%dx%d@+%d+%d)\n", + private->xwindow, + rect.right - rect.left, rect.bottom - rect.top, + x + rect.left, y + rect.top)); + if (!MoveWindow (private->xwindow, + x + rect.left, y + rect.top, + 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->destroyed && + ((private->resize_count > 0) || + (private->width != (guint16) width) || + (private->height != (guint16) height))) + { + RECT rect; + POINT pt; + DWORD dwStyle; + DWORD dwExStyle; + int x, y; + + GDK_NOTE (MISC, g_print ("gdk_window_resize: %#x %dx%d\n", + private->xwindow, width, height)); + + pt.x = 0; + pt.y = 0; + ClientToScreen (private->xwindow, &pt); + rect.left = pt.x; + rect.top = pt.y; + rect.right = pt.x + width; + rect.bottom = pt.y + height; + + dwStyle = GetWindowLong (private->xwindow, GWL_STYLE); + dwExStyle = GetWindowLong (private->xwindow, GWL_EXSTYLE); + if (!AdjustWindowRectEx (&rect, dwStyle, FALSE, dwExStyle)) + g_warning ("gdk_window_resize: AdjustWindowRectEx failed"); + if (private->window_type != GDK_WINDOW_CHILD) + { + x = rect.left; + y = rect.top; + } + else + { + x = private->x; + y = private->y; + } + + private->resize_count += 1; + + if (private->window_type == GDK_WINDOW_CHILD) + { + private->width = width; + private->height = height; + } + GDK_NOTE (MISC, g_print ("...MoveWindow(%#x,%dx%d@+%d+%d)\n", + private->xwindow, + rect.right - rect.left, rect.bottom - rect.top, + x, y)); + if (!MoveWindow (private->xwindow, + x, y, + rect.right - rect.left, rect.bottom - rect.top, + 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->destroyed) + { + RECT rect; + DWORD dwStyle; + DWORD dwExStyle; + + GDK_NOTE (MISC, g_print ("gdk_window_move_resize: %#x %dx%d@+%d+%d\n", + private->xwindow, width, height, x, y)); + + rect.left = x; + rect.top = y; + rect.right = x + width; + rect.bottom = y + height; + + dwStyle = GetWindowLong (private->xwindow, GWL_STYLE); + dwExStyle = GetWindowLong (private->xwindow, GWL_EXSTYLE); + if (!AdjustWindowRectEx (&rect, dwStyle, FALSE, dwExStyle)) + g_warning ("gdk_window_move_resize: AdjustWindowRectEx failed"); + + if (private->window_type == GDK_WINDOW_CHILD) + { + private->x = x; + private->y = y; + private->width = width; + private->height = height; + } + GDK_NOTE (MISC, g_print ("...MoveWindow(%#x,%dx%d@+%d+%d)\n", + private->xwindow, + rect.right - rect.left, rect.bottom - rect.top, + rect.left, rect.top)); + if (!MoveWindow (private->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->destroyed && !parent_private->destroyed) + { + GDK_NOTE (MISC, g_print ("gdk_window_reparent: %#x %#x\n", + window_private->xwindow, + parent_private->xwindow)); + if (!SetParent (window_private->xwindow, parent_private->xwindow)) + g_warning ("gdk_window_reparent: SetParent failed"); + + if (!MoveWindow (window_private->xwindow, + x, y, + window_private->width, window_private->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) +{ + GdkWindowPrivate *private; + + g_return_if_fail (window != NULL); + + private = (GdkWindowPrivate*) window; + + if (!private->destroyed) + { + gdk_window_clear_area (window, 0, 0, private->width, private->height); + } +} + + +void +gdk_window_clear_area (GdkWindow *window, + gint x, + gint y, + gint width, + gint height) +{ + GdkWindowPrivate *private; + + g_return_if_fail (window != NULL); + + private = (GdkWindowPrivate*) window; + + if (!private->destroyed) + { + 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", + private->xwindow, width, height, x, y)); + hdc = GetDC (private->xwindow); + IntersectClipRect (hdc, x, y, x + width, y + height); + SendMessage (private->xwindow, WM_ERASEBKGND, (WPARAM) hdc, 0); + ReleaseDC (private->xwindow, hdc); + } +} + +void +gdk_window_clear_area_e (GdkWindow *window, + gint x, + gint y, + gint width, + gint height) +{ + GdkWindowPrivate *private; + + g_return_if_fail (window != NULL); + + private = (GdkWindowPrivate*) window; + + if (!private->destroyed) + { + RECT rect; + + GDK_NOTE (MISC, g_print ("gdk_window_clear_area_e: %#x %dx%d@+%d+%d\n", + private->xwindow, width, height, x, y)); + + rect.left = x; + rect.right = x + width; + rect.top = y; + rect.bottom = y + height; + if (!InvalidateRect (private->xwindow, &rect, TRUE)) + g_warning ("gdk_window_clear_area_e: InvalidateRect failed"); + UpdateWindow (private->xwindow); + } +} + +void +gdk_window_copy_area (GdkWindow *window, + GdkGC *gc, + gint x, + gint y, + GdkWindow *source_window, + gint source_x, + gint source_y, + gint width, + gint height) +{ + GdkWindowPrivate *src_private; + GdkWindowPrivate *dest_private; + GdkGCPrivate *gc_private; + + g_return_if_fail (window != NULL); + g_return_if_fail (gc != NULL); + + if (source_window == NULL) + source_window = window; + + src_private = (GdkWindowPrivate*) source_window; + dest_private = (GdkWindowPrivate*) window; + gc_private = (GdkGCPrivate*) gc; + + if (!src_private->destroyed && !dest_private->destroyed) + { + HDC hdcDest, hdcSrc; + + if ((hdcDest = GetDC (dest_private->xwindow)) == NULL) + g_warning ("gdk_window_copy_area: GetDC failed"); + + if ((hdcSrc = GetDC (src_private->xwindow)) == NULL) + g_warning ("gdk_window_copy_area: GetDC failed"); + + if (!BitBlt (hdcDest, x, y, width, height, hdcSrc, source_x, source_y, SRCCOPY)) + g_warning ("gdk_window_copy_area: BitBlt failed"); + + ReleaseDC (dest_private->xwindow, hdcDest); + ReleaseDC (src_private->xwindow, hdcSrc); + } +} + +void +gdk_window_raise (GdkWindow *window) +{ + GdkWindowPrivate *private; + + g_return_if_fail (window != NULL); + + private = (GdkWindowPrivate*) window; + + if (!private->destroyed) + { + GDK_NOTE (MISC, g_print ("gdk_window_raise: %#x\n", private->xwindow)); + + if (!BringWindowToTop (private->xwindow)) + g_warning ("gdk_window_raise: BringWindowToTop failed"); + } +} + +void +gdk_window_lower (GdkWindow *window) +{ + GdkWindowPrivate *private; + + g_return_if_fail (window != NULL); + + private = (GdkWindowPrivate*) window; + + if (!private->destroyed) + { + GDK_NOTE (MISC, g_print ("gdk_window_lower: %#x\n", private->xwindow)); + + if (!SetWindowPos (private->xwindow, 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); + + private = (GdkWindowPrivate*) window; + if (private->destroyed) + return; + + GDK_NOTE (MISC, g_print ("gdk_window_set_hints: %#x %dx%d..%dx%d @+%d+%d\n", + private->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->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->xwindow, GWL_STYLE); + dwExStyle = GetWindowLong (private->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->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->xwindow, GWL_STYLE); + dwExStyle = GetWindowLong (private->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->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->xwindow, GWL_STYLE); + dwExStyle = GetWindowLong (private->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->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); + + private = (GdkWindowPrivate*) window; + if (private->destroyed) + return; + + 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->xwindow, GWL_STYLE); + dwExStyle = GetWindowLong (private->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->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->xwindow, GWL_STYLE); + dwExStyle = GetWindowLong (private->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->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->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->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) +{ + GdkWindowPrivate *private; + + g_return_if_fail (window != NULL); + + private = (GdkWindowPrivate*) window; + if (!private->destroyed) + { + if (!SetWindowText (private->xwindow, title)) + g_warning ("gdk_window_set_title: SetWindowText failed"); + } +} + +void +gdk_window_set_role (GdkWindow *window, + const gchar *role) +{ + GdkWindowPrivate *private; + + g_return_if_fail (window != NULL); + + private = (GdkWindowPrivate*) window; + + GDK_NOTE (MISC, g_print ("gdk_window_set_role: %#x %s\n", + private->xwindow, (role ? role : "NULL"))); + /* XXX */ +} + +void +gdk_window_set_transient_for (GdkWindow *window, + GdkWindow *parent) +{ + GdkWindowPrivate *private; + GdkWindowPrivate *parent_private; + + g_return_if_fail (window != NULL); + + private = (GdkWindowPrivate*) window; + parent_private = (GdkWindowPrivate*) parent; + + GDK_NOTE (MISC, g_print ("gdk_window_set_transient_for: %#x %#x\n", + private->xwindow, parent_private->xwindow)); + /* XXX */ +} + +void +gdk_window_set_background (GdkWindow *window, + GdkColor *color) +{ + GdkWindowPrivate *private; + + g_return_if_fail (window != NULL); + + private = (GdkWindowPrivate*) window; + if (!private->destroyed) + { + GdkColormapPrivate *colormap_private = + (GdkColormapPrivate *) private->colormap; + + GDK_NOTE (MISC, g_print ("gdk_window_set_background: %#x %s\n", + private->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; + } +#ifdef MULTIPLE_WINDOW_CLASSES + if (colormap_private != NULL + && colormap_private->xcolormap->rc_palette) + { + /* If we are on a palettized display we can't use the window + * class background brush, but must handle WM_ERASEBKGND. + * At least, I think so. + */ +#endif + private->bg_type = GDK_WIN32_BG_PIXEL; + private->bg_pixel = *color; +#ifdef MULTIPLE_WINDOW_CLASSES + } + else + { + /* Non-palettized display; just set the window class background + brush. */ + HBRUSH hbr; + HGDIOBJ oldbrush; + COLORREF background; + + background = RGB (color->red >> 8, + color->green >> 8, + color->blue >> 8); + + if ((hbr = CreateSolidBrush (GetNearestColor (gdk_DC, + background))) == NULL) + { + g_warning ("gdk_window_set_background: CreateSolidBrush failed"); + return; + } + + oldbrush = (HGDIOBJ) GetClassLong (private->xwindow, + GCL_HBRBACKGROUND); + + if (SetClassLong (private->xwindow, GCL_HBRBACKGROUND, + (LONG) hbr) == 0) + g_warning ("gdk_window_set_background: SetClassLong failed"); + + if (!DeleteObject (oldbrush)) + g_warning ("gdk_window_set_background: DeleteObject failed"); + } +#endif + } +} + +void +gdk_window_set_back_pixmap (GdkWindow *window, + GdkPixmap *pixmap, + gint parent_relative) +{ + GdkWindowPrivate *window_private; +#ifdef MULTIPLE_WINDOW_CLASSES + GdkPixmapPrivate *pixmap_private; +#endif + + g_return_if_fail (window != NULL); + + window_private = (GdkWindowPrivate*) window; +#ifdef MULTIPLE_WINDOW_CLASSES + pixmap_private = (GdkPixmapPrivate*) pixmap; +#endif + + if (!window_private->destroyed) + { + GdkColormapPrivate *colormap_private = + (GdkColormapPrivate *) window_private->colormap; + if (window_private->bg_type == GDK_WIN32_BG_PIXMAP) + { + if (window_private->bg_pixmap != NULL) + { + gdk_pixmap_unref (window_private->bg_pixmap); + window_private->bg_pixmap = NULL; + } + window_private->bg_type = GDK_WIN32_BG_NORMAL; + } + if (parent_relative) + { + window_private->bg_type = GDK_WIN32_BG_PARENT_RELATIVE; + } + else if (!pixmap) + { +#ifdef MULTIPLE_WINDOW_CLASSES + SetClassLong (window_private->xwindow, GCL_HBRBACKGROUND, + (LONG) GetStockObject (BLACK_BRUSH)); +#endif + } +#ifdef MULTIPLE_WINDOW_CLASSES + else if (colormap_private->xcolormap->rc_palette) + { + /* Must do the background painting in the + * WM_ERASEBKGND handler. + */ + window_private->bg_type = GDK_WIN32_BG_PIXMAP; + window_private->bg_pixmap = pixmap; + gdk_pixmap_ref (pixmap); + } + else if (pixmap_private->width <= 8 + && pixmap_private->height <= 8) + { + /* We can use small pixmaps directly as background brush */ + SetClassLong (window_private->xwindow, GCL_HBRBACKGROUND, + (LONG) CreatePatternBrush (pixmap_private->xwindow)); + } +#endif + else + { + /* We must cache the pixmap in the WindowPrivate and + * paint it each time we get WM_ERASEBKGND + */ + window_private->bg_type = GDK_WIN32_BG_PIXMAP; + window_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); + + window_private = (GdkWindowPrivate*) window; + cursor_private = (GdkCursorPrivate*) cursor; + + if (!window_private->destroyed) + { + 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->xwindow, xcursor)); +#ifdef MULTIPLE_WINDOW_CLASSES + if (!SetClassLong (window_private->xwindow, GCL_HCURSOR, (LONG) xcursor)) + g_warning ("gdk_window_set_cursor: SetClassLong failed"); +#else + window_private->xcursor = xcursor; +#endif + SetCursor (xcursor); + } +} + +void +gdk_window_set_colormap (GdkWindow *window, + GdkColormap *colormap) +{ + GdkWindowPrivate *window_private; + GdkColormapPrivate *colormap_private; + + g_return_if_fail (window != NULL); + g_return_if_fail (colormap != NULL); + + window_private = (GdkWindowPrivate*) window; + colormap_private = (GdkColormapPrivate*) colormap; + + if (!window_private->destroyed) + { + /* XXX ??? */ + GDK_NOTE (MISC, g_print ("gdk_window_set_colormap: %#x %#x\n", + window_private->xwindow, + colormap_private->xcolormap)); + if (window_private->colormap) + gdk_colormap_unref (window_private->colormap); + window_private->colormap = colormap; + gdk_colormap_ref (window_private->colormap); + + if (window_private->window_type != GDK_WINDOW_TOPLEVEL) + gdk_window_add_colormap_windows (window); + } +} + +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) +{ + GdkWindowPrivate *window_private; + + if (!window) + window = (GdkWindow*) &gdk_root_parent; + + window_private = (GdkWindowPrivate*) window; + + if (!window_private->destroyed) + { + RECT rect; + + if (!GetClientRect (window_private->xwindow, &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_window_get_visual (window)->depth; + } +} + +void +gdk_window_get_position (GdkWindow *window, + gint *x, + gint *y) +{ + GdkWindowPrivate *window_private; + + g_return_if_fail (window != NULL); + + window_private = (GdkWindowPrivate*) window; + + if (x) + *x = window_private->x; + if (y) + *y = window_private->y; +} + +void +gdk_window_get_size (GdkWindow *window, + gint *width, + gint *height) +{ + GdkWindowPrivate *window_private; + + g_return_if_fail (window != NULL); + + window_private = (GdkWindowPrivate*) window; + + if (width) + *width = window_private->width; + if (height) + *height = window_private->height; +} + +GdkVisual* +gdk_window_get_visual (GdkWindow *window) +{ + GdkWindowPrivate *window_private; + + g_return_val_if_fail (window != NULL, NULL); + + window_private = (GdkWindowPrivate*) window; + /* Huh? ->parent is never set for a pixmap. We should just return + * null immeditately + */ + while (window_private && (window_private->window_type == GDK_WINDOW_PIXMAP)) + window_private = (GdkWindowPrivate*) window_private->parent; + + if (window_private && !window_private->destroyed) + { + if (window_private->colormap == NULL) + { + return gdk_visual_get_system (); /* XXX ??? */ + } + else + return ((GdkColormapPrivate *)window_private->colormap)->visual; + } + + return NULL; +} + +GdkColormap* +gdk_window_get_colormap (GdkWindow *window) +{ + GdkWindowPrivate *window_private; + + g_return_val_if_fail (window != NULL, NULL); + window_private = (GdkWindowPrivate*) window; + + g_return_val_if_fail (window_private->window_type != GDK_WINDOW_PIXMAP, NULL); + if (!window_private->destroyed) + { + if (window_private->colormap == NULL) + { + return gdk_colormap_get_system (); /* XXX ??? */ + } + else + return window_private->colormap; + } + + return NULL; +} + +GdkWindowType +gdk_window_get_type (GdkWindow *window) +{ + GdkWindowPrivate *window_private; + + g_return_val_if_fail (window != NULL, (GdkWindowType) -1); + + window_private = (GdkWindowPrivate*) window; + return window_private->window_type; +} + +gint +gdk_window_get_origin (GdkWindow *window, + gint *x, + gint *y) +{ + GdkWindowPrivate *private; + gint return_val; + gint tx = 0; + gint ty = 0; + + g_return_val_if_fail (window != NULL, 0); + + private = (GdkWindowPrivate*) window; + + if (!private->destroyed) + { + POINT pt; + + pt.x = 0; + pt.y = 0; + ClientToScreen (private->xwindow, &pt); + tx = pt.x; + ty = pt.y; + return_val = 1; + } + else + return_val = 0; + + if (x) + *x = tx; + if (y) + *y = 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); + + private = (GdkWindowPrivate*) window; + if (x) + *x = 0; + if (y) + *y = 0; + if (private->destroyed) + return; + + while (private->parent && ((GdkWindowPrivate*) private->parent)->parent) + private = (GdkWindowPrivate*) private->parent; + if (private->destroyed) + return; + + pt.x = 0; + pt.y = 0; + ClientToScreen (private->xwindow, &pt); + if (x) + *x = pt.x; + if (y) + *y = pt.y; +} + +GdkWindow* +gdk_window_get_pointer (GdkWindow *window, + gint *x, + gint *y, + GdkModifierType *mask) +{ + GdkWindowPrivate *private; + GdkWindow *return_val; + POINT pointc, point; + HWND hwnd, hwndc; + + if (!window) + window = (GdkWindow*) &gdk_root_parent; + + private = (GdkWindowPrivate*) window; + + return_val = NULL; + GetCursorPos (&pointc); + point = pointc; + ScreenToClient (private->xwindow, &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) +{ + GdkWindowPrivate *private; + GdkWindow *window; + POINT point, pointc; + HWND hwnd, hwndc; + RECT rect; + + private = &gdk_root_parent; + + 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); + + return ((GdkWindowPrivate*) window)->parent; +} + +GdkWindow* +gdk_window_get_toplevel (GdkWindow *window) +{ + GdkWindowPrivate *private; + + g_return_val_if_fail (window != NULL, NULL); + + private = (GdkWindowPrivate*) window; + + while (private->window_type == GDK_WINDOW_CHILD) + { + window = ((GdkWindowPrivate*) window)->parent; + private = (GdkWindowPrivate*) window; + } + + return window; +} + +GList* +gdk_window_get_children (GdkWindow *window) +{ + GdkWindowPrivate *private; + GList *children; + + g_return_val_if_fail (window != NULL, NULL); + + private = (GdkWindowPrivate*) window; + if (private->destroyed) + return NULL; + + /* XXX ??? */ + g_warning ("gdk_window_get_children ???"); + children = NULL; + + return children; +} + +GdkEventMask +gdk_window_get_events (GdkWindow *window) +{ + GdkWindowPrivate *private; + GdkEventMask event_mask; + + g_return_val_if_fail (window != NULL, 0); + + private = (GdkWindowPrivate*) window; + if (private->destroyed) + return 0; + + event_mask = 0; + + event_mask = private->event_mask; + + return event_mask; +} + +void +gdk_window_set_events (GdkWindow *window, + GdkEventMask event_mask) +{ + GdkWindowPrivate *private; + + g_return_if_fail (window != NULL); + + private = (GdkWindowPrivate*) window; + if (private->destroyed) + return; + + private->event_mask = event_mask; +} + +void +gdk_window_add_colormap_windows (GdkWindow *window) +{ + g_warning ("gdk_window_add_colormap_windows not implemented"); /* XXX */ +} + +/* + * This needs the X11 shape extension. + * If not available, shaped windows will look + * ugly, but programs still work. Stefan Wille + */ +void +gdk_window_shape_combine_mask (GdkWindow *window, + GdkBitmap *mask, + gint x, gint y) +{ + GdkWindowPrivate *window_private; + + g_return_if_fail (window != NULL); + + window_private = (GdkWindowPrivate*) window; + + if (!mask) + { + GDK_NOTE (MISC, g_print ("gdk_window_shape_combine_mask: %#x none\n", + window_private->xwindow)); + SetWindowRgn (window_private->xwindow, NULL, TRUE); + } + else + { + GdkPixmapPrivate *pixmap_private; + HRGN hrgn; + DWORD dwStyle; + DWORD dwExStyle; + RECT rect; + + /* Convert mask bitmap to region */ + pixmap_private = (GdkPixmapPrivate*) mask; + hrgn = BitmapToRegion (pixmap_private->xwindow); + + GDK_NOTE (MISC, g_print ("gdk_window_shape_combine_mask: %#x %#x\n", + window_private->xwindow, + pixmap_private->xwindow)); + + /* SetWindowRgn wants window (not client) coordinates */ + dwStyle = GetWindowLong (window_private->xwindow, GWL_STYLE); + dwExStyle = GetWindowLong (window_private->xwindow, GWL_EXSTYLE); + GetClientRect (window_private->xwindow, &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 (window_private->window_type == GDK_WINDOW_TOPLEVEL) + { + CombineRgn (hrgn, hrgn, + CreateRectRgn (0, 0, rect.right - rect.left, -rect.top), + RGN_OR); + } + + SetWindowRgn (window_private->xwindow, hrgn, TRUE); + } +} + +void +gdk_window_add_filter (GdkWindow *window, + GdkFilterFunc function, + gpointer data) +{ + GdkWindowPrivate *private; + GList *tmp_list; + GdkEventFilter *filter; + + private = (GdkWindowPrivate*) window; + if (private && private->destroyed) + return; + + if (private) + tmp_list = private->filters; + else + tmp_list = gdk_default_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; + + if (private) + private->filters = g_list_append (private->filters, filter); + else + gdk_default_filters = g_list_append (gdk_default_filters, filter); +} + +void +gdk_window_remove_filter (GdkWindow *window, + GdkFilterFunc function, + gpointer data) +{ + GdkWindowPrivate *private; + GList *tmp_list, *node; + GdkEventFilter *filter; + + private = (GdkWindowPrivate*) window; + + if(private) + tmp_list = private->filters; + else + tmp_list = gdk_default_filters; + + while (tmp_list) + { + filter = (GdkEventFilter *)tmp_list->data; + node = tmp_list; + tmp_list = tmp_list->next; + + if ((filter->function == function) && (filter->data == data)) + { + if(private) + private->filters = g_list_remove_link (private->filters, node); + else + gdk_default_filters = g_list_remove_link (gdk_default_filters, tmp_list); + g_list_free_1 (node); + g_free (filter); + + return; + } + } +} + +void +gdk_window_set_override_redirect (GdkWindow *window, + gboolean override_redirect) +{ + g_warning ("gdk_window_set_override_redirect not implemented"); /* XXX */ +} + +void +gdk_window_set_icon (GdkWindow *window, + GdkWindow *icon_window, + GdkPixmap *pixmap, + GdkBitmap *mask) +{ + g_warning ("gdk_window_set_icon not implemented"); /* XXX */ +} + +void +gdk_window_set_icon_name (GdkWindow *window, + gchar *name) +{ + GdkWindowPrivate *window_private; + + g_return_if_fail (window != NULL); + window_private = (GdkWindowPrivate*) window; + if (window_private->destroyed) + return; + + if (!SetWindowText (window_private->xwindow, name)) + g_warning ("gdk_window_set_icon_name: SetWindowText failed"); +} + +void +gdk_window_set_group (GdkWindow *window, + GdkWindow *leader) +{ + g_warning ("gdk_window_set_group not implemented"); /* XXX */ +} + +void +gdk_window_set_decorations (GdkWindow *window, + GdkWMDecoration decorations) +{ + GdkWindowPrivate *window_private = (GdkWindowPrivate *) window; + LONG style, exstyle; + + style = GetWindowLong (window_private->xwindow, GWL_STYLE); + exstyle = GetWindowLong (window_private->xwindow, 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 (window_private->xwindow, GWL_STYLE, style); +} + +void +gdk_window_set_functions (GdkWindow *window, + GdkWMFunction functions) +{ + GdkWindowPrivate *window_private = (GdkWindowPrivate *) window; + LONG style, exstyle; + + style = GetWindowLong (window_private->xwindow, GWL_STYLE); + exstyle = GetWindowLong (window_private->xwindow, 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 (window_private->xwindow, 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 create/insert spans */ + 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); + } + } + SetWindowRgn (win, region, TRUE); + } +} + +void +gdk_window_set_child_shapes (GdkWindow *window) +{ + GdkWindowPrivate *private; + + g_return_if_fail (window != NULL); + + private = (GdkWindowPrivate*) window; + if (private->destroyed) + return; + + gdk_propagate_shapes ( private->xwindow, FALSE); +} + +void +gdk_window_merge_child_shapes (GdkWindow *window) +{ + GdkWindowPrivate *private; + + g_return_if_fail (window != NULL); + + private = (GdkWindowPrivate*) window; + if (private->destroyed) + return; + + gdk_propagate_shapes (private->xwindow, 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); + + 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); + + while (private && + (private != &gdk_root_parent) && + (private->window_type != GDK_WINDOW_FOREIGN)) + { + if (!private->mapped) + return FALSE; + + private = (GdkWindowPrivate *)private->parent; + } + + return TRUE; +} + +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); +} + + +/* 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) +{ + GdkWindowPrivate *private = (GdkWindowPrivate *)window; + + 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) +{ + GdkWindowPrivate *private = (GdkWindowPrivate *)window; + + 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); + + if (!use_static == !private->guffaw_gravity) + return TRUE; + + if (use_static && !gdk_window_gravity_works ()) + return FALSE; + + private->guffaw_gravity = use_static; + + gdk_window_set_static_bit_gravity (window, use_static); + + tmp_list = private->children; + while (tmp_list) + { + gdk_window_set_static_win_gravity (window, use_static); + + tmp_list = tmp_list->next; + } + + return TRUE; +} diff --git a/gdk/win32/gdkx.h b/gdk/win32/gdkx.h new file mode 100644 index 000000000..508619114 --- /dev/null +++ b/gdk/win32/gdkx.h @@ -0,0 +1,59 @@ +/* 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_X_H__ +#define __GDK_X_H__ + +#include <gdk/gdk.h> +#include <gdk/gdkprivate.h> + +#include <time.h> +#include <locale.h> + +#define GDK_ROOT_WINDOW() ((guint32) HWND_DESKTOP) +#define GDK_ROOT_PARENT() ((GdkWindow *)&gdk_root_parent) +#define GDK_DISPLAY() NULL +#define GDK_WINDOW_XDISPLAY(win) NULL +#define GDK_WINDOW_XWINDOW(win) (((GdkWindowPrivate*) win)->xwindow) +#define GDK_IMAGE_XDISPLAY(image) NULL +#define GDK_IMAGE_XIMAGE(image) (((GdkImagePrivate*) image)->ximage) +#define GDK_GC_XDISPLAY(gc) NULL +#define GDK_GC_XGC(gc) (((GdkGCPrivate*) gc)->xgc) +#define GDK_COLORMAP_XDISPLAY(cmap) NULL +#define GDK_COLORMAP_XCOLORMAP(cmap) (((GdkColormapPrivate*) cmap)->xcolormap) +#define GDK_VISUAL_XVISUAL(vis) (((GdkVisualPrivate*) vis)->xvisual) +#define GDK_FONT_XDISPLAY(font) NULL +#define GDK_FONT_XFONT(font) (((GdkFontPrivate*) font)->xfont) + +GdkVisual* gdkx_visual_get (VisualID xvisualid); +/* XXX: Do not use this function until it is fixed. An X Colormap + * is useless unless we also have the visual. */ +GdkColormap* gdkx_colormap_get (Colormap xcolormap); +/* Functions to create GDK pixmaps and windows from their native equivalents */ +GdkPixmap *gdk_pixmap_foreign_new (guint32 anid); +GdkWindow *gdk_window_foreign_new (guint32 anid); + +#endif /* __GDK_X_H__ */ diff --git a/gdk/win32/gdkxid.c b/gdk/win32/gdkxid.c new file mode 100644 index 000000000..f6d7bf0f4 --- /dev/null +++ b/gdk/win32/gdkxid.c @@ -0,0 +1,87 @@ +/* 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" +#include <stdio.h> + +static guint gdk_xid_hash (XID *xid); +static gint gdk_xid_compare (XID *a, + XID *b); + + +static GHashTable *xid_ht = NULL; + + +void +gdk_xid_table_insert (XID *xid, + gpointer data) +{ + g_return_if_fail (xid != NULL); + + if (!xid_ht) + xid_ht = g_hash_table_new ((GHashFunc) gdk_xid_hash, + (GCompareFunc) gdk_xid_compare); + + g_hash_table_insert (xid_ht, xid, data); +} + +void +gdk_xid_table_remove (XID xid) +{ + if (!xid_ht) + xid_ht = g_hash_table_new ((GHashFunc) gdk_xid_hash, + (GCompareFunc) gdk_xid_compare); + + g_hash_table_remove (xid_ht, &xid); +} + +gpointer +gdk_xid_table_lookup (XID xid) +{ + gpointer data = NULL; + + if (xid_ht) + data = g_hash_table_lookup (xid_ht, &xid); + + return data; +} + + +static guint +gdk_xid_hash (XID *xid) +{ + return (guint) *xid; +} + +static gint +gdk_xid_compare (XID *a, + XID *b) +{ + return (*a == *b); +} diff --git a/gdk/win32/rc/cursor00.cur b/gdk/win32/rc/cursor00.cur Binary files differnew file mode 100644 index 000000000..337e6d4e9 --- /dev/null +++ b/gdk/win32/rc/cursor00.cur diff --git a/gdk/win32/rc/cursor02.cur b/gdk/win32/rc/cursor02.cur Binary files differnew file mode 100644 index 000000000..fbc47749f --- /dev/null +++ b/gdk/win32/rc/cursor02.cur diff --git a/gdk/win32/rc/cursor04.cur b/gdk/win32/rc/cursor04.cur Binary files differnew file mode 100644 index 000000000..9634c42f3 --- /dev/null +++ b/gdk/win32/rc/cursor04.cur diff --git a/gdk/win32/rc/cursor06.cur b/gdk/win32/rc/cursor06.cur Binary files differnew file mode 100644 index 000000000..f7188b22c --- /dev/null +++ b/gdk/win32/rc/cursor06.cur diff --git a/gdk/win32/rc/cursor08.cur b/gdk/win32/rc/cursor08.cur Binary files differnew file mode 100644 index 000000000..d9f15f775 --- /dev/null +++ b/gdk/win32/rc/cursor08.cur diff --git a/gdk/win32/rc/cursor0a.cur b/gdk/win32/rc/cursor0a.cur Binary files differnew file mode 100644 index 000000000..3f8ef4562 --- /dev/null +++ b/gdk/win32/rc/cursor0a.cur diff --git a/gdk/win32/rc/cursor0c.cur b/gdk/win32/rc/cursor0c.cur Binary files differnew file mode 100644 index 000000000..1014eddca --- /dev/null +++ b/gdk/win32/rc/cursor0c.cur diff --git a/gdk/win32/rc/cursor0e.cur b/gdk/win32/rc/cursor0e.cur Binary files differnew file mode 100644 index 000000000..964058d9a --- /dev/null +++ b/gdk/win32/rc/cursor0e.cur diff --git a/gdk/win32/rc/cursor10.cur b/gdk/win32/rc/cursor10.cur Binary files differnew file mode 100644 index 000000000..c4f78096f --- /dev/null +++ b/gdk/win32/rc/cursor10.cur diff --git a/gdk/win32/rc/cursor12.cur b/gdk/win32/rc/cursor12.cur Binary files differnew file mode 100644 index 000000000..920c936ae --- /dev/null +++ b/gdk/win32/rc/cursor12.cur diff --git a/gdk/win32/rc/cursor14.cur b/gdk/win32/rc/cursor14.cur Binary files differnew file mode 100644 index 000000000..c7de122e0 --- /dev/null +++ b/gdk/win32/rc/cursor14.cur diff --git a/gdk/win32/rc/cursor16.cur b/gdk/win32/rc/cursor16.cur Binary files differnew file mode 100644 index 000000000..cfc08f23f --- /dev/null +++ b/gdk/win32/rc/cursor16.cur diff --git a/gdk/win32/rc/cursor18.cur b/gdk/win32/rc/cursor18.cur Binary files differnew file mode 100644 index 000000000..95ed2ee96 --- /dev/null +++ b/gdk/win32/rc/cursor18.cur diff --git a/gdk/win32/rc/cursor1a.cur b/gdk/win32/rc/cursor1a.cur Binary files differnew file mode 100644 index 000000000..ea5136120 --- /dev/null +++ b/gdk/win32/rc/cursor1a.cur diff --git a/gdk/win32/rc/cursor1c.cur b/gdk/win32/rc/cursor1c.cur Binary files differnew file mode 100644 index 000000000..f46fee6fc --- /dev/null +++ b/gdk/win32/rc/cursor1c.cur diff --git a/gdk/win32/rc/cursor1e.cur b/gdk/win32/rc/cursor1e.cur Binary files differnew file mode 100644 index 000000000..49fa7f70d --- /dev/null +++ b/gdk/win32/rc/cursor1e.cur diff --git a/gdk/win32/rc/cursor20.cur b/gdk/win32/rc/cursor20.cur Binary files differnew file mode 100644 index 000000000..cf177a16c --- /dev/null +++ b/gdk/win32/rc/cursor20.cur diff --git a/gdk/win32/rc/cursor22.cur b/gdk/win32/rc/cursor22.cur Binary files differnew file mode 100644 index 000000000..2f8e91247 --- /dev/null +++ b/gdk/win32/rc/cursor22.cur diff --git a/gdk/win32/rc/cursor24.cur b/gdk/win32/rc/cursor24.cur Binary files differnew file mode 100644 index 000000000..87ba5b4db --- /dev/null +++ b/gdk/win32/rc/cursor24.cur diff --git a/gdk/win32/rc/cursor26.cur b/gdk/win32/rc/cursor26.cur Binary files differnew file mode 100644 index 000000000..0b2dbd257 --- /dev/null +++ b/gdk/win32/rc/cursor26.cur diff --git a/gdk/win32/rc/cursor28.cur b/gdk/win32/rc/cursor28.cur Binary files differnew file mode 100644 index 000000000..30550f956 --- /dev/null +++ b/gdk/win32/rc/cursor28.cur diff --git a/gdk/win32/rc/cursor2a.cur b/gdk/win32/rc/cursor2a.cur Binary files differnew file mode 100644 index 000000000..8dca4321f --- /dev/null +++ b/gdk/win32/rc/cursor2a.cur diff --git a/gdk/win32/rc/cursor2c.cur b/gdk/win32/rc/cursor2c.cur Binary files differnew file mode 100644 index 000000000..7be349469 --- /dev/null +++ b/gdk/win32/rc/cursor2c.cur diff --git a/gdk/win32/rc/cursor2e.cur b/gdk/win32/rc/cursor2e.cur Binary files differnew file mode 100644 index 000000000..7a0bc694b --- /dev/null +++ b/gdk/win32/rc/cursor2e.cur diff --git a/gdk/win32/rc/cursor30.cur b/gdk/win32/rc/cursor30.cur Binary files differnew file mode 100644 index 000000000..70ef4fd23 --- /dev/null +++ b/gdk/win32/rc/cursor30.cur diff --git a/gdk/win32/rc/cursor32.cur b/gdk/win32/rc/cursor32.cur Binary files differnew file mode 100644 index 000000000..93b5c4759 --- /dev/null +++ b/gdk/win32/rc/cursor32.cur diff --git a/gdk/win32/rc/cursor34.cur b/gdk/win32/rc/cursor34.cur Binary files differnew file mode 100644 index 000000000..0fad3f1cf --- /dev/null +++ b/gdk/win32/rc/cursor34.cur diff --git a/gdk/win32/rc/cursor36.cur b/gdk/win32/rc/cursor36.cur Binary files differnew file mode 100644 index 000000000..fc8d4f6d4 --- /dev/null +++ b/gdk/win32/rc/cursor36.cur diff --git a/gdk/win32/rc/cursor38.cur b/gdk/win32/rc/cursor38.cur Binary files differnew file mode 100644 index 000000000..4447d7d0b --- /dev/null +++ b/gdk/win32/rc/cursor38.cur diff --git a/gdk/win32/rc/cursor3a.cur b/gdk/win32/rc/cursor3a.cur Binary files differnew file mode 100644 index 000000000..d3595874e --- /dev/null +++ b/gdk/win32/rc/cursor3a.cur diff --git a/gdk/win32/rc/cursor3c.cur b/gdk/win32/rc/cursor3c.cur Binary files differnew file mode 100644 index 000000000..6a3111d7f --- /dev/null +++ b/gdk/win32/rc/cursor3c.cur diff --git a/gdk/win32/rc/cursor3e.cur b/gdk/win32/rc/cursor3e.cur Binary files differnew file mode 100644 index 000000000..fa6fe5b69 --- /dev/null +++ b/gdk/win32/rc/cursor3e.cur diff --git a/gdk/win32/rc/cursor40.cur b/gdk/win32/rc/cursor40.cur Binary files differnew file mode 100644 index 000000000..f07bf4f5c --- /dev/null +++ b/gdk/win32/rc/cursor40.cur diff --git a/gdk/win32/rc/cursor42.cur b/gdk/win32/rc/cursor42.cur Binary files differnew file mode 100644 index 000000000..387d5f0be --- /dev/null +++ b/gdk/win32/rc/cursor42.cur diff --git a/gdk/win32/rc/cursor44.cur b/gdk/win32/rc/cursor44.cur Binary files differnew file mode 100644 index 000000000..190320cba --- /dev/null +++ b/gdk/win32/rc/cursor44.cur diff --git a/gdk/win32/rc/cursor46.cur b/gdk/win32/rc/cursor46.cur Binary files differnew file mode 100644 index 000000000..3e97094d9 --- /dev/null +++ b/gdk/win32/rc/cursor46.cur diff --git a/gdk/win32/rc/cursor48.cur b/gdk/win32/rc/cursor48.cur Binary files differnew file mode 100644 index 000000000..2a5689731 --- /dev/null +++ b/gdk/win32/rc/cursor48.cur diff --git a/gdk/win32/rc/cursor4a.cur b/gdk/win32/rc/cursor4a.cur Binary files differnew file mode 100644 index 000000000..30febfa2d --- /dev/null +++ b/gdk/win32/rc/cursor4a.cur diff --git a/gdk/win32/rc/cursor4c.cur b/gdk/win32/rc/cursor4c.cur Binary files differnew file mode 100644 index 000000000..0407d77a2 --- /dev/null +++ b/gdk/win32/rc/cursor4c.cur diff --git a/gdk/win32/rc/cursor4e.cur b/gdk/win32/rc/cursor4e.cur Binary files differnew file mode 100644 index 000000000..a58e3dba5 --- /dev/null +++ b/gdk/win32/rc/cursor4e.cur diff --git a/gdk/win32/rc/cursor50.cur b/gdk/win32/rc/cursor50.cur Binary files differnew file mode 100644 index 000000000..7352420db --- /dev/null +++ b/gdk/win32/rc/cursor50.cur diff --git a/gdk/win32/rc/cursor52.cur b/gdk/win32/rc/cursor52.cur Binary files differnew file mode 100644 index 000000000..435f99f46 --- /dev/null +++ b/gdk/win32/rc/cursor52.cur diff --git a/gdk/win32/rc/cursor54.cur b/gdk/win32/rc/cursor54.cur Binary files differnew file mode 100644 index 000000000..54eb4f2ce --- /dev/null +++ b/gdk/win32/rc/cursor54.cur diff --git a/gdk/win32/rc/cursor56.cur b/gdk/win32/rc/cursor56.cur Binary files differnew file mode 100644 index 000000000..c808bd4ea --- /dev/null +++ b/gdk/win32/rc/cursor56.cur diff --git a/gdk/win32/rc/cursor58.cur b/gdk/win32/rc/cursor58.cur Binary files differnew file mode 100644 index 000000000..98b6a2fb5 --- /dev/null +++ b/gdk/win32/rc/cursor58.cur diff --git a/gdk/win32/rc/cursor5a.cur b/gdk/win32/rc/cursor5a.cur Binary files differnew file mode 100644 index 000000000..b00070e5c --- /dev/null +++ b/gdk/win32/rc/cursor5a.cur diff --git a/gdk/win32/rc/cursor5c.cur b/gdk/win32/rc/cursor5c.cur Binary files differnew file mode 100644 index 000000000..a407b55fb --- /dev/null +++ b/gdk/win32/rc/cursor5c.cur diff --git a/gdk/win32/rc/cursor5e.cur b/gdk/win32/rc/cursor5e.cur Binary files differnew file mode 100644 index 000000000..ab3449f7a --- /dev/null +++ b/gdk/win32/rc/cursor5e.cur diff --git a/gdk/win32/rc/cursor60.cur b/gdk/win32/rc/cursor60.cur Binary files differnew file mode 100644 index 000000000..847969d26 --- /dev/null +++ b/gdk/win32/rc/cursor60.cur diff --git a/gdk/win32/rc/cursor62.cur b/gdk/win32/rc/cursor62.cur Binary files differnew file mode 100644 index 000000000..36404a50b --- /dev/null +++ b/gdk/win32/rc/cursor62.cur diff --git a/gdk/win32/rc/cursor64.cur b/gdk/win32/rc/cursor64.cur Binary files differnew file mode 100644 index 000000000..a6bdd0efc --- /dev/null +++ b/gdk/win32/rc/cursor64.cur diff --git a/gdk/win32/rc/cursor66.cur b/gdk/win32/rc/cursor66.cur Binary files differnew file mode 100644 index 000000000..81d53b426 --- /dev/null +++ b/gdk/win32/rc/cursor66.cur diff --git a/gdk/win32/rc/cursor68.cur b/gdk/win32/rc/cursor68.cur Binary files differnew file mode 100644 index 000000000..27cfaf077 --- /dev/null +++ b/gdk/win32/rc/cursor68.cur diff --git a/gdk/win32/rc/cursor6a.cur b/gdk/win32/rc/cursor6a.cur Binary files differnew file mode 100644 index 000000000..20f138e45 --- /dev/null +++ b/gdk/win32/rc/cursor6a.cur diff --git a/gdk/win32/rc/cursor6c.cur b/gdk/win32/rc/cursor6c.cur Binary files differnew file mode 100644 index 000000000..1e8d6d82e --- /dev/null +++ b/gdk/win32/rc/cursor6c.cur diff --git a/gdk/win32/rc/cursor6e.cur b/gdk/win32/rc/cursor6e.cur Binary files differnew file mode 100644 index 000000000..3a9b6b0ff --- /dev/null +++ b/gdk/win32/rc/cursor6e.cur diff --git a/gdk/win32/rc/cursor70.cur b/gdk/win32/rc/cursor70.cur Binary files differnew file mode 100644 index 000000000..e2d76732a --- /dev/null +++ b/gdk/win32/rc/cursor70.cur diff --git a/gdk/win32/rc/cursor72.cur b/gdk/win32/rc/cursor72.cur Binary files differnew file mode 100644 index 000000000..4994c6e7a --- /dev/null +++ b/gdk/win32/rc/cursor72.cur diff --git a/gdk/win32/rc/cursor74.cur b/gdk/win32/rc/cursor74.cur Binary files differnew file mode 100644 index 000000000..d5e43613d --- /dev/null +++ b/gdk/win32/rc/cursor74.cur diff --git a/gdk/win32/rc/cursor76.cur b/gdk/win32/rc/cursor76.cur Binary files differnew file mode 100644 index 000000000..34f402aac --- /dev/null +++ b/gdk/win32/rc/cursor76.cur diff --git a/gdk/win32/rc/cursor78.cur b/gdk/win32/rc/cursor78.cur Binary files differnew file mode 100644 index 000000000..70e25dd1c --- /dev/null +++ b/gdk/win32/rc/cursor78.cur diff --git a/gdk/win32/rc/cursor7a.cur b/gdk/win32/rc/cursor7a.cur Binary files differnew file mode 100644 index 000000000..5ea95c4c6 --- /dev/null +++ b/gdk/win32/rc/cursor7a.cur diff --git a/gdk/win32/rc/cursor7c.cur b/gdk/win32/rc/cursor7c.cur Binary files differnew file mode 100644 index 000000000..2b46717dd --- /dev/null +++ b/gdk/win32/rc/cursor7c.cur diff --git a/gdk/win32/rc/cursor7e.cur b/gdk/win32/rc/cursor7e.cur Binary files differnew file mode 100644 index 000000000..4b24e5088 --- /dev/null +++ b/gdk/win32/rc/cursor7e.cur diff --git a/gdk/win32/rc/cursor80.cur b/gdk/win32/rc/cursor80.cur Binary files differnew file mode 100644 index 000000000..a3955a5f7 --- /dev/null +++ b/gdk/win32/rc/cursor80.cur diff --git a/gdk/win32/rc/cursor82.cur b/gdk/win32/rc/cursor82.cur Binary files differnew file mode 100644 index 000000000..984cfbaac --- /dev/null +++ b/gdk/win32/rc/cursor82.cur diff --git a/gdk/win32/rc/cursor84.cur b/gdk/win32/rc/cursor84.cur Binary files differnew file mode 100644 index 000000000..cd6807ec4 --- /dev/null +++ b/gdk/win32/rc/cursor84.cur diff --git a/gdk/win32/rc/cursor86.cur b/gdk/win32/rc/cursor86.cur Binary files differnew file mode 100644 index 000000000..2d38c0351 --- /dev/null +++ b/gdk/win32/rc/cursor86.cur diff --git a/gdk/win32/rc/cursor88.cur b/gdk/win32/rc/cursor88.cur Binary files differnew file mode 100644 index 000000000..62b80615f --- /dev/null +++ b/gdk/win32/rc/cursor88.cur diff --git a/gdk/win32/rc/cursor8a.cur b/gdk/win32/rc/cursor8a.cur Binary files differnew file mode 100644 index 000000000..6c5358d69 --- /dev/null +++ b/gdk/win32/rc/cursor8a.cur diff --git a/gdk/win32/rc/cursor8c.cur b/gdk/win32/rc/cursor8c.cur Binary files differnew file mode 100644 index 000000000..103010b64 --- /dev/null +++ b/gdk/win32/rc/cursor8c.cur diff --git a/gdk/win32/rc/cursor8e.cur b/gdk/win32/rc/cursor8e.cur Binary files differnew file mode 100644 index 000000000..a500a38df --- /dev/null +++ b/gdk/win32/rc/cursor8e.cur diff --git a/gdk/win32/rc/cursor90.cur b/gdk/win32/rc/cursor90.cur Binary files differnew file mode 100644 index 000000000..08731f823 --- /dev/null +++ b/gdk/win32/rc/cursor90.cur diff --git a/gdk/win32/rc/cursor92.cur b/gdk/win32/rc/cursor92.cur Binary files differnew file mode 100644 index 000000000..4364b5df1 --- /dev/null +++ b/gdk/win32/rc/cursor92.cur diff --git a/gdk/win32/rc/cursor94.cur b/gdk/win32/rc/cursor94.cur Binary files differnew file mode 100644 index 000000000..7777d5380 --- /dev/null +++ b/gdk/win32/rc/cursor94.cur diff --git a/gdk/win32/rc/cursor96.cur b/gdk/win32/rc/cursor96.cur Binary files differnew file mode 100644 index 000000000..cecaea39b --- /dev/null +++ b/gdk/win32/rc/cursor96.cur diff --git a/gdk/win32/rc/cursor98.cur b/gdk/win32/rc/cursor98.cur Binary files differnew file mode 100644 index 000000000..5cab68eba --- /dev/null +++ b/gdk/win32/rc/cursor98.cur diff --git a/gdk/win32/rc/gdk.rc b/gdk/win32/rc/gdk.rc new file mode 100644 index 000000000..b52b3f1b2 --- /dev/null +++ b/gdk/win32/rc/gdk.rc @@ -0,0 +1,78 @@ +GTK_ICON ICON "gtk.ico" +X_cursor CURSOR DISCARDABLE "cursor00.cur" +arrow CURSOR DISCARDABLE "cursor02.cur" +based_arrow_down CURSOR DISCARDABLE "cursor04.cur" +based_arrow_up CURSOR DISCARDABLE "cursor06.cur" +boat CURSOR DISCARDABLE "cursor08.cur" +bogosity CURSOR DISCARDABLE "cursor0a.cur" +bottom_left_corner CURSOR DISCARDABLE "cursor0c.cur" +bottom_right_corner CURSOR DISCARDABLE "cursor0e.cur" +bottom_side CURSOR DISCARDABLE "cursor10.cur" +bottom_tee CURSOR DISCARDABLE "cursor12.cur" +box_spiral CURSOR DISCARDABLE "cursor14.cur" +center_ptr CURSOR DISCARDABLE "cursor16.cur" +circle CURSOR DISCARDABLE "cursor18.cur" +clock CURSOR DISCARDABLE "cursor1a.cur" +coffee_mug CURSOR DISCARDABLE "cursor1c.cur" +cross CURSOR DISCARDABLE "cursor1e.cur" +cross_reverse CURSOR DISCARDABLE "cursor20.cur" +crosshair CURSOR DISCARDABLE "cursor22.cur" +diamond_cross CURSOR DISCARDABLE "cursor24.cur" +dot CURSOR DISCARDABLE "cursor26.cur" +dotbox CURSOR DISCARDABLE "cursor28.cur" +double_arrow CURSOR DISCARDABLE "cursor2a.cur" +draft_large CURSOR DISCARDABLE "cursor2c.cur" +draft_small CURSOR DISCARDABLE "cursor2e.cur" +draped_box CURSOR DISCARDABLE "cursor30.cur" +exchange CURSOR DISCARDABLE "cursor32.cur" +fleur CURSOR DISCARDABLE "cursor34.cur" +gobbler CURSOR DISCARDABLE "cursor36.cur" +gumby CURSOR DISCARDABLE "cursor38.cur" +hand1 CURSOR DISCARDABLE "cursor3a.cur" +hand2 CURSOR DISCARDABLE "cursor3c.cur" +heart CURSOR DISCARDABLE "cursor3e.cur" +icon CURSOR DISCARDABLE "cursor40.cur" +iron_cross CURSOR DISCARDABLE "cursor42.cur" +left_ptr CURSOR DISCARDABLE "cursor44.cur" +left_side CURSOR DISCARDABLE "cursor46.cur" +left_tee CURSOR DISCARDABLE "cursor48.cur" +leftbutton CURSOR DISCARDABLE "cursor4a.cur" +ll_angle CURSOR DISCARDABLE "cursor4c.cur" +lr_angle CURSOR DISCARDABLE "cursor4e.cur" +man CURSOR DISCARDABLE "cursor50.cur" +middlebutton CURSOR DISCARDABLE "cursor52.cur" +mouse CURSOR DISCARDABLE "cursor54.cur" +pencil CURSOR DISCARDABLE "cursor56.cur" +pirate CURSOR DISCARDABLE "cursor58.cur" +plus CURSOR DISCARDABLE "cursor5a.cur" +question_arrow CURSOR DISCARDABLE "cursor5c.cur" +right_ptr CURSOR DISCARDABLE "cursor5e.cur" +right_side CURSOR DISCARDABLE "cursor60.cur" +right_tee CURSOR DISCARDABLE "cursor62.cur" +rightbutton CURSOR DISCARDABLE "cursor64.cur" +rtl_logo CURSOR DISCARDABLE "cursor66.cur" +sailboat CURSOR DISCARDABLE "cursor68.cur" +sb_down_arrow CURSOR DISCARDABLE "cursor6a.cur" +sb_h_double_arrow CURSOR DISCARDABLE "cursor6c.cur" +sb_left_arrow CURSOR DISCARDABLE "cursor6e.cur" +sb_right_arrow CURSOR DISCARDABLE "cursor70.cur" +sb_up_arrow CURSOR DISCARDABLE "cursor72.cur" +sb_v_double_arrow CURSOR DISCARDABLE "cursor74.cur" +shuttle CURSOR DISCARDABLE "cursor76.cur" +sizing CURSOR DISCARDABLE "cursor78.cur" +spider CURSOR DISCARDABLE "cursor7a.cur" +spraycan CURSOR DISCARDABLE "cursor7c.cur" +star CURSOR DISCARDABLE "cursor7e.cur" +target CURSOR DISCARDABLE "cursor80.cur" +tcross CURSOR DISCARDABLE "cursor82.cur" +top_left_arrow CURSOR DISCARDABLE "cursor84.cur" +top_left_corner CURSOR DISCARDABLE "cursor86.cur" +top_right_corner CURSOR DISCARDABLE "cursor88.cur" +top_side CURSOR DISCARDABLE "cursor8a.cur" +top_tee CURSOR DISCARDABLE "cursor8c.cur" +trek CURSOR DISCARDABLE "cursor8e.cur" +ul_angle CURSOR DISCARDABLE "cursor90.cur" +umbrella CURSOR DISCARDABLE "cursor92.cur" +ur_angle CURSOR DISCARDABLE "cursor94.cur" +xterm CURSOR DISCARDABLE "cursor98.cur" +watch CURSOR DISCARDABLE "cursor96.cur" diff --git a/gdk/win32/rc/gtk.ico b/gdk/win32/rc/gtk.ico Binary files differnew file mode 100644 index 000000000..54ee412e9 --- /dev/null +++ b/gdk/win32/rc/gtk.ico |