Commit Graph

761 Commits

Author SHA1 Message Date
Window Maker 60348da411 Implement wmaker-popup-v1 Wayland protocol for client-driven popup positioning
Standard xdg_shell does not allow Wayland clients to position toplevels —
the compositor decides placement.  WINGs UI patterns require client-driven
positioning (e.g., a dropdown popup must appear directly below its trigger
button; menu editor items must be placed by the client at specific screen
coordinates).

This protocol lets the client wrap an xdg_toplevel with a wmaker_popup
object and call set_position(x, y) before the surface is mapped.  The
compositor honours the requested position when the surface becomes visible
and on subsequent set_position calls.

Files:
- protocols/wmaker-popup-v1.xml: protocol definition
- src/Makefile.am, src/Makefile: server-protocol.h + protocol.c generation
- WINGs/Makefile.am, WINGs/Makefile: client-protocol.h + protocol.c generation
- src/backend/wayland/wl_backend.c: wmaker_popup_manager global, get_popup
  handler that wraps an xdg_toplevel; set_position handler that updates
  view->popup_x/y and calls wmaker_popup_apply to move the frame_buf
  scene tree.  Apply runs at toplevel_map time too for pre-map positions.
- WINGs/wclient_wl.c: bind manager in registry, wrap popup toplevels with
  wmaker_popup, expose W_WLClientPopupSetPosition.
- WINGs/wview_wl.c: wl_move calls W_WLClientPopupSetPosition for popup
  toplevels so WMMoveWidget propagates to the compositor.
- WINGs/wevent_wl.c: wl_move_window also routes to popup positioning.
2026-05-24 18:27:55 +02:00
Window Maker fd73e94a58 WINGs/wview_wl: stub pointer_grab/ungrab; mark unmanaged toplevels popup
WMPopUpButton's popUpMenu calls viewBackend->pointer_grab which was
NULL on Wayland — calling NULL function pointer crashed WPrefs when
clicking the popup dropdown. Provide no-op stubs (Wayland uses implicit
grab on button press).

Also mark W_CreateUnmanagedTopView views with flags.popup=1 so they
go through the same borderless/skip-taskbar path as editmenu standalone
windows.
2026-05-24 18:05:36 +02:00
Window Maker 3761bef513 WPrefs: make crash handler async-signal-safe with write/fsync
Previous version used fprintf which buffers and may not flush before
_exit if the crash happened mid-libc. Use write() + fsync() so the
backtrace appears in the log even if the crash is deep in a library.
2026-05-24 18:01:43 +02:00
Window Maker 04e6b348b2 Implement popup-style toplevels for menu editor on Wayland
The WPrefs menu editor creates standalone draggable windows for each
menu item via W_CreateTopView. On X11 these are override-redirect
windows. On Wayland they were becoming framed XDG toplevels with
taskbar entries, cluttering the desktop with phantom 'WINGs...' tabs.

Implementation:
1. New W_View flags.popup field, set by editmenu's standalone mode
2. wclient_wl: when realizing a popup view, set xdg_toplevel app_id
   to 'wings-popup' as a hint to the compositor
3. wmaker compositor: detect 'wings-popup' app_id in toplevel_map,
   set borderless + skip-taskbar + skip-switchpanel flags, then call
   wWindowConfigureBorders to rebuild the frame without decorations
4. New W_EventBackend->window_begin_move vtable method:
   - X11: returns False (caller runs manual drag loop)
   - Wayland: calls xdg_toplevel_move, returns True (compositor drives drag)
5. editmenu's dragMenu calls window_begin_move first; on Wayland the
   compositor handles the entire drag, so the manual loop is skipped
2026-05-24 17:58:58 +02:00
Window Maker e01dedb833 WINGs/wclient_wl: set button.x/y in motion events for widget compat
WMEButton.x is at offset 40, WMEMotion.x is at offset 48. The
scroller widget reads event->u.button.x for motion events (legacy
X11 code where XButtonEvent and XMotionEvent have x at the same
offset). Set both union members so widgets reading either get
correct coordinates.
2026-05-24 17:37:24 +02:00
Window Maker 7efede0274 WINGs/wclient_wl: implement implicit pointer grab for drag operations
On X11, a button press creates an implicit pointer grab — all
subsequent motion and release events go to the window that received
the press, even if the pointer moves outside it. This is essential
for scroller knob dragging, window resize handles, etc.

