From cda66e9a263d8467b6d1857808305d5e9f7bc3cd Mon Sep 17 00:00:00 2001
From: emersion <contact@emersion.fr>
Date: Mon, 18 Jun 2018 22:49:28 +0100
Subject: Automatically float xwayland windows

---
 include/sway/server.h   |  9 ++----
 include/sway/xwayland.h | 25 +++++++++++++++
 meson.build             |  3 +-
 sway/desktop/xwayland.c | 83 +++++++++++++++++++++++++++++++++++++++++++------
 sway/input/seat.c       |  3 +-
 sway/meson.build        |  1 +
 sway/server.c           | 18 ++++++-----
 7 files changed, 116 insertions(+), 26 deletions(-)
 create mode 100644 include/sway/xwayland.h

diff --git a/include/sway/server.h b/include/sway/server.h
index 65d96e7a..96cad69d 100644
--- a/include/sway/server.h
+++ b/include/sway/server.h
@@ -11,7 +11,7 @@
 #include <wlr/types/wlr_xdg_shell.h>
 #include <wlr/render/wlr_renderer.h>
 // TODO WLR: make Xwayland optional
-#include <wlr/xwayland.h>
+#include "sway/xwayland.h"
 
 struct sway_server {
 	struct wl_display *wl_display;
@@ -37,12 +37,9 @@ struct sway_server {
 	struct wlr_xdg_shell *xdg_shell;
 	struct wl_listener xdg_shell_surface;
 
-	struct wlr_xwayland *xwayland;
-	struct wlr_xcursor_manager *xcursor_manager;
+	struct sway_xwayland xwayland;
 	struct wl_listener xwayland_surface;
-
-	struct wlr_wl_shell *wl_shell;
-	struct wl_listener wl_shell_surface;
+	struct wl_listener xwayland_ready;
 };
 
 struct sway_server server;
diff --git a/include/sway/xwayland.h b/include/sway/xwayland.h
new file mode 100644
index 00000000..78d1053b
--- /dev/null
+++ b/include/sway/xwayland.h
@@ -0,0 +1,25 @@
+#ifndef SWAY_XWAYLAND_H
+#define SWAY_XWAYLAND_H
+
+#include <wlr/xwayland.h>
+#include <xcb/xproto.h>
+
+enum atom_name {
+	NET_WM_WINDOW_TYPE_DIALOG,
+	NET_WM_WINDOW_TYPE_UTILITY,
+	NET_WM_WINDOW_TYPE_TOOLBAR,
+	NET_WM_WINDOW_TYPE_SPLASH,
+	NET_WM_STATE_MODAL,
+	ATOM_LAST,
+};
+
+struct sway_xwayland {
+	struct wlr_xwayland *wlr_xwayland;
+	struct wlr_xcursor_manager *xcursor_manager;
+
+	xcb_atom_t atoms[ATOM_LAST];
+};
+
+void handle_xwayland_ready(struct wl_listener *listener, void *data);
+
+#endif
diff --git a/meson.build b/meson.build
index d4ee1a11..1d40581a 100644
--- a/meson.build
+++ b/meson.build
@@ -43,7 +43,8 @@ systemd        = dependency('libsystemd', required: false)
 elogind        = dependency('libelogind', required: false)
 math           = cc.find_library('m')
 rt             = cc.find_library('rt')
-git = find_program('git', required: false)
+xcb            = dependency('xcb')
+git            = find_program('git', required: false)
 
 conf_data = configuration_data()
 
diff --git a/sway/desktop/xwayland.c b/sway/desktop/xwayland.c
index 6447b711..2c3848cd 100644
--- a/sway/desktop/xwayland.c
+++ b/sway/desktop/xwayland.c
@@ -15,6 +15,14 @@
 #include "sway/tree/layout.h"
 #include "sway/tree/view.h"
 
+static const char *atom_map[ATOM_LAST] = {
+	"_NET_WM_WINDOW_TYPE_DIALOG",
+	"_NET_WM_WINDOW_TYPE_UTILITY",
+	"_NET_WM_WINDOW_TYPE_TOOLBAR",
+	"_NET_WM_WINDOW_TYPE_SPLASH",
+	"_NET_WM_STATE_MODAL",
+};
+
 static void unmanaged_handle_request_configure(struct wl_listener *listener,
 		void *data) {
 	struct sway_xwayland_unmanaged *surface =
@@ -61,7 +69,8 @@ static void unmanaged_handle_map(struct wl_listener *listener, void *data) {
 
 	if (!wlr_xwayland_surface_is_unmanaged(xsurface)) {
 		struct sway_seat *seat = input_manager_current_seat(input_manager);
-		struct wlr_xwayland *xwayland = seat->input->server->xwayland;
+		struct wlr_xwayland *xwayland =
+			seat->input->server->xwayland.wlr_xwayland;
 		wlr_xwayland_set_seat(xwayland, seat->wlr_seat);
 		seat_set_focus_surface(seat, xsurface->surface);
 	}
@@ -199,15 +208,32 @@ static void set_fullscreen(struct sway_view *view, bool fullscreen) {
 }
 
 static bool wants_floating(struct sway_view *view) {
-	// TODO:
-	// We want to return true if the window type contains any of these:
-	// NET_WM_WINDOW_TYPE_DIALOG
-	// NET_WM_WINDOW_TYPE_UTILITY
-	// NET_WM_WINDOW_TYPE_TOOLBAR
-	// NET_WM_WINDOW_TYPE_SPLASH
-	//
-	// We also want to return true if the NET_WM_STATE is MODAL.
-	// wlroots doesn't appear to provide all this information at the moment.
+	if (xwayland_view_from_view(view) == NULL) {
+		return false;
+	}
+	struct wlr_xwayland_surface *surface = view->wlr_xwayland_surface;
+	struct sway_xwayland *xwayland = &server.xwayland;
+
+	// TODO: return true if the NET_WM_STATE is MODAL
+
+	for (size_t i = 0; i < surface->window_type_len; ++i) {
+		xcb_atom_t type = surface->window_type[i];
+		if (type == xwayland->atoms[NET_WM_WINDOW_TYPE_DIALOG] ||
+				type == xwayland->atoms[NET_WM_WINDOW_TYPE_UTILITY] ||
+				type == xwayland->atoms[NET_WM_WINDOW_TYPE_TOOLBAR] ||
+				type == xwayland->atoms[NET_WM_WINDOW_TYPE_SPLASH]) {
+			return true;
+		}
+	}
+
+	struct wlr_xwayland_surface_size_hints *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 &&
+			size_hints->max_height == size_hints->min_height) {
+		return true;
+	}
+
 	return false;
 }
 
@@ -411,3 +437,40 @@ void handle_xwayland_surface(struct wl_listener *listener, void *data) {
 	wl_signal_add(&xsurface->events.map, &xwayland_view->map);
 	xwayland_view->map.notify = handle_map;
 }
+
+void handle_xwayland_ready(struct wl_listener *listener, void *data) {
+	struct sway_server *server =
+		wl_container_of(listener, server, xwayland_ready);
+	struct sway_xwayland *xwayland = &server->xwayland;
+
+	xcb_connection_t *xcb_conn = xcb_connect(NULL, NULL);
+	int err = xcb_connection_has_error(xcb_conn);
+	if (err) {
+		wlr_log(L_ERROR, "XCB connect failed: %d", err);
+		return;
+	}
+
+	xcb_intern_atom_cookie_t cookies[ATOM_LAST];
+	for (size_t i = 0; i < ATOM_LAST; i++) {
+		cookies[i] =
+			xcb_intern_atom(xcb_conn, 0, strlen(atom_map[i]), atom_map[i]);
+	}
+	for (size_t i = 0; i < ATOM_LAST; i++) {
+		xcb_generic_error_t *error = NULL;
+		xcb_intern_atom_reply_t *reply =
+			xcb_intern_atom_reply(xcb_conn, cookies[i], &error);
+		if (reply != NULL && error == NULL) {
+			xwayland->atoms[i] = reply->atom;
+		}
+		free(reply);
+
+		if (error != NULL) {
+			wlr_log(L_ERROR, "could not resolve atom %s, X11 error code %d",
+				atom_map[i], error->error_code);
+			free(error);
+			break;
+		}
+	}
+
+	xcb_disconnect(xcb_conn);
+}
diff --git a/sway/input/seat.c b/sway/input/seat.c
index 1ea36466..1c2434b0 100644
--- a/sway/input/seat.c
+++ b/sway/input/seat.c
@@ -99,7 +99,8 @@ static void seat_send_focus(struct sway_container *con,
 	if (con->type == C_VIEW
 			&& seat_is_input_allowed(seat, con->sway_view->surface)) {
 		if (con->sway_view->type == SWAY_VIEW_XWAYLAND) {
-			struct wlr_xwayland *xwayland = seat->input->server->xwayland;
+			struct wlr_xwayland *xwayland =
+				seat->input->server->xwayland.wlr_xwayland;
 			wlr_xwayland_set_seat(xwayland, seat->wlr_seat);
 		}
 		struct wlr_keyboard *keyboard = wlr_seat_get_keyboard(seat->wlr_seat);
diff --git a/sway/meson.build b/sway/meson.build
index 0da67ed7..2cf90b11 100644
--- a/sway/meson.build
+++ b/sway/meson.build
@@ -152,6 +152,7 @@ sway_deps = [
 	server_protos,
 	wayland_server,
 	wlroots,
+	xcb,
 	xkbcommon,
 ]
 
diff --git a/sway/server.c b/sway/server.c
index 824b1d8e..878b530d 100644
--- a/sway/server.c
+++ b/sway/server.c
@@ -18,12 +18,11 @@
 #include <wlr/types/wlr_xdg_output.h>
 #include <wlr/util/log.h>
 // TODO WLR: make Xwayland optional
-#include <wlr/xwayland.h>
 #include "sway/config.h"
 #include "sway/input/input-manager.h"
 #include "sway/server.h"
 #include "sway/tree/layout.h"
-
+#include "sway/xwayland.h"
 
 bool server_init(struct sway_server *server) {
 	wlr_log(L_DEBUG, "Initializing Wayland server");
@@ -72,20 +71,23 @@ bool server_init(struct sway_server *server) {
 	server->xdg_shell_surface.notify = handle_xdg_shell_surface;
 
 	// TODO make xwayland optional
-	server->xwayland =
+	server->xwayland.wlr_xwayland =
 		wlr_xwayland_create(server->wl_display, server->compositor, true);
-	wl_signal_add(&server->xwayland->events.new_surface,
+	wl_signal_add(&server->xwayland.wlr_xwayland->events.new_surface,
 		&server->xwayland_surface);
 	server->xwayland_surface.notify = handle_xwayland_surface;
+	wl_signal_add(&server->xwayland.wlr_xwayland->events.ready,
+		&server->xwayland_ready);
+	server->xwayland_ready.notify = handle_xwayland_ready;
 
 	// TODO: configurable cursor theme and size
-	server->xcursor_manager = wlr_xcursor_manager_create(NULL, 24);
-	wlr_xcursor_manager_load(server->xcursor_manager, 1);
+	server->xwayland.xcursor_manager = wlr_xcursor_manager_create(NULL, 24);
+	wlr_xcursor_manager_load(server->xwayland.xcursor_manager, 1);
 	struct wlr_xcursor *xcursor = wlr_xcursor_manager_get_xcursor(
-		server->xcursor_manager, "left_ptr", 1);
+		server->xwayland.xcursor_manager, "left_ptr", 1);
 	if (xcursor != NULL) {
 		struct wlr_xcursor_image *image = xcursor->images[0];
-		wlr_xwayland_set_cursor(server->xwayland, image->buffer,
+		wlr_xwayland_set_cursor(server->xwayland.wlr_xwayland, image->buffer,
 			image->width * 4, image->width, image->height, image->hotspot_x,
 			image->hotspot_y);
 	}
-- 
cgit v1.2.3


From eeb38d65cbf5c8452c449b9f5e003bd255ca6a53 Mon Sep 17 00:00:00 2001
From: emersion <contact@emersion.fr>
Date: Sun, 24 Jun 2018 19:21:02 +0100
Subject: xwayland: accept configure requests from floating views

---
 sway/desktop/xwayland.c | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/sway/desktop/xwayland.c b/sway/desktop/xwayland.c
index 2c3848cd..eb39dc4b 100644
--- a/sway/desktop/xwayland.c
+++ b/sway/desktop/xwayland.c
@@ -334,8 +334,12 @@ static void handle_request_configure(struct wl_listener *listener, void *data) {
 			ev->width, ev->height);
 		return;
 	}
-	// TODO: Let floating views do whatever
-	configure(view, view->swayc->x, view->swayc->y, view->width, view->height);
+	if (container_is_floating(view->swayc)) {
+		configure(view, view->swayc->x, view->swayc->y, ev->width, ev->height);
+	} else {
+		configure(view, view->swayc->x, view->swayc->y,
+			view->width, view->height);
+	}
 }
 
 static void handle_request_fullscreen(struct wl_listener *listener, void *data) {
-- 
cgit v1.2.3


From e9ad10c2d62146784d7c40015d5ea2a8b5b68865 Mon Sep 17 00:00:00 2001
From: Tony Crisci <tony@dubstepdish.com>
Date: Sun, 24 Jun 2018 20:30:43 -0400
Subject: dont focus-follow-mouse when keyboard grab

---
 sway/input/cursor.c | 9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/sway/input/cursor.c b/sway/input/cursor.c
index 37a87756..944e35aa 100644
--- a/sway/input/cursor.c
+++ b/sway/input/cursor.c
@@ -174,10 +174,13 @@ void cursor_send_pointer_motion(struct sway_cursor *cursor, uint32_t time_msec,
 				seat_set_focus_warp(seat, c, false);
 			}
 		} else if (c->type == C_VIEW) {
-			// Focus c if both of the following are true:
+			// Focus c if the following are true:
 			// - cursor is over a new view, i.e. entered a new window; and
-			// - the new view is visible, i.e. not hidden in a stack or tab.
-			if (c != prev_c && view_is_visible(c->sway_view)) {
+			// - the new view is visible, i.e. not hidden in a stack or tab; and
+			// - the seat does not have a keyboard grab
+			if (!wlr_seat_keyboard_has_grab(cursor->seat->wlr_seat) &&
+					c != prev_c &&
+					view_is_visible(c->sway_view)) {
 				seat_set_focus_warp(seat, c, false);
 			} else {
 				struct sway_container *next_focus =
-- 
cgit v1.2.3


From c9be0145576433e71f8b7732f7ff5ddee0d36076 Mon Sep 17 00:00:00 2001
From: Dominique Martinet <asmadeus@codewreck.org>
Date: Tue, 26 Jun 2018 11:59:06 +0900
Subject: xdg_shell: make view floating if a parent has been set

Prompts e.g. authentication request from firefox-wayland ought to be
floating.

This is a bit coarse but just fixed size is not enough, here is what
firefox does:
[1285461.363]  -> xdg_wm_base@18.get_xdg_surface(new id xdg_surface@68, wl_surface@71)
[1285461.508]  -> xdg_surface@68.get_toplevel(new id xdg_toplevel@67)
[1285461.571]  -> xdg_toplevel@67.set_parent(xdg_toplevel@37)
[1285461.630]  -> xdg_toplevel@67.set_title("Authentication Required")
[1285461.736]  -> xdg_toplevel@67.set_app_id("firefox")
...
[1285476.549] xdg_toplevel@67.configure(0, 0, array)
...
[1285502.080]  -> xdg_toplevel@67.set_min_size(299, 187)
[1285502.140]  -> xdg_toplevel@67.set_max_size(1920, 32767)

This can also be observed with e.g. the open window of gedit
(gedit->open->other documents)
---
 sway/desktop/xdg_shell.c    |  9 +++++----
 sway/desktop/xdg_shell_v6.c | 10 ++++++----
 2 files changed, 11 insertions(+), 8 deletions(-)

diff --git a/sway/desktop/xdg_shell.c b/sway/desktop/xdg_shell.c
index d2b8822c..8457c06b 100644
--- a/sway/desktop/xdg_shell.c
+++ b/sway/desktop/xdg_shell.c
@@ -120,11 +120,12 @@ static void set_fullscreen(struct sway_view *view, bool fullscreen) {
 }
 
 static bool wants_floating(struct sway_view *view) {
-	struct wlr_xdg_toplevel_state *state =
-		&view->wlr_xdg_surface->toplevel->current;
-	return state->min_width != 0 && state->min_height != 0
+	struct wlr_xdg_toplevel *toplevel = view->wlr_xdg_surface->toplevel;
+	struct wlr_xdg_toplevel_state *state = &toplevel->current;
+	return (state->min_width != 0 && state->min_height != 0
 		&& state->min_width == state->max_width
-		&& state->min_height == state->max_height;
+		&& state->min_height == state->max_height)
+		|| toplevel->parent;
 }
 
 static void for_each_surface(struct sway_view *view,
diff --git a/sway/desktop/xdg_shell_v6.c b/sway/desktop/xdg_shell_v6.c
index 6ffe334a..eb1cef26 100644
--- a/sway/desktop/xdg_shell_v6.c
+++ b/sway/desktop/xdg_shell_v6.c
@@ -119,11 +119,13 @@ static void set_fullscreen(struct sway_view *view, bool fullscreen) {
 }
 
 static bool wants_floating(struct sway_view *view) {
-	struct wlr_xdg_toplevel_v6_state *state =
-		&view->wlr_xdg_surface_v6->toplevel->current;
-	return state->min_width != 0 && state->min_height != 0
+	struct wlr_xdg_toplevel_v6 *toplevel =
+		view->wlr_xdg_surface_v6->toplevel;
+	struct wlr_xdg_toplevel_v6_state *state = &toplevel->current;
+	return (state->min_width != 0 && state->min_height != 0
 		&& state->min_width == state->max_width
-		&& state->min_height == state->max_height;
+		&& state->min_height == state->max_height)
+		|| toplevel->parent;
 }
 
 static void for_each_surface(struct sway_view *view,
-- 
cgit v1.2.3


From 08800c8ee22f2aad8c00117756c15169d6e543b1 Mon Sep 17 00:00:00 2001
From: Dominique Martinet <asmadeus@codewreck.org>
Date: Tue, 26 Jun 2018 21:16:42 +0900
Subject: layer_shell: cleanup output link on output destroy

Fixes this kind of use-after-free:
==1795==ERROR: AddressSanitizer: heap-use-after-free on address 0x612000191ef0 at pc 0x00000048c388 bp 0x7ffe308f0410 sp 0x7ffe308f0400
WRITE of size 8 at 0x612000191ef0 thread T0
    #0 0x48c387 in wl_list_remove ../common/list.c:157
    #1 0x42196b in handle_destroy ../sway/desktop/layer_shell.c:275
    #2 0x7f55cc2549fa in wlr_signal_emit_safe ../util/signal.c:29
    #3 0x7f55cc22cf68 in layer_surface_destroy ../types/wlr_layer_shell.c:182
    #4 0x7f55cc22d084 in layer_surface_resource_destroy ../types/wlr_layer_shell.c:196
    #5 0x7f55cc4ca025 in destroy_resource src/wayland-server.c:688
    #6 0x7f55cc4ca091 in wl_resource_destroy src/wayland-server.c:705
    #7 0x7f55cc22c3a2 in resource_handle_destroy ../types/wlr_layer_shell.c:18
    #8 0x7f55c8ef103d in ffi_call_unix64 (/lib64/libffi.so.6+0x603d)
    #9 0x7f55c8ef09fe in ffi_call (/lib64/libffi.so.6+0x59fe)
    #10 0x7f55cc4cdf2c  (/lib64/libwayland-server.so.0+0xbf2c)
    #11 0x7f55cc4ca3de in wl_client_connection_data src/wayland-server.c:420
    #12 0x7f55cc4cbf01 in wl_event_loop_dispatch src/event-loop.c:641
    #13 0x7f55cc4ca601 in wl_display_run src/wayland-server.c:1260
    #14 0x40bb1e in server_run ../sway/server.c:141
    #15 0x40ab2f in main ../sway/main.c:432
    #16 0x7f55cb97318a in __libc_start_main ../csu/libc-start.c:308
    #17 0x408d29 in _start (/opt/wayland/bin/sway+0x408d29)

0x612000191ef0 is located 48 bytes inside of 312-byte region [0x612000191ec0,0x612000191ff8)
freed by thread T0 here:
    #0 0x7f55ce3bb880 in __interceptor_free (/lib64/libasan.so.5+0xee880)
    #1 0x42f1db in handle_destroy ../sway/desktop/output.c:1275
    #2 0x7f55cc2549fa in wlr_signal_emit_safe ../util/signal.c:29
    #3 0x7f55cc23b4c2 in wlr_output_destroy ../types/wlr_output.c:284
    #4 0x7f55cc1ddc20 in xdg_toplevel_handle_close ../backend/wayland/output.c:235
    #5 0x7f55c8ef103d in ffi_call_unix64 (/lib64/libffi.so.6+0x603d)

previously allocated by thread T0 here:
    #0 0x7f55ce3bbe50 in calloc (/lib64/libasan.so.5+0xeee50)
    #1 0x42f401 in handle_new_output ../sway/desktop/output.c:1308
    #2 0x7f55cc2549fa in wlr_signal_emit_safe ../util/signal.c:29
    #3 0x7f55cc1d6cbf in new_output_reemit ../backend/multi/backend.c:113
    #4 0x7f55cc2549fa in wlr_signal_emit_safe ../util/signal.c:29
    #5 0x7f55cc1deac7 in wlr_wl_output_create ../backend/wayland/output.c:327
    #6 0x7f55cc1db353 in backend_start ../backend/wayland/backend.c:55
    #7 0x7f55cc1bad55 in wlr_backend_start ../backend/backend.c:35
    #8 0x7f55cc1d67a0 in multi_backend_start ../backend/multi/backend.c:24
    #9 0x7f55cc1bad55 in wlr_backend_start ../backend/backend.c:35
    #10 0x40ba8a in server_run ../sway/server.c:136
    #11 0x40ab2f in main ../sway/main.c:432
    #12 0x7f55cb97318a in __libc_start_main ../csu/libc-start.c:308
---
 sway/desktop/layer_shell.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/sway/desktop/layer_shell.c b/sway/desktop/layer_shell.c
index 3accdefb..94dc22e7 100644
--- a/sway/desktop/layer_shell.c
+++ b/sway/desktop/layer_shell.c
@@ -219,6 +219,8 @@ static void handle_output_destroy(struct wl_listener *listener, void *data) {
 	struct sway_layer_surface *sway_layer =
 		wl_container_of(listener, sway_layer, output_destroy);
 	wl_list_remove(&sway_layer->output_destroy.link);
+	wl_list_remove(&sway_layer->link);
+	wl_list_init(&sway_layer->link);
 	sway_layer->layer_surface->output = NULL;
 	wlr_layer_surface_close(sway_layer->layer_surface);
 }
-- 
cgit v1.2.3


From 6856866a612c9f0708a42cbe6d9627173d9e3569 Mon Sep 17 00:00:00 2001
From: Dominique Martinet <asmadeus@codewreck.org>
Date: Tue, 26 Jun 2018 21:19:38 +0900
Subject: layer_shell: order destroying before sway_output

Both sway_output and sway_layer_shell listen to wlr's output destroy event,
but sway_layer_shell needs to access into sway_output's data strucure and needs
to be destroyed first.

Resolve this by making sway_layer_shell listen to a new event that happens at
start of sway_output's destroy handler
---
 include/sway/output.h      | 4 ++++
 sway/desktop/layer_shell.c | 7 +++----
 sway/desktop/output.c      | 3 +++
 3 files changed, 10 insertions(+), 4 deletions(-)

diff --git a/include/sway/output.h b/include/sway/output.h
index 70f746dc..8180ce3d 100644
--- a/include/sway/output.h
+++ b/include/sway/output.h
@@ -32,6 +32,10 @@ struct sway_output {
 	struct wl_list link;
 
 	pid_t bg_pid;
+
+	struct {
+		struct wl_signal destroy;
+	} events;
 };
 
 void output_damage_whole(struct sway_output *output);
diff --git a/sway/desktop/layer_shell.c b/sway/desktop/layer_shell.c
index 94dc22e7..b57d1ee6 100644
--- a/sway/desktop/layer_shell.c
+++ b/sway/desktop/layer_shell.c
@@ -352,10 +352,6 @@ void handle_layer_shell_surface(struct wl_listener *listener, void *data) {
 	wl_signal_add(&layer_surface->surface->events.commit,
 		&sway_layer->surface_commit);
 
-	sway_layer->output_destroy.notify = handle_output_destroy;
-	wl_signal_add(&layer_surface->output->events.destroy,
-		&sway_layer->output_destroy);
-
 	sway_layer->destroy.notify = handle_destroy;
 	wl_signal_add(&layer_surface->events.destroy, &sway_layer->destroy);
 	sway_layer->map.notify = handle_map;
@@ -368,6 +364,9 @@ void handle_layer_shell_surface(struct wl_listener *listener, void *data) {
 	layer_surface->data = sway_layer;
 
 	struct sway_output *output = layer_surface->output->data;
+	sway_layer->output_destroy.notify = handle_output_destroy;
+	wl_signal_add(&output->events.destroy, &sway_layer->output_destroy);
+
 	wl_list_insert(&output->layers[layer_surface->layer], &sway_layer->link);
 
 	// Temporarily set the layer's current state to client_pending
diff --git a/sway/desktop/output.c b/sway/desktop/output.c
index d4115be8..f0f1603a 100644
--- a/sway/desktop/output.c
+++ b/sway/desktop/output.c
@@ -1199,6 +1199,8 @@ static void damage_handle_destroy(struct wl_listener *listener, void *data) {
 
 static void handle_destroy(struct wl_listener *listener, void *data) {
 	struct sway_output *output = wl_container_of(listener, output, destroy);
+	wl_signal_emit(&output->events.destroy, output);
+
 	if (output->swayc) {
 		container_destroy(output->swayc);
 	}
@@ -1277,6 +1279,7 @@ void output_enable(struct sway_output *output) {
 	for (size_t i = 0; i < len; ++i) {
 		wl_list_init(&output->layers[i]);
 	}
+	wl_signal_init(&output->events.destroy);
 
 	input_manager_configure_xcursor(input_manager);
 
-- 
cgit v1.2.3


From 4550cb2b3e7e6b4242cf2a3e126b6f47bc8f2182 Mon Sep 17 00:00:00 2001
From: ael-code <tommy.ael@gmail.com>
Date: Tue, 26 Jun 2018 12:53:47 +0200
Subject: fix memleak on background cmd error

- src must be free after join_args()
- wordfree must bee used after wordexp
---
 sway/commands/output/background.c | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/sway/commands/output/background.c b/sway/commands/output/background.c
index 82bccf68..4f422cec 100644
--- a/sway/commands/output/background.c
+++ b/sway/commands/output/background.c
@@ -62,8 +62,11 @@ struct cmd_results *output_cmd_background(int argc, char **argv) {
 		wordexp_t p;
 		char *src = join_args(argv, j);
 		if (wordexp(src, &p, 0) != 0 || p.we_wordv[0] == NULL) {
-			return cmd_results_new(CMD_INVALID, "output",
-				"Invalid syntax (%s).", src);
+			struct cmd_results *cmd_res = cmd_results_new(CMD_INVALID, "output",
+				"Invalid syntax (%s)", src);
+			free(src);
+			wordfree(&p);
+			return cmd_res;
 		}
 		free(src);
 		src = p.we_wordv[0];
-- 
cgit v1.2.3


From a4578815f1fa30a7ebb15ddb6601f1ab2f3a3fb6 Mon Sep 17 00:00:00 2001
From: ael-code <tommy.ael@gmail.com>
Date: Tue, 26 Jun 2018 12:57:22 +0200
Subject: cleanup output-background subcommand handling

- fixes a double-free error when access() failed.

- refactor code to make memory managment (alloc/free) more straightforward
   - do not bring the temporary wordexp_t struct around
   - do not postpone errors handling
---
 sway/commands/output/background.c | 49 ++++++++++++++++++++++-----------------
 1 file changed, 28 insertions(+), 21 deletions(-)

diff --git a/sway/commands/output/background.c b/sway/commands/output/background.c
index 4f422cec..55cbdff0 100644
--- a/sway/commands/output/background.c
+++ b/sway/commands/output/background.c
@@ -69,42 +69,49 @@ struct cmd_results *output_cmd_background(int argc, char **argv) {
 			return cmd_res;
 		}
 		free(src);
-		src = p.we_wordv[0];
+		src = strdup(p.we_wordv[0]);
+		wordfree(&p);
+		if (!src) {
+			wlr_log(L_ERROR, "Failed to duplicate string");
+			return cmd_results_new(CMD_FAILURE, "output",
+				"Unable to allocate resource");
+		}
+
 		if (config->reading && *src != '/') {
+			// src file is inside configuration dir
+
 			char *conf = strdup(config->current_config);
-			if (conf) {
-				char *conf_path = dirname(conf);
-				src = malloc(strlen(conf_path) + strlen(src) + 2);
-				if (!src) {
-					free(conf);
-					wordfree(&p);
-					wlr_log(L_ERROR,
-						"Unable to allocate resource: Not enough memory");
-					return cmd_results_new(CMD_FAILURE, "output",
+			if(!conf) {
+				wlr_log(L_ERROR, "Failed to duplicate string");
+				return cmd_results_new(CMD_FAILURE, "output",
 						"Unable to allocate resources");
-				}
-				sprintf(src, "%s/%s", conf_path, p.we_wordv[0]);
+			}
+
+			char *conf_path = dirname(conf);
+			char *rel_path = src;
+			src = malloc(strlen(conf_path) + strlen(src) + 2);
+			if (!src) {
+				free(rel_path);
 				free(conf);
-			} else {
-				wlr_log(L_ERROR, "Unable to allocate background source");
+				wlr_log(L_ERROR, "Unable to allocate memory");
+				return cmd_results_new(CMD_FAILURE, "output",
+						"Unable to allocate resources");
 			}
+
+			sprintf(src, "%s/%s", conf_path, rel_path);
+			free(rel_path);
+			free(conf);
 		}
 
 		if (access(src, F_OK) == -1) {
 			struct cmd_results *cmd_res = cmd_results_new(CMD_FAILURE, "output",
 				"Unable to access background file '%s': %s", src, strerror(errno));
 			free(src);
-			wordfree(&p);
 			return cmd_res;
 		}
 
-		output->background = strdup(src);
+		output->background = src;
 		output->background_option = strdup(mode);
-		if (src != p.we_wordv[0]) {
-			free(src);
-		}
-		wordfree(&p);
-
 		argc -= j + 1; argv += j + 1;
 	}
 
-- 
cgit v1.2.3


From 9a3c6d2dbe0a002b3c9dc5921f20d83fec8ceed6 Mon Sep 17 00:00:00 2001
From: Thomas Plaçais <thomas.placais@outlook.com>
Date: Wed, 27 Jun 2018 15:40:44 +0200
Subject: Check if command input has at least 2 arguments

---
 sway/commands/input.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/sway/commands/input.c b/sway/commands/input.c
index 22a0bb7c..678c57c4 100644
--- a/sway/commands/input.c
+++ b/sway/commands/input.c
@@ -31,7 +31,7 @@ static struct cmd_handler input_handlers[] = {
 
 struct cmd_results *cmd_input(int argc, char **argv) {
 	struct cmd_results *error = NULL;
-	if ((error = checkarg(argc, "input", EXPECTED_AT_LEAST, 1))) {
+	if ((error = checkarg(argc, "input", EXPECTED_AT_LEAST, 2))) {
 		return error;
 	}
 
-- 
cgit v1.2.3


From c4b900c1e04ec45b481a3f05870d8b4a6c49e386 Mon Sep 17 00:00:00 2001
From: Armin Preiml <apreiml@strohwolke.at>
Date: Wed, 27 Jun 2018 17:48:36 +0200
Subject: fix accidently removing borders on XCB_CONFIGURE_REQUEST

The view was configured with the container coordinates.
Although they were right on the first configure, they
changed after a XCB_CONFIGURE_REQUEST, when the
border was already drawn.
---
 sway/desktop/xwayland.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/sway/desktop/xwayland.c b/sway/desktop/xwayland.c
index eb39dc4b..df5f6698 100644
--- a/sway/desktop/xwayland.c
+++ b/sway/desktop/xwayland.c
@@ -335,9 +335,9 @@ static void handle_request_configure(struct wl_listener *listener, void *data) {
 		return;
 	}
 	if (container_is_floating(view->swayc)) {
-		configure(view, view->swayc->x, view->swayc->y, ev->width, ev->height);
+		configure(view, view->x, view->y, ev->width, ev->height);
 	} else {
-		configure(view, view->swayc->x, view->swayc->y,
+		configure(view, view->x, view->y,
 			view->width, view->height);
 	}
 }
-- 
cgit v1.2.3


From 1eede432fc18ee7da7373d869699ca5d2c5f0eaa Mon Sep 17 00:00:00 2001
From: Armin Preiml <apreiml@strohwolke.at>
Date: Thu, 28 Jun 2018 15:22:04 +0200
Subject: fix handling key modifiers if not pressed at first

fixes #2169
---
 sway/input/keyboard.c | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/sway/input/keyboard.c b/sway/input/keyboard.c
index 9e093828..ec149d06 100644
--- a/sway/input/keyboard.c
+++ b/sway/input/keyboard.c
@@ -64,12 +64,12 @@ static void update_shortcut_state(struct sway_shortcut_state *state,
 	bool last_key_was_a_modifier = raw_modifiers != state->last_raw_modifiers;
 	state->last_raw_modifiers = raw_modifiers;
 
-	if (event->state == WLR_KEY_PRESSED) {
-		if (last_key_was_a_modifier && state->last_keycode) {
-			// Last pressed key before this one was a modifier
-			state_erase_key(state, state->last_keycode);
-		}
+    if (last_key_was_a_modifier && state->last_keycode) {
+        // Last pressed key before this one was a modifier
+        state_erase_key(state, state->last_keycode);
+    }
 
+	if (event->state == WLR_KEY_PRESSED) {
 		// Add current key to set; there may be duplicates
 		state_add_key(state, event->keycode, new_key);
 		state->last_keycode = event->keycode;
-- 
cgit v1.2.3