aboutsummaryrefslogtreecommitdiff
path: root/RadTerminalFrame.cpp
blob: b6c8cd54b685fe01f82611dc1c5dca3537a2b105 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
#include <windows.h>
#include <windowsx.h>
#include <vector>
#include "WinUtils.h"
#include "resource.h"

#define PROJ_NAME TEXT("RadTerminal")
#define PROJ_CODE TEXT("RadTerminal")
#define REG_BASE  TEXT("Software\\RadSoft\\") PROJ_CODE

HWND ActionNewWindow(HWND hWnd, bool bParseCmdLine, const std::tstring& profile);
LRESULT CALLBACK RadTerminalMDIFrameProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);

HWND CreateRadTerminalFrame(HINSTANCE hInstance)
{
    WNDCLASS wcMDIFrame = {};

    wcMDIFrame.lpfnWndProc = RadTerminalMDIFrameProc;
    wcMDIFrame.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_ICON1));
    wcMDIFrame.hCursor = LoadCursor(NULL, IDC_ARROW);
    //wcMDIFrame.hbrBackground = GetSysColorBrush(COLOR_WINDOW);
    wcMDIFrame.hInstance = hInstance;
    wcMDIFrame.lpszClassName = TEXT("MDIRadTerminal");

    ATOM atomFrame = RegisterClass(&wcMDIFrame);
    if (atomFrame == NULL)
        return NULL;

    HWND hFrame = CreateWindow(
        MAKEINTATOM(atomFrame),
        PROJ_NAME,
        WS_OVERLAPPEDWINDOW,
        CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
        NULL,       // Parent window
        LoadMenu(hInstance, MAKEINTRESOURCE(IDR_MENU1)),       // Menu
        hInstance,
        nullptr
    );
    if (hFrame == NULL)
        return NULL;

    return hFrame;
}

inline LRESULT MyDefFrameWindowProc(_In_ HWND hWnd, _In_ UINT Msg, _In_ WPARAM wParam, _In_ LPARAM lParam)
{
    if (Msg == WM_DPICHANGED)
    {
        RECT* const prcNewWindow = (RECT*) lParam;
        SetWindowPos(hWnd,
            NULL,
            prcNewWindow->left,
            prcNewWindow->top,
            prcNewWindow->right - prcNewWindow->left,
            prcNewWindow->bottom - prcNewWindow->top,
            SWP_NOZORDER | SWP_NOACTIVATE);
    }

    return DefFrameProc(hWnd, GetMDIClient(hWnd), Msg, wParam, lParam);
}

struct RadTerminalFrameData
{
    std::vector<std::tstring> profiles;
};

BOOL RadTerminalFrameOnCreate(HWND hWnd, LPCREATESTRUCT lpCreateStruct)
{
    FORWARD_WM_CREATE(hWnd, lpCreateStruct, MyDefFrameWindowProc);
    const HINSTANCE hInst = GetWindowInstance(hWnd);

    RadTerminalFrameData* const data = new RadTerminalFrameData;
    SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR) data);

    CLIENTCREATESTRUCT ccs = {};
    HMENU hMenu = GetMenu(hWnd);
    ccs.hWindowMenu = GetSubMenu(hMenu, GetMenuItemCount(hMenu) - 1);
    ccs.idFirstChild = IDM_WINDOWCHILD;

    {
        HKEY hMainKey = NULL;
        if (RegOpenKey(HKEY_CURRENT_USER, REG_BASE TEXT("\\Profiles"), &hMainKey) == ERROR_SUCCESS)
        {
            const std::tstring strDefault = RegGetString(HKEY_CURRENT_USER, REG_BASE, TEXT("Profile"), TEXT("Cmd"));
            std::tstring strName;
            for (DWORD i = 0; RegEnumKeyEx(hMainKey, i, strName); ++i)
            {
                data->profiles.push_back(strName);
                if (strName != TEXT("Default"))
                {
                    MENUITEMINFO mii = {};
                    mii.cbSize = sizeof(mii);
                    mii.fMask = MIIM_ID | MIIM_STRING | MIIM_STATE;
                    mii.fType = MFT_STRING;
                    if (strName == strDefault)
                        mii.fState |= MFS_DEFAULT;
                    mii.wID = ID_NEW_PROFILE_1 + i;
                    mii.dwTypeData = (LPTSTR) strName.c_str();
                    InsertMenuItem(hMenu, ID_NEW_PLACEHOLDER, FALSE, &mii);
                }
            }
            DeleteMenu(hMenu, ID_NEW_PLACEHOLDER, MF_BYCOMMAND);
            RegCloseKey(hMainKey);
        }

        if (data->profiles.empty())
        {
            std::tstring strName = TEXT("Cmd");

            data->profiles.push_back(strName);
            MENUITEMINFO mii = {};
            mii.cbSize = sizeof(mii);
            mii.fMask = MIIM_ID | MIIM_STRING | MIIM_STATE;
            mii.fType = MFT_STRING;
            mii.fState |= MFS_DEFAULT;
            mii.wID = ID_NEW_PROFILE_1;
            mii.dwTypeData = (LPTSTR) strName.c_str();
            InsertMenuItem(hMenu, ID_NEW_PLACEHOLDER, FALSE, &mii);
            DeleteMenu(hMenu, ID_NEW_PLACEHOLDER, MF_BYCOMMAND);
        }
    }

    HWND hWndMDIClient = CreateWindow(TEXT("MDICLIENT"), (LPCTSTR) NULL,
        WS_CHILD | WS_CLIPCHILDREN | WS_VSCROLL | WS_HSCROLL,
        0, 0, 0, 0, hWnd, (HMENU) 0, hInst, (LPSTR) &ccs);
    if (hWndMDIClient == NULL)
        return FALSE;

    ShowWindow(hWndMDIClient, SW_SHOW);

    return TRUE;
}

