aboutsummaryrefslogtreecommitdiff
path: root/sway/desktop
diff options
context:
space:
mode:
authorRyan Dwyer <ryandwyer1@gmail.com>2018-05-24 22:30:44 +1000
committerRyan Dwyer <ryandwyer1@gmail.com>2018-06-01 23:14:58 +1000
commit1f2e399ade77070a2d0b82856ad9a3eef96b8676 (patch)
treec469197e140051aea912cb173723c7e55ce1e410 /sway/desktop
parent1132efe42e8086216c7bab6b405d09a22231dde5 (diff)
Implement floating
Diffstat (limited to 'sway/desktop')
-rw-r--r--sway/desktop/output.c114
-rw-r--r--sway/desktop/xdg_shell.c32
-rw-r--r--sway/desktop/xdg_shell_v6.c32
-rw-r--r--sway/desktop/xwayland.c97
4 files changed, 233 insertions, 42 deletions
diff --git a/sway/desktop/output.c b/sway/desktop/output.c
index 95479819..1d21e80f 100644
--- a/sway/desktop/output.c
+++ b/sway/desktop/output.c
@@ -754,9 +754,87 @@ static void render_container(struct sway_output *output,
case L_TABBED:
render_container_tabbed(output, damage, con, parent_focused);
break;
- case L_FLOATING:
- // TODO
- break;
+ }
+}
+
+static bool floater_intersects_output(struct sway_container *floater,
+ struct sway_container *output) {
+ struct wlr_box box = {
+ .x = floater->x,
+ .y = floater->y,
+ .width = floater->width,
+ .height = floater->height,
+ };
+ return wlr_output_layout_intersects(root_container.sway_root->output_layout,
+ output->sway_output->wlr_output, &box);
+}
+
+static void container_translate(struct sway_container *con, int x, int y) {
+ con->x += x;
+ con->y += y;
+ if (con->type == C_VIEW) {
+ con->sway_view->x += x;
+ con->sway_view->y += y;
+ } else {
+ for (int i = 0; i < con->children->length; ++i) {
+ struct sway_container *child = con->children->items[i];
+ container_translate(child, x, y);
+ }
+ }
+}
+
+static void render_floating_container(struct sway_output *soutput,
+ pixman_region32_t *damage, struct sway_container *con) {
+ // We need to translate the floating container's coordinates from layout
+ // coordinates into output-local coordinates. This needs to happen for all
+ // children of the floating container too.
+ struct sway_container *output = container_parent(con, C_OUTPUT);
+ container_translate(con, -output->x, -output->y);
+
+ if (con->type == C_VIEW) {
+ struct sway_view *view = con->sway_view;
+ struct sway_seat *seat = input_manager_current_seat(input_manager);
+ struct sway_container *focus = seat_get_focus(seat);
+ struct border_colors *colors;
+ struct wlr_texture *title_texture;
+ struct wlr_texture *marks_texture;
+
+ if (focus == con) {
+ colors = &config->border_colors.focused;
+ title_texture = con->title_focused;
+ marks_texture = view->marks_focused;
+ } else {
+ colors = &config->border_colors.unfocused;
+ title_texture = con->title_unfocused;
+ marks_texture = view->marks_unfocused;
+ }
+ render_titlebar(soutput, damage, con, con->x, con->y, con->width,
+ colors, title_texture, marks_texture);
+ render_view(soutput, damage, con, colors);
+ } else {
+ render_container(soutput, damage, con, false);
+ }
+ // Undo the translation
+ container_translate(con, output->x, output->y);
+}
+
+static void render_floating(struct sway_output *soutput,
+ pixman_region32_t *damage) {
+ for (int i = 0; i < root_container.children->length; ++i) {
+ struct sway_container *output = root_container.children->items[i];
+ for (int j = 0; j < output->children->length; ++j) {
+ struct sway_container *workspace = output->children->items[j];
+ struct sway_workspace *ws = workspace->sway_workspace;
+ bool ws_is_visible = workspace_is_visible(workspace);
+ for (int k = 0; k < ws->floating->children->length; ++k) {
+ struct sway_container *floater =
+ ws->floating->children->items[k];
+ if ((ws_is_visible || floater->is_sticky)
+ && floater_intersects_output(floater, soutput->swayc)) {
+ render_floating_container(soutput, damage, floater);
+ }
+ }
+ }
}
}
@@ -794,8 +872,6 @@ static void render_output(struct sway_output *output, struct timespec *when,
goto renderer_end;
}
- //wlr_renderer_clear(renderer, (float[]){1, 1, 0, 1});
-
struct sway_container *workspace = output_get_active_workspace(output);
if (workspace->sway_workspace->fullscreen) {
@@ -818,7 +894,6 @@ static void render_output(struct sway_output *output, struct timespec *when,
}
} else {
float clear_color[] = {0.25f, 0.25f, 0.25f, 1.0f};
- wlr_renderer_clear(renderer, clear_color);
int nrects;
pixman_box32_t *rects = pixman_region32_rectangles(damage, &nrects);
@@ -840,6 +915,8 @@ static void render_output(struct sway_output *output, struct timespec *when,
&root_container.sway_root->xwayland_unmanaged);
render_layer(output, damage,
&output->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP]);
+
+ render_floating(output, damage);
}
render_layer(output, damage,
&output->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY]);
@@ -916,6 +993,7 @@ static void send_frame_done(struct sway_output *output, struct timespec *when) {
struct sway_container *workspace = output_get_active_workspace(output);
send_frame_done_container(&data, workspace);
+ send_frame_done_container(&data, workspace->sway_workspace->floating);
send_frame_done_unmanaged(&data,
&root_container.sway_root->xwayland_unmanaged);
@@ -1037,7 +1115,15 @@ static void output_damage_view(struct sway_output *output,
void output_damage_from_view(struct sway_output *output,
struct sway_view *view) {
- output_damage_view(output, view, false);
+ if (container_self_or_parent_floating(view->swayc)) {
+ view->x -= output->swayc->x;
+ view->y -= output->swayc->y;
+ output_damage_view(output, view, false);
+ view->x += output->swayc->x;
+ view->y += output->swayc->y;
+ } else {
+ output_damage_view(output, view, false);
+ }
}
static void output_damage_whole_container_iterator(struct sway_container *con,
@@ -1053,13 +1139,17 @@ static void output_damage_whole_container_iterator(struct sway_container *con,
void output_damage_whole_container(struct sway_output *output,
struct sway_container *con) {
- float scale = output->wlr_output->scale;
struct wlr_box box = {
- .x = con->x * scale,
- .y = con->y * scale,
- .width = con->width * scale,
- .height = con->height * scale,
+ .x = con->x,
+ .y = con->y,
+ .width = con->width,
+ .height = con->height,
};
+ if (con->is_floating) {
+ box.x -= output->wlr_output->lx;
+ box.y -= output->wlr_output->ly;
+ }
+ scale_box(&box, output->wlr_output->scale);
wlr_output_damage_add_box(output->damage, &box);
if (con->type == C_VIEW) {
diff --git a/sway/desktop/xdg_shell.c b/sway/desktop/xdg_shell.c
index b2b95fa0..e1a73b20 100644
--- a/sway/desktop/xdg_shell.c
+++ b/sway/desktop/xdg_shell.c
@@ -98,6 +98,7 @@ static void configure(struct sway_view *view, double ox, double oy, int width,
xdg_shell_view->pending_width = width;
xdg_shell_view->pending_height = height;
wlr_xdg_toplevel_set_size(view->wlr_xdg_surface, width, height);
+ view_update_position(view, ox, oy);
}
static void set_activated(struct sway_view *view, bool activated) {
@@ -110,6 +111,14 @@ static void set_activated(struct sway_view *view, bool activated) {
}
}
+static void set_maximized(struct sway_view *view, bool maximized) {
+ if (xdg_shell_view_from_view(view) == NULL) {
+ return;
+ }
+ struct wlr_xdg_surface *surface = view->wlr_xdg_surface;
+ wlr_xdg_toplevel_set_maximized(surface, maximized);
+}
+
static void set_fullscreen(struct sway_view *view, bool fullscreen) {
if (xdg_shell_view_from_view(view) == NULL) {
return;
@@ -118,6 +127,11 @@ static void set_fullscreen(struct sway_view *view, bool fullscreen) {
wlr_xdg_toplevel_set_fullscreen(surface, fullscreen);
}
+static bool wants_floating(struct sway_view *view) {
+ // TODO
+ return false;
+}
+
static void for_each_surface(struct sway_view *view,
wlr_surface_iterator_func_t iterator, void *user_data) {
if (xdg_shell_view_from_view(view) == NULL) {
@@ -154,7 +168,9 @@ static const struct sway_view_impl view_impl = {
.get_string_prop = get_string_prop,
.configure = configure,
.set_activated = set_activated,
+ .set_maximized = set_maximized,
.set_fullscreen = set_fullscreen,
+ .wants_floating = wants_floating,
.for_each_surface = for_each_surface,
.close = _close,
.destroy = destroy,
@@ -164,11 +180,17 @@ static void handle_commit(struct wl_listener *listener, void *data) {
struct sway_xdg_shell_view *xdg_shell_view =
wl_container_of(listener, xdg_shell_view, commit);
struct sway_view *view = &xdg_shell_view->view;
- // NOTE: We intentionally discard the view's desired width here
- // TODO: Store this for restoration when moving to floating plane
- // TODO: Let floating views do whatever
- view_update_size(view, xdg_shell_view->pending_width,
- xdg_shell_view->pending_height);
+ struct wlr_box *geometry = &view->wlr_xdg_surface->geometry;
+ if (!view->natural_width && !view->natural_height) {
+ view->natural_width = geometry->width;
+ view->natural_height = geometry->height;
+ }
+ if (view->swayc && view->swayc->is_floating) {
+ view_update_size(view, geometry->width, geometry->height);
+ } else {
+ view_update_size(view, xdg_shell_view->pending_width,
+ xdg_shell_view->pending_height);
+ }
view_update_title(view, false);
view_damage_from(view);
}
diff --git a/sway/desktop/xdg_shell_v6.c b/sway/desktop/xdg_shell_v6.c
index d098c797..47e4162a 100644
--- a/sway/desktop/xdg_shell_v6.c
+++ b/sway/desktop/xdg_shell_v6.c
@@ -97,6 +97,7 @@ static void configure(struct sway_view *view, double ox, double oy, int width,
xdg_shell_v6_view->pending_width = width;
xdg_shell_v6_view->pending_height = height;
wlr_xdg_toplevel_v6_set_size(view->wlr_xdg_surface_v6, width, height);
+ view_update_position(view, ox, oy);
}
static void set_activated(struct sway_view *view, bool activated) {
@@ -109,6 +110,14 @@ static void set_activated(struct sway_view *view, bool activated) {
}
}
+static void set_maximized(struct sway_view *view, bool maximized) {
+ if (xdg_shell_v6_view_from_view(view) == NULL) {
+ return;
+ }
+ struct wlr_xdg_surface_v6 *surface = view->wlr_xdg_surface_v6;
+ wlr_xdg_toplevel_v6_set_maximized(surface, maximized);
+}
+
static void set_fullscreen(struct sway_view *view, bool fullscreen) {
if (xdg_shell_v6_view_from_view(view) == NULL) {
return;
@@ -117,6 +126,11 @@ static void set_fullscreen(struct sway_view *view, bool fullscreen) {
wlr_xdg_toplevel_v6_set_fullscreen(surface, fullscreen);
}
+static bool wants_floating(struct sway_view *view) {
+ // TODO
+ return false;
+}
+
static void for_each_surface(struct sway_view *view,
wlr_surface_iterator_func_t iterator, void *user_data) {
if (xdg_shell_v6_view_from_view(view) == NULL) {
@@ -153,7 +167,9 @@ static const struct sway_view_impl view_impl = {
.get_string_prop = get_string_prop,
.configure = configure,
.set_activated = set_activated,
+ .set_maximized = set_maximized,
.set_fullscreen = set_fullscreen,
+ .wants_floating = wants_floating,
.for_each_surface = for_each_surface,
.close = _close,
.destroy = destroy,
@@ -163,11 +179,17 @@ static void handle_commit(struct wl_listener *listener, void *data) {
struct sway_xdg_shell_v6_view *xdg_shell_v6_view =
wl_container_of(listener, xdg_shell_v6_view, commit);
struct sway_view *view = &xdg_shell_v6_view->view;
- // NOTE: We intentionally discard the view's desired width here
- // TODO: Store this for restoration when moving to floating plane
- // TODO: Let floating views do whatever
- view_update_size(view, xdg_shell_v6_view->pending_width,
- xdg_shell_v6_view->pending_height);
+ struct wlr_box *geometry = &view->wlr_xdg_surface_v6->geometry;
+ if (!view->natural_width && !view->natural_height) {
+ view->natural_width = geometry->width;
+ view->natural_height = geometry->height;
+ }
+ if (view->swayc && view->swayc->is_floating) {
+ view_update_size(view, geometry->width, geometry->height);
+ } else {
+ view_update_size(view, xdg_shell_v6_view->pending_width,
+ xdg_shell_v6_view->pending_height);
+ }
view_update_title(view, false);
view_damage_from(view);
}
diff --git a/sway/desktop/xwayland.c b/sway/desktop/xwayland.c
index 6a99a66a..56cac1bd 100644
--- a/sway/desktop/xwayland.c
+++ b/sway/desktop/xwayland.c
@@ -152,7 +152,9 @@ static uint32_t get_int_prop(struct sway_view *view, enum sway_view_prop prop) {
}
}
-static void configure(struct sway_view *view, double ox, double oy, int width,
+// The x and y arguments are output-local for tiled views, and layout
+// coordinates for floating views.
+static void configure(struct sway_view *view, double x, double y, int width,
int height) {
struct sway_xwayland_view *xwayland_view = xwayland_view_from_view(view);
if (xwayland_view == NULL) {
@@ -160,25 +162,33 @@ static void configure(struct sway_view *view, double ox, double oy, int width,
}
struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface;
- struct sway_container *output = container_parent(view->swayc, C_OUTPUT);
- if (!sway_assert(output, "view must be within tree to set position")) {
- return;
- }
- struct sway_container *root = container_parent(output, C_ROOT);
- if (!sway_assert(root, "output must be within tree to set position")) {
- return;
- }
- struct wlr_output_layout *layout = root->sway_root->output_layout;
- struct wlr_output_layout_output *loutput =
- wlr_output_layout_get(layout, output->sway_output->wlr_output);
- if (!sway_assert(loutput, "output must be within layout to set position")) {
- return;
+ double lx, ly;
+ if (view->swayc->is_floating) {
+ lx = x;
+ ly = y;
+ } else {
+ struct sway_container *output = container_parent(view->swayc, C_OUTPUT);
+ if (!sway_assert(output, "view must be within tree to set position")) {
+ return;
+ }
+ struct sway_container *root = container_parent(output, C_ROOT);
+ if (!sway_assert(root, "output must be within tree to set position")) {
+ return;
+ }
+ struct wlr_output_layout *layout = root->sway_root->output_layout;
+ struct wlr_output_layout_output *loutput =
+ wlr_output_layout_get(layout, output->sway_output->wlr_output);
+ if (!sway_assert(loutput,
+ "output must be within layout to set position")) {
+ return;
+ }
+ lx = x + loutput->x;
+ ly = y + loutput->y;
}
xwayland_view->pending_width = width;
xwayland_view->pending_height = height;
- wlr_xwayland_surface_configure(xsurface, ox + loutput->x, oy + loutput->y,
- width, height);
+ wlr_xwayland_surface_configure(xsurface, lx, ly, width, height);
}
static void set_activated(struct sway_view *view, bool activated) {
@@ -189,6 +199,14 @@ static void set_activated(struct sway_view *view, bool activated) {
wlr_xwayland_surface_activate(surface, activated);
}
+static void set_maximized(struct sway_view *view, bool maximized) {
+ if (xwayland_view_from_view(view) == NULL) {
+ return;
+ }
+ struct wlr_xwayland_surface *surface = view->wlr_xwayland_surface;
+ wlr_xwayland_surface_set_maximized(surface, maximized);
+}
+
static void set_fullscreen(struct sway_view *view, bool fullscreen) {
if (xwayland_view_from_view(view) == NULL) {
return;
@@ -197,6 +215,35 @@ static void set_fullscreen(struct sway_view *view, bool fullscreen) {
wlr_xwayland_surface_set_fullscreen(surface, fullscreen);
}
+static bool wants_floating(struct sway_view *view) {
+ // TODO:
+ // We want to return true if the window type contains any of these:
+ // NET_WM_WINDOW_TYPE_DIALOG
+ // NET_WM_WINDOW_TYPE_UTILITY
+ // NET_WM_WINDOW_TYPE_TOOLBAR
+ // NET_WM_WINDOW_TYPE_SPLASH
+ //
+ // We also want to return true if the NET_WM_STATE is MODAL.
+ // wlroots doesn't appear to provide all this information at the moment.
+ struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface;
+ uint32_t *atom = xsurface->window_type;
+ for (size_t i = 0; i < xsurface->window_type_len; ++i) {
+ wlr_log(L_DEBUG, "xwayland window type %i", *atom);
+ // TODO: Come up with a better way of doing this
+ switch (*atom) {
+ case 36: // NET_WM_WINDOW_TYPE_UTILITY
+ case 44: // NET_WM_WINDOW_TYPE_SPLASH
+ case 276: // ? PGP passphrase dialog
+ case 337: // ? Firefox open file dialog
+ case 338: // ? Firefox open file dialog
+ return true;
+ }
+ ++atom;
+ }
+
+ return false;
+}
+
static void _close(struct sway_view *view) {
if (xwayland_view_from_view(view) == NULL) {
return;
@@ -225,7 +272,9 @@ static const struct sway_view_impl view_impl = {
.get_int_prop = get_int_prop,
.configure = configure,
.set_activated = set_activated,
+ .set_maximized = set_maximized,
.set_fullscreen = set_fullscreen,
+ .wants_floating = wants_floating,
.close = _close,
.destroy = destroy,
};
@@ -234,10 +283,18 @@ static void handle_commit(struct wl_listener *listener, void *data) {
struct sway_xwayland_view *xwayland_view =
wl_container_of(listener, xwayland_view, commit);
struct sway_view *view = &xwayland_view->view;
- // NOTE: We intentionally discard the view's desired width here
- // TODO: Let floating views do whatever
- view_update_size(view, xwayland_view->pending_width,
- xwayland_view->pending_height);
+ struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface;
+ if (!view->natural_width && !view->natural_height) {
+ view->natural_width = xsurface->width;
+ view->natural_height = xsurface->height;
+ }
+ if (view->swayc && view->swayc->is_floating) {
+ view_update_size(view, xsurface->width, xsurface->height);
+ view_update_position(view, xsurface->x, xsurface->y);
+ } else {
+ view_update_size(view, xwayland_view->pending_width,
+ xwayland_view->pending_height);
+ }
view_damage_from(view);
}