SDL: Allow the progress API to be used on all platforms

From f355c7f2172a0f07181529f68ecd2aa44bc37cf5 Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Tue, 25 Mar 2025 08:32:26 -0700
Subject: [PATCH] Allow the progress API to be used on all platforms

It's visually only hooked up on Windows for now, but the API will be internally consistent on all platforms.
---
 src/test/SDL_test_common.c            | 29 ++++++++++++--
 src/video/SDL_sysvideo.h              |  8 ++--
 src/video/SDL_video.c                 | 40 +++++++++----------
 src/video/windows/SDL_windowsevents.c |  5 +--
 src/video/windows/SDL_windowsvideo.c  |  5 +--
 src/video/windows/SDL_windowswindow.c | 55 +++------------------------
 src/video/windows/SDL_windowswindow.h |  8 +---
 7 files changed, 60 insertions(+), 90 deletions(-)

diff --git a/src/test/SDL_test_common.c b/src/test/SDL_test_common.c
index 7e46991d49acb..5f1ab6b920f62 100644
--- a/src/test/SDL_test_common.c
+++ b/src/test/SDL_test_common.c
@@ -2457,20 +2457,42 @@ SDL_AppResult SDLTest_CommonEventMainCallbacks(SDLTest_CommonState *state, const
             break;
         case SDLK_P:
             if (withAlt) {
-                /* Ctrl-P Cycle through progress states */
+                /* Alt-P cycle through progress states */
                 SDL_Window *window = SDL_GetWindowFromEvent(event);
                 if (window) {
-                    float progress_state = SDL_GetWindowProgressState(window);
+                    const char *name;
+                    SDL_ProgressState progress_state = SDL_GetWindowProgressState(window);
                     progress_state += 1;
                     if (progress_state > SDL_PROGRESS_STATE_ERROR) {
                         progress_state = SDL_PROGRESS_STATE_NONE;
                     }
+                    switch (progress_state) {
+                    case SDL_PROGRESS_STATE_NONE:
+                        name = "NONE";
+                        break;
+                    case SDL_PROGRESS_STATE_INDETERMINATE:
+                        name = "INDETERMINATE";
+                        break;
+                    case SDL_PROGRESS_STATE_NORMAL:
+                        name = "NORMAL";
+                        break;
+                    case SDL_PROGRESS_STATE_PAUSED:
+                        name = "PAUSED";
+                        break;
+                    case SDL_PROGRESS_STATE_ERROR:
+                        name = "ERROR";
+                        break;
+                    default:
+                        name = "UNKNOWN";
+                        break;
+                    }
+                    SDL_Log("Setting progress state to %s", name);
                     SDL_SetWindowProgressState(window, progress_state);
                 }
             }
             else if (withControl)
             {
-                /* Alt-P Increase progress value */
+                /* Ctrl-P increase progress value */
                 SDL_Window *window = SDL_GetWindowFromEvent(event);
                 if (window) {
                     float progress_value = SDL_GetWindowProgressValue(window);
@@ -2479,6 +2501,7 @@ SDL_AppResult SDLTest_CommonEventMainCallbacks(SDLTest_CommonState *state, const
                     } else {
                         progress_value += 0.1f;
                     }
+                    SDL_Log("Setting progress value to %.1f", progress_value);
                     SDL_SetWindowProgressValue(window, progress_value);
                 }
             }
diff --git a/src/video/SDL_sysvideo.h b/src/video/SDL_sysvideo.h
index b46e12227a030..5fe87a86d8b50 100644
--- a/src/video/SDL_sysvideo.h
+++ b/src/video/SDL_sysvideo.h
@@ -123,6 +123,9 @@ struct SDL_Window
     SDL_HitTest hit_test;
     void *hit_test_data;
 
+    SDL_ProgressState progress_state;
+    float progress_value;
+
     SDL_PropertiesID props;
 
     int num_renderers;
@@ -303,10 +306,7 @@ struct SDL_VideoDevice
     void (*OnWindowEnter)(SDL_VideoDevice *_this, SDL_Window *window);
     bool (*UpdateWindowShape)(SDL_VideoDevice *_this, SDL_Window *window, SDL_Surface *shape);
     bool (*FlashWindow)(SDL_VideoDevice *_this, SDL_Window *window, SDL_FlashOperation operation);
-    bool (*SetWindowProgressState)(SDL_VideoDevice *_this, SDL_Window *window, SDL_ProgressState state);
-    SDL_ProgressState (*GetWindowProgressState)(SDL_VideoDevice *_this, SDL_Window *window);
-    bool (*SetWindowProgressValue)(SDL_VideoDevice *_this, SDL_Window *window, float value);
-    float (*GetWindowProgressValue)(SDL_VideoDevice *_this, SDL_Window *window);
+    bool (*ApplyWindowProgress)(SDL_VideoDevice *_this, SDL_Window *window);
     bool (*SetWindowFocusable)(SDL_VideoDevice *_this, SDL_Window *window, bool focusable);
     bool (*SyncWindow)(SDL_VideoDevice *_this, SDL_Window *window);
 
diff --git a/src/video/SDL_video.c b/src/video/SDL_video.c
index a5d1f3554a121..a9d91a479c63b 100644
--- a/src/video/SDL_video.c
+++ b/src/video/SDL_video.c
@@ -3930,23 +3930,23 @@ bool SDL_SetWindowProgressState(SDL_Window *window, SDL_ProgressState state)
         return SDL_InvalidParamError("state");
     }
 
-    if (_this->SetWindowProgressState) {
-        return _this->SetWindowProgressState(_this, window, state);
+    window->progress_state = state;
+
+    if (_this->ApplyWindowProgress) {
+        if (!_this->ApplyWindowProgress(_this, window)) {
+            return false;
+        }
     }
 
-    return SDL_Unsupported();
+    return true;
 }
 
 SDL_ProgressState SDL_GetWindowProgressState(SDL_Window *window)
 {
-    CHECK_WINDOW_MAGIC(window, false);
-    CHECK_WINDOW_NOT_POPUP(window, false);
-
-    if (_this->GetWindowProgressState) {
-        return _this->GetWindowProgressState(_this, window);
-    }
+    CHECK_WINDOW_MAGIC(window, SDL_PROGRESS_STATE_INVALID);
+    CHECK_WINDOW_NOT_POPUP(window, SDL_PROGRESS_STATE_INVALID);
 
-    return SDL_Unsupported();
+    return window->progress_state;
 }
 
 bool SDL_SetWindowProgressValue(SDL_Window *window, float value)
@@ -3956,23 +3956,23 @@ bool SDL_SetWindowProgressValue(SDL_Window *window, float value)
 
     value = SDL_clamp(value, 0.0f, 1.f);
 
-    if (_this->SetWindowProgressValue) {
-        return _this->SetWindowProgressValue(_this, window, value);
+    window->progress_value = value;
+
+    if (_this->ApplyWindowProgress) {
+        if (!_this->ApplyWindowProgress(_this, window)) {
+            return false;
+        }
     }
 
-    return SDL_Unsupported();
+    return true;
 }
 
 float SDL_GetWindowProgressValue(SDL_Window *window)
 {
-    CHECK_WINDOW_MAGIC(window, false);
-    CHECK_WINDOW_NOT_POPUP(window, false);
-
-    if (_this->GetWindowProgressValue) {
-        return _this->GetWindowProgressValue(_this, window);
-    }
+    CHECK_WINDOW_MAGIC(window, -1.0f);
+    CHECK_WINDOW_NOT_POPUP(window, -1.0f);
 
-    return SDL_Unsupported();
+    return window->progress_value;
 }
 
 void SDL_OnWindowShown(SDL_Window *window)
