diff options
author | Kirill Volinsky <mataes2007@gmail.com> | 2017-09-19 19:50:57 +0300 |
---|---|---|
committer | Kirill Volinsky <mataes2007@gmail.com> | 2017-09-19 19:50:57 +0300 |
commit | 44eadfd2f33bf3ac4cc1c56c773f09e8cf391385 (patch) | |
tree | 65e1ef4724c620ac1471db8fce38451d7963aedb /plugins/AsSingleWindow/src/WindowsManager.cpp | |
parent | cc13707adf716f558a1e85995c042e5361eec60b (diff) |
AsSingleWindow: adopted but not working
Diffstat (limited to 'plugins/AsSingleWindow/src/WindowsManager.cpp')
-rw-r--r-- | plugins/AsSingleWindow/src/WindowsManager.cpp | 490 |
1 files changed, 490 insertions, 0 deletions
diff --git a/plugins/AsSingleWindow/src/WindowsManager.cpp b/plugins/AsSingleWindow/src/WindowsManager.cpp new file mode 100644 index 0000000000..750d3f60f5 --- /dev/null +++ b/plugins/AsSingleWindow/src/WindowsManager.cpp @@ -0,0 +1,490 @@ +#include "stdafx.h" +#include "WindowsManager.h" +#include "AsSingleWindow.h" + +void sWindowInfo::saveState() +{ + WINDOWPLACEMENT wndPlace; + wndPlace.length = sizeof(wndPlace); + if (! GetWindowPlacement(this->hWnd, &wndPlace)) + return; + + switch (wndPlace.showCmd) + { + case SW_HIDE: + this->eState = WINDOW_STATE_HIDDEN; + break; + case SW_MINIMIZE: + case SW_SHOWMINIMIZED: + case SW_SHOWMINNOACTIVE: + this->eState = WINDOW_STATE_MINIMIZED; + break; + case SW_MAXIMIZE: + case SW_RESTORE: + case SW_SHOW: + case SW_SHOWNA: + case SW_SHOWNOACTIVATE: + case SW_SHOWNORMAL: + this->eState = WINDOW_STATE_NORMAL; + break; + } +} + +void sWindowInfo::saveRect() +{ + switch (this->eState) + { + case WINDOW_STATE_HIDDEN: + case WINDOW_STATE_MINIMIZED: + WINDOWPLACEMENT wndPlace; + wndPlace.length = sizeof(wndPlace); + if (GetWindowPlacement(this->hWnd, &wndPlace)) + this->rLastSavedPosition = wndPlace.rcNormalPosition; + break; + default: + GetWindowRect(this->hWnd, &this->rLastSavedPosition); + break; + } +} + +void pluginSetProgress() +{ + EnterCriticalSection(&pluginVars.m_CS); + pluginVars.IsUpdateInProgress = true; + LeaveCriticalSection(&pluginVars.m_CS); +} + +void pluginSetDone() +{ + EnterCriticalSection(&pluginVars.m_CS); + pluginVars.IsUpdateInProgress = false; + LeaveCriticalSection(&pluginVars.m_CS); +} + +bool pluginIsAlreadyRunning() +{ + EnterCriticalSection(&pluginVars.m_CS); + bool result = pluginVars.IsUpdateInProgress; + LeaveCriticalSection(&pluginVars.m_CS); + return result; +} + +/** + * Поиск окна в списке + * возвращается указатель на структуру с информацией + */ +sWindowInfo* windowFind(HWND hWnd) +{ + windowsList::iterator itr; + for (itr = pluginVars.allWindows.begin(); itr != pluginVars.allWindows.end(); ++itr) + if (itr->hWnd == hWnd) + return &*itr; + + return NULL; +} + +/** + * Поиск окна в списке + * возвращается итератор + */ +windowsList::iterator windowFindItr(HWND hWnd) +{ + windowsList::iterator itr; + for (itr = pluginVars.allWindows.begin(); itr != pluginVars.allWindows.end(); ++itr) + if (itr->hWnd == hWnd) + return itr; + + return itr; +} + +/** + * Поиск окна в списке + * возвращается реверсный итератор + */ +windowsList::reverse_iterator windowFindRevItr(HWND hWnd) +{ + windowsList::reverse_iterator ritr; + for (ritr = pluginVars.allWindows.rbegin(); ritr != pluginVars.allWindows.rend(); ++ritr) + if (ritr->hWnd == hWnd) + return ritr; + + return ritr; +} + +/** + * Добавление окна в список окон и выставление всех начальных значений + * здесь же выставляется хук на wndProc + */ +void windowAdd(HWND hWnd, bool IsMain) +{ + sWindowInfo thisWindowInfo; + + hWnd = windowGetRoot(hWnd); + + // Если окно уже есть в списке (могло быть спрятано) + if (sWindowInfo* wndInfo = windowFind(hWnd)) + { + wndInfo->eState = WINDOW_STATE_NORMAL; // если окно пряталось ранее + windowReposition(hWnd); + return; + } + + thisWindowInfo.hWnd = hWnd; + thisWindowInfo.eState = WINDOW_STATE_NORMAL; + thisWindowInfo.pPrevWndProc = (WNDPROC) SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LONG_PTR) wndProcSync); + + pluginVars.allWindows.push_back(thisWindowInfo); + + if (IsMain) + pluginVars.contactListHWND = hWnd; + + windowReposition(hWnd); +} + +/** + * Поиск окна верхнего уровня + */ +HWND windowGetRoot(HWND hWnd) +{ + HWND hWndParent = GetParent(hWnd); + while (IsWindow(hWndParent) && (hWndParent != GetDesktopWindow())) // IsWindowVisible() ? + { + hWnd = hWndParent; + hWndParent = GetParent(hWnd); + } + return hWnd; +} + +void windowListUpdate() +{ + bool isRemoved = false; + windowsList::iterator itr = pluginVars.allWindows.begin(); + while (itr != pluginVars.allWindows.end()) + // Не удаляем КЛ впринципе, нет необходимости + if (! IsWindow(itr->hWnd) && itr->hWnd != pluginVars.contactListHWND) + { + if (itr->hWnd == pluginVars.contactListHWND) + pluginVars.contactListHWND = 0; + itr = pluginVars.allWindows.erase(itr); + isRemoved = true; + } + else + ++itr; + + if (isRemoved) + if (! pluginVars.allWindows.empty()) + // TODO: разобраться, почему после этого КЛ пропадает в трей + allWindowsMoveAndSize(pluginVars.contactListHWND); +} + +/** + * Установка стартовых координат и размера окна + * базируется на основе координат другого окна в списке + */ +void windowReposition(HWND hWnd) +{ + // TODO: Подумать, нужен ли тут hWnd вообще + RECT prevWindowPos; + + hWnd = windowGetRoot(hWnd); + + // TODO: Проверить, возможно нужен выход из цикла + if (sWindowInfo* wndInfo = windowFind(hWnd)) + { + for (windowsList::iterator itr = pluginVars.allWindows.begin(); itr != pluginVars.allWindows.end(); ++itr) + if (itr->hWnd != hWnd) // TODO: очень странная логика + if (GetWindowRect(itr->hWnd, &prevWindowPos)) + { + SendMessage(itr->hWnd, WM_MOVE, 0, MAKELPARAM(prevWindowPos.left, prevWindowPos.top)); + break; + } + } + else if (! pluginVars.allWindows.empty()) + { + windowsList::iterator itr = pluginVars.allWindows.begin(); + if (GetWindowRect(itr->hWnd, &prevWindowPos)) + SendMessage(itr->hWnd, WM_MOVE, 0, MAKELPARAM(prevWindowPos.left, prevWindowPos.top)); + } +} + +/** + * Перемещение и ресайз всех окон списка + * hWnd - окно-источник события перемещения/ресайза + */ +void allWindowsMoveAndSize(HWND hWnd) +{ + // Если склеивание отключено + if (pluginVars.Options.DrivenWindowPos == ASW_CLWINDOWPOS_DISABLED) + return; + + // Окно должно быть в списке и иметь нормальное состояние + if (sWindowInfo* wndInfo = windowFind(hWnd)) + { + if (wndInfo->eState != WINDOW_STATE_NORMAL) + return; + } + else + return; + + // Отключаем связь, если окон больше двух и выбрана соотв. опция + if (pluginVars.Options.WindowsMerging == ASW_WINDOWS_MERGEDISABLE) + if (pluginVars.allWindows.size() > 2) + return; + + // Просмотр окон от текущего до конца + windowsList::iterator itrC = windowFindItr(hWnd); + if (itrC != pluginVars.allWindows.end()) + { + windowsList::iterator itrN = ++windowFindItr(hWnd); + for (; itrC != pluginVars.allWindows.end(), itrN != pluginVars.allWindows.end(); ++itrC, ++itrN) + { + // Режим только двух окон + if (pluginVars.Options.WindowsMerging == ASW_WINDOWS_MERGEONE) + if ((itrC->hWnd != pluginVars.contactListHWND) && (itrN->hWnd != pluginVars.contactListHWND)) + continue; + + // itrC проверяется в начале функции + UINT incCount = 0; + bool isItrInList = true; + while (itrN->eState != WINDOW_STATE_NORMAL) + { + ++itrN; + ++incCount; + if (itrN == pluginVars.allWindows.end()) + { + isItrInList = false; + break; + } + } + if (! isItrInList) + break; + + sWndCoords wndCoord; + if (calcNewWindowPosition(itrC->hWnd, itrN->hWnd, &wndCoord, (pluginVars.Options.DrivenWindowPos == ASW_CLWINDOWPOS_RIGHT) ? WINDOW_POSITION_RIGHT : WINDOW_POSITION_LEFT)) + SetWindowPos(itrN->hWnd, itrC->hWnd, wndCoord.x, wndCoord.y, wndCoord.width, wndCoord.height, SWP_NOACTIVATE); + + itrN->saveRect(); + + for (; incCount != 0; incCount--) + ++itrC; + } + } + + // Просмотр окон от текущего до начала + windowsList::reverse_iterator ritrC = windowFindRevItr(hWnd); + if (ritrC != pluginVars.allWindows.rend()) + { + windowsList::reverse_iterator ritrN = ++windowFindRevItr(hWnd); + for (; ritrC != pluginVars.allWindows.rend(), ritrN != pluginVars.allWindows.rend(); ++ritrC, ++ritrN) + { + // Режим только двух окон + if (pluginVars.Options.WindowsMerging == ASW_WINDOWS_MERGEONE) + if ((ritrC->hWnd != pluginVars.contactListHWND) && (ritrN->hWnd != pluginVars.contactListHWND)) + continue; + + UINT incCount = 0; + bool isItrInList = true; + while (ritrN->eState != WINDOW_STATE_NORMAL) + { + ++ritrN; + ++incCount; + if (ritrN == pluginVars.allWindows.rend()) + { + isItrInList = false; + break; + } + } + if (! isItrInList) + break; + + sWndCoords wndCoord; + if (calcNewWindowPosition(ritrC->hWnd, ritrN->hWnd, &wndCoord, (pluginVars.Options.DrivenWindowPos == ASW_CLWINDOWPOS_RIGHT) ? WINDOW_POSITION_LEFT : WINDOW_POSITION_RIGHT)) + SetWindowPos(ritrN->hWnd, ritrC->hWnd, wndCoord.x, wndCoord.y, wndCoord.width, wndCoord.height, SWP_NOACTIVATE); + + ritrN->saveRect(); + + for (; incCount != 0; incCount--) + ++ritrC; + } + } + + if (sWindowInfo* wndInfo = windowFind(hWnd)) + wndInfo->saveRect(); +} + +void allWindowsActivation(HWND hWnd) +{ + if (sWindowInfo* wndInfo = windowFind(hWnd)) + { + WindowState wndState = wndInfo->eState; + for (windowsList::iterator itr = pluginVars.allWindows.begin(); itr != pluginVars.allWindows.end(); ++itr) + { + if (itr->hWnd == hWnd) + continue; + + switch (wndState) + { + // Восстанавливаем все окна и выстаиваем на переднем плане + case WINDOW_STATE_NORMAL: + ShowWindow(itr->hWnd, SW_SHOWNA); + ShowWindow(itr->hWnd, SW_RESTORE); + SetWindowPos(itr->hWnd, hWnd, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW | SWP_NOACTIVATE); + itr->eState = WINDOW_STATE_NORMAL; + break; + // Прячем окна диалогов, окно КЛ - скрываем + case WINDOW_STATE_MINIMIZED: + if (itr->hWnd != pluginVars.contactListHWND) + ShowWindow(itr->hWnd, SW_MINIMIZE); + else + ShowWindow(itr->hWnd, SW_HIDE); + itr->eState = WINDOW_STATE_MINIMIZED; + break; + // Прячем все окна + case WINDOW_STATE_HIDDEN: + case WINDOW_STATE_CLOSED: + ShowWindow(itr->hWnd, SW_HIDE); + itr->eState = WINDOW_STATE_HIDDEN; + break; + } + } + } +} + +void windowChangeState(HWND hWnd, WPARAM cmd, LPARAM) +{ + if (sWindowInfo* wndInfo = windowFind(hWnd)) + { + switch (cmd) + { + case SC_CLOSE: + wndInfo->eState = WINDOW_STATE_CLOSED; + windowReposition(hWnd); + break; + case SC_MAXIMIZE: + wndInfo->eState = WINDOW_STATE_MAXIMIZED; + windowReposition(hWnd); + break; + case SC_MINIMIZE: + wndInfo->eState = WINDOW_STATE_MINIMIZED; + allWindowsActivation(hWnd); + break; + case SC_RESTORE: + case SC_MOVE: + case SC_SIZE: + wndInfo->eState = WINDOW_STATE_NORMAL; + allWindowsActivation(hWnd); + windowReposition(hWnd); + break; + } + } +} + +void windowChangeState(HWND hWnd, WindowState newState) +{ + if (sWindowInfo* wndInfo = windowFind(hWnd)) + { + wndInfo->eState = newState; + switch (newState) + { + case WINDOW_STATE_NORMAL: + case WINDOW_STATE_HIDDEN: + allWindowsActivation(hWnd); + break; + } + } +} + +void windowActivation(HWND hWnd, HWND prevhWnd) +{ + // Не активируем окно, если предыдущим активным было уже привязанное окно + if (sWindowInfo* wndInfo = windowFind(prevhWnd)) + return; + + // Почему-то этот код приводит к скукоживанию КЛа / двойному восстановлению + /* + hWnd = windowGetRoot(hWnd); + if (sWindowInfo* wndInfo = windowFind(hWnd)) + { + if (wndInfo->eState == WINDOW_STATE_MINIMIZED) + ShowWindow(wndInfo->hWnd, SW_RESTORE); + if (wndInfo->eState == WINDOW_STATE_HIDDEN) + ShowWindow(wndInfo->hWnd, SW_SHOW); + wndInfo->eState = WINDOW_STATE_NORMAL; + + allWindowsActivation(hWnd); + } + */ + + for (windowsList::iterator itr = pluginVars.allWindows.begin(); itr != pluginVars.allWindows.end(); ++itr) + if (itr->hWnd != hWnd) + { + if (itr->eState == WINDOW_STATE_MINIMIZED) + { + ShowWindow(itr->hWnd, SW_RESTORE); + // itr->eState = WINDOW_STATE_NORMAL; - ведет к глюкам + } + SetWindowPos(itr->hWnd, hWnd, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE); + } +} + +LRESULT CALLBACK wndProcSync(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + if (! pluginIsAlreadyRunning()) + { + pluginSetProgress(); + + windowListUpdate(); + + switch (msg) + { + case WM_SYSCOMMAND: + windowChangeState(hWnd, wParam, lParam); + break; + case WM_SIZE: + allWindowsMoveAndSize(hWnd); + break; + case WM_MOVE: + allWindowsMoveAndSize(hWnd); + break; + case WM_SHOWWINDOW: + windowChangeState(hWnd, wParam ? WINDOW_STATE_NORMAL : WINDOW_STATE_HIDDEN); + allWindowsMoveAndSize(hWnd); + break; + case WM_ACTIVATE: + if (wParam) + windowActivation(hWnd, (HWND) lParam); + break; + //case WM_ACTIVATEAPP: + // if (! wParam) + // windowActivation(hWnd, 0); + // break; + } + + pluginSetDone(); + } + + if (sWindowInfo* wndInfo = windowFind(hWnd)) + return CallWindowProc(wndInfo->pPrevWndProc, hWnd, msg, wParam, lParam); + else + return 0; +} + +bool calcNewWindowPosition(HWND hWndLeading, HWND hWndDriven, sWndCoords* wndCoord, eWindowPosition wndPos) +{ + RECT rWndLeading, rWndDriven; + + if (! GetWindowRect(hWndLeading, &rWndLeading) || ! GetWindowRect(hWndDriven, &rWndDriven)) + return false; + + wndCoord->width = rWndDriven.right - rWndDriven.left; + wndCoord->height = rWndLeading.bottom - rWndLeading.top; + wndCoord->y = rWndLeading.top; + if (wndPos == WINDOW_POSITION_RIGHT) + wndCoord->x = rWndLeading.left - wndCoord->width; + else if (wndPos == WINDOW_POSITION_LEFT) + wndCoord->x = rWndLeading.right; + + return true; +} + +// end of file
\ No newline at end of file |