mirror of
				https://github.com/labwc/labwc.git
				synced 2025-11-03 09:01:51 -05: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