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 65dba365e..4fd840479 100644 --- a/sway/config.c +++ b/sway/config.c @@ -686,6 +686,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, @@ -693,6 +694,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 444f85fd8..46c3611e3 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 33c66bb77..15eca3fdb 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,19 @@ 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); + 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 +74,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 bad8b59a0..fc5a6492e 100644 --- a/sway/handlers.c +++ b/sway/handlers.c @@ -106,18 +106,10 @@ 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); 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) { @@ -153,6 +145,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); @@ -237,12 +233,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); @@ -674,7 +683,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 ba64cb60f..8d28a3141 100644 --- a/wayland/window.c +++ b/wayland/window.c @@ -69,7 +69,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); }