windowmaker-wl/WL_DECOMPOSITION_PLAN.md

14 KiB

wl_backend.c Decomposition Plan

Overview

src/backend/wayland/wl_backend.c is 2329 lines containing 6 unrelated functional areas that have accumulated in a single file. This plan decomposes it into focused modules, each of which can be carried out as an independent commit.

The target is to reduce wl_backend.c to ~900 lines containing only the compositor lifecycle (open/close/run/terminate) and the small protocol handlers that are tightly coupled to it.


Pre-requisites

  • Build system: src/Makefile.am (lines 164-209) lists all backend/wayland/*.c files under wmaker_SOURCES. Any new .c file must be added there.
  • After editing Makefile.am, run autoreconf -fi && ./configure <flags> to regenerate Makefile.in and Makefile.
  • All wayland backend files share state through the global wl_state struct declared in wl_types.h and defined in wl_backend.c.
  • Forward declarations use extern for functions defined in other .c files. Functions that become file-local after extraction should be marked static.

Step 1 — Remove duplicate layer shell code (delete ~180 lines)

Problem: wl_backend.c lines 1539-1720 contain a static copy of the layer shell implementation. An identical non-static copy exists in wl_layer_shell.c (196 lines, already in Makefile.am). The static qualifier on the wl_backend.c copy means it shadows the wl_layer_shell.c version within this translation unit — the wl_layer_shell.c version is effectively dead code.

Functions to delete from wl_backend.c:

Function Lines Status in wl_backend.c
layer_surface_compute_geometry 1546-1568 static — duplicate
layer_surface_compute_position 1574-1608 static — duplicate
handle_layer_surface_map 1610-1618 static — duplicate
handle_layer_surface_unmap 1620-1630 static — duplicate
handle_layer_surface_destroy 1632-1646 static — duplicate
handle_layer_shell_new_surface 1653-1720 static — duplicate
LAYER_VIEW_FROM macro 1539-1540 duplicate of wl_layer_shell.c:14

Changes:

  1. In wl_backend.c, delete lines 1539-1720 (the LAYER_VIEW_FROM macro through the end of handle_layer_shell_new_surface).

  2. In wl_backend.c, change the forward declaration at line 222 from:

    static void handle_layer_shell_new_surface(struct wl_listener *listener, void *data);
    

    to:

    extern void handle_layer_shell_new_surface(struct wl_listener *listener, void *data);
    
  3. No Makefile.am change needed — wl_layer_shell.c is already listed.

Verification: make clean && make — the linker resolves handle_layer_shell_new_surface from wl_layer_shell.o. Run the compositor and verify a layer-shell client (e.g. waybar, wlr-randr) still works.


Step 2 — Extract desktop background to wl_background.c (~300 lines)

Problem: wl_set_desktop_background() (lines 2034-2287) plus its helper types and functions (lines 1984-2032) form a self-contained 300-line module for rendering wallpapers. It has no callers within wl_backend.c — it is called from defaults.c via the backend vtable.

Functions/types to move:

Symbol Lines Visibility
struct wl_bg_buffer 1987-1990 file-local struct
bg_buffer_destroy 1992-1998 static
bg_buffer_begin_data_ptr_access 2000-2009 static
bg_buffer_end_data_ptr_access 2011-2014 static
bg_buffer_impl 2016-2020 static const
parse_color_to_rcolor 2022-2032 static
wl_set_desktop_background 2034-2287 extern (vtable)

Steps:

  1. Create src/backend/wayland/wl_background.c with these includes:

    #ifdef HAVE_CONFIG_H
    #include "config.h"
    #endif
    #include <string.h>
    #include <stdlib.h>
    #include <limits.h>
    #include <wayland-server-core.h>
    #include <wlr/types/wlr_output.h>
    #include <wlr/types/wlr_scene.h>
    #include <wlr/types/wlr_buffer.h>
    #include <wlr/interfaces/wlr_buffer.h>
    #include <libdrm/drm_fourcc.h>
    #include <pixman.h>
    #include "../../screen.h"
    #include "../../resources.h"
    #include "wl_types.h"
    
  2. Move all 7 symbols listed above into the new file. Keep static on the helpers; wl_set_desktop_background stays non-static.

  3. Delete lines 1984-2287 from wl_backend.c.

  4. In wl_backend.c, the #include list does not need changes — the function is resolved at link time.

  5. Add to src/Makefile.am inside the if USE_WAYLAND_BACKEND block:

    backend/wayland/wl_background.c \
    
  6. Run autoreconf -fi && ./configure <flags> && make.

Verification: Set a gradient or pixmap background in ~/GNUstep/Defaults/WindowMaker and confirm it renders.


Step 3 — Move screen internals to wl_screen.c (~235 lines)

Problem: wl_screen.c already contains wl_screen_open, wl_screen_close, wl_screen_init_display, wl_show_crash_dialog, wl_get_color_for_colormap, and wl_parse_color (244 lines). But the screen setup functions wl_screen_alloc_gcs, wl_screen_create_internals, wl_screen_create_pixmaps, wl_screen_load_tech_font, and the one-liner stubs remain in wl_backend.c.

Functions to move:

Function Lines Notes
wl_screen_select_input 1732 one-liner stub
wl_screen_set_root_cursor 1733 one-liner stub
wl_screen_set_icon_sizes 1734 one-liner stub
wl_screen_setup_noticeboard 1735 one-liner stub
wl_screen_alloc_gcs 1737-1836 ~100 lines, X11 GC creation
wl_screen_create_internals 1838-1966 ~130 lines, scene setup
wl_screen_create_pixmaps 1967 one-liner stub
wl_screen_load_tech_font 1968-1978 small
wl_screen_show_mini_screenshot 1979 one-liner stub
wl_screen_capture_area 1980 one-liner stub
wl_screen_capture_window 1981 one-liner stub
wl_refresh_desktop 1982 one-liner stub
wl_monitors_query 2289-2323 ~35 lines
wl_monitors_select_events 2325 one-liner stub

Steps:

  1. Add required includes to wl_screen.c (some may already be present):

    #include <wlr/types/wlr_scene.h>
    #include <wlr/types/wlr_buffer.h>
    #include <wlr/interfaces/wlr_buffer.h>
    #include <pixman.h>
    #include "../../framewin.h"
    #include "../../defaults.h"
    #include "../../xmodifier.h"
    #include "../../def_pixmaps.h"
    
  2. wl_screen_create_internals references these external symbols that must be declared (via extern or header include) in wl_screen.c:

    • frame_buf_impl — defined in wl_framebuf.c; add extern const struct wlr_buffer_impl frame_buf_impl;
    • fb_attach_tree_listener, fb_attach_scene_buf_listener — defined in wl_framebuf.c
    • W_RegisterBacking, W_UnregisterBacking — WINGs internals
    • OVL_GH — defined in wl_overlay.c or wl_types.h
  3. wl_screen_alloc_gcs references DEF_FRAME_THICKNESS (from framewin.h) and WM_EVMASK_* macros. Ensure these headers are included.

  4. Move all 14 functions listed above from wl_backend.c into wl_screen.c.

  5. Delete lines 1732-1982 and 2289-2329 from wl_backend.c.

  6. No Makefile.am change needed — wl_screen.c is already listed.

Verification: make succeeds. Launch compositor, verify screen initialization (GCs created, workspace badge visible, dock shadow works).


Step 4 — Extract X11 event bridge to wl_xwayland.c (~55 lines)

Problem: wl_handle_x11_events() (lines 269-326) translates XEvents from the XWayland connection into WMEvents. It belongs with the other XWayland code in wl_xwayland.c (429 lines, already in Makefile.am under USE_XWAYLAND).

Functions to move:

Function Lines Notes
wl_handle_x11_events 269-326 static in wl_backend.c

Steps:

  1. Move wl_handle_x11_events to wl_xwayland.c. Remove static so it can be called from wl_backend.c.

  2. In wl_backend.c, replace the function body with:

    extern int wl_handle_x11_events(int fd, uint32_t mask, void *data);
    

    (The non-XWAYLAND stub at lines 323-325 stays in wl_backend.c.)

  3. Ensure wl_xwayland.c includes <WINGs/WMEvent.h> and "../../event.h" for WMHandleEvent.

Verification: Launch with XWayland enabled, open an X11 app (e.g. xterm), verify keyboard/mouse events work.


Step 5 — Extract protocol global init from wl_display_open() (~240 lines)

Problem: wl_display_open() is 670 lines. Lines 578-818 are a linear sequence of ~25 protocol global creation calls (wlr_*_create + wl_signal_add). This block has no control flow dependencies on the surrounding code beyond wl_state.display and wl_state.seat being set.

Approach: Extract into a helper function wl_protocols_init() in wl_extensions.c (which currently contains only stubs and error handlers — 172 lines).

Steps:

  1. In wl_extensions.c, add a new function:

    void wl_protocols_init(void)
    

    that contains the protocol global creation block (lines 578-818 of wl_backend.c). This includes creation of:

    • wlr_compositor, wlr_subcompositor
    • wlr_seat, wlr_data_device_manager
    • seat event wiring (request_set_cursor, request_set_selection, request_start_drag, request_set_primary_selection)
    • wlr_primary_selection_v1_device_manager
    • wlr_xdg_output_manager_v1
    • wlr_idle_inhibit_v1
    • wlr_viewporter
    • wlr_relative_pointer_manager_v1
    • wlr_pointer_constraints_v1
    • wlr_keyboard_shortcuts_inhibit_v1
    • wlr_linux_dmabuf_v1
    • wlr_screencopy_manager_v1
    • wlr_export_dmabuf_manager_v1
    • wlr_output_manager_v1
    • wlr_output_power_manager_v1
    • wlr_gamma_control_manager_v1
    • wlr_presentation
    • wlr_text_input_manager_v3
    • wlr_input_method_manager_v2
    • wlr_virtual_keyboard_manager_v1
    • wlr_foreign_toplevel_manager_v1
    • wlr_xdg_activation_v1
    • wlr_layer_shell_v1
    • wlr_data_control_manager_v1
    • wlr_virtual_pointer_manager_v1
    • wlr_xdg_foreign_registry + wlr_xdg_foreign_v2
    • wlr_xdg_shell
    • wmaker_popup_manager_v1 (custom protocol)
    • wlr_xdg_decoration_manager_v1
    • wlr_renderer_init_wl_shm
  2. The function needs these extern handler declarations (move from wl_backend.c forward-declaration block):

    • handle_seat_request_cursor
    • handle_seat_request_set_selection — currently static in wl_backend.c; must become non-static and move to wl_extensions.c or stay in wl_backend.c with an extern declaration
    • handle_seat_request_start_drag — already in wl_dnd.c
    • handle_seat_request_primary_selection — currently static; same treatment
    • handle_idle_new_inhibitor — currently static; same treatment
    • handle_new_pointer_constraint — currently static; same treatment
    • handle_new_shortcuts_inhibitor — currently static; same treatment
    • All the extern handlers already in other files (output_mgr, text_input, etc.)
  3. Move the 5 small static handler functions that are only used by protocol init into wl_extensions.c as well (remove static):

    • handle_seat_request_set_selection (lines 1451-1459)
    • handle_seat_request_primary_selection (lines 1467-1475)
    • handle_idle_new_inhibitor (lines 1484-1491)
    • handle_new_pointer_constraint (lines 1507-1517)
    • handle_new_shortcuts_inhibitor (lines 1528-1535)
  4. In wl_display_open(), replace lines 578-821 with:

    wl_protocols_init();
    
  5. Add required #include directives to wl_extensions.c for the wlroots protocol types used. The full list is long — copy the relevant subset from wl_backend.c's include block.

  6. No Makefile.am change needed — wl_extensions.c is already listed.

Verification: make succeeds. Launch compositor, verify all protocol globals are advertised (wayland-info or wlr-randr should list them).


Execution order

Steps are ordered by risk (lowest first) and independence:

Step Risk Reason
1 (layer shell dedup) Lowest Pure deletion of shadowed static code
2 (background) Low Self-contained, no cross-references
3 (screen internals) Medium Many extern references to resolve
4 (X11 bridge) Low Small, single function
5 (protocol init) Medium Touches the critical init path; many handler relocations

Each step should be a separate commit. Build and smoke-test after each.


Expected result

File Before After
wl_backend.c 2329 lines ~900 lines
wl_layer_shell.c 196 lines (dead) 196 lines (live)
wl_background.c — (new) ~310 lines
wl_screen.c 244 lines ~480 lines
wl_xwayland.c 429 lines ~485 lines
wl_extensions.c 172 lines ~450 lines

The remaining wl_backend.c contains:

  • wl_display_open() (~430 lines) — backend/renderer/allocator/scene/cursor creation, XKB keymap, XWayland setup, frame timer, shutdown pipe, pump thread
  • wl_display_close() (~210 lines) — teardown and listener removal
  • wl_display_post_open(), wl_display_screen_count(), wl_display_default_screen() — trivial stubs
  • wl_event_loop_run() (~190 lines) — signalfd, main dispatch loop
  • wl_event_loop_terminate() — shutdown pipe write
  • wl_startup_pump_thread() — startup helper
  • wl_shutdown_pipe_handler(), frame_timer_cb() — event loop callbacks
  • Global wl_state definition

This is a coherent "compositor lifecycle" module at a manageable size.