diff --git a/src/video/windows/SDL_windowsevents.c b/src/video/windows/SDL_windowsevents.c
index bc11457ccfb06..dce81ba015bbf 100644
--- a/src/video/windows/SDL_windowsevents.c
+++ b/src/video/windows/SDL_windowsevents.c
@@ -2437,9 +2437,8 @@ LRESULT CALLBACK WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lPara
 
 #ifdef HAVE_SHOBJIDL_CORE_H
     if (msg == data->videodata->WM_TASKBAR_BUTTON_CREATED) {
-        SDL_Window *window = data->window;
-        window->internal->taskbar_button_created = true;
-        WIN_ApplyWindowProgress(window);
+        data->taskbar_button_created = true;
+        WIN_ApplyWindowProgress(SDL_GetVideoDevice(), data->window);
     }
 #endif
 
diff --git a/src/video/windows/SDL_windowsvideo.c b/src/video/windows/SDL_windowsvideo.c
index 71bc520d487c7..bdfde9ce3404f 100644
--- a/src/video/windows/SDL_windowsvideo.c
+++ b/src/video/windows/SDL_windowsvideo.c
@@ -272,10 +272,7 @@ static SDL_VideoDevice *WIN_CreateDevice(void)
     device->SetWindowHitTest = WIN_SetWindowHitTest;
     device->AcceptDragAndDrop = WIN_AcceptDragAndDrop;
     device->FlashWindow = WIN_FlashWindow;
-    device->SetWindowProgressState = WIN_SetWindowProgressState;
-    device->GetWindowProgressState = WIN_GetWindowProgressState;
-    device->SetWindowProgressValue = WIN_SetWindowProgressValue;
-    device->GetWindowProgressValue = WIN_GetWindowProgressValue;
+    device->ApplyWindowProgress = WIN_ApplyWindowProgress;
     device->ShowWindowSystemMenu = WIN_ShowWindowSystemMenu;
     device->SetWindowFocusable = WIN_SetWindowFocusable;
     device->UpdateWindowShape = WIN_UpdateWindowShape;
diff --git a/src/video/windows/SDL_windowswindow.c b/src/video/windows/SDL_windowswindow.c
index 755b191053788..3eca533a37d5a 100644
--- a/src/video/windows/SDL_windowswindow.c
+++ b/src/video/windows/SDL_windowswindow.c
@@ -2245,11 +2245,9 @@ bool WIN_FlashWindow(SDL_VideoDevice *_this, SDL_Window *window, SDL_FlashOperat
     return true;
 }
 
