Skip to content

Add progress bar support for Windows #12530

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 11 commits into from
Mar 22, 2025
Merged
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1979,6 +1979,7 @@ elseif(WINDOWS)
check_include_file(audioclient.h HAVE_AUDIOCLIENT_H)
check_include_file(sensorsapi.h HAVE_SENSORSAPI_H)
check_include_file(shellscalingapi.h HAVE_SHELLSCALINGAPI_H)
check_include_file(shobjidl_core.h HAVE_SHOBJIDL_CORE_H)
check_c_source_compiles("
#include <windows.h>
#include <mfapi.h>
Expand Down
1 change: 1 addition & 0 deletions cmake/PreseedMSVCCache.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ if(MSVC)
set(HAVE_MMDEVICEAPI_H "1" CACHE INTERNAL "Have include mmdeviceapi.h")
set(HAVE_SENSORSAPI_H "1" CACHE INTERNAL "Have include sensorsapi.h")
set(HAVE_SHELLSCALINGAPI_H "1" CACHE INTERNAL "Have include shellscalingapi.h")
set(HAVE_SHOBJIDL_CORE_H "1" CACHE INTERNAL "Have include shobjidl_core.h")
set(HAVE_TPCSHRD_H "1" CACHE INTERNAL "Have include tpcshrd.h")
set(HAVE_WIN32_CC "1" CACHE INTERNAL "Test HAVE_WIN32_CC")
set(HAVE_XINPUT_H "1" CACHE INTERNAL "Test HAVE_XINPUT_H")
Expand Down
2 changes: 2 additions & 0 deletions include/SDL3/SDL_test_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,8 @@ 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;
Expand Down
42 changes: 42 additions & 0 deletions include/SDL3/SDL_video.h
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,20 @@ typedef enum SDL_FlashOperation
SDL_FLASH_UNTIL_FOCUSED /**< Flash the window until it gets focus */
} SDL_FlashOperation;

