aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRyan Dwyer <ryandwyer1@gmail.com>2018-04-16 20:36:40 +1000
committerRyan Dwyer <ryandwyer1@gmail.com>2018-04-16 20:36:40 +1000
commit52420cc24d61db8d22cf0d391f1f84b37bf087d5 (patch)
treef975a3708c0d1562a8d2fcdceaed9a76aadbf1f4
parentdbc36935ee857375669e7ab3d0f20f1b5b098d23 (diff)
Implement fullscreen.
-rw-r--r--include/sway/ipc-server.h1
-rw-r--r--include/sway/tree/container.h4
-rw-r--r--include/sway/tree/view.h9
-rw-r--r--sway/commands.c1
-rw-r--r--sway/commands/fullscreen.c40
-rw-r--r--sway/desktop/output.c24
-rw-r--r--sway/desktop/xdg_shell_v6.c26
-rw-r--r--sway/desktop/xwayland.c34
-rw-r--r--sway/input/seat.c14
-rw-r--r--sway/meson.build1
-rw-r--r--sway/tree/layout.c18
-rw-r--r--sway/tree/view.c40
12 files changed, 204 insertions, 8 deletions
diff --git a/include/sway/ipc-server.h b/include/sway/ipc-server.h
index c3389fe8..dd16a175 100644
--- a/include/sway/ipc-server.h
+++ b/include/sway/ipc-server.h
@@ -1,6 +1,7 @@
#ifndef _SWAY_IPC_SERVER_H
#define _SWAY_IPC_SERVER_H
#include <sys/socket.h>
+#include "sway/config.h"
#include "sway/tree/container.h"
#include "ipc.h"
diff --git a/include/sway/tree/container.h b/include/sway/tree/container.h
index 2a8b8aba..22bd7240 100644
--- a/include/sway/tree/container.h
+++ b/include/sway/tree/container.h
@@ -72,9 +72,13 @@ struct sway_container {
// For C_OUTPUT, this is the output position in layout coordinates
// For other types, this is the position in output-local coordinates
double x, y;
+ double saved_x, saved_y;
// does not include borders or gaps.
double width, height;
+ // For C_WORKSPACE only
+ struct sway_view *fullscreen;
+
list_t *children;
struct sway_container *parent;
diff --git a/include/sway/tree/view.h b/include/sway/tree/view.h
index b51c54b5..73d5f6c7 100644
--- a/include/sway/tree/view.h
+++ b/include/sway/tree/view.h
@@ -28,6 +28,7 @@ struct sway_view_impl {
void (*configure)(struct sway_view *view, double ox, double oy, int width,
int height);
void (*set_activated)(struct sway_view *view, bool activated);
+ void (*set_fullscreen)(struct sway_view *view, bool fullscreen);
void (*for_each_surface)(struct sway_view *view,
wlr_surface_iterator_func_t iterator, void *user_data);
void (*close)(struct sway_view *view);
@@ -41,6 +42,8 @@ struct sway_view {
struct sway_container *swayc; // NULL for unmanaged views
struct wlr_surface *surface; // NULL for unmapped views
int width, height;
+ int saved_width, saved_height;
+ bool is_fullscreen;
union {
struct wlr_xdg_surface_v6 *wlr_xdg_surface_v6;
@@ -63,6 +66,7 @@ struct sway_xdg_shell_v6_view {
struct wl_listener request_move;
struct wl_listener request_resize;
struct wl_listener request_maximize;
+ struct wl_listener request_fullscreen;
struct wl_listener new_popup;
struct wl_listener map;
struct wl_listener unmap;
@@ -79,6 +83,7 @@ struct sway_xwayland_view {
struct wl_listener request_resize;
struct wl_listener request_maximize;
struct wl_listener request_configure;
+ struct wl_listener request_fullscreen;
struct wl_listener map;
struct wl_listener unmap;
struct wl_listener destroy;
@@ -93,6 +98,7 @@ struct sway_xwayland_unmanaged {
int lx, ly;
struct wl_listener request_configure;
+ struct wl_listener request_fullscreen;
struct wl_listener commit;
struct wl_listener map;
struct wl_listener unmap;
@@ -106,6 +112,7 @@ struct sway_wl_shell_view {
struct wl_listener request_move;
struct wl_listener request_resize;
struct wl_listener request_maximize;
+ struct wl_listener request_fullscreen;
struct wl_listener destroy;
int pending_width, pending_height;
@@ -155,6 +162,8 @@ void view_configure(struct sway_view *view, double ox, double oy, int width,
void view_set_activated(struct sway_view *view, bool activated);
+void view_set_fullscreen(struct sway_view *view, bool fullscreen);
+
void view_close(struct sway_view *view);
void view_damage(struct sway_view *view, bool whole);
diff --git a/sway/commands.c b/sway/commands.c
index 99f42524..8ddc033b 100644
--- a/sway/commands.c
+++ b/sway/commands.c
@@ -99,6 +99,7 @@ static struct cmd_handler handlers[] = {
{ "exec", cmd_exec },
{ "exec_always", cmd_exec_always },
{ "focus_follows_mouse", cmd_focus_follows_mouse },
+ { "fullscreen", cmd_fullscreen },
{ "include", cmd_include },
{ "input", cmd_input },
{ "mode", cmd_mode },
diff --git a/sway/commands/fullscreen.c b/sway/commands/fullscreen.c
new file mode 100644
index 00000000..3e256282
--- /dev/null
+++ b/sway/commands/fullscreen.c
@@ -0,0 +1,40 @@
+#include <wlr/types/wlr_wl_shell.h>
+#include "log.h"
+#include "sway/commands.h"
+#include "sway/config.h"
+#include "sway/tree/container.h"
+#include "sway/tree/view.h"
+#include "sway/tree/layout.h"
+
+// fullscreen toggle|enable|disable
+struct cmd_results *cmd_fullscreen(int argc, char **argv) {
+ struct cmd_results *error = NULL;
+ if (config->reading) return cmd_results_new(CMD_FAILURE, "fullscreen", "Can't be used in config file.");
+ if (!config->active) return cmd_results_new(CMD_FAILURE, "fullscreen", "Can only be used when sway is running.");
+ if ((error = checkarg(argc, "fullscreen", EXPECTED_AT_LEAST, 1))) {
+ return error;
+ }
+ struct sway_container *container =
+ config->handler_context.current_container;
+ if (container->type != C_VIEW) {
+ return cmd_results_new(CMD_INVALID, "fullscreen",
+ "Only views can fullscreen");
+ }
+ struct sway_view *view = container->sway_view;
+ bool wants_fullscreen;
+
+ if (strcmp(argv[0], "enable") == 0) {
+ wants_fullscreen = true;
+ } else if (strcmp(argv[0], "disable") == 0) {
+ wants_fullscreen = false;
+ } else if (strcmp(argv[0], "toggle") == 0) {
+ wants_fullscreen = !view->is_fullscreen;
+ } else {
+ return cmd_results_new(CMD_INVALID, "fullscreen",
+ "Expected 'fullscreen <enable|disable|toggle>'");
+ }
+
+ view_set_fullscreen(view, wants_fullscreen);
+
+ return cmd_results_new(CMD_SUCCESS, NULL, NULL);
+}
diff --git a/sway/desktop/output.c b/sway/desktop/output.c
index 1b3143d0..b86f20e8 100644
--- a/sway/desktop/output.c
+++ b/sway/desktop/output.c
@@ -273,17 +273,25 @@ static void render_output(struct sway_output *output, struct timespec *when,
float clear_color[] = {0.25f, 0.25f, 0.25f, 1.0f};
wlr_renderer_clear(renderer, clear_color);
- render_layer(output, &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND]);
- render_layer(output, &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM]);
-
struct sway_container *workspace = output_get_active_workspace(output);
- render_container(output, workspace);
- render_unmanaged(output, &root_container.sway_root->xwayland_unmanaged);
+ if (workspace->fullscreen) {
+ wlr_output_set_fullscreen_surface(wlr_output,
+ workspace->fullscreen->surface);
+ } else {
+ wlr_output_set_fullscreen_surface(wlr_output, NULL);
+ render_layer(output,
+ &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND]);
+ render_layer(output, &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM]);
+
+ render_container(output, workspace);
- // TODO: consider revising this when fullscreen windows are supported
- render_layer(output, &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP]);
- render_layer(output, &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY]);
+ render_unmanaged(output, &root_container.sway_root->xwayland_unmanaged);
+
+ render_layer(output, &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP]);
+ render_layer(output,
+ &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY]);
+ }
renderer_end:
if (root_container.sway_root->debug_tree) {
diff --git a/sway/desktop/xdg_shell_v6.c b/sway/desktop/xdg_shell_v6.c
index e4703040..133b60c3 100644
--- a/sway/desktop/xdg_shell_v6.c
+++ b/sway/desktop/xdg_shell_v6.c
@@ -118,6 +118,14 @@ static void set_activated(struct sway_view *view, bool activated) {
}
}
+static void set_fullscreen(struct sway_view *view, bool fullscreen) {
+ 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_fullscreen(surface, fullscreen);
+}
+
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) {
@@ -146,6 +154,7 @@ static void destroy(struct sway_view *view) {
wl_list_remove(&xdg_shell_v6_view->destroy.link);
wl_list_remove(&xdg_shell_v6_view->map.link);
wl_list_remove(&xdg_shell_v6_view->unmap.link);
+ wl_list_remove(&xdg_shell_v6_view->request_fullscreen.link);
free(xdg_shell_v6_view);
}
@@ -153,6 +162,7 @@ static const struct sway_view_impl view_impl = {
.get_prop = get_prop,
.configure = configure,
.set_activated = set_activated,
+ .set_fullscreen = set_fullscreen,
.for_each_surface = for_each_surface,
.close = _close,
.destroy = destroy,
@@ -210,6 +220,18 @@ static void handle_destroy(struct wl_listener *listener, void *data) {
view_destroy(&xdg_shell_v6_view->view);
}
+static void handle_request_fullscreen(struct wl_listener *listener, void *data) {
+ struct sway_xdg_shell_v6_view *xdg_shell_v6_view =
+ wl_container_of(listener, xdg_shell_v6_view, request_fullscreen);
+ struct wlr_xdg_toplevel_v6_set_fullscreen_event *e = data;
+
+ if (xdg_shell_v6_view->view.wlr_xdg_surface_v6->role != WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL) {
+ return;
+ }
+
+ view_set_fullscreen(&xdg_shell_v6_view->view, e->fullscreen);
+}
+
void handle_xdg_shell_v6_surface(struct wl_listener *listener, void *data) {
struct sway_server *server = wl_container_of(listener, server,
xdg_shell_v6_surface);
@@ -246,4 +268,8 @@ void handle_xdg_shell_v6_surface(struct wl_listener *listener, void *data) {
xdg_shell_v6_view->destroy.notify = handle_destroy;
wl_signal_add(&xdg_surface->events.destroy, &xdg_shell_v6_view->destroy);
+
+ xdg_shell_v6_view->request_fullscreen.notify = handle_request_fullscreen;
+ wl_signal_add(&xdg_surface->toplevel->events.request_fullscreen,
+ &xdg_shell_v6_view->request_fullscreen);
}
diff --git a/sway/desktop/xwayland.c b/sway/desktop/xwayland.c
index 69166af0..716d8882 100644
--- a/sway/desktop/xwayland.c
+++ b/sway/desktop/xwayland.c
@@ -25,6 +25,15 @@ static void unmanaged_handle_request_configure(struct wl_listener *listener,
ev->width, ev->height);
}
+static void unmanaged_handle_request_fullscreen(struct wl_listener *listener,
+ void *data) {
+ struct sway_xwayland_view *xwayland_view =
+ wl_container_of(listener, xwayland_view, request_fullscreen);
+ struct sway_view *view = &xwayland_view->view;
+ struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface;
+ view_set_fullscreen(view, xsurface->fullscreen);
+}
+
static void unmanaged_handle_commit(struct wl_listener *listener, void *data) {
struct sway_xwayland_unmanaged *surface =
wl_container_of(listener, surface, commit);
@@ -106,6 +115,9 @@ static struct sway_xwayland_unmanaged *create_unmanaged(
wl_signal_add(&xsurface->events.request_configure,
&surface->request_configure);
surface->request_configure.notify = unmanaged_handle_request_configure;
+ wl_signal_add(&xsurface->events.request_fullscreen,
+ &surface->request_fullscreen);
+ surface->request_fullscreen.notify = unmanaged_handle_request_fullscreen;
wl_signal_add(&xsurface->events.map, &surface->map);
surface->map.notify = unmanaged_handle_map;
wl_signal_add(&xsurface->events.unmap, &surface->unmap);
@@ -179,6 +191,14 @@ static void set_activated(struct sway_view *view, bool activated) {
wlr_xwayland_surface_activate(surface, activated);
}
+static void set_fullscreen(struct sway_view *view, bool fullscreen) {
+ if (xwayland_view_from_view(view) == NULL) {
+ return;
+ }
+ struct wlr_xwayland_surface *surface = view->wlr_xwayland_surface;
+ wlr_xwayland_surface_set_fullscreen(surface, fullscreen);
+}
+
static void _close(struct sway_view *view) {
if (xwayland_view_from_view(view) == NULL) {
return;
@@ -193,6 +213,7 @@ static void destroy(struct sway_view *view) {
}
wl_list_remove(&xwayland_view->destroy.link);
wl_list_remove(&xwayland_view->request_configure.link);
+ wl_list_remove(&xwayland_view->request_fullscreen.link);
wl_list_remove(&xwayland_view->map.link);
wl_list_remove(&xwayland_view->unmap.link);
free(xwayland_view);
@@ -202,6 +223,7 @@ static const struct sway_view_impl view_impl = {
.get_prop = get_prop,
.configure = configure,
.set_activated = set_activated,
+ .set_fullscreen = set_fullscreen,
.close = _close,
.destroy = destroy,
};
@@ -263,6 +285,14 @@ static void handle_request_configure(struct wl_listener *listener, void *data) {
ev->width, ev->height);
}
+static void handle_request_fullscreen(struct wl_listener *listener, void *data) {
+ struct sway_xwayland_view *xwayland_view =
+ wl_container_of(listener, xwayland_view, request_fullscreen);
+ struct sway_view *view = &xwayland_view->view;
+ struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface;
+ view_set_fullscreen(view, xsurface->fullscreen);
+}
+
void handle_xwayland_surface(struct wl_listener *listener, void *data) {
struct sway_server *server = wl_container_of(listener, server,
xwayland_surface);
@@ -298,6 +328,10 @@ void handle_xwayland_surface(struct wl_listener *listener, void *data) {
&xwayland_view->request_configure);
xwayland_view->request_configure.notify = handle_request_configure;
+ wl_signal_add(&xsurface->events.request_fullscreen,
+ &xwayland_view->request_fullscreen);
+ xwayland_view->request_fullscreen.notify = handle_request_fullscreen;
+
wl_signal_add(&xsurface->events.unmap, &xwayland_view->unmap);
xwayland_view->unmap.notify = handle_unmap;
diff --git a/sway/input/seat.c b/sway/input/seat.c
index 09927a1a..f60c43b5 100644
--- a/sway/input/seat.c
+++ b/sway/input/seat.c
@@ -448,6 +448,20 @@ void seat_set_focus_warp(struct sway_seat *seat,
return;
}
+ struct sway_container *last_workspace = last_focus;
+ if (last_workspace && last_workspace->type != C_WORKSPACE) {
+ last_workspace = container_parent(last_workspace, C_WORKSPACE);
+ }
+ struct sway_container *new_workspace = container;
+ if (new_workspace && new_workspace->type != C_WORKSPACE) {
+ new_workspace = container_parent(new_workspace, C_WORKSPACE);
+ }
+
+ if (last_workspace == new_workspace && last_workspace->fullscreen
+ && !container->sway_view->is_fullscreen) {
+ return;
+ }
+
struct sway_container *last_output = last_focus;
if (last_output && last_output->type != C_OUTPUT) {
last_output = container_parent(last_output, C_OUTPUT);
diff --git a/sway/meson.build b/sway/meson.build
index 9e55e335..0bbb8da1 100644
--- a/sway/meson.build
+++ b/sway/meson.build
@@ -34,6 +34,7 @@ sway_sources = files(
'commands/exec_always.c',
'commands/focus.c',
'commands/focus_follows_mouse.c',
+ 'commands/fullscreen.c',
'commands/kill.c',
'commands/opacity.c',
'commands/include.c',
diff --git a/sway/tree/layout.c b/sway/tree/layout.c
index 0b637822..ae6db454 100644
--- a/sway/tree/layout.c
+++ b/sway/tree/layout.c
@@ -137,6 +137,21 @@ void container_move_to(struct sway_container *container,
|| container_has_anscestor(container, destination)) {
return;
}
+
+ if (container->sway_view->is_fullscreen) {
+ struct sway_container *old_workspace = container;
+ if (old_workspace->type != C_WORKSPACE) {
+ old_workspace = container_parent(old_workspace, C_WORKSPACE);
+ }
+ struct sway_container *new_workspace = destination;
+ if (new_workspace->type != C_WORKSPACE) {
+ new_workspace = container_parent(new_workspace, C_WORKSPACE);
+ }
+ if (old_workspace != new_workspace) {
+ view_set_fullscreen(container->sway_view, false);
+ }
+ }
+
struct sway_container *old_parent = container_remove_child(container);
container->width = container->height = 0;
struct sway_container *new_parent;
@@ -557,6 +572,9 @@ void arrange_windows(struct sway_container *container,
return;
case C_WORKSPACE:
{
+ if (container->fullscreen) {
+ return;
+ }
struct sway_container *output =
container_parent(container, C_OUTPUT);
struct wlr_box *area = &output->sway_output->usable_area;
diff --git a/sway/tree/view.c b/sway/tree/view.c
index 99b44720..b958233b 100644
--- a/sway/tree/view.c
+++ b/sway/tree/view.c
@@ -2,6 +2,7 @@
#include <wayland-server.h>
#include <wlr/types/wlr_output_layout.h>
#include "log.h"
+#include "sway/ipc-server.h"
#include "sway/output.h"
#include "sway/tree/container.h"
#include "sway/tree/layout.h"
@@ -73,7 +74,46 @@ void view_set_activated(struct sway_view *view, bool activated) {
}
}
+void view_set_fullscreen(struct sway_view *view, bool fullscreen) {
+ if (view->is_fullscreen == fullscreen) {
+ return;
+ }
+
+ struct sway_container *container = container_parent(view->swayc, C_OUTPUT);
+ struct sway_output *output = container->sway_output;
+ struct sway_container *workspace = container_parent(view->swayc, C_WORKSPACE);
+
+ if (view->impl->set_fullscreen) {
+ view->impl->set_fullscreen(view, fullscreen);
+ }
+
+ if (fullscreen) {
+ view->swayc->saved_x = view->swayc->x;
+ view->swayc->saved_y = view->swayc->y;
+ view->saved_width = view->width;
+ view->saved_height = view->height;
+ view_configure(view, 0, 0, output->wlr_output->width, output->wlr_output->height);
+ workspace->fullscreen = view;
+ } else {
+ view_configure(view, view->swayc->saved_x, view->swayc->saved_y,
+ view->saved_width, view->saved_height);
+ workspace->fullscreen = NULL;
+ }
+
+ view->is_fullscreen = fullscreen;
+ output_damage_whole(output);
+
+ arrange_windows(workspace, -1, -1);
+
+ ipc_event_window(view->swayc, "fullscreen_mode");
+}
+
void view_close(struct sway_view *view) {
+ if (view->is_fullscreen) {
+ struct sway_container *ws = container_parent(view->swayc, C_WORKSPACE);
+ ws->fullscreen = NULL;
+ }
+
if (view->impl->close) {
view->impl->close(view);
}