Merge pull request #1817 from RyanDwyer/fullscreen

Implement fullscreen
This commit is contained in:
emersion 2018-04-19 23:31:25 +01:00 committed by GitHub
commit a5719f9f43
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
17 changed files with 363 additions and 35 deletions

View file

@ -1,6 +1,7 @@
#ifndef _SWAY_IPC_SERVER_H #ifndef _SWAY_IPC_SERVER_H
#define _SWAY_IPC_SERVER_H #define _SWAY_IPC_SERVER_H
#include <sys/socket.h> #include <sys/socket.h>
#include "sway/config.h"
#include "sway/tree/container.h" #include "sway/tree/container.h"
#include "ipc.h" #include "ipc.h"

View file

@ -45,6 +45,7 @@ enum sway_container_border {
struct sway_root; struct sway_root;
struct sway_output; struct sway_output;
struct sway_workspace;
struct sway_view; struct sway_view;
struct sway_container { struct sway_container {
@ -52,6 +53,7 @@ struct sway_container {
// TODO: Encapsulate state for other node types as well like C_CONTAINER // TODO: Encapsulate state for other node types as well like C_CONTAINER
struct sway_root *sway_root; struct sway_root *sway_root;
struct sway_output *sway_output; struct sway_output *sway_output;
struct sway_workspace *sway_workspace;
struct sway_view *sway_view; struct sway_view *sway_view;
}; };

View file

@ -28,6 +28,7 @@ struct sway_view_impl {
void (*configure)(struct sway_view *view, double ox, double oy, int width, void (*configure)(struct sway_view *view, double ox, double oy, int width,
int height); int height);
void (*set_activated)(struct sway_view *view, bool activated); 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, void (*for_each_surface)(struct sway_view *view,
wlr_surface_iterator_func_t iterator, void *user_data); wlr_surface_iterator_func_t iterator, void *user_data);
void (*close)(struct sway_view *view); void (*close)(struct sway_view *view);
@ -41,6 +42,7 @@ struct sway_view {
struct sway_container *swayc; // NULL for unmanaged views struct sway_container *swayc; // NULL for unmanaged views
struct wlr_surface *surface; // NULL for unmapped views struct wlr_surface *surface; // NULL for unmapped views
int width, height; int width, height;
bool is_fullscreen;
union { union {
struct wlr_xdg_surface_v6 *wlr_xdg_surface_v6; struct wlr_xdg_surface_v6 *wlr_xdg_surface_v6;
@ -63,6 +65,7 @@ struct sway_xdg_shell_v6_view {
struct wl_listener request_move; struct wl_listener request_move;
struct wl_listener request_resize; struct wl_listener request_resize;
struct wl_listener request_maximize; struct wl_listener request_maximize;
struct wl_listener request_fullscreen;
struct wl_listener new_popup; struct wl_listener new_popup;
struct wl_listener map; struct wl_listener map;
struct wl_listener unmap; struct wl_listener unmap;
@ -79,6 +82,7 @@ struct sway_xwayland_view {
struct wl_listener request_resize; struct wl_listener request_resize;
struct wl_listener request_maximize; struct wl_listener request_maximize;
struct wl_listener request_configure; struct wl_listener request_configure;
struct wl_listener request_fullscreen;
struct wl_listener map; struct wl_listener map;
struct wl_listener unmap; struct wl_listener unmap;
struct wl_listener destroy; struct wl_listener destroy;
@ -93,6 +97,7 @@ struct sway_xwayland_unmanaged {
int lx, ly; int lx, ly;
struct wl_listener request_configure; struct wl_listener request_configure;
struct wl_listener request_fullscreen;
struct wl_listener commit; struct wl_listener commit;
struct wl_listener map; struct wl_listener map;
struct wl_listener unmap; struct wl_listener unmap;
@ -106,6 +111,8 @@ struct sway_wl_shell_view {
struct wl_listener request_move; struct wl_listener request_move;
struct wl_listener request_resize; struct wl_listener request_resize;
struct wl_listener request_maximize; struct wl_listener request_maximize;
struct wl_listener request_fullscreen;
struct wl_listener set_state;
struct wl_listener destroy; struct wl_listener destroy;
int pending_width, pending_height; 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_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_close(struct sway_view *view);
void view_damage(struct sway_view *view, bool whole); void view_damage(struct sway_view *view, bool whole);

View file

@ -3,6 +3,13 @@
#include "sway/tree/container.h" #include "sway/tree/container.h"
struct sway_view;
struct sway_workspace {
struct sway_container *swayc;
struct sway_view *fullscreen;
};
extern char *prev_workspace_name; extern char *prev_workspace_name;
char *workspace_next_name(const char *output_name); char *workspace_next_name(const char *output_name);

View file

@ -99,6 +99,7 @@ static struct cmd_handler handlers[] = {
{ "exec", cmd_exec }, { "exec", cmd_exec },
{ "exec_always", cmd_exec_always }, { "exec_always", cmd_exec_always },
{ "focus_follows_mouse", cmd_focus_follows_mouse }, { "focus_follows_mouse", cmd_focus_follows_mouse },
{ "fullscreen", cmd_fullscreen },
{ "include", cmd_include }, { "include", cmd_include },
{ "input", cmd_input }, { "input", cmd_input },
{ "mode", cmd_mode }, { "mode", cmd_mode },

View file

@ -0,0 +1,37 @@
#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"
struct cmd_results *cmd_fullscreen(int argc, char **argv) {
struct cmd_results *error = NULL;
if ((error = checkarg(argc, "fullscreen", EXPECTED_LESS_THAN, 2))) {
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 (argc == 0 || strcmp(argv[0], "toggle") == 0) {
wants_fullscreen = !view->is_fullscreen;
} else if (strcmp(argv[0], "enable") == 0) {
wants_fullscreen = true;
} else if (strcmp(argv[0], "disable") == 0) {
wants_fullscreen = false;
} else {
return cmd_results_new(CMD_INVALID, "fullscreen",
"Expected 'fullscreen' or 'fullscreen <enable|disable|toggle>'");
}
view_set_fullscreen(view, wants_fullscreen);
return cmd_results_new(CMD_SUCCESS, NULL, NULL);
}

View file

@ -22,6 +22,7 @@
#include "sway/tree/container.h" #include "sway/tree/container.h"
#include "sway/tree/layout.h" #include "sway/tree/layout.h"
#include "sway/tree/view.h" #include "sway/tree/view.h"
#include "sway/tree/workspace.h"
struct sway_container *output_by_name(const char *name) { struct sway_container *output_by_name(const char *name) {
for (int i = 0; i < root_container.children->length; ++i) { for (int i = 0; i < root_container.children->length; ++i) {
@ -228,8 +229,12 @@ static void render_container_iterator(struct sway_container *con,
static void render_container(struct sway_output *output, static void render_container(struct sway_output *output,
struct sway_container *con) { struct sway_container *con) {
if (con->type == C_VIEW) { // Happens if a view is fullscreened
render_container_iterator(con, output);
} else {
container_descendants(con, C_VIEW, render_container_iterator, output); container_descendants(con, C_VIEW, render_container_iterator, output);
} }
}
static struct sway_container *output_get_active_workspace( static struct sway_container *output_get_active_workspace(
struct sway_output *output) { struct sway_output *output) {
@ -270,19 +275,26 @@ static void render_output(struct sway_output *output, struct timespec *when,
wlr_output_transformed_resolution(wlr_output, &width, &height); wlr_output_transformed_resolution(wlr_output, &width, &height);
pixman_region32_union_rect(damage, damage, 0, 0, width, height); pixman_region32_union_rect(damage, damage, 0, 0, width, height);
struct sway_container *workspace = output_get_active_workspace(output);
if (workspace->sway_workspace->fullscreen) {
float clear_color[] = {0.0f, 0.0f, 0.0f, 1.0f};
wlr_renderer_clear(renderer, clear_color);
// TODO: handle views smaller than the output
render_container(output, workspace->sway_workspace->fullscreen->swayc);
} else {
float clear_color[] = {0.25f, 0.25f, 0.25f, 1.0f}; float clear_color[] = {0.25f, 0.25f, 0.25f, 1.0f};
wlr_renderer_clear(renderer, clear_color); 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_BACKGROUND]);
render_layer(output, &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM]); 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_container(output, workspace);
render_unmanaged(output, &root_container.sway_root->xwayland_unmanaged); render_unmanaged(output, &root_container.sway_root->xwayland_unmanaged);
// 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_TOP]);
}
render_layer(output, &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY]); render_layer(output, &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY]);
renderer_end: renderer_end:
@ -462,6 +474,12 @@ void output_damage_view(struct sway_output *output, struct sway_view *view,
return; return;
} }
struct sway_container *workspace = container_parent(view->swayc,
C_WORKSPACE);
if (workspace->sway_workspace->fullscreen && !view->is_fullscreen) {
return;
}
struct damage_data data = { struct damage_data data = {
.output = output, .output = output,
.whole = whole, .whole = whole,

View file

@ -61,14 +61,21 @@ static void destroy(struct sway_view *view) {
} }
wl_list_remove(&wl_shell_view->commit.link); wl_list_remove(&wl_shell_view->commit.link);
wl_list_remove(&wl_shell_view->destroy.link); wl_list_remove(&wl_shell_view->destroy.link);
wl_list_remove(&wl_shell_view->request_fullscreen.link);
wl_list_remove(&wl_shell_view->set_state.link);
free(wl_shell_view); free(wl_shell_view);
} }
static void set_fullscreen(struct sway_view *view, bool fullscreen) {
// TODO
}
static const struct sway_view_impl view_impl = { static const struct sway_view_impl view_impl = {
.get_prop = get_prop, .get_prop = get_prop,
.configure = configure, .configure = configure,
.close = _close, .close = _close,
.destroy = destroy, .destroy = destroy,
.set_fullscreen = set_fullscreen,
}; };
static void handle_commit(struct wl_listener *listener, void *data) { static void handle_commit(struct wl_listener *listener, void *data) {
@ -88,6 +95,23 @@ static void handle_destroy(struct wl_listener *listener, void *data) {
view_destroy(&wl_shell_view->view); view_destroy(&wl_shell_view->view);
} }
static void handle_request_fullscreen(struct wl_listener *listener, void *data) {
struct sway_wl_shell_view *wl_shell_view =
wl_container_of(listener, wl_shell_view, request_fullscreen);
view_set_fullscreen(&wl_shell_view->view, true);
}
static void handle_set_state(struct wl_listener *listener, void *data) {
struct sway_wl_shell_view *wl_shell_view =
wl_container_of(listener, wl_shell_view, set_state);
struct sway_view *view = &wl_shell_view->view;
struct wlr_wl_shell_surface *surface = view->wlr_wl_shell_surface;
if (view->is_fullscreen &&
surface->state != WLR_WL_SHELL_SURFACE_STATE_FULLSCREEN) {
view_set_fullscreen(view, false);
}
}
void handle_wl_shell_surface(struct wl_listener *listener, void *data) { void handle_wl_shell_surface(struct wl_listener *listener, void *data) {
struct sway_server *server = wl_container_of(listener, server, struct sway_server *server = wl_container_of(listener, server,
wl_shell_surface); wl_shell_surface);
@ -127,5 +151,16 @@ void handle_wl_shell_surface(struct wl_listener *listener, void *data) {
wl_shell_view->destroy.notify = handle_destroy; wl_shell_view->destroy.notify = handle_destroy;
wl_signal_add(&shell_surface->events.destroy, &wl_shell_view->destroy); wl_signal_add(&shell_surface->events.destroy, &wl_shell_view->destroy);
wl_shell_view->request_fullscreen.notify = handle_request_fullscreen;
wl_signal_add(&shell_surface->events.request_fullscreen,
&wl_shell_view->request_fullscreen);
wl_shell_view->set_state.notify = handle_set_state;
wl_signal_add(&shell_surface->events.set_state, &wl_shell_view->set_state);
view_map(&wl_shell_view->view, shell_surface->surface); view_map(&wl_shell_view->view, shell_surface->surface);
if (shell_surface->state == WLR_WL_SHELL_SURFACE_STATE_FULLSCREEN) {
view_set_fullscreen(&wl_shell_view->view, true);
}
} }

View file

@ -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, static void for_each_surface(struct sway_view *view,
wlr_surface_iterator_func_t iterator, void *user_data) { wlr_surface_iterator_func_t iterator, void *user_data) {
if (xdg_shell_v6_view_from_view(view) == NULL) { 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->destroy.link);
wl_list_remove(&xdg_shell_v6_view->map.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->unmap.link);
wl_list_remove(&xdg_shell_v6_view->request_fullscreen.link);
free(xdg_shell_v6_view); free(xdg_shell_v6_view);
} }
@ -153,6 +162,7 @@ static const struct sway_view_impl view_impl = {
.get_prop = get_prop, .get_prop = get_prop,
.configure = configure, .configure = configure,
.set_activated = set_activated, .set_activated = set_activated,
.set_fullscreen = set_fullscreen,
.for_each_surface = for_each_surface, .for_each_surface = for_each_surface,
.close = _close, .close = _close,
.destroy = destroy, .destroy = destroy,
@ -202,6 +212,10 @@ static void handle_map(struct wl_listener *listener, void *data) {
xdg_shell_v6_view->new_popup.notify = handle_new_popup; xdg_shell_v6_view->new_popup.notify = handle_new_popup;
wl_signal_add(&xdg_surface->events.new_popup, wl_signal_add(&xdg_surface->events.new_popup,
&xdg_shell_v6_view->new_popup); &xdg_shell_v6_view->new_popup);
if (xdg_surface->toplevel->client_pending.fullscreen) {
view_set_fullscreen(view, true);
}
} }
static void handle_destroy(struct wl_listener *listener, void *data) { static void handle_destroy(struct wl_listener *listener, void *data) {
@ -210,6 +224,23 @@ static void handle_destroy(struct wl_listener *listener, void *data) {
view_destroy(&xdg_shell_v6_view->view); 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 (!sway_assert(xdg_shell_v6_view->view.wlr_xdg_surface_v6->role == WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL,
"xdg_shell_v6 requested fullscreen of surface with role %i",
xdg_shell_v6_view->view.wlr_xdg_surface_v6->role)) {
return;
}
if (!xdg_shell_v6_view->view.wlr_xdg_surface_v6->mapped) {
return;
}
view_set_fullscreen(&xdg_shell_v6_view->view, e->fullscreen);
}
void handle_xdg_shell_v6_surface(struct wl_listener *listener, void *data) { void handle_xdg_shell_v6_surface(struct wl_listener *listener, void *data) {
struct sway_server *server = wl_container_of(listener, server, struct sway_server *server = wl_container_of(listener, server,
xdg_shell_v6_surface); xdg_shell_v6_surface);
@ -246,4 +277,8 @@ void handle_xdg_shell_v6_surface(struct wl_listener *listener, void *data) {
xdg_shell_v6_view->destroy.notify = handle_destroy; xdg_shell_v6_view->destroy.notify = handle_destroy;
wl_signal_add(&xdg_surface->events.destroy, &xdg_shell_v6_view->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);
} }

View file

@ -179,6 +179,14 @@ static void set_activated(struct sway_view *view, bool activated) {
wlr_xwayland_surface_activate(surface, 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) { static void _close(struct sway_view *view) {
if (xwayland_view_from_view(view) == NULL) { if (xwayland_view_from_view(view) == NULL) {
return; return;
@ -193,6 +201,7 @@ static void destroy(struct sway_view *view) {
} }
wl_list_remove(&xwayland_view->destroy.link); wl_list_remove(&xwayland_view->destroy.link);
wl_list_remove(&xwayland_view->request_configure.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->map.link);
wl_list_remove(&xwayland_view->unmap.link); wl_list_remove(&xwayland_view->unmap.link);
free(xwayland_view); free(xwayland_view);
@ -202,6 +211,7 @@ static const struct sway_view_impl view_impl = {
.get_prop = get_prop, .get_prop = get_prop,
.configure = configure, .configure = configure,
.set_activated = set_activated, .set_activated = set_activated,
.set_fullscreen = set_fullscreen,
.close = _close, .close = _close,
.destroy = destroy, .destroy = destroy,
}; };
@ -238,6 +248,10 @@ static void handle_map(struct wl_listener *listener, void *data) {
// Put it back into the tree // Put it back into the tree
wlr_xwayland_surface_set_maximized(xsurface, true); wlr_xwayland_surface_set_maximized(xsurface, true);
view_map(view, xsurface->surface); view_map(view, xsurface->surface);
if (xsurface->fullscreen) {
view_set_fullscreen(view, true);
}
} }
static void handle_destroy(struct wl_listener *listener, void *data) { static void handle_destroy(struct wl_listener *listener, void *data) {
@ -263,6 +277,14 @@ static void handle_request_configure(struct wl_listener *listener, void *data) {
ev->width, ev->height); 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) { void handle_xwayland_surface(struct wl_listener *listener, void *data) {
struct sway_server *server = wl_container_of(listener, server, struct sway_server *server = wl_container_of(listener, server,
xwayland_surface); xwayland_surface);
@ -298,6 +320,10 @@ void handle_xwayland_surface(struct wl_listener *listener, void *data) {
&xwayland_view->request_configure); &xwayland_view->request_configure);
xwayland_view->request_configure.notify = handle_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); wl_signal_add(&xsurface->events.unmap, &xwayland_view->unmap);
xwayland_view->unmap.notify = handle_unmap; xwayland_view->unmap.notify = handle_unmap;

View file

@ -12,6 +12,7 @@
#include "sway/layers.h" #include "sway/layers.h"
#include "sway/output.h" #include "sway/output.h"
#include "sway/tree/view.h" #include "sway/tree/view.h"
#include "sway/tree/workspace.h"
#include "wlr-layer-shell-unstable-v1-protocol.h" #include "wlr-layer-shell-unstable-v1-protocol.h"
static struct wlr_surface *layer_surface_at(struct sway_output *output, static struct wlr_surface *layer_surface_at(struct sway_output *output,
@ -83,6 +84,16 @@ static struct sway_container *container_at_cursor(struct sway_cursor *cursor,
ox, oy, sx, sy))) { ox, oy, sx, sy))) {
return ws; return ws;
} }
if (ws->sway_workspace->fullscreen) {
struct wlr_surface *wlr_surface = ws->sway_workspace->fullscreen->surface;
if (wlr_surface_point_accepts_input(wlr_surface, ox, oy)) {
*sx = ox;
*sy = oy;
*surface = wlr_surface;
return ws->sway_workspace->fullscreen->swayc;
}
return NULL;
}
if ((*surface = layer_surface_at(output, if ((*surface = layer_surface_at(output,
&output->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP], &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP],
ox, oy, sx, sy))) { ox, oy, sx, sy))) {

View file

@ -18,6 +18,7 @@
#include "sway/output.h" #include "sway/output.h"
#include "sway/tree/container.h" #include "sway/tree/container.h"
#include "sway/tree/view.h" #include "sway/tree/view.h"
#include "sway/tree/workspace.h"
#include "log.h" #include "log.h"
static void seat_device_destroy(struct sway_seat_device *seat_device) { static void seat_device_destroy(struct sway_seat_device *seat_device) {
@ -448,6 +449,21 @@ void seat_set_focus_warp(struct sway_seat *seat,
return; 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 && last_workspace == new_workspace
&& last_workspace->sway_workspace->fullscreen
&& !container->sway_view->is_fullscreen) {
return;
}
struct sway_container *last_output = last_focus; struct sway_container *last_output = last_focus;
if (last_output && last_output->type != C_OUTPUT) { if (last_output && last_output->type != C_OUTPUT) {
last_output = container_parent(last_output, C_OUTPUT); last_output = container_parent(last_output, C_OUTPUT);

View file

@ -34,6 +34,7 @@ sway_sources = files(
'commands/exec_always.c', 'commands/exec_always.c',
'commands/focus.c', 'commands/focus.c',
'commands/focus_follows_mouse.c', 'commands/focus_follows_mouse.c',
'commands/fullscreen.c',
'commands/kill.c', 'commands/kill.c',
'commands/opacity.c', 'commands/opacity.c',
'commands/include.c', 'commands/include.c',

View file

@ -197,6 +197,7 @@ static struct sway_container *container_workspace_destroy(
} }
} }
free(workspace->sway_workspace);
_container_destroy(workspace); _container_destroy(workspace);
output_damage_whole(output->sway_output); output_damage_whole(output->sway_output);

View file

@ -82,6 +82,37 @@ static int index_child(const struct sway_container *child) {
return i; return i;
} }
static void container_handle_fullscreen_reparent(struct sway_container *viewcon,
struct sway_container *old_parent) {
if (viewcon->type != C_VIEW || !viewcon->sway_view->is_fullscreen) {
return;
}
struct sway_view *view = viewcon->sway_view;
struct sway_container *old_workspace = old_parent;
if (old_workspace && old_workspace->type != C_WORKSPACE) {
old_workspace = container_parent(old_workspace, C_WORKSPACE);
}
struct sway_container *new_workspace = container_parent(view->swayc,
C_WORKSPACE);
if (old_workspace == new_workspace) {
return;
}
// Unmark the old workspace as fullscreen
if (old_workspace) {
old_workspace->sway_workspace->fullscreen = NULL;
}
// Mark the new workspace as fullscreen
if (new_workspace->sway_workspace->fullscreen) {
view_set_fullscreen(new_workspace->sway_workspace->fullscreen, false);
}
new_workspace->sway_workspace->fullscreen = view;
// Resize view to new output dimensions
struct sway_output *output = new_workspace->parent->sway_output;
view_configure(view, 0, 0,
output->wlr_output->width, output->wlr_output->height);
}
void container_insert_child(struct sway_container *parent, void container_insert_child(struct sway_container *parent,
struct sway_container *child, int i) { struct sway_container *child, int i) {
struct sway_container *old_parent = child->parent; struct sway_container *old_parent = child->parent;
@ -91,6 +122,7 @@ void container_insert_child(struct sway_container *parent,
wlr_log(L_DEBUG, "Inserting id:%zd at index %d", child->id, i); wlr_log(L_DEBUG, "Inserting id:%zd at index %d", child->id, i);
list_insert(parent->children, i, child); list_insert(parent->children, i, child);
child->parent = parent; child->parent = parent;
container_handle_fullscreen_reparent(child, old_parent);
wl_signal_emit(&child->events.reparent, old_parent); wl_signal_emit(&child->events.reparent, old_parent);
} }
@ -106,6 +138,7 @@ struct sway_container *container_add_sibling(struct sway_container *fixed,
int i = index_child(fixed); int i = index_child(fixed);
list_insert(parent->children, i + 1, active); list_insert(parent->children, i + 1, active);
active->parent = parent; active->parent = parent;
container_handle_fullscreen_reparent(active, old_parent);
wl_signal_emit(&active->events.reparent, old_parent); wl_signal_emit(&active->events.reparent, old_parent);
return active->parent; return active->parent;
} }
@ -115,11 +148,18 @@ void container_add_child(struct sway_container *parent,
wlr_log(L_DEBUG, "Adding %p (%d, %fx%f) to %p (%d, %fx%f)", wlr_log(L_DEBUG, "Adding %p (%d, %fx%f) to %p (%d, %fx%f)",
child, child->type, child->width, child->height, child, child->type, child->width, child->height,
parent, parent->type, parent->width, parent->height); parent, parent->type, parent->width, parent->height);
struct sway_container *old_parent = child->parent;
list_add(parent->children, child); list_add(parent->children, child);
container_handle_fullscreen_reparent(child, old_parent);
child->parent = parent; child->parent = parent;
} }
struct sway_container *container_remove_child(struct sway_container *child) { struct sway_container *container_remove_child(struct sway_container *child) {
if (child->type == C_VIEW && child->sway_view->is_fullscreen) {
struct sway_container *workspace = container_parent(child, C_WORKSPACE);
workspace->sway_workspace->fullscreen = NULL;
}
struct sway_container *parent = child->parent; struct sway_container *parent = child->parent;
for (int i = 0; i < parent->children->length; ++i) { for (int i = 0; i < parent->children->length; ++i) {
if (parent->children->items[i] == child) { if (parent->children->items[i] == child) {
@ -164,6 +204,26 @@ void container_move_to(struct sway_container *container,
arrange_windows(old_parent, -1, -1); arrange_windows(old_parent, -1, -1);
} }
arrange_windows(new_parent, -1, -1); arrange_windows(new_parent, -1, -1);
// If view was moved to a fullscreen workspace, refocus the fullscreen view
struct sway_container *new_workspace = container;
if (new_workspace->type != C_WORKSPACE) {
new_workspace = container_parent(new_workspace, C_WORKSPACE);
}
if (new_workspace->sway_workspace->fullscreen) {
struct sway_seat *seat;
struct sway_container *focus, *focus_ws;
wl_list_for_each(seat, &input_manager->seats, link) {
focus = seat_get_focus(seat);
focus_ws = focus;
if (focus_ws->type != C_WORKSPACE) {
focus_ws = container_parent(focus_ws, C_WORKSPACE);
}
seat_set_focus(seat, new_workspace->sway_workspace->fullscreen->swayc);
if (focus_ws != new_workspace) {
seat_set_focus(seat, focus);
}
}
}
} }
static bool sway_dir_to_wlr(enum movement_direction dir, static bool sway_dir_to_wlr(enum movement_direction dir,
@ -268,6 +328,11 @@ void container_move(struct sway_container *container,
struct sway_container *current = container; struct sway_container *current = container;
struct sway_container *parent = current->parent; struct sway_container *parent = current->parent;
// If moving a fullscreen view, only consider outputs
if (container->type == C_VIEW && container->sway_view->is_fullscreen) {
current = container_parent(container, C_OUTPUT);
}
if (parent != container_flatten(parent)) { if (parent != container_flatten(parent)) {
// Special case: we were the last one in this container, so flatten it // Special case: we were the last one in this container, so flatten it
// and leave // and leave
@ -568,6 +633,11 @@ void arrange_windows(struct sway_container *container,
container->y = y = area->y; container->y = y = area->y;
wlr_log(L_DEBUG, "Arranging workspace '%s' at %f, %f", wlr_log(L_DEBUG, "Arranging workspace '%s' at %f, %f",
container->name, container->x, container->y); container->name, container->x, container->y);
if (container->sway_workspace->fullscreen) {
view_configure(container->sway_workspace->fullscreen, 0, 0,
output->width, output->height);
return;
}
} }
// children are properly handled below // children are properly handled below
break; break;
@ -816,11 +886,18 @@ static struct sway_container *sway_output_from_wlr(struct wlr_output *output) {
struct sway_container *container_get_in_direction( struct sway_container *container_get_in_direction(
struct sway_container *container, struct sway_seat *seat, struct sway_container *container, struct sway_seat *seat,
enum movement_direction dir) { enum movement_direction dir) {
struct sway_container *parent = container->parent;
if (container->type == C_VIEW && container->sway_view->is_fullscreen) {
if (dir == MOVE_PARENT || dir == MOVE_CHILD) {
return NULL;
}
container = container_parent(container, C_OUTPUT);
parent = container->parent;
} else {
if (dir == MOVE_CHILD) { if (dir == MOVE_CHILD) {
return seat_get_focus_inactive(seat, container); return seat_get_focus_inactive(seat, container);
} }
struct sway_container *parent = container->parent;
if (dir == MOVE_PARENT) { if (dir == MOVE_PARENT) {
if (parent->type == C_OUTPUT) { if (parent->type == C_OUTPUT) {
return NULL; return NULL;
@ -828,22 +905,7 @@ struct sway_container *container_get_in_direction(
return parent; return parent;
} }
} }
// TODO WLR fullscreen
/*
if (container->type == C_VIEW && swayc_is_fullscreen(container)) {
wlr_log(L_DEBUG, "Moving from fullscreen view, skipping to output");
container = container_parent(container, C_OUTPUT);
get_layout_center_position(container, &abs_pos);
struct sway_container *output =
swayc_adjacent_output(container, dir, &abs_pos, true);
return get_swayc_in_output_direction(output, dir);
} }
if (container->type == C_WORKSPACE && container->fullscreen) {
sway_log(L_DEBUG, "Moving to fullscreen view");
return container->fullscreen;
}
*/
struct sway_container *wrap_candidate = NULL; struct sway_container *wrap_candidate = NULL;
while (true) { while (true) {
@ -874,6 +936,14 @@ struct sway_container *container_get_in_direction(
if (next == NULL) { if (next == NULL) {
return NULL; return NULL;
} }
struct sway_container *next_workspace = next;
if (next_workspace->type != C_WORKSPACE) {
next_workspace = container_parent(next_workspace, C_WORKSPACE);
}
sway_assert(next_workspace, "Next container has no workspace");
if (next_workspace->sway_workspace->fullscreen) {
return next_workspace->sway_workspace->fullscreen->swayc;
}
if (next->children && next->children->length) { if (next->children && next->children->length) {
// TODO consider floating children as well // TODO consider floating children as well
return seat_get_focus_inactive_view(seat, next); return seat_get_focus_inactive_view(seat, next);

View file

@ -2,10 +2,12 @@
#include <wayland-server.h> #include <wayland-server.h>
#include <wlr/types/wlr_output_layout.h> #include <wlr/types/wlr_output_layout.h>
#include "log.h" #include "log.h"
#include "sway/ipc-server.h"
#include "sway/output.h" #include "sway/output.h"
#include "sway/tree/container.h" #include "sway/tree/container.h"
#include "sway/tree/layout.h" #include "sway/tree/layout.h"
#include "sway/tree/view.h" #include "sway/tree/view.h"
#include "sway/tree/workspace.h"
void view_init(struct sway_view *view, enum sway_view_type type, void view_init(struct sway_view *view, enum sway_view_type type,
const struct sway_view_impl *impl) { const struct sway_view_impl *impl) {
@ -73,6 +75,50 @@ 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 *workspace = container_parent(view->swayc, C_WORKSPACE);
struct sway_container *container = container_parent(workspace, C_OUTPUT);
struct sway_output *output = container->sway_output;
if (view->impl->set_fullscreen) {
view->impl->set_fullscreen(view, fullscreen);
}
view->is_fullscreen = fullscreen;
if (fullscreen) {
if (workspace->sway_workspace->fullscreen) {
view_set_fullscreen(workspace->sway_workspace->fullscreen, false);
}
workspace->sway_workspace->fullscreen = view;
struct sway_seat *seat;
struct sway_container *focus, *focus_ws;
wl_list_for_each(seat, &input_manager->seats, link) {
focus = seat_get_focus(seat);
focus_ws = focus;
if (focus_ws->type != C_WORKSPACE) {
focus_ws = container_parent(focus_ws, C_WORKSPACE);
}
seat_set_focus(seat, view->swayc);
if (focus_ws != workspace) {
seat_set_focus(seat, focus);
}
}
} else {
workspace->sway_workspace->fullscreen = NULL;
}
arrange_windows(workspace, -1, -1);
output_damage_whole(output);
ipc_event_window(view->swayc, "fullscreen_mode");
}
void view_close(struct sway_view *view) { void view_close(struct sway_view *view) {
if (view->impl->close) { if (view->impl->close) {
view->impl->close(view); view->impl->close(view);
@ -197,6 +243,11 @@ void view_unmap(struct sway_view *view) {
wl_signal_emit(&view->events.unmap, view); wl_signal_emit(&view->events.unmap, view);
if (view->is_fullscreen) {
struct sway_container *ws = container_parent(view->swayc, C_WORKSPACE);
ws->sway_workspace->fullscreen = NULL;
}
view_damage(view, true); view_damage(view, true);
wl_list_remove(&view->surface_new_subsurface.link); wl_list_remove(&view->surface_new_subsurface.link);

View file

@ -59,6 +59,13 @@ struct sway_container *workspace_create(struct sway_container *output,
workspace->layout = container_get_default_layout(output); workspace->layout = container_get_default_layout(output);
workspace->workspace_layout = workspace->layout; workspace->workspace_layout = workspace->layout;
struct sway_workspace *swayws = calloc(1, sizeof(struct sway_workspace));
if (!swayws) {
return NULL;
}
swayws->swayc = workspace;
workspace->sway_workspace = swayws;
container_add_child(output, workspace); container_add_child(output, workspace);
container_sort_workspaces(output); container_sort_workspaces(output);
container_create_notify(workspace); container_create_notify(workspace);