diff --git a/src/Makefile.am b/src/Makefile.am index a14c310..0c0b195 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -157,7 +157,8 @@ endif if USE_WAYLAND_BACKEND wmaker_SOURCES += \ backend/wayland/wl_backend.h \ - backend/wayland/wl_backend.c + backend/wayland/wl_backend.c \ + backend/wayland/wl_context.c endif if USE_NESTED_FUNC diff --git a/src/backend/wayland/wl_backend.c b/src/backend/wayland/wl_backend.c index f7e423f..790e684 100644 --- a/src/backend/wayland/wl_backend.c +++ b/src/backend/wayland/wl_backend.c @@ -231,377 +231,11 @@ void W_UnregisterBacking(unsigned long id); /* Forward declarations */ /* ------------------------------------------------------------------ */ -struct wl_toplevel_view; /* defined below */ +#include "wl_types.h" static void wm_dock_app_add(struct wl_toplevel_view *v); static void wm_dock_app_remove(WNativeWindow id); -/* ------------------------------------------------------------------ */ -/* Phase 38: per-toplevel view and context store */ -/* ------------------------------------------------------------------ */ - -/* - * wl_toplevel_view -- one entry per XDG toplevel managed by the compositor. - * Holds the wlroots surface pointer, three lifecycle listeners, and a - * synthetic Window ID used as the policy-layer window handle. - */ -struct wl_toplevel_view { - struct wlr_xdg_surface *xdg_surface; - struct wl_listener map_listener; - struct wl_listener unmap_listener; - struct wl_listener destroy_listener; - struct wl_listener title_listener; /* Phase 46: xdg_toplevel set_title */ - struct wl_listener request_move_listener; /* Phase 15 */ - struct wl_listener request_resize_listener; /* Phase 15 */ - struct wl_listener request_maximize_listener; /* Phase 16 */ - struct wl_listener request_fullscreen_listener;/* Phase 16 */ - struct wl_listener request_minimize_listener; /* Phase 16 */ - struct wl_listener set_app_id_listener; /* Phase 16 */ - struct wl_listener commit_listener; /* initial configure */ - struct wl_listener surface_commit_listener; /* permanent commit listener */ - /* Phase 17: XWayland — set for X11 windows, NULL for XDG toplevels. */ - struct wlr_xwayland_surface *xw_surface; - /* Path 1: geometry listener — keeps scene node in sync when X11 window moves. */ - struct wl_listener xw_geometry_listener; - struct wl_listener xw_surface_map_listener; /* fires when wlr_surface maps */ - /* Phase 18: scene graph tree for this surface (NULL if scene unavailable). */ - struct wlr_scene_tree *scene_node; - /* Listener fires when scene_node is destroyed (e.g. when a parent - * tree is destroyed by wl_frame_destroy as part of unmanage). - * Without it, view->scene_node becomes a dangling pointer and the - * later handle_toplevel_destroy crashes calling wlr_scene_node_destroy - * a second time. */ - struct wl_listener scene_destroy_listener; - WNativeWindow id; /* synthetic handle, >= 0x10000000 */ - WNativeWindow frame_id; /* frame_buf that owns this view (0 = none) */ - int frame_rel_x, frame_rel_y; /* offset within frame */ - int x, y; /* Phase 55: WM-assigned position */ - /* wmaker-popup-v1: client-driven popup position (only valid if popup != NULL) */ - struct wl_resource *popup; /* wmaker_popup_v1 resource or NULL */ - int popup_x, popup_y; - struct wlr_xdg_toplevel *popup_parent; /* parent toplevel or NULL */ - long *wm_state; /* Phase 56: saved WM state or NULL */ - int wm_state_n; /* Phase 56: element count */ - char **wm_command; /* Phase 57: WM_COMMAND argv or NULL */ - int wm_command_n; /* Phase 57: argument count */ - /* Phase 35: foreign toplevel handle — exposes this window to taskbars. */ - struct wlr_foreign_toplevel_handle_v1 *ft_handle; - struct wl_list link; /* wl_state.toplevel_list */ -}; - -/* - * wl_or_view — tracks an override_redirect XWayland surface (WM frames, - * dock icons, menus, tooltips). These are not "managed" by the WM in the - * ICCCM sense but must be composited by the scene graph. - */ -struct wl_or_view { - struct wlr_xwayland_surface *xw_surface; - struct wlr_scene_tree *scene_node; - struct wl_listener map_listener; - struct wl_listener unmap_listener; - struct wl_listener destroy_listener; - struct wl_listener set_geometry_listener; - struct wl_list link; /* wl_state.or_list */ -}; - -/* - * wl_frame_buf — a pixman-backed scene buffer for WM frame windows. - * Each frame (titlebar + buttons + resizebar) is rendered into a single - * ARGB pixman image and displayed via a wlr_scene_buffer node. - */ -struct wl_frame_buf { - struct wlr_buffer base; /* wlr_buffer (must be first) */ - pixman_image_t *image; /* ARGB32 pixel data */ - struct wlr_scene_buffer *scene_buf; /* scene graph node */ - struct wlr_scene_tree *tree; /* grouping tree (top-level frames only) */ - /* Destroy listeners on scene_buf and tree so they get NULL'd when - * wlroots auto-destroys them (e.g. via cascade from parent tree - * destruction during wl_frame_destroy). Without these, code that - * later tries to wlr_scene_node_destroy them again segfaults inside - * wl_list_remove on already-zeroed list links. */ - struct wl_listener scene_buf_destroy; - struct wl_listener tree_destroy; - WNativeWindow id; /* synthetic ID (>= 0x10000000) */ - WNativeWindow parent_id; /* parent frame_buf ID (0 = root) */ - int x, y; /* position in output coords */ - int rel_x, rel_y; /* position relative to parent */ - int width, height; - pixman_image_t *bg_pixmap; /* background pixmap for window_clear */ - struct wl_list link; /* wl_state.frame_list */ -}; - -/* - * Phase 36: wl_layer_view — one entry per mapped zwlr_layer_shell_v1 surface. - * Tracks the wlroots layer surface, its scene node, and lifecycle listeners. - */ -struct wl_layer_view { - struct wlr_layer_surface_v1 *layer_surface; - struct wlr_scene_tree *scene_node; - struct wl_listener map_listener; - struct wl_listener unmap_listener; - struct wl_listener destroy_listener; - struct wl_list link; /* wl_state.layer_list */ -}; - -/* - * Context store: three per-key linked lists keyed by WNativeWindow. - * Backed by a flat list of (win, data) pairs — fine for the small - * number of windows a typical user has open. - */ -struct wl_ctx_entry { - WNativeWindow win; - void *data; - struct wl_list link; -}; - -/* ------------------------------------------------------------------ */ -/* Global compositor state */ -/* ------------------------------------------------------------------ */ - -struct wl_compositor_state { - struct wl_display *display; - struct wlr_backend *backend; - struct wlr_renderer *renderer; - struct wlr_output *output; /* headless output (screen 0) */ - struct wlr_output_layout *output_layout; /* Phase 34 */ - /* Phase 35: core Wayland protocol globals */ - struct wlr_compositor *compositor; - struct wlr_seat *seat; - struct wlr_data_device_manager *data_device_mgr; - struct wlr_xdg_shell *xdg_shell; - /* wmaker-popup-v1 protocol global — client-driven popup positioning */ - struct wl_global *wmaker_popup_manager; - /* Phase 64: XDG decoration manager — tell clients to use CSD */ - struct wlr_xdg_decoration_manager_v1 *decoration_manager; - struct wl_listener decoration_new_listener; - /* Phase 36: XDG toplevel tracking */ - struct wl_listener xdg_new_surface_listener; - int managed_surface_count; /* surfaces seen */ - /* Phase 37: periodic timer that drives client frame callbacks */ - struct wl_event_source *frame_timer; - /* Phase 38: per-toplevel view list and context store */ - struct wl_list toplevel_list; /* wl_toplevel_view.link */ - struct wl_list or_list; /* wl_or_view.link */ - struct wl_list frame_list; /* wl_frame_buf.link */ - struct wl_list layer_list; /* wl_layer_view.link */ - struct wl_list ctx_lists[3]; /* one per WContextKey */ - unsigned long next_synthetic_id; /* >= 0x10000000 */ - /* Phase 43: first real keyboard device (set by handle_backend_new_input) */ - struct wlr_input_device *keyboard_dev; - struct xkb_keymap *xkb_keymap; /* default keymap for keysym lookup */ - struct wl_listener keyboard_key_listener; /* Phase 78 */ - struct wl_listener keyboard_modifiers_listener; /* Phase 78 */ - /* Phase 53: first real pointer device (set by handle_backend_new_input) */ - struct wlr_input_device *pointer_dev; - /* Phase 54: virtual pointer position (screen coordinates) */ - int pointer_x, pointer_y; - /* Phase 14: pointer event listeners wired to pointer_dev->pointer */ - struct wl_listener pointer_motion_listener; - struct wl_listener pointer_motion_abs_listener; - struct wl_listener pointer_button_listener; - struct wl_listener pointer_frame_listener; - /* Phase 17: XWayland server for X11 client support */ - struct wlr_xwayland *xwayland; - struct wl_listener xwayland_new_surface_listener; - struct wl_listener xwayland_ready_listener; - struct wl_listener xwayland_server_destroy_listener; - bool xwayland_ready; /* set by handle_xwayland_ready */ - Display *x_display; /* WM's Xlib connection to own XWayland */ - struct wl_event_source *x11_event_source; /* wl_event_loop fd watcher for x_display */ - pthread_t startup_pump_thread; /* pumps Wayland event loop during StartUp() */ - volatile int startup_pump_running; /* 1 while pump thread is active */ - volatile int terminate; /* set to exit main loop */ - /* Phase 20: real input devices from nested backend + their listeners */ - struct wlr_input_device *real_keyboard_dev; - struct wlr_input_device *real_pointer_dev; - struct wl_listener backend_new_input_listener; - struct wl_listener real_keyboard_key_listener; - struct wl_listener real_keyboard_modifiers_listener; - struct wl_listener real_keyboard_destroy_listener; - struct wl_listener real_pointer_motion_abs_listener; - struct wl_listener real_pointer_button_listener; - struct wl_listener real_pointer_frame_listener; - /* Phase 18: nested Wayland + wlr_scene */ - int is_nested; /* 1 if using wlr_wl_backend */ - struct wlr_backend *headless_inner; /* headless backend (always) */ - struct wlr_backend *wl_backend_inner; /* wl backend (nested only) */ - struct wlr_session *session; /* DRM session (standalone only) */ - struct wlr_allocator *allocator; - struct wlr_scene *scene; - struct wlr_scene_output *scene_output; - struct wl_listener backend_new_output_listener; - struct wl_listener output_frame_listener; - char socket_name[64]; /* Phase 34: e.g. "wayland-0" */ - int started; /* non-zero after successful display_open */ - /* Self-pipe for async-signal-safe shutdown: signal handler writes to [1], - * event loop reads [0] and calls wl_display_terminate(). */ - int shutdown_pipe[2]; - struct wl_event_source *shutdown_source; - /* signalfd-based signal handling: primary mechanism for catching - * SIGTERM/SIGINT/SIGHUP from within the event loop (avoids async-signal- - * safety issues with the traditional signal handler path). */ - int sigfd; - struct wl_event_source *sigfd_source; - /* Phase 22: interactive move/resize grab state. - * grab_type: 0=none, 1=move, 2=resize, 3=WM policy grab. - * Type 3 is used by wl_pointer_grab for WM-internal drags (dock icons, - * app icons, menus). It suppresses wl_update_pointer_focus (so client - * surfaces don't steal pointer events) but does NOT intercept motion — - * WME_MOTION events flow normally to the WMMaskEvent loop. - * grab_view: the toplevel being moved/resized (NULL when grab_type==0 or 3). - * grab_start_ptr_{x,y}: pointer position when grab started. - * grab_start_win_{x,y,w,h}: window geometry when grab started. - * grab_resize_edges: WL_SHELL_SURFACE_RESIZE_* bitmask (resize only). */ - int grab_type; - struct wl_toplevel_view *grab_view; - int grab_start_ptr_x, grab_start_ptr_y; - int grab_start_win_x, grab_start_win_y; - int grab_start_win_w, grab_start_win_h; - uint32_t grab_resize_edges; - /* Phase 23: hardware cursor and xcursor theme. */ - struct wlr_cursor *cursor; - struct wlr_xcursor_manager *xcursor_mgr; - /* Phase 24: seat cursor-surface request listener. */ - struct wl_listener seat_request_cursor_listener; - /* Phase 25: clipboard — seat selection request listener. */ - struct wl_listener seat_request_set_selection_listener; - /* Phase 25b: drag-and-drop — seat request_start_drag listener. */ - struct wl_listener seat_request_start_drag_listener; - /* Phase 26: primary selection (middle-click paste). */ - struct wlr_primary_selection_v1_device_manager *primary_selection_mgr; - struct wl_listener seat_request_primary_selection_listener; - /* Phase 27: xdg-output manager for logical output geometry. */ - struct wlr_xdg_output_manager_v1 *xdg_output_mgr; - /* Phase 28: idle-inhibit manager for video players / fullscreen apps. */ - struct wlr_idle_inhibit_manager_v1 *idle_inhibit_mgr; - struct wl_listener idle_new_inhibitor_listener; - /* Phase 29: wp_viewporter for hardware video scaling / subsurface damage. */ - struct wlr_viewporter *viewporter; - /* Phase 30: relative pointer + pointer constraints for games. */ - struct wlr_relative_pointer_manager_v1 *relative_pointer_mgr; - struct wlr_pointer_constraints_v1 *pointer_constraints; - struct wl_listener new_constraint_listener; - /* Phase 31: keyboard shortcuts inhibitor for fullscreen / remote desktop. */ - struct wlr_keyboard_shortcuts_inhibit_manager_v1 *shortcuts_inhibit_mgr; - struct wl_listener new_shortcuts_inhibitor_listener; - /* Phase 32: GPU zero-copy buffer import, screencopy, GPU framebuffer export. */ - struct wlr_linux_dmabuf_v1 *linux_dmabuf; - struct wlr_screencopy_manager_v1 *screencopy_mgr; - struct wlr_export_dmabuf_manager_v1 *export_dmabuf_mgr; - /* Phase 33: output management (randr), output power (DPMS), gamma control, presentation time. */ - struct wlr_output_manager_v1 *output_mgr; - struct wl_listener output_mgr_apply_listener; - struct wl_listener output_mgr_test_listener; - struct wlr_output_power_manager_v1 *output_power_mgr; - struct wl_listener output_power_set_mode_listener; - struct wlr_gamma_control_manager_v1 *gamma_control_mgr; - struct wlr_presentation *presentation; - /* Phase 34: text input (IME client side), input method (IME server side), virtual keyboard. */ - struct wlr_text_input_manager_v3 *text_input_mgr; - struct wl_listener text_input_new_listener; - struct wlr_input_method_manager_v2 *input_method_mgr; - struct wl_listener input_method_new_listener; - struct wlr_virtual_keyboard_manager_v1 *virtual_keyboard_mgr; - struct wl_listener virtual_keyboard_new_listener; - /* Phase 35: foreign toplevel management + xdg_activation (focus tokens). */ - struct wlr_foreign_toplevel_manager_v1 *foreign_toplevel_mgr; - struct wlr_xdg_activation_v1 *xdg_activation; - struct wl_listener xdg_activation_request_listener; - /* Phase 36: layer shell — panels, docks, wallpapers, overlays. */ - struct wlr_layer_shell_v1 *layer_shell; - struct wl_listener layer_shell_new_surface_listener; - /* Phase 37: clipboard manager, input inhibitor, virtual pointer, idle, xdg-foreign. */ - struct wlr_data_control_manager_v1 *data_control_mgr; - struct wlr_virtual_pointer_manager_v1 *virtual_pointer_mgr; - struct wl_listener virtual_pointer_new_listener; - struct wlr_xdg_foreign_registry *xdg_foreign_registry; - struct wlr_xdg_foreign_v2 *xdg_foreign_v2; - /* Phase 29 axis listeners (headless pointer + real nested pointer). */ - struct wl_listener pointer_axis_listener; - struct wl_listener real_pointer_axis_listener; - struct wl_listener real_pointer_destroy_listener; - /* Phase 30: WM dock panel (native Wayland rendering via wm_shm_surface). */ - struct wm_shm_surface *dock_surface; /* NULL until screen_create_internals */ - int dock_width; /* pixels reserved on right edge */ - int dock_icon_sz; /* icon_sz saved by wm_dock_create */ - int dock_n_slots; /* slot count saved by wm_dock_create */ -/* Phase 30+: managed app list for dock icon rendering */ -#define WM_DOCK_MAX_APPS 32 - struct { - WNativeWindow id; - uint32_t *icon_argb; /* heap ARGB8888, or NULL */ - int icon_w, icon_h; - } dock_apps[WM_DOCK_MAX_APPS]; - int dock_app_count; - /* Stacking level trees — one wlr_scene_tree per layer, ordered - * bottom-to-top (index 0 rendered first = furthest back). - * - * Every scene node that participates in the compositor output is - * assigned to exactly one bucket so that creation order within the - * root tree never matters and there are no Z-order surprises. - * - * Named constants (WL_LAYER_*) map to bucket indices: - * - * 0 WL_LAYER_BACKGROUND background rect / wallpaper - * 1 WL_LAYER_DESKTOP WMDesktopLevel (level < -1) - * 2 WL_LAYER_SUNKEN WMSunkenLevel (level == -1) - * 3 WL_LAYER_NORMAL WMNormalLevel (0 <= level < 3) - * 4 WL_LAYER_FLOATING WMFloatingLevel (3 <= level < 20) - * 5 WL_LAYER_MENU WMMainMenuWindowLevel (20), OR-redirect - * 6 WL_LAYER_DOCK WMStatusWindowLevel / WMDockWindowLevel (21-49) - * also the dock panel wm_shm_surface - * 7 WL_LAYER_FULLSCREEN WMFullscreenLevel (50-99) - * 8 WL_LAYER_OVERLAY WMModalPanel / WMPopUp (>=100) - * also the XOR animation overlay surface - */ -#define WL_LAYER_BACKGROUND 0 -#define WL_LAYER_DESKTOP 1 -#define WL_LAYER_SUNKEN 2 -#define WL_LAYER_NORMAL 3 -#define WL_LAYER_FLOATING 4 -#define WL_LAYER_MENU 5 -#define WL_LAYER_DOCK 6 -#define WL_LAYER_FULLSCREEN 7 -#define WL_LAYER_OVERLAY 8 -#define WL_NUM_LEVEL_BUCKETS 9 - struct wlr_scene_tree *level_trees[WL_NUM_LEVEL_BUCKETS]; - struct wlr_scene_rect *bg_rect; /* default solid background */ - struct wlr_scene_buffer *bg_image; /* wallpaper image (if set) */ - struct wlr_buffer *bg_wlr_buf; /* backing buffer for bg_image */ - - /* Phase 81: full-screen overlay surface for XOR animation drawing */ - struct wm_shm_surface *overlay_surf; /* NULL until first draw */ - /* Focus sink: small off-screen InputOnly X window that receives focus - * when no application window is focused. Mirrors what x11_backend does - * for no_focus_win so that XSetInputFocus calls on this window succeed. */ - WNativeWindow no_focus_xwin; /* 0 until screen_create_internals */ - /* wrlib RContext drawable — an ordinary InputOutput window that XWM must - * not manage (no WM_CLASS, no backing wl_surface). Stored here so - * handle_xwayland_new_surface can filter it before allocating a view. */ - WNativeWindow rcontext_xwin; /* 0 until screen_alloc_gcs */ - /* Deferred dock creation: set in screen_create_internals, consumed in - * wl_event_loop_run() after the startup pump thread stops (to avoid racing - * with the pump thread's frame-timer callback on the scene graph). */ - WScreen *dock_pending_scr; - /* Button icon RImages (parsed from XPM on first use) */ - RImage *btn_close_img; - RImage *btn_iconify_img; - RImage *btn_kill_img; - /* Tracks the frame_buf the pointer was last over (after button resolution), - * so motion handlers can emit synthetic WME_LEAVE/WME_ENTER events when - * the pointer crosses between WM frame sub-windows (titlebar, resizebar, - * buttons). buttonMouseDown's inner press-track loop depends on these. */ - WNativeWindow last_hovered_id; - /* Focus guard: when true, the next focus-follows-pointer event is suppressed. - * Set by switchpanel_send_enter (called twice in wSwitchPanelDestroy) to prevent - * spurious focus changes when the Alt-Tab overlay is destroyed and the pointer - * re-enters the root window or a client surface underneath. */ - bool ignore_focus_ffp; - /* Keyboard grab: when true, key events are queued for WMMaskEvent but not - * forwarded to Wayland clients (used by Alt-Tab cycling). */ - bool keyboard_grabbed; -}; - -static struct wl_compositor_state wl_state; +struct wl_compositor_state wl_state; /* Forward declarations for helpers used before their definition. */ static int level_to_bucket(int level); @@ -5058,55 +4692,6 @@ wl_frame_paint(struct WFrameWindow *fwin) return 1; } -/* ------------------------------------------------------------------ */ -/* Context (window → object lookup table) — Phase 38 */ -/* ------------------------------------------------------------------ */ - -static void -wl_context_save(WNativeWindow win, WContextKey key, void *data) -{ - struct wl_list *list = &wl_state.ctx_lists[(int)key]; - struct wl_ctx_entry *e; - - /* update existing entry if present */ - wl_list_for_each(e, list, link) { - if (e->win == win) { e->data = data; return; } - } - /* new entry */ - e = wmalloc(sizeof(*e)); - e->win = win; - e->data = data; - wl_list_insert(list, &e->link); -} - -static void * -wl_context_find(WNativeWindow win, WContextKey key) -{ - struct wl_list *list = &wl_state.ctx_lists[(int)key]; - struct wl_ctx_entry *e; - - wl_list_for_each(e, list, link) { - if (e->win == win) return e->data; - } - return NULL; -} - -static int -wl_context_delete(WNativeWindow win, WContextKey key) -{ - struct wl_list *list = &wl_state.ctx_lists[(int)key]; - struct wl_ctx_entry *e, *tmp; - - wl_list_for_each_safe(e, tmp, list, link) { - if (e->win == win) { - wl_list_remove(&e->link); - wfree(e); - return 1; - } - } - return 0; /* not found */ -} - /* ------------------------------------------------------------------ */ /* Focus */ /* ------------------------------------------------------------------ */ diff --git a/src/backend/wayland/wl_context.c b/src/backend/wayland/wl_context.c new file mode 100644 index 0000000..bae7285 --- /dev/null +++ b/src/backend/wayland/wl_context.c @@ -0,0 +1,60 @@ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include + +#include "wl_types.h" + + +/* ------------------------------------------------------------------ */ +/* Context (window → object lookup table) — Phase 38 */ +/* ------------------------------------------------------------------ */ + +void +wl_context_save(WNativeWindow win, WContextKey key, void *data) +{ + struct wl_list *list = &wl_state.ctx_lists[(int)key]; + struct wl_ctx_entry *e; + + /* update existing entry if present */ + wl_list_for_each(e, list, link) { + if (e->win == win) { e->data = data; return; } + } + /* new entry */ + e = wmalloc(sizeof(*e)); + e->win = win; + e->data = data; + wl_list_insert(list, &e->link); +} + +void * +wl_context_find(WNativeWindow win, WContextKey key) +{ + struct wl_list *list = &wl_state.ctx_lists[(int)key]; + struct wl_ctx_entry *e; + + wl_list_for_each(e, list, link) { + if (e->win == win) return e->data; + } + return NULL; +} + +int +wl_context_delete(WNativeWindow win, WContextKey key) +{ + struct wl_list *list = &wl_state.ctx_lists[(int)key]; + struct wl_ctx_entry *e, *tmp; + + wl_list_for_each_safe(e, tmp, list, link) { + if (e->win == win) { + wl_list_remove(&e->link); + wfree(e); + return 1; + } + } + return 0; /* not found */ +} + diff --git a/src/backend/wayland/wl_types.h b/src/backend/wayland/wl_types.h new file mode 100644 index 0000000..9354d22 --- /dev/null +++ b/src/backend/wayland/wl_types.h @@ -0,0 +1,382 @@ +#ifndef WL_TYPES_H +#define WL_TYPES_H + +/* wl_types.h -- shared structs and global state for the Wayland backend */ + +#include +#include /* Phase 29+: WM-owned SHM surface buffers */ +#include "wl_backend.h" + +/* ------------------------------------------------------------------ */ +/* Phase 38: per-toplevel view and context store */ +/* ------------------------------------------------------------------ */ + +/* + * wl_toplevel_view -- one entry per XDG toplevel managed by the compositor. + * Holds the wlroots surface pointer, three lifecycle listeners, and a + * synthetic Window ID used as the policy-layer window handle. + */ +struct wl_toplevel_view { + struct wlr_xdg_surface *xdg_surface; + struct wl_listener map_listener; + struct wl_listener unmap_listener; + struct wl_listener destroy_listener; + struct wl_listener title_listener; /* Phase 46: xdg_toplevel set_title */ + struct wl_listener request_move_listener; /* Phase 15 */ + struct wl_listener request_resize_listener; /* Phase 15 */ + struct wl_listener request_maximize_listener; /* Phase 16 */ + struct wl_listener request_fullscreen_listener;/* Phase 16 */ + struct wl_listener request_minimize_listener; /* Phase 16 */ + struct wl_listener set_app_id_listener; /* Phase 16 */ + struct wl_listener commit_listener; /* initial configure */ + struct wl_listener surface_commit_listener; /* permanent commit listener */ + /* Phase 17: XWayland — set for X11 windows, NULL for XDG toplevels. */ + struct wlr_xwayland_surface *xw_surface; + /* Path 1: geometry listener — keeps scene node in sync when X11 window moves. */ + struct wl_listener xw_geometry_listener; + struct wl_listener xw_surface_map_listener; /* fires when wlr_surface maps */ + /* Phase 18: scene graph tree for this surface (NULL if scene unavailable). */ + struct wlr_scene_tree *scene_node; + /* Listener fires when scene_node is destroyed (e.g. when a parent + * tree is destroyed by wl_frame_destroy as part of unmanage). + * Without it, view->scene_node becomes a dangling pointer and the + * later handle_toplevel_destroy crashes calling wlr_scene_node_destroy + * a second time. */ + struct wl_listener scene_destroy_listener; + WNativeWindow id; /* synthetic handle, >= 0x10000000 */ + WNativeWindow frame_id; /* frame_buf that owns this view (0 = none) */ + int frame_rel_x, frame_rel_y; /* offset within frame */ + int x, y; /* Phase 55: WM-assigned position */ + /* wmaker-popup-v1: client-driven popup position (only valid if popup != NULL) */ + struct wl_resource *popup; /* wmaker_popup_v1 resource or NULL */ + int popup_x, popup_y; + struct wlr_xdg_toplevel *popup_parent; /* parent toplevel or NULL */ + long *wm_state; /* Phase 56: saved WM state or NULL */ + int wm_state_n; /* Phase 56: element count */ + char **wm_command; /* Phase 57: WM_COMMAND argv or NULL */ + int wm_command_n; /* Phase 57: argument count */ + /* Phase 35: foreign toplevel handle — exposes this window to taskbars. */ + struct wlr_foreign_toplevel_handle_v1 *ft_handle; + struct wl_list link; /* wl_state.toplevel_list */ +}; + +/* + * wl_or_view — tracks an override_redirect XWayland surface (WM frames, + * dock icons, menus, tooltips). These are not "managed" by the WM in the + * ICCCM sense but must be composited by the scene graph. + */ +struct wl_or_view { + struct wlr_xwayland_surface *xw_surface; + struct wlr_scene_tree *scene_node; + struct wl_listener map_listener; + struct wl_listener unmap_listener; + struct wl_listener destroy_listener; + struct wl_listener set_geometry_listener; + struct wl_list link; /* wl_state.or_list */ +}; + +/* + * wl_frame_buf — a pixman-backed scene buffer for WM frame windows. + * Each frame (titlebar + buttons + resizebar) is rendered into a single + * ARGB pixman image and displayed via a wlr_scene_buffer node. + */ +struct wl_frame_buf { + struct wlr_buffer base; /* wlr_buffer (must be first) */ + pixman_image_t *image; /* ARGB32 pixel data */ + struct wlr_scene_buffer *scene_buf; /* scene graph node */ + struct wlr_scene_tree *tree; /* grouping tree (top-level frames only) */ + /* Destroy listeners on scene_buf and tree so they get NULL'd when + * wlroots auto-destroys them (e.g. via cascade from parent tree + * destruction during wl_frame_destroy). Without these, code that + * later tries to wlr_scene_node_destroy them again segfaults inside + * wl_list_remove on already-zeroed list links. */ + struct wl_listener scene_buf_destroy; + struct wl_listener tree_destroy; + WNativeWindow id; /* synthetic ID (>= 0x10000000) */ + WNativeWindow parent_id; /* parent frame_buf ID (0 = root) */ + int x, y; /* position in output coords */ + int rel_x, rel_y; /* position relative to parent */ + int width, height; + pixman_image_t *bg_pixmap; /* background pixmap for window_clear */ + struct wl_list link; /* wl_state.frame_list */ +}; + +/* + * Phase 36: wl_layer_view — one entry per mapped zwlr_layer_shell_v1 surface. + * Tracks the wlroots layer surface, its scene node, and lifecycle listeners. + */ +struct wl_layer_view { + struct wlr_layer_surface_v1 *layer_surface; + struct wlr_scene_tree *scene_node; + struct wl_listener map_listener; + struct wl_listener unmap_listener; + struct wl_listener destroy_listener; + struct wl_list link; /* wl_state.layer_list */ +}; + +/* + * Context store: three per-key linked lists keyed by WNativeWindow. + * Backed by a flat list of (win, data) pairs — fine for the small + * number of windows a typical user has open. + */ +struct wl_ctx_entry { + WNativeWindow win; + void *data; + struct wl_list link; +}; + +/* ------------------------------------------------------------------ */ +/* Global compositor state */ +/* ------------------------------------------------------------------ */ + +struct wl_compositor_state { + struct wl_display *display; + struct wlr_backend *backend; + struct wlr_renderer *renderer; + struct wlr_output *output; /* headless output (screen 0) */ + struct wlr_output_layout *output_layout; /* Phase 34 */ + /* Phase 35: core Wayland protocol globals */ + struct wlr_compositor *compositor; + struct wlr_seat *seat; + struct wlr_data_device_manager *data_device_mgr; + struct wlr_xdg_shell *xdg_shell; + /* wmaker-popup-v1 protocol global — client-driven popup positioning */ + struct wl_global *wmaker_popup_manager; + /* Phase 64: XDG decoration manager — tell clients to use CSD */ + struct wlr_xdg_decoration_manager_v1 *decoration_manager; + struct wl_listener decoration_new_listener; + /* Phase 36: XDG toplevel tracking */ + struct wl_listener xdg_new_surface_listener; + int managed_surface_count; /* surfaces seen */ + /* Phase 37: periodic timer that drives client frame callbacks */ + struct wl_event_source *frame_timer; + /* Phase 38: per-toplevel view list and context store */ + struct wl_list toplevel_list; /* wl_toplevel_view.link */ + struct wl_list or_list; /* wl_or_view.link */ + struct wl_list frame_list; /* wl_frame_buf.link */ + struct wl_list layer_list; /* wl_layer_view.link */ + struct wl_list ctx_lists[3]; /* one per WContextKey */ + unsigned long next_synthetic_id; /* >= 0x10000000 */ + /* Phase 43: first real keyboard device (set by handle_backend_new_input) */ + struct wlr_input_device *keyboard_dev; + struct xkb_keymap *xkb_keymap; /* default keymap for keysym lookup */ + struct wl_listener keyboard_key_listener; /* Phase 78 */ + struct wl_listener keyboard_modifiers_listener; /* Phase 78 */ + /* Phase 53: first real pointer device (set by handle_backend_new_input) */ + struct wlr_input_device *pointer_dev; + /* Phase 54: virtual pointer position (screen coordinates) */ + int pointer_x, pointer_y; + /* Phase 14: pointer event listeners wired to pointer_dev->pointer */ + struct wl_listener pointer_motion_listener; + struct wl_listener pointer_motion_abs_listener; + struct wl_listener pointer_button_listener; + struct wl_listener pointer_frame_listener; + /* Phase 17: XWayland server for X11 client support */ + struct wlr_xwayland *xwayland; + struct wl_listener xwayland_new_surface_listener; + struct wl_listener xwayland_ready_listener; + struct wl_listener xwayland_server_destroy_listener; + bool xwayland_ready; /* set by handle_xwayland_ready */ + Display *x_display; /* WM's Xlib connection to own XWayland */ + struct wl_event_source *x11_event_source; /* wl_event_loop fd watcher for x_display */ + pthread_t startup_pump_thread; /* pumps Wayland event loop during StartUp() */ + volatile int startup_pump_running; /* 1 while pump thread is active */ + volatile int terminate; /* set to exit main loop */ + /* Phase 20: real input devices from nested backend + their listeners */ + struct wlr_input_device *real_keyboard_dev; + struct wlr_input_device *real_pointer_dev; + struct wl_listener backend_new_input_listener; + struct wl_listener real_keyboard_key_listener; + struct wl_listener real_keyboard_modifiers_listener; + struct wl_listener real_keyboard_destroy_listener; + struct wl_listener real_pointer_motion_abs_listener; + struct wl_listener real_pointer_button_listener; + struct wl_listener real_pointer_frame_listener; + /* Phase 18: nested Wayland + wlr_scene */ + int is_nested; /* 1 if using wlr_wl_backend */ + struct wlr_backend *headless_inner; /* headless backend (always) */ + struct wlr_backend *wl_backend_inner; /* wl backend (nested only) */ + struct wlr_session *session; /* DRM session (standalone only) */ + struct wlr_allocator *allocator; + struct wlr_scene *scene; + struct wlr_scene_output *scene_output; + struct wl_listener backend_new_output_listener; + struct wl_listener output_frame_listener; + char socket_name[64]; /* Phase 34: e.g. "wayland-0" */ + int started; /* non-zero after successful display_open */ + /* Self-pipe for async-signal-safe shutdown: signal handler writes to [1], + * event loop reads [0] and calls wl_display_terminate(). */ + int shutdown_pipe[2]; + struct wl_event_source *shutdown_source; + /* signalfd-based signal handling: primary mechanism for catching + * SIGTERM/SIGINT/SIGHUP from within the event loop (avoids async-signal- + * safety issues with the traditional signal handler path). */ + int sigfd; + struct wl_event_source *sigfd_source; + /* Phase 22: interactive move/resize grab state. + * grab_type: 0=none, 1=move, 2=resize, 3=WM policy grab. + * Type 3 is used by wl_pointer_grab for WM-internal drags (dock icons, + * app icons, menus). It suppresses wl_update_pointer_focus (so client + * surfaces don't steal pointer events) but does NOT intercept motion — + * WME_MOTION events flow normally to the WMMaskEvent loop. + * grab_view: the toplevel being moved/resized (NULL when grab_type==0 or 3). + * grab_start_ptr_{x,y}: pointer position when grab started. + * grab_start_win_{x,y,w,h}: window geometry when grab started. + * grab_resize_edges: WL_SHELL_SURFACE_RESIZE_* bitmask (resize only). */ + int grab_type; + struct wl_toplevel_view *grab_view; + int grab_start_ptr_x, grab_start_ptr_y; + int grab_start_win_x, grab_start_win_y; + int grab_start_win_w, grab_start_win_h; + uint32_t grab_resize_edges; + /* Phase 23: hardware cursor and xcursor theme. */ + struct wlr_cursor *cursor; + struct wlr_xcursor_manager *xcursor_mgr; + /* Phase 24: seat cursor-surface request listener. */ + struct wl_listener seat_request_cursor_listener; + /* Phase 25: clipboard — seat selection request listener. */ + struct wl_listener seat_request_set_selection_listener; + /* Phase 25b: drag-and-drop — seat request_start_drag listener. */ + struct wl_listener seat_request_start_drag_listener; + /* Phase 26: primary selection (middle-click paste). */ + struct wlr_primary_selection_v1_device_manager *primary_selection_mgr; + struct wl_listener seat_request_primary_selection_listener; + /* Phase 27: xdg-output manager for logical output geometry. */ + struct wlr_xdg_output_manager_v1 *xdg_output_mgr; + /* Phase 28: idle-inhibit manager for video players / fullscreen apps. */ + struct wlr_idle_inhibit_manager_v1 *idle_inhibit_mgr; + struct wl_listener idle_new_inhibitor_listener; + /* Phase 29: wp_viewporter for hardware video scaling / subsurface damage. */ + struct wlr_viewporter *viewporter; + /* Phase 30: relative pointer + pointer constraints for games. */ + struct wlr_relative_pointer_manager_v1 *relative_pointer_mgr; + struct wlr_pointer_constraints_v1 *pointer_constraints; + struct wl_listener new_constraint_listener; + /* Phase 31: keyboard shortcuts inhibitor for fullscreen / remote desktop. */ + struct wlr_keyboard_shortcuts_inhibit_manager_v1 *shortcuts_inhibit_mgr; + struct wl_listener new_shortcuts_inhibitor_listener; + /* Phase 32: GPU zero-copy buffer import, screencopy, GPU framebuffer export. */ + struct wlr_linux_dmabuf_v1 *linux_dmabuf; + struct wlr_screencopy_manager_v1 *screencopy_mgr; + struct wlr_export_dmabuf_manager_v1 *export_dmabuf_mgr; + /* Phase 33: output management (randr), output power (DPMS), gamma control, presentation time. */ + struct wlr_output_manager_v1 *output_mgr; + struct wl_listener output_mgr_apply_listener; + struct wl_listener output_mgr_test_listener; + struct wlr_output_power_manager_v1 *output_power_mgr; + struct wl_listener output_power_set_mode_listener; + struct wlr_gamma_control_manager_v1 *gamma_control_mgr; + struct wlr_presentation *presentation; + /* Phase 34: text input (IME client side), input method (IME server side), virtual keyboard. */ + struct wlr_text_input_manager_v3 *text_input_mgr; + struct wl_listener text_input_new_listener; + struct wlr_input_method_manager_v2 *input_method_mgr; + struct wl_listener input_method_new_listener; + struct wlr_virtual_keyboard_manager_v1 *virtual_keyboard_mgr; + struct wl_listener virtual_keyboard_new_listener; + /* Phase 35: foreign toplevel management + xdg_activation (focus tokens). */ + struct wlr_foreign_toplevel_manager_v1 *foreign_toplevel_mgr; + struct wlr_xdg_activation_v1 *xdg_activation; + struct wl_listener xdg_activation_request_listener; + /* Phase 36: layer shell — panels, docks, wallpapers, overlays. */ + struct wlr_layer_shell_v1 *layer_shell; + struct wl_listener layer_shell_new_surface_listener; + /* Phase 37: clipboard manager, input inhibitor, virtual pointer, idle, xdg-foreign. */ + struct wlr_data_control_manager_v1 *data_control_mgr; + struct wlr_virtual_pointer_manager_v1 *virtual_pointer_mgr; + struct wl_listener virtual_pointer_new_listener; + struct wlr_xdg_foreign_registry *xdg_foreign_registry; + struct wlr_xdg_foreign_v2 *xdg_foreign_v2; + /* Phase 29 axis listeners (headless pointer + real nested pointer). */ + struct wl_listener pointer_axis_listener; + struct wl_listener real_pointer_axis_listener; + struct wl_listener real_pointer_destroy_listener; + /* Phase 30: WM dock panel (native Wayland rendering via wm_shm_surface). */ + struct wm_shm_surface *dock_surface; /* NULL until screen_create_internals */ + int dock_width; /* pixels reserved on right edge */ + int dock_icon_sz; /* icon_sz saved by wm_dock_create */ + int dock_n_slots; /* slot count saved by wm_dock_create */ +/* Phase 30+: managed app list for dock icon rendering */ +#define WM_DOCK_MAX_APPS 32 + struct { + WNativeWindow id; + uint32_t *icon_argb; /* heap ARGB8888, or NULL */ + int icon_w, icon_h; + } dock_apps[WM_DOCK_MAX_APPS]; + int dock_app_count; + /* Stacking level trees — one wlr_scene_tree per layer, ordered + * bottom-to-top (index 0 rendered first = furthest back). + * + * Every scene node that participates in the compositor output is + * assigned to exactly one bucket so that creation order within the + * root tree never matters and there are no Z-order surprises. + * + * Named constants (WL_LAYER_*) map to bucket indices: + * + * 0 WL_LAYER_BACKGROUND background rect / wallpaper + * 1 WL_LAYER_DESKTOP WMDesktopLevel (level < -1) + * 2 WL_LAYER_SUNKEN WMSunkenLevel (level == -1) + * 3 WL_LAYER_NORMAL WMNormalLevel (0 <= level < 3) + * 4 WL_LAYER_FLOATING WMFloatingLevel (3 <= level < 20) + * 5 WL_LAYER_MENU WMMainMenuWindowLevel (20), OR-redirect + * 6 WL_LAYER_DOCK WMStatusWindowLevel / WMDockWindowLevel (21-49) + * also the dock panel wm_shm_surface + * 7 WL_LAYER_FULLSCREEN WMFullscreenLevel (50-99) + * 8 WL_LAYER_OVERLAY WMModalPanel / WMPopUp (>=100) + * also the XOR animation overlay surface + */ +#define WL_LAYER_BACKGROUND 0 +#define WL_LAYER_DESKTOP 1 +#define WL_LAYER_SUNKEN 2 +#define WL_LAYER_NORMAL 3 +#define WL_LAYER_FLOATING 4 +#define WL_LAYER_MENU 5 +#define WL_LAYER_DOCK 6 +#define WL_LAYER_FULLSCREEN 7 +#define WL_LAYER_OVERLAY 8 +#define WL_NUM_LEVEL_BUCKETS 9 + struct wlr_scene_tree *level_trees[WL_NUM_LEVEL_BUCKETS]; + struct wlr_scene_rect *bg_rect; /* default solid background */ + struct wlr_scene_buffer *bg_image; /* wallpaper image (if set) */ + struct wlr_buffer *bg_wlr_buf; /* backing buffer for bg_image */ + + /* Phase 81: full-screen overlay surface for XOR animation drawing */ + struct wm_shm_surface *overlay_surf; /* NULL until first draw */ + /* Focus sink: small off-screen InputOnly X window that receives focus + * when no application window is focused. Mirrors what x11_backend does + * for no_focus_win so that XSetInputFocus calls on this window succeed. */ + WNativeWindow no_focus_xwin; /* 0 until screen_create_internals */ + /* wrlib RContext drawable — an ordinary InputOutput window that XWM must + * not manage (no WM_CLASS, no backing wl_surface). Stored here so + * handle_xwayland_new_surface can filter it before allocating a view. */ + WNativeWindow rcontext_xwin; /* 0 until screen_alloc_gcs */ + /* Deferred dock creation: set in screen_create_internals, consumed in + * wl_event_loop_run() after the startup pump thread stops (to avoid racing + * with the pump thread's frame-timer callback on the scene graph). */ + WScreen *dock_pending_scr; + /* Button icon RImages (parsed from XPM on first use) */ + RImage *btn_close_img; + RImage *btn_iconify_img; + RImage *btn_kill_img; + /* Tracks the frame_buf the pointer was last over (after button resolution), + * so motion handlers can emit synthetic WME_LEAVE/WME_ENTER events when + * the pointer crosses between WM frame sub-windows (titlebar, resizebar, + * buttons). buttonMouseDown's inner press-track loop depends on these. */ + WNativeWindow last_hovered_id; + /* Focus guard: when true, the next focus-follows-pointer event is suppressed. + * Set by switchpanel_send_enter (called twice in wSwitchPanelDestroy) to prevent + * spurious focus changes when the Alt-Tab overlay is destroyed and the pointer + * re-enters the root window or a client surface underneath. */ + bool ignore_focus_ffp; + /* Keyboard grab: when true, key events are queued for WMMaskEvent but not + * forwarded to Wayland clients (used by Alt-Tab cycling). */ + bool keyboard_grabbed; +}; + +extern struct wl_compositor_state wl_state; + +void wl_context_save(WNativeWindow win, WContextKey key, void *data); +void * wl_context_find(WNativeWindow win, WContextKey key); +int wl_context_delete(WNativeWindow win, WContextKey key); + +#endif /* WL_TYPES_H */