diff options
Diffstat (limited to 'plugins/AsSingleWindow')
-rw-r--r-- | plugins/AsSingleWindow/AsSingleWindow.vcxproj | 33 | ||||
-rw-r--r-- | plugins/AsSingleWindow/AsSingleWindow.vcxproj.filters | 4 | ||||
-rw-r--r-- | plugins/AsSingleWindow/docs/README.md | 3 | ||||
-rw-r--r-- | plugins/AsSingleWindow/res/optionsPage.rc | bin | 0 -> 8388 bytes | |||
-rw-r--r-- | plugins/AsSingleWindow/src/AsSingleWindow.cpp | 96 | ||||
-rw-r--r-- | plugins/AsSingleWindow/src/AsSingleWindow.h | 47 | ||||
-rw-r--r-- | plugins/AsSingleWindow/src/Options.cpp | 129 | ||||
-rw-r--r-- | plugins/AsSingleWindow/src/Options.h | 31 | ||||
-rw-r--r-- | plugins/AsSingleWindow/src/WindowsManager.cpp | 490 | ||||
-rw-r--r-- | plugins/AsSingleWindow/src/WindowsManager.h | 62 | ||||
-rw-r--r-- | plugins/AsSingleWindow/src/resource.h | 25 | ||||
-rw-r--r-- | plugins/AsSingleWindow/src/stdafx.cxx | 18 | ||||
-rw-r--r-- | plugins/AsSingleWindow/src/stdafx.h | 26 |
13 files changed, 964 insertions, 0 deletions
diff --git a/plugins/AsSingleWindow/AsSingleWindow.vcxproj b/plugins/AsSingleWindow/AsSingleWindow.vcxproj new file mode 100644 index 0000000000..fe4006f613 --- /dev/null +++ b/plugins/AsSingleWindow/AsSingleWindow.vcxproj @@ -0,0 +1,33 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup Label="ProjectConfigurations"> + <ProjectConfiguration Include="Debug|Win32"> + <Configuration>Debug</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug|x64"> + <Configuration>Debug</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|Win32"> + <Configuration>Release</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|x64"> + <Configuration>Release</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + </ItemGroup> + <PropertyGroup Label="Globals"> + <ProjectGuid>{CE6A5A24-EA88-4E67-BDF2-22517528E43F}</ProjectGuid> + <RootNamespace>AsSingleWindow</RootNamespace> + </PropertyGroup> + <ImportGroup Label="PropertySheets"> + <Import Project="$(ProjectDir)..\..\build\vc.common\plugin.props" /> + </ImportGroup> + <ItemDefinitionGroup> + <ClCompile> + <ExceptionHandling>Sync</ExceptionHandling> + </ClCompile> + </ItemDefinitionGroup> +</Project>
\ No newline at end of file diff --git a/plugins/AsSingleWindow/AsSingleWindow.vcxproj.filters b/plugins/AsSingleWindow/AsSingleWindow.vcxproj.filters new file mode 100644 index 0000000000..fcae13a9d8 --- /dev/null +++ b/plugins/AsSingleWindow/AsSingleWindow.vcxproj.filters @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <Import Project="$(ProjectDir)..\..\build\vc.common\common.filters" /> +</Project>
\ No newline at end of file diff --git a/plugins/AsSingleWindow/docs/README.md b/plugins/AsSingleWindow/docs/README.md new file mode 100644 index 0000000000..280b4c127a --- /dev/null +++ b/plugins/AsSingleWindow/docs/README.md @@ -0,0 +1,3 @@ +# AsSingleWindow - Miranda messenger plugin + +All information can be found on my blog: http://soar.name/tag/assinglewindow/ diff --git a/plugins/AsSingleWindow/res/optionsPage.rc b/plugins/AsSingleWindow/res/optionsPage.rc Binary files differnew file mode 100644 index 0000000000..162fe8f496 --- /dev/null +++ b/plugins/AsSingleWindow/res/optionsPage.rc diff --git a/plugins/AsSingleWindow/src/AsSingleWindow.cpp b/plugins/AsSingleWindow/src/AsSingleWindow.cpp new file mode 100644 index 0000000000..757882f7b1 --- /dev/null +++ b/plugins/AsSingleWindow/src/AsSingleWindow.cpp @@ -0,0 +1,96 @@ +#include "stdafx.h" +#include "AsSingleWindow.h" +#include "Options.h" +#include "WindowsManager.h" + +CLIST_INTERFACE *pcli; +int hLangpack; + +PLUGININFOEX pluginInfo = { + sizeof(PLUGININFOEX), // PLUGININFOEX + "AsSingleWindow", + PLUGIN_MAKE_VERSION(0, 1, 2, 1), + "Makes easier windows manipulation: allows you to move, minimize and activate Miranda's windows as if it were a single window.", + "Aleksey Smyrnov aka Soar", + "i@soar.name", + "(c) Soar, 2010-2011", + "http://soar.name/tag/assinglewindow/", + UNICODE_AWARE, + {0xF6C73B4, 0x2B2B, 0x711D, {0xFB, 0xB6, 0xBB, 0x26, 0x7D, 0xFD, 0x72, 0x08}}, // 0xF6C73B42B2B711DFBB6BB267DFD7208 +}; + +sPluginVars pluginVars; + +bool WINAPI DllMain(HINSTANCE hInstDLL, DWORD, LPVOID) +{ + pluginVars.hInst = hInstDLL; + return true; +} + +static const MUUID interfaces[] = {MIID_CLIST, MIID_SRMM, MIID_LAST}; +extern "C" __declspec(dllexport) const MUUID* MirandaPluginInterfaces(void) +{ + return interfaces; +} + +extern "C" __declspec(dllexport) PLUGININFOEX* MirandaPluginInfoEx(DWORD) +{ + return &pluginInfo; +} + +extern "C" __declspec(dllexport) int Load(void) +{ + mir_getLP(&pluginInfo); + pcli = Clist_GetInterface(); + + ::InitializeCriticalSection(&pluginVars.m_CS); + pluginVars.IsUpdateInProgress = false; + pluginVars.heModulesLoaded = HookEvent(ME_SYSTEM_MODULESLOADED, OnModulesLoaded); + pluginVars.heOptionsLoaded = HookEvent(ME_OPT_INITIALISE, InitOptions); + + return 0; +} + +extern "C" __declspec(dllexport) int Unload(void) +{ + UnhookEvent(pluginVars.heOptionsLoaded); + UnhookEvent(pluginVars.heModulesLoaded); + + ::DeleteCriticalSection(&pluginVars.m_CS); + + return 0; +} + +int OnModulesLoaded(WPARAM, LPARAM) +{ + HWND hWndCListWindow = pcli->hwndContactList; + windowAdd(hWndCListWindow, true); + + pluginVars.heMsgWndEvent = HookEvent(ME_MSG_WINDOWEVENT, MsgWindowEvent); + + optionsLoad(); + + return 0; +} + + +int MsgWindowEvent(WPARAM, LPARAM lParam) +{ + MessageWindowEventData* data = (MessageWindowEventData*) lParam; + + if (data == NULL) + return 0; + + switch (data->uType) + { + // Здесь можно отлавливать только открытие окна, + // т.к. закрытие может быть закрытием вкладки + case MSG_WINDOW_EVT_OPEN: + windowAdd(data->hwndWindow, false); + break; + } + + return 0; +} + +// end of file
\ No newline at end of file diff --git a/plugins/AsSingleWindow/src/AsSingleWindow.h b/plugins/AsSingleWindow/src/AsSingleWindow.h new file mode 100644 index 0000000000..e32bc6f948 --- /dev/null +++ b/plugins/AsSingleWindow/src/AsSingleWindow.h @@ -0,0 +1,47 @@ +#pragma once + +#ifndef _ASSINGLEWINDOW_H +#define _ASSINGLEWINDOW_H + +#include "stdafx.h" +#include "WindowsManager.h" + +#define ASW_CLWINDOWPOS_RIGHT 0x01 +#define ASW_CLWINDOWPOS_LEFT 0x02 +#define ASW_CLWINDOWPOS_DISABLED 0x03 + +#define ASW_WINDOWS_MERGEALL 0x01 +#define ASW_WINDOWS_MERGEONE 0x02 +#define ASW_WINDOWS_MERGEDISABLE 0x03 + +//typedef std::map<HWND, sWindowInfo> windowsList; +typedef std::list<sWindowInfo> windowsList; + +struct sPluginVars { + HINSTANCE hInst; + CRITICAL_SECTION m_CS; + + HWND contactListHWND; + windowsList allWindows; + + HANDLE heModulesLoaded; + HANDLE heOptionsLoaded; + HANDLE heMsgWndEvent; + + bool IsUpdateInProgress; + + struct { + UINT8 DrivenWindowPos; + UINT8 WindowsMerging; + } Options; +}; + +extern sPluginVars pluginVars; +extern PLUGININFOEX pluginInfo; + +int OnModulesLoaded(WPARAM, LPARAM); +int MsgWindowEvent(WPARAM, LPARAM); + +#endif + +// end of file
\ No newline at end of file diff --git a/plugins/AsSingleWindow/src/Options.cpp b/plugins/AsSingleWindow/src/Options.cpp new file mode 100644 index 0000000000..546c20245a --- /dev/null +++ b/plugins/AsSingleWindow/src/Options.cpp @@ -0,0 +1,129 @@ +#include "stdafx.h" +#include "AsSingleWindow.h" +#include "Options.h" +#include "resource.h" + +int InitOptions(WPARAM wParam, LPARAM) +{ + OPTIONSDIALOGPAGE Opts = { 0 }; + + Opts.szTitle.a = LPGEN("AsSingleWindow"); + Opts.szGroup.a = LPGEN("Customize"); + + Opts.pfnDlgProc = cbOptionsDialog; + Opts.pszTemplate = MAKEINTRESOURCEA(IDD_ASW_OPTIONSPAGE); + Opts.hInstance = pluginVars.hInst; + Opts.flags = ODPF_BOLDGROUPS; + + Options_AddPage(wParam, &Opts); + + return 0; +} + +INT_PTR CALLBACK cbOptionsDialog(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + switch (msg) { + case WM_INITDIALOG: + dlgProcessInit(hWnd, msg, wParam, lParam); + break; + case WM_COMMAND: + dlgProcessCommand(hWnd, msg, wParam, lParam); + break; + case WM_NOTIFY: + if (((LPNMHDR)lParam)->idFrom == 0) { + switch (((LPNMHDR)lParam)->code) { + case PSN_RESET: + optionsLoad(); + break; + case PSN_APPLY: + optionsUpdate(hWnd); + optionsSave(); + windowReposition(hWnd); // + break; + } + } + break; + case WM_DESTROY: + // free up resources + break; + } + + return false; +} + +void dlgProcessInit(HWND hWnd, UINT, WPARAM, LPARAM) +{ + TranslateDialogDefault(hWnd); + + CheckDlgButton(hWnd, IDC_RADIO_G1_RIGHTCL, (pluginVars.Options.DrivenWindowPos == ASW_CLWINDOWPOS_RIGHT)); + CheckDlgButton(hWnd, IDC_RADIO_G1_LEFTCL, (pluginVars.Options.DrivenWindowPos == ASW_CLWINDOWPOS_LEFT)); + CheckDlgButton(hWnd, IDC_RADIO_G1_DONTMERGEWINDOWS, (pluginVars.Options.DrivenWindowPos == ASW_CLWINDOWPOS_DISABLED)); + + CheckDlgButton(hWnd, IDC_RADIO_G2_MERGEALL, (pluginVars.Options.WindowsMerging == ASW_WINDOWS_MERGEALL)); + CheckDlgButton(hWnd, IDC_RADIO_G2_MERGEONE, (pluginVars.Options.WindowsMerging == ASW_WINDOWS_MERGEONE)); + CheckDlgButton(hWnd, IDC_RADIO_G2_DISABLEMERGE, (pluginVars.Options.WindowsMerging == ASW_WINDOWS_MERGEDISABLE)); + + dlgUpdateControls(hWnd); +} + +void dlgProcessCommand(HWND hWnd, UINT, WPARAM wParam, LPARAM) +{ + WORD idCtrl = LOWORD(wParam); + WORD idNotifyCode = HIWORD(wParam); + + switch (idCtrl) + { + case IDC_RADIO_G1_LEFTCL: + case IDC_RADIO_G1_RIGHTCL: + case IDC_RADIO_G1_DONTMERGEWINDOWS: + if (idNotifyCode == BN_CLICKED) + { + dlgUpdateControls(hWnd); + SendMessage(GetParent(hWnd), PSM_CHANGED, 0, 0); + } + break; + case IDC_RADIO_G2_MERGEALL: + case IDC_RADIO_G2_MERGEONE: + case IDC_RADIO_G2_DISABLEMERGE: + if (idNotifyCode == BN_CLICKED) + SendMessage(GetParent(hWnd), PSM_CHANGED, 0, 0); + break; + } +} + +void dlgUpdateControls(HWND hWnd) +{ + UINT idState; + + idState = IsDlgButtonChecked(hWnd, IDC_RADIO_G1_DONTMERGEWINDOWS); + EnableWindow(GetDlgItem(hWnd, IDC_RADIO_G2_MERGEALL), ! idState); + EnableWindow(GetDlgItem(hWnd, IDC_RADIO_G2_MERGEONE), ! idState); + EnableWindow(GetDlgItem(hWnd, IDC_RADIO_G2_DISABLEMERGE), ! idState); +} + +void optionsLoad() +{ + pluginVars.Options.DrivenWindowPos = db_get_b(0, SETTINGSNAME, "DrivenWindowPosition", ASW_CLWINDOWPOS_RIGHT); + pluginVars.Options.WindowsMerging = db_get_b(0, SETTINGSNAME, "WindowsMerging", ASW_WINDOWS_MERGEONE); +} + +void optionsUpdate(HWND hWnd) +{ + pluginVars.Options.DrivenWindowPos = + (IsDlgButtonChecked(hWnd, IDC_RADIO_G1_LEFTCL) * ASW_CLWINDOWPOS_LEFT) + + (IsDlgButtonChecked(hWnd, IDC_RADIO_G1_RIGHTCL) * ASW_CLWINDOWPOS_RIGHT) + + (IsDlgButtonChecked(hWnd, IDC_RADIO_G1_DONTMERGEWINDOWS) * ASW_CLWINDOWPOS_DISABLED); + + pluginVars.Options.WindowsMerging = + (IsDlgButtonChecked(hWnd, IDC_RADIO_G2_MERGEALL) * ASW_WINDOWS_MERGEALL) + + (IsDlgButtonChecked(hWnd, IDC_RADIO_G2_MERGEONE) * ASW_WINDOWS_MERGEONE) + + (IsDlgButtonChecked(hWnd, IDC_RADIO_G2_DISABLEMERGE) * ASW_WINDOWS_MERGEDISABLE); +} + +void optionsSave() +{ + db_get_b(0, SETTINGSNAME, "DrivenWindowPosition", pluginVars.Options.DrivenWindowPos); + db_get_b(0, SETTINGSNAME, "WindowsMerging", pluginVars.Options.WindowsMerging); +} + +// end of file
\ No newline at end of file diff --git a/plugins/AsSingleWindow/src/Options.h b/plugins/AsSingleWindow/src/Options.h new file mode 100644 index 0000000000..f7519ed554 --- /dev/null +++ b/plugins/AsSingleWindow/src/Options.h @@ -0,0 +1,31 @@ +#pragma once + +#ifndef _OPTIONS_H +#define _OPTIONS_H + +#define SETTINGSNAME "AsSingleWindow" + +#ifdef UNICODE +#define LPGENSTR LPGENT +#define DBGetString DBGetContactSettingTString +#define DBWriteString DBWriteContactSettingTString +#else +#define LPGENSTR LPGEN +#define DBGetString DBGetContactSettingString +#define DBWriteString DBWriteContactSettingString +#endif + +int InitOptions(WPARAM wParam, LPARAM lParam); +INT_PTR CALLBACK cbOptionsDialog(HWND, UINT, WPARAM, LPARAM); + +void dlgProcessInit(HWND, UINT, WPARAM, LPARAM); +void dlgProcessCommand(HWND, UINT, WPARAM, LPARAM); +void dlgUpdateControls(HWND); + +void optionsLoad(); +void optionsUpdate(HWND); +void optionsSave(); + +#endif + +// end of file
\ No newline at end of file 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 diff --git a/plugins/AsSingleWindow/src/WindowsManager.h b/plugins/AsSingleWindow/src/WindowsManager.h new file mode 100644 index 0000000000..e47c03655e --- /dev/null +++ b/plugins/AsSingleWindow/src/WindowsManager.h @@ -0,0 +1,62 @@ +#pragma once + +#ifndef WINDOWSMANAGER_H +#define WINDOWSMANAGER_H + +#include "stdafx.h" + +enum WindowState { + WINDOW_STATE_NORMAL, + WINDOW_STATE_MINIMIZED, + WINDOW_STATE_MAXIMIZED, + WINDOW_STATE_HIDDEN, + WINDOW_STATE_CLOSED, // not used ? +}; + +enum eWindowPosition { + WINDOW_POSITION_LEFT = 1, + WINDOW_POSITION_RIGHT = 2, +}; + +struct sWndCoords { + LONG x, y, width, height; +}; + +struct sWindowInfo { + HWND hWnd; + WindowState eState; + WNDPROC pPrevWndProc; + RECT rLastSavedPosition; + + void saveState(); + void saveRect(); + //void restoreRect(); +}; + +// critical section tools +void pluginSetProgress(); +void pluginSetDone(); +bool pluginIsAlreadyRunning(); + +// system +sWindowInfo* windowFind(HWND); +//windowsList::iterator windowFindItr(HWND); +//windowsList::reverse_iterator windowFindRevItr(HWND); +void windowAdd(HWND, bool); +//void windowRemove(HWND); +HWND windowGetRoot(HWND); +void windowListUpdate(); +void windowReposition(HWND); + +// tools +bool calcNewWindowPosition(HWND, HWND, sWndCoords*, eWindowPosition); +//LONG calcNewWindowPosition(HWND, HWND, RECT*, eWindowPosition); + +// window callbacks +LRESULT CALLBACK wndProcSync(HWND, UINT, WPARAM, LPARAM); +void allWindowsMoveAndSize(HWND); +void allWindowsActivation(HWND); + +#endif WINDOWSMANAGER_H + +// end of file
\ No newline at end of file diff --git a/plugins/AsSingleWindow/src/resource.h b/plugins/AsSingleWindow/src/resource.h new file mode 100644 index 0000000000..fdaced196e --- /dev/null +++ b/plugins/AsSingleWindow/src/resource.h @@ -0,0 +1,25 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by optionsPage.rc +// +#define IDD_ASW_OPTIONSPAGE 103 +#define IDC_RADIO_G1_LEFTCL 1002 +#define IDC_RADIO_G1_RIGHTCL 1003 +#define IDC_RADIO_G1_DONTMERGEWINDOWS 1004 +#define IDC_RADIO_G2_MERGEALL 1005 +#define IDC_RADIO_G2_MERGEONE 1006 +#define IDC_RADIO_G2_DISABLEMERGE 1007 +#define IDC_STATIC_G1 1008 +#define IDC_STATIC_G2 1009 +#define IDC_CHECK_SHIFTMOVING 1010 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 102 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1011 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/plugins/AsSingleWindow/src/stdafx.cxx b/plugins/AsSingleWindow/src/stdafx.cxx new file mode 100644 index 0000000000..8279ea6a37 --- /dev/null +++ b/plugins/AsSingleWindow/src/stdafx.cxx @@ -0,0 +1,18 @@ +/* +Copyright (C) 2012-17 Miranda NG project (https://miranda-ng.org) + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation version 2 +of the License. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "stdafx.h"
\ No newline at end of file diff --git a/plugins/AsSingleWindow/src/stdafx.h b/plugins/AsSingleWindow/src/stdafx.h new file mode 100644 index 0000000000..a7e42fdf90 --- /dev/null +++ b/plugins/AsSingleWindow/src/stdafx.h @@ -0,0 +1,26 @@ +#pragma once + +#define WIN32_LEAN_AND_MEAN + +// Файлы заголовков Windows: +#include <windows.h> +#include <stdio.h> +#include <stdlib.h> +#include <iostream> +#include <CommCtrl.h> +#include <list> +#include <algorithm> + +// Miranda headers +#include "newpluginapi.h" +#include "m_system.h" +#include "m_langpack.h" +#include "m_database.h" +#include "m_message.h" +#include "m_clist.h" +#include "m_clistint.h" +//#include "m_clui.h" +#include "m_options.h" +//#include "m_plugins.h" + +// end of file
\ No newline at end of file |