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