diff options
Diffstat (limited to 'sway/tree')
-rw-r--r-- | sway/tree/container.c | 125 | ||||
-rw-r--r-- | sway/tree/output.c | 15 | ||||
-rw-r--r-- | sway/tree/root.c | 8 | ||||
-rw-r--r-- | sway/tree/view.c | 43 | ||||
-rw-r--r-- | sway/tree/workspace.c | 46 |
5 files changed, 176 insertions, 61 deletions
diff --git a/sway/tree/container.c b/sway/tree/container.c index 6a01eab3..79e04ec0 100644 --- a/sway/tree/container.c +++ b/sway/tree/container.c @@ -5,8 +5,12 @@ #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/render/drm_format_set.h> +#include "linux-dmabuf-unstable-v1-protocol.h" #include "cairo_util.h" #include "pango.h" #include "sway/config.h" @@ -64,6 +68,7 @@ void container_destroy(struct sway_container *con) { wlr_texture_destroy(con->title_focused_inactive); wlr_texture_destroy(con->title_unfocused); wlr_texture_destroy(con->title_urgent); + wlr_texture_destroy(con->title_focused_tab_title); list_free(con->pending.children); list_free(con->current.children); list_free(con->outputs); @@ -73,11 +78,10 @@ void container_destroy(struct sway_container *con) { wlr_texture_destroy(con->marks_focused_inactive); wlr_texture_destroy(con->marks_unfocused); wlr_texture_destroy(con->marks_urgent); + wlr_texture_destroy(con->marks_focused_tab_title); - if (con->view) { - if (con->view->container == con) { - con->view->container = NULL; - } + if (con->view && con->view->container == con) { + con->view->container = NULL; if (con->view->destroying) { view_destroy(con->view); } @@ -382,19 +386,17 @@ struct sway_container *tiling_container_at(struct sway_node *parent, } static bool surface_is_popup(struct wlr_surface *surface) { - if (wlr_surface_is_xdg_surface(surface)) { - struct wlr_xdg_surface *xdg_surface = - wlr_xdg_surface_from_wlr_surface(surface); - while (xdg_surface && xdg_surface->role != WLR_XDG_SURFACE_ROLE_NONE) { - if (xdg_surface->role == WLR_XDG_SURFACE_ROLE_POPUP) { - return true; - } - xdg_surface = xdg_surface->toplevel->parent; + while (!wlr_surface_is_xdg_surface(surface)) { + if (!wlr_surface_is_subsurface(surface)) { + return false; } - return false; + struct wlr_subsurface *subsurface = + wlr_subsurface_from_wlr_surface(surface); + surface = subsurface->parent; } - - return false; + struct wlr_xdg_surface *xdg_surface = + wlr_xdg_surface_from_wlr_surface(surface); + return xdg_surface->role == WLR_XDG_SURFACE_ROLE_POPUP; } struct sway_container *container_at(struct sway_workspace *workspace, @@ -532,6 +534,13 @@ static void render_titlebar_text_texture(struct sway_output *output, cairo_surface_t *surface = cairo_image_surface_create( CAIRO_FORMAT_ARGB32, width, height); + cairo_status_t status = cairo_surface_status(surface); + if (status != CAIRO_STATUS_SUCCESS) { + sway_log(SWAY_ERROR, "cairo_image_surface_create failed: %s", + cairo_status_to_string(status)); + return; + } + cairo_t *cairo = cairo_create(surface); cairo_set_antialias(cairo, CAIRO_ANTIALIAS_BEST); cairo_set_font_options(cairo, fo); @@ -549,8 +558,7 @@ static void render_titlebar_text_texture(struct sway_output *output, cairo_surface_flush(surface); unsigned char *data = cairo_image_surface_get_data(surface); int stride = cairo_image_surface_get_stride(surface); - struct wlr_renderer *renderer = wlr_backend_get_renderer( - output->wlr_output->backend); + struct wlr_renderer *renderer = output->wlr_output->renderer; *texture = wlr_texture_from_pixels( renderer, DRM_FORMAT_ARGB8888, stride, width, height, data); cairo_surface_destroy(surface); @@ -585,6 +593,8 @@ void container_update_title_textures(struct sway_container *container) { &config->border_colors.unfocused); update_title_texture(container, &container->title_urgent, &config->border_colors.urgent); + update_title_texture(container, &container->title_focused_tab_title, + &config->border_colors.focused_tab_title); container_damage_whole(container); } @@ -1050,6 +1060,16 @@ 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; @@ -1061,6 +1081,75 @@ static void set_fullscreen(struct sway_container *con, bool enable) { con->view->foreign_toplevel, enable); } } + + if (!server.linux_dmabuf_v1 || !con->view->surface) { + return; + } + if (!enable) { + wlr_linux_dmabuf_v1_set_surface_feedback(server.linux_dmabuf_v1, + con->view->surface, NULL); + return; + } + + if (!con->pending.workspace || !con->pending.workspace->output) { + return; + } + + 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.renderer); + assert(renderer_formats); + + int renderer_drm_fd = wlr_renderer_get_drm_fd(server.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 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); } static void container_fullscreen_workspace(struct sway_container *con) { @@ -1638,6 +1727,8 @@ void container_update_marks_textures(struct sway_container *con) { &config->border_colors.unfocused); update_marks_texture(con, &con->marks_urgent, &config->border_colors.urgent); + update_marks_texture(con, &con->marks_focused_tab_title, + &config->border_colors.focused_tab_title); container_damage_whole(con); } diff --git a/sway/tree/output.c b/sway/tree/output.c index c095dce0..ad8d2482 100644 --- a/sway/tree/output.c +++ b/sway/tree/output.c @@ -56,8 +56,8 @@ static void restore_workspaces(struct sway_output *output) { } // Saved workspaces - while (root->noop_output->workspaces->length) { - struct sway_workspace *ws = root->noop_output->workspaces->items[0]; + while (root->fallback_output->workspaces->length) { + struct sway_workspace *ws = root->fallback_output->workspaces->items[0]; workspace_detach(ws); output_add_workspace(output, ws); @@ -95,7 +95,7 @@ struct sway_output *output_create(struct wlr_output *wlr_output) { output->detected_subpixel = wlr_output->subpixel; output->scale_filter = SCALE_FILTER_NEAREST; - wl_signal_init(&output->events.destroy); + wl_signal_init(&output->events.disable); wl_list_insert(&root->all_outputs, &output->link); @@ -192,7 +192,7 @@ static void output_evacuate(struct sway_output *output) { new_output = fallback_output; } if (!new_output) { - new_output = root->noop_output; + new_output = root->fallback_output; } struct sway_workspace *new_output_ws = @@ -262,7 +262,7 @@ void output_disable(struct sway_output *output) { } sway_log(SWAY_DEBUG, "Disabling output '%s'", output->wlr_output->name); - wl_signal_emit(&output->events.destroy, output); + wl_signal_emit(&output->events.disable, output); output_evacuate(output); @@ -286,13 +286,10 @@ void output_begin_destroy(struct sway_output *output) { return; } sway_log(SWAY_DEBUG, "Destroying output '%s'", output->wlr_output->name); + wl_signal_emit(&output->node.events.destroy, &output->node); output->node.destroying = true; node_set_dirty(&output->node); - - wl_list_remove(&output->link); - output->wlr_output->data = NULL; - output->wlr_output = NULL; } struct sway_output *output_from_wlr_output(struct wlr_output *output) { diff --git a/sway/tree/root.c b/sway/tree/root.c index dd4d8e33..73f3993c 100644 --- a/sway/tree/root.c +++ b/sway/tree/root.c @@ -374,8 +374,8 @@ void root_for_each_container(void (*f)(struct sway_container *con, void *data), } // Saved workspaces - for (int i = 0; i < root->noop_output->workspaces->length; ++i) { - struct sway_workspace *ws = root->noop_output->workspaces->items[i]; + for (int i = 0; i < root->fallback_output->workspaces->length; ++i) { + struct sway_workspace *ws = root->fallback_output->workspaces->items[i]; workspace_for_each_container(ws, f, data); } } @@ -427,8 +427,8 @@ struct sway_container *root_find_container( } // Saved workspaces - for (int i = 0; i < root->noop_output->workspaces->length; ++i) { - struct sway_workspace *ws = root->noop_output->workspaces->items[i]; + for (int i = 0; i < root->fallback_output->workspaces->length; ++i) { + struct sway_workspace *ws = root->fallback_output->workspaces->items[i]; if ((result = workspace_find_container(ws, test, data))) { return result; } diff --git a/sway/tree/view.c b/sway/tree/view.c index ed8c50f8..8b7061ba 100644 --- a/sway/tree/view.c +++ b/sway/tree/view.c @@ -752,10 +752,29 @@ void view_map(struct sway_view *view, struct wlr_surface *wlr_surface, } struct sway_seat *seat = input_manager_current_seat(); - struct sway_node *node = ws ? seat_get_focus_inactive(seat, &ws->node) - : seat_get_focus_inactive(seat, &root->node); - struct sway_container *target_sibling = node->type == N_CONTAINER ? - node->sway_container : NULL; + struct sway_node *node = + seat_get_focus_inactive(seat, ws ? &ws->node : &root->node); + struct sway_container *target_sibling = NULL; + if (node && node->type == N_CONTAINER) { + if (container_is_floating(node->sway_container)) { + // If we're about to launch the view into the floating container, then + // launch it as a tiled view instead. + if (ws) { + target_sibling = seat_get_focus_inactive_tiling(seat, ws); + if (target_sibling) { + struct sway_container *con = + seat_get_focus_inactive_view(seat, &target_sibling->node); + if (con) { + target_sibling = con; + } + } + } else { + ws = seat_get_last_known_workspace(seat); + } + } else { + target_sibling = node->sway_container; + } + } view->foreign_toplevel = wlr_foreign_toplevel_handle_v1_create(server.foreign_toplevel_manager); @@ -776,13 +795,6 @@ void view_map(struct sway_view *view, struct wlr_surface *wlr_surface, &view->foreign_minimize); - // If we're about to launch the view into the floating container, then - // launch it as a tiled view in the root of the workspace instead. - if (target_sibling && container_is_floating(target_sibling)) { - target_sibling = NULL; - ws = seat_get_last_known_workspace(seat); - } - struct sway_container *container = view->container; if (target_sibling) { container_add_sibling(target_sibling, container, 1); @@ -1129,9 +1141,12 @@ void view_child_init(struct sway_view_child *child, wl_signal_add(&view->events.unmap, &child->view_unmap); child->view_unmap.notify = view_child_handle_view_unmap; - struct sway_workspace *workspace = child->view->container->pending.workspace; - if (workspace) { - wlr_surface_send_enter(child->surface, workspace->output->wlr_output); + struct sway_container *container = child->view->container; + if (container != NULL) { + struct sway_workspace *workspace = container->pending.workspace; + if (workspace) { + wlr_surface_send_enter(child->surface, workspace->output->wlr_output); + } } view_child_init_subsurfaces(child, surface); diff --git a/sway/tree/workspace.c b/sway/tree/workspace.c index 8dd7789d..c84320bd 100644 --- a/sway/tree/workspace.c +++ b/sway/tree/workspace.c @@ -50,8 +50,8 @@ struct sway_output *workspace_get_initial_output(const char *name) { } else if (focus && focus->type == N_CONTAINER) { return focus->sway_container->pending.workspace->output; } - // Fallback to the first output or noop output for headless - return root->outputs->length ? root->outputs->items[0] : root->noop_output; + // Fallback to the first output or the headless output + return root->outputs->length ? root->outputs->items[0] : root->fallback_output; } struct sway_workspace *workspace_create(struct sway_output *output, @@ -844,24 +844,36 @@ struct sway_container *workspace_insert_tiling(struct sway_workspace *workspace, return con; } +bool workspace_has_single_visible_container(struct sway_workspace *ws) { + struct sway_seat *seat = input_manager_get_default_seat(); + struct sway_container *focus = + seat_get_focus_inactive_tiling(seat, ws); + if (focus && !focus->view) { + focus = seat_get_focus_inactive_view(seat, &focus->node); + } + return (focus && focus->view && view_ancestor_is_only_visible(focus->view)); +} + void workspace_add_gaps(struct sway_workspace *ws) { - if (config->smart_gaps) { - struct sway_seat *seat = input_manager_get_default_seat(); - struct sway_container *focus = - seat_get_focus_inactive_tiling(seat, ws); - if (focus && !focus->view) { - focus = seat_get_focus_inactive_view(seat, &focus->node); - } - if (focus && focus->view && view_ancestor_is_only_visible(focus->view)) { - ws->current_gaps.top = 0; - ws->current_gaps.right = 0; - ws->current_gaps.bottom = 0; - ws->current_gaps.left = 0; - return; - } + if (config->smart_gaps == SMART_GAPS_ON + && workspace_has_single_visible_container(ws)) { + ws->current_gaps.top = 0; + ws->current_gaps.right = 0; + ws->current_gaps.bottom = 0; + ws->current_gaps.left = 0; + return; + } + + if (config->smart_gaps == SMART_GAPS_INVERSE_OUTER + && !workspace_has_single_visible_container(ws)) { + ws->current_gaps.top = 0; + ws->current_gaps.right = 0; + ws->current_gaps.bottom = 0; + ws->current_gaps.left = 0; + } else { + ws->current_gaps = ws->gaps_outer; } - ws->current_gaps = ws->gaps_outer; // Add inner gaps and make sure we don't turn out negative ws->current_gaps.top = fmax(0, ws->current_gaps.top + ws->gaps_inner); ws->current_gaps.right = fmax(0, ws->current_gaps.right + ws->gaps_inner); |