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