osd: add multi-monitor support
Some checks failed
labwc.github.io / notify (push) Has been cancelled

Adds `output` attribute to control which monitor(s) display the window
switcher OSD. Supports three modes:
- "all": display on all monitors (default)
- "pointer": display on monitor with mouse cursor
- "keyboard": display on monitor with keyboard focus

The configuration structure is also refactored to nest OSD-specific
settings (show, style, output, thumbnailLabelFormat) under an <osd>
element within <windowSwitcher>, improving logical organization.
This commit is contained in:
Samet Aylak 2025-11-09 23:16:26 -05:00 committed by GitHub
parent 79fbb611e0
commit d65caf8bfd
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 105 additions and 25 deletions

View file

@ -1068,7 +1068,7 @@ entry(xmlNode *node, char *nodename, char *content)
load_default_mouse_bindings();
} else if (!strcasecmp(nodename, "prefix.desktops")) {
xstrdup_replace(rc.workspace_config.prefix, content);
} else if (!strcasecmp(nodename, "thumbnailLabelFormat.windowSwitcher")) {
} else if (!strcasecmp(nodename, "thumbnailLabelFormat.osd.windowSwitcher")) {
xstrdup_replace(rc.window_switcher.thumbnail_label_format, content);
} else if (!lab_xml_node_is_leaf(node)) {
@ -1201,15 +1201,50 @@ entry(xmlNode *node, char *nodename, char *content)
wlr_log(WLR_ERROR, "ignoring invalid value for notifyClient");
}
/* <windowSwitcher show="" preview="" outlines="" /> */
/*
* <windowSwitcher preview="" outlines="">
* <osd show="" style="" output="" thumbnailLabelFormat="" />
* </windowSwitcher>
*
* thumnailLabelFormat is handled above to allow for an empty value
*/
} else if (!strcasecmp(nodename, "show.osd.windowSwitcher")) {
set_bool(content, &rc.window_switcher.show);
} else if (!strcasecmp(nodename, "style.osd.windowSwitcher")) {
if (!strcasecmp(content, "classic")) {
rc.window_switcher.style = WINDOW_SWITCHER_CLASSIC;
} else if (!strcasecmp(content, "thumbnail")) {
rc.window_switcher.style = WINDOW_SWITCHER_THUMBNAIL;
} else {
wlr_log(WLR_ERROR, "Invalid windowSwitcher style %s: "
"should be one of classic|thumbnail", content);
}
} else if (!strcasecmp(nodename, "output.osd.windowSwitcher")) {
if (!strcasecmp(content, "all")) {
rc.window_switcher.output_criteria = OSD_OUTPUT_ALL;
} else if (!strcasecmp(content, "pointer")) {
rc.window_switcher.output_criteria = OSD_OUTPUT_POINTER;
} else if (!strcasecmp(content, "keyboard")) {
rc.window_switcher.output_criteria = OSD_OUTPUT_KEYBOARD;
} else {
wlr_log(WLR_ERROR, "Invalid windowSwitcher output %s: "
"should be one of all|pointer|keyboard", content);
}
/* The following two are for backward compatibility only. */
} else if (!strcasecmp(nodename, "show.windowSwitcher")) {
set_bool(content, &rc.window_switcher.show);
wlr_log(WLR_ERROR, "<windowSwitcher show=\"\" /> is deprecated."
" Use <osd show=\"\" />");
} else if (!strcasecmp(nodename, "style.windowSwitcher")) {
if (!strcasecmp(content, "classic")) {
rc.window_switcher.style = WINDOW_SWITCHER_CLASSIC;
} else if (!strcasecmp(content, "thumbnail")) {
rc.window_switcher.style = WINDOW_SWITCHER_THUMBNAIL;
}
wlr_log(WLR_ERROR, "<windowSwitcher style=\"\" /> is deprecated."
" Use <osd style=\"\" />");
} else if (!strcasecmp(nodename, "preview.windowSwitcher")) {
set_bool(content, &rc.window_switcher.preview);
} else if (!strcasecmp(nodename, "outlines.windowSwitcher")) {
@ -1431,6 +1466,7 @@ rcxml_init(void)
rc.window_switcher.show = true;
rc.window_switcher.style = WINDOW_SWITCHER_CLASSIC;
rc.window_switcher.output_criteria = OSD_OUTPUT_ALL;
rc.window_switcher.thumbnail_label_format = xstrdup("%T");
rc.window_switcher.preview = true;
rc.window_switcher.outlines = true;

View file

@ -294,6 +294,20 @@ preview_cycled_view(struct view *view)
wlr_scene_node_raise_to_top(osd_state->preview_node);
}
static void
update_osd_on_output(struct server *server, struct output *output,
struct osd_impl *osd_impl, struct wl_array *views)
{
if (!output_is_usable(output)) {
return;
}
if (!output->osd_scene.tree) {
osd_impl->create(output, views);
assert(output->osd_scene.tree);
}
osd_impl->update(output);
}
static void
update_osd(struct server *server)
{
@ -318,16 +332,29 @@ update_osd(struct server *server)
if (rc.window_switcher.show) {
/* Display the actual OSD */
struct output *output;
wl_list_for_each(output, &server->outputs, link) {
if (!output_is_usable(output)) {
continue;
switch (rc.window_switcher.output_criteria) {
case OSD_OUTPUT_ALL: {
struct output *output;
wl_list_for_each(output, &server->outputs, link) {
update_osd_on_output(server, output, osd_impl, &views);
}
break;
}
if (!output->osd_scene.tree) {
osd_impl->create(output, &views);
assert(output->osd_scene.tree);
case OSD_OUTPUT_POINTER:
update_osd_on_output(server,
output_nearest_to_cursor(server), osd_impl, &views);
break;
case OSD_OUTPUT_KEYBOARD: {
struct output *output;
if (server->active_view) {
output = server->active_view->output;
} else {
/* Fallback to pointer, if there is no active_view */
output = output_nearest_to_cursor(server);
}
update_osd_on_output(server, output, osd_impl, &views);
break;
}
osd_impl->update(output);
}
}