diff options
Diffstat (limited to 'src/win.c')
-rw-r--r-- | src/win.c | 279 |
1 files changed, 116 insertions, 163 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,7 +44,8 @@ #ifdef __cplusplus # define PUGL_INIT_STRUCT \ - {} + { \ + } #else # define PUGL_INIT_STRUCT {0} #endif @@ -269,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) { @@ -327,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)); @@ -362,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; } } @@ -398,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; } @@ -692,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, @@ -702,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); } @@ -752,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; @@ -814,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); } @@ -967,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 @@ -1053,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 @@ -1068,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) { @@ -1143,17 +1113,18 @@ puglUpdate(PuglWorld* world, double timeout) PuglStatus st = PUGL_SUCCESS; if (timeout < 0.0) { - st = puglPollWinEvents(world, timeout); - st = st ? st : puglDispatchWinEvents(world); + WaitMessage(); + st = puglDispatchWinEvents(world); } else if (timeout < minWaitSeconds) { st = puglDispatchWinEvents(world); } else { const double endTime = startTime + timeout - minWaitSeconds; - for (double t = startTime; t < endTime; t = puglGetTime(world)) { - if ((st = puglPollWinEvents(world, endTime - t)) || - (st = puglDispatchWinEvents(world))) { - break; - } + 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); } } @@ -1168,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) { @@ -1211,21 +1174,27 @@ puglGetTime(const PuglWorld* world) PuglStatus 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 @@ -1239,17 +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) { ArgStringChar* const titleArg = puglArgStringNew(value); - SetWindowText(view->impl->hwnd, titleArg); + st = puglWinStatus(SetWindowText(view->impl->hwnd, titleArg)); puglArgStringFree(titleArg); } - return PUGL_SUCCESS; + return st; } static RECT @@ -1274,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 (!puglIsValidPosition(x, y)) { - 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); @@ -1323,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 (!puglIsValidSize(width, height)) { - 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, @@ -1356,12 +1281,33 @@ puglSetSize(PuglView* const view, const unsigned width, const unsigned height) } PuglStatus +puglSetPositionHint(PuglView* const view, + const PuglPositionHint hint, + const int x, + const int y) +{ + if (x <= INT16_MIN || x > INT16_MAX || y <= INT16_MIN || y > INT16_MAX) { + return PUGL_BAD_PARAMETER; + } + + 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) { - return puglStoreSizeHint(view, hint, width, height); + const PuglStatus st = puglStoreSizeHint(view, hint, width, height); + + return (!st && hint == PUGL_CURRENT_SIZE) + ? puglSetWindowSize(view, width, height) + : st; } PuglStatus @@ -1407,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* @@ -1425,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; } @@ -1437,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 @@ -1456,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; } @@ -1501,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[] = { @@ -1585,8 +1541,8 @@ puglGetAncestorCenter(const PuglView* const view) &rect); const PuglPoint center = { - (PuglCoord)(rect.left + (rect.right - rect.left) / 2), - (PuglCoord)(rect.top + (rect.bottom - rect.top) / 2)}; + (PuglCoord)(rect.left + ((rect.right - rect.left) / 2)), + (PuglCoord)(rect.top + ((rect.bottom - rect.top) / 2))}; return center; } @@ -1656,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; } @@ -1669,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 |