Commit Graph

36 Commits

Author SHA1 Message Date
lkn 16e07f751c wayland: fix modifier+drag grab — pass owner_events=1 in frameMouseDown
The pointer_grab call for Alt+drag (move/resize via MOD_MASK on client
surface) was passing owner_events=0.  wl_pointer_grab only sets
grab_type=3 and clears seat pointer focus when owner_events is True;
with 0 the grab returned success but left no grab state, so motion
events continued flowing to the client instead of the WM drag loop.

Pass 1 (True) to match the calls in resizebarMouseDown and
titlebarMouseDown, which work correctly.
2026-06-06 20:41:42 +02:00
Window Maker 654f24d8f8 fix: remove duplicate fake_leader check that short-circuited WINGs view reparent 2026-05-31 10:00:19 +02:00
Window Maker c968c0b6f9 fix: offset dialog content below titlebar (frame top_width) 2026-05-30 15:40:48 +02:00
Window Maker dcfc4f44f4 fix: exit dialog content not visible at correct position — reparent fake_leader tree into frame tree 2026-05-30 15:39:07 +02:00
Ollie 0abaf1fefa session: save/restore window state for Wayland native clients (match by app_id) 2026-05-28 22:14:32 +02:00
Window Maker 23f0bb320e wm core: shared src/ is now X11-free at the source level
Audit: every "X11 in src/" hit outside src/backend/x11/ and
src/backend/wayland/ is now either:
  - a comment mentioning X11 by name, or
  - a backend-neutral macro/type alias (WM_STATE_*, CW*, P*, etc.)
    whose numeric value happens to match the X11 protocol value.

Zero <X11/...> includes in shared headers/sources.
Zero X11 type uses (XColor/XContext/XEvent/XFontStruct/XGCValues/
XWindowAttributes/XSetWindowAttributes/XErrorEvent etc.).
Zero X11 symbol references in compiled shared object files
(verified: `nm src/*.o | awk '$1=="U"' | grep '^X[A-Z][a-z]'`
returns empty).

Real architectural fixes:

src/backend/backend_types.h — added the missing backend-neutral
constants/types so shared code never names an X11 macro:
  - WM_STATE_WITHDRAWN/NORMAL/ICONIC (ICCCM values 0/1/3).
  - WContextID (typedef int) — XContext analogue.
  - WMColorRGB (XColor-layout-compatible struct).
  - CWX..CWStackMode (ConfigureWindow value-mask bits).
  - ForgetGravity..StaticGravity (ICCCM win_gravity values).
  - PMinSize..PWinGravity (XSizeHints flags) as WNH_* aliases.
  - NoSymbol, NoEventMask, ColormapInstalled/Uninstalled.
  - BitmapSuccess..BitmapNoMemory.
All guarded by #ifndef so the X11 backend's <X11/X.h> include
overrides them with the real X11 values when present.

src/screen.h — w_visual is now `void *` (was `Visual *`).  Added
w_visual_id / w_visual_class so dialog.c's crash panel can read
visual info without dereferencing a Visual struct.  tech_draw_font
is also `void *` with companion tech_draw_font_ascent/descent ints
populated by the backend (X11 from XFontStruct->ascent, Wayland
from a hard-coded bitmap-font metric).

src/WindowMaker.h — XContext fields → WContextID, X11 includes
removed, Time → WMNativeTime.

src/dialog.c — wShowCrashingDialogPanel now uses WMOpenScreen +
WMScreenWidth/Height instead of DefaultScreen()/ScreenOfDisplay()/
WidthOfScreen() so it works in either backend.

Dead-code cleanup found while auditing:

src/event.c — handleUnmapNotify and handleEnterNotify both built
an uninitialized `XEvent ev` and ran it through x11_translate_event
on a peeked queue event.  The translation always read stack garbage
(the local was never populated).  Replaced with the correct flow:
  - unmap handler: skip wUnmanageWindow if a Destroy is already
    queued, the Destroy handler will run it next iteration.
  - enter handler: skip if a Leave for the same window is queued,
    no need to inspect mode/detail (was always reading garbage).
Also dropped the now-unused x11_compat.h / x11_event.h includes
from event.c, dock.c, window.c.

src/misc.c — eatExpose's `XEvent event, foo` were never used; the
function delegates to wm_backend->event_flush_type(WME_EXPOSE).

src/wsmap.c — workspace_map_destroy built an XEvent ClientMessage
but never sent it; the actual notify path is switchpanel_send_enter.
Pass the real root_win argument (was passing literal 0) and drop
the dead XEvent.

