diff options
Diffstat (limited to 'sway/input/cursor.c')
-rw-r--r-- | sway/input/cursor.c | 235 |
1 files changed, 216 insertions, 19 deletions
diff --git a/sway/input/cursor.c b/sway/input/cursor.c index c84d6c40..c87efc2b 100644 --- a/sway/input/cursor.c +++ b/sway/input/cursor.c | |||
@@ -1,4 +1,5 @@ | |||
1 | #define _POSIX_C_SOURCE 200809L | 1 | #define _POSIX_C_SOURCE 200809L |
2 | #include <assert.h> | ||
2 | #include <math.h> | 3 | #include <math.h> |
3 | #include <libevdev/libevdev.h> | 4 | #include <libevdev/libevdev.h> |
4 | #include <linux/input-event-codes.h> | 5 | #include <linux/input-event-codes.h> |
@@ -6,10 +7,11 @@ | |||
6 | #include <float.h> | 7 | #include <float.h> |
7 | #include <limits.h> | 8 | #include <limits.h> |
8 | #include <strings.h> | 9 | #include <strings.h> |
10 | #include <wlr/types/wlr_box.h> | ||
9 | #include <wlr/types/wlr_cursor.h> | 11 | #include <wlr/types/wlr_cursor.h> |
10 | #include <wlr/types/wlr_xcursor_manager.h> | ||
11 | #include <wlr/types/wlr_idle.h> | 12 | #include <wlr/types/wlr_idle.h> |
12 | #include <wlr/types/wlr_box.h> | 13 | #include <wlr/types/wlr_xcursor_manager.h> |
14 | #include <wlr/util/region.h> | ||
13 | #include "list.h" | 15 | #include "list.h" |
14 | #include "log.h" | 16 | #include "log.h" |
15 | #include "config.h" | 17 | #include "config.h" |
@@ -327,8 +329,9 @@ void cursor_unhide(struct sway_cursor *cursor) { | |||
327 | cursor_rebase(cursor); | 329 | cursor_rebase(cursor); |
328 | } | 330 | } |
329 | 331 | ||
330 | void cursor_send_pointer_motion(struct sway_cursor *cursor, | 332 | void cursor_send_pointer_motion(struct sway_cursor *cursor, uint32_t time_msec, |
331 | uint32_t time_msec) { | 333 | struct sway_node *node, struct wlr_surface *surface, |
334 | double sx, double sy) { | ||
332 | if (time_msec == 0) { | 335 | if (time_msec == 0) { |
333 | time_msec = get_current_time_msec(); | 336 | time_msec = get_current_time_msec(); |
334 | } | 337 | } |
@@ -343,12 +346,7 @@ void cursor_send_pointer_motion(struct sway_cursor *cursor, | |||
343 | return; | 346 | return; |
344 | } | 347 | } |
345 | 348 | ||
346 | struct wlr_surface *surface = NULL; | ||
347 | double sx, sy; | ||
348 | |||
349 | struct sway_node *prev_node = cursor->previous.node; | 349 | struct sway_node *prev_node = cursor->previous.node; |
350 | struct sway_node *node = node_at_coords(seat, | ||
351 | cursor->cursor->x, cursor->cursor->y, &surface, &sx, &sy); | ||
352 | 350 | ||
353 | // Update the stored previous position | 351 | // Update the stored previous position |
354 | cursor->previous.x = cursor->cursor->x; | 352 | cursor->previous.x = cursor->cursor->x; |
@@ -401,9 +399,62 @@ static void handle_cursor_motion(struct wl_listener *listener, void *data) { | |||
401 | struct sway_cursor *cursor = wl_container_of(listener, cursor, motion); | 399 | struct sway_cursor *cursor = wl_container_of(listener, cursor, motion); |
402 | struct wlr_event_pointer_motion *event = data; | 400 | struct wlr_event_pointer_motion *event = data; |
403 | cursor_handle_activity(cursor); | 401 | cursor_handle_activity(cursor); |
404 | wlr_cursor_move(cursor->cursor, event->device, | 402 | |
405 | event->delta_x, event->delta_y); | 403 | double dx = event->delta_x; |
406 | cursor_send_pointer_motion(cursor, event->time_msec); | 404 | double dy = event->delta_y; |
405 | |||
406 | struct wlr_surface *surface = NULL; | ||
407 | double sx, sy; | ||
408 | struct sway_node *node = node_at_coords(cursor->seat, | ||
409 | cursor->cursor->x, cursor->cursor->y, &surface, &sx, &sy); | ||
410 | |||
411 | if (cursor->active_constraint) { | ||
412 | if (cursor->active_constraint->surface != surface) { | ||
413 | return; | ||
414 | } | ||
415 | |||
416 | double sx_confined, sy_confined; | ||
417 | if (!wlr_region_confine(&cursor->confine, sx, sy, sx + dx, sy + dy, | ||
418 | &sx_confined, &sy_confined)) { | ||
419 | return; | ||
420 | } | ||
421 | |||
422 | dx = sx_confined - sx; | ||
423 | dy = sy_confined - sy; | ||
424 | } | ||
425 | |||
426 | wlr_cursor_move(cursor->cursor, event->device, dx, dy); | ||
427 | cursor_send_pointer_motion(cursor, event->time_msec, node, surface, | ||
428 | sx + dx, sy + dy); | ||
429 | transaction_commit_dirty(); | ||
430 | } | ||
431 | |||
432 | static void cursor_motion_absolute(struct sway_cursor *cursor, | ||
433 | uint32_t time_msec, struct wlr_input_device *dev, | ||
434 | double x, double y) { | ||
435 | cursor_handle_activity(cursor); | ||
436 | |||
437 | double lx, ly; | ||
438 | wlr_cursor_absolute_to_layout_coords(cursor->cursor, dev, | ||
439 | x, y, &lx, &ly); | ||
440 | |||
441 | struct wlr_surface *surface = NULL; | ||
442 | double sx, sy; | ||
443 | struct sway_node *node = node_at_coords(cursor->seat, | ||
444 | lx, ly, &surface, &sx, &sy); | ||
445 | |||
446 | if (cursor->active_constraint) { | ||
447 | if (cursor->active_constraint->surface != surface) { | ||
448 | return; | ||
449 | } | ||
450 | if (!pixman_region32_contains_point(&cursor->confine, | ||
451 | floor(sx), floor(sy), NULL)) { | ||
452 | return; | ||
453 | } | ||
454 | } | ||
455 | |||
456 | wlr_cursor_warp_closest(cursor->cursor, dev, lx, ly); | ||
457 | cursor_send_pointer_motion(cursor, time_msec, node, surface, sx, sy); | ||
407 | transaction_commit_dirty(); | 458 | transaction_commit_dirty(); |
408 | } | 459 | } |
409 | 460 | ||
@@ -412,10 +463,9 @@ static void handle_cursor_motion_absolute( | |||
412 | struct sway_cursor *cursor = | 463 | struct sway_cursor *cursor = |
413 | wl_container_of(listener, cursor, motion_absolute); | 464 | wl_container_of(listener, cursor, motion_absolute); |
414 | struct wlr_event_pointer_motion_absolute *event = data; | 465 | struct wlr_event_pointer_motion_absolute *event = data; |
415 | cursor_handle_activity(cursor); | 466 | |
416 | wlr_cursor_warp_absolute(cursor->cursor, event->device, event->x, event->y); | 467 | cursor_motion_absolute(cursor, event->time_msec, event->device, |
417 | cursor_send_pointer_motion(cursor, event->time_msec); | 468 | event->x, event->y); |
418 | transaction_commit_dirty(); | ||
419 | } | 469 | } |
420 | 470 | ||
421 | /** | 471 | /** |
@@ -961,9 +1011,7 @@ static void handle_tool_axis(struct wl_listener *listener, void *data) { | |||
961 | apply_mapping_from_region(event->device, ic->mapped_from_region, &x, &y); | 1011 | apply_mapping_from_region(event->device, ic->mapped_from_region, &x, &y); |
962 | } | 1012 | } |
963 | 1013 | ||
964 | wlr_cursor_warp_absolute(cursor->cursor, event->device, x, y); | 1014 | cursor_motion_absolute(cursor, event->time_msec, event->device, x, y); |
965 | cursor_send_pointer_motion(cursor, event->time_msec); | ||
966 | transaction_commit_dirty(); | ||
967 | } | 1015 | } |
968 | 1016 | ||
969 | static void handle_tool_tip(struct wl_listener *listener, void *data) { | 1017 | static void handle_tool_tip(struct wl_listener *listener, void *data) { |
@@ -1001,6 +1049,49 @@ static void handle_tool_button(struct wl_listener *listener, void *data) { | |||
1001 | transaction_commit_dirty(); | 1049 | transaction_commit_dirty(); |
1002 | } | 1050 | } |
1003 | 1051 | ||
1052 | static void check_constraint_region(struct sway_cursor *cursor) { | ||
1053 | struct wlr_pointer_constraint_v1 *constraint = cursor->active_constraint; | ||
1054 | pixman_region32_t *region = &constraint->region; | ||
1055 | struct sway_view *view = view_from_wlr_surface(constraint->surface); | ||
1056 | if (view) { | ||
1057 | struct sway_container *con = view->container; | ||
1058 | |||
1059 | double sx = cursor->cursor->x - con->content_x + view->geometry.x; | ||
1060 | double sy = cursor->cursor->y - con->content_y + view->geometry.y; | ||
1061 | |||
1062 | if (!pixman_region32_contains_point(region, | ||
1063 | floor(sx), floor(sy), NULL)) { | ||
1064 | int nboxes; | ||
1065 | pixman_box32_t *boxes = pixman_region32_rectangles(region, &nboxes); | ||
1066 | if (nboxes > 0) { | ||
1067 | double sx = (boxes[0].x1 + boxes[0].x2) / 2.; | ||
1068 | double sy = (boxes[0].y1 + boxes[0].y2) / 2.; | ||
1069 | |||
1070 | wlr_cursor_warp_closest(cursor->cursor, NULL, | ||
1071 | sx + con->content_x - view->geometry.x, | ||
1072 | sy + con->content_y - view->geometry.y); | ||
1073 | } | ||
1074 | } | ||
1075 | } | ||
1076 | |||
1077 | // A locked pointer will result in an empty region, thus disallowing all movement | ||
1078 | if (constraint->type == WLR_POINTER_CONSTRAINT_V1_CONFINED) { | ||
1079 | pixman_region32_copy(&cursor->confine, region); | ||
1080 | } else { | ||
1081 | pixman_region32_clear(&cursor->confine); | ||
1082 | } | ||
1083 | } | ||
1084 | |||
1085 | static void handle_constraint_commit(struct wl_listener *listener, | ||
1086 | void *data) { | ||
1087 | struct sway_cursor *cursor = | ||
1088 | wl_container_of(listener, cursor, constraint_commit); | ||
1089 | struct wlr_pointer_constraint_v1 *constraint = cursor->active_constraint; | ||
1090 | assert(constraint->surface == data); | ||
1091 | |||
1092 | check_constraint_region(cursor); | ||
1093 | } | ||
1094 | |||
1004 | static void handle_request_set_cursor(struct wl_listener *listener, | 1095 | static void handle_request_set_cursor(struct wl_listener *listener, |
1005 | void *data) { | 1096 | void *data) { |
1006 | struct sway_cursor *cursor = | 1097 | struct sway_cursor *cursor = |
@@ -1162,6 +1253,8 @@ struct sway_cursor *sway_cursor_create(struct sway_seat *seat) { | |||
1162 | &cursor->request_set_cursor); | 1253 | &cursor->request_set_cursor); |
1163 | cursor->request_set_cursor.notify = handle_request_set_cursor; | 1254 | cursor->request_set_cursor.notify = handle_request_set_cursor; |
1164 | 1255 | ||
1256 | wl_list_init(&cursor->constraint_commit.link); | ||
1257 | |||
1165 | cursor->cursor = wlr_cursor; | 1258 | cursor->cursor = wlr_cursor; |
1166 | 1259 | ||
1167 | return cursor; | 1260 | return cursor; |
@@ -1284,3 +1377,107 @@ const char *get_mouse_button_name(uint32_t button) { | |||
1284 | } | 1377 | } |
1285 | return name; | 1378 | return name; |
1286 | } | 1379 | } |
1380 | |||
1381 | static void warp_to_constraint_cursor_hint(struct sway_cursor *cursor) { | ||
1382 | struct wlr_pointer_constraint_v1 *constraint = cursor->active_constraint; | ||
1383 | |||
1384 | if (constraint->current.committed & | ||
1385 | WLR_POINTER_CONSTRAINT_V1_STATE_CURSOR_HINT) { | ||
1386 | double sx = constraint->current.cursor_hint.x; | ||
1387 | double sy = constraint->current.cursor_hint.y; | ||
1388 | |||
1389 | struct sway_view *view = view_from_wlr_surface(constraint->surface); | ||
1390 | struct sway_container *con = view->container; | ||
1391 | |||
1392 | double lx = sx + con->content_x - view->geometry.x; | ||
1393 | double ly = sy + con->content_y - view->geometry.y; | ||
1394 | |||
1395 | wlr_cursor_warp(cursor->cursor, NULL, lx, ly); | ||
1396 | } | ||
1397 | } | ||
1398 | |||
1399 | void handle_constraint_destroy(struct wl_listener *listener, void *data) { | ||
1400 | struct sway_pointer_constraint *sway_constraint = | ||
1401 | wl_container_of(listener, sway_constraint, destroy); | ||
1402 | struct wlr_pointer_constraint_v1 *constraint = data; | ||
1403 | struct sway_seat *seat = constraint->seat->data; | ||
1404 | struct sway_cursor *cursor = seat->cursor; | ||
1405 | |||
1406 | wl_list_remove(&sway_constraint->destroy.link); | ||
1407 | |||
1408 | if (cursor->active_constraint == constraint) { | ||
1409 | warp_to_constraint_cursor_hint(cursor); | ||
1410 | |||
1411 | if (cursor->constraint_commit.link.next != NULL) { | ||
1412 | wl_list_remove(&cursor->constraint_commit.link); | ||
1413 | } | ||
1414 | wl_list_init(&cursor->constraint_commit.link); | ||
1415 | cursor->active_constraint = NULL; | ||
1416 | } | ||
1417 | |||
1418 | free(sway_constraint); | ||
1419 | } | ||
1420 | |||
1421 | void handle_pointer_constraint(struct wl_listener *listener, void *data) { | ||
1422 | struct wlr_pointer_constraint_v1 *constraint = data; | ||
1423 | struct sway_seat *seat = constraint->seat->data; | ||
1424 | |||
1425 | struct sway_pointer_constraint *sway_constraint = | ||
1426 | calloc(1, sizeof(struct sway_pointer_constraint)); | ||
1427 | sway_constraint->constraint = constraint; | ||
1428 | |||
1429 | sway_constraint->destroy.notify = handle_constraint_destroy; | ||
1430 | wl_signal_add(&constraint->events.destroy, &sway_constraint->destroy); | ||
1431 | |||
1432 | struct sway_node *focus = seat_get_focus(seat); | ||
1433 | if (focus && focus->type == N_CONTAINER && focus->sway_container->view) { | ||
1434 | struct wlr_surface *surface = focus->sway_container->view->surface; | ||
1435 | if (surface == constraint->surface) { | ||
1436 | sway_cursor_constrain(seat->cursor, constraint); | ||
1437 | } | ||
1438 | } | ||
1439 | } | ||
1440 | |||
1441 | void sway_cursor_constrain(struct sway_cursor *cursor, | ||
1442 | struct wlr_pointer_constraint_v1 *constraint) { | ||
1443 | if (cursor->active_constraint == constraint) { | ||
1444 | return; | ||
1445 | } | ||
1446 | |||
1447 | wl_list_remove(&cursor->constraint_commit.link); | ||
1448 | if (cursor->active_constraint) { | ||
1449 | if (constraint == NULL) { | ||
1450 | warp_to_constraint_cursor_hint(cursor); | ||
1451 | } | ||
1452 | wlr_pointer_constraint_v1_send_deactivated( | ||
1453 | cursor->active_constraint); | ||
1454 | } | ||
1455 | |||
1456 | cursor->active_constraint = constraint; | ||
1457 | |||
1458 | if (constraint == NULL) { | ||
1459 | wl_list_init(&cursor->constraint_commit.link); | ||
1460 | return; | ||
1461 | } | ||
1462 | |||
1463 | // FIXME: Big hack, stolen from wlr_pointer_constraints_v1.c:121. | ||
1464 | // This is necessary because the focus may be set before the surface | ||
1465 | // has finished committing, which means that warping won't work properly, | ||
1466 | // since this code will be run *after* the focus has been set. | ||
1467 | // That is why we duplicate the code here. | ||
1468 | if (pixman_region32_not_empty(&constraint->current.region)) { | ||
1469 | pixman_region32_intersect(&constraint->region, | ||
1470 | &constraint->surface->input_region, &constraint->current.region); | ||
1471 | } else { | ||
1472 | pixman_region32_copy(&constraint->region, | ||
1473 | &constraint->surface->input_region); | ||
1474 | } | ||
1475 | |||
1476 | check_constraint_region(cursor); | ||
1477 | |||
1478 | wlr_pointer_constraint_v1_send_activated(constraint); | ||
1479 | |||
1480 | cursor->constraint_commit.notify = handle_constraint_commit; | ||
1481 | wl_signal_add(&constraint->surface->events.commit, | ||
1482 | &cursor->constraint_commit); | ||
1483 | } | ||