-
-
Notifications
You must be signed in to change notification settings - Fork 2k
/
Copy pathwin_window.cpp
692 lines (560 loc) · 25.5 KB
/
win_window.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
#include <hex/api/content_registry.hpp>
#include <hex/api/theme_manager.hpp>
#include "window.hpp"
#if defined(OS_WINDOWS)
#include "messaging.hpp"
#include <hex/helpers/utils.hpp>
#include <hex/helpers/logger.hpp>
#include <hex/helpers/default_paths.hpp>
#include <imgui.h>
#include <imgui_internal.h>
#define GLFW_EXPOSE_NATIVE_WIN32
#include <GLFW/glfw3native.h>
#undef GLFW_EXPOSE_NATIVE_WIN32
#include <winbase.h>
#include <winuser.h>
#include <dwmapi.h>
#include <windowsx.h>
#include <shobjidl.h>
#include <wrl/client.h>
#include <fcntl.h>
#include <shellapi.h>
#include <timeapi.h>
#include <VersionHelpers.h>
namespace hex {
template<typename T>
using WinUniquePtr = std::unique_ptr<std::remove_pointer_t<T>, BOOL(*)(T)>;
static LONG_PTR s_oldWndProc;
static float s_titleBarHeight;
static Microsoft::WRL::ComPtr<ITaskbarList4> s_taskbarList;
static bool s_useLayeredWindow = true;
void nativeErrorMessage(const std::string &message) {
log::fatal(message);
MessageBoxA(nullptr, message.c_str(), "Error", MB_ICONERROR | MB_OK);
}
// Custom Window procedure for receiving OS events
static LRESULT commonWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
switch (uMsg) {
case WM_DPICHANGED: {
int interfaceScaleSetting = int(hex::ContentRegistry::Settings::read<float>("hex.builtin.setting.interface", "hex.builtin.setting.interface.scaling_factor", 0.0F) * 10.0F);
if (interfaceScaleSetting != 0)
break;
const auto newScale = LOWORD(wParam) / 96.0F;
const auto oldScale = ImHexApi::System::getNativeScale();
EventDPIChanged::post(oldScale, newScale);
ImHexApi::System::impl::setNativeScale(newScale);
ThemeManager::reapplyCurrentTheme();
ImGui::GetStyle().ScaleAllSizes(newScale);
return TRUE;
}
case WM_COPYDATA: {
// Handle opening files in existing instance
auto message = reinterpret_cast<COPYDATASTRUCT *>(lParam);
if (message == nullptr) break;
ssize_t nullIndex = -1;
auto messageData = static_cast<const char*>(message->lpData);
size_t messageSize = message->cbData;
for (size_t i = 0; i < messageSize; i++) {
if (messageData[i] == '\0') {
nullIndex = i;
break;
}
}
if (nullIndex == -1) {
log::warn("Received invalid forwarded event");
break;
}
std::string eventName(messageData, nullIndex);
std::vector<u8> eventData(messageData + nullIndex + 1, messageData + messageSize);
hex::messaging::messageReceived(eventName, eventData);
break;
}
case WM_SETTINGCHANGE: {
// Handle Windows theme changes
if (lParam == 0) break;
if (reinterpret_cast<const WCHAR*>(lParam) == std::wstring_view(L"ImmersiveColorSet")) {
EventOSThemeChanged::post();
}
break;
}
case WM_SETCURSOR: {
if (LOWORD(lParam) != HTCLIENT) {
return CallWindowProc(reinterpret_cast<WNDPROC>(s_oldWndProc), hwnd, uMsg, wParam, lParam);
} else {
switch (ImGui::GetMouseCursor()) {
case ImGuiMouseCursor_Arrow:
SetCursor(LoadCursor(nullptr, IDC_ARROW));
break;
case ImGuiMouseCursor_Hand:
SetCursor(LoadCursor(nullptr, IDC_HAND));
break;
case ImGuiMouseCursor_ResizeEW:
SetCursor(LoadCursor(nullptr, IDC_SIZEWE));
break;
case ImGuiMouseCursor_ResizeNS:
SetCursor(LoadCursor(nullptr, IDC_SIZENS));
break;
case ImGuiMouseCursor_ResizeNWSE:
SetCursor(LoadCursor(nullptr, IDC_SIZENWSE));
break;
case ImGuiMouseCursor_ResizeNESW:
SetCursor(LoadCursor(nullptr, IDC_SIZENESW));
break;
case ImGuiMouseCursor_ResizeAll:
SetCursor(LoadCursor(nullptr, IDC_SIZEALL));
break;
case ImGuiMouseCursor_NotAllowed:
SetCursor(LoadCursor(nullptr, IDC_NO));
break;
case ImGuiMouseCursor_TextInput:
SetCursor(LoadCursor(nullptr, IDC_IBEAM));
break;
default:
break;
}
return TRUE;
}
}
default:
break;
}
return CallWindowProc(reinterpret_cast<WNDPROC>(s_oldWndProc), hwnd, uMsg, wParam, lParam);
}
// Custom window procedure for borderless window
static LRESULT borderlessWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
switch (uMsg) {
case WM_MOUSELAST:
break;
case WM_NCACTIVATE:
case WM_NCPAINT:
// Handle Windows Aero Snap
return DefWindowProcW(hwnd, uMsg, wParam, lParam);
case WM_NCCALCSIZE: {
// Handle window resizing
RECT &rect = *reinterpret_cast<RECT *>(lParam);
RECT client = rect;
CallWindowProc(reinterpret_cast<WNDPROC>(s_oldWndProc), hwnd, uMsg, wParam, lParam);
if (IsMaximized(hwnd)) {
WINDOWINFO windowInfo = { };
windowInfo.cbSize = sizeof(WINDOWINFO);
GetWindowInfo(hwnd, &windowInfo);
rect = RECT {
.left = static_cast<LONG>(client.left + windowInfo.cyWindowBorders),
.top = static_cast<LONG>(client.top + windowInfo.cyWindowBorders),
.right = static_cast<LONG>(client.right - windowInfo.cyWindowBorders),
.bottom = static_cast<LONG>(client.bottom - windowInfo.cyWindowBorders) + 1
};
} else {
rect = client;
}
// This code tries to avoid DWM flickering when resizing the window
// It's not perfect, but it's really the best we can do.
LARGE_INTEGER performanceFrequency = {};
QueryPerformanceFrequency(&performanceFrequency);
TIMECAPS tc = {};
timeGetDevCaps(&tc, sizeof(tc));
const auto granularity = tc.wPeriodMin;
timeBeginPeriod(tc.wPeriodMin);
DWM_TIMING_INFO dti = {};
dti.cbSize = sizeof(dti);
::DwmGetCompositionTimingInfo(nullptr, &dti);
LARGE_INTEGER end = {};
QueryPerformanceCounter(&end);
const auto period = dti.qpcRefreshPeriod;
const i64 delta = dti.qpcVBlank - end.QuadPart;
i64 sleepTicks = 0;
i64 sleepMilliSeconds = 0;
if (delta >= 0) {
sleepTicks = delta / period;
} else {
sleepTicks = -1 + delta / period;
}
sleepMilliSeconds = delta - (period * sleepTicks);
const double sleepTime = std::round(1000.0 * double(sleepMilliSeconds) / double(performanceFrequency.QuadPart));
if (sleepTime >= 0.0) {
Sleep(DWORD(sleepTime));
}
timeEndPeriod(granularity);
return WVR_REDRAW;
}
case WM_ERASEBKGND:
return 1;
case WM_WINDOWPOSCHANGING: {
// Make sure that windows discards the entire client area when resizing to avoid flickering
const auto windowPos = reinterpret_cast<LPWINDOWPOS>(lParam);
windowPos->flags |= SWP_NOCOPYBITS;
break;
}
case WM_NCHITTEST: {
// Handle window resizing and moving
POINT cursor = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
const POINT border {
static_cast<LONG>((::GetSystemMetrics(SM_CXFRAME) + ::GetSystemMetrics(SM_CXPADDEDBORDER)) * ImHexApi::System::getGlobalScale()),
static_cast<LONG>((::GetSystemMetrics(SM_CYFRAME) + ::GetSystemMetrics(SM_CXPADDEDBORDER)) * ImHexApi::System::getGlobalScale())
};
if (glfwGetWindowMonitor(ImHexApi::System::getMainWindowHandle()) != nullptr) {
return HTCLIENT;
}
RECT window;
if (!::GetWindowRect(hwnd, &window)) {
return HTNOWHERE;
}
constexpr static auto RegionClient = 0b0000;
constexpr static auto RegionLeft = 0b0001;
constexpr static auto RegionRight = 0b0010;
constexpr static auto RegionTop = 0b0100;
constexpr static auto RegionBottom = 0b1000;
const auto result =
RegionLeft * (cursor.x < (window.left + border.x)) |
RegionRight * (cursor.x >= (window.right - border.x)) |
RegionTop * (cursor.y < (window.top + border.y)) |
RegionBottom * (cursor.y >= (window.bottom - border.y));
if (result != 0 && (ImGui::IsAnyItemHovered())) {
break;
}
if (ImGui::IsPopupOpen(nullptr, ImGuiPopupFlags_AnyPopupId)) {
if (result == RegionClient)
return HTCLIENT;
else
return HTCAPTION;
}
std::string_view hoveredWindowName = GImGui->HoveredWindow == nullptr ? "" : GImGui->HoveredWindow->Name;
if (!ImHexApi::System::impl::isWindowResizable()) {
if (result != RegionClient) {
return HTCAPTION;
}
}
switch (result) {
case RegionLeft:
return HTLEFT;
case RegionRight:
return HTRIGHT;
case RegionTop:
return HTTOP;
case RegionBottom:
return HTBOTTOM;
case RegionTop | RegionLeft:
return HTTOPLEFT;
case RegionTop | RegionRight:
return HTTOPRIGHT;
case RegionBottom | RegionLeft:
return HTBOTTOMLEFT;
case RegionBottom | RegionRight:
return HTBOTTOMRIGHT;
case RegionClient:
default:
if (cursor.y < (window.top + s_titleBarHeight * 2)) {
if (hoveredWindowName == "##MainMenuBar" || hoveredWindowName == "ImHexDockSpace") {
if (!ImGui::IsAnyItemHovered()) {
return HTCAPTION;
}
}
}
break;
}
break;
}
default:
break;
}
return commonWindowProc(hwnd, uMsg, wParam, lParam);
}
[[maybe_unused]]
static void reopenConsoleHandle(u32 stdHandleNumber, i32 stdFileDescriptor, FILE *stdStream) {
// Get the Windows handle for the standard stream
HANDLE handle = ::GetStdHandle(stdHandleNumber);
// Redirect the standard stream to the relevant console stream
if (stdFileDescriptor == STDIN_FILENO)
freopen("CONIN$", "rt", stdStream);
else
freopen("CONOUT$", "wt", stdStream);
// Disable buffering
setvbuf(stdStream, nullptr, _IONBF, 0);
// Reopen the standard stream as a file descriptor
auto unboundFd = [stdFileDescriptor, handle]{
if (stdFileDescriptor == STDIN_FILENO)
return _open_osfhandle(intptr_t(handle), _O_RDONLY);
else
return _open_osfhandle(intptr_t(handle), _O_WRONLY);
}();
// Duplicate the file descriptor to the standard stream
dup2(unboundFd, stdFileDescriptor);
}
void enumerateFonts() {
constexpr static auto FontRegistryPath = L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Fonts";
static const std::array RegistryLocations = {
HKEY_LOCAL_MACHINE,
HKEY_CURRENT_USER
};
for (const auto location : RegistryLocations) {
HKEY key;
if (RegOpenKeyExW(location, FontRegistryPath, 0, KEY_READ, &key) != ERROR_SUCCESS) {
continue;
}
DWORD index = 0;
std::wstring valueName(0xFFF, L'\0');
DWORD valueNameSize = valueName.size() * sizeof(wchar_t);
std::wstring valueData(0xFFF, L'\0');
DWORD valueDataSize = valueData.size() * sizeof(wchar_t);
DWORD valueType;
while (RegEnumValueW(key, index, valueName.data(), &valueNameSize, nullptr, &valueType, reinterpret_cast<BYTE *>(valueData.data()), &valueDataSize) == ERROR_SUCCESS) {
if (valueType == REG_SZ) {
auto fontName = hex::utf16ToUtf8(valueName.c_str());
auto fontPath = std::fs::path(valueData);
if (fontPath.is_relative())
fontPath = std::fs::path("C:\\Windows\\Fonts") / fontPath;
registerFont(fontName.c_str(), wolv::util::toUTF8String(fontPath).c_str());
}
valueNameSize = valueName.size();
valueDataSize = valueData.size();
index++;
}
RegCloseKey(key);
}
}
void Window::configureGLFW() {
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0);
glfwWindowHint(GLFW_DECORATED, ImHexApi::System::isBorderlessWindowModeEnabled() ? GL_FALSE : GL_TRUE);
// Windows versions before Windows 10 have issues with transparent framebuffers
// causing the entire window to be slightly transparent ignoring all configurations
if (::IsWindows10OrGreater()) {
glfwWindowHint(GLFW_TRANSPARENT_FRAMEBUFFER, GLFW_TRUE);
} else {
glfwWindowHint(GLFW_TRANSPARENT_FRAMEBUFFER, GLFW_FALSE);
}
}
void Window::initNative() {
if (ImHexApi::System::isDebugBuild()) {
// If the application is running in debug mode, ImHex runs under the CONSOLE subsystem,
// so we don't need to do anything besides enabling ANSI colors
log::impl::enableColorPrinting();
} else if (hex::getEnvironmentVariable("__IMHEX_FORWARD_CONSOLE__") == "1") {
// Check for the __IMHEX_FORWARD_CONSOLE__ environment variable that was set by the forwarder application
// If it's present, attach to its console window
::AttachConsole(ATTACH_PARENT_PROCESS);
// Reopen stdin, stdout and stderr to the console if not in debug mode
reopenConsoleHandle(STD_INPUT_HANDLE, STDIN_FILENO, stdin);
reopenConsoleHandle(STD_OUTPUT_HANDLE, STDOUT_FILENO, stdout);
// Enable ANSI colors in the console
log::impl::enableColorPrinting();
} else {
log::impl::redirectToFile();
}
// Add plugin library folders to dll search path
for (const auto &path : paths::Libraries.read()) {
if (std::fs::exists(path))
AddDllDirectory(path.c_str());
}
enumerateFonts();
}
class DropManager : public IDropTarget {
public:
DropManager() = default;
virtual ~DropManager() = default;
ULONG AddRef() override { return 1; }
ULONG Release() override { return 0; }
HRESULT QueryInterface(REFIID riid, void **ppvObject) override {
if (riid == IID_IDropTarget) {
*ppvObject = this;
return S_OK;
}
*ppvObject = nullptr;
return E_NOINTERFACE;
}
HRESULT STDMETHODCALLTYPE DragEnter(
IDataObject *,
DWORD,
POINTL,
DWORD *pdwEffect) override
{
EventFileDragged::post(true);
*pdwEffect = DROPEFFECT_COPY;
return S_OK;
}
HRESULT STDMETHODCALLTYPE DragOver(
DWORD,
POINTL,
DWORD *pdwEffect) override
{
*pdwEffect = DROPEFFECT_COPY;
return S_OK;
}
HRESULT STDMETHODCALLTYPE DragLeave() override
{
EventFileDragged::post(false);
return S_OK;
}
HRESULT STDMETHODCALLTYPE Drop(
IDataObject *pDataObj,
DWORD,
POINTL,
DWORD *pdwEffect) override
{
FORMATETC fmte = { CF_HDROP, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
STGMEDIUM stgm;
if (SUCCEEDED(pDataObj->GetData(&fmte, &stgm))) {
auto hdrop = HDROP(stgm.hGlobal);
auto fileCount = DragQueryFile(hdrop, 0xFFFFFFFF, nullptr, 0);
for (UINT i = 0; i < fileCount; i++) {
WCHAR szFile[MAX_PATH];
UINT cch = DragQueryFileW(hdrop, i, szFile, MAX_PATH);
if (cch > 0 && cch < MAX_PATH) {
EventFileDropped::post(szFile);
}
}
ReleaseStgMedium(&stgm);
}
EventFileDragged::post(false);
*pdwEffect &= DROPEFFECT_COPY;
return S_OK;
}
};
void Window::setupNativeWindow() {
// Setup borderless window
auto hwnd = glfwGetWin32Window(m_window);
CoInitialize(nullptr);
OleInitialize(nullptr);
static DropManager dm;
if (RegisterDragDrop(hwnd, &dm) != S_OK) {
log::warn("Failed to register drop target");
// Register fallback drop target using glfw
glfwSetDropCallback(m_window, [](GLFWwindow *, int count, const char **paths) {
for (int i = 0; i < count; i++) {
EventFileDropped::post(reinterpret_cast<const char8_t *>(paths[i]));
}
});
}
bool borderlessWindowMode = ImHexApi::System::isBorderlessWindowModeEnabled();
// Set up the correct window procedure based on the borderless window mode state
if (borderlessWindowMode) {
s_oldWndProc = ::SetWindowLongPtr(hwnd, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(borderlessWindowProc));
MARGINS borderless = { 1, 1, 1, 1 };
::DwmExtendFrameIntoClientArea(hwnd, &borderless);
DWORD attribute = DWMNCRP_ENABLED;
::DwmSetWindowAttribute(hwnd, DWMWA_NCRENDERING_POLICY, &attribute, sizeof(attribute));
::SetWindowPos(hwnd, nullptr, 0, 0, 0, 0, SWP_NOZORDER | SWP_NOOWNERZORDER | SWP_FRAMECHANGED | SWP_NOSIZE | SWP_NOMOVE);
} else {
s_oldWndProc = ::SetWindowLongPtr(hwnd, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(commonWindowProc));
}
// Set up a taskbar progress handler
{
if (SUCCEEDED(CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED))) {
CoCreateInstance(CLSID_TaskbarList, nullptr, CLSCTX_INPROC_SERVER, IID_ITaskbarList4, &s_taskbarList);
}
EventSetTaskBarIconState::subscribe([hwnd](u32 state, u32 type, u32 progress){
using enum ImHexApi::System::TaskProgressState;
switch (ImHexApi::System::TaskProgressState(state)) {
case Reset:
s_taskbarList->SetProgressState(hwnd, TBPF_NOPROGRESS);
s_taskbarList->SetProgressValue(hwnd, 0, 0);
break;
case Flash:
FlashWindow(hwnd, true);
break;
case Progress:
s_taskbarList->SetProgressState(hwnd, TBPF_INDETERMINATE);
s_taskbarList->SetProgressValue(hwnd, progress, 100);
break;
}
using enum ImHexApi::System::TaskProgressType;
switch (ImHexApi::System::TaskProgressType(type)) {
case Normal:
s_taskbarList->SetProgressState(hwnd, TBPF_NORMAL);
break;
case Warning:
s_taskbarList->SetProgressState(hwnd, TBPF_PAUSED);
break;
case Error:
s_taskbarList->SetProgressState(hwnd, TBPF_ERROR);
break;
}
});
}
struct ACCENTPOLICY {
u32 accentState;
u32 accentFlags;
u32 gradientColor;
u32 animationId;
};
struct WINCOMPATTRDATA {
int attribute;
PVOID pData;
ULONG dataSize;
};
EventThemeChanged::subscribe([this]{
auto hwnd = glfwGetWin32Window(m_window);
static auto user32Dll = WinUniquePtr<HMODULE>(LoadLibraryA("user32.dll"), FreeLibrary);
if (user32Dll != nullptr) {
using SetWindowCompositionAttributeFunc = BOOL(WINAPI*)(HWND, WINCOMPATTRDATA*);
const auto setWindowCompositionAttribute =
reinterpret_cast<SetWindowCompositionAttributeFunc>(
reinterpret_cast<void*>(
GetProcAddress(user32Dll.get(), "SetWindowCompositionAttribute")
)
);
if (setWindowCompositionAttribute != nullptr) {
ACCENTPOLICY policy = { ImGuiExt::GetCustomStyle().WindowBlur > 0.5F ? 4U : 0U, 0, ImGuiExt::GetCustomColorU32(ImGuiCustomCol_BlurBackground), 0 };
WINCOMPATTRDATA data = { 19, &policy, sizeof(ACCENTPOLICY) };
setWindowCompositionAttribute(hwnd, &data);
}
}
});
RequestChangeTheme::subscribe([this](const std::string &theme) {
auto hwnd = glfwGetWin32Window(m_window);
BOOL value = theme == "Dark" ? TRUE : FALSE;
DwmSetWindowAttribute(hwnd, DWMWA_USE_IMMERSIVE_DARK_MODE, &value, sizeof(value));
});
ImGui::GetIO().ConfigDebugIsDebuggerPresent = ::IsDebuggerPresent();
glfwSetFramebufferSizeCallback(m_window, [](GLFWwindow* window, int width, int height) {
auto *win = static_cast<Window *>(glfwGetWindowUserPointer(window));
win->m_unlockFrameRate = true;
glViewport(0, 0, width, height);
ImHexApi::System::impl::setMainWindowSize(width, height);
});
DwmEnableMMCSS(TRUE);
{
constexpr BOOL value = TRUE;
DwmSetWindowAttribute(hwnd, DWMWA_NCRENDERING_ENABLED, &value, sizeof(value));
}
{
constexpr DWMNCRENDERINGPOLICY value = DWMNCRP_ENABLED;
DwmSetWindowAttribute(hwnd, DWMWA_NCRENDERING_POLICY, &value, sizeof(value));
}
glfwSetWindowRefreshCallback(m_window, [](GLFWwindow *window) {
auto win = static_cast<Window *>(glfwGetWindowUserPointer(window));
win->fullFrame();
DwmFlush();
});
// AMD GPUs seem to have issues with Layered Window rendering. Until we figure out
// why that is or AMD fixes the issue on their side, disable it on these GPUs.
s_useLayeredWindow = ImHexApi::System::getGPUVendor() != "ATI Technologies Inc.";
}
void Window::beginNativeWindowFrame() {
s_titleBarHeight = ImGui::GetCurrentWindowRead()->MenuBarHeight;
// Remove WS_POPUP style from the window to make various window management tools work
auto hwnd = glfwGetWin32Window(m_window);
{
auto style = GetWindowLong(hwnd, GWL_STYLE);
style |= WS_OVERLAPPEDWINDOW;
style &= ~WS_POPUP;
::SetWindowLong(hwnd, GWL_STYLE, style);
}
// Make window composited and layered when supported to eradicate any window flickering that happens while resizing
{
auto style = GetWindowLong(hwnd, GWL_EXSTYLE);
style |= WS_EX_COMPOSITED;
if (s_useLayeredWindow)
style |= WS_EX_LAYERED;
::SetWindowLong(hwnd, GWL_EXSTYLE, style);
}
if (!ImHexApi::System::impl::isWindowResizable()) {
if (glfwGetWindowAttrib(m_window, GLFW_MAXIMIZED) == GLFW_TRUE) {
glfwRestoreWindow(m_window);
}
}
}
void Window::endNativeWindowFrame() {
}
}
#endif