/**
* Window progress state
*
* \since This enum is available since SDL 3.2.8.
*/
typedef enum SDL_ProgressState
{
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_ProgressState;

/**
* An opaque handle to an OpenGL context.
*
Expand Down Expand Up @@ -2806,6 +2820,34 @@ extern SDL_DECLSPEC bool SDLCALL SDL_SetWindowShape(SDL_Window *window, SDL_Surf
*/
extern SDL_DECLSPEC bool SDLCALL SDL_FlashWindow(SDL_Window *window, SDL_FlashOperation operation);

/**
* Sets the state of the progress bar for the given window’s taskbar icon.
*
* \param window the window whose progress state is to be modified.
* \param state the progress state.
* \returns true on success or false 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.2.8.
*/
extern SDL_DECLSPEC bool SDLCALL SDL_SetWindowProgressState(SDL_Window *window, SDL_ProgressState state);

/**
* Sets the value of the progress bar for the given window’s taskbar icon.
*
* \param window the window whose progress value is to be modified.
* \param value the progress value (0.0f - start, 1.0f - end).
* \returns true on success or false 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.2.8.
*/
extern SDL_DECLSPEC bool SDLCALL SDL_SetWindowProgressValue(SDL_Window *window, float value);

/**
* Destroy a window.
*
Expand Down
1 change: 1 addition & 0 deletions include/build_config/SDL_build_config.h.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,7 @@
#cmakedefine HAVE_TPCSHRD_H 1
#cmakedefine HAVE_ROAPI_H 1
#cmakedefine HAVE_SHELLSCALINGAPI_H 1
#cmakedefine HAVE_SHOBJIDL_CORE_H 1

#cmakedefine USE_POSIX_SPAWN 1

Expand Down
3 changes: 3 additions & 0 deletions include/build_config/SDL_build_config_windows.h
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,9 @@ typedef unsigned int uintptr_t;
#if defined(_WIN32_MAXVER) && _WIN32_MAXVER >= 0x0603 /* Windows 8.1 SDK */
#define HAVE_SHELLSCALINGAPI_H 1
#endif
#if defined(_WIN32_MAXVER) && _WIN32_MAXVER >= 0x0601 /* Windows 7 SDK */
#define HAVE_SHOBJIDL_CORE_H 1
#endif
#define HAVE_MMDEVICEAPI_H 1
#define HAVE_AUDIOCLIENT_H 1
#define HAVE_TPCSHRD_H 1
Expand Down
1 change: 1 addition & 0 deletions include/build_config/SDL_build_config_wingdk.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
#define HAVE_D3D11_H 1
#define HAVE_ROAPI_H 1
#define HAVE_SHELLSCALINGAPI_H 1
#define HAVE_SHOBJIDL_CORE_H 1
#define HAVE_MMDEVICEAPI_H 1
#define HAVE_AUDIOCLIENT_H 1
#define HAVE_TPCSHRD_H 1
Expand Down
1 change: 1 addition & 0 deletions include/build_config/SDL_build_config_xbox.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
/*#define HAVE_WINDOWS_GAMING_INPUT_H 1*/
/*#define HAVE_ROAPI_H 1*/
/*#define HAVE_SHELLSCALINGAPI_H 1*/
/*#define HAVE_SHOBJIDL_CORE_H 1*/
#define HAVE_MMDEVICEAPI_H 1
#define HAVE_AUDIOCLIENT_H 1
/*#define HAVE_TPCSHRD_H 1*/
Expand Down
2 changes: 2 additions & 0 deletions src/dynapi/SDL_dynapi.sym
Original file line number Diff line number Diff line change
Expand Up @@ -1242,6 +1242,8 @@ SDL3_0.0.0 {
SDL_SetGPURenderStateFragmentUniforms;
SDL_SetRenderGPUState;
SDL_DestroyGPURenderState;
SDL_SetWindowProgressState;
SDL_SetWindowProgressValue;
# extra symbols go here (don't modify this line)
local: *;
};
2 changes: 2 additions & 0 deletions src/dynapi/SDL_dynapi_overrides.h
Original file line number Diff line number Diff line change
Expand Up @@ -1267,3 +1267,5 @@
#define SDL_SetGPURenderStateFragmentUniforms SDL_SetGPURenderStateFragmentUniforms_REAL
#define SDL_SetRenderGPUState SDL_SetRenderGPUState_REAL
#define SDL_DestroyGPURenderState SDL_DestroyGPURenderState_REAL
#define SDL_SetWindowProgressState SDL_SetWindowProgressState_REAL
#define SDL_SetWindowProgressValue SDL_SetWindowProgressValue_REAL
2 changes: 2 additions & 0 deletions src/dynapi/SDL_dynapi_procs.h
Original file line number Diff line number Diff line change
Expand Up @@ -1275,3 +1275,5 @@ SDL_DYNAPI_PROC(SDL_GPURenderState*,SDL_CreateGPURenderState,(SDL_Renderer *a,SD
SDL_DYNAPI_PROC(bool,SDL_SetGPURenderStateFragmentUniforms,(SDL_GPURenderState *a,Uint32 b,const void *c,Uint32 d),(a,b,c,d),return)
SDL_DYNAPI_PROC(bool,SDL_SetRenderGPUState,(SDL_Renderer *a,SDL_GPURenderState *b),(a,b),return)
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)
25 changes: 25 additions & 0 deletions src/test/SDL_test_common.c
Original file line number Diff line number Diff line change
Expand Up @@ -2455,6 +2455,31 @@ SDL_AppResult SDLTest_CommonEventMainCallbacks(SDLTest_CommonState *state, const
}
}
break;
case SDLK_P:
if (withAlt) {
/* 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;
}
SDL_SetWindowProgressState(window, state->progress_state);
}
}
else if (withControl)
{
/* 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;
}
SDL_SetWindowProgressValue(window, state->progress_value);
}
}
break;
case SDLK_G:
if (withControl) {
/* Ctrl-G toggle mouse grab */
Expand Down
2 changes: 2 additions & 0 deletions src/video/SDL_sysvideo.h
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,8 @@ 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);
bool (*SetWindowProgressValue)(SDL_VideoDevice *_this, SDL_Window *window, float value);
bool (*SetWindowFocusable)(SDL_VideoDevice *_this, SDL_Window *window, bool focusable);
bool (*SyncWindow)(SDL_VideoDevice *_this, SDL_Window *window);

Expand Down
24 changes: 24 additions & 0 deletions src/video/SDL_video.c
Original file line number Diff line number Diff line change
Expand Up @@ -3921,6 +3921,30 @@ bool SDL_FlashWindow(SDL_Window *window, SDL_FlashOperation operation)
return SDL_Unsupported();
}