Implement the same for Wayland client: on button press, record the
target view as wlc_ptr_grab. Motion events during the grab are
delivered to the grabbed view with coordinates translated relative
to it. On button release, deliver to the grabbed view and clear
the grab. Enter/leave synthesis is suppressed during grabs.
2026-05-24 17:33:50 +02:00
Window Maker d6767530e4 WINGs/wview_wl: fix configure event to trigger SubstructureNotify
The viewport's event handler is registered for SUBSTRUCTURE_NOTIFY.
WMHandleEvent switches from STRUCTURE_NOTIFY to SUBSTRUCTURE_NOTIFY
when event.window != configure.event. The event was incorrectly
setting both to the parent window. Fix: set event.window to the
child (resized view) so the mismatch triggers the SubstructureNotify
path.
2026-05-24 17:28:20 +02:00
Window Maker 7b8a6cca3f WINGs/wview_wl: send WME_CONFIGURE to parent on child resize
On X11, resizing a child window generates a ConfigureNotify event
delivered to the parent. Scroll views rely on this to update scroller
proportions when the content view is resized. On Wayland, wl_resize
never generated this event, so the scroller's documentFullyVisible
flag stayed at 1 (set during initial setup when content was small)
and paintScroller drew only a stippled 'full' indicator instead of
the knob/track.

Fix: when a mapped non-toplevel view is resized, dispatch a
WME_CONFIGURE event to its parent synchronously.
2026-05-24 17:27:03 +02:00
Window Maker 4abb21dcf6 debug: log scroller child in scroll view 2026-05-24 17:23:33 +02:00
Window Maker 3337bc110b WINGs: implement XDG toplevel min/max size to prevent resize
WMSetWindowMinSize/MaxSize were no-ops on Wayland. Implement
wl_window_set_geometry to call xdg_toplevel_set_min_size/max_size.
WPrefs sets min=max=520x390, making it non-resizable.
2026-05-24 17:22:53 +02:00
Window Maker b4dbf15817 WINGs: dispatch WME_CONFIGURE synchronously before redisplay on resize
The configure event was enqueued for later processing but the redisplay
happened immediately, painting children at their old positions. Now
WMHandleEvent is called directly with the configure event so widget
delegates relayout children before the redisplay paints them.

Also removed scroller debug logging.
2026-05-24 17:15:36 +02:00
Window Maker 53b23a582c debug: check for unmapped children in scroll view 2026-05-24 17:13:26 +02:00
Window Maker 577e2d6c45 WINGs: send WME_CONFIGURE on resize + debug scroller iteration
- Send WME_CONFIGURE event after xdg_surface configure resize so
  widget delegates can relayout children.
- Add temporary debug to identify why scroller isn't rendering.
2026-05-24 17:12:02 +02:00
Window Maker 1038146e94 WINGs: repaint content after XDG surface configure resize
When the compositor sends a new size via xdg_surface.configure, the
client buffer was reallocated but content was never repainted into it.
The surface was committed with an empty buffer, making the window
content disappear after resize.

Fix: after resizing the buffer in xdg_surface_handle_configure, call
wl_redisplay on the toplevel view to repaint all widget content into
the new buffer before committing.
2026-05-24 17:09:13 +02:00
Window Maker 85216efeea WINGs/wview_wl: redisplay toplevel when non-toplevel view is mapped
Non-toplevel views mapped after the toplevel (e.g., icon buttons added
during Init* calls) need to trigger a redisplay to become visible.
Instead of redisplaying the view itself (which crashed during
realization), find the toplevel ancestor and redisplay from there.

Guards:
- All ancestors must be realized (prevents crash during W_RealizeView)
- Toplevel must be mapped (prevents premature redisplay)
- wl_redisplay_depth==0 (prevents re-entrancy)
2026-05-24 17:02:13 +02:00
Window Maker 9873adf689 WINGs/wview_wl: only trigger wl_redisplay from wl_map for toplevels
The parent-backing-check approach was too fragile. Simplify: wl_map
only triggers wl_redisplay for toplevel views. Non-toplevel views
become visible through:
1. render_wl_pixmap_copy composite-up (when widget paints itself)
2. wl_map_subviews (which redisplays the parent after mapping children)
3. Parent's recursive wl_redisplay (which iterates all mapped children)

This avoids crashes during W_RealizeView recursion where children are
mapped before the widget tree is fully constructed.
2026-05-24 16:58:58 +02:00
Window Maker 66f9d19106 WINGs/wview_wl: don't redisplay from wl_map if parent lacks backing
During W_RealizeView recursion, children are realized and mapped
before their parent's backing pixman image exists. wl_map triggered
wl_redisplay which sent an expose event, the widget painted itself,
and render_wl_pixmap_copy tried to composite up through the parent
chain — hitting a NULL pixman image in pixman_image_composite32.

