aboutsummaryrefslogtreecommitdiffstats
path: root/sway/input/cursor.c
diff options
context:
space:
mode:
Diffstat (limited to 'sway/input/cursor.c')
-rw-r--r--sway/input/cursor.c680
1 files changed, 45 insertions, 635 deletions
diff --git a/sway/input/cursor.c b/sway/input/cursor.c
index 011b4929..61084447 100644
--- a/sway/input/cursor.c
+++ b/sway/input/cursor.c
@@ -158,132 +158,9 @@ struct sway_node *node_at_coords(
158 return &ws->node; 158 return &ws->node;
159} 159}
160 160
161/**
162 * Determine if the edge of the given container is on the edge of the
163 * workspace/output.
164 */
165static bool edge_is_external(struct sway_container *cont, enum wlr_edges edge) {
166 enum sway_container_layout layout = L_NONE;
167 switch (edge) {
168 case WLR_EDGE_TOP:
169 case WLR_EDGE_BOTTOM:
170 layout = L_VERT;
171 break;
172 case WLR_EDGE_LEFT:
173 case WLR_EDGE_RIGHT:
174 layout = L_HORIZ;
175 break;
176 case WLR_EDGE_NONE:
177 sway_assert(false, "Never reached");
178 return false;
179 }
180
181 // Iterate the parents until we find one with the layout we want,
182 // then check if the child has siblings between it and the edge.
183 while (cont) {
184 if (container_parent_layout(cont) == layout) {
185 list_t *siblings = container_get_siblings(cont);
186 int index = list_find(siblings, cont);
187 if (index > 0 && (edge == WLR_EDGE_LEFT || edge == WLR_EDGE_TOP)) {
188 return false;
189 }
190 if (index < siblings->length - 1 &&
191 (edge == WLR_EDGE_RIGHT || edge == WLR_EDGE_BOTTOM)) {
192 return false;
193 }
194 }
195 cont = cont->parent;
196 }
197 return true;
198}
199
200static enum wlr_edges find_edge(struct sway_container *cont,
201 struct sway_cursor *cursor) {
202 if (!cont->view) {
203 return WLR_EDGE_NONE;
204 }
205 if (cont->border == B_NONE || !cont->border_thickness ||
206 cont->border == B_CSD) {
207 return WLR_EDGE_NONE;
208 }
209
210 enum wlr_edges edge = 0;
211 if (cursor->cursor->x < cont->x + cont->border_thickness) {
212 edge |= WLR_EDGE_LEFT;
213 }
214 if (cursor->cursor->y < cont->y + cont->border_thickness) {
215 edge |= WLR_EDGE_TOP;
216 }
217 if (cursor->cursor->x >= cont->x + cont->width - cont->border_thickness) {
218 edge |= WLR_EDGE_RIGHT;
219 }
220 if (cursor->cursor->y >= cont->y + cont->height - cont->border_thickness) {
221 edge |= WLR_EDGE_BOTTOM;
222 }
223
224 return edge;
225}
226
227/**
228 * If the cursor is over a _resizable_ edge, return the edge.
229 * Edges that can't be resized are edges of the workspace.
230 */
231static enum wlr_edges find_resize_edge(struct sway_container *cont,
232 struct sway_cursor *cursor) {
233 enum wlr_edges edge = find_edge(cont, cursor);
234 if (edge && !container_is_floating(cont) && edge_is_external(cont, edge)) {
235 return WLR_EDGE_NONE;
236 }
237 return edge;
238}
239
240static void cursor_do_rebase(struct sway_cursor *cursor, uint32_t time_msec,
241 struct sway_node *node, struct wlr_surface *surface,
242 double sx, double sy) {
243 // Handle cursor image
244 if (surface) {
245 // Reset cursor if switching between clients
246 struct wl_client *client = wl_resource_get_client(surface->resource);
247 if (client != cursor->image_client) {
248 cursor_set_image(cursor, "left_ptr", client);
249 }
250 } else if (node && node->type == N_CONTAINER) {
251 // Try a node's resize edge
252 enum wlr_edges edge = find_resize_edge(node->sway_container, cursor);
253 if (edge == WLR_EDGE_NONE) {
254 cursor_set_image(cursor, "left_ptr", NULL);
255 } else if (container_is_floating(node->sway_container)) {
256 cursor_set_image(cursor, wlr_xcursor_get_resize_name(edge), NULL);
257 } else {
258 if (edge & (WLR_EDGE_LEFT | WLR_EDGE_RIGHT)) {
259 cursor_set_image(cursor, "col-resize", NULL);
260 } else {
261 cursor_set_image(cursor, "row-resize", NULL);
262 }
263 }
264 } else {
265 cursor_set_image(cursor, "left_ptr", NULL);
266 }
267
268 // Send pointer enter/leave
269 struct wlr_seat *wlr_seat = cursor->seat->wlr_seat;
270 if (surface) {
271 if (seat_is_input_allowed(cursor->seat, surface)) {
272 wlr_seat_pointer_notify_enter(wlr_seat, surface, sx, sy);
273 wlr_seat_pointer_notify_motion(wlr_seat, time_msec, sx, sy);
274 }
275 } else {
276 wlr_seat_pointer_clear_focus(wlr_seat);
277 }
278}
279
280void cursor_rebase(struct sway_cursor *cursor) { 161void cursor_rebase(struct sway_cursor *cursor) {
281 uint32_t time_msec = get_current_time_msec(); 162 uint32_t time_msec = get_current_time_msec();
282 struct wlr_surface *surface = NULL; 163 seatop_rebase(cursor->seat, time_msec);
283 double sx = 0.0, sy = 0.0;
284 cursor->previous.node = node_at_coords(cursor->seat,
285 cursor->cursor->x, cursor->cursor->y, &surface, &sx, &sy);
286 cursor_do_rebase(cursor, time_msec, cursor->previous.node, surface, sx, sy);
287} 164}
288 165
289void cursor_rebase_all(void) { 166void cursor_rebase_all(void) {
@@ -293,9 +170,7 @@ void cursor_rebase_all(void) {
293 170
294 struct sway_seat *seat; 171 struct sway_seat *seat;
295 wl_list_for_each(seat, &server.input->seats, link) { 172 wl_list_for_each(seat, &server.input->seats, link) {
296 if (!seat_doing_seatop(seat)) { 173 cursor_rebase(seat->cursor);
297 cursor_rebase(seat->cursor);
298 }
299 } 174 }
300} 175}
301 176
@@ -345,90 +220,17 @@ void cursor_unhide(struct sway_cursor *cursor) {
345 cursor_rebase(cursor); 220 cursor_rebase(cursor);
346} 221}
347 222
348void cursor_send_pointer_motion(struct sway_cursor *cursor, uint32_t time_msec, 223static void cursor_motion(struct sway_cursor *cursor, uint32_t time_msec,
349 struct sway_node *node, struct wlr_surface *surface, 224 struct wlr_input_device *device, double dx, double dy,
350 double sx, double sy) { 225 double dx_unaccel, double dy_unaccel) {
351 if (time_msec == 0) {
352 time_msec = get_current_time_msec();
353 }
354
355 struct sway_seat *seat = cursor->seat;
356
357 if (seat_doing_seatop(seat)) {
358 seatop_motion(seat, time_msec);
359 cursor->previous.x = cursor->cursor->x;
360 cursor->previous.y = cursor->cursor->y;
361 return;
362 }
363
364 struct sway_node *prev_node = cursor->previous.node;
365
366 // Update the stored previous position
367 cursor->previous.x = cursor->cursor->x;
368 cursor->previous.y = cursor->cursor->y;
369 cursor->previous.node = node;
370
371 if (node && (config->focus_follows_mouse == FOLLOWS_YES ||
372 config->focus_follows_mouse == FOLLOWS_ALWAYS)) {
373 struct sway_node *focus = seat_get_focus(seat);
374 if (focus && node->type == N_WORKSPACE) {
375 // Only follow the mouse if it would move to a new output
376 // Otherwise we'll focus the workspace, which is probably wrong
377 struct sway_output *focused_output = node_get_output(focus);
378 struct sway_output *output = node_get_output(node);
379 if (output != focused_output) {
380 seat_set_focus(seat, seat_get_focus_inactive(seat, node));
381 }
382 } else if (node->type == N_CONTAINER && node->sway_container->view) {
383 // Focus node if the following are true:
384 // - cursor is over a new view, i.e. entered a new window; and
385 // - the new view is visible, i.e. not hidden in a stack or tab; and
386 // - the seat does not have a keyboard grab
387 if ((!wlr_seat_keyboard_has_grab(cursor->seat->wlr_seat) &&
388 node != prev_node &&
389 view_is_visible(node->sway_container->view)) ||
390 config->focus_follows_mouse == FOLLOWS_ALWAYS) {
391 seat_set_focus(seat, node);
392 } else {
393 struct sway_node *next_focus =
394 seat_get_focus_inactive(seat, &root->node);
395 if (next_focus && next_focus->type == N_CONTAINER &&
396 next_focus->sway_container->view &&
397 view_is_visible(next_focus->sway_container->view)) {
398 seat_set_focus(seat, next_focus);
399 }
400 }
401 }
402 }
403
404 cursor_do_rebase(cursor, time_msec, node, surface, sx, sy);
405
406 struct sway_drag_icon *drag_icon;
407 wl_list_for_each(drag_icon, &root->drag_icons, link) {
408 if (drag_icon->seat == seat) {
409 drag_icon_update_position(drag_icon);
410 }
411 }
412}
413
414static void handle_cursor_motion(struct wl_listener *listener, void *data) {
415 struct sway_cursor *cursor = wl_container_of(listener, cursor, motion);
416 struct wlr_event_pointer_motion *event = data;
417 cursor_handle_activity(cursor); 226 cursor_handle_activity(cursor);
418 227
419 double dx = event->delta_x;
420 double dy = event->delta_y;
421
422 double dx_unaccel = event->unaccel_dx;
423 double dy_unaccel = event->unaccel_dy;
424
425 wlr_relative_pointer_manager_v1_send_relative_motion( 228 wlr_relative_pointer_manager_v1_send_relative_motion(
426 server.relative_pointer_manager, 229 server.relative_pointer_manager,
427 cursor->seat->wlr_seat, (uint64_t)event->time_msec * 1000, 230 cursor->seat->wlr_seat, (uint64_t)time_msec * 1000,
428 dx, dy, dx_unaccel, dy_unaccel); 231 dx, dy, dx_unaccel, dy_unaccel);
429 232
430 struct wlr_surface *surface = NULL; 233 struct wlr_surface *surface = NULL;
431 struct sway_node *node = NULL;
432 double sx, sy; 234 double sx, sy;
433 if (cursor->active_constraint) { 235 if (cursor->active_constraint) {
434 node_at_coords(cursor->seat, 236 node_at_coords(cursor->seat,
@@ -448,50 +250,18 @@ static void handle_cursor_motion(struct wl_listener *listener, void *data) {
448 dy = sy_confined - sy; 250 dy = sy_confined - sy;
449 } 251 }
450 252
451 wlr_cursor_move(cursor->cursor, event->device, dx, dy); 253 wlr_cursor_move(cursor->cursor, device, dx, dy);
452
453 // Recalculate pointer location after layout checks
454 node = node_at_coords(cursor->seat,
455 cursor->cursor->x, cursor->cursor->y, &surface, &sx, &sy);
456 254
457 cursor_send_pointer_motion(cursor, event->time_msec, node, surface, 255 seatop_motion(cursor->seat, time_msec, dx, dy);
458 sx, sy);
459 transaction_commit_dirty();
460} 256}
461 257
462static void cursor_motion_absolute(struct sway_cursor *cursor, 258static void handle_cursor_motion_relative(
463 uint32_t time_msec, struct wlr_input_device *dev, 259 struct wl_listener *listener, void *data) {
464 double x, double y) { 260 struct sway_cursor *cursor = wl_container_of(listener, cursor, motion);
465 cursor_handle_activity(cursor); 261 struct wlr_event_pointer_motion *e = data;
466
467 double lx, ly;
468 wlr_cursor_absolute_to_layout_coords(cursor->cursor, dev,
469 x, y, &lx, &ly);
470
471 double dx = lx - cursor->cursor->x;
472 double dy = ly - cursor->cursor->y;
473 wlr_relative_pointer_manager_v1_send_relative_motion(
474 server.relative_pointer_manager,
475 cursor->seat->wlr_seat, (uint64_t)time_msec * 1000,
476 dx, dy, dx, dy);
477
478 struct wlr_surface *surface = NULL;
479 double sx = 0.0, sy = 0.0;
480 struct sway_node *node = node_at_coords(cursor->seat,
481 lx, ly, &surface, &sx, &sy);
482
483 if (cursor->active_constraint) {
484 if (cursor->active_constraint->surface != surface) {
485 return;
486 }
487 if (!pixman_region32_contains_point(&cursor->confine,
488 floor(sx), floor(sy), NULL)) {
489 return;
490 }
491 }
492 262
493 wlr_cursor_warp_closest(cursor->cursor, dev, lx, ly); 263 cursor_motion(cursor, e->time_msec, e->device, e->delta_x, e->delta_y,
494 cursor_send_pointer_motion(cursor, time_msec, node, surface, sx, sy); 264 e->unaccel_dx, e->unaccel_dy);
495 transaction_commit_dirty(); 265 transaction_commit_dirty();
496} 266}
497 267
@@ -501,98 +271,15 @@ static void handle_cursor_motion_absolute(
501 wl_container_of(listener, cursor, motion_absolute); 271 wl_container_of(listener, cursor, motion_absolute);
502 struct wlr_event_pointer_motion_absolute *event = data; 272 struct wlr_event_pointer_motion_absolute *event = data;
503 273
504 cursor_motion_absolute(cursor, event->time_msec, event->device, 274 double lx, ly;
505 event->x, event->y); 275 wlr_cursor_absolute_to_layout_coords(cursor->cursor, event->device,
506} 276 event->x, event->y, &lx, &ly);
507
508/**
509 * Remove a button (and duplicates) to the sorted list of currently pressed buttons
510 */
511static void state_erase_button(struct sway_cursor *cursor, uint32_t button) {
512 size_t j = 0;
513 for (size_t i = 0; i < cursor->pressed_button_count; ++i) {
514 if (i > j) {
515 cursor->pressed_buttons[j] = cursor->pressed_buttons[i];
516 }
517 if (cursor->pressed_buttons[i] != button) {
518 ++j;
519 }
520 }
521 while (cursor->pressed_button_count > j) {
522 --cursor->pressed_button_count;
523 cursor->pressed_buttons[cursor->pressed_button_count] = 0;
524 }
525}
526
527/**
528 * Add a button to the sorted list of currently pressed buttons, if there
529 * is space.
530 */
531static void state_add_button(struct sway_cursor *cursor, uint32_t button) {
532 if (cursor->pressed_button_count >= SWAY_CURSOR_PRESSED_BUTTONS_CAP) {
533 return;
534 }
535 size_t i = 0;
536 while (i < cursor->pressed_button_count && cursor->pressed_buttons[i] < button) {
537 ++i;
538 }
539 size_t j = cursor->pressed_button_count;
540 while (j > i) {
541 cursor->pressed_buttons[j] = cursor->pressed_buttons[j - 1];
542 --j;
543 }
544 cursor->pressed_buttons[i] = button;
545 cursor->pressed_button_count++;
546}
547
548/**
549 * Return the mouse binding which matches modifier, click location, release,
550 * and pressed button state, otherwise return null.
551 */
552static struct sway_binding* get_active_mouse_binding(
553 const struct sway_cursor *cursor, list_t *bindings, uint32_t modifiers,
554 bool release, bool on_titlebar, bool on_border, bool on_content,
555 bool on_workspace, const char *identifier) {
556 uint32_t click_region =
557 ((on_titlebar || on_workspace) ? BINDING_TITLEBAR : 0) |
558 ((on_border || on_workspace) ? BINDING_BORDER : 0) |
559 ((on_content || on_workspace) ? BINDING_CONTENTS : 0);
560
561 struct sway_binding *current = NULL;
562 for (int i = 0; i < bindings->length; ++i) {
563 struct sway_binding *binding = bindings->items[i];
564 if (modifiers ^ binding->modifiers ||
565 cursor->pressed_button_count != (size_t)binding->keys->length ||
566 release != (binding->flags & BINDING_RELEASE) ||
567 !(click_region & binding->flags) ||
568 (on_workspace &&
569 (click_region & binding->flags) != click_region) ||
570 (strcmp(binding->input, identifier) != 0 &&
571 strcmp(binding->input, "*") != 0)) {
572 continue;
573 }
574 277
575 bool match = true; 278 double dx = lx - cursor->cursor->x;
576 for (size_t j = 0; j < cursor->pressed_button_count; j++) { 279 double dy = ly - cursor->cursor->y;
577 uint32_t key = *(uint32_t *)binding->keys->items[j];
578 if (key != cursor->pressed_buttons[j]) {
579 match = false;
580 break;
581 }
582 }
583 if (!match) {
584 continue;
585 }
586 280
587 if (!current || strcmp(current->input, "*") == 0) { 281 cursor_motion(cursor, event->time_msec, event->device, dx, dy, dx, dy);
588 current = binding; 282 transaction_commit_dirty();
589 if (strcmp(current->input, identifier) == 0) {
590 // If a binding is found for the exact input, quit searching
591 break;
592 }
593 }
594 }
595 return current;
596} 283}
597 284
598void dispatch_cursor_button(struct sway_cursor *cursor, 285void dispatch_cursor_button(struct sway_cursor *cursor,
@@ -601,318 +288,33 @@ void dispatch_cursor_button(struct sway_cursor *cursor,
601 if (time_msec == 0) { 288 if (time_msec == 0) {
602 time_msec = get_current_time_msec(); 289 time_msec = get_current_time_msec();
603 } 290 }
604 struct sway_seat *seat = cursor->seat;
605 291
606 // Handle existing seat operation 292 seatop_button(cursor->seat, time_msec, device, button, state);
607 if (seat_doing_seatop(seat)) {
608 if (state == WLR_BUTTON_PRESSED) {
609 state_add_button(cursor, button);
610 } else {
611 state_erase_button(cursor, button);
612 }
613 seatop_button(seat, time_msec, device, button, state);
614 if (button == seat->seatop_button && state == WLR_BUTTON_RELEASED) {
615 seatop_finish(seat, time_msec);
616 }
617 return;
618 }
619
620 // Determine what's under the cursor
621 struct wlr_surface *surface = NULL;
622 double sx, sy;
623 struct sway_node *node = node_at_coords(seat,
624 cursor->cursor->x, cursor->cursor->y, &surface, &sx, &sy);
625 struct sway_container *cont = node && node->type == N_CONTAINER ?
626 node->sway_container : NULL;
627 bool is_floating = cont && container_is_floating(cont);
628 bool is_floating_or_child = cont && container_is_floating_or_child(cont);
629 bool is_fullscreen_or_child = cont && container_is_fullscreen_or_child(cont);
630 enum wlr_edges edge = cont ? find_edge(cont, cursor) : WLR_EDGE_NONE;
631 enum wlr_edges resize_edge = edge ?
632 find_resize_edge(cont, cursor) : WLR_EDGE_NONE;
633 bool on_border = edge != WLR_EDGE_NONE;
634 bool on_contents = cont && !on_border && surface;
635 bool on_workspace = node && node->type == N_WORKSPACE;
636 bool on_titlebar = cont && !on_border && !surface;
637
638 // Handle mouse bindings
639 struct wlr_keyboard *keyboard = wlr_seat_get_keyboard(seat->wlr_seat);
640 uint32_t modifiers = keyboard ? wlr_keyboard_get_modifiers(keyboard) : 0;
641
642 char *device_identifier = device ? input_device_get_identifier(device)
643 : strdup("*");
644 struct sway_binding *binding = NULL;
645 if (state == WLR_BUTTON_PRESSED) {
646 state_add_button(cursor, button);
647 binding = get_active_mouse_binding(cursor,
648 config->current_mode->mouse_bindings, modifiers, false,
649 on_titlebar, on_border, on_contents, on_workspace,
650 device_identifier);
651 } else {
652 binding = get_active_mouse_binding(cursor,
653 config->current_mode->mouse_bindings, modifiers, true,
654 on_titlebar, on_border, on_contents, on_workspace,
655 device_identifier);
656 state_erase_button(cursor, button);
657 }
658 free(device_identifier);
659 if (binding) {
660 seat_execute_command(seat, binding);
661 return;
662 }
663
664 // Handle clicking an empty workspace
665 if (node && node->type == N_WORKSPACE) {
666 seat_set_focus(seat, node);
667 return;
668 }
669
670 // Handle clicking a layer surface
671 if (surface && wlr_surface_is_layer_surface(surface)) {
672 struct wlr_layer_surface_v1 *layer =
673 wlr_layer_surface_v1_from_wlr_surface(surface);
674 if (layer->current.keyboard_interactive) {
675 seat_set_focus_layer(seat, layer);
676 }
677 seat_pointer_notify_button(seat, time_msec, button, state);
678 return;
679 }
680
681 // Handle tiling resize via border
682 if (cont && resize_edge && button == BTN_LEFT &&
683 state == WLR_BUTTON_PRESSED && !is_floating) {
684 seat_set_focus_container(seat, cont);
685 seatop_begin_resize_tiling(seat, cont, button, edge);
686 return;
687 }
688
689 // Handle tiling resize via mod
690 bool mod_pressed = keyboard &&
691 (wlr_keyboard_get_modifiers(keyboard) & config->floating_mod);
692 if (cont && !is_floating_or_child && mod_pressed &&
693 state == WLR_BUTTON_PRESSED) {
694 uint32_t btn_resize = config->floating_mod_inverse ?
695 BTN_LEFT : BTN_RIGHT;
696 if (button == btn_resize) {
697 edge = 0;
698 edge |= cursor->cursor->x > cont->x + cont->width / 2 ?
699 WLR_EDGE_RIGHT : WLR_EDGE_LEFT;
700 edge |= cursor->cursor->y > cont->y + cont->height / 2 ?
701 WLR_EDGE_BOTTOM : WLR_EDGE_TOP;
702
703 const char *image = NULL;
704 if (edge == (WLR_EDGE_LEFT | WLR_EDGE_TOP)) {
705 image = "nw-resize";
706 } else if (edge == (WLR_EDGE_TOP | WLR_EDGE_RIGHT)) {
707 image = "ne-resize";
708 } else if (edge == (WLR_EDGE_RIGHT | WLR_EDGE_BOTTOM)) {
709 image = "se-resize";
710 } else if (edge == (WLR_EDGE_BOTTOM | WLR_EDGE_LEFT)) {
711 image = "sw-resize";
712 }
713 cursor_set_image(seat->cursor, image, NULL);
714 seat_set_focus_container(seat, cont);
715 seatop_begin_resize_tiling(seat, cont, button, edge);
716 return;
717 }
718 }
719
720 // Handle beginning floating move
721 if (cont && is_floating_or_child && !is_fullscreen_or_child &&
722 state == WLR_BUTTON_PRESSED) {
723 uint32_t btn_move = config->floating_mod_inverse ? BTN_RIGHT : BTN_LEFT;
724 if (button == btn_move && state == WLR_BUTTON_PRESSED &&
725 (mod_pressed || on_titlebar)) {
726 while (cont->parent) {
727 cont = cont->parent;
728 }
729 seat_set_focus_container(seat, cont);
730 seatop_begin_move_floating(seat, cont, button);
731 return;
732 }
733 }
734
735 // Handle beginning floating resize
736 if (cont && is_floating_or_child && !is_fullscreen_or_child &&
737 state == WLR_BUTTON_PRESSED) {
738 // Via border
739 if (button == BTN_LEFT && resize_edge != WLR_EDGE_NONE) {
740 seatop_begin_resize_floating(seat, cont, button, resize_edge);
741 return;
742 }
743
744 // Via mod+click
745 uint32_t btn_resize = config->floating_mod_inverse ?
746 BTN_LEFT : BTN_RIGHT;
747 if (mod_pressed && button == btn_resize) {
748 struct sway_container *floater = cont;
749 while (floater->parent) {
750 floater = floater->parent;
751 }
752 edge = 0;
753 edge |= cursor->cursor->x > floater->x + floater->width / 2 ?
754 WLR_EDGE_RIGHT : WLR_EDGE_LEFT;
755 edge |= cursor->cursor->y > floater->y + floater->height / 2 ?
756 WLR_EDGE_BOTTOM : WLR_EDGE_TOP;
757 seatop_begin_resize_floating(seat, floater, button, edge);
758 return;
759 }
760 }
761
762 // Handle moving a tiling container
763 if (config->tiling_drag && (mod_pressed || on_titlebar) &&
764 state == WLR_BUTTON_PRESSED && !is_floating_or_child &&
765 cont && cont->fullscreen_mode == FULLSCREEN_NONE) {
766 struct sway_container *focus = seat_get_focused_container(seat);
767 bool focused = focus == cont || container_has_ancestor(focus, cont);
768 if (on_titlebar && !focused) {
769 node = seat_get_focus_inactive(seat, &cont->node);
770 seat_set_focus(seat, node);
771 }
772
773 // If moving a container by it's title bar, use a threshold for the drag
774 if (!mod_pressed && config->tiling_drag_threshold > 0) {
775 seatop_begin_move_tiling_threshold(seat, cont, button);
776 } else {
777 seatop_begin_move_tiling(seat, cont, button);
778 }
779 return;
780 }
781
782 // Handle mousedown on a container surface
783 if (surface && cont && state == WLR_BUTTON_PRESSED) {
784 seat_set_focus_container(seat, cont);
785 seatop_begin_down(seat, cont, time_msec, button, sx, sy);
786 seat_pointer_notify_button(seat, time_msec, button, WLR_BUTTON_PRESSED);
787 return;
788 }
789
790 // Handle clicking a container surface or decorations
791 if (cont) {
792 node = seat_get_focus_inactive(seat, &cont->node);
793 seat_set_focus(seat, node);
794 seat_pointer_notify_button(seat, time_msec, button, state);
795 return;
796 }
797
798 seat_pointer_notify_button(seat, time_msec, button, state);
799} 293}
800 294
801static void handle_cursor_button(struct wl_listener *listener, void *data) { 295static void handle_cursor_button(struct wl_listener *listener, void *data) {
802 struct sway_cursor *cursor = wl_container_of(listener, cursor, button); 296 struct sway_cursor *cursor = wl_container_of(listener, cursor, button);
803 struct wlr_event_pointer_button *event = data; 297 struct wlr_event_pointer_button *event = data;
804 cursor_handle_activity(cursor); 298 cursor_handle_activity(cursor);
299
300 if (event->state == WLR_BUTTON_PRESSED) {
301 cursor->pressed_button_count++;
302 } else {
303 if (cursor->pressed_button_count > 0) {
304 cursor->pressed_button_count--;
305 } else {
306 sway_log(SWAY_ERROR, "Pressed button count was wrong");
307 }
308 }
309
805 dispatch_cursor_button(cursor, event->device, 310 dispatch_cursor_button(cursor, event->device,
806 event->time_msec, event->button, event->state); 311 event->time_msec, event->button, event->state);
807 transaction_commit_dirty(); 312 transaction_commit_dirty();
808} 313}
809 314
810static uint32_t wl_axis_to_button(struct wlr_event_pointer_axis *event) {
811 switch (event->orientation) {
812 case WLR_AXIS_ORIENTATION_VERTICAL:
813 return event->delta < 0 ? SWAY_SCROLL_UP : SWAY_SCROLL_DOWN;
814 case WLR_AXIS_ORIENTATION_HORIZONTAL:
815 return event->delta < 0 ? SWAY_SCROLL_LEFT : SWAY_SCROLL_RIGHT;
816 default:
817 sway_log(SWAY_DEBUG, "Unknown axis orientation");
818 return 0;
819 }
820}
821
822void dispatch_cursor_axis(struct sway_cursor *cursor, 315void dispatch_cursor_axis(struct sway_cursor *cursor,
823 struct wlr_event_pointer_axis *event) { 316 struct wlr_event_pointer_axis *event) {
824 struct sway_seat *seat = cursor->seat; 317 seatop_axis(cursor->seat, event);
825 struct sway_input_device *input_device =
826 event->device ? event->device->data : NULL;
827 struct input_config *ic =
828 input_device ? input_device_get_config(input_device) : NULL;
829
830 // Determine what's under the cursor
831 struct wlr_surface *surface = NULL;
832 double sx, sy;
833 struct sway_node *node = node_at_coords(seat,
834 cursor->cursor->x, cursor->cursor->y, &surface, &sx, &sy);
835 struct sway_container *cont = node && node->type == N_CONTAINER ?
836 node->sway_container : NULL;
837 enum wlr_edges edge = cont ? find_edge(cont, cursor) : WLR_EDGE_NONE;
838 bool on_border = edge != WLR_EDGE_NONE;
839 bool on_titlebar = cont && !on_border && !surface;
840 bool on_titlebar_border = cont && on_border &&
841 cursor->cursor->y < cont->content_y;
842 bool on_contents = cont && !on_border && surface;
843 bool on_workspace = node && node->type == N_WORKSPACE;
844 float scroll_factor =
845 (ic == NULL || ic->scroll_factor == FLT_MIN) ? 1.0f : ic->scroll_factor;
846
847 bool handled = false;
848
849 // Gather information needed for mouse bindings
850 struct wlr_keyboard *keyboard = wlr_seat_get_keyboard(seat->wlr_seat);
851 uint32_t modifiers = keyboard ? wlr_keyboard_get_modifiers(keyboard) : 0;
852 struct wlr_input_device *device =
853 input_device ? input_device->wlr_device : NULL;
854 char *dev_id = device ? input_device_get_identifier(device) : strdup("*");
855 uint32_t button = wl_axis_to_button(event);
856
857 // Handle mouse bindings - x11 mouse buttons 4-7 - press event
858 struct sway_binding *binding = NULL;
859 state_add_button(cursor, button);
860 binding = get_active_mouse_binding(cursor,
861 config->current_mode->mouse_bindings, modifiers, false,
862 on_titlebar, on_border, on_contents, on_workspace, dev_id);
863 if (binding) {
864 seat_execute_command(seat, binding);
865 handled = true;
866 }
867
868 // Scrolling on a tabbed or stacked title bar (handled as press event)
869 if (!handled && (on_titlebar || on_titlebar_border)) {
870 enum sway_container_layout layout = container_parent_layout(cont);
871 if (layout == L_TABBED || layout == L_STACKED) {
872 struct sway_node *tabcontainer = node_get_parent(node);
873 struct sway_node *active =
874 seat_get_active_tiling_child(seat, tabcontainer);
875 list_t *siblings = container_get_siblings(cont);
876 int desired = list_find(siblings, active->sway_container) +
877 round(scroll_factor * event->delta_discrete);
878 if (desired < 0) {
879 desired = 0;
880 } else if (desired >= siblings->length) {
881 desired = siblings->length - 1;
882 }
883 struct sway_node *old_focus = seat_get_focus(seat);
884 struct sway_container *new_sibling_con = siblings->items[desired];
885 struct sway_node *new_sibling = &new_sibling_con->node;
886 struct sway_node *new_focus =
887 seat_get_focus_inactive(seat, new_sibling);
888 if (node_has_ancestor(old_focus, tabcontainer)) {
889 seat_set_focus(seat, new_focus);
890 } else {
891 // Scrolling when focus is not in the tabbed container at all
892 seat_set_raw_focus(seat, new_sibling);
893 seat_set_raw_focus(seat, new_focus);
894 seat_set_raw_focus(seat, old_focus);
895 }
896 handled = true;
897 }
898 }
899
900 // Handle mouse bindings - x11 mouse buttons 4-7 - release event
901 binding = get_active_mouse_binding(cursor,
902 config->current_mode->mouse_bindings, modifiers, true,
903 on_titlebar, on_border, on_contents, on_workspace, dev_id);
904 state_erase_button(cursor, button);
905 if (binding) {
906 seat_execute_command(seat, binding);
907 handled = true;
908 }
909 free(dev_id);
910
911 if (!handled) {
912 wlr_seat_pointer_notify_axis(cursor->seat->wlr_seat, event->time_msec,
913 event->orientation, scroll_factor * event->delta,
914 round(scroll_factor * event->delta_discrete), event->source);
915 }
916} 318}
917 319
918static void handle_cursor_axis(struct wl_listener *listener, void *data) { 320static void handle_cursor_axis(struct wl_listener *listener, void *data) {
@@ -1054,8 +456,16 @@ static void handle_tool_axis(struct wl_listener *listener, void *data) {
1054 apply_mapping_from_region(event->device, ic->mapped_from_region, &x, &y); 456 apply_mapping_from_region(event->device, ic->mapped_from_region, &x, &y);
1055 } 457 }
1056 458
1057 cursor_motion_absolute(cursor, event->time_msec, event->device, x, y); 459 double lx, ly;
460 wlr_cursor_absolute_to_layout_coords(cursor->cursor, event->device,
461 x, y, &lx, &ly);
462
463 double dx = lx - cursor->cursor->x;
464 double dy = ly - cursor->cursor->y;
465
466 cursor_motion(cursor, event->time_msec, event->device, dx, dy, dx, dy);
1058 wlr_seat_pointer_notify_frame(cursor->seat->wlr_seat); 467 wlr_seat_pointer_notify_frame(cursor->seat->wlr_seat);
468 transaction_commit_dirty();
1059} 469}
1060 470
1061static void handle_tool_tip(struct wl_listener *listener, void *data) { 471static void handle_tool_tip(struct wl_listener *listener, void *data) {
@@ -1142,7 +552,7 @@ static void handle_request_set_cursor(struct wl_listener *listener,
1142 void *data) { 552 void *data) {
1143 struct sway_cursor *cursor = 553 struct sway_cursor *cursor =
1144 wl_container_of(listener, cursor, request_set_cursor); 554 wl_container_of(listener, cursor, request_set_cursor);
1145 if (seat_doing_seatop(cursor->seat)) { 555 if (!seatop_allows_set_cursor(cursor->seat)) {
1146 return; 556 return;
1147 } 557 }
1148 struct wlr_seat_pointer_request_set_cursor_event *event = data; 558 struct wlr_seat_pointer_request_set_cursor_event *event = data;
@@ -1257,7 +667,7 @@ struct sway_cursor *sway_cursor_create(struct sway_seat *seat) {
1257 667
1258 // input events 668 // input events
1259 wl_signal_add(&wlr_cursor->events.motion, &cursor->motion); 669 wl_signal_add(&wlr_cursor->events.motion, &cursor->motion);
1260 cursor->motion.notify = handle_cursor_motion; 670 cursor->motion.notify = handle_cursor_motion_relative;
1261 671
1262 wl_signal_add(&wlr_cursor->events.motion_absolute, 672 wl_signal_add(&wlr_cursor->events.motion_absolute,
1263 &cursor->motion_absolute); 673 &cursor->motion_absolute);