aboutsummaryrefslogtreecommitdiffstats
path: root/sway/input
diff options
context:
space:
mode:
Diffstat (limited to 'sway/input')
-rw-r--r--sway/input/cursor.c29
-rw-r--r--sway/input/keyboard.c77
-rw-r--r--sway/input/libinput.c23
-rw-r--r--sway/input/seat.c89
-rw-r--r--sway/input/seatop_default.c43
-rw-r--r--sway/input/seatop_down.c2
-rw-r--r--sway/input/seatop_move_floating.c10
-rw-r--r--sway/input/seatop_move_tiling.c170
-rw-r--r--sway/input/seatop_resize_floating.c36
-rw-r--r--sway/input/seatop_resize_tiling.c28
-rw-r--r--sway/input/switch.c4
-rw-r--r--sway/input/text_input.c53
12 files changed, 421 insertions, 143 deletions
diff --git a/sway/input/cursor.c b/sway/input/cursor.c
index fa604426..cbb5c6e9 100644
--- a/sway/input/cursor.c
+++ b/sway/input/cursor.c
@@ -20,7 +20,6 @@
20#include "util.h" 20#include "util.h"
21#include "sway/commands.h" 21#include "sway/commands.h"
22#include "sway/desktop.h" 22#include "sway/desktop.h"
23#include "sway/desktop/transaction.h"
24#include "sway/input/cursor.h" 23#include "sway/input/cursor.h"
25#include "sway/input/keyboard.h" 24#include "sway/input/keyboard.h"
26#include "sway/input/tablet.h" 25#include "sway/input/tablet.h"
@@ -383,7 +382,6 @@ static void handle_pointer_motion_relative(
383 382
384 pointer_motion(cursor, e->time_msec, e->device, e->delta_x, e->delta_y, 383 pointer_motion(cursor, e->time_msec, e->device, e->delta_x, e->delta_y,
385 e->unaccel_dx, e->unaccel_dy); 384 e->unaccel_dx, e->unaccel_dy);
386 transaction_commit_dirty();
387} 385}
388 386
389static void handle_pointer_motion_absolute( 387static void handle_pointer_motion_absolute(
@@ -401,7 +399,6 @@ static void handle_pointer_motion_absolute(
401 double dy = ly - cursor->cursor->y; 399 double dy = ly - cursor->cursor->y;
402 400
403 pointer_motion(cursor, event->time_msec, event->device, dx, dy, dx, dy); 401 pointer_motion(cursor, event->time_msec, event->device, dx, dy, dx, dy);
404 transaction_commit_dirty();
405} 402}
406 403
407void dispatch_cursor_button(struct sway_cursor *cursor, 404void dispatch_cursor_button(struct sway_cursor *cursor,
@@ -431,7 +428,6 @@ static void handle_pointer_button(struct wl_listener *listener, void *data) {
431 cursor_handle_activity_from_device(cursor, event->device); 428 cursor_handle_activity_from_device(cursor, event->device);
432 dispatch_cursor_button(cursor, event->device, 429 dispatch_cursor_button(cursor, event->device,
433 event->time_msec, event->button, event->state); 430 event->time_msec, event->button, event->state);
434 transaction_commit_dirty();
435} 431}
436 432
437void dispatch_cursor_axis(struct sway_cursor *cursor, 433void dispatch_cursor_axis(struct sway_cursor *cursor,
@@ -444,7 +440,6 @@ static void handle_pointer_axis(struct wl_listener *listener, void *data) {
444 struct wlr_event_pointer_axis *event = data; 440 struct wlr_event_pointer_axis *event = data;
445 cursor_handle_activity_from_device(cursor, event->device); 441 cursor_handle_activity_from_device(cursor, event->device);
446 dispatch_cursor_axis(cursor, event); 442 dispatch_cursor_axis(cursor, event);
447 transaction_commit_dirty();
448} 443}
449 444
450static void handle_pointer_frame(struct wl_listener *listener, void *data) { 445static void handle_pointer_frame(struct wl_listener *listener, void *data) {
@@ -495,7 +490,6 @@ static void handle_touch_down(struct wl_listener *listener, void *data) {
495 dispatch_cursor_button(cursor, event->device, event->time_msec, 490 dispatch_cursor_button(cursor, event->device, event->time_msec,
496 BTN_LEFT, WLR_BUTTON_PRESSED); 491 BTN_LEFT, WLR_BUTTON_PRESSED);
497 wlr_seat_pointer_notify_frame(wlr_seat); 492 wlr_seat_pointer_notify_frame(wlr_seat);
498 transaction_commit_dirty();
499 } 493 }
500} 494}
501 495
@@ -512,7 +506,6 @@ static void handle_touch_up(struct wl_listener *listener, void *data) {
512 dispatch_cursor_button(cursor, event->device, event->time_msec, 506 dispatch_cursor_button(cursor, event->device, event->time_msec,
513 BTN_LEFT, WLR_BUTTON_RELEASED); 507 BTN_LEFT, WLR_BUTTON_RELEASED);
514 wlr_seat_pointer_notify_frame(wlr_seat); 508 wlr_seat_pointer_notify_frame(wlr_seat);
515 transaction_commit_dirty();
516 } 509 }
517 } else { 510 } else {
518 wlr_seat_touch_notify_up(wlr_seat, event->time_msec, event->touch_id); 511 wlr_seat_touch_notify_up(wlr_seat, event->time_msec, event->touch_id);
@@ -553,7 +546,6 @@ static void handle_touch_motion(struct wl_listener *listener, void *data) {
553 dx = lx - cursor->cursor->x; 546 dx = lx - cursor->cursor->x;
554 dy = ly - cursor->cursor->y; 547 dy = ly - cursor->cursor->y;
555 pointer_motion(cursor, event->time_msec, event->device, dx, dy, dx, dy); 548 pointer_motion(cursor, event->time_msec, event->device, dx, dy, dx, dy);
556 transaction_commit_dirty();
557 } 549 }
558 } else if (surface) { 550 } else if (surface) {
559 wlr_seat_touch_notify_motion(wlr_seat, event->time_msec, 551 wlr_seat_touch_notify_motion(wlr_seat, event->time_msec,
@@ -639,8 +631,6 @@ static void handle_tablet_tool_position(struct sway_cursor *cursor,
639 wlr_tablet_v2_tablet_tool_notify_proximity_out(tool->tablet_v2_tool); 631 wlr_tablet_v2_tablet_tool_notify_proximity_out(tool->tablet_v2_tool);
640 pointer_motion(cursor, time_msec, input_device->wlr_device, dx, dy, dx, dy); 632 pointer_motion(cursor, time_msec, input_device->wlr_device, dx, dy, dx, dy);
641 } 633 }
642
643 transaction_commit_dirty();
644} 634}
645 635
646static void handle_tool_axis(struct wl_listener *listener, void *data) { 636static void handle_tool_axis(struct wl_listener *listener, void *data) {
@@ -720,7 +710,6 @@ static void handle_tool_tip(struct wl_listener *listener, void *data) {
720 dispatch_cursor_button(cursor, event->device, event->time_msec, 710 dispatch_cursor_button(cursor, event->device, event->time_msec,
721 BTN_LEFT, WLR_BUTTON_RELEASED); 711 BTN_LEFT, WLR_BUTTON_RELEASED);
722 wlr_seat_pointer_notify_frame(cursor->seat->wlr_seat); 712 wlr_seat_pointer_notify_frame(cursor->seat->wlr_seat);
723 transaction_commit_dirty();
724 } else if (!surface || !wlr_surface_accepts_tablet_v2(tablet_v2, surface)) { 713 } else if (!surface || !wlr_surface_accepts_tablet_v2(tablet_v2, surface)) {
725 // If we started holding the tool tip down on a surface that accepts 714 // If we started holding the tool tip down on a surface that accepts
726 // tablet v2, we should notify that surface if it gets released over a 715 // tablet v2, we should notify that surface if it gets released over a
@@ -733,7 +722,6 @@ static void handle_tool_tip(struct wl_listener *listener, void *data) {
733 dispatch_cursor_button(cursor, event->device, event->time_msec, 722 dispatch_cursor_button(cursor, event->device, event->time_msec,
734 BTN_LEFT, WLR_BUTTON_PRESSED); 723 BTN_LEFT, WLR_BUTTON_PRESSED);
735 wlr_seat_pointer_notify_frame(cursor->seat->wlr_seat); 724 wlr_seat_pointer_notify_frame(cursor->seat->wlr_seat);
736 transaction_commit_dirty();
737 } 725 }
738 } else { 726 } else {
739 seatop_tablet_tool_tip(seat, sway_tool, event->time_msec, event->state); 727 seatop_tablet_tool_tip(seat, sway_tool, event->time_msec, event->state);
@@ -820,7 +808,6 @@ static void handle_tool_button(struct wl_listener *listener, void *data) {
820 break; 808 break;
821 } 809 }
822 wlr_seat_pointer_notify_frame(cursor->seat->wlr_seat); 810 wlr_seat_pointer_notify_frame(cursor->seat->wlr_seat);
823 transaction_commit_dirty();
824 return; 811 return;
825 } 812 }
826 813
@@ -837,8 +824,8 @@ static void check_constraint_region(struct sway_cursor *cursor) {
837 824
838 struct sway_container *con = view->container; 825 struct sway_container *con = view->container;
839 826
840 double sx = cursor->cursor->x - con->content_x + view->geometry.x; 827 double sx = cursor->cursor->x - con->pending.content_x + view->geometry.x;
841 double sy = cursor->cursor->y - con->content_y + view->geometry.y; 828 double sy = cursor->cursor->y - con->pending.content_y + view->geometry.y;
842 829
843 if (!pixman_region32_contains_point(region, 830 if (!pixman_region32_contains_point(region,
844 floor(sx), floor(sy), NULL)) { 831 floor(sx), floor(sy), NULL)) {
@@ -849,8 +836,8 @@ static void check_constraint_region(struct sway_cursor *cursor) {
849 double sy = (boxes[0].y1 + boxes[0].y2) / 2.; 836 double sy = (boxes[0].y1 + boxes[0].y2) / 2.;
850 837
851 wlr_cursor_warp_closest(cursor->cursor, NULL, 838 wlr_cursor_warp_closest(cursor->cursor, NULL,
852 sx + con->content_x - view->geometry.x, 839 sx + con->pending.content_x - view->geometry.x,
853 sy + con->content_y - view->geometry.y); 840 sy + con->pending.content_y - view->geometry.y);
854 841
855 cursor_rebase(cursor); 842 cursor_rebase(cursor);
856 } 843 }
@@ -1170,8 +1157,8 @@ void cursor_warp_to_container(struct sway_cursor *cursor,
1170 return; 1157 return;
1171 } 1158 }
1172 1159
1173 double x = container->x + container->width / 2.0; 1160 double x = container->pending.x + container->pending.width / 2.0;
1174 double y = container->y + container->height / 2.0; 1161 double y = container->pending.y + container->pending.height / 2.0;
1175 1162
1176 wlr_cursor_warp(cursor->cursor, NULL, x, y); 1163 wlr_cursor_warp(cursor->cursor, NULL, x, y);
1177 cursor_unhide(cursor); 1164 cursor_unhide(cursor);
@@ -1284,8 +1271,8 @@ static void warp_to_constraint_cursor_hint(struct sway_cursor *cursor) {
1284 struct sway_view *view = view_from_wlr_surface(constraint->surface); 1271 struct sway_view *view = view_from_wlr_surface(constraint->surface);
1285 struct sway_container *con = view->container; 1272 struct sway_container *con = view->container;
1286 1273
1287 double lx = sx + con->content_x - view->geometry.x; 1274 double lx = sx + con->pending.content_x - view->geometry.x;
1288 double ly = sy + con->content_y - view->geometry.y; 1275 double ly = sy + con->pending.content_y - view->geometry.y;
1289 1276
1290 wlr_cursor_warp(cursor->cursor, NULL, lx, ly); 1277 wlr_cursor_warp(cursor->cursor, NULL, lx, ly);
1291 1278
diff --git a/sway/input/keyboard.c b/sway/input/keyboard.c
index ce259eb2..f258ac7d 100644
--- a/sway/input/keyboard.c
+++ b/sway/input/keyboard.c
@@ -9,7 +9,6 @@
9#include <wlr/types/wlr_keyboard_group.h> 9#include <wlr/types/wlr_keyboard_group.h>
10#include <xkbcommon/xkbcommon-names.h> 10#include <xkbcommon/xkbcommon-names.h>
11#include "sway/commands.h" 11#include "sway/commands.h"
12#include "sway/desktop/transaction.h"
13#include "sway/input/input-manager.h" 12#include "sway/input/input-manager.h"
14#include "sway/input/keyboard.h" 13#include "sway/input/keyboard.h"
15#include "sway/input/seat.h" 14#include "sway/input/seat.h"
@@ -379,6 +378,28 @@ static void update_keyboard_state(struct sway_keyboard *keyboard,
379 } 378 }
380} 379}
381 380
381/**
382 * Get keyboard grab of the seat from sway_keyboard if we should forward events
383 * to it.
384 *
385 * Returns NULL if the keyboard is not grabbed by an input method,
386 * or if event is from virtual keyboard of the same client as grab.
387 * TODO: see swaywm/wlroots#2322
388 */
389static struct wlr_input_method_keyboard_grab_v2 *keyboard_get_im_grab(
390 struct sway_keyboard *keyboard) {
391 struct wlr_input_method_v2 *input_method = keyboard->seat_device->
392 sway_seat->im_relay.input_method;
393 struct wlr_virtual_keyboard_v1 *virtual_keyboard =
394 wlr_input_device_get_virtual_keyboard(keyboard->seat_device->input_device->wlr_device);
395 if (!input_method || !input_method->keyboard_grab || (virtual_keyboard &&
396 wl_resource_get_client(virtual_keyboard->resource) ==
397 wl_resource_get_client(input_method->keyboard_grab->resource))) {
398 return NULL;
399 }
400 return input_method->keyboard_grab;
401}
402
382static void handle_key_event(struct sway_keyboard *keyboard, 403static void handle_key_event(struct sway_keyboard *keyboard,
383 struct wlr_event_keyboard_key *event) { 404 struct wlr_event_keyboard_key *event) {
384 struct sway_seat *seat = keyboard->seat_device->sway_seat; 405 struct sway_seat *seat = keyboard->seat_device->sway_seat;
@@ -489,18 +510,42 @@ static void handle_key_event(struct sway_keyboard *keyboard,
489 keyinfo.raw_keysyms_len); 510 keyinfo.raw_keysyms_len);
490 } 511 }
491 512
492 if (!handled || event->state == WL_KEYBOARD_KEY_STATE_RELEASED) { 513 if (event->state == WL_KEYBOARD_KEY_STATE_RELEASED) {
514 // If the pressed event was sent to a client, also send the released
515 // event. In particular, don't send the released event to the IM grab.
493 bool pressed_sent = update_shortcut_state( 516 bool pressed_sent = update_shortcut_state(
494 &keyboard->state_pressed_sent, event->keycode, event->state, 517 &keyboard->state_pressed_sent, event->keycode,
495 keyinfo.keycode, 0); 518 event->state, keyinfo.keycode, 0);
496 if (pressed_sent || event->state == WL_KEYBOARD_KEY_STATE_PRESSED) { 519 if (pressed_sent) {
497 wlr_seat_set_keyboard(wlr_seat, wlr_device); 520 wlr_seat_set_keyboard(wlr_seat, wlr_device);
498 wlr_seat_keyboard_notify_key(wlr_seat, event->time_msec, 521 wlr_seat_keyboard_notify_key(wlr_seat, event->time_msec,
499 event->keycode, event->state); 522 event->keycode, event->state);
523 handled = true;
524 }
525 }
526
527 if (!handled) {
528 struct wlr_input_method_keyboard_grab_v2 *kb_grab = keyboard_get_im_grab(keyboard);
529
530 if (kb_grab) {
531 wlr_input_method_keyboard_grab_v2_set_keyboard(kb_grab,
532 wlr_device->keyboard);
533 wlr_input_method_keyboard_grab_v2_send_key(kb_grab,
534 event->time_msec, event->keycode, event->state);
535 handled = true;
500 } 536 }
501 } 537 }
502 538
503 transaction_commit_dirty(); 539 if (!handled && event->state != WL_KEYBOARD_KEY_STATE_RELEASED) {
540 // If a released event failed pressed sent test, and not in sent to
541 // keyboard grab, it is still not handled. Don't handle released here.
542 update_shortcut_state(
543 &keyboard->state_pressed_sent, event->keycode, event->state,
544 keyinfo.keycode, 0);
545 wlr_seat_set_keyboard(wlr_seat, wlr_device);
546 wlr_seat_keyboard_notify_key(wlr_seat, event->time_msec,
547 event->keycode, event->state);
548 }
504 549
505 free(device_identifier); 550 free(device_identifier);
506} 551}
@@ -587,7 +632,6 @@ static int handle_keyboard_repeat(void *data) {
587 632
588 seat_execute_command(keyboard->seat_device->sway_seat, 633 seat_execute_command(keyboard->seat_device->sway_seat,
589 keyboard->repeat_binding); 634 keyboard->repeat_binding);
590 transaction_commit_dirty();
591 } 635 }
592 return 0; 636 return 0;
593} 637}
@@ -617,10 +661,19 @@ static void handle_modifier_event(struct sway_keyboard *keyboard) {
617 struct wlr_input_device *wlr_device = 661 struct wlr_input_device *wlr_device =
618 keyboard->seat_device->input_device->wlr_device; 662 keyboard->seat_device->input_device->wlr_device;
619 if (!wlr_device->keyboard->group) { 663 if (!wlr_device->keyboard->group) {
620 struct wlr_seat *wlr_seat = keyboard->seat_device->sway_seat->wlr_seat; 664 struct wlr_input_method_keyboard_grab_v2 *kb_grab = keyboard_get_im_grab(keyboard);
621 wlr_seat_set_keyboard(wlr_seat, wlr_device); 665
622 wlr_seat_keyboard_notify_modifiers(wlr_seat, 666 if (kb_grab) {
623 &wlr_device->keyboard->modifiers); 667 wlr_input_method_keyboard_grab_v2_set_keyboard(kb_grab,
668 wlr_device->keyboard);
669 wlr_input_method_keyboard_grab_v2_send_modifiers(kb_grab,
670 &wlr_device->keyboard->modifiers);
671 } else {
672 struct wlr_seat *wlr_seat = keyboard->seat_device->sway_seat->wlr_seat;
673 wlr_seat_set_keyboard(wlr_seat, wlr_device);
674 wlr_seat_keyboard_notify_modifiers(wlr_seat,
675 &wlr_device->keyboard->modifiers);
676 }
624 677
625 uint32_t modifiers = wlr_keyboard_get_modifiers(wlr_device->keyboard); 678 uint32_t modifiers = wlr_keyboard_get_modifiers(wlr_device->keyboard);
626 determine_bar_visibility(modifiers); 679 determine_bar_visibility(modifiers);
diff --git a/sway/input/libinput.c b/sway/input/libinput.c
index 54520f9e..060a584a 100644
--- a/sway/input/libinput.c
+++ b/sway/input/libinput.c
@@ -1,5 +1,6 @@
1#include <float.h> 1#include <float.h>
2#include <libinput.h> 2#include <libinput.h>
3#include <libudev.h>
3#include <limits.h> 4#include <limits.h>
4#include <wlr/backend/libinput.h> 5#include <wlr/backend/libinput.h>
5#include "log.h" 6#include "log.h"
@@ -312,3 +313,25 @@ void sway_input_reset_libinput_device(struct sway_input_device *input_device) {
312 ipc_event_input("libinput_config", input_device); 313 ipc_event_input("libinput_config", input_device);
313 } 314 }
314} 315}
316
317bool sway_libinput_device_is_builtin(struct sway_input_device *sway_device) {
318 if (!wlr_input_device_is_libinput(sway_device->wlr_device)) {
319 return false;
320 }
321
322 struct libinput_device *device =
323 wlr_libinput_get_device_handle(sway_device->wlr_device);
324 struct udev_device *udev_device =
325 libinput_device_get_udev_device(device);
326 if (!udev_device) {
327 return false;
328 }
329
330 const char *id_path = udev_device_get_property_value(udev_device, "ID_PATH");
331 if (!id_path) {
332 return false;
333 }
334
335 const char prefix[] = "platform-";
336 return strncmp(id_path, prefix, strlen(prefix)) == 0;
337}
diff --git a/sway/input/seat.c b/sway/input/seat.c
index 1f5865ee..2d714acd 100644
--- a/sway/input/seat.c
+++ b/sway/input/seat.c
@@ -20,6 +20,7 @@
20#include "sway/input/cursor.h" 20#include "sway/input/cursor.h"
21#include "sway/input/input-manager.h" 21#include "sway/input/input-manager.h"
22#include "sway/input/keyboard.h" 22#include "sway/input/keyboard.h"
23#include "sway/input/libinput.h"
23#include "sway/input/seat.h" 24#include "sway/input/seat.h"
24#include "sway/input/switch.h" 25#include "sway/input/switch.h"
25#include "sway/input/tablet.h" 26#include "sway/input/tablet.h"
@@ -309,8 +310,8 @@ static void handle_seat_node_destroy(struct wl_listener *listener, void *data) {
309 // Setting focus_inactive 310 // Setting focus_inactive
310 focus = seat_get_focus_inactive(seat, &root->node); 311 focus = seat_get_focus_inactive(seat, &root->node);
311 seat_set_raw_focus(seat, next_focus); 312 seat_set_raw_focus(seat, next_focus);
312 if (focus->type == N_CONTAINER && focus->sway_container->workspace) { 313 if (focus->type == N_CONTAINER && focus->sway_container->pending.workspace) {
313 seat_set_raw_focus(seat, &focus->sway_container->workspace->node); 314 seat_set_raw_focus(seat, &focus->sway_container->pending.workspace->node);
314 } 315 }
315 seat_set_raw_focus(seat, focus); 316 seat_set_raw_focus(seat, focus);
316 } 317 }
@@ -666,6 +667,40 @@ static void seat_reset_input_config(struct sway_seat *seat,
666 sway_device->input_device->wlr_device, NULL); 667 sway_device->input_device->wlr_device, NULL);
667} 668}
668 669
670static bool has_prefix(const char *str, const char *prefix) {
671 return strncmp(str, prefix, strlen(prefix)) == 0;
672}
673
674/**
675 * Get the name of the built-in output, if any. Returns NULL if there isn't
676 * exactly one built-in output.
677 */
678static const char *get_builtin_output_name(void) {
679 const char *match = NULL;
680 for (int i = 0; i < root->outputs->length; ++i) {
681 struct sway_output *output = root->outputs->items[i];
682 const char *name = output->wlr_output->name;
683 if (has_prefix(name, "eDP-") || has_prefix(name, "LVDS-") ||
684 has_prefix(name, "DSI-")) {
685 if (match != NULL) {
686 return NULL;
687 }
688 match = name;
689 }
690 }
691 return match;
692}
693
694static bool is_touch_or_tablet_tool(struct sway_seat_device *seat_device) {
695 switch (seat_device->input_device->wlr_device->type) {
696 case WLR_INPUT_DEVICE_TOUCH:
697 case WLR_INPUT_DEVICE_TABLET_TOOL:
698 return true;
699 default:
700 return false;
701 }
702}
703
669static void seat_apply_input_config(struct sway_seat *seat, 704static void seat_apply_input_config(struct sway_seat *seat,
670 struct sway_seat_device *sway_device) { 705 struct sway_seat_device *sway_device) {
671 struct input_config *ic = 706 struct input_config *ic =
@@ -681,7 +716,21 @@ static void seat_apply_input_config(struct sway_seat *seat,
681 716
682 switch (mapped_to) { 717 switch (mapped_to) {
683 case MAPPED_TO_DEFAULT: 718 case MAPPED_TO_DEFAULT:
719 /*
720 * If the wlroots backend provides an output name, use that.
721 *
722 * Otherwise, try to map built-in touch and tablet tool devices to the
723 * built-in output.
724 */
684 mapped_to_output = sway_device->input_device->wlr_device->output_name; 725 mapped_to_output = sway_device->input_device->wlr_device->output_name;
726 if (mapped_to_output == NULL && is_touch_or_tablet_tool(sway_device) &&
727 sway_libinput_device_is_builtin(sway_device->input_device)) {
728 mapped_to_output = get_builtin_output_name();
729 if (mapped_to_output) {
730 sway_log(SWAY_DEBUG, "Auto-detected output '%s' for device '%s'",
731 mapped_to_output, sway_device->input_device->identifier);
732 }
733 }
685 if (mapped_to_output == NULL) { 734 if (mapped_to_output == NULL) {
686 return; 735 return;
687 } 736 }
@@ -1086,30 +1135,19 @@ void seat_set_focus(struct sway_seat *seat, struct sway_node *node) {
1086 } 1135 }
1087 1136
1088 struct sway_workspace *new_workspace = node->type == N_WORKSPACE ? 1137 struct sway_workspace *new_workspace = node->type == N_WORKSPACE ?
1089 node->sway_workspace : node->sway_container->workspace; 1138 node->sway_workspace : node->sway_container->pending.workspace;
1090 struct sway_container *container = node->type == N_CONTAINER ? 1139 struct sway_container *container = node->type == N_CONTAINER ?
1091 node->sway_container : NULL; 1140 node->sway_container : NULL;
1092 1141
1093 // Deny setting focus to a view which is hidden by a fullscreen container 1142 // Deny setting focus to a view which is hidden by a fullscreen container or global
1094 if (new_workspace && new_workspace->fullscreen && container && 1143 if (container && container_obstructing_fullscreen_container(container)) {
1095 !container_is_fullscreen_or_child(container)) { 1144 return;
1096 // Unless it's a transient container
1097 if (!container_is_transient_for(container, new_workspace->fullscreen)) {
1098 return;
1099 }
1100 } 1145 }
1146
1101 // Deny setting focus to a workspace node when using fullscreen global 1147 // Deny setting focus to a workspace node when using fullscreen global
1102 if (root->fullscreen_global && !container && new_workspace) { 1148 if (root->fullscreen_global && !container && new_workspace) {
1103 return; 1149 return;
1104 } 1150 }
1105 // Deny setting focus to a view which is hidden by a fullscreen global
1106 if (root->fullscreen_global && container != root->fullscreen_global &&
1107 !container_has_ancestor(container, root->fullscreen_global)) {
1108 // Unless it's a transient container
1109 if (!container_is_transient_for(container, root->fullscreen_global)) {
1110 return;
1111 }
1112 }
1113 1151
1114 struct sway_output *new_output = 1152 struct sway_output *new_output =
1115 new_workspace ? new_workspace->output : NULL; 1153 new_workspace ? new_workspace->output : NULL;
@@ -1135,10 +1173,10 @@ void seat_set_focus(struct sway_seat *seat, struct sway_node *node) {
1135 // Put the container parents on the focus stack, then the workspace, then 1173 // Put the container parents on the focus stack, then the workspace, then
1136 // the focused container. 1174 // the focused container.
1137 if (container) { 1175 if (container) {
1138 struct sway_container *parent = container->parent; 1176 struct sway_container *parent = container->pending.parent;
1139 while (parent) { 1177 while (parent) {
1140 seat_set_raw_focus(seat, &parent->node); 1178 seat_set_raw_focus(seat, &parent->node);
1141 parent = parent->parent; 1179 parent = parent->pending.parent;
1142 } 1180 }
1143 } 1181 }
1144 if (new_workspace) { 1182 if (new_workspace) {
@@ -1234,6 +1272,7 @@ void seat_set_focus_surface(struct sway_seat *seat,
1234 wlr_seat_keyboard_notify_clear_focus(seat->wlr_seat); 1272 wlr_seat_keyboard_notify_clear_focus(seat->wlr_seat);
1235 } 1273 }
1236 1274
1275 sway_input_method_relay_set_focus(&seat->im_relay, surface);
1237 seat_tablet_pads_notify_enter(seat, surface); 1276 seat_tablet_pads_notify_enter(seat, surface);
1238} 1277}
1239 1278
@@ -1326,7 +1365,7 @@ struct sway_container *seat_get_focus_inactive_tiling(struct sway_seat *seat,
1326 struct sway_node *node = current->node; 1365 struct sway_node *node = current->node;
1327 if (node->type == N_CONTAINER && 1366 if (node->type == N_CONTAINER &&
1328 !container_is_floating_or_child(node->sway_container) && 1367 !container_is_floating_or_child(node->sway_container) &&
1329 node->sway_container->workspace == workspace) { 1368 node->sway_container->pending.workspace == workspace) {
1330 return node->sway_container; 1369 return node->sway_container;
1331 } 1370 }
1332 } 1371 }
@@ -1343,7 +1382,7 @@ struct sway_container *seat_get_focus_inactive_floating(struct sway_seat *seat,
1343 struct sway_node *node = current->node; 1382 struct sway_node *node = current->node;
1344 if (node->type == N_CONTAINER && 1383 if (node->type == N_CONTAINER &&
1345 container_is_floating_or_child(node->sway_container) && 1384 container_is_floating_or_child(node->sway_container) &&
1346 node->sway_container->workspace == workspace) { 1385 node->sway_container->pending.workspace == workspace) {
1347 return node->sway_container; 1386 return node->sway_container;
1348 } 1387 }
1349 } 1388 }
@@ -1391,7 +1430,7 @@ struct sway_workspace *seat_get_focused_workspace(struct sway_seat *seat) {
1391 return NULL; 1430 return NULL;
1392 } 1431 }
1393 if (focus->type == N_CONTAINER) { 1432 if (focus->type == N_CONTAINER) {
1394 return focus->sway_container->workspace; 1433 return focus->sway_container->pending.workspace;
1395 } 1434 }
1396 if (focus->type == N_WORKSPACE) { 1435 if (focus->type == N_WORKSPACE) {
1397 return focus->sway_workspace; 1436 return focus->sway_workspace;
@@ -1404,8 +1443,8 @@ struct sway_workspace *seat_get_last_known_workspace(struct sway_seat *seat) {
1404 wl_list_for_each(current, &seat->focus_stack, link) { 1443 wl_list_for_each(current, &seat->focus_stack, link) {
1405 struct sway_node *node = current->node; 1444 struct sway_node *node = current->node;
1406 if (node->type == N_CONTAINER && 1445 if (node->type == N_CONTAINER &&
1407 node->sway_container->workspace) { 1446 node->sway_container->pending.workspace) {
1408 return node->sway_container->workspace; 1447 return node->sway_container->pending.workspace;
1409 } else if (node->type == N_WORKSPACE) { 1448 } else if (node->type == N_WORKSPACE) {
1410 return node->sway_workspace; 1449 return node->sway_workspace;
1411 } 1450 }
diff --git a/sway/input/seatop_default.c b/sway/input/seatop_default.c
index a583ed62..f9eb8c8a 100644
--- a/sway/input/seatop_default.c
+++ b/sway/input/seatop_default.c
@@ -4,6 +4,7 @@
4#include <wlr/types/wlr_cursor.h> 4#include <wlr/types/wlr_cursor.h>
5#include <wlr/types/wlr_tablet_v2.h> 5#include <wlr/types/wlr_tablet_v2.h>
6#include <wlr/types/wlr_xcursor_manager.h> 6#include <wlr/types/wlr_xcursor_manager.h>
7#include "sway/desktop/transaction.h"
7#include "sway/input/cursor.h" 8#include "sway/input/cursor.h"
8#include "sway/input/seat.h" 9#include "sway/input/seat.h"
9#include "sway/input/tablet.h" 10#include "sway/input/tablet.h"
@@ -59,7 +60,7 @@ static bool edge_is_external(struct sway_container *cont, enum wlr_edges edge) {
59 return false; 60 return false;
60 } 61 }
61 } 62 }
62 cont = cont->parent; 63 cont = cont->pending.parent;
63 } 64 }
64 return true; 65 return true;
65} 66}
@@ -69,25 +70,25 @@ static enum wlr_edges find_edge(struct sway_container *cont,
69 if (!cont->view || (surface && cont->view->surface != surface)) { 70 if (!cont->view || (surface && cont->view->surface != surface)) {
70 return WLR_EDGE_NONE; 71 return WLR_EDGE_NONE;
71 } 72 }
72 if (cont->border == B_NONE || !cont->border_thickness || 73 if (cont->pending.border == B_NONE || !cont->pending.border_thickness ||
73 cont->border == B_CSD) { 74 cont->pending.border == B_CSD) {
74 return WLR_EDGE_NONE; 75 return WLR_EDGE_NONE;
75 } 76 }
76 if (cont->fullscreen_mode) { 77 if (cont->pending.fullscreen_mode) {
77 return WLR_EDGE_NONE; 78 return WLR_EDGE_NONE;
78 } 79 }
79 80
80 enum wlr_edges edge = 0; 81 enum wlr_edges edge = 0;
81 if (cursor->cursor->x < cont->x + cont->border_thickness) { 82 if (cursor->cursor->x < cont->pending.x + cont->pending.border_thickness) {
82 edge |= WLR_EDGE_LEFT; 83 edge |= WLR_EDGE_LEFT;
83 } 84 }
84 if (cursor->cursor->y < cont->y + cont->border_thickness) { 85 if (cursor->cursor->y < cont->pending.y + cont->pending.border_thickness) {
85 edge |= WLR_EDGE_TOP; 86 edge |= WLR_EDGE_TOP;
86 } 87 }
87 if (cursor->cursor->x >= cont->x + cont->width - cont->border_thickness) { 88 if (cursor->cursor->x >= cont->pending.x + cont->pending.width - cont->pending.border_thickness) {
88 edge |= WLR_EDGE_RIGHT; 89 edge |= WLR_EDGE_RIGHT;
89 } 90 }
90 if (cursor->cursor->y >= cont->y + cont->height - cont->border_thickness) { 91 if (cursor->cursor->y >= cont->pending.y + cont->pending.height - cont->pending.border_thickness) {
91 edge |= WLR_EDGE_BOTTOM; 92 edge |= WLR_EDGE_BOTTOM;
92 } 93 }
93 94
@@ -231,6 +232,7 @@ static void handle_tablet_tool_tip(struct sway_seat *seat,
231 wlr_layer_surface_v1_from_wlr_surface(surface); 232 wlr_layer_surface_v1_from_wlr_surface(surface);
232 if (layer->current.keyboard_interactive) { 233 if (layer->current.keyboard_interactive) {
233 seat_set_focus_layer(seat, layer); 234 seat_set_focus_layer(seat, layer);
235 transaction_commit_dirty();
234 } 236 }
235 } else if (cont) { 237 } else if (cont) {
236 bool is_floating_or_child = container_is_floating_or_child(cont); 238 bool is_floating_or_child = container_is_floating_or_child(cont);
@@ -249,7 +251,7 @@ static void handle_tablet_tool_tip(struct sway_seat *seat,
249 251
250 // Handle moving a tiling container 252 // Handle moving a tiling container
251 if (config->tiling_drag && mod_pressed && !is_floating_or_child && 253 if (config->tiling_drag && mod_pressed && !is_floating_or_child &&
252 cont->fullscreen_mode == FULLSCREEN_NONE) { 254 cont->pending.fullscreen_mode == FULLSCREEN_NONE) {
253 seatop_begin_move_tiling(seat, cont); 255 seatop_begin_move_tiling(seat, cont);
254 return; 256 return;
255 } 257 }
@@ -268,6 +270,7 @@ static void handle_tablet_tool_tip(struct sway_seat *seat,
268 struct wlr_xwayland *xwayland = server.xwayland.wlr_xwayland; 270 struct wlr_xwayland *xwayland = server.xwayland.wlr_xwayland;
269 wlr_xwayland_set_seat(xwayland, seat->wlr_seat); 271 wlr_xwayland_set_seat(xwayland, seat->wlr_seat);
270 seat_set_focus_surface(seat, xsurface->surface, false); 272 seat_set_focus_surface(seat, xsurface->surface, false);
273 transaction_commit_dirty();
271 } 274 }
272 } 275 }
273#endif 276#endif
@@ -356,6 +359,7 @@ static void handle_button(struct sway_seat *seat, uint32_t time_msec,
356 if (node && node->type == N_WORKSPACE) { 359 if (node && node->type == N_WORKSPACE) {
357 if (state == WLR_BUTTON_PRESSED) { 360 if (state == WLR_BUTTON_PRESSED) {
358 seat_set_focus(seat, node); 361 seat_set_focus(seat, node);
362 transaction_commit_dirty();
359 } 363 }
360 seat_pointer_notify_button(seat, time_msec, button, state); 364 seat_pointer_notify_button(seat, time_msec, button, state);
361 return; 365 return;
@@ -367,6 +371,7 @@ static void handle_button(struct sway_seat *seat, uint32_t time_msec,
367 wlr_layer_surface_v1_from_wlr_surface(surface); 371 wlr_layer_surface_v1_from_wlr_surface(surface);
368 if (layer->current.keyboard_interactive) { 372 if (layer->current.keyboard_interactive) {
369 seat_set_focus_layer(seat, layer); 373 seat_set_focus_layer(seat, layer);
374 transaction_commit_dirty();
370 } 375 }
371 seat_pointer_notify_button(seat, time_msec, button, state); 376 seat_pointer_notify_button(seat, time_msec, button, state);
372 return; 377 return;
@@ -381,7 +386,7 @@ static void handle_button(struct sway_seat *seat, uint32_t time_msec,
381 struct sway_container *cont_to_focus = cont; 386 struct sway_container *cont_to_focus = cont;
382 enum sway_container_layout layout = container_parent_layout(cont); 387 enum sway_container_layout layout = container_parent_layout(cont);
383 if (layout == L_TABBED || layout == L_STACKED) { 388 if (layout == L_TABBED || layout == L_STACKED) {
384 cont_to_focus = seat_get_focus_inactive_view(seat, &cont->parent->node); 389 cont_to_focus = seat_get_focus_inactive_view(seat, &cont->pending.parent->node);
385 } 390 }
386 391
387 seat_set_focus_container(seat, cont_to_focus); 392 seat_set_focus_container(seat, cont_to_focus);
@@ -397,9 +402,9 @@ static void handle_button(struct sway_seat *seat, uint32_t time_msec,
397 BTN_LEFT : BTN_RIGHT; 402 BTN_LEFT : BTN_RIGHT;
398 if (button == btn_resize) { 403 if (button == btn_resize) {
399 edge = 0; 404 edge = 0;
400 edge |= cursor->cursor->x > cont->x + cont->width / 2 ? 405 edge |= cursor->cursor->x > cont->pending.x + cont->pending.width / 2 ?
401 WLR_EDGE_RIGHT : WLR_EDGE_LEFT; 406 WLR_EDGE_RIGHT : WLR_EDGE_LEFT;
402 edge |= cursor->cursor->y > cont->y + cont->height / 2 ? 407 edge |= cursor->cursor->y > cont->pending.y + cont->pending.height / 2 ?
403 WLR_EDGE_BOTTOM : WLR_EDGE_TOP; 408 WLR_EDGE_BOTTOM : WLR_EDGE_TOP;
404 409
405 const char *image = NULL; 410 const char *image = NULL;
@@ -446,9 +451,9 @@ static void handle_button(struct sway_seat *seat, uint32_t time_msec,
446 if (mod_pressed && button == btn_resize) { 451 if (mod_pressed && button == btn_resize) {
447 struct sway_container *floater = container_toplevel_ancestor(cont); 452 struct sway_container *floater = container_toplevel_ancestor(cont);
448 edge = 0; 453 edge = 0;
449 edge |= cursor->cursor->x > floater->x + floater->width / 2 ? 454 edge |= cursor->cursor->x > floater->pending.x + floater->pending.width / 2 ?
450 WLR_EDGE_RIGHT : WLR_EDGE_LEFT; 455 WLR_EDGE_RIGHT : WLR_EDGE_LEFT;
451 edge |= cursor->cursor->y > floater->y + floater->height / 2 ? 456 edge |= cursor->cursor->y > floater->pending.y + floater->pending.height / 2 ?
452 WLR_EDGE_BOTTOM : WLR_EDGE_TOP; 457 WLR_EDGE_BOTTOM : WLR_EDGE_TOP;
453 seatop_begin_resize_floating(seat, floater, edge); 458 seatop_begin_resize_floating(seat, floater, edge);
454 return; 459 return;
@@ -458,7 +463,7 @@ static void handle_button(struct sway_seat *seat, uint32_t time_msec,
458 // Handle moving a tiling container 463 // Handle moving a tiling container
459 if (config->tiling_drag && (mod_pressed || on_titlebar) && 464 if (config->tiling_drag && (mod_pressed || on_titlebar) &&
460 state == WLR_BUTTON_PRESSED && !is_floating_or_child && 465 state == WLR_BUTTON_PRESSED && !is_floating_or_child &&
461 cont && cont->fullscreen_mode == FULLSCREEN_NONE) { 466 cont && cont->pending.fullscreen_mode == FULLSCREEN_NONE) {
462 struct sway_container *focus = seat_get_focused_container(seat); 467 struct sway_container *focus = seat_get_focused_container(seat);
463 bool focused = focus == cont || container_has_ancestor(focus, cont); 468 bool focused = focus == cont || container_has_ancestor(focus, cont);
464 if (on_titlebar && !focused) { 469 if (on_titlebar && !focused) {
@@ -487,6 +492,7 @@ static void handle_button(struct sway_seat *seat, uint32_t time_msec,
487 if (cont && state == WLR_BUTTON_PRESSED) { 492 if (cont && state == WLR_BUTTON_PRESSED) {
488 node = seat_get_focus_inactive(seat, &cont->node); 493 node = seat_get_focus_inactive(seat, &cont->node);
489 seat_set_focus(seat, node); 494 seat_set_focus(seat, node);
495 transaction_commit_dirty();
490 seat_pointer_notify_button(seat, time_msec, button, state); 496 seat_pointer_notify_button(seat, time_msec, button, state);
491 return; 497 return;
492 } 498 }
@@ -501,6 +507,7 @@ static void handle_button(struct sway_seat *seat, uint32_t time_msec,
501 struct wlr_xwayland *xwayland = server.xwayland.wlr_xwayland; 507 struct wlr_xwayland *xwayland = server.xwayland.wlr_xwayland;
502 wlr_xwayland_set_seat(xwayland, seat->wlr_seat); 508 wlr_xwayland_set_seat(xwayland, seat->wlr_seat);
503 seat_set_focus_surface(seat, xsurface->surface, false); 509 seat_set_focus_surface(seat, xsurface->surface, false);
510 transaction_commit_dirty();
504 seat_pointer_notify_button(seat, time_msec, button, state); 511 seat_pointer_notify_button(seat, time_msec, button, state);
505 return; 512 return;
506 } 513 }
@@ -530,6 +537,7 @@ static void check_focus_follows_mouse(struct sway_seat *seat,
530 if (focus && hovered_output != node_get_output(focus)) { 537 if (focus && hovered_output != node_get_output(focus)) {
531 struct sway_workspace *ws = output_get_active_workspace(hovered_output); 538 struct sway_workspace *ws = output_get_active_workspace(hovered_output);
532 seat_set_focus(seat, &ws->node); 539 seat_set_focus(seat, &ws->node);
540 transaction_commit_dirty();
533 } 541 }
534 return; 542 return;
535 } 543 }
@@ -541,6 +549,7 @@ static void check_focus_follows_mouse(struct sway_seat *seat,
541 struct sway_output *hovered_output = node_get_output(hovered_node); 549 struct sway_output *hovered_output = node_get_output(hovered_node);
542 if (hovered_output != focused_output) { 550 if (hovered_output != focused_output) {
543 seat_set_focus(seat, seat_get_focus_inactive(seat, hovered_node)); 551 seat_set_focus(seat, seat_get_focus_inactive(seat, hovered_node));
552 transaction_commit_dirty();
544 } 553 }
545 return; 554 return;
546 } 555 }
@@ -556,6 +565,7 @@ static void check_focus_follows_mouse(struct sway_seat *seat,
556 if (hovered_node != e->previous_node || 565 if (hovered_node != e->previous_node ||
557 config->focus_follows_mouse == FOLLOWS_ALWAYS) { 566 config->focus_follows_mouse == FOLLOWS_ALWAYS) {
558 seat_set_focus(seat, hovered_node); 567 seat_set_focus(seat, hovered_node);
568 transaction_commit_dirty();
559 } 569 }
560 } 570 }
561} 571}
@@ -664,7 +674,7 @@ static void handle_pointer_axis(struct sway_seat *seat,
664 bool on_border = edge != WLR_EDGE_NONE; 674 bool on_border = edge != WLR_EDGE_NONE;
665 bool on_titlebar = cont && !on_border && !surface; 675 bool on_titlebar = cont && !on_border && !surface;
666 bool on_titlebar_border = cont && on_border && 676 bool on_titlebar_border = cont && on_border &&
667 cursor->cursor->y < cont->content_y; 677 cursor->cursor->y < cont->pending.content_y;
668 bool on_contents = cont && !on_border && surface; 678 bool on_contents = cont && !on_border && surface;
669 bool on_workspace = node && node->type == N_WORKSPACE; 679 bool on_workspace = node && node->type == N_WORKSPACE;
670 float scroll_factor = 680 float scroll_factor =
@@ -714,6 +724,7 @@ static void handle_pointer_axis(struct sway_seat *seat,
714 // Use the focused child of the tabbed/stacked container, not the 724 // Use the focused child of the tabbed/stacked container, not the
715 // container the user scrolled on. 725 // container the user scrolled on.
716 seat_set_focus(seat, new_focus); 726 seat_set_focus(seat, new_focus);
727 transaction_commit_dirty();
717 handled = true; 728 handled = true;
718 } 729 }
719 } 730 }
diff --git a/sway/input/seatop_down.c b/sway/input/seatop_down.c
index 17f619e3..844cf5ab 100644
--- a/sway/input/seatop_down.c
+++ b/sway/input/seatop_down.c
@@ -5,6 +5,7 @@
5#include "sway/input/cursor.h" 5#include "sway/input/cursor.h"
6#include "sway/input/seat.h" 6#include "sway/input/seat.h"
7#include "sway/tree/view.h" 7#include "sway/tree/view.h"
8#include "sway/desktop/transaction.h"
8#include "log.h" 9#include "log.h"
9 10
10struct seatop_down_event { 11struct seatop_down_event {
@@ -107,4 +108,5 @@ void seatop_begin_down(struct sway_seat *seat, struct sway_container *con,
107 seat->seatop_data = e; 108 seat->seatop_data = e;
108 109
109 container_raise_floating(con); 110 container_raise_floating(con);
111 transaction_commit_dirty();
110} 112}
diff --git a/sway/input/seatop_move_floating.c b/sway/input/seatop_move_floating.c
index 7f501fc9..ddcd4c53 100644
--- a/sway/input/seatop_move_floating.c
+++ b/sway/input/seatop_move_floating.c
@@ -1,6 +1,7 @@
1#define _POSIX_C_SOURCE 200809L 1#define _POSIX_C_SOURCE 200809L
2#include <wlr/types/wlr_cursor.h> 2#include <wlr/types/wlr_cursor.h>
3#include "sway/desktop.h" 3#include "sway/desktop.h"
4#include "sway/desktop/transaction.h"
4#include "sway/input/cursor.h" 5#include "sway/input/cursor.h"
5#include "sway/input/seat.h" 6#include "sway/input/seat.h"
6 7
@@ -14,7 +15,8 @@ static void finalize_move(struct sway_seat *seat) {
14 15
15 // We "move" the container to its own location 16 // We "move" the container to its own location
16 // so it discovers its output again. 17 // so it discovers its output again.
17 container_floating_move_to(e->con, e->con->x, e->con->y); 18 container_floating_move_to(e->con, e->con->pending.x, e->con->pending.y);
19 transaction_commit_dirty();
18 20
19 seatop_begin_default(seat); 21 seatop_begin_default(seat);
20} 22}
@@ -40,6 +42,7 @@ static void handle_pointer_motion(struct sway_seat *seat, uint32_t time_msec) {
40 desktop_damage_whole_container(e->con); 42 desktop_damage_whole_container(e->con);
41 container_floating_move_to(e->con, cursor->x - e->dx, cursor->y - e->dy); 43 container_floating_move_to(e->con, cursor->x - e->dx, cursor->y - e->dy);
42 desktop_damage_whole_container(e->con); 44 desktop_damage_whole_container(e->con);
45 transaction_commit_dirty();
43} 46}
44 47
45static void handle_unref(struct sway_seat *seat, struct sway_container *con) { 48static void handle_unref(struct sway_seat *seat, struct sway_container *con) {
@@ -67,13 +70,14 @@ void seatop_begin_move_floating(struct sway_seat *seat,
67 return; 70 return;
68 } 71 }
69 e->con = con; 72 e->con = con;
70 e->dx = cursor->cursor->x - con->x; 73 e->dx = cursor->cursor->x - con->pending.x;
71 e->dy = cursor->cursor->y - con->y; 74 e->dy = cursor->cursor->y - con->pending.y;
72 75
73 seat->seatop_impl = &seatop_impl; 76 seat->seatop_impl = &seatop_impl;
74 seat->seatop_data = e; 77 seat->seatop_data = e;
75 78
76 container_raise_floating(con); 79 container_raise_floating(con);
80 transaction_commit_dirty();
77 81
78 cursor_set_image(cursor, "grab", NULL); 82 cursor_set_image(cursor, "grab", NULL);
79 wlr_seat_pointer_notify_clear_focus(seat->wlr_seat); 83 wlr_seat_pointer_notify_clear_focus(seat->wlr_seat);
diff --git a/sway/input/seatop_move_tiling.c b/sway/input/seatop_move_tiling.c
index 704e7270..223c6c08 100644
--- a/sway/input/seatop_move_tiling.c
+++ b/sway/input/seatop_move_tiling.c
@@ -3,6 +3,7 @@
3#include <wlr/types/wlr_cursor.h> 3#include <wlr/types/wlr_cursor.h>
4#include <wlr/util/edges.h> 4#include <wlr/util/edges.h>
5#include "sway/desktop.h" 5#include "sway/desktop.h"
6#include "sway/desktop/transaction.h"
6#include "sway/input/cursor.h" 7#include "sway/input/cursor.h"
7#include "sway/input/seat.h" 8#include "sway/input/seat.h"
8#include "sway/ipc-server.h" 9#include "sway/ipc-server.h"
@@ -15,6 +16,10 @@
15// Thickness of the dropzone when dragging to the edge of a layout container 16// Thickness of the dropzone when dragging to the edge of a layout container
16#define DROP_LAYOUT_BORDER 30 17#define DROP_LAYOUT_BORDER 30
17 18
19// Thickness of indicator when dropping onto a titlebar. This should be a
20// multiple of 2.
21#define DROP_SPLIT_INDICATOR 10
22
18struct seatop_move_tiling_event { 23struct seatop_move_tiling_event {
19 struct sway_container *con; 24 struct sway_container *con;
20 struct sway_node *target_node; 25 struct sway_node *target_node;
@@ -22,6 +27,8 @@ struct seatop_move_tiling_event {
22 struct wlr_box drop_box; 27 struct wlr_box drop_box;
23 double ref_lx, ref_ly; // cursor's x/y at start of op 28 double ref_lx, ref_ly; // cursor's x/y at start of op
24 bool threshold_reached; 29 bool threshold_reached;
30 bool split_target;
31 bool insert_after_target;
25}; 32};
26 33
27static void handle_render(struct sway_seat *seat, 34static void handle_render(struct sway_seat *seat,
@@ -91,8 +98,76 @@ static void resize_box(struct wlr_box *box, enum wlr_edges edge,
91 } 98 }
92} 99}
93 100
101static void split_border(double pos, int offset, int len, int n_children,
102 int avoid, int *out_pos, bool *out_after) {
103 int region = 2 * n_children * (pos - offset) / len;
104 // If the cursor is over the right side of a left-adjacent titlebar, or the
105 // left side of a right-adjacent titlebar, it's position when dropped will
106 // be the same. To avoid this, shift the region for adjacent containers.
107 if (avoid >= 0) {
108 if (region == 2 * avoid - 1 || region == 2 * avoid) {
109 region--;
110 } else if (region == 2 * avoid + 1 || region == 2 * avoid + 2) {
111 region++;
112 }
113 }
114
115 int child_index = (region + 1) / 2;
116 *out_after = region % 2;
117 // When dropping at the beginning or end of a container, show the drop
118 // region within the container boundary, otherwise show it on top of the
119 // border between two titlebars.
120 if (child_index == 0) {
121 *out_pos = offset;
122 } else if (child_index == n_children) {
123 *out_pos = offset + len - DROP_SPLIT_INDICATOR;
124 } else {
125 *out_pos = offset + child_index * len / n_children -
126 DROP_SPLIT_INDICATOR / 2;
127 }
128}
129
130static bool split_titlebar(struct sway_node *node, struct sway_container *avoid,
131 struct wlr_cursor *cursor, struct wlr_box *title_box, bool *after) {
132 struct sway_container *con = node->sway_container;
133 struct sway_node *parent = &con->pending.parent->node;
134 int title_height = container_titlebar_height();
135 struct wlr_box box;
136 int n_children, avoid_index;
137 enum sway_container_layout layout =
138 parent ? node_get_layout(parent) : L_NONE;
139 if (layout == L_TABBED || layout == L_STACKED) {
140 node_get_box(parent, &box);
141 n_children = node_get_children(parent)->length;
142 avoid_index = list_find(node_get_children(parent), avoid);
143 } else {
144 node_get_box(node, &box);
145 n_children = 1;
146 avoid_index = -1;
147 }
148 if (layout == L_STACKED && cursor->y < box.y + title_height * n_children) {
149 // Drop into stacked titlebars.
150 title_box->width = box.width;
151 title_box->height = DROP_SPLIT_INDICATOR;
152 title_box->x = box.x;
153 split_border(cursor->y, box.y, title_height * n_children,
154 n_children, avoid_index, &title_box->y, after);
155 return true;
156 } else if (layout != L_STACKED && cursor->y < box.y + title_height) {
157 // Drop into side-by-side titlebars.
158 title_box->width = DROP_SPLIT_INDICATOR;
159 title_box->height = title_height;
160 title_box->y = box.y;
161 split_border(cursor->x, box.x, box.width, n_children,
162 avoid_index, &title_box->x, after);
163 return true;
164 }
165 return false;
166}
167
94static void handle_motion_postthreshold(struct sway_seat *seat) { 168static void handle_motion_postthreshold(struct sway_seat *seat) {
95 struct seatop_move_tiling_event *e = seat->seatop_data; 169 struct seatop_move_tiling_event *e = seat->seatop_data;
170 e->split_target = false;
96 struct wlr_surface *surface = NULL; 171 struct wlr_surface *surface = NULL;
97 double sx, sy; 172 double sx, sy;
98 struct sway_cursor *cursor = seat->cursor; 173 struct sway_cursor *cursor = seat->cursor;
@@ -119,34 +194,60 @@ static void handle_motion_postthreshold(struct sway_seat *seat) {
119 194
120 // Deny moving within own workspace if this is the only child 195 // Deny moving within own workspace if this is the only child
121 struct sway_container *con = node->sway_container; 196 struct sway_container *con = node->sway_container;
122 if (workspace_num_tiling_views(e->con->workspace) == 1 && 197 if (workspace_num_tiling_views(e->con->pending.workspace) == 1 &&
123 con->workspace == e->con->workspace) { 198 con->pending.workspace == e->con->pending.workspace) {
124 e->target_node = NULL; 199 e->target_node = NULL;
125 e->target_edge = WLR_EDGE_NONE; 200 e->target_edge = WLR_EDGE_NONE;
126 return; 201 return;
127 } 202 }
128 203
204 // Check if the cursor is over a tilebar only if the destination
205 // container is not a descendant of the source container.
206 if (!surface && !container_has_ancestor(con, e->con) &&
207 split_titlebar(node, e->con, cursor->cursor,
208 &e->drop_box, &e->insert_after_target)) {
209 // Don't allow dropping over the source container's titlebar
210 // to give users a chance to cancel a drag operation.
211 if (con == e->con) {
212 e->target_node = NULL;
213 } else {
214 e->target_node = node;
215 e->split_target = true;
216 }
217 e->target_edge = WLR_EDGE_NONE;
218 return;
219 }
220
129 // Traverse the ancestors, trying to find a layout container perpendicular 221 // Traverse the ancestors, trying to find a layout container perpendicular
130 // to the edge. Eg. close to the top or bottom of a horiz layout. 222 // to the edge. Eg. close to the top or bottom of a horiz layout.
223 int thresh_top = con->pending.content_y + DROP_LAYOUT_BORDER;
224 int thresh_bottom = con->pending.content_y +
225 con->pending.content_height - DROP_LAYOUT_BORDER;
226 int thresh_left = con->pending.content_x + DROP_LAYOUT_BORDER;
227 int thresh_right = con->pending.content_x +
228 con->pending.content_width - DROP_LAYOUT_BORDER;
131 while (con) { 229 while (con) {
132 enum wlr_edges edge = WLR_EDGE_NONE; 230 enum wlr_edges edge = WLR_EDGE_NONE;
133 enum sway_container_layout layout = container_parent_layout(con); 231 enum sway_container_layout layout = container_parent_layout(con);
134 struct wlr_box parent; 232 struct wlr_box box;
135 con->parent ? container_get_box(con->parent, &parent) : 233 node_get_box(node_get_parent(&con->node), &box);
136 workspace_get_box(con->workspace, &parent);
137 if (layout == L_HORIZ || layout == L_TABBED) { 234 if (layout == L_HORIZ || layout == L_TABBED) {
138 if (cursor->cursor->y < parent.y + DROP_LAYOUT_BORDER) { 235 if (cursor->cursor->y < thresh_top) {
139 edge = WLR_EDGE_TOP; 236 edge = WLR_EDGE_TOP;
140 } else if (cursor->cursor->y > parent.y + parent.height 237 box.height = thresh_top - box.y;
141 - DROP_LAYOUT_BORDER) { 238 } else if (cursor->cursor->y > thresh_bottom) {
142 edge = WLR_EDGE_BOTTOM; 239 edge = WLR_EDGE_BOTTOM;
240 box.height = box.y + box.height - thresh_bottom;
241 box.y = thresh_bottom;
143 } 242 }
144 } else if (layout == L_VERT || layout == L_STACKED) { 243 } else if (layout == L_VERT || layout == L_STACKED) {
145 if (cursor->cursor->x < parent.x + DROP_LAYOUT_BORDER) { 244 if (cursor->cursor->x < thresh_left) {
146 edge = WLR_EDGE_LEFT; 245 edge = WLR_EDGE_LEFT;
147 } else if (cursor->cursor->x > parent.x + parent.width 246 box.width = thresh_left - box.x;
148 - DROP_LAYOUT_BORDER) { 247 } else if (cursor->cursor->x > thresh_right) {
149 edge = WLR_EDGE_RIGHT; 248 edge = WLR_EDGE_RIGHT;
249 box.width = box.x + box.width - thresh_right;
250 box.x = thresh_right;
150 } 251 }
151 } 252 }
152 if (edge) { 253 if (edge) {
@@ -155,12 +256,11 @@ static void handle_motion_postthreshold(struct sway_seat *seat) {
155 e->target_node = node_get_parent(e->target_node); 256 e->target_node = node_get_parent(e->target_node);
156 } 257 }
157 e->target_edge = edge; 258 e->target_edge = edge;
158 node_get_box(e->target_node, &e->drop_box); 259 e->drop_box = box;
159 resize_box(&e->drop_box, edge, DROP_LAYOUT_BORDER);
160 desktop_damage_box(&e->drop_box); 260 desktop_damage_box(&e->drop_box);
161 return; 261 return;
162 } 262 }
163 con = con->parent; 263 con = con->pending.parent;
164 } 264 }
165 265
166 // Use the hovered view - but we must be over the actual surface 266 // Use the hovered view - but we must be over the actual surface
@@ -173,23 +273,23 @@ static void handle_motion_postthreshold(struct sway_seat *seat) {
173 } 273 }
174 274
175 // Find the closest edge 275 // Find the closest edge
176 size_t thickness = fmin(con->content_width, con->content_height) * 0.3; 276 size_t thickness = fmin(con->pending.content_width, con->pending.content_height) * 0.3;
177 size_t closest_dist = INT_MAX; 277 size_t closest_dist = INT_MAX;
178 size_t dist; 278 size_t dist;
179 e->target_edge = WLR_EDGE_NONE; 279 e->target_edge = WLR_EDGE_NONE;
180 if ((dist = cursor->cursor->y - con->y) < closest_dist) { 280 if ((dist = cursor->cursor->y - con->pending.y) < closest_dist) {
181 closest_dist = dist; 281 closest_dist = dist;
182 e->target_edge = WLR_EDGE_TOP; 282 e->target_edge = WLR_EDGE_TOP;
183 } 283 }
184 if ((dist = cursor->cursor->x - con->x) < closest_dist) { 284 if ((dist = cursor->cursor->x - con->pending.x) < closest_dist) {
185 closest_dist = dist; 285 closest_dist = dist;
186 e->target_edge = WLR_EDGE_LEFT; 286 e->target_edge = WLR_EDGE_LEFT;
187 } 287 }
188 if ((dist = con->x + con->width - cursor->cursor->x) < closest_dist) { 288 if ((dist = con->pending.x + con->pending.width - cursor->cursor->x) < closest_dist) {
189 closest_dist = dist; 289 closest_dist = dist;
190 e->target_edge = WLR_EDGE_RIGHT; 290 e->target_edge = WLR_EDGE_RIGHT;
191 } 291 }
192 if ((dist = con->y + con->height - cursor->cursor->y) < closest_dist) { 292 if ((dist = con->pending.y + con->pending.height - cursor->cursor->y) < closest_dist) {
193 closest_dist = dist; 293 closest_dist = dist;
194 e->target_edge = WLR_EDGE_BOTTOM; 294 e->target_edge = WLR_EDGE_BOTTOM;
195 } 295 }
@@ -199,10 +299,10 @@ static void handle_motion_postthreshold(struct sway_seat *seat) {
199 } 299 }
200 300
201 e->target_node = node; 301 e->target_node = node;
202 e->drop_box.x = con->content_x; 302 e->drop_box.x = con->pending.content_x;
203 e->drop_box.y = con->content_y; 303 e->drop_box.y = con->pending.content_y;
204 e->drop_box.width = con->content_width; 304 e->drop_box.width = con->pending.content_width;
205 e->drop_box.height = con->content_height; 305 e->drop_box.height = con->pending.content_height;
206 resize_box(&e->drop_box, e->target_edge, thickness); 306 resize_box(&e->drop_box, e->target_edge, thickness);
207 desktop_damage_box(&e->drop_box); 307 desktop_damage_box(&e->drop_box);
208} 308}
@@ -214,6 +314,7 @@ static void handle_pointer_motion(struct sway_seat *seat, uint32_t time_msec) {
214 } else { 314 } else {
215 handle_motion_prethreshold(seat); 315 handle_motion_prethreshold(seat);
216 } 316 }
317 transaction_commit_dirty();
217} 318}
218 319
219static bool is_parallel(enum sway_container_layout layout, 320static bool is_parallel(enum sway_container_layout layout,
@@ -232,14 +333,15 @@ static void finalize_move(struct sway_seat *seat) {
232 } 333 }
233 334
234 struct sway_container *con = e->con; 335 struct sway_container *con = e->con;
235 struct sway_container *old_parent = con->parent; 336 struct sway_container *old_parent = con->pending.parent;
236 struct sway_workspace *old_ws = con->workspace; 337 struct sway_workspace *old_ws = con->pending.workspace;
237 struct sway_node *target_node = e->target_node; 338 struct sway_node *target_node = e->target_node;
238 struct sway_workspace *new_ws = target_node->type == N_WORKSPACE ? 339 struct sway_workspace *new_ws = target_node->type == N_WORKSPACE ?
239 target_node->sway_workspace : target_node->sway_container->workspace; 340 target_node->sway_workspace : target_node->sway_container->pending.workspace;
240 enum wlr_edges edge = e->target_edge; 341 enum wlr_edges edge = e->target_edge;
241 int after = edge != WLR_EDGE_TOP && edge != WLR_EDGE_LEFT; 342 int after = edge != WLR_EDGE_TOP && edge != WLR_EDGE_LEFT;
242 bool swap = edge == WLR_EDGE_NONE && target_node->type == N_CONTAINER; 343 bool swap = edge == WLR_EDGE_NONE && target_node->type == N_CONTAINER &&
344 !e->split_target;
243 345
244 if (!swap) { 346 if (!swap) {
245 container_detach(con); 347 container_detach(con);
@@ -248,6 +350,14 @@ static void finalize_move(struct sway_seat *seat) {
248 // Moving container into empty workspace 350 // Moving container into empty workspace
249 if (target_node->type == N_WORKSPACE && edge == WLR_EDGE_NONE) { 351 if (target_node->type == N_WORKSPACE && edge == WLR_EDGE_NONE) {
250 con = workspace_add_tiling(new_ws, con); 352 con = workspace_add_tiling(new_ws, con);
353 } else if (e->split_target) {
354 struct sway_container *target = target_node->sway_container;
355 enum sway_container_layout layout = container_parent_layout(target);
356 if (layout != L_TABBED && layout != L_STACKED) {
357 container_split(target, L_TABBED);
358 }
359 container_add_sibling(target, con, e->insert_after_target);
360 ipc_event_window(con, "move");
251 } else if (target_node->type == N_CONTAINER) { 361 } else if (target_node->type == N_CONTAINER) {
252 // Moving container before/after another 362 // Moving container before/after another
253 struct sway_container *target = target_node->sway_container; 363 struct sway_container *target = target_node->sway_container;
@@ -283,8 +393,8 @@ static void finalize_move(struct sway_seat *seat) {
283 int index = list_find(siblings, con); 393 int index = list_find(siblings, con);
284 struct sway_container *sibling = index == 0 ? 394 struct sway_container *sibling = index == 0 ?
285 siblings->items[1] : siblings->items[index - 1]; 395 siblings->items[1] : siblings->items[index - 1];
286 con->width = sibling->width; 396 con->pending.width = sibling->pending.width;
287 con->height = sibling->height; 397 con->pending.height = sibling->pending.height;
288 con->width_fraction = sibling->width_fraction; 398 con->width_fraction = sibling->width_fraction;
289 con->height_fraction = sibling->height_fraction; 399 con->height_fraction = sibling->height_fraction;
290 } 400 }
@@ -294,6 +404,7 @@ static void finalize_move(struct sway_seat *seat) {
294 arrange_workspace(new_ws); 404 arrange_workspace(new_ws);
295 } 405 }
296 406
407 transaction_commit_dirty();
297 seatop_begin_default(seat); 408 seatop_begin_default(seat);
298} 409}
299 410
@@ -348,6 +459,7 @@ void seatop_begin_move_tiling_threshold(struct sway_seat *seat,
348 seat->seatop_data = e; 459 seat->seatop_data = e;
349 460
350 container_raise_floating(con); 461 container_raise_floating(con);
462 transaction_commit_dirty();
351 wlr_seat_pointer_notify_clear_focus(seat->wlr_seat); 463 wlr_seat_pointer_notify_clear_focus(seat->wlr_seat);
352} 464}
353 465
diff --git a/sway/input/seatop_resize_floating.c b/sway/input/seatop_resize_floating.c
index 5da22e47..8400a4b3 100644
--- a/sway/input/seatop_resize_floating.c
+++ b/sway/input/seatop_resize_floating.c
@@ -2,6 +2,7 @@
2#include <limits.h> 2#include <limits.h>
3#include <wlr/types/wlr_cursor.h> 3#include <wlr/types/wlr_cursor.h>
4#include <wlr/types/wlr_xcursor_manager.h> 4#include <wlr/types/wlr_xcursor_manager.h>
5#include "sway/desktop/transaction.h"
5#include "sway/input/cursor.h" 6#include "sway/input/cursor.h"
6#include "sway/input/seat.h" 7#include "sway/input/seat.h"
7#include "sway/tree/arrange.h" 8#include "sway/tree/arrange.h"
@@ -27,6 +28,7 @@ static void handle_button(struct sway_seat *seat, uint32_t time_msec,
27 if (seat->cursor->pressed_button_count == 0) { 28 if (seat->cursor->pressed_button_count == 0) {
28 container_set_resizing(con, false); 29 container_set_resizing(con, false);
29 arrange_container(con); // Send configure w/o resizing hint 30 arrange_container(con); // Send configure w/o resizing hint
31 transaction_commit_dirty();
30 seatop_begin_default(seat); 32 seatop_begin_default(seat);
31 } 33 }
32} 34}
@@ -116,23 +118,24 @@ static void handle_pointer_motion(struct sway_seat *seat, uint32_t time_msec) {
116 118
117 // Determine the amounts we need to bump everything relative to the current 119 // Determine the amounts we need to bump everything relative to the current
118 // size. 120 // size.
119 int relative_grow_width = width - con->width; 121 int relative_grow_width = width - con->pending.width;
120 int relative_grow_height = height - con->height; 122 int relative_grow_height = height - con->pending.height;
121 int relative_grow_x = (e->ref_con_lx + grow_x) - con->x; 123 int relative_grow_x = (e->ref_con_lx + grow_x) - con->pending.x;
122 int relative_grow_y = (e->ref_con_ly + grow_y) - con->y; 124 int relative_grow_y = (e->ref_con_ly + grow_y) - con->pending.y;
123 125
124 // Actually resize stuff 126 // Actually resize stuff
125 con->x += relative_grow_x; 127 con->pending.x += relative_grow_x;
126 con->y += relative_grow_y; 128 con->pending.y += relative_grow_y;
127 con->width += relative_grow_width; 129 con->pending.width += relative_grow_width;
128 con->height += relative_grow_height; 130 con->pending.height += relative_grow_height;
129 131
130 con->content_x += relative_grow_x; 132 con->pending.content_x += relative_grow_x;
131 con->content_y += relative_grow_y; 133 con->pending.content_y += relative_grow_y;
132 con->content_width += relative_grow_width; 134 con->pending.content_width += relative_grow_width;
133 con->content_height += relative_grow_height; 135 con->pending.content_height += relative_grow_height;
134 136
135 arrange_container(con); 137 arrange_container(con);
138 transaction_commit_dirty();
136} 139}
137 140
138static void handle_unref(struct sway_seat *seat, struct sway_container *con) { 141static void handle_unref(struct sway_seat *seat, struct sway_container *con) {
@@ -166,16 +169,17 @@ void seatop_begin_resize_floating(struct sway_seat *seat,
166 e->edge = edge == WLR_EDGE_NONE ? WLR_EDGE_BOTTOM | WLR_EDGE_RIGHT : edge; 169 e->edge = edge == WLR_EDGE_NONE ? WLR_EDGE_BOTTOM | WLR_EDGE_RIGHT : edge;
167 e->ref_lx = seat->cursor->cursor->x; 170 e->ref_lx = seat->cursor->cursor->x;
168 e->ref_ly = seat->cursor->cursor->y; 171 e->ref_ly = seat->cursor->cursor->y;
169 e->ref_con_lx = con->x; 172 e->ref_con_lx = con->pending.x;
170 e->ref_con_ly = con->y; 173 e->ref_con_ly = con->pending.y;
171 e->ref_width = con->width; 174 e->ref_width = con->pending.width;
172 e->ref_height = con->height; 175 e->ref_height = con->pending.height;
173 176
174 seat->seatop_impl = &seatop_impl; 177 seat->seatop_impl = &seatop_impl;
175 seat->seatop_data = e; 178 seat->seatop_data = e;
176 179
177 container_set_resizing(con, true); 180 container_set_resizing(con, true);
178 container_raise_floating(con); 181 container_raise_floating(con);
182 transaction_commit_dirty();
179 183
180 const char *image = edge == WLR_EDGE_NONE ? 184 const char *image = edge == WLR_EDGE_NONE ?
181 "se-resize" : wlr_xcursor_get_resize_name(edge); 185 "se-resize" : wlr_xcursor_get_resize_name(edge);
diff --git a/sway/input/seatop_resize_tiling.c b/sway/input/seatop_resize_tiling.c
index 2cca805d..869d11b5 100644
--- a/sway/input/seatop_resize_tiling.c
+++ b/sway/input/seatop_resize_tiling.c
@@ -2,6 +2,7 @@
2#include <wlr/types/wlr_cursor.h> 2#include <wlr/types/wlr_cursor.h>
3#include <wlr/util/edges.h> 3#include <wlr/util/edges.h>
4#include "sway/commands.h" 4#include "sway/commands.h"
5#include "sway/desktop/transaction.h"
5#include "sway/input/cursor.h" 6#include "sway/input/cursor.h"
6#include "sway/input/seat.h" 7#include "sway/input/seat.h"
7#include "sway/tree/arrange.h" 8#include "sway/tree/arrange.h"
@@ -52,21 +53,22 @@ static void handle_button(struct sway_seat *seat, uint32_t time_msec,
52 if (e->h_con) { 53 if (e->h_con) {
53 container_set_resizing(e->h_con, false); 54 container_set_resizing(e->h_con, false);
54 container_set_resizing(e->h_sib, false); 55 container_set_resizing(e->h_sib, false);
55 if (e->h_con->parent) { 56 if (e->h_con->pending.parent) {
56 arrange_container(e->h_con->parent); 57 arrange_container(e->h_con->pending.parent);
57 } else { 58 } else {
58 arrange_workspace(e->h_con->workspace); 59 arrange_workspace(e->h_con->pending.workspace);
59 } 60 }
60 } 61 }
61 if (e->v_con) { 62 if (e->v_con) {
62 container_set_resizing(e->v_con, false); 63 container_set_resizing(e->v_con, false);
63 container_set_resizing(e->v_sib, false); 64 container_set_resizing(e->v_sib, false);
64 if (e->v_con->parent) { 65 if (e->v_con->pending.parent) {
65 arrange_container(e->v_con->parent); 66 arrange_container(e->v_con->pending.parent);
66 } else { 67 } else {
67 arrange_workspace(e->v_con->workspace); 68 arrange_workspace(e->v_con->pending.workspace);
68 } 69 }
69 } 70 }
71 transaction_commit_dirty();
70 seatop_begin_default(seat); 72 seatop_begin_default(seat);
71 } 73 }
72} 74}
@@ -80,16 +82,16 @@ static void handle_pointer_motion(struct sway_seat *seat, uint32_t time_msec) {
80 82
81 if (e->h_con) { 83 if (e->h_con) {
82 if (e->edge & WLR_EDGE_LEFT) { 84 if (e->edge & WLR_EDGE_LEFT) {
83 amount_x = (e->h_con_orig_width - moved_x) - e->h_con->width; 85 amount_x = (e->h_con_orig_width - moved_x) - e->h_con->pending.width;
84 } else if (e->edge & WLR_EDGE_RIGHT) { 86 } else if (e->edge & WLR_EDGE_RIGHT) {
85 amount_x = (e->h_con_orig_width + moved_x) - e->h_con->width; 87 amount_x = (e->h_con_orig_width + moved_x) - e->h_con->pending.width;
86 } 88 }
87 } 89 }
88 if (e->v_con) { 90 if (e->v_con) {
89 if (e->edge & WLR_EDGE_TOP) { 91 if (e->edge & WLR_EDGE_TOP) {
90 amount_y = (e->v_con_orig_height - moved_y) - e->v_con->height; 92 amount_y = (e->v_con_orig_height - moved_y) - e->v_con->pending.height;
91 } else if (e->edge & WLR_EDGE_BOTTOM) { 93 } else if (e->edge & WLR_EDGE_BOTTOM) {
92 amount_y = (e->v_con_orig_height + moved_y) - e->v_con->height; 94 amount_y = (e->v_con_orig_height + moved_y) - e->v_con->pending.height;
93 } 95 }
94 } 96 }
95 97
@@ -99,6 +101,7 @@ static void handle_pointer_motion(struct sway_seat *seat, uint32_t time_msec) {
99 if (amount_y != 0) { 101 if (amount_y != 0) {
100 container_resize_tiled(e->v_con, e->edge_y, amount_y); 102 container_resize_tiled(e->v_con, e->edge_y, amount_y);
101 } 103 }
104 transaction_commit_dirty();
102} 105}
103 106
104static void handle_unref(struct sway_seat *seat, struct sway_container *con) { 107static void handle_unref(struct sway_seat *seat, struct sway_container *con) {
@@ -140,7 +143,7 @@ void seatop_begin_resize_tiling(struct sway_seat *seat,
140 if (e->h_con) { 143 if (e->h_con) {
141 container_set_resizing(e->h_con, true); 144 container_set_resizing(e->h_con, true);
142 container_set_resizing(e->h_sib, true); 145 container_set_resizing(e->h_sib, true);
143 e->h_con_orig_width = e->h_con->width; 146 e->h_con_orig_width = e->h_con->pending.width;
144 } 147 }
145 } 148 }
146 if (edge & (WLR_EDGE_TOP | WLR_EDGE_BOTTOM)) { 149 if (edge & (WLR_EDGE_TOP | WLR_EDGE_BOTTOM)) {
@@ -151,12 +154,13 @@ void seatop_begin_resize_tiling(struct sway_seat *seat,
151 if (e->v_con) { 154 if (e->v_con) {
152 container_set_resizing(e->v_con, true); 155 container_set_resizing(e->v_con, true);
153 container_set_resizing(e->v_sib, true); 156 container_set_resizing(e->v_sib, true);
154 e->v_con_orig_height = e->v_con->height; 157 e->v_con_orig_height = e->v_con->pending.height;
155 } 158 }
156 } 159 }
157 160
158 seat->seatop_impl = &seatop_impl; 161 seat->seatop_impl = &seatop_impl;
159 seat->seatop_data = e; 162 seat->seatop_data = e;
160 163
164 transaction_commit_dirty();
161 wlr_seat_pointer_notify_clear_focus(seat->wlr_seat); 165 wlr_seat_pointer_notify_clear_focus(seat->wlr_seat);
162} 166}
diff --git a/sway/input/switch.c b/sway/input/switch.c
index b7c28df1..9ea87a1a 100644
--- a/sway/input/switch.c
+++ b/sway/input/switch.c
@@ -1,5 +1,4 @@
1#include "sway/config.h" 1#include "sway/config.h"
2#include "sway/desktop/transaction.h"
3#include "sway/input/switch.h" 2#include "sway/input/switch.h"
4#include <wlr/types/wlr_idle.h> 3#include <wlr/types/wlr_idle.h>
5#include "log.h" 4#include "log.h"
@@ -61,9 +60,6 @@ static void execute_binding(struct sway_switch *sway_switch) {
61 seat_execute_command(seat, dummy_binding); 60 seat_execute_command(seat, dummy_binding);
62 free(dummy_binding); 61 free(dummy_binding);
63 } 62 }
64
65 transaction_commit_dirty();
66
67} 63}
68 64
69static void handle_switch_toggle(struct wl_listener *listener, void *data) { 65static void handle_switch_toggle(struct wl_listener *listener, void *data) {
diff --git a/sway/input/text_input.c b/sway/input/text_input.c
index f83726ee..b8c19c17 100644
--- a/sway/input/text_input.c
+++ b/sway/input/text_input.c
@@ -55,6 +55,37 @@ static void handle_im_commit(struct wl_listener *listener, void *data) {
55 wlr_text_input_v3_send_done(text_input->input); 55 wlr_text_input_v3_send_done(text_input->input);
56} 56}
57 57
58static void handle_im_keyboard_grab_destroy(struct wl_listener *listener, void *data) {
59 struct sway_input_method_relay *relay = wl_container_of(listener, relay,
60 input_method_keyboard_grab_destroy);
61 struct wlr_input_method_keyboard_grab_v2 *keyboard_grab = data;
62 wl_list_remove(&relay->input_method_keyboard_grab_destroy.link);
63
64 if (keyboard_grab->keyboard) {
65 // send modifier state to original client
66 wlr_seat_keyboard_notify_modifiers(keyboard_grab->input_method->seat,
67 &keyboard_grab->keyboard->modifiers);
68 }
69}
70
71static void handle_im_grab_keyboard(struct wl_listener *listener, void *data) {
72 struct sway_input_method_relay *relay = wl_container_of(listener, relay,
73 input_method_grab_keyboard);
74 struct wlr_input_method_keyboard_grab_v2 *keyboard_grab = data;
75
76 // send modifier state to grab
77 struct wlr_keyboard *active_keyboard = wlr_seat_get_keyboard(relay->seat->wlr_seat);
78 wlr_input_method_keyboard_grab_v2_set_keyboard(keyboard_grab,
79 active_keyboard);
80 wlr_input_method_keyboard_grab_v2_send_modifiers(keyboard_grab,
81 &active_keyboard->modifiers);
82
83 wl_signal_add(&keyboard_grab->events.destroy,
84 &relay->input_method_keyboard_grab_destroy);
85 relay->input_method_keyboard_grab_destroy.notify =
86 handle_im_keyboard_grab_destroy;
87}
88
58static void text_input_set_pending_focused_surface( 89static void text_input_set_pending_focused_surface(
59 struct sway_text_input *text_input, struct wlr_surface *surface) { 90 struct sway_text_input *text_input, struct wlr_surface *surface) {
60 wl_list_remove(&text_input->pending_focused_surface_destroy.link); 91 wl_list_remove(&text_input->pending_focused_surface_destroy.link);
@@ -92,13 +123,18 @@ static void relay_send_im_state(struct sway_input_method_relay *relay,
92 return; 123 return;
93 } 124 }
94 // TODO: only send each of those if they were modified 125 // TODO: only send each of those if they were modified
95 wlr_input_method_v2_send_surrounding_text(input_method, 126 if (input->active_features & WLR_TEXT_INPUT_V3_FEATURE_SURROUNDING_TEXT) {
96 input->current.surrounding.text, input->current.surrounding.cursor, 127 wlr_input_method_v2_send_surrounding_text(input_method,
97 input->current.surrounding.anchor); 128 input->current.surrounding.text, input->current.surrounding.cursor,
129 input->current.surrounding.anchor);
130 }
98 wlr_input_method_v2_send_text_change_cause(input_method, 131 wlr_input_method_v2_send_text_change_cause(input_method,
99 input->current.text_change_cause); 132 input->current.text_change_cause);
100 wlr_input_method_v2_send_content_type(input_method, 133 if (input->active_features & WLR_TEXT_INPUT_V3_FEATURE_CONTENT_TYPE) {
101 input->current.content_type.hint, input->current.content_type.purpose); 134 wlr_input_method_v2_send_content_type(input_method,
135 input->current.content_type.hint,
136 input->current.content_type.purpose);
137 }
102 wlr_input_method_v2_send_done(input_method); 138 wlr_input_method_v2_send_done(input_method);
103 // TODO: pass intent, display popup size 139 // TODO: pass intent, display popup size
104} 140}
@@ -144,6 +180,10 @@ static void handle_text_input_disable(struct wl_listener *listener,
144 void *data) { 180 void *data) {
145 struct sway_text_input *text_input = wl_container_of(listener, text_input, 181 struct sway_text_input *text_input = wl_container_of(listener, text_input,
146 text_input_disable); 182 text_input_disable);
183 if (text_input->input->focused_surface == NULL) {
184 sway_log(SWAY_DEBUG, "Disabling text input, but no longer focused");
185 return;
186 }
147 relay_disable_text_input(text_input->relay, text_input); 187 relay_disable_text_input(text_input->relay, text_input);
148} 188}
149 189
@@ -236,6 +276,9 @@ static void relay_handle_input_method(struct wl_listener *listener,
236 wl_signal_add(&relay->input_method->events.commit, 276 wl_signal_add(&relay->input_method->events.commit,
237 &relay->input_method_commit); 277 &relay->input_method_commit);
238 relay->input_method_commit.notify = handle_im_commit; 278 relay->input_method_commit.notify = handle_im_commit;
279 wl_signal_add(&relay->input_method->events.grab_keyboard,
280 &relay->input_method_grab_keyboard);
281 relay->input_method_grab_keyboard.notify = handle_im_grab_keyboard;
239 wl_signal_add(&relay->input_method->events.destroy, 282 wl_signal_add(&relay->input_method->events.destroy,
240 &relay->input_method_destroy); 283 &relay->input_method_destroy);
241 relay->input_method_destroy.notify = handle_im_destroy; 284 relay->input_method_destroy.notify = handle_im_destroy;