From df494a7e517281f21fde265bc31badae3245bb26 Mon Sep 17 00:00:00 2001 From: Dominique Martinet Date: Sun, 1 Jul 2018 22:51:21 +0900 Subject: transaction_apply: use float for quotient Pre-dividing 1000/60 would lose 2/3 due to round-up Found through static analysis --- sway/desktop/transaction.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sway/desktop') diff --git a/sway/desktop/transaction.c b/sway/desktop/transaction.c index d2932c87..cb524999 100644 --- a/sway/desktop/transaction.c +++ b/sway/desktop/transaction.c @@ -186,8 +186,8 @@ static void transaction_apply(struct sway_transaction *transaction) { (now.tv_nsec - commit->tv_nsec) / 1000000.0; float ms_total = ms_arranging + ms_waiting; wlr_log(L_DEBUG, "Transaction %p: %.1fms arranging, %.1fms waiting, " - "%.1fms total (%.1f frames if 60Hz)", transaction, - ms_arranging, ms_waiting, ms_total, ms_total / (1000 / 60)); + "%.1fms total (%.1f frames if 60Hz)", transaction, + ms_arranging, ms_waiting, ms_total, ms_total / (1000.0f / 60)); } // Apply the instruction state to the container's current state -- cgit v1.2.3 From e4bfb3bc98b28cb083b4138a76d88384a33d6e57 Mon Sep 17 00:00:00 2001 From: Dominique Martinet Date: Wed, 27 Jun 2018 18:16:49 +0900 Subject: Add idle inhibit unstable v1 support --- sway/desktop/idle_inhibit_v1.c | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 sway/desktop/idle_inhibit_v1.c (limited to 'sway/desktop') diff --git a/sway/desktop/idle_inhibit_v1.c b/sway/desktop/idle_inhibit_v1.c new file mode 100644 index 00000000..a06e00d5 --- /dev/null +++ b/sway/desktop/idle_inhibit_v1.c @@ -0,0 +1,35 @@ +#include +#include +#include "log.h" +#include "sway/desktop/idle_inhibit_v1.h" +#include "sway/server.h" + + +static void handle_destroy(struct wl_listener *listener, void *data) { + struct sway_idle_inhibitor_v1 *inhibitor = + wl_container_of(listener, inhibitor, destroy); + wlr_log(L_DEBUG, "Sway idle inhibitor destroyed"); + wlr_idle_set_enabled(inhibitor->server->idle, NULL, true); + wl_list_remove(&inhibitor->destroy.link); + free(inhibitor); +} + +void handle_idle_inhibitor_v1(struct wl_listener *listener, void *data) { + struct wlr_idle_inhibitor_v1 *wlr_inhibitor = data; + struct sway_server *server = + wl_container_of(listener, server, new_idle_inhibitor_v1); + wlr_log(L_DEBUG, "New sway idle inhibitor"); + + struct sway_idle_inhibitor_v1 *inhibitor = + calloc(1, sizeof(struct sway_idle_inhibitor_v1)); + if (!inhibitor) { + return; + } + + inhibitor->server = server; + + inhibitor->destroy.notify = handle_destroy; + wl_signal_add(&wlr_inhibitor->events.destroy, &inhibitor->destroy); + + wlr_idle_set_enabled(server->idle, NULL, false); +} -- cgit v1.2.3 From 072b334abc6f065080bf944767bbd53d7a590e47 Mon Sep 17 00:00:00 2001 From: Dominique Martinet Date: Sat, 30 Jun 2018 14:09:32 +0900 Subject: idle_inhibit: stop inhibitor when views become invisible --- sway/desktop/idle_inhibit_v1.c | 22 ++++++++++++++++++++++ sway/desktop/transaction.c | 3 +++ 2 files changed, 25 insertions(+) (limited to 'sway/desktop') diff --git a/sway/desktop/idle_inhibit_v1.c b/sway/desktop/idle_inhibit_v1.c index a06e00d5..a9a8cb24 100644 --- a/sway/desktop/idle_inhibit_v1.c +++ b/sway/desktop/idle_inhibit_v1.c @@ -2,6 +2,7 @@ #include #include "log.h" #include "sway/desktop/idle_inhibit_v1.h" +#include "sway/tree/view.h" #include "sway/server.h" @@ -10,6 +11,7 @@ static void handle_destroy(struct wl_listener *listener, void *data) { wl_container_of(listener, inhibitor, destroy); wlr_log(L_DEBUG, "Sway idle inhibitor destroyed"); wlr_idle_set_enabled(inhibitor->server->idle, NULL, true); + wl_list_remove(&inhibitor->link); wl_list_remove(&inhibitor->destroy.link); free(inhibitor); } @@ -27,9 +29,29 @@ void handle_idle_inhibitor_v1(struct wl_listener *listener, void *data) { } inhibitor->server = server; + inhibitor->view = view_from_wlr_surface(wlr_inhibitor->surface); + wl_list_insert(&server->idle_inhibitors_v1, &inhibitor->link); + inhibitor->destroy.notify = handle_destroy; wl_signal_add(&wlr_inhibitor->events.destroy, &inhibitor->destroy); wlr_idle_set_enabled(server->idle, NULL, false); } + +void idle_inhibit_v1_check_active(struct sway_server *server) { + struct sway_idle_inhibitor_v1 *inhibitor; + bool inhibited = false; + wl_list_for_each(inhibitor, &server->idle_inhibitors_v1, link) { + if (!inhibitor->view) { + /* Cannot guess if view is visible so assume it is */ + inhibited = true; + break; + } + if (view_is_visible(inhibitor->view)) { + inhibited = true; + break; + } + } + wlr_idle_set_enabled(server->idle, NULL, !inhibited); +} diff --git a/sway/desktop/transaction.c b/sway/desktop/transaction.c index d2932c87..7050d70c 100644 --- a/sway/desktop/transaction.c +++ b/sway/desktop/transaction.c @@ -6,6 +6,7 @@ #include #include #include "sway/debug.h" +#include "sway/desktop/idle_inhibit_v1.h" #include "sway/desktop/transaction.h" #include "sway/output.h" #include "sway/tree/container.h" @@ -245,6 +246,7 @@ static void transaction_progress_queue() { transaction_destroy(transaction); } server.transactions->length = 0; + idle_inhibit_v1_check_active(&server); } static int handle_timeout(void *data) { @@ -320,6 +322,7 @@ void transaction_commit(struct sway_transaction *transaction) { wlr_log(L_DEBUG, "Transaction %p has nothing to wait for", transaction); transaction_apply(transaction); transaction_destroy(transaction); + idle_inhibit_v1_check_active(&server); return; } -- cgit v1.2.3 From 71224781c48f98f43f5836de663ef6e01604419c Mon Sep 17 00:00:00 2001 From: Dominique Martinet Date: Mon, 2 Jul 2018 09:26:57 +0900 Subject: idle_inhibit: move server data to its own struct --- sway/desktop/idle_inhibit_v1.c | 40 +++++++++++++++++++++++++++++++--------- sway/desktop/transaction.c | 4 ++-- 2 files changed, 33 insertions(+), 11 deletions(-) (limited to 'sway/desktop') diff --git a/sway/desktop/idle_inhibit_v1.c b/sway/desktop/idle_inhibit_v1.c index a9a8cb24..c02ca26e 100644 --- a/sway/desktop/idle_inhibit_v1.c +++ b/sway/desktop/idle_inhibit_v1.c @@ -10,16 +10,16 @@ static void handle_destroy(struct wl_listener *listener, void *data) { struct sway_idle_inhibitor_v1 *inhibitor = wl_container_of(listener, inhibitor, destroy); wlr_log(L_DEBUG, "Sway idle inhibitor destroyed"); - wlr_idle_set_enabled(inhibitor->server->idle, NULL, true); wl_list_remove(&inhibitor->link); wl_list_remove(&inhibitor->destroy.link); + idle_inhibit_v1_check_active(inhibitor->manager); free(inhibitor); } void handle_idle_inhibitor_v1(struct wl_listener *listener, void *data) { struct wlr_idle_inhibitor_v1 *wlr_inhibitor = data; - struct sway_server *server = - wl_container_of(listener, server, new_idle_inhibitor_v1); + struct sway_idle_inhibit_manager_v1 *manager = + wl_container_of(listener, manager, new_idle_inhibitor_v1); wlr_log(L_DEBUG, "New sway idle inhibitor"); struct sway_idle_inhibitor_v1 *inhibitor = @@ -28,21 +28,22 @@ void handle_idle_inhibitor_v1(struct wl_listener *listener, void *data) { return; } - inhibitor->server = server; + inhibitor->manager = manager; inhibitor->view = view_from_wlr_surface(wlr_inhibitor->surface); - wl_list_insert(&server->idle_inhibitors_v1, &inhibitor->link); + wl_list_insert(&manager->inhibitors, &inhibitor->link); inhibitor->destroy.notify = handle_destroy; wl_signal_add(&wlr_inhibitor->events.destroy, &inhibitor->destroy); - wlr_idle_set_enabled(server->idle, NULL, false); + idle_inhibit_v1_check_active(manager); } -void idle_inhibit_v1_check_active(struct sway_server *server) { +void idle_inhibit_v1_check_active( + struct sway_idle_inhibit_manager_v1 *manager) { struct sway_idle_inhibitor_v1 *inhibitor; bool inhibited = false; - wl_list_for_each(inhibitor, &server->idle_inhibitors_v1, link) { + wl_list_for_each(inhibitor, &manager->inhibitors, link) { if (!inhibitor->view) { /* Cannot guess if view is visible so assume it is */ inhibited = true; @@ -53,5 +54,26 @@ void idle_inhibit_v1_check_active(struct sway_server *server) { break; } } - wlr_idle_set_enabled(server->idle, NULL, !inhibited); + wlr_idle_set_enabled(manager->idle, NULL, !inhibited); +} + +struct sway_idle_inhibit_manager_v1 *sway_idle_inhibit_manager_v1_create( + struct wl_display *wl_display, struct wlr_idle *idle) { + struct sway_idle_inhibit_manager_v1 *manager = + calloc(1, sizeof(struct sway_idle_inhibit_manager_v1)); + if (!manager) { + return NULL; + } + + manager->wlr_manager = wlr_idle_inhibit_v1_create(wl_display); + if (!manager->wlr_manager) { + return NULL; + } + manager->idle = idle; + wl_signal_add(&manager->wlr_manager->events.new_inhibitor, + &manager->new_idle_inhibitor_v1); + manager->new_idle_inhibitor_v1.notify = handle_idle_inhibitor_v1; + wl_list_init(&manager->inhibitors); + + return manager; } diff --git a/sway/desktop/transaction.c b/sway/desktop/transaction.c index 7050d70c..e5ceae61 100644 --- a/sway/desktop/transaction.c +++ b/sway/desktop/transaction.c @@ -246,7 +246,7 @@ static void transaction_progress_queue() { transaction_destroy(transaction); } server.transactions->length = 0; - idle_inhibit_v1_check_active(&server); + idle_inhibit_v1_check_active(server.idle_inhibit_manager_v1); } static int handle_timeout(void *data) { @@ -322,7 +322,7 @@ void transaction_commit(struct sway_transaction *transaction) { wlr_log(L_DEBUG, "Transaction %p has nothing to wait for", transaction); transaction_apply(transaction); transaction_destroy(transaction); - idle_inhibit_v1_check_active(&server); + idle_inhibit_v1_check_active(server.idle_inhibit_manager_v1); return; } -- cgit v1.2.3 From d467452e5e06bb4f9aaf98ba92f9696770b188ed Mon Sep 17 00:00:00 2001 From: Ryan Dwyer Date: Mon, 2 Jul 2018 21:58:21 +1000 Subject: Fix damage on swaybar when view requests to exit fullscreen Fixes #2191 --- sway/desktop/xdg_shell.c | 4 ++-- sway/desktop/xdg_shell_v6.c | 4 ++-- sway/desktop/xwayland.c | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) (limited to 'sway/desktop') diff --git a/sway/desktop/xdg_shell.c b/sway/desktop/xdg_shell.c index 82db4076..2b634749 100644 --- a/sway/desktop/xdg_shell.c +++ b/sway/desktop/xdg_shell.c @@ -222,8 +222,8 @@ static void handle_request_fullscreen(struct wl_listener *listener, void *data) view_set_fullscreen(view, e->fullscreen); - struct sway_container *ws = container_parent(view->swayc, C_WORKSPACE); - arrange_and_commit(ws); + struct sway_container *output = container_parent(view->swayc, C_OUTPUT); + arrange_and_commit(output); } static void handle_unmap(struct wl_listener *listener, void *data) { diff --git a/sway/desktop/xdg_shell_v6.c b/sway/desktop/xdg_shell_v6.c index 0d3c1644..2f0730e4 100644 --- a/sway/desktop/xdg_shell_v6.c +++ b/sway/desktop/xdg_shell_v6.c @@ -217,8 +217,8 @@ static void handle_request_fullscreen(struct wl_listener *listener, void *data) view_set_fullscreen(view, e->fullscreen); - struct sway_container *ws = container_parent(view->swayc, C_WORKSPACE); - arrange_and_commit(ws); + struct sway_container *output = container_parent(view->swayc, C_OUTPUT); + arrange_and_commit(output); } static void handle_unmap(struct wl_listener *listener, void *data) { diff --git a/sway/desktop/xwayland.c b/sway/desktop/xwayland.c index 4bb35f60..71803262 100644 --- a/sway/desktop/xwayland.c +++ b/sway/desktop/xwayland.c @@ -379,8 +379,8 @@ static void handle_request_fullscreen(struct wl_listener *listener, void *data) } view_set_fullscreen(view, xsurface->fullscreen); - struct sway_container *ws = container_parent(view->swayc, C_WORKSPACE); - arrange_and_commit(ws); + struct sway_container *output = container_parent(view->swayc, C_OUTPUT); + arrange_and_commit(output); } static void handle_set_title(struct wl_listener *listener, void *data) { -- cgit v1.2.3 From 50b401677be27103e7c4a67ca455d286f562ff7c Mon Sep 17 00:00:00 2001 From: Ryan Dwyer Date: Wed, 4 Jul 2018 22:58:17 +1000 Subject: Fix use after free in transaction code If we set an instruction as ready twice, it decreases the transaction's num_waiting a second time and applies the transaction earlier than it should. This no doubt has undesired effects, probably resulting in a use after free. Hopefully fixes the first part of #2207. --- sway/desktop/transaction.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'sway/desktop') diff --git a/sway/desktop/transaction.c b/sway/desktop/transaction.c index 7b670aec..b4d796cb 100644 --- a/sway/desktop/transaction.c +++ b/sway/desktop/transaction.c @@ -377,7 +377,9 @@ static void set_instructions_ready(struct sway_view *view, int index) { for (int i = 0; i <= index; ++i) { struct sway_transaction_instruction *instruction = view->swayc->instructions->items[i]; - set_instruction_ready(instruction); + if (!instruction->ready) { + set_instruction_ready(instruction); + } } } -- cgit v1.2.3 From d43500831a78580f59525144a0c9b034d4d399d0 Mon Sep 17 00:00:00 2001 From: Drew DeVault Date: Sun, 1 Jul 2018 09:46:02 -0400 Subject: Updates per wlroots#1076 --- sway/desktop/output.c | 18 +++++++++--------- sway/desktop/transaction.c | 4 ++-- sway/desktop/xdg_shell.c | 4 ++-- sway/desktop/xdg_shell_v6.c | 4 ++-- sway/desktop/xwayland.c | 2 +- 5 files changed, 16 insertions(+), 16 deletions(-) (limited to 'sway/desktop') diff --git a/sway/desktop/output.c b/sway/desktop/output.c index 1e7494b3..a86c1646 100644 --- a/sway/desktop/output.c +++ b/sway/desktop/output.c @@ -81,8 +81,8 @@ static bool get_surface_box(struct root_geometry *geo, return false; } - int sw = surface->current->width; - int sh = surface->current->height; + int sw = surface->current.width; + int sh = surface->current.height; double _sx = sx, _sy = sy; rotate_child_position(&_sx, &_sy, sw, sh, geo->width, geo->height, @@ -115,8 +115,8 @@ static void surface_for_each_surface(struct wlr_surface *surface, wlr_surface_iterator_func_t iterator, void *user_data) { geo->x = ox; geo->y = oy; - geo->width = surface->current->width; - geo->height = surface->current->height; + geo->width = surface->current.width; + geo->height = surface->current.height; geo->rotation = 0; wlr_surface_for_each_surface(surface, iterator, user_data); @@ -258,7 +258,7 @@ static void render_surface_iterator(struct wlr_surface *surface, int sx, int sy, float matrix[9]; enum wl_output_transform transform = - wlr_output_transform_invert(surface->current->transform); + wlr_output_transform_invert(surface->current.transform); wlr_matrix_project_box(matrix, &box, transform, rotation, wlr_output->transform_matrix); @@ -1163,16 +1163,16 @@ static void damage_surface_iterator(struct wlr_surface *surface, int sx, int sy, int center_x = box.x + box.width/2; int center_y = box.y + box.height/2; - if (pixman_region32_not_empty(&surface->current->surface_damage)) { + if (pixman_region32_not_empty(&surface->current.surface_damage)) { pixman_region32_t damage; pixman_region32_init(&damage); - pixman_region32_copy(&damage, &surface->current->surface_damage); + pixman_region32_copy(&damage, &surface->current.surface_damage); wlr_region_scale(&damage, &damage, output->wlr_output->scale); - if (ceil(output->wlr_output->scale) > surface->current->scale) { + if (ceil(output->wlr_output->scale) > surface->current.scale) { // When scaling up a surface, it'll become blurry so we need to // expand the damage region wlr_region_expand(&damage, &damage, - ceil(output->wlr_output->scale) - surface->current->scale); + ceil(output->wlr_output->scale) - surface->current.scale); } pixman_region32_translate(&damage, box.x, box.y); wlr_region_rotated_bounds(&damage, &damage, rotation, diff --git a/sway/desktop/transaction.c b/sway/desktop/transaction.c index b4d796cb..179af617 100644 --- a/sway/desktop/transaction.c +++ b/sway/desktop/transaction.c @@ -73,8 +73,8 @@ static void save_view_buffer(struct sway_view *view, } if (view->surface && wlr_surface_has_buffer(view->surface)) { instruction->saved_buffer = wlr_buffer_ref(view->surface->buffer); - instruction->saved_buffer_width = view->surface->current->width; - instruction->saved_buffer_height = view->surface->current->height; + instruction->saved_buffer_width = view->surface->current.width; + instruction->saved_buffer_height = view->surface->current.height; } } diff --git a/sway/desktop/xdg_shell.c b/sway/desktop/xdg_shell.c index 2b634749..ac35a8d1 100644 --- a/sway/desktop/xdg_shell.c +++ b/sway/desktop/xdg_shell.c @@ -251,8 +251,8 @@ static void handle_map(struct wl_listener *listener, void *data) { view->natural_width = view->wlr_xdg_surface->geometry.width; view->natural_height = view->wlr_xdg_surface->geometry.height; if (!view->natural_width && !view->natural_height) { - view->natural_width = view->wlr_xdg_surface->surface->current->width; - view->natural_height = view->wlr_xdg_surface->surface->current->height; + view->natural_width = view->wlr_xdg_surface->surface->current.width; + view->natural_height = view->wlr_xdg_surface->surface->current.height; } view_map(view, view->wlr_xdg_surface->surface); diff --git a/sway/desktop/xdg_shell_v6.c b/sway/desktop/xdg_shell_v6.c index 2f0730e4..56bbb244 100644 --- a/sway/desktop/xdg_shell_v6.c +++ b/sway/desktop/xdg_shell_v6.c @@ -246,8 +246,8 @@ static void handle_map(struct wl_listener *listener, void *data) { view->natural_width = view->wlr_xdg_surface_v6->geometry.width; view->natural_height = view->wlr_xdg_surface_v6->geometry.height; if (!view->natural_width && !view->natural_height) { - view->natural_width = view->wlr_xdg_surface_v6->surface->current->width; - view->natural_height = view->wlr_xdg_surface_v6->surface->current->height; + view->natural_width = view->wlr_xdg_surface_v6->surface->current.width; + view->natural_height = view->wlr_xdg_surface_v6->surface->current.height; } view_map(view, view->wlr_xdg_surface_v6->surface); diff --git a/sway/desktop/xwayland.c b/sway/desktop/xwayland.c index 71803262..0669a485 100644 --- a/sway/desktop/xwayland.c +++ b/sway/desktop/xwayland.c @@ -278,7 +278,7 @@ static void handle_commit(struct wl_listener *listener, void *data) { wl_container_of(listener, xwayland_view, commit); struct sway_view *view = &xwayland_view->view; struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface; - struct wlr_surface_state *surface_state = xsurface->surface->current; + struct wlr_surface_state *surface_state = &xsurface->surface->current; if (view->swayc->instructions->length) { transaction_notify_view_ready_by_size(view, -- cgit v1.2.3 From 51b215ad5c0cadc4f1c10f407d1a2c375b46a769 Mon Sep 17 00:00:00 2001 From: emersion Date: Sun, 1 Jul 2018 14:55:14 +0100 Subject: Use wlr_surface.buffer_damage --- sway/desktop/output.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) (limited to 'sway/desktop') diff --git a/sway/desktop/output.c b/sway/desktop/output.c index a86c1646..1211cc07 100644 --- a/sway/desktop/output.c +++ b/sway/desktop/output.c @@ -1163,11 +1163,17 @@ static void damage_surface_iterator(struct wlr_surface *surface, int sx, int sy, int center_x = box.x + box.width/2; int center_y = box.y + box.height/2; - if (pixman_region32_not_empty(&surface->current.surface_damage)) { + if (pixman_region32_not_empty(&surface->buffer_damage)) { + enum wl_output_transform transform = + wlr_output_transform_invert(surface->current.transform); + pixman_region32_t damage; pixman_region32_init(&damage); - pixman_region32_copy(&damage, &surface->current.surface_damage); - wlr_region_scale(&damage, &damage, output->wlr_output->scale); + pixman_region32_copy(&damage, &surface->buffer_damage); + wlr_region_transform(&damage, &damage, transform, + surface->current.buffer_width, surface->current.buffer_height); + wlr_region_scale(&damage, &damage, + output->wlr_output->scale / (float)surface->current.scale); if (ceil(output->wlr_output->scale) > surface->current.scale) { // When scaling up a surface, it'll become blurry so we need to // expand the damage region -- cgit v1.2.3 From 58befcf2cdf261b8898b6fd1288a69d367101ff1 Mon Sep 17 00:00:00 2001 From: Ryan Dwyer Date: Sun, 1 Jul 2018 10:58:13 +1000 Subject: Don't send frame done to surfaces behind lockscreen Also, when rendering, don't descend into the tree if the lockscreen is active. Just render the lockscreen's surfaces. --- sway/desktop/output.c | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) (limited to 'sway/desktop') diff --git a/sway/desktop/output.c b/sway/desktop/output.c index 1211cc07..52bd1666 100644 --- a/sway/desktop/output.c +++ b/sway/desktop/output.c @@ -948,8 +948,30 @@ static void render_output(struct sway_output *output, struct timespec *when, struct sway_container *workspace = output_get_active_workspace(output); struct sway_view *fullscreen_view = workspace->current.ws_fullscreen; + struct sway_seat *seat = input_manager_current_seat(input_manager); + + if (seat->exclusive_client && seat->focused_layer) { + float clear_color[] = {0.0f, 0.0f, 0.0f, 1.0f}; + + int nrects; + pixman_box32_t *rects = pixman_region32_rectangles(damage, &nrects); + for (int i = 0; i < nrects; ++i) { + scissor_output(wlr_output, &rects[i]); + wlr_renderer_clear(renderer, clear_color); + } - if (fullscreen_view) { + struct wlr_layer_surface *wlr_layer_surface = seat->focused_layer; + struct sway_layer_surface *sway_layer_surface = + layer_from_wlr_layer_surface(seat->focused_layer); + struct render_data data = { + .output = output, + .damage = damage, + .alpha = 1.0f, + }; + surface_for_each_surface(wlr_layer_surface->surface, + sway_layer_surface->geo.x, sway_layer_surface->geo.y, + &data.root_geo, render_surface_iterator, &data); + } else if (fullscreen_view) { float clear_color[] = {0.0f, 0.0f, 0.0f, 1.0f}; int nrects; @@ -1019,11 +1041,16 @@ struct send_frame_done_data { struct root_geometry root_geo; struct sway_output *output; struct timespec *when; + struct wl_client *exclusive_client; }; static void send_frame_done_iterator(struct wlr_surface *surface, int sx, int sy, void *_data) { struct send_frame_done_data *data = _data; + if (data->exclusive_client && + data->exclusive_client != surface->resource->client) { + return; + } bool intersects = get_surface_box(&data->root_geo, data->output, surface, sx, sy, NULL); @@ -1072,9 +1099,11 @@ static void send_frame_done_container(struct send_frame_done_data *data, } static void send_frame_done(struct sway_output *output, struct timespec *when) { + struct sway_seat *seat = input_manager_current_seat(input_manager); struct send_frame_done_data data = { .output = output, .when = when, + .exclusive_client = seat->exclusive_client, }; struct sway_container *workspace = output_get_active_workspace(output); -- cgit v1.2.3 From 839c3a550043fd38096a15ff8dcd7de1a084efdc Mon Sep 17 00:00:00 2001 From: Ryan Dwyer Date: Tue, 3 Jul 2018 17:29:23 +1000 Subject: Use opaque region to determine if frame done should be sent --- sway/desktop/output.c | 35 +++++++++++++++++++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) (limited to 'sway/desktop') diff --git a/sway/desktop/output.c b/sway/desktop/output.c index 52bd1666..a6b2ebc2 100644 --- a/sway/desktop/output.c +++ b/sway/desktop/output.c @@ -915,6 +915,36 @@ static struct sway_container *output_get_active_workspace( return workspace; } +bool output_has_opaque_lockscreen(struct sway_output *output, + struct sway_seat *seat) { + if (!seat->exclusive_client) { + return false; + } + + struct wlr_layer_surface *wlr_layer_surface; + wl_list_for_each(wlr_layer_surface, &server.layer_shell->surfaces, link) { + if (wlr_layer_surface->output != output->wlr_output) { + continue; + } + struct wlr_surface *wlr_surface = wlr_layer_surface->surface; + if (wlr_surface->resource->client != seat->exclusive_client) { + continue; + } + int nrects; + pixman_box32_t *rects = + pixman_region32_rectangles(&wlr_surface->current->opaque, &nrects); + for (int i = 0; i < nrects; ++i) { + pixman_box32_t *rect = &rects[i]; + if (rect->x1 <= 0 && rect->y1 <= 0 && + rect->x2 >= output->swayc->current.swayc_width && + rect->y2 >= output->swayc->current.swayc_height) { + return true; + } + } + } + return false; +} + static void render_output(struct sway_output *output, struct timespec *when, pixman_region32_t *damage) { struct wlr_output *wlr_output = output->wlr_output; @@ -950,7 +980,7 @@ static void render_output(struct sway_output *output, struct timespec *when, struct sway_view *fullscreen_view = workspace->current.ws_fullscreen; struct sway_seat *seat = input_manager_current_seat(input_manager); - if (seat->exclusive_client && seat->focused_layer) { + if (output_has_opaque_lockscreen(output, seat)) { float clear_color[] = {0.0f, 0.0f, 0.0f, 1.0f}; int nrects; @@ -1103,7 +1133,8 @@ static void send_frame_done(struct sway_output *output, struct timespec *when) { struct send_frame_done_data data = { .output = output, .when = when, - .exclusive_client = seat->exclusive_client, + .exclusive_client = output_has_opaque_lockscreen(output, seat) ? + seat->exclusive_client : NULL, }; struct sway_container *workspace = output_get_active_workspace(output); -- cgit v1.2.3 From f1fadef923ef8b1278bf2e380ab639f32c0cf79b Mon Sep 17 00:00:00 2001 From: Ryan Dwyer Date: Tue, 3 Jul 2018 18:14:46 +1000 Subject: Use pixman_region32_contains_rectangle --- sway/desktop/output.c | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) (limited to 'sway/desktop') diff --git a/sway/desktop/output.c b/sway/desktop/output.c index a6b2ebc2..fa85d260 100644 --- a/sway/desktop/output.c +++ b/sway/desktop/output.c @@ -930,16 +930,13 @@ bool output_has_opaque_lockscreen(struct sway_output *output, if (wlr_surface->resource->client != seat->exclusive_client) { continue; } - int nrects; - pixman_box32_t *rects = - pixman_region32_rectangles(&wlr_surface->current->opaque, &nrects); - for (int i = 0; i < nrects; ++i) { - pixman_box32_t *rect = &rects[i]; - if (rect->x1 <= 0 && rect->y1 <= 0 && - rect->x2 >= output->swayc->current.swayc_width && - rect->y2 >= output->swayc->current.swayc_height) { - return true; - } + pixman_box32_t output_box = { + .x2 = output->swayc->current.swayc_width, + .y2 = output->swayc->current.swayc_height, + }; + if (pixman_region32_contains_rectangle(&wlr_surface->current->opaque, + &output_box)) { + return true; } } return false; -- cgit v1.2.3 From 3b842f4eed7276f44b0a9154976ecfeef07aa867 Mon Sep 17 00:00:00 2001 From: Ryan Dwyer Date: Sat, 7 Jul 2018 00:17:08 +1000 Subject: Detect opaque lockscreen when using a solid color --- sway/desktop/output.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sway/desktop') diff --git a/sway/desktop/output.c b/sway/desktop/output.c index fa85d260..329632b6 100644 --- a/sway/desktop/output.c +++ b/sway/desktop/output.c @@ -934,7 +934,7 @@ bool output_has_opaque_lockscreen(struct sway_output *output, .x2 = output->swayc->current.swayc_width, .y2 = output->swayc->current.swayc_height, }; - if (pixman_region32_contains_rectangle(&wlr_surface->current->opaque, + if (pixman_region32_contains_rectangle(&wlr_surface->current.opaque, &output_box)) { return true; } -- cgit v1.2.3 From 948078122932a9782bbf1042356b62099b0cd25f Mon Sep 17 00:00:00 2001 From: Ryan Dwyer Date: Sat, 7 Jul 2018 00:21:39 +1000 Subject: Don't clear when using opaque lockscreen --- sway/desktop/output.c | 9 --------- 1 file changed, 9 deletions(-) (limited to 'sway/desktop') diff --git a/sway/desktop/output.c b/sway/desktop/output.c index 329632b6..3c34040b 100644 --- a/sway/desktop/output.c +++ b/sway/desktop/output.c @@ -978,15 +978,6 @@ static void render_output(struct sway_output *output, struct timespec *when, struct sway_seat *seat = input_manager_current_seat(input_manager); if (output_has_opaque_lockscreen(output, seat)) { - float clear_color[] = {0.0f, 0.0f, 0.0f, 1.0f}; - - int nrects; - pixman_box32_t *rects = pixman_region32_rectangles(damage, &nrects); - for (int i = 0; i < nrects; ++i) { - scissor_output(wlr_output, &rects[i]); - wlr_renderer_clear(renderer, clear_color); - } - struct wlr_layer_surface *wlr_layer_surface = seat->focused_layer; struct sway_layer_surface *sway_layer_surface = layer_from_wlr_layer_surface(seat->focused_layer); -- cgit v1.2.3 From 464d4d58892597f31da3fcdbcfcd7928643a9ec3 Mon Sep 17 00:00:00 2001 From: Ryan Dwyer Date: Sat, 7 Jul 2018 01:18:54 +1000 Subject: Translate surface by its geo when doing opaque box check --- sway/desktop/output.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) (limited to 'sway/desktop') diff --git a/sway/desktop/output.c b/sway/desktop/output.c index 3c34040b..e5a42db0 100644 --- a/sway/desktop/output.c +++ b/sway/desktop/output.c @@ -930,12 +930,21 @@ bool output_has_opaque_lockscreen(struct sway_output *output, if (wlr_surface->resource->client != seat->exclusive_client) { continue; } + struct sway_layer_surface *sway_layer_surface = + layer_from_wlr_layer_surface(wlr_layer_surface); pixman_box32_t output_box = { .x2 = output->swayc->current.swayc_width, .y2 = output->swayc->current.swayc_height, }; - if (pixman_region32_contains_rectangle(&wlr_surface->current.opaque, - &output_box)) { + pixman_region32_t surface_opaque_box; + pixman_region32_init(&surface_opaque_box); + pixman_region32_copy(&surface_opaque_box, &wlr_surface->current.opaque); + pixman_region32_translate(&surface_opaque_box, + sway_layer_surface->geo.x, sway_layer_surface->geo.y); + bool contains = pixman_region32_contains_rectangle( + &wlr_surface->current.opaque, &output_box); + pixman_region32_fini(&surface_opaque_box); + if (contains) { return true; } } -- cgit v1.2.3 From 47d56306c3c0578daf705e1421b79791be85428e Mon Sep 17 00:00:00 2001 From: emersion Date: Mon, 2 Jul 2018 20:24:17 +0100 Subject: Fix xwayland floating views unclickable Some xwayland views are first configured with a 1x1 size, and then resized. Since the view size isn't updated, they are unclickable. Fixes #2195 --- sway/desktop/xwayland.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'sway/desktop') diff --git a/sway/desktop/xwayland.c b/sway/desktop/xwayland.c index 0669a485..ace290ef 100644 --- a/sway/desktop/xwayland.c +++ b/sway/desktop/xwayland.c @@ -284,6 +284,11 @@ static void handle_commit(struct wl_listener *listener, void *data) { transaction_notify_view_ready_by_size(view, surface_state->width, surface_state->height); } + + if (container_is_floating(view->swayc)) { + view_update_size(view, surface_state->width, surface_state->height); + } + view_damage_from(view); } -- cgit v1.2.3 From 9a9d9116be4109f733a3309d7f9a7c9edd8db4ae Mon Sep 17 00:00:00 2001 From: emersion Date: Fri, 6 Jul 2018 19:33:10 +0100 Subject: Make view_update_* update live props as well --- sway/desktop/xwayland.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'sway/desktop') diff --git a/sway/desktop/xwayland.c b/sway/desktop/xwayland.c index ace290ef..b2874cfe 100644 --- a/sway/desktop/xwayland.c +++ b/sway/desktop/xwayland.c @@ -283,9 +283,7 @@ static void handle_commit(struct wl_listener *listener, void *data) { if (view->swayc->instructions->length) { transaction_notify_view_ready_by_size(view, surface_state->width, surface_state->height); - } - - if (container_is_floating(view->swayc)) { + } else if (container_is_floating(view->swayc)) { view_update_size(view, surface_state->width, surface_state->height); } -- cgit v1.2.3 From 0046eed96903c745142208c40aa5f10d0b5931cb Mon Sep 17 00:00:00 2001 From: Ryan Dwyer Date: Sat, 7 Jul 2018 15:49:51 +1000 Subject: Fix titles when container titles contain UTF-8 characters The title and marks textures would have their height set from the config's computed max font height, but the textures were not regenerated when the config's max font height changed which made a gap appear. Rather than making it regenerate the title textures every time the config font height was changed, I've changed it to just make the textures the height of the title itself and fill any gap when rendering. Also, the title_width and marks_width variables have been renamed to make it more obvious that they are in output-buffer-local coordinates. Fixes #1936. --- sway/desktop/output.c | 40 ++++++++++++++++++++++++++++++++-------- 1 file changed, 32 insertions(+), 8 deletions(-) (limited to 'sway/desktop') diff --git a/sway/desktop/output.c b/sway/desktop/output.c index e5a42db0..336163ea 100644 --- a/sway/desktop/output.c +++ b/sway/desktop/output.c @@ -521,7 +521,7 @@ static void render_titlebar(struct sway_output *output, size_t inner_width = width - TITLEBAR_H_PADDING * 2; // Marks - size_t marks_width = 0; + size_t marks_ob_width = 0; // output-buffer-local if (config->show_marks && marks_texture) { struct wlr_box texture_box; wlr_texture_get_size(marks_texture, @@ -540,11 +540,23 @@ static void render_titlebar(struct sway_output *output, } render_texture(output->wlr_output, output_damage, marks_texture, &texture_box, matrix, con->alpha); - marks_width = texture_box.width; + marks_ob_width = texture_box.width; + + // Gap between the marks and bottom padding, for when the marks texture + // height is smaller than the config's font height + memcpy(&color, colors->background, sizeof(float) * 4); + premultiply_alpha(color, con->alpha); + box.x = texture_box.x; + box.y = texture_box.y + texture_box.height; + box.width = texture_box.width; + box.height = config->font_height * output_scale - texture_box.height; + if (box.height > 0) { + render_rect(output->wlr_output, output_damage, &box, color); + } } // Title text - size_t title_width = 0; + size_t title_ob_width = 0; // output-buffer-local if (title_texture) { struct wlr_box texture_box; wlr_texture_get_size(title_texture, @@ -557,12 +569,24 @@ static void render_titlebar(struct sway_output *output, WL_OUTPUT_TRANSFORM_NORMAL, 0.0, output->wlr_output->transform_matrix); - if (inner_width * output_scale - marks_width < texture_box.width) { - texture_box.width = inner_width * output_scale - marks_width; + if (inner_width * output_scale - marks_ob_width < texture_box.width) { + texture_box.width = inner_width * output_scale - marks_ob_width; } render_texture(output->wlr_output, output_damage, title_texture, &texture_box, matrix, con->alpha); - title_width = texture_box.width; + title_ob_width = texture_box.width; + + // Gap between the title and bottom padding, for when the title texture + // height is smaller than the config's font height + memcpy(&color, colors->background, sizeof(float) * 4); + premultiply_alpha(color, con->alpha); + box.x = texture_box.x; + box.y = texture_box.y + texture_box.height; + box.width = texture_box.width; + box.height = config->font_height * output_scale - texture_box.height; + if (box.height > 0) { + render_rect(output->wlr_output, output_damage, &box, color); + } } // Padding above title @@ -580,9 +604,9 @@ static void render_titlebar(struct sway_output *output, render_rect(output->wlr_output, output_damage, &box, color); // Filler between title and marks - box.width = inner_width * output_scale - title_width - marks_width; + box.width = inner_width * output_scale - title_ob_width - marks_ob_width; if (box.width > 0) { - box.x = (x + TITLEBAR_H_PADDING) * output_scale + title_width; + box.x = (x + TITLEBAR_H_PADDING) * output_scale + title_ob_width; box.y = (y + TITLEBAR_V_PADDING) * output_scale; box.height = config->font_height * output_scale; render_rect(output->wlr_output, output_damage, &box, color); -- cgit v1.2.3 From f9625d1d56482a2c8fce4a2d4743d36607fc639d Mon Sep 17 00:00:00 2001 From: emersion Date: Sat, 7 Jul 2018 10:30:52 +0100 Subject: Split renderer --- sway/desktop/output.c | 917 ++------------------------------------------------ sway/desktop/render.c | 893 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 916 insertions(+), 894 deletions(-) create mode 100644 sway/desktop/render.c (limited to 'sway/desktop') diff --git a/sway/desktop/output.c b/sway/desktop/output.c index 336163ea..8b50bc44 100644 --- a/sway/desktop/output.c +++ b/sway/desktop/output.c @@ -56,25 +56,7 @@ static void rotate_child_position(double *sx, double *sy, double sw, double sh, *sy = ry + ph/2 - sh/2; } -/** - * Contains a surface's root geometry information. For instance, when rendering - * a popup, this will contain the parent view's position and size. - */ -struct root_geometry { - double x, y; - int width, height; - float rotation; -}; - -struct render_data { - struct root_geometry root_geo; - struct sway_output *output; - pixman_region32_t *damage; - struct sway_view *view; - float alpha; -}; - -static bool get_surface_box(struct root_geometry *geo, +bool output_get_surface_box(struct root_geometry *geo, struct sway_output *output, struct wlr_surface *surface, int sx, int sy, struct wlr_box *surface_box) { if (!wlr_surface_has_buffer(surface)) { @@ -110,7 +92,7 @@ static bool get_surface_box(struct root_geometry *geo, return wlr_box_intersection(&output_box, &rotated_box, &intersection); } -static void surface_for_each_surface(struct wlr_surface *surface, +void output_surface_for_each_surface(struct wlr_surface *surface, double ox, double oy, struct root_geometry *geo, wlr_surface_iterator_func_t iterator, void *user_data) { geo->x = ox; @@ -122,12 +104,11 @@ static void surface_for_each_surface(struct wlr_surface *surface, wlr_surface_for_each_surface(surface, iterator, user_data); } -static void output_view_for_each_surface(struct sway_view *view, - struct root_geometry *geo, wlr_surface_iterator_func_t iterator, - void *user_data) { - struct render_data *data = user_data; - geo->x = view->swayc->current.view_x - data->output->swayc->current.swayc_x; - geo->y = view->swayc->current.view_y - data->output->swayc->current.swayc_y; +void output_view_for_each_surface(struct sway_view *view, + struct sway_output *output, struct root_geometry *geo, + wlr_surface_iterator_func_t iterator, void *user_data) { + geo->x = view->swayc->current.view_x - output->swayc->current.swayc_x; + geo->y = view->swayc->current.view_y - output->swayc->current.swayc_y; geo->width = view->swayc->current.view_width; geo->height = view->swayc->current.view_height; geo->rotation = 0; // TODO @@ -135,20 +116,20 @@ static void output_view_for_each_surface(struct sway_view *view, view_for_each_surface(view, iterator, user_data); } -static void layer_for_each_surface(struct wl_list *layer_surfaces, +void output_layer_for_each_surface(struct wl_list *layer_surfaces, struct root_geometry *geo, wlr_surface_iterator_func_t iterator, void *user_data) { struct sway_layer_surface *layer_surface; wl_list_for_each(layer_surface, layer_surfaces, link) { struct wlr_layer_surface *wlr_layer_surface = layer_surface->layer_surface; - surface_for_each_surface(wlr_layer_surface->surface, + output_surface_for_each_surface(wlr_layer_surface->surface, layer_surface->geo.x, layer_surface->geo.y, geo, iterator, user_data); } } -static void unmanaged_for_each_surface(struct wl_list *unmanaged, +void output_unmanaged_for_each_surface(struct wl_list *unmanaged, struct sway_output *output, struct root_geometry *geo, wlr_surface_iterator_func_t iterator, void *user_data) { struct sway_xwayland_unmanaged *unmanaged_surface; @@ -158,12 +139,12 @@ static void unmanaged_for_each_surface(struct wl_list *unmanaged, double ox = unmanaged_surface->lx - output->swayc->current.swayc_x; double oy = unmanaged_surface->ly - output->swayc->current.swayc_y; - surface_for_each_surface(xsurface->surface, ox, oy, geo, + output_surface_for_each_surface(xsurface->surface, ox, oy, geo, iterator, user_data); } } -static void drag_icons_for_each_surface(struct wl_list *drag_icons, +void output_drag_icons_for_each_surface(struct wl_list *drag_icons, struct sway_output *output, struct root_geometry *geo, wlr_surface_iterator_func_t iterator, void *user_data) { struct sway_drag_icon *drag_icon; @@ -172,7 +153,7 @@ static void drag_icons_for_each_surface(struct wl_list *drag_icons, double oy = drag_icon->y - output->swayc->y; if (drag_icon->wlr_drag_icon->mapped) { - surface_for_each_surface(drag_icon->wlr_drag_icon->surface, + output_surface_for_each_surface(drag_icon->wlr_drag_icon->surface, ox, oy, geo, iterator, user_data); } } @@ -185,746 +166,7 @@ static void scale_box(struct wlr_box *box, float scale) { box->height *= scale; } -static void scissor_output(struct wlr_output *wlr_output, - pixman_box32_t *rect) { - struct wlr_renderer *renderer = wlr_backend_get_renderer(wlr_output->backend); - assert(renderer); - - struct wlr_box box = { - .x = rect->x1, - .y = rect->y1, - .width = rect->x2 - rect->x1, - .height = rect->y2 - rect->y1, - }; - - int ow, oh; - wlr_output_transformed_resolution(wlr_output, &ow, &oh); - - enum wl_output_transform transform = - wlr_output_transform_invert(wlr_output->transform); - wlr_box_transform(&box, transform, ow, oh, &box); - - wlr_renderer_scissor(renderer, &box); -} - -static void render_texture(struct wlr_output *wlr_output, - pixman_region32_t *output_damage, struct wlr_texture *texture, - const struct wlr_box *box, const float matrix[static 9], float alpha) { - struct wlr_renderer *renderer = - wlr_backend_get_renderer(wlr_output->backend); - - pixman_region32_t damage; - pixman_region32_init(&damage); - pixman_region32_union_rect(&damage, &damage, box->x, box->y, - box->width, box->height); - pixman_region32_intersect(&damage, &damage, output_damage); - bool damaged = pixman_region32_not_empty(&damage); - if (!damaged) { - goto damage_finish; - } - - int nrects; - pixman_box32_t *rects = pixman_region32_rectangles(&damage, &nrects); - for (int i = 0; i < nrects; ++i) { - scissor_output(wlr_output, &rects[i]); - wlr_render_texture_with_matrix(renderer, texture, matrix, alpha); - } - -damage_finish: - pixman_region32_fini(&damage); -} - -static void render_surface_iterator(struct wlr_surface *surface, int sx, int sy, - void *_data) { - struct render_data *data = _data; - struct wlr_output *wlr_output = data->output->wlr_output; - float rotation = data->root_geo.rotation; - pixman_region32_t *output_damage = data->damage; - float alpha = data->alpha; - - struct wlr_texture *texture = wlr_surface_get_texture(surface); - if (!texture) { - return; - } - - struct wlr_box box; - bool intersects = get_surface_box(&data->root_geo, data->output, surface, - sx, sy, &box); - if (!intersects) { - return; - } - - scale_box(&box, wlr_output->scale); - - float matrix[9]; - enum wl_output_transform transform = - wlr_output_transform_invert(surface->current.transform); - wlr_matrix_project_box(matrix, &box, transform, rotation, - wlr_output->transform_matrix); - - render_texture(wlr_output, output_damage, texture, &box, matrix, alpha); -} - -static void render_layer(struct sway_output *output, - pixman_region32_t *damage, struct wl_list *layer_surfaces) { - struct render_data data = { - .output = output, - .damage = damage, - .alpha = 1.0f, - }; - layer_for_each_surface(layer_surfaces, &data.root_geo, - render_surface_iterator, &data); -} - -static void render_unmanaged(struct sway_output *output, - pixman_region32_t *damage, struct wl_list *unmanaged) { - struct render_data data = { - .output = output, - .damage = damage, - .alpha = 1.0f, - }; - unmanaged_for_each_surface(unmanaged, output, &data.root_geo, - render_surface_iterator, &data); -} - -static void render_drag_icons(struct sway_output *output, - pixman_region32_t *damage, struct wl_list *drag_icons) { - struct render_data data = { - .output = output, - .damage = damage, - .alpha = 1.0f, - }; - drag_icons_for_each_surface(drag_icons, output, &data.root_geo, - render_surface_iterator, &data); -} - -static void render_rect(struct wlr_output *wlr_output, - pixman_region32_t *output_damage, const struct wlr_box *_box, - float color[static 4]) { - struct wlr_renderer *renderer = - wlr_backend_get_renderer(wlr_output->backend); - - struct wlr_box box; - memcpy(&box, _box, sizeof(struct wlr_box)); - box.x -= wlr_output->lx * wlr_output->scale; - box.y -= wlr_output->ly * wlr_output->scale; - - pixman_region32_t damage; - pixman_region32_init(&damage); - pixman_region32_union_rect(&damage, &damage, box.x, box.y, - box.width, box.height); - pixman_region32_intersect(&damage, &damage, output_damage); - bool damaged = pixman_region32_not_empty(&damage); - if (!damaged) { - goto damage_finish; - } - - int nrects; - pixman_box32_t *rects = pixman_region32_rectangles(&damage, &nrects); - for (int i = 0; i < nrects; ++i) { - scissor_output(wlr_output, &rects[i]); - wlr_render_rect(renderer, &box, color, - wlr_output->transform_matrix); - } - -damage_finish: - pixman_region32_fini(&damage); -} - -static void premultiply_alpha(float color[4], float opacity) { - color[3] *= opacity; - color[0] *= color[3]; - color[1] *= color[3]; - color[2] *= color[3]; -} - -static void render_view_surfaces(struct sway_view *view, - struct sway_output *output, pixman_region32_t *damage, float alpha) { - struct render_data data = { - .output = output, - .damage = damage, - .view = view, - .alpha = alpha, - }; - output_view_for_each_surface( - view, &data.root_geo, render_surface_iterator, &data); -} - -static void render_saved_view(struct sway_view *view, - struct sway_output *output, pixman_region32_t *damage, float alpha) { - struct wlr_output *wlr_output = output->wlr_output; - - int width, height; - struct wlr_texture *texture = - transaction_get_saved_texture(view, &width, &height); - if (!texture) { - return; - } - struct wlr_box box = { - .x = view->swayc->current.view_x - output->swayc->current.swayc_x, - .y = view->swayc->current.view_y - output->swayc->current.swayc_y, - .width = width, - .height = height, - }; - - struct wlr_box output_box = { - .width = output->swayc->current.swayc_width, - .height = output->swayc->current.swayc_height, - }; - - struct wlr_box intersection; - bool intersects = wlr_box_intersection(&output_box, &box, &intersection); - if (!intersects) { - return; - } - - scale_box(&box, wlr_output->scale); - - float matrix[9]; - wlr_matrix_project_box(matrix, &box, WL_OUTPUT_TRANSFORM_NORMAL, 0, - wlr_output->transform_matrix); - - render_texture(wlr_output, damage, texture, &box, matrix, alpha); -} - -/** - * Render a view's surface and left/bottom/right borders. - */ -static void render_view(struct sway_output *output, pixman_region32_t *damage, - struct sway_container *con, struct border_colors *colors) { - struct sway_view *view = con->sway_view; - if (view->swayc->instructions->length) { - render_saved_view(view, output, damage, view->swayc->alpha); - } else { - render_view_surfaces(view, output, damage, view->swayc->alpha); - } - - struct wlr_box box; - float output_scale = output->wlr_output->scale; - float color[4]; - struct sway_container_state *state = &con->current; - - if (state->border != B_NONE) { - if (state->border_left) { - memcpy(&color, colors->child_border, sizeof(float) * 4); - premultiply_alpha(color, con->alpha); - box.x = state->swayc_x; - box.y = state->view_y; - box.width = state->border_thickness; - box.height = state->view_height; - scale_box(&box, output_scale); - render_rect(output->wlr_output, damage, &box, color); - } - - if (state->border_right) { - if (state->parent->current.children->length == 1 - && state->parent->current.layout == L_HORIZ) { - memcpy(&color, colors->indicator, sizeof(float) * 4); - } else { - memcpy(&color, colors->child_border, sizeof(float) * 4); - } - premultiply_alpha(color, con->alpha); - box.x = state->view_x + state->view_width; - box.y = state->view_y; - box.width = state->border_thickness; - box.height = state->view_height; - scale_box(&box, output_scale); - render_rect(output->wlr_output, damage, &box, color); - } - - if (state->border_bottom) { - if (state->parent->current.children->length == 1 - && con->current.parent->current.layout == L_VERT) { - memcpy(&color, colors->indicator, sizeof(float) * 4); - } else { - memcpy(&color, colors->child_border, sizeof(float) * 4); - } - premultiply_alpha(color, con->alpha); - box.x = state->swayc_x; - box.y = state->view_y + state->view_height; - box.width = state->swayc_width; - box.height = state->border_thickness; - scale_box(&box, output_scale); - render_rect(output->wlr_output, damage, &box, color); - } - } -} - -/** - * Render a titlebar. - * - * Care must be taken not to render over the same pixel multiple times, - * otherwise the colors will be incorrect when using opacity. - * - * The height is: 1px border, 3px padding, font height, 3px padding, 1px border - * The left side for L_TABBED is: 1px border, 2px padding, title - * The left side for other layouts is: 3px padding, title - */ -static void render_titlebar(struct sway_output *output, - pixman_region32_t *output_damage, struct sway_container *con, - int x, int y, int width, - struct border_colors *colors, struct wlr_texture *title_texture, - struct wlr_texture *marks_texture) { - struct wlr_box box; - float color[4]; - struct sway_container_state *state = &con->current; - float output_scale = output->wlr_output->scale; - enum sway_container_layout layout = state->parent->current.layout; - list_t *children = state->parent->current.children; - bool is_last_child = children->items[children->length - 1] == con; - double output_x = output->swayc->current.swayc_x; - double output_y = output->swayc->current.swayc_y; - - // Single pixel bar above title - memcpy(&color, colors->border, sizeof(float) * 4); - premultiply_alpha(color, con->alpha); - box.x = x; - box.y = y; - box.width = width; - box.height = TITLEBAR_BORDER_THICKNESS; - scale_box(&box, output_scale); - render_rect(output->wlr_output, output_damage, &box, color); - - // Single pixel bar below title - size_t left_offset = 0, right_offset = 0; - bool connects_sides = false; - if (layout == L_HORIZ || layout == L_VERT || - (layout == L_STACKED && is_last_child)) { - if (con->type == C_VIEW) { - left_offset = state->border_left * state->border_thickness; - right_offset = state->border_right * state->border_thickness; - connects_sides = true; - } - } - box.x = x + left_offset; - box.y = y + container_titlebar_height() - TITLEBAR_BORDER_THICKNESS; - box.width = width - left_offset - right_offset; - box.height = TITLEBAR_BORDER_THICKNESS; - scale_box(&box, output_scale); - render_rect(output->wlr_output, output_damage, &box, color); - - if (layout == L_TABBED) { - // Single pixel left edge - box.x = x; - box.y = y + TITLEBAR_BORDER_THICKNESS; - box.width = TITLEBAR_BORDER_THICKNESS; - box.height = - container_titlebar_height() - TITLEBAR_BORDER_THICKNESS * 2; - scale_box(&box, output_scale); - render_rect(output->wlr_output, output_damage, &box, color); - - // Single pixel right edge - box.x = (x + width - TITLEBAR_BORDER_THICKNESS) * output_scale; - render_rect(output->wlr_output, output_damage, &box, color); - } - - size_t inner_width = width - TITLEBAR_H_PADDING * 2; - - // Marks - size_t marks_ob_width = 0; // output-buffer-local - if (config->show_marks && marks_texture) { - struct wlr_box texture_box; - wlr_texture_get_size(marks_texture, - &texture_box.width, &texture_box.height); - texture_box.x = (x - output_x + width - TITLEBAR_H_PADDING) - * output_scale - texture_box.width; - texture_box.y = (y - output_y + TITLEBAR_V_PADDING) * output_scale; - - float matrix[9]; - wlr_matrix_project_box(matrix, &texture_box, - WL_OUTPUT_TRANSFORM_NORMAL, - 0.0, output->wlr_output->transform_matrix); - - if (inner_width * output_scale < texture_box.width) { - texture_box.width = inner_width * output_scale; - } - render_texture(output->wlr_output, output_damage, marks_texture, - &texture_box, matrix, con->alpha); - marks_ob_width = texture_box.width; - - // Gap between the marks and bottom padding, for when the marks texture - // height is smaller than the config's font height - memcpy(&color, colors->background, sizeof(float) * 4); - premultiply_alpha(color, con->alpha); - box.x = texture_box.x; - box.y = texture_box.y + texture_box.height; - box.width = texture_box.width; - box.height = config->font_height * output_scale - texture_box.height; - if (box.height > 0) { - render_rect(output->wlr_output, output_damage, &box, color); - } - } - - // Title text - size_t title_ob_width = 0; // output-buffer-local - if (title_texture) { - struct wlr_box texture_box; - wlr_texture_get_size(title_texture, - &texture_box.width, &texture_box.height); - texture_box.x = (x - output_x + TITLEBAR_H_PADDING) * output_scale; - texture_box.y = (y - output_y + TITLEBAR_V_PADDING) * output_scale; - - float matrix[9]; - wlr_matrix_project_box(matrix, &texture_box, - WL_OUTPUT_TRANSFORM_NORMAL, - 0.0, output->wlr_output->transform_matrix); - - if (inner_width * output_scale - marks_ob_width < texture_box.width) { - texture_box.width = inner_width * output_scale - marks_ob_width; - } - render_texture(output->wlr_output, output_damage, title_texture, - &texture_box, matrix, con->alpha); - title_ob_width = texture_box.width; - - // Gap between the title and bottom padding, for when the title texture - // height is smaller than the config's font height - memcpy(&color, colors->background, sizeof(float) * 4); - premultiply_alpha(color, con->alpha); - box.x = texture_box.x; - box.y = texture_box.y + texture_box.height; - box.width = texture_box.width; - box.height = config->font_height * output_scale - texture_box.height; - if (box.height > 0) { - render_rect(output->wlr_output, output_damage, &box, color); - } - } - - // Padding above title - memcpy(&color, colors->background, sizeof(float) * 4); - premultiply_alpha(color, con->alpha); - box.x = x + (layout == L_TABBED) * TITLEBAR_BORDER_THICKNESS; - box.y = y + TITLEBAR_BORDER_THICKNESS; - box.width = width - (layout == L_TABBED) * TITLEBAR_BORDER_THICKNESS * 2; - box.height = TITLEBAR_V_PADDING - TITLEBAR_BORDER_THICKNESS; - scale_box(&box, output_scale); - render_rect(output->wlr_output, output_damage, &box, color); - - // Padding below title - box.y = (y + TITLEBAR_V_PADDING + config->font_height) * output_scale; - render_rect(output->wlr_output, output_damage, &box, color); - - // Filler between title and marks - box.width = inner_width * output_scale - title_ob_width - marks_ob_width; - if (box.width > 0) { - box.x = (x + TITLEBAR_H_PADDING) * output_scale + title_ob_width; - box.y = (y + TITLEBAR_V_PADDING) * output_scale; - box.height = config->font_height * output_scale; - render_rect(output->wlr_output, output_damage, &box, color); - } - - // Padding left of title - left_offset = (layout == L_TABBED) * TITLEBAR_BORDER_THICKNESS; - box.x = x + left_offset; - box.y = y + TITLEBAR_V_PADDING; - box.width = TITLEBAR_H_PADDING - left_offset; - box.height = config->font_height; - scale_box(&box, output_scale); - render_rect(output->wlr_output, output_damage, &box, color); - - // Padding right of marks - right_offset = (layout == L_TABBED) * TITLEBAR_BORDER_THICKNESS; - box.x = x + width - TITLEBAR_H_PADDING; - box.y = y + TITLEBAR_V_PADDING; - box.width = TITLEBAR_H_PADDING - right_offset; - box.height = config->font_height; - scale_box(&box, output_scale); - render_rect(output->wlr_output, output_damage, &box, color); - - if (connects_sides) { - // Left pixel in line with bottom bar - box.x = x; - box.y = y + container_titlebar_height() - TITLEBAR_BORDER_THICKNESS; - box.width = state->border_thickness * state->border_left; - box.height = TITLEBAR_BORDER_THICKNESS; - scale_box(&box, output_scale); - render_rect(output->wlr_output, output_damage, &box, color); - - // Right pixel in line with bottom bar - box.x = x + width - state->border_thickness * state->border_right; - box.y = y + container_titlebar_height() - TITLEBAR_BORDER_THICKNESS; - box.width = state->border_thickness * state->border_right; - box.height = TITLEBAR_BORDER_THICKNESS; - scale_box(&box, output_scale); - render_rect(output->wlr_output, output_damage, &box, color); - } -} - -/** - * Render the top border line for a view using "border pixel". - */ -static void render_top_border(struct sway_output *output, - pixman_region32_t *output_damage, struct sway_container *con, - struct border_colors *colors) { - struct sway_container_state *state = &con->current; - if (!state->border_top) { - return; - } - struct wlr_box box; - float color[4]; - float output_scale = output->wlr_output->scale; - - // Child border - top edge - memcpy(&color, colors->child_border, sizeof(float) * 4); - premultiply_alpha(color, con->alpha); - box.x = state->swayc_x; - box.y = state->swayc_y; - box.width = state->swayc_width; - box.height = state->border_thickness; - scale_box(&box, output_scale); - render_rect(output->wlr_output, output_damage, &box, color); -} - -static void render_container(struct sway_output *output, - pixman_region32_t *damage, struct sway_container *con, bool parent_focused); - -/** - * Render a container's children using a L_HORIZ or L_VERT layout. - * - * Wrap child views in borders and leave child containers borderless because - * they'll apply their own borders to their children. - */ -static void render_container_simple(struct sway_output *output, - pixman_region32_t *damage, struct sway_container *con, - bool parent_focused) { - struct sway_seat *seat = input_manager_current_seat(input_manager); - struct sway_container *focus = seat_get_focus(seat); - - for (int i = 0; i < con->current.children->length; ++i) { - struct sway_container *child = con->current.children->items[i]; - - if (child->type == C_VIEW) { - struct sway_view *view = child->sway_view; - struct border_colors *colors; - struct wlr_texture *title_texture; - struct wlr_texture *marks_texture; - struct sway_container_state *state = &child->current; - - if (focus == child || parent_focused) { - colors = &config->border_colors.focused; - title_texture = child->title_focused; - marks_texture = view->marks_focused; - } else if (seat_get_focus_inactive(seat, con) == child) { - colors = &config->border_colors.focused_inactive; - title_texture = child->title_focused_inactive; - marks_texture = view->marks_focused_inactive; - } else { - colors = &config->border_colors.unfocused; - title_texture = child->title_unfocused; - marks_texture = view->marks_unfocused; - } - - if (state->border == B_NORMAL) { - render_titlebar(output, damage, child, state->swayc_x, - state->swayc_y, state->swayc_width, colors, - title_texture, marks_texture); - } else { - render_top_border(output, damage, child, colors); - } - render_view(output, damage, child, colors); - } else { - render_container(output, damage, child, - parent_focused || focus == child); - } - } -} - -/** - * Render a container's children using the L_TABBED layout. - */ -static void render_container_tabbed(struct sway_output *output, - pixman_region32_t *damage, struct sway_container *con, - bool parent_focused) { - if (!con->current.children->length) { - return; - } - struct sway_seat *seat = input_manager_current_seat(input_manager); - struct sway_container *focus = seat_get_focus(seat); - struct sway_container *current = seat_get_active_current_child(seat, con); - struct border_colors *current_colors = &config->border_colors.unfocused; - struct sway_container_state *pstate = &con->current; - - // Render tabs - for (int i = 0; i < con->current.children->length; ++i) { - struct sway_container *child = con->current.children->items[i]; - struct sway_view *view = child->type == C_VIEW ? child->sway_view : NULL; - struct sway_container_state *cstate = &child->current; - struct border_colors *colors; - struct wlr_texture *title_texture; - struct wlr_texture *marks_texture; - - if (focus == child || parent_focused) { - colors = &config->border_colors.focused; - title_texture = child->title_focused; - marks_texture = view ? view->marks_focused : NULL; - } else if (child == current) { - colors = &config->border_colors.focused_inactive; - title_texture = child->title_focused_inactive; - marks_texture = view ? view->marks_focused_inactive : NULL; - } else { - colors = &config->border_colors.unfocused; - title_texture = child->title_unfocused; - marks_texture = view ? view->marks_unfocused : NULL; - } - - int tab_width = pstate->swayc_width / pstate->children->length; - int x = pstate->swayc_x + tab_width * i; - // Make last tab use the remaining width of the parent - if (i == pstate->children->length - 1) { - tab_width = pstate->swayc_width - tab_width * i; - } - - render_titlebar(output, damage, child, x, cstate->swayc_y, tab_width, - colors, title_texture, marks_texture); - - if (child == current) { - current_colors = colors; - } - } - - // Render surface and left/right/bottom borders - if (current) { - if (current->type == C_VIEW) { - render_view(output, damage, current, current_colors); - } else { - render_container(output, damage, current, - parent_focused || current == focus); - } - } -} - -/** - * Render a container's children using the L_STACKED layout. - */ -static void render_container_stacked(struct sway_output *output, - pixman_region32_t *damage, struct sway_container *con, - bool parent_focused) { - if (!con->current.children->length) { - return; - } - struct sway_seat *seat = input_manager_current_seat(input_manager); - struct sway_container *focus = seat_get_focus(seat); - struct sway_container *current = seat_get_active_current_child(seat, con); - struct border_colors *current_colors = &config->border_colors.unfocused; - struct sway_container_state *pstate = &con->current; - - // Render titles - for (int i = 0; i < con->current.children->length; ++i) { - struct sway_container *child = con->current.children->items[i]; - struct sway_view *view = child->type == C_VIEW ? child->sway_view : NULL; - struct sway_container_state *cstate = &child->current; - struct border_colors *colors; - struct wlr_texture *title_texture; - struct wlr_texture *marks_texture; - - if (focus == child || parent_focused) { - colors = &config->border_colors.focused; - title_texture = child->title_focused; - marks_texture = view ? view->marks_focused : NULL; - } else if (child == current) { - colors = &config->border_colors.focused_inactive; - title_texture = child->title_focused_inactive; - marks_texture = view ? view->marks_focused_inactive : NULL; - } else { - colors = &config->border_colors.unfocused; - title_texture = child->title_unfocused; - marks_texture = view ? view->marks_unfocused : NULL; - } - - int y = pstate->swayc_y + container_titlebar_height() * i; - render_titlebar(output, damage, child, cstate->swayc_x, y, - cstate->swayc_width, colors, title_texture, marks_texture); - - if (child == current) { - current_colors = colors; - } - } - - // Render surface and left/right/bottom borders - if (current) { - if (current->type == C_VIEW) { - render_view(output, damage, current, current_colors); - } else { - render_container(output, damage, current, - parent_focused || current == focus); - } - } -} - -static void render_container(struct sway_output *output, - pixman_region32_t *damage, struct sway_container *con, - bool parent_focused) { - switch (con->current.layout) { - case L_NONE: - case L_HORIZ: - case L_VERT: - render_container_simple(output, damage, con, parent_focused); - break; - case L_STACKED: - render_container_stacked(output, damage, con, parent_focused); - break; - case L_TABBED: - render_container_tabbed(output, damage, con, parent_focused); - break; - case L_FLOATING: - sway_assert(false, "Didn't expect to see floating here"); - } -} - -static void render_floating_container(struct sway_output *soutput, - pixman_region32_t *damage, struct sway_container *con) { - if (con->type == C_VIEW) { - struct sway_view *view = con->sway_view; - struct sway_seat *seat = input_manager_current_seat(input_manager); - struct sway_container *focus = seat_get_focus(seat); - struct border_colors *colors; - struct wlr_texture *title_texture; - struct wlr_texture *marks_texture; - - if (focus == con) { - colors = &config->border_colors.focused; - title_texture = con->title_focused; - marks_texture = view->marks_focused; - } else { - colors = &config->border_colors.unfocused; - title_texture = con->title_unfocused; - marks_texture = view->marks_unfocused; - } - - if (con->current.border == B_NORMAL) { - render_titlebar(soutput, damage, con, con->current.swayc_x, - con->current.swayc_y, con->current.swayc_width, colors, - title_texture, marks_texture); - } else if (con->current.border != B_NONE) { - render_top_border(soutput, damage, con, colors); - } - render_view(soutput, damage, con, colors); - } else { - render_container(soutput, damage, con, false); - } -} - -static void render_floating(struct sway_output *soutput, - pixman_region32_t *damage) { - for (int i = 0; i < root_container.current.children->length; ++i) { - struct sway_container *output = - root_container.current.children->items[i]; - for (int j = 0; j < output->current.children->length; ++j) { - struct sway_container *ws = output->current.children->items[j]; - if (!workspace_is_visible(ws)) { - continue; - } - list_t *floating = - ws->current.ws_floating->current.children; - for (int k = 0; k < floating->length; ++k) { - struct sway_container *floater = floating->items[k]; - render_floating_container(soutput, damage, floater); - } - } - } -} - -static struct sway_container *output_get_active_workspace( - struct sway_output *output) { +struct sway_container *output_get_active_workspace(struct sway_output *output) { struct sway_seat *seat = input_manager_current_seat(input_manager); struct sway_container *focus = seat_get_focus_inactive(seat, output->swayc); @@ -975,119 +217,6 @@ bool output_has_opaque_lockscreen(struct sway_output *output, return false; } -static void render_output(struct sway_output *output, struct timespec *when, - pixman_region32_t *damage) { - struct wlr_output *wlr_output = output->wlr_output; - - struct wlr_renderer *renderer = - wlr_backend_get_renderer(wlr_output->backend); - if (!sway_assert(renderer != NULL, - "expected the output backend to have a renderer")) { - return; - } - - wlr_renderer_begin(renderer, wlr_output->width, wlr_output->height); - - bool damage_whole_before_swap = false; - if (!pixman_region32_not_empty(damage)) { - // Output isn't damaged but needs buffer swap - goto renderer_end; - } - - const char *damage_debug = getenv("SWAY_DAMAGE_DEBUG"); - if (damage_debug != NULL) { - if (strcmp(damage_debug, "highlight") == 0) { - wlr_renderer_clear(renderer, (float[]){1, 1, 0, 1}); - damage_whole_before_swap = true; - } else if (strcmp(damage_debug, "rerender") == 0) { - int width, height; - wlr_output_transformed_resolution(wlr_output, &width, &height); - pixman_region32_union_rect(damage, damage, 0, 0, width, height); - } - } - - struct sway_container *workspace = output_get_active_workspace(output); - struct sway_view *fullscreen_view = workspace->current.ws_fullscreen; - struct sway_seat *seat = input_manager_current_seat(input_manager); - - if (output_has_opaque_lockscreen(output, seat)) { - struct wlr_layer_surface *wlr_layer_surface = seat->focused_layer; - struct sway_layer_surface *sway_layer_surface = - layer_from_wlr_layer_surface(seat->focused_layer); - struct render_data data = { - .output = output, - .damage = damage, - .alpha = 1.0f, - }; - surface_for_each_surface(wlr_layer_surface->surface, - sway_layer_surface->geo.x, sway_layer_surface->geo.y, - &data.root_geo, render_surface_iterator, &data); - } else if (fullscreen_view) { - float clear_color[] = {0.0f, 0.0f, 0.0f, 1.0f}; - - int nrects; - pixman_box32_t *rects = pixman_region32_rectangles(damage, &nrects); - for (int i = 0; i < nrects; ++i) { - scissor_output(wlr_output, &rects[i]); - wlr_renderer_clear(renderer, clear_color); - } - - // TODO: handle views smaller than the output - render_view_surfaces(fullscreen_view, output, damage, 1.0f); - - if (fullscreen_view->type == SWAY_VIEW_XWAYLAND) { - render_unmanaged(output, damage, - &root_container.sway_root->xwayland_unmanaged); - } - } else { - float clear_color[] = {0.25f, 0.25f, 0.25f, 1.0f}; - - int nrects; - pixman_box32_t *rects = pixman_region32_rectangles(damage, &nrects); - for (int i = 0; i < nrects; ++i) { - scissor_output(wlr_output, &rects[i]); - wlr_renderer_clear(renderer, clear_color); - } - - render_layer(output, damage, - &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND]); - render_layer(output, damage, - &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM]); - - struct sway_seat *seat = input_manager_current_seat(input_manager); - struct sway_container *focus = seat_get_focus(seat); - render_container(output, damage, workspace, focus == workspace); - render_floating(output, damage); - - render_unmanaged(output, damage, - &root_container.sway_root->xwayland_unmanaged); - render_layer(output, damage, - &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP]); - } - render_layer(output, damage, - &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY]); - render_drag_icons(output, damage, &root_container.sway_root->drag_icons); - -renderer_end: - if (root_container.sway_root->debug_tree) { - wlr_render_texture(renderer, root_container.sway_root->debug_tree, - wlr_output->transform_matrix, 0, 0, 1); - } - - if (damage_whole_before_swap || root_container.sway_root->debug_tree) { - int width, height; - wlr_output_transformed_resolution(wlr_output, &width, &height); - pixman_region32_union_rect(damage, damage, 0, 0, width, height); - } - - wlr_renderer_scissor(renderer, NULL); - wlr_renderer_end(renderer); - if (!wlr_output_damage_swap_buffers(output->damage, when, damage)) { - return; - } - output->last_frame = *when; -} - struct send_frame_done_data { struct root_geometry root_geo; struct sway_output *output; @@ -1103,7 +232,7 @@ static void send_frame_done_iterator(struct wlr_surface *surface, return; } - bool intersects = get_surface_box(&data->root_geo, data->output, surface, + bool intersects = output_get_surface_box(&data->root_geo, data->output, surface, sx, sy, NULL); if (intersects) { wlr_surface_send_frame_done(surface, data->when); @@ -1112,19 +241,19 @@ static void send_frame_done_iterator(struct wlr_surface *surface, static void send_frame_done_layer(struct send_frame_done_data *data, struct wl_list *layer_surfaces) { - layer_for_each_surface(layer_surfaces, &data->root_geo, + output_layer_for_each_surface(layer_surfaces, &data->root_geo, send_frame_done_iterator, data); } static void send_frame_done_unmanaged(struct send_frame_done_data *data, struct wl_list *unmanaged) { - unmanaged_for_each_surface(unmanaged, data->output, &data->root_geo, + output_unmanaged_for_each_surface(unmanaged, data->output, &data->root_geo, send_frame_done_iterator, data); } static void send_frame_done_drag_icons(struct send_frame_done_data *data, struct wl_list *drag_icons) { - drag_icons_for_each_surface(drag_icons, data->output, &data->root_geo, + output_drag_icons_for_each_surface(drag_icons, data->output, &data->root_geo, send_frame_done_iterator, data); } @@ -1139,7 +268,7 @@ static void send_frame_done_container_iterator(struct sway_container *con, return; } - output_view_for_each_surface(con->sway_view, &data->root_geo, + output_view_for_each_surface(con->sway_view, data->output, &data->root_geo, send_frame_done_iterator, data); } @@ -1206,7 +335,7 @@ static void damage_handle_frame(struct wl_listener *listener, void *data) { } if (needs_swap) { - render_output(output, &now, &damage); + output_render(output, &now, &damage); } pixman_region32_fini(&damage); @@ -1233,7 +362,7 @@ static void damage_surface_iterator(struct wlr_surface *surface, int sx, int sy, bool whole = data->whole; struct wlr_box box; - bool intersects = get_surface_box(&data->root_geo, data->output, surface, + bool intersects = output_get_surface_box(&data->root_geo, data->output, surface, sx, sy, &box); if (!intersects) { return; @@ -1283,7 +412,7 @@ void output_damage_surface(struct sway_output *output, double ox, double oy, .whole = whole, }; - surface_for_each_surface(surface, ox, oy, &data.root_geo, + output_surface_for_each_surface(surface, ox, oy, &data.root_geo, damage_surface_iterator, &data); } @@ -1302,7 +431,7 @@ static void output_damage_view(struct sway_output *output, .whole = whole, }; - output_view_for_each_surface(view, &data.root_geo, + output_view_for_each_surface(view, output, &data.root_geo, damage_surface_iterator, &data); } diff --git a/sway/desktop/render.c b/sway/desktop/render.c new file mode 100644 index 00000000..43948f29 --- /dev/null +++ b/sway/desktop/render.c @@ -0,0 +1,893 @@ +#define _POSIX_C_SOURCE 200809L +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "log.h" +#include "sway/config.h" +#include "sway/input/input-manager.h" +#include "sway/input/seat.h" +#include "sway/layers.h" +#include "sway/output.h" +#include "sway/server.h" +#include "sway/tree/arrange.h" +#include "sway/tree/container.h" +#include "sway/tree/layout.h" +#include "sway/tree/view.h" +#include "sway/tree/workspace.h" + +struct render_data { + struct root_geometry root_geo; + struct sway_output *output; + pixman_region32_t *damage; + struct sway_view *view; + float alpha; +}; + +static void scale_box(struct wlr_box *box, float scale) { + box->x *= scale; + box->y *= scale; + box->width *= scale; + box->height *= scale; +} + +static void scissor_output(struct wlr_output *wlr_output, + pixman_box32_t *rect) { + struct wlr_renderer *renderer = wlr_backend_get_renderer(wlr_output->backend); + assert(renderer); + + struct wlr_box box = { + .x = rect->x1, + .y = rect->y1, + .width = rect->x2 - rect->x1, + .height = rect->y2 - rect->y1, + }; + + int ow, oh; + wlr_output_transformed_resolution(wlr_output, &ow, &oh); + + enum wl_output_transform transform = + wlr_output_transform_invert(wlr_output->transform); + wlr_box_transform(&box, transform, ow, oh, &box); + + wlr_renderer_scissor(renderer, &box); +} + +static void render_texture(struct wlr_output *wlr_output, + pixman_region32_t *output_damage, struct wlr_texture *texture, + const struct wlr_box *box, const float matrix[static 9], float alpha) { + struct wlr_renderer *renderer = + wlr_backend_get_renderer(wlr_output->backend); + + pixman_region32_t damage; + pixman_region32_init(&damage); + pixman_region32_union_rect(&damage, &damage, box->x, box->y, + box->width, box->height); + pixman_region32_intersect(&damage, &damage, output_damage); + bool damaged = pixman_region32_not_empty(&damage); + if (!damaged) { + goto damage_finish; + } + + int nrects; + pixman_box32_t *rects = pixman_region32_rectangles(&damage, &nrects); + for (int i = 0; i < nrects; ++i) { + scissor_output(wlr_output, &rects[i]); + wlr_render_texture_with_matrix(renderer, texture, matrix, alpha); + } + +damage_finish: + pixman_region32_fini(&damage); +} + +static void render_surface_iterator(struct wlr_surface *surface, int sx, int sy, + void *_data) { + struct render_data *data = _data; + struct wlr_output *wlr_output = data->output->wlr_output; + float rotation = data->root_geo.rotation; + pixman_region32_t *output_damage = data->damage; + float alpha = data->alpha; + + struct wlr_texture *texture = wlr_surface_get_texture(surface); + if (!texture) { + return; + } + + struct wlr_box box; + bool intersects = output_get_surface_box(&data->root_geo, data->output, + surface, sx, sy, &box); + if (!intersects) { + return; + } + + scale_box(&box, wlr_output->scale); + + float matrix[9]; + enum wl_output_transform transform = + wlr_output_transform_invert(surface->current.transform); + wlr_matrix_project_box(matrix, &box, transform, rotation, + wlr_output->transform_matrix); + + render_texture(wlr_output, output_damage, texture, &box, matrix, alpha); +} + +static void render_layer(struct sway_output *output, + pixman_region32_t *damage, struct wl_list *layer_surfaces) { + struct render_data data = { + .output = output, + .damage = damage, + .alpha = 1.0f, + }; + output_layer_for_each_surface(layer_surfaces, &data.root_geo, + render_surface_iterator, &data); +} + +static void render_unmanaged(struct sway_output *output, + pixman_region32_t *damage, struct wl_list *unmanaged) { + struct render_data data = { + .output = output, + .damage = damage, + .alpha = 1.0f, + }; + output_unmanaged_for_each_surface(unmanaged, output, &data.root_geo, + render_surface_iterator, &data); +} + +static void render_drag_icons(struct sway_output *output, + pixman_region32_t *damage, struct wl_list *drag_icons) { + struct render_data data = { + .output = output, + .damage = damage, + .alpha = 1.0f, + }; + output_drag_icons_for_each_surface(drag_icons, output, &data.root_geo, + render_surface_iterator, &data); +} + +static void render_rect(struct wlr_output *wlr_output, + pixman_region32_t *output_damage, const struct wlr_box *_box, + float color[static 4]) { + struct wlr_renderer *renderer = + wlr_backend_get_renderer(wlr_output->backend); + + struct wlr_box box; + memcpy(&box, _box, sizeof(struct wlr_box)); + box.x -= wlr_output->lx * wlr_output->scale; + box.y -= wlr_output->ly * wlr_output->scale; + + pixman_region32_t damage; + pixman_region32_init(&damage); + pixman_region32_union_rect(&damage, &damage, box.x, box.y, + box.width, box.height); + pixman_region32_intersect(&damage, &damage, output_damage); + bool damaged = pixman_region32_not_empty(&damage); + if (!damaged) { + goto damage_finish; + } + + int nrects; + pixman_box32_t *rects = pixman_region32_rectangles(&damage, &nrects); + for (int i = 0; i < nrects; ++i) { + scissor_output(wlr_output, &rects[i]); + wlr_render_rect(renderer, &box, color, + wlr_output->transform_matrix); + } + +damage_finish: + pixman_region32_fini(&damage); +} + +static void premultiply_alpha(float color[4], float opacity) { + color[3] *= opacity; + color[0] *= color[3]; + color[1] *= color[3]; + color[2] *= color[3]; +} + +static void render_view_surfaces(struct sway_view *view, + struct sway_output *output, pixman_region32_t *damage, float alpha) { + struct render_data data = { + .output = output, + .damage = damage, + .view = view, + .alpha = alpha, + }; + output_view_for_each_surface(view, output, &data.root_geo, + render_surface_iterator, &data); +} + +static void render_saved_view(struct sway_view *view, + struct sway_output *output, pixman_region32_t *damage, float alpha) { + struct wlr_output *wlr_output = output->wlr_output; + + int width, height; + struct wlr_texture *texture = + transaction_get_saved_texture(view, &width, &height); + if (!texture) { + return; + } + struct wlr_box box = { + .x = view->swayc->current.view_x - output->swayc->current.swayc_x, + .y = view->swayc->current.view_y - output->swayc->current.swayc_y, + .width = width, + .height = height, + }; + + struct wlr_box output_box = { + .width = output->swayc->current.swayc_width, + .height = output->swayc->current.swayc_height, + }; + + struct wlr_box intersection; + bool intersects = wlr_box_intersection(&output_box, &box, &intersection); + if (!intersects) { + return; + } + + scale_box(&box, wlr_output->scale); + + float matrix[9]; + wlr_matrix_project_box(matrix, &box, WL_OUTPUT_TRANSFORM_NORMAL, 0, + wlr_output->transform_matrix); + + render_texture(wlr_output, damage, texture, &box, matrix, alpha); +} + +/** + * Render a view's surface and left/bottom/right borders. + */ +static void render_view(struct sway_output *output, pixman_region32_t *damage, + struct sway_container *con, struct border_colors *colors) { + struct sway_view *view = con->sway_view; + if (view->swayc->instructions->length) { + render_saved_view(view, output, damage, view->swayc->alpha); + } else { + render_view_surfaces(view, output, damage, view->swayc->alpha); + } + + struct wlr_box box; + float output_scale = output->wlr_output->scale; + float color[4]; + struct sway_container_state *state = &con->current; + + if (state->border != B_NONE) { + if (state->border_left) { + memcpy(&color, colors->child_border, sizeof(float) * 4); + premultiply_alpha(color, con->alpha); + box.x = state->swayc_x; + box.y = state->view_y; + box.width = state->border_thickness; + box.height = state->view_height; + scale_box(&box, output_scale); + render_rect(output->wlr_output, damage, &box, color); + } + + if (state->border_right) { + if (state->parent->current.children->length == 1 + && state->parent->current.layout == L_HORIZ) { + memcpy(&color, colors->indicator, sizeof(float) * 4); + } else { + memcpy(&color, colors->child_border, sizeof(float) * 4); + } + premultiply_alpha(color, con->alpha); + box.x = state->view_x + state->view_width; + box.y = state->view_y; + box.width = state->border_thickness; + box.height = state->view_height; + scale_box(&box, output_scale); + render_rect(output->wlr_output, damage, &box, color); + } + + if (state->border_bottom) { + if (state->parent->current.children->length == 1 + && con->current.parent->current.layout == L_VERT) { + memcpy(&color, colors->indicator, sizeof(float) * 4); + } else { + memcpy(&color, colors->child_border, sizeof(float) * 4); + } + premultiply_alpha(color, con->alpha); + box.x = state->swayc_x; + box.y = state->view_y + state->view_height; + box.width = state->swayc_width; + box.height = state->border_thickness; + scale_box(&box, output_scale); + render_rect(output->wlr_output, damage, &box, color); + } + } +} + +/** + * Render a titlebar. + * + * Care must be taken not to render over the same pixel multiple times, + * otherwise the colors will be incorrect when using opacity. + * + * The height is: 1px border, 3px padding, font height, 3px padding, 1px border + * The left side for L_TABBED is: 1px border, 2px padding, title + * The left side for other layouts is: 3px padding, title + */ +static void render_titlebar(struct sway_output *output, + pixman_region32_t *output_damage, struct sway_container *con, + int x, int y, int width, + struct border_colors *colors, struct wlr_texture *title_texture, + struct wlr_texture *marks_texture) { + struct wlr_box box; + float color[4]; + struct sway_container_state *state = &con->current; + float output_scale = output->wlr_output->scale; + enum sway_container_layout layout = state->parent->current.layout; + list_t *children = state->parent->current.children; + bool is_last_child = children->items[children->length - 1] == con; + double output_x = output->swayc->current.swayc_x; + double output_y = output->swayc->current.swayc_y; + + // Single pixel bar above title + memcpy(&color, colors->border, sizeof(float) * 4); + premultiply_alpha(color, con->alpha); + box.x = x; + box.y = y; + box.width = width; + box.height = TITLEBAR_BORDER_THICKNESS; + scale_box(&box, output_scale); + render_rect(output->wlr_output, output_damage, &box, color); + + // Single pixel bar below title + size_t left_offset = 0, right_offset = 0; + bool connects_sides = false; + if (layout == L_HORIZ || layout == L_VERT || + (layout == L_STACKED && is_last_child)) { + if (con->type == C_VIEW) { + left_offset = state->border_left * state->border_thickness; + right_offset = state->border_right * state->border_thickness; + connects_sides = true; + } + } + box.x = x + left_offset; + box.y = y + container_titlebar_height() - TITLEBAR_BORDER_THICKNESS; + box.width = width - left_offset - right_offset; + box.height = TITLEBAR_BORDER_THICKNESS; + scale_box(&box, output_scale); + render_rect(output->wlr_output, output_damage, &box, color); + + if (layout == L_TABBED) { + // Single pixel left edge + box.x = x; + box.y = y + TITLEBAR_BORDER_THICKNESS; + box.width = TITLEBAR_BORDER_THICKNESS; + box.height = + container_titlebar_height() - TITLEBAR_BORDER_THICKNESS * 2; + scale_box(&box, output_scale); + render_rect(output->wlr_output, output_damage, &box, color); + + // Single pixel right edge + box.x = (x + width - TITLEBAR_BORDER_THICKNESS) * output_scale; + render_rect(output->wlr_output, output_damage, &box, color); + } + + size_t inner_width = width - TITLEBAR_H_PADDING * 2; + + // Marks + size_t marks_ob_width = 0; // output-buffer-local + if (config->show_marks && marks_texture) { + struct wlr_box texture_box; + wlr_texture_get_size(marks_texture, + &texture_box.width, &texture_box.height); + texture_box.x = (x - output_x + width - TITLEBAR_H_PADDING) + * output_scale - texture_box.width; + texture_box.y = (y - output_y + TITLEBAR_V_PADDING) * output_scale; + + float matrix[9]; + wlr_matrix_project_box(matrix, &texture_box, + WL_OUTPUT_TRANSFORM_NORMAL, + 0.0, output->wlr_output->transform_matrix); + + if (inner_width * output_scale < texture_box.width) { + texture_box.width = inner_width * output_scale; + } + render_texture(output->wlr_output, output_damage, marks_texture, + &texture_box, matrix, con->alpha); + marks_ob_width = texture_box.width; + + // Gap between the marks and bottom padding, for when the marks texture + // height is smaller than the config's font height + memcpy(&color, colors->background, sizeof(float) * 4); + premultiply_alpha(color, con->alpha); + box.x = texture_box.x; + box.y = texture_box.y + texture_box.height; + box.width = texture_box.width; + box.height = config->font_height * output_scale - texture_box.height; + if (box.height > 0) { + render_rect(output->wlr_output, output_damage, &box, color); + } + } + + // Title text + size_t title_ob_width = 0; // output-buffer-local + if (title_texture) { + struct wlr_box texture_box; + wlr_texture_get_size(title_texture, + &texture_box.width, &texture_box.height); + texture_box.x = (x - output_x + TITLEBAR_H_PADDING) * output_scale; + texture_box.y = (y - output_y + TITLEBAR_V_PADDING) * output_scale; + + float matrix[9]; + wlr_matrix_project_box(matrix, &texture_box, + WL_OUTPUT_TRANSFORM_NORMAL, + 0.0, output->wlr_output->transform_matrix); + + if (inner_width * output_scale - marks_ob_width < texture_box.width) { + texture_box.width = inner_width * output_scale - marks_ob_width; + } + render_texture(output->wlr_output, output_damage, title_texture, + &texture_box, matrix, con->alpha); + title_ob_width = texture_box.width; + + // Gap between the title and bottom padding, for when the title texture + // height is smaller than the config's font height + memcpy(&color, colors->background, sizeof(float) * 4); + premultiply_alpha(color, con->alpha); + box.x = texture_box.x; + box.y = texture_box.y + texture_box.height; + box.width = texture_box.width; + box.height = config->font_height * output_scale - texture_box.height; + if (box.height > 0) { + render_rect(output->wlr_output, output_damage, &box, color); + } + } + + // Padding above title + memcpy(&color, colors->background, sizeof(float) * 4); + premultiply_alpha(color, con->alpha); + box.x = x + (layout == L_TABBED) * TITLEBAR_BORDER_THICKNESS; + box.y = y + TITLEBAR_BORDER_THICKNESS; + box.width = width - (layout == L_TABBED) * TITLEBAR_BORDER_THICKNESS * 2; + box.height = TITLEBAR_V_PADDING - TITLEBAR_BORDER_THICKNESS; + scale_box(&box, output_scale); + render_rect(output->wlr_output, output_damage, &box, color); + + // Padding below title + box.y = (y + TITLEBAR_V_PADDING + config->font_height) * output_scale; + render_rect(output->wlr_output, output_damage, &box, color); + + // Filler between title and marks + box.width = inner_width * output_scale - title_ob_width - marks_ob_width; + if (box.width > 0) { + box.x = (x + TITLEBAR_H_PADDING) * output_scale + title_ob_width; + box.y = (y + TITLEBAR_V_PADDING) * output_scale; + box.height = config->font_height * output_scale; + render_rect(output->wlr_output, output_damage, &box, color); + } + + // Padding left of title + left_offset = (layout == L_TABBED) * TITLEBAR_BORDER_THICKNESS; + box.x = x + left_offset; + box.y = y + TITLEBAR_V_PADDING; + box.width = TITLEBAR_H_PADDING - left_offset; + box.height = config->font_height; + scale_box(&box, output_scale); + render_rect(output->wlr_output, output_damage, &box, color); + + // Padding right of marks + right_offset = (layout == L_TABBED) * TITLEBAR_BORDER_THICKNESS; + box.x = x + width - TITLEBAR_H_PADDING; + box.y = y + TITLEBAR_V_PADDING; + box.width = TITLEBAR_H_PADDING - right_offset; + box.height = config->font_height; + scale_box(&box, output_scale); + render_rect(output->wlr_output, output_damage, &box, color); + + if (connects_sides) { + // Left pixel in line with bottom bar + box.x = x; + box.y = y + container_titlebar_height() - TITLEBAR_BORDER_THICKNESS; + box.width = state->border_thickness * state->border_left; + box.height = TITLEBAR_BORDER_THICKNESS; + scale_box(&box, output_scale); + render_rect(output->wlr_output, output_damage, &box, color); + + // Right pixel in line with bottom bar + box.x = x + width - state->border_thickness * state->border_right; + box.y = y + container_titlebar_height() - TITLEBAR_BORDER_THICKNESS; + box.width = state->border_thickness * state->border_right; + box.height = TITLEBAR_BORDER_THICKNESS; + scale_box(&box, output_scale); + render_rect(output->wlr_output, output_damage, &box, color); + } +} + +/** + * Render the top border line for a view using "border pixel". + */ +static void render_top_border(struct sway_output *output, + pixman_region32_t *output_damage, struct sway_container *con, + struct border_colors *colors) { + struct sway_container_state *state = &con->current; + if (!state->border_top) { + return; + } + struct wlr_box box; + float color[4]; + float output_scale = output->wlr_output->scale; + + // Child border - top edge + memcpy(&color, colors->child_border, sizeof(float) * 4); + premultiply_alpha(color, con->alpha); + box.x = state->swayc_x; + box.y = state->swayc_y; + box.width = state->swayc_width; + box.height = state->border_thickness; + scale_box(&box, output_scale); + render_rect(output->wlr_output, output_damage, &box, color); +} + +static void render_container(struct sway_output *output, + pixman_region32_t *damage, struct sway_container *con, bool parent_focused); + +/** + * Render a container's children using a L_HORIZ or L_VERT layout. + * + * Wrap child views in borders and leave child containers borderless because + * they'll apply their own borders to their children. + */ +static void render_container_simple(struct sway_output *output, + pixman_region32_t *damage, struct sway_container *con, + bool parent_focused) { + struct sway_seat *seat = input_manager_current_seat(input_manager); + struct sway_container *focus = seat_get_focus(seat); + + for (int i = 0; i < con->current.children->length; ++i) { + struct sway_container *child = con->current.children->items[i]; + + if (child->type == C_VIEW) { + struct sway_view *view = child->sway_view; + struct border_colors *colors; + struct wlr_texture *title_texture; + struct wlr_texture *marks_texture; + struct sway_container_state *state = &child->current; + + if (focus == child || parent_focused) { + colors = &config->border_colors.focused; + title_texture = child->title_focused; + marks_texture = view->marks_focused; + } else if (seat_get_focus_inactive(seat, con) == child) { + colors = &config->border_colors.focused_inactive; + title_texture = child->title_focused_inactive; + marks_texture = view->marks_focused_inactive; + } else { + colors = &config->border_colors.unfocused; + title_texture = child->title_unfocused; + marks_texture = view->marks_unfocused; + } + + if (state->border == B_NORMAL) { + render_titlebar(output, damage, child, state->swayc_x, + state->swayc_y, state->swayc_width, colors, + title_texture, marks_texture); + } else { + render_top_border(output, damage, child, colors); + } + render_view(output, damage, child, colors); + } else { + render_container(output, damage, child, + parent_focused || focus == child); + } + } +} + +/** + * Render a container's children using the L_TABBED layout. + */ +static void render_container_tabbed(struct sway_output *output, + pixman_region32_t *damage, struct sway_container *con, + bool parent_focused) { + if (!con->current.children->length) { + return; + } + struct sway_seat *seat = input_manager_current_seat(input_manager); + struct sway_container *focus = seat_get_focus(seat); + struct sway_container *current = seat_get_active_current_child(seat, con); + struct border_colors *current_colors = &config->border_colors.unfocused; + struct sway_container_state *pstate = &con->current; + + // Render tabs + for (int i = 0; i < con->current.children->length; ++i) { + struct sway_container *child = con->current.children->items[i]; + struct sway_view *view = child->type == C_VIEW ? child->sway_view : NULL; + struct sway_container_state *cstate = &child->current; + struct border_colors *colors; + struct wlr_texture *title_texture; + struct wlr_texture *marks_texture; + + if (focus == child || parent_focused) { + colors = &config->border_colors.focused; + title_texture = child->title_focused; + marks_texture = view ? view->marks_focused : NULL; + } else if (child == current) { + colors = &config->border_colors.focused_inactive; + title_texture = child->title_focused_inactive; + marks_texture = view ? view->marks_focused_inactive : NULL; + } else { + colors = &config->border_colors.unfocused; + title_texture = child->title_unfocused; + marks_texture = view ? view->marks_unfocused : NULL; + } + + int tab_width = pstate->swayc_width / pstate->children->length; + int x = pstate->swayc_x + tab_width * i; + // Make last tab use the remaining width of the parent + if (i == pstate->children->length - 1) { + tab_width = pstate->swayc_width - tab_width * i; + } + + render_titlebar(output, damage, child, x, cstate->swayc_y, tab_width, + colors, title_texture, marks_texture); + + if (child == current) { + current_colors = colors; + } + } + + // Render surface and left/right/bottom borders + if (current) { + if (current->type == C_VIEW) { + render_view(output, damage, current, current_colors); + } else { + render_container(output, damage, current, + parent_focused || current == focus); + } + } +} + +/** + * Render a container's children using the L_STACKED layout. + */ +static void render_container_stacked(struct sway_output *output, + pixman_region32_t *damage, struct sway_container *con, + bool parent_focused) { + if (!con->current.children->length) { + return; + } + struct sway_seat *seat = input_manager_current_seat(input_manager); + struct sway_container *focus = seat_get_focus(seat); + struct sway_container *current = seat_get_active_current_child(seat, con); + struct border_colors *current_colors = &config->border_colors.unfocused; + struct sway_container_state *pstate = &con->current; + + // Render titles + for (int i = 0; i < con->current.children->length; ++i) { + struct sway_container *child = con->current.children->items[i]; + struct sway_view *view = child->type == C_VIEW ? child->sway_view : NULL; + struct sway_container_state *cstate = &child->current; + struct border_colors *colors; + struct wlr_texture *title_texture; + struct wlr_texture *marks_texture; + + if (focus == child || parent_focused) { + colors = &config->border_colors.focused; + title_texture = child->title_focused; + marks_texture = view ? view->marks_focused : NULL; + } else if (child == current) { + colors = &config->border_colors.focused_inactive; + title_texture = child->title_focused_inactive; + marks_texture = view ? view->marks_focused_inactive : NULL; + } else { + colors = &config->border_colors.unfocused; + title_texture = child->title_unfocused; + marks_texture = view ? view->marks_unfocused : NULL; + } + + int y = pstate->swayc_y + container_titlebar_height() * i; + render_titlebar(output, damage, child, cstate->swayc_x, y, + cstate->swayc_width, colors, title_texture, marks_texture); + + if (child == current) { + current_colors = colors; + } + } + + // Render surface and left/right/bottom borders + if (current) { + if (current->type == C_VIEW) { + render_view(output, damage, current, current_colors); + } else { + render_container(output, damage, current, + parent_focused || current == focus); + } + } +} + +static void render_container(struct sway_output *output, + pixman_region32_t *damage, struct sway_container *con, + bool parent_focused) { + switch (con->current.layout) { + case L_NONE: + case L_HORIZ: + case L_VERT: + render_container_simple(output, damage, con, parent_focused); + break; + case L_STACKED: + render_container_stacked(output, damage, con, parent_focused); + break; + case L_TABBED: + render_container_tabbed(output, damage, con, parent_focused); + break; + case L_FLOATING: + sway_assert(false, "Didn't expect to see floating here"); + } +} + +static void render_floating_container(struct sway_output *soutput, + pixman_region32_t *damage, struct sway_container *con) { + if (con->type == C_VIEW) { + struct sway_view *view = con->sway_view; + struct sway_seat *seat = input_manager_current_seat(input_manager); + struct sway_container *focus = seat_get_focus(seat); + struct border_colors *colors; + struct wlr_texture *title_texture; + struct wlr_texture *marks_texture; + + if (focus == con) { + colors = &config->border_colors.focused; + title_texture = con->title_focused; + marks_texture = view->marks_focused; + } else { + colors = &config->border_colors.unfocused; + title_texture = con->title_unfocused; + marks_texture = view->marks_unfocused; + } + + if (con->current.border == B_NORMAL) { + render_titlebar(soutput, damage, con, con->current.swayc_x, + con->current.swayc_y, con->current.swayc_width, colors, + title_texture, marks_texture); + } else if (con->current.border != B_NONE) { + render_top_border(soutput, damage, con, colors); + } + render_view(soutput, damage, con, colors); + } else { + render_container(soutput, damage, con, false); + } +} + +static void render_floating(struct sway_output *soutput, + pixman_region32_t *damage) { + for (int i = 0; i < root_container.current.children->length; ++i) { + struct sway_container *output = + root_container.current.children->items[i]; + for (int j = 0; j < output->current.children->length; ++j) { + struct sway_container *ws = output->current.children->items[j]; + if (!workspace_is_visible(ws)) { + continue; + } + list_t *floating = + ws->current.ws_floating->current.children; + for (int k = 0; k < floating->length; ++k) { + struct sway_container *floater = floating->items[k]; + render_floating_container(soutput, damage, floater); + } + } + } +} + +void output_render(struct sway_output *output, struct timespec *when, + pixman_region32_t *damage) { + struct wlr_output *wlr_output = output->wlr_output; + + struct wlr_renderer *renderer = + wlr_backend_get_renderer(wlr_output->backend); + if (!sway_assert(renderer != NULL, + "expected the output backend to have a renderer")) { + return; + } + + wlr_renderer_begin(renderer, wlr_output->width, wlr_output->height); + + bool damage_whole_before_swap = false; + if (!pixman_region32_not_empty(damage)) { + // Output isn't damaged but needs buffer swap + goto renderer_end; + } + + const char *damage_debug = getenv("SWAY_DAMAGE_DEBUG"); + if (damage_debug != NULL) { + if (strcmp(damage_debug, "highlight") == 0) { + wlr_renderer_clear(renderer, (float[]){1, 1, 0, 1}); + damage_whole_before_swap = true; + } else if (strcmp(damage_debug, "rerender") == 0) { + int width, height; + wlr_output_transformed_resolution(wlr_output, &width, &height); + pixman_region32_union_rect(damage, damage, 0, 0, width, height); + } + } + + struct sway_container *workspace = output_get_active_workspace(output); + struct sway_view *fullscreen_view = workspace->current.ws_fullscreen; + struct sway_seat *seat = input_manager_current_seat(input_manager); + + if (output_has_opaque_lockscreen(output, seat)) { + struct wlr_layer_surface *wlr_layer_surface = seat->focused_layer; + struct sway_layer_surface *sway_layer_surface = + layer_from_wlr_layer_surface(seat->focused_layer); + struct render_data data = { + .output = output, + .damage = damage, + .alpha = 1.0f, + }; + output_surface_for_each_surface(wlr_layer_surface->surface, + sway_layer_surface->geo.x, sway_layer_surface->geo.y, + &data.root_geo, render_surface_iterator, &data); + } else if (fullscreen_view) { + float clear_color[] = {0.0f, 0.0f, 0.0f, 1.0f}; + + int nrects; + pixman_box32_t *rects = pixman_region32_rectangles(damage, &nrects); + for (int i = 0; i < nrects; ++i) { + scissor_output(wlr_output, &rects[i]); + wlr_renderer_clear(renderer, clear_color); + } + + // TODO: handle views smaller than the output + render_view_surfaces(fullscreen_view, output, damage, 1.0f); + + if (fullscreen_view->type == SWAY_VIEW_XWAYLAND) { + render_unmanaged(output, damage, + &root_container.sway_root->xwayland_unmanaged); + } + } else { + float clear_color[] = {0.25f, 0.25f, 0.25f, 1.0f}; + + int nrects; + pixman_box32_t *rects = pixman_region32_rectangles(damage, &nrects); + for (int i = 0; i < nrects; ++i) { + scissor_output(wlr_output, &rects[i]); + wlr_renderer_clear(renderer, clear_color); + } + + render_layer(output, damage, + &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND]); + render_layer(output, damage, + &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM]); + + struct sway_seat *seat = input_manager_current_seat(input_manager); + struct sway_container *focus = seat_get_focus(seat); + render_container(output, damage, workspace, focus == workspace); + render_floating(output, damage); + + render_unmanaged(output, damage, + &root_container.sway_root->xwayland_unmanaged); + render_layer(output, damage, + &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP]); + } + render_layer(output, damage, + &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY]); + render_drag_icons(output, damage, &root_container.sway_root->drag_icons); + +renderer_end: + if (root_container.sway_root->debug_tree) { + wlr_render_texture(renderer, root_container.sway_root->debug_tree, + wlr_output->transform_matrix, 0, 0, 1); + } + + if (damage_whole_before_swap || root_container.sway_root->debug_tree) { + int width, height; + wlr_output_transformed_resolution(wlr_output, &width, &height); + pixman_region32_union_rect(damage, damage, 0, 0, width, height); + } + + wlr_renderer_scissor(renderer, NULL); + wlr_renderer_end(renderer); + if (!wlr_output_damage_swap_buffers(output->damage, when, damage)) { + return; + } + output->last_frame = *when; +} -- cgit v1.2.3 From ab8a86369c01c7146991ff4ae2ef04b0a1db06ca Mon Sep 17 00:00:00 2001 From: Ryan Dwyer Date: Sat, 7 Jul 2018 18:36:20 +1000 Subject: Implement some floating move commands This implements the following for floating containers: * move * move [absolute] position * move [absolute] position mouse --- sway/desktop/desktop.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'sway/desktop') diff --git a/sway/desktop/desktop.c b/sway/desktop/desktop.c index e495790c..6575519d 100644 --- a/sway/desktop/desktop.c +++ b/sway/desktop/desktop.c @@ -13,3 +13,12 @@ void desktop_damage_surface(struct wlr_surface *surface, double lx, double ly, } } } + +void desktop_damage_whole_container(struct sway_container *con) { + for (int i = 0; i < root_container.children->length; ++i) { + struct sway_container *cont = root_container.children->items[i]; + if (cont->type == C_OUTPUT) { + output_damage_whole_container(cont->sway_output, con); + } + } +} -- cgit v1.2.3 From 9dd54f934e73370b3438d48e062ec98a1db6b037 Mon Sep 17 00:00:00 2001 From: Konstantin Pospelov Date: Tue, 10 Jul 2018 00:33:13 +0300 Subject: Fix titlebar rendering for nested stacked containers --- sway/desktop/render.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) (limited to 'sway/desktop') diff --git a/sway/desktop/render.c b/sway/desktop/render.c index 43948f29..f554b813 100644 --- a/sway/desktop/render.c +++ b/sway/desktop/render.c @@ -599,9 +599,11 @@ static void render_container_tabbed(struct sway_output *output, struct border_colors *current_colors = &config->border_colors.unfocused; struct sway_container_state *pstate = &con->current; + int tab_width = pstate->swayc_width / pstate->children->length; + // Render tabs - for (int i = 0; i < con->current.children->length; ++i) { - struct sway_container *child = con->current.children->items[i]; + for (int i = 0; i < pstate->children->length; ++i) { + struct sway_container *child = pstate->children->items[i]; struct sway_view *view = child->type == C_VIEW ? child->sway_view : NULL; struct sway_container_state *cstate = &child->current; struct border_colors *colors; @@ -622,8 +624,8 @@ static void render_container_tabbed(struct sway_output *output, marks_texture = view ? view->marks_unfocused : NULL; } - int tab_width = pstate->swayc_width / pstate->children->length; - int x = pstate->swayc_x + tab_width * i; + int x = cstate->swayc_x + tab_width * i; + // Make last tab use the remaining width of the parent if (i == pstate->children->length - 1) { tab_width = pstate->swayc_width - tab_width * i; @@ -663,9 +665,11 @@ static void render_container_stacked(struct sway_output *output, struct border_colors *current_colors = &config->border_colors.unfocused; struct sway_container_state *pstate = &con->current; + size_t titlebar_height = container_titlebar_height(); + // Render titles - for (int i = 0; i < con->current.children->length; ++i) { - struct sway_container *child = con->current.children->items[i]; + for (int i = 0; i < pstate->children->length; ++i) { + struct sway_container *child = pstate->children->items[i]; struct sway_view *view = child->type == C_VIEW ? child->sway_view : NULL; struct sway_container_state *cstate = &child->current; struct border_colors *colors; @@ -686,7 +690,7 @@ static void render_container_stacked(struct sway_output *output, marks_texture = view ? view->marks_unfocused : NULL; } - int y = pstate->swayc_y + container_titlebar_height() * i; + int y = cstate->swayc_y + titlebar_height * i; render_titlebar(output, damage, child, cstate->swayc_x, y, cstate->swayc_width, colors, title_texture, marks_texture); -- cgit v1.2.3 From 63b4bf500020cf35cebfdce2d73f8e359ff495c2 Mon Sep 17 00:00:00 2001 From: emersion Date: Mon, 9 Jul 2018 22:54:30 +0100 Subject: Update for swaywm/wlroots#1126 --- sway/desktop/idle_inhibit_v1.c | 4 ++-- sway/desktop/layer_shell.c | 6 +++--- sway/desktop/output.c | 2 +- sway/desktop/transaction.c | 14 +++++++------- sway/desktop/xdg_shell.c | 4 ++-- sway/desktop/xdg_shell_v6.c | 4 ++-- sway/desktop/xwayland.c | 10 +++++----- 7 files changed, 22 insertions(+), 22 deletions(-) (limited to 'sway/desktop') diff --git a/sway/desktop/idle_inhibit_v1.c b/sway/desktop/idle_inhibit_v1.c index c02ca26e..108a8417 100644 --- a/sway/desktop/idle_inhibit_v1.c +++ b/sway/desktop/idle_inhibit_v1.c @@ -9,7 +9,7 @@ static void handle_destroy(struct wl_listener *listener, void *data) { struct sway_idle_inhibitor_v1 *inhibitor = wl_container_of(listener, inhibitor, destroy); - wlr_log(L_DEBUG, "Sway idle inhibitor destroyed"); + wlr_log(WLR_DEBUG, "Sway idle inhibitor destroyed"); wl_list_remove(&inhibitor->link); wl_list_remove(&inhibitor->destroy.link); idle_inhibit_v1_check_active(inhibitor->manager); @@ -20,7 +20,7 @@ void handle_idle_inhibitor_v1(struct wl_listener *listener, void *data) { struct wlr_idle_inhibitor_v1 *wlr_inhibitor = data; struct sway_idle_inhibit_manager_v1 *manager = wl_container_of(listener, manager, new_idle_inhibitor_v1); - wlr_log(L_DEBUG, "New sway idle inhibitor"); + wlr_log(WLR_DEBUG, "New sway idle inhibitor"); struct sway_idle_inhibitor_v1 *inhibitor = calloc(1, sizeof(struct sway_idle_inhibitor_v1)); diff --git a/sway/desktop/layer_shell.c b/sway/desktop/layer_shell.c index de1fe349..16910c7e 100644 --- a/sway/desktop/layer_shell.c +++ b/sway/desktop/layer_shell.c @@ -174,7 +174,7 @@ void arrange_layers(struct sway_output *output) { if (memcmp(&usable_area, &output->usable_area, sizeof(struct wlr_box)) != 0) { - wlr_log(L_DEBUG, "Usable area changed, rearranging output"); + wlr_log(WLR_DEBUG, "Usable area changed, rearranging output"); memcpy(&output->usable_area, &usable_area, sizeof(struct wlr_box)); arrange_and_commit(output->swayc); } @@ -269,7 +269,7 @@ static void unmap(struct sway_layer_surface *sway_layer) { static void handle_destroy(struct wl_listener *listener, void *data) { struct sway_layer_surface *sway_layer = wl_container_of(listener, sway_layer, destroy); - wlr_log(L_DEBUG, "Layer surface destroyed (%s)", + wlr_log(WLR_DEBUG, "Layer surface destroyed (%s)", sway_layer->layer_surface->namespace); if (sway_layer->layer_surface->mapped) { unmap(sway_layer); @@ -316,7 +316,7 @@ void handle_layer_shell_surface(struct wl_listener *listener, void *data) { struct wlr_layer_surface *layer_surface = data; struct sway_server *server = wl_container_of(listener, server, layer_shell_surface); - wlr_log(L_DEBUG, "new layer surface: namespace %s layer %d anchor %d " + wlr_log(WLR_DEBUG, "new layer surface: namespace %s layer %d anchor %d " "size %dx%d margin %d,%d,%d,%d", layer_surface->namespace, layer_surface->layer, layer_surface->layer, layer_surface->client_pending.desired_width, diff --git a/sway/desktop/output.c b/sway/desktop/output.c index 8b50bc44..73108450 100644 --- a/sway/desktop/output.c +++ b/sway/desktop/output.c @@ -525,7 +525,7 @@ struct sway_output *output_from_wlr_output(struct wlr_output *wlr_output) { void handle_new_output(struct wl_listener *listener, void *data) { struct sway_server *server = wl_container_of(listener, server, new_output); struct wlr_output *wlr_output = data; - wlr_log(L_DEBUG, "New output %p: %s", wlr_output, wlr_output->name); + wlr_log(WLR_DEBUG, "New output %p: %s", wlr_output, wlr_output->name); struct sway_output *output = calloc(1, sizeof(struct sway_output)); if (!output) { diff --git a/sway/desktop/transaction.c b/sway/desktop/transaction.c index 179af617..2b3f87c3 100644 --- a/sway/desktop/transaction.c +++ b/sway/desktop/transaction.c @@ -175,7 +175,7 @@ void transaction_add_container(struct sway_transaction *transaction, * Apply a transaction to the "current" state of the tree. */ static void transaction_apply(struct sway_transaction *transaction) { - wlr_log(L_DEBUG, "Applying transaction %p", transaction); + wlr_log(WLR_DEBUG, "Applying transaction %p", transaction); if (server.debug_txn_timings) { struct timespec now; clock_gettime(CLOCK_MONOTONIC, &now); @@ -186,7 +186,7 @@ static void transaction_apply(struct sway_transaction *transaction) { float ms_waiting = (now.tv_sec - commit->tv_sec) * 1000 + (now.tv_nsec - commit->tv_nsec) / 1000000.0; float ms_total = ms_arranging + ms_waiting; - wlr_log(L_DEBUG, "Transaction %p: %.1fms arranging, %.1fms waiting, " + wlr_log(WLR_DEBUG, "Transaction %p: %.1fms arranging, %.1fms waiting, " "%.1fms total (%.1f frames if 60Hz)", transaction, ms_arranging, ms_waiting, ms_total, ms_total / (1000.0f / 60)); } @@ -251,7 +251,7 @@ static void transaction_progress_queue() { static int handle_timeout(void *data) { struct sway_transaction *transaction = data; - wlr_log(L_DEBUG, "Transaction %p timed out (%li waiting)", + wlr_log(WLR_DEBUG, "Transaction %p timed out (%li waiting)", transaction, transaction->num_waiting); transaction->num_waiting = 0; transaction_progress_queue(); @@ -286,7 +286,7 @@ static bool should_configure(struct sway_container *con, } void transaction_commit(struct sway_transaction *transaction) { - wlr_log(L_DEBUG, "Transaction %p committing with %i instructions", + wlr_log(WLR_DEBUG, "Transaction %p committing with %i instructions", transaction, transaction->instructions->length); transaction->num_waiting = 0; for (int i = 0; i < transaction->instructions->length; ++i) { @@ -319,7 +319,7 @@ void transaction_commit(struct sway_transaction *transaction) { } else { // There are no other transactions in progress, and this one has nothing // to wait for, so we can skip the queue. - wlr_log(L_DEBUG, "Transaction %p has nothing to wait for", transaction); + wlr_log(WLR_DEBUG, "Transaction %p has nothing to wait for", transaction); transaction_apply(transaction); transaction_destroy(transaction); idle_inhibit_v1_check_active(server.idle_inhibit_manager_v1); @@ -350,7 +350,7 @@ static void set_instruction_ready( struct timespec *start = &transaction->commit_time; float ms = (now.tv_sec - start->tv_sec) * 1000 + (now.tv_nsec - start->tv_nsec) / 1000000.0; - wlr_log(L_DEBUG, "Transaction %p: %li/%li ready in %.1fms (%s)", + wlr_log(WLR_DEBUG, "Transaction %p: %li/%li ready in %.1fms (%s)", transaction, transaction->num_configures - transaction->num_waiting + 1, transaction->num_configures, ms, @@ -362,7 +362,7 @@ static void set_instruction_ready( // If the transaction has timed out then its num_waiting will be 0 already. if (transaction->num_waiting > 0 && --transaction->num_waiting == 0) { #if !TRANSACTION_DEBUG - wlr_log(L_DEBUG, "Transaction %p is ready", transaction); + wlr_log(WLR_DEBUG, "Transaction %p is ready", transaction); wl_event_source_timer_update(transaction->timer, 0); transaction_progress_queue(); #endif diff --git a/sway/desktop/xdg_shell.c b/sway/desktop/xdg_shell.c index ac35a8d1..be14adbe 100644 --- a/sway/desktop/xdg_shell.c +++ b/sway/desktop/xdg_shell.c @@ -304,11 +304,11 @@ void handle_xdg_shell_surface(struct wl_listener *listener, void *data) { struct wlr_xdg_surface *xdg_surface = data; if (xdg_surface->role == WLR_XDG_SURFACE_ROLE_POPUP) { - wlr_log(L_DEBUG, "New xdg_shell popup"); + wlr_log(WLR_DEBUG, "New xdg_shell popup"); return; } - wlr_log(L_DEBUG, "New xdg_shell toplevel title='%s' app_id='%s'", + wlr_log(WLR_DEBUG, "New xdg_shell toplevel title='%s' app_id='%s'", xdg_surface->toplevel->title, xdg_surface->toplevel->app_id); wlr_xdg_surface_ping(xdg_surface); diff --git a/sway/desktop/xdg_shell_v6.c b/sway/desktop/xdg_shell_v6.c index 56bbb244..f5cf085a 100644 --- a/sway/desktop/xdg_shell_v6.c +++ b/sway/desktop/xdg_shell_v6.c @@ -295,11 +295,11 @@ void handle_xdg_shell_v6_surface(struct wl_listener *listener, void *data) { struct wlr_xdg_surface_v6 *xdg_surface = data; if (xdg_surface->role == WLR_XDG_SURFACE_V6_ROLE_POPUP) { - wlr_log(L_DEBUG, "New xdg_shell_v6 popup"); + wlr_log(WLR_DEBUG, "New xdg_shell_v6 popup"); return; } - wlr_log(L_DEBUG, "New xdg_shell_v6 toplevel title='%s' app_id='%s'", + wlr_log(WLR_DEBUG, "New xdg_shell_v6 toplevel title='%s' app_id='%s'", xdg_surface->toplevel->title, xdg_surface->toplevel->app_id); wlr_xdg_surface_v6_ping(xdg_surface); diff --git a/sway/desktop/xwayland.c b/sway/desktop/xwayland.c index b2874cfe..4e5cea7d 100644 --- a/sway/desktop/xwayland.c +++ b/sway/desktop/xwayland.c @@ -119,7 +119,7 @@ static struct sway_xwayland_unmanaged *create_unmanaged( struct sway_xwayland_unmanaged *surface = calloc(1, sizeof(struct sway_xwayland_unmanaged)); if (surface == NULL) { - wlr_log(L_ERROR, "Allocation failed"); + wlr_log(WLR_ERROR, "Allocation failed"); return NULL; } @@ -432,12 +432,12 @@ void handle_xwayland_surface(struct wl_listener *listener, void *data) { if (wlr_xwayland_surface_is_unmanaged(xsurface) || xsurface->override_redirect) { - wlr_log(L_DEBUG, "New xwayland unmanaged surface"); + wlr_log(WLR_DEBUG, "New xwayland unmanaged surface"); create_unmanaged(xsurface); return; } - wlr_log(L_DEBUG, "New xwayland surface title='%s' class='%s'", + wlr_log(WLR_DEBUG, "New xwayland surface title='%s' class='%s'", xsurface->title, xsurface->class); struct sway_xwayland_view *xwayland_view = @@ -490,7 +490,7 @@ void handle_xwayland_ready(struct wl_listener *listener, void *data) { xcb_connection_t *xcb_conn = xcb_connect(NULL, NULL); int err = xcb_connection_has_error(xcb_conn); if (err) { - wlr_log(L_ERROR, "XCB connect failed: %d", err); + wlr_log(WLR_ERROR, "XCB connect failed: %d", err); return; } @@ -509,7 +509,7 @@ void handle_xwayland_ready(struct wl_listener *listener, void *data) { free(reply); if (error != NULL) { - wlr_log(L_ERROR, "could not resolve atom %s, X11 error code %d", + wlr_log(WLR_ERROR, "could not resolve atom %s, X11 error code %d", atom_map[i], error->error_code); free(error); break; -- cgit v1.2.3 From 89c25dd149c00aeb8bdad103878d34427fd016fa Mon Sep 17 00:00:00 2001 From: russ morris Date: Tue, 10 Jul 2018 17:59:00 -0700 Subject: fix tabbed titlebar widths --- sway/desktop/render.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'sway/desktop') diff --git a/sway/desktop/render.c b/sway/desktop/render.c index f554b813..c4646a26 100644 --- a/sway/desktop/render.c +++ b/sway/desktop/render.c @@ -599,7 +599,8 @@ static void render_container_tabbed(struct sway_output *output, struct border_colors *current_colors = &config->border_colors.unfocused; struct sway_container_state *pstate = &con->current; - int tab_width = pstate->swayc_width / pstate->children->length; + double width_gap_adjustment = 2 * pstate->current_gaps; + int tab_width = (pstate->swayc_width - width_gap_adjustment) / pstate->children->length; // Render tabs for (int i = 0; i < pstate->children->length; ++i) { @@ -628,7 +629,7 @@ static void render_container_tabbed(struct sway_output *output, // Make last tab use the remaining width of the parent if (i == pstate->children->length - 1) { - tab_width = pstate->swayc_width - tab_width * i; + tab_width = (pstate->swayc_width - width_gap_adjustment) - tab_width * i; } render_titlebar(output, damage, child, x, cstate->swayc_y, tab_width, -- cgit v1.2.3 From b9d8ecc548e7ed6467660aa4a4cd658c702955b9 Mon Sep 17 00:00:00 2001 From: russ morris Date: Tue, 10 Jul 2018 20:24:57 -0700 Subject: tabs instead of spaces --- sway/desktop/render.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sway/desktop') diff --git a/sway/desktop/render.c b/sway/desktop/render.c index c4646a26..9ebbe9f3 100644 --- a/sway/desktop/render.c +++ b/sway/desktop/render.c @@ -599,7 +599,7 @@ static void render_container_tabbed(struct sway_output *output, struct border_colors *current_colors = &config->border_colors.unfocused; struct sway_container_state *pstate = &con->current; - double width_gap_adjustment = 2 * pstate->current_gaps; + double width_gap_adjustment = 2 * pstate->current_gaps; int tab_width = (pstate->swayc_width - width_gap_adjustment) / pstate->children->length; // Render tabs -- cgit v1.2.3 From c06266e12d2eb14e54da665b966dd1f7618dd123 Mon Sep 17 00:00:00 2001 From: russ morris Date: Tue, 10 Jul 2018 20:34:51 -0700 Subject: fix line lengths --- sway/desktop/render.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'sway/desktop') diff --git a/sway/desktop/render.c b/sway/desktop/render.c index 9ebbe9f3..5aec49b5 100644 --- a/sway/desktop/render.c +++ b/sway/desktop/render.c @@ -600,7 +600,8 @@ static void render_container_tabbed(struct sway_output *output, struct sway_container_state *pstate = &con->current; double width_gap_adjustment = 2 * pstate->current_gaps; - int tab_width = (pstate->swayc_width - width_gap_adjustment) / pstate->children->length; + int tab_width = + (pstate->swayc_width - width_gap_adjustment) / pstate->children->length; // Render tabs for (int i = 0; i < pstate->children->length; ++i) { @@ -629,7 +630,8 @@ static void render_container_tabbed(struct sway_output *output, // Make last tab use the remaining width of the parent if (i == pstate->children->length - 1) { - tab_width = (pstate->swayc_width - width_gap_adjustment) - tab_width * i; + tab_width = + (pstate->swayc_width - width_gap_adjustment) - tab_width * i; } render_titlebar(output, damage, child, x, cstate->swayc_y, tab_width, -- cgit v1.2.3 From 6ae1004cd16096fec1e94e26eb42b5251ab46ebb Mon Sep 17 00:00:00 2001 From: russ morris Date: Tue, 10 Jul 2018 20:57:05 -0700 Subject: removed unnecessary parens --- sway/desktop/render.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sway/desktop') diff --git a/sway/desktop/render.c b/sway/desktop/render.c index 5aec49b5..28c81942 100644 --- a/sway/desktop/render.c +++ b/sway/desktop/render.c @@ -631,7 +631,7 @@ static void render_container_tabbed(struct sway_output *output, // Make last tab use the remaining width of the parent if (i == pstate->children->length - 1) { tab_width = - (pstate->swayc_width - width_gap_adjustment) - tab_width * i; + pstate->swayc_width - width_gap_adjustment - tab_width * i; } render_titlebar(output, damage, child, x, cstate->swayc_y, tab_width, -- cgit v1.2.3 From 3b50a2a3af985d61256b716f53b035fb94bafd7c Mon Sep 17 00:00:00 2001 From: Ryan Dwyer Date: Wed, 11 Jul 2018 20:33:36 +1000 Subject: Use saved buffer when fullscreen view is in a transaction Fixes #2237. --- sway/desktop/render.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'sway/desktop') diff --git a/sway/desktop/render.c b/sway/desktop/render.c index 28c81942..b370f8a2 100644 --- a/sway/desktop/render.c +++ b/sway/desktop/render.c @@ -844,7 +844,11 @@ void output_render(struct sway_output *output, struct timespec *when, } // TODO: handle views smaller than the output - render_view_surfaces(fullscreen_view, output, damage, 1.0f); + if (fullscreen_view->swayc->instructions->length) { + render_saved_view(fullscreen_view, output, damage, 1.0f); + } else { + render_view_surfaces(fullscreen_view, output, damage, 1.0f); + } if (fullscreen_view->type == SWAY_VIEW_XWAYLAND) { render_unmanaged(output, damage, -- cgit v1.2.3 From 9b16227ec3cfc648f177f186d29b9f0002b7bbde Mon Sep 17 00:00:00 2001 From: emersion Date: Thu, 12 Jul 2018 20:01:33 +0100 Subject: Don't disable borders for xwayland floating views --- sway/desktop/xwayland.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'sway/desktop') diff --git a/sway/desktop/xwayland.c b/sway/desktop/xwayland.c index 4e5cea7d..460d1cc8 100644 --- a/sway/desktop/xwayland.c +++ b/sway/desktop/xwayland.c @@ -246,6 +246,14 @@ static bool wants_floating(struct sway_view *view) { return false; } +static bool has_client_side_decorations(struct sway_view *view) { + if (xwayland_view_from_view(view) == NULL) { + return false; + } + struct wlr_xwayland_surface *surface = view->wlr_xwayland_surface; + return surface->decorations != WLR_XWAYLAND_SURFACE_DECORATIONS_ALL; +} + static void _close(struct sway_view *view) { if (xwayland_view_from_view(view) == NULL) { return; @@ -269,6 +277,7 @@ static const struct sway_view_impl view_impl = { .set_tiled = set_tiled, .set_fullscreen = set_fullscreen, .wants_floating = wants_floating, + .has_client_side_decorations = has_client_side_decorations, .close = _close, .destroy = destroy, }; -- cgit v1.2.3 From a96f1c22fe92a46ea0242fa63e8c8cc2bbd09c3f Mon Sep 17 00:00:00 2001 From: emersion Date: Thu, 12 Jul 2018 20:30:10 +0100 Subject: Add xdg-positioner support --- sway/desktop/xdg_shell.c | 50 +++++++++++++++++++++++++++++++++++++++++++++ sway/desktop/xdg_shell_v6.c | 50 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 100 insertions(+) (limited to 'sway/desktop') diff --git a/sway/desktop/xdg_shell.c b/sway/desktop/xdg_shell.c index be14adbe..17b7b750 100644 --- a/sway/desktop/xdg_shell.c +++ b/sway/desktop/xdg_shell.c @@ -45,6 +45,53 @@ static void popup_handle_destroy(struct wl_listener *listener, void *data) { view_child_destroy(&popup->child); } +static void popup_unconstrain(struct sway_xdg_popup *popup) { + // get the output of the popup's positioner anchor point and convert it to + // the toplevel parent's coordinate system and then pass it to + // wlr_xdg_popup_unconstrain_from_box + + struct sway_view *view = popup->child.view; + struct wlr_output_layout *output_layout = + root_container.sway_root->output_layout; + struct wlr_xdg_popup *wlr_popup = popup->wlr_xdg_surface->popup; + + int anchor_lx, anchor_ly; + wlr_xdg_popup_get_anchor_point(wlr_popup, &anchor_lx, &anchor_ly); + + int popup_lx, popup_ly; + wlr_xdg_popup_get_toplevel_coords(wlr_popup, wlr_popup->geometry.x, + wlr_popup->geometry.y, &popup_lx, &popup_ly); + popup_lx += view->x; + popup_ly += view->y; + + anchor_lx += popup_lx; + anchor_ly += popup_ly; + + double dest_x = 0, dest_y = 0; + wlr_output_layout_closest_point(output_layout, NULL, anchor_lx, anchor_ly, + &dest_x, &dest_y); + + struct wlr_output *output = + wlr_output_layout_output_at(output_layout, dest_x, dest_y); + if (output == NULL) { + return; + } + + int width = 0, height = 0; + wlr_output_effective_resolution(output, &width, &height); + + // the output box expressed in the coordinate system of the toplevel parent + // of the popup + struct wlr_box output_toplevel_sx_box = { + .x = output->lx - view->x, + .y = output->ly - view->y, + .width = width, + .height = height + }; + + wlr_xdg_popup_unconstrain_from_box(wlr_popup, &output_toplevel_sx_box); +} + static struct sway_xdg_popup *popup_create( struct wlr_xdg_popup *wlr_popup, struct sway_view *view) { struct wlr_xdg_surface *xdg_surface = wlr_popup->base; @@ -55,12 +102,15 @@ static struct sway_xdg_popup *popup_create( return NULL; } view_child_init(&popup->child, &popup_impl, view, xdg_surface->surface); + popup->wlr_xdg_surface = xdg_surface; wl_signal_add(&xdg_surface->events.new_popup, &popup->new_popup); popup->new_popup.notify = popup_handle_new_popup; wl_signal_add(&xdg_surface->events.destroy, &popup->destroy); popup->destroy.notify = popup_handle_destroy; + popup_unconstrain(popup); + return popup; } diff --git a/sway/desktop/xdg_shell_v6.c b/sway/desktop/xdg_shell_v6.c index f5cf085a..43e58918 100644 --- a/sway/desktop/xdg_shell_v6.c +++ b/sway/desktop/xdg_shell_v6.c @@ -44,6 +44,53 @@ static void popup_handle_destroy(struct wl_listener *listener, void *data) { view_child_destroy(&popup->child); } +static void popup_unconstrain(struct sway_xdg_popup_v6 *popup) { + // get the output of the popup's positioner anchor point and convert it to + // the toplevel parent's coordinate system and then pass it to + // wlr_xdg_popup_unconstrain_from_box + + struct sway_view *view = popup->child.view; + struct wlr_output_layout *output_layout = + root_container.sway_root->output_layout; + struct wlr_xdg_popup_v6 *wlr_popup = popup->wlr_xdg_surface_v6->popup; + + int anchor_lx, anchor_ly; + wlr_xdg_popup_v6_get_anchor_point(wlr_popup, &anchor_lx, &anchor_ly); + + int popup_lx, popup_ly; + wlr_xdg_popup_v6_get_toplevel_coords(wlr_popup, wlr_popup->geometry.x, + wlr_popup->geometry.y, &popup_lx, &popup_ly); + popup_lx += view->x; + popup_ly += view->y; + + anchor_lx += popup_lx; + anchor_ly += popup_ly; + + double dest_x = 0, dest_y = 0; + wlr_output_layout_closest_point(output_layout, NULL, anchor_lx, anchor_ly, + &dest_x, &dest_y); + + struct wlr_output *output = + wlr_output_layout_output_at(output_layout, dest_x, dest_y); + if (output == NULL) { + return; + } + + int width = 0, height = 0; + wlr_output_effective_resolution(output, &width, &height); + + // the output box expressed in the coordinate system of the toplevel parent + // of the popup + struct wlr_box output_toplevel_sx_box = { + .x = output->lx - view->x, + .y = output->ly - view->y, + .width = width, + .height = height + }; + + wlr_xdg_popup_v6_unconstrain_from_box(wlr_popup, &output_toplevel_sx_box); +} + static struct sway_xdg_popup_v6 *popup_create( struct wlr_xdg_popup_v6 *wlr_popup, struct sway_view *view) { struct wlr_xdg_surface_v6 *xdg_surface = wlr_popup->base; @@ -54,12 +101,15 @@ static struct sway_xdg_popup_v6 *popup_create( return NULL; } view_child_init(&popup->child, &popup_impl, view, xdg_surface->surface); + popup->wlr_xdg_surface_v6 = xdg_surface; wl_signal_add(&xdg_surface->events.new_popup, &popup->new_popup); popup->new_popup.notify = popup_handle_new_popup; wl_signal_add(&xdg_surface->events.destroy, &popup->destroy); popup->destroy.notify = popup_handle_destroy; + popup_unconstrain(popup); + return popup; } -- cgit v1.2.3 From d88f1d2196702ba35f47d6b2ce5de2d1f1d9f15a Mon Sep 17 00:00:00 2001 From: emersion Date: Fri, 13 Jul 2018 12:26:20 +0100 Subject: Fix output_has_opaque_lockscreen --- sway/desktop/output.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'sway/desktop') diff --git a/sway/desktop/output.c b/sway/desktop/output.c index 73108450..a2720885 100644 --- a/sway/desktop/output.c +++ b/sway/desktop/output.c @@ -204,11 +204,11 @@ bool output_has_opaque_lockscreen(struct sway_output *output, }; pixman_region32_t surface_opaque_box; pixman_region32_init(&surface_opaque_box); - pixman_region32_copy(&surface_opaque_box, &wlr_surface->current.opaque); + pixman_region32_copy(&surface_opaque_box, &wlr_surface->opaque_region); pixman_region32_translate(&surface_opaque_box, - sway_layer_surface->geo.x, sway_layer_surface->geo.y); - bool contains = pixman_region32_contains_rectangle( - &wlr_surface->current.opaque, &output_box); + sway_layer_surface->geo.x, sway_layer_surface->geo.y); + bool contains = pixman_region32_contains_rectangle(&surface_opaque_box, + &output_box); pixman_region32_fini(&surface_opaque_box); if (contains) { return true; -- cgit v1.2.3 From efda33b28568f2065c2a995d0a05a497b7d33e91 Mon Sep 17 00:00:00 2001 From: emersion Date: Fri, 13 Jul 2018 21:17:31 +0100 Subject: Simplify popup_unconstrain Just use the parent output. --- sway/desktop/xdg_shell.c | 39 +++++---------------------------------- sway/desktop/xdg_shell_v6.c | 39 +++++---------------------------------- 2 files changed, 10 insertions(+), 68 deletions(-) (limited to 'sway/desktop') diff --git a/sway/desktop/xdg_shell.c b/sway/desktop/xdg_shell.c index 17b7b750..fbeeb2e3 100644 --- a/sway/desktop/xdg_shell.c +++ b/sway/desktop/xdg_shell.c @@ -46,47 +46,18 @@ static void popup_handle_destroy(struct wl_listener *listener, void *data) { } static void popup_unconstrain(struct sway_xdg_popup *popup) { - // get the output of the popup's positioner anchor point and convert it to - // the toplevel parent's coordinate system and then pass it to - // wlr_xdg_popup_unconstrain_from_box - struct sway_view *view = popup->child.view; - struct wlr_output_layout *output_layout = - root_container.sway_root->output_layout; struct wlr_xdg_popup *wlr_popup = popup->wlr_xdg_surface->popup; - int anchor_lx, anchor_ly; - wlr_xdg_popup_get_anchor_point(wlr_popup, &anchor_lx, &anchor_ly); - - int popup_lx, popup_ly; - wlr_xdg_popup_get_toplevel_coords(wlr_popup, wlr_popup->geometry.x, - wlr_popup->geometry.y, &popup_lx, &popup_ly); - popup_lx += view->x; - popup_ly += view->y; - - anchor_lx += popup_lx; - anchor_ly += popup_ly; - - double dest_x = 0, dest_y = 0; - wlr_output_layout_closest_point(output_layout, NULL, anchor_lx, anchor_ly, - &dest_x, &dest_y); - - struct wlr_output *output = - wlr_output_layout_output_at(output_layout, dest_x, dest_y); - if (output == NULL) { - return; - } - - int width = 0, height = 0; - wlr_output_effective_resolution(output, &width, &height); + struct sway_container *output = container_parent(view->swayc, C_OUTPUT); // the output box expressed in the coordinate system of the toplevel parent // of the popup struct wlr_box output_toplevel_sx_box = { - .x = output->lx - view->x, - .y = output->ly - view->y, - .width = width, - .height = height + .x = output->x - view->x, + .y = output->y - view->y, + .width = output->width, + .height = output->height, }; wlr_xdg_popup_unconstrain_from_box(wlr_popup, &output_toplevel_sx_box); diff --git a/sway/desktop/xdg_shell_v6.c b/sway/desktop/xdg_shell_v6.c index 43e58918..88d9bb94 100644 --- a/sway/desktop/xdg_shell_v6.c +++ b/sway/desktop/xdg_shell_v6.c @@ -45,47 +45,18 @@ static void popup_handle_destroy(struct wl_listener *listener, void *data) { } static void popup_unconstrain(struct sway_xdg_popup_v6 *popup) { - // get the output of the popup's positioner anchor point and convert it to - // the toplevel parent's coordinate system and then pass it to - // wlr_xdg_popup_unconstrain_from_box - struct sway_view *view = popup->child.view; - struct wlr_output_layout *output_layout = - root_container.sway_root->output_layout; struct wlr_xdg_popup_v6 *wlr_popup = popup->wlr_xdg_surface_v6->popup; - int anchor_lx, anchor_ly; - wlr_xdg_popup_v6_get_anchor_point(wlr_popup, &anchor_lx, &anchor_ly); - - int popup_lx, popup_ly; - wlr_xdg_popup_v6_get_toplevel_coords(wlr_popup, wlr_popup->geometry.x, - wlr_popup->geometry.y, &popup_lx, &popup_ly); - popup_lx += view->x; - popup_ly += view->y; - - anchor_lx += popup_lx; - anchor_ly += popup_ly; - - double dest_x = 0, dest_y = 0; - wlr_output_layout_closest_point(output_layout, NULL, anchor_lx, anchor_ly, - &dest_x, &dest_y); - - struct wlr_output *output = - wlr_output_layout_output_at(output_layout, dest_x, dest_y); - if (output == NULL) { - return; - } - - int width = 0, height = 0; - wlr_output_effective_resolution(output, &width, &height); + struct sway_container *output = container_parent(view->swayc, C_OUTPUT); // the output box expressed in the coordinate system of the toplevel parent // of the popup struct wlr_box output_toplevel_sx_box = { - .x = output->lx - view->x, - .y = output->ly - view->y, - .width = width, - .height = height + .x = output->x - view->x, + .y = output->y - view->y, + .width = output->width, + .height = output->height, }; wlr_xdg_popup_v6_unconstrain_from_box(wlr_popup, &output_toplevel_sx_box); -- cgit v1.2.3 From 2032f85d94f2f222282b242116b3e827dd458f6c Mon Sep 17 00:00:00 2001 From: Ryan Dwyer Date: Sat, 14 Jul 2018 23:14:55 +1000 Subject: Simplify transactions by utilising a dirty flag on containers This PR changes the way we handle transactions to a more simple method. The new method is to mark containers as dirty from low level code (eg. arranging, or container_destroy, and eventually seat_set_focus), then call transaction_commit_dirty which picks up those containers and runs them through a transaction. The old methods of using transactions (arrange_and_commit, or creating one manually) are now no longer possible. The highest-level code (execute_command and view implementation handlers) will call transaction_commit_dirty, so most other code just needs to set containers as dirty. This is done by arranging, but can also be done by calling container_set_dirty. --- sway/desktop/layer_shell.c | 3 +-- sway/desktop/output.c | 14 +++++++++----- sway/desktop/transaction.c | 35 +++++++++++++++++------------------ sway/desktop/xdg_shell.c | 8 +++++--- sway/desktop/xdg_shell_v6.c | 8 +++++--- sway/desktop/xwayland.c | 8 +++++--- 6 files changed, 42 insertions(+), 34 deletions(-) (limited to 'sway/desktop') diff --git a/sway/desktop/layer_shell.c b/sway/desktop/layer_shell.c index 16910c7e..91baa6f8 100644 --- a/sway/desktop/layer_shell.c +++ b/sway/desktop/layer_shell.c @@ -12,7 +12,6 @@ #include "sway/layers.h" #include "sway/output.h" #include "sway/server.h" -#include "sway/tree/arrange.h" #include "sway/tree/layout.h" #include "log.h" @@ -176,7 +175,7 @@ void arrange_layers(struct sway_output *output) { sizeof(struct wlr_box)) != 0) { wlr_log(WLR_DEBUG, "Usable area changed, rearranging output"); memcpy(&output->usable_area, &usable_area, sizeof(struct wlr_box)); - arrange_and_commit(output->swayc); + container_set_dirty(output->swayc); } // Arrange non-exlusive surfaces from top->bottom diff --git a/sway/desktop/output.c b/sway/desktop/output.c index a2720885..a9808406 100644 --- a/sway/desktop/output.c +++ b/sway/desktop/output.c @@ -492,19 +492,21 @@ static void handle_destroy(struct wl_listener *listener, void *data) { output->wlr_output->data = NULL; free(output); - arrange_and_commit(&root_container); + arrange_windows(&root_container); } static void handle_mode(struct wl_listener *listener, void *data) { struct sway_output *output = wl_container_of(listener, output, mode); arrange_layers(output); - arrange_and_commit(output->swayc); + arrange_windows(output->swayc); + transaction_commit_dirty(); } static void handle_transform(struct wl_listener *listener, void *data) { struct sway_output *output = wl_container_of(listener, output, transform); arrange_layers(output); - arrange_and_commit(output->swayc); + arrange_windows(output->swayc); + transaction_commit_dirty(); } static void handle_scale_iterator(struct sway_container *view, void *data) { @@ -515,7 +517,8 @@ static void handle_scale(struct wl_listener *listener, void *data) { struct sway_output *output = wl_container_of(listener, output, scale); arrange_layers(output); container_descendants(output->swayc, C_VIEW, handle_scale_iterator, NULL); - arrange_and_commit(output->swayc); + arrange_windows(output->swayc); + transaction_commit_dirty(); } struct sway_output *output_from_wlr_output(struct wlr_output *wlr_output) { @@ -584,5 +587,6 @@ void output_enable(struct sway_output *output) { output->damage_destroy.notify = damage_handle_destroy; arrange_layers(output); - arrange_and_commit(&root_container); + arrange_windows(&root_container); + transaction_commit_dirty(); } diff --git a/sway/desktop/transaction.c b/sway/desktop/transaction.c index 2b3f87c3..d7ef7130 100644 --- a/sway/desktop/transaction.c +++ b/sway/desktop/transaction.c @@ -47,7 +47,7 @@ struct sway_transaction_instruction { bool ready; }; -struct sway_transaction *transaction_create() { +static struct sway_transaction *transaction_create() { struct sway_transaction *transaction = calloc(1, sizeof(struct sway_transaction)); transaction->instructions = create_list(); @@ -141,23 +141,8 @@ static void copy_pending_state(struct sway_container *container, } } -static bool transaction_has_container(struct sway_transaction *transaction, +static void transaction_add_container(struct sway_transaction *transaction, struct sway_container *container) { - for (int i = 0; i < transaction->instructions->length; ++i) { - struct sway_transaction_instruction *instruction = - transaction->instructions->items[i]; - if (instruction->container == container) { - return true; - } - } - return false; -} - -void transaction_add_container(struct sway_transaction *transaction, - struct sway_container *container) { - if (transaction_has_container(transaction, container)) { - return; - } struct sway_transaction_instruction *instruction = calloc(1, sizeof(struct sway_transaction_instruction)); instruction->transaction = transaction; @@ -285,7 +270,7 @@ static bool should_configure(struct sway_container *con, return true; } -void transaction_commit(struct sway_transaction *transaction) { +static void transaction_commit(struct sway_transaction *transaction) { wlr_log(WLR_DEBUG, "Transaction %p committing with %i instructions", transaction, transaction->instructions->length); transaction->num_waiting = 0; @@ -418,3 +403,17 @@ struct wlr_texture *transaction_get_saved_texture(struct sway_view *view, *height = instruction->saved_buffer_height; return instruction->saved_buffer->texture; } + +void transaction_commit_dirty() { + if (!server.dirty_containers->length) { + return; + } + struct sway_transaction *transaction = transaction_create(); + for (int i = 0; i < server.dirty_containers->length; ++i) { + struct sway_container *container = server.dirty_containers->items[i]; + transaction_add_container(transaction, container); + container->dirty = false; + } + server.dirty_containers->length = 0; + transaction_commit(transaction); +} diff --git a/sway/desktop/xdg_shell.c b/sway/desktop/xdg_shell.c index fbeeb2e3..98c16faf 100644 --- a/sway/desktop/xdg_shell.c +++ b/sway/desktop/xdg_shell.c @@ -244,7 +244,8 @@ static void handle_request_fullscreen(struct wl_listener *listener, void *data) view_set_fullscreen(view, e->fullscreen); struct sway_container *output = container_parent(view->swayc, C_OUTPUT); - arrange_and_commit(output); + arrange_windows(output); + transaction_commit_dirty(); } static void handle_unmap(struct wl_listener *listener, void *data) { @@ -281,10 +282,11 @@ static void handle_map(struct wl_listener *listener, void *data) { if (xdg_surface->toplevel->client_pending.fullscreen) { view_set_fullscreen(view, true); struct sway_container *ws = container_parent(view->swayc, C_WORKSPACE); - arrange_and_commit(ws); + arrange_windows(ws); } else { - arrange_and_commit(view->swayc->parent); + arrange_windows(view->swayc->parent); } + transaction_commit_dirty(); xdg_shell_view->commit.notify = handle_commit; wl_signal_add(&xdg_surface->surface->events.commit, diff --git a/sway/desktop/xdg_shell_v6.c b/sway/desktop/xdg_shell_v6.c index 88d9bb94..4d76f0a7 100644 --- a/sway/desktop/xdg_shell_v6.c +++ b/sway/desktop/xdg_shell_v6.c @@ -239,7 +239,8 @@ static void handle_request_fullscreen(struct wl_listener *listener, void *data) view_set_fullscreen(view, e->fullscreen); struct sway_container *output = container_parent(view->swayc, C_OUTPUT); - arrange_and_commit(output); + arrange_windows(output); + transaction_commit_dirty(); } static void handle_unmap(struct wl_listener *listener, void *data) { @@ -276,10 +277,11 @@ static void handle_map(struct wl_listener *listener, void *data) { if (xdg_surface->toplevel->client_pending.fullscreen) { view_set_fullscreen(view, true); struct sway_container *ws = container_parent(view->swayc, C_WORKSPACE); - arrange_and_commit(ws); + arrange_windows(ws); } else { - arrange_and_commit(view->swayc->parent); + arrange_windows(view->swayc->parent); } + transaction_commit_dirty(); xdg_shell_v6_view->commit.notify = handle_commit; wl_signal_add(&xdg_surface->surface->events.commit, diff --git a/sway/desktop/xwayland.c b/sway/desktop/xwayland.c index 460d1cc8..11516673 100644 --- a/sway/desktop/xwayland.c +++ b/sway/desktop/xwayland.c @@ -333,10 +333,11 @@ static void handle_map(struct wl_listener *listener, void *data) { if (xsurface->fullscreen) { view_set_fullscreen(view, true); struct sway_container *ws = container_parent(view->swayc, C_WORKSPACE); - arrange_and_commit(ws); + arrange_windows(ws); } else { - arrange_and_commit(view->swayc->parent); + arrange_windows(view->swayc->parent); } + transaction_commit_dirty(); } static void handle_destroy(struct wl_listener *listener, void *data) { @@ -392,7 +393,8 @@ static void handle_request_fullscreen(struct wl_listener *listener, void *data) view_set_fullscreen(view, xsurface->fullscreen); struct sway_container *output = container_parent(view->swayc, C_OUTPUT); - arrange_and_commit(output); + arrange_windows(output); + transaction_commit_dirty(); } static void handle_set_title(struct wl_listener *listener, void *data) { -- cgit v1.2.3 From 6b2dc7e63b3a602b29c47e3b70bc7890c063dcf4 Mon Sep 17 00:00:00 2001 From: Ryan Dwyer Date: Sun, 15 Jul 2018 10:41:10 +1000 Subject: Set signature to void --- sway/desktop/transaction.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sway/desktop') diff --git a/sway/desktop/transaction.c b/sway/desktop/transaction.c index d7ef7130..e8222b32 100644 --- a/sway/desktop/transaction.c +++ b/sway/desktop/transaction.c @@ -404,7 +404,7 @@ struct wlr_texture *transaction_get_saved_texture(struct sway_view *view, return instruction->saved_buffer->texture; } -void transaction_commit_dirty() { +void transaction_commit_dirty(void) { if (!server.dirty_containers->length) { return; } -- cgit v1.2.3 From b1afcc69fa70c20d815940fc25189063ed59ae0f Mon Sep 17 00:00:00 2001 From: Drew DeVault Date: Sat, 14 Jul 2018 11:24:22 -0400 Subject: Add extended debugging flags We currently have several ways of setting debug flags, including command line arguments, environment variables, and compile-time macros. This replaces the lot with command line flags. --- sway/desktop/render.c | 4 +++- sway/desktop/transaction.c | 16 ++++++++-------- 2 files changed, 11 insertions(+), 9 deletions(-) (limited to 'sway/desktop') diff --git a/sway/desktop/render.c b/sway/desktop/render.c index b370f8a2..4bfc573b 100644 --- a/sway/desktop/render.c +++ b/sway/desktop/render.c @@ -15,6 +15,7 @@ #include #include "log.h" #include "sway/config.h" +#include "sway/debug.h" #include "sway/input/input-manager.h" #include "sway/input/seat.h" #include "sway/layers.h" @@ -786,6 +787,8 @@ static void render_floating(struct sway_output *soutput, } } +const char *damage_debug = NULL; + void output_render(struct sway_output *output, struct timespec *when, pixman_region32_t *damage) { struct wlr_output *wlr_output = output->wlr_output; @@ -805,7 +808,6 @@ void output_render(struct sway_output *output, struct timespec *when, goto renderer_end; } - const char *damage_debug = getenv("SWAY_DAMAGE_DEBUG"); if (damage_debug != NULL) { if (strcmp(damage_debug, "highlight") == 0) { wlr_renderer_clear(renderer, (float[]){1, 1, 0, 1}); diff --git a/sway/desktop/transaction.c b/sway/desktop/transaction.c index 2b3f87c3..5e42fde5 100644 --- a/sway/desktop/transaction.c +++ b/sway/desktop/transaction.c @@ -19,14 +19,14 @@ * How long we should wait for views to respond to the configure before giving * up and applying the transaction anyway. */ -#define TIMEOUT_MS 200 +int txn_timeout_ms = 200; /** * If enabled, sway will always wait for the transaction timeout before * applying it, rather than applying it when the views are ready. This allows us * to observe the rendered state while a transaction is in progress. */ -#define TRANSACTION_DEBUG false +bool txn_debug = false; struct sway_transaction { struct wl_event_source *timer; @@ -330,7 +330,7 @@ void transaction_commit(struct sway_transaction *transaction) { // Set up a timer which the views must respond within transaction->timer = wl_event_loop_add_timer(server.wl_event_loop, handle_timeout, transaction); - wl_event_source_timer_update(transaction->timer, TIMEOUT_MS); + wl_event_source_timer_update(transaction->timer, txn_timeout_ms); } // The debug tree shows the pending/live tree. Here is a good place to @@ -361,11 +361,11 @@ static void set_instruction_ready( // If all views are ready, apply the transaction. // If the transaction has timed out then its num_waiting will be 0 already. if (transaction->num_waiting > 0 && --transaction->num_waiting == 0) { -#if !TRANSACTION_DEBUG - wlr_log(WLR_DEBUG, "Transaction %p is ready", transaction); - wl_event_source_timer_update(transaction->timer, 0); - transaction_progress_queue(); -#endif + if (!txn_debug) { + wlr_log(WLR_DEBUG, "Transaction %p is ready", transaction); + wl_event_source_timer_update(transaction->timer, 0); + transaction_progress_queue(); + } } } -- cgit v1.2.3 From a120d4c79f9406a2f7cc38c60069d3183c98ea87 Mon Sep 17 00:00:00 2001 From: Ryan Dwyer Date: Sun, 15 Jul 2018 15:20:21 +1000 Subject: Make focus part of transactions Rather than maintain copies of the entire focus stack, this PR transactionises the focus by introducing two new properties to the container state and using those when rendering. * `bool focused` means this container has actual focus. Only one container should have this equalling true in its current state. * `struct sway_container *focus_inactive_child` points to the immediate child that was most recently focused (eg. for tabbed and stacked containers). --- sway/desktop/render.c | 61 +++++++++++++++++----------------------------- sway/desktop/transaction.c | 18 +++++++++++--- 2 files changed, 37 insertions(+), 42 deletions(-) (limited to 'sway/desktop') diff --git a/sway/desktop/render.c b/sway/desktop/render.c index 4bfc573b..17fe823a 100644 --- a/sway/desktop/render.c +++ b/sway/desktop/render.c @@ -543,9 +543,6 @@ static void render_container(struct sway_output *output, static void render_container_simple(struct sway_output *output, pixman_region32_t *damage, struct sway_container *con, bool parent_focused) { - struct sway_seat *seat = input_manager_current_seat(input_manager); - struct sway_container *focus = seat_get_focus(seat); - for (int i = 0; i < con->current.children->length; ++i) { struct sway_container *child = con->current.children->items[i]; @@ -556,11 +553,11 @@ static void render_container_simple(struct sway_output *output, struct wlr_texture *marks_texture; struct sway_container_state *state = &child->current; - if (focus == child || parent_focused) { + if (state->focused || parent_focused) { colors = &config->border_colors.focused; title_texture = child->title_focused; marks_texture = view->marks_focused; - } else if (seat_get_focus_inactive(seat, con) == child) { + } else if (con->current.focused_inactive_child == child) { colors = &config->border_colors.focused_inactive; title_texture = child->title_focused_inactive; marks_texture = view->marks_focused_inactive; @@ -580,7 +577,7 @@ static void render_container_simple(struct sway_output *output, render_view(output, damage, child, colors); } else { render_container(output, damage, child, - parent_focused || focus == child); + parent_focused || child->current.focused); } } } @@ -594,11 +591,9 @@ static void render_container_tabbed(struct sway_output *output, if (!con->current.children->length) { return; } - struct sway_seat *seat = input_manager_current_seat(input_manager); - struct sway_container *focus = seat_get_focus(seat); - struct sway_container *current = seat_get_active_current_child(seat, con); - struct border_colors *current_colors = &config->border_colors.unfocused; struct sway_container_state *pstate = &con->current; + struct sway_container *current = pstate->focused_inactive_child; + struct border_colors *current_colors = &config->border_colors.unfocused; double width_gap_adjustment = 2 * pstate->current_gaps; int tab_width = @@ -613,11 +608,11 @@ static void render_container_tabbed(struct sway_output *output, struct wlr_texture *title_texture; struct wlr_texture *marks_texture; - if (focus == child || parent_focused) { + if (cstate->focused || parent_focused) { colors = &config->border_colors.focused; title_texture = child->title_focused; marks_texture = view ? view->marks_focused : NULL; - } else if (child == current) { + } else if (child == pstate->focused_inactive_child) { colors = &config->border_colors.focused_inactive; title_texture = child->title_focused_inactive; marks_texture = view ? view->marks_focused_inactive : NULL; @@ -644,13 +639,11 @@ static void render_container_tabbed(struct sway_output *output, } // Render surface and left/right/bottom borders - if (current) { - if (current->type == C_VIEW) { - render_view(output, damage, current, current_colors); - } else { - render_container(output, damage, current, - parent_focused || current == focus); - } + if (current->type == C_VIEW) { + render_view(output, damage, current, current_colors); + } else { + render_container(output, damage, current, + parent_focused || current->current.focused); } } @@ -663,11 +656,9 @@ static void render_container_stacked(struct sway_output *output, if (!con->current.children->length) { return; } - struct sway_seat *seat = input_manager_current_seat(input_manager); - struct sway_container *focus = seat_get_focus(seat); - struct sway_container *current = seat_get_active_current_child(seat, con); - struct border_colors *current_colors = &config->border_colors.unfocused; struct sway_container_state *pstate = &con->current; + struct sway_container *current = pstate->focused_inactive_child; + struct border_colors *current_colors = &config->border_colors.unfocused; size_t titlebar_height = container_titlebar_height(); @@ -680,11 +671,11 @@ static void render_container_stacked(struct sway_output *output, struct wlr_texture *title_texture; struct wlr_texture *marks_texture; - if (focus == child || parent_focused) { + if (cstate->focused || parent_focused) { colors = &config->border_colors.focused; title_texture = child->title_focused; marks_texture = view ? view->marks_focused : NULL; - } else if (child == current) { + } else if (child == pstate->focused_inactive_child) { colors = &config->border_colors.focused_inactive; title_texture = child->title_focused_inactive; marks_texture = view ? view->marks_focused_inactive : NULL; @@ -704,13 +695,11 @@ static void render_container_stacked(struct sway_output *output, } // Render surface and left/right/bottom borders - if (current) { - if (current->type == C_VIEW) { - render_view(output, damage, current, current_colors); - } else { - render_container(output, damage, current, - parent_focused || current == focus); - } + if (current->type == C_VIEW) { + render_view(output, damage, current, current_colors); + } else { + render_container(output, damage, current, + parent_focused || current->current.focused); } } @@ -738,13 +727,11 @@ static void render_floating_container(struct sway_output *soutput, pixman_region32_t *damage, struct sway_container *con) { if (con->type == C_VIEW) { struct sway_view *view = con->sway_view; - struct sway_seat *seat = input_manager_current_seat(input_manager); - struct sway_container *focus = seat_get_focus(seat); struct border_colors *colors; struct wlr_texture *title_texture; struct wlr_texture *marks_texture; - if (focus == con) { + if (con->current.focused) { colors = &config->border_colors.focused; title_texture = con->title_focused; marks_texture = view->marks_focused; @@ -871,9 +858,7 @@ void output_render(struct sway_output *output, struct timespec *when, render_layer(output, damage, &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM]); - struct sway_seat *seat = input_manager_current_seat(input_manager); - struct sway_container *focus = seat_get_focus(seat); - render_container(output, damage, workspace, focus == workspace); + render_container(output, damage, workspace, workspace->current.focused); render_floating(output, damage); render_unmanaged(output, damage, diff --git a/sway/desktop/transaction.c b/sway/desktop/transaction.c index 0ae042db..fcfb0b51 100644 --- a/sway/desktop/transaction.c +++ b/sway/desktop/transaction.c @@ -139,6 +139,14 @@ static void copy_pending_state(struct sway_container *container, state->children = create_list(); list_cat(state->children, container->children); } + + struct sway_seat *seat = input_manager_current_seat(input_manager); + state->focused = seat_get_focus(seat) == container; + + if (container->type != C_VIEW) { + state->focused_inactive_child = + seat_get_active_child(seat, container); + } } static void transaction_add_container(struct sway_transaction *transaction, @@ -195,10 +203,12 @@ static void transaction_apply(struct sway_transaction *transaction) { .width = instruction->state.swayc_width, .height = instruction->state.swayc_height, }; - for (int j = 0; j < root_container.children->length; ++j) { - struct sway_container *output = root_container.children->items[j]; - output_damage_box(output->sway_output, &old_box); - output_damage_box(output->sway_output, &new_box); + for (int j = 0; j < root_container.current.children->length; ++j) { + struct sway_container *output = root_container.current.children->items[j]; + if (output->sway_output) { + output_damage_box(output->sway_output, &old_box); + output_damage_box(output->sway_output, &new_box); + } } // There are separate children lists for each instruction state, the -- cgit v1.2.3 From 315d5311b2004b9e148e7b52a7de161b6dfe3878 Mon Sep 17 00:00:00 2001 From: Ryan Dwyer Date: Sun, 15 Jul 2018 22:43:33 +1000 Subject: Implement urgency base functionality Introduces a command to manually set urgency, as well as rendering of urgent views, sending the IPC event, removing urgency after focused for one second, and matching urgent views via criteria. --- sway/desktop/render.c | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) (limited to 'sway/desktop') diff --git a/sway/desktop/render.c b/sway/desktop/render.c index 17fe823a..3180f8ba 100644 --- a/sway/desktop/render.c +++ b/sway/desktop/render.c @@ -553,7 +553,11 @@ static void render_container_simple(struct sway_output *output, struct wlr_texture *marks_texture; struct sway_container_state *state = &child->current; - if (state->focused || parent_focused) { + if (view_is_urgent(view)) { + colors = &config->border_colors.urgent; + title_texture = child->title_urgent; + marks_texture = view->marks_urgent; + } else if (state->focused || parent_focused) { colors = &config->border_colors.focused; title_texture = child->title_focused; marks_texture = view->marks_focused; @@ -608,7 +612,11 @@ static void render_container_tabbed(struct sway_output *output, struct wlr_texture *title_texture; struct wlr_texture *marks_texture; - if (cstate->focused || parent_focused) { + if (view && view_is_urgent(view)) { + colors = &config->border_colors.urgent; + title_texture = child->title_urgent; + marks_texture = view->marks_urgent; + } else if (cstate->focused || parent_focused) { colors = &config->border_colors.focused; title_texture = child->title_focused; marks_texture = view ? view->marks_focused : NULL; @@ -671,7 +679,11 @@ static void render_container_stacked(struct sway_output *output, struct wlr_texture *title_texture; struct wlr_texture *marks_texture; - if (cstate->focused || parent_focused) { + if (view && view_is_urgent(view)) { + colors = &config->border_colors.urgent; + title_texture = child->title_urgent; + marks_texture = view->marks_urgent; + } else if (cstate->focused || parent_focused) { colors = &config->border_colors.focused; title_texture = child->title_focused; marks_texture = view ? view->marks_focused : NULL; @@ -731,7 +743,11 @@ static void render_floating_container(struct sway_output *soutput, struct wlr_texture *title_texture; struct wlr_texture *marks_texture; - if (con->current.focused) { + if (view_is_urgent(view)) { + colors = &config->border_colors.urgent; + title_texture = con->title_urgent; + marks_texture = view->marks_urgent; + } else if (con->current.focused) { colors = &config->border_colors.focused; title_texture = con->title_focused; marks_texture = view->marks_focused; -- cgit v1.2.3 From e3f90f00fefcfba65d2387ac69f5e9aec2eb9883 Mon Sep 17 00:00:00 2001 From: Ryan Dwyer Date: Mon, 16 Jul 2018 08:42:34 +1000 Subject: Implement xwayland urgency hint --- sway/desktop/xwayland.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'sway/desktop') diff --git a/sway/desktop/xwayland.c b/sway/desktop/xwayland.c index 11516673..9df7977d 100644 --- a/sway/desktop/xwayland.c +++ b/sway/desktop/xwayland.c @@ -297,6 +297,10 @@ static void handle_commit(struct wl_listener *listener, void *data) { } view_damage_from(view); + + if (view->allow_request_urgent) { + view_set_urgent(view, (bool)xsurface->hints_urgency); + } } static void handle_unmap(struct wl_listener *listener, void *data) { -- cgit v1.2.3 From af5f736277559398d3d3df20adbb3a90ff88dbd0 Mon Sep 17 00:00:00 2001 From: Ryan Dwyer Date: Mon, 16 Jul 2018 18:22:27 +1000 Subject: Render containers as urgent if they have an urgent child --- sway/desktop/render.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'sway/desktop') diff --git a/sway/desktop/render.c b/sway/desktop/render.c index 3180f8ba..cb995215 100644 --- a/sway/desktop/render.c +++ b/sway/desktop/render.c @@ -611,11 +611,13 @@ static void render_container_tabbed(struct sway_output *output, struct border_colors *colors; struct wlr_texture *title_texture; struct wlr_texture *marks_texture; + bool urgent = view ? + view_is_urgent(view) : container_has_urgent_child(child); - if (view && view_is_urgent(view)) { + if (urgent) { colors = &config->border_colors.urgent; title_texture = child->title_urgent; - marks_texture = view->marks_urgent; + marks_texture = view ? view->marks_urgent : NULL; } else if (cstate->focused || parent_focused) { colors = &config->border_colors.focused; title_texture = child->title_focused; @@ -678,11 +680,13 @@ static void render_container_stacked(struct sway_output *output, struct border_colors *colors; struct wlr_texture *title_texture; struct wlr_texture *marks_texture; + bool urgent = view ? + view_is_urgent(view) : container_has_urgent_child(child); - if (view && view_is_urgent(view)) { + if (urgent) { colors = &config->border_colors.urgent; title_texture = child->title_urgent; - marks_texture = view->marks_urgent; + marks_texture = view ? view->marks_urgent : NULL; } else if (cstate->focused || parent_focused) { colors = &config->border_colors.focused; title_texture = child->title_focused; -- cgit v1.2.3 From 75c699db62e63e2a3c2aa652c9ba9482a8f13ec3 Mon Sep 17 00:00:00 2001 From: Ryan Dwyer Date: Tue, 17 Jul 2018 10:14:33 +1000 Subject: Implement default_floating_border command and adjust CSD behaviour --- sway/desktop/render.c | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-) (limited to 'sway/desktop') diff --git a/sway/desktop/render.c b/sway/desktop/render.c index cb995215..4c85e516 100644 --- a/sway/desktop/render.c +++ b/sway/desktop/render.c @@ -256,6 +256,10 @@ static void render_view(struct sway_output *output, pixman_region32_t *damage, render_view_surfaces(view, output, damage, view->swayc->alpha); } + if (view->using_csd) { + return; + } + struct wlr_box box; float output_scale = output->wlr_output->scale; float color[4]; @@ -571,12 +575,14 @@ static void render_container_simple(struct sway_output *output, marks_texture = view->marks_unfocused; } - if (state->border == B_NORMAL) { - render_titlebar(output, damage, child, state->swayc_x, - state->swayc_y, state->swayc_width, colors, - title_texture, marks_texture); - } else { - render_top_border(output, damage, child, colors); + if (!view->using_csd) { + if (state->border == B_NORMAL) { + render_titlebar(output, damage, child, state->swayc_x, + state->swayc_y, state->swayc_width, colors, + title_texture, marks_texture); + } else { + render_top_border(output, damage, child, colors); + } } render_view(output, damage, child, colors); } else { @@ -761,12 +767,14 @@ static void render_floating_container(struct sway_output *soutput, marks_texture = view->marks_unfocused; } - if (con->current.border == B_NORMAL) { - render_titlebar(soutput, damage, con, con->current.swayc_x, - con->current.swayc_y, con->current.swayc_width, colors, - title_texture, marks_texture); - } else if (con->current.border != B_NONE) { - render_top_border(soutput, damage, con, colors); + if (!view->using_csd) { + if (con->current.border == B_NORMAL) { + render_titlebar(soutput, damage, con, con->current.swayc_x, + con->current.swayc_y, con->current.swayc_width, colors, + title_texture, marks_texture); + } else if (con->current.border != B_NONE) { + render_top_border(soutput, damage, con, colors); + } } render_view(soutput, damage, con, colors); } else { -- cgit v1.2.3 From 37471ac649cf594975b4e0ab09291c116c66feec Mon Sep 17 00:00:00 2001 From: frsfnrrg Date: Tue, 17 Jul 2018 11:21:32 -0400 Subject: Fix memory leak in handle_layer_shell_surface --- sway/desktop/layer_shell.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'sway/desktop') diff --git a/sway/desktop/layer_shell.c b/sway/desktop/layer_shell.c index 91baa6f8..a7d96717 100644 --- a/sway/desktop/layer_shell.c +++ b/sway/desktop/layer_shell.c @@ -325,12 +325,6 @@ void handle_layer_shell_surface(struct wl_listener *listener, void *data) { layer_surface->client_pending.margin.bottom, layer_surface->client_pending.margin.left); - struct sway_layer_surface *sway_layer = - calloc(1, sizeof(struct sway_layer_surface)); - if (!sway_layer) { - return; - } - if (!layer_surface->output) { // Assign last active output struct sway_container *output = NULL; @@ -352,6 +346,12 @@ void handle_layer_shell_surface(struct wl_listener *listener, void *data) { layer_surface->output = output->sway_output->wlr_output; } + struct sway_layer_surface *sway_layer = + calloc(1, sizeof(struct sway_layer_surface)); + if (!sway_layer) { + return; + } + sway_layer->surface_commit.notify = handle_surface_commit; wl_signal_add(&layer_surface->surface->events.commit, &sway_layer->surface_commit); -- cgit v1.2.3 From 3931cb85b220294764db959513ecadb893e2c47b Mon Sep 17 00:00:00 2001 From: frsfnrrg Date: Tue, 17 Jul 2018 11:22:38 -0400 Subject: Fix memory leak in sway/desktop/idle_inhibit_v1.c --- sway/desktop/idle_inhibit_v1.c | 1 + 1 file changed, 1 insertion(+) (limited to 'sway/desktop') diff --git a/sway/desktop/idle_inhibit_v1.c b/sway/desktop/idle_inhibit_v1.c index 108a8417..da17d0f2 100644 --- a/sway/desktop/idle_inhibit_v1.c +++ b/sway/desktop/idle_inhibit_v1.c @@ -67,6 +67,7 @@ struct sway_idle_inhibit_manager_v1 *sway_idle_inhibit_manager_v1_create( manager->wlr_manager = wlr_idle_inhibit_v1_create(wl_display); if (!manager->wlr_manager) { + free(manager); return NULL; } manager->idle = idle; -- cgit v1.2.3 From fb4eca5d56b65a3129a8c17b171167198e6d9d7c Mon Sep 17 00:00:00 2001 From: emersion Date: Wed, 18 Jul 2018 19:10:08 +0100 Subject: Handle xwayland override_redirect flag change This fixes syncplay menus. --- sway/desktop/xwayland.c | 58 ++++++++++++++++++++++++++++--------------------- 1 file changed, 33 insertions(+), 25 deletions(-) (limited to 'sway/desktop') diff --git a/sway/desktop/xwayland.c b/sway/desktop/xwayland.c index 9df7977d..1ee3f660 100644 --- a/sway/desktop/xwayland.c +++ b/sway/desktop/xwayland.c @@ -69,7 +69,7 @@ static void unmanaged_handle_map(struct wl_listener *listener, void *data) { surface->ly = xsurface->y; desktop_damage_surface(xsurface->surface, surface->lx, surface->ly, true); - if (!wlr_xwayland_surface_is_unmanaged(xsurface)) { + if (!xsurface->override_redirect) { struct sway_seat *seat = input_manager_current_seat(input_manager); struct wlr_xwayland *xwayland = seat->input->server->xwayland.wlr_xwayland; @@ -89,7 +89,7 @@ static void unmanaged_handle_unmap(struct wl_listener *listener, void *data) { wl_list_remove(&surface->link); wl_list_remove(&surface->commit.link); - if (!wlr_xwayland_surface_is_unmanaged(xsurface)) { + if (!xsurface->override_redirect) { struct sway_seat *seat = input_manager_current_seat(input_manager); if (seat->wlr_seat->keyboard_state.focused_surface == xsurface->surface) { @@ -303,6 +303,27 @@ static void handle_commit(struct wl_listener *listener, void *data) { } } +static void handle_destroy(struct wl_listener *listener, void *data) { + struct sway_xwayland_view *xwayland_view = + wl_container_of(listener, xwayland_view, destroy); + struct sway_view *view = &xwayland_view->view; + + if (view->surface) { + view_unmap(view); + wl_list_remove(&xwayland_view->commit.link); + } + + wl_list_remove(&xwayland_view->destroy.link); + wl_list_remove(&xwayland_view->request_configure.link); + wl_list_remove(&xwayland_view->request_fullscreen.link); + wl_list_remove(&xwayland_view->set_title.link); + wl_list_remove(&xwayland_view->set_class.link); + wl_list_remove(&xwayland_view->set_window_type.link); + wl_list_remove(&xwayland_view->map.link); + wl_list_remove(&xwayland_view->unmap.link); + view_destroy(&xwayland_view->view); +} + static void handle_unmap(struct wl_listener *listener, void *data) { struct sway_xwayland_view *xwayland_view = wl_container_of(listener, xwayland_view, unmap); @@ -323,6 +344,15 @@ static void handle_map(struct wl_listener *listener, void *data) { struct wlr_xwayland_surface *xsurface = data; struct sway_view *view = &xwayland_view->view; + if (xsurface->override_redirect) { + // This window used not to have the override redirect flag and has it + // now. Switch to unmanaged. + handle_destroy(&xwayland_view->destroy, view); + struct sway_xwayland_unmanaged *unmanaged = create_unmanaged(xsurface); + unmanaged_handle_map(&unmanaged->map, xsurface); + return; + } + view->natural_width = xsurface->width; view->natural_height = xsurface->height; @@ -344,27 +374,6 @@ static void handle_map(struct wl_listener *listener, void *data) { transaction_commit_dirty(); } -static void handle_destroy(struct wl_listener *listener, void *data) { - struct sway_xwayland_view *xwayland_view = - wl_container_of(listener, xwayland_view, destroy); - struct sway_view *view = &xwayland_view->view; - - if (view->surface) { - view_unmap(view); - wl_list_remove(&xwayland_view->commit.link); - } - - wl_list_remove(&xwayland_view->destroy.link); - wl_list_remove(&xwayland_view->request_configure.link); - wl_list_remove(&xwayland_view->request_fullscreen.link); - wl_list_remove(&xwayland_view->set_title.link); - wl_list_remove(&xwayland_view->set_class.link); - wl_list_remove(&xwayland_view->set_window_type.link); - wl_list_remove(&xwayland_view->map.link); - wl_list_remove(&xwayland_view->unmap.link); - view_destroy(&xwayland_view->view); -} - static void handle_request_configure(struct wl_listener *listener, void *data) { struct sway_xwayland_view *xwayland_view = wl_container_of(listener, xwayland_view, request_configure); @@ -445,8 +454,7 @@ void handle_xwayland_surface(struct wl_listener *listener, void *data) { xwayland_surface); struct wlr_xwayland_surface *xsurface = data; - if (wlr_xwayland_surface_is_unmanaged(xsurface) || - xsurface->override_redirect) { + if (xsurface->override_redirect) { wlr_log(WLR_DEBUG, "New xwayland unmanaged surface"); create_unmanaged(xsurface); return; -- cgit v1.2.3 From 747725b8bb35bf3fd38d442f5bb565e7a4b11ec4 Mon Sep 17 00:00:00 2001 From: emersion Date: Wed, 18 Jul 2018 20:00:48 +0100 Subject: Don't unfocus when an override redirect window is mapped --- sway/desktop/xwayland.c | 37 +++++++++++++++---------------------- 1 file changed, 15 insertions(+), 22 deletions(-) (limited to 'sway/desktop') diff --git a/sway/desktop/xwayland.c b/sway/desktop/xwayland.c index 1ee3f660..7737a33a 100644 --- a/sway/desktop/xwayland.c +++ b/sway/desktop/xwayland.c @@ -69,16 +69,11 @@ static void unmanaged_handle_map(struct wl_listener *listener, void *data) { surface->ly = xsurface->y; desktop_damage_surface(xsurface->surface, surface->lx, surface->ly, true); - if (!xsurface->override_redirect) { - struct sway_seat *seat = input_manager_current_seat(input_manager); - struct wlr_xwayland *xwayland = - seat->input->server->xwayland.wlr_xwayland; - wlr_xwayland_set_seat(xwayland, seat->wlr_seat); - seat_set_focus_surface(seat, xsurface->surface); - } - - // TODO: we don't send surface enter/leave events to xwayland unmanaged - // surfaces, but xwayland doesn't support HiDPI anyway + struct sway_seat *seat = input_manager_current_seat(input_manager); + struct wlr_xwayland *xwayland = + seat->input->server->xwayland.wlr_xwayland; + wlr_xwayland_set_seat(xwayland, seat->wlr_seat); + seat_set_focus_surface(seat, xsurface->surface, false); } static void unmanaged_handle_unmap(struct wl_listener *listener, void *data) { @@ -89,18 +84,16 @@ static void unmanaged_handle_unmap(struct wl_listener *listener, void *data) { wl_list_remove(&surface->link); wl_list_remove(&surface->commit.link); - if (!xsurface->override_redirect) { - struct sway_seat *seat = input_manager_current_seat(input_manager); - if (seat->wlr_seat->keyboard_state.focused_surface == - xsurface->surface) { - // Restore focus - struct sway_container *previous = - seat_get_focus_inactive(seat, &root_container); - if (previous) { - // Hack to get seat to re-focus the return value of get_focus - seat_set_focus(seat, previous->parent); - seat_set_focus(seat, previous); - } + struct sway_seat *seat = input_manager_current_seat(input_manager); + if (seat->wlr_seat->keyboard_state.focused_surface == + xsurface->surface) { + // Restore focus + struct sway_container *previous = + seat_get_focus_inactive(seat, &root_container); + if (previous) { + // Hack to get seat to re-focus the return value of get_focus + seat_set_focus(seat, previous->parent); + seat_set_focus(seat, previous); } } } -- cgit v1.2.3 From 63d6233fcb601abd40f6c611aa4193766aaf9044 Mon Sep 17 00:00:00 2001 From: Ryan Dwyer Date: Thu, 19 Jul 2018 21:08:51 +1000 Subject: Allow xwayland views to become urgent when on a non-visible workspace This removes the urgency stuff from the commit handler and puts it in a new set_hints handler instead. This allows the xwayland surface to become urgent without having to commit (which doesn't happen if it's on an non-visible workspace). --- sway/desktop/xwayland.c | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) (limited to 'sway/desktop') diff --git a/sway/desktop/xwayland.c b/sway/desktop/xwayland.c index 7737a33a..72dc7ca2 100644 --- a/sway/desktop/xwayland.c +++ b/sway/desktop/xwayland.c @@ -290,10 +290,6 @@ static void handle_commit(struct wl_listener *listener, void *data) { } view_damage_from(view); - - if (view->allow_request_urgent) { - view_set_urgent(view, (bool)xsurface->hints_urgency); - } } static void handle_destroy(struct wl_listener *listener, void *data) { @@ -312,6 +308,7 @@ static void handle_destroy(struct wl_listener *listener, void *data) { wl_list_remove(&xwayland_view->set_title.link); wl_list_remove(&xwayland_view->set_class.link); wl_list_remove(&xwayland_view->set_window_type.link); + wl_list_remove(&xwayland_view->set_hints.link); wl_list_remove(&xwayland_view->map.link); wl_list_remove(&xwayland_view->unmap.link); view_destroy(&xwayland_view->view); @@ -437,6 +434,19 @@ static void handle_set_window_type(struct wl_listener *listener, void *data) { view_execute_criteria(view); } +static void handle_set_hints(struct wl_listener *listener, void *data) { + struct sway_xwayland_view *xwayland_view = + wl_container_of(listener, xwayland_view, set_hints); + struct sway_view *view = &xwayland_view->view; + struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface; + if (!xsurface->mapped) { + return; + } + if (view->allow_request_urgent) { + view_set_urgent(view, (bool)xsurface->hints_urgency); + } +} + struct sway_view *view_from_wlr_xwayland_surface( struct wlr_xwayland_surface *xsurface) { return xsurface->data; @@ -489,6 +499,9 @@ void handle_xwayland_surface(struct wl_listener *listener, void *data) { &xwayland_view->set_window_type); xwayland_view->set_window_type.notify = handle_set_window_type; + wl_signal_add(&xsurface->events.set_hints, &xwayland_view->set_hints); + xwayland_view->set_hints.notify = handle_set_hints; + wl_signal_add(&xsurface->events.unmap, &xwayland_view->unmap); xwayland_view->unmap.notify = handle_unmap; -- cgit v1.2.3 From 4154234eee1fa86f3a01d2f47b4fa632dcd73644 Mon Sep 17 00:00:00 2001 From: emersion Date: Thu, 19 Jul 2018 21:54:46 +0100 Subject: Update for swaywm/wlroots#1148 --- sway/desktop/transaction.c | 1 - 1 file changed, 1 deletion(-) (limited to 'sway/desktop') diff --git a/sway/desktop/transaction.c b/sway/desktop/transaction.c index fcfb0b51..19f41efc 100644 --- a/sway/desktop/transaction.c +++ b/sway/desktop/transaction.c @@ -4,7 +4,6 @@ #include #include #include -#include #include "sway/debug.h" #include "sway/desktop/idle_inhibit_v1.h" #include "sway/desktop/transaction.h" -- cgit v1.2.3 From c2ed3d8bd6e2ec12f2ce70d7e106c09a7078e91f Mon Sep 17 00:00:00 2001 From: Ryan Dwyer Date: Fri, 20 Jul 2018 19:37:27 +1000 Subject: Implement force_display_urgency_hint The directive sets the timeout before an urgent view becomes normal again after switching to it from another workspace. Also: * When an xwayland surface removes the urgent hint while the timer is active, we now ignore the request. This happens as soon as the view receives focus, so it was effectively making the timer pointless. * The timeout is now only applied when switching to it from another workspace. --- sway/desktop/xwayland.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'sway/desktop') diff --git a/sway/desktop/xwayland.c b/sway/desktop/xwayland.c index 72dc7ca2..bce0a37b 100644 --- a/sway/desktop/xwayland.c +++ b/sway/desktop/xwayland.c @@ -442,6 +442,12 @@ static void handle_set_hints(struct wl_listener *listener, void *data) { if (!xsurface->mapped) { return; } + if (!xsurface->hints_urgency && view->urgent_timer) { + // The view is is in the timeout period. We'll ignore the request to + // unset urgency so that the view remains urgent until the timer clears + // it. + return; + } if (view->allow_request_urgent) { view_set_urgent(view, (bool)xsurface->hints_urgency); } -- cgit v1.2.3 From f9491c9584d2c1fb789eee9c9e21fd6c274f4579 Mon Sep 17 00:00:00 2001 From: Ryan Dwyer Date: Thu, 19 Jul 2018 13:18:04 +1000 Subject: Fix damage issue when moving and resizing --- sway/desktop/output.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'sway/desktop') diff --git a/sway/desktop/output.c b/sway/desktop/output.c index a9808406..a206ac6b 100644 --- a/sway/desktop/output.c +++ b/sway/desktop/output.c @@ -463,11 +463,12 @@ static void output_damage_whole_container_iterator(struct sway_container *con, void output_damage_whole_container(struct sway_output *output, struct sway_container *con) { + // Pad the box by 1px, because the width is a double and might be a fraction struct wlr_box box = { - .x = con->current.swayc_x - output->wlr_output->lx, - .y = con->current.swayc_y - output->wlr_output->ly, - .width = con->current.swayc_width, - .height = con->current.swayc_height, + .x = con->current.swayc_x - output->wlr_output->lx - 1, + .y = con->current.swayc_y - output->wlr_output->ly - 1, + .width = con->current.swayc_width + 2, + .height = con->current.swayc_height + 2, }; scale_box(&box, output->wlr_output->scale); wlr_output_damage_add_box(output->damage, &box); -- cgit v1.2.3 From 31f91bd483797feb411077da0e351ccfae9ecc10 Mon Sep 17 00:00:00 2001 From: Ryan Dwyer Date: Thu, 19 Jul 2018 15:37:09 +1000 Subject: Improve resize performance by partially flushing the transaction queue When interactively resizing some views (eg. Nautilus), new transactions are added to the queue faster than the client can process them. Previously, we would wait for the entire queue to be ready before applying any of them, but in this case the transactions would time out, giving the client choppy performance. This changes the queue handling so it applies the transactions up to the first waiting transaction, without waiting for the entire queue to be ready. --- sway/desktop/transaction.c | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) (limited to 'sway/desktop') diff --git a/sway/desktop/transaction.c b/sway/desktop/transaction.c index 19f41efc..2a89880a 100644 --- a/sway/desktop/transaction.c +++ b/sway/desktop/transaction.c @@ -222,24 +222,16 @@ static void transaction_apply(struct sway_transaction *transaction) { } } -/** - * For simplicity, we only progress the queue if it can be completely flushed. - */ static void transaction_progress_queue() { - // We iterate this list in reverse because we're more likely to find a - // waiting transactions at the end of the list. - for (int i = server.transactions->length - 1; i >= 0; --i) { - struct sway_transaction *transaction = server.transactions->items[i]; + while (server.transactions->length) { + struct sway_transaction *transaction = server.transactions->items[0]; if (transaction->num_waiting) { return; } - } - for (int i = 0; i < server.transactions->length; ++i) { - struct sway_transaction *transaction = server.transactions->items[i]; transaction_apply(transaction); transaction_destroy(transaction); + list_del(server.transactions, 0); } - server.transactions->length = 0; idle_inhibit_v1_check_active(server.idle_inhibit_manager_v1); } -- cgit v1.2.3 From ff445cc85597ee6bfae01f03d3c246e2326f3981 Mon Sep 17 00:00:00 2001 From: Ryan Dwyer Date: Fri, 20 Jul 2018 09:28:22 +1000 Subject: Implement xdg shell request_move and request_resize events Also does a few other related things: * Now uses enum wlr_edges instead of our own enum resize_edge * Now uses wlr_xcursor_get_resize_name and removes our own find_resize_edge_name * Renames drag to move for consistency --- sway/desktop/xdg_shell.c | 33 +++++++++++++++++++++++++++++++++ sway/desktop/xdg_shell_v6.c | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 66 insertions(+) (limited to 'sway/desktop') diff --git a/sway/desktop/xdg_shell.c b/sway/desktop/xdg_shell.c index 98c16faf..d6c3a9a7 100644 --- a/sway/desktop/xdg_shell.c +++ b/sway/desktop/xdg_shell.c @@ -1,4 +1,9 @@ #define _POSIX_C_SOURCE 199309L +#ifdef __linux__ +#include +#elif __FreeBSD__ +#include +#endif #include #include #include @@ -248,6 +253,24 @@ static void handle_request_fullscreen(struct wl_listener *listener, void *data) transaction_commit_dirty(); } +static void handle_request_move(struct wl_listener *listener, void *data) { + struct sway_xdg_shell_view *xdg_shell_view = + wl_container_of(listener, xdg_shell_view, request_move); + struct sway_view *view = &xdg_shell_view->view; + struct wlr_xdg_toplevel_move_event *e = data; + struct sway_seat *seat = e->seat->seat->data; + seat_begin_move(seat, view->swayc); +} + +static void handle_request_resize(struct wl_listener *listener, void *data) { + struct sway_xdg_shell_view *xdg_shell_view = + wl_container_of(listener, xdg_shell_view, request_resize); + struct sway_view *view = &xdg_shell_view->view; + struct wlr_xdg_toplevel_resize_event *e = data; + struct sway_seat *seat = e->seat->seat->data; + seat_begin_resize(seat, view->swayc, BTN_LEFT, e->edges); +} + static void handle_unmap(struct wl_listener *listener, void *data) { struct sway_xdg_shell_view *xdg_shell_view = wl_container_of(listener, xdg_shell_view, unmap); @@ -262,6 +285,8 @@ static void handle_unmap(struct wl_listener *listener, void *data) { wl_list_remove(&xdg_shell_view->commit.link); wl_list_remove(&xdg_shell_view->new_popup.link); wl_list_remove(&xdg_shell_view->request_fullscreen.link); + wl_list_remove(&xdg_shell_view->request_move.link); + wl_list_remove(&xdg_shell_view->request_resize.link); } static void handle_map(struct wl_listener *listener, void *data) { @@ -299,6 +324,14 @@ static void handle_map(struct wl_listener *listener, void *data) { xdg_shell_view->request_fullscreen.notify = handle_request_fullscreen; wl_signal_add(&xdg_surface->toplevel->events.request_fullscreen, &xdg_shell_view->request_fullscreen); + + xdg_shell_view->request_move.notify = handle_request_move; + wl_signal_add(&xdg_surface->toplevel->events.request_move, + &xdg_shell_view->request_move); + + xdg_shell_view->request_resize.notify = handle_request_resize; + wl_signal_add(&xdg_surface->toplevel->events.request_resize, + &xdg_shell_view->request_resize); } static void handle_destroy(struct wl_listener *listener, void *data) { diff --git a/sway/desktop/xdg_shell_v6.c b/sway/desktop/xdg_shell_v6.c index 4d76f0a7..241bd9b0 100644 --- a/sway/desktop/xdg_shell_v6.c +++ b/sway/desktop/xdg_shell_v6.c @@ -1,4 +1,9 @@ #define _POSIX_C_SOURCE 199309L +#ifdef __linux__ +#include +#elif __FreeBSD__ +#include +#endif #include #include #include @@ -243,6 +248,24 @@ static void handle_request_fullscreen(struct wl_listener *listener, void *data) transaction_commit_dirty(); } +static void handle_request_move(struct wl_listener *listener, void *data) { + struct sway_xdg_shell_v6_view *xdg_shell_v6_view = + wl_container_of(listener, xdg_shell_v6_view, request_move); + struct sway_view *view = &xdg_shell_v6_view->view; + struct wlr_xdg_toplevel_v6_move_event *e = data; + struct sway_seat *seat = e->seat->seat->data; + seat_begin_move(seat, view->swayc); +} + +static void handle_request_resize(struct wl_listener *listener, void *data) { + struct sway_xdg_shell_v6_view *xdg_shell_v6_view = + wl_container_of(listener, xdg_shell_v6_view, request_resize); + struct sway_view *view = &xdg_shell_v6_view->view; + struct wlr_xdg_toplevel_v6_resize_event *e = data; + struct sway_seat *seat = e->seat->seat->data; + seat_begin_resize(seat, view->swayc, BTN_LEFT, e->edges); +} + static void handle_unmap(struct wl_listener *listener, void *data) { struct sway_xdg_shell_v6_view *xdg_shell_v6_view = wl_container_of(listener, xdg_shell_v6_view, unmap); @@ -257,6 +280,8 @@ static void handle_unmap(struct wl_listener *listener, void *data) { wl_list_remove(&xdg_shell_v6_view->commit.link); wl_list_remove(&xdg_shell_v6_view->new_popup.link); wl_list_remove(&xdg_shell_v6_view->request_fullscreen.link); + wl_list_remove(&xdg_shell_v6_view->request_move.link); + wl_list_remove(&xdg_shell_v6_view->request_resize.link); } static void handle_map(struct wl_listener *listener, void *data) { @@ -294,6 +319,14 @@ static void handle_map(struct wl_listener *listener, void *data) { xdg_shell_v6_view->request_fullscreen.notify = handle_request_fullscreen; wl_signal_add(&xdg_surface->toplevel->events.request_fullscreen, &xdg_shell_v6_view->request_fullscreen); + + xdg_shell_v6_view->request_move.notify = handle_request_move; + wl_signal_add(&xdg_surface->toplevel->events.request_move, + &xdg_shell_v6_view->request_move); + + xdg_shell_v6_view->request_resize.notify = handle_request_resize; + wl_signal_add(&xdg_surface->toplevel->events.request_resize, + &xdg_shell_v6_view->request_resize); } static void handle_destroy(struct wl_listener *listener, void *data) { -- cgit v1.2.3 From 9df660ee3188386c907d8feb999636ce8d61d095 Mon Sep 17 00:00:00 2001 From: Ryan Dwyer Date: Sat, 21 Jul 2018 11:23:48 +1000 Subject: Store last button and use it when views request to move or resize --- sway/desktop/xdg_shell.c | 13 ++++++------- sway/desktop/xdg_shell_v6.c | 13 ++++++------- 2 files changed, 12 insertions(+), 14 deletions(-) (limited to 'sway/desktop') diff --git a/sway/desktop/xdg_shell.c b/sway/desktop/xdg_shell.c index d6c3a9a7..c5d53d1d 100644 --- a/sway/desktop/xdg_shell.c +++ b/sway/desktop/xdg_shell.c @@ -1,9 +1,4 @@ #define _POSIX_C_SOURCE 199309L -#ifdef __linux__ -#include -#elif __FreeBSD__ -#include -#endif #include #include #include @@ -259,7 +254,9 @@ static void handle_request_move(struct wl_listener *listener, void *data) { struct sway_view *view = &xdg_shell_view->view; struct wlr_xdg_toplevel_move_event *e = data; struct sway_seat *seat = e->seat->seat->data; - seat_begin_move(seat, view->swayc); + if (e->serial == seat->last_button_serial) { + seat_begin_move(seat, view->swayc, seat->last_button); + } } static void handle_request_resize(struct wl_listener *listener, void *data) { @@ -268,7 +265,9 @@ static void handle_request_resize(struct wl_listener *listener, void *data) { struct sway_view *view = &xdg_shell_view->view; struct wlr_xdg_toplevel_resize_event *e = data; struct sway_seat *seat = e->seat->seat->data; - seat_begin_resize(seat, view->swayc, BTN_LEFT, e->edges); + if (e->serial == seat->last_button_serial) { + seat_begin_resize(seat, view->swayc, seat->last_button, e->edges); + } } static void handle_unmap(struct wl_listener *listener, void *data) { diff --git a/sway/desktop/xdg_shell_v6.c b/sway/desktop/xdg_shell_v6.c index 241bd9b0..4bd6af5e 100644 --- a/sway/desktop/xdg_shell_v6.c +++ b/sway/desktop/xdg_shell_v6.c @@ -1,9 +1,4 @@ #define _POSIX_C_SOURCE 199309L -#ifdef __linux__ -#include -#elif __FreeBSD__ -#include -#endif #include #include #include @@ -254,7 +249,9 @@ static void handle_request_move(struct wl_listener *listener, void *data) { struct sway_view *view = &xdg_shell_v6_view->view; struct wlr_xdg_toplevel_v6_move_event *e = data; struct sway_seat *seat = e->seat->seat->data; - seat_begin_move(seat, view->swayc); + if (e->serial == seat->last_button_serial) { + seat_begin_move(seat, view->swayc, seat->last_button); + } } static void handle_request_resize(struct wl_listener *listener, void *data) { @@ -263,7 +260,9 @@ static void handle_request_resize(struct wl_listener *listener, void *data) { struct sway_view *view = &xdg_shell_v6_view->view; struct wlr_xdg_toplevel_v6_resize_event *e = data; struct sway_seat *seat = e->seat->seat->data; - seat_begin_resize(seat, view->swayc, BTN_LEFT, e->edges); + if (e->serial == seat->last_button_serial) { + seat_begin_resize(seat, view->swayc, seat->last_button, e->edges); + } } static void handle_unmap(struct wl_listener *listener, void *data) { -- cgit v1.2.3 From 011d1ebfa4219eb666487529a5a5e7189c14fd40 Mon Sep 17 00:00:00 2001 From: Ryan Dwyer Date: Sat, 21 Jul 2018 12:13:00 +1000 Subject: Consider view's min/max sizes when resizing --- sway/desktop/xdg_shell.c | 12 ++++++++++++ sway/desktop/xdg_shell_v6.c | 12 ++++++++++++ 2 files changed, 24 insertions(+) (limited to 'sway/desktop') diff --git a/sway/desktop/xdg_shell.c b/sway/desktop/xdg_shell.c index c5d53d1d..76fe72ea 100644 --- a/sway/desktop/xdg_shell.c +++ b/sway/desktop/xdg_shell.c @@ -1,4 +1,5 @@ #define _POSIX_C_SOURCE 199309L +#include #include #include #include @@ -95,6 +96,16 @@ static struct sway_xdg_shell_view *xdg_shell_view_from_view( return (struct sway_xdg_shell_view *)view; } +static void get_constraints(struct sway_view *view, double *min_width, + double *max_width, double *min_height, double *max_height) { + struct wlr_xdg_toplevel_state *state = + &view->wlr_xdg_surface->toplevel->current; + *min_width = state->min_width > 0 ? state->min_width : DBL_MIN; + *max_width = state->max_width > 0 ? state->max_width : DBL_MAX; + *min_height = state->min_height > 0 ? state->min_height : DBL_MIN; + *max_height = state->max_height > 0 ? state->max_height : DBL_MAX; +} + static const char *get_string_prop(struct sway_view *view, enum sway_view_prop prop) { if (xdg_shell_view_from_view(view) == NULL) { return NULL; @@ -188,6 +199,7 @@ static void destroy(struct sway_view *view) { } static const struct sway_view_impl view_impl = { + .get_constraints = get_constraints, .get_string_prop = get_string_prop, .configure = configure, .set_activated = set_activated, diff --git a/sway/desktop/xdg_shell_v6.c b/sway/desktop/xdg_shell_v6.c index 4bd6af5e..57b51908 100644 --- a/sway/desktop/xdg_shell_v6.c +++ b/sway/desktop/xdg_shell_v6.c @@ -1,4 +1,5 @@ #define _POSIX_C_SOURCE 199309L +#include #include #include #include @@ -94,6 +95,16 @@ static struct sway_xdg_shell_v6_view *xdg_shell_v6_view_from_view( return (struct sway_xdg_shell_v6_view *)view; } +static void get_constraints(struct sway_view *view, double *min_width, + double *max_width, double *min_height, double *max_height) { + struct wlr_xdg_toplevel_v6_state *state = + &view->wlr_xdg_surface_v6->toplevel->current; + *min_width = state->min_width > 0 ? state->min_width : DBL_MIN; + *max_width = state->max_width > 0 ? state->max_width : DBL_MAX; + *min_height = state->min_height > 0 ? state->min_height : DBL_MIN; + *max_height = state->max_height > 0 ? state->max_height : DBL_MAX; +} + static const char *get_string_prop(struct sway_view *view, enum sway_view_prop prop) { if (xdg_shell_v6_view_from_view(view) == NULL) { return NULL; @@ -184,6 +195,7 @@ static void destroy(struct sway_view *view) { } static const struct sway_view_impl view_impl = { + .get_constraints = get_constraints, .get_string_prop = get_string_prop, .configure = configure, .set_activated = set_activated, -- cgit v1.2.3 From cf5f5eaf8c67c9d06c491a82b0b235aa27bbfe5c Mon Sep 17 00:00:00 2001 From: Ryan Dwyer Date: Sun, 22 Jul 2018 21:45:01 +1000 Subject: Deny move/resize events for tiled xdg shell views --- sway/desktop/xdg_shell.c | 6 ++++++ sway/desktop/xdg_shell_v6.c | 6 ++++++ 2 files changed, 12 insertions(+) (limited to 'sway/desktop') diff --git a/sway/desktop/xdg_shell.c b/sway/desktop/xdg_shell.c index 76fe72ea..706b35c3 100644 --- a/sway/desktop/xdg_shell.c +++ b/sway/desktop/xdg_shell.c @@ -264,6 +264,9 @@ static void handle_request_move(struct wl_listener *listener, void *data) { struct sway_xdg_shell_view *xdg_shell_view = wl_container_of(listener, xdg_shell_view, request_move); struct sway_view *view = &xdg_shell_view->view; + if (!container_is_floating(view->swayc)) { + return; + } struct wlr_xdg_toplevel_move_event *e = data; struct sway_seat *seat = e->seat->seat->data; if (e->serial == seat->last_button_serial) { @@ -275,6 +278,9 @@ static void handle_request_resize(struct wl_listener *listener, void *data) { struct sway_xdg_shell_view *xdg_shell_view = wl_container_of(listener, xdg_shell_view, request_resize); struct sway_view *view = &xdg_shell_view->view; + if (!container_is_floating(view->swayc)) { + return; + } struct wlr_xdg_toplevel_resize_event *e = data; struct sway_seat *seat = e->seat->seat->data; if (e->serial == seat->last_button_serial) { diff --git a/sway/desktop/xdg_shell_v6.c b/sway/desktop/xdg_shell_v6.c index 57b51908..201b5b1e 100644 --- a/sway/desktop/xdg_shell_v6.c +++ b/sway/desktop/xdg_shell_v6.c @@ -259,6 +259,9 @@ static void handle_request_move(struct wl_listener *listener, void *data) { struct sway_xdg_shell_v6_view *xdg_shell_v6_view = wl_container_of(listener, xdg_shell_v6_view, request_move); struct sway_view *view = &xdg_shell_v6_view->view; + if (!container_is_floating(view->swayc)) { + return; + } struct wlr_xdg_toplevel_v6_move_event *e = data; struct sway_seat *seat = e->seat->seat->data; if (e->serial == seat->last_button_serial) { @@ -270,6 +273,9 @@ static void handle_request_resize(struct wl_listener *listener, void *data) { struct sway_xdg_shell_v6_view *xdg_shell_v6_view = wl_container_of(listener, xdg_shell_v6_view, request_resize); struct sway_view *view = &xdg_shell_v6_view->view; + if (!container_is_floating(view->swayc)) { + return; + } struct wlr_xdg_toplevel_v6_resize_event *e = data; struct sway_seat *seat = e->seat->seat->data; if (e->serial == seat->last_button_serial) { -- cgit v1.2.3 From 5ba2ae9c6a4372cbf6f8867b711bb55ef6937cb4 Mon Sep 17 00:00:00 2001 From: Ryan Dwyer Date: Sun, 22 Jul 2018 22:14:36 +1000 Subject: Implement request_move and request_resize for xwayland views I discovered we have to send a click event when ending the move or resize operation to make xwayland's requests work correctly. --- sway/desktop/xwayland.c | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) (limited to 'sway/desktop') diff --git a/sway/desktop/xwayland.c b/sway/desktop/xwayland.c index bce0a37b..2546168b 100644 --- a/sway/desktop/xwayland.c +++ b/sway/desktop/xwayland.c @@ -305,6 +305,8 @@ static void handle_destroy(struct wl_listener *listener, void *data) { wl_list_remove(&xwayland_view->destroy.link); wl_list_remove(&xwayland_view->request_configure.link); wl_list_remove(&xwayland_view->request_fullscreen.link); + wl_list_remove(&xwayland_view->request_move.link); + wl_list_remove(&xwayland_view->request_resize.link); wl_list_remove(&xwayland_view->set_title.link); wl_list_remove(&xwayland_view->set_class.link); wl_list_remove(&xwayland_view->set_window_type.link); @@ -400,6 +402,37 @@ static void handle_request_fullscreen(struct wl_listener *listener, void *data) transaction_commit_dirty(); } +static void handle_request_move(struct wl_listener *listener, void *data) { + struct sway_xwayland_view *xwayland_view = + wl_container_of(listener, xwayland_view, request_move); + struct sway_view *view = &xwayland_view->view; + struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface; + if (!xsurface->mapped) { + return; + } + if (!container_is_floating(view->swayc)) { + return; + } + struct sway_seat *seat = input_manager_current_seat(input_manager); + seat_begin_move(seat, view->swayc, seat->last_button); +} + +static void handle_request_resize(struct wl_listener *listener, void *data) { + struct sway_xwayland_view *xwayland_view = + wl_container_of(listener, xwayland_view, request_resize); + struct sway_view *view = &xwayland_view->view; + struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface; + if (!xsurface->mapped) { + return; + } + if (!container_is_floating(view->swayc)) { + return; + } + struct wlr_xwayland_resize_event *e = data; + struct sway_seat *seat = input_manager_current_seat(input_manager); + seat_begin_resize(seat, view->swayc, seat->last_button, e->edges); +} + static void handle_set_title(struct wl_listener *listener, void *data) { struct sway_xwayland_view *xwayland_view = wl_container_of(listener, xwayland_view, set_title); @@ -495,6 +528,14 @@ void handle_xwayland_surface(struct wl_listener *listener, void *data) { &xwayland_view->request_fullscreen); xwayland_view->request_fullscreen.notify = handle_request_fullscreen; + wl_signal_add(&xsurface->events.request_move, + &xwayland_view->request_move); + xwayland_view->request_move.notify = handle_request_move; + + wl_signal_add(&xsurface->events.request_resize, + &xwayland_view->request_resize); + xwayland_view->request_resize.notify = handle_request_resize; + wl_signal_add(&xsurface->events.set_title, &xwayland_view->set_title); xwayland_view->set_title.notify = handle_set_title; -- cgit v1.2.3 From 238c8afc74241efdc44d1cf88322d322ce1226d9 Mon Sep 17 00:00:00 2001 From: emersion Date: Sun, 22 Jul 2018 22:20:07 +0100 Subject: Handle set_{title,app_id} for xdg-shell and zxdg-shell-v6 This allows to update the title even if the view doesn't commit. This is useful e.g. when a terminal sets its toplevel title to the currently running command and when the view isn't visible. --- sway/desktop/xdg_shell.c | 26 +++++++++++++++++++++++++- sway/desktop/xdg_shell_v6.c | 26 +++++++++++++++++++++++++- 2 files changed, 50 insertions(+), 2 deletions(-) (limited to 'sway/desktop') diff --git a/sway/desktop/xdg_shell.c b/sway/desktop/xdg_shell.c index 706b35c3..62c3abc8 100644 --- a/sway/desktop/xdg_shell.c +++ b/sway/desktop/xdg_shell.c @@ -225,10 +225,24 @@ static void handle_commit(struct wl_listener *listener, void *data) { transaction_notify_view_ready(view, xdg_surface->configure_serial); } - view_update_title(view, false); view_damage_from(view); } +static void handle_set_title(struct wl_listener *listener, void *data) { + struct sway_xdg_shell_view *xdg_shell_view = + wl_container_of(listener, xdg_shell_view, set_title); + struct sway_view *view = &xdg_shell_view->view; + view_update_title(view, false); + view_execute_criteria(view); +} + +static void handle_set_app_id(struct wl_listener *listener, void *data) { + struct sway_xdg_shell_view *xdg_shell_view = + wl_container_of(listener, xdg_shell_view, set_app_id); + struct sway_view *view = &xdg_shell_view->view; + view_execute_criteria(view); +} + static void handle_new_popup(struct wl_listener *listener, void *data) { struct sway_xdg_shell_view *xdg_shell_view = wl_container_of(listener, xdg_shell_view, new_popup); @@ -304,6 +318,8 @@ static void handle_unmap(struct wl_listener *listener, void *data) { wl_list_remove(&xdg_shell_view->request_fullscreen.link); wl_list_remove(&xdg_shell_view->request_move.link); wl_list_remove(&xdg_shell_view->request_resize.link); + wl_list_remove(&xdg_shell_view->set_title.link); + wl_list_remove(&xdg_shell_view->set_app_id.link); } static void handle_map(struct wl_listener *listener, void *data) { @@ -349,6 +365,14 @@ static void handle_map(struct wl_listener *listener, void *data) { xdg_shell_view->request_resize.notify = handle_request_resize; wl_signal_add(&xdg_surface->toplevel->events.request_resize, &xdg_shell_view->request_resize); + + xdg_shell_view->set_title.notify = handle_set_title; + wl_signal_add(&xdg_surface->toplevel->events.set_title, + &xdg_shell_view->set_title); + + xdg_shell_view->set_app_id.notify = handle_set_app_id; + wl_signal_add(&xdg_surface->toplevel->events.set_app_id, + &xdg_shell_view->set_app_id); } static void handle_destroy(struct wl_listener *listener, void *data) { diff --git a/sway/desktop/xdg_shell_v6.c b/sway/desktop/xdg_shell_v6.c index 201b5b1e..7fb85410 100644 --- a/sway/desktop/xdg_shell_v6.c +++ b/sway/desktop/xdg_shell_v6.c @@ -220,10 +220,24 @@ static void handle_commit(struct wl_listener *listener, void *data) { transaction_notify_view_ready(view, xdg_surface_v6->configure_serial); } - view_update_title(view, false); view_damage_from(view); } +static void handle_set_title(struct wl_listener *listener, void *data) { + struct sway_xdg_shell_v6_view *xdg_shell_v6_view = + wl_container_of(listener, xdg_shell_v6_view, set_title); + struct sway_view *view = &xdg_shell_v6_view->view; + view_update_title(view, false); + view_execute_criteria(view); +} + +static void handle_set_app_id(struct wl_listener *listener, void *data) { + struct sway_xdg_shell_v6_view *xdg_shell_v6_view = + wl_container_of(listener, xdg_shell_v6_view, set_app_id); + struct sway_view *view = &xdg_shell_v6_view->view; + view_execute_criteria(view); +} + static void handle_new_popup(struct wl_listener *listener, void *data) { struct sway_xdg_shell_v6_view *xdg_shell_v6_view = wl_container_of(listener, xdg_shell_v6_view, new_popup); @@ -299,6 +313,8 @@ static void handle_unmap(struct wl_listener *listener, void *data) { wl_list_remove(&xdg_shell_v6_view->request_fullscreen.link); wl_list_remove(&xdg_shell_v6_view->request_move.link); wl_list_remove(&xdg_shell_v6_view->request_resize.link); + wl_list_remove(&xdg_shell_v6_view->set_title.link); + wl_list_remove(&xdg_shell_v6_view->set_app_id.link); } static void handle_map(struct wl_listener *listener, void *data) { @@ -344,6 +360,14 @@ static void handle_map(struct wl_listener *listener, void *data) { xdg_shell_v6_view->request_resize.notify = handle_request_resize; wl_signal_add(&xdg_surface->toplevel->events.request_resize, &xdg_shell_v6_view->request_resize); + + xdg_shell_v6_view->set_title.notify = handle_set_title; + wl_signal_add(&xdg_surface->toplevel->events.set_title, + &xdg_shell_v6_view->set_title); + + xdg_shell_v6_view->set_app_id.notify = handle_set_app_id; + wl_signal_add(&xdg_surface->toplevel->events.set_app_id, + &xdg_shell_v6_view->set_app_id); } static void handle_destroy(struct wl_listener *listener, void *data) { -- cgit v1.2.3 From 7ead2e85a7816a65e87bb7fded7414f571d56619 Mon Sep 17 00:00:00 2001 From: somdoron Date: Mon, 23 Jul 2018 19:29:32 +0300 Subject: fix crash on new output while swaylock is running --- sway/desktop/render.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sway/desktop') diff --git a/sway/desktop/render.c b/sway/desktop/render.c index 4c85e516..7da54594 100644 --- a/sway/desktop/render.c +++ b/sway/desktop/render.c @@ -838,7 +838,7 @@ void output_render(struct sway_output *output, struct timespec *when, struct sway_view *fullscreen_view = workspace->current.ws_fullscreen; struct sway_seat *seat = input_manager_current_seat(input_manager); - if (output_has_opaque_lockscreen(output, seat)) { + if (output_has_opaque_lockscreen(output, seat) && seat->focused_layer) { struct wlr_layer_surface *wlr_layer_surface = seat->focused_layer; struct sway_layer_surface *sway_layer_surface = layer_from_wlr_layer_surface(seat->focused_layer); -- cgit v1.2.3