mirror of
https://github.com/labwc/labwc.git
synced 2025-11-01 22:58:47 -04:00
src/output.c: refactor virtual output related functions
This commit moves the virtual output related functions into their own file at `src/output-virtual.c` with its own include file to reduce `include/labwc.h` bit by bit. Additionally, it removes the need to keep the `server->headless.pending_output_name` char array around by temporarily disconnecting the handler when creating a new virtual output. This allows to set the output name right in the `output_virtual_add()` call rather than to store the pending name until the new output event handler has been called. It also makes adding a virtual fallback output easier in a follow-up PR.
This commit is contained in:
parent
40ce95a68c
commit
95e8573388
6 changed files with 132 additions and 65 deletions
|
|
@ -211,7 +211,6 @@ struct server {
|
||||||
struct wlr_backend *backend;
|
struct wlr_backend *backend;
|
||||||
struct headless {
|
struct headless {
|
||||||
struct wlr_backend *backend;
|
struct wlr_backend *backend;
|
||||||
char pending_output_name[4096];
|
|
||||||
} headless;
|
} headless;
|
||||||
struct wlr_session *session;
|
struct wlr_session *session;
|
||||||
|
|
||||||
|
|
@ -491,8 +490,6 @@ struct wlr_box output_usable_area_in_layout_coords(struct output *output);
|
||||||
struct wlr_box output_usable_area_scaled(struct output *output);
|
struct wlr_box output_usable_area_scaled(struct output *output);
|
||||||
void handle_output_power_manager_set_mode(struct wl_listener *listener,
|
void handle_output_power_manager_set_mode(struct wl_listener *listener,
|
||||||
void *data);
|
void *data);
|
||||||
void output_add_virtual(struct server *server, const char *output_name);
|
|
||||||
void output_remove_virtual(struct server *server, const char *output_name);
|
|
||||||
void output_enable_adaptive_sync(struct wlr_output *output, bool enabled);
|
void output_enable_adaptive_sync(struct wlr_output *output, bool enabled);
|
||||||
void new_tearing_hint(struct wl_listener *listener, void *data);
|
void new_tearing_hint(struct wl_listener *listener, void *data);
|
||||||
|
|
||||||
|
|
|
||||||
12
include/output-virtual.h
Normal file
12
include/output-virtual.h
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||||
|
#ifndef LABWC_OUTPUT_VIRTUAL_H
|
||||||
|
#define LABWC_OUTPUT_VIRTUAL_H
|
||||||
|
|
||||||
|
struct server;
|
||||||
|
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);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -16,6 +16,7 @@
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
#include "labwc.h"
|
#include "labwc.h"
|
||||||
#include "menu/menu.h"
|
#include "menu/menu.h"
|
||||||
|
#include "output-virtual.h"
|
||||||
#include "placement.h"
|
#include "placement.h"
|
||||||
#include "regions.h"
|
#include "regions.h"
|
||||||
#include "ssd.h"
|
#include "ssd.h"
|
||||||
|
|
@ -996,14 +997,15 @@ actions_run(struct view *activator, struct server *server,
|
||||||
{
|
{
|
||||||
const char *output_name = action_get_str(action, "output_name",
|
const char *output_name = action_get_str(action, "output_name",
|
||||||
NULL);
|
NULL);
|
||||||
output_add_virtual(server, output_name);
|
output_virtual_add(server, output_name,
|
||||||
|
/*store_wlr_output*/ NULL);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case ACTION_TYPE_VIRTUAL_OUTPUT_REMOVE:
|
case ACTION_TYPE_VIRTUAL_OUTPUT_REMOVE:
|
||||||
{
|
{
|
||||||
const char *output_name = action_get_str(action, "output_name",
|
const char *output_name = action_get_str(action, "output_name",
|
||||||
NULL);
|
NULL);
|
||||||
output_remove_virtual(server, output_name);
|
output_virtual_remove(server, output_name);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case ACTION_TYPE_AUTO_PLACE:
|
case ACTION_TYPE_AUTO_PLACE:
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@ labwc_sources = files(
|
||||||
'node.c',
|
'node.c',
|
||||||
'osd.c',
|
'osd.c',
|
||||||
'output.c',
|
'output.c',
|
||||||
|
'output-virtual.c',
|
||||||
'placement.c',
|
'placement.c',
|
||||||
'regions.c',
|
'regions.c',
|
||||||
'resistance.c',
|
'resistance.c',
|
||||||
|
|
|
||||||
102
src/output-virtual.c
Normal file
102
src/output-virtual.c
Normal file
|
|
@ -0,0 +1,102 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-only
|
||||||
|
|
||||||
|
#include <wlr/backend/headless.h>
|
||||||
|
#include <wlr/types/wlr_output.h>
|
||||||
|
#include "labwc.h"
|
||||||
|
#include "output-virtual.h"
|
||||||
|
|
||||||
|
void
|
||||||
|
output_virtual_add(struct server *server, const char *output_name,
|
||||||
|
struct wlr_output **store_wlr_output)
|
||||||
|
{
|
||||||
|
if (output_name) {
|
||||||
|
/* Prevent creating outputs with the same name */
|
||||||
|
struct output *output;
|
||||||
|
wl_list_for_each(output, &server->outputs, link) {
|
||||||
|
if (wlr_output_is_headless(output->wlr_output) &&
|
||||||
|
!strcmp(output->wlr_output->name, output_name)) {
|
||||||
|
wlr_log(WLR_DEBUG,
|
||||||
|
"refusing to create virtual output with duplicate name");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The headless backend will always emit the new output signal (and
|
||||||
|
* thus call our handler) before `wlr_headless_add_output()` returns.
|
||||||
|
*
|
||||||
|
* This makes it impossible to
|
||||||
|
* - modify the output before it gets enabled in the handler
|
||||||
|
* - use a pointer of the new wlr_output within the handler
|
||||||
|
*
|
||||||
|
* So we temporarily disconnect the handler when creating the output
|
||||||
|
* and then call the handler manually.
|
||||||
|
*
|
||||||
|
* This is important because some operations like `wlr_output_set_name()`
|
||||||
|
* can only be done before the output has been enabled.
|
||||||
|
*
|
||||||
|
* If we add a virtual output before the headless backend has been started
|
||||||
|
* we may end up calling the new output handler twice, one time manually
|
||||||
|
* and one time by the headless backend when it starts up and sends the
|
||||||
|
* signal for all its configured outputs. Rather than keeping a global
|
||||||
|
* server->headless.started state around that we could check here we just
|
||||||
|
* ignore duplicated new output calls in new_output_notify().
|
||||||
|
*/
|
||||||
|
wl_list_remove(&server->new_output.link);
|
||||||
|
|
||||||
|
struct wlr_output *wlr_output = wlr_headless_add_output(
|
||||||
|
server->headless.backend, 1920, 1080);
|
||||||
|
|
||||||
|
if (!wlr_output) {
|
||||||
|
wlr_log(WLR_ERROR, "Failed to create virtual output %s",
|
||||||
|
output_name ? output_name : "");
|
||||||
|
goto restore_handler;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (output_name) {
|
||||||
|
wlr_output_set_name(wlr_output, output_name);
|
||||||
|
}
|
||||||
|
if (store_wlr_output) {
|
||||||
|
/* Ensures that we can use the new wlr_output pointer within new_output_nofity() */
|
||||||
|
*store_wlr_output = wlr_output;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Notify about the new output manually */
|
||||||
|
if (server->new_output.notify) {
|
||||||
|
server->new_output.notify(&server->new_output, wlr_output);
|
||||||
|
}
|
||||||
|
|
||||||
|
restore_handler:
|
||||||
|
/* And finally restore output notifications */
|
||||||
|
wl_signal_add(&server->backend->events.new_output, &server->new_output);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
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)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (output_name) {
|
||||||
|
/*
|
||||||
|
* Given virtual output name, find and
|
||||||
|
* destroy virtual output by that name.
|
||||||
|
*/
|
||||||
|
if (!strcmp(output->wlr_output->name, output_name)) {
|
||||||
|
wlr_output_destroy(output->wlr_output);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/*
|
||||||
|
* When virtual output name was not supplied by user,
|
||||||
|
* simply destroy the first virtual output found.
|
||||||
|
*/
|
||||||
|
wlr_output_destroy(output->wlr_output);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
73
src/output.c
73
src/output.c
|
|
@ -10,7 +10,6 @@
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <strings.h>
|
#include <strings.h>
|
||||||
#include <wlr/backend/drm.h>
|
#include <wlr/backend/drm.h>
|
||||||
#include <wlr/backend/headless.h>
|
|
||||||
#include <wlr/backend/wayland.h>
|
#include <wlr/backend/wayland.h>
|
||||||
#include <wlr/types/wlr_buffer.h>
|
#include <wlr/types/wlr_buffer.h>
|
||||||
#include <wlr/types/wlr_drm_lease_v1.h>
|
#include <wlr/types/wlr_drm_lease_v1.h>
|
||||||
|
|
@ -227,15 +226,22 @@ new_output_notify(struct wl_listener *listener, void *data)
|
||||||
struct server *server = wl_container_of(listener, server, new_output);
|
struct server *server = wl_container_of(listener, server, new_output);
|
||||||
struct wlr_output *wlr_output = data;
|
struct wlr_output *wlr_output = data;
|
||||||
|
|
||||||
/* Name virtual output */
|
struct output *output;
|
||||||
if (wlr_output_is_headless(wlr_output) && server->headless.pending_output_name[0] != '\0') {
|
wl_list_for_each(output, &server->outputs, link) {
|
||||||
wlr_output_set_name(wlr_output, server->headless.pending_output_name);
|
if (output->wlr_output == wlr_output) {
|
||||||
server->headless.pending_output_name[0] = '\0';
|
/*
|
||||||
|
* This is a duplicated notification.
|
||||||
|
* We may end up here when a virtual output
|
||||||
|
* was added before the headless backend was
|
||||||
|
* started up.
|
||||||
|
*/
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We offer any display as available for lease, some apps like
|
* We offer any display as available for lease, some apps like
|
||||||
* gamescope, want to take ownership of a display when they can
|
* gamescope want to take ownership of a display when they can
|
||||||
* to use planes and present directly.
|
* to use planes and present directly.
|
||||||
* This is also useful for debugging the DRM parts of
|
* This is also useful for debugging the DRM parts of
|
||||||
* another compositor.
|
* another compositor.
|
||||||
|
|
@ -305,7 +311,7 @@ new_output_notify(struct wl_listener *listener, void *data)
|
||||||
|
|
||||||
wlr_output_commit(wlr_output);
|
wlr_output_commit(wlr_output);
|
||||||
|
|
||||||
struct output *output = znew(*output);
|
output = znew(*output);
|
||||||
output->wlr_output = wlr_output;
|
output->wlr_output = wlr_output;
|
||||||
wlr_output->data = output;
|
wlr_output->data = output;
|
||||||
output->server = server;
|
output->server = server;
|
||||||
|
|
@ -894,59 +900,6 @@ handle_output_power_manager_set_mode(struct wl_listener *listener, void *data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
output_add_virtual(struct server *server, const char *output_name)
|
|
||||||
{
|
|
||||||
if (output_name) {
|
|
||||||
/* Prevent creating outputs with the same name */
|
|
||||||
struct output *output;
|
|
||||||
wl_list_for_each(output, &server->outputs, link) {
|
|
||||||
if (wlr_output_is_headless(output->wlr_output) &&
|
|
||||||
!strcmp(output->wlr_output->name, output_name)) {
|
|
||||||
wlr_log(WLR_DEBUG,
|
|
||||||
"refusing to create virtual output with duplicate name");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
snprintf(server->headless.pending_output_name,
|
|
||||||
sizeof(server->headless.pending_output_name), "%s", output_name);
|
|
||||||
} else {
|
|
||||||
server->headless.pending_output_name[0] = '\0';
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
* Setting it to (0, 0) here disallows changing resolution from tools like
|
|
||||||
* wlr-randr (returns error)
|
|
||||||
*/
|
|
||||||
wlr_headless_add_output(server->headless.backend, 1920, 1080);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
output_remove_virtual(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 (output_name) {
|
|
||||||
/*
|
|
||||||
* Given virtual output name, find and destroy virtual output by
|
|
||||||
* that name.
|
|
||||||
*/
|
|
||||||
if (!strcmp(output->wlr_output->name, output_name)) {
|
|
||||||
wlr_output_destroy(output->wlr_output);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
/*
|
|
||||||
* When virtual output name was no supplied by user, simply
|
|
||||||
* destroy the first virtual output found.
|
|
||||||
*/
|
|
||||||
wlr_output_destroy(output->wlr_output);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
output_enable_adaptive_sync(struct wlr_output *output, bool enabled)
|
output_enable_adaptive_sync(struct wlr_output *output, bool enabled)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue