]> Pileus Git - ~andy/gtk/blob - gdk/quartz/gdkevents-quartz.c
Clean up namespaces to make the code more maintainable.
[~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-2006 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 #include <Carbon/Carbon.h>
30
31 #include "gdkscreen.h"
32 #include "gdkkeysyms.h"
33
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 static void append_event (GdkEvent *event);
53
54 void 
55 _gdk_events_init (void)
56 {
57   _gdk_quartz_event_loop_init ();
58
59   current_mouse_window = g_object_ref (_gdk_root);
60   current_keyboard_window = g_object_ref (_gdk_root);
61 }
62
63 gboolean
64 gdk_events_pending (void)
65 {
66   return (_gdk_event_queue_find_first (_gdk_display) ||
67           (_gdk_quartz_event_loop_get_current () != NULL));
68 }
69
70 GdkEvent*
71 gdk_event_get_graphics_expose (GdkWindow *window)
72 {
73   /* FIXME: Implement */
74   return NULL;
75 }
76
77 static void
78 generate_grab_broken_event (GdkWindow *window,
79                             gboolean   keyboard,
80                             gboolean   implicit,
81                             GdkWindow *grab_window)
82 {
83   if (!GDK_WINDOW_DESTROYED (window))
84     {
85       GdkEvent *event = gdk_event_new (GDK_GRAB_BROKEN);
86
87       event->grab_broken.window = window;
88       event->grab_broken.send_event = 0;
89       event->grab_broken.keyboard = keyboard;
90       event->grab_broken.implicit = implicit;
91       event->grab_broken.grab_window = grab_window;
92       
93       append_event (event);
94     }
95 }
96
97 GdkGrabStatus
98 gdk_keyboard_grab (GdkWindow  *window,
99                    gint        owner_events,
100                    guint32     time)
101 {
102   g_return_val_if_fail (window != NULL, 0);
103   g_return_val_if_fail (GDK_IS_WINDOW (window), 0);
104
105   if (_gdk_quartz_keyboard_grab_window)
106     {
107       if (_gdk_quartz_keyboard_grab_window != window)
108         generate_grab_broken_event (_gdk_quartz_keyboard_grab_window,
109                                     TRUE, FALSE, window);
110       
111       g_object_unref (_gdk_quartz_keyboard_grab_window);
112     }
113
114   _gdk_quartz_keyboard_grab_window = g_object_ref (window);
115   keyboard_grab_owner_events = owner_events;
116
117   return GDK_GRAB_SUCCESS;
118 }
119
120 void
121 gdk_display_keyboard_ungrab (GdkDisplay *display,
122                              guint32     time)
123 {
124   if (_gdk_quartz_keyboard_grab_window)
125     g_object_unref (_gdk_quartz_keyboard_grab_window);
126   _gdk_quartz_keyboard_grab_window = NULL;
127 }
128
129 gboolean
130 gdk_keyboard_grab_info_libgtk_only (GdkDisplay *display,
131                                     GdkWindow **grab_window,
132                                     gboolean   *owner_events)
133 {
134   if (_gdk_quartz_keyboard_grab_window) 
135     {
136       if (grab_window)
137         *grab_window = _gdk_quartz_keyboard_grab_window;
138       if (owner_events)
139         *owner_events = keyboard_grab_owner_events;
140
141       return TRUE;
142     }
143
144   return FALSE;
145 }
146
147 static void
148 pointer_ungrab_internal (gboolean only_if_implicit)
149 {
150   if (!_gdk_quartz_pointer_grab_window)
151     return;
152
153   if (only_if_implicit && !pointer_grab_implicit)
154     return;
155
156   g_object_unref (_gdk_quartz_pointer_grab_window);
157   _gdk_quartz_pointer_grab_window = NULL;
158
159   /* FIXME: Send crossing events */
160 }
161
162 gboolean
163 gdk_display_pointer_is_grabbed (GdkDisplay *display)
164 {
165   return _gdk_quartz_pointer_grab_window != NULL;
166 }
167
168 gboolean
169 gdk_pointer_grab_info_libgtk_only (GdkDisplay *display,
170                                    GdkWindow **grab_window,
171                                    gboolean   *owner_events)
172 {
173   if (!_gdk_quartz_pointer_grab_window)
174     return FALSE;
175
176   if (grab_window)
177     *grab_window = _gdk_quartz_pointer_grab_window;
178
179   if (owner_events)
180     *owner_events = pointer_grab_owner_events;
181
182   return FALSE;
183 }
184
185 void
186 gdk_display_pointer_ungrab (GdkDisplay *display,
187                             guint32     time)
188 {
189   pointer_ungrab_internal (FALSE);
190 }
191
192 static GdkGrabStatus
193 pointer_grab_internal (GdkWindow    *window,
194                        gboolean      owner_events,
195                        GdkEventMask  event_mask,
196                        GdkWindow    *confine_to,
197                        GdkCursor    *cursor,
198                        gboolean      implicit)
199 {
200   /* FIXME: Send crossing events */
201   
202   _gdk_quartz_pointer_grab_window = g_object_ref (window);
203   pointer_grab_owner_events = owner_events;
204   pointer_grab_event_mask = event_mask;
205   pointer_grab_implicit = implicit;
206
207   return GDK_GRAB_SUCCESS;
208 }
209
210 GdkGrabStatus
211 gdk_pointer_grab (GdkWindow    *window,
212                   gboolean      owner_events,
213                   GdkEventMask  event_mask,
214                   GdkWindow    *confine_to,
215                   GdkCursor    *cursor,
216                   guint32       time)
217 {
218   g_return_val_if_fail (GDK_IS_WINDOW (window), 0);
219   g_return_val_if_fail (confine_to == NULL || GDK_IS_WINDOW (confine_to), 0);
220
221   if (_gdk_quartz_pointer_grab_window)
222     {
223       if (_gdk_quartz_pointer_grab_window == window && !pointer_grab_implicit)
224         return GDK_GRAB_ALREADY_GRABBED;
225       else
226         {
227           if (_gdk_quartz_pointer_grab_window != window)
228             generate_grab_broken_event (_gdk_quartz_pointer_grab_window,
229                                         FALSE, pointer_grab_implicit, window);
230           pointer_ungrab_internal (TRUE);
231         }
232     }
233
234   return pointer_grab_internal (window, owner_events, event_mask, 
235                                 confine_to, cursor, FALSE);
236 }
237
238 static void
239 fixup_event (GdkEvent *event)
240 {
241   if (event->any.window)
242     g_object_ref (event->any.window);
243   if (((event->any.type == GDK_ENTER_NOTIFY) ||
244        (event->any.type == GDK_LEAVE_NOTIFY)) &&
245       (event->crossing.subwindow != NULL))
246     g_object_ref (event->crossing.subwindow);
247   event->any.send_event = FALSE;
248 }
249
250 static void
251 append_event (GdkEvent *event)
252 {
253   fixup_event (event);
254   _gdk_event_queue_append (_gdk_display, event);
255 }
256
257 static GdkFilterReturn
258 apply_filters (GdkWindow  *window,
259                NSEvent    *nsevent,
260                GList      *filters)
261 {
262   GdkFilterReturn result = GDK_FILTER_CONTINUE;
263   GdkEvent *event;
264   GList *node;
265   GList *tmp_list;
266
267   event = gdk_event_new (GDK_NOTHING);
268   if (window != NULL)
269     event->any.window = g_object_ref (window);
270   ((GdkEventPrivate *)event)->flags |= GDK_EVENT_PENDING;
271
272   /* I think GdkFilterFunc semantics require the passed-in event
273    * to already be in the queue. The filter func can generate
274    * more events and append them after it if it likes.
275    */
276   node = _gdk_event_queue_append (_gdk_display, event);
277   
278   tmp_list = filters;
279   while (tmp_list)
280     {
281       GdkEventFilter *filter = (GdkEventFilter *) tmp_list->data;
282       
283       tmp_list = tmp_list->next;
284       result = filter->function (nsevent, event, filter->data);
285       if (result != GDK_FILTER_CONTINUE)
286         break;
287     }
288
289   if (result == GDK_FILTER_CONTINUE || result == GDK_FILTER_REMOVE)
290     {
291       _gdk_event_queue_remove_link (_gdk_display, node);
292       g_list_free_1 (node);
293       gdk_event_free (event);
294     }
295   else /* GDK_FILTER_TRANSLATE */
296     {
297       ((GdkEventPrivate *)event)->flags &= ~GDK_EVENT_PENDING;
298       fixup_event (event);
299     }
300   return result;
301 }
302
303 /* This function checks if the passed in window is interested in the
304  * event mask. If so, it's returned. If not, the event can be propagated
305  * to its parent.
306  */
307 static GdkWindow *
308 find_window_interested_in_event_mask (GdkWindow   *window, 
309                                       GdkEventMask event_mask,
310                                       gboolean     propagate)
311 {
312   while (window)
313     {
314       GdkWindowObject *private = GDK_WINDOW_OBJECT (window);
315
316       if (private->event_mask & event_mask)
317         return window;
318
319       if (!propagate)
320         return NULL;
321       else
322         window = GDK_WINDOW (private->parent);
323     }
324
325   return NULL;
326 }
327
328 static guint32
329 get_event_time (NSEvent *event)
330 {
331   double time = [event timestamp];
332   
333   return time * 1000.0;
334 }
335
336 static int
337 convert_mouse_button_number (int button)
338 {
339   switch (button)
340     {
341     case 0:
342       return 1;
343     case 1:
344       return 3;
345     case 2:
346       return 2;
347     default:
348       return button + 1;
349     }
350 }
351
352 /* Return an event mask from an NSEvent */
353 static GdkEventMask
354 get_event_mask_from_ns_event (NSEvent *nsevent)
355 {
356   switch ([nsevent type])
357     {
358     case NSLeftMouseDown:
359     case NSRightMouseDown:
360     case NSOtherMouseDown:
361       return GDK_BUTTON_PRESS_MASK;
362     case NSLeftMouseUp:
363     case NSRightMouseUp:
364     case NSOtherMouseUp:
365       return GDK_BUTTON_RELEASE_MASK;
366     case NSMouseMoved:
367       return GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK;
368     case NSScrollWheel:
369       /* Since applications that want button press events can get
370        * scroll events on X11 (since scroll wheel events are really
371        * button press events there), we need to use GDK_BUTTON_PRESS_MASK too.
372        */
373       return GDK_SCROLL_MASK | GDK_BUTTON_PRESS_MASK;
374     case NSLeftMouseDragged:
375       return (GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK |
376               GDK_BUTTON_MOTION_MASK | GDK_BUTTON1_MOTION_MASK | 
377               GDK_BUTTON1_MASK);
378     case NSRightMouseDragged:
379       return (GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK |
380               GDK_BUTTON_MOTION_MASK | GDK_BUTTON3_MOTION_MASK | 
381               GDK_BUTTON3_MASK);
382     case NSOtherMouseDragged:
383       {
384         GdkEventMask mask;
385
386         mask = (GDK_POINTER_MOTION_MASK |
387                 GDK_POINTER_MOTION_HINT_MASK |
388                 GDK_BUTTON_MOTION_MASK);
389
390         if (convert_mouse_button_number ([nsevent buttonNumber]) == 2)
391           mask |= (GDK_BUTTON2_MOTION_MASK | GDK_BUTTON2_MOTION_MASK | 
392                    GDK_BUTTON2_MASK);
393
394         return mask;
395       }
396     case NSKeyDown:
397     case NSKeyUp:
398     case NSFlagsChanged:
399       {
400         switch (_gdk_quartz_keys_event_type (nsevent))
401           {
402           case GDK_KEY_PRESS:
403             return GDK_KEY_PRESS_MASK;
404           case GDK_KEY_RELEASE:
405             return GDK_KEY_RELEASE_MASK;
406           case GDK_NOTHING:
407             return 0;
408           default:
409             g_assert_not_reached ();
410           }
411       }
412     default:
413       g_assert_not_reached ();
414     }
415
416   return 0;
417 }
418
419 static GdkEvent *
420 create_focus_event (GdkWindow *window,
421                     gboolean   in)
422 {
423   GdkEvent *event;
424
425   event = gdk_event_new (GDK_FOCUS_CHANGE);
426   event->focus_change.window = window;
427   event->focus_change.in = in;
428
429   return event;
430 }
431
432 /* Note: Used to both set a new focus window and to unset the old one. */
433 void
434 _gdk_quartz_events_update_focus_window (GdkWindow *window,
435                                         gboolean   got_focus)
436 {
437   GdkEvent *event;
438
439   if (got_focus && window == current_keyboard_window)
440     return;
441
442   /* FIXME: Don't do this when grabbed? Or make GdkQuartzWindow
443    * disallow it in the first place instead?
444    */
445   
446   if (!got_focus && window == current_keyboard_window)
447     {
448           event = create_focus_event (current_keyboard_window, FALSE);
449           append_event (event);
450           g_object_unref (current_keyboard_window);
451           current_keyboard_window = NULL;
452     }
453
454   if (got_focus)
455     {
456       if (current_keyboard_window)
457         {
458           event = create_focus_event (current_keyboard_window, FALSE);
459           append_event (event);
460           g_object_unref (current_keyboard_window);
461           current_keyboard_window = NULL;
462         }
463       
464       event = create_focus_event (window, TRUE);
465       append_event (event);
466       current_keyboard_window = g_object_ref (window);
467     }
468 }
469
470 static gboolean
471 gdk_window_is_ancestor (GdkWindow *ancestor,
472                         GdkWindow *window)
473 {
474   if (ancestor == NULL || window == NULL)
475     return FALSE;
476
477   return (gdk_window_get_parent (window) == ancestor ||
478           gdk_window_is_ancestor (ancestor, gdk_window_get_parent (window)));
479 }
480
481 static GdkModifierType
482 get_keyboard_modifiers_from_nsevent (NSEvent *nsevent)
483 {
484   GdkModifierType modifiers = 0;
485   int nsflags;
486
487   nsflags = [nsevent modifierFlags];
488   
489   if (nsflags & NSAlphaShiftKeyMask)
490     modifiers |= GDK_LOCK_MASK;
491   if (nsflags & NSShiftKeyMask)
492     modifiers |= GDK_SHIFT_MASK;
493   if (nsflags & NSControlKeyMask)
494     modifiers |= GDK_CONTROL_MASK;
495   if (nsflags & NSCommandKeyMask)
496     modifiers |= GDK_MOD1_MASK;
497
498   /* FIXME: Support GDK_BUTTON_MASK */
499
500   return modifiers;
501 }
502
503 static void
504 convert_window_coordinates_to_root (GdkWindow *window,
505                                     gdouble    x,
506                                     gdouble    y,
507                                     gdouble   *x_root,
508                                     gdouble   *y_root)
509 {
510   gint ox, oy;
511
512   *x_root = x;
513   *y_root = y;
514   
515   if (gdk_window_get_origin (window, &ox, &oy))
516     {
517       *x_root += ox;
518       *y_root += oy;
519     }
520 }
521
522 static GdkEvent *
523 create_crossing_event (GdkWindow      *window, 
524                        NSEvent        *nsevent, 
525                        GdkEventType    event_type,
526                        GdkCrossingMode mode, 
527                        GdkNotifyType   detail)
528 {
529   GdkEvent *event;
530   NSPoint point;
531
532   event = gdk_event_new (event_type);
533   
534   event->crossing.window = window;
535   event->crossing.subwindow = NULL; /* FIXME */
536   event->crossing.time = get_event_time (nsevent);
537
538   point = [nsevent locationInWindow];
539   event->crossing.x = point.x;
540   event->crossing.y = point.y;
541   convert_window_coordinates_to_root (window, event->crossing.x, event->crossing.y, 
542                                       &event->crossing.x_root,
543                                       &event->crossing.y_root);
544
545   event->crossing.mode = mode;
546   event->crossing.detail = detail;
547   /* FIXME: focus */
548   /* FIXME: state, (button state too) */
549
550   return event;
551 }
552
553 static void
554 synthesize_enter_event (GdkWindow      *window,
555                         NSEvent        *nsevent,
556                         GdkCrossingMode mode,
557                         GdkNotifyType   detail)
558 {
559   GdkEvent *event;
560
561   if (_gdk_quartz_pointer_grab_window != NULL && 
562       !pointer_grab_owner_events && 
563       !(pointer_grab_event_mask & GDK_ENTER_NOTIFY_MASK))
564     return;
565
566   if (!(GDK_WINDOW_OBJECT (window)->event_mask & GDK_ENTER_NOTIFY_MASK))
567     return;
568
569   event = create_crossing_event (window, nsevent, GDK_ENTER_NOTIFY,
570                                  mode, detail);
571
572   append_event (event);
573 }
574   
575 static void
576 synthesize_enter_events (GdkWindow      *from,
577                          GdkWindow      *to,
578                          NSEvent        *nsevent,
579                          GdkCrossingMode mode,
580                          GdkNotifyType   detail)
581 {
582   GdkWindow *prev = gdk_window_get_parent (to);
583
584   if (prev != from)
585     synthesize_enter_events (from, prev, nsevent, mode, detail);
586   synthesize_enter_event (to, nsevent, mode, detail);
587 }
588
589 static void
590 synthesize_leave_event (GdkWindow      *window,
591                         NSEvent        *nsevent,
592                         GdkCrossingMode mode,
593                         GdkNotifyType   detail)
594 {
595   GdkEvent *event;
596
597   if (_gdk_quartz_pointer_grab_window != NULL && 
598       !pointer_grab_owner_events && 
599       !(pointer_grab_event_mask & GDK_LEAVE_NOTIFY_MASK))
600     return;
601
602   if (!(GDK_WINDOW_OBJECT (window)->event_mask & GDK_LEAVE_NOTIFY_MASK))
603     return;
604
605   event = create_crossing_event (window, nsevent, GDK_LEAVE_NOTIFY,
606                                  mode, detail);
607
608   append_event (event);
609 }
610                          
611 static void
612 synthesize_leave_events (GdkWindow      *from,
613                          GdkWindow      *to,
614                          NSEvent        *nsevent,
615                          GdkCrossingMode mode,
616                          GdkNotifyType   detail)
617 {
618   GdkWindow *next = gdk_window_get_parent (from);
619   
620   synthesize_leave_event (from, nsevent, mode, detail);
621   if (next != to)
622     synthesize_leave_events (next, to, nsevent, mode, detail);
623 }
624                          
625 static void
626 synthesize_crossing_events (GdkWindow      *window,
627                             GdkCrossingMode mode,
628                             NSEvent        *nsevent,
629                             gint            x,
630                             gint            y)
631 {
632   GdkWindow *intermediate, *tem, *common_ancestor;
633
634   if (gdk_window_is_ancestor (current_mouse_window, window))
635     {
636       /* Pointer has moved to an inferior window. */
637       synthesize_leave_event (current_mouse_window, nsevent, mode, GDK_NOTIFY_INFERIOR);
638
639       /* If there are intermediate windows, generate ENTER_NOTIFY
640        * events for them
641        */
642       intermediate = gdk_window_get_parent (window);
643
644       if (intermediate != current_mouse_window)
645         {
646           synthesize_enter_events (current_mouse_window, intermediate, nsevent, mode, GDK_NOTIFY_VIRTUAL);
647         }
648
649       synthesize_enter_event (window, nsevent, mode, GDK_NOTIFY_ANCESTOR);
650     }
651   else if (gdk_window_is_ancestor (window, current_mouse_window))
652     {
653       /* Pointer has moved to an ancestor window. */
654       synthesize_leave_event (current_mouse_window, nsevent, mode, GDK_NOTIFY_ANCESTOR);
655       
656       /* If there are intermediate windows, generate LEAVE_NOTIFY
657        * events for them
658        */
659       intermediate = gdk_window_get_parent (current_mouse_window);
660       if (intermediate != window)
661         {
662           synthesize_leave_events (intermediate, window, nsevent, mode, GDK_NOTIFY_VIRTUAL);
663         }
664
665       synthesize_enter_event (window, nsevent, mode, GDK_NOTIFY_INFERIOR);
666     }
667   else if (current_mouse_window)
668     {
669       /* Find least common ancestor of current_mouse_window and window */
670       tem = current_mouse_window;
671       do {
672         common_ancestor = gdk_window_get_parent (tem);
673         tem = common_ancestor;
674       } while (common_ancestor &&
675                !gdk_window_is_ancestor (common_ancestor, window));
676       if (common_ancestor)
677         {
678           synthesize_leave_event (current_mouse_window, nsevent, mode, GDK_NOTIFY_NONLINEAR);
679           intermediate = gdk_window_get_parent (current_mouse_window);
680           if (intermediate != common_ancestor)
681             {
682               synthesize_leave_events (intermediate, common_ancestor,
683                                        nsevent, mode, GDK_NOTIFY_NONLINEAR_VIRTUAL);
684             }
685           intermediate = gdk_window_get_parent (window);
686           if (intermediate != common_ancestor)
687             {
688               synthesize_enter_events (common_ancestor, intermediate,
689                                        nsevent, mode, GDK_NOTIFY_NONLINEAR_VIRTUAL);
690             }
691           synthesize_enter_event (window, nsevent, mode, GDK_NOTIFY_NONLINEAR);
692         }
693     }
694   else
695     {
696       /* This means we have not current_mouse_window. FIXME: Should
697        * we make sure to always set the root window instead of NULL?
698        */
699
700       /* FIXME: Figure out why this is being called with window being
701        * NULL. The check works around a crash for now.
702        */ 
703       if (window)
704         synthesize_enter_event (window, nsevent, mode, GDK_NOTIFY_UNKNOWN);
705     }
706   
707   _gdk_quartz_events_update_mouse_window (window);
708 }
709
710 void 
711 _gdk_quartz_events_send_map_events (GdkWindow *window)
712 {
713   GList *list;
714   GdkWindow *interested_window;
715   GdkWindowObject *private = (GdkWindowObject *)window;
716
717   interested_window = find_window_interested_in_event_mask (window, 
718                                                             GDK_STRUCTURE_MASK,
719                                                             TRUE);
720   
721   if (interested_window)
722     {
723       GdkEvent *event = gdk_event_new (GDK_MAP);
724       event->any.window = interested_window;
725       append_event (event);
726     }
727
728   for (list = private->children; list != NULL; list = list->next)
729     _gdk_quartz_events_send_map_events ((GdkWindow *)list->data);
730 }
731
732 /* Get current mouse window */
733 GdkWindow *
734 _gdk_quartz_events_get_mouse_window (void)
735 {
736   if (_gdk_quartz_pointer_grab_window && !pointer_grab_owner_events)
737     return _gdk_quartz_pointer_grab_window;
738   
739   return current_mouse_window;
740 }
741
742 /* Update mouse window */
743 void 
744 _gdk_quartz_events_update_mouse_window (GdkWindow *window)
745 {
746   if (window)
747     g_object_ref (window);
748   if (current_mouse_window)
749     g_object_unref (current_mouse_window);
750
751   current_mouse_window = window;
752 }
753
754 /* Update current cursor */
755 void
756 _gdk_quartz_events_update_cursor (GdkWindow *window)
757 {
758   GdkWindowObject *private = GDK_WINDOW_OBJECT (window);
759   NSCursor *nscursor = nil;
760
761   while (private) {
762     GdkWindowImplQuartz *impl = GDK_WINDOW_IMPL_QUARTZ (private->impl);
763
764     nscursor = impl->nscursor;
765     if (nscursor)
766       break;
767
768     private = private->parent;
769   }
770
771   if (!nscursor)
772     nscursor = [NSCursor arrowCursor];
773
774   if ([NSCursor currentCursor] != nscursor)
775     [nscursor set];
776 }
777
778 /* This function finds the correct window to send an event to,
779  * taking into account grabs (FIXME: not done yet), event propagation,
780  * and event masks.
781  */
782 static GdkWindow *
783 find_window_for_event (NSEvent *nsevent, gint *x, gint *y)
784 {
785   NSWindow *nswindow = [nsevent window];
786   NSEventType event_type = [nsevent type];
787
788   if (!nswindow)
789     return NULL;
790  
791   /* Window where not created by GDK so the event should be handled by Quartz */
792   if (![[nswindow contentView] isKindOfClass:[GdkQuartzView class]]) 
793     return NULL;
794   
795   if (event_type == NSMouseMoved ||
796       event_type == NSLeftMouseDragged ||
797       event_type == NSRightMouseDragged ||
798       event_type == NSOtherMouseDragged)
799     {
800       GdkWindow *toplevel = [(GdkQuartzView *)[nswindow contentView] gdkWindow];
801       NSPoint point = [nsevent locationInWindow];
802       GdkWindow *mouse_window;
803
804       mouse_window = _gdk_quartz_window_find_child_by_point (toplevel, point.x, point.y, x, y);
805
806       if (!mouse_window)
807         mouse_window = _gdk_root;
808
809       if (_gdk_quartz_pointer_grab_window)
810         {
811           if (mouse_window != current_mouse_window)
812             synthesize_crossing_events (mouse_window, GDK_CROSSING_NORMAL, nsevent, *x, *y);
813         }
814       else
815         {
816           if (current_mouse_window != mouse_window)
817             {
818               synthesize_crossing_events (mouse_window, GDK_CROSSING_NORMAL, nsevent, *x, *y);
819               
820               _gdk_quartz_events_update_cursor (mouse_window);
821             }
822         }
823     }
824
825   switch (event_type)
826     {
827     case NSLeftMouseDown:
828     case NSRightMouseDown:
829     case NSOtherMouseDown:
830     case NSLeftMouseUp:
831     case NSRightMouseUp:
832     case NSOtherMouseUp:
833     case NSMouseMoved:
834     case NSScrollWheel:
835     case NSLeftMouseDragged:
836     case NSRightMouseDragged:
837     case NSOtherMouseDragged:
838       {
839         GdkWindow *toplevel = [(GdkQuartzView *)[nswindow contentView] gdkWindow];
840         NSPoint point = [nsevent locationInWindow];
841         GdkWindow *mouse_window;
842         GdkEventMask event_mask;
843         GdkWindow *real_window;
844
845         if (_gdk_quartz_pointer_grab_window && !pointer_grab_owner_events)
846           {
847             if (pointer_grab_event_mask & get_event_mask_from_ns_event (nsevent))
848               {
849                 int tempx, tempy;
850                 GdkWindowObject *w;
851                 GdkWindowObject *grab_toplevel;
852
853                 w = GDK_WINDOW_OBJECT (_gdk_quartz_pointer_grab_window);
854                 grab_toplevel = GDK_WINDOW_OBJECT (gdk_window_get_toplevel (_gdk_quartz_pointer_grab_window));
855
856                 tempx = point.x;
857                 tempy = GDK_WINDOW_IMPL_QUARTZ (grab_toplevel->impl)->height -
858                   point.y;
859
860                 while (w != grab_toplevel)
861                   {
862                     tempx -= w->x;
863                     tempy -= w->y;
864
865                     w = w->parent;
866                   }
867
868                 *x = tempx;
869                 *y = tempy;
870
871                 return _gdk_quartz_pointer_grab_window;
872               }
873             else
874               {
875                 return NULL;
876               }
877           }
878
879         if (!nswindow)
880           {
881             mouse_window = _gdk_root;
882           }
883         else
884           {
885             mouse_window = _gdk_quartz_window_find_child_by_point (toplevel, point.x, point.y, x, y);
886           }
887
888         event_mask = get_event_mask_from_ns_event (nsevent);
889         real_window = find_window_interested_in_event_mask (mouse_window, event_mask, TRUE);
890         
891         return real_window;
892       }
893       break;
894       
895     case NSMouseEntered:
896       {
897         NSPoint point;
898         GdkWindow *toplevel;
899         GdkWindow *mouse_window;
900
901         point = [nsevent locationInWindow];
902         toplevel = [(GdkQuartzView *)[nswindow contentView] gdkWindow];
903         
904         mouse_window = _gdk_quartz_window_find_child_by_point (toplevel, point.x, point.y, x, y);
905         
906         synthesize_crossing_events (mouse_window, GDK_CROSSING_NORMAL, nsevent, *x, *y);
907       }
908       break;
909
910     case NSMouseExited:
911       synthesize_crossing_events (_gdk_root, GDK_CROSSING_NORMAL, nsevent, *x, *y);
912       break;
913
914     case NSKeyDown:
915     case NSKeyUp:
916     case NSFlagsChanged:
917       {
918         GdkEventMask event_mask;
919
920         if (_gdk_quartz_keyboard_grab_window && !keyboard_grab_owner_events)
921           return _gdk_quartz_keyboard_grab_window;
922
923         event_mask = get_event_mask_from_ns_event (nsevent);
924         return find_window_interested_in_event_mask (current_keyboard_window, event_mask, TRUE);
925       }
926       break;
927
928     case NSAppKitDefined:
929     case NSSystemDefined:
930       /* We ignore these events */
931       break;
932     default:
933       NSLog(@"Unhandled event %@", nsevent);
934     }
935
936   return NULL;
937 }
938
939 static GdkEvent *
940 create_button_event (GdkWindow *window, NSEvent *nsevent,
941                      gint x, gint y)
942 {
943   GdkEvent *event;
944   GdkEventType type;
945   guint button;
946
947   switch ([nsevent type])
948     {
949     case NSLeftMouseDown:
950     case NSRightMouseDown:
951     case NSOtherMouseDown:
952       type = GDK_BUTTON_PRESS;
953       break;
954     case NSLeftMouseUp:
955     case NSRightMouseUp:
956     case NSOtherMouseUp:
957       type = GDK_BUTTON_RELEASE;
958       break;
959     default:
960       g_assert_not_reached ();
961     }
962   
963   button = convert_mouse_button_number ([nsevent buttonNumber]);
964
965   event = gdk_event_new (type);
966   event->button.window = window;
967   event->button.time = get_event_time (nsevent);
968   event->button.x = x;
969   event->button.y = y;
970   /* FIXME event->axes */
971   event->button.state = get_keyboard_modifiers_from_nsevent (nsevent);
972   event->button.button = button;
973   event->button.device = _gdk_display->core_pointer;
974   convert_window_coordinates_to_root (window, x, y, 
975                                       &event->button.x_root,
976                                       &event->button.y_root);
977
978   return event;
979 }
980
981 static GdkEvent *
982 create_motion_event (GdkWindow *window, NSEvent *nsevent, gint x, gint y)
983 {
984   GdkEvent *event;
985   GdkEventType type;
986   GdkModifierType state = 0;
987   int button = 0;
988
989   switch ([nsevent type])
990     {
991     case NSLeftMouseDragged:
992     case NSRightMouseDragged:
993     case NSOtherMouseDragged:
994       button = convert_mouse_button_number ([nsevent buttonNumber]);
995       /* Fall through */
996     case NSMouseMoved:
997       type = GDK_MOTION_NOTIFY;
998       break;
999     default:
1000       g_assert_not_reached ();
1001     }
1002
1003   /* This maps buttons 1 to 5 to GDK_BUTTON[1-5]_MASK */
1004   if (button >= 1 && button <= 5)
1005     state = (1 << (button + 7));
1006   
1007   state |= get_keyboard_modifiers_from_nsevent (nsevent);
1008
1009   event = gdk_event_new (type);
1010   event->motion.window = window;
1011   event->motion.time = get_event_time (nsevent);
1012   event->motion.x = x;
1013   event->motion.y = y;
1014   /* FIXME event->axes */
1015   event->motion.state = state;
1016   event->motion.is_hint = FALSE;
1017   event->motion.device = _gdk_display->core_pointer;
1018   convert_window_coordinates_to_root (window, x, y,
1019                                       &event->motion.x_root, &event->motion.y_root);
1020   
1021   return event;
1022 }
1023
1024 static GdkEvent *
1025 create_scroll_event (GdkWindow *window, NSEvent *nsevent, GdkScrollDirection direction)
1026 {
1027   GdkEvent *event;
1028   NSPoint point;
1029   
1030   event = gdk_event_new (GDK_SCROLL);
1031   event->scroll.window = window;
1032   event->scroll.time = get_event_time (nsevent);
1033
1034   point = [nsevent locationInWindow];
1035   event->scroll.x = point.x;
1036   event->scroll.y = point.y;
1037   convert_window_coordinates_to_root (window, event->scroll.x, event->scroll.y, 
1038                                       &event->scroll.x_root,
1039                                       &event->scroll.y_root);
1040
1041   event->scroll.direction = direction;
1042   event->scroll.device = _gdk_display->core_pointer;
1043   
1044   return event;
1045 }
1046
1047 static GdkEvent *
1048 create_key_event (GdkWindow *window, NSEvent *nsevent, GdkEventType type)
1049 {
1050   GdkEvent *event;
1051   gchar buf[7];
1052   gunichar c = 0;
1053
1054   event = gdk_event_new (type);
1055   event->key.window = window;
1056   event->key.time = get_event_time (nsevent);
1057   event->key.state = get_keyboard_modifiers_from_nsevent (nsevent);
1058   event->key.hardware_keycode = [nsevent keyCode];
1059   event->key.group = ([nsevent modifierFlags] & NSAlternateKeyMask) ? 1 : 0;
1060
1061   event->key.keyval = GDK_VoidSymbol;
1062   
1063   gdk_keymap_translate_keyboard_state (NULL,
1064                                        event->key.hardware_keycode,
1065                                        event->key.state, 
1066                                        event->key.group,
1067                                        &event->key.keyval,
1068                                        NULL, NULL, NULL);
1069
1070   event->key.is_modifier = _gdk_quartz_keys_is_modifier (event->key.hardware_keycode);
1071
1072   event->key.string = NULL;
1073
1074   /* Fill in ->string since apps depend on it, taken from the x11 backend. */
1075   if (event->key.keyval != GDK_VoidSymbol)
1076     c = gdk_keyval_to_unicode (event->key.keyval);
1077
1078     if (c)
1079     {
1080       gsize bytes_written;
1081       gint len;
1082
1083       len = g_unichar_to_utf8 (c, buf);
1084       buf[len] = '\0';
1085       
1086       event->key.string = g_locale_from_utf8 (buf, len,
1087                                               NULL, &bytes_written,
1088                                               NULL);
1089       if (event->key.string)
1090         event->key.length = bytes_written;
1091     }
1092   else if (event->key.keyval == GDK_Escape)
1093     {
1094       event->key.length = 1;
1095       event->key.string = g_strdup ("\033");
1096     }
1097   else if (event->key.keyval == GDK_Return ||
1098           event->key.keyval == GDK_KP_Enter)
1099     {
1100       event->key.length = 1;
1101       event->key.string = g_strdup ("\r");
1102     }
1103
1104   if (!event->key.string)
1105     {
1106       event->key.length = 0;
1107       event->key.string = g_strdup ("");
1108     }
1109
1110   GDK_NOTE(EVENTS,
1111     g_message ("key %s:\t\twindow: %p  key: %12s  %d",
1112           type == GDK_KEY_PRESS ? "press" : "release",
1113           event->key.window,
1114           event->key.keyval ? gdk_keyval_name (event->key.keyval) : "(none)",
1115           event->key.keyval));
1116   return event;
1117 }
1118
1119 static GdkEventMask current_mask = 0;
1120 GdkEventMask 
1121 _gdk_quartz_events_get_current_event_mask (void)
1122 {
1123   return current_mask;
1124 }
1125
1126 static gboolean
1127 gdk_event_translate (NSEvent *nsevent)
1128 {
1129   GdkWindow *window;
1130   GdkFilterReturn result;
1131   GdkEvent *event;
1132   int x, y;
1133
1134   if (_gdk_default_filters)
1135     {
1136       /* Apply global filters */
1137
1138       GdkFilterReturn result = apply_filters (NULL, nsevent, _gdk_default_filters);
1139       
1140       /* If result is GDK_FILTER_CONTINUE, we continue as if nothing
1141        * happened. If it is GDK_FILTER_REMOVE,
1142        * we return TRUE and won't send the message to Quartz.
1143        */
1144       if (result == GDK_FILTER_REMOVE)
1145         return TRUE;
1146     }
1147
1148   /* Catch the case where the entire app loses focus, and break any grabs. */
1149   if ([nsevent type] == NSAppKitDefined)
1150     {
1151       if ([nsevent subtype] == NSApplicationDeactivatedEventType)
1152         {
1153           if (_gdk_quartz_keyboard_grab_window)
1154             {
1155               generate_grab_broken_event (_gdk_quartz_keyboard_grab_window,
1156                                           TRUE, FALSE,
1157                                           NULL);
1158               g_object_unref (_gdk_quartz_keyboard_grab_window);
1159               _gdk_quartz_keyboard_grab_window = NULL;
1160             }
1161
1162           if (_gdk_quartz_pointer_grab_window)
1163             {
1164               generate_grab_broken_event (_gdk_quartz_pointer_grab_window,
1165                                           FALSE, pointer_grab_implicit,
1166                                           NULL);
1167               g_object_unref (_gdk_quartz_pointer_grab_window);
1168               _gdk_quartz_pointer_grab_window = NULL;
1169             }
1170         }
1171     }
1172
1173   window = find_window_for_event (nsevent, &x, &y);
1174
1175   /* FIXME: During owner_event grabs, we don't find a window when there is a
1176    * click on a no-window widget, which makes popups etc still stay up. Need
1177    * to figure out why that is.
1178    */
1179   
1180   if (!window)
1181     return FALSE;
1182
1183   result = apply_filters (window, nsevent, ((GdkWindowObject *) window)->filters);
1184
1185   if (result == GDK_FILTER_REMOVE)
1186     return TRUE;
1187
1188   current_mask = get_event_mask_from_ns_event (nsevent);
1189
1190   switch ([nsevent type])
1191     {
1192     case NSLeftMouseDown:
1193     case NSRightMouseDown:
1194     case NSOtherMouseDown:
1195       {
1196         GdkEventMask event_mask;
1197
1198         /* Emulate implicit grab, when the window has both PRESS and RELEASE
1199          * in its mask, like X (and make it owner_events since that's what
1200          * implicit grabs are like).
1201          */
1202         event_mask = (GDK_BUTTON_RELEASE_MASK | GDK_BUTTON_RELEASE_MASK);
1203         if (!_gdk_quartz_pointer_grab_window &&
1204             (GDK_WINDOW_OBJECT (window)->event_mask & event_mask) == event_mask)
1205           {
1206             pointer_grab_internal (window, TRUE,
1207                                    GDK_WINDOW_OBJECT (window)->event_mask,
1208                                    NULL, NULL, TRUE);
1209           }
1210       }
1211       
1212       event = create_button_event (window, nsevent, x, y);
1213       append_event (event);
1214       
1215       _gdk_event_button_generate (_gdk_display, event);
1216       break;
1217
1218     case NSLeftMouseUp:
1219     case NSRightMouseUp:
1220     case NSOtherMouseUp:
1221       event = create_button_event (window, nsevent, x, y);
1222       append_event (event);
1223       
1224       /* Ungrab implicit grab */
1225       if (_gdk_quartz_pointer_grab_window &&
1226           pointer_grab_implicit)
1227         pointer_ungrab_internal (TRUE);
1228       break;
1229
1230     case NSLeftMouseDragged:
1231     case NSRightMouseDragged:
1232     case NSOtherMouseDragged:
1233     case NSMouseMoved:
1234       event = create_motion_event (window, nsevent, x, y);
1235       append_event (event);
1236       break;
1237
1238     case NSScrollWheel:
1239       {
1240         float dx = [nsevent deltaX];
1241         float dy = [nsevent deltaY];
1242         GdkScrollDirection direction;
1243
1244         /* The delta is how much the mouse wheel has moved. Since there's no such thing in GTK+
1245          * we accomodate by sending a different number of scroll wheel events.
1246          */
1247
1248         /* First do y events */
1249         if (dy < 0.0)
1250           {
1251             dy = -dy;
1252             direction = GDK_SCROLL_DOWN;
1253           }
1254         else
1255           direction = GDK_SCROLL_UP;
1256
1257         while (dy > 0.0)
1258           {
1259             event = create_scroll_event (window, nsevent, direction);
1260             append_event (event);
1261             dy--;
1262           }
1263
1264         /* Now do x events */
1265         if (dx < 0.0)
1266           {
1267             dx = -dx;
1268             direction = GDK_SCROLL_RIGHT;
1269           }
1270         else
1271           direction = GDK_SCROLL_LEFT;
1272
1273         while (dx > 0.0)
1274           {
1275             event = create_scroll_event (window, nsevent, direction);
1276             append_event (event);
1277             dx--;
1278           }
1279
1280         break;
1281       }
1282     case NSKeyDown:
1283     case NSKeyUp:
1284     case NSFlagsChanged:
1285       {
1286         GdkEventType type;
1287
1288         type = _gdk_quartz_keys_event_type (nsevent);
1289         if (type == GDK_NOTHING)
1290           return FALSE;
1291         
1292         event = create_key_event (window, nsevent, type);
1293         append_event (event);
1294         return TRUE;
1295       }
1296       break;
1297     default:
1298       NSLog(@"Untranslated: %@", nsevent);
1299     }
1300
1301   return FALSE;
1302 }
1303
1304 void
1305 _gdk_events_queue (GdkDisplay *display)
1306 {  
1307   NSEvent *current_event = _gdk_quartz_event_loop_get_current ();
1308
1309   if (current_event)
1310     {
1311       if (!gdk_event_translate (current_event)) 
1312         [NSApp sendEvent:current_event];
1313                 
1314       _gdk_quartz_event_loop_release_current ();
1315     }
1316 }
1317
1318 void
1319 gdk_flush (void)
1320 {
1321   /* Not supported. */
1322 }
1323
1324 void 
1325 gdk_display_add_client_message_filter (GdkDisplay   *display,
1326                                        GdkAtom       message_type,
1327                                        GdkFilterFunc func,
1328                                        gpointer      data)
1329 {
1330   /* Not supported. */
1331 }
1332
1333 void 
1334 gdk_add_client_message_filter (GdkAtom       message_type,
1335                                GdkFilterFunc func,
1336                                gpointer      data)
1337 {
1338   /* Not supported. */
1339 }
1340
1341 void
1342 gdk_display_sync (GdkDisplay *display)
1343 {
1344   /* Not supported. */
1345 }
1346
1347 void
1348 gdk_display_flush (GdkDisplay *display)
1349 {
1350   /* Not supported. */
1351 }
1352
1353 gboolean
1354 gdk_event_send_client_message_for_display (GdkDisplay      *display,
1355                                            GdkEvent        *event,
1356                                            GdkNativeWindow  winid)
1357 {
1358   /* Not supported. */
1359   return FALSE;
1360 }
1361
1362 void
1363 gdk_screen_broadcast_client_message (GdkScreen *screen,
1364                                      GdkEvent  *event)
1365 {
1366   /* Not supported. */
1367 }
1368
1369 gboolean
1370 gdk_screen_get_setting (GdkScreen   *screen,
1371                         const gchar *name,
1372                         GValue      *value)
1373 {
1374   if (strcmp (name, "gtk-double-click-time") == 0)
1375     {
1376       NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
1377       float t;
1378
1379       GDK_QUARTZ_ALLOC_POOL;
1380             
1381       t = [defaults floatForKey:@"com.apple.mouse.doubleClickThreshold"];
1382       if (t == 0.0)
1383         {
1384           /* No user setting, use the default in OS X. */
1385           t = 0.5;
1386         }
1387
1388       GDK_QUARTZ_RELEASE_POOL;
1389
1390       g_value_set_int (value, t * 1000);
1391       return TRUE;
1392     }
1393   
1394   /* FIXME: Add more settings */
1395
1396   return FALSE;
1397 }
1398