]> cygwin.com Git - cygwin-apps/setup.git/blame - window.cc
* source.cc: Add support for both -D and -L on command line
[cygwin-apps/setup.git] / window.cc
CommitLineData
df62e023 1/*
0a539fe4 2 * Copyright (c) 2001, 2002, 2003 Gary R. Van Sickle.
df62e023
RC
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
46d04e97 20#include "win32.h"
df62e023 21#include "window.h"
0a539fe4 22#include "RECTWrapper.h"
d943aa72
MB
23#include "msg.h"
24#include "resource.h"
df62e023
RC
25
26ATOM Window::WindowClassAtom = 0;
27HINSTANCE Window::AppInstance = NULL;
28
df62e023
RC
29Window::Window ()
30{
31 WindowHandle = NULL;
32 Parent = NULL;
37f49caf 33 TooltipHandle = NULL;
df62e023
RC
34}
35
36Window::~Window ()
37{
b7301c43 38 // Delete any fonts we created.
daab12c7
BD
39 for (unsigned int i = 0; i < Fonts.size (); i++)
40 DeleteObject (Fonts[i]);
b7301c43 41
37f49caf
BD
42 // shut down the tooltip control, if activated
43 if (TooltipHandle)
44 DestroyWindow (TooltipHandle);
45
df62e023
RC
46 // FIXME: Maybe do some reference counting and do this Unregister
47 // when there are no more of us left. Not real critical unless
48 // we're in a DLL which we're not right now.
49 //UnregisterClass(WindowClassAtom, InstanceHandle);
50}
51
52LRESULT CALLBACK
53Window::FirstWindowProcReflector (HWND hwnd, UINT uMsg, WPARAM wParam,
54 LPARAM lParam)
55{
63c82708 56 Window *wnd = NULL;
df62e023 57
63c82708 58 if(uMsg == WM_NCCREATE)
df62e023 59 {
63c82708
RC
60 // This is the first message a window gets (so MSDN says anyway).
61 // Take this opportunity to "link" the HWND to the 'this' ptr, steering
62 // messages to the class instance's WindowProc().
63 wnd = reinterpret_cast<Window *>(((LPCREATESTRUCT)lParam)->lpCreateParams);
df62e023
RC
64
65 // Set a backreference to this class instance in the HWND.
0a539fe4 66 SetWindowLongPtr (hwnd, GWL_USERDATA, reinterpret_cast<LONG_PTR>(wnd));
df62e023
RC
67
68 // Set a new WindowProc now that we have the peliminaries done.
63c82708
RC
69 // We could instead simply do the contents of Window::WindowProcReflector
70 // in the 'else' clause below, but this way we eliminate an unnecessary 'if/else' on
71 // every message. Yeah, it's probably not worth the trouble.
72 SetWindowLongPtr (hwnd, GWL_WNDPROC, (LONG_PTR) & Window::WindowProcReflector);
693916f8
RC
73 // Finally, store the window handle in the class.
74 wnd->WindowHandle = hwnd;
63c82708
RC
75 }
76 else
d943aa72
MB
77 {
78 // Should never get here.
79 fatal(NULL, IDS_WINDOW_INIT_BADMSG, uMsg);
df62e023
RC
80 }
81
63c82708 82 return wnd->WindowProc (uMsg, wParam, lParam);
df62e023
RC
83}
84
85LRESULT CALLBACK
86Window::WindowProcReflector (HWND hwnd, UINT uMsg, WPARAM wParam,
87 LPARAM lParam)
88{
89 Window *This;
90
91 // Get our this pointer
0a539fe4 92 This = reinterpret_cast<Window *>(GetWindowLongPtr (hwnd, GWL_USERDATA));
df62e023
RC
93
94 return This->WindowProc (uMsg, wParam, lParam);
95}
96
2f3a74d1
MB
97bool
98Window::Create (Window * parent, DWORD Style)
df62e023
RC
99{
100 // First register the window class, if we haven't already
693916f8 101 if (registerWindowClass () == false)
df62e023
RC
102 {
103 // Registration failed
104 return false;
105 }
106
0a539fe4 107 // Save our parent, we'll probably need it eventually.
df62e023
RC
108 Parent = parent;
109
110 // Create the window instance
63c82708
RC
111 WindowHandle = CreateWindowEx (
112 // Extended Style
113 0,
114 "MainWindowClass", //MAKEINTATOM(WindowClassAtom), // window class atom (name)
df62e023
RC
115 "Hello", // no title-bar string yet
116 // Style bits
117 Style,
118 // Default positions and size
119 CW_USEDEFAULT,
120 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
121 // Parent Window
122 parent ==
123 NULL ? (HWND) NULL : parent->GetHWND (),
124 // use class menu
125 (HMENU) NULL,
126 // The application instance
63c82708
RC
127 GetInstance (),
128 // The this ptr, which we'll use to set up the WindowProc reflection.
129 (LPVOID) this);
df62e023
RC
130
131 if (WindowHandle == NULL)
132 {
133 // Failed
134 return false;
135 }
136
137 return true;
138}
139
2f3a74d1
MB
140bool
141Window::registerWindowClass ()
df62e023
RC
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
186void
187Window::Show (int State)
188{
189 ::ShowWindow (WindowHandle, State);
190}
191
63c82708
RC
192RECT
193Window::GetWindowRect() const
194{
195 RECT retval;
196 ::GetWindowRect(WindowHandle, &retval);
197 return retval;
198}
199
200RECT
201Window::GetClientRect() const
202{
203 RECT retval;
204 ::GetClientRect(WindowHandle, &retval);
205 return retval;
206}
207
208bool
209Window::MoveWindow(long x, long y, long w, long h, bool Repaint)
210{
211 return ::MoveWindow (WindowHandle, x, y, w, h, Repaint);
212}
213
0a539fe4
MB
214bool
215Window::MoveWindow(const RECTWrapper &r, bool Repaint)
216{
217 return ::MoveWindow (WindowHandle, r.left, r.top, r.width(), r.height(), Repaint);
218}
219
df62e023
RC
220void
221Window::CenterWindow ()
222{
223 RECT WindowRect, ParentRect;
224 int WindowWidth, WindowHeight;
225 POINT p;
226
227 // Get the window rectangle
63c82708 228 WindowRect = GetWindowRect ();
df62e023
RC
229
230 if (GetParent () == NULL)
231 {
232 // Center on desktop window
63c82708 233 ::GetWindowRect (GetDesktopWindow (), &ParentRect);
df62e023
RC
234 }
235 else
236 {
237 // Center on client area of parent
63c82708 238 ::GetClientRect (GetParent ()->GetHWND (), &ParentRect);
df62e023
RC
239 }
240
241 WindowWidth = WindowRect.right - WindowRect.left;
242 WindowHeight = WindowRect.bottom - WindowRect.top;
243
244 // Find center of area we're centering on
245 p.x = (ParentRect.right - ParentRect.left) / 2;
246 p.y = (ParentRect.bottom - ParentRect.top) / 2;
247
248 // Convert that to screen coords
249 if (GetParent () == NULL)
250 {
251 ClientToScreen (GetDesktopWindow (), &p);
252 }
253 else
254 {
255 ClientToScreen (GetParent ()->GetHWND (), &p);
256 }
257
258 // Calculate new top left corner for window
259 p.x -= WindowWidth / 2;
260 p.y -= WindowHeight / 2;
261
262 // And finally move the window
63c82708 263 MoveWindow (p.x, p.y, WindowWidth, WindowHeight);
df62e023
RC
264}
265
2f3a74d1
MB
266LRESULT
267Window::WindowProc (UINT uMsg, WPARAM wParam, LPARAM lParam)
df62e023 268{
693916f8 269 return DefWindowProc (WindowHandle, uMsg, wParam, lParam);
df62e023
RC
270}
271
2f3a74d1
MB
272bool
273Window::MessageLoop ()
df62e023
RC
274{
275 MSG
276 msg;
277
278 while (GetMessage (&msg, NULL, 0, 0) != 0
279 && GetMessage (&msg, (HWND) NULL, 0, 0) != -1)
280 {
281 if (!IsWindow (WindowHandle) || !IsDialogMessage (WindowHandle, &msg))
282 {
283 TranslateMessage (&msg);
284 DispatchMessage (&msg);
285 }
286 }
287
288 return true;
289}
290
291void
292Window::PostMessage (UINT uMsg, WPARAM wParam, LPARAM lParam)
293{
294 ::PostMessage (GetHWND (), uMsg, wParam, lParam);
295}
b7301c43 296
2f3a74d1
MB
297UINT
298Window::IsButtonChecked (int nIDButton) const
b7301c43 299{
0a539fe4 300 return ::IsDlgButtonChecked (GetHWND (), nIDButton);
b7301c43
RC
301}
302
303bool
2f3a74d1 304Window::SetDlgItemFont (int id, const TCHAR * fontname, int Pointsize,
b7301c43
RC
305 int Weight, bool Italic, bool Underline,
306 bool Strikeout)
307{
308 HWND ctrl;
63c82708 309
b7301c43
RC
310 ctrl = GetDlgItem (id);
311 if (ctrl == NULL)
312 {
313 // Couldn't get that ID
314 return false;
315 }
316
317 // We need the DC for the point size calculation.
318 HDC hdc = GetDC (ctrl);
319
320 // Create the font. We have to keep it around until the dialog item
321 // goes away - basically until we're destroyed.
322 HFONT hfnt;
323 hfnt =
324 CreateFont (-MulDiv (Pointsize, GetDeviceCaps (hdc, LOGPIXELSY), 72), 0,
325 0, 0, Weight, Italic ? TRUE : FALSE,
326 Underline ? TRUE : FALSE, Strikeout ? TRUE : FALSE,
327 ANSI_CHARSET, OUT_TT_PRECIS, CLIP_DEFAULT_PRECIS,
328 PROOF_QUALITY, DEFAULT_PITCH | FF_DONTCARE, fontname);
329 if (hfnt == NULL)
330 {
331 // Font creation failed
332 return false;
333 }
334
0a539fe4 335 // Set the new font, and redraw any text which was already in the item.
b7301c43
RC
336 SendMessage (ctrl, WM_SETFONT, (WPARAM) hfnt, TRUE);
337
daab12c7
BD
338 // Store the handle so that we can DeleteObject() it in dtor
339 Fonts.push_back (hfnt);
b7301c43
RC
340
341 return true;
342}
58db1046
RC
343
344void
08678720 345Window::SetWindowText (const std::string& s)
58db1046 346{
d2a3615c 347 ::SetWindowText (WindowHandle, s.c_str ());
58db1046 348}
63c82708
RC
349
350RECT
351Window::ScreenToClient(const RECT &r) const
352{
353 POINT tl;
354 POINT br;
355
356 tl.y = r.top;
357 tl.x = r.left;
358 ::ScreenToClient(GetHWND(), &tl);
359 br.y = r.bottom;
360 br.x = r.right;
361 ::ScreenToClient(GetHWND(), &br);
362
363 RECT ret;
364
365 ret.top = tl.y;
366 ret.left = tl.x;
367 ret.bottom = br.y;
368 ret.right = br.x;
369
370 return ret;
371}
372
37f49caf
BD
373void
374Window::ActivateTooltips ()
375// initialization of the tooltip capability
376{
377 if (TooltipHandle != NULL)
378 return; // already initialized
379
380 // create a window for the tool tips - will be invisible most of the time
3f6926b1 381 if ((TooltipHandle = CreateWindowEx (0, (LPCTSTR) TOOLTIPS_CLASS, NULL,
37f49caf
BD
382 WS_POPUP | TTS_NOPREFIX | TTS_ALWAYSTIP, CW_USEDEFAULT,
383 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, GetHWND (),
3f6926b1 384 (HMENU) 0, GetInstance (), (LPVOID) 0)) == (HWND) NULL)
37f49caf 385 {
3f6926b1 386 log (LOG_PLAIN) << "Warning: call to CreateWindowEx failed when "
37f49caf
BD
387 "initializing tooltips. Error = %8.8x" << GetLastError ()
388 << endLog;
389 return;
390 }
391
392 // must be topmost so that tooltips will display on top
3f6926b1
BD
393 SetWindowPos (TooltipHandle, HWND_TOPMOST, 0, 0, 0, 0,
394 SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
395
396 // some of our tooltips are lengthy, and will disappear before they can be
397 // read with the default windows delay, so we set a long (30s) delay here.
398 SendMessage (TooltipHandle, TTM_SETDELAYTIME, TTDT_AUTOPOP,
399 (LPARAM) MAKELONG (30000, 0));
37f49caf
BD
400}
401
402void
403Window::SetTooltipState (bool b)
404// enable/disable tooltips
405{
406 SendMessage (TooltipHandle, (UINT)TTM_ACTIVATE, (WPARAM)(BOOL)b, 0);
407}
408
409void
410Window::AddTooltip (HWND target, HWND win, const char *text)
411// adds a tooltip to element 'target' in window 'win'
412// note: text is limited to 80 chars (grumble)
413{
414 if (!TooltipHandle)
415 ActivateTooltips ();
416
417 TOOLINFO ti;
418
419 memset ((void *)&ti, 0, sizeof(ti));
420 ti.cbSize = sizeof(ti);
421
422 ti.uFlags = TTF_IDISHWND // add tool based on handle not ID
423 | TTF_SUBCLASS; // tool is to subclass the window in order
424 // to automatically get mouse events
425 ti.hwnd = win;
426 ti.uId = reinterpret_cast<UINT_PTR>(target);
427 ti.lpszText = (LPTSTR)text; // pointer to text or string resource
428
429 SendMessage (TooltipHandle, (UINT)TTM_ADDTOOL, 0,
430 (LPARAM)(LPTOOLINFO)&ti);
431}
432
433void
434Window::AddTooltip (int id, const char *text)
435// adds a tooltip to a control identified by its ID
436{
437 HWND target, parent;
438
439 if ((target = GetDlgItem (id)) != NULL &&
440 (parent = ::GetParent (target)) != NULL)
441 AddTooltip (target, parent, text);
442}
443
444void
445Window::AddTooltip (int id, int string_resource)
446// adds a tooltip that's represented by a string resource
447// this also allows for tooltips greater than 80 characters
448// we do this by setting the lpszText to LPSTR_TEXTCALLBACK
449// and then responding to the TTN_GETDISPINFO notification
450// in order to do this we store a list of (control ID, string ID) pairs
451{
452 AddTooltip (id, (const char *)LPSTR_TEXTCALLBACK);
453 TooltipStrings[id] = string_resource;
454}
455
456BOOL
457Window::TooltipNotificationHandler (LPARAM lParam)
458// this is the handler for TTN_GETDISPINFO notifications
459{
460 NMTTDISPINFO *dispinfo = (NMTTDISPINFO *)lParam;
461 int ctrlID;
462 std::map<int, int>::iterator findID;
463
464 if ((dispinfo->uFlags & TTF_IDISHWND) &&
465 ((ctrlID = GetDlgCtrlID ((HWND)dispinfo->hdr.idFrom)) != 0) &&
466 ((findID = TooltipStrings.find (ctrlID)) != TooltipStrings.end ())) {
467
468 // enable multiple lines
469 SendMessage(dispinfo->hdr.hwndFrom, TTM_SETMAXTIPWIDTH, 0, 450);
470
471 // this is quite ugly. Apparently even when using string resources
472 // the tooltip length still can't exceed 80 chars. So, we fetch the
473 // resource into our own buffer and use that
474
475 TCHAR buf[2048];
476 LoadString (GetInstance (), findID->second, (LPTSTR)buf,
477 (sizeof (buf) / sizeof (TCHAR)));
478
479 dispinfo->lpszText = buf;
480
481 // set this flag so that the control will not ask for this again
482 dispinfo->uFlags |= TTF_DI_SETITEM;
483 dispinfo->hinst = NULL;
484 return TRUE;
485 }
486
487 return FALSE;
488}
489
This page took 0.096245 seconds and 5 git commands to generate.