summaryrefslogtreecommitdiff
path: root/plugins/AsSingleWindow/src/WindowsManager.cpp
diff options
context:
space:
mode:
authorKirill Volinsky <mataes2007@gmail.com>2017-09-19 19:50:57 +0300
committerKirill Volinsky <mataes2007@gmail.com>2017-09-19 19:50:57 +0300
commit44eadfd2f33bf3ac4cc1c56c773f09e8cf391385 (patch)
tree65e1ef4724c620ac1471db8fce38451d7963aedb /plugins/AsSingleWindow/src/WindowsManager.cpp
parentcc13707adf716f558a1e85995c042e5361eec60b (diff)
AsSingleWindow: adopted but not working
Diffstat (limited to 'plugins/AsSingleWindow/src/WindowsManager.cpp')
-rw-r--r--plugins/AsSingleWindow/src/WindowsManager.cpp490
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