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