summaryrefslogtreecommitdiff
path: root/sway/tree
diff options
context:
space:
mode:
Diffstat (limited to 'sway/tree')
-rw-r--r--sway/tree/container.c125
-rw-r--r--sway/tree/output.c15
-rw-r--r--sway/tree/root.c8
-rw-r--r--sway/tree/view.c43
-rw-r--r--sway/tree/workspace.c46
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);