31
31
#include "gdkscreen.h"
32
32
#include "gdkkeysyms.h"
34
33
#include "gdkprivate-quartz.h"
36
static GPollFD event_poll_fd;
37
static NSEvent *current_event;
39
35
/* This is the window the mouse is currently over */
40
static GdkWindow *current_mouse_window;
36
static GdkWindow *current_mouse_window;
42
38
/* This is the window corresponding to the key window */
43
static GdkWindow *current_keyboard_window;
39
static GdkWindow *current_keyboard_window;
45
41
/* This is the pointer grab window */
46
GdkWindow *_gdk_quartz_pointer_grab_window;
47
static gboolean pointer_grab_owner_events;
42
GdkWindow *_gdk_quartz_pointer_grab_window;
43
static gboolean pointer_grab_owner_events;
48
44
static GdkEventMask pointer_grab_event_mask;
49
static gboolean pointer_grab_implicit;
45
static gboolean pointer_grab_implicit;
51
47
/* This is the keyboard grab window */
52
GdkWindow *_gdk_quartz_keyboard_grab_window;
53
static gboolean keyboard_grab_owner_events;
55
static void append_event (GdkEvent *event);
58
gdk_event_prepare (GSource *source,
64
GDK_QUARTZ_ALLOC_POOL;
68
event = [NSApp nextEventMatchingMask: NSAnyEventMask
69
untilDate: [NSDate distantPast]
70
inMode: NSDefaultRunLoopMode
73
retval = (_gdk_event_queue_find_first (_gdk_display) != NULL ||
76
GDK_QUARTZ_RELEASE_POOL;
82
gdk_event_check (GSource *source)
84
if (_gdk_event_queue_find_first (_gdk_display) != NULL ||
88
/* FIXME: We should maybe try to fetch an event again here */
94
gdk_event_dispatch (GSource *source,
100
GDK_QUARTZ_ALLOC_POOL;
102
_gdk_events_queue (_gdk_display);
104
event = _gdk_event_unqueue (_gdk_display);
109
(*_gdk_event_func) (event, _gdk_event_data);
111
gdk_event_free (event);
114
GDK_QUARTZ_RELEASE_POOL;
119
static GSourceFuncs event_funcs = {
126
static GPollFunc old_poll_func;
128
static pthread_t select_thread = 0;
129
static int wakeup_pipe[2];
130
static pthread_mutex_t pollfd_mutex = PTHREAD_MUTEX_INITIALIZER;
131
static pthread_cond_t ready_cond = PTHREAD_COND_INITIALIZER;
132
static GPollFD *pollfds;
133
static GPollFD *pipe_pollfd;
134
static guint n_pollfds;
135
static CFRunLoopSourceRef select_main_thread_source;
136
static CFRunLoopRef main_thread_run_loop;
139
select_thread_func (void *arg)
145
pthread_mutex_lock (&pollfd_mutex);
146
pthread_cond_wait (&ready_cond, &pollfd_mutex);
148
n_active_fds = old_poll_func (pollfds, n_pollfds, -1);
149
if (pipe_pollfd->revents)
154
n = read (pipe_pollfd->fd, &c, 1);
161
pthread_mutex_unlock (&pollfd_mutex);
165
/* We have active fds, signal the main thread */
166
CFRunLoopSourceSignal (select_main_thread_source);
167
if (CFRunLoopIsWaiting (main_thread_run_loop))
168
CFRunLoopWakeUp (main_thread_run_loop);
174
got_fd_activity (void *info)
178
/* Post a message so we'll break out of the message loop */
179
event = [NSEvent otherEventWithType: NSApplicationDefined
180
location: NSZeroPoint
189
[NSApp postEvent:event atStart:YES];
193
poll_func (GPollFD *ufds, guint nfds, gint timeout_)
200
GDK_QUARTZ_ALLOC_POOL;
204
if (!select_thread) {
205
/* Create source used for signalling the main thread */
206
main_thread_run_loop = CFRunLoopGetCurrent ();
207
CFRunLoopSourceContext source_context = {0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, got_fd_activity };
208
select_main_thread_source = CFRunLoopSourceCreate (NULL, 0, &source_context);
209
CFRunLoopAddSource (main_thread_run_loop, select_main_thread_source, kCFRunLoopDefaultMode);
212
pthread_create (&select_thread, NULL, select_thread_func, NULL);
215
pthread_mutex_lock (&pollfd_mutex);
218
pollfds = g_memdup (ufds, sizeof (GPollFD) * nfds);
220
/* We cheat and use the fake fd for our pipe */
221
for (i = 0; i < nfds; i++)
223
if (pollfds[i].fd == -1)
225
pipe_pollfd = &pollfds[i];
226
pollfds[i].fd = wakeup_pipe[0];
227
pollfds[i].events = G_IO_IN;
231
pthread_mutex_unlock (&pollfd_mutex);
233
/* Start our thread */
234
pthread_cond_signal (&ready_cond);
238
limit_date = [NSDate distantFuture];
239
else if (timeout_ == 0)
240
limit_date = [NSDate distantPast];
242
limit_date = [NSDate dateWithTimeIntervalSinceNow:timeout_/1000.0];
244
event = [NSApp nextEventMatchingMask: NSAnyEventMask
245
untilDate: limit_date
246
inMode: NSDefaultRunLoopMode
251
if ([event type] == NSApplicationDefined)
253
pthread_mutex_lock (&pollfd_mutex);
255
for (i = 0; i < n_pollfds; i++)
257
if (ufds[i].fd == -1)
260
g_assert (ufds[i].fd == pollfds[i].fd);
261
g_assert (ufds[i].events == pollfds[i].events);
263
if (pollfds[i].revents)
265
ufds[i].revents = pollfds[i].revents;
270
pthread_mutex_unlock (&pollfd_mutex);
272
event = [NSApp nextEventMatchingMask: NSAnyEventMask
273
untilDate: [NSDate distantPast]
274
inMode: NSDefaultRunLoopMode
280
/* There were no active fds, break out of the other thread's poll() */
281
if (n_active == 0 && wakeup_pipe[1])
285
write (wakeup_pipe[1], &c, 1);
290
ufds[0].revents = G_IO_IN;
292
/* FIXME: We can't assert here, but we might need to have a
293
* queue for events instead.
295
/*g_assert (current_event == NULL);*/
297
current_event = [event retain];
302
GDK_QUARTZ_RELEASE_POOL;
48
GdkWindow * _gdk_quartz_keyboard_grab_window;
49
static gboolean keyboard_grab_owner_events;
51
static void get_child_coordinates_from_ancestor (GdkWindow *ancestor_window,
54
GdkWindow *child_window,
57
static void get_ancestor_coordinates_from_child (GdkWindow *child_window,
60
GdkWindow *ancestor_window,
63
static void get_converted_window_coordinates (GdkWindow *in_window,
66
GdkWindow *out_window,
69
static void append_event (GdkEvent *event);
308
72
_gdk_events_init (void)
312
event_poll_fd.events = G_IO_IN;
313
event_poll_fd.fd = -1;
315
source = g_source_new (&event_funcs, sizeof (GSource));
316
g_source_add_poll (source, &event_poll_fd);
317
g_source_set_priority (source, GDK_PRIORITY_EVENTS);
318
g_source_set_can_recurse (source, TRUE);
319
g_source_attach (source, NULL);
321
old_poll_func = g_main_context_get_poll_func (NULL);
322
g_main_context_set_poll_func (NULL, poll_func);
74
_gdk_quartz_event_loop_init ();
324
76
current_mouse_window = g_object_ref (_gdk_root);
325
77
current_keyboard_window = g_object_ref (_gdk_root);
792
556
GdkNotifyType detail)
797
561
event = gdk_event_new (event_type);
799
563
event->crossing.window = window;
800
564
event->crossing.subwindow = NULL; /* FIXME */
801
event->crossing.time = get_event_time (nsevent);
803
point = [nsevent locationInWindow];
804
event->crossing.x = point.x;
805
event->crossing.y = point.y;
806
convert_window_coordinates_to_root (window, event->crossing.x, event->crossing.y,
565
event->crossing.time = get_time_from_ns_event (nsevent);
567
/* Split out this block: */
573
nswindow = [nsevent window];
574
point = [nsevent locationInWindow];
576
toplevel = [(GdkQuartzView *)[nswindow contentView] gdkWindow];
580
/* Flip the y coordinate. */
581
if (toplevel == _gdk_root)
582
y_tmp = _gdk_quartz_window_get_inverted_screen_y (point.y);
585
GdkWindowImplQuartz *impl;
587
impl = GDK_WINDOW_IMPL_QUARTZ (GDK_WINDOW_OBJECT (toplevel)->impl);
588
y_tmp = impl->height - point.y;
591
get_converted_window_coordinates (toplevel,
597
event->crossing.x = x_tmp;
598
event->crossing.y = y_tmp;
600
convert_window_coordinates_to_root (window,
807
603
&event->crossing.x_root,
808
604
&event->crossing.y_root);
810
606
event->crossing.mode = mode;
811
607
event->crossing.detail = detail;
813
/* FIXME: state, (button state too) */
608
event->crossing.state = get_keyboard_modifiers_from_ns_event (nsevent);
610
/* FIXME: focus and button state */
1043
/* This function finds the correct window to send an event to,
1044
* taking into account grabs (FIXME: not done yet), event propagation,
1048
find_window_for_event (NSEvent *nsevent, gint *x, gint *y)
840
/* Translates coordinates from an ancestor window + coords, to
841
* coordinates that are relative the child window.
844
get_child_coordinates_from_ancestor (GdkWindow *ancestor_window,
847
GdkWindow *child_window,
851
GdkWindowObject *ancestor_private = GDK_WINDOW_OBJECT (ancestor_window);
852
GdkWindowObject *child_private = GDK_WINDOW_OBJECT (child_window);
854
while (child_private != ancestor_private)
856
ancestor_x -= child_private->x;
857
ancestor_y -= child_private->y;
859
child_private = child_private->parent;
862
*child_x = ancestor_x;
863
*child_y = ancestor_y;
866
/* Translates coordinates from a child window + coords, to
867
* coordinates that are relative the ancestor window.
870
get_ancestor_coordinates_from_child (GdkWindow *child_window,
873
GdkWindow *ancestor_window,
877
GdkWindowObject *child_private = GDK_WINDOW_OBJECT (child_window);
878
GdkWindowObject *ancestor_private = GDK_WINDOW_OBJECT (ancestor_window);
880
while (child_private != ancestor_private)
882
child_x += child_private->x;
883
child_y += child_private->y;
885
child_private = child_private->parent;
888
*ancestor_x = child_x;
889
*ancestor_y = child_y;
892
/* Translates coordinates relative to one window (in_window) into
893
* coordinates relative to another window (out_window).
896
get_converted_window_coordinates (GdkWindow *in_window,
899
GdkWindow *out_window,
903
GdkWindow *in_toplevel;
904
GdkWindow *out_toplevel;
905
int in_origin_x, in_origin_y;
906
int out_origin_x, out_origin_y;
908
/* First translate to "in" toplevel coordinates, then on to "out"
909
* toplevel coordinates, and finally to "out" child (the passed in
910
* window) coordinates.
913
in_toplevel = gdk_window_get_toplevel (in_window);
914
out_toplevel = gdk_window_get_toplevel (out_window);
916
/* Translate in_x, in_y to "in" toplevel coordinates. */
917
get_ancestor_coordinates_from_child (in_window, in_x, in_y,
918
in_toplevel, &in_x, &in_y);
920
gdk_window_get_origin (in_toplevel, &in_origin_x, &in_origin_y);
921
gdk_window_get_origin (out_toplevel, &out_origin_x, &out_origin_y);
923
/* Translate in_x, in_y to "out" toplevel coordinates. */
924
in_x -= out_origin_x - in_origin_x;
925
in_y -= out_origin_y - in_origin_y;
927
get_child_coordinates_from_ancestor (out_toplevel,
933
/* Given a mouse NSEvent, returns the window in which the pointer
934
* position from the event is. The returned coordinates are relative
935
* to the found window, and normal GDK coordinates, not Quartz.
938
find_window_for_mouse_ns_event (NSEvent *nsevent,
946
GdkWindow *found_window;
948
nswindow = [nsevent window];
949
toplevel = [(GdkQuartzView *)[nswindow contentView] gdkWindow];
951
point = [nsevent locationInWindow];
955
/* Flip the y coordinate. */
956
if (toplevel == _gdk_root)
957
y_tmp = _gdk_quartz_window_get_inverted_screen_y (point.y);
960
GdkWindowImplQuartz *impl;
962
impl = GDK_WINDOW_IMPL_QUARTZ (GDK_WINDOW_OBJECT (toplevel)->impl);
963
y_tmp = impl->height - point.y;
966
found_window = _gdk_quartz_window_find_child (toplevel, x_tmp, y_tmp);
968
/* Translate the coordinates so they are relative to the found
972
get_child_coordinates_from_ancestor (toplevel,
983
/* This function finds the correct window to send an event to, taking
984
* into account grabs, event propagation, and event masks.
987
find_window_for_ns_event (NSEvent *nsevent,
1050
991
NSWindow *nswindow = [nsevent window];
1051
992
NSEventType event_type = [nsevent type];
1097
1043
case NSRightMouseDragged:
1098
1044
case NSOtherMouseDragged:
1100
GdkWindow *toplevel = [(GdkQuartzView *)[nswindow contentView] gdkWindow];
1101
NSPoint point = [nsevent locationInWindow];
1102
1046
GdkWindow *mouse_window;
1103
1047
GdkEventMask event_mask;
1104
1048
GdkWindow *real_window;
1106
if (_gdk_quartz_pointer_grab_window && !pointer_grab_owner_events)
1050
/* From the docs for XGrabPointer:
1052
* If owner_events is True and if a generated pointer event
1053
* would normally be reported to this client, it is reported
1054
* as usual. Otherwise, the event is reported with respect to
1055
* the grab_window and is reported only if selected by
1056
* event_mask. For either value of owner_events, unreported
1057
* events are discarded.
1059
* This means we first try the owner, then the grab window,
1062
if (_gdk_quartz_pointer_grab_window)
1064
if (pointer_grab_owner_events)
1066
mouse_window = find_window_for_mouse_ns_event (nsevent, x, y);
1067
event_mask = get_event_mask_from_ns_event (nsevent);
1068
real_window = find_window_interested_in_event_mask (mouse_window, event_mask, TRUE);
1070
if (mouse_window && real_window && mouse_window != real_window)
1071
get_ancestor_coordinates_from_child (mouse_window,
1080
/* FIXME: This part needs some fixing, it doesn't return
1081
* the right coordinates if the nsevent happens for a
1082
* different window than the grab window.
1108
1084
if (pointer_grab_event_mask & get_event_mask_from_ns_event (nsevent))
1112
GdkWindowObject *grab_toplevel;
1114
w = GDK_WINDOW_OBJECT (_gdk_quartz_pointer_grab_window);
1115
grab_toplevel = GDK_WINDOW_OBJECT (gdk_window_get_toplevel (_gdk_quartz_pointer_grab_window));
1118
tempy = GDK_WINDOW_IMPL_QUARTZ (grab_toplevel->impl)->height -
1121
while (w != grab_toplevel)
1086
GdkWindow *grab_toplevel;
1090
grab_toplevel = gdk_window_get_toplevel (_gdk_quartz_pointer_grab_window);
1091
point = [nsevent locationInWindow];
1094
y_tmp = GDK_WINDOW_IMPL_QUARTZ (GDK_WINDOW_OBJECT (grab_toplevel)->impl)->height - point.y;
1096
get_child_coordinates_from_ancestor (grab_toplevel,
1098
_gdk_quartz_pointer_grab_window,
1132
1101
return _gdk_quartz_pointer_grab_window;
1142
mouse_window = _gdk_root;
1146
mouse_window = _gdk_quartz_find_child_window_by_point (toplevel, point.x, point.y, x, y);
1149
event_mask = get_event_mask_from_ns_event (nsevent);
1150
real_window = find_window_interested_in_event_mask (mouse_window, event_mask, TRUE);
1108
/* The non-grabbed case. */
1109
mouse_window = find_window_for_mouse_ns_event (nsevent, x, y);
1110
event_mask = get_event_mask_from_ns_event (nsevent);
1111
real_window = find_window_interested_in_event_mask (mouse_window, event_mask, TRUE);
1113
/* We have to translate the coordinates if the actual
1114
* window is different from the mouse window.
1116
if (mouse_window && real_window && mouse_window != real_window)
1117
get_ancestor_coordinates_from_child (mouse_window,
1156
1127
case NSMouseEntered:
1159
GdkWindow *toplevel;
1160
1129
GdkWindow *mouse_window;
1162
point = [nsevent locationInWindow];
1164
toplevel = [(GdkQuartzView *)[nswindow contentView] gdkWindow];
1166
mouse_window = _gdk_quartz_find_child_window_by_point (toplevel, point.x, point.y, x, y);
1131
mouse_window = find_window_for_mouse_ns_event (nsevent, x, y);
1168
1132
synthesize_crossing_events (mouse_window, GDK_CROSSING_NORMAL, nsevent, *x, *y);