Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
stenzek
GitHub Repository: stenzek/duckstation
Path: blob/master/src/updater/win32_progress_callback.cpp
4243 views
1
// SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <[email protected]>
2
// SPDX-License-Identifier: CC-BY-NC-ND-4.0
3
4
#include "win32_progress_callback.h"
5
6
#include "common/log.h"
7
#include "common/string_util.h"
8
9
#include <CommCtrl.h>
10
11
LOG_CHANNEL(Host);
12
13
Win32ProgressCallback::Win32ProgressCallback() : ProgressCallback()
14
{
15
Create();
16
}
17
18
void Win32ProgressCallback::PushState()
19
{
20
ProgressCallback::PushState();
21
}
22
23
void Win32ProgressCallback::PopState()
24
{
25
ProgressCallback::PopState();
26
Redraw(true);
27
}
28
29
void Win32ProgressCallback::SetCancellable(bool cancellable)
30
{
31
ProgressCallback::SetCancellable(cancellable);
32
Redraw(true);
33
}
34
35
void Win32ProgressCallback::SetTitle(const std::string_view title)
36
{
37
SetWindowTextW(m_window_hwnd, StringUtil::UTF8StringToWideString(title).c_str());
38
}
39
40
void Win32ProgressCallback::SetStatusText(const std::string_view text)
41
{
42
ProgressCallback::SetStatusText(text);
43
Redraw(true);
44
}
45
46
void Win32ProgressCallback::SetProgressRange(u32 range)
47
{
48
ProgressCallback::SetProgressRange(range);
49
Redraw(false);
50
}
51
52
void Win32ProgressCallback::SetProgressValue(u32 value)
53
{
54
ProgressCallback::SetProgressValue(value);
55
Redraw(false);
56
}
57
58
bool Win32ProgressCallback::Create()
59
{
60
static const char* CLASS_NAME = "DSWin32ProgressCallbackWindow";
61
static bool class_registered = false;
62
63
if (!class_registered)
64
{
65
InitCommonControls();
66
67
WNDCLASSEX wc = {};
68
wc.cbSize = sizeof(WNDCLASSEX);
69
wc.lpfnWndProc = WndProcThunk;
70
wc.hInstance = GetModuleHandle(nullptr);
71
// wc.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_ICON));
72
// wc.hIconSm = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_ICON));
73
wc.hCursor = LoadCursor(NULL, IDC_WAIT);
74
wc.hbrBackground = (HBRUSH)COLOR_WINDOW;
75
wc.lpszClassName = CLASS_NAME;
76
if (!RegisterClassExA(&wc))
77
{
78
ERROR_LOG("Failed to register window class");
79
return false;
80
}
81
82
class_registered = true;
83
}
84
85
m_window_hwnd =
86
CreateWindowExA(WS_EX_CLIENTEDGE, CLASS_NAME, "Win32ProgressCallback", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT,
87
CW_USEDEFAULT, WINDOW_WIDTH, WINDOW_HEIGHT, nullptr, nullptr, GetModuleHandle(nullptr), this);
88
if (!m_window_hwnd)
89
{
90
ERROR_LOG("Failed to create window");
91
return false;
92
}
93
94
SetWindowLongPtr(m_window_hwnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(this));
95
ShowWindow(m_window_hwnd, SW_SHOW);
96
PumpMessages();
97
return true;
98
}
99
100
void Win32ProgressCallback::Destroy()
101
{
102
if (!m_window_hwnd)
103
return;
104
105
DestroyWindow(m_window_hwnd);
106
m_window_hwnd = {};
107
m_text_hwnd = {};
108
m_progress_hwnd = {};
109
}
110
111
void Win32ProgressCallback::PumpMessages()
112
{
113
MSG msg;
114
while (PeekMessageA(&msg, m_window_hwnd, 0, 0, PM_REMOVE))
115
{
116
TranslateMessage(&msg);
117
DispatchMessageA(&msg);
118
}
119
}
120
121
void Win32ProgressCallback::Redraw(bool force)
122
{
123
const int percent =
124
static_cast<int>((static_cast<float>(m_progress_value) / static_cast<float>(m_progress_range)) * 100.0f);
125
if (percent == m_last_progress_percent && !force)
126
{
127
PumpMessages();
128
return;
129
}
130
131
m_last_progress_percent = percent;
132
133
SendMessageA(m_progress_hwnd, PBM_SETRANGE, 0, MAKELPARAM(0, m_progress_range));
134
SendMessageA(m_progress_hwnd, PBM_SETPOS, static_cast<WPARAM>(m_progress_value), 0);
135
SetWindowTextA(m_text_hwnd, m_status_text.c_str());
136
RedrawWindow(m_text_hwnd, nullptr, nullptr, RDW_INVALIDATE);
137
PumpMessages();
138
}
139
140
LRESULT CALLBACK Win32ProgressCallback::WndProcThunk(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
141
{
142
Win32ProgressCallback* cb;
143
if (msg == WM_CREATE)
144
{
145
const CREATESTRUCTA* cs = reinterpret_cast<CREATESTRUCTA*>(lparam);
146
cb = static_cast<Win32ProgressCallback*>(cs->lpCreateParams);
147
}
148
else
149
{
150
cb = reinterpret_cast<Win32ProgressCallback*>(GetWindowLongPtrA(hwnd, GWLP_USERDATA));
151
}
152
153
return cb->WndProc(hwnd, msg, wparam, lparam);
154
}
155
156
LRESULT CALLBACK Win32ProgressCallback::WndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
157
{
158
switch (msg)
159
{
160
case WM_CREATE:
161
{
162
const CREATESTRUCTA* cs = reinterpret_cast<CREATESTRUCTA*>(lparam);
163
HFONT default_font = reinterpret_cast<HFONT>(GetStockObject(ANSI_VAR_FONT));
164
SendMessageA(hwnd, WM_SETFONT, WPARAM(default_font), TRUE);
165
166
int y = WINDOW_MARGIN;
167
168
m_text_hwnd = CreateWindowExA(0, "Static", nullptr, WS_VISIBLE | WS_CHILD, WINDOW_MARGIN, y, SUBWINDOW_WIDTH, 16,
169
hwnd, nullptr, cs->hInstance, nullptr);
170
SendMessageA(m_text_hwnd, WM_SETFONT, WPARAM(default_font), TRUE);
171
y += 16 + WINDOW_MARGIN;
172
173
m_progress_hwnd = CreateWindowExA(0, PROGRESS_CLASSA, nullptr, WS_VISIBLE | WS_CHILD, WINDOW_MARGIN, y,
174
SUBWINDOW_WIDTH, 32, hwnd, nullptr, cs->hInstance, nullptr);
175
y += 32 + WINDOW_MARGIN;
176
177
m_list_box_hwnd =
178
CreateWindowExA(0, "LISTBOX", nullptr, WS_VISIBLE | WS_CHILD | WS_VSCROLL | WS_HSCROLL | WS_BORDER | LBS_NOSEL,
179
WINDOW_MARGIN, y, SUBWINDOW_WIDTH, 170, hwnd, nullptr, cs->hInstance, nullptr);
180
SendMessageA(m_list_box_hwnd, WM_SETFONT, WPARAM(default_font), TRUE);
181
y += 170;
182
}
183
break;
184
185
default:
186
return DefWindowProcA(hwnd, msg, wparam, lparam);
187
}
188
189
return 0;
190
}
191
192
void Win32ProgressCallback::DisplayError(const std::string_view message)
193
{
194
ERROR_LOG(message);
195
SendMessageW(m_list_box_hwnd, LB_ADDSTRING, 0,
196
reinterpret_cast<LPARAM>(StringUtil::UTF8StringToWideString(message).c_str()));
197
SendMessageW(m_list_box_hwnd, WM_VSCROLL, SB_BOTTOM, 0);
198
PumpMessages();
199
}
200
201
void Win32ProgressCallback::DisplayWarning(const std::string_view message)
202
{
203
WARNING_LOG(message);
204
SendMessageW(m_list_box_hwnd, LB_ADDSTRING, 0,
205
reinterpret_cast<LPARAM>(StringUtil::UTF8StringToWideString(message).c_str()));
206
SendMessageW(m_list_box_hwnd, WM_VSCROLL, SB_BOTTOM, 0);
207
PumpMessages();
208
}
209
210
void Win32ProgressCallback::DisplayInformation(const std::string_view message)
211
{
212
INFO_LOG(message);
213
SendMessageW(m_list_box_hwnd, LB_ADDSTRING, 0,
214
reinterpret_cast<LPARAM>(StringUtil::UTF8StringToWideString(message).c_str()));
215
SendMessageW(m_list_box_hwnd, WM_VSCROLL, SB_BOTTOM, 0);
216
PumpMessages();
217
}
218
219
void Win32ProgressCallback::DisplayDebugMessage(const std::string_view message)
220
{
221
DEV_LOG(message);
222
}
223
224
void Win32ProgressCallback::ModalError(const std::string_view message)
225
{
226
PumpMessages();
227
MessageBoxW(m_window_hwnd, StringUtil::UTF8StringToWideString(message).c_str(), L"Error", MB_ICONERROR | MB_OK);
228
PumpMessages();
229
}
230
231
bool Win32ProgressCallback::ModalConfirmation(const std::string_view message)
232
{
233
PumpMessages();
234
bool result = MessageBoxW(m_window_hwnd, StringUtil::UTF8StringToWideString(message).c_str(), L"Confirmation",
235
MB_ICONQUESTION | MB_YESNO) == IDYES;
236
PumpMessages();
237
return result;
238
}
239
240
void Win32ProgressCallback::ModalInformation(const std::string_view message)
241
{
242
MessageBoxW(m_window_hwnd, StringUtil::UTF8StringToWideString(message).c_str(), L"Information",
243
MB_ICONINFORMATION | MB_OK);
244
}
245
246