From 60aab98e8d6451be335f95776258479cc4effdeb Mon Sep 17 00:00:00 2001 From: Consolatis <35009135+Consolatis@users.noreply.github.com> Date: Thu, 7 Mar 2024 02:11:46 +0100 Subject: [PATCH] Add optional headless fallback output This allows configuring a headless fallback output that is automatically created whenever there is no other output around. It is destroyed when a new output is discovered. It can be enabled by setting the environment variable LABWC_FALLBACK_OUTPUT to the desired output name. The feature benefits applications like wayvnc the most as there is always an output available to connect to. Co-Authored-By: Simon Long --- docs/environment | 15 +++++++++++++++ include/output-virtual.h | 1 + src/output-virtual.c | 36 +++++++++++++++++++++++++++++++++++- src/output.c | 7 +++++++ src/server.c | 5 +++++ 5 files changed, 63 insertions(+), 1 deletion(-) diff --git a/docs/environment b/docs/environment index 151d9921..be1fd29b 100644 --- a/docs/environment +++ b/docs/environment @@ -68,3 +68,18 @@ # XDG_CURRENT_DESKTOP=wlroots +## +## This causes a virtual output to be created automatically whenever there +## are no outputs around. This helps for cases like wayvnc so there is always +## an output available to connect to. The name can be chosen freely but there +## must be no duplicate output names, for this reason using VIRTUAL-x or a +## physical connector name like HDMI-A-1 is not recommended as wlroots may +## want to create outputs with those names later on which would then fail. +## +## Using an output name that starts with NOOP- has the additional benefit +## that wayvnc will detect it being a virtual output and allow clients to +## resize the output to match the client resolution. +## + +# LABWC_FALLBACK_OUTPUT=NOOP-fallback + diff --git a/include/output-virtual.h b/include/output-virtual.h index 4bceb39c..7822e4f7 100644 --- a/include/output-virtual.h +++ b/include/output-virtual.h @@ -8,5 +8,6 @@ struct wlr_output; void output_virtual_add(struct server *server, const char *output_name, struct wlr_output **store_wlr_output); void output_virtual_remove(struct server *server, const char *output_name); +void output_virtual_update_fallback(struct server *server); #endif diff --git a/src/output-virtual.c b/src/output-virtual.c index 72b1e068..51fc4ac3 100644 --- a/src/output-virtual.c +++ b/src/output-virtual.c @@ -1,10 +1,14 @@ // SPDX-License-Identifier: GPL-2.0-only +#include #include #include +#include "common/string-helpers.h" #include "labwc.h" #include "output-virtual.h" +static struct wlr_output *fallback_output = NULL; + void output_virtual_add(struct server *server, const char *output_name, struct wlr_output **store_wlr_output) @@ -77,7 +81,8 @@ output_virtual_remove(struct server *server, const char *output_name) { struct output *output; wl_list_for_each(output, &server->outputs, link) { - if (!wlr_output_is_headless(output->wlr_output)) { + if (!wlr_output_is_headless(output->wlr_output) + || output->wlr_output == fallback_output) { continue; } @@ -100,3 +105,32 @@ output_virtual_remove(struct server *server, const char *output_name) } } } + +void +output_virtual_update_fallback(struct server *server) +{ + struct wl_list *layout_outputs = &server->output_layout->outputs; + const char *fallback_output_name = getenv("LABWC_FALLBACK_OUTPUT"); + + if (!fallback_output && wl_list_empty(layout_outputs) + && !string_null_or_empty(fallback_output_name)) { + wlr_log(WLR_DEBUG, "adding fallback output %s", fallback_output_name); + + output_virtual_add(server, fallback_output_name, &fallback_output); + } else if (fallback_output && (wl_list_length(layout_outputs) > 1 + || string_null_or_empty(fallback_output_name))) { + wlr_log(WLR_DEBUG, "destroying fallback output %s", + fallback_output->name); + + /* + * We must reset fallback_output to NULL before destroying it. + * + * Otherwise we may end up trying to destroy the same wlr_output + * twice due to wlr_output_destroy() removing the output from the + * layout which in turn causes us to be called again. + */ + struct wlr_output *wlr_output = fallback_output; + fallback_output = NULL; + wlr_output_destroy(wlr_output); + } +} diff --git a/src/output.c b/src/output.c index aad280e8..6f5ebf05 100644 --- a/src/output.c +++ b/src/output.c @@ -24,6 +24,7 @@ #include "labwc.h" #include "layers.h" #include "node.h" +#include "output-virtual.h" #include "regions.h" #include "view.h" #include "xwayland.h" @@ -694,6 +695,12 @@ handle_output_layout_change(struct wl_listener *listener, void *data) { struct server *server = wl_container_of(listener, server, output_layout_change); + + /* Prevents unnecessary layout recalculations */ + server->pending_output_layout_change++; + output_virtual_update_fallback(server); + server->pending_output_layout_change--; + do_output_layout_change(server); } diff --git a/src/server.c b/src/server.c index 5d57ff2f..41ba2163 100644 --- a/src/server.c +++ b/src/server.c @@ -27,6 +27,7 @@ #include "labwc.h" #include "layers.h" #include "menu/menu.h" +#include "output-virtual.h" #include "regions.h" #include "resize_indicator.h" #include "theme.h" @@ -69,6 +70,7 @@ handle_sighup(int signal, void *data) { session_environment_init(); reload_config_and_theme(); + output_virtual_update_fallback(g_server); return 0; } @@ -490,6 +492,9 @@ server_start(struct server *server) exit(EXIT_FAILURE); } + /* Potentially set up the initial fallback output */ + output_virtual_update_fallback(server); + if (setenv("WAYLAND_DISPLAY", socket, true) < 0) { wlr_log_errno(WLR_ERROR, "unable to set WAYLAND_DISPLAY"); } else { -- 2.52.0