]>
Commit | Line | Data |
---|---|---|
df62e023 RC |
1 | /* |
2 | * Copyright (c) 2001, Gary R. Van Sickle. | |
3 | * | |
4 | * This program is free software; you can redistribute it and/or modify | |
5 | * it under the terms of the GNU General Public License as published by | |
6 | * the Free Software Foundation; either version 2 of the License, or | |
7 | * (at your option) any later version. | |
8 | * | |
9 | * A copy of the GNU General Public License can be found at | |
10 | * http://www.gnu.org/ | |
11 | * | |
12 | * Written by Gary R. Van Sickle <g.r.vansickle@worldnet.att.net> | |
13 | * | |
14 | */ | |
15 | ||
16 | // This is the implementation of the Window class. It serves both as a window class | |
17 | // in its own right and as a base class for other window-like classes (e.g. PropertyPage, | |
18 | // PropSheet). | |
19 | ||
20 | #include <windows.h> | |
21 | #include "window.h" | |
22 | ||
23 | ATOM Window::WindowClassAtom = 0; | |
24 | HINSTANCE Window::AppInstance = NULL; | |
25 | ||
26 | // FIXME: I know, this is brutal. Mutexing should at least make window creation threadsafe, | |
27 | // but if somebody has any ideas as to how to get rid of it entirely, please tell me / do so. | |
28 | struct REFLECTION_INFO | |
29 | { | |
30 | Window * | |
31 | This; | |
32 | bool | |
33 | FirstCall; | |
34 | }; | |
35 | REFLECTION_INFO ReflectionInfo; | |
36 | ||
37 | Window::Window () | |
38 | { | |
39 | WindowHandle = NULL; | |
40 | Parent = NULL; | |
b7301c43 | 41 | FontCounter = 0; |
df62e023 RC |
42 | } |
43 | ||
44 | Window::~Window () | |
45 | { | |
b7301c43 RC |
46 | // Delete any fonts we created. |
47 | int i; | |
48 | for (i = 0; i < FontCounter; i++) | |
49 | { | |
50 | DeleteObject (Fonts[i]); | |
51 | } | |
52 | FontCounter = 0; | |
53 | ||
df62e023 RC |
54 | // FIXME: Maybe do some reference counting and do this Unregister |
55 | // when there are no more of us left. Not real critical unless | |
56 | // we're in a DLL which we're not right now. | |
57 | //UnregisterClass(WindowClassAtom, InstanceHandle); | |
58 | } | |
59 | ||
60 | LRESULT CALLBACK | |
61 | Window::FirstWindowProcReflector (HWND hwnd, UINT uMsg, WPARAM wParam, | |
62 | LPARAM lParam) | |
63 | { | |
64 | // Get our this pointer | |
65 | REFLECTION_INFO *rip = &ReflectionInfo; | |
66 | ||
67 | if (rip->FirstCall) | |
68 | { | |
69 | rip->FirstCall = false; | |
70 | ||
71 | // Set the Window handle so the real WindowProc has one to work with. | |
72 | rip->This->WindowHandle = hwnd; | |
73 | ||
74 | // Set a backreference to this class instance in the HWND. | |
75 | // FIXME: Should really be SetWindowLongPtr(), but it appears to | |
76 | // not be defined yet. | |
77 | SetWindowLong (hwnd, GWL_USERDATA, (LONG) rip->This); | |
78 | ||
79 | // Set a new WindowProc now that we have the peliminaries done. | |
80 | // Like subclassing, only not. | |
81 | SetWindowLong (hwnd, GWL_WNDPROC, (LONG) & Window::WindowProcReflector); | |
82 | } | |
83 | ||
84 | return rip->This->WindowProc (uMsg, wParam, lParam); | |
85 | } | |
86 | ||
87 | LRESULT CALLBACK | |
88 | Window::WindowProcReflector (HWND hwnd, UINT uMsg, WPARAM wParam, | |
89 | LPARAM lParam) | |
90 | { | |
91 | Window *This; | |
92 | ||
93 | // Get our this pointer | |
94 | // FIXME: Should really be GetWindowLongPtr(), but it appears to | |
95 | // not be defined yet. | |
96 | This = (Window *) GetWindowLong (hwnd, GWL_USERDATA); | |
97 | ||
98 | return This->WindowProc (uMsg, wParam, lParam); | |
99 | } | |
100 | ||
101 | bool Window::Create (Window * parent, DWORD Style) | |
102 | { | |
103 | // First register the window class, if we haven't already | |
104 | if (RegisterWindowClass () == false) | |
105 | { | |
106 | // Registration failed | |
107 | return false; | |
108 | } | |
109 | ||
110 | // Set up the reflection info, so that the Windows window can find us. | |
111 | ReflectionInfo.This = this; | |
112 | ReflectionInfo.FirstCall = true; | |
113 | ||
114 | Parent = parent; | |
115 | ||
116 | // Create the window instance | |
117 | WindowHandle = CreateWindow ("MainWindowClass", //MAKEINTATOM(WindowClassAtom), // window class atom (name) | |
118 | "Hello", // no title-bar string yet | |
119 | // Style bits | |
120 | Style, | |
121 | // Default positions and size | |
122 | CW_USEDEFAULT, | |
123 | CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, | |
124 | // Parent Window | |
125 | parent == | |
126 | NULL ? (HWND) NULL : parent->GetHWND (), | |
127 | // use class menu | |
128 | (HMENU) NULL, | |
129 | // The application instance | |
130 | GetInstance (), (LPVOID) NULL); | |
131 | ||
132 | if (WindowHandle == NULL) | |
133 | { | |
134 | // Failed | |
135 | return false; | |
136 | } | |
137 | ||
138 | return true; | |
139 | } | |
140 | ||
141 | bool Window::RegisterWindowClass () | |
142 | { | |
143 | if (WindowClassAtom == 0) | |
144 | { | |
145 | // We're not registered yet | |
146 | WNDCLASSEX | |
147 | wc; | |
148 | ||
149 | wc.cbSize = sizeof (wc); | |
150 | // Some sensible style defaults | |
151 | wc.style = CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW; | |
152 | // Our default window procedure. This replaces itself | |
153 | // on the first call with the simpler Window::WindowProcReflector(). | |
154 | wc.lpfnWndProc = Window::FirstWindowProcReflector; | |
155 | // No class bytes | |
156 | wc.cbClsExtra = 0; | |
157 | // One pointer to REFLECTION_INFO in the extra window instance bytes | |
158 | wc.cbWndExtra = 4; | |
159 | // The app instance | |
160 | wc.hInstance = GetInstance (); | |
161 | // Use a bunch of system defaults for the GUI elements | |
162 | wc.hIcon = NULL; | |
163 | wc.hIconSm = NULL; | |
164 | wc.hCursor = NULL; | |
165 | wc.hbrBackground = (HBRUSH) (COLOR_BACKGROUND + 1); | |
166 | // No menu | |
167 | wc.lpszMenuName = NULL; | |
168 | // We'll get a little crazy here with the class name | |
169 | wc.lpszClassName = "MainWindowClass"; | |
170 | ||
171 | // All set, try to register | |
172 | WindowClassAtom = RegisterClassEx (&wc); | |
173 | ||
174 | if (WindowClassAtom == 0) | |
175 | { | |
176 | // Failed | |
177 | return false; | |
178 | } | |
179 | } | |
180 | ||
181 | // We're registered, or already were before the call, | |
182 | // return success in either case. | |
183 | return true; | |
184 | } | |
185 | ||
186 | void | |
187 | Window::Show (int State) | |
188 | { | |
189 | ::ShowWindow (WindowHandle, State); | |
190 | } | |
191 | ||
192 | void | |
193 | Window::CenterWindow () | |
194 | { | |
195 | RECT WindowRect, ParentRect; | |
196 | int WindowWidth, WindowHeight; | |
197 | POINT p; | |
198 | ||
199 | // Get the window rectangle | |
200 | GetWindowRect (GetHWND (), &WindowRect); | |
201 | ||
202 | if (GetParent () == NULL) | |
203 | { | |
204 | // Center on desktop window | |
205 | GetWindowRect (GetDesktopWindow (), &ParentRect); | |
206 | } | |
207 | else | |
208 | { | |
209 | // Center on client area of parent | |
210 | GetClientRect (GetParent ()->GetHWND (), &ParentRect); | |
211 | } | |
212 | ||
213 | WindowWidth = WindowRect.right - WindowRect.left; | |
214 | WindowHeight = WindowRect.bottom - WindowRect.top; | |
215 | ||
216 | // Find center of area we're centering on | |
217 | p.x = (ParentRect.right - ParentRect.left) / 2; | |
218 | p.y = (ParentRect.bottom - ParentRect.top) / 2; | |
219 | ||
220 | // Convert that to screen coords | |
221 | if (GetParent () == NULL) | |
222 | { | |
223 | ClientToScreen (GetDesktopWindow (), &p); | |
224 | } | |
225 | else | |
226 | { | |
227 | ClientToScreen (GetParent ()->GetHWND (), &p); | |
228 | } | |
229 | ||
230 | // Calculate new top left corner for window | |
231 | p.x -= WindowWidth / 2; | |
232 | p.y -= WindowHeight / 2; | |
233 | ||
234 | // And finally move the window | |
235 | MoveWindow (GetHWND (), p.x, p.y, WindowWidth, WindowHeight, TRUE); | |
236 | } | |
237 | ||
238 | LRESULT Window::WindowProc (UINT uMsg, WPARAM wParam, LPARAM lParam) | |
239 | { | |
240 | switch (uMsg) | |
241 | { | |
242 | default: | |
243 | return DefWindowProc (WindowHandle, uMsg, wParam, lParam); | |
244 | } | |
245 | ||
246 | return 0; | |
247 | } | |
248 | ||
249 | bool Window::MessageLoop () | |
250 | { | |
251 | MSG | |
252 | msg; | |
253 | ||
254 | while (GetMessage (&msg, NULL, 0, 0) != 0 | |
255 | && GetMessage (&msg, (HWND) NULL, 0, 0) != -1) | |
256 | { | |
257 | if (!IsWindow (WindowHandle) || !IsDialogMessage (WindowHandle, &msg)) | |
258 | { | |
259 | TranslateMessage (&msg); | |
260 | DispatchMessage (&msg); | |
261 | } | |
262 | } | |
263 | ||
264 | return true; | |
265 | } | |
266 | ||
267 | void | |
268 | Window::PostMessage (UINT uMsg, WPARAM wParam, LPARAM lParam) | |
269 | { | |
270 | ::PostMessage (GetHWND (), uMsg, wParam, lParam); | |
271 | } | |
b7301c43 RC |
272 | |
273 | UINT Window::IsButtonChecked (int nIDButton) const | |
274 | { | |
275 | return::IsDlgButtonChecked (GetHWND (), nIDButton); | |
276 | } | |
277 | ||
278 | bool | |
279 | Window::SetDlgItemFont (int id, const TCHAR * fontname, int Pointsize, | |
280 | int Weight, bool Italic, bool Underline, | |
281 | bool Strikeout) | |
282 | { | |
283 | HWND ctrl; | |
284 | ctrl = GetDlgItem (id); | |
285 | if (ctrl == NULL) | |
286 | { | |
287 | // Couldn't get that ID | |
288 | return false; | |
289 | } | |
290 | ||
291 | // We need the DC for the point size calculation. | |
292 | HDC hdc = GetDC (ctrl); | |
293 | ||
294 | // Create the font. We have to keep it around until the dialog item | |
295 | // goes away - basically until we're destroyed. | |
296 | HFONT hfnt; | |
297 | hfnt = | |
298 | CreateFont (-MulDiv (Pointsize, GetDeviceCaps (hdc, LOGPIXELSY), 72), 0, | |
299 | 0, 0, Weight, Italic ? TRUE : FALSE, | |
300 | Underline ? TRUE : FALSE, Strikeout ? TRUE : FALSE, | |
301 | ANSI_CHARSET, OUT_TT_PRECIS, CLIP_DEFAULT_PRECIS, | |
302 | PROOF_QUALITY, DEFAULT_PITCH | FF_DONTCARE, fontname); | |
303 | if (hfnt == NULL) | |
304 | { | |
305 | // Font creation failed | |
306 | return false; | |
307 | } | |
308 | ||
309 | // Set the new fint, and redraw any text which was already in the item. | |
310 | SendMessage (ctrl, WM_SETFONT, (WPARAM) hfnt, TRUE); | |
311 | ||
312 | // Save it for later. | |
313 | Fonts[FontCounter] = hfnt; | |
314 | FontCounter++; | |
315 | ||
316 | return true; | |
317 | } |