void RadTerminalFrameOnDestroy(HWND hWnd)
{
    FORWARD_WM_DESTROY(hWnd, MyDefFrameWindowProc);
    const RadTerminalFrameData* const data = (RadTerminalFrameData*) GetWindowLongPtr(hWnd, GWLP_USERDATA);
    PostQuitMessage(0);
    delete data;
    SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR) nullptr);
}

void RadTerminalFrameOnSizing(HWND hWnd, UINT edge, LPRECT prRect)
{
    FORWARD_WM_SIZING(hWnd, edge, prRect, MyDefFrameWindowProc);
    HWND hWndMDIClient = GetMDIClient(hWnd);
    BOOL bMaximized = FALSE;
    HWND hActive = GetMDIActive(hWndMDIClient, &bMaximized);
    if (hActive != NULL && bMaximized)
    {
        const UINT dpi = GetDpiForWindow(hWnd);
        FORWARD_WM_SIZING(hActive, edge, prRect, SendMessage);
        UnadjustWindowRectExForDpi(prRect, GetWindowStyle(hActive), GetMenu(hActive) != NULL, GetWindowExStyle(hActive), dpi);
        AdjustWindowRectExForDpi(prRect, GetWindowStyle(hWnd), GetMenu(hWnd) != NULL, GetWindowExStyle(hWnd), dpi);
    }
}

void RadTerminalFrameOnCommand(HWND hWnd, int id, HWND hWndCtl, UINT codeNotify)
{
    const HWND hWndMDIClient = GetMDIClient(hWnd);
    const RadTerminalFrameData* const data = (RadTerminalFrameData*) GetWindowLongPtr(hWnd, GWLP_USERDATA);

    switch (id)
    {
    case ID_FILE_NEW:   ActionNewWindow(hWnd, false, TEXT(""));  break;
    case ID_NEW_PROFILE_1: case ID_NEW_PROFILE_2: case ID_NEW_PROFILE_3:
    case ID_NEW_PROFILE_4: case ID_NEW_PROFILE_5: case ID_NEW_PROFILE_6:
    case ID_NEW_PROFILE_7: case ID_NEW_PROFILE_8: case ID_NEW_PROFILE_9:
        ActionNewWindow(hWnd, false, data->profiles[id - ID_NEW_PROFILE_1]);  break;
    case ID_FILE_EXIT:  PostMessage(hWnd, WM_CLOSE, 0, 0);  break;
    case ID_WINDOW_CASCADE:  CascadeWindows(hWndMDIClient, 0, nullptr, 0, nullptr);  break;
    case ID_WINDOW_TILEHORIZONTALLY:  TileWindows(hWndMDIClient, MDITILE_HORIZONTAL, nullptr, 0, nullptr);  break;
    case ID_WINDOW_TILEVERTICALLY:  TileWindows(hWndMDIClient, MDITILE_VERTICAL, nullptr, 0, nullptr);  break;

    case ID_EDIT_PASTE:
    case ID_VIEW_SCROLL_UP: case ID_VIEW_SCROLL_DOWN:
    case ID_FILE_CLOSE: FORWARD_WM_COMMAND(GetMDIActive(hWndMDIClient), id, hWndCtl, codeNotify, SendMessage);  break;

    default:    FORWARD_WM_COMMAND(hWnd, id, hWndCtl, codeNotify, MyDefFrameWindowProc); break;
    }
}

LRESULT CALLBACK RadTerminalMDIFrameProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    switch (uMsg)
    {
        HANDLE_MSG(hWnd, WM_CREATE, RadTerminalFrameOnCreate);
        HANDLE_MSG(hWnd, WM_DESTROY, RadTerminalFrameOnDestroy);
        HANDLE_MSG(hWnd, WM_SIZING, RadTerminalFrameOnSizing);
        HANDLE_MSG(hWnd, WM_COMMAND, RadTerminalFrameOnCommand);
    default: return MyDefFrameWindowProc(hWnd, uMsg, wParam, lParam);
    }
}