aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md1
-rw-r--r--backend/meson.build6
-rw-r--r--backend/session/logind.c10
-rw-r--r--backend/session/session.c2
-rw-r--r--backend/wayland/output.c2
-rw-r--r--dist/archlinux/PKGBUILD48
-rw-r--r--examples/compositor.c582
-rw-r--r--examples/output-layout.c3
-rw-r--r--examples/rotation.c3
-rw-r--r--examples/shared.c3
-rw-r--r--examples/shared.h2
-rw-r--r--include/backend/drm-properties.h4
-rw-r--r--include/backend/drm-util.h4
-rw-r--r--include/backend/drm.h4
-rw-r--r--include/backend/libinput.h4
-rw-r--r--include/backend/multi.h4
-rw-r--r--include/backend/session/direct-ipc.h4
-rw-r--r--include/backend/wayland.h4
-rw-r--r--include/render/gles2.h5
-rw-r--r--include/wlr/backend.h4
-rw-r--r--include/wlr/backend/interface.h4
-rw-r--r--include/wlr/backend/multi.h4
-rw-r--r--include/wlr/backend/session.h4
-rw-r--r--include/wlr/backend/session/interface.h4
-rw-r--r--include/wlr/interfaces/wlr_data_source.h5
-rw-r--r--include/wlr/interfaces/wlr_input_device.h5
-rw-r--r--include/wlr/interfaces/wlr_keyboard.h5
-rw-r--r--include/wlr/interfaces/wlr_output.h5
-rw-r--r--include/wlr/interfaces/wlr_pointer.h5
-rw-r--r--include/wlr/interfaces/wlr_tablet_pad.h5
-rw-r--r--include/wlr/interfaces/wlr_tablet_tool.h5
-rw-r--r--include/wlr/interfaces/wlr_touch.h5
-rw-r--r--include/wlr/render.h5
-rw-r--r--include/wlr/render/gles2.h5
-rw-r--r--include/wlr/render/interface.h5
-rw-r--r--include/wlr/render/matrix.h4
-rw-r--r--include/wlr/types/wlr_box.h5
-rw-r--r--include/wlr/types/wlr_compositor.h6
-rw-r--r--include/wlr/types/wlr_cursor.h7
-rw-r--r--include/wlr/types/wlr_data_device_manager.h4
-rw-r--r--include/wlr/types/wlr_data_source.h4
-rw-r--r--include/wlr/types/wlr_gamma_control.h5
-rw-r--r--include/wlr/types/wlr_input_device.h4
-rw-r--r--include/wlr/types/wlr_keyboard.h5
-rw-r--r--include/wlr/types/wlr_output.h5
-rw-r--r--include/wlr/types/wlr_output_layout.h5
-rw-r--r--include/wlr/types/wlr_pointer.h5
-rw-r--r--include/wlr/types/wlr_region.h4
-rw-r--r--include/wlr/types/wlr_seat.h105
-rw-r--r--include/wlr/types/wlr_surface.h15
-rw-r--r--include/wlr/types/wlr_tablet_pad.h5
-rw-r--r--include/wlr/types/wlr_tablet_tool.h5
-rw-r--r--include/wlr/types/wlr_touch.h5
-rw-r--r--include/wlr/types/wlr_wl_shell.h5
-rw-r--r--include/wlr/types/wlr_xdg_shell_v6.h163
-rw-r--r--include/wlr/util/list.h4
-rw-r--r--include/wlr/util/log.h5
-rw-r--r--include/wlr/xcursor.h6
-rw-r--r--include/wlr/xwayland.h5
-rw-r--r--meson.build16
-rw-r--r--meson_options.txt1
-rw-r--r--render/egl.c6
-rw-r--r--types/wlr_seat.c336
-rw-r--r--types/wlr_surface.c23
-rw-r--r--types/wlr_xdg_shell_v6.c724
65 files changed, 2010 insertions, 252 deletions
diff --git a/README.md b/README.md
index 6ccef6bc..23aceab0 100644
--- a/README.md
+++ b/README.md
@@ -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);
+}