Skip to content

shameful pr - #868

Open
SamHSmith wants to merge 3 commits into
EpicGames:masterfrom
SamHSmith:master
Open

shameful pr#868
SamHSmith wants to merge 3 commits into
EpicGames:masterfrom
SamHSmith:master

Conversation

@SamHSmith

Copy link
Copy Markdown

This has some linux fixes.

@SamHSmith
SamHSmith force-pushed the master branch 2 times, most recently from 09e8377 to 6d0e265 Compare July 17, 2026 22:50
We always draw our own window decorations (title bar, borders, resize
edges), so we never want the window manager to add server-side ones on
top. Set the legacy _MOTIF_WM_HINTS property with MWM_HINTS_DECORATIONS
and decorations=0 at window creation; this is honored by effectively
every modern WM (Mutter/GNOME, KWin/KDE, XFWM, Openbox, i3, ...)
including XWayland.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

linux/x11: move & resize borderless window via _NET_WM_MOVERESIZE

Disabling server-side decorations also removed the window manager's
move/resize affordances, leaving the window stuck in place. Since we
draw our own title bar & borders, implement the hit-testing ourselves:
the frontend already describes the custom title bar, resize edges, and
the interactive "client area" sub-rects each frame (via the previously
stubbed wm_window_push_custom_* calls), so store that data per-window
and, on a left button press, translate it into an EWMH
_NET_WM_MOVERESIZE request that hands the interactive drag off to the
window manager. This mirrors the Win32 WM_NCHITTEST path.

Presses over a title-bar client area (menu items, window buttons) or
the window body are delivered normally, so those widgets keep working.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

linux/x11: render during interactive resize + resize-edge cursors

Two fixes for the borderless move/resize:

- Render during resize. The window did not select StructureNotifyMask,
  so no ConfigureNotify arrived while the WM drove an interactive resize
  (the pointer is grabbed by the WM, so no other events flow either) and
  nothing repainted until the drag ended. Select structure notifications
  and turn ConfigureNotify/Expose into Wakeup events so the main loop
  renders a frame at each new size.

- Resize cursors. On mouse motion, hit-test the pointer against the
  custom resize edges and override the cursor with the matching
  left-right / up-down / diagonal resize cursor while hovering an edge
  (a title-bar widget under the pointer still wins, as with clicks).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

linux/x11: frame-synced resize via _NET_WM_SYNC_REQUEST

Implement the basic _NET_WM_SYNC_REQUEST protocol correctly so the
compositor holds off compositing until our frame for the new size is
ready, eliminating resize stutter/tearing.

Previously the sync counter was updated immediately in the event
handler, before the frame was drawn, which defeats the protocol (the
compositor is told "ready" while the old-size frame is still on screen).
Instead, remember the requested sync value on the request, and set the
counter only after the frame is presented (from the GL swap, for both
the glx and egl backends).

Also fixes a truncation bug: the counter was set with XSyncIntToValue
(32-bit), dropping the high 32 bits of the 64-bit sync value; use
XSyncIntsToValue with the full hi/lo pair.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

linux: native Wayland window-manager backend (opt-in: build.sh raddbg wayland)

Add a native Wayland backend alongside the X11 one, selected at compile
time via the WM_WAYLAND define (`./build.sh raddbg wayland`). It renders
through EGL/wl_egl_window and implements the full wm_ API:

- xdg-shell (xdg_wm_base/xdg_surface/xdg_toplevel) with client-side
  decorations requested via xdg-decoration, so we draw our own.
- Frame-perfect resize the Wayland-native way: on xdg_surface.configure
  we resize the wl_egl_window, ack_configure, and the next EGL commit is
  atomically the acked size - no XSync counter needed.
- Input via wl_pointer + wl_keyboard (xkbcommon), including key repeat
  (timerfd) and modifier tracking.
- Interactive move/resize handed to the compositor via xdg_toplevel
  move/resize, with the same custom title-bar/edge hit-testing and
  resize-edge cursors (wl_cursor) as the X11 backend.

Color correctness: request an sRGB-capable EGL config (probed, since the
first matching config often fails sRGB surface creation and silently
falls back to linear), so the final blit's linear->sRGB encode matches
the GLX path exactly; and mark the surface opaque to avoid alpha-blend
color shifts.

Generated xdg-shell / xdg-decoration protocol code is committed under
src/linux/window_manager/generated.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

linux: one binary with runtime X11/Wayland selection (no compile-time switch)

Previously the Linux window backend was chosen at compile time
(WM_WAYLAND). Now a single build compiles BOTH backends and picks one at
runtime, so `./build.sh raddbg` just works on either display server.

