window.cc revision 706f2543
1/*
2 * Copyright (c) 2005 Alexander Gottwald
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20 * DEALINGS IN THE SOFTWARE.
21 *
22 * Except as contained in this notice, the name(s) of the above copyright
23 * holders shall not be used in advertising or otherwise to promote the sale,
24 * use or other dealings in this Software without prior written authorization.
25 */
26
27#include "window.h"
28#include "util.h"
29#include <stdio.h>
30#include <stdexcept>
31
32CWindow::CWindowClass CWindow::windowClass("CWINDOWCLASS", DefWindowProc);
33
34CWindow::CWindowClass::CWindowClass(const char *_name, WNDPROC _wndproc) :
35    wndproc(_wndproc), atom(0), classname(_name)
36{
37    Register();
38}
39
40CWindow::CWindowClass::~CWindowClass()
41{
42    UnregisterClass(classname.c_str(), GetModuleHandle(NULL));
43}
44
45void CWindow::CWindowClass::Register()
46{
47    WNDCLASSEX wndclass;
48    memset(&wndclass, 0, sizeof(wndclass));
49    wndclass.cbSize = sizeof(wndclass);
50    wndclass.style = 0;
51    wndclass.lpfnWndProc = wndproc;
52    wndclass.cbClsExtra = 0;
53    wndclass.cbWndExtra = 0;
54    wndclass.hInstance = GetModuleHandle(NULL);
55    wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
56    wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
57    wndclass.hbrBackground = (HBRUSH)(1 + COLOR_BTNFACE);
58    wndclass.lpszMenuName = NULL;
59    wndclass.lpszClassName = classname.c_str();
60    wndclass.hIconSm = NULL;
61    atom = RegisterClassEx(&wndclass);
62    if (atom == 0)
63        throw win32_error("RegisterClassEx failed");
64}
65
66CWindow::CWindow(const char *_title) : title(_title), hwnd(NULL), parent(NULL), bounds(), owndproc(NULL), showing(FALSE)
67{
68    style = WS_CHILD;
69    exstyle = 0;
70}
71
72HWND CWindow::CreateWindowHandle()
73{
74    HWND ret = CreateWindowEx(
75            exstyle,
76            GetClassName(),
77            title.c_str(),
78            style,
79            bounds.left,
80            bounds.top,
81            bounds.width,
82            bounds.height,
83            parent,
84            NULL,
85            GetModuleHandle(NULL),
86            0
87            );
88    if (ret == NULL)
89        throw win32_error("CreateWindowEx failed");
90    return ret;
91}
92
93void CWindow::Create()
94{
95    if (hwnd != NULL)
96        return;
97    hwnd = CreateWindowHandle();
98    if (hwnd == NULL)
99        throw win32_error("Could not create window");
100
101    // Reset the error code
102    DWORD err = 0;
103    SetLastError(err);
104
105    // Attach the object reference to the window handle
106    SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)this);
107    err = GetLastError();
108    if (err != 0)
109        throw win32_error("SetWindowLongPtr failed",err);
110
111    // Set the window proc
112    owndproc = (WNDPROC)SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)WindowProc);
113    err = GetLastError();
114    if (err != 0)
115        throw win32_error("SetWindowLongPtr failed",err);
116}
117
118const char *CWindow::GetClassName()
119{
120    return windowClass.GetClassName();
121}
122
123LRESULT CALLBACK CWindow::WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
124{
125    MessageDebug::debug(hwnd, uMsg, wParam, lParam, __FUNCTION__);
126    CWindow* window = (CWindow*)GetWindowLongPtr(hwnd, GWLP_USERDATA);
127    if (window != NULL)
128        return window->Dispatch(hwnd, uMsg, wParam, lParam);
129    return DefWindowProc(hwnd, uMsg, wParam, lParam);
130}
131
132LRESULT CWindow::Dispatch(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
133{
134    switch (uMsg)
135    {
136        case WM_SIZE:
137            bounds.width = LOWORD(lParam);
138            bounds.height = LOWORD(lParam);
139            break;
140        case WM_MOVE:
141            bounds.left = LOWORD(lParam);
142            bounds.top = LOWORD(lParam);
143            break;
144        case WM_DESTROY:
145            showing = FALSE;
146            break;
147    }
148    if (owndproc)
149        return CallWindowProc(owndproc, hwnd, uMsg, wParam, lParam);
150    else
151        return DefWindowProc(hwnd, uMsg, wParam, lParam);
152}
153
154void CWindow::Show()
155{
156    if (hwnd == NULL)
157        Create();
158    ShowWindow(hwnd, SW_SHOWNORMAL);
159}
160
161int CWindow::ShowModal()
162{
163    MSG msg;
164    BOOL bRet;
165    showing = TRUE;
166    Show();
167
168    while( showing && (bRet = GetMessage( &msg, NULL, 0, 0 )) != 0)
169    {
170        if (bRet == -1)
171        {
172            // handle the error and possibly exit
173        }
174        else
175        {
176            TranslateMessage(&msg);
177            DispatchMessage(&msg);
178        }
179    }
180    return 0;
181}
182
183void CWindow::SetLeft(int left)
184{
185    bounds.left = left;
186    if (hwnd)
187        if (!SetWindowPos(hwnd, NULL,
188                bounds.left, bounds.top,
189                0, 0,
190                SWP_NOZORDER |  SWP_NOSIZE))
191            throw win32_error("SetWindowPos failed");
192}
193
194void CWindow::SetTop(int top)
195{
196    bounds.top = top;
197    if (hwnd)
198        if (!SetWindowPos(hwnd, NULL,
199                bounds.left, bounds.top,
200                0, 0,
201                SWP_NOZORDER |  SWP_NOSIZE))
202            throw win32_error("SetWindowPos failed");
203}
204
205void CWindow::SetWidth(int width)
206{
207    bounds.width = width;
208    if (hwnd)
209        if (!SetWindowPos(hwnd, NULL,
210                0, 0,
211                bounds.width, bounds.height,
212                SWP_NOZORDER |  SWP_NOMOVE))
213            throw win32_error("SetWindowPos failed");
214}
215void CWindow::SetHeight(int height)
216{
217    bounds.height = height;
218    if (hwnd)
219        if (!SetWindowPos(hwnd, NULL,
220                0, 0,
221                bounds.width, bounds.height,
222                SWP_NOZORDER |  SWP_NOMOVE))
223            throw win32_error("SetWindowPos failed");
224}
225
226void CWindow::SetBounds(int left, int top, int width, int height)
227{
228    bounds = CBoundary(left, top, width, height);
229    if (hwnd)
230        if (!SetWindowPos(hwnd, NULL,
231                bounds.left, bounds.top,
232                bounds.width, bounds.height,
233                SWP_NOZORDER))
234            throw win32_error("SetWindowPos failed");
235}
236
237void CWindow::SetBounds(const RECT &rect)
238{
239    bounds = rect;
240    if (hwnd)
241        if (!SetWindowPos(hwnd, NULL,
242                bounds.left, bounds.top,
243                bounds.width, bounds.height,
244                SWP_NOZORDER))
245            throw win32_error("SetWindowPos failed");
246}
247
248HWND CWindow::GetHandle()
249{
250    if (hwnd == NULL)
251        Create();
252    return hwnd;
253}
254
255void CWindow::SetParent(CWindow *window)
256{
257    parent = window->GetHandle();
258    if (hwnd != NULL)
259        if (::SetParent(hwnd, parent) == NULL)
260            throw win32_error("SetParent failed");
261
262}
263
264void CWindow::SetStyle(DWORD style)
265{
266    this->style = style;
267    SetLastError(0);
268    if (hwnd)
269        SetWindowLong(hwnd, GWL_STYLE, style);
270    int err = GetLastError();
271    if (err != 0)
272        throw win32_error("SetWindowLong failed", err);
273}
274
275void CWindow::SetExStyle(DWORD exstyle)
276{
277    this->exstyle = exstyle;
278    SetLastError(0);
279    if (hwnd)
280        SetWindowLong(hwnd, GWL_EXSTYLE, exstyle);
281    int err = GetLastError();
282    if (err != 0)
283        throw win32_error("SetWindowWLong failed", err);
284}
285