]> Pileus Git - ~andy/gtk/blob - gdk/quartz/gdkevents-quartz.c
Update Quartz backend for GDK key name changes
[~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 #include "gdkdevicemanager-core.h"
36
37 #define GRIP_WIDTH 15
38 #define GRIP_HEIGHT 15
39
40 #define WINDOW_IS_TOPLEVEL(window)                   \
41   (GDK_WINDOW_TYPE (window) != GDK_WINDOW_CHILD &&   \
42    GDK_WINDOW_TYPE (window) != GDK_WINDOW_FOREIGN && \
43    GDK_WINDOW_TYPE (window) != GDK_WINDOW_OFFSCREEN)
44
45 /* This is the window corresponding to the key window */
46 static GdkWindow   *current_keyboard_window;
47
48 /* This is the event mask and button state from the last event */
49 static GdkEventMask current_event_mask;
50 static int          current_button_state;
51
52 static void append_event                        (GdkEvent  *event,
53                                                  gboolean   windowing);
54
55 NSEvent *
56 gdk_quartz_event_get_nsevent (GdkEvent *event)
57 {
58   /* FIXME: If the event here is unallocated, we crash. */
59   return ((GdkEventPrivate *) event)->windowing_data;
60 }
61
62 void
63 _gdk_events_init (void)
64 {
65   _gdk_quartz_event_loop_init ();
66
67   current_keyboard_window = g_object_ref (_gdk_root);
68 }
69
70 gboolean
71 gdk_events_pending (void)
72 {
73   return (_gdk_event_queue_find_first (_gdk_display) ||
74           (_gdk_quartz_event_loop_check_pending ()));
75 }
76
77 void
78 gdk_device_ungrab (GdkDevice *device,
79                    guint32    time_)
80 {
81   GdkDeviceGrabInfo *grab;
82
83   grab = _gdk_display_get_last_device_grab (_gdk_display, device);
84   if (grab)
85     grab->serial_end = 0;
86
87   _gdk_display_device_grab_update (_gdk_display, device, 0);
88 }
89
90 GdkGrabStatus
91 _gdk_windowing_device_grab (GdkDevice    *device,
92                             GdkWindow    *window,
93                             GdkWindow    *native,
94                             gboolean      owner_events,
95                             GdkEventMask  event_mask,
96                             GdkWindow    *confine_to,
97                             GdkCursor    *cursor,
98                             guint32       time)
99 {
100   g_return_val_if_fail (GDK_IS_WINDOW (window), 0);
101   g_return_val_if_fail (confine_to == NULL || GDK_IS_WINDOW (confine_to), 0);
102
103   if (!window || GDK_WINDOW_DESTROYED (window))
104     return GDK_GRAB_NOT_VIEWABLE;
105
106   _gdk_display_add_device_grab (_gdk_display,
107                                 device,
108                                 window,
109                                 native,
110                                 GDK_OWNERSHIP_NONE,
111                                 owner_events,
112                                 event_mask,
113                                 0,
114                                 time,
115                                 FALSE);
116
117   return GDK_GRAB_SUCCESS;
118 }
119
120 static void
121 break_all_grabs (guint32 time)
122 {
123   GList *list, *l;
124   GdkDeviceManager *device_manager;
125
126   device_manager = gdk_display_get_device_manager (_gdk_display);
127   list = gdk_device_manager_list_devices (device_manager,
128                                           GDK_DEVICE_TYPE_MASTER);
129   for (l = list; l; l = l->next)
130     {
131       GdkDeviceGrabInfo *grab;
132
133       grab = _gdk_display_get_last_device_grab (_gdk_display, l->data);
134       if (grab)
135         {
136           grab->serial_end = 0;
137           grab->implicit_ungrab = TRUE;
138         }
139
140       _gdk_display_device_grab_update (_gdk_display, l->data, 0);
141     }
142
143   g_list_free (list);
144 }
145
146 static void
147 fixup_event (GdkEvent *event)
148 {
149   if (event->any.window)
150     g_object_ref (event->any.window);
151   if (((event->any.type == GDK_ENTER_NOTIFY) ||
152        (event->any.type == GDK_LEAVE_NOTIFY)) &&
153       (event->crossing.subwindow != NULL))
154     g_object_ref (event->crossing.subwindow);
155   event->any.send_event = FALSE;
156 }
157
158 static void
159 append_event (GdkEvent *event,
160               gboolean  windowing)
161 {
162   GList *node;
163
164   fixup_event (event);
165   node = _gdk_event_queue_append (_gdk_display, event);
166
167   if (windowing)
168     _gdk_windowing_got_event (_gdk_display, node, event, 0);
169 }
170
171 static gint
172 gdk_event_apply_filters (NSEvent *nsevent,
173                          GdkEvent *event,
174                          GList *filters)
175 {
176   GList *tmp_list;
177   GdkFilterReturn result;
178   
179   tmp_list = filters;
180
181   while (tmp_list)
182     {
183       GdkEventFilter *filter = (GdkEventFilter*) tmp_list->data;
184       
185       tmp_list = tmp_list->next;
186       result = filter->function (nsevent, event, filter->data);
187       if (result !=  GDK_FILTER_CONTINUE)
188         return result;
189     }
190
191   return GDK_FILTER_CONTINUE;
192 }
193
194 static guint32
195 get_time_from_ns_event (NSEvent *event)
196 {
197   double time = [event timestamp];
198   
199   return time * 1000.0;
200 }
201
202 static int
203 get_mouse_button_from_ns_event (NSEvent *event)
204 {
205   NSInteger button;
206
207   button = [event buttonNumber];
208
209   switch (button)
210     {
211     case 0:
212       return 1;
213     case 1:
214       return 3;
215     case 2:
216       return 2;
217     default:
218       return button + 1;
219     }
220 }
221
222 static GdkModifierType
223 get_mouse_button_modifiers_from_ns_event (NSEvent *event)
224 {
225   int button;
226   GdkModifierType state = 0;
227
228   /* This maps buttons 1 to 5 to GDK_BUTTON[1-5]_MASK */
229   button = get_mouse_button_from_ns_event (event);
230   if (button >= 1 && button <= 5)
231     state = (1 << (button + 7));
232
233   return state;
234 }
235
236 static GdkModifierType
237 get_keyboard_modifiers_from_ns_event (NSEvent *nsevent)
238 {
239   GdkModifierType modifiers = 0;
240   int nsflags;
241
242   nsflags = [nsevent modifierFlags];
243   
244   if (nsflags & NSAlphaShiftKeyMask)
245     modifiers |= GDK_LOCK_MASK;
246   if (nsflags & NSShiftKeyMask)
247     modifiers |= GDK_SHIFT_MASK;
248   if (nsflags & NSControlKeyMask)
249     modifiers |= GDK_CONTROL_MASK;
250   if (nsflags & NSCommandKeyMask)
251     modifiers |= GDK_MOD1_MASK;
252
253   return modifiers;
254 }
255
256 /* Return an event mask from an NSEvent */
257 static GdkEventMask
258 get_event_mask_from_ns_event (NSEvent *nsevent)
259 {
260   switch ([nsevent type])
261     {
262     case NSLeftMouseDown:
263     case NSRightMouseDown:
264     case NSOtherMouseDown:
265       return GDK_BUTTON_PRESS_MASK;
266     case NSLeftMouseUp:
267     case NSRightMouseUp:
268     case NSOtherMouseUp:
269       return GDK_BUTTON_RELEASE_MASK;
270     case NSMouseMoved:
271       return GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK;
272     case NSScrollWheel:
273       /* Since applications that want button press events can get
274        * scroll events on X11 (since scroll wheel events are really
275        * button press events there), we need to use GDK_BUTTON_PRESS_MASK too.
276        */
277       return GDK_SCROLL_MASK | GDK_BUTTON_PRESS_MASK;
278     case NSLeftMouseDragged:
279       return (GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK |
280               GDK_BUTTON_MOTION_MASK | GDK_BUTTON1_MOTION_MASK | 
281               GDK_BUTTON1_MASK);
282     case NSRightMouseDragged:
283       return (GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK |
284               GDK_BUTTON_MOTION_MASK | GDK_BUTTON3_MOTION_MASK | 
285               GDK_BUTTON3_MASK);
286     case NSOtherMouseDragged:
287       {
288         GdkEventMask mask;
289
290         mask = (GDK_POINTER_MOTION_MASK |
291                 GDK_POINTER_MOTION_HINT_MASK |
292                 GDK_BUTTON_MOTION_MASK);
293
294         if (get_mouse_button_from_ns_event (nsevent) == 2)
295           mask |= (GDK_BUTTON2_MOTION_MASK | GDK_BUTTON2_MOTION_MASK | 
296                    GDK_BUTTON2_MASK);
297
298         return mask;
299       }
300     case NSKeyDown:
301     case NSKeyUp:
302     case NSFlagsChanged:
303       {
304         switch (_gdk_quartz_keys_event_type (nsevent))
305           {
306           case GDK_KEY_PRESS:
307             return GDK_KEY_PRESS_MASK;
308           case GDK_KEY_RELEASE:
309             return GDK_KEY_RELEASE_MASK;
310           case GDK_NOTHING:
311             return 0;
312           default:
313             g_assert_not_reached ();
314           }
315       }
316       break;
317
318     case NSMouseEntered:
319       return GDK_ENTER_NOTIFY_MASK;
320
321     case NSMouseExited:
322       return GDK_LEAVE_NOTIFY_MASK;
323
324     default:
325       g_assert_not_reached ();
326     }
327
328   return 0;
329 }
330
331 static GdkEvent *
332 create_focus_event (GdkWindow *window,
333                     gboolean   in)
334 {
335   GdkEvent *event;
336   GdkDeviceManagerCore *device_manager;
337
338   event = gdk_event_new (GDK_FOCUS_CHANGE);
339   event->focus_change.window = window;
340   event->focus_change.in = in;
341
342   device_manager = GDK_DEVICE_MANAGER_CORE (_gdk_display->device_manager);
343   gdk_event_set_device (event, device_manager->core_keyboard);
344
345   return event;
346 }
347
348
349 static void
350 generate_motion_event (GdkWindow *window)
351 {
352   NSPoint point;
353   NSPoint screen_point;
354   NSWindow *nswindow;
355   GdkQuartzView *view;
356   GdkWindowObject *private;
357   GdkEvent *event;
358   gint x, y, x_root, y_root;
359   GdkDisplay *display;
360
361   event = gdk_event_new (GDK_MOTION_NOTIFY);
362   event->any.window = NULL;
363   event->any.send_event = TRUE;
364
365   private = (GdkWindowObject *)window;
366   nswindow = ((GdkWindowImplQuartz *)private->impl)->toplevel;
367   view = (GdkQuartzView *)[nswindow contentView];
368
369   display = gdk_drawable_get_display (window);
370
371   screen_point = [NSEvent mouseLocation];
372
373   _gdk_quartz_window_nspoint_to_gdk_xy (screen_point, &x_root, &y_root);
374
375   point = [nswindow convertScreenToBase:screen_point];
376
377   x = point.x;
378   y = private->height - point.y;
379
380   event->any.type = GDK_MOTION_NOTIFY;
381   event->motion.window = window;
382   event->motion.time = GDK_CURRENT_TIME;
383   event->motion.x = x;
384   event->motion.y = y;
385   event->motion.x_root = x_root;
386   event->motion.y_root = y_root;
387   /* FIXME event->axes */
388   event->motion.state = 0;
389   event->motion.is_hint = FALSE;
390   event->motion.device = _gdk_display->core_pointer;
391
392   append_event (event, TRUE);
393 }
394
395 /* Note: Used to both set a new focus window and to unset the old one. */
396 void
397 _gdk_quartz_events_update_focus_window (GdkWindow *window,
398                                         gboolean   got_focus)
399 {
400   GdkEvent *event;
401
402   if (got_focus && window == current_keyboard_window)
403     return;
404
405   /* FIXME: Don't do this when grabbed? Or make GdkQuartzWindow
406    * disallow it in the first place instead?
407    */
408   
409   if (!got_focus && window == current_keyboard_window)
410     {
411       event = create_focus_event (current_keyboard_window, FALSE);
412       append_event (event, FALSE);
413       g_object_unref (current_keyboard_window);
414       current_keyboard_window = NULL;
415     }
416
417   if (got_focus)
418     {
419       if (current_keyboard_window)
420         {
421           event = create_focus_event (current_keyboard_window, FALSE);
422           append_event (event, FALSE);
423           g_object_unref (current_keyboard_window);
424           current_keyboard_window = NULL;
425         }
426       
427       event = create_focus_event (window, TRUE);
428       append_event (event, FALSE);
429       current_keyboard_window = g_object_ref (window);
430
431       /* We just became the active window.  Unlike X11, Mac OS X does
432        * not send us motion events while the window does not have focus
433        * ("is not key").  We send a dummy motion notify event now, so that
434        * everything in the window is set to correct state.
435        */
436       generate_motion_event (window);
437     }
438 }
439
440 void
441 _gdk_quartz_events_send_enter_notify_event (GdkWindow *window)
442 {
443   NSPoint point;
444   NSPoint screen_point;
445   NSWindow *nswindow;
446   GdkWindowObject *private;
447   GdkEvent *event;
448   gint x, y, x_root, y_root;
449
450   event = gdk_event_new (GDK_ENTER_NOTIFY);
451   event->any.window = NULL;
452   event->any.send_event = FALSE;
453
454   private = (GdkWindowObject *)window;
455   nswindow = ((GdkWindowImplQuartz *)private->impl)->toplevel;
456
457   screen_point = [NSEvent mouseLocation];
458
459   _gdk_quartz_window_nspoint_to_gdk_xy (screen_point, &x_root, &y_root);
460
461   point = [nswindow convertScreenToBase:screen_point];
462
463   x = point.x;
464   y = private->height - point.y;
465
466   event->crossing.window = window;
467   event->crossing.subwindow = NULL;
468   event->crossing.time = GDK_CURRENT_TIME;
469   event->crossing.x = x;
470   event->crossing.y = y;
471   event->crossing.x_root = x_root;
472   event->crossing.y_root = y_root;
473   event->crossing.mode = GDK_CROSSING_NORMAL;
474   event->crossing.detail = GDK_NOTIFY_ANCESTOR;
475   event->crossing.state = 0;
476
477   gdk_event_set_device (event, _gdk_display->core_pointer);
478
479   append_event (event, TRUE);
480 }
481
482 void
483 _gdk_quartz_events_send_map_event (GdkWindow *window)
484 {
485   GdkWindowObject *private = (GdkWindowObject *)window;
486   GdkWindowImplQuartz *impl = GDK_WINDOW_IMPL_QUARTZ (private->impl);
487
488   if (!impl->toplevel)
489     return;
490
491   if (private->event_mask & GDK_STRUCTURE_MASK)
492     {
493       GdkEvent event;
494
495       event.any.type = GDK_MAP;
496       event.any.window = window;
497   
498       gdk_event_put (&event);
499     }
500 }
501
502 static GdkWindow *
503 find_toplevel_under_pointer (GdkDisplay *display,
504                              NSPoint     screen_point,
505                              gint       *x,
506                              gint       *y)
507 {
508   GdkWindow *toplevel;
509   GdkPointerWindowInfo *info;
510
511   info = _gdk_display_get_pointer_info (display, display->core_pointer);
512   toplevel = info->toplevel_under_pointer;
513   if (toplevel && WINDOW_IS_TOPLEVEL (toplevel))
514     {
515       GdkWindowObject *private;
516       NSWindow *nswindow;
517       NSPoint point;
518
519       private = (GdkWindowObject *)toplevel;
520       nswindow = ((GdkWindowImplQuartz *)private->impl)->toplevel;
521
522       point = [nswindow convertScreenToBase:screen_point];
523
524       *x = point.x;
525       *y = private->height - point.y;
526     }
527
528   return toplevel;
529 }
530
531 static GdkWindow *
532 find_toplevel_for_keyboard_event (NSEvent *nsevent)
533 {
534   GList *list, *l;
535   GdkWindow *window;
536   GdkDisplay *display;
537   GdkQuartzView *view;
538   GdkDeviceManager *device_manager;
539
540   view = (GdkQuartzView *)[[nsevent window] contentView];
541   window = [view gdkWindow];
542
543   display = gdk_drawable_get_display (GDK_DRAWABLE (window));
544
545   device_manager = gdk_display_get_device_manager (display);
546   list = gdk_device_manager_list_devices (device_manager,
547                                           GDK_DEVICE_TYPE_MASTER);
548   for (l = list; l; l = l->next)
549     {
550       GdkDeviceGrabInfo *grab;
551       GdkDevice *device = l->data;
552
553       if (device->source != GDK_SOURCE_KEYBOARD)
554         continue;
555
556       grab = _gdk_display_get_last_device_grab (display, device);
557       if (grab && grab->window && !grab->owner_events)
558         {
559           window = gdk_window_get_effective_toplevel (grab->window);
560           break;
561         }
562     }
563
564   g_list_free (list);
565
566   return window;
567 }
568
569 static GdkWindow *
570 find_toplevel_for_mouse_event (NSEvent    *nsevent,
571                                gint       *x,
572                                gint       *y)
573 {
574   NSPoint point;
575   NSPoint screen_point;
576   NSEventType event_type;
577   GdkWindow *toplevel;
578   GdkQuartzView *view;
579   GdkDisplay *display;
580   GdkDeviceGrabInfo *grab;
581   GdkWindowObject *private;
582
583   view = (GdkQuartzView *)[[nsevent window] contentView];
584   toplevel = [view gdkWindow];
585
586   display = gdk_drawable_get_display (toplevel);
587   private = GDK_WINDOW_OBJECT (toplevel);
588
589   event_type = [nsevent type];
590   point = [nsevent locationInWindow];
591   screen_point = [[nsevent window] convertBaseToScreen:point];
592
593   /* From the docs for XGrabPointer:
594    *
595    * If owner_events is True and if a generated pointer event
596    * would normally be reported to this client, it is reported
597    * as usual. Otherwise, the event is reported with respect to
598    * the grab_window and is reported only if selected by
599    * event_mask. For either value of owner_events, unreported
600    * events are discarded.
601    */
602   grab = _gdk_display_get_last_device_grab (display,
603                                             display->core_pointer);
604   if (WINDOW_IS_TOPLEVEL (toplevel) && grab)
605     {
606       /* Implicit grabs do not go through XGrabPointer and thus the
607        * event mask should not be checked.
608        */
609       if (!grab->implicit
610           && (grab->event_mask & get_event_mask_from_ns_event (nsevent)) == 0)
611         return NULL;
612
613       if (grab->owner_events)
614         {
615           /* For owner events, we need to use the toplevel under the
616            * pointer, not the window from the NSEvent, since that is
617            * reported with respect to the key window, which could be
618            * wrong.
619            */
620           GdkWindow *toplevel_under_pointer;
621           gint x_tmp, y_tmp;
622
623           toplevel_under_pointer = find_toplevel_under_pointer (display,
624                                                                 screen_point,
625                                                                 &x_tmp, &y_tmp);
626           if (toplevel_under_pointer)
627             {
628               toplevel = toplevel_under_pointer;
629               *x = x_tmp;
630               *y = y_tmp;
631             }
632
633           return toplevel;
634         }
635       else
636         {
637           /* Finally check the grab window. */
638           GdkWindow *grab_toplevel;
639           GdkWindowObject *grab_private;
640           NSWindow *grab_nswindow;
641
642           grab_toplevel = gdk_window_get_effective_toplevel (grab->window);
643           grab_private = (GdkWindowObject *)grab_toplevel;
644
645           grab_nswindow = ((GdkWindowImplQuartz *)grab_private->impl)->toplevel;
646           point = [grab_nswindow convertScreenToBase:screen_point];
647
648           /* Note: x_root and y_root are already right. */
649           *x = point.x;
650           *y = grab_private->height - point.y;
651
652           return grab_toplevel;
653         }
654
655       return NULL;
656     }
657   else 
658     {
659       /* The non-grabbed case. */
660       GdkWindow *toplevel_under_pointer;
661       gint x_tmp, y_tmp;
662
663       /* Ignore all events but mouse moved that might be on the title
664        * bar (above the content view). The reason is that otherwise
665        * gdk gets confused about getting e.g. button presses with no
666        * window (the title bar is not known to it).
667        */
668       if (event_type != NSMouseMoved)
669         if (*y < 0)
670           return NULL;
671
672       /* As for owner events, we need to use the toplevel under the
673        * pointer, not the window from the NSEvent.
674        */
675       toplevel_under_pointer = find_toplevel_under_pointer (display,
676                                                             screen_point,
677                                                             &x_tmp, &y_tmp);
678       if (toplevel_under_pointer
679           && WINDOW_IS_TOPLEVEL (toplevel_under_pointer))
680         {
681           GdkWindowObject *toplevel_private;
682           GdkWindowImplQuartz *toplevel_impl;
683
684           toplevel = toplevel_under_pointer;
685
686           toplevel_private = (GdkWindowObject *)toplevel;
687           toplevel_impl = (GdkWindowImplQuartz *)toplevel_private->impl;
688
689           if ([toplevel_impl->toplevel showsResizeIndicator])
690             {
691               NSRect frame;
692
693               /* If the resize indicator is visible and the event
694                * is in the lower right 15x15 corner, we leave these
695                * events to Cocoa as to be handled as resize events.
696                * Applications may have widgets in this area.  These
697                * will most likely be larger than 15x15 and for
698                * scroll bars there are also other means to move
699                * the scroll bar.  Since the resize indicator is
700                * the only way of resizing windows on Mac OS, it
701                * is too important to not make functional.
702                */
703               frame = [toplevel_impl->view bounds];
704               if (x_tmp > frame.size.width - GRIP_WIDTH
705                   && x_tmp < frame.size.width
706                   && y_tmp > frame.size.height - GRIP_HEIGHT
707                   && y_tmp < frame.size.height)
708                 {
709                   return NULL;
710                 }
711             }
712
713           *x = x_tmp;
714           *y = y_tmp;
715         }
716
717       return toplevel;
718     }
719
720   return NULL;
721 }
722
723 /* This function finds the correct window to send an event to, taking
724  * into account grabs, event propagation, and event masks.
725  */
726 static GdkWindow *
727 find_window_for_ns_event (NSEvent *nsevent, 
728                           gint    *x, 
729                           gint    *y,
730                           gint    *x_root,
731                           gint    *y_root)
732 {
733   GdkQuartzView *view;
734   NSPoint point;
735   NSPoint screen_point;
736   NSEventType event_type;
737   GdkWindow *toplevel;
738   GdkWindowObject *private;
739
740   view = (GdkQuartzView *)[[nsevent window] contentView];
741   toplevel = [view gdkWindow];
742   private = GDK_WINDOW_OBJECT (toplevel);
743
744   point = [nsevent locationInWindow];
745   screen_point = [[nsevent window] convertBaseToScreen:point];
746
747   *x = point.x;
748   *y = private->height - point.y;
749
750   _gdk_quartz_window_nspoint_to_gdk_xy (screen_point, x_root, y_root);
751
752   event_type = [nsevent type];
753
754   switch (event_type)
755     {
756     case NSLeftMouseDown:
757     case NSRightMouseDown:
758     case NSOtherMouseDown:
759     case NSLeftMouseUp:
760     case NSRightMouseUp:
761     case NSOtherMouseUp:
762     case NSMouseMoved:
763     case NSScrollWheel:
764     case NSLeftMouseDragged:
765     case NSRightMouseDragged:
766     case NSOtherMouseDragged:
767       return find_toplevel_for_mouse_event (nsevent, x, y);
768       
769     case NSMouseEntered:
770     case NSMouseExited:
771       /* Only handle our own entered/exited events, not the ones for the
772        * titlebar buttons.
773        */
774       if ([view trackingRect] == [nsevent trackingNumber])
775         return toplevel;
776       else
777         return NULL;
778
779     case NSKeyDown:
780     case NSKeyUp:
781     case NSFlagsChanged:
782       return find_toplevel_for_keyboard_event (nsevent);
783
784     default:
785       /* Ignore everything else. */
786       break;
787     }
788
789   return NULL;
790 }
791
792 static void
793 fill_crossing_event (GdkWindow       *toplevel,
794                      GdkEvent        *event,
795                      NSEvent         *nsevent,
796                      gint             x,
797                      gint             y,
798                      gint             x_root,
799                      gint             y_root,
800                      GdkEventType     event_type,
801                      GdkCrossingMode  mode,
802                      GdkNotifyType    detail)
803 {
804   event->any.type = event_type;
805   event->crossing.window = toplevel;
806   event->crossing.subwindow = NULL;
807   event->crossing.time = get_time_from_ns_event (nsevent);
808   event->crossing.x = x;
809   event->crossing.y = y;
810   event->crossing.x_root = x_root;
811   event->crossing.y_root = y_root;
812   event->crossing.mode = mode;
813   event->crossing.detail = detail;
814   event->crossing.state = get_keyboard_modifiers_from_ns_event (nsevent);
815
816   gdk_event_set_device (event, _gdk_display->core_pointer);
817
818   /* FIXME: Focus and button state? */
819 }
820
821 static void
822 fill_button_event (GdkWindow *window,
823                    GdkEvent  *event,
824                    NSEvent   *nsevent,
825                    gint       x,
826                    gint       y,
827                    gint       x_root,
828                    gint       y_root)
829 {
830   GdkEventType type;
831   gint state;
832   gint button;
833
834   state = get_keyboard_modifiers_from_ns_event (nsevent);
835
836   switch ([nsevent type])
837     {
838     case NSLeftMouseDown:
839     case NSRightMouseDown:
840     case NSOtherMouseDown:
841       type = GDK_BUTTON_PRESS;
842       break;
843     case NSLeftMouseUp:
844     case NSRightMouseUp:
845     case NSOtherMouseUp:
846       type = GDK_BUTTON_RELEASE;
847       state |= get_mouse_button_modifiers_from_ns_event (nsevent);
848       break;
849     default:
850       g_assert_not_reached ();
851     }
852   
853   button = get_mouse_button_from_ns_event (nsevent);
854
855   event->any.type = type;
856   event->button.window = window;
857   event->button.time = get_time_from_ns_event (nsevent);
858   event->button.x = x;
859   event->button.y = y;
860   event->button.x_root = x_root;
861   event->button.y_root = y_root;
862   /* FIXME event->axes */
863   event->button.state = state;
864   event->button.button = button;
865   event->button.device = _gdk_display->core_pointer;
866 }
867
868 static void
869 fill_motion_event (GdkWindow *window,
870                    GdkEvent  *event,
871                    NSEvent   *nsevent,
872                    gint       x,
873                    gint       y,
874                    gint       x_root,
875                    gint       y_root)
876 {
877   GdkModifierType state;
878
879   state = get_keyboard_modifiers_from_ns_event (nsevent);
880
881   switch ([nsevent type])
882     {
883     case NSLeftMouseDragged:
884     case NSRightMouseDragged:
885     case NSOtherMouseDragged:
886       state |= get_mouse_button_modifiers_from_ns_event (nsevent);
887       break;
888
889     case NSMouseMoved:
890       break;
891     }
892
893   event->any.type = GDK_MOTION_NOTIFY;
894   event->motion.window = window;
895   event->motion.time = get_time_from_ns_event (nsevent);
896   event->motion.x = x;
897   event->motion.y = y;
898   event->motion.x_root = x_root;
899   event->motion.y_root = y_root;
900   /* FIXME event->axes */
901   event->motion.state = state;
902   event->motion.is_hint = FALSE;
903   event->motion.device = _gdk_display->core_pointer;
904 }
905
906 static void
907 fill_scroll_event (GdkWindow          *window,
908                    GdkEvent           *event,
909                    NSEvent            *nsevent,
910                    gint                x,
911                    gint                y,
912                    gint                x_root,
913                    gint                y_root,
914                    GdkScrollDirection  direction)
915 {
916   GdkWindowObject *private;
917   NSPoint point;
918
919   private = GDK_WINDOW_OBJECT (window);
920
921   point = [nsevent locationInWindow];
922
923   event->any.type = GDK_SCROLL;
924   event->scroll.window = window;
925   event->scroll.time = get_time_from_ns_event (nsevent);
926   event->scroll.x = x;
927   event->scroll.y = y;
928   event->scroll.x_root = x_root;
929   event->scroll.y_root = y_root;
930   event->scroll.state = get_keyboard_modifiers_from_ns_event (nsevent);
931   event->scroll.direction = direction;
932   event->scroll.device = _gdk_display->core_pointer;
933 }
934
935 static void
936 fill_key_event (GdkWindow    *window,
937                 GdkEvent     *event,
938                 NSEvent      *nsevent,
939                 GdkEventType  type)
940 {
941   GdkEventPrivate *priv;
942   GdkDeviceManagerCore *device_manager;
943   gchar buf[7];
944   gunichar c = 0;
945
946   priv = (GdkEventPrivate *) event;
947   priv->windowing_data = [nsevent retain];
948
949   event->any.type = type;
950   event->key.window = window;
951   event->key.time = get_time_from_ns_event (nsevent);
952   event->key.state = get_keyboard_modifiers_from_ns_event (nsevent);
953   event->key.hardware_keycode = [nsevent keyCode];
954   event->key.group = ([nsevent modifierFlags] & NSAlternateKeyMask) ? 1 : 0;
955   event->key.keyval = GDK_KEY_VoidSymbol;
956
957   device_manager = GDK_DEVICE_MANAGER_CORE (_gdk_display->device_manager);
958   gdk_event_set_device (event, device_manager->core_keyboard);
959   
960   gdk_keymap_translate_keyboard_state (NULL,
961                                        event->key.hardware_keycode,
962                                        event->key.state, 
963                                        event->key.group,
964                                        &event->key.keyval,
965                                        NULL, NULL, NULL);
966
967   event->key.is_modifier = _gdk_quartz_keys_is_modifier (event->key.hardware_keycode);
968
969   /* If the key press is a modifier, the state should include the mask
970    * for that modifier but only for releases, not presses. This
971    * matches the X11 backend behavior.
972    */
973   if (event->key.is_modifier)
974     {
975       int mask = 0;
976
977       switch (event->key.keyval)
978         {
979         case GDK_KEY_Meta_R:
980         case GDK_KEY_Meta_L:
981           mask = GDK_MOD1_MASK;
982           break;
983         case GDK_KEY_Shift_R:
984         case GDK_KEY_Shift_L:
985           mask = GDK_SHIFT_MASK;
986           break;
987         case GDK_KEY_Caps_Lock:
988           mask = GDK_LOCK_MASK;
989           break;
990         case GDK_KEY_Alt_R:
991         case GDK_KEY_Alt_L:
992           mask = GDK_MOD5_MASK;
993           break;
994         case GDK_KEY_Control_R:
995         case GDK_KEY_Control_L:
996           mask = GDK_CONTROL_MASK;
997           break;
998         default:
999           mask = 0;
1000         }
1001
1002       if (type == GDK_KEY_PRESS)
1003         event->key.state &= ~mask;
1004       else if (type == GDK_KEY_RELEASE)
1005         event->key.state |= mask;
1006     }
1007
1008   event->key.state |= current_button_state;
1009
1010   event->key.string = NULL;
1011
1012   /* Fill in ->string since apps depend on it, taken from the x11 backend. */
1013   if (event->key.keyval != GDK_KEY_VoidSymbol)
1014     c = gdk_keyval_to_unicode (event->key.keyval);
1015
1016   if (c)
1017     {
1018       gsize bytes_written;
1019       gint len;
1020
1021       len = g_unichar_to_utf8 (c, buf);
1022       buf[len] = '\0';
1023       
1024       event->key.string = g_locale_from_utf8 (buf, len,
1025                                               NULL, &bytes_written,
1026                                               NULL);
1027       if (event->key.string)
1028         event->key.length = bytes_written;
1029     }
1030   else if (event->key.keyval == GDK_KEY_Escape)
1031     {
1032       event->key.length = 1;
1033       event->key.string = g_strdup ("\033");
1034     }
1035   else if (event->key.keyval == GDK_KEY_Return ||
1036           event->key.keyval == GDK_KEY_KP_Enter)
1037     {
1038       event->key.length = 1;
1039       event->key.string = g_strdup ("\r");
1040     }
1041
1042   if (!event->key.string)
1043     {
1044       event->key.length = 0;
1045       event->key.string = g_strdup ("");
1046     }
1047
1048   GDK_NOTE(EVENTS,
1049     g_message ("key %s:\t\twindow: %p  key: %12s  %d",
1050           type == GDK_KEY_PRESS ? "press" : "release",
1051           event->key.window,
1052           event->key.keyval ? gdk_keyval_name (event->key.keyval) : "(none)",
1053           event->key.keyval));
1054 }
1055
1056 static gboolean
1057 synthesize_crossing_event (GdkWindow *window,
1058                            GdkEvent  *event,
1059                            NSEvent   *nsevent,
1060                            gint       x,
1061                            gint       y,
1062                            gint       x_root,
1063                            gint       y_root)
1064 {
1065   GdkWindowObject *private;
1066
1067   private = GDK_WINDOW_OBJECT (window);
1068
1069   switch ([nsevent type])
1070     {
1071     case NSMouseEntered:
1072       /* Enter events are considered always to be from the root window as we
1073        * can't know for sure from what window we enter.
1074        */
1075       if (!(private->event_mask & GDK_ENTER_NOTIFY_MASK))
1076         return FALSE;
1077
1078       fill_crossing_event (window, event, nsevent,
1079                            x, y,
1080                            x_root, y_root,
1081                            GDK_ENTER_NOTIFY,
1082                            GDK_CROSSING_NORMAL,
1083                            GDK_NOTIFY_ANCESTOR);
1084       return TRUE;
1085
1086     case NSMouseExited:
1087       /* Exited always is to the root window as far as we are concerned,
1088        * since there is no way to reliably get information about what new
1089        * window is entered when exiting one.
1090        */
1091       if (!(private->event_mask & GDK_LEAVE_NOTIFY_MASK))
1092         return FALSE;
1093
1094       fill_crossing_event (window, event, nsevent,
1095                            x, y,
1096                            x_root, y_root,
1097                            GDK_LEAVE_NOTIFY,
1098                            GDK_CROSSING_NORMAL,
1099                            GDK_NOTIFY_ANCESTOR);
1100       return TRUE;
1101
1102     default:
1103       break;
1104     }
1105
1106   return FALSE;
1107 }
1108
1109 GdkEventMask 
1110 _gdk_quartz_events_get_current_event_mask (void)
1111 {
1112   return current_event_mask;
1113 }
1114
1115 static gboolean
1116 gdk_event_translate (GdkEvent *event,
1117                      NSEvent  *nsevent)
1118 {
1119   NSEventType event_type;
1120   NSWindow *nswindow;
1121   GdkWindow *window;
1122   int x, y;
1123   int x_root, y_root;
1124   gboolean return_val;
1125
1126   /* There is no support for real desktop wide grabs, so we break
1127    * grabs when the application loses focus (gets deactivated).
1128    */
1129   event_type = [nsevent type];
1130   if (event_type == NSAppKitDefined)
1131     {
1132       if ([nsevent subtype] == NSApplicationDeactivatedEventType)
1133         break_all_grabs (get_time_from_ns_event (nsevent));
1134
1135       /* This could potentially be used to break grabs when clicking
1136        * on the title. The subtype 20 is undocumented so it's probably
1137        * not a good idea: else if (subtype == 20) break_all_grabs ();
1138        */
1139
1140       /* Leave all AppKit events to AppKit. */
1141       return FALSE;
1142     }
1143
1144   /* Keep track of button state, since we don't get that information
1145    * for key events. 
1146    */
1147   switch (event_type)
1148     {
1149     case NSLeftMouseDown:
1150     case NSRightMouseDown:
1151     case NSOtherMouseDown:
1152       current_button_state |= get_mouse_button_modifiers_from_ns_event (nsevent);
1153       break;
1154     case NSLeftMouseUp:
1155     case NSRightMouseUp:
1156     case NSOtherMouseUp:
1157       current_button_state &= ~get_mouse_button_modifiers_from_ns_event (nsevent);
1158       break;
1159     default:
1160       break;
1161     }
1162
1163   if (_gdk_default_filters)
1164     {
1165       /* Apply global filters */
1166       GdkFilterReturn result;
1167
1168       result = gdk_event_apply_filters (nsevent, event, _gdk_default_filters);
1169       if (result != GDK_FILTER_CONTINUE)
1170         {
1171           return_val = (result == GDK_FILTER_TRANSLATE) ? TRUE : FALSE;
1172           goto done;
1173         }
1174     }
1175
1176   nswindow = [nsevent window];
1177
1178   /* Ignore events for no window or ones not created by GDK. */
1179   if (!nswindow || ![[nswindow contentView] isKindOfClass:[GdkQuartzView class]])
1180     return FALSE;
1181
1182   /* Ignore events and break grabs while the window is being
1183    * dragged. This is a workaround for the window getting events for
1184    * the window title.
1185    */
1186   if ([(GdkQuartzWindow *)nswindow isInMove])
1187     {
1188       break_all_grabs (get_time_from_ns_event (nsevent));
1189       return FALSE;
1190     }
1191
1192   /* Find the right GDK window to send the event to, taking grabs and
1193    * event masks into consideration.
1194    */
1195   window = find_window_for_ns_event (nsevent, &x, &y, &x_root, &y_root);
1196   if (!window)
1197     return FALSE;
1198
1199   /* Apply any window filters. */
1200   if (GDK_IS_WINDOW (window))
1201     {
1202       GdkWindowObject *filter_private = (GdkWindowObject *) window;
1203       GdkFilterReturn result;
1204
1205       if (filter_private->filters)
1206         {
1207           g_object_ref (window);
1208
1209           result = gdk_event_apply_filters (nsevent, event, filter_private->filters);
1210
1211           g_object_unref (window);
1212
1213           if (result != GDK_FILTER_CONTINUE)
1214             {
1215               return_val = (result == GDK_FILTER_TRANSLATE) ? TRUE : FALSE;
1216               goto done;
1217             }
1218         }
1219     }
1220
1221   /* If the app is not active leave the event to AppKit so the window gets
1222    * focused correctly and don't do click-through (so we behave like most
1223    * native apps). If the app is active, we focus the window and then handle
1224    * the event, also to match native apps.
1225    */
1226   if ((event_type == NSRightMouseDown ||
1227        event_type == NSOtherMouseDown ||
1228        event_type == NSLeftMouseDown))
1229     {
1230       GdkWindowObject *private = (GdkWindowObject *)window;
1231       GdkWindowImplQuartz *impl = GDK_WINDOW_IMPL_QUARTZ (private->impl);
1232
1233       if (![NSApp isActive])
1234         {
1235           [NSApp activateIgnoringOtherApps:YES];
1236           return FALSE;
1237         }
1238       else if (![impl->toplevel isKeyWindow])
1239         {
1240           GdkDeviceGrabInfo *grab;
1241
1242           grab = _gdk_display_get_last_device_grab (_gdk_display,
1243                                                     _gdk_display->core_pointer);
1244           if (!grab)
1245             [impl->toplevel makeKeyWindow];
1246         }
1247     }
1248
1249   current_event_mask = get_event_mask_from_ns_event (nsevent);
1250
1251   return_val = TRUE;
1252
1253   switch (event_type)
1254     {
1255     case NSLeftMouseDown:
1256     case NSRightMouseDown:
1257     case NSOtherMouseDown:
1258     case NSLeftMouseUp:
1259     case NSRightMouseUp:
1260     case NSOtherMouseUp:
1261       fill_button_event (window, event, nsevent, x, y, x_root, y_root);
1262       break;
1263
1264     case NSLeftMouseDragged:
1265     case NSRightMouseDragged:
1266     case NSOtherMouseDragged:
1267     case NSMouseMoved:
1268       fill_motion_event (window, event, nsevent, x, y, x_root, y_root);
1269       break;
1270
1271     case NSScrollWheel:
1272       {
1273         float dx = [nsevent deltaX];
1274         float dy = [nsevent deltaY];
1275         GdkScrollDirection direction;
1276
1277         if (dy != 0)
1278           {
1279             if (dy < 0.0)
1280               direction = GDK_SCROLL_DOWN;
1281             else
1282               direction = GDK_SCROLL_UP;
1283
1284             fill_scroll_event (window, event, nsevent, x, y, x_root, y_root, direction);
1285           }
1286
1287         if (dx != 0)
1288           {
1289             if (dx < 0.0)
1290               direction = GDK_SCROLL_RIGHT;
1291             else
1292               direction = GDK_SCROLL_LEFT;
1293
1294             fill_scroll_event (window, event, nsevent, x, y, x_root, y_root, direction);
1295           }
1296       }
1297       break;
1298
1299     case NSMouseEntered:
1300     case NSMouseExited:
1301       return_val = synthesize_crossing_event (window, event, nsevent, x, y, x_root, y_root);
1302       break;
1303
1304     case NSKeyDown:
1305     case NSKeyUp:
1306     case NSFlagsChanged:
1307       {
1308         GdkEventType type;
1309
1310         type = _gdk_quartz_keys_event_type (nsevent);
1311         if (type == GDK_NOTHING)
1312           return_val = FALSE;
1313         else
1314           fill_key_event (window, event, nsevent, type);
1315       }
1316       break;
1317
1318     default:
1319       /* Ignore everything elsee. */
1320       return_val = FALSE;
1321       break;
1322     }
1323
1324  done:
1325   if (return_val)
1326     {
1327       if (event->any.window)
1328         g_object_ref (event->any.window);
1329       if (((event->any.type == GDK_ENTER_NOTIFY) ||
1330            (event->any.type == GDK_LEAVE_NOTIFY)) &&
1331           (event->crossing.subwindow != NULL))
1332         g_object_ref (event->crossing.subwindow);
1333     }
1334   else
1335     {
1336       /* Mark this event as having no resources to be freed */
1337       event->any.window = NULL;
1338       event->any.type = GDK_NOTHING;
1339     }
1340
1341   return return_val;
1342 }
1343
1344 void
1345 _gdk_events_queue (GdkDisplay *display)
1346 {  
1347   NSEvent *nsevent;
1348
1349   nsevent = _gdk_quartz_event_loop_get_pending ();
1350   if (nsevent)
1351     {
1352       GdkEvent *event;
1353       GList *node;
1354
1355       event = gdk_event_new (GDK_NOTHING);
1356
1357       event->any.window = NULL;
1358       event->any.send_event = FALSE;
1359
1360       ((GdkEventPrivate *)event)->flags |= GDK_EVENT_PENDING;
1361
1362       node = _gdk_event_queue_append (display, event);
1363
1364       if (gdk_event_translate (event, nsevent))
1365         {
1366           ((GdkEventPrivate *)event)->flags &= ~GDK_EVENT_PENDING;
1367           _gdk_windowing_got_event (display, node, event, 0);
1368         }
1369       else
1370         {
1371           _gdk_event_queue_remove_link (display, node);
1372           g_list_free_1 (node);
1373           gdk_event_free (event);
1374
1375           GDK_THREADS_LEAVE ();
1376           [NSApp sendEvent:nsevent];
1377           GDK_THREADS_ENTER ();
1378         }
1379
1380       _gdk_quartz_event_loop_release_event (nsevent);
1381     }
1382 }
1383
1384 void
1385 gdk_flush (void)
1386 {
1387   /* Not supported. */
1388 }
1389
1390 void
1391 gdk_display_add_client_message_filter (GdkDisplay   *display,
1392                                        GdkAtom       message_type,
1393                                        GdkFilterFunc func,
1394                                        gpointer      data)
1395 {
1396   /* Not supported. */
1397 }
1398
1399 void
1400 gdk_add_client_message_filter (GdkAtom       message_type,
1401                                GdkFilterFunc func,
1402                                gpointer      data)
1403 {
1404   /* Not supported. */
1405 }
1406
1407 void
1408 gdk_display_sync (GdkDisplay *display)
1409 {
1410   /* Not supported. */
1411 }
1412
1413 void
1414 gdk_display_flush (GdkDisplay *display)
1415 {
1416   /* Not supported. */
1417 }
1418
1419 gboolean
1420 gdk_event_send_client_message_for_display (GdkDisplay      *display,
1421                                            GdkEvent        *event,
1422                                            GdkNativeWindow  winid)
1423 {
1424   /* Not supported. */
1425   return FALSE;
1426 }
1427
1428 void
1429 gdk_screen_broadcast_client_message (GdkScreen *screen,
1430                                      GdkEvent  *event)
1431 {
1432   /* Not supported. */
1433 }
1434
1435 gboolean
1436 gdk_screen_get_setting (GdkScreen   *screen,
1437                         const gchar *name,
1438                         GValue      *value)
1439 {
1440   if (strcmp (name, "gtk-double-click-time") == 0)
1441     {
1442       NSUserDefaults *defaults;
1443       float t;
1444
1445       GDK_QUARTZ_ALLOC_POOL;
1446
1447       defaults = [NSUserDefaults standardUserDefaults];
1448             
1449       t = [defaults floatForKey:@"com.apple.mouse.doubleClickThreshold"];
1450       if (t == 0.0)
1451         {
1452           /* No user setting, use the default in OS X. */
1453           t = 0.5;
1454         }
1455
1456       GDK_QUARTZ_RELEASE_POOL;
1457
1458       g_value_set_int (value, t * 1000);
1459
1460       return TRUE;
1461     }
1462   else if (strcmp (name, "gtk-font-name") == 0)
1463     {
1464       NSString *name;
1465       char *str;
1466
1467       GDK_QUARTZ_ALLOC_POOL;
1468
1469       name = [[NSFont systemFontOfSize:0] familyName];
1470
1471       /* Let's try to use the "views" font size (12pt) by default. This is
1472        * used for lists/text/other "content" which is the largest parts of
1473        * apps, using the "regular control" size (13pt) looks a bit out of
1474        * place. We might have to tweak this.
1475        */
1476
1477       /* The size has to be hardcoded as there doesn't seem to be a way to
1478        * get the views font size programmatically.
1479        */
1480       str = g_strdup_printf ("%s 12", [name UTF8String]);
1481       g_value_set_string (value, str);
1482       g_free (str);
1483
1484       GDK_QUARTZ_RELEASE_POOL;
1485
1486       return TRUE;
1487     }
1488   
1489   /* FIXME: Add more settings */
1490
1491   return FALSE;
1492 }
1493
1494 void
1495 _gdk_windowing_event_data_copy (const GdkEvent *src,
1496                                 GdkEvent       *dst)
1497 {
1498   GdkEventPrivate *priv_src = (GdkEventPrivate *) src;
1499   GdkEventPrivate *priv_dst = (GdkEventPrivate *) dst;
1500
1501   if (priv_src->windowing_data)
1502     {
1503       priv_dst->windowing_data = priv_src->windowing_data;
1504       [(NSEvent *)priv_dst->windowing_data retain];
1505     }
1506 }
1507
1508 void
1509 _gdk_windowing_event_data_free (GdkEvent *event)
1510 {
1511   GdkEventPrivate *priv = (GdkEventPrivate *) event;
1512
1513   if (priv->windowing_data)
1514     {
1515       [(NSEvent *)priv->windowing_data release];
1516       priv->windowing_data = NULL;
1517     }
1518 }