]> Pileus Git - ~andy/gtk/blob - gdk/win32/gdkevents-win32.c
ca1ce112d5d812d994c40b7c18876ec946b05065
[~andy/gtk] / gdk / win32 / gdkevents-win32.c
1 /* GDK - The GIMP Drawing Kit
2  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3  * Copyright (C) 1998-2002 Tor Lillqvist
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18  * Boston, MA 02111-1307, USA.
19  */
20
21 /*
22  * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
23  * file for a list of people on the GTK+ Team.  See the ChangeLog
24  * files for a list of changes.  These files are distributed with
25  * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
26  */
27
28 /* Cannot use TrackMouseEvent, as the stupid WM_MOUSELEAVE message
29  * doesn't tell us where the mouse has gone. Thus we cannot use it to
30  * generate a correct GdkNotifyType. Pity, as using TrackMouseEvent
31  * otherwise would make it possible to reliably generate
32  * GDK_LEAVE_NOTIFY events, which would help get rid of those pesky
33  * tooltips sometimes popping up in the wrong place.
34  */
35
36 /* Do use SetCapture, it works now. Thanks to jpe@archaeopteryx.com */
37 #define USE_SETCAPTURE 1
38
39 #include <glib/gprintf.h>
40
41 #include "gdk.h"
42 #include "gdkprivate-win32.h"
43 #include "gdkinput-win32.h"
44 #include "gdkkeysyms.h"
45
46 #ifdef G_WITH_CYGWIN
47 #include <fcntl.h>
48 #include <errno.h>
49 #endif
50
51 #include <objbase.h>
52
53 #if defined (__GNUC__) && defined (HAVE_DIMM_H)
54 /* The w32api imm.h clashes a bit with the IE5.5 dimm.h */
55 # define IMEMENUITEMINFOA hidden_IMEMENUITEMINFOA
56 # define IMEMENUITEMINFOW hidden_IMEMENUITEMINFOW
57 #endif
58
59 #include <imm.h>
60
61 #if defined (__GNUC__) && defined (HAVE_DIMM_H)
62 # undef IMEMENUITEMINFOA
63 # undef IMEMENUITEMINFOW
64 #endif
65
66 #ifdef HAVE_DIMM_H
67 #include <dimm.h>
68 #endif
69
70 /* 
71  * Private function declarations
72  */
73
74 static GdkFilterReturn
75                  gdk_event_apply_filters(MSG      *msg,
76                                          GdkEvent *event,
77                                          GList    *filters);
78 static gboolean  gdk_event_translate    (GdkDisplay *display,
79                                          GdkEvent *event, 
80                                          MSG      *msg,
81                                          gboolean *ret_val_flagp,
82                                          gint     *ret_valp,
83                                          gboolean  return_exposes);
84
85 static gboolean gdk_event_prepare  (GSource     *source,
86                                     gint        *timeout);
87 static gboolean gdk_event_check    (GSource     *source);
88 static gboolean gdk_event_dispatch (GSource     *source,
89                                     GSourceFunc  callback,
90                                     gpointer     user_data);
91
92 /* Private variable declarations
93  */
94
95 static GdkWindow *p_grab_window = NULL; /* Window that currently
96                                          * holds the pointer grab
97                                          */
98
99 static GdkWindow *k_grab_window = NULL; /* Window the holds the
100                                          * keyboard grab
101                                          */
102
103 static GList *client_filters;   /* Filters for client messages */
104
105 static gboolean p_grab_automatic;
106 static GdkEventMask p_grab_mask;
107 static gboolean p_grab_owner_events, k_grab_owner_events;
108 static HCURSOR p_grab_cursor;
109
110 static GSourceFuncs event_funcs = {
111   gdk_event_prepare,
112   gdk_event_check,
113   gdk_event_dispatch,
114   NULL
115 };
116
117 GPollFD event_poll_fd;
118
119 static GdkWindow *current_window = NULL;
120 static gint current_x, current_y;
121 static gdouble current_x_root, current_y_root;
122 static UINT gdk_ping_msg;
123 static UINT msh_mousewheel_msg;
124 static gboolean ignore_wm_char = FALSE;
125 static gboolean is_altgr_key = FALSE;
126
127 #ifdef HAVE_DIMM_H
128 static IActiveIMMApp *active_imm_app = NULL;
129 static IActiveIMMMessagePumpOwner *active_imm_msgpump_owner = NULL;
130 #endif
131
132 static gboolean use_ime_composition = FALSE;
133
134 static HKL latin_locale = NULL;
135
136 gulong
137 _gdk_win32_get_next_tick (gulong suggested_tick)
138 {
139   static gulong cur_tick = 0;
140
141   if (suggested_tick == 0)
142     suggested_tick = GetTickCount ();
143   if (suggested_tick <= cur_tick)
144     return ++cur_tick;
145   else
146     return cur_tick = suggested_tick;
147 }
148
149 static LRESULT 
150 real_window_procedure (HWND   hwnd,
151                        UINT   message,
152                        WPARAM wparam,
153                        LPARAM lparam)
154 {
155   /* any way to have more than one display on win32 ? */
156   GdkDisplay *display = gdk_display_get_default ();
157   GdkEvent *event;
158   MSG msg;
159   DWORD pos;
160 #ifdef HAVE_DIMM_H
161   LRESULT lres;
162 #endif
163   gint ret_val;
164   gboolean ret_val_flag;
165
166   msg.hwnd = hwnd;
167   msg.message = message;
168   msg.wParam = wparam;
169   msg.lParam = lparam;
170   msg.time = _gdk_win32_get_next_tick (0);
171   pos = GetMessagePos ();
172   msg.pt.x = LOWORD (pos);
173   msg.pt.y = HIWORD (pos);
174
175   event = gdk_event_new (GDK_NOTHING);
176   ((GdkEventPrivate *)event)->flags |= GDK_EVENT_PENDING;
177   if (gdk_event_translate (display, event, &msg, &ret_val_flag, &ret_val, FALSE))
178     {
179       ((GdkEventPrivate *)event)->flags &= ~GDK_EVENT_PENDING;
180
181       _gdk_event_queue_append (display, event);
182
183       if (event->type == GDK_BUTTON_PRESS)
184         _gdk_event_button_generate (display, event);
185 #if 1
186       /* Wake up WaitMessage */
187       PostMessage (NULL, gdk_ping_msg, 0, 0);
188 #endif
189       
190       if (ret_val_flag)
191         return ret_val;
192       else
193         return FALSE;
194     }
195   else
196     gdk_event_free (event);
197
198   if (ret_val_flag)
199     return ret_val;
200   else
201     {
202 #ifndef HAVE_DIMM_H
203       return DefWindowProc (hwnd, message, wparam, lparam);
204 #else
205       if (active_imm_app == NULL
206           || (*active_imm_app->lpVtbl->OnDefWindowProc) (active_imm_app, hwnd, message, wparam, lparam, &lres) == S_FALSE)
207         return DefWindowProc (hwnd, message, wparam, lparam);
208       else
209         return lres;
210 #endif
211     }
212 }
213
214 LRESULT CALLBACK
215 _gdk_win32_window_procedure (HWND   hwnd,
216                              UINT   message,
217                              WPARAM wparam,
218                              LPARAM lparam)
219 {
220   LRESULT retval;
221
222   GDK_NOTE (MISC, g_print ("_gdk_win32_window_procedure: %p %s\n",
223                            hwnd, _gdk_win32_message_to_string (message)));
224
225   retval = real_window_procedure (hwnd, message, wparam, lparam);
226
227   GDK_NOTE (MISC, g_print ("_gdk_win32_window_procedure: %p %s return %ld\n",
228                            hwnd, _gdk_win32_message_to_string (message), retval));
229
230   return retval;
231 }
232
233 void 
234 _gdk_events_init (void)
235 {
236   GSource *source;
237 #ifdef HAVE_DIMM_H
238   HRESULT hres;
239 #endif
240   int i, j, n;
241
242   /* List of languages that use a latin keyboard. Somewhat sorted in
243    * "order of least surprise", in case we have to load one of them if
244    * the user only has arabic loaded, for instance.
245    */
246   static int latin_languages[] = {
247     LANG_ENGLISH,
248     LANG_SPANISH,
249     LANG_PORTUGUESE,
250     LANG_FRENCH,
251     LANG_GERMAN,
252     /* Rest in numeric order */
253     LANG_CZECH,
254     LANG_DANISH,
255     LANG_FINNISH,
256     LANG_HUNGARIAN,
257     LANG_ICELANDIC,
258     LANG_ITALIAN,
259     LANG_DUTCH,
260     LANG_NORWEGIAN,
261     LANG_POLISH,
262     LANG_ROMANIAN,
263     LANG_SLOVAK,
264     LANG_ALBANIAN,
265     LANG_SWEDISH,
266     LANG_TURKISH,
267     LANG_INDONESIAN,
268     LANG_SLOVENIAN,
269     LANG_ESTONIAN,
270     LANG_LATVIAN,
271     LANG_LITHUANIAN,
272     LANG_VIETNAMESE,
273     LANG_AFRIKAANS,
274     LANG_FAEROESE,
275     LANG_SWAHILI
276   };
277
278   gdk_ping_msg = RegisterWindowMessage ("gdk-ping");
279   GDK_NOTE (EVENTS, g_print ("gdk-ping = %#x\n", gdk_ping_msg));
280
281   /* This is the string MSH_MOUSEWHEEL from zmouse.h,
282    * http://www.microsoft.com/mouse/intellimouse/sdk/zmouse.h
283    * This message is used by mouse drivers than cannot generate WM_MOUSEWHEEL
284    * or on Win95.
285    */
286   msh_mousewheel_msg = RegisterWindowMessage ("MSWHEEL_ROLLMSG");
287   GDK_NOTE (EVENTS, g_print ("MSH_MOUSEWHEEL = %#x\n", msh_mousewheel_msg));
288
289   /* Check if we have some input locale identifier loaded that uses a
290    * latin keyboard, to be able to get the virtual-key code for the
291    * latin characters corresponding to ASCII control characters.
292    */
293   if ((n = GetKeyboardLayoutList (0, NULL)) == 0)
294     WIN32_API_FAILED ("GetKeyboardLayoutList");
295   else
296     {
297       HKL *hkl_list = g_new (HKL, n);
298       if (GetKeyboardLayoutList (n, hkl_list) == 0)
299         WIN32_API_FAILED ("GetKeyboardLayoutList");
300       else
301         {
302           for (i = 0; latin_locale == NULL && i < n; i++)
303             for (j = 0; j < G_N_ELEMENTS (latin_languages); j++)
304               if (PRIMARYLANGID (LOWORD (hkl_list[i])) == latin_languages[j])
305                 {
306                   latin_locale = hkl_list [i];
307                   break;
308                 }
309         }
310       g_free (hkl_list);
311     }
312
313   if (latin_locale == NULL)
314     {
315       /* Try to load a keyboard layout with latin characters then.
316        */
317       i = 0;
318       while (latin_locale == NULL && i < G_N_ELEMENTS (latin_languages))
319         {
320           char id[9];
321           g_sprintf (id, "%08x", MAKELANGID (latin_languages[i++], SUBLANG_DEFAULT));
322           latin_locale = LoadKeyboardLayout (id, KLF_NOTELLSHELL|KLF_SUBSTITUTE_OK);
323         }
324     }
325
326   GDK_NOTE (EVENTS, g_print ("latin_locale = %08x\n", (guint) latin_locale));
327
328   source = g_source_new (&event_funcs, sizeof (GSource));
329   g_source_set_priority (source, GDK_PRIORITY_EVENTS);
330
331 #ifdef G_WITH_CYGWIN
332   event_poll_fd.fd = open ("/dev/windows", O_RDONLY);
333   if (event_poll_fd.fd == -1)
334     g_error ("can't open \"/dev/windows\": %s", g_strerror (errno));
335 #else
336   event_poll_fd.fd = G_WIN32_MSG_HANDLE;
337 #endif
338   event_poll_fd.events = G_IO_IN;
339   
340   g_source_add_poll (source, &event_poll_fd);
341   g_source_set_can_recurse (source, TRUE);
342   g_source_attach (source, NULL);
343
344 #ifdef HAVE_DIMM_H
345   hres = CoCreateInstance (&CLSID_CActiveIMM,
346                            NULL,
347                            CLSCTX_ALL,
348                            &IID_IActiveIMMApp,
349                            (LPVOID *) &active_imm_app);
350   
351   if (hres == S_OK)
352     {
353       GDK_NOTE (EVENTS, g_print ("IActiveIMMApp created %p\n",
354                                  active_imm_app));
355       (*active_imm_app->lpVtbl->Activate) (active_imm_app, TRUE);
356       
357       hres = (*active_imm_app->lpVtbl->QueryInterface) (active_imm_app, &IID_IActiveIMMMessagePumpOwner, &active_imm_msgpump_owner);
358       GDK_NOTE (EVENTS, g_print ("IActiveIMMMessagePumpOwner created %p\n",
359                                  active_imm_msgpump_owner));
360       (active_imm_msgpump_owner->lpVtbl->Start) (active_imm_msgpump_owner);
361     }
362 #endif
363
364   if (IS_WIN_NT () && (_windows_version & 0xFF) == 5)
365     {
366       /* On Win2k (Beta 3, at least) WM_IME_CHAR doesn't seem to work
367        * correctly for non-Unicode applications. Handle
368        * WM_IME_COMPOSITION with GCS_RESULTSTR instead, fetch the
369        * Unicode char from the IME with ImmGetCompositionStringW().
370        */
371       use_ime_composition = TRUE;
372     }
373 }
374
375 /*
376  *--------------------------------------------------------------
377  * gdk_events_pending
378  *
379  *   Returns if events are pending on the queue.
380  *
381  * Arguments:
382  *
383  * Results:
384  *   Returns TRUE if events are pending
385  *
386  * Side effects:
387  *
388  *--------------------------------------------------------------
389  */
390
391 gboolean
392 gdk_events_pending (void)
393 {
394   MSG msg;
395   GdkDisplay *display = gdk_display_get_default ();
396
397   return (_gdk_event_queue_find_first (display) ||
398           PeekMessage (&msg, NULL, 0, 0, PM_NOREMOVE));
399 }
400
401 /*
402  *--------------------------------------------------------------
403  * gdk_event_get_graphics_expose
404  *
405  *   Waits for a GraphicsExpose or NoExpose event
406  *
407  * Arguments:
408  *
409  * Results: 
410  *   For GraphicsExpose events, returns a pointer to the event
411  *   converted into a GdkEvent Otherwise, returns NULL.
412  *
413  * Side effects:
414  *
415  *-------------------------------------------------------------- */
416
417 GdkEvent*
418 gdk_event_get_graphics_expose (GdkWindow *window)
419 {
420   MSG msg;
421   GdkEvent *event;
422
423   g_return_val_if_fail (window != NULL, NULL);
424   
425   GDK_NOTE (EVENTS, g_print ("gdk_event_get_graphics_expose\n"));
426
427   if (PeekMessage (&msg, GDK_WINDOW_HWND (window), WM_PAINT, WM_PAINT, PM_REMOVE))
428     {
429       event = gdk_event_new (GDK_NOTHING);
430       
431       if (gdk_event_translate (gdk_drawable_get_display (window), 
432                                event, &msg, NULL, NULL, TRUE))
433         {
434           GDK_NOTE (EVENTS, g_print ("gdk_event_get_graphics_expose: got it!\n"));
435           return event;
436         }
437       else
438         gdk_event_free (event);
439     }
440   
441   GDK_NOTE (EVENTS, g_print ("gdk_event_get_graphics_expose: nope\n"));
442   return NULL;  
443 }
444
445 static char *
446 event_mask_string (GdkEventMask mask)
447 {
448   static char bfr[500];
449   char *p = bfr;
450
451   *p = '\0';
452 #define BIT(x) \
453   if (mask & GDK_##x##_MASK) \
454     p += g_sprintf (p, "%s" #x, (p > bfr ? " " : ""))
455   BIT (EXPOSURE);
456   BIT (POINTER_MOTION);
457   BIT (POINTER_MOTION_HINT);
458   BIT (BUTTON_MOTION);
459   BIT (BUTTON1_MOTION);
460   BIT (BUTTON2_MOTION);
461   BIT (BUTTON3_MOTION);
462   BIT (BUTTON_PRESS);
463   BIT (BUTTON_RELEASE);
464   BIT (KEY_PRESS);
465   BIT (KEY_RELEASE);
466   BIT (ENTER_NOTIFY);
467   BIT (LEAVE_NOTIFY);
468   BIT (FOCUS_CHANGE);
469   BIT (STRUCTURE);
470   BIT (PROPERTY_CHANGE);
471   BIT (VISIBILITY_NOTIFY);
472   BIT (PROXIMITY_IN);
473   BIT (PROXIMITY_OUT);
474   BIT (SUBSTRUCTURE);
475   BIT (SCROLL);
476 #undef BIT
477
478   return bfr;
479 }
480
481 /*
482  *--------------------------------------------------------------
483  * gdk_pointer_grab
484  *
485  *   Grabs the pointer to a specific window
486  *
487  * Arguments:
488  *   "window" is the window which will receive the grab
489  *   "owner_events" specifies whether events will be reported as is,
490  *     or relative to "window"
491  *   "event_mask" masks only interesting events
492  *   "confine_to" limits the cursor movement to the specified window
493  *   "cursor" changes the cursor for the duration of the grab
494  *   "time" specifies the time
495  *
496  * Results:
497  *
498  * Side effects:
499  *   requires a corresponding call to gdk_pointer_ungrab
500  *
501  *--------------------------------------------------------------
502  */
503
504 GdkGrabStatus
505 gdk_pointer_grab (GdkWindow    *window,
506                   gboolean      owner_events,
507                   GdkEventMask  event_mask,
508                   GdkWindow    *confine_to,
509                   GdkCursor    *cursor,
510                   guint32       time)
511 {
512   HWND hwnd_confined_to;
513   HCURSOR hcursor;
514   GdkCursorPrivate *cursor_private;
515   gint return_val = GDK_GRAB_SUCCESS;
516
517   g_return_val_if_fail (window != NULL, 0);
518   g_return_val_if_fail (GDK_IS_WINDOW (window), 0);
519   g_return_val_if_fail (confine_to == NULL || GDK_IS_WINDOW (confine_to), 0);
520   
521   cursor_private = (GdkCursorPrivate*) cursor;
522   
523   if (!confine_to || GDK_WINDOW_DESTROYED (confine_to))
524     hwnd_confined_to = NULL;
525   else
526     hwnd_confined_to = GDK_WINDOW_HWND (confine_to);
527   
528   if (!cursor)
529     hcursor = NULL;
530   else
531     hcursor = cursor_private->hcursor;
532 #if 0
533   return_val = _gdk_input_grab_pointer (window,
534                                         owner_events,
535                                         event_mask,
536                                         confine_to,
537                                         time);
538 #endif
539   if (return_val == GDK_GRAB_SUCCESS)
540     {
541       if (!GDK_WINDOW_DESTROYED (window))
542         {
543           GDK_NOTE (EVENTS, g_print ("gdk_pointer_grab: %p %s %p %s\n",
544                                      GDK_WINDOW_HWND (window),
545                                      (owner_events ? "TRUE" : "FALSE"),
546                                      hcursor,
547                                      event_mask_string (event_mask)));
548           p_grab_mask = event_mask;
549           p_grab_owner_events = (owner_events != 0);
550           p_grab_automatic = FALSE;
551           
552 #if USE_SETCAPTURE
553           SetCapture (GDK_WINDOW_HWND (window));
554 #endif
555           return_val = GDK_GRAB_SUCCESS;
556         }
557       else
558         return_val = GDK_GRAB_ALREADY_GRABBED;
559     }
560   
561   if (return_val == GDK_GRAB_SUCCESS)
562     {
563       p_grab_window = window;
564       p_grab_cursor = hcursor;
565     }
566   
567   return return_val;
568 }
569
570 void
571 gdk_display_pointer_ungrab (GdkDisplay *display,
572                             guint32     time)
573 {
574   GDK_NOTE (EVENTS, g_print ("gdk_pointer_ungrab\n"));
575   g_return_if_fail (display == gdk_display_get_default ());
576
577 #if 0
578   _gdk_input_ungrab_pointer (time);
579 #endif
580
581 #if USE_SETCAPTURE
582   if (GetCapture () != NULL)
583     ReleaseCapture ();
584 #endif
585
586   p_grab_window = NULL;
587 }
588
589 /*
590  *--------------------------------------------------------------
591  * find_window_for_pointer_event
592  *
593  *   Find the window a pointer event (mouse up, down, move) should
594  *   be reported to.  If the return value != reported_window then
595  *   the ref count of reported_window will be decremented and the
596  *   ref count of the return value will be incremented.
597  *
598  * Arguments:
599  *
600  *  "reported_window" is the gdk window the xevent was reported relative to
601  *  "xevent" is the win32 message
602  *
603  * Results:
604  *
605  * Side effects:
606  *
607  *--------------------------------------------------------------
608  */
609
610 static GdkWindow* 
611 find_window_for_pointer_event (GdkWindow*  reported_window,
612                                MSG*        msg)
613 {
614   HWND hwnd;
615   POINTS points;
616   POINT pt;
617   GdkWindow* other_window;
618
619   if (p_grab_window == NULL || !p_grab_owner_events)
620     return reported_window;
621
622   points = MAKEPOINTS (msg->lParam);
623   pt.x = points.x;
624   pt.y = points.y;
625   ClientToScreen (msg->hwnd, &pt);
626
627   GDK_NOTE (EVENTS, g_print ("Finding window for grabbed pointer event at (%ld, %ld)\n",
628                              pt.x, pt.y));
629
630   hwnd = WindowFromPoint (pt);
631   if (hwnd == NULL)
632     return reported_window;
633   other_window = gdk_win32_handle_table_lookup ((GdkNativeWindow) hwnd);
634   if (other_window == NULL)
635     return reported_window;
636
637   GDK_NOTE (EVENTS, g_print ("Found window %p for point (%ld, %ld)\n",
638                              hwnd, pt.x, pt.y));
639
640   gdk_window_unref (reported_window);
641   gdk_window_ref (other_window);
642
643   return other_window;
644 }
645
646 gboolean
647 gdk_display_pointer_is_grabbed (GdkDisplay *display)
648 {
649   g_return_val_if_fail (display == gdk_display_get_default (), FALSE);
650   GDK_NOTE (EVENTS, g_print ("gdk_pointer_is_grabbed: %s\n",
651                              p_grab_window != NULL ? "TRUE" : "FALSE"));
652   return p_grab_window != NULL;
653 }
654
655 gboolean
656 gdk_pointer_grab_info_libgtk_only (GdkDisplay *display,
657                                    GdkWindow **grab_window,
658                                    gboolean   *owner_events)
659 {
660   g_return_val_if_fail (display == gdk_display_get_default (), FALSE);
661
662   if (p_grab_window != NULL)
663     {
664       if (grab_window)
665         *grab_window = p_grab_window;
666       if (owner_events)
667         *owner_events = p_grab_owner_events;
668
669       return TRUE;
670     }
671   else
672     return FALSE;
673 }
674
675 /*
676  *--------------------------------------------------------------
677  * gdk_keyboard_grab
678  *
679  *   Grabs the keyboard to a specific window
680  *
681  * Arguments:
682  *   "window" is the window which will receive the grab
683  *   "owner_events" specifies whether events will be reported as is,
684  *     or relative to "window"
685  *   "time" specifies the time
686  *
687  * Results:
688  *
689  * Side effects:
690  *   requires a corresponding call to gdk_keyboard_ungrab
691  *
692  *--------------------------------------------------------------
693  */
694
695 GdkGrabStatus
696 gdk_keyboard_grab (GdkWindow *window,
697                    gboolean   owner_events,
698                    guint32    time)
699 {
700   gint return_val;
701   
702   g_return_val_if_fail (window != NULL, 0);
703   g_return_val_if_fail (GDK_IS_WINDOW (window), 0);
704   
705   GDK_NOTE (EVENTS, g_print ("gdk_keyboard_grab %p\n",
706                              GDK_WINDOW_HWND (window)));
707
708   if (!GDK_WINDOW_DESTROYED (window))
709     {
710       k_grab_owner_events = owner_events != 0;
711       return_val = GDK_GRAB_SUCCESS;
712     }
713   else
714     return_val = GDK_GRAB_ALREADY_GRABBED;
715
716   if (return_val == GDK_GRAB_SUCCESS)
717     k_grab_window = window;
718   
719   return return_val;
720 }
721
722 void
723 gdk_display_keyboard_ungrab (GdkDisplay *display,
724                              guint32 time)
725 {
726   g_return_if_fail (display == gdk_display_get_default ());
727
728   GDK_NOTE (EVENTS, g_print ("gdk_keyboard_ungrab\n"));
729
730   k_grab_window = NULL;
731 }
732
733 gboolean
734 gdk_keyboard_grab_info_libgtk_only (GdkDisplay *display,
735                                     GdkWindow **grab_window,
736                                     gboolean   *owner_events)
737 {
738   g_return_val_if_fail (display == gdk_display_get_default (), FALSE);
739
740   if (k_grab_window)
741     {
742       if (grab_window)
743         *grab_window = k_grab_window;
744       if (owner_events)
745         *owner_events = k_grab_owner_events;
746
747       return TRUE;
748     }
749   else
750     return FALSE;
751 }
752
753 static GdkFilterReturn
754 gdk_event_apply_filters (MSG      *msg,
755                          GdkEvent *event,
756                          GList    *filters)
757 {
758   GdkEventFilter *filter;
759   GList *tmp_list;
760   GdkFilterReturn result;
761   
762   tmp_list = filters;
763   
764   while (tmp_list)
765     {
766       filter = (GdkEventFilter *) tmp_list->data;
767       
768       result = (*filter->function) (msg, event, filter->data);
769       if (result !=  GDK_FILTER_CONTINUE)
770         return result;
771       
772       tmp_list = tmp_list->next;
773     }
774   
775   return GDK_FILTER_CONTINUE;
776 }
777
778 void 
779 gdk_display_add_client_message_filter (GdkDisplay   *display,
780                                        GdkAtom       message_type,
781                                        GdkFilterFunc func,
782                                        gpointer      data)
783 {
784   /* XXX */
785   gdk_add_client_message_filter (message_type, func, data);
786 }
787
788 void 
789 gdk_add_client_message_filter (GdkAtom       message_type,
790                                GdkFilterFunc func,
791                                gpointer      data)
792 {
793   GdkClientFilter *filter = g_new (GdkClientFilter, 1);
794
795   filter->type = message_type;
796   filter->function = func;
797   filter->data = data;
798   
799   client_filters = g_list_prepend (client_filters, filter);
800 }
801
802 static void
803 build_key_event_state (GdkEvent *event)
804 {
805   if (GetKeyState (VK_SHIFT) < 0)
806     event->key.state |= GDK_SHIFT_MASK;
807   if (GetKeyState (VK_CAPITAL) & 0x1)
808     event->key.state |= GDK_LOCK_MASK;
809   if (!is_altgr_key)
810     {
811       if (GetKeyState (VK_CONTROL) < 0)
812         event->key.state |= GDK_CONTROL_MASK;
813       if (GetKeyState (VK_MENU) < 0)
814         event->key.state |= GDK_MOD1_MASK;
815     }
816   else
817     {
818       event->key.state |= GDK_MOD2_MASK;
819       event->key.group = 1;
820     }
821 }
822
823 static gint
824 build_pointer_event_state (MSG *msg)
825 {
826   gint state;
827   
828   state = 0;
829   if (msg->wParam & MK_CONTROL)
830     state |= GDK_CONTROL_MASK;
831   if (msg->wParam & MK_LBUTTON)
832     state |= GDK_BUTTON1_MASK;
833   if (msg->wParam & MK_MBUTTON)
834     state |= GDK_BUTTON2_MASK;
835   if (msg->wParam & MK_RBUTTON)
836     state |= GDK_BUTTON3_MASK;
837   if (msg->wParam & MK_SHIFT)
838     state |= GDK_SHIFT_MASK;
839   if (GetKeyState (VK_MENU) < 0)
840     state |= GDK_MOD1_MASK;
841   if (GetKeyState (VK_CAPITAL) & 0x1)
842     state |= GDK_LOCK_MASK;
843
844   return state;
845 }
846
847 static guint
848 vk_from_char (guint c)
849 {
850   HKL locale = _gdk_input_locale;
851
852   /* For some control characters (control-C, control-J and control-M),
853    * VkKeyScanEx returns special keycodes (different from the
854    * corresponding uncontrolified character).  Thus, for control
855    * characters, uncontrolify it first and return the virtual-key code
856    * it would have on a Latin-based keyboard, otherwise stuff breaks.
857    */
858   if (latin_locale != NULL && c >= '\000' && c <= '\032')
859     {
860       c += '@';
861       locale = latin_locale;
862     }
863
864   return (VkKeyScanEx (c, locale) & 0xFF);
865 }
866
867 static void
868 build_keypress_event (GdkEvent *event,
869                       MSG      *msg)
870 {
871   HIMC himc;
872   gint i, bytecount, ucount;
873   guchar buf[100];
874   wchar_t wbuf[100];
875
876   event->key.type = GDK_KEY_PRESS;
877   event->key.time = _gdk_win32_get_next_tick (msg->time);
878   event->key.state = 0;
879   event->key.group = 0;         /* ??? */
880   event->key.keyval = GDK_VoidSymbol;
881   
882   if (msg->message == WM_IME_COMPOSITION)
883     {
884       himc = ImmGetContext (msg->hwnd);
885       bytecount = ImmGetCompositionStringW (himc, GCS_RESULTSTR,
886                                             wbuf, sizeof (wbuf));
887       ImmReleaseContext (msg->hwnd, himc);
888
889       ucount = bytecount / 2;
890       event->key.hardware_keycode = wbuf[0]; /* ??? */
891     }
892   else
893     {
894       if (msg->message == WM_CHAR || msg->message == WM_SYSCHAR)
895         {
896           bytecount = MIN ((msg->lParam & 0xFFFF), sizeof (buf));
897           for (i = 0; i < bytecount; i++)
898             buf[i] = msg->wParam;
899           event->key.hardware_keycode = vk_from_char (msg->wParam);
900           if (msg->wParam < ' ')
901             {
902               /* For ASCII control chars, the keyval should be the
903                * corresponding ASCII character.
904                */
905               event->key.keyval = msg->wParam + '@';
906               /* This is needed in case of Alt+nnn or Alt+0nnn (on the numpad)
907                * where nnn<32
908                */
909               event->key.state |= GDK_CONTROL_MASK;
910             }
911         }
912       else /* WM_IME_CHAR */
913         {
914           event->key.hardware_keycode = 0; /* ??? */
915           if (msg->wParam & 0xFF00)
916             {
917               /* Contrary to some versions of the documentation,
918                * the lead byte is the most significant byte.
919                */
920               buf[0] = ((msg->wParam >> 8) & 0xFF);
921               buf[1] = (msg->wParam & 0xFF);
922               bytecount = 2;
923             }
924           else
925             {
926               buf[0] = (msg->wParam & 0xFF);
927               bytecount = 1;
928             }
929         }
930
931       /* Convert from the thread's current code page
932        * to Unicode. (Followed by conversion to UTF-8 below.)
933        */
934       ucount = MultiByteToWideChar (_gdk_input_codepage,
935                                     0, buf, bytecount,
936                                     wbuf, G_N_ELEMENTS (wbuf));
937     }
938
939   build_key_event_state (event);
940
941   /* Build UTF-8 string */
942   if (ucount > 0)
943     {
944       if (ucount == 1 && wbuf[0] < 0200)
945         {
946           event->key.string = g_malloc (2);
947           event->key.string[0] = wbuf[0];
948           event->key.string[1] = '\0';
949           event->key.length = 1;
950         }
951       else
952         {
953           event->key.string = _gdk_ucs2_to_utf8 (wbuf, ucount);
954           event->key.length = strlen (event->key.string);
955         }
956       if (event->key.keyval == GDK_VoidSymbol)
957         event->key.keyval = gdk_unicode_to_keyval (wbuf[0]);
958     }
959 }
960
961 static void
962 build_keyrelease_event (GdkEvent *event,
963                         MSG      *msg)
964 {
965   guchar buf;
966   wchar_t wbuf;
967
968   event->key.type = GDK_KEY_RELEASE;
969   event->key.time = _gdk_win32_get_next_tick (msg->time);
970   event->key.state = 0;
971   event->key.group = 0;         /* ??? */
972
973   if (msg->message == WM_CHAR || msg->message == WM_SYSCHAR)
974     {
975       event->key.hardware_keycode = vk_from_char (msg->wParam);
976       if (msg->wParam < ' ')
977         {
978           event->key.keyval = msg->wParam + '@';
979           event->key.state |= GDK_CONTROL_MASK;
980         }
981       else
982         {
983           buf = msg->wParam;
984           MultiByteToWideChar (_gdk_input_codepage,
985                                0, &buf, 1, &wbuf, 1);
986           
987           event->key.keyval = gdk_unicode_to_keyval (wbuf);
988         }
989     }
990   else
991     {
992       event->key.keyval = GDK_VoidSymbol;
993       event->key.hardware_keycode = 0; /* ??? */
994     }
995   build_key_event_state (event);
996   event->key.string = NULL;
997   event->key.length = 0;
998 }
999
1000 #ifdef G_ENABLE_DEBUG
1001
1002 static void
1003 print_event_state (gint state)
1004 {
1005 #define CASE(bit) if (state & GDK_ ## bit ## _MASK) g_print (#bit " ");
1006   CASE (SHIFT);
1007   CASE (LOCK);
1008   CASE (CONTROL);
1009   CASE (MOD1);
1010   CASE (MOD2);
1011   CASE (MOD3);
1012   CASE (MOD4);
1013   CASE (MOD5);
1014   CASE (BUTTON1);
1015   CASE (BUTTON2);
1016   CASE (BUTTON3);
1017   CASE (BUTTON4);
1018   CASE (BUTTON5);
1019 #undef CASE
1020 }
1021
1022 static void
1023 print_event (GdkEvent *event)
1024 {
1025   gchar *escaped, *kvname;
1026
1027   switch (event->any.type)
1028     {
1029 #define CASE(x) case x: g_print ( #x " "); break;
1030     CASE (GDK_NOTHING);
1031     CASE (GDK_DELETE);
1032     CASE (GDK_DESTROY);
1033     CASE (GDK_EXPOSE);
1034     CASE (GDK_MOTION_NOTIFY);
1035     CASE (GDK_BUTTON_PRESS);
1036     CASE (GDK_2BUTTON_PRESS);
1037     CASE (GDK_3BUTTON_PRESS);
1038     CASE (GDK_BUTTON_RELEASE);
1039     CASE (GDK_KEY_PRESS);
1040     CASE (GDK_KEY_RELEASE);
1041     CASE (GDK_ENTER_NOTIFY);
1042     CASE (GDK_LEAVE_NOTIFY);
1043     CASE (GDK_FOCUS_CHANGE);
1044     CASE (GDK_CONFIGURE);
1045     CASE (GDK_MAP);
1046     CASE (GDK_UNMAP);
1047     CASE (GDK_PROPERTY_NOTIFY);
1048     CASE (GDK_SELECTION_CLEAR);
1049     CASE (GDK_SELECTION_REQUEST);
1050     CASE (GDK_SELECTION_NOTIFY);
1051     CASE (GDK_PROXIMITY_IN);
1052     CASE (GDK_PROXIMITY_OUT);
1053     CASE (GDK_DRAG_ENTER);
1054     CASE (GDK_DRAG_LEAVE);
1055     CASE (GDK_DRAG_MOTION);
1056     CASE (GDK_DRAG_STATUS);
1057     CASE (GDK_DROP_START);
1058     CASE (GDK_DROP_FINISHED);
1059     CASE (GDK_CLIENT_EVENT);
1060     CASE (GDK_VISIBILITY_NOTIFY);
1061     CASE (GDK_NO_EXPOSE);
1062     CASE (GDK_SCROLL);
1063     CASE (GDK_WINDOW_STATE);
1064     CASE (GDK_SETTING);
1065 #undef CASE
1066     }
1067   g_print ("%p ", GDK_WINDOW_HWND (event->any.window));
1068
1069   switch (event->any.type)
1070     {
1071     case GDK_EXPOSE:
1072       g_print ("%s %d",
1073                _gdk_win32_gdkrectangle_to_string (&event->expose.area),
1074                event->expose.count);
1075       break;
1076     case GDK_MOTION_NOTIFY:
1077       g_print ("(%.4g,%.4g) %s",
1078                event->motion.x, event->motion.y,
1079                event->motion.is_hint ? "HINT " : "");
1080       print_event_state (event->motion.state);
1081       break;
1082     case GDK_BUTTON_PRESS:
1083     case GDK_2BUTTON_PRESS:
1084     case GDK_3BUTTON_PRESS:
1085     case GDK_BUTTON_RELEASE:
1086       g_print ("%d (%.4g,%.4g) ",
1087                event->button.button,
1088                event->button.x, event->button.y);
1089       print_event_state (event->button.state);
1090       break;
1091     case GDK_KEY_PRESS: 
1092     case GDK_KEY_RELEASE:
1093       if (event->key.length == 0)
1094         escaped = g_strdup ("");
1095       else
1096         escaped = g_strescape (event->key.string, NULL);
1097       kvname = gdk_keyval_name (event->key.keyval);
1098       g_print ("%#.02x %d %s %d:\"%s\" ",
1099                event->key.hardware_keycode, event->key.group,
1100                (kvname ? kvname : "??"),
1101                event->key.length,
1102                escaped);
1103       g_free (escaped);
1104       print_event_state (event->key.state);
1105       break;
1106     case GDK_ENTER_NOTIFY:
1107     case GDK_LEAVE_NOTIFY:
1108       g_print ("%s ",
1109                (event->crossing.detail == GDK_NOTIFY_INFERIOR ? "INFERIOR" :
1110                 (event->crossing.detail == GDK_NOTIFY_ANCESTOR ? "ANCESTOR" :
1111                  (event->crossing.detail == GDK_NOTIFY_NONLINEAR ? "NONLINEAR" :
1112                   "???"))));
1113       break;
1114     case GDK_CONFIGURE:
1115       g_print ("x:%d y:%d w:%d h:%d",
1116                event->configure.x, event->configure.y,
1117                event->configure.width, event->configure.height);
1118       break;
1119     case GDK_SCROLL:
1120       g_print ("%s ",
1121                (event->scroll.direction == GDK_SCROLL_UP ? "UP" :
1122                 (event->scroll.direction == GDK_SCROLL_DOWN ? "DOWN" :
1123                  (event->scroll.direction == GDK_SCROLL_LEFT ? "LEFT" :
1124                   (event->scroll.direction == GDK_SCROLL_RIGHT ? "RIGHT" :
1125                    "???")))));
1126       print_event_state (event->scroll.state);
1127       break;
1128     case GDK_WINDOW_STATE:
1129       g_print ("%s: %s",
1130                _gdk_win32_window_state_to_string (event->window_state.changed_mask),
1131                _gdk_win32_window_state_to_string (event->window_state.new_window_state));
1132     default:
1133       /* Nothing */
1134       break;
1135     }  
1136   g_print ("\n");
1137 }
1138
1139 #endif
1140
1141 static gboolean
1142 gdk_window_is_child (GdkWindow *parent,
1143                      GdkWindow *window)
1144 {
1145   if (parent == NULL || window == NULL)
1146     return FALSE;
1147
1148   return (gdk_window_get_parent (window) == parent ||
1149           gdk_window_is_child (parent, gdk_window_get_parent (window)));
1150 }
1151
1152 static void
1153 synthesize_enter_or_leave_event (GdkWindow    *window,
1154                                  MSG          *msg,
1155                                  GdkEventType  type,
1156                                  GdkNotifyType detail,
1157                                  gint          x,
1158                                  gint          y)
1159 {
1160   GdkEvent *event;
1161   
1162   event = gdk_event_new (type);
1163   event->crossing.window = window;
1164   event->crossing.send_event = FALSE;
1165   gdk_window_ref (event->crossing.window);
1166   event->crossing.subwindow = NULL;
1167   event->crossing.time = _gdk_win32_get_next_tick (msg->time);
1168   event->crossing.x = x;
1169   event->crossing.y = y;
1170   event->crossing.x_root = msg->pt.x;
1171   event->crossing.y_root = msg->pt.y;
1172   event->crossing.mode = GDK_CROSSING_NORMAL;
1173   event->crossing.detail = detail;
1174   event->crossing.focus = TRUE; /* ??? */
1175   event->crossing.state = 0; /* ??? */
1176   
1177   _gdk_event_queue_append (gdk_drawable_get_display (window), event);
1178   
1179   if (type == GDK_ENTER_NOTIFY
1180       && GDK_WINDOW_OBJECT (window)->extension_events != 0)
1181     _gdk_input_enter_event (&event->crossing, window);
1182
1183   GDK_NOTE (EVENTS, print_event (event));
1184 }
1185
1186 static void
1187 synthesize_leave_event (GdkWindow    *window,
1188                         MSG          *msg,
1189                         GdkNotifyType detail)
1190 {
1191   POINT pt;
1192
1193   if (!(GDK_WINDOW_OBJECT (window)->event_mask & GDK_LEAVE_NOTIFY_MASK))
1194     return;
1195
1196   /* Leave events are at (current_x,current_y) in current_window */
1197
1198   if (current_window != window)
1199     {
1200       pt.x = current_x;
1201       pt.y = current_y;
1202       ClientToScreen (GDK_WINDOW_HWND (current_window), &pt);
1203       ScreenToClient (GDK_WINDOW_HWND (window), &pt);
1204       synthesize_enter_or_leave_event (window, msg, GDK_LEAVE_NOTIFY, detail, pt.x, pt.y);
1205     }
1206   else
1207     synthesize_enter_or_leave_event (window, msg, GDK_LEAVE_NOTIFY, detail, current_x, current_y);
1208
1209 }
1210   
1211 static void
1212 synthesize_enter_event (GdkWindow    *window,
1213                         MSG          *msg,
1214                         GdkNotifyType detail)
1215 {
1216   POINT pt;
1217
1218   if (!(GDK_WINDOW_OBJECT (window)->event_mask & GDK_ENTER_NOTIFY_MASK))
1219     return;
1220
1221   /* Enter events are at LOWORD (msg->lParam), HIWORD
1222    * (msg->lParam) in msg->hwnd */
1223
1224   pt.x = LOWORD (msg->lParam);
1225   pt.y = HIWORD (msg->lParam);
1226   if (msg->hwnd != GDK_WINDOW_HWND (window))
1227     {
1228       ClientToScreen (msg->hwnd, &pt);
1229       ScreenToClient (GDK_WINDOW_HWND (window), &pt);
1230     }
1231   synthesize_enter_or_leave_event (window, msg, GDK_ENTER_NOTIFY, detail, pt.x, pt.y);
1232 }
1233   
1234 static void
1235 synthesize_enter_events (GdkWindow    *from,
1236                          GdkWindow    *to,
1237                          MSG          *msg,
1238                          GdkNotifyType detail)
1239 {
1240   GdkWindow *prev = gdk_window_get_parent (to);
1241   
1242   if (prev != from)
1243     synthesize_enter_events (from, prev, msg, detail);
1244   synthesize_enter_event (to, msg, detail);
1245 }
1246                          
1247 static void
1248 synthesize_leave_events (GdkWindow    *from,
1249                          GdkWindow    *to,
1250                          MSG          *msg,
1251                          GdkNotifyType detail)
1252 {
1253   GdkWindow *next = gdk_window_get_parent (from);
1254   
1255   synthesize_leave_event (from, msg, detail);
1256   if (next != to)
1257     synthesize_leave_events (next, to, msg, detail);
1258 }
1259                          
1260 static void
1261 synthesize_crossing_events (GdkWindow *window,
1262                             MSG       *msg)
1263 {
1264   GdkWindow *intermediate, *tem, *common_ancestor;
1265
1266   if (gdk_window_is_child (current_window, window))
1267     {
1268       /* Pointer has moved to an inferior window. */
1269       synthesize_leave_event (current_window, msg, GDK_NOTIFY_INFERIOR);
1270       
1271       /* If there are intermediate windows, generate ENTER_NOTIFY
1272        * events for them
1273        */
1274       intermediate = gdk_window_get_parent (window);
1275       if (intermediate != current_window)
1276         {
1277           synthesize_enter_events (current_window, intermediate, msg, GDK_NOTIFY_VIRTUAL);
1278         }
1279       
1280       synthesize_enter_event (window, msg, GDK_NOTIFY_ANCESTOR);
1281     }
1282   else if (gdk_window_is_child (window, current_window))
1283     {
1284       /* Pointer has moved to an ancestor window. */
1285       synthesize_leave_event (current_window, msg, GDK_NOTIFY_ANCESTOR);
1286       
1287       /* If there are intermediate windows, generate LEAVE_NOTIFY
1288        * events for them
1289        */
1290       intermediate = gdk_window_get_parent (current_window);
1291       if (intermediate != window)
1292         {
1293           synthesize_leave_events (intermediate, window, msg, GDK_NOTIFY_VIRTUAL);
1294         }
1295     }
1296   else if (current_window)
1297     {
1298       /* Find least common ancestor of current_window and window */
1299       tem = current_window;
1300       do {
1301         common_ancestor = gdk_window_get_parent (tem);
1302         tem = common_ancestor;
1303       } while (common_ancestor &&
1304                !gdk_window_is_child (common_ancestor, window));
1305       if (common_ancestor)
1306         {
1307           synthesize_leave_event (current_window, msg, GDK_NOTIFY_NONLINEAR);
1308           intermediate = gdk_window_get_parent (current_window);
1309           if (intermediate != common_ancestor)
1310             {
1311               synthesize_leave_events (intermediate, common_ancestor,
1312                                        msg, GDK_NOTIFY_NONLINEAR_VIRTUAL);
1313             }
1314           intermediate = gdk_window_get_parent (window);
1315           if (intermediate != common_ancestor)
1316             {
1317               synthesize_enter_events (common_ancestor, intermediate,
1318                                        msg, GDK_NOTIFY_NONLINEAR_VIRTUAL);
1319             }
1320           synthesize_enter_event (window, msg, GDK_NOTIFY_NONLINEAR);
1321         }
1322     }
1323   else
1324     {
1325       /* Dunno where we are coming from */
1326       synthesize_enter_event (window, msg, GDK_NOTIFY_UNKNOWN);
1327     }
1328
1329   if (current_window)
1330     gdk_window_unref (current_window);
1331   current_window = window;
1332   if (current_window)
1333     gdk_window_ref (current_window);
1334 }
1335
1336 #if 0
1337
1338 static GList *
1339 get_descendants (GdkWindow *window)
1340 {
1341   GList *list = gdk_window_get_children (window);
1342   GList *head = list;
1343   GList *tmp = NULL;
1344
1345   while (list)
1346     {
1347       tmp = g_list_concat (tmp, get_descendants ((GdkWindow *) list->data));
1348       list = list->next;
1349     }
1350
1351   return g_list_concat (tmp, head);
1352 }
1353
1354 #endif
1355
1356 static void
1357 synthesize_expose_events (GdkWindow *window)
1358 {
1359   RECT r;
1360   HDC hdc;
1361   GdkDrawableImplWin32 *impl = GDK_DRAWABLE_IMPL_WIN32 (GDK_WINDOW_OBJECT (window)->impl);
1362   GList *list = gdk_window_get_children (window);
1363   GList *head = list;
1364   GdkEvent *event;
1365   int k;
1366   
1367   while (list)
1368     {
1369       synthesize_expose_events ((GdkWindow *) list->data);
1370       list = list->next;
1371     }
1372
1373   g_list_free (head);
1374
1375   if (((GdkWindowObject *) window)->input_only)
1376     ;
1377   else if (!(hdc = GetDC (impl->handle)))
1378     WIN32_GDI_FAILED ("GetDC");
1379   else
1380     {
1381       if ((k = GetClipBox (hdc, &r)) == ERROR)
1382         WIN32_GDI_FAILED ("GetClipBox");
1383       else if (k != NULLREGION)
1384         {
1385           event = gdk_event_new (GDK_EXPOSE);
1386           event->expose.window = window;
1387           gdk_window_ref (window);
1388           event->expose.area.x = r.left;
1389           event->expose.area.y = r.top;
1390           event->expose.area.width = r.right - r.left;
1391           event->expose.area.height = r.bottom - r.top;
1392           event->expose.region = gdk_region_rectangle (&(event->expose.area));
1393           event->expose.count = 0;
1394   
1395           _gdk_event_queue_append (gdk_drawable_get_display (window), event);
1396   
1397           GDK_NOTE (EVENTS_OR_COLORMAP, print_event (event));
1398         }
1399       if (!ReleaseDC (impl->handle, hdc))
1400         WIN32_GDI_FAILED ("ReleaseDC");
1401     }
1402 }
1403
1404 static void
1405 update_colors (GdkWindow *window,
1406                gboolean   top)
1407 {
1408   HDC hdc;
1409   GdkDrawableImplWin32 *impl = GDK_DRAWABLE_IMPL_WIN32 (GDK_WINDOW_OBJECT (window)->impl);
1410   GList *list = gdk_window_get_children (window);
1411   GList *head = list;
1412
1413   GDK_NOTE (COLORMAP, (top ? g_print ("update_colors:") : (void) 0));
1414
1415   while (list)
1416     {
1417       update_colors ((GdkWindow *) list->data, FALSE);
1418       list = list->next;
1419     }
1420   g_list_free (head);
1421
1422   if (((GdkWindowObject *) window)->input_only ||
1423       impl->colormap == NULL)
1424     return;
1425
1426   if (!(hdc = GetDC (impl->handle)))
1427     WIN32_GDI_FAILED ("GetDC");
1428   else
1429     {
1430       GdkColormapPrivateWin32 *cmapp = GDK_WIN32_COLORMAP_DATA (impl->colormap);
1431       HPALETTE holdpal;
1432       gint k;
1433       
1434       if ((holdpal = SelectPalette (hdc, cmapp->hpal, TRUE)) == NULL)
1435         WIN32_GDI_FAILED ("SelectPalette");
1436       else if ((k = RealizePalette (hdc)) == GDI_ERROR)
1437         WIN32_GDI_FAILED ("RealizePalette");
1438       else
1439         {
1440           GDK_NOTE (COLORMAP,
1441                     (k > 0 ?
1442                      g_print (" %p pal=%p: realized %d colors\n"
1443                               "update_colors:",
1444                               impl->handle, cmapp->hpal, k) :
1445                      (void) 0,
1446                      g_print (" %p", impl->handle)));
1447           if (!UpdateColors (hdc))
1448             WIN32_GDI_FAILED ("UpdateColors");
1449           SelectPalette (hdc, holdpal, TRUE);
1450           RealizePalette (hdc);
1451         }
1452       if (!ReleaseDC (impl->handle, hdc))
1453         WIN32_GDI_FAILED ("ReleaseDC");
1454     }
1455   GDK_NOTE (COLORMAP, (top ? g_print ("\n") : (void) 0));
1456 }
1457
1458 static void
1459 translate_mouse_coords (GdkWindow *window1,
1460                         GdkWindow *window2,
1461                         MSG       *msg)
1462 {
1463   POINT pt;
1464
1465   pt.x = LOWORD (msg->lParam);
1466   pt.y = HIWORD (msg->lParam);
1467   ClientToScreen (GDK_WINDOW_HWND (window1), &pt);
1468   ScreenToClient (GDK_WINDOW_HWND (window2), &pt);
1469   msg->lParam = MAKELPARAM (pt.x, pt.y);
1470   GDK_NOTE (EVENTS, g_print ("...new coords are (%ld,%ld)\n", pt.x, pt.y));
1471 }
1472
1473 static gboolean
1474 propagate (GdkWindow  **window,
1475            MSG         *msg,
1476            GdkWindow   *grab_window,
1477            gboolean     grab_owner_events,
1478            gint         grab_mask,
1479            gboolean   (*doesnt_want_it) (gint mask,
1480                                          MSG *msg))
1481 {
1482   gboolean in_propagation = FALSE;
1483
1484   if (grab_window != NULL && !grab_owner_events)
1485     {
1486       /* Event source is grabbed with owner_events FALSE */
1487       GDK_NOTE (EVENTS, g_print ("...grabbed, owner_events FALSE, "));
1488       if ((*doesnt_want_it) (grab_mask, msg))
1489         {
1490           GDK_NOTE (EVENTS, g_print ("...grabber doesn't want it\n"));
1491           return FALSE;
1492         }
1493       else
1494         {
1495           GDK_NOTE (EVENTS, g_print ("...sending to grabber %p\n",
1496                                      GDK_WINDOW_HWND (grab_window)));
1497           gdk_drawable_unref (*window);
1498           *window = grab_window;
1499           gdk_drawable_ref (*window);
1500           return TRUE;
1501         }
1502     }
1503   while (TRUE)
1504     {
1505      if ((*doesnt_want_it) (GDK_WINDOW_OBJECT (*window)->event_mask, msg))
1506         {
1507           /* Owner doesn't want it, propagate to parent. */
1508           if (GDK_WINDOW (GDK_WINDOW_OBJECT (*window)->parent) == _gdk_parent_root)
1509             {
1510               /* No parent; check if grabbed */
1511               if (grab_window != NULL)
1512                 {
1513                   /* Event source is grabbed with owner_events TRUE */
1514                   GDK_NOTE (EVENTS, g_print ("...undelivered, but grabbed\n"));
1515                   if ((*doesnt_want_it) (grab_mask, msg))
1516                     {
1517                       /* Grabber doesn't want it either */
1518                       GDK_NOTE (EVENTS, g_print ("...grabber doesn't want it\n"));
1519                       return FALSE;
1520                     }
1521                   else
1522                     {
1523                       /* Grabbed! */
1524                       GDK_NOTE (EVENTS,
1525                                 g_print ("...sending to grabber %p\n",
1526                                          GDK_WINDOW_HWND (grab_window)));
1527                       gdk_drawable_unref (*window);
1528                       *window = grab_window;
1529                       gdk_drawable_ref (*window);
1530                       return TRUE;
1531                     }
1532                 }
1533               else
1534                 {
1535                   GDK_NOTE (EVENTS, g_print ("...undelivered\n"));
1536                   return FALSE;
1537                 }
1538             }
1539           else if (GDK_WINDOW_OBJECT (*window)->parent == NULL)
1540             {
1541               GDK_NOTE (EVENTS, g_print ("...parent NULL (?), undelivered\n"));
1542               return FALSE;
1543             }
1544           else
1545             {
1546               gdk_drawable_unref (*window);
1547               *window = GDK_WINDOW (GDK_WINDOW_OBJECT (*window)->parent);
1548               gdk_drawable_ref (*window);
1549               GDK_NOTE (EVENTS, g_print ("%s %p",
1550                                          (in_propagation ? "," : " ...propagating to"),
1551                                          GDK_WINDOW_HWND (*window)));
1552               /* The only branch where we actually continue the loop */
1553               in_propagation = TRUE;
1554             }
1555         }
1556       else
1557         return TRUE;
1558     }
1559 }
1560
1561 static gboolean
1562 doesnt_want_key (gint mask,
1563                  MSG *msg)
1564 {
1565   return (((msg->message == WM_KEYUP || msg->message == WM_SYSKEYUP)
1566            && !(mask & GDK_KEY_RELEASE_MASK))
1567           ||
1568           ((msg->message == WM_KEYDOWN || msg->message == WM_SYSKEYDOWN)
1569            && !(mask & GDK_KEY_PRESS_MASK)));
1570 }
1571
1572 static gboolean
1573 doesnt_want_char (gint mask,
1574                   MSG *msg)
1575 {
1576   return !(mask & (GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK));
1577 }
1578
1579 static gboolean
1580 doesnt_want_button_press (gint mask,
1581                           MSG *msg)
1582 {
1583   return !(mask & GDK_BUTTON_PRESS_MASK);
1584 }
1585
1586 static gboolean
1587 doesnt_want_button_release (gint mask,
1588                             MSG *msg)
1589 {
1590   return !(mask & GDK_BUTTON_RELEASE_MASK);
1591 }
1592
1593 static gboolean
1594 doesnt_want_button_motion (gint mask,
1595                            MSG *msg)
1596 {
1597   return !((mask & GDK_POINTER_MOTION_MASK)
1598            || ((msg->wParam & (MK_LBUTTON|MK_MBUTTON|MK_RBUTTON))
1599                && (mask & GDK_BUTTON_MOTION_MASK))
1600            || ((msg->wParam & MK_LBUTTON)
1601                && (mask & GDK_BUTTON1_MOTION_MASK))
1602            || ((msg->wParam & MK_MBUTTON)
1603                && (mask & GDK_BUTTON2_MOTION_MASK))
1604            || ((msg->wParam & MK_RBUTTON)
1605                && (mask & GDK_BUTTON3_MOTION_MASK)));
1606 }
1607
1608 static gboolean
1609 doesnt_want_scroll (gint mask,
1610                     MSG *msg)
1611 {
1612 #if 0
1613   return !(mask & GDK_SCROLL_MASK);
1614 #else
1615   return !(mask & GDK_BUTTON_PRESS_MASK);
1616 #endif
1617 }
1618
1619 static char *
1620 decode_key_lparam (LPARAM lParam)
1621 {
1622   static char buf[100];
1623   char *p = buf;
1624
1625   if (HIWORD (lParam) & KF_UP)
1626     p += g_sprintf (p, "KF_UP ");
1627   if (HIWORD (lParam) & KF_REPEAT)
1628     p += g_sprintf (p, "KF_REPEAT ");
1629   if (HIWORD (lParam) & KF_ALTDOWN)
1630     p += g_sprintf (p, "KF_ALTDOWN ");
1631   if (HIWORD (lParam) & KF_EXTENDED)
1632     p += g_sprintf (p, "KF_EXTENDED ");
1633   p += g_sprintf (p, "sc:%d rep:%d", LOBYTE (HIWORD (lParam)), LOWORD (lParam));
1634
1635   return buf;
1636 }
1637
1638 static void
1639 erase_background (GdkWindow *window,
1640                   HDC        hdc)
1641 {
1642   HDC bgdc = NULL;
1643   HBRUSH hbr = NULL;
1644   HPALETTE holdpal = NULL;
1645   RECT rect;
1646   COLORREF bg;
1647   GdkColormap *colormap;
1648   GdkColormapPrivateWin32 *colormap_private;
1649   int x, y;
1650   int x_offset, y_offset;
1651   
1652   if (((GdkWindowObject *) window)->input_only ||
1653       ((GdkWindowObject *) window)->bg_pixmap == GDK_NO_BG ||
1654       GDK_WINDOW_IMPL_WIN32 (((GdkWindowObject *) window)->impl)->position_info.no_bg)
1655     {
1656       GDK_NOTE (EVENTS, g_print (((GdkWindowObject *) window)->input_only ? "...input_only\n" :
1657                                  ((GdkWindowObject *) window)->bg_pixmap == GDK_NO_BG ? "GDK_NO_BG" :
1658                                  GDK_WINDOW_IMPL_WIN32 (((GdkWindowObject *) window)->impl)->position_info.no_bg ? "no_bg\n" : "???\n"));
1659       return;
1660     }
1661
1662   colormap = gdk_drawable_get_colormap (window);
1663
1664   if (colormap &&
1665       (colormap->visual->type == GDK_VISUAL_PSEUDO_COLOR ||
1666        colormap->visual->type == GDK_VISUAL_STATIC_COLOR))
1667     {
1668       int k;
1669           
1670       colormap_private = GDK_WIN32_COLORMAP_DATA (colormap);
1671
1672       if (!(holdpal = SelectPalette (hdc,  colormap_private->hpal, FALSE)))
1673         WIN32_GDI_FAILED ("SelectPalette");
1674       else if ((k = RealizePalette (hdc)) == GDI_ERROR)
1675         WIN32_GDI_FAILED ("RealizePalette");
1676       else if (k > 0)
1677         GDK_NOTE (COLORMAP, g_print ("erase_background: realized %p: %d colors\n",
1678                                      colormap_private->hpal, k));
1679     }
1680   
1681   x_offset = y_offset = 0;
1682   while (window && ((GdkWindowObject *) window)->bg_pixmap == GDK_PARENT_RELATIVE_BG)
1683     {
1684       /* If this window should have the same background as the parent,
1685        * fetch the parent. (And if the same goes for the parent, fetch
1686        * the grandparent, etc.)
1687        */
1688       x_offset += ((GdkWindowObject *) window)->x;
1689       y_offset += ((GdkWindowObject *) window)->y;
1690       window = GDK_WINDOW (((GdkWindowObject *) window)->parent);
1691     }
1692   
1693   if (GDK_WINDOW_IMPL_WIN32 (((GdkWindowObject *) window)->impl)->position_info.no_bg)
1694     {
1695       GDK_NOTE (EVENTS, g_print ("no_bg on ancestor (?)\n"));
1696       /* Improves scolling effect, e.g. main buttons of testgtk */
1697       return;
1698     }
1699
1700   GetClipBox (hdc, &rect);
1701
1702   GDK_NOTE (EVENTS, (hbr = GetStockObject (BLACK_BRUSH),
1703                      FillRect (hdc, &rect, hbr),
1704                      GdiFlush (),
1705                      Sleep (200)));
1706
1707   if (((GdkWindowObject *) window)->bg_pixmap == NULL)
1708     {
1709       bg = _gdk_win32_colormap_color (GDK_DRAWABLE_IMPL_WIN32 (((GdkWindowObject *) window)->impl)->colormap,
1710                                       ((GdkWindowObject *) window)->bg_color.pixel);
1711       
1712       GDK_NOTE (EVENTS, g_print ("...%s bg %06lx\n",
1713                                  _gdk_win32_rect_to_string (&rect),
1714                                  (gulong) bg));
1715       if (!(hbr = CreateSolidBrush (bg)))
1716         WIN32_GDI_FAILED ("CreateSolidBrush");
1717       else if (!FillRect (hdc, &rect, hbr))
1718         WIN32_GDI_FAILED ("FillRect");
1719       if (hbr != NULL)
1720         DeleteObject (hbr);
1721     }
1722   else if (((GdkWindowObject *) window)->bg_pixmap != GDK_NO_BG)
1723     {
1724       GdkPixmap *pixmap = ((GdkWindowObject *) window)->bg_pixmap;
1725       GdkPixmapImplWin32 *pixmap_impl = GDK_PIXMAP_IMPL_WIN32 (GDK_PIXMAP_OBJECT (pixmap)->impl);
1726       
1727       if (x_offset == 0 && y_offset == 0 &&
1728           pixmap_impl->width <= 8 && pixmap_impl->height <= 8)
1729         {
1730           GDK_NOTE (EVENTS, g_print ("...small pixmap, using brush\n"));
1731           if (!(hbr = CreatePatternBrush (GDK_PIXMAP_HBITMAP (pixmap))))
1732             WIN32_GDI_FAILED ("CreatePatternBrush");
1733           else if (!FillRect (hdc, &rect, hbr))
1734             WIN32_GDI_FAILED ("FillRect");
1735           if (hbr != NULL)
1736             DeleteObject (hbr);
1737         }
1738       else
1739         {
1740           HGDIOBJ oldbitmap;
1741
1742           GDK_NOTE (EVENTS,
1743                     g_print ("...blitting pixmap %p (%dx%d) "
1744                              " clip box = %s\n",
1745                              GDK_PIXMAP_HBITMAP (pixmap),
1746                              pixmap_impl->width, pixmap_impl->height,
1747                              _gdk_win32_rect_to_string (&rect)));
1748           
1749           if (!(bgdc = CreateCompatibleDC (hdc)))
1750             {
1751               WIN32_GDI_FAILED ("CreateCompatibleDC");
1752               return;
1753             }
1754           if (!(oldbitmap = SelectObject (bgdc, GDK_PIXMAP_HBITMAP (pixmap))))
1755             {
1756               WIN32_GDI_FAILED ("SelectObject");
1757               DeleteDC (bgdc);
1758               return;
1759             }
1760           x = -x_offset;
1761           while (x < rect.right)
1762             {
1763               if (x + pixmap_impl->width >= rect.left)
1764                 {
1765                   y = -y_offset;
1766                   while (y < rect.bottom)
1767                     {
1768                       if (y + pixmap_impl->height >= rect.top)
1769                         {
1770                           if (!BitBlt (hdc, x, y,
1771                                        pixmap_impl->width, pixmap_impl->height,
1772                                        bgdc, 0, 0, SRCCOPY))
1773                             {
1774                               WIN32_GDI_FAILED ("BitBlt");
1775                               SelectObject (bgdc, oldbitmap);
1776                               DeleteDC (bgdc);
1777                               return;
1778                             }
1779                         }
1780                       y += pixmap_impl->height;
1781                     }
1782                 }
1783               x += pixmap_impl->width;
1784             }
1785           SelectObject (bgdc, oldbitmap);
1786           DeleteDC (bgdc);
1787         }
1788     }
1789 }
1790
1791 static GdkRegion *
1792 _gdk_win32_hrgn_to_region (HRGN hrgn)
1793 {
1794   RGNDATA *rgndata;
1795   RECT *rects;
1796   GdkRegion *result;
1797   gint nbytes;
1798   gint i;
1799
1800   if ((nbytes = GetRegionData (hrgn, 0, NULL)) == 0)
1801     {
1802       WIN32_GDI_FAILED ("GetRegionData");
1803       return NULL;
1804     }
1805
1806   rgndata = (RGNDATA *) g_malloc (nbytes);
1807
1808   if (GetRegionData (hrgn, nbytes, rgndata) == 0)
1809     {
1810       WIN32_GDI_FAILED ("GetRegionData");
1811       g_free (rgndata);
1812       return NULL;
1813     }
1814
1815   result = gdk_region_new ();
1816   rects = (RECT *) rgndata->Buffer;
1817   for (i = 0; i < rgndata->rdh.nCount; i++)
1818     {
1819       GdkRectangle r;
1820
1821       r.x = rects[i].left;
1822       r.y = rects[i].top;
1823       r.width = rects[i].right - r.x;
1824       r.height = rects[i].bottom - r.y;
1825
1826       gdk_region_union_with_rect (result, &r);
1827     }
1828
1829   g_free (rgndata);
1830
1831   return result;
1832 }
1833
1834 static gboolean
1835 gdk_event_translate (GdkDisplay *display,
1836                      GdkEvent *event,
1837                      MSG      *msg,
1838                      gboolean *ret_val_flagp,
1839                      gint     *ret_valp,
1840                      gboolean  return_exposes)
1841 {
1842   DWORD pidActWin;
1843   DWORD pidThis;
1844   PAINTSTRUCT paintstruct;
1845   HDC hdc;
1846   RECT rect;
1847   POINT pt;
1848   MINMAXINFO *mmi;
1849   HWND hwnd;
1850   HCURSOR hcursor;
1851   HRGN hrgn;
1852   CHARSETINFO charset_info;
1853
1854   /* Invariant:
1855    * private == GDK_WINDOW_OBJECT (window)
1856    */
1857   GdkWindow *window;
1858   GdkWindowObject *private;
1859
1860 #define ASSIGN_WINDOW(rhs)                                                 \
1861   (window = rhs,                                                           \
1862    private = (GdkWindowObject *) window)
1863
1864   GdkWindowImplWin32 *impl;
1865
1866   GdkWindow *orig_window, *new_window;
1867   gint xoffset, yoffset;
1868
1869   static gint update_colors_counter = 0;
1870   gint button;
1871
1872   gchar buf[256];
1873   gboolean return_val = FALSE;
1874   
1875   if (ret_val_flagp)
1876     *ret_val_flagp = FALSE;
1877
1878   ASSIGN_WINDOW (gdk_win32_handle_table_lookup ((GdkNativeWindow) msg->hwnd));
1879   orig_window = window;
1880   
1881   event->any.window = window;
1882
1883   /* InSendMessage() does not really mean the same as X11's send_event flag,
1884    * but it is close enough, says jpe@archaeopteryx.com.
1885    */
1886   event->any.send_event = InSendMessage (); 
1887
1888   if (window == NULL)
1889     {
1890       /* Handle WM_QUIT here ? */
1891       if (msg->message == WM_QUIT)
1892         {
1893           GDK_NOTE (EVENTS, g_print ("WM_QUIT: %d\n", msg->wParam));
1894           exit (msg->wParam);
1895         }
1896       else if (msg->message == WM_MOVE
1897                || msg->message == WM_SIZE)
1898         {
1899           /* It's quite normal to get these messages before we have
1900            * had time to register the window in our lookup table, or
1901            * when the window is being destroyed and we already have
1902            * removed it. Repost the same message to our queue so that
1903            * we will get it later when we are prepared.
1904            */
1905           GDK_NOTE (MISC, g_print ("gdk_event_translate: %p %s posted.\n",
1906                                    msg->hwnd, 
1907                                    msg->message == WM_MOVE ?
1908                                    "WM_MOVE" : "WM_SIZE"));
1909         
1910           PostMessage (msg->hwnd, msg->message,
1911                        msg->wParam, msg->lParam);
1912         }
1913 #ifndef WITHOUT_WM_CREATE
1914       else if (WM_CREATE == msg->message)
1915         {
1916           window = (UNALIGNED GdkWindow*) (((LPCREATESTRUCT) msg->lParam)->lpCreateParams);
1917           GDK_WINDOW_HWND (window) = msg->hwnd;
1918           GDK_NOTE (EVENTS, g_print ("gdk_event_translate: created %p\n",
1919                                      msg->hwnd));
1920 # if 0
1921           /* This should handle allmost all the other window==NULL cases.
1922            * This code is executed while gdk_window_new is in it's 
1923            * CreateWindowEx call.
1924            * Don't insert xid there a second time, if it's done here. 
1925            */
1926           gdk_drawable_ref (window);
1927           gdk_win32_handle_table_insert (&GDK_WINDOW_HWND (window), window);
1928 # endif
1929         }
1930       else
1931       {
1932         GDK_NOTE (EVENTS, g_print ("gdk_event_translate: %s for %p (NULL)\n",
1933                                    _gdk_win32_message_to_string (msg->message),
1934                                    msg->hwnd));
1935       }
1936 #endif
1937       return FALSE;
1938     }
1939   
1940   gdk_drawable_ref (window);
1941
1942   if (!GDK_WINDOW_DESTROYED (window))
1943     {
1944       /* Check for filters for this window */
1945       GdkFilterReturn result;
1946
1947       result = gdk_event_apply_filters
1948         (msg, event, GDK_WINDOW_OBJECT (window)->filters);
1949       
1950       if (result != GDK_FILTER_CONTINUE)
1951         {
1952           return_val =  (result == GDK_FILTER_TRANSLATE) ? TRUE : FALSE;
1953           if (ret_val_flagp)
1954             *ret_val_flagp = TRUE;
1955           if (ret_valp)
1956             *ret_valp = return_val;
1957           goto done;
1958         }
1959     }
1960
1961   if (msg->message == msh_mousewheel_msg)
1962     {
1963       GDK_NOTE (EVENTS, g_print ("MSH_MOUSEWHEEL: %p %d\n",
1964                                  msg->hwnd, msg->wParam));
1965       
1966       event->scroll.type = GDK_SCROLL;
1967
1968       /* MSG_MOUSEWHEEL is delivered to the foreground window.  Work
1969        * around that. Also, the position is in screen coordinates, not
1970        * client coordinates as with the button messages.
1971        */
1972       pt.x = LOWORD (msg->lParam);
1973       pt.y = HIWORD (msg->lParam);
1974       if ((hwnd = WindowFromPoint (pt)) == NULL)
1975         goto done;
1976
1977       msg->hwnd = hwnd;
1978       if ((new_window = gdk_win32_handle_table_lookup ((GdkNativeWindow) msg->hwnd)) == NULL)
1979         goto done;
1980
1981       if (new_window != window)
1982         {
1983           gdk_drawable_unref (window);
1984           ASSIGN_WINDOW (new_window);
1985           gdk_drawable_ref (window);
1986         }
1987
1988       if (GDK_WINDOW_OBJECT (window)->extension_events != 0
1989           && _gdk_input_ignore_core)
1990         {
1991           GDK_NOTE (EVENTS, g_print ("...ignored\n"));
1992           goto done;
1993         }
1994
1995       if (!propagate (&window, msg,
1996                       p_grab_window, p_grab_owner_events, p_grab_mask,
1997                       doesnt_want_scroll))
1998         goto done;
1999
2000       ASSIGN_WINDOW (window);
2001
2002       ScreenToClient (msg->hwnd, &pt);
2003       event->button.window = window;
2004       event->scroll.direction = ((int) msg->wParam > 0) ?
2005         GDK_SCROLL_UP : GDK_SCROLL_DOWN;
2006       event->scroll.window = window;
2007       event->scroll.time = _gdk_win32_get_next_tick (msg->time);
2008       _gdk_windowing_window_get_offsets (window, &xoffset, &yoffset);
2009       event->scroll.x = (gint16) pt.x + xoffset;
2010       event->scroll.y = (gint16) pt.y + yoffset;
2011       event->scroll.x_root = (gint16) LOWORD (msg->lParam);
2012       event->scroll.y_root = (gint16) HIWORD (msg->lParam);
2013       event->scroll.state = 0;  /* No state information with MSH_MOUSEWHEEL */
2014       event->scroll.device = display->core_pointer;
2015       return_val = !GDK_WINDOW_DESTROYED (window);
2016
2017       goto done;
2018     }
2019   else
2020     {
2021       GList *tmp_list;
2022       GdkFilterReturn result = GDK_FILTER_CONTINUE;
2023
2024       tmp_list = client_filters;
2025       while (tmp_list)
2026         {
2027           GdkClientFilter *filter = tmp_list->data;
2028           /* FIXME: under win32 messages are not really atoms
2029            * as the following cast suggest, but the appears to be right
2030            * Haven't found a use case though ...
2031            */
2032           if (filter->type == GDK_POINTER_TO_ATOM (msg->message))
2033             {
2034               GDK_NOTE (EVENTS, g_print ("client filter matched\n"));
2035               event->any.window = window;
2036               result = (*filter->function) (msg, event, filter->data);
2037               switch (result)
2038                 {
2039                 case GDK_FILTER_REMOVE:
2040                   *ret_val_flagp = TRUE;
2041                   *ret_valp = 0;
2042                   return_val = FALSE;
2043                   break;
2044
2045                 case GDK_FILTER_TRANSLATE:
2046                   return_val = TRUE;
2047                   break;
2048
2049                 case GDK_FILTER_CONTINUE:
2050                   *ret_val_flagp = TRUE;
2051                   *ret_valp = 1;
2052                   return_val = TRUE;
2053                   event->client.type = GDK_CLIENT_EVENT;
2054                   event->client.window = window;
2055                   /* FIXME: check if the cast is correct, see above */
2056                   event->client.message_type = GDK_POINTER_TO_ATOM (msg->message);
2057                   event->client.data_format = 0;
2058                   event->client.data.l[0] = msg->wParam;
2059                   event->client.data.l[1] = msg->lParam;
2060                   break;
2061                 }
2062               goto done;
2063             }
2064           tmp_list = tmp_list->next;
2065         }
2066     }
2067
2068   switch (msg->message)
2069     {
2070     case WM_INPUTLANGCHANGE:
2071       _gdk_input_locale = (HKL) msg->lParam;
2072       TranslateCharsetInfo ((DWORD FAR *) msg->wParam,
2073                             &charset_info,
2074                             TCI_SRCCHARSET);
2075       _gdk_input_codepage = charset_info.ciACP;
2076       _gdk_keymap_serial++;
2077       GDK_NOTE (EVENTS,
2078                 g_print ("WM_INPUTLANGCHANGE: %p  charset %lu locale %lx cp%d\n",
2079                          msg->hwnd, (gulong) msg->wParam, msg->lParam,
2080                          _gdk_input_codepage));
2081       break;
2082
2083     case WM_SYSKEYUP:
2084     case WM_SYSKEYDOWN:
2085       GDK_NOTE (EVENTS,
2086                 g_print ("WM_SYSKEY%s: %p  %s ch:%.02x %s\n",
2087                          (msg->message == WM_SYSKEYUP ? "UP" : "DOWN"),
2088                          msg->hwnd,
2089                          (GetKeyNameText (msg->lParam, buf,
2090                                           sizeof (buf)) > 0 ?
2091                           buf : ""),
2092                          msg->wParam,
2093                          decode_key_lparam (msg->lParam)));
2094
2095       /* If posted without us having keyboard focus, ignore */
2096       if (msg->wParam != VK_F10 && !(HIWORD (msg->lParam) & KF_ALTDOWN))
2097         break;
2098
2099       /* Let the system handle Alt-Tab, Alt-Enter and Alt-F4 */
2100       if (msg->wParam == VK_TAB
2101           || msg->wParam == VK_RETURN
2102           || msg->wParam == VK_F4)
2103         break;
2104
2105       /* Let the system handle Alt-Space, and ignore the WM_SYSCHAR too */
2106       if (msg->wParam == VK_SPACE)
2107         {
2108           ignore_wm_char = TRUE;
2109           break;
2110         }
2111
2112       /* Jump to code in common with WM_KEYUP and WM_KEYDOWN */
2113       goto keyup_or_down;
2114
2115     case WM_KEYUP:
2116     case WM_KEYDOWN:
2117       GDK_NOTE (EVENTS, 
2118                 g_print ("WM_KEY%s: %p  %s ch:%.02x %s\n",
2119                          (msg->message == WM_KEYUP ? "UP" : "DOWN"),
2120                          msg->hwnd,
2121                          (GetKeyNameText (msg->lParam, buf,
2122                                           sizeof (buf)) > 0 ?
2123                           buf : ""),
2124                          msg->wParam,
2125                          decode_key_lparam (msg->lParam)));
2126
2127     keyup_or_down:
2128
2129       ignore_wm_char = TRUE;
2130
2131       event->key.window = window;
2132
2133       switch (msg->wParam)
2134         {
2135         case VK_LBUTTON:
2136           event->key.keyval = GDK_Pointer_Button1; break;
2137         case VK_RBUTTON:
2138           event->key.keyval = GDK_Pointer_Button3; break;
2139         case VK_MBUTTON:
2140           event->key.keyval = GDK_Pointer_Button2; break;
2141         case VK_CANCEL:
2142           event->key.keyval = GDK_Cancel; break;
2143         case VK_BACK:
2144           event->key.keyval = GDK_BackSpace; break;
2145         case VK_TAB:
2146           event->key.keyval = (GetKeyState (VK_SHIFT) < 0 ? 
2147             GDK_ISO_Left_Tab : GDK_Tab);
2148           break;
2149         case VK_CLEAR:
2150           event->key.keyval = GDK_Clear; break;
2151         case VK_RETURN:
2152           event->key.keyval = GDK_Return; break;
2153         case VK_SHIFT:
2154           /* Don't let Shift auto-repeat */
2155           if (msg->message == WM_KEYDOWN
2156               && (HIWORD (msg->lParam) & KF_REPEAT))
2157             ignore_wm_char = FALSE;
2158           else
2159             event->key.keyval = GDK_Shift_L;
2160           break;
2161         case VK_CONTROL:
2162           /* And not Control either */
2163           if (msg->message == WM_KEYDOWN
2164               && (HIWORD (msg->lParam) & KF_REPEAT))
2165             ignore_wm_char = FALSE;
2166           else if (HIWORD (msg->lParam) & KF_EXTENDED)
2167             event->key.keyval = GDK_Control_R;
2168           else
2169             event->key.keyval = GDK_Control_L;
2170           break;
2171         case VK_MENU:
2172           /* And not Alt */
2173           if (msg->message == WM_KEYDOWN
2174               && (HIWORD (msg->lParam) & KF_REPEAT))
2175             ignore_wm_char = FALSE;
2176           else if (HIWORD (msg->lParam) & KF_EXTENDED)
2177             {
2178               /* AltGr key comes in as Control+Right Alt */
2179               if (GetKeyState (VK_CONTROL) < 0)
2180                 {
2181                   ignore_wm_char = FALSE;
2182                   is_altgr_key = TRUE;
2183                 }
2184               event->key.keyval = GDK_Alt_R;
2185             }
2186           else
2187             {
2188               event->key.keyval = GDK_Alt_L;
2189               /* This needed in case she types Alt+nnn (on the numpad) */
2190               ignore_wm_char = FALSE;
2191             }
2192           break;
2193         case VK_PAUSE:
2194           event->key.keyval = GDK_Pause; break;
2195         case VK_CAPITAL:
2196           event->key.keyval = GDK_Caps_Lock; break;
2197         case VK_ESCAPE:
2198           event->key.keyval = GDK_Escape; break;
2199         case VK_PRIOR:
2200           event->key.keyval = GDK_Prior; break;
2201         case VK_NEXT:
2202           event->key.keyval = GDK_Next; break;
2203         case VK_END:
2204           event->key.keyval = GDK_End; break;
2205         case VK_HOME:
2206           event->key.keyval = GDK_Home; break;
2207         case VK_LEFT:
2208           event->key.keyval = GDK_Left; break;
2209         case VK_UP:
2210           event->key.keyval = GDK_Up; break;
2211         case VK_RIGHT:
2212           event->key.keyval = GDK_Right; break;
2213         case VK_DOWN:
2214           event->key.keyval = GDK_Down; break;
2215         case VK_SELECT:
2216           event->key.keyval = GDK_Select; break;
2217         case VK_PRINT:
2218           event->key.keyval = GDK_Print; break;
2219         case VK_EXECUTE:
2220           event->key.keyval = GDK_Execute; break;
2221         case VK_INSERT:
2222           event->key.keyval = GDK_Insert; break;
2223         case VK_DELETE:
2224           event->key.keyval = GDK_Delete; break;
2225         case VK_HELP:
2226           event->key.keyval = GDK_Help; break;
2227         case VK_NUMPAD0:
2228         case VK_NUMPAD1:
2229         case VK_NUMPAD2:
2230         case VK_NUMPAD3:
2231         case VK_NUMPAD4:
2232         case VK_NUMPAD5:
2233         case VK_NUMPAD6:
2234         case VK_NUMPAD7:
2235         case VK_NUMPAD8:
2236         case VK_NUMPAD9:
2237           /* Apparently applications work better if we just pass numpad digits
2238            * on as real digits? So wait for the WM_CHAR instead.
2239            */
2240           ignore_wm_char = FALSE;
2241           break;
2242         case VK_MULTIPLY:
2243           event->key.keyval = GDK_KP_Multiply; break;
2244         case VK_ADD:
2245           /* Pass it on as an ASCII plus in WM_CHAR. */
2246           ignore_wm_char = FALSE;
2247           break;
2248         case VK_SEPARATOR:
2249           event->key.keyval = GDK_KP_Separator; break;
2250         case VK_SUBTRACT:
2251           /* Pass it on as an ASCII minus in WM_CHAR. */
2252           ignore_wm_char = FALSE;
2253           break;
2254         case VK_DECIMAL:
2255           /* The keypad decimal key should also be passed on as the decimal
2256            * sign ('.' or ',' depending on the Windows locale settings,
2257            * apparently). So wait for the WM_CHAR here, also.
2258            */
2259           ignore_wm_char = FALSE;
2260           break;
2261         case VK_DIVIDE:
2262           event->key.keyval = GDK_KP_Divide; break;
2263         case VK_F1:
2264           event->key.keyval = GDK_F1; break;
2265         case VK_F2:
2266           event->key.keyval = GDK_F2; break;
2267         case VK_F3:
2268           event->key.keyval = GDK_F3; break;
2269         case VK_F4:
2270           event->key.keyval = GDK_F4; break;
2271         case VK_F5:
2272           event->key.keyval = GDK_F5; break;
2273         case VK_F6:
2274           event->key.keyval = GDK_F6; break;
2275         case VK_F7:
2276           event->key.keyval = GDK_F7; break;
2277         case VK_F8:
2278           event->key.keyval = GDK_F8; break;
2279         case VK_F9:
2280           event->key.keyval = GDK_F9; break;
2281         case VK_F10:
2282           event->key.keyval = GDK_F10; break;
2283         case VK_F11:
2284           event->key.keyval = GDK_F11; break;
2285         case VK_F12:
2286           event->key.keyval = GDK_F12; break;
2287         case VK_F13:
2288           event->key.keyval = GDK_F13; break;
2289         case VK_F14:
2290           event->key.keyval = GDK_F14; break;
2291         case VK_F15:
2292           event->key.keyval = GDK_F15; break;
2293         case VK_F16:
2294           event->key.keyval = GDK_F16; break;
2295         case '0':
2296         case '1':
2297         case '2':
2298         case '3':
2299         case '4':
2300         case '5':
2301         case '6':
2302         case '7':
2303         case '8':
2304         case '9':
2305           if (!is_altgr_key && (GetKeyState (VK_CONTROL) < 0
2306                                 || GetKeyState (VK_MENU) < 0))
2307             /* Control- or Alt-digits won't come in as a WM_CHAR,
2308              * but beware of AltGr-digits, which are used for instance
2309              * on Finnish keyboards.
2310              */
2311             event->key.keyval = GDK_0 + (msg->wParam - '0');
2312           else
2313             ignore_wm_char = FALSE;
2314           break;
2315         case VK_OEM_PLUS:       /* On my Win98, the '+' key comes in
2316                                  * as VK_OEM_PLUS, etc.
2317                                  */
2318         case VK_OEM_COMMA:
2319         case VK_OEM_MINUS:
2320         case VK_OEM_PERIOD:
2321         case VK_OEM_2:
2322         case VK_OEM_4:
2323         case VK_OEM_5:
2324         case VK_OEM_6:
2325           if (!is_altgr_key && (GetKeyState (VK_CONTROL) < 0
2326                                 || GetKeyState (VK_MENU) < 0))
2327             /* Control- or Alt-plus won't come in as WM_CHAR,
2328              * but beware of AltGr-plus which is backslash on
2329              * Finnish keyboards
2330              */
2331             /* All these VK_OEM keycodes happen to be the corresponding ASCII
2332              * char + 0x90
2333              */
2334             event->key.keyval = msg->wParam - 0x90;
2335           else
2336             ignore_wm_char = FALSE;
2337           break;
2338         case VK_OEM_1:
2339           if (!is_altgr_key && (GetKeyState (VK_CONTROL) < 0
2340                                 || GetKeyState (VK_MENU) < 0))
2341             /* ;: on US keyboard */
2342             event->key.keyval = ';';
2343           else
2344             ignore_wm_char = FALSE;
2345           break;
2346         case VK_OEM_3:
2347           if (!is_altgr_key && (GetKeyState (VK_CONTROL) < 0
2348                                 || GetKeyState (VK_MENU) < 0))
2349             /* `~ on US keyboard */
2350             event->key.keyval = '`';
2351           else
2352             ignore_wm_char = FALSE;
2353           break;
2354         case VK_OEM_7:
2355           if (!is_altgr_key && (GetKeyState (VK_CONTROL) < 0
2356                                 || GetKeyState (VK_MENU) < 0))
2357             /* '" on US keyboard */
2358             event->key.keyval = '\'';
2359           else
2360             ignore_wm_char = FALSE;
2361           break;
2362         default:
2363           if (msg->message == WM_SYSKEYDOWN || msg->message == WM_SYSKEYUP)
2364             event->key.keyval = msg->wParam;
2365           else
2366             ignore_wm_char = FALSE;
2367           break;
2368         }
2369
2370       if (!ignore_wm_char)
2371         break;
2372
2373       if (!propagate (&window, msg,
2374                       k_grab_window, k_grab_owner_events, GDK_ALL_EVENTS_MASK,
2375                       doesnt_want_key))
2376         break;
2377       ASSIGN_WINDOW (window);
2378
2379       is_altgr_key = FALSE;
2380       event->key.type = ((msg->message == WM_KEYDOWN
2381                           || msg->message == WM_SYSKEYDOWN) ?
2382                          GDK_KEY_PRESS : GDK_KEY_RELEASE);
2383       event->key.time = _gdk_win32_get_next_tick (msg->time);
2384       event->key.state = 0;
2385       if (GetKeyState (VK_SHIFT) < 0)
2386         event->key.state |= GDK_SHIFT_MASK;
2387       if (GetKeyState (VK_CAPITAL) & 0x1)
2388         event->key.state |= GDK_LOCK_MASK;
2389       if (GetKeyState (VK_CONTROL) < 0)
2390         event->key.state |= GDK_CONTROL_MASK;
2391       if (msg->wParam != VK_MENU && GetKeyState (VK_MENU) < 0)
2392         event->key.state |= GDK_MOD1_MASK;
2393       event->key.hardware_keycode = msg->wParam;
2394       event->key.group = 0;
2395       event->key.string = NULL;
2396       event->key.length = 0;
2397       return_val = !GDK_WINDOW_DESTROYED (window);
2398       break;
2399
2400     case WM_IME_COMPOSITION:
2401       if (!use_ime_composition)
2402         break;
2403
2404       GDK_NOTE (EVENTS, g_print ("WM_IME_COMPOSITION: %p  %#lx\n",
2405                                  msg->hwnd, msg->lParam));
2406       if (msg->lParam & GCS_RESULTSTR)
2407         goto wm_char;
2408       break;
2409
2410     case WM_IME_CHAR:
2411       GDK_NOTE (EVENTS,
2412                 g_print ("WM_IME_CHAR: %p  bytes: %#.04x\n",
2413                          msg->hwnd, msg->wParam));
2414       goto wm_char;
2415       
2416     case WM_CHAR:
2417     case WM_SYSCHAR:
2418       GDK_NOTE (EVENTS, 
2419                 g_print ("WM_%sCHAR: %p  %#x %s %s\n",
2420                          (msg->message == WM_CHAR ? "" : "SYS"),
2421                          msg->hwnd, msg->wParam,
2422                          decode_key_lparam (msg->lParam),
2423                          (ignore_wm_char ? "ignored" : "")));
2424
2425       if (ignore_wm_char)
2426         {
2427           ignore_wm_char = FALSE;
2428           break;
2429         }
2430
2431     wm_char:
2432       if (!propagate (&window, msg,
2433                       k_grab_window, k_grab_owner_events, GDK_ALL_EVENTS_MASK,
2434                       doesnt_want_char))
2435           break;
2436       ASSIGN_WINDOW (window);
2437
2438       event->key.window = window;
2439       return_val = !GDK_WINDOW_DESTROYED (window);
2440
2441       if (return_val && (event->key.window == k_grab_window
2442                          || (private->event_mask & GDK_KEY_RELEASE_MASK)))
2443         {
2444           if (window == k_grab_window
2445               || (private->event_mask & GDK_KEY_PRESS_MASK))
2446             {
2447               /* Append a GDK_KEY_PRESS event to the pushback list
2448                * (from which it will be fetched before the release
2449                * event).
2450                */
2451               GdkEvent *event2 = gdk_event_new (GDK_KEY_PRESS);
2452               build_keypress_event (event2, msg);
2453               event2->key.window = window;
2454               gdk_drawable_ref (window);
2455               _gdk_event_queue_append (display, event2);
2456               GDK_NOTE (EVENTS, print_event (event2));
2457             }
2458           /* Return the key release event.  */
2459           build_keyrelease_event (event, msg);
2460         }
2461       else if (return_val && (private->event_mask & GDK_KEY_PRESS_MASK))
2462         {
2463           /* Return just the key press event. */
2464           build_keypress_event (event, msg);
2465         }
2466       else
2467         return_val = FALSE;
2468
2469 #if 0 /* Don't reset is_AltGr_key here. Othewise we can't type several
2470        * AltGr-accessed chars while keeping the AltGr pressed down
2471        * all the time.
2472        */
2473       is_AltGr_key = FALSE;
2474 #endif
2475       break;
2476
2477     case WM_LBUTTONDOWN:
2478       button = 1;
2479       goto buttondown0;
2480     case WM_MBUTTONDOWN:
2481       button = 2;
2482       goto buttondown0;
2483     case WM_RBUTTONDOWN:
2484       button = 3;
2485
2486     buttondown0:
2487       GDK_NOTE (EVENTS, 
2488                 g_print ("WM_%cBUTTONDOWN: %p  (%d,%d)\n",
2489                          " LMR"[button],
2490                          msg->hwnd,
2491                          LOWORD (msg->lParam), HIWORD (msg->lParam)));
2492
2493       if (GDK_WINDOW_OBJECT (window)->extension_events != 0
2494           && _gdk_input_ignore_core)
2495         {
2496           GDK_NOTE (EVENTS, g_print ("...ignored\n"));
2497           break;
2498         }
2499
2500       ASSIGN_WINDOW (find_window_for_pointer_event (window, msg));
2501
2502       if (window != current_window)
2503         synthesize_crossing_events (window, msg);
2504
2505       event->button.type = GDK_BUTTON_PRESS;
2506       if (!propagate (&window, msg,
2507                       p_grab_window, p_grab_owner_events, p_grab_mask,
2508                       doesnt_want_button_press))
2509           break;
2510       ASSIGN_WINDOW (window);
2511
2512       event->button.window = window;
2513
2514       /* Emulate X11's automatic active grab */
2515       if (!p_grab_window)
2516         {
2517           /* No explicit active grab, let's start one automatically */
2518           gint owner_events = (private->event_mask & (GDK_BUTTON_PRESS_MASK|GDK_BUTTON_RELEASE_MASK));
2519           
2520           GDK_NOTE (EVENTS, g_print ("...automatic grab started\n"));
2521           gdk_pointer_grab (window,
2522                             owner_events,
2523                             private->event_mask,
2524                             NULL, NULL, 0);
2525           p_grab_automatic = TRUE;
2526         }
2527
2528       event->button.time = _gdk_win32_get_next_tick (msg->time);
2529       if (window != orig_window)
2530         translate_mouse_coords (orig_window, window, msg);
2531       event->button.x = current_x = (gint16) LOWORD (msg->lParam);
2532       event->button.y = current_y = (gint16) HIWORD (msg->lParam);
2533       _gdk_windowing_window_get_offsets (window, &xoffset, &yoffset);
2534       event->button.x += xoffset;  /* XXX translate current_x, y too? */
2535       event->button.y += yoffset;
2536       event->button.x_root = current_x_root = msg->pt.x;
2537       event->button.y_root = current_y_root = msg->pt.y;
2538       event->button.axes = NULL;
2539       event->button.state = build_pointer_event_state (msg);
2540       event->button.button = button;
2541       event->button.device = display->core_pointer;
2542
2543       return_val = !GDK_WINDOW_DESTROYED (window);
2544       break;
2545
2546     case WM_LBUTTONUP:
2547       button = 1;
2548       goto buttonup0;
2549     case WM_MBUTTONUP:
2550       button = 2;
2551       goto buttonup0;
2552     case WM_RBUTTONUP:
2553       button = 3;
2554
2555     buttonup0:
2556       GDK_NOTE (EVENTS, 
2557                 g_print ("WM_%cBUTTONUP: %p  (%d,%d)\n",
2558                          " LMR"[button],
2559                          msg->hwnd,
2560                          LOWORD (msg->lParam), HIWORD (msg->lParam)));
2561
2562       ASSIGN_WINDOW (find_window_for_pointer_event (window, msg));
2563
2564       if (GDK_WINDOW_OBJECT (window)->extension_events != 0
2565           && _gdk_input_ignore_core)
2566         {
2567           GDK_NOTE (EVENTS, g_print ("...ignored\n"));
2568           break;
2569         }
2570
2571       if (window != current_window)
2572         synthesize_crossing_events (window, msg);
2573
2574       event->button.type = GDK_BUTTON_RELEASE;
2575       if (!propagate (&window, msg,
2576                       p_grab_window, p_grab_owner_events, p_grab_mask,
2577                       doesnt_want_button_release))
2578         {
2579         }
2580       else
2581         {
2582           ASSIGN_WINDOW (window);
2583
2584           event->button.window = window;
2585           event->button.time = _gdk_win32_get_next_tick (msg->time);
2586           if (window != orig_window)
2587             translate_mouse_coords (orig_window, window, msg);
2588           _gdk_windowing_window_get_offsets (window, &xoffset, &yoffset);
2589           event->button.x = (gint16) LOWORD (msg->lParam) + xoffset;
2590           event->button.y = (gint16) HIWORD (msg->lParam) + yoffset;
2591           event->button.x_root = current_x_root = msg->pt.x;
2592           event->button.y_root = current_y_root = msg->pt.y;
2593           event->button.axes = NULL;
2594           event->button.state = build_pointer_event_state (msg);
2595           event->button.button = button;
2596           event->button.device = display->core_pointer;
2597           
2598           return_val = !GDK_WINDOW_DESTROYED (window);
2599         }
2600
2601       if (p_grab_window != NULL
2602           && p_grab_automatic
2603           && (msg->wParam & (MK_LBUTTON | MK_MBUTTON | MK_RBUTTON)) == 0)
2604         gdk_pointer_ungrab (0);
2605       break;
2606
2607     case WM_MOUSEMOVE:
2608       GDK_NOTE (EVENTS,
2609                 g_print ("WM_MOUSEMOVE: %p  %#x (%d,%d)\n",
2610                          msg->hwnd, msg->wParam,
2611                          LOWORD (msg->lParam), HIWORD (msg->lParam)));
2612
2613       ASSIGN_WINDOW (find_window_for_pointer_event (window, msg));
2614
2615       /* If we haven't moved, don't create any event.
2616        * Windows sends WM_MOUSEMOVE messages after button presses
2617        * even if the mouse doesn't move. This disturbs gtk.
2618        */
2619       if (window == current_window
2620           && LOWORD (msg->lParam) == current_x
2621           && HIWORD (msg->lParam) == current_y)
2622         break;
2623
2624       /* HB: only process mouse move messages if we own the active window. */
2625       GetWindowThreadProcessId (GetActiveWindow (), &pidActWin);
2626       GetWindowThreadProcessId (msg->hwnd, &pidThis);
2627       if (pidActWin != pidThis)
2628         break;
2629
2630       if (window != current_window)
2631         synthesize_crossing_events (window, msg);
2632
2633       if (GDK_WINDOW_OBJECT (window)->extension_events != 0
2634           && _gdk_input_ignore_core)
2635         {
2636           GDK_NOTE (EVENTS, g_print ("...ignored\n"));
2637           break;
2638         }
2639
2640       event->motion.type = GDK_MOTION_NOTIFY;
2641       if (!propagate (&window, msg,
2642                       p_grab_window, p_grab_owner_events, p_grab_mask,
2643                       doesnt_want_button_motion))
2644           break;
2645       ASSIGN_WINDOW (window);
2646
2647       event->motion.window = window;
2648       event->motion.time = _gdk_win32_get_next_tick (msg->time);
2649       if (window != orig_window)
2650         translate_mouse_coords (orig_window, window, msg);
2651       event->motion.x = current_x = (gint16) LOWORD (msg->lParam);
2652       event->motion.y = current_y = (gint16) HIWORD (msg->lParam);
2653       _gdk_windowing_window_get_offsets (window, &xoffset, &yoffset);
2654       event->motion.x += xoffset;
2655       event->motion.y += yoffset;
2656       event->motion.x_root = current_x_root = msg->pt.x;
2657       event->motion.y_root = current_y_root = msg->pt.y;
2658       event->motion.axes = NULL;
2659       event->motion.state = build_pointer_event_state (msg);
2660       event->motion.is_hint = FALSE;
2661       event->motion.device = display->core_pointer;
2662
2663       return_val = !GDK_WINDOW_DESTROYED (window);
2664       break;
2665
2666     case WM_NCMOUSEMOVE:
2667       GDK_NOTE (EVENTS,
2668                 g_print ("WM_NCMOUSEMOVE: %p  x,y: %d %d\n",
2669                          msg->hwnd,
2670                          LOWORD (msg->lParam), HIWORD (msg->lParam)));
2671       if (current_window != NULL
2672           && (GDK_WINDOW_OBJECT (current_window)->event_mask & GDK_LEAVE_NOTIFY_MASK))
2673         {
2674           GDK_NOTE (EVENTS, g_print ("...synthesizing LEAVE_NOTIFY event\n"));
2675
2676           event->crossing.type = GDK_LEAVE_NOTIFY;
2677           event->crossing.window = current_window;
2678           event->crossing.subwindow = NULL;
2679           event->crossing.time = _gdk_win32_get_next_tick (msg->time);
2680           _gdk_windowing_window_get_offsets (current_window, &xoffset, &yoffset);
2681           event->crossing.x = current_x + xoffset;
2682           event->crossing.y = current_y + yoffset;
2683           event->crossing.x_root = current_x_root;
2684           event->crossing.y_root = current_y_root;
2685           event->crossing.mode = GDK_CROSSING_NORMAL;
2686           event->crossing.detail = GDK_NOTIFY_NONLINEAR;
2687
2688           event->crossing.focus = TRUE; /* ??? */
2689           event->crossing.state = 0; /* ??? */
2690           return_val = TRUE;
2691         }
2692
2693       if (current_window)
2694         {
2695           gdk_drawable_unref (current_window);
2696           current_window = NULL;
2697         }
2698
2699       break;
2700
2701     case WM_MOUSEWHEEL:
2702       GDK_NOTE (EVENTS, g_print ("WM_MOUSEWHEEL: %p %d\n",
2703                                  msg->hwnd, HIWORD (msg->wParam)));
2704
2705       event->scroll.type = GDK_SCROLL;
2706
2707       /* WM_MOUSEWHEEL is delivered to the focus window Work around
2708        * that. Also, the position is in screen coordinates, not client
2709        * coordinates as with the button messages. I love the
2710        * consistency of Windows.
2711        */
2712       pt.x = LOWORD (msg->lParam);
2713       pt.y = HIWORD (msg->lParam);
2714       if ((hwnd = WindowFromPoint (pt)) == NULL)
2715         break;
2716
2717       msg->hwnd = hwnd;
2718       if ((new_window = gdk_win32_handle_table_lookup ((GdkNativeWindow) msg->hwnd)) == NULL)
2719         break;
2720
2721       if (new_window != window)
2722         {
2723           gdk_drawable_unref (window);
2724           ASSIGN_WINDOW (new_window);
2725           gdk_drawable_ref (window);
2726         }
2727
2728       if (GDK_WINDOW_OBJECT (window)->extension_events != 0
2729           && _gdk_input_ignore_core)
2730         {
2731           GDK_NOTE (EVENTS, g_print ("...ignored\n"));
2732           break;
2733         }
2734
2735       if (!propagate (&window, msg,
2736                       p_grab_window, p_grab_owner_events, p_grab_mask,
2737                       doesnt_want_scroll))
2738         break;
2739
2740       ASSIGN_WINDOW (window);
2741
2742       ScreenToClient (msg->hwnd, &pt);
2743       event->button.window = window;
2744       event->scroll.direction = (((short) HIWORD (msg->wParam)) > 0) ?
2745         GDK_SCROLL_UP : GDK_SCROLL_DOWN;
2746       event->scroll.window = window;
2747       event->scroll.time = _gdk_win32_get_next_tick (msg->time);
2748       _gdk_windowing_window_get_offsets (window, &xoffset, &yoffset);
2749       event->scroll.x = (gint16) pt.x + xoffset;
2750       event->scroll.y = (gint16) pt.y + yoffset;
2751       event->scroll.x_root = (gint16) LOWORD (msg->lParam);
2752       event->scroll.y_root = (gint16) HIWORD (msg->lParam);
2753       event->scroll.state = build_pointer_event_state (msg);
2754       event->scroll.device = display->core_pointer;
2755       return_val = !GDK_WINDOW_DESTROYED (window);
2756       
2757       break;
2758
2759     case WM_QUERYNEWPALETTE:
2760       GDK_NOTE (EVENTS_OR_COLORMAP, g_print ("WM_QUERYNEWPALETTE: %p\n",
2761                                              msg->hwnd));
2762       if (gdk_visual_get_system ()->type == GDK_VISUAL_PSEUDO_COLOR)
2763         {
2764           synthesize_expose_events (window);
2765           update_colors_counter = 0;
2766         }
2767       *ret_val_flagp = TRUE;
2768       *ret_valp = FALSE;
2769       break;
2770
2771     case WM_PALETTECHANGED:
2772       GDK_NOTE (EVENTS_OR_COLORMAP, g_print ("WM_PALETTECHANGED: %p %p\n",
2773                                              msg->hwnd, (HWND) msg->wParam));
2774       *ret_val_flagp = TRUE;
2775       *ret_valp = FALSE;
2776
2777       if (gdk_visual_get_system ()->type != GDK_VISUAL_PSEUDO_COLOR)
2778         break;
2779
2780       if (msg->hwnd == (HWND) msg->wParam)
2781         break;
2782
2783       if (++update_colors_counter == 5)
2784         {
2785           synthesize_expose_events (window);
2786           update_colors_counter = 0;
2787           break;
2788         }
2789       
2790       update_colors (window, TRUE);
2791       break;
2792
2793     case WM_SETFOCUS:
2794     case WM_KILLFOCUS:
2795       GDK_NOTE (EVENTS, g_print ("WM_%sFOCUS: %p\n",
2796                                  (msg->message == WM_SETFOCUS ?
2797                                   "SET" : "KILL"),
2798                                  msg->hwnd));
2799       
2800       if (!(private->event_mask & GDK_FOCUS_CHANGE_MASK))
2801         break;
2802
2803       event->focus_change.type = GDK_FOCUS_CHANGE;
2804       event->focus_change.window = window;
2805       event->focus_change.in = (msg->message == WM_SETFOCUS);
2806       return_val = !GDK_WINDOW_DESTROYED (window);
2807       break;
2808
2809     case WM_ERASEBKGND:
2810       GDK_NOTE (EVENTS, g_print ("WM_ERASEBKGND: %p  dc %p\n",
2811                                  msg->hwnd, (HANDLE) msg->wParam));
2812       
2813       if (GDK_WINDOW_DESTROYED (window))
2814         break;
2815
2816       erase_background (window, (HDC) msg->wParam);
2817       *ret_val_flagp = TRUE; /* always claim as handled */
2818       *ret_valp = 1;
2819       break;
2820
2821     case WM_PAINT:
2822       hrgn = CreateRectRgn (0, 0, 0, 0);
2823       if (GetUpdateRgn (msg->hwnd, hrgn, FALSE) == ERROR)
2824         {
2825           WIN32_GDI_FAILED ("GetUpdateRgn");
2826           break;
2827         }
2828
2829       hdc = BeginPaint (msg->hwnd, &paintstruct);
2830
2831       GDK_NOTE (EVENTS, g_print ("WM_PAINT: %p  %s %s dc %p%s\n",
2832                                  msg->hwnd,
2833                                  _gdk_win32_rect_to_string (&paintstruct.rcPaint),
2834                                  (paintstruct.fErase ? "erase" : ""),
2835                                  hdc,
2836                                  (return_exposes ? " return_exposes" : "")));
2837
2838       EndPaint (msg->hwnd, &paintstruct);
2839
2840       /* HB: don't generate GDK_EXPOSE events for InputOnly
2841        * windows -> backing store now works!
2842        */
2843       if (GDK_WINDOW_OBJECT (window)->input_only)
2844         {
2845           DeleteObject (hrgn);
2846           break;
2847         }
2848
2849       if (!(private->event_mask & GDK_EXPOSURE_MASK))
2850         {
2851           GDK_NOTE (EVENTS, g_print ("...ignored\n"));
2852           DeleteObject (hrgn);
2853           break;
2854         }
2855
2856 #if 0 /* we need to process exposes even with GDK_NO_BG
2857        * Otherwise The GIMP canvas update is broken ....
2858        */
2859       if (GDK_WINDOW_OBJECT (window)->bg_pixmap == GDK_NO_BG)
2860         break;
2861 #endif
2862
2863       if ((paintstruct.rcPaint.right == paintstruct.rcPaint.left)
2864           || (paintstruct.rcPaint.bottom == paintstruct.rcPaint.top))
2865         {
2866           GDK_NOTE (EVENTS, g_print ("...empty paintstruct, ignored\n"));
2867           DeleteObject (hrgn);
2868           break;
2869         }
2870
2871       if (return_exposes)
2872         {
2873           event->expose.type = GDK_EXPOSE;
2874           event->expose.window = window;
2875           event->expose.area.x = paintstruct.rcPaint.left;
2876           event->expose.area.y = paintstruct.rcPaint.top;
2877           event->expose.area.width = paintstruct.rcPaint.right - paintstruct.rcPaint.left;
2878           event->expose.area.height = paintstruct.rcPaint.bottom - paintstruct.rcPaint.top;
2879           event->expose.region = _gdk_win32_hrgn_to_region (hrgn);
2880           event->expose.count = 0;
2881
2882           return_val = !GDK_WINDOW_DESTROYED (window);
2883           if (return_val)
2884             {
2885               GList *list = display->queued_events;
2886               while (list != NULL )
2887                 {
2888                   GdkEventPrivate *event = list->data;
2889                   if (event->event.any.type == GDK_EXPOSE &&
2890                       event->event.any.window == window &&
2891                       !(event->flags & GDK_EVENT_PENDING))
2892                     event->event.expose.count++;
2893
2894                   list = list->next;
2895                 }
2896             }
2897         }
2898       else
2899         {
2900           GdkRegion *update_region = _gdk_win32_hrgn_to_region (hrgn);
2901
2902           _gdk_windowing_window_get_offsets (window, &xoffset, &yoffset);
2903           gdk_region_offset (update_region, xoffset, yoffset);
2904
2905           _gdk_window_process_expose (window, update_region);
2906           gdk_region_destroy (update_region);
2907           return_val = FALSE;
2908         }
2909       DeleteObject (hrgn);
2910       break;
2911
2912     case WM_GETICON:
2913       GDK_NOTE (EVENTS, g_print ("WM_GETICON: %p %s\n",
2914                                  msg->hwnd, 
2915                                  (ICON_BIG == msg->wParam ? "big" : "small")));
2916       break;
2917  
2918     case WM_SETCURSOR:
2919       GDK_NOTE (EVENTS, g_print ("WM_SETCURSOR: %p %#x %#x\n",
2920                                  msg->hwnd,
2921                                  LOWORD (msg->lParam), HIWORD (msg->lParam)));
2922
2923       if (LOWORD (msg->lParam) != HTCLIENT)
2924         break;
2925
2926       if (p_grab_window != NULL && p_grab_cursor != NULL)
2927         hcursor = p_grab_cursor;
2928       else if (!GDK_WINDOW_DESTROYED (window))
2929         hcursor = GDK_WINDOW_IMPL_WIN32 (private->impl)->hcursor;
2930       else
2931         hcursor = NULL;
2932
2933       if (hcursor != NULL)
2934         {
2935           GDK_NOTE (EVENTS, g_print ("...SetCursor(%p)\n", hcursor));
2936           SetCursor (hcursor);
2937           *ret_val_flagp = TRUE;
2938           *ret_valp = TRUE;
2939         }
2940       break;
2941
2942     case WM_SHOWWINDOW:
2943       GDK_NOTE (EVENTS, g_print ("WM_SHOWWINDOW: %p  %d\n",
2944                                  msg->hwnd, msg->wParam));
2945
2946       if (!(private->event_mask & GDK_STRUCTURE_MASK))
2947         break;
2948
2949       if (msg->lParam == SW_OTHERUNZOOM ||
2950           msg->lParam == SW_OTHERZOOM)
2951         break;
2952
2953       event->any.type = (msg->wParam ? GDK_MAP : GDK_UNMAP);
2954       event->any.window = window;
2955
2956       if (event->any.type == GDK_UNMAP
2957           && p_grab_window == window)
2958         gdk_pointer_ungrab (msg->time);
2959
2960       if (event->any.type == GDK_UNMAP
2961           && k_grab_window == window)
2962         gdk_keyboard_ungrab (msg->time);
2963
2964       return_val = !GDK_WINDOW_DESTROYED (window);
2965       break;
2966
2967     case WM_SIZE:
2968       GDK_NOTE (EVENTS,
2969                 g_print ("WM_SIZE: %p  %s %dx%d\n",
2970                          msg->hwnd,
2971                          (msg->wParam == SIZE_MAXHIDE ? "MAXHIDE" :
2972                           (msg->wParam == SIZE_MAXIMIZED ? "MAXIMIZED" :
2973                            (msg->wParam == SIZE_MAXSHOW ? "MAXSHOW" :
2974                             (msg->wParam == SIZE_MINIMIZED ? "MINIMIZED" :
2975                              (msg->wParam == SIZE_RESTORED ? "RESTORED" : "?"))))),
2976                          LOWORD (msg->lParam), HIWORD (msg->lParam)));
2977
2978       if (msg->wParam == SIZE_MINIMIZED)
2979         {
2980           /* Don't generate any GDK event. This is *not* an UNMAP. */
2981
2982           if (p_grab_window == window)
2983             gdk_pointer_ungrab (msg->time);
2984
2985           if (k_grab_window == window)
2986             gdk_keyboard_ungrab (msg->time);
2987
2988           gdk_synthesize_window_state (window,
2989                                        GDK_WINDOW_STATE_WITHDRAWN,
2990                                        GDK_WINDOW_STATE_ICONIFIED);
2991         }
2992       else if ((msg->wParam == SIZE_RESTORED
2993                 || msg->wParam == SIZE_MAXIMIZED)
2994 #if 1
2995                && GDK_WINDOW_TYPE (window) != GDK_WINDOW_CHILD
2996 #endif
2997                                                                  )
2998         {
2999           if (!(private->event_mask & GDK_STRUCTURE_MASK))
3000             break;
3001
3002           event->configure.type = GDK_CONFIGURE;
3003           event->configure.window = window;
3004           pt.x = 0;
3005           pt.y = 0;
3006           ClientToScreen (msg->hwnd, &pt);
3007           event->configure.x = pt.x;
3008           event->configure.y = pt.y;
3009           event->configure.width = LOWORD (msg->lParam);
3010           event->configure.height = HIWORD (msg->lParam);
3011           private->x = event->configure.x;
3012           private->y = event->configure.y;
3013           GDK_WINDOW_IMPL_WIN32 (private->impl)->width = event->configure.width;
3014           GDK_WINDOW_IMPL_WIN32 (private->impl)->height = event->configure.height;
3015
3016           if (msg->wParam == SIZE_RESTORED)
3017             gdk_synthesize_window_state (window,
3018                                          GDK_WINDOW_STATE_ICONIFIED |
3019                                          GDK_WINDOW_STATE_MAXIMIZED |
3020                                          GDK_WINDOW_STATE_WITHDRAWN,
3021                                          0);
3022           else if (msg->wParam == SIZE_MAXIMIZED)
3023             gdk_synthesize_window_state (window,
3024                                          GDK_WINDOW_STATE_ICONIFIED |
3025                                          GDK_WINDOW_STATE_WITHDRAWN,
3026                                          GDK_WINDOW_STATE_MAXIMIZED);
3027
3028           if (private->resize_count > 1)
3029             private->resize_count -= 1;
3030           
3031           return_val = !GDK_WINDOW_DESTROYED (window);
3032           if (return_val && private->extension_events != 0)
3033             _gdk_input_configure_event (&event->configure, window);
3034         }
3035       break;
3036 #if 0
3037     case WM_SIZING :
3038       {
3039         LPRECT lpr = (LPRECT) msg->lParam;
3040         NONCLIENTMETRICS ncm;
3041         ncm.cbSize = sizeof (NONCLIENTMETRICS);
3042
3043         SystemParametersInfo (SPI_GETNONCLIENTMETRICS, ncm.cbSize, &ncm, 0);
3044
3045         g_print ("WM_SIZING borderWidth %d captionHeight %d\n",
3046                  ncm.iBorderWidth, ncm.iCaptionHeight);
3047           event->configure.type = GDK_CONFIGURE;
3048           event->configure.window = window;
3049
3050           event->configure.x = lpr->left + ncm.iBorderWidth;
3051           event->configure.y = lpr->top + ncm.iCaptionHeight;
3052           event->configure.width = lpr->right - lpr->left - 2 * ncm.iBorderWidth;
3053           event->configure.height = lpr->bottom - lpr->top - ncm.iCaptionHeight;
3054           private->x = event->configure.x;
3055           private->y = event->configure.y;
3056           GDK_WINDOW_IMPL_WIN32 (private->impl)->width = event->configure.width;
3057           GDK_WINDOW_IMPL_WIN32 (private->impl)->height = event->configure.height;
3058
3059           if (private->resize_count > 1)
3060             private->resize_count -= 1;
3061
3062           return_val = !GDK_WINDOW_DESTROYED (window);
3063           if (return_val && private->extension_events != 0)
3064             _gdk_input_configure_event (&event->configure, window);
3065       }
3066       break;
3067 #endif
3068     case WM_GETMINMAXINFO:
3069       GDK_NOTE (EVENTS, g_print ("WM_GETMINMAXINFO: %p\n", msg->hwnd));
3070
3071       impl = GDK_WINDOW_IMPL_WIN32 (private->impl);
3072       mmi = (MINMAXINFO*) msg->lParam;
3073       if (impl->hint_flags & GDK_HINT_MIN_SIZE)
3074         {
3075           mmi->ptMinTrackSize.x = impl->hint_min_width;
3076           mmi->ptMinTrackSize.y = impl->hint_min_height;
3077         }
3078       if (impl->hint_flags & GDK_HINT_MAX_SIZE)
3079         {
3080           mmi->ptMaxTrackSize.x = impl->hint_max_width;
3081           mmi->ptMaxTrackSize.y = impl->hint_max_height;
3082
3083           /* kind of WM functionality, limit maximized size to screen */
3084           mmi->ptMaxPosition.x = 0;
3085           mmi->ptMaxPosition.y = 0;         
3086           mmi->ptMaxSize.x = MIN (impl->hint_max_width, gdk_screen_width ());
3087           mmi->ptMaxSize.y = MIN (impl->hint_max_height, gdk_screen_height ());
3088         }
3089       else if (impl->hint_flags & GDK_HINT_MIN_SIZE)
3090         {
3091           /* need to initialize */
3092           mmi->ptMaxSize.x = gdk_screen_width ();
3093           mmi->ptMaxSize.y = gdk_screen_height ();
3094         }
3095       /* lovely API inconsistence: return FALSE when handled */
3096       if (ret_val_flagp)
3097         *ret_val_flagp = !(impl->hint_flags & (GDK_HINT_MIN_SIZE | GDK_HINT_MAX_SIZE));
3098       break;
3099
3100     case WM_MOVE:
3101       GDK_NOTE (EVENTS, g_print ("WM_MOVE: %p  (%d,%d)\n",
3102                                  msg->hwnd,
3103                                  LOWORD (msg->lParam), HIWORD (msg->lParam)));
3104
3105       if (!(private->event_mask & GDK_STRUCTURE_MASK))
3106         break;
3107
3108       if (GDK_WINDOW_TYPE (window) != GDK_WINDOW_CHILD
3109           && !IsIconic (msg->hwnd)
3110           && IsWindowVisible (msg->hwnd))
3111         {
3112           event->configure.type = GDK_CONFIGURE;
3113           event->configure.window = window;
3114           event->configure.x = LOWORD (msg->lParam);
3115           event->configure.y = HIWORD (msg->lParam);
3116           GetClientRect (msg->hwnd, &rect);
3117           event->configure.width = rect.right;
3118           event->configure.height = rect.bottom;
3119           private->x = event->configure.x;
3120           private->y = event->configure.y;
3121           GDK_WINDOW_IMPL_WIN32 (private->impl)->width = event->configure.width;
3122           GDK_WINDOW_IMPL_WIN32 (private->impl)->height = event->configure.height;
3123           
3124           return_val = !GDK_WINDOW_DESTROYED (window);
3125         }
3126       break;
3127
3128 #if 0 /* Not quite right, otherwise it may be faster/better than
3129        * WM_(MOVE|SIZE) remove decoration (frame) sizes ?
3130        */
3131     case WM_WINDOWPOSCHANGED :
3132
3133       if (!(private->event_mask & GDK_STRUCTURE_MASK))
3134         break;
3135
3136       if (GDK_WINDOW_TYPE (window) != GDK_WINDOW_CHILD
3137           && !IsIconic (msg->hwnd)
3138           && IsWindowVisible (msg->hwnd))
3139         {
3140           LPWINDOWPOS lpwp = (LPWINDOWPOS) (msg->lParam);
3141
3142           event->configure.type = GDK_CONFIGURE;
3143           event->configure.window = window;
3144           event->configure.x = lpwp->x;
3145           event->configure.y = lpwp->y;
3146           event->configure.width = lpwp->cx;
3147           event->configure.height = lpwp->cy;
3148           private->x = event->configure.x;
3149           private->y = event->configure.y;
3150           GDK_WINDOW_IMPL_WIN32 (private->impl)->width = event->configure.width;
3151           GDK_WINDOW_IMPL_WIN32 (private->impl)->height = event->configure.height;
3152           
3153           return_val = !GDK_WINDOW_DESTROYED (window);
3154
3155           GDK_NOTE (EVENTS, g_print ("WM_WINDOWPOSCHANGED: %p  %ldx%ld@+%ld+%ld\n",
3156                                      msg->hwnd,
3157                                      lpwp->cx, lpwp->cy, lpwp->x, lpwp->y));
3158
3159           if (ret_val_flagp)
3160             *ret_val_flagp = TRUE;
3161           if (ret_valp)
3162             *ret_valp = 0;
3163         }
3164       break;
3165 #endif
3166     case WM_CLOSE:
3167       GDK_NOTE (EVENTS, g_print ("WM_CLOSE: %p\n", msg->hwnd));
3168
3169       event->any.type = GDK_DELETE;
3170       event->any.window = window;
3171       
3172       return_val = !GDK_WINDOW_DESTROYED (window);
3173       break;
3174
3175 #if 0
3176     /* No, don't use delayed rendering after all. It works only if the
3177      * delayed SetClipboardData is called from the WindowProc, it
3178      * seems. (The #else part below is test code for that. It succeeds
3179      * in setting the clipboard data. But if I call SetClipboardData
3180      * in gdk_property_change (as a consequence of the
3181      * GDK_SELECTION_REQUEST event), it fails.  I deduce that this is
3182      * because delayed rendering requires that SetClipboardData is
3183      * called in the window procedure.)
3184      */
3185     case WM_RENDERFORMAT:
3186     case WM_RENDERALLFORMATS:
3187       flag = FALSE;
3188       GDK_NOTE (EVENTS, flag = TRUE);
3189       if (flag)
3190         g_print ("WM_%s: %p %#x (%s)\n",
3191                  (msg->message == WM_RENDERFORMAT ? "RENDERFORMAT" :
3192                   "RENDERALLFORMATS"),
3193                  msg->hwnd,
3194                  msg->wParam,
3195                  (msg->wParam == CF_TEXT ? "CF_TEXT" :
3196                   (msg->wParam == CF_DIB ? "CF_DIB" :
3197                    (msg->wParam == CF_UNICODETEXT ? "CF_UNICODETEXT" :
3198                     (GetClipboardFormatName (msg->wParam, buf, sizeof (buf)), buf)))));
3199
3200 #if 0
3201       event->selection.type = GDK_SELECTION_REQUEST;
3202       event->selection.window = window;
3203       event->selection.selection = gdk_clipboard_atom;
3204       if (msg->wParam == CF_TEXT)
3205         event->selection.target = GDK_TARGET_STRING;
3206       else
3207         {
3208           GetClipboardFormatName (msg->wParam, buf, sizeof (buf));
3209           event->selection.target = gdk_atom_intern (buf, FALSE);
3210         }
3211       event->selection.property = _gdk_selection_property;
3212       event->selection.requestor = (guint32) msg->hwnd;
3213       event->selection.time = _gdk_win32_get_next_tick (msg->time);
3214       return_val = !GDK_WINDOW_DESTROYED (window);
3215 #else
3216       /* Test code, to see if SetClipboardData works when called from
3217        * the window procedure.
3218        */
3219       {
3220         HGLOBAL hdata = GlobalAlloc (GMEM_MOVEABLE|GMEM_DDESHARE, 10);
3221         char *ptr = GlobalLock (hdata);
3222         strcpy (ptr, "Huhhaa");
3223         GlobalUnlock (hdata);
3224         if (!SetClipboardData (CF_TEXT, hdata))
3225           WIN32_API_FAILED ("SetClipboardData");
3226       }
3227       *ret_valp = 0;
3228       *ret_val_flagp = TRUE;
3229       return_val = FALSE;
3230 #endif
3231       break;
3232 #endif /* No delayed rendering */
3233
3234     case WM_DESTROY:
3235       GDK_NOTE (EVENTS, g_print ("WM_DESTROY: %p\n", msg->hwnd));
3236
3237       event->any.type = GDK_DESTROY;
3238       event->any.window = window;
3239       if (window != NULL && window == current_window)
3240         {
3241           gdk_drawable_unref (current_window);
3242           current_window = NULL;
3243         }
3244
3245       if (p_grab_window == window)
3246         gdk_pointer_ungrab (msg->time);
3247
3248       if (k_grab_window == window)
3249         gdk_keyboard_ungrab (msg->time);
3250
3251       return_val = window != NULL && !GDK_WINDOW_DESTROYED (window);
3252
3253       if ((window != NULL) && (_gdk_root_window != msg->hwnd))
3254         gdk_window_destroy_notify (window);
3255
3256       break;
3257
3258 #ifdef HAVE_WINTAB
3259       /* Handle WINTAB events here, as we know that gdkinput.c will
3260        * use the fixed WT_DEFBASE as lcMsgBase, and we thus can use the
3261        * constants as case labels.
3262        */
3263     case WT_PACKET:
3264       GDK_NOTE (EVENTS, g_print ("WT_PACKET: %p %d %#lx\n",
3265                                  msg->hwnd, msg->wParam, msg->lParam));
3266       goto wintab;
3267       
3268     case WT_CSRCHANGE:
3269       GDK_NOTE (EVENTS, g_print ("WT_CSRCHANGE: %p %d %#lx\n",
3270                                  msg->hwnd, msg->wParam, msg->lParam));
3271       goto wintab;
3272       
3273     case WT_PROXIMITY:
3274       GDK_NOTE (EVENTS, g_print ("WT_PROXIMITY: %p %#x %d %d\n",
3275                                  msg->hwnd, msg->wParam,
3276                                  LOWORD (msg->lParam),
3277                                  HIWORD (msg->lParam)));
3278       /* Fall through */
3279     wintab:
3280       event->any.window = window;
3281       return_val = _gdk_input_other_event (event, msg, window);
3282       break;
3283 #endif
3284
3285     default:
3286       GDK_NOTE (EVENTS, g_print ("%s: %p %#x %#lx\n",
3287                                  _gdk_win32_message_to_string (msg->message),
3288                                  msg->hwnd, msg->wParam, msg->lParam));
3289     }
3290
3291 done:
3292
3293   if (return_val)
3294     {
3295       if (event->any.window)
3296         gdk_drawable_ref (event->any.window);
3297       if (((event->any.type == GDK_ENTER_NOTIFY) ||
3298            (event->any.type == GDK_LEAVE_NOTIFY)) &&
3299           (event->crossing.subwindow != NULL))
3300         gdk_drawable_ref (event->crossing.subwindow);
3301
3302       GDK_NOTE (EVENTS, print_event (event));
3303     }
3304   else
3305     {
3306       /* Mark this event as having no resources to be freed */
3307       event->any.window = NULL;
3308       event->any.type = GDK_NOTHING;
3309     }
3310
3311   if (window)
3312     gdk_drawable_unref (window);
3313   
3314   return return_val;
3315 }
3316
3317 void
3318 _gdk_events_queue (GdkDisplay *display)
3319 {
3320   MSG msg;
3321   GdkEvent *event;
3322   GList *node;
3323
3324   while (!_gdk_event_queue_find_first (display)
3325          && PeekMessage (&msg, NULL, 0, 0, PM_REMOVE))
3326     {
3327 #ifndef HAVE_DIMM_H
3328       TranslateMessage (&msg);
3329 #else
3330       if (active_imm_msgpump_owner == NULL
3331           || (active_imm_msgpump_owner->lpVtbl->OnTranslateMessage) (active_imm_msgpump_owner, &msg) != S_OK)
3332         TranslateMessage (&msg);
3333 #endif
3334
3335       DispatchMessage (&msg);
3336     }
3337 }
3338
3339 static gboolean
3340 gdk_event_prepare (GSource *source,
3341                    gint    *timeout)
3342 {
3343   MSG msg;
3344   gboolean retval;
3345   GdkDisplay *display = gdk_display_get_default ();
3346   
3347   GDK_THREADS_ENTER ();
3348
3349   *timeout = -1;
3350
3351   retval = (_gdk_event_queue_find_first (display) != NULL)
3352             || PeekMessage (&msg, NULL, 0, 0, PM_NOREMOVE);
3353
3354   GDK_THREADS_LEAVE ();
3355
3356   return retval;
3357 }
3358
3359 static gboolean
3360 gdk_event_check (GSource *source)
3361 {
3362   MSG msg;
3363   gboolean retval;
3364   GdkDisplay *display = gdk_display_get_default ();
3365   
3366   GDK_THREADS_ENTER ();
3367
3368   if (event_poll_fd.revents & G_IO_IN)
3369     retval = (_gdk_event_queue_find_first (display) != NULL)
3370               || PeekMessage (&msg, NULL, 0, 0, PM_NOREMOVE);
3371   else
3372     retval = FALSE;
3373
3374   GDK_THREADS_LEAVE ();
3375
3376   return retval;
3377 }
3378
3379 static gboolean
3380 gdk_event_dispatch (GSource     *source,
3381                     GSourceFunc  callback,
3382                     gpointer     user_data)
3383 {
3384   GdkEvent *event;
3385   GdkDisplay *display = gdk_display_get_default ();
3386  
3387   GDK_THREADS_ENTER ();
3388
3389   _gdk_events_queue (display);
3390   event = _gdk_event_unqueue (display);
3391
3392   if (event)
3393     {
3394       if (_gdk_event_func)
3395         (*_gdk_event_func) (event, _gdk_event_data);
3396       
3397       gdk_event_free (event);
3398     }
3399   
3400   GDK_THREADS_LEAVE ();
3401
3402   return TRUE;
3403 }
3404
3405 /* Sends a ClientMessage to all toplevel client windows */
3406 gboolean
3407 gdk_event_send_client_message_for_display (GdkDisplay     *display,
3408                                            GdkEvent       *event, 
3409                                            GdkNativeWindow winid)
3410 {
3411   /* XXX */
3412   return FALSE;
3413 }
3414
3415 void
3416 gdk_screen_broadcast_client_message (GdkScreen *screen, 
3417                                      GdkEvent  *event)
3418 {
3419   /* XXX */
3420 }
3421
3422 void
3423 gdk_flush (void)
3424 {
3425 #if 0
3426   MSG msg;
3427
3428   /* Process all messages currently available */
3429   while (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE))
3430     {
3431       TranslateMessage (&msg);
3432       DispatchMessage (&msg);
3433     }
3434 #endif
3435
3436   GdiFlush ();
3437 }
3438
3439 void
3440 gdk_display_sync (GdkDisplay * display)
3441 {
3442   MSG msg;
3443
3444   g_return_if_fail (display == gdk_display_get_default ());
3445
3446   /* Process all messages currently available */
3447   while (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE))
3448     {
3449       TranslateMessage (&msg);
3450       DispatchMessage (&msg);
3451     }
3452 }