Add wlr_output_manager support

This allows things like wlr-randr to work.

wlr-randr or similar can send in two new events: `output_manager_apply'
and `output_manager_test'.  In output.c, their handler both call an new
`output_manager_configure' function which loops through the list of
outputs twice.  The first loop applies all the requested configuration
ad checks that its not all messed up.  The second loop either commits
that configuration or reverts it depending on whether it worked and
whether we're responding to a test event.

There's also now an output_manager_update function, called whenever the
output layout is changed, which copies changes from the
wlr_output_layout to the wlr_output_manager.
This commit is contained in:
Uks2 2022-06-22 07:27:17 +01:00
parent cb7c6334fc
commit 69507ee640
5 changed files with 162 additions and 0 deletions

View file

@ -17,6 +17,7 @@ struct kiwmi_desktop {
struct wlr_layer_shell_v1 *layer_shell; struct wlr_layer_shell_v1 *layer_shell;
struct wlr_data_device_manager *data_device_manager; struct wlr_data_device_manager *data_device_manager;
struct wlr_output_layout *output_layout; struct wlr_output_layout *output_layout;
struct wlr_output_manager_v1 *output_manager;
struct wl_list outputs; // struct kiwmi_output::link struct wl_list outputs; // struct kiwmi_output::link
struct wl_list views; // struct kiwmi_view::link struct wl_list views; // struct kiwmi_view::link
@ -26,6 +27,8 @@ struct kiwmi_desktop {
struct wl_listener xdg_toplevel_new_decoration; struct wl_listener xdg_toplevel_new_decoration;
struct wl_listener layer_shell_new_surface; struct wl_listener layer_shell_new_surface;
struct wl_listener new_output; struct wl_listener new_output;
struct wl_listener output_manager_apply;
struct wl_listener output_manager_test;
struct { struct {
struct wl_signal new_output; struct wl_signal new_output;

View file

@ -42,6 +42,10 @@ struct kiwmi_render_data {
}; };
void new_output_notify(struct wl_listener *listener, void *data); void new_output_notify(struct wl_listener *listener, void *data);
void output_layout_change_notify(struct wl_listener *listener, void *data);
void output_manager_apply_notify(struct wl_listener *listener, void *data);
void output_manager_test_notify(struct wl_listener *listener, void *data);
void output_manager_update(struct kiwmi_desktop *desktop);
void output_damage(struct kiwmi_output *output); void output_damage(struct kiwmi_output *output);

View file

@ -17,6 +17,7 @@
#include <wlr/types/wlr_export_dmabuf_v1.h> #include <wlr/types/wlr_export_dmabuf_v1.h>
#include <wlr/types/wlr_layer_shell_v1.h> #include <wlr/types/wlr_layer_shell_v1.h>
#include <wlr/types/wlr_output_layout.h> #include <wlr/types/wlr_output_layout.h>
#include <wlr/types/wlr_output_management_v1.h>
#include <wlr/types/wlr_xdg_decoration_v1.h> #include <wlr/types/wlr_xdg_decoration_v1.h>
#include <wlr/types/wlr_xdg_output_v1.h> #include <wlr/types/wlr_xdg_output_v1.h>
#include <wlr/types/wlr_xdg_shell.h> #include <wlr/types/wlr_xdg_shell.h>
@ -79,6 +80,14 @@ desktop_init(struct kiwmi_desktop *desktop)
wl_signal_init(&desktop->events.view_map); wl_signal_init(&desktop->events.view_map);
wl_signal_init(&desktop->events.request_active_output); wl_signal_init(&desktop->events.request_active_output);
desktop->output_manager = wlr_output_manager_v1_create(server->wl_display);
desktop->output_manager_apply.notify = output_manager_apply_notify;
wl_signal_add(
&desktop->output_manager->events.apply, &desktop->output_manager_apply);
desktop->output_manager_test.notify = output_manager_test_notify;
wl_signal_add(
&desktop->output_manager->events.test, &desktop->output_manager_test);
return true; return true;
} }

View file

@ -18,6 +18,7 @@
#include <wlr/types/wlr_matrix.h> #include <wlr/types/wlr_matrix.h>
#include <wlr/types/wlr_output.h> #include <wlr/types/wlr_output.h>
#include <wlr/types/wlr_output_layout.h> #include <wlr/types/wlr_output_layout.h>
#include <wlr/types/wlr_output_management_v1.h>
#include <wlr/types/wlr_surface.h> #include <wlr/types/wlr_surface.h>
#include <wlr/types/wlr_xcursor_manager.h> #include <wlr/types/wlr_xcursor_manager.h>
#include <wlr/util/log.h> #include <wlr/util/log.h>
@ -242,6 +243,31 @@ output_frame_notify(struct wl_listener *listener, void *data)
wlr_output_commit(wlr_output); wlr_output_commit(wlr_output);
} }
void
output_manager_update(struct kiwmi_desktop *desktop)
{
struct wlr_output_configuration_v1 *configuration =
wlr_output_configuration_v1_create();
struct kiwmi_output *output;
wl_list_for_each (output, &desktop->outputs, link) {
struct wlr_output_configuration_head_v1 *head =
wlr_output_configuration_head_v1_create(
configuration, output->wlr_output);
struct wlr_box *area = wlr_output_layout_get_box(
desktop->output_layout, output->wlr_output);
if (area != NULL) {
head->state.x = area->x;
head->state.y = area->y;
}
}
wlr_output_manager_v1_set_configuration(
desktop->output_manager, configuration);
}
static void static void
output_commit_notify(struct wl_listener *listener, void *data) output_commit_notify(struct wl_listener *listener, void *data)
{ {
@ -264,6 +290,7 @@ output_destroy_notify(struct wl_listener *listener, void *UNUSED(data))
if (output->desktop->output_layout) { if (output->desktop->output_layout) {
wlr_output_layout_remove( wlr_output_layout_remove(
output->desktop->output_layout, output->wlr_output); output->desktop->output_layout, output->wlr_output);
output_manager_update(output->desktop);
} }
wl_signal_emit(&output->events.destroy, output); wl_signal_emit(&output->events.destroy, output);
@ -297,6 +324,7 @@ output_mode_notify(struct wl_listener *listener, void *UNUSED(data))
arrange_layers(output); arrange_layers(output);
output_damage(output); output_damage(output);
output_manager_update(output->desktop);
wl_signal_emit(&output->events.resize, output); wl_signal_emit(&output->events.resize, output);
} }
@ -377,6 +405,7 @@ new_output_notify(struct wl_listener *listener, void *data)
wl_list_insert(&desktop->outputs, &output->link); wl_list_insert(&desktop->outputs, &output->link);
wlr_output_layout_add_auto(desktop->output_layout, wlr_output); wlr_output_layout_add_auto(desktop->output_layout, wlr_output);
output_manager_update(desktop);
wlr_output_create_global(wlr_output); wlr_output_create_global(wlr_output);
@ -392,6 +421,122 @@ new_output_notify(struct wl_listener *listener, void *data)
wl_signal_emit(&desktop->events.new_output, output); wl_signal_emit(&desktop->events.new_output, output);
} }
static void
output_manager_configure(
struct kiwmi_server *server,
struct wlr_output_configuration_v1 *configuration,
bool test)
{
struct wlr_output_configuration_head_v1 *head;
struct wlr_output_configuration_head_v1 *bad_head = NULL;
wl_list_for_each (head, &configuration->heads, link) {
struct wlr_output *wlr_output = head->state.output;
wlr_output_enable(wlr_output, head->state.enabled);
if (head->state.enabled) {
if (head->state.mode) {
wlr_output_set_mode(wlr_output, head->state.mode);
} else {
wlr_output_set_custom_mode(
wlr_output,
head->state.custom_mode.width,
head->state.custom_mode.height,
head->state.custom_mode.refresh);
}
wlr_output_set_transform(wlr_output, head->state.transform);
wlr_output_set_scale(wlr_output, head->state.scale);
}
if (!wlr_output_test(wlr_output)) {
bad_head = head;
break;
}
}
wl_list_for_each (head, &configuration->heads, link) {
if (bad_head != NULL || test) {
wlr_output_rollback(head->state.output);
if (head == bad_head) {
break;
} else {
continue;
}
}
struct kiwmi_output *output = head->state.output->data;
bool enable_changed = WLR_OUTPUT_STATE_ENABLED
== (output->wlr_output->pending.committed
& WLR_OUTPUT_STATE_ENABLED);
if (head->state.enabled) {
if (enable_changed) {
wlr_output_layout_add(
server->desktop.output_layout,
output->wlr_output,
head->state.x,
head->state.y);
wl_signal_emit(&output->desktop->events.new_output, output);
} else {
bool resized = output->wlr_output->pending.committed
& (WLR_OUTPUT_STATE_MODE | WLR_OUTPUT_STATE_SCALE
| WLR_OUTPUT_STATE_TRANSFORM);
struct wlr_output_layout_output *layout_output =
wlr_output_layout_get(
server->desktop.output_layout, output->wlr_output);
bool moved = head->state.x != layout_output->x
|| head->state.y != layout_output->y;
if (moved || resized) {
wlr_output_layout_move(
server->desktop.output_layout,
output->wlr_output,
head->state.x,
head->state.y);
wl_signal_emit(&output->events.resize, output);
}
}
} else if (enable_changed) {
wl_signal_emit(&output->events.destroy, output);
wlr_output_layout_remove(
server->desktop.output_layout, output->wlr_output);
}
wlr_output_commit(head->state.output);
}
if (bad_head == NULL) {
wlr_output_configuration_v1_send_succeeded(configuration);
if (!test) {
wlr_output_manager_v1_set_configuration(
server->desktop.output_manager, configuration);
} else {
wlr_output_configuration_v1_destroy(configuration);
}
} else {
wlr_output_configuration_v1_send_failed(configuration);
wlr_output_configuration_v1_destroy(configuration);
}
}
void
output_manager_apply_notify(struct wl_listener *listener, void *data)
{
struct kiwmi_desktop *desktop =
wl_container_of(listener, desktop, output_manager_apply);
struct kiwmi_server *server = wl_container_of(desktop, server, desktop);
struct wlr_output_configuration_v1 *configuration = data;
output_manager_configure(server, configuration, false);
}
void
output_manager_test_notify(struct wl_listener *listener, void *data)
{
struct kiwmi_desktop *desktop =
wl_container_of(listener, desktop, output_manager_test);
struct kiwmi_server *server = wl_container_of(desktop, server, desktop);
struct wlr_output_configuration_v1 *configuration = data;
output_manager_configure(server, configuration, true);
}
void void
output_damage(struct kiwmi_output *output) output_damage(struct kiwmi_output *output)
{ {

View file

@ -55,6 +55,7 @@ l_kiwmi_output_move(lua_State *L)
int ly = lua_tonumber(L, 3); int ly = lua_tonumber(L, 3);
wlr_output_layout_move(output_layout, output->wlr_output, lx, ly); wlr_output_layout_move(output_layout, output->wlr_output, lx, ly);
output_manager_update(output->desktop);
return 0; return 0;
} }