diff --git a/.gitignore b/.gitignore index f635e54fe..d73983bfb 100644 --- a/.gitignore +++ b/.gitignore @@ -1,9 +1 @@ -.clang_complete -*.o -*.a -bin/ -test/ -build/ -build-*/ -wayland-*-protocol.* -wlr-example.ini +/subprojects/ diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 63e279b53..b67855cb8 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -13,7 +13,7 @@ If you already have your own merge request habits, feel free to use them. If you don't, however, allow me to make a suggestion: feature branches pulled from upstream. Try this: -1. Fork wlroots +1. Fork wlroots (make the fork public to allow the CI to run) 2. `git clone git@gitlab.freedesktop.org:/wlroots.git && cd wlroots` 3. `git remote add upstream https://gitlab.freedesktop.org/wlroots/wlroots.git` @@ -167,7 +167,6 @@ if (condition1 && condition2 && ... Try to break the line in the place which you think is the most appropriate. - ### Line Length Try to keep your lines under 80 columns, but you can go up to 100 if it @@ -190,16 +189,18 @@ Functions that are responsible for constructing objects should take one of the two following forms: * `init`: for functions which accept a pointer to a pre-allocated object (e.g. -a member of a struct) and initialize it. +a member of a struct) and initialize it. Such functions must call `memset()` +to zero out the memory before initializing it to avoid leaving unset fields. * `create`: for functions which allocate the memory for an object, initialize -it, and return a pointer. +it, and return a pointer. Such functions should allocate the memory with +`calloc()` to avoid leaving unset fields. Likewise, functions that are responsible for destructing objects should take one of the two following forms: * `finish`: for functions which accept a pointer to an object and deinitialize -it. Such functions should always be able to accept an already deinitialized -object. +it. If a finished object isn't destroyed but kept for future use, it must be +reinitialized to be used again. * `destroy`: for functions which accept a pointer to an object, deinitialize it, and free the memory. Such functions should always be able to accept a NULL pointer. @@ -215,6 +216,19 @@ Try to keep the use of macros to a minimum, especially if a function can do the job. If you do need to use them, try to keep them close to where they're being used and `#undef` them after. +### Documentation + +* Documentation comments for declarations start with `/**` and end with `*/`. +* Cross-reference other declarations by ending function names with `()`, and + writing `struct`, `union`, `enum` or `typedef` before types. +* Document fields which can be NULL with a `// may be NULL` comment, optionally + with more details describing when this can happen. +* Document the bits of a bitfield with a `// enum bar` comment. +* Document the `data` argument of a `struct wl_signal` with a `// struct foo` + comment. +* Document the contents and container of a `struct wl_list` with a + `// content.link` and `// container.list` comment. + ### Example ```c diff --git a/README.md b/README.md index 418aab94b..7fbd691a0 100644 --- a/README.md +++ b/README.md @@ -45,7 +45,7 @@ Install dependencies: * EGL and GLESv2 (optional, for the GLES2 renderer) * Vulkan loader, headers and glslang (optional, for the Vulkan renderer) * libdrm -* GBM +* GBM (optional, for the GBM allocator) * libinput (optional, for the libinput backend) * xkbcommon * udev diff --git a/backend/backend.c b/backend/backend.c index bfb43ba07..4c886af67 100644 --- a/backend/backend.c +++ b/backend/backend.c @@ -17,7 +17,7 @@ #include "backend/backend.h" #include "backend/multi.h" #include "render/allocator/allocator.h" -#include "util/signal.h" +#include "util/env.h" #if WLR_HAS_DRM_BACKEND #include @@ -36,7 +36,7 @@ void wlr_backend_init(struct wlr_backend *backend, const struct wlr_backend_impl *impl) { - assert(backend); + memset(backend, 0, sizeof(*backend)); backend->impl = impl; wl_signal_init(&backend->events.destroy); wl_signal_init(&backend->events.new_input); @@ -44,7 +44,7 @@ void wlr_backend_init(struct wlr_backend *backend, } void wlr_backend_finish(struct wlr_backend *backend) { - wlr_signal_emit_safe(&backend->events.destroy, backend); + wl_signal_emit_mutable(&backend->events.destroy, backend); } bool wlr_backend_start(struct wlr_backend *backend) { @@ -365,8 +365,7 @@ struct wlr_backend *wlr_backend_autocreate(struct wl_display *display) { } wlr_multi_backend_add(backend, libinput); #else - const char *no_devs = getenv("WLR_LIBINPUT_NO_DEVICES"); - if (no_devs && strcmp(no_devs, "1") == 0) { + if (env_parse_bool("WLR_LIBINPUT_NO_DEVICES")) { wlr_log(WLR_INFO, "WLR_LIBINPUT_NO_DEVICES is set, " "starting without libinput backend"); } else { diff --git a/backend/drm/atomic.c b/backend/drm/atomic.c index 7c8ebf42d..eb300382b 100644 --- a/backend/drm/atomic.c +++ b/backend/drm/atomic.c @@ -1,4 +1,6 @@ +#define _POSIX_C_SOURCE 200809L #include +#include #include #include #include @@ -6,6 +8,41 @@ #include "backend/drm/iface.h" #include "backend/drm/util.h" +static char *atomic_commit_flags_str(uint32_t flags) { + const char *const l[] = { + (flags & DRM_MODE_PAGE_FLIP_EVENT) ? "PAGE_FLIP_EVENT" : NULL, + (flags & DRM_MODE_PAGE_FLIP_ASYNC) ? "PAGE_FLIP_ASYNC" : NULL, + (flags & DRM_MODE_ATOMIC_TEST_ONLY) ? "ATOMIC_TEST_ONLY" : NULL, + (flags & DRM_MODE_ATOMIC_NONBLOCK) ? "ATOMIC_NONBLOCK" : NULL, + (flags & DRM_MODE_ATOMIC_ALLOW_MODESET) ? "ATOMIC_ALLOW_MODESET" : NULL, + }; + + char *buf = NULL; + size_t size = 0; + FILE *f = open_memstream(&buf, &size); + if (f == NULL) { + return NULL; + } + + for (size_t i = 0; i < sizeof(l) / sizeof(l[0]); i++) { + if (l[i] == NULL) { + continue; + } + if (ftell(f) > 0) { + fprintf(f, " | "); + } + fprintf(f, "%s", l[i]); + } + + if (ftell(f) == 0) { + fprintf(f, "none"); + } + + fclose(f); + + return buf; +} + struct atomic { drmModeAtomicReq *req; bool failed; @@ -33,9 +70,11 @@ static bool atomic_commit(struct atomic *atom, if (ret != 0) { wlr_drm_conn_log_errno(conn, (flags & DRM_MODE_ATOMIC_TEST_ONLY) ? WLR_DEBUG : WLR_ERROR, - "Atomic %s failed (%s)", - (flags & DRM_MODE_ATOMIC_TEST_ONLY) ? "test" : "commit", - (flags & DRM_MODE_ATOMIC_ALLOW_MODESET) ? "modeset" : "pageflip"); + "Atomic commit failed"); + char *flags_str = atomic_commit_flags_str(flags); + wlr_log(WLR_DEBUG, "(Atomic commit flags: %s)", + flags_str ? flags_str : ""); + free(flags_str); return false; } @@ -217,8 +256,10 @@ static bool atomic_crtc_commit(struct wlr_drm_connector *conn, bool prev_vrr_enabled = output->adaptive_sync_status == WLR_OUTPUT_ADAPTIVE_SYNC_ENABLED; bool vrr_enabled = prev_vrr_enabled; - if ((state->base->committed & WLR_OUTPUT_STATE_ADAPTIVE_SYNC_ENABLED) && - drm_connector_supports_vrr(conn)) { + if ((state->base->committed & WLR_OUTPUT_STATE_ADAPTIVE_SYNC_ENABLED)) { + if (!drm_connector_supports_vrr(conn)) { + return false; + } vrr_enabled = state->base->adaptive_sync_enabled; } @@ -227,7 +268,12 @@ static bool atomic_crtc_commit(struct wlr_drm_connector *conn, } if (modeset) { flags |= DRM_MODE_ATOMIC_ALLOW_MODESET; - } else if (!test_only) { + } else if (!test_only && (state->base->committed & WLR_OUTPUT_STATE_BUFFER)) { + // The wlr_output API requires non-modeset commits with a new buffer to + // wait for the frame event. However compositors often perform + // non-modesets commits without a new buffer without waiting for the + // frame event. In that case we need to make the KMS commit blocking, + // otherwise the kernel will error out with EBUSY. flags |= DRM_MODE_ATOMIC_NONBLOCK; } @@ -238,6 +284,13 @@ static bool atomic_crtc_commit(struct wlr_drm_connector *conn, atomic_add(&atom, conn->id, conn->props.link_status, DRM_MODE_LINK_STATUS_GOOD); } + if (active && conn->props.content_type != 0) { + atomic_add(&atom, conn->id, conn->props.content_type, + DRM_MODE_CONTENT_TYPE_GRAPHICS); + } + if (active && conn->props.max_bpc != 0 && conn->max_bpc > 0) { + atomic_add(&atom, conn->id, conn->props.max_bpc, conn->max_bpc); + } atomic_add(&atom, crtc->id, crtc->props.mode_id, mode_id); atomic_add(&atom, crtc->id, crtc->props.active, active); if (active) { diff --git a/backend/drm/backend.c b/backend/drm/backend.c index 10f324a02..e303bc8f0 100644 --- a/backend/drm/backend.c +++ b/backend/drm/backend.c @@ -1,6 +1,7 @@ #include #include #include +#include #include #include #include @@ -12,7 +13,6 @@ #include #include #include "backend/drm/drm.h" -#include "util/signal.h" struct wlr_drm_backend *get_drm_backend_from_backend( struct wlr_backend *wlr_backend) { @@ -58,6 +58,7 @@ static void backend_destroy(struct wlr_backend *backend) { finish_drm_resources(drm); + udev_hwdb_unref(drm->hwdb); free(drm->name); wlr_session_close_file(drm->session, drm->dev); wl_event_source_remove(drm->drm_event); @@ -172,6 +173,23 @@ static void handle_parent_destroy(struct wl_listener *listener, void *data) { backend_destroy(&drm->backend); } +static struct udev_hwdb *create_udev_hwdb(void) { + struct udev *udev = udev_new(); + if (!udev) { + wlr_log(WLR_ERROR, "udev_new failed"); + return NULL; + } + + struct udev_hwdb *hwdb = udev_hwdb_new(udev); + udev_unref(udev); + if (!hwdb) { + wlr_log(WLR_ERROR, "udev_hwdb_new failed"); + return NULL; + } + + return hwdb; +} + struct wlr_backend *wlr_drm_backend_create(struct wl_display *display, struct wlr_session *session, struct wlr_device *dev, struct wlr_backend *parent) { @@ -226,6 +244,12 @@ struct wlr_backend *wlr_drm_backend_create(struct wl_display *display, drm->session_active.notify = handle_session_active; wl_signal_add(&session->events.active, &drm->session_active); + drm->hwdb = create_udev_hwdb(); + if (!drm->hwdb) { + wlr_log(WLR_INFO, "Failed to load udev_hwdb, " + "falling back to PnP IDs instead of manufacturer names"); + } + if (!check_drm_features(drm)) { goto error_event; } @@ -250,15 +274,17 @@ struct wlr_backend *wlr_drm_backend_create(struct wl_display *display, goto error_mgpu_renderer; } - // Force a linear layout. In case explicit modifiers aren't supported, - // the meaning of implicit modifiers changes from one GPU to the other. - // In case explicit modifiers are supported, we still have no guarantee - // that the buffer producer will support these, so they might fallback - // to implicit modifiers. + // Forbid implicit modifiers, because their meaning changes from one + // GPU to another. for (size_t i = 0; i < texture_formats->len; i++) { const struct wlr_drm_format *fmt = texture_formats->formats[i]; - wlr_drm_format_set_add(&drm->mgpu_formats, fmt->format, - DRM_FORMAT_MOD_LINEAR); + for (size_t j = 0; j < fmt->len; j++) { + uint64_t mod = fmt->modifiers[j]; + if (mod == DRM_FORMAT_MOD_INVALID) { + continue; + } + wlr_drm_format_set_add(&drm->mgpu_formats, fmt->format, mod); + } } } @@ -275,6 +301,7 @@ error_mgpu_renderer: error_resources: finish_drm_resources(drm); error_event: + udev_hwdb_unref(drm->hwdb); wl_list_remove(&drm->session_active.link); wl_event_source_remove(drm->drm_event); error_fd: diff --git a/backend/drm/drm.c b/backend/drm/drm.c index 83279a0d0..7c3a256a6 100644 --- a/backend/drm/drm.c +++ b/backend/drm/drm.c @@ -29,14 +29,18 @@ #include "render/drm_format_set.h" #include "render/swapchain.h" #include "render/wlr_renderer.h" -#include "util/signal.h" +#include "util/env.h" -static const uint32_t SUPPORTED_OUTPUT_STATE = - WLR_OUTPUT_STATE_BACKEND_OPTIONAL | +// Output state which needs a KMS commit to be applied +static const uint32_t COMMIT_OUTPUT_STATE = WLR_OUTPUT_STATE_BUFFER | WLR_OUTPUT_STATE_MODE | WLR_OUTPUT_STATE_ENABLED | - WLR_OUTPUT_STATE_GAMMA_LUT; + WLR_OUTPUT_STATE_GAMMA_LUT | + WLR_OUTPUT_STATE_ADAPTIVE_SYNC_ENABLED; + +static const uint32_t SUPPORTED_OUTPUT_STATE = + WLR_OUTPUT_STATE_BACKEND_OPTIONAL | COMMIT_OUTPUT_STATE; bool check_drm_features(struct wlr_drm_backend *drm) { if (drmGetCap(drm->fd, DRM_CAP_CURSOR_WIDTH, &drm->cursor_width)) { @@ -72,8 +76,7 @@ bool check_drm_features(struct wlr_drm_backend *drm) { return false; } - const char *no_atomic = getenv("WLR_DRM_NO_ATOMIC"); - if (no_atomic && strcmp(no_atomic, "1") == 0) { + if (env_parse_bool("WLR_DRM_NO_ATOMIC")) { wlr_log(WLR_DEBUG, "WLR_DRM_NO_ATOMIC set, forcing legacy DRM interface"); drm->iface = &legacy_iface; @@ -89,8 +92,7 @@ bool check_drm_features(struct wlr_drm_backend *drm) { int ret = drmGetCap(drm->fd, DRM_CAP_TIMESTAMP_MONOTONIC, &cap); drm->clock = (ret == 0 && cap == 1) ? CLOCK_MONOTONIC : CLOCK_REALTIME; - const char *no_modifiers = getenv("WLR_DRM_NO_MODIFIERS"); - if (no_modifiers != NULL && strcmp(no_modifiers, "1") == 0) { + if (env_parse_bool("WLR_DRM_NO_MODIFIERS")) { wlr_log(WLR_DEBUG, "WLR_DRM_NO_MODIFIERS set, disabling modifiers"); } else { ret = drmGetCap(drm->fd, DRM_CAP_ADDFB2_MODIFIERS, &cap); @@ -380,6 +382,7 @@ static bool drm_crtc_page_flip(struct wlr_drm_connector *conn, static void drm_connector_state_init(struct wlr_drm_connector_state *state, struct wlr_drm_connector *conn, const struct wlr_output_state *base) { + memset(state, 0, sizeof(*state)); state->base = base; state->modeset = base->committed & (WLR_OUTPUT_STATE_ENABLED | WLR_OUTPUT_STATE_MODE); @@ -458,37 +461,48 @@ static bool drm_connector_set_pending_fb(struct wlr_drm_connector *conn, static bool drm_connector_alloc_crtc(struct wlr_drm_connector *conn); -static bool drm_connector_test(struct wlr_output *output) { +static bool drm_connector_test(struct wlr_output *output, + const struct wlr_output_state *state) { struct wlr_drm_connector *conn = get_drm_connector_from_output(output); if (!conn->backend->session->active) { return false; } - uint32_t unsupported = output->pending.committed & ~SUPPORTED_OUTPUT_STATE; + uint32_t unsupported = state->committed & ~SUPPORTED_OUTPUT_STATE; if (unsupported != 0) { wlr_log(WLR_DEBUG, "Unsupported output state fields: 0x%"PRIx32, unsupported); return false; } - if ((output->pending.committed & WLR_OUTPUT_STATE_ENABLED) && - output->pending.enabled) { + if ((state->committed & COMMIT_OUTPUT_STATE) == 0) { + // This commit doesn't change the KMS state + return true; + } + + if ((state->committed & WLR_OUTPUT_STATE_ENABLED) && state->enabled) { if (output->current_mode == NULL && - !(output->pending.committed & WLR_OUTPUT_STATE_MODE)) { + !(state->committed & WLR_OUTPUT_STATE_MODE)) { wlr_drm_conn_log(conn, WLR_DEBUG, "Can't enable an output without a mode"); return false; } } + if ((state->committed & WLR_OUTPUT_ADAPTIVE_SYNC_ENABLED) && + state->adaptive_sync_enabled && + !drm_connector_supports_vrr(conn)) { + return false; + } + struct wlr_drm_connector_state pending = {0}; - drm_connector_state_init(&pending, conn, &output->pending); + drm_connector_state_init(&pending, conn, state); if (pending.active) { - if ((output->pending.committed & + if ((state->committed & (WLR_OUTPUT_STATE_ENABLED | WLR_OUTPUT_STATE_MODE)) && - !(output->pending.committed & WLR_OUTPUT_STATE_BUFFER)) { + !(state->committed & WLR_OUTPUT_STATE_BUFFER)) { wlr_drm_conn_log(conn, WLR_DEBUG, "Can't enable an output without a buffer"); return false; @@ -513,7 +527,7 @@ static bool drm_connector_test(struct wlr_output *output) { return true; } - if (output->pending.committed & WLR_OUTPUT_STATE_BUFFER) { + if (state->committed & WLR_OUTPUT_STATE_BUFFER) { if (!drm_connector_set_pending_fb(conn, pending.base)) { return false; } @@ -559,6 +573,11 @@ bool drm_connector_commit_state(struct wlr_drm_connector *conn, return false; } + if ((base->committed & COMMIT_OUTPUT_STATE) == 0) { + // This commit doesn't change the KMS state + return true; + } + struct wlr_drm_connector_state pending = {0}; drm_connector_state_init(&pending, conn, base); @@ -596,14 +615,15 @@ bool drm_connector_commit_state(struct wlr_drm_connector *conn, return true; } -static bool drm_connector_commit(struct wlr_output *output) { +static bool drm_connector_commit(struct wlr_output *output, + const struct wlr_output_state *state) { struct wlr_drm_connector *conn = get_drm_connector_from_output(output); - if (!drm_connector_test(output)) { + if (!drm_connector_test(output, state)) { return false; } - return drm_connector_commit_state(conn, &output->pending); + return drm_connector_commit_state(conn, state); } size_t drm_crtc_get_gamma_lut_size(struct wlr_drm_backend *drm, @@ -692,8 +712,7 @@ static bool drm_connector_set_mode(struct wlr_drm_connector *conn, return true; } - if (conn->status != WLR_DRM_CONN_CONNECTED - && conn->status != WLR_DRM_CONN_NEEDS_MODESET) { + if (conn->status != DRM_MODE_CONNECTED) { wlr_drm_conn_log(conn, WLR_ERROR, "Cannot modeset a disconnected output"); return false; @@ -720,7 +739,6 @@ static bool drm_connector_set_mode(struct wlr_drm_connector *conn, return false; } - conn->status = WLR_DRM_CONN_CONNECTED; wlr_output_update_mode(&conn->output, wlr_mode); wlr_output_update_enabled(&conn->output, true); conn->desired_enabled = true; @@ -892,7 +910,7 @@ static void drm_connector_destroy_output(struct wlr_output *output) { dealloc_crtc(conn); - conn->status = WLR_DRM_CONN_DISCONNECTED; + conn->status = DRM_MODE_DISCONNECTED; conn->desired_enabled = false; conn->possible_crtcs = 0; conn->pending_page_flip_crtc = 0; @@ -1071,9 +1089,7 @@ static void realloc_crtcs(struct wlr_drm_backend *drm) { // Only search CRTCs for user-enabled outputs (that are already // connected or in need of a modeset) - if ((conn->status == WLR_DRM_CONN_CONNECTED || - conn->status == WLR_DRM_CONN_NEEDS_MODESET) && - conn->desired_enabled) { + if (conn->status == DRM_MODE_CONNECTED && conn->desired_enabled) { connector_constraints[i] = conn->possible_crtcs; } else { // Will always fail to match anything @@ -1104,8 +1120,7 @@ static void realloc_crtcs(struct wlr_drm_backend *drm) { */ for (size_t i = 0; i < num_outputs; ++i) { struct wlr_drm_connector *conn = connectors[i]; - if (conn->status == WLR_DRM_CONN_CONNECTED && - conn->desired_enabled && + if (conn->status == DRM_MODE_CONNECTED && conn->output.enabled && connector_match[i] == -1) { wlr_log(WLR_DEBUG, "Could not match a CRTC for previously connected output; " "keeping old configuration"); @@ -1132,7 +1147,6 @@ static void realloc_crtcs(struct wlr_drm_backend *drm) { if (connector_match[i] == -1) { if (prev_enabled) { wlr_drm_conn_log(conn, WLR_DEBUG, "Output has lost its CRTC"); - conn->status = WLR_DRM_CONN_NEEDS_MODESET; wlr_output_update_enabled(&conn->output, false); wlr_output_update_mode(&conn->output, NULL); } @@ -1142,42 +1156,17 @@ static void realloc_crtcs(struct wlr_drm_backend *drm) { conn->crtc = &drm->crtcs[connector_match[i]]; // Only realloc buffers if we have actually been modeset - if (conn->status != WLR_DRM_CONN_CONNECTED) { + if (conn->status != DRM_MODE_CONNECTED || !conn->output.enabled) { continue; } wlr_output_damage_whole(&conn->output); } } -static uint32_t get_possible_crtcs(int fd, const drmModeConnector *conn) { - uint32_t possible_crtcs = 0; - - for (int i = 0; i < conn->count_encoders; ++i) { - drmModeEncoder *enc = drmModeGetEncoder(fd, conn->encoders[i]); - if (!enc) { - continue; - } - - possible_crtcs |= enc->possible_crtcs; - - drmModeFreeEncoder(enc); - } - - return possible_crtcs; -} - static void disconnect_drm_connector(struct wlr_drm_connector *conn); void scan_drm_connectors(struct wlr_drm_backend *drm, struct wlr_device_hotplug_event *event) { - /* - * This GPU is not really a modesetting device. - * It's just being used as a renderer. - */ - if (drm->num_crtcs == 0) { - return; - } - if (event != NULL && event->connector_id != 0) { wlr_log(WLR_INFO, "Scanning DRM connector %"PRIu32" on %s", event->connector_id, drm->name); @@ -1240,12 +1229,17 @@ void scan_drm_connectors(struct wlr_drm_backend *drm, } wlr_conn->backend = drm; - wlr_conn->status = WLR_DRM_CONN_DISCONNECTED; + wlr_conn->status = DRM_MODE_DISCONNECTED; wlr_conn->id = drm_conn->connector_id; + const char *conn_name = + drmModeGetConnectorTypeName(drm_conn->connector_type); + if (conn_name == NULL) { + conn_name = "Unknown"; + } + snprintf(wlr_conn->name, sizeof(wlr_conn->name), - "%s-%"PRIu32, conn_get_name(drm_conn->connector_type), - drm_conn->connector_type_id); + "%s-%"PRIu32, conn_name, drm_conn->connector_type_id); wl_list_insert(drm->outputs.prev, &wlr_conn->link); wlr_log(WLR_INFO, "Found connector '%s'", wlr_conn->name); @@ -1282,7 +1276,7 @@ void scan_drm_connectors(struct wlr_drm_backend *drm, } } - if (wlr_conn->status == WLR_DRM_CONN_DISCONNECTED && + if (wlr_conn->status == DRM_MODE_DISCONNECTED && drm_conn->connection == DRM_MODE_CONNECTED) { wlr_log(WLR_INFO, "'%s' connected", wlr_conn->name); wlr_log(WLR_DEBUG, "Current CRTC: %d", @@ -1310,16 +1304,24 @@ void scan_drm_connectors(struct wlr_drm_backend *drm, wlr_conn->output.non_desktop = non_desktop; } + wlr_conn->max_bpc = 0; + if (wlr_conn->props.max_bpc != 0) { + if (!introspect_drm_prop_range(drm->fd, wlr_conn->props.max_bpc, + NULL, &wlr_conn->max_bpc)) { + wlr_log(WLR_ERROR, "Failed to introspect 'max bpc' property"); + } + } + size_t edid_len = 0; uint8_t *edid = get_drm_prop_blob(drm->fd, wlr_conn->id, wlr_conn->props.edid, &edid_len); - parse_edid(&wlr_conn->output, edid_len, edid); + parse_edid(wlr_conn, edid_len, edid); free(edid); size_t tile_len = 0; uint8_t *tile = get_drm_prop_blob(drm->fd, wlr_conn->id, wlr_conn->props.tile, &tile_len); - parse_tile(&wlr_conn->output, tile_len, tile); + parse_tile(wlr_conn, tile_len, tile); free(tile); char *subconnector = NULL; @@ -1334,9 +1336,13 @@ void scan_drm_connectors(struct wlr_drm_backend *drm, struct wlr_output *output = &wlr_conn->output; char description[128]; - snprintf(description, sizeof(description), "%s %s %s (%s%s%s)", - output->make, output->model, output->serial, output->name, - subconnector ? " via " : "", subconnector ? subconnector : ""); + snprintf(description, sizeof(description), "%s %s%s%s (%s%s%s)", + output->make, output->model, + output->serial ? " " : "", + output->serial ? output->serial : "", + output->name, + subconnector ? " via " : "", + subconnector ? subconnector : ""); wlr_output_set_description(output, description); free(subconnector); @@ -1371,7 +1377,8 @@ void scan_drm_connectors(struct wlr_drm_backend *drm, wl_list_insert(wlr_conn->output.modes.prev, &mode->wlr_mode.link); } - wlr_conn->possible_crtcs = get_possible_crtcs(drm->fd, drm_conn); + wlr_conn->possible_crtcs = + drmModeConnectorGetPossibleCrtcs(drm->fd, drm_conn); if (wlr_conn->possible_crtcs == 0) { wlr_drm_conn_log(wlr_conn, WLR_ERROR, "No CRTC possible"); } @@ -1381,10 +1388,9 @@ void scan_drm_connectors(struct wlr_drm_backend *drm, wlr_output_update_enabled(&wlr_conn->output, wlr_conn->crtc != NULL); wlr_conn->desired_enabled = true; - wlr_conn->status = WLR_DRM_CONN_NEEDS_MODESET; + wlr_conn->status = DRM_MODE_CONNECTED; new_outputs[new_outputs_len++] = wlr_conn; - } else if ((wlr_conn->status == WLR_DRM_CONN_CONNECTED || - wlr_conn->status == WLR_DRM_CONN_NEEDS_MODESET) && + } else if (wlr_conn->status == DRM_MODE_CONNECTED && drm_conn->connection != DRM_MODE_CONNECTED) { wlr_log(WLR_INFO, "'%s' disconnected", wlr_conn->name); disconnect_drm_connector(wlr_conn); @@ -1416,7 +1422,7 @@ void scan_drm_connectors(struct wlr_drm_backend *drm, struct wlr_drm_connector *conn = new_outputs[i]; wlr_drm_conn_log(conn, WLR_INFO, "Requesting modeset"); - wlr_signal_emit_safe(&drm->backend.events.new_output, + wl_signal_emit_mutable(&drm->backend.events.new_output, &conn->output); } } @@ -1474,7 +1480,7 @@ static void handle_page_flip(int fd, unsigned seq, conn->pending_page_flip_crtc = 0; - if (conn->status != WLR_DRM_CONN_CONNECTED || conn->crtc == NULL) { + if (conn->status != DRM_MODE_CONNECTED || conn->crtc == NULL) { wlr_drm_conn_log(conn, WLR_DEBUG, "Ignoring page-flip event for disabled connector"); return; @@ -1537,7 +1543,7 @@ int handle_drm_event(int fd, uint32_t mask, void *data) { } static void disconnect_drm_connector(struct wlr_drm_connector *conn) { - if (conn->status == WLR_DRM_CONN_DISCONNECTED) { + if (conn->status == DRM_MODE_DISCONNECTED) { return; } @@ -1545,7 +1551,7 @@ static void disconnect_drm_connector(struct wlr_drm_connector *conn) { // our wlr_drm_connector. wlr_output_destroy(&conn->output); - assert(conn->status == WLR_DRM_CONN_DISCONNECTED); + assert(conn->status == DRM_MODE_DISCONNECTED); } void destroy_drm_connector(struct wlr_drm_connector *conn) { @@ -1635,7 +1641,7 @@ struct wlr_drm_lease *wlr_drm_create_lease(struct wlr_output **outputs, wl_signal_init(&lease->events.destroy); wlr_log(WLR_DEBUG, "Issuing DRM lease with %d objects", n_objects); - int lease_fd = drmModeCreateLease(drm->fd, objects, n_objects, 0, + int lease_fd = drmModeCreateLease(drm->fd, objects, n_objects, O_CLOEXEC, &lease->lessee_id); if (lease_fd < 0) { free(lease); @@ -1669,7 +1675,7 @@ void wlr_drm_lease_terminate(struct wlr_drm_lease *lease) { void drm_lease_destroy(struct wlr_drm_lease *lease) { struct wlr_drm_backend *drm = lease->backend; - wlr_signal_emit_safe(&lease->events.destroy, NULL); + wl_signal_emit_mutable(&lease->events.destroy, NULL); struct wlr_drm_connector *conn; wl_list_for_each(conn, &drm->outputs, link) { diff --git a/backend/drm/legacy.c b/backend/drm/legacy.c index 84e8a914f..bd8813e83 100644 --- a/backend/drm/legacy.c +++ b/backend/drm/legacy.c @@ -115,8 +115,10 @@ static bool legacy_crtc_commit(struct wlr_drm_connector *conn, } } - if ((state->base->committed & WLR_OUTPUT_STATE_ADAPTIVE_SYNC_ENABLED) && - drm_connector_supports_vrr(conn)) { + if (state->base->committed & WLR_OUTPUT_STATE_ADAPTIVE_SYNC_ENABLED) { + if (!drm_connector_supports_vrr(conn)) { + return false; + } if (drmModeObjectSetProperty(drm->fd, crtc->id, DRM_MODE_OBJECT_CRTC, crtc->props.vrr_enabled, state->base->adaptive_sync_enabled) != 0) { diff --git a/backend/drm/properties.c b/backend/drm/properties.c index c4a97efaa..feb586cb5 100644 --- a/backend/drm/properties.c +++ b/backend/drm/properties.c @@ -1,4 +1,5 @@ #define _POSIX_C_SOURCE 200809L +#include #include #include #include @@ -25,7 +26,9 @@ static const struct prop_info connector_info[] = { { "EDID", INDEX(edid) }, { "PATH", INDEX(path) }, { "TILE", INDEX(tile) }, + { "content type", INDEX(content_type) }, { "link-status", INDEX(link_status) }, + { "max bpc", INDEX(max_bpc) }, { "non-desktop", INDEX(non_desktop) }, { "panel orientation", INDEX(panel_orientation) }, { "subconnector", INDEX(subconnector) }, @@ -181,3 +184,28 @@ char *get_drm_prop_enum(int fd, uint32_t obj, uint32_t prop_id) { return str; } + +bool introspect_drm_prop_range(int fd, uint32_t prop_id, + uint64_t *min, uint64_t *max) { + drmModePropertyRes *prop = drmModeGetProperty(fd, prop_id); + if (!prop) { + return false; + } + + if (drmModeGetPropertyType(prop) != DRM_MODE_PROP_RANGE) { + drmModeFreeProperty(prop); + return false; + } + + assert(prop->count_values == 2); + + if (min != NULL) { + *min = prop->values[0]; + } + if (max != NULL) { + *max = prop->values[1]; + } + + drmModeFreeProperty(prop); + return true; +} diff --git a/backend/drm/renderer.c b/backend/drm/renderer.c index 792de938f..9e1de3d0a 100644 --- a/backend/drm/renderer.c +++ b/backend/drm/renderer.c @@ -48,31 +48,6 @@ void finish_drm_renderer(struct wlr_drm_renderer *renderer) { wlr_renderer_destroy(renderer->wlr_rend); } -bool init_drm_surface(struct wlr_drm_surface *surf, - struct wlr_drm_renderer *renderer, uint32_t width, uint32_t height, - const struct wlr_drm_format *drm_format) { - if (surf->width == width && surf->height == height) { - return true; - } - - surf->renderer = renderer; - surf->width = width; - surf->height = height; - - wlr_swapchain_destroy(surf->swapchain); - surf->swapchain = NULL; - - surf->swapchain = wlr_swapchain_create(renderer->allocator, width, height, - drm_format); - if (surf->swapchain == NULL) { - wlr_log(WLR_ERROR, "Failed to create swapchain"); - memset(surf, 0, sizeof(*surf)); - return false; - } - - return true; -} - static void finish_drm_surface(struct wlr_drm_surface *surf) { if (!surf || !surf->renderer) { return; @@ -83,12 +58,34 @@ static void finish_drm_surface(struct wlr_drm_surface *surf) { memset(surf, 0, sizeof(*surf)); } +bool init_drm_surface(struct wlr_drm_surface *surf, + struct wlr_drm_renderer *renderer, int width, int height, + const struct wlr_drm_format *drm_format) { + if (surf->swapchain != NULL && surf->swapchain->width == width && + surf->swapchain->height == height) { + return true; + } + + finish_drm_surface(surf); + + surf->swapchain = wlr_swapchain_create(renderer->allocator, width, height, + drm_format); + if (surf->swapchain == NULL) { + wlr_log(WLR_ERROR, "Failed to create swapchain"); + return false; + } + + surf->renderer = renderer; + + return true; +} + struct wlr_buffer *drm_surface_blit(struct wlr_drm_surface *surf, struct wlr_buffer *buffer) { struct wlr_renderer *renderer = surf->renderer->wlr_rend; - if (surf->width != (uint32_t)buffer->width || - surf->height != (uint32_t)buffer->height) { + if (surf->swapchain->width != buffer->width || + surf->swapchain->height != buffer->height) { wlr_log(WLR_ERROR, "Surface size doesn't match buffer size"); return NULL; } @@ -106,7 +103,7 @@ struct wlr_buffer *drm_surface_blit(struct wlr_drm_surface *surf, float mat[9]; wlr_matrix_identity(mat); - wlr_matrix_scale(mat, surf->width, surf->height); + wlr_matrix_scale(mat, surf->swapchain->width, surf->swapchain->height); if (!wlr_renderer_begin_with_buffer(renderer, dst)) { wlr_buffer_unlock(dst); diff --git a/backend/drm/util.c b/backend/drm/util.c index 86a4b8eac..17163b797 100644 --- a/backend/drm/util.c +++ b/backend/drm/util.c @@ -1,10 +1,14 @@ +#define _POSIX_C_SOURCE 200809L #include #include #include #include +#include #include +#include #include #include +#include "backend/drm/drm.h" #include "backend/drm/util.h" int32_t calculate_refresh_rate(const drmModeModeInfo *mode) { @@ -26,125 +30,93 @@ int32_t calculate_refresh_rate(const drmModeModeInfo *mode) { return refresh; } -// Constructed from http://edid.tv/manufacturer -static const char *get_manufacturer(uint16_t id) { -#define ID(a, b, c) ((a & 0x1f) << 10) | ((b & 0x1f) << 5) | (c & 0x1f) - switch (id) { - case ID('A', 'A', 'A'): return "Avolites Ltd"; - case ID('A', 'C', 'I'): return "Ancor Communications Inc"; - case ID('A', 'C', 'R'): return "Acer Technologies"; - case ID('A', 'D', 'A'): return "Addi-Data GmbH"; - case ID('A', 'P', 'P'): return "Apple Computer Inc"; - case ID('A', 'S', 'K'): return "Ask A/S"; - case ID('A', 'V', 'T'): return "Avtek (Electronics) Pty Ltd"; - case ID('B', 'N', 'O'): return "Bang & Olufsen"; - case ID('B', 'N', 'Q'): return "BenQ Corporation"; - case ID('C', 'M', 'N'): return "Chimei Innolux Corporation"; - case ID('C', 'M', 'O'): return "Chi Mei Optoelectronics corp."; - case ID('C', 'R', 'O'): return "Extraordinary Technologies PTY Limited"; - case ID('D', 'E', 'L'): return "Dell Inc."; - case ID('D', 'G', 'C'): return "Data General Corporation"; - case ID('D', 'O', 'N'): return "DENON, Ltd."; - case ID('E', 'N', 'C'): return "Eizo Nanao Corporation"; - case ID('E', 'P', 'H'): return "Epiphan Systems Inc."; - case ID('E', 'X', 'P'): return "Data Export Corporation"; - case ID('F', 'N', 'I'): return "Funai Electric Co., Ltd."; - case ID('F', 'U', 'S'): return "Fujitsu Siemens Computers GmbH"; - case ID('G', 'S', 'M'): return "Goldstar Company Ltd"; - case ID('H', 'I', 'Q'): return "Kaohsiung Opto Electronics Americas, Inc."; - case ID('H', 'S', 'D'): return "HannStar Display Corp"; - case ID('H', 'T', 'C'): return "Hitachi Ltd"; - case ID('H', 'W', 'P'): return "Hewlett Packard"; - case ID('I', 'N', 'T'): return "Interphase Corporation"; - case ID('I', 'N', 'X'): return "Communications Supply Corporation (A division of WESCO)"; - case ID('I', 'T', 'E'): return "Integrated Tech Express Inc"; - case ID('I', 'V', 'M'): return "Iiyama North America"; - case ID('L', 'E', 'N'): return "Lenovo Group Limited"; - case ID('M', 'A', 'X'): return "Rogen Tech Distribution Inc"; - case ID('M', 'E', 'G'): return "Abeam Tech Ltd"; - case ID('M', 'E', 'I'): return "Panasonic Industry Company"; - case ID('M', 'T', 'C'): return "Mars-Tech Corporation"; - case ID('M', 'T', 'X'): return "Matrox"; - case ID('N', 'E', 'C'): return "NEC Corporation"; - case ID('N', 'E', 'X'): return "Nexgen Mediatech Inc."; - case ID('O', 'N', 'K'): return "ONKYO Corporation"; - case ID('O', 'R', 'N'): return "ORION ELECTRIC CO., LTD."; - case ID('O', 'T', 'M'): return "Optoma Corporation"; - case ID('O', 'V', 'R'): return "Oculus VR, Inc."; - case ID('P', 'H', 'L'): return "Philips Consumer Electronics Company"; - case ID('P', 'I', 'O'): return "Pioneer Electronic Corporation"; - case ID('P', 'N', 'R'): return "Planar Systems, Inc."; - case ID('Q', 'D', 'S'): return "Quanta Display Inc."; - case ID('R', 'A', 'T'): return "Rent-A-Tech"; - case ID('R', 'E', 'N'): return "Renesas Technology Corp."; - case ID('S', 'A', 'M'): return "Samsung Electric Company"; - case ID('S', 'A', 'N'): return "Sanyo Electric Co., Ltd."; - case ID('S', 'E', 'C'): return "Seiko Epson Corporation"; - case ID('S', 'H', 'P'): return "Sharp Corporation"; - case ID('S', 'I', 'I'): return "Silicon Image, Inc."; - case ID('S', 'N', 'Y'): return "Sony"; - case ID('S', 'T', 'D'): return "STD Computer Inc"; - case ID('S', 'V', 'S'): return "SVSI"; - case ID('S', 'Y', 'N'): return "Synaptics Inc"; - case ID('T', 'C', 'L'): return "Technical Concepts Ltd"; - case ID('T', 'O', 'P'): return "Orion Communications Co., Ltd."; - case ID('T', 'S', 'B'): return "Toshiba America Info Systems Inc"; - case ID('T', 'S', 'T'): return "Transtream Inc"; - case ID('U', 'N', 'K'): return "Unknown"; - case ID('V', 'E', 'S'): return "Vestel Elektronik Sanayi ve Ticaret A. S."; - case ID('V', 'I', 'T'): return "Visitech AS"; - case ID('V', 'I', 'Z'): return "VIZIO, Inc"; - case ID('V', 'L', 'V'): return "Valve"; - case ID('V', 'S', 'C'): return "ViewSonic Corporation"; - case ID('Y', 'M', 'H'): return "Yamaha Corporation"; - default: return "Unknown"; +static const char *get_manufacturer(struct udev_hwdb *hwdb, uint16_t code) { + static char pnp_id[4]; + + // The ASCII 3-letter manufacturer PnP ID is encoded in 5-bit codes + pnp_id[0] = ((code >> 10) & 0x1F) + '@'; + pnp_id[1] = ((code >> 5) & 0x1F) + '@'; + pnp_id[2] = ((code >> 0) & 0x1F) + '@'; + pnp_id[3] = '\0'; + + if (hwdb == NULL) { + return pnp_id; } -#undef ID + + char query[32]; + snprintf(query, sizeof(query), "acpi:%s:", pnp_id); + struct udev_list_entry *acpi_entry = + udev_hwdb_get_properties_list_entry(hwdb, query, 0); + if (acpi_entry == NULL) { + return pnp_id; + } + + struct udev_list_entry *vendor_entry = + udev_list_entry_get_by_name(acpi_entry, "ID_VENDOR_FROM_DATABASE"); + if (vendor_entry == NULL) { + return pnp_id; + } + + return udev_list_entry_get_value(vendor_entry); } /* See https://en.wikipedia.org/wiki/Extended_Display_Identification_Data for layout of EDID data. * We don't parse the EDID properly. We just expect to receive valid data. */ -void parse_edid(struct wlr_output *restrict output, size_t len, const uint8_t *data) { +void parse_edid(struct wlr_drm_connector *conn, size_t len, const uint8_t *data) { + struct wlr_output *output = &conn->output; + + free(output->make); + free(output->model); + free(output->serial); + output->make = NULL; + output->model = NULL; + output->serial = NULL; + if (!data || len < 128) { - snprintf(output->make, sizeof(output->make), ""); - snprintf(output->model, sizeof(output->model), ""); return; } uint16_t id = (data[8] << 8) | data[9]; - snprintf(output->make, sizeof(output->make), "%s", get_manufacturer(id)); + output->make = strdup(get_manufacturer(conn->backend->hwdb, id)); uint16_t model = data[10] | (data[11] << 8); - snprintf(output->model, sizeof(output->model), "0x%04X", model); + char model_str[32]; + snprintf(model_str, sizeof(model_str), "0x%04" PRIX16, model); uint32_t serial = data[12] | (data[13] << 8) | (data[14] << 8) | (data[15] << 8); - snprintf(output->serial, sizeof(output->serial), "0x%08X", serial); + char serial_str[32]; + if (serial != 0) { + snprintf(serial_str, sizeof(serial_str), "0x%08" PRIX32, serial); + } else { + serial_str[0] = '\0'; + } for (size_t i = 72; i <= 108; i += 18) { uint16_t flag = (data[i] << 8) | data[i + 1]; if (flag == 0 && data[i + 3] == 0xFC) { - sprintf(output->model, "%.13s", &data[i + 5]); + snprintf(model_str, sizeof(model_str), "%.13s", &data[i + 5]); // Monitor names are terminated by newline if they're too short - char *nl = strchr(output->model, '\n'); + char *nl = strchr(model_str, '\n'); if (nl) { *nl = '\0'; } } else if (flag == 0 && data[i + 3] == 0xFF) { - sprintf(output->serial, "%.13s", &data[i + 5]); + snprintf(serial_str, sizeof(serial_str), "%.13s", &data[i + 5]); // Monitor serial numbers are terminated by newline if they're too // short - char *nl = strchr(output->serial, '\n'); + char* nl = strchr(serial_str, '\n'); + if (nl) { *nl = '\0'; } } } -} -void parse_tile(struct wlr_output *restrict output, size_t len, const uint8_t *data) { +void parse_tile(struct wlr_drm_connector *conn, size_t len, const uint8_t *data) { + struct wlr_output *output = &conn->output; if (len > 0) { int ret; ret = sscanf((char*)data, "%d:%d:%d:%d:%d:%d:%d:%d", @@ -207,6 +179,9 @@ const char *conn_get_name(uint32_t type_id) { case DRM_MODE_CONNECTOR_USB: return "USB"; #endif default: return "Unknown"; + output->model = strdup(model_str); + if (serial_str[0] != '\0') { + output->serial = strdup(serial_str); } } diff --git a/backend/headless/backend.c b/backend/headless/backend.c index b14dda4a9..34536765e 100644 --- a/backend/headless/backend.c +++ b/backend/headless/backend.c @@ -3,7 +3,6 @@ #include #include #include "backend/headless.h" -#include "util/signal.h" struct wlr_headless_backend *headless_backend_from_backend( struct wlr_backend *wlr_backend) { @@ -20,7 +19,7 @@ static bool backend_start(struct wlr_backend *wlr_backend) { wl_list_for_each(output, &backend->outputs, link) { wl_event_source_timer_update(output->frame_timer, output->frame_delay); wlr_output_update_enabled(&output->wlr_output, true); - wlr_signal_emit_safe(&backend->backend.events.new_output, + wl_signal_emit_mutable(&backend->backend.events.new_output, &output->wlr_output); } diff --git a/backend/headless/output.c b/backend/headless/output.c index f03d6ee0d..5350747f8 100644 --- a/backend/headless/output.c +++ b/backend/headless/output.c @@ -4,7 +4,6 @@ #include #include #include "backend/headless.h" -#include "util/signal.h" static const uint32_t SUPPORTED_OUTPUT_STATE = WLR_OUTPUT_STATE_BACKEND_OPTIONAL | @@ -29,40 +28,41 @@ static bool output_set_custom_mode(struct wlr_headless_output *output, return true; } -static bool output_test(struct wlr_output *wlr_output) { - uint32_t unsupported = - wlr_output->pending.committed & ~SUPPORTED_OUTPUT_STATE; +static bool output_test(struct wlr_output *wlr_output, + const struct wlr_output_state *state) { + uint32_t unsupported = state->committed & ~SUPPORTED_OUTPUT_STATE; if (unsupported != 0) { wlr_log(WLR_DEBUG, "Unsupported output state fields: 0x%"PRIx32, unsupported); return false; } - if (wlr_output->pending.committed & WLR_OUTPUT_STATE_MODE) { - assert(wlr_output->pending.mode_type == WLR_OUTPUT_STATE_MODE_CUSTOM); + if (state->committed & WLR_OUTPUT_STATE_MODE) { + assert(state->mode_type == WLR_OUTPUT_STATE_MODE_CUSTOM); } return true; } -static bool output_commit(struct wlr_output *wlr_output) { +static bool output_commit(struct wlr_output *wlr_output, + const struct wlr_output_state *state) { struct wlr_headless_output *output = headless_output_from_output(wlr_output); - if (!output_test(wlr_output)) { + if (!output_test(wlr_output, state)) { return false; } - if (wlr_output->pending.committed & WLR_OUTPUT_STATE_MODE) { + if (state->committed & WLR_OUTPUT_STATE_MODE) { if (!output_set_custom_mode(output, - wlr_output->pending.custom_mode.width, - wlr_output->pending.custom_mode.height, - wlr_output->pending.custom_mode.refresh)) { + state->custom_mode.width, + state->custom_mode.height, + state->custom_mode.refresh)) { return false; } } - if (wlr_output->pending.committed & WLR_OUTPUT_STATE_BUFFER) { + if (state->committed & WLR_OUTPUT_STATE_BUFFER) { struct wlr_output_event_present present_event = { .commit_seq = wlr_output->commit_seq + 1, .presented = true, @@ -70,6 +70,8 @@ static bool output_commit(struct wlr_output *wlr_output) { wlr_output_send_present(wlr_output, &present_event); } + wl_event_source_timer_update(output->frame_timer, output->frame_delay); + return true; } @@ -93,7 +95,6 @@ bool wlr_output_is_headless(struct wlr_output *wlr_output) { static int signal_frame(void *data) { struct wlr_headless_output *output = data; wlr_output_send_frame(&output->wlr_output); - wl_event_source_timer_update(output->frame_timer, output->frame_delay); return 0; } @@ -114,8 +115,6 @@ struct wlr_output *wlr_headless_add_output(struct wlr_backend *wlr_backend, struct wlr_output *wlr_output = &output->wlr_output; output_set_custom_mode(output, width, height, 0); - strncpy(wlr_output->make, "headless", sizeof(wlr_output->make)); - strncpy(wlr_output->model, "headless", sizeof(wlr_output->model)); char name[64]; snprintf(name, sizeof(name), "HEADLESS-%zu", ++backend->last_output_num); @@ -134,7 +133,7 @@ struct wlr_output *wlr_headless_add_output(struct wlr_backend *wlr_backend, if (backend->started) { wl_event_source_timer_update(output->frame_timer, output->frame_delay); wlr_output_update_enabled(wlr_output, true); - wlr_signal_emit_safe(&backend->backend.events.new_output, wlr_output); + wl_signal_emit_mutable(&backend->backend.events.new_output, wlr_output); } return wlr_output; diff --git a/backend/libinput/backend.c b/backend/libinput/backend.c index 8023807fd..688fae5d3 100644 --- a/backend/libinput/backend.c +++ b/backend/libinput/backend.c @@ -6,7 +6,7 @@ #include #include #include "backend/libinput.h" -#include "util/signal.h" +#include "util/env.h" static struct wlr_libinput_backend *get_libinput_backend_from_backend( struct wlr_backend *wlr_backend) { @@ -104,15 +104,10 @@ static bool backend_start(struct wlr_backend *wlr_backend) { libinput_log_set_priority(backend->libinput_context, LIBINPUT_LOG_PRIORITY_ERROR); int libinput_fd = libinput_get_fd(backend->libinput_context); - char *no_devs = getenv("WLR_LIBINPUT_NO_DEVICES"); - if (no_devs) { - if (strcmp(no_devs, "1") != 0) { - no_devs = NULL; - } - } - if (!no_devs && backend->wlr_device_lists.size == 0) { + + if (!env_parse_bool("WLR_LIBINPUT_NO_DEVICES") && wl_list_empty(&backend->devices)) { handle_libinput_readable(libinput_fd, WL_EVENT_READABLE, backend); - if (backend->wlr_device_lists.size == 0) { + if (wl_list_empty(&backend->devices)) { wlr_log(WLR_ERROR, "libinput initialization failed, no input devices"); wlr_log(WLR_ERROR, "Set WLR_LIBINPUT_NO_DEVICES=1 to suppress this check"); return false; @@ -141,13 +136,9 @@ static void backend_destroy(struct wlr_backend *wlr_backend) { struct wlr_libinput_backend *backend = get_libinput_backend_from_backend(wlr_backend); - struct wl_list **wlr_devices_ptr; - wl_array_for_each(wlr_devices_ptr, &backend->wlr_device_lists) { - struct wlr_libinput_input_device *dev, *tmp; - wl_list_for_each_safe(dev, tmp, *wlr_devices_ptr, link) { - destroy_libinput_input_device(dev); - } - free(*wlr_devices_ptr); + struct wlr_libinput_input_device *dev, *tmp; + wl_list_for_each_safe(dev, tmp, &backend->devices, link) { + destroy_libinput_input_device(dev); } wlr_backend_finish(wlr_backend); @@ -156,7 +147,6 @@ static void backend_destroy(struct wlr_backend *wlr_backend) { wl_list_remove(&backend->session_destroy.link); wl_list_remove(&backend->session_signal.link); - wl_array_release(&backend->wlr_device_lists); if (backend->input_event) { wl_event_source_remove(backend->input_event); } @@ -211,7 +201,7 @@ struct wlr_backend *wlr_libinput_backend_create(struct wl_display *display, } wlr_backend_init(&backend->backend, &backend_impl); - wl_array_init(&backend->wlr_device_lists); + wl_list_init(&backend->devices); backend->session = session; backend->display = display; @@ -230,8 +220,27 @@ struct wlr_backend *wlr_libinput_backend_create(struct wl_display *display, struct libinput_device *wlr_libinput_get_device_handle( struct wlr_input_device *wlr_dev) { - struct wlr_libinput_input_device *dev = - (struct wlr_libinput_input_device *)wlr_dev; + struct wlr_libinput_input_device *dev = NULL; + switch (wlr_dev->type) { + case WLR_INPUT_DEVICE_KEYBOARD: + dev = device_from_keyboard(wlr_keyboard_from_input_device(wlr_dev)); + break; + case WLR_INPUT_DEVICE_POINTER: + dev = device_from_pointer(wlr_pointer_from_input_device(wlr_dev)); + break; + case WLR_INPUT_DEVICE_SWITCH: + dev = device_from_switch(wlr_switch_from_input_device(wlr_dev)); + break; + case WLR_INPUT_DEVICE_TOUCH: + dev = device_from_touch(wlr_touch_from_input_device(wlr_dev)); + break; + case WLR_INPUT_DEVICE_TABLET_TOOL: + dev = device_from_tablet(wlr_tablet_from_input_device(wlr_dev)); + break; + case WLR_INPUT_DEVICE_TABLET_PAD: + dev = device_from_tablet_pad(wlr_tablet_pad_from_input_device(wlr_dev)); + break; + } return dev->handle; } diff --git a/backend/libinput/events.c b/backend/libinput/events.c index e8d99f251..cbbf75370 100644 --- a/backend/libinput/events.c +++ b/backend/libinput/events.c @@ -1,87 +1,62 @@ #define _POSIX_C_SOURCE 200809L -#include + #include #include -#include #include +#include +#include +#include +#include +#include +#include #include #include "backend/libinput.h" -#include "util/array.h" -#include "util/signal.h" -struct wlr_input_device *get_appropriate_device( - enum wlr_input_device_type desired_type, - struct libinput_device *libinput_dev) { - struct wl_list *wlr_devices = libinput_device_get_user_data(libinput_dev); - if (!wlr_devices) { - return NULL; +void destroy_libinput_input_device(struct wlr_libinput_input_device *dev) { + if (dev->keyboard.impl) { + wlr_keyboard_finish(&dev->keyboard); } - struct wlr_libinput_input_device *dev; - wl_list_for_each(dev, wlr_devices, link) { - if (dev->wlr_input_device.type == desired_type) { - return &dev->wlr_input_device; - } + if (dev->pointer.impl) { + wlr_pointer_finish(&dev->pointer); } - return NULL; -} - -void destroy_libinput_input_device(struct wlr_libinput_input_device *dev) -{ - /** - * TODO remove the redundant wlr_input_device from wlr_libinput_input_device - * wlr_libinput_input_device::wlr_input_device is not owned by its input - * device type, which means we have 2 wlr_input_device to cleanup - */ - if (dev->wlr_input_device._device) { - wlr_input_device_destroy(&dev->wlr_input_device); + if (dev->switch_device.impl) { + wlr_switch_finish(&dev->switch_device); + } + if (dev->touch.impl) { + wlr_touch_finish(&dev->touch); + } + if (dev->tablet.impl) { + finish_device_tablet(dev); + } + if (dev->tablet_pad.impl) { + finish_device_tablet_pad(dev); } - wlr_input_device_finish(&dev->wlr_input_device); libinput_device_unref(dev->handle); wl_list_remove(&dev->link); free(dev); } -static struct wlr_input_device *allocate_device( - struct wlr_libinput_backend *backend, - struct libinput_device *libinput_dev, struct wl_list *wlr_devices, - enum wlr_input_device_type type) { - const char *name = libinput_device_get_name(libinput_dev); - struct wlr_libinput_input_device *dev = - calloc(1, sizeof(struct wlr_libinput_input_device)); - if (dev == NULL) { - return NULL; - } - struct wlr_input_device *wlr_dev = &dev->wlr_input_device; - libinput_device_get_size(libinput_dev, - &wlr_dev->width_mm, &wlr_dev->height_mm); - const char *output_name = libinput_device_get_output_name(libinput_dev); - if (output_name != NULL) { - wlr_dev->output_name = strdup(output_name); - } - wl_list_insert(wlr_devices, &dev->link); - dev->handle = libinput_dev; - libinput_device_ref(libinput_dev); - wlr_input_device_init(wlr_dev, type, name); - wlr_dev->vendor = libinput_device_get_id_vendor(libinput_dev); - wlr_dev->product = libinput_device_get_id_product(libinput_dev); - return wlr_dev; -} - bool wlr_input_device_is_libinput(struct wlr_input_device *wlr_dev) { switch (wlr_dev->type) { case WLR_INPUT_DEVICE_KEYBOARD: - return wlr_dev->keyboard->impl == &libinput_keyboard_impl; + return wlr_keyboard_from_input_device(wlr_dev)->impl == + &libinput_keyboard_impl; case WLR_INPUT_DEVICE_POINTER: - return wlr_dev->pointer->impl == &libinput_pointer_impl; + return wlr_pointer_from_input_device(wlr_dev)->impl == + &libinput_pointer_impl; case WLR_INPUT_DEVICE_TOUCH: - return wlr_dev->touch->impl == &libinput_touch_impl; + return wlr_touch_from_input_device(wlr_dev)->impl == + &libinput_touch_impl; case WLR_INPUT_DEVICE_TABLET_TOOL: - return wlr_dev->tablet->impl == &libinput_tablet_impl; + return wlr_tablet_from_input_device(wlr_dev)-> impl == + &libinput_tablet_impl; case WLR_INPUT_DEVICE_TABLET_PAD: - return wlr_dev->tablet_pad->impl == &libinput_tablet_pad_impl; + return wlr_tablet_pad_from_input_device(wlr_dev)->impl == + &libinput_tablet_pad_impl; case WLR_INPUT_DEVICE_SWITCH: - return wlr_dev->switch_device->impl == &libinput_switch_impl; + return wlr_switch_from_input_device(wlr_dev)->impl == + &libinput_switch_impl; default: return false; } @@ -89,165 +64,96 @@ bool wlr_input_device_is_libinput(struct wlr_input_device *wlr_dev) { static void handle_device_added(struct wlr_libinput_backend *backend, struct libinput_device *libinput_dev) { - /* - * Note: the wlr API exposes only devices with a single capability, because - * that meshes better with how Wayland does things and is a bit simpler. - * However, libinput devices often have multiple capabilities - in such - * cases we have to create several devices. - */ int vendor = libinput_device_get_id_vendor(libinput_dev); int product = libinput_device_get_id_product(libinput_dev); const char *name = libinput_device_get_name(libinput_dev); - struct wl_list *wlr_devices = calloc(1, sizeof(struct wl_list)); - if (!wlr_devices) { - wlr_log(WLR_ERROR, "Allocation failed"); + wlr_log(WLR_DEBUG, "Adding %s [%d:%d]", name, vendor, product); + + struct wlr_libinput_input_device *dev = + calloc(1, sizeof(struct wlr_libinput_input_device)); + if (dev == NULL) { + wlr_log_errno(WLR_ERROR, "failed to allocate wlr_libinput_input_device"); return; } - wl_list_init(wlr_devices); - wlr_log(WLR_DEBUG, "Added %s [%d:%d]", name, vendor, product); + + dev->handle = libinput_dev; + libinput_device_ref(libinput_dev); + libinput_device_set_user_data(libinput_dev, dev); + + wl_list_insert(&backend->devices, &dev->link); if (libinput_device_has_capability( libinput_dev, LIBINPUT_DEVICE_CAP_KEYBOARD)) { - struct wlr_input_device *wlr_dev = allocate_device(backend, - libinput_dev, wlr_devices, WLR_INPUT_DEVICE_KEYBOARD); - if (!wlr_dev) { - goto fail; - } - wlr_dev->keyboard = create_libinput_keyboard(libinput_dev); - if (!wlr_dev->keyboard) { - free(wlr_dev); - goto fail; - } - wlr_signal_emit_safe(&backend->backend.events.new_input, wlr_dev); + init_device_keyboard(dev); + + wl_signal_emit_mutable(&backend->backend.events.new_input, + &dev->keyboard.base); } + if (libinput_device_has_capability( libinput_dev, LIBINPUT_DEVICE_CAP_POINTER)) { - struct wlr_input_device *wlr_dev = allocate_device(backend, - libinput_dev, wlr_devices, WLR_INPUT_DEVICE_POINTER); - if (!wlr_dev) { - goto fail; - } - wlr_dev->pointer = create_libinput_pointer(libinput_dev); - if (!wlr_dev->pointer) { - free(wlr_dev); - goto fail; - } - wlr_signal_emit_safe(&backend->backend.events.new_input, wlr_dev); - } - if (libinput_device_has_capability( - libinput_dev, LIBINPUT_DEVICE_CAP_TOUCH)) { - struct wlr_input_device *wlr_dev = allocate_device(backend, - libinput_dev, wlr_devices, WLR_INPUT_DEVICE_TOUCH); - if (!wlr_dev) { - goto fail; - } - wlr_dev->touch = create_libinput_touch(libinput_dev); - if (!wlr_dev->touch) { - free(wlr_dev); - goto fail; - } - wlr_signal_emit_safe(&backend->backend.events.new_input, wlr_dev); - } - if (libinput_device_has_capability(libinput_dev, - LIBINPUT_DEVICE_CAP_TABLET_TOOL)) { - struct wlr_input_device *wlr_dev = allocate_device(backend, - libinput_dev, wlr_devices, WLR_INPUT_DEVICE_TABLET_TOOL); - if (!wlr_dev) { - goto fail; - } - wlr_dev->tablet = create_libinput_tablet(libinput_dev); - if (!wlr_dev->tablet) { - free(wlr_dev); - goto fail; - } - wlr_signal_emit_safe(&backend->backend.events.new_input, wlr_dev); - } - if (libinput_device_has_capability( - libinput_dev, LIBINPUT_DEVICE_CAP_TABLET_PAD)) { - struct wlr_input_device *wlr_dev = allocate_device(backend, - libinput_dev, wlr_devices, WLR_INPUT_DEVICE_TABLET_PAD); - if (!wlr_dev) { - goto fail; - } - wlr_dev->tablet_pad = create_libinput_tablet_pad(libinput_dev); - if (!wlr_dev->tablet_pad) { - free(wlr_dev); - goto fail; - } - wlr_signal_emit_safe(&backend->backend.events.new_input, wlr_dev); - } - if (libinput_device_has_capability( - libinput_dev, LIBINPUT_DEVICE_CAP_GESTURE)) { - // TODO + init_device_pointer(dev); + + wl_signal_emit_mutable(&backend->backend.events.new_input, + &dev->pointer.base); } + if (libinput_device_has_capability( libinput_dev, LIBINPUT_DEVICE_CAP_SWITCH)) { - struct wlr_input_device *wlr_dev = allocate_device(backend, - libinput_dev, wlr_devices, WLR_INPUT_DEVICE_SWITCH); - if (!wlr_dev) { - goto fail; - } - wlr_dev->switch_device = create_libinput_switch(libinput_dev); - if (!wlr_dev->switch_device) { - free(wlr_dev); - goto fail; - } - wlr_signal_emit_safe(&backend->backend.events.new_input, wlr_dev); + init_device_switch(dev); + wl_signal_emit_mutable(&backend->backend.events.new_input, + &dev->switch_device.base); } - if (!wl_list_empty(wlr_devices)) { - struct wl_list **dst = wl_array_add(&backend->wlr_device_lists, sizeof(wlr_devices)); - if (!dst) { - goto fail; - } - *dst = wlr_devices; - - libinput_device_set_user_data(libinput_dev, wlr_devices); - } else { - free(wlr_devices); + if (libinput_device_has_capability( + libinput_dev, LIBINPUT_DEVICE_CAP_TOUCH)) { + init_device_touch(dev); + wl_signal_emit_mutable(&backend->backend.events.new_input, + &dev->touch.base); } - return; -fail: - wlr_log(WLR_ERROR, "Could not allocate new device"); - struct wlr_libinput_input_device *dev, *tmp_dev; - wl_list_for_each_safe(dev, tmp_dev, wlr_devices, link) { - free(dev); + if (libinput_device_has_capability(libinput_dev, + LIBINPUT_DEVICE_CAP_TABLET_TOOL)) { + init_device_tablet(dev); + wl_signal_emit_mutable(&backend->backend.events.new_input, + &dev->tablet.base); + } + + if (libinput_device_has_capability( + libinput_dev, LIBINPUT_DEVICE_CAP_TABLET_PAD)) { + init_device_tablet_pad(dev); + wl_signal_emit_mutable(&backend->backend.events.new_input, + &dev->tablet_pad.base); + } + + if (libinput_device_has_capability( + libinput_dev, LIBINPUT_DEVICE_CAP_GESTURE)) { + wlr_log(WLR_DEBUG, "libinput gesture not handled"); } - free(wlr_devices); } static void handle_device_removed(struct wlr_libinput_backend *backend, struct libinput_device *libinput_dev) { - struct wl_list *wlr_devices = libinput_device_get_user_data(libinput_dev); int vendor = libinput_device_get_id_vendor(libinput_dev); int product = libinput_device_get_id_product(libinput_dev); const char *name = libinput_device_get_name(libinput_dev); wlr_log(WLR_DEBUG, "Removing %s [%d:%d]", name, vendor, product); - if (!wlr_devices) { + + struct wlr_libinput_input_device *dev = + libinput_device_get_user_data(libinput_dev); + if (dev == NULL) { + wlr_log(WLR_ERROR, "libinput_device has no wlr_libinput_input_device"); return; } - struct wlr_libinput_input_device *dev, *tmp_dev; - wl_list_for_each_safe(dev, tmp_dev, wlr_devices, link) { - destroy_libinput_input_device(dev); - } - size_t i = 0; - struct wl_list **ptr; - wl_array_for_each(ptr, &backend->wlr_device_lists) { - struct wl_list *iter = *ptr; - if (iter == wlr_devices) { - array_remove_at(&backend->wlr_device_lists, - i * sizeof(struct wl_list *), sizeof(struct wl_list *)); - break; - } - i++; - } - free(wlr_devices); + + destroy_libinput_input_device(dev); } void handle_libinput_event(struct wlr_libinput_backend *backend, struct libinput_event *event) { struct libinput_device *libinput_dev = libinput_event_get_device(event); + struct wlr_libinput_input_device *dev = + libinput_device_get_user_data(libinput_dev); enum libinput_event_type event_type = libinput_event_get_type(event); switch (event_type) { case LIBINPUT_EVENT_DEVICE_ADDED: @@ -257,83 +163,100 @@ void handle_libinput_event(struct wlr_libinput_backend *backend, handle_device_removed(backend, libinput_dev); break; case LIBINPUT_EVENT_KEYBOARD_KEY: - handle_keyboard_key(event, libinput_dev); + handle_keyboard_key(event, &dev->keyboard); break; case LIBINPUT_EVENT_POINTER_MOTION: - handle_pointer_motion(event, libinput_dev); + handle_pointer_motion(event, &dev->pointer); break; case LIBINPUT_EVENT_POINTER_MOTION_ABSOLUTE: - handle_pointer_motion_abs(event, libinput_dev); + handle_pointer_motion_abs(event, &dev->pointer); break; case LIBINPUT_EVENT_POINTER_BUTTON: - handle_pointer_button(event, libinput_dev); + handle_pointer_button(event, &dev->pointer); break; case LIBINPUT_EVENT_POINTER_AXIS: - handle_pointer_axis(event, libinput_dev); +#if !LIBINPUT_HAS_SCROLL_VALUE120 + /* This event must be ignored in favour of the SCROLL_* events */ + handle_pointer_axis(event, &dev->pointer); +#endif break; +#if LIBINPUT_HAS_SCROLL_VALUE120 + case LIBINPUT_EVENT_POINTER_SCROLL_WHEEL: + handle_pointer_axis_value120(event, &dev->pointer, + WLR_AXIS_SOURCE_WHEEL); + break; + case LIBINPUT_EVENT_POINTER_SCROLL_FINGER: + handle_pointer_axis_value120(event, &dev->pointer, + WLR_AXIS_SOURCE_FINGER); + break; + case LIBINPUT_EVENT_POINTER_SCROLL_CONTINUOUS: + handle_pointer_axis_value120(event, &dev->pointer, + WLR_AXIS_SOURCE_CONTINUOUS); + break; +#endif case LIBINPUT_EVENT_TOUCH_DOWN: - handle_touch_down(event, libinput_dev); + handle_touch_down(event, &dev->touch); break; case LIBINPUT_EVENT_TOUCH_UP: - handle_touch_up(event, libinput_dev); + handle_touch_up(event, &dev->touch); break; case LIBINPUT_EVENT_TOUCH_MOTION: - handle_touch_motion(event, libinput_dev); + handle_touch_motion(event, &dev->touch); break; case LIBINPUT_EVENT_TOUCH_CANCEL: - handle_touch_cancel(event, libinput_dev); + handle_touch_cancel(event, &dev->touch); break; case LIBINPUT_EVENT_TOUCH_FRAME: - handle_touch_frame(event, libinput_dev); + handle_touch_frame(event, &dev->touch); break; case LIBINPUT_EVENT_TABLET_TOOL_AXIS: - handle_tablet_tool_axis(event, libinput_dev); + handle_tablet_tool_axis(event, &dev->tablet); break; case LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY: - handle_tablet_tool_proximity(event, libinput_dev); + handle_tablet_tool_proximity(event, &dev->tablet); break; case LIBINPUT_EVENT_TABLET_TOOL_TIP: - handle_tablet_tool_tip(event, libinput_dev); + handle_tablet_tool_tip(event, &dev->tablet); break; case LIBINPUT_EVENT_TABLET_TOOL_BUTTON: - handle_tablet_tool_button(event, libinput_dev); + handle_tablet_tool_button(event, &dev->tablet); break; case LIBINPUT_EVENT_TABLET_PAD_BUTTON: - handle_tablet_pad_button(event, libinput_dev); + handle_tablet_pad_button(event, &dev->tablet_pad); break; case LIBINPUT_EVENT_TABLET_PAD_RING: - handle_tablet_pad_ring(event, libinput_dev); + handle_tablet_pad_ring(event, &dev->tablet_pad); break; case LIBINPUT_EVENT_TABLET_PAD_STRIP: - handle_tablet_pad_strip(event, libinput_dev); + handle_tablet_pad_strip(event, &dev->tablet_pad); break; case LIBINPUT_EVENT_SWITCH_TOGGLE: - handle_switch_toggle(event, libinput_dev); + handle_switch_toggle(event, &dev->switch_device); break; case LIBINPUT_EVENT_GESTURE_SWIPE_BEGIN: - handle_pointer_swipe_begin(event, libinput_dev); + handle_pointer_swipe_begin(event, &dev->pointer); break; case LIBINPUT_EVENT_GESTURE_SWIPE_UPDATE: - handle_pointer_swipe_update(event, libinput_dev); + handle_pointer_swipe_update(event, &dev->pointer); break; case LIBINPUT_EVENT_GESTURE_SWIPE_END: - handle_pointer_swipe_end(event, libinput_dev); + handle_pointer_swipe_end(event, &dev->pointer); break; case LIBINPUT_EVENT_GESTURE_PINCH_BEGIN: - handle_pointer_pinch_begin(event, libinput_dev); + handle_pointer_pinch_begin(event, &dev->pointer); break; case LIBINPUT_EVENT_GESTURE_PINCH_UPDATE: - handle_pointer_pinch_update(event, libinput_dev); + handle_pointer_pinch_update(event, &dev->pointer); break; case LIBINPUT_EVENT_GESTURE_PINCH_END: - handle_pointer_pinch_end(event, libinput_dev); + handle_pointer_pinch_end(event, &dev->pointer); break; #if LIBINPUT_HAS_HOLD_GESTURES case LIBINPUT_EVENT_GESTURE_HOLD_BEGIN: - handle_pointer_hold_begin(event, libinput_dev); + handle_pointer_hold_begin(event, &dev->pointer); break; case LIBINPUT_EVENT_GESTURE_HOLD_END: - handle_pointer_hold_end(event, libinput_dev); + handle_pointer_hold_end(event, &dev->pointer); break; #endif default: diff --git a/backend/libinput/keyboard.c b/backend/libinput/keyboard.c index 9127217a8..789260d54 100644 --- a/backend/libinput/keyboard.c +++ b/backend/libinput/keyboard.c @@ -1,70 +1,42 @@ #include #include #include -#include -#include -#include +#include #include "backend/libinput.h" -struct wlr_libinput_keyboard { - struct wlr_keyboard wlr_keyboard; - struct libinput_device *libinput_dev; -}; +struct wlr_libinput_input_device *device_from_keyboard( + struct wlr_keyboard *kb) { + assert(kb->impl == &libinput_keyboard_impl); -static struct wlr_libinput_keyboard *get_libinput_keyboard_from_keyboard( - struct wlr_keyboard *wlr_kb) { - assert(wlr_kb->impl == &libinput_keyboard_impl); - return (struct wlr_libinput_keyboard *)wlr_kb; + struct wlr_libinput_input_device *dev = wl_container_of(kb, dev, keyboard); + return dev; } static void keyboard_set_leds(struct wlr_keyboard *wlr_kb, uint32_t leds) { - struct wlr_libinput_keyboard *kb = - get_libinput_keyboard_from_keyboard(wlr_kb); - libinput_device_led_update(kb->libinput_dev, leds); -} - -static void keyboard_destroy(struct wlr_keyboard *wlr_kb) { - struct wlr_libinput_keyboard *kb = - get_libinput_keyboard_from_keyboard(wlr_kb); - libinput_device_unref(kb->libinput_dev); - free(kb); + struct wlr_libinput_input_device *dev = device_from_keyboard(wlr_kb); + libinput_device_led_update(dev->handle, leds); } const struct wlr_keyboard_impl libinput_keyboard_impl = { - .destroy = keyboard_destroy, + .name = "libinput-keyboard", .led_update = keyboard_set_leds }; -struct wlr_keyboard *create_libinput_keyboard( - struct libinput_device *libinput_dev) { - struct wlr_libinput_keyboard *kb = - calloc(1, sizeof(struct wlr_libinput_keyboard)); - if (kb == NULL) { - return NULL; - } - kb->libinput_dev = libinput_dev; - libinput_device_ref(libinput_dev); - libinput_device_led_update(libinput_dev, 0); - struct wlr_keyboard *wlr_kb = &kb->wlr_keyboard; - const char *name = libinput_device_get_name(libinput_dev); +void init_device_keyboard(struct wlr_libinput_input_device *dev) { + const char *name = libinput_device_get_name(dev->handle); + struct wlr_keyboard *wlr_kb = &dev->keyboard; wlr_keyboard_init(wlr_kb, &libinput_keyboard_impl, name); - wlr_kb->base.vendor = libinput_device_get_id_vendor(libinput_dev); - wlr_kb->base.product = libinput_device_get_id_product(libinput_dev); - return wlr_kb; + wlr_kb->base.vendor = libinput_device_get_id_vendor(dev->handle); + wlr_kb->base.product = libinput_device_get_id_product(dev->handle); + + libinput_device_led_update(dev->handle, 0); } void handle_keyboard_key(struct libinput_event *event, - struct libinput_device *libinput_dev) { - struct wlr_input_device *wlr_dev = - get_appropriate_device(WLR_INPUT_DEVICE_KEYBOARD, libinput_dev); - if (!wlr_dev) { - wlr_log(WLR_DEBUG, - "Got a keyboard event for a device with no keyboards?"); - return; - } + struct wlr_keyboard *kb) { struct libinput_event_keyboard *kbevent = libinput_event_get_keyboard_event(event); - struct wlr_event_keyboard_key wlr_event = { 0 }; + struct wlr_keyboard_key_event wlr_event = { 0 }; wlr_event.time_msec = usec_to_msec(libinput_event_keyboard_get_time_usec(kbevent)); wlr_event.keycode = libinput_event_keyboard_get_key(kbevent); @@ -79,5 +51,5 @@ void handle_keyboard_key(struct libinput_event *event, break; } wlr_event.update_state = true; - wlr_keyboard_notify_key(wlr_dev->keyboard, &wlr_event); + wlr_keyboard_notify_key(kb, &wlr_event); } diff --git a/backend/libinput/meson.build b/backend/libinput/meson.build index 38ba05f12..2f3ccab3e 100644 --- a/backend/libinput/meson.build +++ b/backend/libinput/meson.build @@ -28,8 +28,8 @@ wlr_files += files( features += { 'libinput-backend': true } wlr_deps += libinput -# libinput hold gestures are available since 1.19.0 -add_project_arguments( +# libinput hold gestures and high resolution scroll are available since 1.19.0 +add_project_arguments([ '-DLIBINPUT_HAS_HOLD_GESTURES=@0@'.format(libinput.version().version_compare('>=1.19.0').to_int()), - language: 'c', -) + '-DLIBINPUT_HAS_SCROLL_VALUE120=@0@'.format(libinput.version().version_compare('>=1.19.0').to_int()), +], language: 'c') diff --git a/backend/libinput/pointer.c b/backend/libinput/pointer.c index 706ace7b5..48f8ae128 100644 --- a/backend/libinput/pointer.c +++ b/backend/libinput/pointer.c @@ -1,83 +1,65 @@ #include #include -#include -#include -#include -#include +#include #include "backend/libinput.h" -#include "util/signal.h" -const struct wlr_pointer_impl libinput_pointer_impl = {0}; +const struct wlr_pointer_impl libinput_pointer_impl = { + .name = "libinput-pointer", +}; -struct wlr_pointer *create_libinput_pointer( - struct libinput_device *libinput_dev) { - assert(libinput_dev); - struct wlr_pointer *wlr_pointer = calloc(1, sizeof(struct wlr_pointer)); - if (!wlr_pointer) { - wlr_log(WLR_ERROR, "Unable to allocate wlr_pointer"); - return NULL; - } - const char *name = libinput_device_get_name(libinput_dev); +void init_device_pointer(struct wlr_libinput_input_device *dev) { + const char *name = libinput_device_get_name(dev->handle); + struct wlr_pointer *wlr_pointer = &dev->pointer; wlr_pointer_init(wlr_pointer, &libinput_pointer_impl, name); - wlr_pointer->base.vendor = libinput_device_get_id_vendor(libinput_dev); - wlr_pointer->base.product = libinput_device_get_id_product(libinput_dev); - return wlr_pointer; + wlr_pointer->base.vendor = libinput_device_get_id_vendor(dev->handle); + wlr_pointer->base.product = libinput_device_get_id_product(dev->handle); +} + +struct wlr_libinput_input_device *device_from_pointer( + struct wlr_pointer *wlr_pointer) { + assert(wlr_pointer->impl == &libinput_pointer_impl); + + struct wlr_libinput_input_device *dev = + wl_container_of(wlr_pointer, dev, pointer); + return dev; } void handle_pointer_motion(struct libinput_event *event, - struct libinput_device *libinput_dev) { - struct wlr_input_device *wlr_dev = - get_appropriate_device(WLR_INPUT_DEVICE_POINTER, libinput_dev); - if (!wlr_dev) { - wlr_log(WLR_DEBUG, "Got a pointer event for a device with no pointers?"); - return; - } + struct wlr_pointer *pointer) { struct libinput_event_pointer *pevent = libinput_event_get_pointer_event(event); - struct wlr_event_pointer_motion wlr_event = { 0 }; - wlr_event.device = wlr_dev; + struct wlr_pointer_motion_event wlr_event = { 0 }; + wlr_event.pointer = pointer; wlr_event.time_msec = usec_to_msec(libinput_event_pointer_get_time_usec(pevent)); wlr_event.delta_x = libinput_event_pointer_get_dx(pevent); wlr_event.delta_y = libinput_event_pointer_get_dy(pevent); wlr_event.unaccel_dx = libinput_event_pointer_get_dx_unaccelerated(pevent); wlr_event.unaccel_dy = libinput_event_pointer_get_dy_unaccelerated(pevent); - wlr_signal_emit_safe(&wlr_dev->pointer->events.motion, &wlr_event); - wlr_signal_emit_safe(&wlr_dev->pointer->events.frame, wlr_dev->pointer); + wl_signal_emit_mutable(&pointer->events.motion, &wlr_event); + wl_signal_emit_mutable(&pointer->events.frame, pointer); } void handle_pointer_motion_abs(struct libinput_event *event, - struct libinput_device *libinput_dev) { - struct wlr_input_device *wlr_dev = - get_appropriate_device(WLR_INPUT_DEVICE_POINTER, libinput_dev); - if (!wlr_dev) { - wlr_log(WLR_DEBUG, "Got a pointer event for a device with no pointers?"); - return; - } + struct wlr_pointer *pointer) { struct libinput_event_pointer *pevent = libinput_event_get_pointer_event(event); - struct wlr_event_pointer_motion_absolute wlr_event = { 0 }; - wlr_event.device = wlr_dev; + struct wlr_pointer_motion_absolute_event wlr_event = { 0 }; + wlr_event.pointer = pointer; wlr_event.time_msec = usec_to_msec(libinput_event_pointer_get_time_usec(pevent)); wlr_event.x = libinput_event_pointer_get_absolute_x_transformed(pevent, 1); wlr_event.y = libinput_event_pointer_get_absolute_y_transformed(pevent, 1); - wlr_signal_emit_safe(&wlr_dev->pointer->events.motion_absolute, &wlr_event); - wlr_signal_emit_safe(&wlr_dev->pointer->events.frame, wlr_dev->pointer); + wl_signal_emit_mutable(&pointer->events.motion_absolute, &wlr_event); + wl_signal_emit_mutable(&pointer->events.frame, pointer); } void handle_pointer_button(struct libinput_event *event, - struct libinput_device *libinput_dev) { - struct wlr_input_device *wlr_dev = - get_appropriate_device(WLR_INPUT_DEVICE_POINTER, libinput_dev); - if (!wlr_dev) { - wlr_log(WLR_DEBUG, "Got a pointer event for a device with no pointers?"); - return; - } + struct wlr_pointer *pointer) { struct libinput_event_pointer *pevent = libinput_event_get_pointer_event(event); - struct wlr_event_pointer_button wlr_event = { 0 }; - wlr_event.device = wlr_dev; + struct wlr_pointer_button_event wlr_event = { 0 }; + wlr_event.pointer = pointer; wlr_event.time_msec = usec_to_msec(libinput_event_pointer_get_time_usec(pevent)); wlr_event.button = libinput_event_pointer_get_button(pevent); @@ -89,22 +71,16 @@ void handle_pointer_button(struct libinput_event *event, wlr_event.state = WLR_BUTTON_RELEASED; break; } - wlr_signal_emit_safe(&wlr_dev->pointer->events.button, &wlr_event); - wlr_signal_emit_safe(&wlr_dev->pointer->events.frame, wlr_dev->pointer); + wl_signal_emit_mutable(&pointer->events.button, &wlr_event); + wl_signal_emit_mutable(&pointer->events.frame, pointer); } void handle_pointer_axis(struct libinput_event *event, - struct libinput_device *libinput_dev) { - struct wlr_input_device *wlr_dev = - get_appropriate_device(WLR_INPUT_DEVICE_POINTER, libinput_dev); - if (!wlr_dev) { - wlr_log(WLR_DEBUG, "Got a pointer event for a device with no pointers?"); - return; - } + struct wlr_pointer *pointer) { struct libinput_event_pointer *pevent = libinput_event_get_pointer_event(event); - struct wlr_event_pointer_axis wlr_event = { 0 }; - wlr_event.device = wlr_dev; + struct wlr_pointer_axis_event wlr_event = { 0 }; + wlr_event.pointer = pointer; wlr_event.time_msec = usec_to_msec(libinput_event_pointer_get_time_usec(pevent)); switch (libinput_event_pointer_get_axis_source(pevent)) { @@ -126,115 +102,127 @@ void handle_pointer_axis(struct libinput_event *event, LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL, }; for (size_t i = 0; i < sizeof(axes) / sizeof(axes[0]); ++i) { - if (libinput_event_pointer_has_axis(pevent, axes[i])) { - switch (axes[i]) { - case LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL: - wlr_event.orientation = WLR_AXIS_ORIENTATION_VERTICAL; - break; - case LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL: - wlr_event.orientation = WLR_AXIS_ORIENTATION_HORIZONTAL; - break; - } - wlr_event.delta = - libinput_event_pointer_get_axis_value(pevent, axes[i]); - wlr_event.delta_discrete = - libinput_event_pointer_get_axis_value_discrete(pevent, axes[i]); - wlr_signal_emit_safe(&wlr_dev->pointer->events.axis, &wlr_event); + if (!libinput_event_pointer_has_axis(pevent, axes[i])) { + continue; } + + switch (axes[i]) { + case LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL: + wlr_event.orientation = WLR_AXIS_ORIENTATION_VERTICAL; + break; + case LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL: + wlr_event.orientation = WLR_AXIS_ORIENTATION_HORIZONTAL; + break; + } + wlr_event.delta = + libinput_event_pointer_get_axis_value(pevent, axes[i]); + wlr_event.delta_discrete = + libinput_event_pointer_get_axis_value_discrete(pevent, axes[i]); + wlr_event.delta_discrete *= WLR_POINTER_AXIS_DISCRETE_STEP; + wl_signal_emit_mutable(&pointer->events.axis, &wlr_event); } - wlr_signal_emit_safe(&wlr_dev->pointer->events.frame, wlr_dev->pointer); + wl_signal_emit_mutable(&pointer->events.frame, pointer); } -void handle_pointer_swipe_begin(struct libinput_event *event, - struct libinput_device *libinput_dev) { - struct wlr_input_device *wlr_dev = - get_appropriate_device(WLR_INPUT_DEVICE_POINTER, libinput_dev); - if (!wlr_dev) { - wlr_log(WLR_DEBUG, "Got a pointer gesture event for a device with no pointers?"); - return; +#if LIBINPUT_HAS_SCROLL_VALUE120 +void handle_pointer_axis_value120(struct libinput_event *event, + struct wlr_pointer *pointer, enum wlr_axis_source source) { + struct libinput_event_pointer *pevent = + libinput_event_get_pointer_event(event); + struct wlr_pointer_axis_event wlr_event = { 0 }; + wlr_event.pointer = pointer; + wlr_event.time_msec = + usec_to_msec(libinput_event_pointer_get_time_usec(pevent)); + wlr_event.source = source; + + const enum libinput_pointer_axis axes[] = { + LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL, + LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL, + }; + for (size_t i = 0; i < sizeof(axes) / sizeof(axes[0]); ++i) { + if (!libinput_event_pointer_has_axis(pevent, axes[i])) { + continue; + } + switch (axes[i]) { + case LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL: + wlr_event.orientation = WLR_AXIS_ORIENTATION_VERTICAL; + break; + case LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL: + wlr_event.orientation = WLR_AXIS_ORIENTATION_HORIZONTAL; + break; + } + wlr_event.delta = + libinput_event_pointer_get_scroll_value(pevent, axes[i]); + if (source == WLR_AXIS_SOURCE_WHEEL) { + wlr_event.delta_discrete = + libinput_event_pointer_get_scroll_value_v120(pevent, axes[i]); + } + wl_signal_emit_mutable(&pointer->events.axis, &wlr_event); } + wl_signal_emit_mutable(&pointer->events.frame, pointer); +} +#endif + +void handle_pointer_swipe_begin(struct libinput_event *event, + struct wlr_pointer *pointer) { struct libinput_event_gesture *gevent = libinput_event_get_gesture_event(event); - struct wlr_event_pointer_swipe_begin wlr_event = { - .device = wlr_dev, + struct wlr_pointer_swipe_begin_event wlr_event = { + .pointer = pointer, .time_msec = usec_to_msec(libinput_event_gesture_get_time_usec(gevent)), .fingers = libinput_event_gesture_get_finger_count(gevent), }; - wlr_signal_emit_safe(&wlr_dev->pointer->events.swipe_begin, &wlr_event); + wl_signal_emit_mutable(&pointer->events.swipe_begin, &wlr_event); } void handle_pointer_swipe_update(struct libinput_event *event, - struct libinput_device *libinput_dev) { - struct wlr_input_device *wlr_dev = - get_appropriate_device(WLR_INPUT_DEVICE_POINTER, libinput_dev); - if (!wlr_dev) { - wlr_log(WLR_DEBUG, "Got a pointer gesture event for a device with no pointers?"); - return; - } + struct wlr_pointer *pointer) { struct libinput_event_gesture *gevent = libinput_event_get_gesture_event(event); - struct wlr_event_pointer_swipe_update wlr_event = { - .device = wlr_dev, + struct wlr_pointer_swipe_update_event wlr_event = { + .pointer = pointer, .time_msec = usec_to_msec(libinput_event_gesture_get_time_usec(gevent)), .fingers = libinput_event_gesture_get_finger_count(gevent), .dx = libinput_event_gesture_get_dx(gevent), .dy = libinput_event_gesture_get_dy(gevent), }; - wlr_signal_emit_safe(&wlr_dev->pointer->events.swipe_update, &wlr_event); + wl_signal_emit_mutable(&pointer->events.swipe_update, &wlr_event); } void handle_pointer_swipe_end(struct libinput_event *event, - struct libinput_device *libinput_dev) { - struct wlr_input_device *wlr_dev = - get_appropriate_device(WLR_INPUT_DEVICE_POINTER, libinput_dev); - if (!wlr_dev) { - wlr_log(WLR_DEBUG, "Got a pointer gesture event for a device with no pointers?"); - return; - } + struct wlr_pointer *pointer) { struct libinput_event_gesture *gevent = libinput_event_get_gesture_event(event); - struct wlr_event_pointer_swipe_end wlr_event = { - .device = wlr_dev, + struct wlr_pointer_swipe_end_event wlr_event = { + .pointer = pointer, .time_msec = usec_to_msec(libinput_event_gesture_get_time_usec(gevent)), .cancelled = libinput_event_gesture_get_cancelled(gevent), }; - wlr_signal_emit_safe(&wlr_dev->pointer->events.swipe_end, &wlr_event); + wl_signal_emit_mutable(&pointer->events.swipe_end, &wlr_event); } void handle_pointer_pinch_begin(struct libinput_event *event, - struct libinput_device *libinput_dev) { - struct wlr_input_device *wlr_dev = - get_appropriate_device(WLR_INPUT_DEVICE_POINTER, libinput_dev); - if (!wlr_dev) { - wlr_log(WLR_DEBUG, "Got a pointer gesture event for a device with no pointers?"); - return; - } + struct wlr_pointer *pointer) { struct libinput_event_gesture *gevent = libinput_event_get_gesture_event(event); - struct wlr_event_pointer_pinch_begin wlr_event = { - .device = wlr_dev, + struct wlr_pointer_pinch_begin_event wlr_event = { + .pointer = pointer, .time_msec = usec_to_msec(libinput_event_gesture_get_time_usec(gevent)), .fingers = libinput_event_gesture_get_finger_count(gevent), }; - wlr_signal_emit_safe(&wlr_dev->pointer->events.pinch_begin, &wlr_event); + wl_signal_emit_mutable(&pointer->events.pinch_begin, &wlr_event); } void handle_pointer_pinch_update(struct libinput_event *event, - struct libinput_device *libinput_dev) { - struct wlr_input_device *wlr_dev = - get_appropriate_device(WLR_INPUT_DEVICE_POINTER, libinput_dev); - if (!wlr_dev) { - wlr_log(WLR_DEBUG, "Got a pointer gesture event for a device with no pointers?"); - return; - } + struct wlr_pointer *pointer) { struct libinput_event_gesture *gevent = libinput_event_get_gesture_event(event); - struct wlr_event_pointer_pinch_update wlr_event = { - .device = wlr_dev, + struct wlr_pointer_pinch_update_event wlr_event = { + .pointer = pointer, .time_msec = usec_to_msec(libinput_event_gesture_get_time_usec(gevent)), .fingers = libinput_event_gesture_get_finger_count(gevent), @@ -243,62 +231,44 @@ void handle_pointer_pinch_update(struct libinput_event *event, .scale = libinput_event_gesture_get_scale(gevent), .rotation = libinput_event_gesture_get_angle_delta(gevent), }; - wlr_signal_emit_safe(&wlr_dev->pointer->events.pinch_update, &wlr_event); + wl_signal_emit_mutable(&pointer->events.pinch_update, &wlr_event); } void handle_pointer_pinch_end(struct libinput_event *event, - struct libinput_device *libinput_dev) { - struct wlr_input_device *wlr_dev = - get_appropriate_device(WLR_INPUT_DEVICE_POINTER, libinput_dev); - if (!wlr_dev) { - wlr_log(WLR_DEBUG, "Got a pointer gesture event for a device with no pointers?"); - return; - } + struct wlr_pointer *pointer) { struct libinput_event_gesture *gevent = libinput_event_get_gesture_event(event); - struct wlr_event_pointer_pinch_end wlr_event = { - .device = wlr_dev, + struct wlr_pointer_pinch_end_event wlr_event = { + .pointer = pointer, .time_msec = usec_to_msec(libinput_event_gesture_get_time_usec(gevent)), .cancelled = libinput_event_gesture_get_cancelled(gevent), }; - wlr_signal_emit_safe(&wlr_dev->pointer->events.pinch_end, &wlr_event); + wl_signal_emit_mutable(&pointer->events.pinch_end, &wlr_event); } void handle_pointer_hold_begin(struct libinput_event *event, - struct libinput_device *libinput_dev) { - struct wlr_input_device *wlr_dev = - get_appropriate_device(WLR_INPUT_DEVICE_POINTER, libinput_dev); - if (!wlr_dev) { - wlr_log(WLR_DEBUG, "Got a pointer gesture event for a device with no pointers?"); - return; - } + struct wlr_pointer *pointer) { struct libinput_event_gesture *gevent = libinput_event_get_gesture_event(event); - struct wlr_event_pointer_hold_begin wlr_event = { - .device = wlr_dev, + struct wlr_pointer_hold_begin_event wlr_event = { + .pointer = pointer, .time_msec = usec_to_msec(libinput_event_gesture_get_time_usec(gevent)), .fingers = libinput_event_gesture_get_finger_count(gevent), }; - wlr_signal_emit_safe(&wlr_dev->pointer->events.hold_begin, &wlr_event); + wl_signal_emit_mutable(&pointer->events.hold_begin, &wlr_event); } void handle_pointer_hold_end(struct libinput_event *event, - struct libinput_device *libinput_dev) { - struct wlr_input_device *wlr_dev = - get_appropriate_device(WLR_INPUT_DEVICE_POINTER, libinput_dev); - if (!wlr_dev) { - wlr_log(WLR_DEBUG, "Got a pointer gesture event for a device with no pointers?"); - return; - } + struct wlr_pointer *pointer) { struct libinput_event_gesture *gevent = libinput_event_get_gesture_event(event); - struct wlr_event_pointer_hold_end wlr_event = { - .device = wlr_dev, + struct wlr_pointer_hold_end_event wlr_event = { + .pointer = pointer, .time_msec = usec_to_msec(libinput_event_gesture_get_time_usec(gevent)), .cancelled = libinput_event_gesture_get_cancelled(gevent), }; - wlr_signal_emit_safe(&wlr_dev->pointer->events.hold_end, &wlr_event); + wl_signal_emit_mutable(&pointer->events.hold_end, &wlr_event); } diff --git a/backend/libinput/switch.c b/backend/libinput/switch.c index 0e710f090..e8c68befa 100644 --- a/backend/libinput/switch.c +++ b/backend/libinput/switch.c @@ -1,43 +1,34 @@ #include #include -#include -#include #include -#include -#include #include "backend/libinput.h" -#include "util/signal.h" -const struct wlr_switch_impl libinput_switch_impl; +const struct wlr_switch_impl libinput_switch_impl = { + .name = "libinput-switch", +}; -struct wlr_switch *create_libinput_switch( - struct libinput_device *libinput_dev) { - assert(libinput_dev); - struct wlr_switch *wlr_switch = calloc(1, sizeof(struct wlr_switch)); - if (!wlr_switch) { - wlr_log(WLR_ERROR, "Unable to allocate wlr_switch"); - return NULL; - } - const char *name = libinput_device_get_name(libinput_dev); +void init_device_switch(struct wlr_libinput_input_device *dev) { + const char *name = libinput_device_get_name(dev->handle); + struct wlr_switch *wlr_switch = &dev->switch_device; wlr_switch_init(wlr_switch, &libinput_switch_impl, name); - wlr_log(WLR_DEBUG, "Created switch for device %s", name); - wlr_switch->base.vendor = libinput_device_get_id_vendor(libinput_dev); - wlr_switch->base.product = libinput_device_get_id_product(libinput_dev); - return wlr_switch; + wlr_switch->base.vendor = libinput_device_get_id_vendor(dev->handle); + wlr_switch->base.product = libinput_device_get_id_product(dev->handle); +} + +struct wlr_libinput_input_device *device_from_switch( + struct wlr_switch *wlr_switch) { + assert(wlr_switch->impl == &libinput_switch_impl); + + struct wlr_libinput_input_device *dev = + wl_container_of(wlr_switch, dev, switch_device); + return dev; } void handle_switch_toggle(struct libinput_event *event, - struct libinput_device *libinput_dev) { - struct wlr_input_device *wlr_dev = - get_appropriate_device(WLR_INPUT_DEVICE_SWITCH, libinput_dev); - if (!wlr_dev) { - wlr_log(WLR_DEBUG, "Got a switch event for a device with no switch?"); - return; - } + struct wlr_switch *wlr_switch) { struct libinput_event_switch *sevent = libinput_event_get_switch_event (event); - struct wlr_event_switch_toggle wlr_event = { 0 }; - wlr_event.device = wlr_dev; + struct wlr_switch_toggle_event wlr_event = { 0 }; switch (libinput_event_switch_get_switch(sevent)) { case LIBINPUT_SWITCH_LID: wlr_event.switch_type = WLR_SWITCH_TYPE_LID; @@ -56,5 +47,5 @@ void handle_switch_toggle(struct libinput_event *event, } wlr_event.time_msec = usec_to_msec(libinput_event_switch_get_time_usec(sevent)); - wlr_signal_emit_safe(&wlr_dev->switch_device->events.toggle, &wlr_event); + wl_signal_emit_mutable(&wlr_switch->events.toggle, &wlr_event); } diff --git a/backend/libinput/tablet_pad.c b/backend/libinput/tablet_pad.c index 50b8ad6e7..078f7ca12 100644 --- a/backend/libinput/tablet_pad.c +++ b/backend/libinput/tablet_pad.c @@ -1,18 +1,23 @@ -#ifndef _POSIX_C_SOURCE #define _POSIX_C_SOURCE 200809L -#endif #include #include #include #include -#include #include -#include #include #include "backend/libinput.h" -#include "util/signal.h" -// FIXME: Decide on how to alloc/count here +const struct wlr_tablet_pad_impl libinput_tablet_pad_impl = { + .name = "libinput-tablet-pad", +}; + +static void group_destroy(struct wlr_tablet_pad_group *group) { + free(group->buttons); + free(group->strips); + free(group->rings); + free(group); +} + static void add_pad_group_from_libinput(struct wlr_tablet_pad *pad, struct libinput_device *device, unsigned int index) { struct libinput_tablet_pad_mode_group *li_group = @@ -20,6 +25,7 @@ static void add_pad_group_from_libinput(struct wlr_tablet_pad *pad, struct wlr_tablet_pad_group *group = calloc(1, sizeof(struct wlr_tablet_pad_group)); if (!group) { + wlr_log_errno(WLR_ERROR, "failed to allocate wlr_tablet_pad_group"); return; } @@ -29,6 +35,10 @@ static void add_pad_group_from_libinput(struct wlr_tablet_pad *pad, } } group->rings = calloc(sizeof(unsigned int), group->ring_count); + if (group->rings == NULL) { + goto group_fail; + } + size_t ring = 0; for (size_t i = 0; i < pad->ring_count; ++i) { if (libinput_tablet_pad_mode_group_has_ring(li_group, i)) { @@ -42,6 +52,9 @@ static void add_pad_group_from_libinput(struct wlr_tablet_pad *pad, } } group->strips = calloc(sizeof(unsigned int), group->strip_count); + if (group->strips == NULL) { + goto group_fail; + } size_t strip = 0; for (size_t i = 0; i < pad->strip_count; ++i) { if (libinput_tablet_pad_mode_group_has_strip(li_group, i)) { @@ -55,6 +68,9 @@ static void add_pad_group_from_libinput(struct wlr_tablet_pad *pad, } } group->buttons = calloc(sizeof(unsigned int), group->button_count); + if (group->buttons == NULL) { + goto group_fail; + } size_t button = 0; for (size_t i = 0; i < pad->button_count; ++i) { if (libinput_tablet_pad_mode_group_has_button(li_group, i)) { @@ -63,56 +79,72 @@ static void add_pad_group_from_libinput(struct wlr_tablet_pad *pad, } group->mode_count = libinput_tablet_pad_mode_group_get_num_modes(li_group); + + libinput_tablet_pad_mode_group_ref(li_group); + wl_list_insert(&pad->groups, &group->link); + return; + +group_fail: + wlr_log(WLR_ERROR, "failed to configure wlr_tablet_pad_group"); + group_destroy(group); } -const struct wlr_tablet_pad_impl libinput_tablet_pad_impl; - -struct wlr_tablet_pad *create_libinput_tablet_pad( - struct libinput_device *libinput_dev) { - assert(libinput_dev); - struct wlr_tablet_pad *wlr_tablet_pad = - calloc(1, sizeof(struct wlr_tablet_pad)); - if (!wlr_tablet_pad) { - wlr_log(WLR_ERROR, "Unable to allocate wlr_tablet_pad"); - return NULL; - } - const char *name = libinput_device_get_name(libinput_dev); +void init_device_tablet_pad(struct wlr_libinput_input_device *dev) { + struct libinput_device *handle = dev->handle; + const char *name = libinput_device_get_name(handle); + struct wlr_tablet_pad *wlr_tablet_pad = &dev->tablet_pad; wlr_tablet_pad_init(wlr_tablet_pad, &libinput_tablet_pad_impl, name); - wlr_tablet_pad->base.vendor = libinput_device_get_id_vendor(libinput_dev); - wlr_tablet_pad->base.product = libinput_device_get_id_product(libinput_dev); + wlr_tablet_pad->base.vendor = libinput_device_get_id_vendor(handle); + wlr_tablet_pad->base.product = libinput_device_get_id_product(handle); wlr_tablet_pad->button_count = - libinput_device_tablet_pad_get_num_buttons(libinput_dev); + libinput_device_tablet_pad_get_num_buttons(handle); wlr_tablet_pad->ring_count = - libinput_device_tablet_pad_get_num_rings(libinput_dev); + libinput_device_tablet_pad_get_num_rings(handle); wlr_tablet_pad->strip_count = - libinput_device_tablet_pad_get_num_strips(libinput_dev); + libinput_device_tablet_pad_get_num_strips(handle); - struct udev_device *udev = libinput_device_get_udev_device(libinput_dev); + struct udev_device *udev = libinput_device_get_udev_device(handle); char **dst = wl_array_add(&wlr_tablet_pad->paths, sizeof(char *)); *dst = strdup(udev_device_get_syspath(udev)); - int groups = libinput_device_tablet_pad_get_num_mode_groups(libinput_dev); + int groups = libinput_device_tablet_pad_get_num_mode_groups(handle); for (int i = 0; i < groups; ++i) { - add_pad_group_from_libinput(wlr_tablet_pad, libinput_dev, i); + add_pad_group_from_libinput(wlr_tablet_pad, handle, i); + } +} + +void finish_device_tablet_pad(struct wlr_libinput_input_device *dev) { + struct wlr_tablet_pad_group *group, *tmp; + wl_list_for_each_safe(group, tmp, &dev->tablet_pad.groups, link) { + group_destroy(group); } - return wlr_tablet_pad; + wlr_tablet_pad_finish(&dev->tablet_pad); + + int groups = libinput_device_tablet_pad_get_num_mode_groups(dev->handle); + for (int i = 0; i < groups; ++i) { + struct libinput_tablet_pad_mode_group *li_group = + libinput_device_tablet_pad_get_mode_group(dev->handle, i); + libinput_tablet_pad_mode_group_unref(li_group); + } +} + +struct wlr_libinput_input_device *device_from_tablet_pad( + struct wlr_tablet_pad *wlr_tablet_pad) { + assert(wlr_tablet_pad->impl == &libinput_tablet_pad_impl); + + struct wlr_libinput_input_device *dev = + wl_container_of(wlr_tablet_pad, dev, tablet_pad); + return dev; } void handle_tablet_pad_button(struct libinput_event *event, - struct libinput_device *libinput_dev) { - struct wlr_input_device *wlr_dev = - get_appropriate_device(WLR_INPUT_DEVICE_TABLET_PAD, libinput_dev); - if (!wlr_dev) { - wlr_log(WLR_DEBUG, - "Got a tablet pad event for a device with no tablet pad?"); - return; - } + struct wlr_tablet_pad *tablet_pad) { struct libinput_event_tablet_pad *pevent = libinput_event_get_tablet_pad_event(event); - struct wlr_event_tablet_pad_button wlr_event = { 0 }; + struct wlr_tablet_pad_button_event wlr_event = { 0 }; wlr_event.time_msec = usec_to_msec(libinput_event_tablet_pad_get_time_usec(pevent)); wlr_event.button = libinput_event_tablet_pad_get_button_number(pevent); @@ -127,21 +159,14 @@ void handle_tablet_pad_button(struct libinput_event *event, wlr_event.state = WLR_BUTTON_RELEASED; break; } - wlr_signal_emit_safe(&wlr_dev->tablet_pad->events.button, &wlr_event); + wl_signal_emit_mutable(&tablet_pad->events.button, &wlr_event); } void handle_tablet_pad_ring(struct libinput_event *event, - struct libinput_device *libinput_dev) { - struct wlr_input_device *wlr_dev = - get_appropriate_device(WLR_INPUT_DEVICE_TABLET_PAD, libinput_dev); - if (!wlr_dev) { - wlr_log(WLR_DEBUG, - "Got a tablet pad event for a device with no tablet pad?"); - return; - } + struct wlr_tablet_pad *tablet_pad) { struct libinput_event_tablet_pad *pevent = libinput_event_get_tablet_pad_event(event); - struct wlr_event_tablet_pad_ring wlr_event = { 0 }; + struct wlr_tablet_pad_ring_event wlr_event = { 0 }; wlr_event.time_msec = usec_to_msec(libinput_event_tablet_pad_get_time_usec(pevent)); wlr_event.ring = libinput_event_tablet_pad_get_ring_number(pevent); @@ -155,21 +180,14 @@ void handle_tablet_pad_ring(struct libinput_event *event, wlr_event.source = WLR_TABLET_PAD_RING_SOURCE_FINGER; break; } - wlr_signal_emit_safe(&wlr_dev->tablet_pad->events.ring, &wlr_event); + wl_signal_emit_mutable(&tablet_pad->events.ring, &wlr_event); } void handle_tablet_pad_strip(struct libinput_event *event, - struct libinput_device *libinput_dev) { - struct wlr_input_device *wlr_dev = - get_appropriate_device(WLR_INPUT_DEVICE_TABLET_PAD, libinput_dev); - if (!wlr_dev) { - wlr_log(WLR_DEBUG, - "Got a tablet pad event for a device with no tablet pad?"); - return; - } + struct wlr_tablet_pad *tablet_pad) { struct libinput_event_tablet_pad *pevent = libinput_event_get_tablet_pad_event(event); - struct wlr_event_tablet_pad_strip wlr_event = { 0 }; + struct wlr_tablet_pad_strip_event wlr_event = { 0 }; wlr_event.time_msec = usec_to_msec(libinput_event_tablet_pad_get_time_usec(pevent)); wlr_event.strip = libinput_event_tablet_pad_get_strip_number(pevent); @@ -183,5 +201,5 @@ void handle_tablet_pad_strip(struct libinput_event *event, wlr_event.source = WLR_TABLET_PAD_STRIP_SOURCE_FINGER; break; } - wlr_signal_emit_safe(&wlr_dev->tablet_pad->events.strip, &wlr_event); + wl_signal_emit_mutable(&tablet_pad->events.strip, &wlr_event); } diff --git a/backend/libinput/tablet_tool.c b/backend/libinput/tablet_tool.c index 373f87d7b..d049d16ee 100644 --- a/backend/libinput/tablet_tool.c +++ b/backend/libinput/tablet_tool.c @@ -1,92 +1,63 @@ -#ifndef _POSIX_C_SOURCE #define _POSIX_C_SOURCE 200809L -#endif #include #include #include #include -#include -#include #include -#include #include #include "backend/libinput.h" -#include "util/array.h" -#include "util/signal.h" -static bool tablet_is_libinput(struct wlr_tablet *tablet) { - return tablet->impl == &libinput_tablet_impl; -} - -struct wlr_libinput_tablet_tool { +struct tablet_tool { struct wlr_tablet_tool wlr_tool; - - struct libinput_tablet_tool *libinput_tool; - - bool unique; - // Refcount for destroy + release - size_t pad_refs; + struct libinput_tablet_tool *handle; + struct wl_list link; // wlr_libinput_input_device::tablet_tools }; -struct wlr_libinput_tablet { - struct wlr_tablet wlr_tablet; - struct wl_array tools; // struct wlr_libinput_tablet_tool * -}; - -static void destroy_tool(struct wlr_libinput_tablet_tool *tool) { - wlr_signal_emit_safe(&tool->wlr_tool.events.destroy, &tool->wlr_tool); - libinput_tablet_tool_ref(tool->libinput_tool); - libinput_tablet_tool_set_user_data(tool->libinput_tool, NULL); - free(tool); -} - -static void destroy_tablet(struct wlr_tablet *wlr_tablet) { - assert(tablet_is_libinput(wlr_tablet)); - struct wlr_libinput_tablet *tablet = - wl_container_of(wlr_tablet, tablet, wlr_tablet); - - struct wlr_libinput_tablet_tool **tool_ptr; - wl_array_for_each(tool_ptr, &tablet->tools) { - struct wlr_libinput_tablet_tool *tool = *tool_ptr; - if (--tool->pad_refs == 0) { - destroy_tool(tool); - } - } - wl_array_release(&tablet->tools); - - free(tablet); -} - const struct wlr_tablet_impl libinput_tablet_impl = { - .destroy = destroy_tablet, + .name = "libinput-tablet-tool", }; -struct wlr_tablet *create_libinput_tablet( - struct libinput_device *libinput_dev) { - assert(libinput_dev); - struct wlr_libinput_tablet *libinput_tablet = - calloc(1, sizeof(struct wlr_libinput_tablet)); - if (!libinput_tablet) { - wlr_log(WLR_ERROR, "Unable to allocate wlr_tablet_tool"); - return NULL; - } - - struct wlr_tablet *wlr_tablet = &libinput_tablet->wlr_tablet; - const char *name = libinput_device_get_name(libinput_dev); - +void init_device_tablet(struct wlr_libinput_input_device *dev) { + const char *name = libinput_device_get_name(dev->handle); + struct wlr_tablet *wlr_tablet = &dev->tablet; wlr_tablet_init(wlr_tablet, &libinput_tablet_impl, name); - wlr_tablet->base.vendor = libinput_device_get_id_vendor(libinput_dev); - wlr_tablet->base.product = libinput_device_get_id_product(libinput_dev); + wlr_tablet->base.vendor = libinput_device_get_id_vendor(dev->handle); + wlr_tablet->base.product = libinput_device_get_id_product(dev->handle); - struct udev_device *udev = libinput_device_get_udev_device(libinput_dev); + libinput_device_get_size(dev->handle, &wlr_tablet->width_mm, + &wlr_tablet->height_mm); + + struct udev_device *udev = libinput_device_get_udev_device(dev->handle); char **dst = wl_array_add(&wlr_tablet->paths, sizeof(char *)); *dst = strdup(udev_device_get_syspath(udev)); - wlr_tablet->name = strdup(libinput_device_get_name(libinput_dev)); + wl_list_init(&dev->tablet_tools); +} - wl_array_init(&libinput_tablet->tools); +static void tool_destroy(struct tablet_tool *tool) { + wl_signal_emit_mutable(&tool->wlr_tool.events.destroy, &tool->wlr_tool); + libinput_tablet_tool_unref(tool->handle); + libinput_tablet_tool_set_user_data(tool->handle, NULL); + wl_list_remove(&tool->link); + free(tool); +} - return wlr_tablet; +void finish_device_tablet(struct wlr_libinput_input_device *dev) { + struct tablet_tool *tool, *tmp; + wl_list_for_each_safe(tool, tmp, &dev->tablet_tools, link) { + tool_destroy(tool); + } + + wlr_tablet_finish(&dev->tablet); +} + +struct wlr_libinput_input_device *device_from_tablet( + struct wlr_tablet *wlr_tablet) { + assert(wlr_tablet->impl == &libinput_tablet_impl); + + struct wlr_libinput_input_device *dev = + wl_container_of(wlr_tablet, dev, tablet); + return dev; } static enum wlr_tablet_tool_type wlr_type_from_libinput_type( @@ -112,87 +83,54 @@ static enum wlr_tablet_tool_type wlr_type_from_libinput_type( abort(); // unreachable } -static struct wlr_libinput_tablet_tool *get_wlr_tablet_tool( - struct libinput_tablet_tool *tool) { - struct wlr_libinput_tablet_tool *ret = - libinput_tablet_tool_get_user_data(tool); - - if (ret) { - return ret; +static struct tablet_tool *get_tablet_tool( + struct wlr_libinput_input_device *dev, + struct libinput_tablet_tool *libinput_tool) { + struct tablet_tool *tool = + libinput_tablet_tool_get_user_data(libinput_tool); + if (tool) { + return tool; } - ret = calloc(1, sizeof(struct wlr_libinput_tablet_tool)); - if (!ret) { + tool = calloc(1, sizeof(struct tablet_tool)); + if (tool == NULL) { + wlr_log_errno(WLR_ERROR, "failed to allocate wlr_libinput_tablet_tool"); return NULL; } - ret->libinput_tool = libinput_tablet_tool_ref(tool); - ret->wlr_tool.pressure = libinput_tablet_tool_has_pressure(tool); - ret->wlr_tool.distance = libinput_tablet_tool_has_distance(tool); - ret->wlr_tool.tilt = libinput_tablet_tool_has_tilt(tool); - ret->wlr_tool.rotation = libinput_tablet_tool_has_rotation(tool); - ret->wlr_tool.slider = libinput_tablet_tool_has_slider(tool); - ret->wlr_tool.wheel = libinput_tablet_tool_has_wheel(tool); + tool->wlr_tool.type = wlr_type_from_libinput_type( + libinput_tablet_tool_get_type(libinput_tool)); + tool->wlr_tool.hardware_serial = + libinput_tablet_tool_get_serial(libinput_tool); + tool->wlr_tool.hardware_wacom = + libinput_tablet_tool_get_tool_id(libinput_tool); - ret->wlr_tool.hardware_serial = libinput_tablet_tool_get_serial(tool); - ret->wlr_tool.hardware_wacom = libinput_tablet_tool_get_tool_id(tool); - ret->wlr_tool.type = wlr_type_from_libinput_type( - libinput_tablet_tool_get_type(tool)); + tool->wlr_tool.pressure = libinput_tablet_tool_has_pressure(libinput_tool); + tool->wlr_tool.distance = libinput_tablet_tool_has_distance(libinput_tool); + tool->wlr_tool.tilt = libinput_tablet_tool_has_tilt(libinput_tool); + tool->wlr_tool.rotation = libinput_tablet_tool_has_rotation(libinput_tool); + tool->wlr_tool.slider = libinput_tablet_tool_has_slider(libinput_tool); + tool->wlr_tool.wheel = libinput_tablet_tool_has_wheel(libinput_tool); - ret->unique = libinput_tablet_tool_is_unique(tool); + wl_signal_init(&tool->wlr_tool.events.destroy); - wl_signal_init(&ret->wlr_tool.events.destroy); + tool->handle = libinput_tablet_tool_ref(libinput_tool); + libinput_tablet_tool_set_user_data(libinput_tool, tool); - libinput_tablet_tool_set_user_data(tool, ret); - return ret; -} - -static void ensure_tool_reference(struct wlr_libinput_tablet_tool *tool, - struct wlr_tablet *wlr_dev) { - assert(tablet_is_libinput(wlr_dev)); - struct wlr_libinput_tablet *tablet = - wl_container_of(wlr_dev, tablet, wlr_tablet); - - struct wlr_libinput_tablet_tool **tool_ptr; - wl_array_for_each(tool_ptr, &tablet->tools) { - if (*tool_ptr == tool) { // We already have a ref - // XXX: We *could* optimize the tool to the front of - // the list here, since we will probably get the next - // couple of events from the same tool. - // BUT the list should always be rather short (probably - // single digit amount of tools) so it might be more - // work than it saves - return; - } - } - - struct wlr_libinput_tablet_tool **dst = - wl_array_add(&tablet->tools, sizeof(tool)); - if (!dst) { - wlr_log(WLR_ERROR, "Failed to allocate memory for tracking tablet tool"); - return; - } - *dst = tool; - ++tool->pad_refs; + wl_list_insert(&dev->tablet_tools, &tool->link); + return tool; } void handle_tablet_tool_axis(struct libinput_event *event, - struct libinput_device *libinput_dev) { - struct wlr_input_device *wlr_dev = - get_appropriate_device(WLR_INPUT_DEVICE_TABLET_TOOL, libinput_dev); - if (!wlr_dev) { - wlr_log(WLR_DEBUG, - "Got a tablet tool event for a device with no tablet tools?"); - return; - } + struct wlr_tablet *wlr_tablet) { struct libinput_event_tablet_tool *tevent = libinput_event_get_tablet_tool_event(event); - struct wlr_event_tablet_tool_axis wlr_event = { 0 }; - struct wlr_libinput_tablet_tool *tool = get_wlr_tablet_tool( - libinput_event_tablet_tool_get_tool(tevent)); - ensure_tool_reference(tool, wlr_dev->tablet); + struct wlr_libinput_input_device *dev = device_from_tablet(wlr_tablet); + struct tablet_tool *tool = + get_tablet_tool(dev, libinput_event_tablet_tool_get_tool(tevent)); - wlr_event.device = wlr_dev; + struct wlr_tablet_tool_axis_event wlr_event = { 0 }; + wlr_event.tablet = wlr_tablet; wlr_event.tool = &tool->wlr_tool; wlr_event.time_msec = usec_to_msec(libinput_event_tablet_tool_get_time_usec(tevent)); @@ -234,27 +172,20 @@ void handle_tablet_tool_axis(struct libinput_event *event, wlr_event.updated_axes |= WLR_TABLET_TOOL_AXIS_WHEEL; wlr_event.wheel_delta = libinput_event_tablet_tool_get_wheel_delta(tevent); } - wlr_signal_emit_safe(&wlr_dev->tablet->events.axis, &wlr_event); + wl_signal_emit_mutable(&wlr_tablet->events.axis, &wlr_event); } void handle_tablet_tool_proximity(struct libinput_event *event, - struct libinput_device *libinput_dev) { - struct wlr_input_device *wlr_dev = - get_appropriate_device(WLR_INPUT_DEVICE_TABLET_TOOL, libinput_dev); - if (!wlr_dev) { - wlr_log(WLR_DEBUG, - "Got a tablet tool event for a device with no tablet tools?"); - return; - } + struct wlr_tablet *wlr_tablet) { struct libinput_event_tablet_tool *tevent = libinput_event_get_tablet_tool_event(event); - struct wlr_event_tablet_tool_proximity wlr_event = { 0 }; - struct wlr_libinput_tablet_tool *tool = get_wlr_tablet_tool( - libinput_event_tablet_tool_get_tool(tevent)); - ensure_tool_reference(tool, wlr_dev->tablet); + struct wlr_libinput_input_device *dev = device_from_tablet(wlr_tablet); + struct tablet_tool *tool = + get_tablet_tool(dev, libinput_event_tablet_tool_get_tool(tevent)); + struct wlr_tablet_tool_proximity_event wlr_event = { 0 }; + wlr_event.tablet = wlr_tablet; wlr_event.tool = &tool->wlr_tool; - wlr_event.device = wlr_dev; wlr_event.time_msec = usec_to_msec(libinput_event_tablet_tool_get_time_usec(tevent)); wlr_event.x = libinput_event_tablet_tool_get_x_transformed(tevent, 1); @@ -268,56 +199,34 @@ void handle_tablet_tool_proximity(struct libinput_event *event, wlr_event.state = WLR_TABLET_TOOL_PROXIMITY_IN; break; } - wlr_signal_emit_safe(&wlr_dev->tablet->events.proximity, &wlr_event); + wl_signal_emit_mutable(&wlr_tablet->events.proximity, &wlr_event); if (libinput_event_tablet_tool_get_proximity_state(tevent) == LIBINPUT_TABLET_TOOL_PROXIMITY_STATE_IN) { - handle_tablet_tool_axis(event, libinput_dev); + handle_tablet_tool_axis(event, wlr_tablet); } // If the tool is not unique, libinput will not find it again after the // proximity out, so we should destroy it - if (!tool->unique && - libinput_event_tablet_tool_get_proximity_state(tevent) == + if (!libinput_tablet_tool_is_unique(tool->handle) + && libinput_event_tablet_tool_get_proximity_state(tevent) == LIBINPUT_TABLET_TOOL_PROXIMITY_STATE_OUT) { // The tool isn't unique, it can't be on multiple tablets - assert(tool->pad_refs == 1); - assert(tablet_is_libinput(wlr_dev->tablet)); - struct wlr_libinput_tablet *tablet = - wl_container_of(wlr_dev->tablet, tablet, wlr_tablet); - - size_t i = 0; - struct wlr_libinput_tablet_tool **tool_ptr; - wl_array_for_each(tool_ptr, &tablet->tools) { - if (*tool_ptr == tool) { - array_remove_at(&tablet->tools, i * sizeof(tool), sizeof(tool)); - break; - } - i++; - } - - destroy_tool(tool); + tool_destroy(tool); } } void handle_tablet_tool_tip(struct libinput_event *event, - struct libinput_device *libinput_dev) { - struct wlr_input_device *wlr_dev = - get_appropriate_device(WLR_INPUT_DEVICE_TABLET_TOOL, libinput_dev); - if (!wlr_dev) { - wlr_log(WLR_DEBUG, - "Got a tablet tool event for a device with no tablet tools?"); - return; - } - handle_tablet_tool_axis(event, libinput_dev); + struct wlr_tablet *wlr_tablet) { + handle_tablet_tool_axis(event, wlr_tablet); struct libinput_event_tablet_tool *tevent = libinput_event_get_tablet_tool_event(event); - struct wlr_event_tablet_tool_tip wlr_event = { 0 }; - struct wlr_libinput_tablet_tool *tool = get_wlr_tablet_tool( - libinput_event_tablet_tool_get_tool(tevent)); - ensure_tool_reference(tool, wlr_dev->tablet); + struct wlr_libinput_input_device *dev = device_from_tablet(wlr_tablet); + struct tablet_tool *tool = + get_tablet_tool(dev, libinput_event_tablet_tool_get_tool(tevent)); - wlr_event.device = wlr_dev; + struct wlr_tablet_tool_tip_event wlr_event = { 0 }; + wlr_event.tablet = wlr_tablet; wlr_event.tool = &tool->wlr_tool; wlr_event.time_msec = usec_to_msec(libinput_event_tablet_tool_get_time_usec(tevent)); @@ -332,27 +241,20 @@ void handle_tablet_tool_tip(struct libinput_event *event, wlr_event.state = WLR_TABLET_TOOL_TIP_DOWN; break; } - wlr_signal_emit_safe(&wlr_dev->tablet->events.tip, &wlr_event); + wl_signal_emit_mutable(&wlr_tablet->events.tip, &wlr_event); } void handle_tablet_tool_button(struct libinput_event *event, - struct libinput_device *libinput_dev) { - struct wlr_input_device *wlr_dev = - get_appropriate_device(WLR_INPUT_DEVICE_TABLET_TOOL, libinput_dev); - if (!wlr_dev) { - wlr_log(WLR_DEBUG, - "Got a tablet tool event for a device with no tablet tools?"); - return; - } - handle_tablet_tool_axis(event, libinput_dev); + struct wlr_tablet *wlr_tablet) { + handle_tablet_tool_axis(event, wlr_tablet); struct libinput_event_tablet_tool *tevent = libinput_event_get_tablet_tool_event(event); - struct wlr_event_tablet_tool_button wlr_event = { 0 }; - struct wlr_libinput_tablet_tool *tool = get_wlr_tablet_tool( - libinput_event_tablet_tool_get_tool(tevent)); - ensure_tool_reference(tool, wlr_dev->tablet); + struct wlr_libinput_input_device *dev = device_from_tablet(wlr_tablet); + struct tablet_tool *tool = + get_tablet_tool(dev, libinput_event_tablet_tool_get_tool(tevent)); - wlr_event.device = wlr_dev; + struct wlr_tablet_tool_button_event wlr_event = { 0 }; + wlr_event.tablet = wlr_tablet; wlr_event.tool = &tool->wlr_tool; wlr_event.time_msec = usec_to_msec(libinput_event_tablet_tool_get_time_usec(tevent)); @@ -365,5 +267,5 @@ void handle_tablet_tool_button(struct libinput_event *event, wlr_event.state = WLR_BUTTON_PRESSED; break; } - wlr_signal_emit_safe(&wlr_dev->tablet->events.button, &wlr_event); + wl_signal_emit_mutable(&wlr_tablet->events.button, &wlr_event); } diff --git a/backend/libinput/touch.c b/backend/libinput/touch.c index 2e22a97a3..3316754ef 100644 --- a/backend/libinput/touch.c +++ b/backend/libinput/touch.c @@ -1,113 +1,85 @@ #include #include -#include -#include #include -#include -#include #include "backend/libinput.h" -#include "util/signal.h" -const struct wlr_touch_impl libinput_touch_impl; +const struct wlr_touch_impl libinput_touch_impl = { + .name = "libinput-touch", +}; -struct wlr_touch *create_libinput_touch( - struct libinput_device *libinput_dev) { - assert(libinput_dev); - struct wlr_touch *wlr_touch = calloc(1, sizeof(struct wlr_touch)); - if (!wlr_touch) { - wlr_log(WLR_ERROR, "Unable to allocate wlr_touch"); - return NULL; - } - const char *name = libinput_device_get_name(libinput_dev); +void init_device_touch(struct wlr_libinput_input_device *dev) { + const char *name = libinput_device_get_name(dev->handle); + struct wlr_touch *wlr_touch = &dev->touch; wlr_touch_init(wlr_touch, &libinput_touch_impl, name); - wlr_touch->base.vendor = libinput_device_get_id_vendor(libinput_dev); - wlr_touch->base.product = libinput_device_get_id_product(libinput_dev); - return wlr_touch; + wlr_touch->base.vendor = libinput_device_get_id_vendor(dev->handle); + wlr_touch->base.product = libinput_device_get_id_product(dev->handle); + + libinput_device_get_size(dev->handle, &wlr_touch->width_mm, + &wlr_touch->height_mm); +} + +struct wlr_libinput_input_device *device_from_touch( + struct wlr_touch *wlr_touch) { + assert(wlr_touch->impl == &libinput_touch_impl); + + struct wlr_libinput_input_device *dev = + wl_container_of(wlr_touch, dev, touch); + return dev; } void handle_touch_down(struct libinput_event *event, - struct libinput_device *libinput_dev) { - struct wlr_input_device *wlr_dev = - get_appropriate_device(WLR_INPUT_DEVICE_TOUCH, libinput_dev); - if (!wlr_dev) { - wlr_log(WLR_DEBUG, "Got a touch event for a device with no touch?"); - return; - } + struct wlr_touch *touch) { struct libinput_event_touch *tevent = libinput_event_get_touch_event(event); - struct wlr_event_touch_down wlr_event = { 0 }; - wlr_event.device = wlr_dev; + struct wlr_touch_down_event wlr_event = { 0 }; + wlr_event.touch = touch; wlr_event.time_msec = usec_to_msec(libinput_event_touch_get_time_usec(tevent)); wlr_event.touch_id = libinput_event_touch_get_seat_slot(tevent); wlr_event.x = libinput_event_touch_get_x_transformed(tevent, 1); wlr_event.y = libinput_event_touch_get_y_transformed(tevent, 1); - wlr_signal_emit_safe(&wlr_dev->touch->events.down, &wlr_event); + wl_signal_emit_mutable(&touch->events.down, &wlr_event); } void handle_touch_up(struct libinput_event *event, - struct libinput_device *libinput_dev) { - struct wlr_input_device *wlr_dev = - get_appropriate_device(WLR_INPUT_DEVICE_TOUCH, libinput_dev); - if (!wlr_dev) { - wlr_log(WLR_DEBUG, "Got a touch event for a device with no touch?"); - return; - } + struct wlr_touch *touch) { struct libinput_event_touch *tevent = libinput_event_get_touch_event(event); - struct wlr_event_touch_up wlr_event = { 0 }; - wlr_event.device = wlr_dev; + struct wlr_touch_up_event wlr_event = { 0 }; + wlr_event.touch = touch; wlr_event.time_msec = usec_to_msec(libinput_event_touch_get_time_usec(tevent)); wlr_event.touch_id = libinput_event_touch_get_seat_slot(tevent); - wlr_signal_emit_safe(&wlr_dev->touch->events.up, &wlr_event); + wl_signal_emit_mutable(&touch->events.up, &wlr_event); } void handle_touch_motion(struct libinput_event *event, - struct libinput_device *libinput_dev) { - struct wlr_input_device *wlr_dev = - get_appropriate_device(WLR_INPUT_DEVICE_TOUCH, libinput_dev); - if (!wlr_dev) { - wlr_log(WLR_DEBUG, "Got a touch event for a device with no touch?"); - return; - } + struct wlr_touch *touch) { struct libinput_event_touch *tevent = libinput_event_get_touch_event(event); - struct wlr_event_touch_motion wlr_event = { 0 }; - wlr_event.device = wlr_dev; + struct wlr_touch_motion_event wlr_event = { 0 }; + wlr_event.touch = touch; wlr_event.time_msec = usec_to_msec(libinput_event_touch_get_time_usec(tevent)); wlr_event.touch_id = libinput_event_touch_get_seat_slot(tevent); wlr_event.x = libinput_event_touch_get_x_transformed(tevent, 1); wlr_event.y = libinput_event_touch_get_y_transformed(tevent, 1); - wlr_signal_emit_safe(&wlr_dev->touch->events.motion, &wlr_event); + wl_signal_emit_mutable(&touch->events.motion, &wlr_event); } void handle_touch_cancel(struct libinput_event *event, - struct libinput_device *libinput_dev) { - struct wlr_input_device *wlr_dev = - get_appropriate_device(WLR_INPUT_DEVICE_TOUCH, libinput_dev); - if (!wlr_dev) { - wlr_log(WLR_DEBUG, "Got a touch event for a device with no touch?"); - return; - } + struct wlr_touch *touch) { struct libinput_event_touch *tevent = libinput_event_get_touch_event(event); - struct wlr_event_touch_cancel wlr_event = { 0 }; - wlr_event.device = wlr_dev; + struct wlr_touch_cancel_event wlr_event = { 0 }; + wlr_event.touch = touch; wlr_event.time_msec = usec_to_msec(libinput_event_touch_get_time_usec(tevent)); wlr_event.touch_id = libinput_event_touch_get_seat_slot(tevent); - wlr_signal_emit_safe(&wlr_dev->touch->events.cancel, &wlr_event); + wl_signal_emit_mutable(&touch->events.cancel, &wlr_event); } void handle_touch_frame(struct libinput_event *event, - struct libinput_device *libinput_dev) { - struct wlr_input_device *wlr_dev = - get_appropriate_device(WLR_INPUT_DEVICE_TOUCH, libinput_dev); - if (!wlr_dev) { - wlr_log(WLR_DEBUG, "Got a touch event for a device with no touch?"); - return; - } - wlr_signal_emit_safe(&wlr_dev->touch->events.frame, NULL); + struct wlr_touch *touch) { + wl_signal_emit_mutable(&touch->events.frame, NULL); } diff --git a/backend/multi/backend.c b/backend/multi/backend.c index b06bc4865..f392db318 100644 --- a/backend/multi/backend.c +++ b/backend/multi/backend.c @@ -9,7 +9,6 @@ #include #include "backend/backend.h" #include "backend/multi.h" -#include "util/signal.h" struct subbackend_state { struct wlr_backend *backend; @@ -161,13 +160,13 @@ bool wlr_backend_is_multi(struct wlr_backend *b) { static void new_input_reemit(struct wl_listener *listener, void *data) { struct subbackend_state *state = wl_container_of(listener, state, new_input); - wlr_signal_emit_safe(&state->container->events.new_input, data); + wl_signal_emit_mutable(&state->container->events.new_input, data); } static void new_output_reemit(struct wl_listener *listener, void *data) { struct subbackend_state *state = wl_container_of(listener, state, new_output); - wlr_signal_emit_safe(&state->container->events.new_output, data); + wl_signal_emit_mutable(&state->container->events.new_output, data); } static void handle_subbackend_destroy(struct wl_listener *listener, @@ -218,7 +217,7 @@ bool wlr_multi_backend_add(struct wlr_backend *_multi, wl_signal_add(&backend->events.new_output, &sub->new_output); sub->new_output.notify = new_output_reemit; - wlr_signal_emit_safe(&multi->events.backend_add, backend); + wl_signal_emit_mutable(&multi->events.backend_add, backend); return true; } @@ -230,7 +229,7 @@ void wlr_multi_backend_remove(struct wlr_backend *_multi, multi_backend_get_subbackend(multi, backend); if (sub) { - wlr_signal_emit_safe(&multi->events.backend_remove, backend); + wl_signal_emit_mutable(&multi->events.backend_remove, backend); subbackend_state_destroy(sub); } } diff --git a/backend/session/session.c b/backend/session/session.c index 7d6d080da..fcd25fec1 100644 --- a/backend/session/session.c +++ b/backend/session/session.c @@ -17,7 +17,6 @@ #include #include #include "backend/session/session.h" -#include "util/signal.h" #include @@ -26,13 +25,13 @@ static void handle_enable_seat(struct libseat *seat, void *data) { struct wlr_session *session = data; session->active = true; - wlr_signal_emit_safe(&session->events.active, NULL); + wl_signal_emit_mutable(&session->events.active, NULL); } static void handle_disable_seat(struct libseat *seat, void *data) { struct wlr_session *session = data; session->active = false; - wlr_signal_emit_safe(&session->events.active, NULL); + wl_signal_emit_mutable(&session->events.active, NULL); libseat_disable_seat(session->seat_handle); } @@ -198,7 +197,7 @@ static int handle_udev_event(int fd, uint32_t mask, void *data) { struct wlr_session_add_event event = { .path = devnode, }; - wlr_signal_emit_safe(&session->events.add_drm_card, &event); + wl_signal_emit_mutable(&session->events.add_drm_card, &event); } else if (strcmp(action, "change") == 0 || strcmp(action, "remove") == 0) { dev_t devnum = udev_device_get_devnum(udev_dev); struct wlr_device *dev; @@ -211,10 +210,10 @@ static int handle_udev_event(int fd, uint32_t mask, void *data) { wlr_log(WLR_DEBUG, "DRM device %s changed", sysname); struct wlr_device_change_event event = {0}; read_udev_change_event(&event, udev_dev); - wlr_signal_emit_safe(&dev->events.change, &event); + wl_signal_emit_mutable(&dev->events.change, &event); } else if (strcmp(action, "remove") == 0) { wlr_log(WLR_DEBUG, "DRM device %s removed", sysname); - wlr_signal_emit_safe(&dev->events.remove, NULL); + wl_signal_emit_mutable(&dev->events.remove, NULL); } else { assert(0); } @@ -298,7 +297,7 @@ void wlr_session_destroy(struct wlr_session *session) { return; } - wlr_signal_emit_safe(&session->events.destroy, session); + wl_signal_emit_mutable(&session->events.destroy, session); wl_list_remove(&session->display_destroy.link); wl_event_source_remove(session->udev_event); diff --git a/backend/wayland/backend.c b/backend/wayland/backend.c index c0e99a228..9cf4ed5ed 100644 --- a/backend/wayland/backend.c +++ b/backend/wayland/backend.c @@ -19,7 +19,6 @@ #include "backend/wayland.h" #include "render/drm_format_set.h" #include "render/pixel_format.h" -#include "util/signal.h" #include "drm-client-protocol.h" #include "linux-dmabuf-unstable-v1-client-protocol.h" @@ -346,8 +345,15 @@ static void registry_global(void *data, struct wl_registry *registry, wl->compositor = wl_registry_bind(registry, name, &wl_compositor_interface, 4); } else if (strcmp(iface, wl_seat_interface.name) == 0) { + uint32_t target_version = version; + if (version < 5) { + target_version = 5; + } + if (version > 8) { + target_version = 8; + } struct wl_seat *wl_seat = wl_registry_bind(registry, name, - &wl_seat_interface, 5); + &wl_seat_interface, target_version); if (!create_wl_seat(wl_seat, wl)) { wl_seat_destroy(wl_seat); } @@ -413,12 +419,16 @@ static bool backend_start(struct wlr_backend *backend) { struct wlr_wl_seat *seat; wl_list_for_each(seat, &wl->seats, link) { - if (seat->keyboard) { - create_wl_keyboard(seat); + if (seat->wl_keyboard) { + init_seat_keyboard(seat); + } + + if (seat->wl_touch) { + init_seat_touch(seat); } if (wl->tablet_manager) { - wl_add_tablet_seat(wl->tablet_manager, seat); + init_seat_tablet(seat); } } @@ -441,11 +451,6 @@ static void backend_destroy(struct wlr_backend *backend) { wlr_output_destroy(&output->wlr_output); } - struct wlr_wl_input_device *input_device, *tmp_input_device; - wl_list_for_each_safe(input_device, tmp_input_device, &wl->devices, link) { - destroy_wl_input_device(input_device); - } - struct wlr_wl_buffer *buffer, *tmp_buffer; wl_list_for_each_safe(buffer, tmp_buffer, &wl->buffers, link) { destroy_wl_buffer(buffer); @@ -538,7 +543,6 @@ struct wlr_backend *wlr_wl_backend_create(struct wl_display *display, wlr_backend_init(&wl->backend, &backend_impl); wl->local_display = display; - wl_list_init(&wl->devices); wl_list_init(&wl->outputs); wl_list_init(&wl->seats); wl_list_init(&wl->buffers); diff --git a/backend/wayland/meson.build b/backend/wayland/meson.build index 1831bbb30..a8e310f3f 100644 --- a/backend/wayland/meson.build +++ b/backend/wayland/meson.build @@ -8,6 +8,7 @@ wlr_files += files( 'backend.c', 'output.c', 'seat.c', + 'pointer.c', 'tablet_v2.c', ) diff --git a/backend/wayland/output.c b/backend/wayland/output.c index de5d42edd..28fa5e99d 100644 --- a/backend/wayland/output.c +++ b/backend/wayland/output.c @@ -19,7 +19,6 @@ #include "render/pixel_format.h" #include "render/swapchain.h" #include "render/wlr_renderer.h" -#include "util/signal.h" #include "linux-dmabuf-unstable-v1-client-protocol.h" #include "presentation-time-client-protocol.h" @@ -30,7 +29,8 @@ static const uint32_t SUPPORTED_OUTPUT_STATE = WLR_OUTPUT_STATE_BACKEND_OPTIONAL | WLR_OUTPUT_STATE_BUFFER | - WLR_OUTPUT_STATE_MODE; + WLR_OUTPUT_STATE_MODE | + WLR_OUTPUT_STATE_ADAPTIVE_SYNC_ENABLED; static struct wlr_wl_output *get_wl_output_from_output( struct wlr_output *wlr_output) { @@ -240,48 +240,59 @@ static struct wlr_wl_buffer *get_or_create_wl_buffer(struct wlr_wl_backend *wl, return create_wl_buffer(wl, wlr_buffer); } -static bool output_test(struct wlr_output *wlr_output) { +static bool output_test(struct wlr_output *wlr_output, + const struct wlr_output_state *state) { struct wlr_wl_output *output = get_wl_output_from_output(wlr_output); - uint32_t unsupported = - wlr_output->pending.committed & ~SUPPORTED_OUTPUT_STATE; + uint32_t unsupported = state->committed & ~SUPPORTED_OUTPUT_STATE; if (unsupported != 0) { wlr_log(WLR_DEBUG, "Unsupported output state fields: 0x%"PRIx32, unsupported); return false; } - if (wlr_output->pending.committed & WLR_OUTPUT_STATE_MODE) { - assert(wlr_output->pending.mode_type == WLR_OUTPUT_STATE_MODE_CUSTOM); + // Adaptive sync is effectively always enabled when using the Wayland + // backend. This is not something we have control over, so we set the state + // to enabled on creating the output and never allow changing it. + assert(wlr_output->adaptive_sync_status == WLR_OUTPUT_ADAPTIVE_SYNC_ENABLED); + if (state->committed & WLR_OUTPUT_STATE_ADAPTIVE_SYNC_ENABLED) { + if (!state->adaptive_sync_enabled) { + return false; + } } - if ((wlr_output->pending.committed & WLR_OUTPUT_STATE_BUFFER) && - !test_buffer(output->backend, wlr_output->pending.buffer)) { + if (state->committed & WLR_OUTPUT_STATE_MODE) { + assert(state->mode_type == WLR_OUTPUT_STATE_MODE_CUSTOM); + } + + if ((state->committed & WLR_OUTPUT_STATE_BUFFER) && + !test_buffer(output->backend, state->buffer)) { return false; } return true; } -static bool output_commit(struct wlr_output *wlr_output) { +static bool output_commit(struct wlr_output *wlr_output, + const struct wlr_output_state *state) { struct wlr_wl_output *output = get_wl_output_from_output(wlr_output); - if (!output_test(wlr_output)) { + if (!output_test(wlr_output, state)) { return false; } - if (wlr_output->pending.committed & WLR_OUTPUT_STATE_MODE) { + if (state->committed & WLR_OUTPUT_STATE_MODE) { if (!output_set_custom_mode(wlr_output, - wlr_output->pending.custom_mode.width, - wlr_output->pending.custom_mode.height, - wlr_output->pending.custom_mode.refresh)) { + state->custom_mode.width, + state->custom_mode.height, + state->custom_mode.refresh)) { return false; } } - if (wlr_output->pending.committed & WLR_OUTPUT_STATE_BUFFER) { + if (state->committed & WLR_OUTPUT_STATE_BUFFER) { struct wp_presentation_feedback *wp_feedback = NULL; if (output->backend->presentation != NULL) { wp_feedback = wp_presentation_feedback(output->backend->presentation, @@ -289,8 +300,8 @@ static bool output_commit(struct wlr_output *wlr_output) { } pixman_region32_t *damage = NULL; - if (wlr_output->pending.committed & WLR_OUTPUT_STATE_DAMAGE) { - damage = &wlr_output->pending.damage; + if (state->committed & WLR_OUTPUT_STATE_DAMAGE) { + damage = (pixman_region32_t *) &state->damage; } if (output->frame_callback != NULL) { @@ -301,7 +312,7 @@ static bool output_commit(struct wlr_output *wlr_output) { output->frame_callback = wl_surface_frame(output->surface); wl_callback_add_listener(output->frame_callback, &frame_listener, output); - struct wlr_buffer *wlr_buffer = wlr_output->pending.buffer; + struct wlr_buffer *wlr_buffer = state->buffer; struct wlr_wl_buffer *buffer = get_or_create_wl_buffer(output->backend, wlr_buffer); if (buffer == NULL) { @@ -436,7 +447,9 @@ void update_wl_output_cursor(struct wlr_wl_output *output) { if (pointer) { assert(pointer->output == output); assert(output->enter_serial); - wl_pointer_set_cursor(pointer->wl_pointer, output->enter_serial, + + struct wlr_wl_seat *seat = pointer->seat; + wl_pointer_set_cursor(seat->wl_pointer, output->enter_serial, output->cursor.surface, output->cursor.hotspot_x, output->cursor.hotspot_y); } @@ -518,8 +531,8 @@ struct wlr_output *wlr_wl_output_create(struct wlr_backend *wlr_backend) { struct wlr_output *wlr_output = &output->wlr_output; wlr_output_update_custom_mode(wlr_output, 1280, 720, 0); - strncpy(wlr_output->make, "wayland", sizeof(wlr_output->make)); - strncpy(wlr_output->model, "wayland", sizeof(wlr_output->model)); + + wlr_output->adaptive_sync_status = WLR_OUTPUT_ADAPTIVE_SYNC_ENABLED; char name[64]; snprintf(name, sizeof(name), "WL-%zu", ++backend->last_output_num); @@ -578,12 +591,12 @@ struct wlr_output *wlr_wl_output_create(struct wlr_backend *wlr_backend) { wl_list_insert(&backend->outputs, &output->link); wlr_output_update_enabled(wlr_output, true); - wlr_signal_emit_safe(&backend->backend.events.new_output, wlr_output); + wl_signal_emit_mutable(&backend->backend.events.new_output, wlr_output); struct wlr_wl_seat *seat; wl_list_for_each(seat, &backend->seats, link) { - if (seat->pointer) { - create_wl_pointer(seat, output); + if (seat->wl_pointer) { + create_pointer(seat, output); } } diff --git a/backend/wayland/pointer.c b/backend/wayland/pointer.c new file mode 100644 index 000000000..4ce233e52 --- /dev/null +++ b/backend/wayland/pointer.c @@ -0,0 +1,541 @@ +#define _POSIX_C_SOURCE 200809L + +#include +#include +#include +#include +#include + +#include "backend/wayland.h" + +#include "pointer-gestures-unstable-v1-client-protocol.h" +#include "relative-pointer-unstable-v1-client-protocol.h" + +static struct wlr_wl_pointer *output_get_pointer(struct wlr_wl_output *output, + const struct wl_pointer *wl_pointer) { + struct wlr_wl_seat *seat; + wl_list_for_each(seat, &output->backend->seats, link) { + if (seat->wl_pointer != wl_pointer) { + continue; + } + + struct wlr_wl_pointer *pointer; + wl_list_for_each(pointer, &seat->pointers, link) { + if (pointer->output == output) { + return pointer; + } + } + } + + return NULL; +} + +static void pointer_handle_enter(void *data, struct wl_pointer *wl_pointer, + uint32_t serial, struct wl_surface *surface, wl_fixed_t sx, + wl_fixed_t sy) { + struct wlr_wl_seat *seat = data; + if (surface == NULL) { + return; + } + + struct wlr_wl_output *output = wl_surface_get_user_data(surface); + assert(output); + + struct wlr_wl_pointer *pointer = output_get_pointer(output, wl_pointer); + seat->active_pointer = pointer; + + // Manage cursor icon/rendering on output + struct wlr_wl_pointer *current = output->cursor.pointer; + if (current && current != pointer) { + wlr_log(WLR_INFO, "Ignoring seat '%s' pointer in favor of seat '%s'", + seat->name, current->seat->name); + return; + } + + output->enter_serial = serial; + output->cursor.pointer = pointer; + update_wl_output_cursor(output); +} + +static void pointer_handle_leave(void *data, struct wl_pointer *wl_pointer, + uint32_t serial, struct wl_surface *surface) { + struct wlr_wl_seat *seat = data; + if (surface == NULL) { + return; + } + + struct wlr_wl_output *output = wl_surface_get_user_data(surface); + assert(output); + + if (seat->active_pointer != NULL && + seat->active_pointer->output == output) { + seat->active_pointer = NULL; + } + + if (output->cursor.pointer == seat->active_pointer) { + output->enter_serial = 0; + output->cursor.pointer = NULL; + } +} + +static void pointer_handle_motion(void *data, struct wl_pointer *wl_pointer, + uint32_t time, wl_fixed_t sx, wl_fixed_t sy) { + struct wlr_wl_seat *seat = data; + struct wlr_wl_pointer *pointer = seat->active_pointer; + if (pointer == NULL) { + return; + } + + struct wlr_output *wlr_output = &pointer->output->wlr_output; + struct wlr_pointer_motion_absolute_event event = { + .pointer = &pointer->wlr_pointer, + .time_msec = time, + .x = wl_fixed_to_double(sx) / wlr_output->width, + .y = wl_fixed_to_double(sy) / wlr_output->height, + }; + wl_signal_emit_mutable(&pointer->wlr_pointer.events.motion_absolute, &event); +} + +static void pointer_handle_button(void *data, struct wl_pointer *wl_pointer, + uint32_t serial, uint32_t time, uint32_t button, uint32_t state) { + struct wlr_wl_seat *seat = data; + struct wlr_wl_pointer *pointer = seat->active_pointer; + if (pointer == NULL) { + return; + } + + struct wlr_pointer_button_event event = { + .pointer = &pointer->wlr_pointer, + .button = button, + .state = state, + .time_msec = time, + }; + wl_signal_emit_mutable(&pointer->wlr_pointer.events.button, &event); +} + +static void pointer_handle_axis(void *data, struct wl_pointer *wl_pointer, + uint32_t time, uint32_t axis, wl_fixed_t value) { + struct wlr_wl_seat *seat = data; + struct wlr_wl_pointer *pointer = seat->active_pointer; + if (pointer == NULL) { + return; + } + + struct wlr_pointer_axis_event event = { + .pointer = &pointer->wlr_pointer, + .delta = wl_fixed_to_double(value), + .delta_discrete = pointer->axis_discrete, + .orientation = axis, + .time_msec = time, + .source = pointer->axis_source, + }; + wl_signal_emit_mutable(&pointer->wlr_pointer.events.axis, &event); + + pointer->axis_discrete = 0; +} + +static void pointer_handle_frame(void *data, struct wl_pointer *wl_pointer) { + struct wlr_wl_seat *seat = data; + struct wlr_wl_pointer *pointer = seat->active_pointer; + if (pointer == NULL) { + return; + } + + wl_signal_emit_mutable(&pointer->wlr_pointer.events.frame, + &pointer->wlr_pointer); +} + +static void pointer_handle_axis_source(void *data, + struct wl_pointer *wl_pointer, uint32_t axis_source) { + struct wlr_wl_seat *seat = data; + struct wlr_wl_pointer *pointer = seat->active_pointer; + if (pointer == NULL) { + return; + } + + pointer->axis_source = axis_source; +} + +static void pointer_handle_axis_stop(void *data, struct wl_pointer *wl_pointer, + uint32_t time, uint32_t axis) { + struct wlr_wl_seat *seat = data; + struct wlr_wl_pointer *pointer = seat->active_pointer; + if (pointer == NULL) { + return; + } + + struct wlr_pointer_axis_event event = { + .pointer = &pointer->wlr_pointer, + .delta = 0, + .delta_discrete = 0, + .orientation = axis, + .time_msec = time, + .source = pointer->axis_source, + }; + wl_signal_emit_mutable(&pointer->wlr_pointer.events.axis, &event); +} + +static void pointer_handle_axis_discrete(void *data, + struct wl_pointer *wl_pointer, uint32_t axis, int32_t discrete) { + struct wlr_wl_seat *seat = data; + struct wlr_wl_pointer *pointer = seat->active_pointer; + if (pointer == NULL) { + return; + } + + pointer->axis_discrete = discrete * WLR_POINTER_AXIS_DISCRETE_STEP; +} + +static void pointer_handle_axis_value120(void *data, + struct wl_pointer *wl_pointer, uint32_t axis, int32_t value120) { + struct wlr_wl_seat *seat = data; + struct wlr_wl_pointer *pointer = seat->active_pointer; + if (pointer == NULL) { + return; + } + + pointer->axis_discrete = value120; +} + +static const struct wl_pointer_listener pointer_listener = { + .enter = pointer_handle_enter, + .leave = pointer_handle_leave, + .motion = pointer_handle_motion, + .button = pointer_handle_button, + .axis = pointer_handle_axis, + .frame = pointer_handle_frame, + .axis_source = pointer_handle_axis_source, + .axis_stop = pointer_handle_axis_stop, + .axis_discrete = pointer_handle_axis_discrete, + .axis_value120 = pointer_handle_axis_value120, +}; + +static void gesture_swipe_begin(void *data, + struct zwp_pointer_gesture_swipe_v1 *zwp_pointer_gesture_swipe_v1, + uint32_t serial, uint32_t time, struct wl_surface *surface, + uint32_t fingers) { + struct wlr_wl_seat *seat = data; + struct wlr_wl_pointer *pointer = seat->active_pointer; + if (pointer == NULL) { + return; + } + + pointer->fingers = fingers; + + struct wlr_pointer_swipe_begin_event wlr_event = { + .pointer = &pointer->wlr_pointer, + .time_msec = time, + .fingers = fingers, + }; + wl_signal_emit_mutable(&pointer->wlr_pointer.events.swipe_begin, &wlr_event); +} + +static void gesture_swipe_update(void *data, + struct zwp_pointer_gesture_swipe_v1 *zwp_pointer_gesture_swipe_v1, + uint32_t time, wl_fixed_t dx, wl_fixed_t dy) { + struct wlr_wl_seat *seat = data; + struct wlr_wl_pointer *pointer = seat->active_pointer; + if (pointer == NULL) { + return; + } + + struct wlr_pointer_swipe_update_event wlr_event = { + .pointer = &pointer->wlr_pointer, + .time_msec = time, + .fingers = pointer->fingers, + .dx = wl_fixed_to_double(dx), + .dy = wl_fixed_to_double(dy), + }; + wl_signal_emit_mutable(&pointer->wlr_pointer.events.swipe_update, &wlr_event); +} + +static void gesture_swipe_end(void *data, + struct zwp_pointer_gesture_swipe_v1 *zwp_pointer_gesture_swipe_v1, + uint32_t serial, uint32_t time, int32_t cancelled) { + struct wlr_wl_seat *seat = data; + struct wlr_wl_pointer *pointer = seat->active_pointer; + if (pointer == NULL) { + return; + } + + struct wlr_pointer_swipe_end_event wlr_event = { + .pointer = &pointer->wlr_pointer, + .time_msec = time, + .cancelled = cancelled, + }; + wl_signal_emit_mutable(&pointer->wlr_pointer.events.swipe_end, &wlr_event); +} + +static const struct zwp_pointer_gesture_swipe_v1_listener gesture_swipe_impl = { + .begin = gesture_swipe_begin, + .update = gesture_swipe_update, + .end = gesture_swipe_end, +}; + +static void gesture_pinch_begin(void *data, + struct zwp_pointer_gesture_pinch_v1 *zwp_pointer_gesture_pinch_v1, + uint32_t serial, uint32_t time, struct wl_surface *surface, + uint32_t fingers) { + struct wlr_wl_seat *seat = data; + struct wlr_wl_pointer *pointer = seat->active_pointer; + if (pointer == NULL) { + return; + } + + pointer->fingers = fingers; + + struct wlr_pointer_pinch_begin_event wlr_event = { + .pointer = &pointer->wlr_pointer, + .time_msec = time, + .fingers = pointer->fingers, + }; + + wl_signal_emit_mutable(&pointer->wlr_pointer.events.pinch_begin, &wlr_event); +} + +static void gesture_pinch_update(void *data, + struct zwp_pointer_gesture_pinch_v1 *zwp_pointer_gesture_pinch_v1, + uint32_t time, wl_fixed_t dx, wl_fixed_t dy, wl_fixed_t scale, + wl_fixed_t rotation) { + struct wlr_wl_seat *seat = data; + struct wlr_wl_pointer *pointer = seat->active_pointer; + if (pointer == NULL) { + return; + } + + struct wlr_pointer_pinch_update_event wlr_event = { + .pointer = &pointer->wlr_pointer, + .time_msec = time, + .fingers = pointer->fingers, + .dx = wl_fixed_to_double(dx), + .dy = wl_fixed_to_double(dy), + .scale = wl_fixed_to_double(scale), + .rotation = wl_fixed_to_double(rotation), + }; + wl_signal_emit_mutable(&pointer->wlr_pointer.events.pinch_update, &wlr_event); +} + +static void gesture_pinch_end(void *data, + struct zwp_pointer_gesture_pinch_v1 *zwp_pointer_gesture_pinch_v1, + uint32_t serial, uint32_t time, int32_t cancelled) { + struct wlr_wl_seat *seat = data; + struct wlr_wl_pointer *pointer = seat->active_pointer; + if (pointer == NULL) { + return; + } + + struct wlr_pointer_pinch_end_event wlr_event = { + .pointer = &pointer->wlr_pointer, + .time_msec = time, + .cancelled = cancelled, + }; + wl_signal_emit_mutable(&pointer->wlr_pointer.events.pinch_end, &wlr_event); +} + +static const struct zwp_pointer_gesture_pinch_v1_listener gesture_pinch_impl = { + .begin = gesture_pinch_begin, + .update = gesture_pinch_update, + .end = gesture_pinch_end, +}; + +static void gesture_hold_begin(void *data, + struct zwp_pointer_gesture_hold_v1 *zwp_pointer_gesture_hold_v1, + uint32_t serial, uint32_t time, struct wl_surface *surface, + uint32_t fingers) { + struct wlr_wl_seat *seat = data; + struct wlr_wl_pointer *pointer = seat->active_pointer; + if (pointer == NULL) { + return; + } + + pointer->fingers = fingers; + + struct wlr_pointer_hold_begin_event wlr_event = { + .pointer = &pointer->wlr_pointer, + .time_msec = time, + .fingers = fingers, + }; + wl_signal_emit_mutable(&pointer->wlr_pointer.events.hold_begin, &wlr_event); +} + +static void gesture_hold_end(void *data, + struct zwp_pointer_gesture_hold_v1 *zwp_pointer_gesture_hold_v1, + uint32_t serial, uint32_t time, int32_t cancelled) { + struct wlr_wl_seat *seat = data; + struct wlr_wl_pointer *pointer = seat->active_pointer; + if (pointer == NULL) { + return; + } + + struct wlr_pointer_hold_end_event wlr_event = { + .pointer = &pointer->wlr_pointer, + .time_msec = time, + .cancelled = cancelled, + }; + wl_signal_emit_mutable(&pointer->wlr_pointer.events.hold_end, &wlr_event); +} + +static const struct zwp_pointer_gesture_hold_v1_listener gesture_hold_impl = { + .begin = gesture_hold_begin, + .end = gesture_hold_end, +}; + +static void relative_pointer_handle_relative_motion(void *data, + struct zwp_relative_pointer_v1 *relative_pointer, uint32_t utime_hi, + uint32_t utime_lo, wl_fixed_t dx, wl_fixed_t dy, wl_fixed_t dx_unaccel, + wl_fixed_t dy_unaccel) { + struct wlr_wl_seat *seat = data; + struct wlr_wl_pointer *pointer = seat->active_pointer; + if (pointer == NULL) { + return; + } + + uint64_t time_usec = (uint64_t)utime_hi << 32 | utime_lo; + + struct wlr_pointer_motion_event wlr_event = { + .pointer = &pointer->wlr_pointer, + .time_msec = (uint32_t)(time_usec / 1000), + .delta_x = wl_fixed_to_double(dx), + .delta_y = wl_fixed_to_double(dy), + .unaccel_dx = wl_fixed_to_double(dx_unaccel), + .unaccel_dy = wl_fixed_to_double(dy_unaccel), + }; + wl_signal_emit_mutable(&pointer->wlr_pointer.events.motion, &wlr_event); +} + +static const struct zwp_relative_pointer_v1_listener relative_pointer_listener = { + .relative_motion = relative_pointer_handle_relative_motion, +}; + +const struct wlr_pointer_impl wl_pointer_impl = { + .name = "wl-pointer", +}; + +static void destroy_pointer(struct wlr_wl_pointer *pointer) { + if (pointer->output->cursor.pointer == pointer) { + pointer->output->cursor.pointer = NULL; + } + if (pointer->seat->active_pointer == pointer) { + pointer->seat->active_pointer = NULL; + } + + wlr_pointer_finish(&pointer->wlr_pointer); + wl_list_remove(&pointer->output_destroy.link); + wl_list_remove(&pointer->link); + free(pointer); +} + +static void pointer_output_destroy(struct wl_listener *listener, void *data) { + struct wlr_wl_pointer *pointer = + wl_container_of(listener, pointer, output_destroy); + destroy_pointer(pointer); +} + +void create_pointer(struct wlr_wl_seat *seat, struct wlr_wl_output *output) { + assert(seat->wl_pointer); + + if (output_get_pointer(output, seat->wl_pointer)) { + wlr_log(WLR_DEBUG, + "pointer for output '%s' from seat '%s' already exists", + output->wlr_output.name, seat->name); + return; + } + + wlr_log(WLR_DEBUG, "creating pointer for output '%s' from seat '%s'", + output->wlr_output.name, seat->name); + + struct wlr_wl_pointer *pointer = calloc(1, sizeof(struct wlr_wl_pointer)); + if (pointer == NULL) { + wlr_log(WLR_ERROR, "failed to allocate wlr_wl_pointer"); + return; + } + + char name[64] = {0}; + snprintf(name, sizeof(name), "wayland-pointer-%s", seat->name); + wlr_pointer_init(&pointer->wlr_pointer, &wl_pointer_impl, name); + + pointer->wlr_pointer.output_name = strdup(output->wlr_output.name); + + pointer->seat = seat; + pointer->output = output; + + wl_signal_add(&output->wlr_output.events.destroy, &pointer->output_destroy); + pointer->output_destroy.notify = pointer_output_destroy; + + wl_signal_emit_mutable(&seat->backend->backend.events.new_input, + &pointer->wlr_pointer.base); + + wl_list_insert(&seat->pointers, &pointer->link); +} + +void init_seat_pointer(struct wlr_wl_seat *seat) { + assert(seat->wl_pointer); + + struct wlr_wl_backend *backend = seat->backend; + + wl_list_init(&seat->pointers); + + struct wlr_wl_output *output; + wl_list_for_each(output, &backend->outputs, link) { + create_pointer(seat, output); + } + + if (backend->zwp_pointer_gestures_v1) { + uint32_t version = zwp_pointer_gestures_v1_get_version( + backend->zwp_pointer_gestures_v1); + + seat->gesture_swipe = zwp_pointer_gestures_v1_get_swipe_gesture( + backend->zwp_pointer_gestures_v1, seat->wl_pointer); + zwp_pointer_gesture_swipe_v1_add_listener(seat->gesture_swipe, + &gesture_swipe_impl, seat); + + seat->gesture_pinch = zwp_pointer_gestures_v1_get_pinch_gesture( + backend->zwp_pointer_gestures_v1, seat->wl_pointer); + zwp_pointer_gesture_pinch_v1_add_listener(seat->gesture_pinch, + &gesture_pinch_impl, seat); + + if (version >= ZWP_POINTER_GESTURES_V1_GET_HOLD_GESTURE) { + seat->gesture_hold = zwp_pointer_gestures_v1_get_hold_gesture( + backend->zwp_pointer_gestures_v1, seat->wl_pointer); + zwp_pointer_gesture_hold_v1_add_listener(seat->gesture_hold, + &gesture_hold_impl, seat); + } + } + + if (backend->zwp_relative_pointer_manager_v1) { + seat->relative_pointer = + zwp_relative_pointer_manager_v1_get_relative_pointer( + backend->zwp_relative_pointer_manager_v1, seat->wl_pointer); + zwp_relative_pointer_v1_add_listener(seat->relative_pointer, + &relative_pointer_listener, seat); + } + + wl_pointer_add_listener(seat->wl_pointer, &pointer_listener, seat); +} + +void finish_seat_pointer(struct wlr_wl_seat *seat) { + assert(seat->wl_pointer); + + wl_pointer_release(seat->wl_pointer); + + struct wlr_wl_pointer *pointer, *tmp; + wl_list_for_each_safe(pointer, tmp, &seat->pointers, link) { + destroy_pointer(pointer); + } + + if (seat->gesture_swipe != NULL) { + zwp_pointer_gesture_swipe_v1_destroy(seat->gesture_swipe); + } + if (seat->gesture_pinch != NULL) { + zwp_pointer_gesture_pinch_v1_destroy(seat->gesture_pinch); + } + if (seat->gesture_hold != NULL) { + zwp_pointer_gesture_hold_v1_destroy(seat->gesture_hold); + } + if (seat->relative_pointer != NULL) { + zwp_relative_pointer_v1_destroy(seat->relative_pointer); + } + + seat->wl_pointer = NULL; + seat->active_pointer = NULL; +} diff --git a/backend/wayland/seat.c b/backend/wayland/seat.c index 28466bb33..b81fe2193 100644 --- a/backend/wayland/seat.c +++ b/backend/wayland/seat.c @@ -11,207 +11,15 @@ #include #include -#include #include #include #include +#include #include -#include "pointer-gestures-unstable-v1-client-protocol.h" -#include "relative-pointer-unstable-v1-client-protocol.h" #include "backend/wayland.h" -#include "util/signal.h" #include "util/time.h" -static const struct wlr_pointer_impl pointer_impl; -static const struct wlr_keyboard_impl keyboard_impl; -static const struct wlr_touch_impl touch_impl; - -static struct wlr_wl_pointer *output_get_pointer( - struct wlr_wl_output *output, - const struct wl_pointer *wl_pointer) { - struct wlr_wl_input_device *dev; - wl_list_for_each(dev, &output->backend->devices, link) { - if (dev->wlr_input_device.type != WLR_INPUT_DEVICE_POINTER) { - continue; - } - struct wlr_wl_pointer *pointer = - pointer_get_wl(dev->wlr_input_device.pointer); - if (pointer->output == output && pointer->wl_pointer == wl_pointer) { - return pointer; - } - } - - return NULL; -} - -static void pointer_handle_enter(void *data, struct wl_pointer *wl_pointer, - uint32_t serial, struct wl_surface *surface, wl_fixed_t sx, - wl_fixed_t sy) { - struct wlr_wl_seat *seat = data; - if (surface == NULL) { - return; - } - - struct wlr_wl_output *output = wl_surface_get_user_data(surface); - assert(output); - struct wlr_wl_pointer *pointer = output_get_pointer(output, wl_pointer); - seat->active_pointer = pointer; - - // Manage cursor icon/rendering on output - struct wlr_wl_pointer *current_pointer = output->cursor.pointer; - if (current_pointer && current_pointer != pointer) { - wlr_log(WLR_INFO, "Ignoring seat %s pointer cursor in favor of seat %s", - seat->name, current_pointer->input_device->seat->name); - return; - } - - output->enter_serial = serial; - output->cursor.pointer = pointer; - update_wl_output_cursor(output); -} - -static void pointer_handle_leave(void *data, struct wl_pointer *wl_pointer, - uint32_t serial, struct wl_surface *surface) { - struct wlr_wl_seat *seat = data; - if (surface == NULL) { - return; - } - - struct wlr_wl_output *output = wl_surface_get_user_data(surface); - assert(output); - - if (seat->active_pointer != NULL && - seat->active_pointer->output == output) { - seat->active_pointer = NULL; - } - - if (output->cursor.pointer == seat->active_pointer) { - output->enter_serial = 0; - output->cursor.pointer = NULL; - } -} - -static void pointer_handle_motion(void *data, struct wl_pointer *wl_pointer, - uint32_t time, wl_fixed_t sx, wl_fixed_t sy) { - struct wlr_wl_seat *seat = data; - struct wlr_wl_pointer *pointer = seat->active_pointer; - if (pointer == NULL) { - return; - } - - struct wlr_output *wlr_output = &pointer->output->wlr_output; - struct wlr_event_pointer_motion_absolute event = { - .device = &pointer->input_device->wlr_input_device, - .time_msec = time, - .x = wl_fixed_to_double(sx) / wlr_output->width, - .y = wl_fixed_to_double(sy) / wlr_output->height, - }; - wlr_signal_emit_safe(&pointer->wlr_pointer.events.motion_absolute, &event); -} - -static void pointer_handle_button(void *data, struct wl_pointer *wl_pointer, - uint32_t serial, uint32_t time, uint32_t button, uint32_t state) { - struct wlr_wl_seat *seat = data; - struct wlr_wl_pointer *pointer = seat->active_pointer; - if (pointer == NULL) { - return; - } - - struct wlr_event_pointer_button event = { - .device = &pointer->input_device->wlr_input_device, - .button = button, - .state = state, - .time_msec = time, - }; - wlr_signal_emit_safe(&pointer->wlr_pointer.events.button, &event); -} - -static void pointer_handle_axis(void *data, struct wl_pointer *wl_pointer, - uint32_t time, uint32_t axis, wl_fixed_t value) { - struct wlr_wl_seat *seat = data; - struct wlr_wl_pointer *pointer = seat->active_pointer; - if (pointer == NULL) { - return; - } - - struct wlr_event_pointer_axis event = { - .device = &pointer->input_device->wlr_input_device, - .delta = wl_fixed_to_double(value), - .delta_discrete = pointer->axis_discrete, - .orientation = axis, - .time_msec = time, - .source = pointer->axis_source, - }; - wlr_signal_emit_safe(&pointer->wlr_pointer.events.axis, &event); - - pointer->axis_discrete = 0; -} - -static void pointer_handle_frame(void *data, struct wl_pointer *wl_pointer) { - struct wlr_wl_seat *seat = data; - struct wlr_wl_pointer *pointer = seat->active_pointer; - if (pointer == NULL) { - return; - } - - wlr_signal_emit_safe(&pointer->wlr_pointer.events.frame, - &pointer->wlr_pointer); -} - -static void pointer_handle_axis_source(void *data, - struct wl_pointer *wl_pointer, uint32_t axis_source) { - struct wlr_wl_seat *seat = data; - struct wlr_wl_pointer *pointer = seat->active_pointer; - if (pointer == NULL) { - return; - } - - pointer->axis_source = axis_source; -} - -static void pointer_handle_axis_stop(void *data, struct wl_pointer *wl_pointer, - uint32_t time, uint32_t axis) { - struct wlr_wl_seat *seat = data; - struct wlr_wl_pointer *pointer = seat->active_pointer; - if (pointer == NULL) { - return; - } - - struct wlr_event_pointer_axis event = { - .device = &pointer->input_device->wlr_input_device, - .delta = 0, - .delta_discrete = 0, - .orientation = axis, - .time_msec = time, - .source = pointer->axis_source, - }; - wlr_signal_emit_safe(&pointer->wlr_pointer.events.axis, &event); -} - -static void pointer_handle_axis_discrete(void *data, - struct wl_pointer *wl_pointer, uint32_t axis, int32_t discrete) { - struct wlr_wl_seat *seat = data; - struct wlr_wl_pointer *pointer = seat->active_pointer; - if (pointer == NULL) { - return; - } - - pointer->axis_discrete = discrete; -} - -static const struct wl_pointer_listener pointer_listener = { - .enter = pointer_handle_enter, - .leave = pointer_handle_leave, - .motion = pointer_handle_motion, - .button = pointer_handle_button, - .axis = pointer_handle_axis, - .frame = pointer_handle_frame, - .axis_source = pointer_handle_axis_source, - .axis_stop = pointer_handle_axis_stop, - .axis_discrete = pointer_handle_axis_discrete, -}; - static void keyboard_handle_keymap(void *data, struct wl_keyboard *wl_keyboard, uint32_t format, int32_t fd, uint32_t size) { close(fd); @@ -219,66 +27,60 @@ static void keyboard_handle_keymap(void *data, struct wl_keyboard *wl_keyboard, static void keyboard_handle_enter(void *data, struct wl_keyboard *wl_keyboard, uint32_t serial, struct wl_surface *surface, struct wl_array *keys) { - struct wlr_input_device *dev = data; - - uint32_t time = get_current_time_msec(); + struct wlr_keyboard *keyboard = data; uint32_t *keycode_ptr; wl_array_for_each(keycode_ptr, keys) { - struct wlr_event_keyboard_key event = { + struct wlr_keyboard_key_event event = { .keycode = *keycode_ptr, .state = WL_KEYBOARD_KEY_STATE_PRESSED, - .time_msec = time, + .time_msec = get_current_time_msec(), .update_state = false, }; - wlr_keyboard_notify_key(dev->keyboard, &event); + wlr_keyboard_notify_key(keyboard, &event); } } static void keyboard_handle_leave(void *data, struct wl_keyboard *wl_keyboard, uint32_t serial, struct wl_surface *surface) { - struct wlr_input_device *dev = data; + struct wlr_keyboard *keyboard = data; - uint32_t time = get_current_time_msec(); - - size_t num_keycodes = dev->keyboard->num_keycodes; + size_t num_keycodes = keyboard->num_keycodes; uint32_t pressed[num_keycodes + 1]; - memcpy(pressed, dev->keyboard->keycodes, + memcpy(pressed, keyboard->keycodes, num_keycodes * sizeof(uint32_t)); for (size_t i = 0; i < num_keycodes; ++i) { uint32_t keycode = pressed[i]; - struct wlr_event_keyboard_key event = { + struct wlr_keyboard_key_event event = { .keycode = keycode, .state = WL_KEYBOARD_KEY_STATE_RELEASED, - .time_msec = time, + .time_msec = get_current_time_msec(), .update_state = false, }; - wlr_keyboard_notify_key(dev->keyboard, &event); + wlr_keyboard_notify_key(keyboard, &event); } } static void keyboard_handle_key(void *data, struct wl_keyboard *wl_keyboard, uint32_t serial, uint32_t time, uint32_t key, uint32_t state) { - struct wlr_input_device *dev = data; - assert(dev && dev->keyboard); + struct wlr_keyboard *keyboard = data; - struct wlr_event_keyboard_key wlr_event = { + struct wlr_keyboard_key_event wlr_event = { .keycode = key, .state = state, .time_msec = time, .update_state = false, }; - wlr_keyboard_notify_key(dev->keyboard, &wlr_event); + wlr_keyboard_notify_key(keyboard, &wlr_event); } static void keyboard_handle_modifiers(void *data, struct wl_keyboard *wl_keyboard, uint32_t serial, uint32_t mods_depressed, uint32_t mods_latched, uint32_t mods_locked, uint32_t group) { - struct wlr_input_device *dev = data; - assert(dev && dev->keyboard); - wlr_keyboard_notify_modifiers(dev->keyboard, mods_depressed, mods_latched, + struct wlr_keyboard *keyboard = data; + wlr_keyboard_notify_modifiers(keyboard, mods_depressed, mods_latched, mods_locked, group); } @@ -296,11 +98,35 @@ static const struct wl_keyboard_listener keyboard_listener = { .repeat_info = keyboard_handle_repeat_info }; -static void touch_coordinates_to_absolute(struct wlr_wl_input_device *device, +static const struct wlr_keyboard_impl keyboard_impl = { + .name = "wl-keyboard", +}; + +void init_seat_keyboard(struct wlr_wl_seat *seat) { + assert(seat->wl_keyboard); + + char name[128] = {0}; + snprintf(name, sizeof(name), "wayland-keyboard-%s", seat->name); + + wlr_keyboard_init(&seat->wlr_keyboard, &keyboard_impl, name); + wl_keyboard_add_listener(seat->wl_keyboard, &keyboard_listener, + &seat->wlr_keyboard); + + wl_signal_emit_mutable(&seat->backend->backend.events.new_input, + &seat->wlr_keyboard.base); +} + +static void touch_coordinates_to_absolute(struct wlr_wl_seat *seat, wl_fixed_t x, wl_fixed_t y, double *sx, double *sy) { - // TODO: each output needs its own touch + /** + * TODO: multi-output touch support + * Although the wayland backend supports multi-output pointers, the support + * for multi-output touch has been left on the side for simplicity reasons. + * If this is a feature you want/need, please open an issue on the wlroots + * tracker here https://gitlab.freedesktop.org/wlroots/wlroots/-/issues + */ struct wlr_wl_output *output, *tmp; - wl_list_for_each_safe(output, tmp, &device->backend->outputs, link) { + wl_list_for_each_safe(output, tmp, &seat->backend->outputs, link) { *sx = wl_fixed_to_double(x) / output->wlr_output.width; *sy = wl_fixed_to_double(y) / output->wlr_output.height; return; // Choose the first output in the list @@ -312,56 +138,49 @@ static void touch_coordinates_to_absolute(struct wlr_wl_input_device *device, static void touch_handle_down(void *data, struct wl_touch *wl_touch, uint32_t serial, uint32_t time, struct wl_surface *surface, int32_t id, wl_fixed_t x, wl_fixed_t y) { - struct wlr_wl_input_device *device = data; - assert(device && device->wlr_input_device.touch); + struct wlr_wl_seat *seat = data; + struct wlr_touch *touch = &seat->wlr_touch; - double sx, sy; - touch_coordinates_to_absolute(device, x, y, &sx, &sy); - struct wlr_event_touch_down event = { - .device = &device->wlr_input_device, + struct wlr_touch_down_event event = { + .touch = touch, .time_msec = time, .touch_id = id, - .x = sx, - .y = sy }; - wlr_signal_emit_safe(&device->wlr_input_device.touch->events.down, &event); + touch_coordinates_to_absolute(seat, x, y, &event.x, &event.y); + wl_signal_emit_mutable(&touch->events.down, &event); } static void touch_handle_up(void *data, struct wl_touch *wl_touch, uint32_t serial, uint32_t time, int32_t id) { - struct wlr_wl_input_device *device = data; - assert(device && device->wlr_input_device.touch); + struct wlr_wl_seat *seat = data; + struct wlr_touch *touch = &seat->wlr_touch; - struct wlr_event_touch_up event = { - .device = &device->wlr_input_device, + struct wlr_touch_up_event event = { + .touch = touch, .time_msec = time, .touch_id = id, }; - wlr_signal_emit_safe(&device->wlr_input_device.touch->events.up, &event); + wl_signal_emit_mutable(&touch->events.up, &event); } static void touch_handle_motion(void *data, struct wl_touch *wl_touch, uint32_t time, int32_t id, wl_fixed_t x, wl_fixed_t y) { - struct wlr_wl_input_device *device = data; - assert(device && device->wlr_input_device.touch); + struct wlr_wl_seat *seat = data; + struct wlr_touch *touch = &seat->wlr_touch; - double sx, sy; - touch_coordinates_to_absolute(device, x, y, &sx, &sy); - struct wlr_event_touch_motion event = { - .device = &device->wlr_input_device, + struct wlr_touch_motion_event event = { + .touch = touch, .time_msec = time, .touch_id = id, - .x = sx, - .y = sy }; - wlr_signal_emit_safe(&device->wlr_input_device.touch->events.motion, &event); + + touch_coordinates_to_absolute(seat, x, y, &event.x, &event.y); + wl_signal_emit_mutable(&touch->events.motion, &event); } static void touch_handle_frame(void *data, struct wl_touch *wl_touch) { - struct wlr_wl_input_device *device = data; - assert(device && device->wlr_input_device.touch); - - wlr_signal_emit_safe(&device->wlr_input_device.touch->events.frame, NULL); + struct wlr_wl_seat *seat = data; + wl_signal_emit_mutable(&seat->wlr_touch.events.frame, NULL); } static void touch_handle_cancel(void *data, struct wl_touch *wl_touch) { @@ -388,12 +207,32 @@ static const struct wl_touch_listener touch_listener = { .orientation = touch_handle_orientation, }; -static struct wlr_wl_input_device *get_wl_input_device_from_input_device( - struct wlr_input_device *wlr_dev) { - assert(wlr_input_device_is_wl(wlr_dev)); - return (struct wlr_wl_input_device *)wlr_dev; +static const struct wlr_touch_impl touch_impl = { + .name = "wl-touch", +}; + +void init_seat_touch(struct wlr_wl_seat *seat) { + assert(seat->wl_touch); + + char name[128] = {0}; + snprintf(name, sizeof(name), "wayland-touch-%s", seat->name); + + wlr_touch_init(&seat->wlr_touch, &touch_impl, name); + + struct wlr_wl_output *output; + wl_list_for_each(output, &seat->backend->outputs, link) { + /* Multi-output touch not supproted */ + seat->wlr_touch.output_name = strdup(output->wlr_output.name); + break; + } + + wl_touch_add_listener(seat->wl_touch, &touch_listener, seat); + wl_signal_emit_mutable(&seat->backend->backend.events.new_input, + &seat->wlr_touch.base); } +static const struct wl_seat_listener seat_listener; + bool create_wl_seat(struct wl_seat *wl_seat, struct wlr_wl_backend *wl) { struct wlr_wl_seat *seat = calloc(1, sizeof(struct wlr_wl_seat)); if (!seat) { @@ -410,16 +249,24 @@ bool create_wl_seat(struct wl_seat *wl_seat, struct wlr_wl_backend *wl) { void destroy_wl_seats(struct wlr_wl_backend *wl) { struct wlr_wl_seat *seat, *tmp_seat; wl_list_for_each_safe(seat, tmp_seat, &wl->seats, link) { - if (seat->touch) { - wl_touch_destroy(seat->touch); + if (seat->wl_touch) { + wl_touch_release(seat->wl_touch); + wlr_touch_finish(&seat->wlr_touch); } - if (seat->pointer) { - wl_pointer_destroy(seat->pointer); + if (seat->wl_pointer) { + finish_seat_pointer(seat); } - if (seat->keyboard && !wl->started) { - // early termination will not be handled by input_device_destroy - wl_keyboard_destroy(seat->keyboard); + if (seat->wl_keyboard) { + wl_keyboard_release(seat->wl_keyboard); + + if (seat->backend->started) { + wlr_keyboard_finish(&seat->wlr_keyboard); + } } + if (seat->zwp_tablet_seat_v2) { + finish_seat_tablet(seat); + } + free(seat->name); assert(seat->wl_seat); wl_seat_destroy(seat->wl_seat); @@ -429,501 +276,72 @@ void destroy_wl_seats(struct wlr_wl_backend *wl) { } } -static struct wlr_wl_seat *input_device_get_seat(struct wlr_input_device *wlr_dev) { - struct wlr_wl_input_device *dev = - get_wl_input_device_from_input_device(wlr_dev); - assert(dev->seat); - return dev->seat; -} - bool wlr_input_device_is_wl(struct wlr_input_device *dev) { switch (dev->type) { case WLR_INPUT_DEVICE_KEYBOARD: - return dev->keyboard->impl == &keyboard_impl; + return wlr_keyboard_from_input_device(dev)->impl == &keyboard_impl; case WLR_INPUT_DEVICE_POINTER: - return dev->pointer->impl == &pointer_impl; + return wlr_pointer_from_input_device(dev)->impl == &wl_pointer_impl; case WLR_INPUT_DEVICE_TOUCH: - return dev->touch->impl == &touch_impl; + return wlr_touch_from_input_device(dev)->impl == &touch_impl; case WLR_INPUT_DEVICE_TABLET_TOOL: - return dev->tablet->impl == &tablet_impl; + return wlr_tablet_from_input_device(dev)-> impl == &wl_tablet_impl; case WLR_INPUT_DEVICE_TABLET_PAD: - return dev->tablet_pad->impl == &tablet_pad_impl; + return wlr_tablet_pad_from_input_device(dev)->impl == &wl_tablet_pad_impl; default: return false; } } -struct wlr_wl_input_device *create_wl_input_device( - struct wlr_wl_seat *seat, enum wlr_input_device_type type) { - struct wlr_wl_input_device *dev = - calloc(1, sizeof(struct wlr_wl_input_device)); - if (dev == NULL) { - wlr_log_errno(WLR_ERROR, "Allocation failed"); - return NULL; - } - dev->backend = seat->backend; - dev->seat = seat; - - struct wlr_input_device *wlr_dev = &dev->wlr_input_device; - - const char *type_name = "unknown"; - - switch (type) { - case WLR_INPUT_DEVICE_KEYBOARD: - type_name = "keyboard"; - break; - case WLR_INPUT_DEVICE_POINTER: - type_name = "pointer"; - break; - case WLR_INPUT_DEVICE_TOUCH: - type_name = "touch"; - break; - case WLR_INPUT_DEVICE_TABLET_TOOL: - type_name = "tablet-tool"; - break; - case WLR_INPUT_DEVICE_TABLET_PAD: - type_name = "tablet-pad"; - break; - case WLR_INPUT_DEVICE_SWITCH: - type_name = "switch"; - break; - } - - size_t name_size = 8 + strlen(type_name) + strlen(seat->name) + 1; - char name[name_size]; - (void) snprintf(name, name_size, "wayland-%s-%s", type_name, seat->name); - - wlr_input_device_init(wlr_dev, type, name); - wl_list_insert(&seat->backend->devices, &dev->link); - return dev; -} - -void destroy_wl_input_device(struct wlr_wl_input_device *dev) { - /** - * TODO remove the redundant wlr_input_device from wlr_wl_input_device - * wlr_wl_input_device::wlr_input_device is not owned by its input device - * type, which means we have 2 wlr_input_device to cleanup - */ - wlr_input_device_finish(&dev->wlr_input_device); - if (dev->wlr_input_device._device) { - wlr_input_device_destroy(&dev->wlr_input_device); - } - wl_list_remove(&dev->link); - free(dev); -} - -struct wlr_wl_pointer *pointer_get_wl(struct wlr_pointer *wlr_pointer) { - assert(wlr_pointer->impl == &pointer_impl); - return (struct wlr_wl_pointer *)wlr_pointer; -} - -static void pointer_destroy(struct wlr_pointer *wlr_pointer) { - struct wlr_wl_pointer *pointer = pointer_get_wl(wlr_pointer); - - if (pointer->output->cursor.pointer == pointer) { - pointer->output->cursor.pointer = NULL; - } - - struct wlr_wl_seat *seat = pointer->input_device->seat; - if (seat->active_pointer == pointer) { - seat->active_pointer = NULL; - } - - // pointer->wl_pointer belongs to the wlr_wl_seat - - if (pointer->gesture_swipe != NULL) { - zwp_pointer_gesture_swipe_v1_destroy(pointer->gesture_swipe); - } - if (pointer->gesture_pinch != NULL) { - zwp_pointer_gesture_pinch_v1_destroy(pointer->gesture_pinch); - } - if (pointer->gesture_hold != NULL) { - zwp_pointer_gesture_hold_v1_destroy(pointer->gesture_hold); - } - if (pointer->relative_pointer != NULL) { - zwp_relative_pointer_v1_destroy(pointer->relative_pointer); - } - - wl_list_remove(&pointer->output_destroy.link); - free(pointer); -} - -static const struct wlr_pointer_impl pointer_impl = { - .destroy = pointer_destroy, -}; - -static void gesture_swipe_begin(void *data, - struct zwp_pointer_gesture_swipe_v1 *zwp_pointer_gesture_swipe_v1, - uint32_t serial, uint32_t time, - struct wl_surface *surface, uint32_t fingers) { - struct wlr_wl_input_device *input_device = (struct wlr_wl_input_device *)data; - struct wlr_input_device *wlr_dev = &input_device->wlr_input_device; - struct wlr_event_pointer_swipe_begin wlr_event = { - .device = wlr_dev, - .time_msec = time, - .fingers = fingers, - }; - input_device->fingers = fingers; - wlr_signal_emit_safe(&wlr_dev->pointer->events.swipe_begin, &wlr_event); -} - -static void gesture_swipe_update(void *data, - struct zwp_pointer_gesture_swipe_v1 *zwp_pointer_gesture_swipe_v1, - uint32_t time, wl_fixed_t dx, wl_fixed_t dy) { - struct wlr_wl_input_device *input_device = (struct wlr_wl_input_device *)data; - struct wlr_input_device *wlr_dev = &input_device->wlr_input_device; - struct wlr_event_pointer_swipe_update wlr_event = { - .device = wlr_dev, - .time_msec = time, - .fingers = input_device->fingers, - .dx = wl_fixed_to_double(dx), - .dy = wl_fixed_to_double(dy), - }; - wlr_signal_emit_safe(&wlr_dev->pointer->events.swipe_update, &wlr_event); -} - -static void gesture_swipe_end(void *data, - struct zwp_pointer_gesture_swipe_v1 *zwp_pointer_gesture_swipe_v1, - uint32_t serial, uint32_t time, int32_t cancelled) { - struct wlr_wl_input_device *input_device = (struct wlr_wl_input_device *)data; - struct wlr_input_device *wlr_dev = &input_device->wlr_input_device; - struct wlr_event_pointer_swipe_end wlr_event = { - .device = wlr_dev, - .time_msec = time, - .cancelled = cancelled, - }; - wlr_signal_emit_safe(&wlr_dev->pointer->events.swipe_end, &wlr_event); -} - -static const struct zwp_pointer_gesture_swipe_v1_listener gesture_swipe_impl = { - .begin = gesture_swipe_begin, - .update = gesture_swipe_update, - .end = gesture_swipe_end, -}; - -static void gesture_pinch_begin(void *data, - struct zwp_pointer_gesture_pinch_v1 *zwp_pointer_gesture_pinch_v1, - uint32_t serial, uint32_t time, - struct wl_surface *surface, uint32_t fingers) { - struct wlr_wl_input_device *input_device = (struct wlr_wl_input_device *)data; - struct wlr_input_device *wlr_dev = &input_device->wlr_input_device; - struct wlr_event_pointer_pinch_begin wlr_event = { - .device = wlr_dev, - .time_msec = time, - .fingers = fingers, - }; - input_device->fingers = fingers; - wlr_signal_emit_safe(&wlr_dev->pointer->events.pinch_begin, &wlr_event); -} - -static void gesture_pinch_update(void *data, - struct zwp_pointer_gesture_pinch_v1 *zwp_pointer_gesture_pinch_v1, - uint32_t time, wl_fixed_t dx, wl_fixed_t dy, wl_fixed_t scale, wl_fixed_t rotation) { - struct wlr_wl_input_device *input_device = (struct wlr_wl_input_device *)data; - struct wlr_input_device *wlr_dev = &input_device->wlr_input_device; - struct wlr_event_pointer_pinch_update wlr_event = { - .device = wlr_dev, - .time_msec = time, - .fingers = input_device->fingers, - .dx = wl_fixed_to_double(dx), - .dy = wl_fixed_to_double(dy), - .scale = wl_fixed_to_double(scale), - .rotation = wl_fixed_to_double(rotation), - }; - wlr_signal_emit_safe(&wlr_dev->pointer->events.pinch_update, &wlr_event); -} - -static void gesture_pinch_end(void *data, - struct zwp_pointer_gesture_pinch_v1 *zwp_pointer_gesture_pinch_v1, - uint32_t serial, uint32_t time, int32_t cancelled) { - struct wlr_wl_input_device *input_device = (struct wlr_wl_input_device *)data; - struct wlr_input_device *wlr_dev = &input_device->wlr_input_device; - struct wlr_event_pointer_pinch_end wlr_event = { - .device = wlr_dev, - .time_msec = time, - .cancelled = cancelled, - }; - wlr_signal_emit_safe(&wlr_dev->pointer->events.pinch_end, &wlr_event); -} - -static const struct zwp_pointer_gesture_pinch_v1_listener gesture_pinch_impl = { - .begin = gesture_pinch_begin, - .update = gesture_pinch_update, - .end = gesture_pinch_end, -}; - -static void gesture_hold_begin(void *data, - struct zwp_pointer_gesture_hold_v1 *zwp_pointer_gesture_hold_v1, - uint32_t serial, uint32_t time, - struct wl_surface *surface, uint32_t fingers) { - struct wlr_wl_input_device *input_device = (struct wlr_wl_input_device *)data; - struct wlr_input_device *wlr_dev = &input_device->wlr_input_device; - struct wlr_event_pointer_hold_begin wlr_event = { - .device = wlr_dev, - .time_msec = time, - .fingers = fingers, - }; - input_device->fingers = fingers; - wlr_signal_emit_safe(&wlr_dev->pointer->events.hold_begin, &wlr_event); -} - -static void gesture_hold_end(void *data, - struct zwp_pointer_gesture_hold_v1 *zwp_pointer_gesture_hold_v1, - uint32_t serial, uint32_t time, int32_t cancelled) { - struct wlr_wl_input_device *input_device = (struct wlr_wl_input_device *)data; - struct wlr_input_device *wlr_dev = &input_device->wlr_input_device; - struct wlr_event_pointer_hold_end wlr_event = { - .device = wlr_dev, - .time_msec = time, - .cancelled = cancelled, - }; - wlr_signal_emit_safe(&wlr_dev->pointer->events.hold_end, &wlr_event); -} - -static const struct zwp_pointer_gesture_hold_v1_listener gesture_hold_impl = { - .begin = gesture_hold_begin, - .end = gesture_hold_end, -}; - -static void relative_pointer_handle_relative_motion(void *data, - struct zwp_relative_pointer_v1 *relative_pointer, uint32_t utime_hi, - uint32_t utime_lo, wl_fixed_t dx, wl_fixed_t dy, wl_fixed_t dx_unaccel, - wl_fixed_t dy_unaccel) { - struct wlr_wl_input_device *input_device = data; - struct wlr_input_device *wlr_dev = &input_device->wlr_input_device; - if (pointer_get_wl(wlr_dev->pointer) != input_device->seat->active_pointer) { - return; - } - - uint64_t time_usec = (uint64_t)utime_hi << 32 | utime_lo; - - struct wlr_event_pointer_motion wlr_event = { - .device = wlr_dev, - .time_msec = (uint32_t)(time_usec / 1000), - .delta_x = wl_fixed_to_double(dx), - .delta_y = wl_fixed_to_double(dy), - .unaccel_dx = wl_fixed_to_double(dx_unaccel), - .unaccel_dy = wl_fixed_to_double(dy_unaccel), - }; - wlr_signal_emit_safe(&wlr_dev->pointer->events.motion, &wlr_event); -} - -static const struct zwp_relative_pointer_v1_listener relative_pointer_listener = { - .relative_motion = relative_pointer_handle_relative_motion, -}; - - -static void pointer_handle_output_destroy(struct wl_listener *listener, - void *data) { - struct wlr_wl_pointer *pointer = - wl_container_of(listener, pointer, output_destroy); - destroy_wl_input_device(pointer->input_device); -} - -void create_wl_pointer(struct wlr_wl_seat *seat, struct wlr_wl_output *output) { - assert(seat->pointer); - struct wl_pointer *wl_pointer = seat->pointer; - struct wlr_wl_backend *backend = output->backend; - - if (output_get_pointer(output, wl_pointer)) { - wlr_log(WLR_DEBUG, - "Pointer for seat %s and output %s already exists (ignoring)", - seat->name, output->wlr_output.name); - return; - } - - struct wlr_wl_pointer *pointer = calloc(1, sizeof(struct wlr_wl_pointer)); - if (pointer == NULL) { - wlr_log(WLR_ERROR, "Allocation failed"); - return; - } - pointer->wl_pointer = wl_pointer; - pointer->output = output; // we need output to map absolute coordinates onto - - struct wlr_wl_input_device *dev = - create_wl_input_device(seat, WLR_INPUT_DEVICE_POINTER); - if (dev == NULL) { - free(pointer); - wlr_log(WLR_ERROR, "Allocation failed"); - return; - } - pointer->input_device = dev; - - struct wlr_input_device *wlr_dev = &dev->wlr_input_device; - wlr_dev->pointer = &pointer->wlr_pointer; - wlr_dev->output_name = strdup(output->wlr_output.name); - - wlr_pointer_init(&pointer->wlr_pointer, &pointer_impl, wlr_dev->name); - - wl_signal_add(&output->wlr_output.events.destroy, &pointer->output_destroy); - pointer->output_destroy.notify = pointer_handle_output_destroy; - - if (backend->zwp_pointer_gestures_v1) { - uint32_t version = zwp_pointer_gestures_v1_get_version( - backend->zwp_pointer_gestures_v1); - - pointer->gesture_swipe = zwp_pointer_gestures_v1_get_swipe_gesture( - backend->zwp_pointer_gestures_v1, wl_pointer); - zwp_pointer_gesture_swipe_v1_add_listener(pointer->gesture_swipe, &gesture_swipe_impl, dev); - pointer->gesture_pinch = zwp_pointer_gestures_v1_get_pinch_gesture( - backend->zwp_pointer_gestures_v1, wl_pointer); - zwp_pointer_gesture_pinch_v1_add_listener(pointer->gesture_pinch, &gesture_pinch_impl, dev); - - if (version >= ZWP_POINTER_GESTURES_V1_GET_HOLD_GESTURE) { - pointer->gesture_hold = zwp_pointer_gestures_v1_get_hold_gesture( - backend->zwp_pointer_gestures_v1, wl_pointer); - zwp_pointer_gesture_hold_v1_add_listener(pointer->gesture_hold, &gesture_hold_impl, dev); - } - } - - if (backend->zwp_relative_pointer_manager_v1) { - pointer->relative_pointer = - zwp_relative_pointer_manager_v1_get_relative_pointer( - backend->zwp_relative_pointer_manager_v1, wl_pointer); - zwp_relative_pointer_v1_add_listener(pointer->relative_pointer, - &relative_pointer_listener, dev); - } - - wl_pointer_add_listener(wl_pointer, &pointer_listener, seat); - wlr_signal_emit_safe(&backend->backend.events.new_input, wlr_dev); -} - -void create_wl_keyboard(struct wlr_wl_seat *seat) { - assert(seat->keyboard); - struct wl_keyboard *wl_keyboard = seat->keyboard; - struct wlr_wl_input_device *dev = - create_wl_input_device(seat, WLR_INPUT_DEVICE_KEYBOARD); - if (!dev) { - return; - } - - struct wlr_input_device *wlr_dev = &dev->wlr_input_device; - wlr_dev->keyboard = calloc(1, sizeof(*wlr_dev->keyboard)); - if (!wlr_dev->keyboard) { - wlr_log_errno(WLR_ERROR, "Allocation failed"); - destroy_wl_input_device(dev); - return; - } - - wlr_keyboard_init(wlr_dev->keyboard, &keyboard_impl, wlr_dev->name); - - wl_keyboard_add_listener(wl_keyboard, &keyboard_listener, wlr_dev); - wlr_signal_emit_safe(&seat->backend->backend.events.new_input, wlr_dev); -} - -void create_wl_touch(struct wlr_wl_seat *seat) { - assert(seat->touch); - struct wl_touch *wl_touch = seat->touch; - struct wlr_wl_input_device *dev = - create_wl_input_device(seat, WLR_INPUT_DEVICE_TOUCH); - if (!dev) { - return; - } - - struct wlr_input_device *wlr_dev = &dev->wlr_input_device; - - wlr_dev->touch = calloc(1, sizeof(*wlr_dev->touch)); - if (!wlr_dev->touch) { - wlr_log_errno(WLR_ERROR, "Allocation failed"); - destroy_wl_input_device(dev); - return; - } - wlr_touch_init(wlr_dev->touch, &touch_impl, wlr_dev->name); - - wl_touch_add_listener(wl_touch, &touch_listener, dev); - wlr_signal_emit_safe(&seat->backend->backend.events.new_input, wlr_dev); -} - static void seat_handle_capabilities(void *data, struct wl_seat *wl_seat, enum wl_seat_capability caps) { struct wlr_wl_seat *seat = data; struct wlr_wl_backend *backend = seat->backend; - if ((caps & WL_SEAT_CAPABILITY_POINTER) && seat->pointer == NULL) { - wlr_log(WLR_DEBUG, "seat %p offered pointer", (void *)wl_seat); + if ((caps & WL_SEAT_CAPABILITY_POINTER) && seat->wl_pointer == NULL) { + wlr_log(WLR_DEBUG, "seat '%s' offering pointer", seat->name); - struct wl_pointer *wl_pointer = wl_seat_get_pointer(wl_seat); - seat->pointer = wl_pointer; - - struct wlr_wl_output *output; - wl_list_for_each(output, &backend->outputs, link) { - create_wl_pointer(seat, output); - } + seat->wl_pointer = wl_seat_get_pointer(wl_seat); + init_seat_pointer(seat); } - if (!(caps & WL_SEAT_CAPABILITY_POINTER) && seat->pointer != NULL) { - wlr_log(WLR_DEBUG, "seat %p dropped pointer", (void *)wl_seat); - - struct wl_pointer *wl_pointer = seat->pointer; - - struct wlr_wl_input_device *device, *tmp; - wl_list_for_each_safe(device, tmp, &backend->devices, link) { - if (device->wlr_input_device.type != WLR_INPUT_DEVICE_POINTER) { - continue; - } - struct wlr_wl_pointer *pointer = - pointer_get_wl(device->wlr_input_device.pointer); - if (pointer->wl_pointer != wl_pointer) { - continue; - } - wlr_log(WLR_DEBUG, "dropping pointer %s", - pointer->input_device->wlr_input_device.name); - struct wlr_wl_output *output = pointer->output; - destroy_wl_input_device(device); - assert(seat->active_pointer != pointer); - assert(output->cursor.pointer != pointer); - } - - wl_pointer_release(seat->pointer); - seat->pointer = NULL; + if (!(caps & WL_SEAT_CAPABILITY_POINTER) && seat->wl_pointer != NULL) { + wlr_log(WLR_DEBUG, "seat '%s' dropping pointer", seat->name); + finish_seat_pointer(seat); } - if ((caps & WL_SEAT_CAPABILITY_KEYBOARD) && seat->keyboard == NULL) { - wlr_log(WLR_DEBUG, "seat %p offered keyboard", (void *)wl_seat); + if ((caps & WL_SEAT_CAPABILITY_KEYBOARD) && seat->wl_keyboard == NULL) { + wlr_log(WLR_DEBUG, "seat '%s' offering keyboard", seat->name); struct wl_keyboard *wl_keyboard = wl_seat_get_keyboard(wl_seat); - seat->keyboard = wl_keyboard; + seat->wl_keyboard = wl_keyboard; if (backend->started) { - create_wl_keyboard(seat); + init_seat_keyboard(seat); } } - if (!(caps & WL_SEAT_CAPABILITY_KEYBOARD) && seat->keyboard != NULL) { - wlr_log(WLR_DEBUG, "seat %p dropped keyboard", (void *)wl_seat); + if (!(caps & WL_SEAT_CAPABILITY_KEYBOARD) && seat->wl_keyboard != NULL) { + wlr_log(WLR_DEBUG, "seat '%s' dropping keyboard", seat->name); - struct wlr_wl_input_device *device, *tmp; - wl_list_for_each_safe(device, tmp, &backend->devices, link) { - if (device->wlr_input_device.type != WLR_INPUT_DEVICE_KEYBOARD) { - continue; - } + wl_keyboard_release(seat->wl_keyboard); + wlr_keyboard_finish(&seat->wlr_keyboard); - if (device->seat != seat) { - continue; - } - destroy_wl_input_device(device); - } - assert(seat->keyboard == NULL); // free'ed by input_device_destroy + seat->wl_keyboard = NULL; } - if ((caps & WL_SEAT_CAPABILITY_TOUCH) && seat->touch == NULL) { - wlr_log(WLR_DEBUG, "seat %p offered touch", (void *)wl_seat); + if ((caps & WL_SEAT_CAPABILITY_TOUCH) && seat->wl_touch == NULL) { + wlr_log(WLR_DEBUG, "seat '%s' offering touch", seat->name); - seat->touch = wl_seat_get_touch(wl_seat); + seat->wl_touch = wl_seat_get_touch(wl_seat); if (backend->started) { - create_wl_touch(seat); + init_seat_touch(seat); } } - if (!(caps & WL_SEAT_CAPABILITY_TOUCH) && seat->touch != NULL) { - wlr_log(WLR_DEBUG, "seat %p dropped touch", (void *)wl_seat); + if (!(caps & WL_SEAT_CAPABILITY_TOUCH) && seat->wl_touch != NULL) { + wlr_log(WLR_DEBUG, "seat '%s' dropping touch", seat->name); - struct wlr_wl_input_device *device, *tmp; - wl_list_for_each_safe(device, tmp, &backend->devices, link) { - if (device->wlr_input_device.type == WLR_INPUT_DEVICE_TOUCH) { - destroy_wl_input_device(device); - } - } - - wl_touch_release(seat->touch); - seat->touch = NULL; + wl_touch_release(seat->wl_touch); + wlr_touch_finish(&seat->wlr_touch); + seat->wl_touch = NULL; } } @@ -934,11 +352,7 @@ static void seat_handle_name(void *data, struct wl_seat *wl_seat, seat->name = strdup(name); } -const struct wl_seat_listener seat_listener = { +static const struct wl_seat_listener seat_listener = { .capabilities = seat_handle_capabilities, .name = seat_handle_name, }; - -struct wl_seat *wlr_wl_input_device_get_seat(struct wlr_input_device *wlr_dev) { - return input_device_get_seat(wlr_dev)->wl_seat; -} diff --git a/backend/wayland/tablet_v2.c b/backend/wayland/tablet_v2.c index 95cdd119d..d1aeecd27 100644 --- a/backend/wayland/tablet_v2.c +++ b/backend/wayland/tablet_v2.c @@ -1,35 +1,24 @@ -#ifndef _POSIX_C_SOURCE #define _POSIX_C_SOURCE 200809L -#endif -#include #include #include #include #include #include #include -#include - -#include "util/signal.h" -#include "util/time.h" -#include "wlr/util/log.h" -#include "tablet-unstable-v2-client-protocol.h" +#include #include "backend/wayland.h" +#include "util/time.h" -struct wlr_wl_tablet_seat { - struct zwp_tablet_seat_v2 *tablet_seat; -}; +#include "tablet-unstable-v2-client-protocol.h" -struct wlr_wl_tablet_tool { +struct tablet_tool { /* static */ - struct zwp_tablet_tool_v2 *tool; - struct wlr_tablet_tool wlr_tool; + struct wlr_wl_seat *seat; /* semi-static */ struct wlr_wl_output *output; - struct wlr_wl_input_device *tablet; double pre_x, pre_y; /* per frame */ @@ -49,11 +38,11 @@ struct wlr_wl_tablet_tool { bool is_down; }; -struct wlr_wl_tablet_pad_ring { - struct wl_list link; // wlr_wl_tablet_pad_group::rings +struct tablet_pad_ring { + struct wl_list link; // tablet_pad_group::rings /* static */ struct zwp_tablet_pad_ring_v2 *ring; - struct wlr_wl_tablet_pad_group *group; + struct tablet_pad_group *group; size_t index; /* per frame */ @@ -62,10 +51,10 @@ struct wlr_wl_tablet_pad_ring { bool stopped; }; -struct wlr_wl_tablet_pad_strip { - struct wl_list link; // wlr_wl_tablet_pad_group::strips +struct tablet_pad_strip { + struct wl_list link; // tablet_pad_group::strips struct zwp_tablet_pad_strip_v2 *strip; - struct wlr_wl_tablet_pad_group *group; + struct tablet_pad_group *group; size_t index; enum wlr_tablet_pad_strip_source source; @@ -73,43 +62,43 @@ struct wlr_wl_tablet_pad_strip { bool stopped; }; -struct wlr_wl_tablet_pad_group { +struct tablet_pad_group { struct zwp_tablet_pad_group_v2 *pad_group; struct wlr_tablet_pad *pad; unsigned int mode; struct wlr_tablet_pad_group group; - struct wl_list rings; // wlr_wl_tablet_pad_ring::link - struct wl_list strips; // wlr_wl_tablet_pad_strips::link + struct wl_list rings; // tablet_pad_ring::link + struct wl_list strips; // tablet_pad_strips::link }; static void handle_tablet_pad_ring_source(void *data, struct zwp_tablet_pad_ring_v2 *zwp_tablet_pad_ring_v2, uint32_t source) { - struct wlr_wl_tablet_pad_ring *ring = data; + struct tablet_pad_ring *ring = data; ring->source = source; } static void handle_tablet_pad_ring_angle(void *data, struct zwp_tablet_pad_ring_v2 *zwp_tablet_pad_ring_v2, wl_fixed_t degrees) { - struct wlr_wl_tablet_pad_ring *ring = data; + struct tablet_pad_ring *ring = data; ring->angle = wl_fixed_to_double(degrees); } static void handle_tablet_pad_ring_stop(void *data, struct zwp_tablet_pad_ring_v2 *zwp_tablet_pad_ring_v2) { - struct wlr_wl_tablet_pad_ring *ring = data; + struct tablet_pad_ring *ring = data; ring->stopped = true; } static void handle_tablet_pad_ring_frame(void *data, struct zwp_tablet_pad_ring_v2 *zwp_tablet_pad_ring_v2, uint32_t time) { - struct wlr_wl_tablet_pad_ring *ring = data; + struct tablet_pad_ring *ring = data; - struct wlr_event_tablet_pad_ring evt = { + struct wlr_tablet_pad_ring_event evt = { .time_msec = time, .source = ring->source, .ring = ring->index, @@ -118,11 +107,11 @@ static void handle_tablet_pad_ring_frame(void *data, }; if (ring->angle >= 0) { - wlr_signal_emit_safe(&ring->group->pad->events.ring, &evt); + wl_signal_emit_mutable(&ring->group->pad->events.ring, &evt); } if (ring->stopped) { evt.position = -1; - wlr_signal_emit_safe(&ring->group->pad->events.ring, &evt); + wl_signal_emit_mutable(&ring->group->pad->events.ring, &evt); } ring->angle = -1; @@ -140,29 +129,29 @@ static const struct zwp_tablet_pad_ring_v2_listener tablet_pad_ring_listener = { static void handle_tablet_pad_strip_source(void *data, struct zwp_tablet_pad_strip_v2 *zwp_tablet_pad_strip_v2, uint32_t source) { - struct wlr_wl_tablet_pad_strip *strip = data; + struct tablet_pad_strip *strip = data; strip->source = source; } static void handle_tablet_pad_strip_position(void *data, struct zwp_tablet_pad_strip_v2 *zwp_tablet_pad_strip_v2, uint32_t position) { - struct wlr_wl_tablet_pad_strip *strip = data; + struct tablet_pad_strip *strip = data; strip->position = (double) position / 65536.0; } static void handle_tablet_pad_strip_stop(void *data, struct zwp_tablet_pad_strip_v2 *zwp_tablet_pad_strip_v2) { - struct wlr_wl_tablet_pad_strip *strip = data; + struct tablet_pad_strip *strip = data; strip->stopped = true; } static void handle_tablet_pad_strip_frame(void *data, struct zwp_tablet_pad_strip_v2 *zwp_tablet_pad_strip_v2, uint32_t time) { - struct wlr_wl_tablet_pad_strip *strip = data; + struct tablet_pad_strip *strip = data; - struct wlr_event_tablet_pad_strip evt = { + struct wlr_tablet_pad_strip_event evt = { .time_msec = time, .source = strip->source, .strip = strip->index, @@ -171,11 +160,11 @@ static void handle_tablet_pad_strip_frame(void *data, }; if (strip->position >= 0) { - wlr_signal_emit_safe(&strip->group->pad->events.strip, &evt); + wl_signal_emit_mutable(&strip->group->pad->events.strip, &evt); } if (strip->stopped) { evt.position = -1; - wlr_signal_emit_safe(&strip->group->pad->events.strip, &evt); + wl_signal_emit_mutable(&strip->group->pad->events.strip, &evt); } strip->position = -1; @@ -193,7 +182,7 @@ static const struct zwp_tablet_pad_strip_v2_listener tablet_pad_strip_listener = static void handle_tablet_pad_group_buttons(void *data, struct zwp_tablet_pad_group_v2 *pad_group, struct wl_array *buttons) { - struct wlr_wl_tablet_pad_group *group = data; + struct tablet_pad_group *group = data; free(group->group.buttons); group->group.buttons = calloc(1, buttons->size); @@ -208,7 +197,7 @@ static void handle_tablet_pad_group_buttons(void *data, static void handle_tablet_pad_group_modes(void *data, struct zwp_tablet_pad_group_v2 *pad_group, uint32_t modes) { - struct wlr_wl_tablet_pad_group *group = data; + struct tablet_pad_group *group = data; group->group.mode_count = modes; } @@ -216,9 +205,9 @@ static void handle_tablet_pad_group_modes(void *data, static void handle_tablet_pad_group_ring(void *data, struct zwp_tablet_pad_group_v2 *pad_group, struct zwp_tablet_pad_ring_v2 *ring) { - struct wlr_wl_tablet_pad_group *group = data; - struct wlr_wl_tablet_pad_ring *tablet_ring = - calloc(1, sizeof(struct wlr_wl_tablet_pad_ring)); + struct tablet_pad_group *group = data; + struct tablet_pad_ring *tablet_ring = + calloc(1, sizeof(struct tablet_pad_ring)); if (!tablet_ring) { zwp_tablet_pad_ring_v2_destroy(ring); return; @@ -237,9 +226,9 @@ static void handle_tablet_pad_group_ring(void *data, static void handle_tablet_pad_group_strip(void *data, struct zwp_tablet_pad_group_v2 *pad_group, struct zwp_tablet_pad_strip_v2 *strip) { - struct wlr_wl_tablet_pad_group *group = data; - struct wlr_wl_tablet_pad_strip *tablet_strip = - calloc(1, sizeof(struct wlr_wl_tablet_pad_strip)); + struct tablet_pad_group *group = data; + struct tablet_pad_strip *tablet_strip = + calloc(1, sizeof(struct tablet_pad_strip)); if (!tablet_strip) { zwp_tablet_pad_strip_v2_destroy(strip); return; @@ -263,25 +252,20 @@ static void handle_tablet_pad_group_done(void *data, static void handle_tablet_pad_group_mode_switch(void *data, struct zwp_tablet_pad_group_v2 *pad_group, uint32_t time, uint32_t serial, uint32_t mode) { - struct wlr_wl_tablet_pad_group *group = data; + struct tablet_pad_group *group = data; group->mode = mode; } -/* This isn't in the listener, but keep the naming scheme around since the - * other removed functions work like this, and pad sub-resources are just a bit - * special */ -static void handle_tablet_pad_group_removed( - struct wlr_wl_tablet_pad_group *group) { - +static void destroy_tablet_pad_group(struct tablet_pad_group *group) { /* No need to remove the ::link on strips rings as long as we do *not* * wl_list_remove on the wl_groups ring/strip attributes here */ - struct wlr_wl_tablet_pad_ring *ring, *tmp_ring; + struct tablet_pad_ring *ring, *tmp_ring; wl_list_for_each_safe(ring, tmp_ring, &group->rings, link) { zwp_tablet_pad_ring_v2_destroy(ring->ring); free(ring); } - struct wlr_wl_tablet_pad_strip *strip, *tmp_strip; + struct tablet_pad_strip *strip, *tmp_strip; wl_list_for_each_safe(strip, tmp_strip, &group->strips, link) { zwp_tablet_pad_strip_v2_destroy(strip->strip); free(strip); @@ -289,10 +273,11 @@ static void handle_tablet_pad_group_removed( zwp_tablet_pad_group_v2_destroy(group->pad_group); - /* While I'm pretty sure we have control over this as well, it's - * outside the scope of a single function, so better be safe than - * sorry */ + free(group->group.buttons); + free(group->group.strips); + free(group->group.rings); wl_list_remove(&group->group.link); + free(group); } @@ -308,12 +293,13 @@ static const struct zwp_tablet_pad_group_v2_listener tablet_pad_group_listener = static void handle_tablet_pad_group(void *data, struct zwp_tablet_pad_v2 *zwp_tablet_pad, struct zwp_tablet_pad_group_v2 *pad_group) { - struct wlr_wl_input_device *dev = data; - struct wlr_tablet_pad *pad = dev->wlr_input_device.tablet_pad; + struct wlr_wl_seat *seat = data; + struct wlr_tablet_pad *pad = &seat->wlr_tablet_pad; - struct wlr_wl_tablet_pad_group *group = - calloc(1, sizeof(struct wlr_wl_tablet_pad_group)); + struct tablet_pad_group *group = + calloc(1, sizeof(struct tablet_pad_group)); if (!group) { + wlr_log_errno(WLR_ERROR, "failed to allocate tablet_pad_group"); zwp_tablet_pad_group_v2_destroy(pad_group); return; } @@ -330,20 +316,18 @@ static void handle_tablet_pad_group(void *data, } static void handle_tablet_pad_path(void *data, - struct zwp_tablet_pad_v2 *zwp_tablet_pad_v2, - const char *path) { - struct wlr_wl_input_device *dev = data; - struct wlr_tablet_pad *tablet_pad = dev->wlr_input_device.tablet_pad; + struct zwp_tablet_pad_v2 *zwp_tablet_pad_v2, const char *path) { + struct wlr_wl_seat *seat = data; + struct wlr_tablet_pad *tablet_pad = &seat->wlr_tablet_pad; char **dst = wl_array_add(&tablet_pad->paths, sizeof(char *)); *dst = strdup(path); } static void handle_tablet_pad_buttons(void *data, - struct zwp_tablet_pad_v2 *zwp_tablet_pad_v2, - uint32_t buttons) { - struct wlr_wl_input_device *dev = data; - struct wlr_tablet_pad *tablet_pad = dev->wlr_input_device.tablet_pad; + struct zwp_tablet_pad_v2 *zwp_tablet_pad_v2, uint32_t buttons) { + struct wlr_wl_seat *seat = data; + struct wlr_tablet_pad *tablet_pad = &seat->wlr_tablet_pad; tablet_pad->button_count = buttons; } @@ -351,10 +335,8 @@ static void handle_tablet_pad_buttons(void *data, static void handle_tablet_pad_button(void *data, struct zwp_tablet_pad_v2 *zwp_tablet_pad_v2, uint32_t time, uint32_t button, uint32_t state) { - struct wlr_wl_input_device *dev = data; - struct wlr_tablet_pad *tablet_pad = dev->wlr_input_device.tablet_pad; - - struct wlr_event_tablet_pad_button evt = { + struct wlr_wl_seat *seat = data; + struct wlr_tablet_pad_button_event evt = { .time_msec = time, .button = button, .state = state, @@ -362,28 +344,25 @@ static void handle_tablet_pad_button(void *data, .group = 0, }; - wlr_signal_emit_safe(&tablet_pad->events.button, &evt); + wl_signal_emit_mutable(&seat->wlr_tablet_pad.events.button, &evt); } static void handle_tablet_pad_done(void *data, struct zwp_tablet_pad_v2 *zwp_tablet_pad_v2) { - struct wlr_wl_input_device *dev = data; - - wlr_signal_emit_safe(&dev->backend->backend.events.new_input, - &dev->wlr_input_device); + struct wlr_wl_seat *seat = data; + wl_signal_emit_mutable(&seat->backend->backend.events.new_input, + &seat->wlr_tablet_pad.base); } static void handle_tablet_pad_enter(void *data, struct zwp_tablet_pad_v2 *zwp_tablet_pad_v2, uint32_t serial, struct zwp_tablet_v2 *tablet_p, struct wl_surface *surface) { - struct wlr_wl_input_device *dev = data; - struct wlr_tablet_pad *tablet_pad = dev->wlr_input_device.tablet_pad; - struct wlr_wl_input_device *tab_dev = zwp_tablet_v2_get_user_data(tablet_p); - struct wlr_input_device *tablet = &tab_dev->wlr_input_device; - wlr_log(WLR_DEBUG, "Tablet: %p\n", tablet); + struct wlr_wl_seat *seat = data; + assert(seat->zwp_tablet_v2 == tablet_p); - wlr_signal_emit_safe(&tablet_pad->events.attach_tablet, tablet); + wl_signal_emit_mutable(&seat->wlr_tablet_pad.events.attach_tablet, + &seat->wlr_tablet_tool); } static void handle_tablet_pad_leave(void *data, @@ -395,23 +374,17 @@ static void handle_tablet_pad_leave(void *data, static void handle_tablet_pad_removed(void *data, struct zwp_tablet_pad_v2 *zwp_tablet_pad_v2) { - struct wlr_wl_input_device *dev = data; - struct wlr_tablet_pad *tablet_pad = dev->wlr_input_device.tablet_pad; + struct wlr_wl_seat *seat = data; - /* This doesn't free anything, but emits the destroy signal */ - wlr_input_device_destroy(&dev->wlr_input_device); - /* This is a bit ugly, but we need to remove it from our list */ - wl_list_remove(&dev->link); - - struct wlr_wl_tablet_pad_group *group, *it; + struct wlr_tablet_pad *tablet_pad = &seat->wlr_tablet_pad; + struct tablet_pad_group *group, *it; wl_list_for_each_safe(group, it, &tablet_pad->groups, group.link) { - handle_tablet_pad_group_removed(group); + destroy_tablet_pad_group(group); } - /* This frees */ - wlr_tablet_pad_destroy(tablet_pad); - zwp_tablet_pad_v2_destroy(dev->resource); - free(dev); + wlr_tablet_pad_finish(tablet_pad); + zwp_tablet_pad_v2_destroy(seat->zwp_tablet_pad_v2); + seat->zwp_tablet_pad_v2 = NULL; } static const struct zwp_tablet_pad_v2_listener tablet_pad_listener = { @@ -425,37 +398,25 @@ static const struct zwp_tablet_pad_v2_listener tablet_pad_listener = { .removed = handle_tablet_pad_removed, }; -const struct wlr_tablet_pad_impl tablet_pad_impl = {0}; +const struct wlr_tablet_pad_impl wl_tablet_pad_impl = { + .name = "wl-tablet-pad", +}; static void handle_pad_added(void *data, struct zwp_tablet_seat_v2 *zwp_tablet_seat_v2, - struct zwp_tablet_pad_v2 *id) { - wlr_log(WLR_DEBUG, "New tablet pad"); + struct zwp_tablet_pad_v2 *zwp_tablet_pad_v2) { struct wlr_wl_seat *seat = data; - struct wlr_wl_input_device *dev = create_wl_input_device( - seat, WLR_INPUT_DEVICE_TABLET_PAD); - if (!dev) { - /* This leaks a couple of server-sent resource ids. iirc this - * shouldn't ever be a problem, but it isn't exactly nice - * either. */ - zwp_tablet_pad_v2_destroy(id); + if (seat->zwp_tablet_pad_v2 != NULL) { + wlr_log(WLR_ERROR, "zwp_tablet_pad_v2 is already present"); return; } - dev->resource = id; - struct wlr_input_device *wlr_dev = &dev->wlr_input_device; - wlr_dev->tablet_pad = calloc(1, sizeof(*wlr_dev->tablet_pad)); + seat->zwp_tablet_pad_v2 = zwp_tablet_pad_v2; + zwp_tablet_pad_v2_add_listener(zwp_tablet_pad_v2, &tablet_pad_listener, + seat); - if (!wlr_dev->tablet_pad) { - /* This leaks a couple of server-sent resource ids. iirc this - * shouldn't ever be a problem, but it isn't exactly nice - * either. */ - free(dev); - zwp_tablet_pad_v2_destroy(id); - return; - } - wlr_tablet_pad_init(wlr_dev->tablet_pad, &tablet_pad_impl, wlr_dev->name); - zwp_tablet_pad_v2_add_listener(id, &tablet_pad_listener, dev); + wlr_tablet_pad_init(&seat->wlr_tablet_pad, &wl_tablet_pad_impl, + "wlr_tablet_v2"); } static void handle_tablet_tool_done(void *data, @@ -463,7 +424,8 @@ static void handle_tablet_tool_done(void *data, /* empty */ } -static enum wlr_tablet_tool_type tablet_type_to_wlr_type(enum zwp_tablet_tool_v2_type type) { +static enum wlr_tablet_tool_type tablet_type_to_wlr_type( + enum zwp_tablet_tool_v2_type type) { switch (type) { case ZWP_TABLET_TOOL_V2_TYPE_PEN: return WLR_TABLET_TOOL_TYPE_PEN; @@ -488,94 +450,85 @@ static enum wlr_tablet_tool_type tablet_type_to_wlr_type(enum zwp_tablet_tool_v2 } static void handle_tablet_tool_type(void *data, - struct zwp_tablet_tool_v2 *id, - uint32_t tool_type) { - struct wlr_wl_tablet_tool *tool = data; - - tool->wlr_tool.type = tablet_type_to_wlr_type(tool_type); + struct zwp_tablet_tool_v2 *id, uint32_t tool_type) { + struct tablet_tool *tool = data; + struct wlr_tablet_tool *wlr_tool = &tool->seat->wlr_tablet_tool; + wlr_tool->type = tablet_type_to_wlr_type(tool_type); } static void handle_tablet_tool_serial(void *data, - struct zwp_tablet_tool_v2 *id, - uint32_t high, uint32_t low) { - struct wlr_wl_tablet_tool *tool = data; - - tool->wlr_tool.hardware_serial = - ((uint64_t) high) << 32 | (uint64_t) low; + struct zwp_tablet_tool_v2 *id, uint32_t high, uint32_t low) { + struct tablet_tool *tool = data; + struct wlr_tablet_tool *wlr_tool = &tool->seat->wlr_tablet_tool; + wlr_tool->hardware_serial = ((uint64_t) high) << 32 | (uint64_t) low; } static void handle_tablet_tool_id_wacom(void *data, - struct zwp_tablet_tool_v2 *id, - uint32_t high, uint32_t low) { - struct wlr_wl_tablet_tool *tool = data; - - tool->wlr_tool.hardware_wacom = - ((uint64_t) high) << 32 | (uint64_t) low; + struct zwp_tablet_tool_v2 *id, uint32_t high, uint32_t low) { + struct tablet_tool *tool = data; + struct wlr_tablet_tool *wlr_tool = &tool->seat->wlr_tablet_tool; + wlr_tool->hardware_wacom = ((uint64_t) high) << 32 | (uint64_t) low; } static void handle_tablet_tool_capability(void *data, - struct zwp_tablet_tool_v2 *id, - uint32_t capability) { - struct wlr_wl_tablet_tool *tool = data; + struct zwp_tablet_tool_v2 *id, uint32_t capability) { + struct tablet_tool *tool = data; + struct wlr_tablet_tool *wlr_tool = &tool->seat->wlr_tablet_tool; - enum zwp_tablet_tool_v2_capability cap = capability; - - switch (cap) { + /* One event is sent for each capability */ + switch (capability) { case ZWP_TABLET_TOOL_V2_CAPABILITY_TILT: - tool->wlr_tool.tilt = true; + wlr_tool->tilt = true; break; case ZWP_TABLET_TOOL_V2_CAPABILITY_PRESSURE: - tool->wlr_tool.pressure = true; + wlr_tool->pressure = true; break; case ZWP_TABLET_TOOL_V2_CAPABILITY_DISTANCE: - tool->wlr_tool.distance = true; + wlr_tool->distance = true; break; case ZWP_TABLET_TOOL_V2_CAPABILITY_ROTATION: - tool->wlr_tool.rotation = true; + wlr_tool->rotation = true; break; case ZWP_TABLET_TOOL_V2_CAPABILITY_SLIDER: - tool->wlr_tool.slider = true; + wlr_tool->slider = true; break; case ZWP_TABLET_TOOL_V2_CAPABILITY_WHEEL: - tool->wlr_tool.wheel = true; + wlr_tool->wheel = true; break; } } static void handle_tablet_tool_proximity_in(void *data, struct zwp_tablet_tool_v2 *id, uint32_t serial, - struct zwp_tablet_v2 *tablet_id, - struct wl_surface *surface) { - struct wlr_wl_tablet_tool *tool = data; + struct zwp_tablet_v2 *tablet_id, struct wl_surface *surface) { + struct tablet_tool *tool = data; + assert(tablet_id == tool->seat->zwp_tablet_v2); + tool->is_in = true; - tool->tablet = zwp_tablet_v2_get_user_data(tablet_id); tool->output = wl_surface_get_user_data(surface); } static void handle_tablet_tool_proximity_out(void *data, struct zwp_tablet_tool_v2 *id) { - struct wlr_wl_tablet_tool *tool = data; + struct tablet_tool *tool = data; tool->is_out = true; tool->output = NULL; } -static void handle_tablet_tool_down(void *data, - struct zwp_tablet_tool_v2 *id, +static void handle_tablet_tool_down(void *data, struct zwp_tablet_tool_v2 *id, unsigned int serial) { - struct wlr_wl_tablet_tool *tool = data; + struct tablet_tool *tool = data; tool->is_down = true; } -static void handle_tablet_tool_up(void *data, - struct zwp_tablet_tool_v2 *id) { - struct wlr_wl_tablet_tool *tool = data; +static void handle_tablet_tool_up(void *data, struct zwp_tablet_tool_v2 *id) { + struct tablet_tool *tool = data; tool->is_up = true; } -static void handle_tablet_tool_motion(void *data, - struct zwp_tablet_tool_v2 *id, +static void handle_tablet_tool_motion(void *data, struct zwp_tablet_tool_v2 *id, wl_fixed_t x, wl_fixed_t y) { - struct wlr_wl_tablet_tool *tool = data; + struct tablet_tool *tool = data; struct wlr_wl_output *output = tool->output; assert(output); @@ -584,68 +537,63 @@ static void handle_tablet_tool_motion(void *data, } static void handle_tablet_tool_pressure(void *data, - struct zwp_tablet_tool_v2 *id, - uint32_t pressure) { - struct wlr_wl_tablet_tool *tool = data; + struct zwp_tablet_tool_v2 *id, uint32_t pressure) { + struct tablet_tool *tool = data; tool->pressure = (double) pressure / 65535.0; } static void handle_tablet_tool_distance(void *data, - struct zwp_tablet_tool_v2 *id, - uint32_t distance) { - struct wlr_wl_tablet_tool *tool = data; + struct zwp_tablet_tool_v2 *id, uint32_t distance) { + struct tablet_tool *tool = data; tool->distance = (double) distance / 65535.0; } -static void handle_tablet_tool_tilt(void *data, - struct zwp_tablet_tool_v2 *id, +static void handle_tablet_tool_tilt(void *data, struct zwp_tablet_tool_v2 *id, wl_fixed_t x, wl_fixed_t y) { - struct wlr_wl_tablet_tool *tool = data; + struct tablet_tool *tool = data; tool->tilt_x = wl_fixed_to_double(x); tool->tilt_y = wl_fixed_to_double(y); } static void handle_tablet_tool_rotation(void *data, - struct zwp_tablet_tool_v2 *id, - wl_fixed_t rotation) { - struct wlr_wl_tablet_tool *tool = data; + struct zwp_tablet_tool_v2 *id, wl_fixed_t rotation) { + struct tablet_tool *tool = data; tool->rotation = wl_fixed_to_double(rotation); } -static void handle_tablet_tool_slider(void *data, - struct zwp_tablet_tool_v2 *id, +static void handle_tablet_tool_slider(void *data, struct zwp_tablet_tool_v2 *id, int slider) { - struct wlr_wl_tablet_tool *tool = data; + struct tablet_tool *tool = data; tool->slider = (double) slider / 65535.0;; } // TODO: This looks wrong :/ -static void handle_tablet_tool_wheel(void *data, - struct zwp_tablet_tool_v2 *id, +static void handle_tablet_tool_wheel(void *data, struct zwp_tablet_tool_v2 *id, wl_fixed_t degree, int clicks) { - struct wlr_wl_tablet_tool *tool = data; + struct tablet_tool *tool = data; tool->wheel_delta = wl_fixed_to_double(degree); } static void handle_tablet_tool_button(void *data, struct zwp_tablet_tool_v2 *id, uint32_t serial, uint32_t button, uint32_t state) { - struct wlr_wl_tablet_tool *tool = data; - struct wlr_tablet *tablet = tool->tablet->wlr_input_device.tablet; + struct tablet_tool *tool = data; + struct wlr_wl_seat *seat = tool->seat; + struct wlr_tablet *tablet = &seat->wlr_tablet; - struct wlr_event_tablet_tool_button evt = { - .device = &tool->tablet->wlr_input_device, - .tool = &tool->wlr_tool, + struct wlr_tablet_tool_button_event evt = { + .tablet = tablet, + .tool = &seat->wlr_tablet_tool, .time_msec = get_current_time_msec(), .button = button, .state = state == ZWP_TABLET_TOOL_V2_BUTTON_STATE_RELEASED ? WLR_BUTTON_RELEASED : WLR_BUTTON_PRESSED, }; - wlr_signal_emit_safe(&tablet->events.button, &evt); + wl_signal_emit_mutable(&tablet->events.button, &evt); } -static void clear_tablet_tool_values(struct wlr_wl_tablet_tool *tool) { +static void clear_tablet_tool_values(struct tablet_tool *tool) { tool->is_out = tool->is_in = false; tool->is_up = tool->is_down = false; tool->x = tool->y = NAN; @@ -660,31 +608,33 @@ static void clear_tablet_tool_values(struct wlr_wl_tablet_tool *tool) { static void handle_tablet_tool_frame(void *data, struct zwp_tablet_tool_v2 *id, uint32_t time) { - struct wlr_wl_tablet_tool *tool = data; + struct tablet_tool *tool = data; + struct wlr_wl_seat *seat = tool->seat; + if (tool->is_out && tool->is_in) { /* we got a tablet tool coming in and out of proximity before * we could process it. Just ignore anything it did */ goto clear_values; } - struct wlr_tablet *tablet = tool->tablet->wlr_input_device.tablet; + struct wlr_tablet *tablet = &seat->wlr_tablet; if (tool->is_in) { - struct wlr_event_tablet_tool_proximity evt = { - .device = &tool->tablet->wlr_input_device, - .tool = &tool->wlr_tool, + struct wlr_tablet_tool_proximity_event evt = { + .tablet = tablet, + .tool = &seat->wlr_tablet_tool, .time_msec = time, .x = tool->x, .y = tool->y, .state = WLR_TABLET_TOOL_PROXIMITY_IN, }; - wlr_signal_emit_safe(&tablet->events.proximity, &evt); + wl_signal_emit_mutable(&tablet->events.proximity, &evt); } { - struct wlr_event_tablet_tool_axis evt = { - .device = &tool->tablet->wlr_input_device, - .tool = &tool->wlr_tool, + struct wlr_tablet_tool_axis_event evt = { + .tablet = tablet, + .tool = &seat->wlr_tablet_tool, .time_msec = time, .updated_axes = 0, }; @@ -735,7 +685,7 @@ static void handle_tablet_tool_frame(void *data, } if (evt.updated_axes) { - wlr_signal_emit_safe(&tablet->events.axis, &evt); + wl_signal_emit_mutable(&tablet->events.axis, &evt); } } @@ -745,42 +695,42 @@ static void handle_tablet_tool_frame(void *data, * Downside: Here we have the frame time, if we sent right away, we * need to generate the time */ if (tool->is_down) { - struct wlr_event_tablet_tool_tip evt = { - .device = &tool->tablet->wlr_input_device, - .tool = &tool->wlr_tool, + struct wlr_tablet_tool_tip_event evt = { + .tablet = tablet, + .tool = &seat->wlr_tablet_tool, .time_msec = time, .x = tool->x, .y = tool->y, .state = WLR_TABLET_TOOL_TIP_DOWN, }; - wlr_signal_emit_safe(&tablet->events.tip, &evt); + wl_signal_emit_mutable(&tablet->events.tip, &evt); } if (tool->is_up) { - struct wlr_event_tablet_tool_tip evt = { - .device = &tool->tablet->wlr_input_device, - .tool = &tool->wlr_tool, + struct wlr_tablet_tool_tip_event evt = { + .tablet = tablet, + .tool = &seat->wlr_tablet_tool, .time_msec = time, .x = tool->x, .y = tool->y, .state = WLR_TABLET_TOOL_TIP_UP, }; - wlr_signal_emit_safe(&tablet->events.tip, &evt); + wl_signal_emit_mutable(&tablet->events.tip, &evt); } if (tool->is_out) { - struct wlr_event_tablet_tool_proximity evt = { - .device = &tool->tablet->wlr_input_device, - .tool = &tool->wlr_tool, + struct wlr_tablet_tool_proximity_event evt = { + .tablet = tablet, + .tool = &seat->wlr_tablet_tool, .time_msec = time, .x = tool->x, .y = tool->y, .state = WLR_TABLET_TOOL_PROXIMITY_OUT, }; - wlr_signal_emit_safe(&tablet->events.proximity, &evt); + wl_signal_emit_mutable(&tablet->events.proximity, &evt); } clear_values: @@ -789,10 +739,12 @@ clear_values: static void handle_tablet_tool_removed(void *data, struct zwp_tablet_tool_v2 *id) { - struct wlr_wl_tablet_tool *tool = data; + struct tablet_tool *tool = data; + struct wlr_wl_seat *seat = tool->seat; + + zwp_tablet_tool_v2_destroy(seat->zwp_tablet_tool_v2); + seat->zwp_tablet_tool_v2 = NULL; - zwp_tablet_tool_v2_destroy(tool->tool); - wlr_signal_emit_safe(&tool->wlr_tool.events.destroy, &tool->wlr_tool); free(tool); } @@ -822,62 +774,71 @@ static const struct zwp_tablet_tool_v2_listener tablet_tool_listener = { static void handle_tool_added(void *data, struct zwp_tablet_seat_v2 *zwp_tablet_seat_v2, - struct zwp_tablet_tool_v2 *id) { - wlr_log(WLR_DEBUG, "New tablet tool"); - struct wlr_wl_tablet_tool *tool = calloc(1, sizeof(*tool)); - if (!tool) { - zwp_tablet_tool_v2_destroy(id); + struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2) { + struct wlr_wl_seat *seat = data; + if (seat->zwp_tablet_tool_v2 != NULL) { + wlr_log(WLR_ERROR, "zwp_tablet_tool_v2 already present"); return; } - tool->tool = id; + + wl_signal_init(&seat->wlr_tablet_tool.events.destroy); + + struct tablet_tool *tool = calloc(1, sizeof(struct tablet_tool)); + if (tool == NULL) { + wlr_log_errno(WLR_ERROR, "failed to allocate tablet_tool"); + zwp_tablet_tool_v2_destroy(zwp_tablet_tool_v2); + return; + } + + tool->seat = seat; clear_tablet_tool_values(tool); - wl_signal_init(&tool->wlr_tool.events.destroy); - zwp_tablet_tool_v2_add_listener(id, &tablet_tool_listener, tool); + + seat->zwp_tablet_tool_v2 = zwp_tablet_tool_v2; + zwp_tablet_tool_v2_add_listener(seat->zwp_tablet_tool_v2, &tablet_tool_listener, + tool); } static void handle_tablet_name(void *data, struct zwp_tablet_v2 *zwp_tablet_v2, const char *name) { - struct wlr_wl_input_device *dev = data; - struct wlr_tablet *tablet = dev->wlr_input_device.tablet; + struct wlr_wl_seat *seat = data; + struct wlr_tablet *tablet = &seat->wlr_tablet; - free(tablet->name); - tablet->name = strdup(name); + free(tablet->base.name); + tablet->base.name = strdup(name); } static void handle_tablet_id(void *data, struct zwp_tablet_v2 *zwp_tablet_v2, uint32_t vid, uint32_t pid) { - struct wlr_wl_input_device *dev = data; - dev->wlr_input_device.vendor = vid; - dev->wlr_input_device.product = pid; + struct wlr_wl_seat *seat = data; + struct wlr_tablet *tablet = &seat->wlr_tablet; + + tablet->base.vendor = vid; + tablet->base.product = pid; } static void handle_tablet_path(void *data, struct zwp_tablet_v2 *zwp_tablet_v2, const char *path) { - struct wlr_wl_input_device *dev = data; - struct wlr_tablet *tablet = dev->wlr_input_device.tablet; + struct wlr_wl_seat *seat = data; + struct wlr_tablet *tablet = &seat->wlr_tablet; char **dst = wl_array_add(&tablet->paths, sizeof(char *)); *dst = strdup(path); } static void handle_tablet_done(void *data, struct zwp_tablet_v2 *zwp_tablet_v2) { - struct wlr_wl_input_device *dev = data; + struct wlr_wl_seat *seat = data; - wlr_signal_emit_safe(&dev->backend->backend.events.new_input, - &dev->wlr_input_device); + wl_signal_emit_mutable(&seat->backend->backend.events.new_input, + &seat->wlr_tablet.base); } static void handle_tablet_removed(void *data, struct zwp_tablet_v2 *zwp_tablet_v2) { - struct wlr_wl_input_device *dev = data; + struct wlr_wl_seat *seat = data; - /* This doesn't free anything, but emits the destroy signal */ - wlr_input_device_destroy(&dev->wlr_input_device); - /* This is a bit ugly, but we need to remove it from our list */ - wl_list_remove(&dev->link); - - zwp_tablet_v2_destroy(dev->resource); - free(dev); + wlr_tablet_finish(&seat->wlr_tablet); + zwp_tablet_v2_destroy(seat->zwp_tablet_v2); + seat->zwp_tablet_v2 = NULL; } static const struct zwp_tablet_v2_listener tablet_listener = { @@ -888,32 +849,23 @@ static const struct zwp_tablet_v2_listener tablet_listener = { .removed = handle_tablet_removed, }; -const struct wlr_tablet_impl tablet_impl = {0}; +const struct wlr_tablet_impl wl_tablet_impl = { + .name = "wl-tablet-tool", +}; static void handle_tab_added(void *data, struct zwp_tablet_seat_v2 *zwp_tablet_seat_v2, - struct zwp_tablet_v2 *id) { - wlr_log(WLR_DEBUG, "New tablet"); + struct zwp_tablet_v2 *zwp_tablet_v2) { struct wlr_wl_seat *seat = data; - struct wlr_wl_input_device *dev = create_wl_input_device( - seat, WLR_INPUT_DEVICE_TABLET_TOOL); - - if (!dev) { - zwp_tablet_v2_destroy(id); + if (seat->zwp_tablet_v2 != NULL) { + wlr_log(WLR_ERROR, "zwp_tablet_v2 already present"); return; } - dev->resource = id; - struct wlr_input_device *wlr_dev = &dev->wlr_input_device; - wlr_dev->tablet = calloc(1, sizeof(*wlr_dev->tablet)); + seat->zwp_tablet_v2 = zwp_tablet_v2; + zwp_tablet_v2_add_listener(zwp_tablet_v2, &tablet_listener, seat); - if (!wlr_dev->tablet) { - zwp_tablet_v2_destroy(id); - return; - } - zwp_tablet_v2_set_user_data(id, wlr_dev->tablet); - wlr_tablet_init(wlr_dev->tablet, &tablet_impl, wlr_dev->name); - zwp_tablet_v2_add_listener(id, &tablet_listener, dev); + wlr_tablet_init(&seat->wlr_tablet, &wl_tablet_impl, "wlr_tablet_v2"); } static const struct zwp_tablet_seat_v2_listener tablet_seat_listener = { @@ -922,20 +874,55 @@ static const struct zwp_tablet_seat_v2_listener tablet_seat_listener = { .pad_added = handle_pad_added, }; -struct wlr_wl_tablet_seat *wl_add_tablet_seat( - struct zwp_tablet_manager_v2 *manager, - struct wlr_wl_seat *seat) { - struct wlr_wl_tablet_seat *ret = - calloc(1, sizeof(struct wlr_wl_tablet_seat)); +void init_seat_tablet(struct wlr_wl_seat *seat) { + struct zwp_tablet_manager_v2 *manager = seat->backend->tablet_manager; + assert(manager); - if (!(ret->tablet_seat = - zwp_tablet_manager_v2_get_tablet_seat(manager, seat->wl_seat))) { - free(ret); - return NULL; + /** + * TODO: multi tablet support + * The wlr_wl_seat should support multiple tablet_v2 devices, but for + * the sake of simplicity, it supports only one device of each. + * If this is a feature you want/need, please open an issue on the wlroots + * tracker here https://gitlab.freedesktop.org/wlroots/wlroots/-/issues + */ + + seat->zwp_tablet_seat_v2 = + zwp_tablet_manager_v2_get_tablet_seat(manager, seat->wl_seat); + if (seat->zwp_tablet_seat_v2 == NULL) { + wlr_log(WLR_ERROR, "failed to get zwp_tablet_manager_v2 from seat '%s'", + seat->name); + return; } - zwp_tablet_seat_v2_add_listener(ret->tablet_seat, + zwp_tablet_seat_v2_add_listener(seat->zwp_tablet_seat_v2, &tablet_seat_listener, seat); - - return ret; +} + +void finish_seat_tablet(struct wlr_wl_seat *seat) { + if (seat->zwp_tablet_v2 != NULL) { + wlr_tablet_finish(&seat->wlr_tablet); + zwp_tablet_v2_destroy(seat->zwp_tablet_v2); + } + + if (seat->zwp_tablet_tool_v2 != NULL) { + struct tablet_tool *tool = + zwp_tablet_tool_v2_get_user_data(seat->zwp_tablet_tool_v2); + free(tool); + + zwp_tablet_tool_v2_destroy(seat->zwp_tablet_tool_v2); + } + + if (seat->zwp_tablet_pad_v2 != NULL) { + struct wlr_tablet_pad *tablet_pad = &seat->wlr_tablet_pad; + struct tablet_pad_group *group, *it; + wl_list_for_each_safe(group, it, &tablet_pad->groups, group.link) { + destroy_tablet_pad_group(group); + } + + wlr_tablet_pad_finish(tablet_pad); + zwp_tablet_pad_v2_destroy(seat->zwp_tablet_pad_v2); + } + + zwp_tablet_seat_v2_destroy(seat->zwp_tablet_seat_v2); + seat->zwp_tablet_seat_v2 = NULL; } diff --git a/backend/x11/backend.c b/backend/x11/backend.c index 64bcf475b..1bb94410e 100644 --- a/backend/x11/backend.c +++ b/backend/x11/backend.c @@ -30,7 +30,6 @@ #include "backend/x11.h" #include "render/drm_format_set.h" -#include "util/signal.h" // See dri2_format_for_depth in mesa const struct wlr_x11_format formats[] = { @@ -164,7 +163,7 @@ static bool backend_start(struct wlr_backend *backend) { wlr_log(WLR_INFO, "Starting X11 backend"); - wlr_signal_emit_safe(&x11->backend.events.new_input, &x11->keyboard.base); + wl_signal_emit_mutable(&x11->backend.events.new_input, &x11->keyboard.base); for (size_t i = 0; i < x11->requested_outputs; ++i) { wlr_x11_output_create(&x11->backend); @@ -185,7 +184,7 @@ static void backend_destroy(struct wlr_backend *backend) { wlr_output_destroy(&output->wlr_output); } - wlr_keyboard_destroy(&x11->keyboard); + wlr_keyboard_finish(&x11->keyboard); wlr_backend_finish(backend); @@ -637,7 +636,8 @@ struct wlr_backend *wlr_x11_backend_create(struct wl_display *display, } #endif - wlr_keyboard_init(&x11->keyboard, &x11_keyboard_impl, "x11-keyboard"); + wlr_keyboard_init(&x11->keyboard, &x11_keyboard_impl, + x11_keyboard_impl.name); x11->display_destroy.notify = handle_display_destroy; wl_display_add_destroy_listener(display, &x11->display_destroy); diff --git a/backend/x11/input_device.c b/backend/x11/input_device.c index f87f53a0d..603316f11 100644 --- a/backend/x11/input_device.c +++ b/backend/x11/input_device.c @@ -16,11 +16,10 @@ #include #include "backend/x11.h" -#include "util/signal.h" static void send_key_event(struct wlr_x11_backend *x11, uint32_t key, enum wl_keyboard_key_state st, xcb_timestamp_t time) { - struct wlr_event_keyboard_key ev = { + struct wlr_keyboard_key_event ev = { .time_msec = time, .keycode = key, .state = st, @@ -31,20 +30,20 @@ static void send_key_event(struct wlr_x11_backend *x11, uint32_t key, static void send_button_event(struct wlr_x11_output *output, uint32_t key, enum wlr_button_state st, xcb_timestamp_t time) { - struct wlr_event_pointer_button ev = { - .device = &output->pointer.base, + struct wlr_pointer_button_event ev = { + .pointer = &output->pointer, .time_msec = time, .button = key, .state = st, }; - wlr_signal_emit_safe(&output->pointer.events.button, &ev); - wlr_signal_emit_safe(&output->pointer.events.frame, &output->pointer); + wl_signal_emit_mutable(&output->pointer.events.button, &ev); + wl_signal_emit_mutable(&output->pointer.events.frame, &output->pointer); } static void send_axis_event(struct wlr_x11_output *output, int32_t delta, xcb_timestamp_t time) { - struct wlr_event_pointer_axis ev = { - .device = &output->pointer.base, + struct wlr_pointer_axis_event ev = { + .pointer = &output->pointer, .time_msec = time, .source = WLR_AXIS_SOURCE_WHEEL, .orientation = WLR_AXIS_ORIENTATION_VERTICAL, @@ -52,57 +51,57 @@ static void send_axis_event(struct wlr_x11_output *output, int32_t delta, .delta = delta * 15, .delta_discrete = delta, }; - wlr_signal_emit_safe(&output->pointer.events.axis, &ev); - wlr_signal_emit_safe(&output->pointer.events.frame, &output->pointer); + wl_signal_emit_mutable(&output->pointer.events.axis, &ev); + wl_signal_emit_mutable(&output->pointer.events.frame, &output->pointer); } static void send_pointer_position_event(struct wlr_x11_output *output, int16_t x, int16_t y, xcb_timestamp_t time) { - struct wlr_event_pointer_motion_absolute ev = { - .device = &output->pointer.base, + struct wlr_pointer_motion_absolute_event ev = { + .pointer = &output->pointer, .time_msec = time, .x = (double)x / output->wlr_output.width, .y = (double)y / output->wlr_output.height, }; - wlr_signal_emit_safe(&output->pointer.events.motion_absolute, &ev); - wlr_signal_emit_safe(&output->pointer.events.frame, &output->pointer); + wl_signal_emit_mutable(&output->pointer.events.motion_absolute, &ev); + wl_signal_emit_mutable(&output->pointer.events.frame, &output->pointer); } static void send_touch_down_event(struct wlr_x11_output *output, int16_t x, int16_t y, int32_t touch_id, xcb_timestamp_t time) { - struct wlr_event_touch_down ev = { - .device = &output->touch.base, + struct wlr_touch_down_event ev = { + .touch = &output->touch, .time_msec = time, .x = (double)x / output->wlr_output.width, .y = (double)y / output->wlr_output.height, .touch_id = touch_id, }; - wlr_signal_emit_safe(&output->touch.events.down, &ev); - wlr_signal_emit_safe(&output->touch.events.frame, NULL); + wl_signal_emit_mutable(&output->touch.events.down, &ev); + wl_signal_emit_mutable(&output->touch.events.frame, NULL); } static void send_touch_motion_event(struct wlr_x11_output *output, int16_t x, int16_t y, int32_t touch_id, xcb_timestamp_t time) { - struct wlr_event_touch_motion ev = { - .device = &output->touch.base, + struct wlr_touch_motion_event ev = { + .touch = &output->touch, .time_msec = time, .x = (double)x / output->wlr_output.width, .y = (double)y / output->wlr_output.height, .touch_id = touch_id, }; - wlr_signal_emit_safe(&output->touch.events.motion, &ev); - wlr_signal_emit_safe(&output->touch.events.frame, NULL); + wl_signal_emit_mutable(&output->touch.events.motion, &ev); + wl_signal_emit_mutable(&output->touch.events.frame, NULL); } static void send_touch_up_event(struct wlr_x11_output *output, int32_t touch_id, xcb_timestamp_t time) { - struct wlr_event_touch_up ev = { - .device = &output->touch.base, + struct wlr_touch_up_event ev = { + .touch = &output->touch, .time_msec = time, .touch_id = touch_id, }; - wlr_signal_emit_safe(&output->touch.events.up, &ev); - wlr_signal_emit_safe(&output->touch.events.frame, NULL); + wl_signal_emit_mutable(&output->touch.events.up, &ev); + wl_signal_emit_mutable(&output->touch.events.frame, NULL); } static struct wlr_x11_touchpoint *get_touchpoint_from_x11_touch_id( @@ -285,28 +284,16 @@ void handle_x11_xinput_event(struct wlr_x11_backend *x11, } } -static void keyboard_destroy(struct wlr_keyboard *wlr_keyboard) { - // Don't free the keyboard, it's on the stack -} - const struct wlr_keyboard_impl x11_keyboard_impl = { - .destroy = keyboard_destroy, + .name = "x11-keyboard", }; -static void pointer_destroy(struct wlr_pointer *wlr_pointer) { - // Don't free the pointer, it's on the stack -} - const struct wlr_pointer_impl x11_pointer_impl = { - .destroy = pointer_destroy, + .name = "x11-pointer", }; -static void touch_destroy(struct wlr_touch *wlr_touch) { - // Don't free the touch, it's on the stack -} - const struct wlr_touch_impl x11_touch_impl = { - .destroy = touch_destroy, + .name = "x11-touch", }; void update_x11_pointer_position(struct wlr_x11_output *output, @@ -329,11 +316,11 @@ void update_x11_pointer_position(struct wlr_x11_output *output, bool wlr_input_device_is_x11(struct wlr_input_device *wlr_dev) { switch (wlr_dev->type) { case WLR_INPUT_DEVICE_KEYBOARD: - return wlr_dev->keyboard->impl == &x11_keyboard_impl; + return wlr_keyboard_from_input_device(wlr_dev)->impl == &x11_keyboard_impl; case WLR_INPUT_DEVICE_POINTER: - return wlr_dev->pointer->impl == &x11_pointer_impl; + return wlr_pointer_from_input_device(wlr_dev)->impl == &x11_pointer_impl; case WLR_INPUT_DEVICE_TOUCH: - return wlr_dev->touch->impl == &x11_touch_impl; + return wlr_touch_from_input_device(wlr_dev)->impl == &x11_touch_impl; default: return false; } diff --git a/backend/x11/output.c b/backend/x11/output.c index 7037c36cc..f109757dd 100644 --- a/backend/x11/output.c +++ b/backend/x11/output.c @@ -21,24 +21,31 @@ #include #include "backend/x11.h" -#include "util/signal.h" #include "util/time.h" static const uint32_t SUPPORTED_OUTPUT_STATE = WLR_OUTPUT_STATE_BACKEND_OPTIONAL | WLR_OUTPUT_STATE_BUFFER | - WLR_OUTPUT_STATE_MODE; + WLR_OUTPUT_STATE_MODE | + WLR_OUTPUT_STATE_ADAPTIVE_SYNC_ENABLED; static void parse_xcb_setup(struct wlr_output *output, xcb_connection_t *xcb) { const xcb_setup_t *xcb_setup = xcb_get_setup(xcb); - snprintf(output->make, sizeof(output->make), "%.*s", - xcb_setup_vendor_length(xcb_setup), - xcb_setup_vendor(xcb_setup)); - snprintf(output->model, sizeof(output->model), "%"PRIu16".%"PRIu16, - xcb_setup->protocol_major_version, - xcb_setup->protocol_minor_version); + output->make = calloc(1, xcb_setup_vendor_length(xcb_setup) + 1); + if (output->make == NULL) { + wlr_log_errno(WLR_ERROR, "Allocation failed"); + return; + } + memcpy(output->make, xcb_setup_vendor(xcb_setup), + xcb_setup_vendor_length(xcb_setup)); + + char model[64]; + snprintf(model, sizeof(model), "%"PRIu16".%"PRIu16, + xcb_setup->protocol_major_version, + xcb_setup->protocol_minor_version); + output->model = strdup(model); } static struct wlr_x11_output *get_x11_output_from_output( @@ -76,8 +83,8 @@ static void output_destroy(struct wlr_output *wlr_output) { pixman_region32_fini(&output->exposed); - wlr_pointer_destroy(&output->pointer); - wlr_touch_destroy(&output->touch); + wlr_pointer_finish(&output->pointer); + wlr_touch_finish(&output->touch); struct wlr_x11_buffer *buffer, *buffer_tmp; wl_list_for_each_safe(buffer, buffer_tmp, &output->buffers, link) { @@ -97,17 +104,28 @@ static void output_destroy(struct wlr_output *wlr_output) { free(output); } -static bool output_test(struct wlr_output *wlr_output) { - uint32_t unsupported = - wlr_output->pending.committed & ~SUPPORTED_OUTPUT_STATE; +static bool output_test(struct wlr_output *wlr_output, + const struct wlr_output_state *state) { + uint32_t unsupported = state->committed & ~SUPPORTED_OUTPUT_STATE; if (unsupported != 0) { wlr_log(WLR_DEBUG, "Unsupported output state fields: 0x%"PRIx32, unsupported); return false; } - if (wlr_output->pending.committed & WLR_OUTPUT_STATE_MODE) { - assert(wlr_output->pending.mode_type == WLR_OUTPUT_STATE_MODE_CUSTOM); + // All we can do to influence adaptive sync on the X11 backend is set the + // _VARIABLE_REFRESH window property like mesa automatically does. We don't + // have any control beyond that, so we set the state to enabled on creating + // the output and never allow changing it (just like the Wayland backend). + assert(wlr_output->adaptive_sync_status == WLR_OUTPUT_ADAPTIVE_SYNC_ENABLED); + if (state->committed & WLR_OUTPUT_STATE_ADAPTIVE_SYNC_ENABLED) { + if (!state->adaptive_sync_enabled) { + return false; + } + } + + if (state->committed & WLR_OUTPUT_STATE_MODE) { + assert(state->mode_type == WLR_OUTPUT_STATE_MODE_CUSTOM); } return true; @@ -250,10 +268,11 @@ static struct wlr_x11_buffer *get_or_create_x11_buffer( return create_x11_buffer(output, wlr_buffer); } -static bool output_commit_buffer(struct wlr_x11_output *output) { +static bool output_commit_buffer(struct wlr_x11_output *output, + const struct wlr_output_state *state) { struct wlr_x11_backend *x11 = output->x11; - struct wlr_buffer *buffer = output->wlr_output.pending.buffer; + struct wlr_buffer *buffer = state->buffer; struct wlr_x11_buffer *x11_buffer = get_or_create_x11_buffer(output, buffer); if (!x11_buffer) { @@ -261,8 +280,9 @@ static bool output_commit_buffer(struct wlr_x11_output *output) { } xcb_xfixes_region_t region = XCB_NONE; - if (output->wlr_output.pending.committed & WLR_OUTPUT_STATE_DAMAGE) { - pixman_region32_union(&output->exposed, &output->exposed, &output->wlr_output.pending.damage); + if (state->committed & WLR_OUTPUT_STATE_DAMAGE) { + pixman_region32_union(&output->exposed, &output->exposed, + (pixman_region32_t *) &state->damage); int rects_len = 0; pixman_box32_t *rects = pixman_region32_rectangles(&output->exposed, &rects_len); @@ -308,40 +328,26 @@ error: return false; } -static bool output_commit(struct wlr_output *wlr_output) { +static bool output_commit(struct wlr_output *wlr_output, + const struct wlr_output_state *state) { struct wlr_x11_output *output = get_x11_output_from_output(wlr_output); struct wlr_x11_backend *x11 = output->x11; - if (!output_test(wlr_output)) { + if (!output_test(wlr_output, state)) { return false; } - if (wlr_output->pending.committed & WLR_OUTPUT_STATE_MODE) { + if (state->committed & WLR_OUTPUT_STATE_MODE) { if (!output_set_custom_mode(wlr_output, - wlr_output->pending.custom_mode.width, - wlr_output->pending.custom_mode.height, - wlr_output->pending.custom_mode.refresh)) { + state->custom_mode.width, + state->custom_mode.height, + state->custom_mode.refresh)) { return false; } } - if (wlr_output->pending.committed & WLR_OUTPUT_STATE_ADAPTIVE_SYNC_ENABLED && - x11->atoms.variable_refresh != XCB_ATOM_NONE) { - if (wlr_output->pending.adaptive_sync_enabled) { - uint32_t enabled = 1; - xcb_change_property(x11->xcb, XCB_PROP_MODE_REPLACE, output->win, - x11->atoms.variable_refresh, XCB_ATOM_CARDINAL, 32, 1, - &enabled); - wlr_output->adaptive_sync_status = WLR_OUTPUT_ADAPTIVE_SYNC_UNKNOWN; - } else { - xcb_delete_property(x11->xcb, output->win, - x11->atoms.variable_refresh); - wlr_output->adaptive_sync_status = WLR_OUTPUT_ADAPTIVE_SYNC_DISABLED; - } - } - - if (wlr_output->pending.committed & WLR_OUTPUT_STATE_BUFFER) { - if (!output_commit_buffer(output)) { + if (state->committed & WLR_OUTPUT_STATE_BUFFER) { + if (!output_commit_buffer(output, state)) { return false; } } @@ -564,6 +570,12 @@ struct wlr_output *wlr_x11_output_create(struct wlr_backend *backend) { x11->atoms.wm_protocols, XCB_ATOM_ATOM, 32, 1, &x11->atoms.wm_delete_window); + uint32_t enabled = 1; + xcb_change_property(x11->xcb, XCB_PROP_MODE_REPLACE, output->win, + x11->atoms.variable_refresh, XCB_ATOM_CARDINAL, 32, 1, + &enabled); + wlr_output->adaptive_sync_status = WLR_OUTPUT_ADAPTIVE_SYNC_ENABLED; + wlr_x11_output_set_title(wlr_output, NULL); xcb_map_window(x11->xcb, output->win); @@ -574,15 +586,15 @@ struct wlr_output *wlr_x11_output_create(struct wlr_backend *backend) { wlr_output_update_enabled(wlr_output, true); wlr_pointer_init(&output->pointer, &x11_pointer_impl, "x11-pointer"); - output->pointer.base.output_name = strdup(wlr_output->name); + output->pointer.output_name = strdup(wlr_output->name); wlr_touch_init(&output->touch, &x11_touch_impl, "x11-touch"); - output->touch.base.output_name = strdup(wlr_output->name); + output->touch.output_name = strdup(wlr_output->name); wl_list_init(&output->touchpoints); - wlr_signal_emit_safe(&x11->backend.events.new_output, wlr_output); - wlr_signal_emit_safe(&x11->backend.events.new_input, &output->pointer.base); - wlr_signal_emit_safe(&x11->backend.events.new_input, &output->touch.base); + wl_signal_emit_mutable(&x11->backend.events.new_output, wlr_output); + wl_signal_emit_mutable(&x11->backend.events.new_input, &output->pointer.base); + wl_signal_emit_mutable(&x11->backend.events.new_input, &output->touch.base); // Start the rendering loop by requesting the compositor to render a frame wlr_output_schedule_frame(wlr_output); diff --git a/docs/env_vars.md b/docs/env_vars.md index 609ca97bd..624727835 100644 --- a/docs/env_vars.md +++ b/docs/env_vars.md @@ -45,6 +45,16 @@ wlroots reads these environment variables * *WLR_RENDERER_ALLOW_SOFTWARE*: allows the gles2 renderer to use software rendering +## scenes + +* *WLR_SCENE_DEBUG_DAMAGE*: specifies debug options for screen damage related + tasks for compositors that use scenes (available options: none, rerender, + highlight) +* *WLR_SCENE_DISABLE_DIRECT_SCANOUT*: disables direct scan-out for debugging. +* *WLR_SCENE_DISABLE_VISIBILITY*: If set to 1, the visibility of all scene nodes + will be considered to be the full node. Intelligent visibility canculations will + be disabled. + # Generic * *DISPLAY*: if set probe X11 backend in `wlr_backend_autocreate` diff --git a/examples/egl_common.c b/examples/egl_common.c index 616715083..f095a4879 100644 --- a/examples/egl_common.c +++ b/examples/egl_common.c @@ -20,10 +20,10 @@ PFNEGLCREATEPLATFORMWINDOWSURFACEEXTPROC eglCreatePlatformWindowSurfaceEXT; const EGLint config_attribs[] = { EGL_SURFACE_TYPE, EGL_WINDOW_BIT, - EGL_RED_SIZE, 1, - EGL_GREEN_SIZE, 1, - EGL_BLUE_SIZE, 1, - EGL_ALPHA_SIZE, 1, + EGL_RED_SIZE, 8, + EGL_GREEN_SIZE, 8, + EGL_BLUE_SIZE, 8, + EGL_ALPHA_SIZE, 8, EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, EGL_NONE, }; diff --git a/examples/input-method.c b/examples/input-method.c index 479c87613..849971b9b 100644 --- a/examples/input-method.c +++ b/examples/input-method.c @@ -194,7 +194,7 @@ static void do_updates(void) { update_stage++; break; case 2: - if (strcmp(current.surrounding.text, "_Commit_") != 0) { + if (current.surrounding.text && strcmp(current.surrounding.text, "_Commit_") != 0) { return; } zwp_input_method_v2_commit_string(input_method, "_CommitNoPreed_"); @@ -203,7 +203,7 @@ static void do_updates(void) { update_stage++; break; case 3: - if (strcmp(current.surrounding.text, "_Commit__CommitNoPreed_") != 0) { + if (current.surrounding.text && strcmp(current.surrounding.text, "_Commit__CommitNoPreed_") != 0) { return; } zwp_input_method_v2_commit_string(input_method, "_WaitNo_"); @@ -212,7 +212,7 @@ static void do_updates(void) { update_stage++; break; case 4: - if (strcmp(current.surrounding.text, "_Commit__WaitNo_") != 0) { + if (current.surrounding.text && strcmp(current.surrounding.text, "_Commit__WaitNo_") != 0) { return; } zwp_input_method_v2_set_preedit_string(input_method, "PreedWithDel", strlen("Preed"), strlen("Preed")); @@ -221,7 +221,7 @@ static void do_updates(void) { update_stage++; break; case 5: - if (strcmp(current.surrounding.text, "_Commit_") != 0) { + if (current.surrounding.text && strcmp(current.surrounding.text, "_Commit_") != 0) { return; } zwp_input_method_v2_delete_surrounding_text(input_method, strlen("mit_"), 0); @@ -229,7 +229,7 @@ static void do_updates(void) { update_stage++; break; case 6: - if (strcmp(current.surrounding.text, "_Com") != 0) { + if (current.surrounding.text && strcmp(current.surrounding.text, "_Com") != 0) { printf("Failed\n"); } update_stage++; diff --git a/examples/layer-shell.c b/examples/layer-shell.c index 56a8d4aa5..f2e0aaa71 100644 --- a/examples/layer-shell.c +++ b/examples/layer-shell.c @@ -124,9 +124,10 @@ static void draw(void) { glViewport(0, 0, width, height); if (buttons) { - glClearColor(1, 1, 1, alpha); + glClearColor(alpha, alpha, alpha, alpha); } else { - glClearColor(demo.color[0], demo.color[1], demo.color[2], alpha); + glClearColor(demo.color[0] * alpha, demo.color[1] * alpha, + demo.color[2] * alpha, alpha); } glClear(GL_COLOR_BUFFER_BIT); @@ -151,7 +152,8 @@ static void draw_popup(void) { eglMakeCurrent(egl_display, popup_egl_surface, popup_egl_surface, egl_context); glViewport(0, 0, popup_width, popup_height); - glClearColor(popup_red, 0.5f, 0.5f, popup_alpha); + glClearColor(popup_red * popup_alpha, 0.5f * popup_alpha, + 0.5f * popup_alpha, popup_alpha); popup_alpha += alpha_mod; if (popup_alpha < 0.01 || popup_alpha >= 1.0f) { alpha_mod *= -1.0; diff --git a/examples/meson.build b/examples/meson.build index 26d103bbb..51e7d3117 100644 --- a/examples/meson.build +++ b/examples/meson.build @@ -5,6 +5,7 @@ wayland_client = dependency('wayland-client') libpng = dependency('libpng', required: false, disabler: true) egl = dependency('egl', required: false, disabler: true) glesv2 = dependency('glesv2', required: false, disabler: true) +gbm = dependency('gbm', required: false, disabler: true) # These versions correspond to ffmpeg 4.0 libavutil = dependency('libavutil', version: '>=56.14.100', required: false, disabler: true) libavcodec = dependency('libavcodec', version: '>=58.18.100', required: false, disabler: true) diff --git a/examples/multi-pointer.c b/examples/multi-pointer.c index 5095cb729..26311319c 100644 --- a/examples/multi-pointer.c +++ b/examples/multi-pointer.c @@ -64,7 +64,7 @@ struct sample_output { struct sample_keyboard { struct sample_state *sample; - struct wlr_input_device *device; + struct wlr_keyboard *wlr_keyboard; struct wl_listener key; struct wl_listener destroy; }; @@ -109,8 +109,8 @@ static void output_frame_notify(struct wl_listener *listener, void *data) { static void handle_cursor_motion(struct wl_listener *listener, void *data) { struct sample_cursor *cursor = wl_container_of(listener, cursor, cursor_motion); - struct wlr_event_pointer_motion *event = data; - wlr_cursor_move(cursor->cursor, event->device, event->delta_x, + struct wlr_pointer_motion_event *event = data; + wlr_cursor_move(cursor->cursor, &event->pointer->base, event->delta_x, event->delta_y); } @@ -118,8 +118,9 @@ static void handle_cursor_motion_absolute(struct wl_listener *listener, void *data) { struct sample_cursor *cursor = wl_container_of(listener, cursor, cursor_motion_absolute); - struct wlr_event_pointer_motion_absolute *event = data; - wlr_cursor_warp_absolute(cursor->cursor, event->device, event->x, event->y); + struct wlr_pointer_motion_absolute_event *event = data; + wlr_cursor_warp_absolute(cursor->cursor, &event->pointer->base, event->x, + event->y); } static void cursor_destroy(struct sample_cursor *cursor) { @@ -184,10 +185,10 @@ static void new_output_notify(struct wl_listener *listener, void *data) { static void keyboard_key_notify(struct wl_listener *listener, void *data) { struct sample_keyboard *keyboard = wl_container_of(listener, keyboard, key); struct sample_state *sample = keyboard->sample; - struct wlr_event_keyboard_key *event = data; + struct wlr_keyboard_key_event *event = data; uint32_t keycode = event->keycode + 8; const xkb_keysym_t *syms; - int nsyms = xkb_state_key_get_syms(keyboard->device->keyboard->xkb_state, + int nsyms = xkb_state_key_get_syms(keyboard->wlr_keyboard->xkb_state, keycode, &syms); for (int i = 0; i < nsyms; i++) { xkb_keysym_t sym = syms[i]; @@ -210,11 +211,11 @@ static void new_input_notify(struct wl_listener *listener, void *data) { switch (device->type) { case WLR_INPUT_DEVICE_KEYBOARD:; struct sample_keyboard *keyboard = calloc(1, sizeof(struct sample_keyboard)); - keyboard->device = device; + keyboard->wlr_keyboard = wlr_keyboard_from_input_device(device); keyboard->sample = sample; wl_signal_add(&device->events.destroy, &keyboard->destroy); keyboard->destroy.notify = keyboard_destroy_notify; - wl_signal_add(&device->keyboard->events.key, &keyboard->key); + wl_signal_add(&keyboard->wlr_keyboard->events.key, &keyboard->key); keyboard->key.notify = keyboard_key_notify; struct xkb_context *context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); if (!context) { @@ -227,7 +228,7 @@ static void new_input_notify(struct wl_listener *listener, void *data) { wlr_log(WLR_ERROR, "Failed to create XKB keymap"); exit(1); } - wlr_keyboard_set_keymap(device->keyboard, keymap); + wlr_keyboard_set_keymap(keyboard->wlr_keyboard, keymap); xkb_keymap_unref(keymap); xkb_context_unref(context); break; diff --git a/examples/output-layout.c b/examples/output-layout.c index bc5cb7e90..97939953f 100644 --- a/examples/output-layout.c +++ b/examples/output-layout.c @@ -45,7 +45,7 @@ struct sample_output { struct sample_keyboard { struct sample_state *sample; - struct wlr_input_device *device; + struct wlr_keyboard *wlr_keyboard; struct wl_listener key; struct wl_listener destroy; }; @@ -183,10 +183,10 @@ static void new_output_notify(struct wl_listener *listener, void *data) { static void keyboard_key_notify(struct wl_listener *listener, void *data) { struct sample_keyboard *keyboard = wl_container_of(listener, keyboard, key); struct sample_state *sample = keyboard->sample; - struct wlr_event_keyboard_key *event = data; + struct wlr_keyboard_key_event *event = data; uint32_t keycode = event->keycode + 8; const xkb_keysym_t *syms; - int nsyms = xkb_state_key_get_syms(keyboard->device->keyboard->xkb_state, + int nsyms = xkb_state_key_get_syms(keyboard->wlr_keyboard->xkb_state, keycode, &syms); for (int i = 0; i < nsyms; i++) { xkb_keysym_t sym = syms[i]; @@ -229,11 +229,11 @@ static void new_input_notify(struct wl_listener *listener, void *data) { switch (device->type) { case WLR_INPUT_DEVICE_KEYBOARD:; struct sample_keyboard *keyboard = calloc(1, sizeof(struct sample_keyboard)); - keyboard->device = device; + keyboard->wlr_keyboard = wlr_keyboard_from_input_device(device); keyboard->sample = sample; wl_signal_add(&device->events.destroy, &keyboard->destroy); keyboard->destroy.notify = keyboard_destroy_notify; - wl_signal_add(&device->keyboard->events.key, &keyboard->key); + wl_signal_add(&keyboard->wlr_keyboard->events.key, &keyboard->key); keyboard->key.notify = keyboard_key_notify; struct xkb_context *context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); if (!context) { @@ -246,7 +246,7 @@ static void new_input_notify(struct wl_listener *listener, void *data) { wlr_log(WLR_ERROR, "Failed to create XKB keymap"); exit(1); } - wlr_keyboard_set_keymap(device->keyboard, keymap); + wlr_keyboard_set_keymap(keyboard->wlr_keyboard, keymap); xkb_keymap_unref(keymap); xkb_context_unref(context); break; diff --git a/examples/pointer.c b/examples/pointer.c index bf3701a45..6eb328ac2 100644 --- a/examples/pointer.c +++ b/examples/pointer.c @@ -70,7 +70,7 @@ struct sample_output { struct sample_keyboard { struct sample_state *state; - struct wlr_input_device *device; + struct wlr_keyboard *wlr_keyboard; struct wl_listener key; struct wl_listener destroy; }; @@ -112,8 +112,8 @@ static void output_frame_notify(struct wl_listener *listener, void *data) { 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, + struct wlr_pointer_motion_event *event = data; + wlr_cursor_move(sample->cursor, &event->pointer->base, event->delta_x, event->delta_y); } @@ -121,19 +121,19 @@ 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; + struct wlr_pointer_motion_absolute_event *event = data; sample->cur_x = event->x; sample->cur_y = event->y; - wlr_cursor_warp_absolute(sample->cursor, event->device, sample->cur_x, - sample->cur_y); + wlr_cursor_warp_absolute(sample->cursor, &event->pointer->base, + sample->cur_x, sample->cur_y); } 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_pointer_button_event *event = data; float (*color)[4]; if (event->state == WLR_BUTTON_RELEASED) { @@ -150,7 +150,7 @@ static void handle_cursor_button(struct wl_listener *listener, void *data) { 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; + struct wlr_pointer_axis_event *event = data; for (size_t i = 0; i < 3; ++i) { sample->default_color[i] += event->delta > 0 ? -0.05f : 0.05f; @@ -168,7 +168,7 @@ static void handle_cursor_axis(struct wl_listener *listener, void *data) { static void handle_touch_up(struct wl_listener *listener, void *data) { struct sample_state *sample = wl_container_of(listener, sample, touch_up); - struct wlr_event_touch_up *event = data; + struct wlr_touch_up_event *event = data; struct touch_point *point, *tmp; wl_list_for_each_safe(point, tmp, &sample->touch_points, link) { @@ -178,25 +178,25 @@ static void handle_touch_up(struct wl_listener *listener, void *data) { } } - warp_to_touch(sample, event->device); + warp_to_touch(sample, &event->touch->base); } static void handle_touch_down(struct wl_listener *listener, void *data) { struct sample_state *sample = wl_container_of(listener, sample, touch_down); - struct wlr_event_touch_down *event = data; + struct wlr_touch_down_event *event = data; struct touch_point *point = calloc(1, sizeof(struct touch_point)); point->touch_id = event->touch_id; point->x = event->x; point->y = event->y; wl_list_insert(&sample->touch_points, &point->link); - warp_to_touch(sample, event->device); + warp_to_touch(sample, &event->touch->base); } static void handle_touch_motion(struct wl_listener *listener, void *data) { struct sample_state *sample = wl_container_of(listener, sample, touch_motion); - struct wlr_event_touch_motion *event = data; + struct wlr_touch_motion_event *event = data; struct touch_point *point; wl_list_for_each(point, &sample->touch_points, link) { @@ -207,7 +207,7 @@ static void handle_touch_motion(struct wl_listener *listener, void *data) { } } - warp_to_touch(sample, event->device); + warp_to_touch(sample, &event->touch->base); } static void handle_touch_cancel(struct wl_listener *listener, void *data) { @@ -217,21 +217,21 @@ static void handle_touch_cancel(struct wl_listener *listener, void *data) { static void handle_tablet_tool_axis(struct wl_listener *listener, void *data) { struct sample_state *sample = wl_container_of(listener, sample, tablet_tool_axis); - struct wlr_event_tablet_tool_axis *event = data; + struct wlr_tablet_tool_axis_event *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, event->y); + wlr_cursor_warp_absolute(sample->cursor, &event->tablet->base, + event->x, event->y); } } static void keyboard_key_notify(struct wl_listener *listener, void *data) { struct sample_keyboard *keyboard = wl_container_of(listener, keyboard, key); struct sample_state *sample = keyboard->state; - struct wlr_event_keyboard_key *event = data; + struct wlr_keyboard_key_event *event = data; uint32_t keycode = event->keycode + 8; const xkb_keysym_t *syms; - int nsyms = xkb_state_key_get_syms(keyboard->device->keyboard->xkb_state, + int nsyms = xkb_state_key_get_syms(keyboard->wlr_keyboard->xkb_state, keycode, &syms); for (int i = 0; i < nsyms; i++) { xkb_keysym_t sym = syms[i]; @@ -297,11 +297,11 @@ static void new_input_notify(struct wl_listener *listener, void *data) { case WLR_INPUT_DEVICE_KEYBOARD:; struct sample_keyboard *keyboard = calloc(1, sizeof(struct sample_keyboard)); - keyboard->device = device; + keyboard->wlr_keyboard = wlr_keyboard_from_input_device(device); keyboard->state = state; wl_signal_add(&device->events.destroy, &keyboard->destroy); keyboard->destroy.notify = keyboard_destroy_notify; - wl_signal_add(&device->keyboard->events.key, &keyboard->key); + wl_signal_add(&keyboard->wlr_keyboard->events.key, &keyboard->key); keyboard->key.notify = keyboard_key_notify; struct xkb_context *context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); if (!context) { @@ -314,7 +314,7 @@ static void new_input_notify(struct wl_listener *listener, void *data) { wlr_log(WLR_ERROR, "Failed to create XKB keymap"); exit(1); } - wlr_keyboard_set_keymap(device->keyboard, keymap); + wlr_keyboard_set_keymap(keyboard->wlr_keyboard, keymap); xkb_keymap_unref(keymap); xkb_context_unref(context); break; diff --git a/examples/quads.c b/examples/quads.c index d74ef25e6..a9c7a14b8 100644 --- a/examples/quads.c +++ b/examples/quads.c @@ -39,7 +39,7 @@ struct sample_output { struct sample_keyboard { struct sample_state *sample; - struct wlr_input_device *device; + struct wlr_keyboard *wlr_keyboard; struct wl_listener key; struct wl_listener destroy; }; @@ -129,10 +129,10 @@ static void new_output_notify(struct wl_listener *listener, void *data) { static void keyboard_key_notify(struct wl_listener *listener, void *data) { struct sample_keyboard *keyboard = wl_container_of(listener, keyboard, key); struct sample_state *sample = keyboard->sample; - struct wlr_event_keyboard_key *event = data; + struct wlr_keyboard_key_event *event = data; uint32_t keycode = event->keycode + 8; const xkb_keysym_t *syms; - int nsyms = xkb_state_key_get_syms(keyboard->device->keyboard->xkb_state, + int nsyms = xkb_state_key_get_syms(keyboard->wlr_keyboard->xkb_state, keycode, &syms); for (int i = 0; i < nsyms; i++) { xkb_keysym_t sym = syms[i]; @@ -155,11 +155,11 @@ static void new_input_notify(struct wl_listener *listener, void *data) { switch (device->type) { case WLR_INPUT_DEVICE_KEYBOARD:; struct sample_keyboard *keyboard = calloc(1, sizeof(struct sample_keyboard)); - keyboard->device = device; + keyboard->wlr_keyboard = wlr_keyboard_from_input_device(device); keyboard->sample = sample; wl_signal_add(&device->events.destroy, &keyboard->destroy); keyboard->destroy.notify = keyboard_destroy_notify; - wl_signal_add(&device->keyboard->events.key, &keyboard->key); + wl_signal_add(&keyboard->wlr_keyboard->events.key, &keyboard->key); keyboard->key.notify = keyboard_key_notify; struct xkb_context *context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); if (!context) { @@ -172,7 +172,7 @@ static void new_input_notify(struct wl_listener *listener, void *data) { wlr_log(WLR_ERROR, "Failed to create XKB keymap"); exit(1); } - wlr_keyboard_set_keymap(device->keyboard, keymap); + wlr_keyboard_set_keymap(keyboard->wlr_keyboard, keymap); xkb_keymap_unref(keymap); xkb_context_unref(context); break; diff --git a/examples/rotation.c b/examples/rotation.c index cc1cfbb5b..087fa8d18 100644 --- a/examples/rotation.c +++ b/examples/rotation.c @@ -44,7 +44,7 @@ struct sample_output { struct sample_keyboard { struct sample_state *sample; - struct wlr_input_device *device; + struct wlr_keyboard *wlr_keyboard; struct wl_listener key; struct wl_listener destroy; }; @@ -134,10 +134,10 @@ static void new_output_notify(struct wl_listener *listener, void *data) { static void keyboard_key_notify(struct wl_listener *listener, void *data) { struct sample_keyboard *keyboard = wl_container_of(listener, keyboard, key); struct sample_state *sample = keyboard->sample; - struct wlr_event_keyboard_key *event = data; + struct wlr_keyboard_key_event *event = data; uint32_t keycode = event->keycode + 8; const xkb_keysym_t *syms; - int nsyms = xkb_state_key_get_syms(keyboard->device->keyboard->xkb_state, + int nsyms = xkb_state_key_get_syms(keyboard->wlr_keyboard->xkb_state, keycode, &syms); for (int i = 0; i < nsyms; i++) { xkb_keysym_t sym = syms[i]; @@ -176,11 +176,11 @@ static void new_input_notify(struct wl_listener *listener, void *data) { switch (device->type) { case WLR_INPUT_DEVICE_KEYBOARD:; struct sample_keyboard *keyboard = calloc(1, sizeof(struct sample_keyboard)); - keyboard->device = device; + keyboard->wlr_keyboard = wlr_keyboard_from_input_device(device); keyboard->sample = sample; wl_signal_add(&device->events.destroy, &keyboard->destroy); keyboard->destroy.notify = keyboard_destroy_notify; - wl_signal_add(&device->keyboard->events.key, &keyboard->key); + wl_signal_add(&keyboard->wlr_keyboard->events.key, &keyboard->key); keyboard->key.notify = keyboard_key_notify; struct xkb_context *context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); if (!context) { @@ -193,7 +193,7 @@ static void new_input_notify(struct wl_listener *listener, void *data) { wlr_log(WLR_ERROR, "Failed to create XKB keymap"); exit(1); } - wlr_keyboard_set_keymap(device->keyboard, keymap); + wlr_keyboard_set_keymap(keyboard->wlr_keyboard, keymap); xkb_keymap_unref(keymap); xkb_context_unref(context); break; diff --git a/examples/scene-graph.c b/examples/scene-graph.c index c3ce05893..ba5d2d756 100644 --- a/examples/scene-graph.c +++ b/examples/scene-graph.c @@ -99,7 +99,7 @@ static void surface_handle_commit(struct wl_listener *listener, void *data) { static void surface_handle_destroy(struct wl_listener *listener, void *data) { struct surface *surface = wl_container_of(listener, surface, destroy); - wlr_scene_node_destroy(&surface->scene_surface->node); + wlr_scene_node_destroy(&surface->scene_surface->buffer->node); wlr_scene_node_destroy(&surface->border->node); wl_list_remove(&surface->destroy.link); wl_list_remove(&surface->link); @@ -122,14 +122,14 @@ static void server_handle_new_surface(struct wl_listener *listener, wl_signal_add(&wlr_surface->events.destroy, &surface->destroy); /* Border dimensions will be set in surface.commit handler */ - surface->border = wlr_scene_rect_create(&server->scene->node, + surface->border = wlr_scene_rect_create(&server->scene->tree, 0, 0, (float[4]){ 0.5f, 0.5f, 0.5f, 1 }); wlr_scene_node_set_position(&surface->border->node, pos, pos); surface->scene_surface = - wlr_scene_surface_create(&server->scene->node, wlr_surface); + wlr_scene_surface_create(&server->scene->tree, wlr_surface); - wlr_scene_node_set_position(&surface->scene_surface->node, + wlr_scene_node_set_position(&surface->scene_surface->buffer->node, pos + border_width, pos + border_width); } @@ -169,7 +169,7 @@ int main(int argc, char *argv[]) { struct wlr_compositor *compositor = wlr_compositor_create(server.display, server.renderer); - wlr_xdg_shell_create(server.display); + wlr_xdg_shell_create(server.display, 2); server.new_output.notify = server_handle_new_output; wl_signal_add(&server.backend->events.new_output, &server.new_output); diff --git a/examples/screencopy-dmabuf.c b/examples/screencopy-dmabuf.c index e7657e1a9..f16c29daf 100644 --- a/examples/screencopy-dmabuf.c +++ b/examples/screencopy-dmabuf.c @@ -76,7 +76,7 @@ static const struct format formats[] = { {DRM_FORMAT_ABGR8888, false}, }; -static bool find_render_node(char *node, size_t maxlen) { +static bool find_render_node(char *node, size_t node_size) { bool r = false; drmDevice *devices[64]; @@ -87,8 +87,7 @@ static bool find_render_node(char *node, size_t maxlen) { continue; } - strncpy(node, dev->nodes[DRM_NODE_RENDER], maxlen - 1); - node[maxlen - 1] = '\0'; + snprintf(node, node_size, "%s", dev->nodes[DRM_NODE_RENDER]); r = true; break; } diff --git a/examples/simple.c b/examples/simple.c index 94f3abe0e..5a41d19e4 100644 --- a/examples/simple.c +++ b/examples/simple.c @@ -35,7 +35,7 @@ struct sample_output { struct sample_keyboard { struct sample_state *sample; - struct wlr_input_device *device; + struct wlr_keyboard *wlr_keyboard; struct wl_listener key; struct wl_listener destroy; }; @@ -109,10 +109,10 @@ static void new_output_notify(struct wl_listener *listener, void *data) { static void keyboard_key_notify(struct wl_listener *listener, void *data) { struct sample_keyboard *keyboard = wl_container_of(listener, keyboard, key); struct sample_state *sample = keyboard->sample; - struct wlr_event_keyboard_key *event = data; + struct wlr_keyboard_key_event *event = data; uint32_t keycode = event->keycode + 8; const xkb_keysym_t *syms; - int nsyms = xkb_state_key_get_syms(keyboard->device->keyboard->xkb_state, + int nsyms = xkb_state_key_get_syms(keyboard->wlr_keyboard->xkb_state, keycode, &syms); for (int i = 0; i < nsyms; i++) { xkb_keysym_t sym = syms[i]; @@ -137,11 +137,11 @@ static void new_input_notify(struct wl_listener *listener, void *data) { case WLR_INPUT_DEVICE_KEYBOARD:; struct sample_keyboard *keyboard = calloc(1, sizeof(struct sample_keyboard)); - keyboard->device = device; + keyboard->wlr_keyboard = wlr_keyboard_from_input_device(device); keyboard->sample = sample; wl_signal_add(&device->events.destroy, &keyboard->destroy); keyboard->destroy.notify = keyboard_destroy_notify; - wl_signal_add(&device->keyboard->events.key, &keyboard->key); + wl_signal_add(&keyboard->wlr_keyboard->events.key, &keyboard->key); keyboard->key.notify = keyboard_key_notify; struct xkb_context *context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); if (!context) { @@ -154,7 +154,7 @@ static void new_input_notify(struct wl_listener *listener, void *data) { wlr_log(WLR_ERROR, "Failed to create XKB keymap"); exit(1); } - wlr_keyboard_set_keymap(device->keyboard, keymap); + wlr_keyboard_set_keymap(keyboard->wlr_keyboard, keymap); xkb_keymap_unref(keymap); xkb_context_unref(context); break; diff --git a/examples/tablet.c b/examples/tablet.c index 234bfb991..1fb0233bb 100644 --- a/examples/tablet.c +++ b/examples/tablet.c @@ -43,7 +43,7 @@ struct sample_state { struct tablet_tool_state { struct sample_state *sample; - struct wlr_input_device *device; + struct wlr_tablet *wlr_tablet; struct wl_listener destroy; struct wl_listener axis; struct wl_listener proximity; @@ -55,7 +55,7 @@ struct tablet_tool_state { struct tablet_pad_state { struct sample_state *sample; - struct wlr_input_device *device; + struct wlr_tablet_pad *wlr_tablet_pad; struct wl_listener destroy; struct wl_listener button; struct wl_listener ring; @@ -72,7 +72,7 @@ struct sample_output { struct sample_keyboard { struct sample_state *sample; - struct wlr_input_device *device; + struct wlr_keyboard *wlr_keyboard; struct wl_listener key; struct wl_listener destroy; }; @@ -136,7 +136,7 @@ static void output_frame_notify(struct wl_listener *listener, void *data) { static void tablet_tool_axis_notify(struct wl_listener *listener, void *data) { struct tablet_tool_state *tstate = wl_container_of(listener, tstate, axis); - struct wlr_event_tablet_tool_axis *event = data; + struct wlr_tablet_tool_axis_event *event = data; struct sample_state *sample = tstate->sample; if ((event->updated_axes & WLR_TABLET_TOOL_AXIS_X)) { sample->x = event->x; @@ -160,14 +160,14 @@ static void tablet_tool_axis_notify(struct wl_listener *listener, void *data) { static void tablet_tool_proximity_notify(struct wl_listener *listener, void *data) { struct tablet_tool_state *tstate = wl_container_of(listener, tstate, proximity); - struct wlr_event_tablet_tool_proximity *event = data; + struct wlr_tablet_tool_proximity_event *event = data; struct sample_state *sample = tstate->sample; sample->proximity = event->state == WLR_TABLET_TOOL_PROXIMITY_IN; } static void tablet_tool_button_notify(struct wl_listener *listener, void *data) { struct tablet_tool_state *tstate = wl_container_of(listener, tstate, button); - struct wlr_event_tablet_tool_button *event = data; + struct wlr_tablet_tool_button_event *event = data; struct sample_state *sample = tstate->sample; if (event->state == WLR_BUTTON_RELEASED) { sample->button = false; @@ -185,7 +185,7 @@ static void tablet_tool_button_notify(struct wl_listener *listener, void *data) static void tablet_pad_button_notify(struct wl_listener *listener, void *data) { struct tablet_pad_state *pstate = wl_container_of(listener, pstate, button); - struct wlr_event_tablet_pad_button *event = data; + struct wlr_tablet_pad_button_event *event = data; struct sample_state *sample = pstate->sample; float default_color[4] = { 0.5, 0.5, 0.5, 1.0 }; if (event->state == WLR_BUTTON_RELEASED) { @@ -203,7 +203,7 @@ static void tablet_pad_button_notify(struct wl_listener *listener, void *data) { static void tablet_pad_ring_notify(struct wl_listener *listener, void *data) { struct tablet_pad_state *pstate = wl_container_of(listener, pstate, ring); - struct wlr_event_tablet_pad_ring *event = data; + struct wlr_tablet_pad_ring_event *event = data; struct sample_state *sample = pstate->sample; if (event->position != -1) { sample->ring = -(event->position * (M_PI / 180.0)); @@ -261,10 +261,10 @@ static void new_output_notify(struct wl_listener *listener, void *data) { static void keyboard_key_notify(struct wl_listener *listener, void *data) { struct sample_keyboard *keyboard = wl_container_of(listener, keyboard, key); struct sample_state *sample = keyboard->sample; - struct wlr_event_keyboard_key *event = data; + struct wlr_keyboard_key_event *event = data; uint32_t keycode = event->keycode + 8; const xkb_keysym_t *syms; - int nsyms = xkb_state_key_get_syms(keyboard->device->keyboard->xkb_state, + int nsyms = xkb_state_key_get_syms(keyboard->wlr_keyboard->xkb_state, keycode, &syms); for (int i = 0; i < nsyms; i++) { xkb_keysym_t sym = syms[i]; @@ -287,11 +287,11 @@ static void new_input_notify(struct wl_listener *listener, void *data) { switch (device->type) { case WLR_INPUT_DEVICE_KEYBOARD:; struct sample_keyboard *keyboard = calloc(1, sizeof(struct sample_keyboard)); - keyboard->device = device; + keyboard->wlr_keyboard = wlr_keyboard_from_input_device(device); keyboard->sample = sample; wl_signal_add(&device->events.destroy, &keyboard->destroy); keyboard->destroy.notify = keyboard_destroy_notify; - wl_signal_add(&device->keyboard->events.key, &keyboard->key); + wl_signal_add(&keyboard->wlr_keyboard->events.key, &keyboard->key); keyboard->key.notify = keyboard_key_notify; struct xkb_context *context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); if (!context) { @@ -304,39 +304,40 @@ static void new_input_notify(struct wl_listener *listener, void *data) { wlr_log(WLR_ERROR, "Failed to create XKB keymap"); exit(1); } - wlr_keyboard_set_keymap(device->keyboard, keymap); + wlr_keyboard_set_keymap(keyboard->wlr_keyboard, keymap); xkb_keymap_unref(keymap); xkb_context_unref(context); break; case WLR_INPUT_DEVICE_TABLET_PAD:; struct tablet_pad_state *pstate = calloc(sizeof(struct tablet_pad_state), 1); - pstate->device = device; + pstate->wlr_tablet_pad = wlr_tablet_pad_from_input_device(device); pstate->sample = sample; pstate->destroy.notify = tablet_pad_destroy_notify; wl_signal_add(&device->events.destroy, &pstate->destroy); pstate->button.notify = tablet_pad_button_notify; - wl_signal_add(&device->tablet_pad->events.button, &pstate->button); + wl_signal_add(&pstate->wlr_tablet_pad->events.button, &pstate->button); pstate->ring.notify = tablet_pad_ring_notify; - wl_signal_add(&device->tablet_pad->events.ring, &pstate->ring); + wl_signal_add(&pstate->wlr_tablet_pad->events.ring, &pstate->ring); wl_list_insert(&sample->tablet_pads, &pstate->link); break; - case WLR_INPUT_DEVICE_TABLET_TOOL: - sample->width_mm = device->width_mm == 0 ? - 20 : device->width_mm; - sample->height_mm = device->height_mm == 0 ? - 10 : device->height_mm; + case WLR_INPUT_DEVICE_TABLET_TOOL:; + struct wlr_tablet *tablet = wlr_tablet_from_input_device(device); + sample->width_mm = tablet->width_mm == 0 ? + 20 : tablet->width_mm; + sample->height_mm = tablet->height_mm == 0 ? + 10 : tablet->height_mm; struct tablet_tool_state *tstate = calloc(sizeof(struct tablet_tool_state), 1); - tstate->device = device; + tstate->wlr_tablet = tablet; tstate->sample = sample; tstate->destroy.notify = tablet_tool_destroy_notify; wl_signal_add(&device->events.destroy, &tstate->destroy); tstate->axis.notify = tablet_tool_axis_notify; - wl_signal_add(&device->tablet->events.axis, &tstate->axis); + wl_signal_add(&tablet->events.axis, &tstate->axis); tstate->proximity.notify = tablet_tool_proximity_notify; - wl_signal_add(&device->tablet->events.proximity, &tstate->proximity); + wl_signal_add(&tablet->events.proximity, &tstate->proximity); tstate->button.notify = tablet_tool_button_notify; - wl_signal_add(&device->tablet->events.button, &tstate->button); + wl_signal_add(&tablet->events.button, &tstate->button); wl_list_insert(&sample->tablet_tools, &tstate->link); break; default: @@ -344,7 +345,6 @@ static void new_input_notify(struct wl_listener *listener, void *data) { } } - int main(int argc, char *argv[]) { wlr_log_init(WLR_DEBUG, NULL); struct wl_display *display = wl_display_create(); diff --git a/examples/text-input.c b/examples/text-input.c index 363632755..2f530d274 100644 --- a/examples/text-input.c +++ b/examples/text-input.c @@ -244,15 +244,15 @@ static void text_input_handle_done(void *data, buffer[strlen(buffer) - delete_before] = '\0'; } - char *commit_string = current.commit; + const char *commit_string = current.commit; if (!commit_string) { commit_string = ""; } - char *old_buffer = buffer; - buffer = calloc(strlen(buffer) + strlen(commit_string) + 1, sizeof(char)); // realloc may fail anyway - strcpy(buffer, old_buffer); - free(old_buffer); - strcat(buffer, commit_string); + size_t new_size = strlen(buffer) + strlen(commit_string) + 1; + char *new_buffer = calloc(new_size, sizeof(char)); // realloc may fail anyway + snprintf(new_buffer, new_size, "%s%s", buffer, commit_string); + free(buffer); + buffer = new_buffer; send_status_update(zwp_text_input_v3); show_status(); diff --git a/examples/touch.c b/examples/touch.c index ae2dcf8fc..d33e148aa 100644 --- a/examples/touch.c +++ b/examples/touch.c @@ -41,7 +41,7 @@ struct touch_point { struct touch_state { struct sample_state *sample; - struct wlr_input_device *device; + struct wlr_touch *wlr_touch; struct wl_listener destroy; struct wl_listener down; struct wl_listener up; @@ -59,7 +59,7 @@ struct sample_output { struct sample_keyboard { struct sample_state *sample; - struct wlr_input_device *device; + struct wlr_keyboard *wlr_keyboard; struct wl_listener key; struct wl_listener destroy; }; @@ -93,7 +93,7 @@ static void output_frame_notify(struct wl_listener *listener, void *data) { } static void touch_down_notify(struct wl_listener *listener, void *data) { - struct wlr_event_touch_motion *event = data; + struct wlr_touch_motion_event *event = data; struct touch_state *tstate = wl_container_of(listener, tstate, down); struct sample_state *sample = tstate->sample; struct touch_point *point = calloc(1, sizeof(struct touch_point)); @@ -104,7 +104,7 @@ static void touch_down_notify(struct wl_listener *listener, void *data) { } static void touch_up_notify(struct wl_listener *listener, void *data ) { - struct wlr_event_touch_up *event = data; + struct wlr_touch_up_event *event = data; struct touch_state *tstate = wl_container_of(listener, tstate, up); struct sample_state *sample = tstate->sample; struct touch_point *point, *tmp; @@ -117,7 +117,7 @@ static void touch_up_notify(struct wl_listener *listener, void *data ) { } static void touch_motion_notify(struct wl_listener *listener, void *data) { - struct wlr_event_touch_motion *event = data; + struct wlr_touch_motion_event *event = data; struct touch_state *tstate = wl_container_of(listener, tstate, motion); struct sample_state *sample = tstate->sample; struct touch_point *point; @@ -172,10 +172,10 @@ static void new_output_notify(struct wl_listener *listener, void *data) { static void keyboard_key_notify(struct wl_listener *listener, void *data) { struct sample_keyboard *keyboard = wl_container_of(listener, keyboard, key); struct sample_state *sample = keyboard->sample; - struct wlr_event_keyboard_key *event = data; + struct wlr_keyboard_key_event *event = data; uint32_t keycode = event->keycode + 8; const xkb_keysym_t *syms; - int nsyms = xkb_state_key_get_syms(keyboard->device->keyboard->xkb_state, + int nsyms = xkb_state_key_get_syms(keyboard->wlr_keyboard->xkb_state, keycode, &syms); for (int i = 0; i < nsyms; i++) { xkb_keysym_t sym = syms[i]; @@ -198,11 +198,11 @@ static void new_input_notify(struct wl_listener *listener, void *data) { switch (device->type) { case WLR_INPUT_DEVICE_KEYBOARD:; struct sample_keyboard *keyboard = calloc(1, sizeof(struct sample_keyboard)); - keyboard->device = device; + keyboard->wlr_keyboard = wlr_keyboard_from_input_device(device); keyboard->sample = sample; wl_signal_add(&device->events.destroy, &keyboard->destroy); keyboard->destroy.notify = keyboard_destroy_notify; - wl_signal_add(&device->keyboard->events.key, &keyboard->key); + wl_signal_add(&keyboard->wlr_keyboard->events.key, &keyboard->key); keyboard->key.notify = keyboard_key_notify; struct xkb_context *context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); if (!context) { @@ -215,22 +215,22 @@ static void new_input_notify(struct wl_listener *listener, void *data) { wlr_log(WLR_ERROR, "Failed to create XKB keymap"); exit(1); } - wlr_keyboard_set_keymap(device->keyboard, keymap); + wlr_keyboard_set_keymap(keyboard->wlr_keyboard, keymap); xkb_keymap_unref(keymap); xkb_context_unref(context); break; case WLR_INPUT_DEVICE_TOUCH:; struct touch_state *tstate = calloc(sizeof(struct touch_state), 1); - tstate->device = device; + tstate->wlr_touch = wlr_touch_from_input_device(device); tstate->sample = sample; tstate->destroy.notify = touch_destroy_notify; wl_signal_add(&device->events.destroy, &tstate->destroy); tstate->down.notify = touch_down_notify; - wl_signal_add(&device->touch->events.down, &tstate->down); + wl_signal_add(&tstate->wlr_touch->events.down, &tstate->down); tstate->motion.notify = touch_motion_notify; - wl_signal_add(&device->touch->events.motion, &tstate->motion); + wl_signal_add(&tstate->wlr_touch->events.motion, &tstate->motion); tstate->up.notify = touch_up_notify; - wl_signal_add(&device->touch->events.up, &tstate->up); + wl_signal_add(&tstate->wlr_touch->events.up, &tstate->up); wl_list_insert(&sample->touch, &tstate->link); break; default: diff --git a/include/backend/drm/drm.h b/include/backend/drm/drm.h index c5d3358f9..f362f18a0 100644 --- a/include/backend/drm/drm.h +++ b/include/backend/drm/drm.h @@ -58,6 +58,7 @@ struct wlr_drm_backend { const struct wlr_drm_interface *iface; clockid_t clock; bool addfb2_modifiers; + struct udev_hwdb *hwdb; int fd; char *name; @@ -89,15 +90,6 @@ struct wlr_drm_backend { struct wlr_drm_format_set mgpu_formats; }; -enum wlr_drm_connector_status { - // Connector is available but no output is plugged in - WLR_DRM_CONN_DISCONNECTED, - // An output just has been plugged in and is waiting for a modeset - WLR_DRM_CONN_NEEDS_MODESET, - WLR_DRM_CONN_CLEANUP, - WLR_DRM_CONN_CONNECTED, -}; - struct wlr_drm_mode { struct wlr_output_mode wlr_mode; drmModeModeInfo drm_mode; @@ -115,9 +107,10 @@ struct wlr_drm_connector { struct wlr_drm_backend *backend; char name[24]; - enum wlr_drm_connector_status status; + drmModeConnection status; bool desired_enabled; uint32_t id; + uint64_t max_bpc; struct wlr_drm_lease *lease; struct wlr_drm_crtc *crtc; diff --git a/include/backend/drm/properties.h b/include/backend/drm/properties.h index 0c5687e0e..432c183c4 100644 --- a/include/backend/drm/properties.h +++ b/include/backend/drm/properties.h @@ -21,6 +21,8 @@ union wlr_drm_connector_props { uint32_t non_desktop; uint32_t panel_orientation; // not guaranteed to exist uint32_t tile; + uint32_t content_type; // not guaranteed to exist + uint32_t max_bpc; // not guaranteed to exist // atomic-modesetting only @@ -76,4 +78,7 @@ bool get_drm_prop(int fd, uint32_t obj, uint32_t prop, uint64_t *ret); void *get_drm_prop_blob(int fd, uint32_t obj, uint32_t prop, size_t *ret_len); char *get_drm_prop_enum(int fd, uint32_t obj, uint32_t prop); +bool introspect_drm_prop_range(int fd, uint32_t prop_id, + uint64_t *min, uint64_t *max); + #endif diff --git a/include/backend/drm/renderer.h b/include/backend/drm/renderer.h index 52a2a0536..77ed4127a 100644 --- a/include/backend/drm/renderer.h +++ b/include/backend/drm/renderer.h @@ -19,10 +19,6 @@ struct wlr_drm_renderer { struct wlr_drm_surface { struct wlr_drm_renderer *renderer; - - uint32_t width; - uint32_t height; - struct wlr_swapchain *swapchain; }; @@ -40,7 +36,7 @@ bool init_drm_renderer(struct wlr_drm_backend *drm, void finish_drm_renderer(struct wlr_drm_renderer *renderer); bool init_drm_surface(struct wlr_drm_surface *surf, - struct wlr_drm_renderer *renderer, uint32_t width, uint32_t height, + struct wlr_drm_renderer *renderer, int width, int height, const struct wlr_drm_format *drm_format); bool drm_fb_import(struct wlr_drm_fb **fb, struct wlr_drm_backend *drm, diff --git a/include/backend/drm/util.h b/include/backend/drm/util.h index 1ce4b9104..12238f61c 100644 --- a/include/backend/drm/util.h +++ b/include/backend/drm/util.h @@ -2,20 +2,17 @@ #define BACKEND_DRM_UTIL_H #include -#include #include #include +struct wlr_drm_connector; + // Calculates a more accurate refresh rate (mHz) than what mode itself provides int32_t calculate_refresh_rate(const drmModeModeInfo *mode); // Populates the make/model/phys_{width,height} of output from the edid data -void parse_edid(struct wlr_output *restrict output, size_t len, - const uint8_t *data); +void parse_edid(struct wlr_drm_connector *conn, size_t len, const uint8_t *data); // Parses the TILE property -void parse_tile(struct wlr_output *restrict output, size_t len, - const uint8_t *data); -// Returns the string representation of a DRM output type -const char *conn_get_name(uint32_t type_id); +void parse_tile(struct wlr_drm_connector *conn, size_t len, const uint8_t *data); // Part of match_obj enum { diff --git a/include/backend/libinput.h b/include/backend/libinput.h index 39e6dfe5a..1ec94c2d9 100644 --- a/include/backend/libinput.h +++ b/include/backend/libinput.h @@ -5,13 +5,12 @@ #include #include #include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include struct wlr_libinput_backend { struct wlr_backend backend; @@ -26,13 +25,21 @@ struct wlr_libinput_backend { struct wl_listener session_destroy; struct wl_listener session_signal; - struct wl_array wlr_device_lists; // struct wl_list * + struct wl_list devices; // wlr_libinput_device::link }; struct wlr_libinput_input_device { - struct wlr_input_device wlr_input_device; - struct wl_list link; struct libinput_device *handle; + + struct wlr_keyboard keyboard; + struct wlr_pointer pointer; + struct wlr_switch switch_device; + struct wlr_touch touch; + struct wlr_tablet tablet; + struct wl_list tablet_tools; // see backend/libinput/tablet_tool.c + struct wlr_tablet_pad tablet_pad; + + struct wl_list link; }; uint32_t usec_to_msec(uint64_t usec); @@ -40,10 +47,6 @@ uint32_t usec_to_msec(uint64_t usec); void handle_libinput_event(struct wlr_libinput_backend *state, struct libinput_event *event); -struct wlr_input_device *get_appropriate_device( - enum wlr_input_device_type desired_type, - struct libinput_device *device); - void destroy_libinput_input_device(struct wlr_libinput_input_device *dev); extern const struct wlr_keyboard_impl libinput_keyboard_impl; @@ -53,74 +56,83 @@ extern const struct wlr_tablet_impl libinput_tablet_impl; extern const struct wlr_tablet_pad_impl libinput_tablet_pad_impl; extern const struct wlr_touch_impl libinput_touch_impl; -struct wlr_keyboard *create_libinput_keyboard( - struct libinput_device *device); -void handle_keyboard_key(struct libinput_event *event, - struct libinput_device *device); +void init_device_keyboard(struct wlr_libinput_input_device *dev); +struct wlr_libinput_input_device *device_from_keyboard(struct wlr_keyboard *kb); +void handle_keyboard_key(struct libinput_event *event, struct wlr_keyboard *kb); -struct wlr_pointer *create_libinput_pointer( - struct libinput_device *device); +void init_device_pointer(struct wlr_libinput_input_device *dev); +struct wlr_libinput_input_device *device_from_pointer(struct wlr_pointer *kb); void handle_pointer_motion(struct libinput_event *event, - struct libinput_device *device); + struct wlr_pointer *pointer); void handle_pointer_motion_abs(struct libinput_event *event, - struct libinput_device *device); + struct wlr_pointer *pointer); void handle_pointer_button(struct libinput_event *event, - struct libinput_device *device); + struct wlr_pointer *pointer); void handle_pointer_axis(struct libinput_event *event, - struct libinput_device *device); + struct wlr_pointer *pointer); +#if LIBINPUT_HAS_SCROLL_VALUE120 +void handle_pointer_axis_value120(struct libinput_event *event, + struct wlr_pointer *pointer, enum wlr_axis_source source); +#endif void handle_pointer_swipe_begin(struct libinput_event *event, - struct libinput_device *device); + struct wlr_pointer *pointer); void handle_pointer_swipe_update(struct libinput_event *event, - struct libinput_device *device); + struct wlr_pointer *pointer); void handle_pointer_swipe_end(struct libinput_event *event, - struct libinput_device *device); + struct wlr_pointer *pointer); void handle_pointer_pinch_begin(struct libinput_event *event, - struct libinput_device *device); + struct wlr_pointer *pointer); void handle_pointer_pinch_update(struct libinput_event *event, - struct libinput_device *device); + struct wlr_pointer *pointer); void handle_pointer_pinch_end(struct libinput_event *event, - struct libinput_device *device); + struct wlr_pointer *pointer); void handle_pointer_hold_begin(struct libinput_event *event, - struct libinput_device *device); + struct wlr_pointer *pointer); void handle_pointer_hold_end(struct libinput_event *event, - struct libinput_device *device); + struct wlr_pointer *pointer); -struct wlr_switch *create_libinput_switch( - struct libinput_device *device); +void init_device_switch(struct wlr_libinput_input_device *dev); +struct wlr_libinput_input_device *device_from_switch( + struct wlr_switch *switch_device); void handle_switch_toggle(struct libinput_event *event, - struct libinput_device *device); + struct wlr_switch *switch_device); -struct wlr_touch *create_libinput_touch( - struct libinput_device *device); +void init_device_touch(struct wlr_libinput_input_device *dev); +struct wlr_libinput_input_device *device_from_touch( + struct wlr_touch *touch); void handle_touch_down(struct libinput_event *event, - struct libinput_device *device); + struct wlr_touch *touch); void handle_touch_up(struct libinput_event *event, - struct libinput_device *device); + struct wlr_touch *touch); void handle_touch_motion(struct libinput_event *event, - struct libinput_device *device); + struct wlr_touch *touch); void handle_touch_cancel(struct libinput_event *event, - struct libinput_device *device); + struct wlr_touch *touch); void handle_touch_frame(struct libinput_event *event, - struct libinput_device *device); + struct wlr_touch *touch); -struct wlr_tablet *create_libinput_tablet( - struct libinput_device *device); +void init_device_tablet(struct wlr_libinput_input_device *dev); +void finish_device_tablet(struct wlr_libinput_input_device *dev); +struct wlr_libinput_input_device *device_from_tablet( + struct wlr_tablet *tablet); void handle_tablet_tool_axis(struct libinput_event *event, - struct libinput_device *device); + struct wlr_tablet *tablet); void handle_tablet_tool_proximity(struct libinput_event *event, - struct libinput_device *device); + struct wlr_tablet *tablet); void handle_tablet_tool_tip(struct libinput_event *event, - struct libinput_device *device); + struct wlr_tablet *tablet); void handle_tablet_tool_button(struct libinput_event *event, - struct libinput_device *device); + struct wlr_tablet *tablet); -struct wlr_tablet_pad *create_libinput_tablet_pad( - struct libinput_device *device); +void init_device_tablet_pad(struct wlr_libinput_input_device *dev); +void finish_device_tablet_pad(struct wlr_libinput_input_device *dev); +struct wlr_libinput_input_device *device_from_tablet_pad( + struct wlr_tablet_pad *tablet_pad); void handle_tablet_pad_button(struct libinput_event *event, - struct libinput_device *device); + struct wlr_tablet_pad *tablet_pad); void handle_tablet_pad_ring(struct libinput_event *event, - struct libinput_device *device); + struct wlr_tablet_pad *tablet_pad); void handle_tablet_pad_strip(struct libinput_event *event, - struct libinput_device *device); + struct wlr_tablet_pad *tablet_pad); #endif diff --git a/include/backend/wayland.h b/include/backend/wayland.h index 668b69aed..3a0b13271 100644 --- a/include/backend/wayland.h +++ b/include/backend/wayland.h @@ -8,7 +8,11 @@ #include #include +#include #include +#include +#include +#include #include struct wlr_wl_backend { @@ -17,7 +21,6 @@ struct wlr_wl_backend { /* local state */ bool started; struct wl_display *local_display; - struct wl_list devices; struct wl_list outputs; int drm_fd; struct wl_list buffers; // wlr_wl_buffer.link @@ -85,64 +88,73 @@ struct wlr_wl_output { } cursor; }; -struct wlr_wl_input_device { - struct wlr_input_device wlr_input_device; - struct wl_list link; - uint32_t fingers; - - struct wlr_wl_backend *backend; - struct wlr_wl_seat *seat; - void *resource; -}; - struct wlr_wl_pointer { struct wlr_pointer wlr_pointer; - struct wlr_wl_input_device *input_device; + struct wlr_wl_seat *seat; + struct wlr_wl_output *output; + + enum wlr_axis_source axis_source; + int32_t axis_discrete; + uint32_t fingers; // trackpad gesture + + struct wl_listener output_destroy; + + struct wl_list link; +}; + +struct wlr_wl_seat { + char *name; + struct wl_seat *wl_seat; + + struct wlr_wl_backend *backend; + + struct wl_keyboard *wl_keyboard; + struct wlr_keyboard wlr_keyboard; + struct wl_pointer *wl_pointer; + struct wlr_wl_pointer *active_pointer; + struct wl_list pointers; // wlr_wl_pointer::link + struct zwp_pointer_gesture_swipe_v1 *gesture_swipe; struct zwp_pointer_gesture_pinch_v1 *gesture_pinch; struct zwp_pointer_gesture_hold_v1 *gesture_hold; struct zwp_relative_pointer_v1 *relative_pointer; - enum wlr_axis_source axis_source; - int32_t axis_discrete; - struct wlr_wl_output *output; - struct wl_listener output_destroy; -}; + struct wl_touch *wl_touch; + struct wlr_touch wlr_touch; -struct wlr_wl_seat { - struct wl_seat *wl_seat; + struct zwp_tablet_seat_v2 *zwp_tablet_seat_v2; + struct zwp_tablet_v2 *zwp_tablet_v2; + struct wlr_tablet wlr_tablet; + struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2; + struct wlr_tablet_tool wlr_tablet_tool; + struct zwp_tablet_pad_v2 *zwp_tablet_pad_v2; + struct wlr_tablet_pad wlr_tablet_pad; struct wl_list link; // wlr_wl_backend.seats - char *name; - struct wl_touch *touch; - struct wl_pointer *pointer; - struct wl_keyboard *keyboard; - - struct wlr_wl_backend *backend; - struct wlr_wl_pointer *active_pointer; }; struct wlr_wl_backend *get_wl_backend_from_backend(struct wlr_backend *backend); void update_wl_output_cursor(struct wlr_wl_output *output); -struct wlr_wl_pointer *pointer_get_wl(struct wlr_pointer *wlr_pointer); -void create_wl_pointer(struct wlr_wl_seat *seat, struct wlr_wl_output *output); -void create_wl_keyboard(struct wlr_wl_seat *seat); -void create_wl_touch(struct wlr_wl_seat *seat); -struct wlr_wl_input_device *create_wl_input_device( - struct wlr_wl_seat *seat, enum wlr_input_device_type type); + +void init_seat_keyboard(struct wlr_wl_seat *seat); + +void init_seat_pointer(struct wlr_wl_seat *seat); +void finish_seat_pointer(struct wlr_wl_seat *seat); +void create_pointer(struct wlr_wl_seat *seat, struct wlr_wl_output *output); + +void init_seat_touch(struct wlr_wl_seat *seat); + +void init_seat_tablet(struct wlr_wl_seat *seat); +void finish_seat_tablet(struct wlr_wl_seat *seat); + bool create_wl_seat(struct wl_seat *wl_seat, struct wlr_wl_backend *wl); void destroy_wl_seats(struct wlr_wl_backend *wl); -void destroy_wl_input_device(struct wlr_wl_input_device *dev); void destroy_wl_buffer(struct wlr_wl_buffer *buffer); -extern const struct wl_seat_listener seat_listener; -extern const struct wlr_tablet_pad_impl tablet_pad_impl; -extern const struct wlr_tablet_impl tablet_impl; - -struct wlr_wl_tablet_seat *wl_add_tablet_seat( - struct zwp_tablet_manager_v2 *manager, - struct wlr_wl_seat *seat); +extern const struct wlr_pointer_impl wl_pointer_impl; +extern const struct wlr_tablet_pad_impl wl_tablet_pad_impl; +extern const struct wlr_tablet_impl wl_tablet_impl; #endif diff --git a/include/interfaces/wlr_input_device.h b/include/interfaces/wlr_input_device.h new file mode 100644 index 000000000..c24b53662 --- /dev/null +++ b/include/interfaces/wlr_input_device.h @@ -0,0 +1,20 @@ +#ifndef INTERFACES_INPUT_DEVICE_H +#define INTERFACES_INPUT_DEVICE_H + +#include + +/** + * Initializes a given wlr_input_device. Allocates memory for the name and sets + * its vendor and product id to 0. + * wlr_device must be non-NULL. + */ +void wlr_input_device_init(struct wlr_input_device *wlr_device, + enum wlr_input_device_type type, const char *name); + +/** + * Cleans up all the memory owned by a given wlr_input_device and signals + * the destroy event. + */ +void wlr_input_device_finish(struct wlr_input_device *wlr_device); + +#endif diff --git a/include/render/egl.h b/include/render/egl.h index 55e9ce80f..f77e11476 100644 --- a/include/render/egl.h +++ b/include/render/egl.h @@ -3,6 +3,47 @@ #include +struct wlr_egl { + EGLDisplay display; + EGLContext context; + EGLDeviceEXT device; // may be EGL_NO_DEVICE_EXT + struct gbm_device *gbm_device; + + struct { + // Display extensions + bool KHR_image_base; + bool EXT_image_dma_buf_import; + bool EXT_image_dma_buf_import_modifiers; + bool IMG_context_priority; + + // Device extensions + bool EXT_device_drm; + bool EXT_device_drm_render_node; + + // Client extensions + bool EXT_device_query; + bool KHR_platform_gbm; + bool EXT_platform_device; + } exts; + + struct { + PFNEGLGETPLATFORMDISPLAYEXTPROC eglGetPlatformDisplayEXT; + PFNEGLCREATEIMAGEKHRPROC eglCreateImageKHR; + PFNEGLDESTROYIMAGEKHRPROC eglDestroyImageKHR; + PFNEGLQUERYWAYLANDBUFFERWL eglQueryWaylandBufferWL; + PFNEGLQUERYDMABUFFORMATSEXTPROC eglQueryDmaBufFormatsEXT; + PFNEGLQUERYDMABUFMODIFIERSEXTPROC eglQueryDmaBufModifiersEXT; + PFNEGLDEBUGMESSAGECONTROLKHRPROC eglDebugMessageControlKHR; + PFNEGLQUERYDISPLAYATTRIBEXTPROC eglQueryDisplayAttribEXT; + PFNEGLQUERYDEVICESTRINGEXTPROC eglQueryDeviceStringEXT; + PFNEGLQUERYDEVICESEXTPROC eglQueryDevicesEXT; + } procs; + + bool has_modifiers; + struct wlr_drm_format_set dmabuf_texture_formats; + struct wlr_drm_format_set dmabuf_render_formats; +}; + struct wlr_egl_context { EGLDisplay display; EGLContext context; @@ -60,4 +101,16 @@ void wlr_egl_save_context(struct wlr_egl_context *context); */ bool wlr_egl_restore_context(struct wlr_egl_context *context); +/** + * Make the EGL context current. + * + * Callers are expected to clear the current context when they are done by + * calling wlr_egl_unset_current(). + */ +bool wlr_egl_make_current(struct wlr_egl *egl); + +bool wlr_egl_unset_current(struct wlr_egl *egl); + +bool wlr_egl_is_current(struct wlr_egl *egl); + #endif diff --git a/include/render/gles2.h b/include/render/gles2.h index 245b2804e..714bacf56 100644 --- a/include/render/gles2.h +++ b/include/render/gles2.h @@ -17,6 +17,8 @@ struct wlr_gles2_pixel_format { uint32_t drm_format; + // optional field, if empty then internalformat = format + GLint gl_internalformat; GLint gl_format, gl_type; bool has_alpha; }; @@ -45,6 +47,7 @@ struct wlr_gles2_renderer { bool OES_egl_image; bool EXT_texture_type_2_10_10_10_REV; bool OES_texture_half_float_linear; + bool EXT_texture_norm16; } exts; struct { diff --git a/include/types/wlr_buffer.h b/include/types/wlr_buffer.h index bdb6e5b7f..e7097ae25 100644 --- a/include/types/wlr_buffer.h +++ b/include/types/wlr_buffer.h @@ -69,4 +69,13 @@ struct wlr_dmabuf_buffer *dmabuf_buffer_create( */ bool dmabuf_buffer_drop(struct wlr_dmabuf_buffer *buffer); +/** + * Check whether a buffer is fully opaque. + * + * When true is returned, the buffer is guaranteed to be fully opaque, but the + * reverse is not true: false may be returned in cases where the buffer is fully + * opaque. + */ +bool buffer_is_opaque(struct wlr_buffer *buffer); + #endif diff --git a/include/types/wlr_keyboard.h b/include/types/wlr_keyboard.h index edcfec49b..7cd26e8a5 100644 --- a/include/types/wlr_keyboard.h +++ b/include/types/wlr_keyboard.h @@ -1,7 +1,7 @@ #include void keyboard_key_update(struct wlr_keyboard *keyboard, - struct wlr_event_keyboard_key *event); + struct wlr_keyboard_key_event *event); bool keyboard_modifier_update(struct wlr_keyboard *keyboard); diff --git a/include/types/wlr_matrix.h b/include/types/wlr_matrix.h new file mode 100644 index 000000000..ce599dc1b --- /dev/null +++ b/include/types/wlr_matrix.h @@ -0,0 +1,15 @@ +#ifndef TYPES_WLR_MATRIX_H +#define TYPES_WLR_MATRIX_H + +#include + +/** + * Writes a 2D orthographic projection matrix to mat of (width, height) with a + * specified wl_output_transform. + * + * Equivalent to glOrtho(0, width, 0, height, 1, -1) with the transform applied. + */ +void matrix_projection(float mat[static 9], int width, int height, + enum wl_output_transform transform); + +#endif diff --git a/include/types/wlr_output.h b/include/types/wlr_output.h index 1159d00a1..5f0cbe337 100644 --- a/include/types/wlr_output.h +++ b/include/types/wlr_output.h @@ -4,12 +4,15 @@ #include #include -void output_pending_resolution(struct wlr_output *output, int *width, - int *height); +void output_pending_resolution(struct wlr_output *output, + const struct wlr_output_state *state, int *width, int *height); +void output_state_attach_buffer(struct wlr_output_state *state, + struct wlr_buffer *buffer); struct wlr_drm_format *output_pick_format(struct wlr_output *output, const struct wlr_drm_format_set *display_formats, uint32_t format); void output_clear_back_buffer(struct wlr_output *output); -bool output_ensure_buffer(struct wlr_output *output); +bool output_ensure_buffer(struct wlr_output *output, + const struct wlr_output_state *state, bool *new_back_buffer); #endif diff --git a/include/types/wlr_scene.h b/include/types/wlr_scene.h new file mode 100644 index 000000000..64c11bc66 --- /dev/null +++ b/include/types/wlr_scene.h @@ -0,0 +1,8 @@ +#ifndef TYPES_WLR_SCENE_H +#define TYPES_WLR_SCENE_H + +#include + +struct wlr_scene *scene_node_get_root(struct wlr_scene_node *node); + +#endif diff --git a/include/types/wlr_xdg_shell.h b/include/types/wlr_xdg_shell.h index cfed6ee1d..37ef2a95f 100644 --- a/include/types/wlr_xdg_shell.h +++ b/include/types/wlr_xdg_shell.h @@ -26,6 +26,10 @@ void create_xdg_popup(struct wlr_xdg_surface *surface, void unmap_xdg_popup(struct wlr_xdg_popup *popup); void destroy_xdg_popup(struct wlr_xdg_popup *popup); void handle_xdg_popup_committed(struct wlr_xdg_popup *popup); +struct wlr_xdg_popup_configure *send_xdg_popup_configure( + struct wlr_xdg_popup *popup); +void handle_xdg_popup_ack_configure(struct wlr_xdg_popup *popup, + struct wlr_xdg_popup_configure *configure); void create_xdg_toplevel(struct wlr_xdg_surface *surface, uint32_t id); diff --git a/include/util/array.h b/include/util/array.h index 9612e7db9..a51bdb640 100644 --- a/include/util/array.h +++ b/include/util/array.h @@ -1,30 +1,18 @@ #ifndef UTIL_ARRAY_H #define UTIL_ARRAY_H -#include #include #include #include -size_t push_zeroes_to_end(uint32_t arr[], size_t n); - -/** - * Add `target` to `values` if it doesn't exist - * "set"s should only be modified with set_* functions - * Values MUST be greater than 0 - */ -bool set_add(uint32_t values[], size_t *len, size_t cap, uint32_t target); - -/** - * Remove `target` from `values` if it exists - * "set"s should only be modified with set_* functions - * Values MUST be greater than 0 - */ -bool set_remove(uint32_t values[], size_t *len, size_t cap, uint32_t target); - /** * Remove a chunk of memory of the specified size at the specified offset. */ void array_remove_at(struct wl_array *arr, size_t offset, size_t size); +/** + * Grow or shrink the array to fit the specifized size. + */ +bool array_realloc(struct wl_array *arr, size_t size); + #endif diff --git a/include/util/env.h b/include/util/env.h new file mode 100644 index 000000000..6720fa896 --- /dev/null +++ b/include/util/env.h @@ -0,0 +1,11 @@ +#ifndef UTIL_ENV_H +#define UTIL_ENV_H + +#include +#include + +bool env_parse_bool(const char *option); + +ssize_t env_parse_switch(const char *option, const char **switches); + +#endif diff --git a/include/util/set.h b/include/util/set.h new file mode 100644 index 000000000..d6330108a --- /dev/null +++ b/include/util/set.h @@ -0,0 +1,29 @@ +#ifndef UTIL_SET_H +#define UTIL_SET_H + +#include +#include +#include + +/** + * Add target to values. + * + * Target is added to the end of the set. + * + * Returns the index of target, or -1 if the set is full or target already + * exists. + */ +ssize_t set_add(uint32_t values[], size_t *len, size_t cap, uint32_t target); + +/** + * Remove target from values. + * + * When target is removed, the last element of the set is moved to where + * target was. + * + * Returns the previous index of target, or -1 if target wasn't in values. + */ +ssize_t set_remove(uint32_t values[], size_t *len, size_t cap, uint32_t target); + +#endif + diff --git a/include/util/signal.h b/include/util/signal.h deleted file mode 100644 index fd93073aa..000000000 --- a/include/util/signal.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef UTIL_SIGNAL_H -#define UTIL_SIGNAL_H - -#include - -void wlr_signal_emit_safe(struct wl_signal *signal, void *data); - -#endif diff --git a/include/wlr/backend.h b/include/wlr/backend.h index d781f74de..86decad41 100644 --- a/include/wlr/backend.h +++ b/include/wlr/backend.h @@ -14,22 +14,25 @@ struct wlr_backend_impl; +/** + * A backend provides a set of input and output devices. + */ struct wlr_backend { const struct wlr_backend_impl *impl; struct { - /** Raised when destroyed, passed the wlr_backend reference */ + /** Raised when destroyed */ struct wl_signal destroy; - /** Raised when new inputs are added, passed the wlr_input_device */ + /** Raised when new inputs are added, passed the struct wlr_input_device */ struct wl_signal new_input; - /** Raised when new outputs are added, passed the wlr_output */ + /** Raised when new outputs are added, passed the struct wlr_output */ struct wl_signal new_output; } events; }; /** * Automatically initializes the most suitable backend given the environment. - * Will always return a multibackend. The backend is created but not started. + * Will always return a multi-backend. The backend is created but not started. * Returns NULL on failure. */ struct wlr_backend *wlr_backend_autocreate(struct wl_display *display); @@ -41,11 +44,11 @@ struct wlr_backend *wlr_backend_autocreate(struct wl_display *display); bool wlr_backend_start(struct wlr_backend *backend); /** * Destroy the backend and clean up all of its resources. Normally called - * automatically when the wl_display is destroyed. + * automatically when the struct wl_display is destroyed. */ void wlr_backend_destroy(struct wlr_backend *backend); /** - * Obtains the wlr_session reference from this backend if there is any. + * Obtains the struct wlr_session reference from this backend if there is any. * Might return NULL for backends that don't use a session. */ struct wlr_session *wlr_backend_get_session(struct wlr_backend *backend); diff --git a/include/wlr/backend/drm.h b/include/wlr/backend/drm.h index 800bc585f..1617aa151 100644 --- a/include/wlr/backend/drm.h +++ b/include/wlr/backend/drm.h @@ -48,8 +48,9 @@ bool wlr_output_is_drm(struct wlr_output *output); uint32_t wlr_drm_connector_get_id(struct wlr_output *output); /** - * Tries to open non-master DRM FD. The compositor must not call `drmSetMaster` + * Tries to open non-master DRM FD. The compositor must not call drmSetMaster() * on the returned FD. + * * Returns a valid opened DRM FD, or -1 on error. */ int wlr_drm_backend_get_non_master_fd(struct wlr_backend *backend); @@ -71,7 +72,7 @@ struct wlr_drm_lease *wlr_drm_create_lease(struct wlr_output **outputs, void wlr_drm_lease_terminate(struct wlr_drm_lease *lease); /** - * Add mode to the list of available modes + * Add mode to the list of available modes. */ typedef struct _drmModeModeInfo drmModeModeInfo; struct wlr_output_mode *wlr_drm_connector_add_mode(struct wlr_output *output, diff --git a/include/wlr/backend/headless.h b/include/wlr/backend/headless.h index f47354830..2516f3a68 100644 --- a/include/wlr/backend/headless.h +++ b/include/wlr/backend/headless.h @@ -10,7 +10,6 @@ #define WLR_BACKEND_HEADLESS_H #include -#include #include /** @@ -19,9 +18,9 @@ */ struct wlr_backend *wlr_headless_backend_create(struct wl_display *display); /** - * Create a new headless output backed by an in-memory EGL framebuffer. You can - * read pixels from this framebuffer via wlr_renderer_read_pixels but it is - * otherwise not displayed. + * Create a new headless output. + * + * The buffers presented on the output won't be displayed to the user. */ struct wlr_output *wlr_headless_add_output(struct wlr_backend *backend, unsigned int width, unsigned int height); diff --git a/include/wlr/backend/interface.h b/include/wlr/backend/interface.h index f0cafb015..d5bb9bca0 100644 --- a/include/wlr/backend/interface.h +++ b/include/wlr/backend/interface.h @@ -23,8 +23,8 @@ struct wlr_backend_impl { }; /** - * Initializes common state on a wlr_backend and sets the implementation to the - * provided wlr_backend_impl reference. + * Initializes common state on a struct wlr_backend and sets the implementation + * to the provided struct wlr_backend_impl reference. */ void wlr_backend_init(struct wlr_backend *backend, const struct wlr_backend_impl *impl); diff --git a/include/wlr/backend/libinput.h b/include/wlr/backend/libinput.h index 50faaf7dc..83d281f9d 100644 --- a/include/wlr/backend/libinput.h +++ b/include/wlr/backend/libinput.h @@ -13,11 +13,14 @@ #include #include #include -#include + +struct wlr_input_device; struct wlr_backend *wlr_libinput_backend_create(struct wl_display *display, struct wlr_session *session); -/** Gets the underlying libinput_device handle for the given wlr_input_device */ +/** + * Gets the underlying struct libinput_device handle for the given input device. + */ struct libinput_device *wlr_libinput_get_device_handle( struct wlr_input_device *dev); diff --git a/include/wlr/backend/session.h b/include/wlr/backend/session.h index c8461ff7c..e5deda574 100644 --- a/include/wlr/backend/session.h +++ b/include/wlr/backend/session.h @@ -79,36 +79,33 @@ struct wlr_device_change_event { * This should not be called if another program is already in control * of the terminal (Xorg, another Wayland compositor, etc.). * - * If libseat support is not enabled, or if a standalone backend is to be used, - * then you must have CAP_SYS_ADMIN or be root. It is safe to drop privileges - * after this is called. - * * Returns NULL on error. */ struct wlr_session *wlr_session_create(struct wl_display *disp); /* * Closes a previously opened session and restores the virtual terminal. - * You should call wlr_session_close_file on each files you opened - * with wlr_session_open_file before you call this. + * You should call wlr_session_close_file() on each files you opened + * with wlr_session_open_file() before you call this. */ void wlr_session_destroy(struct wlr_session *session); /* * Opens the file at path. - * This can only be used to open DRM or evdev (input) devices. + * + * This can only be used to open DRM or evdev (input) devices. Files opened via + * this function must be closed by calling wlr_session_close_file(). * * When the session becomes inactive: + * * - DRM files lose their DRM master status * - evdev files become invalid and should be closed - * - * Returns -errno on error. */ struct wlr_device *wlr_session_open_file(struct wlr_session *session, const char *path); /* - * Closes a file previously opened with wlr_session_open_file. + * Closes a file previously opened with wlr_session_open_file(). */ void wlr_session_close_file(struct wlr_session *session, struct wlr_device *device); diff --git a/include/wlr/backend/wayland.h b/include/wlr/backend/wayland.h index a32a682a1..a5b5e7a30 100644 --- a/include/wlr/backend/wayland.h +++ b/include/wlr/backend/wayland.h @@ -4,22 +4,23 @@ #include #include #include -#include #include +struct wlr_input_device; + /** - * Creates a new wlr_wl_backend. This backend will be created with no outputs; - * you must use wlr_wl_output_create to add them. + * Creates a new Wayland backend. This backend will be created with no outputs; + * you must use wlr_wl_output_create() to add them. * * The `remote` argument is the name of the host compositor wayland socket. Set * to NULL for the default behaviour (WAYLAND_DISPLAY env variable or wayland-0 - * default) + * default). */ struct wlr_backend *wlr_wl_backend_create(struct wl_display *display, const char *remote); /** - * Returns the remote wl_display used by the Wayland backend. + * Returns the remote struct wl_display used by the Wayland backend. */ struct wl_display *wlr_wl_backend_get_remote_display(struct wlr_backend *backend); @@ -27,37 +28,37 @@ struct wl_display *wlr_wl_backend_get_remote_display(struct wlr_backend *backend * Adds a new output to this backend. You may remove outputs by destroying them. * Note that if called before initializing the backend, this will return NULL * and your outputs will be created during initialization (and given to you via - * the output_add signal). + * the new_output signal). */ struct wlr_output *wlr_wl_output_create(struct wlr_backend *backend); /** - * True if the given backend is a wlr_wl_backend. + * Check whether the provided backend is a Wayland backend. */ bool wlr_backend_is_wl(struct wlr_backend *backend); /** - * True if the given input device is a wlr_wl_input_device. + * Check whether the provided input device is a Wayland input device. */ bool wlr_input_device_is_wl(struct wlr_input_device *device); /** - * True if the given output is a wlr_wl_output. + * Check whether the provided output device is a Wayland output device. */ bool wlr_output_is_wl(struct wlr_output *output); /** - * Sets the title of a wlr_output which is a Wayland window. + * Sets the title of a struct wlr_output which is a Wayland toplevel. */ void wlr_wl_output_set_title(struct wlr_output *output, const char *title); /** - * Returns the remote wl_surface used by the Wayland output. + * Returns the remote struct wl_surface used by the Wayland output. */ struct wl_surface *wlr_wl_output_get_surface(struct wlr_output *output); /** - * Returns the remote wl_seat for a Wayland input device. + * Returns the remote struct wl_seat for a Wayland input device. */ struct wl_seat *wlr_wl_input_device_get_seat(struct wlr_input_device *dev); diff --git a/include/wlr/backend/x11.h b/include/wlr/backend/x11.h index 90918f3f8..54d91c758 100644 --- a/include/wlr/backend/x11.h +++ b/include/wlr/backend/x11.h @@ -6,15 +6,16 @@ #include #include -#include #include +struct wlr_input_device; + /** - * Creates a new wlr_x11_backend. This backend will be created with no outputs; - * you must use wlr_x11_output_create to add them. + * Creates a new X11 backend. This backend will be created with no outputs; + * you must use wlr_x11_output_create() to add them. * * The `x11_display` argument is the name of the X Display socket. Set - * to NULL for the default behaviour of XOpenDisplay. + * to NULL for the default behaviour of XOpenDisplay(). */ struct wlr_backend *wlr_x11_backend_create(struct wl_display *display, const char *x11_display); @@ -23,27 +24,27 @@ struct wlr_backend *wlr_x11_backend_create(struct wl_display *display, * Adds a new output to this backend. You may remove outputs by destroying them. * Note that if called before initializing the backend, this will return NULL * and your outputs will be created during initialization (and given to you via - * the output_add signal). + * the new_output signal). */ struct wlr_output *wlr_x11_output_create(struct wlr_backend *backend); /** - * True if the given backend is a wlr_x11_backend. + * Check whether this backend is an X11 backend. */ bool wlr_backend_is_x11(struct wlr_backend *backend); /** - * True if the given input device is a wlr_x11_input_device. + * Check whether this input device is an X11 input device. */ bool wlr_input_device_is_x11(struct wlr_input_device *device); /** - * True if the given output is a wlr_x11_output. + * Check whether this output device is an X11 output device. */ bool wlr_output_is_x11(struct wlr_output *output); /** - * Sets the title of a wlr_output which is an X11 window. + * Sets the title of a struct wlr_output which is an X11 window. */ void wlr_x11_output_set_title(struct wlr_output *output, const char *title); diff --git a/include/wlr/config.h.in b/include/wlr/config.h.in index 71868a349..0b612271c 100644 --- a/include/wlr/config.h.in +++ b/include/wlr/config.h.in @@ -6,9 +6,10 @@ #mesondefine WLR_HAS_X11_BACKEND #mesondefine WLR_HAS_GLES2_RENDERER - #mesondefine WLR_HAS_VULKAN_RENDERER +#mesondefine WLR_HAS_GBM_ALLOCATOR + #mesondefine WLR_HAS_XWAYLAND #endif diff --git a/include/wlr/interfaces/wlr_buffer.h b/include/wlr/interfaces/wlr_buffer.h new file mode 100644 index 000000000..820300f65 --- /dev/null +++ b/include/wlr/interfaces/wlr_buffer.h @@ -0,0 +1,48 @@ +/* + * This an unstable interface of wlroots. No guarantees are made regarding the + * future consistency of this API. + */ +#ifndef WLR_USE_UNSTABLE +#error "Add -DWLR_USE_UNSTABLE to enable unstable wlroots features" +#endif + +#ifndef WLR_INTERFACES_WLR_BUFFER_H +#define WLR_INTERFACES_WLR_BUFFER_H + +#include + +struct wlr_buffer_impl { + void (*destroy)(struct wlr_buffer *buffer); + bool (*get_dmabuf)(struct wlr_buffer *buffer, + struct wlr_dmabuf_attributes *attribs); + bool (*get_shm)(struct wlr_buffer *buffer, + struct wlr_shm_attributes *attribs); + bool (*begin_data_ptr_access)(struct wlr_buffer *buffer, uint32_t flags, + void **data, uint32_t *format, size_t *stride); + void (*end_data_ptr_access)(struct wlr_buffer *buffer); +}; + +struct wlr_buffer_resource_interface { + const char *name; + bool (*is_instance)(struct wl_resource *resource); + struct wlr_buffer *(*from_resource)(struct wl_resource *resource); +}; + +/** + * Initialize a buffer. This function should be called by producers. The + * initialized buffer is referenced: once the producer is done with the buffer + * they should call wlr_buffer_drop(). + */ +void wlr_buffer_init(struct wlr_buffer *buffer, + const struct wlr_buffer_impl *impl, int width, int height); + +/** + * Allows the registration of a struct wl_resource implementation. + * + * The matching function will be called for the struct wl_resource when creating + * a struct wlr_buffer from a struct wl_resource. + */ +void wlr_buffer_register_resource_interface( + const struct wlr_buffer_resource_interface *iface); + +#endif diff --git a/include/wlr/interfaces/wlr_keyboard.h b/include/wlr/interfaces/wlr_keyboard.h index 4bcef57b2..2ec7c8cfe 100644 --- a/include/wlr/interfaces/wlr_keyboard.h +++ b/include/wlr/interfaces/wlr_keyboard.h @@ -13,15 +13,20 @@ #include struct wlr_keyboard_impl { - void (*destroy)(struct wlr_keyboard *keyboard); + const char *name; void (*led_update)(struct wlr_keyboard *keyboard, uint32_t leds); }; void wlr_keyboard_init(struct wlr_keyboard *keyboard, - const struct wlr_keyboard_impl *impl, const char *name); -void wlr_keyboard_destroy(struct wlr_keyboard *keyboard); + const struct wlr_keyboard_impl *impl, const char *name); + +/** + * Cleans up all of the resources owned by the struct wlr_keyboard. + */ +void wlr_keyboard_finish(struct wlr_keyboard *keyboard); + void wlr_keyboard_notify_key(struct wlr_keyboard *keyboard, - struct wlr_event_keyboard_key *event); + struct wlr_keyboard_key_event *event); void wlr_keyboard_notify_modifiers(struct wlr_keyboard *keyboard, uint32_t mods_depressed, uint32_t mods_latched, uint32_t mods_locked, uint32_t group); diff --git a/include/wlr/interfaces/wlr_output.h b/include/wlr/interfaces/wlr_output.h index 79cc8ee0a..7ef3de98e 100644 --- a/include/wlr/interfaces/wlr_output.h +++ b/include/wlr/interfaces/wlr_output.h @@ -22,10 +22,10 @@ WLR_OUTPUT_STATE_SCALE | \ WLR_OUTPUT_STATE_TRANSFORM | \ WLR_OUTPUT_STATE_RENDER_FORMAT | \ - WLR_OUTPUT_STATE_ADAPTIVE_SYNC_ENABLED) + WLR_OUTPUT_STATE_SUBPIXEL) /** - * A backend implementation of wlr_output. + * A backend implementation of struct wlr_output. * * The commit function is mandatory. Other functions are optional. */ @@ -38,7 +38,7 @@ struct wlr_output_impl { * The hotspot indicates the offset that needs to be applied to the * top-left corner of the image to match the cursor position. In other * words, the image should be displayed at (x - hotspot_x, y - hotspot_y). - * The hotspot is given in the texture's coordinate space. + * The hotspot is given in the buffer's coordinate space. */ bool (*set_cursor)(struct wlr_output *output, struct wlr_buffer *buffer, int hotspot_x, int hotspot_y); @@ -53,18 +53,18 @@ struct wlr_output_impl { */ void (*destroy)(struct wlr_output *output); /** - * Check that the pending output state is a valid configuration. + * Check that the supplied output state is a valid configuration. * * If this function returns true, commit can only fail due to a runtime * error. */ - bool (*test)(struct wlr_output *output); + bool (*test)(struct wlr_output *output, const struct wlr_output_state *state); /** - * Commit the pending output state. + * Commit the supplied output state. * * If a buffer has been attached, a frame event is scheduled. */ - bool (*commit)(struct wlr_output *output); + bool (*commit)(struct wlr_output *output, const struct wlr_output_state *state); /** * Get the maximum number of gamma LUT elements for each channel. * diff --git a/include/wlr/interfaces/wlr_pointer.h b/include/wlr/interfaces/wlr_pointer.h index e39500175..74e0feafe 100644 --- a/include/wlr/interfaces/wlr_pointer.h +++ b/include/wlr/interfaces/wlr_pointer.h @@ -12,11 +12,11 @@ #include struct wlr_pointer_impl { - void (*destroy)(struct wlr_pointer *pointer); + const char *name; }; void wlr_pointer_init(struct wlr_pointer *pointer, const struct wlr_pointer_impl *impl, const char *name); -void wlr_pointer_destroy(struct wlr_pointer *pointer); +void wlr_pointer_finish(struct wlr_pointer *pointer); #endif diff --git a/include/wlr/interfaces/wlr_switch.h b/include/wlr/interfaces/wlr_switch.h index fbf5e6cb9..793ed25c2 100644 --- a/include/wlr/interfaces/wlr_switch.h +++ b/include/wlr/interfaces/wlr_switch.h @@ -12,11 +12,11 @@ #include struct wlr_switch_impl { - void (*destroy)(struct wlr_switch *switch_device); + const char *name; }; void wlr_switch_init(struct wlr_switch *switch_device, const struct wlr_switch_impl *impl, const char *name); -void wlr_switch_destroy(struct wlr_switch *switch_device); +void wlr_switch_finish(struct wlr_switch *switch_device); #endif diff --git a/include/wlr/interfaces/wlr_tablet_pad.h b/include/wlr/interfaces/wlr_tablet_pad.h index ff5c93594..f4a422f2f 100644 --- a/include/wlr/interfaces/wlr_tablet_pad.h +++ b/include/wlr/interfaces/wlr_tablet_pad.h @@ -12,11 +12,19 @@ #include struct wlr_tablet_pad_impl { - void (*destroy)(struct wlr_tablet_pad *pad); + const char *name; }; void wlr_tablet_pad_init(struct wlr_tablet_pad *pad, const struct wlr_tablet_pad_impl *impl, const char *name); -void wlr_tablet_pad_destroy(struct wlr_tablet_pad *pad); + +/** + * Cleans up the resources owned by a struct wlr_tablet_pad. + * + * This function will not clean the memory allocated by + * struct wlr_tablet_pad_group, it's the responsibility of the caller to clean + * it. + */ +void wlr_tablet_pad_finish(struct wlr_tablet_pad *pad); #endif diff --git a/include/wlr/interfaces/wlr_tablet_tool.h b/include/wlr/interfaces/wlr_tablet_tool.h index de7430a2f..68bf8cf74 100644 --- a/include/wlr/interfaces/wlr_tablet_tool.h +++ b/include/wlr/interfaces/wlr_tablet_tool.h @@ -12,11 +12,11 @@ #include struct wlr_tablet_impl { - void (*destroy)(struct wlr_tablet *tablet); + const char *name; }; void wlr_tablet_init(struct wlr_tablet *tablet, const struct wlr_tablet_impl *impl, const char *name); -void wlr_tablet_destroy(struct wlr_tablet *tablet); +void wlr_tablet_finish(struct wlr_tablet *tablet); #endif diff --git a/include/wlr/interfaces/wlr_touch.h b/include/wlr/interfaces/wlr_touch.h index 2b95d2bf8..e48a92f22 100644 --- a/include/wlr/interfaces/wlr_touch.h +++ b/include/wlr/interfaces/wlr_touch.h @@ -12,11 +12,11 @@ #include struct wlr_touch_impl { - void (*destroy)(struct wlr_touch *touch); + const char *name; }; void wlr_touch_init(struct wlr_touch *touch, const struct wlr_touch_impl *impl, const char *name); -void wlr_touch_destroy(struct wlr_touch *touch); +void wlr_touch_finish(struct wlr_touch *touch); #endif diff --git a/include/wlr/meson.build b/include/wlr/meson.build index ae9c17a3e..f7ca413de 100644 --- a/include/wlr/meson.build +++ b/include/wlr/meson.build @@ -1,4 +1,5 @@ -version_array = meson.project_version().split('.') +version_base = meson.project_version().split('-')[0] +version_array = version_base.split('.') version_data = configuration_data() version_data.set_quoted('WLR_VERSION_STR', meson.project_version()) version_data.set('WLR_VERSION_MAJOR', version_array[0]) diff --git a/include/wlr/render/allocator.h b/include/wlr/render/allocator.h index 3150e36c3..f5bb7522c 100644 --- a/include/wlr/render/allocator.h +++ b/include/wlr/render/allocator.h @@ -37,7 +37,7 @@ struct wlr_allocator { }; /** - * Creates the adequate wlr_allocator given a backend and a renderer + * Creates the adequate struct wlr_allocator given a backend and a renderer. */ struct wlr_allocator *wlr_allocator_autocreate(struct wlr_backend *backend, struct wlr_renderer *renderer); @@ -50,7 +50,7 @@ void wlr_allocator_destroy(struct wlr_allocator *alloc); * Allocate a new buffer. * * When the caller is done with it, they must unreference it by calling - * wlr_buffer_drop. + * wlr_buffer_drop(). * * The `format` passed in indicates the format to use and the list of * acceptable modifiers. The order in which modifiers are listed is not diff --git a/include/wlr/render/drm_format_set.h b/include/wlr/render/drm_format_set.h index 9f4a86ea4..6dbdc7494 100644 --- a/include/wlr/render/drm_format_set.h +++ b/include/wlr/render/drm_format_set.h @@ -51,7 +51,7 @@ struct wlr_drm_format_set { void wlr_drm_format_set_finish(struct wlr_drm_format_set *set); /** - * Return a pointer to a member of this `wlr_drm_format_set` of format + * Return a pointer to a member of this struct wlr_drm_format_set of format * `format`, or NULL if none exists. */ const struct wlr_drm_format *wlr_drm_format_set_get( diff --git a/include/wlr/render/egl.h b/include/wlr/render/egl.h index 0d84958be..9bf1b8019 100644 --- a/include/wlr/render/egl.h +++ b/include/wlr/render/egl.h @@ -9,9 +9,6 @@ #ifndef WLR_RENDER_EGL_H #define WLR_RENDER_EGL_H -#ifndef MESA_EGL_NO_X11_HEADERS -#define MESA_EGL_NO_X11_HEADERS -#endif #ifndef EGL_NO_X11 #define EGL_NO_X11 #endif @@ -29,60 +26,31 @@ #include #include -struct wlr_egl { - EGLDisplay display; - EGLContext context; - EGLDeviceEXT device; // may be EGL_NO_DEVICE_EXT - struct gbm_device *gbm_device; - - struct { - // Display extensions - bool KHR_image_base; - bool EXT_image_dma_buf_import; - bool EXT_image_dma_buf_import_modifiers; - bool IMG_context_priority; - - // Device extensions - bool EXT_device_drm; - bool EXT_device_drm_render_node; - - // Client extensions - bool EXT_device_query; - bool KHR_platform_gbm; - bool EXT_platform_device; - } exts; - - struct { - PFNEGLGETPLATFORMDISPLAYEXTPROC eglGetPlatformDisplayEXT; - PFNEGLCREATEIMAGEKHRPROC eglCreateImageKHR; - PFNEGLDESTROYIMAGEKHRPROC eglDestroyImageKHR; - PFNEGLQUERYWAYLANDBUFFERWL eglQueryWaylandBufferWL; - PFNEGLQUERYDMABUFFORMATSEXTPROC eglQueryDmaBufFormatsEXT; - PFNEGLQUERYDMABUFMODIFIERSEXTPROC eglQueryDmaBufModifiersEXT; - PFNEGLDEBUGMESSAGECONTROLKHRPROC eglDebugMessageControlKHR; - PFNEGLQUERYDISPLAYATTRIBEXTPROC eglQueryDisplayAttribEXT; - PFNEGLQUERYDEVICESTRINGEXTPROC eglQueryDeviceStringEXT; - PFNEGLQUERYDEVICESEXTPROC eglQueryDevicesEXT; - } procs; - - bool has_modifiers; - struct wlr_drm_format_set dmabuf_texture_formats; - struct wlr_drm_format_set dmabuf_render_formats; -}; +struct wlr_egl; +/** + * Create a struct wlr_egl with an existing EGL display and context. + * + * This is typically used by compositors which want to customize EGL + * initialization. + */ struct wlr_egl *wlr_egl_create_with_context(EGLDisplay display, EGLContext context); /** - * Make the EGL context current. + * Get the EGL display used by the struct wlr_egl. * - * Callers are expected to clear the current context when they are done by - * calling wlr_egl_unset_current. + * This is typically used by compositors which need to perform custom OpenGL + * operations. */ -bool wlr_egl_make_current(struct wlr_egl *egl); +EGLDisplay wlr_egl_get_display(struct wlr_egl *egl); -bool wlr_egl_unset_current(struct wlr_egl *egl); - -bool wlr_egl_is_current(struct wlr_egl *egl); +/** + * Get the EGL context used by the struct wlr_egl. + * + * This is typically used by compositors which need to perform custom OpenGL + * operations. + */ +EGLContext wlr_egl_get_context(struct wlr_egl *egl); #endif diff --git a/include/wlr/render/interface.h b/include/wlr/render/interface.h index 4207bd304..20d755f9d 100644 --- a/include/wlr/render/interface.h +++ b/include/wlr/render/interface.h @@ -54,11 +54,8 @@ void wlr_renderer_init(struct wlr_renderer *renderer, const struct wlr_renderer_impl *impl); struct wlr_texture_impl { - bool (*is_opaque)(struct wlr_texture *texture); - bool (*write_pixels)(struct wlr_texture *texture, - uint32_t stride, uint32_t width, uint32_t height, - uint32_t src_x, uint32_t src_y, uint32_t dst_x, uint32_t dst_y, - const void *data); + bool (*update_from_buffer)(struct wlr_texture *texture, + struct wlr_buffer *buffer, pixman_region32_t *damage); void (*destroy)(struct wlr_texture *texture); }; diff --git a/include/wlr/render/wlr_renderer.h b/include/wlr/render/wlr_renderer.h index d8b04dc72..50ba6b215 100644 --- a/include/wlr/render/wlr_renderer.h +++ b/include/wlr/render/wlr_renderer.h @@ -77,13 +77,13 @@ void wlr_render_quad_with_matrix(struct wlr_renderer *r, const float color[static 4], const float matrix[static 9]); /** * Get the shared-memory formats supporting import usage. Buffers allocated - * with a format from this list may be imported via wlr_texture_from_pixels. + * with a format from this list may be imported via wlr_texture_from_pixels(). */ const uint32_t *wlr_renderer_get_shm_texture_formats( struct wlr_renderer *r, size_t *len); /** * Get the DMA-BUF formats supporting sampling usage. Buffers allocated with - * a format from this list may be imported via wlr_texture_from_dmabuf. + * a format from this list may be imported via wlr_texture_from_dmabuf(). */ const struct wlr_drm_format_set *wlr_renderer_get_dmabuf_texture_formats( struct wlr_renderer *renderer); @@ -92,7 +92,7 @@ const struct wlr_drm_format_set *wlr_renderer_get_dmabuf_texture_formats( * bytes. * * If `flags` is not NULl, the caller indicates that it accepts frame flags - * defined in `enum wlr_renderer_read_pixels_flags`. + * defined in enum wlr_renderer_read_pixels_flags. */ bool wlr_renderer_read_pixels(struct wlr_renderer *r, uint32_t fmt, uint32_t *flags, uint32_t stride, uint32_t width, uint32_t height, @@ -107,7 +107,7 @@ bool wlr_renderer_init_wl_display(struct wlr_renderer *r, struct wl_display *wl_display); /** - * Initializes wl_shm on the provided wl_display. + * Initializes wl_shm on the provided struct wl_display. */ bool wlr_renderer_init_wl_shm(struct wlr_renderer *r, struct wl_display *wl_display); @@ -120,7 +120,9 @@ bool wlr_renderer_init_wl_shm(struct wlr_renderer *r, int wlr_renderer_get_drm_fd(struct wlr_renderer *r); /** - * Destroys this wlr_renderer. Textures must be destroyed separately. + * Destroys the renderer. + * + * Textures must be destroyed separately. */ void wlr_renderer_destroy(struct wlr_renderer *renderer); diff --git a/include/wlr/render/wlr_texture.h b/include/wlr/render/wlr_texture.h index 1dbcba1de..5d4b0b618 100644 --- a/include/wlr/render/wlr_texture.h +++ b/include/wlr/render/wlr_texture.h @@ -9,6 +9,7 @@ #ifndef WLR_RENDER_WLR_TEXTURE_H #define WLR_RENDER_WLR_TEXTURE_H +#include #include #include #include @@ -25,9 +26,6 @@ struct wlr_texture { /** * Create a new texture from raw pixel data. `stride` is in bytes. The returned * texture is mutable. - * - * Should not be called in a rendering block like renderer_begin()/end() or - * between attaching a renderer to an output and committing it. */ struct wlr_texture *wlr_texture_from_pixels(struct wlr_renderer *renderer, uint32_t fmt, uint32_t stride, uint32_t width, uint32_t height, @@ -35,40 +33,30 @@ struct wlr_texture *wlr_texture_from_pixels(struct wlr_renderer *renderer, /** * Create a new texture from a DMA-BUF. The returned texture is immutable. - * - * Should not be called in a rendering block like renderer_begin()/end() or - * between attaching a renderer to an output and committing it. */ struct wlr_texture *wlr_texture_from_dmabuf(struct wlr_renderer *renderer, struct wlr_dmabuf_attributes *attribs); /** - * Returns true if this texture is using a fully opaque format. - */ -bool wlr_texture_is_opaque(struct wlr_texture *texture); - -/** - * Update a texture with raw pixels. The texture must be mutable, and the input - * data must have the same pixel format that the texture was created with. + * Update a texture with a struct wlr_buffer's contents. * - * Should not be called in a rendering block like renderer_begin()/end() or - * between attaching a renderer to an output and committing it. + * The update might be rejected (in case the texture is immutable, the buffer + * has an unsupported type/format, etc), so callers must be prepared to fall + * back to re-creating the texture from scratch via wlr_texture_from_buffer(). + * + * The damage can be used by the renderer as an optimization: only the supplied + * region needs to be updated. */ -bool wlr_texture_write_pixels(struct wlr_texture *texture, - uint32_t stride, uint32_t width, uint32_t height, - uint32_t src_x, uint32_t src_y, uint32_t dst_x, uint32_t dst_y, - const void *data); +bool wlr_texture_update_from_buffer(struct wlr_texture *texture, + struct wlr_buffer *buffer, pixman_region32_t *damage); /** - * Destroys this wlr_texture. + * Destroys the texture. */ void wlr_texture_destroy(struct wlr_texture *texture); /** * Create a new texture from a buffer. - * - * Should not be called in a rendering block like renderer_begin()/end() or - * between attaching a renderer to an output and committing it. */ struct wlr_texture *wlr_texture_from_buffer(struct wlr_renderer *renderer, struct wlr_buffer *buffer); diff --git a/include/wlr/types/wlr_buffer.h b/include/wlr/types/wlr_buffer.h index 60dbb5c38..b24c0ccd1 100644 --- a/include/wlr/types/wlr_buffer.h +++ b/include/wlr/types/wlr_buffer.h @@ -24,22 +24,11 @@ struct wlr_shm_attributes { off_t offset; }; -struct wlr_buffer_impl { - void (*destroy)(struct wlr_buffer *buffer); - bool (*get_dmabuf)(struct wlr_buffer *buffer, - struct wlr_dmabuf_attributes *attribs); - bool (*get_shm)(struct wlr_buffer *buffer, - struct wlr_shm_attributes *attribs); - bool (*begin_data_ptr_access)(struct wlr_buffer *buffer, uint32_t flags, - void **data, uint32_t *format, size_t *stride); - void (*end_data_ptr_access)(struct wlr_buffer *buffer); -}; - /** * Buffer capabilities. * - * These bits indicate the features supported by a wlr_buffer. There is one bit - * per function in wlr_buffer_impl. + * These bits indicate the features supported by a struct wlr_buffer. There is + * one bit per function in struct wlr_buffer_impl. */ enum wlr_buffer_cap { WLR_BUFFER_CAP_DATA_PTR = 1 << 0, @@ -72,19 +61,6 @@ struct wlr_buffer { struct wlr_addon_set addons; }; -struct wlr_buffer_resource_interface { - const char *name; - bool (*is_instance)(struct wl_resource *resource); - struct wlr_buffer *(*from_resource)(struct wl_resource *resource); -}; - -/** - * Initialize a buffer. This function should be called by producers. The - * initialized buffer is referenced: once the producer is done with the buffer - * they should call wlr_buffer_drop. - */ -void wlr_buffer_init(struct wlr_buffer *buffer, - const struct wlr_buffer_impl *impl, int width, int height); /** * Unreference the buffer. This function should be called by producers when * they are done with the buffer. @@ -93,7 +69,7 @@ void wlr_buffer_drop(struct wlr_buffer *buffer); /** * Lock the buffer. This function should be called by consumers to make * sure the buffer can be safely read from. Once the consumer is done with the - * buffer, they should call wlr_buffer_unlock. + * buffer, they should call wlr_buffer_unlock(). */ struct wlr_buffer *wlr_buffer_lock(struct wlr_buffer *buffer); /** @@ -106,7 +82,7 @@ void wlr_buffer_unlock(struct wlr_buffer *buffer); * returns false. * * The returned DMA-BUF attributes are valid for the lifetime of the - * wlr_buffer. The caller isn't responsible for cleaning up the DMA-BUF + * struct wlr_buffer. The caller isn't responsible for cleaning up the DMA-BUF * attributes. */ bool wlr_buffer_get_dmabuf(struct wlr_buffer *buffer, @@ -116,24 +92,16 @@ bool wlr_buffer_get_dmabuf(struct wlr_buffer *buffer, * memory, returns false. * * The returned shared memory attributes are valid for the lifetime of the - * wlr_buffer. The caller isn't responsible for cleaning up the shared memory - * attributes. + * struct wlr_buffer. The caller isn't responsible for cleaning up the shared + * memory attributes. */ bool wlr_buffer_get_shm(struct wlr_buffer *buffer, struct wlr_shm_attributes *attribs); /** - * Allows the registration of a wl_resource implementation. + * Transforms a struct wl_resource into a struct wlr_buffer and locks it. Once + * the caller is done with the buffer, they must call wlr_buffer_unlock(). * - * The matching function will be called for the wl_resource when creating a - * wlr_buffer from a wl_resource. - */ -void wlr_buffer_register_resource_interface( - const struct wlr_buffer_resource_interface *iface); -/** - * Transforms a wl_resource into a wlr_buffer and locks it. Once the caller is - * done with the buffer, they must call wlr_buffer_unlock. - * - * The provided wl_resource must be a wl_buffer. + * The provided struct wl_resource must be a wl_buffer. */ struct wlr_buffer *wlr_buffer_from_resource(struct wl_resource *resource); @@ -158,7 +126,7 @@ enum wlr_buffer_data_ptr_access_flag { * * The returned pointer should be pointing to a valid memory region for the * operations specified in the flags. The returned pointer is only valid up to - * the next buffer_end_data_ptr_access call. + * the next wlr_buffer_end_data_ptr_access() call. */ bool wlr_buffer_begin_data_ptr_access(struct wlr_buffer *buffer, uint32_t flags, void **data, uint32_t *format, size_t *stride); @@ -183,14 +151,11 @@ struct wlr_client_buffer { // private state struct wl_listener source_destroy; - - // If the client buffer has been created from a wl_shm buffer - uint32_t shm_source_format; }; /** - * Creates a wlr_client_buffer from a given wlr_buffer by creating a texture - * from it, and copying its wl_resource. + * Creates a struct wlr_client_buffer from a given struct wlr_buffer by creating + * a texture from it, and copying its struct wl_resource. */ struct wlr_client_buffer *wlr_client_buffer_create(struct wlr_buffer *buffer, struct wlr_renderer *renderer); diff --git a/include/wlr/types/wlr_compositor.h b/include/wlr/types/wlr_compositor.h index 071610b8f..b0d1eed6a 100644 --- a/include/wlr/types/wlr_compositor.h +++ b/include/wlr/types/wlr_compositor.h @@ -28,6 +28,7 @@ enum wlr_surface_state_field { WLR_SURFACE_STATE_SCALE = 1 << 6, WLR_SURFACE_STATE_FRAME_CALLBACK_LIST = 1 << 7, WLR_SURFACE_STATE_VIEWPORT = 1 << 8, + WLR_SURFACE_STATE_OFFSET = 1 << 9, }; struct wlr_surface_state { @@ -147,7 +148,7 @@ struct wlr_surface { struct wl_signal destroy; } events; - struct wl_list current_outputs; // wlr_surface_output::link + struct wl_list current_outputs; // wlr_surface_output.link struct wlr_addon_set addons; void *data; @@ -162,6 +163,8 @@ struct wlr_surface { int width, height; int buffer_width, buffer_height; } previous; + + bool opaque; }; struct wlr_renderer; @@ -243,9 +246,10 @@ void wlr_surface_send_frame_done(struct wlr_surface *surface, void wlr_surface_get_extends(struct wlr_surface *surface, struct wlr_box *box); /** - * Get the wlr_surface corresponding to a wl_surface resource. This asserts - * that the resource is a valid wl_surface resource created by wlroots and - * will never return NULL. + * Get the struct wlr_surface corresponding to a wl_surface resource. + * + * This asserts that the resource is a valid wl_surface resource created by + * wlroots and will never return NULL. */ struct wlr_surface *wlr_surface_from_resource(struct wl_resource *resource); @@ -281,7 +285,7 @@ void wlr_surface_get_buffer_source_box(struct wlr_surface *surface, * Acquire a lock for the pending surface state. * * The state won't be committed before the caller releases the lock. Instead, - * the state becomes cached. The caller needs to use wlr_surface_unlock_cached + * the state becomes cached. The caller needs to use wlr_surface_unlock_cached() * to release the lock. * * Returns a surface commit sequence number for the cached state. diff --git a/include/wlr/types/wlr_cursor.h b/include/wlr/types/wlr_cursor.h index 7dd73c48e..06ae2f1f0 100644 --- a/include/wlr/types/wlr_cursor.h +++ b/include/wlr/types/wlr_cursor.h @@ -10,19 +10,20 @@ #define WLR_TYPES_WLR_CURSOR_H #include -#include #include #include +struct wlr_input_device; + /** * wlr_cursor implements the behavior of the "cursor", that is, the image on the * screen typically moved about with a mouse or so. It provides tracking for - * this in global coordinates, and integrates with wlr_output, - * wlr_output_layout, and wlr_input_device. You can use it to abstract multiple - * input devices over a single cursor, constrain cursor movement to the usable - * area of a wlr_output_layout and communicate position updates to the hardware - * cursor, constrain specific input devices to specific outputs or regions of - * the screen, and so on. + * this in global coordinates, and integrates with struct wlr_output, + * struct wlr_output_layout, and struct wlr_input_device. You can use it to + * abstract multiple input devices over a single cursor, constrain cursor + * movement to the usable area of a struct wlr_output_layout and communicate + * position updates to the hardware cursor, constrain specific input devices to + * specific outputs or regions of the screen, and so on. */ struct wlr_box; @@ -36,15 +37,15 @@ struct wlr_cursor { * The interpretation of these signals is the responsibility of the * compositor, but some helpers are provided for your benefit. If you * receive a relative motion event, for example, you may want to call - * wlr_cursor_move. If you receive an absolute event, call - * wlr_cursor_warp_absolute. If you pass an input device into these + * wlr_cursor_move(). If you receive an absolute event, call + * wlr_cursor_warp_absolute(). If you pass an input device into these * functions, it will apply the region/output constraints associated with * that device to the resulting cursor motion. If an output layout is * attached, these functions will constrain the resulting cursor motion to * within the usable space of the output layout. * - * Re-broadcasting these signals to, for example, a wlr_seat, is also your - * responsibility. + * Re-broadcasting these signals to, for example, a struct wlr_seat, is also + * your responsibility. */ struct { struct wl_signal motion; @@ -190,13 +191,14 @@ void wlr_cursor_map_input_to_output(struct wlr_cursor *cur, struct wlr_input_device *dev, struct wlr_output *output); /** - * Maps this cursor to an arbitrary region on the associated wlr_output_layout. + * Maps this cursor to an arbitrary region on the associated + * struct wlr_output_layout. */ void wlr_cursor_map_to_region(struct wlr_cursor *cur, const struct wlr_box *box); /** * Maps inputs from this input device to an arbitrary region on the associated - * wlr_output_layout. + * struct wlr_output_layout. */ void wlr_cursor_map_input_to_region(struct wlr_cursor *cur, struct wlr_input_device *dev, const struct wlr_box *box); diff --git a/include/wlr/types/wlr_damage_ring.h b/include/wlr/types/wlr_damage_ring.h new file mode 100644 index 000000000..9415a5563 --- /dev/null +++ b/include/wlr/types/wlr_damage_ring.h @@ -0,0 +1,81 @@ +/* + * This an unstable interface of wlroots. No guarantees are made regarding the + * future consistency of this API. + */ +#ifndef WLR_USE_UNSTABLE +#error "Add -DWLR_USE_UNSTABLE to enable unstable wlroots features" +#endif + +#ifndef WLR_TYPES_WLR_DAMAGE_RING_H +#define WLR_TYPES_WLR_DAMAGE_RING_H + +#include + +/* For triple buffering, a history of two frames is required. */ +#define WLR_DAMAGE_RING_PREVIOUS_LEN 2 + +struct wlr_box; + +struct wlr_damage_ring { + int32_t width, height; + + // Difference between the current buffer and the previous one + pixman_region32_t current; + + // private state + + pixman_region32_t previous[WLR_DAMAGE_RING_PREVIOUS_LEN]; + size_t previous_idx; +}; + +void wlr_damage_ring_init(struct wlr_damage_ring *ring); + +void wlr_damage_ring_finish(struct wlr_damage_ring *ring); + +/** + * Set ring bounds and damage the ring fully. + * + * Next time damage will be added, it will be cropped to the ring bounds. + * If at least one of the dimensions is 0, bounds are removed. + * + * By default, a damage ring doesn't have bounds. + */ +void wlr_damage_ring_set_bounds(struct wlr_damage_ring *ring, + int32_t width, int32_t height); + +/** + * Add a region to the current damage. + * + * Returns true if the region intersects the ring bounds, false otherwise. + */ +bool wlr_damage_ring_add(struct wlr_damage_ring *ring, + pixman_region32_t *damage); + +/** + * Add a box to the current damage. + * + * Returns true if the box intersects the ring bounds, false otherwise. + */ +bool wlr_damage_ring_add_box(struct wlr_damage_ring *ring, + const struct wlr_box *box); + +/** + * Damage the ring fully. + */ +void wlr_damage_ring_add_whole(struct wlr_damage_ring *ring); + +/** + * Rotate the damage ring. This needs to be called after using the accumulated + * damage, e.g. after rendering to an output's back buffer. + */ +void wlr_damage_ring_rotate(struct wlr_damage_ring *ring); + +/** + * Get accumulated damage, which is the difference between the current buffer + * and the buffer with age of buffer_age; in context of rendering, this is + * the region that needs to be redrawn. + */ +void wlr_damage_ring_get_buffer_damage(struct wlr_damage_ring *ring, + int buffer_age, pixman_region32_t *damage); + +#endif diff --git a/include/wlr/types/wlr_data_control_v1.h b/include/wlr/types/wlr_data_control_v1.h index c7e0adf02..4435f14a2 100644 --- a/include/wlr/types/wlr_data_control_v1.h +++ b/include/wlr/types/wlr_data_control_v1.h @@ -14,7 +14,7 @@ struct wlr_data_control_manager_v1 { struct wl_global *global; - struct wl_list devices; // wlr_data_control_device_v1::link + struct wl_list devices; // wlr_data_control_device_v1.link struct { struct wl_signal destroy; @@ -27,7 +27,7 @@ struct wlr_data_control_manager_v1 { struct wlr_data_control_device_v1 { struct wl_resource *resource; struct wlr_data_control_manager_v1 *manager; - struct wl_list link; // wlr_data_control_manager_v1::devices + struct wl_list link; // wlr_data_control_manager_v1.devices struct wlr_seat *seat; struct wl_resource *selection_offer_resource; // current selection offer diff --git a/include/wlr/types/wlr_data_device.h b/include/wlr/types/wlr_data_device.h index 87c578aed..9f2481e6f 100644 --- a/include/wlr/types/wlr_data_device.h +++ b/include/wlr/types/wlr_data_device.h @@ -43,7 +43,7 @@ struct wlr_data_offer { struct wl_resource *resource; struct wlr_data_source *source; enum wlr_data_offer_type type; - struct wl_list link; // wlr_seat::{selection_offers,drag_offers} + struct wl_list link; // wlr_seat.{selection_offers,drag_offers} uint32_t actions; enum wl_data_device_manager_dnd_action preferred_action; @@ -54,7 +54,7 @@ struct wlr_data_offer { /** * A data source implementation. Only the `send` function is mandatory. Refer to - * the matching wl_data_source_* functions documentation to know what they do. + * the matching `wlr_data_source_*` functions documentation to know what they do. */ struct wlr_data_source_impl { void (*send)(struct wlr_data_source *source, const char *mime_type, @@ -131,8 +131,8 @@ struct wlr_drag { struct { struct wl_signal focus; - struct wl_signal motion; // wlr_drag_motion_event - struct wl_signal drop; // wlr_drag_drop_event + struct wl_signal motion; // struct wlr_drag_motion_event + struct wl_signal drop; // struct wlr_drag_drop_event struct wl_signal destroy; } events; @@ -155,7 +155,7 @@ struct wlr_drag_drop_event { }; /** - * Create a wl data device manager global for this display. + * Create a wl_data_device_manager global for this display. */ struct wlr_data_device_manager *wlr_data_device_manager_create( struct wl_display *display); @@ -181,7 +181,7 @@ void wlr_seat_set_selection(struct wlr_seat *seat, /** * Creates a new drag. To request to start the drag, call - * `wlr_seat_request_start_drag`. + * wlr_seat_request_start_drag(). */ struct wlr_drag *wlr_drag_create(struct wlr_seat_client *seat_client, struct wlr_data_source *source, struct wlr_surface *icon_surface); @@ -258,7 +258,7 @@ void wlr_data_source_dnd_finish(struct wlr_data_source *source); * Notifies the data source that a target accepts the drag with the specified * action. * - * This shouldn't be called after `wlr_data_source_dnd_drop` unless the + * This shouldn't be called after wlr_data_source_dnd_drop() unless the * drag-and-drop operation ended in an "ask" action. */ void wlr_data_source_dnd_action(struct wlr_data_source *source, diff --git a/include/wlr/types/wlr_drm_lease_v1.h b/include/wlr/types/wlr_drm_lease_v1.h index 5a7827ea3..314eb8cc1 100644 --- a/include/wlr/types/wlr_drm_lease_v1.h +++ b/include/wlr/types/wlr_drm_lease_v1.h @@ -15,7 +15,7 @@ struct wlr_backend; struct wlr_output; struct wlr_drm_lease_v1_manager { - struct wl_list devices; // wlr_drm_lease_device_v1::link; + struct wl_list devices; // wlr_drm_lease_device_v1.link struct wl_display *display; struct wl_listener display_destroy; @@ -23,9 +23,9 @@ struct wlr_drm_lease_v1_manager { struct { /** * Upon receiving this signal, call - * wlr_drm_lease_device_v1_grant_lease_request to grant a lease of the + * wlr_drm_lease_device_v1_grant_lease_request() to grant a lease of the * requested DRM resources, or - * wlr_drm_lease_device_v1_reject_lease_request to reject the request. + * wlr_drm_lease_device_v1_reject_lease_request() to reject the request. */ struct wl_signal request; } events; @@ -38,10 +38,10 @@ struct wlr_drm_lease_device_v1 { struct wlr_drm_lease_v1_manager *manager; struct wlr_backend *backend; - struct wl_list connectors; // wlr_drm_lease_connector_v1::link - struct wl_list leases; // wlr_drm_lease_v1::link - struct wl_list requests; // wlr_drm_lease_request_v1::link - struct wl_list link; // wlr_drm_lease_v1_manager::devices + struct wl_list connectors; // wlr_drm_lease_connector_v1.link + struct wl_list leases; // wlr_drm_lease_v1.link + struct wl_list requests; // wlr_drm_lease_request_v1.link + struct wl_list link; // wlr_drm_lease_v1_manager.devices struct wl_listener backend_destroy; @@ -51,7 +51,7 @@ struct wlr_drm_lease_device_v1 { struct wlr_drm_lease_v1; struct wlr_drm_lease_connector_v1 { - struct wl_list resources; // wl_resource_get_link + struct wl_list resources; // wl_resource_get_link() struct wlr_output *output; struct wlr_drm_lease_device_v1 *device; @@ -60,7 +60,7 @@ struct wlr_drm_lease_connector_v1 { struct wl_listener destroy; - struct wl_list link; // wlr_drm_lease_device_v1::connectors + struct wl_list link; // wlr_drm_lease_device_v1.connectors }; struct wlr_drm_lease_request_v1 { @@ -76,7 +76,7 @@ struct wlr_drm_lease_request_v1 { bool invalid; - struct wl_list link; // wlr_drm_lease_device_v1::requests + struct wl_list link; // wlr_drm_lease_device_v1.requests }; struct wlr_drm_lease_v1 { @@ -97,7 +97,8 @@ struct wlr_drm_lease_v1 { /** * Creates a DRM lease manager. A DRM lease device will be created for each - * DRM backend supplied in case of a wlr_multi_backend. + * DRM backend supplied in case of a struct wlr_multi_backend. + * * Returns NULL if no DRM backend is supplied. */ struct wlr_drm_lease_v1_manager *wlr_drm_lease_v1_manager_create( @@ -105,6 +106,7 @@ struct wlr_drm_lease_v1_manager *wlr_drm_lease_v1_manager_create( /** * Offers a wlr_output for lease. + * * Returns false if the output can't be offered to lease. */ bool wlr_drm_lease_v1_manager_offer_output( @@ -120,7 +122,7 @@ void wlr_drm_lease_v1_manager_withdraw_output( /** * Grants a client's lease request. The lease device will then provision the * DRM lease and transfer the file descriptor to the client. After calling this, - * each wlr_output leased is destroyed, and will be re-issued through + * each struct wlr_output leased is destroyed, and will be re-issued through * wlr_backend.events.new_outputs when the lease is revoked. * * This will return NULL without leasing any resources if the lease is invalid; diff --git a/include/wlr/types/wlr_export_dmabuf_v1.h b/include/wlr/types/wlr_export_dmabuf_v1.h index 344e6cbf9..39e83be72 100644 --- a/include/wlr/types/wlr_export_dmabuf_v1.h +++ b/include/wlr/types/wlr_export_dmabuf_v1.h @@ -15,7 +15,7 @@ struct wlr_export_dmabuf_manager_v1 { struct wl_global *global; - struct wl_list frames; // wlr_export_dmabuf_frame_v1::link + struct wl_list frames; // wlr_export_dmabuf_frame_v1.link struct wl_listener display_destroy; @@ -27,7 +27,7 @@ struct wlr_export_dmabuf_manager_v1 { struct wlr_export_dmabuf_frame_v1 { struct wl_resource *resource; struct wlr_export_dmabuf_manager_v1 *manager; - struct wl_list link; // wlr_export_dmabuf_manager_v1::frames + struct wl_list link; // wlr_export_dmabuf_manager_v1.frames struct wlr_output *output; diff --git a/include/wlr/types/wlr_foreign_toplevel_management_v1.h b/include/wlr/types/wlr_foreign_toplevel_management_v1.h index d9030b2ea..c4abcb3dd 100644 --- a/include/wlr/types/wlr_foreign_toplevel_management_v1.h +++ b/include/wlr/types/wlr_foreign_toplevel_management_v1.h @@ -15,8 +15,8 @@ struct wlr_foreign_toplevel_manager_v1 { struct wl_event_loop *event_loop; struct wl_global *global; - struct wl_list resources; // wl_resource_get_link - struct wl_list toplevels; // wlr_foreign_toplevel_handle_v1::link + struct wl_list resources; // wl_resource_get_link() + struct wl_list toplevels; // wlr_foreign_toplevel_handle_v1.link struct wl_listener display_destroy; @@ -35,7 +35,7 @@ enum wlr_foreign_toplevel_handle_v1_state { }; struct wlr_foreign_toplevel_handle_v1_output { - struct wl_list link; // wlr_foreign_toplevel_handle_v1::outputs + struct wl_list link; // wlr_foreign_toplevel_handle_v1.outputs struct wlr_output *output; struct wlr_foreign_toplevel_handle_v1 *toplevel; @@ -54,21 +54,21 @@ struct wlr_foreign_toplevel_handle_v1 { char *title; char *app_id; struct wlr_foreign_toplevel_handle_v1 *parent; - struct wl_list outputs; // wlr_foreign_toplevel_v1_output - uint32_t state; // wlr_foreign_toplevel_v1_state + struct wl_list outputs; // wlr_foreign_toplevel_v1_output.link + uint32_t state; // enum wlr_foreign_toplevel_v1_state struct { - // wlr_foreign_toplevel_handle_v1_maximized_event + // struct wlr_foreign_toplevel_handle_v1_maximized_event struct wl_signal request_maximize; - //wlr_foreign_toplevel_handle_v1_minimized_event + // struct wlr_foreign_toplevel_handle_v1_minimized_event struct wl_signal request_minimize; - //wlr_foreign_toplevel_handle_v1_activated_event + // struct wlr_foreign_toplevel_handle_v1_activated_event struct wl_signal request_activate; - //wlr_foreign_toplevel_handle_v1_fullscreen_event + // struct wlr_foreign_toplevel_handle_v1_fullscreen_event struct wl_signal request_fullscreen; struct wl_signal request_close; - //wlr_foreign_toplevel_handle_v1_set_rectangle_event + // struct wlr_foreign_toplevel_handle_v1_set_rectangle_event struct wl_signal set_rectangle; struct wl_signal destroy; } events; @@ -108,12 +108,14 @@ struct wlr_foreign_toplevel_manager_v1 *wlr_foreign_toplevel_manager_v1_create( struct wlr_foreign_toplevel_handle_v1 *wlr_foreign_toplevel_handle_v1_create( struct wlr_foreign_toplevel_manager_v1 *manager); -/* Destroy the given toplevel handle, sending the closed event to any +/** + * Destroy the given toplevel handle, sending the closed event to any * client. Also, if the destroyed toplevel is set as a parent of any * other valid toplevel, clients still holding a handle to both are * sent a parent signal with NULL parent. If this is not desired, the * caller should ensure that any child toplevels are destroyed before - * the parent. */ + * the parent. + */ void wlr_foreign_toplevel_handle_v1_destroy( struct wlr_foreign_toplevel_handle_v1 *toplevel); @@ -136,11 +138,13 @@ void wlr_foreign_toplevel_handle_v1_set_activated( void wlr_foreign_toplevel_handle_v1_set_fullscreen( struct wlr_foreign_toplevel_handle_v1* toplevel, bool fullscreen); -/* Set the parent of a toplevel. If the parent changed from its previous +/** + * Set the parent of a toplevel. If the parent changed from its previous * value, also sends a parent event to all clients that hold handles to * both toplevel and parent (no message is sent to clients that have * previously destroyed their parent handle). NULL is allowed as the - * parent, meaning no parent exists. */ + * parent, meaning no parent exists. + */ void wlr_foreign_toplevel_handle_v1_set_parent( struct wlr_foreign_toplevel_handle_v1 *toplevel, struct wlr_foreign_toplevel_handle_v1 *parent); diff --git a/include/wlr/types/wlr_fullscreen_shell_v1.h b/include/wlr/types/wlr_fullscreen_shell_v1.h index ea8057f16..4e5b2cfe6 100644 --- a/include/wlr/types/wlr_fullscreen_shell_v1.h +++ b/include/wlr/types/wlr_fullscreen_shell_v1.h @@ -17,7 +17,7 @@ struct wlr_fullscreen_shell_v1 { struct { struct wl_signal destroy; - // wlr_fullscreen_shell_v1_present_surface_event + // struct wlr_fullscreen_shell_v1_present_surface_event struct wl_signal present_surface; } events; diff --git a/include/wlr/types/wlr_gamma_control_v1.h b/include/wlr/types/wlr_gamma_control_v1.h index b247bae34..025571487 100644 --- a/include/wlr/types/wlr_gamma_control_v1.h +++ b/include/wlr/types/wlr_gamma_control_v1.h @@ -5,7 +5,7 @@ struct wlr_gamma_control_manager_v1 { struct wl_global *global; - struct wl_list controls; // wlr_gamma_control_v1::link + struct wl_list controls; // wlr_gamma_control_v1.link struct wl_listener display_destroy; diff --git a/include/wlr/types/wlr_idle.h b/include/wlr/types/wlr_idle.h index 8e89a341f..0e1101806 100644 --- a/include/wlr/types/wlr_idle.h +++ b/include/wlr/types/wlr_idle.h @@ -23,7 +23,7 @@ struct wlr_idle { struct wl_global *global; - struct wl_list idle_timers; // wlr_idle_timeout::link + struct wl_list idle_timers; // wlr_idle_timeout.link struct wl_event_loop *event_loop; bool enabled; diff --git a/include/wlr/types/wlr_idle_inhibit_v1.h b/include/wlr/types/wlr_idle_inhibit_v1.h index 59ec83ffb..3127cfdf7 100644 --- a/include/wlr/types/wlr_idle_inhibit_v1.h +++ b/include/wlr/types/wlr_idle_inhibit_v1.h @@ -24,7 +24,7 @@ */ struct wlr_idle_inhibit_manager_v1 { - struct wl_list inhibitors; // wlr_idle_inhibit_inhibitor_v1::link + struct wl_list inhibitors; // wlr_idle_inhibit_inhibitor_v1.link struct wl_global *global; struct wl_listener display_destroy; @@ -42,7 +42,7 @@ struct wlr_idle_inhibitor_v1 { struct wl_resource *resource; struct wl_listener surface_destroy; - struct wl_list link; // wlr_idle_inhibit_manager_v1::inhibitors; + struct wl_list link; // wlr_idle_inhibit_manager_v1.inhibitors struct { struct wl_signal destroy; diff --git a/include/wlr/types/wlr_input_device.h b/include/wlr/types/wlr_input_device.h index 1690a5b92..0bbf517bc 100644 --- a/include/wlr/types/wlr_input_device.h +++ b/include/wlr/types/wlr_input_device.h @@ -25,26 +25,10 @@ enum wlr_input_device_type { WLR_INPUT_DEVICE_SWITCH, }; -struct wlr_input_device_impl; - struct wlr_input_device { enum wlr_input_device_type type; unsigned int vendor, product; char *name; - // Or 0 if not applicable to this device - double width_mm, height_mm; - char *output_name; - - /* wlr_input_device.type determines which of these is valid */ - union { - void *_device; - struct wlr_keyboard *keyboard; - struct wlr_pointer *pointer; - struct wlr_switch *switch_device; - struct wlr_touch *touch; - struct wlr_tablet *tablet; - struct wlr_tablet_pad *tablet_pad; - }; struct { struct wl_signal destroy; @@ -53,19 +37,4 @@ struct wlr_input_device { void *data; }; -void wlr_input_device_init(struct wlr_input_device *wlr_device, - enum wlr_input_device_type type, const char *name); - -/** - * Clean up all of the provided wlr_input_device resources - */ -void wlr_input_device_finish(struct wlr_input_device *wlr_device); - -/** - * Calls the specialized input device destroy function. - * If the wlr_input_device is not owned by a specialized input device, the - * function will finish the wlr_input_device and free it. - */ -void wlr_input_device_destroy(struct wlr_input_device *dev); - #endif diff --git a/include/wlr/types/wlr_input_method_v2.h b/include/wlr/types/wlr_input_method_v2.h index e4401d299..8baeae57b 100644 --- a/include/wlr/types/wlr_input_method_v2.h +++ b/include/wlr/types/wlr_input_method_v2.h @@ -51,10 +51,10 @@ struct wlr_input_method_v2 { struct wl_listener seat_client_destroy; struct { - struct wl_signal commit; // (struct wlr_input_method_v2*) - struct wl_signal new_popup_surface; // (struct wlr_input_popup_surface_v2*) - struct wl_signal grab_keyboard; // (struct wlr_input_method_keyboard_grab_v2*) - struct wl_signal destroy; // (struct wlr_input_method_v2*) + struct wl_signal commit; // struct wlr_input_method_v2 * + struct wl_signal new_popup_surface; // struct wlr_input_popup_surface_v2 * + struct wl_signal grab_keyboard; // struct wlr_input_method_keyboard_grab_v2 * + struct wl_signal destroy; // struct wlr_input_method_v2 * } events; }; @@ -87,19 +87,19 @@ struct wlr_input_method_keyboard_grab_v2 { struct wl_listener keyboard_destroy; struct { - struct wl_signal destroy; // (struct wlr_input_method_keyboard_grab_v2*) + struct wl_signal destroy; // struct wlr_input_method_keyboard_grab_v2 * } events; }; struct wlr_input_method_manager_v2 { struct wl_global *global; - struct wl_list input_methods; // struct wlr_input_method_v2*::link + struct wl_list input_methods; // struct wlr_input_method_v2.link struct wl_listener display_destroy; struct { - struct wl_signal input_method; // (struct wlr_input_method_v2*) - struct wl_signal destroy; // (struct wlr_input_method_manager_v2*) + struct wl_signal input_method; // struct wlr_input_method_v2 * + struct wl_signal destroy; // struct wlr_input_method_manager_v2 * } events; }; @@ -122,9 +122,20 @@ void wlr_input_method_v2_send_done(struct wlr_input_method_v2 *input_method); void wlr_input_method_v2_send_unavailable( struct wlr_input_method_v2 *input_method); +/** + * Returns true if the surface has the input popup surface role. + */ bool wlr_surface_is_input_popup_surface_v2(struct wlr_surface *surface); + +/** + * Get a struct wlr_input_popup_surface_v2 from a struct wlr_surface. + * Asserts that the surface has the input popup surface role. + * May return NULL even if the surface has the input popup surface role if the + * corresponding input popup surface has been destroyed. + */ struct wlr_input_popup_surface_v2 *wlr_input_popup_surface_v2_from_wlr_surface( struct wlr_surface *surface); + void wlr_input_popup_surface_v2_send_text_input_rectangle( struct wlr_input_popup_surface_v2 *popup_surface, struct wlr_box *sbox); diff --git a/include/wlr/types/wlr_keyboard.h b/include/wlr/types/wlr_keyboard.h index b3be053a5..d53d3c304 100644 --- a/include/wlr/types/wlr_keyboard.h +++ b/include/wlr/types/wlr_keyboard.h @@ -73,7 +73,7 @@ struct wlr_keyboard { struct { /** - * The `key` event signals with a `wlr_event_keyboard_key` event that a + * The `key` event signals with a struct wlr_keyboard_key_event that a * key has been pressed or released on the keyboard. This event is * emitted before the xkb state of the keyboard has been updated * (including modifiers). @@ -82,26 +82,33 @@ struct wlr_keyboard { /** * The `modifiers` event signals that the modifier state of the - * `wlr_keyboard` has been updated. At this time, you can read the - * modifier state of the `wlr_keyboard` and handle the updated state by - * sending it to clients. + * struct wlr_keyboard has been updated. At this time, you can read the + * modifier state of the struct wlr_keyboard and handle the updated + * state by sending it to clients. */ struct wl_signal modifiers; struct wl_signal keymap; struct wl_signal repeat_info; - struct wl_signal destroy; } events; void *data; }; -struct wlr_event_keyboard_key { +struct wlr_keyboard_key_event { uint32_t time_msec; uint32_t keycode; bool update_state; // if backend doesn't update modifiers on its own enum wl_keyboard_key_state state; }; +/** + * Get a struct wlr_keyboard from a struct wlr_input_device. + * + * Asserts that the input device is a keyboard. + */ +struct wlr_keyboard *wlr_keyboard_from_input_device( + struct wlr_input_device *input_device); + bool wlr_keyboard_set_keymap(struct wlr_keyboard *kb, struct xkb_keymap *keymap); diff --git a/include/wlr/types/wlr_keyboard_group.h b/include/wlr/types/wlr_keyboard_group.h index 3906d9489..0d5c6a2a4 100644 --- a/include/wlr/types/wlr_keyboard_group.h +++ b/include/wlr/types/wlr_keyboard_group.h @@ -14,28 +14,28 @@ struct wlr_keyboard_group { struct wlr_keyboard keyboard; - struct wl_list devices; // keyboard_group_device::link - struct wl_list keys; // keyboard_group_key::link + struct wl_list devices; // keyboard_group_device.link + struct wl_list keys; // keyboard_group_key.link struct { - /* + /** * Sent when a keyboard has entered the group with keys currently * pressed that are not pressed by any other keyboard in the group. The - * data for this signal will be a wl_array containing the key codes. - * This should be used to update the compositor's internal state. + * data for this signal will be a struct wl_array containing the key + * codes. This should be used to update the compositor's internal state. * Bindings should not be triggered based off of these key codes and * they should also not notify any surfaces of the key press. */ struct wl_signal enter; - /* + /** * Sent when a keyboard has left the group with keys currently pressed * that are not pressed by any other keyboard in the group. The data for - * this signal will be a wl_array containing the key codes. This should - * be used to update the compositor's internal state. Bindings should - * not be triggered based off of these key codes. Additionally, surfaces - * should only be notified if they received a corresponding key press - * for the key code. + * this signal will be a struct wl_array containing the key codes. This + * should be used to update the compositor's internal state. Bindings + * should not be triggered based off of these key codes. Additionally, + * surfaces should only be notified if they received a corresponding key + * press for the key code. */ struct wl_signal leave; } events; diff --git a/include/wlr/types/wlr_keyboard_shortcuts_inhibit_v1.h b/include/wlr/types/wlr_keyboard_shortcuts_inhibit_v1.h index e212e0f4f..946e75f4e 100644 --- a/include/wlr/types/wlr_keyboard_shortcuts_inhibit_v1.h +++ b/include/wlr/types/wlr_keyboard_shortcuts_inhibit_v1.h @@ -23,14 +23,14 @@ */ struct wlr_keyboard_shortcuts_inhibit_manager_v1 { - // wlr_keyboard_shortcuts_inhibitor_v1::link + // wlr_keyboard_shortcuts_inhibitor_v1.link struct wl_list inhibitors; struct wl_global *global; struct wl_listener display_destroy; struct { - struct wl_signal new_inhibitor; // wlr_keyboard_shortcuts_inhibitor_v1 + struct wl_signal new_inhibitor; // struct wlr_keyboard_shortcuts_inhibitor_v1 struct wl_signal destroy; } events; @@ -46,7 +46,7 @@ struct wlr_keyboard_shortcuts_inhibitor_v1 { struct wl_listener surface_destroy; struct wl_listener seat_destroy; - // wlr_keyboard_shortcuts_inhibit_manager_v1::inhibitors + // wlr_keyboard_shortcuts_inhibit_manager_v1.inhibitors struct wl_list link; struct { diff --git a/include/wlr/types/wlr_layer_shell_v1.h b/include/wlr/types/wlr_layer_shell_v1.h index 370fad837..3ebdbeda6 100644 --- a/include/wlr/types/wlr_layer_shell_v1.h +++ b/include/wlr/types/wlr_layer_shell_v1.h @@ -19,11 +19,11 @@ * wlr_layer_shell_v1 allows clients to arrange themselves in "layers" on the * desktop in accordance with the wlr-layer-shell protocol. When a client is * added, the new_surface signal will be raised and passed a reference to our - * wlr_layer_surface_v1. At this time, the client will have configured the + * struct wlr_layer_surface_v1. At this time, the client will have configured the * surface as it desires, including information like desired anchors and * margins. The compositor should use this information to decide how to arrange * the layer on-screen, then determine the dimensions of the layer and call - * wlr_layer_surface_v1_configure. The client will then attach a buffer and + * wlr_layer_surface_v1_configure(). The client will then attach a buffer and * commit the surface, at which point the wlr_layer_surface_v1 map signal is * raised and the compositor should begin rendering the surface. */ @@ -69,7 +69,7 @@ struct wlr_layer_surface_v1_state { }; struct wlr_layer_surface_v1_configure { - struct wl_list link; // wlr_layer_surface_v1::configure_list + struct wl_list link; // wlr_layer_surface_v1.configure_list uint32_t serial; uint32_t width, height; @@ -80,7 +80,7 @@ struct wlr_layer_surface_v1 { struct wlr_output *output; struct wl_resource *resource; struct wlr_layer_shell_v1 *shell; - struct wl_list popups; // wlr_xdg_popup::link + struct wl_list popups; // wlr_xdg_popup.link char *namespace; @@ -93,9 +93,10 @@ struct wlr_layer_surface_v1 { struct { /** - * The destroy signal indicates that the wlr_layer_surface is about to be - * freed. It is guaranteed that the unmap signal is raised before the destroy - * signal if the layer surface is destroyed while mapped. + * The destroy signal indicates that the struct wlr_layer_surface is + * about to be freed. It is guaranteed that the unmap signal is raised + * before the destroy signal if the layer surface is destroyed while + * mapped. */ struct wl_signal destroy; /** @@ -114,7 +115,8 @@ struct wlr_layer_surface_v1 { struct wl_signal unmap; /** * The new_popup signal is raised when a new popup is created. The data - * parameter passed to the listener is a pointer to the new wlr_xdg_popup. + * parameter passed to the listener is a pointer to the new + * struct wlr_xdg_popup. */ struct wl_signal new_popup; } events; @@ -134,12 +136,21 @@ uint32_t wlr_layer_surface_v1_configure(struct wlr_layer_surface_v1 *surface, /** * Notify the client that the surface has been closed and destroy the - * wlr_layer_surface_v1, rendering the resource inert. + * struct wlr_layer_surface_v1, rendering the resource inert. */ void wlr_layer_surface_v1_destroy(struct wlr_layer_surface_v1 *surface); +/** + * Returns true if the surface has the layer surface role. + */ bool wlr_surface_is_layer_surface(struct wlr_surface *surface); +/** + * Get a struct wlr_layer_surface from a struct wlr_surface. + * Asserts that the surface has the layer surface role. + * May return NULL even if the surface has the layer surface role if the + * corresponding layer surface has been destroyed. + */ struct wlr_layer_surface_v1 *wlr_layer_surface_v1_from_wlr_surface( struct wlr_surface *surface); @@ -178,4 +189,12 @@ struct wlr_surface *wlr_layer_surface_v1_popup_surface_at( struct wlr_layer_surface_v1 *surface, double sx, double sy, double *sub_x, double *sub_y); +/** + * Get the corresponding struct wlr_layer_surface_v1 from a resource. + * + * Aborts if the resource doesn't have the correct type. + */ +struct wlr_layer_surface_v1 *wlr_layer_surface_v1_from_resource( + struct wl_resource *resource); + #endif diff --git a/include/wlr/types/wlr_linux_dmabuf_v1.h b/include/wlr/types/wlr_linux_dmabuf_v1.h index df89a1219..6b5f0d682 100644 --- a/include/wlr/types/wlr_linux_dmabuf_v1.h +++ b/include/wlr/types/wlr_linux_dmabuf_v1.h @@ -35,8 +35,8 @@ struct wlr_dmabuf_v1_buffer { bool wlr_dmabuf_v1_resource_is_buffer(struct wl_resource *buffer_resource); /** - * Returns the wlr_dmabuf_buffer if the given resource was created - * via the linux-dmabuf buffer protocol + * Returns the struct wlr_dmabuf_buffer if the given resource was created + * via the linux-dmabuf buffer protocol. */ struct wlr_dmabuf_v1_buffer *wlr_dmabuf_v1_buffer_from_buffer_resource( struct wl_resource *buffer_resource); @@ -72,7 +72,7 @@ struct wlr_linux_dmabuf_v1 { }; /** - * Create linux-dmabuf interface + * Create linux-dmabuf interface. */ struct wlr_linux_dmabuf_v1 *wlr_linux_dmabuf_v1_create(struct wl_display *display, struct wlr_renderer *renderer); diff --git a/include/wlr/types/wlr_matrix.h b/include/wlr/types/wlr_matrix.h index 1a8b5be53..043cf6d35 100644 --- a/include/wlr/types/wlr_matrix.h +++ b/include/wlr/types/wlr_matrix.h @@ -43,14 +43,6 @@ void wlr_matrix_rotate(float mat[static 9], float rad); void wlr_matrix_transform(float mat[static 9], enum wl_output_transform transform); -/** Writes a 2D orthographic projection matrix to mat of (width, height) with a - * specified wl_output_transform. - * - * Deprecated: this function is deprecated and will be removed in a future - * version of wlroots. */ -void wlr_matrix_projection(float mat[static 9], int width, int height, - enum wl_output_transform transform); - /** Shortcut for the various matrix operations involved in projecting the * specified wlr_box onto a given orthographic projection with a given * rotation. The result is written to mat, which can be applied to each diff --git a/include/wlr/types/wlr_output.h b/include/wlr/types/wlr_output.h index e8399b40d..c163cf459 100644 --- a/include/wlr/types/wlr_output.h +++ b/include/wlr/types/wlr_output.h @@ -41,10 +41,6 @@ struct wlr_output_cursor { struct wlr_surface *surface; struct wl_listener surface_commit; struct wl_listener surface_destroy; - - struct { - struct wl_signal destroy; - } events; }; struct wlr_output_tile_info { @@ -61,7 +57,6 @@ struct wlr_output_tile_info { enum wlr_output_adaptive_sync_status { WLR_OUTPUT_ADAPTIVE_SYNC_DISABLED, WLR_OUTPUT_ADAPTIVE_SYNC_ENABLED, - WLR_OUTPUT_ADAPTIVE_SYNC_UNKNOWN, // requested, but maybe disabled }; enum wlr_output_state_field { @@ -75,6 +70,7 @@ enum wlr_output_state_field { WLR_OUTPUT_STATE_GAMMA_LUT = 1 << 7, WLR_OUTPUT_STATE_RENDER_FORMAT = 1 << 8, WLR_OUTPUT_STATE_SOURCE_BOX = 1 << 9, + WLR_OUTPUT_STATE_SUBPIXEL = 1 << 9, }; enum wlr_output_state_mode_type { @@ -96,6 +92,7 @@ struct wlr_output_state { * only valid if WLR_OUTPUT_STATE_SOURCE_BOX */ struct wlr_box source_box; // source box for respective output uint32_t render_format; + enum wl_output_subpixel subpixel; // only valid if WLR_OUTPUT_STATE_BUFFER struct wlr_buffer *buffer; @@ -122,9 +119,9 @@ struct wlr_output_impl; * The `frame` event will be emitted when it is a good time for the compositor * to submit a new frame. * - * To render a new frame, compositors should call `wlr_output_attach_render`, - * render and call `wlr_output_commit`. No rendering should happen outside a - * `frame` event handler or before `wlr_output_attach_render`. + * To render a new frame, compositors should call wlr_output_attach_render(), + * render and call wlr_output_commit(). No rendering should happen outside a + * `frame` event handler or before wlr_output_attach_render(). */ struct wlr_output { const struct wlr_output_impl *impl; @@ -136,9 +133,7 @@ struct wlr_output { char *name; char *description; // may be NULL - char make[56]; - char model[16]; - char serial[16]; + char *make, *model, *serial; // may be NULL int32_t phys_width, phys_height; // mm struct wlr_output_tile_info tile_info; @@ -222,6 +217,7 @@ struct wlr_output_event_damage { struct wlr_output_event_precommit { struct wlr_output *output; struct timespec *when; + const struct wlr_output_state *state; }; struct wlr_output_event_commit { @@ -274,7 +270,7 @@ struct wlr_surface; * emit `frame` events. * * Whether an output is enabled is double-buffered state, see - * `wlr_output_commit`. + * wlr_output_commit(). */ void wlr_output_enable(struct wlr_output *output, bool enable); void wlr_output_create_global(struct wlr_output *output); @@ -283,8 +279,8 @@ void wlr_output_destroy_global(struct wlr_output *output); * Initialize the output's rendering subsystem with the provided allocator and * renderer. Can only be called once. * - * Call this function prior to any call to wlr_output_attach_render, - * wlr_output_commit or wlr_output_cursor_create. + * Call this function prior to any call to wlr_output_attach_render(), + * wlr_output_commit() or wlr_output_cursor_create(). * * The buffer capabilities of the provided must match the capabilities of the * output's backend. Returns false otherwise. @@ -299,7 +295,7 @@ struct wlr_output_mode *wlr_output_preferred_mode(struct wlr_output *output); /** * Sets the output mode. The output needs to be enabled. * - * Mode is double-buffered state, see `wlr_output_commit`. + * Mode is double-buffered state, see wlr_output_commit(). */ void wlr_output_set_mode(struct wlr_output *output, struct wlr_output_mode *mode); @@ -308,25 +304,28 @@ void wlr_output_set_mode(struct wlr_output *output, * Setting `refresh` to zero lets the backend pick a preferred value. The * output needs to be enabled. * - * Custom mode is double-buffered state, see `wlr_output_commit`. + * Custom mode is double-buffered state, see wlr_output_commit(). */ void wlr_output_set_custom_mode(struct wlr_output *output, int32_t width, int32_t height, int32_t refresh); /** * Sets a transform for the output. * - * Transform is double-buffered state, see `wlr_output_commit`. + * Transform is double-buffered state, see wlr_output_commit(). */ void wlr_output_set_transform(struct wlr_output *output, enum wl_output_transform transform); /** * Enables or disables adaptive sync (ie. variable refresh rate) on this - * output. This is just a hint, the backend is free to ignore this setting. + * output. On some backends, this is just a hint and may be ignored. + * Compositors can inspect `wlr_output.adaptive_sync_status` to query the + * effective status. Backends that don't support adaptive sync will reject + * the output commit. * * When enabled, compositors can submit frames a little bit later than the * deadline without dropping a frame. * - * Adaptive sync is double-buffered state, see `wlr_output_commit`. + * Adaptive sync is double-buffered state, see wlr_output_commit(). */ void wlr_output_enable_adaptive_sync(struct wlr_output *output, bool enabled); /** @@ -338,17 +337,17 @@ void wlr_output_enable_adaptive_sync(struct wlr_output *output, bool enabled); * hardware and software permit this. * * This only affects the format of the output buffer used when rendering, - * as with `wlr_output_attach_render`. It has no impact on the cursor buffer + * as with wlr_output_attach_render(). It has no impact on the cursor buffer * format, or on the formats supported for direct scan-out (see also - * `wlr_output_attach_buffer`). + * wlr_output_attach_buffer()). * - * This format is double-buffered state, see `wlr_output_commit`. + * This format is double-buffered state, see wlr_output_commit(). */ void wlr_output_set_render_format(struct wlr_output *output, uint32_t format); /** * Sets a scale for the output. * - * Scale is double-buffered state, see `wlr_output_commit`. + * Scale is double-buffered state, see wlr_output_commit(). */ void wlr_output_set_scale(struct wlr_output *output, float scale); void wlr_output_set_subpixel(struct wlr_output *output, @@ -385,22 +384,22 @@ void wlr_output_effective_resolution(struct wlr_output *output, /** * Attach the renderer's buffer to the output. Compositors must call this * function before rendering. After they are done rendering, they should call - * `wlr_output_commit` to submit the new frame. The output needs to be + * wlr_output_commit() to submit the new frame. The output needs to be * enabled. * * If non-NULL, `buffer_age` is set to the drawing buffer age in number of * frames or -1 if unknown. This is useful for damage tracking. * * If the compositor decides not to render after calling this function, it - * must call wlr_output_rollback. + * must call wlr_output_rollback(). */ bool wlr_output_attach_render(struct wlr_output *output, int *buffer_age); /** - * Attach a buffer to the output. Compositors should call `wlr_output_commit` + * Attach a buffer to the output. Compositors should call wlr_output_commit() * to submit the new frame. The output needs to be enabled. * * Not all backends support direct scan-out on all buffers. Compositors can - * check whether a buffer is supported by calling `wlr_output_test`. + * check whether a buffer is supported by calling wlr_output_test(). */ void wlr_output_attach_buffer(struct wlr_output *output, struct wlr_buffer *buffer); @@ -432,14 +431,14 @@ void wlr_output_set_source_box(struct wlr_output *output, struct wlr_box source_box); /** * Test whether the pending output state would be accepted by the backend. If - * this function returns true, `wlr_output_commit` can only fail due to a + * this function returns true, wlr_output_commit() can only fail due to a * runtime error. * * This function doesn't mutate the pending state. */ bool wlr_output_test(struct wlr_output *output); /** - * Commit the pending output state. If `wlr_output_attach_render` has been + * Commit the pending output state. If wlr_output_attach_render() has been * called, the pending frame will be submitted for display and a `frame` event * will be scheduled. * @@ -450,6 +449,10 @@ bool wlr_output_commit(struct wlr_output *output); * Discard the pending output state. */ void wlr_output_rollback(struct wlr_output *output); +bool wlr_output_test_state(struct wlr_output *output, + const struct wlr_output_state *state); +bool wlr_output_commit_state(struct wlr_output *output, + const struct wlr_output_state *state); /** * Manually schedules a `frame` event. If a `frame` event is already pending, * it is a no-op. @@ -462,11 +465,11 @@ size_t wlr_output_get_gamma_size(struct wlr_output *output); /** * Sets the gamma table for this output. `r`, `g` and `b` are gamma ramps for * red, green and blue. `size` is the length of the ramps and must not exceed - * the value returned by `wlr_output_get_gamma_size`. + * the value returned by wlr_output_get_gamma_size(). * * Providing zero-sized ramps resets the gamma table. * - * The gamma table is double-buffered state, see `wlr_output_commit`. + * The gamma table is double-buffered state, see wlr_output_commit(). */ void wlr_output_set_gamma(struct wlr_output *output, size_t size, const uint16_t *r, const uint16_t *g, const uint16_t *b); @@ -518,11 +521,30 @@ bool wlr_output_cursor_set_image(struct wlr_output_cursor *cursor, int32_t hotspot_x, int32_t hotspot_y); void wlr_output_cursor_set_surface(struct wlr_output_cursor *cursor, struct wlr_surface *surface, int32_t hotspot_x, int32_t hotspot_y); +bool wlr_output_cursor_set_buffer(struct wlr_output_cursor *cursor, + struct wlr_buffer *buffer, int32_t hotspot_x, int32_t hotspot_y); bool wlr_output_cursor_move(struct wlr_output_cursor *cursor, double x, double y); void wlr_output_cursor_destroy(struct wlr_output_cursor *cursor); +void wlr_output_state_set_enabled(struct wlr_output_state *state, + bool enabled); +void wlr_output_state_set_mode(struct wlr_output_state *state, + struct wlr_output_mode *mode); +void wlr_output_state_set_custom_mode(struct wlr_output_state *state, + int32_t width, int32_t height, int32_t refresh); +void wlr_output_state_set_scale(struct wlr_output_state *state, float scale); +void wlr_output_state_set_transform(struct wlr_output_state *state, + enum wl_output_transform transform); +void wlr_output_state_set_adaptive_sync_enabled(struct wlr_output_state *state, + bool enabled); +void wlr_output_state_set_render_format(struct wlr_output_state *state, + uint32_t format); +void wlr_output_state_set_subpixel(struct wlr_output_state *state, + enum wl_output_subpixel subpixel); + + /** * Returns the transform that, when composed with `tr`, gives * `WL_OUTPUT_TRANSFORM_NORMAL`. diff --git a/include/wlr/types/wlr_output_damage.h b/include/wlr/types/wlr_output_damage.h index ba5c88df1..51a5be8c9 100644 --- a/include/wlr/types/wlr_output_damage.h +++ b/include/wlr/types/wlr_output_damage.h @@ -29,9 +29,9 @@ struct wlr_box; * to submit a new frame. * * To render a new frame, compositors should call - * `wlr_output_damage_attach_render`, render and call `wlr_output_commit`. No + * wlr_output_damage_attach_render(), render and call wlr_output_commit(). No * rendering should happen outside a `frame` event handler or before - * `wlr_output_damage_attach_render`. + * wlr_output_damage_attach_render(). */ struct wlr_output_damage { struct wlr_output *output; @@ -64,7 +64,7 @@ void wlr_output_damage_destroy(struct wlr_output_damage *output_damage); /** * Attach the renderer's buffer to the output. Compositors must call this * function before rendering. After they are done rendering, they should call - * `wlr_output_set_damage` and `wlr_output_commit` to submit the new frame. + * wlr_output_set_damage() and wlr_output_commit() to submit the new frame. * * `needs_frame` will be set to true if a frame should be submitted. `damage` * will be set to the region of the output that needs to be repainted, in diff --git a/include/wlr/types/wlr_output_layout.h b/include/wlr/types/wlr_output_layout.h index 3cb6e1e2d..c61e1938b 100644 --- a/include/wlr/types/wlr_output_layout.h +++ b/include/wlr/types/wlr_output_layout.h @@ -18,10 +18,10 @@ struct wlr_box; /** * Helper to arrange outputs in a 2D coordinate space. The output effective - * resolution is used, see wlr_output_effective_resolution. + * resolution is used, see wlr_output_effective_resolution(). * * Outputs added to the output layout are automatically exposed to clients (see - * wlr_output_create_global). They are no longer exposed when removed from the + * wlr_output_create_global()). They are no longer exposed when removed from the * layout. */ struct wlr_output_layout { @@ -115,7 +115,7 @@ void wlr_output_layout_get_box(struct wlr_output_layout *layout, * sensible location in the layout. The coordinates of the output in the layout * may adjust dynamically when the layout changes. If the output is already in * the layout, it will become auto configured. If the position of the output is -* set such as with `wlr_output_layout_move()`, the output will become manually +* set such as with wlr_output_layout_move(), the output will become manually * configured. */ void wlr_output_layout_add_auto(struct wlr_output_layout *layout, diff --git a/include/wlr/types/wlr_output_management_v1.h b/include/wlr/types/wlr_output_management_v1.h index c0551ac1e..be56e8127 100644 --- a/include/wlr/types/wlr_output_management_v1.h +++ b/include/wlr/types/wlr_output_management_v1.h @@ -16,9 +16,9 @@ struct wlr_output_manager_v1 { struct wl_display *display; struct wl_global *global; - struct wl_list resources; // wl_resource_get_link + struct wl_list resources; // wl_resource_get_link() - struct wl_list heads; // wlr_output_head_v1::link + struct wl_list heads; // wlr_output_head_v1.link uint32_t serial; bool current_configuration_dirty; @@ -33,8 +33,8 @@ struct wlr_output_manager_v1 { * event data). That is, the compositor is responsible for destroying * the configuration. */ - struct wl_signal apply; // wlr_output_configuration_v1 - struct wl_signal test; // wlr_output_configuration_v1 + struct wl_signal apply; // struct wlr_output_configuration_v1 + struct wl_signal test; // struct wlr_output_configuration_v1 struct wl_signal destroy; } events; @@ -61,16 +61,16 @@ struct wlr_output_head_v1_state { struct wlr_output_head_v1 { struct wlr_output_head_v1_state state; struct wlr_output_manager_v1 *manager; - struct wl_list link; // wlr_output_manager_v1::heads + struct wl_list link; // wlr_output_manager_v1.heads - struct wl_list resources; // wl_resource_get_link - struct wl_list mode_resources; // wl_resource_get_link + struct wl_list resources; // wl_resource_get_link() + struct wl_list mode_resources; // wl_resource_get_link() struct wl_listener output_destroy; }; struct wlr_output_configuration_v1 { - struct wl_list heads; // wlr_output_configuration_head_v1::link + struct wl_list heads; // wlr_output_configuration_head_v1.link // client state struct wlr_output_manager_v1 *manager; @@ -83,7 +83,7 @@ struct wlr_output_configuration_v1 { struct wlr_output_configuration_head_v1 { struct wlr_output_head_v1_state state; struct wlr_output_configuration_v1 *config; - struct wl_list link; // wlr_output_configuration_v1::heads + struct wl_list link; // wlr_output_configuration_v1.heads // client state struct wl_resource *resource; // can be NULL if finalized or disabled @@ -93,7 +93,7 @@ struct wlr_output_configuration_head_v1 { /** * Create a new output manager. The compositor is responsible for calling - * `wlr_output_manager_v1_set_configuration` whenever the current output + * wlr_output_manager_v1_set_configuration() whenever the current output * configuration changes. */ struct wlr_output_manager_v1 *wlr_output_manager_v1_create( @@ -111,8 +111,8 @@ void wlr_output_manager_v1_set_configuration( /** * Create a new, empty output configuration. Compositors should add current head - * status with `wlr_output_configuration_head_v1_create`. They can then call - * `wlr_output_manager_v1_set_configuration`. + * status with wlr_output_configuration_head_v1_create(). They can then call + * wlr_output_manager_v1_set_configuration(). */ struct wlr_output_configuration_v1 *wlr_output_configuration_v1_create(void); void wlr_output_configuration_v1_destroy( @@ -141,4 +141,16 @@ struct wlr_output_configuration_head_v1 * wlr_output_configuration_head_v1_create( struct wlr_output_configuration_v1 *config, struct wlr_output *output); +/** + * Apply the head state on the supplied struct wlr_output_state. + * + * Compositors can then pass the resulting struct wlr_output_state to + * wlr_output_commit_state() or wlr_output_test_state(). + * + * The position needs to be applied manually by the caller. + */ +void wlr_output_head_v1_state_apply( + const struct wlr_output_head_v1_state *head_state, + struct wlr_output_state *output_state); + #endif diff --git a/include/wlr/types/wlr_output_power_management_v1.h b/include/wlr/types/wlr_output_power_management_v1.h index 23ce814a0..688e37a4f 100644 --- a/include/wlr/types/wlr_output_power_management_v1.h +++ b/include/wlr/types/wlr_output_power_management_v1.h @@ -6,12 +6,12 @@ struct wlr_output_power_manager_v1 { struct wl_global *global; - struct wl_list output_powers; // wlr_output_power_v1::link + struct wl_list output_powers; // wlr_output_power_v1.link struct wl_listener display_destroy; struct { - struct wl_signal set_mode; // wlr_output_power_v1_set_mode_event + struct wl_signal set_mode; // struct wlr_output_power_v1_set_mode_event struct wl_signal destroy; } events; @@ -22,7 +22,7 @@ struct wlr_output_power_v1 { struct wl_resource *resource; struct wlr_output *output; struct wlr_output_power_manager_v1 *manager; - struct wl_list link; + struct wl_list link; // wlr_output_power_manager_v1.output_powers struct wl_listener output_destroy_listener; struct wl_listener output_commit_listener; diff --git a/include/wlr/types/wlr_pointer.h b/include/wlr/types/wlr_pointer.h index a58507189..16aed1dc7 100644 --- a/include/wlr/types/wlr_pointer.h +++ b/include/wlr/types/wlr_pointer.h @@ -21,44 +21,46 @@ struct wlr_pointer { const struct wlr_pointer_impl *impl; + char *output_name; + struct { - struct wl_signal motion; // struct wlr_event_pointer_motion - struct wl_signal motion_absolute; // struct wlr_event_pointer_motion_absolute - struct wl_signal button; // struct wlr_event_pointer_button - struct wl_signal axis; // struct wlr_event_pointer_axis + struct wl_signal motion; // struct wlr_pointer_motion_event + struct wl_signal motion_absolute; // struct wlr_pointer_motion_absolute_event + struct wl_signal button; // struct wlr_pointer_button_event + struct wl_signal axis; // struct wlr_pointer_axis_event struct wl_signal frame; - struct wl_signal swipe_begin; // struct wlr_event_pointer_swipe_begin - struct wl_signal swipe_update; // struct wlr_event_pointer_swipe_update - struct wl_signal swipe_end; // struct wlr_event_pointer_swipe_end + struct wl_signal swipe_begin; // struct wlr_pointer_swipe_begin_event + struct wl_signal swipe_update; // struct wlr_pointer_swipe_update_event + struct wl_signal swipe_end; // struct wlr_pointer_swipe_end_event - struct wl_signal pinch_begin; // struct wlr_event_pointer_pinch_begin - struct wl_signal pinch_update; // struct wlr_event_pointer_pinch_update - struct wl_signal pinch_end; // struct wlr_event_pointer_pinch_end + struct wl_signal pinch_begin; // struct wlr_pointer_pinch_begin_event + struct wl_signal pinch_update; // struct wlr_pointer_pinch_update_event + struct wl_signal pinch_end; // struct wlr_pointer_pinch_end_event - struct wl_signal hold_begin; // struct wlr_event_pointer_hold_begin - struct wl_signal hold_end; // struct wlr_event_pointer_hold_end + struct wl_signal hold_begin; // struct wlr_pointer_hold_begin_event + struct wl_signal hold_end; // struct wlr_pointer_hold_end_event } events; void *data; }; -struct wlr_event_pointer_motion { - struct wlr_input_device *device; +struct wlr_pointer_motion_event { + struct wlr_pointer *pointer; uint32_t time_msec; double delta_x, delta_y; double unaccel_dx, unaccel_dy; }; -struct wlr_event_pointer_motion_absolute { - struct wlr_input_device *device; +struct wlr_pointer_motion_absolute_event { + struct wlr_pointer *pointer; uint32_t time_msec; // From 0..1 double x, y; }; -struct wlr_event_pointer_button { - struct wlr_input_device *device; +struct wlr_pointer_button_event { + struct wlr_pointer *pointer; uint32_t time_msec; uint32_t button; enum wlr_button_state state; @@ -76,8 +78,10 @@ enum wlr_axis_orientation { WLR_AXIS_ORIENTATION_HORIZONTAL, }; -struct wlr_event_pointer_axis { - struct wlr_input_device *device; +#define WLR_POINTER_AXIS_DISCRETE_STEP 120 + +struct wlr_pointer_axis_event { + struct wlr_pointer *pointer; uint32_t time_msec; enum wlr_axis_source source; enum wlr_axis_orientation orientation; @@ -85,14 +89,14 @@ struct wlr_event_pointer_axis { int32_t delta_discrete; }; -struct wlr_event_pointer_swipe_begin { - struct wlr_input_device *device; +struct wlr_pointer_swipe_begin_event { + struct wlr_pointer *pointer; uint32_t time_msec; uint32_t fingers; }; -struct wlr_event_pointer_swipe_update { - struct wlr_input_device *device; +struct wlr_pointer_swipe_update_event { + struct wlr_pointer *pointer; uint32_t time_msec; uint32_t fingers; // Relative coordinates of the logical center of the gesture @@ -100,20 +104,20 @@ struct wlr_event_pointer_swipe_update { double dx, dy; }; -struct wlr_event_pointer_swipe_end { - struct wlr_input_device *device; +struct wlr_pointer_swipe_end_event { + struct wlr_pointer *pointer; uint32_t time_msec; bool cancelled; }; -struct wlr_event_pointer_pinch_begin { - struct wlr_input_device *device; +struct wlr_pointer_pinch_begin_event { + struct wlr_pointer *pointer; uint32_t time_msec; uint32_t fingers; }; -struct wlr_event_pointer_pinch_update { - struct wlr_input_device *device; +struct wlr_pointer_pinch_update_event { + struct wlr_pointer *pointer; uint32_t time_msec; uint32_t fingers; // Relative coordinates of the logical center of the gesture @@ -125,22 +129,30 @@ struct wlr_event_pointer_pinch_update { double rotation; }; -struct wlr_event_pointer_pinch_end { - struct wlr_input_device *device; +struct wlr_pointer_pinch_end_event { + struct wlr_pointer *pointer; uint32_t time_msec; bool cancelled; }; -struct wlr_event_pointer_hold_begin { - struct wlr_input_device *device; +struct wlr_pointer_hold_begin_event { + struct wlr_pointer *pointer; uint32_t time_msec; uint32_t fingers; }; -struct wlr_event_pointer_hold_end { - struct wlr_input_device *device; +struct wlr_pointer_hold_end_event { + struct wlr_pointer *pointer; uint32_t time_msec; bool cancelled; }; +/** + * Get a struct wlr_pointer from a struct wlr_input_device. + * + * Asserts that the input device is a pointer. + */ +struct wlr_pointer *wlr_pointer_from_input_device( + struct wlr_input_device *input_device); + #endif diff --git a/include/wlr/types/wlr_pointer_constraints_v1.h b/include/wlr/types/wlr_pointer_constraints_v1.h index 904387298..21280ff2d 100644 --- a/include/wlr/types/wlr_pointer_constraints_v1.h +++ b/include/wlr/types/wlr_pointer_constraints_v1.h @@ -53,7 +53,7 @@ struct wlr_pointer_constraint_v1 { struct wl_listener surface_destroy; struct wl_listener seat_destroy; - struct wl_list link; // wlr_pointer_constraints_v1::constraints + struct wl_list link; // wlr_pointer_constraints_v1.constraints struct { /** @@ -69,13 +69,13 @@ struct wlr_pointer_constraint_v1 { struct wlr_pointer_constraints_v1 { struct wl_global *global; - struct wl_list constraints; // wlr_pointer_constraint_v1::link + struct wl_list constraints; // wlr_pointer_constraint_v1.link struct { /** * Called when a new pointer constraint is created. * - * data: struct wlr_pointer_constraint_v1 * + * The data pointer is a struct wlr_pointer_constraint_v1. */ struct wl_signal new_constraint; } events; diff --git a/include/wlr/types/wlr_pointer_gestures_v1.h b/include/wlr/types/wlr_pointer_gestures_v1.h index b05b1a30f..5510ce21c 100644 --- a/include/wlr/types/wlr_pointer_gestures_v1.h +++ b/include/wlr/types/wlr_pointer_gestures_v1.h @@ -16,9 +16,9 @@ struct wlr_surface; struct wlr_pointer_gestures_v1 { struct wl_global *global; - struct wl_list swipes; // wl_resource_get_link - struct wl_list pinches; // wl_resource_get_link - struct wl_list holds; // wl_resource_get_link + struct wl_list swipes; // wl_resource_get_link() + struct wl_list pinches; // wl_resource_get_link() + struct wl_list holds; // wl_resource_get_link() struct wl_listener display_destroy; diff --git a/include/wlr/types/wlr_presentation_time.h b/include/wlr/types/wlr_presentation_time.h index b1dc1868a..48bef659a 100644 --- a/include/wlr/types/wlr_presentation_time.h +++ b/include/wlr/types/wlr_presentation_time.h @@ -31,10 +31,10 @@ struct wlr_presentation { }; struct wlr_presentation_feedback { - struct wl_list resources; // wl_resource_get_link + struct wl_list resources; // wl_resource_get_link() - // Only when the wlr_presentation_surface_sampled_on_output helper has been - // called + // Only when the wlr_presentation_surface_sampled_on_output() helper has + // been called. struct wlr_output *output; bool output_committed; uint32_t output_commit_seq; @@ -50,7 +50,7 @@ struct wlr_presentation_event { uint32_t tv_nsec; uint32_t refresh; uint64_t seq; - uint32_t flags; // wp_presentation_feedback_kind + uint32_t flags; // enum wp_presentation_feedback_kind }; struct wlr_backend; @@ -64,8 +64,8 @@ struct wlr_presentation *wlr_presentation_create(struct wl_display *display, * contents (e.g. when rendering the surface's current texture, when * referencing its current buffer, or when directly scanning out its current * buffer). A wlr_presentation_feedback is returned. The compositor should call - * wlr_presentation_feedback_send_presented if this content has been displayed, - * then wlr_presentation_feedback_destroy. + * wlr_presentation_feedback_send_presented() if this content has been displayed, + * then wlr_presentation_feedback_destroy(). * * NULL is returned if the client hasn't requested presentation feedback for * this surface. @@ -79,7 +79,7 @@ void wlr_presentation_feedback_destroy( struct wlr_presentation_feedback *feedback); /** - * Fill a wlr_presentation_event from a wlr_output_event_present. + * Fill a wlr_presentation_event from a struct wlr_output_event_present. */ void wlr_presentation_event_from_output(struct wlr_presentation_event *event, const struct wlr_output_event_present *output_event); @@ -87,9 +87,9 @@ void wlr_presentation_event_from_output(struct wlr_presentation_event *event, /** * Mark the current surface's buffer as sampled on the given output. * - * Instead of calling wlr_presentation_surface_sampled and managing the - * wlr_presentation_feedback itself, the compositor can call this function - * before a wlr_output_commit call to indicate that the surface's current + * Instead of calling wlr_presentation_surface_sampled() and managing the + * struct wlr_presentation_feedback itself, the compositor can call this function + * before a wlr_output_commit() call to indicate that the surface's current * contents will be displayed on the output. */ void wlr_presentation_surface_sampled_on_output( diff --git a/include/wlr/types/wlr_primary_selection_v1.h b/include/wlr/types/wlr_primary_selection_v1.h index 7434d8317..78b542a04 100644 --- a/include/wlr/types/wlr_primary_selection_v1.h +++ b/include/wlr/types/wlr_primary_selection_v1.h @@ -14,7 +14,7 @@ struct wlr_primary_selection_v1_device_manager { struct wl_global *global; - struct wl_list devices; // wlr_primary_selection_v1_device::link + struct wl_list devices; // wlr_primary_selection_v1_device.link struct wl_listener display_destroy; @@ -31,10 +31,10 @@ struct wlr_primary_selection_v1_device_manager { struct wlr_primary_selection_v1_device { struct wlr_primary_selection_v1_device_manager *manager; struct wlr_seat *seat; - struct wl_list link; // wlr_primary_selection_v1_device_manager::devices - struct wl_list resources; // wl_resource_get_link + struct wl_list link; // wlr_primary_selection_v1_device_manager.devices + struct wl_list resources; // wl_resource_get_link() - struct wl_list offers; // wl_resource_get_link + struct wl_list offers; // wl_resource_get_link() struct wl_listener seat_destroy; struct wl_listener seat_focus_change; diff --git a/include/wlr/types/wlr_relative_pointer_v1.h b/include/wlr/types/wlr_relative_pointer_v1.h index 59dd98d62..fcd44d529 100644 --- a/include/wlr/types/wlr_relative_pointer_v1.h +++ b/include/wlr/types/wlr_relative_pointer_v1.h @@ -23,11 +23,11 @@ */ struct wlr_relative_pointer_manager_v1 { struct wl_global *global; - struct wl_list relative_pointers; // wlr_relative_pointer_v1::link + struct wl_list relative_pointers; // wlr_relative_pointer_v1.link struct { struct wl_signal destroy; - struct wl_signal new_relative_pointer; // wlr_relative_pointer_v1 + struct wl_signal new_relative_pointer; // struct wlr_relative_pointer_v1 } events; struct wl_listener display_destroy_listener; @@ -45,7 +45,7 @@ struct wlr_relative_pointer_v1 { struct wl_resource *resource; struct wl_resource *pointer_resource; struct wlr_seat *seat; - struct wl_list link; // wlr_relative_pointer_manager_v1::relative_pointers + struct wl_list link; // wlr_relative_pointer_manager_v1.relative_pointers struct { struct wl_signal destroy; diff --git a/include/wlr/types/wlr_scene.h b/include/wlr/types/wlr_scene.h index 867753996..614397f71 100644 --- a/include/wlr/types/wlr_scene.h +++ b/include/wlr/types/wlr_scene.h @@ -22,80 +22,95 @@ #include #include #include +#include struct wlr_output; struct wlr_output_layout; struct wlr_xdg_surface; struct wlr_layer_surface_v1; +struct wlr_scene_node; +struct wlr_scene_buffer; + +typedef bool (*wlr_scene_buffer_point_accepts_input_func_t)( + struct wlr_scene_buffer *buffer, int sx, int sy); + +typedef void (*wlr_scene_buffer_iterator_func_t)( + struct wlr_scene_buffer *buffer, int sx, int sy, void *user_data); + enum wlr_scene_node_type { - WLR_SCENE_NODE_ROOT, WLR_SCENE_NODE_TREE, - WLR_SCENE_NODE_SURFACE, WLR_SCENE_NODE_RECT, WLR_SCENE_NODE_BUFFER, }; -struct wlr_scene_node_state { - struct wl_list link; // wlr_scene_node_state.children - - struct wl_list children; // wlr_scene_node_state.link - - bool enabled; - int x, y; // relative to parent -}; - /** A node is an object in the scene. */ struct wlr_scene_node { enum wlr_scene_node_type type; - struct wlr_scene_node *parent; - struct wlr_scene_node_state state; + struct wlr_scene_tree *parent; + + struct wl_list link; // wlr_scene_tree.children + + bool enabled; + int x, y; // relative to parent struct { struct wl_signal destroy; } events; void *data; -}; -/** The root scene-graph node. */ -struct wlr_scene { - struct wlr_scene_node node; - - struct wl_list outputs; // wlr_scene_output.link + struct wlr_addon_set addons; // private state - // May be NULL - struct wlr_presentation *presentation; - struct wl_listener presentation_destroy; + pixman_region32_t visible; +}; - // List of buffers which need to be imported as textures - struct wl_list pending_buffers; // wlr_scene_buffer.pending_link +enum wlr_scene_debug_damage_option { + WLR_SCENE_DEBUG_DAMAGE_NONE, + WLR_SCENE_DEBUG_DAMAGE_RERENDER, + WLR_SCENE_DEBUG_DAMAGE_HIGHLIGHT }; /** A sub-tree in the scene-graph. */ struct wlr_scene_tree { struct wlr_scene_node node; + + struct wl_list children; // wlr_scene_node.link +}; + +/** The root scene-graph node. */ +struct wlr_scene { + struct wlr_scene_tree tree; + + struct wl_list outputs; // wlr_scene_output.link + + // May be NULL + struct wlr_presentation *presentation; + + // private state + + struct wl_listener presentation_destroy; + + enum wlr_scene_debug_damage_option debug_damage_option; + bool direct_scanout; + bool calculate_visibility; }; /** A scene-graph node displaying a single surface. */ struct wlr_scene_surface { - struct wlr_scene_node node; + struct wlr_scene_buffer *buffer; struct wlr_surface *surface; - /** - * The output that the largest area of this surface is displayed on. - * This may be NULL if the surface is not currently displayed on any - * outputs. This is the output that should be used for frame callbacks, - * presentation feedback, etc. - */ - struct wlr_output *primary_output; - // private state - int prev_width, prev_height; + struct wlr_addon addon; + struct wl_listener output_enter; + struct wl_listener output_leave; + struct wl_listener output_present; + struct wl_listener frame_done; struct wl_listener surface_destroy; struct wl_listener surface_commit; }; @@ -110,15 +125,36 @@ struct wlr_scene_rect { /** A scene-graph node displaying a buffer */ struct wlr_scene_buffer { struct wlr_scene_node node; + + // May be NULL struct wlr_buffer *buffer; + struct { + struct wl_signal output_enter; // struct wlr_scene_output + struct wl_signal output_leave; // struct wlr_scene_output + struct wl_signal output_present; // struct wlr_scene_output + struct wl_signal frame_done; // struct timespec + } events; + + // May be NULL + wlr_scene_buffer_point_accepts_input_func_t point_accepts_input; + + /** + * The output that the largest area of this buffer is displayed on. + * This may be NULL if the buffer is not currently displayed on any + * outputs. This is the output that should be used for frame callbacks, + * presentation feedback, etc. + */ + struct wlr_scene_output *primary_output; + // private state + uint64_t active_outputs; struct wlr_texture *texture; struct wlr_fbox src_box; int dst_width, dst_height; enum wl_output_transform transform; - struct wl_list pending_link; // wlr_scene.pending_buffers + pixman_region32_t opaque_region; }; /** A viewport for an output in the scene-graph */ @@ -128,18 +164,32 @@ struct wlr_scene_output { struct wlr_scene *scene; struct wlr_addon addon; - struct wlr_output_damage *damage; + struct wlr_damage_ring damage_ring; int x, y; + struct { + struct wl_signal destroy; + } events; + // private state + uint8_t index; bool prev_scanout; + + struct wl_listener output_commit; + struct wl_listener output_mode; + struct wl_listener output_damage; + struct wl_listener output_needs_frame; + + struct wl_list damage_highlight_regions; + + struct wl_array render_list; }; /** A layer shell scene helper */ struct wlr_scene_layer_surface_v1 { - struct wlr_scene_node *node; + struct wlr_scene_tree *tree; struct wlr_layer_surface_v1 *layer_surface; // private state @@ -150,9 +200,6 @@ struct wlr_scene_layer_surface_v1 { struct wl_listener layer_surface_unmap; }; -typedef void (*wlr_scene_node_iterator_func_t)(struct wlr_scene_node *node, - int sx, int sy, void *data); - /** * Immediately destroy the scene-graph node. */ @@ -190,7 +237,7 @@ void wlr_scene_node_lower_to_bottom(struct wlr_scene_node *node); * Move the node to another location in the tree. */ void wlr_scene_node_reparent(struct wlr_scene_node *node, - struct wlr_scene_node *new_parent); + struct wlr_scene_tree *new_parent); /** * Get the node's layout-local coordinates. * @@ -198,12 +245,12 @@ void wlr_scene_node_reparent(struct wlr_scene_node *node, */ bool wlr_scene_node_coords(struct wlr_scene_node *node, int *lx, int *ly); /** - * Call `iterator` on each surface in the scene-graph, with the surface's + * Call `iterator` on each buffer in the scene-graph, with the buffer's * position in layout coordinates. The function is called from root to leaves * (in rendering order). */ -void wlr_scene_node_for_each_surface(struct wlr_scene_node *node, - wlr_surface_iterator_func_t iterator, void *user_data); +void wlr_scene_node_for_each_buffer(struct wlr_scene_node *node, + wlr_scene_buffer_iterator_func_t iterator, void *user_data); /** * Find the topmost node in this scene-graph that contains the point at the * given layout-local coordinates. (For surface nodes, this means accepting @@ -217,19 +264,11 @@ struct wlr_scene_node *wlr_scene_node_at(struct wlr_scene_node *node, * Create a new scene-graph. */ struct wlr_scene *wlr_scene_create(void); -/** - * Manually render the scene-graph on an output. The compositor needs to call - * wlr_renderer_begin before and wlr_renderer_end after calling this function. - * Damage is given in output-buffer-local coordinates and can be set to NULL to - * disable damage tracking. - */ -void wlr_scene_render_output(struct wlr_scene *scene, struct wlr_output *output, - int lx, int ly, pixman_region32_t *damage); /** * Handle presentation feedback for all surfaces in the scene, assuming that * scene outputs and the scene rendering functions are used. * - * Asserts that a wlr_presentation hasn't already been set for the scene. + * Asserts that a struct wlr_presentation hasn't already been set for the scene. */ void wlr_scene_set_presentation(struct wlr_scene *scene, struct wlr_presentation *presentation); @@ -237,26 +276,33 @@ void wlr_scene_set_presentation(struct wlr_scene *scene, /** * Add a node displaying nothing but its children. */ -struct wlr_scene_tree *wlr_scene_tree_create(struct wlr_scene_node *parent); +struct wlr_scene_tree *wlr_scene_tree_create(struct wlr_scene_tree *parent); /** * Add a node displaying a single surface to the scene-graph. * * The child sub-surfaces are ignored. * - * wlr_surface_send_enter()/wlr_surface_send_leave() will be called + * wlr_surface_send_enter() and wlr_surface_send_leave() will be called * automatically based on the position of the surface and outputs in * the scene. */ -struct wlr_scene_surface *wlr_scene_surface_create(struct wlr_scene_node *parent, +struct wlr_scene_surface *wlr_scene_surface_create(struct wlr_scene_tree *parent, struct wlr_surface *surface); -struct wlr_scene_surface *wlr_scene_surface_from_node(struct wlr_scene_node *node); +struct wlr_scene_buffer *wlr_scene_buffer_from_node(struct wlr_scene_node *node); + +/** + * If this buffer is backed by a surface, then the struct wlr_scene_surface is + * returned. If not, NULL will be returned. + */ +struct wlr_scene_surface *wlr_scene_surface_from_buffer( + struct wlr_scene_buffer *scene_buffer); /** * Add a node displaying a solid-colored rectangle to the scene-graph. */ -struct wlr_scene_rect *wlr_scene_rect_create(struct wlr_scene_node *parent, +struct wlr_scene_rect *wlr_scene_rect_create(struct wlr_scene_tree *parent, int width, int height, const float color[static 4]); /** @@ -271,10 +317,36 @@ void wlr_scene_rect_set_color(struct wlr_scene_rect *rect, const float color[sta /** * Add a node displaying a buffer to the scene-graph. + * + * If the buffer is NULL, this node will not be displayed. */ -struct wlr_scene_buffer *wlr_scene_buffer_create(struct wlr_scene_node *parent, +struct wlr_scene_buffer *wlr_scene_buffer_create(struct wlr_scene_tree *parent, struct wlr_buffer *buffer); +/** + * Sets the buffer's backing buffer. + * + * If the buffer is NULL, the buffer node will not be displayed. + */ +void wlr_scene_buffer_set_buffer(struct wlr_scene_buffer *scene_buffer, + struct wlr_buffer *buffer); + +/** + * Sets the buffer's backing buffer with a custom damage region. + * + * The damage region is in buffer-local coordinates. If the region is NULL, + * the whole buffer node will be damaged. + */ +void wlr_scene_buffer_set_buffer_with_damage(struct wlr_scene_buffer *scene_buffer, + struct wlr_buffer *buffer, pixman_region32_t *region); + +/** + * Sets the buffer's opaque region. This is an optimization hint used to + * determine if buffers which reside under this one need to be rendered or not. + */ +void wlr_scene_buffer_set_opaque_region(struct wlr_scene_buffer *scene_buffer, + pixman_region32_t *region); + /** * Set the source rectangle describing the region of the buffer which will be * sampled to render this node. This allows cropping the buffer. @@ -300,6 +372,12 @@ void wlr_scene_buffer_set_dest_size(struct wlr_scene_buffer *scene_buffer, void wlr_scene_buffer_set_transform(struct wlr_scene_buffer *scene_buffer, enum wl_output_transform transform); +/** + * Calls the buffer's frame_done signal. + */ +void wlr_scene_buffer_send_frame_done(struct wlr_scene_buffer *scene_buffer, + struct timespec *now); + /** * Add a viewport for the specified output to the scene-graph. * @@ -322,20 +400,20 @@ void wlr_scene_output_set_position(struct wlr_scene_output *scene_output, bool wlr_scene_output_commit(struct wlr_scene_output *scene_output); /** * Call wlr_surface_send_frame_done() on all surfaces in the scene rendered by - * wlr_scene_output_commit() for which wlr_scene_surface->primary_output + * wlr_scene_output_commit() for which wlr_scene_surface.primary_output * matches the given scene_output. */ void wlr_scene_output_send_frame_done(struct wlr_scene_output *scene_output, struct timespec *now); /** - * Call `iterator` on each surface in the scene-graph visible on the output, - * with the surface's position in layout coordinates. The function is called + * Call `iterator` on each buffer in the scene-graph visible on the output, + * with the buffer's position in layout coordinates. The function is called * from root to leaves (in rendering order). */ -void wlr_scene_output_for_each_surface(struct wlr_scene_output *scene_output, - wlr_surface_iterator_func_t iterator, void *user_data); +void wlr_scene_output_for_each_buffer(struct wlr_scene_output *scene_output, + wlr_scene_buffer_iterator_func_t iterator, void *user_data); /** - * Get a scene-graph output from a wlr_output. + * Get a scene-graph output from a struct wlr_output. * * If the output hasn't been added to the scene-graph, returns NULL. */ @@ -345,8 +423,10 @@ struct wlr_scene_output *wlr_scene_get_scene_output(struct wlr_scene *scene, /** * Attach an output layout to a scene. * - * Outputs in the output layout are automatically added to the scene. Any - * change to the output layout is mirrored to the scene-graph outputs. + * Adding, removing, or repositioning an output in the output layout + * will respectively add, remove or reposition a corresponding + * scene-graph output. When the output layout is destroyed, scene-graph + * outputs which were created by this helper will be destroyed. */ bool wlr_scene_attach_output_layout(struct wlr_scene *scene, struct wlr_output_layout *output_layout); @@ -355,8 +435,8 @@ bool wlr_scene_attach_output_layout(struct wlr_scene *scene, * Add a node displaying a surface and all of its sub-surfaces to the * scene-graph. */ -struct wlr_scene_node *wlr_scene_subsurface_tree_create( - struct wlr_scene_node *parent, struct wlr_surface *surface); +struct wlr_scene_tree *wlr_scene_subsurface_tree_create( + struct wlr_scene_tree *parent, struct wlr_surface *surface); /** * Add a node displaying an xdg_surface and all of its sub-surfaces to the @@ -365,8 +445,8 @@ struct wlr_scene_node *wlr_scene_subsurface_tree_create( * The origin of the returned scene-graph node will match the top-left corner * of the xdg_surface window geometry. */ -struct wlr_scene_node *wlr_scene_xdg_surface_create( - struct wlr_scene_node *parent, struct wlr_xdg_surface *xdg_surface); +struct wlr_scene_tree *wlr_scene_xdg_surface_create( + struct wlr_scene_tree *parent, struct wlr_xdg_surface *xdg_surface); /** * Add a node displaying a layer_surface_v1 and all of its sub-surfaces to the @@ -376,7 +456,7 @@ struct wlr_scene_node *wlr_scene_xdg_surface_create( * of the layer surface. */ struct wlr_scene_layer_surface_v1 *wlr_scene_layer_surface_v1_create( - struct wlr_scene_node *parent, struct wlr_layer_surface_v1 *layer_surface); + struct wlr_scene_tree *parent, struct wlr_layer_surface_v1 *layer_surface); /** * Configure a layer_surface_v1, position its scene node in accordance to its diff --git a/include/wlr/types/wlr_screencopy_v1.h b/include/wlr/types/wlr_screencopy_v1.h index 9947b0156..50e398e7e 100644 --- a/include/wlr/types/wlr_screencopy_v1.h +++ b/include/wlr/types/wlr_screencopy_v1.h @@ -15,7 +15,7 @@ struct wlr_screencopy_manager_v1 { struct wl_global *global; - struct wl_list frames; // wlr_screencopy_frame_v1::link + struct wl_list frames; // wlr_screencopy_frame_v1.link struct wl_listener display_destroy; @@ -35,7 +35,7 @@ struct wlr_screencopy_v1_client { struct wlr_screencopy_frame_v1 { struct wl_resource *resource; struct wlr_screencopy_v1_client *client; - struct wl_list link; + struct wl_list link; // wlr_screencopy_manager_v1.frames enum wl_shm_format format; uint32_t fourcc; diff --git a/include/wlr/types/wlr_seat.h b/include/wlr/types/wlr_seat.h index 41f3918b0..d19844497 100644 --- a/include/wlr/types/wlr_seat.h +++ b/include/wlr/types/wlr_seat.h @@ -32,7 +32,7 @@ struct wlr_serial_ringset { /** * Contains state for a single client's bound wl_seat resource and can be used * to issue input events to that client. The lifetime of these objects is - * managed by wlr_seat; some may be NULL. + * managed by struct wlr_seat; some may be NULL. */ struct wlr_seat_client { struct wl_client *client; @@ -54,6 +54,19 @@ struct wlr_seat_client { // for use by wlr_seat_client_{next_serial,validate_event_serial} struct wlr_serial_ringset serials; bool needs_touch_frame; + + // When the client doesn't support high-resolution scroll, accumulate deltas + // until we can notify a discrete event. + // Some mice have a free spinning wheel, making possible to lock the wheel + // when the accumulator value is not 0. To avoid synchronization issues + // between the mouse wheel and the accumulators, store the last delta and + // when the scroll direction changes, reset the accumulator. + // Indexed by wlr_axis_orientation. + struct { + int32_t acc_discrete[2]; + int32_t last_discrete[2]; + double acc_axis[2]; + } value120; }; struct wlr_touch_point { @@ -119,13 +132,15 @@ struct wlr_touch_grab_interface { void (*enter)(struct wlr_seat_touch_grab *grab, uint32_t time_msec, struct wlr_touch_point *point); void (*frame)(struct wlr_seat_touch_grab *grab); - // XXX this will conflict with the actual touch cancel which is different so - // we need to rename this + // Cancel grab void (*cancel)(struct wlr_seat_touch_grab *grab); + // Send wl_touch::cancel + void (*wl_cancel)(struct wlr_seat_touch_grab *grab, + struct wlr_surface *surface); }; /** - * Passed to `wlr_seat_touch_start_grab()` to start a grab of the touch device. + * Passed to wlr_seat_touch_start_grab() to start a grab of the touch device. * The grabber is responsible for handling touch events for the seat. */ struct wlr_seat_touch_grab { @@ -135,7 +150,7 @@ struct wlr_seat_touch_grab { }; /** - * Passed to `wlr_seat_keyboard_start_grab()` to start a grab of the keyboard. + * Passed to wlr_seat_keyboard_start_grab() to start a grab of the keyboard. * The grabber is responsible for handling keyboard events for the seat. */ struct wlr_seat_keyboard_grab { @@ -145,7 +160,7 @@ struct wlr_seat_keyboard_grab { }; /** - * Passed to `wlr_seat_pointer_start_grab()` to start a grab of the pointer. The + * Passed to wlr_seat_pointer_start_grab() to start a grab of the pointer. The * grabber is responsible for handling pointer events for the seat. */ struct wlr_seat_pointer_grab { @@ -177,7 +192,7 @@ struct wlr_seat_pointer_state { struct wl_listener surface_destroy; struct { - struct wl_signal focus_change; // wlr_seat_pointer_focus_change_event + struct wl_signal focus_change; // struct wlr_seat_pointer_focus_change_event } events; }; @@ -199,13 +214,13 @@ struct wlr_seat_keyboard_state { struct wlr_seat_keyboard_grab *default_grab; struct { - struct wl_signal focus_change; // wlr_seat_keyboard_focus_change_event + struct wl_signal focus_change; // struct wlr_seat_keyboard_focus_change_event } events; }; struct wlr_seat_touch_state { struct wlr_seat *seat; - struct wl_list touch_points; // wlr_touch_point::link + struct wl_list touch_points; // wlr_touch_point.link uint32_t grab_serial; uint32_t grab_id; @@ -228,7 +243,7 @@ struct wlr_seat { struct wlr_data_source *selection_source; uint32_t selection_serial; - struct wl_list selection_offers; // wlr_data_offer::link + struct wl_list selection_offers; // wlr_data_offer.link struct wlr_primary_selection_source *primary_selection_source; uint32_t primary_selection_serial; @@ -237,7 +252,7 @@ struct wlr_seat { struct wlr_drag *drag; struct wlr_data_source *drag_source; uint32_t drag_serial; - struct wl_list drag_offers; // wlr_data_offer::link + struct wl_list drag_offers; // wlr_data_offer.link struct wlr_seat_pointer_state pointer_state; struct wlr_seat_keyboard_state keyboard_state; @@ -258,26 +273,26 @@ struct wlr_seat { struct wl_signal touch_grab_begin; struct wl_signal touch_grab_end; - // wlr_seat_pointer_request_set_cursor_event + // struct wlr_seat_pointer_request_set_cursor_event struct wl_signal request_set_cursor; // Called when an application _wants_ to set the selection (user copies some data). - // Compositors should listen to this event and call wlr_seat_set_selection + // Compositors should listen to this event and call wlr_seat_set_selection() // if they want to accept the client's request. - struct wl_signal request_set_selection; // wlr_seat_request_set_selection_event + struct wl_signal request_set_selection; // struct wlr_seat_request_set_selection_event // Called after the data source is set for the selection. struct wl_signal set_selection; // Called when an application _wants_ to set the primary selection (user selects some data). - // Compositors should listen to this event and call wlr_seat_set_primary_selection + // Compositors should listen to this event and call wlr_seat_set_primary_selection() // if they want to accept the client's request. - struct wl_signal request_set_primary_selection; // wlr_seat_request_set_primary_selection_event + struct wl_signal request_set_primary_selection; // struct wlr_seat_request_set_primary_selection_event // Called after the primary selection source object is set. struct wl_signal set_primary_selection; - // wlr_seat_request_start_drag_event + // struct wlr_seat_request_start_drag_event struct wl_signal request_start_drag; - struct wl_signal start_drag; // wlr_drag + struct wl_signal start_drag; // struct wlr_drag struct wl_signal destroy; } events; @@ -320,16 +335,16 @@ struct wlr_seat_keyboard_focus_change_event { }; /** - * Allocates a new wlr_seat and adds a wl_seat global to the display. + * Allocates a new struct wlr_seat and adds a wl_seat global to the display. */ struct wlr_seat *wlr_seat_create(struct wl_display *display, const char *name); /** - * Destroys a wlr_seat, removes its wl_seat global and clears focus for all + * Destroys a seat, removes its wl_seat global and clears focus for all * devices belonging to the seat. */ void wlr_seat_destroy(struct wlr_seat *wlr_seat); /** - * Gets a wlr_seat_client for the specified client, or returns NULL if no + * Gets a struct wlr_seat_client for the specified client, or returns NULL if no * client is bound for that client. */ struct wlr_seat_client *wlr_seat_client_for_wl_client(struct wlr_seat *wlr_seat, @@ -357,7 +372,7 @@ bool wlr_seat_pointer_surface_has_focus(struct wlr_seat *wlr_seat, * 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. * This function does not respect pointer grabs: you probably want - * `wlr_seat_pointer_notify_enter()` instead. + * wlr_seat_pointer_notify_enter() instead. */ void wlr_seat_pointer_enter(struct wlr_seat *wlr_seat, struct wlr_surface *surface, double sx, double sy); @@ -365,14 +380,14 @@ void wlr_seat_pointer_enter(struct wlr_seat *wlr_seat, /** * Clear the focused surface for the pointer and leave all entered surfaces. * This function does not respect pointer grabs: you probably want - * `wlr_seat_pointer_notify_clear_focus()` instead. + * wlr_seat_pointer_notify_clear_focus() instead. */ 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. This function does not respect pointer grabs: - * you probably want `wlr_seat_pointer_notify_motion()` instead. + * you probably want wlr_seat_pointer_notify_motion() instead. */ void wlr_seat_pointer_send_motion(struct wlr_seat *wlr_seat, uint32_t time_msec, double sx, double sy); @@ -380,7 +395,7 @@ void wlr_seat_pointer_send_motion(struct wlr_seat *wlr_seat, uint32_t time_msec, /** * Send a button event to the surface with pointer focus. Coordinates for the * button event are surface-local. Returns the serial. This function does not - * respect pointer grabs: you probably want `wlr_seat_pointer_notify_button()` + * respect pointer grabs: you probably want wlr_seat_pointer_notify_button() * instead. */ uint32_t wlr_seat_pointer_send_button(struct wlr_seat *wlr_seat, @@ -388,7 +403,7 @@ uint32_t wlr_seat_pointer_send_button(struct wlr_seat *wlr_seat, /** * Send an axis event to the surface with pointer focus. This function does not - * respect pointer grabs: you probably want `wlr_seat_pointer_notify_axis()` + * respect pointer grabs: you probably want wlr_seat_pointer_notify_axis() * instead. */ void wlr_seat_pointer_send_axis(struct wlr_seat *wlr_seat, uint32_t time_msec, @@ -397,7 +412,7 @@ void wlr_seat_pointer_send_axis(struct wlr_seat *wlr_seat, uint32_t time_msec, /** * Send a frame event to the surface with pointer focus. This function does not - * respect pointer grabs: you probably want `wlr_seat_pointer_notify_frame()` + * respect pointer grabs: you probably want wlr_seat_pointer_notify_frame() * instead. */ void wlr_seat_pointer_send_frame(struct wlr_seat *wlr_seat); @@ -474,7 +489,7 @@ bool wlr_seat_pointer_has_grab(struct wlr_seat *seat); /** * Set this keyboard as the active keyboard for the seat. */ -void wlr_seat_set_keyboard(struct wlr_seat *seat, struct wlr_input_device *dev); +void wlr_seat_set_keyboard(struct wlr_seat *seat, struct wlr_keyboard *keyboard); /** * Get the active keyboard for the seat. @@ -483,7 +498,7 @@ struct wlr_keyboard *wlr_seat_get_keyboard(struct wlr_seat *seat); /** * Send the keyboard key to focused keyboard resources. This function does not - * respect keyboard grabs: you probably want `wlr_seat_keyboard_notify_key()` + * respect keyboard grabs: you probably want wlr_seat_keyboard_notify_key() * instead. */ void wlr_seat_keyboard_send_key(struct wlr_seat *seat, uint32_t time_msec, @@ -492,7 +507,7 @@ void wlr_seat_keyboard_send_key(struct wlr_seat *seat, uint32_t time_msec, /** * Send the modifier state to focused keyboard resources. This function does * not respect keyboard grabs: you probably want - * `wlr_seat_keyboard_notify_modifiers()` instead. + * wlr_seat_keyboard_notify_modifiers() instead. */ void wlr_seat_keyboard_send_modifiers(struct wlr_seat *seat, struct wlr_keyboard_modifiers *modifiers); @@ -501,7 +516,7 @@ void wlr_seat_keyboard_send_modifiers(struct wlr_seat *seat, * 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. This function does not respect keyboard grabs: you - * probably want `wlr_seat_keyboard_notify_enter()` instead. + * probably want wlr_seat_keyboard_notify_enter() instead. */ void wlr_seat_keyboard_enter(struct wlr_seat *seat, struct wlr_surface *surface, uint32_t keycodes[], size_t num_keycodes, @@ -510,7 +525,7 @@ void wlr_seat_keyboard_enter(struct wlr_seat *seat, /** * Clear the focused surface for the keyboard and leave all entered surfaces. * This function does not respect keyboard grabs: you probably want - * `wlr_seat_keyboard_notify_clear_focus()` instead. + * wlr_seat_keyboard_notify_clear_focus() instead. */ void wlr_seat_keyboard_clear_focus(struct wlr_seat *wlr_seat); @@ -571,7 +586,7 @@ struct wlr_touch_point *wlr_seat_touch_get_point(struct wlr_seat *seat, /** * Notify the seat that the touch point given by `touch_id` has entered a new * surface. The surface is required. To clear focus, use - * `wlr_seat_touch_point_clear_focus()`. + * wlr_seat_touch_point_clear_focus(). */ void wlr_seat_touch_point_focus(struct wlr_seat *seat, struct wlr_surface *surface, uint32_t time_msec, @@ -589,7 +604,7 @@ void wlr_seat_touch_point_clear_focus(struct wlr_seat *seat, uint32_t time_msec, * this will add a new touch point with the given `touch_id`. The touch down may * not be valid if the surface seat client does not accept touch input. * Coordinates are surface-local. This function does not respect touch grabs: - * you probably want `wlr_seat_touch_notify_down()` instead. + * you probably want wlr_seat_touch_notify_down() instead. */ uint32_t wlr_seat_touch_send_down(struct wlr_seat *seat, struct wlr_surface *surface, uint32_t time_msec, @@ -599,7 +614,7 @@ uint32_t wlr_seat_touch_send_down(struct wlr_seat *seat, * Send a touch up event for the touch point given by the `touch_id`. The event * will go to the client for the surface given in the corresponding touch down * event. This will remove the touch point. This function does not respect touch - * grabs: you probably want `wlr_seat_touch_notify_up()` instead. + * grabs: you probably want wlr_seat_touch_notify_up() instead. */ void wlr_seat_touch_send_up(struct wlr_seat *seat, uint32_t time_msec, int32_t touch_id); @@ -608,11 +623,19 @@ void wlr_seat_touch_send_up(struct wlr_seat *seat, uint32_t time_msec, * Send a touch motion event for the touch point given by the `touch_id`. The * event will go to the client for the surface given in the corresponding touch * down event. This function does not respect touch grabs: you probably want - * `wlr_seat_touch_notify_motion()` instead. + * wlr_seat_touch_notify_motion() instead. */ void wlr_seat_touch_send_motion(struct wlr_seat *seat, uint32_t time_msec, int32_t touch_id, double sx, double sy); +/** + * Notify the seat that this is a global gesture and the client should cancel + * processing it. The event will go to the client for the surface given. + * This function does not respect touch grabs: you probably want + * wlr_seat_touch_notify_cancel() instead. + */ +void wlr_seat_touch_send_cancel(struct wlr_seat *seat, struct wlr_surface *surface); + void wlr_seat_touch_send_frame(struct wlr_seat *seat); /** @@ -639,6 +662,13 @@ void wlr_seat_touch_notify_up(struct wlr_seat *seat, uint32_t time_msec, void wlr_seat_touch_notify_motion(struct wlr_seat *seat, uint32_t time_msec, int32_t touch_id, double sx, double sy); +/** + * Notify the seat that this is a global gesture and the client should + * cancel processing it. Defers to any grab of the touch device. + */ +void wlr_seat_touch_notify_cancel(struct wlr_seat *seat, + struct wlr_surface *surface); + void wlr_seat_touch_notify_frame(struct wlr_seat *seat); /** @@ -678,7 +708,7 @@ bool wlr_seat_validate_pointer_grab_serial(struct wlr_seat *seat, /** * Check whether this serial is valid to start a touch grab action. If it's the - * case and point_ptr is non-NULL, *point_ptr is set to the touch point matching + * case and point_ptr is non-NULL, `*point_ptr` is set to the touch point matching * the serial. */ bool wlr_seat_validate_touch_grab_serial(struct wlr_seat *seat, diff --git a/include/wlr/types/wlr_server_decoration.h b/include/wlr/types/wlr_server_decoration.h index 28467a21f..7e78c5f21 100644 --- a/include/wlr/types/wlr_server_decoration.h +++ b/include/wlr/types/wlr_server_decoration.h @@ -44,8 +44,8 @@ enum wlr_server_decoration_manager_mode { */ struct wlr_server_decoration_manager { struct wl_global *global; - struct wl_list resources; // wl_resource_get_link - struct wl_list decorations; // wlr_server_decoration::link + struct wl_list resources; // wl_resource_get_link() + struct wl_list decorations; // wlr_server_decoration.link uint32_t default_mode; // enum wlr_server_decoration_manager_mode diff --git a/include/wlr/types/wlr_session_lock_v1.h b/include/wlr/types/wlr_session_lock_v1.h index b410b9e56..c09978c70 100644 --- a/include/wlr/types/wlr_session_lock_v1.h +++ b/include/wlr/types/wlr_session_lock_v1.h @@ -31,7 +31,7 @@ struct wlr_session_lock_manager_v1 { struct wlr_session_lock_v1 { struct wl_resource *resource; - struct wl_list surfaces; // struct wlr_session_lock_surface_v1::link + struct wl_list surfaces; // struct wlr_session_lock_surface_v1.link struct { struct wl_signal new_surface; // struct wlr_session_lock_surface_v1 * @@ -48,7 +48,7 @@ struct wlr_session_lock_surface_v1_state { }; struct wlr_session_lock_surface_v1_configure { - struct wl_list link; // wlr_session_lock_surface_v1::configure_list + struct wl_list link; // wlr_session_lock_surface_v1.configure_list uint32_t serial; uint32_t width, height; @@ -56,14 +56,14 @@ struct wlr_session_lock_surface_v1_configure { struct wlr_session_lock_surface_v1 { struct wl_resource *resource; - struct wl_list link; // wlr_session_lock_v1::surfaces + struct wl_list link; // wlr_session_lock_v1.surfaces struct wlr_output *output; struct wlr_surface *surface; bool configured, mapped; - struct wl_list configure_list; // wlr_session_lock_surface_v1_configure::link + struct wl_list configure_list; // wlr_session_lock_surface_v1_configure.link struct wlr_session_lock_surface_v1_state current; struct wlr_session_lock_surface_v1_state pending; @@ -91,7 +91,17 @@ uint32_t wlr_session_lock_surface_v1_configure( struct wlr_session_lock_surface_v1 *lock_surface, uint32_t width, uint32_t height); +/** + * Returns true if the surface has the session lock surface role. + */ bool wlr_surface_is_session_lock_surface_v1(struct wlr_surface *surface); + +/** + * Get a struct wlr_session_lock_surface_v1 from a struct wlr_surface. + * Asserts that the surface has the session lock surface role. + * May return NULL even if the surface has the session lock surface role if the + * corresponding session lock surface has been destroyed. + */ struct wlr_session_lock_surface_v1 *wlr_session_lock_surface_v1_from_wlr_surface( struct wlr_surface *surface); diff --git a/include/wlr/types/wlr_single_pixel_buffer_v1.h b/include/wlr/types/wlr_single_pixel_buffer_v1.h new file mode 100644 index 000000000..3eba546a5 --- /dev/null +++ b/include/wlr/types/wlr_single_pixel_buffer_v1.h @@ -0,0 +1,19 @@ +/* + * This an unstable interface of wlroots. No guarantees are made regarding the + * future consistency of this API. + */ +#ifndef WLR_USE_UNSTABLE +#error "Add -DWLR_USE_UNSTABLE to enable unstable wlroots features" +#endif + +#ifndef WLR_TYPES_WLR_SINGLE_PIXEL_BUFFER_V1 +#define WLR_TYPES_WLR_SINGLE_PIXEL_BUFFER_V1 + +#include + +struct wlr_single_pixel_buffer_manager_v1; + +struct wlr_single_pixel_buffer_manager_v1 *wlr_single_pixel_buffer_manager_v1_create( + struct wl_display *display); + +#endif diff --git a/include/wlr/types/wlr_subcompositor.h b/include/wlr/types/wlr_subcompositor.h index d8e57ed83..e7f6ab2f5 100644 --- a/include/wlr/types/wlr_subcompositor.h +++ b/include/wlr/types/wlr_subcompositor.h @@ -63,11 +63,16 @@ struct wlr_subcompositor { } events; }; +/** + * Returns true if the surface has the subsurface role. + */ bool wlr_surface_is_subsurface(struct wlr_surface *surface); /** - * Get a subsurface from a surface. Can return NULL if the subsurface has been - * destroyed. + * Get a struct wlr_subsurface from a struct wlr_surface. + * Asserts that the surface has the subsurface role. + * May return NULL even if the surface has the subsurface role if the + * corresponding subsurface has been destroyed. */ struct wlr_subsurface *wlr_subsurface_from_wlr_surface( struct wlr_surface *surface); diff --git a/include/wlr/types/wlr_switch.h b/include/wlr/types/wlr_switch.h index 31811ec33..b560f0baa 100644 --- a/include/wlr/types/wlr_switch.h +++ b/include/wlr/types/wlr_switch.h @@ -28,21 +28,27 @@ struct wlr_switch { }; enum wlr_switch_type { - WLR_SWITCH_TYPE_LID = 1, + WLR_SWITCH_TYPE_LID, WLR_SWITCH_TYPE_TABLET_MODE, }; enum wlr_switch_state { WLR_SWITCH_STATE_OFF = 0, WLR_SWITCH_STATE_ON, - WLR_SWITCH_STATE_TOGGLE }; -struct wlr_event_switch_toggle { - struct wlr_input_device *device; +struct wlr_switch_toggle_event { uint32_t time_msec; enum wlr_switch_type switch_type; enum wlr_switch_state switch_state; }; +/** + * Get a struct wlr_switch from a struct wlr_input_device. + * + * Asserts that the input device is a switch. + */ +struct wlr_switch *wlr_switch_from_input_device( + struct wlr_input_device *input_device); + #endif diff --git a/include/wlr/types/wlr_tablet_pad.h b/include/wlr/types/wlr_tablet_pad.h index 249233537..f19505a97 100644 --- a/include/wlr/types/wlr_tablet_pad.h +++ b/include/wlr/types/wlr_tablet_pad.h @@ -30,14 +30,14 @@ struct wlr_tablet_pad { struct wl_signal button; struct wl_signal ring; struct wl_signal strip; - struct wl_signal attach_tablet; //struct wlr_tablet_tool + struct wl_signal attach_tablet; // struct wlr_tablet_tool } events; size_t button_count; size_t ring_count; size_t strip_count; - struct wl_list groups; // wlr_tablet_pad_group::link + struct wl_list groups; // wlr_tablet_pad_group.link struct wl_array paths; // char * void *data; @@ -58,7 +58,7 @@ struct wlr_tablet_pad_group { unsigned int mode_count; }; -struct wlr_event_tablet_pad_button { +struct wlr_tablet_pad_button_event { uint32_t time_msec; uint32_t button; enum wlr_button_state state; @@ -71,7 +71,7 @@ enum wlr_tablet_pad_ring_source { WLR_TABLET_PAD_RING_SOURCE_FINGER, }; -struct wlr_event_tablet_pad_ring { +struct wlr_tablet_pad_ring_event { uint32_t time_msec; enum wlr_tablet_pad_ring_source source; uint32_t ring; @@ -84,7 +84,7 @@ enum wlr_tablet_pad_strip_source { WLR_TABLET_PAD_STRIP_SOURCE_FINGER, }; -struct wlr_event_tablet_pad_strip { +struct wlr_tablet_pad_strip_event { uint32_t time_msec; enum wlr_tablet_pad_strip_source source; uint32_t strip; @@ -92,4 +92,12 @@ struct wlr_event_tablet_pad_strip { unsigned int mode; }; +/** + * Get a struct wlr_tablet_pad from a struct wlr_input_device. + * + * Asserts that the input device is a tablet pad. + */ +struct wlr_tablet_pad *wlr_tablet_pad_from_input_device( + struct wlr_input_device *); + #endif diff --git a/include/wlr/types/wlr_tablet_tool.h b/include/wlr/types/wlr_tablet_tool.h index b8b4000f7..495c7094a 100644 --- a/include/wlr/types/wlr_tablet_tool.h +++ b/include/wlr/types/wlr_tablet_tool.h @@ -64,6 +64,8 @@ struct wlr_tablet { const struct wlr_tablet_impl *impl; + double width_mm, height_mm; + struct { struct wl_signal axis; struct wl_signal proximity; @@ -71,7 +73,6 @@ struct wlr_tablet { struct wl_signal button; } events; - char *name; struct wl_array paths; // char * void *data; @@ -89,8 +90,8 @@ enum wlr_tablet_tool_axes { WLR_TABLET_TOOL_AXIS_WHEEL = 1 << 8, }; -struct wlr_event_tablet_tool_axis { - struct wlr_input_device *device; +struct wlr_tablet_tool_axis_event { + struct wlr_tablet *tablet; struct wlr_tablet_tool *tool; uint32_t time_msec; @@ -112,8 +113,8 @@ enum wlr_tablet_tool_proximity_state { WLR_TABLET_TOOL_PROXIMITY_IN, }; -struct wlr_event_tablet_tool_proximity { - struct wlr_input_device *device; +struct wlr_tablet_tool_proximity_event { + struct wlr_tablet *tablet; struct wlr_tablet_tool *tool; uint32_t time_msec; // From 0..1 @@ -122,12 +123,12 @@ struct wlr_event_tablet_tool_proximity { }; enum wlr_tablet_tool_tip_state { - WLR_TABLET_TOOL_TIP_UP, - WLR_TABLET_TOOL_TIP_DOWN, + WLR_TABLET_TOOL_TIP_UP = 1 << 0, + WLR_TABLET_TOOL_TIP_DOWN = 1 << 1, }; -struct wlr_event_tablet_tool_tip { - struct wlr_input_device *device; +struct wlr_tablet_tool_tip_event { + struct wlr_tablet *tablet; struct wlr_tablet_tool *tool; uint32_t time_msec; // From 0..1 @@ -135,12 +136,20 @@ struct wlr_event_tablet_tool_tip { enum wlr_tablet_tool_tip_state state; }; -struct wlr_event_tablet_tool_button { - struct wlr_input_device *device; +struct wlr_tablet_tool_button_event { + struct wlr_tablet *tablet; struct wlr_tablet_tool *tool; uint32_t time_msec; uint32_t button; enum wlr_button_state state; }; +/** + * Get a struct wlr_tablet from a struct wlr_input_device. + * + * Asserts that the input device is a tablet tool. + */ +struct wlr_tablet *wlr_tablet_from_input_device( + struct wlr_input_device *input_device); + #endif diff --git a/include/wlr/types/wlr_tablet_v2.h b/include/wlr/types/wlr_tablet_v2.h index 4483a578e..548282445 100644 --- a/include/wlr/types/wlr_tablet_v2.h +++ b/include/wlr/types/wlr_tablet_v2.h @@ -11,13 +11,14 @@ #include #include -#include #include "tablet-unstable-v2-protocol.h" /* This can probably be even lower,the tools don't have a lot of buttons */ #define WLR_TABLET_V2_TOOL_BUTTONS_CAP 16 +struct wlr_input_device; + struct wlr_tablet_pad_v2_grab_interface; struct wlr_tablet_pad_v2_grab { @@ -40,8 +41,8 @@ struct wlr_tablet_pad_client_v2; struct wlr_tablet_manager_v2 { struct wl_global *wl_global; - struct wl_list clients; // wlr_tablet_manager_client_v2::link - struct wl_list seats; // wlr_tablet_seat_v2::link + struct wl_list clients; // wlr_tablet_manager_client_v2.link + struct wl_list seats; // wlr_tablet_seat_v2.link struct wl_listener display_destroy; @@ -53,10 +54,10 @@ struct wlr_tablet_manager_v2 { }; struct wlr_tablet_v2_tablet { - struct wl_list link; // wlr_tablet_seat_v2::tablets + struct wl_list link; // wlr_tablet_seat_v2.tablets struct wlr_tablet *wlr_tablet; struct wlr_input_device *wlr_device; - struct wl_list clients; // wlr_tablet_client_v2::tablet_link + struct wl_list clients; // wlr_tablet_client_v2.tablet_link struct wl_listener tool_destroy; @@ -64,9 +65,9 @@ struct wlr_tablet_v2_tablet { }; struct wlr_tablet_v2_tablet_tool { - struct wl_list link; // wlr_tablet_seat_v2::tablets + struct wl_list link; // wlr_tablet_seat_v2.tablets struct wlr_tablet_tool *wlr_tool; - struct wl_list clients; // wlr_tablet_tool_client_v2::tool_link + struct wl_list clients; // wlr_tablet_tool_client_v2.tool_link struct wl_listener tool_destroy; @@ -90,10 +91,10 @@ struct wlr_tablet_v2_tablet_tool { }; struct wlr_tablet_v2_tablet_pad { - struct wl_list link; // wlr_tablet_seat_v2::pads + struct wl_list link; // wlr_tablet_seat_v2.pads struct wlr_tablet_pad *wlr_pad; struct wlr_input_device *wlr_device; - struct wl_list clients; // wlr_tablet_pad_client_v2::pad_link + struct wl_list clients; // wlr_tablet_pad_client_v2.pad_link size_t group_count; uint32_t *groups; diff --git a/include/wlr/types/wlr_text_input_v3.h b/include/wlr/types/wlr_text_input_v3.h index 5bac69a65..a3c6c7eba 100644 --- a/include/wlr/types/wlr_text_input_v3.h +++ b/include/wlr/types/wlr_text_input_v3.h @@ -39,7 +39,7 @@ struct wlr_text_input_v3_state { // Tracks which features were used in the current commit. // Useful in the enabling commit, where usage means support. - uint32_t features; // OR'ed wlr_text_input_v3_features + uint32_t features; // bitfield of enum wlr_text_input_v3_features }; struct wlr_text_input_v3 { @@ -52,7 +52,7 @@ struct wlr_text_input_v3 { bool pending_enabled; bool current_enabled; // supported in the current text input, more granular than surface - uint32_t active_features; // OR'ed wlr_text_input_v3_features + uint32_t active_features; // bitfield of enum wlr_text_input_v3_features struct wl_list link; @@ -60,22 +60,22 @@ struct wlr_text_input_v3 { struct wl_listener seat_destroy; struct { - struct wl_signal enable; // (struct wlr_text_input_v3*) - struct wl_signal commit; // (struct wlr_text_input_v3*) - struct wl_signal disable; // (struct wlr_text_input_v3*) - struct wl_signal destroy; // (struct wlr_text_input_v3*) + struct wl_signal enable; // struct wlr_text_input_v3 * + struct wl_signal commit; // struct wlr_text_input_v3 * + struct wl_signal disable; // struct wlr_text_input_v3 * + struct wl_signal destroy; // struct wlr_text_input_v3 * } events; }; struct wlr_text_input_manager_v3 { struct wl_global *global; - struct wl_list text_inputs; // struct wlr_text_input_v3::resource::link + struct wl_list text_inputs; // struct wlr_text_input_v3.resource.link struct wl_listener display_destroy; struct { - struct wl_signal text_input; // (struct wlr_text_input_v3*) - struct wl_signal destroy; // (struct wlr_input_method_manager_v3*) + struct wl_signal text_input; // struct wlr_text_input_v3 * + struct wl_signal destroy; // struct wlr_input_method_manager_v3 * } events; }; diff --git a/include/wlr/types/wlr_touch.h b/include/wlr/types/wlr_touch.h index b2c097e8f..82c4b8618 100644 --- a/include/wlr/types/wlr_touch.h +++ b/include/wlr/types/wlr_touch.h @@ -20,43 +20,54 @@ struct wlr_touch { const struct wlr_touch_impl *impl; + char *output_name; + double width_mm, height_mm; + struct { - struct wl_signal down; // struct wlr_event_touch_down - struct wl_signal up; // struct wlr_event_touch_up - struct wl_signal motion; // struct wlr_event_touch_motion - struct wl_signal cancel; // struct wlr_event_touch_cancel + struct wl_signal down; // struct wlr_touch_down_event + struct wl_signal up; // struct wlr_touch_up_event + struct wl_signal motion; // struct wlr_touch_motion_event + struct wl_signal cancel; // struct wlr_touch_cancel_event struct wl_signal frame; } events; void *data; }; -struct wlr_event_touch_down { - struct wlr_input_device *device; +struct wlr_touch_down_event { + struct wlr_touch *touch; uint32_t time_msec; int32_t touch_id; // From 0..1 double x, y; }; -struct wlr_event_touch_up { - struct wlr_input_device *device; +struct wlr_touch_up_event { + struct wlr_touch *touch; uint32_t time_msec; int32_t touch_id; }; -struct wlr_event_touch_motion { - struct wlr_input_device *device; +struct wlr_touch_motion_event { + struct wlr_touch *touch; uint32_t time_msec; int32_t touch_id; // From 0..1 double x, y; }; -struct wlr_event_touch_cancel { - struct wlr_input_device *device; +struct wlr_touch_cancel_event { + struct wlr_touch *touch; uint32_t time_msec; int32_t touch_id; }; +/** + * Get a struct wlr_touch from a struct wlr_input_device. + * + * Asserts that the input device is a touch device. + */ +struct wlr_touch *wlr_touch_from_input_device( + struct wlr_input_device *input_device); + #endif diff --git a/include/wlr/types/wlr_viewporter.h b/include/wlr/types/wlr_viewporter.h index f909d9cc1..8a1793675 100644 --- a/include/wlr/types/wlr_viewporter.h +++ b/include/wlr/types/wlr_viewporter.h @@ -18,9 +18,9 @@ * * - The size of the surface texture may not match the surface size anymore. * Compositors must use the surface size only. - * - Compositors must call wlr_render_subtexture_with_matrix when rendering a + * - Compositors must call wlr_render_subtexture_with_matrix() when rendering a * surface texture with the source box returned by - * wlr_surface_get_buffer_source_box. + * wlr_surface_get_buffer_source_box(). */ struct wlr_viewporter { struct wl_global *global; diff --git a/include/wlr/types/wlr_virtual_keyboard_v1.h b/include/wlr/types/wlr_virtual_keyboard_v1.h index a818f1416..00200c44f 100644 --- a/include/wlr/types/wlr_virtual_keyboard_v1.h +++ b/include/wlr/types/wlr_virtual_keyboard_v1.h @@ -14,12 +14,12 @@ struct wlr_virtual_keyboard_manager_v1 { struct wl_global *global; - struct wl_list virtual_keyboards; // struct wlr_virtual_keyboard_v1* + struct wl_list virtual_keyboards; // wlr_virtual_keyboard_v1.link struct wl_listener display_destroy; struct { - struct wl_signal new_virtual_keyboard; // struct wlr_virtual_keyboard_v1* + struct wl_signal new_virtual_keyboard; // struct wlr_virtual_keyboard_v1 * struct wl_signal destroy; } events; }; @@ -30,11 +30,7 @@ struct wlr_virtual_keyboard_v1 { struct wlr_seat *seat; bool has_keymap; - struct wl_list link; - - struct { - struct wl_signal destroy; // struct wlr_virtual_keyboard_v1* - } events; + struct wl_list link; // wlr_virtual_keyboard_manager_v1.virtual_keyboards }; struct wlr_virtual_keyboard_manager_v1* wlr_virtual_keyboard_manager_v1_create( diff --git a/include/wlr/types/wlr_virtual_pointer_v1.h b/include/wlr/types/wlr_virtual_pointer_v1.h index 307d61586..d00f2758b 100644 --- a/include/wlr/types/wlr_virtual_pointer_v1.h +++ b/include/wlr/types/wlr_virtual_pointer_v1.h @@ -16,12 +16,12 @@ struct wlr_virtual_pointer_manager_v1 { struct wl_global *global; - struct wl_list virtual_pointers; // struct wlr_virtual_pointer_v1* + struct wl_list virtual_pointers; // wlr_virtual_pointer_v1.link struct wl_listener display_destroy; struct { - struct wl_signal new_virtual_pointer; // struct wlr_virtual_pointer_v1_new_pointer_event* + struct wl_signal new_virtual_pointer; // struct wlr_virtual_pointer_v1_new_pointer_event * struct wl_signal destroy; } events; }; @@ -30,15 +30,11 @@ struct wlr_virtual_pointer_v1 { struct wlr_pointer pointer; struct wl_resource *resource; /* Vertical and horizontal */ - struct wlr_event_pointer_axis axis_event[2]; + struct wlr_pointer_axis_event axis_event[2]; enum wl_pointer_axis axis; bool axis_valid[2]; - struct wl_list link; - - struct { - struct wl_signal destroy; // struct wlr_virtual_pointer_v1* - } events; + struct wl_list link; // wlr_virtual_pointer_manager_v1.virtual_pointers }; struct wlr_virtual_pointer_v1_new_pointer_event { diff --git a/include/wlr/types/wlr_xcursor_manager.h b/include/wlr/types/wlr_xcursor_manager.h index a95302143..f7781ca6a 100644 --- a/include/wlr/types/wlr_xcursor_manager.h +++ b/include/wlr/types/wlr_xcursor_manager.h @@ -23,9 +23,9 @@ struct wlr_xcursor_manager_theme { }; /** - * wlr_xcursor_manager dynamically loads xcursor themes at sizes necessary for - * use on outputs at arbitrary scale factors. You should call - * wlr_xcursor_manager_load for each output you will show your cursor on, with + * struct wlr_xcursor_manager dynamically loads xcursor themes at sizes necessary + * for use on outputs at arbitrary scale factors. You should call + * wlr_xcursor_manager_load() for each output you will show your cursor on, with * the scale factor parameter set to that output's scale factor. */ struct wlr_xcursor_manager { @@ -51,17 +51,17 @@ bool wlr_xcursor_manager_load(struct wlr_xcursor_manager *manager, /** * Retrieves a wlr_xcursor reference for the given cursor name at the given - * scale factor, or NULL if this wlr_xcursor_manager has not loaded a cursor - * theme at the requested scale. + * scale factor, or NULL if this struct wlr_xcursor_manager has not loaded a + * cursor theme at the requested scale. */ struct wlr_xcursor *wlr_xcursor_manager_get_xcursor( struct wlr_xcursor_manager *manager, const char *name, float scale); /** - * Set a wlr_cursor's cursor image to the specified cursor name for all scale - * factors. wlr_cursor will take over from this point and ensure the correct - * cursor is used on each output, assuming a wlr_output_layout is attached to - * it. + * Set a struct wlr_cursor's cursor image to the specified cursor name for all + * scale factors. struct wlr_cursor will take over from this point and ensure + * the correct cursor is used on each output, assuming a + * struct wlr_output_layout is attached to it. */ void wlr_xcursor_manager_set_cursor_image(struct wlr_xcursor_manager *manager, const char *name, struct wlr_cursor *cursor); diff --git a/include/wlr/types/wlr_xdg_activation_v1.h b/include/wlr/types/wlr_xdg_activation_v1.h index 97801af2a..f36be4648 100644 --- a/include/wlr/types/wlr_xdg_activation_v1.h +++ b/include/wlr/types/wlr_xdg_activation_v1.h @@ -45,7 +45,7 @@ struct wlr_xdg_activation_v1 { struct { struct wl_signal destroy; - struct wl_signal request_activate; // wlr_xdg_activation_v1_request_activate_event + struct wl_signal request_activate; // struct wlr_xdg_activation_v1_request_activate_event } events; // private state diff --git a/include/wlr/types/wlr_xdg_decoration_v1.h b/include/wlr/types/wlr_xdg_decoration_v1.h index b36515595..138eb0208 100644 --- a/include/wlr/types/wlr_xdg_decoration_v1.h +++ b/include/wlr/types/wlr_xdg_decoration_v1.h @@ -12,7 +12,7 @@ enum wlr_xdg_toplevel_decoration_v1_mode { struct wlr_xdg_decoration_manager_v1 { struct wl_global *global; - struct wl_list decorations; // wlr_xdg_toplevel_decoration::link + struct wl_list decorations; // wlr_xdg_toplevel_decoration.link struct wl_listener display_destroy; @@ -25,7 +25,7 @@ struct wlr_xdg_decoration_manager_v1 { }; struct wlr_xdg_toplevel_decoration_v1_configure { - struct wl_list link; // wlr_xdg_toplevel_decoration::configure_list + struct wl_list link; // wlr_xdg_toplevel_decoration.configure_list struct wlr_xdg_surface_configure *surface_configure; enum wlr_xdg_toplevel_decoration_v1_mode mode; }; @@ -38,7 +38,7 @@ struct wlr_xdg_toplevel_decoration_v1 { struct wl_resource *resource; struct wlr_xdg_surface *surface; struct wlr_xdg_decoration_manager_v1 *manager; - struct wl_list link; // wlr_xdg_decoration_manager_v1::link + struct wl_list link; // wlr_xdg_decoration_manager_v1.link struct wlr_xdg_toplevel_decoration_v1_state current, pending; @@ -47,7 +47,7 @@ struct wlr_xdg_toplevel_decoration_v1 { bool added; - struct wl_list configure_list; // wlr_xdg_toplevel_decoration_v1_configure::link + struct wl_list configure_list; // wlr_xdg_toplevel_decoration_v1_configure.link struct { struct wl_signal destroy; diff --git a/include/wlr/types/wlr_xdg_foreign_registry.h b/include/wlr/types/wlr_xdg_foreign_registry.h index 462a9a86e..54c91e4d7 100644 --- a/include/wlr/types/wlr_xdg_foreign_registry.h +++ b/include/wlr/types/wlr_xdg_foreign_registry.h @@ -14,8 +14,8 @@ #define WLR_XDG_FOREIGN_HANDLE_SIZE 37 /** - * wlr_xdg_foreign_registry is used for storing a list of exported surfaces with - * the xdg-foreign family of protocols. + * struct wlr_xdg_foreign_registry is used for storing a list of exported + * surfaces with the xdg-foreign family of protocols. * * It can be used to allow interoperability between clients using different * versions of the protocol (if all versions use the same registry). @@ -30,7 +30,7 @@ struct wlr_xdg_foreign_registry { }; struct wlr_xdg_foreign_exported { - struct wl_list link; // wlr_xdg_foreign_registry::exported_surfaces + struct wl_list link; // wlr_xdg_foreign_registry.exported_surfaces struct wlr_xdg_foreign_registry *registry; struct wlr_surface *surface; @@ -43,7 +43,7 @@ struct wlr_xdg_foreign_exported { }; /** - * Create an empty wlr_xdg_foreign_registry. + * Create an empty struct wlr_xdg_foreign_registry. * * It will be destroyed when the associated display is destroyed. */ diff --git a/include/wlr/types/wlr_xdg_foreign_v1.h b/include/wlr/types/wlr_xdg_foreign_v1.h index d98c72312..25bc1181c 100644 --- a/include/wlr/types/wlr_xdg_foreign_v1.h +++ b/include/wlr/types/wlr_xdg_foreign_v1.h @@ -15,7 +15,7 @@ struct wlr_xdg_foreign_v1 { struct { struct wl_global *global; - struct wl_list objects; // wlr_xdg_exported_v1::link or wlr_xdg_imported_v1::link + struct wl_list objects; // wlr_xdg_exported_v1.link or wlr_xdg_imported_v1.link } exporter, importer; struct wl_listener foreign_registry_destroy; @@ -34,9 +34,9 @@ struct wlr_xdg_exported_v1 { struct wlr_xdg_foreign_exported base; struct wl_resource *resource; - struct wl_listener xdg_surface_destroy; + struct wl_listener xdg_surface_unmap; - struct wl_list link; // wlr_xdg_foreign_v1::exporter::objects + struct wl_list link; // wlr_xdg_foreign_v1.exporter.objects }; struct wlr_xdg_imported_v1 { @@ -44,7 +44,7 @@ struct wlr_xdg_imported_v1 { struct wl_listener exported_destroyed; struct wl_resource *resource; - struct wl_list link; // wlr_xdg_foreign_v1::importer::objects + struct wl_list link; // wlr_xdg_foreign_v1.importer.objects struct wl_list children; }; @@ -52,7 +52,7 @@ struct wlr_xdg_imported_child_v1 { struct wlr_xdg_imported_v1 *imported; struct wlr_surface *surface; - struct wl_list link; // wlr_xdg_imported_v1::children + struct wl_list link; // wlr_xdg_imported_v1.children struct wl_listener xdg_surface_unmap; struct wl_listener xdg_toplevel_set_parent; diff --git a/include/wlr/types/wlr_xdg_foreign_v2.h b/include/wlr/types/wlr_xdg_foreign_v2.h index d0fb506a3..78659e97a 100644 --- a/include/wlr/types/wlr_xdg_foreign_v2.h +++ b/include/wlr/types/wlr_xdg_foreign_v2.h @@ -15,7 +15,7 @@ struct wlr_xdg_foreign_v2 { struct { struct wl_global *global; - struct wl_list objects; // wlr_xdg_exported_v2::link or wlr_xdg_imported_v2::link + struct wl_list objects; // wlr_xdg_exported_v2.link or wlr_xdg_imported_v2.link } exporter, importer; struct wl_listener foreign_registry_destroy; @@ -34,9 +34,9 @@ struct wlr_xdg_exported_v2 { struct wlr_xdg_foreign_exported base; struct wl_resource *resource; - struct wl_listener xdg_surface_destroy; + struct wl_listener xdg_surface_unmap; - struct wl_list link; // wlr_xdg_foreign_v2::exporter::objects + struct wl_list link; // wlr_xdg_foreign_v2.exporter.objects }; struct wlr_xdg_imported_v2 { @@ -44,7 +44,7 @@ struct wlr_xdg_imported_v2 { struct wl_listener exported_destroyed; struct wl_resource *resource; - struct wl_list link; // wlr_xdg_foreign_v2::importer::objects + struct wl_list link; // wlr_xdg_foreign_v2.importer.objects struct wl_list children; }; @@ -52,7 +52,7 @@ struct wlr_xdg_imported_child_v2 { struct wlr_xdg_imported_v2 *imported; struct wlr_surface *surface; - struct wl_list link; // wlr_xdg_imported_v2::children + struct wl_list link; // wlr_xdg_imported_v2.children struct wl_listener xdg_surface_unmap; struct wl_listener xdg_toplevel_set_parent; diff --git a/include/wlr/types/wlr_xdg_shell.h b/include/wlr/types/wlr_xdg_shell.h index 48bfbb975..90371282e 100644 --- a/include/wlr/types/wlr_xdg_shell.h +++ b/include/wlr/types/wlr_xdg_shell.h @@ -17,6 +17,7 @@ struct wlr_xdg_shell { struct wl_global *global; + uint32_t version; struct wl_list clients; struct wl_list popup_grabs; uint32_t ping_timeout; @@ -43,7 +44,7 @@ struct wlr_xdg_client { struct wl_client *client; struct wl_list surfaces; - struct wl_list link; // wlr_xdg_shell::clients + struct wl_list link; // wlr_xdg_shell.clients uint32_t ping_serial; struct wl_event_source *ping_timer; @@ -55,9 +56,14 @@ struct wlr_xdg_positioner_rules { enum xdg_positioner_gravity gravity; enum xdg_positioner_constraint_adjustment constraint_adjustment; + bool reactive; + + bool has_parent_configure_serial; + uint32_t parent_configure_serial; + struct { int32_t width, height; - } size; + } size, parent_size; struct { int32_t x, y; @@ -69,6 +75,25 @@ struct wlr_xdg_positioner { struct wlr_xdg_positioner_rules rules; }; +struct wlr_xdg_popup_state { + // Position of the popup relative to the upper left corner of + // the window geometry of the parent surface + struct wlr_box geometry; + + bool reactive; +}; + +enum wlr_xdg_popup_configure_field { + WLR_XDG_POPUP_CONFIGURE_REPOSITION_TOKEN = 1 << 0, +}; + +struct wlr_xdg_popup_configure { + uint32_t fields; // enum wlr_xdg_popup_configure_field + struct wlr_box geometry; + struct wlr_xdg_positioner_rules rules; + uint32_t reposition_token; +}; + struct wlr_xdg_popup { struct wlr_xdg_surface *base; struct wl_list link; @@ -78,13 +103,15 @@ struct wlr_xdg_popup { struct wlr_surface *parent; struct wlr_seat *seat; - // Position of the popup relative to the upper left corner of the window - // geometry of the parent surface - struct wlr_box geometry; + struct wlr_xdg_popup_configure scheduled; - struct wlr_xdg_positioner_rules positioner_rules; + struct wlr_xdg_popup_state current, pending; - struct wl_list grab_link; // wlr_xdg_popup_grab::popups + struct { + struct wl_signal reposition; + } events; + + struct wl_list grab_link; // wlr_xdg_popup_grab.popups }; // each seat gets a popup grab @@ -95,7 +122,7 @@ struct wlr_xdg_popup_grab { struct wlr_seat_touch_grab touch_grab; struct wlr_seat *seat; struct wl_list popups; - struct wl_list link; // wlr_xdg_shell::popup_grabs + struct wl_list link; // wlr_xdg_shell.popup_grabs struct wl_listener seat_destroy; }; @@ -113,10 +140,27 @@ struct wlr_xdg_toplevel_state { uint32_t min_width, min_height; }; +enum wlr_xdg_toplevel_wm_capabilities { + WLR_XDG_TOPLEVEL_WM_CAPABILITIES_WINDOW_MENU = 1 << 0, + WLR_XDG_TOPLEVEL_WM_CAPABILITIES_MAXIMIZE = 1 << 1, + WLR_XDG_TOPLEVEL_WM_CAPABILITIES_FULLSCREEN = 1 << 2, + WLR_XDG_TOPLEVEL_WM_CAPABILITIES_MINIMIZE = 1 << 3, +}; + +enum wlr_xdg_toplevel_configure_field { + WLR_XDG_TOPLEVEL_CONFIGURE_BOUNDS = 1 << 0, + WLR_XDG_TOPLEVEL_CONFIGURE_WM_CAPABILITIES = 1 << 1, +}; + struct wlr_xdg_toplevel_configure { + uint32_t fields; // enum wlr_xdg_toplevel_configure_field bool maximized, fullscreen, resizing, activated; uint32_t tiled; // enum wlr_edges uint32_t width, height; + struct { + uint32_t width, height; + } bounds; + uint32_t wm_capabilities; // enum wlr_xdg_toplevel_wm_capabilities }; struct wlr_xdg_toplevel_requested { @@ -140,15 +184,23 @@ struct wlr_xdg_toplevel { // Properties that the client has requested. Intended to be checked // by the compositor on surface map and state change requests (such as - // xdg_toplevel::set_fullscreen) and handled accordingly. + // xdg_toplevel.set_fullscreen) and handled accordingly. struct wlr_xdg_toplevel_requested requested; char *title; char *app_id; struct { + // Note: as per xdg-shell protocol, the compositor has to + // handle state requests by sending a configure event, + // even if it didn't actually change the state. Therefore, + // every compositor implementing xdg-shell support *must* + // listen to these signals and schedule a configure event + // immediately or at some time in the future; not doing so + // is a protocol violation. struct wl_signal request_maximize; struct wl_signal request_fullscreen; + struct wl_signal request_minimize; struct wl_signal request_move; struct wl_signal request_resize; @@ -161,10 +213,13 @@ struct wlr_xdg_toplevel { struct wlr_xdg_surface_configure { struct wlr_xdg_surface *surface; - struct wl_list link; // wlr_xdg_surface::configure_list + struct wl_list link; // wlr_xdg_surface.configure_list uint32_t serial; - struct wlr_xdg_toplevel_configure *toplevel_configure; + union { + struct wlr_xdg_toplevel_configure *toplevel_configure; + struct wlr_xdg_popup_configure *popup_configure; + }; }; struct wlr_xdg_surface_state { @@ -186,7 +241,7 @@ struct wlr_xdg_surface { struct wlr_xdg_client *client; struct wl_resource *resource; struct wlr_surface *surface; - struct wl_list link; // wlr_xdg_client::surfaces + struct wl_list link; // wlr_xdg_client.surfaces enum wlr_xdg_surface_role role; union { @@ -194,7 +249,7 @@ struct wlr_xdg_surface { struct wlr_xdg_popup *popup; }; - struct wl_list popups; // wlr_xdg_popup::link + struct wl_list popups; // wlr_xdg_popup.link bool added, configured, mapped; struct wl_event_source *configure_idle; @@ -228,8 +283,8 @@ struct wlr_xdg_surface { struct wl_signal unmap; // for protocol extensions - struct wl_signal configure; // wlr_xdg_surface_configure - struct wl_signal ack_configure; // wlr_xdg_surface_configure + struct wl_signal configure; // struct wlr_xdg_surface_configure + struct wl_signal ack_configure; // struct wlr_xdg_surface_configure } events; void *data; @@ -255,9 +310,13 @@ struct wlr_xdg_toplevel_show_window_menu_event { uint32_t x, y; }; -struct wlr_xdg_shell *wlr_xdg_shell_create(struct wl_display *display); +/** + * Create the xdg_wm_base global with the specified version. + */ +struct wlr_xdg_shell *wlr_xdg_shell_create(struct wl_display *display, + uint32_t version); -/** Get the corresponding wlr_xdg_surface from a resource. +/** Get the corresponding struct wlr_xdg_surface from a resource. * * Aborts if the resource doesn't have the correct type. Returns NULL if the * resource is inert. @@ -265,7 +324,7 @@ struct wlr_xdg_shell *wlr_xdg_shell_create(struct wl_display *display); struct wlr_xdg_surface *wlr_xdg_surface_from_resource( struct wl_resource *resource); -/** Get the corresponding wlr_xdg_popup from a resource. +/** Get the corresponding struct wlr_xdg_popup from a resource. * * Aborts if the resource doesn't have the correct type. Returns NULL if the * resource is inert. @@ -273,7 +332,7 @@ struct wlr_xdg_surface *wlr_xdg_surface_from_resource( struct wlr_xdg_popup *wlr_xdg_popup_from_resource( struct wl_resource *resource); -/** Get the corresponding wlr_xdg_toplevel from a resource. +/** Get the corresponding struct wlr_xdg_toplevel from a resource. * * Aborts if the resource doesn't have the correct type. Returns NULL if the * resource is inert. @@ -281,7 +340,7 @@ struct wlr_xdg_popup *wlr_xdg_popup_from_resource( struct wlr_xdg_toplevel *wlr_xdg_toplevel_from_resource( struct wl_resource *resource); -/** Get the corresponding wlr_xdg_positioner from a resource. +/** Get the corresponding struct wlr_xdg_positioner from a resource. * * Aborts if the resource doesn't have the correct type. */ @@ -332,11 +391,26 @@ uint32_t wlr_xdg_toplevel_set_resizing(struct wlr_xdg_toplevel *toplevel, /** * Request that this toplevel consider itself in a tiled layout and some * edges are adjacent to another part of the tiling grid. `tiled_edges` is a - * bitfield of `enum wlr_edges`. Returns the associated configure serial. + * bitfield of enum wlr_edges. Returns the associated configure serial. */ uint32_t wlr_xdg_toplevel_set_tiled(struct wlr_xdg_toplevel *toplevel, uint32_t tiled_edges); +/** + * Configure the recommended bounds for the client's window geometry size. + * Returns the associated configure serial. + */ +uint32_t wlr_xdg_toplevel_set_bounds(struct wlr_xdg_toplevel *toplevel, + int32_t width, int32_t height); + +/** + * Configure the window manager capabilities for this toplevel. `caps` is a + * bitfield of `enum wlr_xdg_toplevel_wm_capabilities`. Returns the associated + * configure serial. + */ +uint32_t wlr_xdg_toplevel_set_wm_capabilities(struct wlr_xdg_toplevel *toplevel, + uint32_t caps); + /** * Request that this toplevel closes. */ @@ -405,17 +479,27 @@ struct wlr_surface *wlr_xdg_surface_popup_surface_at( struct wlr_xdg_surface *surface, double sx, double sy, double *sub_x, double *sub_y); +/** + * Returns true if the surface has the xdg surface role. + */ bool wlr_surface_is_xdg_surface(struct wlr_surface *surface); +/** + * Get a struct wlr_xdg_surface from a struct wlr_surface. + * Asserts that the surface has the xdg surface role. + * May return NULL even if the surface has the xdg surface role if the + * corresponding xdg surface has been destroyed. + */ struct wlr_xdg_surface *wlr_xdg_surface_from_wlr_surface( struct wlr_surface *surface); /** * Get the surface geometry. + * * This is either the geometry as set by the client, or defaulted to the bounds * of the surface + the subsurfaces (as specified by the protocol). * - * The x and y value can be <0 + * The x and y value can be < 0. */ void wlr_xdg_surface_get_geometry(struct wlr_xdg_surface *surface, struct wlr_box *box); diff --git a/include/wlr/util/addon.h b/include/wlr/util/addon.h index 382252ae2..c64200cf9 100644 --- a/include/wlr/util/addon.h +++ b/include/wlr/util/addon.h @@ -20,6 +20,7 @@ struct wlr_addon; struct wlr_addon_interface { const char *name; + // Has to call wlr_addon_finish() void (*destroy)(struct wlr_addon *addon); }; @@ -34,10 +35,10 @@ void wlr_addon_set_init(struct wlr_addon_set *set); void wlr_addon_set_finish(struct wlr_addon_set *set); void wlr_addon_init(struct wlr_addon *addon, struct wlr_addon_set *set, - const void *owner, const struct wlr_addon_interface *impl); + const void *owner, const struct wlr_addon_interface *impl); void wlr_addon_finish(struct wlr_addon *addon); struct wlr_addon *wlr_addon_find(struct wlr_addon_set *set, const void *owner, - const struct wlr_addon_interface *impl); + const struct wlr_addon_interface *impl); #endif diff --git a/include/wlr/util/box.h b/include/wlr/util/box.h index 66cfa21c6..84df50a6f 100644 --- a/include/wlr/util/box.h +++ b/include/wlr/util/box.h @@ -23,7 +23,7 @@ * * The x and y coordinates are inclusive, and the width and height lengths are * exclusive. In other words, the box starts from the coordinates (x, y), and - * goes up to but not including (x + width, y + height) + * goes up to but not including (x + width, y + height). */ struct wlr_box { int x, y; @@ -33,7 +33,7 @@ struct wlr_box { /** * A floating-point box representing a rectangle region in a 2D space. * - * wlr_fbox has the same semantics as wlr_box + * struct wlr_fbox has the same semantics as struct wlr_box. */ struct wlr_fbox { double x, y; @@ -41,34 +41,35 @@ struct wlr_fbox { }; /** - * Finds the closest point within the box bounds + * Finds the closest point within the box bounds. * - * Returns NAN if the box is empty + * Returns NAN if the box is empty. */ void wlr_box_closest_point(const struct wlr_box *box, double x, double y, double *dest_x, double *dest_y); /** - * Gives the intersecting box between two wlr_box. + * Gives the intersecting box between two struct wlr_box. * - * Returns an empty wlr_box if the provided wlr_box don't intersect. + * Returns an empty box if the provided boxes don't intersect. */ bool wlr_box_intersection(struct wlr_box *dest, const struct wlr_box *box_a, const struct wlr_box *box_b); /** - * Verifies if a point is contained within the bounds of a given wlr_box. + * Verifies if a point is contained within the bounds of a given struct wlr_box. * * For example: - * - A point at (100, 50) is not contained in the box (0, 0, 100, 50). - * - A point at (10, 10) is contained in the box (10, 0, 50, 50). + * + * - A point at (100, 50) is not contained in the box (0, 0, 100, 50). + * - A point at (10, 10) is contained in the box (10, 0, 50, 50). */ bool wlr_box_contains_point(const struct wlr_box *box, double x, double y); /** * Checks whether a box is empty or not. * - * A wlr_box is considered empty if its width and/or height is zero or negative. + * A box is considered empty if its width and/or height is zero or negative. */ bool wlr_box_empty(const struct wlr_box *box); @@ -81,7 +82,7 @@ void wlr_box_transform(struct wlr_box *dest, const struct wlr_box *box, /** * Checks whether a box is empty or not. * - * A wlr_box is considered empty if its width and/or height is zero or negative. + * A box is considered empty if its width and/or height is zero or negative. */ bool wlr_fbox_empty(const struct wlr_fbox *box); @@ -91,4 +92,18 @@ bool wlr_fbox_empty(const struct wlr_fbox *box); void wlr_fbox_transform(struct wlr_fbox *dest, const struct wlr_fbox *box, enum wl_output_transform transform, double width, double height); +#ifdef WLR_USE_UNSTABLE + +/** + * Returns true if the two boxes are equal, false otherwise. + */ +bool wlr_box_equal(const struct wlr_box *a, const struct wlr_box *b); + +/** + * Returns true if the two boxes are equal, false otherwise. + */ +bool wlr_fbox_equal(const struct wlr_fbox *a, const struct wlr_fbox *b); + +#endif + #endif diff --git a/include/wlr/util/log.h b/include/wlr/util/log.h index aacdea99f..5e5d8393b 100644 --- a/include/wlr/util/log.h +++ b/include/wlr/util/log.h @@ -32,13 +32,20 @@ enum wlr_log_importance { typedef void (*wlr_log_func_t)(enum wlr_log_importance importance, const char *fmt, va_list args); -// Will log all messages less than or equal to `verbosity` -// If `callback` is NULL, wlr will use its default logger. -// The function can be called multiple times to update the verbosity or -// callback function. +/** + * Set the log verbosity and callback. + * + * Only messages less than or equal to the supplied verbosity will be logged. + * If the callback is NULL, the default logger is used. + * + * This function can be called multiple times to update the verbosity or + * callback function. + */ void wlr_log_init(enum wlr_log_importance verbosity, wlr_log_func_t callback); -// Returns the log verbosity provided to wlr_log_init +/** + * Get the current log verbosity configured by wlr_log_init(). + */ enum wlr_log_importance wlr_log_get_verbosity(void); #ifdef __GNUC__ diff --git a/include/wlr/xwayland.h b/include/wlr/xwayland.h index aa9569fea..ca35da802 100644 --- a/include/wlr/xwayland.h +++ b/include/wlr/xwayland.h @@ -15,6 +15,7 @@ #include #include #include +#include struct wlr_xwm; struct wlr_xwayland_cursor; @@ -23,6 +24,8 @@ struct wlr_xwayland_server_options { bool lazy; bool enable_wm; bool no_touch_pointer_emulation; + bool force_xrandr_emulation; + int terminate_delay; // in seconds, 0 to terminate immediately }; struct wlr_xwayland_server { @@ -96,30 +99,6 @@ enum wlr_xwayland_surface_decorations { WLR_XWAYLAND_SURFACE_DECORATIONS_NO_TITLE = 2, }; -struct wlr_xwayland_surface_hints { - uint32_t flags; - uint32_t input; - int32_t initial_state; - xcb_pixmap_t icon_pixmap; - xcb_window_t icon_window; - int32_t icon_x, icon_y; - xcb_pixmap_t icon_mask; - xcb_window_t window_group; -}; - -struct wlr_xwayland_surface_size_hints { - uint32_t flags; - int32_t x, y; - int32_t width, height; - int32_t min_width, min_height; - int32_t max_width, max_height; - int32_t width_inc, height_inc; - int32_t base_width, base_height; - int32_t min_aspect_num, min_aspect_den; - int32_t max_aspect_num, max_aspect_den; - uint32_t win_gravity; -}; - /** * This represents the input focus described as follows: * @@ -176,9 +155,8 @@ struct wlr_xwayland_surface { size_t protocols_len; uint32_t decorations; - struct wlr_xwayland_surface_hints *hints; - uint32_t hints_urgency; - struct wlr_xwayland_surface_size_hints *size_hints; + xcb_icccm_wm_hints_t *hints; + xcb_size_hints_t *size_hints; bool pinging; struct wl_event_source *ping_timer; @@ -295,8 +273,17 @@ void wlr_xwayland_surface_set_fullscreen(struct wlr_xwayland_surface *surface, void wlr_xwayland_set_seat(struct wlr_xwayland *xwayland, struct wlr_seat *seat); +/** + * Returns true if the surface has the xwayland surface role. + */ bool wlr_surface_is_xwayland_surface(struct wlr_surface *surface); +/** + * Get a struct wlr_xwayland_surface from a struct wlr_surface. + * Asserts that the surface has the xwayland surface role. + * May return NULL even if the surface has the xwayland surface role if the + * corresponding xwayland surface has been destroyed. + */ struct wlr_xwayland_surface *wlr_xwayland_surface_from_wlr_surface( struct wlr_surface *surface); diff --git a/include/xwayland/meson.build b/include/xwayland/meson.build index 1dad9259b..fcc5bd3af 100644 --- a/include/xwayland/meson.build +++ b/include/xwayland/meson.build @@ -1,19 +1,29 @@ -have_listenfd = false -have_no_touch_pointer_emulation = false +xwayland_feature_names = [ + 'listenfd', + 'no_touch_pointer_emulation', + 'force_xrandr_emulation', + 'terminate_delay', +] + +xwayland_features = {} if xwayland.found() xwayland_path = xwayland.get_variable('xwayland') - have_listenfd = xwayland.get_variable('have_listenfd', - default_value: 'false') == 'true' - have_no_touch_pointer_emulation = xwayland.get_variable( - 'have_no_touch_pointer_emulation', default_value: 'false') == 'true' + foreach name : xwayland_feature_names + have = xwayland.get_variable('have_' + name, default_value: 'false') == 'true' + xwayland_features += { name: have } + endforeach else xwayland_path = xwayland_prog.full_path() + foreach name : xwayland_feature_names + xwayland_features += { name: false } + endforeach endif xwayland_config_data = configuration_data() xwayland_config_data.set_quoted('XWAYLAND_PATH', xwayland_path) -xwayland_config_data.set10('HAVE_XWAYLAND_LISTENFD', have_listenfd) -xwayland_config_data.set10('HAVE_XWAYLAND_NO_TOUCH_POINTER_EMULATION', have_no_touch_pointer_emulation) +foreach name, have : xwayland_features + xwayland_config_data.set10('HAVE_XWAYLAND_' + name.to_upper(), have) +endforeach configure_file( output: 'config.h', configuration: xwayland_config_data, diff --git a/include/xwayland/xwm.h b/include/xwayland/xwm.h index 0cdf6ea1a..41e35ef39 100644 --- a/include/xwayland/xwm.h +++ b/include/xwayland/xwm.h @@ -122,6 +122,7 @@ struct wlr_xwm { const xcb_query_extension_reply_t *xfixes; const xcb_query_extension_reply_t *xres; + uint32_t xfixes_major_version; #if HAS_XCB_ERRORS xcb_errors_context_t *errors_context; #endif diff --git a/meson.build b/meson.build index f7fb659c4..58a64a0b3 100644 --- a/meson.build +++ b/meson.build @@ -1,7 +1,7 @@ project( 'wlroots', 'c', - version: '0.16.0', + version: '0.16.0-dev', license: 'MIT', meson_version: '>=0.58.1', default_options: [ @@ -17,8 +17,8 @@ project( # between minor releases. soversion = 11 -little_endian = host_machine.endian() == 'little' -big_endian = host_machine.endian() == 'big' +little_endian = target_machine.endian() == 'little' +big_endian = target_machine.endian() == 'big' add_project_arguments([ '-DWLR_USE_UNSTABLE', @@ -92,23 +92,24 @@ features = { 'xwayland': false, 'gles2-renderer': false, 'vulkan-renderer': false, + 'gbm-allocator': false, } internal_features = { 'xcb-errors': false, + 'egl': false, } wayland_project_options = ['tests=false', 'documentation=false'] wayland_server = dependency('wayland-server', - version: '>=1.20', + version: '>=1.21', fallback: 'wayland', default_options: wayland_project_options, ) drm = dependency('libdrm', - version: '>=2.4.109', + version: '>=2.4.112', fallback: 'libdrm', default_options: [ - 'libkms=false', 'intel=false', 'radeon=false', 'amdgpu=false', @@ -123,9 +124,9 @@ drm = dependency('libdrm', 'cairo-tests=false', 'man-pages=false', 'valgrind=false', + 'tests=false', ], ) -gbm = dependency('gbm', version: '>=17.1.0') xkbcommon = dependency('xkbcommon') udev = dependency('libudev') pixman = dependency('pixman-1') @@ -136,7 +137,6 @@ wlr_files = [] wlr_deps = [ wayland_server, drm, - gbm, xkbcommon, udev, pixman, @@ -169,7 +169,7 @@ symbols_file = 'wlroots.syms' symbols_flag = '-Wl,--version-script,@0@/@1@'.format(meson.current_source_dir(), symbols_file) lib_wlr = library( meson.project_name(), wlr_files, - soversion: soversion, + soversion: soversion.to_string(), dependencies: wlr_deps, include_directories: [wlr_inc, proto_inc], install: true, diff --git a/meson_options.txt b/meson_options.txt index 550acbe6f..1a439a4d8 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -4,3 +4,5 @@ option('examples', type: 'boolean', value: true, description: 'Build example app option('icon_directory', description: 'Location used to look for cursors (default: ${datadir}/icons)', type: 'string', value: '') option('renderers', type: 'array', choices: ['auto', 'gles2', 'vulkan'], value: ['auto'], description: 'Select built-in renderers') option('backends', type: 'array', choices: ['auto', 'drm', 'libinput', 'x11'], value: ['auto'], description: 'Select built-in backends') +option('allocators', type: 'array', choices: ['auto', 'gbm'], value: ['auto'], + description: 'Select built-in allocators') diff --git a/protocol/meson.build b/protocol/meson.build index 179c731dc..920c181ca 100644 --- a/protocol/meson.build +++ b/protocol/meson.build @@ -1,5 +1,5 @@ wayland_protos = dependency('wayland-protocols', - version: '>=1.25', + version: '>=1.26', fallback: 'wayland-protocols', default_options: ['tests=false'], ) @@ -21,6 +21,7 @@ protocols = { 'xdg-activation-v1': wl_protocol_dir / 'staging/xdg-activation/xdg-activation-v1.xml', 'drm-lease-v1': wl_protocol_dir / 'staging/drm-lease/drm-lease-v1.xml', 'ext-session-lock-v1': wl_protocol_dir / 'staging/ext-session-lock/ext-session-lock-v1.xml', + 'single-pixel-buffer-v1': wl_protocol_dir / 'staging/single-pixel-buffer/single-pixel-buffer-v1.xml', # Unstable upstream protocols 'fullscreen-shell-unstable-v1': wl_protocol_dir / 'unstable/fullscreen-shell/fullscreen-shell-unstable-v1.xml', diff --git a/protocol/wlr-output-management-unstable-v1.xml b/protocol/wlr-output-management-unstable-v1.xml index cadc45fb2..3568e04ce 100644 --- a/protocol/wlr-output-management-unstable-v1.xml +++ b/protocol/wlr-output-management-unstable-v1.xml @@ -39,7 +39,7 @@ interface version number is reset. - + This interface is a manager that allows reading and writing the current output device configuration. @@ -115,7 +115,7 @@ - + This event indicates that the compositor is done sending manager events. The compositor will destroy the object immediately after sending this @@ -125,7 +125,7 @@ - + A head is an output device. The difference between a wl_output object and a head is that heads are advertised even if they are turned off. A head @@ -251,14 +251,15 @@ - - The compositor will destroy the object immediately after sending this - event, so it will become invalid and the client should release any - resources associated with it. + + This event indicates that the head is no longer available. The head + object becomes inert. Clients should send a destroy request and release + any resources associated with it. + This event describes the manufacturer of the head. @@ -328,9 +329,18 @@ + + + + + + This request indicates that the client will no longer use this head + object. + + - + This object describes an output mode. @@ -368,15 +378,24 @@ - - The compositor will destroy the object immediately after sending this - event, so it will become invalid and the client should release any - resources associated with it. + + This event indicates that the mode is no longer available. The mode + object becomes inert. Clients should send a destroy request and release + any resources associated with it. + + + + + + This request indicates that the client will no longer use this mode + object. + + - + This object is used by the client to describe a full output configuration. @@ -494,7 +513,7 @@ - + This object is used by the client to update a single head's configuration. diff --git a/render/allocator/allocator.c b/render/allocator/allocator.c index 5108ad043..b380584c7 100644 --- a/render/allocator/allocator.c +++ b/render/allocator/allocator.c @@ -3,6 +3,8 @@ #include #include #include +#include +#include #include #include #include @@ -10,13 +12,17 @@ #include "backend/backend.h" #include "render/allocator/allocator.h" #include "render/allocator/drm_dumb.h" -#include "render/allocator/gbm.h" #include "render/allocator/shm.h" #include "render/wlr_renderer.h" +#if WLR_HAS_GBM_ALLOCATOR +#include "render/allocator/gbm.h" +#endif + void wlr_allocator_init(struct wlr_allocator *alloc, const struct wlr_allocator_interface *impl, uint32_t buffer_caps) { assert(impl && impl->destroy && impl->create_buffer); + memset(alloc, 0, sizeof(*alloc)); alloc->impl = impl; alloc->buffer_caps = buffer_caps; wl_signal_init(&alloc->events.destroy); @@ -29,7 +35,7 @@ static int reopen_drm_node(int drm_fd, bool allow_render_node) { if (drmIsMaster(drm_fd)) { // Only recent kernels support empty leases uint32_t lessee_id; - int lease_fd = drmModeCreateLease(drm_fd, NULL, 0, 0, &lessee_id); + int lease_fd = drmModeCreateLease(drm_fd, NULL, 0, O_CLOEXEC, &lessee_id); if (lease_fd >= 0) { return lease_fd; } else if (lease_fd != -EINVAL && lease_fd != -EOPNOTSUPP) { @@ -92,6 +98,8 @@ struct wlr_allocator *allocator_autocreate_with_drm_fd( uint32_t renderer_caps = renderer_get_render_buffer_caps(renderer); struct wlr_allocator *alloc = NULL; + +#if WLR_HAS_GBM_ALLOCATOR uint32_t gbm_caps = WLR_BUFFER_CAP_DMABUF; if ((backend_caps & gbm_caps) && (renderer_caps & gbm_caps) && drm_fd >= 0) { @@ -106,6 +114,7 @@ struct wlr_allocator *allocator_autocreate_with_drm_fd( close(gbm_fd); wlr_log(WLR_DEBUG, "Failed to create gbm allocator"); } +#endif uint32_t shm_caps = WLR_BUFFER_CAP_SHM | WLR_BUFFER_CAP_DATA_PTR; if ((backend_caps & shm_caps) && (renderer_caps & shm_caps)) { @@ -149,7 +158,7 @@ void wlr_allocator_destroy(struct wlr_allocator *alloc) { if (alloc == NULL) { return; } - wl_signal_emit(&alloc->events.destroy, NULL); + wl_signal_emit_mutable(&alloc->events.destroy, NULL); alloc->impl->destroy(alloc); } diff --git a/render/allocator/drm_dumb.c b/render/allocator/drm_dumb.c index 5b47462bc..e2812ecb6 100644 --- a/render/allocator/drm_dumb.c +++ b/render/allocator/drm_dumb.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include diff --git a/render/allocator/gbm.c b/render/allocator/gbm.c index 8f73862a2..8c670774b 100644 --- a/render/allocator/gbm.c +++ b/render/allocator/gbm.c @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include diff --git a/render/allocator/meson.build b/render/allocator/meson.build index db17ccb2c..97c5a1c36 100644 --- a/render/allocator/meson.build +++ b/render/allocator/meson.build @@ -1,9 +1,25 @@ +allocators = get_option('allocators') +if 'auto' in allocators and get_option('auto_features').enabled() + allocators = ['gbm'] +elif 'auto' in allocators and get_option('auto_features').disabled() + allocators = [] +endif + wlr_files += files( 'allocator.c', - 'gbm.c', 'shm.c', 'drm_dumb.c', ) -has = cc.has_function('gbm_bo_get_fd_for_plane', dependencies: [gbm]) -add_project_arguments('-DHAS_GBM_BO_GET_FD_FOR_PLANE=@0@'.format(has.to_int()), language: 'c') +gbm = disabler() +if 'gbm' in allocators or 'auto' in allocators + gbm = dependency('gbm', version: '>=17.1.0', required: 'gbm' in allocators) +endif +if gbm.found() + wlr_files += files('gbm.c') + wlr_deps += gbm + features += { 'gbm-allocator': true } + + has = cc.has_function('gbm_bo_get_fd_for_plane', dependencies: [gbm]) + add_project_arguments('-DHAS_GBM_BO_GET_FD_FOR_PLANE=@0@'.format(has.to_int()), language: 'c') +endif diff --git a/render/allocator/shm.c b/render/allocator/shm.c index 044d5eb12..9e49a1445 100644 --- a/render/allocator/shm.c +++ b/render/allocator/shm.c @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include diff --git a/render/dmabuf.c b/render/dmabuf.c index 3c4311590..433cb82e0 100644 --- a/render/dmabuf.c +++ b/render/dmabuf.c @@ -29,7 +29,7 @@ bool wlr_dmabuf_attributes_copy(struct wlr_dmabuf_attributes *dst, error: for (int j = 0; j < i; j++) { - close(dst->fd[i]); + close(dst->fd[j]); dst->fd[j] = -1; } dst->n_planes = 0; diff --git a/render/egl.c b/render/egl.c index d5d6cfb7d..ee961f4b9 100644 --- a/render/egl.c +++ b/render/egl.c @@ -11,6 +11,7 @@ #include #include #include "render/egl.h" +#include "util/env.h" static enum wlr_log_importance egl_log_importance_to_wlr(EGLint type) { switch (type) { @@ -284,8 +285,7 @@ static bool egl_init_display(struct wlr_egl *egl, EGLDisplay *display) { } if (check_egl_ext(device_exts_str, "EGL_MESA_device_software")) { - const char *allow_software = getenv("WLR_RENDERER_ALLOW_SOFTWARE"); - if (allow_software != NULL && strcmp(allow_software, "1") == 0) { + if (env_parse_bool("WLR_RENDERER_ALLOW_SOFTWARE")) { wlr_log(WLR_INFO, "Using software rendering"); } else { wlr_log(WLR_ERROR, "Software rendering detected, please use " @@ -440,6 +440,7 @@ static EGLDeviceEXT get_egl_device_from_drm_fd(struct wlr_egl *egl, } } + drmFreeDevice(&device); free(devices); return egl_device; @@ -551,6 +552,7 @@ struct wlr_egl *wlr_egl_create_with_context(EGLDisplay display, } if (!egl_init_display(egl, display)) { + free(egl); return NULL; } @@ -582,6 +584,14 @@ void wlr_egl_destroy(struct wlr_egl *egl) { free(egl); } +EGLDisplay wlr_egl_get_display(struct wlr_egl *egl) { + return egl->display; +} + +EGLContext wlr_egl_get_context(struct wlr_egl *egl) { + return egl->context; +} + bool wlr_egl_destroy_image(struct wlr_egl *egl, EGLImage image) { if (!egl->exts.KHR_image_base) { return false; diff --git a/render/gles2/meson.build b/render/gles2/meson.build index f2cd5fbaf..504f0c11e 100644 --- a/render/gles2/meson.build +++ b/render/gles2/meson.build @@ -1,6 +1,6 @@ glesv2 = dependency('glesv2', required: 'gles2' in renderers) -if not (glesv2.found() and egl.found()) +if not (glesv2.found() and internal_features['egl']) subdir_done() endif diff --git a/render/gles2/pixel_format.c b/render/gles2/pixel_format.c index b155bbbe9..acaac5ceb 100644 --- a/render/gles2/pixel_format.c +++ b/render/gles2/pixel_format.c @@ -93,6 +93,20 @@ static const struct wlr_gles2_pixel_format formats[] = { .gl_type = GL_HALF_FLOAT_OES, .has_alpha = true, }, + { + .drm_format = DRM_FORMAT_XBGR16161616, + .gl_internalformat = GL_RGBA16_EXT, + .gl_format = GL_RGBA, + .gl_type = GL_UNSIGNED_SHORT, + .has_alpha = false, + }, + { + .drm_format = DRM_FORMAT_ABGR16161616, + .gl_internalformat = GL_RGBA16_EXT, + .gl_format = GL_RGBA, + .gl_type = GL_UNSIGNED_SHORT, + .has_alpha = true, + }, #endif }; @@ -112,6 +126,10 @@ bool is_gles2_pixel_format_supported(const struct wlr_gles2_renderer *renderer, && !renderer->exts.OES_texture_half_float_linear) { return false; } + if (format->gl_type == GL_UNSIGNED_SHORT + && !renderer->exts.EXT_texture_norm16) { + return false; + } /* * Note that we don't need to check for GL_EXT_texture_format_BGRA8888 * here, since we've already checked if we have it at renderer creation diff --git a/render/gles2/renderer.c b/render/gles2/renderer.c index 67b8ead47..c00a7f51c 100644 --- a/render/gles2/renderer.c +++ b/render/gles2/renderer.c @@ -1,6 +1,5 @@ #include #include -#include #include #include #include @@ -18,6 +17,7 @@ #include "render/egl.h" #include "render/gles2.h" #include "render/pixel_format.h" +#include "types/wlr_matrix.h" static const GLfloat verts[] = { 1, 0, // top right @@ -204,8 +204,8 @@ static void gles2_begin(struct wlr_renderer *wlr_renderer, uint32_t width, renderer->viewport_height = height; // refresh projection matrix - wlr_matrix_projection(renderer->projection, width, height, - WL_OUTPUT_TRANSFORM_NORMAL); + matrix_projection(renderer->projection, width, height, + WL_OUTPUT_TRANSFORM_FLIPPED_180); glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); @@ -246,12 +246,6 @@ static void gles2_scissor(struct wlr_renderer *wlr_renderer, pop_gles2_debug(renderer); } -static const float flip_180[9] = { - 1.0f, 0.0f, 0.0f, - 0.0f, -1.0f, 0.0f, - 0.0f, 0.0f, 1.0f, -}; - static bool gles2_render_subtexture_with_matrix( struct wlr_renderer *wlr_renderer, struct wlr_texture *wlr_texture, const struct wlr_fbox *box, const float matrix[static 9], @@ -287,7 +281,6 @@ static bool gles2_render_subtexture_with_matrix( float gl_matrix[9]; wlr_matrix_multiply(gl_matrix, renderer->projection, matrix); - wlr_matrix_multiply(gl_matrix, flip_180, gl_matrix); // OpenGL ES 2 requires the glUniformMatrix3fv transpose parameter to be set // to GL_FALSE @@ -347,7 +340,6 @@ static void gles2_render_quad_with_matrix(struct wlr_renderer *wlr_renderer, float gl_matrix[9]; wlr_matrix_multiply(gl_matrix, renderer->projection, matrix); - wlr_matrix_multiply(gl_matrix, flip_180, gl_matrix); // OpenGL ES 2 requires the glUniformMatrix3fv transpose parameter to be set // to GL_FALSE @@ -403,15 +395,10 @@ static uint32_t gles2_preferred_read_format( push_gles2_debug(renderer); - GLint gl_format = -1, gl_type = -1; + GLint gl_format = -1, gl_type = -1, alpha_size = -1; glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_FORMAT, &gl_format); glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_TYPE, &gl_type); - - EGLint alpha_size = -1; - glBindRenderbuffer(GL_RENDERBUFFER, renderer->current_buffer->rbo); - glGetRenderbufferParameteriv(GL_RENDERBUFFER, - GL_RENDERBUFFER_ALPHA_SIZE, &alpha_size); - glBindRenderbuffer(GL_RENDERBUFFER, 0); + glGetIntegerv(GL_ALPHA_BITS, &alpha_size); pop_gles2_debug(renderer); @@ -765,6 +752,9 @@ struct wlr_renderer *wlr_gles2_renderer_create(struct wlr_egl *egl) { renderer->exts.OES_texture_half_float_linear = check_gl_ext(exts_str, "GL_OES_texture_half_float_linear"); + renderer->exts.EXT_texture_norm16 = + check_gl_ext(exts_str, "GL_EXT_texture_norm16"); + if (check_gl_ext(exts_str, "GL_KHR_debug")) { renderer->exts.KHR_debug = true; load_gl_proc(&renderer->procs.glDebugMessageCallbackKHR, diff --git a/render/gles2/texture.c b/render/gles2/texture.c index 8d6f3fc24..776baf40a 100644 --- a/render/gles2/texture.c +++ b/render/gles2/texture.c @@ -15,7 +15,6 @@ #include "render/gles2.h" #include "render/pixel_format.h" #include "types/wlr_buffer.h" -#include "util/signal.h" static const struct wlr_texture_impl texture_impl; @@ -29,11 +28,6 @@ struct wlr_gles2_texture *gles2_get_texture( return (struct wlr_gles2_texture *)wlr_texture; } -static bool gles2_texture_is_opaque(struct wlr_texture *wlr_texture) { - struct wlr_gles2_texture *texture = gles2_get_texture(wlr_texture); - return !texture->has_alpha; -} - static bool check_stride(const struct wlr_pixel_format_info *fmt, uint32_t stride, uint32_t width) { if (stride % (fmt->bpp / 8) != 0) { @@ -49,14 +43,24 @@ static bool check_stride(const struct wlr_pixel_format_info *fmt, return true; } -static bool gles2_texture_write_pixels(struct wlr_texture *wlr_texture, - uint32_t stride, uint32_t width, uint32_t height, - uint32_t src_x, uint32_t src_y, uint32_t dst_x, uint32_t dst_y, - const void *data) { +static bool gles2_texture_update_from_buffer(struct wlr_texture *wlr_texture, + struct wlr_buffer *buffer, pixman_region32_t *damage) { struct wlr_gles2_texture *texture = gles2_get_texture(wlr_texture); if (texture->target != GL_TEXTURE_2D || texture->image != EGL_NO_IMAGE_KHR) { - wlr_log(WLR_ERROR, "Cannot write pixels to immutable texture"); + return false; + } + + void *data; + uint32_t format; + size_t stride; + if (!wlr_buffer_begin_data_ptr_access(buffer, + WLR_BUFFER_DATA_PTR_ACCESS_READ, &data, &format, &stride)) { + return false; + } + + if (format != texture->drm_format) { + wlr_buffer_end_data_ptr_access(buffer); return false; } @@ -68,7 +72,8 @@ static bool gles2_texture_write_pixels(struct wlr_texture *wlr_texture, drm_get_pixel_format_info(texture->drm_format); assert(drm_fmt); - if (!check_stride(drm_fmt, stride, width)) { + if (!check_stride(drm_fmt, stride, buffer->width)) { + wlr_buffer_end_data_ptr_access(buffer); return false; } @@ -80,12 +85,21 @@ static bool gles2_texture_write_pixels(struct wlr_texture *wlr_texture, glBindTexture(GL_TEXTURE_2D, texture->tex); - glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, stride / (drm_fmt->bpp / 8)); - glPixelStorei(GL_UNPACK_SKIP_PIXELS_EXT, src_x); - glPixelStorei(GL_UNPACK_SKIP_ROWS_EXT, src_y); + int rects_len = 0; + pixman_box32_t *rects = pixman_region32_rectangles(damage, &rects_len); - glTexSubImage2D(GL_TEXTURE_2D, 0, dst_x, dst_y, width, height, - fmt->gl_format, fmt->gl_type, data); + for (int i = 0; i < rects_len; i++) { + pixman_box32_t rect = rects[i]; + + glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, stride / (drm_fmt->bpp / 8)); + glPixelStorei(GL_UNPACK_SKIP_PIXELS_EXT, rect.x1); + glPixelStorei(GL_UNPACK_SKIP_ROWS_EXT, rect.y1); + + int width = rect.x2 - rect.x1; + int height = rect.y2 - rect.y1; + glTexSubImage2D(GL_TEXTURE_2D, 0, rect.x1, rect.y1, width, height, + fmt->gl_format, fmt->gl_type, data); + } glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, 0); glPixelStorei(GL_UNPACK_SKIP_PIXELS_EXT, 0); @@ -97,6 +111,8 @@ static bool gles2_texture_write_pixels(struct wlr_texture *wlr_texture, wlr_egl_restore_context(&prev_ctx); + wlr_buffer_end_data_ptr_access(buffer); + return true; } @@ -161,8 +177,7 @@ static void gles2_texture_unref(struct wlr_texture *wlr_texture) { } static const struct wlr_texture_impl texture_impl = { - .is_opaque = gles2_texture_is_opaque, - .write_pixels = gles2_texture_write_pixels, + .update_from_buffer = gles2_texture_update_from_buffer, .destroy = gles2_texture_unref, }; @@ -210,6 +225,11 @@ static struct wlr_texture *gles2_texture_from_pixels( texture->has_alpha = fmt->has_alpha; texture->drm_format = fmt->drm_format; + GLint internal_format = fmt->gl_internalformat; + if (!internal_format) { + internal_format = fmt->gl_format; + } + struct wlr_egl_context prev_ctx; wlr_egl_save_context(&prev_ctx); wlr_egl_make_current(renderer->egl); @@ -222,7 +242,7 @@ static struct wlr_texture *gles2_texture_from_pixels( glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, stride / (drm_fmt->bpp / 8)); - glTexImage2D(GL_TEXTURE_2D, 0, fmt->gl_format, width, height, 0, + glTexImage2D(GL_TEXTURE_2D, 0, internal_format, width, height, 0, fmt->gl_format, fmt->gl_type, data); glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, 0); diff --git a/render/meson.build b/render/meson.build index a1289edee..c8c6032fa 100644 --- a/render/meson.build +++ b/render/meson.build @@ -16,9 +16,11 @@ wlr_files += files( if 'gles2' in renderers or 'auto' in renderers egl = dependency('egl', required: 'gles2' in renderers) - if egl.found() - wlr_deps += egl + gbm = dependency('gbm', required: 'gles2' in renderers) + if egl.found() and gbm.found() + wlr_deps += [egl, gbm] wlr_files += files('egl.c') + internal_features += { 'egl': true } endif subdir('gles2') endif diff --git a/render/pixel_format.c b/render/pixel_format.c index bd59af8b1..e6417fd7c 100644 --- a/render/pixel_format.c +++ b/render/pixel_format.c @@ -128,6 +128,18 @@ static const struct wlr_pixel_format_info pixel_format_info[] = { .bpp = 64, .has_alpha = true, }, + { + .drm_format = DRM_FORMAT_XBGR16161616, + .opaque_substitute = DRM_FORMAT_INVALID, + .bpp = 64, + .has_alpha = false, + }, + { + .drm_format = DRM_FORMAT_ABGR16161616, + .opaque_substitute = DRM_FORMAT_XBGR16161616, + .bpp = 64, + .has_alpha = true, + }, }; static const size_t pixel_format_info_size = diff --git a/render/pixman/renderer.c b/render/pixman/renderer.c index 13db08800..2853b7047 100644 --- a/render/pixman/renderer.c +++ b/render/pixman/renderer.c @@ -46,11 +46,6 @@ static struct wlr_pixman_texture *get_texture( return (struct wlr_pixman_texture *)wlr_texture; } -static bool texture_is_opaque(struct wlr_texture *wlr_texture) { - struct wlr_pixman_texture *texture = get_texture(wlr_texture); - return !texture->format_info->has_alpha; -} - static void texture_destroy(struct wlr_texture *wlr_texture) { struct wlr_pixman_texture *texture = get_texture(wlr_texture); wl_list_remove(&texture->link); @@ -61,7 +56,6 @@ static void texture_destroy(struct wlr_texture *wlr_texture) { } static const struct wlr_texture_impl texture_impl = { - .is_opaque = texture_is_opaque, .destroy = texture_destroy, }; diff --git a/render/vulkan/pixel_format.c b/render/vulkan/pixel_format.c index cfab5ffe8..b4c400700 100644 --- a/render/vulkan/pixel_format.c +++ b/render/vulkan/pixel_format.c @@ -296,6 +296,8 @@ void vulkan_format_props_query(struct wlr_vk_device *dev, if (add_fmt_props) { dev->format_props[dev->format_prop_count] = props; ++dev->format_prop_count; + } else { + vulkan_format_props_finish(&props); } } diff --git a/render/vulkan/renderer.c b/render/vulkan/renderer.c index 21b36bdd6..c373269df 100644 --- a/render/vulkan/renderer.c +++ b/render/vulkan/renderer.c @@ -23,6 +23,7 @@ #include "render/vulkan/shaders/texture.frag.h" #include "render/vulkan/shaders/quad.frag.h" #include "types/wlr_buffer.h" +#include "types/wlr_matrix.h" // TODO: // - simplify stage allocation, don't track allocations but use ringbuffer-like @@ -564,9 +565,9 @@ static void vulkan_begin(struct wlr_renderer *wlr_renderer, vkCmdSetScissor(cb, 0, 1, &rect); // Refresh projection matrix. - // wlr_matrix_projection assumes a GL corrdinate system so we need + // matrix_projection() assumes a GL coordinate system so we need // to pass WL_OUTPUT_TRANSFORM_FLIPPED_180 to adjust it for vulkan. - wlr_matrix_projection(renderer->projection, width, height, + matrix_projection(renderer->projection, width, height, WL_OUTPUT_TRANSFORM_FLIPPED_180); renderer->render_width = width; diff --git a/render/vulkan/texture.c b/render/vulkan/texture.c index b705603cf..52356f640 100644 --- a/render/vulkan/texture.c +++ b/render/vulkan/texture.c @@ -7,14 +7,19 @@ #include #include #include +#include #include #include "render/pixel_format.h" #include "render/vulkan.h" static const struct wlr_texture_impl texture_impl; +bool wlr_texture_is_vk(struct wlr_texture *wlr_texture) { + return wlr_texture->impl == &texture_impl; +} + struct wlr_vk_texture *vulkan_get_texture(struct wlr_texture *wlr_texture) { - assert(wlr_texture->impl == &texture_impl); + assert(wlr_texture_is_vk(wlr_texture)); return (struct wlr_vk_texture *)wlr_texture; } @@ -28,14 +33,6 @@ static VkImageAspectFlagBits mem_plane_aspect(unsigned i) { } } -static bool vulkan_texture_is_opaque(struct wlr_texture *wlr_texture) { - struct wlr_vk_texture *texture = vulkan_get_texture(wlr_texture); - const struct wlr_pixel_format_info *format_info = drm_get_pixel_format_info( - texture->format->drm_format); - assert(format_info); - return !format_info->has_alpha; -} - // Will transition the texture to shaderReadOnlyOptimal layout for reading // from fragment shader later on static bool write_pixels(struct wlr_texture *wlr_texture, @@ -139,12 +136,45 @@ static bool write_pixels(struct wlr_texture *wlr_texture, return true; } -static bool vulkan_texture_write_pixels(struct wlr_texture *wlr_texture, - uint32_t stride, uint32_t width, uint32_t height, uint32_t src_x, - uint32_t src_y, uint32_t dst_x, uint32_t dst_y, const void *vdata) { - return write_pixels(wlr_texture, stride, width, height, src_x, src_y, - dst_x, dst_y, vdata, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, - VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_ACCESS_SHADER_READ_BIT); +static bool vulkan_texture_update_from_buffer(struct wlr_texture *wlr_texture, + struct wlr_buffer *buffer, pixman_region32_t *damage) { + struct wlr_vk_texture *texture = vulkan_get_texture(wlr_texture); + + void *data; + uint32_t format; + size_t stride; + if (!wlr_buffer_begin_data_ptr_access(buffer, + WLR_BUFFER_DATA_PTR_ACCESS_READ, &data, &format, &stride)) { + return false; + } + + bool ok = true; + + if (format != texture->format->drm_format) { + ok = false; + goto out; + } + + int rects_len = 0; + pixman_box32_t *rects = pixman_region32_rectangles(damage, &rects_len); + + for (int i = 0; i < rects_len; i++) { + pixman_box32_t rect = rects[i]; + uint32_t width = rect.x2 - rect.x1; + uint32_t height = rect.y2 - rect.y1; + + // TODO: only map memory once + ok = write_pixels(wlr_texture, stride, width, height, rect.x1, rect.y1, + rect.x1, rect.y1, data, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_ACCESS_SHADER_READ_BIT); + if (!ok) { + goto out; + } + } + +out: + wlr_buffer_end_data_ptr_access(buffer); + return ok; } void vulkan_texture_destroy(struct wlr_vk_texture *texture) { @@ -194,8 +224,7 @@ static void vulkan_texture_unref(struct wlr_texture *wlr_texture) { } static const struct wlr_texture_impl texture_impl = { - .is_opaque = vulkan_texture_is_opaque, - .write_pixels = vulkan_texture_write_pixels, + .update_from_buffer = vulkan_texture_update_from_buffer, .destroy = vulkan_texture_unref, }; @@ -241,8 +270,6 @@ static struct wlr_texture *vulkan_texture_from_pixels(struct wlr_renderer *wlr_r texture->format = &fmt->format; // create image - unsigned mem_bits = 0xFFFFFFFF; - VkImageCreateInfo img_info = {0}; img_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; img_info.imageType = VK_IMAGE_TYPE_2D; @@ -257,8 +284,6 @@ static struct wlr_texture *vulkan_texture_from_pixels(struct wlr_renderer *wlr_r img_info.tiling = VK_IMAGE_TILING_OPTIMAL; img_info.usage |= VK_IMAGE_USAGE_TRANSFER_DST_BIT; - mem_bits = vulkan_find_mem_type(renderer->dev, - VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, mem_bits); VkImageLayout layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; res = vkCreateImage(dev, &img_info, NULL, &texture->image); @@ -274,7 +299,15 @@ static struct wlr_texture *vulkan_texture_from_pixels(struct wlr_renderer *wlr_r VkMemoryAllocateInfo mem_info = {0}; mem_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; mem_info.allocationSize = mem_reqs.size; - mem_info.memoryTypeIndex = mem_bits & mem_reqs.memoryTypeBits; + + int mem_type_index = vulkan_find_mem_type(renderer->dev, + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, mem_reqs.memoryTypeBits); + if (mem_type_index == -1) { + wlr_log(WLR_ERROR, "failed to find suitable vulkan memory type"); + goto error; + } + mem_info.memoryTypeIndex = mem_type_index; + res = vkAllocateMemory(dev, &mem_info, NULL, &texture->memories[0]); if (res != VK_SUCCESS) { wlr_vk_error("vkAllocatorMemory failed", res); diff --git a/render/wlr_renderer.c b/render/wlr_renderer.c index 2b5cf9945..f140f9afa 100644 --- a/render/wlr_renderer.c +++ b/render/wlr_renderer.c @@ -26,9 +26,9 @@ #endif // WLR_HAS_VULKAN_RENDERER #include "backend/backend.h" -#include "util/signal.h" #include "render/pixel_format.h" #include "render/wlr_renderer.h" +#include "util/env.h" void wlr_renderer_init(struct wlr_renderer *renderer, const struct wlr_renderer_impl *impl) { @@ -39,6 +39,8 @@ void wlr_renderer_init(struct wlr_renderer *renderer, assert(impl->render_quad_with_matrix); assert(impl->get_shm_texture_formats); assert(impl->get_render_buffer_caps); + + memset(renderer, 0, sizeof(*renderer)); renderer->impl = impl; wl_signal_init(&renderer->events.destroy); @@ -51,7 +53,7 @@ void wlr_renderer_destroy(struct wlr_renderer *r) { assert(!r->rendering); - wlr_signal_emit_safe(&r->events.destroy, r); + wl_signal_emit_mutable(&r->events.destroy, r); if (r->impl && r->impl->destroy) { r->impl->destroy(r); @@ -265,54 +267,65 @@ bool wlr_renderer_init_wl_display(struct wlr_renderer *r, return true; } -struct wlr_renderer *renderer_autocreate_with_drm_fd(int drm_fd) { - const char *name = getenv("WLR_RENDERER"); - if (name) { - wlr_log(WLR_INFO, "Loading user-specified renderer due to WLR_RENDERER: %s", - name); +static void log_creation_failure(bool is_auto, const char *msg) { + wlr_log(is_auto ? WLR_DEBUG : WLR_ERROR, "%s%s", msg, is_auto ? ". Skipping!" : ""); +} +struct wlr_renderer *renderer_autocreate_with_drm_fd(int drm_fd) { + const char *renderer_options[] = { + "auto", #if WLR_HAS_GLES2_RENDERER - if (strcmp(name, "gles2") == 0) { - if (drm_fd < 0) { - wlr_log(WLR_ERROR, "Cannot create GLES2 renderer: " - "no DRM FD available"); - return NULL; - } - return wlr_gles2_renderer_create_with_drm_fd(drm_fd); - } + "gles2", #endif #if WLR_HAS_VULKAN_RENDERER - if (strcmp(name, "vulkan") == 0) { - return wlr_vk_renderer_create_with_drm_fd(drm_fd); - } + "vulkan", #endif - if (strcmp(name, "pixman") == 0) { - return wlr_pixman_renderer_create(); - } - - wlr_log(WLR_ERROR, "Invalid WLR_RENDERER value: '%s'", name); - return NULL; - } + "pixman", + NULL + }; + const char *renderer_name = renderer_options[env_parse_switch("WLR_RENDERER", renderer_options)]; + bool is_auto = strcmp(renderer_name, "auto") == 0; struct wlr_renderer *renderer = NULL; + #if WLR_HAS_GLES2_RENDERER - if (drm_fd >= 0) { - if ((renderer = wlr_gles2_renderer_create_with_drm_fd(drm_fd)) != NULL) { - return renderer; + if (!renderer && (is_auto || strcmp(renderer_name, "gles2") == 0)) { + if (drm_fd < 0) { + log_creation_failure(is_auto, "Cannot create GLES2 renderer: no DRM FD available"); + } else { + renderer = wlr_gles2_renderer_create_with_drm_fd(drm_fd); + if (!renderer) { + log_creation_failure(is_auto, "Failed to create a GLES2 renderer"); + } } - wlr_log(WLR_DEBUG, "Failed to create GLES2 renderer"); - } else { - wlr_log(WLR_DEBUG, "Skipping GLES2 renderer: no DRM FD available"); } #endif - if ((renderer = wlr_pixman_renderer_create()) != NULL) { - return renderer; +#if WLR_HAS_VULKAN_RENDERER + if (!renderer && (is_auto || strcmp(renderer_name, "vulkan") == 0)) { + if (drm_fd < 0) { + log_creation_failure(is_auto, "Cannot create Vulkan renderer: no DRM FD available"); + } else { + renderer = wlr_vk_renderer_create_with_drm_fd(drm_fd); + if (!renderer) { + log_creation_failure(is_auto, "Failed to create a Vulkan renderer"); + } + } } - wlr_log(WLR_DEBUG, "Failed to create pixman renderer"); +#endif - wlr_log(WLR_ERROR, "Could not initialize renderer"); - return NULL; + if (!renderer && (is_auto || strcmp(renderer_name, "pixman") == 0)) { + renderer = wlr_pixman_renderer_create(); + if (!renderer) { + log_creation_failure(is_auto, "Failed to create a pixman renderer"); + } + } + + if (!renderer) { + wlr_log(WLR_ERROR, "Could not initialize renderer"); + } + + return renderer; } static int open_drm_render_node(void) { diff --git a/render/wlr_texture.c b/render/wlr_texture.c index c4563dd67..7a59af30d 100644 --- a/render/wlr_texture.c +++ b/render/wlr_texture.c @@ -1,12 +1,14 @@ #include #include #include +#include #include #include #include "types/wlr_buffer.h" void wlr_texture_init(struct wlr_texture *texture, const struct wlr_texture_impl *impl, uint32_t width, uint32_t height) { + memset(texture, 0, sizeof(*texture)); texture->impl = impl; texture->width = width; texture->height = height; @@ -63,27 +65,25 @@ struct wlr_texture *wlr_texture_from_dmabuf(struct wlr_renderer *renderer, struct wlr_texture *wlr_texture_from_buffer(struct wlr_renderer *renderer, struct wlr_buffer *buffer) { - assert(!renderer->rendering); if (!renderer->impl->texture_from_buffer) { return NULL; } return renderer->impl->texture_from_buffer(renderer, buffer); } -bool wlr_texture_is_opaque(struct wlr_texture *texture) { - if (!texture->impl->is_opaque) { +bool wlr_texture_update_from_buffer(struct wlr_texture *texture, + struct wlr_buffer *buffer, pixman_region32_t *damage) { + if (!texture->impl->update_from_buffer) { return false; } - return texture->impl->is_opaque(texture); -} - -bool wlr_texture_write_pixels(struct wlr_texture *texture, - uint32_t stride, uint32_t width, uint32_t height, - uint32_t src_x, uint32_t src_y, uint32_t dst_x, uint32_t dst_y, - const void *data) { - if (!texture->impl->write_pixels) { + if (texture->width != (uint32_t)buffer->width || + texture->height != (uint32_t)buffer->height) { return false; } - return texture->impl->write_pixels(texture, stride, width, height, - src_x, src_y, dst_x, dst_y, data); + const pixman_box32_t *extents = pixman_region32_extents(damage); + if (extents->x1 < 0 || extents->y1 < 0 || extents->x2 > buffer->width || + extents->y2 > buffer->height) { + return false; + } + return texture->impl->update_from_buffer(texture, buffer, damage); } diff --git a/tinywl/Makefile b/tinywl/Makefile index 505666f03..68bac2522 100644 --- a/tinywl/Makefile +++ b/tinywl/Makefile @@ -12,11 +12,7 @@ xdg-shell-protocol.h: $(WAYLAND_SCANNER) server-header \ $(WAYLAND_PROTOCOLS)/stable/xdg-shell/xdg-shell.xml $@ -xdg-shell-protocol.c: xdg-shell-protocol.h - $(WAYLAND_SCANNER) private-code \ - $(WAYLAND_PROTOCOLS)/stable/xdg-shell/xdg-shell.xml $@ - -tinywl: tinywl.c xdg-shell-protocol.h xdg-shell-protocol.c +tinywl: tinywl.c xdg-shell-protocol.h $(CC) $(CFLAGS) \ -g -Werror -I. \ -DWLR_USE_UNSTABLE \ diff --git a/tinywl/README.md b/tinywl/README.md index e0385d243..7fc83b96d 100644 --- a/tinywl/README.md +++ b/tinywl/README.md @@ -43,5 +43,3 @@ Notable omissions from TinyWL: - Optional protocols, e.g. screen capture, primary selection, virtual keyboard, etc. Most of these are plug-and-play with wlroots, but they're omitted for brevity. -- Damage tracking, which tracks which parts of the screen are changing and - minimizes redraws accordingly. diff --git a/tinywl/tinywl.c b/tinywl/tinywl.c index a4fcc2626..4fc8477c7 100644 --- a/tinywl/tinywl.c +++ b/tinywl/tinywl.c @@ -73,28 +73,32 @@ struct tinywl_output { struct tinywl_server *server; struct wlr_output *wlr_output; struct wl_listener frame; + struct wl_listener destroy; }; struct tinywl_view { struct wl_list link; struct tinywl_server *server; struct wlr_xdg_toplevel *xdg_toplevel; - struct wlr_scene_node *scene_node; + struct wlr_scene_tree *scene_tree; struct wl_listener map; struct wl_listener unmap; struct wl_listener destroy; struct wl_listener request_move; struct wl_listener request_resize; + struct wl_listener request_maximize; + struct wl_listener request_fullscreen; int x, y; }; struct tinywl_keyboard { struct wl_list link; struct tinywl_server *server; - struct wlr_input_device *device; + struct wlr_keyboard *wlr_keyboard; struct wl_listener modifiers; struct wl_listener key; + struct wl_listener destroy; }; static void focus_view(struct tinywl_view *view, struct wlr_surface *surface) { @@ -122,7 +126,7 @@ static void focus_view(struct tinywl_view *view, struct wlr_surface *surface) { } struct wlr_keyboard *keyboard = wlr_seat_get_keyboard(seat); /* Move the view to the front */ - wlr_scene_node_raise_to_top(view->scene_node); + wlr_scene_node_raise_to_top(&view->scene_tree->node); wl_list_remove(&view->link); wl_list_insert(&server->views, &view->link); /* Activate the new surface */ @@ -132,8 +136,10 @@ static void focus_view(struct tinywl_view *view, struct wlr_surface *surface) { * track of this and automatically send key events to the appropriate * clients without additional work on your part. */ - wlr_seat_keyboard_notify_enter(seat, view->xdg_toplevel->base->surface, - keyboard->keycodes, keyboard->num_keycodes, &keyboard->modifiers); + if (keyboard != NULL) { + wlr_seat_keyboard_notify_enter(seat, view->xdg_toplevel->base->surface, + keyboard->keycodes, keyboard->num_keycodes, &keyboard->modifiers); + } } static void keyboard_handle_modifiers( @@ -148,10 +154,10 @@ static void keyboard_handle_modifiers( * same seat. You can swap out the underlying wlr_keyboard like this and * wlr_seat handles this transparently. */ - wlr_seat_set_keyboard(keyboard->server->seat, keyboard->device); + wlr_seat_set_keyboard(keyboard->server->seat, keyboard->wlr_keyboard); /* Send modifiers to the client. */ wlr_seat_keyboard_notify_modifiers(keyboard->server->seat, - &keyboard->device->keyboard->modifiers); + &keyboard->wlr_keyboard->modifiers); } static bool handle_keybinding(struct tinywl_server *server, xkb_keysym_t sym) { @@ -187,7 +193,7 @@ static void keyboard_handle_key( struct tinywl_keyboard *keyboard = wl_container_of(listener, keyboard, key); struct tinywl_server *server = keyboard->server; - struct wlr_event_keyboard_key *event = data; + struct wlr_keyboard_key_event *event = data; struct wlr_seat *seat = server->seat; /* Translate libinput keycode -> xkbcommon */ @@ -195,10 +201,10 @@ static void keyboard_handle_key( /* Get a list of keysyms based on the keymap for this keyboard */ const xkb_keysym_t *syms; int nsyms = xkb_state_key_get_syms( - keyboard->device->keyboard->xkb_state, keycode, &syms); + keyboard->wlr_keyboard->xkb_state, keycode, &syms); bool handled = false; - uint32_t modifiers = wlr_keyboard_get_modifiers(keyboard->device->keyboard); + uint32_t modifiers = wlr_keyboard_get_modifiers(keyboard->wlr_keyboard); if ((modifiers & WLR_MODIFIER_ALT) && event->state == WL_KEYBOARD_KEY_STATE_PRESSED) { /* If alt is held down and this button was _pressed_, we attempt to @@ -210,18 +216,34 @@ static void keyboard_handle_key( if (!handled) { /* Otherwise, we pass it along to the client. */ - wlr_seat_set_keyboard(seat, keyboard->device); + wlr_seat_set_keyboard(seat, keyboard->wlr_keyboard); wlr_seat_keyboard_notify_key(seat, event->time_msec, event->keycode, event->state); } } +static void keyboard_handle_destroy(struct wl_listener *listener, void *data) { + /* This event is raised by the keyboard base wlr_input_device to signal + * the destruction of the wlr_keyboard. It will no longer receive events + * and should be destroyed. + */ + struct tinywl_keyboard *keyboard = + wl_container_of(listener, keyboard, destroy); + wl_list_remove(&keyboard->modifiers.link); + wl_list_remove(&keyboard->key.link); + wl_list_remove(&keyboard->destroy.link); + wl_list_remove(&keyboard->link); + free(keyboard); +} + static void server_new_keyboard(struct tinywl_server *server, struct wlr_input_device *device) { + struct wlr_keyboard *wlr_keyboard = wlr_keyboard_from_input_device(device); + struct tinywl_keyboard *keyboard = calloc(1, sizeof(struct tinywl_keyboard)); keyboard->server = server; - keyboard->device = device; + keyboard->wlr_keyboard = wlr_keyboard; /* We need to prepare an XKB keymap and assign it to the keyboard. This * assumes the defaults (e.g. layout = "us"). */ @@ -229,18 +251,20 @@ static void server_new_keyboard(struct tinywl_server *server, struct xkb_keymap *keymap = xkb_keymap_new_from_names(context, NULL, XKB_KEYMAP_COMPILE_NO_FLAGS); - wlr_keyboard_set_keymap(device->keyboard, keymap); + wlr_keyboard_set_keymap(wlr_keyboard, keymap); xkb_keymap_unref(keymap); xkb_context_unref(context); - wlr_keyboard_set_repeat_info(device->keyboard, 25, 600); + wlr_keyboard_set_repeat_info(wlr_keyboard, 25, 600); /* Here we set up listeners for keyboard events. */ keyboard->modifiers.notify = keyboard_handle_modifiers; - wl_signal_add(&device->keyboard->events.modifiers, &keyboard->modifiers); + wl_signal_add(&wlr_keyboard->events.modifiers, &keyboard->modifiers); keyboard->key.notify = keyboard_handle_key; - wl_signal_add(&device->keyboard->events.key, &keyboard->key); + wl_signal_add(&wlr_keyboard->events.key, &keyboard->key); + keyboard->destroy.notify = keyboard_handle_destroy; + wl_signal_add(&device->events.destroy, &keyboard->destroy); - wlr_seat_set_keyboard(server->seat, device); + wlr_seat_set_keyboard(server->seat, keyboard->wlr_keyboard); /* And add the keyboard to our list of keyboards */ wl_list_insert(&server->keyboards, &keyboard->link); @@ -318,17 +342,25 @@ static struct tinywl_view *desktop_view_at( * we only care about surface nodes as we are specifically looking for a * surface in the surface tree of a tinywl_view. */ struct wlr_scene_node *node = wlr_scene_node_at( - &server->scene->node, lx, ly, sx, sy); - if (node == NULL || node->type != WLR_SCENE_NODE_SURFACE) { + &server->scene->tree.node, lx, ly, sx, sy); + if (node == NULL || node->type != WLR_SCENE_NODE_BUFFER) { return NULL; } - *surface = wlr_scene_surface_from_node(node)->surface; + struct wlr_scene_buffer *scene_buffer = wlr_scene_buffer_from_node(node); + struct wlr_scene_surface *scene_surface = + wlr_scene_surface_from_buffer(scene_buffer); + if (!scene_surface) { + return NULL; + } + + *surface = scene_surface->surface; /* Find the node corresponding to the tinywl_view at the root of this * surface tree, it is the only one for which we set the data field. */ - while (node != NULL && node->data == NULL) { - node = node->parent; + struct wlr_scene_tree *tree = node->parent; + while (tree != NULL && tree->node.data == NULL) { + tree = tree->node.parent; } - return node->data; + return tree->node.data; } static void process_cursor_move(struct tinywl_server *server, uint32_t time) { @@ -336,7 +368,7 @@ static void process_cursor_move(struct tinywl_server *server, uint32_t time) { struct tinywl_view *view = server->grabbed_view; view->x = server->cursor->x - server->grab_x; view->y = server->cursor->y - server->grab_y; - wlr_scene_node_set_position(view->scene_node, view->x, view->y); + wlr_scene_node_set_position(&view->scene_tree->node, view->x, view->y); } static void process_cursor_resize(struct tinywl_server *server, uint32_t time) { @@ -385,7 +417,7 @@ static void process_cursor_resize(struct tinywl_server *server, uint32_t time) { wlr_xdg_surface_get_geometry(view->xdg_toplevel->base, &geo_box); view->x = new_left - geo_box.x; view->y = new_top - geo_box.y; - wlr_scene_node_set_position(view->scene_node, view->x, view->y); + wlr_scene_node_set_position(&view->scene_tree->node, view->x, view->y); int new_width = new_right - new_left; int new_height = new_bottom - new_top; @@ -441,13 +473,13 @@ static void server_cursor_motion(struct wl_listener *listener, void *data) { * pointer motion event (i.e. a delta) */ struct tinywl_server *server = wl_container_of(listener, server, cursor_motion); - struct wlr_event_pointer_motion *event = data; + struct wlr_pointer_motion_event *event = data; /* The cursor doesn't move unless we tell it to. The cursor automatically * handles constraining the motion to the output layout, as well as any * special configuration applied for the specific input device which * generated the event. You can pass NULL for the device if you want to move * the cursor around without any input. */ - wlr_cursor_move(server->cursor, event->device, + wlr_cursor_move(server->cursor, &event->pointer->base, event->delta_x, event->delta_y); process_cursor_motion(server, event->time_msec); } @@ -462,8 +494,9 @@ static void server_cursor_motion_absolute( * emits these events. */ struct tinywl_server *server = wl_container_of(listener, server, cursor_motion_absolute); - struct wlr_event_pointer_motion_absolute *event = data; - wlr_cursor_warp_absolute(server->cursor, event->device, event->x, event->y); + struct wlr_pointer_motion_absolute_event *event = data; + wlr_cursor_warp_absolute(server->cursor, &event->pointer->base, event->x, + event->y); process_cursor_motion(server, event->time_msec); } @@ -472,7 +505,7 @@ static void server_cursor_button(struct wl_listener *listener, void *data) { * event. */ struct tinywl_server *server = wl_container_of(listener, server, cursor_button); - struct wlr_event_pointer_button *event = data; + struct wlr_pointer_button_event *event = data; /* Notify the client with pointer focus that a button press has occurred */ wlr_seat_pointer_notify_button(server->seat, event->time_msec, event->button, event->state); @@ -494,7 +527,7 @@ static void server_cursor_axis(struct wl_listener *listener, void *data) { * for example when you move the scroll wheel. */ struct tinywl_server *server = wl_container_of(listener, server, cursor_axis); - struct wlr_event_pointer_axis *event = data; + struct wlr_pointer_axis_event *event = data; /* Notify the client with pointer focus of the axis event. */ wlr_seat_pointer_notify_axis(server->seat, event->time_msec, event->orientation, event->delta, @@ -529,6 +562,15 @@ static void output_frame(struct wl_listener *listener, void *data) { wlr_scene_output_send_frame_done(scene_output, &now); } +static void output_destroy(struct wl_listener *listener, void *data) { + struct tinywl_output *output = wl_container_of(listener, output, destroy); + + wl_list_remove(&output->frame.link); + wl_list_remove(&output->destroy.link); + wl_list_remove(&output->link); + free(output); +} + static void server_new_output(struct wl_listener *listener, void *data) { /* This event is raised by the backend when a new output (aka a display or * monitor) becomes available. */ @@ -562,6 +604,11 @@ static void server_new_output(struct wl_listener *listener, void *data) { /* Sets up a listener for the frame notify event. */ output->frame.notify = output_frame; wl_signal_add(&wlr_output->events.frame, &output->frame); + + /* Sets up a listener for the destroy notify event. */ + output->destroy.notify = output_destroy; + wl_signal_add(&wlr_output->events.destroy, &output->destroy); + wl_list_insert(&server->outputs, &output->link); /* Adds this to the output layout. The add_auto function arranges outputs @@ -601,6 +648,8 @@ static void xdg_toplevel_destroy(struct wl_listener *listener, void *data) { wl_list_remove(&view->destroy.link); wl_list_remove(&view->request_move.link); wl_list_remove(&view->request_resize.link); + wl_list_remove(&view->request_maximize.link); + wl_list_remove(&view->request_fullscreen.link); free(view); } @@ -666,6 +715,26 @@ static void xdg_toplevel_request_resize( begin_interactive(view, TINYWL_CURSOR_RESIZE, event->edges); } +static void xdg_toplevel_request_maximize( + struct wl_listener *listener, void *data) { + /* This event is raised when a client would like to maximize itself, + * typically because the user clicked on the maximize button on + * client-side decorations. tinywl doesn't support maximization, but + * to conform to xdg-shell protocol we still must send a configure. + * wlr_xdg_surface_schedule_configure() is used to send an empty reply. */ + struct tinywl_view *view = + wl_container_of(listener, view, request_maximize); + wlr_xdg_surface_schedule_configure(view->xdg_toplevel->base); +} + +static void xdg_toplevel_request_fullscreen( + struct wl_listener *listener, void *data) { + /* Just as with request_maximize, we must send a configure here. */ + struct tinywl_view *view = + wl_container_of(listener, view, request_fullscreen); + wlr_xdg_surface_schedule_configure(view->xdg_toplevel->base); +} + static void server_new_xdg_surface(struct wl_listener *listener, void *data) { /* This event is raised when wlr_xdg_shell receives a new xdg surface from a * client, either a toplevel (application window) or popup. */ @@ -681,9 +750,9 @@ static void server_new_xdg_surface(struct wl_listener *listener, void *data) { if (xdg_surface->role == WLR_XDG_SURFACE_ROLE_POPUP) { struct wlr_xdg_surface *parent = wlr_xdg_surface_from_wlr_surface( xdg_surface->popup->parent); - struct wlr_scene_node *parent_node = parent->data; + struct wlr_scene_tree *parent_tree = parent->data; xdg_surface->data = wlr_scene_xdg_surface_create( - parent_node, xdg_surface); + parent_tree, xdg_surface); return; } assert(xdg_surface->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL); @@ -693,10 +762,10 @@ static void server_new_xdg_surface(struct wl_listener *listener, void *data) { calloc(1, sizeof(struct tinywl_view)); view->server = server; view->xdg_toplevel = xdg_surface->toplevel; - view->scene_node = wlr_scene_xdg_surface_create( - &view->server->scene->node, view->xdg_toplevel->base); - view->scene_node->data = view; - xdg_surface->data = view->scene_node; + view->scene_tree = wlr_scene_xdg_surface_create( + &view->server->scene->tree, view->xdg_toplevel->base); + view->scene_tree->node.data = view; + xdg_surface->data = view->scene_tree; /* Listen to the various events it can emit */ view->map.notify = xdg_toplevel_map; @@ -712,6 +781,12 @@ static void server_new_xdg_surface(struct wl_listener *listener, void *data) { wl_signal_add(&toplevel->events.request_move, &view->request_move); view->request_resize.notify = xdg_toplevel_request_resize; wl_signal_add(&toplevel->events.request_resize, &view->request_resize); + view->request_maximize.notify = xdg_toplevel_request_maximize; + wl_signal_add(&toplevel->events.request_maximize, + &view->request_maximize); + view->request_fullscreen.notify = xdg_toplevel_request_fullscreen; + wl_signal_add(&toplevel->events.request_fullscreen, + &view->request_fullscreen); } int main(int argc, char *argv[]) { @@ -743,12 +818,21 @@ int main(int argc, char *argv[]) { * backend based on the current environment, such as opening an X11 window * if an X11 server is running. */ server.backend = wlr_backend_autocreate(server.wl_display); + if (server.backend == NULL) { + wlr_log(WLR_ERROR, "failed to create wlr_backend"); + return 1; + } /* Autocreates a renderer, either Pixman, GLES2 or Vulkan for us. The user * can also specify a renderer using the WLR_RENDERER env var. * The renderer is responsible for defining the various pixel formats it * supports for shared memory, this configures that for clients. */ server.renderer = wlr_renderer_autocreate(server.backend); + if (server.renderer == NULL) { + wlr_log(WLR_ERROR, "failed to create wlr_renderer"); + return 1; + } + wlr_renderer_init_wl_display(server.renderer, server.wl_display); /* Autocreates an allocator for us. @@ -757,6 +841,10 @@ int main(int argc, char *argv[]) { * screen */ server.allocator = wlr_allocator_autocreate(server.backend, server.renderer); + if (server.allocator == NULL) { + wlr_log(WLR_ERROR, "failed to create wlr_allocator"); + return 1; + } /* This creates some hands-off wlroots interfaces. The compositor is * necessary for clients to allocate surfaces, the subcompositor allows to @@ -788,13 +876,14 @@ int main(int argc, char *argv[]) { server.scene = wlr_scene_create(); wlr_scene_attach_output_layout(server.scene, server.output_layout); - /* Set up the xdg-shell. The xdg-shell is a Wayland protocol which is used - * for application windows. For more detail on shells, refer to my article: + /* Set up xdg-shell version 3. The xdg-shell is a Wayland protocol which is + * used for application windows. For more detail on shells, refer to my + * article: * * https://drewdevault.com/2018/07/29/Wayland-shells.html */ wl_list_init(&server.views); - server.xdg_shell = wlr_xdg_shell_create(server.wl_display); + server.xdg_shell = wlr_xdg_shell_create(server.wl_display, 3); server.new_xdg_surface.notify = server_new_xdg_surface; wl_signal_add(&server.xdg_shell->events.new_surface, &server.new_xdg_surface); @@ -825,6 +914,7 @@ int main(int argc, char *argv[]) { * * And more comments are sprinkled throughout the notify functions above. */ + server.cursor_mode = TINYWL_CURSOR_PASSTHROUGH; server.cursor_motion.notify = server_cursor_motion; wl_signal_add(&server.cursor->events.motion, &server.cursor_motion); server.cursor_motion_absolute.notify = server_cursor_motion_absolute; diff --git a/types/data_device/wlr_data_device.c b/types/data_device/wlr_data_device.c index ceaf80e72..7e6747905 100644 --- a/types/data_device/wlr_data_device.c +++ b/types/data_device/wlr_data_device.c @@ -9,7 +9,6 @@ #include #include #include "types/wlr_data_device.h" -#include "util/signal.h" #define DATA_DEVICE_MANAGER_VERSION 3 @@ -162,7 +161,7 @@ void wlr_seat_request_set_selection(struct wlr_seat *seat, .source = source, .serial = serial, }; - wlr_signal_emit_safe(&seat->events.request_set_selection, &event); + wl_signal_emit_mutable(&seat->events.request_set_selection, &event); } static void seat_handle_selection_source_destroy( @@ -179,7 +178,7 @@ static void seat_handle_selection_source_destroy( seat_client_send_selection(focused_client); } - wlr_signal_emit_safe(&seat->events.set_selection, seat); + wl_signal_emit_mutable(&seat->events.set_selection, seat); } void wlr_seat_set_selection(struct wlr_seat *seat, @@ -211,7 +210,7 @@ void wlr_seat_set_selection(struct wlr_seat *seat, seat_client_send_selection(focused_client); } - wlr_signal_emit_safe(&seat->events.set_selection, seat); + wl_signal_emit_mutable(&seat->events.set_selection, seat); } @@ -280,7 +279,7 @@ static void data_device_manager_bind(struct wl_client *client, static void handle_display_destroy(struct wl_listener *listener, void *data) { struct wlr_data_device_manager *manager = wl_container_of(listener, manager, display_destroy); - wlr_signal_emit_safe(&manager->events.destroy, manager); + wl_signal_emit_mutable(&manager->events.destroy, manager); wl_list_remove(&manager->display_destroy.link); wl_global_destroy(manager->global); free(manager); diff --git a/types/data_device/wlr_data_offer.c b/types/data_device/wlr_data_offer.c index ce28c6d6e..67552b470 100644 --- a/types/data_device/wlr_data_offer.c +++ b/types/data_device/wlr_data_offer.c @@ -8,7 +8,6 @@ #include #include #include "types/wlr_data_device.h" -#include "util/signal.h" static const struct wl_data_offer_interface data_offer_impl; diff --git a/types/data_device/wlr_data_source.c b/types/data_device/wlr_data_source.c index 1baaac60a..dc9725fb1 100644 --- a/types/data_device/wlr_data_source.c +++ b/types/data_device/wlr_data_source.c @@ -9,12 +9,12 @@ #include #include #include "types/wlr_data_device.h" -#include "util/signal.h" void wlr_data_source_init(struct wlr_data_source *source, const struct wlr_data_source_impl *impl) { assert(impl->send); + memset(source, 0, sizeof(*source)); source->impl = impl; wl_array_init(&source->mime_types); wl_signal_init(&source->events.destroy); @@ -39,7 +39,7 @@ void wlr_data_source_destroy(struct wlr_data_source *source) { return; } - wlr_signal_emit_safe(&source->events.destroy, source); + wl_signal_emit_mutable(&source->events.destroy, source); char **p; wl_array_for_each(p, &source->mime_types) { diff --git a/types/data_device/wlr_drag.c b/types/data_device/wlr_drag.c index 9865d9309..9b48df324 100644 --- a/types/data_device/wlr_drag.c +++ b/types/data_device/wlr_drag.c @@ -9,7 +9,6 @@ #include #include #include "types/wlr_data_device.h" -#include "util/signal.h" static void drag_handle_seat_client_destroy(struct wl_listener *listener, void *data) { @@ -104,16 +103,16 @@ static void drag_set_focus(struct wlr_drag *drag, wl_signal_add(&focus_client->events.destroy, &drag->seat_client_destroy); out: - wlr_signal_emit_safe(&drag->events.focus, drag); + wl_signal_emit_mutable(&drag->events.focus, drag); } static void drag_icon_set_mapped(struct wlr_drag_icon *icon, bool mapped) { if (mapped && !icon->mapped) { icon->mapped = true; - wlr_signal_emit_safe(&icon->events.map, icon); + wl_signal_emit_mutable(&icon->events.map, icon); } else if (!mapped && icon->mapped) { - wlr_signal_emit_safe(&icon->events.unmap, icon); icon->mapped = false; + wl_signal_emit_mutable(&icon->events.unmap, icon); } } @@ -151,7 +150,7 @@ static void drag_destroy(struct wlr_drag *drag) { // to ensure that the wl_data_device.leave is sent before emitting the // signal. This allows e.g. wl_pointer.enter to be sent in the destroy // signal handler. - wlr_signal_emit_safe(&drag->events.destroy, drag); + wl_signal_emit_mutable(&drag->events.destroy, drag); if (drag->source) { wl_list_remove(&drag->source_destroy.link); @@ -188,7 +187,7 @@ static void drag_handle_pointer_motion(struct wlr_seat_pointer_grab *grab, .sx = sx, .sy = sy, }; - wlr_signal_emit_safe(&drag->events.motion, &event); + wl_signal_emit_mutable(&drag->events.motion, &event); } } @@ -209,7 +208,7 @@ static void drag_drop(struct wlr_drag *drag, uint32_t time) { .drag = drag, .time = time, }; - wlr_signal_emit_safe(&drag->events.drop, &event); + wl_signal_emit_mutable(&drag->events.drop, &event); } static uint32_t drag_handle_pointer_button(struct wlr_seat_pointer_grab *grab, @@ -364,7 +363,7 @@ static void drag_icon_destroy(struct wlr_drag_icon *icon) { return; } drag_icon_set_mapped(icon, false); - wlr_signal_emit_safe(&icon->events.destroy, icon); + wl_signal_emit_mutable(&icon->events.destroy, icon); icon->surface->role_data = NULL; wl_list_remove(&icon->surface_destroy.link); free(icon); @@ -480,7 +479,7 @@ void wlr_seat_request_start_drag(struct wlr_seat *seat, struct wlr_drag *drag, .origin = origin, .serial = serial, }; - wlr_signal_emit_safe(&seat->events.request_start_drag, &event); + wl_signal_emit_mutable(&seat->events.request_start_drag, &event); } static void seat_handle_drag_source_destroy(struct wl_listener *listener, @@ -511,7 +510,7 @@ void wlr_seat_start_drag(struct wlr_seat *seat, struct wlr_drag *drag, wl_signal_add(&drag->source->events.destroy, &seat->drag_source_destroy); } - wlr_signal_emit_safe(&seat->events.start_drag, drag); + wl_signal_emit_mutable(&seat->events.start_drag, drag); } void wlr_seat_start_pointer_drag(struct wlr_seat *seat, struct wlr_drag *drag, diff --git a/types/meson.build b/types/meson.build index 315031cea..934311c86 100644 --- a/types/meson.build +++ b/types/meson.build @@ -6,8 +6,10 @@ wlr_files += files( 'output/cursor.c', 'output/output.c', 'output/render.c', + 'output/state.c', 'output/transform.c', 'scene/subsurface_tree.c', + 'scene/surface.c', 'scene/wlr_scene.c', 'scene/output_layout.c', 'scene/xdg_shell.c', @@ -28,6 +30,7 @@ wlr_files += files( 'wlr_buffer.c', 'wlr_compositor.c', 'wlr_cursor.c', + 'wlr_damage_ring.c', 'wlr_data_control_v1.c', 'wlr_drm.c', 'wlr_export_dmabuf_v1.c', @@ -61,6 +64,7 @@ wlr_files += files( 'wlr_screencopy_v1.c', 'wlr_server_decoration.c', 'wlr_session_lock_v1.c', + 'wlr_single_pixel_buffer_v1.c', 'wlr_subcompositor.c', 'wlr_switch.c', 'wlr_tablet_pad.c', diff --git a/types/output/cursor.c b/types/output/cursor.c index f3055c5c4..89f41b772 100644 --- a/types/output/cursor.c +++ b/types/output/cursor.c @@ -8,8 +8,8 @@ #include #include "render/allocator/allocator.h" #include "render/swapchain.h" +#include "types/wlr_buffer.h" #include "types/wlr_output.h" -#include "util/signal.h" static bool output_set_hardware_cursor(struct wlr_output *output, struct wlr_buffer *buffer, int hotspot_x, int hotspot_y) { @@ -167,7 +167,7 @@ static void output_cursor_damage_whole(struct wlr_output_cursor *cursor) { .output = cursor->output, .damage = &damage, }; - wlr_signal_emit_safe(&cursor->output->events.damage, &event); + wl_signal_emit_mutable(&cursor->output->events.damage, &event); pixman_region32_fini(&damage); } @@ -375,28 +375,50 @@ static bool output_cursor_attempt_hardware(struct wlr_output_cursor *cursor) { bool wlr_output_cursor_set_image(struct wlr_output_cursor *cursor, const uint8_t *pixels, int32_t stride, uint32_t width, uint32_t height, int32_t hotspot_x, int32_t hotspot_y) { + struct wlr_buffer *buffer = NULL; + + if (pixels) { + struct wlr_readonly_data_buffer *ro_buffer = readonly_data_buffer_create( + DRM_FORMAT_ARGB8888, stride, width, height, pixels); + if (ro_buffer == NULL) { + return false; + } + buffer = &ro_buffer->base; + } + bool ok = wlr_output_cursor_set_buffer(cursor, buffer, hotspot_x, hotspot_y); + + wlr_buffer_drop(buffer); + return ok; +} + +bool wlr_output_cursor_set_buffer(struct wlr_output_cursor *cursor, + struct wlr_buffer *buffer, int32_t hotspot_x, int32_t hotspot_y) { struct wlr_renderer *renderer = cursor->output->renderer; if (!renderer) { - // if the backend has no renderer, we can't draw a cursor, but this is - // actually okay, for ex. with the noop backend - return true; + return false; } output_cursor_reset(cursor); - cursor->width = width; - cursor->height = height; + if (buffer != NULL) { + cursor->width = buffer->width; + cursor->height = buffer->height; + } else { + cursor->width = 0; + cursor->height = 0; + } + cursor->hotspot_x = hotspot_x; cursor->hotspot_y = hotspot_y; + output_cursor_update_visible(cursor); wlr_texture_destroy(cursor->texture); cursor->texture = NULL; cursor->enabled = false; - if (pixels != NULL) { - cursor->texture = wlr_texture_from_pixels(renderer, - DRM_FORMAT_ARGB8888, stride, width, height, pixels); + if (buffer != NULL) { + cursor->texture = wlr_texture_from_buffer(renderer, buffer); if (cursor->texture == NULL) { return false; } @@ -547,7 +569,6 @@ struct wlr_output_cursor *wlr_output_cursor_create(struct wlr_output *output) { return NULL; } cursor->output = output; - wl_signal_init(&cursor->events.destroy); wl_list_init(&cursor->surface_commit.link); cursor->surface_commit.notify = output_cursor_handle_commit; wl_list_init(&cursor->surface_destroy.link); @@ -562,7 +583,6 @@ void wlr_output_cursor_destroy(struct wlr_output_cursor *cursor) { return; } output_cursor_reset(cursor); - wlr_signal_emit_safe(&cursor->events.destroy, cursor); if (cursor->output->hardware_cursor == cursor) { // If this cursor was the hardware cursor, disable it output_set_hardware_cursor(cursor->output, NULL, 0, 0); diff --git a/types/output/output.c b/types/output/output.c index 5ed7e01d5..287ab683d 100644 --- a/types/output/output.c +++ b/types/output/output.c @@ -10,16 +10,27 @@ #include "render/allocator/allocator.h" #include "render/swapchain.h" #include "types/wlr_output.h" +#include "util/env.h" #include "util/global.h" -#include "util/signal.h" #define OUTPUT_VERSION 4 static void send_geometry(struct wl_resource *resource) { struct wlr_output *output = wlr_output_from_resource(resource); + + const char *make = output->make; + if (make == NULL) { + make = "Unknown"; + } + + const char *model = output->model; + if (model == NULL) { + model = "Unknown"; + } + wl_output_send_geometry(resource, 0, 0, output->phys_width, output->phys_height, output->subpixel, - output->make, output->model, output->transform); + make, model, output->transform); } static void send_current_mode(struct wl_resource *resource) { @@ -113,7 +124,7 @@ static void output_bind(struct wl_client *wl_client, void *data, .resource = resource, }; - wlr_signal_emit_safe(&output->events.bind, &evt); + wl_signal_emit_mutable(&output->events.bind, &evt); } void wlr_output_create_global(struct wlr_output *output) { @@ -176,7 +187,7 @@ void wlr_output_update_enabled(struct wlr_output *output, bool enabled) { } output->enabled = enabled; - wlr_signal_emit_safe(&output->events.enable, output); + wl_signal_emit_mutable(&output->events.enable, output); } static void output_update_matrix(struct wlr_output *output) { @@ -194,52 +205,17 @@ static void output_update_matrix(struct wlr_output *output) { } void wlr_output_enable(struct wlr_output *output, bool enable) { - if (output->enabled == enable) { - output->pending.committed &= ~WLR_OUTPUT_STATE_ENABLED; - return; - } - - output->pending.committed |= WLR_OUTPUT_STATE_ENABLED; - output->pending.enabled = enable; -} - -static void output_state_clear_mode(struct wlr_output_state *state) { - if (!(state->committed & WLR_OUTPUT_STATE_MODE)) { - return; - } - - state->mode = NULL; - - state->committed &= ~WLR_OUTPUT_STATE_MODE; + wlr_output_state_set_enabled(&output->pending, enable); } void wlr_output_set_mode(struct wlr_output *output, struct wlr_output_mode *mode) { - output_state_clear_mode(&output->pending); - - if (output->current_mode == mode) { - return; - } - - output->pending.committed |= WLR_OUTPUT_STATE_MODE; - output->pending.mode_type = WLR_OUTPUT_STATE_MODE_FIXED; - output->pending.mode = mode; + wlr_output_state_set_mode(&output->pending, mode); } void wlr_output_set_custom_mode(struct wlr_output *output, int32_t width, int32_t height, int32_t refresh) { - output_state_clear_mode(&output->pending); - - if (output->width == width && output->height == height && - output->refresh == refresh) { - return; - } - - output->pending.committed |= WLR_OUTPUT_STATE_MODE; - output->pending.mode_type = WLR_OUTPUT_STATE_MODE_CUSTOM; - output->pending.custom_mode.width = width; - output->pending.custom_mode.height = height; - output->pending.custom_mode.refresh = refresh; + wlr_output_state_set_custom_mode(&output->pending, width, height, refresh); } void wlr_output_update_mode(struct wlr_output *output, @@ -279,65 +255,29 @@ void wlr_output_update_custom_mode(struct wlr_output *output, int32_t width, } wlr_output_schedule_done(output); - wlr_signal_emit_safe(&output->events.mode, output); + wl_signal_emit_mutable(&output->events.mode, output); } void wlr_output_set_transform(struct wlr_output *output, enum wl_output_transform transform) { - if (output->transform == transform) { - output->pending.committed &= ~WLR_OUTPUT_STATE_TRANSFORM; - return; - } - - output->pending.committed |= WLR_OUTPUT_STATE_TRANSFORM; - output->pending.transform = transform; + wlr_output_state_set_transform(&output->pending, transform); } void wlr_output_set_scale(struct wlr_output *output, float scale) { - if (output->scale == scale) { - output->pending.committed &= ~WLR_OUTPUT_STATE_SCALE; - return; - } - - output->pending.committed |= WLR_OUTPUT_STATE_SCALE; - output->pending.scale = scale; + wlr_output_state_set_scale(&output->pending, scale); } void wlr_output_enable_adaptive_sync(struct wlr_output *output, bool enabled) { - bool currently_enabled = - output->adaptive_sync_status != WLR_OUTPUT_ADAPTIVE_SYNC_DISABLED; - if (currently_enabled == enabled) { - output->pending.committed &= ~WLR_OUTPUT_STATE_ADAPTIVE_SYNC_ENABLED; - return; - } - - output->pending.committed |= WLR_OUTPUT_STATE_ADAPTIVE_SYNC_ENABLED; - output->pending.adaptive_sync_enabled = enabled; + wlr_output_state_set_adaptive_sync_enabled(&output->pending, enabled); } void wlr_output_set_render_format(struct wlr_output *output, uint32_t format) { - if (output->render_format == format) { - output->pending.committed &= ~WLR_OUTPUT_STATE_RENDER_FORMAT; - return; - } - - output->pending.committed |= WLR_OUTPUT_STATE_RENDER_FORMAT; - output->pending.render_format = format; + wlr_output_state_set_render_format(&output->pending, format); } void wlr_output_set_subpixel(struct wlr_output *output, enum wl_output_subpixel subpixel) { - if (output->subpixel == subpixel) { - return; - } - - output->subpixel = subpixel; - - struct wl_resource *resource; - wl_resource_for_each(resource, &output->resources) { - send_geometry(resource); - } - wlr_output_schedule_done(output); + wlr_output_state_set_subpixel(&output->pending, subpixel); } void wlr_output_set_name(struct wlr_output *output, const char *name) { @@ -366,7 +306,7 @@ void wlr_output_set_description(struct wlr_output *output, const char *desc) { } wlr_output_schedule_done(output); - wlr_signal_emit_safe(&output->events.description, output); + wl_signal_emit_mutable(&output->events.description, output); } static void handle_display_destroy(struct wl_listener *listener, void *data) { @@ -375,12 +315,35 @@ static void handle_display_destroy(struct wl_listener *listener, void *data) { wlr_output_destroy_global(output); } +static void output_state_init(struct wlr_output_state *state) { + memset(state, 0, sizeof(*state)); + pixman_region32_init(&state->damage); +} + +static void output_state_finish(struct wlr_output_state *state) { + wlr_buffer_unlock(state->buffer); + // struct wlr_buffer is ref'counted, so the pointer may remain valid after + // wlr_buffer_unlock(). Reset the field to NULL to ensure nobody mistakenly + // reads it after output_state_finish(). + state->buffer = NULL; + pixman_region32_fini(&state->damage); + free(state->gamma_lut); +} + +static void output_state_move(struct wlr_output_state *dst, + struct wlr_output_state *src) { + *dst = *src; + output_state_init(src); +} + void wlr_output_init(struct wlr_output *output, struct wlr_backend *backend, const struct wlr_output_impl *impl, struct wl_display *display) { assert(impl->commit); if (impl->set_cursor || impl->move_cursor) { assert(impl->set_cursor && impl->move_cursor); } + + memset(output, 0, sizeof(*output)); output->backend = backend; output->impl = impl; output->display = display; @@ -402,13 +365,11 @@ void wlr_output_init(struct wlr_output *output, struct wlr_backend *backend, wl_signal_init(&output->events.mode); wl_signal_init(&output->events.description); wl_signal_init(&output->events.destroy); - pixman_region32_init(&output->pending.damage); + output_state_init(&output->pending); - const char *no_hardware_cursors = getenv("WLR_NO_HARDWARE_CURSORS"); - if (no_hardware_cursors != NULL && strcmp(no_hardware_cursors, "1") == 0) { - wlr_log(WLR_DEBUG, - "WLR_NO_HARDWARE_CURSORS set, forcing software cursors"); - output->software_cursor_locks = 1; + output->software_cursor_locks = env_parse_bool("WLR_NO_HARDWARE_CURSORS"); + if (output->software_cursor_locks) { + wlr_log(WLR_DEBUG, "WLR_NO_HARDWARE_CURSORS set, forcing software cursors"); } wlr_addon_set_init(&output->addons); @@ -426,7 +387,7 @@ void wlr_output_destroy(struct wlr_output *output) { wlr_output_destroy_global(output); output_clear_back_buffer(output); - wlr_signal_emit_safe(&output->events.destroy, output); + wl_signal_emit_mutable(&output->events.destroy, output); wlr_addon_set_finish(&output->addons); // The backend is responsible for free-ing the list of modes @@ -451,8 +412,11 @@ void wlr_output_destroy(struct wlr_output *output) { free(output->name); free(output->description); + free(output->make); + free(output->model); + free(output->serial); - pixman_region32_fini(&output->pending.damage); + output_state_finish(&output->pending); if (output->impl && output->impl->destroy) { output->impl->destroy(output); @@ -526,17 +490,17 @@ static void output_state_clear(struct wlr_output_state *state) { state->committed = 0; } -void output_pending_resolution(struct wlr_output *output, int *width, - int *height) { - if (output->pending.committed & WLR_OUTPUT_STATE_MODE) { - switch (output->pending.mode_type) { +void output_pending_resolution(struct wlr_output *output, + const struct wlr_output_state *state, int *width, int *height) { + if (state->committed & WLR_OUTPUT_STATE_MODE) { + switch (state->mode_type) { case WLR_OUTPUT_STATE_MODE_FIXED: - *width = output->pending.mode->width; - *height = output->pending.mode->height; + *width = state->mode->width; + *height = state->mode->height; return; case WLR_OUTPUT_STATE_MODE_CUSTOM: - *width = output->pending.custom_mode.width; - *height = output->pending.custom_mode.height; + *width = state->custom_mode.width; + *height = state->custom_mode.height; return; } abort(); @@ -546,8 +510,66 @@ void output_pending_resolution(struct wlr_output *output, int *width, } } -static bool output_basic_test(struct wlr_output *output) { - if (output->pending.committed & WLR_OUTPUT_STATE_BUFFER) { +/** + * Compare a struct wlr_output_state with the current state of a struct + * wlr_output. + * + * Returns a bitfield of the unchanged fields. + * + * Some fields are not checked: damage always changes in-between frames, the + * gamma LUT is too expensive to check, the contents of the buffer might have + * changed, etc. + */ +static uint32_t output_compare_state(struct wlr_output *output, + const struct wlr_output_state *state) { + uint32_t fields = 0; + if (state->committed & WLR_OUTPUT_STATE_MODE) { + bool unchanged = false; + switch (state->mode_type) { + case WLR_OUTPUT_STATE_MODE_FIXED: + unchanged = output->current_mode == state->mode; + break; + case WLR_OUTPUT_STATE_MODE_CUSTOM: + unchanged = output->width == state->custom_mode.width && + output->height == state->custom_mode.height && + output->refresh == state->custom_mode.refresh; + break; + } + if (unchanged) { + fields |= WLR_OUTPUT_STATE_MODE; + } + } + if ((state->committed & WLR_OUTPUT_STATE_ENABLED) && output->enabled == state->enabled) { + fields |= WLR_OUTPUT_STATE_ENABLED; + } + if ((state->committed & WLR_OUTPUT_STATE_SCALE) && output->scale == state->scale) { + fields |= WLR_OUTPUT_STATE_SCALE; + } + if ((state->committed & WLR_OUTPUT_STATE_TRANSFORM) && + output->transform == state->transform) { + fields |= WLR_OUTPUT_STATE_TRANSFORM; + } + if (state->committed & WLR_OUTPUT_STATE_ADAPTIVE_SYNC_ENABLED) { + bool enabled = + output->adaptive_sync_status != WLR_OUTPUT_ADAPTIVE_SYNC_DISABLED; + if (enabled == state->adaptive_sync_enabled) { + fields |= WLR_OUTPUT_STATE_ADAPTIVE_SYNC_ENABLED; + } + } + if ((state->committed & WLR_OUTPUT_STATE_RENDER_FORMAT) && + output->render_format == state->render_format) { + fields |= WLR_OUTPUT_STATE_RENDER_FORMAT; + } + if ((state->committed & WLR_OUTPUT_STATE_SUBPIXEL) && + output->subpixel == state->subpixel) { + fields |= WLR_OUTPUT_STATE_SUBPIXEL; + } + return fields; +} + +static bool output_basic_test(struct wlr_output *output, + const struct wlr_output_state *state) { + if (state->committed & WLR_OUTPUT_STATE_BUFFER) { if (output->frame_pending) { wlr_log(WLR_DEBUG, "Tried to commit a buffer while a frame is pending"); return false; @@ -574,23 +596,24 @@ static bool output_basic_test(struct wlr_output *output) { // If the size doesn't match, reject buffer (scaling is not // supported) int pending_width, pending_height; - output_pending_resolution(output, &pending_width, &pending_height); - if (output->pending.buffer->width != pending_width || - output->pending.buffer->height != pending_height) { + output_pending_resolution(output, state, + &pending_width, &pending_height); + if (state->buffer->width != pending_width || + state->buffer->height != pending_height) { wlr_log(WLR_DEBUG, "Direct scan-out buffer size mismatch"); return false; } } } - if (output->pending.committed & WLR_OUTPUT_STATE_RENDER_FORMAT) { + if (state->committed & WLR_OUTPUT_STATE_RENDER_FORMAT) { struct wlr_allocator *allocator = output->allocator; assert(allocator != NULL); const struct wlr_drm_format_set *display_formats = wlr_output_get_primary_formats(output, allocator->buffer_caps); struct wlr_drm_format *format = output_pick_format(output, display_formats, - output->pending.render_format); + state->render_format); if (format == NULL) { wlr_log(WLR_ERROR, "Failed to pick primary buffer format for output"); return false; @@ -600,77 +623,115 @@ static bool output_basic_test(struct wlr_output *output) { } bool enabled = output->enabled; - if (output->pending.committed & WLR_OUTPUT_STATE_ENABLED) { - enabled = output->pending.enabled; + if (state->committed & WLR_OUTPUT_STATE_ENABLED) { + enabled = state->enabled; } - if (enabled && (output->pending.committed & (WLR_OUTPUT_STATE_ENABLED | + if (enabled && (state->committed & (WLR_OUTPUT_STATE_ENABLED | WLR_OUTPUT_STATE_MODE))) { int pending_width, pending_height; - output_pending_resolution(output, &pending_width, &pending_height); + output_pending_resolution(output, state, + &pending_width, &pending_height); if (pending_width == 0 || pending_height == 0) { wlr_log(WLR_DEBUG, "Tried to enable an output with a zero mode"); return false; } } - if (!enabled && output->pending.committed & WLR_OUTPUT_STATE_BUFFER) { + if (!enabled && state->committed & WLR_OUTPUT_STATE_BUFFER) { wlr_log(WLR_DEBUG, "Tried to commit a buffer on a disabled output"); return false; } - if (!enabled && output->pending.committed & WLR_OUTPUT_STATE_MODE) { + if (!enabled && state->committed & WLR_OUTPUT_STATE_MODE) { wlr_log(WLR_DEBUG, "Tried to modeset a disabled output"); return false; } - if (!enabled && output->pending.committed & WLR_OUTPUT_STATE_ADAPTIVE_SYNC_ENABLED) { + if (!enabled && state->committed & WLR_OUTPUT_STATE_ADAPTIVE_SYNC_ENABLED) { wlr_log(WLR_DEBUG, "Tried to enable adaptive sync on a disabled output"); return false; } - if (!enabled && output->pending.committed & WLR_OUTPUT_STATE_RENDER_FORMAT) { + if (!enabled && state->committed & WLR_OUTPUT_STATE_RENDER_FORMAT) { wlr_log(WLR_DEBUG, "Tried to set format for a disabled output"); return false; } - if (!enabled && output->pending.committed & WLR_OUTPUT_STATE_GAMMA_LUT) { + if (!enabled && state->committed & WLR_OUTPUT_STATE_GAMMA_LUT) { wlr_log(WLR_DEBUG, "Tried to set the gamma lut on a disabled output"); return false; } + if (!enabled && state->committed & WLR_OUTPUT_STATE_SUBPIXEL) { + wlr_log(WLR_DEBUG, "Tried to set the subpixel layout on a disabled output"); + return false; + } return true; } -bool wlr_output_test(struct wlr_output *output) { - bool had_buffer = output->pending.committed & WLR_OUTPUT_STATE_BUFFER; - bool success; +bool wlr_output_test_state(struct wlr_output *output, + const struct wlr_output_state *state) { + uint32_t unchanged = output_compare_state(output, state); - if (!output_basic_test(output)) { - return false; - } - if (!output_ensure_buffer(output)) { + // Create a shallow copy of the state with only the fields which have been + // changed and potentially a new buffer. + struct wlr_output_state copy = *state; + copy.committed &= ~unchanged; + + if (!output_basic_test(output, ©)) { return false; } if (!output->impl->test) { return true; } - success = output->impl->test(output); + bool new_back_buffer = false; + if (!output_ensure_buffer(output, ©, &new_back_buffer)) { + return false; + } + if (new_back_buffer) { + assert((copy.committed & WLR_OUTPUT_STATE_BUFFER) == 0); + copy.committed |= WLR_OUTPUT_STATE_BUFFER; + copy.buffer = output->back_buffer; + } - if (!had_buffer) { + bool success = output->impl->test(output, ©); + if (new_back_buffer) { output_clear_back_buffer(output); } return success; } -bool wlr_output_commit(struct wlr_output *output) { - if (!output_basic_test(output)) { +bool wlr_output_test(struct wlr_output *output) { + return wlr_output_test_state(output, &output->pending); +} + +bool wlr_output_commit_state(struct wlr_output *output, + const struct wlr_output_state *state) { + uint32_t unchanged = output_compare_state(output, state); + + // Create a shallow copy of the state with only the fields which have been + // changed and potentially a new buffer. + struct wlr_output_state pending = *state; + pending.committed &= ~unchanged; + + if (!output_basic_test(output, &pending)) { wlr_log(WLR_ERROR, "Basic output test failed for %s", output->name); + output_clear_back_buffer(output); return false; } - if (!output_ensure_buffer(output)) { + bool new_back_buffer = false; + if (!output_ensure_buffer(output, &pending, &new_back_buffer)) { + output_clear_back_buffer(output); return false; } + if (new_back_buffer) { + assert((pending.committed & WLR_OUTPUT_STATE_BUFFER) == 0); + pending.committed |= WLR_OUTPUT_STATE_BUFFER; + // Lock the buffer to ensure it stays valid past the + // output_clear_back_buffer() call below. + pending.buffer = wlr_buffer_lock(output->back_buffer); + } - if ((output->pending.committed & WLR_OUTPUT_STATE_BUFFER) && + if ((pending.committed & WLR_OUTPUT_STATE_BUFFER) && output->idle_frame != NULL) { wl_event_source_remove(output->idle_frame); output->idle_frame = NULL; @@ -682,27 +743,30 @@ bool wlr_output_commit(struct wlr_output *output) { struct wlr_output_event_precommit pre_event = { .output = output, .when = &now, + .state = &pending, }; - wlr_signal_emit_safe(&output->events.precommit, &pre_event); + wl_signal_emit_mutable(&output->events.precommit, &pre_event); // output_clear_back_buffer detaches the buffer from the renderer. This is // important to do before calling impl->commit(), because this marks an // implicit rendering synchronization point. The backend needs it to avoid // displaying a buffer when asynchronous GPU work isn't finished. struct wlr_buffer *back_buffer = NULL; - if ((output->pending.committed & WLR_OUTPUT_STATE_BUFFER) && + if ((pending.committed & WLR_OUTPUT_STATE_BUFFER) && output->back_buffer != NULL) { back_buffer = wlr_buffer_lock(output->back_buffer); output_clear_back_buffer(output); } - if (!output->impl->commit(output)) { + if (!output->impl->commit(output, &pending)) { wlr_buffer_unlock(back_buffer); - output_state_clear(&output->pending); + if (new_back_buffer) { + wlr_buffer_unlock(pending.buffer); + } return false; } - if (output->pending.committed & WLR_OUTPUT_STATE_BUFFER) { + if (pending.committed & WLR_OUTPUT_STATE_BUFFER) { struct wlr_output_cursor *cursor; wl_list_for_each(cursor, &output->cursors, link) { if (!cursor->enabled || !cursor->visible || cursor->surface == NULL) { @@ -712,24 +776,29 @@ bool wlr_output_commit(struct wlr_output *output) { } } - if (output->pending.committed & WLR_OUTPUT_STATE_RENDER_FORMAT) { - output->render_format = output->pending.render_format; + if (pending.committed & WLR_OUTPUT_STATE_RENDER_FORMAT) { + output->render_format = pending.render_format; + } + + if (pending.committed & WLR_OUTPUT_STATE_SUBPIXEL) { + output->subpixel = pending.subpixel; } output->commit_seq++; - bool scale_updated = output->pending.committed & WLR_OUTPUT_STATE_SCALE; + bool scale_updated = pending.committed & WLR_OUTPUT_STATE_SCALE; if (scale_updated) { - output->scale = output->pending.scale; + output->scale = pending.scale; } - if (output->pending.committed & WLR_OUTPUT_STATE_TRANSFORM) { - output->transform = output->pending.transform; + if (pending.committed & WLR_OUTPUT_STATE_TRANSFORM) { + output->transform = pending.transform; output_update_matrix(output); } - bool geometry_updated = output->pending.committed & - (WLR_OUTPUT_STATE_MODE | WLR_OUTPUT_STATE_TRANSFORM); + bool geometry_updated = pending.committed & + (WLR_OUTPUT_STATE_MODE | WLR_OUTPUT_STATE_TRANSFORM | + WLR_OUTPUT_STATE_SUBPIXEL); if (geometry_updated || scale_updated) { struct wl_resource *resource; wl_resource_for_each(resource, &output->resources) { @@ -744,15 +813,14 @@ bool wlr_output_commit(struct wlr_output *output) { } // Destroy the swapchains when an output is disabled - if ((output->pending.committed & WLR_OUTPUT_STATE_ENABLED) && - !output->pending.enabled) { + if ((pending.committed & WLR_OUTPUT_STATE_ENABLED) && !pending.enabled) { wlr_swapchain_destroy(output->swapchain); output->swapchain = NULL; wlr_swapchain_destroy(output->cursor_swapchain); output->cursor_swapchain = NULL; } - if (output->pending.committed & WLR_OUTPUT_STATE_BUFFER) { + if (pending.committed & WLR_OUTPUT_STATE_BUFFER) { output->frame_pending = true; output->needs_frame = false; } @@ -761,34 +829,46 @@ bool wlr_output_commit(struct wlr_output *output) { wlr_swapchain_set_buffer_submitted(output->swapchain, back_buffer); } - uint32_t committed = output->pending.committed; - output_state_clear(&output->pending); - struct wlr_output_event_commit event = { .output = output, - .committed = committed, + .committed = pending.committed, .when = &now, - .buffer = back_buffer, + .buffer = (pending.committed & WLR_OUTPUT_STATE_BUFFER) ? pending.buffer : NULL, }; - wlr_signal_emit_safe(&output->events.commit, &event); + wl_signal_emit_mutable(&output->events.commit, &event); - if (back_buffer != NULL) { - wlr_buffer_unlock(back_buffer); + wlr_buffer_unlock(back_buffer); + if (new_back_buffer) { + wlr_buffer_unlock(pending.buffer); } return true; } +bool wlr_output_commit(struct wlr_output *output) { + // Make sure the pending state is cleared before the output is committed + struct wlr_output_state state = {0}; + output_state_move(&state, &output->pending); + bool ok = wlr_output_commit_state(output, &state); + output_state_finish(&state); + return ok; +} + void wlr_output_rollback(struct wlr_output *output) { output_clear_back_buffer(output); output_state_clear(&output->pending); } +void output_state_attach_buffer(struct wlr_output_state *state, + struct wlr_buffer *buffer) { + output_state_clear_buffer(state); + state->committed |= WLR_OUTPUT_STATE_BUFFER; + state->buffer = wlr_buffer_lock(buffer); +} + void wlr_output_attach_buffer(struct wlr_output *output, struct wlr_buffer *buffer) { - output_state_clear_buffer(&output->pending); - output->pending.committed |= WLR_OUTPUT_STATE_BUFFER; - output->pending.buffer = wlr_buffer_lock(buffer); + output_state_attach_buffer(&output->pending, buffer); } void wlr_output_set_source_box(struct wlr_output *output, @@ -800,7 +880,7 @@ void wlr_output_set_source_box(struct wlr_output *output, void wlr_output_send_frame(struct wlr_output *output) { output->frame_pending = false; if (output->enabled) { - wlr_signal_emit_safe(&output->events.frame, output); + wl_signal_emit_mutable(&output->events.frame, output); } } @@ -846,7 +926,7 @@ void wlr_output_send_present(struct wlr_output *output, event->when = &now; } - wlr_signal_emit_safe(&output->events.present, event); + wl_signal_emit_mutable(&output->events.present, event); } void wlr_output_set_gamma(struct wlr_output *output, size_t size, @@ -878,7 +958,7 @@ void wlr_output_update_needs_frame(struct wlr_output *output) { return; } output->needs_frame = true; - wlr_signal_emit_safe(&output->events.needs_frame, output); + wl_signal_emit_mutable(&output->events.needs_frame, output); } void wlr_output_damage_whole(struct wlr_output *output) { @@ -892,7 +972,7 @@ void wlr_output_damage_whole(struct wlr_output *output) { .output = output, .damage = &damage, }; - wlr_signal_emit_safe(&output->events.damage, &event); + wl_signal_emit_mutable(&output->events.damage, &event); pixman_region32_fini(&damage); } diff --git a/types/output/render.c b/types/output/render.c index 985b93a98..eaacf8a06 100644 --- a/types/output/render.c +++ b/types/output/render.c @@ -44,9 +44,9 @@ bool wlr_output_init_render(struct wlr_output *output, * If set to false, the swapchain's format is guaranteed to not use modifiers. */ static bool output_create_swapchain(struct wlr_output *output, - bool allow_modifiers) { + const struct wlr_output_state *state, bool allow_modifiers) { int width, height; - output_pending_resolution(output, &width, &height); + output_pending_resolution(output, state, &width, &height); struct wlr_allocator *allocator = output->allocator; assert(allocator != NULL); @@ -99,10 +99,10 @@ static bool output_create_swapchain(struct wlr_output *output, } static bool output_attach_back_buffer(struct wlr_output *output, - int *buffer_age) { + const struct wlr_output_state *state, int *buffer_age) { assert(output->back_buffer == NULL); - if (!output_create_swapchain(output, true)) { + if (!output_create_swapchain(output, state, true)) { return false; } @@ -138,23 +138,29 @@ void output_clear_back_buffer(struct wlr_output *output) { output->back_buffer = NULL; } -bool wlr_output_attach_render(struct wlr_output *output, int *buffer_age) { - if (!output_attach_back_buffer(output, buffer_age)) { +static bool output_attach_render(struct wlr_output *output, + struct wlr_output_state *state, int *buffer_age) { + if (!output_attach_back_buffer(output, state, buffer_age)) { return false; } - wlr_output_attach_buffer(output, output->back_buffer); + output_state_attach_buffer(state, output->back_buffer); return true; } -static bool output_attach_empty_buffer(struct wlr_output *output) { - assert(!(output->pending.committed & WLR_OUTPUT_STATE_BUFFER)); +bool wlr_output_attach_render(struct wlr_output *output, int *buffer_age) { + return output_attach_render(output, &output->pending, buffer_age); +} - if (!wlr_output_attach_render(output, NULL)) { +static bool output_attach_empty_back_buffer(struct wlr_output *output, + const struct wlr_output_state *state) { + assert(!(state->committed & WLR_OUTPUT_STATE_BUFFER)); + + if (!output_attach_back_buffer(output, state, NULL)) { return false; } int width, height; - output_pending_resolution(output, &width, &height); + output_pending_resolution(output, state, &width, &height); struct wlr_renderer *renderer = output->renderer; wlr_renderer_begin(renderer, width, height); @@ -164,42 +170,62 @@ static bool output_attach_empty_buffer(struct wlr_output *output) { return true; } -bool output_ensure_buffer(struct wlr_output *output) { +static bool output_test_with_back_buffer(struct wlr_output *output, + const struct wlr_output_state *state) { + assert(output->impl->test != NULL); + + // Create a shallow copy of the state with the empty back buffer included + // to pass to the backend. + struct wlr_output_state copy = *state; + assert((copy.committed & WLR_OUTPUT_STATE_BUFFER) == 0); + copy.committed |= WLR_OUTPUT_STATE_BUFFER; + assert(output->back_buffer != NULL); + copy.buffer = output->back_buffer; + + return output->impl->test(output, ©); +} + +// This function may attach a new, empty back buffer if necessary. +// If so, the new_back_buffer out parameter will be set to true. +bool output_ensure_buffer(struct wlr_output *output, + const struct wlr_output_state *state, + bool *new_back_buffer) { + assert(*new_back_buffer == false); + // If we're lighting up an output or changing its mode, make sure to // provide a new buffer bool needs_new_buffer = false; - if ((output->pending.committed & WLR_OUTPUT_STATE_ENABLED) && - output->pending.enabled) { + if ((state->committed & WLR_OUTPUT_STATE_ENABLED) && state->enabled) { needs_new_buffer = true; } - if (output->pending.committed & WLR_OUTPUT_STATE_MODE) { + if (state->committed & WLR_OUTPUT_STATE_MODE) { needs_new_buffer = true; } - if (output->pending.committed & WLR_OUTPUT_STATE_RENDER_FORMAT) { + if (state->committed & WLR_OUTPUT_STATE_RENDER_FORMAT) { needs_new_buffer = true; } - if (!needs_new_buffer || - (output->pending.committed & WLR_OUTPUT_STATE_BUFFER)) { + if (!needs_new_buffer || (state->committed & WLR_OUTPUT_STATE_BUFFER)) { return true; } // If the backend doesn't necessarily need a new buffer on modeset, don't // bother allocating one. - if (!output->impl->test || output->impl->test(output)) { + if (!output->impl->test || output->impl->test(output, state)) { return true; } wlr_log(WLR_DEBUG, "Attaching empty buffer to output for modeset"); - if (!output_attach_empty_buffer(output)) { - goto error; + if (!output_attach_empty_back_buffer(output, state)) { + return false; } - if (!output->impl->test || output->impl->test(output)) { + + if (output_test_with_back_buffer(output, state)) { + *new_back_buffer = true; return true; } output_clear_back_buffer(output); - output->pending.committed &= ~WLR_OUTPUT_STATE_BUFFER; if (output->swapchain->format->len == 0) { return false; @@ -209,20 +235,28 @@ bool output_ensure_buffer(struct wlr_output *output) { // modifiers to see if that makes a difference. wlr_log(WLR_DEBUG, "Output modeset test failed, retrying without modifiers"); - if (!output_create_swapchain(output, false)) { + if (!output_create_swapchain(output, state, false)) { return false; } - if (!output_attach_empty_buffer(output)) { - goto error; - } - if (!output->impl->test(output)) { - goto error; - } - return true; -error: + if (!output_attach_empty_back_buffer(output, state)) { + goto error_destroy_swapchain; + } + + if (output_test_with_back_buffer(output, state)) { + *new_back_buffer = true; + return true; + } + output_clear_back_buffer(output); - output->pending.committed &= ~WLR_OUTPUT_STATE_BUFFER; + +error_destroy_swapchain: + // Destroy the modifierless swapchain so that the output does not get stuck + // without modifiers. A new swapchain with modifiers will be created when + // needed by output_attach_back_buffer(). + wlr_swapchain_destroy(output->swapchain); + output->swapchain = NULL; + return false; } @@ -291,7 +325,7 @@ uint32_t wlr_output_preferred_read_format(struct wlr_output *output) { return DRM_FORMAT_INVALID; } - if (!output_attach_back_buffer(output, NULL)) { + if (!output_attach_back_buffer(output, &output->pending, NULL)) { return false; } diff --git a/types/output/state.c b/types/output/state.c new file mode 100644 index 000000000..abfe5a647 --- /dev/null +++ b/types/output/state.c @@ -0,0 +1,52 @@ +#include "types/wlr_output.h" + +void wlr_output_state_set_enabled(struct wlr_output_state *state, + bool enabled) { + state->committed |= WLR_OUTPUT_STATE_ENABLED; + state->enabled = enabled; +} + +void wlr_output_state_set_mode(struct wlr_output_state *state, + struct wlr_output_mode *mode) { + state->committed |= WLR_OUTPUT_STATE_MODE; + state->mode_type = WLR_OUTPUT_STATE_MODE_FIXED; + state->mode = mode; +} + +void wlr_output_state_set_custom_mode(struct wlr_output_state *state, + int32_t width, int32_t height, int32_t refresh) { + state->committed |= WLR_OUTPUT_STATE_MODE; + state->mode_type = WLR_OUTPUT_STATE_MODE_CUSTOM; + state->custom_mode.width = width; + state->custom_mode.height = height; + state->custom_mode.refresh = refresh; +} + +void wlr_output_state_set_scale(struct wlr_output_state *state, float scale) { + state->committed |= WLR_OUTPUT_STATE_SCALE; + state->scale = scale; +} + +void wlr_output_state_set_transform(struct wlr_output_state *state, + enum wl_output_transform transform) { + state->committed |= WLR_OUTPUT_STATE_TRANSFORM; + state->transform = transform; +} + +void wlr_output_state_set_adaptive_sync_enabled(struct wlr_output_state *state, + bool enabled) { + state->committed |= WLR_OUTPUT_STATE_ADAPTIVE_SYNC_ENABLED; + state->adaptive_sync_enabled = enabled; +} + +void wlr_output_state_set_render_format(struct wlr_output_state *state, + uint32_t format) { + state->committed |= WLR_OUTPUT_STATE_RENDER_FORMAT; + state->render_format = format; +} + +void wlr_output_state_set_subpixel(struct wlr_output_state *state, + enum wl_output_subpixel subpixel) { + state->committed |= WLR_OUTPUT_STATE_SUBPIXEL; + state->subpixel = subpixel; +} diff --git a/types/scene/layer_shell_v1.c b/types/scene/layer_shell_v1.c index 1c2b6e4ff..229869830 100644 --- a/types/scene/layer_shell_v1.c +++ b/types/scene/layer_shell_v1.c @@ -18,21 +18,21 @@ static void scene_layer_surface_handle_layer_surface_destroy( struct wl_listener *listener, void *data) { struct wlr_scene_layer_surface_v1 *scene_layer_surface = wl_container_of(listener, scene_layer_surface, layer_surface_destroy); - wlr_scene_node_destroy(scene_layer_surface->node); + wlr_scene_node_destroy(&scene_layer_surface->tree->node); } static void scene_layer_surface_handle_layer_surface_map( struct wl_listener *listener, void *data) { struct wlr_scene_layer_surface_v1 *scene_layer_surface = wl_container_of(listener, scene_layer_surface, layer_surface_map); - wlr_scene_node_set_enabled(scene_layer_surface->node, true); + wlr_scene_node_set_enabled(&scene_layer_surface->tree->node, true); } static void scene_layer_surface_handle_layer_surface_unmap( struct wl_listener *listener, void *data) { struct wlr_scene_layer_surface_v1 *scene_layer_surface = wl_container_of(listener, scene_layer_surface, layer_surface_unmap); - wlr_scene_node_set_enabled(scene_layer_surface->node, false); + wlr_scene_node_set_enabled(&scene_layer_surface->tree->node, false); } static void layer_surface_exclusive_zone( @@ -94,7 +94,7 @@ void wlr_scene_layer_surface_v1_configure( if (box.width == 0) { box.x = bounds.x + state->margin.left; box.width = bounds.width - - state->margin.left + state->margin.right; + (state->margin.left + state->margin.right); } else if (state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT && state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT) { box.x = bounds.x + bounds.width/2 -box.width/2; @@ -110,7 +110,7 @@ void wlr_scene_layer_surface_v1_configure( if (box.height == 0) { box.y = bounds.y + state->margin.top; box.height = bounds.height - - state->margin.top + state->margin.bottom; + (state->margin.top + state->margin.bottom); } else if (state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP && state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM) { box.y = bounds.y + bounds.height/2 - box.height/2; @@ -122,16 +122,16 @@ void wlr_scene_layer_surface_v1_configure( box.y = bounds.y + bounds.height/2 - box.height/2; } - wlr_scene_node_set_position(scene_layer_surface->node, box.x, box.y); + wlr_scene_node_set_position(&scene_layer_surface->tree->node, box.x, box.y); wlr_layer_surface_v1_configure(layer_surface, box.width, box.height); - if (state->exclusive_zone > 0) { + if (layer_surface->mapped && state->exclusive_zone > 0) { layer_surface_exclusive_zone(state, usable_area); } } struct wlr_scene_layer_surface_v1 *wlr_scene_layer_surface_v1_create( - struct wlr_scene_node *parent, + struct wlr_scene_tree *parent, struct wlr_layer_surface_v1 *layer_surface) { struct wlr_scene_layer_surface_v1 *scene_layer_surface = calloc(1, sizeof(*scene_layer_surface)); @@ -141,24 +141,23 @@ struct wlr_scene_layer_surface_v1 *wlr_scene_layer_surface_v1_create( scene_layer_surface->layer_surface = layer_surface; - struct wlr_scene_tree *tree = wlr_scene_tree_create(parent); - if (tree == NULL) { + scene_layer_surface->tree = wlr_scene_tree_create(parent); + if (scene_layer_surface->tree == NULL) { free(scene_layer_surface); return NULL; } - scene_layer_surface->node = &tree->node; - struct wlr_scene_node *surface_node = wlr_scene_subsurface_tree_create( - scene_layer_surface->node, layer_surface->surface); - if (surface_node == NULL) { - wlr_scene_node_destroy(scene_layer_surface->node); + struct wlr_scene_tree *surface_tree = wlr_scene_subsurface_tree_create( + scene_layer_surface->tree, layer_surface->surface); + if (surface_tree == NULL) { + wlr_scene_node_destroy(&scene_layer_surface->tree->node); free(scene_layer_surface); return NULL; } scene_layer_surface->tree_destroy.notify = scene_layer_surface_handle_tree_destroy; - wl_signal_add(&scene_layer_surface->node->events.destroy, + wl_signal_add(&scene_layer_surface->tree->node.events.destroy, &scene_layer_surface->tree_destroy); scene_layer_surface->layer_surface_destroy.notify = @@ -176,7 +175,7 @@ struct wlr_scene_layer_surface_v1 *wlr_scene_layer_surface_v1_create( wl_signal_add(&layer_surface->events.unmap, &scene_layer_surface->layer_surface_unmap); - wlr_scene_node_set_enabled(scene_layer_surface->node, + wlr_scene_node_set_enabled(&scene_layer_surface->tree->node, layer_surface->mapped); return scene_layer_surface; diff --git a/types/scene/output_layout.c b/types/scene/output_layout.c index 33dac1303..1d1484ad1 100644 --- a/types/scene/output_layout.c +++ b/types/scene/output_layout.c @@ -6,36 +6,58 @@ struct wlr_scene_output_layout { struct wlr_output_layout *layout; struct wlr_scene *scene; + struct wl_list outputs; // wlr_scene_output_layout_output.link + struct wl_listener layout_add; struct wl_listener layout_change; struct wl_listener layout_destroy; struct wl_listener scene_destroy; }; -static void scene_output_layout_destroy(struct wlr_scene_output_layout *sol) { - wl_list_remove(&sol->layout_destroy.link); - wl_list_remove(&sol->layout_add.link); - wl_list_remove(&sol->layout_change.link); - wl_list_remove(&sol->scene_destroy.link); - free(sol); +struct wlr_scene_output_layout_output { + struct wlr_output_layout_output *layout_output; + struct wlr_scene_output *scene_output; + + struct wl_list link; // wlr_scene_output_layout.outputs + + struct wl_listener layout_output_destroy; + struct wl_listener scene_output_destroy; +}; + +static void scene_output_layout_output_destroy( + struct wlr_scene_output_layout_output *solo) { + wl_list_remove(&solo->layout_output_destroy.link); + wl_list_remove(&solo->scene_output_destroy.link); + wl_list_remove(&solo->link); + wlr_scene_output_destroy(solo->scene_output); + free(solo); } -static void scene_output_layout_handle_layout_destroy( +static void scene_output_layout_output_handle_layout_output_destroy( struct wl_listener *listener, void *data) { - struct wlr_scene_output_layout *sol = - wl_container_of(listener, sol, layout_destroy); + struct wlr_scene_output_layout_output *solo = + wl_container_of(listener, solo, layout_output_destroy); + scene_output_layout_output_destroy(solo); +} - // Remove all outputs managed by the output layout - struct wlr_scene_output *scene_output, *tmp; - wl_list_for_each_safe(scene_output, tmp, &sol->scene->outputs, link) { - struct wlr_output_layout_output *lo = - wlr_output_layout_get(sol->layout, scene_output->output); - if (lo != NULL) { - wlr_scene_output_destroy(scene_output); - } +static void scene_output_layout_output_handle_scene_output_destroy( + struct wl_listener *listener, void *data) { + struct wlr_scene_output_layout_output *solo = + wl_container_of(listener, solo, scene_output_destroy); + solo->scene_output = NULL; + scene_output_layout_output_destroy(solo); +} + +static void scene_output_layout_destroy(struct wlr_scene_output_layout *sol) { + struct wlr_scene_output_layout_output *solo, *tmp; + wl_list_for_each_safe(solo, tmp, &sol->outputs, link) { + scene_output_layout_output_destroy(solo); } - - scene_output_layout_destroy(sol); + wl_list_remove(&sol->layout_add.link); + wl_list_remove(&sol->layout_change.link); + wl_list_remove(&sol->layout_destroy.link); + wl_list_remove(&sol->scene_destroy.link); + free(sol); } static void scene_output_layout_handle_layout_change( @@ -43,33 +65,56 @@ static void scene_output_layout_handle_layout_change( struct wlr_scene_output_layout *sol = wl_container_of(listener, sol, layout_change); - struct wlr_scene_output *scene_output, *tmp; - wl_list_for_each_safe(scene_output, tmp, &sol->scene->outputs, link) { - struct wlr_output_layout_output *lo = - wlr_output_layout_get(sol->layout, scene_output->output); - if (lo == NULL) { - // Output has been removed from the layout - wlr_scene_output_destroy(scene_output); - continue; - } - - wlr_scene_output_set_position(scene_output, lo->x, lo->y); + struct wlr_scene_output_layout_output *solo; + wl_list_for_each(solo, &sol->outputs, link) { + wlr_scene_output_set_position(solo->scene_output, + solo->layout_output->x, solo->layout_output->y); } } +static void scene_output_layout_add(struct wlr_scene_output_layout *sol, + struct wlr_output_layout_output *lo) { + struct wlr_scene_output_layout_output *solo = calloc(1, sizeof(*solo)); + if (solo == NULL) { + return; + } + + solo->scene_output = wlr_scene_output_create(sol->scene, lo->output); + if (solo->scene_output == NULL) { + free(solo); + return; + } + + solo->layout_output = lo; + + solo->layout_output_destroy.notify = + scene_output_layout_output_handle_layout_output_destroy; + wl_signal_add(&lo->events.destroy, &solo->layout_output_destroy); + + solo->scene_output_destroy.notify = + scene_output_layout_output_handle_scene_output_destroy; + wl_signal_add(&solo->scene_output->events.destroy, + &solo->scene_output_destroy); + + wl_list_insert(&sol->outputs, &solo->link); + + wlr_scene_output_set_position(solo->scene_output, lo->x, lo->y); +} + static void scene_output_layout_handle_layout_add( struct wl_listener *listener, void *data) { struct wlr_scene_output_layout *sol = wl_container_of(listener, sol, layout_add); struct wlr_output_layout_output *lo = data; - struct wlr_scene_output *scene_output = - wlr_scene_output_create(sol->scene, lo->output); - if (scene_output == NULL) { - return; - } + scene_output_layout_add(sol, lo); +} - wlr_scene_output_set_position(scene_output, lo->x, lo->y); +static void scene_output_layout_handle_layout_destroy( + struct wl_listener *listener, void *data) { + struct wlr_scene_output_layout *sol = + wl_container_of(listener, sol, layout_destroy); + scene_output_layout_destroy(sol); } static void scene_output_layout_handle_scene_destroy( @@ -89,6 +134,8 @@ bool wlr_scene_attach_output_layout(struct wlr_scene *scene, sol->scene = scene; sol->layout = output_layout; + wl_list_init(&sol->outputs); + sol->layout_destroy.notify = scene_output_layout_handle_layout_destroy; wl_signal_add(&output_layout->events.destroy, &sol->layout_destroy); @@ -99,7 +146,12 @@ bool wlr_scene_attach_output_layout(struct wlr_scene *scene, wl_signal_add(&output_layout->events.add, &sol->layout_add); sol->scene_destroy.notify = scene_output_layout_handle_scene_destroy; - wl_signal_add(&output_layout->events.destroy, &sol->scene_destroy); + wl_signal_add(&scene->tree.node.events.destroy, &sol->scene_destroy); + + struct wlr_output_layout_output *lo; + wl_list_for_each(lo, &output_layout->outputs, link) { + scene_output_layout_add(sol, lo); + } return true; } diff --git a/types/scene/subsurface_tree.c b/types/scene/subsurface_tree.c index 8384db8fb..35420abe4 100644 --- a/types/scene/subsurface_tree.c +++ b/types/scene/subsurface_tree.c @@ -81,9 +81,9 @@ static void subsurface_tree_reconfigure( } if (prev != NULL) { - wlr_scene_node_place_above(&subsurface_tree->scene_surface->node, prev); + wlr_scene_node_place_above(&subsurface_tree->scene_surface->buffer->node, prev); } - prev = &subsurface_tree->scene_surface->node; + prev = &subsurface_tree->scene_surface->buffer->node; wl_list_for_each(subsurface, &surface->current.subsurfaces_above, current.link) { @@ -148,13 +148,13 @@ static const struct wlr_addon_interface subsurface_tree_addon_impl = { }; static struct wlr_scene_subsurface_tree *scene_surface_tree_create( - struct wlr_scene_node *parent, struct wlr_surface *surface); + struct wlr_scene_tree *parent, struct wlr_surface *surface); static bool subsurface_tree_create_subsurface( struct wlr_scene_subsurface_tree *parent, struct wlr_subsurface *subsurface) { struct wlr_scene_subsurface_tree *child = scene_surface_tree_create( - &parent->tree->node, subsurface->surface); + parent->tree, subsurface->surface); if (child == NULL) { return false; } @@ -188,7 +188,7 @@ static void subsurface_tree_handle_surface_new_subsurface( } static struct wlr_scene_subsurface_tree *scene_surface_tree_create( - struct wlr_scene_node *parent, struct wlr_surface *surface) { + struct wlr_scene_tree *parent, struct wlr_surface *surface) { struct wlr_scene_subsurface_tree *subsurface_tree = calloc(1, sizeof(*subsurface_tree)); if (subsurface_tree == NULL) { @@ -201,7 +201,7 @@ static struct wlr_scene_subsurface_tree *scene_surface_tree_create( } subsurface_tree->scene_surface = - wlr_scene_surface_create(&subsurface_tree->tree->node, surface); + wlr_scene_surface_create(subsurface_tree->tree, surface); if (subsurface_tree->scene_surface == NULL) { goto error_scene_surface; } @@ -248,12 +248,12 @@ error_surface_tree: return NULL; } -struct wlr_scene_node *wlr_scene_subsurface_tree_create( - struct wlr_scene_node *parent, struct wlr_surface *surface) { +struct wlr_scene_tree *wlr_scene_subsurface_tree_create( + struct wlr_scene_tree *parent, struct wlr_surface *surface) { struct wlr_scene_subsurface_tree *subsurface_tree = scene_surface_tree_create(parent, surface); if (subsurface_tree == NULL) { return NULL; } - return &subsurface_tree->tree->node; + return subsurface_tree->tree; } diff --git a/types/scene/surface.c b/types/scene/surface.c new file mode 100644 index 000000000..b122d210d --- /dev/null +++ b/types/scene/surface.c @@ -0,0 +1,181 @@ +#include +#include +#include +#include "types/wlr_scene.h" + +static void handle_scene_buffer_output_enter( + struct wl_listener *listener, void *data) { + struct wlr_scene_surface *surface = + wl_container_of(listener, surface, output_enter); + struct wlr_scene_output *output = data; + + wlr_surface_send_enter(surface->surface, output->output); +} + +static void handle_scene_buffer_output_leave( + struct wl_listener *listener, void *data) { + struct wlr_scene_surface *surface = + wl_container_of(listener, surface, output_leave); + struct wlr_scene_output *output = data; + + wlr_surface_send_leave(surface->surface, output->output); +} + +static void handle_scene_buffer_output_present( + struct wl_listener *listener, void *data) { + struct wlr_scene_surface *surface = + wl_container_of(listener, surface, output_present); + struct wlr_scene_output *scene_output = data; + + if (surface->buffer->primary_output == scene_output) { + struct wlr_scene *root = scene_node_get_root(&surface->buffer->node); + struct wlr_presentation *presentation = root->presentation; + + if (presentation) { + wlr_presentation_surface_sampled_on_output( + presentation, surface->surface, scene_output->output); + } + } +} + +static void handle_scene_buffer_frame_done( + struct wl_listener *listener, void *data) { + struct wlr_scene_surface *surface = + wl_container_of(listener, surface, frame_done); + struct timespec *now = data; + + wlr_surface_send_frame_done(surface->surface, now); +} + +static void scene_surface_handle_surface_destroy( + struct wl_listener *listener, void *data) { + struct wlr_scene_surface *surface = + wl_container_of(listener, surface, surface_destroy); + + wlr_scene_node_destroy(&surface->buffer->node); +} + +static void set_buffer_with_surface_state(struct wlr_scene_buffer *scene_buffer, + struct wlr_surface *surface) { + struct wlr_surface_state *state = &surface->current; + + wlr_scene_buffer_set_opaque_region(scene_buffer, &surface->opaque_region); + + struct wlr_fbox src_box; + wlr_surface_get_buffer_source_box(surface, &src_box); + wlr_scene_buffer_set_source_box(scene_buffer, &src_box); + + wlr_scene_buffer_set_dest_size(scene_buffer, state->width, state->height); + wlr_scene_buffer_set_transform(scene_buffer, state->transform); + + if (surface->buffer) { + wlr_scene_buffer_set_buffer_with_damage(scene_buffer, + &surface->buffer->base, &surface->buffer_damage); + } else { + wlr_scene_buffer_set_buffer(scene_buffer, NULL); + } +} + +static void handle_scene_surface_surface_commit( + struct wl_listener *listener, void *data) { + struct wlr_scene_surface *surface = + wl_container_of(listener, surface, surface_commit); + struct wlr_scene_buffer *scene_buffer = surface->buffer; + + set_buffer_with_surface_state(scene_buffer, surface->surface); + + // Even if the surface hasn't submitted damage, schedule a new frame if + // the client has requested a wl_surface.frame callback. Check if the node + // is visible. If not, the client will never receive a frame_done event + // anyway so it doesn't make sense to schedule here. + int lx, ly; + bool enabled = wlr_scene_node_coords(&scene_buffer->node, &lx, &ly); + + if (!wl_list_empty(&surface->surface->current.frame_callback_list) && + surface->buffer->primary_output != NULL && enabled) { + wlr_output_schedule_frame(surface->buffer->primary_output->output); + } +} + +static bool scene_buffer_point_accepts_input(struct wlr_scene_buffer *scene_buffer, + int sx, int sy) { + struct wlr_scene_surface *scene_surface = + wlr_scene_surface_from_buffer(scene_buffer); + + return wlr_surface_point_accepts_input(scene_surface->surface, sx, sy); +} + +static void surface_addon_destroy(struct wlr_addon *addon) { + struct wlr_scene_surface *surface = wl_container_of(addon, surface, addon); + + wlr_addon_finish(&surface->addon); + + wl_list_remove(&surface->output_enter.link); + wl_list_remove(&surface->output_leave.link); + wl_list_remove(&surface->output_present.link); + wl_list_remove(&surface->frame_done.link); + wl_list_remove(&surface->surface_destroy.link); + wl_list_remove(&surface->surface_commit.link); + + free(surface); +} + +static const struct wlr_addon_interface surface_addon_impl = { + .name = "wlr_scene_surface", + .destroy = surface_addon_destroy, +}; + +struct wlr_scene_surface *wlr_scene_surface_from_buffer( + struct wlr_scene_buffer *scene_buffer) { + struct wlr_addon *addon = wlr_addon_find(&scene_buffer->node.addons, + scene_buffer, &surface_addon_impl); + if (!addon) { + return NULL; + } + + struct wlr_scene_surface *surface = wl_container_of(addon, surface, addon); + return surface; +} + +struct wlr_scene_surface *wlr_scene_surface_create(struct wlr_scene_tree *parent, + struct wlr_surface *wlr_surface) { + struct wlr_scene_surface *surface = calloc(1, sizeof(*surface)); + if (surface == NULL) { + return NULL; + } + + struct wlr_scene_buffer *scene_buffer = wlr_scene_buffer_create(parent, NULL); + if (!scene_buffer) { + free(surface); + return NULL; + } + + surface->buffer = scene_buffer; + surface->surface = wlr_surface; + scene_buffer->point_accepts_input = scene_buffer_point_accepts_input; + + surface->output_enter.notify = handle_scene_buffer_output_enter; + wl_signal_add(&scene_buffer->events.output_enter, &surface->output_enter); + + surface->output_leave.notify = handle_scene_buffer_output_leave; + wl_signal_add(&scene_buffer->events.output_leave, &surface->output_leave); + + surface->output_present.notify = handle_scene_buffer_output_present; + wl_signal_add(&scene_buffer->events.output_present, &surface->output_present); + + surface->frame_done.notify = handle_scene_buffer_frame_done; + wl_signal_add(&scene_buffer->events.frame_done, &surface->frame_done); + + surface->surface_destroy.notify = scene_surface_handle_surface_destroy; + wl_signal_add(&wlr_surface->events.destroy, &surface->surface_destroy); + + surface->surface_commit.notify = handle_scene_surface_surface_commit; + wl_signal_add(&wlr_surface->events.commit, &surface->surface_commit); + + wlr_addon_init(&surface->addon, &scene_buffer->node.addons, + scene_buffer, &surface_addon_impl); + + set_buffer_with_surface_state(scene_buffer, wlr_surface); + + return surface; +} diff --git a/types/scene/wlr_scene.c b/types/scene/wlr_scene.c index 5d5ff9657..d963e70a2 100644 --- a/types/scene/wlr_scene.c +++ b/types/scene/wlr_scene.c @@ -1,141 +1,143 @@ +#define _POSIX_C_SOURCE 200809L #include #include #include #include #include #include +#include #include -#include #include #include #include #include -#include "util/signal.h" +#include "types/wlr_buffer.h" +#include "types/wlr_scene.h" +#include "util/array.h" +#include "util/env.h" +#include "util/time.h" -static struct wlr_scene *scene_root_from_node(struct wlr_scene_node *node) { - assert(node->type == WLR_SCENE_NODE_ROOT); - return (struct wlr_scene *)node; -} +#define HIGHLIGHT_DAMAGE_FADEOUT_TIME 250 static struct wlr_scene_tree *scene_tree_from_node(struct wlr_scene_node *node) { assert(node->type == WLR_SCENE_NODE_TREE); return (struct wlr_scene_tree *)node; } -struct wlr_scene_surface *wlr_scene_surface_from_node( - struct wlr_scene_node *node) { - assert(node->type == WLR_SCENE_NODE_SURFACE); - return (struct wlr_scene_surface *)node; -} - static struct wlr_scene_rect *scene_rect_from_node( struct wlr_scene_node *node) { assert(node->type == WLR_SCENE_NODE_RECT); return (struct wlr_scene_rect *)node; } -static struct wlr_scene_buffer *scene_buffer_from_node( +struct wlr_scene_buffer *wlr_scene_buffer_from_node( struct wlr_scene_node *node) { assert(node->type == WLR_SCENE_NODE_BUFFER); return (struct wlr_scene_buffer *)node; } -static struct wlr_scene *scene_node_get_root(struct wlr_scene_node *node) { - while (node->parent != NULL) { - node = node->parent; +struct wlr_scene *scene_node_get_root(struct wlr_scene_node *node) { + struct wlr_scene_tree *tree; + if (node->type == WLR_SCENE_NODE_TREE) { + tree = scene_tree_from_node(node); + } else { + tree = node->parent; } - return scene_root_from_node(node); -} -static void scene_node_state_init(struct wlr_scene_node_state *state) { - wl_list_init(&state->children); - wl_list_init(&state->link); - state->enabled = true; -} - -static void scene_node_state_finish(struct wlr_scene_node_state *state) { - wl_list_remove(&state->link); + while (tree->node.parent != NULL) { + tree = tree->node.parent; + } + return (struct wlr_scene *)tree; } static void scene_node_init(struct wlr_scene_node *node, - enum wlr_scene_node_type type, struct wlr_scene_node *parent) { - assert(type == WLR_SCENE_NODE_ROOT || parent != NULL); - + enum wlr_scene_node_type type, struct wlr_scene_tree *parent) { + memset(node, 0, sizeof(*node)); node->type = type; node->parent = parent; - scene_node_state_init(&node->state); + node->enabled = true; + + wl_list_init(&node->link); + wl_signal_init(&node->events.destroy); + pixman_region32_init(&node->visible); if (parent != NULL) { - wl_list_insert(parent->state.children.prev, &node->state.link); - } -} - -static void scene_node_finish(struct wlr_scene_node *node) { - wlr_signal_emit_safe(&node->events.destroy, NULL); - - struct wlr_scene_node *child, *child_tmp; - wl_list_for_each_safe(child, child_tmp, - &node->state.children, state.link) { - wlr_scene_node_destroy(child); + wl_list_insert(parent->children.prev, &node->link); } - scene_node_state_finish(&node->state); + wlr_addon_set_init(&node->addons); } -static void scene_node_damage_whole(struct wlr_scene_node *node); +struct highlight_region { + pixman_region32_t region; + struct timespec when; + struct wl_list link; +}; void wlr_scene_node_destroy(struct wlr_scene_node *node) { if (node == NULL) { return; } - scene_node_damage_whole(node); - scene_node_finish(node); + // We want to call the destroy listeners before we do anything else + // in case the destroy signal would like to remove children before they + // are recursively destroyed. + wl_signal_emit_mutable(&node->events.destroy, NULL); + + wlr_scene_node_set_enabled(node, false); struct wlr_scene *scene = scene_node_get_root(node); - struct wlr_scene_output *scene_output; - switch (node->type) { - case WLR_SCENE_NODE_ROOT:; - struct wlr_scene_output *scene_output_tmp; - wl_list_for_each_safe(scene_output, scene_output_tmp, &scene->outputs, link) { - wlr_scene_output_destroy(scene_output); + if (node->type == WLR_SCENE_NODE_BUFFER) { + struct wlr_scene_buffer *scene_buffer = wlr_scene_buffer_from_node(node); + + uint64_t active = scene_buffer->active_outputs; + if (active) { + struct wlr_scene_output *scene_output; + wl_list_for_each(scene_output, &scene->outputs, link) { + if (active & (1ull << scene_output->index)) { + wl_signal_emit_mutable(&scene_buffer->events.output_leave, + scene_output); + } + } } - wl_list_remove(&scene->presentation_destroy.link); - - free(scene); - break; - case WLR_SCENE_NODE_TREE:; - struct wlr_scene_tree *tree = scene_tree_from_node(node); - free(tree); - break; - case WLR_SCENE_NODE_SURFACE:; - struct wlr_scene_surface *scene_surface = wlr_scene_surface_from_node(node); - - wl_list_for_each(scene_output, &scene->outputs, link) { - // This is a noop if wlr_surface_send_enter() wasn't previously called for - // the given output. - wlr_surface_send_leave(scene_surface->surface, scene_output->output); - } - - wl_list_remove(&scene_surface->surface_commit.link); - wl_list_remove(&scene_surface->surface_destroy.link); - - free(scene_surface); - break; - case WLR_SCENE_NODE_RECT:; - struct wlr_scene_rect *scene_rect = scene_rect_from_node(node); - free(scene_rect); - break; - case WLR_SCENE_NODE_BUFFER:; - struct wlr_scene_buffer *scene_buffer = scene_buffer_from_node(node); - wl_list_remove(&scene_buffer->pending_link); wlr_texture_destroy(scene_buffer->texture); wlr_buffer_unlock(scene_buffer->buffer); - free(scene_buffer); - break; + pixman_region32_fini(&scene_buffer->opaque_region); + } else if (node->type == WLR_SCENE_NODE_TREE) { + struct wlr_scene_tree *scene_tree = scene_tree_from_node(node); + + if (scene_tree == &scene->tree) { + assert(!node->parent); + struct wlr_scene_output *scene_output, *scene_output_tmp; + wl_list_for_each_safe(scene_output, scene_output_tmp, &scene->outputs, link) { + wlr_scene_output_destroy(scene_output); + } + + wl_list_remove(&scene->presentation_destroy.link); + } else { + assert(node->parent); + } + + struct wlr_scene_node *child, *child_tmp; + wl_list_for_each_safe(child, child_tmp, + &scene_tree->children, link) { + wlr_scene_node_destroy(child); + } } + + wlr_addon_set_finish(&node->addons); + wl_list_remove(&node->link); + pixman_region32_fini(&node->visible); + free(node); +} + +static void scene_tree_init(struct wlr_scene_tree *tree, + struct wlr_scene_tree *parent) { + memset(tree, 0, sizeof(*tree)); + scene_node_init(&tree->node, WLR_SCENE_NODE_TREE, parent); + wl_list_init(&tree->children); } struct wlr_scene *wlr_scene_create(void) { @@ -143,49 +145,174 @@ struct wlr_scene *wlr_scene_create(void) { if (scene == NULL) { return NULL; } - scene_node_init(&scene->node, WLR_SCENE_NODE_ROOT, NULL); + + scene_tree_init(&scene->tree, NULL); + wl_list_init(&scene->outputs); wl_list_init(&scene->presentation_destroy.link); - wl_list_init(&scene->pending_buffers); + + const char *debug_damage_options[] = { + "none", + "rerender", + "highlight", + NULL + }; + + scene->debug_damage_option = env_parse_switch("WLR_SCENE_DEBUG_DAMAGE", debug_damage_options); + scene->direct_scanout = !env_parse_bool("WLR_SCENE_DISABLE_DIRECT_SCANOUT"); + scene->calculate_visibility = !env_parse_bool("WLR_SCENE_DISABLE_VISIBILITY"); + return scene; } -struct wlr_scene_tree *wlr_scene_tree_create(struct wlr_scene_node *parent) { +struct wlr_scene_tree *wlr_scene_tree_create(struct wlr_scene_tree *parent) { + assert(parent); + struct wlr_scene_tree *tree = calloc(1, sizeof(struct wlr_scene_tree)); if (tree == NULL) { return NULL; } - scene_node_init(&tree->node, WLR_SCENE_NODE_TREE, parent); + scene_tree_init(tree, parent); return tree; } -static void scene_surface_handle_surface_destroy(struct wl_listener *listener, - void *data) { - struct wlr_scene_surface *scene_surface = - wl_container_of(listener, scene_surface, surface_destroy); - wlr_scene_node_destroy(&scene_surface->node); +static void scene_node_get_size(struct wlr_scene_node *node, int *lx, int *ly); + +typedef bool (*scene_node_box_iterator_func_t)(struct wlr_scene_node *node, + int sx, int sy, void *data); + +static bool _scene_nodes_in_box(struct wlr_scene_node *node, struct wlr_box *box, + scene_node_box_iterator_func_t iterator, void *user_data, int lx, int ly) { + if (!node->enabled) { + return false; + } + + switch (node->type) { + case WLR_SCENE_NODE_TREE:; + struct wlr_scene_tree *scene_tree = scene_tree_from_node(node); + struct wlr_scene_node *child; + wl_list_for_each_reverse(child, &scene_tree->children, link) { + if (_scene_nodes_in_box(child, box, iterator, user_data, lx + child->x, ly + child->y)) { + return true; + } + } + break; + case WLR_SCENE_NODE_RECT: + case WLR_SCENE_NODE_BUFFER:; + struct wlr_box node_box = { .x = lx, .y = ly }; + scene_node_get_size(node, &node_box.width, &node_box.height); + + if (wlr_box_intersection(&node_box, &node_box, box) && + iterator(node, lx, ly, user_data)) { + return true; + } + break; + } + + return false; } -// This function must be called whenever the coordinates/dimensions of a scene -// surface or scene output change. It is not necessary to call when a scene -// surface's node is enabled/disabled or obscured by other nodes. To quote the -// protocol: "The surface might be hidden even if no leave event has been sent." -static void scene_surface_update_outputs( - struct wlr_scene_surface *scene_surface, - int lx, int ly, struct wlr_scene *scene) { - struct wlr_box surface_box = { - .x = lx, - .y = ly, - .width = scene_surface->surface->current.width, - .height = scene_surface->surface->current.height, - }; +static bool scene_nodes_in_box(struct wlr_scene_node *node, struct wlr_box *box, + scene_node_box_iterator_func_t iterator, void *user_data) { + int x, y; + wlr_scene_node_coords(node, &x, &y); - int largest_overlap = 0; - scene_surface->primary_output = NULL; + return _scene_nodes_in_box(node, box, iterator, user_data, x, y); +} + +static void scene_node_opaque_region(struct wlr_scene_node *node, int x, int y, + pixman_region32_t *opaque) { + if (node->type == WLR_SCENE_NODE_RECT) { + struct wlr_scene_rect *scene_rect = scene_rect_from_node(node); + if (scene_rect->color[3] != 1) { + return; + } + } else if (node->type == WLR_SCENE_NODE_BUFFER) { + struct wlr_scene_buffer *scene_buffer = wlr_scene_buffer_from_node(node); + + if (!scene_buffer->buffer) { + return; + } + + if (!buffer_is_opaque(scene_buffer->buffer)) { + pixman_region32_copy(opaque, &scene_buffer->opaque_region); + pixman_region32_translate(opaque, x, y); + return; + } + } + + int width, height; + scene_node_get_size(node, &width, &height); + pixman_region32_fini(opaque); + pixman_region32_init_rect(opaque, x, y, width, height); +} + +struct scene_update_data { + pixman_region32_t *visible; + pixman_region32_t *update_region; + struct wl_list *outputs; + bool calculate_visibility; +}; + +static uint32_t region_area(pixman_region32_t *region) { + uint32_t area = 0; + + int nrects; + pixman_box32_t *rects = pixman_region32_rectangles(region, &nrects); + for (int i = 0; i < nrects; ++i) { + area += (rects[i].x2 - rects[i].x1) * (rects[i].y2 - rects[i].y1); + } + + return area; +} + +static void scene_damage_outputs(struct wlr_scene *scene, pixman_region32_t *damage) { + if (!pixman_region32_not_empty(damage)) { + return; + } struct wlr_scene_output *scene_output; wl_list_for_each(scene_output, &scene->outputs, link) { + pixman_region32_t output_damage; + pixman_region32_init(&output_damage); + pixman_region32_copy(&output_damage, damage); + pixman_region32_translate(&output_damage, + -scene_output->x, -scene_output->y); + wlr_region_scale(&output_damage, &output_damage, + scene_output->output->scale); + if (wlr_damage_ring_add(&scene_output->damage_ring, &output_damage)) { + wlr_output_schedule_frame(scene_output->output); + } + pixman_region32_fini(&output_damage); + } +} + +static void update_node_update_outputs(struct wlr_scene_node *node, + struct wl_list *outputs, struct wlr_scene_output *ignore) { + if (node->type != WLR_SCENE_NODE_BUFFER) { + return; + } + + struct wlr_scene_buffer *scene_buffer = wlr_scene_buffer_from_node(node); + + int largest_overlap = 0; + scene_buffer->primary_output = NULL; + + uint64_t active_outputs = 0; + + // let's update the outputs in two steps: + // - the primary outputs + // - the enter/leave signals + // This ensures that the enter/leave signals can rely on the primary output + // to have a reasonable value. Otherwise, they may get a value that's in + // the middle of a calculation. + struct wlr_scene_output *scene_output; + wl_list_for_each(scene_output, outputs, link) { + if (scene_output == ignore) { + continue; + } + struct wlr_box output_box = { .x = scene_output->x, .y = scene_output->y, @@ -193,139 +320,180 @@ static void scene_surface_update_outputs( wlr_output_effective_resolution(scene_output->output, &output_box.width, &output_box.height); - struct wlr_box intersection; - if (wlr_box_intersection(&intersection, &surface_box, &output_box)) { - int overlap = intersection.width * intersection.height; + pixman_region32_t intersection; + pixman_region32_init(&intersection); + pixman_region32_intersect_rect(&intersection, &node->visible, + output_box.x, output_box.y, output_box.width, output_box.height); + + if (pixman_region32_not_empty(&intersection)) { + int overlap = region_area(&intersection); if (overlap > largest_overlap) { largest_overlap = overlap; - scene_surface->primary_output = scene_output->output; + scene_buffer->primary_output = scene_output; } - // These enter/leave functions are a noop if the event has already been - // sent for the given output. - wlr_surface_send_enter(scene_surface->surface, scene_output->output); - } else { - wlr_surface_send_leave(scene_surface->surface, scene_output->output); + active_outputs |= 1ull << scene_output->index; + } + + pixman_region32_fini(&intersection); + } + + uint64_t old_active = scene_buffer->active_outputs; + scene_buffer->active_outputs = active_outputs; + + wl_list_for_each(scene_output, outputs, link) { + uint64_t mask = 1ull << scene_output->index; + bool intersects = active_outputs & mask; + bool intersects_before = old_active & mask; + + if (intersects && !intersects_before) { + wl_signal_emit_mutable(&scene_buffer->events.output_enter, scene_output); + } else if (!intersects && intersects_before) { + wl_signal_emit_mutable(&scene_buffer->events.output_leave, scene_output); } } } -static void scene_node_update_surface_outputs_iterator( - struct wlr_scene_node *node, int lx, int ly, struct wlr_scene *scene) { - if (node->type == WLR_SCENE_NODE_SURFACE) { - struct wlr_scene_surface *scene_surface = - wlr_scene_surface_from_node(node); - scene_surface_update_outputs(scene_surface, lx, ly, scene); +static bool scene_node_update_iterator(struct wlr_scene_node *node, + int lx, int ly, void *_data) { + struct scene_update_data *data = _data; + + struct wlr_box box = { .x = lx, .y = ly }; + scene_node_get_size(node, &box.width, &box.height); + + pixman_region32_subtract(&node->visible, &node->visible, data->update_region); + pixman_region32_union(&node->visible, &node->visible, data->visible); + pixman_region32_intersect_rect(&node->visible, &node->visible, + lx, ly, box.width, box.height); + + if (data->calculate_visibility) { + pixman_region32_t opaque; + pixman_region32_init(&opaque); + scene_node_opaque_region(node, lx, ly, &opaque); + pixman_region32_subtract(data->visible, data->visible, &opaque); + pixman_region32_fini(&opaque); } - struct wlr_scene_node *child; - wl_list_for_each(child, &node->state.children, state.link) { - scene_node_update_surface_outputs_iterator(child, lx + child->state.x, - ly + child->state.y, scene); - } + update_node_update_outputs(node, data->outputs, NULL); + + return false; } -static void scene_node_update_surface_outputs(struct wlr_scene_node *node) { +static void scene_node_visibility(struct wlr_scene_node *node, + pixman_region32_t *visible) { + if (!node->enabled) { + return; + } + + if (node->type == WLR_SCENE_NODE_TREE) { + struct wlr_scene_tree *scene_tree = scene_tree_from_node(node); + struct wlr_scene_node *child; + wl_list_for_each(child, &scene_tree->children, link) { + scene_node_visibility(child, visible); + } + return; + } + + pixman_region32_union(visible, visible, &node->visible); +} + +static void scene_node_bounds(struct wlr_scene_node *node, + int x, int y, pixman_region32_t *visible) { + if (!node->enabled) { + return; + } + + if (node->type == WLR_SCENE_NODE_TREE) { + struct wlr_scene_tree *scene_tree = scene_tree_from_node(node); + struct wlr_scene_node *child; + wl_list_for_each(child, &scene_tree->children, link) { + scene_node_bounds(child, x + child->x, y + child->y, visible); + } + return; + } + + int width, height; + scene_node_get_size(node, &width, &height); + pixman_region32_union_rect(visible, visible, x, y, width, height); +} + +static void scene_update_region(struct wlr_scene *scene, + pixman_region32_t *update_region) { + pixman_region32_t visible; + pixman_region32_init(&visible); + pixman_region32_copy(&visible, update_region); + + struct scene_update_data data = { + .visible = &visible, + .update_region = update_region, + .outputs = &scene->outputs, + .calculate_visibility = scene->calculate_visibility, + }; + + struct pixman_box32 *region_box = pixman_region32_extents(update_region); + struct wlr_box box = { + .x = region_box->x1, + .y = region_box->y1, + .width = region_box->x2 - region_box->x1, + .height = region_box->y2 - region_box->y1, + }; + + // update node visibility and output enter/leave events + scene_nodes_in_box(&scene->tree.node, &box, scene_node_update_iterator, &data); + + pixman_region32_fini(&visible); +} + +static void scene_node_update(struct wlr_scene_node *node, + pixman_region32_t *damage) { struct wlr_scene *scene = scene_node_get_root(node); - int lx, ly; - wlr_scene_node_coords(node, &lx, &ly); - scene_node_update_surface_outputs_iterator(node, lx, ly, scene); -} -static void scene_surface_handle_surface_commit(struct wl_listener *listener, - void *data) { - struct wlr_scene_surface *scene_surface = - wl_container_of(listener, scene_surface, surface_commit); - struct wlr_surface *surface = scene_surface->surface; - - struct wlr_scene *scene = scene_node_get_root(&scene_surface->node); - - int lx, ly; - bool enabled = wlr_scene_node_coords(&scene_surface->node, &lx, &ly); - - if (surface->current.width != scene_surface->prev_width || - surface->current.height != scene_surface->prev_height) { - scene_surface_update_outputs(scene_surface, lx, ly, scene); - scene_surface->prev_width = surface->current.width; - scene_surface->prev_height = surface->current.height; - } - - if (!enabled) { - return; - } - - // Even if the surface hasn't submitted damage, schedule a new frame if - // the client has requested a wl_surface.frame callback. - if (!wl_list_empty(&surface->current.frame_callback_list) && - scene_surface->primary_output != NULL) { - wlr_output_schedule_frame(scene_surface->primary_output); - } - - if (!pixman_region32_not_empty(&surface->buffer_damage)) { - return; - } - - struct wlr_scene_output *scene_output; - wl_list_for_each(scene_output, &scene->outputs, link) { - struct wlr_output *output = scene_output->output; - - pixman_region32_t damage; - pixman_region32_init(&damage); - wlr_surface_get_effective_damage(surface, &damage); - - pixman_region32_translate(&damage, - lx - scene_output->x, ly - scene_output->y); - - wlr_region_scale(&damage, &damage, output->scale); - if (ceil(output->scale) > surface->current.scale) { - // When scaling up a surface it'll become blurry, so we need to - // expand the damage region. - wlr_region_expand(&damage, &damage, - ceil(output->scale) - surface->current.scale); + int x, y; + if (!wlr_scene_node_coords(node, &x, &y)) { + if (damage) { + scene_update_region(scene, damage); + scene_damage_outputs(scene, damage); + pixman_region32_fini(damage); } - wlr_output_damage_add(scene_output->damage, &damage); - pixman_region32_fini(&damage); + + return; } + + pixman_region32_t visible; + if (!damage) { + pixman_region32_init(&visible); + scene_node_visibility(node, &visible); + damage = &visible; + } + + pixman_region32_t update_region; + pixman_region32_init(&update_region); + pixman_region32_copy(&update_region, damage); + scene_node_bounds(node, x, y, &update_region); + + scene_update_region(scene, &update_region); + pixman_region32_fini(&update_region); + + scene_node_visibility(node, damage); + scene_damage_outputs(scene, damage); + pixman_region32_fini(damage); } -struct wlr_scene_surface *wlr_scene_surface_create(struct wlr_scene_node *parent, - struct wlr_surface *surface) { - struct wlr_scene_surface *scene_surface = - calloc(1, sizeof(struct wlr_scene_surface)); - if (scene_surface == NULL) { - return NULL; - } - scene_node_init(&scene_surface->node, WLR_SCENE_NODE_SURFACE, parent); - - scene_surface->surface = surface; - - scene_surface->surface_destroy.notify = scene_surface_handle_surface_destroy; - wl_signal_add(&surface->events.destroy, &scene_surface->surface_destroy); - - scene_surface->surface_commit.notify = scene_surface_handle_surface_commit; - wl_signal_add(&surface->events.commit, &scene_surface->surface_commit); - - scene_node_damage_whole(&scene_surface->node); - - scene_node_update_surface_outputs(&scene_surface->node); - - return scene_surface; -} - -struct wlr_scene_rect *wlr_scene_rect_create(struct wlr_scene_node *parent, +struct wlr_scene_rect *wlr_scene_rect_create(struct wlr_scene_tree *parent, int width, int height, const float color[static 4]) { struct wlr_scene_rect *scene_rect = calloc(1, sizeof(struct wlr_scene_rect)); if (scene_rect == NULL) { return NULL; } + assert(parent); scene_node_init(&scene_rect->node, WLR_SCENE_NODE_RECT, parent); scene_rect->width = width; scene_rect->height = height; memcpy(scene_rect->color, color, sizeof(scene_rect->color)); - scene_node_damage_whole(&scene_rect->node); + scene_node_update(&scene_rect->node, NULL); return scene_rect; } @@ -335,10 +503,9 @@ void wlr_scene_rect_set_size(struct wlr_scene_rect *rect, int width, int height) return; } - scene_node_damage_whole(&rect->node); rect->width = width; rect->height = height; - scene_node_damage_whole(&rect->node); + scene_node_update(&rect->node, NULL); } void wlr_scene_rect_set_color(struct wlr_scene_rect *rect, const float color[static 4]) { @@ -347,32 +514,143 @@ void wlr_scene_rect_set_color(struct wlr_scene_rect *rect, const float color[sta } memcpy(rect->color, color, sizeof(rect->color)); - scene_node_damage_whole(&rect->node); + scene_node_update(&rect->node, NULL); } -struct wlr_scene_buffer *wlr_scene_buffer_create(struct wlr_scene_node *parent, +struct wlr_scene_buffer *wlr_scene_buffer_create(struct wlr_scene_tree *parent, struct wlr_buffer *buffer) { struct wlr_scene_buffer *scene_buffer = calloc(1, sizeof(*scene_buffer)); if (scene_buffer == NULL) { return NULL; } + assert(parent); scene_node_init(&scene_buffer->node, WLR_SCENE_NODE_BUFFER, parent); - scene_buffer->buffer = wlr_buffer_lock(buffer); + if (buffer) { + scene_buffer->buffer = wlr_buffer_lock(buffer); + } - scene_node_damage_whole(&scene_buffer->node); + wl_signal_init(&scene_buffer->events.output_enter); + wl_signal_init(&scene_buffer->events.output_leave); + wl_signal_init(&scene_buffer->events.output_present); + wl_signal_init(&scene_buffer->events.frame_done); + pixman_region32_init(&scene_buffer->opaque_region); - struct wlr_scene *scene = scene_node_get_root(parent); - wl_list_insert(&scene->pending_buffers, &scene_buffer->pending_link); + scene_node_update(&scene_buffer->node, NULL); return scene_buffer; } +void wlr_scene_buffer_set_buffer_with_damage(struct wlr_scene_buffer *scene_buffer, + struct wlr_buffer *buffer, pixman_region32_t *damage) { + // specifying a region for a NULL buffer doesn't make sense. We need to know + // about the buffer to scale the buffer local coordinates down to scene + // coordinates. + assert(buffer || !damage); + + if (buffer != scene_buffer->buffer) { + wlr_texture_destroy(scene_buffer->texture); + scene_buffer->texture = NULL; + wlr_buffer_unlock(scene_buffer->buffer); + + if (buffer) { + scene_buffer->buffer = wlr_buffer_lock(buffer); + } else { + scene_buffer->buffer = NULL; + } + + if (!damage) { + scene_node_update(&scene_buffer->node, NULL); + } + } + + if (!damage) { + return; + } + + int lx, ly; + if (!wlr_scene_node_coords(&scene_buffer->node, &lx, &ly)) { + return; + } + + struct wlr_fbox box = scene_buffer->src_box; + if (wlr_fbox_empty(&box)) { + box.x = 0; + box.y = 0; + + if (scene_buffer->transform & WL_OUTPUT_TRANSFORM_90) { + box.width = buffer->height; + box.height = buffer->width; + } else { + box.width = buffer->width; + box.height = buffer->height; + } + } + + double scale_x, scale_y; + if (scene_buffer->dst_width || scene_buffer->dst_height) { + scale_x = scene_buffer->dst_width / box.width; + scale_y = scene_buffer->dst_height / box.height; + } else { + scale_x = buffer->width / box.width; + scale_y = buffer->height / box.height; + } + + pixman_region32_t trans_damage; + pixman_region32_init(&trans_damage); + wlr_region_transform(&trans_damage, damage, + scene_buffer->transform, buffer->width, buffer->height); + pixman_region32_intersect_rect(&trans_damage, &trans_damage, + box.x, box.y, box.width, box.height); + + struct wlr_scene *scene = scene_node_get_root(&scene_buffer->node); + struct wlr_scene_output *scene_output; + wl_list_for_each(scene_output, &scene->outputs, link) { + float output_scale = scene_output->output->scale; + pixman_region32_t output_damage; + pixman_region32_init(&output_damage); + wlr_region_scale_xy(&output_damage, &trans_damage, + output_scale * scale_x, output_scale * scale_y); + + pixman_region32_t cull_region; + pixman_region32_init(&cull_region); + wlr_region_scale(&cull_region, &scene_buffer->node.visible, output_scale); + pixman_region32_translate(&cull_region, -lx * output_scale, -ly * output_scale); + pixman_region32_intersect(&output_damage, &output_damage, &cull_region); + pixman_region32_fini(&cull_region); + + pixman_region32_translate(&output_damage, + (lx - scene_output->x) * output_scale, + (ly - scene_output->y) * output_scale); + if (wlr_damage_ring_add(&scene_output->damage_ring, &output_damage)) { + wlr_output_schedule_frame(scene_output->output); + } + pixman_region32_fini(&output_damage); + } + + pixman_region32_fini(&trans_damage); +} + +void wlr_scene_buffer_set_buffer(struct wlr_scene_buffer *scene_buffer, + struct wlr_buffer *buffer) { + wlr_scene_buffer_set_buffer_with_damage(scene_buffer, buffer, NULL); +} + +void wlr_scene_buffer_set_opaque_region(struct wlr_scene_buffer *scene_buffer, + pixman_region32_t *region) { + if (pixman_region32_equal(&scene_buffer->opaque_region, region)) { + return; + } + + pixman_region32_copy(&scene_buffer->opaque_region, region); + scene_node_update(&scene_buffer->node, NULL); +} + void wlr_scene_buffer_set_source_box(struct wlr_scene_buffer *scene_buffer, const struct wlr_fbox *box) { struct wlr_fbox *cur = &scene_buffer->src_box; if ((wlr_fbox_empty(box) && wlr_fbox_empty(cur)) || - (box != NULL && memcmp(cur, box, sizeof(*box)) == 0)) { + (box != NULL && wlr_fbox_equal(cur, box))) { return; } @@ -382,7 +660,7 @@ void wlr_scene_buffer_set_source_box(struct wlr_scene_buffer *scene_buffer, memset(cur, 0, sizeof(*cur)); } - scene_node_damage_whole(&scene_buffer->node); + scene_node_update(&scene_buffer->node, NULL); } void wlr_scene_buffer_set_dest_size(struct wlr_scene_buffer *scene_buffer, @@ -391,10 +669,9 @@ void wlr_scene_buffer_set_dest_size(struct wlr_scene_buffer *scene_buffer, return; } - scene_node_damage_whole(&scene_buffer->node); scene_buffer->dst_width = width; scene_buffer->dst_height = height; - scene_node_damage_whole(&scene_buffer->node); + scene_node_update(&scene_buffer->node, NULL); } void wlr_scene_buffer_set_transform(struct wlr_scene_buffer *scene_buffer, @@ -403,9 +680,15 @@ void wlr_scene_buffer_set_transform(struct wlr_scene_buffer *scene_buffer, return; } - scene_node_damage_whole(&scene_buffer->node); scene_buffer->transform = transform; - scene_node_damage_whole(&scene_buffer->node); + scene_node_update(&scene_buffer->node, NULL); +} + +void wlr_scene_buffer_send_frame_done(struct wlr_scene_buffer *scene_buffer, + struct timespec *now) { + if (pixman_region32_not_empty(&scene_buffer->node.visible)) { + wl_signal_emit_mutable(&scene_buffer->events.frame_done, now); + } } static struct wlr_texture *scene_buffer_get_texture( @@ -431,26 +714,19 @@ static void scene_node_get_size(struct wlr_scene_node *node, *height = 0; switch (node->type) { - case WLR_SCENE_NODE_ROOT: case WLR_SCENE_NODE_TREE: return; - case WLR_SCENE_NODE_SURFACE:; - struct wlr_scene_surface *scene_surface = - wlr_scene_surface_from_node(node); - *width = scene_surface->surface->current.width; - *height = scene_surface->surface->current.height; - break; case WLR_SCENE_NODE_RECT:; struct wlr_scene_rect *scene_rect = scene_rect_from_node(node); *width = scene_rect->width; *height = scene_rect->height; break; case WLR_SCENE_NODE_BUFFER:; - struct wlr_scene_buffer *scene_buffer = scene_buffer_from_node(node); + struct wlr_scene_buffer *scene_buffer = wlr_scene_buffer_from_node(node); if (scene_buffer->dst_width > 0 && scene_buffer->dst_height > 0) { *width = scene_buffer->dst_width; *height = scene_buffer->dst_height; - } else { + } else if (scene_buffer->buffer) { if (scene_buffer->transform & WL_OUTPUT_TRANSFORM_90) { *height = scene_buffer->buffer->width; *width = scene_buffer->buffer->height; @@ -474,72 +750,31 @@ static void scale_box(struct wlr_box *box, float scale) { box->y = round(box->y * scale); } -static void _scene_node_damage_whole(struct wlr_scene_node *node, - struct wlr_scene *scene, int lx, int ly) { - if (!node->state.enabled) { - return; - } - - struct wlr_scene_node *child; - wl_list_for_each(child, &node->state.children, state.link) { - _scene_node_damage_whole(child, scene, - lx + child->state.x, ly + child->state.y); - } - - int width, height; - scene_node_get_size(node, &width, &height); - - struct wlr_scene_output *scene_output; - wl_list_for_each(scene_output, &scene->outputs, link) { - struct wlr_box box = { - .x = lx - scene_output->x, - .y = ly - scene_output->y, - .width = width, - .height = height, - }; - - scale_box(&box, scene_output->output->scale); - - wlr_output_damage_add_box(scene_output->damage, &box); - } -} - -static void scene_node_damage_whole(struct wlr_scene_node *node) { - struct wlr_scene *scene = scene_node_get_root(node); - if (wl_list_empty(&scene->outputs)) { - return; - } - - int lx, ly; - if (!wlr_scene_node_coords(node, &lx, &ly)) { - return; - } - - _scene_node_damage_whole(node, scene, lx, ly); -} - void wlr_scene_node_set_enabled(struct wlr_scene_node *node, bool enabled) { - if (node->state.enabled == enabled) { + if (node->enabled == enabled) { return; } - // One of these damage_whole() calls will short-circuit and be a no-op - scene_node_damage_whole(node); - node->state.enabled = enabled; - scene_node_damage_whole(node); + int x, y; + pixman_region32_t visible; + pixman_region32_init(&visible); + if (wlr_scene_node_coords(node, &x, &y)) { + scene_node_visibility(node, &visible); + } + + node->enabled = enabled; + + scene_node_update(node, &visible); } void wlr_scene_node_set_position(struct wlr_scene_node *node, int x, int y) { - if (node->state.x == x && node->state.y == y) { + if (node->x == x && node->y == y) { return; } - scene_node_damage_whole(node); - node->state.x = x; - node->state.y = y; - scene_node_damage_whole(node); - - scene_node_update_surface_outputs(node); + node->x = x; + node->y = y; + scene_node_update(node, NULL); } void wlr_scene_node_place_above(struct wlr_scene_node *node, @@ -547,15 +782,13 @@ void wlr_scene_node_place_above(struct wlr_scene_node *node, assert(node != sibling); assert(node->parent == sibling->parent); - if (node->state.link.prev == &sibling->state.link) { + if (node->link.prev == &sibling->link) { return; } - wl_list_remove(&node->state.link); - wl_list_insert(&sibling->state.link, &node->state.link); - - scene_node_damage_whole(node); - scene_node_damage_whole(sibling); + wl_list_remove(&node->link); + wl_list_insert(&sibling->link, &node->link); + scene_node_update(node, NULL); } void wlr_scene_node_place_below(struct wlr_scene_node *node, @@ -563,20 +796,18 @@ void wlr_scene_node_place_below(struct wlr_scene_node *node, assert(node != sibling); assert(node->parent == sibling->parent); - if (node->state.link.next == &sibling->state.link) { + if (node->link.next == &sibling->link) { return; } - wl_list_remove(&node->state.link); - wl_list_insert(sibling->state.link.prev, &node->state.link); - - scene_node_damage_whole(node); - scene_node_damage_whole(sibling); + wl_list_remove(&node->link); + wl_list_insert(sibling->link.prev, &node->link); + scene_node_update(node, NULL); } void wlr_scene_node_raise_to_top(struct wlr_scene_node *node) { struct wlr_scene_node *current_top = wl_container_of( - node->parent->state.children.prev, current_top, state.link); + node->parent->children.prev, current_top, link); if (node == current_top) { return; } @@ -585,7 +816,7 @@ void wlr_scene_node_raise_to_top(struct wlr_scene_node *node) { void wlr_scene_node_lower_to_bottom(struct wlr_scene_node *node) { struct wlr_scene_node *current_bottom = wl_container_of( - node->parent->state.children.next, current_bottom, state.link); + node->parent->children.next, current_bottom, link); if (node == current_bottom) { return; } @@ -593,39 +824,47 @@ void wlr_scene_node_lower_to_bottom(struct wlr_scene_node *node) { } void wlr_scene_node_reparent(struct wlr_scene_node *node, - struct wlr_scene_node *new_parent) { - assert(node->type != WLR_SCENE_NODE_ROOT && new_parent != NULL); + struct wlr_scene_tree *new_parent) { + assert(new_parent != NULL); if (node->parent == new_parent) { return; } /* Ensure that a node cannot become its own ancestor */ - for (struct wlr_scene_node *ancestor = new_parent; ancestor != NULL; - ancestor = ancestor->parent) { - assert(ancestor != node); + for (struct wlr_scene_tree *ancestor = new_parent; ancestor != NULL; + ancestor = ancestor->node.parent) { + assert(&ancestor->node != node); } - scene_node_damage_whole(node); + int x, y; + pixman_region32_t visible; + pixman_region32_init(&visible); + if (wlr_scene_node_coords(node, &x, &y)) { + scene_node_visibility(node, &visible); + } - wl_list_remove(&node->state.link); + wl_list_remove(&node->link); node->parent = new_parent; - wl_list_insert(new_parent->state.children.prev, &node->state.link); - - scene_node_damage_whole(node); - - scene_node_update_surface_outputs(node); + wl_list_insert(new_parent->children.prev, &node->link); + scene_node_update(node, &visible); } bool wlr_scene_node_coords(struct wlr_scene_node *node, int *lx_ptr, int *ly_ptr) { + assert(node); + int lx = 0, ly = 0; bool enabled = true; - while (node != NULL) { - lx += node->state.x; - ly += node->state.y; - enabled = enabled && node->state.enabled; - node = node->parent; + while (true) { + lx += node->x; + ly += node->y; + enabled = enabled && node->enabled; + if (node->parent == NULL) { + break; + } + + node = &node->parent->node; } *lx_ptr = lx; @@ -633,76 +872,83 @@ bool wlr_scene_node_coords(struct wlr_scene_node *node, return enabled; } -static void scene_node_for_each_surface(struct wlr_scene_node *node, - int lx, int ly, wlr_surface_iterator_func_t user_iterator, +static void scene_node_for_each_scene_buffer(struct wlr_scene_node *node, + int lx, int ly, wlr_scene_buffer_iterator_func_t user_iterator, void *user_data) { - if (!node->state.enabled) { + if (!node->enabled) { return; } - lx += node->state.x; - ly += node->state.y; + lx += node->x; + ly += node->y; - if (node->type == WLR_SCENE_NODE_SURFACE) { - struct wlr_scene_surface *scene_surface = wlr_scene_surface_from_node(node); - user_iterator(scene_surface->surface, lx, ly, user_data); - } - - struct wlr_scene_node *child; - wl_list_for_each(child, &node->state.children, state.link) { - scene_node_for_each_surface(child, lx, ly, user_iterator, user_data); + if (node->type == WLR_SCENE_NODE_BUFFER) { + struct wlr_scene_buffer *scene_buffer = wlr_scene_buffer_from_node(node); + user_iterator(scene_buffer, lx, ly, user_data); + } else if (node->type == WLR_SCENE_NODE_TREE) { + struct wlr_scene_tree *scene_tree = scene_tree_from_node(node); + struct wlr_scene_node *child; + wl_list_for_each(child, &scene_tree->children, link) { + scene_node_for_each_scene_buffer(child, lx, ly, user_iterator, user_data); + } } } -void wlr_scene_node_for_each_surface(struct wlr_scene_node *node, - wlr_surface_iterator_func_t user_iterator, void *user_data) { - scene_node_for_each_surface(node, 0, 0, user_iterator, user_data); +void wlr_scene_node_for_each_buffer(struct wlr_scene_node *node, + wlr_scene_buffer_iterator_func_t user_iterator, void *user_data) { + scene_node_for_each_scene_buffer(node, 0, 0, user_iterator, user_data); +} + +struct node_at_data { + double lx, ly; + double rx, ry; + struct wlr_scene_node *node; +}; + +static bool scene_node_at_iterator(struct wlr_scene_node *node, + int lx, int ly, void *data) { + struct node_at_data *at_data = data; + + double rx = at_data->lx - lx; + double ry = at_data->ly - ly; + + if (node->type == WLR_SCENE_NODE_BUFFER) { + struct wlr_scene_buffer *scene_buffer = wlr_scene_buffer_from_node(node); + + if (scene_buffer->point_accepts_input && + !scene_buffer->point_accepts_input(scene_buffer, rx, ry)) { + return false; + } + } + + at_data->rx = rx; + at_data->ry = ry; + at_data->node = node; + return true; } struct wlr_scene_node *wlr_scene_node_at(struct wlr_scene_node *node, double lx, double ly, double *nx, double *ny) { - if (!node->state.enabled) { - return NULL; - } + struct wlr_box box = { + .x = floor(lx), + .y = floor(ly), + .width = 1, + .height = 1 + }; - // TODO: optimize by storing a bounding box in each node? - lx -= node->state.x; - ly -= node->state.y; + struct node_at_data data = { + .lx = lx, + .ly = ly + }; - struct wlr_scene_node *child; - wl_list_for_each_reverse(child, &node->state.children, state.link) { - struct wlr_scene_node *node = - wlr_scene_node_at(child, lx, ly, nx, ny); - if (node != NULL) { - return node; + if (scene_nodes_in_box(node, &box, scene_node_at_iterator, &data)) { + if (nx) { + *nx = data.rx; } - } - - bool intersects = false; - switch (node->type) { - case WLR_SCENE_NODE_ROOT: - case WLR_SCENE_NODE_TREE: - break; - case WLR_SCENE_NODE_SURFACE:; - struct wlr_scene_surface *scene_surface = wlr_scene_surface_from_node(node); - intersects = wlr_surface_point_accepts_input(scene_surface->surface, lx, ly); - break; - case WLR_SCENE_NODE_RECT: - case WLR_SCENE_NODE_BUFFER:; - int width, height; - scene_node_get_size(node, &width, &height); - intersects = lx >= 0 && lx < width && ly >= 0 && ly < height; - break; - } - - if (intersects) { - if (nx != NULL) { - *nx = lx; + if (ny) { + *ny = data.ry; } - if (ny != NULL) { - *ny = ly; - } - return node; + return data.node; } return NULL; @@ -730,28 +976,21 @@ static void scissor_output(struct wlr_output *output, pixman_box32_t *rect) { } static void render_rect(struct wlr_output *output, - pixman_region32_t *output_damage, const float color[static 4], + pixman_region32_t *damage, const float color[static 4], const struct wlr_box *box, const float matrix[static 9]) { struct wlr_renderer *renderer = output->renderer; assert(renderer); - pixman_region32_t damage; - pixman_region32_init(&damage); - pixman_region32_init_rect(&damage, box->x, box->y, box->width, box->height); - pixman_region32_intersect(&damage, &damage, output_damage); - int nrects; - pixman_box32_t *rects = pixman_region32_rectangles(&damage, &nrects); + pixman_box32_t *rects = pixman_region32_rectangles(damage, &nrects); for (int i = 0; i < nrects; ++i) { scissor_output(output, &rects[i]); wlr_render_rect(renderer, box, color, matrix); } - - pixman_region32_fini(&damage); } static void render_texture(struct wlr_output *output, - pixman_region32_t *output_damage, struct wlr_texture *texture, + pixman_region32_t *damage, struct wlr_texture *texture, const struct wlr_fbox *src_box, const struct wlr_box *dst_box, const float matrix[static 9]) { struct wlr_renderer *renderer = output->renderer; @@ -759,40 +998,38 @@ static void render_texture(struct wlr_output *output, struct wlr_fbox default_src_box = {0}; if (wlr_fbox_empty(src_box)) { - default_src_box.width = dst_box->width; - default_src_box.height = dst_box->height; + default_src_box.width = texture->width; + default_src_box.height = texture->height; src_box = &default_src_box; } - pixman_region32_t damage; - pixman_region32_init(&damage); - pixman_region32_init_rect(&damage, dst_box->x, dst_box->y, - dst_box->width, dst_box->height); - pixman_region32_intersect(&damage, &damage, output_damage); - int nrects; - pixman_box32_t *rects = pixman_region32_rectangles(&damage, &nrects); + pixman_box32_t *rects = pixman_region32_rectangles(damage, &nrects); for (int i = 0; i < nrects; ++i) { scissor_output(output, &rects[i]); wlr_render_subtexture_with_matrix(renderer, texture, src_box, matrix, 1.0); } - - pixman_region32_fini(&damage); } -struct render_data { - struct wlr_output *output; - pixman_region32_t *damage; +static void scene_node_render(struct wlr_scene_node *node, + struct wlr_scene_output *scene_output, pixman_region32_t *damage) { + int x, y; + wlr_scene_node_coords(node, &x, &y); + x -= scene_output->x; + y -= scene_output->y; - // May be NULL - struct wlr_presentation *presentation; -}; + struct wlr_output *output = scene_output->output; -static void render_node_iterator(struct wlr_scene_node *node, - int x, int y, void *_data) { - struct render_data *data = _data; - struct wlr_output *output = data->output; - pixman_region32_t *output_damage = data->damage; + pixman_region32_t render_region; + pixman_region32_init(&render_region); + pixman_region32_copy(&render_region, &node->visible); + pixman_region32_translate(&render_region, -scene_output->x, -scene_output->y); + wlr_region_scale(&render_region, &render_region, output->scale); + pixman_region32_intersect(&render_region, &render_region, damage); + if (!pixman_region32_not_empty(&render_region)) { + pixman_region32_fini(&render_region); + return; + } struct wlr_box dst_box = { .x = x, @@ -805,100 +1042,37 @@ static void render_node_iterator(struct wlr_scene_node *node, float matrix[9]; enum wl_output_transform transform; switch (node->type) { - case WLR_SCENE_NODE_ROOT: case WLR_SCENE_NODE_TREE: - /* Root or tree node has nothing to render itself */ - break; - case WLR_SCENE_NODE_SURFACE:; - struct wlr_scene_surface *scene_surface = wlr_scene_surface_from_node(node); - struct wlr_surface *surface = scene_surface->surface; - - texture = wlr_surface_get_texture(surface); - if (texture == NULL) { - return; - } - - transform = wlr_output_transform_invert(surface->current.transform); - wlr_matrix_project_box(matrix, &dst_box, transform, 0.0, - output->transform_matrix); - - struct wlr_fbox src_box = {0}; - wlr_surface_get_buffer_source_box(surface, &src_box); - - render_texture(output, output_damage, texture, - &src_box, &dst_box, matrix); - - if (data->presentation != NULL && scene_surface->primary_output == output) { - wlr_presentation_surface_sampled_on_output(data->presentation, - surface, output); - } + assert(false); break; case WLR_SCENE_NODE_RECT:; struct wlr_scene_rect *scene_rect = scene_rect_from_node(node); - render_rect(output, output_damage, scene_rect->color, &dst_box, + render_rect(output, &render_region, scene_rect->color, &dst_box, output->transform_matrix); break; case WLR_SCENE_NODE_BUFFER:; - struct wlr_scene_buffer *scene_buffer = scene_buffer_from_node(node); + struct wlr_scene_buffer *scene_buffer = wlr_scene_buffer_from_node(node); + assert(scene_buffer->buffer); struct wlr_renderer *renderer = output->renderer; texture = scene_buffer_get_texture(scene_buffer, renderer); if (texture == NULL) { - return; + break; } transform = wlr_output_transform_invert(scene_buffer->transform); wlr_matrix_project_box(matrix, &dst_box, transform, 0.0, output->transform_matrix); - render_texture(output, output_damage, texture, &scene_buffer->src_box, + render_texture(output, &render_region, texture, &scene_buffer->src_box, &dst_box, matrix); + + wl_signal_emit_mutable(&scene_buffer->events.output_present, scene_output); break; } -} -static void scene_node_for_each_node(struct wlr_scene_node *node, - int lx, int ly, wlr_scene_node_iterator_func_t user_iterator, - void *user_data) { - if (!node->state.enabled) { - return; - } - - lx += node->state.x; - ly += node->state.y; - - user_iterator(node, lx, ly, user_data); - - struct wlr_scene_node *child; - wl_list_for_each(child, &node->state.children, state.link) { - scene_node_for_each_node(child, lx, ly, user_iterator, user_data); - } -} - -void wlr_scene_render_output(struct wlr_scene *scene, struct wlr_output *output, - int lx, int ly, pixman_region32_t *damage) { - pixman_region32_t full_region; - pixman_region32_init_rect(&full_region, 0, 0, output->width, output->height); - if (damage == NULL) { - damage = &full_region; - } - - struct wlr_renderer *renderer = output->renderer; - assert(renderer); - - if (output->enabled && pixman_region32_not_empty(damage)) { - struct render_data data = { - .output = output, - .damage = damage, - .presentation = scene->presentation, - }; - scene_node_for_each_node(&scene->node, -lx, -ly, - render_node_iterator, &data); - wlr_renderer_scissor(renderer, NULL); - } - - pixman_region32_fini(&full_region); + pixman_region32_fini(&render_region); } static void scene_handle_presentation_destroy(struct wl_listener *listener, @@ -929,6 +1103,63 @@ static const struct wlr_addon_interface output_addon_impl = { .destroy = scene_output_handle_destroy, }; +static void scene_node_output_update(struct wlr_scene_node *node, + struct wl_list *outputs, struct wlr_scene_output *ignore) { + if (node->type == WLR_SCENE_NODE_TREE) { + struct wlr_scene_tree *scene_tree = scene_tree_from_node(node); + struct wlr_scene_node *child; + wl_list_for_each(child, &scene_tree->children, link) { + scene_node_output_update(child, outputs, ignore); + } + return; + } + + update_node_update_outputs(node, outputs, ignore); +} + +static void scene_output_update_geometry(struct wlr_scene_output *scene_output) { + int width, height; + wlr_output_transformed_resolution(scene_output->output, &width, &height); + wlr_damage_ring_set_bounds(&scene_output->damage_ring, width, height); + wlr_output_schedule_frame(scene_output->output); + + scene_node_output_update(&scene_output->scene->tree.node, + &scene_output->scene->outputs, NULL); +} + +static void scene_output_handle_commit(struct wl_listener *listener, void *data) { + struct wlr_scene_output *scene_output = wl_container_of(listener, + scene_output, output_commit); + struct wlr_output_event_commit *event = data; + + if (event->committed & (WLR_OUTPUT_STATE_MODE | + WLR_OUTPUT_STATE_TRANSFORM | + WLR_OUTPUT_STATE_SCALE)) { + scene_output_update_geometry(scene_output); + } +} + +static void scene_output_handle_mode(struct wl_listener *listener, void *data) { + struct wlr_scene_output *scene_output = wl_container_of(listener, + scene_output, output_mode); + scene_output_update_geometry(scene_output); +} + +static void scene_output_handle_damage(struct wl_listener *listener, void *data) { + struct wlr_scene_output *scene_output = wl_container_of(listener, + scene_output, output_damage); + struct wlr_output_event_damage *event = data; + if (wlr_damage_ring_add(&scene_output->damage_ring, event->damage)) { + wlr_output_schedule_frame(scene_output->output); + } +} + +static void scene_output_handle_needs_frame(struct wl_listener *listener, void *data) { + struct wlr_scene_output *scene_output = wl_container_of(listener, + scene_output, output_needs_frame); + wlr_output_schedule_frame(scene_output->output); +} + struct wlr_scene_output *wlr_scene_output_create(struct wlr_scene *scene, struct wlr_output *output) { struct wlr_scene_output *scene_output = calloc(1, sizeof(*scene_output)); @@ -936,35 +1167,79 @@ struct wlr_scene_output *wlr_scene_output_create(struct wlr_scene *scene, return NULL; } - scene_output->damage = wlr_output_damage_create(output); - if (scene_output->damage == NULL) { - free(scene_output); - return NULL; - } - scene_output->output = output; scene_output->scene = scene; wlr_addon_init(&scene_output->addon, &output->addons, scene, &output_addon_impl); - wl_list_insert(&scene->outputs, &scene_output->link); - wlr_output_damage_add_whole(scene_output->damage); + wlr_damage_ring_init(&scene_output->damage_ring); + wl_list_init(&scene_output->damage_highlight_regions); + + int prev_output_index = -1; + struct wl_list *prev_output_link = &scene->outputs; + + struct wlr_scene_output *current_output; + wl_list_for_each(current_output, &scene->outputs, link) { + if (prev_output_index + 1 != current_output->index) { + break; + } + + prev_output_index = current_output->index; + prev_output_link = ¤t_output->link; + } + + scene_output->index = prev_output_index + 1; + assert(scene_output->index < 64); + wl_list_insert(prev_output_link, &scene_output->link); + + wl_signal_init(&scene_output->events.destroy); + + scene_output->output_commit.notify = scene_output_handle_commit; + wl_signal_add(&output->events.commit, &scene_output->output_commit); + + scene_output->output_mode.notify = scene_output_handle_mode; + wl_signal_add(&output->events.mode, &scene_output->output_mode); + + scene_output->output_damage.notify = scene_output_handle_damage; + wl_signal_add(&output->events.damage, &scene_output->output_damage); + + scene_output->output_needs_frame.notify = scene_output_handle_needs_frame; + wl_signal_add(&output->events.needs_frame, &scene_output->output_needs_frame); + + scene_output_update_geometry(scene_output); return scene_output; } -static void scene_output_send_leave_iterator(struct wlr_surface *surface, - int sx, int sy, void *data) { - struct wlr_output *output = data; - wlr_surface_send_leave(surface, output); +static void highlight_region_destroy(struct highlight_region *damage) { + wl_list_remove(&damage->link); + pixman_region32_fini(&damage->region); + free(damage); } void wlr_scene_output_destroy(struct wlr_scene_output *scene_output) { + if (scene_output == NULL) { + return; + } + + wl_signal_emit_mutable(&scene_output->events.destroy, NULL); + + scene_node_output_update(&scene_output->scene->tree.node, + &scene_output->scene->outputs, scene_output); + + struct highlight_region *damage, *tmp_damage; + wl_list_for_each_safe(damage, tmp_damage, &scene_output->damage_highlight_regions, link) { + highlight_region_destroy(damage); + } + wlr_addon_finish(&scene_output->addon); + wlr_damage_ring_finish(&scene_output->damage_ring); wl_list_remove(&scene_output->link); + wl_list_remove(&scene_output->output_commit.link); + wl_list_remove(&scene_output->output_mode.link); + wl_list_remove(&scene_output->output_damage.link); + wl_list_remove(&scene_output->output_needs_frame.link); - wlr_scene_output_for_each_surface(scene_output, - scene_output_send_leave_iterator, scene_output->output); - + wl_array_release(&scene_output->render_list); free(scene_output); } @@ -988,156 +1263,305 @@ void wlr_scene_output_set_position(struct wlr_scene_output *scene_output, scene_output->x = lx; scene_output->y = ly; - wlr_output_damage_add_whole(scene_output->damage); - scene_node_update_surface_outputs(&scene_output->scene->node); + scene_output_update_geometry(scene_output); } -struct check_scanout_data { - // in - struct wlr_box viewport_box; - // out - struct wlr_scene_node *node; - size_t n; +static bool scene_node_invisible(struct wlr_scene_node *node) { + if (node->type == WLR_SCENE_NODE_TREE) { + return true; + } else if (node->type == WLR_SCENE_NODE_RECT) { + struct wlr_scene_rect *rect = scene_rect_from_node(node); + + return rect->color[3] == 0.f; + } else if (node->type == WLR_SCENE_NODE_BUFFER) { + struct wlr_scene_buffer *buffer = wlr_scene_buffer_from_node(node); + + return buffer->buffer == NULL; + } + + return false; +} + +struct render_list_constructor_data { + struct wlr_box box; + struct wl_array *render_list; + bool calculate_visibility; }; -static void check_scanout_iterator(struct wlr_scene_node *node, - int x, int y, void *_data) { - struct check_scanout_data *data = _data; +static bool construct_render_list_iterator(struct wlr_scene_node *node, + int lx, int ly, void *_data) { + struct render_list_constructor_data *data = _data; - struct wlr_box node_box = { .x = x, .y = y }; - scene_node_get_size(node, &node_box.width, &node_box.height); - - struct wlr_box intersection; - if (!wlr_box_intersection(&intersection, &data->viewport_box, &node_box)) { - return; + if (scene_node_invisible(node)) { + return false; } - data->n++; + // while rendering, the background should always be black. + // If we see a black rect, we can ignore rendering everything under the rect + // and even the rect itself. + if (node->type == WLR_SCENE_NODE_RECT && data->calculate_visibility) { + struct wlr_scene_rect *rect = scene_rect_from_node(node); + float *black = (float[4]){ 0.f, 0.f, 0.f, 1.f }; - if (data->viewport_box.x == node_box.x && - data->viewport_box.y == node_box.y && - data->viewport_box.width == node_box.width && - data->viewport_box.height == node_box.height) { - data->node = node; + if (memcmp(rect->color, black, sizeof(float) * 4) == 0) { + return false; + } } + + pixman_region32_t intersection; + pixman_region32_init(&intersection); + pixman_region32_intersect_rect(&intersection, &node->visible, + data->box.x, data->box.y, + data->box.width, data->box.height); + if (!pixman_region32_not_empty(&intersection)) { + pixman_region32_fini(&intersection); + return false; + } + + pixman_region32_fini(&intersection); + + struct wlr_scene_node **entry = wl_array_add(data->render_list, + sizeof(struct wlr_scene_node *)); + if (entry) { + *entry = node; + } + return false; } -static bool scene_output_scanout(struct wlr_scene_output *scene_output) { +static bool scene_node_try_direct_scanout(struct wlr_scene_node *node, + struct wlr_scene_output *scene_output, struct wlr_box *box) { + if (!scene_output->scene->direct_scanout) { + return false; + } + + if (scene_output->scene->debug_damage_option == + WLR_SCENE_DEBUG_DAMAGE_HIGHLIGHT) { + // We don't want to enter direct scan out if we have highlight regions + // enabled. Otherwise, we won't be able to render the damage regions. + return false; + } + + if (node->type != WLR_SCENE_NODE_BUFFER) { + return false; + } + + struct wlr_scene_buffer *buffer = wlr_scene_buffer_from_node(node); struct wlr_output *output = scene_output->output; - struct wlr_box viewport_box = { .x = scene_output->x, .y = scene_output->y }; - wlr_output_effective_resolution(output, - &viewport_box.width, &viewport_box.height); + struct wlr_fbox default_box = {0}; + if (buffer->transform & WL_OUTPUT_TRANSFORM_90) { + default_box.width = buffer->buffer->height; + default_box.height = buffer->buffer->width; + } else { + default_box.width = buffer->buffer->width; + default_box.height = buffer->buffer->height; + } - struct check_scanout_data check_scanout_data = { - .viewport_box = viewport_box, - }; - scene_node_for_each_node(&scene_output->scene->node, 0, 0, - check_scanout_iterator, &check_scanout_data); - if (check_scanout_data.n != 1 || check_scanout_data.node == NULL) { + if (!wlr_fbox_empty(&buffer->src_box) && + !wlr_fbox_equal(&buffer->src_box, &default_box)) { return false; } - struct wlr_scene_node *node = check_scanout_data.node; - struct wlr_buffer *buffer; - switch (node->type) { - case WLR_SCENE_NODE_SURFACE:; - struct wlr_scene_surface *scene_surface = wlr_scene_surface_from_node(node); - if (scene_surface->surface->buffer == NULL || - scene_surface->surface->current.viewport.has_src || - scene_surface->surface->current.transform != output->transform) { - return false; - } - buffer = &scene_surface->surface->buffer->base; - break; - case WLR_SCENE_NODE_BUFFER:; - struct wlr_scene_buffer *scene_buffer = scene_buffer_from_node(node); - if (scene_buffer->buffer == NULL || - !wlr_fbox_empty(&scene_buffer->src_box) || - scene_buffer->transform != output->transform) { - return false; - } - buffer = scene_buffer->buffer; - break; - default: + if (buffer->transform != output->transform) { return false; } - wlr_output_attach_buffer(output, buffer); + struct wlr_box node_box; + wlr_scene_node_coords(node, &node_box.x, &node_box.y); + scene_node_get_size(node, &node_box.width, &node_box.height); + + if (!wlr_box_equal(box, &node_box)) { + return false; + } + + wlr_output_attach_buffer(output, buffer->buffer); if (!wlr_output_test(output)) { wlr_output_rollback(output); return false; } - struct wlr_presentation *presentation = scene_output->scene->presentation; - if (presentation != NULL && node->type == WLR_SCENE_NODE_SURFACE) { - struct wlr_scene_surface *scene_surface = - wlr_scene_surface_from_node(node); - // Since outputs may overlap, we still need to check this even though - // we know that the surface size matches the size of this output. - if (scene_surface->primary_output == output) { - wlr_presentation_surface_sampled_on_output(presentation, - scene_surface->surface, output); - } - } - return wlr_output_commit(output); } bool wlr_scene_output_commit(struct wlr_scene_output *scene_output) { struct wlr_output *output = scene_output->output; + enum wlr_scene_debug_damage_option debug_damage = + scene_output->scene->debug_damage_option; struct wlr_renderer *renderer = output->renderer; assert(renderer != NULL); - bool scanout = scene_output_scanout(scene_output); - if (scanout != scene_output->prev_scanout) { + struct render_list_constructor_data list_con = { + .box = { .x = scene_output->x, .y = scene_output->y }, + .render_list = &scene_output->render_list, + .calculate_visibility = scene_output->scene->calculate_visibility, + }; + wlr_output_effective_resolution(output, + &list_con.box.width, &list_con.box.height); + + list_con.render_list->size = 0; + scene_nodes_in_box(&scene_output->scene->tree.node, &list_con.box, + construct_render_list_iterator, &list_con); + array_realloc(list_con.render_list, list_con.render_list->size); + + int list_len = list_con.render_list->size / sizeof(struct wlr_scene_node *); + struct wlr_scene_node **list_data = list_con.render_list->data; + + // if there is only one thing to render let's see if that thing can be + // directly scanned out + bool scanout = false; + if (list_len == 1) { + struct wlr_scene_node *node = list_data[0]; + scanout = scene_node_try_direct_scanout(node, scene_output, &list_con.box); + } + + if (scene_output->prev_scanout != scanout) { + scene_output->prev_scanout = scanout; wlr_log(WLR_DEBUG, "Direct scan-out %s", scanout ? "enabled" : "disabled"); // When exiting direct scan-out, damage everything - wlr_output_damage_add_whole(scene_output->damage); + wlr_damage_ring_add_whole(&scene_output->damage_ring); } - scene_output->prev_scanout = scanout; + if (scanout) { + struct wlr_scene_node *node = list_data[0]; + + assert(node->type == WLR_SCENE_NODE_BUFFER); + struct wlr_scene_buffer *buffer = wlr_scene_buffer_from_node(node); + wl_signal_emit_mutable(&buffer->events.output_present, scene_output); return true; } - bool needs_frame; - pixman_region32_t damage; - pixman_region32_init(&damage); - if (!wlr_output_damage_attach_render(scene_output->damage, - &needs_frame, &damage)) { - pixman_region32_fini(&damage); + if (debug_damage == WLR_SCENE_DEBUG_DAMAGE_RERENDER) { + wlr_damage_ring_add_whole(&scene_output->damage_ring); + } + + struct timespec now; + if (debug_damage == WLR_SCENE_DEBUG_DAMAGE_HIGHLIGHT) { + struct wl_list *regions = &scene_output->damage_highlight_regions; + clock_gettime(CLOCK_MONOTONIC, &now); + + // add the current frame's damage if there is damage + if (pixman_region32_not_empty(&scene_output->damage_ring.current)) { + struct highlight_region *current_damage = + calloc(1, sizeof(*current_damage)); + if (current_damage) { + pixman_region32_init(¤t_damage->region); + pixman_region32_copy(¤t_damage->region, + &scene_output->damage_ring.current); + current_damage->when = now; + wl_list_insert(regions, ¤t_damage->link); + } + } + + pixman_region32_t acc_damage; + pixman_region32_init(&acc_damage); + struct highlight_region *damage, *tmp_damage; + wl_list_for_each_safe(damage, tmp_damage, regions, link) { + // remove overlaping damage regions + pixman_region32_subtract(&damage->region, &damage->region, &acc_damage); + pixman_region32_union(&acc_damage, &acc_damage, &damage->region); + + // if this damage is too old or has nothing in it, get rid of it + struct timespec time_diff; + timespec_sub(&time_diff, &now, &damage->when); + if (timespec_to_msec(&time_diff) >= HIGHLIGHT_DAMAGE_FADEOUT_TIME || + !pixman_region32_not_empty(&damage->region)) { + highlight_region_destroy(damage); + } + } + + wlr_damage_ring_add(&scene_output->damage_ring, &acc_damage); + pixman_region32_fini(&acc_damage); + } + + int buffer_age; + if (!wlr_output_attach_render(output, &buffer_age)) { return false; } - if (!needs_frame) { + pixman_region32_t damage; + pixman_region32_init(&damage); + wlr_damage_ring_get_buffer_damage(&scene_output->damage_ring, + buffer_age, &damage); + if (!output->needs_frame && !pixman_region32_not_empty( + &scene_output->damage_ring.current)) { pixman_region32_fini(&damage); wlr_output_rollback(output); return true; } - // Try to import new buffers as textures - struct wlr_scene_buffer *scene_buffer, *scene_buffer_tmp; - wl_list_for_each_safe(scene_buffer, scene_buffer_tmp, - &scene_output->scene->pending_buffers, pending_link) { - scene_buffer_get_texture(scene_buffer, renderer); - wl_list_remove(&scene_buffer->pending_link); - wl_list_init(&scene_buffer->pending_link); - } - wlr_renderer_begin(renderer, output->width, output->height); + pixman_region32_t background; + pixman_region32_init(&background); + pixman_region32_copy(&background, &damage); + + // Cull areas of the background that are occluded by opaque regions of + // scene nodes above. Those scene nodes will just render atop having us + // never see the background. + if (scene_output->scene->calculate_visibility) { + for (int i = list_len - 1; i >= 0; i--) { + struct wlr_scene_node *node = list_data[i]; + int x, y; + wlr_scene_node_coords(node, &x, &y); + + // We must only cull opaque regions that are visible by the node. + // The node's visibility will have the knowledge of a black rect + // that may have been omitted from the render list via the black + // rect optimization. In order to ensure we don't cull background + // rendering in that black rect region, consider the node's visibility. + pixman_region32_t opaque; + pixman_region32_init(&opaque); + scene_node_opaque_region(node, x, y, &opaque); + pixman_region32_intersect(&opaque, &opaque, &node->visible); + + wlr_region_scale(&opaque, &opaque, scene_output->output->scale); + pixman_region32_subtract(&background, &background, &opaque); + pixman_region32_fini(&opaque); + } + } + int nrects; - pixman_box32_t *rects = pixman_region32_rectangles(&damage, &nrects); + pixman_box32_t *rects = pixman_region32_rectangles(&background, &nrects); for (int i = 0; i < nrects; ++i) { scissor_output(output, &rects[i]); wlr_renderer_clear(renderer, (float[4]){ 0.0, 0.0, 0.0, 1.0 }); } + pixman_region32_fini(&background); + + for (int i = list_len - 1; i >= 0; i--) { + struct wlr_scene_node *node = list_data[i]; + scene_node_render(node, scene_output, &damage); + } + + wlr_renderer_scissor(renderer, NULL); + + if (debug_damage == WLR_SCENE_DEBUG_DAMAGE_HIGHLIGHT) { + struct highlight_region *damage; + wl_list_for_each(damage, &scene_output->damage_highlight_regions, link) { + struct timespec time_diff; + timespec_sub(&time_diff, &now, &damage->when); + int64_t time_diff_ms = timespec_to_msec(&time_diff); + float alpha = 1.0 - (double)time_diff_ms / HIGHLIGHT_DAMAGE_FADEOUT_TIME; + + int nrects; + pixman_box32_t *rects = pixman_region32_rectangles(&damage->region, &nrects); + for (int i = 0; i < nrects; ++i) { + struct wlr_box box = { + .x = rects[i].x1, + .y = rects[i].y1, + .width = rects[i].x2 - rects[i].x1, + .height = rects[i].y2 - rects[i].y1, + }; + + float color[4] = { alpha * .5, 0.0, 0.0, alpha * .5 }; + wlr_render_rect(renderer, &box, color, output->transform_matrix); + } + } + } - wlr_scene_render_output(scene_output->scene, output, - scene_output->x, scene_output->y, &damage); wlr_output_render_software_cursors(output, &damage); wlr_renderer_end(renderer); @@ -1151,74 +1575,89 @@ bool wlr_scene_output_commit(struct wlr_scene_output *scene_output) { pixman_region32_t frame_damage; pixman_region32_init(&frame_damage); - wlr_region_transform(&frame_damage, &scene_output->damage->current, + wlr_region_transform(&frame_damage, + &scene_output->damage_ring.current, transform, tr_width, tr_height); wlr_output_set_damage(output, &frame_damage); pixman_region32_fini(&frame_damage); - return wlr_output_commit(output); + bool success = wlr_output_commit(output); + + if (success) { + wlr_damage_ring_rotate(&scene_output->damage_ring); + } + + if (debug_damage == WLR_SCENE_DEBUG_DAMAGE_HIGHLIGHT && + !wl_list_empty(&scene_output->damage_highlight_regions)) { + wlr_output_schedule_frame(scene_output->output); + } + + return success; } -static void scene_output_send_frame_done_iterator(struct wlr_scene_node *node, - struct wlr_output *output, struct timespec *now) { - if (!node->state.enabled) { +static void scene_node_send_frame_done(struct wlr_scene_node *node, + struct wlr_scene_output *scene_output, struct timespec *now) { + if (!node->enabled) { return; } - if (node->type == WLR_SCENE_NODE_SURFACE) { - struct wlr_scene_surface *scene_surface = - wlr_scene_surface_from_node(node); - if (scene_surface->primary_output == output) { - wlr_surface_send_frame_done(scene_surface->surface, now); - } - } + if (node->type == WLR_SCENE_NODE_BUFFER) { + struct wlr_scene_buffer *scene_buffer = + wlr_scene_buffer_from_node(node); - struct wlr_scene_node *child; - wl_list_for_each(child, &node->state.children, state.link) { - scene_output_send_frame_done_iterator(child, output, now); + if (scene_buffer->primary_output == scene_output) { + wlr_scene_buffer_send_frame_done(scene_buffer, now); + } + } else if (node->type == WLR_SCENE_NODE_TREE) { + struct wlr_scene_tree *scene_tree = scene_tree_from_node(node); + struct wlr_scene_node *child; + wl_list_for_each(child, &scene_tree->children, link) { + scene_node_send_frame_done(child, scene_output, now); + } } } void wlr_scene_output_send_frame_done(struct wlr_scene_output *scene_output, struct timespec *now) { - scene_output_send_frame_done_iterator(&scene_output->scene->node, - scene_output->output, now); + scene_node_send_frame_done(&scene_output->scene->tree.node, + scene_output, now); } -static void scene_output_for_each_surface(const struct wlr_box *output_box, +static void scene_output_for_each_scene_buffer(const struct wlr_box *output_box, struct wlr_scene_node *node, int lx, int ly, - wlr_surface_iterator_func_t user_iterator, void *user_data) { - if (!node->state.enabled) { + wlr_scene_buffer_iterator_func_t user_iterator, void *user_data) { + if (!node->enabled) { return; } - lx += node->state.x; - ly += node->state.y; + lx += node->x; + ly += node->y; - if (node->type == WLR_SCENE_NODE_SURFACE) { + if (node->type == WLR_SCENE_NODE_BUFFER) { struct wlr_box node_box = { .x = lx, .y = ly }; scene_node_get_size(node, &node_box.width, &node_box.height); struct wlr_box intersection; if (wlr_box_intersection(&intersection, output_box, &node_box)) { - struct wlr_scene_surface *scene_surface = - wlr_scene_surface_from_node(node); - user_iterator(scene_surface->surface, lx, ly, user_data); + struct wlr_scene_buffer *scene_buffer = + wlr_scene_buffer_from_node(node); + user_iterator(scene_buffer, lx, ly, user_data); + } + } else if (node->type == WLR_SCENE_NODE_TREE) { + struct wlr_scene_tree *scene_tree = scene_tree_from_node(node); + struct wlr_scene_node *child; + wl_list_for_each(child, &scene_tree->children, link) { + scene_output_for_each_scene_buffer(output_box, child, lx, ly, + user_iterator, user_data); } - } - - struct wlr_scene_node *child; - wl_list_for_each(child, &node->state.children, state.link) { - scene_output_for_each_surface(output_box, child, lx, ly, - user_iterator, user_data); } } -void wlr_scene_output_for_each_surface(struct wlr_scene_output *scene_output, - wlr_surface_iterator_func_t iterator, void *user_data) { +void wlr_scene_output_for_each_buffer(struct wlr_scene_output *scene_output, + wlr_scene_buffer_iterator_func_t iterator, void *user_data) { struct wlr_box box = { .x = scene_output->x, .y = scene_output->y }; wlr_output_effective_resolution(scene_output->output, &box.width, &box.height); - scene_output_for_each_surface(&box, &scene_output->scene->node, 0, 0, + scene_output_for_each_scene_buffer(&box, &scene_output->scene->tree.node, 0, 0, iterator, user_data); } diff --git a/types/scene/xdg_shell.c b/types/scene/xdg_shell.c index 9b3ad71c3..16883488f 100644 --- a/types/scene/xdg_shell.c +++ b/types/scene/xdg_shell.c @@ -5,7 +5,7 @@ struct wlr_scene_xdg_surface { struct wlr_scene_tree *tree; struct wlr_xdg_surface *xdg_surface; - struct wlr_scene_node *surface_node; + struct wlr_scene_tree *surface_tree; struct wl_listener tree_destroy; struct wl_listener xdg_surface_destroy; @@ -54,13 +54,13 @@ static void scene_xdg_surface_update_position( struct wlr_box geo = {0}; wlr_xdg_surface_get_geometry(xdg_surface, &geo); - wlr_scene_node_set_position(scene_xdg_surface->surface_node, + wlr_scene_node_set_position(&scene_xdg_surface->surface_tree->node, -geo.x, -geo.y); if (xdg_surface->role == WLR_XDG_SURFACE_ROLE_POPUP) { struct wlr_xdg_popup *popup = xdg_surface->popup; wlr_scene_node_set_position(&scene_xdg_surface->tree->node, - popup->geometry.x, popup->geometry.y); + popup->current.geometry.x, popup->current.geometry.y); } } @@ -71,8 +71,8 @@ static void scene_xdg_surface_handle_xdg_surface_commit(struct wl_listener *list scene_xdg_surface_update_position(scene_xdg_surface); } -struct wlr_scene_node *wlr_scene_xdg_surface_create( - struct wlr_scene_node *parent, struct wlr_xdg_surface *xdg_surface) { +struct wlr_scene_tree *wlr_scene_xdg_surface_create( + struct wlr_scene_tree *parent, struct wlr_xdg_surface *xdg_surface) { struct wlr_scene_xdg_surface *scene_xdg_surface = calloc(1, sizeof(*scene_xdg_surface)); if (scene_xdg_surface == NULL) { @@ -87,9 +87,9 @@ struct wlr_scene_node *wlr_scene_xdg_surface_create( return NULL; } - scene_xdg_surface->surface_node = wlr_scene_subsurface_tree_create( - &scene_xdg_surface->tree->node, xdg_surface->surface); - if (scene_xdg_surface->surface_node == NULL) { + scene_xdg_surface->surface_tree = wlr_scene_subsurface_tree_create( + scene_xdg_surface->tree, xdg_surface->surface); + if (scene_xdg_surface->surface_tree == NULL) { wlr_scene_node_destroy(&scene_xdg_surface->tree->node); free(scene_xdg_surface); return NULL; @@ -120,5 +120,5 @@ struct wlr_scene_node *wlr_scene_xdg_surface_create( wlr_scene_node_set_enabled(&scene_xdg_surface->tree->node, xdg_surface->mapped); scene_xdg_surface_update_position(scene_xdg_surface); - return &scene_xdg_surface->tree->node; + return scene_xdg_surface->tree; } diff --git a/types/seat/wlr_seat.c b/types/seat/wlr_seat.c index 4933133c6..59b760ca5 100644 --- a/types/seat/wlr_seat.c +++ b/types/seat/wlr_seat.c @@ -5,15 +5,14 @@ #include #include #include -#include #include #include +#include #include #include "types/wlr_seat.h" #include "util/global.h" -#include "util/signal.h" -#define SEAT_VERSION 7 +#define SEAT_VERSION 8 static void seat_handle_get_pointer(struct wl_client *client, struct wl_resource *seat_resource, uint32_t id) { @@ -67,7 +66,7 @@ static void seat_client_handle_resource_destroy( return; } - wlr_signal_emit_safe(&client->events.destroy, client); + wl_signal_emit_mutable(&client->events.destroy, client); if (client == client->seat->pointer_state.focused_client) { client->seat->pointer_state.focused_client = NULL; @@ -143,6 +142,20 @@ static void seat_handle_bind(struct wl_client *client, void *_wlr_seat, wl_signal_init(&seat_client->events.destroy); wl_list_insert(&wlr_seat->clients, &seat_client->link); + + struct wlr_surface *pointer_focus = + wlr_seat->pointer_state.focused_surface; + if (pointer_focus != NULL && + wl_resource_get_client(pointer_focus->resource) == client) { + wlr_seat->pointer_state.focused_client = seat_client; + } + + struct wlr_surface *keyboard_focus = + wlr_seat->keyboard_state.focused_surface; + if (keyboard_focus != NULL && + wl_resource_get_client(keyboard_focus->resource) == client) { + wlr_seat->keyboard_state.focused_client = seat_client; + } } wl_resource_set_implementation(wl_resource, &seat_impl, @@ -167,7 +180,7 @@ void wlr_seat_destroy(struct wlr_seat *seat) { wlr_seat_touch_point_clear_focus(seat, 0, point->touch_id); } - wlr_signal_emit_safe(&seat->events.destroy, seat); + wl_signal_emit_mutable(&seat->events.destroy, seat); wl_list_remove(&seat->display_destroy.link); diff --git a/types/seat/wlr_seat_keyboard.c b/types/seat/wlr_seat_keyboard.c index 9ed5fb345..186b8251a 100644 --- a/types/seat/wlr_seat_keyboard.c +++ b/types/seat/wlr_seat_keyboard.c @@ -5,11 +5,9 @@ #include #include #include -#include #include #include "types/wlr_data_device.h" #include "types/wlr_seat.h" -#include "util/signal.h" static void default_keyboard_enter(struct wlr_seat_keyboard_grab *grab, struct wlr_surface *surface, uint32_t keycodes[], size_t num_keycodes, @@ -119,11 +117,10 @@ static void handle_keyboard_destroy(struct wl_listener *listener, void *data) { } void wlr_seat_set_keyboard(struct wlr_seat *seat, - struct wlr_input_device *device) { + struct wlr_keyboard *keyboard) { // TODO call this on device key event before the event reaches the // compositor and set a pending keyboard and then send the new keyboard // state on the next keyboard notify event. - struct wlr_keyboard *keyboard = (device ? device->keyboard : NULL); if (seat->keyboard_state.keyboard == keyboard) { return; } @@ -136,16 +133,15 @@ void wlr_seat_set_keyboard(struct wlr_seat *seat, } if (keyboard) { - assert(device->type == WLR_INPUT_DEVICE_KEYBOARD); seat->keyboard_state.keyboard = keyboard; - wl_signal_add(&device->events.destroy, + wl_signal_add(&keyboard->base.events.destroy, &seat->keyboard_state.keyboard_destroy); seat->keyboard_state.keyboard_destroy.notify = handle_keyboard_destroy; - wl_signal_add(&device->keyboard->events.keymap, + wl_signal_add(&keyboard->events.keymap, &seat->keyboard_state.keyboard_keymap); seat->keyboard_state.keyboard_keymap.notify = handle_keyboard_keymap; - wl_signal_add(&device->keyboard->events.repeat_info, + wl_signal_add(&keyboard->events.repeat_info, &seat->keyboard_state.keyboard_repeat_info); seat->keyboard_state.keyboard_repeat_info.notify = handle_keyboard_repeat_info; @@ -171,7 +167,7 @@ void wlr_seat_keyboard_start_grab(struct wlr_seat *wlr_seat, grab->seat = wlr_seat; wlr_seat->keyboard_state.grab = grab; - wlr_signal_emit_safe(&wlr_seat->events.keyboard_grab_begin, grab); + wl_signal_emit_mutable(&wlr_seat->events.keyboard_grab_begin, grab); } void wlr_seat_keyboard_end_grab(struct wlr_seat *wlr_seat) { @@ -179,7 +175,7 @@ void wlr_seat_keyboard_end_grab(struct wlr_seat *wlr_seat) { if (grab != wlr_seat->keyboard_state.default_grab) { wlr_seat->keyboard_state.grab = wlr_seat->keyboard_state.default_grab; - wlr_signal_emit_safe(&wlr_seat->events.keyboard_grab_end, grab); + wl_signal_emit_mutable(&wlr_seat->events.keyboard_grab_end, grab); if (grab->interface->cancel) { grab->interface->cancel(grab); } @@ -306,7 +302,7 @@ void wlr_seat_keyboard_enter(struct wlr_seat *seat, .old_surface = focused_surface, .new_surface = surface, }; - wlr_signal_emit_safe(&seat->keyboard_state.events.focus_change, &event); + wl_signal_emit_mutable(&seat->keyboard_state.events.focus_change, &event); } void wlr_seat_keyboard_notify_enter(struct wlr_seat *seat, diff --git a/types/seat/wlr_seat_pointer.c b/types/seat/wlr_seat_pointer.c index ce4ca54e2..8d6154b02 100644 --- a/types/seat/wlr_seat_pointer.c +++ b/types/seat/wlr_seat_pointer.c @@ -5,11 +5,9 @@ #include #include #include -#include #include #include "types/wlr_seat.h" -#include "util/signal.h" -#include "util/array.h" +#include "util/set.h" static void default_pointer_enter(struct wlr_seat_pointer_grab *grab, struct wlr_surface *surface, double sx, double sy) { @@ -102,7 +100,7 @@ static void pointer_set_cursor(struct wl_client *client, .hotspot_x = hotspot_x, .hotspot_y = hotspot_y, }; - wlr_signal_emit_safe(&seat_client->seat->events.request_set_cursor, &event); + wl_signal_emit_mutable(&seat_client->seat->events.request_set_cursor, &event); } static void pointer_release(struct wl_client *client, @@ -212,7 +210,7 @@ void wlr_seat_pointer_enter(struct wlr_seat *wlr_seat, .sx = sx, .sy = sy, }; - wlr_signal_emit_safe(&wlr_seat->pointer_state.events.focus_change, &event); + wl_signal_emit_mutable(&wlr_seat->pointer_state.events.focus_change, &event); } void wlr_seat_pointer_clear_focus(struct wlr_seat *wlr_seat) { @@ -270,6 +268,47 @@ uint32_t wlr_seat_pointer_send_button(struct wlr_seat *wlr_seat, uint32_t time, return serial; } +static bool should_reset_value120_accumulators(int32_t current, int32_t last) { + if (last == 0) { + return true; + } + + return (current < 0 && last > 0) || (current > 0 && last < 0); +} + +static void update_value120_accumulators(struct wlr_seat_client *client, + enum wlr_axis_orientation orientation, + double value, int32_t value_discrete, + double *low_res_value, int32_t *low_res_value_discrete) { + if (value_discrete == 0) { + // Continuous scrolling has no effect on accumulators + return; + } + + int32_t *acc_discrete = &client->value120.acc_discrete[orientation]; + int32_t *last_discrete = &client->value120.last_discrete[orientation]; + double *acc_axis = &client->value120.acc_axis[orientation]; + + if (should_reset_value120_accumulators(value_discrete, *last_discrete)) { + *acc_discrete = 0; + *acc_axis = 0; + } + *acc_discrete += value_discrete; + *last_discrete = value_discrete; + *acc_axis += value; + + // Compute low resolution event values for older clients and reset + // the accumulators if needed + *low_res_value_discrete = *acc_discrete / WLR_POINTER_AXIS_DISCRETE_STEP; + if (*low_res_value_discrete == 0) { + *low_res_value = 0; + } else { + *acc_discrete -= *low_res_value_discrete * WLR_POINTER_AXIS_DISCRETE_STEP; + *low_res_value = *acc_axis; + *acc_axis = 0; + } +} + void wlr_seat_pointer_send_axis(struct wlr_seat *wlr_seat, uint32_t time, enum wlr_axis_orientation orientation, double value, int32_t value_discrete, enum wlr_axis_source source) { @@ -287,6 +326,11 @@ void wlr_seat_pointer_send_axis(struct wlr_seat *wlr_seat, uint32_t time, send_source = true; } + double low_res_value; + int32_t low_res_value_discrete = 0; + update_value120_accumulators(client, orientation, value, value_discrete, + &low_res_value, &low_res_value_discrete); + struct wl_resource *resource; wl_resource_for_each(resource, &client->pointers) { if (wlr_seat_client_from_pointer_resource(resource) == NULL) { @@ -295,18 +339,39 @@ void wlr_seat_pointer_send_axis(struct wlr_seat *wlr_seat, uint32_t time, uint32_t version = wl_resource_get_version(resource); + if (version < WL_POINTER_AXIS_VALUE120_SINCE_VERSION && + value_discrete != 0 && low_res_value_discrete == 0) { + // The client doesn't support high resolution discrete scrolling + // and we haven't accumulated enough wheel clicks for a single + // low resolution event. Don't send anything. + continue; + } + if (send_source && version >= WL_POINTER_AXIS_SOURCE_SINCE_VERSION) { wl_pointer_send_axis_source(resource, source); } if (value) { - if (value_discrete && - version >= WL_POINTER_AXIS_DISCRETE_SINCE_VERSION) { - wl_pointer_send_axis_discrete(resource, orientation, - value_discrete); + if (value_discrete) { + if (version >= WL_POINTER_AXIS_VALUE120_SINCE_VERSION) { + // High resolution discrete scrolling + wl_pointer_send_axis_value120(resource, orientation, + value_discrete); + wl_pointer_send_axis(resource, time, orientation, + wl_fixed_from_double(value)); + } else { + // Low resolution discrete scrolling + if (version >= WL_POINTER_AXIS_DISCRETE_SINCE_VERSION) { + wl_pointer_send_axis_discrete(resource, orientation, + low_res_value_discrete); + } + wl_pointer_send_axis(resource, time, orientation, + wl_fixed_from_double(low_res_value)); + } + } else { + // Continuous scrolling + wl_pointer_send_axis(resource, time, orientation, + wl_fixed_from_double(value)); } - - wl_pointer_send_axis(resource, time, orientation, - wl_fixed_from_double(value)); } else if (version >= WL_POINTER_AXIS_STOP_SINCE_VERSION) { wl_pointer_send_axis_stop(resource, time, orientation); } @@ -337,14 +402,14 @@ void wlr_seat_pointer_start_grab(struct wlr_seat *wlr_seat, grab->seat = wlr_seat; wlr_seat->pointer_state.grab = grab; - wlr_signal_emit_safe(&wlr_seat->events.pointer_grab_begin, grab); + wl_signal_emit_mutable(&wlr_seat->events.pointer_grab_begin, grab); } void wlr_seat_pointer_end_grab(struct wlr_seat *wlr_seat) { struct wlr_seat_pointer_grab *grab = wlr_seat->pointer_state.grab; if (grab != wlr_seat->pointer_state.default_grab) { wlr_seat->pointer_state.grab = wlr_seat->pointer_state.default_grab; - wlr_signal_emit_safe(&wlr_seat->events.pointer_grab_end, grab); + wl_signal_emit_mutable(&wlr_seat->events.pointer_grab_end, grab); if (grab->interface->cancel) { grab->interface->cancel(grab); } diff --git a/types/seat/wlr_seat_touch.c b/types/seat/wlr_seat_touch.c index 99c50cf88..9b533c07b 100644 --- a/types/seat/wlr_seat_touch.c +++ b/types/seat/wlr_seat_touch.c @@ -5,10 +5,8 @@ #include #include #include -#include #include #include "types/wlr_seat.h" -#include "util/signal.h" static uint32_t default_touch_down(struct wlr_seat_touch_grab *grab, uint32_t time, struct wlr_touch_point *point) { @@ -42,6 +40,11 @@ static void default_touch_cancel(struct wlr_seat_touch_grab *grab) { // cannot be cancelled } +static void default_touch_wl_cancel(struct wlr_seat_touch_grab *grab, + struct wlr_surface *surface) { + wlr_seat_touch_send_cancel(grab->seat, surface); +} + const struct wlr_touch_grab_interface default_touch_grab_impl = { .down = default_touch_down, .up = default_touch_up, @@ -49,6 +52,7 @@ const struct wlr_touch_grab_interface default_touch_grab_impl = { .enter = default_touch_enter, .frame = default_touch_frame, .cancel = default_touch_cancel, + .wl_cancel = default_touch_wl_cancel, }; @@ -79,7 +83,7 @@ void wlr_seat_touch_start_grab(struct wlr_seat *wlr_seat, grab->seat = wlr_seat; wlr_seat->touch_state.grab = grab; - wlr_signal_emit_safe(&wlr_seat->events.touch_grab_begin, grab); + wl_signal_emit_mutable(&wlr_seat->events.touch_grab_begin, grab); } void wlr_seat_touch_end_grab(struct wlr_seat *wlr_seat) { @@ -87,7 +91,7 @@ void wlr_seat_touch_end_grab(struct wlr_seat *wlr_seat) { if (grab != wlr_seat->touch_state.default_grab) { wlr_seat->touch_state.grab = wlr_seat->touch_state.default_grab; - wlr_signal_emit_safe(&wlr_seat->events.touch_grab_end, grab); + wl_signal_emit_mutable(&wlr_seat->events.touch_grab_end, grab); if (grab->interface->cancel) { grab->interface->cancel(grab); } @@ -103,7 +107,7 @@ static void touch_point_clear_focus(struct wlr_touch_point *point) { } static void touch_point_destroy(struct wlr_touch_point *point) { - wlr_signal_emit_safe(&point->events.destroy, point); + wl_signal_emit_mutable(&point->events.destroy, point); touch_point_clear_focus(point); wl_list_remove(&point->surface_destroy.link); @@ -239,6 +243,26 @@ void wlr_seat_touch_notify_frame(struct wlr_seat *seat) { } } +void wlr_seat_touch_notify_cancel(struct wlr_seat *seat, + struct wlr_surface *surface) { + struct wlr_seat_touch_grab *grab = seat->touch_state.grab; + if (grab->interface->wl_cancel) { + grab->interface->wl_cancel(grab, surface); + } + + struct wl_client *client = wl_resource_get_client(surface->resource); + struct wlr_seat_client *seat_client = wlr_seat_client_for_wl_client(seat, client); + if (seat_client == NULL) { + return; + } + struct wlr_touch_point *point, *tmp; + wl_list_for_each_safe(point, tmp, &seat->touch_state.touch_points, link) { + if (point->client == seat_client) { + touch_point_destroy(point); + } + } +} + static void handle_point_focus_destroy(struct wl_listener *listener, void *data) { struct wlr_touch_point *point = @@ -377,6 +401,22 @@ void wlr_seat_touch_send_frame(struct wlr_seat *seat) { } } +void wlr_seat_touch_send_cancel(struct wlr_seat *seat, struct wlr_surface *surface) { + struct wl_client *client = wl_resource_get_client(surface->resource); + struct wlr_seat_client *seat_client = wlr_seat_client_for_wl_client(seat, client); + if (seat_client == NULL) { + return; + } + + struct wl_resource *resource; + wl_resource_for_each(resource, &seat_client->touches) { + if (seat_client_from_touch_resource(resource) == NULL) { + continue; + } + wl_touch_send_cancel(resource); + } +} + int wlr_seat_touch_num_points(struct wlr_seat *seat) { return wl_list_length(&seat->touch_state.touch_points); } diff --git a/types/tablet_v2/wlr_tablet_v2.c b/types/tablet_v2/wlr_tablet_v2.c index 3bd333119..63bce2f72 100644 --- a/types/tablet_v2/wlr_tablet_v2.c +++ b/types/tablet_v2/wlr_tablet_v2.c @@ -13,7 +13,6 @@ #include #include #include "tablet-unstable-v2-protocol.h" -#include "util/signal.h" #define TABLET_MANAGER_VERSION 1 @@ -275,7 +274,7 @@ static void tablet_v2_bind(struct wl_client *wl_client, void *data, static void handle_display_destroy(struct wl_listener *listener, void *data) { struct wlr_tablet_manager_v2 *manager = wl_container_of(listener, manager, display_destroy); - wlr_signal_emit_safe(&manager->events.destroy, manager); + wl_signal_emit_mutable(&manager->events.destroy, manager); wl_list_remove(&manager->display_destroy.link); wl_global_destroy(manager->wl_global); free(manager); diff --git a/types/tablet_v2/wlr_tablet_v2_pad.c b/types/tablet_v2/wlr_tablet_v2_pad.c index 58094f575..1bdb4ab76 100644 --- a/types/tablet_v2/wlr_tablet_v2_pad.c +++ b/types/tablet_v2/wlr_tablet_v2_pad.c @@ -2,7 +2,6 @@ #define _POSIX_C_SOURCE 200809L #endif -#include "tablet-unstable-v2-protocol.h" #include #include #include @@ -12,6 +11,7 @@ #include #include #include +#include "tablet-unstable-v2-protocol.h" static const struct wlr_tablet_pad_v2_grab_interface default_pad_grab_interface; @@ -49,9 +49,9 @@ static void handle_tablet_pad_ring_v2_set_feedback(struct wl_client *client, .serial = serial, .description = description, .index = aux->index - }; + }; - wl_signal_emit(&aux->pad->pad->events.ring_feedback, &evt); + wl_signal_emit_mutable(&aux->pad->pad->events.ring_feedback, &evt); } static void handle_tablet_pad_ring_v2_destroy(struct wl_client *client, @@ -87,9 +87,9 @@ static void handle_tablet_pad_strip_v2_set_feedback(struct wl_client *client, .serial = serial, .description = description, .index = aux->index - }; + }; - wl_signal_emit(&aux->pad->pad->events.strip_feedback, &evt); + wl_signal_emit_mutable(&aux->pad->pad->events.strip_feedback, &evt); } static void handle_tablet_pad_strip_v2_destroy(struct wl_client *client, @@ -114,9 +114,9 @@ static void handle_tablet_pad_v2_set_feedback( struct wl_client *client, .serial = serial, .index = button, .description = description, - }; + }; - wl_signal_emit(&pad->pad->events.button_feedback, &evt); + wl_signal_emit_mutable(&pad->pad->events.button_feedback, &evt); } static const struct zwp_tablet_pad_v2_interface tablet_pad_impl = { @@ -375,7 +375,7 @@ struct wlr_tablet_v2_tablet_pad *wlr_tablet_pad_create( if (!seat) { return NULL; } - struct wlr_tablet_pad *wlr_pad = wlr_device->tablet_pad; + struct wlr_tablet_pad *wlr_pad = wlr_tablet_pad_from_input_device(wlr_device); struct wlr_tablet_v2_tablet_pad *pad = calloc(1, sizeof(struct wlr_tablet_v2_tablet_pad)); if (!pad) { return NULL; diff --git a/types/tablet_v2/wlr_tablet_v2_tablet.c b/types/tablet_v2/wlr_tablet_v2_tablet.c index 1d3c08fd4..38668fda1 100644 --- a/types/tablet_v2/wlr_tablet_v2_tablet.c +++ b/types/tablet_v2/wlr_tablet_v2_tablet.c @@ -60,7 +60,7 @@ struct wlr_tablet_v2_tablet *wlr_tablet_create( if (!seat) { return NULL; } - struct wlr_tablet *wlr_tablet = wlr_device->tablet; + struct wlr_tablet *wlr_tablet = wlr_tablet_from_input_device(wlr_device); struct wlr_tablet_v2_tablet *tablet = calloc(1, sizeof(struct wlr_tablet_v2_tablet)); if (!tablet) { return NULL; @@ -108,9 +108,9 @@ void add_tablet_client(struct wlr_tablet_seat_client_v2 *seat, zwp_tablet_seat_v2_send_tablet_added(seat->resource, client->resource); // Send the expected events - if (tablet->wlr_tablet->name) { + if (tablet->wlr_tablet->base.name) { zwp_tablet_v2_send_name(client->resource, - tablet->wlr_tablet->name); + tablet->wlr_tablet->base.name); } zwp_tablet_v2_send_id(client->resource, tablet->wlr_device->vendor, tablet->wlr_device->product); diff --git a/types/tablet_v2/wlr_tablet_v2_tool.c b/types/tablet_v2/wlr_tablet_v2_tool.c index 9e5b9658a..df8ab7618 100644 --- a/types/tablet_v2/wlr_tablet_v2_tool.c +++ b/types/tablet_v2/wlr_tablet_v2_tool.c @@ -2,9 +2,6 @@ #define _POSIX_C_SOURCE 200809L #endif -#include "tablet-unstable-v2-protocol.h" -#include "util/array.h" -#include "util/time.h" #include #include #include @@ -13,6 +10,9 @@ #include #include #include +#include "util/set.h" +#include "util/time.h" +#include "tablet-unstable-v2-protocol.h" static const struct wlr_tablet_tool_v2_grab_interface default_tool_grab_interface; @@ -46,7 +46,7 @@ static void handle_tablet_tool_v2_set_cursor(struct wl_client *client, .seat_client = tool->seat->seat_client, }; - wl_signal_emit(&tool->tool->events.set_cursor, &evt); + wl_signal_emit_mutable(&tool->tool->events.set_cursor, &evt); } static void handle_tablet_tool_v2_destroy(struct wl_client *client, @@ -257,50 +257,26 @@ struct wlr_tablet_tool_client_v2 *tablet_tool_client_from_resource(struct wl_res return wl_resource_get_user_data(resource); } - -/* Actual protocol foo */ - -// Button 0 is KEY_RESERVED in input-event-codes on linux (and freebsd) static ssize_t tablet_tool_button_update(struct wlr_tablet_v2_tablet_tool *tool, uint32_t button, enum zwp_tablet_pad_v2_button_state state) { - bool found = false; - size_t i = 0; - for (; i < tool->num_buttons; ++i) { - if (tool->pressed_buttons[i] == button) { - found = true; - wlr_log(WLR_DEBUG, "Found the button \\o/: %u", button); - break; - - } - } - - if (state == ZWP_TABLET_PAD_V2_BUTTON_STATE_PRESSED && found) { - /* Already have the button saved, durr */ - return -1; - } - - if (state == ZWP_TABLET_PAD_V2_BUTTON_STATE_PRESSED && !found) { - if (tool->num_buttons < WLR_TABLET_V2_TOOL_BUTTONS_CAP) { - i = tool->num_buttons++; - tool->pressed_buttons[i] = button; + ssize_t i; + if (state == ZWP_TABLET_PAD_V2_BUTTON_STATE_PRESSED) { + i = set_add(tool->pressed_buttons, &tool->num_buttons, + WLR_TABLET_V2_TOOL_BUTTONS_CAP, button); + if (i != -1) { tool->pressed_serials[i] = -1; } else { - i = -1; - wlr_log(WLR_ERROR, "You pressed more than %d tablet tool buttons. " - "This is currently not supported by wlroots. Please report this " - "with a description of your tablet, since this is either a " - "bug, or fancy hardware", WLR_TABLET_V2_TOOL_BUTTONS_CAP); + wlr_log(WLR_ERROR, "Failed to add tablet tool button %x", button); + } + } else { + i = set_remove(tool->pressed_buttons, &tool->num_buttons, + WLR_TABLET_V2_TOOL_BUTTONS_CAP, button); + if (i != -1) { + tool->pressed_serials[i] = tool->pressed_serials[tool->num_buttons]; + } else { + wlr_log(WLR_ERROR, "Failed to remove tablet tool button %x", button); } } - if (state == ZWP_TABLET_PAD_V2_BUTTON_STATE_RELEASED && found) { - wlr_log(WLR_DEBUG, "Removed the button \\o/: %u", button); - tool->pressed_buttons[i] = 0; - tool->pressed_serials[i] = 0; - tool->num_buttons = push_zeroes_to_end(tool->pressed_buttons, WLR_TABLET_V2_TOOL_BUTTONS_CAP); - tool->num_buttons = push_zeroes_to_end(tool->pressed_serials, WLR_TABLET_V2_TOOL_BUTTONS_CAP); - } - - assert(tool->num_buttons <= WLR_TABLET_V2_TOOL_BUTTONS_CAP); return i; } diff --git a/types/wlr_buffer.c b/types/wlr_buffer.c index fa281c682..90bc40a8c 100644 --- a/types/wlr_buffer.c +++ b/types/wlr_buffer.c @@ -1,6 +1,7 @@ #include #include #include +#include #include #include #include @@ -8,7 +9,6 @@ #include #include "render/pixel_format.h" #include "types/wlr_buffer.h" -#include "util/signal.h" void wlr_buffer_init(struct wlr_buffer *buffer, const struct wlr_buffer_impl *impl, int width, int height) { @@ -16,6 +16,8 @@ void wlr_buffer_init(struct wlr_buffer *buffer, if (impl->begin_data_ptr_access || impl->end_data_ptr_access) { assert(impl->begin_data_ptr_access && impl->end_data_ptr_access); } + + memset(buffer, 0, sizeof(*buffer)); buffer->impl = impl; buffer->width = width; buffer->height = height; @@ -31,7 +33,7 @@ static void buffer_consider_destroy(struct wlr_buffer *buffer) { assert(!buffer->accessing_data_ptr); - wlr_signal_emit_safe(&buffer->events.destroy, NULL); + wl_signal_emit_mutable(&buffer->events.destroy, NULL); wlr_addon_set_finish(&buffer->addons); buffer->impl->destroy(buffer); @@ -61,7 +63,7 @@ void wlr_buffer_unlock(struct wlr_buffer *buffer) { buffer->n_locks--; if (buffer->n_locks == 0) { - wl_signal_emit(&buffer->events.release, NULL); + wl_signal_emit_mutable(&buffer->events.release, NULL); } buffer_consider_destroy(buffer); @@ -234,6 +236,32 @@ struct wlr_buffer *wlr_buffer_from_resource(struct wl_resource *resource) { return buffer; } +bool buffer_is_opaque(struct wlr_buffer *buffer) { + void *data; + uint32_t format; + size_t stride; + struct wlr_dmabuf_attributes dmabuf; + struct wlr_shm_attributes shm; + if (wlr_buffer_get_dmabuf(buffer, &dmabuf)) { + format = dmabuf.format; + } else if (wlr_buffer_get_shm(buffer, &shm)) { + format = shm.format; + } else if (wlr_buffer_begin_data_ptr_access(buffer, + WLR_BUFFER_DATA_PTR_ACCESS_READ, &data, &format, &stride)) { + wlr_buffer_end_data_ptr_access(buffer); + } else { + return false; + } + + const struct wlr_pixel_format_info *format_info = + drm_get_pixel_format_info(format); + if (format_info == NULL) { + return false; + } + + return !format_info->has_alpha; +} + struct wlr_client_buffer *wlr_client_buffer_create(struct wlr_buffer *buffer, struct wlr_renderer *renderer) { struct wlr_texture *texture = wlr_texture_from_buffer(renderer, buffer); @@ -256,14 +284,6 @@ struct wlr_client_buffer *wlr_client_buffer_create(struct wlr_buffer *buffer, wl_signal_add(&buffer->events.destroy, &client_buffer->source_destroy); client_buffer->source_destroy.notify = client_buffer_handle_source_destroy; - if (buffer_is_shm_client_buffer(buffer)) { - struct wlr_shm_client_buffer *shm_client_buffer = - shm_client_buffer_from_buffer(buffer); - client_buffer->shm_source_format = shm_client_buffer->format; - } else { - client_buffer->shm_source_format = DRM_FORMAT_INVALID; - } - // Ensure the buffer will be released before being destroyed wlr_buffer_lock(&client_buffer->base); wlr_buffer_drop(&client_buffer->base); @@ -278,46 +298,7 @@ bool wlr_client_buffer_apply_damage(struct wlr_client_buffer *client_buffer, return false; } - if ((uint32_t)next->width != client_buffer->texture->width || - (uint32_t)next->height != client_buffer->texture->height) { - return false; - } - - if (client_buffer->shm_source_format == DRM_FORMAT_INVALID) { - // Uploading only damaged regions only works for wl_shm buffers and - // mutable textures (created from wl_shm buffer) - return false; - } - - void *data; - uint32_t format; - size_t stride; - if (!wlr_buffer_begin_data_ptr_access(next, WLR_BUFFER_DATA_PTR_ACCESS_READ, - &data, &format, &stride)) { - return false; - } - - if (format != client_buffer->shm_source_format) { - // Uploading to textures can't change the format - wlr_buffer_end_data_ptr_access(next); - return false; - } - - int n; - pixman_box32_t *rects = pixman_region32_rectangles(damage, &n); - for (int i = 0; i < n; ++i) { - pixman_box32_t *r = &rects[i]; - if (!wlr_texture_write_pixels(client_buffer->texture, stride, - r->x2 - r->x1, r->y2 - r->y1, r->x1, r->y1, - r->x1, r->y1, data)) { - wlr_buffer_end_data_ptr_access(next); - return false; - } - } - - wlr_buffer_end_data_ptr_access(next); - - return true; + return wlr_texture_update_from_buffer(client_buffer->texture, next, damage); } static const struct wlr_buffer_impl shm_client_buffer_impl; diff --git a/types/wlr_compositor.c b/types/wlr_compositor.c index bb4275ef3..f6bbcd029 100644 --- a/types/wlr_compositor.c +++ b/types/wlr_compositor.c @@ -10,11 +10,11 @@ #include #include #include +#include "types/wlr_buffer.h" #include "types/wlr_region.h" -#include "util/signal.h" #include "util/time.h" -#define COMPOSITOR_VERSION 4 +#define COMPOSITOR_VERSION 5 #define CALLBACK_VERSION 1 static int min(int fst, int snd) { @@ -43,6 +43,14 @@ static void surface_handle_attach(struct wl_client *client, struct wl_resource *buffer_resource, int32_t dx, int32_t dy) { struct wlr_surface *surface = wlr_surface_from_resource(resource); + if (wl_resource_get_version(resource) >= WL_SURFACE_OFFSET_SINCE_VERSION && + (dx != 0 || dy != 0)) { + wl_resource_post_error(resource, WL_SURFACE_ERROR_INVALID_OFFSET, + "Offset must be zero on wl_surface.attach version >= %"PRIu32, + WL_SURFACE_OFFSET_SINCE_VERSION); + return; + } + struct wlr_buffer *buffer = NULL; if (buffer_resource != NULL) { buffer = wlr_buffer_from_resource(buffer_resource); @@ -53,11 +61,15 @@ static void surface_handle_attach(struct wl_client *client, } surface->pending.committed |= WLR_SURFACE_STATE_BUFFER; - surface->pending.dx = dx; - surface->pending.dy = dy; wlr_buffer_unlock(surface->pending.buffer); surface->pending.buffer = buffer; + + if (wl_resource_get_version(resource) < WL_SURFACE_OFFSET_SINCE_VERSION) { + surface->pending.committed |= WLR_SURFACE_STATE_OFFSET; + surface->pending.dx = dx; + surface->pending.dy = dy; + } } static void surface_handle_damage(struct wl_client *client, @@ -176,12 +188,21 @@ static void surface_finalize_pending(struct wlr_surface *surface) { if (!pending->viewport.has_src && (pending->buffer_width % pending->scale != 0 || pending->buffer_height % pending->scale != 0)) { - // TODO: send WL_SURFACE_ERROR_INVALID_SIZE error once this issue is - // resolved: + // TODO: send WL_SURFACE_ERROR_INVALID_SIZE error to cursor surfaces + // once this issue is resolved: // https://gitlab.freedesktop.org/wayland/wayland/-/issues/194 - wlr_log(WLR_DEBUG, "Client bug: submitted a buffer whose size (%dx%d) " - "is not divisible by scale (%d)", pending->buffer_width, - pending->buffer_height, pending->scale); + if (!surface->role + || strcmp(surface->role->name, "wl_pointer-cursor") == 0 + || strcmp(surface->role->name, "wp_tablet_tool-cursor") == 0) { + wlr_log(WLR_DEBUG, "Client bug: submitted a buffer whose size (%dx%d) " + "is not divisible by scale (%d)", pending->buffer_width, + pending->buffer_height, pending->scale); + } else { + wl_resource_post_error(surface->resource, + WL_SURFACE_ERROR_INVALID_SIZE, + "Buffer size (%dx%d) is not divisible by scale (%d)", + pending->buffer_width, pending->buffer_height, pending->scale); + } } if (pending->viewport.has_dst) { @@ -209,10 +230,7 @@ static void surface_update_damage(pixman_region32_t *buffer_damage, if (pending->width != current->width || pending->height != current->height || - pending->viewport.src.x != current->viewport.src.x || - pending->viewport.src.y != current->viewport.src.y || - pending->viewport.src.width != current->viewport.src.width || - pending->viewport.src.height != current->viewport.src.height) { + !wlr_fbox_equal(&pending->viewport.src, ¤t->viewport.src)) { // Damage the whole buffer on resize or viewport source box change pixman_region32_union_rect(buffer_damage, buffer_damage, 0, 0, pending->buffer_width, pending->buffer_height); @@ -269,11 +287,14 @@ static void surface_state_move(struct wlr_surface_state *state, if (next->committed & WLR_SURFACE_STATE_TRANSFORM) { state->transform = next->transform; } - if (next->committed & WLR_SURFACE_STATE_BUFFER) { + if (next->committed & WLR_SURFACE_STATE_OFFSET) { state->dx = next->dx; state->dy = next->dy; next->dx = next->dy = 0; - + } else { + state->dx = state->dy = 0; + } + if (next->committed & WLR_SURFACE_STATE_BUFFER) { wlr_buffer_unlock(state->buffer); state->buffer = NULL; if (next->buffer) { @@ -281,8 +302,6 @@ static void surface_state_move(struct wlr_surface_state *state, } wlr_buffer_unlock(next->buffer); next->buffer = NULL; - } else { - state->dx = state->dy = 0; } if (next->committed & WLR_SURFACE_STATE_SURFACE_DAMAGE) { pixman_region32_copy(&state->surface_damage, &next->surface_damage); @@ -327,9 +346,12 @@ static void surface_apply_damage(struct wlr_surface *surface) { wlr_buffer_unlock(&surface->buffer->base); } surface->buffer = NULL; + surface->opaque = false; return; } + surface->opaque = buffer_is_opaque(surface->current.buffer); + if (surface->buffer != NULL) { if (wlr_client_buffer_apply_damage(surface->buffer, surface->current.buffer, &surface->buffer_damage)) { @@ -363,7 +385,8 @@ static void surface_update_opaque_region(struct wlr_surface *surface) { return; } - if (wlr_texture_is_opaque(texture)) { + if (surface->opaque) { + pixman_region32_fini(&surface->opaque_region); pixman_region32_init_rect(&surface->opaque_region, 0, 0, surface->current.width, surface->current.height); return; @@ -466,7 +489,7 @@ static void surface_commit_state(struct wlr_surface *surface, surface->role->commit(surface); } - wlr_signal_emit_safe(&surface->events.commit, surface); + wl_signal_emit_mutable(&surface->events.commit, surface); } static void collect_subsurface_damage_iter(struct wlr_surface *surface, @@ -505,7 +528,7 @@ static void subsurface_parent_commit(struct wlr_subsurface *subsurface) { if (!subsurface->added) { subsurface->added = true; - wlr_signal_emit_safe(&subsurface->parent->events.new_subsurface, + wl_signal_emit_mutable(&subsurface->parent->events.new_subsurface, subsurface); } } @@ -515,7 +538,7 @@ static void surface_handle_commit(struct wl_client *client, struct wlr_surface *surface = wlr_surface_from_resource(resource); surface_finalize_pending(surface); - wlr_signal_emit_safe(&surface->events.client_commit, NULL); + wl_signal_emit_mutable(&surface->events.client_commit, NULL); if (surface->pending.cached_state_locks > 0 || !wl_list_empty(&surface->cached)) { surface_cache_pending(surface); @@ -563,6 +586,15 @@ static void surface_handle_damage_buffer(struct wl_client *client, x, y, width, height); } +static void surface_handle_offset(struct wl_client *client, + struct wl_resource *resource, int32_t x, int32_t y) { + struct wlr_surface *surface = wlr_surface_from_resource(resource); + + surface->pending.committed |= WLR_SURFACE_STATE_OFFSET; + surface->pending.dx = x; + surface->pending.dy = y; +} + static const struct wl_surface_interface surface_implementation = { .destroy = surface_handle_destroy, .attach = surface_handle_attach, @@ -573,7 +605,8 @@ static const struct wl_surface_interface surface_implementation = { .commit = surface_handle_commit, .set_buffer_transform = surface_handle_set_buffer_transform, .set_buffer_scale = surface_handle_set_buffer_scale, - .damage_buffer = surface_handle_damage_buffer + .damage_buffer = surface_handle_damage_buffer, + .offset = surface_handle_offset, }; struct wlr_surface *wlr_surface_from_resource(struct wl_resource *resource) { @@ -583,6 +616,8 @@ struct wlr_surface *wlr_surface_from_resource(struct wl_resource *resource) { } static void surface_state_init(struct wlr_surface_state *state) { + memset(state, 0, sizeof(*state)); + state->scale = 1; state->transform = WL_OUTPUT_TRANSFORM_NORMAL; @@ -629,7 +664,7 @@ static void surface_handle_resource_destroy(struct wl_resource *resource) { surface_output_destroy(surface_output); } - wlr_signal_emit_safe(&surface->events.destroy, surface); + wl_signal_emit_mutable(&surface->events.destroy, surface); wlr_addon_set_finish(&surface->addons); @@ -1088,7 +1123,7 @@ static void compositor_create_surface(struct wl_client *client, return; } - wlr_signal_emit_safe(&compositor->events.new_surface, surface); + wl_signal_emit_mutable(&compositor->events.new_surface, surface); } static void compositor_create_region(struct wl_client *client, @@ -1118,7 +1153,7 @@ static void compositor_handle_display_destroy( struct wl_listener *listener, void *data) { struct wlr_compositor *compositor = wl_container_of(listener, compositor, display_destroy); - wlr_signal_emit_safe(&compositor->events.destroy, NULL); + wl_signal_emit_mutable(&compositor->events.destroy, NULL); wl_list_remove(&compositor->display_destroy.link); wl_global_destroy(compositor->global); free(compositor); diff --git a/types/wlr_cursor.c b/types/wlr_cursor.c index 3160ca03b..aafae2482 100644 --- a/types/wlr_cursor.c +++ b/types/wlr_cursor.c @@ -12,7 +12,6 @@ #include #include #include -#include "util/signal.h" struct wlr_cursor_device { struct wlr_cursor *cursor; @@ -237,19 +236,22 @@ static void cursor_warp_unchecked(struct wlr_cursor *cur, * Absolute movement for touch and pen devices will be relative to this box and * pointer movement will be constrained to this box. * - * If none of these are set, empties the box and absolute movement should be + * If none of these are set, the box is empty and absolute movement should be * relative to the extents of the layout. */ static void get_mapping(struct wlr_cursor *cur, struct wlr_input_device *dev, struct wlr_box *box) { assert(cur->state->layout); - struct wlr_cursor_device *c_device = get_cursor_device(cur, dev); + memset(box, 0, sizeof(*box)); + + struct wlr_cursor_device *c_device = get_cursor_device(cur, dev); if (c_device) { if (!wlr_box_empty(&c_device->mapped_box)) { *box = c_device->mapped_box; return; - } else if (c_device->mapped_output) { + } + if (c_device->mapped_output) { wlr_output_layout_get_box(cur->state->layout, c_device->mapped_output, box); return; @@ -258,11 +260,12 @@ static void get_mapping(struct wlr_cursor *cur, if (!wlr_box_empty(&cur->state->mapped_box)) { *box = cur->state->mapped_box; - } else if (cur->state->mapped_output) { + return; + } + if (cur->state->mapped_output) { wlr_output_layout_get_box(cur->state->layout, cur->state->mapped_output, box); - } else { - box->width = box->height = 0; + return; } } @@ -365,10 +368,10 @@ void wlr_cursor_set_surface(struct wlr_cursor *cur, struct wlr_surface *surface, } static void handle_pointer_motion(struct wl_listener *listener, void *data) { - struct wlr_event_pointer_motion *event = data; + struct wlr_pointer_motion_event *event = data; struct wlr_cursor_device *device = wl_container_of(listener, device, motion); - wlr_signal_emit_safe(&device->cursor->events.motion, event); + wl_signal_emit_mutable(&device->cursor->events.motion, event); } static void apply_output_transform(double *x, double *y, @@ -431,7 +434,7 @@ static struct wlr_output *get_mapped_output(struct wlr_cursor_device *cursor_dev static void handle_pointer_motion_absolute(struct wl_listener *listener, void *data) { - struct wlr_event_pointer_motion_absolute *event = data; + struct wlr_pointer_motion_absolute_event *event = data; struct wlr_cursor_device *device = wl_container_of(listener, device, motion_absolute); @@ -440,84 +443,84 @@ static void handle_pointer_motion_absolute(struct wl_listener *listener, if (output) { apply_output_transform(&event->x, &event->y, output->transform); } - wlr_signal_emit_safe(&device->cursor->events.motion_absolute, event); + wl_signal_emit_mutable(&device->cursor->events.motion_absolute, event); } static void handle_pointer_button(struct wl_listener *listener, void *data) { - struct wlr_event_pointer_button *event = data; + struct wlr_pointer_button_event *event = data; struct wlr_cursor_device *device = wl_container_of(listener, device, button); - wlr_signal_emit_safe(&device->cursor->events.button, event); + wl_signal_emit_mutable(&device->cursor->events.button, event); } static void handle_pointer_axis(struct wl_listener *listener, void *data) { - struct wlr_event_pointer_axis *event = data; + struct wlr_pointer_axis_event *event = data; struct wlr_cursor_device *device = wl_container_of(listener, device, axis); - wlr_signal_emit_safe(&device->cursor->events.axis, event); + wl_signal_emit_mutable(&device->cursor->events.axis, event); } static void handle_pointer_frame(struct wl_listener *listener, void *data) { struct wlr_cursor_device *device = wl_container_of(listener, device, frame); - wlr_signal_emit_safe(&device->cursor->events.frame, device->cursor); + wl_signal_emit_mutable(&device->cursor->events.frame, device->cursor); } static void handle_pointer_swipe_begin(struct wl_listener *listener, void *data) { - struct wlr_event_pointer_swipe_begin *event = data; + struct wlr_pointer_swipe_begin_event *event = data; struct wlr_cursor_device *device = wl_container_of(listener, device, swipe_begin); - wlr_signal_emit_safe(&device->cursor->events.swipe_begin, event); + wl_signal_emit_mutable(&device->cursor->events.swipe_begin, event); } static void handle_pointer_swipe_update(struct wl_listener *listener, void *data) { - struct wlr_event_pointer_swipe_update *event = data; + struct wlr_pointer_swipe_update_event *event = data; struct wlr_cursor_device *device = wl_container_of(listener, device, swipe_update); - wlr_signal_emit_safe(&device->cursor->events.swipe_update, event); + wl_signal_emit_mutable(&device->cursor->events.swipe_update, event); } static void handle_pointer_swipe_end(struct wl_listener *listener, void *data) { - struct wlr_event_pointer_swipe_end *event = data; + struct wlr_pointer_swipe_end_event *event = data; struct wlr_cursor_device *device = wl_container_of(listener, device, swipe_end); - wlr_signal_emit_safe(&device->cursor->events.swipe_end, event); + wl_signal_emit_mutable(&device->cursor->events.swipe_end, event); } static void handle_pointer_pinch_begin(struct wl_listener *listener, void *data) { - struct wlr_event_pointer_pinch_begin *event = data; + struct wlr_pointer_pinch_begin_event *event = data; struct wlr_cursor_device *device = wl_container_of(listener, device, pinch_begin); - wlr_signal_emit_safe(&device->cursor->events.pinch_begin, event); + wl_signal_emit_mutable(&device->cursor->events.pinch_begin, event); } static void handle_pointer_pinch_update(struct wl_listener *listener, void *data) { - struct wlr_event_pointer_pinch_update *event = data; + struct wlr_pointer_pinch_update_event *event = data; struct wlr_cursor_device *device = wl_container_of(listener, device, pinch_update); - wlr_signal_emit_safe(&device->cursor->events.pinch_update, event); + wl_signal_emit_mutable(&device->cursor->events.pinch_update, event); } static void handle_pointer_pinch_end(struct wl_listener *listener, void *data) { - struct wlr_event_pointer_pinch_end *event = data; + struct wlr_pointer_pinch_end_event *event = data; struct wlr_cursor_device *device = wl_container_of(listener, device, pinch_end); - wlr_signal_emit_safe(&device->cursor->events.pinch_end, event); + wl_signal_emit_mutable(&device->cursor->events.pinch_end, event); } static void handle_pointer_hold_begin(struct wl_listener *listener, void *data) { - struct wlr_event_pointer_hold_begin *event = data; + struct wlr_pointer_hold_begin_event *event = data; struct wlr_cursor_device *device = wl_container_of(listener, device, hold_begin); - wlr_signal_emit_safe(&device->cursor->events.hold_begin, event); + wl_signal_emit_mutable(&device->cursor->events.hold_begin, event); } static void handle_pointer_hold_end(struct wl_listener *listener, void *data) { - struct wlr_event_pointer_hold_end *event = data; + struct wlr_pointer_hold_end_event *event = data; struct wlr_cursor_device *device = wl_container_of(listener, device, hold_end); - wlr_signal_emit_safe(&device->cursor->events.hold_end, event); + wl_signal_emit_mutable(&device->cursor->events.hold_end, event); } static void handle_touch_up(struct wl_listener *listener, void *data) { - struct wlr_event_touch_up *event = data; + struct wlr_touch_up_event *event = data; struct wlr_cursor_device *device; device = wl_container_of(listener, device, touch_up); - wlr_signal_emit_safe(&device->cursor->events.touch_up, event); + wl_signal_emit_mutable(&device->cursor->events.touch_up, event); } static void handle_touch_down(struct wl_listener *listener, void *data) { - struct wlr_event_touch_down *event = data; + struct wlr_touch_down_event *event = data; struct wlr_cursor_device *device; device = wl_container_of(listener, device, touch_down); @@ -526,11 +529,11 @@ static void handle_touch_down(struct wl_listener *listener, void *data) { if (output) { apply_output_transform(&event->x, &event->y, output->transform); } - wlr_signal_emit_safe(&device->cursor->events.touch_down, event); + wl_signal_emit_mutable(&device->cursor->events.touch_down, event); } static void handle_touch_motion(struct wl_listener *listener, void *data) { - struct wlr_event_touch_motion *event = data; + struct wlr_touch_motion_event *event = data; struct wlr_cursor_device *device; device = wl_container_of(listener, device, touch_motion); @@ -539,24 +542,24 @@ static void handle_touch_motion(struct wl_listener *listener, void *data) { if (output) { apply_output_transform(&event->x, &event->y, output->transform); } - wlr_signal_emit_safe(&device->cursor->events.touch_motion, event); + wl_signal_emit_mutable(&device->cursor->events.touch_motion, event); } static void handle_touch_cancel(struct wl_listener *listener, void *data) { - struct wlr_event_touch_cancel *event = data; + struct wlr_touch_cancel_event *event = data; struct wlr_cursor_device *device; device = wl_container_of(listener, device, touch_cancel); - wlr_signal_emit_safe(&device->cursor->events.touch_cancel, event); + wl_signal_emit_mutable(&device->cursor->events.touch_cancel, event); } static void handle_touch_frame(struct wl_listener *listener, void *data) { struct wlr_cursor_device *device = wl_container_of(listener, device, touch_frame); - wlr_signal_emit_safe(&device->cursor->events.touch_frame, NULL); + wl_signal_emit_mutable(&device->cursor->events.touch_frame, NULL); } static void handle_tablet_tool_tip(struct wl_listener *listener, void *data) { - struct wlr_event_tablet_tool_tip *event = data; + struct wlr_tablet_tool_tip_event *event = data; struct wlr_cursor_device *device; device = wl_container_of(listener, device, tablet_tool_tip); @@ -565,11 +568,11 @@ static void handle_tablet_tool_tip(struct wl_listener *listener, void *data) { if (output) { apply_output_transform(&event->x, &event->y, output->transform); } - wlr_signal_emit_safe(&device->cursor->events.tablet_tool_tip, event); + wl_signal_emit_mutable(&device->cursor->events.tablet_tool_tip, event); } static void handle_tablet_tool_axis(struct wl_listener *listener, void *data) { - struct wlr_event_tablet_tool_axis *event = data; + struct wlr_tablet_tool_axis_event *event = data; struct wlr_cursor_device *device; device = wl_container_of(listener, device, tablet_tool_axis); @@ -600,20 +603,20 @@ static void handle_tablet_tool_axis(struct wl_listener *listener, void *data) { } } - wlr_signal_emit_safe(&device->cursor->events.tablet_tool_axis, event); + wl_signal_emit_mutable(&device->cursor->events.tablet_tool_axis, event); } static void handle_tablet_tool_button(struct wl_listener *listener, void *data) { - struct wlr_event_tablet_tool_button *event = data; + struct wlr_tablet_tool_button *event = data; struct wlr_cursor_device *device; device = wl_container_of(listener, device, tablet_tool_button); - wlr_signal_emit_safe(&device->cursor->events.tablet_tool_button, event); + wl_signal_emit_mutable(&device->cursor->events.tablet_tool_button, event); } static void handle_tablet_tool_proximity(struct wl_listener *listener, void *data) { - struct wlr_event_tablet_tool_proximity *event = data; + struct wlr_tablet_tool_proximity_event *event = data; struct wlr_cursor_device *device; device = wl_container_of(listener, device, tablet_tool_proximity); @@ -622,7 +625,7 @@ static void handle_tablet_tool_proximity(struct wl_listener *listener, if (output) { apply_output_transform(&event->x, &event->y, output->transform); } - wlr_signal_emit_safe(&device->cursor->events.tablet_tool_proximity, event); + wl_signal_emit_mutable(&device->cursor->events.tablet_tool_proximity, event); } static void handle_device_destroy(struct wl_listener *listener, void *data) { @@ -648,75 +651,78 @@ static struct wlr_cursor_device *cursor_device_create( c_device->destroy.notify = handle_device_destroy; if (device->type == WLR_INPUT_DEVICE_POINTER) { - wl_signal_add(&device->pointer->events.motion, &c_device->motion); + struct wlr_pointer *pointer = wlr_pointer_from_input_device(device); + + wl_signal_add(&pointer->events.motion, &c_device->motion); c_device->motion.notify = handle_pointer_motion; - wl_signal_add(&device->pointer->events.motion_absolute, + wl_signal_add(&pointer->events.motion_absolute, &c_device->motion_absolute); c_device->motion_absolute.notify = handle_pointer_motion_absolute; - wl_signal_add(&device->pointer->events.button, &c_device->button); + wl_signal_add(&pointer->events.button, &c_device->button); c_device->button.notify = handle_pointer_button; - wl_signal_add(&device->pointer->events.axis, &c_device->axis); + wl_signal_add(&pointer->events.axis, &c_device->axis); c_device->axis.notify = handle_pointer_axis; - wl_signal_add(&device->pointer->events.frame, &c_device->frame); + wl_signal_add(&pointer->events.frame, &c_device->frame); c_device->frame.notify = handle_pointer_frame; - wl_signal_add(&device->pointer->events.swipe_begin, &c_device->swipe_begin); + wl_signal_add(&pointer->events.swipe_begin, &c_device->swipe_begin); c_device->swipe_begin.notify = handle_pointer_swipe_begin; - wl_signal_add(&device->pointer->events.swipe_update, &c_device->swipe_update); + wl_signal_add(&pointer->events.swipe_update, &c_device->swipe_update); c_device->swipe_update.notify = handle_pointer_swipe_update; - wl_signal_add(&device->pointer->events.swipe_end, &c_device->swipe_end); + wl_signal_add(&pointer->events.swipe_end, &c_device->swipe_end); c_device->swipe_end.notify = handle_pointer_swipe_end; - wl_signal_add(&device->pointer->events.pinch_begin, &c_device->pinch_begin); + wl_signal_add(&pointer->events.pinch_begin, &c_device->pinch_begin); c_device->pinch_begin.notify = handle_pointer_pinch_begin; - wl_signal_add(&device->pointer->events.pinch_update, &c_device->pinch_update); + wl_signal_add(&pointer->events.pinch_update, &c_device->pinch_update); c_device->pinch_update.notify = handle_pointer_pinch_update; - wl_signal_add(&device->pointer->events.pinch_end, &c_device->pinch_end); + wl_signal_add(&pointer->events.pinch_end, &c_device->pinch_end); c_device->pinch_end.notify = handle_pointer_pinch_end; - wl_signal_add(&device->pointer->events.hold_begin, &c_device->hold_begin); + wl_signal_add(&pointer->events.hold_begin, &c_device->hold_begin); c_device->hold_begin.notify = handle_pointer_hold_begin; - wl_signal_add(&device->pointer->events.hold_end, &c_device->hold_end); + wl_signal_add(&pointer->events.hold_end, &c_device->hold_end); c_device->hold_end.notify = handle_pointer_hold_end; } else if (device->type == WLR_INPUT_DEVICE_TOUCH) { - wl_signal_add(&device->touch->events.motion, &c_device->touch_motion); + struct wlr_touch *touch = wlr_touch_from_input_device(device); + + wl_signal_add(&touch->events.motion, &c_device->touch_motion); c_device->touch_motion.notify = handle_touch_motion; - wl_signal_add(&device->touch->events.down, &c_device->touch_down); + wl_signal_add(&touch->events.down, &c_device->touch_down); c_device->touch_down.notify = handle_touch_down; - wl_signal_add(&device->touch->events.up, &c_device->touch_up); + wl_signal_add(&touch->events.up, &c_device->touch_up); c_device->touch_up.notify = handle_touch_up; - wl_signal_add(&device->touch->events.cancel, &c_device->touch_cancel); + wl_signal_add(&touch->events.cancel, &c_device->touch_cancel); c_device->touch_cancel.notify = handle_touch_cancel; - wl_signal_add(&device->touch->events.frame, &c_device->touch_frame); + wl_signal_add(&touch->events.frame, &c_device->touch_frame); c_device->touch_frame.notify = handle_touch_frame; } else if (device->type == WLR_INPUT_DEVICE_TABLET_TOOL) { - wl_signal_add(&device->tablet->events.tip, - &c_device->tablet_tool_tip); + struct wlr_tablet *tablet = wlr_tablet_from_input_device(device); + + wl_signal_add(&tablet->events.tip, &c_device->tablet_tool_tip); c_device->tablet_tool_tip.notify = handle_tablet_tool_tip; - wl_signal_add(&device->tablet->events.proximity, + wl_signal_add(&tablet->events.proximity, &c_device->tablet_tool_proximity); c_device->tablet_tool_proximity.notify = handle_tablet_tool_proximity; - wl_signal_add(&device->tablet->events.axis, - &c_device->tablet_tool_axis); + wl_signal_add(&tablet->events.axis, &c_device->tablet_tool_axis); c_device->tablet_tool_axis.notify = handle_tablet_tool_axis; - wl_signal_add(&device->tablet->events.button, - &c_device->tablet_tool_button); + wl_signal_add(&tablet->events.button, &c_device->tablet_tool_button); c_device->tablet_tool_button.notify = handle_tablet_tool_button; } @@ -866,19 +872,21 @@ void wlr_cursor_map_input_to_output(struct wlr_cursor *cur, void wlr_cursor_map_to_region(struct wlr_cursor *cur, const struct wlr_box *box) { + memset(&cur->state->mapped_box, 0, sizeof(cur->state->mapped_box)); + if (box) { if (wlr_box_empty(box)) { wlr_log(WLR_ERROR, "cannot map cursor to an empty region"); return; } cur->state->mapped_box = *box; - } else { - cur->state->mapped_box.width = cur->state->mapped_box.height = 0; } } void wlr_cursor_map_input_to_region(struct wlr_cursor *cur, struct wlr_input_device *dev, const struct wlr_box *box) { + memset(&cur->state->mapped_box, 0, sizeof(cur->state->mapped_box)); + struct wlr_cursor_device *c_device = get_cursor_device(cur, dev); if (!c_device) { wlr_log(WLR_ERROR, "Cannot map device \"%s\" to geometry (not found in" @@ -894,7 +902,5 @@ void wlr_cursor_map_input_to_region(struct wlr_cursor *cur, return; } c_device->mapped_box = *box; - } else { - c_device->mapped_box.width = c_device->mapped_box.height = 0; } } diff --git a/types/wlr_damage_ring.c b/types/wlr_damage_ring.c new file mode 100644 index 000000000..000aba935 --- /dev/null +++ b/types/wlr_damage_ring.c @@ -0,0 +1,112 @@ +#include +#include +#include +#include +#include +#include + +#define WLR_DAMAGE_RING_MAX_RECTS 20 + +void wlr_damage_ring_init(struct wlr_damage_ring *ring) { + memset(ring, 0, sizeof(*ring)); + + ring->width = INT_MAX; + ring->height = INT_MAX; + + pixman_region32_init(&ring->current); + for (size_t i = 0; i < WLR_DAMAGE_RING_PREVIOUS_LEN; ++i) { + pixman_region32_init(&ring->previous[i]); + } +} + +void wlr_damage_ring_finish(struct wlr_damage_ring *ring) { + pixman_region32_fini(&ring->current); + for (size_t i = 0; i < WLR_DAMAGE_RING_PREVIOUS_LEN; ++i) { + pixman_region32_fini(&ring->previous[i]); + } +} + +void wlr_damage_ring_set_bounds(struct wlr_damage_ring *ring, + int32_t width, int32_t height) { + if (width == 0 || height == 0) { + ring->width = INT_MAX; + ring->height = INT_MAX; + } else { + ring->width = width; + ring->height = height; + } + wlr_damage_ring_add_whole(ring); +} + +bool wlr_damage_ring_add(struct wlr_damage_ring *ring, + pixman_region32_t *damage) { + pixman_region32_t clipped; + pixman_region32_init(&clipped); + pixman_region32_intersect_rect(&clipped, damage, + 0, 0, ring->width, ring->height); + bool intersects = pixman_region32_not_empty(&clipped); + if (intersects) { + pixman_region32_union(&ring->current, &ring->current, &clipped); + } + pixman_region32_fini(&clipped); + return intersects; +} + +bool wlr_damage_ring_add_box(struct wlr_damage_ring *ring, + const struct wlr_box *box) { + struct wlr_box clipped = { + .x = 0, + .y = 0, + .width = ring->width, + .height = ring->height, + }; + if (wlr_box_intersection(&clipped, &clipped, box)) { + pixman_region32_union_rect(&ring->current, + &ring->current, clipped.x, clipped.y, + clipped.width, clipped.height); + return true; + } + return false; +} + +void wlr_damage_ring_add_whole(struct wlr_damage_ring *ring) { + pixman_region32_union_rect(&ring->current, + &ring->current, 0, 0, ring->width, ring->height); +} + +void wlr_damage_ring_rotate(struct wlr_damage_ring *ring) { + // modular decrement + ring->previous_idx = ring->previous_idx + + WLR_DAMAGE_RING_PREVIOUS_LEN - 1; + ring->previous_idx %= WLR_DAMAGE_RING_PREVIOUS_LEN; + + pixman_region32_copy(&ring->previous[ring->previous_idx], &ring->current); + pixman_region32_clear(&ring->current); +} + +void wlr_damage_ring_get_buffer_damage(struct wlr_damage_ring *ring, + int buffer_age, pixman_region32_t *damage) { + if (buffer_age <= 0 || buffer_age - 1 > WLR_DAMAGE_RING_PREVIOUS_LEN) { + pixman_region32_clear(damage); + pixman_region32_union_rect(damage, damage, + 0, 0, ring->width, ring->height); + } else { + pixman_region32_copy(damage, &ring->current); + + // Accumulate damage from old buffers + for (int i = 0; i < buffer_age - 1; ++i) { + int j = (ring->previous_idx + i) % WLR_DAMAGE_RING_PREVIOUS_LEN; + pixman_region32_union(damage, damage, &ring->previous[j]); + } + + // Check the number of rectangles + int n_rects = pixman_region32_n_rects(damage); + if (n_rects > WLR_DAMAGE_RING_MAX_RECTS) { + pixman_box32_t *extents = pixman_region32_extents(damage); + pixman_region32_union_rect(damage, damage, + extents->x1, extents->y1, + extents->x2 - extents->x1, + extents->y2 - extents->y1); + } + } +} diff --git a/types/wlr_data_control_v1.c b/types/wlr_data_control_v1.c index 239e238ad..55789d4dc 100644 --- a/types/wlr_data_control_v1.c +++ b/types/wlr_data_control_v1.c @@ -7,7 +7,6 @@ #include #include #include -#include "util/signal.h" #include "wlr-data-control-unstable-v1-protocol.h" #define DATA_CONTROL_MANAGER_VERSION 2 @@ -628,7 +627,7 @@ static void manager_handle_get_data_device(struct wl_client *client, &device->seat_set_primary_selection); wl_list_insert(&manager->devices, &device->link); - wlr_signal_emit_safe(&manager->events.new_device, device); + wl_signal_emit_mutable(&manager->events.new_device, device); // At this point maybe the compositor decided to destroy the device. If // it's the case then the resource will be inert. @@ -666,7 +665,7 @@ static void manager_bind(struct wl_client *client, void *data, uint32_t version, static void handle_display_destroy(struct wl_listener *listener, void *data) { struct wlr_data_control_manager_v1 *manager = wl_container_of(listener, manager, display_destroy); - wlr_signal_emit_safe(&manager->events.destroy, manager); + wl_signal_emit_mutable(&manager->events.destroy, manager); wl_list_remove(&manager->display_destroy.link); wl_global_destroy(manager->global); free(manager); diff --git a/types/wlr_drm.c b/types/wlr_drm.c index a02fba841..32eea1c79 100644 --- a/types/wlr_drm.c +++ b/types/wlr_drm.c @@ -4,13 +4,13 @@ #include #include #include +#include #include #include #include #include #include #include "drm-protocol.h" -#include "util/signal.h" #define WLR_DRM_VERSION 2 @@ -171,7 +171,7 @@ static void drm_bind(struct wl_client *client, void *data, } static void drm_destroy(struct wlr_drm *drm) { - wlr_signal_emit_safe(&drm->events.destroy, NULL); + wl_signal_emit_mutable(&drm->events.destroy, NULL); wl_list_remove(&drm->display_destroy.link); wl_list_remove(&drm->renderer_destroy.link); diff --git a/types/wlr_drm_lease_v1.c b/types/wlr_drm_lease_v1.c index 7cb9974d7..315c5ff9f 100644 --- a/types/wlr_drm_lease_v1.c +++ b/types/wlr_drm_lease_v1.c @@ -9,7 +9,6 @@ #include #include "backend/drm/drm.h" #include "drm-lease-v1-protocol.h" -#include "util/signal.h" #include "util/global.h" #define DRM_LEASE_DEVICE_V1_VERSION 1 @@ -353,7 +352,7 @@ static void drm_lease_request_v1_handle_submit( request->lease = lease; /* TODO: reject the request if the user does not grant it */ - wlr_signal_emit_safe(&request->device->manager->events.request, + wl_signal_emit_mutable(&request->device->manager->events.request, request); /* Request is done */ @@ -621,10 +620,18 @@ static void handle_backend_destroy(struct wl_listener *listener, void *data) { static void drm_lease_device_v1_create(struct wlr_drm_lease_v1_manager *manager, struct wlr_backend *backend) { - assert(backend); + struct wlr_drm_backend *drm_backend = get_drm_backend_from_backend(backend); + + // Make sure we can get a non-master FD for the DRM backend. On some setups + // we don't have the permission for this. + int fd = wlr_drm_backend_get_non_master_fd(backend); + if (fd < 0) { + wlr_log(WLR_INFO, "Skipping %s: failed to get read-only DRM FD", + drm_backend->name); + return; + } + close(fd); - struct wlr_drm_backend *drm_backend = - get_drm_backend_from_backend(backend); wlr_log(WLR_DEBUG, "Creating wlr_drm_lease_device_v1 for %s", drm_backend->name); diff --git a/types/wlr_export_dmabuf_v1.c b/types/wlr_export_dmabuf_v1.c index b47758c63..c1d26e604 100644 --- a/types/wlr_export_dmabuf_v1.c +++ b/types/wlr_export_dmabuf_v1.c @@ -6,7 +6,6 @@ #include #include #include -#include "util/signal.h" #include "wlr-export-dmabuf-unstable-v1-protocol.h" #define EXPORT_DMABUF_MANAGER_VERSION 1 @@ -182,7 +181,7 @@ static void manager_bind(struct wl_client *client, void *data, uint32_t version, static void handle_display_destroy(struct wl_listener *listener, void *data) { struct wlr_export_dmabuf_manager_v1 *manager = wl_container_of(listener, manager, display_destroy); - wlr_signal_emit_safe(&manager->events.destroy, manager); + wl_signal_emit_mutable(&manager->events.destroy, manager); wl_list_remove(&manager->display_destroy.link); wl_global_destroy(manager->global); free(manager); diff --git a/types/wlr_foreign_toplevel_management_v1.c b/types/wlr_foreign_toplevel_management_v1.c index a700a115b..c6fea5b7f 100644 --- a/types/wlr_foreign_toplevel_management_v1.c +++ b/types/wlr_foreign_toplevel_management_v1.c @@ -7,7 +7,6 @@ #include #include #include -#include "util/signal.h" #include "wlr-foreign-toplevel-management-unstable-v1-protocol.h" #define FOREIGN_TOPLEVEL_MANAGEMENT_V1_VERSION 3 @@ -33,7 +32,7 @@ static void toplevel_handle_send_maximized_event(struct wl_resource *resource, .toplevel = toplevel, .maximized = state, }; - wlr_signal_emit_safe(&toplevel->events.request_maximize, &event); + wl_signal_emit_mutable(&toplevel->events.request_maximize, &event); } static void foreign_toplevel_handle_set_maximized(struct wl_client *client, @@ -58,7 +57,7 @@ static void toplevel_send_minimized_event(struct wl_resource *resource, .toplevel = toplevel, .minimized = state, }; - wlr_signal_emit_safe(&toplevel->events.request_minimize, &event); + wl_signal_emit_mutable(&toplevel->events.request_minimize, &event); } static void foreign_toplevel_handle_set_minimized(struct wl_client *client, @@ -88,7 +87,7 @@ static void toplevel_send_fullscreen_event(struct wl_resource *resource, .fullscreen = state, .output = output, }; - wlr_signal_emit_safe(&toplevel->events.request_fullscreen, &event); + wl_signal_emit_mutable(&toplevel->events.request_fullscreen, &event); } static void foreign_toplevel_handle_set_fullscreen(struct wl_client *client, @@ -117,7 +116,7 @@ static void foreign_toplevel_handle_activate(struct wl_client *client, .toplevel = toplevel, .seat = seat_client->seat, }; - wlr_signal_emit_safe(&toplevel->events.request_activate, &event); + wl_signal_emit_mutable(&toplevel->events.request_activate, &event); } static void foreign_toplevel_handle_close(struct wl_client *client, @@ -127,7 +126,7 @@ static void foreign_toplevel_handle_close(struct wl_client *client, if (!toplevel) { return; } - wlr_signal_emit_safe(&toplevel->events.request_close, toplevel); + wl_signal_emit_mutable(&toplevel->events.request_close, toplevel); } static void foreign_toplevel_handle_set_rectangle(struct wl_client *client, @@ -154,7 +153,7 @@ static void foreign_toplevel_handle_set_rectangle(struct wl_client *client, .width = width, .height = height, }; - wlr_signal_emit_safe(&toplevel->events.set_rectangle, &event); + wl_signal_emit_mutable(&toplevel->events.set_rectangle, &event); } static void foreign_toplevel_handle_destroy(struct wl_client *client, @@ -495,7 +494,7 @@ void wlr_foreign_toplevel_handle_v1_destroy( return; } - wlr_signal_emit_safe(&toplevel->events.destroy, toplevel); + wl_signal_emit_mutable(&toplevel->events.destroy, toplevel); struct wl_resource *resource, *tmp; wl_resource_for_each_safe(resource, tmp, &toplevel->resources) { @@ -678,7 +677,7 @@ static void foreign_toplevel_manager_bind(struct wl_client *client, void *data, static void handle_display_destroy(struct wl_listener *listener, void *data) { struct wlr_foreign_toplevel_manager_v1 *manager = wl_container_of(listener, manager, display_destroy); - wlr_signal_emit_safe(&manager->events.destroy, manager); + wl_signal_emit_mutable(&manager->events.destroy, manager); wl_list_remove(&manager->display_destroy.link); wl_global_destroy(manager->global); free(manager); diff --git a/types/wlr_fullscreen_shell_v1.c b/types/wlr_fullscreen_shell_v1.c index 7e9f85539..4d4ded482 100644 --- a/types/wlr_fullscreen_shell_v1.c +++ b/types/wlr_fullscreen_shell_v1.c @@ -4,7 +4,6 @@ #include #include #include -#include "util/signal.h" #define FULLSCREEN_SHELL_VERSION 1 @@ -37,7 +36,7 @@ static void shell_handle_present_surface(struct wl_client *client, .method = method, .output = output, }; - wlr_signal_emit_safe(&shell->events.present_surface, &event); + wl_signal_emit_mutable(&shell->events.present_surface, &event); } static void shell_handle_present_surface_for_mode(struct wl_client *client, @@ -79,7 +78,7 @@ static void shell_bind(struct wl_client *client, void *data, uint32_t version, static void handle_display_destroy(struct wl_listener *listener, void *data) { struct wlr_fullscreen_shell_v1 *shell = wl_container_of(listener, shell, display_destroy); - wlr_signal_emit_safe(&shell->events.destroy, shell); + wl_signal_emit_mutable(&shell->events.destroy, shell); wl_list_remove(&shell->display_destroy.link); wl_global_destroy(shell->global); free(shell); diff --git a/types/wlr_gamma_control_v1.c b/types/wlr_gamma_control_v1.c index 095b4a6f4..009a42a52 100644 --- a/types/wlr_gamma_control_v1.c +++ b/types/wlr_gamma_control_v1.c @@ -7,7 +7,6 @@ #include #include #include -#include "util/signal.h" #include "wlr-gamma-control-unstable-v1-protocol.h" #define GAMMA_CONTROL_MANAGER_V1_VERSION 1 @@ -259,7 +258,7 @@ static void gamma_control_manager_bind(struct wl_client *client, void *data, static void handle_display_destroy(struct wl_listener *listener, void *data) { struct wlr_gamma_control_manager_v1 *manager = wl_container_of(listener, manager, display_destroy); - wlr_signal_emit_safe(&manager->events.destroy, manager); + wl_signal_emit_mutable(&manager->events.destroy, manager); wl_list_remove(&manager->display_destroy.link); wl_global_destroy(manager->global); free(manager); diff --git a/types/wlr_idle.c b/types/wlr_idle.c index 4c338931c..cb3a1cc38 100644 --- a/types/wlr_idle.c +++ b/types/wlr_idle.c @@ -5,7 +5,6 @@ #include #include #include "idle-protocol.h" -#include "util/signal.h" static const struct org_kde_kwin_idle_timeout_interface idle_timeout_impl; @@ -22,7 +21,7 @@ static int idle_notify(void *data) { return 0; } timer->idle_state = true; - wlr_signal_emit_safe(&timer->events.idle, timer); + wl_signal_emit_mutable(&timer->events.idle, timer); if (timer->resource) { org_kde_kwin_idle_timeout_send_idle(timer->resource); @@ -38,7 +37,7 @@ static void handle_activity(struct wlr_idle_timeout *timer) { // in case the previous state was sleeping send a resume event and switch state if (timer->idle_state) { timer->idle_state = false; - wlr_signal_emit_safe(&timer->events.resume, timer); + wl_signal_emit_mutable(&timer->events.resume, timer); if (timer->resource) { org_kde_kwin_idle_timeout_send_resumed(timer->resource); @@ -212,7 +211,7 @@ static void idle_bind(struct wl_client *wl_client, void *data, static void handle_display_destroy(struct wl_listener *listener, void *data) { struct wlr_idle *idle = wl_container_of(listener, idle, display_destroy); - wlr_signal_emit_safe(&idle->events.destroy, idle); + wl_signal_emit_mutable(&idle->events.destroy, idle); wl_list_remove(&idle->display_destroy.link); wl_global_destroy(idle->global); free(idle); @@ -249,7 +248,7 @@ struct wlr_idle *wlr_idle_create(struct wl_display *display) { } void wlr_idle_notify_activity(struct wlr_idle *idle, struct wlr_seat *seat) { - wlr_signal_emit_safe(&idle->events.activity_notify, seat); + wl_signal_emit_mutable(&idle->events.activity_notify, seat); } struct wlr_idle_timeout *wlr_idle_timeout_create(struct wlr_idle *idle, @@ -258,7 +257,7 @@ struct wlr_idle_timeout *wlr_idle_timeout_create(struct wlr_idle *idle, } void wlr_idle_timeout_destroy(struct wlr_idle_timeout *timer) { - wlr_signal_emit_safe(&timer->events.destroy, NULL); + wl_signal_emit_mutable(&timer->events.destroy, NULL); wl_list_remove(&timer->input_listener.link); wl_list_remove(&timer->seat_destroy.link); diff --git a/types/wlr_idle_inhibit_v1.c b/types/wlr_idle_inhibit_v1.c index 61a66dc1f..7369643e3 100644 --- a/types/wlr_idle_inhibit_v1.c +++ b/types/wlr_idle_inhibit_v1.c @@ -1,6 +1,5 @@ #include #include -#include #include #include #include @@ -33,7 +32,7 @@ static void idle_inhibitor_v1_destroy(struct wlr_idle_inhibitor_v1 *inhibitor) { return; } - wlr_signal_emit_safe(&inhibitor->events.destroy, inhibitor->surface); + wl_signal_emit_mutable(&inhibitor->events.destroy, inhibitor->surface); wl_resource_set_user_data(inhibitor->resource, NULL); wl_list_remove(&inhibitor->link); @@ -98,7 +97,7 @@ static void manager_handle_create_inhibitor(struct wl_client *client, inhibitor, idle_inhibitor_v1_handle_resource_destroy); wl_list_insert(&manager->inhibitors, &inhibitor->link); - wlr_signal_emit_safe(&manager->events.new_inhibitor, inhibitor); + wl_signal_emit_mutable(&manager->events.new_inhibitor, inhibitor); } static void manager_handle_destroy(struct wl_client *client, @@ -114,7 +113,7 @@ static const struct zwp_idle_inhibit_manager_v1_interface idle_inhibit_impl = { static void handle_display_destroy(struct wl_listener *listener, void *data) { struct wlr_idle_inhibit_manager_v1 *manager = wl_container_of(listener, manager, display_destroy); - wlr_signal_emit_safe(&manager->events.destroy, manager); + wl_signal_emit_mutable(&manager->events.destroy, manager); wl_list_remove(&manager->display_destroy.link); wl_global_destroy(manager->global); free(manager); diff --git a/types/wlr_input_device.c b/types/wlr_input_device.c index 6897febed..21916d699 100644 --- a/types/wlr_input_device.c +++ b/types/wlr_input_device.c @@ -1,19 +1,12 @@ #define _POSIX_C_SOURCE 200809L + #include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "util/signal.h" +#include "interfaces/wlr_input_device.h" void wlr_input_device_init(struct wlr_input_device *dev, enum wlr_input_device_type type, const char *name) { + memset(dev, 0, sizeof(*dev)); dev->type = type; dev->name = strdup(name); dev->vendor = 0; @@ -27,40 +20,9 @@ void wlr_input_device_finish(struct wlr_input_device *wlr_device) { return; } - wlr_signal_emit_safe(&wlr_device->events.destroy, wlr_device); + wl_signal_emit_mutable(&wlr_device->events.destroy, wlr_device); + + wl_list_remove(&wlr_device->events.destroy.listener_list); free(wlr_device->name); - free(wlr_device->output_name); -} - -void wlr_input_device_destroy(struct wlr_input_device *dev) { - if (!dev) { - return; - } - - if (dev->_device) { - switch (dev->type) { - case WLR_INPUT_DEVICE_KEYBOARD: - wlr_keyboard_destroy(dev->keyboard); - break; - case WLR_INPUT_DEVICE_POINTER: - wlr_pointer_destroy(dev->pointer); - break; - case WLR_INPUT_DEVICE_SWITCH: - wlr_switch_destroy(dev->switch_device); - break; - case WLR_INPUT_DEVICE_TOUCH: - wlr_touch_destroy(dev->touch); - break; - case WLR_INPUT_DEVICE_TABLET_TOOL: - wlr_tablet_destroy(dev->tablet); - break; - case WLR_INPUT_DEVICE_TABLET_PAD: - wlr_tablet_pad_destroy(dev->tablet_pad); - break; - } - } else { - wlr_input_device_finish(dev); - free(dev); - } } diff --git a/types/wlr_input_inhibitor.c b/types/wlr_input_inhibitor.c index 55b141753..c6fbb5af7 100644 --- a/types/wlr_input_inhibitor.c +++ b/types/wlr_input_inhibitor.c @@ -4,7 +4,6 @@ #include #include "wlr/types/wlr_input_inhibitor.h" #include "wlr-input-inhibitor-unstable-v1-protocol.h" -#include "util/signal.h" static const struct zwlr_input_inhibit_manager_v1_interface inhibit_manager_implementation; static const struct zwlr_input_inhibitor_v1_interface input_inhibitor_implementation; @@ -27,7 +26,7 @@ static void input_inhibit_manager_deactivate( } manager->active_client = NULL; manager->active_inhibitor = NULL; - wlr_signal_emit_safe(&manager->events.deactivate, manager); + wl_signal_emit_mutable(&manager->events.deactivate, manager); } static void input_inhibitor_destroy(struct wl_client *client, @@ -71,7 +70,7 @@ static void inhibit_manager_get_inhibitor(struct wl_client *client, manager->active_client = client; manager->active_inhibitor = wl_resource; - wlr_signal_emit_safe(&manager->events.activate, manager); + wl_signal_emit_mutable(&manager->events.activate, manager); } static const struct zwlr_input_inhibit_manager_v1_interface inhibit_manager_implementation = { @@ -106,7 +105,7 @@ static void inhibit_manager_bind(struct wl_client *wl_client, void *data, static void handle_display_destroy(struct wl_listener *listener, void *data) { struct wlr_input_inhibit_manager *manager = wl_container_of(listener, manager, display_destroy); - wlr_signal_emit_safe(&manager->events.destroy, manager); + wl_signal_emit_mutable(&manager->events.destroy, manager); wl_list_remove(&manager->display_destroy.link); wl_global_destroy(manager->global); free(manager); diff --git a/types/wlr_input_method_v2.c b/types/wlr_input_method_v2.c index 559927eb1..6d2e49f98 100644 --- a/types/wlr_input_method_v2.c +++ b/types/wlr_input_method_v2.c @@ -12,7 +12,6 @@ #include #include "input-method-unstable-v2-protocol.h" #include "util/shm.h" -#include "util/signal.h" static const struct zwp_input_method_v2_interface input_method_impl; static const struct zwp_input_method_keyboard_grab_v2_interface keyboard_grab_impl; @@ -41,7 +40,7 @@ static void input_method_destroy(struct wlr_input_method_v2 *input_method) { popup_surface, tmp, &input_method->popup_surfaces, link) { popup_surface_destroy(popup_surface); } - wlr_signal_emit_safe(&input_method->events.destroy, input_method); + wl_signal_emit_mutable(&input_method->events.destroy, input_method); wl_list_remove(wl_resource_get_link(input_method->resource)); wl_list_remove(&input_method->seat_client_destroy.link); wlr_input_method_keyboard_grab_v2_destroy(input_method->keyboard_grab); @@ -76,7 +75,7 @@ static void im_commit(struct wl_client *client, struct wl_resource *resource, input_method->current_serial = serial; struct wlr_input_method_v2_state default_state = {0}; input_method->pending = default_state; - wlr_signal_emit_safe(&input_method->events.commit, (void*)input_method); + wl_signal_emit_mutable(&input_method->events.commit, (void*)input_method); } static void im_commit_string(struct wl_client *client, @@ -141,10 +140,10 @@ static void popup_surface_set_mapped( struct wlr_input_popup_surface_v2 *popup_surface, bool mapped) { if (mapped && !popup_surface->mapped) { popup_surface->mapped = true; - wlr_signal_emit_safe(&popup_surface->events.map, popup_surface); + wl_signal_emit_mutable(&popup_surface->events.map, popup_surface); } else if (!mapped && popup_surface->mapped) { - wlr_signal_emit_safe(&popup_surface->events.unmap, popup_surface); popup_surface->mapped = false; + wl_signal_emit_mutable(&popup_surface->events.unmap, popup_surface); } } @@ -182,7 +181,7 @@ bool wlr_surface_is_input_popup_surface_v2(struct wlr_surface *surface) { static void popup_surface_destroy( struct wlr_input_popup_surface_v2 *popup_surface) { popup_surface_set_mapped(popup_surface, false); - wlr_signal_emit_safe(&popup_surface->events.destroy, NULL); + wl_signal_emit_mutable(&popup_surface->events.destroy, NULL); wl_list_remove(&popup_surface->surface_destroy.link); wl_list_remove(&popup_surface->link); wl_resource_set_user_data(popup_surface->resource, NULL); @@ -264,7 +263,7 @@ static void im_get_input_popup_surface(struct wl_client *client, && popup_surface->input_method->client_active); wl_list_insert(&input_method->popup_surfaces, &popup_surface->link); - wlr_signal_emit_safe(&input_method->events.new_popup_surface, popup_surface); + wl_signal_emit_mutable(&input_method->events.new_popup_surface, popup_surface); } void wlr_input_method_keyboard_grab_v2_destroy( @@ -272,7 +271,7 @@ void wlr_input_method_keyboard_grab_v2_destroy( if (!keyboard_grab) { return; } - wlr_signal_emit_safe(&keyboard_grab->events.destroy, keyboard_grab); + wl_signal_emit_mutable(&keyboard_grab->events.destroy, keyboard_grab); keyboard_grab->input_method->keyboard_grab = NULL; if (keyboard_grab->keyboard) { wl_list_remove(&keyboard_grab->keyboard_keymap.link); @@ -410,7 +409,7 @@ void wlr_input_method_keyboard_grab_v2_set_keyboard( &keyboard_grab->keyboard_repeat_info); keyboard_grab->keyboard_destroy.notify = handle_keyboard_destroy; - wl_signal_add(&keyboard->events.destroy, + wl_signal_add(&keyboard->base.events.destroy, &keyboard_grab->keyboard_destroy); wlr_input_method_keyboard_grab_v2_send_modifiers(keyboard_grab, @@ -452,7 +451,7 @@ static void im_grab_keyboard(struct wl_client *client, keyboard_grab->input_method = input_method; input_method->keyboard_grab = keyboard_grab; wl_signal_init(&keyboard_grab->events.destroy); - wlr_signal_emit_safe(&input_method->events.grab_keyboard, keyboard_grab); + wl_signal_emit_mutable(&input_method->events.grab_keyboard, keyboard_grab); } static const struct zwp_input_method_v2_interface input_method_impl = { @@ -575,7 +574,7 @@ static void manager_get_input_method(struct wl_client *client, input_method->resource = im_resource; wl_list_insert(&im_manager->input_methods, wl_resource_get_link(input_method->resource)); - wlr_signal_emit_safe(&im_manager->events.input_method, input_method); + wl_signal_emit_mutable(&im_manager->events.input_method, input_method); } static void manager_destroy(struct wl_client *client, @@ -607,7 +606,7 @@ static void input_method_manager_bind(struct wl_client *wl_client, void *data, static void handle_display_destroy(struct wl_listener *listener, void *data) { struct wlr_input_method_manager_v2 *manager = wl_container_of(listener, manager, display_destroy); - wlr_signal_emit_safe(&manager->events.destroy, manager); + wl_signal_emit_mutable(&manager->events.destroy, manager); wl_list_remove(&manager->display_destroy.link); wl_global_destroy(manager->global); free(manager); diff --git a/types/wlr_keyboard.c b/types/wlr_keyboard.c index afa689b12..5150af877 100644 --- a/types/wlr_keyboard.c +++ b/types/wlr_keyboard.c @@ -5,12 +5,18 @@ #include #include #include -#include #include +#include "interfaces/wlr_input_device.h" #include "types/wlr_keyboard.h" -#include "util/array.h" +#include "util/set.h" #include "util/shm.h" -#include "util/signal.h" +#include "util/time.h" + +struct wlr_keyboard *wlr_keyboard_from_input_device( + struct wlr_input_device *input_device) { + assert(input_device->type == WLR_INPUT_DEVICE_KEYBOARD); + return wl_container_of(input_device, (struct wlr_keyboard *)NULL, base); +} void keyboard_led_update(struct wlr_keyboard *keyboard) { if (keyboard->xkb_state == NULL) { @@ -60,7 +66,7 @@ bool keyboard_modifier_update(struct wlr_keyboard *keyboard) { } void keyboard_key_update(struct wlr_keyboard *keyboard, - struct wlr_event_keyboard_key *event) { + struct wlr_keyboard_key_event *event) { if (event->state == WL_KEYBOARD_KEY_STATE_PRESSED) { set_add(keyboard->keycodes, &keyboard->num_keycodes, WLR_KEYBOARD_KEYS_CAP, event->keycode); @@ -84,16 +90,16 @@ void wlr_keyboard_notify_modifiers(struct wlr_keyboard *keyboard, bool updated = keyboard_modifier_update(keyboard); if (updated) { - wlr_signal_emit_safe(&keyboard->events.modifiers, keyboard); + wl_signal_emit_mutable(&keyboard->events.modifiers, keyboard); } keyboard_led_update(keyboard); } void wlr_keyboard_notify_key(struct wlr_keyboard *keyboard, - struct wlr_event_keyboard_key *event) { + struct wlr_keyboard_key_event *event) { keyboard_key_update(keyboard, event); - wlr_signal_emit_safe(&keyboard->events.key, event); + wl_signal_emit_mutable(&keyboard->events.key, event); if (keyboard->xkb_state == NULL) { return; @@ -107,7 +113,7 @@ void wlr_keyboard_notify_key(struct wlr_keyboard *keyboard, bool updated = keyboard_modifier_update(keyboard); if (updated) { - wlr_signal_emit_safe(&keyboard->events.modifiers, keyboard); + wl_signal_emit_mutable(&keyboard->events.modifiers, keyboard); } keyboard_led_update(keyboard); @@ -115,15 +121,14 @@ void wlr_keyboard_notify_key(struct wlr_keyboard *keyboard, void wlr_keyboard_init(struct wlr_keyboard *kb, const struct wlr_keyboard_impl *impl, const char *name) { + memset(kb, 0, sizeof(*kb)); wlr_input_device_init(&kb->base, WLR_INPUT_DEVICE_KEYBOARD, name); - kb->base.keyboard = kb; kb->impl = impl; wl_signal_init(&kb->events.key); wl_signal_init(&kb->events.modifiers); wl_signal_init(&kb->events.keymap); wl_signal_init(&kb->events.repeat_info); - wl_signal_init(&kb->events.destroy); kb->keymap_fd = -1; @@ -132,25 +137,29 @@ void wlr_keyboard_init(struct wlr_keyboard *kb, kb->repeat_info.delay = 600; } -void wlr_keyboard_destroy(struct wlr_keyboard *kb) { - if (kb == NULL) { - return; +void wlr_keyboard_finish(struct wlr_keyboard *kb) { + /* Release pressed keys */ + size_t orig_num_keycodes = kb->num_keycodes; + for (size_t i = 0; i < orig_num_keycodes; ++i) { + assert(kb->num_keycodes == orig_num_keycodes - i); + struct wlr_keyboard_key_event event = { + .time_msec = get_current_time_msec(), + .keycode = kb->keycodes[orig_num_keycodes - i - 1], + .update_state = false, + .state = WL_KEYBOARD_KEY_STATE_RELEASED, + }; + wlr_keyboard_notify_key(kb, &event); // updates num_keycodes } - wlr_signal_emit_safe(&kb->events.destroy, kb); + wlr_input_device_finish(&kb->base); + /* Finish xkbcommon resources */ xkb_state_unref(kb->xkb_state); xkb_keymap_unref(kb->keymap); free(kb->keymap_string); if (kb->keymap_fd >= 0) { close(kb->keymap_fd); } - if (kb->impl && kb->impl->destroy) { - kb->impl->destroy(kb); - } else { - wl_list_remove(&kb->events.key.listener_list); - free(kb); - } } void wlr_keyboard_led_update(struct wlr_keyboard *kb, uint32_t leds) { @@ -236,7 +245,7 @@ bool wlr_keyboard_set_keymap(struct wlr_keyboard *kb, keyboard_modifier_update(kb); - wlr_signal_emit_safe(&kb->events.keymap, kb); + wl_signal_emit_mutable(&kb->events.keymap, kb); return true; err: @@ -256,7 +265,7 @@ void wlr_keyboard_set_repeat_info(struct wlr_keyboard *kb, int32_t rate, } kb->repeat_info.rate = rate; kb->repeat_info.delay = delay; - wlr_signal_emit_safe(&kb->events.repeat_info, kb); + wl_signal_emit_mutable(&kb->events.repeat_info, kb); } uint32_t wlr_keyboard_get_modifiers(struct wlr_keyboard *kb) { diff --git a/types/wlr_keyboard_group.c b/types/wlr_keyboard_group.c index 35fc54702..263545844 100644 --- a/types/wlr_keyboard_group.c +++ b/types/wlr_keyboard_group.c @@ -7,7 +7,6 @@ #include #include #include "types/wlr_keyboard.h" -#include "util/signal.h" #include "wlr/interfaces/wlr_keyboard.h" #include "wlr/types/wlr_keyboard.h" #include "wlr/types/wlr_keyboard_group.h" @@ -37,18 +36,8 @@ static void keyboard_set_leds(struct wlr_keyboard *kb, uint32_t leds) { } } -static void keyboard_destroy(struct wlr_keyboard *kb) { - // Just remove the event listeners. The keyboard will be freed as part of - // the wlr_keyboard_group in wlr_keyboard_group_destroy. - wl_list_remove(&kb->events.key.listener_list); - wl_list_remove(&kb->events.modifiers.listener_list); - wl_list_remove(&kb->events.keymap.listener_list); - wl_list_remove(&kb->events.repeat_info.listener_list); - wl_list_remove(&kb->events.destroy.listener_list); -} - static const struct wlr_keyboard_impl impl = { - .destroy = keyboard_destroy, + .name = "keyboard-group", .led_update = keyboard_set_leds }; @@ -60,7 +49,7 @@ struct wlr_keyboard_group *wlr_keyboard_group_create(void) { return NULL; } - wlr_keyboard_init(&group->keyboard, &impl, "keyboard-group"); + wlr_keyboard_init(&group->keyboard, &impl, "wlr_keyboard_group"); wl_list_init(&group->devices); wl_list_init(&group->keys); @@ -79,7 +68,7 @@ struct wlr_keyboard_group *wlr_keyboard_group_from_wlr_keyboard( } static bool process_key(struct keyboard_group_device *group_device, - struct wlr_event_keyboard_key *event) { + struct wlr_keyboard_key_event *event) { struct wlr_keyboard_group *group = group_device->keyboard->group; struct keyboard_group_key *key, *tmp; @@ -198,7 +187,7 @@ static void refresh_state(struct keyboard_group_device *device, for (size_t i = 0; i < device->keyboard->num_keycodes; i++) { struct timespec now; clock_gettime(CLOCK_MONOTONIC, &now); - struct wlr_event_keyboard_key event = { + struct wlr_keyboard_key_event event = { .time_msec = (int64_t)now.tv_sec * 1000 + now.tv_nsec / 1000000, .keycode = device->keyboard->keycodes[i], .update_state = true, @@ -222,9 +211,9 @@ static void refresh_state(struct keyboard_group_device *device, // If there are any unique keys, emit the enter/leave event if (keys.size > 0) { if (state == WL_KEYBOARD_KEY_STATE_PRESSED) { - wlr_signal_emit_safe(&device->keyboard->group->events.enter, &keys); + wl_signal_emit_mutable(&device->keyboard->group->events.enter, &keys); } else { - wlr_signal_emit_safe(&device->keyboard->group->events.leave, &keys); + wl_signal_emit_mutable(&device->keyboard->group->events.leave, &keys); } } @@ -289,7 +278,7 @@ bool wlr_keyboard_group_add_keyboard(struct wlr_keyboard_group *group, wl_signal_add(&keyboard->events.repeat_info, &device->repeat_info); device->repeat_info.notify = handle_keyboard_repeat_info; - wl_signal_add(&keyboard->events.destroy, &device->destroy); + wl_signal_add(&keyboard->base.events.destroy, &device->destroy); device->destroy.notify = handle_keyboard_destroy; struct wlr_keyboard *group_kb = &group->keyboard; @@ -325,7 +314,7 @@ void wlr_keyboard_group_destroy(struct wlr_keyboard_group *group) { wl_list_for_each_safe(device, tmp, &group->devices, link) { wlr_keyboard_group_remove_keyboard(group, device->keyboard); } - wlr_keyboard_destroy(&group->keyboard); + wlr_keyboard_finish(&group->keyboard); wl_list_remove(&group->events.enter.listener_list); wl_list_remove(&group->events.leave.listener_list); free(group); diff --git a/types/wlr_keyboard_shortcuts_inhibit_v1.c b/types/wlr_keyboard_shortcuts_inhibit_v1.c index 247d350d8..cc9bac14c 100644 --- a/types/wlr_keyboard_shortcuts_inhibit_v1.c +++ b/types/wlr_keyboard_shortcuts_inhibit_v1.c @@ -1,6 +1,5 @@ #include #include -#include #include #include #include "keyboard-shortcuts-inhibit-unstable-v1-protocol.h" @@ -35,7 +34,7 @@ static void keyboard_shortcuts_inhibitor_v1_destroy( return; } - wlr_signal_emit_safe(&inhibitor->events.destroy, inhibitor); + wl_signal_emit_mutable(&inhibitor->events.destroy, inhibitor); wl_resource_set_user_data(inhibitor->resource, NULL); wl_list_remove(&inhibitor->link); @@ -144,7 +143,7 @@ static void manager_handle_inhibit_shortcuts(struct wl_client *client, keyboard_shortcuts_inhibitor_v1_handle_resource_destroy); wl_list_insert(&manager->inhibitors, &inhibitor->link); - wlr_signal_emit_safe(&manager->events.new_inhibitor, inhibitor); + wl_signal_emit_mutable(&manager->events.new_inhibitor, inhibitor); } static void manager_handle_destroy(struct wl_client *client, @@ -161,7 +160,7 @@ keyboard_shortcuts_inhibit_impl = { static void handle_display_destroy(struct wl_listener *listener, void *data) { struct wlr_keyboard_shortcuts_inhibit_manager_v1 *manager = wl_container_of(listener, manager, display_destroy); - wlr_signal_emit_safe(&manager->events.destroy, manager); + wl_signal_emit_mutable(&manager->events.destroy, manager); wl_list_remove(&manager->display_destroy.link); wl_global_destroy(manager->global); free(manager); diff --git a/types/wlr_layer_shell_v1.c b/types/wlr_layer_shell_v1.c index c8d3a1cb5..f21ae7999 100644 --- a/types/wlr_layer_shell_v1.c +++ b/types/wlr_layer_shell_v1.c @@ -8,7 +8,6 @@ #include #include #include -#include "util/signal.h" #include "wlr-layer-shell-unstable-v1-protocol.h" #define LAYER_SHELL_VERSION 4 @@ -28,7 +27,7 @@ static struct wlr_layer_shell_v1 *layer_shell_from_resource( return wl_resource_get_user_data(resource); } -static struct wlr_layer_surface_v1 *layer_surface_from_resource( +struct wlr_layer_surface_v1 *wlr_layer_surface_v1_from_resource( struct wl_resource *resource) { assert(wl_resource_instance_of(resource, &zwlr_layer_surface_v1_interface, &layer_surface_implementation)); @@ -58,7 +57,8 @@ static void layer_surface_configure_destroy( static void layer_surface_handle_ack_configure(struct wl_client *client, struct wl_resource *resource, uint32_t serial) { - struct wlr_layer_surface_v1 *surface = layer_surface_from_resource(resource); + struct wlr_layer_surface_v1 *surface = + wlr_layer_surface_v1_from_resource(resource); if (!surface) { return; @@ -98,7 +98,8 @@ static void layer_surface_handle_ack_configure(struct wl_client *client, static void layer_surface_handle_set_size(struct wl_client *client, struct wl_resource *resource, uint32_t width, uint32_t height) { - struct wlr_layer_surface_v1 *surface = layer_surface_from_resource(resource); + struct wlr_layer_surface_v1 *surface = + wlr_layer_surface_v1_from_resource(resource); if (!surface) { return; @@ -127,7 +128,8 @@ static void layer_surface_handle_set_anchor(struct wl_client *client, ZWLR_LAYER_SURFACE_V1_ERROR_INVALID_ANCHOR, "invalid anchor %" PRIu32, anchor); } - struct wlr_layer_surface_v1 *surface = layer_surface_from_resource(resource); + struct wlr_layer_surface_v1 *surface = + wlr_layer_surface_v1_from_resource(resource); if (!surface) { return; @@ -144,7 +146,7 @@ static void layer_surface_handle_set_anchor(struct wl_client *client, static void layer_surface_handle_set_exclusive_zone(struct wl_client *client, struct wl_resource *resource, int32_t zone) { - struct wlr_layer_surface_v1 *surface = layer_surface_from_resource(resource); + struct wlr_layer_surface_v1 *surface = wlr_layer_surface_v1_from_resource(resource); if (!surface) { return; @@ -162,7 +164,8 @@ static void layer_surface_handle_set_exclusive_zone(struct wl_client *client, static void layer_surface_handle_set_margin( struct wl_client *client, struct wl_resource *resource, int32_t top, int32_t right, int32_t bottom, int32_t left) { - struct wlr_layer_surface_v1 *surface = layer_surface_from_resource(resource); + struct wlr_layer_surface_v1 *surface = + wlr_layer_surface_v1_from_resource(resource); if (!surface) { return; @@ -186,7 +189,7 @@ static void layer_surface_handle_set_margin( static void layer_surface_handle_set_keyboard_interactivity( struct wl_client *client, struct wl_resource *resource, uint32_t interactive) { - struct wlr_layer_surface_v1 *surface = layer_surface_from_resource(resource); + struct wlr_layer_surface_v1 *surface = wlr_layer_surface_v1_from_resource(resource); if (!surface) { return; @@ -210,7 +213,7 @@ static void layer_surface_handle_get_popup(struct wl_client *client, struct wl_resource *layer_resource, struct wl_resource *popup_resource) { struct wlr_layer_surface_v1 *parent = - layer_surface_from_resource(layer_resource); + wlr_layer_surface_v1_from_resource(layer_resource); struct wlr_xdg_popup *popup = wlr_xdg_popup_from_resource(popup_resource); @@ -219,13 +222,13 @@ static void layer_surface_handle_get_popup(struct wl_client *client, } popup->parent = parent->surface; wl_list_insert(&parent->popups, &popup->link); - wlr_signal_emit_safe(&parent->events.new_popup, popup); + wl_signal_emit_mutable(&parent->events.new_popup, popup); } static void layer_surface_set_layer(struct wl_client *client, struct wl_resource *surface_resource, uint32_t layer) { struct wlr_layer_surface_v1 *surface = - layer_surface_from_resource(surface_resource); + wlr_layer_surface_v1_from_resource(surface_resource); if (!surface) { return; } @@ -258,8 +261,10 @@ static const struct zwlr_layer_surface_v1_interface layer_surface_implementation }; static void layer_surface_unmap(struct wlr_layer_surface_v1 *surface) { + surface->configured = surface->mapped = false; + // TODO: probably need to ungrab before this event - wlr_signal_emit_safe(&surface->events.unmap, surface); + wl_signal_emit_mutable(&surface->events.unmap, surface); struct wlr_xdg_popup *popup, *popup_tmp; wl_list_for_each_safe(popup, popup_tmp, &surface->popups, link) { @@ -271,14 +276,13 @@ static void layer_surface_unmap(struct wlr_layer_surface_v1 *surface) { layer_surface_configure_destroy(configure); } - surface->configured = surface->mapped = false; } static void layer_surface_destroy(struct wlr_layer_surface_v1 *surface) { if (surface->configured && surface->mapped) { layer_surface_unmap(surface); } - wlr_signal_emit_safe(&surface->events.destroy, surface); + wl_signal_emit_mutable(&surface->events.destroy, surface); wl_resource_set_user_data(surface->resource, NULL); surface->surface->role_data = NULL; wl_list_remove(&surface->surface_destroy.link); @@ -288,7 +292,7 @@ static void layer_surface_destroy(struct wlr_layer_surface_v1 *surface) { static void layer_surface_resource_destroy(struct wl_resource *resource) { struct wlr_layer_surface_v1 *surface = - layer_surface_from_resource(resource); + wlr_layer_surface_v1_from_resource(resource); if (surface != NULL) { layer_surface_destroy(surface); } @@ -360,7 +364,7 @@ static void layer_surface_role_commit(struct wlr_surface *wlr_surface) { surface->added = true; assert(!surface->configured); assert(!surface->mapped); - wlr_signal_emit_safe(&surface->shell->events.new_surface, surface); + wl_signal_emit_mutable(&surface->shell->events.new_surface, surface); // Return early here as the compositor may have closed this layer surface // in response to the new_surface event. return; @@ -369,7 +373,7 @@ static void layer_surface_role_commit(struct wlr_surface *wlr_surface) { if (surface->configured && wlr_surface_has_buffer(surface->surface) && !surface->mapped) { surface->mapped = true; - wlr_signal_emit_safe(&surface->events.map, surface); + wl_signal_emit_mutable(&surface->events.map, surface); } } @@ -496,7 +500,7 @@ static void layer_shell_bind(struct wl_client *wl_client, void *data, static void handle_display_destroy(struct wl_listener *listener, void *data) { struct wlr_layer_shell_v1 *layer_shell = wl_container_of(listener, layer_shell, display_destroy); - wlr_signal_emit_safe(&layer_shell->events.destroy, layer_shell); + wl_signal_emit_mutable(&layer_shell->events.destroy, layer_shell); wl_list_remove(&layer_shell->display_destroy.link); wl_global_destroy(layer_shell->global); free(layer_shell); @@ -548,16 +552,15 @@ void wlr_layer_surface_v1_for_each_surface(struct wlr_layer_surface_v1 *surface, void wlr_layer_surface_v1_for_each_popup_surface(struct wlr_layer_surface_v1 *surface, wlr_surface_iterator_func_t iterator, void *user_data){ - struct wlr_xdg_popup *popup_state; - wl_list_for_each(popup_state, &surface->popups, link) { - struct wlr_xdg_surface *popup = popup_state->base; - if (!popup->configured || !popup->mapped) { + struct wlr_xdg_popup *popup; + wl_list_for_each(popup, &surface->popups, link) { + if (!popup->base->configured || !popup->base->mapped) { continue; } double popup_sx, popup_sy; - popup_sx = popup->popup->geometry.x - popup->current.geometry.x; - popup_sy = popup->popup->geometry.y - popup->current.geometry.y; + popup_sx = popup->current.geometry.x - popup->base->current.geometry.x; + popup_sy = popup->current.geometry.y - popup->base->current.geometry.y; struct layer_surface_iterator_data data = { .user_iterator = iterator, @@ -565,7 +568,8 @@ void wlr_layer_surface_v1_for_each_popup_surface(struct wlr_layer_surface_v1 *su .x = popup_sx, .y = popup_sy, }; - wlr_xdg_surface_for_each_surface(popup, layer_surface_iterator, &data); + wlr_xdg_surface_for_each_surface(popup->base, + layer_surface_iterator, &data); } } @@ -583,20 +587,18 @@ struct wlr_surface *wlr_layer_surface_v1_surface_at( struct wlr_surface *wlr_layer_surface_v1_popup_surface_at( struct wlr_layer_surface_v1 *surface, double sx, double sy, double *sub_x, double *sub_y) { - struct wlr_xdg_popup *popup_state; - wl_list_for_each(popup_state, &surface->popups, link) { - struct wlr_xdg_surface *popup = popup_state->base; - if (!popup->mapped) { + struct wlr_xdg_popup *popup; + wl_list_for_each(popup, &surface->popups, link) { + if (!popup->base->mapped) { continue; } - double popup_sx = popup_state->geometry.x - popup->current.geometry.x; - double popup_sy = popup_state->geometry.y - popup->current.geometry.y; + double popup_sx, popup_sy; + popup_sx = popup->current.geometry.x - popup->base->current.geometry.x; + popup_sy = popup->current.geometry.y - popup->base->current.geometry.y; - struct wlr_surface *sub = wlr_xdg_surface_surface_at(popup, - sx - popup_sx, - sy - popup_sy, - sub_x, sub_y); + struct wlr_surface *sub = wlr_xdg_surface_surface_at( + popup->base, sx - popup_sx, sy - popup_sy, sub_x, sub_y); if (sub != NULL) { return sub; } diff --git a/types/wlr_linux_dmabuf_v1.c b/types/wlr_linux_dmabuf_v1.c index 5138e469f..7480b9e19 100644 --- a/types/wlr_linux_dmabuf_v1.c +++ b/types/wlr_linux_dmabuf_v1.c @@ -4,13 +4,13 @@ #include #include #include +#include #include #include #include #include #include "linux-dmabuf-unstable-v1-protocol.h" #include "render/drm_format_set.h" -#include "util/signal.h" #include "util/shm.h" #define LINUX_DMABUF_VERSION 4 @@ -474,16 +474,12 @@ static ssize_t get_drm_format_set_index(const struct wlr_drm_format_set *set, format_found = true; break; } - idx += 1 + fmt->len; + idx += fmt->len; } if (!format_found) { return -1; } - if (modifier == DRM_FORMAT_MOD_INVALID) { - return idx; - } - for (size_t i = 0; i < fmt->len; i++) { if (fmt->modifiers[i] == modifier) { return idx; @@ -505,7 +501,7 @@ static struct wlr_linux_dmabuf_feedback_v1_compiled *feedback_compile( size_t table_len = 0; for (size_t i = 0; i < fallback_tranche->formats->len; i++) { const struct wlr_drm_format *fmt = fallback_tranche->formats->formats[i]; - table_len += 1 + fmt->len; + table_len += fmt->len; } assert(table_len > 0); @@ -532,12 +528,6 @@ static struct wlr_linux_dmabuf_feedback_v1_compiled *feedback_compile( for (size_t i = 0; i < fallback_tranche->formats->len; i++) { const struct wlr_drm_format *fmt = fallback_tranche->formats->formats[i]; - table[n] = (struct wlr_linux_dmabuf_feedback_v1_table_entry){ - .format = fmt->format, - .modifier = DRM_FORMAT_MOD_INVALID, - }; - n++; - for (size_t k = 0; k < fmt->len; k++) { table[n] = (struct wlr_linux_dmabuf_feedback_v1_table_entry){ .format = fmt->format, @@ -583,20 +573,6 @@ static struct wlr_linux_dmabuf_feedback_v1_compiled *feedback_compile( uint16_t *indices = compiled_tranche->indices.data; for (size_t j = 0; j < tranche->formats->len; j++) { const struct wlr_drm_format *fmt = tranche->formats->formats[j]; - - ssize_t index = get_drm_format_set_index( - fallback_tranche->formats, fmt->format, - DRM_FORMAT_MOD_INVALID); - if (index < 0) { - wlr_log(WLR_ERROR, "Format 0x%" PRIX32 " and modifier " - "INVALID are in tranche #%zu but are missing " - "from the fallback tranche", - fmt->format, i); - goto error_compiled; - } - indices[n] = index; - n++; - for (size_t k = 0; k < fmt->len; k++) { ssize_t index = get_drm_format_set_index( fallback_tranche->formats, fmt->format, fmt->modifiers[k]); @@ -910,7 +886,7 @@ static void linux_dmabuf_bind(struct wl_client *client, void *data, } static void linux_dmabuf_v1_destroy(struct wlr_linux_dmabuf_v1 *linux_dmabuf) { - wlr_signal_emit_safe(&linux_dmabuf->events.destroy, linux_dmabuf); + wl_signal_emit_mutable(&linux_dmabuf->events.destroy, linux_dmabuf); struct wlr_linux_dmabuf_v1_surface *surface, *surface_tmp; wl_list_for_each_safe(surface, surface_tmp, &linux_dmabuf->surfaces, link) { diff --git a/types/wlr_matrix.c b/types/wlr_matrix.c index a1b2b31a1..7b6671f57 100644 --- a/types/wlr_matrix.c +++ b/types/wlr_matrix.c @@ -4,6 +4,7 @@ #include #include #include +#include "types/wlr_matrix.h" void wlr_matrix_identity(float mat[static 9]) { static const float identity[9] = { @@ -117,8 +118,7 @@ void wlr_matrix_transform(float mat[static 9], wlr_matrix_multiply(mat, mat, transforms[transform]); } -// Equivalent to glOrtho(0, width, 0, height, 1, -1) with the transform applied -void wlr_matrix_projection(float mat[static 9], int width, int height, +void matrix_projection(float mat[static 9], int width, int height, enum wl_output_transform transform) { memset(mat, 0, sizeof(*mat) * 9); diff --git a/types/wlr_output_damage.c b/types/wlr_output_damage.c index 6d24a4bf4..8254f65e9 100644 --- a/types/wlr_output_damage.c +++ b/types/wlr_output_damage.c @@ -5,7 +5,6 @@ #include #include #include -#include "util/signal.h" static void output_handle_destroy(struct wl_listener *listener, void *data) { struct wlr_output_damage *output_damage = @@ -41,15 +40,17 @@ static void output_handle_frame(struct wl_listener *listener, void *data) { return; } - wlr_signal_emit_safe(&output_damage->events.frame, output_damage); + wl_signal_emit_mutable(&output_damage->events.frame, output_damage); } static void output_handle_precommit(struct wl_listener *listener, void *data) { struct wlr_output_damage *output_damage = wl_container_of(listener, output_damage, output_precommit); + const struct wlr_output_event_precommit *event = data; + const struct wlr_output_state *state = event->state; struct wlr_output *output = output_damage->output; - if (output->pending.committed & WLR_OUTPUT_STATE_BUFFER) { + if (state->committed & WLR_OUTPUT_STATE_BUFFER) { // TODO: find a better way to access this info without a precommit // handler output_damage->pending_attach_render = output->back_buffer != NULL; @@ -126,7 +127,7 @@ void wlr_output_damage_destroy(struct wlr_output_damage *output_damage) { if (output_damage == NULL) { return; } - wlr_signal_emit_safe(&output_damage->events.destroy, output_damage); + wl_signal_emit_mutable(&output_damage->events.destroy, output_damage); wl_list_remove(&output_damage->output_destroy.link); wl_list_remove(&output_damage->output_mode.link); wl_list_remove(&output_damage->output_needs_frame.link); @@ -187,11 +188,17 @@ void wlr_output_damage_add(struct wlr_output_damage *output_damage, int width, height; wlr_output_transformed_resolution(output_damage->output, &width, &height); - pixman_region32_union(&output_damage->current, &output_damage->current, - damage); - pixman_region32_intersect_rect(&output_damage->current, - &output_damage->current, 0, 0, width, height); - wlr_output_schedule_frame(output_damage->output); + pixman_region32_t clipped_damage; + pixman_region32_init(&clipped_damage); + pixman_region32_intersect_rect(&clipped_damage, damage, 0, 0, width, height); + + if (pixman_region32_not_empty(&clipped_damage)) { + pixman_region32_union(&output_damage->current, &output_damage->current, + &clipped_damage); + wlr_output_schedule_frame(output_damage->output); + } + + pixman_region32_fini(&clipped_damage); } void wlr_output_damage_add_whole(struct wlr_output_damage *output_damage) { @@ -206,12 +213,9 @@ void wlr_output_damage_add_whole(struct wlr_output_damage *output_damage) { void wlr_output_damage_add_box(struct wlr_output_damage *output_damage, struct wlr_box *box) { - int width, height; - wlr_output_transformed_resolution(output_damage->output, &width, &height); - - pixman_region32_union_rect(&output_damage->current, &output_damage->current, + pixman_region32_t damage; + pixman_region32_init_rect(&damage, box->x, box->y, box->width, box->height); - pixman_region32_intersect_rect(&output_damage->current, - &output_damage->current, 0, 0, width, height); - wlr_output_schedule_frame(output_damage->output); + wlr_output_damage_add(output_damage, &damage); + pixman_region32_fini(&damage); } diff --git a/types/wlr_output_layout.c b/types/wlr_output_layout.c index 28d91e8d4..37c57fc66 100644 --- a/types/wlr_output_layout.c +++ b/types/wlr_output_layout.c @@ -6,7 +6,6 @@ #include #include #include -#include "util/signal.h" struct wlr_output_layout_output_state { struct wlr_output_layout *layout; @@ -37,7 +36,7 @@ struct wlr_output_layout *wlr_output_layout_create(void) { static void output_layout_output_destroy( struct wlr_output_layout_output *l_output) { - wlr_signal_emit_safe(&l_output->events.destroy, l_output); + wl_signal_emit_mutable(&l_output->events.destroy, l_output); wlr_output_destroy_global(l_output->output); wl_list_remove(&l_output->state->mode.link); wl_list_remove(&l_output->state->commit.link); @@ -52,7 +51,7 @@ void wlr_output_layout_destroy(struct wlr_output_layout *layout) { return; } - wlr_signal_emit_safe(&layout->events.destroy, layout); + wl_signal_emit_mutable(&layout->events.destroy, layout); struct wlr_output_layout_output *l_output, *temp; wl_list_for_each_safe(l_output, temp, &layout->outputs, link) { @@ -115,7 +114,7 @@ static void output_layout_reconfigure(struct wlr_output_layout *layout) { max_x += output_box.width; } - wlr_signal_emit_safe(&layout->events.change, layout); + wl_signal_emit_mutable(&layout->events.change, layout); } static void output_update_global(struct wlr_output *output) { @@ -211,7 +210,7 @@ void wlr_output_layout_add(struct wlr_output_layout *layout, output_update_global(output); if (is_new) { - wlr_signal_emit_safe(&layout->events.add, l_output); + wl_signal_emit_mutable(&layout->events.add, l_output); } } @@ -231,6 +230,9 @@ bool wlr_output_layout_contains_point(struct wlr_output_layout *layout, if (reference) { struct wlr_output_layout_output *l_output = wlr_output_layout_get(layout, reference); + if (!l_output) { + return false; + } struct wlr_box output_box; output_layout_output_get_box(l_output, &output_box); return wlr_box_contains_point(&output_box, lx, ly); @@ -363,6 +365,8 @@ void wlr_output_layout_closest_point(struct wlr_output_layout *layout, void wlr_output_layout_get_box(struct wlr_output_layout *layout, struct wlr_output *reference, struct wlr_box *dest_box) { + memset(dest_box, 0, sizeof(*dest_box)); + struct wlr_output_layout_output *l_output; if (reference) { // output extents @@ -370,8 +374,6 @@ void wlr_output_layout_get_box(struct wlr_output_layout *layout, if (l_output) { output_layout_output_get_box(l_output, dest_box); - } else { - dest_box->width = dest_box->height = 0; } } else { // layout extents @@ -422,7 +424,7 @@ void wlr_output_layout_add_auto(struct wlr_output_layout *layout, output_update_global(output); if (is_new) { - wlr_signal_emit_safe(&layout->events.add, l_output); + wl_signal_emit_mutable(&layout->events.add, l_output); } } @@ -457,6 +459,10 @@ static struct wlr_output *wlr_output_layout_output_in_direction( struct wlr_box ref_box; wlr_output_layout_get_box(layout, reference, &ref_box); + if (wlr_box_empty(&ref_box)) { + // The output doesn't belong to the layout + return NULL; + } double min_distance = (distance_method == NEAREST) ? DBL_MAX : DBL_MIN; struct wlr_output *closest_output = NULL; diff --git a/types/wlr_output_management_v1.c b/types/wlr_output_management_v1.c index 7acfe9d95..3fb9cf432 100644 --- a/types/wlr_output_management_v1.c +++ b/types/wlr_output_management_v1.c @@ -3,10 +3,9 @@ #include #include #include -#include "util/signal.h" #include "wlr-output-management-unstable-v1-protocol.h" -#define OUTPUT_MANAGER_VERSION 2 +#define OUTPUT_MANAGER_VERSION 3 enum { HEAD_STATE_ENABLED = 1 << 0, @@ -19,19 +18,23 @@ enum { static const uint32_t HEAD_STATE_ALL = HEAD_STATE_ENABLED | HEAD_STATE_MODE | HEAD_STATE_POSITION | HEAD_STATE_TRANSFORM | HEAD_STATE_SCALE; +static const struct zwlr_output_head_v1_interface head_impl; // Can return NULL if the head is inert static struct wlr_output_head_v1 *head_from_resource( struct wl_resource *resource) { assert(wl_resource_instance_of(resource, - &zwlr_output_head_v1_interface, NULL)); + &zwlr_output_head_v1_interface, &head_impl)); return wl_resource_get_user_data(resource); } +static const struct zwlr_output_mode_v1_interface output_mode_impl; + +// Can return NULL if the mode is inert static struct wlr_output_mode *mode_from_resource( struct wl_resource *resource) { assert(wl_resource_instance_of(resource, - &zwlr_output_mode_v1_interface, NULL)); + &zwlr_output_mode_v1_interface, &output_mode_impl)); return wl_resource_get_user_data(resource); } @@ -42,11 +45,15 @@ static void head_destroy(struct wlr_output_head_v1 *head) { struct wl_resource *resource, *tmp; wl_resource_for_each_safe(resource, tmp, &head->mode_resources) { zwlr_output_mode_v1_send_finished(resource); - wl_resource_destroy(resource); + wl_list_remove(wl_resource_get_link(resource)); + wl_list_init(wl_resource_get_link(resource)); + wl_resource_set_user_data(resource, NULL); } wl_resource_for_each_safe(resource, tmp, &head->resources) { zwlr_output_head_v1_send_finished(resource); - wl_resource_destroy(resource); + wl_list_remove(wl_resource_get_link(resource)); + wl_list_init(wl_resource_get_link(resource)); + wl_resource_set_user_data(resource, NULL); } wl_list_remove(&head->link); wl_list_remove(&head->output_destroy.link); @@ -413,7 +420,7 @@ static void config_handle_apply(struct wl_client *client, return; } - wlr_signal_emit_safe(&config->manager->events.apply, config); + wl_signal_emit_mutable(&config->manager->events.apply, config); } static void config_handle_test(struct wl_client *client, @@ -432,7 +439,7 @@ static void config_handle_test(struct wl_client *client, return; } - wlr_signal_emit_safe(&config->manager->events.test, config); + wl_signal_emit_mutable(&config->manager->events.test, config); } static void config_handle_destroy(struct wl_client *client, @@ -589,7 +596,7 @@ static void manager_handle_display_destroy(struct wl_listener *listener, void *data) { struct wlr_output_manager_v1 *manager = wl_container_of(listener, manager, display_destroy); - wlr_signal_emit_safe(&manager->events.destroy, manager); + wl_signal_emit_mutable(&manager->events.destroy, manager); wl_list_remove(&manager->display_destroy.link); struct wlr_output_head_v1 *head, *tmp; wl_list_for_each_safe(head, tmp, &manager->heads, link) { @@ -649,10 +656,19 @@ static void send_mode_state(struct wl_resource *mode_resource, } } -static void mode_handle_resource_destroy(struct wl_resource *resource) { +static void output_mode_handle_resource_destroy(struct wl_resource *resource) { wl_list_remove(wl_resource_get_link(resource)); } +static void output_mode_handle_release(struct wl_client *client, + struct wl_resource *resource) { + wl_resource_destroy(resource); +} + +static const struct zwlr_output_mode_v1_interface output_mode_impl = { + .release = output_mode_handle_release, +}; + static struct wl_resource *head_send_mode(struct wlr_output_head_v1 *head, struct wl_resource *head_resource, struct wlr_output_mode *mode) { struct wl_client *client = wl_resource_get_client(head_resource); @@ -663,8 +679,8 @@ static struct wl_resource *head_send_mode(struct wlr_output_head_v1 *head, wl_resource_post_no_memory(head_resource); return NULL; } - wl_resource_set_implementation(mode_resource, NULL, mode, - mode_handle_resource_destroy); + wl_resource_set_implementation(mode_resource, &output_mode_impl, mode, + output_mode_handle_resource_destroy); wl_list_insert(&head->mode_resources, wl_resource_get_link(mode_resource)); zwlr_output_head_v1_send_mode(head_resource, mode_resource); @@ -740,6 +756,15 @@ static void head_handle_resource_destroy(struct wl_resource *resource) { wl_list_remove(wl_resource_get_link(resource)); } +static void head_handle_release(struct wl_client *client, + struct wl_resource *resource) { + wl_resource_destroy(resource); +} + +static const struct zwlr_output_head_v1_interface head_impl = { + .release = head_handle_release, +}; + static void manager_send_head(struct wlr_output_manager_v1 *manager, struct wlr_output_head_v1 *head, struct wl_resource *manager_resource) { struct wlr_output *output = head->state.output; @@ -752,7 +777,7 @@ static void manager_send_head(struct wlr_output_manager_v1 *manager, wl_resource_post_no_memory(manager_resource); return; } - wl_resource_set_implementation(head_resource, NULL, head, + wl_resource_set_implementation(head_resource, &head_impl, head, head_handle_resource_destroy); wl_list_insert(&head->resources, wl_resource_get_link(head_resource)); @@ -767,13 +792,13 @@ static void manager_send_head(struct wlr_output_manager_v1 *manager, output->phys_width, output->phys_height); } - if (version >= ZWLR_OUTPUT_HEAD_V1_MAKE_SINCE_VERSION && output->make[0] != '\0') { + if (version >= ZWLR_OUTPUT_HEAD_V1_MAKE_SINCE_VERSION && output->make != NULL) { zwlr_output_head_v1_send_make(head_resource, output->make); } - if (version >= ZWLR_OUTPUT_HEAD_V1_MODEL_SINCE_VERSION && output->model[0] != '\0') { + if (version >= ZWLR_OUTPUT_HEAD_V1_MODEL_SINCE_VERSION && output->model != NULL) { zwlr_output_head_v1_send_model(head_resource, output->model); } - if (version >= ZWLR_OUTPUT_HEAD_V1_SERIAL_NUMBER_SINCE_VERSION && output->serial[0] != '\0') { + if (version >= ZWLR_OUTPUT_HEAD_V1_SERIAL_NUMBER_SINCE_VERSION && output->serial != NULL) { zwlr_output_head_v1_send_serial_number(head_resource, output->serial); } @@ -907,3 +932,25 @@ void wlr_output_manager_v1_set_configuration( } manager->current_configuration_dirty = false; } + +void wlr_output_head_v1_state_apply( + const struct wlr_output_head_v1_state *head_state, + struct wlr_output_state *output_state) { + wlr_output_state_set_enabled(output_state, head_state->enabled); + + if (!head_state->enabled) { + return; + } + + if (head_state->mode != NULL) { + wlr_output_state_set_mode(output_state, head_state->mode); + } else { + wlr_output_state_set_custom_mode(output_state, + head_state->custom_mode.width, + head_state->custom_mode.height, + head_state->custom_mode.refresh); + } + + wlr_output_state_set_scale(output_state, head_state->scale); + wlr_output_state_set_transform(output_state, head_state->transform); +} diff --git a/types/wlr_output_power_management_v1.c b/types/wlr_output_power_management_v1.c index e607eb161..7e4d1b3f7 100644 --- a/types/wlr_output_power_management_v1.c +++ b/types/wlr_output_power_management_v1.c @@ -7,7 +7,6 @@ #include #include #include -#include "util/signal.h" #include "wlr-output-power-management-unstable-v1-protocol.h" #define OUTPUT_POWER_MANAGER_V1_VERSION 1 @@ -93,7 +92,7 @@ static void output_power_handle_set_mode(struct wl_client *client, .output = output_power->output, .mode = mode, }; - wlr_signal_emit_safe(&output_power->manager->events.set_mode, &event); + wl_signal_emit_mutable(&output_power->manager->events.set_mode, &event); } static const struct zwlr_output_power_v1_interface output_power_impl = { @@ -196,7 +195,7 @@ static void output_power_manager_bind(struct wl_client *client, void *data, static void handle_display_destroy(struct wl_listener *listener, void *data) { struct wlr_output_power_manager_v1 *manager = wl_container_of(listener, manager, display_destroy); - wlr_signal_emit_safe(&manager->events.destroy, manager); + wl_signal_emit_mutable(&manager->events.destroy, manager); wl_global_destroy(manager->global); free(manager); } diff --git a/types/wlr_pointer.c b/types/wlr_pointer.c index caabec1b3..be505b6c4 100644 --- a/types/wlr_pointer.c +++ b/types/wlr_pointer.c @@ -1,13 +1,22 @@ +#include #include #include #include #include #include +#include "interfaces/wlr_input_device.h" + +struct wlr_pointer *wlr_pointer_from_input_device( + struct wlr_input_device *input_device) { + assert(input_device->type == WLR_INPUT_DEVICE_POINTER); + return wl_container_of(input_device, (struct wlr_pointer *)NULL, base); +} + void wlr_pointer_init(struct wlr_pointer *pointer, const struct wlr_pointer_impl *impl, const char *name) { + memset(pointer, 0, sizeof(*pointer)); wlr_input_device_init(&pointer->base, WLR_INPUT_DEVICE_POINTER, name); - pointer->base.pointer = pointer; pointer->impl = impl; wl_signal_init(&pointer->events.motion); @@ -25,14 +34,8 @@ void wlr_pointer_init(struct wlr_pointer *pointer, wl_signal_init(&pointer->events.hold_end); } -void wlr_pointer_destroy(struct wlr_pointer *pointer) { - if (!pointer) { - return; - } +void wlr_pointer_finish(struct wlr_pointer *pointer) { wlr_input_device_finish(&pointer->base); - if (pointer->impl && pointer->impl->destroy) { - pointer->impl->destroy(pointer); - } else { - free(pointer); - } + + free(pointer->output_name); } diff --git a/types/wlr_pointer_constraints_v1.c b/types/wlr_pointer_constraints_v1.c index e90daf72e..7a8d209bc 100644 --- a/types/wlr_pointer_constraints_v1.c +++ b/types/wlr_pointer_constraints_v1.c @@ -9,7 +9,6 @@ #include #include #include -#include "util/signal.h" static const struct zwp_locked_pointer_v1_interface locked_pointer_impl; static const struct zwp_confined_pointer_v1_interface confined_pointer_impl; @@ -47,7 +46,7 @@ static void pointer_constraint_destroy(struct wlr_pointer_constraint_v1 *constra wlr_log(WLR_DEBUG, "destroying constraint %p", constraint); - wlr_signal_emit_safe(&constraint->events.destroy, constraint); + wl_signal_emit_mutable(&constraint->events.destroy, constraint); wl_resource_set_user_data(constraint->resource, NULL); wl_list_remove(&constraint->link); @@ -130,7 +129,7 @@ static void pointer_constraint_commit( } if (updated_region) { - wlr_signal_emit_safe(&constraint->events.set_region, NULL); + wl_signal_emit_mutable(&constraint->events.set_region, NULL); } } @@ -246,7 +245,7 @@ static void pointer_constraint_create(struct wl_client *client, wl_list_insert(&pointer_constraints->constraints, &constraint->link); - wlr_signal_emit_safe(&pointer_constraints->events.new_constraint, + wl_signal_emit_mutable(&pointer_constraints->events.new_constraint, constraint); } diff --git a/types/wlr_pointer_gestures_v1.c b/types/wlr_pointer_gestures_v1.c index b8229dfc4..9089b4806 100644 --- a/types/wlr_pointer_gestures_v1.c +++ b/types/wlr_pointer_gestures_v1.c @@ -9,7 +9,6 @@ #include #include #include -#include "util/signal.h" #include "pointer-gestures-unstable-v1-protocol.h" #define POINTER_GESTURES_VERSION 3 @@ -52,13 +51,14 @@ void wlr_pointer_gestures_v1_send_swipe_begin( uint32_t time_msec, uint32_t fingers) { struct wlr_surface *focus = seat->pointer_state.focused_surface; - if (focus == NULL) { + struct wlr_seat_client *focus_seat_client = + seat->pointer_state.focused_client; + if (focus == NULL || focus_seat_client == NULL) { return; } - struct wl_client *focus_client = wl_resource_get_client(focus->resource); - uint32_t serial = wlr_seat_client_next_serial( - seat->pointer_state.focused_client); + struct wl_client *focus_client = focus_seat_client->client; + uint32_t serial = wlr_seat_client_next_serial(focus_seat_client); struct wl_resource *gesture; wl_resource_for_each(gesture, &gestures->swipes) { @@ -79,11 +79,13 @@ void wlr_pointer_gestures_v1_send_swipe_update( double dx, double dy) { struct wlr_surface *focus = seat->pointer_state.focused_surface; - if (focus == NULL) { + struct wlr_seat_client *focus_seat_client = + seat->pointer_state.focused_client; + if (focus == NULL || focus_seat_client == NULL) { return; } - struct wl_client *focus_client = wl_resource_get_client(focus->resource); + struct wl_client *focus_client = focus_seat_client->client; struct wl_resource *gesture; wl_resource_for_each(gesture, &gestures->swipes) { @@ -103,13 +105,14 @@ void wlr_pointer_gestures_v1_send_swipe_end( uint32_t time_msec, bool cancelled) { struct wlr_surface *focus = seat->pointer_state.focused_surface; - if (focus == NULL) { + struct wlr_seat_client *focus_seat_client = + seat->pointer_state.focused_client; + if (focus == NULL || focus_seat_client == NULL) { return; } - struct wl_client *focus_client = wl_resource_get_client(focus->resource); - uint32_t serial = wlr_seat_client_next_serial( - seat->pointer_state.focused_client); + struct wl_client *focus_client = focus_seat_client->client; + uint32_t serial = wlr_seat_client_next_serial(focus_seat_client); struct wl_resource *gesture; wl_resource_for_each(gesture, &gestures->swipes) { @@ -164,13 +167,14 @@ void wlr_pointer_gestures_v1_send_pinch_begin( uint32_t time_msec, uint32_t fingers) { struct wlr_surface *focus = seat->pointer_state.focused_surface; - if (focus == NULL) { + struct wlr_seat_client *focus_seat_client = + seat->pointer_state.focused_client; + if (focus == NULL || focus_seat_client == NULL) { return; } - struct wl_client *focus_client = wl_resource_get_client(focus->resource); - uint32_t serial = wlr_seat_client_next_serial( - seat->pointer_state.focused_client); + struct wl_client *focus_client = focus_seat_client->client; + uint32_t serial = wlr_seat_client_next_serial(focus_seat_client); struct wl_resource *gesture; wl_resource_for_each(gesture, &gestures->pinches) { @@ -193,11 +197,13 @@ void wlr_pointer_gestures_v1_send_pinch_update( double scale, double rotation) { struct wlr_surface *focus = seat->pointer_state.focused_surface; - if (focus == NULL) { + struct wlr_seat_client *focus_seat_client = + seat->pointer_state.focused_client; + if (focus == NULL || focus_seat_client == NULL) { return; } - struct wl_client *focus_client = wl_resource_get_client(focus->resource); + struct wl_client *focus_client = focus_seat_client->client; struct wl_resource *gesture; wl_resource_for_each(gesture, &gestures->pinches) { @@ -219,13 +225,14 @@ void wlr_pointer_gestures_v1_send_pinch_end( uint32_t time_msec, bool cancelled) { struct wlr_surface *focus = seat->pointer_state.focused_surface; - if (focus == NULL) { + struct wlr_seat_client *focus_seat_client = + seat->pointer_state.focused_client; + if (focus == NULL || focus_seat_client == NULL) { return; } - struct wl_client *focus_client = wl_resource_get_client(focus->resource); - uint32_t serial = wlr_seat_client_next_serial( - seat->pointer_state.focused_client); + struct wl_client *focus_client = focus_seat_client->client; + uint32_t serial = wlr_seat_client_next_serial(focus_seat_client); struct wl_resource *gesture; wl_resource_for_each(gesture, &gestures->pinches) { @@ -285,13 +292,14 @@ void wlr_pointer_gestures_v1_send_hold_begin( uint32_t time_msec, uint32_t fingers) { struct wlr_surface *focus = seat->pointer_state.focused_surface; - if (focus == NULL) { + struct wlr_seat_client *focus_seat_client = + seat->pointer_state.focused_client; + if (focus == NULL || focus_seat_client == NULL) { return; } - struct wl_client *focus_client = wl_resource_get_client(focus->resource); - uint32_t serial = wlr_seat_client_next_serial( - seat->pointer_state.focused_client); + struct wl_client *focus_client = focus_seat_client->client; + uint32_t serial = wlr_seat_client_next_serial(focus_seat_client); struct wl_resource *gesture; wl_resource_for_each(gesture, &gestures->holds) { @@ -311,13 +319,14 @@ void wlr_pointer_gestures_v1_send_hold_end( uint32_t time_msec, bool cancelled) { struct wlr_surface *focus = seat->pointer_state.focused_surface; - if (focus == NULL) { + struct wlr_seat_client *focus_seat_client = + seat->pointer_state.focused_client; + if (focus == NULL || focus_seat_client == NULL) { return; } - struct wl_client *focus_client = wl_resource_get_client(focus->resource); - uint32_t serial = wlr_seat_client_next_serial( - seat->pointer_state.focused_client); + struct wl_client *focus_client = focus_seat_client->client; + uint32_t serial = wlr_seat_client_next_serial(focus_seat_client); struct wl_resource *gesture; wl_resource_for_each(gesture, &gestures->holds) { diff --git a/types/wlr_presentation_time.c b/types/wlr_presentation_time.c index a6facbdbe..115315315 100644 --- a/types/wlr_presentation_time.c +++ b/types/wlr_presentation_time.c @@ -7,7 +7,6 @@ #include #include #include "presentation-time-protocol.h" -#include "util/signal.h" #define PRESENTATION_VERSION 1 @@ -173,7 +172,7 @@ static void presentation_bind(struct wl_client *client, void *data, static void handle_display_destroy(struct wl_listener *listener, void *data) { struct wlr_presentation *presentation = wl_container_of(listener, presentation, display_destroy); - wlr_signal_emit_safe(&presentation->events.destroy, presentation); + wl_signal_emit_mutable(&presentation->events.destroy, presentation); wl_list_remove(&presentation->display_destroy.link); wl_global_destroy(presentation->global); free(presentation); diff --git a/types/wlr_primary_selection.c b/types/wlr_primary_selection.c index 0875462c8..d576bf0a4 100644 --- a/types/wlr_primary_selection.c +++ b/types/wlr_primary_selection.c @@ -2,12 +2,12 @@ #include #include #include -#include "util/signal.h" void wlr_primary_selection_source_init( struct wlr_primary_selection_source *source, const struct wlr_primary_selection_source_impl *impl) { assert(impl->send); + memset(source, 0, sizeof(*source)); wl_array_init(&source->mime_types); wl_signal_init(&source->events.destroy); source->impl = impl; @@ -19,7 +19,7 @@ void wlr_primary_selection_source_destroy( return; } - wlr_signal_emit_safe(&source->events.destroy, source); + wl_signal_emit_mutable(&source->events.destroy, source); char **p; wl_array_for_each(p, &source->mime_types) { @@ -62,7 +62,7 @@ void wlr_seat_request_set_primary_selection(struct wlr_seat *seat, .source = source, .serial = serial, }; - wlr_signal_emit_safe(&seat->events.request_set_primary_selection, &event); + wl_signal_emit_mutable(&seat->events.request_set_primary_selection, &event); } static void seat_handle_primary_selection_source_destroy( @@ -71,7 +71,7 @@ static void seat_handle_primary_selection_source_destroy( wl_container_of(listener, seat, primary_selection_source_destroy); wl_list_remove(&seat->primary_selection_source_destroy.link); seat->primary_selection_source = NULL; - wlr_signal_emit_safe(&seat->events.set_primary_selection, seat); + wl_signal_emit_mutable(&seat->events.set_primary_selection, seat); } void wlr_seat_set_primary_selection(struct wlr_seat *seat, @@ -97,5 +97,5 @@ void wlr_seat_set_primary_selection(struct wlr_seat *seat, &seat->primary_selection_source_destroy); } - wlr_signal_emit_safe(&seat->events.set_primary_selection, seat); + wl_signal_emit_mutable(&seat->events.set_primary_selection, seat); } diff --git a/types/wlr_primary_selection_v1.c b/types/wlr_primary_selection_v1.c index 009b09557..511d5ddb9 100644 --- a/types/wlr_primary_selection_v1.c +++ b/types/wlr_primary_selection_v1.c @@ -9,7 +9,6 @@ #include #include #include "primary-selection-unstable-v1-protocol.h" -#include "util/signal.h" #define DEVICE_MANAGER_VERSION 1 @@ -458,7 +457,7 @@ static void handle_display_destroy(struct wl_listener *listener, void *data) { device_destroy(device); } - wlr_signal_emit_safe(&manager->events.destroy, manager); + wl_signal_emit_mutable(&manager->events.destroy, manager); wl_list_remove(&manager->display_destroy.link); wl_global_destroy(manager->global); free(manager); diff --git a/types/wlr_relative_pointer_v1.c b/types/wlr_relative_pointer_v1.c index 8613f2b91..44da791f7 100644 --- a/types/wlr_relative_pointer_v1.c +++ b/types/wlr_relative_pointer_v1.c @@ -1,7 +1,6 @@ #include #include #include -#include #include #include #include @@ -14,31 +13,20 @@ static const struct zwp_relative_pointer_manager_v1_interface relative_pointer_manager_v1_impl; static const struct zwp_relative_pointer_v1_interface relative_pointer_v1_impl; - -/** - * helper functions - */ - struct wlr_relative_pointer_v1 *wlr_relative_pointer_v1_from_resource(struct wl_resource *resource) { assert(wl_resource_instance_of(resource, &zwp_relative_pointer_v1_interface, &relative_pointer_v1_impl)); return wl_resource_get_user_data(resource); } - static struct wlr_relative_pointer_manager_v1 *relative_pointer_manager_from_resource(struct wl_resource *resource) { assert(wl_resource_instance_of(resource, &zwp_relative_pointer_manager_v1_interface, &relative_pointer_manager_v1_impl)); return wl_resource_get_user_data(resource); } - -/** - * relative_pointer handler functions - */ - static void relative_pointer_destroy(struct wlr_relative_pointer_v1 *relative_pointer) { - wlr_signal_emit_safe(&relative_pointer->events.destroy, relative_pointer); + wl_signal_emit_mutable(&relative_pointer->events.destroy, relative_pointer); wl_list_remove(&relative_pointer->link); wl_list_remove(&relative_pointer->seat_destroy.link); @@ -57,14 +45,8 @@ static void relative_pointer_v1_handle_resource_destroy(struct wl_resource *reso relative_pointer_destroy(relative_pointer); } - static void relative_pointer_v1_handle_destroy(struct wl_client *client, struct wl_resource *resource) { - struct wlr_relative_pointer_v1 *relative_pointer = - wlr_relative_pointer_v1_from_resource(resource); - wlr_log(WLR_DEBUG, "relative_pointer_v1 %p released by client %p", - relative_pointer, client); - wl_resource_destroy(resource); } @@ -84,23 +66,32 @@ static void relative_pointer_handle_pointer_destroy(struct wl_listener *listener relative_pointer_destroy(relative_pointer); } -/** - * relative_pointer_manager handler functions - */ - static void relative_pointer_manager_v1_handle_destroy(struct wl_client *client, struct wl_resource *resource) { wl_resource_destroy(resource); - - wlr_log(WLR_DEBUG, "relative_pointer_v1 manager unbound from client %p", - client); } static void relative_pointer_manager_v1_handle_get_relative_pointer(struct wl_client *client, struct wl_resource *resource, uint32_t id, struct wl_resource *pointer) { + struct wlr_relative_pointer_manager_v1 *manager = + relative_pointer_manager_from_resource(resource); struct wlr_seat_client *seat_client = wlr_seat_client_from_pointer_resource(pointer); + struct wl_resource *relative_pointer_resource = wl_resource_create(client, + &zwp_relative_pointer_v1_interface, wl_resource_get_version(resource), id); + if (relative_pointer_resource == NULL) { + wl_client_post_no_memory(client); + return; + } + wl_resource_set_implementation(relative_pointer_resource, &relative_pointer_v1_impl, + NULL, relative_pointer_v1_handle_resource_destroy); + + if (seat_client == NULL) { + // Leave the resource inert + return; + } + struct wlr_relative_pointer_v1 *relative_pointer = calloc(1, sizeof(struct wlr_relative_pointer_v1)); if (relative_pointer == NULL) { @@ -108,45 +99,28 @@ static void relative_pointer_manager_v1_handle_get_relative_pointer(struct wl_cl return; } - struct wl_resource *relative_pointer_resource = wl_resource_create(client, - &zwp_relative_pointer_v1_interface, wl_resource_get_version(resource), id); - if (relative_pointer_resource == NULL) { - free(relative_pointer); - wl_client_post_no_memory(client); - return; - } - relative_pointer->resource = relative_pointer_resource; - relative_pointer->seat = seat_client->seat; relative_pointer->pointer_resource = pointer; + relative_pointer->seat = seat_client->seat; + wl_signal_add(&relative_pointer->seat->events.destroy, + &relative_pointer->seat_destroy); + relative_pointer->seat_destroy.notify = relative_pointer_handle_seat_destroy; + wl_signal_init(&relative_pointer->events.destroy); - wl_resource_set_implementation(relative_pointer_resource, &relative_pointer_v1_impl, - relative_pointer, relative_pointer_v1_handle_resource_destroy); + wl_resource_set_user_data(relative_pointer_resource, relative_pointer); - struct wlr_relative_pointer_manager_v1 *manager = - relative_pointer_manager_from_resource(resource); - - wl_list_insert(&manager->relative_pointers, - &relative_pointer->link); - - wl_signal_add(&relative_pointer->seat->events.destroy, - &relative_pointer->seat_destroy); - relative_pointer->seat_destroy.notify = relative_pointer_handle_seat_destroy; + wl_list_insert(&manager->relative_pointers, &relative_pointer->link); wl_resource_add_destroy_listener(relative_pointer->pointer_resource, &relative_pointer->pointer_destroy); relative_pointer->pointer_destroy.notify = relative_pointer_handle_pointer_destroy; - wlr_signal_emit_safe(&manager->events.new_relative_pointer, + wl_signal_emit_mutable(&manager->events.new_relative_pointer, relative_pointer); - - wlr_log(WLR_DEBUG, "relative_pointer_v1 %p created for client %p", - relative_pointer, client); } - static void relative_pointer_manager_v1_bind(struct wl_client *wl_client, void *data, uint32_t version, uint32_t id) { struct wlr_relative_pointer_manager_v1 *manager = data; @@ -165,32 +139,21 @@ static void relative_pointer_manager_v1_bind(struct wl_client *wl_client, void * static void handle_display_destroy(struct wl_listener *listener, void *data) { struct wlr_relative_pointer_manager_v1 *manager = wl_container_of(listener, manager, display_destroy_listener); - wlr_signal_emit_safe(&manager->events.destroy, manager); + wl_signal_emit_mutable(&manager->events.destroy, manager); wl_list_remove(&manager->display_destroy_listener.link); wl_global_destroy(manager->global); free(manager); } - -/** - * Implementations - */ - static const struct zwp_relative_pointer_manager_v1_interface relative_pointer_manager_v1_impl = { .destroy = relative_pointer_manager_v1_handle_destroy, .get_relative_pointer = relative_pointer_manager_v1_handle_get_relative_pointer, }; - static const struct zwp_relative_pointer_v1_interface relative_pointer_v1_impl = { .destroy = relative_pointer_v1_handle_destroy, }; - -/** - * Public functions - */ - struct wlr_relative_pointer_manager_v1 *wlr_relative_pointer_manager_v1_create(struct wl_display *display) { struct wlr_relative_pointer_manager_v1 *manager = calloc(1, sizeof(struct wlr_relative_pointer_manager_v1)); @@ -230,7 +193,7 @@ void wlr_relative_pointer_manager_v1_send_relative_motion( wl_list_for_each(pointer, &manager->relative_pointers, link) { struct wlr_seat_client *seat_client = wlr_seat_client_from_pointer_resource(pointer->pointer_resource); - if (seat != pointer->seat || focused != seat_client) { + if (!pointer->seat || seat != pointer->seat || focused != seat_client) { continue; } diff --git a/types/wlr_screencopy_v1.c b/types/wlr_screencopy_v1.c index e2c020db5..30e529a9a 100644 --- a/types/wlr_screencopy_v1.c +++ b/types/wlr_screencopy_v1.c @@ -12,7 +12,6 @@ #include #include "wlr-screencopy-unstable-v1-protocol.h" #include "render/pixel_format.h" -#include "util/signal.h" #define SCREENCOPY_MANAGER_VERSION 3 @@ -40,16 +39,18 @@ static struct screencopy_damage *screencopy_damage_find( return NULL; } -static void screencopy_damage_accumulate(struct screencopy_damage *damage) { +static void screencopy_damage_accumulate(struct screencopy_damage *damage, + const struct wlr_output_state *state) { struct pixman_region32 *region = &damage->damage; struct wlr_output *output = damage->output; - if (output->pending.committed & WLR_OUTPUT_STATE_DAMAGE) { + if (state->committed & WLR_OUTPUT_STATE_DAMAGE) { // If the compositor submitted damage, copy it over - pixman_region32_union(region, region, &output->pending.damage); + pixman_region32_union(region, region, + (pixman_region32_t *) &state->damage); pixman_region32_intersect_rect(region, region, 0, 0, output->width, output->height); - } else if (output->pending.committed & WLR_OUTPUT_STATE_BUFFER) { + } else if (state->committed & WLR_OUTPUT_STATE_BUFFER) { // If the compositor did not submit damage but did submit a buffer // damage everything pixman_region32_union_rect(region, region, 0, 0, @@ -61,7 +62,8 @@ static void screencopy_damage_handle_output_precommit( struct wl_listener *listener, void *data) { struct screencopy_damage *damage = wl_container_of(listener, damage, output_precommit); - screencopy_damage_accumulate(damage); + const struct wlr_output_event_precommit *event = data; + screencopy_damage_accumulate(damage, event->state); } static void screencopy_damage_destroy(struct screencopy_damage *damage) { @@ -542,6 +544,12 @@ static void capture_output(struct wl_client *wl_client, "Failed to capture output: no read format supported by renderer"); goto error; } + const struct wlr_pixel_format_info *info = drm_get_pixel_format_info(drm_format); + if (!info) { + wlr_log(WLR_ERROR, + "Failed to capture output: no pixel format info matching read format"); + goto error; + } frame->format = convert_drm_format_to_wl_shm(drm_format); if (output->allocator && @@ -569,7 +577,7 @@ static void capture_output(struct wl_client *wl_client, } frame->box = buffer_box; - frame->stride = 4 * buffer_box.width; // TODO: depends on read format + frame->stride = (info->bpp / 8) * buffer_box.width; zwlr_screencopy_frame_v1_send_buffer(frame->resource, frame->format, buffer_box.width, buffer_box.height, frame->stride); @@ -671,7 +679,7 @@ failure: static void handle_display_destroy(struct wl_listener *listener, void *data) { struct wlr_screencopy_manager_v1 *manager = wl_container_of(listener, manager, display_destroy); - wlr_signal_emit_safe(&manager->events.destroy, manager); + wl_signal_emit_mutable(&manager->events.destroy, manager); wl_list_remove(&manager->display_destroy.link); wl_global_destroy(manager->global); free(manager); diff --git a/types/wlr_server_decoration.c b/types/wlr_server_decoration.c index a80793939..425230ec3 100644 --- a/types/wlr_server_decoration.c +++ b/types/wlr_server_decoration.c @@ -4,7 +4,6 @@ #include #include #include "server-decoration-protocol.h" -#include "util/signal.h" static const struct org_kde_kwin_server_decoration_interface server_decoration_impl; @@ -29,14 +28,14 @@ static void server_decoration_handle_request_mode(struct wl_client *client, return; } decoration->mode = mode; - wlr_signal_emit_safe(&decoration->events.mode, decoration); + wl_signal_emit_mutable(&decoration->events.mode, decoration); org_kde_kwin_server_decoration_send_mode(decoration->resource, decoration->mode); } static void server_decoration_destroy( struct wlr_server_decoration *decoration) { - wlr_signal_emit_safe(&decoration->events.destroy, decoration); + wl_signal_emit_mutable(&decoration->events.destroy, decoration); wl_list_remove(&decoration->surface_destroy_listener.link); wl_resource_set_user_data(decoration->resource, NULL); wl_list_remove(&decoration->link); @@ -119,7 +118,7 @@ static void server_decoration_manager_handle_create(struct wl_client *client, org_kde_kwin_server_decoration_send_mode(decoration->resource, decoration->mode); - wlr_signal_emit_safe(&manager->events.new_decoration, decoration); + wl_signal_emit_mutable(&manager->events.new_decoration, decoration); } static const struct org_kde_kwin_server_decoration_manager_interface @@ -166,7 +165,7 @@ static void server_decoration_manager_bind(struct wl_client *client, void *data, static void handle_display_destroy(struct wl_listener *listener, void *data) { struct wlr_server_decoration_manager *manager = wl_container_of(listener, manager, display_destroy); - wlr_signal_emit_safe(&manager->events.destroy, manager); + wl_signal_emit_mutable(&manager->events.destroy, manager); wl_list_remove(&manager->display_destroy.link); wl_global_destroy(manager->global); free(manager); diff --git a/types/wlr_session_lock_v1.c b/types/wlr_session_lock_v1.c index ffba20614..294b4a872 100644 --- a/types/wlr_session_lock_v1.c +++ b/types/wlr_session_lock_v1.c @@ -6,7 +6,6 @@ #include #include #include -#include "util/signal.h" #include "ext-session-lock-v1-protocol.h" #define SESSION_LOCK_VERSION 1 @@ -157,7 +156,7 @@ static void lock_surface_role_commit(struct wlr_surface *surface) { if (!lock_surface->mapped) { lock_surface->mapped = true; - wlr_signal_emit_safe(&lock_surface->events.map, NULL); + wl_signal_emit_mutable(&lock_surface->events.map, NULL); } } @@ -185,7 +184,7 @@ static const struct wlr_surface_role lock_surface_role = { static void lock_surface_destroy( struct wlr_session_lock_surface_v1 *lock_surface) { - wlr_signal_emit_safe(&lock_surface->events.destroy, NULL); + wl_signal_emit_mutable(&lock_surface->events.destroy, NULL); wl_list_remove(&lock_surface->link); @@ -312,7 +311,7 @@ static void lock_handle_get_lock_surface(struct wl_client *client, wl_signal_add(&surface->events.destroy, &lock_surface->surface_destroy); lock_surface->surface_destroy.notify = lock_surface_handle_surface_destroy; - wlr_signal_emit_safe(&lock->events.new_surface, lock_surface); + wl_signal_emit_mutable(&lock->events.new_surface, lock_surface); } static void lock_handle_unlock_and_destroy(struct wl_client *client, @@ -322,7 +321,7 @@ static void lock_handle_unlock_and_destroy(struct wl_client *client, return; } - wlr_signal_emit_safe(&lock->events.unlock, NULL); + wl_signal_emit_mutable(&lock->events.unlock, NULL); wl_resource_destroy(lock_resource); } @@ -344,7 +343,7 @@ static void lock_destroy(struct wlr_session_lock_v1 *lock) { } assert(wl_list_empty(&lock->surfaces)); - wlr_signal_emit_safe(&lock->events.destroy, NULL); + wl_signal_emit_mutable(&lock->events.destroy, NULL); assert(wl_list_empty(&lock->events.new_surface.listener_list)); assert(wl_list_empty(&lock->events.unlock.listener_list)); @@ -395,7 +394,7 @@ static void lock_manager_handle_lock(struct wl_client *client, wl_resource_set_implementation(lock->resource, &lock_implementation, lock, lock_resource_destroy); - wlr_signal_emit_safe(&lock_manager->events.new_lock, lock); + wl_signal_emit_mutable(&lock_manager->events.new_lock, lock); } static const struct ext_session_lock_manager_v1_interface lock_manager_implementation = { @@ -420,7 +419,7 @@ static void lock_manager_bind(struct wl_client *client, void *data, static void handle_display_destroy(struct wl_listener *listener, void *data) { struct wlr_session_lock_manager_v1 *lock_manager = wl_container_of(listener, lock_manager, display_destroy); - wlr_signal_emit_safe(&lock_manager->events.destroy, NULL); + wl_signal_emit_mutable(&lock_manager->events.destroy, NULL); wl_list_remove(&lock_manager->display_destroy.link); wl_global_destroy(lock_manager->global); diff --git a/types/wlr_single_pixel_buffer_v1.c b/types/wlr_single_pixel_buffer_v1.c new file mode 100644 index 000000000..e4dac829f --- /dev/null +++ b/types/wlr_single_pixel_buffer_v1.c @@ -0,0 +1,172 @@ +#include +#include +#include +#include +#include +#include +#include "single-pixel-buffer-v1-protocol.h" + +#define SINGLE_PIXEL_MANAGER_VERSION 1 + +struct wlr_single_pixel_buffer_manager_v1 { + struct wl_global *global; + + struct wl_listener display_destroy; +}; + +struct wlr_single_pixel_buffer_v1 { + struct wlr_buffer base; + struct wl_resource *resource; + uint32_t r, g, b, a; + uint8_t argb8888[4]; // packed little-endian DRM_FORMAT_ARGB8888 +}; + +static void destroy_resource(struct wl_client *client, + struct wl_resource *resource) { + wl_resource_destroy(resource); +} + +static const struct wl_buffer_interface wl_buffer_impl = { + .destroy = destroy_resource, +}; + +static const struct wlr_buffer_impl buffer_impl; + +static bool buffer_resource_is_instance(struct wl_resource *resource) { + return wl_resource_instance_of(resource, &wl_buffer_interface, + &wl_buffer_impl); +} + +static struct wlr_single_pixel_buffer_v1 *single_pixel_buffer_v1_from_resource( + struct wl_resource *resource) { + assert(buffer_resource_is_instance(resource)); + return wl_resource_get_user_data(resource); +} + +static struct wlr_buffer *buffer_from_resource( + struct wl_resource *resource) { + return &single_pixel_buffer_v1_from_resource(resource)->base; +} + +static const struct wlr_buffer_resource_interface buffer_resource_interface = { + .name = "single_pixel_buffer_v1", + .is_instance = buffer_resource_is_instance, + .from_resource = buffer_from_resource, +}; + +static void buffer_destroy(struct wlr_buffer *wlr_buffer) { + struct wlr_single_pixel_buffer_v1 *buffer = + wl_container_of(wlr_buffer, buffer, base); + if (buffer->resource != NULL) { + wl_resource_set_user_data(buffer->resource, NULL); + } + free(buffer); +} + +static bool buffer_begin_data_ptr_access(struct wlr_buffer *wlr_buffer, + uint32_t flags, void **data, uint32_t *format, size_t *stride) { + struct wlr_single_pixel_buffer_v1 *buffer = + wl_container_of(wlr_buffer, buffer, base); + if (flags & ~WLR_BUFFER_DATA_PTR_ACCESS_READ) { + return false; // the buffer is read-only + } + *data = &buffer->argb8888; + *format = DRM_FORMAT_ARGB8888; + *stride = sizeof(buffer->argb8888); + return true; +} + +static void buffer_end_data_ptr_access(struct wlr_buffer *wlr_buffer) { + // This space is intentionally left blank +} + +static const struct wlr_buffer_impl buffer_impl = { + .destroy = buffer_destroy, + .begin_data_ptr_access = buffer_begin_data_ptr_access, + .end_data_ptr_access = buffer_end_data_ptr_access, +}; + +static void buffer_handle_resource_destroy(struct wl_resource *resource) { + struct wlr_single_pixel_buffer_v1 *buffer = single_pixel_buffer_v1_from_resource(resource); + buffer->resource = NULL; + wlr_buffer_drop(&buffer->base); +} + +static void manager_handle_create_u32_rgba_buffer(struct wl_client *client, + struct wl_resource *resource, uint32_t id, uint32_t r, uint32_t g, + uint32_t b, uint32_t a) { + struct wlr_single_pixel_buffer_v1 *buffer = calloc(1, sizeof(*buffer)); + if (buffer == NULL) { + wl_client_post_no_memory(client); + return; + } + + buffer->resource = wl_resource_create(client, &wl_buffer_interface, 1, id); + if (buffer->resource == NULL) { + wl_client_post_no_memory(client); + free(buffer); + return; + } + + wlr_buffer_init(&buffer->base, &buffer_impl, 1, 1); + wl_resource_set_implementation(buffer->resource, + &wl_buffer_impl, buffer, buffer_handle_resource_destroy); + + buffer->r = r; + buffer->g = g; + buffer->b = b; + buffer->a = a; + + double f = (double)0xFF / 0xFFFFFFFF; + buffer->argb8888[0] = (uint8_t)((double)buffer->b * f); + buffer->argb8888[1] = (uint8_t)((double)buffer->g * f); + buffer->argb8888[2] = (uint8_t)((double)buffer->r * f); + buffer->argb8888[3] = (uint8_t)((double)buffer->a * f); +} + +static const struct wp_single_pixel_buffer_manager_v1_interface manager_impl = { + .destroy = destroy_resource, + .create_u32_rgba_buffer = manager_handle_create_u32_rgba_buffer, +}; + +static void manager_bind(struct wl_client *client, void *data, + uint32_t version, uint32_t id) { + struct wl_resource *resource = wl_resource_create(client, + &wp_single_pixel_buffer_manager_v1_interface, version, id); + if (resource == NULL) { + wl_client_post_no_memory(client); + return; + } + wl_resource_set_implementation(resource, &manager_impl, NULL, NULL); +} + +static void handle_display_destroy(struct wl_listener *listener, void *data) { + struct wlr_single_pixel_buffer_manager_v1 *manager = + wl_container_of(listener, manager, display_destroy); + wl_global_destroy(manager->global); + free(manager); +} + +struct wlr_single_pixel_buffer_manager_v1 *wlr_single_pixel_buffer_manager_v1_create( + struct wl_display *display) { + struct wlr_single_pixel_buffer_manager_v1 *manager = calloc(1, sizeof(*manager)); + if (manager == NULL) { + return NULL; + } + + manager->global = wl_global_create(display, + &wp_single_pixel_buffer_manager_v1_interface, + SINGLE_PIXEL_MANAGER_VERSION, + NULL, manager_bind); + if (manager->global == NULL) { + free(manager); + return NULL; + } + + manager->display_destroy.notify = handle_display_destroy; + wl_display_add_destroy_listener(display, &manager->display_destroy); + + wlr_buffer_register_resource_interface(&buffer_resource_interface); + + return manager; +} diff --git a/types/wlr_subcompositor.c b/types/wlr_subcompositor.c index 2b9b97cd2..530f74765 100644 --- a/types/wlr_subcompositor.c +++ b/types/wlr_subcompositor.c @@ -4,7 +4,6 @@ #include #include #include "types/wlr_region.h" -#include "util/signal.h" #define SUBCOMPOSITOR_VERSION 1 @@ -37,7 +36,7 @@ static void subsurface_destroy(struct wlr_subsurface *subsurface) { subsurface_unmap(subsurface); - wlr_signal_emit_safe(&subsurface->events.destroy, subsurface); + wl_signal_emit_mutable(&subsurface->events.destroy, subsurface); wl_list_remove(&subsurface->surface_destroy.link); wl_list_remove(&subsurface->surface_client_commit.link); @@ -229,8 +228,8 @@ static void subsurface_consider_map(struct wlr_subsurface *subsurface, } // Now we can map the subsurface - wlr_signal_emit_safe(&subsurface->events.map, subsurface); subsurface->mapped = true; + wl_signal_emit_mutable(&subsurface->events.map, subsurface); // Try mapping all children too struct wlr_subsurface *child; @@ -249,8 +248,8 @@ static void subsurface_unmap(struct wlr_subsurface *subsurface) { return; } - wlr_signal_emit_safe(&subsurface->events.unmap, subsurface); subsurface->mapped = false; + wl_signal_emit_mutable(&subsurface->events.unmap, subsurface); // Unmap all children struct wlr_subsurface *child; @@ -374,6 +373,8 @@ static struct wlr_subsurface *subsurface_create(struct wlr_surface *surface, surface->role_data = subsurface; + subsurface_consider_map(subsurface, true); + return subsurface; } @@ -456,7 +457,7 @@ static void subcompositor_handle_display_destroy( struct wl_listener *listener, void *data) { struct wlr_subcompositor *subcompositor = wl_container_of(listener, subcompositor, display_destroy); - wlr_signal_emit_safe(&subcompositor->events.destroy, NULL); + wl_signal_emit_mutable(&subcompositor->events.destroy, NULL); wl_list_remove(&subcompositor->display_destroy.link); wl_global_destroy(subcompositor->global); free(subcompositor); diff --git a/types/wlr_switch.c b/types/wlr_switch.c index 42611da96..5a2083ff2 100644 --- a/types/wlr_switch.c +++ b/types/wlr_switch.c @@ -1,26 +1,27 @@ +#include #include #include #include #include #include +#include "interfaces/wlr_input_device.h" + +struct wlr_switch *wlr_switch_from_input_device( + struct wlr_input_device *input_device) { + assert(input_device->type == WLR_INPUT_DEVICE_SWITCH); + return wl_container_of(input_device, (struct wlr_switch *)NULL, base); +} + void wlr_switch_init(struct wlr_switch *switch_device, const struct wlr_switch_impl *impl, const char *name) { + memset(switch_device, 0, sizeof(*switch_device)); wlr_input_device_init(&switch_device->base, WLR_INPUT_DEVICE_SWITCH, name); - switch_device->base.switch_device = switch_device; switch_device->impl = impl; wl_signal_init(&switch_device->events.toggle); } -void wlr_switch_destroy(struct wlr_switch *switch_device) { - if (!switch_device) { - return; - } +void wlr_switch_finish(struct wlr_switch *switch_device) { wlr_input_device_finish(&switch_device->base); - if (switch_device->impl && switch_device->impl->destroy) { - switch_device->impl->destroy(switch_device); - } else { - free(switch_device); - } } diff --git a/types/wlr_tablet_pad.c b/types/wlr_tablet_pad.c index 663ccd39e..34c81301c 100644 --- a/types/wlr_tablet_pad.c +++ b/types/wlr_tablet_pad.c @@ -1,13 +1,23 @@ +#include #include #include #include #include #include +#include + +#include "interfaces/wlr_input_device.h" + +struct wlr_tablet_pad *wlr_tablet_pad_from_input_device( + struct wlr_input_device *input_device) { + assert(input_device->type == WLR_INPUT_DEVICE_TABLET_PAD); + return wl_container_of(input_device, (struct wlr_tablet_pad *)NULL, base); +} void wlr_tablet_pad_init(struct wlr_tablet_pad *pad, const struct wlr_tablet_pad_impl *impl, const char *name) { + memset(pad, 0, sizeof(*pad)); wlr_input_device_init(&pad->base, WLR_INPUT_DEVICE_TABLET_PAD, name); - pad->base.tablet_pad = pad; pad->impl = impl; wl_signal_init(&pad->events.button); @@ -19,10 +29,8 @@ void wlr_tablet_pad_init(struct wlr_tablet_pad *pad, wl_array_init(&pad->paths); } -void wlr_tablet_pad_destroy(struct wlr_tablet_pad *pad) { - if (!pad) { - return; - } +void wlr_tablet_pad_finish(struct wlr_tablet_pad *pad) { + wlr_input_device_finish(&pad->base); char **path_ptr; wl_array_for_each(path_ptr, &pad->paths) { @@ -30,10 +38,8 @@ void wlr_tablet_pad_destroy(struct wlr_tablet_pad *pad) { } wl_array_release(&pad->paths); - wlr_input_device_finish(&pad->base); - if (pad->impl && pad->impl->destroy) { - pad->impl->destroy(pad); - } else { - free(pad); + /* TODO: wlr_tablet_pad should own its wlr_tablet_pad_group */ + if (!wl_list_empty(&pad->groups)) { + wlr_log(WLR_ERROR, "wlr_tablet_pad groups is not empty"); } } diff --git a/types/wlr_tablet_tool.c b/types/wlr_tablet_tool.c index e50d29d1a..a25b71a6e 100644 --- a/types/wlr_tablet_tool.c +++ b/types/wlr_tablet_tool.c @@ -1,13 +1,22 @@ +#include #include #include #include #include #include +#include "interfaces/wlr_input_device.h" + +struct wlr_tablet *wlr_tablet_from_input_device( + struct wlr_input_device *input_device) { + assert(input_device->type == WLR_INPUT_DEVICE_TABLET_TOOL); + return wl_container_of(input_device, (struct wlr_tablet *)NULL, base); +} + void wlr_tablet_init(struct wlr_tablet *tablet, const struct wlr_tablet_impl *impl, const char *name) { + memset(tablet, 0, sizeof(*tablet)); wlr_input_device_init(&tablet->base, WLR_INPUT_DEVICE_TABLET_TOOL, name); - tablet->base.tablet = tablet; tablet->impl = impl; wl_signal_init(&tablet->events.axis); @@ -17,21 +26,12 @@ void wlr_tablet_init(struct wlr_tablet *tablet, wl_array_init(&tablet->paths); } -void wlr_tablet_destroy(struct wlr_tablet *tablet) { - if (!tablet) { - return; - } +void wlr_tablet_finish(struct wlr_tablet *tablet) { + wlr_input_device_finish(&tablet->base); char **path_ptr; wl_array_for_each(path_ptr, &tablet->paths) { free(*path_ptr); } wl_array_release(&tablet->paths); - - wlr_input_device_finish(&tablet->base); - if (tablet->impl && tablet->impl->destroy) { - tablet->impl->destroy(tablet); - } else { - free(tablet); - } } diff --git a/types/wlr_text_input_v3.c b/types/wlr_text_input_v3.c index 65a8ebd6f..ca06329e6 100644 --- a/types/wlr_text_input_v3.c +++ b/types/wlr_text_input_v3.c @@ -8,7 +8,6 @@ #include #include #include "text-input-unstable-v3-protocol.h" -#include "util/signal.h" static void text_input_clear_focused_surface(struct wlr_text_input_v3 *text_input) { wl_list_remove(&text_input->surface_destroy.link); @@ -66,7 +65,7 @@ void wlr_text_input_v3_send_done(struct wlr_text_input_v3 *text_input) { } static void wlr_text_input_destroy(struct wlr_text_input_v3 *text_input) { - wlr_signal_emit_safe(&text_input->events.destroy, text_input); + wl_signal_emit_mutable(&text_input->events.destroy, text_input); text_input_clear_focused_surface(text_input); wl_list_remove(&text_input->seat_destroy.link); // remove from manager::text_inputs @@ -188,12 +187,12 @@ static void text_input_commit(struct wl_client *client, if (!old_enabled && text_input->current_enabled) { text_input->active_features = text_input->current.features; - wlr_signal_emit_safe(&text_input->events.enable, text_input); + wl_signal_emit_mutable(&text_input->events.enable, text_input); } else if (old_enabled && !text_input->current_enabled) { text_input->active_features = 0; - wlr_signal_emit_safe(&text_input->events.disable, text_input); + wl_signal_emit_mutable(&text_input->events.disable, text_input); } else { // including never enabled - wlr_signal_emit_safe(&text_input->events.commit, text_input); + wl_signal_emit_mutable(&text_input->events.commit, text_input); } } @@ -280,7 +279,7 @@ static void text_input_manager_get_text_input(struct wl_client *client, text_input_manager_from_resource(resource); wl_list_insert(&manager->text_inputs, &text_input->link); - wlr_signal_emit_safe(&manager->events.text_input, text_input); + wl_signal_emit_mutable(&manager->events.text_input, text_input); } static const struct zwp_text_input_manager_v3_interface @@ -307,7 +306,7 @@ static void text_input_manager_bind(struct wl_client *wl_client, void *data, static void handle_display_destroy(struct wl_listener *listener, void *data) { struct wlr_text_input_manager_v3 *manager = wl_container_of(listener, manager, display_destroy); - wlr_signal_emit_safe(&manager->events.destroy, manager); + wl_signal_emit_mutable(&manager->events.destroy, manager); wl_list_remove(&manager->display_destroy.link); wl_global_destroy(manager->global); free(manager); diff --git a/types/wlr_touch.c b/types/wlr_touch.c index 366191101..d6285180e 100644 --- a/types/wlr_touch.c +++ b/types/wlr_touch.c @@ -1,13 +1,22 @@ +#include #include #include #include #include #include +#include "interfaces/wlr_input_device.h" + +struct wlr_touch *wlr_touch_from_input_device( + struct wlr_input_device *input_device) { + assert(input_device->type == WLR_INPUT_DEVICE_TOUCH); + return wl_container_of(input_device, (struct wlr_touch *)NULL, base); +} + void wlr_touch_init(struct wlr_touch *touch, const struct wlr_touch_impl *impl, const char *name) { + memset(touch, 0, sizeof(*touch)); wlr_input_device_init(&touch->base, WLR_INPUT_DEVICE_TOUCH, name); - touch->base.touch = touch; touch->impl = impl; wl_signal_init(&touch->events.down); @@ -17,11 +26,8 @@ void wlr_touch_init(struct wlr_touch *touch, wl_signal_init(&touch->events.frame); } -void wlr_touch_destroy(struct wlr_touch *touch) { +void wlr_touch_finish(struct wlr_touch *touch) { wlr_input_device_finish(&touch->base); - if (touch && touch->impl && touch->impl->destroy) { - touch->impl->destroy(touch); - } else { - free(touch); - } + + free(touch->output_name); } diff --git a/types/wlr_viewporter.c b/types/wlr_viewporter.c index 097af8576..504390e7e 100644 --- a/types/wlr_viewporter.c +++ b/types/wlr_viewporter.c @@ -3,7 +3,6 @@ #include #include #include -#include "util/signal.h" #include "viewporter-protocol.h" #define VIEWPORTER_VERSION 1 @@ -211,7 +210,7 @@ static void viewporter_bind(struct wl_client *client, void *data, static void handle_display_destroy(struct wl_listener *listener, void *data) { struct wlr_viewporter *viewporter = wl_container_of(listener, viewporter, display_destroy); - wlr_signal_emit_safe(&viewporter->events.destroy, NULL); + wl_signal_emit_mutable(&viewporter->events.destroy, NULL); wl_global_destroy(viewporter->global); free(viewporter); } diff --git a/types/wlr_virtual_keyboard_v1.c b/types/wlr_virtual_keyboard_v1.c index 07eeb3678..9b90ec9fb 100644 --- a/types/wlr_virtual_keyboard_v1.c +++ b/types/wlr_virtual_keyboard_v1.c @@ -8,44 +8,10 @@ #include #include #include -#include "util/signal.h" -#include "util/time.h" #include "virtual-keyboard-unstable-v1-protocol.h" -/** - * Send release event for each pressed key to bring the keyboard back to - * neutral state. - * - * This may be needed for virtual keyboards. For physical devices, kernel - * or libinput will deal with the removal of devices. - */ -static void keyboard_release_pressed_keys(struct wlr_keyboard *keyboard) { - size_t orig_num_keycodes = keyboard->num_keycodes; - for (size_t i = 0; i < orig_num_keycodes; ++i) { - assert(keyboard->num_keycodes == orig_num_keycodes - i); - struct wlr_event_keyboard_key event = { - .time_msec = get_current_time_msec(), - .keycode = keyboard->keycodes[orig_num_keycodes - i - 1], - .update_state = false, - .state = WL_KEYBOARD_KEY_STATE_RELEASED, - }; - wlr_keyboard_notify_key(keyboard, &event); // updates num_keycodes - } -} - -static void keyboard_destroy(struct wlr_keyboard *wlr_kb) { - struct wlr_virtual_keyboard_v1 *keyboard = - (struct wlr_virtual_keyboard_v1 *)wlr_kb; - - keyboard_release_pressed_keys(&keyboard->keyboard); - wl_resource_set_user_data(keyboard->resource, NULL); - wlr_signal_emit_safe(&keyboard->events.destroy, keyboard); - wl_list_remove(&keyboard->link); - free(keyboard); -} - static const struct wlr_keyboard_impl keyboard_impl = { - .destroy = keyboard_destroy, + .name = "virtual-keyboard", }; static const struct zwp_virtual_keyboard_v1_interface virtual_keyboard_impl; @@ -59,11 +25,15 @@ static struct wlr_virtual_keyboard_v1 *virtual_keyboard_from_resource( struct wlr_virtual_keyboard_v1 *wlr_input_device_get_virtual_keyboard( struct wlr_input_device *wlr_dev) { - if (wlr_dev->type != WLR_INPUT_DEVICE_KEYBOARD - || wlr_dev->keyboard->impl != &keyboard_impl) { + if (wlr_dev->type != WLR_INPUT_DEVICE_KEYBOARD) { return NULL; } - return (struct wlr_virtual_keyboard_v1 *)wlr_dev->keyboard; + struct wlr_keyboard *wlr_keyboard = wlr_keyboard_from_input_device(wlr_dev); + if (wlr_keyboard->impl != &keyboard_impl) { + return NULL; + } + return wl_container_of(wlr_keyboard, + (struct wlr_virtual_keyboard_v1 *)NULL, keyboard); } static void virtual_keyboard_keymap(struct wl_client *client, @@ -111,7 +81,7 @@ static void virtual_keyboard_key(struct wl_client *client, "Cannot send a keypress before defining a keymap"); return; } - struct wlr_event_keyboard_key event = { + struct wlr_keyboard_key_event event = { .time_msec = time, .keycode = key, .update_state = false, @@ -138,9 +108,15 @@ static void virtual_keyboard_modifiers(struct wl_client *client, static void virtual_keyboard_destroy_resource(struct wl_resource *resource) { struct wlr_virtual_keyboard_v1 *keyboard = virtual_keyboard_from_resource(resource); - if (keyboard != NULL) { - wlr_keyboard_destroy(&keyboard->keyboard); + if (keyboard == NULL) { + return; } + + wlr_keyboard_finish(&keyboard->keyboard); + + wl_resource_set_user_data(keyboard->resource, NULL); + wl_list_remove(&keyboard->link); + free(keyboard); } static void virtual_keyboard_destroy(struct wl_client *client, @@ -178,7 +154,7 @@ static void virtual_keyboard_manager_create_virtual_keyboard( } wlr_keyboard_init(&virtual_keyboard->keyboard, &keyboard_impl, - "virtual-keyboard"); + "wlr_virtual_keyboard_v1"); struct wl_resource *keyboard_resource = wl_resource_create(client, &zwp_virtual_keyboard_v1_interface, wl_resource_get_version(resource), @@ -196,11 +172,10 @@ static void virtual_keyboard_manager_create_virtual_keyboard( virtual_keyboard->resource = keyboard_resource; virtual_keyboard->seat = seat_client->seat; - wl_signal_init(&virtual_keyboard->events.destroy); wl_list_insert(&manager->virtual_keyboards, &virtual_keyboard->link); - wlr_signal_emit_safe(&manager->events.new_virtual_keyboard, + wl_signal_emit_mutable(&manager->events.new_virtual_keyboard, virtual_keyboard); } @@ -225,7 +200,7 @@ static void virtual_keyboard_manager_bind(struct wl_client *client, void *data, static void handle_display_destroy(struct wl_listener *listener, void *data) { struct wlr_virtual_keyboard_manager_v1 *manager = wl_container_of(listener, manager, display_destroy); - wlr_signal_emit_safe(&manager->events.destroy, manager); + wl_signal_emit_mutable(&manager->events.destroy, manager); wl_list_remove(&manager->display_destroy.link); wl_global_destroy(manager->global); free(manager); diff --git a/types/wlr_virtual_pointer_v1.c b/types/wlr_virtual_pointer_v1.c index 6215bbfff..f4dd60c17 100644 --- a/types/wlr_virtual_pointer_v1.c +++ b/types/wlr_virtual_pointer_v1.c @@ -5,21 +5,10 @@ #include #include #include -#include "util/signal.h" #include "wlr-virtual-pointer-unstable-v1-protocol.h" -static void pointer_destroy(struct wlr_pointer *pointer) { - struct wlr_virtual_pointer_v1 *virtual_pointer = - (struct wlr_virtual_pointer_v1 *)pointer; - - wl_resource_set_user_data(virtual_pointer->resource, NULL); - wlr_signal_emit_safe(&virtual_pointer->events.destroy, virtual_pointer); - wl_list_remove(&virtual_pointer->link); - free(virtual_pointer); -} - static const struct wlr_pointer_impl pointer_impl = { - .destroy = pointer_destroy, + .name = "virtual-pointer", }; static const struct zwlr_virtual_pointer_v1_interface virtual_pointer_impl; @@ -39,16 +28,15 @@ static void virtual_pointer_motion(struct wl_client *client, if (pointer == NULL) { return; } - struct wlr_input_device *wlr_dev = &pointer->pointer.base; - struct wlr_event_pointer_motion event = { - .device = wlr_dev, + struct wlr_pointer_motion_event event = { + .pointer = &pointer->pointer, .time_msec = time, .delta_x = wl_fixed_to_double(dx), .delta_y = wl_fixed_to_double(dy), .unaccel_dx = wl_fixed_to_double(dx), .unaccel_dy = wl_fixed_to_double(dy), }; - wlr_signal_emit_safe(&pointer->pointer.events.motion, &event); + wl_signal_emit_mutable(&pointer->pointer.events.motion, &event); } static void virtual_pointer_motion_absolute(struct wl_client *client, @@ -62,14 +50,13 @@ static void virtual_pointer_motion_absolute(struct wl_client *client, if (x_extent == 0 || y_extent == 0) { return; } - struct wlr_input_device *wlr_dev = &pointer->pointer.base; - struct wlr_event_pointer_motion_absolute event = { - .device = wlr_dev, + struct wlr_pointer_motion_absolute_event event = { + .pointer = &pointer->pointer, .time_msec = time, .x = (double)x / x_extent, .y = (double)y / y_extent, }; - wlr_signal_emit_safe(&wlr_dev->pointer->events.motion_absolute, &event); + wl_signal_emit_mutable(&pointer->pointer.events.motion_absolute, &event); } static void virtual_pointer_button(struct wl_client *client, @@ -80,14 +67,13 @@ static void virtual_pointer_button(struct wl_client *client, if (pointer == NULL) { return; } - struct wlr_input_device *wlr_dev = &pointer->pointer.base; - struct wlr_event_pointer_button event = { - .device = wlr_dev, + struct wlr_pointer_button_event event = { + .pointer = &pointer->pointer, .time_msec = time, .button = button, .state = state ? WLR_BUTTON_PRESSED : WLR_BUTTON_RELEASED }; - wlr_signal_emit_safe(&wlr_dev->pointer->events.button, &event); + wl_signal_emit_mutable(&pointer->pointer.events.button, &event); } static void virtual_pointer_axis(struct wl_client *client, @@ -104,10 +90,9 @@ static void virtual_pointer_axis(struct wl_client *client, if (pointer == NULL) { return; } - struct wlr_input_device *wlr_dev = &pointer->pointer.base; pointer->axis = axis; pointer->axis_valid[pointer->axis] = true; - pointer->axis_event[pointer->axis].device = wlr_dev; + pointer->axis_event[pointer->axis].pointer = &pointer->pointer; pointer->axis_event[pointer->axis].time_msec = time; pointer->axis_event[pointer->axis].orientation = axis; pointer->axis_event[pointer->axis].delta = wl_fixed_to_double(value); @@ -120,21 +105,20 @@ static void virtual_pointer_frame(struct wl_client *client, if (pointer == NULL) { return; } - struct wlr_input_device *wlr_dev = &pointer->pointer.base; for (size_t i = 0; i < sizeof(pointer->axis_valid) / sizeof(pointer->axis_valid[0]); ++i) { if (pointer->axis_valid[i]) { /* Deliver pending axis event */ - wlr_signal_emit_safe(&wlr_dev->pointer->events.axis, + wl_signal_emit_mutable(&pointer->pointer.events.axis, &pointer->axis_event[i]); memset(&pointer->axis_event[i], 0, sizeof(pointer->axis_event[i])); pointer->axis_valid[i] = false; } } - wlr_signal_emit_safe(&wlr_dev->pointer->events.frame, wlr_dev->pointer); + wl_signal_emit_mutable(&pointer->pointer.events.frame, &pointer->pointer); } static void virtual_pointer_axis_source(struct wl_client *client, @@ -150,8 +134,7 @@ static void virtual_pointer_axis_source(struct wl_client *client, if (pointer == NULL) { return; } - struct wlr_input_device *wlr_dev = &pointer->pointer.base; - pointer->axis_event[pointer->axis].device = wlr_dev; + pointer->axis_event[pointer->axis].pointer = &pointer->pointer; pointer->axis_event[pointer->axis].source = source; } @@ -168,10 +151,9 @@ static void virtual_pointer_axis_stop(struct wl_client *client, if (pointer == NULL) { return; } - struct wlr_input_device *wlr_dev = &pointer->pointer.base; pointer->axis = axis; pointer->axis_valid[pointer->axis] = true; - pointer->axis_event[pointer->axis].device = wlr_dev; + pointer->axis_event[pointer->axis].pointer = &pointer->pointer; pointer->axis_event[pointer->axis].time_msec = time; pointer->axis_event[pointer->axis].orientation = axis; pointer->axis_event[pointer->axis].delta = 0; @@ -192,10 +174,9 @@ static void virtual_pointer_axis_discrete(struct wl_client *client, if (pointer == NULL) { return; } - struct wlr_input_device *wlr_dev = &pointer->pointer.base; pointer->axis = axis; pointer->axis_valid[pointer->axis] = true; - pointer->axis_event[pointer->axis].device = wlr_dev; + pointer->axis_event[pointer->axis].pointer = &pointer->pointer; pointer->axis_event[pointer->axis].time_msec = time; pointer->axis_event[pointer->axis].orientation = axis; pointer->axis_event[pointer->axis].delta = wl_fixed_to_double(value); @@ -205,9 +186,15 @@ static void virtual_pointer_axis_discrete(struct wl_client *client, static void virtual_pointer_destroy_resource(struct wl_resource *resource) { struct wlr_virtual_pointer_v1 *pointer = virtual_pointer_from_resource(resource); - if (pointer != NULL) { - wlr_pointer_destroy(&pointer->pointer); + if (pointer == NULL) { + return; } + + wlr_pointer_finish(&pointer->pointer); + + wl_resource_set_user_data(pointer->resource, NULL); + wl_list_remove(&pointer->link); + free(pointer); } static void virtual_pointer_destroy(struct wl_client *client, @@ -250,7 +237,7 @@ static void virtual_pointer_manager_create_virtual_pointer_with_output( } wlr_pointer_init(&virtual_pointer->pointer, &pointer_impl, - "virtual-pointer"); + "wlr_virtual_pointer_v1"); struct wl_resource *pointer_resource = wl_resource_create(client, &zwlr_virtual_pointer_v1_interface, wl_resource_get_version(resource), @@ -280,10 +267,9 @@ static void virtual_pointer_manager_create_virtual_pointer_with_output( } virtual_pointer->resource = pointer_resource; - wl_signal_init(&virtual_pointer->events.destroy); wl_list_insert(&manager->virtual_pointers, &virtual_pointer->link); - wlr_signal_emit_safe(&manager->events.new_virtual_pointer, &event); + wl_signal_emit_mutable(&manager->events.new_virtual_pointer, &event); } static void virtual_pointer_manager_create_virtual_pointer( @@ -321,7 +307,7 @@ static void virtual_pointer_manager_bind(struct wl_client *client, void *data, static void handle_display_destroy(struct wl_listener *listener, void *data) { struct wlr_virtual_pointer_manager_v1 *manager = wl_container_of(listener, manager, display_destroy); - wlr_signal_emit_safe(&manager->events.destroy, manager); + wl_signal_emit_mutable(&manager->events.destroy, manager); wl_list_remove(&manager->display_destroy.link); wl_global_destroy(manager->global); struct wlr_virtual_pointer_v1 *pointer, *pointer_tmp; diff --git a/types/wlr_xdg_activation_v1.c b/types/wlr_xdg_activation_v1.c index 02ba9e07f..eb8b930c7 100644 --- a/types/wlr_xdg_activation_v1.c +++ b/types/wlr_xdg_activation_v1.c @@ -6,7 +6,6 @@ #include #include #include -#include "util/signal.h" #include "util/token.h" #include "xdg-activation-v1-protocol.h" @@ -33,7 +32,7 @@ void wlr_xdg_activation_token_v1_destroy( wl_event_source_remove(token->timeout); } - wlr_signal_emit_safe(&token->events.destroy, NULL); + wl_signal_emit_mutable(&token->events.destroy, NULL); wl_list_remove(&token->link); wl_list_remove(&token->seat_destroy.link); @@ -248,15 +247,11 @@ static void activation_handle_destroy(struct wl_client *client, wl_resource_destroy(activation_resource); } -static void activation_handle_get_activation_token(struct wl_client *client, - struct wl_resource *activation_resource, uint32_t id) { - struct wlr_xdg_activation_v1 *activation = - activation_from_resource(activation_resource); - +static struct wlr_xdg_activation_token_v1 *activation_token_create( + struct wlr_xdg_activation_v1 *activation) { struct wlr_xdg_activation_token_v1 *token = calloc(1, sizeof(*token)); if (token == NULL) { - wl_client_post_no_memory(client); - return; + return NULL; } wl_list_init(&token->link); wl_list_init(&token->seat_destroy.link); @@ -265,6 +260,20 @@ static void activation_handle_get_activation_token(struct wl_client *client, token->activation = activation; + return token; +} + +static void activation_handle_get_activation_token(struct wl_client *client, + struct wl_resource *activation_resource, uint32_t id) { + struct wlr_xdg_activation_v1 *activation = + activation_from_resource(activation_resource); + + struct wlr_xdg_activation_token_v1 *token = activation_token_create(activation); + if (token == NULL) { + wl_client_post_no_memory(client); + return; + } + uint32_t version = wl_resource_get_version(activation_resource); token->resource = wl_resource_create(client, &xdg_activation_token_v1_interface, version, id); @@ -302,7 +311,7 @@ static void activation_handle_activate(struct wl_client *client, .token = token, .surface = surface, }; - wlr_signal_emit_safe(&activation->events.request_activate, &event); + wl_signal_emit_mutable(&activation->events.request_activate, &event); wlr_xdg_activation_token_v1_destroy(token); } @@ -329,7 +338,7 @@ static void activation_bind(struct wl_client *client, void *data, static void handle_display_destroy(struct wl_listener *listener, void *data) { struct wlr_xdg_activation_v1 *activation = wl_container_of(listener, activation, display_destroy); - wlr_signal_emit_safe(&activation->events.destroy, NULL); + wl_signal_emit_mutable(&activation->events.destroy, NULL); struct wlr_xdg_activation_token_v1 *token, *token_tmp; wl_list_for_each_safe(token, token_tmp, &activation->tokens, link) { @@ -371,19 +380,12 @@ struct wlr_xdg_activation_v1 *wlr_xdg_activation_v1_create( struct wlr_xdg_activation_token_v1 *wlr_xdg_activation_token_v1_create( struct wlr_xdg_activation_v1 *activation) { - struct wlr_xdg_activation_token_v1 *token = calloc(1, sizeof(*token)); + struct wlr_xdg_activation_token_v1 *token = activation_token_create(activation); + if (token == NULL) { return NULL; } - wl_list_init(&token->link); - // Currently no way to set seat/surface - wl_list_init(&token->seat_destroy.link); - wl_list_init(&token->surface_destroy.link); - wl_signal_init(&token->events.destroy); - - token->activation = activation; - if (!token_init(token)) { wlr_xdg_activation_token_v1_destroy(token); return NULL; @@ -412,15 +414,10 @@ struct wlr_xdg_activation_token_v1 *wlr_xdg_activation_v1_add_token( struct wlr_xdg_activation_v1 *activation, const char *token_str) { assert(token_str); - struct wlr_xdg_activation_token_v1 *token = calloc(1, sizeof(*token)); + struct wlr_xdg_activation_token_v1 *token = activation_token_create(activation); if (token == NULL) { return NULL; } - wl_list_init(&token->link); - wl_list_init(&token->seat_destroy.link); - wl_list_init(&token->surface_destroy.link); - - token->activation = activation; token->token = strdup(token_str); wl_list_insert(&activation->tokens, &token->link); diff --git a/types/wlr_xdg_decoration_v1.c b/types/wlr_xdg_decoration_v1.c index d0f969f45..fcd97a5cc 100644 --- a/types/wlr_xdg_decoration_v1.c +++ b/types/wlr_xdg_decoration_v1.c @@ -3,7 +3,6 @@ #include #include #include -#include "util/signal.h" #include "xdg-decoration-unstable-v1-protocol.h" #define DECORATION_MANAGER_VERSION 1 @@ -31,7 +30,7 @@ static void toplevel_decoration_handle_set_mode(struct wl_client *client, decoration->requested_mode = (enum wlr_xdg_toplevel_decoration_v1_mode)mode; - wlr_signal_emit_safe(&decoration->events.request_mode, decoration); + wl_signal_emit_mutable(&decoration->events.request_mode, decoration); } static void toplevel_decoration_handle_unset_mode(struct wl_client *client, @@ -40,7 +39,7 @@ static void toplevel_decoration_handle_unset_mode(struct wl_client *client, toplevel_decoration_from_resource(resource); decoration->requested_mode = WLR_XDG_TOPLEVEL_DECORATION_V1_MODE_NONE; - wlr_signal_emit_safe(&decoration->events.request_mode, decoration); + wl_signal_emit_mutable(&decoration->events.request_mode, decoration); } static const struct zxdg_toplevel_decoration_v1_interface @@ -62,7 +61,7 @@ static void toplevel_decoration_handle_resource_destroy( struct wl_resource *resource) { struct wlr_xdg_toplevel_decoration_v1 *decoration = toplevel_decoration_from_resource(resource); - wlr_signal_emit_safe(&decoration->events.destroy, decoration); + wl_signal_emit_mutable(&decoration->events.destroy, decoration); wl_list_remove(&decoration->surface_commit.link); wl_list_remove(&decoration->surface_destroy.link); wl_list_remove(&decoration->surface_configure.link); @@ -148,7 +147,7 @@ static void toplevel_decoration_handle_surface_commit( if (decoration->surface->added && !decoration->added) { decoration->added = true; - wlr_signal_emit_safe(&manager->events.new_toplevel_decoration, + wl_signal_emit_mutable(&manager->events.new_toplevel_decoration, decoration); } } @@ -232,7 +231,7 @@ static void decoration_manager_handle_get_toplevel_decoration( if (toplevel->base->added) { decoration->added = true; - wlr_signal_emit_safe(&manager->events.new_toplevel_decoration, + wl_signal_emit_mutable(&manager->events.new_toplevel_decoration, decoration); } } @@ -260,7 +259,7 @@ static void decoration_manager_bind(struct wl_client *client, void *data, static void handle_display_destroy(struct wl_listener *listener, void *data) { struct wlr_xdg_decoration_manager_v1 *manager = wl_container_of(listener, manager, display_destroy); - wlr_signal_emit_safe(&manager->events.destroy, manager); + wl_signal_emit_mutable(&manager->events.destroy, manager); wl_list_remove(&manager->display_destroy.link); wl_global_destroy(manager->global); free(manager); diff --git a/types/wlr_xdg_foreign_registry.c b/types/wlr_xdg_foreign_registry.c index 0b75e5932..c27d84069 100644 --- a/types/wlr_xdg_foreign_registry.c +++ b/types/wlr_xdg_foreign_registry.c @@ -1,5 +1,4 @@ #include -#include "util/signal.h" #include "util/token.h" #include #include @@ -38,7 +37,7 @@ struct wlr_xdg_foreign_exported *wlr_xdg_foreign_registry_find_by_handle( } void wlr_xdg_foreign_exported_finish(struct wlr_xdg_foreign_exported *surface) { - wlr_signal_emit_safe(&surface->events.destroy, NULL); + wl_signal_emit_mutable(&surface->events.destroy, NULL); surface->registry = NULL; wl_list_remove(&surface->link); wl_list_init(&surface->link); @@ -49,7 +48,7 @@ static void foreign_registry_handle_display_destroy(struct wl_listener *listener struct wlr_xdg_foreign_registry *registry = wl_container_of(listener, registry, display_destroy); - wlr_signal_emit_safe(®istry->events.destroy, NULL); + wl_signal_emit_mutable(®istry->events.destroy, NULL); // Implementations are supposed to remove all surfaces assert(wl_list_empty(®istry->exported_surfaces)); diff --git a/types/wlr_xdg_foreign_v1.c b/types/wlr_xdg_foreign_v1.c index c07959aaf..c9391662c 100644 --- a/types/wlr_xdg_foreign_v1.c +++ b/types/wlr_xdg_foreign_v1.c @@ -6,7 +6,6 @@ #include #include #include -#include "util/signal.h" #include "xdg-foreign-unstable-v1-protocol.h" #define FOREIGN_V1_VERSION 1 @@ -82,6 +81,17 @@ static void xdg_imported_handle_set_parent_of(struct wl_client *client, if (!verify_is_toplevel(resource, wlr_surface_child)) { return; } + + struct wlr_xdg_surface *surface = + wlr_xdg_surface_from_wlr_surface(wlr_surface); + struct wlr_xdg_surface *surface_child = + wlr_xdg_surface_from_wlr_surface(wlr_surface_child); + + if (!surface->mapped) { + wlr_xdg_toplevel_set_parent(surface_child->toplevel, NULL); + return; + } + struct wlr_xdg_imported_child_v1 *child; wl_list_for_each(child, &imported->children, link) { if (child->surface == wlr_surface_child) { @@ -98,11 +108,6 @@ static void xdg_imported_handle_set_parent_of(struct wl_client *client, child->xdg_surface_unmap.notify = handle_child_xdg_surface_unmap; child->xdg_toplevel_set_parent.notify = handle_xdg_toplevel_set_parent; - struct wlr_xdg_surface *surface = - wlr_xdg_surface_from_wlr_surface(wlr_surface); - struct wlr_xdg_surface *surface_child = - wlr_xdg_surface_from_wlr_surface(wlr_surface_child); - wlr_xdg_toplevel_set_parent(surface_child->toplevel, surface->toplevel); wl_signal_add(&surface_child->events.unmap, &child->xdg_surface_unmap); @@ -151,10 +156,7 @@ static void destroy_imported(struct wlr_xdg_imported_v1 *imported) { wl_list_for_each_safe(child, child_tmp, &imported->children, link) { struct wlr_xdg_surface *xdg_child = wlr_xdg_surface_from_wlr_surface(child->surface); - - if (xdg_child != NULL) { - wlr_xdg_toplevel_set_parent(xdg_child->toplevel, NULL); - } + wlr_xdg_toplevel_set_parent(xdg_child->toplevel, NULL); } wl_list_remove(&imported->exported_destroyed.link); @@ -169,7 +171,7 @@ static void destroy_imported(struct wlr_xdg_imported_v1 *imported) { static void destroy_exported(struct wlr_xdg_exported_v1 *exported) { wlr_xdg_foreign_exported_finish(&exported->base); - wl_list_remove(&exported->xdg_surface_destroy.link); + wl_list_remove(&exported->xdg_surface_unmap.link); wl_list_remove(&exported->link); wl_resource_set_user_data(exported->resource, NULL); free(exported); @@ -185,10 +187,10 @@ static void xdg_exported_handle_resource_destroy( } } -static void handle_xdg_surface_destroy( +static void handle_xdg_surface_unmap( struct wl_listener *listener, void *data) { struct wlr_xdg_exported_v1 *exported = - wl_container_of(listener, exported, xdg_surface_destroy); + wl_container_of(listener, exported, xdg_surface_unmap); destroy_exported(exported); } @@ -235,10 +237,10 @@ static void xdg_exporter_handle_export(struct wl_client *wl_client, zxdg_exported_v1_send_handle(exported->resource, exported->base.handle); - exported->xdg_surface_destroy.notify = handle_xdg_surface_destroy; + exported->xdg_surface_unmap.notify = handle_xdg_surface_unmap; struct wlr_xdg_surface *xdg_surface = wlr_xdg_surface_from_wlr_surface(surface); - wl_signal_add(&xdg_surface->events.unmap, &exported->xdg_surface_destroy); + wl_signal_add(&xdg_surface->events.unmap, &exported->xdg_surface_unmap); } static const struct zxdg_exporter_v1_interface xdg_exporter_impl = { @@ -358,7 +360,7 @@ static void xdg_foreign_destroy(struct wlr_xdg_foreign_v1 *foreign) { return; } - wlr_signal_emit_safe(&foreign->events.destroy, NULL); + wl_signal_emit_mutable(&foreign->events.destroy, NULL); wl_list_remove(&foreign->foreign_registry_destroy.link); wl_list_remove(&foreign->display_destroy.link); diff --git a/types/wlr_xdg_foreign_v2.c b/types/wlr_xdg_foreign_v2.c index abd997352..8d2567238 100644 --- a/types/wlr_xdg_foreign_v2.c +++ b/types/wlr_xdg_foreign_v2.c @@ -6,7 +6,6 @@ #include #include #include -#include "util/signal.h" #include "xdg-foreign-unstable-v2-protocol.h" #define FOREIGN_V2_VERSION 1 @@ -88,6 +87,17 @@ static void xdg_imported_handle_set_parent_of(struct wl_client *client, if (!verify_is_toplevel(resource, wlr_surface_child)) { return; } + + struct wlr_xdg_surface *surface = + wlr_xdg_surface_from_wlr_surface(wlr_surface); + struct wlr_xdg_surface *surface_child = + wlr_xdg_surface_from_wlr_surface(wlr_surface_child); + + if (!surface->mapped) { + wlr_xdg_toplevel_set_parent(surface_child->toplevel, NULL); + return; + } + struct wlr_xdg_imported_child_v2 *child; wl_list_for_each(child, &imported->children, link) { if (child->surface == wlr_surface_child) { @@ -104,11 +114,6 @@ static void xdg_imported_handle_set_parent_of(struct wl_client *client, child->xdg_surface_unmap.notify = handle_child_xdg_surface_unmap; child->xdg_toplevel_set_parent.notify = handle_xdg_toplevel_set_parent; - struct wlr_xdg_surface *surface = - wlr_xdg_surface_from_wlr_surface(wlr_surface); - struct wlr_xdg_surface *surface_child = - wlr_xdg_surface_from_wlr_surface(wlr_surface_child); - wlr_xdg_toplevel_set_parent(surface_child->toplevel, surface->toplevel); wl_signal_add(&surface_child->events.unmap, &child->xdg_surface_unmap); @@ -157,10 +162,7 @@ static void destroy_imported(struct wlr_xdg_imported_v2 *imported) { wl_list_for_each_safe(child, child_tmp, &imported->children, link) { struct wlr_xdg_surface *xdg_child = wlr_xdg_surface_from_wlr_surface(child->surface); - - if (xdg_child != NULL) { - wlr_xdg_toplevel_set_parent(xdg_child->toplevel, NULL); - } + wlr_xdg_toplevel_set_parent(xdg_child->toplevel, NULL); } wl_list_remove(&imported->exported_destroyed.link); @@ -175,7 +177,7 @@ static void destroy_imported(struct wlr_xdg_imported_v2 *imported) { static void destroy_exported(struct wlr_xdg_exported_v2 *exported) { wlr_xdg_foreign_exported_finish(&exported->base); - wl_list_remove(&exported->xdg_surface_destroy.link); + wl_list_remove(&exported->xdg_surface_unmap.link); wl_list_remove(&exported->link); wl_resource_set_user_data(exported->resource, NULL); free(exported); @@ -191,10 +193,10 @@ static void xdg_exported_handle_resource_destroy( } } -static void handle_xdg_surface_destroy( +static void handle_xdg_surface_unmap( struct wl_listener *listener, void *data) { struct wlr_xdg_exported_v2 *exported = - wl_container_of(listener, exported, xdg_surface_destroy); + wl_container_of(listener, exported, xdg_surface_unmap); destroy_exported(exported); } @@ -241,10 +243,10 @@ static void xdg_exporter_handle_export(struct wl_client *wl_client, zxdg_exported_v2_send_handle(exported->resource, exported->base.handle); - exported->xdg_surface_destroy.notify = handle_xdg_surface_destroy; + exported->xdg_surface_unmap.notify = handle_xdg_surface_unmap; struct wlr_xdg_surface *xdg_surface = wlr_xdg_surface_from_wlr_surface(surface); - wl_signal_add(&xdg_surface->events.unmap, &exported->xdg_surface_destroy); + wl_signal_add(&xdg_surface->events.unmap, &exported->xdg_surface_unmap); } static const struct zxdg_exporter_v2_interface xdg_exporter_impl = { @@ -364,7 +366,7 @@ static void xdg_foreign_destroy(struct wlr_xdg_foreign_v2 *foreign) { return; } - wlr_signal_emit_safe(&foreign->events.destroy, NULL); + wl_signal_emit_mutable(&foreign->events.destroy, NULL); wl_list_remove(&foreign->foreign_registry_destroy.link); wl_list_remove(&foreign->display_destroy.link); diff --git a/types/wlr_xdg_output_v1.c b/types/wlr_xdg_output_v1.c index 8d5fee485..d030748d2 100644 --- a/types/wlr_xdg_output_v1.c +++ b/types/wlr_xdg_output_v1.c @@ -6,7 +6,6 @@ #include #include #include "xdg-output-unstable-v1-protocol.h" -#include "util/signal.h" #define OUTPUT_MANAGER_VERSION 3 #define OUTPUT_DONE_DEPRECATED_SINCE_VERSION 3 @@ -128,11 +127,11 @@ static void output_manager_handle_get_xdg_output(struct wl_client *client, wl_resource_get_link(xdg_output_resource)); // Name and description should only be sent once per output - uint32_t version = wl_resource_get_version(xdg_output_resource); - if (version >= ZXDG_OUTPUT_V1_NAME_SINCE_VERSION) { + uint32_t xdg_version = wl_resource_get_version(xdg_output_resource); + if (xdg_version >= ZXDG_OUTPUT_V1_NAME_SINCE_VERSION) { zxdg_output_v1_send_name(xdg_output_resource, output->name); } - if (version >= ZXDG_OUTPUT_V1_DESCRIPTION_SINCE_VERSION && + if (xdg_version >= ZXDG_OUTPUT_V1_DESCRIPTION_SINCE_VERSION && output->description != NULL) { zxdg_output_v1_send_description(xdg_output_resource, output->description); @@ -140,7 +139,11 @@ static void output_manager_handle_get_xdg_output(struct wl_client *client, output_send_details(xdg_output, xdg_output_resource); - wl_output_send_done(output_resource); + uint32_t wl_version = wl_resource_get_version(output_resource); + if (wl_version >= WL_OUTPUT_DONE_SINCE_VERSION && + xdg_version >= OUTPUT_DONE_DEPRECATED_SINCE_VERSION) { + wl_output_send_done(output_resource); + } } static const struct zxdg_output_manager_v1_interface @@ -231,7 +234,7 @@ static void manager_destroy(struct wlr_xdg_output_manager_v1 *manager) { wl_list_for_each_safe(output, tmp, &manager->outputs, link) { output_destroy(output); } - wlr_signal_emit_safe(&manager->events.destroy, manager); + wl_signal_emit_mutable(&manager->events.destroy, manager); wl_list_remove(&manager->display_destroy.link); wl_list_remove(&manager->layout_add.link); wl_list_remove(&manager->layout_change.link); diff --git a/types/xdg_shell/wlr_xdg_popup.c b/types/xdg_shell/wlr_xdg_popup.c index 973a339be..d0b83201b 100644 --- a/types/xdg_shell/wlr_xdg_popup.c +++ b/types/xdg_shell/wlr_xdg_popup.c @@ -2,7 +2,41 @@ #include #include #include "types/wlr_xdg_shell.h" -#include "util/signal.h" + +void handle_xdg_popup_ack_configure( + struct wlr_xdg_popup *popup, + struct wlr_xdg_popup_configure *configure) { + popup->pending.geometry = configure->geometry; + popup->pending.reactive = configure->rules.reactive; +} + +struct wlr_xdg_popup_configure *send_xdg_popup_configure( + struct wlr_xdg_popup *popup) { + struct wlr_xdg_popup_configure *configure = + calloc(1, sizeof(*configure)); + if (configure == NULL) { + wl_resource_post_no_memory(popup->resource); + return NULL; + } + *configure = popup->scheduled; + + uint32_t version = wl_resource_get_version(popup->resource); + + if ((configure->fields & WLR_XDG_POPUP_CONFIGURE_REPOSITION_TOKEN) && + version >= XDG_POPUP_REPOSITIONED_SINCE_VERSION) { + xdg_popup_send_repositioned(popup->resource, + configure->reposition_token); + } + + struct wlr_box *geometry = &configure->geometry; + xdg_popup_send_configure(popup->resource, + geometry->x, geometry->y, + geometry->width, geometry->height); + + popup->scheduled.fields = 0; + + return configure; +} static void xdg_popup_grab_end(struct wlr_xdg_popup_grab *popup_grab) { struct wlr_xdg_popup *popup, *tmp; @@ -214,7 +248,10 @@ void handle_xdg_popup_committed(struct wlr_xdg_popup *popup) { if (!popup->committed) { wlr_xdg_surface_schedule_configure(popup->base); popup->committed = true; + return; } + + popup->current = popup->pending; } static const struct xdg_popup_interface xdg_popup_implementation; @@ -267,6 +304,29 @@ static void xdg_popup_handle_grab(struct wl_client *client, &popup_grab->touch_grab); } +static void xdg_popup_handle_reposition( + struct wl_client *client, struct wl_resource *resource, + struct wl_resource *positioner_resource, uint32_t token) { + struct wlr_xdg_popup *popup = + wlr_xdg_popup_from_resource(resource); + if (!popup) { + return; + } + + struct wlr_xdg_positioner *positioner = + wlr_xdg_positioner_from_resource(positioner_resource); + wlr_xdg_positioner_rules_get_geometry( + &positioner->rules, &popup->scheduled.geometry); + popup->scheduled.rules = positioner->rules; + + popup->scheduled.fields |= WLR_XDG_POPUP_CONFIGURE_REPOSITION_TOKEN; + popup->scheduled.reposition_token = token; + + wlr_xdg_surface_schedule_configure(popup->base); + + wl_signal_emit_mutable(&popup->events.reposition, NULL); +} + static void xdg_popup_handle_destroy(struct wl_client *client, struct wl_resource *resource) { struct wlr_xdg_popup *popup = @@ -285,6 +345,7 @@ static void xdg_popup_handle_destroy(struct wl_client *client, static const struct xdg_popup_interface xdg_popup_implementation = { .destroy = xdg_popup_handle_destroy, .grab = xdg_popup_handle_grab, + .reposition = xdg_popup_handle_reposition, }; static void xdg_popup_handle_resource_destroy(struct wl_resource *resource) { @@ -348,15 +409,16 @@ void create_xdg_popup(struct wlr_xdg_surface *surface, surface->role = WLR_XDG_SURFACE_ROLE_POPUP; - memcpy(&surface->popup->positioner_rules, - &positioner->rules, sizeof(positioner->rules)); wlr_xdg_positioner_rules_get_geometry( - &positioner->rules, &surface->popup->geometry); + &positioner->rules, &surface->popup->scheduled.geometry); + surface->popup->scheduled.rules = positioner->rules; + + wl_signal_init(&surface->popup->events.reposition); if (parent) { surface->popup->parent = parent->surface; wl_list_insert(&parent->popups, &surface->popup->link); - wlr_signal_emit_safe(&parent->events.new_popup, surface->popup); + wl_signal_emit_mutable(&parent->events.new_popup, surface->popup); } else { wl_list_init(&surface->popup->link); } @@ -380,7 +442,7 @@ void unmap_xdg_popup(struct wlr_xdg_popup *popup) { if (grab->seat->touch_state.grab == &grab->touch_grab) { wlr_seat_touch_end_grab(grab->seat); } - + destroy_xdg_popup_grab(grab); } @@ -417,8 +479,8 @@ void wlr_xdg_popup_get_toplevel_coords(struct wlr_xdg_popup *popup, wlr_xdg_surface_from_wlr_surface(parent); if (xdg_surface->role == WLR_XDG_SURFACE_ROLE_POPUP) { - popup_sx += xdg_surface->popup->geometry.x; - popup_sy += xdg_surface->popup->geometry.y; + popup_sx += xdg_surface->popup->current.geometry.x; + popup_sy += xdg_surface->popup->current.geometry.y; parent = xdg_surface->popup->parent; } else { popup_sx += xdg_surface->current.geometry.x; @@ -443,6 +505,7 @@ void wlr_xdg_popup_unconstrain_from_box(struct wlr_xdg_popup *popup, .width = toplevel_space_box->width, .height = toplevel_space_box->height, }; - wlr_xdg_positioner_rules_unconstrain_box(&popup->positioner_rules, - &popup_constraint, &popup->geometry); + wlr_xdg_positioner_rules_unconstrain_box(&popup->scheduled.rules, + &popup_constraint, &popup->scheduled.geometry); + wlr_xdg_surface_schedule_configure(popup->base); } diff --git a/types/xdg_shell/wlr_xdg_positioner.c b/types/xdg_shell/wlr_xdg_positioner.c index 6fa1ed991..6a991bbac 100644 --- a/types/xdg_shell/wlr_xdg_positioner.c +++ b/types/xdg_shell/wlr_xdg_positioner.c @@ -95,6 +95,34 @@ static void xdg_positioner_handle_set_offset(struct wl_client *client, positioner->rules.offset.y = y; } +static void xdg_positioner_handle_set_reactive( + struct wl_client *client, struct wl_resource *resource) { + struct wlr_xdg_positioner *positioner = + wlr_xdg_positioner_from_resource(resource); + + positioner->rules.reactive = true; +} + +static void xdg_positioner_handle_set_parent_configure( + struct wl_client *client, struct wl_resource *resource, + uint32_t serial) { + struct wlr_xdg_positioner *positioner = + wlr_xdg_positioner_from_resource(resource); + + positioner->rules.has_parent_configure_serial = true; + positioner->rules.parent_configure_serial = serial; +} + +static void xdg_positioner_handle_set_parent_size(struct wl_client *client, + struct wl_resource *resource, + int32_t parent_width, int32_t parent_height) { + struct wlr_xdg_positioner *positioner = + wlr_xdg_positioner_from_resource(resource); + + positioner->rules.parent_size.width = parent_width; + positioner->rules.parent_size.height = parent_height; +} + static void xdg_positioner_handle_destroy(struct wl_client *client, struct wl_resource *resource) { wl_resource_destroy(resource); @@ -110,6 +138,9 @@ static const struct xdg_positioner_interface .set_constraint_adjustment = xdg_positioner_handle_set_constraint_adjustment, .set_offset = xdg_positioner_handle_set_offset, + .set_reactive = xdg_positioner_handle_set_reactive, + .set_parent_size = xdg_positioner_handle_set_parent_size, + .set_parent_configure = xdg_positioner_handle_set_parent_configure, }; static void xdg_positioner_handle_resource_destroy( @@ -343,13 +374,10 @@ static bool xdg_positioner_rules_unconstrain_by_slide( struct constraint_offsets *offsets) { uint32_t gravity = xdg_positioner_gravity_to_wlr_edges(rules->gravity); - // We can only slide if there is gravity on this axis bool slide_x = (offsets->left > 0 || offsets->right > 0) && - (rules->constraint_adjustment & XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_X) && - (gravity & (WLR_EDGE_LEFT | WLR_EDGE_RIGHT)); + (rules->constraint_adjustment & XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_X); bool slide_y = (offsets->top > 0 || offsets->bottom > 0) && - (rules->constraint_adjustment & XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_Y) && - (gravity & (WLR_EDGE_TOP | WLR_EDGE_BOTTOM)); + (rules->constraint_adjustment & XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_Y); if (!slide_x && !slide_y) { return false; @@ -363,9 +391,13 @@ static bool xdg_positioner_rules_unconstrain_by_slide( // the box is bigger than the anchor rect and completely includes it. // In this case, the second slide will fail immediately, so simply // slide towards the direction of the gravity. + // Note that the protocol doesn't specify the behavior when there is no + // gravity on the axis (which is what e.g. GTK tooltips use). In this + // case, fall back to sliding the box to the right/bottom, which is what + // GTK X11 popup adjustment code does. if (gravity & WLR_EDGE_LEFT) { box->x -= offsets->right; - } else if (gravity & WLR_EDGE_RIGHT) { + } else { box->x += offsets->left; } } else { @@ -386,7 +418,7 @@ static bool xdg_positioner_rules_unconstrain_by_slide( if (offsets->top > 0 && offsets->bottom > 0) { if (gravity & WLR_EDGE_TOP) { box->y -= offsets->bottom; - } else if (gravity & WLR_EDGE_BOTTOM) { + } else { box->y += offsets->top; } } else { diff --git a/types/xdg_shell/wlr_xdg_shell.c b/types/xdg_shell/wlr_xdg_shell.c index 0b1302622..69c9a6967 100644 --- a/types/xdg_shell/wlr_xdg_shell.c +++ b/types/xdg_shell/wlr_xdg_shell.c @@ -1,9 +1,8 @@ #include #include #include "types/wlr_xdg_shell.h" -#include "util/signal.h" -#define WM_BASE_VERSION 2 +#define WM_BASE_VERSION 5 static const struct xdg_wm_base_interface xdg_shell_impl; @@ -84,7 +83,7 @@ static int xdg_client_ping_timeout(void *user_data) { struct wlr_xdg_surface *surface; wl_list_for_each(surface, &client->surfaces, link) { - wlr_signal_emit_safe(&surface->events.ping_timeout, NULL); + wl_signal_emit_mutable(&surface->events.ping_timeout, NULL); } client->ping_serial = 0; @@ -131,26 +130,30 @@ static void xdg_shell_bind(struct wl_client *wl_client, void *data, static void handle_display_destroy(struct wl_listener *listener, void *data) { struct wlr_xdg_shell *xdg_shell = wl_container_of(listener, xdg_shell, display_destroy); - wlr_signal_emit_safe(&xdg_shell->events.destroy, xdg_shell); + wl_signal_emit_mutable(&xdg_shell->events.destroy, xdg_shell); wl_list_remove(&xdg_shell->display_destroy.link); wl_global_destroy(xdg_shell->global); free(xdg_shell); } -struct wlr_xdg_shell *wlr_xdg_shell_create(struct wl_display *display) { +struct wlr_xdg_shell *wlr_xdg_shell_create(struct wl_display *display, + uint32_t version) { + assert(version <= WM_BASE_VERSION); + struct wlr_xdg_shell *xdg_shell = calloc(1, sizeof(struct wlr_xdg_shell)); if (!xdg_shell) { return NULL; } + xdg_shell->version = version; xdg_shell->ping_timeout = 10000; wl_list_init(&xdg_shell->clients); wl_list_init(&xdg_shell->popup_grabs); struct wl_global *global = wl_global_create(display, - &xdg_wm_base_interface, WM_BASE_VERSION, xdg_shell, xdg_shell_bind); + &xdg_wm_base_interface, version, xdg_shell, xdg_shell_bind); if (!global) { free(xdg_shell); return NULL; diff --git a/types/xdg_shell/wlr_xdg_surface.c b/types/xdg_shell/wlr_xdg_surface.c index 73ed66c92..ae0dfcc14 100644 --- a/types/xdg_shell/wlr_xdg_surface.c +++ b/types/xdg_shell/wlr_xdg_surface.c @@ -4,7 +4,6 @@ #include #include #include "types/wlr_xdg_shell.h" -#include "util/signal.h" bool wlr_surface_is_xdg_surface(struct wlr_surface *surface) { return surface->role == &xdg_toplevel_surface_role || @@ -29,17 +28,19 @@ static void xdg_surface_configure_destroy( void unmap_xdg_surface(struct wlr_xdg_surface *surface) { assert(surface->role != WLR_XDG_SURFACE_ROLE_NONE); + surface->configured = false; + + // TODO: probably need to ungrab before this event + if (surface->mapped) { + surface->mapped = false; + wl_signal_emit_mutable(&surface->events.unmap, NULL); + } struct wlr_xdg_popup *popup, *popup_tmp; wl_list_for_each_safe(popup, popup_tmp, &surface->popups, link) { wlr_xdg_popup_destroy(popup); } - // TODO: probably need to ungrab before this event - if (surface->mapped) { - wlr_signal_emit_safe(&surface->events.unmap, NULL); - } - switch (surface->role) { case WLR_XDG_SURFACE_ROLE_TOPLEVEL: unmap_xdg_toplevel(surface->toplevel); @@ -56,7 +57,6 @@ void unmap_xdg_surface(struct wlr_xdg_surface *surface) { xdg_surface_configure_destroy(configure); } - surface->configured = surface->mapped = false; if (surface->configure_idle) { wl_event_source_remove(surface->configure_idle); surface->configure_idle = NULL; @@ -97,7 +97,7 @@ static void xdg_surface_handle_ack_configure(struct wl_client *client, if (configure->serial == serial) { break; } - wlr_signal_emit_safe(&surface->events.ack_configure, configure); + wl_signal_emit_mutable(&surface->events.ack_configure, configure); xdg_surface_configure_destroy(configure); } @@ -107,16 +107,18 @@ static void xdg_surface_handle_ack_configure(struct wl_client *client, break; case WLR_XDG_SURFACE_ROLE_TOPLEVEL: handle_xdg_toplevel_ack_configure(surface->toplevel, - configure->toplevel_configure); + configure->toplevel_configure); break; case WLR_XDG_SURFACE_ROLE_POPUP: + handle_xdg_popup_ack_configure(surface->popup, + configure->popup_configure); break; } surface->configured = true; surface->pending.configure_serial = serial; - wlr_signal_emit_safe(&surface->events.ack_configure, configure); + wl_signal_emit_mutable(&surface->events.ack_configure, configure); xdg_surface_configure_destroy(configure); } @@ -145,15 +147,12 @@ static void surface_send_configure(void *user_data) { send_xdg_toplevel_configure(surface->toplevel); break; case WLR_XDG_SURFACE_ROLE_POPUP: - xdg_popup_send_configure(surface->popup->resource, - surface->popup->geometry.x, - surface->popup->geometry.y, - surface->popup->geometry.width, - surface->popup->geometry.height); + configure->popup_configure = + send_xdg_popup_configure(surface->popup); break; } - wlr_signal_emit_safe(&surface->events.configure, configure); + wl_signal_emit_mutable(&surface->events.configure, configure); xdg_surface_send_configure(surface->resource, configure->serial); } @@ -306,13 +305,13 @@ void xdg_surface_role_commit(struct wlr_surface *wlr_surface) { if (!surface->added) { surface->added = true; - wlr_signal_emit_safe(&surface->client->shell->events.new_surface, + wl_signal_emit_mutable(&surface->client->shell->events.new_surface, surface); } if (surface->configured && wlr_surface_has_buffer(surface->surface) && !surface->mapped) { surface->mapped = true; - wlr_signal_emit_safe(&surface->events.map, NULL); + wl_signal_emit_mutable(&surface->events.map, NULL); } } @@ -405,7 +404,7 @@ void reset_xdg_surface(struct wlr_xdg_surface *surface) { } if (surface->added) { - wlr_signal_emit_safe(&surface->events.destroy, NULL); + wl_signal_emit_mutable(&surface->events.destroy, NULL); surface->added = false; } @@ -465,9 +464,9 @@ void wlr_xdg_popup_get_position(struct wlr_xdg_popup *popup, wlr_xdg_surface_from_wlr_surface(popup->parent); struct wlr_box parent_geo; wlr_xdg_surface_get_geometry(parent, &parent_geo); - *popup_sx = parent_geo.x + popup->geometry.x - + *popup_sx = parent_geo.x + popup->current.geometry.x - popup->base->current.geometry.x; - *popup_sy = parent_geo.y + popup->geometry.y - + *popup_sy = parent_geo.y + popup->current.geometry.y - popup->base->current.geometry.y; } diff --git a/types/xdg_shell/wlr_xdg_toplevel.c b/types/xdg_shell/wlr_xdg_toplevel.c index ed304cfcd..58acec271 100644 --- a/types/xdg_shell/wlr_xdg_toplevel.c +++ b/types/xdg_shell/wlr_xdg_toplevel.c @@ -5,7 +5,6 @@ #include #include #include "types/wlr_xdg_shell.h" -#include "util/signal.h" void handle_xdg_toplevel_ack_configure( struct wlr_xdg_toplevel *toplevel, @@ -31,43 +30,55 @@ struct wlr_xdg_toplevel_configure *send_xdg_toplevel_configure( } *configure = toplevel->scheduled; - struct wl_array states; - wl_array_init(&states); - if (configure->maximized) { - uint32_t *s = wl_array_add(&states, sizeof(uint32_t)); - if (!s) { - wlr_log(WLR_ERROR, "Could not allocate state for maximized xdg_toplevel"); - goto error_out; + uint32_t version = wl_resource_get_version(toplevel->resource); + + if ((configure->fields & WLR_XDG_TOPLEVEL_CONFIGURE_BOUNDS) && + version >= XDG_TOPLEVEL_CONFIGURE_BOUNDS_SINCE_VERSION) { + xdg_toplevel_send_configure_bounds(toplevel->resource, + configure->bounds.width, configure->bounds.height); + } + + if ((configure->fields & WLR_XDG_TOPLEVEL_CONFIGURE_WM_CAPABILITIES) && + version >= XDG_TOPLEVEL_WM_CAPABILITIES_SINCE_VERSION) { + size_t caps_len = 0; + uint32_t caps[32]; + if (configure->wm_capabilities & WLR_XDG_TOPLEVEL_WM_CAPABILITIES_WINDOW_MENU) { + caps[caps_len++] = XDG_TOPLEVEL_WM_CAPABILITIES_WINDOW_MENU; } - *s = XDG_TOPLEVEL_STATE_MAXIMIZED; + if (configure->wm_capabilities & WLR_XDG_TOPLEVEL_WM_CAPABILITIES_MAXIMIZE) { + caps[caps_len++] = XDG_TOPLEVEL_WM_CAPABILITIES_MAXIMIZE; + } + if (configure->wm_capabilities & WLR_XDG_TOPLEVEL_WM_CAPABILITIES_FULLSCREEN) { + caps[caps_len++] = XDG_TOPLEVEL_WM_CAPABILITIES_FULLSCREEN; + } + if (configure->wm_capabilities & WLR_XDG_TOPLEVEL_WM_CAPABILITIES_MINIMIZE) { + caps[caps_len++] = XDG_TOPLEVEL_WM_CAPABILITIES_MINIMIZE; + } + assert(caps_len <= sizeof(caps) / sizeof(caps[0])); + + struct wl_array caps_array = { + .size = caps_len * sizeof(caps[0]), + .data = caps, + }; + xdg_toplevel_send_wm_capabilities(toplevel->resource, &caps_array); + } + + size_t nstates = 0; + uint32_t states[32]; + if (configure->maximized) { + states[nstates++] = XDG_TOPLEVEL_STATE_MAXIMIZED; } if (configure->fullscreen) { - uint32_t *s = wl_array_add(&states, sizeof(uint32_t)); - if (!s) { - wlr_log(WLR_ERROR, "Could not allocate state for fullscreen xdg_toplevel"); - goto error_out; - } - *s = XDG_TOPLEVEL_STATE_FULLSCREEN; + states[nstates++] = XDG_TOPLEVEL_STATE_FULLSCREEN; } if (configure->resizing) { - uint32_t *s = wl_array_add(&states, sizeof(uint32_t)); - if (!s) { - wlr_log(WLR_ERROR, "Could not allocate state for resizing xdg_toplevel"); - goto error_out; - } - *s = XDG_TOPLEVEL_STATE_RESIZING; + states[nstates++] = XDG_TOPLEVEL_STATE_RESIZING; } if (configure->activated) { - uint32_t *s = wl_array_add(&states, sizeof(uint32_t)); - if (!s) { - wlr_log(WLR_ERROR, "Could not allocate state for activated xdg_toplevel"); - goto error_out; - } - *s = XDG_TOPLEVEL_STATE_ACTIVATED; + states[nstates++] = XDG_TOPLEVEL_STATE_ACTIVATED; } if (configure->tiled) { - if (wl_resource_get_version(toplevel->resource) >= - XDG_TOPLEVEL_STATE_TILED_LEFT_SINCE_VERSION) { + if (version >= XDG_TOPLEVEL_STATE_TILED_LEFT_SINCE_VERSION) { const struct { enum wlr_edges edge; enum xdg_toplevel_state state; @@ -82,40 +93,26 @@ struct wlr_xdg_toplevel_configure *send_xdg_toplevel_configure( if ((configure->tiled & tiled[i].edge) == 0) { continue; } - - uint32_t *s = wl_array_add(&states, sizeof(uint32_t)); - if (!s) { - wlr_log(WLR_ERROR, - "Could not allocate state for tiled xdg_toplevel"); - goto error_out; - } - *s = tiled[i].state; + states[nstates++] = tiled[i].state; } } else if (!configure->maximized) { - // This version doesn't support tiling, best we can do is make the - // toplevel maximized - uint32_t *s = wl_array_add(&states, sizeof(uint32_t)); - if (!s) { - wlr_log(WLR_ERROR, - "Could not allocate state for maximized xdg_toplevel"); - goto error_out; - } - *s = XDG_TOPLEVEL_STATE_MAXIMIZED; + states[nstates++] = XDG_TOPLEVEL_STATE_MAXIMIZED; } } + assert(nstates <= sizeof(states) / sizeof(states[0])); uint32_t width = configure->width; uint32_t height = configure->height; - xdg_toplevel_send_configure(toplevel->resource, width, height, &states); + struct wl_array wl_states = { + .size = nstates * sizeof(states[0]), + .data = states, + }; + xdg_toplevel_send_configure(toplevel->resource, + width, height, &wl_states); + + toplevel->scheduled.fields = 0; - wl_array_release(&states); return configure; - -error_out: - wl_array_release(&states); - free(configure); - wl_resource_post_no_memory(toplevel->resource); - return NULL; } void handle_xdg_toplevel_committed(struct wlr_xdg_toplevel *toplevel) { @@ -124,6 +121,16 @@ void handle_xdg_toplevel_committed(struct wlr_xdg_toplevel *toplevel) { // is added wlr_xdg_surface_schedule_configure(toplevel->base); toplevel->added = true; + + if (toplevel->base->client->shell->version >= + XDG_TOPLEVEL_WM_CAPABILITIES_SINCE_VERSION) { + // The first configure event must carry WM capabilities + wlr_xdg_toplevel_set_wm_capabilities(toplevel, + WLR_XDG_TOPLEVEL_WM_CAPABILITIES_WINDOW_MENU | + WLR_XDG_TOPLEVEL_WM_CAPABILITIES_MAXIMIZE | + WLR_XDG_TOPLEVEL_WM_CAPABILITIES_FULLSCREEN | + WLR_XDG_TOPLEVEL_WM_CAPABILITIES_MINIMIZE); + } return; } @@ -150,15 +157,17 @@ void wlr_xdg_toplevel_set_parent(struct wlr_xdg_toplevel *toplevel, if (toplevel->parent) { wl_list_remove(&toplevel->parent_unmap.link); } - - toplevel->parent = parent; - if (parent) { + + if (parent && parent->base->mapped) { + toplevel->parent = parent; toplevel->parent_unmap.notify = handle_parent_unmap; wl_signal_add(&toplevel->parent->base->events.unmap, - &toplevel->parent_unmap); + &toplevel->parent_unmap); + } else { + toplevel->parent = NULL; } - wlr_signal_emit_safe(&toplevel->events.set_parent, NULL); + wl_signal_emit_mutable(&toplevel->events.set_parent, NULL); } static void xdg_toplevel_handle_set_parent(struct wl_client *client, @@ -182,12 +191,13 @@ static void xdg_toplevel_handle_set_title(struct wl_client *client, tmp = strdup(title); if (tmp == NULL) { + wl_resource_post_no_memory(resource); return; } free(toplevel->title); toplevel->title = tmp; - wlr_signal_emit_safe(&toplevel->events.set_title, NULL); + wl_signal_emit_mutable(&toplevel->events.set_title, NULL); } static void xdg_toplevel_handle_set_app_id(struct wl_client *client, @@ -198,12 +208,13 @@ static void xdg_toplevel_handle_set_app_id(struct wl_client *client, tmp = strdup(app_id); if (tmp == NULL) { + wl_resource_post_no_memory(resource); return; } free(toplevel->app_id); toplevel->app_id = tmp; - wlr_signal_emit_safe(&toplevel->events.set_app_id, NULL); + wl_signal_emit_mutable(&toplevel->events.set_app_id, NULL); } static void xdg_toplevel_handle_show_window_menu(struct wl_client *client, @@ -234,7 +245,7 @@ static void xdg_toplevel_handle_show_window_menu(struct wl_client *client, .y = y, }; - wlr_signal_emit_safe(&toplevel->events.request_show_window_menu, &event); + wl_signal_emit_mutable(&toplevel->events.request_show_window_menu, &event); } static void xdg_toplevel_handle_move(struct wl_client *client, @@ -263,7 +274,7 @@ static void xdg_toplevel_handle_move(struct wl_client *client, .serial = serial, }; - wlr_signal_emit_safe(&toplevel->events.request_move, &event); + wl_signal_emit_mutable(&toplevel->events.request_move, &event); } static void xdg_toplevel_handle_resize(struct wl_client *client, @@ -293,7 +304,7 @@ static void xdg_toplevel_handle_resize(struct wl_client *client, .edges = edges, }; - wlr_signal_emit_safe(&toplevel->events.request_resize, &event); + wl_signal_emit_mutable(&toplevel->events.request_resize, &event); } static void xdg_toplevel_handle_set_max_size(struct wl_client *client, @@ -317,8 +328,7 @@ static void xdg_toplevel_handle_set_maximized(struct wl_client *client, struct wlr_xdg_toplevel *toplevel = wlr_xdg_toplevel_from_resource(resource); toplevel->requested.maximized = true; - wlr_signal_emit_safe(&toplevel->events.request_maximize, NULL); - wlr_xdg_surface_schedule_configure(toplevel->base); + wl_signal_emit_mutable(&toplevel->events.request_maximize, NULL); } static void xdg_toplevel_handle_unset_maximized(struct wl_client *client, @@ -326,8 +336,7 @@ static void xdg_toplevel_handle_unset_maximized(struct wl_client *client, struct wlr_xdg_toplevel *toplevel = wlr_xdg_toplevel_from_resource(resource); toplevel->requested.maximized = false; - wlr_signal_emit_safe(&toplevel->events.request_maximize, NULL); - wlr_xdg_surface_schedule_configure(toplevel->base); + wl_signal_emit_mutable(&toplevel->events.request_maximize, NULL); } static void handle_fullscreen_output_destroy(struct wl_listener *listener, @@ -366,8 +375,7 @@ static void xdg_toplevel_handle_set_fullscreen(struct wl_client *client, store_fullscreen_requested(toplevel, true, output); - wlr_signal_emit_safe(&toplevel->events.request_fullscreen, NULL); - wlr_xdg_surface_schedule_configure(toplevel->base); + wl_signal_emit_mutable(&toplevel->events.request_fullscreen, NULL); } static void xdg_toplevel_handle_unset_fullscreen(struct wl_client *client, @@ -377,8 +385,7 @@ static void xdg_toplevel_handle_unset_fullscreen(struct wl_client *client, store_fullscreen_requested(toplevel, false, NULL); - wlr_signal_emit_safe(&toplevel->events.request_fullscreen, NULL); - wlr_xdg_surface_schedule_configure(toplevel->base); + wl_signal_emit_mutable(&toplevel->events.request_fullscreen, NULL); } static void xdg_toplevel_handle_set_minimized(struct wl_client *client, @@ -386,7 +393,7 @@ static void xdg_toplevel_handle_set_minimized(struct wl_client *client, struct wlr_xdg_toplevel *toplevel = wlr_xdg_toplevel_from_resource(resource); toplevel->requested.minimized = true; - wlr_signal_emit_safe(&toplevel->events.request_minimize, NULL); + wl_signal_emit_mutable(&toplevel->events.request_minimize, NULL); } static void xdg_toplevel_handle_destroy(struct wl_client *client, @@ -535,6 +542,28 @@ uint32_t wlr_xdg_toplevel_set_resizing(struct wlr_xdg_toplevel *toplevel, uint32_t wlr_xdg_toplevel_set_tiled(struct wlr_xdg_toplevel *toplevel, uint32_t tiled) { + assert(toplevel->base->client->shell->version >= + XDG_TOPLEVEL_STATE_TILED_LEFT_SINCE_VERSION); toplevel->scheduled.tiled = tiled; return wlr_xdg_surface_schedule_configure(toplevel->base); } + +uint32_t wlr_xdg_toplevel_set_bounds(struct wlr_xdg_toplevel *toplevel, + int32_t width, int32_t height) { + assert(toplevel->base->client->shell->version >= + XDG_TOPLEVEL_CONFIGURE_BOUNDS_SINCE_VERSION); + assert(width >= 0 && height >= 0); + toplevel->scheduled.fields |= WLR_XDG_TOPLEVEL_CONFIGURE_BOUNDS; + toplevel->scheduled.bounds.width = width; + toplevel->scheduled.bounds.height = height; + return wlr_xdg_surface_schedule_configure(toplevel->base); +} + +uint32_t wlr_xdg_toplevel_set_wm_capabilities(struct wlr_xdg_toplevel *toplevel, + uint32_t caps) { + assert(toplevel->base->client->shell->version >= + XDG_TOPLEVEL_WM_CAPABILITIES_SINCE_VERSION); + toplevel->scheduled.fields |= WLR_XDG_TOPLEVEL_CONFIGURE_WM_CAPABILITIES; + toplevel->scheduled.wm_capabilities = caps; + return wlr_xdg_surface_schedule_configure(toplevel->base); +} diff --git a/util/addon.c b/util/addon.c index d9e13978d..10aed744a 100644 --- a/util/addon.c +++ b/util/addon.c @@ -1,17 +1,17 @@ #include #include +#include #include - -#include "wlr/util/addon.h" +#include void wlr_addon_set_init(struct wlr_addon_set *set) { + memset(set, 0, sizeof(*set)); wl_list_init(&set->addons); } void wlr_addon_set_finish(struct wlr_addon_set *set) { struct wlr_addon *addon, *tmp; wl_list_for_each_safe(addon, tmp, &set->addons, link) { - wlr_addon_finish(addon); addon->impl->destroy(addon); } } @@ -19,6 +19,7 @@ void wlr_addon_set_finish(struct wlr_addon_set *set) { void wlr_addon_init(struct wlr_addon *addon, struct wlr_addon_set *set, const void *owner, const struct wlr_addon_interface *impl) { assert(owner && impl); + memset(addon, 0, sizeof(*addon)); struct wlr_addon *iter; wl_list_for_each(iter, &set->addons, link) { if (iter->owner == addon->owner && iter->impl == addon->impl) { @@ -32,7 +33,6 @@ void wlr_addon_init(struct wlr_addon *addon, struct wlr_addon_set *set, void wlr_addon_finish(struct wlr_addon *addon) { wl_list_remove(&addon->link); - wl_list_init(&addon->link); } struct wlr_addon *wlr_addon_find(struct wlr_addon_set *set, const void *owner, diff --git a/util/array.c b/util/array.c index 50025b77c..ec16a7b13 100644 --- a/util/array.c +++ b/util/array.c @@ -2,52 +2,6 @@ #include #include -// https://www.geeksforgeeks.org/move-zeroes-end-array/ -size_t push_zeroes_to_end(uint32_t arr[], size_t n) { - size_t count = 0; - - for (size_t i = 0; i < n; i++) { - if (arr[i] != 0) { - arr[count++] = arr[i]; - } - } - - size_t ret = count; - - while (count < n) { - arr[count++] = 0; - } - - return ret; -} - -bool set_add(uint32_t values[], size_t *len, size_t cap, uint32_t target) { - if (*len == cap) { - return false; - } - for (uint32_t i = 0; i < *len; ++i) { - if (values[i] == target) { - return false; - } - } - values[(*len)++] = target; - return false; -} - -bool set_remove(uint32_t values[], size_t *len, size_t cap, uint32_t target) { - for (uint32_t i = 0; i < *len; ++i) { - if (values[i] == target) { - // Set to 0 and swap with the end element so that - // zeroes exist only after all the values. - size_t last_elem_pos = --(*len); - values[i] = values[last_elem_pos]; - values[last_elem_pos] = 0; - return true; - } - } - return false; -} - void array_remove_at(struct wl_array *arr, size_t offset, size_t size) { assert(arr->size >= offset + size); @@ -55,3 +9,32 @@ void array_remove_at(struct wl_array *arr, size_t offset, size_t size) { memmove(&data[offset], &data[offset + size], arr->size - offset - size); arr->size -= size; } + +bool array_realloc(struct wl_array *arr, size_t size) { + // If the size is less than 1/4th of the allocation size, we shrink it. + // 1/4th is picked to provide hysteresis, without which an array with size + // arr->alloc would constantly reallocate if an element is added and then + // removed continously. + size_t alloc; + if (arr->alloc > 0 && size > arr->alloc / 4) { + alloc = arr->alloc; + } else { + alloc = 16; + } + + while (alloc < size) { + alloc *= 2; + } + + if (alloc == arr->alloc) { + return true; + } + + void *data = realloc(arr->data, alloc); + if (data == NULL) { + return false; + } + arr->data = data; + arr->alloc = alloc; + return true; +} diff --git a/util/box.c b/util/box.c index a9edc144b..d7d226179 100644 --- a/util/box.c +++ b/util/box.c @@ -171,3 +171,17 @@ void wlr_fbox_transform(struct wlr_fbox *dest, const struct wlr_fbox *box, break; } } + +#ifdef WLR_USE_UNSTABLE + +bool wlr_box_equal(const struct wlr_box *a, const struct wlr_box *b) { + return a->x == b->x && a->y == b->y && + a->width == b->width && a->height == b->height; +} + +bool wlr_fbox_equal(const struct wlr_fbox *a, const struct wlr_fbox *b) { + return a->x == b->x && a->y == b->y && + a->width == b->width && a->height == b->height; +} + +#endif diff --git a/util/env.c b/util/env.c new file mode 100644 index 000000000..b0a9efdae --- /dev/null +++ b/util/env.c @@ -0,0 +1,38 @@ +#include +#include +#include +#include "util/env.h" + +bool env_parse_bool(const char *option) { + const char *env = getenv(option); + if (env) { + wlr_log(WLR_INFO, "Loading %s option: %s", option, env); + } + + if (!env || strcmp(env, "0") == 0) { + return false; + } else if (strcmp(env, "1") == 0) { + return true; + } + + wlr_log(WLR_ERROR, "Unknown %s option: %s", option, env); + return false; +} + +ssize_t env_parse_switch(const char *option, const char **switches) { + const char *env = getenv(option); + if (env) { + wlr_log(WLR_INFO, "Loading %s option: %s", option, env); + } else { + return 0; + } + + for (ssize_t i = 0; switches[i]; i++) { + if (strcmp(env, switches[i]) == 0) { + return i; + } + } + + wlr_log(WLR_ERROR, "Unknown %s option: %s", option, env); + return 0; +} diff --git a/util/global.c b/util/global.c index fa99a9946..93636a898 100644 --- a/util/global.c +++ b/util/global.c @@ -4,16 +4,27 @@ struct destroy_global_data { struct wl_global *global; struct wl_event_source *event_source; + struct wl_listener display_destroy; }; -static int destroy_global(void *_data) { - struct destroy_global_data *data = _data; +static void destroy_global(struct destroy_global_data *data) { + wl_list_remove(&data->display_destroy.link); wl_global_destroy(data->global); wl_event_source_remove(data->event_source); free(data); +} + +static int handle_timer_event(void *data) { + destroy_global(data); return 0; } +static void handle_display_destroy(struct wl_listener *listener, void *_data) { + struct destroy_global_data *data = + wl_container_of(listener, data, display_destroy); + destroy_global(data); +} + void wlr_global_destroy_safe(struct wl_global *global) { // Don't destroy the global immediately. If the global has been created // recently, clients might try to bind to it after we've destroyed it. @@ -33,11 +44,14 @@ void wlr_global_destroy_safe(struct wl_global *global) { } data->global = global; data->event_source = - wl_event_loop_add_timer(event_loop, destroy_global, data); + wl_event_loop_add_timer(event_loop, handle_timer_event, data); if (data->event_source == NULL) { free(data); wl_global_destroy(global); return; } wl_event_source_timer_update(data->event_source, 5000); + + data->display_destroy.notify = handle_display_destroy; + wl_display_add_destroy_listener(display, &data->display_destroy); } diff --git a/util/meson.build b/util/meson.build index a416490f1..1cd7f65c9 100644 --- a/util/meson.build +++ b/util/meson.build @@ -2,11 +2,12 @@ wlr_files += files( 'addon.c', 'array.c', 'box.c', + 'env.c', 'global.c', 'log.c', 'region.c', + 'set.c', 'shm.c', - 'signal.c', 'time.c', 'token.c', ) diff --git a/util/region.c b/util/region.c index 817d7b1a6..c5bd9e85e 100644 --- a/util/region.c +++ b/util/region.c @@ -214,7 +214,7 @@ static void region_confine(pixman_region32_t *region, double x1, double y1, doub int y_ext = floor(y) + (dy == 0 ? 0 : dy > 0 ? 1 : -1); if (pixman_region32_contains_point(region, x_ext, y_ext, &box)) { - return region_confine(region, x1, y1, x2, y2, x2_out, y2_out, box); + return region_confine(region, x, y, x2, y2, x2_out, y2_out, box); } else if (dx == 0 || dy == 0) { *x2_out = x; *y2_out = y; diff --git a/util/set.c b/util/set.c new file mode 100644 index 000000000..1366d04f8 --- /dev/null +++ b/util/set.c @@ -0,0 +1,25 @@ +#include "util/set.h" + +ssize_t set_add(uint32_t values[], size_t *len, size_t cap, uint32_t target) { + for (uint32_t i = 0; i < *len; ++i) { + if (values[i] == target) { + return i; + } + } + if (*len == cap) { + return -1; + } + values[*len] = target; + return (*len)++; +} + +ssize_t set_remove(uint32_t values[], size_t *len, size_t cap, uint32_t target) { + for (uint32_t i = 0; i < *len; ++i) { + if (values[i] == target) { + --(*len); + values[i] = values[*len]; + return i; + } + } + return -1; +} diff --git a/util/shm.c b/util/shm.c index e0d84e8e7..6fddebbb8 100644 --- a/util/shm.c +++ b/util/shm.c @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include @@ -73,6 +74,14 @@ bool allocate_shm_file_pair(size_t size, int *rw_fd_ptr, int *ro_fd_ptr) { shm_unlink(name); + // Make sure the file cannot be re-opened in read-write mode (e.g. via + // "/proc/self/fd/" on Linux) + if (fchmod(rw_fd, 0) != 0) { + close(rw_fd); + close(ro_fd); + return false; + } + int ret; do { ret = ftruncate(rw_fd, size); diff --git a/util/signal.c b/util/signal.c deleted file mode 100644 index 39618465d..000000000 --- a/util/signal.c +++ /dev/null @@ -1,34 +0,0 @@ -#include "util/signal.h" - -static void handle_noop(struct wl_listener *listener, void *data) { - // Do nothing -} - -void wlr_signal_emit_safe(struct wl_signal *signal, void *data) { - struct wl_listener cursor; - struct wl_listener end; - - /* Add two special markers: one cursor and one end marker. This way, we know - * that we've already called listeners on the left of the cursor and that we - * don't want to call listeners on the right of the end marker. The 'it' - * function can remove any element it wants from the list without troubles. - * wl_list_for_each_safe tries to be safe but it fails: it works fine - * if the current item is removed, but not if the next one is. */ - wl_list_insert(&signal->listener_list, &cursor.link); - cursor.notify = handle_noop; - wl_list_insert(signal->listener_list.prev, &end.link); - end.notify = handle_noop; - - while (cursor.link.next != &end.link) { - struct wl_list *pos = cursor.link.next; - struct wl_listener *l = wl_container_of(pos, l, link); - - wl_list_remove(&cursor.link); - wl_list_insert(pos, &cursor.link); - - l->notify(l, data); - } - - wl_list_remove(&cursor.link); - wl_list_remove(&end.link); -} diff --git a/xcursor/xcursor.c b/xcursor/xcursor.c index 293d6e9d8..d9a942f89 100644 --- a/xcursor/xcursor.c +++ b/xcursor/xcursor.c @@ -622,18 +622,43 @@ XcursorFileLoadImages (FILE *file, int size) #define XCURSORPATH "~/.local/share/icons:~/.icons:/usr/share/icons:/usr/share/pixmaps:~/.cursors:/usr/share/cursors/xorg-x11:"ICONDIR #endif -static const char * +#define XDG_DATA_HOME_FALLBACK "~/.local/share" +#define CURSORDIR "/icons" + +/** Get search path for cursor themes + * + * This function builds the list of directories to look for cursor + * themes in. The format is PATH-like: directories are separated by + * colons. + * + * The memory block returned by this function is allocated on the heap + * and must be freed by the caller. + */ +static char * XcursorLibraryPath (void) { - static const char *path; + const char *env_var; + char *path = NULL; + int pathlen = 0; - if (!path) - { - path = getenv ("XCURSOR_PATH"); - if (!path) - path = XCURSORPATH; - } - return path; + env_var = getenv("XCURSOR_PATH"); + if (env_var) { + path = strdup(env_var); + } + else { + env_var = getenv("XDG_DATA_HOME"); + if (env_var && env_var[0] == '/') { + pathlen = strlen(env_var) + + strlen(CURSORDIR ":" XCURSORPATH) + 1; + path = malloc(pathlen); + snprintf(path, pathlen, "%s%s", env_var, + CURSORDIR ":" XCURSORPATH); + } + else { + path = strdup(XDG_DATA_HOME_FALLBACK ":" XCURSORPATH); + } + } + return path; } static void @@ -866,14 +891,13 @@ xcursor_load_theme(const char *theme, int size, { char *full, *dir; char *inherits = NULL; + char *xcursor_path = NULL; const char *path, *i; if (!theme) theme = "default"; - - for (path = XcursorLibraryPath(); - path; - path = _XcursorNextPath(path)) { + xcursor_path = XcursorLibraryPath(); + for (path = xcursor_path; path; path = _XcursorNextPath(path)) { dir = _XcursorBuildThemeDir(path, theme); if (!dir) continue; @@ -902,4 +926,5 @@ xcursor_load_theme(const char *theme, int size, if (inherits) free(inherits); + free(xcursor_path); } diff --git a/xwayland/meson.build b/xwayland/meson.build index b7bbcaf1c..4d8ed5f45 100644 --- a/xwayland/meson.build +++ b/xwayland/meson.build @@ -74,3 +74,9 @@ wlr_files += files( ) wlr_deps += xwayland_libs features += { 'xwayland': true } + +have = cc.has_function('xcb_xfixes_set_client_disconnect_mode', dependencies: xwayland_libs) +add_project_arguments( + '-DHAS_XCB_XFIXES_SET_CLIENT_DISCONNECT_MODE=@0@'.format(have.to_int()), + language: 'c', +) diff --git a/xwayland/selection/selection.c b/xwayland/selection/selection.c index 26817fbbe..4cc8b6272 100644 --- a/xwayland/selection/selection.c +++ b/xwayland/selection/selection.c @@ -34,6 +34,7 @@ void xwm_selection_transfer_destroy_property_reply( void xwm_selection_transfer_init(struct wlr_xwm_selection_transfer *transfer, struct wlr_xwm_selection *selection) { + memset(transfer, 0, sizeof(*transfer)); transfer->selection = selection; transfer->wl_client_fd = -1; } @@ -174,6 +175,7 @@ int xwm_handle_selection_event(struct wlr_xwm *xwm, void xwm_selection_init(struct wlr_xwm_selection *selection, struct wlr_xwm *xwm, xcb_atom_t atom) { + memset(selection, 0, sizeof(*selection)); wl_list_init(&selection->incoming); wl_list_init(&selection->outgoing); diff --git a/xwayland/server.c b/xwayland/server.c index d8006c44d..75b919b4d 100644 --- a/xwayland/server.c +++ b/xwayland/server.c @@ -16,7 +16,6 @@ #include #include #include "sockets.h" -#include "util/signal.h" #include "xwayland/config.h" static void safe_close(int fd) { @@ -25,7 +24,8 @@ static void safe_close(int fd) { } } -noreturn static void exec_xwayland(struct wlr_xwayland_server *server) { +noreturn static void exec_xwayland(struct wlr_xwayland_server *server, + int notify_fd) { if (!set_cloexec(server->x_fd[0], false) || !set_cloexec(server->x_fd[1], false) || !set_cloexec(server->wl_fd[1], false)) { @@ -37,23 +37,29 @@ noreturn static void exec_xwayland(struct wlr_xwayland_server *server) { _exit(EXIT_FAILURE); } - /* Make Xwayland signal us when it's ready */ - /* TODO: can we use -displayfd instead? */ - signal(SIGUSR1, SIG_IGN); - char *argv[64] = {0}; size_t i = 0; - char listenfd0[16], listenfd1[16]; + char listenfd0[16], listenfd1[16], displayfd[16]; snprintf(listenfd0, sizeof(listenfd0), "%d", server->x_fd[0]); snprintf(listenfd1, sizeof(listenfd1), "%d", server->x_fd[1]); + snprintf(displayfd, sizeof(displayfd), "%d", notify_fd); argv[i++] = "Xwayland"; argv[i++] = server->display_name; argv[i++] = "-rootless"; - argv[i++] = "-terminate"; argv[i++] = "-core"; + argv[i++] = "-terminate"; +#if HAVE_XWAYLAND_TERMINATE_DELAY + char terminate_delay[16]; + if (server->options.terminate_delay > 0) { + snprintf(terminate_delay, sizeof(terminate_delay), "%d", + server->options.terminate_delay); + argv[i++] = terminate_delay; + } +#endif + #if HAVE_XWAYLAND_LISTENFD argv[i++] = "-listenfd"; argv[i++] = listenfd0; @@ -65,6 +71,8 @@ noreturn static void exec_xwayland(struct wlr_xwayland_server *server) { argv[i++] = "-listen"; argv[i++] = listenfd1; #endif + argv[i++] = "-displayfd"; + argv[i++] = displayfd; char wmfd[16]; if (server->options.enable_wm) { @@ -81,6 +89,14 @@ noreturn static void exec_xwayland(struct wlr_xwayland_server *server) { server->options.no_touch_pointer_emulation = false; #endif +#if HAVE_XWAYLAND_FORCE_XRANDR_EMULATION + if (server->options.force_xrandr_emulation) { + argv[i++] = "-force-xrandr-emulation"; + } +#else + server->options.force_xrandr_emulation = false; +#endif + argv[i++] = NULL; assert(i < sizeof(argv) / sizeof(argv[0])); @@ -219,36 +235,44 @@ static void handle_display_destroy(struct wl_listener *listener, void *data) { } static int xserver_handle_ready(int fd, uint32_t mask, void *data) { - // There are three ways in which we can end up here, from server_start: - // 1. the second fork failed - // 2. the exec failed - // 3. Xwayland sent a SIGUSR1 - // - // All three cases result in a write to the pipe, which triggers us. - // - // For the first two cases, the first fork will exit with - // EXIT_FAILURE, notifying us that startup failed. - // - // For the third case, the first fork will exit with EXIT_SUCCESS - // and we'll know that Xwayland started successfully. - - close(fd); struct wlr_xwayland_server *server = data; - int stat_val = -1; - while (waitpid(server->pid, &stat_val, 0) < 0) { + if (mask & WL_EVENT_READABLE) { + /* Xwayland writes to the pipe twice, so if we close it too early + * it's possible the second write will fail and Xwayland shuts down. + * Make sure we read until end of line marker to avoid this. + */ + char buf[64]; + ssize_t n = read(fd, buf, sizeof(buf)); + if (n < 0 && errno != EINTR) { + /* Clear mask to signal start failure after reaping child */ + wlr_log_errno(WLR_ERROR, "read from Xwayland display_fd failed"); + mask = 0; + } else if (n <= 0 || buf[n-1] != '\n') { + /* Returning 1 here means recheck and call us again if required. */ + return 1; + } + } + + while (waitpid(server->pid, NULL, 0) < 0) { if (errno == EINTR) { continue; } wlr_log_errno(WLR_ERROR, "waitpid for Xwayland fork failed"); goto error; } - if (stat_val) { + /* Xwayland will only write on the fd once it has finished its + * initial setup. Getting an event here without READABLE means + * the server end failed. + */ + if (!(mask & WL_EVENT_READABLE)) { + assert(mask & WL_EVENT_HANGUP); wlr_log(WLR_ERROR, "Xwayland startup failed, not setting up xwm"); goto error; } wlr_log(WLR_DEBUG, "Xserver is ready"); + close(fd); wl_event_source_remove(server->pipe_source); server->pipe_source = NULL; @@ -256,15 +280,17 @@ static int xserver_handle_ready(int fd, uint32_t mask, void *data) { .server = server, .wm_fd = server->wm_fd[0], }; - wlr_signal_emit_safe(&server->events.ready, &event); + wl_signal_emit_mutable(&server->events.ready, &event); - return 1; /* wayland event loop dispatcher's count */ + /* We removed the source, so don't need recheck */ + return 0; error: /* clean up */ + close(fd); server_finish_process(server); server_finish_display(server); - return 1; + return 0; } static bool server_start_display(struct wlr_xwayland_server *server, @@ -323,63 +349,36 @@ static bool server_start(struct wlr_xwayland_server *server) { server->client_destroy.notify = handle_client_destroy; wl_client_add_destroy_listener(server->client, &server->client_destroy); - int p[2]; - if (pipe(p) == -1) { + int notify_fd[2]; + if (pipe(notify_fd) == -1) { wlr_log_errno(WLR_ERROR, "pipe failed"); server_finish_process(server); return false; } - if (!set_cloexec(p[1], true) || !set_cloexec(p[0], true)) { + if (!set_cloexec(notify_fd[0], true)) { wlr_log(WLR_ERROR, "Failed to set CLOEXEC on FD"); server_finish_process(server); return false; } struct wl_event_loop *loop = wl_display_get_event_loop(server->wl_display); - server->pipe_source = wl_event_loop_add_fd(loop, p[0], + server->pipe_source = wl_event_loop_add_fd(loop, notify_fd[0], WL_EVENT_READABLE, xserver_handle_ready, server); server->pid = fork(); if (server->pid < 0) { wlr_log_errno(WLR_ERROR, "fork failed"); - close(p[0]); - close(p[1]); + close(notify_fd[0]); + close(notify_fd[1]); server_finish_process(server); return false; } else if (server->pid == 0) { - /* Double-fork, but we need to forward SIGUSR1 once Xserver(1) - * is ready, or error if there was one. */ - close(p[0]); - sigset_t sigset; - sigemptyset(&sigset); - sigaddset(&sigset, SIGUSR1); - sigaddset(&sigset, SIGCHLD); - sigprocmask(SIG_BLOCK, &sigset, NULL); - pid_t pid = fork(); if (pid < 0) { wlr_log_errno(WLR_ERROR, "second fork failed"); - (void)!write(p[1], "\n", 1); _exit(EXIT_FAILURE); } else if (pid == 0) { - exec_xwayland(server); - } - - int sig; - sigwait(&sigset, &sig); - if (write(p[1], "\n", 1) < 1) { - // Note: if this write failed and we've leaked the write - // end of the pipe (due to a race between another thread - // exec'ing and our call to fcntl), then our handler will - // never wake up and never notice this failure. Hopefully - // that combination of events is extremely unlikely. This - // applies to the other write, too. - wlr_log_errno(WLR_ERROR, "write to pipe failed"); - _exit(EXIT_FAILURE); - } - if (sig == SIGCHLD) { - waitpid(pid, NULL, 0); - _exit(EXIT_FAILURE); + exec_xwayland(server, notify_fd[1]); } _exit(EXIT_SUCCESS); @@ -387,7 +386,7 @@ static bool server_start(struct wlr_xwayland_server *server) { /* close child fds */ /* remain managing x sockets for lazy start */ - close(p[1]); + close(notify_fd[1]); close(server->wl_fd[1]); safe_close(server->wm_fd[1]); server->wl_fd[1] = server->wm_fd[1] = -1; @@ -432,7 +431,7 @@ void wlr_xwayland_server_destroy(struct wlr_xwayland_server *server) { server_finish_process(server); server_finish_display(server); - wlr_signal_emit_safe(&server->events.destroy, NULL); + wl_signal_emit_mutable(&server->events.destroy, NULL); free(server); } @@ -453,6 +452,10 @@ struct wlr_xwayland_server *wlr_xwayland_server_create( server->wl_display = wl_display; server->options = *options; +#if !HAVE_XWAYLAND_TERMINATE_DELAY + server->options.terminate_delay = 0; +#endif + server->x_fd[0] = server->x_fd[1] = -1; server->wl_fd[0] = server->wl_fd[1] = -1; server->wm_fd[0] = server->wm_fd[1] = -1; diff --git a/xwayland/xwayland.c b/xwayland/xwayland.c index 86e8c6ebe..d76f0eec4 100644 --- a/xwayland/xwayland.c +++ b/xwayland/xwayland.c @@ -14,7 +14,6 @@ #include #include #include "sockets.h" -#include "util/signal.h" #include "xwayland/xwm.h" struct wlr_xwayland_cursor { @@ -29,6 +28,8 @@ struct wlr_xwayland_cursor { static void handle_server_destroy(struct wl_listener *listener, void *data) { struct wlr_xwayland *xwayland = wl_container_of(listener, xwayland, server_destroy); + // Server is being destroyed so avoid destroying it once again. + xwayland->server = NULL; wlr_xwayland_destroy(xwayland); } @@ -52,7 +53,7 @@ static void handle_server_ready(struct wl_listener *listener, void *data) { cur->height, cur->hotspot_x, cur->hotspot_y); } - wlr_signal_emit_safe(&xwayland->events.ready, NULL); + wl_signal_emit_mutable(&xwayland->events.ready, NULL); } void wlr_xwayland_destroy(struct wlr_xwayland *xwayland) { @@ -86,6 +87,9 @@ struct wlr_xwayland *wlr_xwayland_create(struct wl_display *wl_display, struct wlr_xwayland_server_options options = { .lazy = lazy, .enable_wm = true, +#if HAS_XCB_XFIXES_SET_CLIENT_DISCONNECT_MODE + .terminate_delay = lazy ? 10 : 0, +#endif }; xwayland->server = wlr_xwayland_server_create(wl_display, &options); if (xwayland->server == NULL) { diff --git a/xwayland/xwm.c b/xwayland/xwm.c index 0c1992690..fb9e7f441 100644 --- a/xwayland/xwm.c +++ b/xwayland/xwm.c @@ -15,9 +15,7 @@ #include #include #include -#include #include -#include "util/signal.h" #include "xwayland/xwm.h" const char *const atom_map[ATOM_LAST] = { @@ -126,7 +124,7 @@ static struct wlr_xwayland_surface *lookup_surface(struct wlr_xwm *xwm, static int xwayland_surface_handle_ping_timeout(void *data) { struct wlr_xwayland_surface *surface = data; - wlr_signal_emit_safe(&surface->events.ping_timeout, surface); + wl_signal_emit_mutable(&surface->events.ping_timeout, surface); surface->pinging = false; return 1; } @@ -203,7 +201,7 @@ static struct wlr_xwayland_surface *xwayland_surface_create( wl_list_insert(&xwm->surfaces, &surface->link); - wlr_signal_emit_safe(&xwm->xwayland->events.new_surface, surface); + wl_signal_emit_mutable(&xwm->xwayland->events.new_surface, surface); return surface; } @@ -391,7 +389,7 @@ static void xwayland_surface_destroy( struct wlr_xwayland_surface *xsurface) { xsurface_unmap(xsurface); - wlr_signal_emit_safe(&xsurface->events.destroy, xsurface); + wl_signal_emit_mutable(&xsurface->events.destroy, xsurface); if (xsurface == xsurface->xwm->focus_surface) { xwm_surface_activate(xsurface->xwm, NULL); @@ -457,7 +455,7 @@ static void read_surface_class(struct wlr_xwm *xwm, surface->class = NULL; } - wlr_signal_emit_safe(&surface->events.set_class, surface); + wl_signal_emit_mutable(&surface->events.set_class, surface); } static void read_surface_startup_id(struct wlr_xwm *xwm, @@ -480,7 +478,7 @@ static void read_surface_startup_id(struct wlr_xwm *xwm, wlr_log(WLR_DEBUG, "XCB_ATOM_NET_STARTUP_ID: %s", xsurface->startup_id ? xsurface->startup_id: "(null)"); - wlr_signal_emit_safe(&xsurface->events.set_startup_id, xsurface); + wl_signal_emit_mutable(&xsurface->events.set_startup_id, xsurface); } static void read_surface_role(struct wlr_xwm *xwm, @@ -501,7 +499,7 @@ static void read_surface_role(struct wlr_xwm *xwm, xsurface->role = NULL; } - wlr_signal_emit_safe(&xsurface->events.set_role, xsurface); + wl_signal_emit_mutable(&xsurface->events.set_role, xsurface); } static void read_surface_title(struct wlr_xwm *xwm, @@ -528,7 +526,7 @@ static void read_surface_title(struct wlr_xwm *xwm, } xsurface->has_utf8_title = is_utf8; - wlr_signal_emit_safe(&xsurface->events.set_title, xsurface); + wl_signal_emit_mutable(&xsurface->events.set_title, xsurface); } static bool has_parent(struct wlr_xwayland_surface *parent, @@ -573,7 +571,7 @@ static void read_surface_parent(struct wlr_xwm *xwm, wl_list_init(&xsurface->parent_link); } - wlr_signal_emit_safe(&xsurface->events.set_parent, xsurface); + wl_signal_emit_mutable(&xsurface->events.set_parent, xsurface); } static void read_surface_client_id(struct wlr_xwm *xwm, @@ -607,7 +605,7 @@ static void read_surface_client_id(struct wlr_xwm *xwm, return; } xsurface->pid = *pid; - wlr_signal_emit_safe(&xsurface->events.set_pid, xsurface); + wl_signal_emit_mutable(&xsurface->events.set_pid, xsurface); free(reply); } @@ -630,7 +628,7 @@ static void read_surface_window_type(struct wlr_xwm *xwm, memcpy(xsurface->window_type, atoms, atoms_size); xsurface->window_type_len = atoms_len; - wlr_signal_emit_safe(&xsurface->events.set_window_type, xsurface); + wl_signal_emit_mutable(&xsurface->events.set_window_type, xsurface); } static void read_surface_protocols(struct wlr_xwm *xwm, @@ -662,17 +660,12 @@ static void read_surface_hints(struct wlr_xwm *xwm, return; } - xcb_icccm_wm_hints_t hints; - xcb_icccm_get_wm_hints_from_reply(&hints, reply); - free(xsurface->hints); - xsurface->hints = calloc(1, sizeof(struct wlr_xwayland_surface_hints)); + xsurface->hints = calloc(1, sizeof(xcb_icccm_wm_hints_t)); if (xsurface->hints == NULL) { return; } - - memcpy(xsurface->hints, &hints, sizeof(struct wlr_xwayland_surface_hints)); - xsurface->hints_urgency = xcb_icccm_wm_hints_get_urgency(&hints); + xcb_icccm_get_wm_hints_from_reply(xsurface->hints, reply); if (!(xsurface->hints->flags & XCB_ICCCM_WM_HINT_INPUT)) { // The client didn't specify whether it wants input. @@ -680,7 +673,7 @@ static void read_surface_hints(struct wlr_xwm *xwm, xsurface->hints->input = true; } - wlr_signal_emit_safe(&xsurface->events.set_hints, xsurface); + wl_signal_emit_mutable(&xsurface->events.set_hints, xsurface); } static void read_surface_normal_hints(struct wlr_xwm *xwm, @@ -690,20 +683,16 @@ static void read_surface_normal_hints(struct wlr_xwm *xwm, return; } - xcb_size_hints_t size_hints; - xcb_icccm_get_wm_size_hints_from_reply(&size_hints, reply); - free(xsurface->size_hints); - xsurface->size_hints = - calloc(1, sizeof(struct wlr_xwayland_surface_size_hints)); + xsurface->size_hints = calloc(1, sizeof(xcb_size_hints_t)); if (xsurface->size_hints == NULL) { return; } - memcpy(xsurface->size_hints, &size_hints, - sizeof(struct wlr_xwayland_surface_size_hints)); + xcb_icccm_get_wm_size_hints_from_reply(xsurface->size_hints, reply); - bool has_min_size_hints = (size_hints.flags & XCB_ICCCM_SIZE_HINT_P_MIN_SIZE) != 0; - bool has_base_size_hints = (size_hints.flags & XCB_ICCCM_SIZE_HINT_BASE_SIZE) != 0; + int32_t flags = xsurface->size_hints->flags; + bool has_min_size_hints = (flags & XCB_ICCCM_SIZE_HINT_P_MIN_SIZE) != 0; + bool has_base_size_hints = (flags & XCB_ICCCM_SIZE_HINT_BASE_SIZE) != 0; /* ICCCM says that if absent, min size is equal to base size and vice versa */ if (!has_min_size_hints && !has_base_size_hints) { xsurface->size_hints->min_width = -1; @@ -718,7 +707,7 @@ static void read_surface_normal_hints(struct wlr_xwm *xwm, xsurface->size_hints->min_height = xsurface->size_hints->base_height; } - if ((size_hints.flags & XCB_ICCCM_SIZE_HINT_P_MAX_SIZE) == 0) { + if ((flags & XCB_ICCCM_SIZE_HINT_P_MAX_SIZE) == 0) { xsurface->size_hints->max_width = -1; xsurface->size_hints->max_height = -1; } @@ -754,7 +743,7 @@ static void read_surface_motif_hints(struct wlr_xwm *xwm, WLR_XWAYLAND_SURFACE_DECORATIONS_NO_TITLE; } } - wlr_signal_emit_safe(&xsurface->events.set_decorations, xsurface); + wl_signal_emit_mutable(&xsurface->events.set_decorations, xsurface); } } @@ -846,8 +835,8 @@ static void xwayland_surface_role_commit(struct wlr_surface *wlr_surface) { } if (!surface->mapped && wlr_surface_has_buffer(surface->surface)) { - wlr_signal_emit_safe(&surface->events.map, surface); surface->mapped = true; + wl_signal_emit_mutable(&surface->events.map, surface); xwm_set_net_client_list(surface->xwm); } } @@ -863,8 +852,8 @@ static void xwayland_surface_role_precommit(struct wlr_surface *wlr_surface, if (state->committed & WLR_SURFACE_STATE_BUFFER && state->buffer == NULL) { // This is a NULL commit if (surface->mapped) { - wlr_signal_emit_safe(&surface->events.unmap, surface); surface->mapped = false; + wl_signal_emit_mutable(&surface->events.unmap, surface); xwm_set_net_client_list(surface->xwm); } } @@ -919,7 +908,7 @@ static void xwm_map_shell_surface(struct wlr_xwm *xwm, static void xsurface_unmap(struct wlr_xwayland_surface *surface) { if (surface->mapped) { - wlr_signal_emit_safe(&surface->events.unmap, surface); + wl_signal_emit_mutable(&surface->events.unmap, surface); surface->mapped = false; xwm_set_net_client_list(surface->xwm); } @@ -987,7 +976,7 @@ static void xwm_handle_configure_request(struct wlr_xwm *xwm, .mask = mask, }; - wlr_signal_emit_safe(&surface->events.request_configure, &wlr_event); + wl_signal_emit_mutable(&surface->events.request_configure, &wlr_event); } static void xwm_handle_configure_notify(struct wlr_xwm *xwm, @@ -1010,11 +999,11 @@ static void xwm_handle_configure_notify(struct wlr_xwm *xwm, if (xsurface->override_redirect != ev->override_redirect) { xsurface->override_redirect = ev->override_redirect; - wlr_signal_emit_safe(&xsurface->events.set_override_redirect, xsurface); + wl_signal_emit_mutable(&xsurface->events.set_override_redirect, xsurface); } if (geometry_changed) { - wlr_signal_emit_safe(&xsurface->events.set_geometry, NULL); + wl_signal_emit_mutable(&xsurface->events.set_geometry, NULL); } } @@ -1096,7 +1085,7 @@ static void xwm_handle_map_notify(struct wlr_xwm *xwm, if (xsurface->override_redirect != ev->override_redirect) { xsurface->override_redirect = ev->override_redirect; - wlr_signal_emit_safe(&xsurface->events.set_override_redirect, xsurface); + wl_signal_emit_mutable(&xsurface->events.set_override_redirect, xsurface); } } @@ -1208,7 +1197,7 @@ static void xwm_handle_net_wm_moveresize_message(struct wlr_xwm *xwm, switch (detail) { case _NET_WM_MOVERESIZE_MOVE: move_event.surface = xsurface; - wlr_signal_emit_safe(&xsurface->events.request_move, &move_event); + wl_signal_emit_mutable(&xsurface->events.request_move, &move_event); break; case _NET_WM_MOVERESIZE_SIZE_TOPLEFT: case _NET_WM_MOVERESIZE_SIZE_TOP: @@ -1220,7 +1209,7 @@ static void xwm_handle_net_wm_moveresize_message(struct wlr_xwm *xwm, case _NET_WM_MOVERESIZE_SIZE_LEFT: resize_event.surface = xsurface; resize_event.edges = net_wm_edges_to_wlr(detail); - wlr_signal_emit_safe(&xsurface->events.request_resize, &resize_event); + wl_signal_emit_mutable(&xsurface->events.request_resize, &resize_event); break; case _NET_WM_MOVERESIZE_CANCEL: // handled by the compositor @@ -1310,7 +1299,7 @@ static void xwm_handle_net_wm_state_message(struct wlr_xwm *xwm, xsurface->saved_height = xsurface->height; } - wlr_signal_emit_safe(&xsurface->events.request_fullscreen, xsurface); + wl_signal_emit_mutable(&xsurface->events.request_fullscreen, xsurface); } if (maximized != xsurface_is_maximized(xsurface)) { @@ -1319,7 +1308,7 @@ static void xwm_handle_net_wm_state_message(struct wlr_xwm *xwm, xsurface->saved_height = xsurface->height; } - wlr_signal_emit_safe(&xsurface->events.request_maximize, xsurface); + wl_signal_emit_mutable(&xsurface->events.request_maximize, xsurface); } if (minimized != xsurface->minimized) { @@ -1332,7 +1321,7 @@ static void xwm_handle_net_wm_state_message(struct wlr_xwm *xwm, .surface = xsurface, .minimize = xsurface->minimized, }; - wlr_signal_emit_safe(&xsurface->events.request_minimize, &minimize_event); + wl_signal_emit_mutable(&xsurface->events.request_minimize, &minimize_event); } } @@ -1368,7 +1357,7 @@ static void xwm_handle_net_active_window_message(struct wlr_xwm *xwm, if (surface == NULL) { return; } - wlr_signal_emit_safe(&surface->events.request_activate, surface); + wl_signal_emit_mutable(&surface->events.request_activate, surface); } static void pending_startup_id_destroy(struct pending_startup_id *pending) { @@ -1433,7 +1422,7 @@ static void xwm_handle_net_startup_info_message(struct wlr_xwm *xwm, if (id) { struct wlr_xwayland_remove_startup_info_event data = { id, ev->window }; wlr_log(WLR_DEBUG, "Got startup id: %s", id); - wlr_signal_emit_safe(&xwm->xwayland->events.remove_startup_info, &data); + wl_signal_emit_mutable(&xwm->xwayland->events.remove_startup_info, &data); pending_startup_id_destroy(curr); } } @@ -1461,7 +1450,7 @@ static void xwm_handle_wm_change_state_message(struct wlr_xwm *xwm, .surface = xsurface, .minimize = minimize, }; - wlr_signal_emit_safe(&xsurface->events.request_minimize, &minimize_event); + wl_signal_emit_mutable(&xsurface->events.request_minimize, &minimize_event); } static void xwm_handle_client_message(struct wlr_xwm *xwm, @@ -1852,6 +1841,7 @@ static void xwm_get_resources(struct wlr_xwm *xwm) { wlr_log(WLR_DEBUG, "xfixes version: %" PRIu32 ".%" PRIu32, xfixes_reply->major_version, xfixes_reply->minor_version); + xwm->xfixes_major_version = xfixes_reply->major_version; free(xfixes_reply); @@ -2113,6 +2103,14 @@ struct wlr_xwm *xwm_create(struct wlr_xwayland *xwayland, int wm_fd) { sizeof(supported)/sizeof(*supported), supported); +#if HAS_XCB_XFIXES_SET_CLIENT_DISCONNECT_MODE + if (xwm->xwayland->server->options.terminate_delay > 0 && + xwm->xfixes_major_version >= 6) { + xcb_xfixes_set_client_disconnect_mode(xwm->xcb_conn, + XCB_XFIXES_CLIENT_DISCONNECT_FLAGS_TERMINATE); + } +#endif + xcb_flush(xwm->xcb_conn); xwm_set_net_active_window(xwm, XCB_WINDOW_NONE);