Fix: before triggering wl_redisplay from wl_map, walk up the parent
chain and verify all ancestors have valid backings. If any ancestor
lacks a backing (still being realized), skip the redisplay — the
parent's wl_map will handle it once the full tree is ready.
2026-05-24 16:56:08 +02:00
Window Maker b2f878314c WPrefs: replace X11 WidthOfScreen/HeightOfScreen with WMScreenWidth/Height
WindowHandling.c and Icons.c called WidthOfScreen(DefaultScreenOfDisplay(
WMScreenDisplay(scr))) which dereferences NULL on Wayland (no X Display).
Use WMScreenWidth/WMScreenHeight instead — these work on both backends.

Also added temporary SIGSEGV backtrace handler to main.c for debugging.
2026-05-24 16:54:34 +02:00
Window Maker 50bc0d35aa WINGs/wview_wl: prevent re-entrant wl_redisplay from wl_map
When a panel's createWidgets callback maps child widgets, each
WMMapWidget triggered wl_redisplay which sent expose events. Those
expose handlers could create/destroy more widgets, causing re-entrant
modification of the view tree during iteration — segfault.

Fix: track wl_redisplay call depth. wl_map only triggers wl_redisplay
when depth==0 (not already inside a redisplay). Child views mapped
during a redisplay cycle will be painted by the parent's recursive
child iteration instead.

Also save nextSister before recursing into children to handle list
modifications during iteration.
2026-05-24 16:20:43 +02:00
Window Maker 8d77acc349 WINGs: guard against destroyed views in redisplay and composite-up
When a button click triggers changeSection which destroys widgets
(nameL, versionL, statusL) and then maps new ones, the recursive
wl_redisplay and the composite-up in render_wl_pixmap_copy could
encounter views marked alreadyDead or with freed backings.

Add alreadyDead checks to:
- wl_redisplay entry (skip dead views)
- wl_redisplay child iteration (skip dead children)
- render_wl_pixmap_copy composite-up loop (stop at dead views)
2026-05-24 16:17:06 +02:00
Window Maker 777a5229eb wl_backend: fix shadowed sx/sy in wl_update_pointer_focus
The inner 'double sx, sy' declaration shadowed the outer one. When
view_surface_at succeeded inside the frame_buf check, the surface-local
coordinates were written to the inner variables and lost. The outer
sx/sy (used by wlr_seat_pointer_notify_enter/motion) remained
uninitialized, causing the client to receive garbage coordinates.

Also removed debug print from wclient_wl.c.
2026-05-24 16:14:10 +02:00
Window Maker 1d1f5bdc71 wl_backend: forward pointer events to client surface in client area
frame_buf_at() matches the entire window frame tree including the
client content area. This caused wl_update_pointer_focus to never
set seat pointer focus on the client surface, so Wayland clients
(like WPrefs) never received pointer enter/motion/button events.

Fix: when frame_buf_at returns a hit, also check view_surface_at.
If a client surface is found at the pointer position, use it instead
of treating the area as WM-internal decorations.
2026-05-24 16:04:25 +02:00
Window Maker 7e21ae259a WINGs/wrender_wl: composite up to toplevel after pixmap_copy to view
On X11, painting to a window pixmap (via XCopyArea in the DOUBLE_BUFFER
path) makes content immediately visible because the X server handles
display. On Wayland, writing to a view's backing pixman image has no
effect until it's composited up through the parent chain to the toplevel
surface and committed.

When render_wl_pixmap_copy detects the destination is a registered view
backing (ID in 0x10000000-0x2FFFFFFF range), it now walks up the parent
chain compositing each view into its parent, then commits the toplevel.
This makes widget paint operations (labels, buttons, frames) immediately
visible without requiring a full wl_redisplay cycle.
2026-05-24 15:55:12 +02:00
Window Maker 50096c7487 WINGs/wview_wl,wclient_wl: fix rendering and input for child views
Rendering: wl_map only triggered wl_redisplay for topLevel views.
Non-toplevel views (buttons, frames, labels) were mapped but never
painted. Now wl_map calls wl_redisplay for any realized view.
wl_redisplay already recurses into children, so wl_map_subviews is
simplified to just set mapped flags then redisplay the parent.

Input: pointer events were delivered to the toplevel view because
Wayland has a single surface per window (unlike X11 where each widget
has its own window). Added hit-testing via W_FindViewAtPoint to route
button press/release and motion events to the correct child view.
Also synthesizes enter/leave events as the pointer moves between
child views (needed for button highlight on hover).
2026-05-24 15:49:05 +02:00
Window Maker c70fec7f56 WINGs/wview_wl: recursively redisplay children in wl_redisplay
wl_redisplay fills the view's background then paints widget content
via expose, but never re-composited child views. Children painted
earlier were erased by the parent's background fill. Now recursively
calls wl_redisplay on all mapped+realized children after the parent's
expose handler, so the full widget tree composites bottom-up.
2026-05-24 15:38:04 +02:00
Window Maker 9a9cc9e9df WINGs/wclient_wl: pass NULL to wl_display_connect for default socket
WPrefs passes display_name="" by default. wl_display_connect("")
treats the empty string as a literal socket name and fails. Pass NULL
instead so it uses $WAYLAND_DISPLAY. Also handle the literal string
"wayland" (from detect matching) the same way.
2026-05-24 15:34:09 +02:00
Window Maker bc431e5727 WINGs/wclient_wl: create RContext before WMCreateScreenWithRContext
wlclient_open passed NULL as the RContext, causing a segfault in
RConvertImageMask (called from makePixmap during screen init) when
WPrefs.app launched under Wayland.

