aboutsummaryrefslogtreecommitdiffstats
path: root/src/win.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/win.c')
-rw-r--r--src/win.c1591
1 files changed, 793 insertions, 798 deletions
diff --git a/src/win.c b/src/win.c
index 44033fc..664912b 100644
--- a/src/win.c
+++ b/src/win.c
@@ -32,24 +32,24 @@
#include <wctype.h>
#ifndef WM_MOUSEWHEEL
-# define WM_MOUSEWHEEL 0x020A
+# define WM_MOUSEWHEEL 0x020A
#endif
#ifndef WM_MOUSEHWHEEL
-# define WM_MOUSEHWHEEL 0x020E
+# define WM_MOUSEHWHEEL 0x020E
#endif
#ifndef WHEEL_DELTA
-# define WHEEL_DELTA 120
+# define WHEEL_DELTA 120
#endif
#ifndef GWLP_USERDATA
-# define GWLP_USERDATA (-21)
+# define GWLP_USERDATA (-21)
#endif
-#define PUGL_LOCAL_CLOSE_MSG (WM_USER + 50)
-#define PUGL_LOCAL_MARK_MSG (WM_USER + 51)
+#define PUGL_LOCAL_CLOSE_MSG (WM_USER + 50)
+#define PUGL_LOCAL_MARK_MSG (WM_USER + 51)
#define PUGL_LOCAL_CLIENT_MSG (WM_USER + 52)
-#define PUGL_USER_TIMER_MIN 9470
+#define PUGL_USER_TIMER_MIN 9470
-typedef BOOL (WINAPI *PFN_SetProcessDPIAware)(void);
+typedef BOOL(WINAPI* PFN_SetProcessDPIAware)(void);
LRESULT CALLBACK
wndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
@@ -57,268 +57,267 @@ wndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
static wchar_t*
puglUtf8ToWideChar(const char* const utf8)
{
- const int len = MultiByteToWideChar(CP_UTF8, 0, utf8, -1, NULL, 0);
- if (len > 0) {
- wchar_t* result = (wchar_t*)calloc((size_t)len, sizeof(wchar_t));
- MultiByteToWideChar(CP_UTF8, 0, utf8, -1, result, len);
- return result;
- }
-
- return NULL;
+ const int len = MultiByteToWideChar(CP_UTF8, 0, utf8, -1, NULL, 0);
+ if (len > 0) {
+ wchar_t* result = (wchar_t*)calloc((size_t)len, sizeof(wchar_t));
+ MultiByteToWideChar(CP_UTF8, 0, utf8, -1, result, len);
+ return result;
+ }
+
+ return NULL;
}
static char*
puglWideCharToUtf8(const wchar_t* const wstr, size_t* len)
{
- int n = WideCharToMultiByte(CP_UTF8, 0, wstr, -1, NULL, 0, NULL, NULL);
- if (n > 0) {
- char* result = (char*)calloc((size_t)n, sizeof(char));
- WideCharToMultiByte(CP_UTF8, 0, wstr, -1, result, n, NULL, NULL);
- *len = (size_t)n;
- return result;
- }
-
- return NULL;
+ int n = WideCharToMultiByte(CP_UTF8, 0, wstr, -1, NULL, 0, NULL, NULL);
+ if (n > 0) {
+ char* result = (char*)calloc((size_t)n, sizeof(char));
+ WideCharToMultiByte(CP_UTF8, 0, wstr, -1, result, n, NULL, NULL);
+ *len = (size_t)n;
+ return result;
+ }
+
+ return NULL;
}
static bool
puglRegisterWindowClass(const char* name)
{
- WNDCLASSEX wc = { 0 };
- if (GetClassInfoEx(GetModuleHandle(NULL), name, &wc)) {
- return true; // Already registered
- }
-
- wc.cbSize = sizeof(wc);
- wc.style = CS_OWNDC;
- wc.lpfnWndProc = wndProc;
- wc.hInstance = GetModuleHandle(NULL);
- wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
- wc.hCursor = LoadCursor(NULL, IDC_ARROW);
- wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
- wc.lpszClassName = name;
-
- return RegisterClassEx(&wc);
+ WNDCLASSEX wc = {0};
+ if (GetClassInfoEx(GetModuleHandle(NULL), name, &wc)) {
+ return true; // Already registered
+ }
+
+ wc.cbSize = sizeof(wc);
+ wc.style = CS_OWNDC;
+ wc.lpfnWndProc = wndProc;
+ wc.hInstance = GetModuleHandle(NULL);
+ wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
+ wc.hCursor = LoadCursor(NULL, IDC_ARROW);
+ wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
+ wc.lpszClassName = name;
+
+ return RegisterClassEx(&wc);
}
PuglWorldInternals*
-puglInitWorldInternals(PuglWorldType PUGL_UNUSED(type),
+puglInitWorldInternals(PuglWorldType PUGL_UNUSED(type),
PuglWorldFlags PUGL_UNUSED(flags))
{
- PuglWorldInternals* impl = (PuglWorldInternals*)calloc(
- 1, sizeof(PuglWorldInternals));
- if (!impl) {
- return NULL;
- }
-
- HMODULE user32 = LoadLibrary("user32.dll");
- if (user32) {
- PFN_SetProcessDPIAware SetProcessDPIAware =
- (PFN_SetProcessDPIAware)GetProcAddress(
- user32, "SetProcessDPIAware");
- if (SetProcessDPIAware) {
- SetProcessDPIAware();
- }
-
- FreeLibrary(user32);
- }
-
- LARGE_INTEGER frequency;
- QueryPerformanceFrequency(&frequency);
- impl->timerFrequency = (double)frequency.QuadPart;
-
- return impl;
+ PuglWorldInternals* impl =
+ (PuglWorldInternals*)calloc(1, sizeof(PuglWorldInternals));
+ if (!impl) {
+ return NULL;
+ }
+
+ HMODULE user32 = LoadLibrary("user32.dll");
+ if (user32) {
+ PFN_SetProcessDPIAware SetProcessDPIAware =
+ (PFN_SetProcessDPIAware)GetProcAddress(user32, "SetProcessDPIAware");
+ if (SetProcessDPIAware) {
+ SetProcessDPIAware();
+ }
+
+ FreeLibrary(user32);
+ }
+
+ LARGE_INTEGER frequency;
+ QueryPerformanceFrequency(&frequency);
+ impl->timerFrequency = (double)frequency.QuadPart;
+
+ return impl;
}
void*
puglGetNativeWorld(PuglWorld* PUGL_UNUSED(world))
{
- return GetModuleHandle(NULL);
+ return GetModuleHandle(NULL);
}
PuglInternals*
puglInitViewInternals(void)
{
- return (PuglInternals*)calloc(1, sizeof(PuglInternals));
+ return (PuglInternals*)calloc(1, sizeof(PuglInternals));
}
static PuglStatus
puglPollWinEvents(PuglWorld* world, const double timeout)
{
- (void)world;
-
- if (timeout < 0) {
- WaitMessage();
- } else {
- MsgWaitForMultipleObjects(
- 0, NULL, FALSE, (DWORD)(timeout * 1e3), QS_ALLEVENTS);
- }
- return PUGL_SUCCESS;
+ (void)world;
+
+ if (timeout < 0) {
+ WaitMessage();
+ } else {
+ MsgWaitForMultipleObjects(
+ 0, NULL, FALSE, (DWORD)(timeout * 1e3), QS_ALLEVENTS);
+ }
+ return PUGL_SUCCESS;
}
PuglStatus
puglRealize(PuglView* view)
{
- PuglInternals* impl = view->impl;
- if (impl->hwnd) {
- return PUGL_FAILURE;
- }
-
- // Getting depth from the display mode seems tedious, just set usual values
- if (view->hints[PUGL_RED_BITS] == PUGL_DONT_CARE) {
- view->hints[PUGL_RED_BITS] = 8;
- }
- if (view->hints[PUGL_BLUE_BITS] == PUGL_DONT_CARE) {
- view->hints[PUGL_BLUE_BITS] = 8;
- }
- if (view->hints[PUGL_GREEN_BITS] == PUGL_DONT_CARE) {
- view->hints[PUGL_GREEN_BITS] = 8;
- }
- if (view->hints[PUGL_ALPHA_BITS] == PUGL_DONT_CARE) {
- view->hints[PUGL_ALPHA_BITS] = 8;
- }
-
- // Get refresh rate for resize draw timer
- DEVMODEA devMode = {0};
- EnumDisplaySettingsA(NULL, ENUM_CURRENT_SETTINGS, &devMode);
- view->hints[PUGL_REFRESH_RATE] = (int)devMode.dmDisplayFrequency;
-
- // Register window class if necessary
- if (!puglRegisterWindowClass(view->world->className)) {
- return PUGL_REGISTRATION_FAILED;
- }
-
- if (!view->backend || !view->backend->configure) {
- return PUGL_BAD_BACKEND;
- }
-
- PuglStatus st = PUGL_SUCCESS;
- if ((st = view->backend->configure(view)) ||
- (st = view->backend->create(view))) {
- return st;
- }
-
- if (view->title) {
- puglSetWindowTitle(view, view->title);
- }
-
- view->impl->cursor = LoadCursor(NULL, IDC_ARROW);
-
- puglSetFrame(view, view->frame);
- SetWindowLongPtr(impl->hwnd, GWLP_USERDATA, (LONG_PTR)view);
-
- puglDispatchSimpleEvent(view, PUGL_CREATE);
-
- return PUGL_SUCCESS;
+ PuglInternals* impl = view->impl;
+ if (impl->hwnd) {
+ return PUGL_FAILURE;
+ }
+
+ // Getting depth from the display mode seems tedious, just set usual values
+ if (view->hints[PUGL_RED_BITS] == PUGL_DONT_CARE) {
+ view->hints[PUGL_RED_BITS] = 8;
+ }
+ if (view->hints[PUGL_BLUE_BITS] == PUGL_DONT_CARE) {
+ view->hints[PUGL_BLUE_BITS] = 8;
+ }
+ if (view->hints[PUGL_GREEN_BITS] == PUGL_DONT_CARE) {
+ view->hints[PUGL_GREEN_BITS] = 8;
+ }
+ if (view->hints[PUGL_ALPHA_BITS] == PUGL_DONT_CARE) {
+ view->hints[PUGL_ALPHA_BITS] = 8;
+ }
+
+ // Get refresh rate for resize draw timer
+ DEVMODEA devMode = {0};
+ EnumDisplaySettingsA(NULL, ENUM_CURRENT_SETTINGS, &devMode);
+ view->hints[PUGL_REFRESH_RATE] = (int)devMode.dmDisplayFrequency;
+
+ // Register window class if necessary
+ if (!puglRegisterWindowClass(view->world->className)) {
+ return PUGL_REGISTRATION_FAILED;
+ }
+
+ if (!view->backend || !view->backend->configure) {
+ return PUGL_BAD_BACKEND;
+ }
+
+ PuglStatus st = PUGL_SUCCESS;
+ if ((st = view->backend->configure(view)) ||
+ (st = view->backend->create(view))) {
+ return st;
+ }
+
+ if (view->title) {
+ puglSetWindowTitle(view, view->title);
+ }
+
+ view->impl->cursor = LoadCursor(NULL, IDC_ARROW);
+
+ puglSetFrame(view, view->frame);
+ SetWindowLongPtr(impl->hwnd, GWLP_USERDATA, (LONG_PTR)view);
+
+ puglDispatchSimpleEvent(view, PUGL_CREATE);
+
+ return PUGL_SUCCESS;
}
PuglStatus
puglShow(PuglView* view)
{
- PuglInternals* impl = view->impl;
-
- if (!impl->hwnd) {
- const PuglStatus st = puglRealize(view);
- if (st) {
- return st;
- }
- }
-
- ShowWindow(impl->hwnd, SW_SHOWNORMAL);
- SetFocus(impl->hwnd);
- return PUGL_SUCCESS;
+ PuglInternals* impl = view->impl;
+
+ if (!impl->hwnd) {
+ const PuglStatus st = puglRealize(view);
+ if (st) {
+ return st;
+ }
+ }
+
+ ShowWindow(impl->hwnd, SW_SHOWNORMAL);
+ SetFocus(impl->hwnd);
+ return PUGL_SUCCESS;
}
PuglStatus
puglHide(PuglView* view)
{
- PuglInternals* impl = view->impl;
+ PuglInternals* impl = view->impl;
- ShowWindow(impl->hwnd, SW_HIDE);
- return PUGL_SUCCESS;
+ ShowWindow(impl->hwnd, SW_HIDE);
+ return PUGL_SUCCESS;
}
void
puglFreeViewInternals(PuglView* view)
{
- if (view) {
- if (view->backend) {
- view->backend->destroy(view);
- }
-
- ReleaseDC(view->impl->hwnd, view->impl->hdc);
- DestroyWindow(view->impl->hwnd);
- free(view->impl);
- }
+ if (view) {
+ if (view->backend) {
+ view->backend->destroy(view);
+ }
+
+ ReleaseDC(view->impl->hwnd, view->impl->hdc);
+ DestroyWindow(view->impl->hwnd);
+ free(view->impl);
+ }
}
void
puglFreeWorldInternals(PuglWorld* world)
{
- UnregisterClass(world->className, NULL);
- free(world->impl);
+ UnregisterClass(world->className, NULL);
+ free(world->impl);
}
static PuglKey
keySymToSpecial(WPARAM sym)
{
- // clang-format off
- switch (sym) {
- case VK_F1: return PUGL_KEY_F1;
- case VK_F2: return PUGL_KEY_F2;
- case VK_F3: return PUGL_KEY_F3;
- case VK_F4: return PUGL_KEY_F4;
- case VK_F5: return PUGL_KEY_F5;
- case VK_F6: return PUGL_KEY_F6;
- case VK_F7: return PUGL_KEY_F7;
- case VK_F8: return PUGL_KEY_F8;
- case VK_F9: return PUGL_KEY_F9;
- case VK_F10: return PUGL_KEY_F10;
- case VK_F11: return PUGL_KEY_F11;
- case VK_F12: return PUGL_KEY_F12;
- case VK_BACK: return PUGL_KEY_BACKSPACE;
- case VK_DELETE: return PUGL_KEY_DELETE;
- case VK_LEFT: return PUGL_KEY_LEFT;
- case VK_UP: return PUGL_KEY_UP;
- case VK_RIGHT: return PUGL_KEY_RIGHT;
- case VK_DOWN: return PUGL_KEY_DOWN;
- case VK_PRIOR: return PUGL_KEY_PAGE_UP;
- case VK_NEXT: return PUGL_KEY_PAGE_DOWN;
- case VK_HOME: return PUGL_KEY_HOME;
- case VK_END: return PUGL_KEY_END;
- case VK_INSERT: return PUGL_KEY_INSERT;
- case VK_SHIFT:
- case VK_LSHIFT: return PUGL_KEY_SHIFT_L;
- case VK_RSHIFT: return PUGL_KEY_SHIFT_R;
- case VK_CONTROL:
- case VK_LCONTROL: return PUGL_KEY_CTRL_L;
- case VK_RCONTROL: return PUGL_KEY_CTRL_R;
- case VK_MENU:
- case VK_LMENU: return PUGL_KEY_ALT_L;
- case VK_RMENU: return PUGL_KEY_ALT_R;
- case VK_LWIN: return PUGL_KEY_SUPER_L;
- case VK_RWIN: return PUGL_KEY_SUPER_R;
- case VK_CAPITAL: return PUGL_KEY_CAPS_LOCK;
- case VK_SCROLL: return PUGL_KEY_SCROLL_LOCK;
- case VK_NUMLOCK: return PUGL_KEY_NUM_LOCK;
- case VK_SNAPSHOT: return PUGL_KEY_PRINT_SCREEN;
- case VK_PAUSE: return PUGL_KEY_PAUSE;
- }
- // clang-format on
-
- return (PuglKey)0;
+ // clang-format off
+ switch (sym) {
+ case VK_F1: return PUGL_KEY_F1;
+ case VK_F2: return PUGL_KEY_F2;
+ case VK_F3: return PUGL_KEY_F3;
+ case VK_F4: return PUGL_KEY_F4;
+ case VK_F5: return PUGL_KEY_F5;
+ case VK_F6: return PUGL_KEY_F6;
+ case VK_F7: return PUGL_KEY_F7;
+ case VK_F8: return PUGL_KEY_F8;
+ case VK_F9: return PUGL_KEY_F9;
+ case VK_F10: return PUGL_KEY_F10;
+ case VK_F11: return PUGL_KEY_F11;
+ case VK_F12: return PUGL_KEY_F12;
+ case VK_BACK: return PUGL_KEY_BACKSPACE;
+ case VK_DELETE: return PUGL_KEY_DELETE;
+ case VK_LEFT: return PUGL_KEY_LEFT;
+ case VK_UP: return PUGL_KEY_UP;
+ case VK_RIGHT: return PUGL_KEY_RIGHT;
+ case VK_DOWN: return PUGL_KEY_DOWN;
+ case VK_PRIOR: return PUGL_KEY_PAGE_UP;
+ case VK_NEXT: return PUGL_KEY_PAGE_DOWN;
+ case VK_HOME: return PUGL_KEY_HOME;
+ case VK_END: return PUGL_KEY_END;
+ case VK_INSERT: return PUGL_KEY_INSERT;
+ case VK_SHIFT:
+ case VK_LSHIFT: return PUGL_KEY_SHIFT_L;
+ case VK_RSHIFT: return PUGL_KEY_SHIFT_R;
+ case VK_CONTROL:
+ case VK_LCONTROL: return PUGL_KEY_CTRL_L;
+ case VK_RCONTROL: return PUGL_KEY_CTRL_R;
+ case VK_MENU:
+ case VK_LMENU: return PUGL_KEY_ALT_L;
+ case VK_RMENU: return PUGL_KEY_ALT_R;
+ case VK_LWIN: return PUGL_KEY_SUPER_L;
+ case VK_RWIN: return PUGL_KEY_SUPER_R;
+ case VK_CAPITAL: return PUGL_KEY_CAPS_LOCK;
+ case VK_SCROLL: return PUGL_KEY_SCROLL_LOCK;
+ case VK_NUMLOCK: return PUGL_KEY_NUM_LOCK;
+ case VK_SNAPSHOT: return PUGL_KEY_PRINT_SCREEN;
+ case VK_PAUSE: return PUGL_KEY_PAUSE;
+ }
+ // clang-format on
+
+ return (PuglKey)0;
}
static uint32_t
getModifiers(void)
{
- // clang-format off
- return (((GetKeyState(VK_SHIFT) < 0) ? PUGL_MOD_SHIFT : 0u) |
- ((GetKeyState(VK_CONTROL) < 0) ? PUGL_MOD_CTRL : 0u) |
- ((GetKeyState(VK_MENU) < 0) ? PUGL_MOD_ALT : 0u) |
- ((GetKeyState(VK_LWIN) < 0) ? PUGL_MOD_SUPER : 0u) |
- ((GetKeyState(VK_RWIN) < 0) ? PUGL_MOD_SUPER : 0u));
- // clang-format on
+ // clang-format off
+ return (((GetKeyState(VK_SHIFT) < 0) ? PUGL_MOD_SHIFT : 0u) |
+ ((GetKeyState(VK_CONTROL) < 0) ? PUGL_MOD_CTRL : 0u) |
+ ((GetKeyState(VK_MENU) < 0) ? PUGL_MOD_ALT : 0u) |
+ ((GetKeyState(VK_LWIN) < 0) ? PUGL_MOD_SUPER : 0u) |
+ ((GetKeyState(VK_RWIN) < 0) ? PUGL_MOD_SUPER : 0u));
+ // clang-format on
}
static void
@@ -328,59 +327,59 @@ initMouseEvent(PuglEvent* event,
bool press,
LPARAM lParam)
{
- POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
- ClientToScreen(view->impl->hwnd, &pt);
-
- if (press) {
- SetCapture(view->impl->hwnd);
- } else {
- ReleaseCapture();
- }
-
- event->button.time = GetMessageTime() / 1e3;
- event->button.type = press ? PUGL_BUTTON_PRESS : PUGL_BUTTON_RELEASE;
- event->button.x = GET_X_LPARAM(lParam);
- event->button.y = GET_Y_LPARAM(lParam);
- event->button.xRoot = pt.x;
- event->button.yRoot = pt.y;
- event->button.state = getModifiers();
- event->button.button = (uint32_t)button;
+ POINT pt = {GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)};
+ ClientToScreen(view->impl->hwnd, &pt);
+
+ if (press) {
+ SetCapture(view->impl->hwnd);
+ } else {
+ ReleaseCapture();
+ }
+
+ event->button.time = GetMessageTime() / 1e3;
+ event->button.type = press ? PUGL_BUTTON_PRESS : PUGL_BUTTON_RELEASE;
+ event->button.x = GET_X_LPARAM(lParam);
+ event->button.y = GET_Y_LPARAM(lParam);
+ event->button.xRoot = pt.x;
+ event->button.yRoot = pt.y;
+ event->button.state = getModifiers();
+ event->button.button = (uint32_t)button;
}
static void
initScrollEvent(PuglEvent* event, PuglView* view, LPARAM lParam)
{
- POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
- ScreenToClient(view->impl->hwnd, &pt);
-
- event->scroll.time = GetMessageTime() / 1e3;
- event->scroll.type = PUGL_SCROLL;
- event->scroll.x = pt.x;
- event->scroll.y = pt.y;
- event->scroll.xRoot = GET_X_LPARAM(lParam);
- event->scroll.yRoot = GET_Y_LPARAM(lParam);
- event->scroll.state = getModifiers();
- event->scroll.dx = 0;
- event->scroll.dy = 0;
+ POINT pt = {GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)};
+ ScreenToClient(view->impl->hwnd, &pt);
+
+ event->scroll.time = GetMessageTime() / 1e3;
+ event->scroll.type = PUGL_SCROLL;
+ event->scroll.x = pt.x;
+ event->scroll.y = pt.y;
+ event->scroll.xRoot = GET_X_LPARAM(lParam);
+ event->scroll.yRoot = GET_Y_LPARAM(lParam);
+ event->scroll.state = getModifiers();
+ event->scroll.dx = 0;
+ event->scroll.dy = 0;
}
/// Return the code point for buf, or the replacement character on error
static uint32_t
puglDecodeUTF16(const wchar_t* buf, const int len)
{
- const uint32_t c0 = buf[0];
- const uint32_t c1 = buf[0];
- if (c0 >= 0xD800 && c0 < 0xDC00) {
- if (len < 2) {
- return 0xFFFD; // Surrogate, but length is only 1
- } else if (c1 >= 0xDC00 && c1 <= 0xDFFF) {
- return ((c0 & 0x03FF) << 10) + (c1 & 0x03FF) + 0x10000;
- }
-
- return 0xFFFD; // Unpaired surrogates
- }
-
- return c0;
+ const uint32_t c0 = buf[0];
+ const uint32_t c1 = buf[0];
+ if (c0 >= 0xD800 && c0 < 0xDC00) {
+ if (len < 2) {
+ return 0xFFFD; // Surrogate, but length is only 1
+ } else if (c1 >= 0xDC00 && c1 <= 0xDFFF) {
+ return ((c0 & 0x03FF) << 10) + (c1 & 0x03FF) + 0x10000;
+ }
+
+ return 0xFFFD; // Unpaired surrogates
+ }
+
+ return c0;
}
static void
@@ -390,120 +389,120 @@ initKeyEvent(PuglEventKey* event,
WPARAM wParam,
LPARAM lParam)
{
- POINT rpos = { 0, 0 };
- GetCursorPos(&rpos);
-
- POINT cpos = { rpos.x, rpos.y };
- ScreenToClient(view->impl->hwnd, &rpos);
-
- const unsigned scode = (uint32_t)((lParam & 0xFF0000) >> 16);
- const unsigned vkey = ((wParam == VK_SHIFT)
- ? MapVirtualKey(scode, MAPVK_VSC_TO_VK_EX)
- : (unsigned)wParam);
-
- const unsigned vcode = MapVirtualKey(vkey, MAPVK_VK_TO_VSC);
- const unsigned kchar = MapVirtualKey(vkey, MAPVK_VK_TO_CHAR);
- const bool dead = kchar >> (sizeof(UINT) * 8 - 1) & 1;
- const bool ext = lParam & 0x01000000;
-
- event->type = press ? PUGL_KEY_PRESS : PUGL_KEY_RELEASE;
- event->time = GetMessageTime() / 1e3;
- event->state = getModifiers();
- event->xRoot = rpos.x;
- event->yRoot = rpos.y;
- event->x = cpos.x;
- event->y = cpos.y;
- event->keycode = (uint32_t)((lParam & 0xFF0000) >> 16);
- event->key = 0;
-
- const PuglKey special = keySymToSpecial(vkey);
- if (special) {
- if (ext && (special == PUGL_KEY_CTRL || special == PUGL_KEY_ALT)) {
- event->key = (uint32_t)special + 1u; // Right hand key
- } else {
- event->key = (uint32_t)special;
- }
- } else if (!dead) {
- // Translate unshifted key
- BYTE keyboardState[256] = {0};
- wchar_t buf[5] = {0};
-
- event->key = puglDecodeUTF16(
- buf, ToUnicode(vkey, vcode, keyboardState, buf, 4, 1 << 2));
- }
+ POINT rpos = {0, 0};
+ GetCursorPos(&rpos);
+
+ POINT cpos = {rpos.x, rpos.y};
+ ScreenToClient(view->impl->hwnd, &rpos);
+
+ const unsigned scode = (uint32_t)((lParam & 0xFF0000) >> 16);
+ const unsigned vkey =
+ ((wParam == VK_SHIFT) ? MapVirtualKey(scode, MAPVK_VSC_TO_VK_EX)
+ : (unsigned)wParam);
+
+ const unsigned vcode = MapVirtualKey(vkey, MAPVK_VK_TO_VSC);
+ const unsigned kchar = MapVirtualKey(vkey, MAPVK_VK_TO_CHAR);
+ const bool dead = kchar >> (sizeof(UINT) * 8 - 1) & 1;
+ const bool ext = lParam & 0x01000000;
+
+ event->type = press ? PUGL_KEY_PRESS : PUGL_KEY_RELEASE;
+ event->time = GetMessageTime() / 1e3;
+ event->state = getModifiers();
+ event->xRoot = rpos.x;
+ event->yRoot = rpos.y;
+ event->x = cpos.x;
+ event->y = cpos.y;
+ event->keycode = (uint32_t)((lParam & 0xFF0000) >> 16);
+ event->key = 0;
+
+ const PuglKey special = keySymToSpecial(vkey);
+ if (special) {
+ if (ext && (special == PUGL_KEY_CTRL || special == PUGL_KEY_ALT)) {
+ event->key = (uint32_t)special + 1u; // Right hand key
+ } else {
+ event->key = (uint32_t)special;
+ }
+ } else if (!dead) {
+ // Translate unshifted key
+ BYTE keyboardState[256] = {0};
+ wchar_t buf[5] = {0};
+
+ event->key = puglDecodeUTF16(
+ buf, ToUnicode(vkey, vcode, keyboardState, buf, 4, 1 << 2));
+ }
}
static void
initCharEvent(PuglEvent* event, PuglView* view, WPARAM wParam, LPARAM lParam)
{
- const wchar_t utf16[2] = {wParam & 0xFFFF,
- (wchar_t)((wParam >> 16) & 0xFFFF)};
+ const wchar_t utf16[2] = {wParam & 0xFFFF,
+ (wchar_t)((wParam >> 16) & 0xFFFF)};
- initKeyEvent(&event->key, view, true, wParam, lParam);
- event->type = PUGL_TEXT;
- event->text.character = puglDecodeUTF16(utf16, 2);
+ initKeyEvent(&event->key, view, true, wParam, lParam);
+ event->type = PUGL_TEXT;
+ event->text.character = puglDecodeUTF16(utf16, 2);
- if (!WideCharToMultiByte(
- CP_UTF8, 0, utf16, 2, event->text.string, 8, NULL, NULL)) {
- memset(event->text.string, 0, 8);
- }
+ if (!WideCharToMultiByte(
+ CP_UTF8, 0, utf16, 2, event->text.string, 8, NULL, NULL)) {
+ memset(event->text.string, 0, 8);
+ }
}
static bool
ignoreKeyEvent(PuglView* view, LPARAM lParam)
{
- return view->hints[PUGL_IGNORE_KEY_REPEAT] && (lParam & (1 << 30));
+ return view->hints[PUGL_IGNORE_KEY_REPEAT] && (lParam & (1 << 30));
}
static RECT
handleConfigure(PuglView* view, PuglEvent* event)
{
- RECT rect;
- GetClientRect(view->impl->hwnd, &rect);
- MapWindowPoints(view->impl->hwnd,
- view->parent ? (HWND)view->parent : HWND_DESKTOP,
- (LPPOINT)&rect,
- 2);
-
- const LONG width = rect.right - rect.left;
- const LONG height = rect.bottom - rect.top;
-
- view->frame.x = rect.left;
- view->frame.y = rect.top;
-
- event->configure.type = PUGL_CONFIGURE;
- event->configure.x = view->frame.x;
- event->configure.y = view->frame.y;
- event->configure.width = width;
- event->configure.height = height;
-
- if (view->frame.width != width || view->frame.height != height) {
- view->frame.width = width;
- view->frame.height = height;
- }
-
- return rect;
+ RECT rect;
+ GetClientRect(view->impl->hwnd, &rect);
+ MapWindowPoints(view->impl->hwnd,
+ view->parent ? (HWND)view->parent : HWND_DESKTOP,
+ (LPPOINT)&rect,
+ 2);
+
+ const LONG width = rect.right - rect.left;
+ const LONG height = rect.bottom - rect.top;
+
+ view->frame.x = rect.left;
+ view->frame.y = rect.top;
+
+ event->configure.type = PUGL_CONFIGURE;
+ event->configure.x = view->frame.x;
+ event->configure.y = view->frame.y;
+ event->configure.width = width;
+ event->configure.height = height;
+
+ if (view->frame.width != width || view->frame.height != height) {
+ view->frame.width = width;
+ view->frame.height = height;
+ }
+
+ return rect;
}
static void
handleCrossing(PuglView* view, const PuglEventType type, POINT pos)
{
- POINT root_pos = pos;
- ClientToScreen(view->impl->hwnd, &root_pos);
-
- const PuglEventCrossing ev = {
- type,
- 0,
- GetMessageTime() / 1e3,
- (double)pos.x,
- (double)pos.y,
- (double)root_pos.x,
- (double)root_pos.y,
- getModifiers(),
- PUGL_CROSSING_NORMAL,
- };
-
- puglDispatchEvent(view, (const PuglEvent*)&ev);
+ POINT root_pos = pos;
+ ClientToScreen(view->impl->hwnd, &root_pos);
+
+ const PuglEventCrossing ev = {
+ type,
+ 0,
+ GetMessageTime() / 1e3,
+ (double)pos.x,
+ (double)pos.y,
+ (double)root_pos.x,
+ (double)root_pos.y,
+ getModifiers(),
+ PUGL_CROSSING_NORMAL,
+ };
+
+ puglDispatchEvent(view, (const PuglEvent*)&ev);
}
static void
@@ -511,501 +510,497 @@ constrainAspect(const PuglView* const view,
RECT* const size,
const WPARAM wParam)
{
- const float minA = (float)view->minAspectX / (float)view->minAspectY;
- const float maxA = (float)view->maxAspectX / (float)view->maxAspectY;
- const float w = (float)(size->right - size->left);
- const float h = (float)(size->bottom - size->top);
- const float a = w / h;
-
- switch (wParam) {
- case WMSZ_TOP:
- size->top = (a < minA ? (LONG)((float)size->bottom - w * minA) :
- a > maxA ? (LONG)((float)size->bottom - w * maxA) :
- size->top);
- break;
- case WMSZ_TOPRIGHT:
- case WMSZ_RIGHT:
- case WMSZ_BOTTOMRIGHT:
- size->right = (a < minA ? (LONG)((float)size->left + h * minA) :
- a > maxA ? (LONG)((float)size->left + h * maxA) :
- size->right);
- break;
- case WMSZ_BOTTOM:
- size->bottom = (a < minA ? (LONG)((float)size->top + w * minA) :
- a > maxA ? (LONG)((float)size->top + w * maxA) :
- size->bottom);
- break;
- case WMSZ_BOTTOMLEFT:
- case WMSZ_LEFT:
- case WMSZ_TOPLEFT:
- size->left = (a < minA ? (LONG)((float)size->right - h * minA) :
- a > maxA ? (LONG)((float)size->right - h * maxA) :
- size->left);
- break;
- }
+ const float minA = (float)view->minAspectX / (float)view->minAspectY;
+ const float maxA = (float)view->maxAspectX / (float)view->maxAspectY;
+ const float w = (float)(size->right - size->left);
+ const float h = (float)(size->bottom - size->top);
+ const float a = w / h;
+
+ switch (wParam) {
+ case WMSZ_TOP:
+ size->top = (a < minA ? (LONG)((float)size->bottom - w * minA)
+ : a > maxA ? (LONG)((float)size->bottom - w * maxA)
+ : size->top);
+ break;
+ case WMSZ_TOPRIGHT:
+ case WMSZ_RIGHT:
+ case WMSZ_BOTTOMRIGHT:
+ size->right = (a < minA ? (LONG)((float)size->left + h * minA)
+ : a > maxA ? (LONG)((float)size->left + h * maxA)
+ : size->right);
+ break;
+ case WMSZ_BOTTOM:
+ size->bottom = (a < minA ? (LONG)((float)size->top + w * minA)
+ : a > maxA ? (LONG)((float)size->top + w * maxA)
+ : size->bottom);
+ break;
+ case WMSZ_BOTTOMLEFT:
+ case WMSZ_LEFT:
+ case WMSZ_TOPLEFT:
+ size->left = (a < minA ? (LONG)((float)size->right - h * minA)
+ : a > maxA ? (LONG)((float)size->right - h * maxA)
+ : size->left);
+ break;
+ }
}
static LRESULT
handleMessage(PuglView* view, UINT message, WPARAM wParam, LPARAM lParam)
{
- PuglEvent event = {{PUGL_NOTHING, 0}};
- RECT rect = {0, 0, 0, 0};
- POINT pt = {0, 0};
- MINMAXINFO* mmi = NULL;
- void* dummy_ptr = NULL;
-
- if (InSendMessageEx(dummy_ptr)) {
- event.any.flags |= PUGL_IS_SEND_EVENT;
- }
-
- switch (message) {
- case WM_SETCURSOR:
- if (LOWORD(lParam) == HTCLIENT) {
- SetCursor(view->impl->cursor);
- } else {
- return DefWindowProc(view->impl->hwnd, message, wParam, lParam);
- }
- break;
- case WM_SHOWWINDOW:
- if (wParam) {
- handleConfigure(view, &event);
- puglDispatchEvent(view, &event);
- event.type = PUGL_NOTHING;
-
- RedrawWindow(view->impl->hwnd, NULL, NULL,
- RDW_INVALIDATE|RDW_ALLCHILDREN|RDW_INTERNALPAINT);
- }
-
- if ((bool)wParam != view->visible) {
- view->visible = wParam;
- event.any.type = wParam ? PUGL_MAP : PUGL_UNMAP;
- }
- break;
- case WM_SIZE:
- handleConfigure(view, &event);
- InvalidateRect(view->impl->hwnd, NULL, false);
- break;
- case WM_SIZING:
- if (view->minAspectX) {
- constrainAspect(view, (RECT*)lParam, wParam);
- return TRUE;
- }
- break;
- case WM_ENTERSIZEMOVE:
- case WM_ENTERMENULOOP:
- puglDispatchSimpleEvent(view, PUGL_LOOP_ENTER);
- break;
- case WM_TIMER:
- if (wParam >= PUGL_USER_TIMER_MIN) {
- PuglEvent ev = {{PUGL_TIMER, 0}};
- ev.timer.id = wParam - PUGL_USER_TIMER_MIN;
- puglDispatchEvent(view, &ev);
- }
- break;
- case WM_EXITSIZEMOVE:
- case WM_EXITMENULOOP:
- puglDispatchSimpleEvent(view, PUGL_LOOP_LEAVE);
- break;
- case WM_GETMINMAXINFO:
- mmi = (MINMAXINFO*)lParam;
- mmi->ptMinTrackSize.x = view->minWidth;
- mmi->ptMinTrackSize.y = view->minHeight;
- if (view->maxWidth > 0 && view->maxHeight > 0) {
- mmi->ptMaxTrackSize.x = view->maxWidth;
- mmi->ptMaxTrackSize.y = view->maxHeight;
- }
- break;
- case WM_PAINT:
- GetUpdateRect(view->impl->hwnd, &rect, false);
- event.expose.type = PUGL_EXPOSE;
- event.expose.x = rect.left;
- event.expose.y = rect.top;
- event.expose.width = rect.right - rect.left;
- event.expose.height = rect.bottom - rect.top;
- break;
- case WM_ERASEBKGND:
- return true;
- case WM_MOUSEMOVE:
- pt.x = GET_X_LPARAM(lParam);
- pt.y = GET_Y_LPARAM(lParam);
-
- if (!view->impl->mouseTracked) {
- TRACKMOUSEEVENT tme = {0};
-
- tme.cbSize = sizeof(tme);
- tme.dwFlags = TME_LEAVE;
- tme.hwndTrack = view->impl->hwnd;
- TrackMouseEvent(&tme);
-
- handleCrossing(view, PUGL_POINTER_IN, pt);
- view->impl->mouseTracked = true;
- }
-
- ClientToScreen(view->impl->hwnd, &pt);
- event.motion.type = PUGL_MOTION;
- event.motion.time = GetMessageTime() / 1e3;
- event.motion.x = GET_X_LPARAM(lParam);
- event.motion.y = GET_Y_LPARAM(lParam);
- event.motion.xRoot = pt.x;
- event.motion.yRoot = pt.y;
- event.motion.state = getModifiers();
- break;
- case WM_MOUSELEAVE:
- GetCursorPos(&pt);
- ScreenToClient(view->impl->hwnd, &pt);
- handleCrossing(view, PUGL_POINTER_OUT, pt);
- view->impl->mouseTracked = false;
- break;
- case WM_LBUTTONDOWN:
- initMouseEvent(&event, view, 1, true, lParam);
- break;
- case WM_MBUTTONDOWN:
- initMouseEvent(&event, view, 2, true, lParam);
- break;
- case WM_RBUTTONDOWN:
- initMouseEvent(&event, view, 3, true, lParam);
- break;
- case WM_LBUTTONUP:
- initMouseEvent(&event, view, 1, false, lParam);
- break;
- case WM_MBUTTONUP:
- initMouseEvent(&event, view, 2, false, lParam);
- break;
- case WM_RBUTTONUP:
- initMouseEvent(&event, view, 3, false, lParam);
- break;
- case WM_MOUSEWHEEL:
- initScrollEvent(&event, view, lParam);
- event.scroll.dy = GET_WHEEL_DELTA_WPARAM(wParam) / (double)WHEEL_DELTA;
- event.scroll.direction = (event.scroll.dy > 0
- ? PUGL_SCROLL_UP
- : PUGL_SCROLL_DOWN);
- break;
- case WM_MOUSEHWHEEL:
- initScrollEvent(&event, view, lParam);
- event.scroll.dx = GET_WHEEL_DELTA_WPARAM(wParam) / (double)WHEEL_DELTA;
- event.scroll.direction = (event.scroll.dx > 0
- ? PUGL_SCROLL_RIGHT
- : PUGL_SCROLL_LEFT);
- break;
- case WM_KEYDOWN:
- if (!ignoreKeyEvent(view, lParam)) {
- initKeyEvent(&event.key, view, true, wParam, lParam);
- }
- break;
- case WM_KEYUP:
- initKeyEvent(&event.key, view, false, wParam, lParam);
- break;
- case WM_CHAR:
- initCharEvent(&event, view, wParam, lParam);
- break;
- case WM_SETFOCUS:
- event.type = PUGL_FOCUS_IN;
- break;
- case WM_KILLFOCUS:
- event.type = PUGL_FOCUS_OUT;
- break;
- case WM_SYSKEYDOWN:
- initKeyEvent(&event.key, view, true, wParam, lParam);
- break;
- case WM_SYSKEYUP:
- initKeyEvent(&event.key, view, false, wParam, lParam);
- break;
- case WM_SYSCHAR:
- return TRUE;
- case PUGL_LOCAL_CLIENT_MSG:
- event.client.type = PUGL_CLIENT;
- event.client.data1 = (uintptr_t)wParam;
- event.client.data2 = (uintptr_t)lParam;
- break;
- case WM_QUIT:
- case PUGL_LOCAL_CLOSE_MSG:
- event.any.type = PUGL_CLOSE;
- break;
- default:
- return DefWindowProc(view->impl->hwnd, message, wParam, lParam);
- }
-
- puglDispatchEvent(view, &event);
-
- return 0;
+ PuglEvent event = {{PUGL_NOTHING, 0}};
+ RECT rect = {0, 0, 0, 0};
+ POINT pt = {0, 0};
+ MINMAXINFO* mmi = NULL;
+ void* dummy_ptr = NULL;
+
+ if (InSendMessageEx(dummy_ptr)) {
+ event.any.flags |= PUGL_IS_SEND_EVENT;
+ }
+
+ switch (message) {
+ case WM_SETCURSOR:
+ if (LOWORD(lParam) == HTCLIENT) {
+ SetCursor(view->impl->cursor);
+ } else {
+ return DefWindowProc(view->impl->hwnd, message, wParam, lParam);
+ }
+ break;
+ case WM_SHOWWINDOW:
+ if (wParam) {
+ handleConfigure(view, &event);
+ puglDispatchEvent(view, &event);
+ event.type = PUGL_NOTHING;
+
+ RedrawWindow(view->impl->hwnd,
+ NULL,
+ NULL,
+ RDW_INVALIDATE | RDW_ALLCHILDREN | RDW_INTERNALPAINT);
+ }
+
+ if ((bool)wParam != view->visible) {
+ view->visible = wParam;
+ event.any.type = wParam ? PUGL_MAP : PUGL_UNMAP;
+ }
+ break;
+ case WM_SIZE:
+ handleConfigure(view, &event);
+ InvalidateRect(view->impl->hwnd, NULL, false);
+ break;
+ case WM_SIZING:
+ if (view->minAspectX) {
+ constrainAspect(view, (RECT*)lParam, wParam);
+ return TRUE;
+ }
+ break;
+ case WM_ENTERSIZEMOVE:
+ case WM_ENTERMENULOOP:
+ puglDispatchSimpleEvent(view, PUGL_LOOP_ENTER);
+ break;
+ case WM_TIMER:
+ if (wParam >= PUGL_USER_TIMER_MIN) {
+ PuglEvent ev = {{PUGL_TIMER, 0}};
+ ev.timer.id = wParam - PUGL_USER_TIMER_MIN;
+ puglDispatchEvent(view, &ev);
+ }
+ break;
+ case WM_EXITSIZEMOVE:
+ case WM_EXITMENULOOP:
+ puglDispatchSimpleEvent(view, PUGL_LOOP_LEAVE);
+ break;
+ case WM_GETMINMAXINFO:
+ mmi = (MINMAXINFO*)lParam;
+ mmi->ptMinTrackSize.x = view->minWidth;
+ mmi->ptMinTrackSize.y = view->minHeight;
+ if (view->maxWidth > 0 && view->maxHeight > 0) {
+ mmi->ptMaxTrackSize.x = view->maxWidth;
+ mmi->ptMaxTrackSize.y = view->maxHeight;
+ }
+ break;
+ case WM_PAINT:
+ GetUpdateRect(view->impl->hwnd, &rect, false);
+ event.expose.type = PUGL_EXPOSE;
+ event.expose.x = rect.left;
+ event.expose.y = rect.top;
+ event.expose.width = rect.right - rect.left;
+ event.expose.height = rect.bottom - rect.top;
+ break;
+ case WM_ERASEBKGND:
+ return true;
+ case WM_MOUSEMOVE:
+ pt.x = GET_X_LPARAM(lParam);
+ pt.y = GET_Y_LPARAM(lParam);
+
+ if (!view->impl->mouseTracked) {
+ TRACKMOUSEEVENT tme = {0};
+
+ tme.cbSize = sizeof(tme);
+ tme.dwFlags = TME_LEAVE;
+ tme.hwndTrack = view->impl->hwnd;
+ TrackMouseEvent(&tme);
+
+ handleCrossing(view, PUGL_POINTER_IN, pt);
+ view->impl->mouseTracked = true;
+ }
+
+ ClientToScreen(view->impl->hwnd, &pt);
+ event.motion.type = PUGL_MOTION;
+ event.motion.time = GetMessageTime() / 1e3;
+ event.motion.x = GET_X_LPARAM(lParam);
+ event.motion.y = GET_Y_LPARAM(lParam);
+ event.motion.xRoot = pt.x;
+ event.motion.yRoot = pt.y;
+ event.motion.state = getModifiers();
+ break;
+ case WM_MOUSELEAVE:
+ GetCursorPos(&pt);
+ ScreenToClient(view->impl->hwnd, &pt);
+ handleCrossing(view, PUGL_POINTER_OUT, pt);
+ view->impl->mouseTracked = false;
+ break;
+ case WM_LBUTTONDOWN:
+ initMouseEvent(&event, view, 1, true, lParam);
+ break;
+ case WM_MBUTTONDOWN:
+ initMouseEvent(&event, view, 2, true, lParam);
+ break;
+ case WM_RBUTTONDOWN:
+ initMouseEvent(&event, view, 3, true, lParam);
+ break;
+ case WM_LBUTTONUP:
+ initMouseEvent(&event, view, 1, false, lParam);
+ break;
+ case WM_MBUTTONUP:
+ initMouseEvent(&event, view, 2, false, lParam);
+ break;
+ case WM_RBUTTONUP:
+ initMouseEvent(&event, view, 3, false, lParam);
+ break;
+ case WM_MOUSEWHEEL:
+ initScrollEvent(&event, view, lParam);
+ event.scroll.dy = GET_WHEEL_DELTA_WPARAM(wParam) / (double)WHEEL_DELTA;
+ event.scroll.direction =
+ (event.scroll.dy > 0 ? PUGL_SCROLL_UP : PUGL_SCROLL_DOWN);
+ break;
+ case WM_MOUSEHWHEEL:
+ initScrollEvent(&event, view, lParam);
+ event.scroll.dx = GET_WHEEL_DELTA_WPARAM(wParam) / (double)WHEEL_DELTA;
+ event.scroll.direction =
+ (event.scroll.dx > 0 ? PUGL_SCROLL_RIGHT : PUGL_SCROLL_LEFT);
+ break;
+ case WM_KEYDOWN:
+ if (!ignoreKeyEvent(view, lParam)) {
+ initKeyEvent(&event.key, view, true, wParam, lParam);
+ }
+ break;
+ case WM_KEYUP:
+ initKeyEvent(&event.key, view, false, wParam, lParam);
+ break;
+ case WM_CHAR:
+ initCharEvent(&event, view, wParam, lParam);
+ break;
+ case WM_SETFOCUS:
+ event.type = PUGL_FOCUS_IN;
+ break;
+ case WM_KILLFOCUS:
+ event.type = PUGL_FOCUS_OUT;
+ break;
+ case WM_SYSKEYDOWN:
+ initKeyEvent(&event.key, view, true, wParam, lParam);
+ break;
+ case WM_SYSKEYUP:
+ initKeyEvent(&event.key, view, false, wParam, lParam);
+ break;
+ case WM_SYSCHAR:
+ return TRUE;
+ case PUGL_LOCAL_CLIENT_MSG:
+ event.client.type = PUGL_CLIENT;
+ event.client.data1 = (uintptr_t)wParam;
+ event.client.data2 = (uintptr_t)lParam;
+ break;
+ case WM_QUIT:
+ case PUGL_LOCAL_CLOSE_MSG:
+ event.any.type = PUGL_CLOSE;
+ break;
+ default:
+ return DefWindowProc(view->impl->hwnd, message, wParam, lParam);
+ }
+
+ puglDispatchEvent(view, &event);
+
+ return 0;
}
PuglStatus
puglGrabFocus(PuglView* view)
{
- SetFocus(view->impl->hwnd);
- return PUGL_SUCCESS;
+ SetFocus(view->impl->hwnd);
+ return PUGL_SUCCESS;
}
bool
puglHasFocus(const PuglView* view)
{
- return GetFocus() == view->impl->hwnd;
+ return GetFocus() == view->impl->hwnd;
}
PuglStatus
puglRequestAttention(PuglView* view)
{
- FLASHWINFO info = {sizeof(FLASHWINFO),
- view->impl->hwnd,
- FLASHW_ALL|FLASHW_TIMERNOFG,
- 1,
- 0};
+ FLASHWINFO info = {
+ sizeof(FLASHWINFO), view->impl->hwnd, FLASHW_ALL | FLASHW_TIMERNOFG, 1, 0};
- FlashWindowEx(&info);
+ FlashWindowEx(&info);
- return PUGL_SUCCESS;
+ return PUGL_SUCCESS;
}
PuglStatus
puglStartTimer(PuglView* view, uintptr_t id, double timeout)
{
- const UINT msec = (UINT)floor(timeout * 1000.0);
+ const UINT msec = (UINT)floor(timeout * 1000.0);
- return (SetTimer(view->impl->hwnd, PUGL_USER_TIMER_MIN + id, msec, NULL)
- ? PUGL_SUCCESS
- : PUGL_UNKNOWN_ERROR);
+ return (SetTimer(view->impl->hwnd, PUGL_USER_TIMER_MIN + id, msec, NULL)
+ ? PUGL_SUCCESS
+ : PUGL_UNKNOWN_ERROR);
}
PuglStatus
puglStopTimer(PuglView* view, uintptr_t id)
{
- return (KillTimer(view->impl->hwnd, PUGL_USER_TIMER_MIN + id)
- ? PUGL_SUCCESS
- : PUGL_UNKNOWN_ERROR);
+ return (KillTimer(view->impl->hwnd, PUGL_USER_TIMER_MIN + id)
+ ? PUGL_SUCCESS
+ : PUGL_UNKNOWN_ERROR);
}
PuglStatus
puglSendEvent(PuglView* view, const PuglEvent* event)
{
- if (event->type == PUGL_CLIENT) {
- PostMessage(view->impl->hwnd,
- PUGL_LOCAL_CLIENT_MSG,
- (WPARAM)event->client.data1,
- (LPARAM)event->client.data2);
+ if (event->type == PUGL_CLIENT) {
+ PostMessage(view->impl->hwnd,
+ PUGL_LOCAL_CLIENT_MSG,
+ (WPARAM)event->client.data1,
+ (LPARAM)event->client.data2);
- return PUGL_SUCCESS;
- }
+ return PUGL_SUCCESS;
+ }
- return PUGL_UNSUPPORTED_TYPE;
+ return PUGL_UNSUPPORTED_TYPE;
}
#ifndef PUGL_DISABLE_DEPRECATED
PuglStatus
puglWaitForEvent(PuglView* PUGL_UNUSED(view))
{
- WaitMessage();
- return PUGL_SUCCESS;
+ WaitMessage();
+ return PUGL_SUCCESS;
}
#endif
static PuglStatus
puglDispatchViewEvents(PuglView* view)
{
- /* Windows has no facility to process only currently queued messages, which
- causes the event loop to run forever in cases like mouse movement where
- the queue is constantly being filled with new messages. To work around
- this, we post a message to ourselves before starting, record its time
- when it is received, then break the loop on the first message that was
- created afterwards. */
-
- long markTime = 0;
- MSG msg;
- while (PeekMessage(&msg, view->impl->hwnd, 0, 0, PM_REMOVE)) {
- if (msg.message == PUGL_LOCAL_MARK_MSG) {
- markTime = GetMessageTime();
- } else {
- TranslateMessage(&msg);
- DispatchMessage(&msg);
- if (markTime != 0 && GetMessageTime() > markTime) {
- break;
- }
- }
- }
-
- return PUGL_SUCCESS;
+ /* Windows has no facility to process only currently queued messages, which
+ causes the event loop to run forever in cases like mouse movement where
+ the queue is constantly being filled with new messages. To work around
+ this, we post a message to ourselves before starting, record its time
+ when it is received, then break the loop on the first message that was
+ created afterwards. */
+
+ long markTime = 0;
+ MSG msg;
+ while (PeekMessage(&msg, view->impl->hwnd, 0, 0, PM_REMOVE)) {
+ if (msg.message == PUGL_LOCAL_MARK_MSG) {
+ markTime = GetMessageTime();
+ } else {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ if (markTime != 0 && GetMessageTime() > markTime) {
+ break;
+ }
+ }
+ }
+
+ return PUGL_SUCCESS;
}
static PuglStatus
puglDispatchWinEvents(PuglWorld* world)
{
- for (size_t i = 0; i < world->numViews; ++i) {
- PostMessage(world->views[i]->impl->hwnd, PUGL_LOCAL_MARK_MSG, 0, 0);
- }
+ for (size_t i = 0; i < world->numViews; ++i) {
+ PostMessage(world->views[i]->impl->hwnd, PUGL_LOCAL_MARK_MSG, 0, 0);
+ }
- for (size_t i = 0; i < world->numViews; ++i) {
- puglDispatchViewEvents(world->views[i]);
- }
+ for (size_t i = 0; i < world->numViews; ++i) {
+ puglDispatchViewEvents(world->views[i]);
+ }
- return PUGL_SUCCESS;
+ return PUGL_SUCCESS;
}
PuglStatus
puglUpdate(PuglWorld* world, double timeout)
{
- const double startTime = puglGetTime(world);
- PuglStatus st = PUGL_SUCCESS;
-
- if (timeout < 0.0) {
- st = puglPollWinEvents(world, timeout);
- st = st ? st : puglDispatchWinEvents(world);
- } else if (timeout == 0.0) {
- st = puglDispatchWinEvents(world);
- } else {
- const double endTime = startTime + timeout - 0.001;
- for (double t = startTime; t < endTime; t = puglGetTime(world)) {
- if ((st = puglPollWinEvents(world, endTime - t)) ||
- (st = puglDispatchWinEvents(world))) {
- break;
- }
- }
- }
-
- for (size_t i = 0; i < world->numViews; ++i) {
- if (world->views[i]->visible) {
- puglDispatchSimpleEvent(world->views[i], PUGL_UPDATE);
- }
-
- UpdateWindow(world->views[i]->impl->hwnd);
- }
-
- return st;
+ const double startTime = puglGetTime(world);
+ PuglStatus st = PUGL_SUCCESS;
+
+ if (timeout < 0.0) {
+ st = puglPollWinEvents(world, timeout);
+ st = st ? st : puglDispatchWinEvents(world);
+ } else if (timeout == 0.0) {
+ st = puglDispatchWinEvents(world);
+ } else {
+ const double endTime = startTime + timeout - 0.001;
+ for (double t = startTime; t < endTime; t = puglGetTime(world)) {
+ if ((st = puglPollWinEvents(world, endTime - t)) ||
+ (st = puglDispatchWinEvents(world))) {
+ break;
+ }
+ }
+ }
+
+ for (size_t i = 0; i < world->numViews; ++i) {
+ if (world->views[i]->visible) {
+ puglDispatchSimpleEvent(world->views[i], PUGL_UPDATE);
+ }
+
+ UpdateWindow(world->views[i]->impl->hwnd);
+ }
+
+ return st;
}
#ifndef PUGL_DISABLE_DEPRECATED
PuglStatus
puglProcessEvents(PuglView* view)
{
- return puglUpdate(view->world, 0.0);
+ return puglUpdate(view->world, 0.0);
}
#endif
LRESULT CALLBACK
wndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
- PuglView* view = (PuglView*)GetWindowLongPtr(hwnd, GWLP_USERDATA);
-
- switch (message) {
- case WM_CREATE:
- PostMessage(hwnd, WM_SHOWWINDOW, TRUE, 0);
- return 0;
- case WM_CLOSE:
- PostMessage(hwnd, PUGL_LOCAL_CLOSE_MSG, wParam, lParam);
- return 0;
- case WM_DESTROY:
- return 0;
- default:
- if (view && hwnd == view->impl->hwnd) {
- return handleMessage(view, message, wParam, lParam);
- } else {
- return DefWindowProc(hwnd, message, wParam, lParam);
- }
- }
+ PuglView* view = (PuglView*)GetWindowLongPtr(hwnd, GWLP_USERDATA);
+
+ switch (message) {
+ case WM_CREATE:
+ PostMessage(hwnd, WM_SHOWWINDOW, TRUE, 0);
+ return 0;
+ case WM_CLOSE:
+ PostMessage(hwnd, PUGL_LOCAL_CLOSE_MSG, wParam, lParam);
+ return 0;
+ case WM_DESTROY:
+ return 0;
+ default:
+ if (view && hwnd == view->impl->hwnd) {
+ return handleMessage(view, message, wParam, lParam);
+ } else {
+ return DefWindowProc(hwnd, message, wParam, lParam);
+ }
+ }
}
double
puglGetTime(const PuglWorld* world)
{
- LARGE_INTEGER count;
- QueryPerformanceCounter(&count);
- return ((double)count.QuadPart / world->impl->timerFrequency -
- world->startTime);
+ LARGE_INTEGER count;
+ QueryPerformanceCounter(&count);
+ return ((double)count.QuadPart / world->impl->timerFrequency -
+ world->startTime);
}
PuglStatus
puglPostRedisplay(PuglView* view)
{
- InvalidateRect(view->impl->hwnd, NULL, false);
- return PUGL_SUCCESS;
+ InvalidateRect(view->impl->hwnd, NULL, false);
+ return PUGL_SUCCESS;
}
PuglStatus
puglPostRedisplayRect(PuglView* view, const PuglRect rect)
{
- const RECT r = {(long)floor(rect.x),
- (long)floor(rect.y),
- (long)ceil(rect.x + rect.width),
- (long)ceil(rect.y + rect.height)};
+ const RECT r = {(long)floor(rect.x),
+ (long)floor(rect.y),
+ (long)ceil(rect.x + rect.width),
+ (long)ceil(rect.y + rect.height)};
- InvalidateRect(view->impl->hwnd, &r, false);
+ InvalidateRect(view->impl->hwnd, &r, false);
- return PUGL_SUCCESS;
+ return PUGL_SUCCESS;
}
PuglNativeView
puglGetNativeWindow(PuglView* view)
{
- return (PuglNativeView)view->impl->hwnd;
+ return (PuglNativeView)view->impl->hwnd;
}
PuglStatus
puglSetWindowTitle(PuglView* view, const char* title)
{
- puglSetString(&view->title, title);
+ puglSetString(&view->title, title);
- if (view->impl->hwnd) {
- wchar_t* wtitle = puglUtf8ToWideChar(title);
- if (wtitle) {
- SetWindowTextW(view->impl->hwnd, wtitle);
- free(wtitle);
- }
- }
+ if (view->impl->hwnd) {
+ wchar_t* wtitle = puglUtf8ToWideChar(title);
+ if (wtitle) {
+ SetWindowTextW(view->impl->hwnd, wtitle);
+ free(wtitle);
+ }
+ }
- return PUGL_SUCCESS;
+ return PUGL_SUCCESS;
}
PuglStatus
puglSetFrame(PuglView* view, const PuglRect frame)
{
- view->frame = frame;
-
- if (view->impl->hwnd) {
- RECT rect = { (long)frame.x,
- (long)frame.y,
- (long)frame.x + (long)frame.width,
- (long)frame.y + (long)frame.height };
-
- AdjustWindowRectEx(&rect, puglWinGetWindowFlags(view),
- FALSE,
- puglWinGetWindowExFlags(view));
-
- if (!SetWindowPos(view->impl->hwnd,
- HWND_TOP,
- rect.left,
- rect.top,
- rect.right - rect.left,
- rect.bottom - rect.top,
- SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOZORDER)) {
- return PUGL_UNKNOWN_ERROR;
- }
- }
-
- return PUGL_SUCCESS;
+ view->frame = frame;
+
+ if (view->impl->hwnd) {
+ RECT rect = {(long)frame.x,
+ (long)frame.y,
+ (long)frame.x + (long)frame.width,
+ (long)frame.y + (long)frame.height};
+
+ AdjustWindowRectEx(
+ &rect, puglWinGetWindowFlags(view), FALSE, puglWinGetWindowExFlags(view));
+
+ if (!SetWindowPos(view->impl->hwnd,
+ HWND_TOP,
+ rect.left,
+ rect.top,
+ rect.right - rect.left,
+ rect.bottom - rect.top,
+ SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOZORDER)) {
+ return PUGL_UNKNOWN_ERROR;
+ }
+ }
+
+ return PUGL_SUCCESS;
}
PuglStatus
puglSetDefaultSize(PuglView* const view, const int width, const int height)
{
- view->defaultWidth = width;
- view->defaultHeight = height;
- return PUGL_SUCCESS;
+ view->defaultWidth = width;
+ view->defaultHeight = height;
+ return PUGL_SUCCESS;
}
PuglStatus
puglSetMinSize(PuglView* const view, const int width, const int height)
{
- view->minWidth = width;
- view->minHeight = height;
- return PUGL_SUCCESS;
+ view->minWidth = width;
+ view->minHeight = height;
+ return PUGL_SUCCESS;
}
PuglStatus
puglSetMaxSize(PuglView* const view, const int width, const int height)
{
- view->maxWidth = width;
- view->maxHeight = height;
- return PUGL_SUCCESS;
+ view->maxWidth = width;
+ view->maxHeight = height;
+ return PUGL_SUCCESS;
}
PuglStatus
@@ -1015,28 +1010,28 @@ puglSetAspectRatio(PuglView* const view,
const int maxX,
const int maxY)
{
- view->minAspectX = minX;
- view->minAspectY = minY;
- view->maxAspectX = maxX;
- view->maxAspectY = maxY;
- return PUGL_SUCCESS;
+ view->minAspectX = minX;
+ view->minAspectY = minY;
+ view->maxAspectX = maxX;
+ view->maxAspectY = maxY;
+ return PUGL_SUCCESS;
}
PuglStatus
puglSetTransientFor(PuglView* view, PuglNativeView parent)
{
- if (view->parent) {
- return PUGL_FAILURE;
- }
+ if (view->parent) {
+ return PUGL_FAILURE;
+ }
- view->transientParent = parent;
+ view->transientParent = parent;
- if (view->impl->hwnd) {
- SetWindowLongPtr(view->impl->hwnd, GWLP_HWNDPARENT, (LONG_PTR)parent);
- return GetLastError() == NO_ERROR ? PUGL_SUCCESS : PUGL_FAILURE;
- }
+ if (view->impl->hwnd) {
+ SetWindowLongPtr(view->impl->hwnd, GWLP_HWNDPARENT, (LONG_PTR)parent);
+ return GetLastError() == NO_ERROR ? PUGL_SUCCESS : PUGL_FAILURE;
+ }
- return PUGL_SUCCESS;
+ return PUGL_SUCCESS;
}
const void*
@@ -1044,26 +1039,26 @@ puglGetClipboard(PuglView* const view,
const char** const type,
size_t* const len)
{
- PuglInternals* const impl = view->impl;
-
- if (!IsClipboardFormatAvailable(CF_UNICODETEXT) ||
- !OpenClipboard(impl->hwnd)) {
- return NULL;
- }
-
- HGLOBAL mem = GetClipboardData(CF_UNICODETEXT);
- wchar_t* wstr = mem ? (wchar_t*)GlobalLock(mem) : NULL;
- if (!wstr) {
- CloseClipboard();
- return NULL;
- }
-
- free(view->clipboard.data);
- view->clipboard.data = puglWideCharToUtf8(wstr, &view->clipboard.len);
- GlobalUnlock(mem);
- CloseClipboard();
-
- return puglGetInternalClipboard(view, type, len);
+ PuglInternals* const impl = view->impl;
+
+ if (!IsClipboardFormatAvailable(CF_UNICODETEXT) ||
+ !OpenClipboard(impl->hwnd)) {
+ return NULL;
+ }
+
+ HGLOBAL mem = GetClipboardData(CF_UNICODETEXT);
+ wchar_t* wstr = mem ? (wchar_t*)GlobalLock(mem) : NULL;
+ if (!wstr) {
+ CloseClipboard();
+ return NULL;
+ }
+
+ free(view->clipboard.data);
+ view->clipboard.data = puglWideCharToUtf8(wstr, &view->clipboard.len);
+ GlobalUnlock(mem);
+ CloseClipboard();
+
+ return puglGetInternalClipboard(view, type, len);
}
PuglStatus
@@ -1072,72 +1067,72 @@ puglSetClipboard(PuglView* const view,
const void* const data,
const size_t len)
{
- PuglInternals* const impl = view->impl;
-
- PuglStatus st = puglSetInternalClipboard(view, type, data, len);
- if (st) {
- return st;
- } else if (!OpenClipboard(impl->hwnd)) {
- return PUGL_UNKNOWN_ERROR;
- }
-
- // Measure string and allocate global memory for clipboard
- const char* str = (const char*)data;
- const int wlen = MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0);
- HGLOBAL mem = GlobalAlloc(GMEM_MOVEABLE,
- (size_t)(wlen + 1) * sizeof(wchar_t));
- if (!mem) {
- CloseClipboard();
- return PUGL_UNKNOWN_ERROR;
- }
-
- // Lock global memory
- wchar_t* wstr = (wchar_t*)GlobalLock(mem);
- if (!wstr) {
- GlobalFree(mem);
- CloseClipboard();
- return PUGL_UNKNOWN_ERROR;
- }
-
- // Convert string into global memory and set it as clipboard data
- MultiByteToWideChar(CP_UTF8, 0, str, (int)len, wstr, wlen);
- wstr[wlen] = 0;
- GlobalUnlock(mem);
- SetClipboardData(CF_UNICODETEXT, mem);
- CloseClipboard();
- return PUGL_SUCCESS;
+ PuglInternals* const impl = view->impl;
+
+ PuglStatus st = puglSetInternalClipboard(view, type, data, len);
+ if (st) {
+ return st;
+ } else if (!OpenClipboard(impl->hwnd)) {
+ return PUGL_UNKNOWN_ERROR;
+ }
+
+ // Measure string and allocate global memory for clipboard
+ const char* str = (const char*)data;
+ const int wlen = MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0);
+ HGLOBAL mem =
+ GlobalAlloc(GMEM_MOVEABLE, (size_t)(wlen + 1) * sizeof(wchar_t));
+ if (!mem) {
+ CloseClipboard();
+ return PUGL_UNKNOWN_ERROR;
+ }
+
+ // Lock global memory
+ wchar_t* wstr = (wchar_t*)GlobalLock(mem);
+ if (!wstr) {
+ GlobalFree(mem);
+ CloseClipboard();
+ return PUGL_UNKNOWN_ERROR;
+ }
+
+ // Convert string into global memory and set it as clipboard data
+ MultiByteToWideChar(CP_UTF8, 0, str, (int)len, wstr, wlen);
+ wstr[wlen] = 0;
+ GlobalUnlock(mem);
+ SetClipboardData(CF_UNICODETEXT, mem);
+ CloseClipboard();
+ return PUGL_SUCCESS;
}
static const char* const cursor_ids[] = {
- IDC_ARROW, // ARROW
- IDC_IBEAM, // CARET
- IDC_CROSS, // CROSSHAIR
- IDC_HAND, // HAND
- IDC_NO, // NO
- IDC_SIZEWE, // LEFT_RIGHT
- IDC_SIZENS, // UP_DOWN
+ IDC_ARROW, // ARROW
+ IDC_IBEAM, // CARET
+ IDC_CROSS, // CROSSHAIR
+ IDC_HAND, // HAND
+ IDC_NO, // NO
+ IDC_SIZEWE, // LEFT_RIGHT
+ IDC_SIZENS, // UP_DOWN
};
PuglStatus
puglSetCursor(PuglView* view, PuglCursor cursor)
{
- PuglInternals* const impl = view->impl;
- const unsigned index = (unsigned)cursor;
- const unsigned count = sizeof(cursor_ids) / sizeof(cursor_ids[0]);
+ PuglInternals* const impl = view->impl;
+ const unsigned index = (unsigned)cursor;
+ const unsigned count = sizeof(cursor_ids) / sizeof(cursor_ids[0]);
- if (index >= count) {
- return PUGL_BAD_PARAMETER;
- }
+ if (index >= count) {
+ return PUGL_BAD_PARAMETER;
+ }
- const HCURSOR cur = LoadCursor(NULL, cursor_ids[index]);
- if (!cur) {
- return PUGL_FAILURE;
- }
+ const HCURSOR cur = LoadCursor(NULL, cursor_ids[index]);
+ if (!cur) {
+ return PUGL_FAILURE;
+ }
- impl->cursor = cur;
- if (impl->mouseTracked) {
- SetCursor(cur);
- }
+ impl->cursor = cur;
+ if (impl->mouseTracked) {
+ SetCursor(cur);
+ }
- return PUGL_SUCCESS;
+ return PUGL_SUCCESS;
}