]> cygwin.com Git - cygwin-apps/setup.git/blob - window.cc
* ini.h (SETUP_BZ2_FILENAME): Reflect new architecture layout in ftp.
[cygwin-apps/setup.git] / window.cc
1 /*
2 * Copyright (c) 2001, 2002, 2003 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 "win32.h"
21 #include "window.h"
22 #include "RECTWrapper.h"
23 #include "msg.h"
24 #include "resource.h"
25
26 ATOM Window::WindowClassAtom = 0;
27 HINSTANCE Window::AppInstance = NULL;
28
29 Window::Window ()
30 {
31 WindowHandle = NULL;
32 Parent = NULL;
33 TooltipHandle = NULL;
34 BusyCount = 0;
35 BusyCursor = NULL;
36
37 }
38
39 Window::~Window ()
40 {
41 // Delete any fonts we created.
42 for (unsigned int i = 0; i < Fonts.size (); i++)
43 DeleteObject (Fonts[i]);
44
45 // shut down the tooltip control, if activated
46 if (TooltipHandle)
47 DestroyWindow (TooltipHandle);
48
49 // FIXME: Maybe do some reference counting and do this Unregister
50 // when there are no more of us left. Not real critical unless
51 // we're in a DLL which we're not right now.
52 //UnregisterClass(WindowClassAtom, InstanceHandle);
53 }
54
55 LRESULT CALLBACK
56 Window::FirstWindowProcReflector (HWND hwnd, UINT uMsg, WPARAM wParam,
57 LPARAM lParam)
58 {
59 Window *wnd = NULL;
60
61 if(uMsg == WM_NCCREATE)
62 {
63 // This is the first message a window gets (so MSDN says anyway).
64 // Take this opportunity to "link" the HWND to the 'this' ptr, steering
65 // messages to the class instance's WindowProc().
66 wnd = reinterpret_cast<Window *>(((LPCREATESTRUCT)lParam)->lpCreateParams);
67
68 // Set a backreference to this class instance in the HWND.
69 SetWindowLongPtr (hwnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(wnd));
70
71 // Set a new WindowProc now that we have the peliminaries done.
72 // We could instead simply do the contents of Window::WindowProcReflector
73 // in the 'else' clause below, but this way we eliminate an unnecessary 'if/else' on
74 // every message. Yeah, it's probably not worth the trouble.
75 SetWindowLongPtr (hwnd, GWLP_WNDPROC, (LONG_PTR) & Window::WindowProcReflector);
76 // Finally, store the window handle in the class.
77 wnd->WindowHandle = hwnd;
78 }
79 else
80 {
81 // Should never get here.
82 fatal(NULL, IDS_WINDOW_INIT_BADMSG, uMsg);
83 }
84
85 return wnd->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 This = reinterpret_cast<Window *>(GetWindowLongPtr (hwnd, GWLP_USERDATA));
96
97 return This->WindowProc (uMsg, wParam, lParam);
98 }
99
100 bool
101 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 // Save our parent, we'll probably need it eventually.
111 Parent = parent;
112
113 // Create the window instance
114 WindowHandle = CreateWindowEx (
115 // Extended Style
116 0,
117 "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 (),
131 // The this ptr, which we'll use to set up the WindowProc reflection.
132 (LPVOID) this);
133
134 if (WindowHandle == NULL)
135 {
136 // Failed
137 return false;
138 }
139
140 return true;
141 }
142
143 bool
144 Window::registerWindowClass ()
145 {
146 if (WindowClassAtom == 0)
147 {
148 // We're not registered yet
149 WNDCLASSEX
150 wc;
151
152 wc.cbSize = sizeof (wc);
153 // Some sensible style defaults
154 wc.style = CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW;
155 // Our default window procedure. This replaces itself
156 // on the first call with the simpler Window::WindowProcReflector().
157 wc.lpfnWndProc = Window::FirstWindowProcReflector;
158 // No class bytes
159 wc.cbClsExtra = 0;
160 // One pointer to REFLECTION_INFO in the extra window instance bytes
161 wc.cbWndExtra = 4;
162 // The app instance
163 wc.hInstance = GetInstance ();
164 // Use a bunch of system defaults for the GUI elements
165 wc.hIcon = NULL;
166 wc.hIconSm = NULL;
167 wc.hCursor = NULL;
168 wc.hbrBackground = (HBRUSH) (COLOR_BACKGROUND + 1);
169 // No menu
170 wc.lpszMenuName = NULL;
171 // We'll get a little crazy here with the class name
172 wc.lpszClassName = "MainWindowClass";
173
174 // All set, try to register
175 WindowClassAtom = RegisterClassEx (&wc);
176
177 if (WindowClassAtom == 0)
178 {
179 // Failed
180 return false;
181 }
182 }
183
184 // We're registered, or already were before the call,
185 // return success in either case.
186 return true;
187 }
188
189 void
190 Window::Show (int State)
191 {
192 ::ShowWindow (WindowHandle, State);
193 }
194
195 RECT
196 Window::GetWindowRect() const
197 {
198 RECT retval;
199 ::GetWindowRect(WindowHandle, &retval);
200 return retval;
201 }
202
203 RECT
204 Window::GetClientRect() const
205 {
206 RECT retval;
207 ::GetClientRect(WindowHandle, &retval);
208 return retval;
209 }
210
211 bool
212 Window::MoveWindow(long x, long y, long w, long h, bool Repaint)
213 {
214 return ::MoveWindow (WindowHandle, x, y, w, h, Repaint);
215 }
216
217 bool
218 Window::MoveWindow(const RECTWrapper &r, bool Repaint)
219 {
220 return ::MoveWindow (WindowHandle, r.left, r.top, r.width(), r.height(), Repaint);
221 }
222
223 void
224 Window::CenterWindow ()
225 {
226 RECT WindowRect, ParentRect;
227 int WindowWidth, WindowHeight;
228 POINT p;
229
230 // Get the window rectangle
231 WindowRect = GetWindowRect ();
232
233 if (GetParent () == NULL)
234 {
235 // Center on desktop window
236 ::GetWindowRect (GetDesktopWindow (), &ParentRect);
237 }
238 else
239 {
240 // Center on client area of parent
241 ::GetClientRect (GetParent ()->GetHWND (), &ParentRect);
242 }
243
244 WindowWidth = WindowRect.right - WindowRect.left;
245 WindowHeight = WindowRect.bottom - WindowRect.top;
246
247 // Find center of area we're centering on
248 p.x = (ParentRect.right - ParentRect.left) / 2;
249 p.y = (ParentRect.bottom - ParentRect.top) / 2;
250
251 // Convert that to screen coords
252 if (GetParent () == NULL)
253 {
254 ClientToScreen (GetDesktopWindow (), &p);
255 }
256 else
257 {
258 ClientToScreen (GetParent ()->GetHWND (), &p);
259 }
260
261 // Calculate new top left corner for window
262 p.x -= WindowWidth / 2;
263 p.y -= WindowHeight / 2;
264
265 // And finally move the window
266 MoveWindow (p.x, p.y, WindowWidth, WindowHeight);
267 }
268
269 LRESULT
270 Window::WindowProc (UINT uMsg, WPARAM wParam, LPARAM lParam)
271 {
272 return DefWindowProc (WindowHandle, uMsg, wParam, lParam);
273 }
274
275 bool
276 Window::MessageLoop ()
277 {
278 MSG
279 msg;
280
281 while (GetMessage (&msg, NULL, 0, 0) != 0
282 && GetMessage (&msg, (HWND) NULL, 0, 0) != -1)
283 {
284 if (!IsWindow (WindowHandle) || !IsDialogMessage (WindowHandle, &msg))
285 {
286 TranslateMessage (&msg);
287 DispatchMessage (&msg);
288 }
289 }
290
291 return true;
292 }
293
294 void
295 Window::PostMessageNow (UINT uMsg, WPARAM wParam, LPARAM lParam)
296 {
297 ::PostMessage (GetHWND (), uMsg, wParam, lParam);
298 }
299
300 UINT
301 Window::IsButtonChecked (int nIDButton) const
302 {
303 return ::IsDlgButtonChecked (GetHWND (), nIDButton);
304 }
305
306 bool
307 Window::SetDlgItemFont (int id, const TCHAR * fontname, int Pointsize,
308 int Weight, bool Italic, bool Underline,
309 bool Strikeout)
310 {
311 HWND ctrl;
312
313 ctrl = GetDlgItem (id);
314 if (ctrl == NULL)
315 {
316 // Couldn't get that ID
317 return false;
318 }
319
320 // We need the DC for the point size calculation.
321 HDC hdc = GetDC (ctrl);
322
323 // Create the font. We have to keep it around until the dialog item
324 // goes away - basically until we're destroyed.
325 HFONT hfnt;
326 hfnt =
327 CreateFont (-MulDiv (Pointsize, GetDeviceCaps (hdc, LOGPIXELSY), 72), 0,
328 0, 0, Weight, Italic ? TRUE : FALSE,
329 Underline ? TRUE : FALSE, Strikeout ? TRUE : FALSE,
330 ANSI_CHARSET, OUT_TT_PRECIS, CLIP_DEFAULT_PRECIS,
331 PROOF_QUALITY, DEFAULT_PITCH | FF_DONTCARE, fontname);
332 if (hfnt == NULL)
333 {
334 // Font creation failed
335 return false;
336 }
337
338 // Set the new font, and redraw any text which was already in the item.
339 SendMessage (ctrl, WM_SETFONT, (WPARAM) hfnt, TRUE);
340
341 // Store the handle so that we can DeleteObject() it in dtor
342 Fonts.push_back (hfnt);
343
344 return true;
345 }
346
347 void
348 Window::SetWindowText (const std::string& s)
349 {
350 ::SetWindowText (WindowHandle, s.c_str ());
351 }
352
353 RECT
354 Window::ScreenToClient(const RECT &r) const
355 {
356 POINT tl;
357 POINT br;
358
359 tl.y = r.top;
360 tl.x = r.left;
361 ::ScreenToClient(GetHWND(), &tl);
362 br.y = r.bottom;
363 br.x = r.right;
364 ::ScreenToClient(GetHWND(), &br);
365
366 RECT ret;
367
368 ret.top = tl.y;
369 ret.left = tl.x;
370 ret.bottom = br.y;
371 ret.right = br.x;
372
373 return ret;
374 }
375
376 void
377 Window::ActivateTooltips ()
378 // initialization of the tooltip capability
379 {
380 if (TooltipHandle != NULL)
381 return; // already initialized
382
383 // create a window for the tool tips - will be invisible most of the time
384 if ((TooltipHandle = CreateWindowEx (0, (LPCTSTR) TOOLTIPS_CLASS, NULL,
385 WS_POPUP | TTS_NOPREFIX | TTS_ALWAYSTIP, CW_USEDEFAULT,
386 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, GetHWND (),
387 (HMENU) 0, GetInstance (), (LPVOID) 0)) == (HWND) NULL)
388 {
389 log (LOG_PLAIN) << "Warning: call to CreateWindowEx failed when "
390 "initializing tooltips. Error = %8.8x" << GetLastError ()
391 << endLog;
392 return;
393 }
394
395 // must be topmost so that tooltips will display on top
396 SetWindowPos (TooltipHandle, HWND_TOPMOST, 0, 0, 0, 0,
397 SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
398
399 // some of our tooltips are lengthy, and will disappear before they can be
400 // read with the default windows delay, so we set a long (30s) delay here.
401 SendMessage (TooltipHandle, TTM_SETDELAYTIME, TTDT_AUTOPOP,
402 (LPARAM) MAKELONG (30000, 0));
403 }
404
405 void
406 Window::SetTooltipState (bool b)
407 // enable/disable tooltips
408 {
409 SendMessage (TooltipHandle, (UINT)TTM_ACTIVATE, (WPARAM)(BOOL)b, 0);
410 }
411
412 void
413 Window::AddTooltip (HWND target, HWND win, const char *text)
414 // adds a tooltip to element 'target' in window 'win'
415 // note: text is limited to 80 chars (grumble)
416 {
417 if (!TooltipHandle)
418 ActivateTooltips ();
419
420 TOOLINFO ti;
421
422 memset ((void *)&ti, 0, sizeof(ti));
423 ti.cbSize = sizeof(ti);
424
425 ti.uFlags = TTF_IDISHWND // add tool based on handle not ID
426 | TTF_SUBCLASS; // tool is to subclass the window in order
427 // to automatically get mouse events
428 ti.hwnd = win;
429 ti.uId = reinterpret_cast<UINT_PTR>(target);
430 ti.lpszText = (LPTSTR)text; // pointer to text or string resource
431
432 SendMessage (TooltipHandle, (UINT)TTM_ADDTOOL, 0,
433 (LPARAM)(LPTOOLINFO)&ti);
434 }
435
436 void
437 Window::AddTooltip (int id, const char *text)
438 // adds a tooltip to a control identified by its ID
439 {
440 HWND target, parent;
441
442 if ((target = GetDlgItem (id)) != NULL &&
443 (parent = ::GetParent (target)) != NULL)
444 AddTooltip (target, parent, text);
445 }
446
447 void
448 Window::AddTooltip (int id, int string_resource)
449 // adds a tooltip that's represented by a string resource
450 // this also allows for tooltips greater than 80 characters
451 // we do this by setting the lpszText to LPSTR_TEXTCALLBACK
452 // and then responding to the TTN_GETDISPINFO notification
453 // in order to do this we store a list of (control ID, string ID) pairs
454 {
455 AddTooltip (id, (const char *)LPSTR_TEXTCALLBACK);
456 TooltipStrings[id] = string_resource;
457 }
458
459 BOOL
460 Window::TooltipNotificationHandler (LPARAM lParam)
461 // this is the handler for TTN_GETDISPINFO notifications
462 {
463 NMTTDISPINFO *dispinfo = (NMTTDISPINFO *)lParam;
464 int ctrlID;
465 std::map<int, int>::iterator findID;
466
467 if ((dispinfo->uFlags & TTF_IDISHWND) &&
468 ((ctrlID = GetDlgCtrlID ((HWND)dispinfo->hdr.idFrom)) != 0) &&
469 ((findID = TooltipStrings.find (ctrlID)) != TooltipStrings.end ())) {
470
471 // enable multiple lines
472 SendMessage(dispinfo->hdr.hwndFrom, TTM_SETMAXTIPWIDTH, 0, 450);
473
474 // this is quite ugly. Apparently even when using string resources
475 // the tooltip length still can't exceed 80 chars. So, we fetch the
476 // resource into our own buffer and use that
477
478 TCHAR buf[2048];
479 LoadString (GetInstance (), findID->second, (LPTSTR)buf,
480 (sizeof (buf) / sizeof (TCHAR)));
481
482 dispinfo->lpszText = buf;
483
484 // set this flag so that the control will not ask for this again
485 dispinfo->uFlags |= TTF_DI_SETITEM;
486 dispinfo->hinst = NULL;
487 return TRUE;
488 }
489
490 return FALSE;
491 }
492
493 void
494 Window::SetBusy (void)
495 {
496 // The docs suggest that you can call SetCursor, and it won't do
497 // anything if you've chosen the same cursor as is already set.
498 // However it looked to me as if it was resetting the animation
499 // frame every time when I tried it, hence this routine to make
500 // sure we only call it once on the way into and once on the way
501 // out of busy mode.
502 if (BusyCount++ == 0)
503 {
504 if (BusyCursor == NULL)
505 BusyCursor = LoadCursor (NULL, IDC_WAIT);
506 OldCursor = SetCursor (BusyCursor);
507 }
508 }
509
510 void
511 Window::ClearBusy (void)
512 {
513 if (BusyCount && (--BusyCount == 0))
514 {
515 SetCursor (OldCursor);
516 }
517 }
518
This page took 0.056601 seconds and 5 git commands to generate.