-bool WIN_ApplyWindowProgress(SDL_Window* window)
+bool WIN_ApplyWindowProgress(SDL_VideoDevice *_this, SDL_Window* window)
 {
-#ifndef HAVE_SHOBJIDL_CORE_H
-    return false;
-#else
+#ifdef HAVE_SHOBJIDL_CORE_H
     SDL_WindowData *data = window->internal;
     if (!data->taskbar_button_created) {
         return true;
@@ -2261,7 +2259,7 @@ bool WIN_ApplyWindowProgress(SDL_Window* window)
     }
 
     TBPFLAG tbpFlags;
-    switch (data->progress_state) {
+    switch (window->progress_state) {
     case SDL_PROGRESS_STATE_NONE:
         tbpFlags = TBPF_NOPROGRESS;
         break;
@@ -2286,55 +2284,14 @@ bool WIN_ApplyWindowProgress(SDL_Window* window)
         return WIN_SetErrorFromHRESULT("ITaskbarList3::SetProgressState()", ret);
     }
 
-    if (data->progress_state >= SDL_PROGRESS_STATE_NORMAL) {
-        ret = taskbar_list->lpVtbl->SetProgressValue(taskbar_list, data->hwnd, (ULONGLONG)(data->progress_value * 10000.f), 10000);
+    if (window->progress_state >= SDL_PROGRESS_STATE_NORMAL) {
+        ret = taskbar_list->lpVtbl->SetProgressValue(taskbar_list, data->hwnd, (ULONGLONG)(window->progress_value * 10000.f), 10000);
         if (FAILED(ret)) {
             return WIN_SetErrorFromHRESULT("ITaskbarList3::SetProgressValue()", ret);
         }
     }
-
-    return true;
-#endif
-}
-
-bool WIN_SetWindowProgressState(SDL_VideoDevice *_this, SDL_Window *window, SDL_ProgressState state)
-{
-#ifndef HAVE_SHOBJIDL_CORE_H
-    return SDL_Unsupported();
-#else
-    window->internal->progress_state = state;
-    return WIN_ApplyWindowProgress(window);
-#endif
-}
-
-SDL_ProgressState WIN_GetWindowProgressState(SDL_VideoDevice *_this, SDL_Window *window)
-{
-#ifndef HAVE_SHOBJIDL_CORE_H
-    SDL_Unsupported();
-    return SDL_PROGRESS_STATE_INVALID;
-#else
-    return window->internal->progress_state;
-#endif // HAVE_SHOBJIDL_CORE_H
-}
-
-bool WIN_SetWindowProgressValue(SDL_VideoDevice *_this, SDL_Window *window, float value)
-{
-#ifndef HAVE_SHOBJIDL_CORE_H
-    return SDL_Unsupported();
-#else
-    window->internal->progress_value = value;
-    return WIN_ApplyWindowProgress(window);
 #endif
-}
-
-float WIN_GetWindowProgressValue(SDL_VideoDevice *_this, SDL_Window *window)
-{
-#ifndef HAVE_SHOBJIDL_CORE_H
-    SDL_Unsupported();
-    return -1.0f;
-#else
-    return window->internal->progress_value;
-#endif  // HAVE_SHOBJIDL_CORE_H
+    return true;
 }
 
 void WIN_ShowWindowSystemMenu(SDL_Window *window, int x, int y)
diff --git a/src/video/windows/SDL_windowswindow.h b/src/video/windows/SDL_windowswindow.h
index 449abfe54d162..d23d83c04e46b 100644
--- a/src/video/windows/SDL_windowswindow.h
+++ b/src/video/windows/SDL_windowswindow.h
@@ -94,8 +94,6 @@ struct SDL_WindowData
     SDL_Window *keyboard_focus;
     SDL_WindowEraseBackgroundMode hint_erase_background_mode;
     bool taskbar_button_created;
-    SDL_ProgressState progress_state;
-    float progress_value;
     struct SDL_VideoData *videodata;
 #ifdef SDL_VIDEO_OPENGL_EGL
     EGLSurface egl_surface;
@@ -136,11 +134,7 @@ extern void WIN_UnclipCursorForWindow(SDL_Window *window);
 extern bool WIN_SetWindowHitTest(SDL_Window *window, bool enabled);
 extern void WIN_AcceptDragAndDrop(SDL_Window *window, bool accept);
 extern bool WIN_FlashWindow(SDL_VideoDevice *_this, SDL_Window *window, SDL_FlashOperation operation);
-extern bool WIN_ApplyWindowProgress(SDL_Window *window);
-extern bool WIN_SetWindowProgressState(SDL_VideoDevice *_this, SDL_Window *window, SDL_ProgressState state);
-extern SDL_ProgressState WIN_GetWindowProgressState(SDL_VideoDevice *_this, SDL_Window *window);
-extern bool WIN_SetWindowProgressValue(SDL_VideoDevice *_this, SDL_Window *window, float value);
-extern float WIN_GetWindowProgressValue(SDL_VideoDevice *_this, SDL_Window *window);
+extern bool WIN_ApplyWindowProgress(SDL_VideoDevice *_this, SDL_Window *window);
 extern void WIN_UpdateDarkModeForHWND(HWND hwnd);
 extern bool WIN_SetWindowPositionInternal(SDL_Window *window, UINT flags, SDL_WindowRect rect_type);
 extern void WIN_ShowWindowSystemMenu(SDL_Window *window, int x, int y);