Fix: call RCreateContextWayland() to create a valid 32-bit ARGB
context before passing it to WMCreateScreenWithRContext.
2026-05-24 15:31:41 +02:00
Window Maker 7a422330f6 defaults: use nanosecond mtime precision to detect rapid file writes
The user-facing root menu's 'Background → Images → Tiled' menu item runs
'wmsetbg -u -t image.jpg', which internally invokes wdwrite TWICE in
rapid succession:
  1. wdwrite WindowMaker SmoothWorkspaceBack NO
  2. wdwrite WindowMaker WorkspaceBack '(tpixmap, ...)'

Both writes complete within the same wall-clock second. The previous
mtime check used time_t (1-second precision):
  if (timestamp < stbuf.st_mtime)

After the first write, wmaker reads the file (only SmoothWorkspaceBack
changed; WorkspaceBack still old) and sets timestamp = current second.
The second write happens in the same second, so st_mtime equals
timestamp exactly — the check fails and the second write is silently
ignored. The user has to invoke the menu twice for the change to apply.

Fix: WDDomain.timestamp is now struct timespec (nanosecond precision).
New MTIME_NEWER() macro compares full timespec values. Two writes within
the same second now have distinct nanosecond components so both are
detected.

Also removed all debug logging.
2026-05-24 15:24:03 +02:00
Window Maker 861082f1ad wl_backend: react to IN_MOVED_TO, skip temp files
The atomic-rename pattern (mkstemp + rename) generates two relevant
events per save: IN_CLOSE_WRITE on the temp file (e.g.
WindowMaker.AjuyyW), then IN_MOVED_TO on the destination (WindowMaker).

Previously we reacted to IN_CLOSE_WRITE first and set oneShotFlag,
which then suppressed the IN_MOVED_TO. But at the time of
IN_CLOSE_WRITE, the rename hadn't happened yet — stat(WindowMaker)
returned the OLD mtime — so we'd skip and never re-check on the
subsequent IN_MOVED_TO either.

Fix: skip events on temp files (filenames containing a dot) and
react on IN_MOVED_TO for the actual destination filename. Direct
in-place writes (rare) are still handled via IN_CLOSE_WRITE for
non-temp filenames.

Also removed debug logging.
2026-05-24 15:03:46 +02:00
Window Maker c9a0fe8654 wl_backend: handle IN_MOVED_TO for atomic file replacement
WMWritePropListToFile uses an atomic write pattern: write to a temp
file, fsync, fclose, then rename to the destination. The inotify
directory watch sees:
  1. IN_CLOSE_WRITE on the temp file (WindowMaker.XXXXXX)
  2. IN_MOVED_TO on WindowMaker (the rename)

We were only handling IN_CLOSE_WRITE, but at that point the rename
hadn't happened yet, so stat(WindowMaker) returned the OLD mtime
and we skipped. The NEXT save's IN_CLOSE_WRITE would then catch
the PREVIOUS save's mtime change — hence the 'one click behind'
pattern users observed.

Now handles IN_MOVED_TO too, catching the actual atomic replacement.

Also removed debug logging.
2026-05-24 14:55:10 +02:00
Window Maker e97c76b582 wl_backend: use IN_CLOSE_WRITE instead of IN_MODIFY for inotify
IN_MODIFY fires during the write, before the file is fully written.
The Wayland event loop's 16ms dispatch catches this almost instantly,
reading stale/partial content. IN_CLOSE_WRITE fires after the writer
closes the file, guaranteeing the content is complete.

This fixes the 'one step behind' issue where background changes only
appeared on the second apply.
2026-05-24 14:45:45 +02:00
Window Maker 6ecdeca3fc wl_backend: fix background not updating on first apply
Two issues:
1. bg_image scene node wasn't re-enabled when switching from solid
   color back to an image background
2. No frame was scheduled after background change, so the compositor
   wouldn't repaint until the next natural frame tick

Now explicitly enables the bg_image node and calls
wlr_output_schedule_frame() after any background change.
2026-05-24 14:44:26 +02:00
Window Maker 94054aeec8 wl_backend: implement all background image fill modes
- tpixmap (Tiled): repeat image across screen
- spixmap (Scaled): stretch to exact screen dimensions
- cpixmap (Centered): place at center with background color fill
- mpixmap (Maximized): scale preserving aspect ratio, letterbox
- fpixmap (Filled): scale preserving aspect ratio, crop to fill

All modes now use RSmoothScaleImage for quality, respect the
background color (3rd texture argument) for uncovered areas, and
handle transparent images via RCombineImageWithColor.
2026-05-24 14:41:57 +02:00
Window Maker 07022840ac wl_backend: add X11 rgb.txt color name lookup
The named color table only had basic colors (black, white, red, etc.)
but Window Maker backgrounds use extended X11 color names like
deepskyblue4, tomato4, blue4. Now falls back to parsing
/usr/share/X11/rgb.txt for any unrecognized color name.

Fixes Sunset and other multi-color gradient backgrounds that use
X11 named colors.
2026-05-24 14:38:14 +02:00
Window Maker a62a05bbb7 wl_backend: fix background color parsing to support named colors
The color parser only handled #RRGGBB and rgb:XX/XX/XX formats, but
Window Maker backgrounds use X11 named colors (deepskyblue4, black,
tomato4, etc.). Now uses wGetColor() which resolves any color format
through the backend's color lookup.

Also: solid backgrounds now update the scene rect directly (faster,
no buffer allocation needed).
2026-05-24 14:35:50 +02:00
Window Maker 286e588110 wl_backend: add multi-color gradient support for desktop backgrounds
Added mvgradient/mhgradient/mdgradient handling using wrlib's
RRenderMultiGradient(). This covers presets like 'Sunset' which use
more than 2 color stops.

Also cleaned up color parsing (removed empty else branches) and
removed debug logging.
2026-05-24 14:30:57 +02:00
Window Maker 93587378d9 wl_backend: implement desktop background rendering
On X11, wmsetbg sets the root window pixmap. On Wayland there's no root
window, so the compositor must render the background directly.

Added wm_backend->set_desktop_background() vtable method:
- X11: NULL (wmsetbg continues to handle it)
- Wayland: parses the texture proplist description and renders:
  - solid colors
  - vertical/horizontal/diagonal gradients (via RRenderGradient)
  - pixmap/spixmap/cpixmap images (via RLoadImage + RScaleImage)

The rendered image is displayed as a wlr_scene_buffer in the
WL_LAYER_BACKGROUND layer, replacing the static solid-color rect.

setWorkspaceBack() in defaults.c now calls the backend method when
available, so background changes from WPrefs take effect immediately.
2026-05-24 14:23:09 +02:00
Window Maker aab89ab11a icon: repaint clip text after tile change
tileObserver was calling window_clear after update_icon_pixmap, which on
Wayland overwrote the painted icon with just the background tile (erasing
clip workspace number/name text). On X11 this worked because XClearWindow
triggers an Expose event that repaints everything.

Fix: remove the redundant window_clear (update_icon_pixmap already calls
wIconPaint which does window_clear + icon_paint internally), and
explicitly call wClipIconPaint for the clip icon to redraw the workspace
number and name overlay.
2026-05-24 14:18:39 +02:00
Window Maker 91c49c8631 wl_backend: fix window_clear to repaint from background pixmap
wl_window_clear was filling with transparent black, which made dock/clip
icons disappear after a theme change. On X11, XClearWindow repaints the
window with its background pixmap — the Wayland backend now does the same.

Added bg_pixmap field to frame_buf, set in window_set_background_pixmap,
and used in window_clear to composite the background back into the buffer.
2026-05-24 14:15:46 +02:00
Window Maker 0d795bc84a wl_backend: add inotify config-file watching to event loop
The Wayland event loop was missing inotify polling, so theme/style/
background changes from WPrefs (or manual edits to ~/GNUstep/Defaults/)
were never detected. The X11 backend had this since day one.

Now the Wayland event loop checks inotify on every iteration (non-blocking
select with zero timeout). When a config file modification is detected,
wDefaultsCheckDomains() is called, which re-reads the defaults database
and posts appearance-change notifications — triggering immediate visual
refresh of title bars, menus, icons, and backgrounds.
2026-05-24 14:13:14 +02:00
Window Maker 8119bfe098 WPrefs.app: zero X11 deps, zero #ifdef USE_X11_BACKEND
Complete architectural separation: all WPrefs.app panel code is now
backend-neutral. No X11 calls, no X11 types, no X11 includes, no
backend-specific #ifdef guards in shared sources.

