mirror of
https://gitlab.freedesktop.org/wlroots/wlroots.git
synced 2026-04-14 08:22:25 -04:00
Merge branch 'rhpd' into 'master'
backend/session: Add rapid hotplug detection See merge request wlroots/wlroots!4633
This commit is contained in:
commit
3c661edf3c
3 changed files with 82 additions and 27 deletions
|
|
@ -16,6 +16,7 @@
|
|||
#include <xf86drmMode.h>
|
||||
#include "backend/session/session.h"
|
||||
#include "util/time.h"
|
||||
#include "util/env.h"
|
||||
|
||||
#include <libseat.h>
|
||||
|
||||
|
|
@ -166,31 +167,11 @@ static void read_udev_change_event(struct wlr_device_change_event *event,
|
|||
}
|
||||
}
|
||||
|
||||
static int handle_udev_event(int fd, uint32_t mask, void *data) {
|
||||
struct wlr_session *session = data;
|
||||
static int handle_udev_event(const char *sysname, const char *devnode, const char *action,
|
||||
struct wlr_session *session, struct udev_device *udev_dev, void *data) {
|
||||
|
||||
struct udev_device *udev_dev = udev_monitor_receive_device(session->mon);
|
||||
if (!udev_dev) {
|
||||
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);
|
||||
wlr_log(WLR_DEBUG, "udev event for %s (%s)", sysname, action);
|
||||
|
||||
if (!is_drm_card(sysname) || !action || !devnode) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
const char *seat = udev_device_get_property_value(udev_dev, "ID_SEAT");
|
||||
if (!seat) {
|
||||
seat = "seat0";
|
||||
}
|
||||
if (session->seat[0] != '\0' && strcmp(session->seat, seat) != 0) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (strcmp(action, "add") == 0) {
|
||||
wlr_log(WLR_DEBUG, "DRM device %s added", sysname);
|
||||
struct wlr_session_add_event event = {
|
||||
|
|
@ -206,10 +187,19 @@ static int handle_udev_event(int fd, uint32_t mask, void *data) {
|
|||
}
|
||||
|
||||
if (strcmp(action, "change") == 0) {
|
||||
wlr_log(WLR_DEBUG, "DRM device %s changed", sysname);
|
||||
struct wlr_device_change_event event = {0};
|
||||
read_udev_change_event(&event, udev_dev);
|
||||
wl_signal_emit_mutable(&dev->events.change, &event);
|
||||
bool double_uevent_occured;
|
||||
if (env_parse_bool("WLR_RAPID_HOTPLUG_PREVENT")) {
|
||||
double_uevent_occured = check_double_uevent(sysname, devnode, action, data);
|
||||
} else {
|
||||
double_uevent_occured = false;
|
||||
}
|
||||
if (!double_uevent_occured) {
|
||||
wlr_log(WLR_DEBUG, "Resuming change event for DRM device %s", sysname);
|
||||
wlr_log(WLR_DEBUG, "DRM device %s changed", sysname);
|
||||
struct wlr_device_change_event event = {0};
|
||||
read_udev_change_event(&event, udev_dev);
|
||||
wl_signal_emit_mutable(&dev->events.change, &event);
|
||||
}
|
||||
} else if (strcmp(action, "remove") == 0) {
|
||||
wlr_log(WLR_DEBUG, "DRM device %s removed", sysname);
|
||||
wl_signal_emit_mutable(&dev->events.remove, NULL);
|
||||
|
|
@ -220,11 +210,69 @@ static int handle_udev_event(int fd, uint32_t mask, void *data) {
|
|||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int handle_udev_event_buffer(int fd, uint32_t mask, void *data) {
|
||||
struct wlr_session *session = data;
|
||||
|
||||
struct udev_device *udev_dev = udev_monitor_receive_device(session->mon);
|
||||
if (!udev_dev) {
|
||||
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);
|
||||
|
||||
if (!is_drm_card(sysname) || !action || !devnode) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
const char *seat = udev_device_get_property_value(udev_dev, "ID_SEAT");
|
||||
if (!seat) {
|
||||
seat = "seat0";
|
||||
}
|
||||
if (session->seat[0] != '\0' && strcmp(session->seat, seat) != 0) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
handle_udev_event(sysname, devnode, action, session, udev_dev, data);
|
||||
|
||||
out:
|
||||
udev_device_unref(udev_dev);
|
||||
return 1;
|
||||
}
|
||||
|
||||
bool check_double_uevent(const char *stored_sysname, const char *stored_devnode,
|
||||
const char *stored_action, void *data) {
|
||||
bool double_uevent_occured = false;
|
||||
|
||||
wlr_log(WLR_DEBUG, "Sleeping to wait for potential hot-plugs");
|
||||
sleep(1);
|
||||
|
||||
struct wlr_session *session = data;
|
||||
struct udev_device *udev_dev = udev_monitor_receive_device(session->mon);
|
||||
|
||||
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);
|
||||
|
||||
if(sysname != NULL && devnode != NULL && action != NULL) {
|
||||
if (strcmp(stored_sysname, sysname) == 0 && strcmp(stored_devnode, devnode) == 0
|
||||
&& strcmp(stored_action, action) == 0) {
|
||||
wlr_log(WLR_DEBUG, "DRM device %s double uevent ignored", sysname);
|
||||
double_uevent_occured = true;
|
||||
} else {
|
||||
handle_udev_event(sysname, devnode, action, session, udev_dev, data);
|
||||
}
|
||||
}
|
||||
|
||||
udev_device_unref(udev_dev);
|
||||
|
||||
return double_uevent_occured;
|
||||
}
|
||||
|
||||
static void handle_event_loop_destroy(struct wl_listener *listener, void *data) {
|
||||
struct wlr_session *session =
|
||||
wl_container_of(listener, session, event_loop_destroy);
|
||||
|
|
@ -267,7 +315,7 @@ struct wlr_session *wlr_session_create(struct wl_event_loop *event_loop) {
|
|||
int fd = udev_monitor_get_fd(session->mon);
|
||||
|
||||
session->udev_event = wl_event_loop_add_fd(event_loop, fd,
|
||||
WL_EVENT_READABLE, handle_udev_event, session);
|
||||
WL_EVENT_READABLE, handle_udev_event_buffer, session);
|
||||
if (!session->udev_event) {
|
||||
wlr_log_errno(WLR_ERROR, "Failed to create udev event source");
|
||||
goto error_mon;
|
||||
|
|
|
|||
|
|
@ -18,6 +18,10 @@ wlroots reads these environment variables
|
|||
and Vulkan
|
||||
* *WLR_EGL_NO_MODIFIERS*: set to 1 to disable format modifiers in EGL, this can
|
||||
be used to understand and work around driver bugs.
|
||||
* *WLR_RAPID_HOTPLUG_PREVENT*: set to 1 to wait after an output device hotplug
|
||||
in case another occurs immediately after, and if so, ignore both. This is to
|
||||
work around monitors that implement DisplayPort's "deep sleep" feature, but
|
||||
causes a second delay for each change event due to waiting.
|
||||
|
||||
## DRM backend
|
||||
|
||||
|
|
|
|||
|
|
@ -12,6 +12,9 @@ int libseat_session_open_device(struct wlr_session *base, const char *path);
|
|||
void libseat_session_close_device(struct wlr_session *base, int fd);
|
||||
bool libseat_change_vt(struct wlr_session *base, unsigned vt);
|
||||
|
||||
bool check_double_uevent(const char *stored_sysname, const char *stored_devnode,
|
||||
const char *stored_action, void *data);
|
||||
|
||||
void session_init(struct wlr_session *session);
|
||||
|
||||
struct wlr_device *session_open_if_kms(struct wlr_session *restrict session,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue