Add allOutputs option to window switcher

Introduces a new configuration option for the window switcher
that allows users to filter windows by output (monitor).

Changes:
- Added `allOutputs` attribute to <windowSwitcher>
  - Default is "no" (only shows windows on the cursor's output)
  - When set to "yes", shows windows from all outputs

- Introduced LAB_VIEW_CRITERIA_CURSOR_OUTPUT flag to filter views by output
  - Windows are matched against the output nearest to the cursor
  - Bit positions of existing criteria flags shifted to accommodate new flag

- Modified OSD display behavior to show only on the cursor's output
  - Previously, the OSD would appear on all outputs simultaneously
  - Now displays only on the output nearest to the cursor location

This provides better multi-monitor support by allowing users to focus on
windows relevant to their current screen, reducing visual clutter when
working across multiple displays.
This commit is contained in:
Samet Aylak 2025-11-02 08:54:29 -05:00
parent 0f62648d39
commit 764cd942eb
No known key found for this signature in database
GPG key ID: E5DEF544B937EE49
6 changed files with 43 additions and 16 deletions

View file

@ -339,7 +339,7 @@ this is for compatibility with Openbox.
## WINDOW SWITCHER ## WINDOW SWITCHER
``` ```
<windowSwitcher show="yes" style="classic" preview="yes" outlines="yes" allWorkspaces="no"> <windowSwitcher show="yes" style="classic" preview="yes" outlines="yes" allWorkspaces="no" allOutputs="no">
<fields> <fields>
<field content="icon" width="5%" /> <field content="icon" width="5%" />
<field content="desktop_entry_name" width="30%" /> <field content="desktop_entry_name" width="30%" />
@ -348,7 +348,7 @@ this is for compatibility with Openbox.
</windowSwitcher> </windowSwitcher>
``` ```
*<windowSwitcher show="" style="" preview="" outlines="" allWorkspaces="" unshade="">* *<windowSwitcher show="" style="" preview="" outlines="" allWorkspaces="" allOutputs="" unshade="">*
*show* [yes|no] Draw the OnScreenDisplay when switching between *show* [yes|no] Draw the OnScreenDisplay when switching between
windows. Default is yes. windows. Default is yes.
@ -366,6 +366,10 @@ this is for compatibility with Openbox.
they are on. Default no (that is only windows on the current workspace they are on. Default no (that is only windows on the current workspace
are shown). are shown).
*allOutputs* [yes|no] Show windows regardless of what output
they are on. Default no (that is only windows on the cursor output
are shown).
*unshade* [yes|no] Temporarily unshade windows when switching between *unshade* [yes|no] Temporarily unshade windows when switching between
them and permanently unshade on the final selection. Default is yes. them and permanently unshade on the final selection. Default is yes.

View file

@ -78,7 +78,7 @@
</theme> </theme>
<windowSwitcher show="yes" style="classic" preview="yes" <windowSwitcher show="yes" style="classic" preview="yes"
outlines="yes" allWorkspaces="no" unshade="yes"> outlines="yes" allWorkspaces="no" allOutputs="no" unshade="yes">
<fields> <fields>
<field content="icon" width="5%" /> <field content="icon" width="5%" />
<field content="desktop_entry_name" width="30%" /> <field content="desktop_entry_name" width="30%" />
@ -98,7 +98,7 @@
Some contents are fixed-length and others are variable-length. Some contents are fixed-length and others are variable-length.
See "man 5 labwc-config" for details. See "man 5 labwc-config" for details.
<windowSwitcher show="yes" preview="no" outlines="no" allWorkspaces="yes"> <windowSwitcher show="yes" preview="no" outlines="no" allWorkspaces="yes" allOutputs="no">
<fields> <fields>
<field content="workspace" width="5%" /> <field content="workspace" width="5%" />
<field content="state" width="3%" /> <field content="state" width="3%" />
@ -118,7 +118,7 @@
then workspace name, then identifier/app-id, then the window title. then workspace name, then identifier/app-id, then the window title.
It uses 100% of OSD window width. It uses 100% of OSD window width.
<windowSwitcher show="yes" preview="no" outlines="no" allWorkspaces="yes"> <windowSwitcher show="yes" preview="no" outlines="no" allWorkspaces="yes" allOutputs="no">
<fields> <fields>
<field content="custom" format="foobar %b %3s %-10o %-20W %-10i %t" width="100%" /> <field content="custom" format="foobar %b %3s %-10o %-20W %-10i %t" width="100%" />
</fields> </fields>

View file

@ -67,16 +67,17 @@ enum lab_view_criteria {
* what is visible on the current workspace * what is visible on the current workspace
*/ */
LAB_VIEW_CRITERIA_CURRENT_WORKSPACE = 1 << 0, LAB_VIEW_CRITERIA_CURRENT_WORKSPACE = 1 << 0,
LAB_VIEW_CRITERIA_CURSOR_OUTPUT = 1 << 1,
/* Positive criteria */ /* Positive criteria */
LAB_VIEW_CRITERIA_FULLSCREEN = 1 << 1, LAB_VIEW_CRITERIA_FULLSCREEN = 1 << 2,
LAB_VIEW_CRITERIA_ALWAYS_ON_TOP = 1 << 2, LAB_VIEW_CRITERIA_ALWAYS_ON_TOP = 1 << 3,
LAB_VIEW_CRITERIA_ROOT_TOPLEVEL = 1 << 3, LAB_VIEW_CRITERIA_ROOT_TOPLEVEL = 1 << 4,
/* Negative criteria */ /* Negative criteria */
LAB_VIEW_CRITERIA_NO_ALWAYS_ON_TOP = 1 << 6, LAB_VIEW_CRITERIA_NO_ALWAYS_ON_TOP = 1 << 7,
LAB_VIEW_CRITERIA_NO_SKIP_WINDOW_SWITCHER = 1 << 7, LAB_VIEW_CRITERIA_NO_SKIP_WINDOW_SWITCHER = 1 << 8,
LAB_VIEW_CRITERIA_NO_OMNIPRESENT = 1 << 8, LAB_VIEW_CRITERIA_NO_OMNIPRESENT = 1 << 9,
}; };
/* /*

View file

@ -1217,6 +1217,11 @@ entry(xmlNode *node, char *nodename, char *content)
rc.window_switcher.criteria &= rc.window_switcher.criteria &=
~LAB_VIEW_CRITERIA_CURRENT_WORKSPACE; ~LAB_VIEW_CRITERIA_CURRENT_WORKSPACE;
} }
} else if (!strcasecmp(nodename, "allOutputs.windowSwitcher")) {
if (parse_bool(content, -1) == true) {
rc.window_switcher.criteria &=
~LAB_VIEW_CRITERIA_CURSOR_OUTPUT;
}
} else if (!strcasecmp(nodename, "unshade.windowSwitcher")) { } else if (!strcasecmp(nodename, "unshade.windowSwitcher")) {
set_bool(content, &rc.window_switcher.unshade); set_bool(content, &rc.window_switcher.unshade);
@ -1433,6 +1438,7 @@ rcxml_init(void)
rc.window_switcher.outlines = true; rc.window_switcher.outlines = true;
rc.window_switcher.unshade = true; rc.window_switcher.unshade = true;
rc.window_switcher.criteria = LAB_VIEW_CRITERIA_CURRENT_WORKSPACE rc.window_switcher.criteria = LAB_VIEW_CRITERIA_CURRENT_WORKSPACE
| LAB_VIEW_CRITERIA_CURSOR_OUTPUT
| LAB_VIEW_CRITERIA_ROOT_TOPLEVEL | LAB_VIEW_CRITERIA_ROOT_TOPLEVEL
| LAB_VIEW_CRITERIA_NO_SKIP_WINDOW_SWITCHER; | LAB_VIEW_CRITERIA_NO_SKIP_WINDOW_SWITCHER;

View file

@ -292,11 +292,20 @@ update_osd(struct server *server)
if (rc.window_switcher.show) { if (rc.window_switcher.show) {
/* Display the actual OSD */ /* Display the actual OSD */
struct output *output; // struct output *output;
wl_list_for_each(output, &server->outputs, link) { // wl_list_for_each(output, &server->outputs, link) {
if (!output_is_usable(output)) { // if (!output_is_usable(output)) {
continue; // continue;
} // }
// if (!output->osd_scene.tree) {
// osd_impl->create(output, &views);
// assert(output->osd_scene.tree);
// }
// osd_impl->update(output);
// }
struct output *output = output_nearest_to_cursor(server);
if (output_is_usable(output)) {
if (!output->osd_scene.tree) { if (!output->osd_scene.tree) {
osd_impl->create(output, &views); osd_impl->create(output, &views);
assert(output->osd_scene.tree); assert(output->osd_scene.tree);

View file

@ -277,6 +277,13 @@ matches_criteria(struct view *view, enum lab_view_criteria criteria)
return false; return false;
} }
} }
if (criteria & LAB_VIEW_CRITERIA_CURSOR_OUTPUT) {
struct server *server = view->server;
struct output *output = output_nearest_to_cursor(server);
if (view->output != output) {
return false;
}
}
if (criteria & LAB_VIEW_CRITERIA_FULLSCREEN) { if (criteria & LAB_VIEW_CRITERIA_FULLSCREEN) {
if (!view->fullscreen) { if (!view->fullscreen) {
return false; return false;