#include #include #include #include #include #include #include #include #include #include static void motion_absolute_handler(struct wl_listener *listener, void *data); static void frame_handler(struct wl_listener *listener, void *data); static void motion_handler(struct wl_listener *listener, void *data); static void button_handler(struct wl_listener *listener, void *data); static void axis_handler(struct wl_listener *listener, void *data); static void request_set_cursor_handler(struct wl_listener *listener, void *data); static void surface_destroy_handler(struct wl_listener *listener, void *data); static unsigned long get_cursor_size(void) { const char *cursor_size = getenv("XCURSOR_SIZE"); if (cursor_size != NULL && strlen(cursor_size) > 0) { errno = 0; char *end; unsigned long size = strtoul(cursor_size, &end, 10); if (*end == '\0' && errno == 0) { return size; } } setenv("XCURSOR_SIZE", "16", 1); return 16; } static const char * get_cursor_theme(void) { char *cursor_theme = getenv("XCURSOR_THEME"); if (cursor_theme != NULL && strlen(cursor_theme) > 0) { return cursor_theme; } setenv("XCURSOR_THEME", "Adwaita", 1); return "Adwaita"; } static void configure_bindings(struct hikari_cursor *cursor, struct wl_list *bindings) { int nr[256] = { 0 }; struct hikari_binding_config *binding_config; wl_list_for_each (binding_config, bindings, link) { nr[binding_config->key.modifiers]++; } for (int mask = 0; mask < 256; mask++) { cursor->bindings[mask].nbindings = nr[mask]; if (nr[mask] != 0) { cursor->bindings[mask].bindings = hikari_calloc(nr[mask], sizeof(struct hikari_binding)); } else { cursor->bindings[mask].bindings = NULL; } nr[mask] = 0; } wl_list_for_each (binding_config, bindings, link) { uint8_t mask = binding_config->key.modifiers; struct hikari_binding *binding = &cursor->bindings[mask].bindings[nr[mask]]; binding->action = &binding_config->action; switch (binding_config->key.type) { case HIKARI_ACTION_BINDING_KEY_KEYCODE: binding->keycode = binding_config->key.value.keycode; break; case HIKARI_ACTION_BINDING_KEY_KEYSYM: assert(false); break; } nr[mask]++; } } void hikari_cursor_init( struct hikari_cursor *cursor, struct wlr_output_layout *output_layout) { struct wlr_cursor *wlr_cursor = wlr_cursor_create(); wlr_cursor_attach_output_layout(wlr_cursor, output_layout); const char *cursor_theme = get_cursor_theme(); unsigned long cursor_size = get_cursor_size(); cursor->cursor_mgr = wlr_xcursor_manager_create(cursor_theme, cursor_size); wlr_xcursor_manager_load(cursor->cursor_mgr, 1); cursor->wlr_cursor = wlr_cursor; wl_list_init(&cursor->surface_destroy.link); hikari_binding_group_init(cursor->bindings); } void hikari_cursor_configure_bindings( struct hikari_cursor *cursor, struct wl_list *bindings) { hikari_binding_group_fini(cursor->bindings); hikari_binding_group_init(cursor->bindings); configure_bindings(cursor, bindings); } void hikari_cursor_fini(struct hikari_cursor *cursor) { hikari_binding_group_fini(cursor->bindings); hikari_cursor_deactivate(cursor); wlr_xcursor_manager_destroy(cursor->cursor_mgr); } void hikari_cursor_activate(struct hikari_cursor *cursor) { struct wlr_cursor *wlr_cursor = cursor->wlr_cursor; cursor->motion_absolute.notify = motion_absolute_handler; wl_signal_add(&wlr_cursor->events.motion_absolute, &cursor->motion_absolute); cursor->frame.notify = frame_handler; wl_signal_add(&wlr_cursor->events.frame, &cursor->frame); cursor->motion.notify = motion_handler; wl_signal_add(&wlr_cursor->events.motion, &cursor->motion); cursor->button.notify = button_handler; wl_signal_add(&wlr_cursor->events.button, &cursor->button); cursor->axis.notify = axis_handler; wl_signal_add(&wlr_cursor->events.axis, &cursor->axis); cursor->request_set_cursor.notify = request_set_cursor_handler; wl_signal_add(&hikari_server.seat->events.request_set_cursor, &cursor->request_set_cursor); hikari_cursor_reset_image(cursor); } void hikari_cursor_deactivate(struct hikari_cursor *cursor) { wl_list_remove(&cursor->motion_absolute.link); wl_list_remove(&cursor->frame.link); wl_list_remove(&cursor->motion.link); wl_list_remove(&cursor->button.link); wl_list_remove(&cursor->axis.link); wl_list_remove(&cursor->request_set_cursor.link); hikari_cursor_set_image(cursor, NULL); } void hikari_cursor_set_image(struct hikari_cursor *cursor, const char *path) { wl_list_remove(&cursor->surface_destroy.link); wl_list_init(&cursor->surface_destroy.link); if (path != NULL) { wlr_xcursor_manager_set_cursor_image( cursor->cursor_mgr, path, cursor->wlr_cursor); } else { wlr_cursor_set_image(cursor->wlr_cursor, NULL, 0, 0, 0, 0, 0, 0); } } void hikari_cursor_center(struct hikari_cursor *cursor, struct hikari_output *output, struct wlr_box *geometry) { int x = output->geometry.x + geometry->x + geometry->width / 2; int y = output->geometry.y + geometry->y + geometry->height / 2; hikari_cursor_warp(cursor, x, y); } static void motion_absolute_handler(struct wl_listener *listener, void *data) { struct hikari_cursor *cursor = wl_container_of(listener, cursor, motion_absolute); assert(!hikari_server_in_lock_mode()); struct wlr_event_pointer_motion_absolute *event = data; wlr_cursor_warp_absolute( cursor->wlr_cursor, event->device, event->x, event->y); hikari_server.mode->cursor_move(event->time_msec); } static void frame_handler(struct wl_listener *listener, void *data) { assert(!hikari_server_in_lock_mode()); wlr_seat_pointer_notify_frame(hikari_server.seat); } static void motion_handler(struct wl_listener *listener, void *data) { struct hikari_cursor *cursor = wl_container_of(listener, cursor, motion); assert(!hikari_server_in_lock_mode()); struct wlr_event_pointer_motion *event = data; wlr_cursor_move( cursor->wlr_cursor, event->device, event->delta_x, event->delta_y); hikari_server.mode->cursor_move(event->time_msec); } static void button_handler(struct wl_listener *listener, void *data) { assert(!hikari_server_in_lock_mode()); struct hikari_cursor *cursor = wl_container_of(listener, cursor, button); struct wlr_event_pointer_button *event = data; hikari_server.mode->button_handler(cursor, event); } static void axis_handler(struct wl_listener *listener, void *data) { assert(!hikari_server_in_lock_mode()); struct wlr_event_pointer_axis *event = data; wlr_seat_pointer_notify_axis(hikari_server.seat, event->time_msec, event->orientation, event->delta, event->delta_discrete, event->source); } static void request_set_cursor_handler(struct wl_listener *listener, void *data) { if (!hikari_server_in_normal_mode()) { return; } struct hikari_cursor *cursor = wl_container_of(listener, cursor, request_set_cursor); struct hikari_server *server = &hikari_server; struct wlr_seat_pointer_request_set_cursor_event *event = data; struct wlr_seat *seat = server->seat; struct wl_client *focused_client = NULL; struct wlr_surface *focused_surface = seat->pointer_state.focused_surface; if (focused_surface != NULL) { focused_client = wl_resource_get_client(focused_surface->resource); } if (focused_client == NULL || event->seat_client->client != focused_client) { return; } struct wlr_surface *surface = event->surface; wl_list_remove(&cursor->surface_destroy.link); if (surface != NULL) { cursor->surface_destroy.notify = surface_destroy_handler; wl_signal_add(&surface->events.destroy, &cursor->surface_destroy); } else { wl_list_init(&cursor->surface_destroy.link); } wlr_cursor_set_surface( cursor->wlr_cursor, surface, event->hotspot_x, event->hotspot_y); } static void surface_destroy_handler(struct wl_listener *listener, void *data) { struct hikari_cursor *cursor = wl_container_of(listener, cursor, surface_destroy); hikari_cursor_reset_image(cursor); }