xquartz: add non-dispatch fallbacks for 10.5

Based on https://github.com/XQuartz/xorg-server/blob/server-1.20-legacy
This commit is contained in:
Sergey Fedorov 2026-05-25 21:52:40 +08:00 • committed by Enrico Weigelt
commit 0946eb14c5
7 changed files with 132 additions and 11 deletions

View file

@ -6,8 +6,14 @@
// Copyright (c) 2021 Apple Inc. All rights reserved.
//
#import "NSUserDefaults+XQuartzDefaults.h"
#import <dispatch/dispatch.h>
#include "NSUserDefaults+XQuartzDefaults.h"
#include "osxcompat.h"
#ifdef HAS_LIBDISPATCH
#include <dispatch/dispatch.h>
#else
#include <pthread.h>
#endif
NSString * const XQuartzPrefKeyAppsMenu = @"apps_menu";
NSString * const XQuartzPrefKeyFakeButtons = @"enable_fake_buttons";
@ -128,32 +134,50 @@ xquartzDefaultsOnce(void *arg)
[*defaults registerDefaults:systemDefaultsDict];
}
#ifdef HAS_LIBDISPATCH
typedef dispatch_once_t compat_once_t;
#define COMPAT_ONCE_INIT 0
#define compat_once_f dispatch_once_f
#else
typedef pthread_once_t compat_once_t;
#define COMPAT_ONCE_INIT PTHREAD_ONCE_INIT
static inline void compat_once_f(compat_once_t *once, void *context, void (*func)(void *)) {
// pthread_once only takes a void(*)(void), so wrap context in a static
static void *compat_context;
static void (*compat_func)(void *);
compat_context = context;
compat_func = func;
void wrapper(void) { compat_func(compat_context); }
pthread_once(once, wrapper);
}
#endif
@implementation NSUserDefaults (XQuartzDefaults)
+ (NSUserDefaults *)globalDefaults
{
static dispatch_once_t once;
static compat_once_t once = COMPAT_ONCE_INIT;
static NSUserDefaults *defaults;
dispatch_once_f(&once, &defaults, globalDefaultsOnce);
compat_once_f(&once, &defaults, globalDefaultsOnce);
return defaults;
}
+ (NSUserDefaults *)dockDefaults
{
static dispatch_once_t once;
static compat_once_t once = COMPAT_ONCE_INIT;
static NSUserDefaults *defaults;
dispatch_once_f(&once, &defaults, dockDefaultsOnce);
compat_once_f(&once, &defaults, dockDefaultsOnce);
return defaults;
}
+ (NSUserDefaults *)xquartzDefaults
{
static dispatch_once_t once;
static compat_once_t once = COMPAT_ONCE_INIT;
static NSUserDefaults *defaults;
dispatch_once_f(&once, &defaults, xquartzDefaultsOnce);
compat_once_f(&once, &defaults, xquartzDefaultsOnce);
return defaults;
}

View file

@ -61,9 +61,14 @@ xpbproxy_run(void);
#define XSERVER_VERSION "?"
#endif
#ifdef HAS_LIBDISPATCH
#include <dispatch/dispatch.h>
static dispatch_queue_t eventTranslationQueue;
#else
// aquaMenuBarHeight is just a proxy for initialization
#define eventTranslationQueue aquaMenuBarHeight
#endif
#ifndef __has_feature
#define __has_feature(x) 0
@ -483,8 +488,12 @@ sendX11NSEvent_fptr(void *e_ptr)
}
if (for_x) {
#ifdef HAS_LIBDISPATCH
NSEvent *event_copy = [e retain];
dispatch_async_f(eventTranslationQueue, event_copy, sendX11NSEvent_fptr);
#else
[self sendX11NSEvent:e];
#endif
}
}
@ -842,13 +851,20 @@ X11ApplicationMain(int argc, char **argv, char **envp)
/* Calculate the height of the menubar so we can avoid it. */
aquaMenuBarHeight = [[NSApp mainMenu] menuBarHeight];
#if ! __LP64__
if (!aquaMenuBarHeight) {
aquaMenuBarHeight = [NSMenuView menuBarHeight];
}
#endif
if (!aquaMenuBarHeight) {
NSScreen* primaryScreen = [[NSScreen screens] objectAtIndex:0];
aquaMenuBarHeight = NSHeight(primaryScreen.frame) - NSMaxY(primaryScreen.visibleFrame);
}
#ifdef HAS_LIBDISPATCH
eventTranslationQueue = dispatch_queue_create(BUNDLE_ID_PREFIX ".X11.NSEventsToX11EventsQueue", NULL);
assert(eventTranslationQueue != NULL);
#endif
/* Set the key layout seed before we start the server */
last_key_layout = TISCopyCurrentKeyboardLayoutInputSource();

