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