Commit graph

1159 commits

Author SHA1 Message Date
John Lindgren
16c5373be5 tree-wide: use die_if_null() for wlr_scene alloc failures
Some checks failed
labwc.github.io / notify (push) Has been cancelled
wlr_scene_*_create() functions all allocate memory via calloc() and
return NULL if the allocation fails. Previously, the failures were
handled in any of 3 different ways:

 - sending a wayland protocol error
 - exiting labwc with an error
 - segfault (no NULL check at all)

Since labwc does not attempt to survive heap exhaustion in other
allocation paths (such as `znew`), it seems more consistent to use the
same die_if_null() check used in those paths to exit with an error.

For the three most common create() functions (tree, rect, buffer),
add small lab_wlr_ wrappers to common/scene-helpers.
2026-03-15 21:26:37 +00:00
Consolatis
4faab834f9 xwayland: make X11 always-on-top request opt-in
Fixes: #3441
2026-03-15 13:09:05 +01:00
tokyo4j
3bb4ccd22d view: save view->last_placement on initial positioning
Fix a regression introduced in 3f223fe5 where output layout changes may
move xdg views outside of the output layout with the error:
`view has no last placement info`. This happens also for X11 views if
they don't specify its own geometry on map.

Recent changes introduced `view->last_placement` which is used to
restore view positions after layout changes. This is supposed to be
updated when a view is mapped or manually moved by the user.

However, 3f223fe5 replaced `view_place_by_policy()` with
`view_compute_position_by_policy()` in the xdg view map handler. Unlike
`view_place_by_policy()`, this function does not update
`view->last_placement`, leaving it unset at the time of output layout
changes.

Therefore, this patch adds explicit calls to `view_save_last_placement()`
in the map handler to ensure `view->last_placement` is always set for
mapped views.
2026-03-10 21:05:53 +09:00
tokyo4j
00f63622b5 interactive: subtle refactor to interactive_set_grab_context()
- Add `server` argument to `interactive_set_grab_context()` to clarify
  it updates something in `server`.
- Add `const` qualifier to `ctx` argument of
  `interactive_set_grab_context()` and `cursor_get_resize_edges()`
2026-03-05 19:19:01 +09:00
John Lindgren
df73a97efa view: add/improve some comments 2026-03-05 19:06:59 +09:00
John Lindgren
5238dcaa08 view: factor out view_compute_position_by_policy() 2026-03-05 19:06:59 +09:00
John Lindgren
d4ca1dfb69 view: make view_move_to_cursor() static 2026-03-05 19:06:59 +09:00
John Lindgren
72cdd02eb1 xwayland: handle client close request 2026-03-02 17:58:33 +01:00
John Lindgren
079b3b8a10 xwayland: honor client request for always-on-top 2026-03-01 01:40:46 +01:00
John Lindgren
13200cc0d7 view: add view_set_layer() 2026-03-01 01:40:46 +01:00
Johan Malm
bdbb1be35a layer: focus popup rather than layer-shell surface
When a opening a layer-shell popup via IPC (like `lxVqt-qdbus openmenu` or
`xfce4-popup-applicationsmenu`), give keyboard focus to the popup, not the
parent layer-shell surface.

Written-by: @tokyo4j
2026-02-21 14:05:56 +00:00
Johan Malm
a277c35c3d layer: on popup destory, return focus
...to whoever had it before the popop

Co-authored-by: @tokyo4j
2026-02-21 14:05:56 +00:00
Johan Malm
180293e0bb Give keyboard focus to xdg-popups of unfocused layer-shell clients
...in support of enabling panel menus to be opened by keyboard shortcuts
and get keyboard focus so that they can be operated with the keyboard.

An example use-case is the xfce4-panel applications-menu being opened by
the command xfce4-popup-applicationmenu.
2026-02-21 14:05:56 +00:00
tokyo4j
a2eae22fc2 view: decouple always-on-top windows from the omnipresent state
Before this commit, always-on-{top,bottom} windows were always visible
on all workspaces (omnipresent) because the they were not in
per-workspace trees like normal windows.

This commit fixes this by introducing per-layer trees in
`struct workspace`.

