diff --git a/include/slurp.h b/include/slurp.h index ec76976..004cbea 100644 --- a/include/slurp.h +++ b/include/slurp.h @@ -22,7 +22,6 @@ struct slurp_state { struct wl_compositor *compositor; struct zwlr_layer_shell_v1 *layer_shell; struct wl_list outputs; // slurp_output::link - struct wl_list pointers; // slurp_pointer::link struct wl_list seats; // slurp_seat::link struct { @@ -59,25 +58,23 @@ struct slurp_output { struct wl_cursor_image *cursor_image; }; -struct slurp_pointer { +struct slurp_seat { + struct wl_surface *cursor_surface; struct slurp_state *state; - struct wl_pointer *wl_pointer; - struct wl_list link; // slurp_state::pointers + struct wl_seat *wl_seat; + struct wl_list link; // slurp_state::seats - int32_t x, y; - int32_t pressed_x, pressed_y; + // keyboard: + struct wl_keyboard *wl_keyboard; + + // pointer: + struct wl_pointer *wl_pointer; enum wl_pointer_button_state button_state; struct slurp_output *current_output; - - struct wl_surface *cursor_surface; -}; - -struct slurp_seat { - struct wl_seat *wl_seat; - struct wl_list link; // slurp_state::seats + int32_t x, y; + int32_t pressed_x, pressed_y; }; -void pointer_get_box(struct slurp_pointer *pointer, int *x, int *y, - int *width, int *height); +void seat_get_box(struct slurp_seat *seat, struct slurp_box *result); #endif diff --git a/main.c b/main.c index 91a23d5..e097e7e 100644 --- a/main.c +++ b/main.c @@ -23,67 +23,66 @@ static struct slurp_output *output_from_surface(struct slurp_state *state, static void pointer_handle_enter(void *data, struct wl_pointer *wl_pointer, uint32_t serial, struct wl_surface *surface, wl_fixed_t surface_x, wl_fixed_t surface_y) { - struct slurp_pointer *pointer = data; - struct slurp_output *output = output_from_surface(pointer->state, surface); + struct slurp_seat *seat = data; + struct slurp_output *output = output_from_surface(seat->state, surface); if (output == NULL) { return; } - pointer->x = wl_fixed_to_int(surface_x); - pointer->y = wl_fixed_to_int(surface_y); + seat->x = wl_fixed_to_int(surface_x); + seat->y = wl_fixed_to_int(surface_y); // TODO: handle multiple overlapping outputs - pointer->current_output = output; + seat->current_output = output; - wl_surface_set_buffer_scale(pointer->cursor_surface, output->scale); - wl_surface_attach(pointer->cursor_surface, + wl_surface_set_buffer_scale(seat->cursor_surface, output->scale); + wl_surface_attach(seat->cursor_surface, wl_cursor_image_get_buffer(output->cursor_image), 0, 0); - wl_pointer_set_cursor(wl_pointer, serial, pointer->cursor_surface, + wl_pointer_set_cursor(wl_pointer, serial, seat->cursor_surface, output->cursor_image->hotspot_x / output->scale, output->cursor_image->hotspot_y / output->scale); - wl_surface_commit(pointer->cursor_surface); + wl_surface_commit(seat->cursor_surface); } static void pointer_handle_leave(void *data, struct wl_pointer *wl_pointer, uint32_t serial, struct wl_surface *surface) { - struct slurp_pointer *pointer = data; + struct slurp_seat *seat = data; // TODO: handle multiple overlapping outputs - pointer->current_output = NULL; + seat->current_output = NULL; } static void pointer_handle_motion(void *data, struct wl_pointer *wl_pointer, uint32_t time, wl_fixed_t surface_x, wl_fixed_t surface_y) { - struct slurp_pointer *pointer = data; + struct slurp_seat *seat = data; - pointer->x = wl_fixed_to_int(surface_x); - pointer->y = wl_fixed_to_int(surface_y); + seat->x = wl_fixed_to_int(surface_x); + seat->y = wl_fixed_to_int(surface_y); - if (pointer->button_state == WL_POINTER_BUTTON_STATE_PRESSED && - pointer->current_output != NULL) { - set_output_dirty(pointer->current_output); + if (seat->button_state == WL_POINTER_BUTTON_STATE_PRESSED && + seat->current_output != NULL) { + set_output_dirty(seat->current_output); } } static void pointer_handle_button(void *data, struct wl_pointer *wl_pointer, uint32_t serial, uint32_t time, uint32_t button, uint32_t button_state) { - struct slurp_pointer *pointer = data; - struct slurp_state *state = pointer->state; + struct slurp_seat *seat = data; + struct slurp_state *state = seat->state; - pointer->button_state = button_state; + seat->button_state = button_state; switch (button_state) { case WL_POINTER_BUTTON_STATE_PRESSED: - pointer->pressed_x = pointer->x; - pointer->pressed_y = pointer->y; + seat->pressed_x = seat->x; + seat->pressed_y = seat->y; break; case WL_POINTER_BUTTON_STATE_RELEASED: - pointer_get_box(pointer, &state->result.x, &state->result.y, - &state->result.width, &state->result.height); - if (pointer->current_output != NULL) { - state->result.x += pointer->current_output->geometry.x; - state->result.y += pointer->current_output->geometry.y; + seat_get_box(seat, &state->result); + if (seat->current_output != NULL) { + state->result.x += seat->current_output->geometry.x; + state->result.y += seat->current_output->geometry.y; } state->running = false; break; @@ -98,47 +97,48 @@ static const struct wl_pointer_listener pointer_listener = { .axis = noop, }; -static void create_pointer(struct slurp_state *state, - struct wl_pointer *wl_pointer) { - struct slurp_pointer *pointer = calloc(1, sizeof(struct slurp_pointer)); - if (pointer == NULL) { - fprintf(stderr, "allocation failed\n"); - return; - } - pointer->state = state; - pointer->wl_pointer = wl_pointer; - wl_list_insert(&state->pointers, &pointer->link); - - wl_pointer_add_listener(wl_pointer, &pointer_listener, pointer); +static int min(int a, int b) { + return (a < b) ? a : b; } -static void destroy_pointer(struct slurp_pointer *pointer) { - wl_list_remove(&pointer->link); - wl_surface_destroy(pointer->cursor_surface); - wl_pointer_destroy(pointer->wl_pointer); - free(pointer); +void seat_get_box(struct slurp_seat *seat, struct slurp_box *result) { + result->x = min(seat->pressed_x, seat->x); + result->y = min(seat->pressed_y, seat->y); + result->width = abs(seat->x - seat->pressed_x); + result->height = abs(seat->y - seat->pressed_y); } -static int min(int a, int b) { - return (a < b) ? a : b; +static void keyboard_handle_key(void *data, struct wl_keyboard *wl_keyboard, + uint32_t serial, uint32_t time, uint32_t key, uint32_t key_state) { + struct slurp_seat *seat = data; + struct slurp_state *state = seat->state; + if (key_state == WL_KEYBOARD_KEY_STATE_PRESSED) { + if (key == KEY_ESC) { + state->running = false; + } + } } -void pointer_get_box(struct slurp_pointer *pointer, int *x, int *y, - int *width, int *height) { - *x = min(pointer->pressed_x, pointer->x); - *y = min(pointer->pressed_y, pointer->y); - *width = abs(pointer->x - pointer->pressed_x); - *height = abs(pointer->y - pointer->pressed_y); -} +static const struct wl_keyboard_listener keyboard_listener = { + .keymap = noop, + .enter = noop, + .leave = noop, + .key = keyboard_handle_key, + .modifiers = noop, +}; -static void seat_handle_capabilities(void *data, struct wl_seat *seat, +static void seat_handle_capabilities(void *data, struct wl_seat *wl_seat, uint32_t capabilities) { - struct slurp_state *state = data; + struct slurp_seat *seat = data; if (capabilities & WL_SEAT_CAPABILITY_POINTER) { - struct wl_pointer *wl_pointer = wl_seat_get_pointer(seat); - create_pointer(state, wl_pointer); + seat->wl_pointer = wl_seat_get_pointer(wl_seat); + wl_pointer_add_listener(seat->wl_pointer, &pointer_listener, seat); + } + if (capabilities & WL_SEAT_CAPABILITY_KEYBOARD) { + seat->wl_keyboard = wl_seat_get_keyboard(wl_seat); + wl_keyboard_add_listener(seat->wl_keyboard, &keyboard_listener, seat); } } @@ -152,13 +152,21 @@ static void create_seat(struct slurp_state *state, struct wl_seat *wl_seat) { fprintf(stderr, "allocation failed\n"); return; } + seat->state = state; seat->wl_seat = wl_seat; wl_list_insert(&state->seats, &seat->link); - wl_seat_add_listener(wl_seat, &seat_listener, state); + wl_seat_add_listener(wl_seat, &seat_listener, seat); } static void destroy_seat(struct slurp_seat *seat) { wl_list_remove(&seat->link); + wl_surface_destroy(seat->cursor_surface); + if (seat->wl_pointer) { + wl_pointer_destroy(seat->wl_pointer); + } + if (seat->wl_keyboard) { + wl_keyboard_destroy(seat->wl_keyboard); + } wl_seat_destroy(seat->wl_seat); free(seat); } @@ -417,7 +425,6 @@ int main(int argc, char *argv[]) { } wl_list_init(&state.outputs); - wl_list_init(&state.pointers); wl_list_init(&state.seats); state.display = wl_display_connect(NULL); @@ -464,6 +471,7 @@ int main(int argc, char *argv[]) { ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT | ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT | ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM); + zwlr_layer_surface_v1_set_keyboard_interactivity(output->layer_surface, true); zwlr_layer_surface_v1_set_exclusive_zone(output->layer_surface, -1); wl_surface_commit(output->surface); @@ -487,9 +495,9 @@ int main(int argc, char *argv[]) { output->cursor_image = cursor->images[0]; } - struct slurp_pointer *pointer; - wl_list_for_each(pointer, &state.pointers, link) { - pointer->cursor_surface = + struct slurp_seat *seat; + wl_list_for_each(seat, &state.seats, link) { + seat->cursor_surface = wl_compositor_create_surface(state.compositor); } @@ -498,15 +506,11 @@ int main(int argc, char *argv[]) { // This space intentionally left blank } - struct slurp_pointer *pointer_tmp; - wl_list_for_each_safe(pointer, pointer_tmp, &state.pointers, link) { - destroy_pointer(pointer); - } struct slurp_output *output_tmp; wl_list_for_each_safe(output, output_tmp, &state.outputs, link) { destroy_output(output); } - struct slurp_seat *seat, *seat_tmp; + struct slurp_seat *seat_tmp; wl_list_for_each_safe(seat, seat_tmp, &state.seats, link) { destroy_seat(seat); } diff --git a/render.c b/render.c index 22e0350..efd59c7 100644 --- a/render.c +++ b/render.c @@ -25,26 +25,27 @@ void render(struct slurp_output *output) { set_source_u32(cairo, state->colors.background); cairo_paint(cairo); - struct slurp_pointer *pointer; - wl_list_for_each(pointer, &state->pointers, link) { - if (pointer->button_state != WL_POINTER_BUTTON_STATE_PRESSED || - pointer->current_output != output) { + struct slurp_seat *seat; + wl_list_for_each(seat, &state->seats, link) { + if (!seat->wl_pointer) continue; + if (seat->button_state != WL_POINTER_BUTTON_STATE_PRESSED || + seat->current_output != output) { continue; } - int x, y, width, height; - pointer_get_box(pointer, &x, &y, &width, &height); + struct slurp_box b; + seat_get_box(seat, &b); // Draw border set_source_u32(cairo, state->colors.selection); - cairo_rectangle(cairo, x * scale, y * scale, - width * scale, height * scale); + cairo_rectangle(cairo, b.x * scale, b.y * scale, + b.width * scale, b.height * scale); cairo_fill(cairo); set_source_u32(cairo, state->colors.border); cairo_set_line_width(cairo, state->border_weight * scale); - cairo_rectangle(cairo, x * scale, y * scale, - width * scale, height * scale); + cairo_rectangle(cairo, b.x * scale, b.y * scale, + b.width * scale, b.height * scale); cairo_stroke(cairo); if (state->display_dimensions) { @@ -53,8 +54,8 @@ void render(struct slurp_output *output) { cairo_set_font_size(cairo, 14 * scale); // buffer of 12 can hold selections up to 99999x99999 char dimensions[12]; - snprintf(dimensions, sizeof(dimensions), "%ix%i", width, height); - cairo_move_to(cairo, (x + width + 10) * scale, (y + height + 20) * scale); + snprintf(dimensions, sizeof(dimensions), "%ix%i", b.width, b.height); + cairo_move_to(cairo, (b.x + b.width + 10) * scale, (b.y + b.height + 20) * scale); cairo_show_text(cairo, dimensions); } }