aboutsummaryrefslogtreecommitdiff
path: root/c/win.cpp
diff options
context:
space:
mode:
authorJohn Ankarström <john@ankarstrom.se>2022-08-09 21:49:18 +0200
committerJohn Ankarström <john@ankarstrom.se>2022-08-09 21:49:18 +0200
commit805cc4cec440525629758af918d50a850209ec0b (patch)
tree570077b7091020c899a1160523b7aba0523d3ed9 /c/win.cpp
parentdf2ccebabb5af3b304ba8220e4c9364f8fd9f830 (diff)
downloadEpisodeBrowser-805cc4cec440525629758af918d50a850209ec0b.tar.gz
Add WithNextWindow function.
I'm not sure if this clarifies or complicates the control flow. My hope is the former.
Diffstat (limited to 'c/win.cpp')
-rw-r--r--c/win.cpp130
1 files changed, 84 insertions, 46 deletions
diff --git a/c/win.cpp b/c/win.cpp
index 593b340..a68d5b3 100644
--- a/c/win.cpp
+++ b/c/win.cpp
@@ -3,6 +3,90 @@
#include "win.h"
+void WithNextWindow(void (*proc)(HWND))
+{
+ /* WithNextWindow uses a CBT hook to call an arbitrary
+ * procedure just before the creation of the next window. The
+ * hook is removed as soon as HCBT_CREATEWND is received.
+ * Thus, proc is guaranteed to be executed only once. Note
+ * that static storage must be used, as SetWindowHookEx cannot
+ * accept a capturing lambda as the hook procedure. */
+
+ static __thread auto procNext = proc;
+ static __thread HHOOK hHook = Require(SetWindowsHookEx(WH_CBT, [](const int nCode,
+ const WPARAM wParam, const LPARAM lParam) -> LRESULT CALLBACK
+ {
+ if (nCode == HCBT_CREATEWND) {
+ Require(UnhookWindowsHookEx(hHook));
+ procNext(reinterpret_cast<HWND>(wParam));
+ return 0;
+ } else
+ return CallNextHookEx(0, nCode, wParam, lParam);
+ }, nullptr, GetCurrentThreadId()));
+}
+
+/* Display next created window in the center of given window. */
+static void CenterNextWindow(HWND hWnd)
+{
+ if (!hWnd)
+ return;
+
+ /* CenterNextWindow employs a trick similar to that above.
+ * Note, however, that repositioning does not work unless it
+ * is delayed until the new window is activated. This
+ * complicates the code somewhat. */
+
+ static __thread HWND hWndParent = hWnd;
+ static __thread HWND hWndNext = nullptr;
+ static __thread HHOOK hHook = Require(SetWindowsHookEx(WH_CBT, [](const int nCode,
+ const WPARAM wParam, const LPARAM lParam) noexcept -> LRESULT CALLBACK
+ {
+ if (!hWndNext && nCode == HCBT_CREATEWND) {
+ hWndNext = reinterpret_cast<HWND>(wParam);
+ return 0;
+ } else if (nCode == HCBT_ACTIVATE
+ && reinterpret_cast<HWND>(wParam) == hWndNext) {
+ Require(UnhookWindowsHookEx(hHook));
+
+ long lStyle = GetWindowLong(hWndNext, GWL_STYLE);
+ if (!(lStyle & WS_POPUP)) return 0;
+
+ RECT rcMain, rcMsg;
+ GetWindowRect(hWndParent, &rcMain);
+ GetWindowRect(hWndNext, &rcMsg);
+ SetWindowPos(hWndNext, nullptr,
+ rcMain.left+(rcMain.right-rcMain.left)/2-(rcMsg.right-rcMsg.left)/2,
+ rcMain.top+(rcMain.bottom-rcMain.top)/2-(rcMsg.bottom-rcMsg.top)/2,
+ -1, -1,
+ SWP_NOZORDER|SWP_NOSIZE|SWP_NOACTIVATE);
+
+ return 0;
+ } else
+ return CallNextHookEx(0, nCode, wParam, lParam);
+ }, nullptr, GetCurrentThreadId()));
+}
+
+int EBMessageBox(const wchar_t* const wszText, const wchar_t* const wszCaption, const UINT uType)
+{
+ extern HWND g_hWnd;
+ CenterNextWindow(g_hWnd);
+ return MessageBox(g_hWnd, wszText, wszCaption, uType);
+}
+
+int GetRelativeCursorPos(const HWND hWnd, POINT* const pt) noexcept
+{
+ RECT rc;
+ if (!GetClientRect(hWnd, &rc)) return 0;
+ SetLastError(ERROR_SUCCESS);
+ if (!MapWindowPoints(hWnd, nullptr, (POINT*)&rc, 2)) return 0;
+
+ POINT ptMouse;
+ if (!GetCursorPos(&ptMouse)) return 0;
+ pt->x = ptMouse.x-rc.left;
+ pt->y = ptMouse.y-rc.top;
+ return 1;
+}
+
Win32Error::Win32Error() noexcept
: code(GetLastError()) {}
@@ -64,49 +148,3 @@ Library::~Library()
{
FreeLibrary(m_hModule);
}
-
-int EBMessageBox(const wchar_t* const wszText, const wchar_t* const wszCaption, const UINT uType)
-{
- extern HWND g_hWnd;
-
- auto proc = [](const int nCode, const WPARAM wParam, const LPARAM lParam) noexcept
- -> LRESULT CALLBACK
- {
- if (!g_hWnd || nCode < 0 || nCode != HCBT_ACTIVATE)
- return CallNextHookEx(0, nCode, wParam, lParam);
-
- HWND hWnd = reinterpret_cast<HWND>(wParam);
- long lStyle = GetWindowLong(hWnd, GWL_STYLE);
- if (!(lStyle & WS_POPUP)) return 0;
-
- RECT rcMain, rcMsg;
- GetWindowRect(g_hWnd, &rcMain);
- GetWindowRect(hWnd, &rcMsg);
- SetWindowPos(hWnd, nullptr,
- rcMain.left+(rcMain.right-rcMain.left)/2-(rcMsg.right-rcMsg.left)/2,
- rcMain.top+(rcMain.bottom-rcMain.top)/2-(rcMsg.bottom-rcMsg.top)/2,
- -1, -1,
- SWP_NOZORDER|SWP_NOSIZE|SWP_NOACTIVATE);
-
- return 0;
- };
-
- HHOOK hHook = Require(SetWindowsHookEx(WH_CBT, proc, nullptr, GetCurrentThreadId()));
- int r = MessageBox(g_hWnd, wszText, wszCaption, uType);
- Require(UnhookWindowsHookEx(hHook));
- return r;
-}
-
-int GetRelativeCursorPos(const HWND hWnd, POINT* const pt)
-{
- RECT rc;
- if (!GetClientRect(hWnd, &rc)) return 0;
- SetLastError(ERROR_SUCCESS);
- if (!MapWindowPoints(hWnd, nullptr, (POINT*)&rc, 2)) return 0;
-
- POINT ptMouse;
- if (!GetCursorPos(&ptMouse)) return 0;
- pt->x = ptMouse.x-rc.left;
- pt->y = ptMouse.y-rc.top;
- return 1;
-}