diff options
| author | fschildt <florian.schildt@protonmail.com> | 2025-08-22 15:23:11 +0200 | 
|---|---|---|
| committer | fschildt <florian.schildt@protonmail.com> | 2025-10-15 11:33:23 +0200 | 
| commit | 04e4627e6c11254ee6f49edf5feb1b8d711da41a (patch) | |
| tree | e28f2e62d3e1b83f9686cdeb102e3f47379e6793 /src/graveyard/win32/Win32WindowService.cpp | |
Diffstat (limited to 'src/graveyard/win32/Win32WindowService.cpp')
| -rw-r--r-- | src/graveyard/win32/Win32WindowService.cpp | 375 | 
1 files changed, 375 insertions, 0 deletions
diff --git a/src/graveyard/win32/Win32WindowService.cpp b/src/graveyard/win32/Win32WindowService.cpp new file mode 100644 index 0000000..80d17c0 --- /dev/null +++ b/src/graveyard/win32/Win32WindowService.cpp @@ -0,0 +1,375 @@ +#include <stdio.h> + +static DWORD g_main_thread_id; +static PIXELFORMATDESCRIPTOR g_pfd; + +internal LRESULT +win32__window_proc(HWND window, UINT message, WPARAM w_param, LPARAM l_param) +{ +    LRESULT result = 0; +    switch (message) +    { +        case WM_CLOSE: +        case WM_QUIT: +        case WM_CHAR: +        case WM_SIZE: +        { +            PostThreadMessage(g_main_thread_id, message, w_param, l_param); +        } +        break; + +        case WM_KEYDOWN: +        { +            if (w_param >= VK_LEFT && w_param <= VK_DOWN) +            { +                PostThreadMessage(g_main_thread_id, message, w_param, l_param); +            } +            else +            { +                // let windows turn this into a WM_CHAR +                result = DefWindowProcA(window, message, w_param, l_param); +            } +        } +        break; + +        default: +        { +            result = DefWindowProcA(window, message, w_param, l_param); +        } +        break; +    } + +    return result; +} + +internal HWND +win32__create_window(const char *name, int width, int height) +{ +    const char *classname = "win32_window_class"; + +    WNDCLASSEX window_class = {}; +    window_class.style = CS_OWNDC; +    window_class.cbSize = sizeof(window_class); +    window_class.lpfnWndProc = &win32__window_proc; +    window_class.hInstance = GetModuleHandle(NULL); +    window_class.hIcon = LoadIcon(NULL, IDI_APPLICATION); +    window_class.hCursor = LoadCursor(NULL, IDC_ARROW); +    window_class.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH); +    window_class.lpszClassName = classname; +    if (RegisterClassExA(&window_class) == 0) +    { +        printf("RegisterClassEx() failed\n"); +        return 0; +    } + +    HWND window = CreateWindowExA(0, +                                  classname, +                                  name, +                                  WS_OVERLAPPEDWINDOW | WS_VISIBLE, +                                  CW_USEDEFAULT, +                                  CW_USEDEFAULT, +                                  width, +                                  height, +                                  0, +                                  0, +                                  window_class.hInstance, +                                  0); +    if (!window) +    { +        printf("CreateWindowEx() failed\n"); +    } + +    return window; +} + +internal void +win32__destroy_window(HWND window) +{ +    DestroyWindow(window); +} + +internal LRESULT +win32__service_window_proc(HWND window, UINT message, WPARAM w_param, LPARAM l_param) +{ +	LRESULT result = 0; +	switch (message) +	{ +        case Win32WindowService::CREATE_WINDOW: +        { +            Win32WindowSettings *settings = (Win32WindowSettings*)w_param; + +            HWND handle = win32__create_window(settings->name, settings->width, settings->height); +            result = (LRESULT)handle; +        } +        break; + +        case Win32WindowService::DESTROY_WINDOW: +        { +            win32__destroy_window(window); +        } +        break; + +        default: +        { +            result = DefWindowProc(window, message, w_param, l_param); +        } +        break; +	} +	return result; +} + +HWND +win32__create_service_window() +{ +    PIXELFORMATDESCRIPTOR *pfd = &g_pfd; +    memset(pfd, 0, sizeof(PIXELFORMATDESCRIPTOR)); +    pfd->nSize = sizeof(PIXELFORMATDESCRIPTOR); +    pfd->nVersion = 1; +    pfd->dwFlags = PFD_DRAW_TO_WINDOW | PFD_DOUBLEBUFFER; +    pfd->iPixelType = PFD_TYPE_RGBA; +    pfd->cColorBits = 32; +    pfd->cDepthBits = 24; +    pfd->cStencilBits = 8; +    pfd->iLayerType = PFD_MAIN_PLANE; + +    WNDCLASSEX swc = {}; +    swc.style         = CS_OWNDC; +    swc.cbSize        = sizeof(swc); +    swc.lpfnWndProc   = &win32__service_window_proc; +    swc.hInstance     = GetModuleHandle(NULL); +    swc.hIcon         = LoadIcon(NULL, IDI_APPLICATION); +    swc.hCursor       = LoadCursor(NULL, IDC_ARROW); +    swc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH); +    swc.lpszClassName = "win32_service_window_class"; +    if (RegisterClassEx(&swc) == 0) +    { +        printf("RegisterClassEx() failed\n"); +        return 0; +    } + +    const char *name = "win32_service_window"; +    HWND handle = CreateWindowEx(0, +                                 swc.lpszClassName, +                                 name, +                                 0, +                                 CW_USEDEFAULT, +                                 CW_USEDEFAULT, +                                 CW_USEDEFAULT, +                                 CW_USEDEFAULT, +                                 0, +                                 0, +                                 swc.hInstance, +                                 0); +    if (!handle) +    { +        printf("CreateWindowEx() for service window failed\n"); +        return 0; +    } + +    HDC dc = GetDC(handle); +    if (!dc) +    { +        printf("GetDC() for service window failed\n"); +        DestroyWindow(handle); +        return 0; +    } + +    int pixel_format = ChoosePixelFormat(dc, &g_pfd); +    if (pixel_format == 0) +    { +        printf("ChoosePixelFormat() for service window failed\n"); +        DestroyWindow(handle); +        return 0; +    } + +    BOOL pixel_format_set = SetPixelFormat(dc, pixel_format, &g_pfd); +    if (pixel_format_set == FALSE) +    { +        printf("SetPixelFormat() for service window failed\n"); +        DestroyWindow(handle); +        return 0; +    } + +    return handle; +} + +DWORD WINAPI +win32__window_service_thread(LPVOID data) +{ +    Win32WindowService *window_service = (Win32WindowService*)data; + +    // create service window and report back to main thread +    HWND service_window = win32__create_service_window(); +    window_service->m_ServiceWindow = service_window; +    if (!service_window) +    { +        PostThreadMessage(g_main_thread_id, Win32WindowService::SERVICE_WINDOW_NOT_CREATED, 0, 0); +        return 0; +    } +    PostThreadMessage(g_main_thread_id, Win32WindowService::SERVICE_WINDOW_CREATED, 0, 0); + +    // get events for all windows, redirect to service window proc, let it report back +    for (;;) +    { +        MSG message; +        BOOL recvd = GetMessageA(&message, 0, 0, 0); +        if (recvd == -1) +        { +            printf("GetMessage failed\n"); +            return 0; +        } + +        TranslateMessage(&message); +        DispatchMessage(&message); +    } +} + +bool +Win32WindowService::Init() +{ +    DWORD main_thread_id = GetCurrentThreadId(); +    g_main_thread_id = main_thread_id; + +    DWORD tid; +    HANDLE thread = CreateThread(0, 0, win32__window_service_thread, this, 0, &tid); +    if (!thread) +    { +        printf("CreatThread() when starting window manager failed\n"); +        return false; +    } + +    // wait until service window is ready +    for (;;) +    { +        MSG message; +        GetMessageA(&message, 0, 0, 0); + +        if (message.message == Win32WindowService::SERVICE_WINDOW_CREATED) +            return true; +        else if (message.message == Win32WindowService::SERVICE_WINDOW_NOT_CREATED) +            return false; +        else assert(0); +    } +} + +Win32Window * +Win32WindowService::CreateWin32Window(const char *name, int width, int height) +{ +    static int counter = 0; +    assert(counter++ == 0); + +    // let the service (other thread) create the window +    Win32WindowSettings settings = {}; +    settings.name = name; +    settings.width = width; +    settings.height = height; + +    HWND handle = (HWND)SendMessage(m_ServiceWindow, Win32WindowService::CREATE_WINDOW, (WPARAM)&settings, 0); +    if (!handle) return 0; + + +    // do remaining initialization +    HDC dc = GetDC(handle); +    if (!dc) +    { +        printf("GetDC failed\n"); +        return 0; +    } + +    PIXELFORMATDESCRIPTOR *pfd = &g_pfd; +    int pixel_format = ChoosePixelFormat(dc, pfd); +    if (pixel_format == 0) +    { +        printf("ChoosePixelFormat failed\n"); +        return false; +    } + +    BOOL pixel_format_set = SetPixelFormat(dc, pixel_format, &g_pfd); +    if (pixel_format_set == FALSE) +    { +        printf("SetPixelFormat() failed\n"); +        return false; +    } + +    Win32Window *window = new Win32Window(handle, dc); +    if (!window->RecreateOffscreenBuffer(width, height)) +    { +        delete window; +        window = 0; +    } +    return window; +} + +void +Win32WindowService::DestroyWin32Window(Win32Window *window) +{ +    SendMessage(m_ServiceWindow, Win32WindowService::DESTROY_WINDOW, (WPARAM)window, 0); +    delete window; +} + +i32 +Win32WindowService::GetWindowEvents(Win32Window *window, Sys_Event *events, i32 max_event_count) +{ +    i32 event_count = 0; + +    // This receives messages for all windows, so we can only have 1 window atm. +    MSG msg; +    while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE) && event_count < max_event_count) +    { +        Sys_Event *event = events + event_count; +        switch (msg.message) +        { +#define ADD_KEY_EVENT(keycode) \ +    event->type = SYS_EVENT_KEY; \ +    event->key.c = (char)keycode; \ +    event_count += 1; +            case WM_CHAR: +            { +                char keycode = (char)msg.wParam; +                bool is_down = (msg.lParam & (1<<31)) == 0; +                if (is_down) +                { +                    ADD_KEY_EVENT(keycode); +                } +            } +            break; + +            case WM_KEYDOWN: +            { +                if      (msg.wParam == VK_LEFT)  {ADD_KEY_EVENT(SYS_KEY_LEFT)} +                else if (msg.wParam == VK_UP)    {ADD_KEY_EVENT(SYS_KEY_UP)} +                else if (msg.wParam == VK_RIGHT) {ADD_KEY_EVENT(SYS_KEY_RIGHT)} +                else if (msg.wParam == VK_DOWN)  {ADD_KEY_EVENT(SYS_KEY_DOWN)} +                else if (msg.wParam == VK_TAB)   {ADD_KEY_EVENT('\t')} +                else if (msg.wParam == VK_RETURN){ADD_KEY_EVENT('\r')} +                else {} +            } +            break; +#undef ADD_KEY_EVENT + +            case WM_SIZE: +            { +                i32 width = (i32)LOWORD(msg.lParam); +                i32 height = (i32)HIWORD(msg.lParam); +                window->RecreateOffscreenBuffer(width, height); +            } +            break; + +            case WM_CLOSE: +            case WM_QUIT: +            { +                return -1; +            } +            break; + + +            default: +            { +                printf("unhandled window event %d\n", msg.message); +            } +        } +    } + +    return event_count; +} +  | 
