From a7da3ad59bd8ec70f0cd813d15875fa2731a83eb Mon Sep 17 00:00:00 2001
From: Frank Praznik <[EMAIL REDACTED]>
Date: Fri, 18 Oct 2024 11:26:41 -0400
Subject: [PATCH] x11: Support sorting displays via the priority hint
Store the connector name for displays and use it for sorting them according to priority, if the hint is set.
---
include/SDL3/SDL_hints.h | 1 +
src/video/x11/SDL_x11modes.c | 49 ++++++++++++++++++++++++++++++++++++
src/video/x11/SDL_x11modes.h | 1 +
3 files changed, 51 insertions(+)
diff --git a/include/SDL3/SDL_hints.h b/include/SDL3/SDL_hints.h
index 3afd1a5676344..e097ce072f233 100644
--- a/include/SDL3/SDL_hints.h
+++ b/include/SDL3/SDL_hints.h
@@ -3158,6 +3158,7 @@ extern "C" {
*
* - KMSDRM (kmsdrm)
* - Wayland (wayland)
+ * - X11 (x11)
*
* This hint should be set before SDL is initialized.
*
diff --git a/src/video/x11/SDL_x11modes.c b/src/video/x11/SDL_x11modes.c
index 1194af2c0e9de..f2170c4ba6f5c 100644
--- a/src/video/x11/SDL_x11modes.c
+++ b/src/video/x11/SDL_x11modes.c
@@ -623,6 +623,7 @@ static bool X11_FillXRandRDisplayInfo(SDL_VideoDevice *_this, Display *dpy, int
displaydata->y = display_y;
displaydata->use_xrandr = true;
displaydata->xrandr_output = outputid;
+ SDL_strlcpy(displaydata->connector_name, display_name, sizeof(displaydata->connector_name));
SetXRandRModeInfo(dpy, res, output_crtc, modeID, &mode);
SetXRandRDisplayName(dpy, EDID, display_name, display_name_size, outputid, display_mm_width, display_mm_height);
@@ -751,6 +752,52 @@ void X11_HandleXRandREvent(SDL_VideoDevice *_this, const XEvent *xevent)
}
}
+static void X11_SortOutputsByPriorityHint(SDL_VideoDevice *_this)
+{
+ const char *name_hint = SDL_GetHint(SDL_HINT_VIDEO_DISPLAY_PRIORITY);
+
+ if (name_hint) {
+ char *saveptr;
+ char *str = SDL_strdup(name_hint);
+ SDL_VideoDisplay **sorted_list = SDL_malloc(sizeof(SDL_VideoDisplay *) * _this->num_displays);
+
+ if (str && sorted_list) {
+ int sorted_index = 0;
+
+ // Sort the requested displays to the front of the list.
+ const char *token = SDL_strtok_r(str, ",", &saveptr);
+ while (token) {
+ for (int i = 0; i < _this->num_displays; ++i) {
+ SDL_VideoDisplay *d = _this->displays[i];
+ if (d) {
+ SDL_DisplayData *data = d->internal;
+ if (SDL_strcmp(token, data->connector_name) == 0) {
+ sorted_list[sorted_index++] = d;
+ _this->displays[i] = NULL;
+ break;
+ }
+ }
+ }
+
+ token = SDL_strtok_r(NULL, ",", &saveptr);
+ }
+
+ // Append the remaining displays to the end of the list.
+ for (int i = 0; i < _this->num_displays; ++i) {
+ if (_this->displays[i]) {
+ sorted_list[sorted_index++] = _this->displays[i];
+ }
+ }
+
+ // Copy the sorted list back to the display list.
+ SDL_memcpy(_this->displays, sorted_list, sizeof(SDL_VideoDisplay *) * _this->num_displays);
+ }
+
+ SDL_free(str);
+ SDL_free(sorted_list);
+ }
+}
+
static bool X11_InitModes_XRandR(SDL_VideoDevice *_this)
{
SDL_VideoData *data = _this->internal;
@@ -810,6 +857,8 @@ static bool X11_InitModes_XRandR(SDL_VideoDevice *_this)
return SDL_SetError("No available displays");
}
+ X11_SortOutputsByPriorityHint(_this);
+
return true;
}
#endif // SDL_VIDEO_DRIVER_X11_XRANDR
diff --git a/src/video/x11/SDL_x11modes.h b/src/video/x11/SDL_x11modes.h
index 4c250b6a72cb0..d8a92032bd1d5 100644
--- a/src/video/x11/SDL_x11modes.h
+++ b/src/video/x11/SDL_x11modes.h
@@ -38,6 +38,7 @@ struct SDL_DisplayData
#ifdef SDL_VIDEO_DRIVER_X11_XRANDR
RROutput xrandr_output;
+ char connector_name[16];
#endif
};