summaryrefslogtreecommitdiff
path: root/sway/desktop
diff options
context:
space:
mode:
Diffstat (limited to 'sway/desktop')
-rw-r--r--sway/desktop/desktop.c9
-rw-r--r--sway/desktop/fx_renderer.c81
-rw-r--r--sway/desktop/idle_inhibit_v1.c2
-rw-r--r--sway/desktop/launcher.c211
-rw-r--r--sway/desktop/layer_shell.c63
-rw-r--r--sway/desktop/output.c155
-rw-r--r--sway/desktop/render.c43
-rw-r--r--sway/desktop/surface.c2
-rw-r--r--sway/desktop/xdg_shell.c132
-rw-r--r--sway/desktop/xwayland.c62
10 files changed, 594 insertions, 166 deletions
diff --git a/sway/desktop/desktop.c b/sway/desktop/desktop.c
index ec45d80a..c8d4502c 100644
--- a/sway/desktop/desktop.c
+++ b/sway/desktop/desktop.c
@@ -6,10 +6,11 @@ void desktop_damage_surface(struct wlr_surface *surface, double lx, double ly,
bool whole) {
for (int i = 0; i < root->outputs->length; ++i) {
struct sway_output *output = root->outputs->items[i];
- struct wlr_box *output_box = wlr_output_layout_get_box(
- root->output_layout, output->wlr_output);
- output_damage_surface(output, lx - output_box->x,
- ly - output_box->y, surface, whole);
+ struct wlr_box output_box;
+ wlr_output_layout_get_box(root->output_layout,
+ output->wlr_output, &output_box);
+ output_damage_surface(output, lx - output_box.x,
+ ly - output_box.y, surface, whole);
}
}
diff --git a/sway/desktop/fx_renderer.c b/sway/desktop/fx_renderer.c
index 3b4279fe..782ceb88 100644
--- a/sway/desktop/fx_renderer.c
+++ b/sway/desktop/fx_renderer.c
@@ -35,6 +35,71 @@ static const GLfloat verts[] = {
0, 1, // bottom left
};
+static const float transforms[][9] = {
+ [WL_OUTPUT_TRANSFORM_NORMAL] = {
+ 1.0f, 0.0f, 0.0f,
+ 0.0f, 1.0f, 0.0f,
+ 0.0f, 0.0f, 1.0f,
+ },
+ [WL_OUTPUT_TRANSFORM_90] = {
+ 0.0f, 1.0f, 0.0f,
+ -1.0f, 0.0f, 0.0f,
+ 0.0f, 0.0f, 1.0f,
+ },
+ [WL_OUTPUT_TRANSFORM_180] = {
+ -1.0f, 0.0f, 0.0f,
+ 0.0f, -1.0f, 0.0f,
+ 0.0f, 0.0f, 1.0f,
+ },
+ [WL_OUTPUT_TRANSFORM_270] = {
+ 0.0f, -1.0f, 0.0f,
+ 1.0f, 0.0f, 0.0f,
+ 0.0f, 0.0f, 1.0f,
+ },
+ [WL_OUTPUT_TRANSFORM_FLIPPED] = {
+ -1.0f, 0.0f, 0.0f,
+ 0.0f, 1.0f, 0.0f,
+ 0.0f, 0.0f, 1.0f,
+ },
+ [WL_OUTPUT_TRANSFORM_FLIPPED_90] = {
+ 0.0f, 1.0f, 0.0f,
+ 1.0f, 0.0f, 0.0f,
+ 0.0f, 0.0f, 1.0f,
+ },
+ [WL_OUTPUT_TRANSFORM_FLIPPED_180] = {
+ 1.0f, 0.0f, 0.0f,
+ 0.0f, -1.0f, 0.0f,
+ 0.0f, 0.0f, 1.0f,
+ },
+ [WL_OUTPUT_TRANSFORM_FLIPPED_270] = {
+ 0.0f, -1.0f, 0.0f,
+ -1.0f, 0.0f, 0.0f,
+ 0.0f, 0.0f, 1.0f,
+ },
+};
+
+static void matrix_projection(float mat[static 9], int width, int height,
+ enum wl_output_transform transform) {
+ memset(mat, 0, sizeof(*mat) * 9);
+
+ const float *t = transforms[transform];
+ float x = 2.0f / width;
+ float y = 2.0f / height;
+
+ // Rotation + reflection
+ mat[0] = x * t[0];
+ mat[1] = x * t[1];
+ mat[3] = y * -t[3];
+ mat[4] = y * -t[4];
+
+ // Translation
+ mat[2] = -copysign(1.0f, mat[0] + mat[1]);
+ mat[5] = -copysign(1.0f, mat[3] + mat[4]);
+
+ // Identity
+ mat[8] = 1.0f;
+}
+
static GLuint compile_shader(GLuint type, const GLchar *src) {
GLuint shader = glCreateShader(type);
glShaderSource(shader, 1, &src, NULL);
@@ -156,7 +221,8 @@ struct fx_renderer *fx_renderer_create(struct wlr_egl *egl) {
// TODO: wlr_egl_make_current or eglMakeCurrent?
// TODO: assert instead of conditional statement?
- if (!wlr_egl_make_current(egl)) {
+ if (!eglMakeCurrent(wlr_egl_get_display(egl), EGL_NO_SURFACE, EGL_NO_SURFACE,
+ wlr_egl_get_context(egl))) {
sway_log(SWAY_ERROR, "GLES2 RENDERER: Could not make EGL current");
return NULL;
}
@@ -242,7 +308,11 @@ struct fx_renderer *fx_renderer_create(struct wlr_egl *egl) {
goto error;
}
- wlr_egl_unset_current(renderer->egl);
+ if (!eglMakeCurrent(wlr_egl_get_display(renderer->egl),
+ EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT)) {
+ sway_log(SWAY_ERROR, "GLES2 RENDERER: Could not unset current EGL");
+ goto error;
+ }
sway_log(SWAY_INFO, "GLES2 RENDERER: Shaders Initialized Successfully");
return renderer;
@@ -257,7 +327,10 @@ error:
glDeleteProgram(renderer->shaders.tex_rgbx.program);
glDeleteProgram(renderer->shaders.tex_ext.program);
- wlr_egl_unset_current(renderer->egl);
+ if (!eglMakeCurrent(wlr_egl_get_display(renderer->egl),
+ EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT)) {
+ sway_log(SWAY_ERROR, "GLES2 RENDERER: Could not unset current EGL");
+ }
// TODO: more freeing?
free(renderer);
@@ -270,7 +343,7 @@ void fx_renderer_begin(struct fx_renderer *renderer, uint32_t width, uint32_t he
glViewport(0, 0, width, height);
// refresh projection matrix
- wlr_matrix_projection(renderer->projection, width, height,
+ matrix_projection(renderer->projection, width, height,
WL_OUTPUT_TRANSFORM_FLIPPED_180);
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
diff --git a/sway/desktop/idle_inhibit_v1.c b/sway/desktop/idle_inhibit_v1.c
index 82353038..3a4d0b87 100644
--- a/sway/desktop/idle_inhibit_v1.c
+++ b/sway/desktop/idle_inhibit_v1.c
@@ -1,5 +1,6 @@
#include <stdlib.h>
#include <wlr/types/wlr_idle.h>
+#include <wlr/types/wlr_idle_notify_v1.h>
#include "log.h"
#include "sway/desktop/idle_inhibit_v1.h"
#include "sway/input/seat.h"
@@ -140,6 +141,7 @@ void sway_idle_inhibit_v1_check_active(
}
}
wlr_idle_set_enabled(manager->idle, NULL, !inhibited);
+ wlr_idle_notifier_v1_set_inhibited(server.idle_notifier_v1, inhibited);
}
struct sway_idle_inhibit_manager_v1 *sway_idle_inhibit_manager_v1_create(
diff --git a/sway/desktop/launcher.c b/sway/desktop/launcher.c
new file mode 100644
index 00000000..48e5d24c
--- /dev/null
+++ b/sway/desktop/launcher.c
@@ -0,0 +1,211 @@
+#define _POSIX_C_SOURCE 200809L
+#include <stdlib.h>
+#include <string.h>
+#include <wlr/types/wlr_xdg_activation_v1.h>
+#include "sway/input/seat.h"
+#include "sway/output.h"
+#include "sway/desktop/launcher.h"
+#include "sway/tree/node.h"
+#include "sway/tree/container.h"
+#include "sway/tree/workspace.h"
+#include "sway/tree/root.h"
+#include "log.h"
+
+/**
+ * Get the pid of a parent process given the pid of a child process.
+ *
+ * Returns the parent pid or NULL if the parent pid cannot be determined.
+ */
+static pid_t get_parent_pid(pid_t child) {
+ pid_t parent = -1;
+ char file_name[100];
+ char *buffer = NULL;
+ const char *sep = " ";
+ FILE *stat = NULL;
+ size_t buf_size = 0;
+
+ snprintf(file_name, sizeof(file_name), "/proc/%d/stat", child);
+
+ if ((stat = fopen(file_name, "r"))) {
+ if (getline(&buffer, &buf_size, stat) != -1) {
+ strtok(buffer, sep); // pid
+ strtok(NULL, sep); // executable name
+ strtok(NULL, sep); // state
+ char *token = strtok(NULL, sep); // parent pid
+ parent = strtol(token, NULL, 10);
+ }
+ free(buffer);
+ fclose(stat);
+ }
+
+ if (parent) {
+ return (parent == child) ? -1 : parent;
+ }
+
+ return -1;
+}
+
+void launcher_ctx_consume(struct launcher_ctx *ctx) {
+ // The view is now responsible for destroying this ctx
+ wl_list_remove(&ctx->token_destroy.link);
+ wl_list_init(&ctx->token_destroy.link);
+
+ if (!ctx->activated) {
+ // An unactivated token hasn't been destroyed yet
+ wlr_xdg_activation_token_v1_destroy(ctx->token);
+ }
+ ctx->token = NULL;
+
+ // Prevent additional matches
+ wl_list_remove(&ctx->link);
+ wl_list_init(&ctx->link);
+}
+
+void launcher_ctx_destroy(struct launcher_ctx *ctx) {
+ if (ctx == NULL) {
+ return;
+ }
+ wl_list_remove(&ctx->node_destroy.link);
+ wl_list_remove(&ctx->token_destroy.link);
+ wl_list_remove(&ctx->link);
+ wlr_xdg_activation_token_v1_destroy(ctx->token);
+ free(ctx->name);
+ free(ctx);
+}
+
+struct launcher_ctx *launcher_ctx_find_pid(pid_t pid) {
+ if (wl_list_empty(&server.pending_launcher_ctxs)) {
+ return NULL;
+ }
+
+ struct launcher_ctx *ctx = NULL;
+ sway_log(SWAY_DEBUG, "Looking up workspace for pid %d", pid);
+
+ do {
+ struct launcher_ctx *_ctx = NULL;
+ wl_list_for_each(_ctx, &server.pending_launcher_ctxs, link) {
+ if (pid == _ctx->pid) {
+ ctx = _ctx;
+ sway_log(SWAY_DEBUG,
+ "found %s match for pid %d: %s",
+ node_type_to_str(ctx->node->type), pid, node_get_name(ctx->node));
+ break;
+ }
+ }
+ pid = get_parent_pid(pid);
+ } while (pid > 1);
+
+ return ctx;
+}
+
+struct sway_workspace *launcher_ctx_get_workspace(
+ struct launcher_ctx *ctx) {
+ struct sway_workspace *ws = NULL;
+ struct sway_output *output = NULL;
+
+ switch (ctx->node->type) {
+ case N_CONTAINER:
+ // Unimplemented
+ // TODO: add container matching?
+ ws = ctx->node->sway_container->pending.workspace;
+ break;
+ case N_WORKSPACE:
+ ws = ctx->node->sway_workspace;
+ break;
+ case N_OUTPUT:
+ output = ctx->node->sway_output;
+ ws = workspace_by_name(ctx->name);
+ if (!ws) {
+ sway_log(SWAY_DEBUG,
+ "Creating workspace %s for pid %d because it disappeared",
+ ctx->name, ctx->pid);
+ if (!output->enabled) {
+ sway_log(SWAY_DEBUG,
+ "Workspace output %s is disabled, trying another one",
+ output->wlr_output->name);
+ output = NULL;
+ }
+ ws = workspace_create(output, ctx->name);
+ }
+ break;
+ case N_ROOT:
+ ws = workspace_create(NULL, ctx->name);
+ break;
+ }
+
+ return ws;
+}
+
+static void ctx_handle_node_destroy(struct wl_listener *listener, void *data) {
+ struct launcher_ctx *ctx = wl_container_of(listener, ctx, node_destroy);
+ switch (ctx->node->type) {
+ case N_CONTAINER:
+ // Unimplemented
+ break;
+ case N_WORKSPACE:;
+ struct sway_workspace *ws = ctx->node->sway_workspace;
+ wl_list_remove(&ctx->node_destroy.link);
+ wl_list_init(&ctx->node_destroy.link);
+ // We want to save this ws name to recreate later, hopefully on the
+ // same output
+ free(ctx->name);
+ ctx->name = strdup(ws->name);
+ if (!ws->output || ws->output->node.destroying) {
+ // If the output is being destroyed it would be pointless to track
+ // If the output is being disabled, we'll find out if it's still
+ // disabled when we try to match it.
+ ctx->node = &root->node;
+ break;
+ }
+ ctx->node = &ws->output->node;
+ wl_signal_add(&ctx->node->events.destroy, &ctx->node_destroy);
+ break;
+ case N_OUTPUT:
+ wl_list_remove(&ctx->node_destroy.link);
+ wl_list_init(&ctx->node_destroy.link);
+ // We'll make the ws ctx->name somewhere else
+ ctx->node = &root->node;
+ break;
+ case N_ROOT:
+ // Unreachable
+ break;
+ }
+}
+
+static void token_handle_destroy(struct wl_listener *listener, void *data) {
+ struct launcher_ctx *ctx = wl_container_of(listener, ctx, token_destroy);
+ ctx->token = NULL;
+ launcher_ctx_destroy(ctx);
+}
+
+struct launcher_ctx *launcher_ctx_create() {
+ struct sway_seat *seat = input_manager_current_seat();
+ struct sway_workspace *ws = seat_get_focused_workspace(seat);
+ if (!ws) {
+ sway_log(SWAY_DEBUG, "Failed to create launch context. No workspace.");
+ return NULL;
+ }
+
+ struct launcher_ctx *ctx = calloc(1, sizeof(struct launcher_ctx));
+ struct wlr_xdg_activation_token_v1 *token =
+ wlr_xdg_activation_token_v1_create(server.xdg_activation_v1);
+ token->data = ctx;
+ ctx->name = strdup(ws->name);
+ ctx->token = token;
+ ctx->node = &ws->node;
+
+ ctx->node_destroy.notify = ctx_handle_node_destroy;
+ wl_signal_add(&ctx->node->events.destroy, &ctx->node_destroy);
+
+ ctx->token_destroy.notify = token_handle_destroy;
+ wl_signal_add(&token->events.destroy, &ctx->token_destroy);
+
+ wl_list_init(&ctx->link);
+ wl_list_insert(&server.pending_launcher_ctxs, &ctx->link);
+ return ctx;
+}
+
+const char *launcher_ctx_get_token_name(struct launcher_ctx *ctx) {
+ const char *token = wlr_xdg_activation_token_v1_get_name(ctx->token);
+ return token;
+}
diff --git a/sway/desktop/layer_shell.c b/sway/desktop/layer_shell.c
index 27e457f1..6e3cc0e2 100644
--- a/sway/desktop/layer_shell.c
+++ b/sway/desktop/layer_shell.c
@@ -3,8 +3,8 @@
#include <string.h>
#include <wayland-server-core.h>
#include <wlr/types/wlr_layer_shell_v1.h>
-#include <wlr/types/wlr_output_damage.h>
#include <wlr/types/wlr_output.h>
+#include <wlr/types/wlr_subcompositor.h>
#include "log.h"
#include "sway/desktop/transaction.h"
#include "sway/input/cursor.h"
@@ -270,10 +270,6 @@ static void handle_output_destroy(struct wl_listener *listener, void *data) {
wl_resource_get_client(sway_layer->layer_surface->resource);
bool set_focus = seat->exclusive_client == client;
- wl_list_remove(&sway_layer->output_destroy.link);
- wl_list_remove(&sway_layer->link);
- wl_list_init(&sway_layer->link);
-
if (set_focus) {
struct sway_layer_surface *layer =
find_mapped_layer_by_client(client, sway_layer->layer_surface->output);
@@ -282,7 +278,6 @@ static void handle_output_destroy(struct wl_listener *listener, void *data) {
}
}
- sway_layer->layer_surface->output = NULL;
wlr_layer_surface_v1_destroy(sway_layer->layer_surface);
}
@@ -291,10 +286,7 @@ static void handle_surface_commit(struct wl_listener *listener, void *data) {
wl_container_of(listener, layer, surface_commit);
struct wlr_layer_surface_v1 *layer_surface = layer->layer_surface;
struct wlr_output *wlr_output = layer_surface->output;
- if (wlr_output == NULL) {
- return;
- }
-
+ sway_assert(wlr_output, "wlr_layer_surface_v1 has null output");
struct sway_output *output = wlr_output->data;
struct wlr_box old_extent = layer->extent;
@@ -341,13 +333,8 @@ static void unmap(struct sway_layer_surface *sway_layer) {
cursor_rebase_all();
struct wlr_output *wlr_output = sway_layer->layer_surface->output;
- if (wlr_output == NULL) {
- return;
- }
+ sway_assert(wlr_output, "wlr_layer_surface_v1 has null output");
struct sway_output *output = wlr_output->data;
- if (output == NULL) {
- return;
- }
output_damage_surface(output, sway_layer->geo.x, sway_layer->geo.y,
sway_layer->layer_surface->surface, true);
}
@@ -375,22 +362,24 @@ static void handle_destroy(struct wl_listener *listener, void *data) {
wl_list_remove(&sway_layer->surface_commit.link);
wl_list_remove(&sway_layer->new_popup.link);
wl_list_remove(&sway_layer->new_subsurface.link);
- if (sway_layer->layer_surface->output != NULL) {
- struct sway_output *output = sway_layer->layer_surface->output->data;
- if (output != NULL) {
- arrange_layers(output);
- transaction_commit_dirty();
- }
- wl_list_remove(&sway_layer->output_destroy.link);
- sway_layer->layer_surface->output = NULL;
- }
+
+ struct wlr_output *wlr_output = sway_layer->layer_surface->output;
+ sway_assert(wlr_output, "wlr_layer_surface_v1 has null output");
+ struct sway_output *output = wlr_output->data;
+ arrange_layers(output);
+ transaction_commit_dirty();
+ wl_list_remove(&sway_layer->output_destroy.link);
+ sway_layer->layer_surface->output = NULL;
+
free(sway_layer);
}
static void handle_map(struct wl_listener *listener, void *data) {
struct sway_layer_surface *sway_layer = wl_container_of(listener,
sway_layer, map);
- struct sway_output *output = sway_layer->layer_surface->output->data;
+ struct wlr_output *wlr_output = sway_layer->layer_surface->output;
+ sway_assert(wlr_output, "wlr_layer_surface_v1 has null output");
+ struct sway_output *output = wlr_output->data;
output_damage_surface(output, sway_layer->geo.x, sway_layer->geo.y,
sway_layer->layer_surface->surface, true);
wlr_surface_send_enter(sway_layer->layer_surface->surface,
@@ -408,9 +397,7 @@ static void subsurface_damage(struct sway_layer_subsurface *subsurface,
bool whole) {
struct sway_layer_surface *layer = subsurface->layer_surface;
struct wlr_output *wlr_output = layer->layer_surface->output;
- if (!wlr_output) {
- return;
- }
+ sway_assert(wlr_output, "wlr_layer_surface_v1 has null output");
struct sway_output *output = wlr_output->data;
int ox = subsurface->wlr_subsurface->current.x + layer->geo.x;
int oy = subsurface->wlr_subsurface->current.y + layer->geo.y;
@@ -496,15 +483,15 @@ static struct sway_layer_surface *popup_get_layer(
static void popup_damage(struct sway_layer_popup *layer_popup, bool whole) {
struct wlr_xdg_popup *popup = layer_popup->wlr_popup;
struct wlr_surface *surface = popup->base->surface;
- int popup_sx = popup->geometry.x - popup->base->current.geometry.x;
- int popup_sy = popup->geometry.y - popup->base->current.geometry.y;
+ int popup_sx = popup->current.geometry.x - popup->base->current.geometry.x;
+ int popup_sy = popup->current.geometry.y - popup->base->current.geometry.y;
int ox = popup_sx, oy = popup_sy;
struct sway_layer_surface *layer;
while (true) {
if (layer_popup->parent_type == LAYER_PARENT_POPUP) {
layer_popup = layer_popup->parent_popup;
- ox += layer_popup->wlr_popup->geometry.x;
- oy += layer_popup->wlr_popup->geometry.y;
+ ox += layer_popup->wlr_popup->current.geometry.x;
+ oy += layer_popup->wlr_popup->current.geometry.y;
} else {
layer = layer_popup->parent_layer;
ox += layer->geo.x;
@@ -513,6 +500,7 @@ static void popup_damage(struct sway_layer_popup *layer_popup, bool whole) {
}
}
struct wlr_output *wlr_output = layer->layer_surface->output;
+ sway_assert(wlr_output, "wlr_layer_surface_v1 has null output");
struct sway_output *output = wlr_output->data;
output_damage_surface(output, ox, oy, surface, whole);
}
@@ -521,6 +509,7 @@ static void popup_handle_map(struct wl_listener *listener, void *data) {
struct sway_layer_popup *popup = wl_container_of(listener, popup, map);
struct sway_layer_surface *layer = popup_get_layer(popup);
struct wlr_output *wlr_output = layer->layer_surface->output;
+ sway_assert(wlr_output, "wlr_layer_surface_v1 has null output");
wlr_surface_send_enter(popup->wlr_popup->base->surface, wlr_output);
popup_damage(popup, true);
}
@@ -550,7 +539,9 @@ static void popup_unconstrain(struct sway_layer_popup *popup) {
struct sway_layer_surface *layer = popup_get_layer(popup);
struct wlr_xdg_popup *wlr_popup = popup->wlr_popup;
- struct sway_output *output = layer->layer_surface->output->data;
+ struct wlr_output *wlr_output = layer->layer_surface->output;
+ sway_assert(wlr_output, "wlr_layer_surface_v1 has null output");
+ struct sway_output *output = wlr_output->data;
// the output box expressed in the coordinate system of the toplevel parent
// of the popup
@@ -642,6 +633,10 @@ void handle_layer_shell_surface(struct wl_listener *listener, void *data) {
sway_log(SWAY_ERROR,
"no output to auto-assign layer surface '%s' to",
layer_surface->namespace);
+ // Note that layer_surface->output can be NULL
+ // here, but none of our destroy callbacks are
+ // registered yet so we don't have to make them
+ // handle that case.
wlr_layer_surface_v1_destroy(layer_surface);
return;
}
diff --git a/sway/desktop/output.c b/sway/desktop/output.c
index b6d19dd6..182ca428 100644
--- a/sway/desktop/output.c
+++ b/sway/desktop/output.c
@@ -10,11 +10,10 @@
#include <wlr/types/wlr_buffer.h>
#include <wlr/types/wlr_drm_lease_v1.h>
#include <wlr/types/wlr_matrix.h>
-#include <wlr/types/wlr_output_damage.h>
#include <wlr/types/wlr_output_layout.h>
#include <wlr/types/wlr_output.h>
#include <wlr/types/wlr_presentation_time.h>
-#include <wlr/types/wlr_surface.h>
+#include <wlr/types/wlr_compositor.h>
#include <wlr/util/region.h>
#include "config.h"
#include "log.h"
@@ -276,6 +275,25 @@ static void for_each_surface_container_iterator(struct sway_container *con,
static void output_for_each_surface(struct sway_output *output,
sway_surface_iterator_func_t iterator, void *user_data) {
+ if (server.session_lock.locked) {
+ if (server.session_lock.lock == NULL) {
+ return;
+ }
+ struct wlr_session_lock_surface_v1 *lock_surface;
+ wl_list_for_each(lock_surface, &server.session_lock.lock->surfaces, link) {
+ if (lock_surface->output != output->wlr_output) {
+ continue;
+ }
+ if (!lock_surface->mapped) {
+ continue;
+ }
+
+ output_surface_for_each_surface(output, lock_surface->surface,
+ 0.0, 0.0, iterator, user_data);
+ }
+ return;
+ }
+
if (output_has_opaque_overlay_layer_surface(output)) {
goto overlay;
}
@@ -435,6 +453,10 @@ static bool scan_out_fullscreen_view(struct sway_output *output,
return false;
}
+ if (server.session_lock.locked) {
+ return false;
+ }
+
if (!wl_list_empty(&view->saved_buffers)) {
return false;
}
@@ -533,31 +555,43 @@ static int output_repaint_timer_handler(void *data) {
}
}
- bool needs_frame;
+ int buffer_age;
+ if (!wlr_output_attach_render(output->wlr_output, &buffer_age)) {
+ return 0;
+ }
+
pixman_region32_t damage;
pixman_region32_init(&damage);
- if (!wlr_output_damage_attach_render(output->damage,
- &needs_frame, &damage)) {
+ wlr_damage_ring_get_buffer_damage(&output->damage_ring, buffer_age, &damage);
+ if (!output->wlr_output->needs_frame &&
+ !pixman_region32_not_empty(&output->damage_ring.current)) {
+ pixman_region32_fini(&damage);
+ wlr_output_rollback(output->wlr_output);
return 0;
}
- if (needs_frame) {
- struct timespec now;
- clock_gettime(CLOCK_MONOTONIC, &now);
+ struct timespec now;
+ clock_gettime(CLOCK_MONOTONIC, &now);
- output_render(output, &now, &damage);
- } else {
- wlr_output_rollback(output->wlr_output);
- }
+ output_render(output, &now, &damage);
pixman_region32_fini(&damage);
return 0;
}
-static void damage_handle_frame(struct wl_listener *listener, void *user_data) {
+static void handle_damage(struct wl_listener *listener, void *user_data) {
+ struct sway_output *output =
+ wl_container_of(listener, output, damage);
+ struct wlr_output_event_damage *event = user_data;
+ if (wlr_damage_ring_add(&output->damage_ring, event->damage)) {
+ wlr_output_schedule_frame(output->wlr_output);
+ }
+}
+
+static void handle_frame(struct wl_listener *listener, void *user_data) {
struct sway_output *output =
- wl_container_of(listener, output, damage_frame);
+ wl_container_of(listener, output, frame);
if (!output->enabled || !output->wlr_output->enabled) {
return;
}
@@ -620,11 +654,18 @@ static void damage_handle_frame(struct wl_listener *listener, void *user_data) {
send_frame_done(output, &data);
}
+static void handle_needs_frame(struct wl_listener *listener, void *user_data) {
+ struct sway_output *output =
+ wl_container_of(listener, output, needs_frame);
+ wlr_output_schedule_frame(output->wlr_output);
+}
+
void output_damage_whole(struct sway_output *output) {
// The output can exist with no wlr_output if it's just been disconnected
// and the transaction to evacuate it has't completed yet.
- if (output && output->wlr_output && output->damage) {
- wlr_output_damage_add_whole(output->damage);
+ if (output != NULL && output->wlr_output != NULL) {
+ wlr_damage_ring_add_whole(&output->damage_ring);
+ wlr_output_schedule_frame(output->wlr_output);
}
}
@@ -648,11 +689,15 @@ static void damage_surface_iterator(struct sway_output *output,
ceil(output->wlr_output->scale) - surface->current.scale);
}
pixman_region32_translate(&damage, box.x, box.y);
- wlr_output_damage_add(output->damage, &damage);
+ if (wlr_damage_ring_add(&output->damage_ring, &damage)) {
+ wlr_output_schedule_frame(output->wlr_output);
+ }
pixman_region32_fini(&damage);
if (whole) {
- wlr_output_damage_add_box(output->damage, &box);
+ if (wlr_damage_ring_add_box(&output->damage_ring, &box)) {
+ wlr_output_schedule_frame(output->wlr_output);
+ }
}
if (!wl_list_empty(&surface->current.frame_callback_list)) {
@@ -682,7 +727,9 @@ void output_damage_box(struct sway_output *output, struct wlr_box *_box) {
box.x -= output->lx;
box.y -= output->ly;
scale_box(&box, output->wlr_output->scale);
- wlr_output_damage_add_box(output->damage, &box);
+ if (wlr_damage_ring_add_box(&output->damage_ring, &box)) {
+ wlr_output_schedule_frame(output->wlr_output);
+ }
}
static void damage_child_views_iterator(struct sway_container *con,
@@ -706,7 +753,9 @@ void output_damage_whole_container(struct sway_output *output,
.height = con->current.height + 2,
};
scale_box(&box, output->wlr_output->scale);
- wlr_output_damage_add_box(output->damage, &box);
+ if (wlr_damage_ring_add_box(&output->damage_ring, &box)) {
+ wlr_output_schedule_frame(output->wlr_output);
+ }
// Damage subsurfaces as well, which may extend outside the box
if (con->view) {
damage_child_views_iterator(con, output);
@@ -715,20 +764,6 @@ void output_damage_whole_container(struct sway_output *output,
}
}
-static void damage_handle_destroy(struct wl_listener *listener, void *data) {
- struct sway_output *output =
- wl_container_of(listener, output, damage_destroy);
- if (!output->enabled) {
- return;
- }
- output_disable(output);
-
- wl_list_remove(&output->damage_destroy.link);
- wl_list_remove(&output->damage_frame.link);
-
- transaction_commit_dirty();
-}
-
static void update_output_manager_config(struct sway_server *server) {
struct wlr_output_configuration_v1 *config =
wlr_output_configuration_v1_create();
@@ -740,14 +775,15 @@ static void update_output_manager_config(struct sway_server *server) {
}
struct wlr_output_configuration_head_v1 *config_head =
wlr_output_configuration_head_v1_create(config, output->wlr_output);
- struct wlr_box *output_box = wlr_output_layout_get_box(
- root->output_layout, output->wlr_output);
- // We mark the output enabled even if it is switched off by DPMS
+ struct wlr_box output_box;
+ wlr_output_layout_get_box(root->output_layout,
+ output->wlr_output, &output_box);
+ // We mark the output enabled when it's switched off but not disabled
config_head->state.enabled = output->current_mode != NULL && output->enabled;
config_head->state.mode = output->current_mode;
- if (output_box) {
- config_head->state.x = output_box->x;
- config_head->state.y = output_box->y;
+ if (!wlr_box_empty(&output_box)) {
+ config_head->state.x = output_box.x;
+ config_head->state.y = output_box.y;
}
}
@@ -757,18 +793,24 @@ static void update_output_manager_config(struct sway_server *server) {
static void handle_destroy(struct wl_listener *listener, void *data) {
struct sway_output *output = wl_container_of(listener, output, destroy);
struct sway_server *server = output->server;
- output_begin_destroy(output);
if (output->enabled) {
output_disable(output);
}
+ output_begin_destroy(output);
+
wl_list_remove(&output->link);
wl_list_remove(&output->destroy.link);
wl_list_remove(&output->commit.link);
wl_list_remove(&output->mode.link);
wl_list_remove(&output->present.link);
+ wl_list_remove(&output->damage.link);
+ wl_list_remove(&output->frame.link);
+ wl_list_remove(&output->needs_frame.link);
+
+ wlr_damage_ring_finish(&output->damage_ring);
output->wlr_output->data = NULL;
output->wlr_output = NULL;
@@ -796,10 +838,16 @@ static void handle_mode(struct wl_listener *listener, void *data) {
if (!output->enabled) {
return;
}
+
arrange_layers(output);
arrange_output(output);
transaction_commit_dirty();
+ int width, height;
+ wlr_output_transformed_resolution(output->wlr_output, &width, &height);
+ wlr_damage_ring_set_bounds(&output->damage_ring, width, height);
+ wlr_output_schedule_frame(output->wlr_output);
+
update_output_manager_config(output->server);
}
@@ -827,6 +875,13 @@ static void handle_commit(struct wl_listener *listener, void *data) {
update_output_manager_config(output->server);
}
+
+ if (event->committed & (WLR_OUTPUT_STATE_MODE | WLR_OUTPUT_STATE_TRANSFORM)) {
+ int width, height;
+ wlr_output_transformed_resolution(output->wlr_output, &width, &height);
+ wlr_damage_ring_set_bounds(&output->damage_ring, width, height);
+ wlr_output_schedule_frame(output->wlr_output);
+ }
}
static void handle_present(struct wl_listener *listener, void *data) {
@@ -862,10 +917,12 @@ void handle_new_output(struct wl_listener *listener, void *data) {
if (wlr_output->non_desktop) {
sway_log(SWAY_DEBUG, "Not configuring non-desktop output");
+ struct sway_output_non_desktop *non_desktop = output_non_desktop_create(wlr_output);
if (server->drm_lease_manager) {
wlr_drm_lease_v1_manager_offer_output(server->drm_lease_manager,
wlr_output);
}
+ list_add(root->non_desktop_outputs, non_desktop);
return;
}
@@ -880,7 +937,7 @@ void handle_new_output(struct wl_listener *listener, void *data) {
return;
}
output->server = server;
- output->damage = wlr_output_damage_create(wlr_output);
+ wlr_damage_ring_init(&output->damage_ring);
wl_signal_add(&wlr_output->events.destroy, &output->destroy);
output->destroy.notify = handle_destroy;
@@ -890,10 +947,12 @@ void handle_new_output(struct wl_listener *listener, void *data) {
output->mode.notify = handle_mode;
wl_signal_add(&wlr_output->events.present, &output->present);
output->present.notify = handle_present;
- wl_signal_add(&output->damage->events.frame, &output->damage_frame);
- output->damage_frame.notify = damage_handle_frame;
- wl_signal_add(&output->damage->events.destroy, &output->damage_destroy);
- output->damage_destroy.notify = damage_handle_destroy;
+ wl_signal_add(&wlr_output->events.damage, &output->damage);
+ output->damage.notify = handle_damage;
+ wl_signal_add(&wlr_output->events.frame, &output->frame);
+ output->frame.notify = handle_frame;
+ wl_signal_add(&wlr_output->events.needs_frame, &output->needs_frame);
+ output->needs_frame.notify = handle_needs_frame;
output->repaint_timer = wl_event_loop_add_timer(server->wl_event_loop,
output_repaint_timer_handler, output);
@@ -1007,10 +1066,10 @@ void handle_output_power_manager_set_mode(struct wl_listener *listener,
struct output_config *oc = new_output_config(output->wlr_output->name);
switch (event->mode) {
case ZWLR_OUTPUT_POWER_V1_MODE_OFF:
- oc->dpms_state = DPMS_OFF;
+ oc->power = 0;
break;
case ZWLR_OUTPUT_POWER_V1_MODE_ON:
- oc->dpms_state = DPMS_ON;
+ oc->power = 1;
break;
}
oc = store_output_config(oc);
diff --git a/sway/desktop/render.c b/sway/desktop/render.c
index 6247d937..35e2150e 100644
--- a/sway/desktop/render.c
+++ b/sway/desktop/render.c
@@ -9,11 +9,11 @@
#include <wlr/render/gles2.h>
#include <wlr/render/wlr_renderer.h>
#include <wlr/types/wlr_buffer.h>
+#include <wlr/types/wlr_damage_ring.h>
#include <wlr/types/wlr_matrix.h>
-#include <wlr/types/wlr_output_damage.h>
#include <wlr/types/wlr_output_layout.h>
#include <wlr/types/wlr_output.h>
-#include <wlr/types/wlr_surface.h>
+#include <wlr/types/wlr_compositor.h>
#include <wlr/util/region.h>
#include "log.h"
#include "config.h"
@@ -1301,6 +1301,41 @@ void output_render(struct sway_output *output, struct timespec *when,
fx_renderer_clear((float[]){1, 1, 0, 1});
}
+ if (server.session_lock.locked) {
+ float clear_color[] = {0.0f, 0.0f, 0.0f, 1.0f};
+ if (server.session_lock.lock == NULL) {
+ // abandoned lock -> red BG
+ clear_color[0] = 1.f;
+ }
+ int nrects;
+ pixman_box32_t *rects = pixman_region32_rectangles(damage, &nrects);
+ for (int i = 0; i < nrects; ++i) {
+ scissor_output(wlr_output, &rects[i]);
+ fx_renderer_clear(clear_color);
+ }
+
+ if (server.session_lock.lock != NULL) {
+ struct render_data data = {
+ .damage = damage,
+ .deco_data = get_undecorated_decoration_data(),
+ };
+
+ struct wlr_session_lock_surface_v1 *lock_surface;
+ wl_list_for_each(lock_surface, &server.session_lock.lock->surfaces, link) {
+ if (lock_surface->output != wlr_output) {
+ continue;
+ }
+ if (!lock_surface->mapped) {
+ continue;
+ }
+
+ output_surface_for_each_surface(output, lock_surface->surface,
+ 0.0, 0.0, render_surface_iterator, &data);
+ }
+ }
+ goto renderer_end;
+ }
+
if (output_has_opaque_overlay_layer_surface(output)) {
goto render_overlay;
}
@@ -1409,7 +1444,7 @@ renderer_end:
enum wl_output_transform transform =
wlr_output_transform_invert(wlr_output->transform);
- wlr_region_transform(&frame_damage, &output->damage->current,
+ wlr_region_transform(&frame_damage, &output->damage_ring.current,
transform, width, height);
if (debug.damage != DAMAGE_DEFAULT) {
@@ -1423,5 +1458,7 @@ renderer_end:
if (!wlr_output_commit(wlr_output)) {
return;
}
+
+ wlr_damage_ring_rotate(&output->damage_ring);
output->last_frame = *when;
}
diff --git a/sway/desktop/surface.c b/sway/desktop/surface.c
index 767b2045..1d7b536d 100644
--- a/sway/desktop/surface.c
+++ b/sway/desktop/surface.c
@@ -1,7 +1,7 @@
#define _POSIX_C_SOURCE 200112L
#include <stdlib.h>
#include <time.h>
-#include <wlr/types/wlr_surface.h>
+#include <wlr/types/wlr_compositor.h>
#include "sway/server.h"
#include "sway/surface.h"
diff --git a/sway/desktop/xdg_shell.c b/sway/desktop/xdg_shell.c
index 5fae8296..8da922d5 100644
--- a/sway/desktop/xdg_shell.c
+++ b/sway/desktop/xdg_shell.c
@@ -24,11 +24,11 @@ static const struct sway_view_child_impl popup_impl;
static void popup_get_view_coords(struct sway_view_child *child,
int *sx, int *sy) {
struct sway_xdg_popup *popup = (struct sway_xdg_popup *)child;
- struct wlr_xdg_surface *surface = popup->wlr_xdg_surface;
+ struct wlr_xdg_popup *wlr_popup = popup->wlr_xdg_popup;
- wlr_xdg_popup_get_toplevel_coords(surface->popup,
- surface->popup->geometry.x - surface->current.geometry.x,
- surface->popup->geometry.y - surface->current.geometry.y,
+ wlr_xdg_popup_get_toplevel_coords(wlr_popup,
+ wlr_popup->current.geometry.x - wlr_popup->base->current.geometry.x,
+ wlr_popup->current.geometry.y - wlr_popup->base->current.geometry.y,
sx, sy);
}
@@ -65,7 +65,7 @@ static void popup_handle_destroy(struct wl_listener *listener, void *data) {
static void popup_unconstrain(struct sway_xdg_popup *popup) {
struct sway_view *view = popup->child.view;
- struct wlr_xdg_popup *wlr_popup = popup->wlr_xdg_surface->popup;
+ struct wlr_xdg_popup *wlr_popup = popup->wlr_xdg_popup;
struct sway_output *output = view->container->pending.workspace->output;
@@ -91,7 +91,7 @@ static struct sway_xdg_popup *popup_create(
return NULL;
}
view_child_init(&popup->child, &popup_impl, view, xdg_surface->surface);
- popup->wlr_xdg_surface = xdg_surface;
+ popup->wlr_xdg_popup = xdg_surface->popup;
wl_signal_add(&xdg_surface->events.new_popup, &popup->new_popup);
popup->new_popup.notify = popup_handle_new_popup;
@@ -119,7 +119,7 @@ static struct sway_xdg_shell_view *xdg_shell_view_from_view(
static void get_constraints(struct sway_view *view, double *min_width,
double *max_width, double *min_height, double *max_height) {
struct wlr_xdg_toplevel_state *state =
- &view->wlr_xdg_surface->toplevel->current;
+ &view->wlr_xdg_toplevel->current;
*min_width = state->min_width > 0 ? state->min_width : DBL_MIN;
*max_width = state->max_width > 0 ? state->max_width : DBL_MAX;
*min_height = state->min_height > 0 ? state->min_height : DBL_MIN;
@@ -133,9 +133,9 @@ static const char *get_string_prop(struct sway_view *view,
}
switch (prop) {
case VIEW_PROP_TITLE:
- return view->wlr_xdg_surface->toplevel->title;
+ return view->wlr_xdg_toplevel->title;
case VIEW_PROP_APP_ID:
- return view->wlr_xdg_surface->toplevel->app_id;
+ return view->wlr_xdg_toplevel->app_id;
default:
return NULL;
}
@@ -148,50 +148,45 @@ static uint32_t configure(struct sway_view *view, double lx, double ly,
if (xdg_shell_view == NULL) {
return 0;
}
- return wlr_xdg_toplevel_set_size(view->wlr_xdg_surface, width, height);
+ return wlr_xdg_toplevel_set_size(view->wlr_xdg_toplevel,
+ width, height);
}
static void set_activated(struct sway_view *view, bool activated) {
if (xdg_shell_view_from_view(view) == NULL) {
return;
}
- struct wlr_xdg_surface *surface = view->wlr_xdg_surface;
- if (surface->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL) {
- wlr_xdg_toplevel_set_activated(surface, activated);
- }
+ wlr_xdg_toplevel_set_activated(view->wlr_xdg_toplevel, activated);
}
static void set_tiled(struct sway_view *view, bool tiled) {
if (xdg_shell_view_from_view(view) == NULL) {
return;
}
- struct wlr_xdg_surface *surface = view->wlr_xdg_surface;
enum wlr_edges edges = WLR_EDGE_NONE;
if (tiled) {
edges = WLR_EDGE_LEFT | WLR_EDGE_RIGHT | WLR_EDGE_TOP |
WLR_EDGE_BOTTOM;
}
- wlr_xdg_toplevel_set_tiled(surface, edges);
+ wlr_xdg_toplevel_set_tiled(view->wlr_xdg_toplevel, edges);
}
static void set_fullscreen(struct sway_view *view, bool fullscreen) {
if (xdg_shell_view_from_view(view) == NULL) {
return;
}
- struct wlr_xdg_surface *surface = view->wlr_xdg_surface;
- wlr_xdg_toplevel_set_fullscreen(surface, fullscreen);
+ wlr_xdg_toplevel_set_fullscreen(view->wlr_xdg_toplevel, fullscreen);
}
static void set_resizing(struct sway_view *view, bool resizing) {
if (xdg_shell_view_from_view(view) == NULL) {
return;
}
- struct wlr_xdg_surface *surface = view->wlr_xdg_surface;
- wlr_xdg_toplevel_set_resizing(surface, resizing);
+ wlr_xdg_toplevel_set_resizing(view->wlr_xdg_toplevel, resizing);
}
static bool wants_floating(struct sway_view *view) {
- struct wlr_xdg_toplevel *toplevel = view->wlr_xdg_surface->toplevel;
+ struct wlr_xdg_toplevel *toplevel = view->wlr_xdg_toplevel;
struct wlr_xdg_toplevel_state *state = &toplevel->current;
return (state->min_width != 0 && state->min_height != 0
&& (state->min_width == state->max_width
@@ -204,7 +199,7 @@ static void for_each_surface(struct sway_view *view,
if (xdg_shell_view_from_view(view) == NULL) {
return;
}
- wlr_xdg_surface_for_each_surface(view->wlr_xdg_surface, iterator,
+ wlr_xdg_surface_for_each_surface(view->wlr_xdg_toplevel->base, iterator,
user_data);
}
@@ -213,8 +208,8 @@ static void for_each_popup_surface(struct sway_view *view,
if (xdg_shell_view_from_view(view) == NULL) {
return;
}
- wlr_xdg_surface_for_each_popup_surface(view->wlr_xdg_surface, iterator,
- user_data);
+ wlr_xdg_surface_for_each_popup_surface(view->wlr_xdg_toplevel->base,
+ iterator, user_data);
}
static bool is_transient_for(struct sway_view *child,
@@ -222,12 +217,12 @@ static bool is_transient_for(struct sway_view *child,
if (xdg_shell_view_from_view(child) == NULL) {
return false;
}
- struct wlr_xdg_surface *surface = child->wlr_xdg_surface;
- while (surface && surface->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL) {
- if (surface->toplevel->parent == ancestor->wlr_xdg_surface) {
+ struct wlr_xdg_toplevel *toplevel = child->wlr_xdg_toplevel;
+ while (toplevel) {
+ if (toplevel->parent == ancestor->wlr_xdg_toplevel) {
return true;
}
- surface = surface->toplevel->parent;
+ toplevel = toplevel->parent;
}
return false;
}
@@ -236,17 +231,13 @@ static void _close(struct sway_view *view) {
if (xdg_shell_view_from_view(view) == NULL) {
return;
}
- struct wlr_xdg_surface *surface = view->wlr_xdg_surface;
- if (surface->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL
- && surface->toplevel) {
- wlr_xdg_toplevel_send_close(surface);
- }
+ wlr_xdg_toplevel_send_close(view->wlr_xdg_toplevel);
}
static void close_popups(struct sway_view *view) {
struct wlr_xdg_popup *popup, *tmp;
- wl_list_for_each_safe(popup, tmp, &view->wlr_xdg_surface->popups, link) {
- wlr_xdg_popup_destroy(popup->base);
+ wl_list_for_each_safe(popup, tmp, &view->wlr_xdg_toplevel->base->popups, link) {
+ wlr_xdg_popup_destroy(popup);
}
}
@@ -280,7 +271,7 @@ 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;
- struct wlr_xdg_surface *xdg_surface = view->wlr_xdg_surface;
+ struct wlr_xdg_surface *xdg_surface = view->wlr_xdg_toplevel->base;
struct wlr_box new_geo;
wlr_xdg_surface_get_geometry(xdg_surface, &new_geo);
@@ -334,26 +325,27 @@ static void handle_new_popup(struct wl_listener *listener, void *data) {
popup_create(wlr_popup, &xdg_shell_view->view);
}
+static void handle_request_maximize(struct wl_listener *listener, void *data) {
+ struct sway_xdg_shell_view *xdg_shell_view =
+ wl_container_of(listener, xdg_shell_view, request_maximize);
+ struct wlr_xdg_toplevel *toplevel = xdg_shell_view->view.wlr_xdg_toplevel;
+ wlr_xdg_surface_schedule_configure(toplevel->base);
+}
+
static void handle_request_fullscreen(struct wl_listener *listener, void *data) {
struct sway_xdg_shell_view *xdg_shell_view =
wl_container_of(listener, xdg_shell_view, request_fullscreen);
- struct wlr_xdg_toplevel_set_fullscreen_event *e = data;
- struct wlr_xdg_surface *xdg_surface =
- xdg_shell_view->view.wlr_xdg_surface;
+ struct wlr_xdg_toplevel *toplevel = xdg_shell_view->view.wlr_xdg_toplevel;
struct sway_view *view = &xdg_shell_view->view;
- if (!sway_assert(xdg_surface->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL,
- "xdg_shell requested fullscreen of surface with role %i",
- xdg_surface->role)) {
- return;
- }
- if (!xdg_surface->mapped) {
+ if (!toplevel->base->mapped) {
return;
}
struct sway_container *container = view->container;
- if (e->fullscreen && e->output && e->output->data) {
- struct sway_output *output = e->output->data;
+ struct wlr_xdg_toplevel_requested *req = &toplevel->requested;
+ if (req->fullscreen && req->fullscreen_output && req->fullscreen_output->data) {
+ struct sway_output *output = req->fullscreen_output->data;
struct sway_workspace *ws = output_get_active_workspace(output);
if (ws && !container_is_scratchpad_hidden(container) &&
container->pending.workspace != ws) {
@@ -365,7 +357,7 @@ static void handle_request_fullscreen(struct wl_listener *listener, void *data)
}
}
- container_set_fullscreen(container, e->fullscreen);
+ container_set_fullscreen(container, req->fullscreen);
arrange_root();
transaction_commit_dirty();
@@ -375,7 +367,8 @@ static void handle_request_move(struct wl_listener *listener, void *data) {
struct sway_xdg_shell_view *xdg_shell_view =
wl_container_of(listener, xdg_shell_view, request_move);
struct sway_view *view = &xdg_shell_view->view;
- if (!container_is_floating(view->container)) {
+ if (!container_is_floating(view->container) ||
+ view->container->pending.fullscreen_mode) {
return;
}
struct wlr_xdg_toplevel_move_event *e = data;
@@ -412,6 +405,7 @@ static void handle_unmap(struct wl_listener *listener, void *data) {
wl_list_remove(&xdg_shell_view->commit.link);
wl_list_remove(&xdg_shell_view->new_popup.link);
+ wl_list_remove(&xdg_shell_view->request_maximize.link);
wl_list_remove(&xdg_shell_view->request_fullscreen.link);
wl_list_remove(&xdg_shell_view->request_move.link);
wl_list_remove(&xdg_shell_view->request_resize.link);
@@ -423,13 +417,13 @@ static void handle_map(struct wl_listener *listener, void *data) {
struct sway_xdg_shell_view *xdg_shell_view =
wl_container_of(listener, xdg_shell_view, map);
struct sway_view *view = &xdg_shell_view->view;
- struct wlr_xdg_surface *xdg_surface = view->wlr_xdg_surface;
+ struct wlr_xdg_toplevel *toplevel = view->wlr_xdg_toplevel;
- view->natural_width = view->wlr_xdg_surface->current.geometry.width;
- view->natural_height = view->wlr_xdg_surface->current.geometry.height;
+ view->natural_width = toplevel->base->current.geometry.width;
+ view->natural_height = toplevel->base->current.geometry.height;
if (!view->natural_width && !view->natural_height) {
- view->natural_width = view->wlr_xdg_surface->surface->current.width;
- view->natural_height = view->wlr_xdg_surface->surface->current.height;
+ view->natural_width = toplevel->base->surface->current.width;
+ view->natural_height = toplevel->base->surface->current.height;
}
bool csd = false;
@@ -440,44 +434,48 @@ static void handle_map(struct wl_listener *listener, void *data) {
csd = mode == WLR_XDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE;
} else {
struct sway_server_decoration *deco =
- decoration_from_surface(xdg_surface->surface);
+ decoration_from_surface(toplevel->base->surface);
csd = !deco || deco->wlr_server_decoration->mode ==
WLR_SERVER_DECORATION_MANAGER_MODE_CLIENT;
}
- view_map(view, view->wlr_xdg_surface->surface,
- xdg_surface->toplevel->requested.fullscreen,
- xdg_surface->toplevel->requested.fullscreen_output,
+ view_map(view, toplevel->base->surface,
+ toplevel->requested.fullscreen,
+ toplevel->requested.fullscreen_output,
csd);
transaction_commit_dirty();
xdg_shell_view->commit.notify = handle_commit;
- wl_signal_add(&xdg_surface->surface->events.commit,
+ wl_signal_add(&toplevel->base->surface->events.commit,
&xdg_shell_view->commit);
xdg_shell_view->new_popup.notify = handle_new_popup;
- wl_signal_add(&xdg_surface->events.new_popup,
+ wl_signal_add(&toplevel->base->events.new_popup,
&xdg_shell_view->new_popup);
+ xdg_shell_view->request_maximize.notify = handle_request_maximize;
+ wl_signal_add(&toplevel->events.request_maximize,
+ &xdg_shell_view->request_maximize);
+
xdg_shell_view->request_fullscreen.notify = handle_request_fullscreen;
- wl_signal_add(&xdg_surface->toplevel->events.request_fullscreen,
+ wl_signal_add(&toplevel->events.request_fullscreen,
&xdg_shell_view->request_fullscreen);
xdg_shell_view->request_move.notify = handle_request_move;
- wl_signal_add(&xdg_surface->toplevel->events.request_move,
+ wl_signal_add(&toplevel->events.request_move,
&xdg_shell_view->request_move);
xdg_shell_view->request_resize.notify = handle_request_resize;
- wl_signal_add(&xdg_surface->toplevel->events.request_resize,
+ wl_signal_add(&toplevel->events.request_resize,
&xdg_shell_view->request_resize);
xdg_shell_view->set_title.notify = handle_set_title;
- wl_signal_add(&xdg_surface->toplevel->events.set_title,
+ wl_signal_add(&toplevel->events.set_title,
&xdg_shell_view->set_title);
xdg_shell_view->set_app_id.notify = handle_set_app_id;
- wl_signal_add(&xdg_surface->toplevel->events.set_app_id,
+ wl_signal_add(&toplevel->events.set_app_id,
&xdg_shell_view->set_app_id);
}
@@ -491,7 +489,7 @@ static void handle_destroy(struct wl_listener *listener, void *data) {
wl_list_remove(&xdg_shell_view->destroy.link);
wl_list_remove(&xdg_shell_view->map.link);
wl_list_remove(&xdg_shell_view->unmap.link);
- view->wlr_xdg_surface = NULL;
+ view->wlr_xdg_toplevel = NULL;
if (view->xdg_decoration) {
view->xdg_decoration->view = NULL;
}
@@ -522,7 +520,7 @@ void handle_xdg_shell_surface(struct wl_listener *listener, void *data) {
}
view_init(&xdg_shell_view->view, SWAY_VIEW_XDG_SHELL, &view_impl);
- xdg_shell_view->view.wlr_xdg_surface = xdg_surface;
+ xdg_shell_view->view.wlr_xdg_toplevel = xdg_surface->toplevel;
xdg_shell_view->map.notify = handle_map;
wl_signal_add(&xdg_surface->events.map, &xdg_shell_view->map);
diff --git a/sway/desktop/xwayland.c b/sway/desktop/xwayland.c
index 40288f97..e15a3341 100644
--- a/sway/desktop/xwayland.c
+++ b/sway/desktop/xwayland.c
@@ -5,7 +5,9 @@
#include <wayland-server-core.h>
#include <wlr/types/wlr_output_layout.h>
#include <wlr/types/wlr_output.h>
+#include <wlr/types/wlr_xdg_activation_v1.h>
#include <wlr/xwayland.h>
+#include <xcb/xcb_icccm.h>
#include "log.h"
#include "sway/desktop.h"
#include "sway/desktop/transaction.h"
@@ -15,6 +17,7 @@
#include "sway/output.h"
#include "sway/tree/arrange.h"
#include "sway/tree/container.h"
+#include "sway/server.h"
#include "sway/tree/view.h"
#include "sway/tree/workspace.h"
@@ -121,6 +124,20 @@ static void unmanaged_handle_unmap(struct wl_listener *listener, void *data) {
}
}
+static void unmanaged_handle_request_activate(struct wl_listener *listener, void *data) {
+ struct wlr_xwayland_surface *xsurface = data;
+ if (!xsurface->mapped) {
+ return;
+ }
+ struct sway_seat *seat = input_manager_current_seat();
+ struct sway_container *focus = seat_get_focused_container(seat);
+ if (focus && focus->view && focus->view->pid != xsurface->pid) {
+ return;
+ }
+
+ seat_set_focus_surface(seat, xsurface->surface, false);
+}
+
static void unmanaged_handle_destroy(struct wl_listener *listener, void *data) {
struct sway_xwayland_unmanaged *surface =
wl_container_of(listener, surface, destroy);
@@ -129,6 +146,7 @@ static void unmanaged_handle_destroy(struct wl_listener *listener, void *data) {
wl_list_remove(&surface->unmap.link);
wl_list_remove(&surface->destroy.link);
wl_list_remove(&surface->override_redirect.link);
+ wl_list_remove(&surface->request_activate.link);
free(surface);
}
@@ -176,6 +194,8 @@ static struct sway_xwayland_unmanaged *create_unmanaged(
surface->destroy.notify = unmanaged_handle_destroy;
wl_signal_add(&xsurface->events.set_override_redirect, &surface->override_redirect);
surface->override_redirect.notify = unmanaged_handle_override_redirect;
+ wl_signal_add(&xsurface->events.request_activate, &surface->request_activate);
+ surface->request_activate.notify = unmanaged_handle_request_activate;
return surface;
}
@@ -294,7 +314,7 @@ static bool wants_floating(struct sway_view *view) {
}
}
- struct wlr_xwayland_surface_size_hints *size_hints = surface->size_hints;
+ xcb_size_hints_t *size_hints = surface->size_hints;
if (size_hints != NULL &&
size_hints->min_width > 0 && size_hints->min_height > 0 &&
(size_hints->max_width == size_hints->min_width ||
@@ -348,7 +368,7 @@ static void destroy(struct sway_view *view) {
static void get_constraints(struct sway_view *view, double *min_width,
double *max_width, double *min_height, double *max_height) {
struct wlr_xwayland_surface *surface = view->wlr_xwayland_surface;
- struct wlr_xwayland_surface_size_hints *size_hints = surface->size_hints;
+ xcb_size_hints_t *size_hints = surface->size_hints;
if (size_hints == NULL) {
*min_width = DBL_MIN;
@@ -448,6 +468,7 @@ static void handle_destroy(struct wl_listener *listener, void *data) {
wl_list_remove(&xwayland_view->set_title.link);
wl_list_remove(&xwayland_view->set_class.link);
wl_list_remove(&xwayland_view->set_role.link);
+ wl_list_remove(&xwayland_view->set_startup_id.link);
wl_list_remove(&xwayland_view->set_window_type.link);
wl_list_remove(&xwayland_view->set_hints.link);
wl_list_remove(&xwayland_view->set_decorations.link);
@@ -577,7 +598,8 @@ static void handle_request_move(struct wl_listener *listener, void *data) {
if (!xsurface->mapped) {
return;
}
- if (!container_is_floating(view->container)) {
+ if (!container_is_floating(view->container) ||
+ view->container->pending.fullscreen_mode) {
return;
}
struct sway_seat *seat = input_manager_current_seat();
@@ -647,6 +669,31 @@ static void handle_set_role(struct wl_listener *listener, void *data) {
view_execute_criteria(view);
}
+static void handle_set_startup_id(struct wl_listener *listener, void *data) {
+ struct sway_xwayland_view *xwayland_view =
+ wl_container_of(listener, xwayland_view, set_startup_id);
+ struct sway_view *view = &xwayland_view->view;
+ struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface;
+ if (xsurface->startup_id == NULL) {
+ return;
+ }
+
+ struct wlr_xdg_activation_token_v1 *token =
+ wlr_xdg_activation_v1_find_token(
+ server.xdg_activation_v1, xsurface->startup_id);
+ if (token == NULL) {
+ // Tried to activate with an unknown or expired token
+ return;
+ }
+
+ struct launcher_ctx *ctx = token->data;
+ if (token->data == NULL) {
+ // TODO: support external launchers in X
+ return;
+ }
+ view_assign_ctx(view, ctx);
+}
+
static void handle_set_window_type(struct wl_listener *listener, void *data) {
struct sway_xwayland_view *xwayland_view =
wl_container_of(listener, xwayland_view, set_window_type);
@@ -666,14 +713,15 @@ static void handle_set_hints(struct wl_listener *listener, void *data) {
if (!xsurface->mapped) {
return;
}
- if (!xsurface->hints_urgency && view->urgent_timer) {
+ const bool hints_urgency = xcb_icccm_wm_hints_get_urgency(xsurface->hints);
+ if (!hints_urgency && view->urgent_timer) {
// The view is in the timeout period. We'll ignore the request to
// unset urgency so that the view remains urgent until the timer clears
// it.
return;
}
if (view->allow_request_urgent) {
- view_set_urgent(view, (bool)xsurface->hints_urgency);
+ view_set_urgent(view, hints_urgency);
}
}
@@ -731,6 +779,10 @@ struct sway_xwayland_view *create_xwayland_view(struct wlr_xwayland_surface *xsu
wl_signal_add(&xsurface->events.set_role, &xwayland_view->set_role);
xwayland_view->set_role.notify = handle_set_role;
+ wl_signal_add(&xsurface->events.set_startup_id,
+ &xwayland_view->set_startup_id);
+ xwayland_view->set_startup_id.notify = handle_set_startup_id;
+
wl_signal_add(&xsurface->events.set_window_type,
&xwayland_view->set_window_type);
xwayland_view->set_window_type.notify = handle_set_window_type;