New W_EventBackend vtable methods (implemented in X11, stubbed in WL):
  - grab_keyboard / ungrab_keyboard / allow_events
  - grab_pointer / ungrab_pointer / query_pointer
  - get_window_geometry / move_window / translate_coordinates
  - get_root_window / query_tree
  - get_pointer_control / set_pointer_control
  - modifier_from_key / get_modifier_keysyms
  - keysym_to_string / keysym_to_keycode / keycode_to_keysym
  - keysym_convert_case
  - send_wm_command
  - set_window_hints / set_window_property_string / set_window_property_data
  - recolor_cursor
  - set_error_handler / restore_error_handler

Panel changes:
  - xmodifier.c: thin wrapper calling eventBackend->modifier_from_key()
  - main.c: X11 locale init removed (belongs in backend screen_init)
  - WPrefs.c: eventBackend->send_wm_command("Reconfigure")
  - MouseSettings.c: vtable for pointer control + modifier keysyms
  - KeyboardShortcuts.c: vtable for grab/keysym/modifier ops
  - Menu.c: RImage crosshair icon, vtable keyboard grab
  - editmenu.c: vtable for all window/pointer/property ops

Verified: nm audit shows zero X11 symbol refs in WPrefs .o files.
grep shows zero #ifdef USE_X11_BACKEND in WPrefs.app/.
2026-05-24 14:04:14 +02:00
Window Maker b996a0e274 WPrefs.app: TexturePanel.c X11-free in compiled code
Active code: XFillRectangle → renderBackend/WMPaintColorSwatch,
XCopyArea → renderBackend->pixmap_copy, XFreePixmap →
renderBackend->pixmap_free, XParseColor → WMCreateNamedColor,
screen size queries → WMScreenWidth/Height.

7 remaining X11 calls are all inside #if 0 dead-code test blocks
(never compiled). Architecturally clean.
2026-05-24 13:35:07 +02:00
Window Maker 8fe50a7001 WPrefs.app: WPrefs.c X11-free (reconfigure via SIGUSR1 on Wayland)
- XSendEvent/_WINDOWMAKER_COMMAND path guarded with USE_X11_BACKEND
- Wayland path: send SIGUSR1 to wmaker via PID file
- XFlush calls replaced with eventBackend->flush()
- Added X11 includes inside #ifdef guard only

Also: double.c/Paths.c already committed; HotCornerShortcuts.c done.

Remaining panels with X11 calls (all architectural violations):
  editmenu.c (30), Menu.c (14), TexturePanel.c (13),
  KeyboardShortcuts.c (11), MouseSettings.c (5)
2026-05-24 13:30:35 +02:00
Window Maker fabf6c01b2 WPrefs.app: HotCornerShortcuts.c X11-free (RImage quadrant extraction)
Replaced XCreatePixmap/XCopyArea/XCreateGC/XFreeGC/XFreePixmap with
RImage-based quadrant extraction: RLoadImage → RGetSubImage for each
corner → WMCreatePixmapFromRImage → WMSetLabelImage.

panel->quarter[] changed from WMNativePixmap to WMPixmap*.
Cleanup uses WMReleasePixmap instead of XFreePixmap.
2026-05-24 13:28:11 +02:00
Window Maker f8a2ff12d0 WPrefs.app: double.c/Paths.c use render backend instead of Xlib
double.c: XFillRectangle/XClearWindow → renderBackend->fill_rect
Paths.c: XFillRectangle → renderBackend->fill_rect
2026-05-24 13:25:46 +02:00
Window Maker f0d7879b23 WPrefs.app: begin X11/Wayland separation
- WPrefs.h: drop #include <X11/Xlib.h>; ModifierFromKey takes WMScreen*
- main.c: X11 locale calls guarded with #ifdef USE_X11_BACKEND
- xmodifier.c: X11-specific modifier mapping code guarded with
  #ifdef USE_X11_BACKEND; Wayland mode uses sensible defaults
  (Mod1=Alt=Meta, Mod4=Super)
- Appearance.c: all 65 Xlib calls replaced with RImage-based rendering
  (RCreateImage, RDrawLine, RCopyArea, RFillImage, etc.) and
  WMCreatePixmapFromRImage for display. previewNoText/previewBack
  fields changed from WMNativePixmap to RImage*.

Remaining panels still have X11 calls (editmenu, Menu, TexturePanel,
KeyboardShortcuts, HotCornerShortcuts, WPrefs, MouseSettings,
double, Paths) — will be addressed in follow-up commits.
2026-05-24 13:23:47 +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 a4eb10b2b5 wrlib: split X11 image-conversion path; --disable-x11-wraster
Phase θ — wrlib's X11 image-conversion path (RConvertImage,
RPutXImage, the X11 RCreateContext, libXpm-based RLoadXPM) is now
opt-out via --disable-x11-wraster, mirroring the WINGs phase η work.

