From 802233f3d023bf8fd1ce8dc0416a382ce570bf13 Mon Sep 17 00:00:00 2001 From: Drew DeVault Date: Sun, 17 Jan 2016 12:58:03 -0500 Subject: [PATCH] Support for swaybg as a shell surface This is a lot of work for a small payoff - the mouse cursor is now correctly rendered over the background. Containers can now specify a custom arrange function which will be called during arrange_windows instead of the usual path for that container type. For backgrounds, the function sends it to the back and sets its geometry to the size of the screen. This requires some changes I'm not too happy with in arrange_windows with respect to how containers figure out the arrangemnet of their children (special cases are undesirable). Also, if anyone runs a debug build as their actual WM, you should know that I've made it so swaybg is invoked as `./bin/swaybg` in debug builds now. This PR also includes a bunch of unrelated refactoring. This is a pretty significant change and I can only test it under the x backend, so I'd appreciate it if you kind folks would review+test it yourselves and leave some :+1: if you like it. --- include/container.h | 3 +++ include/extensions.h | 41 ++++++++++++++++++++++------------------- include/output.h | 2 ++ sway/config.c | 10 ++++++++++ sway/container.c | 18 +++--------------- sway/extensions.c | 34 +++++++++++++++++++++------------- sway/handlers.c | 32 +++++++++++++++++++++----------- sway/layout.c | 32 ++++++++++++++++++++++++++------ sway/output.c | 21 +++++++++++++++++++++ swaybg/main.c | 6 +++--- wayland/window.c | 2 +- 11 files changed, 133 insertions(+), 68 deletions(-) diff --git a/include/container.h b/include/container.h index d5126e746..087437c8f 100644 --- a/include/container.h +++ b/include/container.h @@ -77,6 +77,9 @@ struct sway_container { bool is_focused; bool sticky; // floating view always visible on its output + // Custom arrange function + void (*arrange)(struct sway_container *, double width, double height); + // Attributes that mostly views have. char *name; char *class; diff --git a/include/extensions.h b/include/extensions.h index 164688eef..aa8ff16c8 100644 --- a/include/extensions.h +++ b/include/extensions.h @@ -5,40 +5,43 @@ #include #include "wayland-desktop-shell-server-protocol.h" #include "list.h" +#include "container.h" struct background_config { - wlc_handle output; - wlc_resource surface; - // we need the wl_resource of the surface in the destructor - struct wl_resource *wl_surface_res; + wlc_handle output; + wlc_handle handle; + wlc_resource surface; + // we need the wl_resource of the surface in the destructor + struct wl_resource *wl_surface_res; }; struct panel_config { - // wayland resource used in callbacks, is used to track this panel - struct wl_resource *wl_resource; - wlc_handle output; - wlc_resource surface; - // we need the wl_resource of the surface in the destructor - struct wl_resource *wl_surface_res; - enum desktop_shell_panel_position panel_position; + // wayland resource used in callbacks, is used to track this panel + struct wl_resource *wl_resource; + wlc_handle output; + wlc_resource surface; + // we need the wl_resource of the surface in the destructor + struct wl_resource *wl_surface_res; + enum desktop_shell_panel_position panel_position; }; struct desktop_shell_state { - list_t *backgrounds; - list_t *panels; - list_t *lock_surfaces; - bool is_locked; - struct wlc_size panel_size; + list_t *backgrounds; + list_t *panels; + list_t *lock_surfaces; + bool is_locked; + struct wlc_size panel_size; }; struct swaylock_state { - bool active; - wlc_handle output; - wlc_resource surface; + bool active; + wlc_handle output; + wlc_resource surface; }; extern struct desktop_shell_state desktop_shell; void register_extensions(void); +void arrange_background_view(swayc_t *view, double width, double height); #endif diff --git a/include/output.h b/include/output.h index 1307ead81..a193bc461 100644 --- a/include/output.h +++ b/include/output.h @@ -16,4 +16,6 @@ void get_absolute_position(swayc_t *container, struct wlc_point *point); // given wlc_point. void get_absolute_center_position(swayc_t *container, struct wlc_point *point); +struct output_config *config_for_output(wlc_handle output); + #endif diff --git a/sway/config.c b/sway/config.c index ae6a02b1b..279e5eba2 100644 --- a/sway/config.c +++ b/sway/config.c @@ -566,6 +566,7 @@ void apply_output_config(struct output_config *oc, swayc_t *output) { snprintf(output_id, bufsize, "%d", output_i); output_id[bufsize-1] = 0; +#ifdef NDEBUG char *const cmd[] = { "swaybg", output_id, @@ -573,6 +574,15 @@ void apply_output_config(struct output_config *oc, swayc_t *output) { oc->background_option, NULL, }; +#else + char *const cmd[] = { + "./bin/swaybg", + output_id, + oc->background, + oc->background_option, + NULL, + }; +#endif output->bg_pid = fork(); if (output->bg_pid == 0) { diff --git a/sway/container.c b/sway/container.c index 63374f9e5..9d295a459 100644 --- a/sway/container.c +++ b/sway/container.c @@ -11,6 +11,7 @@ #include "layout.h" #include "input_state.h" #include "log.h" +#include "output.h" #define ASSERT_NONNULL(PTR) \ sway_assert (PTR, #PTR "must be non-null") @@ -90,21 +91,7 @@ swayc_t *new_output(wlc_handle handle) { sway_log(L_DEBUG, "New output %lu:%s", handle, name); - struct output_config *oc = NULL; - int i; - for (i = 0; i < config->output_configs->length; ++i) { - struct output_config *cur = config->output_configs->items[i]; - if (strcasecmp(name, cur->name) == 0) { - sway_log(L_DEBUG, "Matched output config for %s", name); - oc = cur; - break; - } - if (strcasecmp("*", cur->name) == 0) { - sway_log(L_DEBUG, "Matched wildcard output config for %s", name); - oc = cur; - break; - } - } + struct output_config *oc = config_for_output(handle); if (oc && !oc->enabled) { return NULL; @@ -125,6 +112,7 @@ swayc_t *new_output(wlc_handle handle) { // Create workspace char *ws_name = NULL; if (name) { + int i; for (i = 0; i < config->workspace_outputs->length; ++i) { struct workspace_output *wso = config->workspace_outputs->items[i]; if (strcasecmp(wso->output, name) == 0) { diff --git a/sway/extensions.c b/sway/extensions.c index 00a72a804..cadf1f928 100644 --- a/sway/extensions.c +++ b/sway/extensions.c @@ -24,18 +24,6 @@ static struct panel_config *find_or_create_panel_config(struct wl_resource *reso return config; } -void background_surface_destructor(struct wl_resource *resource) { - sway_log(L_DEBUG, "Background surface killed"); - int i; - for (i = 0; i < desktop_shell.backgrounds->length; ++i) { - struct background_config *config = desktop_shell.backgrounds->items[i]; - if (config->wl_surface_res == resource) { - list_del(desktop_shell.backgrounds, i); - break; - } - } -} - void panel_surface_destructor(struct wl_resource *resource) { sway_log(L_DEBUG, "Panel surface killed"); int i; @@ -63,6 +51,21 @@ void lock_surface_destructor(struct wl_resource *resource) { } } +void arrange_background_view(swayc_t *view, double width, double height) { + sway_log(L_DEBUG, "Arranging background view %p", view); + int i; + for (i = 0; i < desktop_shell.backgrounds->length; ++i) { + struct background_config *config = desktop_shell.backgrounds->items[i]; + if (config->handle == view->handle) { + struct wlc_size resolution = *wlc_output_get_resolution(config->output); + resolution.w = 100; + resolution.h = 100; + wlc_view_set_geometry(view->handle, WLC_RESIZE_EDGE_NONE, &(struct wlc_geometry){ wlc_origin_zero, resolution }); + wlc_view_send_to_back(view->handle); + } + } +} + static void set_background(struct wl_client *client, struct wl_resource *resource, struct wl_resource *_output, struct wl_resource *surface) { wlc_handle output = wlc_handle_from_wl_output_resource(_output); @@ -73,9 +76,14 @@ static void set_background(struct wl_client *client, struct wl_resource *resourc struct background_config *config = malloc(sizeof(struct background_config)); config->output = output; config->surface = wlc_resource_from_wl_surface_resource(surface); + config->handle = wlc_handle_from_wl_surface_resource(surface); config->wl_surface_res = surface; list_add(desktop_shell.backgrounds, config); - wl_resource_set_destructor(surface, background_surface_destructor); + + swayc_t *view = swayc_by_handle(config->handle); + if (view) { + view->arrange = arrange_background_view; + } } static void set_panel(struct wl_client *client, struct wl_resource *resource, diff --git a/sway/handlers.c b/sway/handlers.c index 60bfac871..b6f22de5b 100644 --- a/sway/handlers.c +++ b/sway/handlers.c @@ -72,18 +72,11 @@ static void handle_output_destroyed(wlc_handle output) { } } -static void handle_output_pre_render(wlc_handle output) { +static void handle_output_post_render(wlc_handle output) { struct wlc_size resolution = *wlc_output_get_resolution(output); + swayc_t *swayc = swayc_by_handle(output); int i; - for (i = 0; i < desktop_shell.backgrounds->length; ++i) { - struct background_config *config = desktop_shell.backgrounds->items[i]; - if (config->output == output) { - wlc_surface_render(config->surface, &(struct wlc_geometry){ wlc_origin_zero, resolution }); - break; - } - } - for (i = 0; i < desktop_shell.panels->length; ++i) { struct panel_config *config = desktop_shell.panels->items[i]; if (config->output == output) { @@ -119,6 +112,10 @@ static void handle_output_resolution_change(wlc_handle output, const struct wlc_ sway_log(L_DEBUG, "Output %u resolution changed to %d x %d", (unsigned int)output, to->w, to->h); swayc_t *c = swayc_by_handle(output); if (!c) return; + struct output_config *oc = config_for_output(output); + if (oc) { + apply_output_config(oc, c); + } c->width = to->w; c->height = to->h; arrange_windows(&root_container, -1, -1); @@ -203,12 +200,25 @@ static bool handle_view_created(wlc_handle handle) { } if (newview) { + int i; set_focused_container(newview); + + // Check if this view has a special role + wlc_resource resource = wlc_view_get_surface(handle); + for (i = 0; i < desktop_shell.backgrounds->length; ++i) { + struct background_config *config = desktop_shell.backgrounds->items[i]; + if (config->surface == resource) { + sway_log(L_DEBUG, "Setting view %p as background", newview); + newview->handle = handle; + newview->arrange = arrange_background_view; + } + } + swayc_t *output = swayc_parent_by_type(newview, C_OUTPUT); arrange_windows(output, -1, -1); // check if it matches for_window in config and execute if so list_t *criteria = criteria_for(newview); - for (int i = 0; i < criteria->length; i++) { + for (i = 0; i < criteria->length; i++) { struct criteria *crit = criteria->items[i]; sway_log(L_DEBUG, "for_window '%s' matches new view %p, cmd: '%s'", crit->crit_raw, newview, crit->cmdlist); @@ -639,7 +649,7 @@ struct wlc_interface interface = { .resolution = handle_output_resolution_change, .focus = handle_output_focused, .render = { - .pre = handle_output_pre_render + .post = handle_output_post_render } }, .view = { diff --git a/sway/layout.c b/sway/layout.c index d5fdbf0bf..59017fe08 100644 --- a/sway/layout.c +++ b/sway/layout.c @@ -445,6 +445,12 @@ static void arrange_windows_r(swayc_t *container, double width, double height) { sway_log(L_DEBUG, "Arranging layout for %p %s %fx%f+%f,%f", container, container->name, container->width, container->height, container->x, container->y); + if (container->arrange) { + sway_log(L_DEBUG, "Invoking arrangement override handler for container %p", container); + container->arrange(container, width, height); + return; + } + double x = 0, y = 0; switch (container->type) { case C_ROOT: @@ -524,6 +530,14 @@ static void arrange_windows_r(swayc_t *container, double width, double height) { y = container->y; break; } + + int total_children = 0; // not including arrangement override containers + for (i = 0; i < container->children->length; ++i) { + swayc_t *child = container->children->items[i]; + if (!child->arrange) { + total_children++; + } + } double scale = 0; switch (container->layout) { @@ -531,10 +545,12 @@ static void arrange_windows_r(swayc_t *container, double width, double height) { default: // Calculate total width for (i = 0; i < container->children->length; ++i) { - double *old_width = &((swayc_t *)container->children->items[i])->width; + swayc_t *child = container->children->items[i]; + if (child->arrange) continue; + double *old_width = &child->width; if (*old_width <= 0) { - if (container->children->length > 1) { - *old_width = width / (container->children->length - 1); + if (total_children > 1) { + *old_width = width / (total_children - 1); } else { *old_width = width; } @@ -547,6 +563,7 @@ static void arrange_windows_r(swayc_t *container, double width, double height) { sway_log(L_DEBUG, "Arranging %p horizontally", container); for (i = 0; i < container->children->length; ++i) { swayc_t *child = container->children->items[i]; + if (child->arrange) continue; sway_log(L_DEBUG, "Calculating arrangement for %p:%d (will scale %f by %f)", child, child->type, width, scale); child->x = x; child->y = y; @@ -563,10 +580,12 @@ static void arrange_windows_r(swayc_t *container, double width, double height) { case L_VERT: // Calculate total height for (i = 0; i < container->children->length; ++i) { - double *old_height = &((swayc_t *)container->children->items[i])->height; + swayc_t *child = container->children->items[i]; + if (child->arrange) continue; + double *old_height = &child->height; if (*old_height <= 0) { - if (container->children->length > 1) { - *old_height = height / (container->children->length - 1); + if (total_children > 1) { + *old_height = height / (total_children - 1); } else { *old_height = height; } @@ -579,6 +598,7 @@ static void arrange_windows_r(swayc_t *container, double width, double height) { sway_log(L_DEBUG, "Arranging %p vertically", container); for (i = 0; i < container->children->length; ++i) { swayc_t *child = container->children->items[i]; + if (child->arrange) continue; sway_log(L_DEBUG, "Calculating arrangement for %p:%d (will scale %f by %f)", child, child->type, height, scale); child->x = x; child->y = y; diff --git a/sway/output.c b/sway/output.c index cf8ed9a5c..ea64efc28 100644 --- a/sway/output.c +++ b/sway/output.c @@ -1,4 +1,5 @@ #include +#include "config.h" #include "output.h" #include "log.h" @@ -22,6 +23,26 @@ swayc_t *output_by_name(const char* name, const struct wlc_point *abs_pos) { return NULL; } +struct output_config *config_for_output(wlc_handle output) { + const char *name = wlc_output_get_name(output); + struct output_config *oc = NULL; + int i; + for (i = 0; i < config->output_configs->length; ++i) { + struct output_config *cur = config->output_configs->items[i]; + if (strcasecmp(name, cur->name) == 0) { + sway_log(L_DEBUG, "Matched output config for %s", name); + oc = cur; + break; + } + if (strcasecmp("*", cur->name) == 0) { + sway_log(L_DEBUG, "Matched wildcard output config for %s", name); + oc = cur; + break; + } + } + return oc; +} + // Position is where on the edge (as absolute position) the adjacent output should be searched for. swayc_t *swayc_adjacent_output(swayc_t *output, enum movement_direction dir, const struct wlc_point *abs_pos, bool pick_closest) { diff --git a/swaybg/main.c b/swaybg/main.c index b936be2b8..40497ffb9 100644 --- a/swaybg/main.c +++ b/swaybg/main.c @@ -46,10 +46,10 @@ int main(int argc, const char **argv) { } int desired_output = atoi(argv[1]); - sway_log(L_INFO, "Using output %d of %d", desired_output, registry->outputs->length); - int i; struct output_state *output = registry->outputs->items[desired_output]; - struct window *window = window_setup(registry, output->width, output->height, false); + sway_log(L_INFO, "Using output %d of %d (%dx%d)", desired_output, registry->outputs->length, output->width, output->height); + int i; + struct window *window = window_setup(registry, output->width, output->height, true); if (!window) { sway_abort("Failed to create surfaces."); } diff --git a/wayland/window.c b/wayland/window.c index 916e3b57e..5be8b7e25 100644 --- a/wayland/window.c +++ b/wayland/window.c @@ -67,7 +67,7 @@ struct window *window_setup(struct registry *registry, uint32_t width, uint32_t window->surface = wl_compositor_create_surface(registry->compositor); if (shell_surface) { - window->shell_surface = wl_shell_get_shell_surface(registry->shell, window->surface); + window->shell_surface = wl_shell_get_shell_surface(window->registry->shell, window->surface); wl_shell_surface_add_listener(window->shell_surface, &surface_listener, window); wl_shell_surface_set_toplevel(window->shell_surface); }