View file

@ -57,7 +57,9 @@
#include "mach_startupServer.h"
#include "osxcompat.h"
#ifdef HAS_LIBDISPATCH
#include <dispatch/dispatch.h>
#endif
#include <asl.h>
@ -116,6 +118,23 @@ static char *pref_app_to_run;
static char *pref_login_shell;
static char *pref_startx_script;
#ifndef HAS_LIBDISPATCH
/*** Pthread Magics ***/
static pthread_t
create_thread(void *(*func)(void *), void *arg)
{
pthread_attr_t attr;
pthread_t tid;
pthread_attr_init(&attr);
pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
pthread_create(&tid, &attr, func, arg);
pthread_attr_destroy(&attr);
return tid;
}
#endif
/*** Mach-O IPC Stuffs ***/
@ -223,9 +242,16 @@ typedef struct {
/* This thread accepts an incoming connection and hands off the file
* descriptor for the new connection to accept_fd_handoff()
*/
#ifdef HAS_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;
@ -260,6 +286,9 @@ socket_handoff(socket_handoff_t *handoff_data)
launchd_fd);
DarwinListenOnOpenFD(launchd_fd);
#ifndef HAS_LIBDISPATCH
return NULL;
#endif
}
static int
@ -347,9 +376,13 @@ do_request_fd_handoff_socket(mach_port_t port, string_t filename)
strlcpy(filename, handoff_data->filename, STRING_T_SIZE);
#ifdef HAS_LIBDISPATCH
dispatch_async_f(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),
handoff_data,
socketHandoff_fptr);
#else
create_thread(socket_handoff_thread, handoff_data);
#endif
#ifdef DEBUG
ErrorF(

View file

@ -69,7 +69,7 @@ libxquartz_defs = [
]
if cc.has_function('dispatch_async')
libxquartz_defs += '-DHAVE_LIBDISPATCH'
libxquartz_defs += '-DHAS_LIBDISPATCH'
endif
libXquartz = static_library('Xquartz',

View file

@ -60,6 +60,7 @@
#include "exevents.h"
#include "X11/keysym.h"
#include "keysym2ucs.h"
#include "osxcompat.h"
extern void
CopyKeyClass(DeviceIntPtr device, DeviceIntPtr master);
@ -771,11 +772,15 @@ QuartzReadSystemKeymap(darwinKeyboardInfo *info)
KeySym *k;
/* This is an ugly ant-pattern, but it is more expedient to address the problem right now. */
#ifdef HAS_LIBDISPATCH
if (pthread_main_np()) {
getKeyboardData(&ctx);
} else {
dispatch_sync_f(dispatch_get_main_queue(), &ctx, getKeyboardData);
}
#else
getKeyboardData(&ctx);
#endif
if (ctx.chr_data == NULL) {
ErrorF("Couldn't get uchr or kchr resource\n");

View file

@ -52,10 +52,13 @@
#include "quartzKeyboard.h"
#include "rootlessWindow.h"
#include "xprEvent.h"
#include "osxcompat.h"
#ifdef HAS_LIBDISPATCH
#include <dispatch/dispatch.h>
#endif
#if XPLUGIN_VERSION >= 6
#include <dispatch/dispatch.h>
static void bringAllToFront(void *unused) {
(void)unused; /* to silence the compiler warning */
xp_window_bring_all_to_front();
@ -76,7 +79,7 @@ bool QuartzModeEventHandler(int screenNum, XQuartzEvent *e, DeviceIntPtr dev) {
case kXquartzBringAllToFront:
DEBUG_LOG("kXquartzBringAllToFront\n");
#if XPLUGIN_VERSION >= 6
#if defined(HAS_LIBDISPATCH) && (XPLUGIN_VERSION >= 6)
dispatch_async_f(
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), NULL,
bringAllToFront);

View file

@ -44,8 +44,13 @@
#include <X11/Xatom.h>
#include "windowstr.h"
#include "quartz.h"
#include "osxcompat.h"
#ifdef HAS_LIBDISPATCH
#include <dispatch/dispatch.h>
#else
#include <pthread.h>
#endif
#define DEFINE_ATOM_HELPER(func, atom_name) \
static Atom func(void) { \
@ -63,7 +68,11 @@ typedef struct _WindowHashInsertCtx {
static x_hash_table * window_hash;
/* Need to guard window_hash since xprIsX11Window can be called from any thread. */
#ifdef HAS_LIBDISPATCH
static dispatch_queue_t window_hash_serial_q;
#else
static pthread_rwlock_t window_hash_rwlock;
#endif
/* Prototypes for static functions */
static Bool
@ -206,6 +215,7 @@ xprCreateFrame(RootlessWindowPtr pFrame, ScreenPtr pScreen,
return FALSE;
}
#ifdef HAS_LIBDISPATCH
WindowHashInsertCtx *ctx = malloc(sizeof(WindowHashInsertCtx));
if (!ctx) return FALSE;
@ -213,6 +223,12 @@ xprCreateFrame(RootlessWindowPtr pFrame, ScreenPtr pScreen,
ctx->frame = pFrame;
dispatch_async_f(window_hash_serial_q, ctx, windowHashInsert);
#else
pthread_rwlock_wrlock(&window_hash_rwlock);
x_hash_table_insert(window_hash, pFrame->wid, pFrame);
pthread_rwlock_unlock(&window_hash_rwlock);
#endif
xprSetNativeProperty(pFrame);
return TRUE;
@ -248,11 +264,18 @@ static void windowLookup(void *arg) {
static void
xprDestroyFrame(RootlessFrameID wid)
{
#ifdef HAS_LIBDISPATCH
WindowHashRemoveCtx *ctx = malloc(sizeof(WindowHashRemoveCtx));
if (!ctx) FatalError("Could not allocate memory for the hash removal context.");
ctx->wid = wid;
dispatch_async_f(window_hash_serial_q, ctx, windowHashRemove);
#else
pthread_rwlock_wrlock(&window_hash_rwlock);
x_hash_table_remove(window_hash, wid);
pthread_rwlock_unlock(&window_hash_rwlock);
#endif
xp_error err = xp_destroy_window(x_cvt_vptr_to_uint(wid));
if (err != Success)
@ -324,7 +347,13 @@ xprRestackFrame(RootlessFrameID wid, RootlessFrameID nextWid)
wc.sibling = x_cvt_vptr_to_uint(nextWid);
}
#ifdef HAS_LIBDISPATCH
dispatch_sync_f(window_hash_serial_q, &ctx, windowLookup);
#else
pthread_rwlock_rdlock(&window_hash_rwlock);
winRec = x_hash_table_lookup(window_hash, wid, NULL);
pthread_rwlock_unlock(&window_hash_rwlock);
#endif
if (winRec) {
if (XQuartzIsRootless)
@ -515,9 +544,13 @@ xprInit(ScreenPtr pScreen)
rootless_CopyWindow_threshold = xp_scroll_area_threshold;
assert((window_hash = x_hash_table_new(NULL, NULL, NULL, NULL)));
#ifdef HAS_LIBDISPATCH
assert((window_hash_serial_q =
dispatch_queue_create(BUNDLE_ID_PREFIX ".X11.xpr_window_hash",
NULL)));
#else
assert(0 == pthread_rwlock_init(&window_hash_rwlock, NULL));
#endif
return TRUE;
}
@ -535,12 +568,19 @@ WindowPtr
xprGetXWindow(xp_window_id wid)
{
RootlessWindowRec *winRec;
#ifdef HAS_LIBDISPATCH
WindowGetCtx ctx = {
.wid = x_cvt_uint_to_vptr(wid),
.winrec = &winRec
};
dispatch_sync_f(window_hash_serial_q, &ctx, windowGet);
#else
RootlessWindowRec *winRec;
pthread_rwlock_rdlock(&window_hash_rwlock);
winRec = x_hash_table_lookup(window_hash, x_cvt_uint_to_vptr(wid), NULL);
pthread_rwlock_unlock(&window_hash_rwlock);
#endif
return winRec != NULL ? winRec->win : NULL;
}