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