diff options
Diffstat (limited to 'src/win.c')
-rw-r--r-- | src/win.c | 499 |
1 files changed, 224 insertions, 275 deletions
@@ -4,9 +4,10 @@ #include "win.h" #include "internal.h" +#include "macros.h" #include "platform.h" -#include "pugl/pugl.h" +#include <pugl/pugl.h> #include <dwmapi.h> #include <windows.h> @@ -43,12 +44,10 @@ #ifdef __cplusplus # define PUGL_INIT_STRUCT \ - {} -#else -# define PUGL_INIT_STRUCT \ { \ - 0 \ } +#else +# define PUGL_INIT_STRUCT {0} #endif typedef BOOL(WINAPI* PFN_SetProcessDPIAware)(void); @@ -58,8 +57,12 @@ typedef HRESULT(WINAPI* PFN_GetScaleFactorForMonitor)(HMONITOR, DWORD*); LRESULT CALLBACK wndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam); -static wchar_t* -puglUtf8ToWideChar(const char* const utf8) +#ifdef UNICODE + +typedef wchar_t ArgStringChar; + +static ArgStringChar* +puglArgStringNew(const char* const utf8) { const int len = MultiByteToWideChar(CP_UTF8, 0, utf8, -1, NULL, 0); if (len > 0) { @@ -71,6 +74,30 @@ puglUtf8ToWideChar(const char* const utf8) return NULL; } +static void +puglArgStringFree(ArgStringChar* const utf8) +{ + free(utf8); +} + +#else // !defined(UNICODE) + +typedef const char ArgStringChar; + +static ArgStringChar* +puglArgStringNew(const char* const utf8) +{ + return utf8; +} + +static void +puglArgStringFree(ArgStringChar* const utf8) +{ + (void)utf8; +} + +#endif + static char* puglWideCharToUtf8(const wchar_t* const wstr, size_t* len) { @@ -94,11 +121,7 @@ puglWinStatus(const BOOL success) static bool puglRegisterWindowClass(const char* name) { -#ifdef UNICODE - wchar_t* const wname = puglUtf8ToWideChar(name); -#else - const char* const wname = name; -#endif + ArgStringChar* const nameArg = puglArgStringNew(name); HMODULE module = NULL; if (!GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | @@ -109,7 +132,7 @@ puglRegisterWindowClass(const char* name) } WNDCLASSEX wc = PUGL_INIT_STRUCT; - if (GetClassInfoEx(module, wname, &wc)) { + if (GetClassInfoEx(module, nameArg, &wc)) { return true; // Already registered } @@ -120,12 +143,10 @@ puglRegisterWindowClass(const char* name) wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH); - wc.lpszClassName = wname; + wc.lpszClassName = nameArg; const bool success = !!RegisterClassEx(&wc); -#ifdef UNICODE - free(wname); -#endif + puglArgStringFree(nameArg); return success; } @@ -184,7 +205,7 @@ static double puglWinGetViewScaleFactor(const PuglView* const view) { const HMODULE shcore = - LoadLibraryExA("Shcore.dll", NULL, LOAD_LIBRARY_SEARCH_SYSTEM32); + LoadLibraryEx(TEXT("Shcore.dll"), NULL, LOAD_LIBRARY_SEARCH_SYSTEM32); if (!shcore) { return 1.0; } @@ -219,7 +240,7 @@ puglInitWorldInternals(PuglWorldType type, PuglWorldFlags PUGL_UNUSED(flags)) if (type == PUGL_PROGRAM) { HMODULE user32 = - LoadLibraryExA("user32.dll", NULL, LOAD_LIBRARY_SEARCH_SYSTEM32); + LoadLibraryEx(TEXT("user32.dll"), NULL, LOAD_LIBRARY_SEARCH_SYSTEM32); if (user32) { PFN_SetProcessDPIAware SetProcessDPIAware = (PFN_SetProcessDPIAware)GetProcAddress(user32, "SetProcessDPIAware"); @@ -250,20 +271,6 @@ puglInitViewInternals(PuglWorld* PUGL_UNUSED(world)) 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; -} - PuglStatus puglRealize(PuglView* view) { @@ -287,9 +294,9 @@ puglRealize(PuglView* view) puglEnsureHint(view, PUGL_ALPHA_BITS, 8); // Get refresh rate for resize draw timer - DEVMODEA devMode; + DEVMODE devMode; memset(&devMode, 0, sizeof(devMode)); - EnumDisplaySettingsA(NULL, ENUM_CURRENT_SETTINGS, &devMode); + EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &devMode); view->hints[PUGL_REFRESH_RATE] = (int)devMode.dmDisplayFrequency; // Register window class if necessary @@ -308,16 +315,16 @@ puglRealize(PuglView* view) puglSetViewString(view, PUGL_WINDOW_TITLE, view->strings[PUGL_WINDOW_TITLE]); puglSetTransientParent(view, view->transientParent); - view->impl->scaleFactor = puglWinGetViewScaleFactor(view); - view->impl->cursor = LoadCursor(NULL, IDC_ARROW); + impl->scaleFactor = puglWinGetViewScaleFactor(view); + impl->cursor = LoadCursor(NULL, IDC_ARROW); if (view->hints[PUGL_DARK_FRAME]) { const BOOL useDarkMode = TRUE; - if ((DwmSetWindowAttribute(view->impl->hwnd, + if ((DwmSetWindowAttribute(impl->hwnd, DWMWA_USE_IMMERSIVE_DARK_MODE, &useDarkMode, sizeof(useDarkMode)) != S_OK)) { - DwmSetWindowAttribute(view->impl->hwnd, + DwmSetWindowAttribute(impl->hwnd, PRE_20H1_DWMWA_USE_IMMERSIVE_DARK_MODE, &useDarkMode, sizeof(useDarkMode)); @@ -343,24 +350,22 @@ puglUnrealize(PuglView* const view) view->backend->destroy(view); } - ReleaseDC(view->impl->hwnd, view->impl->hdc); - view->impl->hdc = NULL; - - DestroyWindow(view->impl->hwnd); - view->impl->hwnd = NULL; - memset(&view->lastConfigure, 0, sizeof(PuglConfigureEvent)); - return PUGL_SUCCESS; + ReleaseDC(impl->hwnd, impl->hdc); + impl->hdc = NULL; + + const PuglStatus st = puglWinStatus(DestroyWindow(impl->hwnd)); + impl->hwnd = NULL; + return st; } PuglStatus puglShow(PuglView* view, const PuglShowCommand command) { PuglInternals* impl = view->impl; - + PuglStatus st = PUGL_SUCCESS; if (!impl->hwnd) { - const PuglStatus st = puglRealize(view); - if (st) { + if ((st = puglRealize(view))) { return st; } } @@ -379,15 +384,13 @@ puglShow(PuglView* view, const PuglShowCommand command) break; } - return PUGL_SUCCESS; + return st; } PuglStatus puglHide(PuglView* view) { - PuglInternals* impl = view->impl; - - ShowWindow(impl->hwnd, SW_HIDE); + ShowWindow(view->impl->hwnd, SW_HIDE); return PUGL_SUCCESS; } @@ -408,14 +411,11 @@ puglFreeViewInternals(PuglView* view) void puglFreeWorldInternals(PuglWorld* world) { -#ifdef UNICODE - wchar_t* const wname = puglUtf8ToWideChar(world->strings[PUGL_CLASS_NAME]); - UnregisterClass(wname, NULL); - free(wname); -#else - UnregisterClass(world->strings[PUGL_CLASS_NAME], NULL); -#endif + const char* const className = world->strings[PUGL_CLASS_NAME]; + ArgStringChar* const classNameArg = puglArgStringNew(className); + UnregisterClass(classNameArg, NULL); + puglArgStringFree(classNameArg); free(world->impl); } @@ -426,14 +426,14 @@ keyInRange(const WPARAM winSym, const PuglKey puglMin) { return (winSym >= winMin && winSym <= winMax) - ? (PuglKey)(puglMin + (winSym - winMin)) - : (PuglKey)0; + ? (PuglKey)((WPARAM)puglMin + (winSym - winMin)) + : PUGL_KEY_NONE; } static PuglKey keySymToSpecial(const WPARAM sym, const bool ext) { - PuglKey key = (PuglKey)0; + PuglKey key = PUGL_KEY_NONE; if ((key = keyInRange(sym, VK_F1, VK_F12, PUGL_KEY_F1)) || (key = keyInRange(sym, VK_PRIOR, @@ -482,23 +482,26 @@ keySymToSpecial(const WPARAM sym, const bool ext) // clang-format on } - return (PuglKey)0; + return PUGL_KEY_NONE; +} + +static bool +is_toggled(int vkey) +{ + return (unsigned)GetKeyState(vkey) & 1U; } static uint32_t getModifiers(void) { - // clang-format off - return ( - ((GetKeyState(VK_SHIFT) < 0) ? (uint32_t)PUGL_MOD_SHIFT : 0U) | - ((GetKeyState(VK_CONTROL) < 0) ? (uint32_t)PUGL_MOD_CTRL : 0U) | - ((GetKeyState(VK_MENU) < 0) ? (uint32_t)PUGL_MOD_ALT : 0U) | - ((GetKeyState(VK_LWIN) < 0) ? (uint32_t)PUGL_MOD_SUPER : 0U) | - ((GetKeyState(VK_RWIN) < 0) ? (uint32_t)PUGL_MOD_SUPER : 0U) | - ((GetKeyState(VK_NUMLOCK) & 1U) ? (uint32_t)PUGL_MOD_NUM_LOCK : 0U) | - ((GetKeyState(VK_SCROLL) & 1U) ? (uint32_t)PUGL_MOD_SCROLL_LOCK : 0U) | - ((GetKeyState(VK_CAPITAL) & 1U) ? (uint32_t)PUGL_MOD_CAPS_LOCK : 0U)); - // clang-format on + return ((uint32_t)(((GetKeyState(VK_SHIFT) < 0) ? PUGL_MOD_SHIFT : 0) | + ((GetKeyState(VK_CONTROL) < 0) ? PUGL_MOD_CTRL : 0) | + ((GetKeyState(VK_MENU) < 0) ? PUGL_MOD_ALT : 0) | + ((GetKeyState(VK_LWIN) < 0) ? PUGL_MOD_SUPER : 0) | + ((GetKeyState(VK_RWIN) < 0) ? PUGL_MOD_SUPER : 0) | + (is_toggled(VK_NUMLOCK) ? PUGL_MOD_NUM_LOCK : 0) | + (is_toggled(VK_SCROLL) ? PUGL_MOD_SCROLL_LOCK : 0) | + (is_toggled(VK_CAPITAL) ? PUGL_MOD_CAPS_LOCK : 0))); } static void @@ -673,7 +676,7 @@ handleCrossing(PuglView* view, const PuglEventType type, POINT pos) const PuglCrossingEvent ev = { type, - 0, + 0U, GetMessageTime() / 1e3, (double)pos.x, (double)pos.y, @@ -683,7 +686,7 @@ handleCrossing(PuglView* view, const PuglEventType type, POINT pos) PUGL_CROSSING_NORMAL, }; - PuglEvent crossingEvent = {{type, 0}}; + PuglEvent crossingEvent = {{type, 0U}}; crossingEvent.crossing = ev; puglDispatchEvent(view, &crossingEvent); } @@ -693,8 +696,8 @@ constrainAspect(const PuglView* const view, RECT* const size, const WPARAM wParam) { - const PuglViewSize minAspect = view->sizeHints[PUGL_MIN_ASPECT]; - const PuglViewSize maxAspect = view->sizeHints[PUGL_MAX_ASPECT]; + const PuglArea minAspect = view->sizeHints[PUGL_MIN_ASPECT]; + const PuglArea maxAspect = view->sizeHints[PUGL_MAX_ASPECT]; const float minA = (float)minAspect.width / (float)minAspect.height; const float maxA = (float)maxAspect.width / (float)maxAspect.height; @@ -733,7 +736,7 @@ constrainAspect(const PuglView* const view, static LRESULT handleMessage(PuglView* view, UINT message, WPARAM wParam, LPARAM lParam) { - PuglEvent event = {{PUGL_NOTHING, 0}}; + PuglEvent event = {{PUGL_NOTHING, 0U}}; RECT rect = {0, 0, 0, 0}; POINT pt = {0, 0}; MINMAXINFO* mmi = NULL; @@ -779,8 +782,8 @@ handleMessage(PuglView* view, UINT message, WPARAM wParam, LPARAM lParam) handleConfigure(view, &event); break; case WM_SIZING: - if (puglIsValidSize(view->sizeHints[PUGL_MIN_ASPECT]) && - puglIsValidSize(view->sizeHints[PUGL_MAX_ASPECT])) { + if (puglIsValidArea(view->sizeHints[PUGL_MIN_ASPECT]) && + puglIsValidArea(view->sizeHints[PUGL_MAX_ASPECT])) { constrainAspect(view, (RECT*)lParam, wParam); return TRUE; } @@ -795,7 +798,7 @@ handleMessage(PuglView* view, UINT message, WPARAM wParam, LPARAM lParam) break; case WM_TIMER: if (wParam >= PUGL_USER_TIMER_MIN) { - PuglEvent ev = {{PUGL_TIMER, 0}}; + PuglEvent ev = {{PUGL_TIMER, 0U}}; ev.timer.id = wParam - PUGL_USER_TIMER_MIN; puglDispatchEvent(view, &ev); } @@ -812,7 +815,7 @@ handleMessage(PuglView* view, UINT message, WPARAM wParam, LPARAM lParam) mmi = (MINMAXINFO*)lParam; mmi->ptMinTrackSize.x = view->sizeHints[PUGL_MIN_SIZE].width; mmi->ptMinTrackSize.y = view->sizeHints[PUGL_MIN_SIZE].height; - if (puglIsValidSize(view->sizeHints[PUGL_MAX_SIZE])) { + if (puglIsValidArea(view->sizeHints[PUGL_MAX_SIZE])) { mmi->ptMaxTrackSize.x = view->sizeHints[PUGL_MAX_SIZE].width; mmi->ptMaxTrackSize.y = view->sizeHints[PUGL_MAX_SIZE].height; } @@ -948,8 +951,7 @@ handleMessage(PuglView* view, UINT message, WPARAM wParam, LPARAM lParam) PuglStatus puglGrabFocus(PuglView* view) { - SetFocus(view->impl->hwnd); - return PUGL_SUCCESS; + return puglWinStatus(!!SetFocus(view->impl->hwnd)); } bool @@ -1023,7 +1025,7 @@ puglSetViewStyle(PuglView* const view, const PuglViewStyleFlags flags) const bool newMaximized = styleIsMaximized(flags); if (oldMaximized != newMaximized) { ShowWindow(impl->hwnd, newMaximized ? SW_SHOWMAXIMIZED : SW_RESTORE); - puglPostRedisplay(view); + puglObscureView(view); } return PUGL_SUCCESS; @@ -1034,9 +1036,8 @@ puglStartTimer(PuglView* view, uintptr_t id, double timeout) { 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); + SetTimer(view->impl->hwnd, PUGL_USER_TIMER_MIN + id, msec, NULL); + return PUGL_SUCCESS; } PuglStatus @@ -1049,31 +1050,19 @@ PuglStatus puglSendEvent(PuglView* view, const PuglEvent* event) { if (event->type == PUGL_CLOSE) { - PostMessage(view->impl->hwnd, WM_CLOSE, 0, 0); - return PUGL_SUCCESS; + return puglWinStatus(PostMessage(view->impl->hwnd, WM_CLOSE, 0, 0)); } 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 puglWinStatus(PostMessage(view->impl->hwnd, + PUGL_LOCAL_CLIENT_MSG, + (WPARAM)event->client.data1, + (LPARAM)event->client.data2)); } return PUGL_UNSUPPORTED; } -#ifndef PUGL_DISABLE_DEPRECATED -PuglStatus -puglWaitForEvent(PuglView* PUGL_UNUSED(view)) -{ - WaitMessage(); - return PUGL_SUCCESS; -} -#endif - static PuglStatus puglDispatchViewEvents(PuglView* view) { @@ -1118,21 +1107,24 @@ puglDispatchWinEvents(PuglWorld* world) PuglStatus puglUpdate(PuglWorld* world, double timeout) { + static const double minWaitSeconds = 0.002; + 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.001) { + WaitMessage(); + st = puglDispatchWinEvents(world); + } else if (timeout < minWaitSeconds) { 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; - } + const double endTime = startTime + timeout - minWaitSeconds; + double t = startTime; + while (!st && t < endTime) { + const DWORD timeoutMs = (DWORD)((endTime - t) * 1e3); + MsgWaitForMultipleObjects(0, NULL, FALSE, timeoutMs, QS_ALLEVENTS); + st = puglDispatchWinEvents(world); + t = puglGetTime(world); } } @@ -1147,14 +1139,6 @@ puglUpdate(PuglWorld* world, double timeout) return st; } -#ifndef PUGL_DISABLE_DEPRECATED -PuglStatus -puglProcessEvents(PuglView* view) -{ - return puglUpdate(view->world, 0.0); -} -#endif - LRESULT CALLBACK wndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { @@ -1188,23 +1172,29 @@ puglGetTime(const PuglWorld* world) } PuglStatus -puglPostRedisplay(PuglView* view) +puglObscureView(PuglView* view) { - InvalidateRect(view->impl->hwnd, NULL, false); - return PUGL_SUCCESS; + return puglWinStatus(InvalidateRect(view->impl->hwnd, NULL, false)); } PuglStatus -puglPostRedisplayRect(PuglView* view, const PuglRect rect) +puglObscureRegion(PuglView* const view, + const int x, + const int y, + const unsigned width, + const unsigned height) { - const RECT r = {(long)floor(rect.x), - (long)floor(rect.y), - (long)ceil(rect.x + rect.width), - (long)ceil(rect.y + rect.height)}; + if (!puglIsValidPosition(x, y) || !puglIsValidSize(width, height)) { + return PUGL_BAD_PARAMETER; + } - InvalidateRect(view->impl->hwnd, &r, false); + const int cx = MAX(0, x); + const int cy = MAX(0, y); + const unsigned cw = MIN(view->lastConfigure.width, width); + const unsigned ch = MIN(view->lastConfigure.height, height); - return PUGL_SUCCESS; + const RECT r = {cx, cy, cx + (long)cw, cy + (long)ch}; + return puglWinStatus(InvalidateRect(view->impl->hwnd, &r, false)); } PuglNativeView @@ -1218,19 +1208,18 @@ puglViewStringChanged(PuglView* const view, const PuglStringHint key, const char* const value) { + PuglStatus st = PUGL_SUCCESS; if (!view->impl->hwnd) { - return PUGL_SUCCESS; + return st; } if (key == PUGL_WINDOW_TITLE) { - wchar_t* const wtitle = puglUtf8ToWideChar(value); - if (wtitle) { - SetWindowTextW(view->impl->hwnd, wtitle); - free(wtitle); - } + ArgStringChar* const titleArg = puglArgStringNew(value); + st = puglWinStatus(SetWindowText(view->impl->hwnd, titleArg)); + puglArgStringFree(titleArg); } - return PUGL_SUCCESS; + return st; } static RECT @@ -1255,45 +1244,9 @@ puglGetScaleFactor(const PuglView* const view) : puglWinGetViewScaleFactor(view); } -PuglStatus -puglSetFrame(PuglView* view, const PuglRect frame) -{ - if (!view->impl->hwnd) { - // Set defaults to be used when realized - view->defaultX = frame.x; - view->defaultY = frame.y; - view->sizeHints[PUGL_DEFAULT_SIZE].width = frame.width; - view->sizeHints[PUGL_DEFAULT_SIZE].height = frame.height; - return PUGL_SUCCESS; - } - - const RECT rect = - adjustedWindowRect(view, frame.x, frame.y, frame.width, frame.height); - - return puglWinStatus( - SetWindowPos(view->impl->hwnd, - HWND_TOP, - rect.left, - rect.top, - rect.right - rect.left, - rect.bottom - rect.top, - SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOZORDER)); -} - -PuglStatus -puglSetPosition(PuglView* const view, const int x, const int y) +static PuglStatus +puglSetWindowPosition(PuglView* const view, const int x, const int y) { - if (x < INT16_MIN || x > INT16_MAX || y < INT16_MIN || y > INT16_MAX) { - return PUGL_BAD_PARAMETER; - } - - if (!view->impl->hwnd) { - // Set defaults to be used when realized - view->defaultX = x; - view->defaultY = y; - return PUGL_SUCCESS; - } - const RECT rect = adjustedWindowRect( view, x, y, view->lastConfigure.width, view->lastConfigure.height); @@ -1304,20 +1257,11 @@ puglSetPosition(PuglView* const view, const int x, const int y) SetWindowPos(view->impl->hwnd, HWND_TOP, rect.left, rect.top, 0, 0, flags)); } -PuglStatus -puglSetSize(PuglView* const view, const unsigned width, const unsigned height) +static PuglStatus +puglSetWindowSize(PuglView* const view, + const unsigned width, + const unsigned height) { - if (width > INT16_MAX || height > INT16_MAX) { - return PUGL_BAD_PARAMETER; - } - - if (!view->impl->hwnd) { - // Set defaults to be used when realized - view->sizeHints[PUGL_DEFAULT_SIZE].width = (PuglSpan)width; - view->sizeHints[PUGL_DEFAULT_SIZE].height = (PuglSpan)height; - return PUGL_SUCCESS; - } - const RECT rect = adjustedWindowRect(view, view->lastConfigure.x, view->lastConfigure.y, @@ -1337,18 +1281,33 @@ puglSetSize(PuglView* const view, const unsigned width, const unsigned height) } PuglStatus -puglSetSizeHint(PuglView* const view, - const PuglSizeHint hint, - const PuglSpan width, - const PuglSpan height) +puglSetPositionHint(PuglView* const view, + const PuglPositionHint hint, + const int x, + const int y) { - if ((unsigned)hint >= PUGL_NUM_SIZE_HINTS) { + if (x <= INT16_MIN || x > INT16_MAX || y <= INT16_MIN || y > INT16_MAX) { return PUGL_BAD_PARAMETER; } - view->sizeHints[hint].width = width; - view->sizeHints[hint].height = height; - return PUGL_SUCCESS; + view->positionHints[hint].x = (PuglCoord)x; + view->positionHints[hint].y = (PuglCoord)y; + + return (hint == PUGL_CURRENT_POSITION) ? puglSetWindowPosition(view, x, y) + : PUGL_SUCCESS; +} + +PuglStatus +puglSetSizeHint(PuglView* const view, + const PuglSizeHint hint, + const unsigned width, + const unsigned height) +{ + const PuglStatus st = puglStoreSizeHint(view, hint, width, height); + + return (!st && hint == PUGL_CURRENT_SIZE) + ? puglSetWindowSize(view, width, height) + : st; } PuglStatus @@ -1394,15 +1353,14 @@ puglAcceptOffer(PuglView* const view, const PuglDataEvent data = { PUGL_DATA, - 0, + 0U, GetMessageTime() / 1e3, 0, }; PuglEvent dataEvent; dataEvent.data = data; - puglDispatchEvent(view, &dataEvent); - return PUGL_SUCCESS; + return puglDispatchEvent(view, &dataEvent); } const void* @@ -1412,8 +1370,21 @@ puglGetClipboard(PuglView* const view, { PuglInternals* const impl = view->impl; - if (typeIndex > 0U || !IsClipboardFormatAvailable(CF_UNICODETEXT) || - !OpenClipboard(impl->hwnd)) { + if (typeIndex > 0U || !IsClipboardFormatAvailable(CF_UNICODETEXT)) { + return NULL; + } + + // Try to open the clipboard several times since others may have locked it + BOOL opened = FALSE; + static const unsigned max_tries = 16U; + for (unsigned i = 0U; !opened && i < max_tries; ++i) { + opened = OpenClipboard(impl->hwnd); + if (!opened) { + Sleep(0); + } + } + + if (!opened) { return NULL; } @@ -1424,15 +1395,14 @@ puglGetClipboard(PuglView* const view, return NULL; } - free(view->impl->clipboard.data); - view->impl->clipboard.data = - puglWideCharToUtf8(wstr, &view->impl->clipboard.len); + free(impl->clipboard.data); + impl->clipboard.data = puglWideCharToUtf8(wstr, &impl->clipboard.len); GlobalUnlock(mem); CloseClipboard(); - *len = view->impl->clipboard.len; - return view->impl->clipboard.data; + *len = impl->clipboard.len; + return impl->clipboard.data; } PuglStatus @@ -1443,7 +1413,7 @@ puglSetClipboard(PuglView* const view, { PuglInternals* const impl = view->impl; - PuglStatus st = puglSetBlob(&view->impl->clipboard, data, len); + PuglStatus st = puglSetBlob(&impl->clipboard, data, len); if (st) { return st; } @@ -1488,14 +1458,13 @@ puglPaste(PuglView* const view) { const PuglDataOfferEvent offer = { PUGL_DATA_OFFER, - 0, + 0U, GetMessageTime() / 1e3, }; PuglEvent offerEvent; offerEvent.offer = offer; - puglDispatchEvent(view, &offerEvent); - return PUGL_SUCCESS; + return puglDispatchEvent(view, &offerEvent); } static const TCHAR* const cursor_ids[] = { @@ -1563,42 +1532,18 @@ puglWinGetPixelFormatDescriptor(const PuglHints hints) return pfd; } -static PuglRect -getInitialFrame(PuglView* const view) +PuglPoint +puglGetAncestorCenter(const PuglView* const view) { - if (view->lastConfigure.type == PUGL_CONFIGURE) { - // Use the last configured frame - const PuglRect frame = {view->lastConfigure.x, - view->lastConfigure.y, - view->lastConfigure.width, - view->lastConfigure.height}; - return frame; - } - - const PuglSpan defaultWidth = view->sizeHints[PUGL_DEFAULT_SIZE].width; - const PuglSpan defaultHeight = view->sizeHints[PUGL_DEFAULT_SIZE].height; - const int x = view->defaultX; - const int y = view->defaultY; - if (x >= INT16_MIN && x <= INT16_MAX && y >= INT16_MIN && y <= INT16_MAX) { - // Use the default position set with puglSetPosition while unrealized - const PuglRect frame = { - (PuglCoord)x, (PuglCoord)y, defaultWidth, defaultHeight}; - return frame; - } - - // Get a bounding rect from the "nearest" parent or parent-like window - const HWND hwnd = puglWinGetWindow(view); - RECT rect = {0, 0, 0, 0}; - GetWindowRect(hwnd ? hwnd : GetDesktopWindow(), &rect); + RECT rect = {0, 0, 0, 0}; + GetWindowRect(view->transientParent ? (HWND)view->transientParent + : GetDesktopWindow(), + &rect); - // Center the frame around the center of the bounding rectangle - const LONG centerX = rect.left + (rect.right - rect.left) / 2; - const LONG centerY = rect.top + (rect.bottom - rect.top) / 2; - const PuglRect frame = {(PuglCoord)(centerX - (defaultWidth / 2)), - (PuglCoord)(centerY - (defaultHeight / 2)), - defaultWidth, - defaultHeight}; - return frame; + const PuglPoint center = { + (PuglCoord)(rect.left + ((rect.right - rect.left) / 2)), + (PuglCoord)(rect.top + ((rect.bottom - rect.top) / 2))}; + return center; } PuglStatus @@ -1613,28 +1558,35 @@ puglWinCreateWindow(PuglView* const view, PuglNativeView parent = view->parent ? view->parent : view->transientParent; // Calculate initial window rectangle - const unsigned winFlags = puglWinGetWindowFlags(view); - const unsigned winExFlags = puglWinGetWindowExFlags(view); - const PuglRect frame = getInitialFrame(view); - RECT wr = {(long)frame.x, - (long)frame.y, - (long)frame.x + frame.width, - (long)frame.y + frame.height}; + const unsigned winFlags = puglWinGetWindowFlags(view); + const unsigned winExFlags = puglWinGetWindowExFlags(view); + const PuglArea size = puglGetInitialSize(view); + const PuglPoint pos = puglGetInitialPosition(view, size); + RECT wr = {(long)pos.x, + (long)pos.y, + (long)pos.x + size.width, + (long)pos.y + size.height}; AdjustWindowRectEx(&wr, winFlags, FALSE, winExFlags); + ArgStringChar* const classNameArg = puglArgStringNew(className); + ArgStringChar* const titleArg = puglArgStringNew(title); + // Create window and get drawing context - if (!(*hwnd = CreateWindowExA(winExFlags, - className, - title, - winFlags, - wr.left, - wr.right, - wr.right - wr.left, - wr.bottom - wr.top, - (HWND)parent, - NULL, - NULL, - NULL))) { + *hwnd = CreateWindowEx(winExFlags, + classNameArg, + titleArg, + winFlags, + wr.left, + wr.right, + wr.right - wr.left, + wr.bottom - wr.top, + (HWND)parent, + NULL, + NULL, + NULL); + puglArgStringFree(titleArg); + puglArgStringFree(classNameArg); + if (!*hwnd) { return PUGL_REALIZE_FAILED; } @@ -1660,7 +1612,6 @@ puglWinConfigure(PuglView* view) { PuglInternals* const impl = view->impl; PuglStatus st = PUGL_SUCCESS; - if ((st = puglWinCreateWindow(view, "Pugl", &impl->hwnd, &impl->hdc))) { return st; } @@ -1673,20 +1624,18 @@ puglWinConfigure(PuglView* view) DestroyWindow(impl->hwnd); impl->hwnd = NULL; impl->hdc = NULL; - return PUGL_SET_FORMAT_FAILED; + st = PUGL_SET_FORMAT_FAILED; } - return PUGL_SUCCESS; + return st; } PuglStatus puglWinEnter(PuglView* view, const PuglExposeEvent* expose) { - if (expose) { - BeginPaint(view->impl->hwnd, &view->impl->paint); - } - - return PUGL_SUCCESS; + return expose + ? puglWinStatus(!!BeginPaint(view->impl->hwnd, &view->impl->paint)) + : PUGL_SUCCESS; } PuglStatus |