diff options
-rw-r--r-- | examples/layer-shell.c | 150 | ||||
-rw-r--r-- | examples/meson.build | 3 | ||||
-rw-r--r-- | include/rootston/desktop.h | 7 | ||||
-rw-r--r-- | include/rootston/output.h | 1 | ||||
-rw-r--r-- | rootston/cursor.c | 122 | ||||
-rw-r--r-- | rootston/desktop.c | 82 |
6 files changed, 288 insertions, 77 deletions
diff --git a/examples/layer-shell.c b/examples/layer-shell.c index 70407888..89fa9ea9 100644 --- a/examples/layer-shell.c +++ b/examples/layer-shell.c @@ -7,12 +7,17 @@ #include <time.h> #include <unistd.h> #include <wayland-client.h> +#include <wayland-cursor.h> #include <wayland-egl.h> #include <wlr/render/egl.h> #include <wlr/util/log.h> #include "wlr-layer-shell-unstable-v1-client-protocol.h" static struct wl_compositor *compositor = NULL; +static struct wl_seat *seat = NULL; +static struct wl_shm *shm = NULL; +static struct wl_pointer *pointer = NULL; +//static struct wl_keyboard *keyboard = NULL; static struct zwlr_layer_shell_v1 *layer_shell = NULL; struct zwlr_layer_surface_v1 *layer_surface; static struct wl_output *wl_output = NULL; @@ -32,6 +37,12 @@ static double alpha = 1.0; static bool run_display = true; static bool animate = false; static double frame = 0; +static int cur_x = -1, cur_y = -1; +static int buttons = 0; + +struct wl_cursor_theme *cursor_theme; +struct wl_cursor_image *cursor_image; +struct wl_surface *cursor_surface; static struct { struct timespec last_frame; @@ -62,13 +73,15 @@ static void draw(void) { (ts.tv_nsec - demo.last_frame.tv_nsec) / 1000000; int inc = (demo.dec + 1) % 3; - demo.color[inc] += ms / 2000.0f; - demo.color[demo.dec] -= ms / 2000.0f; + if (!buttons) { + demo.color[inc] += ms / 2000.0f; + demo.color[demo.dec] -= ms / 2000.0f; - if (demo.color[demo.dec] < 0.0f) { - demo.color[inc] = 1.0f; - demo.color[demo.dec] = 0.0f; - demo.dec = inc; + if (demo.color[demo.dec] < 0.0f) { + demo.color[inc] = 1.0f; + demo.color[demo.dec] = 0.0f; + demo.dec = inc; + } } if (animate) { @@ -83,9 +96,21 @@ static void draw(void) { } glViewport(0, 0, width, height); - glClearColor(demo.color[0], demo.color[1], demo.color[2], alpha); + if (buttons) { + glClearColor(1, 1, 1, alpha); + } else { + glClearColor(demo.color[0], demo.color[1], demo.color[2], alpha); + } glClear(GL_COLOR_BUFFER_BIT); + if (cur_x != -1 && cur_y != -1) { + glEnable(GL_SCISSOR_TEST); + glScissor(cur_x, height - cur_y, 5, 5); + glClearColor(0, 0, 0, 1); + glClear(GL_COLOR_BUFFER_BIT); + glDisable(GL_SCISSOR_TEST); + } + frame_callback = wl_surface_frame(wl_surface); wl_callback_add_listener(frame_callback, &frame_listener, NULL); @@ -119,11 +144,102 @@ struct zwlr_layer_surface_v1_listener layer_surface_listener = { .closed = layer_surface_closed, }; +static void wl_pointer_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) { + wl_surface_attach(cursor_surface, + wl_cursor_image_get_buffer(cursor_image), 0, 0); + wl_pointer_set_cursor(wl_pointer, serial, cursor_surface, + cursor_image->hotspot_x, cursor_image->hotspot_y); + wl_surface_commit(cursor_surface); +} + +static void wl_pointer_leave(void *data, struct wl_pointer *wl_pointer, + uint32_t serial, struct wl_surface *surface) { + cur_x = cur_y = -1; + buttons = 0; +} + +static void wl_pointer_motion(void *data, struct wl_pointer *wl_pointer, + uint32_t time, wl_fixed_t surface_x, wl_fixed_t surface_y) { + cur_x = wl_fixed_to_int(surface_x); + cur_y = wl_fixed_to_int(surface_y); +} + +static void wl_pointer_button(void *data, struct wl_pointer *wl_pointer, + uint32_t serial, uint32_t time, uint32_t button, uint32_t state) { + if (state == WL_POINTER_BUTTON_STATE_PRESSED) { + buttons++; + } else { + buttons--; + } +} + +static void wl_pointer_axis(void *data, struct wl_pointer *wl_pointer, + uint32_t time, uint32_t axis, wl_fixed_t value) { + // Who cares +} + +static void wl_pointer_frame(void *data, struct wl_pointer *wl_pointer) { + // Who cares +} + +static void wl_pointer_axis_source(void *data, struct wl_pointer *wl_pointer, + uint32_t axis_source) { + // Who cares +} + +static void wl_pointer_axis_stop(void *data, struct wl_pointer *wl_pointer, + uint32_t time, uint32_t axis) { + // Who cares +} + +static void wl_pointer_axis_discrete(void *data, struct wl_pointer *wl_pointer, + uint32_t axis, int32_t discrete) { + // Who cares +} + +struct wl_pointer_listener pointer_listener = { + .enter = wl_pointer_enter, + .leave = wl_pointer_leave, + .motion = wl_pointer_motion, + .button = wl_pointer_button, + .axis = wl_pointer_axis, + .frame = wl_pointer_frame, + .axis_source = wl_pointer_axis_source, + .axis_stop = wl_pointer_axis_stop, + .axis_discrete = wl_pointer_axis_discrete, +}; + +static void seat_handle_capabilities(void *data, struct wl_seat *wl_seat, + enum wl_seat_capability caps) { + if ((caps & WL_SEAT_CAPABILITY_POINTER)) { + pointer = wl_seat_get_pointer(wl_seat); + wl_pointer_add_listener(pointer, &pointer_listener, NULL); + } + if ((caps & WL_SEAT_CAPABILITY_KEYBOARD)) { + // TODO + } +} + +static void seat_handle_name(void *data, struct wl_seat *wl_seat, + const char *name) { + // Who cares +} + +const struct wl_seat_listener seat_listener = { + .capabilities = seat_handle_capabilities, + .name = seat_handle_name, +}; + static void handle_global(void *data, struct wl_registry *registry, uint32_t name, const char *interface, uint32_t version) { if (strcmp(interface, "wl_compositor") == 0) { compositor = wl_registry_bind(registry, name, &wl_compositor_interface, 1); + } else if (strcmp(interface, wl_shm_interface.name) == 0) { + shm = wl_registry_bind(registry, name, + &wl_shm_interface, 1); } else if (strcmp(interface, "wl_output") == 0) { if (output == 0 && !wl_output) { wl_output = wl_registry_bind(registry, name, @@ -131,6 +247,10 @@ static void handle_global(void *data, struct wl_registry *registry, } else { output--; } + } else if (strcmp(interface, wl_seat_interface.name) == 0) { + seat = wl_registry_bind(registry, name, + &wl_seat_interface, 1); + wl_seat_add_listener(seat, &seat_listener, NULL); } else if (strcmp(interface, zwlr_layer_shell_v1_interface.name) == 0) { layer_shell = wl_registry_bind( registry, name, &zwlr_layer_shell_v1_interface, 1); @@ -250,11 +370,15 @@ int main(int argc, char **argv) { wl_display_roundtrip(display); if (compositor == NULL) { - fprintf(stderr, "wl-compositor not available\n"); + fprintf(stderr, "wl_compositor not available\n"); + return 1; + } + if (shm == NULL) { + fprintf(stderr, "wl_shm not available\n"); return 1; } if (layer_shell == NULL) { - fprintf(stderr, "layer-shell not available\n"); + fprintf(stderr, "layer_shell not available\n"); return 1; } if (wl_output == NULL) { @@ -262,6 +386,12 @@ int main(int argc, char **argv) { return 1; } + assert(cursor_theme = wl_cursor_theme_load(NULL, 16, shm)); + struct wl_cursor *cursor; + assert(cursor = wl_cursor_theme_get_cursor(cursor_theme, "left_ptr")); + cursor_image = cursor->images[0]; + assert(cursor_surface = wl_compositor_create_surface(compositor)); + EGLint attribs[] = { EGL_ALPHA_SIZE, 8, EGL_NONE }; wlr_egl_init(&egl, EGL_PLATFORM_WAYLAND_EXT, display, attribs, WL_SHM_FORMAT_ARGB8888); @@ -294,5 +424,7 @@ int main(int argc, char **argv) { while (wl_display_dispatch(display) != -1 && run_display) { // This space intentionally left blank } + + wl_cursor_theme_destroy(cursor_theme); return 0; } diff --git a/examples/meson.build b/examples/meson.build index 558af4ac..9e60c37a 100644 --- a/examples/meson.build +++ b/examples/meson.build @@ -6,6 +6,7 @@ lib_shared = static_library( ) threads = dependency('threads') +wayland_cursor = dependency('wayland-cursor') executable('simple', 'simple.c', dependencies: wlroots, link_with: lib_shared) executable('pointer', 'pointer.c', dependencies: wlroots, link_with: lib_shared) @@ -52,5 +53,5 @@ executable( executable( 'layer-shell', 'layer-shell.c', - dependencies: [wayland_client, wlr_protos, wlroots] + dependencies: [wayland_cursor, wayland_client, wlr_protos, wlroots] ) diff --git a/include/rootston/desktop.h b/include/rootston/desktop.h index 5714aa0a..c1dcad56 100644 --- a/include/rootston/desktop.h +++ b/include/rootston/desktop.h @@ -1,6 +1,5 @@ #ifndef ROOTSTON_DESKTOP_H #define ROOTSTON_DESKTOP_H - #include <time.h> #include <wayland-server.h> #include <wlr/config.h> @@ -73,8 +72,10 @@ struct roots_desktop *desktop_create(struct roots_server *server, void desktop_destroy(struct roots_desktop *desktop); struct roots_output *desktop_output_from_wlr_output( struct roots_desktop *desktop, struct wlr_output *output); -struct roots_view *desktop_view_at(struct roots_desktop *desktop, double lx, - double ly, struct wlr_surface **surface, double *sx, double *sy); + +struct wlr_surface *desktop_surface_at(struct roots_desktop *desktop, + double lx, double ly, double *sx, double *sy, + struct roots_view **view); struct roots_view *view_create(struct roots_desktop *desktop); void view_destroy(struct roots_view *view); diff --git a/include/rootston/output.h b/include/rootston/output.h index bf152038..f78ee81d 100644 --- a/include/rootston/output.h +++ b/include/rootston/output.h @@ -1,6 +1,5 @@ #ifndef ROOTSTON_OUTPUT_H #define ROOTSTON_OUTPUT_H - #include <pixman.h> #include <time.h> #include <wayland-server.h> diff --git a/rootston/cursor.c b/rootston/cursor.c index c794cbce..1ee195c2 100644 --- a/rootston/cursor.c +++ b/rootston/cursor.c @@ -10,6 +10,7 @@ #include <dev/evdev/input-event-codes.h> #endif #include "rootston/cursor.h" +#include "rootston/desktop.h" #include "rootston/xcursor.h" struct roots_cursor *roots_cursor_create(struct roots_seat *seat) { @@ -98,51 +99,59 @@ static void seat_view_deco_button(struct roots_seat_view *view, double sx, } } -static void roots_cursor_update_position(struct roots_cursor *cursor, +static void roots_passthrough_cursor(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 = NULL; double sx, sy; - switch (cursor->mode) { - case ROOTS_CURSOR_PASSTHROUGH: - view = desktop_view_at(desktop, cursor->cursor->x, cursor->cursor->y, - &surface, &sx, &sy); + struct roots_view *view = NULL; + struct roots_seat *seat = cursor->seat; + struct roots_desktop *desktop = seat->input->server->desktop; + struct wlr_surface *surface = desktop_surface_at(desktop, + cursor->cursor->x, cursor->cursor->y, &sx, &sy, &view); + struct wl_client *client = NULL; + if (surface) { + client = wl_resource_get_client(surface->resource); + } + + if (cursor->cursor_client != client) { + wlr_xcursor_manager_set_cursor_image(cursor->xcursor_manager, + cursor->default_xcursor, cursor->cursor); + cursor->cursor_client = client; + } + + if (view) { struct roots_seat_view *seat_view = roots_seat_view_from_view(seat, view); - if (cursor->pointer_view && (surface || seat_view != cursor->pointer_view)) { + if (cursor->pointer_view && (surface || + seat_view != cursor->pointer_view)) { seat_view_deco_leave(cursor->pointer_view); cursor->pointer_view = NULL; } - bool set_compositor_cursor = !view && !surface && cursor->cursor_client; - if (view && surface) { - 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) { - wlr_xcursor_manager_set_cursor_image(cursor->xcursor_manager, - cursor->default_xcursor, cursor->cursor); - cursor->cursor_client = NULL; - } - if (view && !surface) { - if (seat_view) { - cursor->pointer_view = seat_view; - seat_view_deco_motion(seat_view, sx, sy); - } - } if (view && surface) { - // motion over a view surface - 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); + if (!surface) { + cursor->pointer_view = seat_view; + seat_view_deco_motion(seat_view, sx, sy); } + } - struct roots_drag_icon *drag_icon; - wl_list_for_each(drag_icon, &seat->drag_icons, link) { - roots_drag_icon_update_position(drag_icon); - } + if (surface) { + 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); + } + + struct roots_drag_icon *drag_icon; + wl_list_for_each(drag_icon, &seat->drag_icons, link) { + roots_drag_icon_update_position(drag_icon); + } +} + +static void roots_cursor_update_position( + struct roots_cursor *cursor, uint32_t time) { + struct roots_seat *seat = cursor->seat; + struct roots_view *view; + switch (cursor->mode) { + case ROOTS_CURSOR_PASSTHROUGH: + roots_passthrough_cursor(cursor, time); break; case ROOTS_CURSOR_MOVE: view = roots_seat_get_focus(seat); @@ -180,15 +189,9 @@ static void roots_cursor_update_position(struct roots_cursor *cursor, } else if (cursor->resize_edges & WLR_EDGE_RIGHT) { width += dx; } - - if (width < 1) { - width = 1; - } - if (height < 1) { - height = 1; - } - - view_move_resize(view, x, y, width, height); + view_move_resize(view, x, y, + width < 1 ? 1 : width, + height < 1 ? 1 : height); } break; case ROOTS_CURSOR_ROTATE: @@ -214,15 +217,15 @@ static void roots_cursor_press_button(struct roots_cursor *cursor, uint32_t state, double lx, double ly) { struct roots_seat *seat = cursor->seat; struct roots_desktop *desktop = seat->input->server->desktop; + bool is_touch = device->type == WLR_INPUT_DEVICE_TOUCH; - struct wlr_surface *surface = NULL; double sx, sy; - struct roots_view *view = - desktop_view_at(desktop, lx, ly, &surface, &sx, &sy); + struct roots_view *view; + struct wlr_surface *surface = desktop_surface_at(desktop, + lx, ly, &sx, &sy, &view); - if (state == WLR_BUTTON_PRESSED && - view && + if (state == WLR_BUTTON_PRESSED && view && roots_seat_has_meta_pressed(seat)) { roots_seat_set_focus(seat, view); @@ -250,11 +253,9 @@ static void roots_cursor_press_button(struct roots_cursor *cursor, break; } } else { - - if (view && !surface) { - if (cursor->pointer_view) { - seat_view_deco_button(cursor->pointer_view, sx, sy, button, state); - } + if (view && !surface && cursor->pointer_view) { + seat_view_deco_button(cursor->pointer_view, + sx, sy, button, state); } if (state == WLR_BUTTON_RELEASED && @@ -308,7 +309,6 @@ void roots_cursor_handle_axis(struct roots_cursor *cursor, void roots_cursor_handle_touch_down(struct roots_cursor *cursor, struct wlr_event_touch_down *event) { struct roots_desktop *desktop = cursor->seat->input->server->desktop; - struct wlr_surface *surface = NULL; double lx, ly; bool result = wlr_cursor_absolute_to_layout_coords(cursor->cursor, event->device, event->x, event->y, &lx, &ly); @@ -316,7 +316,8 @@ void roots_cursor_handle_touch_down(struct roots_cursor *cursor, return; } double sx, sy; - desktop_view_at(desktop, lx, ly, &surface, &sx, &sy); + struct wlr_surface *surface = desktop_surface_at( + desktop, lx, ly, &sx, &sy, NULL); uint32_t serial = 0; if (surface) { @@ -359,17 +360,16 @@ void roots_cursor_handle_touch_motion(struct roots_cursor *cursor, return; } - struct wlr_surface *surface = NULL; double lx, ly; - bool result = - wlr_cursor_absolute_to_layout_coords(cursor->cursor, + bool result = wlr_cursor_absolute_to_layout_coords(cursor->cursor, event->device, event->x, event->y, &lx, &ly); if (!result) { return; } double sx, sy; - desktop_view_at(desktop, lx, ly, &surface, &sx, &sy); + struct wlr_surface *surface = desktop_surface_at( + desktop, lx, ly, &sx, &sy, NULL); if (surface) { wlr_seat_touch_point_focus(cursor->seat->seat, surface, diff --git a/rootston/desktop.c b/rootston/desktop.c index 15e0e336..7ee2c69a 100644 --- a/rootston/desktop.c +++ b/rootston/desktop.c @@ -20,10 +20,12 @@ #include <wlr/types/wlr_xdg_shell_v6.h> #include <wlr/types/wlr_xdg_shell.h> #include <wlr/util/log.h> +#include "rootston/layers.h" #include "rootston/seat.h" #include "rootston/server.h" #include "rootston/view.h" #include "rootston/xcursor.h" +#include "wlr-layer-shell-unstable-v1-protocol.h" struct roots_view *view_create(struct roots_desktop *desktop) { struct roots_view *view = calloc(1, sizeof(struct roots_view)); @@ -632,8 +634,9 @@ static bool view_at(struct roots_view *view, double lx, double ly, return false; } -struct roots_view *desktop_view_at(struct roots_desktop *desktop, double lx, - double ly, struct wlr_surface **surface, double *sx, double *sy) { +static struct roots_view *desktop_view_at(struct roots_desktop *desktop, + double lx, double ly, struct wlr_surface **surface, + double *sx, double *sy) { struct wlr_output *wlr_output = wlr_output_layout_output_at(desktop->layout, lx, ly); if (wlr_output != NULL) { @@ -657,6 +660,81 @@ struct roots_view *desktop_view_at(struct roots_desktop *desktop, double lx, return NULL; } +static struct wlr_surface *layer_surface_at(struct roots_output *output, + struct wl_list *layer, double ox, double oy, double *sx, double *sy) { + struct roots_layer_surface *roots_surface; + wl_list_for_each_reverse(roots_surface, layer, link) { + struct wlr_surface *wlr_surface = + roots_surface->layer_surface->surface; + double _sx = ox - roots_surface->geo.x; + double _sy = oy - roots_surface->geo.y; + struct wlr_box box = { + .x = roots_surface->geo.x, + .y = roots_surface->geo.y, + .width = wlr_surface->current->width, + .height = wlr_surface->current->height, + }; + // TODO: Test popups/subsurfaces + if (wlr_box_contains_point(&box, ox, oy) && + pixman_region32_contains_point(&wlr_surface->current->input, + _sx, _sy, NULL)) { + *sx = _sx; + *sy = _sy; + return wlr_surface; + } + } + return NULL; +} + +struct wlr_surface *desktop_surface_at(struct roots_desktop *desktop, + double lx, double ly, double *sx, double *sy, + struct roots_view **view) { + struct wlr_surface *surface = NULL; + struct wlr_output *wlr_output = + wlr_output_layout_output_at(desktop->layout, lx, ly); + struct roots_output *roots_output; + double ox = lx, oy = ly; + *view = NULL; + + if (wlr_output) { + roots_output = wlr_output->data; + wlr_output_layout_output_coords(desktop->layout, wlr_output, &ox, &oy); + + if ((surface = layer_surface_at(roots_output, + &roots_output->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY], + ox, oy, sx, sy))) { + return surface; + } + if ((surface = layer_surface_at(roots_output, + &roots_output->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP], + ox, oy, sx, sy))) { + return surface; + } + } + + struct roots_view *_view; + if ((_view = desktop_view_at(desktop, lx, ly, &surface, sx, sy))) { + if (view) { + *view = _view; + } + return surface; + } + + if (wlr_output) { + if ((surface = layer_surface_at(roots_output, + &roots_output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM], + ox, oy, sx, sy))) { + return surface; + } + if ((surface = layer_surface_at(roots_output, + &roots_output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND], + ox, oy, sx, sy))) { + return surface; + } + } + return NULL; +} + static void handle_layout_change(struct wl_listener *listener, void *data) { struct roots_desktop *desktop = wl_container_of(listener, desktop, layout_change); |