Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
2bd398a
glx: Initialize glx even if there are currently no screens attached
jeremyhu Sep 11, 2016
24264dd
randr: Initialize RandR even if there are currently no screens attached
jeremyhu Sep 11, 2016
ecea151
Revert "os/WaitFor: Check timers on every iteration"
jeremyhu Jun 14, 2022
247c17f
rootless: Fix Glyphs damage bounding box origin and coordinate space
jeremyhu Mar 22, 2026
5c3881c
rootless: Factor RootlessStopDrawing() into a frame-keyed helper
jeremyhu Aug 17, 2026
854a8df
rootless: Stop drawing before destroying a frame
jeremyhu Aug 17, 2026
5a0f22b
rootless: Stop drawing before handing a frame to a new top-level parent
jeremyhu Aug 17, 2026
b4958e5
xquartz: Do not initialize the window hash inside assert()
jeremyhu Aug 17, 2026
ff58a4a
rootless: Guard against a NULL window when a native window moves
jeremyhu Aug 17, 2026
ec54923
xquartz: Fix use-after-free of the frame record in the window hash
jeremyhu Aug 17, 2026
52b2a39
xquartz: Do not treat a failed frame destroy as fatal
jeremyhu Aug 17, 2026
4ed3b22
rootless: Stop drawing before resizing the root's frame
jeremyhu Aug 17, 2026
5d0995a
xquartz: Log failures to reconfigure a frame
jeremyhu Aug 17, 2026
5ba38fb
rootless: Correct the documented flush behavior for moving a frame
jeremyhu Aug 17, 2026
cab18f6
rootless: Bound the clip of frameless windows to the screen pixmap
jeremyhu Aug 17, 2026
1f78051
rootless: Don't use the implementation's accelerated copy for 8bit fr…
tenox7 Aug 26, 2026
16c82f8
rootless: Pass global coordinates to RootlessDamageRegion()
tenox7 Aug 26, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 0 additions & 22 deletions glx/glxext.c
Original file line number Diff line number Diff line change
Expand Up @@ -281,24 +281,6 @@ GlxPushProvider(__GLXprovider * provider)
__glXProviderStack = provider;
}

static Bool
checkScreenVisuals(void)
{
int i, j;

for (i = 0; i < screenInfo.numScreens; i++) {
ScreenPtr screen = screenInfo.screens[i];
for (j = 0; j < screen->numVisuals; j++) {
if ((screen->visuals[j].class == TrueColor ||
screen->visuals[j].class == DirectColor) &&
screen->visuals[j].nplanes > 12)
return TRUE;
}
}

return FALSE;
}

