feat: implement Openbox-style bottom window handle and grips

Add full handle/grip assembly to the bottom of SSD window frames,
following the Openbox themerc specification for geometry and theming.
Theme parsing:
- Parse window.handle.width (handle bar height, default 6)
- Parse window.grip.width (corner grip width, default 20)
- Parse window.[active|inactive].handle.bg with Solid/Gradient support
- Parse window.[active|inactive].grip.bg (inherits from handle if unset)
- Pre-render 1px-wide fill buffers and cairo patterns for handle/grip
Scene graph (new ssd-handle.c):
- Handle assembly replaces bottom border when active, with its own
  left/right/top borders and three-segment bottom border
- Grips at left/right corners for diagonal resize (sw/se-resize)
- Center handle for vertical resize (s-resize)
- Vertical separator lines between grips and handle using border color
- Per Openbox spec, handle_width is content-only height with borders
  drawn around it (total assembly height = 2*border_width + handle_width)
Interactive visual states (grips only):
- Hover: 20% black overlay on grip content area
- Pressed: 40% black overlay with 1px inset shadow (dark top/left,
  light bottom/right) for a pushed-in 3D effect
- Dragging: 20% overlay with inset shadow maintained
- Global hover tracking (server.hovered_handle_ssd/element) ensures
  proper cleanup when cursor moves across views or to desktop
Decoration toggle cycle (ToggleDecorations action):
- New LAB_SSD_MODE_BORDER_HANDLE between BORDER and FULL
- keepBorder=true: full -> border+handle -> border -> none -> full
- keepBorder=false: full -> none -> full (unchanged)
Node types and input:
- New LAB_NODE_HANDLE, LAB_NODE_GRIP_LEFT, LAB_NODE_GRIP_RIGHT
- Integrated into LAB_NODE_BORDER/BORDER_BOTTOM containment so
  existing Border context mousebinds (Resize) work automatically
- Handle/grip descriptors resolved directly in get_cursor_context()
  bypassing ssd_get_resizing_type() for precise cursor shapes
Visibility rules:
- Hidden when maximized, shaded, or handle_width is 0
- Hidden in LAB_SSD_MODE_BORDER and LAB_SSD_MODE_NONE states
- Bottom border in ssd-border.c disabled when handle is active
Documentation:
- labwc-theme.5.scd: document all handle/grip theme properties
- labwc-actions.5.scd: update ToggleDecorations to 4-state cycle
- docs/themerc: add handle/grip default values
This commit is contained in:
stormshadow 2026-05-14 06:23:49 +05:30
parent 4af693a7fd
commit ba5a0b9829
19 changed files with 1132 additions and 17 deletions

View file

@ -217,13 +217,14 @@ Actions are used in menus and keyboard/mouse bindings.
*<action name="ToggleDecorations" />*
Toggle decorations of focused window.
This is a 3-state action which can be executed multiple times:
- Only the titlebar will be hidden, borders and resize area are kept
This is a 4-state action which can be executed multiple times:
- Titlebar is hidden; borders and handle/grip remain visible
- Handle/grip is also hidden; only borders remain
- Remaining decorations will be disabled
- Decorations will be shown normally
By disabling the theme configuration 'keepBorder' the first step
will be removed and the action only toggles between on and off.
By disabling the theme configuration 'keepBorder' the cycle reduces
to toggling between full decorations and no decorations.
*<action name="ToggleFullscreen" />*
Toggle fullscreen state of focused window.
@ -526,9 +527,10 @@ Actions that execute other actions. Used in keyboard/mouse bindings.
Whether the client is tiled (snapped) to the indicated
region. The indicated region may be a glob.
*decoration* [full|border|none]
*decoration* [full|border-handle|border|none]
Whether the client has full server-side decorations,
borders only, or no server-side decorations.
borders with handle/grip, borders only, or no
server-side decorations.
*monitor* [current|left|right|<monitor_name>]
Whether the client is on a monitor relative to the to