diff options
Diffstat (limited to 'sway/input')
-rw-r--r-- | sway/input/cursor.c | 29 | ||||
-rw-r--r-- | sway/input/keyboard.c | 77 | ||||
-rw-r--r-- | sway/input/libinput.c | 23 | ||||
-rw-r--r-- | sway/input/seat.c | 89 | ||||
-rw-r--r-- | sway/input/seatop_default.c | 43 | ||||
-rw-r--r-- | sway/input/seatop_down.c | 2 | ||||
-rw-r--r-- | sway/input/seatop_move_floating.c | 10 | ||||
-rw-r--r-- | sway/input/seatop_move_tiling.c | 170 | ||||
-rw-r--r-- | sway/input/seatop_resize_floating.c | 36 | ||||
-rw-r--r-- | sway/input/seatop_resize_tiling.c | 28 | ||||
-rw-r--r-- | sway/input/switch.c | 4 | ||||
-rw-r--r-- | sway/input/text_input.c | 53 |
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 | ||
389 | static void handle_pointer_motion_absolute( | 387 | static 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 | ||
407 | void dispatch_cursor_button(struct sway_cursor *cursor, | 404 | void 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 | ||
437 | void dispatch_cursor_axis(struct sway_cursor *cursor, | 433 | void 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 | ||
450 | static void handle_pointer_frame(struct wl_listener *listener, void *data) { | 445 | static 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 | ||
646 | static void handle_tool_axis(struct wl_listener *listener, void *data) { | 636 | static 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 | */ | ||
389 | static 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 | |||
382 | static void handle_key_event(struct sway_keyboard *keyboard, | 403 | static 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 | |||
317 | bool 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 | ||
670 | static 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 | */ | ||
678 | static 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 | |||
694 | static 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 | |||
669 | static void seat_apply_input_config(struct sway_seat *seat, | 704 | static 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 | ||
10 | struct seatop_down_event { | 11 | struct 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 | ||
45 | static void handle_unref(struct sway_seat *seat, struct sway_container *con) { | 48 | static 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 | |||
18 | struct seatop_move_tiling_event { | 23 | struct 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 | ||
27 | static void handle_render(struct sway_seat *seat, | 34 | static 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 | ||
101 | static 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 | |||
130 | static 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 | |||
94 | static void handle_motion_postthreshold(struct sway_seat *seat) { | 168 | static 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 | ||
219 | static bool is_parallel(enum sway_container_layout layout, | 320 | static 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 | ||
138 | static void handle_unref(struct sway_seat *seat, struct sway_container *con) { | 141 | static 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 | ||
104 | static void handle_unref(struct sway_seat *seat, struct sway_container *con) { | 107 | static 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 | ||
69 | static void handle_switch_toggle(struct wl_listener *listener, void *data) { | 65 | static 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 | ||
58 | static 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 | |||
71 | static 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 | |||
58 | static void text_input_set_pending_focused_surface( | 89 | static 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; |