I also added `enum view_layer` and `view->layer` for simplicity.
2026-02-12 14:44:20 +09:00
John Lindgren
a672e8a9fd interactive: set grab parameters at cursor press
Add interactive_set_grab_context() which is called when the mouse button
is first pressed, before interactive_begin(). This fixes two small issues:

- The cursor origin position for interactive move/resize was slightly
  off (depending on mouse resolution), because it was set after the
  mouse had already moved slightly. Now it's exact.

- If app- or keybind-initiated maximize (etc.) happened after the button
  press but before the mouse was moved, then interactive_begin() would
  still start move/resize even though the view might now be far away
  from the cursor. Now interactive_cancel() works as expected, even if
  called before interactive_begin().

Also, make sure to call interactive_cancel() for un-maximize as well.
2026-02-10 21:29:16 +00:00
Johan Malm
54554f43dd theme: add option window.button.hover.bg.color 2026-02-08 18:45:48 +00:00
tokyo4j
12b6d05481 view: fix error messages on region or usable area changes
f58b532 implemented output-relative position saving/restoring on output
un-plugging/re-plugging. It worked as follows:

1. Store the output-relative view geometry in `view->last_placement`
  (if not set) before adding/removing an output from the layout.
2. After adding/removing an output, call `view_adjust_for_layout_change()`
  after the layout change to restore the output-relative view geometry
  based on `view->last_placement`.

However, it didn't consider `view_adjust_for_layout_change()` being
called from other places such as `regions_reconfigure()` and
`output_update_all_usable_areas()`, causing an error message "view has
no last placement info". This can happen when a panel is mapped or
unmapped, or on Reconfigure.

This commit fixes it by changing the life cycle of
`view->last_placement`. It used to be set only before output layout
changes and cleared on user-initiated moves/resizes, but now it is set
and updated on user-initiated moves/resizes. I think this is more
intuitive, too.
2026-02-04 19:14:51 +09:00
tokyo4j
7fabc6afe3 string-helpers: update comments for str_equal() 2026-02-04 19:14:51 +09:00
tokyo4j
55a256f2fa desktop: use for_each_view() in desktop_topmost_focusable_view()
Fixes a regression in 83b619c2 that the bottom-most view is focused
when when an exclusive layer surface (e.g. fuzzel) is unfocused.

Also, added some comments to clarify the order.
2026-01-31 17:16:13 +01:00
tokyo4j
37618a1456 Avoid double use of struct workspace
`struct workspace` was used both for representing an actual workspace
and for an entry of workspace configuration. Avoid it for clarity.
2026-01-30 18:41:37 +01:00
tokyo4j
4819f47f98 cycle: fix spurious focus changes on finishing window switcher
As described in the `FIXME` comment in `cycle.c`, we had spurious focus
changes where the keyboard focus is momentarily given to the previously
focused window when finishing the window switcher, an then it is given
to the selected window.

This commit fixes this by adding a parameter in
`seat_focus_override_end()` to avoid restoring the focus to the
previously focused window.

I also removed the check for `!seat->seat->keyboard_state.focused_surface`
in `seat_focus_override_end()`. I thought it was necessary to avoid
updating the keyboard focus if the focus was given to a session-lock
surface before e.g. finishing window switching, but `seat_focus()` is
no-op in that case anyway.
2026-01-30 17:06:30 +00:00
tokyo4j
a62441ff77 cycle: show non-dialog child windows in window switcher
Before this commit, the window switcher skipped all the child windows.

However, as child windows not marked as modal dialogs can lose focus
(ref. `desktop_focus_view()`), it will make sense to include them in the
window switcher so that users can refocus them with keyboard.
This behavior follows KWin.
2026-01-27 21:10:32 +00:00
tokyo4j
87586104cd view: add view_is_modal_dialog() 2026-01-27 21:10:32 +00:00
tokyo4j
37c7de32c8 view: keep and restore the output-relative position on layout changes
Before this patch, we always tried to preserve the global positions of
floating windows across layout changes, which meant that windows could
jump to different outputs if the output coordinates changed.

Instead, this patch adds the output name and output-relative position in
`view->last_placement` to keep them across layout changes, like KDE and
GNOME do.

