yum-mirror/slang

Making it easier to work with shaders

git clone https://git.yummers.dev/yum-mirror/slang

Ellie HermaszewskaMove switch statement bodies to their own lines (#5493)b118451e3

master
12.6 KiB457 linesraw
1#ifdef _WIN32
2
3#include "../window.h"
4
5#include <windows.h>
6#include <windowsx.h>
7using namespace Slang;
8
9#pragma comment(lib, "Gdi32")
10
11namespace platform
12{
13
14static const wchar_t* kWindowClassName = L"slang-platform-window";
15
16typedef BOOL(WINAPI* EnableNonClientDpiScalingProc)(_In_ HWND hwnd);
17
18class Win32AppContext
19{
20public:
21    static EnableNonClientDpiScalingProc enableNonClientDpiScaling;
22    static RefPtr<Window> mainWindow;
23    static OrderedDictionary<HWND, Window*> windows;
24    static HWND mainWindowHandle;
25    static bool isTerminated;
26    static bool isWindows81OrGreater;
27};
28
29EnableNonClientDpiScalingProc Win32AppContext::enableNonClientDpiScaling = nullptr;
30HWND Win32AppContext::mainWindowHandle = nullptr;
31RefPtr<Window> Win32AppContext::mainWindow;
32OrderedDictionary<HWND, Window*> Win32AppContext::windows;
33bool Win32AppContext::isTerminated = false;
34bool Win32AppContext::isWindows81OrGreater = false;
35
36
37ButtonState::Enum _addButtonState(ButtonState::Enum val, ButtonState::Enum newState)
38{
39    return (ButtonState::Enum)((int)val | (int)newState);
40}
41
42ButtonState::Enum getModifierState()
43{
44    ButtonState::Enum result = ButtonState::Enum::None;
45    if (GetAsyncKeyState(VK_CONTROL))
46        result = _addButtonState(result, ButtonState::Enum::Control);
47    if (GetAsyncKeyState(VK_SHIFT))
48        result = _addButtonState(result, ButtonState::Enum::Shift);
49    if (GetAsyncKeyState(VK_MENU))
50        result = _addButtonState(result, ButtonState::Enum::Alt);
51    return result;
52}
53
54ButtonState::Enum getModifierState(WPARAM wParam)
55{
56    ButtonState::Enum result = ButtonState::Enum::None;
57    if (wParam & MK_CONTROL)
58        result = _addButtonState(result, ButtonState::Enum::Control);
59    if (wParam & MK_MBUTTON)
60        result = _addButtonState(result, ButtonState::Enum::MiddleButton);
61    if (wParam & MK_RBUTTON)
62        result = _addButtonState(result, ButtonState::Enum::RightButton);
63    if (wParam & MK_SHIFT)
64        result = _addButtonState(result, ButtonState::Enum::Shift);
65    if (GetAsyncKeyState(VK_MENU))
66        result = _addButtonState(result, ButtonState::Enum::Alt);
67    return result;
68}
69
70LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
71{
72    bool useDefProc = true;
73    Window* window = nullptr;
74    Win32AppContext::windows.tryGetValue(hWnd, window);
75    switch (message)
76    {
77    case WM_LBUTTONUP:
78    case WM_MBUTTONUP:
79    case WM_RBUTTONUP:
80        {
81            int mx = GET_X_LPARAM(lParam);
82            int my = GET_Y_LPARAM(lParam);
83            bool processed = false;
84            if (window)
85            {
86                window->events.mouseUp(MouseEventArgs{mx, my, 0, getModifierState(wParam)});
87            }
88        }
89        break;
90    case WM_LBUTTONDOWN:
91    case WM_MBUTTONDOWN:
92    case WM_RBUTTONDOWN:
93        {
94            int mx = GET_X_LPARAM(lParam);
95            int my = GET_Y_LPARAM(lParam);
96            bool processed = false;
97            if (window)
98            {
99                window->events.mouseDown(MouseEventArgs{mx, my, 0, getModifierState(wParam)});
100            }
101        }
102        break;
103    case WM_MOUSEMOVE:
104        {
105            int mx = GET_X_LPARAM(lParam);
106            int my = GET_Y_LPARAM(lParam);
107            if (window)
108            {
109                window->events.mouseMove(MouseEventArgs{mx, my, 0, getModifierState(wParam)});
110            }
111        }
112        break;
113    case WM_MOUSEWHEEL:
114        {
115            int delta = GET_WHEEL_DELTA_WPARAM(wParam);
116            if (window)
117            {
118                window->events.mouseMove(MouseEventArgs{0, 0, delta, getModifierState(wParam)});
119            }
120        }
121        break;
122    case WM_CHAR:
123        {
124            if (window)
125            {
126                KeyEventArgs keyEventArgs =
127                    {KeyCode::None, (wchar_t)(wParam), ButtonState::Enum::None, false};
128                window->events.keyPress(keyEventArgs);
129                if (keyEventArgs.cancelEvent)
130                    useDefProc = false;
131            }
132        }
133        break;
134    case WM_KEYDOWN:
135        {
136            if (window)
137            {
138                KeyEventArgs keyEventArgs = {(KeyCode)(wParam), 0, getModifierState(), false};
139                window->events.keyDown(keyEventArgs);
140                if (keyEventArgs.cancelEvent)
141                    useDefProc = false;
142            }
143        }
144        break;
145    case WM_KEYUP:
146        {
147            if (window)
148            {
149                KeyEventArgs keyEventArgs = {(KeyCode)(wParam), 0, getModifierState(), false};
150                window->events.keyUp(keyEventArgs);
151                if (keyEventArgs.cancelEvent)
152                    useDefProc = false;
153            }
154        }
155        break;
156    case WM_SETFOCUS:
157        {
158            if (window)
159            {
160                window->events.focus();
161            }
162        }
163        break;
164    case WM_KILLFOCUS:
165        {
166            if (window)
167            {
168                window->events.lostFocus();
169            }
170        }
171        break;
172    case WM_SIZE:
173        {
174            if (window)
175            {
176                window->events.sizeChanged();
177            }
178        }
179        break;
180    case WM_NCCREATE:
181        {
182            if (Win32AppContext::enableNonClientDpiScaling)
183                Win32AppContext::enableNonClientDpiScaling(hWnd);
184            return DefWindowProc(hWnd, message, wParam, lParam);
185        }
186        break;
187    default:
188        break;
189    }
190    if (message == WM_DESTROY && hWnd == Win32AppContext::mainWindowHandle)
191    {
192        PostQuitMessage(0);
193        return 0;
194    }
195    if (useDefProc)
196        return DefWindowProc(hWnd, message, wParam, lParam);
197    return 0;
198}
199
200void registerWindowClass()
201{
202    WNDCLASSEX wcex;
203
204    wcex.cbSize = sizeof(WNDCLASSEX);
205
206    wcex.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC | CS_DBLCLKS;
207    wcex.lpfnWndProc = WndProc;
208    wcex.cbClsExtra = 0;
209    wcex.cbWndExtra = 0;
210    wcex.hInstance = GetModuleHandle(NULL);
211    wcex.hIcon = 0;
212    wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
213    wcex.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
214    wcex.lpszMenuName = 0;
215    wcex.lpszClassName = kWindowClassName;
216    wcex.hIconSm = 0;
217
218    RegisterClassExW(&wcex);
219}
220
221void unregisterWindowClass()
222{
223    UnregisterClassW(kWindowClassName, GetModuleHandle(NULL));
224}
225
226HRESULT(WINAPI* getDpiForMonitor)
227(void* hmonitor, int dpiType, unsigned int* dpiX, unsigned int* dpiY);
228
229void Application::init()
230{
231    *(FARPROC*)&Win32AppContext::enableNonClientDpiScaling =
232        GetProcAddress(GetModuleHandleA("User32"), "EnableNonClientDpiScaling");
233    void*(WINAPI * RtlGetVersion)(LPOSVERSIONINFOEXW);
234    OSVERSIONINFOEXW osInfo;
235    *(FARPROC*)&RtlGetVersion = GetProcAddress(GetModuleHandleA("ntdll"), "RtlGetVersion");
236
237    if (RtlGetVersion)
238    {
239        osInfo.dwOSVersionInfoSize = sizeof(osInfo);
240        RtlGetVersion(&osInfo);
241        if (osInfo.dwMajorVersion > 8 || (osInfo.dwMajorVersion == 8 && osInfo.dwMinorVersion >= 1))
242            Win32AppContext::isWindows81OrGreater = true;
243    }
244    HRESULT(WINAPI * setProcessDpiAwareness)(int value);
245    *(FARPROC*)&setProcessDpiAwareness =
246        GetProcAddress(GetModuleHandleA("Shcore"), "SetProcessDpiAwareness");
247    *(FARPROC*)&getDpiForMonitor = GetProcAddress(GetModuleHandleA("Shcore"), "GetDpiForMonitor");
248    if (setProcessDpiAwareness)
249    {
250        if (Win32AppContext::isWindows81OrGreater)
251            setProcessDpiAwareness(2); // PROCESS_PER_MONITOR_DPI_AWARE
252        else
253            setProcessDpiAwareness(1); // PROCESS_SYSTEM_DPI_AWARE
254    }
255    registerWindowClass();
256}
257
258void doEventsImpl(bool waitForEvents)
259{
260    int hasMsg = 0;
261    do
262    {
263        MSG msg = {};
264        hasMsg =
265            (waitForEvents ? GetMessage(&msg, NULL, 0, 0) : PeekMessage(&msg, NULL, 0, 0, TRUE));
266        if (hasMsg)
267        {
268            TranslateMessage(&msg);
269            DispatchMessage(&msg);
270        }
271        if (msg.message == WM_QUIT)
272            Win32AppContext::isTerminated = true;
273    } while (!Win32AppContext::isTerminated && hasMsg);
274}
275
276void Application::doEvents()
277{
278    doEventsImpl(false);
279}
280
281void Application::quit()
282{
283    Win32AppContext::isTerminated = true;
284}
285
286void Application::dispose()
287{
288    Win32AppContext::mainWindow = nullptr;
289    Win32AppContext::windows = decltype(Win32AppContext::windows)();
290    unregisterWindowClass();
291}
292
293void Application::run(Window* mainWindow, bool waitForEvents)
294{
295    if (mainWindow)
296    {
297        Win32AppContext::mainWindow = mainWindow;
298        Win32AppContext::mainWindowHandle = (HWND)mainWindow->getNativeHandle().handleValues[0];
299        ShowWindow(Win32AppContext::mainWindowHandle, SW_SHOW);
300        UpdateWindow(Win32AppContext::mainWindowHandle);
301    }
302    while (!Win32AppContext::isTerminated)
303    {
304        doEventsImpl(waitForEvents);
305        if (Win32AppContext::isTerminated)
306            break;
307        if (mainWindow)
308        {
309            mainWindow->events.mainLoop();
310        }
311    }
312}
313
314class Win32PlatformWindow : public Window
315{
316public:
317    HWND handle;
318    DWORD style;
319    bool visible = false;
320    Win32PlatformWindow(const WindowDesc& desc)
321    {
322        DWORD windowExtendedStyle = 0;
323        style = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU;
324        if (desc.style == WindowStyle::Default)
325        {
326            style |= WS_MAXIMIZEBOX | WS_MINIMIZEBOX | WS_THICKFRAME;
327        }
328
329        HINSTANCE instance = (HINSTANCE)GetModuleHandle(0);
330
331        RECT windowRect;
332        windowRect.left = 0;
333        windowRect.top = 0;
334        windowRect.bottom = desc.height;
335        windowRect.right = desc.width;
336        AdjustWindowRect(&windowRect, style, FALSE);
337
338        handle = CreateWindowExW(
339            windowExtendedStyle,
340            (LPWSTR)kWindowClassName,
341            String(desc.title).toWString().begin(),
342            style,
343            CW_USEDEFAULT,
344            0, // x, y
345            windowRect.right,
346            windowRect.bottom,
347            NULL, // parent
348            NULL, // menu
349            instance,
350            NULL);
351        if (handle)
352            Win32AppContext::windows[handle] = this;
353    }
354
355    ~Win32PlatformWindow() { close(); }
356
357    virtual void setClientSize(uint32_t width, uint32_t height) override
358    {
359        RECT currentRect;
360        GetWindowRect(handle, &currentRect);
361
362        RECT windowRect;
363        windowRect.left = currentRect.left;
364        windowRect.top = currentRect.top;
365        windowRect.bottom = height;
366        windowRect.right = width;
367        AdjustWindowRect(&windowRect, style, FALSE);
368
369        MoveWindow(
370            handle,
371            windowRect.left,
372            windowRect.top,
373            windowRect.right - windowRect.left,
374            windowRect.bottom - windowRect.top,
375            FALSE);
376    }
377
378    virtual Rect getClientRect() override
379    {
380        RECT currentRect;
381        GetClientRect(handle, &currentRect);
382        Rect rect;
383        rect.x = currentRect.left;
384        rect.y = currentRect.top;
385        rect.width = currentRect.right - currentRect.left;
386        rect.height = currentRect.bottom - currentRect.top;
387        return rect;
388    }
389
390    virtual void centerScreen() override
391    {
392        RECT screenRect;
393        GetClientRect(GetDesktopWindow(), &screenRect);
394        RECT currentRect;
395        GetWindowRect(handle, &currentRect);
396
397        auto width = currentRect.right - currentRect.left;
398        auto height = currentRect.bottom - currentRect.top;
399
400        auto left = (screenRect.right - width) / 2;
401        auto top = (screenRect.bottom - height) / 2;
402
403        MoveWindow(handle, left, top, width, height, FALSE);
404    }
405
406    virtual void close() override
407    {
408        if (handle)
409        {
410            Win32AppContext::windows.remove(handle);
411        }
412        DestroyWindow(handle);
413        handle = NULL;
414    }
415    virtual bool getFocused() override { return GetFocus() == handle; }
416    virtual bool getVisible() override { return visible; }
417    virtual WindowHandle getNativeHandle() override { return WindowHandle::fromHwnd(handle); }
418    virtual void setText(Slang::String text) override
419    {
420        SetWindowText(handle, text.toWString().begin());
421    }
422    virtual void show() override
423    {
424        ShowWindow(handle, SW_SHOW);
425        visible = true;
426    }
427    virtual void hide() override
428    {
429        ShowWindow(handle, SW_HIDE);
430        visible = false;
431    }
432    virtual int getCurrentDpi() override
433    {
434        int dpi = 96;
435        if (Win32AppContext::isWindows81OrGreater && getDpiForMonitor)
436        {
437            getDpiForMonitor(
438                MonitorFromWindow(handle, MONITOR_DEFAULTTOPRIMARY),
439                0,
440                (UINT*)&dpi,
441                (UINT*)&dpi);
442            return dpi;
443        }
444        dpi = GetDeviceCaps(NULL, LOGPIXELSY);
445        return dpi;
446    }
447};
448
449Window* Application::createWindow(const WindowDesc& desc)
450{
451    return new Win32PlatformWindow(desc);
452}
453
454
455} // namespace platform
456
457#endif