- The per-OS wm_ functions in each backend are renamed wm_x11_* / wm_wl_*,
  and a small dispatch layer (linux_window_manager_dispatch.c) implements
  the public wm_* API, forwarding to the active backend via lnx_wm_backend.
- Selection (wm_init): prefer Wayland, fall back to X11 if the Wayland
  connect fails or no session is present. RADDBG_BACKEND=x11|wayland
  overrides; an absent WAYLAND_DISPLAY implies X11. wm_wl_init now returns
  a bool instead of aborting, so the fallback is graceful.
- Rendering uses EGL for both backends (GLX can't drive Wayland); the EGL
  init/equip/swap branch on lnx_wm_backend at runtime, picking the native
  display/window and doing the X11-only _NET_WM_SYNC_REQUEST ack. The
  sRGB-capable-config probe now runs for both, and X11 additionally
  extracts the matching X visual.
- build.sh always links X11 + Wayland (x11 xext wayland-client wayland-egl
  wayland-cursor xkbcommon) and defaults the GL backend to EGL.

Verified all three selection paths (Wayland default, RADDBG_BACKEND=x11,
absent WAYLAND_DISPLAY) from a single binary; X11 path renders correctly.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

raddbg: thicken window resize border to 4px for an easier grab target

window_edge_px feeds both the visual border inset and the resize hit
region (via wm_window_push_custom_edges), shared by the X11 and Wayland
backends. Bump it from ~3.4px to a DPI-scaled 4px at 96 DPI.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
SamHSmith and others added 2 commits July 29, 2026 16:38
Both wm_set_clipboard_text / wm_get_clipboard_text were stubs on Linux, so
copy and paste silently did nothing on either backend. Implement them
natively for both.

X11 has no clipboard, only *selections*: a name the server associates with a
window, whose owner is expected to answer conversion requests from every
other client for as long as it runs (ICCCM ch.2). So:

- Ownership and replies hang off one never-mapped 1x1 window created at init,
  not off a real window, because the clipboard has to keep working after the
  window the text was copied from is closed.
- We answer TARGETS, TIMESTAMP, MULTIPLE, UTF8_STRING, text/plain,
  text/plain;charset=utf-8, TEXT and STRING. STRING is converted down to
  Latin-1 as the spec requires (lossy, but that target only exists for
  clients old enough not to know UTF8_STRING); everything else is UTF-8.
- Payloads too large for a single X request are handed over incrementally via
  INCR, in both directions. Sending drips one chunk per PropertyNotify as the
  requestor deletes the property; receiving does the reverse. The receive side
  has to discard the stale PropertyNotify for the INCR header itself, which
  the owner writes *before* notifying us, or the first chunk read races
  against a property that is no longer there.
- Pasting waits for SelectionNotify with XCheckIfEvent + poll rather than
  XNextEvent, so unrelated events stay queued for the main loop, and keeps
  servicing incoming SelectionRequests while it blocks - otherwise a client
  pasting from us at that moment would stall for its own timeout.
- Selection claims and conversion requests carry the newest server timestamp
  we have seen instead of CurrentTime, falling back to CurrentTime if the
  server rejects the claim (which it does when our timestamp predates the
  current owner's).
- SelectionClear re-checks ownership before dropping our text: our own
  re-claim can overtake the clear for a *previous* loss, and acting on it
  would throw away a copy the user just made.
- An X error handler is installed, but it only swallows errors raised while we
  are mid-request to a foreign window - which legitimately races with that
  client being destroyed, and would otherwise take the process down through
  Xlib's default handler. Outside that window it defers to whatever handler
  was installed before us, or stands in for the Xlib default.

Wayland moves the payload itself rather than a reference to it, so copying
means publishing a wl_data_source and filling a pipe whenever somebody pastes,
and pasting means reading a wl_data_offer's pipe. The core-protocol
wl_data_device_manager bindings are hand-declared alongside the existing
wl_* ones. Notes:

- Reading our own offer would deadlock (the compositor would ask us to fill
  the pipe while we sit blocked on the other end), so while we own the
  selection we answer from our own copy.
- The source's `send` runs on the event-dispatch thread with a pipe whose
  reader may stall or vanish, so writes are non-blocking, bounded, and done
  with SIGPIPE blocked. SIG_IGN is deliberately not used: ignored dispositions
  survive exec and would change SIGPIPE behavior for every process we launch
  and debug.
- Offers are tracked in a small free-list keyed by the proxy's user data, and
  pruned on every selection / dnd leave / drop, so drag & drop offers we do
  not use cannot accumulate.

Verified on X11 against xclip: UTF-8 round trips both ways, every advertised
target converts, MULTIPLE converts the good pairs and rewrites the refused
one to None, and a 5MB payload transfers byte-identically in both directions
over INCR. The Wayland path is implemented but has not been run against a
live compositor.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

1 participant