This also allows us to remove `view->lost_output_due_to_layout_change`,
which was required to keep the output of fullscreen/maximized windows,
since we now always try to keep `view->output` whether or not the window
is floating.
2026-01-15 02:10:31 +09:00
tokyo4j
f58b532214 view: save last placement info before layout change
I will add output name and relative view position in
`view->last_placement` later, which needs to be saved before layout
changes unlike the global position.
2026-01-15 02:10:31 +09:00
tokyo4j
ee52853e69 view: rename last_layout_geometry to last_placement.layout_geo 2026-01-15 02:10:31 +09:00
John Lindgren
20929c0484 view: rework saving/restoring geometry across layout changes
After several iterations, this is basically a complete re-work. The old
implementation was difficult to follow and sometimes failed to restore
fullscreen/maximized/tiled geometry correctly, since it was based
entirely on natural (floating) geometry.

The new implementation:
 - always saves the actual (pending) geometry at first layout change
 - explicitly tracks whether a view has moved between outputs
 - consolidates invalidating the saved geometry into one place, rather
   than having lots of invalidate() calls sprinkled everywhere
2026-01-12 17:41:02 +09:00
John Lindgren
f5909ac54d view: eliminate store_natural_geometry arguments
These were added to fix handling of natural geometry for snap-to-edge
behavior back in 9021020f6e and seemed like a good idea at the time.
Since then, the number of call sites has exploded, so it seems more
maintainable to put explicit checks for interactive move within the
three functions affected.
2026-01-01 12:54:16 +00:00
tokyo4j
742c2b53fd cycle: implement scrollable OSD
Before this commit, the OSD could overflow the screen when displaying
many window items. In this commit, we hide the overflowed items and
show a scrollbar to fit the OSD within the screen.
2025-12-31 22:46:53 +00:00
tokyo4j
8ad96c0410 cycle: add server->cycle_preview_tree
This doesn't change any behaviors.
2025-12-28 21:03:03 +00:00
tokyo4j
dfe428ae14 cycle: refactor to aggregate type definitions into cycle.h
We declared `cycle_state` struct in `labwc.h` and `cycle_osd_scene`
struct in `output.h`, which was unclean in terms of separation of
concerns.

So this commit firstly moves `cycle_state` to `cycle.h`, then replaces
`cycle_osd_scene` in `output.h` with `cycle_osd_output` in `cycle.h`
which is dynamically allocated in a similar manner to
`session_lock_output`. This ensures that all states about alt-tabbing
are stored in `server->cycle`.

Also, this commit fixes a rare memory leak in `output->cycle_osd.items`
when an output is destroyed while alt-tabbing, by freeing it when the
osd tree is destroyed.
2025-12-28 20:57:37 +00:00
tokyo4j
610d869561 cycle: add <action name="NextWindow" output="" and identifier="">
Some checks failed
labwc.github.io / notify (push) Has been cancelled
output="all|focused|cursor" filters windows by the output they are on.
identifier="all|current" filters windows by their app-id.
2025-12-26 05:25:54 +09:00
tokyo4j
a5c6ff499c cycle: support <action name="NextWindow" workspace="current|all">
This commit deprecates <windowSwitcher allWorkspaces="yes|no"> and adds
per-action argument <action name="NextWindow" workspace="current|all">.
2025-12-26 05:25:54 +09:00
Cameron Scott McCreery
64aec6ff5d
workspaces: add config option for initial workspace selection
Some checks failed
labwc.github.io / notify (push) Has been cancelled
2025-12-22 22:17:43 +01:00
tokyo4j
64af206114 Rename cycle_osd_output_criteria to cycle_output_filter 2025-12-22 18:57:51 +00:00
tokyo4j
e2d83ff7f5 rcxml: sync rcxml.window_switcher with XML format 2025-12-22 18:57:51 +00:00
Maik Broemme
8fdf375af3
window-switcher: add order parameter to allow stable window list ordering
Some checks failed
labwc.github.io / notify (push) Has been cancelled
Add a new configuration option to control the window switcher traversal order.

