]> Pileus Git - ~andy/gtk/blob - gdk/win32/gdkevents-win32.c
Broadway/Quartz/Win32: make event source prepare()/check() note paused status
[~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  * Copyright (C) 2001,2009 Hans Breuer
5  * Copyright (C) 2007-2009 Cody Russell
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library. If not, see <http://www.gnu.org/licenses/>.
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  * Update: a combination of TrackMouseEvent, GetCursorPos and 
36  * GetWindowPos can and is actually used to get rid of those
37  * pesky tooltips. It should be possible to use this for the
38  * whole ENTER/LEAVE NOTIFY handling but some platforms may
39  * not have TrackMouseEvent at all (?) --hb
40  */
41
42 #include "config.h"
43
44 #include <glib/gprintf.h>
45
46 #include "gdk.h"
47 #include "gdkdisplayprivate.h"
48 #include "gdkprivate-win32.h"
49 #include "gdkwin32.h"
50 #include "gdkkeysyms.h"
51 #include "gdkdevicemanager-win32.h"
52 #include "gdkdeviceprivate.h"
53 #include "gdkdevice-wintab.h"
54 #include "gdkwin32dnd.h"
55 #include "gdkdndprivate.h"
56
57 #include <windowsx.h>
58
59 #ifdef G_WITH_CYGWIN
60 #include <fcntl.h>
61 #include <errno.h>
62 #endif
63
64 #include <objbase.h>
65
66 #include <imm.h>
67
68 #ifndef XBUTTON1
69 #define XBUTTON1 1
70 #define XBUTTON2 2
71 #endif
72
73 #ifndef VK_XBUTTON1
74 #define VK_XBUTTON1 5
75 #define VK_XBUTTON2 6
76 #endif
77
78 #ifndef MK_XBUTTON1
79 #define MK_XBUTTON1 32
80 #define MK_XBUTTON2 64
81 #endif
82
83 /* Undefined flags: */
84 #define SWP_NOCLIENTSIZE 0x0800
85 #define SWP_NOCLIENTMOVE 0x1000
86 #define SWP_STATECHANGED 0x8000
87 /* 
88  * Private function declarations
89  */
90
91 #define SYNAPSIS_ICON_WINDOW_CLASS "SynTrackCursorWindowClass"
92
93 static gboolean gdk_event_translate (MSG        *msg,
94                                      gint       *ret_valp);
95 static void     handle_wm_paint     (MSG        *msg,
96                                      GdkWindow  *window,
97                                      gboolean    return_exposes,
98                                      GdkEvent  **event);
99
100 static gboolean gdk_event_prepare  (GSource     *source,
101                                     gint        *timeout);
102 static gboolean gdk_event_check    (GSource     *source);
103 static gboolean gdk_event_dispatch (GSource     *source,
104                                     GSourceFunc  callback,
105                                     gpointer     user_data);
106
107 /* Private variable declarations
108  */
109
110 static GList *client_filters;   /* Filters for client messages */
111 extern gint       _gdk_input_ignore_core;
112
113 HCURSOR _gdk_win32_grab_cursor;
114
115 static GSourceFuncs event_funcs = {
116   gdk_event_prepare,
117   gdk_event_check,
118   gdk_event_dispatch,
119   NULL
120 };
121
122 GPollFD event_poll_fd;
123
124 static GdkWindow *mouse_window = NULL;
125 static GdkWindow *mouse_window_ignored_leave = NULL;
126 static gint current_x, current_y;
127 static gint current_root_x, current_root_y;
128 static UINT client_message;
129
130 static UINT got_gdk_events_message;
131 static HWND modal_win32_dialog = NULL;
132
133 #if 0
134 static HKL latin_locale = NULL;
135 #endif
136
137 static gboolean in_ime_composition = FALSE;
138 static UINT     modal_timer;
139 static UINT     sync_timer = 0;
140
141 static int debug_indent = 0;
142
143 static void
144 assign_object (gpointer lhsp,
145                gpointer rhs)
146 {
147   if (*(gpointer *)lhsp != rhs)
148     {
149       if (*(gpointer *)lhsp != NULL)
150         g_object_unref (*(gpointer *)lhsp);
151       *(gpointer *)lhsp = rhs;
152       if (rhs != NULL)
153         g_object_ref (rhs);
154     }
155 }
156
157 static void
158 track_mouse_event (DWORD dwFlags,
159                    HWND  hwnd)
160 {
161   TRACKMOUSEEVENT tme;
162
163   tme.cbSize = sizeof(TRACKMOUSEEVENT);
164   tme.dwFlags = dwFlags;
165   tme.hwndTrack = hwnd;
166   tme.dwHoverTime = HOVER_DEFAULT; /* not used */
167
168   if (!TrackMouseEvent (&tme))
169     WIN32_API_FAILED ("TrackMouseEvent");
170   else if (dwFlags == TME_LEAVE)
171     GDK_NOTE (EVENTS, g_print(" (TrackMouseEvent %p)", hwnd));
172   else if (dwFlags == TME_CANCEL)
173     GDK_NOTE (EVENTS, g_print(" (cancel TrackMouseEvent %p)", hwnd));
174 }
175
176 gulong
177 _gdk_win32_get_next_tick (gulong suggested_tick)
178 {
179   static gulong cur_tick = 0;
180
181   if (suggested_tick == 0)
182     suggested_tick = GetTickCount ();
183   if (suggested_tick <= cur_tick)
184     return cur_tick;
185   else
186     return cur_tick = suggested_tick;
187 }
188
189 static void
190 generate_focus_event (GdkDeviceManager *device_manager,
191                       GdkWindow        *window,
192                       gboolean          in)
193 {
194   GdkDevice *device;
195   GdkDevice *source_device;
196   GdkEvent *event;
197
198   device = GDK_DEVICE_MANAGER_WIN32 (device_manager)->core_keyboard;
199   source_device = GDK_DEVICE_MANAGER_WIN32 (device_manager)->system_keyboard;
200
201   event = gdk_event_new (GDK_FOCUS_CHANGE);
202   event->focus_change.window = window;
203   event->focus_change.in = in;
204   gdk_event_set_device (event, device);
205   gdk_event_set_source_device (event, source_device);
206
207   _gdk_win32_append_event (event);
208 }
209
210 static void
211 generate_grab_broken_event (GdkDeviceManager *device_manager,
212                             GdkWindow        *window,
213                             gboolean          keyboard,
214                             GdkWindow        *grab_window)
215 {
216   GdkEvent *event = gdk_event_new (GDK_GRAB_BROKEN);
217   GdkDevice *device;
218   GdkDevice *source_device;
219
220   if (keyboard)
221     {
222       device = GDK_DEVICE_MANAGER_WIN32 (device_manager)->core_keyboard;
223       source_device = GDK_DEVICE_MANAGER_WIN32 (device_manager)->system_keyboard;
224     }
225   else
226     {
227       device = GDK_DEVICE_MANAGER_WIN32 (device_manager)->core_pointer;
228       source_device = GDK_DEVICE_MANAGER_WIN32 (device_manager)->system_pointer;
229     }
230
231   event->grab_broken.window = window;
232   event->grab_broken.send_event = 0;
233   event->grab_broken.keyboard = keyboard;
234   event->grab_broken.implicit = FALSE;
235   event->grab_broken.grab_window = grab_window;
236   gdk_event_set_device (event, device);
237   gdk_event_set_source_device (event, device);
238
239   _gdk_win32_append_event (event);
240 }
241
242 static LRESULT 
243 inner_window_procedure (HWND   hwnd,
244                         UINT   message,
245                         WPARAM wparam,
246                         LPARAM lparam)
247 {
248   MSG msg;
249   DWORD pos;
250   gint ret_val = 0;
251
252   msg.hwnd = hwnd;
253   msg.message = message;
254   msg.wParam = wparam;
255   msg.lParam = lparam;
256   msg.time = _gdk_win32_get_next_tick (0);
257   pos = GetMessagePos ();
258   msg.pt.x = GET_X_LPARAM (pos);
259   msg.pt.y = GET_Y_LPARAM (pos);
260
261   if (gdk_event_translate (&msg, &ret_val))
262     {
263       /* If gdk_event_translate() returns TRUE, we return ret_val from
264        * the window procedure.
265        */
266       if (modal_win32_dialog)
267         PostMessageW (modal_win32_dialog, got_gdk_events_message,
268                       (WPARAM) 1, 0);
269       return ret_val;
270     }
271   else
272     {
273       /* Otherwise call DefWindowProcW(). */
274       GDK_NOTE (EVENTS, g_print (" DefWindowProcW"));
275       return DefWindowProcW (hwnd, message, wparam, lparam);
276     }
277 }
278
279 LRESULT CALLBACK
280 _gdk_win32_window_procedure (HWND   hwnd,
281                              UINT   message,
282                              WPARAM wparam,
283                              LPARAM lparam)
284 {
285   LRESULT retval;
286
287   GDK_NOTE (EVENTS, g_print ("%s%*s%s %p",
288                              (debug_indent > 0 ? "\n" : ""),
289                              debug_indent, "", 
290                              _gdk_win32_message_to_string (message), hwnd));
291   debug_indent += 2;
292   retval = inner_window_procedure (hwnd, message, wparam, lparam);
293   debug_indent -= 2;
294
295   GDK_NOTE (EVENTS, g_print (" => %I64d%s", (gint64) retval, (debug_indent == 0 ? "\n" : "")));
296
297   return retval;
298 }
299
300 void 
301 _gdk_events_init (void)
302 {
303   GSource *source;
304
305 #if 0
306   int i, j, n;
307
308   /* List of languages that use a latin keyboard. Somewhat sorted in
309    * "order of least surprise", in case we have to load one of them if
310    * the user only has arabic loaded, for instance.
311    */
312   static int latin_languages[] = {
313     LANG_ENGLISH,
314     LANG_SPANISH,
315     LANG_PORTUGUESE,
316     LANG_FRENCH,
317     LANG_GERMAN,
318     /* Rest in numeric order */
319     LANG_CZECH,
320     LANG_DANISH,
321     LANG_FINNISH,
322     LANG_HUNGARIAN,
323     LANG_ICELANDIC,
324     LANG_ITALIAN,
325     LANG_DUTCH,
326     LANG_NORWEGIAN,
327     LANG_POLISH,
328     LANG_ROMANIAN,
329     LANG_SLOVAK,
330     LANG_ALBANIAN,
331     LANG_SWEDISH,
332     LANG_TURKISH,
333     LANG_INDONESIAN,
334     LANG_SLOVENIAN,
335     LANG_ESTONIAN,
336     LANG_LATVIAN,
337     LANG_LITHUANIAN,
338     LANG_VIETNAMESE,
339     LANG_AFRIKAANS,
340     LANG_FAEROESE
341 #ifdef LANG_SWAHILI
342    ,LANG_SWAHILI
343 #endif
344   };
345 #endif
346
347   client_message = RegisterWindowMessage ("GDK_WIN32_CLIENT_MESSAGE");
348   got_gdk_events_message = RegisterWindowMessage ("GDK_WIN32_GOT_EVENTS");
349
350 #if 0
351   /* Check if we have some input locale identifier loaded that uses a
352    * latin keyboard, to be able to get the virtual-key code for the
353    * latin characters corresponding to ASCII control characters.
354    */
355   if ((n = GetKeyboardLayoutList (0, NULL)) == 0)
356     WIN32_API_FAILED ("GetKeyboardLayoutList");
357   else
358     {
359       HKL *hkl_list = g_new (HKL, n);
360       if (GetKeyboardLayoutList (n, hkl_list) == 0)
361         WIN32_API_FAILED ("GetKeyboardLayoutList");
362       else
363         {
364           for (i = 0; latin_locale == NULL && i < n; i++)
365             for (j = 0; j < G_N_ELEMENTS (latin_languages); j++)
366               if (PRIMARYLANGID (LOWORD (hkl_list[i])) == latin_languages[j])
367                 {
368                   latin_locale = hkl_list [i];
369                   break;
370                 }
371         }
372       g_free (hkl_list);
373     }
374
375   if (latin_locale == NULL)
376     {
377       /* Try to load a keyboard layout with latin characters then.
378        */
379       i = 0;
380       while (latin_locale == NULL && i < G_N_ELEMENTS (latin_languages))
381         {
382           char id[9];
383           g_sprintf (id, "%08x", MAKELANGID (latin_languages[i++], SUBLANG_DEFAULT));
384           latin_locale = LoadKeyboardLayout (id, KLF_NOTELLSHELL|KLF_SUBSTITUTE_OK);
385         }
386     }
387
388   GDK_NOTE (EVENTS, g_print ("latin_locale = %08x\n", (guint) latin_locale));
389 #endif
390
391   source = g_source_new (&event_funcs, sizeof (GSource));
392   g_source_set_name (source, "GDK Win32 event source"); 
393   g_source_set_priority (source, GDK_PRIORITY_EVENTS);
394
395 #ifdef G_WITH_CYGWIN
396   event_poll_fd.fd = open ("/dev/windows", O_RDONLY);
397   if (event_poll_fd.fd == -1)
398     g_error ("can't open \"/dev/windows\": %s", g_strerror (errno));
399 #else
400   event_poll_fd.fd = G_WIN32_MSG_HANDLE;
401 #endif
402   event_poll_fd.events = G_IO_IN;
403   
404   g_source_add_poll (source, &event_poll_fd);
405   g_source_set_can_recurse (source, TRUE);
406   g_source_attach (source, NULL);
407 }
408
409 gboolean
410 _gdk_win32_display_has_pending (GdkDisplay *display)
411 {
412   return (_gdk_event_queue_find_first (display) ||
413           (modal_win32_dialog == NULL &&
414            GetQueueStatus (QS_ALLINPUT) != 0));
415 }
416
417 #if 0 /* Unused, but might be useful to re-introduce in some debugging output? */
418
419 static char *
420 event_mask_string (GdkEventMask mask)
421 {
422   static char bfr[500];
423   char *p = bfr;
424
425   *p = '\0';
426 #define BIT(x) \
427   if (mask & GDK_##x##_MASK) \
428     p += g_sprintf (p, "%s" #x, (p > bfr ? " " : ""))
429   BIT (EXPOSURE);
430   BIT (POINTER_MOTION);
431   BIT (POINTER_MOTION_HINT);
432   BIT (BUTTON_MOTION);
433   BIT (BUTTON1_MOTION);
434   BIT (BUTTON2_MOTION);
435   BIT (BUTTON3_MOTION);
436   BIT (BUTTON_PRESS);
437   BIT (BUTTON_RELEASE);
438   BIT (KEY_PRESS);
439   BIT (KEY_RELEASE);
440   BIT (ENTER_NOTIFY);
441   BIT (LEAVE_NOTIFY);
442   BIT (FOCUS_CHANGE);
443   BIT (STRUCTURE);
444   BIT (PROPERTY_CHANGE);
445   BIT (VISIBILITY_NOTIFY);
446   BIT (PROXIMITY_IN);
447   BIT (PROXIMITY_OUT);
448   BIT (SUBSTRUCTURE);
449   BIT (SCROLL);
450 #undef BIT
451
452   return bfr;
453 }
454
455 #endif
456
457 static GdkWindow *
458 find_window_for_mouse_event (GdkWindow* reported_window,
459                              MSG*       msg)
460 {
461   POINT pt;
462   GdkDeviceManagerWin32 *device_manager;
463   GdkWindow *event_window;
464   HWND hwnd;
465   RECT rect;
466   GdkDeviceGrabInfo *grab;
467
468   device_manager = GDK_DEVICE_MANAGER_WIN32 (gdk_display_get_device_manager (_gdk_display));
469
470   grab = _gdk_display_get_last_device_grab (_gdk_display, device_manager->core_pointer);
471   if (grab == NULL)
472     return reported_window;
473
474   pt = msg->pt;
475
476   if (!grab->owner_events)
477     event_window = grab->native_window;
478   else
479     {
480       event_window = NULL;
481       hwnd = WindowFromPoint (pt);
482       if (hwnd != NULL)
483         {
484           POINT client_pt = pt;
485
486           ScreenToClient (hwnd, &client_pt);
487           GetClientRect (hwnd, &rect);
488           if (PtInRect (&rect, client_pt))
489             event_window = gdk_win32_handle_table_lookup (hwnd);
490         }
491       if (event_window == NULL)
492         event_window = grab->native_window;
493     }
494
495   /* need to also adjust the coordinates to the new window */
496   ScreenToClient (GDK_WINDOW_HWND (event_window), &pt);
497
498   /* ATTENTION: need to update client coords */
499   msg->lParam = MAKELPARAM (pt.x, pt.y);
500
501   return event_window;
502 }
503
504 static void
505 build_key_event_state (GdkEvent *event,
506                        BYTE     *key_state)
507 {
508   event->key.state = 0;
509
510   if (key_state[VK_SHIFT] & 0x80)
511     event->key.state |= GDK_SHIFT_MASK;
512
513   if (key_state[VK_CAPITAL] & 0x01)
514     event->key.state |= GDK_LOCK_MASK;
515
516   if (key_state[VK_LBUTTON] & 0x80)
517     event->key.state |= GDK_BUTTON1_MASK;
518   if (key_state[VK_MBUTTON] & 0x80)
519     event->key.state |= GDK_BUTTON2_MASK;
520   if (key_state[VK_RBUTTON] & 0x80)
521     event->key.state |= GDK_BUTTON3_MASK;
522   if (key_state[VK_XBUTTON1] & 0x80)
523     event->key.state |= GDK_BUTTON4_MASK;
524   if (key_state[VK_XBUTTON2] & 0x80)
525     event->key.state |= GDK_BUTTON5_MASK;
526
527   if (_gdk_keyboard_has_altgr &&
528       (key_state[VK_LCONTROL] & 0x80) &&
529       (key_state[VK_RMENU] & 0x80))
530     {
531       event->key.group = 1;
532       event->key.state |= GDK_MOD2_MASK;
533       if (key_state[VK_RCONTROL] & 0x80)
534         event->key.state |= GDK_CONTROL_MASK;
535       if (key_state[VK_LMENU] & 0x80)
536         event->key.state |= GDK_MOD1_MASK;
537     }
538   else
539     {
540       event->key.group = 0;
541       if (key_state[VK_CONTROL] & 0x80)
542         event->key.state |= GDK_CONTROL_MASK;
543       if (key_state[VK_MENU] & 0x80)
544         event->key.state |= GDK_MOD1_MASK;
545     }
546 }
547
548 static gint
549 build_pointer_event_state (MSG *msg)
550 {
551   gint state;
552   
553   state = 0;
554
555   if (msg->wParam & MK_CONTROL)
556     state |= GDK_CONTROL_MASK;
557
558   if ((msg->message != WM_LBUTTONDOWN &&
559        (msg->wParam & MK_LBUTTON)) ||
560       msg->message == WM_LBUTTONUP)
561     state |= GDK_BUTTON1_MASK;
562
563   if ((msg->message != WM_MBUTTONDOWN &&
564        (msg->wParam & MK_MBUTTON)) ||
565       msg->message == WM_MBUTTONUP)
566     state |= GDK_BUTTON2_MASK;
567
568   if ((msg->message != WM_RBUTTONDOWN &&
569        (msg->wParam & MK_RBUTTON)) ||
570       msg->message == WM_RBUTTONUP)
571     state |= GDK_BUTTON3_MASK;
572
573   if (((msg->message != WM_XBUTTONDOWN || HIWORD (msg->wParam) != XBUTTON1) &&
574        (msg->wParam & MK_XBUTTON1)) ||
575       (msg->message == WM_XBUTTONUP && HIWORD (msg->wParam) == XBUTTON1))
576     state |= GDK_BUTTON4_MASK;
577
578   if (((msg->message != WM_XBUTTONDOWN || HIWORD (msg->wParam) != XBUTTON2) &&
579        (msg->wParam & MK_XBUTTON2)) ||
580       (msg->message == WM_XBUTTONUP && HIWORD (msg->wParam) == XBUTTON2))
581     state |= GDK_BUTTON5_MASK;
582
583   if (msg->wParam & MK_SHIFT)
584     state |= GDK_SHIFT_MASK;
585
586   if (GetKeyState (VK_MENU) < 0)
587     state |= GDK_MOD1_MASK;
588
589   if (GetKeyState (VK_CAPITAL) & 0x1)
590     state |= GDK_LOCK_MASK;
591
592   return state;
593 }
594
595 static void
596 build_wm_ime_composition_event (GdkEvent *event,
597                                 MSG      *msg,
598                                 wchar_t   wc,
599                                 BYTE     *key_state)
600 {
601   event->key.time = _gdk_win32_get_next_tick (msg->time);
602   
603   build_key_event_state (event, key_state);
604
605   event->key.hardware_keycode = 0; /* FIXME: What should it be? */
606   event->key.string = NULL;
607   event->key.length = 0;
608   event->key.keyval = gdk_unicode_to_keyval (wc);
609 }
610
611 #ifdef G_ENABLE_DEBUG
612
613 static void
614 print_event_state (guint state)
615 {
616 #define CASE(bit) if (state & GDK_ ## bit ## _MASK) g_print (#bit " ");
617   CASE (SHIFT);
618   CASE (LOCK);
619   CASE (CONTROL);
620   CASE (MOD1);
621   CASE (MOD2);
622   CASE (MOD3);
623   CASE (MOD4);
624   CASE (MOD5);
625   CASE (BUTTON1);
626   CASE (BUTTON2);
627   CASE (BUTTON3);
628   CASE (BUTTON4);
629   CASE (BUTTON5);
630 #undef CASE
631 }
632
633 void
634 _gdk_win32_print_event (const GdkEvent *event)
635 {
636   gchar *escaped, *kvname;
637   gchar *selection_name, *target_name, *property_name;
638
639   g_print ("%s%*s===> ", (debug_indent > 0 ? "\n" : ""), debug_indent, "");
640   switch (event->any.type)
641     {
642 #define CASE(x) case x: g_print (#x); break;
643     CASE (GDK_NOTHING);
644     CASE (GDK_DELETE);
645     CASE (GDK_DESTROY);
646     CASE (GDK_EXPOSE);
647     CASE (GDK_MOTION_NOTIFY);
648     CASE (GDK_BUTTON_PRESS);
649     CASE (GDK_2BUTTON_PRESS);
650     CASE (GDK_3BUTTON_PRESS);
651     CASE (GDK_BUTTON_RELEASE);
652     CASE (GDK_KEY_PRESS);
653     CASE (GDK_KEY_RELEASE);
654     CASE (GDK_ENTER_NOTIFY);
655     CASE (GDK_LEAVE_NOTIFY);
656     CASE (GDK_FOCUS_CHANGE);
657     CASE (GDK_CONFIGURE);
658     CASE (GDK_MAP);
659     CASE (GDK_UNMAP);
660     CASE (GDK_PROPERTY_NOTIFY);
661     CASE (GDK_SELECTION_CLEAR);
662     CASE (GDK_SELECTION_REQUEST);
663     CASE (GDK_SELECTION_NOTIFY);
664     CASE (GDK_PROXIMITY_IN);
665     CASE (GDK_PROXIMITY_OUT);
666     CASE (GDK_DRAG_ENTER);
667     CASE (GDK_DRAG_LEAVE);
668     CASE (GDK_DRAG_MOTION);
669     CASE (GDK_DRAG_STATUS);
670     CASE (GDK_DROP_START);
671     CASE (GDK_DROP_FINISHED);
672     CASE (GDK_CLIENT_EVENT);
673     CASE (GDK_VISIBILITY_NOTIFY);
674     CASE (GDK_SCROLL);
675     CASE (GDK_WINDOW_STATE);
676     CASE (GDK_SETTING);
677     CASE (GDK_OWNER_CHANGE);
678     CASE (GDK_GRAB_BROKEN);
679 #undef CASE
680     default: g_assert_not_reached ();
681     }
682
683   g_print (" %p ", event->any.window ? GDK_WINDOW_HWND (event->any.window) : NULL);
684
685   switch (event->any.type)
686     {
687     case GDK_EXPOSE:
688       g_print ("%s %d",
689                _gdk_win32_gdkrectangle_to_string (&event->expose.area),
690                event->expose.count);
691       break;
692     case GDK_MOTION_NOTIFY:
693       g_print ("(%.4g,%.4g) (%.4g,%.4g) %s",
694                event->motion.x, event->motion.y,
695                event->motion.x_root, event->motion.y_root,
696                event->motion.is_hint ? "HINT " : "");
697       print_event_state (event->motion.state);
698       break;
699     case GDK_BUTTON_PRESS:
700     case GDK_2BUTTON_PRESS:
701     case GDK_3BUTTON_PRESS:
702     case GDK_BUTTON_RELEASE:
703       g_print ("%d (%.4g,%.4g) (%.4g,%.4g) ",
704                event->button.button,
705                event->button.x, event->button.y,
706                event->button.x_root, event->button.y_root);
707       print_event_state (event->button.state);
708       break;
709     case GDK_KEY_PRESS: 
710     case GDK_KEY_RELEASE:
711       if (event->key.length == 0)
712         escaped = g_strdup ("");
713       else
714         escaped = g_strescape (event->key.string, NULL);
715       kvname = gdk_keyval_name (event->key.keyval);
716       g_print ("%#.02x group:%d %s %d:\"%s\" ",
717                event->key.hardware_keycode, event->key.group,
718                (kvname ? kvname : "??"),
719                event->key.length,
720                escaped);
721       g_free (escaped);
722       print_event_state (event->key.state);
723       break;
724     case GDK_ENTER_NOTIFY:
725     case GDK_LEAVE_NOTIFY:
726       g_print ("%p (%.4g,%.4g) (%.4g,%.4g) %s %s%s",
727                event->crossing.subwindow == NULL ? NULL : GDK_WINDOW_HWND (event->crossing.subwindow),
728                event->crossing.x, event->crossing.y,
729                event->crossing.x_root, event->crossing.y_root,
730                (event->crossing.mode == GDK_CROSSING_NORMAL ? "NORMAL" :
731                 (event->crossing.mode == GDK_CROSSING_GRAB ? "GRAB" :
732                  (event->crossing.mode == GDK_CROSSING_UNGRAB ? "UNGRAB" :
733                   "???"))),
734                (event->crossing.detail == GDK_NOTIFY_ANCESTOR ? "ANCESTOR" :
735                 (event->crossing.detail == GDK_NOTIFY_VIRTUAL ? "VIRTUAL" :
736                  (event->crossing.detail == GDK_NOTIFY_INFERIOR ? "INFERIOR" :
737                   (event->crossing.detail == GDK_NOTIFY_NONLINEAR ? "NONLINEAR" :
738                    (event->crossing.detail == GDK_NOTIFY_NONLINEAR_VIRTUAL ? "NONLINEAR_VIRTUAL" :
739                     (event->crossing.detail == GDK_NOTIFY_UNKNOWN ? "UNKNOWN" :
740                      "???")))))),
741                event->crossing.focus ? " FOCUS" : "");
742       print_event_state (event->crossing.state);
743       break;
744     case GDK_FOCUS_CHANGE:
745       g_print ("%s", (event->focus_change.in ? "IN" : "OUT"));
746       break;
747     case GDK_CONFIGURE:
748       g_print ("x:%d y:%d w:%d h:%d",
749                event->configure.x, event->configure.y,
750                event->configure.width, event->configure.height);
751       break;
752     case GDK_SELECTION_CLEAR:
753     case GDK_SELECTION_REQUEST:
754     case GDK_SELECTION_NOTIFY:
755       selection_name = gdk_atom_name (event->selection.selection);
756       target_name = gdk_atom_name (event->selection.target);
757       property_name = gdk_atom_name (event->selection.property);
758       g_print ("sel:%s tgt:%s prop:%s",
759                selection_name, target_name, property_name);
760       g_free (selection_name);
761       g_free (target_name);
762       g_free (property_name);
763       break;
764     case GDK_DRAG_ENTER:
765     case GDK_DRAG_LEAVE:
766     case GDK_DRAG_MOTION:
767     case GDK_DRAG_STATUS:
768     case GDK_DROP_START:
769     case GDK_DROP_FINISHED:
770       if (event->dnd.context != NULL)
771         g_print ("ctx:%p: %s %s src:%p dest:%p",
772                  event->dnd.context,
773                  _gdk_win32_drag_protocol_to_string (event->dnd.context->protocol),
774                  event->dnd.context->is_source ? "SOURCE" : "DEST",
775                  event->dnd.context->source_window == NULL ? NULL : GDK_WINDOW_HWND (event->dnd.context->source_window),
776                  event->dnd.context->dest_window == NULL ? NULL : GDK_WINDOW_HWND (event->dnd.context->dest_window));
777       break;
778     case GDK_CLIENT_EVENT:
779       /* no more GdkEventClient */
780       break;
781     case GDK_SCROLL:
782       g_print ("(%.4g,%.4g) (%.4g,%.4g) %s ",
783                event->scroll.x, event->scroll.y,
784                event->scroll.x_root, event->scroll.y_root,
785                (event->scroll.direction == GDK_SCROLL_UP ? "UP" :
786                 (event->scroll.direction == GDK_SCROLL_DOWN ? "DOWN" :
787                  (event->scroll.direction == GDK_SCROLL_LEFT ? "LEFT" :
788                   (event->scroll.direction == GDK_SCROLL_RIGHT ? "RIGHT" :
789                    "???")))));
790       print_event_state (event->scroll.state);
791       break;
792     case GDK_WINDOW_STATE:
793       g_print ("%s: %s",
794                _gdk_win32_window_state_to_string (event->window_state.changed_mask),
795                _gdk_win32_window_state_to_string (event->window_state.new_window_state));
796     case GDK_SETTING:
797       g_print ("%s: %s",
798                (event->setting.action == GDK_SETTING_ACTION_NEW ? "NEW" :
799                 (event->setting.action == GDK_SETTING_ACTION_CHANGED ? "CHANGED" :
800                  (event->setting.action == GDK_SETTING_ACTION_DELETED ? "DELETED" :
801                   "???"))),
802                (event->setting.name ? event->setting.name : "NULL"));
803     case GDK_GRAB_BROKEN:
804       g_print ("%s %s %p",
805                (event->grab_broken.keyboard ? "KEYBOARD" : "POINTER"),
806                (event->grab_broken.implicit ? "IMPLICIT" : "EXPLICIT"),
807                (event->grab_broken.grab_window ? GDK_WINDOW_HWND (event->grab_broken.grab_window) : 0));
808     default:
809       /* Nothing */
810       break;
811     }  
812   g_print ("%s", (debug_indent == 0 ? "\n" : "")); 
813 }
814
815 static char *
816 decode_key_lparam (LPARAM lParam)
817 {
818   static char buf[100];
819   char *p = buf;
820
821   if (HIWORD (lParam) & KF_UP)
822     p += g_sprintf (p, "KF_UP ");
823   if (HIWORD (lParam) & KF_REPEAT)
824     p += g_sprintf (p, "KF_REPEAT ");
825   if (HIWORD (lParam) & KF_ALTDOWN)
826     p += g_sprintf (p, "KF_ALTDOWN ");
827   if (HIWORD (lParam) & KF_EXTENDED)
828     p += g_sprintf (p, "KF_EXTENDED ");
829   p += g_sprintf (p, "sc:%d rep:%d", LOBYTE (HIWORD (lParam)), LOWORD (lParam));
830
831   return buf;
832 }
833
834 #endif
835
836 static void
837 fixup_event (GdkEvent *event)
838 {
839   if (event->any.window)
840     g_object_ref (event->any.window);
841   if (((event->any.type == GDK_ENTER_NOTIFY) ||
842        (event->any.type == GDK_LEAVE_NOTIFY)) &&
843       (event->crossing.subwindow != NULL))
844     g_object_ref (event->crossing.subwindow);
845   if (((event->any.type == GDK_SELECTION_CLEAR) ||
846        (event->any.type == GDK_SELECTION_NOTIFY) ||
847        (event->any.type == GDK_SELECTION_REQUEST)) &&
848       (event->selection.requestor != NULL))
849     g_object_ref (event->selection.requestor);
850   if ((event->any.type == GDK_OWNER_CHANGE) &&
851       (event->owner_change.owner != NULL))
852     g_object_ref (event->owner_change.owner);
853   event->any.send_event = InSendMessage (); 
854 }
855
856 void
857 _gdk_win32_append_event (GdkEvent *event)
858 {
859   GList *link;
860   
861   fixup_event (event);
862 #if 1
863   link = _gdk_event_queue_append (_gdk_display, event);
864   GDK_NOTE (EVENTS, _gdk_win32_print_event (event));
865   /* event morphing, the passed in may not be valid afterwards */
866   _gdk_windowing_got_event (_gdk_display, link, event, 0);
867 #else
868   _gdk_event_queue_append (_gdk_display, event);
869   GDK_NOTE (EVENTS, _gdk_win32_print_event (event));
870 #endif
871 }
872
873 static void
874 fill_key_event_string (GdkEvent *event)
875 {
876   gunichar c;
877   gchar buf[256];
878
879   /* Fill in event->string crudely, since various programs
880    * depend on it.
881    */
882   
883   c = 0;
884   if (event->key.keyval != GDK_KEY_VoidSymbol)
885     c = gdk_keyval_to_unicode (event->key.keyval);
886
887   if (c)
888     {
889       gsize bytes_written;
890       gint len;
891       
892       /* Apply the control key - Taken from Xlib
893        */
894       if (event->key.state & GDK_CONTROL_MASK)
895         {
896           if ((c >= '@' && c < '\177') || c == ' ')
897             c &= 0x1F;
898           else if (c == '2')
899             {
900               event->key.string = g_memdup ("\0\0", 2);
901               event->key.length = 1;
902               return;
903             }
904           else if (c >= '3' && c <= '7')
905             c -= ('3' - '\033');
906           else if (c == '8')
907             c = '\177';
908           else if (c == '/')
909             c = '_' & 0x1F;
910         }
911       
912       len = g_unichar_to_utf8 (c, buf);
913       buf[len] = '\0';
914           
915       event->key.string = g_locale_from_utf8 (buf, len,
916                                               NULL, &bytes_written,
917                                               NULL);
918       if (event->key.string)
919         event->key.length = bytes_written;
920     }
921   else if (event->key.keyval == GDK_KEY_Escape)
922     {
923       event->key.length = 1;
924       event->key.string = g_strdup ("\033");
925     }
926   else if (event->key.keyval == GDK_KEY_Return ||
927            event->key.keyval == GDK_KEY_KP_Enter)
928     {
929       event->key.length = 1;
930       event->key.string = g_strdup ("\r");
931     }
932   
933   if (!event->key.string)
934     {
935       event->key.length = 0;
936       event->key.string = g_strdup ("");
937     }
938 }
939
940 static GdkFilterReturn
941 apply_event_filters (GdkWindow  *window,
942                      MSG        *msg,
943                      GList     **filters)
944 {
945   GdkFilterReturn result = GDK_FILTER_CONTINUE;
946   GdkEvent *event;
947   GList *node;
948   GList *tmp_list;
949
950   event = gdk_event_new (GDK_NOTHING);
951   if (window != NULL)
952     event->any.window = g_object_ref (window);
953   ((GdkEventPrivate *)event)->flags |= GDK_EVENT_PENDING;
954
955   /* I think GdkFilterFunc semantics require the passed-in event
956    * to already be in the queue. The filter func can generate
957    * more events and append them after it if it likes.
958    */
959   node = _gdk_event_queue_append (_gdk_display, event);
960   
961   tmp_list = *filters;
962   while (tmp_list)
963     {
964       GdkEventFilter *filter = (GdkEventFilter *) tmp_list->data;
965       GList *node;
966
967       if ((filter->flags & GDK_EVENT_FILTER_REMOVED) != 0)
968         {
969           tmp_list = tmp_list->next;
970           continue;
971         }
972
973       filter->ref_count++;
974       result = filter->function (msg, event, filter->data);
975
976       /* get the next node after running the function since the
977          function may add or remove a next node */
978       node = tmp_list;
979       tmp_list = tmp_list->next;
980
981       filter->ref_count--;
982       if (filter->ref_count == 0)
983         {
984           *filters = g_list_remove_link (*filters, node);
985           g_list_free_1 (node);
986           g_free (filter);
987         }
988
989       if (result !=  GDK_FILTER_CONTINUE)
990         break;
991     }
992
993   if (result == GDK_FILTER_CONTINUE || result == GDK_FILTER_REMOVE)
994     {
995       _gdk_event_queue_remove_link (_gdk_display, node);
996       g_list_free_1 (node);
997       gdk_event_free (event);
998     }
999   else /* GDK_FILTER_TRANSLATE */
1000     {
1001       ((GdkEventPrivate *)event)->flags &= ~GDK_EVENT_PENDING;
1002       fixup_event (event);
1003       GDK_NOTE (EVENTS, _gdk_win32_print_event (event));
1004     }
1005   return result;
1006 }
1007
1008 /*
1009  * On Windows, transient windows will not have their own taskbar entries.
1010  * Because of this, we must hide and restore groups of transients in both
1011  * directions.  That is, all transient children must be hidden or restored
1012  * with this window, but if this window's transient owner also has a
1013  * transient owner then this window's transient owner must be hidden/restored
1014  * with this one.  And etc, up the chain until we hit an ancestor that has no
1015  * transient owner.
1016  *
1017  * It would be a good idea if applications don't chain transient windows
1018  * together.  There's a limit to how much evil GTK can try to shield you
1019  * from.
1020  */
1021 static void
1022 show_window_recurse (GdkWindow *window, gboolean hide_window)
1023 {
1024   GdkWindowImplWin32 *impl = GDK_WINDOW_IMPL_WIN32 (window->impl);
1025   GSList *children = impl->transient_children;
1026   GdkWindow *child = NULL;
1027
1028   if (!impl->changing_state)
1029     {
1030       impl->changing_state = TRUE;
1031
1032       if (children != NULL)
1033         {
1034           while (children != NULL)
1035             {
1036               child = children->data;
1037               show_window_recurse (child, hide_window);
1038
1039               children = g_slist_next (children);
1040             }
1041         }
1042
1043       if (GDK_WINDOW_IS_MAPPED (window))
1044         {
1045           if (!hide_window)
1046             {
1047               if (gdk_window_get_state (window) & GDK_WINDOW_STATE_ICONIFIED)
1048                 {
1049                   if (gdk_window_get_state (window) & GDK_WINDOW_STATE_MAXIMIZED)
1050                     {
1051                       ShowWindow (GDK_WINDOW_HWND (window), SW_SHOWMAXIMIZED);
1052                     }
1053                   else
1054                     {
1055                       ShowWindow (GDK_WINDOW_HWND (window), SW_RESTORE);
1056                     }
1057                 }
1058             }
1059           else
1060             {
1061               ShowWindow (GDK_WINDOW_HWND (window), SW_MINIMIZE);
1062             }
1063         }
1064
1065       impl->changing_state = FALSE;
1066     }
1067 }
1068
1069 static void
1070 do_show_window (GdkWindow *window, gboolean hide_window)
1071 {
1072   GdkWindow *tmp_window = NULL;
1073   GdkWindowImplWin32 *tmp_impl = GDK_WINDOW_IMPL_WIN32 (window->impl);
1074
1075   if (!tmp_impl->changing_state)
1076     {
1077       /* Find the top-level window in our transient chain. */
1078       while (tmp_impl->transient_owner != NULL)
1079         {
1080           tmp_window = tmp_impl->transient_owner;
1081           tmp_impl = GDK_WINDOW_IMPL_WIN32 (tmp_window->impl);
1082         }
1083
1084       /* If we couldn't find one, use the window provided. */
1085       if (tmp_window == NULL)
1086         {
1087           tmp_window = window;
1088         }
1089
1090       /* Recursively show/hide every window in the chain. */
1091       if (tmp_window != window)
1092         {
1093           show_window_recurse (tmp_window, hide_window);
1094         }
1095     }
1096 }
1097
1098 static void
1099 send_crossing_event (GdkDisplay                 *display,
1100                      GdkWindow                  *window,
1101                      GdkEventType                type,
1102                      GdkCrossingMode             mode,
1103                      GdkNotifyType               notify_type,
1104                      GdkWindow                  *subwindow,
1105                      POINT                      *screen_pt,
1106                      GdkModifierType             mask,
1107                      guint32                     time_)
1108 {
1109   GdkEvent *event;
1110   GdkDeviceGrabInfo *grab;
1111   GdkDeviceManagerWin32 *device_manager;
1112   POINT pt;
1113
1114   device_manager = GDK_DEVICE_MANAGER_WIN32 (gdk_display_get_device_manager (display));
1115
1116   grab = _gdk_display_has_device_grab (display, device_manager->core_pointer, 0);
1117
1118   if (grab != NULL &&
1119       !grab->owner_events &&
1120       mode != GDK_CROSSING_UNGRAB)
1121     {
1122       /* !owner_event => only report events wrt grab window, ignore rest */
1123       if ((GdkWindow *)window != grab->native_window)
1124         return;
1125     }
1126
1127   pt = *screen_pt;
1128   ScreenToClient (GDK_WINDOW_HWND (window), &pt);
1129   
1130   event = gdk_event_new (type);
1131   event->crossing.window = window;
1132   event->crossing.subwindow = subwindow;
1133   event->crossing.time = _gdk_win32_get_next_tick (time_);
1134   event->crossing.x = pt.x;
1135   event->crossing.y = pt.y;
1136   event->crossing.x_root = screen_pt->x + _gdk_offset_x;
1137   event->crossing.y_root = screen_pt->y + _gdk_offset_y;
1138   event->crossing.mode = mode;
1139   event->crossing.detail = notify_type;
1140   event->crossing.mode = mode;
1141   event->crossing.detail = notify_type;
1142   event->crossing.focus = FALSE;
1143   event->crossing.state = mask;
1144   gdk_event_set_device (event, device_manager->core_pointer);
1145   gdk_event_set_source_device (event, device_manager->system_pointer);
1146
1147   _gdk_win32_append_event (event);
1148 }
1149
1150 static GdkWindow *
1151 get_native_parent (GdkWindow *window)
1152 {
1153   if (window->parent != NULL)
1154     return window->parent->impl_window;
1155   return NULL;
1156 }
1157
1158 static GdkWindow *
1159 find_common_ancestor (GdkWindow *win1,
1160                       GdkWindow *win2)
1161 {
1162   GdkWindow *tmp;
1163   GList *path1 = NULL, *path2 = NULL;
1164   GList *list1, *list2;
1165
1166   tmp = win1;
1167   while (tmp != NULL && tmp->window_type != GDK_WINDOW_ROOT)
1168     {
1169       path1 = g_list_prepend (path1, tmp);
1170       tmp = get_native_parent (tmp);
1171     }
1172
1173   tmp = win2;
1174   while (tmp != NULL && tmp->window_type != GDK_WINDOW_ROOT)
1175     {
1176       path2 = g_list_prepend (path2, tmp);
1177       tmp = get_native_parent (tmp);
1178     }
1179
1180   list1 = path1;
1181   list2 = path2;
1182   tmp = NULL;
1183   while (list1 && list2 && (list1->data == list2->data))
1184     {
1185       tmp = (GdkWindow *)list1->data;
1186       list1 = g_list_next (list1);
1187       list2 = g_list_next (list2);
1188     }
1189   g_list_free (path1);
1190   g_list_free (path2);
1191
1192   return tmp;
1193 }
1194
1195 void
1196 synthesize_crossing_events (GdkDisplay                 *display,
1197                             GdkWindow                  *src,
1198                             GdkWindow                  *dest,
1199                             GdkCrossingMode             mode,
1200                             POINT                      *screen_pt,
1201                             GdkModifierType             mask,
1202                             guint32                     time_,
1203                             gboolean                    non_linear)
1204 {
1205   GdkWindow *c;
1206   GdkWindow *win, *last, *next;
1207   GList *path, *list;
1208   GdkWindow *a;
1209   GdkWindow *b;
1210   GdkNotifyType notify_type;
1211
1212   a = src;
1213   b = dest;
1214   if (a == b)
1215     return; /* No crossings generated between src and dest */
1216
1217   c = find_common_ancestor (a, b);
1218
1219   non_linear |= (c != a) && (c != b);
1220
1221   if (a) /* There might not be a source (i.e. if no previous pointer_in_window) */
1222     {
1223       /* Traverse up from a to (excluding) c sending leave events */
1224       if (non_linear)
1225         notify_type = GDK_NOTIFY_NONLINEAR;
1226       else if (c == a)
1227         notify_type = GDK_NOTIFY_INFERIOR;
1228       else
1229         notify_type = GDK_NOTIFY_ANCESTOR;
1230       send_crossing_event (display,
1231                            a, GDK_LEAVE_NOTIFY,
1232                            mode,
1233                            notify_type,
1234                            NULL,
1235                            screen_pt,
1236                            mask, time_);
1237
1238       if (c != a)
1239         {
1240           if (non_linear)
1241             notify_type = GDK_NOTIFY_NONLINEAR_VIRTUAL;
1242           else
1243             notify_type = GDK_NOTIFY_VIRTUAL;
1244
1245           last = a;
1246           win = get_native_parent (a);
1247           while (win != c && win->window_type != GDK_WINDOW_ROOT)
1248             {
1249               send_crossing_event (display,
1250                                    win, GDK_LEAVE_NOTIFY,
1251                                    mode,
1252                                    notify_type,
1253                                    (GdkWindow *)last,
1254                                    screen_pt,
1255                                    mask, time_);
1256
1257               last = win;
1258               win = get_native_parent (win);
1259             }
1260         }
1261     }
1262
1263   if (b) /* Might not be a dest, e.g. if we're moving out of the window */
1264     {
1265       /* Traverse down from c to b */
1266       if (c != b)
1267         {
1268           path = NULL;
1269           win = get_native_parent (b);
1270           while (win != c && win->window_type != GDK_WINDOW_ROOT)
1271             {
1272               path = g_list_prepend (path, win);
1273               win = get_native_parent (win);
1274             }
1275
1276           if (non_linear)
1277             notify_type = GDK_NOTIFY_NONLINEAR_VIRTUAL;
1278           else
1279             notify_type = GDK_NOTIFY_VIRTUAL;
1280
1281           list = path;
1282           while (list)
1283             {
1284               win = (GdkWindow *)list->data;
1285               list = g_list_next (list);
1286               if (list)
1287                 next = (GdkWindow *)list->data;
1288               else
1289                 next = b;
1290
1291               send_crossing_event (display,
1292                                    win, GDK_ENTER_NOTIFY,
1293                                    mode,
1294                                    notify_type,
1295                                    next,
1296                                    screen_pt,
1297                                    mask, time_);
1298             }
1299           g_list_free (path);
1300         }
1301
1302
1303       if (non_linear)
1304         notify_type = GDK_NOTIFY_NONLINEAR;
1305       else if (c == a)
1306         notify_type = GDK_NOTIFY_ANCESTOR;
1307       else
1308         notify_type = GDK_NOTIFY_INFERIOR;
1309
1310       send_crossing_event (display,
1311                            b, GDK_ENTER_NOTIFY,
1312                            mode,
1313                            notify_type,
1314                            NULL,
1315                            screen_pt,
1316                            mask, time_);
1317     }
1318 }
1319
1320 /* The check_extended flag controls whether to check if the windows want
1321  * events from extended input devices and if the message should be skipped
1322  * because an extended input device is active
1323  */
1324 static gboolean
1325 propagate (GdkWindow  **window,
1326            MSG         *msg,
1327            GdkWindow   *grab_window,
1328            gboolean     grab_owner_events,
1329            gint         grab_mask,
1330            gboolean   (*doesnt_want_it) (gint mask,
1331                                          MSG *msg))
1332 {
1333   if (grab_window != NULL && !grab_owner_events)
1334     {
1335       /* Event source is grabbed with owner_events FALSE */
1336
1337       if ((*doesnt_want_it) (grab_mask, msg))
1338         {
1339           GDK_NOTE (EVENTS, g_print (" (grabber doesn't want it)"));
1340           return FALSE;
1341         }
1342       else
1343         {
1344           GDK_NOTE (EVENTS, g_print (" (to grabber)"));
1345           assign_object (window, grab_window);
1346           return TRUE;
1347         }
1348     }
1349
1350   /* If we come here, we know that if grab_window != NULL then
1351    * grab_owner_events is TRUE
1352    */
1353   while (TRUE)
1354     {
1355       if ((*doesnt_want_it) ((*window)->event_mask, msg))
1356         {
1357           /* Owner doesn't want it, propagate to parent. */
1358           GdkWindow *parent = gdk_window_get_parent (*window);
1359           if (parent == _gdk_root || parent == NULL)
1360             {
1361               /* No parent; check if grabbed */
1362               if (grab_window != NULL)
1363                 {
1364                   /* Event source is grabbed with owner_events TRUE */
1365
1366                   if ((*doesnt_want_it) (grab_mask, msg))
1367                     {
1368                       /* Grabber doesn't want it either */
1369                       GDK_NOTE (EVENTS, g_print (" (grabber doesn't want it)"));
1370                       return FALSE;
1371                     }
1372                   else
1373                     {
1374                       /* Grabbed! */
1375                       GDK_NOTE (EVENTS, g_print (" (to grabber)"));
1376                       assign_object (window, grab_window);
1377                       return TRUE;
1378                     }
1379                 }
1380               else
1381                 {
1382                   GDK_NOTE (EVENTS, g_print (" (undelivered)"));
1383                   return FALSE;
1384                 }
1385             }
1386           else
1387             {
1388               assign_object (window, parent);
1389               /* The only branch where we actually continue the loop */
1390             }
1391         }
1392       else
1393         return TRUE;
1394     }
1395 }
1396
1397 static gboolean
1398 doesnt_want_key (gint mask,
1399                  MSG *msg)
1400 {
1401   return (((msg->message == WM_KEYUP || msg->message == WM_SYSKEYUP) &&
1402            !(mask & GDK_KEY_RELEASE_MASK)) ||
1403           ((msg->message == WM_KEYDOWN || msg->message == WM_SYSKEYDOWN) &&
1404            !(mask & GDK_KEY_PRESS_MASK)));
1405 }
1406
1407 static gboolean
1408 doesnt_want_char (gint mask,
1409                   MSG *msg)
1410 {
1411   return !(mask & (GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK));
1412 }
1413
1414 void
1415 _gdk_win32_emit_configure_event (GdkWindow *window)
1416 {
1417   GdkWindowImplWin32 *window_impl;
1418   RECT client_rect;
1419   POINT point;
1420   HWND hwnd;
1421
1422   window_impl = GDK_WINDOW_IMPL_WIN32 (window->impl);
1423   if (window_impl->inhibit_configure)
1424     return;
1425
1426   hwnd = GDK_WINDOW_HWND (window);
1427
1428   GetClientRect (hwnd, &client_rect);
1429   point.x = client_rect.left; /* always 0 */
1430   point.y = client_rect.top;
1431
1432   /* top level windows need screen coords */
1433   if (gdk_window_get_parent (window) == _gdk_root)
1434     {
1435       ClientToScreen (hwnd, &point);
1436       point.x += _gdk_offset_x;
1437       point.y += _gdk_offset_y;
1438     }
1439
1440   window->width = client_rect.right - client_rect.left;
1441   window->height = client_rect.bottom - client_rect.top;
1442   
1443   window->x = point.x;
1444   window->y = point.y;
1445
1446   _gdk_window_update_size (window);
1447   
1448   if (window->event_mask & GDK_STRUCTURE_MASK)
1449     {
1450       GdkEvent *event = gdk_event_new (GDK_CONFIGURE);
1451
1452       event->configure.window = window;
1453
1454       event->configure.width = client_rect.right - client_rect.left;
1455       event->configure.height = client_rect.bottom - client_rect.top;
1456       
1457       event->configure.x = point.x;
1458       event->configure.y = point.y;
1459
1460       _gdk_win32_append_event (event);
1461     }
1462 }
1463
1464 cairo_region_t *
1465 _gdk_win32_hrgn_to_region (HRGN hrgn)
1466 {
1467   RGNDATA *rgndata;
1468   RECT *rects;
1469   cairo_region_t *result;
1470   gint nbytes;
1471   guint i;
1472
1473   if ((nbytes = GetRegionData (hrgn, 0, NULL)) == 0)
1474     {
1475       WIN32_GDI_FAILED ("GetRegionData");
1476       return NULL;
1477     }
1478
1479   rgndata = (RGNDATA *) g_malloc (nbytes);
1480
1481   if (GetRegionData (hrgn, nbytes, rgndata) == 0)
1482     {
1483       WIN32_GDI_FAILED ("GetRegionData");
1484       g_free (rgndata);
1485       return NULL;
1486     }
1487
1488   result = cairo_region_create ();
1489   rects = (RECT *) rgndata->Buffer;
1490   for (i = 0; i < rgndata->rdh.nCount; i++)
1491     {
1492       GdkRectangle r;
1493
1494       r.x = rects[i].left;
1495       r.y = rects[i].top;
1496       r.width = rects[i].right - r.x;
1497       r.height = rects[i].bottom - r.y;
1498
1499       cairo_region_union_rectangle (result, &r);
1500     }
1501
1502   g_free (rgndata);
1503
1504   return result;
1505 }
1506
1507 static void
1508 adjust_drag (LONG *drag,
1509              LONG  curr,
1510              gint  inc)
1511 {
1512   if (*drag > curr)
1513     *drag = curr + ((*drag + inc/2 - curr) / inc) * inc;
1514   else
1515     *drag = curr - ((curr - *drag + inc/2) / inc) * inc;
1516 }
1517
1518 static void
1519 handle_wm_paint (MSG        *msg,
1520                  GdkWindow  *window,
1521                  gboolean    return_exposes,
1522                  GdkEvent  **event)
1523 {
1524   HRGN hrgn = CreateRectRgn (0, 0, 0, 0);
1525   HDC hdc;
1526   PAINTSTRUCT paintstruct;
1527   cairo_region_t *update_region;
1528
1529   if (GetUpdateRgn (msg->hwnd, hrgn, FALSE) == ERROR)
1530     {
1531       WIN32_GDI_FAILED ("GetUpdateRgn");
1532       DeleteObject (hrgn);
1533       return;
1534     }
1535
1536   hdc = BeginPaint (msg->hwnd, &paintstruct);
1537
1538   GDK_NOTE (EVENTS, g_print (" %s %s dc %p%s",
1539                              _gdk_win32_rect_to_string (&paintstruct.rcPaint),
1540                              (paintstruct.fErase ? "erase" : ""),
1541                              hdc,
1542                              (return_exposes ? " return_exposes" : "")));
1543
1544   EndPaint (msg->hwnd, &paintstruct);
1545
1546   if ((paintstruct.rcPaint.right == paintstruct.rcPaint.left) ||
1547       (paintstruct.rcPaint.bottom == paintstruct.rcPaint.top))
1548     {
1549       GDK_NOTE (EVENTS, g_print (" (empty paintstruct, ignored)"));
1550       DeleteObject (hrgn);
1551       return;
1552     }
1553
1554   if (return_exposes)
1555     {
1556       if (!GDK_WINDOW_DESTROYED (window))
1557         {
1558           GList *list = _gdk_display->queued_events;
1559
1560           *event = gdk_event_new (GDK_EXPOSE);
1561           (*event)->expose.window = window;
1562           (*event)->expose.area.x = paintstruct.rcPaint.left;
1563           (*event)->expose.area.y = paintstruct.rcPaint.top;
1564           (*event)->expose.area.width = paintstruct.rcPaint.right - paintstruct.rcPaint.left;
1565           (*event)->expose.area.height = paintstruct.rcPaint.bottom - paintstruct.rcPaint.top;
1566           (*event)->expose.region = _gdk_win32_hrgn_to_region (hrgn);
1567           (*event)->expose.count = 0;
1568
1569           while (list != NULL)
1570             {
1571               GdkEventPrivate *evp = list->data;
1572
1573               if (evp->event.any.type == GDK_EXPOSE &&
1574                   evp->event.any.window == window &&
1575                   !(evp->flags & GDK_EVENT_PENDING))
1576                 evp->event.expose.count++;
1577
1578               list = list->next;
1579             }
1580         }
1581
1582       DeleteObject (hrgn);
1583       return;
1584     }
1585
1586   update_region = _gdk_win32_hrgn_to_region (hrgn);
1587   if (!cairo_region_is_empty (update_region))
1588     _gdk_window_invalidate_for_expose (window, update_region);
1589   cairo_region_destroy (update_region);
1590
1591   DeleteObject (hrgn);
1592 }
1593
1594 static VOID CALLBACK 
1595 modal_timer_proc (HWND     hwnd,
1596                   UINT     msg,
1597                   UINT_PTR id,
1598                   DWORD    time)
1599 {
1600   int arbitrary_limit = 10;
1601
1602   while (_modal_operation_in_progress &&
1603          g_main_context_pending (NULL) &&
1604          arbitrary_limit--)
1605     g_main_context_iteration (NULL, FALSE);
1606 }
1607
1608 void
1609 _gdk_win32_begin_modal_call (void)
1610 {
1611   g_assert (!_modal_operation_in_progress);
1612
1613   _modal_operation_in_progress = TRUE;
1614
1615   modal_timer = SetTimer (NULL, 0, 10, modal_timer_proc);
1616   if (modal_timer == 0)
1617     WIN32_API_FAILED ("SetTimer");
1618 }
1619
1620 void
1621 _gdk_win32_end_modal_call (void)
1622 {
1623   g_assert (_modal_operation_in_progress);
1624
1625   _modal_operation_in_progress = FALSE;
1626
1627   if (modal_timer != 0)
1628     {
1629       API_CALL (KillTimer, (NULL, modal_timer));
1630       modal_timer = 0;
1631    }
1632 }
1633
1634 static VOID CALLBACK
1635 sync_timer_proc (HWND     hwnd,
1636                  UINT     msg,
1637                  UINT_PTR id,
1638                  DWORD    time)
1639 {
1640   MSG message;
1641   if (PeekMessageW (&message, hwnd, WM_PAINT, WM_PAINT, PM_REMOVE))
1642     {
1643       return;
1644     }
1645
1646   RedrawWindow (hwnd, NULL, NULL, RDW_INVALIDATE|RDW_UPDATENOW|RDW_ALLCHILDREN);
1647
1648   KillTimer (hwnd, sync_timer);
1649 }
1650
1651 static void
1652 handle_display_change (void)
1653 {
1654   _gdk_monitor_init ();
1655   _gdk_root_window_size_init ();
1656   g_signal_emit_by_name (_gdk_screen, "size_changed");
1657 }
1658
1659 static void
1660 generate_button_event (GdkEventType      type,
1661                        gint              button,
1662                        GdkWindow        *window,
1663                        MSG              *msg)
1664 {
1665   GdkEvent *event = gdk_event_new (type);
1666   GdkDeviceManagerWin32 *device_manager;
1667
1668   if (_gdk_input_ignore_core)
1669     return;
1670
1671   device_manager = GDK_DEVICE_MANAGER_WIN32 (gdk_display_get_device_manager (_gdk_display));
1672
1673   event->button.window = window;
1674   event->button.time = _gdk_win32_get_next_tick (msg->time);
1675   event->button.x = current_x = (gint16) GET_X_LPARAM (msg->lParam);
1676   event->button.y = current_y = (gint16) GET_Y_LPARAM (msg->lParam);
1677   event->button.x_root = msg->pt.x + _gdk_offset_x;
1678   event->button.y_root = msg->pt.y + _gdk_offset_y;
1679   event->button.axes = NULL;
1680   event->button.state = build_pointer_event_state (msg);
1681   event->button.button = button;
1682   gdk_event_set_device (event, device_manager->core_pointer);
1683   gdk_event_set_source_device (event, device_manager->system_pointer);
1684
1685   _gdk_win32_append_event (event);
1686 }
1687
1688 static void
1689 ensure_stacking_on_unminimize (MSG *msg)
1690 {
1691   HWND rover;
1692   HWND lowest_transient = NULL;
1693
1694   rover = msg->hwnd;
1695   while ((rover = GetNextWindow (rover, GW_HWNDNEXT)))
1696     {
1697       GdkWindow *rover_gdkw = gdk_win32_handle_table_lookup (rover);
1698
1699       /* Checking window group not implemented yet */
1700       if (rover_gdkw)
1701         {
1702           GdkWindowImplWin32 *rover_impl =
1703             GDK_WINDOW_IMPL_WIN32 (rover_gdkw->impl);
1704
1705           if (GDK_WINDOW_IS_MAPPED (rover_gdkw) &&
1706               (rover_impl->type_hint == GDK_WINDOW_TYPE_HINT_UTILITY ||
1707                rover_impl->type_hint == GDK_WINDOW_TYPE_HINT_DIALOG ||
1708                rover_impl->transient_owner != NULL))
1709             {
1710               lowest_transient = rover;
1711             }
1712         }
1713     }
1714   if (lowest_transient != NULL)
1715     {
1716       GDK_NOTE (EVENTS, g_print (" restacking: %p", lowest_transient));
1717       SetWindowPos (msg->hwnd, lowest_transient, 0, 0, 0, 0,
1718                     SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);
1719     }
1720 }
1721
1722 static gboolean
1723 ensure_stacking_on_window_pos_changing (MSG       *msg,
1724                                         GdkWindow *window)
1725 {
1726   GdkWindowImplWin32 *impl = GDK_WINDOW_IMPL_WIN32 (window->impl);
1727   WINDOWPOS *windowpos = (WINDOWPOS *) msg->lParam;
1728
1729   if (GetActiveWindow () == msg->hwnd &&
1730       impl->type_hint != GDK_WINDOW_TYPE_HINT_UTILITY &&
1731       impl->type_hint != GDK_WINDOW_TYPE_HINT_DIALOG &&
1732       impl->transient_owner == NULL)
1733     {
1734       /* Make sure the window stays behind any transient-type windows
1735        * of the same window group.
1736        *
1737        * If the window is not active and being activated, we let
1738        * Windows bring it to the top and rely on the WM_ACTIVATEAPP
1739        * handling to bring any utility windows on top of it.
1740        */
1741       HWND rover;
1742       gboolean restacking;
1743
1744       rover = windowpos->hwndInsertAfter;
1745       restacking = FALSE;
1746       while (rover)
1747         {
1748           GdkWindow *rover_gdkw = gdk_win32_handle_table_lookup (rover);
1749
1750           /* Checking window group not implemented yet */
1751           if (rover_gdkw)
1752             {
1753               GdkWindowImplWin32 *rover_impl =
1754                 GDK_WINDOW_IMPL_WIN32 (rover_gdkw->impl);
1755
1756               if (GDK_WINDOW_IS_MAPPED (rover_gdkw) &&
1757                   (rover_impl->type_hint == GDK_WINDOW_TYPE_HINT_UTILITY ||
1758                    rover_impl->type_hint == GDK_WINDOW_TYPE_HINT_DIALOG ||
1759                    rover_impl->transient_owner != NULL))
1760                 {
1761                   restacking = TRUE;
1762                   windowpos->hwndInsertAfter = rover;
1763                 }
1764             }
1765           rover = GetNextWindow (rover, GW_HWNDNEXT);
1766         }
1767
1768       if (restacking)
1769         {
1770           GDK_NOTE (EVENTS, g_print (" restacking: %p", windowpos->hwndInsertAfter));
1771           return TRUE;
1772         }
1773     }
1774   return FALSE;
1775 }
1776
1777 static void
1778 ensure_stacking_on_activate_app (MSG       *msg,
1779                                  GdkWindow *window)
1780 {
1781   GdkWindowImplWin32 *impl = GDK_WINDOW_IMPL_WIN32 (window->impl);
1782
1783   if (impl->type_hint == GDK_WINDOW_TYPE_HINT_UTILITY ||
1784       impl->type_hint == GDK_WINDOW_TYPE_HINT_DIALOG ||
1785       impl->transient_owner != NULL)
1786     {
1787       SetWindowPos (msg->hwnd, HWND_TOP, 0, 0, 0, 0,
1788                     SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);
1789       return;
1790     }
1791
1792   if (IsWindowVisible (msg->hwnd) &&
1793       msg->hwnd == GetActiveWindow ())
1794     {
1795       /* This window is not a transient-type window and it is the
1796        * activated window. Make sure this window is as visible as
1797        * possible, just below the lowest transient-type window of this
1798        * app.
1799        */
1800       HWND rover;
1801
1802       rover = msg->hwnd;
1803       while ((rover = GetNextWindow (rover, GW_HWNDPREV)))
1804         {
1805           GdkWindow *rover_gdkw = gdk_win32_handle_table_lookup (rover);
1806
1807           /* Checking window group not implemented yet */
1808           if (rover_gdkw)
1809             {
1810               GdkWindowImplWin32 *rover_impl =
1811                 GDK_WINDOW_IMPL_WIN32 (rover_gdkw->impl);
1812
1813               if (GDK_WINDOW_IS_MAPPED (rover_gdkw) &&
1814                   (rover_impl->type_hint == GDK_WINDOW_TYPE_HINT_UTILITY ||
1815                    rover_impl->type_hint == GDK_WINDOW_TYPE_HINT_DIALOG ||
1816                    rover_impl->transient_owner != NULL))
1817                 {
1818                   GDK_NOTE (EVENTS, g_print (" restacking: %p", rover));
1819                   SetWindowPos (msg->hwnd, rover, 0, 0, 0, 0,
1820                                 SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);
1821                   break;
1822                 }
1823             }
1824         }
1825     }
1826 }
1827
1828 #define GDK_ANY_BUTTON_MASK (GDK_BUTTON1_MASK | \
1829                              GDK_BUTTON2_MASK | \
1830                              GDK_BUTTON3_MASK | \
1831                              GDK_BUTTON4_MASK | \
1832                              GDK_BUTTON5_MASK)
1833
1834 static gboolean
1835 gdk_event_translate (MSG  *msg,
1836                      gint *ret_valp)
1837 {
1838   RECT rect, *drag, orig_drag;
1839   POINT point;
1840   MINMAXINFO *mmi;
1841   HWND hwnd;
1842   HCURSOR hcursor;
1843   BYTE key_state[256];
1844   HIMC himc;
1845   WINDOWPOS *windowpos;
1846   gboolean ignore_leave;
1847
1848   GdkEvent *event;
1849
1850   wchar_t wbuf[100];
1851   gint ccount;
1852
1853   GdkWindow *window = NULL;
1854   GdkWindowImplWin32 *impl;
1855
1856   GdkWindow *orig_window, *new_window;
1857
1858   GdkDeviceManager *device_manager;
1859   GdkDeviceManagerWin32 *device_manager_win32;
1860
1861   GdkDeviceGrabInfo *keyboard_grab = NULL;
1862   GdkDeviceGrabInfo *pointer_grab = NULL;
1863   GdkWindow *grab_window = NULL;
1864
1865   gint button;
1866   GdkAtom target;
1867
1868   gchar buf[256];
1869   gboolean return_val = FALSE;
1870
1871   int i;
1872
1873   if (_gdk_default_filters)
1874     {
1875       /* Apply global filters */
1876
1877       GdkFilterReturn result = apply_event_filters (NULL, msg, &_gdk_default_filters);
1878       
1879       /* If result is GDK_FILTER_CONTINUE, we continue as if nothing
1880        * happened. If it is GDK_FILTER_REMOVE or GDK_FILTER_TRANSLATE,
1881        * we return TRUE, and DefWindowProcW() will not be called.
1882        */
1883       if (result == GDK_FILTER_REMOVE || result == GDK_FILTER_TRANSLATE)
1884         return TRUE;
1885     }
1886
1887   window = gdk_win32_handle_table_lookup (msg->hwnd);
1888   orig_window = window;
1889
1890   if (window == NULL)
1891     {
1892       /* XXX Handle WM_QUIT here ? */
1893       if (msg->message == WM_QUIT)
1894         {
1895           GDK_NOTE (EVENTS, g_print (" %d", (int) msg->wParam));
1896           exit (msg->wParam);
1897         }
1898       else if (msg->message == WM_CREATE)
1899         {
1900           window = (UNALIGNED GdkWindow*) (((LPCREATESTRUCTW) msg->lParam)->lpCreateParams);
1901           GDK_WINDOW_HWND (window) = msg->hwnd;
1902         }
1903       else
1904         {
1905           GDK_NOTE (EVENTS, g_print (" (no GdkWindow)"));
1906         }
1907       return FALSE;
1908     }
1909
1910   device_manager = gdk_display_get_device_manager (_gdk_display);
1911   device_manager_win32 = GDK_DEVICE_MANAGER_WIN32 (device_manager);
1912
1913   keyboard_grab = _gdk_display_get_last_device_grab (_gdk_display,
1914                                                      device_manager_win32->core_keyboard);
1915   pointer_grab = _gdk_display_get_last_device_grab (_gdk_display,
1916                                                     device_manager_win32->core_pointer);
1917
1918   g_object_ref (window);
1919
1920   /* window's refcount has now been increased, so code below should
1921    * not just return from this function, but instead goto done (or
1922    * break out of the big switch). To protect against forgetting this,
1923    * #define return to a syntax error...
1924    */
1925 #define return GOTO_DONE_INSTEAD
1926   
1927   if (!GDK_WINDOW_DESTROYED (window) && window->filters)
1928     {
1929       /* Apply per-window filters */
1930
1931       GdkFilterReturn result = apply_event_filters (window, msg, &window->filters);
1932
1933       if (result == GDK_FILTER_REMOVE || result == GDK_FILTER_TRANSLATE)
1934         {
1935           return_val = TRUE;
1936           goto done;
1937         }
1938     }
1939
1940   if (msg->message == client_message)
1941     {
1942       GList *tmp_list;
1943       GdkFilterReturn result = GDK_FILTER_CONTINUE;
1944       GList *node;
1945
1946       GDK_NOTE (EVENTS, g_print (" client_message"));
1947
1948       event = gdk_event_new (GDK_NOTHING);
1949       ((GdkEventPrivate *)event)->flags |= GDK_EVENT_PENDING;
1950
1951       node = _gdk_event_queue_append (_gdk_display, event);
1952
1953       tmp_list = client_filters;
1954       while (tmp_list)
1955         {
1956           GdkClientFilter *filter = tmp_list->data;
1957
1958           tmp_list = tmp_list->next;
1959
1960           if (filter->type == GDK_POINTER_TO_ATOM (msg->wParam))
1961             {
1962               GDK_NOTE (EVENTS, g_print (" (match)"));
1963
1964               result = (*filter->function) (msg, event, filter->data);
1965
1966               if (result != GDK_FILTER_CONTINUE)
1967                 break;
1968             }
1969         }
1970
1971       switch (result)
1972         {
1973         case GDK_FILTER_REMOVE:
1974           _gdk_event_queue_remove_link (_gdk_display, node);
1975           g_list_free_1 (node);
1976           gdk_event_free (event);
1977           return_val = TRUE;
1978           goto done;
1979
1980         case GDK_FILTER_TRANSLATE:
1981           ((GdkEventPrivate *)event)->flags &= ~GDK_EVENT_PENDING;
1982           GDK_NOTE (EVENTS, _gdk_win32_print_event (event));
1983           return_val = TRUE;
1984           goto done;
1985
1986         case GDK_FILTER_CONTINUE:
1987           /* No more: Send unknown client messages on to Gtk for it to use */
1988           GDK_NOTE (EVENTS, _gdk_win32_print_event (event));
1989           return_val = TRUE;
1990           goto done;
1991         }
1992     }
1993
1994   switch (msg->message)
1995     {
1996     case WM_INPUTLANGCHANGE:
1997       _gdk_input_locale = (HKL) msg->lParam;
1998       _gdk_input_locale_is_ime = ImmIsIME (_gdk_input_locale);
1999       GetLocaleInfo (MAKELCID (LOWORD (_gdk_input_locale), SORT_DEFAULT),
2000                      LOCALE_IDEFAULTANSICODEPAGE,
2001                      buf, sizeof (buf));
2002       _gdk_input_codepage = atoi (buf);
2003       _gdk_keymap_serial++;
2004       GDK_NOTE (EVENTS,
2005                 g_print (" cs:%lu hkl:%p%s cp:%d",
2006                          (gulong) msg->wParam,
2007                          (gpointer) msg->lParam, _gdk_input_locale_is_ime ? " (IME)" : "",
2008                          _gdk_input_codepage));
2009       break;
2010
2011     case WM_SYSKEYUP:
2012     case WM_SYSKEYDOWN:
2013       GDK_NOTE (EVENTS,
2014                 g_print (" %s ch:%.02x %s",
2015                          _gdk_win32_key_to_string (msg->lParam),
2016                          (int) msg->wParam,
2017                          decode_key_lparam (msg->lParam)));
2018
2019       /* If posted without us having keyboard focus, ignore */
2020       if ((msg->wParam != VK_F10 && msg->wParam != VK_MENU) &&
2021           !(HIWORD (msg->lParam) & KF_ALTDOWN))
2022         break;
2023
2024       /* Let the system handle Alt-Tab, Alt-Space and Alt-F4 unless
2025        * the keyboard is grabbed.
2026        */
2027       if (!keyboard_grab &&
2028           (msg->wParam == VK_TAB ||
2029            msg->wParam == VK_SPACE ||
2030            msg->wParam == VK_F4))
2031         break;
2032
2033       /* Jump to code in common with WM_KEYUP and WM_KEYDOWN */
2034       goto keyup_or_down;
2035
2036     case WM_KEYUP:
2037     case WM_KEYDOWN:
2038       GDK_NOTE (EVENTS, 
2039                 g_print (" %s ch:%.02x %s",
2040                          _gdk_win32_key_to_string (msg->lParam),
2041                          (int) msg->wParam,
2042                          decode_key_lparam (msg->lParam)));
2043
2044     keyup_or_down:
2045
2046       /* Ignore key messages intended for the IME */
2047       if (msg->wParam == VK_PROCESSKEY ||
2048           in_ime_composition)
2049         break;
2050
2051       if (keyboard_grab &&
2052           !propagate (&window, msg,
2053                       keyboard_grab->window,
2054                       keyboard_grab->owner_events,
2055                       GDK_ALL_EVENTS_MASK,
2056                       doesnt_want_key))
2057         break;
2058
2059       if (GDK_WINDOW_DESTROYED (window))
2060         break;
2061
2062       event = gdk_event_new ((msg->message == WM_KEYDOWN ||
2063                               msg->message == WM_SYSKEYDOWN) ?
2064                              GDK_KEY_PRESS : GDK_KEY_RELEASE);
2065       event->key.window = window;
2066       event->key.time = _gdk_win32_get_next_tick (msg->time);
2067       event->key.keyval = GDK_KEY_VoidSymbol;
2068       event->key.string = NULL;
2069       event->key.length = 0;
2070       event->key.hardware_keycode = msg->wParam;
2071       gdk_event_set_device (event, device_manager_win32->core_keyboard);
2072       gdk_event_set_source_device (event, device_manager_win32->system_keyboard);
2073       if (HIWORD (msg->lParam) & KF_EXTENDED)
2074         {
2075           switch (msg->wParam)
2076             {
2077             case VK_CONTROL:
2078               event->key.hardware_keycode = VK_RCONTROL;
2079               break;
2080             case VK_SHIFT:      /* Actually, KF_EXTENDED is not set
2081                                  * for the right shift key.
2082                                  */
2083               event->key.hardware_keycode = VK_RSHIFT;
2084               break;
2085             case VK_MENU:
2086               event->key.hardware_keycode = VK_RMENU;
2087               break;
2088             }
2089         }
2090       else if (msg->wParam == VK_SHIFT &&
2091                LOBYTE (HIWORD (msg->lParam)) == _scancode_rshift)
2092         event->key.hardware_keycode = VK_RSHIFT;
2093
2094       API_CALL (GetKeyboardState, (key_state));
2095
2096       /* g_print ("ctrl:%02x lctrl:%02x rctrl:%02x alt:%02x lalt:%02x ralt:%02x\n", key_state[VK_CONTROL], key_state[VK_LCONTROL], key_state[VK_RCONTROL], key_state[VK_MENU], key_state[VK_LMENU], key_state[VK_RMENU]); */
2097       
2098       build_key_event_state (event, key_state);
2099
2100       if (msg->wParam == VK_PACKET &&
2101           ToUnicode (VK_PACKET, HIWORD (msg->lParam), key_state, wbuf, 1, 0) == 1)
2102         event->key.keyval = gdk_unicode_to_keyval (wbuf[0]);
2103       else
2104         gdk_keymap_translate_keyboard_state (_gdk_win32_display_get_keymap (_gdk_display),
2105                                              event->key.hardware_keycode,
2106                                              event->key.state,
2107                                              event->key.group,
2108                                              &event->key.keyval,
2109                                              NULL, NULL, NULL);
2110
2111       fill_key_event_string (event);
2112
2113       /* Reset MOD1_MASK if it is the Alt key itself */
2114       if (msg->wParam == VK_MENU)
2115         event->key.state &= ~GDK_MOD1_MASK;
2116
2117       _gdk_win32_append_event (event);
2118
2119       return_val = TRUE;
2120       break;
2121
2122     case WM_SYSCHAR:
2123       if (msg->wParam != VK_SPACE)
2124         {
2125           /* To prevent beeps, don't let DefWindowProcW() be called */
2126           return_val = TRUE;
2127           goto done;
2128         }
2129       break;
2130
2131     case WM_IME_STARTCOMPOSITION:
2132       in_ime_composition = TRUE;
2133       break;
2134
2135     case WM_IME_ENDCOMPOSITION:
2136       in_ime_composition = FALSE;
2137       break;
2138
2139     case WM_IME_COMPOSITION:
2140       /* On Win2k WM_IME_CHAR doesn't work correctly for non-Unicode
2141        * applications. Thus, handle WM_IME_COMPOSITION with
2142        * GCS_RESULTSTR instead, fetch the Unicode chars from the IME
2143        * with ImmGetCompositionStringW().
2144        *
2145        * See for instance
2146        * http://groups.google.com/groups?selm=natX5.57%24g77.19788%40nntp2.onemain.com
2147        * and
2148        * http://groups.google.com/groups?selm=u2XfrXw5BHA.1628%40tkmsftngp02
2149        * for comments by other people that seems to have the same
2150        * experience. WM_IME_CHAR just gives question marks, apparently
2151        * because of going through some conversion to the current code
2152        * page.
2153        *
2154        * WM_IME_CHAR might work on NT4 or Win9x with ActiveIMM, but
2155        * use WM_IME_COMPOSITION there, too, to simplify the code.
2156        */
2157       GDK_NOTE (EVENTS, g_print (" %#lx", (long) msg->lParam));
2158
2159       if (!(msg->lParam & GCS_RESULTSTR))
2160         break;
2161
2162       if (keyboard_grab &&
2163           !propagate (&window, msg,
2164                       keyboard_grab->window,
2165                       keyboard_grab->owner_events,
2166                       GDK_ALL_EVENTS_MASK,
2167                       doesnt_want_char))
2168         break;
2169
2170       if (GDK_WINDOW_DESTROYED (window))
2171         break;
2172
2173       himc = ImmGetContext (msg->hwnd);
2174       ccount = ImmGetCompositionStringW (himc, GCS_RESULTSTR,
2175                                          wbuf, sizeof (wbuf));
2176       ImmReleaseContext (msg->hwnd, himc);
2177
2178       ccount /= 2;
2179
2180       API_CALL (GetKeyboardState, (key_state));
2181
2182       for (i = 0; i < ccount; i++)
2183         {
2184           if (window->event_mask & GDK_KEY_PRESS_MASK)
2185             {
2186               /* Build a key press event */
2187               event = gdk_event_new (GDK_KEY_PRESS);
2188               event->key.window = window;
2189               gdk_event_set_device (event, device_manager_win32->core_keyboard);
2190               gdk_event_set_source_device (event, device_manager_win32->system_keyboard);
2191               build_wm_ime_composition_event (event, msg, wbuf[i], key_state);
2192
2193               _gdk_win32_append_event (event);
2194             }
2195           
2196           if (window->event_mask & GDK_KEY_RELEASE_MASK)
2197             {
2198               /* Build a key release event.  */
2199               event = gdk_event_new (GDK_KEY_RELEASE);
2200               event->key.window = window;
2201               gdk_event_set_device (event, device_manager_win32->core_keyboard);
2202               gdk_event_set_source_device (event, device_manager_win32->system_keyboard);
2203               build_wm_ime_composition_event (event, msg, wbuf[i], key_state);
2204
2205               _gdk_win32_append_event (event);
2206             }
2207         }
2208       return_val = TRUE;
2209       break;
2210
2211     case WM_LBUTTONDOWN:
2212       button = 1;
2213       goto buttondown0;
2214
2215     case WM_MBUTTONDOWN:
2216       button = 2;
2217       goto buttondown0;
2218
2219     case WM_RBUTTONDOWN:
2220       button = 3;
2221       goto buttondown0;
2222
2223     case WM_XBUTTONDOWN:
2224       if (HIWORD (msg->wParam) == XBUTTON1)
2225         button = 4;
2226       else
2227         button = 5;
2228
2229     buttondown0:
2230       GDK_NOTE (EVENTS, 
2231                 g_print (" (%d,%d)",
2232                          GET_X_LPARAM (msg->lParam), GET_Y_LPARAM (msg->lParam)));
2233
2234       assign_object (&window, find_window_for_mouse_event (window, msg));
2235       /* TODO_CSW?: there used to some synthesize and propagate */
2236       if (GDK_WINDOW_DESTROYED (window))
2237         break;
2238
2239       if (pointer_grab == NULL)
2240         {
2241           SetCapture (GDK_WINDOW_HWND (window));
2242         }
2243
2244       generate_button_event (GDK_BUTTON_PRESS, button,
2245                              window, msg);
2246
2247       return_val = TRUE;
2248       break;
2249
2250     case WM_LBUTTONUP:
2251       button = 1;
2252       goto buttonup0;
2253
2254     case WM_MBUTTONUP:
2255       button = 2;
2256       goto buttonup0;
2257
2258     case WM_RBUTTONUP:
2259       button = 3;
2260       goto buttonup0;
2261
2262     case WM_XBUTTONUP:
2263       if (HIWORD (msg->wParam) == XBUTTON1)
2264         button = 4;
2265       else
2266         button = 5;
2267
2268     buttonup0:
2269       GDK_NOTE (EVENTS, 
2270                 g_print (" (%d,%d)",
2271                          GET_X_LPARAM (msg->lParam), GET_Y_LPARAM (msg->lParam)));
2272
2273       assign_object (&window, find_window_for_mouse_event (window, msg));
2274
2275       if (pointer_grab != NULL && pointer_grab->implicit)
2276         {
2277           gint state = build_pointer_event_state (msg);
2278
2279           /* We keep the implicit grab until no buttons at all are held down */
2280           if ((state & GDK_ANY_BUTTON_MASK & ~(GDK_BUTTON1_MASK << (button - 1))) == 0)
2281             {
2282               ReleaseCapture ();
2283
2284               new_window = NULL;
2285               hwnd = WindowFromPoint (msg->pt);
2286               if (hwnd != NULL)
2287                 {
2288                   POINT client_pt = msg->pt;
2289
2290                   ScreenToClient (hwnd, &client_pt);
2291                   GetClientRect (hwnd, &rect);
2292                   if (PtInRect (&rect, client_pt))
2293                     new_window = gdk_win32_handle_table_lookup (hwnd);
2294                 }
2295               synthesize_crossing_events (_gdk_display,
2296                                           pointer_grab->native_window, new_window,
2297                                           GDK_CROSSING_UNGRAB,
2298                                           &msg->pt,
2299                                           0, /* TODO: Set right mask */
2300                                           msg->time,
2301                                           FALSE);
2302               assign_object (&mouse_window, new_window);
2303               mouse_window_ignored_leave = NULL;
2304             }
2305         }
2306
2307       generate_button_event (GDK_BUTTON_RELEASE, button,
2308                              window, msg);
2309
2310       return_val = TRUE;
2311       break;
2312
2313     case WM_MOUSEMOVE:
2314       GDK_NOTE (EVENTS,
2315                 g_print (" %p (%d,%d)",
2316                          (gpointer) msg->wParam,
2317                          GET_X_LPARAM (msg->lParam), GET_Y_LPARAM (msg->lParam)));
2318
2319       new_window = window;
2320
2321       if (pointer_grab != NULL)
2322         {
2323           POINT pt;
2324           pt = msg->pt;
2325
2326           new_window = NULL;
2327           hwnd = WindowFromPoint (pt);
2328           if (hwnd != NULL)
2329             {
2330               POINT client_pt = pt;
2331
2332               ScreenToClient (hwnd, &client_pt);
2333               GetClientRect (hwnd, &rect);
2334               if (PtInRect (&rect, client_pt))
2335                 new_window = gdk_win32_handle_table_lookup (hwnd);
2336             }
2337
2338           if (!pointer_grab->owner_events &&
2339               new_window != NULL &&
2340               new_window != pointer_grab->native_window)
2341             new_window = NULL;
2342         }
2343
2344       if (mouse_window != new_window)
2345         {
2346           GDK_NOTE (EVENTS, g_print (" mouse_sinwod %p -> %p",
2347                                      mouse_window ? GDK_WINDOW_HWND (mouse_window) : NULL, 
2348                                      new_window ? GDK_WINDOW_HWND (new_window) : NULL));
2349           synthesize_crossing_events (_gdk_display,
2350                                       mouse_window, new_window,
2351                                       GDK_CROSSING_NORMAL,
2352                                       &msg->pt,
2353                                       0, /* TODO: Set right mask */
2354                                       msg->time,
2355                                       FALSE);
2356           assign_object (&mouse_window, new_window);
2357           mouse_window_ignored_leave = NULL;
2358           if (new_window != NULL)
2359             track_mouse_event (TME_LEAVE, GDK_WINDOW_HWND (new_window));
2360         }
2361       else if (new_window != NULL && 
2362                new_window == mouse_window_ignored_leave)
2363         {
2364           /* If we ignored a leave event for this window and we're now getting
2365              input again we need to re-arm the mouse tracking, as that was
2366              cancelled by the mouseleave. */
2367           mouse_window_ignored_leave = NULL;
2368           track_mouse_event (TME_LEAVE, GDK_WINDOW_HWND (new_window));
2369         }
2370
2371       assign_object (&window, find_window_for_mouse_event (window, msg));
2372
2373       /* If we haven't moved, don't create any GDK event. Windows
2374        * sends WM_MOUSEMOVE messages after a new window is shows under
2375        * the mouse, even if the mouse hasn't moved. This disturbs gtk.
2376        */
2377       if (msg->pt.x + _gdk_offset_x == current_root_x &&
2378           msg->pt.y + _gdk_offset_y == current_root_y)
2379         break;
2380
2381       current_root_x = msg->pt.x + _gdk_offset_x;
2382       current_root_y = msg->pt.y + _gdk_offset_y;
2383
2384       if (!_gdk_input_ignore_core)
2385         {
2386           event = gdk_event_new (GDK_MOTION_NOTIFY);
2387           event->motion.window = window;
2388           event->motion.time = _gdk_win32_get_next_tick (msg->time);
2389           event->motion.x = current_x = (gint16) GET_X_LPARAM (msg->lParam);
2390           event->motion.y = current_y = (gint16) GET_Y_LPARAM (msg->lParam);
2391           event->motion.x_root = current_root_x;
2392           event->motion.y_root = current_root_y;
2393           event->motion.axes = NULL;
2394           event->motion.state = build_pointer_event_state (msg);
2395           event->motion.is_hint = FALSE;
2396           gdk_event_set_device (event, device_manager_win32->core_pointer);
2397           gdk_event_set_source_device (event, device_manager_win32->system_pointer);
2398
2399           _gdk_win32_append_event (event);
2400         }
2401
2402       return_val = TRUE;
2403       break;
2404
2405     case WM_NCMOUSEMOVE:
2406       GDK_NOTE (EVENTS,
2407                 g_print (" (%d,%d)",
2408                          GET_X_LPARAM (msg->lParam), GET_Y_LPARAM (msg->lParam)));
2409       break;
2410
2411     case WM_MOUSELEAVE:
2412       GDK_NOTE (EVENTS, g_print (" %d (%ld,%ld)",
2413                                  HIWORD (msg->wParam), msg->pt.x, msg->pt.y));
2414
2415       new_window = NULL;
2416       hwnd = WindowFromPoint (msg->pt);
2417       ignore_leave = FALSE;
2418       if (hwnd != NULL)
2419         {
2420           char classname[64];
2421
2422           POINT client_pt = msg->pt;
2423
2424           /* The synapitics trackpad drivers have this irritating
2425              feature where it pops up a window right under the pointer
2426              when you scroll. We ignore the leave and enter events for 
2427              this window */
2428           if (GetClassNameA (hwnd, classname, sizeof(classname)) &&
2429               strcmp (classname, SYNAPSIS_ICON_WINDOW_CLASS) == 0)
2430             ignore_leave = TRUE;
2431
2432           ScreenToClient (hwnd, &client_pt);
2433           GetClientRect (hwnd, &rect);
2434           if (PtInRect (&rect, client_pt))
2435             new_window = gdk_win32_handle_table_lookup (hwnd);
2436         }
2437
2438       if (!ignore_leave)
2439         synthesize_crossing_events (_gdk_display,
2440                                     mouse_window, new_window,
2441                                     GDK_CROSSING_NORMAL,
2442                                     &msg->pt,
2443                                     0, /* TODO: Set right mask */
2444                                     msg->time,
2445                                     FALSE);
2446       assign_object (&mouse_window, new_window);
2447       mouse_window_ignored_leave = ignore_leave ? new_window : NULL;
2448
2449
2450       return_val = TRUE;
2451       break;
2452
2453     case WM_MOUSEWHEEL:
2454       GDK_NOTE (EVENTS, g_print (" %d", (short) HIWORD (msg->wParam)));
2455
2456       /* WM_MOUSEWHEEL is delivered to the focus window. Work around
2457        * that. Also, the position is in screen coordinates, not client
2458        * coordinates as with the button messages. I love the
2459        * consistency of Windows.
2460        */
2461       point.x = GET_X_LPARAM (msg->lParam);
2462       point.y = GET_Y_LPARAM (msg->lParam);
2463
2464       if ((hwnd = WindowFromPoint (point)) == NULL)
2465         break;
2466       
2467       {
2468         char classname[64];
2469
2470         /* The synapitics trackpad drivers have this irritating
2471            feature where it pops up a window right under the pointer
2472            when you scroll. We backtrack and to the toplevel and
2473            find the innermost child instead. */
2474         if (GetClassNameA (hwnd, classname, sizeof(classname)) &&
2475             strcmp (classname, SYNAPSIS_ICON_WINDOW_CLASS) == 0)
2476           {
2477             HWND hwndc;
2478
2479             /* Find our toplevel window */
2480             hwnd = GetAncestor (msg->hwnd, GA_ROOT);
2481
2482             /* Walk back up to the outermost child at the desired point */
2483             do {
2484               ScreenToClient (hwnd, &point);
2485               hwndc = ChildWindowFromPoint (hwnd, point);
2486               ClientToScreen (hwnd, &point);
2487             } while (hwndc != hwnd && (hwnd = hwndc, 1));
2488           }
2489       }
2490
2491       msg->hwnd = hwnd;
2492       if ((new_window = gdk_win32_handle_table_lookup (msg->hwnd)) == NULL)
2493         break;
2494
2495       if (new_window != window)
2496         {
2497           assign_object (&window, new_window);
2498         }
2499
2500       ScreenToClient (msg->hwnd, &point);
2501
2502       event = gdk_event_new (GDK_SCROLL);
2503       event->scroll.window = window;
2504       event->scroll.direction = (((short) HIWORD (msg->wParam)) > 0) ?
2505         GDK_SCROLL_UP : GDK_SCROLL_DOWN;
2506       event->scroll.time = _gdk_win32_get_next_tick (msg->time);
2507       event->scroll.x = (gint16) point.x;
2508       event->scroll.y = (gint16) point.y;
2509       event->scroll.x_root = (gint16) GET_X_LPARAM (msg->lParam) + _gdk_offset_x;
2510       event->scroll.y_root = (gint16) GET_Y_LPARAM (msg->lParam) + _gdk_offset_y;
2511       event->scroll.state = build_pointer_event_state (msg);
2512       gdk_event_set_device (event, device_manager_win32->core_pointer);
2513       gdk_event_set_source_device (event, device_manager_win32->system_pointer);
2514
2515       _gdk_win32_append_event (event);
2516       
2517       return_val = TRUE;
2518       break;
2519
2520     case WM_HSCROLL:
2521       /* Just print more debugging information, don't actually handle it. */
2522       GDK_NOTE (EVENTS,
2523                 (g_print (" %s",
2524                           (LOWORD (msg->wParam) == SB_ENDSCROLL ? "ENDSCROLL" :
2525                            (LOWORD (msg->wParam) == SB_LEFT ? "LEFT" :
2526                             (LOWORD (msg->wParam) == SB_RIGHT ? "RIGHT" :
2527                              (LOWORD (msg->wParam) == SB_LINELEFT ? "LINELEFT" :
2528                               (LOWORD (msg->wParam) == SB_LINERIGHT ? "LINERIGHT" :
2529                                (LOWORD (msg->wParam) == SB_PAGELEFT ? "PAGELEFT" :
2530                                 (LOWORD (msg->wParam) == SB_PAGERIGHT ? "PAGERIGHT" :
2531                                  (LOWORD (msg->wParam) == SB_THUMBPOSITION ? "THUMBPOSITION" :
2532                                   (LOWORD (msg->wParam) == SB_THUMBTRACK ? "THUMBTRACK" :
2533                                    "???")))))))))),
2534                  (LOWORD (msg->wParam) == SB_THUMBPOSITION ||
2535                   LOWORD (msg->wParam) == SB_THUMBTRACK) ?
2536                  (g_print (" %d", HIWORD (msg->wParam)), 0) : 0));
2537       break;
2538
2539     case WM_VSCROLL:
2540       /* Just print more debugging information, don't actually handle it. */
2541       GDK_NOTE (EVENTS,
2542                 (g_print (" %s",
2543                           (LOWORD (msg->wParam) == SB_ENDSCROLL ? "ENDSCROLL" :
2544                            (LOWORD (msg->wParam) == SB_BOTTOM ? "BOTTOM" :
2545                             (LOWORD (msg->wParam) == SB_TOP ? "TOP" :
2546                              (LOWORD (msg->wParam) == SB_LINEDOWN ? "LINDOWN" :
2547                               (LOWORD (msg->wParam) == SB_LINEUP ? "LINEUP" :
2548                                (LOWORD (msg->wParam) == SB_PAGEDOWN ? "PAGEDOWN" :
2549                                 (LOWORD (msg->wParam) == SB_PAGEUP ? "PAGEUP" :
2550                                  (LOWORD (msg->wParam) == SB_THUMBPOSITION ? "THUMBPOSITION" :
2551                                   (LOWORD (msg->wParam) == SB_THUMBTRACK ? "THUMBTRACK" :
2552                                    "???")))))))))),
2553                  (LOWORD (msg->wParam) == SB_THUMBPOSITION ||
2554                   LOWORD (msg->wParam) == SB_THUMBTRACK) ?
2555                  (g_print (" %d", HIWORD (msg->wParam)), 0) : 0));
2556       break;
2557
2558      case WM_MOUSEACTIVATE:
2559        {
2560          if (gdk_window_get_window_type (window) == GDK_WINDOW_TEMP 
2561              || !window->accept_focus)
2562            {
2563              *ret_valp = MA_NOACTIVATE;
2564              return_val = TRUE;
2565            }
2566
2567          if (_gdk_modal_blocked (gdk_window_get_toplevel (window)))
2568            {
2569              *ret_valp = MA_NOACTIVATEANDEAT;
2570              return_val = TRUE;
2571            }
2572        }
2573
2574        break;
2575
2576     case WM_KILLFOCUS:
2577       if (keyboard_grab != NULL &&
2578           !GDK_WINDOW_DESTROYED (keyboard_grab->window))
2579         {
2580           generate_grab_broken_event (device_manager, keyboard_grab->window, TRUE, NULL);
2581         }
2582
2583       /* fallthrough */
2584     case WM_SETFOCUS:
2585       if (keyboard_grab != NULL &&
2586           !keyboard_grab->owner_events)
2587         break;
2588
2589       if (!(window->event_mask & GDK_FOCUS_CHANGE_MASK))
2590         break;
2591
2592       if (GDK_WINDOW_DESTROYED (window))
2593         break;
2594
2595       generate_focus_event (device_manager, window, (msg->message == WM_SETFOCUS));
2596       return_val = TRUE;
2597       break;
2598
2599     case WM_ERASEBKGND:
2600       GDK_NOTE (EVENTS, g_print (" %p", (HANDLE) msg->wParam));
2601       
2602       if (GDK_WINDOW_DESTROYED (window))
2603         break;
2604
2605       return_val = TRUE;
2606       *ret_valp = 1;
2607       break;
2608
2609     case WM_SYNCPAINT:
2610       sync_timer = SetTimer (GDK_WINDOW_HWND (window),
2611                              1,
2612                              200, sync_timer_proc);
2613       break;
2614
2615     case WM_PAINT:
2616       handle_wm_paint (msg, window, FALSE, NULL);
2617       break;
2618
2619     case WM_SETCURSOR:
2620       GDK_NOTE (EVENTS, g_print (" %#x %#x",
2621                                  LOWORD (msg->lParam), HIWORD (msg->lParam)));
2622
2623       if (pointer_grab != NULL)
2624         grab_window = pointer_grab->window;
2625
2626       if (grab_window == NULL && LOWORD (msg->lParam) != HTCLIENT)
2627         break;
2628
2629       if (grab_window != NULL && _gdk_win32_grab_cursor != NULL)
2630         hcursor = _gdk_win32_grab_cursor;
2631       else if (!GDK_WINDOW_DESTROYED (window))
2632         hcursor = GDK_WINDOW_IMPL_WIN32 (window->impl)->hcursor;
2633       else
2634         hcursor = NULL;
2635
2636       if (hcursor != NULL)
2637         {
2638           GDK_NOTE (EVENTS, g_print (" (SetCursor(%p)", hcursor));
2639           SetCursor (hcursor);
2640           return_val = TRUE;
2641           *ret_valp = TRUE;
2642         }
2643       break;
2644
2645     case WM_SYSCOMMAND:
2646       switch (msg->wParam)
2647         {
2648         case SC_MINIMIZE:
2649         case SC_RESTORE:
2650           do_show_window (window, msg->wParam == SC_MINIMIZE ? TRUE : FALSE);
2651           break;
2652         }
2653
2654       break;
2655
2656     case WM_ENTERSIZEMOVE:
2657     case WM_ENTERMENULOOP:
2658       if (msg->message == WM_ENTERSIZEMOVE)
2659         _modal_move_resize_window = msg->hwnd;
2660
2661       _gdk_win32_begin_modal_call ();
2662       break;
2663
2664     case WM_EXITSIZEMOVE:
2665     case WM_EXITMENULOOP:
2666       if (_modal_operation_in_progress)
2667         {
2668           _modal_move_resize_window = NULL;
2669           _gdk_win32_end_modal_call ();
2670         }
2671       break;
2672
2673     case WM_CAPTURECHANGED:
2674       /* Sometimes we don't get WM_EXITSIZEMOVE, for instance when you
2675          select move/size in the menu and then click somewhere without
2676          moving/resizing. We work around this using WM_CAPTURECHANGED. */
2677       if (_modal_operation_in_progress)
2678         {
2679           _modal_move_resize_window = NULL;
2680           _gdk_win32_end_modal_call ();
2681         }
2682       break;
2683
2684     case WM_WINDOWPOSCHANGING:
2685       GDK_NOTE (EVENTS, (windowpos = (WINDOWPOS *) msg->lParam,
2686                          g_print (" %s %s %dx%d@%+d%+d now below %p",
2687                                   _gdk_win32_window_pos_bits_to_string (windowpos->flags),
2688                                   (windowpos->hwndInsertAfter == HWND_BOTTOM ? "BOTTOM" :
2689                                    (windowpos->hwndInsertAfter == HWND_NOTOPMOST ? "NOTOPMOST" :
2690                                     (windowpos->hwndInsertAfter == HWND_TOP ? "TOP" :
2691                                      (windowpos->hwndInsertAfter == HWND_TOPMOST ? "TOPMOST" :
2692                                       (sprintf (buf, "%p", windowpos->hwndInsertAfter),
2693                                        buf))))),
2694                                   windowpos->cx, windowpos->cy, windowpos->x, windowpos->y,
2695                                   GetNextWindow (msg->hwnd, GW_HWNDPREV))));
2696
2697       if (GDK_WINDOW_IS_MAPPED (window))
2698         return_val = ensure_stacking_on_window_pos_changing (msg, window);
2699       break;
2700
2701     case WM_WINDOWPOSCHANGED:
2702       windowpos = (WINDOWPOS *) msg->lParam;
2703       GDK_NOTE (EVENTS, g_print (" %s %s %dx%d@%+d%+d",
2704                                  _gdk_win32_window_pos_bits_to_string (windowpos->flags),
2705                                  (windowpos->hwndInsertAfter == HWND_BOTTOM ? "BOTTOM" :
2706                                   (windowpos->hwndInsertAfter == HWND_NOTOPMOST ? "NOTOPMOST" :
2707                                    (windowpos->hwndInsertAfter == HWND_TOP ? "TOP" :
2708                                     (windowpos->hwndInsertAfter == HWND_TOPMOST ? "TOPMOST" :
2709                                      (sprintf (buf, "%p", windowpos->hwndInsertAfter),
2710                                       buf))))),
2711                                  windowpos->cx, windowpos->cy, windowpos->x, windowpos->y));
2712
2713       /* Break grabs on unmap or minimize */
2714       if (windowpos->flags & SWP_HIDEWINDOW || 
2715           ((windowpos->flags & SWP_STATECHANGED) && IsIconic (msg->hwnd)))
2716         {
2717           if (pointer_grab != NULL)
2718             {
2719               if (pointer_grab->window == window)
2720                 gdk_pointer_ungrab (msg->time);
2721             }
2722
2723           if (keyboard_grab != NULL &&
2724               keyboard_grab->window == window)
2725             gdk_keyboard_ungrab (msg->time);
2726         }
2727
2728       /* Send MAP events  */
2729       if ((windowpos->flags & SWP_SHOWWINDOW) &&
2730           !GDK_WINDOW_DESTROYED (window))
2731         {
2732           event = gdk_event_new (GDK_MAP);
2733           event->any.window = window;
2734           _gdk_win32_append_event (event);
2735         }
2736
2737       /* Update window state */
2738       if (windowpos->flags & (SWP_STATECHANGED | SWP_SHOWWINDOW | SWP_HIDEWINDOW))
2739         {
2740           GdkWindowState set_bits, unset_bits, old_state, new_state;
2741
2742           old_state = window->state;
2743
2744           set_bits = 0;
2745           unset_bits = 0;
2746
2747           if (IsWindowVisible (msg->hwnd))
2748             unset_bits |= GDK_WINDOW_STATE_WITHDRAWN;
2749           else
2750             set_bits |= GDK_WINDOW_STATE_WITHDRAWN;
2751
2752           if (IsIconic (msg->hwnd))
2753             set_bits |= GDK_WINDOW_STATE_ICONIFIED;
2754           else
2755             unset_bits |= GDK_WINDOW_STATE_ICONIFIED;
2756
2757           if (IsZoomed (msg->hwnd))
2758             set_bits |= GDK_WINDOW_STATE_MAXIMIZED;
2759           else
2760             unset_bits |= GDK_WINDOW_STATE_MAXIMIZED;
2761
2762           gdk_synthesize_window_state (window, unset_bits, set_bits);
2763
2764           new_state = window->state;
2765
2766           /* Whenever one window changes iconified state we need to also
2767            * change the iconified state in all transient related windows,
2768            * as windows doesn't give icons for transient childrens. 
2769            */
2770           if ((old_state & GDK_WINDOW_STATE_ICONIFIED) != 
2771               (new_state & GDK_WINDOW_STATE_ICONIFIED))
2772             do_show_window (window, (new_state & GDK_WINDOW_STATE_ICONIFIED));
2773
2774
2775           /* When un-minimizing, make sure we're stacked under any 
2776              transient-type windows. */
2777           if (!(old_state & GDK_WINDOW_STATE_ICONIFIED) &&
2778               (new_state & GDK_WINDOW_STATE_ICONIFIED))
2779             ensure_stacking_on_unminimize (msg);
2780         }
2781
2782       /* Show, New size or position => configure event */
2783       if (!(windowpos->flags & SWP_NOCLIENTMOVE) ||
2784           !(windowpos->flags & SWP_NOCLIENTSIZE) ||
2785           (windowpos->flags & SWP_SHOWWINDOW))
2786         {
2787           if (GDK_WINDOW_TYPE (window) != GDK_WINDOW_CHILD &&
2788               !IsIconic (msg->hwnd) &&
2789               !GDK_WINDOW_DESTROYED (window))
2790             _gdk_win32_emit_configure_event (window);
2791         }
2792
2793       if ((windowpos->flags & SWP_HIDEWINDOW) &&
2794           !GDK_WINDOW_DESTROYED (window))
2795         {
2796           /* Send UNMAP events  */
2797           event = gdk_event_new (GDK_UNMAP);
2798           event->any.window = window;
2799           _gdk_win32_append_event (event);
2800
2801           /* Make transient parent the forground window when window unmaps */
2802           impl = GDK_WINDOW_IMPL_WIN32 (window->impl);
2803
2804           if (impl->transient_owner &&
2805               GetForegroundWindow () == GDK_WINDOW_HWND (window))
2806             SetForegroundWindow (GDK_WINDOW_HWND (impl->transient_owner));
2807         }
2808
2809       if (!(windowpos->flags & SWP_NOCLIENTSIZE))
2810         {
2811           if (window->resize_count > 1)
2812             window->resize_count -= 1;
2813         }
2814
2815       /* Call modal timer immediate so that we repaint faster after a resize. */
2816       if (_modal_operation_in_progress)
2817         modal_timer_proc (0,0,0,0);
2818
2819       /* Claim as handled, so that WM_SIZE and WM_MOVE are avoided */
2820       return_val = TRUE;
2821       *ret_valp = 0;
2822       break;
2823
2824     case WM_SIZING:
2825       GetWindowRect (GDK_WINDOW_HWND (window), &rect);
2826       drag = (RECT *) msg->lParam;
2827       GDK_NOTE (EVENTS, g_print (" %s curr:%s drag:%s",
2828                                  (msg->wParam == WMSZ_BOTTOM ? "BOTTOM" :
2829                                   (msg->wParam == WMSZ_BOTTOMLEFT ? "BOTTOMLEFT" :
2830                                    (msg->wParam == WMSZ_LEFT ? "LEFT" :
2831                                     (msg->wParam == WMSZ_TOPLEFT ? "TOPLEFT" :
2832                                      (msg->wParam == WMSZ_TOP ? "TOP" :
2833                                       (msg->wParam == WMSZ_TOPRIGHT ? "TOPRIGHT" :
2834                                        (msg->wParam == WMSZ_RIGHT ? "RIGHT" :
2835                                         
2836                                         (msg->wParam == WMSZ_BOTTOMRIGHT ? "BOTTOMRIGHT" :
2837                                          "???")))))))),
2838                                  _gdk_win32_rect_to_string (&rect),
2839                                  _gdk_win32_rect_to_string (drag)));
2840
2841       impl = GDK_WINDOW_IMPL_WIN32 (window->impl);
2842       orig_drag = *drag;
2843       if (impl->hint_flags & GDK_HINT_RESIZE_INC)
2844         {
2845           GDK_NOTE (EVENTS, g_print (" (RESIZE_INC)"));
2846           if (impl->hint_flags & GDK_HINT_BASE_SIZE)
2847             {
2848               /* Resize in increments relative to the base size */
2849               rect.left = rect.top = 0;
2850               rect.right = impl->hints.base_width;
2851               rect.bottom = impl->hints.base_height;
2852               _gdk_win32_adjust_client_rect (window, &rect);
2853               point.x = rect.left;
2854               point.y = rect.top;
2855               ClientToScreen (GDK_WINDOW_HWND (window), &point);
2856               rect.left = point.x;
2857               rect.top = point.y;
2858               point.x = rect.right;
2859               point.y = rect.bottom;
2860               ClientToScreen (GDK_WINDOW_HWND (window), &point);
2861               rect.right = point.x;
2862               rect.bottom = point.y;
2863               
2864               GDK_NOTE (EVENTS, g_print (" (also BASE_SIZE, using %s)",
2865                                          _gdk_win32_rect_to_string (&rect)));
2866             }
2867
2868           switch (msg->wParam)
2869             {
2870             case WMSZ_BOTTOM:
2871               if (drag->bottom == rect.bottom)
2872                 break;
2873               adjust_drag (&drag->bottom, rect.bottom, impl->hints.height_inc);
2874               break;
2875
2876             case WMSZ_BOTTOMLEFT:
2877               if (drag->bottom == rect.bottom && drag->left == rect.left)
2878                 break;
2879               adjust_drag (&drag->bottom, rect.bottom, impl->hints.height_inc);
2880               adjust_drag (&drag->left, rect.left, impl->hints.width_inc);
2881               break;
2882
2883             case WMSZ_LEFT:
2884               if (drag->left == rect.left)
2885                 break;
2886               adjust_drag (&drag->left, rect.left, impl->hints.width_inc);
2887               break;
2888
2889             case WMSZ_TOPLEFT:
2890               if (drag->top == rect.top && drag->left == rect.left)
2891                 break;
2892               adjust_drag (&drag->top, rect.top, impl->hints.height_inc);
2893               adjust_drag (&drag->left, rect.left, impl->hints.width_inc);
2894               break;
2895
2896             case WMSZ_TOP:
2897               if (drag->top == rect.top)
2898                 break;
2899               adjust_drag (&drag->top, rect.top, impl->hints.height_inc);
2900               break;
2901
2902             case WMSZ_TOPRIGHT:
2903               if (drag->top == rect.top && drag->right == rect.right)
2904                 break;
2905               adjust_drag (&drag->top, rect.top, impl->hints.height_inc);
2906               adjust_drag (&drag->right, rect.right, impl->hints.width_inc);
2907               break;
2908
2909             case WMSZ_RIGHT:
2910               if (drag->right == rect.right)
2911                 break;
2912               adjust_drag (&drag->right, rect.right, impl->hints.width_inc);
2913               break;
2914
2915             case WMSZ_BOTTOMRIGHT:
2916               if (drag->bottom == rect.bottom && drag->right == rect.right)
2917                 break;
2918               adjust_drag (&drag->bottom, rect.bottom, impl->hints.height_inc);
2919               adjust_drag (&drag->right, rect.right, impl->hints.width_inc);
2920               break;
2921             }
2922
2923           if (drag->bottom != orig_drag.bottom || drag->left != orig_drag.left ||
2924               drag->top != orig_drag.top || drag->right != orig_drag.right)
2925             {
2926               *ret_valp = TRUE;
2927               return_val = TRUE;
2928               GDK_NOTE (EVENTS, g_print (" (handled RESIZE_INC: %s)",
2929                                          _gdk_win32_rect_to_string (drag)));
2930             }
2931         }
2932
2933       /* WM_GETMINMAXINFO handles min_size and max_size hints? */
2934
2935       if (impl->hint_flags & GDK_HINT_ASPECT)
2936         {
2937           RECT decorated_rect;
2938           RECT undecorated_drag;
2939           int decoration_width, decoration_height;
2940           gdouble drag_aspect;
2941           int drag_width, drag_height, new_width, new_height;
2942
2943           GetClientRect (GDK_WINDOW_HWND (window), &rect);
2944           decorated_rect = rect;
2945           _gdk_win32_adjust_client_rect (window, &decorated_rect);
2946
2947           /* Set undecorated_drag to the client area being dragged
2948            * out, in screen coordinates.
2949            */
2950           undecorated_drag = *drag;
2951           undecorated_drag.left -= decorated_rect.left - rect.left;
2952           undecorated_drag.right -= decorated_rect.right - rect.right;
2953           undecorated_drag.top -= decorated_rect.top - rect.top;
2954           undecorated_drag.bottom -= decorated_rect.bottom - rect.bottom;
2955
2956           decoration_width = (decorated_rect.right - decorated_rect.left) - (rect.right - rect.left);
2957           decoration_height = (decorated_rect.bottom - decorated_rect.top) - (rect.bottom - rect.top);
2958
2959           drag_width = undecorated_drag.right - undecorated_drag.left;
2960           drag_height = undecorated_drag.bottom - undecorated_drag.top;
2961
2962           drag_aspect = (gdouble) drag_width / drag_height;
2963
2964           GDK_NOTE (EVENTS, g_print (" (ASPECT:%g--%g curr: %g)",
2965                                      impl->hints.min_aspect, impl->hints.max_aspect, drag_aspect));
2966
2967           if (drag_aspect < impl->hints.min_aspect)
2968             {
2969               /* Aspect is getting too narrow */
2970               switch (msg->wParam)
2971                 {
2972                 case WMSZ_BOTTOM:
2973                 case WMSZ_TOP:
2974                   /* User drags top or bottom edge outward. Keep height, increase width. */
2975                   new_width = impl->hints.min_aspect * drag_height;
2976                   drag->left -= (new_width - drag_width) / 2;
2977                   drag->right = drag->left + new_width + decoration_width;
2978                   break;
2979                 case WMSZ_BOTTOMLEFT:
2980                 case WMSZ_BOTTOMRIGHT:
2981                   /* User drags bottom-left or bottom-right corner down. Adjust height. */
2982                   new_height = drag_width / impl->hints.min_aspect;
2983                   drag->bottom = drag->top + new_height + decoration_height;
2984                   break;
2985                 case WMSZ_LEFT:
2986                 case WMSZ_RIGHT:
2987                   /* User drags left or right edge inward. Decrease height */
2988                   new_height = drag_width / impl->hints.min_aspect;
2989                   drag->top += (drag_height - new_height) / 2;
2990                   drag->bottom = drag->top + new_height + decoration_height;
2991                   break;
2992                 case WMSZ_TOPLEFT:
2993                 case WMSZ_TOPRIGHT:
2994                   /* User drags top-left or top-right corner up. Adjust height. */
2995                   new_height = drag_width / impl->hints.min_aspect;
2996                   drag->top = drag->bottom - new_height - decoration_height;
2997                 }
2998             }
2999           else if (drag_aspect > impl->hints.max_aspect)
3000             {
3001               /* Aspect is getting too wide */
3002               switch (msg->wParam)
3003                 {
3004                 case WMSZ_BOTTOM:
3005                 case WMSZ_TOP:
3006                   /* User drags top or bottom edge inward. Decrease width. */
3007                   new_width = impl->hints.max_aspect * drag_height;
3008                   drag->left += (drag_width - new_width) / 2;
3009                   drag->right = drag->left + new_width + decoration_width;
3010                   break;
3011                 case WMSZ_BOTTOMLEFT:
3012                 case WMSZ_TOPLEFT:
3013                   /* User drags bottom-left or top-left corner left. Adjust width. */
3014                   new_width = impl->hints.max_aspect * drag_height;
3015                   drag->left = drag->right - new_width - decoration_width;
3016                   break;
3017                 case WMSZ_BOTTOMRIGHT:
3018                 case WMSZ_TOPRIGHT:
3019                   /* User drags bottom-right or top-right corner right. Adjust width. */
3020                   new_width = impl->hints.max_aspect * drag_height;
3021                   drag->right = drag->left + new_width + decoration_width;
3022                   break;
3023                 case WMSZ_LEFT:
3024                 case WMSZ_RIGHT:
3025                   /* User drags left or right edge outward. Increase height. */
3026                   new_height = drag_width / impl->hints.max_aspect;
3027                   drag->top -= (new_height - drag_height) / 2;
3028                   drag->bottom = drag->top + new_height + decoration_height;
3029                   break;
3030                 }
3031             }
3032
3033           *ret_valp = TRUE;
3034           return_val = TRUE;
3035           GDK_NOTE (EVENTS, g_print (" (handled ASPECT: %s)",
3036                                      _gdk_win32_rect_to_string (drag)));
3037         }
3038       break;
3039
3040     case WM_GETMINMAXINFO:
3041       if (GDK_WINDOW_DESTROYED (window))
3042         break;
3043
3044       impl = GDK_WINDOW_IMPL_WIN32 (window->impl);
3045       mmi = (MINMAXINFO*) msg->lParam;
3046       GDK_NOTE (EVENTS, g_print (" (mintrack:%ldx%ld maxtrack:%ldx%ld "
3047                                  "maxpos:%+ld%+ld maxsize:%ldx%ld)",
3048                                  mmi->ptMinTrackSize.x, mmi->ptMinTrackSize.y,
3049                                  mmi->ptMaxTrackSize.x, mmi->ptMaxTrackSize.y,
3050                                  mmi->ptMaxPosition.x, mmi->ptMaxPosition.y,
3051                                  mmi->ptMaxSize.x, mmi->ptMaxSize.y));
3052
3053       if (impl->hint_flags & GDK_HINT_MIN_SIZE)
3054         {
3055           rect.left = rect.top = 0;
3056           rect.right = impl->hints.min_width;
3057           rect.bottom = impl->hints.min_height;
3058
3059           _gdk_win32_adjust_client_rect (window, &rect);
3060
3061           mmi->ptMinTrackSize.x = rect.right - rect.left;
3062           mmi->ptMinTrackSize.y = rect.bottom - rect.top;
3063         }
3064
3065       if (impl->hint_flags & GDK_HINT_MAX_SIZE)
3066         {
3067           int maxw, maxh;
3068
3069           rect.left = rect.top = 0;
3070           rect.right = impl->hints.max_width;
3071           rect.bottom = impl->hints.max_height;
3072
3073           _gdk_win32_adjust_client_rect (window, &rect);
3074
3075           /* at least on win9x we have the 16 bit trouble */
3076           maxw = rect.right - rect.left;
3077           maxh = rect.bottom - rect.top;
3078           mmi->ptMaxTrackSize.x = maxw > 0 && maxw < G_MAXSHORT ? maxw : G_MAXSHORT;
3079           mmi->ptMaxTrackSize.y = maxh > 0 && maxh < G_MAXSHORT ? maxh : G_MAXSHORT;
3080         }
3081
3082       if (impl->hint_flags & (GDK_HINT_MIN_SIZE | GDK_HINT_MAX_SIZE))
3083         {
3084           /* Don't call DefWindowProcW() */
3085           GDK_NOTE (EVENTS, g_print (" (handled, mintrack:%ldx%ld maxtrack:%ldx%ld "
3086                                      "maxpos:%+ld%+ld maxsize:%ldx%ld)",
3087                                      mmi->ptMinTrackSize.x, mmi->ptMinTrackSize.y,
3088                                      mmi->ptMaxTrackSize.x, mmi->ptMaxTrackSize.y,
3089                                      mmi->ptMaxPosition.x, mmi->ptMaxPosition.y,
3090                                      mmi->ptMaxSize.x, mmi->ptMaxSize.y));
3091           return_val = TRUE;
3092         }
3093       mmi->ptMaxTrackSize.x = 30000;
3094       mmi->ptMaxTrackSize.y = 30000;
3095       return_val = TRUE;
3096       break;
3097
3098     case WM_CLOSE:
3099       if (GDK_WINDOW_DESTROYED (window))
3100         break;
3101
3102       event = gdk_event_new (GDK_DELETE);
3103       event->any.window = window;
3104
3105       _gdk_win32_append_event (event);
3106
3107       impl = GDK_WINDOW_IMPL_WIN32 (window->impl);
3108
3109       if (impl->transient_owner && GetForegroundWindow() == GDK_WINDOW_HWND (window))
3110         {
3111           SetForegroundWindow (GDK_WINDOW_HWND (impl->transient_owner));
3112         }
3113
3114       return_val = TRUE;
3115       break;
3116
3117     case WM_NCDESTROY:
3118       if (pointer_grab != NULL)
3119         {
3120           if (pointer_grab->window == window)
3121             gdk_pointer_ungrab (msg->time);
3122         }
3123
3124       if (keyboard_grab &&
3125           keyboard_grab->window == window)
3126         gdk_keyboard_ungrab (msg->time);
3127
3128       if ((window != NULL) && (msg->hwnd != GetDesktopWindow ()))
3129         gdk_window_destroy_notify (window);
3130
3131       if (window == NULL || GDK_WINDOW_DESTROYED (window))
3132         break;
3133
3134       event = gdk_event_new (GDK_DESTROY);
3135       event->any.window = window;
3136
3137       _gdk_win32_append_event (event);
3138
3139       return_val = TRUE;
3140       break;
3141
3142     case WM_DISPLAYCHANGE:
3143       handle_display_change ();
3144       break;
3145       
3146     case WM_DESTROYCLIPBOARD:
3147       if (!_ignore_destroy_clipboard)
3148         {
3149           event = gdk_event_new (GDK_SELECTION_CLEAR);
3150           event->selection.window = window;
3151           event->selection.selection = GDK_SELECTION_CLIPBOARD;
3152           event->selection.time = _gdk_win32_get_next_tick (msg->time);
3153           _gdk_win32_append_event (event);
3154         }
3155       else
3156         {
3157           return_val = TRUE;
3158         }
3159
3160       break;
3161
3162     case WM_RENDERFORMAT:
3163       GDK_NOTE (EVENTS, g_print (" %s", _gdk_win32_cf_to_string (msg->wParam)));
3164
3165       if (!(target = g_hash_table_lookup (_format_atom_table, GINT_TO_POINTER (msg->wParam))))
3166         {
3167           GDK_NOTE (EVENTS, g_print (" (target not found)"));
3168           return_val = TRUE;
3169           break;
3170         }
3171
3172       /* We need to render to clipboard immediately, don't call
3173        * _gdk_win32_append_event()
3174        */
3175       event = gdk_event_new (GDK_SELECTION_REQUEST);
3176       event->selection.window = window;
3177       event->selection.send_event = FALSE;
3178       event->selection.selection = GDK_SELECTION_CLIPBOARD;
3179       event->selection.target = target;
3180       event->selection.property = _gdk_selection;
3181       event->selection.requestor = gdk_win32_handle_table_lookup (msg->hwnd);
3182       event->selection.time = msg->time;
3183
3184       fixup_event (event);
3185       GDK_NOTE (EVENTS, g_print (" (calling _gdk_event_emit)"));
3186       GDK_NOTE (EVENTS, _gdk_win32_print_event (event));
3187       _gdk_event_emit (event);
3188       gdk_event_free (event);
3189
3190       /* Now the clipboard owner should have rendered */
3191       if (!_delayed_rendering_data)
3192         {
3193           GDK_NOTE (EVENTS, g_print (" (no _delayed_rendering_data?)"));
3194         }
3195       else
3196         {
3197           if (msg->wParam == CF_DIB)
3198             {
3199               _delayed_rendering_data =
3200                 _gdk_win32_selection_convert_to_dib (_delayed_rendering_data,
3201                                                      target);
3202               if (!_delayed_rendering_data)
3203                 {
3204                   g_warning ("Cannot convert to DIB from delayed rendered image");
3205                   break;
3206                 }
3207             }
3208
3209           /* The requestor is holding the clipboard, no
3210            * OpenClipboard() is required/possible
3211            */
3212           GDK_NOTE (DND,
3213                     g_print (" SetClipboardData(%s,%p)",
3214                              _gdk_win32_cf_to_string (msg->wParam),
3215                              _delayed_rendering_data));
3216
3217           API_CALL (SetClipboardData, (msg->wParam, _delayed_rendering_data));
3218           _delayed_rendering_data = NULL;
3219         }
3220       break;
3221
3222     case WM_ACTIVATE:
3223       GDK_NOTE (EVENTS, g_print (" %s%s %p",
3224                                  (LOWORD (msg->wParam) == WA_ACTIVE ? "ACTIVE" :
3225                                   (LOWORD (msg->wParam) == WA_CLICKACTIVE ? "CLICKACTIVE" :
3226                                    (LOWORD (msg->wParam) == WA_INACTIVE ? "INACTIVE" : "???"))),
3227                                  HIWORD (msg->wParam) ? " minimized" : "",
3228                                  (HWND) msg->lParam));
3229       /* We handle mouse clicks for modally-blocked windows under WM_MOUSEACTIVATE,
3230        * but we still need to deal with alt-tab, or with SetActiveWindow() type
3231        * situations.
3232        */
3233       if (_gdk_modal_blocked (window) && LOWORD (msg->wParam) == WA_ACTIVE)
3234         {
3235           GdkWindow *modal_current = _gdk_modal_current ();
3236           SetActiveWindow (GDK_WINDOW_HWND (modal_current));
3237           *ret_valp = 0;
3238           return_val = TRUE;
3239           break;
3240         }
3241
3242       if (LOWORD (msg->wParam) == WA_INACTIVE)
3243         gdk_synthesize_window_state (window, GDK_WINDOW_STATE_FOCUSED, 0);
3244       else
3245         gdk_synthesize_window_state (window, 0, GDK_WINDOW_STATE_FOCUSED);
3246
3247       /* Bring any tablet contexts to the top of the overlap order when
3248        * one of our windows is activated.
3249        * NOTE: It doesn't seem to work well if it is done in WM_ACTIVATEAPP
3250        * instead
3251        */
3252       if (LOWORD(msg->wParam) != WA_INACTIVE)
3253         _gdk_input_set_tablet_active ();
3254       break;
3255
3256     case WM_ACTIVATEAPP:
3257       GDK_NOTE (EVENTS, g_print (" %s thread: %I64d",
3258                                  msg->wParam ? "YES" : "NO",
3259                                  (gint64) msg->lParam));
3260       if (msg->wParam && GDK_WINDOW_IS_MAPPED (window))
3261         ensure_stacking_on_activate_app (msg, window);
3262       break;
3263
3264       /* Handle WINTAB events here, as we know that gdkinput.c will
3265        * use the fixed WT_DEFBASE as lcMsgBase, and we thus can use the
3266        * constants as case labels.
3267        */
3268     case WT_PACKET:
3269       GDK_NOTE (EVENTS, g_print (" %d %p",
3270                                  (int) msg->wParam, (gpointer) msg->lParam));
3271       goto wintab;
3272       
3273     case WT_CSRCHANGE:
3274       GDK_NOTE (EVENTS, g_print (" %d %p",
3275                                  (int) msg->wParam, (gpointer) msg->lParam));
3276       goto wintab;
3277       
3278     case WT_PROXIMITY:
3279       GDK_NOTE (EVENTS, g_print (" %p %d %d",
3280                                  (gpointer) msg->wParam,
3281                                  LOWORD (msg->lParam),
3282                                  HIWORD (msg->lParam)));
3283       /* Fall through */
3284     wintab:
3285
3286       event = gdk_event_new (GDK_NOTHING);
3287       event->any.window = window;
3288       g_object_ref (window);
3289
3290       if (_gdk_input_other_event (event, msg, window))
3291         _gdk_win32_append_event (event);
3292       else
3293         gdk_event_free (event);
3294
3295       break;
3296     }
3297
3298 done:
3299
3300   if (window)
3301     g_object_unref (window);
3302   
3303 #undef return
3304   return return_val;
3305 }
3306
3307 void
3308 _gdk_win32_display_queue_events (GdkDisplay *display)
3309 {
3310   MSG msg;
3311
3312   if (modal_win32_dialog != NULL)
3313     return;
3314   
3315   while (!_gdk_event_queue_find_first (display) &&
3316          PeekMessageW (&msg, NULL, 0, 0, PM_REMOVE))
3317     {
3318       TranslateMessage (&msg);
3319       DispatchMessageW (&msg);
3320     }
3321 }
3322
3323 static gboolean
3324 gdk_event_prepare (GSource *source,
3325                    gint    *timeout)
3326 {
3327   gboolean retval;
3328
3329   gdk_threads_enter ();
3330
3331   *timeout = -1;
3332
3333   if (display->event_pause_count > 0)
3334     retval = FALSE;
3335   else
3336     retval = (_gdk_event_queue_find_first (_gdk_display) != NULL ||
3337               (modal_win32_dialog == NULL &&
3338                GetQueueStatus (QS_ALLINPUT) != 0));
3339
3340   gdk_threads_leave ();
3341
3342   return retval;
3343 }
3344
3345 static gboolean
3346 gdk_event_check (GSource *source)
3347 {
3348   gboolean retval;
3349   
3350   gdk_threads_enter ();
3351
3352   if (display->event_pause_count > 0)
3353     retval = FALSE;
3354   else if (event_poll_fd.revents & G_IO_IN)
3355     retval = (_gdk_event_queue_find_first (_gdk_display) != NULL ||
3356               (modal_win32_dialog == NULL &&
3357                GetQueueStatus (QS_ALLINPUT) != 0));
3358   else
3359     retval = FALSE;
3360
3361   gdk_threads_leave ();
3362
3363   return retval;
3364 }
3365
3366 static gboolean
3367 gdk_event_dispatch (GSource     *source,
3368                     GSourceFunc  callback,
3369                     gpointer     user_data)
3370 {
3371   GdkEvent *event;
3372  
3373   gdk_threads_enter ();
3374
3375   _gdk_win32_display_queue_events (_gdk_display);
3376   event = _gdk_event_unqueue (_gdk_display);
3377
3378   if (event)
3379     {
3380       _gdk_event_emit (event);
3381       
3382       gdk_event_free (event);
3383
3384       /* Do drag & drop if it is still pending */
3385       if (_dnd_source_state == GDK_WIN32_DND_PENDING) 
3386         {
3387           _dnd_source_state = GDK_WIN32_DND_DRAGGING;
3388           _gdk_win32_dnd_do_dragdrop ();
3389           _dnd_source_state = GDK_WIN32_DND_NONE;
3390         }
3391     }
3392   
3393   gdk_threads_leave ();
3394
3395   return TRUE;
3396 }
3397
3398 void
3399 gdk_win32_set_modal_dialog_libgtk_only (HWND window)
3400 {
3401   modal_win32_dialog = window;
3402 }