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