aboutsummaryrefslogtreecommitdiffstats
path: root/sway
diff options
context:
space:
mode:
authorLibravatar Ryan Dwyer <ryandwyer1@gmail.com>2018-07-18 16:13:28 +1000
committerLibravatar Ryan Dwyer <ryandwyer1@gmail.com>2018-07-22 23:10:19 +1000
commit9fbe13b9be18c732b58033a57a22a299af91a170 (patch)
treea24901c1bb4eff87877c0d9fb96767b662a9d533 /sway
parentMerge pull request #2320 from RedSoxFan/reset-outputs-on-reload (diff)
downloadsway-9fbe13b9be18c732b58033a57a22a299af91a170.tar.gz
sway-9fbe13b9be18c732b58033a57a22a299af91a170.tar.zst
sway-9fbe13b9be18c732b58033a57a22a299af91a170.zip
Implement floating_modifier and mouse operations for floating views
This implements the following: * `floating_modifier` configuration directive * Drag a floating window by its title bar * Hold mod + drag a floating window from anywhere * Resize a floating view by dragging the border * Resize a floating view by holding mod and right clicking anywhere on the view * Resize a floating view and keep aspect ratio by holding shift while resizing using either method * Mouse cursor turns into resize when hovering floating border or corner
Diffstat (limited to 'sway')
-rw-r--r--sway/commands.c1
-rw-r--r--sway/commands/floating_modifier.c30
-rw-r--r--sway/input/cursor.c322
-rw-r--r--sway/meson.build1
-rw-r--r--sway/tree/container.c16
-rw-r--r--sway/tree/layout.c1
-rw-r--r--sway/tree/view.c2
7 files changed, 361 insertions, 12 deletions
diff --git a/sway/commands.c b/sway/commands.c
index f1f03574..f40f0e9d 100644
--- a/sway/commands.c
+++ b/sway/commands.c
@@ -103,6 +103,7 @@ static struct cmd_handler handlers[] = {
103 { "exec_always", cmd_exec_always }, 103 { "exec_always", cmd_exec_always },
104 { "floating_maximum_size", cmd_floating_maximum_size }, 104 { "floating_maximum_size", cmd_floating_maximum_size },
105 { "floating_minimum_size", cmd_floating_minimum_size }, 105 { "floating_minimum_size", cmd_floating_minimum_size },
106 { "floating_modifier", cmd_floating_modifier },
106 { "focus", cmd_focus }, 107 { "focus", cmd_focus },
107 { "focus_follows_mouse", cmd_focus_follows_mouse }, 108 { "focus_follows_mouse", cmd_focus_follows_mouse },
108 { "focus_wrapping", cmd_focus_wrapping }, 109 { "focus_wrapping", cmd_focus_wrapping },
diff --git a/sway/commands/floating_modifier.c b/sway/commands/floating_modifier.c
new file mode 100644
index 00000000..1ced50af
--- /dev/null
+++ b/sway/commands/floating_modifier.c
@@ -0,0 +1,30 @@
1#ifdef __linux__
2#include <linux/input-event-codes.h>
3#elif __FreeBSD__
4#include <dev/evdev/input-event-codes.h>
5#endif
6#include <xkbcommon/xkbcommon.h>
7#include <xkbcommon/xkbcommon-names.h>
8#include <strings.h>
9#include "sway/commands.h"
10#include "sway/config.h"
11#include "list.h"
12#include "log.h"
13#include "util.h"
14
15struct cmd_results *cmd_floating_modifier(int argc, char **argv) {
16 struct cmd_results *error = NULL;
17 if ((error = checkarg(argc, "floating_modifier", EXPECTED_EQUAL_TO, 1))) {
18 return error;
19 }
20
21 uint32_t mod = get_modifier_mask_by_name(argv[0]);
22 if (!mod) {
23 return cmd_results_new(CMD_INVALID, "floating_modifier",
24 "Invalid modifier");
25 }
26
27 config->floating_mod = mod;
28
29 return cmd_results_new(CMD_SUCCESS, NULL, NULL);
30}
diff --git a/sway/input/cursor.c b/sway/input/cursor.c
index c76c20b3..6ad214b5 100644
--- a/sway/input/cursor.c
+++ b/sway/input/cursor.c
@@ -5,15 +5,19 @@
5#elif __FreeBSD__ 5#elif __FreeBSD__
6#include <dev/evdev/input-event-codes.h> 6#include <dev/evdev/input-event-codes.h>
7#endif 7#endif
8#include <limits.h>
8#include <wlr/types/wlr_cursor.h> 9#include <wlr/types/wlr_cursor.h>
9#include <wlr/types/wlr_xcursor_manager.h> 10#include <wlr/types/wlr_xcursor_manager.h>
10#include <wlr/types/wlr_idle.h> 11#include <wlr/types/wlr_idle.h>
11#include "list.h" 12#include "list.h"
12#include "log.h" 13#include "log.h"
14#include "sway/desktop.h"
13#include "sway/desktop/transaction.h" 15#include "sway/desktop/transaction.h"
14#include "sway/input/cursor.h" 16#include "sway/input/cursor.h"
17#include "sway/input/keyboard.h"
15#include "sway/layers.h" 18#include "sway/layers.h"
16#include "sway/output.h" 19#include "sway/output.h"
20#include "sway/tree/arrange.h"
17#include "sway/tree/view.h" 21#include "sway/tree/view.h"
18#include "sway/tree/workspace.h" 22#include "sway/tree/workspace.h"
19#include "wlr-layer-shell-unstable-v1-protocol.h" 23#include "wlr-layer-shell-unstable-v1-protocol.h"
@@ -127,7 +131,7 @@ static struct sway_container *container_at_coords(
127 return ws; 131 return ws;
128 } 132 }
129 133
130 c = seat_get_focus_inactive(seat, output->swayc); 134 c = seat_get_active_child(seat, output->swayc);
131 if (c) { 135 if (c) {
132 return c; 136 return c;
133 } 137 }
@@ -139,6 +143,173 @@ static struct sway_container *container_at_coords(
139 return output->swayc; 143 return output->swayc;
140} 144}
141 145
146static enum resize_edge find_resize_edge(struct sway_container *cont,
147 struct sway_cursor *cursor) {
148 if (cont->type != C_VIEW) {
149 return RESIZE_EDGE_NONE;
150 }
151 struct sway_view *view = cont->sway_view;
152 if (view->border == B_NONE || !view->border_thickness || view->using_csd) {
153 return RESIZE_EDGE_NONE;
154 }
155
156 enum resize_edge edge = 0;
157 if (cursor->cursor->x < cont->x + view->border_thickness) {
158 edge |= RESIZE_EDGE_LEFT;
159 }
160 if (cursor->cursor->y < cont->y + view->border_thickness) {
161 edge |= RESIZE_EDGE_TOP;
162 }
163 if (cursor->cursor->x >= cont->x + cont->width - view->border_thickness) {
164 edge |= RESIZE_EDGE_RIGHT;
165 }
166 if (cursor->cursor->y >= cont->y + cont->height - view->border_thickness) {
167 edge |= RESIZE_EDGE_BOTTOM;
168 }
169 return edge;
170}
171
172static void handle_drag_motion(struct sway_seat *seat,
173 struct sway_cursor *cursor) {
174 struct sway_container *con = seat->op_container;
175 desktop_damage_whole_container(con);
176 container_floating_translate(con,
177 cursor->cursor->x - cursor->previous.x,
178 cursor->cursor->y - cursor->previous.y);
179 desktop_damage_whole_container(con);
180}
181
182static void calculate_floating_constraints(struct sway_container *con,
183 int *min_width, int *max_width, int *min_height, int *max_height) {
184 if (config->floating_minimum_width == -1) { // no minimum
185 *min_width = 0;
186 } else if (config->floating_minimum_width == 0) { // automatic
187 *min_width = 75;
188 } else {
189 *min_width = config->floating_minimum_width;
190 }
191
192 if (config->floating_minimum_height == -1) { // no minimum
193 *min_height = 0;
194 } else if (config->floating_minimum_height == 0) { // automatic
195 *min_height = 50;
196 } else {
197 *min_height = config->floating_minimum_height;
198 }
199
200 if (config->floating_maximum_width == -1) { // no maximum
201 *max_width = INT_MAX;
202 } else if (config->floating_maximum_width == 0) { // automatic
203 struct sway_container *ws = container_parent(con, C_WORKSPACE);
204 *max_width = ws->width;
205 } else {
206 *max_width = config->floating_maximum_width;
207 }
208
209 if (config->floating_maximum_height == -1) { // no maximum
210 *max_height = INT_MAX;
211 } else if (config->floating_maximum_height == 0) { // automatic
212 struct sway_container *ws = container_parent(con, C_WORKSPACE);
213 *max_height = ws->height;
214 } else {
215 *max_height = config->floating_maximum_height;
216 }
217}
218static void handle_resize_motion(struct sway_seat *seat,
219 struct sway_cursor *cursor) {
220 struct sway_container *con = seat->op_container;
221 double center_lx = con->x + con->width / 2;
222 double center_ly = con->y + con->height / 2;
223 enum resize_edge edge = seat->op_resize_edge;
224
225 // The amount the mouse has moved since the start of the resize operation
226 // Positive is down/right
227 double mouse_move_x = cursor->cursor->x - seat->op_ref_lx;
228 double mouse_move_y = cursor->cursor->y - seat->op_ref_ly;
229
230 if (edge == RESIZE_EDGE_TOP || edge == RESIZE_EDGE_BOTTOM) {
231 mouse_move_x = 0;
232 }
233 if (edge == RESIZE_EDGE_LEFT || edge == RESIZE_EDGE_RIGHT) {
234 mouse_move_y = 0;
235 }
236
237 double grow_width = seat->op_ref_lx > center_lx ?
238 mouse_move_x : -mouse_move_x;
239 double grow_height = seat->op_ref_ly > center_ly ?
240 mouse_move_y : -mouse_move_y;
241
242 if (seat->op_resize_preserve_ratio) {
243 double x_multiplier = grow_width / seat->op_ref_width;
244 double y_multiplier = grow_height / seat->op_ref_height;
245 double avg_multiplier = (x_multiplier + y_multiplier) / 2;
246 grow_width = seat->op_ref_width * avg_multiplier;
247 grow_height = seat->op_ref_height * avg_multiplier;
248 }
249
250 // If we're resizing from the center (mod + right click), we need to double
251 // the amount we're growing because we're doing it in both directions.
252 if (edge == RESIZE_EDGE_NONE) {
253 grow_width *= 2;
254 grow_height *= 2;
255 }
256
257 // Determine new width/height, and accommodate for min/max values
258 double width = seat->op_ref_width + grow_width;
259 double height = seat->op_ref_height + grow_height;
260 int min_width, max_width, min_height, max_height;
261 calculate_floating_constraints(con, &min_width, &max_width,
262 &min_height, &max_height);
263 width = fmax(min_width, fmin(width, max_width));
264 height = fmax(min_height, fmin(height, max_height));
265
266 // Recalculate these, in case we hit a min/max limit
267 grow_width = width - seat->op_ref_width;
268 grow_height = height - seat->op_ref_height;
269
270 // Determine grow x/y values - these are relative to the container's x/y at
271 // the start of the resize operation.
272 double grow_x = 0, grow_y = 0;
273 if (edge & RESIZE_EDGE_LEFT) {
274 grow_x = -grow_width;
275 } else if (edge & RESIZE_EDGE_RIGHT) {
276 grow_x = 0;
277 } else {
278 grow_x = -grow_width / 2;
279 }
280 if (edge & RESIZE_EDGE_TOP) {
281 grow_y = -grow_height;
282 } else if (edge & RESIZE_EDGE_BOTTOM) {
283 grow_y = 0;
284 } else {
285 grow_y = -grow_height / 2;
286 }
287
288 // Determine the amounts we need to bump everything relative to the current
289 // size.
290 int relative_grow_width = width - con->width;
291 int relative_grow_height = height - con->height;
292 int relative_grow_x = (seat->op_ref_con_lx + grow_x) - con->x;
293 int relative_grow_y = (seat->op_ref_con_ly + grow_y) - con->y;
294
295 // Actually resize stuff
296 con->x += relative_grow_x;
297 con->y += relative_grow_y;
298 con->width += relative_grow_width;
299 con->height += relative_grow_height;
300
301 if (con->type == C_VIEW) {
302 struct sway_view *view = con->sway_view;
303 view->x += relative_grow_x;
304 view->y += relative_grow_y;
305 view->width += relative_grow_width;
306 view->height += relative_grow_height;
307 }
308
309 arrange_windows(con);
310 transaction_commit_dirty();
311}
312
142void cursor_send_pointer_motion(struct sway_cursor *cursor, uint32_t time_msec, 313void cursor_send_pointer_motion(struct sway_cursor *cursor, uint32_t time_msec,
143 bool allow_refocusing) { 314 bool allow_refocusing) {
144 if (time_msec == 0) { 315 if (time_msec == 0) {
@@ -146,6 +317,18 @@ void cursor_send_pointer_motion(struct sway_cursor *cursor, uint32_t time_msec,
146 } 317 }
147 318
148 struct sway_seat *seat = cursor->seat; 319 struct sway_seat *seat = cursor->seat;
320
321 if (seat->operation != OP_NONE) {
322 if (seat->operation == OP_DRAG) {
323 handle_drag_motion(seat, cursor);
324 } else {
325 handle_resize_motion(seat, cursor);
326 }
327 cursor->previous.x = cursor->cursor->x;
328 cursor->previous.y = cursor->cursor->y;
329 return;
330 }
331
149 struct wlr_seat *wlr_seat = seat->wlr_seat; 332 struct wlr_seat *wlr_seat = seat->wlr_seat;
150 struct wlr_surface *surface = NULL; 333 struct wlr_surface *surface = NULL;
151 double sx, sy; 334 double sx, sy;
@@ -194,15 +377,54 @@ void cursor_send_pointer_motion(struct sway_cursor *cursor, uint32_t time_msec,
194 } 377 }
195 } 378 }
196 379
197 // reset cursor if switching between clients 380 // Handle cursor image
198 struct wl_client *client = NULL; 381 if (surface) {
199 if (surface != NULL) { 382 // Reset cursor if switching between clients
200 client = wl_resource_get_client(surface->resource); 383 struct wl_client *client = wl_resource_get_client(surface->resource);
201 } 384 if (client != cursor->image_client) {
202 if (client != cursor->image_client) { 385 wlr_xcursor_manager_set_cursor_image(cursor->xcursor_manager,
386 "left_ptr", cursor->cursor);
387 cursor->image_client = client;
388 }
389 } else if (c && container_is_floating(c)) {
390 // Try a floating container's resize edge
391 enum resize_edge edge = find_resize_edge(c, cursor);
392 if (edge == RESIZE_EDGE_NONE) {
393 wlr_xcursor_manager_set_cursor_image(cursor->xcursor_manager,
394 "left_ptr", cursor->cursor);
395 } else if (edge == RESIZE_EDGE_TOP) {
396 wlr_xcursor_manager_set_cursor_image(cursor->xcursor_manager,
397 "top_side", cursor->cursor);
398 } else if (edge == RESIZE_EDGE_RIGHT) {
399 wlr_xcursor_manager_set_cursor_image(cursor->xcursor_manager,
400 "right_side", cursor->cursor);
401 } else if (edge == RESIZE_EDGE_BOTTOM) {
402 wlr_xcursor_manager_set_cursor_image(cursor->xcursor_manager,
403 "bottom_side", cursor->cursor);
404 } else if (edge == RESIZE_EDGE_LEFT) {
405 wlr_xcursor_manager_set_cursor_image(cursor->xcursor_manager,
406 "left_side", cursor->cursor);
407 } else if (edge == (RESIZE_EDGE_TOP | RESIZE_EDGE_LEFT)) {
408 wlr_xcursor_manager_set_cursor_image(cursor->xcursor_manager,
409 "top_left_corner", cursor->cursor);
410 } else if (edge == (RESIZE_EDGE_TOP | RESIZE_EDGE_RIGHT)) {
411 wlr_xcursor_manager_set_cursor_image(cursor->xcursor_manager,
412 "top_right_corner", cursor->cursor);
413 } else if (edge == (RESIZE_EDGE_BOTTOM | RESIZE_EDGE_LEFT)) {
414 wlr_xcursor_manager_set_cursor_image(cursor->xcursor_manager,
415 "bottom_left_corner", cursor->cursor);
416 } else if (edge == (RESIZE_EDGE_BOTTOM | RESIZE_EDGE_RIGHT)) {
417 wlr_xcursor_manager_set_cursor_image(cursor->xcursor_manager,
418 "bottom_right_corner", cursor->cursor);
419 } else {
420 wlr_xcursor_manager_set_cursor_image(cursor->xcursor_manager,
421 "left_ptr", cursor->cursor);
422 }
423 cursor->image_client = NULL;
424 } else {
203 wlr_xcursor_manager_set_cursor_image(cursor->xcursor_manager, 425 wlr_xcursor_manager_set_cursor_image(cursor->xcursor_manager,
204 "left_ptr", cursor->cursor); 426 "left_ptr", cursor->cursor);
205 cursor->image_client = client; 427 cursor->image_client = NULL;
206 } 428 }
207 429
208 // send pointer enter/leave 430 // send pointer enter/leave
@@ -243,8 +465,79 @@ static void handle_cursor_motion_absolute(
243 transaction_commit_dirty(); 465 transaction_commit_dirty();
244} 466}
245 467
468static void handle_end_operation(struct sway_seat *seat) {
469 if (seat->operation == OP_DRAG) {
470 // We "move" the container to its own location so it discovers its
471 // output again.
472 struct sway_container *con = seat->op_container;
473 container_floating_move_to(con, con->x, con->y);
474 seat->operation = OP_NONE;
475 seat->op_container = NULL;
476 } else {
477 // OP_RESIZE
478 seat->operation = OP_NONE;
479 seat->op_container = NULL;
480 }
481}
482
483static void dispatch_cursor_button_floating(struct sway_cursor *cursor,
484 uint32_t time_msec, uint32_t button, enum wlr_button_state state,
485 struct wlr_surface *surface, double sx, double sy,
486 struct sway_container *cont) {
487 struct sway_seat *seat = cursor->seat;
488
489 // Deny dragging or resizing a fullscreen view
490 if (cont->type == C_VIEW && cont->sway_view->is_fullscreen) {
491 wlr_seat_pointer_notify_button(seat->wlr_seat, time_msec, button, state);
492 return;
493 }
494
495 struct wlr_keyboard *keyboard = wlr_seat_get_keyboard(seat->wlr_seat);
496 bool mod_pressed = keyboard &&
497 (keyboard->modifiers.depressed & config->floating_mod);
498 enum resize_edge edge = find_resize_edge(cont, cursor);
499 bool over_title = edge == RESIZE_EDGE_NONE && !surface;
500
501 // Check for beginning drag
502 if (button == BTN_LEFT && state == WLR_BUTTON_PRESSED &&
503 (mod_pressed || over_title)) {
504 seat->operation = OP_DRAG;
505 seat->op_container = cont;
506 seat->op_button = button;
507 return;
508 }
509
510 // Check for beginning resize
511 bool resizing_via_border = button == BTN_LEFT && edge;
512 bool resizing_via_mod = button == BTN_RIGHT && mod_pressed;
513 if ((resizing_via_border || resizing_via_mod) &&
514 state == WLR_BUTTON_PRESSED) {
515 seat->operation = OP_RESIZE;
516 seat->op_container = cont;
517 seat->op_resize_preserve_ratio = keyboard &&
518 (keyboard->modifiers.depressed & 1); // Shift
519 seat->op_resize_edge = edge;
520 seat->op_button = button;
521 seat->op_ref_lx = cursor->cursor->x;
522 seat->op_ref_ly = cursor->cursor->y;
523 seat->op_ref_con_lx = cont->x;
524 seat->op_ref_con_ly = cont->y;
525 seat->op_ref_width = cont->width;
526 seat->op_ref_height = cont->height;
527 return;
528 }
529
530 // Send event to surface
531 wlr_seat_pointer_notify_button(seat->wlr_seat, time_msec, button, state);
532}
533
246void dispatch_cursor_button(struct sway_cursor *cursor, 534void dispatch_cursor_button(struct sway_cursor *cursor,
247 uint32_t time_msec, uint32_t button, enum wlr_button_state state) { 535 uint32_t time_msec, uint32_t button, enum wlr_button_state state) {
536 if (cursor->seat->operation != OP_NONE &&
537 button == cursor->seat->op_button && state == WLR_BUTTON_RELEASED) {
538 handle_end_operation(cursor->seat);
539 return;
540 }
248 if (time_msec == 0) { 541 if (time_msec == 0) {
249 time_msec = get_current_time_msec(); 542 time_msec = get_current_time_msec();
250 } 543 }
@@ -259,6 +552,11 @@ void dispatch_cursor_button(struct sway_cursor *cursor,
259 if (layer->current.keyboard_interactive) { 552 if (layer->current.keyboard_interactive) {
260 seat_set_focus_layer(cursor->seat, layer); 553 seat_set_focus_layer(cursor->seat, layer);
261 } 554 }
555 wlr_seat_pointer_notify_button(cursor->seat->wlr_seat,
556 time_msec, button, state);
557 } else if (cont && container_is_floating(cont)) {
558 dispatch_cursor_button_floating(cursor, time_msec, button, state,
559 surface, sx, sy, cont);
262 } else if (surface && cont && cont->type != C_VIEW) { 560 } else if (surface && cont && cont->type != C_VIEW) {
263 // Avoid moving keyboard focus from a surface that accepts it to one 561 // Avoid moving keyboard focus from a surface that accepts it to one
264 // that does not unless the change would move us to a new workspace. 562 // that does not unless the change would move us to a new workspace.
@@ -275,12 +573,14 @@ void dispatch_cursor_button(struct sway_cursor *cursor,
275 if (new_ws != old_ws) { 573 if (new_ws != old_ws) {
276 seat_set_focus(cursor->seat, cont); 574 seat_set_focus(cursor->seat, cont);
277 } 575 }
576 wlr_seat_pointer_notify_button(cursor->seat->wlr_seat,
577 time_msec, button, state);
278 } else if (cont) { 578 } else if (cont) {
279 seat_set_focus(cursor->seat, cont); 579 seat_set_focus(cursor->seat, cont);
580 wlr_seat_pointer_notify_button(cursor->seat->wlr_seat,
581 time_msec, button, state);
280 } 582 }
281 583
282 wlr_seat_pointer_notify_button(cursor->seat->wlr_seat,
283 time_msec, button, state);
284 transaction_commit_dirty(); 584 transaction_commit_dirty();
285} 585}
286 586
diff --git a/sway/meson.build b/sway/meson.build
index 09bc40b8..f4fdc8ea 100644
--- a/sway/meson.build
+++ b/sway/meson.build
@@ -42,6 +42,7 @@ sway_sources = files(
42 'commands/exec_always.c', 42 'commands/exec_always.c',
43 'commands/floating.c', 43 'commands/floating.c',
44 'commands/floating_minmax_size.c', 44 'commands/floating_minmax_size.c',
45 'commands/floating_modifier.c',
45 'commands/focus.c', 46 'commands/focus.c',
46 'commands/focus_follows_mouse.c', 47 'commands/focus_follows_mouse.c',
47 'commands/focus_wrapping.c', 48 'commands/focus_wrapping.c',
diff --git a/sway/tree/container.c b/sway/tree/container.c
index 4dbfbb29..ba4af352 100644
--- a/sway/tree/container.c
+++ b/sway/tree/container.c
@@ -323,6 +323,8 @@ static struct sway_container *container_destroy_noreaping(
323 } 323 }
324 } 324 }
325 325
326 container_end_mouse_operation(con);
327
326 con->destroying = true; 328 con->destroying = true;
327 container_set_dirty(con); 329 container_set_dirty(con);
328 330
@@ -964,6 +966,8 @@ void container_set_floating(struct sway_container *container, bool enable) {
964 container_reap_empty_recursive(workspace->sway_workspace->floating); 966 container_reap_empty_recursive(workspace->sway_workspace->floating);
965 } 967 }
966 968
969 container_end_mouse_operation(container);
970
967 ipc_event_window(container, "floating"); 971 ipc_event_window(container, "floating");
968} 972}
969 973
@@ -1009,7 +1013,7 @@ void container_get_box(struct sway_container *container, struct wlr_box *box) {
1009/** 1013/**
1010 * Translate the container's position as well as all children. 1014 * Translate the container's position as well as all children.
1011 */ 1015 */
1012static void container_floating_translate(struct sway_container *con, 1016void container_floating_translate(struct sway_container *con,
1013 double x_amount, double y_amount) { 1017 double x_amount, double y_amount) {
1014 con->x += x_amount; 1018 con->x += x_amount;
1015 con->y += y_amount; 1019 con->y += y_amount;
@@ -1105,3 +1109,13 @@ static bool find_urgent_iterator(struct sway_container *con,
1105bool container_has_urgent_child(struct sway_container *container) { 1109bool container_has_urgent_child(struct sway_container *container) {
1106 return container_find(container, find_urgent_iterator, NULL); 1110 return container_find(container, find_urgent_iterator, NULL);
1107} 1111}
1112
1113void container_end_mouse_operation(struct sway_container *container) {
1114 struct sway_seat *seat;
1115 wl_list_for_each(seat, &input_manager->seats, link) {
1116 if (seat->op_container == container) {
1117 seat->op_container = NULL;
1118 seat->operation = OP_NONE;
1119 }
1120 }
1121}
diff --git a/sway/tree/layout.c b/sway/tree/layout.c
index 1f898f8a..533906fa 100644
--- a/sway/tree/layout.c
+++ b/sway/tree/layout.c
@@ -562,6 +562,7 @@ void container_move(struct sway_container *container,
562 workspace_detect_urgent(last_ws); 562 workspace_detect_urgent(last_ws);
563 workspace_detect_urgent(next_ws); 563 workspace_detect_urgent(next_ws);
564 } 564 }
565 container_end_mouse_operation(container);
565} 566}
566 567
567enum sway_container_layout container_get_default_layout( 568enum sway_container_layout container_get_default_layout(
diff --git a/sway/tree/view.c b/sway/tree/view.c
index 7881e6d7..24594950 100644
--- a/sway/tree/view.c
+++ b/sway/tree/view.c
@@ -387,6 +387,8 @@ void view_set_fullscreen(struct sway_view *view, bool fullscreen) {
387 } 387 }
388 } 388 }
389 389
390 container_end_mouse_operation(view->swayc);
391
390 ipc_event_window(view->swayc, "fullscreen_mode"); 392 ipc_event_window(view->swayc, "fullscreen_mode");
391} 393}
392 394