diff options
65 files changed, 2010 insertions, 252 deletions
@@ -25,6 +25,7 @@ Install dependencies: * udev * pixman * systemd (optional, for logind support) +* elogind (optional, for logind support on systems without systemd) * libcap (optional, for capability support) * asciidoc (optional, for man pages) diff --git a/backend/meson.build b/backend/meson.build index eb8c5d8b..a3cb7b64 100644 --- a/backend/meson.build +++ b/backend/meson.build @@ -28,9 +28,13 @@ if systemd.found() backend_files += files('session/logind.c') endif +if elogind.found() + backend_files += files('session/logind.c') +endif + lib_wlr_backend = static_library( 'wlr_backend', backend_files, include_directories: wlr_inc, - dependencies: [wayland_server, egl, gbm, libinput, systemd, wlr_protos], + dependencies: [wayland_server, egl, gbm, libinput, systemd, elogind, wlr_protos], ) diff --git a/backend/session/logind.c b/backend/session/logind.c index 3b237360..42b48e94 100644 --- a/backend/session/logind.c +++ b/backend/session/logind.c @@ -5,8 +5,6 @@ #include <stdlib.h> #include <string.h> #include <errno.h> -#include <systemd/sd-bus.h> -#include <systemd/sd-login.h> #include <unistd.h> #include <sys/sysmacros.h> #include <sys/stat.h> @@ -15,6 +13,14 @@ #include <wlr/backend/session/interface.h> #include <wlr/util/log.h> +#ifdef HAS_SYSTEMD + #include <systemd/sd-bus.h> + #include <systemd/sd-login.h> +#elif HAS_ELOGIND + #include <elogind/sd-bus.h> + #include <elogind/sd-login.h> +#endif + enum { DRM_MAJOR = 226 }; const struct session_impl session_logind; diff --git a/backend/session/session.c b/backend/session/session.c index c9bc1397..cfa617f6 100644 --- a/backend/session/session.c +++ b/backend/session/session.c @@ -18,6 +18,8 @@ extern const struct session_impl session_direct; static const struct session_impl *impls[] = { #ifdef HAS_SYSTEMD &session_logind, +#elif HAS_ELOGIND + &session_logind, #endif &session_direct, NULL, diff --git a/backend/wayland/output.c b/backend/wayland/output.c index e5079001..3e673bcc 100644 --- a/backend/wayland/output.c +++ b/backend/wayland/output.c @@ -7,7 +7,7 @@ #include <sys/types.h> #include <sys/mman.h> #include <wayland-client.h> -#include <GLES3/gl3.h> +#include <GLES2/gl2.h> #include <wlr/interfaces/wlr_output.h> #include <wlr/util/log.h> #include "backend/wayland.h" diff --git a/dist/archlinux/PKGBUILD b/dist/archlinux/PKGBUILD new file mode 100644 index 00000000..a65fc7ff --- /dev/null +++ b/dist/archlinux/PKGBUILD @@ -0,0 +1,48 @@ +pkgname=wlroots +pkgver=r600.d89272d +pkgrel=1 +license=('MIT') +pkgdesc='Wayland compositor library' +makedepends=("meson") +depends=( + "wayland" + "wayland-protocols" + "mesa" + "libdrm" + "libinput" + "libxkbcommon" + "libsystemd" + "pixman" + "libxcb" +) +arch=("x86_64") +url="https://github.com/SirCmpwn/wlroots" +source=("${pkgname}::git+https://github.com/SirCmpwn/wlroots.git") +sha1sums=('SKIP') +provides=('wlroots') +conflicts=('wlroots') + +pkgver() { + cd "${srcdir}/${pkgname}" + printf "r%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)" +} + +build() { + cd "${srcdir}/${pkgname}" + + meson build \ + --prefix=/usr \ + -Dbuildtype=debugoptimized \ + -Db_lto=True \ + -Denable-systemd=True \ + -Denable-elogind=False \ + -Denable-libcap=False + + ninja -C build +} + +package() { + cd "${srcdir}/${pkgname}" + + DESTDIR="${pkgdir}" ninja -C build install +} diff --git a/examples/compositor.c b/examples/compositor.c index ca69bdbf..8154c2e3 100644 --- a/examples/compositor.c +++ b/examples/compositor.c @@ -7,6 +7,8 @@ #include <unistd.h> #include <sys/mman.h> #include <wayland-server.h> +// TODO: BSD et al +#include <linux/input-event-codes.h> #include <wlr/backend.h> #include <wlr/backend/session.h> #include <wlr/render.h> @@ -17,19 +19,56 @@ #include <wlr/types/wlr_wl_shell.h> #include <wlr/types/wlr_xdg_shell_v6.h> #include <wlr/types/wlr_seat.h> +#include <wlr/types/wlr_input_device.h> #include <wlr/types/wlr_data_device_manager.h> #include <wlr/types/wlr_gamma_control.h> #include "wlr/types/wlr_compositor.h" +#include <wlr/types/wlr_cursor.h> +#include <wlr/types/wlr_output_layout.h> #include <wlr/xwayland.h> #include <xkbcommon/xkbcommon.h> #include <wlr/util/log.h> +#include "config.h" #include "shared.h" +#include <assert.h> // TODO: move to common header? int os_create_anonymous_file(off_t size); +struct sample_state; + +struct example_xdg_surface_v6 { + struct wlr_xdg_surface_v6 *surface; + struct sample_state *sample; + + // position of the wlr_surface in the layout + struct { + int lx; + int ly; + } position; + + struct wl_listener destroy_listener; + struct wl_listener ping_timeout_listener; + struct wl_listener request_minimize_listener; + struct wl_listener request_move_listener; + struct wl_listener request_resize_listener; + struct wl_listener request_show_window_menu_listener; +}; + +struct input_event_cache { + uint32_t serial; + struct wlr_cursor *cursor; + struct wlr_input_device *device; +}; + +struct motion_context { + struct example_xdg_surface_v6 *surface; + int off_x, off_y; +}; + struct sample_state { struct wlr_renderer *renderer; + struct compositor_state *compositor; struct wlr_compositor *wlr_compositor; struct wlr_wl_shell *wl_shell; struct wlr_seat *wl_seat; @@ -39,11 +78,68 @@ struct sample_state { struct wl_listener keyboard_bound; struct wlr_xwayland *xwayland; struct wlr_gamma_control_manager *gamma_control_manager; + bool mod_down; int keymap_fd; size_t keymap_size; uint32_t serial; + + struct motion_context motion_context; + + struct example_config *config; + struct wlr_output_layout *layout; + struct wlr_cursor *cursor; + struct wlr_xcursor *xcursor; + + // Ring buffer + int input_cache_idx; + struct input_event_cache input_cache[16]; + + struct wl_listener cursor_motion; + struct wl_listener cursor_motion_absolute; + struct wl_listener cursor_button; + struct wl_listener cursor_axis; + + struct wl_listener tool_axis; + struct wl_listener tool_tip; + struct wl_listener tool_button; + + struct wl_listener new_xdg_surface_v6; + + struct wlr_xdg_surface_v6 *focused_surface; }; +static void example_set_focused_surface(struct sample_state *sample, + struct wlr_xdg_surface_v6 *surface) { + if (sample->focused_surface == surface) { + return; + } + + // set activated state of the xdg surfaces + struct wlr_xdg_surface_v6 *xdg_surface; + struct wlr_xdg_client_v6 *xdg_client; + wl_list_for_each(xdg_client, &sample->xdg_shell->clients, link) { + wl_list_for_each(xdg_surface, &xdg_client->surfaces, link) { + if (!xdg_surface->configured || + xdg_surface->role != WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL) { + continue; + } + wlr_xdg_toplevel_v6_set_activated(xdg_surface, + xdg_surface == surface); + } + } + + if (surface) { + // TODO: send array of currently pressed keys + struct wl_array keys; + wl_array_init(&keys); + wlr_seat_keyboard_enter(sample->wl_seat, surface->surface, keys); + } else { + wlr_seat_keyboard_clear_focus(sample->wl_seat); + } + + sample->focused_surface = surface; +} + /* * Convert timespec to milliseconds */ @@ -53,13 +149,13 @@ static inline int64_t timespec_to_msec(const struct timespec *a) { static void output_frame_handle_surface(struct sample_state *sample, struct wlr_output *wlr_output, struct timespec *ts, - struct wl_resource *_res) { + struct wl_resource *_res, int ox, int oy) { struct wlr_surface *surface = wl_resource_get_user_data(_res); float matrix[16]; float transform[16]; wlr_surface_flush_damage(surface); if (surface->texture->valid) { - wlr_matrix_translate(&transform, 200, 200, 0); + wlr_matrix_translate(&transform, ox, oy, 0); wlr_surface_get_matrix(surface, &matrix, &wlr_output->transform_matrix, &transform); wlr_render_with_matrix(sample->renderer, surface->texture, &matrix); @@ -71,7 +167,129 @@ static void output_frame_handle_surface(struct sample_state *sample, } } } -static void handle_output_frame(struct output_state *output, struct timespec *ts) { + +static void handle_xdg_surface_v6_ping_timeout(struct wl_listener *listener, + void *data) { + struct wlr_xdg_surface_v6 *surface = data; + wlr_log(L_DEBUG, "got ping timeout for surface: %s", surface->title); +} + +static void handle_xdg_surface_v6_destroy(struct wl_listener *listener, + void *data) { + struct example_xdg_surface_v6 *example_surface = + wl_container_of(listener, example_surface, destroy_listener); + wl_list_remove(&example_surface->destroy_listener.link); + wl_list_remove(&example_surface->ping_timeout_listener.link); + wl_list_remove(&example_surface->request_move_listener.link); + wl_list_remove(&example_surface->request_resize_listener.link); + wl_list_remove(&example_surface->request_show_window_menu_listener.link); + wl_list_remove(&example_surface->request_minimize_listener.link); + free(example_surface); +} + +static void handle_xdg_surface_v6_request_move(struct wl_listener *listener, + void *data) { + struct example_xdg_surface_v6 *esurface = + wl_container_of(listener, esurface, request_move_listener); + struct wlr_xdg_toplevel_v6_move_event *e = data; + struct sample_state *sample = esurface->sample; + struct input_event_cache *event = NULL; + for (size_t i = 0; + i < sizeof(sample->input_cache) / sizeof(sample->input_cache[0]); + ++i) { + if (sample->input_cache[i].cursor + && sample->input_cache[i].serial == e->serial) { + event = &sample->input_cache[i]; + break; + } + } + if (!event || sample->motion_context.surface) { + return; + } + sample->motion_context.surface = esurface; + sample->motion_context.off_x = sample->cursor->x - esurface->position.lx; + sample->motion_context.off_y = sample->cursor->y - esurface->position.ly; + wlr_seat_pointer_clear_focus(sample->wl_seat); +} + +static void handle_xdg_surface_v6_request_resize(struct wl_listener *listener, + void *data) { + struct example_xdg_surface_v6 *example_surface = + wl_container_of(listener, example_surface, request_resize_listener); + struct wlr_xdg_toplevel_v6_resize_event *e = data; + wlr_log(L_DEBUG, "TODO: surface requested resize: %s", e->surface->title); +} + +static void handle_xdg_surface_v6_request_show_window_menu( + struct wl_listener *listener, void *data) { + struct example_xdg_surface_v6 *example_surface = + wl_container_of(listener, example_surface, + request_show_window_menu_listener); + struct wlr_xdg_toplevel_v6_show_window_menu_event *e = data; + wlr_log(L_DEBUG, "TODO: surface requested to show window menu: %s", + e->surface->title); +} + +static void handle_xdg_surface_v6_request_minimize( + struct wl_listener *listener, void *data) { + struct example_xdg_surface_v6 *example_surface = + wl_container_of(listener, example_surface, request_minimize_listener); + wlr_log(L_DEBUG, "TODO: surface requested to be minimized: %s", + example_surface->surface->title); +} + +static void handle_new_xdg_surface_v6(struct wl_listener *listener, + void *data) { + struct sample_state *sample_state = + wl_container_of(listener, sample_state, new_xdg_surface_v6); + struct wlr_xdg_surface_v6 *surface = data; + wlr_log(L_DEBUG, "new xdg surface: title=%s, app_id=%s", + surface->title, surface->app_id); + + wlr_xdg_surface_v6_ping(surface); + + struct example_xdg_surface_v6 *esurface = + calloc(1, sizeof(struct example_xdg_surface_v6)); + if (esurface == NULL) { + return; + } + + esurface->sample = sample_state; + esurface->surface = surface; + // TODO sensible default position + esurface->position.lx = 300; + esurface->position.ly = 300; + surface->data = esurface; + + wl_signal_add(&surface->events.destroy, &esurface->destroy_listener); + esurface->destroy_listener.notify = handle_xdg_surface_v6_destroy; + + wl_signal_add(&surface->events.ping_timeout, + &esurface->ping_timeout_listener); + esurface->ping_timeout_listener.notify = handle_xdg_surface_v6_ping_timeout; + + wl_signal_add(&surface->events.request_move, + &esurface->request_move_listener); + esurface->request_move_listener.notify = handle_xdg_surface_v6_request_move; + + wl_signal_add(&surface->events.request_resize, + &esurface->request_resize_listener); + esurface->request_resize_listener.notify = + handle_xdg_surface_v6_request_resize; + + wl_signal_add(&surface->events.request_show_window_menu, + &esurface->request_show_window_menu_listener); + esurface->request_show_window_menu_listener.notify = + handle_xdg_surface_v6_request_show_window_menu; + + wl_signal_add(&surface->events.request_minimize, + &esurface->request_minimize_listener); + esurface->request_minimize_listener.notify = + handle_xdg_surface_v6_request_minimize; +} + +static void handle_output_frame(struct output_state *output, + struct timespec *ts) { struct compositor_state *state = output->compositor; struct sample_state *sample = state->data; struct wlr_output *wlr_output = output->output; @@ -81,77 +299,324 @@ static void handle_output_frame(struct output_state *output, struct timespec *ts struct wlr_wl_shell_surface *wl_shell_surface; wl_list_for_each(wl_shell_surface, &sample->wl_shell->surfaces, link) { - output_frame_handle_surface(sample, wlr_output, ts, wl_shell_surface->surface); + output_frame_handle_surface(sample, wlr_output, ts, + wl_shell_surface->surface, 200, 200); } struct wlr_xdg_surface_v6 *xdg_surface; - wl_list_for_each(xdg_surface, &sample->xdg_shell->surfaces, link) { - output_frame_handle_surface(sample, wlr_output, ts, xdg_surface->surface); + struct wlr_xdg_client_v6 *xdg_client; + wl_list_for_each(xdg_client, &sample->xdg_shell->clients, link) { + wl_list_for_each(xdg_surface, &xdg_client->surfaces, link) { + if (!xdg_surface->configured) { + continue; + } + + struct example_xdg_surface_v6 *esurface = xdg_surface->data; + assert(esurface); + + int width = xdg_surface->surface->current.buffer_width; + int height = xdg_surface->surface->current.buffer_height; + + bool intersects_output = wlr_output_layout_intersects( + sample->layout, wlr_output, + esurface->position.lx, esurface->position.ly, + esurface->position.lx + width, esurface->position.ly + height); + + if (intersects_output) { + double ox = esurface->position.lx, oy = esurface->position.ly; + wlr_output_layout_output_coords(sample->layout, wlr_output, + &ox, &oy); + output_frame_handle_surface(sample, wlr_output, ts, + xdg_surface->surface->resource, ox, oy); + } + } } struct wlr_x11_window *x11_window; wl_list_for_each(x11_window, &sample->xwayland->displayable_windows, link) { - output_frame_handle_surface(sample, wlr_output, ts, x11_window->surface); + output_frame_handle_surface(sample, wlr_output, ts, + x11_window->surface, 200, 200); } wlr_renderer_end(sample->renderer); wlr_output_swap_buffers(wlr_output); } -static void handle_keyboard_key(struct keyboard_state *keyboard, uint32_t keycode, - xkb_keysym_t sym, enum wlr_key_state key_state) { +static void handle_keyboard_key(struct keyboard_state *keyboard, + uint32_t keycode, xkb_keysym_t sym, enum wlr_key_state key_state, + uint64_t time_usec) { struct compositor_state *state = keyboard->compositor; struct sample_state *sample = state->data; - struct wl_resource *res = NULL; - struct wlr_seat_handle *seat_handle = NULL; - wl_list_for_each(res, &sample->wlr_compositor->surfaces, link) { - break; + uint32_t depressed = xkb_state_serialize_mods(keyboard->xkb_state, + XKB_STATE_MODS_DEPRESSED); + uint32_t latched = xkb_state_serialize_mods(keyboard->xkb_state, + XKB_STATE_MODS_LATCHED); + uint32_t locked = xkb_state_serialize_mods(keyboard->xkb_state, + XKB_STATE_MODS_LOCKED); + uint32_t group = xkb_state_serialize_layout(keyboard->xkb_state, + XKB_STATE_LAYOUT_EFFECTIVE); + + wlr_seat_keyboard_send_modifiers(sample->wl_seat, depressed, latched, + locked, group); + wlr_seat_keyboard_send_key(sample->wl_seat, (uint32_t)time_usec, keycode, + key_state); + + if (sym == XKB_KEY_Super_L || sym == XKB_KEY_Super_R) { + sample->mod_down = key_state == WLR_KEY_PRESSED; + } +} + +static struct wlr_xdg_surface_v6 *example_xdg_surface_at( + struct sample_state *sample, int lx, int ly) { + struct wlr_xdg_surface_v6 *xdg_surface; + struct wlr_xdg_client_v6 *xdg_client; + wl_list_for_each(xdg_client, &sample->xdg_shell->clients, link) { + wl_list_for_each(xdg_surface, &xdg_client->surfaces, link) { + if (!xdg_surface->configured) { + continue; + } + + struct example_xdg_surface_v6 *esurface = xdg_surface->data; + + double window_x = esurface->position.lx + xdg_surface->geometry->x; + double window_y = esurface->position.ly + xdg_surface->geometry->y; + + if (sample->cursor->x >= window_x && + sample->cursor->y >= window_y && + sample->cursor->x <= window_x + + xdg_surface->geometry->width && + sample->cursor->y <= window_y + + xdg_surface->geometry->height) { + return xdg_surface; + } + } } - if (res) { - seat_handle = wlr_seat_handle_for_client(sample->wl_seat, - wl_resource_get_client(res)); + return NULL; +} + +static void update_pointer_position(struct sample_state *sample, uint32_t time) { + if (sample->motion_context.surface) { + struct example_xdg_surface_v6 *surface; + surface = sample->motion_context.surface; + surface->position.lx = sample->cursor->x - sample->motion_context.off_x; + surface->position.ly = sample->cursor->y - sample->motion_context.off_y; + return; } - if (res != sample->focus && seat_handle && seat_handle->keyboard) { - struct wl_array keys; - wl_array_init(&keys); - wl_keyboard_send_enter(seat_handle->keyboard, ++sample->serial, res, &keys); - sample->focus = res; + struct wlr_xdg_surface_v6 *surface = example_xdg_surface_at(sample, + sample->cursor->x, sample->cursor->y); + + if (surface) { + struct example_xdg_surface_v6 *esurface = surface->data; + + double sx = sample->cursor->x - esurface->position.lx; + double sy = sample->cursor->y - esurface->position.ly; + + // TODO z-order + wlr_seat_pointer_enter(sample->wl_seat, surface->surface, sx, sy); + wlr_seat_pointer_send_motion(sample->wl_seat, time, sx, sy); + } else { + wlr_seat_pointer_clear_focus(sample->wl_seat); } +} + +static void handle_cursor_motion(struct wl_listener *listener, void *data) { + struct sample_state *sample = + wl_container_of(listener, sample, cursor_motion); + struct wlr_event_pointer_motion *event = data; + + wlr_cursor_move(sample->cursor, event->device, event->delta_x, + event->delta_y); + + update_pointer_position(sample, (uint32_t)event->time_usec); +} + +static void handle_cursor_motion_absolute(struct wl_listener *listener, + void *data) { + struct sample_state *sample = + wl_container_of(listener, sample, cursor_motion_absolute); + struct wlr_event_pointer_motion_absolute *event = data; + + wlr_cursor_warp_absolute(sample->cursor, event->device, + event->x_mm / event->width_mm, event->y_mm / event->height_mm); - if (seat_handle && seat_handle->keyboard) { - uint32_t depressed = xkb_state_serialize_mods(keyboard->xkb_state, - XKB_STATE_MODS_DEPRESSED); - uint32_t latched = xkb_state_serialize_mods(keyboard->xkb_state, - XKB_STATE_MODS_LATCHED); - uint32_t locked = xkb_state_serialize_mods(keyboard->xkb_state, - XKB_STATE_MODS_LOCKED); - uint32_t group = xkb_state_serialize_layout(keyboard->xkb_state, - XKB_STATE_LAYOUT_EFFECTIVE); - wl_keyboard_send_modifiers(seat_handle->keyboard, ++sample->serial, depressed, - latched, locked, group); - wl_keyboard_send_key(seat_handle->keyboard, ++sample->serial, 0, keycode, key_state); + update_pointer_position(sample, (uint32_t)event->time_usec); +} + +static void handle_cursor_axis(struct wl_listener *listener, void *data) { + struct sample_state *sample = + wl_container_of(listener, sample, cursor_axis); + struct wlr_event_pointer_axis *event = data; + wlr_seat_pointer_send_axis(sample->wl_seat, event->time_sec, + event->orientation, event->delta); +} + +static void handle_cursor_button(struct wl_listener *listener, void *data) { + struct sample_state *sample = + wl_container_of(listener, sample, cursor_button); + struct wlr_event_pointer_button *event = data; + + struct wlr_xdg_surface_v6 *surface = + example_xdg_surface_at(sample, sample->cursor->x, sample->cursor->y); + + uint32_t serial = wlr_seat_pointer_send_button(sample->wl_seat, + (uint32_t)event->time_usec, event->button, event->state); + + int i; + switch (event->state) { + case WLR_BUTTON_RELEASED: + if (sample->motion_context.surface) { + sample->motion_context.surface = NULL; + } + break; + case WLR_BUTTON_PRESSED: + i = sample->input_cache_idx; + sample->input_cache[i].serial = serial; + sample->input_cache[i].cursor = sample->cursor; + sample->input_cache[i].device = event->device; + sample->input_cache_idx = (i + 1) + % (sizeof(sample->input_cache) / sizeof(sample->input_cache[0])); + example_set_focused_surface(sample, surface); + wlr_log(L_DEBUG, "Stored event %d at %d", serial, i); + if (sample->mod_down && event->button == BTN_LEFT) { + struct example_xdg_surface_v6 *esurface = surface->data; + sample->motion_context.surface = esurface; + sample->motion_context.off_x = sample->cursor->x - esurface->position.lx; + sample->motion_context.off_y = sample->cursor->y - esurface->position.ly; + wlr_seat_pointer_clear_focus(sample->wl_seat); + } + break; + } +} + +static void handle_tool_axis(struct wl_listener *listener, void *data) { + struct sample_state *sample = + wl_container_of(listener, sample, tool_axis); + struct wlr_event_tablet_tool_axis *event = data; + if ((event->updated_axes & WLR_TABLET_TOOL_AXIS_X) && + (event->updated_axes & WLR_TABLET_TOOL_AXIS_Y)) { + wlr_cursor_warp_absolute(sample->cursor, event->device, + event->x_mm / event->width_mm, event->y_mm / event->height_mm); + update_pointer_position(sample, (uint32_t)event->time_usec); } } -static void handle_keyboard_bound(struct wl_listener *listener, void *data) { - struct wlr_seat_handle *handle = data; - struct sample_state *state = wl_container_of(listener, state, keyboard_bound); +static void handle_tool_tip(struct wl_listener *listener, void *data) { + struct sample_state *sample = + wl_container_of(listener, sample, tool_tip); + struct wlr_event_tablet_tool_tip *event = data; + + struct wlr_xdg_surface_v6 *surface = + example_xdg_surface_at(sample, sample->cursor->x, sample->cursor->y); + example_set_focused_surface(sample, surface); - wl_keyboard_send_keymap(handle->keyboard, WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1, - state->keymap_fd, state->keymap_size); + wlr_seat_pointer_send_button(sample->wl_seat, (uint32_t)event->time_usec, + BTN_LEFT, event->state); +} - if (wl_resource_get_version(handle->keyboard) >= 2) { - wl_keyboard_send_repeat_info(handle->keyboard, 25, 600); +static void handle_input_add(struct compositor_state *state, + struct wlr_input_device *device) { + struct sample_state *sample = state->data; + + if (device->type == WLR_INPUT_DEVICE_POINTER || + device->type == WLR_INPUT_DEVICE_TOUCH || + device->type == WLR_INPUT_DEVICE_TABLET_TOOL) { + wlr_cursor_attach_input_device(sample->cursor, device); + example_config_configure_cursor(sample->config, sample->cursor, + sample->compositor); } } -int main() { +static void handle_output_add(struct output_state *ostate) { + struct sample_state *sample = ostate->compositor->data; + struct wlr_output *wlr_output = ostate->output; + struct wlr_xcursor_image *image = sample->xcursor->images[0]; + + struct output_config *o_config = + example_config_get_output(sample->config, ostate->output); + + if (o_config) { + wlr_output_transform(ostate->output, o_config->transform); + wlr_output_layout_add(sample->layout, ostate->output, o_config->x, + o_config->y); + } else { + wlr_output_layout_add_auto(sample->layout, ostate->output); + } + + example_config_configure_cursor(sample->config, sample->cursor, + sample->compositor); + + // TODO the cursor must be set depending on which surface it is displayed + // over which should happen in the compositor. + if (!wlr_output_set_cursor(wlr_output, image->buffer, + image->width, image->width, image->height)) { + wlr_log(L_DEBUG, "Failed to set hardware cursor"); + return; + } + + wlr_cursor_warp(sample->cursor, NULL, sample->cursor->x, sample->cursor->y); +} + +static void handle_output_remove(struct output_state *ostate) { + struct sample_state *sample = ostate->compositor->data; + + wlr_output_layout_remove(sample->layout, ostate->output); + + example_config_configure_cursor(sample->config, sample->cursor, + sample->compositor); +} + +int main(int argc, char *argv[]) { struct sample_state state = { 0 }; struct compositor_state compositor = { 0, .data = &state, .output_frame_cb = handle_output_frame, }; + + compositor.input_add_cb = handle_input_add; + compositor.output_add_cb = handle_output_add; + compositor.output_remove_cb = handle_output_remove; + + state.compositor = &compositor; + state.config = parse_args(argc, argv); + state.cursor = wlr_cursor_create(); + state.layout = wlr_output_layout_create(); + wlr_cursor_attach_output_layout(state.cursor, state.layout); + wlr_cursor_map_to_region(state.cursor, state.config->cursor.mapped_box); + + struct wlr_xcursor_theme *theme = wlr_xcursor_theme_load("default", 16); + if (!theme) { + wlr_log(L_ERROR, "Failed to load cursor theme"); + return 1; + } + state.xcursor = wlr_xcursor_theme_get_cursor(theme, "left_ptr"); + if (!state.xcursor) { + wlr_log(L_ERROR, "Failed to load left_ptr cursor"); + return 1; + } + + wlr_cursor_set_xcursor(state.cursor, state.xcursor); + + // pointer events + wl_signal_add(&state.cursor->events.motion, &state.cursor_motion); + state.cursor_motion.notify = handle_cursor_motion; + + wl_signal_add(&state.cursor->events.motion_absolute, + &state.cursor_motion_absolute); + state.cursor_motion_absolute.notify = handle_cursor_motion_absolute; + + wl_signal_add(&state.cursor->events.button, &state.cursor_button); + state.cursor_button.notify = handle_cursor_button; + + wl_signal_add(&state.cursor->events.axis, &state.cursor_axis); + state.cursor_axis.notify = handle_cursor_axis; + + wl_signal_add(&state.cursor->events.tablet_tool_axis, &state.tool_axis); + state.tool_axis.notify = handle_tool_axis; + + wl_signal_add(&state.cursor->events.tablet_tool_tip, &state.tool_tip); + state.tool_tip.notify = handle_tool_tip; + compositor_init(&compositor); state.renderer = wlr_gles2_renderer_create(compositor.backend); @@ -160,15 +625,25 @@ int main() { exit(EXIT_FAILURE); } wl_display_init_shm(compositor.display); - state.wlr_compositor = wlr_compositor_create(compositor.display, state.renderer); + state.wlr_compositor = + wlr_compositor_create(compositor.display, state.renderer); state.wl_shell = wlr_wl_shell_create(compositor.display); state.xdg_shell = wlr_xdg_shell_v6_create(compositor.display); - state.data_device_manager = wlr_data_device_manager_create(compositor.display); - state.gamma_control_manager = wlr_gamma_control_manager_create(compositor.display); + + // shell events + wl_signal_add(&state.xdg_shell->events.new_surface, + &state.new_xdg_surface_v6); + state.new_xdg_surface_v6.notify = handle_new_xdg_surface_v6; + + + state.data_device_manager = + wlr_data_device_manager_create(compositor.display); + + state.gamma_control_manager = + wlr_gamma_control_manager_create(compositor.display); state.wl_seat = wlr_seat_create(compositor.display, "seat0"); - state.keyboard_bound.notify = handle_keyboard_bound; - wl_signal_add(&state.wl_seat->events.keyboard_bound, &state.keyboard_bound); + assert(state.wl_seat); wlr_seat_set_capabilities(state.wl_seat, WL_SEAT_CAPABILITY_KEYBOARD | WL_SEAT_CAPABILITY_POINTER | WL_SEAT_CAPABILITY_TOUCH); @@ -178,19 +653,26 @@ int main() { XKB_KEYMAP_FORMAT_TEXT_V1); state.keymap_size = strlen(keymap); state.keymap_fd = os_create_anonymous_file(state.keymap_size); - void *ptr = mmap(NULL, state.keymap_size, - PROT_READ | PROT_WRITE, - MAP_SHARED, state.keymap_fd, 0); + void *ptr = + mmap(NULL, state.keymap_size, PROT_READ | PROT_WRITE, MAP_SHARED, + state.keymap_fd, 0); strcpy(ptr, keymap); free(keymap); break; } - state.xwayland = wlr_xwayland_create(compositor.display, state.wlr_compositor); + + wlr_seat_keyboard_set_keymap(state.wl_seat, state.keymap_fd, + state.keymap_size); + + state.xwayland = wlr_xwayland_create(compositor.display, + state.wlr_compositor); compositor.keyboard_key_cb = handle_keyboard_key; wl_display_run(compositor.display); + wl_list_remove(&state.new_xdg_surface_v6.link); + wlr_xwayland_destroy(state.xwayland); close(state.keymap_fd); wlr_seat_destroy(state.wl_seat); diff --git a/examples/output-layout.c b/examples/output-layout.c index be542630..69cb241a 100644 --- a/examples/output-layout.c +++ b/examples/output-layout.c @@ -157,7 +157,8 @@ static void update_velocities(struct compositor_state *state, } static void handle_keyboard_key(struct keyboard_state *kbstate, - uint32_t keycode, xkb_keysym_t sym, enum wlr_key_state key_state) { + uint32_t keycode, xkb_keysym_t sym, enum wlr_key_state key_state, + uint64_t time_usec) { // NOTE: It may be better to simply refer to our key state during each frame // and make this change in pixels/sec^2 // Also, key repeat diff --git a/examples/rotation.c b/examples/rotation.c index 2596e492..dfb81e59 100644 --- a/examples/rotation.c +++ b/examples/rotation.c @@ -99,7 +99,8 @@ static void update_velocities(struct compositor_state *state, } static void handle_keyboard_key(struct keyboard_state *kbstate, - uint32_t keycode, xkb_keysym_t sym, enum wlr_key_state key_state) { + uint32_t keycode, xkb_keysym_t sym, enum wlr_key_state key_state, + uint64_t time_usec) { // NOTE: It may be better to simply refer to our key state during each frame // and make this change in pixels/sec^2 // Also, key repeat diff --git a/examples/shared.c b/examples/shared.c index 0346c96d..19cf83f0 100644 --- a/examples/shared.c +++ b/examples/shared.c @@ -48,7 +48,8 @@ static void keyboard_key_notify(struct wl_listener *listener, void *data) { key_state == WLR_KEY_PRESSED ? "pressed" : "released"); } if (kbstate->compositor->keyboard_key_cb) { - kbstate->compositor->keyboard_key_cb(kbstate, event->keycode, sym, key_state); + kbstate->compositor->keyboard_key_cb(kbstate, event->keycode, sym, + key_state, event->time_usec); } if (sym == XKB_KEY_Escape) { wl_display_terminate(kbstate->compositor->display); diff --git a/examples/shared.h b/examples/shared.h index 7cf4db63..f564bffa 100644 --- a/examples/shared.h +++ b/examples/shared.h @@ -87,7 +87,7 @@ struct compositor_state { struct output_state *s); void (*keyboard_remove_cb)(struct keyboard_state *s); void (*keyboard_key_cb)(struct keyboard_state *s, uint32_t keycode, - xkb_keysym_t sym, enum wlr_key_state key_state); + xkb_keysym_t sym, enum wlr_key_state key_state, uint64_t time_usec); void (*pointer_motion_cb)(struct pointer_state *s, double d_x, double d_y); void (*pointer_motion_absolute_cb)(struct pointer_state *s, diff --git a/include/backend/drm-properties.h b/include/backend/drm-properties.h index 7a061dd3..7de386ea 100644 --- a/include/backend/drm-properties.h +++ b/include/backend/drm-properties.h @@ -1,5 +1,5 @@ -#ifndef DRM_PROPERTIES_H -#define DRM_PROPERTIES_H +#ifndef BACKEND_DRM_PROPERTIES_H +#define BACKEND_DRM_PROPERTIES_H #include <stdbool.h> #include <stdint.h> diff --git a/include/backend/drm-util.h b/include/backend/drm-util.h index 9abee6ea..6818b4db 100644 --- a/include/backend/drm-util.h +++ b/include/backend/drm-util.h @@ -1,5 +1,5 @@ -#ifndef WLR_DRM_UTIL_H -#define WLR_DRM_UTIL_H +#ifndef BACKEND_DRM_UTIL_H +#define BACKEND_DRM_UTIL_H #include <stdint.h> #include <xf86drm.h> diff --git a/include/backend/drm.h b/include/backend/drm.h index 27ddad6f..b474e8b3 100644 --- a/include/backend/drm.h +++ b/include/backend/drm.h @@ -1,5 +1,5 @@ -#ifndef DRM_BACKEND_H -#define DRM_BACKEND_H +#ifndef BACKEND_DRM_H +#define BACKEND_DRM_H #include <stdbool.h> #include <stddef.h> diff --git a/include/backend/libinput.h b/include/backend/libinput.h index f484ea8d..bb6083a4 100644 --- a/include/backend/libinput.h +++ b/include/backend/libinput.h @@ -1,5 +1,5 @@ -#ifndef _WLR_BACKEND_LIBINPUT_INTERNAL_H -#define _WLR_BACKEND_LIBINPUT_INTERNAL_H +#ifndef BACKEND_LIBINPUT_H +#define BACKEND_LIBINPUT_H #include <libinput.h> #include <wayland-server-core.h> #include <wlr/types/wlr_input_device.h> diff --git a/include/backend/multi.h b/include/backend/multi.h index c7a2198e..2c409b3a 100644 --- a/include/backend/multi.h +++ b/include/backend/multi.h @@ -1,5 +1,5 @@ -#ifndef _WLR_MULTI_BACKEND_INTERNAL -#define _WLR_MULTI_BACKEND_INTERNAL +#ifndef BACKEND_MULTI_H +#define BACKEND_MULTI_H #include <wlr/backend/interface.h> #include <wlr/backend/multi.h> diff --git a/include/backend/session/direct-ipc.h b/include/backend/session/direct-ipc.h index 2189d6fa..c660b58f 100644 --- a/include/backend/session/direct-ipc.h +++ b/include/backend/session/direct-ipc.h @@ -1,5 +1,5 @@ -#ifndef SESSION_DIRECT_IPC -#define SESSION_DIRECT_IPC +#ifndef BACKEND_SESSION_DIRECT_IPC_H +#define BACKEND_SESSION_DIRECT_IPC_H #include <sys/types.h> diff --git a/include/backend/wayland.h b/include/backend/wayland.h index 5e278dc9..917a798a 100644 --- a/include/backend/wayland.h +++ b/include/backend/wayland.h @@ -1,5 +1,5 @@ -#ifndef _WLR_INTERNAL_BACKEND_WAYLAND_H -#define _WLR_INTERNAL_BACKEND_WAYLAND_H +#ifndef BACKEND_WAYLAND_H +#define BACKEND_WAYLAND_H #include <wayland-client.h> #include <wayland-server.h> diff --git a/include/render/gles2.h b/include/render/gles2.h index 79f13ed9..688a51dd 100644 --- a/include/render/gles2.h +++ b/include/render/gles2.h @@ -1,5 +1,6 @@ -#ifndef _WLR_RENDER_GLES2_INTERNAL_H -#define _WLR_RENDER_GLES2_INTERNAL_H +#ifndef RENDER_GLES2_H +#define RENDER_GLES2_H + #include <stdint.h> #include <string.h> #include <stdbool.h> diff --git a/include/wlr/backend.h b/include/wlr/backend.h index f92857eb..6c11152f 100644 --- a/include/wlr/backend.h +++ b/include/wlr/backend.h @@ -1,5 +1,5 @@ -#ifndef _WLR_BACKEND_H -#define _WLR_BACKEND_H +#ifndef WLR_BACKEND_H +#define WLR_BACKEND_H #include <wayland-server.h> #include <wlr/backend/session.h> diff --git a/include/wlr/backend/interface.h b/include/wlr/backend/interface.h index b0814da5..ea41400a 100644 --- a/include/wlr/backend/interface.h +++ b/include/wlr/backend/interface.h @@ -1,5 +1,5 @@ -#ifndef _WLR_BACKEND_INTERFACE_H -#define _WLR_BACKEND_INTERFACE_H +#ifndef WLR_BACKEND_INTERFACE_H +#define WLR_BACKEND_INTERFACE_H #include <stdbool.h> #include <wlr/backend.h> diff --git a/include/wlr/backend/multi.h b/include/wlr/backend/multi.h index 3fcaaf1e..5559f2c1 100644 --- a/include/wlr/backend/multi.h +++ b/include/wlr/backend/multi.h @@ -1,5 +1,5 @@ -#ifndef _WLR_BACKEND_MULTI_H -#define _WLR_BACKEND_MULTI_H +#ifndef WLR_BACKEND_MULTI_H +#define WLR_BACKEND_MULTI_H #include <wlr/backend.h> #include <wlr/backend/session.h> diff --git a/include/wlr/backend/session.h b/include/wlr/backend/session.h index 04e701b0..52cf13b7 100644 --- a/include/wlr/backend/session.h +++ b/include/wlr/backend/session.h @@ -1,5 +1,5 @@ -#ifndef WLR_SESSION_H -#define WLR_SESSION_H +#ifndef WLR_BACKEND_SESSION_H +#define WLR_BACKEND_SESSION_H #include <stdbool.h> #include <wayland-server.h> diff --git a/include/wlr/backend/session/interface.h b/include/wlr/backend/session/interface.h index 1a029c54..b35ed71d 100644 --- a/include/wlr/backend/session/interface.h +++ b/include/wlr/backend/session/interface.h @@ -1,5 +1,5 @@ -#ifndef WLR_SESSION_INTERFACE_H -#define WLR_SESSION_INTERFACE_H +#ifndef WLR_BACKEND_SESSION_INTERFACE_H +#define WLR_BACKEND_SESSION_INTERFACE_H #include <wlr/backend/session.h> diff --git a/include/wlr/interfaces/wlr_data_source.h b/include/wlr/interfaces/wlr_data_source.h index 221c8007..821bdea0 100644 --- a/include/wlr/interfaces/wlr_data_source.h +++ b/include/wlr/interfaces/wlr_data_source.h @@ -1,5 +1,6 @@ -#ifndef _WLR_INTERFACES_DATA_SOURCE_H -#define _WLR_INTERFACES_DATA_SOURCE_H +#ifndef WLR_INTERFACES_WLR_DATA_SOURCE_H +#define WLR_INTERFACES_WLR_DATA_SOURCE_H + #include <wlr/types/wlr_data_source.h> struct wlr_data_source_impl { diff --git a/include/wlr/interfaces/wlr_input_device.h b/include/wlr/interfaces/wlr_input_device.h index b236a24a..2a681ff8 100644 --- a/include/wlr/interfaces/wlr_input_device.h +++ b/include/wlr/interfaces/wlr_input_device.h @@ -1,5 +1,6 @@ -#ifndef _WLR_INTERFACES_INPUT_DEVICE_H -#define _WLR_INTERFACES_INPUT_DEVICE_H +#ifndef WLR_INTERFACES_WLR_INPUT_DEVICE_H +#define WLR_INTERFACES_WLR_INPUT_DEVICE_H + #include <wlr/types/wlr_input_device.h> struct wlr_input_device_impl { diff --git a/include/wlr/interfaces/wlr_keyboard.h b/include/wlr/interfaces/wlr_keyboard.h index 779b302f..4958e2b8 100644 --- a/include/wlr/interfaces/wlr_keyboard.h +++ b/include/wlr/interfaces/wlr_keyboard.h @@ -1,5 +1,6 @@ -#ifndef _WLR_INTERFACE_KEYBOARD_H -#define _WLR_INTERFACE_KEYBOARD_H +#ifndef WLR_INTERFACES_WLR_KEYBOARD_H +#define WLR_INTERFACES_WLR_KEYBOARD_H + #include <wlr/types/wlr_keyboard.h> #include <stdint.h> diff --git a/include/wlr/interfaces/wlr_output.h b/include/wlr/interfaces/wlr_output.h index a95fe588..7ed19ed9 100644 --- a/include/wlr/interfaces/wlr_output.h +++ b/include/wlr/interfaces/wlr_output.h @@ -1,5 +1,6 @@ -#ifndef _WLR_INTERFACE_OUTPUT_H -#define _WLR_INTERFACE_OUTPUT_H +#ifndef WLR_INTERFACES_WLR_OUTPUT_H +#define WLR_INTERFACES_WLR_OUTPUT_H + #include <wlr/types/wlr_output.h> #include <stdbool.h> diff --git a/include/wlr/interfaces/wlr_pointer.h b/include/wlr/interfaces/wlr_pointer.h index 8d4bf703..af677b97 100644 --- a/include/wlr/interfaces/wlr_pointer.h +++ b/include/wlr/interfaces/wlr_pointer.h @@ -1,5 +1,6 @@ -#ifndef _WLR_INTERFACES_POINTER_H -#define _WLR_INTERFACES_POINTER_H +#ifndef WLR_INTERFACES_WLR_POINTER_H +#define WLR_INTERFACES_WLR_POINTER_H + #include <wlr/types/wlr_pointer.h> struct wlr_pointer_impl { diff --git a/include/wlr/interfaces/wlr_tablet_pad.h b/include/wlr/interfaces/wlr_tablet_pad.h index 81af3c3f..5ec1e3eb 100644 --- a/include/wlr/interfaces/wlr_tablet_pad.h +++ b/include/wlr/interfaces/wlr_tablet_pad.h @@ -1,5 +1,6 @@ -#ifndef _WLR_INTERFACES_TABLET_PAD_H -#define _WLR_INTERFACES_TABLET_PAD_H +#ifndef WLR_INTERFACES_WLR_TABLET_PAD_H +#define WLR_INTERFACES_WLR_TABLET_PAD_H + #include <wlr/types/wlr_tablet_pad.h> struct wlr_tablet_pad_impl { diff --git a/include/wlr/interfaces/wlr_tablet_tool.h b/include/wlr/interfaces/wlr_tablet_tool.h index 43a24fd0..347a0003 100644 --- a/include/wlr/interfaces/wlr_tablet_tool.h +++ b/include/wlr/interfaces/wlr_tablet_tool.h @@ -1,5 +1,6 @@ -#ifndef _WLR_INTERFACES_TABLET_TOOL_H -#define _WLR_INTERFACES_TABLET_TOOL_H +#ifndef WLR_INTERFACES_WLR_TABLET_TOOL_H +#define WLR_INTERFACES_WLR_TABLET_TOOL_H + #include <wlr/types/wlr_tablet_tool.h> struct wlr_tablet_tool_impl { diff --git a/include/wlr/interfaces/wlr_touch.h b/include/wlr/interfaces/wlr_touch.h index b5fcef18..63bac6b8 100644 --- a/include/wlr/interfaces/wlr_touch.h +++ b/include/wlr/interfaces/wlr_touch.h @@ -1,5 +1,6 @@ -#ifndef _WLR_INTERFACES_TOUCH_H -#define _WLR_INTERFACES_TOUCH_H +#ifndef WLR_INTERFACES_WLR_TOUCH_H +#define WLR_INTERFACES_WLR_TOUCH_H + #include <wlr/types/wlr_touch.h> struct wlr_touch_impl { diff --git a/include/wlr/render.h b/include/wlr/render.h index b7924928..325f8c01 100644 --- a/include/wlr/render.h +++ b/include/wlr/render.h @@ -1,5 +1,6 @@ -#ifndef _WLR_RENDER_H -#define _WLR_RENDER_H +#ifndef WLR_RENDER_H +#define WLR_RENDER_H + #include <stdint.h> #include <wayland-server-protocol.h> #include <wlr/types/wlr_output.h> diff --git a/include/wlr/render/gles2.h b/include/wlr/render/gles2.h index 4a944eb7..25e760d5 100644 --- a/include/wlr/render/gles2.h +++ b/include/wlr/render/gles2.h @@ -1,5 +1,6 @@ -#ifndef _WLR_GLES2_RENDERER_H -#define _WLR_GLES2_RENDERER_H +#ifndef WLR_RENDER_GLES2_H +#define WLR_RENDER_GLES2_H + #include <wlr/render.h> #include <wlr/backend.h> diff --git a/include/wlr/render/interface.h b/include/wlr/render/interface.h index c00e0701..e3ba0414 100644 --- a/include/wlr/render/interface.h +++ b/include/wlr/render/interface.h @@ -1,5 +1,6 @@ -#ifndef _WLR_RENDER_INTERFACE_H -#define _WLR_RENDER_INTERFACE_H +#ifndef WLR_RENDER_INTERFACE_H +#define WLR_RENDER_INTERFACE_H + #include <wayland-server-protocol.h> #include <stdbool.h> #include <wlr/render.h> diff --git a/include/wlr/render/matrix.h b/include/wlr/render/matrix.h index 789f7341..177af4b3 100644 --- a/include/wlr/render/matrix.h +++ b/include/wlr/render/matrix.h @@ -1,5 +1,5 @@ -#ifndef _WLR_RENDER_MATRIX_H -#define _WLR_RENDER_MATRIX_H +#ifndef WLR_RENDER_MATRIX_H +#define WLR_RENDER_MATRIX_H #include <stdint.h> diff --git a/include/wlr/types/wlr_box.h b/include/wlr/types/wlr_box.h index e2b1ab4e..5b8b00c9 100644 --- a/include/wlr/types/wlr_box.h +++ b/include/wlr/types/wlr_box.h @@ -1,5 +1,6 @@ -#ifndef _WLR_TYPES_GEOMETRY_H -#define _WLR_TYPES_GEOMETRY_H +#ifndef WLR_TYPES_WLR_BOX_H +#define WLR_TYPES_WLR_BOX_H + #include <stdbool.h> struct wlr_box { diff --git a/include/wlr/types/wlr_compositor.h b/include/wlr/types/wlr_compositor.h index 58a93760..b2f5a972 100644 --- a/include/wlr/types/wlr_compositor.h +++ b/include/wlr/types/wlr_compositor.h @@ -1,5 +1,6 @@ -#ifndef _EXAMPLE_COMPOSITOR_H -#define _EXAMPLE_COMPOSITOR_H +#ifndef WLR_TYPES_WLR_COMPOSITOR_H +#define WLR_TYPES_WLR_COMPOSITOR_H + #include <wayland-server.h> #include <wlr/render.h> @@ -22,4 +23,5 @@ struct wlr_compositor *wlr_compositor_create(struct wl_display *display, struct wlr_surface; void wl_compositor_surface_destroyed(struct wlr_compositor *wlr_compositor, struct wlr_surface *surface); + #endif diff --git a/include/wlr/types/wlr_cursor.h b/include/wlr/types/wlr_cursor.h index 5fc0ec76..e8c13b1d 100644 --- a/include/wlr/types/wlr_cursor.h +++ b/include/wlr/types/wlr_cursor.h @@ -1,5 +1,6 @@ -#ifndef _WLR_TYPES_CURSOR_H -#define _WLR_TYPES_CURSOR_H +#ifndef WLR_TYPES_WLR_CURSOR_H +#define WLR_TYPES_WLR_CURSOR_H + #include <wayland-server.h> #include <wlr/types/wlr_output.h> #include <wlr/types/wlr_output_layout.h> @@ -11,7 +12,7 @@ struct wlr_cursor_state; struct wlr_cursor { struct wlr_cursor_state *state; - int x, y; + double x, y; struct { struct wl_signal motion; diff --git a/include/wlr/types/wlr_data_device_manager.h b/include/wlr/types/wlr_data_device_manager.h index d7ae46c8..500f8acd 100644 --- a/include/wlr/types/wlr_data_device_manager.h +++ b/include/wlr/types/wlr_data_device_manager.h @@ -1,5 +1,5 @@ -#ifndef _WLR_TYPES_DATA_DEVICE_MANAGER_H -#define _WLR_TYPES_DATA_DEVICE_MANAGER_H +#ifndef WLR_TYPES_WLR_DATA_DEVICE_MANAGER_H +#define WLR_TYPES_WLR_DATA_DEVICE_MANAGER_H #include <wayland-server.h> diff --git a/include/wlr/types/wlr_data_source.h b/include/wlr/types/wlr_data_source.h index 63b0fe2a..19834cb6 100644 --- a/include/wlr/types/wlr_data_source.h +++ b/include/wlr/types/wlr_data_source.h @@ -1,5 +1,5 @@ -#ifndef _WLR_TYPES_DATA_SOURCE_H -#define _WLR_TYPES_DATA_SOURCE_H +#ifndef WLR_TYPES_WLR_DATA_SOURCE_H +#define WLR_TYPES_WLR_DATA_SOURCE_H #include <wayland-server.h> #include <wlr/util/list.h> diff --git a/include/wlr/types/wlr_gamma_control.h b/include/wlr/types/wlr_gamma_control.h index 259c6474..96c9f545 100644 --- a/include/wlr/types/wlr_gamma_control.h +++ b/include/wlr/types/wlr_gamma_control.h @@ -1,5 +1,6 @@ -#ifndef _WLR_GAMMA_CONTROL_H -#define _WLR_GAMMA_CONTROL_H +#ifndef WLR_TYPES_WLR_GAMMA_CONTROL_H +#define WLR_TYPES_WLR_GAMMA_CONTROL_H + #include <wayland-server.h> struct wlr_gamma_control_manager { diff --git a/include/wlr/types/wlr_input_device.h b/include/wlr/types/wlr_input_device.h index 5a41ce9d..50b0fb88 100644 --- a/include/wlr/types/wlr_input_device.h +++ b/include/wlr/types/wlr_input_device.h @@ -1,5 +1,5 @@ -#ifndef _WLR_TYPES_INPUT_H -#define _WLR_TYPES_INPUT_H +#ifndef WLR_TYPES_WLR_INPUT_DEVICE_H +#define WLR_TYPES_WLR_INPUT_DEVICE_H enum wlr_button_state { WLR_BUTTON_RELEASED, diff --git a/include/wlr/types/wlr_keyboard.h b/include/wlr/types/wlr_keyboard.h index ce7d6659..3f5d0d0c 100644 --- a/include/wlr/types/wlr_keyboard.h +++ b/include/wlr/types/wlr_keyboard.h @@ -1,5 +1,6 @@ -#ifndef _WLR_TYPES_KEYBOARD_H -#define _WLR_TYPES_KEYBOARD_H +#ifndef WLR_TYPES_WLR_KEYBOARD_H +#define WLR_TYPES_WLR_KEYBOARD_H + #include <wayland-server.h> #include <stdint.h> diff --git a/include/wlr/types/wlr_output.h b/include/wlr/types/wlr_output.h index b70bd19e..3208acac 100644 --- a/include/wlr/types/wlr_output.h +++ b/include/wlr/types/wlr_output.h @@ -1,5 +1,6 @@ -#ifndef _WLR_TYPES_OUTPUT_H -#define _WLR_TYPES_OUTPUT_H +#ifndef WLR_TYPES_WLR_OUTPUT_H +#define WLR_TYPES_WLR_OUTPUT_H + #include <wayland-server.h> #include <wlr/util/list.h> #include <stdbool.h> diff --git a/include/wlr/types/wlr_output_layout.h b/include/wlr/types/wlr_output_layout.h index 1f4a96d5..fe09106f 100644 --- a/include/wlr/types/wlr_output_layout.h +++ b/include/wlr/types/wlr_output_layout.h @@ -1,5 +1,6 @@ -#ifndef _WLR_TYPES_OUTPUT_LAYOUT_H -#define _WLR_TYPES_OUTPUT_LAYOUT_H +#ifndef WLR_TYPES_WLR_OUTPUT_LAYOUT_H +#define WLR_TYPES_WLR_OUTPUT_LAYOUT_H + #include <wlr/types/wlr_output.h> #include <wayland-util.h> #include <stdbool.h> diff --git a/include/wlr/types/wlr_pointer.h b/include/wlr/types/wlr_pointer.h index 9153963a..a59d8817 100644 --- a/include/wlr/types/wlr_pointer.h +++ b/include/wlr/types/wlr_pointer.h @@ -1,5 +1,6 @@ -#ifndef _WLR_TYPES_POINTER_H -#define _WLR_TYPES_POINTER_H +#ifndef WLR_TYPES_WLR_POINTER_H +#define WLR_TYPES_WLR_POINTER_H + #include <wlr/types/wlr_input_device.h> #include <wayland-server.h> #include <stdint.h> diff --git a/include/wlr/types/wlr_region.h b/include/wlr/types/wlr_region.h index 9a64ac13..6d59ee5e 100644 --- a/include/wlr/types/wlr_region.h +++ b/include/wlr/types/wlr_region.h @@ -1,5 +1,5 @@ -#ifndef _WLR_TYPES_REGION_H -#define _WLR_TYPES_REGION_H +#ifndef WLR_TYPES_WLR_REGION_H +#define WLR_TYPES_WLR_REGION_H struct wl_resource; diff --git a/include/wlr/types/wlr_seat.h b/include/wlr/types/wlr_seat.h index 69f17b1e..0270ad4e 100644 --- a/include/wlr/types/wlr_seat.h +++ b/include/wlr/types/wlr_seat.h @@ -1,5 +1,8 @@ -#ifndef _WLR_TYPES_SEAT_H -#define _WLR_TYPES_SEAT_H +#ifndef WLR_TYPES_WLR_SEAT_H +#define WLR_TYPES_WLR_SEAT_H + +#include <wlr/types/wlr_surface.h> +#include <wlr/types/wlr_input_device.h> #include <wayland-server.h> /** @@ -19,13 +22,38 @@ struct wlr_seat_handle { struct wl_list link; }; +struct wlr_seat_pointer_state { + struct wlr_seat *wlr_seat; + struct wlr_seat_handle *focused_handle; + struct wlr_surface *focused_surface; + + struct wl_listener focus_surface_destroy_listener; + struct wl_listener focus_resource_destroy_listener; +}; + +struct wlr_seat_keyboard_state { + struct wlr_seat *wlr_seat; + struct wlr_seat_handle *focused_handle; + struct wlr_surface *focused_surface; + + int keymap_fd; + size_t keymap_size; + + struct wl_listener focus_surface_destroy_listener; + struct wl_listener focus_resource_destroy_listener; +}; + struct wlr_seat { struct wl_global *wl_global; + struct wl_display *display; struct wl_list handles; char *name; uint32_t capabilities; struct wlr_data_device *data_device; + struct wlr_seat_pointer_state pointer_state; + struct wlr_seat_keyboard_state keyboard_state; + struct { struct wl_signal client_bound; struct wl_signal client_unbound; @@ -54,11 +82,82 @@ struct wlr_seat_handle *wlr_seat_handle_for_client(struct wlr_seat *wlr_seat, * Updates the capabilities available on this seat. * Will automatically send them to all clients. */ -void wlr_seat_set_capabilities(struct wlr_seat *wlr_seat, uint32_t capabilities); +void wlr_seat_set_capabilities(struct wlr_seat *wlr_seat, + uint32_t capabilities); /** * Updates the name of this seat. * Will automatically send it to all clients. */ void wlr_seat_set_name(struct wlr_seat *wlr_seat, const char *name); +/** + * Whether or not the surface has pointer focus + */ +bool wlr_seat_pointer_surface_has_focus(struct wlr_seat *wlr_seat, + struct wlr_surface *surface); + +/** + * Send a pointer enter event to the given surface and consider it to be the + * focused surface for the pointer. This will send a leave event to the last + * surface that was entered. Coordinates for the enter event are surface-local. + */ +void wlr_seat_pointer_enter(struct wlr_seat *wlr_seat, + struct wlr_surface *surface, double sx, double sy); + +/** + * Clear the focused surface for the pointer and leave all entered surfaces. + */ +void wlr_seat_pointer_clear_focus(struct wlr_seat *wlr_seat); + +/** + * Send a motion event to the surface with pointer focus. Coordinates for the + * motion event are surface-local. + */ +void wlr_seat_pointer_send_motion(struct wlr_seat *wlr_seat, uint32_t time, + double sx, double sy); + +/** + * Send a button event to the surface with pointer focus. Coordinates for the + * button event are surface-local. Returns the serial. + */ +uint32_t wlr_seat_pointer_send_button(struct wlr_seat *wlr_seat, uint32_t time, + uint32_t button, uint32_t state); + +void wlr_seat_pointer_send_axis(struct wlr_seat *wlr_seat, uint32_t time, + enum wlr_axis_orientation orientation, double value); + +/** + * Send a keyboard enter event to the given surface and consider it to be the + * focused surface for the keyboard. This will send a leave event to the last + * surface that was entered. Pass an array of currently pressed keys. + */ +void wlr_seat_keyboard_enter(struct wlr_seat *wlr_seat, + struct wlr_surface *surface, struct wl_array keys); + +/** + * Clear the focused surface for the keyboard and leave all entered surfaces. + */ +void wlr_seat_keyboard_clear_focus(struct wlr_seat *wlr_seat); + +/** + * Send a key event to the surface with keyboard focus. Returns the event + * serial. + */ +uint32_t wlr_seat_keyboard_send_key(struct wlr_seat *wlr_seat, uint32_t time, + uint32_t key, uint32_t state); + +/** + * Send the modifiers event to the surface with keyboard focus. Also sends the + * event to the surface with pointer focus. + */ +void wlr_seat_keyboard_send_modifiers(struct wlr_seat *wlr_seat, + uint32_t mods_depressed, uint32_t mods_latched, uint32_t mods_locked, + uint32_t group); + +/** + * Set the keymap and send it to seat keyboard resources. + */ +void wlr_seat_keyboard_set_keymap(struct wlr_seat *wlr_seat, int keymap_fd, + size_t keymap_size); + #endif diff --git a/include/wlr/types/wlr_surface.h b/include/wlr/types/wlr_surface.h index f0765160..87d421e3 100644 --- a/include/wlr/types/wlr_surface.h +++ b/include/wlr/types/wlr_surface.h @@ -1,8 +1,10 @@ -#ifndef _WLR_TYPES_WLR_SURFACE_H -#define _WLR_TYPES_WLR_SURFACE_H +#ifndef WLR_TYPES_WLR_SURFACE_H +#define WLR_TYPES_WLR_SURFACE_H + #include <wayland-server.h> #include <pixman.h> #include <stdint.h> +#include <stdbool.h> struct wlr_frame_callback { struct wl_resource *resource; @@ -42,6 +44,7 @@ struct wlr_surface { struct { struct wl_signal commit; + struct wl_signal destroy; } signals; struct wl_list frame_callback_list; // wl_surface.frame @@ -69,4 +72,12 @@ void wlr_surface_get_matrix(struct wlr_surface *surface, const float (*projection)[16], const float (*transform)[16]); + +/** + * Set the lifetime role for this surface. Returns 0 on success or -1 if the + * role cannot be set. + */ +int wlr_surface_set_role(struct wlr_surface *surface, const char *role, + struct wl_resource *error_resource, uint32_t error_code); + #endif diff --git a/include/wlr/types/wlr_tablet_pad.h b/include/wlr/types/wlr_tablet_pad.h index 6c14c669..b747e6f1 100644 --- a/include/wlr/types/wlr_tablet_pad.h +++ b/include/wlr/types/wlr_tablet_pad.h @@ -1,5 +1,6 @@ -#ifndef _WLR_TYPES_TABLET_PAD_H -#define _WLR_TYPES_TABLET_PAD_H +#ifndef WLR_TYPES_WLR_TABLET_PAD_H +#define WLR_TYPES_WLR_TABLET_PAD_H + #include <wlr/types/wlr_input_device.h> #include <wayland-server.h> #include <stdint.h> diff --git a/include/wlr/types/wlr_tablet_tool.h b/include/wlr/types/wlr_tablet_tool.h index 9090828a..f04dfe15 100644 --- a/include/wlr/types/wlr_tablet_tool.h +++ b/include/wlr/types/wlr_tablet_tool.h @@ -1,5 +1,6 @@ -#ifndef _WLR_TYPES_TABLET_TOOL_H -#define _WLR_TYPES_TABLET_TOOL_H +#ifndef WLR_TYPES_TABLET_TOOL_H +#define WLR_TYPES_TABLET_TOOL_H + #include <wlr/types/wlr_input_device.h> #include <wayland-server.h> #include <stdint.h> diff --git a/include/wlr/types/wlr_touch.h b/include/wlr/types/wlr_touch.h index 1a27cad3..f1165c87 100644 --- a/include/wlr/types/wlr_touch.h +++ b/include/wlr/types/wlr_touch.h @@ -1,5 +1,6 @@ -#ifndef _WLR_TYPES_TOUCH_H -#define _WLR_TYPES_TOUCH_H +#ifndef WLR_TYPES_WLR_TOUCH_H +#define WLR_TYPES_WLR_TOUCH_H + #include <wayland-server.h> #include <stdint.h> diff --git a/include/wlr/types/wlr_wl_shell.h b/include/wlr/types/wlr_wl_shell.h index a085711b..1443bbf0 100644 --- a/include/wlr/types/wlr_wl_shell.h +++ b/include/wlr/types/wlr_wl_shell.h @@ -1,5 +1,6 @@ -#ifndef _WLR_WL_SHELL_H -#define _WLR_WL_SHELL_H +#ifndef WLR_TYPES_WLR_WL_SHELL_H +#define WLR_TYPES_WLR_WL_SHELL_H + #include <wayland-server.h> struct wlr_wl_shell { diff --git a/include/wlr/types/wlr_xdg_shell_v6.h b/include/wlr/types/wlr_xdg_shell_v6.h index 41cf483a..cc52d9c7 100644 --- a/include/wlr/types/wlr_xdg_shell_v6.h +++ b/include/wlr/types/wlr_xdg_shell_v6.h @@ -1,24 +1,175 @@ -#ifndef _WLR_XDG_SHELL_V6_H -#define _WLR_XDG_SHELL_V6_H +#ifndef WLR_TYPES_WLR_XDG_SHELL_V6_H +#define WLR_TYPES_WLR_XDG_SHELL_V6_H + +#include <wlr/types/wlr_box.h> #include <wayland-server.h> struct wlr_xdg_shell_v6 { struct wl_global *wl_global; - struct wl_list wl_resources; - struct wl_list surfaces; + struct wl_list clients; + uint32_t ping_timeout; + + struct { + struct wl_signal new_surface; + } events; void *data; }; +struct wlr_xdg_client_v6 { + struct wlr_xdg_shell_v6 *shell; + struct wl_resource *resource; + struct wl_client *client; + struct wl_list surfaces; + + struct wl_list link; // wlr_xdg_shell_v6::clients + + uint32_t ping_serial; + struct wl_event_source *ping_timer; +}; + + +enum wlr_xdg_surface_v6_role { + WLR_XDG_SURFACE_V6_ROLE_NONE, + WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL, + WLR_XDG_SURFACE_V6_ROLE_POPUP, +}; + +struct wlr_xdg_toplevel_v6_state { + bool maximized; + bool fullscreen; + bool resizing; + bool activated; + + uint32_t width; + uint32_t height; + + uint32_t max_width; + uint32_t max_height; + + uint32_t min_width; + uint32_t min_height; +}; + +struct wlr_xdg_toplevel_v6 { + struct wl_resource *resource; + struct wlr_xdg_surface_v6 *base; + struct wlr_xdg_surface_v6 *parent; + bool added; + struct wlr_xdg_toplevel_v6_state next; // client protocol requests + struct wlr_xdg_toplevel_v6_state pending; // user configure requests + struct wlr_xdg_toplevel_v6_state current; +}; + +// TODO split up into toplevel and popup configure +struct wlr_xdg_surface_v6_configure { + struct wl_list link; // wlr_xdg_surface_v6::configure_list + uint32_t serial; + struct wlr_xdg_toplevel_v6_state state; +}; + struct wlr_xdg_surface_v6 { + struct wlr_xdg_client_v6 *client; struct wl_resource *resource; - struct wl_resource *surface; - struct wl_list link; + struct wlr_surface *surface; + struct wl_list link; // wlr_xdg_client_v6::surfaces + enum wlr_xdg_surface_v6_role role; + struct wlr_xdg_toplevel_v6 *toplevel_state; + + bool configured; + struct wl_event_source *configure_idle; + struct wl_list configure_list; + + char *title; + char *app_id; + + bool has_next_geometry; + struct wlr_box *next_geometry; + struct wlr_box *geometry; + + struct wl_listener surface_destroy_listener; + struct wl_listener surface_commit_listener; + + struct { + struct wl_signal commit; + struct wl_signal destroy; + struct wl_signal ack_configure; + struct wl_signal ping_timeout; + + struct wl_signal request_minimize; + struct wl_signal request_move; + struct wl_signal request_resize; + struct wl_signal request_show_window_menu; + } events; void *data; }; +struct wlr_xdg_toplevel_v6_move_event { + struct wl_client *client; + struct wlr_xdg_surface_v6 *surface; + struct wlr_seat_handle *seat_handle; + 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; + uint32_t serial; + uint32_t edges; +}; + +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; + uint32_t serial; + uint32_t x; + uint32_t y; +}; + struct wlr_xdg_shell_v6 *wlr_xdg_shell_v6_create(struct wl_display *display); void wlr_xdg_shell_v6_destroy(struct wlr_xdg_shell_v6 *xdg_shell); +/** + * Send a ping to the surface. If the surface does not respond in a reasonable + * amount of time, the ping_timeout event will be emitted. + */ +void wlr_xdg_surface_v6_ping(struct wlr_xdg_surface_v6 *surface); + +/** + * Request that this toplevel surface be the given size. + */ +void wlr_xdg_toplevel_v6_set_size(struct wlr_xdg_surface_v6 *surface, + uint32_t width, uint32_t height); + +/** + * Request that this toplevel surface show itself in an activated or deactivated + * state. + */ +void wlr_xdg_toplevel_v6_set_activated(struct wlr_xdg_surface_v6 *surface, + bool activated); + +/** + * Request that this toplevel surface consider itself maximized or not + * maximized. + */ +void wlr_xdg_toplevel_v6_set_maximized(struct wlr_xdg_surface_v6 *surface, + bool maximized); + +/** + * Request that this toplevel surface consider itself fullscreen or not + * fullscreen. + */ +void wlr_xdg_toplevel_v6_set_fullscreen(struct wlr_xdg_surface_v6 *surface, + bool fullscreen); + +/** + * Request that this toplevel surface consider itself to be resizing or not + * resizing. + */ +void wlr_xdg_toplevel_v6_set_resizing(struct wlr_xdg_surface_v6 *surface, + bool resizing); + #endif diff --git a/include/wlr/util/list.h b/include/wlr/util/list.h index 6e746ec4..02039d89 100644 --- a/include/wlr/util/list.h +++ b/include/wlr/util/list.h @@ -1,5 +1,5 @@ -#ifndef _WLR_UTIL_LIST_H -#define _WLR_UTIL_LIST_H +#ifndef WLR_UTIL_LIST_H +#define WLR_UTIL_LIST_H #include <stddef.h> diff --git a/include/wlr/util/log.h b/include/wlr/util/log.h index 2acaa2ed..3de2cacf 100644 --- a/include/wlr/util/log.h +++ b/include/wlr/util/log.h @@ -1,5 +1,6 @@ -#ifndef _WLR_UTIL_LOG_H -#define _WLR_UTIL_LOG_H +#ifndef WLR_UTIL_LOG_H +#define WLR_UTIL_LOG_H + #include <stdbool.h> #include <stdarg.h> #include <string.h> diff --git a/include/wlr/xcursor.h b/include/wlr/xcursor.h index ae07b4fa..c12d5405 100644 --- a/include/wlr/xcursor.h +++ b/include/wlr/xcursor.h @@ -27,8 +27,10 @@ * This is adapted from wayland-cursor, but with the wl_shm client stuff removed * so we can use it on the compositor, too. */ -#ifndef _WLR_XCURSOR_H -#define _WLR_XCURSOR_H + +#ifndef WLR_XCURSOR_H +#define WLR_XCURSOR_H + #include <stdint.h> struct wlr_xcursor_image { diff --git a/include/wlr/xwayland.h b/include/wlr/xwayland.h index a0fb34ce..41b8042f 100644 --- a/include/wlr/xwayland.h +++ b/include/wlr/xwayland.h @@ -1,5 +1,6 @@ -#ifndef _WLR_XWAYLAND_H -#define _WLR_XWAYLAND_H +#ifndef WLR_XWAYLAND_H +#define WLR_XWAYLAND_H + #include <time.h> #include <stdbool.h> #include <wlr/types/wlr_compositor.h> diff --git a/meson.build b/meson.build index ceded2d1..194e7111 100644 --- a/meson.build +++ b/meson.build @@ -20,6 +20,7 @@ add_project_link_arguments( ) wlr_inc = include_directories('include') +install_subdir('include/wlr', install_dir: 'include') cc = meson.get_compiler('c') @@ -46,6 +47,7 @@ xcb = dependency('xcb') xcb_composite = dependency('xcb-composite') libcap = dependency('libcap', required: false) systemd = dependency('libsystemd', required: false) +elogind = dependency('libelogind', required: false) math = cc.find_library('m', required: false) if libcap.found() and get_option('enable_libcap') @@ -56,6 +58,10 @@ if systemd.found() and get_option('enable_systemd') add_project_arguments('-DHAS_SYSTEMD', language: 'c') endif +if elogind.found() and get_option('enable_elogind') + add_project_arguments('-DHAS_ELOGIND', language: 'c') +endif + subdir('protocol') subdir('backend') subdir('render') @@ -98,6 +104,7 @@ lib_wlr = library( ], dependencies: wlr_deps, include_directories: wlr_inc, + install: true, ) wlroots = declare_dependency( @@ -107,3 +114,12 @@ wlroots = declare_dependency( ) subdir('examples') + +pkgconfig = import('pkgconfig') +pkgconfig.generate( + libraries: lib_wlr, + version: '0.0.1', + filebase: 'wlroots', + name: 'wlroots', + description: 'Wayland compositor library', +) diff --git a/meson_options.txt b/meson_options.txt index ab74eec1..a3f9ca45 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -1,2 +1,3 @@ option('enable_libcap', type: 'boolean', value: true, description: 'Enable support for capabilities') option('enable_systemd', type: 'boolean', value: true, description: 'Enable support for logind') +option('enable_elogind', type: 'boolean', value: true, description: 'Enable support for logind') diff --git a/render/egl.c b/render/egl.c index 73680d1d..048626ba 100644 --- a/render/egl.c +++ b/render/egl.c @@ -59,7 +59,7 @@ static bool egl_exts(struct wlr_egl *egl) { egl->create_platform_window_surface = (PFNEGLCREATEPLATFORMWINDOWSURFACEEXTPROC) eglGetProcAddress("eglCreatePlatformWindowSurfaceEXT"); - if (!egl->get_platform_display) { + if (!egl->create_platform_window_surface) { wlr_log(L_ERROR, "Failed to load EGL extension 'eglCreatePlatformWindowSurfaceEXT'"); return false; @@ -175,13 +175,14 @@ bool wlr_egl_init(struct wlr_egl *egl, EGLenum platform, return true; error: + eglMakeCurrent(EGL_NO_DISPLAY, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); eglTerminate(egl->display); eglReleaseThread(); - eglMakeCurrent(EGL_NO_DISPLAY, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); return false; } void wlr_egl_free(struct wlr_egl *egl) { + eglMakeCurrent(EGL_NO_DISPLAY, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); if (egl->wl_display && egl->eglUnbindWaylandDisplayWL) { egl->eglUnbindWaylandDisplayWL(egl->display, egl->wl_display); } @@ -189,7 +190,6 @@ void wlr_egl_free(struct wlr_egl *egl) { eglDestroyContext(egl->display, egl->context); eglTerminate(egl->display); eglReleaseThread(); - eglMakeCurrent(EGL_NO_DISPLAY, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); } bool wlr_egl_bind_display(struct wlr_egl *egl, struct wl_display *local_display) { diff --git a/types/wlr_seat.c b/types/wlr_seat.c index 2c1abd94..1d544902 100644 --- a/types/wlr_seat.c +++ b/types/wlr_seat.c @@ -4,6 +4,7 @@ #include <string.h> #include <wayland-server.h> #include <wlr/types/wlr_seat.h> +#include <wlr/types/wlr_input_device.h> #include <wlr/util/log.h> static void resource_destroy(struct wl_client *client, @@ -12,11 +13,11 @@ static void resource_destroy(struct wl_client *client, } static void wl_pointer_set_cursor(struct wl_client *client, - struct wl_resource *resource, - uint32_t serial, - struct wl_resource *surface, - int32_t hotspot_x, - int32_t hotspot_y) { + struct wl_resource *resource, + uint32_t serial, + struct wl_resource *surface, + int32_t hotspot_x, + int32_t hotspot_y) { wlr_log(L_DEBUG, "TODO: wl_pointer_set_cursor"); } @@ -69,7 +70,7 @@ static void wl_seat_get_keyboard(struct wl_client *client, } if (handle->keyboard) { // TODO: this is probably a protocol violation but it simplifies our - // code and it'd be stupid for clients to create several pointers for + // code and it'd be stupid for clients to create several keyboards for // the same seat wl_resource_destroy(handle->keyboard); } @@ -77,6 +78,20 @@ static void wl_seat_get_keyboard(struct wl_client *client, wl_resource_get_version(_handle), id); wl_resource_set_implementation(handle->keyboard, &wl_keyboard_impl, handle, &wl_keyboard_destroy); + + if (wl_resource_get_version(handle->keyboard) >= + WL_KEYBOARD_REPEAT_INFO_SINCE_VERSION) { + wl_keyboard_send_repeat_info(handle->keyboard, 25, 600); + } + + if (handle->wlr_seat->keyboard_state.keymap_size) { + // TODO: handle no keymap + wl_keyboard_send_keymap(handle->keyboard, + WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1, + handle->wlr_seat->keyboard_state.keymap_fd, + handle->wlr_seat->keyboard_state.keymap_size); + } + wl_signal_emit(&handle->wlr_seat->events.keyboard_bound, handle); } @@ -109,8 +124,15 @@ static void wl_seat_get_touch(struct wl_client *client, handle, &wl_touch_destroy); } -static void wl_seat_destroy(struct wl_resource *resource) { +static void wlr_seat_handle_resource_destroy(struct wl_resource *resource) { struct wlr_seat_handle *handle = wl_resource_get_user_data(resource); + if (handle == handle->wlr_seat->pointer_state.focused_handle) { + handle->wlr_seat->pointer_state.focused_handle = NULL; + } + if (handle == handle->wlr_seat->keyboard_state.focused_handle) { + handle->wlr_seat->keyboard_state.focused_handle = NULL; + } + if (handle->pointer) { wl_resource_destroy(handle->pointer); } @@ -140,7 +162,8 @@ static void wl_seat_bind(struct wl_client *wl_client, void *_wlr_seat, struct wlr_seat *wlr_seat = _wlr_seat; assert(wl_client && wlr_seat); if (version > 6) { - wlr_log(L_ERROR, "Client requested unsupported wl_seat version, disconnecting"); + wlr_log(L_ERROR, + "Client requested unsupported wl_seat version, disconnecting"); wl_client_destroy(wl_client); return; } @@ -149,7 +172,7 @@ static void wl_seat_bind(struct wl_client *wl_client, void *_wlr_seat, wl_client, &wl_seat_interface, version, id); handle->wlr_seat = wlr_seat; wl_resource_set_implementation(handle->wl_resource, &wl_seat_impl, - handle, wl_seat_destroy); + handle, wlr_seat_handle_resource_destroy); wl_list_insert(&wlr_seat->handles, &handle->link); wl_seat_send_capabilities(handle->wl_resource, wlr_seat->capabilities); wl_signal_emit(&wlr_seat->events.client_bound, handle); @@ -160,6 +183,17 @@ struct wlr_seat *wlr_seat_create(struct wl_display *display, const char *name) { if (!wlr_seat) { return NULL; } + + wlr_seat->pointer_state.wlr_seat = wlr_seat; + wl_list_init(&wlr_seat->pointer_state.focus_resource_destroy_listener.link); + wl_list_init(&wlr_seat->pointer_state.focus_surface_destroy_listener.link); + + wlr_seat->keyboard_state.wlr_seat = wlr_seat; + wl_list_init( + &wlr_seat->keyboard_state.focus_resource_destroy_listener.link); + wl_list_init( + &wlr_seat->keyboard_state.focus_surface_destroy_listener.link); + struct wl_global *wl_global = wl_global_create(display, &wl_seat_interface, 6, wlr_seat, wl_seat_bind); if (!wl_global) { @@ -167,11 +201,14 @@ struct wlr_seat *wlr_seat_create(struct wl_display *display, const char *name) { return NULL; } wlr_seat->wl_global = wl_global; + wlr_seat->display = display; wlr_seat->name = strdup(name); wl_list_init(&wlr_seat->handles); + wl_signal_init(&wlr_seat->events.client_bound); wl_signal_init(&wlr_seat->events.client_unbound); wl_signal_init(&wlr_seat->events.keyboard_bound); + return wlr_seat; } @@ -182,7 +219,8 @@ void wlr_seat_destroy(struct wlr_seat *wlr_seat) { struct wlr_seat_handle *handle, *tmp; wl_list_for_each_safe(handle, tmp, &wlr_seat->handles, link) { - wl_resource_destroy(handle->wl_resource); // will destroy other resources as well + // will destroy other resources as well + wl_resource_destroy(handle->wl_resource); } wl_global_destroy(wlr_seat->wl_global); @@ -220,3 +258,281 @@ void wlr_seat_set_name(struct wlr_seat *wlr_seat, const char *name) { wl_seat_send_name(handle->wl_resource, name); } } + +bool wlr_seat_pointer_surface_has_focus(struct wlr_seat *wlr_seat, + struct wlr_surface *surface) { + return surface == wlr_seat->pointer_state.focused_surface; +} + +static void handle_pointer_focus_surface_destroyed( + struct wl_listener *listener, void *data) { + struct wlr_seat_pointer_state *state = + wl_container_of(listener, state, focus_surface_destroy_listener); + + state->focused_surface = NULL; + wlr_seat_pointer_clear_focus(state->wlr_seat); +} + +static void handle_pointer_focus_resource_destroyed( + struct wl_listener *listener, void *data) { + struct wlr_seat_pointer_state *state = + wl_container_of(listener, state, focus_resource_destroy_listener); + + state->focused_surface = NULL; + wlr_seat_pointer_clear_focus(state->wlr_seat); +} + +static bool wlr_seat_pointer_has_focus_resource(struct wlr_seat *wlr_seat) { + return wlr_seat->pointer_state.focused_handle && + wlr_seat->pointer_state.focused_handle->pointer; +} + +void wlr_seat_pointer_enter(struct wlr_seat *wlr_seat, + struct wlr_surface *surface, double sx, double sy) { + assert(wlr_seat); + + if (wlr_seat->pointer_state.focused_surface == surface) { + // this surface already got an enter notify + return; + } + + struct wlr_seat_handle *handle = NULL; + + if (surface) { + struct wl_client *client = wl_resource_get_client(surface->resource); + handle = wlr_seat_handle_for_client(wlr_seat, client); + } + + struct wlr_seat_handle *focused_handle = + wlr_seat->pointer_state.focused_handle; + struct wlr_surface *focused_surface = + wlr_seat->pointer_state.focused_surface; + + // leave the previously entered surface + if (focused_handle && focused_handle->pointer && focused_surface) { + uint32_t serial = wl_display_next_serial(wlr_seat->display); + wl_pointer_send_leave(focused_handle->pointer, serial, + focused_surface->resource); + wl_pointer_send_frame(focused_handle->pointer); + } + + // enter the current surface + if (handle && handle->pointer) { + uint32_t serial = wl_display_next_serial(wlr_seat->display); + wl_pointer_send_enter(handle->pointer, serial, surface->resource, + wl_fixed_from_double(sx), wl_fixed_from_double(sy)); + wl_pointer_send_frame(handle->pointer); + } + + // reinitialize the focus destroy events + wl_list_remove( + &wlr_seat->pointer_state.focus_surface_destroy_listener.link); + wl_list_init(&wlr_seat->pointer_state.focus_surface_destroy_listener.link); + wl_list_remove( + &wlr_seat->pointer_state.focus_resource_destroy_listener.link); + wl_list_init(&wlr_seat->pointer_state.focus_resource_destroy_listener.link); + if (surface) { + wl_signal_add(&surface->signals.destroy, + &wlr_seat->pointer_state.focus_surface_destroy_listener); + wl_resource_add_destroy_listener(surface->resource, + &wlr_seat->pointer_state.focus_resource_destroy_listener); + wlr_seat->pointer_state.focus_resource_destroy_listener.notify = + handle_pointer_focus_resource_destroyed; + wlr_seat->pointer_state.focus_surface_destroy_listener.notify = + handle_pointer_focus_surface_destroyed; + } + + wlr_seat->pointer_state.focused_handle = handle; + wlr_seat->pointer_state.focused_surface = surface; + + // TODO: send focus change event +} + +void wlr_seat_pointer_clear_focus(struct wlr_seat *wlr_seat) { + wlr_seat_pointer_enter(wlr_seat, NULL, 0, 0); +} + +void wlr_seat_pointer_send_motion(struct wlr_seat *wlr_seat, uint32_t time, + double sx, double sy) { + if (!wlr_seat_pointer_has_focus_resource(wlr_seat)) { + return; + } + + wl_pointer_send_motion(wlr_seat->pointer_state.focused_handle->pointer, + time, wl_fixed_from_double(sx), wl_fixed_from_double(sy)); + wl_pointer_send_frame(wlr_seat->pointer_state.focused_handle->pointer); +} + +uint32_t wlr_seat_pointer_send_button(struct wlr_seat *wlr_seat, uint32_t time, + uint32_t button, uint32_t state) { + if (!wlr_seat_pointer_has_focus_resource(wlr_seat)) { + return 0; + } + + uint32_t serial = wl_display_next_serial(wlr_seat->display); + wl_pointer_send_button(wlr_seat->pointer_state.focused_handle->pointer, + serial, time, button, state); + wl_pointer_send_frame(wlr_seat->pointer_state.focused_handle->pointer); + return serial; +} + +void wlr_seat_pointer_send_axis(struct wlr_seat *wlr_seat, uint32_t time, + enum wlr_axis_orientation orientation, double value) { + if (!wlr_seat_pointer_has_focus_resource(wlr_seat)) { + return; + } + + struct wl_resource *pointer = + wlr_seat->pointer_state.focused_handle->pointer; + + if (value) { + wl_pointer_send_axis(pointer, time, orientation, + wl_fixed_from_double(value)); + } else { + wl_pointer_send_axis_stop(pointer, time, orientation); + } + + wl_pointer_send_frame(pointer); +} + +static void handle_keyboard_focus_surface_destroyed( + struct wl_listener *listener, void *data) { + struct wlr_seat_keyboard_state *state = + wl_container_of(listener, state, focus_surface_destroy_listener); + + state->focused_surface = NULL; + wlr_seat_keyboard_clear_focus(state->wlr_seat); +} + +static void handle_keyboard_focus_resource_destroyed( + struct wl_listener *listener, void *data) { + struct wlr_seat_keyboard_state *state = + wl_container_of(listener, state, focus_resource_destroy_listener); + + state->focused_surface = NULL; + wlr_seat_keyboard_clear_focus(state->wlr_seat); +} + +void wlr_seat_keyboard_enter(struct wlr_seat *wlr_seat, + struct wlr_surface *surface, struct wl_array keys) { + if (wlr_seat->keyboard_state.focused_surface == surface) { + // this surface already got an enter notify + return; + } + + struct wlr_seat_handle *handle = NULL; + + if (surface) { + struct wl_client *client = wl_resource_get_client(surface->resource); + handle = wlr_seat_handle_for_client(wlr_seat, client); + } + + struct wlr_seat_handle *focused_handle = + wlr_seat->keyboard_state.focused_handle; + struct wlr_surface *focused_surface = + wlr_seat->keyboard_state.focused_surface; + + // leave the previously entered surface + if (focused_handle && focused_handle->keyboard && focused_surface) { + uint32_t serial = wl_display_next_serial(wlr_seat->display); + wl_keyboard_send_leave(focused_handle->keyboard, serial, + focused_surface->resource); + } + + // enter the current surface + if (handle && handle->keyboard) { + uint32_t serial = wl_display_next_serial(wlr_seat->display); + wl_keyboard_send_enter(handle->keyboard, serial, + surface->resource, &keys); + + // TODO: send modifiers + } + + // reinitialize the focus destroy events + wl_list_remove( + &wlr_seat->keyboard_state.focus_surface_destroy_listener.link); + wl_list_init(&wlr_seat->keyboard_state.focus_surface_destroy_listener.link); + wl_list_remove( + &wlr_seat->keyboard_state.focus_resource_destroy_listener.link); + wl_list_init( + &wlr_seat->keyboard_state.focus_resource_destroy_listener.link); + if (surface) { + wl_signal_add(&surface->signals.destroy, + &wlr_seat->keyboard_state.focus_surface_destroy_listener); + wl_resource_add_destroy_listener(surface->resource, + &wlr_seat->keyboard_state.focus_resource_destroy_listener); + wlr_seat->keyboard_state.focus_resource_destroy_listener.notify = + handle_keyboard_focus_resource_destroyed; + wlr_seat->keyboard_state.focus_surface_destroy_listener.notify = + handle_keyboard_focus_surface_destroyed; + } + + wlr_seat->keyboard_state.focused_handle = handle; + wlr_seat->keyboard_state.focused_surface = surface; +} + +void wlr_seat_keyboard_clear_focus(struct wlr_seat *wlr_seat) { + struct wl_array keys; + wl_array_init(&keys); + wlr_seat_keyboard_enter(wlr_seat, NULL, keys); +} + +static bool wlr_seat_keyboard_has_focus_resource(struct wlr_seat *wlr_seat) { + return wlr_seat->keyboard_state.focused_handle && + wlr_seat->keyboard_state.focused_handle->keyboard; +} + +uint32_t wlr_seat_keyboard_send_key(struct wlr_seat *wlr_seat, uint32_t time, + uint32_t key, uint32_t state) { + if (!wlr_seat_keyboard_has_focus_resource(wlr_seat)) { + return 0; + } + + uint32_t serial = wl_display_next_serial(wlr_seat->display); + wl_keyboard_send_key(wlr_seat->keyboard_state.focused_handle->keyboard, + serial, time, key, state); + + return serial; +} + +void wlr_seat_keyboard_send_modifiers(struct wlr_seat *wlr_seat, + uint32_t mods_depressed, uint32_t mods_latched, uint32_t mods_locked, + uint32_t group) { + uint32_t serial = 0; + struct wl_resource *keyboard; + + if (wlr_seat_keyboard_has_focus_resource(wlr_seat)) { + serial = wl_display_next_serial(wlr_seat->display); + keyboard = wlr_seat->keyboard_state.focused_handle->keyboard; + wl_keyboard_send_modifiers(keyboard, serial, mods_depressed, + mods_latched, mods_locked, group); + } + + if (wlr_seat_pointer_has_focus_resource(wlr_seat) && + wlr_seat->pointer_state.focused_handle->keyboard && + wlr_seat->pointer_state.focused_handle != + wlr_seat->keyboard_state.focused_handle) { + if (serial == 0) { + serial = wl_display_next_serial(wlr_seat->display); + } + keyboard = wlr_seat->pointer_state.focused_handle->keyboard; + + wl_keyboard_send_modifiers(keyboard, serial, mods_depressed, + mods_latched, mods_locked, group); + } +} + +void wlr_seat_keyboard_set_keymap(struct wlr_seat *wlr_seat, int keymap_fd, + size_t keymap_size) { + // TODO: we probably should wait to send the keymap if keys are pressed + struct wlr_seat_handle *handle; + wl_list_for_each(handle, &wlr_seat->handles, link) { + if (handle->keyboard) { + wl_keyboard_send_keymap(handle->keyboard, + WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1, keymap_fd, keymap_size); + } + } + + wlr_seat->keyboard_state.keymap_fd = keymap_fd; + wlr_seat->keyboard_state.keymap_size = keymap_size; +} diff --git a/types/wlr_surface.c b/types/wlr_surface.c index e733c544..a9a54abe 100644 --- a/types/wlr_surface.c +++ b/types/wlr_surface.c @@ -365,6 +365,7 @@ const struct wl_surface_interface surface_interface = { static void destroy_surface(struct wl_resource *resource) { struct wlr_surface *surface = wl_resource_get_user_data(resource); + wl_signal_emit(&surface->signals.destroy, surface); wlr_texture_destroy(surface->texture); struct wlr_frame_callback *cb, *next; @@ -399,6 +400,7 @@ struct wlr_surface *wlr_surface_create(struct wl_resource *res, pixman_region32_init(&surface->pending.opaque); pixman_region32_init(&surface->pending.input); wl_signal_init(&surface->signals.commit); + wl_signal_init(&surface->signals.destroy); wl_list_init(&surface->frame_callback_list); wl_resource_set_implementation(res, &surface_interface, surface, destroy_surface); @@ -420,3 +422,24 @@ void wlr_surface_get_matrix(struct wlr_surface *surface, wlr_matrix_mul(matrix, &scale, matrix); wlr_matrix_mul(projection, matrix, matrix); } + +int wlr_surface_set_role(struct wlr_surface *surface, const char *role, + struct wl_resource *error_resource, uint32_t error_code) { + assert(role); + + if (surface->role == NULL || + surface->role == role || + strcmp(surface->role, role) == 0) { + surface->role = role; + + return 0; + } + + wl_resource_post_error(error_resource, error_code, + "Cannot assign role %s to wl_surface@%d, already has role %s\n", + role, + wl_resource_get_id(surface->resource), + surface->role); + + return -1; +} diff --git a/types/wlr_xdg_shell_v6.c b/types/wlr_xdg_shell_v6.c index b5df9bd8..a7450add 100644 --- a/types/wlr_xdg_shell_v6.c +++ b/types/wlr_xdg_shell_v6.c @@ -1,111 +1,266 @@ +#ifndef _POSIX_C_SOURCE +#define _POSIX_C_SOURCE 200809L +#endif #include <assert.h> #include <stdlib.h> +#include <string.h> #include <wayland-server.h> #include <wlr/types/wlr_xdg_shell_v6.h> +#include <wlr/types/wlr_surface.h> +#include <wlr/types/wlr_seat.h> #include <wlr/util/log.h> #include "xdg-shell-unstable-v6-protocol.h" -static void resource_destroy(struct wl_client *client, struct wl_resource *resource) { - // TODO: we probably need to do more than this +static const char *wlr_desktop_xdg_toplevel_role = "xdg_toplevel"; + +static void resource_destroy(struct wl_client *client, + struct wl_resource *resource) { wl_resource_destroy(resource); } -static void xdg_toplevel_set_parent(struct wl_client *client, +static void xdg_toplevel_protocol_set_parent(struct wl_client *client, struct wl_resource *resource, struct wl_resource *parent_resource) { - wlr_log(L_DEBUG, "TODO: toplevel set parent"); + struct wlr_xdg_surface_v6 *surface = wl_resource_get_user_data(resource); + struct wlr_xdg_surface_v6 *parent = NULL; + + if (parent_resource != NULL) { + parent = wl_resource_get_user_data(parent_resource); + } + + surface->toplevel_state->parent = parent; } -static void xdg_toplevel_set_title(struct wl_client *client, +static void xdg_toplevel_protocol_set_title(struct wl_client *client, struct wl_resource *resource, const char *title) { - wlr_log(L_DEBUG, "TODO: toplevel set title"); + struct wlr_xdg_surface_v6 *surface = wl_resource_get_user_data(resource); + char *tmp; + + tmp = strdup(title); + if (tmp == NULL) { + return; + } + + free(surface->title); + surface->title = tmp; } -static void xdg_toplevel_set_app_id(struct wl_client *client, +static void xdg_toplevel_protocol_set_app_id(struct wl_client *client, struct wl_resource *resource, const char *app_id) { - wlr_log(L_DEBUG, "TODO: toplevel set app id"); + struct wlr_xdg_surface_v6 *surface = wl_resource_get_user_data(resource); + char *tmp; + + tmp = strdup(app_id); + if (tmp == NULL) { + return; + } + + free(surface->app_id); + surface->app_id = tmp; } -static void xdg_toplevel_show_window_menu(struct wl_client *client, - struct wl_resource *resource, struct wl_resource *seat, uint32_t serial, - int32_t x, int32_t y) { - wlr_log(L_DEBUG, "TODO: toplevel show window menu"); +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 = + wl_resource_get_user_data(seat_resource); + + if (!surface->configured) { + wl_resource_post_error(surface->toplevel_state->resource, + ZXDG_SURFACE_V6_ERROR_NOT_CONSTRUCTED, + "surface has not been configured yet"); + return; + } + + struct wlr_xdg_toplevel_v6_show_window_menu_event *event = + calloc(1, sizeof(struct wlr_xdg_toplevel_v6_show_window_menu_event)); + if (event == NULL) { + wl_client_post_no_memory(client); + return; + } + + event->client = client; + event->surface = surface; + event->seat_handle = seat_handle; + event->serial = serial; + event->x = x; + event->y = y; + + wl_signal_emit(&surface->events.request_show_window_menu, event); + + free(event); } -static void xdg_toplevel_move(struct wl_client *client, +static void xdg_toplevel_protocol_move(struct wl_client *client, struct wl_resource *resource, struct wl_resource *seat_resource, uint32_t serial) { - wlr_log(L_DEBUG, "TODO: toplevel move"); + struct wlr_xdg_surface_v6 *surface = wl_resource_get_user_data(resource); + struct wlr_seat_handle *seat_handle = + wl_resource_get_user_data(seat_resource); + + if (!surface->configured) { + wl_resource_post_error(surface->toplevel_state->resource, + ZXDG_SURFACE_V6_ERROR_NOT_CONSTRUCTED, + "surface has not been configured yet"); + return; + } + + struct wlr_xdg_toplevel_v6_move_event *event = + calloc(1, sizeof(struct wlr_xdg_toplevel_v6_move_event)); + if (event == NULL) { + wl_client_post_no_memory(client); + return; + } + + event->client = client; + event->surface = surface; + event->seat_handle = seat_handle; + event->serial = serial; + + wl_signal_emit(&surface->events.request_move, event); + + free(event); } -static void xdg_toplevel_resize(struct wl_client *client, +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) { - wlr_log(L_DEBUG, "TODO: toplevel resize"); + struct wlr_xdg_surface_v6 *surface = wl_resource_get_user_data(resource); + struct wlr_seat_handle *seat_handle = + wl_resource_get_user_data(seat_resource); + + if (!surface->configured) { + wl_resource_post_error(surface->toplevel_state->resource, + ZXDG_SURFACE_V6_ERROR_NOT_CONSTRUCTED, + "surface has not been configured yet"); + return; + } + + struct wlr_xdg_toplevel_v6_resize_event *event = + calloc(1, sizeof(struct wlr_xdg_toplevel_v6_resize_event)); + if (event == NULL) { + wl_client_post_no_memory(client); + return; + } + + event->client = client; + event->surface = surface; + event->seat_handle = seat_handle; + event->serial = serial; + event->edges = edges; + + wl_signal_emit(&surface->events.request_resize, event); + + free(event); } -static void xdg_toplevel_set_max_size(struct wl_client *client, +static void xdg_toplevel_protocol_set_max_size(struct wl_client *client, struct wl_resource *resource, int32_t width, int32_t height) { - wlr_log(L_DEBUG, "TODO: toplevel set max size"); + struct wlr_xdg_surface_v6 *surface = wl_resource_get_user_data(resource); + surface->toplevel_state->next.max_width = width; + surface->toplevel_state->next.max_height = height; } -static void xdg_toplevel_set_min_size(struct wl_client *client, +static void xdg_toplevel_protocol_set_min_size(struct wl_client *client, struct wl_resource *resource, int32_t width, int32_t height) { - wlr_log(L_DEBUG, "TODO: toplevel set min size"); + struct wlr_xdg_surface_v6 *surface = wl_resource_get_user_data(resource); + surface->toplevel_state->next.min_width = width; + surface->toplevel_state->next.min_height = height; } -static void xdg_toplevel_set_maximized(struct wl_client *client, +static void xdg_toplevel_protocol_set_maximized(struct wl_client *client, struct wl_resource *resource) { - wlr_log(L_DEBUG, "TODO: toplevel set maximized"); + struct wlr_xdg_surface_v6 *surface = wl_resource_get_user_data(resource); + surface->toplevel_state->next.maximized = true; } -static void xdg_toplevel_unset_maximized(struct wl_client *client, struct wl_resource *resource) { - wlr_log(L_DEBUG, "TODO: toplevel unset maximized"); +static void xdg_toplevel_protocol_unset_maximized(struct wl_client *client, + struct wl_resource *resource) { + struct wlr_xdg_surface_v6 *surface = wl_resource_get_user_data(resource); + surface->toplevel_state->next.maximized = false; } -static void xdg_toplevel_set_fullscreen(struct wl_client *client, struct wl_resource *resource, struct wl_resource *output_resource) { - wlr_log(L_DEBUG, "TODO: toplevel set fullscreen"); +static void xdg_toplevel_protocol_set_fullscreen(struct wl_client *client, + struct wl_resource *resource, struct wl_resource *output_resource) { + struct wlr_xdg_surface_v6 *surface = wl_resource_get_user_data(resource); + surface->toplevel_state->next.fullscreen = true; } -static void xdg_toplevel_unset_fullscreen(struct wl_client *client, struct wl_resource *resource) { - wlr_log(L_DEBUG, "TODO: toplevel unset fullscreen"); +static void xdg_toplevel_protocol_unset_fullscreen(struct wl_client *client, + struct wl_resource *resource) { + struct wlr_xdg_surface_v6 *surface = wl_resource_get_user_data(resource); + surface->toplevel_state->next.fullscreen = false; } -static void xdg_toplevel_set_minimized(struct wl_client *client, struct wl_resource *resource) { - wlr_log(L_DEBUG, "TODO: toplevel set minimized"); +static void xdg_toplevel_protocol_set_minimized(struct wl_client *client, + struct wl_resource *resource) { + struct wlr_xdg_surface_v6 *surface = wl_resource_get_user_data(resource); + wl_signal_emit(&surface->events.request_minimize, surface); } -static const struct zxdg_toplevel_v6_interface zxdg_toplevel_v6_implementation = { +static const struct zxdg_toplevel_v6_interface zxdg_toplevel_v6_implementation = +{ .destroy = resource_destroy, - .set_parent = xdg_toplevel_set_parent, - .set_title = xdg_toplevel_set_title, - .set_app_id = xdg_toplevel_set_app_id, - .show_window_menu = xdg_toplevel_show_window_menu, - .move = xdg_toplevel_move, - .resize = xdg_toplevel_resize, - .set_max_size = xdg_toplevel_set_max_size, - .set_min_size = xdg_toplevel_set_min_size, - .set_maximized = xdg_toplevel_set_maximized, - .unset_maximized = xdg_toplevel_unset_maximized, - .set_fullscreen = xdg_toplevel_set_fullscreen, - .unset_fullscreen = xdg_toplevel_unset_fullscreen, - .set_minimized = xdg_toplevel_set_minimized + .set_parent = xdg_toplevel_protocol_set_parent, + .set_title = xdg_toplevel_protocol_set_title, + .set_app_id = xdg_toplevel_protocol_set_app_id, + .show_window_menu = xdg_toplevel_protocol_show_window_menu, + .move = xdg_toplevel_protocol_move, + .resize = xdg_toplevel_protocol_resize, + .set_max_size = xdg_toplevel_protocol_set_max_size, + .set_min_size = xdg_toplevel_protocol_set_min_size, + .set_maximized = xdg_toplevel_protocol_set_maximized, + .unset_maximized = xdg_toplevel_protocol_unset_maximized, + .set_fullscreen = xdg_toplevel_protocol_set_fullscreen, + .unset_fullscreen = xdg_toplevel_protocol_unset_fullscreen, + .set_minimized = xdg_toplevel_protocol_set_minimized }; -static void xdg_surface_destroy(struct wl_resource *resource) { - struct wlr_xdg_surface_v6 *surface = wl_resource_get_user_data(resource); +static void xdg_surface_destroy(struct wlr_xdg_surface_v6 *surface) { + wl_signal_emit(&surface->events.destroy, surface); + wl_resource_set_user_data(surface->resource, NULL); wl_list_remove(&surface->link); + wl_list_remove(&surface->surface_destroy_listener.link); + wl_list_remove(&surface->surface_commit_listener.link); + free(surface->geometry); + free(surface->next_geometry); + free(surface->title); + free(surface->app_id); free(surface); } +static void xdg_surface_resource_destroy(struct wl_resource *resource) { + struct wlr_xdg_surface_v6 *surface = wl_resource_get_user_data(resource); + if (surface != NULL) { + xdg_surface_destroy(surface); + } +} + static void xdg_surface_get_toplevel(struct wl_client *client, struct wl_resource *resource, uint32_t id) { - // TODO: Flesh out + struct wlr_xdg_surface_v6 *surface = wl_resource_get_user_data(resource); + + if (wlr_surface_set_role(surface->surface, wlr_desktop_xdg_toplevel_role, + resource, ZXDG_SHELL_V6_ERROR_ROLE)) { + return; + } + + surface->toplevel_state = calloc(1, sizeof(struct wlr_xdg_toplevel_v6)); + if (surface->toplevel_state == NULL) { + wl_client_post_no_memory(client); + return; + } + + surface->role = WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL; + surface->toplevel_state->base = surface; + struct wl_resource *toplevel_resource = wl_resource_create(client, &zxdg_toplevel_v6_interface, wl_resource_get_version(resource), id); + + surface->toplevel_state->resource = toplevel_resource; + wl_resource_set_implementation(toplevel_resource, - &zxdg_toplevel_v6_implementation, NULL, NULL); - struct wl_display *display = wl_client_get_display(client); - zxdg_surface_v6_send_configure(resource, wl_display_next_serial(display)); + &zxdg_toplevel_v6_implementation, surface, NULL); } static void xdg_surface_get_popup(struct wl_client *client, @@ -114,15 +269,80 @@ static void xdg_surface_get_popup(struct wl_client *client, wlr_log(L_DEBUG, "TODO xdg surface get popup"); } +static void wlr_xdg_toplevel_v6_ack_configure( + struct wlr_xdg_surface_v6 *surface, + struct wlr_xdg_surface_v6_configure *configure) { + assert(surface->role == WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL); + surface->toplevel_state->next = configure->state; + surface->toplevel_state->pending.width = 0; + surface->toplevel_state->pending.height = 0; +} + static void xdg_surface_ack_configure(struct wl_client *client, struct wl_resource *resource, uint32_t serial) { - wlr_log(L_DEBUG, "TODO xdg surface ack configure"); + struct wlr_xdg_surface_v6 *surface = wl_resource_get_user_data(resource); + + if (surface->role == WLR_XDG_SURFACE_V6_ROLE_NONE) { + wl_resource_post_error(surface->resource, + ZXDG_SURFACE_V6_ERROR_NOT_CONSTRUCTED, + "xdg_surface must have a role"); + return; + } + + bool found = false; + struct wlr_xdg_surface_v6_configure *configure, *tmp; + wl_list_for_each_safe(configure, tmp, &surface->configure_list, link) { + if (configure->serial < serial) { + wl_list_remove(&configure->link); + free(configure); + } else if (configure->serial == serial) { + wl_list_remove(&configure->link); + found = true; + break; + } else { + break; + } + } + if (!found) { + wl_resource_post_error(surface->client->resource, + ZXDG_SHELL_V6_ERROR_INVALID_SURFACE_STATE, + "wrong configure serial: %u", serial); + return; + } + + // TODO handle popups + if (surface->role == WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL) { + wlr_xdg_toplevel_v6_ack_configure(surface, configure); + } + + if (!surface->configured) { + surface->configured = true; + wl_signal_emit(&surface->client->shell->events.new_surface, surface); + } + + wl_signal_emit(&surface->events.ack_configure, surface); + + free(configure); } - + static void xdg_surface_set_window_geometry(struct wl_client *client, struct wl_resource *resource, int32_t x, int32_t y, int32_t width, int32_t height) { - wlr_log(L_DEBUG, "TODO xdg surface set window geometry"); + struct wlr_xdg_surface_v6 *surface = wl_resource_get_user_data(resource); + + if (surface->role == WLR_XDG_SURFACE_V6_ROLE_NONE) { + wl_resource_post_error(surface->resource, + ZXDG_SURFACE_V6_ERROR_NOT_CONSTRUCTED, + "xdg_surface must have a role"); + return; + } + + surface->has_next_geometry = true; + surface->next_geometry->height = height; + surface->next_geometry->width = width; + surface->next_geometry->x = x; + surface->next_geometry->y = y; + } static const struct zxdg_surface_v6_interface zxdg_surface_v6_implementation = { @@ -138,26 +358,270 @@ static void xdg_shell_create_positioner(struct wl_client *client, wlr_log(L_DEBUG, "TODO: xdg shell create positioner"); } -static void xdg_shell_get_xdg_surface(struct wl_client *client, - struct wl_resource *_xdg_shell, uint32_t id, - struct wl_resource *_surface) { - struct wlr_xdg_shell_v6 *xdg_shell = wl_resource_get_user_data(_xdg_shell); +static bool wlr_xdg_surface_v6_toplevel_state_compare( + struct wlr_xdg_toplevel_v6 *state) { + // is pending state different from current state? + if (state->pending.activated != state->current.activated) { + return false; + } + if (state->pending.fullscreen != state->current.fullscreen) { + return false; + } + if (state->pending.maximized != state->current.maximized) { + return false; + } + if (state->pending.resizing != state->current.resizing) { + return false; + } + + if ((uint32_t)state->base->geometry->width == state->pending.width && + (uint32_t)state->base->geometry->height == state->pending.height) { + return true; + } + + if (state->pending.width == 0 && state->pending.height == 0) { + return true; + } + + return false; +} + +static void wlr_xdg_toplevel_v6_send_configure( + struct wlr_xdg_surface_v6 *surface, + struct wlr_xdg_surface_v6_configure *configure) { + assert(surface->role == WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL); + uint32_t *s; + struct wl_array states; + + configure->state = surface->toplevel_state->pending; + + wl_array_init(&states); + if (surface->toplevel_state->pending.maximized) { + s = wl_array_add(&states, sizeof(uint32_t)); + *s = ZXDG_TOPLEVEL_V6_STATE_MAXIMIZED; + } + if (surface->toplevel_state->pending.fullscreen) { + s = wl_array_add(&states, sizeof(uint32_t)); + *s = ZXDG_TOPLEVEL_V6_STATE_FULLSCREEN; + } + if (surface->toplevel_state->pending.resizing) { + s = wl_array_add(&states, sizeof(uint32_t)); + *s = ZXDG_TOPLEVEL_V6_STATE_RESIZING; + } + if (surface->toplevel_state->pending.activated) { + s = wl_array_add(&states, sizeof(uint32_t)); + *s = ZXDG_TOPLEVEL_V6_STATE_ACTIVATED; + } + + uint32_t width = surface->toplevel_state->pending.width; + uint32_t height = surface->toplevel_state->pending.height; + + if (width == 0 || height == 0) { + width = surface->geometry->width; + height = surface->geometry->height; + } + + zxdg_toplevel_v6_send_configure(surface->toplevel_state->resource, width, + height, &states); + + wl_array_release(&states); +} + +static void wlr_xdg_surface_send_configure(void *user_data) { + struct wlr_xdg_surface_v6 *surface = user_data; + struct wl_display *display = wl_client_get_display(surface->client->client); + + // TODO handle popups + assert(surface->role == WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL); + + surface->configure_idle = NULL; + + struct wlr_xdg_surface_v6_configure *configure = + calloc(1, sizeof(struct wlr_xdg_surface_v6_configure)); + if (configure == NULL) { + wl_client_post_no_memory(surface->client->client); + return; + } + + wl_list_insert(surface->configure_list.prev, &configure->link); + configure->serial = wl_display_next_serial(display); + + wlr_xdg_toplevel_v6_send_configure(surface, configure); + + zxdg_surface_v6_send_configure(surface->resource, configure->serial); +} + +static void wlr_xdg_surface_v6_schedule_configure( + struct wlr_xdg_surface_v6 *surface, bool force) { + // TODO handle popups + assert(surface->role == WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL); + + struct wl_display *display = wl_client_get_display(surface->client->client); + struct wl_event_loop *loop = wl_display_get_event_loop(display); + + bool pending_same = !force && + wlr_xdg_surface_v6_toplevel_state_compare(surface->toplevel_state); + + if (surface->configure_idle != NULL) { + if (!pending_same) { + // configure request already scheduled + return; + } + + // configure request not necessary anymore + wl_event_source_remove(surface->configure_idle); + surface->configure_idle = NULL; + } else { + if (pending_same) { + // configure request not necessary + return; + } + + surface->configure_idle = + wl_event_loop_add_idle( + loop, + wlr_xdg_surface_send_configure, + surface); + } +} + +static void handle_wlr_surface_destroyed(struct wl_listener *listener, + void *data) { + struct wlr_xdg_surface_v6 *xdg_surface = + wl_container_of(listener, xdg_surface, surface_destroy_listener); + xdg_surface_destroy(xdg_surface); +} + +static void wlr_xdg_surface_v6_toplevel_committed( + struct wlr_xdg_surface_v6 *surface) { + assert(surface->role == WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL); + + if (!surface->surface->current.buffer && !surface->toplevel_state->added) { + // on the first commit, send a configure request to tell the client it + // is added + wlr_xdg_surface_v6_schedule_configure(surface, true); + surface->toplevel_state->added = true; + return; + } + + if (!surface->surface->current.buffer) { + return; + } + + surface->toplevel_state->current = surface->toplevel_state->next; +} + +static void handle_wlr_surface_committed(struct wl_listener *listener, + void *data) { + struct wlr_xdg_surface_v6 *surface = + wl_container_of(listener, surface, surface_commit_listener); + + if (surface->surface->current.buffer && !surface->configured) { + wl_resource_post_error(surface->resource, + ZXDG_SURFACE_V6_ERROR_UNCONFIGURED_BUFFER, + "xdg_surface has never been configured"); + return; + } + + if (surface->has_next_geometry) { + surface->has_next_geometry = false; + surface->geometry->x = surface->next_geometry->x; + surface->geometry->y = surface->next_geometry->y; + surface->geometry->width = surface->next_geometry->width; + surface->geometry->height = surface->next_geometry->height; + } + + switch (surface->role) { + case WLR_XDG_SURFACE_V6_ROLE_NONE: + wl_resource_post_error(surface->resource, + ZXDG_SURFACE_V6_ERROR_NOT_CONSTRUCTED, + "xdg_surface must have a role"); + break; + case WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL: + wlr_xdg_surface_v6_toplevel_committed(surface); + break; + case WLR_XDG_SURFACE_V6_ROLE_POPUP: + wlr_log(L_DEBUG, "TODO: popup surface committed"); + break; + } + + wl_signal_emit(&surface->events.commit, surface); +} + +static void xdg_shell_get_xdg_surface(struct wl_client *wl_client, + struct wl_resource *client_resource, uint32_t id, + struct wl_resource *surface_resource) { + struct wlr_xdg_client_v6 *client = + wl_resource_get_user_data(client_resource); + struct wlr_xdg_surface_v6 *surface; if (!(surface = calloc(1, sizeof(struct wlr_xdg_surface_v6)))) { + wl_client_post_no_memory(wl_client); + return; + } + + if (!(surface->geometry = calloc(1, sizeof(struct wlr_box)))) { + free(surface); + wl_client_post_no_memory(wl_client); return; } - surface->surface = _surface; - surface->resource = wl_resource_create(client, - &zxdg_surface_v6_interface, wl_resource_get_version(_xdg_shell), id); + + if (!(surface->next_geometry = calloc(1, sizeof(struct wlr_box)))) { + free(surface->geometry); + free(surface); + wl_client_post_no_memory(wl_client); + return; + } + + surface->client = client; + surface->role = WLR_XDG_SURFACE_V6_ROLE_NONE; + surface->surface = wl_resource_get_user_data(surface_resource); + surface->resource = wl_resource_create(wl_client, + &zxdg_surface_v6_interface, wl_resource_get_version(client_resource), + id); + + if (surface->surface->current.buffer != NULL) { + wl_resource_post_error(surface->resource, + ZXDG_SURFACE_V6_ERROR_UNCONFIGURED_BUFFER, + "xdg_surface must not have a buffer at creation"); + return; + } + + wl_list_init(&surface->configure_list); + + wl_signal_init(&surface->events.request_minimize); + wl_signal_init(&surface->events.request_move); + wl_signal_init(&surface->events.request_resize); + wl_signal_init(&surface->events.request_show_window_menu); + wl_signal_init(&surface->events.commit); + wl_signal_init(&surface->events.destroy); + wl_signal_init(&surface->events.ack_configure); + wl_signal_init(&surface->events.ping_timeout); + + wl_signal_add(&surface->surface->signals.destroy, + &surface->surface_destroy_listener); + surface->surface_destroy_listener.notify = handle_wlr_surface_destroyed; + + wl_signal_add(&surface->surface->signals.commit, + &surface->surface_commit_listener); + surface->surface_commit_listener.notify = handle_wlr_surface_committed; + wlr_log(L_DEBUG, "new xdg_surface %p (res %p)", surface, surface->resource); wl_resource_set_implementation(surface->resource, - &zxdg_surface_v6_implementation, surface, xdg_surface_destroy); - wl_list_insert(&xdg_shell->surfaces, &surface->link); + &zxdg_surface_v6_implementation, surface, xdg_surface_resource_destroy); + wl_list_insert(&client->surfaces, &surface->link); } -static void xdg_shell_pong(struct wl_client *client, +static void xdg_shell_pong(struct wl_client *wl_client, struct wl_resource *resource, uint32_t serial) { - wlr_log(L_DEBUG, "TODO xdg shell pong"); + struct wlr_xdg_client_v6 *client = wl_resource_get_user_data(resource); + + if (client->ping_serial != serial) { + return; + } + + wl_event_source_timer_update(client->ping_timer, 0); + client->ping_serial = 0; } static struct zxdg_shell_v6_interface xdg_shell_impl = { @@ -166,8 +630,33 @@ static struct zxdg_shell_v6_interface xdg_shell_impl = { .pong = xdg_shell_pong, }; -static void xdg_shell_destroy(struct wl_resource *resource) { - wl_list_remove(wl_resource_get_link(resource)); +static void wlr_xdg_client_v6_destroy(struct wl_resource *resource) { + struct wlr_xdg_client_v6 *client = wl_resource_get_user_data(resource); + + struct wlr_xdg_surface_v6 *surface, *tmp = NULL; + wl_list_for_each_safe(surface, tmp, &client->surfaces, link) { + wl_list_remove(&surface->link); + wl_list_init(&surface->link); + } + + if (client->ping_timer != NULL) { + wl_event_source_remove(client->ping_timer); + } + + wl_list_remove(&client->link); + free(client); +} + +static int wlr_xdg_client_v6_ping_timeout(void *user_data) { + struct wlr_xdg_client_v6 *client = user_data; + + struct wlr_xdg_surface_v6 *surface; + wl_list_for_each(surface, &client->surfaces, link) { + wl_signal_emit(&surface->events.ping_timeout, surface); + } + + client->ping_serial = 0; + return 1; } static void xdg_shell_bind(struct wl_client *wl_client, void *_xdg_shell, @@ -175,14 +664,36 @@ static void xdg_shell_bind(struct wl_client *wl_client, void *_xdg_shell, struct wlr_xdg_shell_v6 *xdg_shell = _xdg_shell; assert(wl_client && xdg_shell); if (version > 1) { - wlr_log(L_ERROR, "Client requested unsupported xdg_shell_v6 version, disconnecting"); + wlr_log(L_ERROR, + "Client requested unsupported xdg_shell_v6 version, disconnecting"); wl_client_destroy(wl_client); return; } - struct wl_resource *wl_resource = wl_resource_create( - wl_client, &zxdg_shell_v6_interface, version, id); - wl_resource_set_implementation(wl_resource, &xdg_shell_impl, xdg_shell, xdg_shell_destroy); - wl_list_insert(&xdg_shell->wl_resources, wl_resource_get_link(wl_resource)); + struct wlr_xdg_client_v6 *client = + calloc(1, sizeof(struct wlr_xdg_client_v6)); + if (client == NULL) { + wl_client_post_no_memory(wl_client); + return; + } + + wl_list_init(&client->surfaces); + + client->resource = + wl_resource_create(wl_client, &zxdg_shell_v6_interface, version, id); + client->client = wl_client; + client->shell = xdg_shell; + + wl_resource_set_implementation(client->resource, &xdg_shell_impl, client, + wlr_xdg_client_v6_destroy); + wl_list_insert(&xdg_shell->clients, &client->link); + + struct wl_display *display = wl_client_get_display(client->client); + struct wl_event_loop *loop = wl_display_get_event_loop(display); + client->ping_timer = wl_event_loop_add_timer(loop, + wlr_xdg_client_v6_ping_timeout, client); + if (client->ping_timer == NULL) { + wl_client_post_no_memory(client->client); + } } struct wlr_xdg_shell_v6 *wlr_xdg_shell_v6_create(struct wl_display *display) { @@ -191,6 +702,11 @@ struct wlr_xdg_shell_v6 *wlr_xdg_shell_v6_create(struct wl_display *display) { if (!xdg_shell) { return NULL; } + + xdg_shell->ping_timeout = 10000; + + wl_list_init(&xdg_shell->clients); + struct wl_global *wl_global = wl_global_create(display, &zxdg_shell_v6_interface, 1, xdg_shell, xdg_shell_bind); if (!wl_global) { @@ -198,8 +714,9 @@ struct wlr_xdg_shell_v6 *wlr_xdg_shell_v6_create(struct wl_display *display) { return NULL; } xdg_shell->wl_global = wl_global; - wl_list_init(&xdg_shell->wl_resources); - wl_list_init(&xdg_shell->surfaces); + + wl_signal_init(&xdg_shell->events.new_surface); + return xdg_shell; } @@ -207,13 +724,62 @@ void wlr_xdg_shell_v6_destroy(struct wlr_xdg_shell_v6 *xdg_shell) { if (!xdg_shell) { return; } - struct wl_resource *resource = NULL, *temp = NULL; - wl_resource_for_each_safe(resource, temp, &xdg_shell->wl_resources) { - struct wl_list *link = wl_resource_get_link(resource); - wl_list_remove(link); - } - // TODO: destroy surfaces // TODO: this segfault (wl_display->registry_resource_list is not init) // wl_global_destroy(xdg_shell->wl_global); free(xdg_shell); } + +void wlr_xdg_surface_v6_ping(struct wlr_xdg_surface_v6 *surface) { + if (surface->client->ping_serial != 0) { + // already pinged + return; + } + + surface->client->ping_serial = + wl_display_next_serial(wl_client_get_display(surface->client->client)); + wl_event_source_timer_update(surface->client->ping_timer, + surface->client->shell->ping_timeout); + zxdg_shell_v6_send_ping(surface->client->resource, + surface->client->ping_serial); +} + +void wlr_xdg_toplevel_v6_set_size(struct wlr_xdg_surface_v6 *surface, + uint32_t width, uint32_t height) { + assert(surface->role == WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL); + surface->toplevel_state->pending.width = width; + surface->toplevel_state->pending.height = height; + + wlr_xdg_surface_v6_schedule_configure(surface, false); +} + +void wlr_xdg_toplevel_v6_set_activated(struct wlr_xdg_surface_v6 *surface, + bool activated) { + assert(surface->role == WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL); + surface->toplevel_state->pending.activated = activated; + + wlr_xdg_surface_v6_schedule_configure(surface, false); +} + +void wlr_xdg_toplevel_v6_set_maximized(struct wlr_xdg_surface_v6 *surface, + bool maximized) { + assert(surface->role == WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL); + surface->toplevel_state->pending.maximized = maximized; + + wlr_xdg_surface_v6_schedule_configure(surface, false); +} + +void wlr_xdg_toplevel_v6_set_fullscreen(struct wlr_xdg_surface_v6 *surface, + bool fullscreen) { + assert(surface->role == WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL); + surface->toplevel_state->pending.fullscreen = fullscreen; + + wlr_xdg_surface_v6_schedule_configure(surface, false); +} + +void wlr_xdg_toplevel_v6_set_resizing(struct wlr_xdg_surface_v6 *surface, + bool resizing) { + assert(surface->role == WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL); + surface->toplevel_state->pending.fullscreen = resizing; + + wlr_xdg_surface_v6_schedule_configure(surface, false); +} |