From 7524dbd06113ec081eaa882aa54e03553ccf96aa Mon Sep 17 00:00:00 2001 From: Jeremy Huddleston Date: Thu, 21 Apr 2011 15:11:52 -0700 Subject: [PATCH 1/6] XQuartz: Make the DarwinProcessFDAdditionQueue_thread wait 3 seconds to allow xinitrc to catch up Previously, we weren't always waiting the full three seconds. This should be better, but is still sub-optimal. We really want to start processing these once a WM has been started. http://xquartz.macosforge.org/trac/ticket/416 Signed-off-by: Jeremy Huddleston --- hw/xquartz/darwinEvents.c | 22 ++++++++++++++++++++++ hw/xquartz/mach-startup/bundle-main.c | 17 +---------------- 2 files changed, 23 insertions(+), 16 deletions(-) diff --git a/hw/xquartz/darwinEvents.c b/hw/xquartz/darwinEvents.c index 16fec4a01..0853b7199 100644 --- a/hw/xquartz/darwinEvents.c +++ b/hw/xquartz/darwinEvents.c @@ -61,6 +61,7 @@ in this Software without prior written authorization from The Open Group. #include #include #include +#include #include @@ -305,6 +306,27 @@ void DarwinListenOnOpenFD(int fd) { } static void DarwinProcessFDAdditionQueue_thread(void *args) { + /* TODO: Possibly adjust this to no longer be a race... maybe trigger this + * once a client connects and claims to be the WM. + * + * From ajax: + * There's already an internal callback chain for setting selection [in 1.5] + * ownership. See the CallSelectionCallback at the bottom of + * ProcSetSelectionOwner, and xfixes/select.c for an example of how to hook + * into it. + */ + + struct timespec sleep_for; + struct timespec sleep_remaining; + + sleep_for.tv_sec = 3; + sleep_for.tv_nsec = 0; + + ErrorF("X11.app: DarwinProcessFDAdditionQueue_thread: Sleeping to allow xinitrc to catchup.\n"); + while(nanosleep(&sleep_for, &sleep_remaining) != 0) { + sleep_for = sleep_remaining; + } + pthread_mutex_lock(&fd_add_lock); while(true) { while(fd_add_count) { diff --git a/hw/xquartz/mach-startup/bundle-main.c b/hw/xquartz/mach-startup/bundle-main.c index 75b39392a..4c79cfb42 100644 --- a/hw/xquartz/mach-startup/bundle-main.c +++ b/hw/xquartz/mach-startup/bundle-main.c @@ -47,7 +47,6 @@ #include #include -#include #include #include @@ -204,7 +203,6 @@ static void socket_handoff_thread(void *arg) { socket_handoff_t *handoff_data = (socket_handoff_t *)arg; int launchd_fd = -1; int connected_fd; - unsigned remain; /* Now actually get the passed file descriptor from this connection * If we encounter an error, keep listening. @@ -227,20 +225,7 @@ static void socket_handoff_thread(void *arg) { close(handoff_data->fd); unlink(handoff_data->filename); free(handoff_data); - - /* TODO: Clean up this race better... giving xinitrc time to run... need to wait for 1.5 branch: - * - * From ajax: - * There's already an internal callback chain for setting selection [in 1.5] - * ownership. See the CallSelectionCallback at the bottom of - * ProcSetSelectionOwner, and xfixes/select.c for an example of how to hook - * into it. - */ - - remain = 3000000; - fprintf(stderr, "X11.app: Received new $DISPLAY fd: %d ... sleeping to allow xinitrc to catchup.\n", launchd_fd); - while((remain = usleep(remain)) > 0); - + fprintf(stderr, "X11.app Handing off fd to server thread via DarwinListenOnOpenFD(%d)\n", launchd_fd); DarwinListenOnOpenFD(launchd_fd); } From 3960115dbc83ec1eb8d9c8e90466af3fa0b32abd Mon Sep 17 00:00:00 2001 From: Jeremy Huddleston Date: Thu, 21 Apr 2011 15:19:12 -0700 Subject: [PATCH 2/6] XQuartz: Fix prototypes for thread functions Signed-off-by: Jeremy Huddleston --- hw/xquartz/X11Application.m | 2 +- hw/xquartz/darwinEvents.c | 6 ++++-- hw/xquartz/mach-startup/bundle-main.c | 6 ++++-- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/hw/xquartz/X11Application.m b/hw/xquartz/X11Application.m index 3521517a2..988a86bae 100644 --- a/hw/xquartz/X11Application.m +++ b/hw/xquartz/X11Application.m @@ -950,7 +950,7 @@ environment the next time you start X11?", @"Startup xinitrc dialog"); [X11App prefs_synchronize]; } -static inline pthread_t create_thread(void *func, void *arg) { +static inline pthread_t create_thread(void *(*func)(void *), void *arg) { pthread_attr_t attr; pthread_t tid; diff --git a/hw/xquartz/darwinEvents.c b/hw/xquartz/darwinEvents.c index 0853b7199..edf60c89c 100644 --- a/hw/xquartz/darwinEvents.c +++ b/hw/xquartz/darwinEvents.c @@ -94,7 +94,7 @@ static pthread_mutex_t mieq_lock = PTHREAD_MUTEX_INITIALIZER; static pthread_cond_t mieq_ready_cond = PTHREAD_COND_INITIALIZER; /*** Pthread Magics ***/ -static pthread_t create_thread(void *func, void *arg) { +static pthread_t create_thread(void *(*func)(void *), void *arg) { pthread_attr_t attr; pthread_t tid; @@ -305,7 +305,7 @@ void DarwinListenOnOpenFD(int fd) { pthread_mutex_unlock(&fd_add_lock); } -static void DarwinProcessFDAdditionQueue_thread(void *args) { +static void *DarwinProcessFDAdditionQueue_thread(void *args) { /* TODO: Possibly adjust this to no longer be a race... maybe trigger this * once a client connects and claims to be the WM. * @@ -334,6 +334,8 @@ static void DarwinProcessFDAdditionQueue_thread(void *args) { } pthread_cond_wait(&fd_add_ready_cond, &fd_add_lock); } + + return NULL; } Bool DarwinEQInit(void) { diff --git a/hw/xquartz/mach-startup/bundle-main.c b/hw/xquartz/mach-startup/bundle-main.c index 4c79cfb42..d55d1edc7 100644 --- a/hw/xquartz/mach-startup/bundle-main.c +++ b/hw/xquartz/mach-startup/bundle-main.c @@ -95,7 +95,7 @@ static int execute(const char *command); static char *command_from_prefs(const char *key, const char *default_value); /*** Pthread Magics ***/ -static pthread_t create_thread(void *func, void *arg) { +static pthread_t create_thread(void *(*func)(void *), void *arg) { pthread_attr_t attr; pthread_t tid; @@ -199,7 +199,7 @@ typedef struct { /* This thread accepts an incoming connection and hands off the file * descriptor for the new connection to accept_fd_handoff() */ -static void socket_handoff_thread(void *arg) { +static void *socket_handoff_thread(void *arg) { socket_handoff_t *handoff_data = (socket_handoff_t *)arg; int launchd_fd = -1; int connected_fd; @@ -228,6 +228,8 @@ static void socket_handoff_thread(void *arg) { fprintf(stderr, "X11.app Handing off fd to server thread via DarwinListenOnOpenFD(%d)\n", launchd_fd); DarwinListenOnOpenFD(launchd_fd); + + return NULL; } static int create_socket(char *filename_out) { From ca7b9e6c817681b9cec738e43cf020ac19b5e732 Mon Sep 17 00:00:00 2001 From: Jeremy Huddleston Date: Thu, 21 Apr 2011 15:51:32 -0700 Subject: [PATCH 3/6] configure.ac: Add check for libdispatch when building for darwin Signed-off-by: Jeremy Huddleston --- configure.ac | 10 +++++++--- include/dix-config.h.in | 3 +++ 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/configure.ac b/configure.ac index 9e04ff015..887dae571 100644 --- a/configure.ac +++ b/configure.ac @@ -726,9 +726,9 @@ case $host_os in save_LDFLAGS=$LDFLAGS LDFLAGS="$LDFLAGS -framework Carbon" AC_LINK_IFELSE([char FSFindFolder(); int main() { FSFindFolder(); return 0;}], - [xorg_cv_Carbon_framework=yes], - [xorg_cv_Carbon_framework=no]) - LDFLAGS=$save_LDFLAGS]) + [xorg_cv_Carbon_framework=yes], + [xorg_cv_Carbon_framework=no]) + LDFLAGS=$save_LDFLAGS]) if test "X$xorg_cv_Carbon_framework" = Xyes; then XQUARTZ=yes @@ -737,6 +737,10 @@ case $host_os in fi fi + AC_CHECK_FUNC(dispatch_async, + AC_DEFINE([HAVE_LIBDISPATCH], 1, [Define to 1 if you have the libdispatch (GCD) available]), + []) + if test "x$XQUARTZ" = xyes ; then XQUARTZ=yes XVFB=no diff --git a/include/dix-config.h.in b/include/dix-config.h.in index fd9ecced2..14229b435 100644 --- a/include/dix-config.h.in +++ b/include/dix-config.h.in @@ -136,6 +136,9 @@ /* Define to 1 if you have the `m' library (-lm). */ #undef HAVE_LIBM +/* Define to 1 if you have the libdispatch (GCD) available */ +#undef HAVE_LIBDISPATCH + /* Define to 1 if you have the `link' function. */ #undef HAVE_LINK From 034538ea9b4770025e3573bc708039cabbe1e10d Mon Sep 17 00:00:00 2001 From: Jeremy Huddleston Date: Thu, 21 Apr 2011 16:31:58 -0700 Subject: [PATCH 4/6] XQuartz: Use dispatch_async to handoff the FD Signed-off-by: Jeremy Huddleston --- hw/xquartz/mach-startup/bundle-main.c | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/hw/xquartz/mach-startup/bundle-main.c b/hw/xquartz/mach-startup/bundle-main.c index d55d1edc7..6a6c01c3b 100644 --- a/hw/xquartz/mach-startup/bundle-main.c +++ b/hw/xquartz/mach-startup/bundle-main.c @@ -40,10 +40,15 @@ #include #include #include -#include #include #include +#ifdef HAVE_LIBDISPATCH +#include +#else +#include +#endif + #include #include @@ -94,6 +99,7 @@ int server_main(int argc, char **argv, char **envp); static int execute(const char *command); static char *command_from_prefs(const char *key, const char *default_value); +#ifndef HAVE_LIBDISPATCH /*** Pthread Magics ***/ static pthread_t create_thread(void *(*func)(void *), void *arg) { pthread_attr_t attr; @@ -107,6 +113,7 @@ static pthread_t create_thread(void *(*func)(void *), void *arg) { return tid; } +#endif /*** Mach-O IPC Stuffs ***/ @@ -199,8 +206,13 @@ typedef struct { /* This thread accepts an incoming connection and hands off the file * descriptor for the new connection to accept_fd_handoff() */ +#ifdef HAVE_LIBDISPATCH +static void socket_handoff(socket_handoff_t *handoff_data) { +#else static void *socket_handoff_thread(void *arg) { socket_handoff_t *handoff_data = (socket_handoff_t *)arg; +#endif + int launchd_fd = -1; int connected_fd; @@ -229,7 +241,9 @@ static void *socket_handoff_thread(void *arg) { fprintf(stderr, "X11.app Handing off fd to server thread via DarwinListenOnOpenFD(%d)\n", launchd_fd); DarwinListenOnOpenFD(launchd_fd); +#ifndef HAVE_LIBDISPATCH return NULL; +#endif } static int create_socket(char *filename_out) { @@ -298,8 +312,14 @@ kern_return_t do_request_fd_handoff_socket(mach_port_t port, string_t filename) } strlcpy(filename, handoff_data->filename, STRING_T_SIZE); - + +#ifdef HAVE_LIBDISPATCH + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0), ^{ + socket_handoff(handoff_data); + }); +#else create_thread(socket_handoff_thread, handoff_data); +#endif #ifdef DEBUG fprintf(stderr, "X11.app: Thread created for handoff. Returning success to tell caller to connect and push the fd.\n"); From 72bd232b117b2867282e0ae1855d779e126f912b Mon Sep 17 00:00:00 2001 From: Jeremy Huddleston Date: Fri, 22 Apr 2011 00:39:12 -0700 Subject: [PATCH 5/6] XQuartz: Send tablet proximity events with tilt and pressure Signed-off-by: Jeremy Huddleston --- hw/xquartz/X11Application.m | 55 ++++++++++++++++++++++++++----------- hw/xquartz/darwin.c | 3 -- hw/xquartz/darwin.h | 1 - hw/xquartz/darwinEvents.c | 20 +++++++------- hw/xquartz/darwinEvents.h | 3 +- 5 files changed, 51 insertions(+), 31 deletions(-) diff --git a/hw/xquartz/X11Application.m b/hw/xquartz/X11Application.m index 988a86bae..1e3643670 100644 --- a/hw/xquartz/X11Application.m +++ b/hw/xquartz/X11Application.m @@ -1079,13 +1079,29 @@ static const char *untrusted_str(NSEvent *e) { #endif - (void) sendX11NSEvent:(NSEvent *)e { - NSPoint location = NSZeroPoint, tilt = NSZeroPoint; + NSPoint location = NSZeroPoint; int ev_button, ev_type; - float pressure = 0.0; + static float pressure = 0.0; // static so ProximityOut will have the value from the previous tablet event + static NSPoint tilt; // static so ProximityOut will have the value from the previous tablet event + static DeviceIntPtr darwinTabletCurrent = NULL; + static BOOL needsProximityIn = NO; // Do we do need to handle a pending ProximityIn once we have pressure/tilt? DeviceIntPtr pDev; int modifierFlags; BOOL isMouseOrTabletEvent, isTabletEvent; +#ifdef HAVE_LIBDISPATCH + static dispatch_once_t once_pred; + dispatch_once(&once_pred, ^{ + tilt = NSZeroPoint; + darwinTabletCurrent = darwinTabletStylus; + }); +#else + if(!darwinTabletCurrent) { + tilt = NSZeroPoint; + darwinTabletCurrent = darwinTabletStylus; + } +#endif + isMouseOrTabletEvent = [e type] == NSLeftMouseDown || [e type] == NSOtherMouseDown || [e type] == NSRightMouseDown || [e type] == NSLeftMouseUp || [e type] == NSOtherMouseUp || [e type] == NSRightMouseUp || [e type] == NSLeftMouseDragged || [e type] == NSOtherMouseDragged || [e type] == NSRightMouseDragged || @@ -1207,19 +1223,14 @@ static const char *untrusted_str(NSEvent *e) { darwinTabletCurrent=darwinTabletCursor; break; } - - /* NSTabletProximityEventSubtype doesn't encode pressure ant tilt - * So we just pretend the motion was caused by the mouse. Hopefully - * we'll have a better solution for this in the future (like maybe - * NSTabletProximityEventSubtype will come from NSTabletPoint - * rather than NSMouseMoved. - pressure = [e pressure]; - tilt = [e tilt]; - pDev = darwinTabletCurrent; - */ - DarwinSendProximityEvents([e isEnteringProximity] ? ProximityIn : ProximityOut, - location.x, location.y); + if([e isEnteringProximity]) + needsProximityIn = YES; + else + DarwinSendProximityEvents(darwinTabletCurrent, ProximityOut, + location.x, location.y, pressure, + tilt.x, tilt.y); + return; } if ([e type] == NSTabletPoint || [e subtype] == NSTabletPointEventSubtype) { @@ -1227,6 +1238,14 @@ static const char *untrusted_str(NSEvent *e) { tilt = [e tilt]; pDev = darwinTabletCurrent; + + if(needsProximityIn) { + DarwinSendProximityEvents(darwinTabletCurrent, ProximityIn, + location.x, location.y, pressure, + tilt.x, tilt.y); + + needsProximityIn = NO; + } } if(!XQuartzServerVisible && noTestExtensions) { @@ -1280,8 +1299,12 @@ static const char *untrusted_str(NSEvent *e) { break; } - DarwinSendProximityEvents([e isEnteringProximity] ? ProximityIn : ProximityOut, - location.x, location.y); + if([e isEnteringProximity]) + needsProximityIn = YES; + else + DarwinSendProximityEvents(darwinTabletCurrent, ProximityOut, + location.x, location.y, pressure, + tilt.x, tilt.y); break; case NSScrollWheel: diff --git a/hw/xquartz/darwin.c b/hw/xquartz/darwin.c index 3b6f0a29e..00be74ba0 100644 --- a/hw/xquartz/darwin.c +++ b/hw/xquartz/darwin.c @@ -117,7 +117,6 @@ unsigned int windowItemModMask = NX_COMMANDMASK; // devices DeviceIntPtr darwinKeyboard = NULL; DeviceIntPtr darwinPointer = NULL; -DeviceIntPtr darwinTabletCurrent = NULL; DeviceIntPtr darwinTabletStylus = NULL; DeviceIntPtr darwinTabletCursor = NULL; DeviceIntPtr darwinTabletEraser = NULL; @@ -492,8 +491,6 @@ void InitInput( int argc, char **argv ) darwinTabletEraser = AddInputDevice(serverClient, DarwinTabletProc, TRUE); darwinTabletEraser->name = strdup("eraser"); - darwinTabletCurrent = darwinTabletStylus; - DarwinEQInit(); QuartzInitInput(argc, argv); diff --git a/hw/xquartz/darwin.h b/hw/xquartz/darwin.h index e874af24c..360225742 100644 --- a/hw/xquartz/darwin.h +++ b/hw/xquartz/darwin.h @@ -56,7 +56,6 @@ extern io_connect_t darwinParamConnect; extern int darwinEventReadFD; extern int darwinEventWriteFD; extern DeviceIntPtr darwinPointer; -extern DeviceIntPtr darwinTabletCurrent; extern DeviceIntPtr darwinTabletCursor; extern DeviceIntPtr darwinTabletStylus; extern DeviceIntPtr darwinTabletEraser; diff --git a/hw/xquartz/darwinEvents.c b/hw/xquartz/darwinEvents.c index edf60c89c..dc0b84270 100644 --- a/hw/xquartz/darwinEvents.c +++ b/hw/xquartz/darwinEvents.c @@ -489,7 +489,7 @@ void DarwinSendPointerEvents(DeviceIntPtr pDev, int ev_type, int ev_button, floa DarwinPrepareValuators(pDev, valuators, screen, pointer_x, pointer_y, pressure, tilt_x, tilt_y); darwinEvents_lock(); { ValuatorMask mask; - valuator_mask_set_range(&mask, 0, (pDev == darwinTabletCurrent) ? 5 : 2, valuators); + valuator_mask_set_range(&mask, 0, (pDev == darwinPointer) ? 2 : 5, valuators); num_events = GetPointerEvents(darwinEvents, pDev, ev_type, ev_button, POINTER_ABSOLUTE, &mask); for(i=0; i Date: Fri, 22 Apr 2011 01:23:09 -0700 Subject: [PATCH 6/6] XQuartz: Do translation and handoff of NSEvent to X11 in a separate serial queue Signed-off-by: Jeremy Huddleston --- hw/xquartz/X11Application.m | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/hw/xquartz/X11Application.m b/hw/xquartz/X11Application.m index 1e3643670..e56bf0cf3 100644 --- a/hw/xquartz/X11Application.m +++ b/hw/xquartz/X11Application.m @@ -61,6 +61,12 @@ extern int xpbproxy_run (void); #define XSERVER_VERSION "?" #endif +#ifdef HAVE_LIBDISPATCH +#include + +static dispatch_queue_t eventTranslationQueue; +#endif + /* Stuck modifier / button state... force release when we context switch */ static NSEventType keyState[NUM_KEYCODES]; @@ -385,7 +391,15 @@ static void message_kit_thread (SEL selector, NSObject *arg) { if (for_appkit) [super sendEvent:e]; - if (for_x) [self sendX11NSEvent:e]; + if (for_x) { +#ifdef HAVE_LIBDISPATCH + dispatch_async(eventTranslationQueue, ^{ +#endif + [self sendX11NSEvent:e]; +#ifdef HAVE_LIBDISPATCH + }); +#endif + } } - (void) set_window_menu:(NSArray *)list { @@ -999,6 +1013,11 @@ void X11ApplicationMain (int argc, char **argv, char **envp) { aquaMenuBarHeight = NSHeight([[NSScreen mainScreen] frame]) - NSMaxY([[NSScreen mainScreen] visibleFrame]); +#ifdef HAVE_LIBDISPATCH + eventTranslationQueue = dispatch_queue_create(LAUNCHD_ID_PREFIX".X11.NSEventsToX11EventsQueue", NULL); + assert(eventTranslationQueue != NULL); +#endif + /* Set the key layout seed before we start the server */ #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1050 last_key_layout = TISCopyCurrentKeyboardLayoutInputSource();