Result: with --disable-x11-backend --disable-x11-wraster the WINGs
runtime libraries have ZERO libX11 transitive deps:

  $ ldd WINGs/.libs/libWINGs.so | grep X11
  (empty)
  $ ldd wrlib/.libs/libwraster.so | grep X11
  (empty)

That was the last libX11 transitive dep coming through WINGs — the
goal of the API surgery is now achieved at the library level.

configure.ac:
- New --enable-x11-wraster (default = same as --enable-x11-backend),
  AM_CONDITIONAL([USE_X11_WRASTER]), AC_DEFINE([USE_X11_WRASTER]).
  Forcing --disable-x11-wraster while --enable-x11-backend is rejected
  (X11 backend depends on the X11 conversion path).
- WRASTER_GFXLIBS_NO_XPM: GFXLIBS with -lXpm filtered (libXpm pulls
  libX11; load_xpm_normalized.c is the X11-free XPM loader used in
  the disabled-X11 build).
- WINGS_PANGO_LIBS_NO_XFT: PANGO_LIBS with -lpangoxft-* and -lXft
  filtered (PangoXft depends on libXft -> libX11; pangoft2 path is
  the X11-free Pango variant).

wrlib/Makefile.am:
- Split source list: shared / X11-only / Wayland-only.
- X11 sources (context.c, convert.c, convert_x11.c, xpixmap.c,
  xutil.c, load_xpm.c) only built when USE_X11_WRASTER.
- New context_wl.c (always built) — Wayland-mode RCreateContextWayland
  extracted from context.c.
- New wstubs_no_x11.c (only built when !USE_X11_WRASTER) — empty
  stubs for the public wraster API symbols normally exported from
  the X11 path (RCreateContext, RDestroyContext, RConvertImage,
  RConvertImageMask, RGetClosestXColor, RCreateImageFromDrawable,
  RCreateImageFromXImage, RCreateXImage, RGetXImage, RDestroyXImage,
  RPutXImage, RGetImageFromXPMData, RLoadXPM).
- @XLIBS@/@LIBXMU@ only added to libwraster_la_LIBADD when
  USE_X11_WRASTER; load_xpm.c only built when (USE_XPM and
  USE_X11_WRASTER).
- Added --filter USE_X11_WRASTER to the wraster.h generation rule
  so the @!USE_X11_WRASTER@ lines (forcing WRASTER_NO_XLIB) are
  retained when X11 is disabled.

wrlib/wraster.h.in:
- When USE_X11_WRASTER is undefined at config time, force
  WRASTER_NO_XLIB so consumers see only forward-decl'd opaque types
  (Display/Visual/XImage/etc.) and never <X11/Xlib.h>.
- Added True/False/None defines to the WRASTER_NO_XLIB block (raster.c
  uses them; previously got via Xlib.h).

wrlib/context.c — RCreateContextWayland moved out to context_wl.c.
wrlib/wstubs_no_x11.c — new (157 lines).
wrlib/context_wl.c — new (extracted Wayland branch).

WINGs/Makefile.am:
- libWINGs_la_LIBADD now uses WINGS_PANGO_LIBS, which is @PANGO_LIBS@
  when X11 backend enabled, @WINGS_PANGO_LIBS_NO_XFT@ otherwise.

WINGs/widgets.c — WMCreateScreen + WMCreateSimpleApplicationScreen
moved to widgets_x11.c (they use DefaultScreen() and RCreateContext()
which are X11-only).  Stubs added in WINGs/wstubs_no_x11.c.
WINGs shared rootWin assignment now reads context->drawable instead
of calling X11 RootWindow() macro directly.

WINGs/WINGs/wnative.h — added X11-numeric constants used by shared
WINGs widget code:
- Button1..Button5 (X.h pointer-button numbers)
- KeyPress..LASTEvent (X.h event-type constants)
- CWBackPixmap..CWCursor (X.h CreateWindow/ChangeWindowAttributes
  mask bits)
- WMShortRect (XRectangle layout-compatible struct)
All guarded by #ifndef so X11 headers can override on the X11 build.

WINGs/configuration.c — dropped unused <X11/Xlocale.h> include.
WINGs/wruler.c, wtabview.c, wtext.c — replaced raw XPoint/XRectangle
with WMShortPoint/WMShortRect; replaced lone XSetWindowAttributes
shim with direct view->attribs.cursor access.

src/WindowMaker.h — explicitly include <X11/Xlib.h>, <X11/Xutil.h>,
<X11/Xresource.h>, <X11/Xatom.h>.  The wmaker compositor uses these
extensively in its public headers; previously got them transitively
via WINGs.h.  After the WINGs surgery WINGs.h no longer pulls Xlib,
so the compositor must include them itself.

