]> Pileus Git - ~andy/gtk/blob - gdk/quartz/gdkevents-quartz.c
Remove special casing of menu key events as it's no longer necessary;
[~andy/gtk] / gdk / quartz / gdkevents-quartz.c
1 /* gdkevents-quartz.c
2  *
3  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
4  * Copyright (C) 1998-2002 Tor Lillqvist
5  * Copyright (C) 2005-2008 Imendio AB
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the
19  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20  * Boston, MA 02111-1307, USA.
21  */
22
23 #include <config.h>
24 #include <sys/types.h>
25 #include <sys/sysctl.h>
26 #include <pthread.h>
27 #include <unistd.h>
28
29 #import <Cocoa/Cocoa.h>
30 #include <Carbon/Carbon.h>
31
32 #include "gdkscreen.h"
33 #include "gdkkeysyms.h"
34 #include "gdkprivate-quartz.h"
35
36 /* This is the window the mouse is currently over */
37 static GdkWindow   *current_mouse_window;
38
39 /* This is the window corresponding to the key window */
40 static GdkWindow   *current_keyboard_window;
41
42 /* This is the pointer grab window */
43 GdkWindow          *_gdk_quartz_pointer_grab_window;
44 static gboolean     pointer_grab_owner_events;
45 static GdkEventMask pointer_grab_event_mask;
46 static gboolean     pointer_grab_implicit;
47
48 /* This is the keyboard grab window */
49 GdkWindow *         _gdk_quartz_keyboard_grab_window;
50 static gboolean     keyboard_grab_owner_events;
51
52 /* This is the event mask and button state from the last event */
53 static GdkEventMask current_event_mask;
54 static int          current_button_state;
55
56 static void get_child_coordinates_from_ancestor (GdkWindow *ancestor_window,
57                                                  gint       ancestor_x,
58                                                  gint       ancestor_y,
59                                                  GdkWindow *child_window, 
60                                                  gint      *child_x, 
61                                                  gint      *child_y);
62 static void get_ancestor_coordinates_from_child (GdkWindow *child_window,
63                                                  gint       child_x,
64                                                  gint       child_y,
65                                                  GdkWindow *ancestor_window, 
66                                                  gint      *ancestor_x, 
67                                                  gint      *ancestor_y);
68 static void get_converted_window_coordinates    (GdkWindow *in_window,
69                                                  gint       in_x,
70                                                  gint       in_y,
71                                                  GdkWindow *out_window, 
72                                                  gint      *out_x, 
73                                                  gint      *out_y);
74 static void append_event                        (GdkEvent  *event);
75
76 static const gchar *
77 which_window_is_this (GdkWindow *window)
78 {
79   static gchar buf[256];
80   const gchar *name = NULL;
81   gpointer widget;
82
83   /* Get rid of compiler warning. */
84   if (0) which_window_is_this (window);
85
86   if (window == _gdk_root)
87     name = "root";
88   else if (window == NULL)
89     name = "null";
90
91   if (window)
92     {
93       gdk_window_get_user_data (window, &widget);
94       if (widget)
95         name = G_OBJECT_TYPE_NAME (widget);
96     }
97
98   if (!name)
99     name = "unknown";
100
101   snprintf (buf, 256, "<%s (%p)%s>", 
102             name, window, 
103             window == current_mouse_window ? ", is mouse" : "");
104
105   return buf;
106 }
107
108 NSEvent *
109 gdk_quartz_event_get_nsevent (GdkEvent *event)
110 {
111   /* FIXME: If the event here is unallocated, we crash. */
112   return ((GdkEventPrivate *) event)->windowing_data;
113 }
114
115 void 
116 _gdk_events_init (void)
117 {
118   _gdk_quartz_event_loop_init ();
119
120   current_mouse_window = g_object_ref (_gdk_root);
121   current_keyboard_window = g_object_ref (_gdk_root);
122 }
123
124 gboolean
125 gdk_events_pending (void)
126 {
127   return (_gdk_event_queue_find_first (_gdk_display) ||
128           (_gdk_quartz_event_loop_check_pending ()));
129 }
130
131 GdkEvent*
132 gdk_event_get_graphics_expose (GdkWindow *window)
133 {
134   /* FIXME: Implement */
135   return NULL;
136 }
137
138 static void
139 generate_grab_broken_event (GdkWindow *window,
140                             gboolean   keyboard,
141                             gboolean   implicit,
142                             GdkWindow *grab_window)
143 {
144   if (!GDK_WINDOW_DESTROYED (window))
145     {
146       GdkEvent *event = gdk_event_new (GDK_GRAB_BROKEN);
147
148       event->grab_broken.window = window;
149       event->grab_broken.send_event = 0;
150       event->grab_broken.keyboard = keyboard;
151       event->grab_broken.implicit = implicit;
152       event->grab_broken.grab_window = grab_window;
153       
154       append_event (event);
155     }
156 }
157
158 GdkGrabStatus
159 gdk_keyboard_grab (GdkWindow  *window,
160                    gint        owner_events,
161                    guint32     time)
162 {
163   g_return_val_if_fail (window != NULL, 0);
164   g_return_val_if_fail (GDK_IS_WINDOW (window), 0);
165
166   if (_gdk_quartz_keyboard_grab_window)
167     {
168       if (_gdk_quartz_keyboard_grab_window != window)
169         generate_grab_broken_event (_gdk_quartz_keyboard_grab_window,
170                                     TRUE, FALSE, window);
171       
172       g_object_unref (_gdk_quartz_keyboard_grab_window);
173     }
174
175   _gdk_quartz_keyboard_grab_window = g_object_ref (window);
176   keyboard_grab_owner_events = owner_events;
177
178   return GDK_GRAB_SUCCESS;
179 }
180
181 void
182 gdk_display_keyboard_ungrab (GdkDisplay *display,
183                              guint32     time)
184 {
185   if (_gdk_quartz_keyboard_grab_window)
186     g_object_unref (_gdk_quartz_keyboard_grab_window);
187   _gdk_quartz_keyboard_grab_window = NULL;
188 }
189
190 gboolean
191 gdk_keyboard_grab_info_libgtk_only (GdkDisplay *display,
192                                     GdkWindow **grab_window,
193                                     gboolean   *owner_events)
194 {
195   if (_gdk_quartz_keyboard_grab_window) 
196     {
197       if (grab_window)
198         *grab_window = _gdk_quartz_keyboard_grab_window;
199       if (owner_events)
200         *owner_events = keyboard_grab_owner_events;
201
202       return TRUE;
203     }
204
205   return FALSE;
206 }
207
208 static void
209 pointer_ungrab_internal (gboolean only_if_implicit)
210 {
211   if (!_gdk_quartz_pointer_grab_window)
212     return;
213
214   if (only_if_implicit && !pointer_grab_implicit)
215     return;
216
217   g_object_unref (_gdk_quartz_pointer_grab_window);
218   _gdk_quartz_pointer_grab_window = NULL;
219
220   pointer_grab_owner_events = FALSE;
221   pointer_grab_event_mask = 0;
222   pointer_grab_implicit = FALSE;
223
224   /* FIXME: Send crossing events */
225 }
226
227 gboolean
228 gdk_display_pointer_is_grabbed (GdkDisplay *display)
229 {
230   return (_gdk_quartz_pointer_grab_window != NULL && 
231           !pointer_grab_implicit);
232 }
233
234 gboolean
235 gdk_pointer_grab_info_libgtk_only (GdkDisplay *display,
236                                    GdkWindow **grab_window,
237                                    gboolean   *owner_events)
238 {
239   if (!_gdk_quartz_pointer_grab_window)
240     return FALSE;
241
242   if (grab_window)
243     *grab_window = _gdk_quartz_pointer_grab_window;
244
245   if (owner_events)
246     *owner_events = pointer_grab_owner_events;
247
248   return FALSE;
249 }
250
251 void
252 gdk_display_pointer_ungrab (GdkDisplay *display,
253                             guint32     time)
254 {
255   pointer_ungrab_internal (FALSE);
256 }
257
258 static GdkGrabStatus
259 pointer_grab_internal (GdkWindow    *window,
260                        gboolean      owner_events,
261                        GdkEventMask  event_mask,
262                        GdkWindow    *confine_to,
263                        GdkCursor    *cursor,
264                        gboolean      implicit)
265 {
266   /* FIXME: Send crossing events */
267   
268   _gdk_quartz_pointer_grab_window = g_object_ref (window);
269   pointer_grab_owner_events = owner_events;
270   pointer_grab_event_mask = event_mask;
271   pointer_grab_implicit = implicit;
272
273   return GDK_GRAB_SUCCESS;
274 }
275
276 GdkGrabStatus
277 gdk_pointer_grab (GdkWindow    *window,
278                   gboolean      owner_events,
279                   GdkEventMask  event_mask,
280                   GdkWindow    *confine_to,
281                   GdkCursor    *cursor,
282                   guint32       time)
283 {
284   g_return_val_if_fail (GDK_IS_WINDOW (window), 0);
285   g_return_val_if_fail (confine_to == NULL || GDK_IS_WINDOW (confine_to), 0);
286
287   if (_gdk_quartz_pointer_grab_window)
288     {
289       if (_gdk_quartz_pointer_grab_window != window)
290         generate_grab_broken_event (_gdk_quartz_pointer_grab_window,
291                                     FALSE, pointer_grab_implicit, window);
292
293       pointer_ungrab_internal (FALSE);
294     }
295
296   return pointer_grab_internal (window, owner_events, event_mask, 
297                                 confine_to, cursor, FALSE);
298 }
299
300 /* This is used to break any grabs in the case where we have to due to
301  * the grab emulation. Instead of enforcing the desktop wide grab, we
302  * break it when the app loses focus for example.
303  */
304 static void
305 break_all_grabs (void)
306 {
307   if (_gdk_quartz_keyboard_grab_window)
308     {
309       generate_grab_broken_event (_gdk_quartz_keyboard_grab_window,
310                                   TRUE, FALSE,
311                                   NULL);
312       g_object_unref (_gdk_quartz_keyboard_grab_window);
313       _gdk_quartz_keyboard_grab_window = NULL;
314     }
315
316   if (_gdk_quartz_pointer_grab_window)
317     {
318       generate_grab_broken_event (_gdk_quartz_pointer_grab_window,
319                                   FALSE, pointer_grab_implicit,
320                                   NULL);
321       pointer_ungrab_internal (FALSE);
322     }
323 }
324
325 static void
326 fixup_event (GdkEvent *event)
327 {
328   if (event->any.window)
329     g_object_ref (event->any.window);
330   if (((event->any.type == GDK_ENTER_NOTIFY) ||
331        (event->any.type == GDK_LEAVE_NOTIFY)) &&
332       (event->crossing.subwindow != NULL))
333     g_object_ref (event->crossing.subwindow);
334   event->any.send_event = FALSE;
335 }
336
337 static void
338 append_event (GdkEvent *event)
339 {
340   fixup_event (event);
341   _gdk_event_queue_append (_gdk_display, event);
342 }
343
344 static GdkFilterReturn
345 apply_filters (GdkWindow  *window,
346                NSEvent    *nsevent,
347                GList      *filters)
348 {
349   GdkFilterReturn result = GDK_FILTER_CONTINUE;
350   GdkEvent *event;
351   GList *node;
352   GList *tmp_list;
353
354   event = gdk_event_new (GDK_NOTHING);
355   if (window != NULL)
356     event->any.window = g_object_ref (window);
357   ((GdkEventPrivate *)event)->flags |= GDK_EVENT_PENDING;
358
359   /* I think GdkFilterFunc semantics require the passed-in event
360    * to already be in the queue. The filter func can generate
361    * more events and append them after it if it likes.
362    */
363   node = _gdk_event_queue_append (_gdk_display, event);
364   
365   tmp_list = filters;
366   while (tmp_list)
367     {
368       GdkEventFilter *filter = (GdkEventFilter *) tmp_list->data;
369       
370       tmp_list = tmp_list->next;
371       result = filter->function (nsevent, event, filter->data);
372       if (result != GDK_FILTER_CONTINUE)
373         break;
374     }
375
376   if (result == GDK_FILTER_CONTINUE || result == GDK_FILTER_REMOVE)
377     {
378       _gdk_event_queue_remove_link (_gdk_display, node);
379       g_list_free_1 (node);
380       gdk_event_free (event);
381     }
382   else /* GDK_FILTER_TRANSLATE */
383     {
384       ((GdkEventPrivate *)event)->flags &= ~GDK_EVENT_PENDING;
385       fixup_event (event);
386     }
387   return result;
388 }
389
390 /* Checks if the passed in window is interested in the event mask, and
391  * if so, it's returned. If not, the event can be propagated through
392  * its ancestors until one with the right event mask is found, up to
393  * the nearest toplevel.
394  */
395 static GdkWindow *
396 find_window_interested_in_event_mask (GdkWindow    *window, 
397                                       GdkEventMask  event_mask,
398                                       gboolean      propagate)
399 {
400   GdkWindowObject *private;
401
402   private = GDK_WINDOW_OBJECT (window);
403   while (private)
404     {
405       if (private->event_mask & event_mask)
406         return (GdkWindow *)private;
407
408       if (!propagate)
409         return NULL;
410
411       /* Don't traverse beyond toplevels. */
412       if (GDK_WINDOW_TYPE (private) != GDK_WINDOW_CHILD)
413         break;
414
415       private = private->parent;
416     }
417
418   return NULL;
419 }
420
421 static guint32
422 get_time_from_ns_event (NSEvent *event)
423 {
424   double time = [event timestamp];
425   
426   return time * 1000.0;
427 }
428
429 static int
430 get_mouse_button_from_ns_event (NSEvent *event)
431 {
432   int button;
433
434   button = [event buttonNumber];
435
436   switch (button)
437     {
438     case 0:
439       return 1;
440     case 1:
441       return 3;
442     case 2:
443       return 2;
444     default:
445       return button + 1;
446     }
447 }
448
449 static GdkModifierType
450 get_mouse_button_modifiers_from_ns_event (NSEvent *event)
451 {
452   int button;
453   GdkModifierType state = 0;
454
455   /* This maps buttons 1 to 5 to GDK_BUTTON[1-5]_MASK */
456   button = get_mouse_button_from_ns_event (event);
457   if (button >= 1 && button <= 5)
458     state = (1 << (button + 7));
459
460   return state;
461 }
462
463 static GdkModifierType
464 get_keyboard_modifiers_from_ns_event (NSEvent *nsevent)
465 {
466   GdkModifierType modifiers = 0;
467   int nsflags;
468
469   nsflags = [nsevent modifierFlags];
470   
471   if (nsflags & NSAlphaShiftKeyMask)
472     modifiers |= GDK_LOCK_MASK;
473   if (nsflags & NSShiftKeyMask)
474     modifiers |= GDK_SHIFT_MASK;
475   if (nsflags & NSControlKeyMask)
476     modifiers |= GDK_CONTROL_MASK;
477   if (nsflags & NSCommandKeyMask)
478     modifiers |= GDK_META_MASK;
479   if (nsflags & NSAlternateKeyMask)
480     modifiers |= GDK_MOD1_MASK;
481
482   return modifiers;
483 }
484
485 /* Return an event mask from an NSEvent */
486 static GdkEventMask
487 get_event_mask_from_ns_event (NSEvent *nsevent)
488 {
489   switch ([nsevent type])
490     {
491     case NSLeftMouseDown:
492     case NSRightMouseDown:
493     case NSOtherMouseDown:
494       return GDK_BUTTON_PRESS_MASK;
495     case NSLeftMouseUp:
496     case NSRightMouseUp:
497     case NSOtherMouseUp:
498       return GDK_BUTTON_RELEASE_MASK;
499     case NSMouseMoved:
500       return GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK;
501     case NSScrollWheel:
502       /* Since applications that want button press events can get
503        * scroll events on X11 (since scroll wheel events are really
504        * button press events there), we need to use GDK_BUTTON_PRESS_MASK too.
505        */
506       return GDK_SCROLL_MASK | GDK_BUTTON_PRESS_MASK;
507     case NSLeftMouseDragged:
508       return (GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK |
509               GDK_BUTTON_MOTION_MASK | GDK_BUTTON1_MOTION_MASK | 
510               GDK_BUTTON1_MASK);
511     case NSRightMouseDragged:
512       return (GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK |
513               GDK_BUTTON_MOTION_MASK | GDK_BUTTON3_MOTION_MASK | 
514               GDK_BUTTON3_MASK);
515     case NSOtherMouseDragged:
516       {
517         GdkEventMask mask;
518
519         mask = (GDK_POINTER_MOTION_MASK |
520                 GDK_POINTER_MOTION_HINT_MASK |
521                 GDK_BUTTON_MOTION_MASK);
522
523         if (get_mouse_button_from_ns_event (nsevent) == 2)
524           mask |= (GDK_BUTTON2_MOTION_MASK | GDK_BUTTON2_MOTION_MASK | 
525                    GDK_BUTTON2_MASK);
526
527         return mask;
528       }
529     case NSKeyDown:
530     case NSKeyUp:
531     case NSFlagsChanged:
532       {
533         switch (_gdk_quartz_keys_event_type (nsevent))
534           {
535           case GDK_KEY_PRESS:
536             return GDK_KEY_PRESS_MASK;
537           case GDK_KEY_RELEASE:
538             return GDK_KEY_RELEASE_MASK;
539           case GDK_NOTHING:
540             return 0;
541           default:
542             g_assert_not_reached ();
543           }
544       }
545     default:
546       g_assert_not_reached ();
547     }
548
549   return 0;
550 }
551
552 static GdkEvent *
553 create_focus_event (GdkWindow *window,
554                     gboolean   in)
555 {
556   GdkEvent *event;
557
558   event = gdk_event_new (GDK_FOCUS_CHANGE);
559   event->focus_change.window = window;
560   event->focus_change.in = in;
561
562   return event;
563 }
564
565 /* Note: Used to both set a new focus window and to unset the old one. */
566 void
567 _gdk_quartz_events_update_focus_window (GdkWindow *window,
568                                         gboolean   got_focus)
569 {
570   GdkEvent *event;
571
572   if (got_focus && window == current_keyboard_window)
573     return;
574
575   /* FIXME: Don't do this when grabbed? Or make GdkQuartzWindow
576    * disallow it in the first place instead?
577    */
578   
579   if (!got_focus && window == current_keyboard_window)
580     {
581       event = create_focus_event (current_keyboard_window, FALSE);
582       append_event (event);
583       g_object_unref (current_keyboard_window);
584       current_keyboard_window = NULL;
585     }
586
587   if (got_focus)
588     {
589       if (current_keyboard_window)
590         {
591           event = create_focus_event (current_keyboard_window, FALSE);
592           append_event (event);
593           g_object_unref (current_keyboard_window);
594           current_keyboard_window = NULL;
595         }
596       
597       event = create_focus_event (window, TRUE);
598       append_event (event);
599       current_keyboard_window = g_object_ref (window);
600     }
601 }
602
603 static void
604 convert_window_coordinates_to_root (GdkWindow *window,
605                                     gdouble    x,
606                                     gdouble    y,
607                                     gdouble   *x_root,
608                                     gdouble   *y_root)
609 {
610   gint ox, oy;
611
612   *x_root = x;
613   *y_root = y;
614   
615   if (gdk_window_get_origin (window, &ox, &oy))
616     {
617       *x_root += ox;
618       *y_root += oy;
619     }
620 }
621
622 /* FIXME: Refactor and share with scroll event. */
623 static GdkEvent *
624 create_crossing_event (GdkWindow      *window, 
625                        NSEvent        *nsevent, 
626                        GdkEventType    event_type,
627                        GdkCrossingMode mode, 
628                        GdkNotifyType   detail)
629 {
630   GdkEvent *event;
631   gint x_tmp, y_tmp;
632
633   event = gdk_event_new (event_type);
634
635   event->crossing.window = window;
636   event->crossing.subwindow = NULL; /* FIXME */
637   event->crossing.time = get_time_from_ns_event (nsevent);
638
639   /* Split out this block: */
640   {
641     NSWindow *nswindow;
642     GdkWindow *toplevel;
643     GdkWindowImplQuartz *impl;
644     NSPoint point;
645
646     nswindow = [nsevent window];
647     point = [nsevent locationInWindow];
648
649     toplevel = [(GdkQuartzView *)[nswindow contentView] gdkWindow];
650
651     impl = GDK_WINDOW_IMPL_QUARTZ (GDK_WINDOW_OBJECT (toplevel)->impl);
652
653     x_tmp = point.x;
654     y_tmp = impl->height - point.y;
655
656     get_converted_window_coordinates (toplevel,
657                                       x_tmp, y_tmp,
658                                       window,
659                                       &x_tmp, &y_tmp);
660     }
661
662   event->crossing.x = x_tmp;
663   event->crossing.y = y_tmp;
664
665   convert_window_coordinates_to_root (window, 
666                                       event->crossing.x, 
667                                       event->crossing.y, 
668                                       &event->crossing.x_root,
669                                       &event->crossing.y_root);
670
671   event->crossing.mode = mode;
672   event->crossing.detail = detail;
673   event->crossing.state = get_keyboard_modifiers_from_ns_event (nsevent);
674
675   /* FIXME: focus and button state */
676
677   return event;
678 }
679
680 static void
681 synthesize_enter_event (GdkWindow      *window,
682                         NSEvent        *nsevent,
683                         GdkCrossingMode mode,
684                         GdkNotifyType   detail)
685 {
686   GdkEvent *event;
687
688   if (_gdk_quartz_pointer_grab_window != NULL && 
689       !pointer_grab_owner_events && 
690       !(pointer_grab_event_mask & GDK_ENTER_NOTIFY_MASK))
691     return;
692
693   if (!(GDK_WINDOW_OBJECT (window)->event_mask & GDK_ENTER_NOTIFY_MASK))
694     return;
695
696   event = create_crossing_event (window, nsevent, GDK_ENTER_NOTIFY,
697                                  mode, detail);
698
699   append_event (event);
700 }
701   
702 static void
703 synthesize_enter_events (GdkWindow      *from,
704                          GdkWindow      *to,
705                          NSEvent        *nsevent,
706                          GdkCrossingMode mode,
707                          GdkNotifyType   detail)
708 {
709   GdkWindow *prev = gdk_window_get_parent (to);
710
711   if (prev != from)
712     synthesize_enter_events (from, prev, nsevent, mode, detail);
713   synthesize_enter_event (to, nsevent, mode, detail);
714 }
715
716 static void
717 synthesize_leave_event (GdkWindow      *window,
718                         NSEvent        *nsevent,
719                         GdkCrossingMode mode,
720                         GdkNotifyType   detail)
721 {
722   GdkEvent *event;
723
724   if (_gdk_quartz_pointer_grab_window != NULL && 
725       !pointer_grab_owner_events && 
726       !(pointer_grab_event_mask & GDK_LEAVE_NOTIFY_MASK))
727     return;
728
729   if (!(GDK_WINDOW_OBJECT (window)->event_mask & GDK_LEAVE_NOTIFY_MASK))
730     return;
731
732   event = create_crossing_event (window, nsevent, GDK_LEAVE_NOTIFY,
733                                  mode, detail);
734
735   append_event (event);
736 }
737                          
738 static void
739 synthesize_leave_events (GdkWindow      *from,
740                          GdkWindow      *to,
741                          NSEvent        *nsevent,
742                          GdkCrossingMode mode,
743                          GdkNotifyType   detail)
744 {
745   GdkWindow *next = gdk_window_get_parent (from);
746   
747   synthesize_leave_event (from, nsevent, mode, detail);
748   if (next != to)
749     synthesize_leave_events (next, to, nsevent, mode, detail);
750 }
751                          
752 static void
753 synthesize_crossing_events (GdkWindow      *window,
754                             GdkCrossingMode mode,
755                             NSEvent        *nsevent,
756                             gint            x,
757                             gint            y)
758 {
759   GdkWindow *intermediate, *tem, *common_ancestor;
760
761   if (window == current_mouse_window)
762     return;
763
764   if (_gdk_quartz_window_is_ancestor (current_mouse_window, window))
765     {
766       /* Pointer has moved to an inferior window. */
767       synthesize_leave_event (current_mouse_window, nsevent, mode, GDK_NOTIFY_INFERIOR);
768
769       /* If there are intermediate windows, generate ENTER_NOTIFY
770        * events for them
771        */
772       intermediate = gdk_window_get_parent (window);
773
774       if (intermediate != current_mouse_window)
775         {
776           synthesize_enter_events (current_mouse_window, intermediate, nsevent, mode, GDK_NOTIFY_VIRTUAL);
777         }
778
779       synthesize_enter_event (window, nsevent, mode, GDK_NOTIFY_ANCESTOR);
780     }
781   else if (_gdk_quartz_window_is_ancestor (window, current_mouse_window))
782     {
783       /* Pointer has moved to an ancestor window. */
784       synthesize_leave_event (current_mouse_window, nsevent, mode, GDK_NOTIFY_ANCESTOR);
785       
786       /* If there are intermediate windows, generate LEAVE_NOTIFY
787        * events for them
788        */
789       intermediate = gdk_window_get_parent (current_mouse_window);
790       if (intermediate != window)
791         {
792           synthesize_leave_events (intermediate, window, nsevent, mode, GDK_NOTIFY_VIRTUAL);
793         }
794
795       synthesize_enter_event (window, nsevent, mode, GDK_NOTIFY_INFERIOR);
796     }
797   else if (current_mouse_window)
798     {
799       /* Find least common ancestor of current_mouse_window and window */
800       tem = current_mouse_window;
801       do {
802         common_ancestor = gdk_window_get_parent (tem);
803         tem = common_ancestor;
804       } while (common_ancestor &&
805                !_gdk_quartz_window_is_ancestor (common_ancestor, window));
806       if (common_ancestor)
807         {
808           synthesize_leave_event (current_mouse_window, nsevent, mode, GDK_NOTIFY_NONLINEAR);
809           intermediate = gdk_window_get_parent (current_mouse_window);
810           if (intermediate != common_ancestor)
811             {
812               synthesize_leave_events (intermediate, common_ancestor,
813                                        nsevent, mode, GDK_NOTIFY_NONLINEAR_VIRTUAL);
814             }
815           intermediate = gdk_window_get_parent (window);
816           if (intermediate != common_ancestor)
817             {
818               synthesize_enter_events (common_ancestor, intermediate,
819                                        nsevent, mode, GDK_NOTIFY_NONLINEAR_VIRTUAL);
820             }
821           synthesize_enter_event (window, nsevent, mode, GDK_NOTIFY_NONLINEAR);
822         }
823     }
824   else
825     {
826       /* This means we have no current_mouse_window, which probably
827        * means that there is a bug somewhere, we should always have
828        * the root in we don't have another window. Does this ever
829        * happen?
830        */
831       g_warning ("Trying to create crossing event when current_mouse_window is NULL");
832     }
833
834   _gdk_quartz_events_update_mouse_window (window);
835
836   /* FIXME: This does't work when someone calls gdk_window_set_cursor
837    * during a grab. The right behavior is that the cursor doesn't
838    * change when a grab is in effect, but in that case it does.
839    */
840   if (window && !_gdk_quartz_pointer_grab_window)
841     _gdk_quartz_events_update_cursor (window);
842 }
843
844 void 
845 _gdk_quartz_events_send_map_events (GdkWindow *window)
846 {
847   GList *list;
848   GdkWindow *interested_window;
849   GdkWindowObject *private = (GdkWindowObject *)window;
850
851   interested_window = find_window_interested_in_event_mask (window, 
852                                                             GDK_STRUCTURE_MASK,
853                                                             TRUE);
854   
855   if (interested_window)
856     {
857       GdkEvent *event = gdk_event_new (GDK_MAP);
858       event->any.window = interested_window;
859       append_event (event);
860     }
861
862   for (list = private->children; list != NULL; list = list->next)
863     _gdk_quartz_events_send_map_events ((GdkWindow *)list->data);
864 }
865
866 /* Get current mouse window */
867 GdkWindow *
868 _gdk_quartz_events_get_mouse_window (gboolean consider_grabs)
869 {
870   if (!consider_grabs)
871     return current_mouse_window;
872
873   if (_gdk_quartz_pointer_grab_window && !pointer_grab_owner_events)
874     return _gdk_quartz_pointer_grab_window;
875   
876   return current_mouse_window;
877 }
878
879 /* Update mouse window */
880 void 
881 _gdk_quartz_events_update_mouse_window (GdkWindow *window)
882 {
883   if (window == current_mouse_window)
884     return;
885
886 #ifdef G_ENABLE_DEBUG
887   if (_gdk_debug_flags & GDK_DEBUG_EVENTS)
888     _gdk_quartz_window_debug_highlight (window, 0);
889 #endif /* G_ENABLE_DEBUG */  
890
891   if (window)
892     g_object_ref (window);
893   if (current_mouse_window)
894     g_object_unref (current_mouse_window);
895
896   current_mouse_window = window;
897 }
898
899 /* Update current cursor */
900 void
901 _gdk_quartz_events_update_cursor (GdkWindow *window)
902 {
903   GdkWindowObject *private = GDK_WINDOW_OBJECT (window);
904   NSCursor *nscursor = nil;
905
906   while (private)
907     {
908       GdkWindowImplQuartz *impl = GDK_WINDOW_IMPL_QUARTZ (private->impl);
909
910       nscursor = impl->nscursor;
911       if (nscursor)
912         break;
913
914       private = private->parent;
915     }
916
917   GDK_QUARTZ_ALLOC_POOL;
918
919   if (!nscursor)
920     nscursor = [NSCursor arrowCursor];
921
922   if ([NSCursor currentCursor] != nscursor)
923     [nscursor set];
924
925   GDK_QUARTZ_RELEASE_POOL;
926 }
927
928 /* Translates coordinates from an ancestor window + coords, to
929  * coordinates that are relative the child window.
930  */
931 static void
932 get_child_coordinates_from_ancestor (GdkWindow *ancestor_window,
933                                      gint       ancestor_x,
934                                      gint       ancestor_y,
935                                      GdkWindow *child_window, 
936                                      gint      *child_x, 
937                                      gint      *child_y)
938 {
939   GdkWindowObject *ancestor_private = GDK_WINDOW_OBJECT (ancestor_window);
940   GdkWindowObject *child_private = GDK_WINDOW_OBJECT (child_window);
941
942   while (child_private != ancestor_private)
943     {
944       ancestor_x -= child_private->x;
945       ancestor_y -= child_private->y;
946
947       child_private = child_private->parent;
948     }
949
950   *child_x = ancestor_x;
951   *child_y = ancestor_y;
952 }
953
954 /* Translates coordinates from a child window + coords, to
955  * coordinates that are relative the ancestor window.
956  */
957 static void
958 get_ancestor_coordinates_from_child (GdkWindow *child_window,
959                                      gint       child_x,
960                                      gint       child_y,
961                                      GdkWindow *ancestor_window, 
962                                      gint      *ancestor_x, 
963                                      gint      *ancestor_y)
964 {
965   GdkWindowObject *child_private = GDK_WINDOW_OBJECT (child_window);
966   GdkWindowObject *ancestor_private = GDK_WINDOW_OBJECT (ancestor_window);
967
968   while (child_private != ancestor_private)
969     {
970       child_x += child_private->x;
971       child_y += child_private->y;
972
973       child_private = child_private->parent;
974     }
975
976   *ancestor_x = child_x;
977   *ancestor_y = child_y;
978 }
979
980 /* Translates coordinates relative to one window (in_window) into
981  * coordinates relative to another window (out_window).
982  */
983 static void
984 get_converted_window_coordinates (GdkWindow *in_window,
985                                   gint       in_x,
986                                   gint       in_y,
987                                   GdkWindow *out_window, 
988                                   gint      *out_x, 
989                                   gint      *out_y)
990 {
991   GdkWindow *in_toplevel;
992   GdkWindow *out_toplevel;
993   int in_origin_x, in_origin_y;
994   int out_origin_x, out_origin_y;
995
996   if (in_window == out_window)
997     {
998       *out_x = in_x;
999       *out_y = in_y;
1000       return;
1001     }
1002
1003   /* First translate to "in" toplevel coordinates, then on to "out"
1004    * toplevel coordinates, and finally to "out" child (the passed in
1005    * window) coordinates.
1006    */
1007
1008   in_toplevel = gdk_window_get_toplevel (in_window);
1009   out_toplevel  = gdk_window_get_toplevel (out_window);
1010
1011   /* Translate in_x, in_y to "in" toplevel coordinates. */
1012   get_ancestor_coordinates_from_child (in_window, in_x, in_y,
1013                                        in_toplevel, &in_x, &in_y);
1014
1015   gdk_window_get_origin (in_toplevel, &in_origin_x, &in_origin_y);
1016   gdk_window_get_origin (out_toplevel, &out_origin_x, &out_origin_y);
1017
1018   /* Translate in_x, in_y to "out" toplevel coordinates. */
1019   in_x -= out_origin_x - in_origin_x;
1020   in_y -= out_origin_y - in_origin_y;
1021
1022   get_child_coordinates_from_ancestor (out_toplevel, 
1023                                        in_x, in_y,
1024                                        out_window,
1025                                        out_x, out_y);
1026 }
1027
1028 /* Given a mouse NSEvent (must be a mouse event for a GDK window),
1029  * finds the subwindow over which the pointer is located. Returns
1030  * coordinates relative to the found window. If no window is found,
1031  * returns the root window, and root window coordinates.
1032  */
1033 static GdkWindow *
1034 find_mouse_window_for_ns_event (NSEvent *nsevent,
1035                                 gint    *x_ret,
1036                                 gint    *y_ret)
1037 {
1038   GdkWindow *event_toplevel;
1039   GdkWindowImplQuartz *impl;
1040   GdkWindow *mouse_toplevel;
1041   GdkWindow *mouse_window;
1042   NSPoint point;
1043   gint x_tmp, y_tmp;
1044
1045   event_toplevel = [(GdkQuartzView *)[[nsevent window] contentView] gdkWindow];
1046   impl = GDK_WINDOW_IMPL_QUARTZ (GDK_WINDOW_OBJECT (event_toplevel)->impl);
1047   point = [nsevent locationInWindow];
1048
1049   x_tmp = point.x;
1050   y_tmp = impl->height - point.y;
1051
1052   mouse_toplevel = gdk_window_get_toplevel (current_mouse_window);
1053
1054   get_converted_window_coordinates (event_toplevel,
1055                                     x_tmp, y_tmp,
1056                                     mouse_toplevel,
1057                                     &x_tmp, &y_tmp);
1058
1059   mouse_window = _gdk_quartz_window_find_child (mouse_toplevel, x_tmp, y_tmp);
1060   if (mouse_window && mouse_window != mouse_toplevel)
1061     {
1062       get_child_coordinates_from_ancestor (mouse_toplevel,
1063                                            x_tmp, y_tmp,
1064                                            mouse_window,
1065                                            &x_tmp, &y_tmp);
1066     }
1067   else if (!mouse_window)
1068     {
1069       /* This happens for events on the window title buttons and the
1070        * desktop, treat those as being on the root window.
1071        */
1072       get_converted_window_coordinates (mouse_toplevel,
1073                                         x_tmp, y_tmp,
1074                                         _gdk_root,
1075                                         &x_tmp, &y_tmp);
1076       mouse_window = _gdk_root;
1077     }
1078
1079   *x_ret = x_tmp;
1080   *y_ret = y_tmp;
1081
1082   return mouse_window;
1083 }
1084
1085 /* Trigger crossing events if necessary. This is used when showing a new
1086  * window, since the tracking rect API doesn't work reliably when a window
1087  * shows up under the mouse cursor. It's done by finding the topmost window
1088  * under the mouse pointer and synthesizing crossing events into that
1089  * window.
1090  */
1091 void
1092 _gdk_quartz_events_trigger_crossing_events (gboolean defer_to_mainloop)
1093 {
1094   NSPoint point;
1095   gint x, y; 
1096   gint x_toplevel, y_toplevel;
1097   GdkWindow *mouse_window;
1098   GdkWindow *toplevel;
1099   GdkWindowImplQuartz *impl;
1100   guint flags = 0;
1101   NSTimeInterval timestamp = 0;
1102   NSEvent *current_event;
1103   NSEvent *nsevent;
1104
1105   if (defer_to_mainloop)
1106     {
1107       nsevent = [NSEvent otherEventWithType:NSApplicationDefined
1108                                    location:NSZeroPoint
1109                               modifierFlags:0
1110                                   timestamp:0
1111                                windowNumber:0
1112                                     context:nil
1113                                     subtype:GDK_QUARTZ_EVENT_SUBTYPE_FAKE_CROSSING
1114                                       data1:0
1115                                       data2:0];
1116       [NSApp postEvent:nsevent atStart:NO];
1117       return;
1118     }
1119
1120   point = [NSEvent mouseLocation];
1121   x = point.x;
1122   y = _gdk_quartz_window_get_inverted_screen_y (point.y);
1123
1124   mouse_window = _gdk_quartz_window_find_child (_gdk_root, x, y);
1125   if (!mouse_window || mouse_window == _gdk_root)
1126     return;
1127
1128   toplevel = gdk_window_get_toplevel (mouse_window);
1129
1130   /* We ignore crossing within the same toplevel since that is already
1131    * handled elsewhere.
1132    */
1133   if (toplevel == gdk_window_get_toplevel (current_mouse_window))
1134     return;
1135
1136   get_converted_window_coordinates (_gdk_root,
1137                                     x, y,
1138                                     toplevel,
1139                                     &x_toplevel, &y_toplevel);
1140
1141   get_converted_window_coordinates (_gdk_root,
1142                                     x, y,
1143                                     mouse_window,
1144                                     &x, &y);
1145
1146   /* Fix up the event to be less fake if possible. */
1147   current_event = [NSApp currentEvent];
1148   if (current_event)
1149     {
1150       flags = [current_event modifierFlags];
1151       timestamp = [current_event timestamp];
1152     }
1153
1154   if (timestamp == 0)
1155     timestamp = GetCurrentEventTime ();
1156
1157   impl = GDK_WINDOW_IMPL_QUARTZ (GDK_WINDOW_OBJECT (toplevel)->impl);
1158   nsevent = [NSEvent otherEventWithType:NSApplicationDefined
1159                                location:NSMakePoint (x_toplevel, impl->height - y_toplevel)
1160                           modifierFlags:flags
1161                               timestamp:timestamp
1162                            windowNumber:[impl->toplevel windowNumber]
1163                                 context:nil
1164                                 subtype:GDK_QUARTZ_EVENT_SUBTYPE_FAKE_CROSSING
1165                                   data1:0
1166                                   data2:0];
1167
1168 #ifdef G_ENABLE_DEBUG
1169   /*_gdk_quartz_window_debug_highlight (mouse_window, 0);*/
1170 #endif
1171
1172   synthesize_crossing_events (mouse_window, GDK_CROSSING_NORMAL, nsevent, x, y);
1173 }
1174
1175 /* Synthesizes crossing events if necessary, based on the passed in
1176  * NSEvent. Uses NSMouseEntered and NSMouseExisted for toplevels and
1177  * the mouse moved/dragged events for child windows, to see if the
1178  * mouse window has changed.
1179  */
1180 static void
1181 synthesize_crossing_events_for_ns_event (NSEvent *nsevent)
1182 {
1183   NSEventType event_type;
1184   GdkWindow *mouse_window;
1185   gint x; 
1186   gint y;
1187
1188   event_type = [nsevent type];
1189
1190   switch (event_type)
1191     {
1192     case NSMouseMoved:
1193     case NSLeftMouseDragged:
1194     case NSRightMouseDragged:
1195     case NSOtherMouseDragged:
1196       /* We only handle moving the pointer to another GDK window.
1197        * Leaving to a non-GDK toplevel window (or window title bar or
1198        * the desktop) is covered by NSMouseExited events.
1199        */
1200       mouse_window = find_mouse_window_for_ns_event (nsevent, &x, &y);
1201       if (mouse_window != _gdk_root)
1202         synthesize_crossing_events (mouse_window, GDK_CROSSING_NORMAL, nsevent, x, y);
1203
1204       break;
1205
1206     case NSMouseEntered:
1207       {
1208         GdkWindow *event_toplevel;
1209         GdkWindowImplQuartz *impl;
1210         NSPoint point;
1211
1212         /* This is the only case where we actually use the window from
1213          * the event since we need to know which toplevel we entered
1214          * so it can be tracked properly.
1215          */
1216         event_toplevel = [(GdkQuartzView *)[[nsevent window] contentView] gdkWindow];
1217         impl = GDK_WINDOW_IMPL_QUARTZ (GDK_WINDOW_OBJECT (event_toplevel)->impl);
1218
1219         point = [nsevent locationInWindow];
1220
1221         x = point.x;
1222         y = impl->height - point.y;
1223
1224         mouse_window = _gdk_quartz_window_find_child (event_toplevel, x, y);
1225
1226         /* Treat unknown windows (like the title bar buttons or
1227          * desktop) as the root window.
1228          */
1229         if (!mouse_window)
1230           mouse_window = _gdk_root;
1231
1232         if (mouse_window != event_toplevel)
1233           get_converted_window_coordinates (event_toplevel,
1234                                             x, y,
1235                                             mouse_window,
1236                                             &x, &y);
1237
1238         synthesize_crossing_events (mouse_window, GDK_CROSSING_NORMAL, nsevent, x, y);
1239       }
1240       break;
1241
1242     case NSMouseExited:
1243       {
1244         GdkWindow *event_toplevel;
1245         GdkWindowImplQuartz *impl;
1246         NSPoint point;
1247
1248         /* We only use NSMouseExited when leaving to the root
1249          * window. The other cases are handled above by checking the
1250          * motion/button events, or getting a NSMouseEntered for
1251          * another GDK window. The reason we don't use NSMouseExited
1252          * for other windows is that quartz first delivers the entered
1253          * event and then the exited which is the opposite from what
1254          * we need.
1255          */
1256         event_toplevel = [(GdkQuartzView *)[[nsevent window] contentView] gdkWindow];
1257         impl = GDK_WINDOW_IMPL_QUARTZ (GDK_WINDOW_OBJECT (event_toplevel)->impl);
1258         point = [nsevent locationInWindow];
1259
1260         x = point.x;
1261         y = impl->height - point.y;
1262
1263         x += GDK_WINDOW_OBJECT (event_toplevel)->x;
1264         y += GDK_WINDOW_OBJECT (event_toplevel)->y;
1265
1266         /* If there is a window other than the root window at this
1267          * position, it means we didn't exit to the root window and we
1268          * ignore the event. (Note that we can get NULL here when swithing
1269          * spaces for example.)
1270          *
1271          * FIXME: This is not enough, it doesn't catch the case where
1272          * we leave a GDK window to a non-GDK window that has GDK
1273          * windows below it.
1274          */
1275         mouse_window = _gdk_quartz_window_find_child (_gdk_root, x, y);
1276
1277         if (!mouse_window ||
1278             gdk_window_get_toplevel (mouse_window) ==
1279             gdk_window_get_toplevel (current_mouse_window))
1280           {
1281             mouse_window = _gdk_root;
1282           }
1283
1284         if (mouse_window == _gdk_root)
1285           synthesize_crossing_events (_gdk_root, GDK_CROSSING_NORMAL, nsevent, x, y);
1286       }
1287       break;
1288
1289     default:
1290       break;
1291     }
1292 }
1293
1294 /* This function finds the correct window to send an event to, taking
1295  * into account grabs, event propagation, and event masks.
1296  */
1297 static GdkWindow *
1298 find_window_for_ns_event (NSEvent *nsevent, 
1299                           gint    *x, 
1300                           gint    *y)
1301 {
1302   NSEventType event_type;
1303
1304   event_type = [nsevent type];
1305
1306   switch (event_type)
1307     {
1308     case NSLeftMouseDown:
1309     case NSRightMouseDown:
1310     case NSOtherMouseDown:
1311     case NSLeftMouseUp:
1312     case NSRightMouseUp:
1313     case NSOtherMouseUp:
1314     case NSMouseMoved:
1315     case NSScrollWheel:
1316     case NSLeftMouseDragged:
1317     case NSRightMouseDragged:
1318     case NSOtherMouseDragged:
1319       {
1320         GdkWindow *mouse_window;
1321         GdkEventMask event_mask;
1322         GdkWindow *real_window;
1323
1324         /* From the docs for XGrabPointer:
1325          *
1326          * If owner_events is True and if a generated pointer event
1327          * would normally be reported to this client, it is reported
1328          * as usual. Otherwise, the event is reported with respect to
1329          * the grab_window and is reported only if selected by
1330          * event_mask. For either value of owner_events, unreported
1331          * events are discarded.
1332          *
1333          * This means we first try the owner, then the grab window,
1334          * then give up.
1335          */
1336         if (_gdk_quartz_pointer_grab_window)
1337           {
1338             if (pointer_grab_owner_events)
1339               {
1340                 mouse_window = find_mouse_window_for_ns_event (nsevent, x, y);
1341                 event_mask = get_event_mask_from_ns_event (nsevent);
1342                 real_window = find_window_interested_in_event_mask (mouse_window, event_mask, TRUE);
1343                 
1344                 if (mouse_window && real_window && mouse_window != real_window)
1345                   get_ancestor_coordinates_from_child (mouse_window,
1346                                                        *x, *y,
1347                                                        real_window,
1348                                                        x, y);
1349
1350                 if (real_window)
1351                   return real_window;
1352               }
1353
1354             /* Finally check the grab window. */
1355             if (pointer_grab_event_mask & get_event_mask_from_ns_event (nsevent))
1356               {
1357                 GdkWindow *event_toplevel;
1358                 GdkWindow *grab_toplevel;
1359                 NSPoint point;
1360                 int x_tmp, y_tmp;
1361
1362                 event_toplevel = [(GdkQuartzView *)[[nsevent window] contentView] gdkWindow];
1363                 grab_toplevel = gdk_window_get_toplevel (_gdk_quartz_pointer_grab_window);
1364                 point = [nsevent locationInWindow];
1365
1366                 x_tmp = point.x;
1367                 y_tmp = GDK_WINDOW_IMPL_QUARTZ (GDK_WINDOW_OBJECT (grab_toplevel)->impl)->height - point.y;
1368
1369                 /* Translate the coordinates so they are relative to
1370                  * the grab window instead of the event toplevel for
1371                  * the cases where they are not the same.
1372                  */
1373                 get_converted_window_coordinates (event_toplevel,
1374                                                   x_tmp, y_tmp,
1375                                                   _gdk_quartz_pointer_grab_window,
1376                                                   x, y);
1377
1378                 return _gdk_quartz_pointer_grab_window;
1379               }
1380
1381             return NULL;
1382           }
1383         else 
1384           {
1385             /* The non-grabbed case. */
1386             mouse_window = find_mouse_window_for_ns_event (nsevent, x, y);
1387             event_mask = get_event_mask_from_ns_event (nsevent);
1388             real_window = find_window_interested_in_event_mask (mouse_window, event_mask, TRUE);
1389             
1390             /* We have to translate the coordinates if the actual
1391              * window is different from the mouse window.
1392              */
1393             if (mouse_window && real_window && mouse_window != real_window)
1394               get_ancestor_coordinates_from_child (mouse_window,
1395                                                    *x, *y,
1396                                                    real_window,
1397                                                    x, y);
1398
1399             return real_window;
1400           }
1401       }
1402       break;
1403       
1404     case NSMouseEntered:
1405     case NSMouseExited:
1406       /* Already handled in synthesize_crossing_events_for_ns_event. */
1407       break;
1408
1409     case NSKeyDown:
1410     case NSKeyUp:
1411     case NSFlagsChanged:
1412       {
1413         GdkEventMask event_mask;
1414
1415         if (_gdk_quartz_keyboard_grab_window && !keyboard_grab_owner_events)
1416           return _gdk_quartz_keyboard_grab_window;
1417
1418         event_mask = get_event_mask_from_ns_event (nsevent);
1419         return find_window_interested_in_event_mask (current_keyboard_window, event_mask, TRUE);
1420       }
1421       break;
1422
1423     default:
1424       /* Ignore everything else. */
1425       break;
1426     }
1427
1428   return NULL;
1429 }
1430
1431 static GdkEvent *
1432 create_button_event (GdkWindow *window, 
1433                      NSEvent   *nsevent,
1434                      gint       x,
1435                      gint       y)
1436 {
1437   GdkEvent *event;
1438   GdkEventType type;
1439   gint state;
1440   gint button;
1441
1442   state = get_keyboard_modifiers_from_ns_event (nsevent);
1443
1444   switch ([nsevent type])
1445     {
1446     case NSLeftMouseDown:
1447     case NSRightMouseDown:
1448     case NSOtherMouseDown:
1449       type = GDK_BUTTON_PRESS;
1450       break;
1451     case NSLeftMouseUp:
1452     case NSRightMouseUp:
1453     case NSOtherMouseUp:
1454       type = GDK_BUTTON_RELEASE;
1455       state |= get_mouse_button_modifiers_from_ns_event (nsevent);
1456       break;
1457     default:
1458       g_assert_not_reached ();
1459     }
1460   
1461   button = get_mouse_button_from_ns_event (nsevent);
1462
1463   event = gdk_event_new (type);
1464   event->button.window = window;
1465   event->button.time = get_time_from_ns_event (nsevent);
1466   event->button.x = x;
1467   event->button.y = y;
1468   /* FIXME event->axes */
1469   event->button.state = state;
1470   event->button.button = button;
1471   event->button.device = _gdk_display->core_pointer;
1472   convert_window_coordinates_to_root (window, x, y, 
1473                                       &event->button.x_root,
1474                                       &event->button.y_root);
1475
1476   return event;
1477 }
1478
1479 static GdkEvent *
1480 create_motion_event (GdkWindow *window, 
1481                      NSEvent   *nsevent, 
1482                      gint       x, 
1483                      gint       y)
1484 {
1485   GdkEvent *event;
1486   GdkEventType type;
1487   GdkModifierType state = 0;
1488
1489   switch ([nsevent type])
1490     {
1491     case NSLeftMouseDragged:
1492     case NSRightMouseDragged:
1493     case NSOtherMouseDragged:
1494       state = get_mouse_button_modifiers_from_ns_event (nsevent);
1495       /* Fall through */
1496     case NSMouseMoved:
1497       type = GDK_MOTION_NOTIFY;
1498       break;
1499     default:
1500       g_assert_not_reached ();
1501     }
1502
1503   state |= get_keyboard_modifiers_from_ns_event (nsevent);
1504
1505   event = gdk_event_new (type);
1506   event->motion.window = window;
1507   event->motion.time = get_time_from_ns_event (nsevent);
1508   event->motion.x = x;
1509   event->motion.y = y;
1510   /* FIXME event->axes */
1511   event->motion.state = state;
1512   event->motion.is_hint = FALSE;
1513   event->motion.device = _gdk_display->core_pointer;
1514   convert_window_coordinates_to_root (window, x, y,
1515                                       &event->motion.x_root, &event->motion.y_root);
1516   
1517   return event;
1518 }
1519
1520 static GdkEvent *
1521 create_scroll_event (GdkWindow          *window, 
1522                      NSEvent            *nsevent, 
1523                      GdkScrollDirection  direction)
1524 {
1525   GdkEvent *event;
1526   NSPoint point;
1527   
1528   event = gdk_event_new (GDK_SCROLL);
1529   event->scroll.window = window;
1530   event->scroll.time = get_time_from_ns_event (nsevent);
1531
1532   point = [nsevent locationInWindow];
1533   event->scroll.x = point.x;
1534   event->scroll.y = point.y;
1535   event->scroll.state = get_keyboard_modifiers_from_ns_event (nsevent);
1536   convert_window_coordinates_to_root (window, event->scroll.x, event->scroll.y, 
1537                                       &event->scroll.x_root,
1538                                       &event->scroll.y_root);
1539
1540   event->scroll.direction = direction;
1541   event->scroll.device = _gdk_display->core_pointer;
1542   
1543   return event;
1544 }
1545
1546 static GdkEvent *
1547 create_key_event (GdkWindow    *window, 
1548                   NSEvent      *nsevent, 
1549                   GdkEventType  type)
1550 {
1551   GdkEvent *event;
1552   GdkEventPrivate *priv;
1553   gchar buf[7];
1554   gunichar c = 0;
1555
1556   event = gdk_event_new (type);
1557
1558   priv = (GdkEventPrivate *) event;
1559   priv->windowing_data = [nsevent retain];
1560
1561   event->key.window = window;
1562   event->key.time = get_time_from_ns_event (nsevent);
1563   event->key.state = get_keyboard_modifiers_from_ns_event (nsevent);
1564   event->key.hardware_keycode = [nsevent keyCode];
1565   event->key.group = ([nsevent modifierFlags] & NSAlternateKeyMask) ? 1 : 0;
1566
1567   event->key.keyval = GDK_VoidSymbol;
1568   
1569   gdk_keymap_translate_keyboard_state (NULL,
1570                                        event->key.hardware_keycode,
1571                                        event->key.state, 
1572                                        event->key.group,
1573                                        &event->key.keyval,
1574                                        NULL, NULL, NULL);
1575
1576   event->key.is_modifier = _gdk_quartz_keys_is_modifier (event->key.hardware_keycode);
1577
1578   /* If the key press is a modifier, the state should include the mask
1579    * for that modifier but only for releases, not presses. This
1580    * matches the X11 backend behavior.
1581    */
1582   if (event->key.is_modifier)
1583     {
1584       int mask = 0;
1585
1586       switch (event->key.keyval)
1587         {
1588         case GDK_Meta_R:
1589         case GDK_Meta_L:
1590           mask = GDK_META_MASK;
1591           break;
1592         case GDK_Shift_R:
1593         case GDK_Shift_L:
1594           mask = GDK_SHIFT_MASK;
1595           break;
1596         case GDK_Caps_Lock:
1597           mask = GDK_LOCK_MASK;
1598           break;
1599         case GDK_Alt_R:
1600         case GDK_Alt_L:
1601           mask = GDK_MOD1_MASK;
1602           break;
1603         case GDK_Control_R:
1604         case GDK_Control_L:
1605           mask = GDK_CONTROL_MASK;
1606           break;
1607         default:
1608           mask = 0;
1609         }
1610
1611       if (type == GDK_KEY_PRESS)
1612         event->key.state &= ~mask;
1613       else if (type == GDK_KEY_RELEASE)
1614         event->key.state |= mask;
1615     }
1616
1617   event->key.state |= current_button_state;
1618
1619   event->key.string = NULL;
1620
1621   /* Fill in ->string since apps depend on it, taken from the x11 backend. */
1622   if (event->key.keyval != GDK_VoidSymbol)
1623     c = gdk_keyval_to_unicode (event->key.keyval);
1624
1625     if (c)
1626     {
1627       gsize bytes_written;
1628       gint len;
1629
1630       len = g_unichar_to_utf8 (c, buf);
1631       buf[len] = '\0';
1632       
1633       event->key.string = g_locale_from_utf8 (buf, len,
1634                                               NULL, &bytes_written,
1635                                               NULL);
1636       if (event->key.string)
1637         event->key.length = bytes_written;
1638     }
1639   else if (event->key.keyval == GDK_Escape)
1640     {
1641       event->key.length = 1;
1642       event->key.string = g_strdup ("\033");
1643     }
1644   else if (event->key.keyval == GDK_Return ||
1645           event->key.keyval == GDK_KP_Enter)
1646     {
1647       event->key.length = 1;
1648       event->key.string = g_strdup ("\r");
1649     }
1650
1651   if (!event->key.string)
1652     {
1653       event->key.length = 0;
1654       event->key.string = g_strdup ("");
1655     }
1656
1657   GDK_NOTE(EVENTS,
1658     g_message ("key %s:\t\twindow: %p  key: %12s  %d",
1659           type == GDK_KEY_PRESS ? "press" : "release",
1660           event->key.window,
1661           event->key.keyval ? gdk_keyval_name (event->key.keyval) : "(none)",
1662           event->key.keyval));
1663   return event;
1664 }
1665
1666 GdkEventMask 
1667 _gdk_quartz_events_get_current_event_mask (void)
1668 {
1669   return current_event_mask;
1670 }
1671
1672 static gboolean
1673 gdk_event_translate (NSEvent *nsevent)
1674 {
1675   NSWindow *nswindow;
1676   GdkWindow *window;
1677   GdkFilterReturn result;
1678   GdkEvent *event;
1679   int x, y;
1680
1681   /* There is no support for real desktop wide grabs, so we break
1682    * grabs when the application loses focus (gets deactivated).
1683    */
1684   if ([nsevent type] == NSAppKitDefined)
1685     {
1686       if ([nsevent subtype] == NSApplicationDeactivatedEventType)
1687         break_all_grabs ();
1688
1689       /* This could potentially be used to break grabs when clicking
1690        * on the title. The subtype 20 is undocumented so it's probably
1691        * not a good idea: else if (subtype == 20) break_all_grabs ();
1692        */
1693     }
1694
1695   /* Handle our generated "fake" crossing events. */
1696   if ([nsevent type] == NSApplicationDefined && 
1697       [nsevent subtype] == GDK_QUARTZ_EVENT_SUBTYPE_FAKE_CROSSING)
1698     {
1699       _gdk_quartz_events_trigger_crossing_events (FALSE);
1700       return TRUE;
1701     }
1702
1703   /* Keep track of button state, since we don't get that information
1704    * for key events. 
1705    */
1706   switch ([nsevent type])
1707     {
1708     case NSLeftMouseDown:
1709     case NSRightMouseDown:
1710     case NSOtherMouseDown:
1711       current_button_state |= get_mouse_button_modifiers_from_ns_event (nsevent);
1712       break;
1713     case NSLeftMouseUp:
1714     case NSRightMouseUp:
1715     case NSOtherMouseUp:
1716       current_button_state &= ~get_mouse_button_modifiers_from_ns_event (nsevent);
1717       break;
1718     default:
1719       break;
1720     }
1721
1722   nswindow = [nsevent window];
1723
1724   /* Apply any global filters. */
1725   if (_gdk_default_filters)
1726     {
1727       result = apply_filters (NULL, nsevent, _gdk_default_filters);
1728
1729       /* If result is GDK_FILTER_CONTINUE, we continue as if nothing
1730        * happened. If it is GDK_FILTER_REMOVE,
1731        * we return TRUE and won't send the message to Quartz.
1732        */
1733       if (result == GDK_FILTER_REMOVE)
1734         return TRUE;
1735     }
1736
1737   /* Ignore events for no window or ones not created by GDK. */
1738   if (!nswindow || ![[nswindow contentView] isKindOfClass:[GdkQuartzView class]])
1739     return FALSE;
1740
1741   /* Ignore events and break grabs while the window is being
1742    * dragged. This is a workaround for the window getting events for
1743    * the window title.
1744    */
1745   if ([(GdkQuartzWindow *)nswindow isInMove])
1746     {
1747       break_all_grabs ();
1748       return FALSE;
1749     }
1750
1751   /* Take care of NSMouseEntered/Exited events and mouse movements
1752    * events and emit the right GDK crossing events.
1753    */
1754   synthesize_crossing_events_for_ns_event (nsevent);
1755
1756   /* Find the right GDK window to send the event to, taking grabs and
1757    * event masks into consideration.
1758    */
1759   window = find_window_for_ns_event (nsevent, &x, &y);
1760   if (!window)
1761     return FALSE;
1762
1763   /* Apply any window filters. */
1764   result = apply_filters (window, nsevent, ((GdkWindowObject *) window)->filters);
1765   if (result == GDK_FILTER_REMOVE)
1766     return TRUE;
1767
1768   /* We need the appliction to be activated on clicks so that popups
1769    * like context menus get events routed properly. This is handled
1770    * automatically for left mouse button presses but not other
1771    * buttons, so we do it here.
1772    */
1773   if ([nsevent type] == NSRightMouseDown || [nsevent type] == NSOtherMouseDown)
1774     {
1775       if (![NSApp isActive])
1776         [NSApp activateIgnoringOtherApps:YES];
1777     }
1778
1779   current_event_mask = get_event_mask_from_ns_event (nsevent);
1780
1781   switch ([nsevent type])
1782     {
1783     case NSLeftMouseDown:
1784     case NSRightMouseDown:
1785     case NSOtherMouseDown:
1786       {
1787         GdkEventMask event_mask;
1788
1789         /* Emulate implicit grab, when the window has both PRESS and RELEASE
1790          * in its mask, like X.
1791          */
1792         event_mask = (GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK);
1793         if (!_gdk_quartz_pointer_grab_window &&
1794             (GDK_WINDOW_OBJECT (window)->event_mask & event_mask) == event_mask)
1795           {
1796             pointer_grab_internal (window, FALSE,
1797                                    GDK_WINDOW_OBJECT (window)->event_mask,
1798                                    NULL, NULL, TRUE);
1799           }
1800       }
1801       
1802       event = create_button_event (window, nsevent, x, y);
1803       append_event (event);
1804       
1805       _gdk_event_button_generate (_gdk_display, event);
1806       break;
1807
1808     case NSLeftMouseUp:
1809     case NSRightMouseUp:
1810     case NSOtherMouseUp:
1811       event = create_button_event (window, nsevent, x, y);
1812       append_event (event);
1813       
1814       /* Ungrab implicit grab */
1815       if (_gdk_quartz_pointer_grab_window && pointer_grab_implicit)
1816         pointer_ungrab_internal (TRUE);
1817       break;
1818
1819     case NSLeftMouseDragged:
1820     case NSRightMouseDragged:
1821     case NSOtherMouseDragged:
1822     case NSMouseMoved:
1823       event = create_motion_event (window, nsevent, x, y);
1824       append_event (event);
1825       break;
1826
1827     case NSScrollWheel:
1828       {
1829         float dx = [nsevent deltaX];
1830         float dy = [nsevent deltaY];
1831         GdkScrollDirection direction;
1832
1833         /* The delta is how much the mouse wheel has moved. Since there's no such thing in GTK+
1834          * we accomodate by sending a different number of scroll wheel events.
1835          */
1836
1837         /* First do y events */
1838         if (dy < 0.0)
1839           {
1840             dy = -dy;
1841             direction = GDK_SCROLL_DOWN;
1842           }
1843         else
1844           direction = GDK_SCROLL_UP;
1845
1846         while (dy > 0.0)
1847           {
1848             event = create_scroll_event (window, nsevent, direction);
1849             append_event (event);
1850             dy--;
1851
1852             /* Ignore the delta for now, things get too slow when the events queue up. */
1853             break;
1854           }
1855
1856         /* Now do x events */
1857         if (dx < 0.0)
1858           {
1859             dx = -dx;
1860             direction = GDK_SCROLL_RIGHT;
1861           }
1862         else
1863           direction = GDK_SCROLL_LEFT;
1864
1865         while (dx > 0.0)
1866           {
1867             event = create_scroll_event (window, nsevent, direction);
1868             append_event (event);
1869             dx--;
1870             
1871             /* Ignore the delta for now, things get too slow when the events queue up. */
1872             break;
1873           }
1874
1875       }
1876       break;
1877
1878     case NSKeyDown:
1879     case NSKeyUp:
1880     case NSFlagsChanged:
1881       {
1882         GdkEventType type;
1883
1884         type = _gdk_quartz_keys_event_type (nsevent);
1885         if (type == GDK_NOTHING)
1886           return FALSE;
1887         
1888         event = create_key_event (window, nsevent, type);
1889         append_event (event);
1890         return TRUE;
1891       }
1892       break;
1893
1894     default:
1895       /* Ignore everything elsee. */
1896       break;
1897     }
1898
1899   return FALSE;
1900 }
1901
1902 void
1903 _gdk_events_queue (GdkDisplay *display)
1904 {  
1905   NSEvent *event;
1906
1907   event = _gdk_quartz_event_loop_get_pending ();
1908   if (event)
1909     {
1910       if (!gdk_event_translate (event))
1911         {
1912           GDK_THREADS_LEAVE ();
1913           [NSApp sendEvent:event];
1914           GDK_THREADS_ENTER ();
1915         }
1916
1917       _gdk_quartz_event_loop_release_event (event);
1918     }
1919 }
1920
1921 void
1922 gdk_flush (void)
1923 {
1924   /* Not supported. */
1925 }
1926
1927 void 
1928 gdk_display_add_client_message_filter (GdkDisplay   *display,
1929                                        GdkAtom       message_type,
1930                                        GdkFilterFunc func,
1931                                        gpointer      data)
1932 {
1933   /* Not supported. */
1934 }
1935
1936 void 
1937 gdk_add_client_message_filter (GdkAtom       message_type,
1938                                GdkFilterFunc func,
1939                                gpointer      data)
1940 {
1941   /* Not supported. */
1942 }
1943
1944 void
1945 gdk_display_sync (GdkDisplay *display)
1946 {
1947   /* Not supported. */
1948 }
1949
1950 void
1951 gdk_display_flush (GdkDisplay *display)
1952 {
1953   /* Not supported. */
1954 }
1955
1956 gboolean
1957 gdk_event_send_client_message_for_display (GdkDisplay      *display,
1958                                            GdkEvent        *event,
1959                                            GdkNativeWindow  winid)
1960 {
1961   /* Not supported. */
1962   return FALSE;
1963 }
1964
1965 void
1966 gdk_screen_broadcast_client_message (GdkScreen *screen,
1967                                      GdkEvent  *event)
1968 {
1969   /* Not supported. */
1970 }
1971
1972 gboolean
1973 gdk_screen_get_setting (GdkScreen   *screen,
1974                         const gchar *name,
1975                         GValue      *value)
1976 {
1977   if (strcmp (name, "gtk-double-click-time") == 0)
1978     {
1979       NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
1980       float t;
1981
1982       GDK_QUARTZ_ALLOC_POOL;
1983             
1984       t = [defaults floatForKey:@"com.apple.mouse.doubleClickThreshold"];
1985       if (t == 0.0)
1986         {
1987           /* No user setting, use the default in OS X. */
1988           t = 0.5;
1989         }
1990
1991       GDK_QUARTZ_RELEASE_POOL;
1992
1993       g_value_set_int (value, t * 1000);
1994       return TRUE;
1995     }
1996   
1997   /* FIXME: Add more settings */
1998
1999   return FALSE;
2000 }
2001
2002 void
2003 _gdk_windowing_event_data_copy (const GdkEvent *src,
2004                                 GdkEvent       *dst)
2005 {
2006   GdkEventPrivate *priv_src = (GdkEventPrivate *) src;
2007   GdkEventPrivate *priv_dst = (GdkEventPrivate *) dst;
2008
2009   if (priv_src->windowing_data)
2010     {
2011       priv_dst->windowing_data = priv_src->windowing_data;
2012       [(NSEvent *)priv_dst->windowing_data retain];
2013     }
2014 }
2015
2016 void
2017 _gdk_windowing_event_data_free (GdkEvent *event)
2018 {
2019   GdkEventPrivate *priv = (GdkEventPrivate *) event;
2020
2021   if (priv->windowing_data)
2022     {
2023       [(NSEvent *)priv->windowing_data release];
2024       priv->windowing_data = NULL;
2025     }
2026 }