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 /* FIXME: Send crossing events */
163 gdk_display_pointer_is_grabbed (GdkDisplay *display)
165 return _gdk_quartz_pointer_grab_window != NULL;
169 gdk_pointer_grab_info_libgtk_only (GdkDisplay *display,
170 GdkWindow **grab_window,
171 gboolean *owner_events)
173 if (!_gdk_quartz_pointer_grab_window)
177 *grab_window = _gdk_quartz_pointer_grab_window;
180 *owner_events = pointer_grab_owner_events;
186 gdk_display_pointer_ungrab (GdkDisplay *display,
189 pointer_ungrab_internal (FALSE);
193 pointer_grab_internal (GdkWindow *window,
194 gboolean owner_events,
195 GdkEventMask event_mask,
196 GdkWindow *confine_to,
200 /* FIXME: Send crossing events */
202 _gdk_quartz_pointer_grab_window = g_object_ref (window);
203 pointer_grab_owner_events = owner_events;
204 pointer_grab_event_mask = event_mask;
205 pointer_grab_implicit = implicit;
207 return GDK_GRAB_SUCCESS;
211 gdk_pointer_grab (GdkWindow *window,
212 gboolean owner_events,
213 GdkEventMask event_mask,
214 GdkWindow *confine_to,
218 g_return_val_if_fail (GDK_IS_WINDOW (window), 0);
219 g_return_val_if_fail (confine_to == NULL || GDK_IS_WINDOW (confine_to), 0);
221 if (_gdk_quartz_pointer_grab_window)
223 if (_gdk_quartz_pointer_grab_window == window && !pointer_grab_implicit)
224 return GDK_GRAB_ALREADY_GRABBED;
227 if (_gdk_quartz_pointer_grab_window != window)
228 generate_grab_broken_event (_gdk_quartz_pointer_grab_window,
229 FALSE, pointer_grab_implicit, window);
230 pointer_ungrab_internal (TRUE);
234 return pointer_grab_internal (window, owner_events, event_mask,
235 confine_to, cursor, FALSE);
239 fixup_event (GdkEvent *event)
241 if (event->any.window)
242 g_object_ref (event->any.window);
243 if (((event->any.type == GDK_ENTER_NOTIFY) ||
244 (event->any.type == GDK_LEAVE_NOTIFY)) &&
245 (event->crossing.subwindow != NULL))
246 g_object_ref (event->crossing.subwindow);
247 event->any.send_event = FALSE;
251 append_event (GdkEvent *event)
254 _gdk_event_queue_append (_gdk_display, event);
257 static GdkFilterReturn
258 apply_filters (GdkWindow *window,
262 GdkFilterReturn result = GDK_FILTER_CONTINUE;
267 event = gdk_event_new (GDK_NOTHING);
269 event->any.window = g_object_ref (window);
270 ((GdkEventPrivate *)event)->flags |= GDK_EVENT_PENDING;
272 /* I think GdkFilterFunc semantics require the passed-in event
273 * to already be in the queue. The filter func can generate
274 * more events and append them after it if it likes.
276 node = _gdk_event_queue_append (_gdk_display, event);
281 GdkEventFilter *filter = (GdkEventFilter *) tmp_list->data;
283 tmp_list = tmp_list->next;
284 result = filter->function (nsevent, event, filter->data);
285 if (result != GDK_FILTER_CONTINUE)
289 if (result == GDK_FILTER_CONTINUE || result == GDK_FILTER_REMOVE)
291 _gdk_event_queue_remove_link (_gdk_display, node);
292 g_list_free_1 (node);
293 gdk_event_free (event);
295 else /* GDK_FILTER_TRANSLATE */
297 ((GdkEventPrivate *)event)->flags &= ~GDK_EVENT_PENDING;
303 /* This function checks if the passed in window is interested in the
304 * event mask. If so, it's returned. If not, the event can be propagated
308 find_window_interested_in_event_mask (GdkWindow *window,
309 GdkEventMask event_mask,
314 GdkWindowObject *private = GDK_WINDOW_OBJECT (window);
316 if (private->event_mask & event_mask)
322 window = GDK_WINDOW (private->parent);
329 get_event_time (NSEvent *event)
331 double time = [event timestamp];
333 return time * 1000.0;
337 convert_mouse_button_number (int button)
352 /* Return an event mask from an NSEvent */
354 get_event_mask_from_ns_event (NSEvent *nsevent)
356 switch ([nsevent type])
358 case NSLeftMouseDown:
359 case NSRightMouseDown:
360 case NSOtherMouseDown:
361 return GDK_BUTTON_PRESS_MASK;
365 return GDK_BUTTON_RELEASE_MASK;
367 return GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK;
369 /* Since applications that want button press events can get
370 * scroll events on X11 (since scroll wheel events are really
371 * button press events there), we need to use GDK_BUTTON_PRESS_MASK too.
373 return GDK_SCROLL_MASK | GDK_BUTTON_PRESS_MASK;
374 case NSLeftMouseDragged:
375 return (GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK |
376 GDK_BUTTON_MOTION_MASK | GDK_BUTTON1_MOTION_MASK |
378 case NSRightMouseDragged:
379 return (GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK |
380 GDK_BUTTON_MOTION_MASK | GDK_BUTTON3_MOTION_MASK |
382 case NSOtherMouseDragged:
386 mask = (GDK_POINTER_MOTION_MASK |
387 GDK_POINTER_MOTION_HINT_MASK |
388 GDK_BUTTON_MOTION_MASK);
390 if (convert_mouse_button_number ([nsevent buttonNumber]) == 2)
391 mask |= (GDK_BUTTON2_MOTION_MASK | GDK_BUTTON2_MOTION_MASK |
400 switch (_gdk_quartz_keys_event_type (nsevent))
403 return GDK_KEY_PRESS_MASK;
404 case GDK_KEY_RELEASE:
405 return GDK_KEY_RELEASE_MASK;
409 g_assert_not_reached ();
413 g_assert_not_reached ();
420 create_focus_event (GdkWindow *window,
425 event = gdk_event_new (GDK_FOCUS_CHANGE);
426 event->focus_change.window = window;
427 event->focus_change.in = in;
432 /* Note: Used to both set a new focus window and to unset the old one. */
434 _gdk_quartz_events_update_focus_window (GdkWindow *window,
439 if (got_focus && window == current_keyboard_window)
442 /* FIXME: Don't do this when grabbed? Or make GdkQuartzWindow
443 * disallow it in the first place instead?
446 if (!got_focus && window == current_keyboard_window)
448 event = create_focus_event (current_keyboard_window, FALSE);
449 append_event (event);
450 g_object_unref (current_keyboard_window);
451 current_keyboard_window = NULL;
456 if (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;
464 event = create_focus_event (window, TRUE);
465 append_event (event);
466 current_keyboard_window = g_object_ref (window);
471 gdk_window_is_ancestor (GdkWindow *ancestor,
474 if (ancestor == NULL || window == NULL)
477 return (gdk_window_get_parent (window) == ancestor ||
478 gdk_window_is_ancestor (ancestor, gdk_window_get_parent (window)));
481 static GdkModifierType
482 get_keyboard_modifiers_from_nsevent (NSEvent *nsevent)
484 GdkModifierType modifiers = 0;
487 nsflags = [nsevent modifierFlags];
489 if (nsflags & NSAlphaShiftKeyMask)
490 modifiers |= GDK_LOCK_MASK;
491 if (nsflags & NSShiftKeyMask)
492 modifiers |= GDK_SHIFT_MASK;
493 if (nsflags & NSControlKeyMask)
494 modifiers |= GDK_CONTROL_MASK;
495 if (nsflags & NSCommandKeyMask)
496 modifiers |= GDK_MOD1_MASK;
498 /* FIXME: Support GDK_BUTTON_MASK */
504 convert_window_coordinates_to_root (GdkWindow *window,
515 if (gdk_window_get_origin (window, &ox, &oy))
523 create_crossing_event (GdkWindow *window,
525 GdkEventType event_type,
526 GdkCrossingMode mode,
527 GdkNotifyType detail)
532 event = gdk_event_new (event_type);
534 event->crossing.window = window;
535 event->crossing.subwindow = NULL; /* FIXME */
536 event->crossing.time = get_event_time (nsevent);
538 point = [nsevent locationInWindow];
539 event->crossing.x = point.x;
540 event->crossing.y = point.y;
541 convert_window_coordinates_to_root (window, event->crossing.x, event->crossing.y,
542 &event->crossing.x_root,
543 &event->crossing.y_root);
545 event->crossing.mode = mode;
546 event->crossing.detail = detail;
548 /* FIXME: state, (button state too) */
554 synthesize_enter_event (GdkWindow *window,
556 GdkCrossingMode mode,
557 GdkNotifyType detail)
561 if (_gdk_quartz_pointer_grab_window != NULL &&
562 !pointer_grab_owner_events &&
563 !(pointer_grab_event_mask & GDK_ENTER_NOTIFY_MASK))
566 if (!(GDK_WINDOW_OBJECT (window)->event_mask & GDK_ENTER_NOTIFY_MASK))
569 event = create_crossing_event (window, nsevent, GDK_ENTER_NOTIFY,
572 append_event (event);
576 synthesize_enter_events (GdkWindow *from,
579 GdkCrossingMode mode,
580 GdkNotifyType detail)
582 GdkWindow *prev = gdk_window_get_parent (to);
585 synthesize_enter_events (from, prev, nsevent, mode, detail);
586 synthesize_enter_event (to, nsevent, mode, detail);
590 synthesize_leave_event (GdkWindow *window,
592 GdkCrossingMode mode,
593 GdkNotifyType detail)
597 if (_gdk_quartz_pointer_grab_window != NULL &&
598 !pointer_grab_owner_events &&
599 !(pointer_grab_event_mask & GDK_LEAVE_NOTIFY_MASK))
602 if (!(GDK_WINDOW_OBJECT (window)->event_mask & GDK_LEAVE_NOTIFY_MASK))
605 event = create_crossing_event (window, nsevent, GDK_LEAVE_NOTIFY,
608 append_event (event);
612 synthesize_leave_events (GdkWindow *from,
615 GdkCrossingMode mode,
616 GdkNotifyType detail)
618 GdkWindow *next = gdk_window_get_parent (from);
620 synthesize_leave_event (from, nsevent, mode, detail);
622 synthesize_leave_events (next, to, nsevent, mode, detail);
626 synthesize_crossing_events (GdkWindow *window,
627 GdkCrossingMode mode,
632 GdkWindow *intermediate, *tem, *common_ancestor;
634 if (gdk_window_is_ancestor (current_mouse_window, window))
636 /* Pointer has moved to an inferior window. */
637 synthesize_leave_event (current_mouse_window, nsevent, mode, GDK_NOTIFY_INFERIOR);
639 /* If there are intermediate windows, generate ENTER_NOTIFY
642 intermediate = gdk_window_get_parent (window);
644 if (intermediate != current_mouse_window)
646 synthesize_enter_events (current_mouse_window, intermediate, nsevent, mode, GDK_NOTIFY_VIRTUAL);
649 synthesize_enter_event (window, nsevent, mode, GDK_NOTIFY_ANCESTOR);
651 else if (gdk_window_is_ancestor (window, current_mouse_window))
653 /* Pointer has moved to an ancestor window. */
654 synthesize_leave_event (current_mouse_window, nsevent, mode, GDK_NOTIFY_ANCESTOR);
656 /* If there are intermediate windows, generate LEAVE_NOTIFY
659 intermediate = gdk_window_get_parent (current_mouse_window);
660 if (intermediate != window)
662 synthesize_leave_events (intermediate, window, nsevent, mode, GDK_NOTIFY_VIRTUAL);
665 synthesize_enter_event (window, nsevent, mode, GDK_NOTIFY_INFERIOR);
667 else if (current_mouse_window)
669 /* Find least common ancestor of current_mouse_window and window */
670 tem = current_mouse_window;
672 common_ancestor = gdk_window_get_parent (tem);
673 tem = common_ancestor;
674 } while (common_ancestor &&
675 !gdk_window_is_ancestor (common_ancestor, window));
678 synthesize_leave_event (current_mouse_window, nsevent, mode, GDK_NOTIFY_NONLINEAR);
679 intermediate = gdk_window_get_parent (current_mouse_window);
680 if (intermediate != common_ancestor)
682 synthesize_leave_events (intermediate, common_ancestor,
683 nsevent, mode, GDK_NOTIFY_NONLINEAR_VIRTUAL);
685 intermediate = gdk_window_get_parent (window);
686 if (intermediate != common_ancestor)
688 synthesize_enter_events (common_ancestor, intermediate,
689 nsevent, mode, GDK_NOTIFY_NONLINEAR_VIRTUAL);
691 synthesize_enter_event (window, nsevent, mode, GDK_NOTIFY_NONLINEAR);
696 /* This means we have not current_mouse_window. FIXME: Should
697 * we make sure to always set the root window instead of NULL?
700 /* FIXME: Figure out why this is being called with window being
701 * NULL. The check works around a crash for now.
704 synthesize_enter_event (window, nsevent, mode, GDK_NOTIFY_UNKNOWN);
707 _gdk_quartz_events_update_mouse_window (window);
711 _gdk_quartz_events_send_map_events (GdkWindow *window)
714 GdkWindow *interested_window;
715 GdkWindowObject *private = (GdkWindowObject *)window;
717 interested_window = find_window_interested_in_event_mask (window,
721 if (interested_window)
723 GdkEvent *event = gdk_event_new (GDK_MAP);
724 event->any.window = interested_window;
725 append_event (event);
728 for (list = private->children; list != NULL; list = list->next)
729 _gdk_quartz_events_send_map_events ((GdkWindow *)list->data);
732 /* Get current mouse window */
734 _gdk_quartz_events_get_mouse_window (void)
736 if (_gdk_quartz_pointer_grab_window && !pointer_grab_owner_events)
737 return _gdk_quartz_pointer_grab_window;
739 return current_mouse_window;
742 /* Update mouse window */
744 _gdk_quartz_events_update_mouse_window (GdkWindow *window)
747 g_object_ref (window);
748 if (current_mouse_window)
749 g_object_unref (current_mouse_window);
751 current_mouse_window = window;
754 /* Update current cursor */
756 _gdk_quartz_events_update_cursor (GdkWindow *window)
758 GdkWindowObject *private = GDK_WINDOW_OBJECT (window);
759 NSCursor *nscursor = nil;
762 GdkWindowImplQuartz *impl = GDK_WINDOW_IMPL_QUARTZ (private->impl);
764 nscursor = impl->nscursor;
768 private = private->parent;
772 nscursor = [NSCursor arrowCursor];
774 if ([NSCursor currentCursor] != nscursor)
778 /* This function finds the correct window to send an event to,
779 * taking into account grabs (FIXME: not done yet), event propagation,
783 find_window_for_event (NSEvent *nsevent, gint *x, gint *y)
785 NSWindow *nswindow = [nsevent window];
786 NSEventType event_type = [nsevent type];
791 /* Window where not created by GDK so the event should be handled by Quartz */
792 if (![[nswindow contentView] isKindOfClass:[GdkQuartzView class]])
795 if (event_type == NSMouseMoved ||
796 event_type == NSLeftMouseDragged ||
797 event_type == NSRightMouseDragged ||
798 event_type == NSOtherMouseDragged)
800 GdkWindow *toplevel = [(GdkQuartzView *)[nswindow contentView] gdkWindow];
801 NSPoint point = [nsevent locationInWindow];
802 GdkWindow *mouse_window;
804 mouse_window = _gdk_quartz_window_find_child_by_point (toplevel, point.x, point.y, x, y);
807 mouse_window = _gdk_root;
809 if (_gdk_quartz_pointer_grab_window)
811 if (mouse_window != current_mouse_window)
812 synthesize_crossing_events (mouse_window, GDK_CROSSING_NORMAL, nsevent, *x, *y);
816 if (current_mouse_window != mouse_window)
818 synthesize_crossing_events (mouse_window, GDK_CROSSING_NORMAL, nsevent, *x, *y);
820 _gdk_quartz_events_update_cursor (mouse_window);
827 case NSLeftMouseDown:
828 case NSRightMouseDown:
829 case NSOtherMouseDown:
835 case NSLeftMouseDragged:
836 case NSRightMouseDragged:
837 case NSOtherMouseDragged:
839 GdkWindow *toplevel = [(GdkQuartzView *)[nswindow contentView] gdkWindow];
840 NSPoint point = [nsevent locationInWindow];
841 GdkWindow *mouse_window;
842 GdkEventMask event_mask;
843 GdkWindow *real_window;
845 if (_gdk_quartz_pointer_grab_window && !pointer_grab_owner_events)
847 if (pointer_grab_event_mask & get_event_mask_from_ns_event (nsevent))
851 GdkWindowObject *grab_toplevel;
853 w = GDK_WINDOW_OBJECT (_gdk_quartz_pointer_grab_window);
854 grab_toplevel = GDK_WINDOW_OBJECT (gdk_window_get_toplevel (_gdk_quartz_pointer_grab_window));
857 tempy = GDK_WINDOW_IMPL_QUARTZ (grab_toplevel->impl)->height -
860 while (w != grab_toplevel)
871 return _gdk_quartz_pointer_grab_window;
881 mouse_window = _gdk_root;
885 mouse_window = _gdk_quartz_window_find_child_by_point (toplevel, point.x, point.y, x, y);
888 event_mask = get_event_mask_from_ns_event (nsevent);
889 real_window = find_window_interested_in_event_mask (mouse_window, event_mask, TRUE);
899 GdkWindow *mouse_window;
901 point = [nsevent locationInWindow];
902 toplevel = [(GdkQuartzView *)[nswindow contentView] gdkWindow];
904 mouse_window = _gdk_quartz_window_find_child_by_point (toplevel, point.x, point.y, x, y);
906 synthesize_crossing_events (mouse_window, GDK_CROSSING_NORMAL, nsevent, *x, *y);
911 synthesize_crossing_events (_gdk_root, GDK_CROSSING_NORMAL, nsevent, *x, *y);
918 GdkEventMask event_mask;
920 if (_gdk_quartz_keyboard_grab_window && !keyboard_grab_owner_events)
921 return _gdk_quartz_keyboard_grab_window;
923 event_mask = get_event_mask_from_ns_event (nsevent);
924 return find_window_interested_in_event_mask (current_keyboard_window, event_mask, TRUE);
928 case NSAppKitDefined:
929 case NSSystemDefined:
930 /* We ignore these events */
933 NSLog(@"Unhandled event %@", nsevent);
940 create_button_event (GdkWindow *window, NSEvent *nsevent,
947 switch ([nsevent type])
949 case NSLeftMouseDown:
950 case NSRightMouseDown:
951 case NSOtherMouseDown:
952 type = GDK_BUTTON_PRESS;
957 type = GDK_BUTTON_RELEASE;
960 g_assert_not_reached ();
963 button = convert_mouse_button_number ([nsevent buttonNumber]);
965 event = gdk_event_new (type);
966 event->button.window = window;
967 event->button.time = get_event_time (nsevent);
970 /* FIXME event->axes */
971 event->button.state = get_keyboard_modifiers_from_nsevent (nsevent);
972 event->button.button = button;
973 event->button.device = _gdk_display->core_pointer;
974 convert_window_coordinates_to_root (window, x, y,
975 &event->button.x_root,
976 &event->button.y_root);
982 create_motion_event (GdkWindow *window, NSEvent *nsevent, gint x, gint y)
986 GdkModifierType state = 0;
989 switch ([nsevent type])
991 case NSLeftMouseDragged:
992 case NSRightMouseDragged:
993 case NSOtherMouseDragged:
994 button = convert_mouse_button_number ([nsevent buttonNumber]);
997 type = GDK_MOTION_NOTIFY;
1000 g_assert_not_reached ();
1003 /* This maps buttons 1 to 5 to GDK_BUTTON[1-5]_MASK */
1004 if (button >= 1 && button <= 5)
1005 state = (1 << (button + 7));
1007 state |= get_keyboard_modifiers_from_nsevent (nsevent);
1009 event = gdk_event_new (type);
1010 event->motion.window = window;
1011 event->motion.time = get_event_time (nsevent);
1012 event->motion.x = x;
1013 event->motion.y = y;
1014 /* FIXME event->axes */
1015 event->motion.state = state;
1016 event->motion.is_hint = FALSE;
1017 event->motion.device = _gdk_display->core_pointer;
1018 convert_window_coordinates_to_root (window, x, y,
1019 &event->motion.x_root, &event->motion.y_root);
1025 create_scroll_event (GdkWindow *window, NSEvent *nsevent, GdkScrollDirection direction)
1030 event = gdk_event_new (GDK_SCROLL);
1031 event->scroll.window = window;
1032 event->scroll.time = get_event_time (nsevent);
1034 point = [nsevent locationInWindow];
1035 event->scroll.x = point.x;
1036 event->scroll.y = point.y;
1037 convert_window_coordinates_to_root (window, event->scroll.x, event->scroll.y,
1038 &event->scroll.x_root,
1039 &event->scroll.y_root);
1041 event->scroll.direction = direction;
1042 event->scroll.device = _gdk_display->core_pointer;
1048 create_key_event (GdkWindow *window, NSEvent *nsevent, GdkEventType type)
1054 event = gdk_event_new (type);
1055 event->key.window = window;
1056 event->key.time = get_event_time (nsevent);
1057 event->key.state = get_keyboard_modifiers_from_nsevent (nsevent);
1058 event->key.hardware_keycode = [nsevent keyCode];
1059 event->key.group = ([nsevent modifierFlags] & NSAlternateKeyMask) ? 1 : 0;
1061 event->key.keyval = GDK_VoidSymbol;
1063 gdk_keymap_translate_keyboard_state (NULL,
1064 event->key.hardware_keycode,
1070 event->key.is_modifier = _gdk_quartz_keys_is_modifier (event->key.hardware_keycode);
1072 event->key.string = NULL;
1074 /* Fill in ->string since apps depend on it, taken from the x11 backend. */
1075 if (event->key.keyval != GDK_VoidSymbol)
1076 c = gdk_keyval_to_unicode (event->key.keyval);
1080 gsize bytes_written;
1083 len = g_unichar_to_utf8 (c, buf);
1086 event->key.string = g_locale_from_utf8 (buf, len,
1087 NULL, &bytes_written,
1089 if (event->key.string)
1090 event->key.length = bytes_written;
1092 else if (event->key.keyval == GDK_Escape)
1094 event->key.length = 1;
1095 event->key.string = g_strdup ("\033");
1097 else if (event->key.keyval == GDK_Return ||
1098 event->key.keyval == GDK_KP_Enter)
1100 event->key.length = 1;
1101 event->key.string = g_strdup ("\r");
1104 if (!event->key.string)
1106 event->key.length = 0;
1107 event->key.string = g_strdup ("");
1111 g_message ("key %s:\t\twindow: %p key: %12s %d",
1112 type == GDK_KEY_PRESS ? "press" : "release",
1114 event->key.keyval ? gdk_keyval_name (event->key.keyval) : "(none)",
1115 event->key.keyval));
1119 static GdkEventMask current_mask = 0;
1121 _gdk_quartz_events_get_current_event_mask (void)
1123 return current_mask;
1127 gdk_event_translate (NSEvent *nsevent)
1130 GdkFilterReturn result;
1134 if (_gdk_default_filters)
1136 /* Apply global filters */
1138 GdkFilterReturn result = apply_filters (NULL, nsevent, _gdk_default_filters);
1140 /* If result is GDK_FILTER_CONTINUE, we continue as if nothing
1141 * happened. If it is GDK_FILTER_REMOVE,
1142 * we return TRUE and won't send the message to Quartz.
1144 if (result == GDK_FILTER_REMOVE)
1148 /* Catch the case where the entire app loses focus, and break any grabs. */
1149 if ([nsevent type] == NSAppKitDefined)
1151 if ([nsevent subtype] == NSApplicationDeactivatedEventType)
1153 if (_gdk_quartz_keyboard_grab_window)
1155 generate_grab_broken_event (_gdk_quartz_keyboard_grab_window,
1158 g_object_unref (_gdk_quartz_keyboard_grab_window);
1159 _gdk_quartz_keyboard_grab_window = NULL;
1162 if (_gdk_quartz_pointer_grab_window)
1164 generate_grab_broken_event (_gdk_quartz_pointer_grab_window,
1165 FALSE, pointer_grab_implicit,
1167 g_object_unref (_gdk_quartz_pointer_grab_window);
1168 _gdk_quartz_pointer_grab_window = NULL;
1173 window = find_window_for_event (nsevent, &x, &y);
1175 /* FIXME: During owner_event grabs, we don't find a window when there is a
1176 * click on a no-window widget, which makes popups etc still stay up. Need
1177 * to figure out why that is.
1183 result = apply_filters (window, nsevent, ((GdkWindowObject *) window)->filters);
1185 if (result == GDK_FILTER_REMOVE)
1188 current_mask = get_event_mask_from_ns_event (nsevent);
1190 switch ([nsevent type])
1192 case NSLeftMouseDown:
1193 case NSRightMouseDown:
1194 case NSOtherMouseDown:
1196 GdkEventMask event_mask;
1198 /* Emulate implicit grab, when the window has both PRESS and RELEASE
1199 * in its mask, like X (and make it owner_events since that's what
1200 * implicit grabs are like).
1202 event_mask = (GDK_BUTTON_RELEASE_MASK | GDK_BUTTON_RELEASE_MASK);
1203 if (!_gdk_quartz_pointer_grab_window &&
1204 (GDK_WINDOW_OBJECT (window)->event_mask & event_mask) == event_mask)
1206 pointer_grab_internal (window, TRUE,
1207 GDK_WINDOW_OBJECT (window)->event_mask,
1212 event = create_button_event (window, nsevent, x, y);
1213 append_event (event);
1215 _gdk_event_button_generate (_gdk_display, event);
1219 case NSRightMouseUp:
1220 case NSOtherMouseUp:
1221 event = create_button_event (window, nsevent, x, y);
1222 append_event (event);
1224 /* Ungrab implicit grab */
1225 if (_gdk_quartz_pointer_grab_window &&
1226 pointer_grab_implicit)
1227 pointer_ungrab_internal (TRUE);
1230 case NSLeftMouseDragged:
1231 case NSRightMouseDragged:
1232 case NSOtherMouseDragged:
1234 event = create_motion_event (window, nsevent, x, y);
1235 append_event (event);
1240 float dx = [nsevent deltaX];
1241 float dy = [nsevent deltaY];
1242 GdkScrollDirection direction;
1244 /* The delta is how much the mouse wheel has moved. Since there's no such thing in GTK+
1245 * we accomodate by sending a different number of scroll wheel events.
1248 /* First do y events */
1252 direction = GDK_SCROLL_DOWN;
1255 direction = GDK_SCROLL_UP;
1259 event = create_scroll_event (window, nsevent, direction);
1260 append_event (event);
1264 /* Now do x events */
1268 direction = GDK_SCROLL_RIGHT;
1271 direction = GDK_SCROLL_LEFT;
1275 event = create_scroll_event (window, nsevent, direction);
1276 append_event (event);
1284 case NSFlagsChanged:
1288 type = _gdk_quartz_keys_event_type (nsevent);
1289 if (type == GDK_NOTHING)
1292 event = create_key_event (window, nsevent, type);
1293 append_event (event);
1298 NSLog(@"Untranslated: %@", nsevent);
1305 _gdk_events_queue (GdkDisplay *display)
1307 NSEvent *current_event = _gdk_quartz_event_loop_get_current ();
1311 if (!gdk_event_translate (current_event))
1312 [NSApp sendEvent:current_event];
1314 _gdk_quartz_event_loop_release_current ();
1321 /* Not supported. */
1325 gdk_display_add_client_message_filter (GdkDisplay *display,
1326 GdkAtom message_type,
1330 /* Not supported. */
1334 gdk_add_client_message_filter (GdkAtom message_type,
1338 /* Not supported. */
1342 gdk_display_sync (GdkDisplay *display)
1344 /* Not supported. */
1348 gdk_display_flush (GdkDisplay *display)
1350 /* Not supported. */
1354 gdk_event_send_client_message_for_display (GdkDisplay *display,
1356 GdkNativeWindow winid)
1358 /* Not supported. */
1363 gdk_screen_broadcast_client_message (GdkScreen *screen,
1366 /* Not supported. */
1370 gdk_screen_get_setting (GdkScreen *screen,
1374 if (strcmp (name, "gtk-double-click-time") == 0)
1376 NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
1379 GDK_QUARTZ_ALLOC_POOL;
1381 t = [defaults floatForKey:@"com.apple.mouse.doubleClickThreshold"];
1384 /* No user setting, use the default in OS X. */
1388 GDK_QUARTZ_RELEASE_POOL;
1390 g_value_set_int (value, t * 1000);
1394 /* FIXME: Add more settings */