static void
GetGLXDrawableBytes(void *value, XID id, ResourceSizePtr size)
{
Expand Down Expand Up @@ -472,10 +454,6 @@ static Bool
xorgGlxServerPreInit(const ExtensionEntry *extEntry)
{
if (glxGeneration != serverGeneration) {
/* Mesa requires at least one True/DirectColor visual */
if (!checkScreenVisuals())
return FALSE;

__glXContextRes = CreateNewResourceType((DeleteType) ContextGone,
"GLXContext");
__glXDrawableRes = CreateNewResourceType((DeleteType) DrawableGone,
Expand Down
73 changes: 50 additions & 23 deletions hw/xquartz/xpr/xprFrame.c
Original file line number Diff line number Diff line change
Expand Up @@ -106,11 +106,18 @@ xprCopyWindow(RootlessFrameID wid, int dstNrects, const BoxRec *dstRects,
int dx,
int dy);

static inline xp_error
static inline void
xprConfigureWindow(xp_window_id id, unsigned int mask,
const xp_window_changes *values)
{
return xp_configure_window(id, mask, values);
xp_error err = xp_configure_window(id, mask, values);

/* Log rather than drop a reconfigure silently: the implementation rejects every mask on a frame that is locked for
* drawing, which would otherwise leave a window on screen that the X server believes it has already moved, resized
* or unmapped.
*/
if (err != Success)
ErrorF("Could not configure window %d, mask 0x%x (%d).\n", (int)id, mask, (int)err);
}

static void
Expand Down Expand Up @@ -197,9 +204,9 @@ xprCreateFrame(RootlessWindowPtr pFrame, ScreenPtr pScreen,
return FALSE;
}

dispatch_async(window_hash_serial_q, ^ {
x_hash_table_insert(window_hash, pFrame->wid, pFrame);
});
dispatch_sync(window_hash_serial_q, ^ {
x_hash_table_insert(window_hash, pFrame->wid, pFrame);
});

xprSetNativeProperty(pFrame);

Expand All @@ -214,15 +221,15 @@ xprDestroyFrame(RootlessFrameID wid)
{
xp_error err;

dispatch_async(window_hash_serial_q, ^ {
x_hash_table_remove(window_hash, wid);
});
dispatch_sync(window_hash_serial_q, ^ {
x_hash_table_remove(window_hash, wid);
});

err = xp_destroy_window(x_cvt_vptr_to_uint(wid));
/* Not a FatalError: leaking the window costs us far less than terminating every client connected to the server.
*/
if (err != Success)
FatalError("Could not destroy window %d (%d).",
(int)x_cvt_vptr_to_uint(
wid), (int)err);
ErrorF("Could not destroy window %d (%d).\n", (int)x_cvt_vptr_to_uint(wid), (int)err);
}

/*
Expand Down Expand Up @@ -284,6 +291,9 @@ xprRestackFrame(RootlessFrameID wid, RootlessFrameID nextWid)
wc.sibling = x_cvt_vptr_to_uint(nextWid);
}

/* Unlike xprGetXWindow(), reading the record after the critical section is safe here because this only ever runs on
* the server thread, which is also the only thread that frees it.
*/
dispatch_sync(window_hash_serial_q, ^ {
winRec = x_hash_table_lookup(window_hash, wid, NULL);
});
Expand Down Expand Up @@ -355,6 +365,10 @@ xprStartDrawing(RootlessFrameID wid, char **pixelData, int *bytesPerRow)

err = xp_lock_window(x_cvt_vptr_to_uint(
wid), NULL, NULL, data, rowbytes, NULL);
/* Deliberately still fatal, unlike the failures either side of this: the implementation leaves data[] untouched on
* failure and RootlessStartDrawing() cannot refuse, so carrying on would hand fb an uninitialized pointer to draw
* through. Demoting this needs a way to report the failure upwards first.
*/
if (err != Success)
FatalError("Could not lock window %d for drawing (%d).",
(int)x_cvt_vptr_to_uint(
Expand Down Expand Up @@ -386,7 +400,7 @@ xprStopDrawing(RootlessFrameID wid, Bool flush)
* FatalError after http://xquartz.macosforge.org/trac/ticket/482 is fixed.
*/
if (err != Success)
ErrorF("Could not unlock window %d after drawing (%d).",
ErrorF("Could not unlock window %d after drawing (%d).\n",
(int)x_cvt_vptr_to_uint(
wid), (int)err);
}
Expand Down Expand Up @@ -476,10 +490,14 @@ xprInit(ScreenPtr pScreen)
rootless_CopyBytes_threshold = xp_copy_bytes_threshold;
rootless_CopyWindow_threshold = xp_scroll_area_threshold;

assert((window_hash = x_hash_table_new(NULL, NULL, NULL, NULL)));
assert((window_hash_serial_q =
dispatch_queue_create(BUNDLE_ID_PREFIX ".X11.xpr_window_hash",
NULL)));
window_hash = x_hash_table_new(NULL, NULL, NULL, NULL);
if (window_hash == NULL)
FatalError("Could not allocate window hash.");

window_hash_serial_q =
dispatch_queue_create(BUNDLE_ID_PREFIX ".X11.xpr_window_hash", NULL);
if (window_hash_serial_q == NULL)
FatalError("Could not create window hash queue.");

return TRUE;
}
Expand All @@ -491,14 +509,21 @@ xprInit(ScreenPtr pScreen)
WindowPtr
xprGetXWindow(xp_window_id wid)
{
RootlessWindowRec *winRec __block;
WindowPtr pWin __block = NULL;

/* Load the window inside the critical section. Letting the frame record escape it would defeat the point, since
* the server thread frees the record as soon as the frame is destroyed.
*/
dispatch_sync(window_hash_serial_q, ^ {
winRec =
RootlessWindowRec *winRec =
x_hash_table_lookup(window_hash,
x_cvt_uint_to_vptr(wid), NULL);

if (winRec != NULL)
pWin = winRec->win;
});

return winRec != NULL ? winRec->win : NULL;
return pWin;
}

/*
Expand Down Expand Up @@ -566,14 +591,16 @@ xprHideWindows(Bool hide)

Bool no_configure_window;

static inline int
/* As xprConfigureWindow(), but honoring no_configure_window so that responding to a native window change does not echo
* straight back to the implementation. Only the colormap and hide paths below go through this; the move, resize,
* restack, reshape and unmap hooks call xprConfigureWindow() directly and so are not suppressed.
*/
static inline void
configure_window(xp_window_id id, unsigned int mask,
const xp_window_changes *values)
{
if (!no_configure_window)
return xp_configure_window(id, mask, values);
else
return XP_Success;
xprConfigureWindow(id, mask, values);
}

static
Expand Down
6 changes: 4 additions & 2 deletions miext/rootless/README.txt
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,8 @@ typedef Bool (*RootlessCreateFrameProc)

/*
* Destroy a frame.
* Drawing is stopped and all updates are flushed before this is called.
* Drawing is stopped before this is called.
* The frame record stays valid for the duration of the call and is freed immediately afterwards.
*
* wid Frame id
*/
Expand All @@ -182,7 +183,7 @@ typedef void (*RootlessDestroyFrameProc)

/*
* Move a frame on screen.
* Drawing is stopped and all updates are flushed before this is called.
* Drawing is stopped before this is called.
*
* wid Frame id
* pScreen Screen to move the new frame to
Expand Down Expand Up @@ -232,6 +233,7 @@ typedef void (*RootlessReshapeFrameProc)

/*
* Unmap a frame.
* Drawing is stopped before this is called.
*
* wid Frame id
*/
Expand Down
6 changes: 4 additions & 2 deletions miext/rootless/rootless.h
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,8 @@ typedef Bool (*RootlessCreateFrameProc)

/*
* Destroy a frame.
* Drawing is stopped and all updates are flushed before this is called.
* Drawing is stopped before this is called.
* The frame record stays valid for the duration of the call and is freed immediately afterwards.
*
* wid Frame id
*/
Expand All @@ -123,7 +124,7 @@ typedef void (*RootlessDestroyFrameProc)

/*
* Move a frame on screen.
* Drawing is stopped and all updates are flushed before this is called.
* Drawing is stopped before this is called.
*
* wid Frame id
* pScreen Screen to move the new frame to
Expand Down Expand Up @@ -172,6 +173,7 @@ typedef void (*RootlessReshapeFrameProc)

/*
* Unmap a frame.
* Drawing is stopped before this is called.
*
* wid Frame id
*/
Expand Down
Loading