aboutsummaryrefslogtreecommitdiff
path: root/src/graveyard/win32/Win32WindowService.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/graveyard/win32/Win32WindowService.cpp')
-rw-r--r--src/graveyard/win32/Win32WindowService.cpp375
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;
+}
+