summaryrefslogtreecommitdiff
path: root/plugins/AsSingleWindow
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/AsSingleWindow')
-rw-r--r--plugins/AsSingleWindow/AsSingleWindow.vcxproj33
-rw-r--r--plugins/AsSingleWindow/AsSingleWindow.vcxproj.filters4
-rw-r--r--plugins/AsSingleWindow/docs/README.md3
-rw-r--r--plugins/AsSingleWindow/res/optionsPage.rcbin0 -> 8388 bytes
-rw-r--r--plugins/AsSingleWindow/src/AsSingleWindow.cpp96
-rw-r--r--plugins/AsSingleWindow/src/AsSingleWindow.h47
-rw-r--r--plugins/AsSingleWindow/src/Options.cpp129
-rw-r--r--plugins/AsSingleWindow/src/Options.h31
-rw-r--r--plugins/AsSingleWindow/src/WindowsManager.cpp490
-rw-r--r--plugins/AsSingleWindow/src/WindowsManager.h62
-rw-r--r--plugins/AsSingleWindow/src/resource.h25
-rw-r--r--plugins/AsSingleWindow/src/stdafx.cxx18
-rw-r--r--plugins/AsSingleWindow/src/stdafx.h26
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
new file mode 100644
index 0000000000..162fe8f496
--- /dev/null
+++ b/plugins/AsSingleWindow/res/optionsPage.rc
Binary files differ
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