src/icon.c — set_dockapp_in_icon's `XWindowAttributes attr` and
cycleColor's `XGCValues gcv` were unused.

src/window.c — windowLanguageClick had a function-signature
mismatch with framewin.h's on_click_language (XEvent* vs WMEvent*).
The framewin code passes a WMEvent.  Fixed the parameter type and
its single use of event->xbutton.button.

src/moveres.c — already-disabled `#if 0` block in showPosition
that called XDrawLine / XSetForeground on the root window: removed.
Replaced tech_draw_font->ascent/descent dereferences with the new
flat int fields.

src/xutil.h — removed declarations of FormatXError (moved to X11
backend long ago) and Request/GetSelection (never implemented).

Mass renames in shared src/:
  IconicState/NormalState/WithdrawnState → WM_STATE_ICONIC/NORMAL/
                                            WITHDRAWN
  IconWindowHint/InputHint/StateHint/IconPixmapHint/IconMaskHint/
  IconPositionHint/WindowGroupHint/UrgencyHint
                                          → WMH_*_HINT
  XColor (in struct fields and locals)    → WMColorRGB
  XContext (in screen.context.{...})      → WContextID
  XPoint                                  → WMShortPoint
  XRectangle                              → WMShortRect
  XFontStruct *                           → void *

Backends translate at the boundary:
  src/backend/x11/x11_backend.c keeps its native XColor/XContext/
  XFontStruct internally and casts to the backend-neutral types
  at the public-API surface (memcpy works because WMColorRGB has
  XColor's exact layout).
  src/backend/wayland/wl_backend.c populates the same fields
  directly without any X11 indirection.

Verified:
  Default build: `Window Maker 0.96.0` runs.
  Shared src/ object files: `nm | grep '^X[A-Z][a-z]'` is empty.
  All shared X11 macro names (CW*, P*, ICCCM hint flags) are
  defined locally in backend_types.h, no X11 dep needed.

Out of scope (separate refactor): wmaker compositor binary itself
still links libX11 because src/backend/x11/* and the XWayland
integration in src/backend/wayland/wl_backend.c need real X11
types.  Both are below the vtable, so shared code is unaffected.
2026-05-24 12:52:31 +02:00
Window Maker fb817a7b27 wings: revert accidental WNativeWindow rename in strings/comments
The phase-β sed pass renamed every C 'Window' identifier to
WNativeWindow.  That correctly updated typedef uses but also rewrote
the string 'Window Maker', UI labels like 'Window Manager', 'Window
Placement', 'Window Title', 'Window List', 'Window System session',
etc., plus a number of comments referring to 'Window' as English.

Fixed all of those.  The C type uses (WNativeWindow rootWin, etc.)
remain unchanged — only English-language occurrences are reverted.
Verified that wmaker now reports 'Window Maker 0.96.0' again and
build is clean across WINGs/, src/, WPrefs.app/.
2026-05-24 11:42:37 +02:00
Window Maker 0f839a9c6d wings: phase β — rename X11 typedefs in shared/Wayland code
Sed pass restricted to files outside src/backend/x11 and outside
*_x11.c — i.e. all code that should not depend on X11 typedefs.

  Window     → WNativeWindow      (existing typedef in WMEvent.h)
  Atom       → WMNativeAtom
  Pixmap     → WMNativePixmap
  Cursor     → WMNativeCursor
  Drawable   → WMDrawable          (existing typedef)
  KeySym     → WMNativeKeysym
  Colormap   → WMNativeColormap

X11 backend files keep using the original Xlib type names because
they make Xlib API calls that take those types.  All typedefs are
ultimately 'unsigned long' so values pass through opaquely between
shared code and the backend.

Public WINGs API affected: WMSelectionCallback, WMSelectionProcs,
and a handful of widget signatures that took Atom/Window arguments
now take WMNativeAtom/WNativeWindow.  Source-compatible at the
binary level; consumers must rebuild.

Time and XID typedefs left for a follow-up — both are heavily used
in field/variable names that need careful auditing.  Display* and
GC stay in W_Screen for now; phase δ moves them into an X11-only
sub-struct.
2026-05-24 10:49:47 +02:00
Window Maker 1a49d6b857 wings: phase α.3 — rename X11 enum/macro values to WM_*
Mass rename of X11 enum values used in shared/Wayland code, with the
numeric values preserved so the wire layout of WMEvent fields and
the X11-backend translation tables remain unchanged.

  NotifyNormal/Grab/Ungrab/WhileGrabbed     → WM_NOTIFY_*
  NotifyAncestor/Virtual/Inferior/Nonlinear/
    NonlinearVirtual/Pointer/PointerRoot/
    DetailNone                              → WM_NOTIFY_*
  PropertyNewValue/Delete                   → WM_PROPERTY_*
  MappingModifier/Keyboard/Pointer          → WM_MAPPING_*
  VisibilityUnobscured/PartiallyObscured/
    FullyObscured                           → WM_VISIBILITY_*
  GrabModeAsync/Sync, GrabSuccess           → WM_GRAB_*
  RevertToParent/PointerRoot/None           → WM_REVERT_TO_*
  CurrentTime                               → WM_CURRENT_TIME
  None                                      → WM_NATIVE_NONE

The 'None' rename was done with conservative regex passes restricted
to clear C-context patterns (= None;, , None,, !=None, etc.) so that
'"None"' string literals in defaults and XPM 'c None' colour names
are preserved untouched.  Comments containing the English word 'None'
are also left alone.  X11 backend files that legitimately use the
X11 macros (Xlib calls returning None, etc.) are unchanged.

Build clean across WINGs, src, WPrefs.app.
2026-05-24 10:47:37 +02:00
Window Maker 82e3c3b65d wings: phase α.2 — rename X11 event masks to WM_EVMASK_*
Sed pass.  KeyPressMask, KeyReleaseMask, ButtonPressMask,
ButtonReleaseMask, EnterWindowMask, LeaveWindowMask,
PointerMotionMask, PointerMotionHintMask, Button{1..5}MotionMask,
ButtonMotionMask, KeymapStateMask, ExposureMask,
VisibilityChangeMask, StructureNotifyMask, ResizeRedirectMask,
SubstructureNotifyMask, SubstructureRedirectMask, FocusChangeMask,
PropertyChangeMask, ColormapChangeMask all renamed to the
corresponding WM_EVMASK_* names defined in wnative.h.

Numeric values still match the X11 layout, so wevent_x11.c's
matching tables and any code that masks bits keep working
unchanged.  Build clean across WINGs/, src/, WPrefs.app/.
2026-05-24 10:43:23 +02:00
Window Maker 5f65867974 wings: introduce wnative.h; phase α.1 (modifier/button masks)
WINGs API surgery, step 1.

New public header WINGs/WINGs/wnative.h declares WINGs-native types
and constants with no X11 header dependency:

  - WMNativePixmap/Atom/Cursor/Keysym/Time/XID/Colormap/Bool typedefs
    (all 'unsigned long' — compatible with the existing wire ABI).
  - WM_MOD_SHIFT/LOCK/CONTROL/MOD{1..5} modifier mask bits.
  - WM_BUTTON{1..5}_MASK pointer button mask bits.
  - WM_ANY_MODIFIER/WM_ANY_BUTTON sentinels.
  - WM_EVMASK_* event-mask bits (forthcoming patches).
  - WM_NOTIFY_* crossing modes/details.
  - WM_PROPERTY_* / WM_MAPPING_* / WM_VISIBILITY_* / WM_GRAB_* /
    WM_REVERT_TO_* / WM_CURRENT_TIME / WM_NATIVE_NONE.

Numeric values intentionally match X11 layout for binary
compatibility with WMEvent fields (which were defined that way
originally).  The architectural property that matters is that NONE
of the symbol *names* below are X11 macros — they belong to WINGs
and are defined without any X11 header.

WMEvent.h, WUtil.h, WINGs.h now #include <WINGs/wnative.h> so every
WINGs consumer picks up the new constants.  X11 headers are still
included from the public WINGs headers; phase ε will drop them.

Phase α.1 — first sed pass:

  ShiftMask     → WM_MOD_SHIFT
  ControlMask   → WM_MOD_CONTROL
  LockMask      → WM_MOD_LOCK
  Mod{1..5}Mask → WM_MOD_MOD{1..5}
  Button{1..5}Mask → WM_BUTTON{1..5}_MASK
  AnyModifier   → WM_ANY_MODIFIER
  AnyButton     → WM_ANY_BUTTON

Applied across WINGs/, src/, WPrefs.app/ via sed with word
boundaries.  Build verified clean; binary identical in size,
re-linked successfully.
2026-05-24 10:42:04 +02:00
Window Maker a2cb136f8a arch: move wmspec.c (EWMH) and xdnd.c (XDND) into src/backend/x11/
Both files implement X11-specific protocols (EWMH _NET_* and XDND).
They were sitting in shared src/ because they predated the backend
split; the only remaining users in shared code were now via
wm_backend-> dispatch.

To get there, four new vtable slots replace the last direct calls
from shared src/:

  screen_get_head_usable_area  (screen.c was calling wNETWMGetUsableArea)
  window_get_icon_image        (icon.c was calling get_window_image_from_x11)
  netwm_set_frame_extents      (window.c, winspector.c were calling wNETFrameExtents)
  (window_fetch_name and window_get_icon_name extended to consult EWMH first)

Other changes:
  * get_window_image_from_x11 now takes Display* explicitly so the
    Wayland backend can pass wl_state.x_display for XWayland clients
    instead of relying on a global (which is NULL on Wayland).
  * Eight shared .c files lose their now-unused #include "wmspec.h"
    or #include "xdnd.h".
  * Makefile.am moves wmspec.{c,h} and xdnd.{c,h} into the backend/x11
    listing.
  * src/Makefile.am drops the obsolete --disable-xdnd Makefile branch
    and unconditional sources list still references the new paths.

Final state: every Xlib call in the codebase lives in src/backend/x11/
or src/backend/wayland/.  The only remaining "X*(" matches outside
backend/ are six XSetForeground/XDrawLine calls in src/moveres.c
inside an \#if 0 block (dead code; left for now).  src/ has zero
_x11_raw references.
2026-05-24 09:16:39 +02:00
Window Maker 0950b228af feat: Wave 2 — eliminate direct Xlib calls and #ifdef guards
- R.5: usermenu.c: XStringToKeysym→xkb_keysym_from_name, XSendEvent guarded
- B.1: appicon.c: XClearArea→wm_backend->window_clear
- A4.1: workspace.c: remove 5 USE_XINERAMA guards, unified backend-neutral
- R.7: window.c: remove 4 USE_XSHAPE guards, vtable dispatch
2026-05-17 20:26:43 +02:00
Levi Neely 57536b9991 moveres: replace XEvent with WMEvent in move/resize functions
wMouseMoveWindow and wMouseResizeWindow took XEvent* but were
being passed WMEvent* via casts. The XEvent union layout differs
completely from WMEvent, so ev->xmotion.x_root read garbage —
causing the window to jump to a wrong position and the move to
become uncontrollable.

Changed both functions to take WMEvent*, accessing ev->u.button
fields directly. Removes all XEvent references from the core
policy layer (zero backend-specific types in the middle).
2026-05-14 13:15:34 +02:00
Levi Neely 4be05c799c Phase 84: eliminate all backend guards from policy code
Remove every is_wayland / !is_wayland guard from WM policy files.
All backend-specific logic now lives exclusively in the backends:

- main.c: display_post_open vtable slot handles fatal check, visual ID,
  display name, and multiHead parsing (X11) or no-ops (Wayland)
- event.c: EventLoop() unconditionally calls event_loop_run(); the X11
  backend's implementation contains the WMNextEvent+inotify loop
- screen.c: screen_init_display vtable slot handles RContext/WMScreen/
  color creation (each backend owns its full init path)
- monitor.c: show_crash_dialog vtable slot (X11 shows panel, Wayland
  returns abort)
- startup.c: InitializeSwitchMenu called unconditionally (it's
  backend-agnostic); defaults polling timer no longer guarded
- shutdown.c: wScreenSaveState called unconditionally
- window.c: client_reparent called unconditionally (Wayland no-ops);
  dead frameless-window code removed

Policy code is now completely backend-agnostic. The only references to
is_wayland are the vtable field definitions in the two backend files.
2026-05-14 12:41:01 +02:00
Levi Neely ac1dbd3b8e Phase 83: frame decorations for native Wayland clients
- Create WM frames (titlebar, buttons, resizebar) for native XDG
  toplevels — remove the is_wayland guard that skipped frame creation
- Set decoration mode to SERVER_SIDE so clients don't draw their own
  titlebar (CSD)
- Skip client_reparent for Wayland (no X11 reparenting needed; the
  client scene node is independent of the frame scene buffers)
- Set frame_border_width=0 in wl_screen_create_internals (Wayland has
  no X11-style window border; the frame_buf renders all decoration)
- Use wlr_scene_subsurface_tree_create for client surface (avoids XDG
  geometry offset issues)

Known issue: transient size mismatch on initial map when saved session
state or size constraints differ from the client's committed buffer.
Resolves after the client processes the configure event.
2026-05-14 12:18:13 +02:00
Levi Neely bf9a0a9cf5 Fix dialog titlebar and background rendering
- window.c: always call frame_paint for internal windows (title=NULL
  skipped wFrameWindowChangeTitle which was the only paint trigger)
- wview_wl.c: fill view backing with background color before expose
  (X11 server fills background automatically, Wayland needs explicit fill)
2026-05-13 21:34:07 +02:00
Levi Neely f2dfe4a4d0 Remove XEvent from frame callbacks (titlebar, resizebar, buttons)
All WFrameWindow callbacks (on_mousedown_titlebar, on_dblclick_titlebar,
on_mousedown_resizebar, on_click_left, on_click_right, on_dblclick_right)
now take WMEvent* instead of XEvent*. This fixes the crash when clicking
the menu titlebar in Wayland mode (_x11_raw was NULL).

Affected files: framewin.h, framewin.c, menu.c, window.c, dialog.c,
winspector.c. All verified X11-free with nm.
2026-05-13 17:27:02 +02:00
Levi Neely 9c48a0c841 Phase 80t: ZERO X11 symbols in policy files — architecture complete
- wmspec.c, xdnd.c, xmodifier.c: pure X11 mechanism code now compiled
  as part of x11_backend.o (included via #include in x11_backend.c).
  Removed from main link (Makefile modified).
- Policy file calls to NETWM/XDND functions replaced with vtable dispatch:
  netwm_process_client_message, xdnd_process_client_message,
  xdnd_process_selection, xdnd_make_awareness,
  netwm_check_client_hint_change, netwm_position_splash,
  netwm_check_initial_frame_state
- x11_prop_get_check_property now returns wfree-able memory (callers
  use wfree instead of XFree)

RESULT: nm -u *.o | grep ' U X' returns ZERO for all non-backend .o files.
The backend abstraction is architecturally complete.
2026-05-13 13:03:14 +02:00
Levi Neely b72d527ee7 Phase 80d: clean X11 from appmenu, main, switchpanel, window, xutil, texture
New vtable slots: appmenu_send, display_get_name, switchpanel_send_enter,
format_x_error, draw_bevel.

- appmenu.c: sendMessage dispatches through appmenu_send
- main.c: XDisplayName replaced with display_get_name
- switchpanel.c: XSendEvent replaced with switchpanel_send_enter
- window.c: XFree removed (backend owns cmap_windows lifecycle)
- xutil.c: FormatXError moved entirely to x11_backend.c
- texture.c: wDrawBevel dispatches through draw_bevel (done prev commit)

All 5 files verified X11-free with nm.
2026-05-13 10:42:06 +02:00
Levi Neely 9cfe322573 Phase 80b: eliminate if(dpy) guards and replace X11 calls with vtable dispatch
- Remove all 20 'if (dpy &&' guards from policy files
- Replace XMapWindow, XUnmapWindow, XMoveWindow, XClearWindow,
  XFreePixmap, XFlush, XSync, XResizeWindow, XSetWindowBackground,
  XSetWindowBackgroundPixmap, XMoveResizeWindow, XSelectInput,
  XMapRaised, XUngrabPointer, XUngrabKeyboard, XGrabKeyboard,
  XGrabServer, XUngrabServer, XRestackWindows, XDestroyWindow,
  XReparentWindow, XAddToSaveSet, XSetWindowBorderWidth
  with vtable dispatch across all policy files
- Make wFrameWindowPaint mechanism code: X11 backend's frame_paint
  now calls it; all policy call sites dispatch through vtable
- Replace dpy feature-gating in main.c/startup.c with is_wayland

Remaining: 278 dpy refs in policy files, mostly in rendering functions
(wIconPaint, wAppIconPaint, paintEntry, drawFrame, balloon, dock,
dialog, superfluous, event) that are X11 mechanism code reachable
only through the X11 backend path.
2026-05-13 10:21:00 +02:00
Levi Neely 553d2ca0ba Phase 80: eliminate all 43 if(!dpy) return guards via vtable dispatch
Remove every 'if (!dpy) return' guard from policy files by moving
X11 mechanism code behind WMBackend vtable slots. Call sites now
dispatch through wm_backend->slot(), the X11 backend implements the
mechanism, and the Wayland backend provides no-ops or Wayland-native
implementations.

New vtable slots added to backend.h:
- Frame: frame_alloc_border_pixel, frame_update_texture, frame_paint_button
- NETWM: netwm_init, netwm_cleanup, netwm_update_desktop,
  netwm_get_current_desktop, netwm_update_opacity, netwm_update_actions,
  netwm_check_client_hints, netwm_check_initial_state, netwm_get_pid,
  netwm_cleanup_frame_extents
- Properties: prop_get_protocols, prop_get_check_property,
  prop_set_wmaker_protocols, prop_set_icon_tile, prop_cleanup
- Client: client_restore, client_set_state, client_send_protocol,
  client_kill, client_get_colormap_windows
- Misc: eat_expose, move_window, slide_windows, get_text_selection,
  get_shortcut_string, get_command_for_window
- Icon: icon_update_pixmap, icon_paint
- AppIcon: appicon_show, appicon_paint, appicon_bounce
- Shutdown: restore_desktop, wipe_desktop
- Resources: get_color_for_colormap, free_color, colormap_install
- Protocol: xdnd_init, motif_get_hints
- Startup: manage_all_windows
- Event: event_handle_signal_exit

Structural changes:
- MWMHints moved from motif.c local typedef to motif.h
- WProtocols given struct tag for forward declaration
- Static functions made non-static: wGetTextSelection, wGetCommandForWindow,
  wGetMWMHints, wWipeDesktop, wManageAllWindows, wNETWMUpdateWindowOpacity

Verification: grep -rn 'if (!dpy)' src/*.c returns zero results.
nm wl_backend.o confirms no new X11 symbols in Wayland path.
2026-05-13 10:01:57 +02:00
Levi Neely 2bcc676202 wayland: fix XWayland window visibility
Two bugs prevented XWayland client windows from appearing:

1. flags.mapped never set for XWayland windows (window.c)
   The condition `else if (!dpy)` is false when dpy is the XWayland
   Display* (it is only true for pure native-Wayland mode with no X11).
   Changed to `else if (!dpy || wm_backend->is_wayland)` so XWayland
   windows also get flags.mapped=1 after wManageWindow, matching the
   semantics of XDG toplevel windows.

2. scene node positioned at xw->x,xw->y before configure round-trip
   handle_xwayland_map used xw->x,xw->y for the initial scene node
   position.  These values may not yet reflect the configure sent in
   handle_new_xwayland_surface (the X11 round-trip is async).  Changed
   to use view->x,view->y which are set to output/4 in
   handle_new_xwayland_surface and kept in sync by set_geometry listener.

Also added a log line when xw->surface is NULL at map time so the cause
is diagnosable from wmaker stderr.

Note: if xterm connects to the wrong DISPLAY (e.g. Sway's :1 instead of
wmaker's :2), no handle_xwayland_map fires at all.  Check wmaker's
"XWayland ready on :X" log line for the correct display number.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-31 16:54:21 +02:00
Levi Neely b44d556351 wayland: Phase 74 — frame NULL guards in window.c
wWindowConfigure: add early-return Wayland path that dispatches
client_synth_configure via vtable and updates client geometry instead
of trying to configure a non-existent X11 frame window.

wWindowSingleFocus: use client dimensions when frame is NULL for the
wScreenBringInside call.

wWindowSaveState: fall back to client width/height when frame is NULL
(non-maximized path).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-28 09:58:43 +01:00
Levi Neely c2c4f699f3 wayland: Phase 70 — apply WIN_WORKSPACE macro to all frame->workspace reads
Mechanically replace all remaining wwin->frame->workspace reads (41
occurrences across 9 source files) with the WIN_WORKSPACE(w) macro
introduced in Phase 69.  Write sites (inside if-dpy or if-frame guards)
retain direct frame->workspace assignments as they cannot reach Wayland.

Also fixes two sed-introduced malformations:
  - actions.c: tmp->WIN_WORKSPACE(prev) → WIN_WORKSPACE(tmp->prev)
  - placement.c: ((WIcon*)parent)->WIN_WORKSPACE(owner) → correct form

Files changed: actions.c cycling.c event.c moveres.c placement.c
               switchpanel.c window.c wmspec.c workspace.c

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-28 09:46:35 +01:00
Levi Neely 36aa1c5725 wayland: Phase 69 — WIN_WORKSPACE macro; safe workspace reads without frame
Add WIN_WORKSPACE(w) macro to window.h that returns frame->workspace
when the window has a frame (X11 path) or wwin->workspace when it does
not (Wayland path, set in Phase 67).

Replace all unsafe frame->workspace reads with WIN_WORKSPACE() in:
  - window.c:   wWindowObscuresWindow (workspace comparison + geometry),
                wWindowFocusPrev/Next (same-workspace filter),
                wWindowSaveState (state serialization)
  - session.c:  session save (workspace name lookup)
  - switchmenu.c: all five switch-menu workspace comparisons/lookups

Also guard wWindowObscuresWindow's frame->core width/height reads with
a ternary that falls back to client.{width,height} for frameless windows.

This eliminates the last class of NULL frame->workspace dereferences
reachable from workspace-switch, focus-cycle, session-save, and
switch-menu code paths.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-28 09:43:09 +01:00
Levi Neely e60dff8ffd wayland: Phase 67 — WWindow.workspace; safe workspace switching without frame
Add int workspace to WWindow so Wayland-managed windows (which have no
WFrameWindow and therefore no frame->workspace slot) can track their
workspace assignment.  Set wwin->workspace = workspace in the Wayland
branch of wManageWindow alongside the existing geometry recording.

Guard wWorkspaceForceChange against NULL frame dereferences: introduce a
tmp_workspace local that falls back to tmp->workspace when frame is NULL,
and protect the omnipresent workspace assignment the same way.  Also add
a NULL guard for tmp->icon->core in the miniwindow-unmap path.

This prevents NULL dereferences if workspace switching is triggered
(e.g., via a root-menu action) while Wayland windows are managed.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-28 09:38:07 +01:00
Levi Neely 6764c14863 wayland: Phase 62 — mapped flag, focus lifecycle, and keyboard clear-focus
Three related fixes to make the WM focus lifecycle work end-to-end in
the Wayland path:

1. window.c: set wwin->flags.mapped=1 for Wayland windows (the
   wWindowMap call in wManageWindow is guarded by if(wwin->frame)
   which is NULL in Wayland, leaving mapped=0 and causing wSetFocusTo
   to take the no-focus branch immediately).

2. screen.c: call screen_create_internals in the Wayland goto path;
   this was skipped by goto screen_done but is needed to set
   auto_focus=1 and clear initial keyboard focus via wlr_seat.

3. wl_backend.c: implement wl_screen_create_internals (sets
   no_focus_win=WNATIVE_NONE, auto_focus=1, clears seat focus);
   wl_focus_set now calls wlr_seat_keyboard_clear_focus and logs
   "focus_clear" when win==WNATIVE_NONE; remove the redundant direct
   wl_focus_set call from handle_toplevel_map since wManageWindow now
   handles focus via wSetFocusTo.

Smoke test: add check 20 verifying "focus_clear" is logged after the
last managed window unmaps.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-28 09:11:56 +01:00
Levi Neely c03581c81f wayland: Phase 52b — guard wWindowSynthConfigureNotify frame titlebar access
Add wwin->frame NULL check before accessing wwin->frame->titlebar in
wWindowSynthConfigureNotify so frameless Wayland windows do not
dereference a NULL frame pointer when a synthetic configure notify
is sent.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-28 07:12:50 +01:00
Levi Neely 8f0c54240e wayland: Phase 52 — guard wWindowMap/Unmap and misc X11 paths for NULL frame
Add if (wwin->frame) guards to wWindowMap and wWindowUnmap so that
frameless Wayland windows do not dereference wwin->frame->core->window.
Guard getCommandForWindow in misc.c against NULL dpy to prevent
XGetCommand crash when the PID-based haveCommand path fires.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-28 07:09:20 +01:00
Levi Neely 14da9a65ae wayland: Phase 50 — client_get_pid via wl_client_get_credentials; misc guards
Implement wl_client_get_pid using wl_resource_get_client +
wl_client_get_credentials so the WM can retrieve the OS PID of
Wayland clients.  Guard getCommandForWindow in misc.c against NULL
dpy to prevent XGetCommand crash when the real PID path fires.
Guard wWindowChangeWorkspace against NULL frame for frameless
Wayland windows.  Log pid= in the wManageWindow-succeeded line;
add Phase 50 pid check to smoke test.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-28 07:03:55 +01:00
Levi Neely 69cee6fb15 wayland: Phase 45 — pointer_query returns on-screen; focus path guarded
pointer_query / pointer_query_full: return 1 when compositor is running
(wl_state.started) so the same_screen check in wManageWindow passes and
wSetFocusTo is called for newly mapped XDG toplevels.

Guard frame-dependent calls in the focus update path:
  - wWindowFocus (window.c): guard wFrameWindowChangeState on frame!=NULL
  - wWindowUnfocus (window.c): same; also guard wFrameWindowPaint on
    owner->frame when clearing semi-focus on transient owner

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-28 06:43:16 +01:00
Levi Neely 490ecb34ff wayland: Phase 40 — wire toplevel unmap to wUnmanageWindow
Guard all dpy==NULL / frame==NULL crash sites in the unmanage path:
  - wUnmanageWindow (window.c): frame ptr set to NULL-safe expression;
    window_unmap, raise_delay timer, and owner border change all
    guarded on frame != NULL
  - wSelectWindow (actions.c): early return if !wwin->frame
  - wNETCleanupFrameExtents (wmspec.c): early return if !dpy
  - wClientRestore (client.c): early return if !dpy

Wire handle_toplevel_unmap → context_find → wUnmanageWindow(destroyed=True)
so XDG toplevels are removed from scr->focused_window on client disconnect.

Smoke test: add Phase 40 check — grep "toplevel unmapped".

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-28 06:34:15 +01:00
Levi Neely ca09635129 wayland: Phase 39 — wire toplevel map to wManageWindow
Guard all dpy==NULL crash sites reached from wManageWindow:
  - wNETWMGetPidForWindow (wmspec.c) — XGetWindowProperty with NULL dpy
  - wNETWMCheckClientHints (wmspec.c) — XGetWindowProperty
  - wNETWMCheckInitialClientState (wmspec.c) — XChangeProperty chain
  - getMWMHints (motif.c) — XInternAtom before NULL dpy check
  - wClientSetState (client.c) — XChangeProperty
  - wColormapInstallForWindow (colormap.c) — XGetWindowAttributes
  - wWindowSetKeyGrabs (window.c) — frame->core->window dereference

Wire handle_toplevel_map → wManageWindow(scr, view->id) so mapped
XDG toplevels appear in scr->focused_window.  Log success via
"wl_backend: wManageWindow succeeded id=0x%lx".

Smoke test: add Phase 39 check — grep "wManageWindow succeeded".

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-28 06:23:23 +01:00
Levi Neely a486329b52 Wayland backend abstraction: WMBackend vtable (Phases 0–30)
Introduce a display-system-agnostic WMBackend vtable that routes all
display operations through function pointers, making the WM policy
layer independent of X11.  The X11 implementation is preserved in
src/backend/x11/ and behaviour is unchanged.

Key structural changes
──────────────────────
• src/backend/backend_types.h — backend-neutral type definitions:
    WNativeWindow, WKeyCode, WContextKey, WBackendScreen,
    WBackendEvent (+typed fields), WNormalHints, WWMHints,
    WNETWindowType, WHeadGeometry, WClientAttributes, WClientVisual,
    WSegment, WPoint, WM_KEY_* keysym constants, WA_* atom IDs,
    WKB_GROUP*_INDEX, WCUR_NONE

• src/backend/backend.h — WMBackend vtable (~100 function-pointer
    slots) covering: frame/context lifecycle, stacking, focus, grabs,
    pointer, keyboard, overlays, properties, ICCCM, EWMH/NETWM,
    monitors, screen setup, cursors, extensions, error handlers.
    No <X11/> headers remain in this file after Phase 30.

• src/backend/x11/ — X11 backend implementation:
    x11_backend.c  full vtable; all display calls confined here
    x11_props.c    WM_NORMAL_HINTS / WM_HINTS translation
    x11_event.c    XEvent → WBackendEvent translation
    x11_monitor.c  Xinerama / RandR monitor query

Policy files cleaned
────────────────────
All 47 files in WM_POLICY_CLEAN_FILES pass check-no-x11-policy
(no direct #include <X11/> anywhere).  X11 types that still appear
in policy structs (Visual*, Colormap, Window, Atom …) arrive only
transitively via WINGs.h; the vtable boundary itself is X11-free.

Tests
─────
• tests/smoke-test.sh — full Xvfb lifecycle test (PASS)
• tests/test_geom.c   — geometry / constraint unit tests
• tests/test_x11_event.c — WBackendEvent field extraction tests

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-27 19:20:00 +01:00
Levi Neely fcee811b99 WindowMaker 0.96.0 upstream source 2026-03-26 15:38:49 +01:00