bool SDL_SetWindowProgressState(SDL_Window *window, SDL_ProgressState state)
{
CHECK_WINDOW_MAGIC(window, false);
CHECK_WINDOW_NOT_POPUP(window, false);

if (_this->SetWindowProgressState) {
return _this->SetWindowProgressState(_this, window, state);
}

return SDL_Unsupported();
}

bool SDL_SetWindowProgressValue(SDL_Window *window, float value)
{
CHECK_WINDOW_MAGIC(window, false);
CHECK_WINDOW_NOT_POPUP(window, false);

if (_this->SetWindowProgressValue) {
return _this->SetWindowProgressValue(_this, window, value);
}

return SDL_Unsupported();
}

void SDL_OnWindowShown(SDL_Window *window)
{
// Set window state if we have pending window flags cached
Expand Down
10 changes: 10 additions & 0 deletions src/video/windows/SDL_windowsevents.c
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,10 @@
#include "wmmsg.h"
#endif

#ifdef HAVE_SHOBJIDL_CORE_H
#include <shobjidl_core.h>
#endif

#ifdef SDL_PLATFORM_GDK
#include "../../core/gdk/SDL_gdk.h"
#endif
Expand Down Expand Up @@ -2431,6 +2435,12 @@ LRESULT CALLBACK WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lPara
#endif // !defined(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES)
}

#ifdef HAVE_SHOBJIDL_CORE_H
if (msg == data->videodata->WM_TASKBAR_BUTTON_CREATED) {
data->videodata->taskbar_button_created = true;
}
#endif

// If there's a window proc, assume it's going to handle messages
if (data->wndproc) {
return CallWindowProc(data->wndproc, hwnd, msg, wParam, lParam);
Expand Down
17 changes: 17 additions & 0 deletions src/video/windows/SDL_windowsvideo.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@
#include "SDL_windowsrawinput.h"
#include "SDL_windowsvulkan.h"

#ifdef HAVE_SHOBJIDL_CORE_H
#include <shobjidl_core.h>
#endif

#ifdef SDL_GDK_TEXTINPUT
#include "../gdk/SDL_gdktextinput.h"
#endif
Expand Down Expand Up @@ -268,6 +272,8 @@ static SDL_VideoDevice *WIN_CreateDevice(void)
device->SetWindowHitTest = WIN_SetWindowHitTest;
device->AcceptDragAndDrop = WIN_AcceptDragAndDrop;
device->FlashWindow = WIN_FlashWindow;
device->SetWindowProgressState = WIN_SetWindowProgressState;
device->SetWindowProgressValue = WIN_SetWindowProgressValue;
device->ShowWindowSystemMenu = WIN_ShowWindowSystemMenu;
device->SetWindowFocusable = WIN_SetWindowFocusable;
device->UpdateWindowShape = WIN_UpdateWindowShape;
Expand Down Expand Up @@ -552,6 +558,9 @@ static bool WIN_VideoInit(SDL_VideoDevice *_this)
#if !defined(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES)
data->_SDL_WAKEUP = RegisterWindowMessageA("_SDL_WAKEUP");
#endif
#if defined(HAVE_SHOBJIDL_CORE_H)
data->WM_TASKBAR_BUTTON_CREATED = RegisterWindowMessageA("TaskbarButtonCreated");
#endif

return true;
}
Expand Down Expand Up @@ -581,6 +590,14 @@ 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;
}
#endif

if (data->coinitialized) {
WIN_CoUninitialize();
data->coinitialized = false;
Expand Down
8 changes: 8 additions & 0 deletions src/video/windows/SDL_windowsvideo.h
Original file line number Diff line number Diff line change
Expand Up @@ -308,6 +308,8 @@ typedef enum PROCESS_DPI_AWARENESS
#include <shellscalingapi.h>
#endif

typedef struct ITaskbarList3 ITaskbarList3;

#ifndef _DPI_AWARENESS_CONTEXTS_

typedef enum DPI_AWARENESS
Expand Down Expand Up @@ -536,6 +538,12 @@ struct SDL_VideoData

BYTE pre_hook_key_state[256];
UINT _SDL_WAKEUP;

#ifdef HAVE_SHOBJIDL_CORE_H
UINT WM_TASKBAR_BUTTON_CREATED;
bool taskbar_button_created;
ITaskbarList3 *taskbar_list;
#endif
};

extern bool g_WindowsEnableMessageLoop;
Expand Down
Loading
Loading