3 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
4 * Copyright (C) 1998-2002 Tor Lillqvist
5 * Copyright (C) 2005-2006 Imendio AB
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.
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.
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.
24 #include <sys/types.h>
25 #include <sys/sysctl.h>
29 #include <Carbon/Carbon.h>
31 #include "gdkscreen.h"
32 #include "gdkkeysyms.h"
34 #include "gdkprivate-quartz.h"
36 /* This is the window the mouse is currently over */
37 static GdkWindow *current_mouse_window;
39 /* This is the window corresponding to the key window */
40 static GdkWindow *current_keyboard_window;
42 /* This is the pointer grab window */
43 GdkWindow *_gdk_quartz_pointer_grab_window;
44 static gboolean pointer_grab_owner_events;
45 static GdkEventMask pointer_grab_event_mask;
46 static gboolean pointer_grab_implicit;
48 /* This is the keyboard grab window */
49 GdkWindow *_gdk_quartz_keyboard_grab_window;
50 static gboolean keyboard_grab_owner_events;
52 static void append_event (GdkEvent *event);
55 _gdk_events_init (void)
57 _gdk_quartz_event_loop_init ();
59 current_mouse_window = g_object_ref (_gdk_root);
60 current_keyboard_window = g_object_ref (_gdk_root);
64 gdk_events_pending (void)
66 return (_gdk_event_queue_find_first (_gdk_display) ||
67 (_gdk_quartz_event_loop_get_current () != NULL));
71 gdk_event_get_graphics_expose (GdkWindow *window)
73 /* FIXME: Implement */
78 generate_grab_broken_event (GdkWindow *window,
81 GdkWindow *grab_window)
83 if (!GDK_WINDOW_DESTROYED (window))
85 GdkEvent *event = gdk_event_new (GDK_GRAB_BROKEN);
87 event->grab_broken.window = window;
88 event->grab_broken.send_event = 0;
89 event->grab_broken.keyboard = keyboard;
90 event->grab_broken.implicit = implicit;
91 event->grab_broken.grab_window = grab_window;
98 gdk_keyboard_grab (GdkWindow *window,
102 g_return_val_if_fail (window != NULL, 0);
103 g_return_val_if_fail (GDK_IS_WINDOW (window), 0);
105 if (_gdk_quartz_keyboard_grab_window)
107 if (_gdk_quartz_keyboard_grab_window != window)
108 generate_grab_broken_event (_gdk_quartz_keyboard_grab_window,
109 TRUE, FALSE, window);
111 g_object_unref (_gdk_quartz_keyboard_grab_window);
114 _gdk_quartz_keyboard_grab_window = g_object_ref (window);
115 keyboard_grab_owner_events = owner_events;
117 return GDK_GRAB_SUCCESS;
121 gdk_display_keyboard_ungrab (GdkDisplay *display,
124 if (_gdk_quartz_keyboard_grab_window)
125 g_object_unref (_gdk_quartz_keyboard_grab_window);
126 _gdk_quartz_keyboard_grab_window = NULL;
130 gdk_keyboard_grab_info_libgtk_only (GdkDisplay *display,
131 GdkWindow **grab_window,
132 gboolean *owner_events)
134 if (_gdk_quartz_keyboard_grab_window)
137 *grab_window = _gdk_quartz_keyboard_grab_window;
139 *owner_events = keyboard_grab_owner_events;
148 pointer_ungrab_internal (gboolean only_if_implicit)
150 if (!_gdk_quartz_pointer_grab_window)
153 if (only_if_implicit && !pointer_grab_implicit)
156 g_object_unref (_gdk_quartz_pointer_grab_window);
157 _gdk_quartz_pointer_grab_window = NULL;
159 pointer_grab_owner_events = FALSE;
160 pointer_grab_event_mask = 0;
161 pointer_grab_implicit = FALSE;
163 /* FIXME: Send crossing events */
167 gdk_display_pointer_is_grabbed (GdkDisplay *display)
169 return _gdk_quartz_pointer_grab_window != NULL;
173 gdk_pointer_grab_info_libgtk_only (GdkDisplay *display,
174 GdkWindow **grab_window,
175 gboolean *owner_events)
177 if (!_gdk_quartz_pointer_grab_window)
181 *grab_window = _gdk_quartz_pointer_grab_window;
184 *owner_events = pointer_grab_owner_events;
190 gdk_display_pointer_ungrab (GdkDisplay *display,
193 pointer_ungrab_internal (FALSE);
197 pointer_grab_internal (GdkWindow *window,
198 gboolean owner_events,
199 GdkEventMask event_mask,
200 GdkWindow *confine_to,
204 /* FIXME: Send crossing events */
206 _gdk_quartz_pointer_grab_window = g_object_ref (window);
207 pointer_grab_owner_events = owner_events;
208 pointer_grab_event_mask = event_mask;
209 pointer_grab_implicit = implicit;
211 return GDK_GRAB_SUCCESS;
215 gdk_pointer_grab (GdkWindow *window,
216 gboolean owner_events,
217 GdkEventMask event_mask,
218 GdkWindow *confine_to,
222 g_return_val_if_fail (GDK_IS_WINDOW (window), 0);
223 g_return_val_if_fail (confine_to == NULL || GDK_IS_WINDOW (confine_to), 0);
225 if (_gdk_quartz_pointer_grab_window)
227 if (_gdk_quartz_pointer_grab_window == window && !pointer_grab_implicit)
228 return GDK_GRAB_ALREADY_GRABBED;
231 if (_gdk_quartz_pointer_grab_window != window)
232 generate_grab_broken_event (_gdk_quartz_pointer_grab_window,
233 FALSE, pointer_grab_implicit, window);
234 pointer_ungrab_internal (TRUE);
238 return pointer_grab_internal (window, owner_events, event_mask,
239 confine_to, cursor, FALSE);
243 fixup_event (GdkEvent *event)
245 if (event->any.window)
246 g_object_ref (event->any.window);
247 if (((event->any.type == GDK_ENTER_NOTIFY) ||
248 (event->any.type == GDK_LEAVE_NOTIFY)) &&
249 (event->crossing.subwindow != NULL))
250 g_object_ref (event->crossing.subwindow);
251 event->any.send_event = FALSE;
255 append_event (GdkEvent *event)
258 _gdk_event_queue_append (_gdk_display, event);
261 static GdkFilterReturn
262 apply_filters (GdkWindow *window,
266 GdkFilterReturn result = GDK_FILTER_CONTINUE;
271 event = gdk_event_new (GDK_NOTHING);
273 event->any.window = g_object_ref (window);
274 ((GdkEventPrivate *)event)->flags |= GDK_EVENT_PENDING;
276 /* I think GdkFilterFunc semantics require the passed-in event
277 * to already be in the queue. The filter func can generate
278 * more events and append them after it if it likes.
280 node = _gdk_event_queue_append (_gdk_display, event);
285 GdkEventFilter *filter = (GdkEventFilter *) tmp_list->data;
287 tmp_list = tmp_list->next;
288 result = filter->function (nsevent, event, filter->data);
289 if (result != GDK_FILTER_CONTINUE)
293 if (result == GDK_FILTER_CONTINUE || result == GDK_FILTER_REMOVE)
295 _gdk_event_queue_remove_link (_gdk_display, node);
296 g_list_free_1 (node);
297 gdk_event_free (event);
299 else /* GDK_FILTER_TRANSLATE */
301 ((GdkEventPrivate *)event)->flags &= ~GDK_EVENT_PENDING;
307 /* Checks if the passed in window is interested in the event mask, and
308 * if so, it's returned. If not, the event can be propagated through
309 * its ancestors until one with the right event mask is found, up to
310 * the nearest toplevel.
313 find_window_interested_in_event_mask (GdkWindow *window,
314 GdkEventMask event_mask,
317 GdkWindowObject *private;
319 private = GDK_WINDOW_OBJECT (window);
322 if (private->event_mask & event_mask)
323 return (GdkWindow *)private;
328 /* Don't traverse beyond toplevels. */
329 if (GDK_WINDOW_TYPE (private) != GDK_WINDOW_CHILD)
332 private = private->parent;
339 get_event_time (NSEvent *event)
341 double time = [event timestamp];
343 return time * 1000.0;
347 convert_mouse_button_number (int button)
362 /* Return an event mask from an NSEvent */
364 get_event_mask_from_ns_event (NSEvent *nsevent)
366 switch ([nsevent type])
368 case NSLeftMouseDown:
369 case NSRightMouseDown:
370 case NSOtherMouseDown:
371 return GDK_BUTTON_PRESS_MASK;
375 return GDK_BUTTON_RELEASE_MASK;
377 return GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK;
379 /* Since applications that want button press events can get
380 * scroll events on X11 (since scroll wheel events are really
381 * button press events there), we need to use GDK_BUTTON_PRESS_MASK too.
383 return GDK_SCROLL_MASK | GDK_BUTTON_PRESS_MASK;
384 case NSLeftMouseDragged:
385 return (GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK |
386 GDK_BUTTON_MOTION_MASK | GDK_BUTTON1_MOTION_MASK |
388 case NSRightMouseDragged:
389 return (GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK |
390 GDK_BUTTON_MOTION_MASK | GDK_BUTTON3_MOTION_MASK |
392 case NSOtherMouseDragged:
396 mask = (GDK_POINTER_MOTION_MASK |
397 GDK_POINTER_MOTION_HINT_MASK |
398 GDK_BUTTON_MOTION_MASK);
400 if (convert_mouse_button_number ([nsevent buttonNumber]) == 2)
401 mask |= (GDK_BUTTON2_MOTION_MASK | GDK_BUTTON2_MOTION_MASK |
410 switch (_gdk_quartz_keys_event_type (nsevent))
413 return GDK_KEY_PRESS_MASK;
414 case GDK_KEY_RELEASE:
415 return GDK_KEY_RELEASE_MASK;
419 g_assert_not_reached ();
423 g_assert_not_reached ();
430 create_focus_event (GdkWindow *window,
435 event = gdk_event_new (GDK_FOCUS_CHANGE);
436 event->focus_change.window = window;
437 event->focus_change.in = in;
442 /* Note: Used to both set a new focus window and to unset the old one. */
444 _gdk_quartz_events_update_focus_window (GdkWindow *window,
449 if (got_focus && window == current_keyboard_window)
452 /* FIXME: Don't do this when grabbed? Or make GdkQuartzWindow
453 * disallow it in the first place instead?
456 if (!got_focus && window == current_keyboard_window)
458 event = create_focus_event (current_keyboard_window, FALSE);
459 append_event (event);
460 g_object_unref (current_keyboard_window);
461 current_keyboard_window = NULL;
466 if (current_keyboard_window)
468 event = create_focus_event (current_keyboard_window, FALSE);
469 append_event (event);
470 g_object_unref (current_keyboard_window);
471 current_keyboard_window = NULL;
474 event = create_focus_event (window, TRUE);
475 append_event (event);
476 current_keyboard_window = g_object_ref (window);
481 gdk_window_is_ancestor (GdkWindow *ancestor,
484 if (ancestor == NULL || window == NULL)
487 return (gdk_window_get_parent (window) == ancestor ||
488 gdk_window_is_ancestor (ancestor, gdk_window_get_parent (window)));
491 static GdkModifierType
492 get_keyboard_modifiers_from_nsevent (NSEvent *nsevent)
494 GdkModifierType modifiers = 0;
497 nsflags = [nsevent modifierFlags];
499 if (nsflags & NSAlphaShiftKeyMask)
500 modifiers |= GDK_LOCK_MASK;
501 if (nsflags & NSShiftKeyMask)
502 modifiers |= GDK_SHIFT_MASK;
503 if (nsflags & NSControlKeyMask)
504 modifiers |= GDK_CONTROL_MASK;
505 if (nsflags & NSCommandKeyMask)
506 modifiers |= GDK_MOD1_MASK;
508 /* FIXME: Support GDK_BUTTON_MASK */
514 convert_window_coordinates_to_root (GdkWindow *window,
525 if (gdk_window_get_origin (window, &ox, &oy))
533 create_crossing_event (GdkWindow *window,
535 GdkEventType event_type,
536 GdkCrossingMode mode,
537 GdkNotifyType detail)
542 event = gdk_event_new (event_type);
544 event->crossing.window = window;
545 event->crossing.subwindow = NULL; /* FIXME */
546 event->crossing.time = get_event_time (nsevent);
548 point = [nsevent locationInWindow];
549 event->crossing.x = point.x;
550 event->crossing.y = point.y;
551 convert_window_coordinates_to_root (window, event->crossing.x, event->crossing.y,
552 &event->crossing.x_root,
553 &event->crossing.y_root);
555 event->crossing.mode = mode;
556 event->crossing.detail = detail;
558 /* FIXME: state, (button state too) */
564 synthesize_enter_event (GdkWindow *window,
566 GdkCrossingMode mode,
567 GdkNotifyType detail)
571 if (_gdk_quartz_pointer_grab_window != NULL &&
572 !pointer_grab_owner_events &&
573 !(pointer_grab_event_mask & GDK_ENTER_NOTIFY_MASK))
576 if (!(GDK_WINDOW_OBJECT (window)->event_mask & GDK_ENTER_NOTIFY_MASK))
579 event = create_crossing_event (window, nsevent, GDK_ENTER_NOTIFY,
582 append_event (event);
586 synthesize_enter_events (GdkWindow *from,
589 GdkCrossingMode mode,
590 GdkNotifyType detail)
592 GdkWindow *prev = gdk_window_get_parent (to);
595 synthesize_enter_events (from, prev, nsevent, mode, detail);
596 synthesize_enter_event (to, nsevent, mode, detail);
600 synthesize_leave_event (GdkWindow *window,
602 GdkCrossingMode mode,
603 GdkNotifyType detail)
607 if (_gdk_quartz_pointer_grab_window != NULL &&
608 !pointer_grab_owner_events &&
609 !(pointer_grab_event_mask & GDK_LEAVE_NOTIFY_MASK))
612 if (!(GDK_WINDOW_OBJECT (window)->event_mask & GDK_LEAVE_NOTIFY_MASK))
615 event = create_crossing_event (window, nsevent, GDK_LEAVE_NOTIFY,
618 append_event (event);
622 synthesize_leave_events (GdkWindow *from,
625 GdkCrossingMode mode,
626 GdkNotifyType detail)
628 GdkWindow *next = gdk_window_get_parent (from);
630 synthesize_leave_event (from, nsevent, mode, detail);
632 synthesize_leave_events (next, to, nsevent, mode, detail);
636 synthesize_crossing_events (GdkWindow *window,
637 GdkCrossingMode mode,
642 GdkWindow *intermediate, *tem, *common_ancestor;
644 if (gdk_window_is_ancestor (current_mouse_window, window))
646 /* Pointer has moved to an inferior window. */
647 synthesize_leave_event (current_mouse_window, nsevent, mode, GDK_NOTIFY_INFERIOR);
649 /* If there are intermediate windows, generate ENTER_NOTIFY
652 intermediate = gdk_window_get_parent (window);
654 if (intermediate != current_mouse_window)
656 synthesize_enter_events (current_mouse_window, intermediate, nsevent, mode, GDK_NOTIFY_VIRTUAL);
659 synthesize_enter_event (window, nsevent, mode, GDK_NOTIFY_ANCESTOR);
661 else if (gdk_window_is_ancestor (window, current_mouse_window))
663 /* Pointer has moved to an ancestor window. */
664 synthesize_leave_event (current_mouse_window, nsevent, mode, GDK_NOTIFY_ANCESTOR);
666 /* If there are intermediate windows, generate LEAVE_NOTIFY
669 intermediate = gdk_window_get_parent (current_mouse_window);
670 if (intermediate != window)
672 synthesize_leave_events (intermediate, window, nsevent, mode, GDK_NOTIFY_VIRTUAL);
675 synthesize_enter_event (window, nsevent, mode, GDK_NOTIFY_INFERIOR);
677 else if (current_mouse_window)
679 /* Find least common ancestor of current_mouse_window and window */
680 tem = current_mouse_window;
682 common_ancestor = gdk_window_get_parent (tem);
683 tem = common_ancestor;
684 } while (common_ancestor &&
685 !gdk_window_is_ancestor (common_ancestor, window));
688 synthesize_leave_event (current_mouse_window, nsevent, mode, GDK_NOTIFY_NONLINEAR);
689 intermediate = gdk_window_get_parent (current_mouse_window);
690 if (intermediate != common_ancestor)
692 synthesize_leave_events (intermediate, common_ancestor,
693 nsevent, mode, GDK_NOTIFY_NONLINEAR_VIRTUAL);
695 intermediate = gdk_window_get_parent (window);
696 if (intermediate != common_ancestor)
698 synthesize_enter_events (common_ancestor, intermediate,
699 nsevent, mode, GDK_NOTIFY_NONLINEAR_VIRTUAL);
701 synthesize_enter_event (window, nsevent, mode, GDK_NOTIFY_NONLINEAR);
706 /* This means we have not current_mouse_window. FIXME: Should
707 * we make sure to always set the root window instead of NULL?
710 /* FIXME: Figure out why this is being called with window being
711 * NULL. The check works around a crash for now.
714 synthesize_enter_event (window, nsevent, mode, GDK_NOTIFY_UNKNOWN);
717 _gdk_quartz_events_update_mouse_window (window);
721 _gdk_quartz_events_send_map_events (GdkWindow *window)
724 GdkWindow *interested_window;
725 GdkWindowObject *private = (GdkWindowObject *)window;
727 interested_window = find_window_interested_in_event_mask (window,
731 if (interested_window)
733 GdkEvent *event = gdk_event_new (GDK_MAP);
734 event->any.window = interested_window;
735 append_event (event);
738 for (list = private->children; list != NULL; list = list->next)
739 _gdk_quartz_events_send_map_events ((GdkWindow *)list->data);
742 /* Get current mouse window */
744 _gdk_quartz_events_get_mouse_window (void)
746 if (_gdk_quartz_pointer_grab_window && !pointer_grab_owner_events)
747 return _gdk_quartz_pointer_grab_window;
749 return current_mouse_window;
752 /* Update mouse window */
754 _gdk_quartz_events_update_mouse_window (GdkWindow *window)
757 g_object_ref (window);
758 if (current_mouse_window)
759 g_object_unref (current_mouse_window);
761 current_mouse_window = window;
764 /* Update current cursor */
766 _gdk_quartz_events_update_cursor (GdkWindow *window)
768 GdkWindowObject *private = GDK_WINDOW_OBJECT (window);
769 NSCursor *nscursor = nil;
772 GdkWindowImplQuartz *impl = GDK_WINDOW_IMPL_QUARTZ (private->impl);
774 nscursor = impl->nscursor;
778 private = private->parent;
782 nscursor = [NSCursor arrowCursor];
784 if ([NSCursor currentCursor] != nscursor)
788 /* This function finds the correct window to send an event to,
789 * taking into account grabs (FIXME: not done yet), event propagation,
793 find_window_for_event (NSEvent *nsevent, gint *x, gint *y)
795 NSWindow *nswindow = [nsevent window];
796 NSEventType event_type = [nsevent type];
801 /* Window where not created by GDK so the event should be handled by Quartz */
802 if (![[nswindow contentView] isKindOfClass:[GdkQuartzView class]])
805 if (event_type == NSMouseMoved ||
806 event_type == NSLeftMouseDragged ||
807 event_type == NSRightMouseDragged ||
808 event_type == NSOtherMouseDragged)
810 GdkWindow *toplevel = [(GdkQuartzView *)[nswindow contentView] gdkWindow];
811 NSPoint point = [nsevent locationInWindow];
812 GdkWindow *mouse_window;
814 mouse_window = _gdk_quartz_window_find_child_by_point (toplevel, point.x, point.y, x, y);
817 mouse_window = _gdk_root;
819 if (_gdk_quartz_pointer_grab_window)
821 if (mouse_window != current_mouse_window)
822 synthesize_crossing_events (mouse_window, GDK_CROSSING_NORMAL, nsevent, *x, *y);
826 if (current_mouse_window != mouse_window)
828 synthesize_crossing_events (mouse_window, GDK_CROSSING_NORMAL, nsevent, *x, *y);
830 _gdk_quartz_events_update_cursor (mouse_window);
837 case NSLeftMouseDown:
838 case NSRightMouseDown:
839 case NSOtherMouseDown:
845 case NSLeftMouseDragged:
846 case NSRightMouseDragged:
847 case NSOtherMouseDragged:
849 GdkWindow *toplevel = [(GdkQuartzView *)[nswindow contentView] gdkWindow];
850 NSPoint point = [nsevent locationInWindow];
851 GdkWindow *mouse_window;
852 GdkEventMask event_mask;
853 GdkWindow *real_window;
855 if (_gdk_quartz_pointer_grab_window && !pointer_grab_owner_events)
857 if (pointer_grab_event_mask & get_event_mask_from_ns_event (nsevent))
861 GdkWindowObject *grab_toplevel;
863 w = GDK_WINDOW_OBJECT (_gdk_quartz_pointer_grab_window);
864 grab_toplevel = GDK_WINDOW_OBJECT (gdk_window_get_toplevel (_gdk_quartz_pointer_grab_window));
867 tempy = GDK_WINDOW_IMPL_QUARTZ (grab_toplevel->impl)->height -
870 while (w != grab_toplevel)
881 return _gdk_quartz_pointer_grab_window;
891 mouse_window = _gdk_root;
895 mouse_window = _gdk_quartz_window_find_child_by_point (toplevel, point.x, point.y, x, y);
898 event_mask = get_event_mask_from_ns_event (nsevent);
899 real_window = find_window_interested_in_event_mask (mouse_window, event_mask, TRUE);
909 GdkWindow *mouse_window;
911 point = [nsevent locationInWindow];
912 toplevel = [(GdkQuartzView *)[nswindow contentView] gdkWindow];
914 mouse_window = _gdk_quartz_window_find_child_by_point (toplevel, point.x, point.y, x, y);
916 synthesize_crossing_events (mouse_window, GDK_CROSSING_NORMAL, nsevent, *x, *y);
921 synthesize_crossing_events (_gdk_root, GDK_CROSSING_NORMAL, nsevent, *x, *y);
928 GdkEventMask event_mask;
930 if (_gdk_quartz_keyboard_grab_window && !keyboard_grab_owner_events)
931 return _gdk_quartz_keyboard_grab_window;
933 event_mask = get_event_mask_from_ns_event (nsevent);
934 return find_window_interested_in_event_mask (current_keyboard_window, event_mask, TRUE);
938 case NSAppKitDefined:
939 case NSSystemDefined:
940 /* We ignore these events */
943 NSLog(@"Unhandled event %@", nsevent);
950 create_button_event (GdkWindow *window, NSEvent *nsevent,
957 switch ([nsevent type])
959 case NSLeftMouseDown:
960 case NSRightMouseDown:
961 case NSOtherMouseDown:
962 type = GDK_BUTTON_PRESS;
967 type = GDK_BUTTON_RELEASE;
970 g_assert_not_reached ();
973 button = convert_mouse_button_number ([nsevent buttonNumber]);
975 event = gdk_event_new (type);
976 event->button.window = window;
977 event->button.time = get_event_time (nsevent);
980 /* FIXME event->axes */
981 event->button.state = get_keyboard_modifiers_from_nsevent (nsevent);
982 event->button.button = button;
983 event->button.device = _gdk_display->core_pointer;
984 convert_window_coordinates_to_root (window, x, y,
985 &event->button.x_root,
986 &event->button.y_root);
992 create_motion_event (GdkWindow *window, NSEvent *nsevent, gint x, gint y)
996 GdkModifierType state = 0;
999 switch ([nsevent type])
1001 case NSLeftMouseDragged:
1002 case NSRightMouseDragged:
1003 case NSOtherMouseDragged:
1004 button = convert_mouse_button_number ([nsevent buttonNumber]);
1007 type = GDK_MOTION_NOTIFY;
1010 g_assert_not_reached ();
1013 /* This maps buttons 1 to 5 to GDK_BUTTON[1-5]_MASK */
1014 if (button >= 1 && button <= 5)
1015 state = (1 << (button + 7));
1017 state |= get_keyboard_modifiers_from_nsevent (nsevent);
1019 event = gdk_event_new (type);
1020 event->motion.window = window;
1021 event->motion.time = get_event_time (nsevent);
1022 event->motion.x = x;
1023 event->motion.y = y;
1024 /* FIXME event->axes */
1025 event->motion.state = state;
1026 event->motion.is_hint = FALSE;
1027 event->motion.device = _gdk_display->core_pointer;
1028 convert_window_coordinates_to_root (window, x, y,
1029 &event->motion.x_root, &event->motion.y_root);
1035 create_scroll_event (GdkWindow *window, NSEvent *nsevent, GdkScrollDirection direction)
1040 event = gdk_event_new (GDK_SCROLL);
1041 event->scroll.window = window;
1042 event->scroll.time = get_event_time (nsevent);
1044 point = [nsevent locationInWindow];
1045 event->scroll.x = point.x;
1046 event->scroll.y = point.y;
1047 convert_window_coordinates_to_root (window, event->scroll.x, event->scroll.y,
1048 &event->scroll.x_root,
1049 &event->scroll.y_root);
1051 event->scroll.direction = direction;
1052 event->scroll.device = _gdk_display->core_pointer;
1058 create_key_event (GdkWindow *window, NSEvent *nsevent, GdkEventType type)
1064 event = gdk_event_new (type);
1065 event->key.window = window;
1066 event->key.time = get_event_time (nsevent);
1067 event->key.state = get_keyboard_modifiers_from_nsevent (nsevent);
1068 event->key.hardware_keycode = [nsevent keyCode];
1069 event->key.group = ([nsevent modifierFlags] & NSAlternateKeyMask) ? 1 : 0;
1071 event->key.keyval = GDK_VoidSymbol;
1073 gdk_keymap_translate_keyboard_state (NULL,
1074 event->key.hardware_keycode,
1080 event->key.is_modifier = _gdk_quartz_keys_is_modifier (event->key.hardware_keycode);
1082 event->key.string = NULL;
1084 /* Fill in ->string since apps depend on it, taken from the x11 backend. */
1085 if (event->key.keyval != GDK_VoidSymbol)
1086 c = gdk_keyval_to_unicode (event->key.keyval);
1090 gsize bytes_written;
1093 len = g_unichar_to_utf8 (c, buf);
1096 event->key.string = g_locale_from_utf8 (buf, len,
1097 NULL, &bytes_written,
1099 if (event->key.string)
1100 event->key.length = bytes_written;
1102 else if (event->key.keyval == GDK_Escape)
1104 event->key.length = 1;
1105 event->key.string = g_strdup ("\033");
1107 else if (event->key.keyval == GDK_Return ||
1108 event->key.keyval == GDK_KP_Enter)
1110 event->key.length = 1;
1111 event->key.string = g_strdup ("\r");
1114 if (!event->key.string)
1116 event->key.length = 0;
1117 event->key.string = g_strdup ("");
1121 g_message ("key %s:\t\twindow: %p key: %12s %d",
1122 type == GDK_KEY_PRESS ? "press" : "release",
1124 event->key.keyval ? gdk_keyval_name (event->key.keyval) : "(none)",
1125 event->key.keyval));
1129 static GdkEventMask current_mask = 0;
1131 _gdk_quartz_events_get_current_event_mask (void)
1133 return current_mask;
1137 gdk_event_translate (NSEvent *nsevent)
1140 GdkFilterReturn result;
1144 if (_gdk_default_filters)
1146 /* Apply global filters */
1148 GdkFilterReturn result = apply_filters (NULL, nsevent, _gdk_default_filters);
1150 /* If result is GDK_FILTER_CONTINUE, we continue as if nothing
1151 * happened. If it is GDK_FILTER_REMOVE,
1152 * we return TRUE and won't send the message to Quartz.
1154 if (result == GDK_FILTER_REMOVE)
1158 /* Catch the case where the entire app loses focus, and break any grabs. */
1159 if ([nsevent type] == NSAppKitDefined)
1161 if ([nsevent subtype] == NSApplicationDeactivatedEventType)
1163 if (_gdk_quartz_keyboard_grab_window)
1165 generate_grab_broken_event (_gdk_quartz_keyboard_grab_window,
1168 g_object_unref (_gdk_quartz_keyboard_grab_window);
1169 _gdk_quartz_keyboard_grab_window = NULL;
1172 if (_gdk_quartz_pointer_grab_window)
1174 generate_grab_broken_event (_gdk_quartz_pointer_grab_window,
1175 FALSE, pointer_grab_implicit,
1177 pointer_ungrab_internal (FALSE);
1182 window = find_window_for_event (nsevent, &x, &y);
1184 /* FIXME: During owner_event grabs, we don't find a window when there is a
1185 * click on a no-window widget, which makes popups etc still stay up. Need
1186 * to figure out why that is.
1192 result = apply_filters (window, nsevent, ((GdkWindowObject *) window)->filters);
1194 if (result == GDK_FILTER_REMOVE)
1197 current_mask = get_event_mask_from_ns_event (nsevent);
1199 switch ([nsevent type])
1201 case NSLeftMouseDown:
1202 case NSRightMouseDown:
1203 case NSOtherMouseDown:
1205 GdkEventMask event_mask;
1207 /* Emulate implicit grab, when the window has both PRESS and RELEASE
1208 * in its mask, like X (and make it owner_events since that's what
1209 * implicit grabs are like).
1211 event_mask = (GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK);
1212 if (!_gdk_quartz_pointer_grab_window &&
1213 (GDK_WINDOW_OBJECT (window)->event_mask & event_mask) == event_mask)
1215 pointer_grab_internal (window, TRUE,
1216 GDK_WINDOW_OBJECT (window)->event_mask,
1221 event = create_button_event (window, nsevent, x, y);
1222 append_event (event);
1224 _gdk_event_button_generate (_gdk_display, event);
1228 case NSRightMouseUp:
1229 case NSOtherMouseUp:
1230 event = create_button_event (window, nsevent, x, y);
1231 append_event (event);
1233 /* Ungrab implicit grab */
1234 if (_gdk_quartz_pointer_grab_window && pointer_grab_implicit)
1235 pointer_ungrab_internal (TRUE);
1238 case NSLeftMouseDragged:
1239 case NSRightMouseDragged:
1240 case NSOtherMouseDragged:
1242 event = create_motion_event (window, nsevent, x, y);
1243 append_event (event);
1248 float dx = [nsevent deltaX];
1249 float dy = [nsevent deltaY];
1250 GdkScrollDirection direction;
1252 /* The delta is how much the mouse wheel has moved. Since there's no such thing in GTK+
1253 * we accomodate by sending a different number of scroll wheel events.
1256 /* First do y events */
1260 direction = GDK_SCROLL_DOWN;
1263 direction = GDK_SCROLL_UP;
1267 event = create_scroll_event (window, nsevent, direction);
1268 append_event (event);
1272 /* Now do x events */
1276 direction = GDK_SCROLL_RIGHT;
1279 direction = GDK_SCROLL_LEFT;
1283 event = create_scroll_event (window, nsevent, direction);
1284 append_event (event);
1292 case NSFlagsChanged:
1296 type = _gdk_quartz_keys_event_type (nsevent);
1297 if (type == GDK_NOTHING)
1300 event = create_key_event (window, nsevent, type);
1301 append_event (event);
1306 NSLog(@"Untranslated: %@", nsevent);
1313 _gdk_events_queue (GdkDisplay *display)
1315 NSEvent *current_event = _gdk_quartz_event_loop_get_current ();
1319 if (!gdk_event_translate (current_event))
1320 [NSApp sendEvent:current_event];
1322 _gdk_quartz_event_loop_release_current ();
1329 /* Not supported. */
1333 gdk_display_add_client_message_filter (GdkDisplay *display,
1334 GdkAtom message_type,
1338 /* Not supported. */
1342 gdk_add_client_message_filter (GdkAtom message_type,
1346 /* Not supported. */
1350 gdk_display_sync (GdkDisplay *display)
1352 /* Not supported. */
1356 gdk_display_flush (GdkDisplay *display)
1358 /* Not supported. */
1362 gdk_event_send_client_message_for_display (GdkDisplay *display,
1364 GdkNativeWindow winid)
1366 /* Not supported. */
1371 gdk_screen_broadcast_client_message (GdkScreen *screen,
1374 /* Not supported. */
1378 gdk_screen_get_setting (GdkScreen *screen,
1382 if (strcmp (name, "gtk-double-click-time") == 0)
1384 NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
1387 GDK_QUARTZ_ALLOC_POOL;
1389 t = [defaults floatForKey:@"com.apple.mouse.doubleClickThreshold"];
1392 /* No user setting, use the default in OS X. */
1396 GDK_QUARTZ_RELEASE_POOL;
1398 g_value_set_int (value, t * 1000);
1402 /* FIXME: Add more settings */