diff options
Diffstat (limited to 'sway/tree/container.c')
-rw-r--r-- | sway/tree/container.c | 296 |
1 files changed, 217 insertions, 79 deletions
diff --git a/sway/tree/container.c b/sway/tree/container.c index 2e61ff5c..9b90b774 100644 --- a/sway/tree/container.c +++ b/sway/tree/container.c @@ -3,14 +3,10 @@ #include <drm_fourcc.h> #include <stdint.h> #include <stdlib.h> -#include <string.h> -#include <strings.h> -#include <sys/stat.h> #include <wayland-server-core.h> #include <wlr/types/wlr_linux_dmabuf_v1.h> #include <wlr/types/wlr_output_layout.h> #include <wlr/types/wlr_subcompositor.h> -#include <wlr/render/drm_format_set.h> #include "linux-dmabuf-unstable-v1-protocol.h" #include "cairo_util.h" #include "pango.h" @@ -22,6 +18,7 @@ #include "sway/ipc-server.h" #include "sway/output.h" #include "sway/server.h" +#include "sway/surface.h" #include "sway/tree/arrange.h" #include "sway/tree/view.h" #include "sway/tree/workspace.h" @@ -392,17 +389,17 @@ struct sway_container *tiling_container_at(struct sway_node *parent, } static bool surface_is_popup(struct wlr_surface *surface) { - while (!wlr_surface_is_xdg_surface(surface)) { - if (!wlr_surface_is_subsurface(surface)) { + while (wlr_xdg_surface_try_from_wlr_surface(surface) == NULL) { + struct wlr_subsurface *subsurface = + wlr_subsurface_try_from_wlr_surface(surface); + if (subsurface == NULL) { return false; } - struct wlr_subsurface *subsurface = - wlr_subsurface_from_wlr_surface(surface); surface = subsurface->parent; } struct wlr_xdg_surface *xdg_surface = - wlr_xdg_surface_from_wlr_surface(surface); - return xdg_surface->role == WLR_XDG_SURFACE_ROLE_POPUP; + wlr_xdg_surface_try_from_wlr_surface(surface); + return xdg_surface->role == WLR_XDG_SURFACE_ROLE_POPUP && xdg_surface->popup != NULL; } struct sway_container *container_at(struct sway_workspace *workspace, @@ -516,7 +513,6 @@ static void render_titlebar_text_texture(struct sway_output *output, cairo_t *c = cairo_create(dummy_surface); cairo_set_antialias(c, CAIRO_ANTIALIAS_BEST); cairo_font_options_t *fo = cairo_font_options_create(); - cairo_font_options_set_hint_style(fo, CAIRO_HINT_STYLE_FULL); if (output->wlr_output->subpixel == WL_OUTPUT_SUBPIXEL_NONE) { cairo_font_options_set_antialias(fo, CAIRO_ANTIALIAS_GRAY); } else { @@ -721,6 +717,21 @@ void floating_calculate_constraints(int *min_width, int *max_width, } +void floating_fix_coordinates(struct sway_container *con, struct wlr_box *old, struct wlr_box *new) { + if (!old->width || !old->height) { + // Fall back to centering on the workspace. + container_floating_move_to_center(con); + } else { + int rel_x = con->pending.x - old->x + (con->pending.width / 2); + int rel_y = con->pending.y - old->y + (con->pending.height / 2); + + con->pending.x = new->x + (double)(rel_x * new->width) / old->width - (con->pending.width / 2); + con->pending.y = new->y + (double)(rel_y * new->height) / old->height - (con->pending.height / 2); + + sway_log(SWAY_DEBUG, "Transformed container %p to coords (%f, %f)", con, con->pending.x, con->pending.y); + } +} + static void floating_natural_resize(struct sway_container *con) { int min_width, max_width, min_height, max_height; floating_calculate_constraints(&min_width, &max_width, @@ -1034,6 +1045,13 @@ void container_floating_move_to(struct sway_container *con, workspace_add_floating(new_workspace, con); arrange_workspace(old_workspace); arrange_workspace(new_workspace); + // If the moved container was a visible scratchpad container, then + // update its transform. + if (con->scratchpad) { + struct wlr_box output_box; + output_get_box(new_output, &output_box); + con->transform = output_box; + } workspace_detect_urgent(old_workspace); workspace_detect_urgent(new_workspace); } @@ -1065,16 +1083,6 @@ void container_end_mouse_operation(struct sway_container *container) { } } -static bool devid_from_fd(int fd, dev_t *devid) { - struct stat stat; - if (fstat(fd, &stat) != 0) { - sway_log_errno(SWAY_ERROR, "fstat failed"); - return false; - } - *devid = stat.st_rdev; - return true; -} - static void set_fullscreen(struct sway_container *con, bool enable) { if (!con->view) { return; @@ -1101,60 +1109,19 @@ static void set_fullscreen(struct sway_container *con, bool enable) { } struct sway_output *output = con->pending.workspace->output; - struct wlr_output *wlr_output = output->wlr_output; - - // TODO: add wlroots helpers for all of this stuff - - const struct wlr_drm_format_set *renderer_formats = - wlr_renderer_get_dmabuf_texture_formats(server.wlr_renderer); - assert(renderer_formats); - - int renderer_drm_fd = wlr_renderer_get_drm_fd(server.wlr_renderer); - int backend_drm_fd = wlr_backend_get_drm_fd(wlr_output->backend); - if (renderer_drm_fd < 0 || backend_drm_fd < 0) { - return; - } - - dev_t render_dev, scanout_dev; - if (!devid_from_fd(renderer_drm_fd, &render_dev) || - !devid_from_fd(backend_drm_fd, &scanout_dev)) { - return; - } - - const struct wlr_drm_format_set *output_formats = - wlr_output_get_primary_formats(output->wlr_output, - WLR_BUFFER_CAP_DMABUF); - if (!output_formats) { - return; - } - - struct wlr_drm_format_set scanout_formats = {0}; - if (!wlr_drm_format_set_intersect(&scanout_formats, - output_formats, renderer_formats)) { - return; - } - - struct wlr_linux_dmabuf_feedback_v1_tranche tranches[] = { - { - .target_device = scanout_dev, - .flags = ZWP_LINUX_DMABUF_FEEDBACK_V1_TRANCHE_FLAGS_SCANOUT, - .formats = &scanout_formats, - }, - { - .target_device = render_dev, - .formats = renderer_formats, - }, + const struct wlr_linux_dmabuf_feedback_v1_init_options options = { + .main_renderer = server.renderer, + .scanout_primary_output = output->wlr_output, }; + struct wlr_linux_dmabuf_feedback_v1 feedback = {0}; + if (!wlr_linux_dmabuf_feedback_v1_init_with_options(&feedback, &options)) { + return; + } - const struct wlr_linux_dmabuf_feedback_v1 feedback = { - .main_device = render_dev, - .tranches = tranches, - .tranches_len = sizeof(tranches) / sizeof(tranches[0]), - }; wlr_linux_dmabuf_v1_set_surface_feedback(server.linux_dmabuf_v1, con->view->surface, &feedback); - wlr_drm_format_set_finish(&scanout_formats); + wlr_linux_dmabuf_feedback_v1_finish(&feedback); } static void container_fullscreen_workspace(struct sway_container *con) { @@ -1326,14 +1293,14 @@ bool container_is_fullscreen_or_child(struct sway_container *container) { static void surface_send_enter_iterator(struct wlr_surface *surface, int x, int y, void *data) { - struct wlr_output *wlr_output = data; - wlr_surface_send_enter(surface, wlr_output); + struct sway_output *output = data; + surface_enter_output(surface, output); } static void surface_send_leave_iterator(struct wlr_surface *surface, int x, int y, void *data) { - struct wlr_output *wlr_output = data; - wlr_surface_send_leave(surface, wlr_output); + struct sway_output *output = data; + surface_leave_output(surface, output); } void container_discover_outputs(struct sway_container *con) { @@ -1359,7 +1326,7 @@ void container_discover_outputs(struct sway_container *con) { sway_log(SWAY_DEBUG, "Container %p entered output %p", con, output); if (con->view) { view_for_each_surface(con->view, - surface_send_enter_iterator, output->wlr_output); + surface_send_enter_iterator, output); if (con->view->foreign_toplevel) { wlr_foreign_toplevel_handle_v1_output_enter( con->view->foreign_toplevel, output->wlr_output); @@ -1371,7 +1338,7 @@ void container_discover_outputs(struct sway_container *con) { sway_log(SWAY_DEBUG, "Container %p left output %p", con, output); if (con->view) { view_for_each_surface(con->view, - surface_send_leave_iterator, output->wlr_output); + surface_send_leave_iterator, output); if (con->view->foreign_toplevel) { wlr_foreign_toplevel_handle_v1_output_leave( con->view->foreign_toplevel, output->wlr_output); @@ -1412,9 +1379,6 @@ list_t *container_get_siblings(struct sway_container *container) { if (container->pending.parent) { return container->pending.parent->pending.children; } - if (container_is_scratchpad_hidden(container)) { - return NULL; - } if (!container->pending.workspace) { return NULL; } @@ -1827,3 +1791,177 @@ int container_squash(struct sway_container *con) { } return change; } + +static void swap_places(struct sway_container *con1, + struct sway_container *con2) { + struct sway_container *temp = malloc(sizeof(struct sway_container)); + temp->pending.x = con1->pending.x; + temp->pending.y = con1->pending.y; + temp->pending.width = con1->pending.width; + temp->pending.height = con1->pending.height; + temp->width_fraction = con1->width_fraction; + temp->height_fraction = con1->height_fraction; + temp->pending.parent = con1->pending.parent; + temp->pending.workspace = con1->pending.workspace; + bool temp_floating = container_is_floating(con1); + + con1->pending.x = con2->pending.x; + con1->pending.y = con2->pending.y; + con1->pending.width = con2->pending.width; + con1->pending.height = con2->pending.height; + con1->width_fraction = con2->width_fraction; + con1->height_fraction = con2->height_fraction; + + con2->pending.x = temp->pending.x; + con2->pending.y = temp->pending.y; + con2->pending.width = temp->pending.width; + con2->pending.height = temp->pending.height; + con2->width_fraction = temp->width_fraction; + con2->height_fraction = temp->height_fraction; + + int temp_index = container_sibling_index(con1); + if (con2->pending.parent) { + container_insert_child(con2->pending.parent, con1, + container_sibling_index(con2)); + } else if (container_is_floating(con2)) { + workspace_add_floating(con2->pending.workspace, con1); + } else { + workspace_insert_tiling(con2->pending.workspace, con1, + container_sibling_index(con2)); + } + if (temp->pending.parent) { + container_insert_child(temp->pending.parent, con2, temp_index); + } else if (temp_floating) { + workspace_add_floating(temp->pending.workspace, con2); + } else { + workspace_insert_tiling(temp->pending.workspace, con2, temp_index); + } + + free(temp); +} + +static void swap_focus(struct sway_container *con1, + struct sway_container *con2, struct sway_seat *seat, + struct sway_container *focus) { + if (focus == con1 || focus == con2) { + struct sway_workspace *ws1 = con1->pending.workspace; + struct sway_workspace *ws2 = con2->pending.workspace; + enum sway_container_layout layout1 = container_parent_layout(con1); + enum sway_container_layout layout2 = container_parent_layout(con2); + if (focus == con1 && (layout2 == L_TABBED || layout2 == L_STACKED)) { + if (workspace_is_visible(ws2)) { + seat_set_focus(seat, &con2->node); + } + seat_set_focus_container(seat, ws1 != ws2 ? con2 : con1); + } else if (focus == con2 && (layout1 == L_TABBED + || layout1 == L_STACKED)) { + if (workspace_is_visible(ws1)) { + seat_set_focus(seat, &con1->node); + } + seat_set_focus_container(seat, ws1 != ws2 ? con1 : con2); + } else if (ws1 != ws2) { + seat_set_focus_container(seat, focus == con1 ? con2 : con1); + } else { + seat_set_focus_container(seat, focus); + } + } else { + seat_set_focus_container(seat, focus); + } + + if (root->fullscreen_global) { + seat_set_focus(seat, + seat_get_focus_inactive(seat, &root->fullscreen_global->node)); + } +} + +void container_swap(struct sway_container *con1, struct sway_container *con2) { + if (!sway_assert(con1 && con2, "Cannot swap with nothing")) { + return; + } + if (!sway_assert(!container_has_ancestor(con1, con2) + && !container_has_ancestor(con2, con1), + "Cannot swap ancestor and descendant")) { + return; + } + + sway_log(SWAY_DEBUG, "Swapping containers %zu and %zu", + con1->node.id, con2->node.id); + + bool scratch1 = con1->scratchpad; + bool hidden1 = container_is_scratchpad_hidden(con1); + bool scratch2 = con2->scratchpad; + bool hidden2 = container_is_scratchpad_hidden(con2); + if (scratch1) { + if (hidden1) { + root_scratchpad_show(con1); + } + root_scratchpad_remove_container(con1); + } + if (scratch2) { + if (hidden2) { + root_scratchpad_show(con2); + } + root_scratchpad_remove_container(con2); + } + + enum sway_fullscreen_mode fs1 = con1->pending.fullscreen_mode; + if (fs1) { + container_fullscreen_disable(con1); + } + enum sway_fullscreen_mode fs2 = con2->pending.fullscreen_mode; + if (fs2) { + container_fullscreen_disable(con2); + } + + struct sway_seat *seat = input_manager_current_seat(); + struct sway_container *focus = seat_get_focused_container(seat); + struct sway_workspace *vis1 = + output_get_active_workspace(con1->pending.workspace->output); + struct sway_workspace *vis2 = + output_get_active_workspace(con2->pending.workspace->output); + if (!sway_assert(vis1 && vis2, "con1 or con2 are on an output without a" + "workspace. This should not happen")) { + return; + } + + char *stored_prev_name = NULL; + if (seat->prev_workspace_name) { + stored_prev_name = strdup(seat->prev_workspace_name); + } + + swap_places(con1, con2); + + if (!workspace_is_visible(vis1)) { + seat_set_focus(seat, seat_get_focus_inactive(seat, &vis1->node)); + } + if (!workspace_is_visible(vis2)) { + seat_set_focus(seat, seat_get_focus_inactive(seat, &vis2->node)); + } + + swap_focus(con1, con2, seat, focus); + + if (stored_prev_name) { + free(seat->prev_workspace_name); + seat->prev_workspace_name = stored_prev_name; + } + + if (scratch1) { + root_scratchpad_add_container(con2, NULL); + if (!hidden1) { + root_scratchpad_show(con2); + } + } + if (scratch2) { + root_scratchpad_add_container(con1, NULL); + if (!hidden2) { + root_scratchpad_show(con1); + } + } + + if (fs1) { + container_set_fullscreen(con2, fs1); + } + if (fs2) { + container_set_fullscreen(con1, fs2); + } +} |