mirror of
https://gitlab.freedesktop.org/wlroots/wlroots.git
synced 2026-03-29 07:58:24 -04:00
merge in upstream
This commit is contained in:
commit
3576eec3cf
154 changed files with 4860 additions and 4410 deletions
|
|
@ -16,7 +16,7 @@ sources:
|
||||||
tasks:
|
tasks:
|
||||||
- setup: |
|
- setup: |
|
||||||
cd wlroots
|
cd wlroots
|
||||||
meson build -Dauto_features=enabled -Dlogind=disabled -Dxcb-errors=disabled
|
meson build -Dauto_features=enabled -Dlogind=disabled -Dlibseat=disabled -Dxcb-errors=disabled
|
||||||
- build: |
|
- build: |
|
||||||
cd wlroots
|
cd wlroots
|
||||||
ninja -C build
|
ninja -C build
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@ packages:
|
||||||
- xcb-util-errors
|
- xcb-util-errors
|
||||||
- xcb-util-image
|
- xcb-util-image
|
||||||
- xcb-util-wm
|
- xcb-util-wm
|
||||||
|
- seatd
|
||||||
sources:
|
sources:
|
||||||
- https://github.com/swaywm/wlroots
|
- https://github.com/swaywm/wlroots
|
||||||
tasks:
|
tasks:
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@ packages:
|
||||||
- x11/pixman
|
- x11/pixman
|
||||||
- x11/xcb-util-errors
|
- x11/xcb-util-errors
|
||||||
- x11/xcb-util-wm
|
- x11/xcb-util-wm
|
||||||
|
- sysutils/seatd
|
||||||
sources:
|
sources:
|
||||||
- https://github.com/swaywm/wlroots
|
- https://github.com/swaywm/wlroots
|
||||||
tasks:
|
tasks:
|
||||||
|
|
|
||||||
|
|
@ -151,7 +151,7 @@ static struct wlr_backend *attempt_noop_backend(struct wl_display *display) {
|
||||||
static struct wlr_backend *attempt_drm_backend(struct wl_display *display,
|
static struct wlr_backend *attempt_drm_backend(struct wl_display *display,
|
||||||
struct wlr_backend *backend, struct wlr_session *session,
|
struct wlr_backend *backend, struct wlr_session *session,
|
||||||
wlr_renderer_create_func_t create_renderer_func) {
|
wlr_renderer_create_func_t create_renderer_func) {
|
||||||
int gpus[8];
|
struct wlr_device *gpus[8];
|
||||||
size_t num_gpus = wlr_session_find_gpus(session, 8, gpus);
|
size_t num_gpus = wlr_session_find_gpus(session, 8, gpus);
|
||||||
struct wlr_backend *primary_drm = NULL;
|
struct wlr_backend *primary_drm = NULL;
|
||||||
wlr_log(WLR_INFO, "Found %zu GPUs", num_gpus);
|
wlr_log(WLR_INFO, "Found %zu GPUs", num_gpus);
|
||||||
|
|
@ -160,7 +160,7 @@ static struct wlr_backend *attempt_drm_backend(struct wl_display *display,
|
||||||
struct wlr_backend *drm = wlr_drm_backend_create(display, session,
|
struct wlr_backend *drm = wlr_drm_backend_create(display, session,
|
||||||
gpus[i], primary_drm, create_renderer_func);
|
gpus[i], primary_drm, create_renderer_func);
|
||||||
if (!drm) {
|
if (!drm) {
|
||||||
wlr_log(WLR_ERROR, "Failed to open DRM device %d", gpus[i]);
|
wlr_log(WLR_ERROR, "Failed to create DRM backend");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -254,8 +254,7 @@ struct wlr_backend *wlr_backend_autocreate(struct wl_display *display,
|
||||||
return backend;
|
return backend;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (getenv("WAYLAND_DISPLAY") || getenv("_WAYLAND_DISPLAY") ||
|
if (getenv("WAYLAND_DISPLAY") || getenv("WAYLAND_SOCKET")) {
|
||||||
getenv("WAYLAND_SOCKET")) {
|
|
||||||
struct wlr_backend *wl_backend = attempt_wl_backend(display,
|
struct wlr_backend *wl_backend = attempt_wl_backend(display,
|
||||||
create_renderer_func);
|
create_renderer_func);
|
||||||
if (!wl_backend) {
|
if (!wl_backend) {
|
||||||
|
|
|
||||||
|
|
@ -25,8 +25,7 @@ static void atomic_begin(struct atomic *atom) {
|
||||||
|
|
||||||
static bool atomic_commit(struct atomic *atom,
|
static bool atomic_commit(struct atomic *atom,
|
||||||
struct wlr_drm_connector *conn, uint32_t flags) {
|
struct wlr_drm_connector *conn, uint32_t flags) {
|
||||||
struct wlr_drm_backend *drm =
|
struct wlr_drm_backend *drm = conn->backend;
|
||||||
get_drm_backend_from_backend(conn->output.backend);
|
|
||||||
if (atom->failed) {
|
if (atom->failed) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
@ -34,7 +33,7 @@ static bool atomic_commit(struct atomic *atom,
|
||||||
int ret = drmModeAtomicCommit(drm->fd, atom->req, flags, drm);
|
int ret = drmModeAtomicCommit(drm->fd, atom->req, flags, drm);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
wlr_log_errno(WLR_ERROR, "%s: Atomic %s failed (%s)",
|
wlr_log_errno(WLR_ERROR, "%s: Atomic %s failed (%s)",
|
||||||
conn->output.name,
|
conn->name,
|
||||||
(flags & DRM_MODE_ATOMIC_TEST_ONLY) ? "test" : "commit",
|
(flags & DRM_MODE_ATOMIC_TEST_ONLY) ? "test" : "commit",
|
||||||
(flags & DRM_MODE_ATOMIC_ALLOW_MODESET) ? "modeset" : "pageflip");
|
(flags & DRM_MODE_ATOMIC_ALLOW_MODESET) ? "modeset" : "pageflip");
|
||||||
return false;
|
return false;
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,7 @@ static void backend_destroy(struct wlr_backend *backend) {
|
||||||
|
|
||||||
struct wlr_drm_connector *conn, *next;
|
struct wlr_drm_connector *conn, *next;
|
||||||
wl_list_for_each_safe(conn, next, &drm->outputs, link) {
|
wl_list_for_each_safe(conn, next, &drm->outputs, link) {
|
||||||
wlr_output_destroy(&conn->output);
|
destroy_drm_connector(conn);
|
||||||
}
|
}
|
||||||
|
|
||||||
wlr_signal_emit_safe(&backend->events.destroy, backend);
|
wlr_signal_emit_safe(&backend->events.destroy, backend);
|
||||||
|
|
@ -50,7 +50,9 @@ static void backend_destroy(struct wlr_backend *backend) {
|
||||||
|
|
||||||
finish_drm_resources(drm);
|
finish_drm_resources(drm);
|
||||||
finish_drm_renderer(&drm->renderer);
|
finish_drm_renderer(&drm->renderer);
|
||||||
wlr_session_close_file(drm->session, drm->fd);
|
|
||||||
|
free(drm->name);
|
||||||
|
wlr_session_close_file(drm->session, drm->dev);
|
||||||
wl_event_source_remove(drm->drm_event);
|
wl_event_source_remove(drm->drm_event);
|
||||||
free(drm);
|
free(drm);
|
||||||
}
|
}
|
||||||
|
|
@ -85,7 +87,7 @@ bool wlr_backend_is_drm(struct wlr_backend *b) {
|
||||||
static void session_signal(struct wl_listener *listener, void *data) {
|
static void session_signal(struct wl_listener *listener, void *data) {
|
||||||
struct wlr_drm_backend *drm =
|
struct wlr_drm_backend *drm =
|
||||||
wl_container_of(listener, drm, session_signal);
|
wl_container_of(listener, drm, session_signal);
|
||||||
struct wlr_session *session = data;
|
struct wlr_session *session = drm->session;
|
||||||
|
|
||||||
if (session->active) {
|
if (session->active) {
|
||||||
wlr_log(WLR_INFO, "DRM fd resumed");
|
wlr_log(WLR_INFO, "DRM fd resumed");
|
||||||
|
|
@ -108,9 +110,7 @@ static void drm_invalidated(struct wl_listener *listener, void *data) {
|
||||||
struct wlr_drm_backend *drm =
|
struct wlr_drm_backend *drm =
|
||||||
wl_container_of(listener, drm, drm_invalidated);
|
wl_container_of(listener, drm, drm_invalidated);
|
||||||
|
|
||||||
char *name = drmGetDeviceNameFromFd2(drm->fd);
|
wlr_log(WLR_DEBUG, "%s invalidated", drm->name);
|
||||||
wlr_log(WLR_DEBUG, "%s invalidated", name);
|
|
||||||
free(name);
|
|
||||||
|
|
||||||
scan_drm_connectors(drm);
|
scan_drm_connectors(drm);
|
||||||
}
|
}
|
||||||
|
|
@ -128,15 +128,15 @@ static void handle_display_destroy(struct wl_listener *listener, void *data) {
|
||||||
}
|
}
|
||||||
|
|
||||||
struct wlr_backend *wlr_drm_backend_create(struct wl_display *display,
|
struct wlr_backend *wlr_drm_backend_create(struct wl_display *display,
|
||||||
struct wlr_session *session, int gpu_fd, struct wlr_backend *parent,
|
struct wlr_session *session, struct wlr_device *dev,
|
||||||
|
struct wlr_backend *parent,
|
||||||
wlr_renderer_create_func_t create_renderer_func) {
|
wlr_renderer_create_func_t create_renderer_func) {
|
||||||
assert(display && session && gpu_fd >= 0);
|
assert(display && session && dev);
|
||||||
assert(!parent || wlr_backend_is_drm(parent));
|
assert(!parent || wlr_backend_is_drm(parent));
|
||||||
|
|
||||||
char *name = drmGetDeviceNameFromFd2(gpu_fd);
|
char *name = drmGetDeviceNameFromFd2(dev->fd);
|
||||||
drmVersion *version = drmGetVersion(gpu_fd);
|
drmVersion *version = drmGetVersion(dev->fd);
|
||||||
wlr_log(WLR_INFO, "Initializing DRM backend for %s (%s)", name, version->name);
|
wlr_log(WLR_INFO, "Initializing DRM backend for %s (%s)", name, version->name);
|
||||||
free(name);
|
|
||||||
drmFreeVersion(version);
|
drmFreeVersion(version);
|
||||||
|
|
||||||
struct wlr_drm_backend *drm = calloc(1, sizeof(struct wlr_drm_backend));
|
struct wlr_drm_backend *drm = calloc(1, sizeof(struct wlr_drm_backend));
|
||||||
|
|
@ -149,13 +149,15 @@ struct wlr_backend *wlr_drm_backend_create(struct wl_display *display,
|
||||||
drm->session = session;
|
drm->session = session;
|
||||||
wl_list_init(&drm->outputs);
|
wl_list_init(&drm->outputs);
|
||||||
|
|
||||||
drm->fd = gpu_fd;
|
drm->dev = dev;
|
||||||
|
drm->fd = dev->fd;
|
||||||
|
drm->name = name;
|
||||||
if (parent != NULL) {
|
if (parent != NULL) {
|
||||||
drm->parent = get_drm_backend_from_backend(parent);
|
drm->parent = get_drm_backend_from_backend(parent);
|
||||||
}
|
}
|
||||||
|
|
||||||
drm->drm_invalidated.notify = drm_invalidated;
|
drm->drm_invalidated.notify = drm_invalidated;
|
||||||
wlr_session_signal_add(session, gpu_fd, &drm->drm_invalidated);
|
wl_signal_add(&dev->events.change, &drm->drm_invalidated);
|
||||||
|
|
||||||
drm->display = display;
|
drm->display = display;
|
||||||
struct wl_event_loop *event_loop = wl_display_get_event_loop(display);
|
struct wl_event_loop *event_loop = wl_display_get_event_loop(display);
|
||||||
|
|
@ -168,7 +170,7 @@ struct wlr_backend *wlr_drm_backend_create(struct wl_display *display,
|
||||||
}
|
}
|
||||||
|
|
||||||
drm->session_signal.notify = session_signal;
|
drm->session_signal.notify = session_signal;
|
||||||
wl_signal_add(&session->session_signal, &drm->session_signal);
|
wl_signal_add(&session->events.active, &drm->session_signal);
|
||||||
|
|
||||||
if (!check_drm_features(drm)) {
|
if (!check_drm_features(drm)) {
|
||||||
goto error_event;
|
goto error_event;
|
||||||
|
|
@ -195,7 +197,7 @@ error_event:
|
||||||
wl_list_remove(&drm->session_signal.link);
|
wl_list_remove(&drm->session_signal.link);
|
||||||
wl_event_source_remove(drm->drm_event);
|
wl_event_source_remove(drm->drm_event);
|
||||||
error_fd:
|
error_fd:
|
||||||
wlr_session_close_file(drm->session, drm->fd);
|
wlr_session_close_file(drm->session, dev);
|
||||||
free(drm);
|
free(drm);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,7 @@
|
||||||
#include "backend/drm/drm.h"
|
#include "backend/drm/drm.h"
|
||||||
#include "backend/drm/iface.h"
|
#include "backend/drm/iface.h"
|
||||||
#include "backend/drm/util.h"
|
#include "backend/drm/util.h"
|
||||||
|
#include "render/swapchain.h"
|
||||||
#include "util/signal.h"
|
#include "util/signal.h"
|
||||||
|
|
||||||
bool check_drm_features(struct wlr_drm_backend *drm) {
|
bool check_drm_features(struct wlr_drm_backend *drm) {
|
||||||
|
|
@ -104,22 +105,6 @@ static bool add_plane(struct wlr_drm_backend *drm,
|
||||||
DRM_FORMAT_MOD_INVALID);
|
DRM_FORMAT_MOD_INVALID);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Choose an RGB format for the plane
|
|
||||||
uint32_t rgb_format = DRM_FORMAT_INVALID;
|
|
||||||
for (size_t j = 0; j < drm_plane->count_formats; ++j) {
|
|
||||||
uint32_t fmt = drm_plane->formats[j];
|
|
||||||
|
|
||||||
if (fmt == DRM_FORMAT_ARGB2101010 || fmt == DRM_FORMAT_XRGB2101010 ||
|
|
||||||
fmt == DRM_FORMAT_ARGB8888) {
|
|
||||||
// Prefer formats with 10 bit color and/or alpha channel.
|
|
||||||
rgb_format = fmt;
|
|
||||||
break;
|
|
||||||
} else if (fmt == DRM_FORMAT_XRGB8888) {
|
|
||||||
rgb_format = fmt;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
p->drm_format = rgb_format;
|
|
||||||
|
|
||||||
if (p->props.in_formats) {
|
if (p->props.in_formats) {
|
||||||
uint64_t blob_id;
|
uint64_t blob_id;
|
||||||
if (!get_drm_prop(drm->fd, p->id, p->props.in_formats, &blob_id)) {
|
if (!get_drm_prop(drm->fd, p->id, p->props.in_formats, &blob_id)) {
|
||||||
|
|
@ -197,35 +182,29 @@ static bool init_planes(struct wlr_drm_backend *drm) {
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
// We don't really care about overlay planes, as we don't support them
|
||||||
* This is a very naive implementation of the plane matching
|
// yet.
|
||||||
* logic. Primary and cursor planes should only work on a
|
|
||||||
* single CRTC, and this should be perfectly adequate, but
|
|
||||||
* overlay planes can potentially work with multiple CRTCs,
|
|
||||||
* meaning this could return inefficient/skewed results.
|
|
||||||
*
|
|
||||||
* However, we don't really care about overlay planes, as we
|
|
||||||
* don't support them yet. We only bother to keep basic
|
|
||||||
* tracking of them for DRM lease clients.
|
|
||||||
*
|
|
||||||
* possible_crtcs is a bitmask of crtcs, where each bit is an
|
|
||||||
* index into drmModeRes.crtcs. So if bit 0 is set (ffs starts
|
|
||||||
* counting from 1), crtc 0 is possible.
|
|
||||||
*/
|
|
||||||
int crtc_bit = ffs(plane->possible_crtcs) - 1;
|
|
||||||
|
|
||||||
// This would be a kernel bug
|
|
||||||
assert(crtc_bit >= 0 && (size_t)crtc_bit < drm->num_crtcs);
|
|
||||||
|
|
||||||
struct wlr_drm_crtc *crtc = &drm->crtcs[crtc_bit];
|
|
||||||
|
|
||||||
if (type == DRM_PLANE_TYPE_OVERLAY) {
|
if (type == DRM_PLANE_TYPE_OVERLAY) {
|
||||||
uint32_t *tmp = realloc(crtc->overlays,
|
drmModeFreePlane(plane);
|
||||||
sizeof(*crtc->overlays) * (crtc->num_overlays + 1));
|
continue;
|
||||||
if (tmp) {
|
}
|
||||||
crtc->overlays = tmp;
|
|
||||||
crtc->overlays[crtc->num_overlays++] = id;
|
assert(drm->num_crtcs <= 32);
|
||||||
|
struct wlr_drm_crtc *crtc = NULL;
|
||||||
|
for (size_t j = 0; j < drm->num_crtcs ; j++) {
|
||||||
|
uint32_t crtc_bit = 1 << j;
|
||||||
|
if ((plane->possible_crtcs & crtc_bit) == 0) {
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct wlr_drm_crtc *candidate = &drm->crtcs[j];
|
||||||
|
if ((type == DRM_PLANE_TYPE_PRIMARY && !candidate->primary) ||
|
||||||
|
(type == DRM_PLANE_TYPE_CURSOR && !candidate->cursor)) {
|
||||||
|
crtc = candidate;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!crtc) {
|
||||||
drmModeFreePlane(plane);
|
drmModeFreePlane(plane);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
@ -314,7 +293,6 @@ void finish_drm_resources(struct wlr_drm_backend *drm) {
|
||||||
wlr_drm_format_set_finish(&crtc->cursor->formats);
|
wlr_drm_format_set_finish(&crtc->cursor->formats);
|
||||||
free(crtc->cursor);
|
free(crtc->cursor);
|
||||||
}
|
}
|
||||||
free(crtc->overlays);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
free(drm->crtcs);
|
free(drm->crtcs);
|
||||||
|
|
@ -332,16 +310,24 @@ static bool drm_connector_attach_render(struct wlr_output *output,
|
||||||
return drm_surface_make_current(&conn->crtc->primary->surf, buffer_age);
|
return drm_surface_make_current(&conn->crtc->primary->surf, buffer_age);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void drm_plane_set_committed(struct wlr_drm_plane *plane) {
|
||||||
|
drm_fb_move(&plane->queued_fb, &plane->pending_fb);
|
||||||
|
|
||||||
|
struct wlr_buffer *queued = plane->queued_fb.wlr_buf;
|
||||||
|
if (queued != NULL) {
|
||||||
|
wlr_swapchain_set_buffer_submitted(plane->surf.swapchain, queued);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static bool drm_crtc_commit(struct wlr_drm_connector *conn, uint32_t flags) {
|
static bool drm_crtc_commit(struct wlr_drm_connector *conn, uint32_t flags) {
|
||||||
struct wlr_drm_backend *drm =
|
struct wlr_drm_backend *drm = conn->backend;
|
||||||
get_drm_backend_from_backend(conn->output.backend);
|
|
||||||
struct wlr_drm_crtc *crtc = conn->crtc;
|
struct wlr_drm_crtc *crtc = conn->crtc;
|
||||||
bool ok = drm->iface->crtc_commit(drm, conn, flags);
|
bool ok = drm->iface->crtc_commit(drm, conn, flags);
|
||||||
if (ok && !(flags & DRM_MODE_ATOMIC_TEST_ONLY)) {
|
if (ok && !(flags & DRM_MODE_ATOMIC_TEST_ONLY)) {
|
||||||
memcpy(&crtc->current, &crtc->pending, sizeof(struct wlr_drm_crtc_state));
|
memcpy(&crtc->current, &crtc->pending, sizeof(struct wlr_drm_crtc_state));
|
||||||
drm_fb_move(&crtc->primary->queued_fb, &crtc->primary->pending_fb);
|
drm_plane_set_committed(crtc->primary);
|
||||||
if (crtc->cursor != NULL) {
|
if (crtc->cursor != NULL) {
|
||||||
drm_fb_move(&crtc->cursor->queued_fb, &crtc->cursor->pending_fb);
|
drm_plane_set_committed(crtc->cursor);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
memcpy(&crtc->pending, &crtc->current, sizeof(struct wlr_drm_crtc_state));
|
memcpy(&crtc->pending, &crtc->current, sizeof(struct wlr_drm_crtc_state));
|
||||||
|
|
@ -362,18 +348,24 @@ static bool drm_crtc_page_flip(struct wlr_drm_connector *conn) {
|
||||||
// we'll wait for all queued page-flips to complete, so we don't need this
|
// we'll wait for all queued page-flips to complete, so we don't need this
|
||||||
// safeguard.
|
// safeguard.
|
||||||
if (conn->pageflip_pending && !crtc->pending_modeset) {
|
if (conn->pageflip_pending && !crtc->pending_modeset) {
|
||||||
wlr_log(WLR_ERROR, "Failed to page-flip output '%s': "
|
wlr_drm_conn_log(conn, WLR_ERROR, "Failed to page-flip output: "
|
||||||
"a page-flip is already pending", conn->output.name);
|
"a page-flip is already pending");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(crtc->pending.active);
|
assert(crtc->pending.active);
|
||||||
assert(plane_get_next_fb(crtc->primary)->type != WLR_DRM_FB_TYPE_NONE);
|
assert(plane_get_next_fb(crtc->primary)->bo);
|
||||||
if (!drm_crtc_commit(conn, DRM_MODE_PAGE_FLIP_EVENT)) {
|
if (!drm_crtc_commit(conn, DRM_MODE_PAGE_FLIP_EVENT)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
conn->pageflip_pending = true;
|
conn->pageflip_pending = true;
|
||||||
|
|
||||||
|
// wlr_output's API guarantees that submitting a buffer will schedule a
|
||||||
|
// frame event. However the DRM backend will also schedule a frame event
|
||||||
|
// when performing a modeset. Set frame_pending to true so that
|
||||||
|
// wlr_output_schedule_frame doesn't trigger a synthetic frame event.
|
||||||
|
conn->output.frame_pending = true;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -381,8 +373,6 @@ static uint32_t strip_alpha_channel(uint32_t format) {
|
||||||
switch (format) {
|
switch (format) {
|
||||||
case DRM_FORMAT_ARGB8888:
|
case DRM_FORMAT_ARGB8888:
|
||||||
return DRM_FORMAT_XRGB8888;
|
return DRM_FORMAT_XRGB8888;
|
||||||
case DRM_FORMAT_ARGB2101010:
|
|
||||||
return DRM_FORMAT_XRGB2101010;
|
|
||||||
default:
|
default:
|
||||||
return DRM_FORMAT_INVALID;
|
return DRM_FORMAT_INVALID;
|
||||||
}
|
}
|
||||||
|
|
@ -390,8 +380,7 @@ static uint32_t strip_alpha_channel(uint32_t format) {
|
||||||
|
|
||||||
static bool test_buffer(struct wlr_drm_connector *conn,
|
static bool test_buffer(struct wlr_drm_connector *conn,
|
||||||
struct wlr_buffer *wlr_buffer) {
|
struct wlr_buffer *wlr_buffer) {
|
||||||
struct wlr_output *output = &conn->output;
|
struct wlr_drm_backend *drm = conn->backend;
|
||||||
struct wlr_drm_backend *drm = get_drm_backend_from_backend(output->backend);
|
|
||||||
|
|
||||||
if (!drm->session->active) {
|
if (!drm->session->active) {
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -441,7 +430,8 @@ static bool drm_connector_test(struct wlr_output *output) {
|
||||||
output->pending.enabled) {
|
output->pending.enabled) {
|
||||||
if (output->current_mode == NULL &&
|
if (output->current_mode == NULL &&
|
||||||
!(output->pending.committed & WLR_OUTPUT_STATE_MODE)) {
|
!(output->pending.committed & WLR_OUTPUT_STATE_MODE)) {
|
||||||
wlr_log(WLR_DEBUG, "Can't enable an output without a mode");
|
wlr_drm_conn_log(conn, WLR_DEBUG,
|
||||||
|
"Can't enable an output without a mode");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -476,7 +466,7 @@ static struct wlr_output_mode *drm_connector_get_pending_mode(
|
||||||
|
|
||||||
static bool drm_connector_commit_buffer(struct wlr_output *output) {
|
static bool drm_connector_commit_buffer(struct wlr_output *output) {
|
||||||
struct wlr_drm_connector *conn = get_drm_connector_from_output(output);
|
struct wlr_drm_connector *conn = get_drm_connector_from_output(output);
|
||||||
struct wlr_drm_backend *drm = get_drm_backend_from_backend(output->backend);
|
struct wlr_drm_backend *drm = conn->backend;
|
||||||
|
|
||||||
struct wlr_drm_crtc *crtc = conn->crtc;
|
struct wlr_drm_crtc *crtc = conn->crtc;
|
||||||
if (!crtc) {
|
if (!crtc) {
|
||||||
|
|
@ -488,7 +478,7 @@ static bool drm_connector_commit_buffer(struct wlr_output *output) {
|
||||||
switch (output->pending.buffer_type) {
|
switch (output->pending.buffer_type) {
|
||||||
case WLR_OUTPUT_STATE_BUFFER_RENDER:
|
case WLR_OUTPUT_STATE_BUFFER_RENDER:
|
||||||
if (!drm_fb_lock_surface(&plane->pending_fb, &plane->surf)) {
|
if (!drm_fb_lock_surface(&plane->pending_fb, &plane->surf)) {
|
||||||
wlr_log(WLR_ERROR, "drm_fb_lock_surface failed");
|
wlr_drm_conn_log(conn, WLR_ERROR, "drm_fb_lock_surface failed");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
@ -512,8 +502,7 @@ static bool drm_connector_commit_buffer(struct wlr_output *output) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool drm_connector_supports_vrr(struct wlr_drm_connector *conn) {
|
bool drm_connector_supports_vrr(struct wlr_drm_connector *conn) {
|
||||||
struct wlr_drm_backend *drm =
|
struct wlr_drm_backend *drm = conn->backend;
|
||||||
get_drm_backend_from_backend(conn->output.backend);
|
|
||||||
|
|
||||||
struct wlr_drm_crtc *crtc = conn->crtc;
|
struct wlr_drm_crtc *crtc = conn->crtc;
|
||||||
if (!crtc) {
|
if (!crtc) {
|
||||||
|
|
@ -524,13 +513,13 @@ bool drm_connector_supports_vrr(struct wlr_drm_connector *conn) {
|
||||||
if (conn->props.vrr_capable == 0 ||
|
if (conn->props.vrr_capable == 0 ||
|
||||||
!get_drm_prop(drm->fd, conn->id, conn->props.vrr_capable,
|
!get_drm_prop(drm->fd, conn->id, conn->props.vrr_capable,
|
||||||
&vrr_capable) || !vrr_capable) {
|
&vrr_capable) || !vrr_capable) {
|
||||||
wlr_log(WLR_DEBUG, "Failed to enable adaptive sync: "
|
wlr_drm_conn_log(conn, WLR_DEBUG, "Failed to enable adaptive sync: "
|
||||||
"connector '%s' doesn't support VRR", conn->output.name);
|
"connector doesn't support VRR");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (crtc->props.vrr_enabled == 0) {
|
if (crtc->props.vrr_enabled == 0) {
|
||||||
wlr_log(WLR_DEBUG, "Failed to enable adaptive sync: "
|
wlr_drm_conn_log(conn, WLR_DEBUG, "Failed to enable adaptive sync: "
|
||||||
"CRTC %"PRIu32" doesn't support VRR", crtc->id);
|
"CRTC %"PRIu32" doesn't support VRR", crtc->id);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
@ -540,7 +529,7 @@ bool drm_connector_supports_vrr(struct wlr_drm_connector *conn) {
|
||||||
|
|
||||||
static bool drm_connector_commit(struct wlr_output *output) {
|
static bool drm_connector_commit(struct wlr_output *output) {
|
||||||
struct wlr_drm_connector *conn = get_drm_connector_from_output(output);
|
struct wlr_drm_connector *conn = get_drm_connector_from_output(output);
|
||||||
struct wlr_drm_backend *drm = get_drm_backend_from_backend(output->backend);
|
struct wlr_drm_backend *drm = conn->backend;
|
||||||
|
|
||||||
if (!drm_connector_test(output)) {
|
if (!drm_connector_test(output)) {
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -590,13 +579,13 @@ static bool drm_connector_commit(struct wlr_output *output) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static void drm_connector_rollback_render(struct wlr_output *output) {
|
static void drm_connector_rollback_render(struct wlr_output *output) {
|
||||||
struct wlr_drm_backend *drm = get_drm_backend_from_backend(output->backend);
|
struct wlr_drm_connector *conn = get_drm_connector_from_output(output);
|
||||||
wlr_egl_unset_current(&drm->renderer.egl);
|
return drm_surface_unset_current(&conn->crtc->primary->surf);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t drm_crtc_get_gamma_lut_size(struct wlr_drm_backend *drm,
|
size_t drm_crtc_get_gamma_lut_size(struct wlr_drm_backend *drm,
|
||||||
struct wlr_drm_crtc *crtc) {
|
struct wlr_drm_crtc *crtc) {
|
||||||
if (crtc->props.gamma_lut_size == 0) {
|
if (crtc->props.gamma_lut_size == 0 || drm->iface == &legacy_iface) {
|
||||||
return (size_t)crtc->legacy_crtc->gamma_size;
|
return (size_t)crtc->legacy_crtc->gamma_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -612,7 +601,7 @@ size_t drm_crtc_get_gamma_lut_size(struct wlr_drm_backend *drm,
|
||||||
|
|
||||||
static size_t drm_connector_get_gamma_size(struct wlr_output *output) {
|
static size_t drm_connector_get_gamma_size(struct wlr_output *output) {
|
||||||
struct wlr_drm_connector *conn = get_drm_connector_from_output(output);
|
struct wlr_drm_connector *conn = get_drm_connector_from_output(output);
|
||||||
struct wlr_drm_backend *drm = get_drm_backend_from_backend(output->backend);
|
struct wlr_drm_backend *drm = conn->backend;
|
||||||
struct wlr_drm_crtc *crtc = conn->crtc;
|
struct wlr_drm_crtc *crtc = conn->crtc;
|
||||||
|
|
||||||
if (crtc == NULL) {
|
if (crtc == NULL) {
|
||||||
|
|
@ -625,7 +614,7 @@ static size_t drm_connector_get_gamma_size(struct wlr_output *output) {
|
||||||
static bool drm_connector_export_dmabuf(struct wlr_output *output,
|
static bool drm_connector_export_dmabuf(struct wlr_output *output,
|
||||||
struct wlr_dmabuf_attributes *attribs) {
|
struct wlr_dmabuf_attributes *attribs) {
|
||||||
struct wlr_drm_connector *conn = get_drm_connector_from_output(output);
|
struct wlr_drm_connector *conn = get_drm_connector_from_output(output);
|
||||||
struct wlr_drm_backend *drm = get_drm_backend_from_backend(output->backend);
|
struct wlr_drm_backend *drm = conn->backend;
|
||||||
struct wlr_drm_crtc *crtc = conn->crtc;
|
struct wlr_drm_crtc *crtc = conn->crtc;
|
||||||
|
|
||||||
if (!drm->session->active) {
|
if (!drm->session->active) {
|
||||||
|
|
@ -636,20 +625,22 @@ static bool drm_connector_export_dmabuf(struct wlr_output *output,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct wlr_drm_plane *plane = crtc->primary;
|
struct wlr_drm_fb *fb = &crtc->primary->queued_fb;
|
||||||
|
if (fb->bo == NULL) {
|
||||||
if (plane->current_fb.type == WLR_DRM_FB_TYPE_NONE) {
|
fb = &crtc->primary->current_fb;
|
||||||
|
}
|
||||||
|
if (fb->bo == NULL) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return export_drm_bo(plane->current_fb.bo, attribs);
|
return export_drm_bo(fb->bo, attribs);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct wlr_drm_fb *plane_get_next_fb(struct wlr_drm_plane *plane) {
|
struct wlr_drm_fb *plane_get_next_fb(struct wlr_drm_plane *plane) {
|
||||||
if (plane->pending_fb.type != WLR_DRM_FB_TYPE_NONE) {
|
if (plane->pending_fb.bo) {
|
||||||
return &plane->pending_fb;
|
return &plane->pending_fb;
|
||||||
}
|
}
|
||||||
if (plane->queued_fb.type != WLR_DRM_FB_TYPE_NONE) {
|
if (plane->queued_fb.bo) {
|
||||||
return &plane->queued_fb;
|
return &plane->queued_fb;
|
||||||
}
|
}
|
||||||
return &plane->current_fb;
|
return &plane->current_fb;
|
||||||
|
|
@ -658,15 +649,16 @@ struct wlr_drm_fb *plane_get_next_fb(struct wlr_drm_plane *plane) {
|
||||||
static bool drm_connector_pageflip_renderer(struct wlr_drm_connector *conn) {
|
static bool drm_connector_pageflip_renderer(struct wlr_drm_connector *conn) {
|
||||||
struct wlr_drm_crtc *crtc = conn->crtc;
|
struct wlr_drm_crtc *crtc = conn->crtc;
|
||||||
if (!crtc) {
|
if (!crtc) {
|
||||||
wlr_log(WLR_ERROR, "Page-flip failed on connector '%s': no CRTC",
|
wlr_drm_conn_log(conn, WLR_ERROR, "Page-flip failed: no CRTC");
|
||||||
conn->output.name);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// drm_crtc_page_flip expects a FB to be available
|
// drm_crtc_page_flip expects a FB to be available
|
||||||
struct wlr_drm_plane *plane = crtc->primary;
|
struct wlr_drm_plane *plane = crtc->primary;
|
||||||
if (plane_get_next_fb(plane)->type == WLR_DRM_FB_TYPE_NONE) {
|
if (!plane_get_next_fb(plane)->bo) {
|
||||||
drm_surface_render_black_frame(&plane->surf);
|
if (!drm_surface_render_black_frame(&plane->surf)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
if (!drm_fb_lock_surface(&plane->pending_fb, &plane->surf)) {
|
if (!drm_fb_lock_surface(&plane->pending_fb, &plane->surf)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
@ -677,21 +669,19 @@ static bool drm_connector_pageflip_renderer(struct wlr_drm_connector *conn) {
|
||||||
|
|
||||||
static bool drm_connector_init_renderer(struct wlr_drm_connector *conn,
|
static bool drm_connector_init_renderer(struct wlr_drm_connector *conn,
|
||||||
struct wlr_drm_mode *mode) {
|
struct wlr_drm_mode *mode) {
|
||||||
struct wlr_drm_backend *drm =
|
struct wlr_drm_backend *drm = conn->backend;
|
||||||
get_drm_backend_from_backend(conn->output.backend);
|
|
||||||
|
|
||||||
if (conn->state != WLR_DRM_CONN_CONNECTED &&
|
if (conn->state != WLR_DRM_CONN_CONNECTED &&
|
||||||
conn->state != WLR_DRM_CONN_NEEDS_MODESET) {
|
conn->state != WLR_DRM_CONN_NEEDS_MODESET) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
wlr_log(WLR_DEBUG, "Initializing renderer on connector '%s'",
|
wlr_drm_conn_log(conn, WLR_DEBUG, "Initializing renderer");
|
||||||
conn->output.name);
|
|
||||||
|
|
||||||
struct wlr_drm_crtc *crtc = conn->crtc;
|
struct wlr_drm_crtc *crtc = conn->crtc;
|
||||||
if (!crtc) {
|
if (!crtc) {
|
||||||
wlr_log(WLR_ERROR, "Failed to initialize renderer on connector '%s': "
|
wlr_drm_conn_log(conn, WLR_ERROR,
|
||||||
"no CRTC", conn->output.name);
|
"Failed to initialize renderer: no CRTC");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
struct wlr_drm_plane *plane = crtc->primary;
|
struct wlr_drm_plane *plane = crtc->primary;
|
||||||
|
|
@ -702,28 +692,28 @@ static bool drm_connector_init_renderer(struct wlr_drm_connector *conn,
|
||||||
|
|
||||||
int width = mode->wlr_mode.width;
|
int width = mode->wlr_mode.width;
|
||||||
int height = mode->wlr_mode.height;
|
int height = mode->wlr_mode.height;
|
||||||
uint32_t format = drm->renderer.gbm_format;
|
uint32_t format = DRM_FORMAT_ARGB8888;
|
||||||
|
|
||||||
bool modifiers = true;
|
bool modifiers = true;
|
||||||
const char *no_modifiers = getenv("WLR_DRM_NO_MODIFIERS");
|
const char *no_modifiers = getenv("WLR_DRM_NO_MODIFIERS");
|
||||||
if (no_modifiers != NULL && strcmp(no_modifiers, "1") == 0) {
|
if (no_modifiers != NULL && strcmp(no_modifiers, "1") == 0) {
|
||||||
wlr_log(WLR_DEBUG,
|
wlr_drm_conn_log(conn, WLR_DEBUG,
|
||||||
"WLR_DRM_NO_MODIFIERS set, initializing planes without modifiers");
|
"WLR_DRM_NO_MODIFIERS set, initializing planes without modifiers");
|
||||||
modifiers = false;
|
modifiers = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!drm_plane_init_surface(plane, drm, width, height, format, 0, modifiers) ||
|
if (!drm_plane_init_surface(plane, drm, width, height, format, false, modifiers) ||
|
||||||
!drm_connector_pageflip_renderer(conn)) {
|
!drm_connector_pageflip_renderer(conn)) {
|
||||||
if (!modifiers) {
|
if (!modifiers) {
|
||||||
wlr_log(WLR_ERROR, "Failed to initialize renderer "
|
wlr_drm_conn_log(conn, WLR_ERROR, "Failed to initialize renderer:"
|
||||||
"on connector '%s': initial page-flip failed",
|
"initial page-flip failed");
|
||||||
conn->output.name);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If page-flipping with modifiers enabled doesn't work, retry without
|
// If page-flipping with modifiers enabled doesn't work, retry without
|
||||||
// modifiers
|
// modifiers
|
||||||
wlr_log(WLR_INFO, "Page-flip failed with primary FB modifiers enabled, "
|
wlr_drm_conn_log(conn, WLR_INFO,
|
||||||
|
"Page-flip failed with primary FB modifiers enabled, "
|
||||||
"retrying without modifiers");
|
"retrying without modifiers");
|
||||||
modifiers = false;
|
modifiers = false;
|
||||||
|
|
||||||
|
|
@ -732,13 +722,12 @@ static bool drm_connector_init_renderer(struct wlr_drm_connector *conn,
|
||||||
crtc->pending.mode = mode;
|
crtc->pending.mode = mode;
|
||||||
|
|
||||||
if (!drm_plane_init_surface(plane, drm, width, height, format,
|
if (!drm_plane_init_surface(plane, drm, width, height, format,
|
||||||
0, modifiers)) {
|
false, modifiers)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!drm_connector_pageflip_renderer(conn)) {
|
if (!drm_connector_pageflip_renderer(conn)) {
|
||||||
wlr_log(WLR_ERROR, "Failed to initialize renderer "
|
wlr_drm_conn_log(conn, WLR_ERROR, "Failed to initialize renderer:"
|
||||||
"on connector '%s': initial page-flip failed",
|
"initial page-flip failed");
|
||||||
conn->output.name);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -756,19 +745,16 @@ static void attempt_enable_needs_modeset(struct wlr_drm_backend *drm) {
|
||||||
if (conn->state == WLR_DRM_CONN_NEEDS_MODESET &&
|
if (conn->state == WLR_DRM_CONN_NEEDS_MODESET &&
|
||||||
conn->crtc != NULL && conn->desired_mode != NULL &&
|
conn->crtc != NULL && conn->desired_mode != NULL &&
|
||||||
conn->desired_enabled) {
|
conn->desired_enabled) {
|
||||||
wlr_log(WLR_DEBUG, "Output %s has a desired mode and a CRTC, "
|
wlr_drm_conn_log(conn, WLR_DEBUG,
|
||||||
"attempting a modeset", conn->output.name);
|
"Output has a desired mode and a CRTC, attempting a modeset");
|
||||||
drm_connector_set_mode(conn, conn->desired_mode);
|
drm_connector_set_mode(conn, conn->desired_mode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void drm_connector_cleanup(struct wlr_drm_connector *conn);
|
|
||||||
|
|
||||||
bool drm_connector_set_mode(struct wlr_drm_connector *conn,
|
bool drm_connector_set_mode(struct wlr_drm_connector *conn,
|
||||||
struct wlr_output_mode *wlr_mode) {
|
struct wlr_output_mode *wlr_mode) {
|
||||||
struct wlr_drm_backend *drm =
|
struct wlr_drm_backend *drm = conn->backend;
|
||||||
get_drm_backend_from_backend(conn->output.backend);
|
|
||||||
|
|
||||||
conn->desired_enabled = wlr_mode != NULL;
|
conn->desired_enabled = wlr_mode != NULL;
|
||||||
conn->desired_mode = wlr_mode;
|
conn->desired_mode = wlr_mode;
|
||||||
|
|
@ -789,7 +775,8 @@ bool drm_connector_set_mode(struct wlr_drm_connector *conn,
|
||||||
|
|
||||||
if (conn->state != WLR_DRM_CONN_CONNECTED
|
if (conn->state != WLR_DRM_CONN_CONNECTED
|
||||||
&& conn->state != WLR_DRM_CONN_NEEDS_MODESET) {
|
&& conn->state != WLR_DRM_CONN_NEEDS_MODESET) {
|
||||||
wlr_log(WLR_ERROR, "Cannot modeset a disconnected output");
|
wlr_drm_conn_log(conn, WLR_ERROR,
|
||||||
|
"Cannot modeset a disconnected output");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -798,18 +785,19 @@ bool drm_connector_set_mode(struct wlr_drm_connector *conn,
|
||||||
realloc_crtcs(drm);
|
realloc_crtcs(drm);
|
||||||
}
|
}
|
||||||
if (conn->crtc == NULL) {
|
if (conn->crtc == NULL) {
|
||||||
wlr_log(WLR_ERROR, "Cannot modeset '%s': no CRTC for this connector",
|
wlr_drm_conn_log(conn, WLR_ERROR,
|
||||||
conn->output.name);
|
"Cannot perform modeset: no CRTC for this connector");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
wlr_log(WLR_INFO, "Modesetting '%s' with '%ux%u@%u mHz'",
|
wlr_drm_conn_log(conn, WLR_INFO,
|
||||||
conn->output.name, wlr_mode->width, wlr_mode->height,
|
"Modesetting with '%" PRId32 "x%" PRId32 "@%" PRId32 "mHz'",
|
||||||
wlr_mode->refresh);
|
wlr_mode->width, wlr_mode->height, wlr_mode->refresh);
|
||||||
|
|
||||||
struct wlr_drm_mode *mode = (struct wlr_drm_mode *)wlr_mode;
|
struct wlr_drm_mode *mode = (struct wlr_drm_mode *)wlr_mode;
|
||||||
if (!drm_connector_init_renderer(conn, mode)) {
|
if (!drm_connector_init_renderer(conn, mode)) {
|
||||||
wlr_log(WLR_ERROR, "Failed to initialize renderer for plane");
|
wlr_drm_conn_log(conn, WLR_ERROR,
|
||||||
|
"Failed to initialize renderer for plane");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -852,7 +840,7 @@ struct wlr_output_mode *wlr_drm_connector_add_mode(struct wlr_output *output,
|
||||||
mode->wlr_mode.height = mode->drm_mode.vdisplay;
|
mode->wlr_mode.height = mode->drm_mode.vdisplay;
|
||||||
mode->wlr_mode.refresh = calculate_refresh_rate(modeinfo);
|
mode->wlr_mode.refresh = calculate_refresh_rate(modeinfo);
|
||||||
|
|
||||||
wlr_log(WLR_INFO, "Registered custom mode "
|
wlr_drm_conn_log(conn, WLR_INFO, "Registered custom mode "
|
||||||
"%"PRId32"x%"PRId32"@%"PRId32,
|
"%"PRId32"x%"PRId32"@%"PRId32,
|
||||||
mode->wlr_mode.width, mode->wlr_mode.height,
|
mode->wlr_mode.width, mode->wlr_mode.height,
|
||||||
mode->wlr_mode.refresh);
|
mode->wlr_mode.refresh);
|
||||||
|
|
@ -866,7 +854,7 @@ static bool drm_connector_set_cursor(struct wlr_output *output,
|
||||||
enum wl_output_transform transform,
|
enum wl_output_transform transform,
|
||||||
int32_t hotspot_x, int32_t hotspot_y, bool update_texture) {
|
int32_t hotspot_x, int32_t hotspot_y, bool update_texture) {
|
||||||
struct wlr_drm_connector *conn = get_drm_connector_from_output(output);
|
struct wlr_drm_connector *conn = get_drm_connector_from_output(output);
|
||||||
struct wlr_drm_backend *drm = get_drm_backend_from_backend(output->backend);
|
struct wlr_drm_backend *drm = conn->backend;
|
||||||
struct wlr_drm_crtc *crtc = conn->crtc;
|
struct wlr_drm_crtc *crtc = conn->crtc;
|
||||||
|
|
||||||
if (!crtc) {
|
if (!crtc) {
|
||||||
|
|
@ -878,7 +866,7 @@ static bool drm_connector_set_cursor(struct wlr_output *output,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!plane->surf.gbm) {
|
if (!plane->surf.swapchain) {
|
||||||
int ret;
|
int ret;
|
||||||
uint64_t w, h;
|
uint64_t w, h;
|
||||||
ret = drmGetCap(drm->fd, DRM_CAP_CURSOR_WIDTH, &w);
|
ret = drmGetCap(drm->fd, DRM_CAP_CURSOR_WIDTH, &w);
|
||||||
|
|
@ -887,8 +875,8 @@ static bool drm_connector_set_cursor(struct wlr_output *output,
|
||||||
h = ret ? 64 : h;
|
h = ret ? 64 : h;
|
||||||
|
|
||||||
if (!drm_plane_init_surface(plane, drm, w, h,
|
if (!drm_plane_init_surface(plane, drm, w, h,
|
||||||
DRM_FORMAT_ARGB8888, GBM_BO_USE_LINEAR, false)) {
|
DRM_FORMAT_ARGB8888, true, false)) {
|
||||||
wlr_log(WLR_ERROR, "Cannot allocate cursor resources");
|
wlr_drm_conn_log(conn, WLR_ERROR, "Cannot allocate cursor resources");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -926,7 +914,7 @@ static bool drm_connector_set_cursor(struct wlr_output *output,
|
||||||
height = height * output->scale / scale;
|
height = height * output->scale / scale;
|
||||||
|
|
||||||
if (width > (int)plane->surf.width || height > (int)plane->surf.height) {
|
if (width > (int)plane->surf.width || height > (int)plane->surf.height) {
|
||||||
wlr_log(WLR_ERROR, "Cursor too large (max %dx%d)",
|
wlr_drm_conn_log(conn, WLR_ERROR, "Cursor too large (max %dx%d)",
|
||||||
(int)plane->surf.width, (int)plane->surf.height);
|
(int)plane->surf.width, (int)plane->surf.height);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
@ -954,19 +942,6 @@ static bool drm_connector_set_cursor(struct wlr_output *output,
|
||||||
plane->cursor_enabled = true;
|
plane->cursor_enabled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (plane->cursor_enabled) {
|
|
||||||
drm_fb_acquire(&plane->pending_fb, drm, &plane->mgpu_surf);
|
|
||||||
/* Workaround for nouveau buffers created with GBM_BO_USER_LINEAR are
|
|
||||||
* placed in NOUVEAU_GEM_DOMAIN_GART. When the bo is attached to the
|
|
||||||
* cursor plane it is moved to NOUVEAU_GEM_DOMAIN_VRAM. However, this
|
|
||||||
* does not wait for the render operations to complete, leaving an
|
|
||||||
* empty surface. See
|
|
||||||
* https://gitlab.freedesktop.org/xorg/driver/xf86-video-nouveau/issues/480
|
|
||||||
* The render operations can be waited for using:
|
|
||||||
*/
|
|
||||||
glFinish();
|
|
||||||
}
|
|
||||||
|
|
||||||
wlr_output_update_needs_frame(output);
|
wlr_output_update_needs_frame(output);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
@ -991,10 +966,8 @@ static bool drm_connector_move_cursor(struct wlr_output *output,
|
||||||
wlr_output_transform_invert(output->transform);
|
wlr_output_transform_invert(output->transform);
|
||||||
wlr_box_transform(&box, &box, transform, width, height);
|
wlr_box_transform(&box, &box, transform, width, height);
|
||||||
|
|
||||||
if (plane != NULL) {
|
box.x -= plane->cursor_hotspot_x;
|
||||||
box.x -= plane->cursor_hotspot_x;
|
box.y -= plane->cursor_hotspot_y;
|
||||||
box.y -= plane->cursor_hotspot_y;
|
|
||||||
}
|
|
||||||
|
|
||||||
conn->cursor_x = box.x;
|
conn->cursor_x = box.x;
|
||||||
conn->cursor_y = box.y;
|
conn->cursor_y = box.y;
|
||||||
|
|
@ -1014,18 +987,38 @@ bool drm_connector_is_cursor_visible(struct wlr_drm_connector *conn) {
|
||||||
conn->cursor_y + (int)plane->surf.height >= 0;
|
conn->cursor_y + (int)plane->surf.height >= 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void drm_connector_destroy(struct wlr_output *output) {
|
static void dealloc_crtc(struct wlr_drm_connector *conn);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Destroy the compositor-facing part of a connector.
|
||||||
|
*
|
||||||
|
* The connector isn't destroyed when disconnected. Only the compositor-facing
|
||||||
|
* wlr_output interface is cleaned up.
|
||||||
|
*/
|
||||||
|
static void drm_connector_destroy_output(struct wlr_output *output) {
|
||||||
struct wlr_drm_connector *conn = get_drm_connector_from_output(output);
|
struct wlr_drm_connector *conn = get_drm_connector_from_output(output);
|
||||||
drm_connector_cleanup(conn);
|
|
||||||
drmModeFreeCrtc(conn->old_crtc);
|
dealloc_crtc(conn);
|
||||||
wl_list_remove(&conn->link);
|
|
||||||
free(conn);
|
conn->state = WLR_DRM_CONN_DISCONNECTED;
|
||||||
|
conn->desired_enabled = false;
|
||||||
|
conn->desired_mode = NULL;
|
||||||
|
conn->possible_crtc = 0;
|
||||||
|
conn->pageflip_pending = false;
|
||||||
|
|
||||||
|
struct wlr_drm_mode *mode, *mode_tmp;
|
||||||
|
wl_list_for_each_safe(mode, mode_tmp, &conn->output.modes, wlr_mode.link) {
|
||||||
|
wl_list_remove(&mode->wlr_mode.link);
|
||||||
|
free(mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(&conn->output, 0, sizeof(struct wlr_output));
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct wlr_output_impl output_impl = {
|
static const struct wlr_output_impl output_impl = {
|
||||||
.set_cursor = drm_connector_set_cursor,
|
.set_cursor = drm_connector_set_cursor,
|
||||||
.move_cursor = drm_connector_move_cursor,
|
.move_cursor = drm_connector_move_cursor,
|
||||||
.destroy = drm_connector_destroy,
|
.destroy = drm_connector_destroy_output,
|
||||||
.attach_render = drm_connector_attach_render,
|
.attach_render = drm_connector_attach_render,
|
||||||
.test = drm_connector_test,
|
.test = drm_connector_test,
|
||||||
.commit = drm_connector_commit,
|
.commit = drm_connector_commit,
|
||||||
|
|
@ -1048,14 +1041,13 @@ static const int32_t subpixel_map[] = {
|
||||||
};
|
};
|
||||||
|
|
||||||
static void dealloc_crtc(struct wlr_drm_connector *conn) {
|
static void dealloc_crtc(struct wlr_drm_connector *conn) {
|
||||||
struct wlr_drm_backend *drm =
|
struct wlr_drm_backend *drm = conn->backend;
|
||||||
get_drm_backend_from_backend(conn->output.backend);
|
|
||||||
if (conn->crtc == NULL) {
|
if (conn->crtc == NULL) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
wlr_log(WLR_DEBUG, "De-allocating CRTC %zu for output '%s'",
|
wlr_drm_conn_log(conn, WLR_DEBUG, "De-allocating CRTC %zu",
|
||||||
conn->crtc - drm->crtcs, conn->output.name);
|
conn->crtc - drm->crtcs);
|
||||||
|
|
||||||
conn->crtc->pending_modeset = true;
|
conn->crtc->pending_modeset = true;
|
||||||
conn->crtc->pending.active = false;
|
conn->crtc->pending.active = false;
|
||||||
|
|
@ -1098,8 +1090,7 @@ static void realloc_crtcs(struct wlr_drm_backend *drm) {
|
||||||
connectors[i] = conn;
|
connectors[i] = conn;
|
||||||
|
|
||||||
wlr_log(WLR_DEBUG, " '%s' crtc=%d state=%d desired_enabled=%d",
|
wlr_log(WLR_DEBUG, " '%s' crtc=%d state=%d desired_enabled=%d",
|
||||||
conn->output.name,
|
conn->name, conn->crtc ? (int)(conn->crtc - drm->crtcs) : -1,
|
||||||
conn->crtc ? (int)(conn->crtc - drm->crtcs) : -1,
|
|
||||||
conn->state, conn->desired_enabled);
|
conn->state, conn->desired_enabled);
|
||||||
|
|
||||||
if (conn->crtc) {
|
if (conn->crtc) {
|
||||||
|
|
@ -1157,9 +1148,7 @@ static void realloc_crtcs(struct wlr_drm_backend *drm) {
|
||||||
bool prev_enabled = conn->crtc;
|
bool prev_enabled = conn->crtc;
|
||||||
|
|
||||||
wlr_log(WLR_DEBUG, " '%s' crtc=%zd state=%d desired_enabled=%d",
|
wlr_log(WLR_DEBUG, " '%s' crtc=%zd state=%d desired_enabled=%d",
|
||||||
conn->output.name,
|
conn->name, connector_match[i], conn->state, conn->desired_enabled);
|
||||||
connector_match[i],
|
|
||||||
conn->state, conn->desired_enabled);
|
|
||||||
|
|
||||||
// We don't need to change anything.
|
// We don't need to change anything.
|
||||||
if (prev_enabled && connector_match[i] == conn->crtc - drm->crtcs) {
|
if (prev_enabled && connector_match[i] == conn->crtc - drm->crtcs) {
|
||||||
|
|
@ -1170,8 +1159,7 @@ static void realloc_crtcs(struct wlr_drm_backend *drm) {
|
||||||
|
|
||||||
if (connector_match[i] == -1) {
|
if (connector_match[i] == -1) {
|
||||||
if (prev_enabled) {
|
if (prev_enabled) {
|
||||||
wlr_log(WLR_DEBUG, "Output has %s lost its CRTC",
|
wlr_drm_conn_log(conn, WLR_DEBUG, "Output has lost its CRTC");
|
||||||
conn->output.name);
|
|
||||||
conn->state = WLR_DRM_CONN_NEEDS_MODESET;
|
conn->state = WLR_DRM_CONN_NEEDS_MODESET;
|
||||||
wlr_output_update_enabled(&conn->output, false);
|
wlr_output_update_enabled(&conn->output, false);
|
||||||
conn->desired_mode = conn->output.current_mode;
|
conn->desired_mode = conn->output.current_mode;
|
||||||
|
|
@ -1190,8 +1178,7 @@ static void realloc_crtcs(struct wlr_drm_backend *drm) {
|
||||||
struct wlr_drm_mode *mode =
|
struct wlr_drm_mode *mode =
|
||||||
(struct wlr_drm_mode *)conn->output.current_mode;
|
(struct wlr_drm_mode *)conn->output.current_mode;
|
||||||
if (!drm_connector_init_renderer(conn, mode)) {
|
if (!drm_connector_init_renderer(conn, mode)) {
|
||||||
wlr_log(WLR_ERROR, "Failed to initialize renderer on output %s",
|
wlr_drm_conn_log(conn, WLR_ERROR, "Failed to initialize renderer");
|
||||||
conn->output.name);
|
|
||||||
wlr_output_update_enabled(&conn->output, false);
|
wlr_output_update_enabled(&conn->output, false);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
@ -1201,8 +1188,8 @@ static void realloc_crtcs(struct wlr_drm_backend *drm) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint32_t get_possible_crtcs(int fd, drmModeRes *res,
|
static uint32_t get_possible_crtcs(int fd, drmModeRes *res,
|
||||||
drmModeConnector *conn, bool is_mst) {
|
drmModeConnector *conn) {
|
||||||
uint32_t ret = 0;
|
uint32_t possible_crtcs = 0;
|
||||||
|
|
||||||
for (int i = 0; i < conn->count_encoders; ++i) {
|
for (int i = 0; i < conn->count_encoders; ++i) {
|
||||||
drmModeEncoder *enc = drmModeGetEncoder(fd, conn->encoders[i]);
|
drmModeEncoder *enc = drmModeGetEncoder(fd, conn->encoders[i]);
|
||||||
|
|
@ -1210,35 +1197,16 @@ static uint32_t get_possible_crtcs(int fd, drmModeRes *res,
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret |= enc->possible_crtcs;
|
possible_crtcs |= enc->possible_crtcs;
|
||||||
|
|
||||||
drmModeFreeEncoder(enc);
|
drmModeFreeEncoder(enc);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sometimes DP MST connectors report no encoders, so we'll loop though
|
return possible_crtcs;
|
||||||
// all of the encoders of the MST type instead.
|
|
||||||
// TODO: See if there is a better solution.
|
|
||||||
|
|
||||||
if (!is_mst || ret) {
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < res->count_encoders; ++i) {
|
|
||||||
drmModeEncoder *enc = drmModeGetEncoder(fd, res->encoders[i]);
|
|
||||||
if (!enc) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (enc->encoder_type == DRM_MODE_ENCODER_DPMST) {
|
|
||||||
ret |= enc->possible_crtcs;
|
|
||||||
}
|
|
||||||
|
|
||||||
drmModeFreeEncoder(enc);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void disconnect_drm_connector(struct wlr_drm_connector *conn);
|
||||||
|
|
||||||
void scan_drm_connectors(struct wlr_drm_backend *drm) {
|
void scan_drm_connectors(struct wlr_drm_backend *drm) {
|
||||||
/*
|
/*
|
||||||
* This GPU is not really a modesetting device.
|
* This GPU is not really a modesetting device.
|
||||||
|
|
@ -1248,7 +1216,7 @@ void scan_drm_connectors(struct wlr_drm_backend *drm) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
wlr_log(WLR_INFO, "Scanning DRM connectors");
|
wlr_log(WLR_INFO, "Scanning DRM connectors on %s", drm->name);
|
||||||
|
|
||||||
drmModeRes *res = drmModeGetResources(drm->fd);
|
drmModeRes *res = drmModeGetResources(drm->fd);
|
||||||
if (!res) {
|
if (!res) {
|
||||||
|
|
@ -1292,13 +1260,12 @@ void scan_drm_connectors(struct wlr_drm_backend *drm) {
|
||||||
drmModeFreeConnector(drm_conn);
|
drmModeFreeConnector(drm_conn);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
wlr_output_init(&wlr_conn->output, &drm->backend, &output_impl,
|
|
||||||
drm->display);
|
|
||||||
|
|
||||||
|
wlr_conn->backend = drm;
|
||||||
wlr_conn->state = WLR_DRM_CONN_DISCONNECTED;
|
wlr_conn->state = WLR_DRM_CONN_DISCONNECTED;
|
||||||
wlr_conn->id = drm_conn->connector_id;
|
wlr_conn->id = drm_conn->connector_id;
|
||||||
|
|
||||||
snprintf(wlr_conn->output.name, sizeof(wlr_conn->output.name),
|
snprintf(wlr_conn->name, sizeof(wlr_conn->name),
|
||||||
"%s-%"PRIu32, conn_get_name(drm_conn->connector_type),
|
"%s-%"PRIu32, conn_get_name(drm_conn->connector_type),
|
||||||
drm_conn->connector_type_id);
|
drm_conn->connector_type_id);
|
||||||
|
|
||||||
|
|
@ -1307,7 +1274,7 @@ void scan_drm_connectors(struct wlr_drm_backend *drm) {
|
||||||
}
|
}
|
||||||
|
|
||||||
wl_list_insert(drm->outputs.prev, &wlr_conn->link);
|
wl_list_insert(drm->outputs.prev, &wlr_conn->link);
|
||||||
wlr_log(WLR_INFO, "Found connector '%s'", wlr_conn->output.name);
|
wlr_log(WLR_INFO, "Found connector '%s'", wlr_conn->name);
|
||||||
} else {
|
} else {
|
||||||
seen[index] = true;
|
seen[index] = true;
|
||||||
}
|
}
|
||||||
|
|
@ -1329,24 +1296,30 @@ void scan_drm_connectors(struct wlr_drm_backend *drm) {
|
||||||
uint64_t link_status;
|
uint64_t link_status;
|
||||||
if (!get_drm_prop(drm->fd, wlr_conn->id,
|
if (!get_drm_prop(drm->fd, wlr_conn->id,
|
||||||
wlr_conn->props.link_status, &link_status)) {
|
wlr_conn->props.link_status, &link_status)) {
|
||||||
wlr_log(WLR_ERROR, "Failed to get link status for '%s'",
|
wlr_drm_conn_log(wlr_conn, WLR_ERROR,
|
||||||
wlr_conn->output.name);
|
"Failed to get link status prop");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (link_status == DRM_MODE_LINK_STATUS_BAD) {
|
if (link_status == DRM_MODE_LINK_STATUS_BAD) {
|
||||||
// We need to reload our list of modes and force a modeset
|
// We need to reload our list of modes and force a modeset
|
||||||
wlr_log(WLR_INFO, "Bad link for '%s'", wlr_conn->output.name);
|
wlr_drm_conn_log(wlr_conn, WLR_INFO, "Bad link detected");
|
||||||
drm_connector_cleanup(wlr_conn);
|
disconnect_drm_connector(wlr_conn);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (wlr_conn->state == WLR_DRM_CONN_DISCONNECTED &&
|
if (wlr_conn->state == WLR_DRM_CONN_DISCONNECTED &&
|
||||||
drm_conn->connection == DRM_MODE_CONNECTED) {
|
drm_conn->connection == DRM_MODE_CONNECTED) {
|
||||||
wlr_log(WLR_INFO, "'%s' connected", wlr_conn->output.name);
|
wlr_log(WLR_INFO, "'%s' connected", wlr_conn->name);
|
||||||
wlr_log(WLR_DEBUG, "Current CRTC: %d",
|
wlr_log(WLR_DEBUG, "Current CRTC: %d",
|
||||||
wlr_conn->crtc ? (int)wlr_conn->crtc->id : -1);
|
wlr_conn->crtc ? (int)wlr_conn->crtc->id : -1);
|
||||||
|
|
||||||
|
wlr_output_init(&wlr_conn->output, &drm->backend, &output_impl,
|
||||||
|
drm->display);
|
||||||
|
|
||||||
|
memcpy(wlr_conn->output.name, wlr_conn->name,
|
||||||
|
sizeof(wlr_conn->output.name));
|
||||||
|
|
||||||
wlr_conn->output.phys_width = drm_conn->mmWidth;
|
wlr_conn->output.phys_width = drm_conn->mmWidth;
|
||||||
wlr_conn->output.phys_height = drm_conn->mmHeight;
|
wlr_conn->output.phys_height = drm_conn->mmHeight;
|
||||||
wlr_log(WLR_INFO, "Physical size: %"PRId32"x%"PRId32,
|
wlr_log(WLR_INFO, "Physical size: %"PRId32"x%"PRId32,
|
||||||
|
|
@ -1397,20 +1370,9 @@ void scan_drm_connectors(struct wlr_drm_backend *drm) {
|
||||||
wl_list_insert(&wlr_conn->output.modes, &mode->wlr_mode.link);
|
wl_list_insert(&wlr_conn->output.modes, &mode->wlr_mode.link);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t path_len;
|
wlr_conn->possible_crtc = get_possible_crtcs(drm->fd, res, drm_conn);
|
||||||
bool is_mst = false;
|
|
||||||
char *path = get_drm_prop_blob(drm->fd, wlr_conn->id,
|
|
||||||
wlr_conn->props.path, &path_len);
|
|
||||||
if (path_len > 4 && path && strncmp(path, "mst:", 4) == 0) {
|
|
||||||
is_mst = true;
|
|
||||||
}
|
|
||||||
free(path);
|
|
||||||
|
|
||||||
wlr_conn->possible_crtc = get_possible_crtcs(drm->fd, res, drm_conn,
|
|
||||||
is_mst);
|
|
||||||
if (wlr_conn->possible_crtc == 0) {
|
if (wlr_conn->possible_crtc == 0) {
|
||||||
wlr_log(WLR_ERROR, "No CRTC possible for connector '%s'",
|
wlr_drm_conn_log(wlr_conn, WLR_ERROR, "No CRTC possible");
|
||||||
wlr_conn->output.name);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: this results in connectors being enabled without a mode
|
// TODO: this results in connectors being enabled without a mode
|
||||||
|
|
@ -1423,9 +1385,8 @@ void scan_drm_connectors(struct wlr_drm_backend *drm) {
|
||||||
} else if ((wlr_conn->state == WLR_DRM_CONN_CONNECTED ||
|
} else if ((wlr_conn->state == WLR_DRM_CONN_CONNECTED ||
|
||||||
wlr_conn->state == WLR_DRM_CONN_NEEDS_MODESET) &&
|
wlr_conn->state == WLR_DRM_CONN_NEEDS_MODESET) &&
|
||||||
drm_conn->connection != DRM_MODE_CONNECTED) {
|
drm_conn->connection != DRM_MODE_CONNECTED) {
|
||||||
wlr_log(WLR_INFO, "'%s' disconnected", wlr_conn->output.name);
|
wlr_log(WLR_INFO, "'%s' disconnected", wlr_conn->name);
|
||||||
|
disconnect_drm_connector(wlr_conn);
|
||||||
drm_connector_cleanup(wlr_conn);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
drmModeFreeEncoder(curr_enc);
|
drmModeFreeEncoder(curr_enc);
|
||||||
|
|
@ -1444,10 +1405,8 @@ void scan_drm_connectors(struct wlr_drm_backend *drm) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
wlr_log(WLR_INFO, "'%s' disappeared", conn->output.name);
|
wlr_log(WLR_INFO, "'%s' disappeared", conn->name);
|
||||||
drm_connector_cleanup(conn);
|
disconnect_drm_connector(conn);
|
||||||
|
|
||||||
wlr_output_destroy(&conn->output);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
realloc_crtcs(drm);
|
realloc_crtcs(drm);
|
||||||
|
|
@ -1455,8 +1414,7 @@ void scan_drm_connectors(struct wlr_drm_backend *drm) {
|
||||||
for (size_t i = 0; i < new_outputs_len; ++i) {
|
for (size_t i = 0; i < new_outputs_len; ++i) {
|
||||||
struct wlr_drm_connector *conn = new_outputs[i];
|
struct wlr_drm_connector *conn = new_outputs[i];
|
||||||
|
|
||||||
wlr_log(WLR_INFO, "Requesting modeset for '%s'",
|
wlr_drm_conn_log(conn, WLR_INFO, "Requesting modeset");
|
||||||
conn->output.name);
|
|
||||||
wlr_signal_emit_safe(&drm->backend.events.new_output,
|
wlr_signal_emit_safe(&drm->backend.events.new_output,
|
||||||
&conn->output);
|
&conn->output);
|
||||||
}
|
}
|
||||||
|
|
@ -1481,7 +1439,7 @@ static void page_flip_handler(int fd, unsigned seq,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!conn) {
|
if (!conn) {
|
||||||
wlr_log(WLR_DEBUG, "No connector for crtc_id %u", crtc_id);
|
wlr_log(WLR_DEBUG, "No connector for CRTC %u", crtc_id);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1492,11 +1450,10 @@ static void page_flip_handler(int fd, unsigned seq,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct wlr_drm_plane *plane = conn->crtc->primary;
|
struct wlr_drm_plane *plane = conn->crtc->primary;
|
||||||
if (plane->queued_fb.type != WLR_DRM_FB_TYPE_NONE) {
|
if (plane->queued_fb.bo) {
|
||||||
drm_fb_move(&plane->current_fb, &plane->queued_fb);
|
drm_fb_move(&plane->current_fb, &plane->queued_fb);
|
||||||
}
|
}
|
||||||
if (conn->crtc->cursor &&
|
if (conn->crtc->cursor && conn->crtc->cursor->queued_fb.bo) {
|
||||||
conn->crtc->cursor->queued_fb.type != WLR_DRM_FB_TYPE_NONE) {
|
|
||||||
drm_fb_move(&conn->crtc->cursor->current_fb,
|
drm_fb_move(&conn->crtc->cursor->current_fb,
|
||||||
&conn->crtc->cursor->queued_fb);
|
&conn->crtc->cursor->queued_fb);
|
||||||
}
|
}
|
||||||
|
|
@ -1507,7 +1464,8 @@ static void page_flip_handler(int fd, unsigned seq,
|
||||||
* data between the GPUs, even if we were using the direct scanout
|
* data between the GPUs, even if we were using the direct scanout
|
||||||
* interface.
|
* interface.
|
||||||
*/
|
*/
|
||||||
if (!drm->parent && plane->current_fb.type == WLR_DRM_FB_TYPE_WLR_BUFFER) {
|
if (!drm->parent && plane->current_fb.wlr_buf &&
|
||||||
|
wlr_client_buffer_get(plane->current_fb.wlr_buf)) {
|
||||||
present_flags |= WLR_OUTPUT_PRESENT_ZERO_COPY;
|
present_flags |= WLR_OUTPUT_PRESENT_ZERO_COPY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1526,7 +1484,7 @@ static void page_flip_handler(int fd, unsigned seq,
|
||||||
};
|
};
|
||||||
wlr_output_send_present(&conn->output, &present_event);
|
wlr_output_send_present(&conn->output, &present_event);
|
||||||
|
|
||||||
if (drm->session->active) {
|
if (drm->session->active && conn->output.enabled) {
|
||||||
wlr_output_send_frame(&conn->output);
|
wlr_output_send_frame(&conn->output);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1581,49 +1539,20 @@ void restore_drm_outputs(struct wlr_drm_backend *drm) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void drm_connector_cleanup(struct wlr_drm_connector *conn) {
|
static void disconnect_drm_connector(struct wlr_drm_connector *conn) {
|
||||||
if (!conn) {
|
if (conn->state == WLR_DRM_CONN_DISCONNECTED) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (conn->state) {
|
// This will cleanup the compositor-facing wlr_output, but won't destroy
|
||||||
case WLR_DRM_CONN_CONNECTED:
|
// our wlr_drm_connector.
|
||||||
case WLR_DRM_CONN_CLEANUP:
|
wlr_output_destroy(&conn->output);
|
||||||
conn->output.current_mode = NULL;
|
}
|
||||||
conn->desired_mode = NULL;
|
|
||||||
struct wlr_drm_mode *mode, *tmp;
|
void destroy_drm_connector(struct wlr_drm_connector *conn) {
|
||||||
wl_list_for_each_safe(mode, tmp, &conn->output.modes, wlr_mode.link) {
|
disconnect_drm_connector(conn);
|
||||||
wl_list_remove(&mode->wlr_mode.link);
|
|
||||||
free(mode);
|
drmModeFreeCrtc(conn->old_crtc);
|
||||||
}
|
wl_list_remove(&conn->link);
|
||||||
|
free(conn);
|
||||||
conn->output.enabled = false;
|
|
||||||
conn->output.width = conn->output.height = conn->output.refresh = 0;
|
|
||||||
|
|
||||||
memset(&conn->output.make, 0, sizeof(conn->output.make));
|
|
||||||
memset(&conn->output.model, 0, sizeof(conn->output.model));
|
|
||||||
memset(&conn->output.serial, 0, sizeof(conn->output.serial));
|
|
||||||
|
|
||||||
if (conn->output.idle_frame != NULL) {
|
|
||||||
wl_event_source_remove(conn->output.idle_frame);
|
|
||||||
conn->output.idle_frame = NULL;
|
|
||||||
}
|
|
||||||
conn->output.needs_frame = false;
|
|
||||||
conn->output.frame_pending = false;
|
|
||||||
|
|
||||||
/* Fallthrough */
|
|
||||||
case WLR_DRM_CONN_NEEDS_MODESET:
|
|
||||||
wlr_log(WLR_INFO, "Emitting destruction signal for '%s'",
|
|
||||||
conn->output.name);
|
|
||||||
dealloc_crtc(conn);
|
|
||||||
conn->possible_crtc = 0;
|
|
||||||
conn->desired_mode = NULL;
|
|
||||||
conn->pageflip_pending = false;
|
|
||||||
wlr_signal_emit_safe(&conn->output.events.destroy, &conn->output);
|
|
||||||
break;
|
|
||||||
case WLR_DRM_CONN_DISCONNECTED:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
conn->state = WLR_DRM_CONN_DISCONNECTED;
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -42,15 +42,14 @@ static bool legacy_crtc_commit(struct wlr_drm_backend *drm,
|
||||||
DRM_MODE_DPMS_ON : DRM_MODE_DPMS_OFF;
|
DRM_MODE_DPMS_ON : DRM_MODE_DPMS_OFF;
|
||||||
if (drmModeConnectorSetProperty(drm->fd, conn->id, conn->props.dpms,
|
if (drmModeConnectorSetProperty(drm->fd, conn->id, conn->props.dpms,
|
||||||
dpms) != 0) {
|
dpms) != 0) {
|
||||||
wlr_log_errno(WLR_ERROR, "%s: failed to set DPMS property",
|
wlr_drm_conn_log_errno(conn, WLR_ERROR,
|
||||||
conn->output.name);
|
"Failed to set DPMS property");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (drmModeSetCrtc(drm->fd, crtc->id, fb_id, 0, 0,
|
if (drmModeSetCrtc(drm->fd, crtc->id, fb_id, 0, 0,
|
||||||
conns, conns_len, mode)) {
|
conns, conns_len, mode)) {
|
||||||
wlr_log_errno(WLR_ERROR, "%s: failed to set CRTC",
|
wlr_drm_conn_log_errno(conn, WLR_ERROR, "Failed to set CRTC");
|
||||||
conn->output.name);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -67,16 +66,15 @@ static bool legacy_crtc_commit(struct wlr_drm_backend *drm,
|
||||||
if (drmModeObjectSetProperty(drm->fd, crtc->id, DRM_MODE_OBJECT_CRTC,
|
if (drmModeObjectSetProperty(drm->fd, crtc->id, DRM_MODE_OBJECT_CRTC,
|
||||||
crtc->props.vrr_enabled,
|
crtc->props.vrr_enabled,
|
||||||
output->pending.adaptive_sync_enabled) != 0) {
|
output->pending.adaptive_sync_enabled) != 0) {
|
||||||
wlr_log_errno(WLR_ERROR,
|
wlr_drm_conn_log_errno(conn, WLR_ERROR,
|
||||||
"drmModeObjectSetProperty(VRR_ENABLED) failed");
|
"drmModeObjectSetProperty(VRR_ENABLED) failed");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
output->adaptive_sync_status = output->pending.adaptive_sync_enabled ?
|
output->adaptive_sync_status = output->pending.adaptive_sync_enabled ?
|
||||||
WLR_OUTPUT_ADAPTIVE_SYNC_ENABLED :
|
WLR_OUTPUT_ADAPTIVE_SYNC_ENABLED :
|
||||||
WLR_OUTPUT_ADAPTIVE_SYNC_DISABLED;
|
WLR_OUTPUT_ADAPTIVE_SYNC_DISABLED;
|
||||||
wlr_log(WLR_DEBUG, "VRR %s on connector '%s'",
|
wlr_drm_conn_log(conn, WLR_DEBUG, "VRR %s",
|
||||||
output->pending.adaptive_sync_enabled ? "enabled" : "disabled",
|
output->pending.adaptive_sync_enabled ? "enabled" : "disabled");
|
||||||
output->name);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cursor != NULL && drm_connector_is_cursor_visible(conn)) {
|
if (cursor != NULL && drm_connector_is_cursor_visible(conn)) {
|
||||||
|
|
@ -84,29 +82,26 @@ static bool legacy_crtc_commit(struct wlr_drm_backend *drm,
|
||||||
struct gbm_bo *cursor_bo =
|
struct gbm_bo *cursor_bo =
|
||||||
drm_fb_acquire(cursor_fb, drm, &cursor->mgpu_surf);
|
drm_fb_acquire(cursor_fb, drm, &cursor->mgpu_surf);
|
||||||
if (!cursor_bo) {
|
if (!cursor_bo) {
|
||||||
wlr_log_errno(WLR_DEBUG, "%s: failed to acquire cursor FB",
|
wlr_drm_conn_log_errno(conn, WLR_DEBUG,
|
||||||
conn->output.name);
|
"Failed to acquire cursor FB");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (drmModeSetCursor(drm->fd, crtc->id,
|
if (drmModeSetCursor(drm->fd, crtc->id,
|
||||||
gbm_bo_get_handle(cursor_bo).u32,
|
gbm_bo_get_handle(cursor_bo).u32,
|
||||||
cursor->surf.width, cursor->surf.height)) {
|
cursor->surf.width, cursor->surf.height)) {
|
||||||
wlr_log_errno(WLR_DEBUG, "%s: failed to set hardware cursor",
|
wlr_drm_conn_log_errno(conn, WLR_DEBUG, "drmModeSetCursor failed");
|
||||||
conn->output.name);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (drmModeMoveCursor(drm->fd,
|
if (drmModeMoveCursor(drm->fd,
|
||||||
crtc->id, conn->cursor_x, conn->cursor_y) != 0) {
|
crtc->id, conn->cursor_x, conn->cursor_y) != 0) {
|
||||||
wlr_log_errno(WLR_ERROR, "%s: failed to move cursor",
|
wlr_drm_conn_log_errno(conn, WLR_ERROR, "drmModeMoveCursor failed");
|
||||||
conn->output.name);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (drmModeSetCursor(drm->fd, crtc->id, 0, 0, 0)) {
|
if (drmModeSetCursor(drm->fd, crtc->id, 0, 0, 0)) {
|
||||||
wlr_log_errno(WLR_DEBUG, "%s: failed to unset hardware cursor",
|
wlr_drm_conn_log_errno(conn, WLR_DEBUG, "drmModeSetCursor failed");
|
||||||
conn->output.name);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -114,7 +109,7 @@ static bool legacy_crtc_commit(struct wlr_drm_backend *drm,
|
||||||
if (flags & DRM_MODE_PAGE_FLIP_EVENT) {
|
if (flags & DRM_MODE_PAGE_FLIP_EVENT) {
|
||||||
if (drmModePageFlip(drm->fd, crtc->id, fb_id,
|
if (drmModePageFlip(drm->fd, crtc->id, fb_id,
|
||||||
DRM_MODE_PAGE_FLIP_EVENT, drm)) {
|
DRM_MODE_PAGE_FLIP_EVENT, drm)) {
|
||||||
wlr_log_errno(WLR_ERROR, "%s: Failed to page flip", conn->output.name);
|
wlr_drm_conn_log_errno(conn, WLR_ERROR, "drmModePageFlip failed");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -35,8 +35,6 @@ static const struct prop_info crtc_info[] = {
|
||||||
{ "GAMMA_LUT_SIZE", INDEX(gamma_lut_size) },
|
{ "GAMMA_LUT_SIZE", INDEX(gamma_lut_size) },
|
||||||
{ "MODE_ID", INDEX(mode_id) },
|
{ "MODE_ID", INDEX(mode_id) },
|
||||||
{ "VRR_ENABLED", INDEX(vrr_enabled) },
|
{ "VRR_ENABLED", INDEX(vrr_enabled) },
|
||||||
{ "rotation", INDEX(rotation) },
|
|
||||||
{ "scaling mode", INDEX(scaling_mode) },
|
|
||||||
#undef INDEX
|
#undef INDEX
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -53,6 +51,7 @@ static const struct prop_info plane_info[] = {
|
||||||
{ "SRC_W", INDEX(src_w) },
|
{ "SRC_W", INDEX(src_w) },
|
||||||
{ "SRC_X", INDEX(src_x) },
|
{ "SRC_X", INDEX(src_x) },
|
||||||
{ "SRC_Y", INDEX(src_y) },
|
{ "SRC_Y", INDEX(src_y) },
|
||||||
|
{ "rotation", INDEX(rotation) },
|
||||||
{ "type", INDEX(type) },
|
{ "type", INDEX(type) },
|
||||||
#undef INDEX
|
#undef INDEX
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
|
#define _POSIX_C_SOURCE 200809L
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <drm_fourcc.h>
|
#include <drm_fourcc.h>
|
||||||
|
#include <fcntl.h>
|
||||||
#include <gbm.h>
|
#include <gbm.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
@ -12,9 +14,14 @@
|
||||||
#include <wlr/types/wlr_matrix.h>
|
#include <wlr/types/wlr_matrix.h>
|
||||||
#include <wlr/util/log.h>
|
#include <wlr/util/log.h>
|
||||||
#include "backend/drm/drm.h"
|
#include "backend/drm/drm.h"
|
||||||
|
#include "render/drm_format_set.h"
|
||||||
|
#include "render/gbm_allocator.h"
|
||||||
|
#include "render/swapchain.h"
|
||||||
|
#include "render/wlr_renderer.h"
|
||||||
|
|
||||||
bool init_drm_renderer(struct wlr_drm_backend *drm,
|
bool init_drm_renderer(struct wlr_drm_backend *drm,
|
||||||
struct wlr_drm_renderer *renderer, wlr_renderer_create_func_t create_renderer_func) {
|
struct wlr_drm_renderer *renderer, wlr_renderer_create_func_t create_renderer_func) {
|
||||||
|
// TODO: get rid of renderer->gbm
|
||||||
renderer->gbm = gbm_create_device(drm->fd);
|
renderer->gbm = gbm_create_device(drm->fd);
|
||||||
if (!renderer->gbm) {
|
if (!renderer->gbm) {
|
||||||
wlr_log(WLR_ERROR, "Failed to create GBM device");
|
wlr_log(WLR_ERROR, "Failed to create GBM device");
|
||||||
|
|
@ -25,29 +32,31 @@ bool init_drm_renderer(struct wlr_drm_backend *drm,
|
||||||
create_renderer_func = wlr_renderer_autocreate;
|
create_renderer_func = wlr_renderer_autocreate;
|
||||||
}
|
}
|
||||||
|
|
||||||
static EGLint config_attribs[] = {
|
|
||||||
EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
|
|
||||||
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
|
|
||||||
EGL_RED_SIZE, 1,
|
|
||||||
EGL_GREEN_SIZE, 1,
|
|
||||||
EGL_BLUE_SIZE, 1,
|
|
||||||
EGL_ALPHA_SIZE, 1,
|
|
||||||
EGL_NONE,
|
|
||||||
};
|
|
||||||
|
|
||||||
// TODO: allow setting from sway config/args. Have sane default set.
|
|
||||||
renderer->gbm_format = GBM_FORMAT_ARGB2101010;
|
|
||||||
renderer->wlr_rend = create_renderer_func(&renderer->egl,
|
renderer->wlr_rend = create_renderer_func(&renderer->egl,
|
||||||
EGL_PLATFORM_GBM_MESA, renderer->gbm,
|
EGL_PLATFORM_GBM_KHR, renderer->gbm, NULL, 0);
|
||||||
config_attribs, renderer->gbm_format);
|
|
||||||
if (!renderer->wlr_rend) {
|
if (!renderer->wlr_rend) {
|
||||||
wlr_log(WLR_ERROR, "Failed to create EGL/WLR renderer");
|
wlr_log(WLR_ERROR, "Failed to create EGL/WLR renderer");
|
||||||
goto error_gbm;
|
goto error_gbm;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int alloc_fd = fcntl(drm->fd, F_DUPFD_CLOEXEC, 0);
|
||||||
|
if (alloc_fd < 0) {
|
||||||
|
wlr_log_errno(WLR_ERROR, "fcntl(F_DUPFD_CLOEXEC) failed");
|
||||||
|
goto error_wlr_rend;
|
||||||
|
}
|
||||||
|
|
||||||
|
renderer->allocator = wlr_gbm_allocator_create(alloc_fd);
|
||||||
|
if (renderer->allocator == NULL) {
|
||||||
|
wlr_log(WLR_ERROR, "Failed to create allocator");
|
||||||
|
close(alloc_fd);
|
||||||
|
goto error_wlr_rend;
|
||||||
|
}
|
||||||
|
|
||||||
renderer->fd = drm->fd;
|
renderer->fd = drm->fd;
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
error_wlr_rend:
|
||||||
|
wlr_renderer_destroy(renderer->wlr_rend);
|
||||||
error_gbm:
|
error_gbm:
|
||||||
gbm_device_destroy(renderer->gbm);
|
gbm_device_destroy(renderer->gbm);
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -58,6 +67,7 @@ void finish_drm_renderer(struct wlr_drm_renderer *renderer) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
wlr_allocator_destroy(&renderer->allocator->base);
|
||||||
wlr_renderer_destroy(renderer->wlr_rend);
|
wlr_renderer_destroy(renderer->wlr_rend);
|
||||||
wlr_egl_finish(&renderer->egl);
|
wlr_egl_finish(&renderer->egl);
|
||||||
gbm_device_destroy(renderer->gbm);
|
gbm_device_destroy(renderer->gbm);
|
||||||
|
|
@ -65,7 +75,7 @@ void finish_drm_renderer(struct wlr_drm_renderer *renderer) {
|
||||||
|
|
||||||
static bool init_drm_surface(struct wlr_drm_surface *surf,
|
static 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, uint32_t width, uint32_t height,
|
||||||
uint32_t format, struct wlr_drm_format_set *set, uint32_t flags) {
|
const struct wlr_drm_format *drm_format) {
|
||||||
if (surf->width == width && surf->height == height) {
|
if (surf->width == width && surf->height == height) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
@ -74,43 +84,20 @@ static bool init_drm_surface(struct wlr_drm_surface *surf,
|
||||||
surf->width = width;
|
surf->width = width;
|
||||||
surf->height = height;
|
surf->height = height;
|
||||||
|
|
||||||
if (surf->gbm) {
|
wlr_buffer_unlock(surf->back_buffer);
|
||||||
gbm_surface_destroy(surf->gbm);
|
surf->back_buffer = NULL;
|
||||||
surf->gbm = NULL;
|
wlr_swapchain_destroy(surf->swapchain);
|
||||||
}
|
surf->swapchain = NULL;
|
||||||
wlr_egl_destroy_surface(&surf->renderer->egl, surf->egl);
|
|
||||||
|
|
||||||
if (!(flags & GBM_BO_USE_LINEAR) && set != NULL) {
|
surf->swapchain = wlr_swapchain_create(&renderer->allocator->base,
|
||||||
const struct wlr_drm_format *drm_format =
|
width, height, drm_format);
|
||||||
wlr_drm_format_set_get(set, format);
|
if (surf->swapchain == NULL) {
|
||||||
if (drm_format != NULL) {
|
wlr_log(WLR_ERROR, "Failed to create swapchain");
|
||||||
surf->gbm = gbm_surface_create_with_modifiers(renderer->gbm,
|
memset(surf, 0, sizeof(*surf));
|
||||||
width, height, format, drm_format->modifiers, drm_format->len);
|
return false;
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (surf->gbm == NULL) {
|
|
||||||
surf->gbm = gbm_surface_create(renderer->gbm, width, height,
|
|
||||||
format, GBM_BO_USE_RENDERING | flags);
|
|
||||||
}
|
|
||||||
if (!surf->gbm) {
|
|
||||||
wlr_log_errno(WLR_ERROR, "Failed to create GBM surface");
|
|
||||||
goto error_zero;
|
|
||||||
}
|
|
||||||
|
|
||||||
surf->egl = wlr_egl_create_surface(&renderer->egl, surf->gbm);
|
|
||||||
if (surf->egl == EGL_NO_SURFACE) {
|
|
||||||
wlr_log(WLR_ERROR, "Failed to create EGL surface");
|
|
||||||
goto error_gbm;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
error_gbm:
|
|
||||||
gbm_surface_destroy(surf->gbm);
|
|
||||||
error_zero:
|
|
||||||
memset(surf, 0, sizeof(*surf));
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void finish_drm_surface(struct wlr_drm_surface *surf) {
|
static void finish_drm_surface(struct wlr_drm_surface *surf) {
|
||||||
|
|
@ -118,17 +105,40 @@ static void finish_drm_surface(struct wlr_drm_surface *surf) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
wlr_egl_destroy_surface(&surf->renderer->egl, surf->egl);
|
wlr_buffer_unlock(surf->back_buffer);
|
||||||
if (surf->gbm) {
|
wlr_swapchain_destroy(surf->swapchain);
|
||||||
gbm_surface_destroy(surf->gbm);
|
|
||||||
}
|
|
||||||
|
|
||||||
memset(surf, 0, sizeof(*surf));
|
memset(surf, 0, sizeof(*surf));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool drm_surface_make_current(struct wlr_drm_surface *surf,
|
bool drm_surface_make_current(struct wlr_drm_surface *surf,
|
||||||
int *buffer_age) {
|
int *buffer_age) {
|
||||||
return wlr_egl_make_current(&surf->renderer->egl, surf->egl, buffer_age);
|
wlr_buffer_unlock(surf->back_buffer);
|
||||||
|
surf->back_buffer = wlr_swapchain_acquire(surf->swapchain, buffer_age);
|
||||||
|
if (surf->back_buffer == NULL) {
|
||||||
|
wlr_log(WLR_ERROR, "Failed to acquire swapchain buffer");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!wlr_egl_make_current(&surf->renderer->egl, EGL_NO_SURFACE, NULL)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!wlr_renderer_bind_buffer(surf->renderer->wlr_rend, surf->back_buffer)) {
|
||||||
|
wlr_log(WLR_ERROR, "Failed to attach buffer to renderer");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void drm_surface_unset_current(struct wlr_drm_surface *surf) {
|
||||||
|
assert(surf->back_buffer != NULL);
|
||||||
|
|
||||||
|
wlr_renderer_bind_buffer(surf->renderer->wlr_rend, NULL);
|
||||||
|
wlr_egl_unset_current(&surf->renderer->egl);
|
||||||
|
|
||||||
|
wlr_buffer_unlock(surf->back_buffer);
|
||||||
|
surf->back_buffer = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool export_drm_bo(struct gbm_bo *bo, struct wlr_dmabuf_attributes *attribs) {
|
bool export_drm_bo(struct gbm_bo *bo, struct wlr_dmabuf_attributes *attribs) {
|
||||||
|
|
@ -203,8 +213,6 @@ static uint32_t strip_alpha_channel(uint32_t format) {
|
||||||
switch (format) {
|
switch (format) {
|
||||||
case DRM_FORMAT_ARGB8888:
|
case DRM_FORMAT_ARGB8888:
|
||||||
return DRM_FORMAT_XRGB8888;
|
return DRM_FORMAT_XRGB8888;
|
||||||
case DRM_FORMAT_ARGB2101010:
|
|
||||||
return DRM_FORMAT_XRGB2101010;
|
|
||||||
default:
|
default:
|
||||||
return DRM_FORMAT_INVALID;
|
return DRM_FORMAT_INVALID;
|
||||||
}
|
}
|
||||||
|
|
@ -212,85 +220,117 @@ static uint32_t strip_alpha_channel(uint32_t format) {
|
||||||
|
|
||||||
bool drm_plane_init_surface(struct wlr_drm_plane *plane,
|
bool drm_plane_init_surface(struct wlr_drm_plane *plane,
|
||||||
struct wlr_drm_backend *drm, int32_t width, uint32_t height,
|
struct wlr_drm_backend *drm, int32_t width, uint32_t height,
|
||||||
uint32_t format, uint32_t flags, bool with_modifiers) {
|
uint32_t format, bool force_linear, bool with_modifiers) {
|
||||||
if (!wlr_drm_format_set_has(&plane->formats, format, DRM_FORMAT_MOD_INVALID)) {
|
if (!wlr_drm_format_set_has(&plane->formats, format, DRM_FORMAT_MOD_INVALID)) {
|
||||||
format = strip_alpha_channel(format);
|
format = strip_alpha_channel(format);
|
||||||
}
|
}
|
||||||
if (!wlr_drm_format_set_has(&plane->formats, format, DRM_FORMAT_MOD_INVALID)) {
|
const struct wlr_drm_format *plane_format =
|
||||||
|
wlr_drm_format_set_get(&plane->formats, format);
|
||||||
|
if (plane_format == NULL) {
|
||||||
wlr_log(WLR_ERROR, "Plane %"PRIu32" doesn't support format 0x%"PRIX32,
|
wlr_log(WLR_ERROR, "Plane %"PRIu32" doesn't support format 0x%"PRIX32,
|
||||||
plane->id, format);
|
plane->id, format);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct wlr_drm_format_set *format_set =
|
const struct wlr_drm_format_set *render_formats =
|
||||||
with_modifiers ? &plane->formats : NULL;
|
wlr_renderer_get_dmabuf_render_formats(drm->renderer.wlr_rend);
|
||||||
|
if (render_formats == NULL) {
|
||||||
|
wlr_log(WLR_ERROR, "Failed to get render formats");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const struct wlr_drm_format *render_format =
|
||||||
|
wlr_drm_format_set_get(render_formats, format);
|
||||||
|
if (render_format == NULL) {
|
||||||
|
wlr_log(WLR_ERROR, "Renderer doesn't support format 0x%"PRIX32,
|
||||||
|
format);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct wlr_drm_format *drm_format = NULL;
|
||||||
|
if (with_modifiers) {
|
||||||
|
drm_format = wlr_drm_format_intersect(plane_format, render_format);
|
||||||
|
if (drm_format == NULL) {
|
||||||
|
wlr_log(WLR_ERROR,
|
||||||
|
"Failed to intersect plane and render formats 0x%"PRIX32,
|
||||||
|
format);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
drm_format = wlr_drm_format_create(format);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct wlr_drm_format *drm_format_linear = wlr_drm_format_create(format);
|
||||||
|
if (drm_format_linear == NULL) {
|
||||||
|
free(drm_format);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!wlr_drm_format_add(&drm_format_linear, DRM_FORMAT_MOD_LINEAR)) {
|
||||||
|
free(drm_format_linear);
|
||||||
|
free(drm_format);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (force_linear) {
|
||||||
|
free(drm_format);
|
||||||
|
drm_format = wlr_drm_format_dup(drm_format_linear);
|
||||||
|
}
|
||||||
|
|
||||||
drm_plane_finish_surface(plane);
|
drm_plane_finish_surface(plane);
|
||||||
|
|
||||||
|
bool ok = true;
|
||||||
if (!drm->parent) {
|
if (!drm->parent) {
|
||||||
return init_drm_surface(&plane->surf, &drm->renderer, width, height,
|
ok = init_drm_surface(&plane->surf, &drm->renderer,
|
||||||
format, format_set, flags | GBM_BO_USE_SCANOUT);
|
width, height, drm_format);
|
||||||
|
} else {
|
||||||
|
ok = init_drm_surface(&plane->surf, &drm->parent->renderer,
|
||||||
|
width, height, drm_format_linear);
|
||||||
|
if (ok && !init_drm_surface(&plane->mgpu_surf, &drm->renderer,
|
||||||
|
width, height, drm_format)) {
|
||||||
|
finish_drm_surface(&plane->surf);
|
||||||
|
ok = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!init_drm_surface(&plane->surf, &drm->parent->renderer,
|
free(drm_format_linear);
|
||||||
width, height, format, NULL,
|
free(drm_format);
|
||||||
flags | GBM_BO_USE_LINEAR)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!init_drm_surface(&plane->mgpu_surf, &drm->renderer,
|
return ok;
|
||||||
width, height, format, format_set,
|
|
||||||
flags | GBM_BO_USE_SCANOUT)) {
|
|
||||||
finish_drm_surface(&plane->surf);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void drm_fb_clear(struct wlr_drm_fb *fb) {
|
void drm_fb_clear(struct wlr_drm_fb *fb) {
|
||||||
switch (fb->type) {
|
if (!fb->bo) {
|
||||||
case WLR_DRM_FB_TYPE_NONE:
|
assert(!fb->wlr_buf);
|
||||||
assert(!fb->bo);
|
return;
|
||||||
break;
|
|
||||||
case WLR_DRM_FB_TYPE_SURFACE:
|
|
||||||
gbm_surface_release_buffer(fb->surf->gbm, fb->bo);
|
|
||||||
break;
|
|
||||||
case WLR_DRM_FB_TYPE_WLR_BUFFER:
|
|
||||||
gbm_bo_destroy(fb->bo);
|
|
||||||
wlr_buffer_unlock(fb->wlr_buf);
|
|
||||||
fb->wlr_buf = NULL;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fb->type = WLR_DRM_FB_TYPE_NONE;
|
gbm_bo_destroy(fb->bo);
|
||||||
|
wlr_buffer_unlock(fb->wlr_buf);
|
||||||
|
|
||||||
|
fb->wlr_buf = NULL;
|
||||||
fb->bo = NULL;
|
fb->bo = NULL;
|
||||||
|
|
||||||
if (fb->mgpu_bo) {
|
if (fb->mgpu_bo) {
|
||||||
assert(fb->mgpu_surf);
|
assert(fb->mgpu_surf);
|
||||||
gbm_surface_release_buffer(fb->mgpu_surf->gbm, fb->mgpu_bo);
|
gbm_bo_destroy(fb->mgpu_bo);
|
||||||
|
wlr_buffer_unlock(fb->mgpu_wlr_buf);
|
||||||
fb->mgpu_bo = NULL;
|
fb->mgpu_bo = NULL;
|
||||||
|
fb->mgpu_wlr_buf = NULL;
|
||||||
fb->mgpu_surf = NULL;
|
fb->mgpu_surf = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool drm_fb_lock_surface(struct wlr_drm_fb *fb, struct wlr_drm_surface *surf) {
|
bool drm_fb_lock_surface(struct wlr_drm_fb *fb, struct wlr_drm_surface *surf) {
|
||||||
drm_fb_clear(fb);
|
assert(surf->back_buffer != NULL);
|
||||||
|
|
||||||
if (!wlr_egl_swap_buffers(&surf->renderer->egl, surf->egl, NULL)) {
|
struct wlr_buffer *buffer = wlr_buffer_lock(surf->back_buffer);
|
||||||
wlr_log(WLR_ERROR, "Failed to swap buffers");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
fb->bo = gbm_surface_lock_front_buffer(surf->gbm);
|
// Unset the current EGL context ASAP, because other operations may require
|
||||||
if (!fb->bo) {
|
// making another context current.
|
||||||
wlr_log(WLR_ERROR, "Failed to lock front buffer");
|
drm_surface_unset_current(surf);
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
fb->type = WLR_DRM_FB_TYPE_SURFACE;
|
bool ok = drm_fb_import_wlr(fb, surf->renderer, buffer, NULL);
|
||||||
fb->surf = surf;
|
wlr_buffer_unlock(buffer);
|
||||||
return true;
|
return ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool drm_fb_import_wlr(struct wlr_drm_fb *fb, struct wlr_drm_renderer *renderer,
|
bool drm_fb_import_wlr(struct wlr_drm_fb *fb, struct wlr_drm_renderer *renderer,
|
||||||
|
|
@ -302,7 +342,7 @@ bool drm_fb_import_wlr(struct wlr_drm_fb *fb, struct wlr_drm_renderer *renderer,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!wlr_drm_format_set_has(set, attribs.format, attribs.modifier)) {
|
if (set && !wlr_drm_format_set_has(set, attribs.format, attribs.modifier)) {
|
||||||
// The format isn't supported by the plane. Try stripping the alpha
|
// The format isn't supported by the plane. Try stripping the alpha
|
||||||
// channel, if any.
|
// channel, if any.
|
||||||
uint32_t format = strip_alpha_channel(attribs.format);
|
uint32_t format = strip_alpha_channel(attribs.format);
|
||||||
|
|
@ -352,7 +392,6 @@ bool drm_fb_import_wlr(struct wlr_drm_fb *fb, struct wlr_drm_renderer *renderer,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
fb->type = WLR_DRM_FB_TYPE_WLR_BUFFER;
|
|
||||||
fb->wlr_buf = wlr_buffer_lock(buf);
|
fb->wlr_buf = wlr_buffer_lock(buf);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -413,17 +452,15 @@ struct gbm_bo *drm_fb_acquire(struct wlr_drm_fb *fb, struct wlr_drm_backend *drm
|
||||||
wlr_render_texture_with_matrix(renderer, tex, mat, 1.0f);
|
wlr_render_texture_with_matrix(renderer, tex, mat, 1.0f);
|
||||||
wlr_renderer_end(renderer);
|
wlr_renderer_end(renderer);
|
||||||
|
|
||||||
if (!wlr_egl_swap_buffers(&mgpu->renderer->egl, mgpu->egl, NULL)) {
|
struct wlr_drm_fb mgpu_fb = {
|
||||||
wlr_log(WLR_ERROR, "Failed to swap buffers");
|
.bo = fb->mgpu_bo,
|
||||||
return NULL;
|
.wlr_buf = fb->mgpu_wlr_buf,
|
||||||
|
};
|
||||||
|
if (!drm_fb_lock_surface(&mgpu_fb, mgpu)) {
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
fb->mgpu_bo = mgpu_fb.bo;
|
||||||
fb->mgpu_bo = gbm_surface_lock_front_buffer(mgpu->gbm);
|
fb->mgpu_wlr_buf = mgpu_fb.wlr_buf;
|
||||||
if (!fb->mgpu_bo) {
|
|
||||||
wlr_log(WLR_ERROR, "Failed to lock front buffer");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
fb->mgpu_surf = mgpu;
|
fb->mgpu_surf = mgpu;
|
||||||
return fb->mgpu_bo;
|
return fb->mgpu_bo;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -221,7 +221,7 @@ uint32_t get_fb_for_bo(struct gbm_bo *bo, bool with_modifiers) {
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool is_taken(size_t n, const uint32_t arr[static n], uint32_t key) {
|
static bool is_taken(size_t n, const uint32_t arr[static n], uint32_t key) {
|
||||||
for (size_t i = 0; i < n; ++i) {
|
for (size_t i = 0; i < n; ++i) {
|
||||||
if (arr[i] == key) {
|
if (arr[i] == key) {
|
||||||
return true;
|
return true;
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,20 @@
|
||||||
|
#define _POSIX_C_SOURCE 200809L
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <GLES2/gl2.h>
|
#include <drm_fourcc.h>
|
||||||
#include <GLES2/gl2ext.h>
|
#include <fcntl.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
#include <wlr/interfaces/wlr_input_device.h>
|
#include <wlr/interfaces/wlr_input_device.h>
|
||||||
#include <wlr/interfaces/wlr_output.h>
|
#include <wlr/interfaces/wlr_output.h>
|
||||||
#include <wlr/render/egl.h>
|
#include <wlr/render/egl.h>
|
||||||
|
#include <wlr/render/wlr_renderer.h>
|
||||||
|
#include <wlr/render/gles2.h>
|
||||||
#include <wlr/util/log.h>
|
#include <wlr/util/log.h>
|
||||||
|
#include <xf86drm.h>
|
||||||
#include "backend/headless.h"
|
#include "backend/headless.h"
|
||||||
|
#include "render/drm_format_set.h"
|
||||||
|
#include "render/gbm_allocator.h"
|
||||||
|
#include "render/wlr_renderer.h"
|
||||||
#include "util/signal.h"
|
#include "util/signal.h"
|
||||||
|
|
||||||
struct wlr_headless_backend *headless_backend_from_backend(
|
struct wlr_headless_backend *headless_backend_from_backend(
|
||||||
|
|
@ -62,10 +70,12 @@ static void backend_destroy(struct wlr_backend *wlr_backend) {
|
||||||
|
|
||||||
wlr_signal_emit_safe(&wlr_backend->events.destroy, backend);
|
wlr_signal_emit_safe(&wlr_backend->events.destroy, backend);
|
||||||
|
|
||||||
|
free(backend->format);
|
||||||
if (backend->egl == &backend->priv_egl) {
|
if (backend->egl == &backend->priv_egl) {
|
||||||
wlr_renderer_destroy(backend->renderer);
|
wlr_renderer_destroy(backend->renderer);
|
||||||
wlr_egl_finish(&backend->priv_egl);
|
wlr_egl_finish(&backend->priv_egl);
|
||||||
}
|
}
|
||||||
|
wlr_allocator_destroy(backend->allocator);
|
||||||
free(backend);
|
free(backend);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -95,26 +105,30 @@ static void handle_renderer_destroy(struct wl_listener *listener, void *data) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool backend_init(struct wlr_headless_backend *backend,
|
static bool backend_init(struct wlr_headless_backend *backend,
|
||||||
struct wl_display *display, struct wlr_renderer *renderer) {
|
struct wl_display *display, struct wlr_allocator *allocator,
|
||||||
|
struct wlr_renderer *renderer) {
|
||||||
wlr_backend_init(&backend->backend, &backend_impl);
|
wlr_backend_init(&backend->backend, &backend_impl);
|
||||||
backend->display = display;
|
backend->display = display;
|
||||||
wl_list_init(&backend->outputs);
|
wl_list_init(&backend->outputs);
|
||||||
wl_list_init(&backend->input_devices);
|
wl_list_init(&backend->input_devices);
|
||||||
|
|
||||||
|
backend->allocator = allocator;
|
||||||
backend->renderer = renderer;
|
backend->renderer = renderer;
|
||||||
backend->egl = wlr_gles2_renderer_get_egl(renderer);
|
backend->egl = wlr_gles2_renderer_get_egl(renderer);
|
||||||
|
|
||||||
if (wlr_gles2_renderer_check_ext(backend->renderer, "GL_OES_rgb8_rgba8") ||
|
const struct wlr_drm_format_set *formats =
|
||||||
wlr_gles2_renderer_check_ext(backend->renderer,
|
wlr_renderer_get_dmabuf_render_formats(backend->renderer);
|
||||||
"GL_OES_required_internalformat") ||
|
if (formats == NULL) {
|
||||||
wlr_gles2_renderer_check_ext(backend->renderer, "GL_ARM_rgba8")) {
|
wlr_log(WLR_ERROR, "Failed to get available DMA-BUF formats from renderer");
|
||||||
backend->internal_format = GL_RGBA8_OES;
|
return false;
|
||||||
} else {
|
|
||||||
wlr_log(WLR_INFO, "GL_RGBA8_OES not supported, "
|
|
||||||
"falling back to GL_RGBA4 internal format "
|
|
||||||
"(performance may be affected)");
|
|
||||||
backend->internal_format = GL_RGBA4;
|
|
||||||
}
|
}
|
||||||
|
const struct wlr_drm_format *format =
|
||||||
|
wlr_drm_format_set_get(formats, DRM_FORMAT_XRGB8888);
|
||||||
|
if (format == NULL) {
|
||||||
|
wlr_log(WLR_ERROR, "Renderer doesn't support XRGB8888");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
backend->format = wlr_drm_format_dup(format);
|
||||||
|
|
||||||
backend->display_destroy.notify = handle_display_destroy;
|
backend->display_destroy.notify = handle_display_destroy;
|
||||||
wl_display_add_destroy_listener(display, &backend->display_destroy);
|
wl_display_add_destroy_listener(display, &backend->display_destroy);
|
||||||
|
|
@ -124,68 +138,144 @@ static bool backend_init(struct wlr_headless_backend *backend,
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int open_drm_render_node(void) {
|
||||||
|
uint32_t flags = 0;
|
||||||
|
int devices_len = drmGetDevices2(flags, NULL, 0);
|
||||||
|
if (devices_len < 0) {
|
||||||
|
wlr_log(WLR_ERROR, "drmGetDevices2 failed");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
drmDevice **devices = calloc(devices_len, sizeof(drmDevice *));
|
||||||
|
if (devices == NULL) {
|
||||||
|
wlr_log_errno(WLR_ERROR, "Allocation failed");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
devices_len = drmGetDevices2(flags, devices, devices_len);
|
||||||
|
if (devices_len < 0) {
|
||||||
|
free(devices);
|
||||||
|
wlr_log(WLR_ERROR, "drmGetDevices2 failed");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int fd = -1;
|
||||||
|
for (int i = 0; i < devices_len; i++) {
|
||||||
|
drmDevice *dev = devices[i];
|
||||||
|
if (dev->available_nodes & (1 << DRM_NODE_RENDER)) {
|
||||||
|
const char *name = dev->nodes[DRM_NODE_RENDER];
|
||||||
|
wlr_log(WLR_DEBUG, "Opening DRM render node '%s'", name);
|
||||||
|
fd = open(name, O_RDWR | O_CLOEXEC);
|
||||||
|
if (fd < 0) {
|
||||||
|
wlr_log_errno(WLR_ERROR, "Failed to open '%s'", name);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (fd < 0) {
|
||||||
|
wlr_log(WLR_ERROR, "Failed to find any DRM render node");
|
||||||
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
|
for (int i = 0; i < devices_len; i++) {
|
||||||
|
drmFreeDevice(&devices[i]);
|
||||||
|
}
|
||||||
|
free(devices);
|
||||||
|
|
||||||
|
return fd;
|
||||||
|
}
|
||||||
|
|
||||||
struct wlr_backend *wlr_headless_backend_create(struct wl_display *display,
|
struct wlr_backend *wlr_headless_backend_create(struct wl_display *display,
|
||||||
wlr_renderer_create_func_t create_renderer_func) {
|
wlr_renderer_create_func_t create_renderer_func) {
|
||||||
wlr_log(WLR_INFO, "Creating headless backend");
|
wlr_log(WLR_INFO, "Creating headless backend");
|
||||||
|
|
||||||
|
int drm_fd = open_drm_render_node();
|
||||||
|
if (drm_fd < 0) {
|
||||||
|
wlr_log(WLR_ERROR, "Failed to open DRM render node");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct wlr_gbm_allocator *gbm_alloc = wlr_gbm_allocator_create(drm_fd);
|
||||||
|
if (gbm_alloc == NULL) {
|
||||||
|
wlr_log(WLR_ERROR, "Failed to create GBM allocator");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
struct wlr_headless_backend *backend =
|
struct wlr_headless_backend *backend =
|
||||||
calloc(1, sizeof(struct wlr_headless_backend));
|
calloc(1, sizeof(struct wlr_headless_backend));
|
||||||
if (!backend) {
|
if (!backend) {
|
||||||
wlr_log(WLR_ERROR, "Failed to allocate wlr_headless_backend");
|
wlr_log(WLR_ERROR, "Failed to allocate wlr_headless_backend");
|
||||||
return NULL;
|
goto error_backend;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const EGLint config_attribs[] = {
|
|
||||||
EGL_SURFACE_TYPE, 0,
|
|
||||||
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
|
|
||||||
EGL_BLUE_SIZE, 1,
|
|
||||||
EGL_GREEN_SIZE, 1,
|
|
||||||
EGL_RED_SIZE, 1,
|
|
||||||
EGL_NONE,
|
|
||||||
};
|
|
||||||
|
|
||||||
if (!create_renderer_func) {
|
if (!create_renderer_func) {
|
||||||
create_renderer_func = wlr_renderer_autocreate;
|
create_renderer_func = wlr_renderer_autocreate;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct wlr_renderer *renderer = create_renderer_func(&backend->priv_egl,
|
struct wlr_renderer *renderer = create_renderer_func(&backend->priv_egl,
|
||||||
EGL_PLATFORM_SURFACELESS_MESA, EGL_DEFAULT_DISPLAY,
|
EGL_PLATFORM_GBM_KHR, gbm_alloc->gbm_device, NULL, 0);
|
||||||
(EGLint*)config_attribs, 0);
|
|
||||||
if (!renderer) {
|
if (!renderer) {
|
||||||
wlr_log(WLR_ERROR, "Failed to create renderer");
|
wlr_log(WLR_ERROR, "Failed to create renderer");
|
||||||
free(backend);
|
goto error_renderer;
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!backend_init(backend, display, renderer)) {
|
if (!backend_init(backend, display, &gbm_alloc->base, renderer)) {
|
||||||
wlr_renderer_destroy(backend->renderer);
|
goto error_init;
|
||||||
free(backend);
|
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return &backend->backend;
|
return &backend->backend;
|
||||||
|
|
||||||
|
error_init:
|
||||||
|
wlr_renderer_destroy(renderer);
|
||||||
|
error_renderer:
|
||||||
|
free(backend);
|
||||||
|
error_backend:
|
||||||
|
wlr_allocator_destroy(&gbm_alloc->base);
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct wlr_backend *wlr_headless_backend_create_with_renderer(
|
struct wlr_backend *wlr_headless_backend_create_with_renderer(
|
||||||
struct wl_display *display, struct wlr_renderer *renderer) {
|
struct wl_display *display, struct wlr_renderer *renderer) {
|
||||||
wlr_log(WLR_INFO, "Creating headless backend");
|
wlr_log(WLR_INFO, "Creating headless backend with parent renderer");
|
||||||
|
|
||||||
|
int drm_fd = wlr_renderer_get_drm_fd(renderer);
|
||||||
|
if (drm_fd < 0) {
|
||||||
|
wlr_log(WLR_ERROR, "Failed to get DRM device FD from renderer");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
drm_fd = fcntl(drm_fd, F_DUPFD_CLOEXEC, 0);
|
||||||
|
if (drm_fd < 0) {
|
||||||
|
wlr_log_errno(WLR_ERROR, "fcntl(F_DUPFD_CLOEXEC) failed");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct wlr_gbm_allocator *gbm_alloc = wlr_gbm_allocator_create(drm_fd);
|
||||||
|
if (gbm_alloc == NULL) {
|
||||||
|
wlr_log(WLR_ERROR, "Failed to create GBM allocator");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
struct wlr_headless_backend *backend =
|
struct wlr_headless_backend *backend =
|
||||||
calloc(1, sizeof(struct wlr_headless_backend));
|
calloc(1, sizeof(struct wlr_headless_backend));
|
||||||
if (!backend) {
|
if (!backend) {
|
||||||
wlr_log(WLR_ERROR, "Failed to allocate wlr_headless_backend");
|
wlr_log(WLR_ERROR, "Failed to allocate wlr_headless_backend");
|
||||||
return NULL;
|
goto error_backend;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!backend_init(backend, display, renderer)) {
|
if (!backend_init(backend, display, &gbm_alloc->base, renderer)) {
|
||||||
free(backend);
|
goto error_init;
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
backend->renderer_destroy.notify = handle_renderer_destroy;
|
backend->renderer_destroy.notify = handle_renderer_destroy;
|
||||||
wl_signal_add(&renderer->events.destroy, &backend->renderer_destroy);
|
wl_signal_add(&renderer->events.destroy, &backend->renderer_destroy);
|
||||||
|
|
||||||
return &backend->backend;
|
return &backend->backend;
|
||||||
|
|
||||||
|
error_init:
|
||||||
|
free(backend);
|
||||||
|
error_backend:
|
||||||
|
wlr_allocator_destroy(&gbm_alloc->base);
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool wlr_backend_is_headless(struct wlr_backend *backend) {
|
bool wlr_backend_is_headless(struct wlr_backend *backend) {
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,12 @@
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <GLES2/gl2.h>
|
|
||||||
#include <GLES2/gl2ext.h>
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
#include <wlr/interfaces/wlr_output.h>
|
#include <wlr/interfaces/wlr_output.h>
|
||||||
#include <wlr/render/wlr_renderer.h>
|
#include <wlr/render/wlr_renderer.h>
|
||||||
#include <wlr/util/log.h>
|
#include <wlr/util/log.h>
|
||||||
#include "backend/headless.h"
|
#include "backend/headless.h"
|
||||||
|
#include "render/swapchain.h"
|
||||||
|
#include "render/wlr_renderer.h"
|
||||||
#include "util/signal.h"
|
#include "util/signal.h"
|
||||||
|
|
||||||
static struct wlr_headless_output *headless_output_from_output(
|
static struct wlr_headless_output *headless_output_from_output(
|
||||||
|
|
@ -14,53 +15,6 @@ static struct wlr_headless_output *headless_output_from_output(
|
||||||
return (struct wlr_headless_output *)wlr_output;
|
return (struct wlr_headless_output *)wlr_output;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool create_fbo(struct wlr_headless_output *output,
|
|
||||||
unsigned int width, unsigned int height) {
|
|
||||||
if (!wlr_egl_make_current(output->backend->egl, EGL_NO_SURFACE, NULL)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
GLuint rbo;
|
|
||||||
glGenRenderbuffers(1, &rbo);
|
|
||||||
glBindRenderbuffer(GL_RENDERBUFFER, rbo);
|
|
||||||
glRenderbufferStorage(GL_RENDERBUFFER, output->backend->internal_format,
|
|
||||||
width, height);
|
|
||||||
glBindRenderbuffer(GL_RENDERBUFFER, 0);
|
|
||||||
|
|
||||||
GLuint fbo;
|
|
||||||
glGenFramebuffers(1, &fbo);
|
|
||||||
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
|
|
||||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
|
|
||||||
GL_RENDERBUFFER, rbo);
|
|
||||||
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
|
|
||||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
|
||||||
|
|
||||||
wlr_egl_unset_current(output->backend->egl);
|
|
||||||
|
|
||||||
if (status != GL_FRAMEBUFFER_COMPLETE) {
|
|
||||||
wlr_log(WLR_ERROR, "Failed to create FBO");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
output->fbo = fbo;
|
|
||||||
output->rbo = rbo;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void destroy_fbo(struct wlr_headless_output *output) {
|
|
||||||
if (!wlr_egl_make_current(output->backend->egl, EGL_NO_SURFACE, NULL)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
glDeleteFramebuffers(1, &output->fbo);
|
|
||||||
glDeleteRenderbuffers(1, &output->rbo);
|
|
||||||
|
|
||||||
wlr_egl_unset_current(output->backend->egl);
|
|
||||||
|
|
||||||
output->fbo = 0;
|
|
||||||
output->rbo = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool output_set_custom_mode(struct wlr_output *wlr_output, int32_t width,
|
static bool output_set_custom_mode(struct wlr_output *wlr_output, int32_t width,
|
||||||
int32_t height, int32_t refresh) {
|
int32_t height, int32_t refresh) {
|
||||||
struct wlr_headless_output *output =
|
struct wlr_headless_output *output =
|
||||||
|
|
@ -70,8 +24,10 @@ static bool output_set_custom_mode(struct wlr_output *wlr_output, int32_t width,
|
||||||
refresh = HEADLESS_DEFAULT_REFRESH;
|
refresh = HEADLESS_DEFAULT_REFRESH;
|
||||||
}
|
}
|
||||||
|
|
||||||
destroy_fbo(output);
|
wlr_swapchain_destroy(output->swapchain);
|
||||||
if (!create_fbo(output, width, height)) {
|
output->swapchain = wlr_swapchain_create(output->backend->allocator,
|
||||||
|
width, height, output->backend->format);
|
||||||
|
if (!output->swapchain) {
|
||||||
wlr_output_destroy(wlr_output);
|
wlr_output_destroy(wlr_output);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
@ -87,15 +43,20 @@ static bool output_attach_render(struct wlr_output *wlr_output,
|
||||||
struct wlr_headless_output *output =
|
struct wlr_headless_output *output =
|
||||||
headless_output_from_output(wlr_output);
|
headless_output_from_output(wlr_output);
|
||||||
|
|
||||||
if (!wlr_egl_make_current(output->backend->egl, EGL_NO_SURFACE, NULL)) {
|
wlr_buffer_unlock(output->back_buffer);
|
||||||
|
output->back_buffer = wlr_swapchain_acquire(output->swapchain, buffer_age);
|
||||||
|
if (!output->back_buffer) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
glBindFramebuffer(GL_FRAMEBUFFER, output->fbo);
|
if (!wlr_egl_make_current(output->backend->egl, EGL_NO_SURFACE, NULL)) {
|
||||||
|
return false;
|
||||||
if (buffer_age != NULL) {
|
|
||||||
*buffer_age = 0; // We only have one buffer
|
|
||||||
}
|
}
|
||||||
|
if (!wlr_renderer_bind_buffer(output->backend->renderer,
|
||||||
|
output->back_buffer)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -130,10 +91,28 @@ static bool output_commit(struct wlr_output *wlr_output) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (wlr_output->pending.committed & WLR_OUTPUT_STATE_BUFFER) {
|
if (wlr_output->pending.committed & WLR_OUTPUT_STATE_BUFFER) {
|
||||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
struct wlr_buffer *buffer = NULL;
|
||||||
wlr_egl_unset_current(output->backend->egl);
|
switch (wlr_output->pending.buffer_type) {
|
||||||
|
case WLR_OUTPUT_STATE_BUFFER_RENDER:
|
||||||
|
assert(output->back_buffer != NULL);
|
||||||
|
|
||||||
|
wlr_renderer_bind_buffer(output->backend->renderer, NULL);
|
||||||
|
wlr_egl_unset_current(output->backend->egl);
|
||||||
|
|
||||||
|
buffer = output->back_buffer;
|
||||||
|
output->back_buffer = NULL;
|
||||||
|
break;
|
||||||
|
case WLR_OUTPUT_STATE_BUFFER_SCANOUT:
|
||||||
|
buffer = wlr_buffer_lock(wlr_output->pending.buffer);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
assert(buffer != NULL);
|
||||||
|
|
||||||
|
wlr_buffer_unlock(output->front_buffer);
|
||||||
|
output->front_buffer = buffer;
|
||||||
|
|
||||||
|
wlr_swapchain_set_buffer_submitted(output->swapchain, buffer);
|
||||||
|
|
||||||
// Nothing needs to be done for FBOs
|
|
||||||
wlr_output_send_present(wlr_output, NULL);
|
wlr_output_send_present(wlr_output, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -144,8 +123,29 @@ static void output_rollback_render(struct wlr_output *wlr_output) {
|
||||||
struct wlr_headless_output *output =
|
struct wlr_headless_output *output =
|
||||||
headless_output_from_output(wlr_output);
|
headless_output_from_output(wlr_output);
|
||||||
assert(wlr_egl_is_current(output->backend->egl));
|
assert(wlr_egl_is_current(output->backend->egl));
|
||||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
|
||||||
|
wlr_renderer_bind_buffer(output->backend->renderer, NULL);
|
||||||
wlr_egl_unset_current(output->backend->egl);
|
wlr_egl_unset_current(output->backend->egl);
|
||||||
|
|
||||||
|
wlr_buffer_unlock(output->back_buffer);
|
||||||
|
output->back_buffer = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool output_export_dmabuf(struct wlr_output *wlr_output,
|
||||||
|
struct wlr_dmabuf_attributes *attribs) {
|
||||||
|
struct wlr_headless_output *output =
|
||||||
|
headless_output_from_output(wlr_output);
|
||||||
|
|
||||||
|
if (!output->front_buffer) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct wlr_dmabuf_attributes tmp;
|
||||||
|
if (!wlr_buffer_get_dmabuf(output->front_buffer, &tmp)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return wlr_dmabuf_attributes_copy(attribs, &tmp);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void output_destroy(struct wlr_output *wlr_output) {
|
static void output_destroy(struct wlr_output *wlr_output) {
|
||||||
|
|
@ -153,7 +153,9 @@ static void output_destroy(struct wlr_output *wlr_output) {
|
||||||
headless_output_from_output(wlr_output);
|
headless_output_from_output(wlr_output);
|
||||||
wl_list_remove(&output->link);
|
wl_list_remove(&output->link);
|
||||||
wl_event_source_remove(output->frame_timer);
|
wl_event_source_remove(output->frame_timer);
|
||||||
destroy_fbo(output);
|
wlr_swapchain_destroy(output->swapchain);
|
||||||
|
wlr_buffer_unlock(output->back_buffer);
|
||||||
|
wlr_buffer_unlock(output->front_buffer);
|
||||||
free(output);
|
free(output);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -162,6 +164,7 @@ static const struct wlr_output_impl output_impl = {
|
||||||
.attach_render = output_attach_render,
|
.attach_render = output_attach_render,
|
||||||
.commit = output_commit,
|
.commit = output_commit,
|
||||||
.rollback_render = output_rollback_render,
|
.rollback_render = output_rollback_render,
|
||||||
|
.export_dmabuf = output_export_dmabuf,
|
||||||
};
|
};
|
||||||
|
|
||||||
bool wlr_output_is_headless(struct wlr_output *wlr_output) {
|
bool wlr_output_is_headless(struct wlr_output *wlr_output) {
|
||||||
|
|
@ -191,7 +194,9 @@ struct wlr_output *wlr_headless_add_output(struct wlr_backend *wlr_backend,
|
||||||
backend->display);
|
backend->display);
|
||||||
struct wlr_output *wlr_output = &output->wlr_output;
|
struct wlr_output *wlr_output = &output->wlr_output;
|
||||||
|
|
||||||
if (!create_fbo(output, width, height)) {
|
output->swapchain = wlr_swapchain_create(backend->allocator,
|
||||||
|
width, height, backend->format);
|
||||||
|
if (!output->swapchain) {
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -206,14 +211,6 @@ struct wlr_output *wlr_headless_add_output(struct wlr_backend *wlr_backend,
|
||||||
"Headless output %zd", backend->last_output_num);
|
"Headless output %zd", backend->last_output_num);
|
||||||
wlr_output_set_description(wlr_output, description);
|
wlr_output_set_description(wlr_output, description);
|
||||||
|
|
||||||
if (!output_attach_render(wlr_output, NULL)) {
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
wlr_renderer_begin(backend->renderer, wlr_output->width, wlr_output->height);
|
|
||||||
wlr_renderer_clear(backend->renderer, (float[]){ 1.0, 1.0, 1.0, 1.0 });
|
|
||||||
wlr_renderer_end(backend->renderer);
|
|
||||||
|
|
||||||
struct wl_event_loop *ev = wl_display_get_event_loop(backend->display);
|
struct wl_event_loop *ev = wl_display_get_event_loop(backend->display);
|
||||||
output->frame_timer = wl_event_loop_add_timer(ev, signal_frame, output);
|
output->frame_timer = wl_event_loop_add_timer(ev, signal_frame, output);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <libinput.h>
|
#include <libinput.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
#include <wlr/backend/interface.h>
|
#include <wlr/backend/interface.h>
|
||||||
#include <wlr/backend/session.h>
|
#include <wlr/backend/session.h>
|
||||||
#include <wlr/util/log.h>
|
#include <wlr/util/log.h>
|
||||||
|
|
@ -16,12 +17,27 @@ static struct wlr_libinput_backend *get_libinput_backend_from_backend(
|
||||||
static int libinput_open_restricted(const char *path,
|
static int libinput_open_restricted(const char *path,
|
||||||
int flags, void *_backend) {
|
int flags, void *_backend) {
|
||||||
struct wlr_libinput_backend *backend = _backend;
|
struct wlr_libinput_backend *backend = _backend;
|
||||||
return wlr_session_open_file(backend->session, path);
|
struct wlr_device *dev = wlr_session_open_file(backend->session, path);
|
||||||
|
if (dev == NULL) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return dev->fd;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void libinput_close_restricted(int fd, void *_backend) {
|
static void libinput_close_restricted(int fd, void *_backend) {
|
||||||
struct wlr_libinput_backend *backend = _backend;
|
struct wlr_libinput_backend *backend = _backend;
|
||||||
wlr_session_close_file(backend->session, fd);
|
|
||||||
|
struct wlr_device *dev;
|
||||||
|
bool found = false;
|
||||||
|
wl_list_for_each(dev, &backend->session->devices, link) {
|
||||||
|
if (dev->fd == fd) {
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (found) {
|
||||||
|
wlr_session_close_file(backend->session, dev);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct libinput_interface libinput_impl = {
|
static const struct libinput_interface libinput_impl = {
|
||||||
|
|
@ -44,9 +60,24 @@ static int handle_libinput_readable(int fd, uint32_t mask, void *_backend) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static enum wlr_log_importance libinput_log_priority_to_wlr(
|
||||||
|
enum libinput_log_priority priority) {
|
||||||
|
switch (priority) {
|
||||||
|
case LIBINPUT_LOG_PRIORITY_ERROR:
|
||||||
|
return WLR_ERROR;
|
||||||
|
case LIBINPUT_LOG_PRIORITY_INFO:
|
||||||
|
return WLR_INFO;
|
||||||
|
default:
|
||||||
|
return WLR_DEBUG;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void log_libinput(struct libinput *libinput_context,
|
static void log_libinput(struct libinput *libinput_context,
|
||||||
enum libinput_log_priority priority, const char *fmt, va_list args) {
|
enum libinput_log_priority priority, const char *fmt, va_list args) {
|
||||||
_wlr_vlog(WLR_ERROR, fmt, args);
|
enum wlr_log_importance importance = libinput_log_priority_to_wlr(priority);
|
||||||
|
static char wlr_fmt[1024];
|
||||||
|
snprintf(wlr_fmt, sizeof(wlr_fmt), "[libinput] %s", fmt);
|
||||||
|
_wlr_vlog(importance, wlr_fmt, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool backend_start(struct wlr_backend *wlr_backend) {
|
static bool backend_start(struct wlr_backend *wlr_backend) {
|
||||||
|
|
@ -144,7 +175,7 @@ bool wlr_backend_is_libinput(struct wlr_backend *b) {
|
||||||
static void session_signal(struct wl_listener *listener, void *data) {
|
static void session_signal(struct wl_listener *listener, void *data) {
|
||||||
struct wlr_libinput_backend *backend =
|
struct wlr_libinput_backend *backend =
|
||||||
wl_container_of(listener, backend, session_signal);
|
wl_container_of(listener, backend, session_signal);
|
||||||
struct wlr_session *session = data;
|
struct wlr_session *session = backend->session;
|
||||||
|
|
||||||
if (!backend->libinput_context) {
|
if (!backend->libinput_context) {
|
||||||
return;
|
return;
|
||||||
|
|
@ -188,7 +219,7 @@ struct wlr_backend *wlr_libinput_backend_create(struct wl_display *display,
|
||||||
backend->display = display;
|
backend->display = display;
|
||||||
|
|
||||||
backend->session_signal.notify = session_signal;
|
backend->session_signal.notify = session_signal;
|
||||||
wl_signal_add(&session->session_signal, &backend->session_signal);
|
wl_signal_add(&session->events.active, &backend->session_signal);
|
||||||
|
|
||||||
backend->session_destroy.notify = handle_session_destroy;
|
backend->session_destroy.notify = handle_session_destroy;
|
||||||
wl_signal_add(&session->events.destroy, &backend->session_destroy);
|
wl_signal_add(&session->events.destroy, &backend->session_destroy);
|
||||||
|
|
|
||||||
|
|
@ -72,10 +72,10 @@ void handle_keyboard_key(struct libinput_event *event,
|
||||||
libinput_event_keyboard_get_key_state(kbevent);
|
libinput_event_keyboard_get_key_state(kbevent);
|
||||||
switch (state) {
|
switch (state) {
|
||||||
case LIBINPUT_KEY_STATE_RELEASED:
|
case LIBINPUT_KEY_STATE_RELEASED:
|
||||||
wlr_event.state = WLR_KEY_RELEASED;
|
wlr_event.state = WL_KEYBOARD_KEY_STATE_RELEASED;
|
||||||
break;
|
break;
|
||||||
case LIBINPUT_KEY_STATE_PRESSED:
|
case LIBINPUT_KEY_STATE_PRESSED:
|
||||||
wlr_event.state = WLR_KEY_PRESSED;
|
wlr_event.state = WL_KEYBOARD_KEY_STATE_PRESSED;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
wlr_event.update_state = true;
|
wlr_event.update_state = true;
|
||||||
|
|
|
||||||
|
|
@ -113,10 +113,8 @@ static enum wlr_tablet_tool_type wlr_type_from_libinput_type(
|
||||||
return WLR_TABLET_TOOL_TYPE_MOUSE;
|
return WLR_TABLET_TOOL_TYPE_MOUSE;
|
||||||
case LIBINPUT_TABLET_TOOL_TYPE_LENS:
|
case LIBINPUT_TABLET_TOOL_TYPE_LENS:
|
||||||
return WLR_TABLET_TOOL_TYPE_LENS;
|
return WLR_TABLET_TOOL_TYPE_LENS;
|
||||||
#if LIBINPUT_MINOR >= 14
|
|
||||||
case LIBINPUT_TABLET_TOOL_TYPE_TOTEM:
|
case LIBINPUT_TABLET_TOOL_TYPE_TOTEM:
|
||||||
return WLR_TABLET_TOOL_TYPE_TOTEM;
|
return WLR_TABLET_TOOL_TYPE_TOTEM;
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
abort(); // unreachable
|
abort(); // unreachable
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@
|
||||||
#include <wlr/util/log.h>
|
#include <wlr/util/log.h>
|
||||||
#include <xf86drm.h>
|
#include <xf86drm.h>
|
||||||
#include "backend/session/direct-ipc.h"
|
#include "backend/session/direct-ipc.h"
|
||||||
|
#include "backend/session/session.h"
|
||||||
#include "util/signal.h"
|
#include "util/signal.h"
|
||||||
|
|
||||||
const struct session_impl session_direct;
|
const struct session_impl session_direct;
|
||||||
|
|
@ -114,7 +115,7 @@ static int vt_handler(int signo, void *data) {
|
||||||
|
|
||||||
if (session->base.active) {
|
if (session->base.active) {
|
||||||
session->base.active = false;
|
session->base.active = false;
|
||||||
wlr_signal_emit_safe(&session->base.session_signal, session);
|
wlr_signal_emit_safe(&session->base.events.active, NULL);
|
||||||
|
|
||||||
wl_list_for_each(dev, &session->base.devices, link) {
|
wl_list_for_each(dev, &session->base.devices, link) {
|
||||||
if (ioctl(dev->fd, DRM_IOCTL_VERSION, &dv) == 0) {
|
if (ioctl(dev->fd, DRM_IOCTL_VERSION, &dv) == 0) {
|
||||||
|
|
@ -133,7 +134,7 @@ static int vt_handler(int signo, void *data) {
|
||||||
}
|
}
|
||||||
|
|
||||||
session->base.active = true;
|
session->base.active = true;
|
||||||
wlr_signal_emit_safe(&session->base.session_signal, session);
|
wlr_signal_emit_safe(&session->base.events.active, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
|
|
@ -274,6 +275,7 @@ static struct wlr_session *direct_session_create(struct wl_display *disp) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
session_init(&session->base);
|
||||||
session->sock = direct_ipc_init(&session->child);
|
session->sock = direct_ipc_init(&session->child);
|
||||||
if (session->sock == -1) {
|
if (session->sock == -1) {
|
||||||
goto error_session;
|
goto error_session;
|
||||||
|
|
@ -297,6 +299,7 @@ static struct wlr_session *direct_session_create(struct wl_display *disp) {
|
||||||
|
|
||||||
snprintf(session->base.seat, sizeof(session->base.seat), "%s", seat);
|
snprintf(session->base.seat, sizeof(session->base.seat), "%s", seat);
|
||||||
session->base.impl = &session_direct;
|
session->base.impl = &session_direct;
|
||||||
|
session->base.active = true;
|
||||||
return &session->base;
|
return &session->base;
|
||||||
|
|
||||||
error_ipc:
|
error_ipc:
|
||||||
|
|
|
||||||
|
|
@ -24,16 +24,6 @@
|
||||||
|
|
||||||
enum { DRM_MAJOR = 226 };
|
enum { DRM_MAJOR = 226 };
|
||||||
|
|
||||||
static bool have_permissions(void) {
|
|
||||||
#ifdef __linux__
|
|
||||||
if (geteuid() != 0) {
|
|
||||||
wlr_log(WLR_ERROR, "Do not have root privileges; cannot become DRM master");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void send_msg(int sock, int fd, void *buf, size_t buf_len) {
|
static void send_msg(int sock, int fd, void *buf, size_t buf_len) {
|
||||||
char control[CMSG_SPACE(sizeof(fd))] = {0};
|
char control[CMSG_SPACE(sizeof(fd))] = {0};
|
||||||
struct iovec iovec = { .iov_base = buf, .iov_len = buf_len };
|
struct iovec iovec = { .iov_base = buf, .iov_len = buf_len };
|
||||||
|
|
@ -223,10 +213,6 @@ void direct_ipc_finish(int sock, pid_t pid) {
|
||||||
}
|
}
|
||||||
|
|
||||||
int direct_ipc_init(pid_t *pid_out) {
|
int direct_ipc_init(pid_t *pid_out) {
|
||||||
if (!have_permissions()) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int sock[2];
|
int sock[2];
|
||||||
if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, sock) < 0) {
|
if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, sock) < 0) {
|
||||||
wlr_log_errno(WLR_ERROR, "Failed to create socket pair");
|
wlr_log_errno(WLR_ERROR, "Failed to create socket pair");
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@
|
||||||
#include <wlr/backend/session/interface.h>
|
#include <wlr/backend/session/interface.h>
|
||||||
#include <wlr/util/log.h>
|
#include <wlr/util/log.h>
|
||||||
#include "backend/session/direct-ipc.h"
|
#include "backend/session/direct-ipc.h"
|
||||||
|
#include "backend/session/session.h"
|
||||||
#include "util/signal.h"
|
#include "util/signal.h"
|
||||||
|
|
||||||
enum { DRM_MAJOR = 226 };
|
enum { DRM_MAJOR = 226 };
|
||||||
|
|
@ -125,7 +126,7 @@ static int vt_handler(int signo, void *data) {
|
||||||
|
|
||||||
if (session->base.active) {
|
if (session->base.active) {
|
||||||
session->base.active = false;
|
session->base.active = false;
|
||||||
wlr_signal_emit_safe(&session->base.session_signal, session);
|
wlr_signal_emit_safe(&session->base.events.active, NULL);
|
||||||
|
|
||||||
struct wlr_device *dev;
|
struct wlr_device *dev;
|
||||||
wl_list_for_each(dev, &session->base.devices, link) {
|
wl_list_for_each(dev, &session->base.devices, link) {
|
||||||
|
|
@ -148,7 +149,7 @@ static int vt_handler(int signo, void *data) {
|
||||||
}
|
}
|
||||||
|
|
||||||
session->base.active = true;
|
session->base.active = true;
|
||||||
wlr_signal_emit_safe(&session->base.session_signal, session);
|
wlr_signal_emit_safe(&session->base.events.active, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
|
|
@ -246,6 +247,7 @@ static struct wlr_session *direct_session_create(struct wl_display *disp) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
session_init(&session->base);
|
||||||
session->sock = direct_ipc_init(&session->child);
|
session->sock = direct_ipc_init(&session->child);
|
||||||
if (session->sock == -1) {
|
if (session->sock == -1) {
|
||||||
goto error_session;
|
goto error_session;
|
||||||
|
|
@ -267,6 +269,7 @@ static struct wlr_session *direct_session_create(struct wl_display *disp) {
|
||||||
|
|
||||||
snprintf(session->base.seat, sizeof(session->base.seat), "%s", seat);
|
snprintf(session->base.seat, sizeof(session->base.seat), "%s", seat);
|
||||||
session->base.impl = &session_direct;
|
session->base.impl = &session_direct;
|
||||||
|
session->base.active = true;
|
||||||
|
|
||||||
wlr_log(WLR_INFO, "Successfully loaded direct session");
|
wlr_log(WLR_INFO, "Successfully loaded direct session");
|
||||||
return &session->base;
|
return &session->base;
|
||||||
|
|
|
||||||
218
backend/session/libseat.c
Normal file
218
backend/session/libseat.c
Normal file
|
|
@ -0,0 +1,218 @@
|
||||||
|
#define _POSIX_C_SOURCE 200809L
|
||||||
|
#include <assert.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <wayland-server-core.h>
|
||||||
|
#include <wlr/backend/session/interface.h>
|
||||||
|
#include <wlr/config.h>
|
||||||
|
#include <wlr/util/log.h>
|
||||||
|
#include "backend/session/session.h"
|
||||||
|
#include "util/signal.h"
|
||||||
|
|
||||||
|
#include <libseat.h>
|
||||||
|
|
||||||
|
const struct session_impl session_libseat;
|
||||||
|
|
||||||
|
struct libseat_device {
|
||||||
|
struct wl_list link;
|
||||||
|
int fd;
|
||||||
|
int device_id;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct libseat_session {
|
||||||
|
struct wlr_session base;
|
||||||
|
|
||||||
|
struct libseat *seat;
|
||||||
|
struct wl_event_source *event;
|
||||||
|
struct wl_list devices;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void handle_enable_seat(struct libseat *seat, void *data) {
|
||||||
|
struct libseat_session *session = data;
|
||||||
|
session->base.active = true;
|
||||||
|
wlr_signal_emit_safe(&session->base.events.active, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handle_disable_seat(struct libseat *seat, void *data) {
|
||||||
|
struct libseat_session *session = data;
|
||||||
|
session->base.active = false;
|
||||||
|
wlr_signal_emit_safe(&session->base.events.active, NULL);
|
||||||
|
libseat_disable_seat(session->seat);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int libseat_event(int fd, uint32_t mask, void *data) {
|
||||||
|
struct libseat *seat = data;
|
||||||
|
libseat_dispatch(seat, 0);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct libseat_seat_listener seat_listener = {
|
||||||
|
.enable_seat = handle_enable_seat,
|
||||||
|
.disable_seat = handle_disable_seat,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct libseat_session *libseat_session_from_session(
|
||||||
|
struct wlr_session *base) {
|
||||||
|
assert(base->impl == &session_libseat);
|
||||||
|
return (struct libseat_session *)base;
|
||||||
|
}
|
||||||
|
|
||||||
|
static enum wlr_log_importance libseat_log_level_to_wlr(
|
||||||
|
enum libseat_log_level level) {
|
||||||
|
switch (level) {
|
||||||
|
case LIBSEAT_LOG_LEVEL_ERROR:
|
||||||
|
return WLR_ERROR;
|
||||||
|
case LIBSEAT_LOG_LEVEL_INFO:
|
||||||
|
return WLR_INFO;
|
||||||
|
default:
|
||||||
|
return WLR_DEBUG;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void log_libseat(enum libseat_log_level level,
|
||||||
|
const char *fmt, va_list args) {
|
||||||
|
enum wlr_log_importance importance = libseat_log_level_to_wlr(level);
|
||||||
|
|
||||||
|
static char wlr_fmt[1024];
|
||||||
|
snprintf(wlr_fmt, sizeof(wlr_fmt), "[libseat] %s", fmt);
|
||||||
|
|
||||||
|
_wlr_vlog(importance, wlr_fmt, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct wlr_session *libseat_session_create(struct wl_display *disp) {
|
||||||
|
struct libseat_session *session = calloc(1, sizeof(*session));
|
||||||
|
if (!session) {
|
||||||
|
wlr_log_errno(WLR_ERROR, "Allocation failed");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
session_init(&session->base);
|
||||||
|
wl_list_init(&session->devices);
|
||||||
|
|
||||||
|
libseat_set_log_handler(log_libseat);
|
||||||
|
libseat_set_log_level(LIBSEAT_LOG_LEVEL_ERROR);
|
||||||
|
|
||||||
|
// libseat will take care of updating the logind state if necessary
|
||||||
|
setenv("XDG_SESSION_TYPE", "wayland", 1);
|
||||||
|
|
||||||
|
session->seat = libseat_open_seat(&seat_listener, session);
|
||||||
|
if (session->seat == NULL) {
|
||||||
|
wlr_log_errno(WLR_ERROR, "Unable to create seat");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *seat_name = libseat_seat_name(session->seat);
|
||||||
|
if (seat_name == NULL) {
|
||||||
|
wlr_log_errno(WLR_ERROR, "Unable to get seat info");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
snprintf(session->base.seat, sizeof(session->base.seat), "%s", seat_name);
|
||||||
|
|
||||||
|
struct wl_event_loop *event_loop = wl_display_get_event_loop(disp);
|
||||||
|
session->event = wl_event_loop_add_fd(event_loop, libseat_get_fd(session->seat),
|
||||||
|
WL_EVENT_READABLE, libseat_event, session->seat);
|
||||||
|
if (session->event == NULL) {
|
||||||
|
wlr_log(WLR_ERROR, "Failed to create libseat event source");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We may have received enable_seat immediately after the open_seat result,
|
||||||
|
// so, dispatch once without timeout to speed up activation.
|
||||||
|
if (libseat_dispatch(session->seat, 0) == -1) {
|
||||||
|
wlr_log_errno(WLR_ERROR, "libseat dispatch failed");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
wlr_log(WLR_INFO, "Successfully loaded libseat session");
|
||||||
|
session->base.impl = &session_libseat;
|
||||||
|
return &session->base;
|
||||||
|
|
||||||
|
error:
|
||||||
|
if (session->seat != NULL) {
|
||||||
|
libseat_close_seat(session->seat);
|
||||||
|
}
|
||||||
|
if (session->event != NULL) {
|
||||||
|
wl_event_source_remove(session->event);
|
||||||
|
}
|
||||||
|
free(session);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void libseat_session_destroy(struct wlr_session *base) {
|
||||||
|
struct libseat_session *session = libseat_session_from_session(base);
|
||||||
|
|
||||||
|
libseat_close_seat(session->seat);
|
||||||
|
wl_event_source_remove(session->event);
|
||||||
|
free(session);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct libseat_device *find_device_by_fd(struct libseat_session *session, int fd) {
|
||||||
|
struct libseat_device *dev;
|
||||||
|
wl_list_for_each(dev, &session->devices, link) {
|
||||||
|
if (dev->fd == fd) {
|
||||||
|
return dev;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int libseat_session_open_device(struct wlr_session *base, const char *path) {
|
||||||
|
struct libseat_session *session = libseat_session_from_session(base);
|
||||||
|
|
||||||
|
int fd;
|
||||||
|
int device_id = libseat_open_device(session->seat, path, &fd);
|
||||||
|
if (device_id == -1) {
|
||||||
|
wlr_log_errno(WLR_ERROR, "Failed to open device '%s'", path);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct libseat_device *dev = calloc(1, sizeof(struct libseat_device));
|
||||||
|
if (dev == NULL) {
|
||||||
|
wlr_log_errno(WLR_ERROR, "Allocation failed");
|
||||||
|
libseat_close_device(session->seat, device_id);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
dev->fd = fd;
|
||||||
|
dev->device_id = device_id;
|
||||||
|
wl_list_insert(&session->devices, &dev->link);
|
||||||
|
|
||||||
|
return fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void libseat_session_close_device(struct wlr_session *base, int fd) {
|
||||||
|
struct libseat_session *session = libseat_session_from_session(base);
|
||||||
|
|
||||||
|
struct libseat_device *dev = find_device_by_fd(session, fd);
|
||||||
|
if (dev == NULL) {
|
||||||
|
wlr_log(WLR_ERROR, "No device with fd %d found", fd);
|
||||||
|
close(fd);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (libseat_close_device(session->seat, dev->device_id) == -1) {
|
||||||
|
wlr_log_errno(WLR_ERROR, "Failed to close device %d", dev->device_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
wl_list_remove(&dev->link);
|
||||||
|
free(dev);
|
||||||
|
close(fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool libseat_change_vt(struct wlr_session *base, unsigned vt) {
|
||||||
|
struct libseat_session *session = libseat_session_from_session(base);
|
||||||
|
return libseat_switch_session(session->seat, vt) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const struct session_impl session_libseat = {
|
||||||
|
.create = libseat_session_create,
|
||||||
|
.destroy = libseat_session_destroy,
|
||||||
|
.open = libseat_session_open_device,
|
||||||
|
.close = libseat_session_close_device,
|
||||||
|
.change_vt = libseat_change_vt,
|
||||||
|
};
|
||||||
|
|
@ -13,6 +13,7 @@
|
||||||
#include <wlr/backend/session/interface.h>
|
#include <wlr/backend/session/interface.h>
|
||||||
#include <wlr/config.h>
|
#include <wlr/config.h>
|
||||||
#include <wlr/util/log.h>
|
#include <wlr/util/log.h>
|
||||||
|
#include "backend/session/session.h"
|
||||||
#include "util/signal.h"
|
#include "util/signal.h"
|
||||||
|
|
||||||
#if WLR_HAS_SYSTEMD
|
#if WLR_HAS_SYSTEMD
|
||||||
|
|
@ -35,9 +36,7 @@ struct logind_session {
|
||||||
|
|
||||||
char *id;
|
char *id;
|
||||||
char *path;
|
char *path;
|
||||||
char *seat_path;
|
|
||||||
|
|
||||||
bool can_graphical;
|
|
||||||
// specifies whether a drm device was taken
|
// specifies whether a drm device was taken
|
||||||
// if so, the session will be (de)activated with the drm fd,
|
// if so, the session will be (de)activated with the drm fd,
|
||||||
// otherwise with the dbus PropertiesChanged on "active" signal
|
// otherwise with the dbus PropertiesChanged on "active" signal
|
||||||
|
|
@ -129,8 +128,8 @@ static void logind_release_device(struct wlr_session *base, int fd) {
|
||||||
static bool logind_change_vt(struct wlr_session *base, unsigned vt) {
|
static bool logind_change_vt(struct wlr_session *base, unsigned vt) {
|
||||||
struct logind_session *session = logind_session_from_session(base);
|
struct logind_session *session = logind_session_from_session(base);
|
||||||
|
|
||||||
// Only seat0 has VTs associated with it
|
// Only if seat has VTs associated with it
|
||||||
if (strcmp(session->base.seat, "seat0") != 0) {
|
if (!sd_seat_can_tty(session->base.seat)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -142,7 +141,7 @@ static bool logind_change_vt(struct wlr_session *base, unsigned vt) {
|
||||||
"/org/freedesktop/login1/seat/seat0", "org.freedesktop.login1.Seat", "SwitchTo",
|
"/org/freedesktop/login1/seat/seat0", "org.freedesktop.login1.Seat", "SwitchTo",
|
||||||
&error, &msg, "u", (uint32_t)vt);
|
&error, &msg, "u", (uint32_t)vt);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
wlr_log(WLR_ERROR, "Failed to change to vt '%d'", vt);
|
wlr_log(WLR_ERROR, "Failed to change to vt '%u'", vt);
|
||||||
}
|
}
|
||||||
|
|
||||||
sd_bus_error_free(&error);
|
sd_bus_error_free(&error);
|
||||||
|
|
@ -178,34 +177,6 @@ out:
|
||||||
return ret >= 0;
|
return ret >= 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool find_seat_path(struct logind_session *session) {
|
|
||||||
int ret;
|
|
||||||
sd_bus_message *msg = NULL;
|
|
||||||
sd_bus_error error = SD_BUS_ERROR_NULL;
|
|
||||||
|
|
||||||
ret = sd_bus_call_method(session->bus, "org.freedesktop.login1",
|
|
||||||
"/org/freedesktop/login1", "org.freedesktop.login1.Manager",
|
|
||||||
"GetSeat", &error, &msg, "s", session->base.seat);
|
|
||||||
if (ret < 0) {
|
|
||||||
wlr_log(WLR_ERROR, "Failed to get seat path: %s", error.message);
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
const char *path;
|
|
||||||
ret = sd_bus_message_read(msg, "o", &path);
|
|
||||||
if (ret < 0) {
|
|
||||||
wlr_log(WLR_ERROR, "Could not parse seat path: %s", error.message);
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
session->seat_path = strdup(path);
|
|
||||||
|
|
||||||
out:
|
|
||||||
sd_bus_error_free(&error);
|
|
||||||
sd_bus_message_unref(msg);
|
|
||||||
|
|
||||||
return ret >= 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool session_activate(struct logind_session *session) {
|
static bool session_activate(struct logind_session *session) {
|
||||||
int ret;
|
int ret;
|
||||||
sd_bus_message *msg = NULL;
|
sd_bus_message *msg = NULL;
|
||||||
|
|
@ -241,6 +212,32 @@ static bool take_control(struct logind_session *session) {
|
||||||
return ret >= 0;
|
return ret >= 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void set_type(struct logind_session *session) {
|
||||||
|
int ret;
|
||||||
|
sd_bus_message *msg = NULL;
|
||||||
|
sd_bus_error error = SD_BUS_ERROR_NULL;
|
||||||
|
|
||||||
|
ret = sd_bus_call_method(session->bus, "org.freedesktop.login1",
|
||||||
|
session->path, "org.freedesktop.login1.Session", "SetType",
|
||||||
|
&error, &msg, "s", "wayland");
|
||||||
|
if (ret < 0) {
|
||||||
|
wlr_log(WLR_DEBUG, "Failed to set logind session type for session: %s",
|
||||||
|
error.message);
|
||||||
|
}
|
||||||
|
|
||||||
|
sd_bus_error_free(&error);
|
||||||
|
sd_bus_message_unref(msg);
|
||||||
|
|
||||||
|
if (ret < 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = setenv("XDG_SESSION_TYPE", "wayland", 1);
|
||||||
|
if (ret < 0) {
|
||||||
|
wlr_log(WLR_ERROR, "Failed to set XDG_SESSION_TYPE for session");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void release_control(struct logind_session *session) {
|
static void release_control(struct logind_session *session) {
|
||||||
int ret;
|
int ret;
|
||||||
sd_bus_message *msg = NULL;
|
sd_bus_message *msg = NULL;
|
||||||
|
|
@ -267,7 +264,6 @@ static void logind_session_destroy(struct wlr_session *base) {
|
||||||
sd_bus_unref(session->bus);
|
sd_bus_unref(session->bus);
|
||||||
free(session->id);
|
free(session->id);
|
||||||
free(session->path);
|
free(session->path);
|
||||||
free(session->seat_path);
|
|
||||||
free(session);
|
free(session);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -310,7 +306,7 @@ static int pause_device(sd_bus_message *msg, void *userdata,
|
||||||
if (major == DRM_MAJOR && strcmp(type, "gone") != 0) {
|
if (major == DRM_MAJOR && strcmp(type, "gone") != 0) {
|
||||||
assert(session->has_drm);
|
assert(session->has_drm);
|
||||||
session->base.active = false;
|
session->base.active = false;
|
||||||
wlr_signal_emit_safe(&session->base.session_signal, session);
|
wlr_signal_emit_safe(&session->base.events.active, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strcmp(type, "pause") == 0) {
|
if (strcmp(type, "pause") == 0) {
|
||||||
|
|
@ -352,7 +348,7 @@ static int resume_device(sd_bus_message *msg, void *userdata,
|
||||||
|
|
||||||
if (!session->base.active) {
|
if (!session->base.active) {
|
||||||
session->base.active = true;
|
session->base.active = true;
|
||||||
wlr_signal_emit_safe(&session->base.session_signal, session);
|
wlr_signal_emit_safe(&session->base.events.active, NULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -411,7 +407,7 @@ static int session_properties_changed(sd_bus_message *msg, void *userdata,
|
||||||
|
|
||||||
if (session->base.active != active) {
|
if (session->base.active != active) {
|
||||||
session->base.active = active;
|
session->base.active = active;
|
||||||
wlr_signal_emit_safe(&session->base.session_signal, session);
|
wlr_signal_emit_safe(&session->base.events.active, NULL);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -451,7 +447,7 @@ static int session_properties_changed(sd_bus_message *msg, void *userdata,
|
||||||
|
|
||||||
if (session->base.active != active) {
|
if (session->base.active != active) {
|
||||||
session->base.active = active;
|
session->base.active = active;
|
||||||
wlr_signal_emit_safe(&session->base.session_signal, session);
|
wlr_signal_emit_safe(&session->base.events.active, NULL);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -469,95 +465,6 @@ error:
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int seat_properties_changed(sd_bus_message *msg, void *userdata,
|
|
||||||
sd_bus_error *ret_error) {
|
|
||||||
struct logind_session *session = userdata;
|
|
||||||
int ret = 0;
|
|
||||||
|
|
||||||
// if we have a drm fd we don't depend on this
|
|
||||||
if (session->has_drm) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// PropertiesChanged arg 1: interface
|
|
||||||
const char *interface;
|
|
||||||
ret = sd_bus_message_read_basic(msg, 's', &interface); // skip path
|
|
||||||
if (ret < 0) {
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (strcmp(interface, "org.freedesktop.login1.Seat") != 0) {
|
|
||||||
// not interesting for us; ignore
|
|
||||||
wlr_log(WLR_DEBUG, "ignoring PropertiesChanged from %s", interface);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// PropertiesChanged arg 2: changed properties with values
|
|
||||||
ret = sd_bus_message_enter_container(msg, 'a', "{sv}");
|
|
||||||
if (ret < 0) {
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
const char *s;
|
|
||||||
while ((ret = sd_bus_message_enter_container(msg, 'e', "sv")) > 0) {
|
|
||||||
ret = sd_bus_message_read_basic(msg, 's', &s);
|
|
||||||
if (ret < 0) {
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (strcmp(s, "CanGraphical") == 0) {
|
|
||||||
int ret;
|
|
||||||
ret = sd_bus_message_enter_container(msg, 'v', "b");
|
|
||||||
if (ret < 0) {
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = sd_bus_message_read_basic(msg, 'b', &session->can_graphical);
|
|
||||||
if (ret < 0) {
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
} else {
|
|
||||||
sd_bus_message_skip(msg, "{sv}");
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = sd_bus_message_exit_container(msg);
|
|
||||||
if (ret < 0) {
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ret < 0) {
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = sd_bus_message_exit_container(msg);
|
|
||||||
if (ret < 0) {
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
// PropertiesChanged arg 3: changed properties without values
|
|
||||||
sd_bus_message_enter_container(msg, 'a', "s");
|
|
||||||
while ((ret = sd_bus_message_read_basic(msg, 's', &s)) > 0) {
|
|
||||||
if (strcmp(s, "CanGraphical") == 0) {
|
|
||||||
session->can_graphical = sd_seat_can_graphical(session->base.seat);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ret < 0) {
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
error:
|
|
||||||
wlr_log(WLR_ERROR, "Failed to parse D-Bus PropertiesChanged: %s",
|
|
||||||
strerror(-ret));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool add_signal_matches(struct logind_session *session) {
|
static bool add_signal_matches(struct logind_session *session) {
|
||||||
static const char *logind = "org.freedesktop.login1";
|
static const char *logind = "org.freedesktop.login1";
|
||||||
static const char *logind_path = "/org/freedesktop/login1";
|
static const char *logind_path = "/org/freedesktop/login1";
|
||||||
|
|
@ -595,14 +502,6 @@ static bool add_signal_matches(struct logind_session *session) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = sd_bus_match_signal(session->bus, NULL, logind, session->seat_path,
|
|
||||||
property_interface, "PropertiesChanged",
|
|
||||||
seat_properties_changed, session);
|
|
||||||
if (ret < 0) {
|
|
||||||
wlr_log(WLR_ERROR, "Failed to add D-Bus match: %s", strerror(-ret));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -670,6 +569,8 @@ static bool get_display_session(char **session_id) {
|
||||||
char *xdg_session_id = getenv("XDG_SESSION_ID");
|
char *xdg_session_id = getenv("XDG_SESSION_ID");
|
||||||
|
|
||||||
if (xdg_session_id) {
|
if (xdg_session_id) {
|
||||||
|
wlr_log(WLR_INFO, "Selecting session from XDG_SESSION_ID: %s", xdg_session_id);
|
||||||
|
|
||||||
// This just checks whether the supplied session ID is valid
|
// This just checks whether the supplied session ID is valid
|
||||||
if (sd_session_is_active(xdg_session_id) < 0) {
|
if (sd_session_is_active(xdg_session_id) < 0) {
|
||||||
wlr_log(WLR_ERROR, "Invalid XDG_SESSION_ID: '%s'", xdg_session_id);
|
wlr_log(WLR_ERROR, "Invalid XDG_SESSION_ID: '%s'", xdg_session_id);
|
||||||
|
|
@ -750,6 +651,8 @@ static struct wlr_session *logind_session_create(struct wl_display *disp) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
session_init(&session->base);
|
||||||
|
|
||||||
if (!get_display_session(&session->id)) {
|
if (!get_display_session(&session->id)) {
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
@ -762,7 +665,7 @@ static struct wlr_session *logind_session_create(struct wl_display *disp) {
|
||||||
}
|
}
|
||||||
snprintf(session->base.seat, sizeof(session->base.seat), "%s", seat);
|
snprintf(session->base.seat, sizeof(session->base.seat), "%s", seat);
|
||||||
|
|
||||||
if (strcmp(seat, "seat0") == 0) {
|
if (sd_seat_can_tty(seat)) {
|
||||||
ret = sd_session_get_vt(session->id, &session->base.vtnr);
|
ret = sd_session_get_vt(session->id, &session->base.vtnr);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
wlr_log(WLR_ERROR, "Session not running in virtual terminal");
|
wlr_log(WLR_ERROR, "Session not running in virtual terminal");
|
||||||
|
|
@ -782,12 +685,6 @@ static struct wlr_session *logind_session_create(struct wl_display *disp) {
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!find_seat_path(session)) {
|
|
||||||
sd_bus_unref(session->bus);
|
|
||||||
free(session->path);
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!add_signal_matches(session)) {
|
if (!add_signal_matches(session)) {
|
||||||
goto error_bus;
|
goto error_bus;
|
||||||
}
|
}
|
||||||
|
|
@ -804,30 +701,18 @@ static struct wlr_session *logind_session_create(struct wl_display *disp) {
|
||||||
goto error_bus;
|
goto error_bus;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for CanGraphical first
|
set_type(session);
|
||||||
session->can_graphical = sd_seat_can_graphical(session->base.seat);
|
|
||||||
if (!session->can_graphical) {
|
|
||||||
wlr_log(WLR_INFO, "Waiting for 'CanGraphical' on seat %s", session->base.seat);
|
|
||||||
}
|
|
||||||
|
|
||||||
while (!session->can_graphical) {
|
|
||||||
ret = wl_event_loop_dispatch(event_loop, -1);
|
|
||||||
if (ret < 0) {
|
|
||||||
wlr_log(WLR_ERROR, "Polling error waiting for 'CanGraphical' on seat %s",
|
|
||||||
session->base.seat);
|
|
||||||
goto error_bus;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
wlr_log(WLR_INFO, "Successfully loaded logind session");
|
wlr_log(WLR_INFO, "Successfully loaded logind session");
|
||||||
|
|
||||||
session->base.impl = &session_logind;
|
session->base.impl = &session_logind;
|
||||||
|
session->base.active = true;
|
||||||
|
|
||||||
return &session->base;
|
return &session->base;
|
||||||
|
|
||||||
error_bus:
|
error_bus:
|
||||||
sd_bus_unref(session->bus);
|
sd_bus_unref(session->bus);
|
||||||
free(session->path);
|
free(session->path);
|
||||||
free(session->seat_path);
|
|
||||||
|
|
||||||
error:
|
error:
|
||||||
free(session->id);
|
free(session->id);
|
||||||
|
|
|
||||||
|
|
@ -62,3 +62,12 @@ if logind_found
|
||||||
wlr_files += files('logind.c')
|
wlr_files += files('logind.c')
|
||||||
wlr_deps += logind
|
wlr_deps += logind
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
# libseat
|
||||||
|
|
||||||
|
libseat = dependency('libseat', required: get_option('libseat'), version: '>=0.2.0')
|
||||||
|
if libseat.found()
|
||||||
|
wlr_files += files('libseat.c')
|
||||||
|
wlr_deps += libseat
|
||||||
|
conf_data.set10('WLR_HAS_LIBSEAT', true)
|
||||||
|
endif
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@
|
||||||
#include <wayland-server-core.h>
|
#include <wayland-server-core.h>
|
||||||
#include <wlr/backend/session/interface.h>
|
#include <wlr/backend/session/interface.h>
|
||||||
#include <wlr/util/log.h>
|
#include <wlr/util/log.h>
|
||||||
|
#include "backend/session/session.h"
|
||||||
#include "util/signal.h"
|
#include "util/signal.h"
|
||||||
|
|
||||||
const struct session_impl session_noop;
|
const struct session_impl session_noop;
|
||||||
|
|
@ -33,7 +34,9 @@ static struct wlr_session *noop_session_create(struct wl_display *disp) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
session_init(session);
|
||||||
session->impl = &session_noop;
|
session->impl = &session_noop;
|
||||||
|
session->active = true;
|
||||||
|
|
||||||
wlr_log(WLR_INFO, "Successfully initialized noop session");
|
wlr_log(WLR_INFO, "Successfully initialized noop session");
|
||||||
return session;
|
return session;
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,8 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <time.h>
|
||||||
#include <wayland-server-core.h>
|
#include <wayland-server-core.h>
|
||||||
#include <wlr/backend/session.h>
|
#include <wlr/backend/session.h>
|
||||||
#include <wlr/backend/session/interface.h>
|
#include <wlr/backend/session/interface.h>
|
||||||
|
|
@ -13,13 +15,20 @@
|
||||||
#include <wlr/util/log.h>
|
#include <wlr/util/log.h>
|
||||||
#include <xf86drm.h>
|
#include <xf86drm.h>
|
||||||
#include <xf86drmMode.h>
|
#include <xf86drmMode.h>
|
||||||
|
#include "backend/session/session.h"
|
||||||
#include "util/signal.h"
|
#include "util/signal.h"
|
||||||
|
|
||||||
|
#define WAIT_GPU_TIMEOUT 10000 // ms
|
||||||
|
|
||||||
|
extern const struct session_impl session_libseat;
|
||||||
extern const struct session_impl session_logind;
|
extern const struct session_impl session_logind;
|
||||||
extern const struct session_impl session_direct;
|
extern const struct session_impl session_direct;
|
||||||
extern const struct session_impl session_noop;
|
extern const struct session_impl session_noop;
|
||||||
|
|
||||||
static const struct session_impl *impls[] = {
|
static const struct session_impl *impls[] = {
|
||||||
|
#if WLR_HAS_LIBSEAT
|
||||||
|
&session_libseat,
|
||||||
|
#endif
|
||||||
#if WLR_HAS_SYSTEMD || WLR_HAS_ELOGIND
|
#if WLR_HAS_SYSTEMD || WLR_HAS_ELOGIND
|
||||||
&session_logind,
|
&session_logind,
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -27,6 +36,19 @@ static const struct session_impl *impls[] = {
|
||||||
NULL,
|
NULL,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static bool is_drm_card(const char *sysname) {
|
||||||
|
const char prefix[] = "card";
|
||||||
|
if (strncmp(sysname, prefix, strlen(prefix)) != 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
for (size_t i = strlen(prefix); sysname[i] != '\0'; i++) {
|
||||||
|
if (sysname[i] < '0' || sysname[i] > '9') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
static int udev_event(int fd, uint32_t mask, void *data) {
|
static int udev_event(int fd, uint32_t mask, void *data) {
|
||||||
struct wlr_session *session = data;
|
struct wlr_session *session = data;
|
||||||
|
|
||||||
|
|
@ -35,22 +57,38 @@ static int udev_event(int fd, uint32_t mask, void *data) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char *sysname = udev_device_get_sysname(udev_dev);
|
||||||
|
const char *devnode = udev_device_get_devnode(udev_dev);
|
||||||
const char *action = udev_device_get_action(udev_dev);
|
const char *action = udev_device_get_action(udev_dev);
|
||||||
|
wlr_log(WLR_DEBUG, "udev event for %s (%s)", sysname, action);
|
||||||
|
|
||||||
wlr_log(WLR_DEBUG, "udev event for %s (%s)",
|
if (!is_drm_card(sysname) || !action || !devnode) {
|
||||||
udev_device_get_sysname(udev_dev), action);
|
|
||||||
|
|
||||||
if (!action || strcmp(action, "change") != 0) {
|
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
dev_t devnum = udev_device_get_devnum(udev_dev);
|
const char *seat = udev_device_get_property_value(udev_dev, "ID_SEAT");
|
||||||
struct wlr_device *dev;
|
if (!seat) {
|
||||||
|
seat = "seat0";
|
||||||
|
}
|
||||||
|
if (session->seat[0] != '\0' && strcmp(session->seat, seat) != 0) {
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
wl_list_for_each(dev, &session->devices, link) {
|
if (strcmp(action, "add") == 0) {
|
||||||
if (dev->dev == devnum) {
|
wlr_log(WLR_DEBUG, "DRM device %s added", sysname);
|
||||||
wlr_signal_emit_safe(&dev->signal, session);
|
struct wlr_session_add_event event = {
|
||||||
break;
|
.path = devnode,
|
||||||
|
};
|
||||||
|
wlr_signal_emit_safe(&session->events.add_drm_card, &event);
|
||||||
|
} else if (strcmp(action, "change") == 0) {
|
||||||
|
dev_t devnum = udev_device_get_devnum(udev_dev);
|
||||||
|
struct wlr_device *dev;
|
||||||
|
wl_list_for_each(dev, &session->devices, link) {
|
||||||
|
if (dev->dev == devnum) {
|
||||||
|
wlr_log(WLR_DEBUG, "DRM device %s changed", sysname);
|
||||||
|
wlr_signal_emit_safe(&dev->events.change, NULL);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -65,12 +103,25 @@ static void handle_display_destroy(struct wl_listener *listener, void *data) {
|
||||||
wlr_session_destroy(session);
|
wlr_session_destroy(session);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void session_init(struct wlr_session *session) {
|
||||||
|
wl_signal_init(&session->events.active);
|
||||||
|
wl_signal_init(&session->events.add_drm_card);
|
||||||
|
wl_signal_init(&session->events.destroy);
|
||||||
|
wl_list_init(&session->devices);
|
||||||
|
}
|
||||||
|
|
||||||
struct wlr_session *wlr_session_create(struct wl_display *disp) {
|
struct wlr_session *wlr_session_create(struct wl_display *disp) {
|
||||||
struct wlr_session *session = NULL;
|
struct wlr_session *session = NULL;
|
||||||
|
|
||||||
const char *env_wlr_session = getenv("WLR_SESSION");
|
const char *env_wlr_session = getenv("WLR_SESSION");
|
||||||
if (env_wlr_session) {
|
if (env_wlr_session) {
|
||||||
if (strcmp(env_wlr_session, "logind") == 0 ||
|
if (strcmp(env_wlr_session, "libseat") == 0) {
|
||||||
|
#if WLR_HAS_LIBSEAT
|
||||||
|
session = session_libseat.create(disp);
|
||||||
|
#else
|
||||||
|
wlr_log(WLR_ERROR, "wlroots is not compiled with libseat support");
|
||||||
|
#endif
|
||||||
|
} else if (strcmp(env_wlr_session, "logind") == 0 ||
|
||||||
strcmp(env_wlr_session, "systemd") == 0) {
|
strcmp(env_wlr_session, "systemd") == 0) {
|
||||||
#if WLR_HAS_SYSTEMD || WLR_HAS_ELOGIND
|
#if WLR_HAS_SYSTEMD || WLR_HAS_ELOGIND
|
||||||
session = session_logind.create(disp);
|
session = session_logind.create(disp);
|
||||||
|
|
@ -97,11 +148,6 @@ struct wlr_session *wlr_session_create(struct wl_display *disp) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
session->active = true;
|
|
||||||
wl_signal_init(&session->session_signal);
|
|
||||||
wl_signal_init(&session->events.destroy);
|
|
||||||
wl_list_init(&session->devices);
|
|
||||||
|
|
||||||
session->udev = udev_new();
|
session->udev = udev_new();
|
||||||
if (!session->udev) {
|
if (!session->udev) {
|
||||||
wlr_log_errno(WLR_ERROR, "Failed to create udev context");
|
wlr_log_errno(WLR_ERROR, "Failed to create udev context");
|
||||||
|
|
@ -127,6 +173,8 @@ struct wlr_session *wlr_session_create(struct wl_display *disp) {
|
||||||
goto error_mon;
|
goto error_mon;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
session->display = disp;
|
||||||
|
|
||||||
session->display_destroy.notify = handle_display_destroy;
|
session->display_destroy.notify = handle_display_destroy;
|
||||||
wl_display_add_destroy_listener(disp, &session->display_destroy);
|
wl_display_add_destroy_listener(disp, &session->display_destroy);
|
||||||
|
|
||||||
|
|
@ -156,10 +204,11 @@ void wlr_session_destroy(struct wlr_session *session) {
|
||||||
session->impl->destroy(session);
|
session->impl->destroy(session);
|
||||||
}
|
}
|
||||||
|
|
||||||
int wlr_session_open_file(struct wlr_session *session, const char *path) {
|
struct wlr_device *wlr_session_open_file(struct wlr_session *session,
|
||||||
|
const char *path) {
|
||||||
int fd = session->impl->open(session, path);
|
int fd = session->impl->open(session, path);
|
||||||
if (fd < 0) {
|
if (fd < 0) {
|
||||||
return fd;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct wlr_device *dev = malloc(sizeof(*dev));
|
struct wlr_device *dev = malloc(sizeof(*dev));
|
||||||
|
|
@ -176,45 +225,24 @@ int wlr_session_open_file(struct wlr_session *session, const char *path) {
|
||||||
|
|
||||||
dev->fd = fd;
|
dev->fd = fd;
|
||||||
dev->dev = st.st_rdev;
|
dev->dev = st.st_rdev;
|
||||||
wl_signal_init(&dev->signal);
|
wl_signal_init(&dev->events.change);
|
||||||
wl_list_insert(&session->devices, &dev->link);
|
wl_list_insert(&session->devices, &dev->link);
|
||||||
|
|
||||||
return fd;
|
return dev;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
free(dev);
|
free(dev);
|
||||||
return fd;
|
close(fd);
|
||||||
}
|
|
||||||
|
|
||||||
static struct wlr_device *find_device(struct wlr_session *session, int fd) {
|
|
||||||
struct wlr_device *dev;
|
|
||||||
|
|
||||||
wl_list_for_each(dev, &session->devices, link) {
|
|
||||||
if (dev->fd == fd) {
|
|
||||||
return dev;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
wlr_log(WLR_ERROR, "Tried to use fd %d not opened by session", fd);
|
|
||||||
assert(0);
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void wlr_session_close_file(struct wlr_session *session, int fd) {
|
void wlr_session_close_file(struct wlr_session *session,
|
||||||
struct wlr_device *dev = find_device(session, fd);
|
struct wlr_device *dev) {
|
||||||
|
session->impl->close(session, dev->fd);
|
||||||
session->impl->close(session, fd);
|
|
||||||
wl_list_remove(&dev->link);
|
wl_list_remove(&dev->link);
|
||||||
free(dev);
|
free(dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
void wlr_session_signal_add(struct wlr_session *session, int fd,
|
|
||||||
struct wl_listener *listener) {
|
|
||||||
struct wlr_device *dev = find_device(session, fd);
|
|
||||||
|
|
||||||
wl_signal_add(&dev->signal, listener);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool wlr_session_change_vt(struct wlr_session *session, unsigned vt) {
|
bool wlr_session_change_vt(struct wlr_session *session, unsigned vt) {
|
||||||
if (!session) {
|
if (!session) {
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -226,32 +254,32 @@ bool wlr_session_change_vt(struct wlr_session *session, unsigned vt) {
|
||||||
/* Tests if 'path' is KMS compatible by trying to open it.
|
/* Tests if 'path' is KMS compatible by trying to open it.
|
||||||
* It leaves the open device in *fd_out it it succeeds.
|
* It leaves the open device in *fd_out it it succeeds.
|
||||||
*/
|
*/
|
||||||
static int open_if_kms(struct wlr_session *restrict session,
|
static struct wlr_device *open_if_kms(struct wlr_session *restrict session,
|
||||||
const char *restrict path) {
|
const char *restrict path) {
|
||||||
if (!path) {
|
if (!path) {
|
||||||
return -1;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
int fd = wlr_session_open_file(session, path);
|
struct wlr_device *dev = wlr_session_open_file(session, path);
|
||||||
if (fd < 0) {
|
if (!dev) {
|
||||||
return -1;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
drmVersion *ver = drmGetVersion(fd);
|
drmVersion *ver = drmGetVersion(dev->fd);
|
||||||
if (!ver) {
|
if (!ver) {
|
||||||
goto out_fd;
|
goto out_dev;
|
||||||
}
|
}
|
||||||
|
|
||||||
drmFreeVersion(ver);
|
drmFreeVersion(ver);
|
||||||
return fd;
|
return dev;
|
||||||
|
|
||||||
out_fd:
|
out_dev:
|
||||||
wlr_session_close_file(session, fd);
|
wlr_session_close_file(session, dev);
|
||||||
return -1;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static size_t explicit_find_gpus(struct wlr_session *session,
|
static size_t explicit_find_gpus(struct wlr_session *session,
|
||||||
size_t ret_len, int ret[static ret_len], const char *str) {
|
size_t ret_len, struct wlr_device *ret[static ret_len], const char *str) {
|
||||||
char *gpus = strdup(str);
|
char *gpus = strdup(str);
|
||||||
if (!gpus) {
|
if (!gpus) {
|
||||||
wlr_log_errno(WLR_ERROR, "Allocation failed");
|
wlr_log_errno(WLR_ERROR, "Allocation failed");
|
||||||
|
|
@ -267,7 +295,7 @@ static size_t explicit_find_gpus(struct wlr_session *session,
|
||||||
}
|
}
|
||||||
|
|
||||||
ret[i] = open_if_kms(session, ptr);
|
ret[i] = open_if_kms(session, ptr);
|
||||||
if (ret[i] < 0) {
|
if (!ret[i]) {
|
||||||
wlr_log(WLR_ERROR, "Unable to open %s as DRM device", ptr);
|
wlr_log(WLR_ERROR, "Unable to open %s as DRM device", ptr);
|
||||||
} else {
|
} else {
|
||||||
++i;
|
++i;
|
||||||
|
|
@ -278,25 +306,92 @@ static size_t explicit_find_gpus(struct wlr_session *session,
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static struct udev_enumerate *enumerate_drm_cards(struct udev *udev) {
|
||||||
|
struct udev_enumerate *en = udev_enumerate_new(udev);
|
||||||
|
if (!en) {
|
||||||
|
wlr_log(WLR_ERROR, "udev_enumerate_new failed");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
udev_enumerate_add_match_subsystem(en, "drm");
|
||||||
|
udev_enumerate_add_match_sysname(en, "card[0-9]*");
|
||||||
|
|
||||||
|
if (udev_enumerate_scan_devices(en) != 0) {
|
||||||
|
wlr_log(WLR_ERROR, "udev_enumerate_scan_devices failed");
|
||||||
|
udev_enumerate_unref(en);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return en;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint64_t get_current_time_ms(void) {
|
||||||
|
struct timespec ts = {0};
|
||||||
|
clock_gettime(CLOCK_MONOTONIC, &ts);
|
||||||
|
return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct find_gpus_add_handler {
|
||||||
|
bool added;
|
||||||
|
struct wl_listener listener;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void find_gpus_handle_add(struct wl_listener *listener, void *data) {
|
||||||
|
struct find_gpus_add_handler *handler =
|
||||||
|
wl_container_of(listener, handler, listener);
|
||||||
|
handler->added = true;
|
||||||
|
}
|
||||||
|
|
||||||
/* Tries to find the primary GPU by checking for the "boot_vga" attribute.
|
/* Tries to find the primary GPU by checking for the "boot_vga" attribute.
|
||||||
* If it's not found, it returns the first valid GPU it finds.
|
* If it's not found, it returns the first valid GPU it finds.
|
||||||
*/
|
*/
|
||||||
size_t wlr_session_find_gpus(struct wlr_session *session,
|
size_t wlr_session_find_gpus(struct wlr_session *session,
|
||||||
size_t ret_len, int *ret) {
|
size_t ret_len, struct wlr_device **ret) {
|
||||||
const char *explicit = getenv("WLR_DRM_DEVICES");
|
const char *explicit = getenv("WLR_DRM_DEVICES");
|
||||||
if (explicit) {
|
if (explicit) {
|
||||||
return explicit_find_gpus(session, ret_len, ret, explicit);
|
return explicit_find_gpus(session, ret_len, ret, explicit);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct udev_enumerate *en = udev_enumerate_new(session->udev);
|
struct udev_enumerate *en = enumerate_drm_cards(session->udev);
|
||||||
if (!en) {
|
if (!en) {
|
||||||
wlr_log(WLR_ERROR, "Failed to create udev enumeration");
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
udev_enumerate_add_match_subsystem(en, "drm");
|
if (udev_enumerate_get_list_entry(en) == NULL) {
|
||||||
udev_enumerate_add_match_sysname(en, "card[0-9]*");
|
udev_enumerate_unref(en);
|
||||||
udev_enumerate_scan_devices(en);
|
wlr_log(WLR_INFO, "Waiting for a DRM card device");
|
||||||
|
|
||||||
|
struct find_gpus_add_handler handler = {0};
|
||||||
|
handler.listener.notify = find_gpus_handle_add;
|
||||||
|
wl_signal_add(&session->events.add_drm_card, &handler.listener);
|
||||||
|
|
||||||
|
uint64_t started_at = get_current_time_ms();
|
||||||
|
uint64_t timeout = WAIT_GPU_TIMEOUT;
|
||||||
|
struct wl_event_loop *event_loop =
|
||||||
|
wl_display_get_event_loop(session->display);
|
||||||
|
while (!handler.added) {
|
||||||
|
int ret = wl_event_loop_dispatch(event_loop, (int)timeout);
|
||||||
|
if (ret < 0) {
|
||||||
|
wlr_log_errno(WLR_ERROR, "Failed to wait for DRM card device: "
|
||||||
|
"wl_event_loop_dispatch failed");
|
||||||
|
udev_enumerate_unref(en);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t now = get_current_time_ms();
|
||||||
|
if (now >= started_at + WAIT_GPU_TIMEOUT) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
timeout = started_at + WAIT_GPU_TIMEOUT - now;
|
||||||
|
}
|
||||||
|
|
||||||
|
wl_list_remove(&handler.listener.link);
|
||||||
|
|
||||||
|
en = enumerate_drm_cards(session->udev);
|
||||||
|
if (!en) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
struct udev_list_entry *entry;
|
struct udev_list_entry *entry;
|
||||||
size_t i = 0;
|
size_t i = 0;
|
||||||
|
|
@ -334,17 +429,18 @@ size_t wlr_session_find_gpus(struct wlr_session *session,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int fd = open_if_kms(session, udev_device_get_devnode(dev));
|
struct wlr_device *wlr_dev =
|
||||||
if (fd < 0) {
|
open_if_kms(session, udev_device_get_devnode(dev));
|
||||||
|
if (!wlr_dev) {
|
||||||
udev_device_unref(dev);
|
udev_device_unref(dev);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
udev_device_unref(dev);
|
udev_device_unref(dev);
|
||||||
|
|
||||||
ret[i] = fd;
|
ret[i] = wlr_dev;
|
||||||
if (is_boot_vga) {
|
if (is_boot_vga) {
|
||||||
int tmp = ret[0];
|
struct wlr_device *tmp = ret[0];
|
||||||
ret[0] = ret[i];
|
ret[0] = ret[i];
|
||||||
ret[i] = tmp;
|
ret[i] = tmp;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,10 @@
|
||||||
|
#define _POSIX_C_SOURCE 200809L
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
#include <fcntl.h>
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
#include <wlr/config.h>
|
#include <wlr/config.h>
|
||||||
|
|
||||||
|
|
@ -16,7 +19,11 @@
|
||||||
#include <wlr/util/log.h>
|
#include <wlr/util/log.h>
|
||||||
|
|
||||||
#include "backend/wayland.h"
|
#include "backend/wayland.h"
|
||||||
|
#include "render/drm_format_set.h"
|
||||||
|
#include "render/gbm_allocator.h"
|
||||||
|
#include "render/wlr_renderer.h"
|
||||||
#include "util/signal.h"
|
#include "util/signal.h"
|
||||||
|
|
||||||
#include "linux-dmabuf-unstable-v1-client-protocol.h"
|
#include "linux-dmabuf-unstable-v1-client-protocol.h"
|
||||||
#include "pointer-gestures-unstable-v1-client-protocol.h"
|
#include "pointer-gestures-unstable-v1-client-protocol.h"
|
||||||
#include "presentation-time-client-protocol.h"
|
#include "presentation-time-client-protocol.h"
|
||||||
|
|
@ -97,15 +104,17 @@ static void registry_global(void *data, struct wl_registry *registry,
|
||||||
uint32_t name, const char *iface, uint32_t version) {
|
uint32_t name, const char *iface, uint32_t version) {
|
||||||
struct wlr_wl_backend *wl = data;
|
struct wlr_wl_backend *wl = data;
|
||||||
|
|
||||||
wlr_log(WLR_DEBUG, "Remote wayland global: %s v%d", iface, version);
|
wlr_log(WLR_DEBUG, "Remote wayland global: %s v%" PRIu32, iface, version);
|
||||||
|
|
||||||
if (strcmp(iface, wl_compositor_interface.name) == 0) {
|
if (strcmp(iface, wl_compositor_interface.name) == 0) {
|
||||||
wl->compositor = wl_registry_bind(registry, name,
|
wl->compositor = wl_registry_bind(registry, name,
|
||||||
&wl_compositor_interface, 4);
|
&wl_compositor_interface, 4);
|
||||||
} else if (strcmp(iface, wl_seat_interface.name) == 0) {
|
} else if (strcmp(iface, wl_seat_interface.name) == 0) {
|
||||||
wl->seat = wl_registry_bind(registry, name,
|
struct wl_seat *wl_seat = wl_registry_bind(registry, name,
|
||||||
&wl_seat_interface, 5);
|
&wl_seat_interface, 5);
|
||||||
wl_seat_add_listener(wl->seat, &seat_listener, wl);
|
if (!create_wl_seat(wl_seat, wl)) {
|
||||||
|
wl_seat_destroy(wl_seat);
|
||||||
|
}
|
||||||
} else if (strcmp(iface, xdg_wm_base_interface.name) == 0) {
|
} else if (strcmp(iface, xdg_wm_base_interface.name) == 0) {
|
||||||
wl->xdg_wm_base = wl_registry_bind(registry, name,
|
wl->xdg_wm_base = wl_registry_bind(registry, name,
|
||||||
&xdg_wm_base_interface, 1);
|
&xdg_wm_base_interface, 1);
|
||||||
|
|
@ -155,13 +164,15 @@ static bool backend_start(struct wlr_backend *backend) {
|
||||||
|
|
||||||
wl->started = true;
|
wl->started = true;
|
||||||
|
|
||||||
if (wl->keyboard) {
|
struct wlr_wl_seat *seat;
|
||||||
create_wl_keyboard(wl->keyboard, wl);
|
wl_list_for_each(seat, &wl->seats, link) {
|
||||||
}
|
if (seat->keyboard) {
|
||||||
|
create_wl_keyboard(seat);
|
||||||
|
}
|
||||||
|
|
||||||
if (wl->tablet_manager && wl->seat) {
|
if (wl->tablet_manager) {
|
||||||
wl_add_tablet_seat(wl->tablet_manager,
|
wl_add_tablet_seat(wl->tablet_manager, seat);
|
||||||
wl->seat, wl);
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (size_t i = 0; i < wl->requested_outputs; ++i) {
|
for (size_t i = 0; i < wl->requested_outputs; ++i) {
|
||||||
|
|
@ -192,8 +203,6 @@ static void backend_destroy(struct wlr_backend *backend) {
|
||||||
|
|
||||||
wl_list_remove(&wl->local_display_destroy.link);
|
wl_list_remove(&wl->local_display_destroy.link);
|
||||||
|
|
||||||
free(wl->seat_name);
|
|
||||||
|
|
||||||
wl_event_source_remove(wl->remote_display_src);
|
wl_event_source_remove(wl->remote_display_src);
|
||||||
|
|
||||||
wlr_renderer_destroy(wl->renderer);
|
wlr_renderer_destroy(wl->renderer);
|
||||||
|
|
@ -201,12 +210,12 @@ static void backend_destroy(struct wlr_backend *backend) {
|
||||||
|
|
||||||
wlr_drm_format_set_finish(&wl->linux_dmabuf_v1_formats);
|
wlr_drm_format_set_finish(&wl->linux_dmabuf_v1_formats);
|
||||||
|
|
||||||
if (wl->pointer) {
|
struct wlr_wl_buffer *buffer, *tmp_buffer;
|
||||||
wl_pointer_destroy(wl->pointer);
|
wl_list_for_each_safe(buffer, tmp_buffer, &wl->buffers, link) {
|
||||||
}
|
destroy_wl_buffer(buffer);
|
||||||
if (wl->seat) {
|
|
||||||
wl_seat_destroy(wl->seat);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
destroy_wl_seats(wl);
|
||||||
if (wl->zxdg_decoration_manager_v1) {
|
if (wl->zxdg_decoration_manager_v1) {
|
||||||
zxdg_decoration_manager_v1_destroy(wl->zxdg_decoration_manager_v1);
|
zxdg_decoration_manager_v1_destroy(wl->zxdg_decoration_manager_v1);
|
||||||
}
|
}
|
||||||
|
|
@ -265,6 +274,8 @@ struct wlr_backend *wlr_wl_backend_create(struct wl_display *display,
|
||||||
wl->local_display = display;
|
wl->local_display = display;
|
||||||
wl_list_init(&wl->devices);
|
wl_list_init(&wl->devices);
|
||||||
wl_list_init(&wl->outputs);
|
wl_list_init(&wl->outputs);
|
||||||
|
wl_list_init(&wl->seats);
|
||||||
|
wl_list_init(&wl->buffers);
|
||||||
|
|
||||||
wl->remote_display = wl_display_connect(remote);
|
wl->remote_display = wl_display_connect(remote);
|
||||||
if (!wl->remote_display) {
|
if (!wl->remote_display) {
|
||||||
|
|
@ -279,8 +290,8 @@ struct wlr_backend *wlr_wl_backend_create(struct wl_display *display,
|
||||||
}
|
}
|
||||||
|
|
||||||
wl_registry_add_listener(wl->registry, ®istry_listener, wl);
|
wl_registry_add_listener(wl->registry, ®istry_listener, wl);
|
||||||
wl_display_dispatch(wl->remote_display);
|
wl_display_roundtrip(wl->remote_display); // get globals
|
||||||
wl_display_roundtrip(wl->remote_display);
|
wl_display_roundtrip(wl->remote_display); // get linux-dmabuf formats
|
||||||
|
|
||||||
if (!wl->compositor) {
|
if (!wl->compositor) {
|
||||||
wlr_log(WLR_ERROR,
|
wlr_log(WLR_ERROR,
|
||||||
|
|
@ -304,28 +315,66 @@ struct wlr_backend *wlr_wl_backend_create(struct wl_display *display,
|
||||||
}
|
}
|
||||||
wl_event_source_check(wl->remote_display_src);
|
wl_event_source_check(wl->remote_display_src);
|
||||||
|
|
||||||
static EGLint config_attribs[] = {
|
|
||||||
EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
|
|
||||||
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
|
|
||||||
EGL_RED_SIZE, 1,
|
|
||||||
EGL_GREEN_SIZE, 1,
|
|
||||||
EGL_BLUE_SIZE, 1,
|
|
||||||
EGL_ALPHA_SIZE, 1,
|
|
||||||
EGL_NONE,
|
|
||||||
};
|
|
||||||
|
|
||||||
if (!create_renderer_func) {
|
if (!create_renderer_func) {
|
||||||
create_renderer_func = wlr_renderer_autocreate;
|
create_renderer_func = wlr_renderer_autocreate;
|
||||||
}
|
}
|
||||||
|
|
||||||
wl->renderer = create_renderer_func(&wl->egl, EGL_PLATFORM_WAYLAND_EXT,
|
wl->renderer = create_renderer_func(&wl->egl, EGL_PLATFORM_WAYLAND_EXT,
|
||||||
wl->remote_display, config_attribs, WL_SHM_FORMAT_ARGB8888);
|
wl->remote_display, NULL, 0);
|
||||||
|
|
||||||
if (!wl->renderer) {
|
if (!wl->renderer) {
|
||||||
wlr_log(WLR_ERROR, "Could not create renderer");
|
wlr_log(WLR_ERROR, "Could not create renderer");
|
||||||
goto error_event;
|
goto error_event;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: get FD from linux-dmabuf hints instead
|
||||||
|
int drm_fd = wlr_renderer_get_drm_fd(wl->renderer);
|
||||||
|
if (drm_fd < 0) {
|
||||||
|
wlr_log(WLR_ERROR, "Failed to get DRM device FD from renderer");
|
||||||
|
goto error_event;
|
||||||
|
}
|
||||||
|
|
||||||
|
drm_fd = fcntl(drm_fd, F_DUPFD_CLOEXEC, 0);
|
||||||
|
if (drm_fd < 0) {
|
||||||
|
wlr_log_errno(WLR_ERROR, "fcntl(F_DUPFD_CLOEXEC) failed");
|
||||||
|
goto error_event;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct wlr_gbm_allocator *alloc = wlr_gbm_allocator_create(drm_fd);
|
||||||
|
if (alloc == NULL) {
|
||||||
|
wlr_log(WLR_ERROR, "Failed to create GBM allocator");
|
||||||
|
goto error_event;
|
||||||
|
}
|
||||||
|
wl->allocator = &alloc->base;
|
||||||
|
|
||||||
|
uint32_t fmt = DRM_FORMAT_ARGB8888;
|
||||||
|
const struct wlr_drm_format *remote_format =
|
||||||
|
wlr_drm_format_set_get(&wl->linux_dmabuf_v1_formats, fmt);
|
||||||
|
if (remote_format == NULL) {
|
||||||
|
wlr_log(WLR_ERROR, "Remote compositor doesn't support format "
|
||||||
|
"0x%"PRIX32" via linux-dmabuf-unstable-v1", fmt);
|
||||||
|
goto error_event;
|
||||||
|
}
|
||||||
|
|
||||||
|
const struct wlr_drm_format_set *render_formats =
|
||||||
|
wlr_renderer_get_dmabuf_render_formats(wl->renderer);
|
||||||
|
if (render_formats == NULL) {
|
||||||
|
wlr_log(WLR_ERROR, "Failed to get available DMA-BUF formats from renderer");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const struct wlr_drm_format *render_format =
|
||||||
|
wlr_drm_format_set_get(render_formats, fmt);
|
||||||
|
if (render_format == NULL) {
|
||||||
|
wlr_log(WLR_ERROR, "Renderer doesn't support DRM format 0x%"PRIX32, fmt);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
wl->format = wlr_drm_format_intersect(remote_format, render_format);
|
||||||
|
if (wl->format == NULL) {
|
||||||
|
wlr_log(WLR_ERROR, "Failed to intersect remote and render modifiers "
|
||||||
|
"for format 0x%"PRIX32, fmt);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
wl->local_display_destroy.notify = handle_display_destroy;
|
wl->local_display_destroy.notify = handle_display_destroy;
|
||||||
wl_display_add_destroy_listener(display, &wl->local_display_destroy);
|
wl_display_add_destroy_listener(display, &wl->local_display_destroy);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,10 @@
|
||||||
#include <wlr/util/log.h>
|
#include <wlr/util/log.h>
|
||||||
|
|
||||||
#include "backend/wayland.h"
|
#include "backend/wayland.h"
|
||||||
|
#include "render/swapchain.h"
|
||||||
|
#include "render/wlr_renderer.h"
|
||||||
#include "util/signal.h"
|
#include "util/signal.h"
|
||||||
|
|
||||||
#include "linux-dmabuf-unstable-v1-client-protocol.h"
|
#include "linux-dmabuf-unstable-v1-client-protocol.h"
|
||||||
#include "presentation-time-client-protocol.h"
|
#include "presentation-time-client-protocol.h"
|
||||||
#include "xdg-decoration-unstable-v1-client-protocol.h"
|
#include "xdg-decoration-unstable-v1-client-protocol.h"
|
||||||
|
|
@ -94,37 +97,69 @@ static const struct wp_presentation_feedback_listener
|
||||||
static bool output_set_custom_mode(struct wlr_output *wlr_output,
|
static bool output_set_custom_mode(struct wlr_output *wlr_output,
|
||||||
int32_t width, int32_t height, int32_t refresh) {
|
int32_t width, int32_t height, int32_t refresh) {
|
||||||
struct wlr_wl_output *output = get_wl_output_from_output(wlr_output);
|
struct wlr_wl_output *output = get_wl_output_from_output(wlr_output);
|
||||||
wl_egl_window_resize(output->egl_window, width, height, 0, 0);
|
|
||||||
|
if (wlr_output->width != width || wlr_output->height != height) {
|
||||||
|
struct wlr_swapchain *swapchain = wlr_swapchain_create(
|
||||||
|
output->backend->allocator, width, height, output->backend->format);
|
||||||
|
if (swapchain == NULL) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
wlr_swapchain_destroy(output->swapchain);
|
||||||
|
output->swapchain = swapchain;
|
||||||
|
}
|
||||||
|
|
||||||
wlr_output_update_custom_mode(&output->wlr_output, width, height, 0);
|
wlr_output_update_custom_mode(&output->wlr_output, width, height, 0);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool output_attach_render(struct wlr_output *wlr_output,
|
static bool output_attach_render(struct wlr_output *wlr_output,
|
||||||
int *buffer_age) {
|
int *buffer_age) {
|
||||||
struct wlr_wl_output *output =
|
struct wlr_wl_output *output = get_wl_output_from_output(wlr_output);
|
||||||
get_wl_output_from_output(wlr_output);
|
|
||||||
return wlr_egl_make_current(&output->backend->egl, output->egl_surface,
|
wlr_buffer_unlock(output->back_buffer);
|
||||||
buffer_age);
|
output->back_buffer = wlr_swapchain_acquire(output->swapchain, buffer_age);
|
||||||
|
if (!output->back_buffer) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!wlr_egl_make_current(&output->backend->egl, EGL_NO_SURFACE, NULL)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!wlr_renderer_bind_buffer(output->backend->renderer,
|
||||||
|
output->back_buffer)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void destroy_wl_buffer(struct wlr_wl_buffer *buffer) {
|
void destroy_wl_buffer(struct wlr_wl_buffer *buffer) {
|
||||||
if (buffer == NULL) {
|
if (buffer == NULL) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
wl_list_remove(&buffer->buffer_destroy.link);
|
||||||
|
wl_list_remove(&buffer->link);
|
||||||
wl_buffer_destroy(buffer->wl_buffer);
|
wl_buffer_destroy(buffer->wl_buffer);
|
||||||
wlr_buffer_unlock(buffer->buffer);
|
|
||||||
free(buffer);
|
free(buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void buffer_handle_release(void *data, struct wl_buffer *wl_buffer) {
|
static void buffer_handle_release(void *data, struct wl_buffer *wl_buffer) {
|
||||||
struct wlr_wl_buffer *buffer = data;
|
struct wlr_wl_buffer *buffer = data;
|
||||||
destroy_wl_buffer(buffer);
|
buffer->released = true;
|
||||||
|
wlr_buffer_unlock(buffer->buffer); // might free buffer
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct wl_buffer_listener buffer_listener = {
|
static const struct wl_buffer_listener buffer_listener = {
|
||||||
.release = buffer_handle_release,
|
.release = buffer_handle_release,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static void buffer_handle_buffer_destroy(struct wl_listener *listener,
|
||||||
|
void *data) {
|
||||||
|
struct wlr_wl_buffer *buffer =
|
||||||
|
wl_container_of(listener, buffer, buffer_destroy);
|
||||||
|
destroy_wl_buffer(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
static bool test_buffer(struct wlr_wl_backend *wl,
|
static bool test_buffer(struct wlr_wl_backend *wl,
|
||||||
struct wlr_buffer *wlr_buffer) {
|
struct wlr_buffer *wlr_buffer) {
|
||||||
struct wlr_dmabuf_attributes attribs;
|
struct wlr_dmabuf_attributes attribs;
|
||||||
|
|
@ -181,12 +216,33 @@ static struct wlr_wl_buffer *create_wl_buffer(struct wlr_wl_backend *wl,
|
||||||
}
|
}
|
||||||
buffer->wl_buffer = wl_buffer;
|
buffer->wl_buffer = wl_buffer;
|
||||||
buffer->buffer = wlr_buffer_lock(wlr_buffer);
|
buffer->buffer = wlr_buffer_lock(wlr_buffer);
|
||||||
|
wl_list_insert(&wl->buffers, &buffer->link);
|
||||||
|
|
||||||
wl_buffer_add_listener(wl_buffer, &buffer_listener, buffer);
|
wl_buffer_add_listener(wl_buffer, &buffer_listener, buffer);
|
||||||
|
|
||||||
|
buffer->buffer_destroy.notify = buffer_handle_buffer_destroy;
|
||||||
|
wl_signal_add(&wlr_buffer->events.destroy, &buffer->buffer_destroy);
|
||||||
|
|
||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static struct wlr_wl_buffer *get_or_create_wl_buffer(struct wlr_wl_backend *wl,
|
||||||
|
struct wlr_buffer *wlr_buffer) {
|
||||||
|
struct wlr_wl_buffer *buffer;
|
||||||
|
wl_list_for_each(buffer, &wl->buffers, link) {
|
||||||
|
// We can only re-use a wlr_wl_buffer if the parent compositor has
|
||||||
|
// released it, because wl_buffer.release is per-wl_buffer, not per
|
||||||
|
// wl_surface.commit.
|
||||||
|
if (buffer->buffer == wlr_buffer && buffer->released) {
|
||||||
|
buffer->released = false;
|
||||||
|
wlr_buffer_lock(buffer->buffer);
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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) {
|
||||||
struct wlr_wl_output *output =
|
struct wlr_wl_output *output =
|
||||||
get_wl_output_from_output(wlr_output);
|
get_wl_output_from_output(wlr_output);
|
||||||
|
|
@ -246,39 +302,49 @@ static bool output_commit(struct wlr_output *wlr_output) {
|
||||||
output->frame_callback = wl_surface_frame(output->surface);
|
output->frame_callback = wl_surface_frame(output->surface);
|
||||||
wl_callback_add_listener(output->frame_callback, &frame_listener, output);
|
wl_callback_add_listener(output->frame_callback, &frame_listener, output);
|
||||||
|
|
||||||
|
struct wlr_buffer *wlr_buffer = NULL;
|
||||||
switch (wlr_output->pending.buffer_type) {
|
switch (wlr_output->pending.buffer_type) {
|
||||||
case WLR_OUTPUT_STATE_BUFFER_RENDER:
|
case WLR_OUTPUT_STATE_BUFFER_RENDER:
|
||||||
if (!wlr_egl_swap_buffers(&output->backend->egl,
|
assert(output->back_buffer != NULL);
|
||||||
output->egl_surface, damage)) {
|
wlr_buffer = output->back_buffer;
|
||||||
return false;
|
|
||||||
}
|
wlr_renderer_bind_buffer(output->backend->renderer, NULL);
|
||||||
|
wlr_egl_unset_current(&output->backend->egl);
|
||||||
break;
|
break;
|
||||||
case WLR_OUTPUT_STATE_BUFFER_SCANOUT:;
|
case WLR_OUTPUT_STATE_BUFFER_SCANOUT:;
|
||||||
struct wlr_wl_buffer *buffer =
|
wlr_buffer = wlr_output->pending.buffer;
|
||||||
create_wl_buffer(output->backend, wlr_output->pending.buffer);
|
|
||||||
if (buffer == NULL) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
wl_surface_attach(output->surface, buffer->wl_buffer, 0, 0);
|
|
||||||
|
|
||||||
if (damage == NULL) {
|
|
||||||
wl_surface_damage_buffer(output->surface,
|
|
||||||
0, 0, INT32_MAX, INT32_MAX);
|
|
||||||
} else {
|
|
||||||
int rects_len;
|
|
||||||
pixman_box32_t *rects =
|
|
||||||
pixman_region32_rectangles(damage, &rects_len);
|
|
||||||
for (int i = 0; i < rects_len; i++) {
|
|
||||||
pixman_box32_t *r = &rects[i];
|
|
||||||
wl_surface_damage_buffer(output->surface, r->x1, r->y1,
|
|
||||||
r->x2 - r->x1, r->y2 - r->y1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
wl_surface_commit(output->surface);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct wlr_wl_buffer *buffer =
|
||||||
|
get_or_create_wl_buffer(output->backend, wlr_buffer);
|
||||||
|
if (buffer == NULL) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
wl_surface_attach(output->surface, buffer->wl_buffer, 0, 0);
|
||||||
|
|
||||||
|
if (damage == NULL) {
|
||||||
|
wl_surface_damage_buffer(output->surface,
|
||||||
|
0, 0, INT32_MAX, INT32_MAX);
|
||||||
|
} else {
|
||||||
|
int rects_len;
|
||||||
|
pixman_box32_t *rects =
|
||||||
|
pixman_region32_rectangles(damage, &rects_len);
|
||||||
|
for (int i = 0; i < rects_len; i++) {
|
||||||
|
pixman_box32_t *r = &rects[i];
|
||||||
|
wl_surface_damage_buffer(output->surface, r->x1, r->y1,
|
||||||
|
r->x2 - r->x1, r->y2 - r->y1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
wl_surface_commit(output->surface);
|
||||||
|
|
||||||
|
wlr_buffer_unlock(output->back_buffer);
|
||||||
|
output->back_buffer = NULL;
|
||||||
|
|
||||||
|
wlr_swapchain_set_buffer_submitted(output->swapchain, wlr_buffer);
|
||||||
|
|
||||||
if (wp_feedback != NULL) {
|
if (wp_feedback != NULL) {
|
||||||
struct wlr_wl_presentation_feedback *feedback =
|
struct wlr_wl_presentation_feedback *feedback =
|
||||||
calloc(1, sizeof(*feedback));
|
calloc(1, sizeof(*feedback));
|
||||||
|
|
@ -302,8 +368,8 @@ static bool output_commit(struct wlr_output *wlr_output) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static void output_rollback_render(struct wlr_output *wlr_output) {
|
static void output_rollback_render(struct wlr_output *wlr_output) {
|
||||||
struct wlr_wl_output *output =
|
struct wlr_wl_output *output = get_wl_output_from_output(wlr_output);
|
||||||
get_wl_output_from_output(wlr_output);
|
wlr_renderer_bind_buffer(output->backend->renderer, NULL);
|
||||||
wlr_egl_unset_current(&output->backend->egl);
|
wlr_egl_unset_current(&output->backend->egl);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -341,19 +407,30 @@ static bool output_set_cursor(struct wlr_output *wlr_output,
|
||||||
width = width * wlr_output->scale / scale;
|
width = width * wlr_output->scale / scale;
|
||||||
height = height * wlr_output->scale / scale;
|
height = height * wlr_output->scale / scale;
|
||||||
|
|
||||||
output->cursor.width = width;
|
if (output->cursor.swapchain == NULL ||
|
||||||
output->cursor.height = height;
|
output->cursor.swapchain->width != width ||
|
||||||
|
output->cursor.swapchain->height != height) {
|
||||||
if (output->cursor.egl_window == NULL) {
|
wlr_swapchain_destroy(output->cursor.swapchain);
|
||||||
output->cursor.egl_window =
|
output->cursor.swapchain = wlr_swapchain_create(
|
||||||
wl_egl_window_create(surface, width, height);
|
output->backend->allocator, width, height,
|
||||||
|
output->backend->format);
|
||||||
|
if (output->cursor.swapchain == NULL) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
wl_egl_window_resize(output->cursor.egl_window, width, height, 0, 0);
|
|
||||||
|
|
||||||
EGLSurface egl_surface =
|
struct wlr_buffer *wlr_buffer =
|
||||||
wlr_egl_create_surface(&backend->egl, output->cursor.egl_window);
|
wlr_swapchain_acquire(output->cursor.swapchain, NULL);
|
||||||
|
if (wlr_buffer == NULL) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
wlr_egl_make_current(&backend->egl, egl_surface, NULL);
|
if (!wlr_egl_make_current(&output->backend->egl, EGL_NO_SURFACE, NULL)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!wlr_renderer_bind_buffer(output->backend->renderer, wlr_buffer)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
struct wlr_box cursor_box = {
|
struct wlr_box cursor_box = {
|
||||||
.width = width,
|
.width = width,
|
||||||
|
|
@ -371,8 +448,23 @@ static bool output_set_cursor(struct wlr_output *wlr_output,
|
||||||
wlr_render_texture_with_matrix(backend->renderer, texture, matrix, 1.0);
|
wlr_render_texture_with_matrix(backend->renderer, texture, matrix, 1.0);
|
||||||
wlr_renderer_end(backend->renderer);
|
wlr_renderer_end(backend->renderer);
|
||||||
|
|
||||||
wlr_egl_swap_buffers(&backend->egl, egl_surface, NULL);
|
wlr_renderer_bind_buffer(output->backend->renderer, NULL);
|
||||||
wlr_egl_destroy_surface(&backend->egl, egl_surface);
|
wlr_egl_unset_current(&output->backend->egl);
|
||||||
|
|
||||||
|
struct wlr_wl_buffer *buffer =
|
||||||
|
create_wl_buffer(output->backend, wlr_buffer);
|
||||||
|
if (buffer == NULL) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
wl_surface_attach(surface, buffer->wl_buffer, 0, 0);
|
||||||
|
wl_surface_damage_buffer(surface, 0, 0, INT32_MAX, INT32_MAX);
|
||||||
|
wl_surface_commit(surface);
|
||||||
|
|
||||||
|
wlr_buffer_unlock(wlr_buffer);
|
||||||
|
|
||||||
|
output->cursor.width = width;
|
||||||
|
output->cursor.height = height;
|
||||||
} else {
|
} else {
|
||||||
wl_surface_attach(surface, NULL, 0, 0);
|
wl_surface_attach(surface, NULL, 0, 0);
|
||||||
wl_surface_commit(surface);
|
wl_surface_commit(surface);
|
||||||
|
|
@ -390,9 +482,7 @@ static void output_destroy(struct wlr_output *wlr_output) {
|
||||||
|
|
||||||
wl_list_remove(&output->link);
|
wl_list_remove(&output->link);
|
||||||
|
|
||||||
if (output->cursor.egl_window != NULL) {
|
wlr_swapchain_destroy(output->cursor.swapchain);
|
||||||
wl_egl_window_destroy(output->cursor.egl_window);
|
|
||||||
}
|
|
||||||
if (output->cursor.surface) {
|
if (output->cursor.surface) {
|
||||||
wl_surface_destroy(output->cursor.surface);
|
wl_surface_destroy(output->cursor.surface);
|
||||||
}
|
}
|
||||||
|
|
@ -407,8 +497,8 @@ static void output_destroy(struct wlr_output *wlr_output) {
|
||||||
presentation_feedback_destroy(feedback);
|
presentation_feedback_destroy(feedback);
|
||||||
}
|
}
|
||||||
|
|
||||||
wlr_egl_destroy_surface(&output->backend->egl, output->egl_surface);
|
wlr_buffer_unlock(output->back_buffer);
|
||||||
wl_egl_window_destroy(output->egl_window);
|
wlr_swapchain_destroy(output->swapchain);
|
||||||
if (output->zxdg_toplevel_decoration_v1) {
|
if (output->zxdg_toplevel_decoration_v1) {
|
||||||
zxdg_toplevel_decoration_v1_destroy(output->zxdg_toplevel_decoration_v1);
|
zxdg_toplevel_decoration_v1_destroy(output->zxdg_toplevel_decoration_v1);
|
||||||
}
|
}
|
||||||
|
|
@ -419,8 +509,11 @@ static void output_destroy(struct wlr_output *wlr_output) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void update_wl_output_cursor(struct wlr_wl_output *output) {
|
void update_wl_output_cursor(struct wlr_wl_output *output) {
|
||||||
if (output->backend->pointer && output->enter_serial) {
|
struct wlr_wl_pointer *pointer = output->cursor.pointer;
|
||||||
wl_pointer_set_cursor(output->backend->pointer, output->enter_serial,
|
if (pointer) {
|
||||||
|
assert(pointer->output == output);
|
||||||
|
assert(output->enter_serial);
|
||||||
|
wl_pointer_set_cursor(pointer->wl_pointer, output->enter_serial,
|
||||||
output->cursor.surface, output->cursor.hotspot_x,
|
output->cursor.surface, output->cursor.hotspot_x,
|
||||||
output->cursor.hotspot_y);
|
output->cursor.hotspot_y);
|
||||||
}
|
}
|
||||||
|
|
@ -555,40 +648,29 @@ struct wlr_output *wlr_wl_output_create(struct wlr_backend *wlr_backend) {
|
||||||
&xdg_toplevel_listener, output);
|
&xdg_toplevel_listener, output);
|
||||||
wl_surface_commit(output->surface);
|
wl_surface_commit(output->surface);
|
||||||
|
|
||||||
output->egl_window = wl_egl_window_create(output->surface,
|
output->swapchain = wlr_swapchain_create(output->backend->allocator,
|
||||||
wlr_output->width, wlr_output->height);
|
wlr_output->width, wlr_output->height, output->backend->format);
|
||||||
output->egl_surface = wlr_egl_create_surface(&backend->egl,
|
if (output->swapchain == NULL) {
|
||||||
output->egl_window);
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
wl_display_roundtrip(output->backend->remote_display);
|
wl_display_roundtrip(output->backend->remote_display);
|
||||||
|
|
||||||
// start rendering loop per callbacks by rendering first frame
|
|
||||||
if (!wlr_egl_make_current(&output->backend->egl, output->egl_surface,
|
|
||||||
NULL)) {
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
wlr_renderer_begin(backend->renderer, wlr_output->width, wlr_output->height);
|
|
||||||
wlr_renderer_clear(backend->renderer, (float[]){ 1.0, 1.0, 1.0, 1.0 });
|
|
||||||
wlr_renderer_end(backend->renderer);
|
|
||||||
|
|
||||||
output->frame_callback = wl_surface_frame(output->surface);
|
|
||||||
wl_callback_add_listener(output->frame_callback, &frame_listener, output);
|
|
||||||
|
|
||||||
if (!wlr_egl_swap_buffers(&output->backend->egl, output->egl_surface,
|
|
||||||
NULL)) {
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
wl_list_insert(&backend->outputs, &output->link);
|
wl_list_insert(&backend->outputs, &output->link);
|
||||||
wlr_output_update_enabled(wlr_output, true);
|
wlr_output_update_enabled(wlr_output, true);
|
||||||
|
|
||||||
wlr_signal_emit_safe(&backend->backend.events.new_output, wlr_output);
|
wlr_signal_emit_safe(&backend->backend.events.new_output, wlr_output);
|
||||||
|
|
||||||
if (backend->pointer != NULL) {
|
struct wlr_wl_seat *seat;
|
||||||
create_wl_pointer(backend->pointer, output);
|
wl_list_for_each(seat, &backend->seats, link) {
|
||||||
|
if (seat->pointer) {
|
||||||
|
create_wl_pointer(seat, output);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Start the rendering loop by requesting the compositor to render a frame
|
||||||
|
wlr_output_schedule_frame(wlr_output);
|
||||||
|
|
||||||
return wlr_output;
|
return wlr_output;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
|
|
|
||||||
|
|
@ -22,14 +22,16 @@
|
||||||
#include "util/signal.h"
|
#include "util/signal.h"
|
||||||
#include "util/time.h"
|
#include "util/time.h"
|
||||||
|
|
||||||
static struct wlr_wl_pointer *output_get_pointer(struct wlr_wl_output *output) {
|
static struct wlr_wl_pointer *output_get_pointer(
|
||||||
|
struct wlr_wl_output *output,
|
||||||
|
const struct wl_pointer *wl_pointer) {
|
||||||
struct wlr_input_device *wlr_dev;
|
struct wlr_input_device *wlr_dev;
|
||||||
wl_list_for_each(wlr_dev, &output->backend->devices, link) {
|
wl_list_for_each(wlr_dev, &output->backend->devices, link) {
|
||||||
if (wlr_dev->type != WLR_INPUT_DEVICE_POINTER) {
|
if (wlr_dev->type != WLR_INPUT_DEVICE_POINTER) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
struct wlr_wl_pointer *pointer = pointer_get_wl(wlr_dev->pointer);
|
struct wlr_wl_pointer *pointer = pointer_get_wl(wlr_dev->pointer);
|
||||||
if (pointer->output == output) {
|
if (pointer->output == output && pointer->wl_pointer == wl_pointer) {
|
||||||
return pointer;
|
return pointer;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -40,43 +42,54 @@ static struct wlr_wl_pointer *output_get_pointer(struct wlr_wl_output *output) {
|
||||||
static void pointer_handle_enter(void *data, struct wl_pointer *wl_pointer,
|
static void pointer_handle_enter(void *data, struct wl_pointer *wl_pointer,
|
||||||
uint32_t serial, struct wl_surface *surface, wl_fixed_t sx,
|
uint32_t serial, struct wl_surface *surface, wl_fixed_t sx,
|
||||||
wl_fixed_t sy) {
|
wl_fixed_t sy) {
|
||||||
struct wlr_wl_backend *backend = data;
|
struct wlr_wl_seat *seat = data;
|
||||||
if (surface == NULL) {
|
if (surface == NULL) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct wlr_wl_output *output = wl_surface_get_user_data(surface);
|
struct wlr_wl_output *output = wl_surface_get_user_data(surface);
|
||||||
assert(output);
|
assert(output);
|
||||||
struct wlr_wl_pointer *pointer = output_get_pointer(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->enter_serial = serial;
|
||||||
backend->current_pointer = pointer;
|
output->cursor.pointer = pointer;
|
||||||
update_wl_output_cursor(output);
|
update_wl_output_cursor(output);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void pointer_handle_leave(void *data, struct wl_pointer *wl_pointer,
|
static void pointer_handle_leave(void *data, struct wl_pointer *wl_pointer,
|
||||||
uint32_t serial, struct wl_surface *surface) {
|
uint32_t serial, struct wl_surface *surface) {
|
||||||
struct wlr_wl_backend *backend = data;
|
struct wlr_wl_seat *seat = data;
|
||||||
if (surface == NULL) {
|
if (surface == NULL) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct wlr_wl_output *output = wl_surface_get_user_data(surface);
|
struct wlr_wl_output *output = wl_surface_get_user_data(surface);
|
||||||
assert(output);
|
assert(output);
|
||||||
output->enter_serial = 0;
|
|
||||||
|
|
||||||
if (backend->current_pointer == NULL ||
|
if (seat->active_pointer != NULL &&
|
||||||
backend->current_pointer->output != output) {
|
seat->active_pointer->output == output) {
|
||||||
return;
|
seat->active_pointer = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
backend->current_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,
|
static void pointer_handle_motion(void *data, struct wl_pointer *wl_pointer,
|
||||||
uint32_t time, wl_fixed_t sx, wl_fixed_t sy) {
|
uint32_t time, wl_fixed_t sx, wl_fixed_t sy) {
|
||||||
struct wlr_wl_backend *backend = data;
|
struct wlr_wl_seat *seat = data;
|
||||||
struct wlr_wl_pointer *pointer = backend->current_pointer;
|
struct wlr_wl_pointer *pointer = seat->active_pointer;
|
||||||
if (pointer == NULL) {
|
if (pointer == NULL) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -93,8 +106,8 @@ static void pointer_handle_motion(void *data, struct wl_pointer *wl_pointer,
|
||||||
|
|
||||||
static void pointer_handle_button(void *data, struct wl_pointer *wl_pointer,
|
static void pointer_handle_button(void *data, struct wl_pointer *wl_pointer,
|
||||||
uint32_t serial, uint32_t time, uint32_t button, uint32_t state) {
|
uint32_t serial, uint32_t time, uint32_t button, uint32_t state) {
|
||||||
struct wlr_wl_backend *backend = data;
|
struct wlr_wl_seat *seat = data;
|
||||||
struct wlr_wl_pointer *pointer = backend->current_pointer;
|
struct wlr_wl_pointer *pointer = seat->active_pointer;
|
||||||
if (pointer == NULL) {
|
if (pointer == NULL) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -110,8 +123,8 @@ static void pointer_handle_button(void *data, struct wl_pointer *wl_pointer,
|
||||||
|
|
||||||
static void pointer_handle_axis(void *data, struct wl_pointer *wl_pointer,
|
static void pointer_handle_axis(void *data, struct wl_pointer *wl_pointer,
|
||||||
uint32_t time, uint32_t axis, wl_fixed_t value) {
|
uint32_t time, uint32_t axis, wl_fixed_t value) {
|
||||||
struct wlr_wl_backend *backend = data;
|
struct wlr_wl_seat *seat = data;
|
||||||
struct wlr_wl_pointer *pointer = backend->current_pointer;
|
struct wlr_wl_pointer *pointer = seat->active_pointer;
|
||||||
if (pointer == NULL) {
|
if (pointer == NULL) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -130,8 +143,8 @@ static void pointer_handle_axis(void *data, struct wl_pointer *wl_pointer,
|
||||||
}
|
}
|
||||||
|
|
||||||
static void pointer_handle_frame(void *data, struct wl_pointer *wl_pointer) {
|
static void pointer_handle_frame(void *data, struct wl_pointer *wl_pointer) {
|
||||||
struct wlr_wl_backend *backend = data;
|
struct wlr_wl_seat *seat = data;
|
||||||
struct wlr_wl_pointer *pointer = backend->current_pointer;
|
struct wlr_wl_pointer *pointer = seat->active_pointer;
|
||||||
if (pointer == NULL) {
|
if (pointer == NULL) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -142,8 +155,8 @@ static void pointer_handle_frame(void *data, struct wl_pointer *wl_pointer) {
|
||||||
|
|
||||||
static void pointer_handle_axis_source(void *data,
|
static void pointer_handle_axis_source(void *data,
|
||||||
struct wl_pointer *wl_pointer, uint32_t axis_source) {
|
struct wl_pointer *wl_pointer, uint32_t axis_source) {
|
||||||
struct wlr_wl_backend *backend = data;
|
struct wlr_wl_seat *seat = data;
|
||||||
struct wlr_wl_pointer *pointer = backend->current_pointer;
|
struct wlr_wl_pointer *pointer = seat->active_pointer;
|
||||||
if (pointer == NULL) {
|
if (pointer == NULL) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -153,8 +166,8 @@ static void pointer_handle_axis_source(void *data,
|
||||||
|
|
||||||
static void pointer_handle_axis_stop(void *data, struct wl_pointer *wl_pointer,
|
static void pointer_handle_axis_stop(void *data, struct wl_pointer *wl_pointer,
|
||||||
uint32_t time, uint32_t axis) {
|
uint32_t time, uint32_t axis) {
|
||||||
struct wlr_wl_backend *backend = data;
|
struct wlr_wl_seat *seat = data;
|
||||||
struct wlr_wl_pointer *pointer = backend->current_pointer;
|
struct wlr_wl_pointer *pointer = seat->active_pointer;
|
||||||
if (pointer == NULL) {
|
if (pointer == NULL) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -172,8 +185,8 @@ static void pointer_handle_axis_stop(void *data, struct wl_pointer *wl_pointer,
|
||||||
|
|
||||||
static void pointer_handle_axis_discrete(void *data,
|
static void pointer_handle_axis_discrete(void *data,
|
||||||
struct wl_pointer *wl_pointer, uint32_t axis, int32_t discrete) {
|
struct wl_pointer *wl_pointer, uint32_t axis, int32_t discrete) {
|
||||||
struct wlr_wl_backend *backend = data;
|
struct wlr_wl_seat *seat = data;
|
||||||
struct wlr_wl_pointer *pointer = backend->current_pointer;
|
struct wlr_wl_pointer *pointer = seat->active_pointer;
|
||||||
if (pointer == NULL) {
|
if (pointer == NULL) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -208,7 +221,7 @@ static void keyboard_handle_enter(void *data, struct wl_keyboard *wl_keyboard,
|
||||||
wl_array_for_each(keycode_ptr, keys) {
|
wl_array_for_each(keycode_ptr, keys) {
|
||||||
struct wlr_event_keyboard_key event = {
|
struct wlr_event_keyboard_key event = {
|
||||||
.keycode = *keycode_ptr,
|
.keycode = *keycode_ptr,
|
||||||
.state = WLR_KEY_PRESSED,
|
.state = WL_KEYBOARD_KEY_STATE_PRESSED,
|
||||||
.time_msec = time,
|
.time_msec = time,
|
||||||
.update_state = false,
|
.update_state = false,
|
||||||
};
|
};
|
||||||
|
|
@ -231,7 +244,7 @@ static void keyboard_handle_leave(void *data, struct wl_keyboard *wl_keyboard,
|
||||||
|
|
||||||
struct wlr_event_keyboard_key event = {
|
struct wlr_event_keyboard_key event = {
|
||||||
.keycode = keycode,
|
.keycode = keycode,
|
||||||
.state = WLR_KEY_RELEASED,
|
.state = WL_KEYBOARD_KEY_STATE_RELEASED,
|
||||||
.time_msec = time,
|
.time_msec = time,
|
||||||
.update_state = false,
|
.update_state = false,
|
||||||
};
|
};
|
||||||
|
|
@ -276,19 +289,153 @@ static struct wl_keyboard_listener keyboard_listener = {
|
||||||
.repeat_info = keyboard_handle_repeat_info
|
.repeat_info = keyboard_handle_repeat_info
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static void touch_coordinates_to_absolute(struct wlr_wl_input_device *device,
|
||||||
|
wl_fixed_t x, wl_fixed_t y, double *sx, double *sy) {
|
||||||
|
// TODO: each output needs its own touch
|
||||||
|
struct wlr_wl_output *output, *tmp;
|
||||||
|
wl_list_for_each_safe(output, tmp, &device->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
|
||||||
|
}
|
||||||
|
|
||||||
|
*sx = *sy = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
double sx, sy;
|
||||||
|
touch_coordinates_to_absolute(device, x, y, &sx, &sy);
|
||||||
|
struct wlr_event_touch_down event = {
|
||||||
|
.device = &device->wlr_input_device,
|
||||||
|
.time_msec = time,
|
||||||
|
.touch_id = id,
|
||||||
|
.x = sx,
|
||||||
|
.y = sy
|
||||||
|
};
|
||||||
|
wlr_signal_emit_safe(&device->wlr_input_device.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_event_touch_up event = {
|
||||||
|
.device = &device->wlr_input_device,
|
||||||
|
.time_msec = time,
|
||||||
|
.touch_id = id,
|
||||||
|
};
|
||||||
|
wlr_signal_emit_safe(&device->wlr_input_device.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);
|
||||||
|
|
||||||
|
double sx, sy;
|
||||||
|
touch_coordinates_to_absolute(device, x, y, &sx, &sy);
|
||||||
|
struct wlr_event_touch_motion event = {
|
||||||
|
.device = &device->wlr_input_device,
|
||||||
|
.time_msec = time,
|
||||||
|
.touch_id = id,
|
||||||
|
.x = sx,
|
||||||
|
.y = sy
|
||||||
|
};
|
||||||
|
wlr_signal_emit_safe(&device->wlr_input_device.touch->events.motion, &event);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void touch_handle_frame(void *data, struct wl_touch *wl_touch) {
|
||||||
|
// no-op
|
||||||
|
}
|
||||||
|
|
||||||
|
static void touch_handle_cancel(void *data, struct wl_touch *wl_touch) {
|
||||||
|
// no-op
|
||||||
|
}
|
||||||
|
|
||||||
|
static void touch_handle_shape(void *data, struct wl_touch *wl_touch,
|
||||||
|
int32_t id, wl_fixed_t major, wl_fixed_t minor) {
|
||||||
|
// no-op
|
||||||
|
}
|
||||||
|
|
||||||
|
static void touch_handle_orientation(void *data, struct wl_touch *wl_touch,
|
||||||
|
int32_t id, wl_fixed_t orientation) {
|
||||||
|
// no-op
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct wl_touch_listener touch_listener = {
|
||||||
|
.down = touch_handle_down,
|
||||||
|
.up = touch_handle_up,
|
||||||
|
.motion = touch_handle_motion,
|
||||||
|
.frame = touch_handle_frame,
|
||||||
|
.cancel = touch_handle_cancel,
|
||||||
|
.shape = touch_handle_shape,
|
||||||
|
.orientation = touch_handle_orientation,
|
||||||
|
};
|
||||||
|
|
||||||
static struct wlr_wl_input_device *get_wl_input_device_from_input_device(
|
static struct wlr_wl_input_device *get_wl_input_device_from_input_device(
|
||||||
struct wlr_input_device *wlr_dev) {
|
struct wlr_input_device *wlr_dev) {
|
||||||
assert(wlr_input_device_is_wl(wlr_dev));
|
assert(wlr_input_device_is_wl(wlr_dev));
|
||||||
return (struct wlr_wl_input_device *)wlr_dev;
|
return (struct wlr_wl_input_device *)wlr_dev;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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) {
|
||||||
|
wlr_log_errno(WLR_ERROR, "Allocation failed");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
seat->wl_seat = wl_seat;
|
||||||
|
seat->backend = wl;
|
||||||
|
wl_list_insert(&wl->seats, &seat->link);
|
||||||
|
wl_seat_add_listener(wl_seat, &seat_listener, seat);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
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->pointer) {
|
||||||
|
wl_pointer_destroy(seat->pointer);
|
||||||
|
}
|
||||||
|
if (seat->keyboard && !wl->started) {
|
||||||
|
// early termination will not be handled by input_device_destroy
|
||||||
|
wl_keyboard_destroy(seat->keyboard);
|
||||||
|
}
|
||||||
|
free(seat->name);
|
||||||
|
assert(seat->wl_seat);
|
||||||
|
wl_seat_destroy(seat->wl_seat);
|
||||||
|
|
||||||
|
wl_list_remove(&seat->link);
|
||||||
|
free(seat);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
static void input_device_destroy(struct wlr_input_device *wlr_dev) {
|
static void input_device_destroy(struct wlr_input_device *wlr_dev) {
|
||||||
struct wlr_wl_input_device *dev =
|
struct wlr_wl_input_device *dev =
|
||||||
get_wl_input_device_from_input_device(wlr_dev);
|
get_wl_input_device_from_input_device(wlr_dev);
|
||||||
if (dev->wlr_input_device.type == WLR_INPUT_DEVICE_KEYBOARD) {
|
if (dev->wlr_input_device.type == WLR_INPUT_DEVICE_KEYBOARD) {
|
||||||
wl_keyboard_release(dev->backend->keyboard);
|
struct wlr_wl_seat *seat = input_device_get_seat(wlr_dev);
|
||||||
dev->backend->keyboard = NULL;
|
wl_keyboard_release(seat->keyboard);
|
||||||
|
seat->keyboard = NULL;
|
||||||
}
|
}
|
||||||
|
// We can't destroy pointer here because we might have multiple devices
|
||||||
|
// exposing it to compositor.
|
||||||
wl_list_remove(&dev->wlr_input_device.link);
|
wl_list_remove(&dev->wlr_input_device.link);
|
||||||
free(dev);
|
free(dev);
|
||||||
}
|
}
|
||||||
|
|
@ -302,22 +449,27 @@ bool wlr_input_device_is_wl(struct wlr_input_device *dev) {
|
||||||
}
|
}
|
||||||
|
|
||||||
struct wlr_wl_input_device *create_wl_input_device(
|
struct wlr_wl_input_device *create_wl_input_device(
|
||||||
struct wlr_wl_backend *backend, enum wlr_input_device_type type) {
|
struct wlr_wl_seat *seat, enum wlr_input_device_type type) {
|
||||||
struct wlr_wl_input_device *dev =
|
struct wlr_wl_input_device *dev =
|
||||||
calloc(1, sizeof(struct wlr_wl_input_device));
|
calloc(1, sizeof(struct wlr_wl_input_device));
|
||||||
if (dev == NULL) {
|
if (dev == NULL) {
|
||||||
wlr_log_errno(WLR_ERROR, "Allocation failed");
|
wlr_log_errno(WLR_ERROR, "Allocation failed");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
dev->backend = backend;
|
dev->backend = seat->backend;
|
||||||
|
dev->seat = seat;
|
||||||
|
|
||||||
struct wlr_input_device *wlr_dev = &dev->wlr_input_device;
|
struct wlr_input_device *wlr_dev = &dev->wlr_input_device;
|
||||||
|
|
||||||
unsigned int vendor = 0, product = 0;
|
unsigned int vendor = 0, product = 0;
|
||||||
const char *name = "wayland";
|
|
||||||
|
size_t name_size = 8 + strlen(seat->name) + 1;
|
||||||
|
char name[name_size];
|
||||||
|
(void) snprintf(name, name_size, "wayland-%s", seat->name);
|
||||||
|
|
||||||
wlr_input_device_init(wlr_dev, type, &input_device_impl, name, vendor,
|
wlr_input_device_init(wlr_dev, type, &input_device_impl, name, vendor,
|
||||||
product);
|
product);
|
||||||
wl_list_insert(&backend->devices, &wlr_dev->link);
|
wl_list_insert(&seat->backend->devices, &wlr_dev->link);
|
||||||
return dev;
|
return dev;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -331,8 +483,13 @@ struct wlr_wl_pointer *pointer_get_wl(struct wlr_pointer *wlr_pointer) {
|
||||||
static void pointer_destroy(struct wlr_pointer *wlr_pointer) {
|
static void pointer_destroy(struct wlr_pointer *wlr_pointer) {
|
||||||
struct wlr_wl_pointer *pointer = pointer_get_wl(wlr_pointer);
|
struct wlr_wl_pointer *pointer = pointer_get_wl(wlr_pointer);
|
||||||
|
|
||||||
if (pointer->output->backend->current_pointer == pointer) {
|
if (pointer->output->cursor.pointer == pointer) {
|
||||||
pointer->output->backend->current_pointer = NULL;
|
pointer->output->cursor.pointer = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct wlr_wl_seat *seat = pointer->input_device->seat;
|
||||||
|
if (seat->active_pointer == pointer) {
|
||||||
|
seat->active_pointer = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
wl_list_remove(&pointer->output_destroy.link);
|
wl_list_remove(&pointer->output_destroy.link);
|
||||||
|
|
@ -450,6 +607,9 @@ static void relative_pointer_handle_relative_motion(void *data,
|
||||||
wl_fixed_t dy_unaccel) {
|
wl_fixed_t dy_unaccel) {
|
||||||
struct wlr_wl_input_device *input_device = data;
|
struct wlr_wl_input_device *input_device = data;
|
||||||
struct wlr_input_device *wlr_dev = &input_device->wlr_input_device;
|
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;
|
uint64_t time_usec = (uint64_t)utime_hi << 32 | utime_lo;
|
||||||
|
|
||||||
|
|
@ -473,21 +633,22 @@ static void pointer_handle_output_destroy(struct wl_listener *listener,
|
||||||
void *data) {
|
void *data) {
|
||||||
struct wlr_wl_pointer *pointer =
|
struct wlr_wl_pointer *pointer =
|
||||||
wl_container_of(listener, pointer, output_destroy);
|
wl_container_of(listener, pointer, output_destroy);
|
||||||
|
if (pointer->relative_pointer) {
|
||||||
|
zwp_relative_pointer_v1_destroy(pointer->relative_pointer);
|
||||||
|
}
|
||||||
wlr_input_device_destroy(&pointer->input_device->wlr_input_device);
|
wlr_input_device_destroy(&pointer->input_device->wlr_input_device);
|
||||||
}
|
}
|
||||||
|
|
||||||
void create_wl_pointer(struct wl_pointer *wl_pointer, struct wlr_wl_output *output) {
|
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;
|
struct wlr_wl_backend *backend = output->backend;
|
||||||
|
|
||||||
struct wlr_input_device *wlr_dev;
|
if (output_get_pointer(output, wl_pointer)) {
|
||||||
wl_list_for_each(wlr_dev, &output->backend->devices, link) {
|
wlr_log(WLR_DEBUG,
|
||||||
if (wlr_dev->type != WLR_INPUT_DEVICE_POINTER) {
|
"Pointer for seat %s and output %s already exists (ignoring)",
|
||||||
continue;
|
seat->name, output->wlr_output.name);
|
||||||
}
|
return;
|
||||||
struct wlr_wl_pointer *pointer = pointer_get_wl(wlr_dev->pointer);
|
|
||||||
if (pointer->output == output) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct wlr_wl_pointer *pointer = calloc(1, sizeof(struct wlr_wl_pointer));
|
struct wlr_wl_pointer *pointer = calloc(1, sizeof(struct wlr_wl_pointer));
|
||||||
|
|
@ -496,13 +657,10 @@ void create_wl_pointer(struct wl_pointer *wl_pointer, struct wlr_wl_output *outp
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
pointer->wl_pointer = wl_pointer;
|
pointer->wl_pointer = wl_pointer;
|
||||||
pointer->output = output;
|
pointer->output = output; // we need output to map absolute coordinates onto
|
||||||
|
|
||||||
wl_signal_add(&output->wlr_output.events.destroy, &pointer->output_destroy);
|
|
||||||
pointer->output_destroy.notify = pointer_handle_output_destroy;
|
|
||||||
|
|
||||||
struct wlr_wl_input_device *dev =
|
struct wlr_wl_input_device *dev =
|
||||||
create_wl_input_device(backend, WLR_INPUT_DEVICE_POINTER);
|
create_wl_input_device(seat, WLR_INPUT_DEVICE_POINTER);
|
||||||
if (dev == NULL) {
|
if (dev == NULL) {
|
||||||
free(pointer);
|
free(pointer);
|
||||||
wlr_log(WLR_ERROR, "Allocation failed");
|
wlr_log(WLR_ERROR, "Allocation failed");
|
||||||
|
|
@ -510,7 +668,10 @@ void create_wl_pointer(struct wl_pointer *wl_pointer, struct wlr_wl_output *outp
|
||||||
}
|
}
|
||||||
pointer->input_device = dev;
|
pointer->input_device = dev;
|
||||||
|
|
||||||
wlr_dev = &dev->wlr_input_device;
|
wl_signal_add(&output->wlr_output.events.destroy, &pointer->output_destroy);
|
||||||
|
pointer->output_destroy.notify = pointer_handle_output_destroy;
|
||||||
|
|
||||||
|
struct wlr_input_device *wlr_dev = &dev->wlr_input_device;
|
||||||
wlr_dev->pointer = &pointer->wlr_pointer;
|
wlr_dev->pointer = &pointer->wlr_pointer;
|
||||||
wlr_dev->output_name = strdup(output->wlr_output.name);
|
wlr_dev->output_name = strdup(output->wlr_output.name);
|
||||||
wlr_pointer_init(wlr_dev->pointer, &pointer_impl);
|
wlr_pointer_init(wlr_dev->pointer, &pointer_impl);
|
||||||
|
|
@ -532,13 +693,15 @@ void create_wl_pointer(struct wl_pointer *wl_pointer, struct wlr_wl_output *outp
|
||||||
&relative_pointer_listener, dev);
|
&relative_pointer_listener, dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
wl_pointer_add_listener(wl_pointer, &pointer_listener, backend);
|
wl_pointer_add_listener(wl_pointer, &pointer_listener, seat);
|
||||||
wlr_signal_emit_safe(&backend->backend.events.new_input, wlr_dev);
|
wlr_signal_emit_safe(&backend->backend.events.new_input, wlr_dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
void create_wl_keyboard(struct wl_keyboard *wl_keyboard, struct wlr_wl_backend *wl) {
|
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 =
|
struct wlr_wl_input_device *dev =
|
||||||
create_wl_input_device(wl, WLR_INPUT_DEVICE_KEYBOARD);
|
create_wl_input_device(seat, WLR_INPUT_DEVICE_KEYBOARD);
|
||||||
if (!dev) {
|
if (!dev) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -548,75 +711,138 @@ void create_wl_keyboard(struct wl_keyboard *wl_keyboard, struct wlr_wl_backend *
|
||||||
wlr_dev->keyboard = calloc(1, sizeof(*wlr_dev->keyboard));
|
wlr_dev->keyboard = calloc(1, sizeof(*wlr_dev->keyboard));
|
||||||
if (!wlr_dev->keyboard) {
|
if (!wlr_dev->keyboard) {
|
||||||
wlr_log_errno(WLR_ERROR, "Allocation failed");
|
wlr_log_errno(WLR_ERROR, "Allocation failed");
|
||||||
free(dev);
|
wlr_input_device_destroy(wlr_dev);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
wlr_keyboard_init(wlr_dev->keyboard, NULL);
|
wlr_keyboard_init(wlr_dev->keyboard, NULL);
|
||||||
|
|
||||||
wl_keyboard_add_listener(wl_keyboard, &keyboard_listener, wlr_dev);
|
wl_keyboard_add_listener(wl_keyboard, &keyboard_listener, wlr_dev);
|
||||||
wlr_signal_emit_safe(&wl->backend.events.new_input, 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");
|
||||||
|
wlr_input_device_destroy(wlr_dev);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
wlr_touch_init(wlr_dev->touch, NULL);
|
||||||
|
|
||||||
|
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,
|
static void seat_handle_capabilities(void *data, struct wl_seat *wl_seat,
|
||||||
enum wl_seat_capability caps) {
|
enum wl_seat_capability caps) {
|
||||||
struct wlr_wl_backend *backend = data;
|
struct wlr_wl_seat *seat = data;
|
||||||
assert(backend->seat == wl_seat);
|
struct wlr_wl_backend *backend = seat->backend;
|
||||||
|
|
||||||
if ((caps & WL_SEAT_CAPABILITY_POINTER) && backend->pointer == NULL) {
|
if ((caps & WL_SEAT_CAPABILITY_POINTER) && seat->pointer == NULL) {
|
||||||
wlr_log(WLR_DEBUG, "seat %p offered pointer", (void *)wl_seat);
|
wlr_log(WLR_DEBUG, "seat %p offered pointer", (void *)wl_seat);
|
||||||
|
|
||||||
struct wl_pointer *wl_pointer = wl_seat_get_pointer(wl_seat);
|
struct wl_pointer *wl_pointer = wl_seat_get_pointer(wl_seat);
|
||||||
backend->pointer = wl_pointer;
|
seat->pointer = wl_pointer;
|
||||||
|
|
||||||
struct wlr_wl_output *output;
|
struct wlr_wl_output *output;
|
||||||
wl_list_for_each(output, &backend->outputs, link) {
|
wl_list_for_each(output, &backend->outputs, link) {
|
||||||
create_wl_pointer(wl_pointer, output);
|
create_wl_pointer(seat, output);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!(caps & WL_SEAT_CAPABILITY_POINTER) && backend->pointer != NULL) {
|
if (!(caps & WL_SEAT_CAPABILITY_POINTER) && seat->pointer != NULL) {
|
||||||
wlr_log(WLR_DEBUG, "seat %p dropped pointer", (void *)wl_seat);
|
wlr_log(WLR_DEBUG, "seat %p dropped pointer", (void *)wl_seat);
|
||||||
|
|
||||||
|
struct wl_pointer *wl_pointer = seat->pointer;
|
||||||
|
|
||||||
struct wlr_input_device *device, *tmp;
|
struct wlr_input_device *device, *tmp;
|
||||||
wl_list_for_each_safe(device, tmp, &backend->devices, link) {
|
wl_list_for_each_safe(device, tmp, &backend->devices, link) {
|
||||||
if (device->type == WLR_INPUT_DEVICE_POINTER) {
|
if (device->type != WLR_INPUT_DEVICE_POINTER) {
|
||||||
wlr_input_device_destroy(device);
|
continue;
|
||||||
}
|
}
|
||||||
|
struct wlr_wl_pointer *pointer = pointer_get_wl(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;
|
||||||
|
wlr_input_device_destroy(device);
|
||||||
|
assert(seat->active_pointer != pointer);
|
||||||
|
assert(output->cursor.pointer != pointer);
|
||||||
}
|
}
|
||||||
|
|
||||||
wl_pointer_release(backend->pointer);
|
wl_pointer_release(seat->pointer);
|
||||||
backend->pointer = NULL;
|
seat->pointer = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((caps & WL_SEAT_CAPABILITY_KEYBOARD) && backend->keyboard == NULL) {
|
if ((caps & WL_SEAT_CAPABILITY_KEYBOARD) && seat->keyboard == NULL) {
|
||||||
wlr_log(WLR_DEBUG, "seat %p offered keyboard", (void *)wl_seat);
|
wlr_log(WLR_DEBUG, "seat %p offered keyboard", (void *)wl_seat);
|
||||||
|
|
||||||
struct wl_keyboard *wl_keyboard = wl_seat_get_keyboard(wl_seat);
|
struct wl_keyboard *wl_keyboard = wl_seat_get_keyboard(wl_seat);
|
||||||
backend->keyboard = wl_keyboard;
|
seat->keyboard = wl_keyboard;
|
||||||
|
|
||||||
if (backend->started) {
|
if (backend->started) {
|
||||||
create_wl_keyboard(wl_keyboard, backend);
|
create_wl_keyboard(seat);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!(caps & WL_SEAT_CAPABILITY_KEYBOARD) && backend->keyboard != NULL) {
|
if (!(caps & WL_SEAT_CAPABILITY_KEYBOARD) && seat->keyboard != NULL) {
|
||||||
wlr_log(WLR_DEBUG, "seat %p dropped keyboard", (void *)wl_seat);
|
wlr_log(WLR_DEBUG, "seat %p dropped keyboard", (void *)wl_seat);
|
||||||
|
|
||||||
struct wlr_input_device *device, *tmp;
|
struct wlr_input_device *device, *tmp;
|
||||||
wl_list_for_each_safe(device, tmp, &backend->devices, link) {
|
wl_list_for_each_safe(device, tmp, &backend->devices, link) {
|
||||||
if (device->type == WLR_INPUT_DEVICE_KEYBOARD) {
|
if (device->type != WLR_INPUT_DEVICE_KEYBOARD) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct wlr_wl_input_device *input_device =
|
||||||
|
get_wl_input_device_from_input_device(device);
|
||||||
|
if (input_device->seat != seat) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
wlr_input_device_destroy(device);
|
||||||
|
}
|
||||||
|
assert(seat->keyboard == NULL); // free'ed by input_device_destroy
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((caps & WL_SEAT_CAPABILITY_TOUCH) && seat->touch == NULL) {
|
||||||
|
wlr_log(WLR_DEBUG, "seat %p offered touch", (void *)wl_seat);
|
||||||
|
|
||||||
|
seat->touch = wl_seat_get_touch(wl_seat);
|
||||||
|
if (backend->started) {
|
||||||
|
create_wl_touch(seat);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!(caps & WL_SEAT_CAPABILITY_TOUCH) && seat->touch != NULL) {
|
||||||
|
wlr_log(WLR_DEBUG, "seat %p dropped touch", (void *)wl_seat);
|
||||||
|
|
||||||
|
struct wlr_input_device *device, *tmp;
|
||||||
|
wl_list_for_each_safe(device, tmp, &backend->devices, link) {
|
||||||
|
if (device->type == WLR_INPUT_DEVICE_TOUCH) {
|
||||||
wlr_input_device_destroy(device);
|
wlr_input_device_destroy(device);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
assert(backend->keyboard == NULL); // free'ed by input_device_destroy
|
|
||||||
|
wl_touch_release(seat->touch);
|
||||||
|
seat->touch = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void seat_handle_name(void *data, struct wl_seat *wl_seat,
|
static void seat_handle_name(void *data, struct wl_seat *wl_seat,
|
||||||
const char *name) {
|
const char *name) {
|
||||||
struct wlr_wl_backend *backend = data;
|
struct wlr_wl_seat *seat = data;
|
||||||
assert(backend->seat == wl_seat);
|
free(seat->name);
|
||||||
// Do we need to check if seatName was previously set for name change?
|
seat->name = strdup(name);
|
||||||
free(backend->seat_name);
|
|
||||||
backend->seat_name = strdup(name);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const struct wl_seat_listener seat_listener = {
|
const struct wl_seat_listener seat_listener = {
|
||||||
|
|
@ -625,7 +851,5 @@ const struct wl_seat_listener seat_listener = {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct wl_seat *wlr_wl_input_device_get_seat(struct wlr_input_device *wlr_dev) {
|
struct wl_seat *wlr_wl_input_device_get_seat(struct wlr_input_device *wlr_dev) {
|
||||||
struct wlr_wl_input_device *dev =
|
return input_device_get_seat(wlr_dev)->wl_seat;
|
||||||
get_wl_input_device_from_input_device(wlr_dev);
|
|
||||||
return dev->backend->seat;
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -429,9 +429,9 @@ static void handle_pad_added(void *data,
|
||||||
struct zwp_tablet_seat_v2 *zwp_tablet_seat_v2,
|
struct zwp_tablet_seat_v2 *zwp_tablet_seat_v2,
|
||||||
struct zwp_tablet_pad_v2 *id) {
|
struct zwp_tablet_pad_v2 *id) {
|
||||||
wlr_log(WLR_DEBUG, "New tablet pad");
|
wlr_log(WLR_DEBUG, "New tablet pad");
|
||||||
struct wlr_wl_backend *backend = data;
|
struct wlr_wl_seat *seat = data;
|
||||||
struct wlr_wl_input_device *dev = create_wl_input_device(
|
struct wlr_wl_input_device *dev = create_wl_input_device(
|
||||||
backend, WLR_INPUT_DEVICE_TABLET_PAD);
|
seat, WLR_INPUT_DEVICE_TABLET_PAD);
|
||||||
if (!dev) {
|
if (!dev) {
|
||||||
/* This leaks a couple of server-sent resource ids. iirc this
|
/* This leaks a couple of server-sent resource ids. iirc this
|
||||||
* shouldn't ever be a problem, but it isn't exactly nice
|
* shouldn't ever be a problem, but it isn't exactly nice
|
||||||
|
|
@ -889,9 +889,9 @@ static void handle_tab_added(void *data,
|
||||||
struct zwp_tablet_seat_v2 *zwp_tablet_seat_v2,
|
struct zwp_tablet_seat_v2 *zwp_tablet_seat_v2,
|
||||||
struct zwp_tablet_v2 *id) {
|
struct zwp_tablet_v2 *id) {
|
||||||
wlr_log(WLR_DEBUG, "New tablet");
|
wlr_log(WLR_DEBUG, "New tablet");
|
||||||
struct wlr_wl_backend *backend = data;
|
struct wlr_wl_seat *seat = data;
|
||||||
struct wlr_wl_input_device *dev = create_wl_input_device(
|
struct wlr_wl_input_device *dev = create_wl_input_device(
|
||||||
backend, WLR_INPUT_DEVICE_TABLET_TOOL);
|
seat, WLR_INPUT_DEVICE_TABLET_TOOL);
|
||||||
|
|
||||||
if (!dev) {
|
if (!dev) {
|
||||||
zwp_tablet_v2_destroy(id);
|
zwp_tablet_v2_destroy(id);
|
||||||
|
|
@ -919,18 +919,18 @@ static const struct zwp_tablet_seat_v2_listener tablet_seat_listener = {
|
||||||
|
|
||||||
struct wlr_wl_tablet_seat *wl_add_tablet_seat(
|
struct wlr_wl_tablet_seat *wl_add_tablet_seat(
|
||||||
struct zwp_tablet_manager_v2 *manager,
|
struct zwp_tablet_manager_v2 *manager,
|
||||||
struct wl_seat *seat, struct wlr_wl_backend *backend) {
|
struct wlr_wl_seat *seat) {
|
||||||
struct wlr_wl_tablet_seat *ret =
|
struct wlr_wl_tablet_seat *ret =
|
||||||
calloc(1, sizeof(struct wlr_wl_tablet_seat));
|
calloc(1, sizeof(struct wlr_wl_tablet_seat));
|
||||||
|
|
||||||
if (!(ret->tablet_seat =
|
if (!(ret->tablet_seat =
|
||||||
zwp_tablet_manager_v2_get_tablet_seat(manager, seat))) {
|
zwp_tablet_manager_v2_get_tablet_seat(manager, seat->wl_seat))) {
|
||||||
free(ret);
|
free(ret);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
zwp_tablet_seat_v2_add_listener(ret->tablet_seat,
|
zwp_tablet_seat_v2_add_listener(ret->tablet_seat,
|
||||||
&tablet_seat_listener, backend);
|
&tablet_seat_listener, seat);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,21 @@
|
||||||
#define _POSIX_C_SOURCE 200112L
|
#define _POSIX_C_SOURCE 200809L
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
#include <fcntl.h>
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
#include <wlr/config.h>
|
#include <wlr/config.h>
|
||||||
|
|
||||||
|
#include <drm_fourcc.h>
|
||||||
#include <X11/Xlib-xcb.h>
|
#include <X11/Xlib-xcb.h>
|
||||||
#include <wayland-server-core.h>
|
#include <wayland-server-core.h>
|
||||||
#include <xcb/xcb.h>
|
#include <xcb/xcb.h>
|
||||||
|
#include <xcb/dri3.h>
|
||||||
|
#include <xcb/present.h>
|
||||||
#include <xcb/xfixes.h>
|
#include <xcb/xfixes.h>
|
||||||
#include <xcb/xinput.h>
|
#include <xcb/xinput.h>
|
||||||
|
|
||||||
|
|
@ -25,8 +29,26 @@
|
||||||
#include <wlr/util/log.h>
|
#include <wlr/util/log.h>
|
||||||
|
|
||||||
#include "backend/x11.h"
|
#include "backend/x11.h"
|
||||||
|
#include "render/drm_format_set.h"
|
||||||
|
#include "render/gbm_allocator.h"
|
||||||
|
#include "render/wlr_renderer.h"
|
||||||
#include "util/signal.h"
|
#include "util/signal.h"
|
||||||
|
|
||||||
|
// See dri2_format_for_depth in mesa
|
||||||
|
const struct wlr_x11_format formats[] = {
|
||||||
|
{ .drm = DRM_FORMAT_XRGB8888, .depth = 24, .bpp = 32 },
|
||||||
|
{ .drm = DRM_FORMAT_ARGB8888, .depth = 32, .bpp = 32 },
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct wlr_x11_format *x11_format_from_depth(uint8_t depth) {
|
||||||
|
for (size_t i = 0; i < sizeof(formats) / sizeof(formats[0]); i++) {
|
||||||
|
if (formats[i].depth == depth) {
|
||||||
|
return &formats[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
struct wlr_x11_output *get_x11_output_from_window_id(
|
struct wlr_x11_output *get_x11_output_from_window_id(
|
||||||
struct wlr_x11_backend *x11, xcb_window_t window) {
|
struct wlr_x11_backend *x11, xcb_window_t window) {
|
||||||
struct wlr_x11_output *output;
|
struct wlr_x11_output *output;
|
||||||
|
|
@ -38,6 +60,10 @@ struct wlr_x11_output *get_x11_output_from_window_id(
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void handle_x11_error(struct wlr_x11_backend *x11, xcb_value_error_t *ev);
|
||||||
|
static void handle_x11_unknown_event(struct wlr_x11_backend *x11,
|
||||||
|
xcb_generic_event_t *ev);
|
||||||
|
|
||||||
static void handle_x11_event(struct wlr_x11_backend *x11,
|
static void handle_x11_event(struct wlr_x11_backend *x11,
|
||||||
xcb_generic_event_t *event) {
|
xcb_generic_event_t *event) {
|
||||||
switch (event->response_type & XCB_EVENT_RESPONSE_TYPE_MASK) {
|
switch (event->response_type & XCB_EVENT_RESPONSE_TYPE_MASK) {
|
||||||
|
|
@ -68,6 +94,9 @@ static void handle_x11_event(struct wlr_x11_backend *x11,
|
||||||
if (output != NULL) {
|
if (output != NULL) {
|
||||||
wlr_output_destroy(&output->wlr_output);
|
wlr_output_destroy(&output->wlr_output);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
wlr_log(WLR_DEBUG, "Unhandled client message %"PRIu32,
|
||||||
|
ev->data.data32[0]);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -75,8 +104,21 @@ static void handle_x11_event(struct wlr_x11_backend *x11,
|
||||||
xcb_ge_generic_event_t *ev = (xcb_ge_generic_event_t *)event;
|
xcb_ge_generic_event_t *ev = (xcb_ge_generic_event_t *)event;
|
||||||
if (ev->extension == x11->xinput_opcode) {
|
if (ev->extension == x11->xinput_opcode) {
|
||||||
handle_x11_xinput_event(x11, ev);
|
handle_x11_xinput_event(x11, ev);
|
||||||
|
} else if (ev->extension == x11->present_opcode) {
|
||||||
|
handle_x11_present_event(x11, ev);
|
||||||
|
} else {
|
||||||
|
handle_x11_unknown_event(x11, event);
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
case 0: {
|
||||||
|
xcb_value_error_t *ev = (xcb_value_error_t *)event;
|
||||||
|
handle_x11_error(x11, ev);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
handle_x11_unknown_event(x11, event);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -139,6 +181,13 @@ static void backend_destroy(struct wlr_backend *backend) {
|
||||||
|
|
||||||
wlr_renderer_destroy(x11->renderer);
|
wlr_renderer_destroy(x11->renderer);
|
||||||
wlr_egl_finish(&x11->egl);
|
wlr_egl_finish(&x11->egl);
|
||||||
|
wlr_allocator_destroy(x11->allocator);
|
||||||
|
wlr_drm_format_set_finish(&x11->dri3_formats);
|
||||||
|
free(x11->drm_format);
|
||||||
|
|
||||||
|
#if WLR_HAS_XCB_ERRORS
|
||||||
|
xcb_errors_context_free(x11->errors_context);
|
||||||
|
#endif
|
||||||
|
|
||||||
if (x11->xlib_conn) {
|
if (x11->xlib_conn) {
|
||||||
XCloseDisplay(x11->xlib_conn);
|
XCloseDisplay(x11->xlib_conn);
|
||||||
|
|
@ -168,6 +217,110 @@ static void handle_display_destroy(struct wl_listener *listener, void *data) {
|
||||||
backend_destroy(&x11->backend);
|
backend_destroy(&x11->backend);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static xcb_depth_t *get_depth(xcb_screen_t *screen, uint8_t depth) {
|
||||||
|
xcb_depth_iterator_t iter = xcb_screen_allowed_depths_iterator(screen);
|
||||||
|
while (iter.rem > 0) {
|
||||||
|
if (iter.data->depth == depth) {
|
||||||
|
return iter.data;
|
||||||
|
}
|
||||||
|
xcb_depth_next(&iter);
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static xcb_visualid_t pick_visualid(xcb_depth_t *depth) {
|
||||||
|
xcb_visualtype_t *visuals = xcb_depth_visuals(depth);
|
||||||
|
for (int i = 0; i < xcb_depth_visuals_length(depth); i++) {
|
||||||
|
if (visuals[i]._class == XCB_VISUAL_CLASS_TRUE_COLOR) {
|
||||||
|
return visuals[i].visual_id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int query_dri3_drm_fd(struct wlr_x11_backend *x11) {
|
||||||
|
xcb_dri3_open_cookie_t open_cookie =
|
||||||
|
xcb_dri3_open(x11->xcb, x11->screen->root, 0);
|
||||||
|
xcb_dri3_open_reply_t *open_reply =
|
||||||
|
xcb_dri3_open_reply(x11->xcb, open_cookie, NULL);
|
||||||
|
if (open_reply == NULL) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int *open_fds = xcb_dri3_open_reply_fds(x11->xcb, open_reply);
|
||||||
|
if (open_fds == NULL) {
|
||||||
|
free(open_reply);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(open_reply->nfd == 1);
|
||||||
|
int drm_fd = open_fds[0];
|
||||||
|
|
||||||
|
free(open_reply);
|
||||||
|
|
||||||
|
int flags = fcntl(drm_fd, F_GETFD);
|
||||||
|
if (flags < 0) {
|
||||||
|
close(drm_fd);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (fcntl(drm_fd, F_SETFD, flags | FD_CLOEXEC) < 0) {
|
||||||
|
close(drm_fd);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return drm_fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool query_dri3_modifiers(struct wlr_x11_backend *x11,
|
||||||
|
const struct wlr_x11_format *format) {
|
||||||
|
// Query the root window's supported modifiers, because we only care about
|
||||||
|
// screen_modifiers for now
|
||||||
|
xcb_dri3_get_supported_modifiers_cookie_t modifiers_cookie =
|
||||||
|
xcb_dri3_get_supported_modifiers(x11->xcb, x11->screen->root,
|
||||||
|
format->depth, format->bpp);
|
||||||
|
xcb_dri3_get_supported_modifiers_reply_t *modifiers_reply =
|
||||||
|
xcb_dri3_get_supported_modifiers_reply(x11->xcb, modifiers_cookie,
|
||||||
|
NULL);
|
||||||
|
if (!modifiers_reply) {
|
||||||
|
wlr_log(WLR_ERROR, "Failed to get DMA-BUF modifiers supported by "
|
||||||
|
"the X11 server for the format 0x%"PRIX32, format->drm);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If modifiers aren't supported, DRI3 will return an empty list
|
||||||
|
const uint64_t *modifiers =
|
||||||
|
xcb_dri3_get_supported_modifiers_screen_modifiers(modifiers_reply);
|
||||||
|
int modifiers_len =
|
||||||
|
xcb_dri3_get_supported_modifiers_screen_modifiers_length(modifiers_reply);
|
||||||
|
for (int i = 0; i < modifiers_len; i++) {
|
||||||
|
wlr_drm_format_set_add(&x11->dri3_formats, format->drm, modifiers[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(modifiers_reply);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool query_dri3_formats(struct wlr_x11_backend *x11) {
|
||||||
|
xcb_depth_iterator_t iter = xcb_screen_allowed_depths_iterator(x11->screen);
|
||||||
|
while (iter.rem > 0) {
|
||||||
|
uint8_t depth = iter.data->depth;
|
||||||
|
|
||||||
|
const struct wlr_x11_format *format = x11_format_from_depth(depth);
|
||||||
|
if (format != NULL) {
|
||||||
|
wlr_drm_format_set_add(&x11->dri3_formats, format->drm,
|
||||||
|
DRM_FORMAT_MOD_INVALID);
|
||||||
|
|
||||||
|
if (!query_dri3_modifiers(x11, format)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
xcb_depth_next(&iter);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
struct wlr_backend *wlr_x11_backend_create(struct wl_display *display,
|
struct wlr_backend *wlr_x11_backend_create(struct wl_display *display,
|
||||||
const char *x11_display,
|
const char *x11_display,
|
||||||
wlr_renderer_create_func_t create_renderer_func) {
|
wlr_renderer_create_func_t create_renderer_func) {
|
||||||
|
|
@ -225,6 +378,47 @@ struct wlr_backend *wlr_x11_backend_create(struct wl_display *display,
|
||||||
|
|
||||||
const xcb_query_extension_reply_t *ext;
|
const xcb_query_extension_reply_t *ext;
|
||||||
|
|
||||||
|
// DRI3 extension
|
||||||
|
|
||||||
|
ext = xcb_get_extension_data(x11->xcb, &xcb_dri3_id);
|
||||||
|
if (!ext || !ext->present) {
|
||||||
|
wlr_log(WLR_ERROR, "X11 does not support DRI3 extension");
|
||||||
|
goto error_display;
|
||||||
|
}
|
||||||
|
|
||||||
|
xcb_dri3_query_version_cookie_t dri3_cookie =
|
||||||
|
xcb_dri3_query_version(x11->xcb, 1, 2);
|
||||||
|
xcb_dri3_query_version_reply_t *dri3_reply =
|
||||||
|
xcb_dri3_query_version_reply(x11->xcb, dri3_cookie, NULL);
|
||||||
|
if (!dri3_reply || dri3_reply->major_version < 1 ||
|
||||||
|
dri3_reply->minor_version < 2) {
|
||||||
|
wlr_log(WLR_ERROR, "X11 does not support required DRI3 version");
|
||||||
|
goto error_display;
|
||||||
|
}
|
||||||
|
free(dri3_reply);
|
||||||
|
|
||||||
|
// Present extension
|
||||||
|
|
||||||
|
ext = xcb_get_extension_data(x11->xcb, &xcb_present_id);
|
||||||
|
if (!ext || !ext->present) {
|
||||||
|
wlr_log(WLR_ERROR, "X11 does not support Present extension");
|
||||||
|
goto error_display;
|
||||||
|
}
|
||||||
|
x11->present_opcode = ext->major_opcode;
|
||||||
|
|
||||||
|
xcb_present_query_version_cookie_t present_cookie =
|
||||||
|
xcb_present_query_version(x11->xcb, 1, 2);
|
||||||
|
xcb_present_query_version_reply_t *present_reply =
|
||||||
|
xcb_present_query_version_reply(x11->xcb, present_cookie, NULL);
|
||||||
|
if (!present_reply || present_reply->major_version < 1) {
|
||||||
|
wlr_log(WLR_ERROR, "X11 does not support required Present version");
|
||||||
|
free(present_reply);
|
||||||
|
goto error_display;
|
||||||
|
}
|
||||||
|
free(present_reply);
|
||||||
|
|
||||||
|
// Xfixes extension
|
||||||
|
|
||||||
ext = xcb_get_extension_data(x11->xcb, &xcb_xfixes_id);
|
ext = xcb_get_extension_data(x11->xcb, &xcb_xfixes_id);
|
||||||
if (!ext || !ext->present) {
|
if (!ext || !ext->present) {
|
||||||
wlr_log(WLR_ERROR, "X11 does not support Xfixes extension");
|
wlr_log(WLR_ERROR, "X11 does not support Xfixes extension");
|
||||||
|
|
@ -243,6 +437,8 @@ struct wlr_backend *wlr_x11_backend_create(struct wl_display *display,
|
||||||
}
|
}
|
||||||
free(fixes_reply);
|
free(fixes_reply);
|
||||||
|
|
||||||
|
// Xinput extension
|
||||||
|
|
||||||
ext = xcb_get_extension_data(x11->xcb, &xcb_input_id);
|
ext = xcb_get_extension_data(x11->xcb, &xcb_input_id);
|
||||||
if (!ext || !ext->present) {
|
if (!ext || !ext->present) {
|
||||||
wlr_log(WLR_ERROR, "X11 does not support Xinput extension");
|
wlr_log(WLR_ERROR, "X11 does not support Xinput extension");
|
||||||
|
|
@ -273,29 +469,103 @@ struct wlr_backend *wlr_x11_backend_create(struct wl_display *display,
|
||||||
wl_event_source_check(x11->event_source);
|
wl_event_source_check(x11->event_source);
|
||||||
|
|
||||||
x11->screen = xcb_setup_roots_iterator(xcb_get_setup(x11->xcb)).data;
|
x11->screen = xcb_setup_roots_iterator(xcb_get_setup(x11->xcb)).data;
|
||||||
|
if (!x11->screen) {
|
||||||
|
wlr_log(WLR_ERROR, "Failed to get X11 screen");
|
||||||
|
goto error_event;
|
||||||
|
}
|
||||||
|
|
||||||
|
x11->depth = get_depth(x11->screen, 32);
|
||||||
|
if (!x11->depth) {
|
||||||
|
wlr_log(WLR_ERROR, "Failed to get 32-bit depth for X11 screen");
|
||||||
|
goto error_event;
|
||||||
|
}
|
||||||
|
|
||||||
|
x11->visualid = pick_visualid(x11->depth);
|
||||||
|
if (!x11->visualid) {
|
||||||
|
wlr_log(WLR_ERROR, "Failed to pick X11 visual");
|
||||||
|
goto error_event;
|
||||||
|
}
|
||||||
|
|
||||||
|
x11->x11_format = x11_format_from_depth(x11->depth->depth);
|
||||||
|
if (!x11->x11_format) {
|
||||||
|
wlr_log(WLR_ERROR, "Unsupported depth %"PRIu8, x11->depth->depth);
|
||||||
|
goto error_event;
|
||||||
|
}
|
||||||
|
|
||||||
|
x11->colormap = xcb_generate_id(x11->xcb);
|
||||||
|
xcb_create_colormap(x11->xcb, XCB_COLORMAP_ALLOC_NONE, x11->colormap,
|
||||||
|
x11->screen->root, x11->visualid);
|
||||||
|
|
||||||
|
// DRI3 may return a render node (Xwayland) or an authenticated primary
|
||||||
|
// node (plain Glamor).
|
||||||
|
int drm_fd = query_dri3_drm_fd(x11);
|
||||||
|
if (drm_fd < 0) {
|
||||||
|
wlr_log(WLR_ERROR, "Failed to query DRI3 DRM FD");
|
||||||
|
goto error_event;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct wlr_gbm_allocator *gbm_alloc = wlr_gbm_allocator_create(drm_fd);
|
||||||
|
if (gbm_alloc == NULL) {
|
||||||
|
wlr_log(WLR_ERROR, "Failed to create GBM allocator");
|
||||||
|
close(drm_fd);
|
||||||
|
goto error_event;
|
||||||
|
}
|
||||||
|
x11->allocator = &gbm_alloc->base;
|
||||||
|
|
||||||
if (!create_renderer_func) {
|
if (!create_renderer_func) {
|
||||||
create_renderer_func = wlr_renderer_autocreate;
|
create_renderer_func = wlr_renderer_autocreate;
|
||||||
}
|
}
|
||||||
|
|
||||||
static EGLint config_attribs[] = {
|
x11->renderer = create_renderer_func(&x11->egl, EGL_PLATFORM_GBM_KHR,
|
||||||
EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
|
gbm_alloc->gbm_device, NULL, 0);
|
||||||
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
|
|
||||||
EGL_RED_SIZE, 1,
|
|
||||||
EGL_GREEN_SIZE, 1,
|
|
||||||
EGL_BLUE_SIZE, 1,
|
|
||||||
EGL_ALPHA_SIZE, 0,
|
|
||||||
EGL_NONE,
|
|
||||||
};
|
|
||||||
|
|
||||||
x11->renderer = create_renderer_func(&x11->egl, EGL_PLATFORM_X11_KHR,
|
|
||||||
x11->xlib_conn, config_attribs, x11->screen->root_visual);
|
|
||||||
|
|
||||||
if (x11->renderer == NULL) {
|
if (x11->renderer == NULL) {
|
||||||
wlr_log(WLR_ERROR, "Failed to create renderer");
|
wlr_log(WLR_ERROR, "Failed to create renderer");
|
||||||
goto error_event;
|
goto error_event;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const struct wlr_drm_format_set *render_formats =
|
||||||
|
wlr_renderer_get_dmabuf_render_formats(x11->renderer);
|
||||||
|
if (render_formats == NULL) {
|
||||||
|
wlr_log(WLR_ERROR, "Failed to get available DMA-BUF formats from renderer");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const struct wlr_drm_format *render_format =
|
||||||
|
wlr_drm_format_set_get(render_formats, x11->x11_format->drm);
|
||||||
|
if (render_format == NULL) {
|
||||||
|
wlr_log(WLR_ERROR, "Renderer doesn't support DRM format 0x%"PRIX32,
|
||||||
|
x11->x11_format->drm);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!query_dri3_formats(x11)) {
|
||||||
|
wlr_log(WLR_ERROR, "Failed to query supported DRI3 formats");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const struct wlr_drm_format *dri3_format =
|
||||||
|
wlr_drm_format_set_get(&x11->dri3_formats, x11->x11_format->drm);
|
||||||
|
if (dri3_format == NULL) {
|
||||||
|
wlr_log(WLR_ERROR, "X11 server doesn't support DRM format 0x%"PRIX32,
|
||||||
|
x11->x11_format->drm);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
x11->drm_format = wlr_drm_format_intersect(dri3_format, render_format);
|
||||||
|
if (x11->drm_format == NULL) {
|
||||||
|
wlr_log(WLR_ERROR, "Failed to intersect DRI3 and render modifiers for "
|
||||||
|
"format 0x%"PRIX32, x11->x11_format->drm);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if WLR_HAS_XCB_ERRORS
|
||||||
|
if (xcb_errors_context_new(x11->xcb, &x11->errors_context) != 0) {
|
||||||
|
wlr_log(WLR_ERROR, "Failed to create error context");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
x11->present_event_id = xcb_generate_id(x11->xcb);
|
||||||
|
|
||||||
wlr_input_device_init(&x11->keyboard_dev, WLR_INPUT_DEVICE_KEYBOARD,
|
wlr_input_device_init(&x11->keyboard_dev, WLR_INPUT_DEVICE_KEYBOARD,
|
||||||
&input_device_impl, "X11 keyboard", 0, 0);
|
&input_device_impl, "X11 keyboard", 0, 0);
|
||||||
wlr_keyboard_init(&x11->keyboard, &keyboard_impl);
|
wlr_keyboard_init(&x11->keyboard, &keyboard_impl);
|
||||||
|
|
@ -314,3 +584,58 @@ error_x11:
|
||||||
free(x11);
|
free(x11);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void handle_x11_error(struct wlr_x11_backend *x11, xcb_value_error_t *ev) {
|
||||||
|
#if WLR_HAS_XCB_ERRORS
|
||||||
|
const char *major_name = xcb_errors_get_name_for_major_code(
|
||||||
|
x11->errors_context, ev->major_opcode);
|
||||||
|
if (!major_name) {
|
||||||
|
wlr_log(WLR_DEBUG, "X11 error happened, but could not get major name");
|
||||||
|
goto log_raw;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *minor_name = xcb_errors_get_name_for_minor_code(
|
||||||
|
x11->errors_context, ev->major_opcode, ev->minor_opcode);
|
||||||
|
|
||||||
|
const char *extension;
|
||||||
|
const char *error_name = xcb_errors_get_name_for_error(x11->errors_context,
|
||||||
|
ev->error_code, &extension);
|
||||||
|
if (!error_name) {
|
||||||
|
wlr_log(WLR_DEBUG, "X11 error happened, but could not get error name");
|
||||||
|
goto log_raw;
|
||||||
|
}
|
||||||
|
|
||||||
|
wlr_log(WLR_ERROR, "X11 error: op %s (%s), code %s (%s), "
|
||||||
|
"sequence %"PRIu16", value %"PRIu32,
|
||||||
|
major_name, minor_name ? minor_name : "no minor",
|
||||||
|
error_name, extension ? extension : "no extension",
|
||||||
|
ev->sequence, ev->bad_value);
|
||||||
|
|
||||||
|
return;
|
||||||
|
|
||||||
|
log_raw:
|
||||||
|
#endif
|
||||||
|
|
||||||
|
wlr_log(WLR_ERROR, "X11 error: op %"PRIu8":%"PRIu16", code %"PRIu8", "
|
||||||
|
"sequence %"PRIu16", value %"PRIu32,
|
||||||
|
ev->major_opcode, ev->minor_opcode, ev->error_code,
|
||||||
|
ev->sequence, ev->bad_value);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handle_x11_unknown_event(struct wlr_x11_backend *x11,
|
||||||
|
xcb_generic_event_t *ev) {
|
||||||
|
#if WLR_HAS_XCB_ERRORS
|
||||||
|
const char *extension;
|
||||||
|
const char *event_name = xcb_errors_get_name_for_xcb_event(
|
||||||
|
x11->errors_context, ev, &extension);
|
||||||
|
if (!event_name) {
|
||||||
|
wlr_log(WLR_DEBUG, "No name for unhandled event: %u",
|
||||||
|
ev->response_type);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
wlr_log(WLR_DEBUG, "Unhandled X11 event: %s (%u)", event_name, ev->response_type);
|
||||||
|
#else
|
||||||
|
wlr_log(WLR_DEBUG, "Unhandled X11 event: %u", ev->response_type);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,8 @@
|
||||||
|
|
||||||
#include <linux/input-event-codes.h>
|
#include <linux/input-event-codes.h>
|
||||||
|
|
||||||
|
#include <wayland-server-protocol.h>
|
||||||
|
|
||||||
#include <xcb/xcb.h>
|
#include <xcb/xcb.h>
|
||||||
#include <xcb/xfixes.h>
|
#include <xcb/xfixes.h>
|
||||||
#include <xcb/xinput.h>
|
#include <xcb/xinput.h>
|
||||||
|
|
@ -18,7 +20,7 @@
|
||||||
#include "util/signal.h"
|
#include "util/signal.h"
|
||||||
|
|
||||||
static void send_key_event(struct wlr_x11_backend *x11, uint32_t key,
|
static void send_key_event(struct wlr_x11_backend *x11, uint32_t key,
|
||||||
enum wlr_key_state st, xcb_timestamp_t time) {
|
enum wl_keyboard_key_state st, xcb_timestamp_t time) {
|
||||||
struct wlr_event_keyboard_key ev = {
|
struct wlr_event_keyboard_key ev = {
|
||||||
.time_msec = time,
|
.time_msec = time,
|
||||||
.keycode = key,
|
.keycode = key,
|
||||||
|
|
@ -123,7 +125,7 @@ void handle_x11_xinput_event(struct wlr_x11_backend *x11,
|
||||||
|
|
||||||
wlr_keyboard_notify_modifiers(&x11->keyboard, ev->mods.base,
|
wlr_keyboard_notify_modifiers(&x11->keyboard, ev->mods.base,
|
||||||
ev->mods.latched, ev->mods.locked, ev->mods.effective);
|
ev->mods.latched, ev->mods.locked, ev->mods.effective);
|
||||||
send_key_event(x11, ev->detail - 8, WLR_KEY_PRESSED, ev->time);
|
send_key_event(x11, ev->detail - 8, WL_KEYBOARD_KEY_STATE_PRESSED, ev->time);
|
||||||
x11->time = ev->time;
|
x11->time = ev->time;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -133,7 +135,7 @@ void handle_x11_xinput_event(struct wlr_x11_backend *x11,
|
||||||
|
|
||||||
wlr_keyboard_notify_modifiers(&x11->keyboard, ev->mods.base,
|
wlr_keyboard_notify_modifiers(&x11->keyboard, ev->mods.base,
|
||||||
ev->mods.latched, ev->mods.locked, ev->mods.effective);
|
ev->mods.latched, ev->mods.locked, ev->mods.effective);
|
||||||
send_key_event(x11, ev->detail - 8, WLR_KEY_RELEASED, ev->time);
|
send_key_event(x11, ev->detail - 8, WL_KEYBOARD_KEY_STATE_RELEASED, ev->time);
|
||||||
x11->time = ev->time;
|
x11->time = ev->time;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,8 +2,10 @@ x11_libs = []
|
||||||
x11_required = [
|
x11_required = [
|
||||||
'x11-xcb',
|
'x11-xcb',
|
||||||
'xcb',
|
'xcb',
|
||||||
'xcb-xinput',
|
'xcb-dri3',
|
||||||
|
'xcb-present',
|
||||||
'xcb-xfixes',
|
'xcb-xfixes',
|
||||||
|
'xcb-xinput',
|
||||||
]
|
]
|
||||||
|
|
||||||
msg = []
|
msg = []
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,9 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <drm_fourcc.h>
|
||||||
|
#include <xcb/dri3.h>
|
||||||
|
#include <xcb/present.h>
|
||||||
#include <xcb/xcb.h>
|
#include <xcb/xcb.h>
|
||||||
#include <xcb/xinput.h>
|
#include <xcb/xinput.h>
|
||||||
|
|
||||||
|
|
@ -13,7 +16,10 @@
|
||||||
#include <wlr/util/log.h>
|
#include <wlr/util/log.h>
|
||||||
|
|
||||||
#include "backend/x11.h"
|
#include "backend/x11.h"
|
||||||
|
#include "render/swapchain.h"
|
||||||
|
#include "render/wlr_renderer.h"
|
||||||
#include "util/signal.h"
|
#include "util/signal.h"
|
||||||
|
#include "util/time.h"
|
||||||
|
|
||||||
static int signal_frame(void *data) {
|
static int signal_frame(void *data) {
|
||||||
struct wlr_x11_output *output = data;
|
struct wlr_x11_output *output = data;
|
||||||
|
|
@ -76,6 +82,8 @@ static bool output_set_custom_mode(struct wlr_output *wlr_output,
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void destroy_x11_buffer(struct wlr_x11_buffer *buffer);
|
||||||
|
|
||||||
static void output_destroy(struct wlr_output *wlr_output) {
|
static void output_destroy(struct wlr_output *wlr_output) {
|
||||||
struct wlr_x11_output *output = get_x11_output_from_output(wlr_output);
|
struct wlr_x11_output *output = get_x11_output_from_output(wlr_output);
|
||||||
struct wlr_x11_backend *x11 = output->x11;
|
struct wlr_x11_backend *x11 = output->x11;
|
||||||
|
|
@ -83,9 +91,15 @@ static void output_destroy(struct wlr_output *wlr_output) {
|
||||||
wlr_input_device_destroy(&output->pointer_dev);
|
wlr_input_device_destroy(&output->pointer_dev);
|
||||||
wlr_input_device_destroy(&output->touch_dev);
|
wlr_input_device_destroy(&output->touch_dev);
|
||||||
|
|
||||||
|
struct wlr_x11_buffer *buffer, *buffer_tmp;
|
||||||
|
wl_list_for_each_safe(buffer, buffer_tmp, &output->buffers, link) {
|
||||||
|
destroy_x11_buffer(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
wl_list_remove(&output->link);
|
wl_list_remove(&output->link);
|
||||||
wl_event_source_remove(output->frame_timer);
|
wl_event_source_remove(output->frame_timer);
|
||||||
wlr_egl_destroy_surface(&x11->egl, output->surf);
|
wlr_buffer_unlock(output->back_buffer);
|
||||||
|
wlr_swapchain_destroy(output->swapchain);
|
||||||
xcb_destroy_window(x11->xcb, output->win);
|
xcb_destroy_window(x11->xcb, output->win);
|
||||||
xcb_flush(x11->xcb);
|
xcb_flush(x11->xcb);
|
||||||
free(output);
|
free(output);
|
||||||
|
|
@ -96,7 +110,20 @@ static bool output_attach_render(struct wlr_output *wlr_output,
|
||||||
struct wlr_x11_output *output = get_x11_output_from_output(wlr_output);
|
struct wlr_x11_output *output = get_x11_output_from_output(wlr_output);
|
||||||
struct wlr_x11_backend *x11 = output->x11;
|
struct wlr_x11_backend *x11 = output->x11;
|
||||||
|
|
||||||
return wlr_egl_make_current(&x11->egl, output->surf, buffer_age);
|
wlr_buffer_unlock(output->back_buffer);
|
||||||
|
output->back_buffer = wlr_swapchain_acquire(output->swapchain, buffer_age);
|
||||||
|
if (!output->back_buffer) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!wlr_egl_make_current(&x11->egl, EGL_NO_SURFACE, NULL)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!wlr_renderer_bind_buffer(x11->renderer, output->back_buffer)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool output_test(struct wlr_output *wlr_output) {
|
static bool output_test(struct wlr_output *wlr_output) {
|
||||||
|
|
@ -112,6 +139,147 @@ static bool output_test(struct wlr_output *wlr_output) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void destroy_x11_buffer(struct wlr_x11_buffer *buffer) {
|
||||||
|
if (!buffer) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
wl_list_remove(&buffer->buffer_destroy.link);
|
||||||
|
wl_list_remove(&buffer->link);
|
||||||
|
xcb_free_pixmap(buffer->x11->xcb, buffer->pixmap);
|
||||||
|
free(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void buffer_handle_buffer_destroy(struct wl_listener *listener,
|
||||||
|
void *data) {
|
||||||
|
struct wlr_x11_buffer *buffer =
|
||||||
|
wl_container_of(listener, buffer, buffer_destroy);
|
||||||
|
destroy_x11_buffer(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct wlr_x11_buffer *create_x11_buffer(struct wlr_x11_output *output,
|
||||||
|
struct wlr_buffer *wlr_buffer) {
|
||||||
|
struct wlr_x11_backend *x11 = output->x11;
|
||||||
|
|
||||||
|
struct wlr_dmabuf_attributes attrs = {0};
|
||||||
|
if (!wlr_buffer_get_dmabuf(wlr_buffer, &attrs)) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (attrs.format != x11->x11_format->drm) {
|
||||||
|
// The pixmap's depth must match the window's depth, otherwise Present
|
||||||
|
// will throw a Match error
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// xcb closes the FDs after sending them, so we need to dup them here
|
||||||
|
struct wlr_dmabuf_attributes dup_attrs = {0};
|
||||||
|
if (!wlr_dmabuf_attributes_copy(&dup_attrs, &attrs)) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
const struct wlr_x11_format *x11_fmt = x11->x11_format;
|
||||||
|
xcb_pixmap_t pixmap = xcb_generate_id(x11->xcb);
|
||||||
|
xcb_dri3_pixmap_from_buffers(x11->xcb, pixmap, output->win,
|
||||||
|
attrs.n_planes, attrs.width, attrs.height, attrs.stride[0],
|
||||||
|
attrs.offset[0], attrs.stride[1], attrs.offset[1], attrs.stride[2],
|
||||||
|
attrs.offset[2], attrs.stride[3], attrs.offset[3], x11_fmt->depth,
|
||||||
|
x11_fmt->bpp, attrs.modifier, dup_attrs.fd);
|
||||||
|
|
||||||
|
struct wlr_x11_buffer *buffer = calloc(1, sizeof(struct wlr_x11_buffer));
|
||||||
|
if (!buffer) {
|
||||||
|
xcb_free_pixmap(x11->xcb, pixmap);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
buffer->buffer = wlr_buffer_lock(wlr_buffer);
|
||||||
|
buffer->pixmap = pixmap;
|
||||||
|
buffer->x11 = x11;
|
||||||
|
wl_list_insert(&output->buffers, &buffer->link);
|
||||||
|
|
||||||
|
buffer->buffer_destroy.notify = buffer_handle_buffer_destroy;
|
||||||
|
wl_signal_add(&wlr_buffer->events.destroy, &buffer->buffer_destroy);
|
||||||
|
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct wlr_x11_buffer *get_or_create_x11_buffer(
|
||||||
|
struct wlr_x11_output *output, struct wlr_buffer *wlr_buffer) {
|
||||||
|
struct wlr_x11_buffer *buffer;
|
||||||
|
wl_list_for_each(buffer, &output->buffers, link) {
|
||||||
|
if (buffer->buffer == wlr_buffer) {
|
||||||
|
wlr_buffer_lock(buffer->buffer);
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return create_x11_buffer(output, wlr_buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool output_commit_buffer(struct wlr_x11_output *output) {
|
||||||
|
struct wlr_x11_backend *x11 = output->x11;
|
||||||
|
|
||||||
|
assert(output->back_buffer != NULL);
|
||||||
|
|
||||||
|
wlr_renderer_bind_buffer(x11->renderer, NULL);
|
||||||
|
wlr_egl_unset_current(&x11->egl);
|
||||||
|
|
||||||
|
struct wlr_x11_buffer *x11_buffer =
|
||||||
|
get_or_create_x11_buffer(output, output->back_buffer);
|
||||||
|
if (!x11_buffer) {
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
xcb_xfixes_region_t region = XCB_NONE;
|
||||||
|
if (output->wlr_output.pending.committed & WLR_OUTPUT_STATE_DAMAGE) {
|
||||||
|
pixman_region32_t *damage = &output->wlr_output.pending.damage;
|
||||||
|
|
||||||
|
int rects_len = 0;
|
||||||
|
pixman_box32_t *rects = pixman_region32_rectangles(damage, &rects_len);
|
||||||
|
|
||||||
|
xcb_rectangle_t *xcb_rects = calloc(rects_len, sizeof(xcb_rectangle_t));
|
||||||
|
if (!xcb_rects) {
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < rects_len; i++) {
|
||||||
|
pixman_box32_t *box = &rects[i];
|
||||||
|
xcb_rects[i] = (struct xcb_rectangle_t){
|
||||||
|
.x = box->x1,
|
||||||
|
.y = box->y1,
|
||||||
|
.width = box->x2 - box->x1,
|
||||||
|
.height = box->y2 - box->y1,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
xcb_xfixes_region_t region = xcb_generate_id(x11->xcb);
|
||||||
|
xcb_xfixes_create_region(x11->xcb, region, rects_len, xcb_rects);
|
||||||
|
|
||||||
|
free(xcb_rects);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t serial = output->wlr_output.commit_seq;
|
||||||
|
uint32_t options = 0;
|
||||||
|
xcb_present_pixmap(x11->xcb, output->win, x11_buffer->pixmap, serial,
|
||||||
|
0, region, 0, 0, XCB_NONE, XCB_NONE, XCB_NONE, options, 0, 0, 0,
|
||||||
|
0, NULL);
|
||||||
|
|
||||||
|
if (region != XCB_NONE) {
|
||||||
|
xcb_xfixes_destroy_region(x11->xcb, region);
|
||||||
|
}
|
||||||
|
|
||||||
|
wlr_buffer_unlock(output->back_buffer);
|
||||||
|
output->back_buffer = NULL;
|
||||||
|
|
||||||
|
wlr_swapchain_set_buffer_submitted(output->swapchain, x11_buffer->buffer);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
|
||||||
|
error:
|
||||||
|
destroy_x11_buffer(x11_buffer);
|
||||||
|
wlr_buffer_unlock(output->back_buffer);
|
||||||
|
output->back_buffer = NULL;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
static bool output_commit(struct wlr_output *wlr_output) {
|
static bool output_commit(struct wlr_output *wlr_output) {
|
||||||
struct wlr_x11_output *output = get_x11_output_from_output(wlr_output);
|
struct wlr_x11_output *output = get_x11_output_from_output(wlr_output);
|
||||||
struct wlr_x11_backend *x11 = output->x11;
|
struct wlr_x11_backend *x11 = output->x11;
|
||||||
|
|
@ -145,24 +313,21 @@ static bool output_commit(struct wlr_output *wlr_output) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (wlr_output->pending.committed & WLR_OUTPUT_STATE_BUFFER) {
|
if (wlr_output->pending.committed & WLR_OUTPUT_STATE_BUFFER) {
|
||||||
pixman_region32_t *damage = NULL;
|
if (!output_commit_buffer(output)) {
|
||||||
if (wlr_output->pending.committed & WLR_OUTPUT_STATE_DAMAGE) {
|
|
||||||
damage = &wlr_output->pending.damage;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!wlr_egl_swap_buffers(&x11->egl, output->surf, damage)) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
wlr_output_send_present(wlr_output, NULL);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
xcb_flush(x11->xcb);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void output_rollback_render(struct wlr_output *wlr_output) {
|
static void output_rollback_render(struct wlr_output *wlr_output) {
|
||||||
struct wlr_x11_output *output = get_x11_output_from_output(wlr_output);
|
struct wlr_x11_output *output = get_x11_output_from_output(wlr_output);
|
||||||
wlr_egl_unset_current(&output->x11->egl);
|
struct wlr_x11_backend *x11 = output->x11;
|
||||||
|
wlr_renderer_bind_buffer(x11->renderer, NULL);
|
||||||
|
wlr_egl_unset_current(&x11->egl);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct wlr_output_impl output_impl = {
|
static const struct wlr_output_impl output_impl = {
|
||||||
|
|
@ -186,6 +351,7 @@ struct wlr_output *wlr_x11_output_create(struct wlr_backend *backend) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
output->x11 = x11;
|
output->x11 = x11;
|
||||||
|
wl_list_init(&output->buffers);
|
||||||
|
|
||||||
struct wlr_output *wlr_output = &output->wlr_output;
|
struct wlr_output *wlr_output = &output->wlr_output;
|
||||||
wlr_output_init(wlr_output, &x11->backend, &output_impl, x11->wl_display);
|
wlr_output_init(wlr_output, &x11->backend, &output_impl, x11->wl_display);
|
||||||
|
|
@ -193,6 +359,14 @@ struct wlr_output *wlr_x11_output_create(struct wlr_backend *backend) {
|
||||||
wlr_output->width = 1024;
|
wlr_output->width = 1024;
|
||||||
wlr_output->height = 768;
|
wlr_output->height = 768;
|
||||||
|
|
||||||
|
output->swapchain = wlr_swapchain_create(x11->allocator,
|
||||||
|
wlr_output->width, wlr_output->height, x11->drm_format);
|
||||||
|
if (!output->swapchain) {
|
||||||
|
wlr_log(WLR_ERROR, "Failed to create swapchain");
|
||||||
|
free(output);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
output_set_refresh(&output->wlr_output, 0);
|
output_set_refresh(&output->wlr_output, 0);
|
||||||
|
|
||||||
snprintf(wlr_output->name, sizeof(wlr_output->name), "X11-%zd",
|
snprintf(wlr_output->name, sizeof(wlr_output->name), "X11-%zd",
|
||||||
|
|
@ -204,14 +378,18 @@ struct wlr_output *wlr_x11_output_create(struct wlr_backend *backend) {
|
||||||
"X11 output %zd", x11->last_output_num);
|
"X11 output %zd", x11->last_output_num);
|
||||||
wlr_output_set_description(wlr_output, description);
|
wlr_output_set_description(wlr_output, description);
|
||||||
|
|
||||||
uint32_t mask = XCB_CW_EVENT_MASK;
|
// The X11 protocol requires us to set a colormap and border pixel if the
|
||||||
|
// depth doesn't match the root window's
|
||||||
|
uint32_t mask = XCB_CW_BORDER_PIXEL | XCB_CW_EVENT_MASK | XCB_CW_COLORMAP;
|
||||||
uint32_t values[] = {
|
uint32_t values[] = {
|
||||||
XCB_EVENT_MASK_EXPOSURE | XCB_EVENT_MASK_STRUCTURE_NOTIFY
|
0,
|
||||||
|
XCB_EVENT_MASK_EXPOSURE | XCB_EVENT_MASK_STRUCTURE_NOTIFY,
|
||||||
|
x11->colormap,
|
||||||
};
|
};
|
||||||
output->win = xcb_generate_id(x11->xcb);
|
output->win = xcb_generate_id(x11->xcb);
|
||||||
xcb_create_window(x11->xcb, XCB_COPY_FROM_PARENT, output->win,
|
xcb_create_window(x11->xcb, x11->depth->depth, output->win,
|
||||||
x11->screen->root, 0, 0, wlr_output->width, wlr_output->height, 1,
|
x11->screen->root, 0, 0, wlr_output->width, wlr_output->height, 0,
|
||||||
XCB_WINDOW_CLASS_INPUT_OUTPUT, x11->screen->root_visual, mask, values);
|
XCB_WINDOW_CLASS_INPUT_OUTPUT, x11->visualid, mask, values);
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
xcb_input_event_mask_t head;
|
xcb_input_event_mask_t head;
|
||||||
|
|
@ -231,12 +409,10 @@ struct wlr_output *wlr_x11_output_create(struct wlr_backend *backend) {
|
||||||
};
|
};
|
||||||
xcb_input_xi_select_events(x11->xcb, output->win, 1, &xinput_mask.head);
|
xcb_input_xi_select_events(x11->xcb, output->win, 1, &xinput_mask.head);
|
||||||
|
|
||||||
output->surf = wlr_egl_create_surface(&x11->egl, &output->win);
|
uint32_t present_mask = XCB_PRESENT_EVENT_MASK_IDLE_NOTIFY |
|
||||||
if (!output->surf) {
|
XCB_PRESENT_EVENT_MASK_COMPLETE_NOTIFY;
|
||||||
wlr_log(WLR_ERROR, "Failed to create EGL surface");
|
xcb_present_select_input(x11->xcb, x11->present_event_id, output->win,
|
||||||
free(output);
|
present_mask);
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
xcb_change_property(x11->xcb, XCB_PROP_MODE_REPLACE, output->win,
|
xcb_change_property(x11->xcb, XCB_PROP_MODE_REPLACE, output->win,
|
||||||
x11->atoms.wm_protocols, XCB_ATOM_ATOM, 32, 1,
|
x11->atoms.wm_protocols, XCB_ATOM_ATOM, 32, 1,
|
||||||
|
|
@ -278,17 +454,30 @@ struct wlr_output *wlr_x11_output_create(struct wlr_backend *backend) {
|
||||||
void handle_x11_configure_notify(struct wlr_x11_output *output,
|
void handle_x11_configure_notify(struct wlr_x11_output *output,
|
||||||
xcb_configure_notify_event_t *ev) {
|
xcb_configure_notify_event_t *ev) {
|
||||||
// ignore events that set an invalid size:
|
// ignore events that set an invalid size:
|
||||||
if (ev->width > 0 && ev->height > 0) {
|
if (ev->width == 0 || ev->height == 0) {
|
||||||
wlr_output_update_custom_mode(&output->wlr_output, ev->width,
|
|
||||||
ev->height, output->wlr_output.refresh);
|
|
||||||
|
|
||||||
// Move the pointer to its new location
|
|
||||||
update_x11_pointer_position(output, output->x11->time);
|
|
||||||
} else {
|
|
||||||
wlr_log(WLR_DEBUG,
|
wlr_log(WLR_DEBUG,
|
||||||
"Ignoring X11 configure event for height=%d, width=%d",
|
"Ignoring X11 configure event for height=%d, width=%d",
|
||||||
ev->width, ev->height);
|
ev->width, ev->height);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (output->swapchain->width != ev->width ||
|
||||||
|
output->swapchain->height != ev->height) {
|
||||||
|
struct wlr_swapchain *swapchain = wlr_swapchain_create(
|
||||||
|
output->x11->allocator, ev->width, ev->height,
|
||||||
|
output->x11->drm_format);
|
||||||
|
if (!swapchain) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
wlr_swapchain_destroy(output->swapchain);
|
||||||
|
output->swapchain = swapchain;
|
||||||
|
}
|
||||||
|
|
||||||
|
wlr_output_update_custom_mode(&output->wlr_output, ev->width,
|
||||||
|
ev->height, output->wlr_output.refresh);
|
||||||
|
|
||||||
|
// Move the pointer to its new location
|
||||||
|
update_x11_pointer_position(output, output->x11->time);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool wlr_output_is_x11(struct wlr_output *wlr_output) {
|
bool wlr_output_is_x11(struct wlr_output *wlr_output) {
|
||||||
|
|
@ -310,3 +499,70 @@ void wlr_x11_output_set_title(struct wlr_output *output, const char *title) {
|
||||||
x11_output->x11->atoms.net_wm_name, x11_output->x11->atoms.utf8_string, 8,
|
x11_output->x11->atoms.net_wm_name, x11_output->x11->atoms.utf8_string, 8,
|
||||||
strlen(title), title);
|
strlen(title), title);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static struct wlr_x11_buffer *get_x11_buffer(struct wlr_x11_output *output,
|
||||||
|
xcb_pixmap_t pixmap) {
|
||||||
|
struct wlr_x11_buffer *buffer;
|
||||||
|
wl_list_for_each(buffer, &output->buffers, link) {
|
||||||
|
if (buffer->pixmap == pixmap) {
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void handle_x11_present_event(struct wlr_x11_backend *x11,
|
||||||
|
xcb_ge_generic_event_t *event) {
|
||||||
|
struct wlr_x11_output *output;
|
||||||
|
|
||||||
|
switch (event->event_type) {
|
||||||
|
case XCB_PRESENT_EVENT_IDLE_NOTIFY:;
|
||||||
|
xcb_present_idle_notify_event_t *idle_notify =
|
||||||
|
(xcb_present_idle_notify_event_t *)event;
|
||||||
|
|
||||||
|
output = get_x11_output_from_window_id(x11, idle_notify->window);
|
||||||
|
if (!output) {
|
||||||
|
wlr_log(WLR_DEBUG, "Got PresentIdleNotify event for unknown window");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct wlr_x11_buffer *buffer =
|
||||||
|
get_x11_buffer(output, idle_notify->pixmap);
|
||||||
|
if (!buffer) {
|
||||||
|
wlr_log(WLR_DEBUG, "Got PresentIdleNotify event for unknown buffer");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
wlr_buffer_unlock(buffer->buffer); // may destroy buffer
|
||||||
|
break;
|
||||||
|
case XCB_PRESENT_COMPLETE_NOTIFY:;
|
||||||
|
xcb_present_complete_notify_event_t *complete_notify =
|
||||||
|
(xcb_present_complete_notify_event_t *)event;
|
||||||
|
|
||||||
|
output = get_x11_output_from_window_id(x11, complete_notify->window);
|
||||||
|
if (!output) {
|
||||||
|
wlr_log(WLR_DEBUG, "Got PresentCompleteNotify event for unknown window");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct timespec t;
|
||||||
|
timespec_from_nsec(&t, complete_notify->ust * 1000);
|
||||||
|
|
||||||
|
uint32_t flags = 0;
|
||||||
|
if (complete_notify->mode == XCB_PRESENT_COMPLETE_MODE_FLIP) {
|
||||||
|
flags |= WLR_OUTPUT_PRESENT_ZERO_COPY;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct wlr_output_event_present present_event = {
|
||||||
|
.output = &output->wlr_output,
|
||||||
|
.commit_seq = complete_notify->serial,
|
||||||
|
.when = &t,
|
||||||
|
.seq = complete_notify->msc,
|
||||||
|
.flags = flags,
|
||||||
|
};
|
||||||
|
wlr_output_send_present(&output->wlr_output, &present_event);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
wlr_log(WLR_DEBUG, "Unhandled Present event %"PRIu16, event->event_type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,8 @@ wlroots reads these environment variables
|
||||||
* *WLR_SESSION*: specifies the wlr\_session to be used (available sessions:
|
* *WLR_SESSION*: specifies the wlr\_session to be used (available sessions:
|
||||||
logind/systemd, direct)
|
logind/systemd, direct)
|
||||||
* *WLR_DIRECT_TTY*: specifies the tty to be used (instead of using /dev/tty)
|
* *WLR_DIRECT_TTY*: specifies the tty to be used (instead of using /dev/tty)
|
||||||
|
* *WLR_XWAYLAND*: specifies the path to an Xwayland binary to be used (instead
|
||||||
|
of following shell search semantics for "Xwayland")
|
||||||
|
|
||||||
## DRM backend
|
## DRM backend
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -753,8 +753,11 @@ static int init(struct capture_context *ctx) {
|
||||||
ctx->registry = wl_display_get_registry(ctx->display);
|
ctx->registry = wl_display_get_registry(ctx->display);
|
||||||
wl_registry_add_listener(ctx->registry, ®istry_listener, ctx);
|
wl_registry_add_listener(ctx->registry, ®istry_listener, ctx);
|
||||||
|
|
||||||
|
// First roundtrip to fetch globals
|
||||||
|
wl_display_roundtrip(ctx->display);
|
||||||
|
|
||||||
|
// Second roundtrip to fetch wl_output information
|
||||||
wl_display_roundtrip(ctx->display);
|
wl_display_roundtrip(ctx->display);
|
||||||
wl_display_dispatch(ctx->display);
|
|
||||||
|
|
||||||
if (!ctx->export_manager) {
|
if (!ctx->export_manager) {
|
||||||
av_log(ctx, AV_LOG_ERROR, "Compositor doesn't support %s!\n",
|
av_log(ctx, AV_LOG_ERROR, "Compositor doesn't support %s!\n",
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@
|
||||||
#include <wayland-client.h>
|
#include <wayland-client.h>
|
||||||
#include "wlr-foreign-toplevel-management-unstable-v1-client-protocol.h"
|
#include "wlr-foreign-toplevel-management-unstable-v1-client-protocol.h"
|
||||||
|
|
||||||
#define WLR_FOREIGN_TOPLEVEL_MANAGEMENT_VERSION 2
|
#define WLR_FOREIGN_TOPLEVEL_MANAGEMENT_VERSION 3
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Usage:
|
* Usage:
|
||||||
|
|
@ -38,11 +38,14 @@ enum toplevel_state_field {
|
||||||
TOPLEVEL_STATE_INVALID = (1 << 4),
|
TOPLEVEL_STATE_INVALID = (1 << 4),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const uint32_t no_parent = (uint32_t)-1;
|
||||||
|
|
||||||
struct toplevel_state {
|
struct toplevel_state {
|
||||||
char *title;
|
char *title;
|
||||||
char *app_id;
|
char *app_id;
|
||||||
|
|
||||||
uint32_t state;
|
uint32_t state;
|
||||||
|
uint32_t parent_id;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void copy_state(struct toplevel_state *current,
|
static void copy_state(struct toplevel_state *current,
|
||||||
|
|
@ -67,6 +70,8 @@ static void copy_state(struct toplevel_state *current,
|
||||||
current->state = pending->state;
|
current->state = pending->state;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
current->parent_id = pending->parent_id;
|
||||||
|
|
||||||
pending->state = TOPLEVEL_STATE_INVALID;
|
pending->state = TOPLEVEL_STATE_INVALID;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -84,6 +89,12 @@ static void print_toplevel(struct toplevel_v1 *toplevel, bool print_endl) {
|
||||||
toplevel->current.title ?: "(nil)",
|
toplevel->current.title ?: "(nil)",
|
||||||
toplevel->current.app_id ?: "(nil)");
|
toplevel->current.app_id ?: "(nil)");
|
||||||
|
|
||||||
|
if (toplevel->current.parent_id != no_parent) {
|
||||||
|
printf(" parent=%u", toplevel->current.parent_id);
|
||||||
|
} else {
|
||||||
|
printf(" no parent");
|
||||||
|
}
|
||||||
|
|
||||||
if (print_endl) {
|
if (print_endl) {
|
||||||
printf("\n");
|
printf("\n");
|
||||||
}
|
}
|
||||||
|
|
@ -172,6 +183,28 @@ static void toplevel_handle_state(void *data,
|
||||||
toplevel->pending.state = array_to_state(state);
|
toplevel->pending.state = array_to_state(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static struct zwlr_foreign_toplevel_manager_v1 *toplevel_manager = NULL;
|
||||||
|
static struct wl_list toplevel_list;
|
||||||
|
|
||||||
|
static void toplevel_handle_parent(void *data,
|
||||||
|
struct zwlr_foreign_toplevel_handle_v1 *zwlr_toplevel,
|
||||||
|
struct zwlr_foreign_toplevel_handle_v1 *zwlr_parent) {
|
||||||
|
struct toplevel_v1 *toplevel = data;
|
||||||
|
toplevel->pending.parent_id = no_parent;
|
||||||
|
if (zwlr_parent) {
|
||||||
|
struct toplevel_v1 *toplevel_tmp;
|
||||||
|
wl_list_for_each(toplevel_tmp, &toplevel_list, link) {
|
||||||
|
if (toplevel_tmp->zwlr_toplevel == zwlr_parent) {
|
||||||
|
toplevel->pending.parent_id = toplevel_tmp->id;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (toplevel->pending.parent_id == no_parent) {
|
||||||
|
fprintf(stderr, "Cannot find parent toplevel!\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void toplevel_handle_done(void *data,
|
static void toplevel_handle_done(void *data,
|
||||||
struct zwlr_foreign_toplevel_handle_v1 *zwlr_toplevel) {
|
struct zwlr_foreign_toplevel_handle_v1 *zwlr_toplevel) {
|
||||||
struct toplevel_v1 *toplevel = data;
|
struct toplevel_v1 *toplevel = data;
|
||||||
|
|
@ -202,11 +235,9 @@ static const struct zwlr_foreign_toplevel_handle_v1_listener toplevel_impl = {
|
||||||
.state = toplevel_handle_state,
|
.state = toplevel_handle_state,
|
||||||
.done = toplevel_handle_done,
|
.done = toplevel_handle_done,
|
||||||
.closed = toplevel_handle_closed,
|
.closed = toplevel_handle_closed,
|
||||||
|
.parent = toplevel_handle_parent
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct zwlr_foreign_toplevel_manager_v1 *toplevel_manager = NULL;
|
|
||||||
static struct wl_list toplevel_list;
|
|
||||||
|
|
||||||
static void toplevel_manager_handle_toplevel(void *data,
|
static void toplevel_manager_handle_toplevel(void *data,
|
||||||
struct zwlr_foreign_toplevel_manager_v1 *toplevel_manager,
|
struct zwlr_foreign_toplevel_manager_v1 *toplevel_manager,
|
||||||
struct zwlr_foreign_toplevel_handle_v1 *zwlr_toplevel) {
|
struct zwlr_foreign_toplevel_handle_v1 *zwlr_toplevel) {
|
||||||
|
|
@ -218,6 +249,8 @@ static void toplevel_manager_handle_toplevel(void *data,
|
||||||
|
|
||||||
toplevel->id = global_id++;
|
toplevel->id = global_id++;
|
||||||
toplevel->zwlr_toplevel = zwlr_toplevel;
|
toplevel->zwlr_toplevel = zwlr_toplevel;
|
||||||
|
toplevel->current.parent_id = no_parent;
|
||||||
|
toplevel->pending.parent_id = no_parent;
|
||||||
wl_list_insert(&toplevel_list, &toplevel->link);
|
wl_list_insert(&toplevel_list, &toplevel->link);
|
||||||
|
|
||||||
zwlr_foreign_toplevel_handle_v1_add_listener(zwlr_toplevel, &toplevel_impl,
|
zwlr_foreign_toplevel_handle_v1_add_listener(zwlr_toplevel, &toplevel_impl,
|
||||||
|
|
@ -332,7 +365,6 @@ int main(int argc, char **argv) {
|
||||||
|
|
||||||
struct wl_registry *registry = wl_display_get_registry(display);
|
struct wl_registry *registry = wl_display_get_registry(display);
|
||||||
wl_registry_add_listener(registry, ®istry_listener, NULL);
|
wl_registry_add_listener(registry, ®istry_listener, NULL);
|
||||||
wl_display_dispatch(display);
|
|
||||||
wl_display_roundtrip(display);
|
wl_display_roundtrip(display);
|
||||||
|
|
||||||
if (toplevel_manager == NULL) {
|
if (toplevel_manager == NULL) {
|
||||||
|
|
|
||||||
|
|
@ -162,7 +162,6 @@ int main(int argc, char *argv[]) {
|
||||||
|
|
||||||
struct wl_registry *registry = wl_display_get_registry(display);
|
struct wl_registry *registry = wl_display_get_registry(display);
|
||||||
wl_registry_add_listener(registry, ®istry_listener, NULL);
|
wl_registry_add_listener(registry, ®istry_listener, NULL);
|
||||||
wl_display_dispatch(display);
|
|
||||||
wl_display_roundtrip(display);
|
wl_display_roundtrip(display);
|
||||||
|
|
||||||
if (gamma_control_manager == NULL) {
|
if (gamma_control_manager == NULL) {
|
||||||
|
|
|
||||||
|
|
@ -177,7 +177,6 @@ int main(int argc, char **argv) {
|
||||||
|
|
||||||
struct wl_registry *registry = wl_display_get_registry(display);
|
struct wl_registry *registry = wl_display_get_registry(display);
|
||||||
wl_registry_add_listener(registry, ®istry_listener, NULL);
|
wl_registry_add_listener(registry, ®istry_listener, NULL);
|
||||||
wl_display_dispatch(display);
|
|
||||||
wl_display_roundtrip(display);
|
wl_display_roundtrip(display);
|
||||||
|
|
||||||
if (compositor == NULL) {
|
if (compositor == NULL) {
|
||||||
|
|
|
||||||
|
|
@ -125,7 +125,6 @@ int main(int argc, char *argv[]) {
|
||||||
|
|
||||||
struct wl_registry *registry = wl_display_get_registry(display);
|
struct wl_registry *registry = wl_display_get_registry(display);
|
||||||
wl_registry_add_listener(registry, ®istry_listener, NULL);
|
wl_registry_add_listener(registry, ®istry_listener, NULL);
|
||||||
wl_display_dispatch(display);
|
|
||||||
wl_display_roundtrip(display);
|
wl_display_roundtrip(display);
|
||||||
wl_registry_destroy(registry);
|
wl_registry_destroy(registry);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -150,7 +150,6 @@ int main(int argc, char **argv) {
|
||||||
struct wl_registry *registry = wl_display_get_registry(display);
|
struct wl_registry *registry = wl_display_get_registry(display);
|
||||||
assert(registry);
|
assert(registry);
|
||||||
wl_registry_add_listener(registry, ®istry_listener, NULL);
|
wl_registry_add_listener(registry, ®istry_listener, NULL);
|
||||||
wl_display_dispatch(display);
|
|
||||||
wl_display_roundtrip(display);
|
wl_display_roundtrip(display);
|
||||||
assert(compositor && seat && wm_base && input_inhibit_manager);
|
assert(compositor && seat && wm_base && input_inhibit_manager);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -191,7 +191,6 @@ int main(int argc, char **argv) {
|
||||||
|
|
||||||
struct wl_registry *registry = wl_display_get_registry(display);
|
struct wl_registry *registry = wl_display_get_registry(display);
|
||||||
wl_registry_add_listener(registry, ®istry_listener, NULL);
|
wl_registry_add_listener(registry, ®istry_listener, NULL);
|
||||||
wl_display_dispatch(display);
|
|
||||||
wl_display_roundtrip(display);
|
wl_display_roundtrip(display);
|
||||||
|
|
||||||
if (input_method_manager == NULL) {
|
if (input_method_manager == NULL) {
|
||||||
|
|
|
||||||
|
|
@ -324,7 +324,6 @@ int main(int argc, char **argv) {
|
||||||
|
|
||||||
struct wl_registry *registry = wl_display_get_registry(display);
|
struct wl_registry *registry = wl_display_get_registry(display);
|
||||||
wl_registry_add_listener(registry, ®istry_listener, NULL);
|
wl_registry_add_listener(registry, ®istry_listener, NULL);
|
||||||
wl_display_dispatch(display);
|
|
||||||
wl_display_roundtrip(display);
|
wl_display_roundtrip(display);
|
||||||
|
|
||||||
if (compositor == NULL) {
|
if (compositor == NULL) {
|
||||||
|
|
|
||||||
|
|
@ -209,7 +209,6 @@ int main(int argc, char **argv) {
|
||||||
|
|
||||||
struct wl_registry *registry = wl_display_get_registry(display);
|
struct wl_registry *registry = wl_display_get_registry(display);
|
||||||
wl_registry_add_listener(registry, ®istry_listener, NULL);
|
wl_registry_add_listener(registry, ®istry_listener, NULL);
|
||||||
wl_display_dispatch(display);
|
|
||||||
wl_display_roundtrip(display);
|
wl_display_roundtrip(display);
|
||||||
|
|
||||||
if (compositor == NULL) {
|
if (compositor == NULL) {
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
threads = dependency('threads')
|
threads = dependency('threads')
|
||||||
|
wayland_egl = dependency('wayland-egl')
|
||||||
wayland_cursor = dependency('wayland-cursor')
|
wayland_cursor = dependency('wayland-cursor')
|
||||||
libpng = dependency('libpng', required: false, disabler: true)
|
libpng = dependency('libpng', required: false, disabler: true)
|
||||||
# These versions correspond to ffmpeg 4.0
|
# These versions correspond to ffmpeg 4.0
|
||||||
|
|
@ -54,7 +55,7 @@ clients = {
|
||||||
},
|
},
|
||||||
'idle-inhibit': {
|
'idle-inhibit': {
|
||||||
'src': 'idle-inhibit.c',
|
'src': 'idle-inhibit.c',
|
||||||
'dep': wlroots,
|
'dep': [wayland_egl, wlroots],
|
||||||
'proto': [
|
'proto': [
|
||||||
'idle-inhibit-unstable-v1',
|
'idle-inhibit-unstable-v1',
|
||||||
'xdg-shell',
|
'xdg-shell',
|
||||||
|
|
@ -62,7 +63,7 @@ clients = {
|
||||||
},
|
},
|
||||||
'keyboard-shortcuts-inhibit': {
|
'keyboard-shortcuts-inhibit': {
|
||||||
'src': 'keyboard-shortcuts-inhibit.c',
|
'src': 'keyboard-shortcuts-inhibit.c',
|
||||||
'dep': [wayland_cursor, wlroots],
|
'dep': [wayland_egl, wayland_cursor, wlroots],
|
||||||
'proto': [
|
'proto': [
|
||||||
'keyboard-shortcuts-inhibit-unstable-v1',
|
'keyboard-shortcuts-inhibit-unstable-v1',
|
||||||
'xdg-shell',
|
'xdg-shell',
|
||||||
|
|
@ -70,7 +71,7 @@ clients = {
|
||||||
},
|
},
|
||||||
'layer-shell': {
|
'layer-shell': {
|
||||||
'src': 'layer-shell.c',
|
'src': 'layer-shell.c',
|
||||||
'dep': [wayland_cursor, wlroots],
|
'dep': [wayland_egl, wayland_cursor, wlroots],
|
||||||
'proto': [
|
'proto': [
|
||||||
'wlr-layer-shell-unstable-v1',
|
'wlr-layer-shell-unstable-v1',
|
||||||
'xdg-shell',
|
'xdg-shell',
|
||||||
|
|
@ -78,7 +79,7 @@ clients = {
|
||||||
},
|
},
|
||||||
'input-inhibitor': {
|
'input-inhibitor': {
|
||||||
'src': 'input-inhibitor.c',
|
'src': 'input-inhibitor.c',
|
||||||
'dep': [wayland_cursor, wlroots],
|
'dep': [wayland_egl, wayland_cursor, wlroots],
|
||||||
'proto': [
|
'proto': [
|
||||||
'wlr-input-inhibitor-unstable-v1',
|
'wlr-input-inhibitor-unstable-v1',
|
||||||
'xdg-shell',
|
'xdg-shell',
|
||||||
|
|
@ -96,7 +97,7 @@ clients = {
|
||||||
},
|
},
|
||||||
'pointer-constraints': {
|
'pointer-constraints': {
|
||||||
'src': 'pointer-constraints.c',
|
'src': 'pointer-constraints.c',
|
||||||
'dep': wlroots,
|
'dep': [wayland_egl, wlroots],
|
||||||
'proto': [
|
'proto': [
|
||||||
'pointer-constraints-unstable-v1',
|
'pointer-constraints-unstable-v1',
|
||||||
'xdg-shell',
|
'xdg-shell',
|
||||||
|
|
@ -104,7 +105,7 @@ clients = {
|
||||||
},
|
},
|
||||||
'relative-pointer': {
|
'relative-pointer': {
|
||||||
'src': 'relative-pointer-unstable-v1.c',
|
'src': 'relative-pointer-unstable-v1.c',
|
||||||
'dep': wlroots,
|
'dep': [wayland_egl, wlroots],
|
||||||
'proto': [
|
'proto': [
|
||||||
'pointer-constraints-unstable-v1',
|
'pointer-constraints-unstable-v1',
|
||||||
'relative-pointer-unstable-v1',
|
'relative-pointer-unstable-v1',
|
||||||
|
|
@ -137,7 +138,7 @@ clients = {
|
||||||
},
|
},
|
||||||
'toplevel-decoration': {
|
'toplevel-decoration': {
|
||||||
'src': 'toplevel-decoration.c',
|
'src': 'toplevel-decoration.c',
|
||||||
'dep': wlroots,
|
'dep': [wayland_egl, wlroots],
|
||||||
'proto': [
|
'proto': [
|
||||||
'xdg-decoration-unstable-v1',
|
'xdg-decoration-unstable-v1',
|
||||||
'xdg-shell',
|
'xdg-shell',
|
||||||
|
|
@ -145,7 +146,7 @@ clients = {
|
||||||
},
|
},
|
||||||
'input-method': {
|
'input-method': {
|
||||||
'src': 'input-method.c',
|
'src': 'input-method.c',
|
||||||
'dep': libepoll,
|
'dep': [wayland_egl, libepoll],
|
||||||
'proto': [
|
'proto': [
|
||||||
'input-method-unstable-v2',
|
'input-method-unstable-v2',
|
||||||
'text-input-unstable-v3',
|
'text-input-unstable-v3',
|
||||||
|
|
@ -154,7 +155,7 @@ clients = {
|
||||||
},
|
},
|
||||||
'text-input': {
|
'text-input': {
|
||||||
'src': 'text-input.c',
|
'src': 'text-input.c',
|
||||||
'dep': [wayland_cursor, wlroots],
|
'dep': [wayland_egl, wayland_cursor, wlroots],
|
||||||
'proto': [
|
'proto': [
|
||||||
'text-input-unstable-v3',
|
'text-input-unstable-v3',
|
||||||
'xdg-shell',
|
'xdg-shell',
|
||||||
|
|
|
||||||
|
|
@ -10,13 +10,13 @@
|
||||||
#include <wayland-server-core.h>
|
#include <wayland-server-core.h>
|
||||||
#include <wlr/backend.h>
|
#include <wlr/backend.h>
|
||||||
#include <wlr/backend/session.h>
|
#include <wlr/backend/session.h>
|
||||||
#include <wlr/render/gles2.h>
|
|
||||||
#include <wlr/render/wlr_renderer.h>
|
#include <wlr/render/wlr_renderer.h>
|
||||||
#include <wlr/types/wlr_cursor.h>
|
#include <wlr/types/wlr_cursor.h>
|
||||||
#include <wlr/types/wlr_keyboard.h>
|
#include <wlr/types/wlr_keyboard.h>
|
||||||
#include <wlr/types/wlr_list.h>
|
#include <wlr/types/wlr_list.h>
|
||||||
#include <wlr/types/wlr_matrix.h>
|
#include <wlr/types/wlr_matrix.h>
|
||||||
#include <wlr/types/wlr_output_layout.h>
|
#include <wlr/types/wlr_output_layout.h>
|
||||||
|
#include <wlr/types/wlr_pointer.h>
|
||||||
#include <wlr/util/log.h>
|
#include <wlr/util/log.h>
|
||||||
#include <wlr/xcursor.h>
|
#include <wlr/xcursor.h>
|
||||||
#include <xkbcommon/xkbcommon.h>
|
#include <xkbcommon/xkbcommon.h>
|
||||||
|
|
|
||||||
|
|
@ -190,7 +190,7 @@ static void keyboard_key_notify(struct wl_listener *listener, void *data) {
|
||||||
// and make this change in pixels/sec^2
|
// and make this change in pixels/sec^2
|
||||||
// Also, key repeat
|
// Also, key repeat
|
||||||
int delta = 75;
|
int delta = 75;
|
||||||
if (event->state == WLR_KEY_PRESSED) {
|
if (event->state == WL_KEYBOARD_KEY_STATE_PRESSED) {
|
||||||
switch (sym) {
|
switch (sym) {
|
||||||
case XKB_KEY_Left:
|
case XKB_KEY_Left:
|
||||||
update_velocities(sample, -delta, 0);
|
update_velocities(sample, -delta, 0);
|
||||||
|
|
|
||||||
|
|
@ -109,12 +109,11 @@ int main(int argc, char *argv[]) {
|
||||||
|
|
||||||
struct wl_registry *registry = wl_display_get_registry(display);
|
struct wl_registry *registry = wl_display_get_registry(display);
|
||||||
wl_registry_add_listener(registry, ®istry_listener, NULL);
|
wl_registry_add_listener(registry, ®istry_listener, NULL);
|
||||||
wl_display_dispatch(display);
|
|
||||||
wl_display_roundtrip(display);
|
wl_display_roundtrip(display);
|
||||||
|
|
||||||
if (output_power_manager == NULL) {
|
if (output_power_manager == NULL) {
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"compositor doesn't support wlr-output-power-managment-unstable-v1\n");
|
"compositor doesn't support wlr-output-power-management-unstable-v1\n");
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -198,7 +198,6 @@ int main(int argc, char **argv) {
|
||||||
|
|
||||||
struct wl_registry *registry = wl_display_get_registry(display);
|
struct wl_registry *registry = wl_display_get_registry(display);
|
||||||
wl_registry_add_listener(registry, ®istry_listener, NULL);
|
wl_registry_add_listener(registry, ®istry_listener, NULL);
|
||||||
wl_display_dispatch(display);
|
|
||||||
wl_display_roundtrip(display);
|
wl_display_roundtrip(display);
|
||||||
|
|
||||||
struct wl_region *disjoint_region = wl_compositor_create_region(compositor);
|
struct wl_region *disjoint_region = wl_compositor_create_region(compositor);
|
||||||
|
|
|
||||||
|
|
@ -9,13 +9,15 @@
|
||||||
#include <wayland-server-core.h>
|
#include <wayland-server-core.h>
|
||||||
#include <wlr/backend.h>
|
#include <wlr/backend.h>
|
||||||
#include <wlr/backend/session.h>
|
#include <wlr/backend/session.h>
|
||||||
#include <wlr/render/gles2.h>
|
|
||||||
#include <wlr/render/wlr_renderer.h>
|
#include <wlr/render/wlr_renderer.h>
|
||||||
#include <wlr/types/wlr_cursor.h>
|
#include <wlr/types/wlr_cursor.h>
|
||||||
#include <wlr/types/wlr_keyboard.h>
|
#include <wlr/types/wlr_keyboard.h>
|
||||||
#include <wlr/types/wlr_list.h>
|
#include <wlr/types/wlr_list.h>
|
||||||
#include <wlr/types/wlr_matrix.h>
|
#include <wlr/types/wlr_matrix.h>
|
||||||
#include <wlr/types/wlr_output_layout.h>
|
#include <wlr/types/wlr_output_layout.h>
|
||||||
|
#include <wlr/types/wlr_pointer.h>
|
||||||
|
#include <wlr/types/wlr_tablet_tool.h>
|
||||||
|
#include <wlr/types/wlr_touch.h>
|
||||||
#include <wlr/types/wlr_xcursor_manager.h>
|
#include <wlr/types/wlr_xcursor_manager.h>
|
||||||
#include <wlr/util/log.h>
|
#include <wlr/util/log.h>
|
||||||
#include <xkbcommon/xkbcommon.h>
|
#include <xkbcommon/xkbcommon.h>
|
||||||
|
|
|
||||||
|
|
@ -412,7 +412,6 @@ int main(int argc, char **argv) {
|
||||||
|
|
||||||
struct wl_registry *registry = wl_display_get_registry(display);
|
struct wl_registry *registry = wl_display_get_registry(display);
|
||||||
wl_registry_add_listener(registry, ®istry_listener, NULL);
|
wl_registry_add_listener(registry, ®istry_listener, NULL);
|
||||||
wl_display_dispatch(display);
|
|
||||||
wl_display_roundtrip(display);
|
wl_display_roundtrip(display);
|
||||||
|
|
||||||
/* Check that all the global interfaces were captured */
|
/* Check that all the global interfaces were captured */
|
||||||
|
|
|
||||||
|
|
@ -140,7 +140,7 @@ static void keyboard_key_notify(struct wl_listener *listener, void *data) {
|
||||||
if (sym == XKB_KEY_Escape) {
|
if (sym == XKB_KEY_Escape) {
|
||||||
wl_display_terminate(sample->display);
|
wl_display_terminate(sample->display);
|
||||||
}
|
}
|
||||||
if (event->state == WLR_KEY_PRESSED) {
|
if (event->state == WL_KEYBOARD_KEY_STATE_PRESSED) {
|
||||||
switch (sym) {
|
switch (sym) {
|
||||||
case XKB_KEY_Left:
|
case XKB_KEY_Left:
|
||||||
update_velocities(sample, -16, 0);
|
update_velocities(sample, -16, 0);
|
||||||
|
|
|
||||||
|
|
@ -297,7 +297,7 @@ int main(int argc, char *argv[]) {
|
||||||
|
|
||||||
drm_fd = open(render_node, O_RDWR);
|
drm_fd = open(render_node, O_RDWR);
|
||||||
if (drm_fd < 0) {
|
if (drm_fd < 0) {
|
||||||
fprintf(stderr, "Failed to open drm render node: %m\n");
|
perror("Failed to open drm render node");
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -309,13 +309,12 @@ int main(int argc, char *argv[]) {
|
||||||
|
|
||||||
struct wl_display *display = wl_display_connect(NULL);
|
struct wl_display *display = wl_display_connect(NULL);
|
||||||
if (display == NULL) {
|
if (display == NULL) {
|
||||||
fprintf(stderr, "failed to create display: %m\n");
|
perror("failed to create display");
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct wl_registry *registry = wl_display_get_registry(display);
|
struct wl_registry *registry = wl_display_get_registry(display);
|
||||||
wl_registry_add_listener(registry, ®istry_listener, NULL);
|
wl_registry_add_listener(registry, ®istry_listener, NULL);
|
||||||
wl_display_dispatch(display);
|
|
||||||
wl_display_roundtrip(display);
|
wl_display_roundtrip(display);
|
||||||
|
|
||||||
if (dmabuf == NULL) {
|
if (dmabuf == NULL) {
|
||||||
|
|
@ -344,7 +343,7 @@ int main(int argc, char *argv[]) {
|
||||||
void *data = gbm_bo_map(buffer.bo, 0, 0, buffer.width, buffer.height,
|
void *data = gbm_bo_map(buffer.bo, 0, 0, buffer.width, buffer.height,
|
||||||
GBM_BO_TRANSFER_READ, &stride, &map_data);
|
GBM_BO_TRANSFER_READ, &stride, &map_data);
|
||||||
if (!data) {
|
if (!data) {
|
||||||
fprintf(stderr, "Failed to map gbm bo: %m\n");
|
perror("Failed to map gbm bo");
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -90,7 +90,7 @@ static struct wl_buffer *create_shm_buffer(enum wl_shm_format fmt,
|
||||||
|
|
||||||
void *data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
|
void *data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
|
||||||
if (data == MAP_FAILED) {
|
if (data == MAP_FAILED) {
|
||||||
fprintf(stderr, "mmap failed: %m\n");
|
perror("mmap failed");
|
||||||
close(fd);
|
close(fd);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
@ -228,13 +228,12 @@ static void write_image(char *filename, enum wl_shm_format wl_fmt, int width,
|
||||||
int main(int argc, char *argv[]) {
|
int main(int argc, char *argv[]) {
|
||||||
struct wl_display * display = wl_display_connect(NULL);
|
struct wl_display * display = wl_display_connect(NULL);
|
||||||
if (display == NULL) {
|
if (display == NULL) {
|
||||||
fprintf(stderr, "failed to create display: %m\n");
|
perror("failed to create display");
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct wl_registry *registry = wl_display_get_registry(display);
|
struct wl_registry *registry = wl_display_get_registry(display);
|
||||||
wl_registry_add_listener(registry, ®istry_listener, NULL);
|
wl_registry_add_listener(registry, ®istry_listener, NULL);
|
||||||
wl_display_dispatch(display);
|
|
||||||
wl_display_roundtrip(display);
|
wl_display_roundtrip(display);
|
||||||
|
|
||||||
if (shm == NULL) {
|
if (shm == NULL) {
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
#define _POSIX_C_SOURCE 200112L
|
#define _POSIX_C_SOURCE 200112L
|
||||||
#include <GLES2/gl2.h>
|
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
@ -8,8 +7,10 @@
|
||||||
#include <wayland-server-core.h>
|
#include <wayland-server-core.h>
|
||||||
#include <wlr/backend.h>
|
#include <wlr/backend.h>
|
||||||
#include <wlr/backend/session.h>
|
#include <wlr/backend/session.h>
|
||||||
|
#include <wlr/render/wlr_renderer.h>
|
||||||
#include <wlr/types/wlr_output.h>
|
#include <wlr/types/wlr_output.h>
|
||||||
#include <wlr/types/wlr_input_device.h>
|
#include <wlr/types/wlr_input_device.h>
|
||||||
|
#include <wlr/types/wlr_keyboard.h>
|
||||||
#include <wlr/util/log.h>
|
#include <wlr/util/log.h>
|
||||||
#include <xkbcommon/xkbcommon.h>
|
#include <xkbcommon/xkbcommon.h>
|
||||||
|
|
||||||
|
|
@ -18,7 +19,7 @@ struct sample_state {
|
||||||
struct wl_listener new_output;
|
struct wl_listener new_output;
|
||||||
struct wl_listener new_input;
|
struct wl_listener new_input;
|
||||||
struct timespec last_frame;
|
struct timespec last_frame;
|
||||||
float color[3];
|
float color[4];
|
||||||
int dec;
|
int dec;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -40,6 +41,8 @@ static void output_frame_notify(struct wl_listener *listener, void *data) {
|
||||||
struct sample_output *sample_output =
|
struct sample_output *sample_output =
|
||||||
wl_container_of(listener, sample_output, frame);
|
wl_container_of(listener, sample_output, frame);
|
||||||
struct sample_state *sample = sample_output->sample;
|
struct sample_state *sample = sample_output->sample;
|
||||||
|
struct wlr_output *wlr_output = sample_output->output;
|
||||||
|
|
||||||
struct timespec now;
|
struct timespec now;
|
||||||
clock_gettime(CLOCK_MONOTONIC, &now);
|
clock_gettime(CLOCK_MONOTONIC, &now);
|
||||||
|
|
||||||
|
|
@ -56,12 +59,15 @@ static void output_frame_notify(struct wl_listener *listener, void *data) {
|
||||||
sample->dec = inc;
|
sample->dec = inc;
|
||||||
}
|
}
|
||||||
|
|
||||||
wlr_output_attach_render(sample_output->output, NULL);
|
wlr_output_attach_render(wlr_output, NULL);
|
||||||
|
|
||||||
glClearColor(sample->color[0], sample->color[1], sample->color[2], 1.0);
|
struct wlr_renderer *renderer =
|
||||||
glClear(GL_COLOR_BUFFER_BIT);
|
wlr_backend_get_renderer(wlr_output->backend);
|
||||||
|
wlr_renderer_begin(renderer, wlr_output->width, wlr_output->height);
|
||||||
|
wlr_renderer_clear(renderer, sample->color);
|
||||||
|
wlr_renderer_end(renderer);
|
||||||
|
|
||||||
wlr_output_commit(sample_output->output);
|
wlr_output_commit(wlr_output);
|
||||||
sample->last_frame = now;
|
sample->last_frame = now;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -80,9 +86,9 @@ static void new_output_notify(struct wl_listener *listener, void *data) {
|
||||||
wl_container_of(listener, sample, new_output);
|
wl_container_of(listener, sample, new_output);
|
||||||
struct sample_output *sample_output =
|
struct sample_output *sample_output =
|
||||||
calloc(1, sizeof(struct sample_output));
|
calloc(1, sizeof(struct sample_output));
|
||||||
if (!wl_list_empty(&output->modes)) {
|
|
||||||
struct wlr_output_mode *mode =
|
struct wlr_output_mode *mode = wlr_output_preferred_mode(output);
|
||||||
wl_container_of(output->modes.prev, mode, link);
|
if (mode != NULL) {
|
||||||
wlr_output_set_mode(output, mode);
|
wlr_output_set_mode(output, mode);
|
||||||
}
|
}
|
||||||
sample_output->output = output;
|
sample_output->output = output;
|
||||||
|
|
@ -162,7 +168,7 @@ int main(void) {
|
||||||
wlr_log_init(WLR_DEBUG, NULL);
|
wlr_log_init(WLR_DEBUG, NULL);
|
||||||
struct wl_display *display = wl_display_create();
|
struct wl_display *display = wl_display_create();
|
||||||
struct sample_state state = {
|
struct sample_state state = {
|
||||||
.color = { 1.0, 0.0, 0.0 },
|
.color = { 1.0, 0.0, 0.0, 1.0 },
|
||||||
.dec = 0,
|
.dec = 0,
|
||||||
.last_frame = { 0 },
|
.last_frame = { 0 },
|
||||||
.display = display
|
.display = display
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@
|
||||||
#include <wlr/types/wlr_matrix.h>
|
#include <wlr/types/wlr_matrix.h>
|
||||||
#include <wlr/types/wlr_output.h>
|
#include <wlr/types/wlr_output.h>
|
||||||
#include <wlr/types/wlr_input_device.h>
|
#include <wlr/types/wlr_input_device.h>
|
||||||
|
#include <wlr/types/wlr_keyboard.h>
|
||||||
#include <wlr/types/wlr_tablet_pad.h>
|
#include <wlr/types/wlr_tablet_pad.h>
|
||||||
#include <wlr/types/wlr_tablet_tool.h>
|
#include <wlr/types/wlr_tablet_tool.h>
|
||||||
#include <wlr/util/log.h>
|
#include <wlr/util/log.h>
|
||||||
|
|
|
||||||
|
|
@ -344,7 +344,6 @@ int main(int argc, char **argv) {
|
||||||
|
|
||||||
struct wl_registry *registry = wl_display_get_registry(display);
|
struct wl_registry *registry = wl_display_get_registry(display);
|
||||||
wl_registry_add_listener(registry, ®istry_listener, NULL);
|
wl_registry_add_listener(registry, ®istry_listener, NULL);
|
||||||
wl_display_dispatch(display);
|
|
||||||
wl_display_roundtrip(display);
|
wl_display_roundtrip(display);
|
||||||
|
|
||||||
if (compositor == NULL) {
|
if (compositor == NULL) {
|
||||||
|
|
|
||||||
|
|
@ -203,7 +203,6 @@ int main(int argc, char **argv) {
|
||||||
|
|
||||||
struct wl_registry *registry = wl_display_get_registry(display);
|
struct wl_registry *registry = wl_display_get_registry(display);
|
||||||
wl_registry_add_listener(registry, ®istry_listener, NULL);
|
wl_registry_add_listener(registry, ®istry_listener, NULL);
|
||||||
wl_display_dispatch(display);
|
|
||||||
wl_display_roundtrip(display);
|
wl_display_roundtrip(display);
|
||||||
|
|
||||||
if (compositor == NULL) {
|
if (compositor == NULL) {
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,9 @@
|
||||||
#include <wlr/render/wlr_renderer.h>
|
#include <wlr/render/wlr_renderer.h>
|
||||||
#include <wlr/types/wlr_list.h>
|
#include <wlr/types/wlr_list.h>
|
||||||
#include <wlr/types/wlr_input_device.h>
|
#include <wlr/types/wlr_input_device.h>
|
||||||
|
#include <wlr/types/wlr_keyboard.h>
|
||||||
#include <wlr/types/wlr_matrix.h>
|
#include <wlr/types/wlr_matrix.h>
|
||||||
|
#include <wlr/types/wlr_touch.h>
|
||||||
#include <wlr/util/log.h>
|
#include <wlr/util/log.h>
|
||||||
#include <xkbcommon/xkbcommon.h>
|
#include <xkbcommon/xkbcommon.h>
|
||||||
#include "cat.h"
|
#include "cat.h"
|
||||||
|
|
|
||||||
|
|
@ -61,13 +61,12 @@ int main(int argc, char *argv[]) {
|
||||||
}
|
}
|
||||||
struct wl_display * display = wl_display_connect(NULL);
|
struct wl_display * display = wl_display_connect(NULL);
|
||||||
if (display == NULL) {
|
if (display == NULL) {
|
||||||
fprintf(stderr, "failed to create display: %m\n");
|
perror("failed to create display");
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct wl_registry *registry = wl_display_get_registry(display);
|
struct wl_registry *registry = wl_display_get_registry(display);
|
||||||
wl_registry_add_listener(registry, ®istry_listener, NULL);
|
wl_registry_add_listener(registry, ®istry_listener, NULL);
|
||||||
wl_display_dispatch(display);
|
|
||||||
wl_display_roundtrip(display);
|
wl_display_roundtrip(display);
|
||||||
|
|
||||||
if (pointer_manager == NULL) {
|
if (pointer_manager == NULL) {
|
||||||
|
|
@ -132,7 +131,6 @@ int main(int argc, char *argv[]) {
|
||||||
|
|
||||||
zwlr_virtual_pointer_v1_frame(pointer);
|
zwlr_virtual_pointer_v1_frame(pointer);
|
||||||
zwlr_virtual_pointer_v1_destroy(pointer);
|
zwlr_virtual_pointer_v1_destroy(pointer);
|
||||||
wl_display_dispatch(display);
|
|
||||||
|
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,6 @@ struct wlr_drm_plane {
|
||||||
/* Buffer currently displayed on screen */
|
/* Buffer currently displayed on screen */
|
||||||
struct wlr_drm_fb current_fb;
|
struct wlr_drm_fb current_fb;
|
||||||
|
|
||||||
uint32_t drm_format; // ARGB2101010, XRGB2101010, ARGB8888, or XRGB8888
|
|
||||||
struct wlr_drm_format_set formats;
|
struct wlr_drm_format_set formats;
|
||||||
|
|
||||||
// Only used by cursor
|
// Only used by cursor
|
||||||
|
|
@ -63,13 +62,6 @@ struct wlr_drm_crtc {
|
||||||
struct wlr_drm_plane *primary;
|
struct wlr_drm_plane *primary;
|
||||||
struct wlr_drm_plane *cursor;
|
struct wlr_drm_plane *cursor;
|
||||||
|
|
||||||
/*
|
|
||||||
* We don't support overlay planes yet, but we keep track of them to
|
|
||||||
* give to DRM lease clients.
|
|
||||||
*/
|
|
||||||
size_t num_overlays;
|
|
||||||
uint32_t *overlays;
|
|
||||||
|
|
||||||
union wlr_drm_crtc_props props;
|
union wlr_drm_crtc_props props;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -82,6 +74,8 @@ struct wlr_drm_backend {
|
||||||
bool addfb2_modifiers;
|
bool addfb2_modifiers;
|
||||||
|
|
||||||
int fd;
|
int fd;
|
||||||
|
char *name;
|
||||||
|
struct wlr_device *dev;
|
||||||
|
|
||||||
size_t num_crtcs;
|
size_t num_crtcs;
|
||||||
struct wlr_drm_crtc *crtcs;
|
struct wlr_drm_crtc *crtcs;
|
||||||
|
|
@ -115,8 +109,10 @@ struct wlr_drm_mode {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct wlr_drm_connector {
|
struct wlr_drm_connector {
|
||||||
struct wlr_output output;
|
struct wlr_output output; // only valid if state != DISCONNECTED
|
||||||
|
|
||||||
|
struct wlr_drm_backend *backend;
|
||||||
|
char name[24];
|
||||||
enum wlr_drm_connector_state state;
|
enum wlr_drm_connector_state state;
|
||||||
struct wlr_output_mode *desired_mode;
|
struct wlr_output_mode *desired_mode;
|
||||||
bool desired_enabled;
|
bool desired_enabled;
|
||||||
|
|
@ -134,7 +130,7 @@ struct wlr_drm_connector {
|
||||||
struct wl_list link;
|
struct wl_list link;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We've asked for a state change in the kernel, and yet to recieve a
|
* We've asked for a state change in the kernel, and yet to receive a
|
||||||
* notification for its completion. Currently, the kernel only has a
|
* notification for its completion. Currently, the kernel only has a
|
||||||
* queue length of 1, and no way to modify your submissions after
|
* queue length of 1, and no way to modify your submissions after
|
||||||
* they're sent.
|
* they're sent.
|
||||||
|
|
@ -150,6 +146,7 @@ void finish_drm_resources(struct wlr_drm_backend *drm);
|
||||||
void restore_drm_outputs(struct wlr_drm_backend *drm);
|
void restore_drm_outputs(struct wlr_drm_backend *drm);
|
||||||
void scan_drm_connectors(struct wlr_drm_backend *state);
|
void scan_drm_connectors(struct wlr_drm_backend *state);
|
||||||
int handle_drm_event(int fd, uint32_t mask, void *data);
|
int handle_drm_event(int fd, uint32_t mask, void *data);
|
||||||
|
void destroy_drm_connector(struct wlr_drm_connector *conn);
|
||||||
bool drm_connector_set_mode(struct wlr_drm_connector *conn,
|
bool drm_connector_set_mode(struct wlr_drm_connector *conn,
|
||||||
struct wlr_output_mode *mode);
|
struct wlr_output_mode *mode);
|
||||||
bool drm_connector_is_cursor_visible(struct wlr_drm_connector *conn);
|
bool drm_connector_is_cursor_visible(struct wlr_drm_connector *conn);
|
||||||
|
|
@ -159,4 +156,9 @@ size_t drm_crtc_get_gamma_lut_size(struct wlr_drm_backend *drm,
|
||||||
|
|
||||||
struct wlr_drm_fb *plane_get_next_fb(struct wlr_drm_plane *plane);
|
struct wlr_drm_fb *plane_get_next_fb(struct wlr_drm_plane *plane);
|
||||||
|
|
||||||
|
#define wlr_drm_conn_log(conn, verb, fmt, ...) \
|
||||||
|
wlr_log(verb, "connector %s: " fmt, conn->name, ##__VA_ARGS__)
|
||||||
|
#define wlr_drm_conn_log_errno(conn, verb, fmt, ...) \
|
||||||
|
wlr_log_errno(verb, "connector %s: " fmt, conn->name, ##__VA_ARGS__)
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -28,8 +28,6 @@ union wlr_drm_connector_props {
|
||||||
union wlr_drm_crtc_props {
|
union wlr_drm_crtc_props {
|
||||||
struct {
|
struct {
|
||||||
// Neither of these are guaranteed to exist
|
// Neither of these are guaranteed to exist
|
||||||
uint32_t rotation;
|
|
||||||
uint32_t scaling_mode;
|
|
||||||
uint32_t vrr_enabled;
|
uint32_t vrr_enabled;
|
||||||
uint32_t gamma_lut;
|
uint32_t gamma_lut;
|
||||||
uint32_t gamma_lut_size;
|
uint32_t gamma_lut_size;
|
||||||
|
|
|
||||||
|
|
@ -17,9 +17,8 @@ struct wlr_drm_renderer {
|
||||||
struct gbm_device *gbm;
|
struct gbm_device *gbm;
|
||||||
struct wlr_egl egl;
|
struct wlr_egl egl;
|
||||||
|
|
||||||
uint32_t gbm_format;
|
|
||||||
|
|
||||||
struct wlr_renderer *wlr_rend;
|
struct wlr_renderer *wlr_rend;
|
||||||
|
struct wlr_gbm_allocator *allocator;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct wlr_drm_surface {
|
struct wlr_drm_surface {
|
||||||
|
|
@ -28,27 +27,17 @@ struct wlr_drm_surface {
|
||||||
uint32_t width;
|
uint32_t width;
|
||||||
uint32_t height;
|
uint32_t height;
|
||||||
|
|
||||||
struct gbm_surface *gbm;
|
struct wlr_swapchain *swapchain;
|
||||||
EGLSurface egl;
|
struct wlr_buffer *back_buffer;
|
||||||
};
|
|
||||||
|
|
||||||
enum wlr_drm_fb_type {
|
|
||||||
WLR_DRM_FB_TYPE_NONE,
|
|
||||||
WLR_DRM_FB_TYPE_SURFACE,
|
|
||||||
WLR_DRM_FB_TYPE_WLR_BUFFER
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct wlr_drm_fb {
|
struct wlr_drm_fb {
|
||||||
enum wlr_drm_fb_type type;
|
|
||||||
struct gbm_bo *bo;
|
struct gbm_bo *bo;
|
||||||
|
struct wlr_buffer *wlr_buf;
|
||||||
|
|
||||||
struct wlr_drm_surface *mgpu_surf;
|
struct wlr_drm_surface *mgpu_surf;
|
||||||
struct gbm_bo *mgpu_bo;
|
struct gbm_bo *mgpu_bo;
|
||||||
|
struct wlr_buffer *mgpu_wlr_buf;
|
||||||
union {
|
|
||||||
struct wlr_drm_surface *surf;
|
|
||||||
struct wlr_buffer *wlr_buf;
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
bool init_drm_renderer(struct wlr_drm_backend *drm,
|
bool init_drm_renderer(struct wlr_drm_backend *drm,
|
||||||
|
|
@ -56,6 +45,7 @@ bool init_drm_renderer(struct wlr_drm_backend *drm,
|
||||||
void finish_drm_renderer(struct wlr_drm_renderer *renderer);
|
void finish_drm_renderer(struct wlr_drm_renderer *renderer);
|
||||||
|
|
||||||
bool drm_surface_make_current(struct wlr_drm_surface *surf, int *buffer_age);
|
bool drm_surface_make_current(struct wlr_drm_surface *surf, int *buffer_age);
|
||||||
|
void drm_surface_unset_current(struct wlr_drm_surface *surf);
|
||||||
bool export_drm_bo(struct gbm_bo *bo, struct wlr_dmabuf_attributes *attribs);
|
bool export_drm_bo(struct gbm_bo *bo, struct wlr_dmabuf_attributes *attribs);
|
||||||
|
|
||||||
void drm_fb_clear(struct wlr_drm_fb *fb);
|
void drm_fb_clear(struct wlr_drm_fb *fb);
|
||||||
|
|
@ -71,7 +61,7 @@ struct gbm_bo *drm_fb_acquire(struct wlr_drm_fb *fb, struct wlr_drm_backend *drm
|
||||||
|
|
||||||
bool drm_plane_init_surface(struct wlr_drm_plane *plane,
|
bool drm_plane_init_surface(struct wlr_drm_plane *plane,
|
||||||
struct wlr_drm_backend *drm, int32_t width, uint32_t height,
|
struct wlr_drm_backend *drm, int32_t width, uint32_t height,
|
||||||
uint32_t format, uint32_t flags, bool with_modifiers);
|
uint32_t format, bool force_linear, bool with_modifiers);
|
||||||
void drm_plane_finish_surface(struct wlr_drm_plane *plane);
|
void drm_plane_finish_surface(struct wlr_drm_plane *plane);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,6 @@
|
||||||
|
|
||||||
#include <wlr/backend/headless.h>
|
#include <wlr/backend/headless.h>
|
||||||
#include <wlr/backend/interface.h>
|
#include <wlr/backend/interface.h>
|
||||||
#include <wlr/render/gles2.h>
|
|
||||||
|
|
||||||
#define HEADLESS_DEFAULT_REFRESH (60 * 1000) // 60 Hz
|
#define HEADLESS_DEFAULT_REFRESH (60 * 1000) // 60 Hz
|
||||||
|
|
||||||
|
|
@ -12,6 +11,8 @@ struct wlr_headless_backend {
|
||||||
struct wlr_egl priv_egl; // may be uninitialized
|
struct wlr_egl priv_egl; // may be uninitialized
|
||||||
struct wlr_egl *egl;
|
struct wlr_egl *egl;
|
||||||
struct wlr_renderer *renderer;
|
struct wlr_renderer *renderer;
|
||||||
|
struct wlr_allocator *allocator;
|
||||||
|
struct wlr_drm_format *format;
|
||||||
struct wl_display *display;
|
struct wl_display *display;
|
||||||
struct wl_list outputs;
|
struct wl_list outputs;
|
||||||
size_t last_output_num;
|
size_t last_output_num;
|
||||||
|
|
@ -19,7 +20,6 @@ struct wlr_headless_backend {
|
||||||
struct wl_listener display_destroy;
|
struct wl_listener display_destroy;
|
||||||
struct wl_listener renderer_destroy;
|
struct wl_listener renderer_destroy;
|
||||||
bool started;
|
bool started;
|
||||||
GLenum internal_format;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct wlr_headless_output {
|
struct wlr_headless_output {
|
||||||
|
|
@ -28,7 +28,8 @@ struct wlr_headless_output {
|
||||||
struct wlr_headless_backend *backend;
|
struct wlr_headless_backend *backend;
|
||||||
struct wl_list link;
|
struct wl_list link;
|
||||||
|
|
||||||
GLuint fbo, rbo;
|
struct wlr_swapchain *swapchain;
|
||||||
|
struct wlr_buffer *back_buffer, *front_buffer;
|
||||||
|
|
||||||
struct wl_event_source *frame_timer;
|
struct wl_event_source *frame_timer;
|
||||||
int frame_delay; // ms
|
int frame_delay; // ms
|
||||||
|
|
|
||||||
8
include/backend/session/session.h
Normal file
8
include/backend/session/session.h
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
#ifndef BACKEND_SESSION_SESSION_H
|
||||||
|
#define BACKEND_SESSION_SESSION_H
|
||||||
|
|
||||||
|
struct wlr_session;
|
||||||
|
|
||||||
|
void session_init(struct wlr_session *session);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -4,14 +4,13 @@
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
|
||||||
#include <wayland-client.h>
|
#include <wayland-client.h>
|
||||||
#include <wayland-egl.h>
|
|
||||||
#include <wayland-server-core.h>
|
#include <wayland-server-core.h>
|
||||||
#include <wayland-util.h>
|
|
||||||
|
|
||||||
#include <wlr/backend/wayland.h>
|
#include <wlr/backend/wayland.h>
|
||||||
#include <wlr/render/egl.h>
|
#include <wlr/render/egl.h>
|
||||||
#include <wlr/render/wlr_renderer.h>
|
#include <wlr/render/wlr_renderer.h>
|
||||||
#include <wlr/types/wlr_box.h>
|
#include <wlr/types/wlr_box.h>
|
||||||
|
#include <wlr/types/wlr_pointer.h>
|
||||||
#include <wlr/render/drm_format_set.h>
|
#include <wlr/render/drm_format_set.h>
|
||||||
|
|
||||||
struct wlr_wl_backend {
|
struct wlr_wl_backend {
|
||||||
|
|
@ -24,9 +23,13 @@ struct wlr_wl_backend {
|
||||||
struct wl_list outputs;
|
struct wl_list outputs;
|
||||||
struct wlr_egl egl;
|
struct wlr_egl egl;
|
||||||
struct wlr_renderer *renderer;
|
struct wlr_renderer *renderer;
|
||||||
|
struct wlr_drm_format *format;
|
||||||
|
struct wlr_allocator *allocator;
|
||||||
|
struct wl_list buffers; // wlr_wl_buffer.link
|
||||||
size_t requested_outputs;
|
size_t requested_outputs;
|
||||||
size_t last_output_num;
|
size_t last_output_num;
|
||||||
struct wl_listener local_display_destroy;
|
struct wl_listener local_display_destroy;
|
||||||
|
|
||||||
/* remote state */
|
/* remote state */
|
||||||
struct wl_display *remote_display;
|
struct wl_display *remote_display;
|
||||||
struct wl_event_source *remote_display_src;
|
struct wl_event_source *remote_display_src;
|
||||||
|
|
@ -38,18 +41,17 @@ struct wlr_wl_backend {
|
||||||
struct wp_presentation *presentation;
|
struct wp_presentation *presentation;
|
||||||
struct zwp_linux_dmabuf_v1 *zwp_linux_dmabuf_v1;
|
struct zwp_linux_dmabuf_v1 *zwp_linux_dmabuf_v1;
|
||||||
struct zwp_relative_pointer_manager_v1 *zwp_relative_pointer_manager_v1;
|
struct zwp_relative_pointer_manager_v1 *zwp_relative_pointer_manager_v1;
|
||||||
struct wl_seat *seat;
|
struct wl_list seats; // wlr_wl_seat.link
|
||||||
struct wl_pointer *pointer;
|
|
||||||
struct wl_keyboard *keyboard;
|
|
||||||
struct wlr_wl_pointer *current_pointer;
|
|
||||||
struct zwp_tablet_manager_v2 *tablet_manager;
|
struct zwp_tablet_manager_v2 *tablet_manager;
|
||||||
char *seat_name;
|
|
||||||
struct wlr_drm_format_set linux_dmabuf_v1_formats;
|
struct wlr_drm_format_set linux_dmabuf_v1_formats;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct wlr_wl_buffer {
|
struct wlr_wl_buffer {
|
||||||
struct wlr_buffer *buffer;
|
struct wlr_buffer *buffer;
|
||||||
struct wl_buffer *wl_buffer;
|
struct wl_buffer *wl_buffer;
|
||||||
|
bool released;
|
||||||
|
struct wl_list link; // wlr_wl_backend.buffers
|
||||||
|
struct wl_listener buffer_destroy;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct wlr_wl_presentation_feedback {
|
struct wlr_wl_presentation_feedback {
|
||||||
|
|
@ -70,15 +72,17 @@ struct wlr_wl_output {
|
||||||
struct xdg_surface *xdg_surface;
|
struct xdg_surface *xdg_surface;
|
||||||
struct xdg_toplevel *xdg_toplevel;
|
struct xdg_toplevel *xdg_toplevel;
|
||||||
struct zxdg_toplevel_decoration_v1 *zxdg_toplevel_decoration_v1;
|
struct zxdg_toplevel_decoration_v1 *zxdg_toplevel_decoration_v1;
|
||||||
struct wl_egl_window *egl_window;
|
|
||||||
EGLSurface egl_surface;
|
|
||||||
struct wl_list presentation_feedbacks;
|
struct wl_list presentation_feedbacks;
|
||||||
|
|
||||||
|
struct wlr_swapchain *swapchain;
|
||||||
|
struct wlr_buffer *back_buffer;
|
||||||
|
|
||||||
uint32_t enter_serial;
|
uint32_t enter_serial;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
|
struct wlr_wl_pointer *pointer;
|
||||||
struct wl_surface *surface;
|
struct wl_surface *surface;
|
||||||
struct wl_egl_window *egl_window;
|
struct wlr_swapchain *swapchain;
|
||||||
int32_t hotspot_x, hotspot_y;
|
int32_t hotspot_x, hotspot_y;
|
||||||
int32_t width, height;
|
int32_t width, height;
|
||||||
} cursor;
|
} cursor;
|
||||||
|
|
@ -89,6 +93,7 @@ struct wlr_wl_input_device {
|
||||||
uint32_t fingers;
|
uint32_t fingers;
|
||||||
|
|
||||||
struct wlr_wl_backend *backend;
|
struct wlr_wl_backend *backend;
|
||||||
|
struct wlr_wl_seat *seat;
|
||||||
void *resource;
|
void *resource;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -107,18 +112,35 @@ struct wlr_wl_pointer {
|
||||||
struct wl_listener output_destroy;
|
struct wl_listener output_destroy;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct wlr_wl_seat {
|
||||||
|
struct wl_seat *wl_seat;
|
||||||
|
|
||||||
|
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);
|
struct wlr_wl_backend *get_wl_backend_from_backend(struct wlr_backend *backend);
|
||||||
void update_wl_output_cursor(struct wlr_wl_output *output);
|
void update_wl_output_cursor(struct wlr_wl_output *output);
|
||||||
struct wlr_wl_pointer *pointer_get_wl(struct wlr_pointer *wlr_pointer);
|
struct wlr_wl_pointer *pointer_get_wl(struct wlr_pointer *wlr_pointer);
|
||||||
void create_wl_pointer(struct wl_pointer *wl_pointer, struct wlr_wl_output *output);
|
void create_wl_pointer(struct wlr_wl_seat *seat, struct wlr_wl_output *output);
|
||||||
void create_wl_keyboard(struct wl_keyboard *wl_keyboard, struct wlr_wl_backend *wl);
|
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_input_device *create_wl_input_device(
|
||||||
struct wlr_wl_backend *backend, enum wlr_input_device_type type);
|
struct wlr_wl_seat *seat, enum wlr_input_device_type type);
|
||||||
|
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_buffer(struct wlr_wl_buffer *buffer);
|
||||||
|
|
||||||
extern const struct wl_seat_listener seat_listener;
|
extern const struct wl_seat_listener seat_listener;
|
||||||
|
|
||||||
struct wlr_wl_tablet_seat *wl_add_tablet_seat(
|
struct wlr_wl_tablet_seat *wl_add_tablet_seat(
|
||||||
struct zwp_tablet_manager_v2 *manager,
|
struct zwp_tablet_manager_v2 *manager,
|
||||||
struct wl_seat *seat, struct wlr_wl_backend *backend);
|
struct wlr_wl_seat *seat);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,26 @@
|
||||||
#ifndef BACKEND_X11_H
|
#ifndef BACKEND_X11_H
|
||||||
#define BACKEND_X11_H
|
#define BACKEND_X11_H
|
||||||
|
|
||||||
|
#include <wlr/config.h>
|
||||||
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
|
||||||
#include <X11/Xlib-xcb.h>
|
#include <X11/Xlib-xcb.h>
|
||||||
#include <wayland-server-core.h>
|
#include <wayland-server-core.h>
|
||||||
#include <xcb/xcb.h>
|
#include <xcb/xcb.h>
|
||||||
|
#include <xcb/present.h>
|
||||||
|
|
||||||
|
#if WLR_HAS_XCB_ERRORS
|
||||||
|
#include <xcb/xcb_errors.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <wlr/backend/x11.h>
|
#include <wlr/backend/x11.h>
|
||||||
#include <wlr/config.h>
|
|
||||||
#include <wlr/interfaces/wlr_input_device.h>
|
#include <wlr/interfaces/wlr_input_device.h>
|
||||||
|
#include <wlr/interfaces/wlr_keyboard.h>
|
||||||
#include <wlr/interfaces/wlr_output.h>
|
#include <wlr/interfaces/wlr_output.h>
|
||||||
|
#include <wlr/interfaces/wlr_pointer.h>
|
||||||
|
#include <wlr/interfaces/wlr_touch.h>
|
||||||
|
#include <wlr/render/drm_format_set.h>
|
||||||
#include <wlr/render/egl.h>
|
#include <wlr/render/egl.h>
|
||||||
#include <wlr/render/wlr_renderer.h>
|
#include <wlr/render/wlr_renderer.h>
|
||||||
|
|
||||||
|
|
@ -26,7 +36,9 @@ struct wlr_x11_output {
|
||||||
struct wl_list link; // wlr_x11_backend::outputs
|
struct wl_list link; // wlr_x11_backend::outputs
|
||||||
|
|
||||||
xcb_window_t win;
|
xcb_window_t win;
|
||||||
EGLSurface surf;
|
|
||||||
|
struct wlr_swapchain *swapchain;
|
||||||
|
struct wlr_buffer *back_buffer;
|
||||||
|
|
||||||
struct wlr_pointer pointer;
|
struct wlr_pointer pointer;
|
||||||
struct wlr_input_device pointer_dev;
|
struct wlr_input_device pointer_dev;
|
||||||
|
|
@ -38,6 +50,8 @@ struct wlr_x11_output {
|
||||||
struct wl_event_source *frame_timer;
|
struct wl_event_source *frame_timer;
|
||||||
int frame_delay;
|
int frame_delay;
|
||||||
|
|
||||||
|
struct wl_list buffers; // wlr_x11_buffer::link
|
||||||
|
|
||||||
bool cursor_hidden;
|
bool cursor_hidden;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -55,6 +69,10 @@ struct wlr_x11_backend {
|
||||||
Display *xlib_conn;
|
Display *xlib_conn;
|
||||||
xcb_connection_t *xcb;
|
xcb_connection_t *xcb;
|
||||||
xcb_screen_t *screen;
|
xcb_screen_t *screen;
|
||||||
|
xcb_depth_t *depth;
|
||||||
|
xcb_visualid_t visualid;
|
||||||
|
xcb_colormap_t colormap;
|
||||||
|
xcb_present_event_t present_event_id;
|
||||||
|
|
||||||
size_t requested_outputs;
|
size_t requested_outputs;
|
||||||
size_t last_output_num;
|
size_t last_output_num;
|
||||||
|
|
@ -65,6 +83,10 @@ struct wlr_x11_backend {
|
||||||
|
|
||||||
struct wlr_egl egl;
|
struct wlr_egl egl;
|
||||||
struct wlr_renderer *renderer;
|
struct wlr_renderer *renderer;
|
||||||
|
struct wlr_drm_format_set dri3_formats;
|
||||||
|
const struct wlr_x11_format *x11_format;
|
||||||
|
struct wlr_drm_format *drm_format;
|
||||||
|
struct wlr_allocator *allocator;
|
||||||
struct wl_event_source *event_source;
|
struct wl_event_source *event_source;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
|
|
@ -78,11 +100,29 @@ struct wlr_x11_backend {
|
||||||
// The time we last received an event
|
// The time we last received an event
|
||||||
xcb_timestamp_t time;
|
xcb_timestamp_t time;
|
||||||
|
|
||||||
|
#if WLR_HAS_XCB_ERRORS
|
||||||
|
xcb_errors_context_t *errors_context;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
uint8_t present_opcode;
|
||||||
uint8_t xinput_opcode;
|
uint8_t xinput_opcode;
|
||||||
|
|
||||||
struct wl_listener display_destroy;
|
struct wl_listener display_destroy;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct wlr_x11_buffer {
|
||||||
|
struct wlr_x11_backend *x11;
|
||||||
|
struct wlr_buffer *buffer;
|
||||||
|
xcb_pixmap_t pixmap;
|
||||||
|
struct wl_list link; // wlr_x11_output::buffers
|
||||||
|
struct wl_listener buffer_destroy;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct wlr_x11_format {
|
||||||
|
uint32_t drm;
|
||||||
|
uint8_t depth, bpp;
|
||||||
|
};
|
||||||
|
|
||||||
struct wlr_x11_backend *get_x11_backend_from_backend(
|
struct wlr_x11_backend *get_x11_backend_from_backend(
|
||||||
struct wlr_backend *wlr_backend);
|
struct wlr_backend *wlr_backend);
|
||||||
struct wlr_x11_output *get_x11_output_from_window_id(
|
struct wlr_x11_output *get_x11_output_from_window_id(
|
||||||
|
|
@ -100,5 +140,7 @@ void update_x11_pointer_position(struct wlr_x11_output *output,
|
||||||
|
|
||||||
void handle_x11_configure_notify(struct wlr_x11_output *output,
|
void handle_x11_configure_notify(struct wlr_x11_output *output,
|
||||||
xcb_configure_notify_event_t *event);
|
xcb_configure_notify_event_t *event);
|
||||||
|
void handle_x11_present_event(struct wlr_x11_backend *x11,
|
||||||
|
xcb_ge_generic_event_t *event);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
42
include/render/allocator.h
Normal file
42
include/render/allocator.h
Normal file
|
|
@ -0,0 +1,42 @@
|
||||||
|
#ifndef RENDER_ALLOCATOR
|
||||||
|
#define RENDER_ALLOCATOR
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <wayland-server-core.h>
|
||||||
|
#include <wlr/render/dmabuf.h>
|
||||||
|
#include <wlr/render/drm_format_set.h>
|
||||||
|
|
||||||
|
struct wlr_allocator;
|
||||||
|
|
||||||
|
struct wlr_allocator_interface {
|
||||||
|
struct wlr_buffer *(*create_buffer)(struct wlr_allocator *alloc,
|
||||||
|
int width, int height, const struct wlr_drm_format *format);
|
||||||
|
void (*destroy)(struct wlr_allocator *alloc);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct wlr_allocator {
|
||||||
|
const struct wlr_allocator_interface *impl;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
struct wl_signal destroy;
|
||||||
|
} events;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Destroy the allocator.
|
||||||
|
*/
|
||||||
|
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.
|
||||||
|
*/
|
||||||
|
struct wlr_buffer *wlr_allocator_create_buffer(struct wlr_allocator *alloc,
|
||||||
|
int width, int height, const struct wlr_drm_format *format);
|
||||||
|
|
||||||
|
// For wlr_allocator implementors
|
||||||
|
void wlr_allocator_init(struct wlr_allocator *alloc,
|
||||||
|
const struct wlr_allocator_interface *impl);
|
||||||
|
|
||||||
|
#endif
|
||||||
19
include/render/drm_format_set.h
Normal file
19
include/render/drm_format_set.h
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
#ifndef RENDER_DRM_FORMAT_SET_H
|
||||||
|
#define RENDER_DRM_FORMAT_SET_H
|
||||||
|
|
||||||
|
#include <wlr/render/drm_format_set.h>
|
||||||
|
|
||||||
|
struct wlr_drm_format *wlr_drm_format_create(uint32_t format);
|
||||||
|
bool wlr_drm_format_add(struct wlr_drm_format **fmt_ptr, uint64_t modifier);
|
||||||
|
struct wlr_drm_format *wlr_drm_format_dup(const struct wlr_drm_format *format);
|
||||||
|
/**
|
||||||
|
* Intersect modifiers for two DRM formats.
|
||||||
|
*
|
||||||
|
* Both arguments must have the same format field. If the formats aren't
|
||||||
|
* compatible, NULL is returned. If either format doesn't support any modifier,
|
||||||
|
* a format that doesn't support any modifier is returned.
|
||||||
|
*/
|
||||||
|
struct wlr_drm_format *wlr_drm_format_intersect(
|
||||||
|
const struct wlr_drm_format *a, const struct wlr_drm_format *b);
|
||||||
|
|
||||||
|
#endif
|
||||||
29
include/render/gbm_allocator.h
Normal file
29
include/render/gbm_allocator.h
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
#ifndef RENDER_GBM_ALLOCATOR_H
|
||||||
|
#define RENDER_GBM_ALLOCATOR_H
|
||||||
|
|
||||||
|
#include <gbm.h>
|
||||||
|
#include <wlr/types/wlr_buffer.h>
|
||||||
|
#include "render/allocator.h"
|
||||||
|
|
||||||
|
struct wlr_gbm_buffer {
|
||||||
|
struct wlr_buffer base;
|
||||||
|
|
||||||
|
struct gbm_bo *gbm_bo;
|
||||||
|
struct wlr_dmabuf_attributes dmabuf;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct wlr_gbm_allocator {
|
||||||
|
struct wlr_allocator base;
|
||||||
|
|
||||||
|
int fd;
|
||||||
|
struct gbm_device *gbm_device;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new GBM allocator from a render FD.
|
||||||
|
*
|
||||||
|
* Takes ownership over the FD.
|
||||||
|
*/
|
||||||
|
struct wlr_gbm_allocator *wlr_gbm_allocator_create(int render_fd);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -14,17 +14,6 @@
|
||||||
#include <wlr/render/wlr_texture.h>
|
#include <wlr/render/wlr_texture.h>
|
||||||
#include <wlr/util/log.h>
|
#include <wlr/util/log.h>
|
||||||
|
|
||||||
struct wlr_gles2_procs {
|
|
||||||
PFNGLEGLIMAGETARGETTEXTURE2DOESPROC glEGLImageTargetTexture2DOES;
|
|
||||||
PFNGLDEBUGMESSAGECALLBACKKHRPROC glDebugMessageCallbackKHR;
|
|
||||||
PFNGLDEBUGMESSAGECONTROLKHRPROC glDebugMessageControlKHR;
|
|
||||||
PFNGLPOPDEBUGGROUPKHRPROC glPopDebugGroupKHR;
|
|
||||||
PFNGLPUSHDEBUGGROUPKHRPROC glPushDebugGroupKHR;
|
|
||||||
PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC glEGLImageTargetRenderbufferStorageOES;
|
|
||||||
};
|
|
||||||
|
|
||||||
extern struct wlr_gles2_procs gles2_procs;
|
|
||||||
|
|
||||||
struct wlr_gles2_pixel_format {
|
struct wlr_gles2_pixel_format {
|
||||||
enum wl_shm_format wl_format;
|
enum wl_shm_format wl_format;
|
||||||
GLint gl_format, gl_type;
|
GLint gl_format, gl_type;
|
||||||
|
|
@ -46,6 +35,7 @@ struct wlr_gles2_renderer {
|
||||||
struct wlr_renderer wlr_renderer;
|
struct wlr_renderer wlr_renderer;
|
||||||
|
|
||||||
struct wlr_egl *egl;
|
struct wlr_egl *egl;
|
||||||
|
int drm_fd;
|
||||||
|
|
||||||
const char *exts_str;
|
const char *exts_str;
|
||||||
struct {
|
struct {
|
||||||
|
|
@ -55,6 +45,15 @@ struct wlr_gles2_renderer {
|
||||||
bool egl_image_oes;
|
bool egl_image_oes;
|
||||||
} exts;
|
} exts;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
PFNGLEGLIMAGETARGETTEXTURE2DOESPROC glEGLImageTargetTexture2DOES;
|
||||||
|
PFNGLDEBUGMESSAGECALLBACKKHRPROC glDebugMessageCallbackKHR;
|
||||||
|
PFNGLDEBUGMESSAGECONTROLKHRPROC glDebugMessageControlKHR;
|
||||||
|
PFNGLPOPDEBUGGROUPKHRPROC glPopDebugGroupKHR;
|
||||||
|
PFNGLPUSHDEBUGGROUPKHRPROC glPushDebugGroupKHR;
|
||||||
|
PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC glEGLImageTargetRenderbufferStorageOES;
|
||||||
|
} procs;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
struct {
|
struct {
|
||||||
GLuint program;
|
GLuint program;
|
||||||
|
|
@ -74,12 +73,27 @@ struct wlr_gles2_renderer {
|
||||||
struct wlr_gles2_tex_shader tex_ext;
|
struct wlr_gles2_tex_shader tex_ext;
|
||||||
} shaders;
|
} shaders;
|
||||||
|
|
||||||
|
struct wl_list buffers; // wlr_gles2_buffer.link
|
||||||
|
|
||||||
|
struct wlr_gles2_buffer *current_buffer;
|
||||||
uint32_t viewport_width, viewport_height;
|
uint32_t viewport_width, viewport_height;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct wlr_gles2_buffer {
|
||||||
|
struct wlr_buffer *buffer;
|
||||||
|
struct wlr_gles2_renderer *renderer;
|
||||||
|
struct wl_list link; // wlr_gles2_renderer.buffers
|
||||||
|
|
||||||
|
EGLImageKHR image;
|
||||||
|
GLuint rbo;
|
||||||
|
GLuint fbo;
|
||||||
|
|
||||||
|
struct wl_listener buffer_destroy;
|
||||||
|
};
|
||||||
|
|
||||||
struct wlr_gles2_texture {
|
struct wlr_gles2_texture {
|
||||||
struct wlr_texture wlr_texture;
|
struct wlr_texture wlr_texture;
|
||||||
struct wlr_egl *egl;
|
struct wlr_gles2_renderer *renderer;
|
||||||
|
|
||||||
// Basically:
|
// Basically:
|
||||||
// GL_TEXTURE_2D == mutable
|
// GL_TEXTURE_2D == mutable
|
||||||
|
|
@ -102,12 +116,22 @@ const struct wlr_gles2_pixel_format *get_gles2_format_from_gl(
|
||||||
GLint gl_format, GLint gl_type, bool alpha);
|
GLint gl_format, GLint gl_type, bool alpha);
|
||||||
const enum wl_shm_format *get_gles2_wl_formats(size_t *len);
|
const enum wl_shm_format *get_gles2_wl_formats(size_t *len);
|
||||||
|
|
||||||
|
struct wlr_gles2_renderer *gles2_get_renderer(
|
||||||
|
struct wlr_renderer *wlr_renderer);
|
||||||
struct wlr_gles2_texture *gles2_get_texture(
|
struct wlr_gles2_texture *gles2_get_texture(
|
||||||
struct wlr_texture *wlr_texture);
|
struct wlr_texture *wlr_texture);
|
||||||
|
|
||||||
void push_gles2_marker(const char *file, const char *func);
|
struct wlr_texture *gles2_texture_from_pixels(struct wlr_renderer *wlr_renderer,
|
||||||
void pop_gles2_marker(void);
|
enum wl_shm_format wl_fmt, uint32_t stride, uint32_t width, uint32_t height,
|
||||||
#define PUSH_GLES2_DEBUG push_gles2_marker(_WLR_FILENAME, __func__)
|
const void *data);
|
||||||
#define POP_GLES2_DEBUG pop_gles2_marker()
|
struct wlr_texture *gles2_texture_from_wl_drm(struct wlr_renderer *wlr_renderer,
|
||||||
|
struct wl_resource *data);
|
||||||
|
struct wlr_texture *gles2_texture_from_dmabuf(struct wlr_renderer *wlr_renderer,
|
||||||
|
struct wlr_dmabuf_attributes *attribs);
|
||||||
|
|
||||||
|
void push_gles2_debug_(struct wlr_gles2_renderer *renderer,
|
||||||
|
const char *file, const char *func);
|
||||||
|
#define push_gles2_debug(renderer) push_gles2_debug_(renderer, _WLR_FILENAME, __func__)
|
||||||
|
void pop_gles2_debug(struct wlr_gles2_renderer *renderer);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
50
include/render/swapchain.h
Normal file
50
include/render/swapchain.h
Normal file
|
|
@ -0,0 +1,50 @@
|
||||||
|
#ifndef RENDER_SWAPCHAIN_H
|
||||||
|
#define RENDER_SWAPCHAIN_H
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <wayland-server-core.h>
|
||||||
|
#include <wlr/render/drm_format_set.h>
|
||||||
|
|
||||||
|
#define WLR_SWAPCHAIN_CAP 4
|
||||||
|
|
||||||
|
struct wlr_swapchain_slot {
|
||||||
|
struct wlr_buffer *buffer;
|
||||||
|
bool acquired; // waiting for release
|
||||||
|
int age;
|
||||||
|
|
||||||
|
struct wl_listener release;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct wlr_swapchain {
|
||||||
|
struct wlr_allocator *allocator; // NULL if destroyed
|
||||||
|
|
||||||
|
int width, height;
|
||||||
|
struct wlr_drm_format *format;
|
||||||
|
|
||||||
|
struct wlr_swapchain_slot slots[WLR_SWAPCHAIN_CAP];
|
||||||
|
|
||||||
|
struct wl_listener allocator_destroy;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct wlr_swapchain *wlr_swapchain_create(
|
||||||
|
struct wlr_allocator *alloc, int width, int height,
|
||||||
|
const struct wlr_drm_format *format);
|
||||||
|
void wlr_swapchain_destroy(struct wlr_swapchain *swapchain);
|
||||||
|
/**
|
||||||
|
* Acquire a buffer from the swap chain.
|
||||||
|
*
|
||||||
|
* The returned buffer is locked. When the caller is done with it, they must
|
||||||
|
* unlock it by calling wlr_buffer_unlock.
|
||||||
|
*/
|
||||||
|
struct wlr_buffer *wlr_swapchain_acquire(struct wlr_swapchain *swapchain,
|
||||||
|
int *age);
|
||||||
|
/**
|
||||||
|
* Mark the buffer as submitted for presentation. This needs to be called by
|
||||||
|
* swap chain users on frame boundaries.
|
||||||
|
*
|
||||||
|
* If the buffer hasn't been created via the swap chain, the call is ignored.
|
||||||
|
*/
|
||||||
|
void wlr_swapchain_set_buffer_submitted(struct wlr_swapchain *swapchain,
|
||||||
|
struct wlr_buffer *buffer);
|
||||||
|
|
||||||
|
#endif
|
||||||
14
include/render/wlr_renderer.h
Normal file
14
include/render/wlr_renderer.h
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
#ifndef RENDER_WLR_RENDERER_H
|
||||||
|
#define RENDER_WLR_RENDERER_H
|
||||||
|
|
||||||
|
#include <wlr/render/wlr_renderer.h>
|
||||||
|
|
||||||
|
bool wlr_renderer_bind_buffer(struct wlr_renderer *r, struct wlr_buffer *buffer);
|
||||||
|
/**
|
||||||
|
* Get the DMA-BUF formats supporting rendering usage. Buffers allocated with
|
||||||
|
* a format from this list may be attached via wlr_renderer_bind_buffer.
|
||||||
|
*/
|
||||||
|
const struct wlr_drm_format_set *wlr_renderer_get_dmabuf_render_formats(
|
||||||
|
struct wlr_renderer *renderer);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -1,47 +0,0 @@
|
||||||
#ifndef TYPES_WLR_XDG_SHELL_V6_H
|
|
||||||
#define TYPES_WLR_XDG_SHELL_V6_H
|
|
||||||
|
|
||||||
#include <wayland-server-core.h>
|
|
||||||
#include <wlr/types/wlr_xdg_shell_v6.h>
|
|
||||||
#include "xdg-shell-unstable-v6-protocol.h"
|
|
||||||
|
|
||||||
struct wlr_xdg_positioner_v6_resource {
|
|
||||||
struct wl_resource *resource;
|
|
||||||
struct wlr_xdg_positioner_v6 attrs;
|
|
||||||
};
|
|
||||||
|
|
||||||
extern const struct wlr_surface_role xdg_toplevel_v6_surface_role;
|
|
||||||
extern const struct wlr_surface_role xdg_popup_v6_surface_role;
|
|
||||||
|
|
||||||
uint32_t schedule_xdg_surface_v6_configure(struct wlr_xdg_surface_v6 *surface);
|
|
||||||
struct wlr_xdg_surface_v6 *create_xdg_surface_v6(
|
|
||||||
struct wlr_xdg_client_v6 *client, struct wlr_surface *surface,
|
|
||||||
uint32_t id);
|
|
||||||
void unmap_xdg_surface_v6(struct wlr_xdg_surface_v6 *surface);
|
|
||||||
void destroy_xdg_surface_v6(struct wlr_xdg_surface_v6 *surface);
|
|
||||||
void handle_xdg_surface_v6_commit(struct wlr_surface *wlr_surface);
|
|
||||||
void handle_xdg_surface_v6_precommit(struct wlr_surface *wlr_surface);
|
|
||||||
|
|
||||||
void create_xdg_positioner_v6(struct wlr_xdg_client_v6 *client, uint32_t id);
|
|
||||||
struct wlr_xdg_positioner_v6_resource *get_xdg_positioner_v6_from_resource(
|
|
||||||
struct wl_resource *resource);
|
|
||||||
|
|
||||||
void create_xdg_popup_v6(struct wlr_xdg_surface_v6 *xdg_surface,
|
|
||||||
struct wlr_xdg_surface_v6 *parent,
|
|
||||||
struct wlr_xdg_positioner_v6_resource *positioner, int32_t id);
|
|
||||||
void handle_xdg_surface_v6_popup_committed(struct wlr_xdg_surface_v6 *surface);
|
|
||||||
struct wlr_xdg_popup_grab_v6 *get_xdg_shell_v6_popup_grab_from_seat(
|
|
||||||
struct wlr_xdg_shell_v6 *shell, struct wlr_seat *seat);
|
|
||||||
void destroy_xdg_popup_v6(struct wlr_xdg_surface_v6 *surface);
|
|
||||||
|
|
||||||
void create_xdg_toplevel_v6(struct wlr_xdg_surface_v6 *xdg_surface,
|
|
||||||
uint32_t id);
|
|
||||||
void handle_xdg_surface_v6_toplevel_committed(struct wlr_xdg_surface_v6 *surface);
|
|
||||||
void send_xdg_toplevel_v6_configure(struct wlr_xdg_surface_v6 *surface,
|
|
||||||
struct wlr_xdg_surface_v6_configure *configure);
|
|
||||||
void handle_xdg_toplevel_v6_ack_configure(struct wlr_xdg_surface_v6 *surface,
|
|
||||||
struct wlr_xdg_surface_v6_configure *configure);
|
|
||||||
bool compare_xdg_surface_v6_toplevel_state(struct wlr_xdg_toplevel_v6 *state);
|
|
||||||
void destroy_xdg_toplevel_v6(struct wlr_xdg_surface_v6 *surface);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
@ -13,6 +13,11 @@ uint32_t get_current_time_msec(void);
|
||||||
*/
|
*/
|
||||||
int64_t timespec_to_msec(const struct timespec *a);
|
int64_t timespec_to_msec(const struct timespec *a);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert nanoseconds to a timespec.
|
||||||
|
*/
|
||||||
|
void timespec_from_nsec(struct timespec *r, int64_t nsec);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Subtracts timespec `b` from timespec `a`, and stores the difference in `r`.
|
* Subtracts timespec `b` from timespec `a`, and stores the difference in `r`.
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,8 @@
|
||||||
* a DRM backend, other kinds of backends raise SIGABRT).
|
* a DRM backend, other kinds of backends raise SIGABRT).
|
||||||
*/
|
*/
|
||||||
struct wlr_backend *wlr_drm_backend_create(struct wl_display *display,
|
struct wlr_backend *wlr_drm_backend_create(struct wl_display *display,
|
||||||
struct wlr_session *session, int gpu_fd, struct wlr_backend *parent,
|
struct wlr_session *session, struct wlr_device *dev,
|
||||||
|
struct wlr_backend *parent,
|
||||||
wlr_renderer_create_func_t create_renderer_func);
|
wlr_renderer_create_func_t create_renderer_func);
|
||||||
|
|
||||||
bool wlr_backend_is_drm(struct wlr_backend *backend);
|
bool wlr_backend_is_drm(struct wlr_backend *backend);
|
||||||
|
|
|
||||||
|
|
@ -11,9 +11,11 @@ struct session_impl;
|
||||||
struct wlr_device {
|
struct wlr_device {
|
||||||
int fd;
|
int fd;
|
||||||
dev_t dev;
|
dev_t dev;
|
||||||
struct wl_signal signal;
|
|
||||||
|
|
||||||
struct wl_list link;
|
struct wl_list link;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
struct wl_signal change;
|
||||||
|
} events;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct wlr_session {
|
struct wlr_session {
|
||||||
|
|
@ -22,7 +24,6 @@ struct wlr_session {
|
||||||
* Signal for when the session becomes active/inactive.
|
* Signal for when the session becomes active/inactive.
|
||||||
* It's called when we swap virtual terminal.
|
* It's called when we swap virtual terminal.
|
||||||
*/
|
*/
|
||||||
struct wl_signal session_signal;
|
|
||||||
bool active;
|
bool active;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -38,13 +39,20 @@ struct wlr_session {
|
||||||
|
|
||||||
struct wl_list devices;
|
struct wl_list devices;
|
||||||
|
|
||||||
|
struct wl_display *display;
|
||||||
struct wl_listener display_destroy;
|
struct wl_listener display_destroy;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
|
struct wl_signal active;
|
||||||
|
struct wl_signal add_drm_card; // struct wlr_session_add_event
|
||||||
struct wl_signal destroy;
|
struct wl_signal destroy;
|
||||||
} events;
|
} events;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct wlr_session_add_event {
|
||||||
|
const char *path;
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Opens a session, taking control of the current virtual terminal.
|
* Opens a session, taking control of the current virtual terminal.
|
||||||
* This should not be called if another program is already in control
|
* This should not be called if another program is already in control
|
||||||
|
|
@ -74,21 +82,21 @@ void wlr_session_destroy(struct wlr_session *session);
|
||||||
*
|
*
|
||||||
* Returns -errno on error.
|
* Returns -errno on error.
|
||||||
*/
|
*/
|
||||||
int wlr_session_open_file(struct wlr_session *session, const char *path);
|
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, int fd);
|
void wlr_session_close_file(struct wlr_session *session,
|
||||||
|
struct wlr_device *device);
|
||||||
|
|
||||||
void wlr_session_signal_add(struct wlr_session *session, int fd,
|
|
||||||
struct wl_listener *listener);
|
|
||||||
/*
|
/*
|
||||||
* Changes the virtual terminal.
|
* Changes the virtual terminal.
|
||||||
*/
|
*/
|
||||||
bool wlr_session_change_vt(struct wlr_session *session, unsigned vt);
|
bool wlr_session_change_vt(struct wlr_session *session, unsigned vt);
|
||||||
|
|
||||||
size_t wlr_session_find_gpus(struct wlr_session *session,
|
size_t wlr_session_find_gpus(struct wlr_session *session,
|
||||||
size_t ret_len, int *ret);
|
size_t ret_len, struct wlr_device **ret);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,11 @@
|
||||||
#ifndef WLR_CONFIG_H
|
#ifndef WLR_CONFIG_H
|
||||||
#define WLR_CONFIG_H
|
#define WLR_CONFIG_H
|
||||||
|
|
||||||
#mesondefine WLR_HAS_EGLMESAEXT_H
|
|
||||||
|
|
||||||
#mesondefine WLR_HAS_LIBCAP
|
|
||||||
|
|
||||||
#mesondefine WLR_HAS_SYSTEMD
|
#mesondefine WLR_HAS_SYSTEMD
|
||||||
#mesondefine WLR_HAS_ELOGIND
|
#mesondefine WLR_HAS_ELOGIND
|
||||||
|
|
||||||
|
#mesondefine WLR_HAS_LIBSEAT
|
||||||
|
|
||||||
#mesondefine WLR_HAS_X11_BACKEND
|
#mesondefine WLR_HAS_X11_BACKEND
|
||||||
|
|
||||||
#mesondefine WLR_HAS_XWAYLAND
|
#mesondefine WLR_HAS_XWAYLAND
|
||||||
|
|
|
||||||
|
|
@ -15,9 +15,9 @@
|
||||||
#define WLR_DMABUF_MAX_PLANES 4
|
#define WLR_DMABUF_MAX_PLANES 4
|
||||||
|
|
||||||
enum wlr_dmabuf_attributes_flags {
|
enum wlr_dmabuf_attributes_flags {
|
||||||
WLR_DMABUF_ATTRIBUTES_FLAGS_Y_INVERT = 1,
|
WLR_DMABUF_ATTRIBUTES_FLAGS_Y_INVERT = 1 << 0,
|
||||||
WLR_DMABUF_ATTRIBUTES_FLAGS_INTERLACED = 2,
|
WLR_DMABUF_ATTRIBUTES_FLAGS_INTERLACED = 1 << 1,
|
||||||
WLR_DMABUF_ATTRIBUTES_FLAGS_BOTTOM_FIRST = 4,
|
WLR_DMABUF_ATTRIBUTES_FLAGS_BOTTOM_FIRST = 1 << 2,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct wlr_dmabuf_attributes {
|
struct wlr_dmabuf_attributes {
|
||||||
|
|
|
||||||
|
|
@ -15,15 +15,14 @@
|
||||||
#ifndef EGL_NO_X11
|
#ifndef EGL_NO_X11
|
||||||
#define EGL_NO_X11
|
#define EGL_NO_X11
|
||||||
#endif
|
#endif
|
||||||
|
#ifndef EGL_NO_PLATFORM_SPECIFIC_TYPES
|
||||||
|
#define EGL_NO_PLATFORM_SPECIFIC_TYPES
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <wlr/config.h>
|
#include <wlr/config.h>
|
||||||
|
|
||||||
#include <EGL/egl.h>
|
#include <EGL/egl.h>
|
||||||
#include <EGL/eglext.h>
|
#include <EGL/eglext.h>
|
||||||
#if WLR_HAS_EGLMESAEXT_H
|
|
||||||
// TODO: remove eglmesaext.h
|
|
||||||
#include <EGL/eglmesaext.h>
|
|
||||||
#endif
|
|
||||||
#include <pixman.h>
|
#include <pixman.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <wayland-server-core.h>
|
#include <wayland-server-core.h>
|
||||||
|
|
@ -42,8 +41,10 @@ struct wlr_egl {
|
||||||
EGLDisplay display;
|
EGLDisplay display;
|
||||||
EGLConfig config;
|
EGLConfig config;
|
||||||
EGLContext context;
|
EGLContext context;
|
||||||
|
EGLDeviceEXT device; // may be EGL_NO_DEVICE_EXT
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
|
// Display extensions
|
||||||
bool bind_wayland_display_wl;
|
bool bind_wayland_display_wl;
|
||||||
bool buffer_age_ext;
|
bool buffer_age_ext;
|
||||||
bool image_base_khr;
|
bool image_base_khr;
|
||||||
|
|
@ -51,6 +52,9 @@ struct wlr_egl {
|
||||||
bool image_dmabuf_import_ext;
|
bool image_dmabuf_import_ext;
|
||||||
bool image_dmabuf_import_modifiers_ext;
|
bool image_dmabuf_import_modifiers_ext;
|
||||||
bool swap_buffers_with_damage;
|
bool swap_buffers_with_damage;
|
||||||
|
|
||||||
|
// Device extensions
|
||||||
|
bool device_drm_ext;
|
||||||
} exts;
|
} exts;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
|
|
@ -67,12 +71,14 @@ struct wlr_egl {
|
||||||
PFNEGLEXPORTDMABUFIMAGEQUERYMESAPROC eglExportDMABUFImageQueryMESA;
|
PFNEGLEXPORTDMABUFIMAGEQUERYMESAPROC eglExportDMABUFImageQueryMESA;
|
||||||
PFNEGLEXPORTDMABUFIMAGEMESAPROC eglExportDMABUFImageMESA;
|
PFNEGLEXPORTDMABUFIMAGEMESAPROC eglExportDMABUFImageMESA;
|
||||||
PFNEGLDEBUGMESSAGECONTROLKHRPROC eglDebugMessageControlKHR;
|
PFNEGLDEBUGMESSAGECONTROLKHRPROC eglDebugMessageControlKHR;
|
||||||
|
PFNEGLQUERYDISPLAYATTRIBEXTPROC eglQueryDisplayAttribEXT;
|
||||||
|
PFNEGLQUERYDEVICESTRINGEXTPROC eglQueryDeviceStringEXT;
|
||||||
} procs;
|
} procs;
|
||||||
|
|
||||||
struct wl_display *wl_display;
|
struct wl_display *wl_display;
|
||||||
|
|
||||||
struct wlr_drm_format_set dmabuf_formats;
|
struct wlr_drm_format_set dmabuf_texture_formats;
|
||||||
EGLBoolean **external_only_dmabuf_formats;
|
struct wlr_drm_format_set dmabuf_render_formats;
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO: Allocate and return a wlr_egl
|
// TODO: Allocate and return a wlr_egl
|
||||||
|
|
@ -117,9 +123,15 @@ EGLImageKHR wlr_egl_create_image_from_dmabuf(struct wlr_egl *egl,
|
||||||
struct wlr_dmabuf_attributes *attributes, bool *external_only);
|
struct wlr_dmabuf_attributes *attributes, bool *external_only);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the available dmabuf formats
|
* Get DMA-BUF formats suitable for sampling usage.
|
||||||
*/
|
*/
|
||||||
const struct wlr_drm_format_set *wlr_egl_get_dmabuf_formats(struct wlr_egl *egl);
|
const struct wlr_drm_format_set *wlr_egl_get_dmabuf_texture_formats(
|
||||||
|
struct wlr_egl *egl);
|
||||||
|
/**
|
||||||
|
* Get DMA-BUF formats suitable for rendering usage.
|
||||||
|
*/
|
||||||
|
const struct wlr_drm_format_set *wlr_egl_get_dmabuf_render_formats(
|
||||||
|
struct wlr_egl *egl);
|
||||||
|
|
||||||
bool wlr_egl_export_image_to_dmabuf(struct wlr_egl *egl, EGLImageKHR image,
|
bool wlr_egl_export_image_to_dmabuf(struct wlr_egl *egl, EGLImageKHR image,
|
||||||
int32_t width, int32_t height, uint32_t flags,
|
int32_t width, int32_t height, uint32_t flags,
|
||||||
|
|
@ -161,4 +173,6 @@ bool wlr_egl_swap_buffers(struct wlr_egl *egl, EGLSurface surface,
|
||||||
|
|
||||||
bool wlr_egl_destroy_surface(struct wlr_egl *egl, EGLSurface surface);
|
bool wlr_egl_destroy_surface(struct wlr_egl *egl, EGLSurface surface);
|
||||||
|
|
||||||
|
int wlr_egl_dup_drm_fd(struct wlr_egl *egl);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -21,14 +21,6 @@ struct wlr_egl *wlr_gles2_renderer_get_egl(struct wlr_renderer *renderer);
|
||||||
bool wlr_gles2_renderer_check_ext(struct wlr_renderer *renderer,
|
bool wlr_gles2_renderer_check_ext(struct wlr_renderer *renderer,
|
||||||
const char *ext);
|
const char *ext);
|
||||||
|
|
||||||
struct wlr_texture *wlr_gles2_texture_from_pixels(struct wlr_egl *egl,
|
|
||||||
enum wl_shm_format wl_fmt, uint32_t stride, uint32_t width, uint32_t height,
|
|
||||||
const void *data);
|
|
||||||
struct wlr_texture *wlr_gles2_texture_from_wl_drm(struct wlr_egl *egl,
|
|
||||||
struct wl_resource *data);
|
|
||||||
struct wlr_texture *wlr_gles2_texture_from_dmabuf(struct wlr_egl *egl,
|
|
||||||
struct wlr_dmabuf_attributes *attribs);
|
|
||||||
|
|
||||||
struct wlr_gles2_texture_attribs {
|
struct wlr_gles2_texture_attribs {
|
||||||
GLenum target; /* either GL_TEXTURE_2D or GL_TEXTURE_EXTERNAL_OES */
|
GLenum target; /* either GL_TEXTURE_2D or GL_TEXTURE_EXTERNAL_OES */
|
||||||
GLuint tex;
|
GLuint tex;
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,9 @@
|
||||||
#ifndef EGL_NO_X11
|
#ifndef EGL_NO_X11
|
||||||
#define EGL_NO_X11
|
#define EGL_NO_X11
|
||||||
#endif
|
#endif
|
||||||
|
#ifndef EGL_NO_PLATFORM_SPECIFIC_TYPES
|
||||||
|
#define EGL_NO_PLATFORM_SPECIFIC_TYPES
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <EGL/egl.h>
|
#include <EGL/egl.h>
|
||||||
#include <EGL/eglext.h>
|
#include <EGL/eglext.h>
|
||||||
|
|
@ -27,6 +30,8 @@
|
||||||
#include <wlr/render/dmabuf.h>
|
#include <wlr/render/dmabuf.h>
|
||||||
|
|
||||||
struct wlr_renderer_impl {
|
struct wlr_renderer_impl {
|
||||||
|
bool (*bind_buffer)(struct wlr_renderer *renderer,
|
||||||
|
struct wlr_buffer *buffer);
|
||||||
void (*begin)(struct wlr_renderer *renderer, uint32_t width,
|
void (*begin)(struct wlr_renderer *renderer, uint32_t width,
|
||||||
uint32_t height);
|
uint32_t height);
|
||||||
void (*end)(struct wlr_renderer *renderer);
|
void (*end)(struct wlr_renderer *renderer);
|
||||||
|
|
@ -39,15 +44,15 @@ struct wlr_renderer_impl {
|
||||||
const float color[static 4], const float matrix[static 9]);
|
const float color[static 4], const float matrix[static 9]);
|
||||||
void (*render_ellipse_with_matrix)(struct wlr_renderer *renderer,
|
void (*render_ellipse_with_matrix)(struct wlr_renderer *renderer,
|
||||||
const float color[static 4], const float matrix[static 9]);
|
const float color[static 4], const float matrix[static 9]);
|
||||||
const enum wl_shm_format *(*formats)(
|
const enum wl_shm_format *(*get_shm_texture_formats)(
|
||||||
struct wlr_renderer *renderer, size_t *len);
|
struct wlr_renderer *renderer, size_t *len);
|
||||||
bool (*format_supported)(struct wlr_renderer *renderer,
|
|
||||||
enum wl_shm_format fmt);
|
|
||||||
bool (*resource_is_wl_drm_buffer)(struct wlr_renderer *renderer,
|
bool (*resource_is_wl_drm_buffer)(struct wlr_renderer *renderer,
|
||||||
struct wl_resource *resource);
|
struct wl_resource *resource);
|
||||||
void (*wl_drm_buffer_get_size)(struct wlr_renderer *renderer,
|
void (*wl_drm_buffer_get_size)(struct wlr_renderer *renderer,
|
||||||
struct wl_resource *buffer, int *width, int *height);
|
struct wl_resource *buffer, int *width, int *height);
|
||||||
const struct wlr_drm_format_set *(*get_dmabuf_formats)(
|
const struct wlr_drm_format_set *(*get_dmabuf_texture_formats)(
|
||||||
|
struct wlr_renderer *renderer);
|
||||||
|
const struct wlr_drm_format_set *(*get_dmabuf_render_formats)(
|
||||||
struct wlr_renderer *renderer);
|
struct wlr_renderer *renderer);
|
||||||
enum wl_shm_format (*preferred_read_format)(struct wlr_renderer *renderer);
|
enum wl_shm_format (*preferred_read_format)(struct wlr_renderer *renderer);
|
||||||
bool (*read_pixels)(struct wlr_renderer *renderer, enum wl_shm_format fmt,
|
bool (*read_pixels)(struct wlr_renderer *renderer, enum wl_shm_format fmt,
|
||||||
|
|
@ -67,6 +72,7 @@ struct wlr_renderer_impl {
|
||||||
bool (*blit_dmabuf)(struct wlr_renderer *renderer,
|
bool (*blit_dmabuf)(struct wlr_renderer *renderer,
|
||||||
struct wlr_dmabuf_attributes *dst,
|
struct wlr_dmabuf_attributes *dst,
|
||||||
struct wlr_dmabuf_attributes *src);
|
struct wlr_dmabuf_attributes *src);
|
||||||
|
int (*get_drm_fd)(struct wlr_renderer *renderer);
|
||||||
};
|
};
|
||||||
|
|
||||||
void wlr_renderer_init(struct wlr_renderer *renderer,
|
void wlr_renderer_init(struct wlr_renderer *renderer,
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ enum wlr_renderer_read_pixels_flags {
|
||||||
|
|
||||||
struct wlr_renderer_impl;
|
struct wlr_renderer_impl;
|
||||||
struct wlr_drm_format_set;
|
struct wlr_drm_format_set;
|
||||||
|
struct wlr_buffer;
|
||||||
|
|
||||||
struct wlr_renderer {
|
struct wlr_renderer {
|
||||||
const struct wlr_renderer_impl *impl;
|
const struct wlr_renderer_impl *impl;
|
||||||
|
|
@ -35,7 +36,7 @@ struct wlr_renderer {
|
||||||
struct wlr_renderer *wlr_renderer_autocreate(struct wlr_egl *egl, EGLenum platform,
|
struct wlr_renderer *wlr_renderer_autocreate(struct wlr_egl *egl, EGLenum platform,
|
||||||
void *remote_display, EGLint *config_attribs, EGLint visual_id);
|
void *remote_display, EGLint *config_attribs, EGLint visual_id);
|
||||||
|
|
||||||
void wlr_renderer_begin(struct wlr_renderer *r, int width, int height);
|
void wlr_renderer_begin(struct wlr_renderer *r, uint32_t width, uint32_t height);
|
||||||
void wlr_renderer_end(struct wlr_renderer *r);
|
void wlr_renderer_end(struct wlr_renderer *r);
|
||||||
void wlr_renderer_clear(struct wlr_renderer *r, const float color[static 4]);
|
void wlr_renderer_clear(struct wlr_renderer *r, const float color[static 4]);
|
||||||
/**
|
/**
|
||||||
|
|
@ -82,10 +83,11 @@ void wlr_render_ellipse(struct wlr_renderer *r, const struct wlr_box *box,
|
||||||
void wlr_render_ellipse_with_matrix(struct wlr_renderer *r,
|
void wlr_render_ellipse_with_matrix(struct wlr_renderer *r,
|
||||||
const float color[static 4], const float matrix[static 9]);
|
const float color[static 4], const float matrix[static 9]);
|
||||||
/**
|
/**
|
||||||
* Returns a list of pixel formats supported by this renderer.
|
* Get the shared-memory formats supporting import usage. Buffers allocated
|
||||||
|
* with a format from this list may be imported via wlr_texture_from_pixels.
|
||||||
*/
|
*/
|
||||||
const enum wl_shm_format *wlr_renderer_get_formats(struct wlr_renderer *r,
|
const enum wl_shm_format *wlr_renderer_get_shm_texture_formats(
|
||||||
size_t *len);
|
struct wlr_renderer *r, size_t *len);
|
||||||
/**
|
/**
|
||||||
* Returns true if this wl_buffer is a wl_drm buffer.
|
* Returns true if this wl_buffer is a wl_drm buffer.
|
||||||
*/
|
*/
|
||||||
|
|
@ -97,9 +99,10 @@ bool wlr_renderer_resource_is_wl_drm_buffer(struct wlr_renderer *renderer,
|
||||||
void wlr_renderer_wl_drm_buffer_get_size(struct wlr_renderer *renderer,
|
void wlr_renderer_wl_drm_buffer_get_size(struct wlr_renderer *renderer,
|
||||||
struct wl_resource *buffer, int *width, int *height);
|
struct wl_resource *buffer, int *width, int *height);
|
||||||
/**
|
/**
|
||||||
* Get the available DMA-BUF formats.
|
* Get the DMA-BUF formats supporting sampling usage. Buffers allocated with
|
||||||
|
* a format from this list may be imported via wlr_texture_from_dmabuf.
|
||||||
*/
|
*/
|
||||||
const struct wlr_drm_format_set *wlr_renderer_get_dmabuf_formats(
|
const struct wlr_drm_format_set *wlr_renderer_get_dmabuf_texture_formats(
|
||||||
struct wlr_renderer *renderer);
|
struct wlr_renderer *renderer);
|
||||||
/**
|
/**
|
||||||
* Reads out of pixels of the currently bound surface into data. `stride` is in
|
* Reads out of pixels of the currently bound surface into data. `stride` is in
|
||||||
|
|
@ -117,11 +120,6 @@ bool wlr_renderer_read_pixels(struct wlr_renderer *r, enum wl_shm_format fmt,
|
||||||
*/
|
*/
|
||||||
bool wlr_renderer_blit_dmabuf(struct wlr_renderer *r,
|
bool wlr_renderer_blit_dmabuf(struct wlr_renderer *r,
|
||||||
struct wlr_dmabuf_attributes *dst, struct wlr_dmabuf_attributes *src);
|
struct wlr_dmabuf_attributes *dst, struct wlr_dmabuf_attributes *src);
|
||||||
/**
|
|
||||||
* Checks if a format is supported.
|
|
||||||
*/
|
|
||||||
bool wlr_renderer_format_supported(struct wlr_renderer *r,
|
|
||||||
enum wl_shm_format fmt);
|
|
||||||
/**
|
/**
|
||||||
* Creates necessary shm and invokes the initialization of the implementation.
|
* Creates necessary shm and invokes the initialization of the implementation.
|
||||||
*
|
*
|
||||||
|
|
@ -130,6 +128,13 @@ bool wlr_renderer_format_supported(struct wlr_renderer *r,
|
||||||
bool wlr_renderer_init_wl_display(struct wlr_renderer *r,
|
bool wlr_renderer_init_wl_display(struct wlr_renderer *r,
|
||||||
struct wl_display *wl_display);
|
struct wl_display *wl_display);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtains the FD of the DRM device used for rendering, or -1 if unavailable.
|
||||||
|
*
|
||||||
|
* The caller doesn't have ownership of the FD, it must not close it.
|
||||||
|
*/
|
||||||
|
int wlr_renderer_get_drm_fd(struct wlr_renderer *r);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Destroys this wlr_renderer. Textures must be destroyed separately.
|
* Destroys this wlr_renderer. Textures must be destroyed separately.
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,9 @@ struct wlr_texture {
|
||||||
/**
|
/**
|
||||||
* Create a new texture from raw pixel data. `stride` is in bytes. The returned
|
* Create a new texture from raw pixel data. `stride` is in bytes. The returned
|
||||||
* texture is mutable.
|
* 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,
|
struct wlr_texture *wlr_texture_from_pixels(struct wlr_renderer *renderer,
|
||||||
enum wl_shm_format wl_fmt, uint32_t stride, uint32_t width, uint32_t height,
|
enum wl_shm_format wl_fmt, uint32_t stride, uint32_t width, uint32_t height,
|
||||||
|
|
@ -32,12 +35,18 @@ struct wlr_texture *wlr_texture_from_pixels(struct wlr_renderer *renderer,
|
||||||
/**
|
/**
|
||||||
* Create a new texture from a wl_drm resource. The returned texture is
|
* Create a new texture from a wl_drm resource. The returned texture is
|
||||||
* immutable.
|
* 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_wl_drm(struct wlr_renderer *renderer,
|
struct wlr_texture *wlr_texture_from_wl_drm(struct wlr_renderer *renderer,
|
||||||
struct wl_resource *data);
|
struct wl_resource *data);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new texture from a DMA-BUF. The returned texture is immutable.
|
* 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_texture *wlr_texture_from_dmabuf(struct wlr_renderer *renderer,
|
||||||
struct wlr_dmabuf_attributes *attribs);
|
struct wlr_dmabuf_attributes *attribs);
|
||||||
|
|
@ -58,6 +67,9 @@ bool wlr_texture_is_opaque(struct wlr_texture *texture);
|
||||||
/**
|
/**
|
||||||
* Update a texture with raw pixels. The texture must be mutable, and the input
|
* 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.
|
* data must have the same pixel format that the texture was created with.
|
||||||
|
*
|
||||||
|
* Should not be called in a rendering block like renderer_begin()/end() or
|
||||||
|
* between attaching a renderer to an output and committing it.
|
||||||
*/
|
*/
|
||||||
bool wlr_texture_write_pixels(struct wlr_texture *texture,
|
bool wlr_texture_write_pixels(struct wlr_texture *texture,
|
||||||
uint32_t stride, uint32_t width, uint32_t height,
|
uint32_t stride, uint32_t width, uint32_t height,
|
||||||
|
|
|
||||||
|
|
@ -103,6 +103,11 @@ struct wlr_client_buffer {
|
||||||
|
|
||||||
struct wlr_renderer;
|
struct wlr_renderer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a client buffer from a generic buffer. If the buffer isn't a client
|
||||||
|
* buffer, returns NULL.
|
||||||
|
*/
|
||||||
|
struct wlr_client_buffer *wlr_client_buffer_get(struct wlr_buffer *buffer);
|
||||||
/**
|
/**
|
||||||
* Check if a resource is a wl_buffer resource.
|
* Check if a resource is a wl_buffer resource.
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -136,7 +136,6 @@ struct wlr_drag {
|
||||||
struct wl_signal destroy;
|
struct wl_signal destroy;
|
||||||
} events;
|
} events;
|
||||||
|
|
||||||
struct wl_listener point_destroy;
|
|
||||||
struct wl_listener source_destroy;
|
struct wl_listener source_destroy;
|
||||||
struct wl_listener seat_client_destroy;
|
struct wl_listener seat_client_destroy;
|
||||||
struct wl_listener icon_destroy;
|
struct wl_listener icon_destroy;
|
||||||
|
|
|
||||||
|
|
@ -29,12 +29,11 @@ struct wlr_export_dmabuf_frame_v1 {
|
||||||
struct wlr_export_dmabuf_manager_v1 *manager;
|
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_dmabuf_attributes attribs;
|
|
||||||
struct wlr_output *output;
|
struct wlr_output *output;
|
||||||
|
|
||||||
bool cursor_locked;
|
bool cursor_locked;
|
||||||
|
|
||||||
struct wl_listener output_precommit;
|
struct wl_listener output_commit;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct wlr_export_dmabuf_manager_v1 *wlr_export_dmabuf_manager_v1_create(
|
struct wlr_export_dmabuf_manager_v1 *wlr_export_dmabuf_manager_v1_create(
|
||||||
|
|
|
||||||
|
|
@ -50,6 +50,7 @@ struct wlr_foreign_toplevel_handle_v1 {
|
||||||
|
|
||||||
char *title;
|
char *title;
|
||||||
char *app_id;
|
char *app_id;
|
||||||
|
struct wlr_foreign_toplevel_handle_v1 *parent;
|
||||||
struct wl_list outputs; // wlr_foreign_toplevel_v1_output
|
struct wl_list outputs; // wlr_foreign_toplevel_v1_output
|
||||||
uint32_t state; // wlr_foreign_toplevel_v1_state
|
uint32_t state; // wlr_foreign_toplevel_v1_state
|
||||||
|
|
||||||
|
|
@ -104,6 +105,12 @@ 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_handle_v1 *wlr_foreign_toplevel_handle_v1_create(
|
||||||
struct wlr_foreign_toplevel_manager_v1 *manager);
|
struct wlr_foreign_toplevel_manager_v1 *manager);
|
||||||
|
/* 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. */
|
||||||
void wlr_foreign_toplevel_handle_v1_destroy(
|
void wlr_foreign_toplevel_handle_v1_destroy(
|
||||||
struct wlr_foreign_toplevel_handle_v1 *toplevel);
|
struct wlr_foreign_toplevel_handle_v1 *toplevel);
|
||||||
|
|
||||||
|
|
@ -126,4 +133,14 @@ void wlr_foreign_toplevel_handle_v1_set_activated(
|
||||||
void wlr_foreign_toplevel_handle_v1_set_fullscreen(
|
void wlr_foreign_toplevel_handle_v1_set_fullscreen(
|
||||||
struct wlr_foreign_toplevel_handle_v1* toplevel, bool fullscreen);
|
struct wlr_foreign_toplevel_handle_v1* toplevel, bool fullscreen);
|
||||||
|
|
||||||
|
/* 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. */
|
||||||
|
void wlr_foreign_toplevel_handle_v1_set_parent(
|
||||||
|
struct wlr_foreign_toplevel_handle_v1 *toplevel,
|
||||||
|
struct wlr_foreign_toplevel_handle_v1 *parent);
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,10 @@ struct wlr_gamma_control_v1 {
|
||||||
struct wlr_output *output;
|
struct wlr_output *output;
|
||||||
struct wl_list link;
|
struct wl_list link;
|
||||||
|
|
||||||
|
uint16_t *table;
|
||||||
|
size_t ramp_size;
|
||||||
|
|
||||||
|
struct wl_listener output_commit_listener;
|
||||||
struct wl_listener output_destroy_listener;
|
struct wl_listener output_destroy_listener;
|
||||||
|
|
||||||
void *data;
|
void *data;
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,8 @@
|
||||||
#ifndef WLR_TYPES_WLR_INPUT_DEVICE_H
|
#ifndef WLR_TYPES_WLR_INPUT_DEVICE_H
|
||||||
#define WLR_TYPES_WLR_INPUT_DEVICE_H
|
#define WLR_TYPES_WLR_INPUT_DEVICE_H
|
||||||
|
|
||||||
|
#include <wayland-server-core.h>
|
||||||
|
|
||||||
enum wlr_button_state {
|
enum wlr_button_state {
|
||||||
WLR_BUTTON_RELEASED,
|
WLR_BUTTON_RELEASED,
|
||||||
WLR_BUTTON_PRESSED,
|
WLR_BUTTON_PRESSED,
|
||||||
|
|
@ -23,14 +25,6 @@ enum wlr_input_device_type {
|
||||||
WLR_INPUT_DEVICE_SWITCH,
|
WLR_INPUT_DEVICE_SWITCH,
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Note: these are circular dependencies */
|
|
||||||
#include <wlr/types/wlr_keyboard.h>
|
|
||||||
#include <wlr/types/wlr_pointer.h>
|
|
||||||
#include <wlr/types/wlr_touch.h>
|
|
||||||
#include <wlr/types/wlr_tablet_tool.h>
|
|
||||||
#include <wlr/types/wlr_tablet_pad.h>
|
|
||||||
#include <wlr/types/wlr_switch.h>
|
|
||||||
|
|
||||||
struct wlr_input_device_impl;
|
struct wlr_input_device_impl;
|
||||||
|
|
||||||
struct wlr_input_device {
|
struct wlr_input_device {
|
||||||
|
|
|
||||||
|
|
@ -12,28 +12,28 @@
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <wayland-server-core.h>
|
#include <wayland-server-core.h>
|
||||||
#include <wayland-server-core.h>
|
#include <wayland-server-protocol.h>
|
||||||
#include <xkbcommon/xkbcommon.h>
|
#include <xkbcommon/xkbcommon.h>
|
||||||
|
|
||||||
#define WLR_LED_COUNT 3
|
#define WLR_LED_COUNT 3
|
||||||
|
|
||||||
enum wlr_keyboard_led {
|
enum wlr_keyboard_led {
|
||||||
WLR_LED_NUM_LOCK = 1,
|
WLR_LED_NUM_LOCK = 1 << 0,
|
||||||
WLR_LED_CAPS_LOCK = 2,
|
WLR_LED_CAPS_LOCK = 1 << 1,
|
||||||
WLR_LED_SCROLL_LOCK = 4,
|
WLR_LED_SCROLL_LOCK = 1 << 2,
|
||||||
};
|
};
|
||||||
|
|
||||||
#define WLR_MODIFIER_COUNT 8
|
#define WLR_MODIFIER_COUNT 8
|
||||||
|
|
||||||
enum wlr_keyboard_modifier {
|
enum wlr_keyboard_modifier {
|
||||||
WLR_MODIFIER_SHIFT = 1,
|
WLR_MODIFIER_SHIFT = 1 << 0,
|
||||||
WLR_MODIFIER_CAPS = 2,
|
WLR_MODIFIER_CAPS = 1 << 1,
|
||||||
WLR_MODIFIER_CTRL = 4,
|
WLR_MODIFIER_CTRL = 1 << 2,
|
||||||
WLR_MODIFIER_ALT = 8,
|
WLR_MODIFIER_ALT = 1 << 3,
|
||||||
WLR_MODIFIER_MOD2 = 16,
|
WLR_MODIFIER_MOD2 = 1 << 4,
|
||||||
WLR_MODIFIER_MOD3 = 32,
|
WLR_MODIFIER_MOD3 = 1 << 5,
|
||||||
WLR_MODIFIER_LOGO = 64,
|
WLR_MODIFIER_LOGO = 1 << 6,
|
||||||
WLR_MODIFIER_MOD5 = 128,
|
WLR_MODIFIER_MOD5 = 1 << 7,
|
||||||
};
|
};
|
||||||
|
|
||||||
#define WLR_KEYBOARD_KEYS_CAP 32
|
#define WLR_KEYBOARD_KEYS_CAP 32
|
||||||
|
|
@ -91,16 +91,11 @@ struct wlr_keyboard {
|
||||||
void *data;
|
void *data;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum wlr_key_state {
|
|
||||||
WLR_KEY_RELEASED,
|
|
||||||
WLR_KEY_PRESSED,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct wlr_event_keyboard_key {
|
struct wlr_event_keyboard_key {
|
||||||
uint32_t time_msec;
|
uint32_t time_msec;
|
||||||
uint32_t keycode;
|
uint32_t keycode;
|
||||||
bool update_state; // if backend doesn't update modifiers on its own
|
bool update_state; // if backend doesn't update modifiers on its own
|
||||||
enum wlr_key_state state;
|
enum wl_keyboard_key_state state;
|
||||||
};
|
};
|
||||||
|
|
||||||
bool wlr_keyboard_set_keymap(struct wlr_keyboard *kb,
|
bool wlr_keyboard_set_keymap(struct wlr_keyboard *kb,
|
||||||
|
|
|
||||||
|
|
@ -138,6 +138,10 @@ struct wlr_layer_surface_v1 *wlr_layer_surface_v1_from_wlr_surface(
|
||||||
void wlr_layer_surface_v1_for_each_surface(struct wlr_layer_surface_v1 *surface,
|
void wlr_layer_surface_v1_for_each_surface(struct wlr_layer_surface_v1 *surface,
|
||||||
wlr_surface_iterator_func_t iterator, void *user_data);
|
wlr_surface_iterator_func_t iterator, void *user_data);
|
||||||
|
|
||||||
|
/* Calls the iterator function for each popup of this surface */
|
||||||
|
void wlr_layer_surface_v1_for_each_popup(struct wlr_layer_surface_v1 *surface,
|
||||||
|
wlr_surface_iterator_func_t iterator, void *user_data);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Find a surface within this layer-surface tree at the given surface-local
|
* Find a surface within this layer-surface tree at the given surface-local
|
||||||
* coordinates. Returns the surface and coordinates in the leaf surface
|
* coordinates. Returns the surface and coordinates in the leaf surface
|
||||||
|
|
|
||||||
|
|
@ -164,9 +164,11 @@ struct wlr_output {
|
||||||
// Emitted right before commit
|
// Emitted right before commit
|
||||||
struct wl_signal precommit; // wlr_output_event_precommit
|
struct wl_signal precommit; // wlr_output_event_precommit
|
||||||
// Emitted right after commit
|
// Emitted right after commit
|
||||||
struct wl_signal commit;
|
struct wl_signal commit; // wlr_output_event_commit
|
||||||
// Emitted right after the buffer has been presented to the user
|
// Emitted right after the buffer has been presented to the user
|
||||||
struct wl_signal present; // wlr_output_event_present
|
struct wl_signal present; // wlr_output_event_present
|
||||||
|
// Emitted after a client bound the wl_output global
|
||||||
|
struct wl_signal bind; // wlr_output_event_bind
|
||||||
struct wl_signal enable;
|
struct wl_signal enable;
|
||||||
struct wl_signal mode;
|
struct wl_signal mode;
|
||||||
struct wl_signal scale;
|
struct wl_signal scale;
|
||||||
|
|
@ -199,6 +201,12 @@ struct wlr_output_event_precommit {
|
||||||
struct timespec *when;
|
struct timespec *when;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct wlr_output_event_commit {
|
||||||
|
struct wlr_output *output;
|
||||||
|
uint32_t committed; // bitmask of enum wlr_output_state_field
|
||||||
|
struct timespec *when;
|
||||||
|
};
|
||||||
|
|
||||||
enum wlr_output_present_flag {
|
enum wlr_output_present_flag {
|
||||||
// The presentation was synchronized to the "vertical retrace" by the
|
// The presentation was synchronized to the "vertical retrace" by the
|
||||||
// display hardware such that tearing does not happen.
|
// display hardware such that tearing does not happen.
|
||||||
|
|
@ -228,6 +236,11 @@ struct wlr_output_event_present {
|
||||||
uint32_t flags; // enum wlr_output_present_flag
|
uint32_t flags; // enum wlr_output_present_flag
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct wlr_output_event_bind {
|
||||||
|
struct wlr_output *output;
|
||||||
|
struct wl_resource *resource;
|
||||||
|
};
|
||||||
|
|
||||||
struct wlr_surface;
|
struct wlr_surface;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -342,8 +355,7 @@ bool wlr_output_preferred_read_format(struct wlr_output *output,
|
||||||
* the screen that has changed since the last frame.
|
* the screen that has changed since the last frame.
|
||||||
*
|
*
|
||||||
* Compositors implementing damage tracking should call this function with the
|
* Compositors implementing damage tracking should call this function with the
|
||||||
* damaged region in output-buffer-local coordinates (ie. scaled and
|
* damaged region in output-buffer-local coordinates.
|
||||||
* transformed).
|
|
||||||
*
|
*
|
||||||
* This region is not to be confused with the renderer's buffer damage, ie. the
|
* This region is not to be confused with the renderer's buffer damage, ie. the
|
||||||
* region compositors need to repaint. Compositors usually need to repaint more
|
* region compositors need to repaint. Compositors usually need to repaint more
|
||||||
|
|
@ -392,8 +404,7 @@ size_t wlr_output_get_gamma_size(struct wlr_output *output);
|
||||||
void wlr_output_set_gamma(struct wlr_output *output, size_t size,
|
void wlr_output_set_gamma(struct wlr_output *output, size_t size,
|
||||||
const uint16_t *r, const uint16_t *g, const uint16_t *b);
|
const uint16_t *r, const uint16_t *g, const uint16_t *b);
|
||||||
/**
|
/**
|
||||||
* Exports the output's current back-buffer as a DMA-BUF (ie. the buffer that
|
* Exports the last committed buffer as a DMA-BUF.
|
||||||
* will be displayed on next commit).
|
|
||||||
*
|
*
|
||||||
* The caller is responsible for cleaning up the DMA-BUF attributes.
|
* The caller is responsible for cleaning up the DMA-BUF attributes.
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -124,10 +124,10 @@ struct wlr_output *wlr_output_layout_get_center_output(
|
||||||
struct wlr_output_layout *layout);
|
struct wlr_output_layout *layout);
|
||||||
|
|
||||||
enum wlr_direction {
|
enum wlr_direction {
|
||||||
WLR_DIRECTION_UP = 1,
|
WLR_DIRECTION_UP = 1 << 0,
|
||||||
WLR_DIRECTION_DOWN = 2,
|
WLR_DIRECTION_DOWN = 1 << 1,
|
||||||
WLR_DIRECTION_LEFT = 4,
|
WLR_DIRECTION_LEFT = 1 << 2,
|
||||||
WLR_DIRECTION_RIGHT = 8,
|
WLR_DIRECTION_RIGHT = 1 << 3,
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@ struct wlr_output_power_v1 {
|
||||||
struct wl_list link;
|
struct wl_list link;
|
||||||
|
|
||||||
struct wl_listener output_destroy_listener;
|
struct wl_listener output_destroy_listener;
|
||||||
struct wl_listener output_enable_listener;
|
struct wl_listener output_commit_listener;
|
||||||
|
|
||||||
void *data;
|
void *data;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <wayland-server-core.h>
|
#include <wayland-server-core.h>
|
||||||
|
#include <wayland-server-protocol.h>
|
||||||
#include <wlr/types/wlr_input_device.h>
|
#include <wlr/types/wlr_input_device.h>
|
||||||
|
|
||||||
struct wlr_pointer_impl;
|
struct wlr_pointer_impl;
|
||||||
|
|
|
||||||
|
|
@ -53,6 +53,7 @@ struct wlr_screencopy_frame_v1 {
|
||||||
|
|
||||||
struct wlr_output *output;
|
struct wlr_output *output;
|
||||||
struct wl_listener output_precommit;
|
struct wl_listener output_precommit;
|
||||||
|
struct wl_listener output_commit;
|
||||||
struct wl_listener output_destroy;
|
struct wl_listener output_destroy;
|
||||||
struct wl_listener output_enable;
|
struct wl_listener output_enable;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@
|
||||||
#include <wayland-server-core.h>
|
#include <wayland-server-core.h>
|
||||||
#include <wlr/types/wlr_input_device.h>
|
#include <wlr/types/wlr_input_device.h>
|
||||||
#include <wlr/types/wlr_keyboard.h>
|
#include <wlr/types/wlr_keyboard.h>
|
||||||
|
#include <wlr/types/wlr_pointer.h>
|
||||||
#include <wlr/types/wlr_surface.h>
|
#include <wlr/types/wlr_surface.h>
|
||||||
|
|
||||||
#define WLR_SERIAL_RINGSET_SIZE 128
|
#define WLR_SERIAL_RINGSET_SIZE 128
|
||||||
|
|
|
||||||
|
|
@ -67,6 +67,15 @@ struct wlr_surface_role {
|
||||||
void (*precommit)(struct wlr_surface *surface);
|
void (*precommit)(struct wlr_surface *surface);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct wlr_surface_output {
|
||||||
|
struct wlr_surface *surface;
|
||||||
|
struct wlr_output *output;
|
||||||
|
|
||||||
|
struct wl_list link; // wlr_surface::current_outputs
|
||||||
|
struct wl_listener bind;
|
||||||
|
struct wl_listener destroy;
|
||||||
|
};
|
||||||
|
|
||||||
struct wlr_surface {
|
struct wlr_surface {
|
||||||
struct wl_resource *resource;
|
struct wl_resource *resource;
|
||||||
struct wlr_renderer *renderer;
|
struct wlr_renderer *renderer;
|
||||||
|
|
@ -126,6 +135,8 @@ struct wlr_surface {
|
||||||
// wlr_subsurface::parent_pending_link
|
// wlr_subsurface::parent_pending_link
|
||||||
struct wl_list subsurface_pending_list;
|
struct wl_list subsurface_pending_list;
|
||||||
|
|
||||||
|
struct wl_list current_outputs; // wlr_surface_output::link
|
||||||
|
|
||||||
struct wl_listener renderer_destroy;
|
struct wl_listener renderer_destroy;
|
||||||
|
|
||||||
void *data;
|
void *data;
|
||||||
|
|
|
||||||
|
|
@ -48,8 +48,6 @@ struct wlr_xdg_client {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct wlr_xdg_positioner {
|
struct wlr_xdg_positioner {
|
||||||
struct wl_resource *resource;
|
|
||||||
|
|
||||||
struct wlr_box anchor_rect;
|
struct wlr_box anchor_rect;
|
||||||
enum xdg_positioner_anchor anchor;
|
enum xdg_positioner_anchor anchor;
|
||||||
enum xdg_positioner_gravity gravity;
|
enum xdg_positioner_gravity gravity;
|
||||||
|
|
@ -124,6 +122,7 @@ struct wlr_xdg_toplevel {
|
||||||
|
|
||||||
struct wlr_xdg_toplevel_state client_pending;
|
struct wlr_xdg_toplevel_state client_pending;
|
||||||
struct wlr_xdg_toplevel_state server_pending;
|
struct wlr_xdg_toplevel_state server_pending;
|
||||||
|
struct wlr_xdg_toplevel_state last_acked;
|
||||||
struct wlr_xdg_toplevel_state current;
|
struct wlr_xdg_toplevel_state current;
|
||||||
|
|
||||||
char *title;
|
char *title;
|
||||||
|
|
|
||||||
|
|
@ -1,374 +0,0 @@
|
||||||
/*
|
|
||||||
* This protocol is obsolete and will be removed in a future version. The
|
|
||||||
* recommended replacement is xdg-shell.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* 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_XDG_SHELL_V6_H
|
|
||||||
#define WLR_TYPES_WLR_XDG_SHELL_V6_H
|
|
||||||
|
|
||||||
#include <wayland-server-core.h>
|
|
||||||
#include <wlr/types/wlr_box.h>
|
|
||||||
#include <wlr/types/wlr_seat.h>
|
|
||||||
#include "xdg-shell-unstable-v6-protocol.h"
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An interface enabling clients to turn their wl_surfaces into windows in a
|
|
||||||
* desktop environment.
|
|
||||||
*/
|
|
||||||
struct wlr_xdg_shell_v6 {
|
|
||||||
struct wl_global *global;
|
|
||||||
struct wl_list clients;
|
|
||||||
struct wl_list popup_grabs;
|
|
||||||
uint32_t ping_timeout;
|
|
||||||
|
|
||||||
struct wl_listener display_destroy;
|
|
||||||
|
|
||||||
struct {
|
|
||||||
/**
|
|
||||||
* The `new_surface` event signals that a client has requested to
|
|
||||||
* create a new shell surface. At this point, the surface is ready to
|
|
||||||
* be configured but is not mapped or ready receive input events. The
|
|
||||||
* surface will be ready to be managed on the `map` event.
|
|
||||||
*/
|
|
||||||
struct wl_signal new_surface;
|
|
||||||
struct wl_signal destroy;
|
|
||||||
} events;
|
|
||||||
|
|
||||||
void *data;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct wlr_xdg_client_v6 {
|
|
||||||
struct wlr_xdg_shell_v6 *shell;
|
|
||||||
struct wl_resource *resource;
|
|
||||||
struct wl_client *client;
|
|
||||||
struct wl_list surfaces;
|
|
||||||
|
|
||||||
struct wl_list link; // wlr_xdg_shell_v6::clients
|
|
||||||
|
|
||||||
uint32_t ping_serial;
|
|
||||||
struct wl_event_source *ping_timer;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct wlr_xdg_positioner_v6 {
|
|
||||||
struct wlr_box anchor_rect;
|
|
||||||
enum zxdg_positioner_v6_anchor anchor;
|
|
||||||
enum zxdg_positioner_v6_gravity gravity;
|
|
||||||
enum zxdg_positioner_v6_constraint_adjustment constraint_adjustment;
|
|
||||||
|
|
||||||
struct {
|
|
||||||
int32_t width, height;
|
|
||||||
} size;
|
|
||||||
|
|
||||||
struct {
|
|
||||||
int32_t x, y;
|
|
||||||
} offset;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct wlr_xdg_popup_v6 {
|
|
||||||
struct wlr_xdg_surface_v6 *base;
|
|
||||||
struct wl_list link;
|
|
||||||
|
|
||||||
struct wl_resource *resource;
|
|
||||||
bool committed;
|
|
||||||
struct wlr_xdg_surface_v6 *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_positioner_v6 positioner;
|
|
||||||
|
|
||||||
struct wl_list grab_link; // wlr_xdg_popup_grab_v6::popups
|
|
||||||
};
|
|
||||||
|
|
||||||
// each seat gets a popup grab
|
|
||||||
struct wlr_xdg_popup_grab_v6 {
|
|
||||||
struct wl_client *client;
|
|
||||||
struct wlr_seat_pointer_grab pointer_grab;
|
|
||||||
struct wlr_seat_keyboard_grab keyboard_grab;
|
|
||||||
struct wlr_seat_touch_grab touch_grab;
|
|
||||||
struct wlr_seat *seat;
|
|
||||||
struct wl_list popups;
|
|
||||||
struct wl_list link; // wlr_xdg_shell_v6::popup_grabs
|
|
||||||
struct wl_listener seat_destroy;
|
|
||||||
};
|
|
||||||
|
|
||||||
enum wlr_xdg_surface_v6_role {
|
|
||||||
WLR_XDG_SURFACE_V6_ROLE_NONE,
|
|
||||||
WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL,
|
|
||||||
WLR_XDG_SURFACE_V6_ROLE_POPUP,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct wlr_xdg_toplevel_v6_state {
|
|
||||||
bool maximized, fullscreen, resizing, activated;
|
|
||||||
uint32_t width, height;
|
|
||||||
uint32_t max_width, max_height;
|
|
||||||
uint32_t min_width, min_height;
|
|
||||||
|
|
||||||
// Since the fullscreen request may be made before the toplevel's surface
|
|
||||||
// is mapped, this is used to store the requested fullscreen output (if
|
|
||||||
// any) for wlr_xdg_toplevel_v6::client_pending.
|
|
||||||
struct wlr_output *fullscreen_output;
|
|
||||||
struct wl_listener fullscreen_output_destroy;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An xdg-surface is a user interface element requiring management by the
|
|
||||||
* compositor. An xdg-surface alone isn't useful, a role should be assigned to
|
|
||||||
* it in order to map it.
|
|
||||||
*
|
|
||||||
* When a surface has a role and is ready to be displayed, the `map` event is
|
|
||||||
* emitted. When a surface should no longer be displayed, the `unmap` event is
|
|
||||||
* emitted. The `unmap` event is guaranteed to be emitted before the `destroy`
|
|
||||||
* event if the view is destroyed when mapped.
|
|
||||||
*/
|
|
||||||
struct wlr_xdg_toplevel_v6 {
|
|
||||||
struct wl_resource *resource;
|
|
||||||
struct wlr_xdg_surface_v6 *base;
|
|
||||||
struct wlr_xdg_surface_v6 *parent;
|
|
||||||
bool added;
|
|
||||||
|
|
||||||
struct wlr_xdg_toplevel_v6_state client_pending;
|
|
||||||
struct wlr_xdg_toplevel_v6_state server_pending;
|
|
||||||
struct wlr_xdg_toplevel_v6_state current;
|
|
||||||
|
|
||||||
char *title;
|
|
||||||
char *app_id;
|
|
||||||
|
|
||||||
struct {
|
|
||||||
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;
|
|
||||||
struct wl_signal request_show_window_menu;
|
|
||||||
struct wl_signal set_parent;
|
|
||||||
struct wl_signal set_title;
|
|
||||||
struct wl_signal set_app_id;
|
|
||||||
} events;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct wlr_xdg_surface_v6_configure {
|
|
||||||
struct wl_list link; // wlr_xdg_surface_v6::configure_list
|
|
||||||
uint32_t serial;
|
|
||||||
|
|
||||||
struct wlr_xdg_toplevel_v6_state *toplevel_state;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct wlr_xdg_surface_v6 {
|
|
||||||
struct wlr_xdg_client_v6 *client;
|
|
||||||
struct wl_resource *resource;
|
|
||||||
struct wlr_surface *surface;
|
|
||||||
struct wl_list link; // wlr_xdg_client_v6::surfaces
|
|
||||||
enum wlr_xdg_surface_v6_role role;
|
|
||||||
|
|
||||||
union {
|
|
||||||
struct wlr_xdg_toplevel_v6 *toplevel;
|
|
||||||
struct wlr_xdg_popup_v6 *popup;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct wl_list popups; // wlr_xdg_popup_v6::link
|
|
||||||
|
|
||||||
bool added, configured, mapped;
|
|
||||||
uint32_t configure_serial;
|
|
||||||
struct wl_event_source *configure_idle;
|
|
||||||
uint32_t configure_next_serial;
|
|
||||||
struct wl_list configure_list;
|
|
||||||
|
|
||||||
bool has_next_geometry;
|
|
||||||
struct wlr_box next_geometry;
|
|
||||||
struct wlr_box geometry;
|
|
||||||
|
|
||||||
struct wl_listener surface_destroy;
|
|
||||||
struct wl_listener surface_commit;
|
|
||||||
|
|
||||||
struct {
|
|
||||||
struct wl_signal destroy;
|
|
||||||
struct wl_signal ping_timeout;
|
|
||||||
struct wl_signal new_popup;
|
|
||||||
/**
|
|
||||||
* The `map` event signals that the shell surface is ready to be
|
|
||||||
* managed by the compositor and rendered on the screen. At this point,
|
|
||||||
* the surface has configured its properties, has had the opportunity
|
|
||||||
* to bind to the seat to receive input events, and has a buffer that
|
|
||||||
* is ready to be rendered. You can now safely add this surface to a
|
|
||||||
* list of views.
|
|
||||||
*/
|
|
||||||
struct wl_signal map;
|
|
||||||
/**
|
|
||||||
* The `unmap` event signals that the surface is no longer in a state
|
|
||||||
* where it should be shown on the screen. This might happen if the
|
|
||||||
* surface no longer has a displayable buffer because either the
|
|
||||||
* surface has been hidden or is about to be destroyed.
|
|
||||||
*/
|
|
||||||
struct wl_signal unmap;
|
|
||||||
} events;
|
|
||||||
|
|
||||||
void *data;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct wlr_xdg_toplevel_v6_move_event {
|
|
||||||
struct wlr_xdg_surface_v6 *surface;
|
|
||||||
struct wlr_seat_client *seat;
|
|
||||||
uint32_t serial;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct wlr_xdg_toplevel_v6_resize_event {
|
|
||||||
struct wlr_xdg_surface_v6 *surface;
|
|
||||||
struct wlr_seat_client *seat;
|
|
||||||
uint32_t serial;
|
|
||||||
uint32_t edges;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct wlr_xdg_toplevel_v6_set_fullscreen_event {
|
|
||||||
struct wlr_xdg_surface_v6 *surface;
|
|
||||||
bool fullscreen;
|
|
||||||
struct wlr_output *output;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct wlr_xdg_toplevel_v6_show_window_menu_event {
|
|
||||||
struct wlr_xdg_surface_v6 *surface;
|
|
||||||
struct wlr_seat_client *seat;
|
|
||||||
uint32_t serial;
|
|
||||||
uint32_t x, y;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct wlr_xdg_shell_v6 *wlr_xdg_shell_v6_create(struct wl_display *display);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Send a ping to the surface. If the surface does not respond in a reasonable
|
|
||||||
* amount of time, the ping_timeout event will be emitted.
|
|
||||||
*/
|
|
||||||
void wlr_xdg_surface_v6_ping(struct wlr_xdg_surface_v6 *surface);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Request that this toplevel surface be the given size. Returns the associated
|
|
||||||
* configure serial.
|
|
||||||
*/
|
|
||||||
uint32_t wlr_xdg_toplevel_v6_set_size(struct wlr_xdg_surface_v6 *surface,
|
|
||||||
uint32_t width, uint32_t height);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Request that this toplevel surface show itself in an activated or deactivated
|
|
||||||
* state. Returns the associated configure serial.
|
|
||||||
*/
|
|
||||||
uint32_t wlr_xdg_toplevel_v6_set_activated(struct wlr_xdg_surface_v6 *surface,
|
|
||||||
bool activated);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Request that this toplevel surface consider itself maximized or not
|
|
||||||
* maximized. Returns the associated configure serial.
|
|
||||||
*/
|
|
||||||
uint32_t wlr_xdg_toplevel_v6_set_maximized(struct wlr_xdg_surface_v6 *surface,
|
|
||||||
bool maximized);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Request that this toplevel surface consider itself fullscreen or not
|
|
||||||
* fullscreen. Returns the associated configure serial.
|
|
||||||
*/
|
|
||||||
uint32_t wlr_xdg_toplevel_v6_set_fullscreen(struct wlr_xdg_surface_v6 *surface,
|
|
||||||
bool fullscreen);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Request that this toplevel surface consider itself to be resizing or not
|
|
||||||
* resizing. Returns the associated configure serial.
|
|
||||||
*/
|
|
||||||
uint32_t wlr_xdg_toplevel_v6_set_resizing(struct wlr_xdg_surface_v6 *surface,
|
|
||||||
bool resizing);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Request that this xdg surface closes.
|
|
||||||
*/
|
|
||||||
void wlr_xdg_surface_v6_send_close(struct wlr_xdg_surface_v6 *surface);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Find a surface within this xdg-surface tree at the given surface-local
|
|
||||||
* coordinates. Returns the surface and coordinates in the leaf surface
|
|
||||||
* coordinate system or NULL if no surface is found at that location.
|
|
||||||
*/
|
|
||||||
struct wlr_surface *wlr_xdg_surface_v6_surface_at(
|
|
||||||
struct wlr_xdg_surface_v6 *surface, double sx, double sy,
|
|
||||||
double *sub_x, double *sub_y);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the geometry for this positioner based on the anchor rect, gravity, and
|
|
||||||
* size of this positioner.
|
|
||||||
*/
|
|
||||||
struct wlr_box wlr_xdg_positioner_v6_get_geometry(
|
|
||||||
struct wlr_xdg_positioner_v6 *positioner);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the anchor point for this popup in the toplevel parent's coordinate system.
|
|
||||||
*/
|
|
||||||
void wlr_xdg_popup_v6_get_anchor_point(struct wlr_xdg_popup_v6 *popup,
|
|
||||||
int *toplevel_sx, int *toplevel_sy);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Convert the given coordinates in the popup coordinate system to the toplevel
|
|
||||||
* surface coordinate system.
|
|
||||||
*/
|
|
||||||
void wlr_xdg_popup_v6_get_toplevel_coords(struct wlr_xdg_popup_v6 *popup,
|
|
||||||
int popup_sx, int popup_sy, int *toplevel_sx, int *toplevel_sy);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the geometry of this popup to unconstrain it according to its
|
|
||||||
* xdg-positioner rules. The box should be in the popup's root toplevel parent
|
|
||||||
* surface coordinate system.
|
|
||||||
*/
|
|
||||||
void wlr_xdg_popup_v6_unconstrain_from_box(struct wlr_xdg_popup_v6 *popup,
|
|
||||||
struct wlr_box *toplevel_sx_box);
|
|
||||||
|
|
||||||
/**
|
|
||||||
Invert the right/left anchor and gravity for this positioner. This can be
|
|
||||||
used to "flip" the positioner around the anchor rect in the x direction.
|
|
||||||
*/
|
|
||||||
void wlr_positioner_v6_invert_x(
|
|
||||||
struct wlr_xdg_positioner_v6 *positioner);
|
|
||||||
|
|
||||||
/**
|
|
||||||
Invert the top/bottom anchor and gravity for this positioner. This can be
|
|
||||||
used to "flip" the positioner around the anchor rect in the y direction.
|
|
||||||
*/
|
|
||||||
void wlr_positioner_v6_invert_y(
|
|
||||||
struct wlr_xdg_positioner_v6 *positioner);
|
|
||||||
|
|
||||||
bool wlr_surface_is_xdg_surface_v6(struct wlr_surface *surface);
|
|
||||||
|
|
||||||
struct wlr_xdg_surface_v6 *wlr_xdg_surface_v6_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
|
|
||||||
*/
|
|
||||||
void wlr_xdg_surface_v6_get_geometry(struct wlr_xdg_surface_v6 *surface, struct wlr_box *box);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Call `iterator` on each surface and popup in the xdg-surface tree, with the
|
|
||||||
* surface's position relative to the root xdg-surface. The function is called
|
|
||||||
* from root to leaves (in rendering order).
|
|
||||||
*/
|
|
||||||
void wlr_xdg_surface_v6_for_each_surface(struct wlr_xdg_surface_v6 *surface,
|
|
||||||
wlr_surface_iterator_func_t iterator, void *user_data);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Call `iterator` on each popup in the xdg-surface tree, with the popup's
|
|
||||||
* position relative to the root xdg-surface. The function is called from root
|
|
||||||
* to leaves (in rendering order).
|
|
||||||
*/
|
|
||||||
void wlr_xdg_surface_v6_for_each_popup(struct wlr_xdg_surface_v6 *surface,
|
|
||||||
wlr_surface_iterator_func_t iterator, void *user_data);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
@ -19,10 +19,10 @@
|
||||||
|
|
||||||
enum wlr_edges {
|
enum wlr_edges {
|
||||||
WLR_EDGE_NONE = 0,
|
WLR_EDGE_NONE = 0,
|
||||||
WLR_EDGE_TOP = 1,
|
WLR_EDGE_TOP = 1 << 0,
|
||||||
WLR_EDGE_BOTTOM = 2,
|
WLR_EDGE_BOTTOM = 1 << 1,
|
||||||
WLR_EDGE_LEFT = 4,
|
WLR_EDGE_LEFT = 1 << 2,
|
||||||
WLR_EDGE_RIGHT = 8,
|
WLR_EDGE_RIGHT = 1 << 3,
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue