Skip to content

Commit

Permalink
Add wlr_output_manager support
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
Uks2 committed Jul 30, 2022
1 parent cb7c633 commit 8916132
Show file tree
Hide file tree
Showing 4 changed files with 159 additions and 0 deletions.
3 changes: 3 additions & 0 deletions include/desktop/desktop.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ struct kiwmi_desktop {
struct wlr_layer_shell_v1 *layer_shell;
struct wlr_data_device_manager *data_device_manager;
struct wlr_output_layout *output_layout;
struct wlr_output_manager_v1 *output_manager;
struct wl_list outputs; // struct kiwmi_output::link
struct wl_list views; // struct kiwmi_view::link

Expand All @@ -26,6 +27,8 @@ struct kiwmi_desktop {
struct wl_listener xdg_toplevel_new_decoration;
struct wl_listener layer_shell_new_surface;
struct wl_listener new_output;
struct wl_listener output_manager_apply;
struct wl_listener output_manager_test;

struct {
struct wl_signal new_output;
Expand Down
3 changes: 3 additions & 0 deletions include/desktop/output.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@ struct kiwmi_render_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_damage(struct kiwmi_output *output);

Expand Down
9 changes: 9 additions & 0 deletions kiwmi/desktop/desktop.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include <wlr/types/wlr_export_dmabuf_v1.h>
#include <wlr/types/wlr_layer_shell_v1.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_output_v1.h>
#include <wlr/types/wlr_xdg_shell.h>
Expand Down Expand Up @@ -79,6 +80,14 @@ desktop_init(struct kiwmi_desktop *desktop)
wl_signal_init(&desktop->events.view_map);
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;
}

Expand Down
144 changes: 144 additions & 0 deletions kiwmi/desktop/output.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include <wlr/types/wlr_matrix.h>
#include <wlr/types/wlr_output.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_xcursor_manager.h>
#include <wlr/util/log.h>
Expand Down Expand Up @@ -242,6 +243,31 @@ output_frame_notify(struct wl_listener *listener, void *data)
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
output_commit_notify(struct wl_listener *listener, void *data)
{
Expand All @@ -264,6 +290,7 @@ output_destroy_notify(struct wl_listener *listener, void *UNUSED(data))
if (output->desktop->output_layout) {
wlr_output_layout_remove(
output->desktop->output_layout, output->wlr_output);
output_manager_update(output->desktop);
}

wl_signal_emit(&output->events.destroy, output);
Expand Down Expand Up @@ -377,6 +404,7 @@ new_output_notify(struct wl_listener *listener, void *data)
wl_list_insert(&desktop->outputs, &output->link);

wlr_output_layout_add_auto(desktop->output_layout, wlr_output);
output_manager_update(desktop);

wlr_output_create_global(wlr_output);

Expand All @@ -392,6 +420,122 @@ new_output_notify(struct wl_listener *listener, void *data)
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 moved = 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);
moved |= head->state.x != layout_output->x
|| head->state.y != layout_output->y;
if (moved) {
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
output_damage(struct kiwmi_output *output)
{
Expand Down

0 comments on commit 8916132

Please sign in to comment.