]> Pileus Git - ~andy/gtk/blob - gdk/quartz/gdkevents-quartz.c
Remove width/height from GdkWindowImplQuartz and use those in GdkWindowObject
[~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 TRUE;
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_MOD1_MASK;
479
480   return modifiers;
481 }
482
483 /* Return an event mask from an NSEvent */
484 static GdkEventMask
485 get_event_mask_from_ns_event (NSEvent *nsevent)
486 {
487   switch ([nsevent type])
488     {
489     case NSLeftMouseDown:
490     case NSRightMouseDown:
491     case NSOtherMouseDown:
492       return GDK_BUTTON_PRESS_MASK;
493     case NSLeftMouseUp:
494     case NSRightMouseUp:
495     case NSOtherMouseUp:
496       return GDK_BUTTON_RELEASE_MASK;
497     case NSMouseMoved:
498       return GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK;
499     case NSScrollWheel:
500       /* Since applications that want button press events can get
501        * scroll events on X11 (since scroll wheel events are really
502        * button press events there), we need to use GDK_BUTTON_PRESS_MASK too.
503        */
504       return GDK_SCROLL_MASK | GDK_BUTTON_PRESS_MASK;
505     case NSLeftMouseDragged:
506       return (GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK |
507               GDK_BUTTON_MOTION_MASK | GDK_BUTTON1_MOTION_MASK | 
508               GDK_BUTTON1_MASK);
509     case NSRightMouseDragged:
510       return (GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK |
511               GDK_BUTTON_MOTION_MASK | GDK_BUTTON3_MOTION_MASK | 
512               GDK_BUTTON3_MASK);
513     case NSOtherMouseDragged:
514       {
515         GdkEventMask mask;
516
517         mask = (GDK_POINTER_MOTION_MASK |
518                 GDK_POINTER_MOTION_HINT_MASK |
519                 GDK_BUTTON_MOTION_MASK);
520
521         if (get_mouse_button_from_ns_event (nsevent) == 2)
522           mask |= (GDK_BUTTON2_MOTION_MASK | GDK_BUTTON2_MOTION_MASK | 
523                    GDK_BUTTON2_MASK);
524
525         return mask;
526       }
527     case NSKeyDown:
528     case NSKeyUp:
529     case NSFlagsChanged:
530       {
531         switch (_gdk_quartz_keys_event_type (nsevent))
532           {
533           case GDK_KEY_PRESS:
534             return GDK_KEY_PRESS_MASK;
535           case GDK_KEY_RELEASE:
536             return GDK_KEY_RELEASE_MASK;
537           case GDK_NOTHING:
538             return 0;
539           default:
540             g_assert_not_reached ();
541           }
542       }
543     default:
544       g_assert_not_reached ();
545     }
546
547   return 0;
548 }
549
550 static GdkEvent *
551 create_focus_event (GdkWindow *window,
552                     gboolean   in)
553 {
554   GdkEvent *event;
555
556   event = gdk_event_new (GDK_FOCUS_CHANGE);
557   event->focus_change.window = window;
558   event->focus_change.in = in;
559
560   return event;
561 }
562
563 /* Note: Used to both set a new focus window and to unset the old one. */
564 void
565 _gdk_quartz_events_update_focus_window (GdkWindow *window,
566                                         gboolean   got_focus)
567 {
568   GdkEvent *event;
569
570   if (got_focus && window == current_keyboard_window)
571     return;
572
573   /* FIXME: Don't do this when grabbed? Or make GdkQuartzWindow
574    * disallow it in the first place instead?
575    */
576   
577   if (!got_focus && window == current_keyboard_window)
578     {
579       event = create_focus_event (current_keyboard_window, FALSE);
580       append_event (event);
581       g_object_unref (current_keyboard_window);
582       current_keyboard_window = NULL;
583     }
584
585   if (got_focus)
586     {
587       if (current_keyboard_window)
588         {
589           event = create_focus_event (current_keyboard_window, FALSE);
590           append_event (event);
591           g_object_unref (current_keyboard_window);
592           current_keyboard_window = NULL;
593         }
594       
595       event = create_focus_event (window, TRUE);
596       append_event (event);
597       current_keyboard_window = g_object_ref (window);
598     }
599 }
600
601 static void
602 convert_window_coordinates_to_root (GdkWindow *window,
603                                     gdouble    x,
604                                     gdouble    y,
605                                     gdouble   *x_root,
606                                     gdouble   *y_root)
607 {
608   gint ox, oy;
609
610   *x_root = x;
611   *y_root = y;
612   
613   if (gdk_window_get_origin (window, &ox, &oy))
614     {
615       *x_root += ox;
616       *y_root += oy;
617     }
618 }
619
620 /* FIXME: Refactor and share with scroll event. */
621 static GdkEvent *
622 create_crossing_event (GdkWindow      *window, 
623                        NSEvent        *nsevent, 
624                        GdkEventType    event_type,
625                        GdkCrossingMode mode, 
626                        GdkNotifyType   detail)
627 {
628   GdkEvent *event;
629   gint x_tmp, y_tmp;
630
631   event = gdk_event_new (event_type);
632
633   event->crossing.window = window;
634   event->crossing.subwindow = NULL; /* FIXME */
635   event->crossing.time = get_time_from_ns_event (nsevent);
636
637   /* Split out this block: */
638   {
639     NSWindow *nswindow;
640     GdkWindow *toplevel;
641     GdkWindowImplQuartz *impl;
642     GdkWindowObject *private;
643     NSPoint point;
644
645     nswindow = [nsevent window];
646     point = [nsevent locationInWindow];
647
648     toplevel = [(GdkQuartzView *)[nswindow contentView] gdkWindow];
649
650     impl = GDK_WINDOW_IMPL_QUARTZ (GDK_WINDOW_OBJECT (toplevel)->impl);
651     private = GDK_WINDOW_OBJECT (toplevel);
652
653     x_tmp = point.x;
654     y_tmp = private->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   GdkWindowObject *private;
1041   GdkWindow *mouse_toplevel;
1042   GdkWindow *mouse_window;
1043   NSPoint point;
1044   gint x_tmp, y_tmp;
1045
1046   event_toplevel = [(GdkQuartzView *)[[nsevent window] contentView] gdkWindow];
1047   impl = GDK_WINDOW_IMPL_QUARTZ (GDK_WINDOW_OBJECT (event_toplevel)->impl);
1048   private = GDK_WINDOW_OBJECT (event_toplevel);
1049   point = [nsevent locationInWindow];
1050
1051   x_tmp = point.x;
1052   y_tmp = private->height - point.y;
1053
1054   mouse_toplevel = gdk_window_get_toplevel (current_mouse_window);
1055
1056   get_converted_window_coordinates (event_toplevel,
1057                                     x_tmp, y_tmp,
1058                                     mouse_toplevel,
1059                                     &x_tmp, &y_tmp);
1060
1061   mouse_window = _gdk_quartz_window_find_child (mouse_toplevel, x_tmp, y_tmp);
1062   if (mouse_window && mouse_window != mouse_toplevel)
1063     {
1064       get_child_coordinates_from_ancestor (mouse_toplevel,
1065                                            x_tmp, y_tmp,
1066                                            mouse_window,
1067                                            &x_tmp, &y_tmp);
1068     }
1069   else if (!mouse_window)
1070     {
1071       /* This happens for events on the window title buttons and the
1072        * desktop, treat those as being on the root window.
1073        */
1074       get_converted_window_coordinates (mouse_toplevel,
1075                                         x_tmp, y_tmp,
1076                                         _gdk_root,
1077                                         &x_tmp, &y_tmp);
1078       mouse_window = _gdk_root;
1079     }
1080
1081   *x_ret = x_tmp;
1082   *y_ret = y_tmp;
1083
1084   return mouse_window;
1085 }
1086
1087 /* Trigger crossing events if necessary. This is used when showing a new
1088  * window, since the tracking rect API doesn't work reliably when a window
1089  * shows up under the mouse cursor. It's done by finding the topmost window
1090  * under the mouse pointer and synthesizing crossing events into that
1091  * window.
1092  */
1093 void
1094 _gdk_quartz_events_trigger_crossing_events (gboolean defer_to_mainloop)
1095 {
1096   NSPoint point;
1097   gint x, y; 
1098   gint x_toplevel, y_toplevel;
1099   GdkWindow *mouse_window;
1100   GdkWindow *toplevel;
1101   GdkWindowImplQuartz *impl;
1102   GdkWindowObject *private;
1103   guint flags = 0;
1104   NSTimeInterval timestamp = 0;
1105   NSEvent *current_event;
1106   NSEvent *nsevent;
1107
1108   if (defer_to_mainloop)
1109     {
1110       nsevent = [NSEvent otherEventWithType:NSApplicationDefined
1111                                    location:NSZeroPoint
1112                               modifierFlags:0
1113                                   timestamp:0
1114                                windowNumber:0
1115                                     context:nil
1116                                     subtype:GDK_QUARTZ_EVENT_SUBTYPE_FAKE_CROSSING
1117                                       data1:0
1118                                       data2:0];
1119       [NSApp postEvent:nsevent atStart:NO];
1120       return;
1121     }
1122
1123   point = [NSEvent mouseLocation];
1124   x = point.x;
1125   y = _gdk_quartz_window_get_inverted_screen_y (point.y);
1126
1127   mouse_window = _gdk_quartz_window_find_child (_gdk_root, x, y);
1128   if (!mouse_window || mouse_window == _gdk_root)
1129     return;
1130
1131   toplevel = gdk_window_get_toplevel (mouse_window);
1132
1133   /* We ignore crossing within the same toplevel since that is already
1134    * handled elsewhere.
1135    */
1136   if (toplevel == gdk_window_get_toplevel (current_mouse_window))
1137     return;
1138
1139   get_converted_window_coordinates (_gdk_root,
1140                                     x, y,
1141                                     toplevel,
1142                                     &x_toplevel, &y_toplevel);
1143
1144   get_converted_window_coordinates (_gdk_root,
1145                                     x, y,
1146                                     mouse_window,
1147                                     &x, &y);
1148
1149   /* Fix up the event to be less fake if possible. */
1150   current_event = [NSApp currentEvent];
1151   if (current_event)
1152     {
1153       flags = [current_event modifierFlags];
1154       timestamp = [current_event timestamp];
1155     }
1156
1157   if (timestamp == 0)
1158     timestamp = GetCurrentEventTime ();
1159
1160   impl = GDK_WINDOW_IMPL_QUARTZ (GDK_WINDOW_OBJECT (toplevel)->impl);
1161   private = GDK_WINDOW_OBJECT (impl);
1162   nsevent = [NSEvent otherEventWithType:NSApplicationDefined
1163                                location:NSMakePoint (x_toplevel, private->height - y_toplevel)
1164                           modifierFlags:flags
1165                               timestamp:timestamp
1166                            windowNumber:[impl->toplevel windowNumber]
1167                                 context:nil
1168                                 subtype:GDK_QUARTZ_EVENT_SUBTYPE_FAKE_CROSSING
1169                                   data1:0
1170                                   data2:0];
1171
1172 #ifdef G_ENABLE_DEBUG
1173   /*_gdk_quartz_window_debug_highlight (mouse_window, 0);*/
1174 #endif
1175
1176   synthesize_crossing_events (mouse_window, GDK_CROSSING_NORMAL, nsevent, x, y);
1177 }
1178
1179 /* Synthesizes crossing events if necessary, based on the passed in
1180  * NSEvent. Uses NSMouseEntered and NSMouseExisted for toplevels and
1181  * the mouse moved/dragged events for child windows, to see if the
1182  * mouse window has changed.
1183  */
1184 static void
1185 synthesize_crossing_events_for_ns_event (NSEvent *nsevent)
1186 {
1187   NSEventType event_type;
1188   GdkWindow *mouse_window;
1189   gint x; 
1190   gint y;
1191
1192   event_type = [nsevent type];
1193
1194   switch (event_type)
1195     {
1196     case NSMouseMoved:
1197     case NSLeftMouseDragged:
1198     case NSRightMouseDragged:
1199     case NSOtherMouseDragged:
1200       /* We only handle moving the pointer to another GDK window.
1201        * Leaving to a non-GDK toplevel window (or window title bar or
1202        * the desktop) is covered by NSMouseExited events.
1203        */
1204       mouse_window = find_mouse_window_for_ns_event (nsevent, &x, &y);
1205       if (mouse_window != _gdk_root)
1206         synthesize_crossing_events (mouse_window, GDK_CROSSING_NORMAL, nsevent, x, y);
1207
1208       break;
1209
1210     case NSMouseEntered:
1211       {
1212         GdkWindow *event_toplevel;
1213         GdkWindowImplQuartz *impl;
1214         GdkWindowObject *private;
1215         NSPoint point;
1216
1217         /* This is the only case where we actually use the window from
1218          * the event since we need to know which toplevel we entered
1219          * so it can be tracked properly.
1220          */
1221         event_toplevel = [(GdkQuartzView *)[[nsevent window] contentView] gdkWindow];
1222         impl = GDK_WINDOW_IMPL_QUARTZ (GDK_WINDOW_OBJECT (event_toplevel)->impl);
1223         private = GDK_WINDOW_OBJECT (event_toplevel);
1224
1225         point = [nsevent locationInWindow];
1226
1227         x = point.x;
1228         y = private->height - point.y;
1229
1230         mouse_window = _gdk_quartz_window_find_child (event_toplevel, x, y);
1231
1232         /* Treat unknown windows (like the title bar buttons or
1233          * desktop) as the root window.
1234          */
1235         if (!mouse_window)
1236           mouse_window = _gdk_root;
1237
1238         if (mouse_window != event_toplevel)
1239           get_converted_window_coordinates (event_toplevel,
1240                                             x, y,
1241                                             mouse_window,
1242                                             &x, &y);
1243
1244         synthesize_crossing_events (mouse_window, GDK_CROSSING_NORMAL, nsevent, x, y);
1245       }
1246       break;
1247
1248     case NSMouseExited:
1249       {
1250         GdkWindow *event_toplevel;
1251         GdkWindowImplQuartz *impl;
1252         GdkWindowObject *private;
1253         NSPoint point;
1254
1255         /* We only use NSMouseExited when leaving to the root
1256          * window. The other cases are handled above by checking the
1257          * motion/button events, or getting a NSMouseEntered for
1258          * another GDK window. The reason we don't use NSMouseExited
1259          * for other windows is that quartz first delivers the entered
1260          * event and then the exited which is the opposite from what
1261          * we need.
1262          */
1263         event_toplevel = [(GdkQuartzView *)[[nsevent window] contentView] gdkWindow];
1264         impl = GDK_WINDOW_IMPL_QUARTZ (GDK_WINDOW_OBJECT (event_toplevel)->impl);
1265         private = GDK_WINDOW_OBJECT (event_toplevel);
1266         point = [nsevent locationInWindow];
1267
1268         x = point.x;
1269         y = private->height - point.y;
1270
1271         x += GDK_WINDOW_OBJECT (event_toplevel)->x;
1272         y += GDK_WINDOW_OBJECT (event_toplevel)->y;
1273
1274         /* If there is a window other than the root window at this
1275          * position, it means we didn't exit to the root window and we
1276          * ignore the event. (Note that we can get NULL here when swithing
1277          * spaces for example.)
1278          *
1279          * FIXME: This is not enough, it doesn't catch the case where
1280          * we leave a GDK window to a non-GDK window that has GDK
1281          * windows below it.
1282          */
1283         mouse_window = _gdk_quartz_window_find_child (_gdk_root, x, y);
1284
1285         if (!mouse_window ||
1286             gdk_window_get_toplevel (mouse_window) ==
1287             gdk_window_get_toplevel (current_mouse_window))
1288           {
1289             mouse_window = _gdk_root;
1290           }
1291
1292         if (mouse_window == _gdk_root)
1293           synthesize_crossing_events (_gdk_root, GDK_CROSSING_NORMAL, nsevent, x, y);
1294       }
1295       break;
1296
1297     default:
1298       break;
1299     }
1300 }
1301
1302 /* This function finds the correct window to send an event to, taking
1303  * into account grabs, event propagation, and event masks.
1304  */
1305 static GdkWindow *
1306 find_window_for_ns_event (NSEvent *nsevent, 
1307                           gint    *x, 
1308                           gint    *y)
1309 {
1310   NSEventType event_type;
1311
1312   event_type = [nsevent type];
1313
1314   switch (event_type)
1315     {
1316     case NSLeftMouseDown:
1317     case NSRightMouseDown:
1318     case NSOtherMouseDown:
1319     case NSLeftMouseUp:
1320     case NSRightMouseUp:
1321     case NSOtherMouseUp:
1322     case NSMouseMoved:
1323     case NSScrollWheel:
1324     case NSLeftMouseDragged:
1325     case NSRightMouseDragged:
1326     case NSOtherMouseDragged:
1327       {
1328         GdkWindow *mouse_window;
1329         GdkEventMask event_mask;
1330         GdkWindow *real_window;
1331
1332         /* From the docs for XGrabPointer:
1333          *
1334          * If owner_events is True and if a generated pointer event
1335          * would normally be reported to this client, it is reported
1336          * as usual. Otherwise, the event is reported with respect to
1337          * the grab_window and is reported only if selected by
1338          * event_mask. For either value of owner_events, unreported
1339          * events are discarded.
1340          *
1341          * This means we first try the owner, then the grab window,
1342          * then give up.
1343          */
1344         if (_gdk_quartz_pointer_grab_window)
1345           {
1346             if (pointer_grab_owner_events)
1347               {
1348                 mouse_window = find_mouse_window_for_ns_event (nsevent, x, y);
1349                 event_mask = get_event_mask_from_ns_event (nsevent);
1350                 real_window = find_window_interested_in_event_mask (mouse_window, event_mask, TRUE);
1351                 
1352                 if (mouse_window && real_window && mouse_window != real_window)
1353                   get_ancestor_coordinates_from_child (mouse_window,
1354                                                        *x, *y,
1355                                                        real_window,
1356                                                        x, y);
1357
1358                 if (real_window)
1359                   return real_window;
1360               }
1361
1362             /* Finally check the grab window. */
1363             if (pointer_grab_event_mask & get_event_mask_from_ns_event (nsevent))
1364               {
1365                 GdkWindow *event_toplevel;
1366                 GdkWindow *grab_toplevel;
1367                 NSPoint point;
1368                 int x_tmp, y_tmp;
1369
1370                 event_toplevel = [(GdkQuartzView *)[[nsevent window] contentView] gdkWindow];
1371                 grab_toplevel = gdk_window_get_toplevel (_gdk_quartz_pointer_grab_window);
1372                 point = [nsevent locationInWindow];
1373
1374                 x_tmp = point.x;
1375                 y_tmp = GDK_WINDOW_OBJECT (grab_toplevel)->height - point.y;
1376
1377                 /* Translate the coordinates so they are relative to
1378                  * the grab window instead of the event toplevel for
1379                  * the cases where they are not the same.
1380                  */
1381                 get_converted_window_coordinates (event_toplevel,
1382                                                   x_tmp, y_tmp,
1383                                                   _gdk_quartz_pointer_grab_window,
1384                                                   x, y);
1385
1386                 return _gdk_quartz_pointer_grab_window;
1387               }
1388
1389             return NULL;
1390           }
1391         else 
1392           {
1393             /* The non-grabbed case. */
1394             mouse_window = find_mouse_window_for_ns_event (nsevent, x, y);
1395             event_mask = get_event_mask_from_ns_event (nsevent);
1396             real_window = find_window_interested_in_event_mask (mouse_window, event_mask, TRUE);
1397             
1398             /* We have to translate the coordinates if the actual
1399              * window is different from the mouse window.
1400              */
1401             if (mouse_window && real_window && mouse_window != real_window)
1402               get_ancestor_coordinates_from_child (mouse_window,
1403                                                    *x, *y,
1404                                                    real_window,
1405                                                    x, y);
1406
1407             return real_window;
1408           }
1409       }
1410       break;
1411       
1412     case NSMouseEntered:
1413     case NSMouseExited:
1414       /* Already handled in synthesize_crossing_events_for_ns_event. */
1415       break;
1416
1417     case NSKeyDown:
1418     case NSKeyUp:
1419     case NSFlagsChanged:
1420       {
1421         GdkEventMask event_mask;
1422
1423         if (_gdk_quartz_keyboard_grab_window && !keyboard_grab_owner_events)
1424           return _gdk_quartz_keyboard_grab_window;
1425
1426         event_mask = get_event_mask_from_ns_event (nsevent);
1427         return find_window_interested_in_event_mask (current_keyboard_window, event_mask, TRUE);
1428       }
1429       break;
1430
1431     default:
1432       /* Ignore everything else. */
1433       break;
1434     }
1435
1436   return NULL;
1437 }
1438
1439 static GdkEvent *
1440 create_button_event (GdkWindow *window, 
1441                      NSEvent   *nsevent,
1442                      gint       x,
1443                      gint       y)
1444 {
1445   GdkEvent *event;
1446   GdkEventType type;
1447   gint state;
1448   gint button;
1449
1450   state = get_keyboard_modifiers_from_ns_event (nsevent);
1451
1452   switch ([nsevent type])
1453     {
1454     case NSLeftMouseDown:
1455     case NSRightMouseDown:
1456     case NSOtherMouseDown:
1457       type = GDK_BUTTON_PRESS;
1458       break;
1459     case NSLeftMouseUp:
1460     case NSRightMouseUp:
1461     case NSOtherMouseUp:
1462       type = GDK_BUTTON_RELEASE;
1463       state |= get_mouse_button_modifiers_from_ns_event (nsevent);
1464       break;
1465     default:
1466       g_assert_not_reached ();
1467     }
1468   
1469   button = get_mouse_button_from_ns_event (nsevent);
1470
1471   event = gdk_event_new (type);
1472   event->button.window = window;
1473   event->button.time = get_time_from_ns_event (nsevent);
1474   event->button.x = x;
1475   event->button.y = y;
1476   /* FIXME event->axes */
1477   event->button.state = state;
1478   event->button.button = button;
1479   event->button.device = _gdk_display->core_pointer;
1480   convert_window_coordinates_to_root (window, x, y, 
1481                                       &event->button.x_root,
1482                                       &event->button.y_root);
1483
1484   return event;
1485 }
1486
1487 static GdkEvent *
1488 create_motion_event (GdkWindow *window, 
1489                      NSEvent   *nsevent, 
1490                      gint       x, 
1491                      gint       y)
1492 {
1493   GdkEvent *event;
1494   GdkEventType type;
1495   GdkModifierType state = 0;
1496
1497   switch ([nsevent type])
1498     {
1499     case NSLeftMouseDragged:
1500     case NSRightMouseDragged:
1501     case NSOtherMouseDragged:
1502       state = get_mouse_button_modifiers_from_ns_event (nsevent);
1503       /* Fall through */
1504     case NSMouseMoved:
1505       type = GDK_MOTION_NOTIFY;
1506       break;
1507     default:
1508       g_assert_not_reached ();
1509     }
1510
1511   state |= get_keyboard_modifiers_from_ns_event (nsevent);
1512
1513   event = gdk_event_new (type);
1514   event->motion.window = window;
1515   event->motion.time = get_time_from_ns_event (nsevent);
1516   event->motion.x = x;
1517   event->motion.y = y;
1518   /* FIXME event->axes */
1519   event->motion.state = state;
1520   event->motion.is_hint = FALSE;
1521   event->motion.device = _gdk_display->core_pointer;
1522   convert_window_coordinates_to_root (window, x, y,
1523                                       &event->motion.x_root, &event->motion.y_root);
1524   
1525   return event;
1526 }
1527
1528 static GdkEvent *
1529 create_scroll_event (GdkWindow          *window, 
1530                      NSEvent            *nsevent, 
1531                      GdkScrollDirection  direction)
1532 {
1533   GdkEvent *event;
1534   NSPoint point;
1535   
1536   event = gdk_event_new (GDK_SCROLL);
1537   event->scroll.window = window;
1538   event->scroll.time = get_time_from_ns_event (nsevent);
1539
1540   point = [nsevent locationInWindow];
1541   event->scroll.x = point.x;
1542   event->scroll.y = point.y;
1543   event->scroll.state = get_keyboard_modifiers_from_ns_event (nsevent);
1544   convert_window_coordinates_to_root (window, event->scroll.x, event->scroll.y, 
1545                                       &event->scroll.x_root,
1546                                       &event->scroll.y_root);
1547
1548   event->scroll.direction = direction;
1549   event->scroll.device = _gdk_display->core_pointer;
1550   
1551   return event;
1552 }
1553
1554 static GdkEvent *
1555 create_key_event (GdkWindow    *window, 
1556                   NSEvent      *nsevent, 
1557                   GdkEventType  type)
1558 {
1559   GdkEvent *event;
1560   GdkEventPrivate *priv;
1561   gchar buf[7];
1562   gunichar c = 0;
1563
1564   event = gdk_event_new (type);
1565
1566   priv = (GdkEventPrivate *) event;
1567   priv->windowing_data = [nsevent retain];
1568
1569   event->key.window = window;
1570   event->key.time = get_time_from_ns_event (nsevent);
1571   event->key.state = get_keyboard_modifiers_from_ns_event (nsevent);
1572   event->key.hardware_keycode = [nsevent keyCode];
1573   event->key.group = ([nsevent modifierFlags] & NSAlternateKeyMask) ? 1 : 0;
1574
1575   event->key.keyval = GDK_VoidSymbol;
1576   
1577   gdk_keymap_translate_keyboard_state (NULL,
1578                                        event->key.hardware_keycode,
1579                                        event->key.state, 
1580                                        event->key.group,
1581                                        &event->key.keyval,
1582                                        NULL, NULL, NULL);
1583
1584   event->key.is_modifier = _gdk_quartz_keys_is_modifier (event->key.hardware_keycode);
1585
1586   /* If the key press is a modifier, the state should include the mask
1587    * for that modifier but only for releases, not presses. This
1588    * matches the X11 backend behavior.
1589    */
1590   if (event->key.is_modifier)
1591     {
1592       int mask = 0;
1593
1594       switch (event->key.keyval)
1595         {
1596         case GDK_Meta_R:
1597         case GDK_Meta_L:
1598           mask = GDK_MOD1_MASK;
1599           break;
1600         case GDK_Shift_R:
1601         case GDK_Shift_L:
1602           mask = GDK_SHIFT_MASK;
1603           break;
1604         case GDK_Caps_Lock:
1605           mask = GDK_LOCK_MASK;
1606           break;
1607         case GDK_Alt_R:
1608         case GDK_Alt_L:
1609           mask = GDK_MOD5_MASK;
1610           break;
1611         case GDK_Control_R:
1612         case GDK_Control_L:
1613           mask = GDK_CONTROL_MASK;
1614           break;
1615         default:
1616           mask = 0;
1617         }
1618
1619       if (type == GDK_KEY_PRESS)
1620         event->key.state &= ~mask;
1621       else if (type == GDK_KEY_RELEASE)
1622         event->key.state |= mask;
1623     }
1624
1625   event->key.state |= current_button_state;
1626
1627   event->key.string = NULL;
1628
1629   /* Fill in ->string since apps depend on it, taken from the x11 backend. */
1630   if (event->key.keyval != GDK_VoidSymbol)
1631     c = gdk_keyval_to_unicode (event->key.keyval);
1632
1633     if (c)
1634     {
1635       gsize bytes_written;
1636       gint len;
1637
1638       len = g_unichar_to_utf8 (c, buf);
1639       buf[len] = '\0';
1640       
1641       event->key.string = g_locale_from_utf8 (buf, len,
1642                                               NULL, &bytes_written,
1643                                               NULL);
1644       if (event->key.string)
1645         event->key.length = bytes_written;
1646     }
1647   else if (event->key.keyval == GDK_Escape)
1648     {
1649       event->key.length = 1;
1650       event->key.string = g_strdup ("\033");
1651     }
1652   else if (event->key.keyval == GDK_Return ||
1653           event->key.keyval == GDK_KP_Enter)
1654     {
1655       event->key.length = 1;
1656       event->key.string = g_strdup ("\r");
1657     }
1658
1659   if (!event->key.string)
1660     {
1661       event->key.length = 0;
1662       event->key.string = g_strdup ("");
1663     }
1664
1665   GDK_NOTE(EVENTS,
1666     g_message ("key %s:\t\twindow: %p  key: %12s  %d",
1667           type == GDK_KEY_PRESS ? "press" : "release",
1668           event->key.window,
1669           event->key.keyval ? gdk_keyval_name (event->key.keyval) : "(none)",
1670           event->key.keyval));
1671   return event;
1672 }
1673
1674 GdkEventMask 
1675 _gdk_quartz_events_get_current_event_mask (void)
1676 {
1677   return current_event_mask;
1678 }
1679
1680 static gboolean
1681 gdk_event_translate (NSEvent *nsevent)
1682 {
1683   NSWindow *nswindow;
1684   GdkWindow *window;
1685   GdkFilterReturn result;
1686   GdkEvent *event;
1687   int x, y;
1688
1689   /* There is no support for real desktop wide grabs, so we break
1690    * grabs when the application loses focus (gets deactivated).
1691    */
1692   if ([nsevent type] == NSAppKitDefined)
1693     {
1694       if ([nsevent subtype] == NSApplicationDeactivatedEventType)
1695         break_all_grabs ();
1696
1697       /* This could potentially be used to break grabs when clicking
1698        * on the title. The subtype 20 is undocumented so it's probably
1699        * not a good idea: else if (subtype == 20) break_all_grabs ();
1700        */
1701     }
1702
1703   /* Handle our generated "fake" crossing events. */
1704   if ([nsevent type] == NSApplicationDefined && 
1705       [nsevent subtype] == GDK_QUARTZ_EVENT_SUBTYPE_FAKE_CROSSING)
1706     {
1707       _gdk_quartz_events_trigger_crossing_events (FALSE);
1708       return TRUE;
1709     }
1710
1711   /* Keep track of button state, since we don't get that information
1712    * for key events. 
1713    */
1714   switch ([nsevent type])
1715     {
1716     case NSLeftMouseDown:
1717     case NSRightMouseDown:
1718     case NSOtherMouseDown:
1719       current_button_state |= get_mouse_button_modifiers_from_ns_event (nsevent);
1720       break;
1721     case NSLeftMouseUp:
1722     case NSRightMouseUp:
1723     case NSOtherMouseUp:
1724       current_button_state &= ~get_mouse_button_modifiers_from_ns_event (nsevent);
1725       break;
1726     default:
1727       break;
1728     }
1729
1730   nswindow = [nsevent window];
1731
1732   /* Apply any global filters. */
1733   if (_gdk_default_filters)
1734     {
1735       result = apply_filters (NULL, nsevent, _gdk_default_filters);
1736
1737       /* If result is GDK_FILTER_CONTINUE, we continue as if nothing
1738        * happened. If it is GDK_FILTER_REMOVE,
1739        * we return TRUE and won't send the message to Quartz.
1740        */
1741       if (result == GDK_FILTER_REMOVE)
1742         return TRUE;
1743     }
1744
1745   /* Ignore events for no window or ones not created by GDK. */
1746   if (!nswindow || ![[nswindow contentView] isKindOfClass:[GdkQuartzView class]])
1747     return FALSE;
1748
1749   /* Ignore events and break grabs while the window is being
1750    * dragged. This is a workaround for the window getting events for
1751    * the window title.
1752    */
1753   if ([(GdkQuartzWindow *)nswindow isInMove])
1754     {
1755       break_all_grabs ();
1756       return FALSE;
1757     }
1758
1759   /* Take care of NSMouseEntered/Exited events and mouse movements
1760    * events and emit the right GDK crossing events.
1761    */
1762   synthesize_crossing_events_for_ns_event (nsevent);
1763
1764   /* Find the right GDK window to send the event to, taking grabs and
1765    * event masks into consideration.
1766    */
1767   window = find_window_for_ns_event (nsevent, &x, &y);
1768   if (!window)
1769     return FALSE;
1770
1771   /* Apply any window filters. */
1772   result = apply_filters (window, nsevent, ((GdkWindowObject *) window)->filters);
1773   if (result == GDK_FILTER_REMOVE)
1774     return TRUE;
1775
1776   /* We need the appliction to be activated on clicks so that popups
1777    * like context menus get events routed properly. This is handled
1778    * automatically for left mouse button presses but not other
1779    * buttons, so we do it here.
1780    */
1781   if ([nsevent type] == NSRightMouseDown || [nsevent type] == NSOtherMouseDown)
1782     {
1783       if (![NSApp isActive])
1784         [NSApp activateIgnoringOtherApps:YES];
1785     }
1786
1787   current_event_mask = get_event_mask_from_ns_event (nsevent);
1788
1789   switch ([nsevent type])
1790     {
1791     case NSLeftMouseDown:
1792     case NSRightMouseDown:
1793     case NSOtherMouseDown:
1794       {
1795         GdkEventMask event_mask;
1796
1797         /* Emulate implicit grab, when the window has both PRESS and RELEASE
1798          * in its mask, like X.
1799          */
1800         event_mask = (GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK);
1801         if (!_gdk_quartz_pointer_grab_window &&
1802             (GDK_WINDOW_OBJECT (window)->event_mask & event_mask) == event_mask)
1803           {
1804             pointer_grab_internal (window, FALSE,
1805                                    GDK_WINDOW_OBJECT (window)->event_mask,
1806                                    NULL, NULL, TRUE);
1807           }
1808       }
1809       
1810       event = create_button_event (window, nsevent, x, y);
1811       append_event (event);
1812       
1813       _gdk_event_button_generate (_gdk_display, event);
1814       break;
1815
1816     case NSLeftMouseUp:
1817     case NSRightMouseUp:
1818     case NSOtherMouseUp:
1819       event = create_button_event (window, nsevent, x, y);
1820       append_event (event);
1821       
1822       /* Ungrab implicit grab */
1823       if (_gdk_quartz_pointer_grab_window && pointer_grab_implicit)
1824         pointer_ungrab_internal (TRUE);
1825       break;
1826
1827     case NSLeftMouseDragged:
1828     case NSRightMouseDragged:
1829     case NSOtherMouseDragged:
1830     case NSMouseMoved:
1831       event = create_motion_event (window, nsevent, x, y);
1832       append_event (event);
1833       break;
1834
1835     case NSScrollWheel:
1836       {
1837         float dx = [nsevent deltaX];
1838         float dy = [nsevent deltaY];
1839         GdkScrollDirection direction;
1840
1841         /* The delta is how much the mouse wheel has moved. Since there's no such thing in GTK+
1842          * we accomodate by sending a different number of scroll wheel events.
1843          */
1844
1845         /* First do y events */
1846         if (dy < 0.0)
1847           {
1848             dy = -dy;
1849             direction = GDK_SCROLL_DOWN;
1850           }
1851         else
1852           direction = GDK_SCROLL_UP;
1853
1854         while (dy > 0.0)
1855           {
1856             event = create_scroll_event (window, nsevent, direction);
1857             append_event (event);
1858             dy--;
1859
1860             /* Ignore the delta for now, things get too slow when the events queue up. */
1861             break;
1862           }
1863
1864         /* Now do x events */
1865         if (dx < 0.0)
1866           {
1867             dx = -dx;
1868             direction = GDK_SCROLL_RIGHT;
1869           }
1870         else
1871           direction = GDK_SCROLL_LEFT;
1872
1873         while (dx > 0.0)
1874           {
1875             event = create_scroll_event (window, nsevent, direction);
1876             append_event (event);
1877             dx--;
1878             
1879             /* Ignore the delta for now, things get too slow when the events queue up. */
1880             break;
1881           }
1882
1883       }
1884       break;
1885
1886     case NSKeyDown:
1887     case NSKeyUp:
1888     case NSFlagsChanged:
1889       {
1890         GdkEventType type;
1891
1892         type = _gdk_quartz_keys_event_type (nsevent);
1893         if (type == GDK_NOTHING)
1894           return FALSE;
1895         
1896         event = create_key_event (window, nsevent, type);
1897         append_event (event);
1898         return TRUE;
1899       }
1900       break;
1901
1902     default:
1903       /* Ignore everything elsee. */
1904       break;
1905     }
1906
1907   return FALSE;
1908 }
1909
1910 void
1911 _gdk_events_queue (GdkDisplay *display)
1912 {  
1913   NSEvent *event;
1914
1915   event = _gdk_quartz_event_loop_get_pending ();
1916   if (event)
1917     {
1918       if (!gdk_event_translate (event))
1919         {
1920           GDK_THREADS_LEAVE ();
1921           [NSApp sendEvent:event];
1922           GDK_THREADS_ENTER ();
1923         }
1924
1925       _gdk_quartz_event_loop_release_event (event);
1926     }
1927 }
1928
1929 void
1930 gdk_flush (void)
1931 {
1932   /* Not supported. */
1933 }
1934
1935 void 
1936 gdk_display_add_client_message_filter (GdkDisplay   *display,
1937                                        GdkAtom       message_type,
1938                                        GdkFilterFunc func,
1939                                        gpointer      data)
1940 {
1941   /* Not supported. */
1942 }
1943
1944 void 
1945 gdk_add_client_message_filter (GdkAtom       message_type,
1946                                GdkFilterFunc func,
1947                                gpointer      data)
1948 {
1949   /* Not supported. */
1950 }
1951
1952 void
1953 gdk_display_sync (GdkDisplay *display)
1954 {
1955   /* Not supported. */
1956 }
1957
1958 void
1959 gdk_display_flush (GdkDisplay *display)
1960 {
1961   /* Not supported. */
1962 }
1963
1964 gboolean
1965 gdk_event_send_client_message_for_display (GdkDisplay      *display,
1966                                            GdkEvent        *event,
1967                                            GdkNativeWindow  winid)
1968 {
1969   /* Not supported. */
1970   return FALSE;
1971 }
1972
1973 void
1974 gdk_screen_broadcast_client_message (GdkScreen *screen,
1975                                      GdkEvent  *event)
1976 {
1977   /* Not supported. */
1978 }
1979
1980 gboolean
1981 gdk_screen_get_setting (GdkScreen   *screen,
1982                         const gchar *name,
1983                         GValue      *value)
1984 {
1985   if (strcmp (name, "gtk-double-click-time") == 0)
1986     {
1987       NSUserDefaults *defaults;
1988       float t;
1989
1990       GDK_QUARTZ_ALLOC_POOL;
1991
1992       defaults = [NSUserDefaults standardUserDefaults];
1993             
1994       t = [defaults floatForKey:@"com.apple.mouse.doubleClickThreshold"];
1995       if (t == 0.0)
1996         {
1997           /* No user setting, use the default in OS X. */
1998           t = 0.5;
1999         }
2000
2001       GDK_QUARTZ_RELEASE_POOL;
2002
2003       g_value_set_int (value, t * 1000);
2004
2005       return TRUE;
2006     }
2007   else if (strcmp (name, "gtk-font-name") == 0)
2008     {
2009       NSString *name;
2010       char *str;
2011
2012       GDK_QUARTZ_ALLOC_POOL;
2013
2014       name = [[NSFont systemFontOfSize:0] familyName];
2015
2016       /* Let's try to use the "views" font size (12pt) by default. This is
2017        * used for lists/text/other "content" which is the largest parts of
2018        * apps, using the "regular control" size (13pt) looks a bit out of
2019        * place. We might have to tweak this.
2020        */
2021
2022       /* The size has to be hardcoded as there doesn't seem to be a way to
2023        * get the views font size programmatically.
2024        */
2025       str = g_strdup_printf ("%s 12", [name UTF8String]);
2026       g_value_set_string (value, str);
2027       g_free (str);
2028
2029       GDK_QUARTZ_RELEASE_POOL;
2030
2031       return TRUE;
2032     }
2033   
2034   /* FIXME: Add more settings */
2035
2036   return FALSE;
2037 }
2038
2039 void
2040 _gdk_windowing_event_data_copy (const GdkEvent *src,
2041                                 GdkEvent       *dst)
2042 {
2043   GdkEventPrivate *priv_src = (GdkEventPrivate *) src;
2044   GdkEventPrivate *priv_dst = (GdkEventPrivate *) dst;
2045
2046   if (priv_src->windowing_data)
2047     {
2048       priv_dst->windowing_data = priv_src->windowing_data;
2049       [(NSEvent *)priv_dst->windowing_data retain];
2050     }
2051 }
2052
2053 void
2054 _gdk_windowing_event_data_free (GdkEvent *event)
2055 {
2056   GdkEventPrivate *priv = (GdkEventPrivate *) event;
2057
2058   if (priv->windowing_data)
2059     {
2060       [(NSEvent *)priv->windowing_data release];
2061       priv->windowing_data = NULL;
2062     }
2063 }