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 | |
| parent | cc13707adf716f558a1e85995c042e5361eec60b (diff) | |
AsSingleWindow: adopted but not working
Diffstat (limited to 'plugins/AsSingleWindow/src')
| -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 | 
9 files changed, 924 insertions, 0 deletions
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  | 
