aboutsummaryrefslogtreecommitdiff
path: root/Src/Plugins/General/gen_ml/skinnedmenuthreadinfo.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Src/Plugins/General/gen_ml/skinnedmenuthreadinfo.cpp')
-rw-r--r--Src/Plugins/General/gen_ml/skinnedmenuthreadinfo.cpp468
1 files changed, 468 insertions, 0 deletions
diff --git a/Src/Plugins/General/gen_ml/skinnedmenuthreadinfo.cpp b/Src/Plugins/General/gen_ml/skinnedmenuthreadinfo.cpp
new file mode 100644
index 00000000..d0b19a7e
--- /dev/null
+++ b/Src/Plugins/General/gen_ml/skinnedmenuthreadinfo.cpp
@@ -0,0 +1,468 @@
+#include "main.h"
+#include "./skinnedMenuThreadInfo.h"
+#include "./skinnedMenu.h"
+#include "./skinnedMenuWnd.h"
+#ifndef _DEBUG
+ #include <new>
+#endif
+
+static DWORD tlsIndex = TLS_OUT_OF_INDEXES;
+
+ size_t ref;
+ HHOOK attachHook;
+ SkinnedMenu *attachMenu;
+ HHOOK validationHook;
+ SkinnedMenuWnd *validationWindow;
+ khash_t(intptr_map) *windowMap;
+ khash_t(int_set) *claimedIdSet;
+ unsigned int lastAssignedId;
+ HMENU activeMeasureMenu;
+
+SkinnedMenuThreadInfo::SkinnedMenuThreadInfo()
+ : ref(1), attachHook(NULL), attachMenu(NULL), validationHook(NULL),
+ validationWindow(NULL), lastAssignedId((unsigned int)-100),
+ activeMeasureMenu(NULL)
+{
+ windowMap = kh_init(intptr_map);
+ claimedIdSet = kh_init(int_set);
+}
+
+SkinnedMenuThreadInfo::~SkinnedMenuThreadInfo()
+{
+ if (TLS_OUT_OF_INDEXES != tlsIndex)
+ TlsSetValue(tlsIndex, NULL);
+
+ if (NULL != attachHook)
+ {
+ UnhookWindowsHookEx(attachHook);
+ attachHook = NULL;
+ }
+
+ if (NULL != validationHook)
+ {
+ UnhookWindowsHookEx(validationHook);
+ validationHook = NULL;
+ }
+
+ if (NULL != windowMap)
+ kh_destroy(intptr_map, windowMap);
+
+ if (NULL != claimedIdSet)
+ kh_destroy(int_set, claimedIdSet);
+}
+
+HRESULT SkinnedMenuThreadInfo::GetInstance(BOOL allowCreate, SkinnedMenuThreadInfo **instance)
+{
+ HRESULT hr;
+ SkinnedMenuThreadInfo *self;
+
+ if (NULL == instance)
+ return E_POINTER;
+
+ *instance = NULL;
+
+ if (TLS_OUT_OF_INDEXES == tlsIndex)
+ {
+ tlsIndex = TlsAlloc();
+ if (TLS_OUT_OF_INDEXES == tlsIndex)
+ return E_OUTOFMEMORY;
+
+ self = NULL;
+
+ if (FALSE != TlsSetValue(tlsIndex, NULL))
+ SetLastError(ERROR_SUCCESS);
+ }
+ else
+ {
+ self = (SkinnedMenuThreadInfo*)TlsGetValue(tlsIndex);
+ }
+
+ if (NULL == self)
+ {
+ unsigned long errorCode;
+ errorCode = GetLastError();
+ if (ERROR_SUCCESS != errorCode)
+ {
+ hr = HRESULT_FROM_WIN32(errorCode);
+ }
+ else
+ {
+ if (FALSE == allowCreate)
+ {
+ self = NULL;
+ hr = S_FALSE;
+ }
+ else
+ {
+ #ifndef _DEBUG
+ self = new (std::nothrow) SkinnedMenuThreadInfo();
+ #else
+ self = new SkinnedMenuThreadInfo();
+ #endif
+ if (NULL == self)
+ hr = E_OUTOFMEMORY;
+ else
+ {
+ if (FALSE == TlsSetValue(tlsIndex, self))
+ {
+ errorCode = GetLastError();
+ hr = HRESULT_FROM_WIN32(errorCode);
+ self->Release();
+ self = NULL;
+ }
+ else
+ {
+ hr = S_OK;
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ self->AddRef();
+ hr = S_OK;
+ }
+
+ *instance = self;
+ return hr;
+}
+
+size_t SkinnedMenuThreadInfo::AddRef()
+{
+ return InterlockedIncrement((LONG*)&ref);
+}
+
+size_t SkinnedMenuThreadInfo::Release()
+{
+ if (0 == ref)
+ return ref;
+
+ LONG r = InterlockedDecrement((LONG*)&ref);
+ if (0 == r)
+ delete(this);
+
+ return r;
+}
+
+BOOL SkinnedMenuThreadInfo::SetAttachHook(SkinnedMenu *menu)
+{
+ if (NULL == menu)
+ return FALSE;
+
+ if (NULL != attachHook)
+ return FALSE;
+
+ attachMenu = menu;
+ attachHook = SetWindowsHookEx(WH_CALLWNDPROC, SkinnedMenuThreadInfo_AttachHookCb, NULL, GetCurrentThreadId());
+ if (NULL == attachHook)
+ {
+ attachMenu = FALSE;
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+BOOL SkinnedMenuThreadInfo::RemoveAttachHook(SkinnedMenu *menu)
+{
+ if (NULL == attachHook)
+ return FALSE;
+
+ if (menu != attachMenu)
+ return FALSE;
+
+ UnhookWindowsHookEx(attachHook);
+
+ attachHook = NULL;
+ attachMenu = NULL;
+
+ return TRUE;
+}
+
+BOOL SkinnedMenuThreadInfo::IsAttachHookActive()
+{
+ return (NULL != attachHook);
+}
+
+LRESULT SkinnedMenuThreadInfo::AttachHook(int nCode, WPARAM wParam, LPARAM lParam)
+{
+ if (HC_ACTION == nCode)
+ {
+ CWPSTRUCT *pcwp = (CWPSTRUCT*)lParam;
+ if (WM_NCCREATE == pcwp->message)
+ {
+ wchar_t szName[128] = {0};
+ if (GetClassNameW(pcwp->hwnd, szName, ARRAYSIZE(szName)) &&
+ CSTR_EQUAL == CompareStringW(CSTR_INVARIANT, NORM_IGNORECASE, szName, -1, L"#32768", -1))
+ {
+ LRESULT result;
+ HHOOK hookCopy;
+ SkinnedMenu *menuCopy;
+
+ menuCopy = attachMenu;
+ hookCopy = attachHook;
+
+ attachHook = NULL;
+ attachMenu = NULL;
+
+ result = CallNextHookEx(hookCopy, nCode, wParam, lParam);
+ UnhookWindowsHookEx(hookCopy);
+
+ if (NULL != menuCopy)
+ menuCopy->AttachToHwnd(pcwp->hwnd);
+
+ return result;
+ }
+ }
+ }
+
+ return CallNextHookEx(attachHook, nCode, wParam, lParam);
+}
+
+BOOL SkinnedMenuThreadInfo::SetValidationHook(SkinnedMenuWnd *window)
+{
+ HMENU prevMenu;
+
+ if (NULL == window)
+ return FALSE;
+
+ if (NULL != validationHook)
+ return FALSE;
+
+ validationWindow = window;
+ prevMenu = SetActiveMeasureMenu(window->GetMenuHandle());
+
+ validationHook = SetWindowsHookEx(WH_CALLWNDPROC, SkinnedMenuThreadInfo_ValidationHookCb, NULL, GetCurrentThreadId());
+ if (NULL == validationHook)
+ {
+ validationWindow = FALSE;
+ SetActiveMeasureMenu(prevMenu);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+BOOL SkinnedMenuThreadInfo::RemoveValidationHook(SkinnedMenuWnd *window)
+{
+ if (NULL == validationHook)
+ return FALSE;
+
+ if (window != validationWindow)
+ return FALSE;
+
+
+ UnhookWindowsHookEx(validationHook);
+
+ validationWindow = NULL;
+ validationHook = NULL;
+
+ return TRUE;
+}
+
+BOOL SkinnedMenuThreadInfo::IsValidationHookActive()
+{
+ return (NULL != validationHook);
+}
+
+LRESULT SkinnedMenuThreadInfo::ValidationHook(int nCode, WPARAM wParam, LPARAM lParam)
+{
+ if (HC_ACTION == nCode)
+ {
+ CWPSTRUCT *pcwp = (CWPSTRUCT*)lParam;
+
+ if (WM_MEASUREITEM == pcwp->message ||
+ WM_DRAWITEM == pcwp->message)
+ {
+ if (NULL != validationWindow && NULL != pcwp->lParam)
+ {
+ BOOL validationCompleted(FALSE);
+
+ if (WM_MEASUREITEM == pcwp->message)
+ {
+ MEASUREITEMSTRUCT *measureItem;
+ measureItem = (MEASUREITEMSTRUCT*)pcwp->lParam;
+ if (ODT_MENU == measureItem->CtlType &&
+ validationWindow->GetMenuHandle() == GetActiveMeasureMenu())
+ {
+ validationCompleted = TRUE;
+ }
+ }
+ else
+ {
+ DRAWITEMSTRUCT *drawItem;
+ drawItem = (DRAWITEMSTRUCT*)pcwp->lParam;
+
+ if (ODT_MENU == drawItem->CtlType &&
+ validationWindow->GetMenuHandle() == (HMENU)drawItem->hwndItem)
+ {
+ validationCompleted = TRUE;
+ }
+ }
+
+ if (FALSE != validationCompleted)
+ {
+ LRESULT result;
+ HHOOK hookCopy;
+ SkinnedMenuWnd *windowCopy;
+
+ windowCopy = validationWindow;
+ hookCopy = validationHook;
+
+ validationHook = NULL;
+ validationWindow = NULL;
+
+ if (NULL != windowCopy && windowCopy->GetOwnerWindow() != pcwp->hwnd)
+ {
+ windowCopy->SetOwnerWindow(pcwp->hwnd);
+ }
+
+ result = CallNextHookEx(hookCopy, nCode, wParam, lParam);
+ UnhookWindowsHookEx(hookCopy);
+
+
+ return result;
+ }
+ }
+ }
+ }
+
+ return CallNextHookEx(attachHook, nCode, wParam, lParam);
+}
+
+BOOL SkinnedMenuThreadInfo::RegisterMenu(HMENU menu, HWND window)
+{
+ int code;
+ khint_t key;
+
+ if (NULL == menu)
+ return FALSE;
+
+ if (NULL == windowMap)
+ return FALSE;
+
+ key = kh_put(intptr_map, windowMap, (intptr_t)menu, &code);
+ kh_val(windowMap, key) = window;
+
+ return TRUE;
+}
+
+BOOL SkinnedMenuThreadInfo::UnregisterMenu(HMENU menu)
+{
+ khint_t key;
+
+ if (NULL == menu)
+ return FALSE;
+
+ if (NULL == windowMap)
+ return FALSE;
+
+ key = kh_get(intptr_map, windowMap, (intptr_t)menu);
+ if (kh_end(windowMap) == key)
+ return FALSE;
+
+ kh_del(intptr_map, windowMap, key);
+ return TRUE;
+}
+
+HWND SkinnedMenuThreadInfo::FindMenuWindow(HMENU menu)
+{
+ khint_t key;
+
+ if (NULL == menu)
+ return NULL;
+
+ if (NULL == windowMap)
+ return NULL;
+
+ key = kh_get(intptr_map, windowMap, (intptr_t)menu);
+ if (kh_end(windowMap) == key)
+ return NULL;
+
+ return kh_val(windowMap, key);
+}
+
+void SkinnedMenuThreadInfo::ClaimId(unsigned int id)
+{
+ int code;
+ kh_put(int_set, claimedIdSet, id, &code);
+}
+
+void SkinnedMenuThreadInfo::ReleaseId(unsigned int id)
+{
+ khint_t key;
+ key = kh_get(int_set, claimedIdSet, id);
+ if (kh_end(claimedIdSet) != key)
+ kh_del(int_set, claimedIdSet, key);
+}
+
+unsigned int SkinnedMenuThreadInfo::GetAvailableId()
+{
+ khint_t key;
+ unsigned int originalId;
+
+ lastAssignedId--;
+ if ((unsigned int)-1 == lastAssignedId)
+ lastAssignedId--;
+
+ originalId = lastAssignedId;
+
+ for(;;)
+ {
+ key = kh_get(int_set, claimedIdSet, lastAssignedId);
+ if (kh_end(claimedIdSet) == key)
+ return lastAssignedId;
+
+ lastAssignedId--;
+ if ((unsigned int)-1 == lastAssignedId)
+ lastAssignedId--;
+
+ if (lastAssignedId == originalId)
+ break;
+ }
+
+ return (unsigned int)-1;
+}
+
+HMENU SkinnedMenuThreadInfo::SetActiveMeasureMenu(HMENU menu)
+{
+ HMENU prevMenu;
+ prevMenu = activeMeasureMenu;
+ activeMeasureMenu = menu;
+ return prevMenu;
+
+}
+
+HMENU SkinnedMenuThreadInfo::GetActiveMeasureMenu()
+{
+ return activeMeasureMenu;
+}
+
+static LRESULT CALLBACK SkinnedMenuThreadInfo_AttachHookCb(int nCode, WPARAM wParam, LPARAM lParam)
+{
+ LRESULT result;
+ SkinnedMenuThreadInfo *self;
+
+ if (S_OK != SkinnedMenuThreadInfo::GetInstance(FALSE, &self))
+ return 0;
+
+ result = self->AttachHook(nCode, wParam, lParam);
+
+ self->Release();
+ return result;
+}
+
+static LRESULT CALLBACK SkinnedMenuThreadInfo_ValidationHookCb(int nCode, WPARAM wParam, LPARAM lParam)
+{
+ LRESULT result;
+ SkinnedMenuThreadInfo *self;
+
+ if (S_OK != SkinnedMenuThreadInfo::GetInstance(FALSE, &self))
+ return 0;
+
+ result = self->ValidationHook(nCode, wParam, lParam);
+
+ self->Release();
+ return result;
+} \ No newline at end of file