Commit | Line | Data |
---|---|---|
a09e091a JB |
1 | /* |
2 | * Darwin event queue and event handling | |
3 | * | |
4 | * Copyright 2007-2008 Apple Inc. | |
5 | * Copyright 2004 Kaleb S. KEITHLEY. All Rights Reserved. | |
6 | * Copyright (c) 2002-2004 Torrey T. Lyons. All Rights Reserved. | |
7 | * | |
8 | * This file is based on mieq.c by Keith Packard, | |
9 | * which contains the following copyright: | |
10 | * Copyright 1990, 1998 The Open Group | |
11 | * | |
12 | * | |
13 | * Copyright (c) 2002-2012 Apple Inc. All rights reserved. | |
14 | * | |
15 | * Permission is hereby granted, free of charge, to any person | |
16 | * obtaining a copy of this software and associated documentation files | |
17 | * (the "Software"), to deal in the Software without restriction, | |
18 | * including without limitation the rights to use, copy, modify, merge, | |
19 | * publish, distribute, sublicense, and/or sell copies of the Software, | |
20 | * and to permit persons to whom the Software is furnished to do so, | |
21 | * subject to the following conditions: | |
22 | * | |
23 | * The above copyright notice and this permission notice shall be | |
24 | * included in all copies or substantial portions of the Software. | |
25 | * | |
26 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | |
27 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | |
28 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | |
29 | * NONINFRINGEMENT. IN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT | |
30 | * HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, | |
31 | * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
32 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | |
33 | * DEALINGS IN THE SOFTWARE. | |
34 | * | |
35 | * Except as contained in this notice, the name(s) of the above | |
36 | * copyright holders shall not be used in advertising or otherwise to | |
37 | * promote the sale, use or other dealings in this Software without | |
38 | * prior written authorization. | |
39 | */ | |
40 | ||
41 | #include "sanitizedCarbon.h" | |
42 | ||
43 | #ifdef HAVE_DIX_CONFIG_H | |
44 | #include <dix-config.h> | |
45 | #endif | |
46 | ||
47 | #include <X11/X.h> | |
48 | #include <X11/Xmd.h> | |
49 | #include <X11/Xproto.h> | |
50 | #include "misc.h" | |
51 | #include "windowstr.h" | |
52 | #include "pixmapstr.h" | |
53 | #include "inputstr.h" | |
54 | #include "inpututils.h" | |
55 | #include "eventstr.h" | |
56 | #include "mi.h" | |
57 | #include "scrnintstr.h" | |
58 | #include "mipointer.h" | |
59 | #include "os.h" | |
60 | #include "exglobals.h" | |
61 | ||
62 | #include "darwin.h" | |
63 | #include "quartz.h" | |
64 | #include "quartzKeyboard.h" | |
65 | #include "quartzRandR.h" | |
66 | #include "darwinEvents.h" | |
67 | ||
68 | #include <sys/types.h> | |
69 | #include <sys/uio.h> | |
70 | #include <unistd.h> | |
71 | #include <pthread.h> | |
72 | #include <errno.h> | |
73 | #include <time.h> | |
74 | ||
75 | #include <IOKit/hidsystem/IOLLEvent.h> | |
76 | ||
77 | #include <X11/extensions/applewmconst.h> | |
78 | #include "applewmExt.h" | |
79 | ||
80 | /* FIXME: Abstract this better */ | |
81 | extern Bool | |
82 | QuartzModeEventHandler(int screenNum, XQuartzEvent *e, DeviceIntPtr dev); | |
83 | ||
84 | int darwin_all_modifier_flags = 0; // last known modifier state | |
85 | int darwin_all_modifier_mask = 0; | |
86 | int darwin_x11_modifier_mask = 0; | |
87 | ||
88 | #define FD_ADD_MAX 128 | |
89 | static int fd_add[FD_ADD_MAX]; | |
90 | int fd_add_count = 0; | |
91 | static pthread_mutex_t fd_add_lock = PTHREAD_MUTEX_INITIALIZER; | |
92 | static pthread_cond_t fd_add_ready_cond = PTHREAD_COND_INITIALIZER; | |
93 | static pthread_t fd_add_tid = NULL; | |
94 | ||
95 | static InternalEvent* darwinEvents = NULL; | |
96 | ||
97 | static pthread_mutex_t mieq_lock = PTHREAD_MUTEX_INITIALIZER; | |
98 | static pthread_cond_t mieq_ready_cond = PTHREAD_COND_INITIALIZER; | |
99 | ||
100 | /*** Pthread Magics ***/ | |
101 | static pthread_t | |
102 | create_thread(void *(*func)(void *), void *arg) | |
103 | { | |
104 | pthread_attr_t attr; | |
105 | pthread_t tid; | |
106 | ||
107 | pthread_attr_init(&attr); | |
108 | pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM); | |
109 | pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); | |
110 | pthread_create(&tid, &attr, func, arg); | |
111 | pthread_attr_destroy(&attr); | |
112 | ||
113 | return tid; | |
114 | } | |
115 | ||
116 | void | |
117 | darwinEvents_lock(void); | |
118 | void | |
119 | darwinEvents_lock(void) | |
120 | { | |
121 | int err; | |
122 | if ((err = pthread_mutex_lock(&mieq_lock))) { | |
123 | ErrorF("%s:%s:%d: Failed to lock mieq_lock: %d\n", | |
124 | __FILE__, __FUNCTION__, __LINE__, err); | |
125 | xorg_backtrace(); | |
126 | } | |
127 | if (darwinEvents == NULL) { | |
128 | pthread_cond_wait(&mieq_ready_cond, &mieq_lock); | |
129 | } | |
130 | } | |
131 | ||
132 | void | |
133 | darwinEvents_unlock(void); | |
134 | void | |
135 | darwinEvents_unlock(void) | |
136 | { | |
137 | int err; | |
138 | if ((err = pthread_mutex_unlock(&mieq_lock))) { | |
139 | ErrorF("%s:%s:%d: Failed to unlock mieq_lock: %d\n", | |
140 | __FILE__, __FUNCTION__, __LINE__, err); | |
141 | xorg_backtrace(); | |
142 | } | |
143 | } | |
144 | ||
145 | /* | |
146 | * DarwinPressModifierKey | |
147 | * Press or release the given modifier key (one of NX_MODIFIERKEY_* constants) | |
148 | */ | |
149 | static void | |
150 | DarwinPressModifierKey(int pressed, int key) | |
151 | { | |
152 | int keycode = DarwinModifierNXKeyToNXKeycode(key, 0); | |
153 | ||
154 | if (keycode == 0) { | |
155 | ErrorF("DarwinPressModifierKey bad keycode: key=%d\n", key); | |
156 | return; | |
157 | } | |
158 | ||
159 | DarwinSendKeyboardEvents(pressed, keycode); | |
160 | } | |
161 | ||
162 | /* | |
163 | * DarwinUpdateModifiers | |
164 | * Send events to update the modifier state. | |
165 | */ | |
166 | ||
167 | static int darwin_x11_modifier_mask_list[] = { | |
168 | #ifdef NX_DEVICELCMDKEYMASK | |
169 | NX_DEVICELCTLKEYMASK, NX_DEVICERCTLKEYMASK, | |
170 | NX_DEVICELSHIFTKEYMASK, NX_DEVICERSHIFTKEYMASK, | |
171 | NX_DEVICELCMDKEYMASK, NX_DEVICERCMDKEYMASK, | |
172 | NX_DEVICELALTKEYMASK, NX_DEVICERALTKEYMASK, | |
173 | #else | |
174 | NX_CONTROLMASK, NX_SHIFTMASK, NX_COMMANDMASK, | |
175 | NX_ALTERNATEMASK, | |
176 | #endif | |
177 | NX_ALPHASHIFTMASK, | |
178 | 0 | |
179 | }; | |
180 | ||
181 | static int darwin_all_modifier_mask_additions[] = { NX_SECONDARYFNMASK, }; | |
182 | ||
183 | static void | |
184 | DarwinUpdateModifiers(int pressed, // KeyPress or KeyRelease | |
185 | int flags) // modifier flags that have changed | |
186 | { | |
187 | int *f; | |
188 | int key; | |
189 | ||
190 | /* Capslock is special. This mask is the state of capslock (on/off), | |
191 | * not the state of the button. Hopefully we can find a better solution. | |
192 | */ | |
193 | if (NX_ALPHASHIFTMASK & flags) { | |
194 | DarwinPressModifierKey(KeyPress, NX_MODIFIERKEY_ALPHALOCK); | |
195 | DarwinPressModifierKey(KeyRelease, NX_MODIFIERKEY_ALPHALOCK); | |
196 | } | |
197 | ||
198 | for (f = darwin_x11_modifier_mask_list; *f; f++) | |
199 | if (*f & flags && *f != NX_ALPHASHIFTMASK) { | |
200 | key = DarwinModifierNXMaskToNXKey(*f); | |
201 | if (key == -1) | |
202 | ErrorF("DarwinUpdateModifiers: Unsupported NXMask: 0x%x\n", | |
203 | *f); | |
204 | else | |
205 | DarwinPressModifierKey(pressed, key); | |
206 | } | |
207 | } | |
208 | ||
209 | /* Generic handler for Xquartz-specifc events. When possible, these should | |
210 | be moved into their own individual functions and set as handlers using | |
211 | mieqSetHandler. */ | |
212 | ||
213 | static void | |
214 | DarwinEventHandler(int screenNum, InternalEvent *ie, DeviceIntPtr dev) | |
215 | { | |
216 | XQuartzEvent *e = &(ie->xquartz_event); | |
217 | ||
218 | switch (e->subtype) { | |
219 | case kXquartzControllerNotify: | |
220 | DEBUG_LOG("kXquartzControllerNotify\n"); | |
221 | AppleWMSendEvent(AppleWMControllerNotify, | |
222 | AppleWMControllerNotifyMask, | |
223 | e->data[0], | |
224 | e->data[1]); | |
225 | break; | |
226 | ||
227 | case kXquartzPasteboardNotify: | |
228 | DEBUG_LOG("kXquartzPasteboardNotify\n"); | |
229 | AppleWMSendEvent(AppleWMPasteboardNotify, | |
230 | AppleWMPasteboardNotifyMask, | |
231 | e->data[0], | |
232 | e->data[1]); | |
233 | break; | |
234 | ||
235 | case kXquartzActivate: | |
236 | DEBUG_LOG("kXquartzActivate\n"); | |
237 | QuartzShow(); | |
238 | AppleWMSendEvent(AppleWMActivationNotify, | |
239 | AppleWMActivationNotifyMask, | |
240 | AppleWMIsActive, 0); | |
241 | break; | |
242 | ||
243 | case kXquartzDeactivate: | |
244 | DEBUG_LOG("kXquartzDeactivate\n"); | |
245 | AppleWMSendEvent(AppleWMActivationNotify, | |
246 | AppleWMActivationNotifyMask, | |
247 | AppleWMIsInactive, 0); | |
248 | QuartzHide(); | |
249 | break; | |
250 | ||
251 | case kXquartzReloadPreferences: | |
252 | DEBUG_LOG("kXquartzReloadPreferences\n"); | |
253 | AppleWMSendEvent(AppleWMActivationNotify, | |
254 | AppleWMActivationNotifyMask, | |
255 | AppleWMReloadPreferences, 0); | |
256 | break; | |
257 | ||
258 | case kXquartzToggleFullscreen: | |
259 | DEBUG_LOG("kXquartzToggleFullscreen\n"); | |
260 | if (XQuartzIsRootless) | |
261 | ErrorF( | |
262 | "Ignoring kXquartzToggleFullscreen because of rootless mode."); | |
263 | else | |
264 | QuartzRandRToggleFullscreen(); | |
265 | break; | |
266 | ||
267 | case kXquartzSetRootless: | |
268 | DEBUG_LOG("kXquartzSetRootless\n"); | |
269 | if (e->data[0]) { | |
270 | QuartzRandRSetFakeRootless(); | |
271 | } | |
272 | else { | |
273 | QuartzRandRSetFakeFullscreen(FALSE); | |
274 | } | |
275 | break; | |
276 | ||
277 | case kXquartzSetRootClip: | |
278 | QuartzSetRootClip((Bool)e->data[0]); | |
279 | break; | |
280 | ||
281 | case kXquartzQuit: | |
282 | GiveUp(0); | |
283 | break; | |
284 | ||
285 | case kXquartzSpaceChanged: | |
286 | DEBUG_LOG("kXquartzSpaceChanged\n"); | |
287 | QuartzSpaceChanged(e->data[0]); | |
288 | break; | |
289 | ||
290 | case kXquartzListenOnOpenFD: | |
291 | ErrorF("Calling ListenOnOpenFD() for new fd: %d\n", (int)e->data[0]); | |
292 | ListenOnOpenFD((int)e->data[0], 1); | |
293 | break; | |
294 | ||
295 | case kXquartzReloadKeymap: | |
296 | DarwinKeyboardReloadHandler(); | |
297 | break; | |
298 | ||
299 | case kXquartzDisplayChanged: | |
300 | DEBUG_LOG("kXquartzDisplayChanged\n"); | |
301 | QuartzUpdateScreens(); | |
302 | ||
303 | /* Update our RandR info */ | |
304 | QuartzRandRUpdateFakeModes(TRUE); | |
305 | break; | |
306 | ||
307 | default: | |
308 | if (!QuartzModeEventHandler(screenNum, e, dev)) | |
309 | ErrorF("Unknown application defined event type %d.\n", e->subtype); | |
310 | } | |
311 | } | |
312 | ||
313 | void | |
314 | DarwinListenOnOpenFD(int fd) | |
315 | { | |
316 | ErrorF("DarwinListenOnOpenFD: %d\n", fd); | |
317 | ||
318 | pthread_mutex_lock(&fd_add_lock); | |
319 | if (fd_add_count < FD_ADD_MAX) | |
320 | fd_add[fd_add_count++] = fd; | |
321 | else | |
322 | ErrorF("FD Addition buffer at max. Dropping fd addition request.\n"); | |
323 | ||
324 | pthread_cond_broadcast(&fd_add_ready_cond); | |
325 | pthread_mutex_unlock(&fd_add_lock); | |
326 | } | |
327 | ||
328 | static void * | |
329 | DarwinProcessFDAdditionQueue_thread(void *args) | |
330 | { | |
331 | /* TODO: Possibly adjust this to no longer be a race... maybe trigger this | |
332 | * once a client connects and claims to be the WM. | |
333 | * | |
334 | * From ajax: | |
335 | * There's already an internal callback chain for setting selection [in 1.5] | |
336 | * ownership. See the CallSelectionCallback at the bottom of | |
337 | * ProcSetSelectionOwner, and xfixes/select.c for an example of how to hook | |
338 | * into it. | |
339 | */ | |
340 | ||
341 | struct timespec sleep_for; | |
342 | struct timespec sleep_remaining; | |
343 | ||
344 | sleep_for.tv_sec = 3; | |
345 | sleep_for.tv_nsec = 0; | |
346 | ||
347 | ErrorF( | |
348 | "X11.app: DarwinProcessFDAdditionQueue_thread: Sleeping to allow xinitrc to catchup.\n"); | |
349 | while (nanosleep(&sleep_for, &sleep_remaining) != 0) { | |
350 | sleep_for = sleep_remaining; | |
351 | } | |
352 | ||
353 | pthread_mutex_lock(&fd_add_lock); | |
354 | while (true) { | |
355 | while (fd_add_count) { | |
356 | DarwinSendDDXEvent(kXquartzListenOnOpenFD, 1, | |
357 | fd_add[--fd_add_count]); | |
358 | } | |
359 | pthread_cond_wait(&fd_add_ready_cond, &fd_add_lock); | |
360 | } | |
361 | ||
362 | return NULL; | |
363 | } | |
364 | ||
365 | Bool | |
366 | DarwinEQInit(void) | |
367 | { | |
368 | int *p; | |
369 | ||
370 | for (p = darwin_x11_modifier_mask_list, darwin_all_modifier_mask = 0; *p; | |
371 | p++) { | |
372 | darwin_x11_modifier_mask |= *p; | |
373 | } | |
374 | ||
375 | for (p = darwin_all_modifier_mask_additions, | |
376 | darwin_all_modifier_mask = darwin_x11_modifier_mask; | |
377 | *p; p++) { | |
378 | darwin_all_modifier_mask |= *p; | |
379 | } | |
380 | ||
381 | mieqInit(); | |
382 | mieqSetHandler(ET_XQuartz, DarwinEventHandler); | |
383 | ||
384 | /* Note that this *could* cause a potential async issue, since we're checking | |
385 | * darwinEvents without holding the lock, but darwinEvents is only ever set | |
386 | * here, so I don't bother. | |
387 | */ | |
388 | if (!darwinEvents) { | |
389 | darwinEvents = InitEventList(GetMaximumEventsNum()); | |
390 | ; | |
391 | ||
392 | if (!darwinEvents) | |
393 | FatalError("Couldn't allocate event buffer\n"); | |
394 | ||
395 | darwinEvents_lock(); | |
396 | pthread_cond_broadcast(&mieq_ready_cond); | |
397 | darwinEvents_unlock(); | |
398 | } | |
399 | ||
400 | if (!fd_add_tid) | |
401 | fd_add_tid = create_thread(DarwinProcessFDAdditionQueue_thread, NULL); | |
402 | ||
403 | return TRUE; | |
404 | } | |
405 | ||
406 | void | |
407 | DarwinEQFini(void) | |
408 | { | |
409 | mieqFini(); | |
410 | } | |
411 | ||
412 | /* | |
413 | * ProcessInputEvents | |
414 | * Read and process events from the event queue until it is empty. | |
415 | */ | |
416 | void | |
417 | ProcessInputEvents(void) | |
418 | { | |
419 | char nullbyte; | |
420 | int x = sizeof(nullbyte); | |
421 | ||
422 | mieqProcessInputEvents(); | |
423 | ||
424 | // Empty the signaling pipe | |
425 | while (x == sizeof(nullbyte)) { | |
426 | x = read(darwinEventReadFD, &nullbyte, sizeof(nullbyte)); | |
427 | } | |
428 | } | |
429 | ||
430 | /* Sends a null byte down darwinEventWriteFD, which will cause the | |
431 | Dispatch() event loop to check out event queue */ | |
432 | static void | |
433 | DarwinPokeEQ(void) | |
434 | { | |
435 | char nullbyte = 0; | |
436 | // <daniels> oh, i ... er ... christ. | |
437 | write(darwinEventWriteFD, &nullbyte, sizeof(nullbyte)); | |
438 | } | |
439 | ||
440 | void | |
441 | DarwinInputReleaseButtonsAndKeys(DeviceIntPtr pDev) | |
442 | { | |
443 | darwinEvents_lock(); | |
444 | { | |
445 | int i; | |
446 | if (pDev->button) { | |
447 | for (i = 0; i < pDev->button->numButtons; i++) { | |
448 | if (BitIsOn(pDev->button->down, i)) { | |
449 | QueuePointerEvents(pDev, ButtonRelease, i, | |
450 | POINTER_ABSOLUTE, | |
451 | NULL); | |
452 | } | |
453 | } | |
454 | } | |
455 | ||
456 | if (pDev->key) { | |
457 | for (i = 0; i < NUM_KEYCODES; i++) { | |
458 | if (BitIsOn(pDev->key->down, i + MIN_KEYCODE)) { | |
459 | QueueKeyboardEvents(pDev, KeyRelease, i + MIN_KEYCODE, | |
460 | NULL); | |
461 | } | |
462 | } | |
463 | } | |
464 | DarwinPokeEQ(); | |
465 | } darwinEvents_unlock(); | |
466 | } | |
467 | ||
468 | void | |
469 | DarwinSendTabletEvents(DeviceIntPtr pDev, int ev_type, int ev_button, | |
470 | double pointer_x, double pointer_y, | |
471 | double pressure, double tilt_x, | |
472 | double tilt_y) | |
473 | { | |
474 | ScreenPtr screen; | |
475 | ValuatorMask valuators; | |
476 | ||
477 | if (!darwinEvents) { | |
478 | DEBUG_LOG("%s called before darwinEvents was initialized\n", | |
479 | __FUNCTION__); | |
480 | return; | |
481 | } | |
482 | ||
483 | screen = miPointerGetScreen(pDev); | |
484 | if (!screen) { | |
485 | DEBUG_LOG("%s called before screen was initialized\n", | |
486 | __FUNCTION__); | |
487 | return; | |
488 | } | |
489 | ||
490 | /* Fix offset between darwin and X screens */ | |
491 | pointer_x -= darwinMainScreenX + screen->x; | |
492 | pointer_y -= darwinMainScreenY + screen->y; | |
493 | ||
494 | /* Adjust our pointer location to the [0,1] range */ | |
495 | pointer_x = pointer_x / (double)screenInfo.width; | |
496 | pointer_y = pointer_y / (double)screenInfo.height; | |
497 | ||
498 | valuator_mask_zero(&valuators); | |
499 | valuator_mask_set_double(&valuators, 0, XQUARTZ_VALUATOR_LIMIT * pointer_x); | |
500 | valuator_mask_set_double(&valuators, 1, XQUARTZ_VALUATOR_LIMIT * pointer_y); | |
501 | valuator_mask_set_double(&valuators, 2, XQUARTZ_VALUATOR_LIMIT * pressure); | |
502 | valuator_mask_set_double(&valuators, 3, XQUARTZ_VALUATOR_LIMIT * tilt_x); | |
503 | valuator_mask_set_double(&valuators, 4, XQUARTZ_VALUATOR_LIMIT * tilt_y); | |
504 | ||
505 | darwinEvents_lock(); | |
506 | { | |
507 | if (ev_type == ProximityIn || ev_type == ProximityOut) { | |
508 | QueueProximityEvents(pDev, ev_type, &valuators); | |
509 | } else { | |
510 | QueuePointerEvents(pDev, ev_type, ev_button, POINTER_ABSOLUTE, | |
511 | &valuators); | |
512 | } | |
513 | DarwinPokeEQ(); | |
514 | } darwinEvents_unlock(); | |
515 | } | |
516 | ||
517 | void | |
518 | DarwinSendPointerEvents(DeviceIntPtr pDev, int ev_type, int ev_button, | |
519 | double pointer_x, double pointer_y, | |
520 | double pointer_dx, double pointer_dy) | |
521 | { | |
522 | static int darwinFakeMouseButtonDown = 0; | |
523 | ScreenPtr screen; | |
524 | ValuatorMask valuators; | |
525 | ||
526 | if (!darwinEvents) { | |
527 | DEBUG_LOG("%s called before darwinEvents was initialized\n", | |
528 | __FUNCTION__); | |
529 | return; | |
530 | } | |
531 | ||
532 | screen = miPointerGetScreen(pDev); | |
533 | if (!screen) { | |
534 | DEBUG_LOG("%s called before screen was initialized\n", | |
535 | __FUNCTION__); | |
536 | return; | |
537 | } | |
538 | ||
539 | /* Handle fake click */ | |
540 | if (ev_type == ButtonPress && darwinFakeButtons && ev_button == 1) { | |
541 | if (darwinFakeMouseButtonDown != 0) { | |
542 | /* We're currently "down" with another button, so release it first */ | |
543 | DarwinSendPointerEvents(pDev, ButtonRelease, | |
544 | darwinFakeMouseButtonDown, | |
545 | pointer_x, pointer_y, 0.0, 0.0); | |
546 | darwinFakeMouseButtonDown = 0; | |
547 | } | |
548 | if (darwin_all_modifier_flags & darwinFakeMouse2Mask) { | |
549 | ev_button = 2; | |
550 | darwinFakeMouseButtonDown = 2; | |
551 | DarwinUpdateModKeys( | |
552 | darwin_all_modifier_flags & ~darwinFakeMouse2Mask); | |
553 | } | |
554 | else if (darwin_all_modifier_flags & darwinFakeMouse3Mask) { | |
555 | ev_button = 3; | |
556 | darwinFakeMouseButtonDown = 3; | |
557 | DarwinUpdateModKeys( | |
558 | darwin_all_modifier_flags & ~darwinFakeMouse3Mask); | |
559 | } | |
560 | } | |
561 | ||
562 | if (ev_type == ButtonRelease && ev_button == 1) { | |
563 | if (darwinFakeMouseButtonDown) { | |
564 | ev_button = darwinFakeMouseButtonDown; | |
565 | } | |
566 | ||
567 | if (darwinFakeMouseButtonDown == 2) { | |
568 | DarwinUpdateModKeys( | |
569 | darwin_all_modifier_flags & ~darwinFakeMouse2Mask); | |
570 | } | |
571 | else if (darwinFakeMouseButtonDown == 3) { | |
572 | DarwinUpdateModKeys( | |
573 | darwin_all_modifier_flags & ~darwinFakeMouse3Mask); | |
574 | } | |
575 | ||
576 | darwinFakeMouseButtonDown = 0; | |
577 | } | |
578 | ||
579 | /* Fix offset between darwin and X screens */ | |
580 | pointer_x -= darwinMainScreenX + screen->x; | |
581 | pointer_y -= darwinMainScreenY + screen->y; | |
582 | ||
583 | valuator_mask_zero(&valuators); | |
584 | valuator_mask_set_double(&valuators, 0, pointer_x); | |
585 | valuator_mask_set_double(&valuators, 1, pointer_y); | |
586 | ||
587 | if (ev_type == MotionNotify) { | |
588 | if (pointer_dx != 0.0) | |
589 | valuator_mask_set_double(&valuators, 2, pointer_dx); | |
590 | if (pointer_dy != 0.0) | |
591 | valuator_mask_set_double(&valuators, 3, pointer_dy); | |
592 | } | |
593 | ||
594 | darwinEvents_lock(); | |
595 | { | |
596 | QueuePointerEvents(pDev, ev_type, ev_button, POINTER_ABSOLUTE, | |
597 | &valuators); | |
598 | DarwinPokeEQ(); | |
599 | } darwinEvents_unlock(); | |
600 | } | |
601 | ||
602 | void | |
603 | DarwinSendKeyboardEvents(int ev_type, int keycode) | |
604 | { | |
605 | ||
606 | if (!darwinEvents) { | |
607 | DEBUG_LOG( | |
608 | "DarwinSendKeyboardEvents called before darwinEvents was initialized\n"); | |
609 | return; | |
610 | } | |
611 | ||
612 | darwinEvents_lock(); | |
613 | { | |
614 | QueueKeyboardEvents(darwinKeyboard, ev_type, keycode + MIN_KEYCODE, | |
615 | NULL); | |
616 | DarwinPokeEQ(); | |
617 | } darwinEvents_unlock(); | |
618 | } | |
619 | ||
620 | /* Send the appropriate number of button clicks to emulate scroll wheel */ | |
621 | void | |
622 | DarwinSendScrollEvents(double scroll_x, double scroll_y) { | |
623 | ScreenPtr screen; | |
624 | ValuatorMask valuators; | |
625 | ||
626 | if (!darwinEvents) { | |
627 | DEBUG_LOG( | |
628 | "DarwinSendScrollEvents called before darwinEvents was initialized\n"); | |
629 | return; | |
630 | } | |
631 | ||
632 | screen = miPointerGetScreen(darwinPointer); | |
633 | if (!screen) { | |
634 | DEBUG_LOG( | |
635 | "DarwinSendScrollEvents called before screen was initialized\n"); | |
636 | return; | |
637 | } | |
638 | ||
639 | valuator_mask_zero(&valuators); | |
640 | valuator_mask_set_double(&valuators, 4, scroll_y); | |
641 | valuator_mask_set_double(&valuators, 5, scroll_x); | |
642 | ||
643 | darwinEvents_lock(); | |
644 | { | |
645 | QueuePointerEvents(darwinPointer, MotionNotify, 0, | |
646 | POINTER_RELATIVE, &valuators); | |
647 | DarwinPokeEQ(); | |
648 | } darwinEvents_unlock(); | |
649 | } | |
650 | ||
651 | /* Send the appropriate KeyPress/KeyRelease events to GetKeyboardEvents to | |
652 | reflect changing modifier flags (alt, control, meta, etc) */ | |
653 | void | |
654 | DarwinUpdateModKeys(int flags) | |
655 | { | |
656 | DarwinUpdateModifiers( | |
657 | KeyRelease, darwin_all_modifier_flags & ~flags & | |
658 | darwin_x11_modifier_mask); | |
659 | DarwinUpdateModifiers( | |
660 | KeyPress, ~darwin_all_modifier_flags & flags & | |
661 | darwin_x11_modifier_mask); | |
662 | darwin_all_modifier_flags = flags; | |
663 | } | |
664 | ||
665 | /* | |
666 | * DarwinSendDDXEvent | |
667 | * Send the X server thread a message by placing it on the event queue. | |
668 | */ | |
669 | void | |
670 | DarwinSendDDXEvent(int type, int argc, ...) | |
671 | { | |
672 | XQuartzEvent e; | |
673 | int i; | |
674 | va_list args; | |
675 | ||
676 | memset(&e, 0, sizeof(e)); | |
677 | e.header = ET_Internal; | |
678 | e.type = ET_XQuartz; | |
679 | e.length = sizeof(e); | |
680 | e.time = GetTimeInMillis(); | |
681 | e.subtype = type; | |
682 | ||
683 | if (argc > 0 && argc < XQUARTZ_EVENT_MAXARGS) { | |
684 | va_start(args, argc); | |
685 | for (i = 0; i < argc; i++) | |
686 | e.data[i] = (uint32_t)va_arg(args, uint32_t); | |
687 | va_end(args); | |
688 | } | |
689 | ||
690 | darwinEvents_lock(); | |
691 | { | |
692 | mieqEnqueue(NULL, (InternalEvent *)&e); | |
693 | DarwinPokeEQ(); | |
694 | } darwinEvents_unlock(); | |
695 | } |