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