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