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