diff options
Diffstat (limited to 'hw')
-rw-r--r-- | hw/xquartz/Makefile.am | 6 | ||||
-rw-r--r-- | hw/xquartz/X11Application.h | 3 | ||||
-rw-r--r-- | hw/xquartz/applewmExt.h | 6 | ||||
-rw-r--r-- | hw/xquartz/console_redirect.c | 418 | ||||
-rw-r--r-- | hw/xquartz/console_redirect.h | 44 | ||||
-rw-r--r-- | hw/xquartz/mach-startup/Makefile.am | 1 | ||||
-rw-r--r-- | hw/xquartz/mach-startup/bundle-main.c | 56 | ||||
-rw-r--r-- | hw/xquartz/mach-startup/launchd_fd.c | 18 | ||||
-rw-r--r-- | hw/xquartz/mach-startup/stub.c | 69 | ||||
-rw-r--r-- | hw/xquartz/man/Xquartz.man | 63 | ||||
-rw-r--r-- | hw/xquartz/quartzKeyboard.c | 6 | ||||
-rw-r--r-- | hw/xquartz/sanitizedCocoa.h | 39 | ||||
-rw-r--r-- | hw/xquartz/xpr/xprFrame.c | 20 |
13 files changed, 660 insertions, 89 deletions
diff --git a/hw/xquartz/Makefile.am b/hw/xquartz/Makefile.am index 76f624d78..a7cc012d9 100644 --- a/hw/xquartz/Makefile.am +++ b/hw/xquartz/Makefile.am @@ -33,7 +33,8 @@ libXquartz_la_SOURCES = \ quartzCocoa.m \ quartzKeyboard.c \ quartzStartup.c \ - quartzRandR.c + quartzRandR.c \ + console_redirect.c EXTRA_DIST = \ X11Application.h \ @@ -49,4 +50,5 @@ EXTRA_DIST = \ quartzKeyboard.h \ quartzRandR.h \ sanitizedCarbon.h \ - sanitizedCocoa.h + sanitizedCocoa.h \ + console_redirect.h diff --git a/hw/xquartz/X11Application.h b/hw/xquartz/X11Application.h index 256ff187a..619f32f7a 100644 --- a/hw/xquartz/X11Application.h +++ b/hw/xquartz/X11Application.h @@ -43,11 +43,12 @@ - (void) set_controller:controller; - (void) set_window_menu:(NSArray *)list; +- (CFPropertyListRef) prefs_get_copy:(NSString *)key CF_RETURNS_RETAINED; - (int) prefs_get_integer:(NSString *)key default:(int)def; - (const char *) prefs_get_string:(NSString *)key default:(const char *)def; - (float) prefs_get_float:(NSString *)key default:(float)def; - (int) prefs_get_boolean:(NSString *)key default:(int)def; -- (NSURL *) prefs_copy_url:(NSString *)key default:(NSURL *)def; +- (NSURL *) prefs_copy_url:(NSString *)key default:(NSURL *)def NS_RETURNS_RETAINED; - (NSArray *) prefs_get_array:(NSString *)key; - (void) prefs_set_integer:(NSString *)key value:(int)value; - (void) prefs_set_float:(NSString *)key value:(float)value; diff --git a/hw/xquartz/applewmExt.h b/hw/xquartz/applewmExt.h index 35c8f8f6d..c46a7bde4 100644 --- a/hw/xquartz/applewmExt.h +++ b/hw/xquartz/applewmExt.h @@ -35,9 +35,9 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include <Xplugin.h> #if XPLUGIN_VERSION < 4 -typedef xp_frame_attr int; -typedef xp_frame_class int; -typedef xp_frame_rect int; +typedef int xp_frame_attr; +typedef int xp_frame_class; +typedef int xp_frame_rect; #endif typedef int (*DisableUpdateProc)(void); diff --git a/hw/xquartz/console_redirect.c b/hw/xquartz/console_redirect.c new file mode 100644 index 000000000..cdd2b8960 --- /dev/null +++ b/hw/xquartz/console_redirect.c @@ -0,0 +1,418 @@ +/* Copyright (c) 2011 Apple Inc. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT + * HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Except as contained in this notice, the name(s) of the above + * copyright holders shall not be used in advertising or otherwise to + * promote the sale, use or other dealings in this Software without + * prior written authorization. + */ + +#ifdef HAVE_DIX_CONFIG_H +#include <dix-config.h> +#else +#define DEBUG_CONSOLE_REDIRECT 1 +#define HAVE_LIBDISPATCH 1 +#endif + +#include <assert.h> +#include <unistd.h> +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <sys/types.h> +#include <sys/event.h> +#include <asl.h> +#include <errno.h> +#include <fcntl.h> + +#include "console_redirect.h" + +#define BUF_SIZE 512 + +#ifdef HAVE_LIBDISPATCH +#include <dispatch/dispatch.h> + +static dispatch_queue_t redirect_serial_q; +static dispatch_group_t read_source_group; +#else +#include <pthread.h> + +static pthread_t redirect_pthread; +static pthread_mutex_t redirect_fds_lock = PTHREAD_MUTEX_INITIALIZER; + +static int kq; + +/* Notifications to our reader thread */ +#define ASL_REDIRECT_TERMINATE ((void *)(uintptr_t)1) +#endif + +typedef struct { + int level; + aslclient asl; + aslmsg msg; + + /* Buffered reading */ + char *buf; + char *w; + +#ifdef HAVE_LIBDISPATCH + dispatch_source_t read_source; +#endif +} asl_redirect; + +static asl_redirect *redirect_fds = NULL; +static int n_redirect_fds = 0; + +/* Read from the FD until there is no more to read and redirect to ASL. + * Preconditions: + * 1: pthread_mutex_lock lock is held (pthreads) or called + * from the appropriate serial queue for operating on + * redirect_fds + * 2: fd corresponds to a valid entry in redirect_fds + * + * Return values: + * If the pipe is closed, EOF is returned regardless of how many bytes + * were processed. If the pipe is still open, the number of read bytes + * is returned. + */ +static inline int _read_redirect(int fd, int flush) { + int total_read = 0; + int nbytes; + asl_redirect *aslr = &redirect_fds[fd]; + + while((nbytes = read(fd, aslr->w, BUF_SIZE - (aslr->w - aslr->buf) - 1)) > 0) { + char *s, *p; + + /* Increment our returned number read */ + total_read += nbytes; + + nbytes += (aslr->w - aslr->buf); + aslr->buf[nbytes] = '\0'; + + /* One line at a time */ + for(p=aslr->buf; *p && (p - aslr->buf) < nbytes; p = s + 1) { + // Find null or \n + for(s=p; *s && *s != '\n'; s++); + if(*s == '\n') { + *s='\0'; + asl_log(aslr->asl, aslr->msg, aslr->level, "%s", p); + } else if(aslr->buf != p) { + memmove(aslr->buf, p, BUF_SIZE); + aslr->w = aslr->buf + (s - p); + break; + } else if(nbytes == BUF_SIZE - 1) { + asl_log(aslr->asl, aslr->msg, aslr->level, "%s", p); + aslr->w = aslr->buf; + break; + } + } + } + + /* Flush if requested or we're at EOF */ + if(flush || nbytes == 0) { + if(aslr->w > aslr->buf) { + *aslr->w = '\0'; + asl_log(aslr->asl, aslr->msg, aslr->level, "%s", aslr->buf); + } + } + + if(nbytes == 0) + return EOF; + return total_read; +} + +#ifdef HAVE_LIBDISPATCH +static void read_from_source(void *_source) { + dispatch_source_t source = (dispatch_source_t)_source; + int fd = dispatch_source_get_handle(source); + if(_read_redirect(fd, 0) == EOF) { + dispatch_source_cancel(source); + } +} + +static void cancel_source(void *_source) { + dispatch_source_t source = (dispatch_source_t)_source; + int fd = dispatch_source_get_handle(source); + asl_redirect *aslr = &redirect_fds[fd]; + + /* Flush the buffer */ + _read_redirect(fd, 1); + + close(fd); + free(aslr->buf); + memset(aslr, 0, sizeof(*aslr)); + dispatch_release(source); + dispatch_group_leave(read_source_group); +} + +#else /* !HAVE_LIBDISPATCH */ +static void *redirect_thread(void *ctx __unused) { + struct kevent ev; + int n; + + while(1) { + n = kevent(kq, NULL, 0, &ev, 1, NULL); + + /* Bail on errors */ + if(n < 0) { + asl_log(NULL, NULL, ASL_LEVEL_ERR, "kevent failure: %s", strerror(errno)); + break; + } + + /* This should not happen */ + if(n == 0) + continue; + + switch(ev.filter) { + case EVFILT_READ: + pthread_mutex_lock(&redirect_fds_lock); + { + int fd = ev.ident; + int close_fd = 0; + asl_redirect *aslr = &redirect_fds[fd]; + + if(fd < 0 || fd >= n_redirect_fds || aslr->buf == NULL) { + asl_log(NULL, NULL, ASL_LEVEL_ERR, "Unexpected file descriptor: %d", fd); + goto next; + } + + if(ev.flags & EV_EOF) { + close_fd = 1; + if(EOF != _read_redirect(fd, 1)) { + asl_log(NULL, NULL, ASL_LEVEL_ERR, "kevent reported EOF on %d, but read doesn't concur.", fd); + } + } else { + close_fd = (EOF == _read_redirect(fd, 0)); + } + + if(close_fd) { + EV_SET(&ev, fd, EVFILT_READ, EV_DELETE, 0, 0, 0); + kevent(kq, &ev, 1, NULL, 0, NULL); + close(fd); + free(aslr->buf); + memset(aslr, 0, sizeof(*aslr)); + } + } + next: + pthread_mutex_unlock(&redirect_fds_lock); + + case EVFILT_TIMER: + if(ev.udata == ASL_REDIRECT_TERMINATE) + return NULL; + + default: + ;; + } + } + + return NULL; +} +#endif + +static void redirect_atexit(void) { + /* stdout is linebuffered, so flush the buffer */ + if(redirect_fds[STDOUT_FILENO].buf) + fflush(stdout); + +#ifdef HAVE_LIBDISPATCH + { + int i; + + /* Cancel all of our dispatch sources, so they flush to ASL */ + for(i=0; i < n_redirect_fds; i++) + if(redirect_fds[i].read_source) + dispatch_source_cancel(redirect_fds[i].read_source); + + /* Wait at least three seconds for our sources to flush to ASL */ + dispatch_group_wait(read_source_group, dispatch_time(DISPATCH_TIME_NOW, 3LL * NSEC_PER_SEC)); + } +#else + { + struct kevent ev; + + /* Tell our reader thread it is time to pack up and go home */ + EV_SET(&ev, 0, EVFILT_TIMER, EV_ADD | EV_ONESHOT, 0, 0, ASL_REDIRECT_TERMINATE); + kevent(kq, &ev, 1, NULL, 0, NULL); + + pthread_join(redirect_pthread, NULL); + } +#endif +} + +#ifdef HAVE_LIBDISPATCH +static void xq_asl_init(void *ctx __unused) +#else +static void xq_asl_init(void) +#endif +{ + assert((redirect_fds = calloc(16, sizeof(*redirect_fds))) != NULL); + n_redirect_fds = 16; + +#ifdef HAVE_LIBDISPATCH + redirect_serial_q = dispatch_queue_create("com.apple.asl-redirect", NULL); + assert(redirect_serial_q != NULL); + + read_source_group = dispatch_group_create(); + assert(read_source_group != NULL); +#else + assert((kq = kqueue()) != -1); + assert(pthread_create(&redirect_pthread, NULL, redirect_thread, NULL) == 0); +#endif + + atexit(redirect_atexit); +} + +int xq_asl_log_fd(aslclient asl, aslmsg msg, int level, int fd) { +#ifdef HAVE_LIBDISPATCH + int err __block = 0; + static dispatch_once_t once_control; + dispatch_once_f(&once_control, NULL, xq_asl_init); +#else + int err = 0; + static pthread_once_t once_control = PTHREAD_ONCE_INIT; + assert(pthread_once(&once_control, xq_asl_init) == 0); +#endif + + if(fd < 0) + return EBADF; + +#ifdef HAVE_LIBDISPATCH +#define BLOCK_DONE return + dispatch_sync(redirect_serial_q, ^ +#else +#define BLOCK_DONE goto done + assert(pthread_mutex_lock(&redirect_fds_lock) == 0); +#endif + { + /* Reallocate if we need more space */ + if(fd >= n_redirect_fds) { + size_t new_n = 1 << (ffs(fd) + 1); + asl_redirect *new_array = realloc(redirect_fds, new_n * sizeof(*redirect_fds)); + if(!new_array) { + err = errno; + BLOCK_DONE; + } + redirect_fds = new_array; + memset(redirect_fds + n_redirect_fds, 0, new_n - n_redirect_fds); + n_redirect_fds = new_n; + } + + /* If we're already listening on it, return error. */ + if(redirect_fds[fd].buf != NULL) { + err = EBADF; + BLOCK_DONE; + } + + /* Initialize our buffer */ + redirect_fds[fd].buf = (char *)malloc(BUF_SIZE); + if(redirect_fds[fd].buf == NULL) { + err = errno; + BLOCK_DONE; + } + redirect_fds[fd].w = redirect_fds[fd].buf; + + /* Store our ASL settings */ + redirect_fds[fd].level = level; + redirect_fds[fd].asl = asl; + redirect_fds[fd].msg = msg; + + /* Don't block on reads from this fd */ + fcntl(fd, F_SETFL, O_NONBLOCK); + + /* Start listening */ +#ifdef HAVE_LIBDISPATCH + { + dispatch_source_t read_source = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, fd, 0, redirect_serial_q); + redirect_fds[fd].read_source = read_source; + dispatch_set_context(read_source, read_source); + dispatch_source_set_event_handler_f(read_source, read_from_source); + dispatch_source_set_cancel_handler_f(read_source, cancel_source); + dispatch_group_enter(read_source_group); + dispatch_resume(read_source); + } +#else + { + struct kevent ev; + EV_SET(&ev, fd, EVFILT_READ, EV_ADD, 0, 0, 0); + kevent(kq, &ev, 1, NULL, 0, NULL); + } +#endif + } +#ifdef HAVE_LIBDISPATCH + ); +#else +done: + assert(pthread_mutex_unlock(&redirect_fds_lock) == 0); +#endif +#undef BLOCK_DONE + + return err; +} + +int xq_asl_capture_fd(aslclient asl, aslmsg msg, int level, int fd) { + int pipepair[2]; + + /* Create pipe */ + if(pipe(pipepair) == -1) + return errno; + + /* Close the read fd but not the write fd on exec */ + if(fcntl(pipepair[0], F_SETFD, FD_CLOEXEC) == -1) + return errno; + + /* Replace the existing fd */ + if(dup2(pipepair[1], fd) == -1) { + close(pipepair[0]); + close(pipepair[1]); + return errno; + } + + /* If we capture STDOUT_FILENO, make sure we linebuffer stdout */ + if(fd == STDOUT_FILENO) + setlinebuf(stdout); + + /* Close the duplicate fds since they've been reassigned */ + close(pipepair[1]); + + /* Hand off the read end of our pipe to xq_asl_log_fd */ + return xq_asl_log_fd(asl, msg, level, pipepair[0]); +} + +#ifdef DEBUG_CONSOLE_REDIRECT +int main(int argc __unused, char **argv __unused) { + xq_asl_capture_fd(NULL, NULL, ASL_LEVEL_NOTICE, STDOUT_FILENO); + xq_asl_capture_fd(NULL, NULL, ASL_LEVEL_ERR, STDERR_FILENO); + + fprintf(stderr, "TEST ERR1\n"); + fprintf(stdout, "TEST OUT1\n"); + fprintf(stderr, "TEST ERR2\n"); + fprintf(stdout, "TEST OUT2\n"); + system("/bin/echo SYST OUT"); + system("/bin/echo SYST ERR >&2"); + fprintf(stdout, "TEST OUT3\n"); + fprintf(stdout, "TEST OUT4\n"); + fprintf(stderr, "TEST ERR3\n"); + fprintf(stderr, "TEST ERR4\n"); + + exit(0); +} +#endif diff --git a/hw/xquartz/console_redirect.h b/hw/xquartz/console_redirect.h new file mode 100644 index 000000000..94520a35c --- /dev/null +++ b/hw/xquartz/console_redirect.h @@ -0,0 +1,44 @@ +/* Copyright (c) 2011 Apple Inc. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT + * HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Except as contained in this notice, the name(s) of the above + * copyright holders shall not be used in advertising or otherwise to + * promote the sale, use or other dealings in this Software without + * prior written authorization. + */ + +#ifndef _XQUARTZ_CONSOLE_REDIRECT_H_ +#define _XQUARTZ_CONSOLE_REDIRECT_H_ + +#include <asl.h> + +/* The given fd is replaced with a pipe. Anything written to it will will be + * logged to ASL. + */ +int xq_asl_capture_fd(aslclient asl, aslmsg msg, int level, int fd); + +/* The given fd is read from and passed along to ASL until all write ends of the + * pipe are closed. Once the last writer has closed the pipe, we close our end. + */ +int xq_asl_log_fd(aslclient asl, aslmsg msg, int level, int fd); + +#endif diff --git a/hw/xquartz/mach-startup/Makefile.am b/hw/xquartz/mach-startup/Makefile.am index 4dff45aa8..1ce54ad86 100644 --- a/hw/xquartz/mach-startup/Makefile.am +++ b/hw/xquartz/mach-startup/Makefile.am @@ -1,4 +1,5 @@ AM_CPPFLAGS = \ + -I$(srcdir)/.. \ -DBUILD_DATE=\"$(BUILD_DATE)\" \ -DXSERVER_VERSION=\"$(VERSION)\" \ -DX11BINDIR=\"$(bindir)\" diff --git a/hw/xquartz/mach-startup/bundle-main.c b/hw/xquartz/mach-startup/bundle-main.c index 846025b44..8e3437644 100644 --- a/hw/xquartz/mach-startup/bundle-main.c +++ b/hw/xquartz/mach-startup/bundle-main.c @@ -36,6 +36,7 @@ #endif #include <X11/Xlib.h> +#include <assert.h> #include <unistd.h> #include <stdio.h> #include <string.h> @@ -60,12 +61,14 @@ #include "mach_startup.h" #include "mach_startupServer.h" -#include "launchd_fd.h" +#include "console_redirect.h" + /* From darwinEvents.c ... but don't want to pull in all the server cruft */ void DarwinListenOnOpenFD(int fd); /* Ditto, from os/log.c */ extern void ErrorF(const char *f, ...) _X_ATTRIBUTE_PRINTF(1,2); +extern void FatalError(const char *f, ...) _X_ATTRIBUTE_PRINTF(1,2) _X_NORETURN; extern int noPanoramiXExtension; @@ -102,6 +105,10 @@ 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); +static char *pref_app_to_run; +static char *pref_login_shell; +static char *pref_startx_script; + #ifndef HAVE_LIBDISPATCH /*** Pthread Magics ***/ static pthread_t create_thread(void *(*func)(void *), void *arg) { @@ -446,7 +453,7 @@ static int startup_trigger(int argc, char **argv, char **envp) { /* Could open the display, start the launcher */ XCloseDisplay(display); - return execute(command_from_prefs("app_to_run", DEFAULT_CLIENT)); + return execute(pref_app_to_run); } } @@ -457,7 +464,7 @@ static int startup_trigger(int argc, char **argv, char **envp) { } else { ErrorF("X11.app: Could not connect to server (DISPLAY is not set). Starting X server.\n"); } - return execute(command_from_prefs("startx_script", DEFAULT_STARTX)); + return execute(pref_startx_script); } /** Setup the environment we want our child processes to inherit */ @@ -475,6 +482,28 @@ static void ensure_path(const char *dir) { } } +static void setup_console_redirect(const char *bundle_id) { + char *asl_sender; + char *asl_facility; + aslclient aslc; + + asprintf(&asl_sender, "%s.server", bundle_id); + assert(asl_sender); + + asl_facility = strdup(bundle_id); + assert(asl_facility); + if(strcmp(asl_facility + strlen(asl_facility) - 4, ".X11") == 0) + asl_facility[strlen(asl_facility) - 4] = '\0'; + + assert(aslc = asl_open(asl_sender, asl_facility, ASL_OPT_NO_DELAY)); + free(asl_sender); + free(asl_facility); + + asl_set_filter(aslc, ASL_FILTER_MASK_UPTO(ASL_LEVEL_WARNING)); + xq_asl_capture_fd(aslc, NULL, ASL_LEVEL_INFO, STDOUT_FILENO); + xq_asl_capture_fd(aslc, NULL, ASL_LEVEL_NOTICE, STDERR_FILENO); +} + static void setup_env(void) { char *temp; const char *pds = NULL; @@ -497,6 +526,8 @@ static void setup_env(void) { pds = BUNDLE_ID_PREFIX".X11"; } + setup_console_redirect(pds); + server_bootstrap_name = strdup(pds); if(!server_bootstrap_name) { ErrorF("X11.app: Memory allocation error.\n"); @@ -594,11 +625,20 @@ int main(int argc, char **argv, char **envp) { pid_t child1, child2; int status; + pref_app_to_run = command_from_prefs("app_to_run", DEFAULT_CLIENT); + assert(pref_app_to_run); + + pref_login_shell = command_from_prefs("login_shell", DEFAULT_SHELL); + assert(pref_login_shell); + + pref_startx_script = command_from_prefs("startx_script", DEFAULT_STARTX); + assert(pref_startx_script); + /* Do the fork-twice trick to avoid having to reap zombies */ child1 = fork(); switch (child1) { case -1: /* error */ - break; + FatalError("fork() failed: %s\n", strerror(errno)); case 0: /* child1 */ child2 = fork(); @@ -607,7 +647,7 @@ int main(int argc, char **argv, char **envp) { int max_files, i; case -1: /* error */ - break; + FatalError("fork() failed: %s\n", strerror(errno)); case 0: /* child2 */ /* close all open files except for standard streams */ @@ -629,6 +669,10 @@ int main(int argc, char **argv, char **envp) { default: /* parent */ waitpid(child1, &status, 0); } + + free(pref_app_to_run); + free(pref_login_shell); + free(pref_startx_script); } /* Main event loop */ @@ -646,7 +690,7 @@ static int execute(const char *command) { const char *newargv[4]; const char **p; - newargv[0] = command_from_prefs("login_shell", DEFAULT_SHELL); + newargv[0] = pref_login_shell; newargv[1] = "-c"; newargv[2] = command; newargv[3] = NULL; diff --git a/hw/xquartz/mach-startup/launchd_fd.c b/hw/xquartz/mach-startup/launchd_fd.c index 5c7e03cf3..8003dd177 100644 --- a/hw/xquartz/mach-startup/launchd_fd.c +++ b/hw/xquartz/mach-startup/launchd_fd.c @@ -31,41 +31,43 @@ #endif #include <launch.h> -#include <stdio.h> +#include <asl.h> #include <errno.h> #include "launchd_fd.h" +extern aslclient aslc; + int launchd_display_fd(void) { launch_data_t sockets_dict, checkin_request, checkin_response; launch_data_t listening_fd_array, listening_fd; /* Get launchd fd */ if ((checkin_request = launch_data_new_string(LAUNCH_KEY_CHECKIN)) == NULL) { - fprintf(stderr,"launch_data_new_string(\"" LAUNCH_KEY_CHECKIN "\") Unable to create string.\n"); + asl_log(aslc, NULL, ASL_LEVEL_ERR, "launch_data_new_string(\"" LAUNCH_KEY_CHECKIN "\") Unable to create string.\n"); return ERROR_FD; } if ((checkin_response = launch_msg(checkin_request)) == NULL) { - fprintf(stderr,"launch_msg(\"" LAUNCH_KEY_CHECKIN "\") IPC failure: %s\n",strerror(errno)); + asl_log(aslc, NULL, ASL_LEVEL_WARNING, "launch_msg(\"" LAUNCH_KEY_CHECKIN "\") IPC failure: %s\n",strerror(errno)); return ERROR_FD; } if (LAUNCH_DATA_ERRNO == launch_data_get_type(checkin_response)) { // ignore EACCES, which is common if we weren't started by launchd if (launch_data_get_errno(checkin_response) != EACCES) - fprintf(stderr,"launchd check-in failed: %s\n", strerror(launch_data_get_errno(checkin_response))); + asl_log(aslc, NULL, ASL_LEVEL_ERR, "launchd check-in failed: %s\n", strerror(launch_data_get_errno(checkin_response))); return ERROR_FD; } sockets_dict = launch_data_dict_lookup(checkin_response, LAUNCH_JOBKEY_SOCKETS); if (NULL == sockets_dict) { - fprintf(stderr,"launchd check-in: no sockets found to answer requests on!\n"); + asl_log(aslc, NULL, ASL_LEVEL_ERR, "launchd check-in: no sockets found to answer requests on!\n"); return ERROR_FD; } if (launch_data_dict_get_count(sockets_dict) > 1) { - fprintf(stderr,"launchd check-in: some sockets will be ignored!\n"); + asl_log(aslc, NULL, ASL_LEVEL_ERR, "launchd check-in: some sockets will be ignored!\n"); return ERROR_FD; } @@ -73,13 +75,13 @@ int launchd_display_fd(void) { if (NULL == listening_fd_array) { listening_fd_array = launch_data_dict_lookup(sockets_dict, ":0"); if (NULL == listening_fd_array) { - fprintf(stderr,"launchd check-in: No known sockets found to answer requests on! \"%s:0\" and \":0\" failed.\n", BUNDLE_ID_PREFIX); + asl_log(aslc, NULL, ASL_LEVEL_ERR, "launchd check-in: No known sockets found to answer requests on! \"%s:0\" and \":0\" failed.\n", BUNDLE_ID_PREFIX); return ERROR_FD; } } if (launch_data_array_get_count(listening_fd_array)!=1) { - fprintf(stderr,"launchd check-in: Expected 1 socket from launchd, got %u)\n", + asl_log(aslc, NULL, ASL_LEVEL_ERR, "launchd check-in: Expected 1 socket from launchd, got %u)\n", (unsigned)launch_data_array_get_count(listening_fd_array)); return ERROR_FD; } diff --git a/hw/xquartz/mach-startup/stub.c b/hw/xquartz/mach-startup/stub.c index c8a628311..8319dd06e 100644 --- a/hw/xquartz/mach-startup/stub.c +++ b/hw/xquartz/mach-startup/stub.c @@ -33,9 +33,9 @@ #endif #include <string.h> -#include <stdio.h> #include <unistd.h> #include <errno.h> +#include <asl.h> #include <sys/socket.h> #include <sys/un.h> @@ -43,8 +43,6 @@ #define kX11AppBundleId BUNDLE_ID_PREFIX".X11" #define kX11AppBundlePath "/Contents/MacOS/X11" -static char *server_bootstrap_name = kX11AppBundleId; - #include <mach/mach.h> #include <mach/mach_error.h> #include <servers/bootstrap.h> @@ -57,8 +55,8 @@ static char *server_bootstrap_name = kX11AppBundleId; #include "launchd_fd.h" static char x11_path[PATH_MAX + 1]; - static pid_t x11app_pid = 0; +aslclient aslc; static void set_x11_path(void) { #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1050 @@ -69,26 +67,24 @@ static void set_x11_path(void) { switch (osstatus) { case noErr: if (appURL == NULL) { - fprintf(stderr, "Xquartz: Invalid response from LSFindApplicationForInfo(%s)\n", + asl_log(aslc, NULL, ASL_LEVEL_ERR, "Xquartz: Invalid response from LSFindApplicationForInfo(%s)", kX11AppBundleId); exit(1); } if (!CFURLGetFileSystemRepresentation(appURL, true, (unsigned char *)x11_path, sizeof(x11_path))) { - fprintf(stderr, "Xquartz: Error resolving URL for %s\n", kX11AppBundleId); + asl_log(aslc, NULL, ASL_LEVEL_ERR, "Xquartz: Error resolving URL for %s", kX11AppBundleId); exit(3); } strlcat(x11_path, kX11AppBundlePath, sizeof(x11_path)); -#ifdef DEBUG - fprintf(stderr, "Xquartz: X11.app = %s\n", x11_path); -#endif + asl_log(aslc, NULL, ASL_LEVEL_INFO, "Xquartz: X11.app = %s", x11_path); break; case kLSApplicationNotFoundErr: - fprintf(stderr, "Xquartz: Unable to find application for %s\n", kX11AppBundleId); + asl_log(aslc, NULL, ASL_LEVEL_ERR, "Xquartz: Unable to find application for %s", kX11AppBundleId); exit(10); default: - fprintf(stderr, "Xquartz: Unable to find application for %s, error code = %d\n", + asl_log(aslc, NULL, ASL_LEVEL_ERR, "Xquartz: Unable to find application for %s, error code = %d", kX11AppBundleId, (int)osstatus); exit(11); } @@ -114,12 +110,12 @@ static int connect_to_socket(const char *filename) { ret_fd = socket(PF_UNIX, SOCK_STREAM, 0); if(ret_fd == -1) { - fprintf(stderr, "Xquartz: Failed to create socket: %s - %s\n", filename, strerror(errno)); + asl_log(aslc, NULL, ASL_LEVEL_ERR, "Xquartz: Failed to create socket: %s - %s", filename, strerror(errno)); return -1; } if(connect(ret_fd, servaddr, servaddr_len) < 0) { - fprintf(stderr, "Xquartz: Failed to connect to socket: %s - %d - %s\n", filename, errno, strerror(errno)); + asl_log(aslc, NULL, ASL_LEVEL_ERR, "Xquartz: Failed to connect to socket: %s - %d - %s", filename, errno, strerror(errno)); close(ret_fd); return -1; } @@ -160,14 +156,11 @@ static void send_fd_handoff(int connected_fd, int launchd_fd) { *((int*)CMSG_DATA(cmsg)) = launchd_fd; if(sendmsg(connected_fd, &msg, 0) < 0) { - fprintf(stderr, "Xquartz: Error sending $DISPLAY file descriptor over fd %d: %d -- %s\n", connected_fd, errno, strerror(errno)); + asl_log(aslc, NULL, ASL_LEVEL_ERR, "Xquartz: Error sending $DISPLAY file descriptor over fd %d: %d -- %s", connected_fd, errno, strerror(errno)); return; } -#ifdef DEBUG - fprintf(stderr, "Xquartz: Message sent. Closing handoff fd.\n"); -#endif - + asl_log(aslc, NULL, ASL_LEVEL_DEBUG, "Xquartz: Message sent. Closing handoff fd."); close(connected_fd); } @@ -187,10 +180,25 @@ int main(int argc, char **argv, char **envp) { int launchd_fd; string_t handoff_socket_filename; sig_t handler; + char *asl_sender; + char *asl_facility; + char *server_bootstrap_name = kX11AppBundleId; if(getenv("X11_PREFS_DOMAIN")) server_bootstrap_name = getenv("X11_PREFS_DOMAIN"); - + + asprintf(&asl_sender, "%s.stub", server_bootstrap_name); + assert(asl_sender); + + asl_facility = strdup(server_bootstrap_name); + assert(asl_facility); + if(strcmp(asl_facility + strlen(asl_facility) - 4, ".X11") == 0) + asl_facility[strlen(asl_facility) - 4] = '\0'; + + assert(aslc = asl_open(asl_sender, asl_facility, ASL_OPT_NO_DELAY)); + free(asl_sender); + free(asl_facility); + /* We don't have a mechanism in place to handle this interrupt driven * server-start notification, so just send the signal now, so xinit doesn't * time out waiting for it and will just poll for the server. @@ -211,13 +219,13 @@ int main(int argc, char **argv, char **envp) { if(kr != KERN_SUCCESS) { pid_t child; - fprintf(stderr, "Xquartz: Unable to locate waiting server: %s\n", server_bootstrap_name); + asl_log(aslc, NULL, ASL_LEVEL_WARNING, "Xquartz: Unable to locate waiting server: %s", server_bootstrap_name); set_x11_path(); /* This forking is ugly and will be cleaned up later */ child = fork(); if(child == -1) { - fprintf(stderr, "Xquartz: Could not fork: %s\n", strerror(errno)); + asl_log(aslc, NULL, ASL_LEVEL_ERR, "Xquartz: Could not fork: %s", strerror(errno)); return EXIT_FAILURE; } @@ -226,7 +234,7 @@ int main(int argc, char **argv, char **envp) { _argv[0] = x11_path; _argv[1] = "--listenonly"; _argv[2] = NULL; - fprintf(stderr, "Xquartz: Starting X server: %s --listenonly\n", x11_path); + asl_log(aslc, NULL, ASL_LEVEL_NOTICE, "Xquartz: Starting X server: %s --listenonly", x11_path); return execvp(x11_path, _argv); } @@ -240,9 +248,9 @@ int main(int argc, char **argv, char **envp) { if(kr != KERN_SUCCESS) { #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1050 - fprintf(stderr, "Xquartz: bootstrap_look_up(): %s\n", bootstrap_strerror(kr)); + asl_log(aslc, NULL, ASL_LEVEL_ERR, "Xquartz: bootstrap_look_up(): %s", bootstrap_strerror(kr)); #else - fprintf(stderr, "Xquartz: bootstrap_look_up(): %ul\n", (unsigned long)kr); + asl_log(aslc, NULL, ASL_LEVEL_ERR, "Xquartz: bootstrap_look_up(): %ul", (unsigned long)kr); #endif return EXIT_FAILURE; } @@ -258,20 +266,17 @@ int main(int argc, char **argv, char **envp) { for(try=0, try_max=5; try < try_max; try++) { if(request_fd_handoff_socket(mp, handoff_socket_filename) != KERN_SUCCESS) { - fprintf(stderr, "Xquartz: Failed to request a socket from the server to send the $DISPLAY fd over (try %d of %d)\n", (int)try+1, (int)try_max); + asl_log(aslc, NULL, ASL_LEVEL_INFO, "Xquartz: Failed to request a socket from the server to send the $DISPLAY fd over (try %d of %d)", (int)try+1, (int)try_max); continue; } handoff_fd = connect_to_socket(handoff_socket_filename); if(handoff_fd == -1) { - fprintf(stderr, "Xquartz: Failed to connect to socket (try %d of %d)\n", (int)try+1, (int)try_max); + asl_log(aslc, NULL, ASL_LEVEL_ERR, "Xquartz: Failed to connect to socket (try %d of %d)", (int)try+1, (int)try_max); continue; } -#ifdef DEBUG - fprintf(stderr, "Xquartz: Handoff connection established (try %d of %d) on fd %d, \"%s\". Sending message.\n", (int)try+1, (int)try_max, handoff_fd, handoff_socket_filename); -#endif - + asl_log(aslc, NULL, ASL_LEVEL_INFO, "Xquartz: Handoff connection established (try %d of %d) on fd %d, \"%s\". Sending message.", (int)try+1, (int)try_max, handoff_fd, handoff_socket_filename); send_fd_handoff(handoff_fd, launchd_fd); close(handoff_fd); break; @@ -288,7 +293,7 @@ int main(int argc, char **argv, char **envp) { newenvp = (string_array_t)calloc((1 + envpc), sizeof(string_t)); if(!newargv || !newenvp) { - fprintf(stderr, "Xquartz: Memory allocation failure\n"); + asl_log(aslc, NULL, ASL_LEVEL_ERR, "Xquartz: Memory allocation failure"); return EXIT_FAILURE; } @@ -305,7 +310,7 @@ int main(int argc, char **argv, char **envp) { free(newenvp); if (kr != KERN_SUCCESS) { - fprintf(stderr, "Xquartz: start_x11_server: %s\n", mach_error_string(kr)); + asl_log(aslc, NULL, ASL_LEVEL_ERR, "Xquartz: start_x11_server: %s", mach_error_string(kr)); return EXIT_FAILURE; } return EXIT_SUCCESS; diff --git a/hw/xquartz/man/Xquartz.man b/hw/xquartz/man/Xquartz.man index 447194740..19e8efbad 100644 --- a/hw/xquartz/man/Xquartz.man +++ b/hw/xquartz/man/Xquartz.man @@ -16,72 +16,72 @@ OS X handles the desktop background. .SH CUSTOMIZATION \fIXquartz\fP can be customized using the defaults(1) command. The available options are: .TP 8 -.B defaults write __laucnd_id_prefix__.X11 enable_fake_buttons -boolean true +.B defaults write __bundle_id_prefix__.X11 enable_fake_buttons -boolean true Emulates a 3 button mouse using modifier keys. By default, the Command modifier is used to emulate button 2 and Option is used for button 3. Thus, clicking the first mouse button while holding down Command will act like clicking button 2. Holding down Option will simulate button 3. .TP 8 -.B defaults write __laucnd_id_prefix__.X11 fake_button2 \fImodifiers\fP +.B defaults write __bundle_id_prefix__.X11 fake_button2 \fImodifiers\fP Change the modifier keys used to emulate the second mouse button. By default, Command is used to emulate the second button. Any combination of the following modifier names may be used: {l,r,}shift, {l,r,}option, {l,r,}control, {l,r,}command, fn .TP 8 -.B defaults write __laucnd_id_prefix__.X11 fake_button3 \fImodifiers\fP +.B defaults write __bundle_id_prefix__.X11 fake_button3 \fImodifiers\fP Change the modifier keys used to emulate the second mouse button. By default, Command is used to emulate the second button. Any combination of the following modifier names may be used: {l,r,}shift, {l,r,}option, {l,r,}control, {l,r,}command, fn .TP 8 -.B defaults write __laucnd_id_prefix__.X11 fullscreen_hotkeys -boolean true +.B defaults write __bundle_id_prefix__.X11 fullscreen_hotkeys -boolean true Enable OSX hotkeys while in fullscreen .TP 8 -.B defaults write __laucnd_id_prefix__.X11 fullscreen_menu -boolean true +.B defaults write __bundle_id_prefix__.X11 fullscreen_menu -boolean true Show the OSX menu while in fullscreen .TP 8 -.B defaults write __laucnd_id_prefix__.X11 no_quit_alert -boolean true +.B defaults write __bundle_id_prefix__.X11 no_quit_alert -boolean true Disables the alert dialog displayed when attempting to quit X11. .TP 8 -.B defaults write __laucnd_id_prefix__.X11 no_auth -boolean true +.B defaults write __bundle_id_prefix__.X11 no_auth -boolean true Stops the X server requiring that clients authenticate themselves when connecting. See Xsecurity(__miscmansuffix__). .TP 8 -.B defaults write __laucnd_id_prefix__.X11 nolisten_tcp -boolean false +.B defaults write __bundle_id_prefix__.X11 nolisten_tcp -boolean false This will tell the server to listen and accept TCP connections. Doing this without enabling xauth is a possible security concern. See Xsecurity(__miscmansuffix__). .TP 8 -.B defaults write __laucnd_id_prefix__.X11 enable_system_beep -boolean false +.B defaults write __bundle_id_prefix__.X11 enable_system_beep -boolean false Don't use the standard system beep effect for X11 alerts. .TP 8 -.B defaults write __laucnd_id_prefix__.X11 enable_key_equivalents -boolean false +.B defaults write __bundle_id_prefix__.X11 enable_key_equivalents -boolean false Disable menu keyboard equivalents while X11 windows are focused. .TP 8 -.B defaults write __laucnd_id_prefix__.X11 depth \fIdepth\fP +.B defaults write __bundle_id_prefix__.X11 depth \fIdepth\fP Specifies the color bit depth to use. Currently only 15, and 24 color bits per pixel are supported. If not specified, or a value of -1 is specified, defaults to the depth of the main display. .TP 8 -.B defaults write __laucnd_id_prefix__.X11 sync_keymap -boolean true +.B defaults write __bundle_id_prefix__.X11 sync_keymap -boolean true Keep the X11 keymap up to date with the OSX system keymap. .TP 8 -.B defaults write __laucnd_id_prefix__.X11 option_sends_alt -boolean true +.B defaults write __bundle_id_prefix__.X11 option_sends_alt -boolean true The Option key will send Alt_L and Alt_R instead of Mode_switch. .TP 8 -.B defaults write __laucnd_id_prefix__.X11 sync_pasteboard -boolean true +.B defaults write __bundle_id_prefix__.X11 sync_pasteboard -boolean true Enable syncing between the OSX pasteboard and clipboard/primary selection buffers in X11. This option needs to be true for any of the other pasteboard sync options to have an effect. .TP 8 -.B defaults write __laucnd_id_prefix__.X11 sync_pasteboard_to_clipboard -boolean true +.B defaults write __bundle_id_prefix__.X11 sync_pasteboard_to_clipboard -boolean true Update the X11 CLIPBOARD when the OSX NSPasteboard is updated. .TP 8 -.B defaults write __laucnd_id_prefix__.X11 sync_pasteboard_to_primary -boolean true +.B defaults write __bundle_id_prefix__.X11 sync_pasteboard_to_primary -boolean true Update the the X11 PRIMARY buffer when the OSX NSPasteboard is updated. .TP 8 -.B defaults write __laucnd_id_prefix__.X11 sync_clipboard_to_pasteboard -boolean true +.B defaults write __bundle_id_prefix__.X11 sync_clipboard_to_pasteboard -boolean true Update the the OSX NSPasteboard when the X11 CLIPBOARD is updated. Note that enabling this option causes the clipboard synchronization to act as a clipboard manager in X11. This makes it impossible to use xclipboard, klipper, or any other such clipboard managers. If you want to use any of these programs, you must disable this option. .TP 8 -.B defaults write __laucnd_id_prefix__.X11 sync_primary_on_select -boolean true +.B defaults write __bundle_id_prefix__.X11 sync_primary_on_select -boolean true This option defaults to false and is provided only "for experts." It updates the NSPasteboard whenever a new X11 selection is made (rather than requiring you to hit cmd-c to copy the selection to the NSPasteboard). Since the X11 protocol does not require applications to send notification when they change selection, this might not work in all cases (if you run into this problem, try selecting text in another application first, then selecting the text you want). .TP 8 -.B defaults write __laucnd_id_prefix__.X11 enable_test_extensions -boolean true +.B defaults write __bundle_id_prefix__.X11 enable_test_extensions -boolean true This option defaults to false and is only accessible through the command line. Enable this option to turn on the DEC-XTRAP, RECORD, and XTEST extensions in the server. .SH OPTIONS .PP @@ -102,9 +102,32 @@ Same as fake_button3 above. .TP 8 .B "\-depth \fIdepth\fP" Same as depth above. +.SH LOGGING +XQuartz stores a server log at ~/Library/Logs/X11.__bundle_id_prefix__.log which +is analogous to /var/log/Xorg.#.log on systems that use the XFree86 DDX such as +Linux, BSD, and Solaris. +.PP +In addition to this server log, XQuartz sends messages to syslogd(8) using +asl(3). These logs are sent to the __bundle_id_prefix__ facility, and you can +watch these logs using the following syslog(1) command: +.TP 8 +.B $ syslog -w -k Facility __bundle_id_prefix__ +.PP +By default, XQaurtz sets an ASL mask which prevents it from logging messages +below the ASL_LEVEL_WARNING level (meaning almost all logging is done strictly +to the file referenced above). To force XQuartz to send all log messages to +syslogd(8), you can adjust this mask using the following syslog(1) command: +.TP 8 +.B $ syslog -c X11.bin -d +.PP +The stdout and stderr messages printed by any process launched by XQuartz will +be redirected to this syslog facility with a priority level of ASL_LEVEL_INFO +and ASL_LEVEL_NOTICE respectively. In order to see these messages in syslog, +you will need to adjust XQuartz's asl mask as above but using -i or -n +instead of -d. .SH "SEE ALSO" .PP -X(__miscmansuffix__), Xserver(1), xdm(1), xinit(1) +X(__miscmansuffix__), Xserver(1), xdm(1), xinit(1), syslog(1), syslogd(8) .PP http://xquartz.macosforge.org .PP diff --git a/hw/xquartz/quartzKeyboard.c b/hw/xquartz/quartzKeyboard.c index c54011488..e682f08b6 100644 --- a/hw/xquartz/quartzKeyboard.c +++ b/hw/xquartz/quartzKeyboard.c @@ -56,13 +56,7 @@ #include "X11Application.h" -#ifdef NDEBUG -#undef NDEBUG #include <assert.h> -#define NDEBUG 1 -#else -#include <assert.h> -#endif #include <pthread.h> #include "xkbsrv.h" diff --git a/hw/xquartz/sanitizedCocoa.h b/hw/xquartz/sanitizedCocoa.h index 58de64c1c..5a2a282d1 100644 --- a/hw/xquartz/sanitizedCocoa.h +++ b/hw/xquartz/sanitizedCocoa.h @@ -16,7 +16,8 @@ #define BOOL OSX_BOOL #define EventType HIT_EventType -#include <Cocoa/Cocoa.h> +#import <Cocoa/Cocoa.h> +#import <Foundation/Foundation.h> #undef Cursor #undef WindowPtr @@ -24,4 +25,40 @@ #undef BOOL #undef EventType +#ifndef __has_feature +#define __has_feature(x) 0 // Compatibility with non-clang compilers. +#endif + +#ifndef NS_RETURNS_RETAINED +#if __has_feature(attribute_ns_returns_retained) +#define NS_RETURNS_RETAINED __attribute__((ns_returns_retained)) +#else +#define NS_RETURNS_RETAINED +#endif +#endif + +#ifndef NS_RETURNS_NOT_RETAINED +#if __has_feature(attribute_ns_returns_not_retained) +#define NS_RETURNS_NOT_RETAINED __attribute__((ns_returns_not_retained)) +#else +#define NS_RETURNS_NOT_RETAINED +#endif +#endif + +#ifndef CF_RETURNS_RETAINED +#if __has_feature(attribute_cf_returns_retained) +#define CF_RETURNS_RETAINED __attribute__((cf_returns_retained)) +#else +#define CF_RETURNS_RETAINED +#endif +#endif + +#ifndef CF_RETURNS_NOT_RETAINED +#if __has_feature(attribute_cf_returns_not_retained) +#define CF_RETURNS_NOT_RETAINED __attribute__((cf_returns_not_retained)) +#else +#define CF_RETURNS_NOT_RETAINED +#endif +#endif + #endif /* _XQ_SANITIZED_COCOA_H_ */ diff --git a/hw/xquartz/xpr/xprFrame.c b/hw/xquartz/xpr/xprFrame.c index 5f6b1cb7b..4818653f6 100644 --- a/hw/xquartz/xpr/xprFrame.c +++ b/hw/xquartz/xpr/xprFrame.c @@ -69,7 +69,7 @@ static x_hash_table *window_hash; #ifdef HAVE_LIBDISPATCH static dispatch_queue_t window_hash_serial_q; #else -static pthread_mutex_t window_hash_mutex; +static pthread_rwlock_t window_hash_rwlock; #endif /* Prototypes for static functions */ @@ -192,9 +192,9 @@ xprCreateFrame(RootlessWindowPtr pFrame, ScreenPtr pScreen, x_hash_table_insert(window_hash, pFrame->wid, pFrame); }); #else - pthread_mutex_lock(&window_hash_mutex); + pthread_rwlock_wrlock(&window_hash_rwlock); x_hash_table_insert(window_hash, pFrame->wid, pFrame); - pthread_mutex_unlock(&window_hash_mutex); + pthread_rwlock_wrlock(&window_hash_rwlock); #endif xprSetNativeProperty(pFrame); @@ -216,9 +216,9 @@ xprDestroyFrame(RootlessFrameID wid) x_hash_table_remove(window_hash, wid); }); #else - pthread_mutex_lock(&window_hash_mutex); + pthread_rwlock_wrlock(&window_hash_rwlock); x_hash_table_remove(window_hash, wid); - pthread_mutex_unlock(&window_hash_mutex); + pthread_rwlock_unlock(&window_hash_rwlock); #endif err = xp_destroy_window(x_cvt_vptr_to_uint(wid)); @@ -292,9 +292,9 @@ static void xprRestackFrame(RootlessFrameID wid, RootlessFrameID nextWid) { winRec = x_hash_table_lookup(window_hash, wid, NULL); }); #else - pthread_mutex_lock(&window_hash_mutex); + pthread_rwlock_rdlock(&window_hash_rwlock); winRec = x_hash_table_lookup(window_hash, wid, NULL); - pthread_mutex_unlock(&window_hash_mutex); + pthread_rwlock_unlock(&window_hash_rwlock); #endif if(winRec) { @@ -479,7 +479,7 @@ xprInit(ScreenPtr pScreen) #ifdef HAVE_LIBDISPATCH assert((window_hash_serial_q = dispatch_queue_create(BUNDLE_ID_PREFIX".X11.xpr_window_hash", NULL))); #else - assert(0 == pthread_mutex_init(&window_hash_mutex, NULL)); + assert(0 == pthread_rwlock_init(&window_hash_rwlock, NULL)); #endif return TRUE; @@ -500,9 +500,9 @@ xprGetXWindow(xp_window_id wid) }); #else RootlessWindowRec *winRec; - pthread_mutex_lock(&window_hash_mutex); + pthread_rwlock_rdlock(&window_hash_rwlock); winRec = x_hash_table_lookup(window_hash, x_cvt_uint_to_vptr(wid), NULL); - pthread_mutex_unlock(&window_hash_mutex); + pthread_rwlock_unlock(&window_hash_rwlock); #endif return winRec != NULL ? winRec->win : NULL; |