diff --git a/include/SDL3/SDL_test_common.h b/include/SDL3/SDL_test_common.h index 5f8a1ffea5..91efe8ac34 100644 --- a/include/SDL3/SDL_test_common.h +++ b/include/SDL3/SDL_test_common.h @@ -87,8 +87,6 @@ typedef struct const char *window_icon; SDL_WindowFlags window_flags; bool flash_on_focus_loss; - SDL_ProgressState progress_state; - float progress_value; int window_x; int window_y; int window_w; diff --git a/include/SDL3/SDL_video.h b/include/SDL3/SDL_video.h index f72e891e39..531cbfa071 100644 --- a/include/SDL3/SDL_video.h +++ b/include/SDL3/SDL_video.h @@ -314,11 +314,12 @@ typedef enum SDL_FlashOperation */ typedef enum SDL_ProgressState { + SDL_PROGRESS_STATE_INVALID = -1, /**< An invalid progress state indicating an error; check SDL_GetError() */ SDL_PROGRESS_STATE_NONE, /**< No progress bar is shown */ SDL_PROGRESS_STATE_INDETERMINATE, /**< The progress bar is shown in a indeterminate state */ SDL_PROGRESS_STATE_NORMAL, /**< The progress bar is shown in a normal state */ SDL_PROGRESS_STATE_PAUSED, /**< The progress bar is shown in a paused state */ - SDL_PROGRESS_STATE_ERROR /**< The progress bar is shown in an error state */ + SDL_PROGRESS_STATE_ERROR /**< The progress bar is shown in a state indicating the application had an error */ } SDL_ProgressState; /** @@ -2835,13 +2836,22 @@ extern SDL_DECLSPEC bool SDLCALL SDL_FlashWindow(SDL_Window *window, SDL_FlashOp */ extern SDL_DECLSPEC bool SDLCALL SDL_SetWindowProgressState(SDL_Window *window, SDL_ProgressState state); +/** +* Get the state of the progress bar for the given window’s taskbar icon. +* +* \param window the window to get the current progress state from. +* \returns the progress state, or SDL_PROGRESS_STATE_INVALID on failure; call +* SDL_GetError() for more information. +* +* \threadsafety This function should only be called on the main thread. +* +* \since This function is available since SDL 3.4.0. +*/ +extern SDL_DECLSPEC SDL_ProgressState SDLCALL SDL_GetWindowProgressState(SDL_Window *window); + /** * Sets the value of the progress bar for the given window’s taskbar icon. * - * If the state is `SDL_PROGRESS_STATE_NONE` or - * `SDL_PROGRESS_STATE_INDETERMINATE`, it gets changed to - * `SDL_PROGRESS_STATE_NORMAL`. - * * \param window the window whose progress value is to be modified. * \param value the progress value (0.0f - start, 1.0f - end). If the value is * outside the valid range, it gets clamped. @@ -2854,6 +2864,19 @@ extern SDL_DECLSPEC bool SDLCALL SDL_SetWindowProgressState(SDL_Window *window, */ extern SDL_DECLSPEC bool SDLCALL SDL_SetWindowProgressValue(SDL_Window *window, float value); +/** +* Get the value of the progress bar for the given window’s taskbar icon. +* +* \param window the window to get the current progress value from. +* \returns the progress value in the range of [0.0 - 1.0], or -1 on +* failure; call SDL_GetError() for more information. +* +* \threadsafety This function should only be called on the main thread. +* +* \since This function is available since SDL 3.4.0. +*/ +extern SDL_DECLSPEC float SDLCALL SDL_GetWindowProgressValue(SDL_Window *window); + /** * Destroy a window. * diff --git a/src/dynapi/SDL_dynapi.sym b/src/dynapi/SDL_dynapi.sym index 8c061ccaed..9f84fbbc91 100644 --- a/src/dynapi/SDL_dynapi.sym +++ b/src/dynapi/SDL_dynapi.sym @@ -1244,6 +1244,8 @@ SDL3_0.0.0 { SDL_DestroyGPURenderState; SDL_SetWindowProgressState; SDL_SetWindowProgressValue; + SDL_GetWindowProgressState; + SDL_GetWindowProgressValue; # extra symbols go here (don't modify this line) local: *; }; diff --git a/src/dynapi/SDL_dynapi_overrides.h b/src/dynapi/SDL_dynapi_overrides.h index d3f218f52a..7ebb71721c 100644 --- a/src/dynapi/SDL_dynapi_overrides.h +++ b/src/dynapi/SDL_dynapi_overrides.h @@ -1269,3 +1269,5 @@ #define SDL_DestroyGPURenderState SDL_DestroyGPURenderState_REAL #define SDL_SetWindowProgressState SDL_SetWindowProgressState_REAL #define SDL_SetWindowProgressValue SDL_SetWindowProgressValue_REAL +#define SDL_GetWindowProgressState SDL_GetWindowProgressState_REAL +#define SDL_GetWindowProgressValue SDL_GetWindowProgressValue_REAL diff --git a/src/dynapi/SDL_dynapi_procs.h b/src/dynapi/SDL_dynapi_procs.h index d9c9ab1f4c..fa12a5815a 100644 --- a/src/dynapi/SDL_dynapi_procs.h +++ b/src/dynapi/SDL_dynapi_procs.h @@ -1277,3 +1277,5 @@ SDL_DYNAPI_PROC(bool,SDL_SetRenderGPUState,(SDL_Renderer *a,SDL_GPURenderState * SDL_DYNAPI_PROC(void,SDL_DestroyGPURenderState,(SDL_GPURenderState *a),(a),) SDL_DYNAPI_PROC(bool,SDL_SetWindowProgressState,(SDL_Window *a,SDL_ProgressState b),(a,b),return) SDL_DYNAPI_PROC(bool,SDL_SetWindowProgressValue,(SDL_Window *a,float b),(a,b),return) +SDL_DYNAPI_PROC(SDL_ProgressState,SDL_GetWindowProgressState,(SDL_Window *a),(a),return) +SDL_DYNAPI_PROC(float,SDL_GetWindowProgressValue,(SDL_Window *a),(a),return) diff --git a/src/test/SDL_test_common.c b/src/test/SDL_test_common.c index f1a3537618..7e46991d49 100644 --- a/src/test/SDL_test_common.c +++ b/src/test/SDL_test_common.c @@ -2460,11 +2460,12 @@ SDL_AppResult SDLTest_CommonEventMainCallbacks(SDLTest_CommonState *state, const /* Ctrl-P Cycle through progress states */ SDL_Window *window = SDL_GetWindowFromEvent(event); if (window) { - state->progress_state += 1; - if (state->progress_state > SDL_PROGRESS_STATE_ERROR) { - state->progress_state = SDL_PROGRESS_STATE_NONE; + float progress_state = SDL_GetWindowProgressState(window); + progress_state += 1; + if (progress_state > SDL_PROGRESS_STATE_ERROR) { + progress_state = SDL_PROGRESS_STATE_NONE; } - SDL_SetWindowProgressState(window, state->progress_state); + SDL_SetWindowProgressState(window, progress_state); } } else if (withControl) @@ -2472,11 +2473,13 @@ SDL_AppResult SDLTest_CommonEventMainCallbacks(SDLTest_CommonState *state, const /* Alt-P Increase progress value */ SDL_Window *window = SDL_GetWindowFromEvent(event); if (window) { - state->progress_value += 0.1f; - if (state->progress_value > 1.f) { - state->progress_value = 0.f; + float progress_value = SDL_GetWindowProgressValue(window); + if (withShift) { + progress_value -= 0.1f; + } else { + progress_value += 0.1f; } - SDL_SetWindowProgressValue(window, state->progress_value); + SDL_SetWindowProgressValue(window, progress_value); } } break; diff --git a/src/video/SDL_sysvideo.h b/src/video/SDL_sysvideo.h index f9b604c4b7..b46e12227a 100644 --- a/src/video/SDL_sysvideo.h +++ b/src/video/SDL_sysvideo.h @@ -304,7 +304,9 @@ struct SDL_VideoDevice 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 (*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 415875ee05..a5d1f3554a 100644 --- a/src/video/SDL_video.c +++ b/src/video/SDL_video.c @@ -3937,6 +3937,18 @@ bool SDL_SetWindowProgressState(SDL_Window *window, SDL_ProgressState state) return SDL_Unsupported(); } +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); + } + + return SDL_Unsupported(); +} + bool SDL_SetWindowProgressValue(SDL_Window *window, float value) { CHECK_WINDOW_MAGIC(window, false); @@ -3951,6 +3963,18 @@ bool SDL_SetWindowProgressValue(SDL_Window *window, float value) return SDL_Unsupported(); } +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); + } + + return SDL_Unsupported(); +} + void SDL_OnWindowShown(SDL_Window *window) { // Set window state if we have pending window flags cached diff --git a/src/video/windows/SDL_windowsevents.c b/src/video/windows/SDL_windowsevents.c index 6caf32ff50..bc11457ccf 100644 --- a/src/video/windows/SDL_windowsevents.c +++ b/src/video/windows/SDL_windowsevents.c @@ -2437,7 +2437,9 @@ 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) { - data->videodata->taskbar_button_created = true; + SDL_Window *window = data->window; + window->internal->taskbar_button_created = true; + WIN_ApplyWindowProgress(window); } #endif diff --git a/src/video/windows/SDL_windowsvideo.c b/src/video/windows/SDL_windowsvideo.c index 3319d05ffc..71bc520d48 100644 --- a/src/video/windows/SDL_windowsvideo.c +++ b/src/video/windows/SDL_windowsvideo.c @@ -273,7 +273,9 @@ static SDL_VideoDevice *WIN_CreateDevice(void) 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->ShowWindowSystemMenu = WIN_ShowWindowSystemMenu; device->SetWindowFocusable = WIN_SetWindowFocusable; device->UpdateWindowShape = WIN_UpdateWindowShape; @@ -591,7 +593,6 @@ void WIN_VideoQuit(SDL_VideoDevice *_this) #endif // !(defined(SDL_PLATFORM_XBOXONE) || defined(SDL_PLATFORM_XBOXSERIES)) #if defined(HAVE_SHOBJIDL_CORE_H) - data->taskbar_button_created = false; if (data->taskbar_list) { IUnknown_Release(data->taskbar_list); data->taskbar_list = NULL; diff --git a/src/video/windows/SDL_windowsvideo.h b/src/video/windows/SDL_windowsvideo.h index 4e985bd9b6..8a0edf5ae0 100644 --- a/src/video/windows/SDL_windowsvideo.h +++ b/src/video/windows/SDL_windowsvideo.h @@ -541,7 +541,6 @@ struct SDL_VideoData #ifdef HAVE_SHOBJIDL_CORE_H UINT WM_TASKBAR_BUTTON_CREATED; - bool taskbar_button_created; ITaskbarList3 *taskbar_list; #endif }; diff --git a/src/video/windows/SDL_windowswindow.c b/src/video/windows/SDL_windowswindow.c index e840d10ba8..755b191053 100644 --- a/src/video/windows/SDL_windowswindow.c +++ b/src/video/windows/SDL_windowswindow.c @@ -188,10 +188,7 @@ static DWORD GetWindowStyleEx(SDL_Window *window) static ITaskbarList3 *GetTaskbarList(SDL_Window* window) { const SDL_WindowData *data = window->internal; - if (!data->videodata->taskbar_button_created) { - SDL_SetError("Missing taskbar button"); - return NULL; - } + SDL_assert(data->taskbar_button_created); if (!data->videodata->taskbar_list) { HRESULT ret = CoCreateInstance(&CLSID_TaskbarList, NULL, CLSCTX_ALL, &IID_ITaskbarList3, (LPVOID *)&data->videodata->taskbar_list); if (FAILED(ret)) { @@ -2248,18 +2245,23 @@ bool WIN_FlashWindow(SDL_VideoDevice *_this, SDL_Window *window, SDL_FlashOperat return true; } -bool WIN_SetWindowProgressState(SDL_VideoDevice *_this, SDL_Window *window, SDL_ProgressState state) +bool WIN_ApplyWindowProgress(SDL_Window* window) { #ifndef HAVE_SHOBJIDL_CORE_H return false; #else + SDL_WindowData *data = window->internal; + if (!data->taskbar_button_created) { + return true; + } + ITaskbarList3 *taskbar_list = GetTaskbarList(window); if (!taskbar_list) { return false; - }; + } TBPFLAG tbpFlags; - switch (state) { + switch (data->progress_state) { case SDL_PROGRESS_STATE_NONE: tbpFlags = TBPF_NOPROGRESS; break; @@ -2279,31 +2281,59 @@ bool WIN_SetWindowProgressState(SDL_VideoDevice *_this, SDL_Window *window, SDL_ return SDL_SetError("Parameter 'state' is not supported"); } - HRESULT ret = taskbar_list->lpVtbl->SetProgressState(taskbar_list, window->internal->hwnd, tbpFlags); + HRESULT ret = taskbar_list->lpVtbl->SetProgressState(taskbar_list, data->hwnd, tbpFlags); if (FAILED(ret)) { 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 (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 false; + return SDL_Unsupported(); #else - ITaskbarList3 *taskbar_list = GetTaskbarList(window); - if (!taskbar_list) { - return false; - }; + window->internal->progress_value = value; + return WIN_ApplyWindowProgress(window); +#endif +} - HRESULT ret = taskbar_list->lpVtbl->SetProgressValue(taskbar_list, window->internal->hwnd, (ULONGLONG)(value * 10000.f), 10000); - if (FAILED(ret)) { - return WIN_SetErrorFromHRESULT("ITaskbarList3::SetProgressValue()", ret); - } - - return true; +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 } diff --git a/src/video/windows/SDL_windowswindow.h b/src/video/windows/SDL_windowswindow.h index 9ec2578f63..449abfe54d 100644 --- a/src/video/windows/SDL_windowswindow.h +++ b/src/video/windows/SDL_windowswindow.h @@ -93,6 +93,9 @@ struct SDL_WindowData WCHAR *ICMFileName; 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; @@ -133,8 +136,11 @@ 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 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);