`order="focus"` cycling is convenient for quick toggling, but some users - me as well -
prefer a stable taskbar-like order which can now be achieved with `order="age"`.
2025-12-08 18:54:23 +01:00
John Lindgren
a1d8ebc0de node: update node_descriptor_create() comment 2025-12-07 14:55:32 +09:00
elviosak
94d33f9119
snapping: replace <snapping><range> with <snapping><range inner="" outer=""> (#3241)
Some checks failed
labwc.github.io / notify (push) Has been cancelled
<inner>/<outer> configure the size of snapping area on output edges with/without adjacent outputs.
2025-12-06 16:09:28 +09:00
John Lindgren
d748dc78bc xwayland: flush XCB connection to mitigate race between Raise and input
Some checks are pending
labwc.github.io / notify (push) Waiting to run
2025-12-02 19:50:03 +01:00
tokyo4j
c4277ab507 cycle: update config to <osd output="all|cursor|focused">
I think `<windowSwitcher><osd output="keyboard">` is a bit unclear and
hard to interpret as "show OSD in the output with keyboard focus". Also,
we use "cursor" instead of "pointer" in other configurations like
`<placement policy="cursor">` and `<action name="ShowMenu" atCursor="">`.

So let's replace `output="all|pointer|keyboard"` with
`output="all|cursor|focused"`. In documentation, I reordered them to
`output="all|focused|cursor"` as "focused" feels like a bit more
sophisticated and general policy.
2025-12-02 17:09:54 +01:00
John Lindgren
7f7b5f57ec xdg: center small fullscreen views and add black background fill 2025-12-02 14:57:41 +09:00
John Lindgren
5ea617a393 box: factor out box_center() 2025-12-02 14:57:41 +09:00
tokyo4j
9f5ff391cc cycle: remember cycled window list in server->cycle.views
This allows changing the cycled order in the future, e.g. focused order vs
created order.

Functionally, this commit also changes the initially selected window;
before this commit, the previous/next of the topmost window was always
selected, but now the previous/next of the active window is selected first
if it is in the cycled list. This won't change behaviors for most users,
but this ensures that the user can go back to the focused window with
Alt-Tab + Alt-Shift-Tab even when it is not the topmost window.

This commit fixes the TODO in the previous commit by trying to preserve
the selected view when a view is destroyed during window cycling.
2025-11-30 21:33:46 +00:00
tokyo4j
b6c1a9ea59 cycle: clarify the lifecycle of window switcher
This commit clarifies the lifecycle of the window switcher (cycle) by:
- init_cycle(): initializes the window switcher (e.g. OSD).
- update_cycle(): updates the window switcher states including OSD,
  preview and outlines.
- destroy_cycle(): clears all the window switcher states.

This commit temporarily regresses by not trying to preserve the selected
view when a view is destroyed. This will be addressed in the next commit.
2025-11-30 21:33:46 +00:00
tokyo4j
2b28c41b23 cycle: use dummy node to remember the scene position of previewed window
With this approach, we only need to store cycle->dummy_node instead of
cycle->preview_anchor and cycle->preview_parent and we don't need to care
about annoying cases like when the previewed window has no siblings or
when a window tracked by cycle->preview_anchor is destroyed.
2025-11-30 20:56:34 +09:00
tokyo4j
e4ebc30c90 cursor: update focus on entering SSD if followMouse=yes
This fixes a known regression in 885919fc that cursor entering the
titlebar (and other SSD parts) doesn't update the keyboard focus even when
followMouse=yes.
2025-11-30 20:55:54 +09:00
tokyo4j
acb3da7903 cursor: generalize seat->pressed
This commit moduralize seat_{set,reset}_pressed() into
cursor_context_save() so that we can also have seat->hovered later.
2025-11-30 20:55:54 +09:00
tokyo4j
4fcb873f6f Use "cycle" instead of "osd" across the codebase
We were using the word "osd" to describe the window switcher, but it can
be used with on-screen display (OSD) disabled by
`<windowSwitcher><osd show="false">`. Let's use "cycle" instead to avoid
confusion.
2025-11-30 16:20:16 +09:00
tokyo4j
65cc2e40ba Rename osd.{h,c} to cycle.{h,c} 2025-11-30 16:20:16 +09:00