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