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