Verified:
  Default build (--enable-x11-backend, --enable-x11-wraster):
    Window Maker 0.96.0 boots, all features intact.
  Pure-Wayland build (--disable-x11-backend --disable-x11-wraster):
    libwraster.so / libWINGs.so build cleanly, no libX11 in ldd.
    (wmaker compositor binary still has X11 deps from src/* code;
     out of scope for this commit — that's a compositor-level
     refactor.)
2026-05-24 12:24:45 +02:00
Window Maker cff52676c2 wings: add --disable-x11-backend for pure-Wayland WINGs builds
Phase η: completes the WINGs API surgery by adding the configure
option that actually excludes the X11 backend from the build.

  ./configure --enable-wayland-client --disable-x11-backend
    → libWINGs has zero X11 symbol dependencies in its own objects

configure.ac: --enable-x11-backend (default yes) controls the new
USE_X11_BACKEND m4 conditional and #define.

WINGs/Makefile.am: split source list into:
  - backend-neutral / shared sources (always)
  - if USE_X11_BACKEND: dragsource_x11.c / dragdestination_x11.c /
    dragcommon_x11.c / selection_x11.c / wappresource_x11.c /
    wballoon_x11.c / wcolor_x11.c / wcolorpanel_x11.c /
    wevent_x11.c / wfont_x11.c / widgets_x11.c /
    winputmethod_x11.c / wrender_x11.c / wview_x11.c
  - else: wstubs_no_x11.c (new)
XLIBS / XFT_LIBS only added to libWINGs_la_LIBADD when X11 backend
is enabled.

WINGs/wstubs_no_x11.c: empty implementations of every public WINGs
API symbol that normally lives in *_x11.c — DnD setup, selection
handlers, IM context, balloons, color/font panels, application icon
hints, atom helpers.  Each stub is a no-op (returns success-neutral
value); calling them in pure-Wayland mode is silent rather than an
error, so future Wayland equivalents can drop in transparently.

WINGs/widgets.c: WMCreateScreenWithRContext uses weak references
to the W_*BackendX11 instances so they can resolve to NULL when not
linked.  If the caller asked for X11 mode but X11 backend is not
built, falls back to Wayland with a warning.

WINGs/WINGsP.h.in: backend extern decls (W_*BackendX11) marked weak
so links resolve to NULL when X11 backend is excluded.

Verification:
  $ ./configure --disable-x11-backend && make
  $ for f in WINGs/.libs/*.o; do nm $f | grep '^.*U X[A-Z][a-z]'; done
  (empty)

libWINGs.so still pulls libX11 transitively via wrlib (wraster's X11
image-conversion path); that's a separate refactor.  At the WINGs
source level the partition is now complete: shared / X11 / Wayland.
2026-05-24 11:56:57 +02:00
Window Maker 9a02eb658e wings: phase ζ — formal W_PlatformBackend vtable for WMOpenScreen
Replaces the inline if-Wayland-else-X11 dispatch in WMOpenScreen with
a proper vtable.  Each platform-open backend now provides one
W_PlatformBackend instance:

  W_PlatformBackendX11       — widgets_x11.c
  W_PlatformBackendWLClient  — wclient_wl.c

WMOpenScreen walks an ordered registry of weak references to these
instances:

  static const W_PlatformBackend *const wm_platform_backends[] = {
      &W_PlatformBackendWLClient,
      &W_PlatformBackendX11,
      NULL
  };

It first asks each backend's .detect() whether it wants the supplied
display string, and calls .open() on the first to claim it.  If no
backend claims, it falls back to trying each .open() in order.

Weak references mean a build that excludes a backend (e.g. a future
--disable-x11-backend) link cleanly with the symbol resolving to
NULL — WMOpenScreen just skips it.

The detection logic moves out of shared widgets.c entirely:
  x11_detect: explicit non-wayland display string OR $DISPLAY set.
  wlclient_detect: 'wayland' prefix, WMAKER_USE_WAYLAND, or
                   $WAYLAND_DISPLAY set + $DISPLAY unset.

Also replaces WMCreateScreenWithRContext's getenv("WMAKER_USE_WAYLAND")
with an explicit W_SetNextScreenKind(WM_SCREEN_KIND_WAYLAND) flag the
platform backend sets before calling.  No env detection in shared code.

Updated wmaker compositor (src/backend/wayland/wl_backend.c) to call
W_SetNextScreenKind(WM_SCREEN_KIND_WAYLAND) before its own
WMCreateScreenWithRContext call.

Verified: wmaker still starts in compositor mode, version string OK,
build clean, vtable dispatch invokes the right backend.
2026-05-24 11:49:34 +02:00