Browse Source

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.
Frank Praznik 6 months ago
parent
commit
a7da3ad59b
3 changed files with 51 additions and 0 deletions
  1. 1 0
      include/SDL3/SDL_hints.h
  2. 49 0
      src/video/x11/SDL_x11modes.c
  3. 1 0
      src/video/x11/SDL_x11modes.h

+ 1 - 0
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.
  *

+ 49 - 0
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

+ 1 - 0
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
 };