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