Преглед изворни кода

wayland: Send display moved events on display geometry changes

Updates are sent to outputs, however, dispatching the moved event was overlooked and never implemented.
Frank Praznik пре 2 дана
родитељ
комит
41bce956f0

+ 29 - 3
src/video/wayland/SDL_waylandvideo.c

@@ -442,6 +442,15 @@ static void Wayland_SortOutputs(SDL_VideoData *vid)
     Wayland_SortOutputsByPriorityHint(vid);
 }
 
+static void Wayland_RefreshWindowPositions()
+{
+    SDL_VideoDevice *vid = SDL_GetVideoDevice();
+
+    for (SDL_Window *w = vid->windows; w; w = w->next) {
+        Wayland_UpdateWindowPosition(w);
+    }
+}
+
 static void handle_wl_output_done(void *data, struct wl_output *output);
 
 // Initialization/Query functions
@@ -786,6 +795,7 @@ static void handle_xdg_output_logical_position(void *data, struct zxdg_output_v1
 {
     SDL_DisplayData *internal = (SDL_DisplayData *)data;
 
+    internal->geometry_changed |= internal->logical.x != x || internal->logical.y != y;
     internal->logical.x = x;
     internal->logical.y = y;
     internal->has_logical_position = true;
@@ -795,6 +805,7 @@ static void handle_xdg_output_logical_size(void *data, struct zxdg_output_v1 *xd
 {
     SDL_DisplayData *internal = (SDL_DisplayData *)data;
 
+    internal->geometry_changed |= internal->logical.width != width || internal->logical.height != height;
     internal->logical.width = width;
     internal->logical.height = height;
     internal->has_logical_size = true;
@@ -932,6 +943,7 @@ static void handle_wl_output_geometry(void *data, struct wl_output *output, int
 
     // Apply the change from wl-output only if xdg-output is not supported
     if (!internal->has_logical_position) {
+        internal->geometry_changed |= internal->logical.x != x || internal->logical.y != y;
         internal->logical.x = x;
         internal->logical.y = y;
     }
@@ -980,6 +992,7 @@ static void handle_wl_output_mode(void *data, struct wl_output *output, uint32_t
     SDL_DisplayData *internal = (SDL_DisplayData *)data;
 
     if (flags & WL_OUTPUT_MODE_CURRENT) {
+        internal->geometry_changed |= internal->pixel.width != width || internal->pixel.height != height;
         internal->pixel.width = width;
         internal->pixel.height = height;
 
@@ -988,6 +1001,7 @@ static void handle_wl_output_mode(void *data, struct wl_output *output, uint32_t
          * handle_done and xdg-output coordinates are pre-transformed.
          */
         if (!internal->has_logical_size) {
+            internal->geometry_changed |= internal->logical.width != width || internal->logical.height != height;
             internal->logical.width = width;
             internal->logical.height = height;
         }
@@ -1103,11 +1117,9 @@ static void handle_wl_output_done(void *data, struct wl_output *output)
         }
     } else {
         // ...otherwise expose the integer scaled variants of the desktop resolution down to 1.
-        int i;
-
         desktop_mode.pixel_density = 1.0f;
 
-        for (i = (int)internal->scale_factor; i > 0; --i) {
+        for (int i = (int)internal->scale_factor; i > 0; --i) {
             desktop_mode.w = internal->logical.width * i;
             desktop_mode.h = internal->logical.height * i;
             SDL_AddFullscreenDisplayMode(dpy, &desktop_mode);
@@ -1141,13 +1153,27 @@ static void handle_wl_output_done(void *data, struct wl_output *output)
             if (video->scale_to_display_enabled) {
                 Wayland_DeriveOutputPixelCoordinates(video);
             }
+
             internal->display = SDL_AddVideoDisplay(&internal->placeholder, true);
+            Wayland_RefreshWindowPositions();
+
             SDL_free(internal->placeholder.name);
             SDL_zero(internal->placeholder);
         }
     } else {
         SDL_SendDisplayEvent(dpy, SDL_EVENT_DISPLAY_ORIENTATION, internal->orientation, 0);
+
+        if (internal->geometry_changed) {
+            if (video->scale_to_display_enabled) {
+                Wayland_DeriveOutputPixelCoordinates(video);
+            }
+
+            SDL_SendDisplayEvent(dpy, SDL_EVENT_DISPLAY_MOVED, 0, 0);
+            Wayland_RefreshWindowPositions();
+        }
     }
+
+    internal->geometry_changed = false;
 }
 
 static void handle_wl_output_scale(void *data, struct wl_output *output, int32_t factor)

+ 1 - 0
src/video/wayland/SDL_waylandvideo.h

@@ -150,6 +150,7 @@ struct SDL_DisplayData
     int wl_output_done_count;
     bool has_logical_position;
     bool has_logical_size;
+    bool geometry_changed;
 };
 
 // Needed here to get wl_surface declaration, fixes GitHub#4594

+ 30 - 43
src/video/wayland/SDL_waylandwindow.c

@@ -655,11 +655,10 @@ static void FlushPendingEvents(SDL_Window *window)
  * what monitor we're on, so let's send move events that put the window at the
  * center of the whatever display the wl_surface_listener events give us.
  */
-static void Wayland_move_window(SDL_Window *window)
+void Wayland_UpdateWindowPosition(SDL_Window *window)
 {
     SDL_WindowData *wind = window->internal;
     SDL_DisplayData *display;
-    SDL_DisplayID *displays;
 
     if (wind->outputs && wind->num_outputs) {
         display = wind->outputs[wind->num_outputs - 1];
@@ -668,45 +667,33 @@ static void Wayland_move_window(SDL_Window *window)
         return;
     }
 
-    displays = SDL_GetDisplays(NULL);
-    if (displays) {
-        for (int i = 0; displays[i]; ++i) {
-            if (SDL_GetDisplayDriverData(displays[i]) == display) {
-                /* We want to send a very very specific combination here:
-                 *
-                 * 1. A coordinate that tells the application what display we're on
-                 * 2. Exactly (0, 0)
-                 *
-                 * Part 1 is useful information but is also really important for
-                 * ensuring we end up on the right display for fullscreen, while
-                 * part 2 is important because numerous applications use a specific
-                 * combination of GetWindowPosition and GetGlobalMouseState, and of
-                 * course neither are supported by Wayland. Since global mouse will
-                 * fall back to just GetMouseState, we need the window position to
-                 * be zero so the cursor math works without it going off in some
-                 * random direction. See UE5 Editor for a notable example of this!
-                 *
-                 * This may be an issue some day if we're ever able to implement
-                 * SDL_GetDisplayUsableBounds!
-                 *
-                 * -flibit
-                 */
-
-                if (wind->last_displayID != displays[i]) {
-                    wind->last_displayID = displays[i];
-                    if (wind->shell_surface_type != WAYLAND_SHELL_SURFACE_TYPE_XDG_POPUP) {
-                        if (!wind->waylandData->scale_to_display_enabled) {
-                            SDL_SendWindowEvent(window, SDL_EVENT_WINDOW_MOVED, display->logical.x, display->logical.y);
-                        } else {
-                            SDL_SendWindowEvent(window, SDL_EVENT_WINDOW_MOVED, display->pixel.x, display->pixel.y);
-                        }
-                        SDL_SendWindowEvent(window, SDL_EVENT_WINDOW_DISPLAY_CHANGED, wind->last_displayID, 0);
-                    }
-                }
-                break;
-            }
+    /* We want to send a very very specific combination here:
+     *
+     * 1. A coordinate that tells the application what display we're on
+     * 2. Exactly (0, 0)
+     *
+     * Part 1 is useful information but is also really important for
+     * ensuring we end up on the right display for fullscreen, while
+     * part 2 is important because numerous applications use a specific
+     * combination of GetWindowPosition and GetGlobalMouseState, and of
+     * course neither are supported by Wayland. Since global mouse will
+     * fall back to just GetMouseState, we need the window position to
+     * be zero so the cursor math works without it going off in some
+     * random direction. See UE5 Editor for a notable example of this!
+     *
+     * This may be an issue some day if we're ever able to implement
+     * SDL_GetDisplayUsableBounds!
+     *
+     * -flibit
+     */
+    wind->last_displayID = display->display;
+    if (wind->shell_surface_type != WAYLAND_SHELL_SURFACE_TYPE_XDG_POPUP) {
+        if (!wind->waylandData->scale_to_display_enabled) {
+            SDL_SendWindowEvent(window, SDL_EVENT_WINDOW_MOVED, display->logical.x, display->logical.y);
+        } else {
+            SDL_SendWindowEvent(window, SDL_EVENT_WINDOW_MOVED, display->pixel.x, display->pixel.y);
         }
-        SDL_free(displays);
+        SDL_SendWindowEvent(window, SDL_EVENT_WINDOW_DISPLAY_CHANGED, wind->last_displayID, 0);
     }
 }
 
@@ -779,7 +766,7 @@ static void UpdateWindowFullscreen(SDL_Window *window, bool fullscreen)
             /* Send a move event, in case it was deferred while the fullscreen window was moving and
              * on multiple outputs.
              */
-            Wayland_move_window(window);
+            Wayland_UpdateWindowPosition(window);
         }
     }
 }
@@ -1788,7 +1775,7 @@ void Wayland_RemoveOutputFromWindow(SDL_WindowData *window, SDL_DisplayData *dis
         SDL_free(window->outputs);
         window->outputs = NULL;
     } else if (!window->is_fullscreen || window->num_outputs == 1) {
-        Wayland_move_window(window->sdlwindow);
+        Wayland_UpdateWindowPosition(window->sdlwindow);
         Wayland_MaybeUpdateScaleFactor(window);
     }
 }
@@ -1813,7 +1800,7 @@ static void handle_surface_enter(void *data, struct wl_surface *surface, struct
 
     // Update the scale factor after the move so that fullscreen outputs are updated.
     if (!window->is_fullscreen || window->num_outputs == 1) {
-        Wayland_move_window(window->sdlwindow);
+        Wayland_UpdateWindowPosition(window->sdlwindow);
         Wayland_MaybeUpdateScaleFactor(window);
     }
 }

+ 1 - 0
src/video/wayland/SDL_waylandwindow.h

@@ -278,5 +278,6 @@ extern bool Wayland_SyncWindow(SDL_VideoDevice *_this, SDL_Window *window);
 extern bool Wayland_ReconfigureWindow(SDL_VideoDevice *_this, SDL_Window *window, SDL_WindowFlags flags);
 
 extern void Wayland_RemoveOutputFromWindow(SDL_WindowData *window, SDL_DisplayData *display_data);
+extern void Wayland_UpdateWindowPosition(SDL_Window *window);
 
 #endif // SDL_waylandwindow_h_