diff --git a/include/rootston/cursor.h b/include/rootston/cursor.h index 8a8d33f2..18d5f720 100644 --- a/include/rootston/cursor.h +++ b/include/rootston/cursor.h @@ -3,10 +3,45 @@ #include "rootston/seat.h" +enum roots_cursor_mode { + ROOTS_CURSOR_PASSTHROUGH = 0, + ROOTS_CURSOR_MOVE = 1, + ROOTS_CURSOR_RESIZE = 2, + ROOTS_CURSOR_ROTATE = 3, +}; + +enum roots_cursor_resize_edge { + ROOTS_CURSOR_RESIZE_EDGE_TOP = 1, + ROOTS_CURSOR_RESIZE_EDGE_BOTTOM = 2, + ROOTS_CURSOR_RESIZE_EDGE_LEFT = 4, + ROOTS_CURSOR_RESIZE_EDGE_RIGHT = 8, +}; + +struct roots_input_event { + uint32_t serial; + struct wlr_cursor *cursor; + struct wlr_input_device *device; +}; + struct roots_cursor { struct roots_seat *seat; struct wlr_cursor *cursor; + enum roots_cursor_mode mode; + + // state from input (review if this is necessary) + struct wlr_xcursor_theme *xcursor_theme; + struct wlr_seat *wl_seat; + struct wl_client *cursor_client; + int offs_x, offs_y; + int view_x, view_y, view_width, view_height; + float view_rotation; + uint32_t resize_edges; + // Ring buffer of input events that could trigger move/resize/rotate + int input_events_idx; + struct wl_list touch_points; + struct roots_input_event input_events[16]; + struct wl_listener motion; struct wl_listener motion_absolute; struct wl_listener button; diff --git a/include/rootston/input.h b/include/rootston/input.h index 7b1358f8..7463ba3a 100644 --- a/include/rootston/input.h +++ b/include/rootston/input.h @@ -5,64 +5,15 @@ #include #include #include +#include "rootston/cursor.h" #include "rootston/config.h" #include "rootston/view.h" #include "rootston/server.h" -enum roots_cursor_mode { - ROOTS_CURSOR_PASSTHROUGH = 0, - ROOTS_CURSOR_MOVE = 1, - ROOTS_CURSOR_RESIZE = 2, - ROOTS_CURSOR_ROTATE = 3, -}; - -enum roots_cursor_resize_edge { - ROOTS_CURSOR_RESIZE_EDGE_TOP = 1, - ROOTS_CURSOR_RESIZE_EDGE_BOTTOM = 2, - ROOTS_CURSOR_RESIZE_EDGE_LEFT = 4, - ROOTS_CURSOR_RESIZE_EDGE_RIGHT = 8, -}; - -struct roots_input_event { - uint32_t serial; - struct wlr_cursor *cursor; - struct wlr_input_device *device; -}; - -struct roots_drag_icon { - struct wlr_surface *surface; - struct wl_list link; // roots_input::drag_icons - bool mapped; - - int32_t sx; - int32_t sy; - - struct wl_listener surface_destroy; - struct wl_listener surface_commit; -}; - struct roots_input { struct roots_config *config; struct roots_server *server; - // TODO: multiseat, multicursor - struct wlr_cursor *cursor; - struct wlr_xcursor_theme *xcursor_theme; - struct wlr_seat *wl_seat; - struct wl_list drag_icons; - struct wl_client *cursor_client; - - enum roots_cursor_mode mode; - struct roots_view *active_view; - int offs_x, offs_y; - int view_x, view_y, view_width, view_height; - float view_rotation; - uint32_t resize_edges; - - // Ring buffer of input events that could trigger move/resize/rotate - int input_events_idx; - struct roots_input_event input_events[16]; - struct wl_list keyboards; struct wl_list pointers; struct wl_list touch; @@ -117,4 +68,7 @@ struct wlr_xcursor *get_rotate_xcursor(struct wlr_xcursor_theme *theme); void set_view_focus(struct roots_input *input, struct roots_desktop *desktop, struct roots_view *view); +struct roots_seat *input_seat_from_wlr_seat(struct roots_input *input, + struct wlr_seat *seat); + #endif diff --git a/include/rootston/keyboard.h b/include/rootston/keyboard.h index cb639ba1..e3caf8fb 100644 --- a/include/rootston/keyboard.h +++ b/include/rootston/keyboard.h @@ -10,6 +10,7 @@ struct roots_keyboard { struct roots_input *input; struct roots_seat *seat; struct wlr_input_device *device; + struct keyboard_config *config; struct wl_list seat_link; // XXX temporary struct wl_list link; diff --git a/include/rootston/seat.h b/include/rootston/seat.h index b7c8b477..b5593651 100644 --- a/include/rootston/seat.h +++ b/include/rootston/seat.h @@ -6,11 +6,26 @@ #include "rootston/input.h" #include "rootston/keyboard.h" +struct roots_drag_icon { + struct wlr_surface *surface; + struct wl_list link; // roots_seat::drag_icons + bool mapped; + + int32_t sx; + int32_t sy; + + struct wl_listener surface_destroy; + struct wl_listener surface_commit; +}; + struct roots_seat { struct roots_input *input; struct wlr_seat *seat; struct roots_cursor *cursor; struct wl_list link; + struct wl_list drag_icons; + + struct roots_view *focus; struct wl_list keyboards; struct wl_list pointers; @@ -57,4 +72,19 @@ void roots_seat_add_device(struct roots_seat *seat, void roots_seat_remove_device(struct roots_seat *seat, struct wlr_input_device *device); +void roots_seat_configure_cursor(struct roots_seat *seat); + +void roots_seat_configure_xcursor(struct roots_seat *seat); + +bool roots_seat_has_meta_pressed(struct roots_seat *seat); + +void roots_seat_focus_view(struct roots_seat *seat, struct roots_view *view); + +void roots_seat_begin_move(struct roots_seat *seat, struct roots_view *view); + +void roots_seat_begin_resize(struct roots_seat *seat, struct roots_view *view, + uint32_t edges); + +void roots_seat_begin_rotate(struct roots_seat *seat, struct roots_view *view); + #endif diff --git a/include/wlr/types/wlr_wl_shell.h b/include/wlr/types/wlr_wl_shell.h index 4e814817..ab3b4b10 100644 --- a/include/wlr/types/wlr_wl_shell.h +++ b/include/wlr/types/wlr_wl_shell.h @@ -93,14 +93,14 @@ struct wlr_wl_shell_surface { struct wlr_wl_shell_surface_move_event { struct wl_client *client; struct wlr_wl_shell_surface *surface; - struct wlr_seat_handle *seat_handle; + struct wlr_seat_client *seat; uint32_t serial; }; struct wlr_wl_shell_surface_resize_event { struct wl_client *client; struct wlr_wl_shell_surface *surface; - struct wlr_seat_handle *seat_handle; + struct wlr_seat_client *seat; uint32_t serial; enum wl_shell_surface_resize edges; }; diff --git a/include/wlr/types/wlr_xdg_shell_v6.h b/include/wlr/types/wlr_xdg_shell_v6.h index b0de41e2..e17393f6 100644 --- a/include/wlr/types/wlr_xdg_shell_v6.h +++ b/include/wlr/types/wlr_xdg_shell_v6.h @@ -138,14 +138,14 @@ struct wlr_xdg_surface_v6 { struct wlr_xdg_toplevel_v6_move_event { struct wl_client *client; struct wlr_xdg_surface_v6 *surface; - struct wlr_seat_handle *seat_handle; + struct wlr_seat_client *seat; uint32_t serial; }; struct wlr_xdg_toplevel_v6_resize_event { struct wl_client *client; struct wlr_xdg_surface_v6 *surface; - struct wlr_seat_handle *seat_handle; + struct wlr_seat_client *seat; uint32_t serial; uint32_t edges; }; @@ -153,7 +153,7 @@ struct wlr_xdg_toplevel_v6_resize_event { struct wlr_xdg_toplevel_v6_show_window_menu_event { struct wl_client *client; struct wlr_xdg_surface_v6 *surface; - struct wlr_seat_handle *seat_handle; + struct wlr_seat_client *seat; uint32_t serial; uint32_t x; uint32_t y; diff --git a/rootston/desktop.c b/rootston/desktop.c index 29f78ac7..e752e639 100644 --- a/rootston/desktop.c +++ b/rootston/desktop.c @@ -14,15 +14,19 @@ #include #include #include "rootston/server.h" -#include "rootston/server.h" +#include "rootston/seat.h" +// TODO replace me with a signal void view_destroy(struct roots_view *view) { struct roots_desktop *desktop = view->desktop; struct roots_input *input = desktop->server->input; - if (input->active_view == view) { - input->active_view = NULL; - input->mode = ROOTS_CURSOR_PASSTHROUGH; + struct roots_seat *seat; + wl_list_for_each(seat, &input->seats, link) { + if (seat->focus == view) { + seat->focus = NULL; + seat->cursor->mode = ROOTS_CURSOR_PASSTHROUGH; + } } for (size_t i = 0; i < desktop->views->length; ++i) { @@ -89,15 +93,9 @@ bool view_center(struct roots_view *view) { view_get_size(view, &size); struct roots_desktop *desktop = view->desktop; - struct wlr_cursor *cursor = desktop->server->input->cursor; struct wlr_output *output = - wlr_output_layout_output_at(desktop->layout, cursor->x, cursor->y); - - if (!output) { - output = wlr_output_layout_get_center_output(desktop->layout); - } - + wlr_output_layout_get_center_output(desktop->layout); if (!output) { // empty layout return false; @@ -121,19 +119,15 @@ void view_setup(struct roots_view *view) { view_center(view); struct roots_input *input = view->desktop->server->input; - set_view_focus(input, view->desktop, view); + // TODO what seat gets focus? the one with the last input event? + struct roots_seat *seat; + wl_list_for_each(seat, &input->seats, link) { + roots_seat_focus_view(seat, view); + } } void view_teardown(struct roots_view *view) { - struct wlr_list *views = view->desktop->views; - if (views->length < 2 || views->items[views->length-1] != view) { - return; - } - - struct roots_view *prev_view = views->items[views->length-2]; - struct roots_input *input = prev_view->desktop->server->input; - set_view_focus(input, prev_view->desktop, prev_view); - wlr_seat_keyboard_notify_enter(input->wl_seat, prev_view->wlr_surface); + // TODO replace me with a signal } struct roots_view *view_at(struct roots_desktop *desktop, double lx, double ly, diff --git a/rootston/input.c b/rootston/input.c index 4a567763..8e45d6d3 100644 --- a/rootston/input.c +++ b/rootston/input.c @@ -84,43 +84,6 @@ struct roots_input *input_create(struct roots_server *server, input->config = config; input->server = server; - input->xcursor_theme = wlr_xcursor_theme_load("default", 16); - if (input->xcursor_theme == NULL) { - wlr_log(L_ERROR, "Cannot load xcursor theme"); - free(input); - return NULL; - } - - struct wlr_xcursor *xcursor = get_default_xcursor(input->xcursor_theme); - if (xcursor == NULL) { - wlr_log(L_ERROR, "Cannot load xcursor from theme"); - wlr_xcursor_theme_destroy(input->xcursor_theme); - free(input); - return NULL; - } - - if (server->desktop->xwayland != NULL) { - struct wlr_xcursor_image *xcursor_image = xcursor->images[0]; - wlr_xwayland_set_cursor(server->desktop->xwayland, - xcursor_image->buffer, xcursor_image->width, xcursor_image->width, - xcursor_image->height, xcursor_image->hotspot_x, - xcursor_image->hotspot_y); - } - - input->wl_seat = wlr_seat_create(server->wl_display, "seat0"); - if (input->wl_seat == NULL) { - wlr_log(L_ERROR, "Cannot create seat"); - wlr_xcursor_theme_destroy(input->xcursor_theme); - free(input); - return NULL; - } - wlr_seat_set_capabilities(input->wl_seat, WL_SEAT_CAPABILITY_KEYBOARD - | WL_SEAT_CAPABILITY_POINTER | WL_SEAT_CAPABILITY_TOUCH); - - wl_list_init(&input->keyboards); - wl_list_init(&input->pointers); - wl_list_init(&input->touch); - wl_list_init(&input->tablet_tools); wl_list_init(&input->seats); input->input_add.notify = input_add_notify; @@ -128,23 +91,20 @@ struct roots_input *input_create(struct roots_server *server, input->input_remove.notify = input_remove_notify; wl_signal_add(&server->backend->events.input_remove, &input->input_remove); - input->cursor = wlr_cursor_create(); - cursor_initialize(input); - - struct wlr_xcursor_image *image = xcursor->images[0]; - wlr_cursor_set_image(input->cursor, image->buffer, image->width, - image->width, image->height, image->hotspot_x, image->hotspot_y); - - wlr_cursor_attach_output_layout(input->cursor, server->desktop->layout); - wlr_cursor_map_to_region(input->cursor, config->cursor.mapped_box); - cursor_load_config(config, input->cursor, - input, server->desktop); - - wl_list_init(&input->drag_icons); - return input; } void input_destroy(struct roots_input *input) { // TODO } + +struct roots_seat *input_seat_from_wlr_seat(struct roots_input *input, + struct wlr_seat *wlr_seat) { + struct roots_seat *seat = NULL; + wl_list_for_each(seat, &input->seats, link) { + if (seat->seat == wlr_seat) { + return seat; + } + } + return seat; +} diff --git a/rootston/keyboard.c b/rootston/keyboard.c index 0865f551..ef5eb8ab 100644 --- a/rootston/keyboard.c +++ b/rootston/keyboard.c @@ -39,7 +39,7 @@ static void keyboard_binding_execute(struct roots_keyboard *keyboard, } else if (strcmp(command, "next_window") == 0) { if (server->desktop->views->length > 0) { struct roots_view *view = server->desktop->views->items[0]; - set_view_focus(keyboard->input, server->desktop, view); + roots_seat_focus_view(keyboard->seat, view); } } else if (strncmp(exec_prefix, command, strlen(exec_prefix)) == 0) { const char *shell_cmd = command + strlen(exec_prefix); @@ -192,13 +192,9 @@ struct roots_keyboard *roots_keyboard_create(struct wlr_input_device *device, keyboard->device = device; keyboard->input = input; - // XXX temporary - wl_list_insert(&input->keyboards, &keyboard->link); - - struct keyboard_config config; - memset(&config, 0, sizeof(config)); - keyboard_config_merge(&config, config_get_keyboard(input->config, device)); - keyboard_config_merge(&config, config_get_keyboard(input->config, NULL)); + struct keyboard_config *config = calloc(1, sizeof(struct keyboard_config)); + keyboard_config_merge(config, config_get_keyboard(input->config, device)); + keyboard_config_merge(config, config_get_keyboard(input->config, NULL)); struct keyboard_config env_config = { .rules = getenv("XKB_DEFAULT_RULES"), @@ -207,15 +203,16 @@ struct roots_keyboard *roots_keyboard_create(struct wlr_input_device *device, .variant = getenv("XKB_DEFAULT_VARIANT"), .options = getenv("XKB_DEFAULT_OPTIONS"), }; - keyboard_config_merge(&config, &env_config); + keyboard_config_merge(config, &env_config); + keyboard->config = config; struct xkb_rule_names rules; memset(&rules, 0, sizeof(rules)); - rules.rules = config.rules; - rules.model = config.model; - rules.layout = config.layout; - rules.variant = config.variant; - rules.options = config.options; + rules.rules = config->rules; + rules.model = config->model; + rules.layout = config->layout; + rules.variant = config->variant; + rules.options = config->options; struct xkb_context *context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); if (context == NULL) { wlr_log(L_ERROR, "Cannot create XKB context"); @@ -231,5 +228,6 @@ struct roots_keyboard *roots_keyboard_create(struct wlr_input_device *device, void roots_keyboard_destroy(struct wlr_input_device *device, struct roots_input *input) { struct roots_keyboard *keyboard = device->data; wl_list_remove(&keyboard->link); + free(keyboard->config); free(keyboard); } diff --git a/rootston/meson.build b/rootston/meson.build index baed5330..062f56fc 100644 --- a/rootston/meson.build +++ b/rootston/meson.build @@ -1,6 +1,6 @@ sources = [ 'config.c', - 'cursor.c', + #'cursor.c', 'roots_cursor.c', 'desktop.c', 'ini.c', diff --git a/rootston/output.c b/rootston/output.c index baa7b6cc..329c29be 100644 --- a/rootston/output.c +++ b/rootston/output.c @@ -151,15 +151,18 @@ static void output_frame_notify(struct wl_listener *listener, void *data) { } struct roots_drag_icon *drag_icon = NULL; - wl_list_for_each(drag_icon, &server->input->drag_icons, link) { - if (!drag_icon->mapped) { - continue; + struct roots_seat *seat = NULL; + wl_list_for_each(seat, &server->input->seats, link) { + wl_list_for_each(drag_icon, &seat->drag_icons, link) { + if (!drag_icon->mapped) { + continue; + } + struct wlr_surface *icon = drag_icon->surface; + struct wlr_cursor *cursor = seat->cursor->cursor; + double icon_x = cursor->x + drag_icon->sx; + double icon_y = cursor->y + drag_icon->sy; + render_surface(icon, desktop, wlr_output, &now, icon_x, icon_y, 0); } - struct wlr_surface *icon = drag_icon->surface; - struct wlr_cursor *cursor = server->input->cursor; - double icon_x = cursor->x + drag_icon->sx; - double icon_y = cursor->y + drag_icon->sy; - render_surface(icon, desktop, wlr_output, &now, icon_x, icon_y, 0); } wlr_renderer_end(server->renderer); @@ -224,14 +227,11 @@ void output_add_notify(struct wl_listener *listener, void *data) { wlr_output_layout_add_auto(desktop->layout, wlr_output); } - cursor_load_config(config, input->cursor, input, desktop); - - struct wlr_xcursor *xcursor = get_default_xcursor(input->xcursor_theme); - struct wlr_xcursor_image *image = xcursor->images[0]; - wlr_cursor_set_image(input->cursor, image->buffer, image->width, - image->width, image->height, image->hotspot_x, image->hotspot_y); - - wlr_cursor_warp(input->cursor, NULL, input->cursor->x, input->cursor->y); + struct roots_seat *seat; + wl_list_for_each(seat, &input->seats, link) { + roots_seat_configure_cursor(seat); + roots_seat_configure_xcursor(seat); + } } void output_remove_notify(struct wl_listener *listener, void *data) { diff --git a/rootston/roots_cursor.c b/rootston/roots_cursor.c index 72eff996..92c0cc9e 100644 --- a/rootston/roots_cursor.c +++ b/rootston/roots_cursor.c @@ -1,4 +1,11 @@ +#define _XOPEN_SOURCE 700 #include +#include +#ifdef __linux__ +#include +#elif __FreeBSD__ +#include +#endif #include #include "rootston/cursor.h" @@ -19,47 +26,261 @@ void roots_cursor_destroy(struct roots_cursor *cursor) { // TODO } +static void cursor_set_xcursor_image(struct roots_cursor *cursor, + struct wlr_xcursor_image *image) { + wlr_cursor_set_image(cursor->cursor, image->buffer, image->width, + image->width, image->height, image->hotspot_x, image->hotspot_y); +} + +static void roots_cursor_update_position(struct roots_cursor *cursor, uint32_t time) { + struct roots_desktop *desktop = cursor->seat->input->server->desktop; + struct roots_seat *seat = cursor->seat; + struct roots_view *view; + struct wlr_surface *surface; + double sx, sy; + switch (cursor->mode) { + case ROOTS_CURSOR_PASSTHROUGH: + view = view_at(desktop, cursor->cursor->x, cursor->cursor->y, + &surface, &sx, &sy); + bool set_compositor_cursor = !view && cursor->cursor_client; + if (view) { + struct wl_client *view_client = + wl_resource_get_client(view->wlr_surface->resource); + set_compositor_cursor = view_client != cursor->cursor_client; + } + if (set_compositor_cursor) { + struct wlr_xcursor *xcursor = get_default_xcursor(cursor->xcursor_theme); + cursor_set_xcursor_image(cursor, xcursor->images[0]); + cursor->cursor_client = NULL; + } + if (view) { + wlr_seat_pointer_notify_enter(seat->seat, surface, sx, sy); + wlr_seat_pointer_notify_motion(seat->seat, time, sx, sy); + } else { + wlr_seat_pointer_clear_focus(seat->seat); + } + break; + case ROOTS_CURSOR_MOVE: + if (seat->focus) { + double dx = cursor->cursor->x - cursor->offs_x; + double dy = cursor->cursor->y - cursor->offs_y; + view_move(seat->focus, cursor->view_x + dx, + cursor->view_y + dy); + } + break; + case ROOTS_CURSOR_RESIZE: + if (seat->focus) { + double dx = cursor->cursor->x - cursor->offs_x; + double dy = cursor->cursor->y - cursor->offs_y; + double active_x = seat->focus->x; + double active_y = seat->focus->y; + int width = cursor->view_width; + int height = cursor->view_height; + if (cursor->resize_edges & ROOTS_CURSOR_RESIZE_EDGE_TOP) { + active_y = cursor->view_y + dy; + height -= dy; + if (height < 0) { + active_y += height; + } + } else if (cursor->resize_edges & ROOTS_CURSOR_RESIZE_EDGE_BOTTOM) { + height += dy; + } + if (cursor->resize_edges & ROOTS_CURSOR_RESIZE_EDGE_LEFT) { + active_x = cursor->view_x + dx; + width -= dx; + if (width < 0) { + active_x += width; + } + } else if (cursor->resize_edges & ROOTS_CURSOR_RESIZE_EDGE_RIGHT) { + width += dx; + } + + if (width < 0) { + width = 0; + } + if (height < 0) { + height = 0; + } + + if (active_x != seat->focus->x || + active_y != seat->focus->y) { + view_move_resize(seat->focus, active_x, active_y, + width, height); + } else { + view_resize(seat->focus, width, height); + } + } + break; + case ROOTS_CURSOR_ROTATE: + if (seat->focus) { + struct roots_view *view = seat->focus; + int ox = view->x + view->wlr_surface->current->width/2, + oy = view->y + view->wlr_surface->current->height/2; + int ux = cursor->offs_x - ox, + uy = cursor->offs_y - oy; + int vx = cursor->cursor->x - ox, + vy = cursor->cursor->y - oy; + float angle = atan2(vx*uy - vy*ux, vx*ux + vy*uy); + int steps = 12; + angle = round(angle/M_PI*steps) / (steps/M_PI); + view->rotation = cursor->view_rotation + angle; + } + break; + } + +} + +static void roots_cursor_press_button(struct roots_cursor *cursor, + struct wlr_input_device *device, uint32_t time, uint32_t button, + uint32_t state) { + struct roots_seat *seat = cursor->seat; + struct roots_desktop *desktop = seat->input->server->desktop; + struct wlr_surface *surface; + double sx, sy; + struct roots_view *view = view_at(desktop, + cursor->cursor->x, cursor->cursor->y, &surface, &sx, &sy); + + if (state == WLR_BUTTON_PRESSED && view && roots_seat_has_meta_pressed(seat)) { + // TODO + roots_seat_focus_view(seat, view); + + uint32_t edges; + switch (button) { + case BTN_LEFT: + // TODO + roots_seat_begin_move(seat, view); + break; + case BTN_RIGHT: + edges = 0; + if (sx < view->wlr_surface->current->width/2) { + edges |= ROOTS_CURSOR_RESIZE_EDGE_LEFT; + } else { + edges |= ROOTS_CURSOR_RESIZE_EDGE_RIGHT; + } + if (sy < view->wlr_surface->current->height/2) { + edges |= ROOTS_CURSOR_RESIZE_EDGE_TOP; + } else { + edges |= ROOTS_CURSOR_RESIZE_EDGE_BOTTOM; + } + roots_seat_begin_resize(seat, view, edges); + break; + case BTN_MIDDLE: + roots_seat_begin_rotate(seat, view); + break; + } + return; + } + + // TODO + uint32_t serial = + wlr_seat_pointer_notify_button(seat->seat, time, button, state); + + int i; + switch (state) { + case WLR_BUTTON_RELEASED: + seat->cursor->mode = ROOTS_CURSOR_PASSTHROUGH; + roots_cursor_update_position(cursor, time); + break; + case WLR_BUTTON_PRESSED: + // TODO + i = cursor->input_events_idx; + cursor->input_events[i].serial = serial; + cursor->input_events[i].cursor = cursor->cursor; + cursor->input_events[i].device = device; + cursor->input_events_idx = (i + 1) + % (sizeof(cursor->input_events) / sizeof(cursor->input_events[0])); + roots_seat_focus_view(seat, view); + break; + } +} + void roots_cursor_handle_motion(struct roots_cursor *cursor, struct wlr_event_pointer_motion *event) { - wlr_log(L_DEBUG, "TODO: cursor handle motion"); + wlr_cursor_move(cursor->cursor, event->device, + event->delta_x, event->delta_y); + roots_cursor_update_position(cursor, event->time_msec); } void roots_cursor_handle_motion_absolute(struct roots_cursor *cursor, struct wlr_event_pointer_motion_absolute *event) { - wlr_log(L_DEBUG, "TODO: cursor handle motion absolute"); + wlr_cursor_warp_absolute(cursor->cursor, event->device, + event->x_mm / event->width_mm, event->y_mm / event->height_mm); + roots_cursor_update_position(cursor, event->time_msec); } void roots_cursor_handle_button(struct roots_cursor *cursor, struct wlr_event_pointer_button *event) { - wlr_log(L_DEBUG, "TODO: cursor handle button"); + roots_cursor_press_button(cursor, event->device, event->time_msec, + event->button, event->state); } void roots_cursor_handle_axis(struct roots_cursor *cursor, struct wlr_event_pointer_axis *event) { - wlr_log(L_DEBUG, "TODO: cursor handle axis"); + wlr_seat_pointer_notify_axis(cursor->seat->seat, event->time_msec, + event->orientation, event->delta); } void roots_cursor_handle_touch_down(struct roots_cursor *cursor, struct wlr_event_touch_down *event) { - wlr_log(L_DEBUG, "TODO: cursor handle touch down"); + struct roots_touch_point *point = + calloc(1, sizeof(struct roots_touch_point)); + if (!point) { + wlr_log(L_ERROR, "could not allocate memory for touch point"); + return; + } + + point->device = event->device->data; + point->slot = event->slot; + point->x = event->x_mm / event->width_mm; + point->y = event->y_mm / event->height_mm; + wlr_cursor_warp_absolute(cursor->cursor, event->device, point->x, point->y); + roots_cursor_update_position(cursor, event->time_msec); + wl_list_insert(&cursor->touch_points, &point->link); + roots_cursor_press_button(cursor, event->device, + event->time_msec, BTN_LEFT, 1); } void roots_cursor_handle_touch_up(struct roots_cursor *cursor, struct wlr_event_touch_up *event) { - wlr_log(L_DEBUG, "TODO: cursor handle touch up"); + struct roots_touch_point *point; + wl_list_for_each(point, &cursor->touch_points, link) { + if (point->slot == event->slot) { + wl_list_remove(&point->link); + free(point); + break; + } + } + roots_cursor_press_button(cursor, event->device, + event->time_msec, BTN_LEFT, 0); } void roots_cursor_handle_touch_motion(struct roots_cursor *cursor, struct wlr_event_touch_motion *event) { - wlr_log(L_DEBUG, "TODO: cursor handle touch motion"); + struct roots_touch_point *point; + wl_list_for_each(point, &cursor->touch_points, link) { + if (point->slot == event->slot) { + point->x = event->x_mm / event->width_mm; + point->y = event->y_mm / event->height_mm; + wlr_cursor_warp_absolute(cursor->cursor, event->device, + point->x, point->y); + roots_cursor_update_position(cursor, event->time_msec); + break; + } + } } void roots_cursor_handle_tool_axis(struct roots_cursor *cursor, struct wlr_event_tablet_tool_axis *event) { - wlr_log(L_DEBUG, "TODO: cursor handle tool axis"); + if ((event->updated_axes & WLR_TABLET_TOOL_AXIS_X) && + (event->updated_axes & WLR_TABLET_TOOL_AXIS_Y)) { + wlr_cursor_warp_absolute(cursor->cursor, event->device, + event->x_mm / event->width_mm, event->y_mm / event->height_mm); + roots_cursor_update_position(cursor, event->time_msec); + } } void roots_cursor_handle_tool_tip(struct roots_cursor *cursor, struct wlr_event_tablet_tool_tip *event) { - wlr_log(L_DEBUG, "TODO: cursor handle tool tip"); + roots_cursor_press_button(cursor, event->device, + event->time_msec, BTN_LEFT, event->state); } diff --git a/rootston/seat.c b/rootston/seat.c index 957843ec..ec7709fa 100644 --- a/rootston/seat.c +++ b/rootston/seat.c @@ -1,6 +1,7 @@ #include #include #include +#include #include @@ -110,7 +111,7 @@ static void seat_set_device_output_mappings(struct roots_seat *seat, } } -static void roots_seat_configure_cursor(struct roots_seat *seat) { +void roots_seat_configure_cursor(struct roots_seat *seat) { struct roots_config *config = seat->input->config; struct roots_desktop *desktop = seat->input->server->desktop; struct wlr_cursor *cursor = seat->cursor->cursor; @@ -156,10 +157,44 @@ static void roots_seat_init_cursor(struct roots_seat *seat) { if (!seat->cursor) { return; } + seat->cursor->seat = seat; struct wlr_cursor *wlr_cursor = seat->cursor->cursor; struct roots_desktop *desktop = seat->input->server->desktop; wlr_cursor_attach_output_layout(wlr_cursor, desktop->layout); + seat->cursor->xcursor_theme = wlr_xcursor_theme_load("default", 16); + if (seat->cursor->xcursor_theme == NULL) { + wlr_log(L_ERROR, "Cannot load xcursor theme"); + roots_cursor_destroy(seat->cursor); + seat->cursor = NULL; + return; + } + + struct wlr_xcursor *xcursor = get_default_xcursor(seat->cursor->xcursor_theme); + if (xcursor == NULL) { + wlr_log(L_ERROR, "Cannot load xcursor from theme"); + wlr_xcursor_theme_destroy(seat->cursor->xcursor_theme); + roots_cursor_destroy(seat->cursor); + seat->cursor = NULL; + return; + } + + struct wlr_xcursor_image *image = xcursor->images[0]; + wlr_cursor_set_image(seat->cursor->cursor, image->buffer, image->width, + image->width, image->height, image->hotspot_x, image->hotspot_y); + + // XXX: xwayland will always have the theme of the last created seat + if (seat->input->server->desktop->xwayland != NULL) { + wlr_xwayland_set_cursor(seat->input->server->desktop->xwayland, + image->buffer, image->width, image->width, + image->height, image->hotspot_x, + image->hotspot_y); + } + + wl_list_init(&seat->cursor->touch_points); + + roots_seat_configure_cursor(seat); + // add input signals wl_signal_add(&wlr_cursor->events.motion, &seat->cursor->motion); seat->cursor->motion.notify = handle_cursor_motion; @@ -196,6 +231,12 @@ struct roots_seat *roots_seat_create(struct roots_input *input, char *name) { return NULL; } + wl_list_init(&seat->keyboards); + wl_list_init(&seat->pointers); + wl_list_init(&seat->touch); + wl_list_init(&seat->tablet_tools); + wl_list_init(&seat->drag_icons); + seat->input = input; roots_seat_init_cursor(seat); @@ -218,11 +259,6 @@ struct roots_seat *roots_seat_create(struct roots_input *input, char *name) { wl_list_insert(&input->seats, &seat->link); - wl_list_init(&seat->keyboards); - wl_list_init(&seat->pointers); - wl_list_init(&seat->touch); - wl_list_init(&seat->tablet_tools); - return seat; } @@ -231,6 +267,7 @@ void roots_seat_destroy(struct roots_seat *seat) { } static void seat_add_keyboard(struct roots_seat *seat, struct wlr_input_device *device) { + assert(device->type == WLR_INPUT_DEVICE_KEYBOARD); struct roots_keyboard *keyboard = roots_keyboard_create(device, seat->input); keyboard->seat = seat; @@ -319,3 +356,88 @@ void roots_seat_remove_device(struct roots_seat *seat, struct wlr_input_device *device) { // TODO } + +void roots_seat_configure_xcursor(struct roots_seat *seat) { + struct wlr_xcursor *xcursor = get_default_xcursor(seat->cursor->xcursor_theme); + struct wlr_xcursor_image *image = xcursor->images[0]; + wlr_cursor_set_image(seat->cursor->cursor, image->buffer, image->width, + image->width, image->height, image->hotspot_x, image->hotspot_y); + + wlr_cursor_warp(seat->cursor->cursor, NULL, seat->cursor->cursor->x, + seat->cursor->cursor->y); +} + +bool roots_seat_has_meta_pressed(struct roots_seat *seat) { + struct roots_keyboard *keyboard; + wl_list_for_each(keyboard, &seat->keyboards, seat_link) { + if (!keyboard->config->meta_key) { + continue; + } + + uint32_t modifiers = + wlr_keyboard_get_modifiers(keyboard->device->keyboard); + if ((modifiers ^ keyboard->config->meta_key) == 0) { + return true; + } + } + + return false; +} + +void roots_seat_focus_view(struct roots_seat *seat, struct roots_view *view) { + struct roots_desktop *desktop = seat->input->server->desktop; + if (seat->focus == view) { + return; + } + seat->focus = view; + seat->cursor->mode = ROOTS_CURSOR_PASSTHROUGH; + if (!view) { + return; + } + + if (view->type == ROOTS_XWAYLAND_VIEW && + view->xwayland_surface->override_redirect) { + return; + } + + size_t index = 0; + for (size_t i = 0; i < desktop->views->length; ++i) { + struct roots_view *_view = desktop->views->items[i]; + if (_view != view) { + view_activate(_view, false); + } else { + index = i; + } + } + view_activate(view, true); + // TODO: list_swap + wlr_list_del(desktop->views, index); + wlr_list_add(desktop->views, view); + wlr_seat_keyboard_notify_enter(seat->seat, view->wlr_surface); +} + +void roots_seat_begin_move(struct roots_seat *seat, struct roots_view *view) { + struct roots_cursor *cursor = seat->cursor; + cursor->mode = ROOTS_CURSOR_MOVE; + cursor->offs_x = cursor->cursor->x; + cursor->offs_y = cursor->cursor->y; + cursor->view_x = view->x; + cursor->view_y = view->y; + wlr_seat_pointer_clear_focus(seat->seat); + + struct wlr_xcursor *xcursor = get_move_xcursor(seat->cursor->xcursor_theme); + if (xcursor != NULL) { + struct wlr_xcursor_image *image = xcursor->images[0]; + wlr_cursor_set_image(cursor->cursor, image->buffer, image->width, + image->width, image->height, image->hotspot_x, image->hotspot_y); + } +} + +void roots_seat_begin_resize(struct roots_seat *seat, struct roots_view *view, + uint32_t edges) { + // TODO +} + +void roots_seat_begin_rotate(struct roots_seat *seat, struct roots_view *view) { + // TODO +} diff --git a/rootston/wl_shell.c b/rootston/wl_shell.c index e38eb697..81b9e640 100644 --- a/rootston/wl_shell.c +++ b/rootston/wl_shell.c @@ -29,11 +29,11 @@ static void handle_request_move(struct wl_listener *listener, void *data) { struct roots_view *view = roots_surface->view; struct roots_input *input = view->desktop->server->input; struct wlr_wl_shell_surface_move_event *e = data; - const struct roots_input_event *event = get_input_event(input, e->serial); - if (!event || input->mode != ROOTS_CURSOR_PASSTHROUGH) { + struct roots_seat *seat = input_seat_from_wlr_seat(input, e->seat->seat); + if (!seat || seat->cursor->mode != ROOTS_CURSOR_PASSTHROUGH) { return; } - view_begin_move(input, event->cursor, view); + roots_seat_begin_move(seat, view); } static void handle_request_resize(struct wl_listener *listener, void *data) { @@ -42,11 +42,12 @@ static void handle_request_resize(struct wl_listener *listener, void *data) { struct roots_view *view = roots_surface->view; struct roots_input *input = view->desktop->server->input; struct wlr_wl_shell_surface_resize_event *e = data; - const struct roots_input_event *event = get_input_event(input, e->serial); - if (!event || input->mode != ROOTS_CURSOR_PASSTHROUGH) { + struct roots_seat *seat = input_seat_from_wlr_seat(input, e->seat->seat); + // TODO verify input event + if (!seat || seat->cursor->mode != ROOTS_CURSOR_PASSTHROUGH) { return; } - view_begin_resize(input, event->cursor, view, e->edges); + roots_seat_begin_resize(seat, view, e->edges); } static void handle_surface_commit(struct wl_listener *listener, void *data) { diff --git a/rootston/xdg_shell_v6.c b/rootston/xdg_shell_v6.c index ca33c582..4a694349 100644 --- a/rootston/xdg_shell_v6.c +++ b/rootston/xdg_shell_v6.c @@ -98,11 +98,12 @@ static void handle_request_move(struct wl_listener *listener, void *data) { struct roots_view *view = roots_xdg_surface->view; struct roots_input *input = view->desktop->server->input; struct wlr_xdg_toplevel_v6_move_event *e = data; - const struct roots_input_event *event = get_input_event(input, e->serial); - if (!event || input->mode != ROOTS_CURSOR_PASSTHROUGH) { + struct roots_seat *seat = input_seat_from_wlr_seat(input, e->seat->seat); + // TODO verify event serial + if (!seat || seat->cursor->mode != ROOTS_CURSOR_PASSTHROUGH) { return; } - view_begin_move(input, event->cursor, view); + roots_seat_begin_move(seat, view); } static void handle_request_resize(struct wl_listener *listener, void *data) { @@ -111,11 +112,12 @@ static void handle_request_resize(struct wl_listener *listener, void *data) { struct roots_view *view = roots_xdg_surface->view; struct roots_input *input = view->desktop->server->input; struct wlr_xdg_toplevel_v6_resize_event *e = data; - const struct roots_input_event *event = get_input_event(input, e->serial); - if (!event || input->mode != ROOTS_CURSOR_PASSTHROUGH) { + // TODO verify event serial + struct roots_seat *seat = input_seat_from_wlr_seat(input, e->seat->seat); + if (!seat || seat->cursor->mode != ROOTS_CURSOR_PASSTHROUGH) { return; } - view_begin_resize(input, event->cursor, view, e->edges); + roots_seat_begin_resize(seat, view, e->edges); } static void handle_commit(struct wl_listener *listener, void *data) { diff --git a/rootston/xwayland.c b/rootston/xwayland.c index e3fc1c84..b53b98a9 100644 --- a/rootston/xwayland.c +++ b/rootston/xwayland.c @@ -114,22 +114,8 @@ static void handle_request_configure(struct wl_listener *listener, void *data) { // seat based on seat pointer focus, but interactive moving and resizing is not // yet seat aware. Even then, we can only guess because X11 events don't give us // enough wayland info to know for sure. -static struct wlr_cursor *guess_cursor_for_view(struct roots_view *view) { - struct roots_input *input = view->desktop->server->input; - size_t len = sizeof(input->input_events) / sizeof(*input->input_events); - for (size_t i = 0; i < len; i++) { - struct wlr_cursor *cursor = input->input_events[i].cursor; - if (cursor) { - int width = view->xwayland_surface->surface->current->width; - int height = view->xwayland_surface->surface->current->height; - if (cursor->x > view->x && cursor->y > view->y && - cursor->x < view->x + width && - cursor->y < view->y + height) { - return cursor; - } - } - } - +static struct roots_seat *guess_seat_for_view(struct roots_view *view) { + // TODO return NULL; } @@ -137,28 +123,26 @@ static void handle_request_move(struct wl_listener *listener, void *data) { struct roots_xwayland_surface *roots_surface = wl_container_of(listener, roots_surface, request_move); struct roots_view *view = roots_surface->view; - struct roots_input *input = view->desktop->server->input; - struct wlr_cursor *cursor = guess_cursor_for_view(view); + struct roots_seat *seat = guess_seat_for_view(view); - if (!cursor || input->mode != ROOTS_CURSOR_PASSTHROUGH) { + if (!seat || seat->cursor->mode != ROOTS_CURSOR_PASSTHROUGH) { return; } - view_begin_move(input, cursor, view); + roots_seat_begin_move(seat, view); } static void handle_request_resize(struct wl_listener *listener, void *data) { struct roots_xwayland_surface *roots_surface = wl_container_of(listener, roots_surface, request_resize); struct roots_view *view = roots_surface->view; - struct roots_input *input = view->desktop->server->input; - struct wlr_cursor *cursor = guess_cursor_for_view(view); + struct roots_seat *seat = guess_seat_for_view(view); struct wlr_xwayland_resize_event *e = data; - if (!cursor || input->mode != ROOTS_CURSOR_PASSTHROUGH) { + if (!seat || seat->cursor->mode != ROOTS_CURSOR_PASSTHROUGH) { return; } - view_begin_resize(input, cursor, view, e->edges); + roots_seat_begin_resize(seat, view, e->edges); } static void handle_map_notify(struct wl_listener *listener, void *data) { diff --git a/types/wlr_wl_shell.c b/types/wlr_wl_shell.c index fe61075e..ce32d186 100644 --- a/types/wlr_wl_shell.c +++ b/types/wlr_wl_shell.c @@ -110,7 +110,7 @@ static void shell_surface_protocol_move(struct wl_client *client, uint32_t serial) { wlr_log(L_DEBUG, "got shell surface move"); struct wlr_wl_shell_surface *surface = wl_resource_get_user_data(resource); - struct wlr_seat_handle *seat_handle = + struct wlr_seat_client *seat = wl_resource_get_user_data(seat_resource); struct wlr_wl_shell_surface_move_event *event = @@ -121,7 +121,7 @@ static void shell_surface_protocol_move(struct wl_client *client, } event->client = client; event->surface = surface; - event->seat_handle = seat_handle; + event->seat = seat; event->serial = serial; wl_signal_emit(&surface->events.request_move, event); @@ -177,7 +177,7 @@ static void shell_surface_protocol_resize(struct wl_client *client, uint32_t serial, enum wl_shell_surface_resize edges) { wlr_log(L_DEBUG, "got shell surface resize"); struct wlr_wl_shell_surface *surface = wl_resource_get_user_data(resource); - struct wlr_seat_handle *seat_handle = + struct wlr_seat_client *seat = wl_resource_get_user_data(seat_resource); struct wlr_wl_shell_surface_resize_event *event = @@ -188,7 +188,7 @@ static void shell_surface_protocol_resize(struct wl_client *client, } event->client = client; event->surface = surface; - event->seat_handle = seat_handle; + event->seat = seat; event->serial = serial; event->edges = edges; diff --git a/types/wlr_xdg_shell_v6.c b/types/wlr_xdg_shell_v6.c index fc45bc17..0c41b66f 100644 --- a/types/wlr_xdg_shell_v6.c +++ b/types/wlr_xdg_shell_v6.c @@ -557,7 +557,7 @@ static void xdg_toplevel_protocol_show_window_menu(struct wl_client *client, struct wl_resource *resource, struct wl_resource *seat_resource, uint32_t serial, int32_t x, int32_t y) { struct wlr_xdg_surface_v6 *surface = wl_resource_get_user_data(resource); - struct wlr_seat_handle *seat_handle = + struct wlr_seat_client *seat = wl_resource_get_user_data(seat_resource); if (!surface->configured) { @@ -576,7 +576,7 @@ static void xdg_toplevel_protocol_show_window_menu(struct wl_client *client, event->client = client; event->surface = surface; - event->seat_handle = seat_handle; + event->seat = seat; event->serial = serial; event->x = x; event->y = y; @@ -590,7 +590,7 @@ static void xdg_toplevel_protocol_move(struct wl_client *client, struct wl_resource *resource, struct wl_resource *seat_resource, uint32_t serial) { struct wlr_xdg_surface_v6 *surface = wl_resource_get_user_data(resource); - struct wlr_seat_handle *seat_handle = + struct wlr_seat_client *seat = wl_resource_get_user_data(seat_resource); if (!surface->configured) { @@ -609,7 +609,7 @@ static void xdg_toplevel_protocol_move(struct wl_client *client, event->client = client; event->surface = surface; - event->seat_handle = seat_handle; + event->seat = seat; event->serial = serial; wl_signal_emit(&surface->events.request_move, event); @@ -621,7 +621,7 @@ static void xdg_toplevel_protocol_resize(struct wl_client *client, struct wl_resource *resource, struct wl_resource *seat_resource, uint32_t serial, uint32_t edges) { struct wlr_xdg_surface_v6 *surface = wl_resource_get_user_data(resource); - struct wlr_seat_handle *seat_handle = + struct wlr_seat_client *seat = wl_resource_get_user_data(seat_resource); if (!surface->configured) { @@ -640,7 +640,7 @@ static void xdg_toplevel_protocol_resize(struct wl_client *client, event->client = client; event->surface = surface; - event->seat_handle = seat_handle; + event->seat = seat; event->serial = serial; event->edges = edges;