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