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