Develop and Download Open Source Software

Browse Subversion Repository

Contents of /trunk/src/window.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 132 - (show annotations) (download) (as text)
Tue Sep 13 17:40:57 2016 UTC (7 years, 6 months ago) by z0rac
File MIME type: text/x-c++src
File size: 13286 byte(s)


1 /*
2 * Copyright (C) 2009-2016 TSUBAKIMOTO Hiroya <z0rac@users.sourceforge.jp>
3 *
4 * This software comes with ABSOLUTELY NO WARRANTY; for details of
5 * the license terms, see the LICENSE.txt file included with the program.
6 */
7 #define _WIN32_WINNT 0x0500
8 #define _WIN32_IE 0x0300
9 #include "win32.h"
10 #include "window.h"
11 #include <cassert>
12
13 #ifdef _DEBUG
14 #include <iostream>
15 #define DBG(s) s
16 #define LOG(s) (cout << s)
17 #else
18 #define DBG(s)
19 #define LOG(s)
20 #endif
21
22 /*
23 * Functions of the class window
24 */
25 window::window(LPCSTR classname, LPCSTR menu, HWND owner)
26 : _hwnd(_new(classname, menu, owner))
27 {
28 _initialize();
29 }
30
31 window::window(LPCSTR classname, const window& parent, int id)
32 : _hwnd(_new(classname, parent, id))
33 {
34 _initialize();
35 }
36
37 window::~window()
38 {
39 if (_hwnd) _release(!child());
40 }
41
42 int
43 window::eventloop()
44 {
45 for (;;) {
46 MSG msg;
47 switch (GetMessage(&msg, NULL, 0, 0)) {
48 case 0: return int(msg.wParam);
49 case -1: continue;
50 }
51 TranslateMessage(&msg);
52 DispatchMessage(&msg);
53 }
54 }
55
56 void
57 window::broadcast(UINT m, WPARAM w, LPARAM l)
58 {
59 struct _enum {
60 UINT m;
61 WPARAM w;
62 LPARAM l;
63 DWORD id;
64 static BOOL CALLBACK proc(HWND h, LPARAM l)
65 {
66 DWORD id;
67 GetWindowThreadProcessId(h, &id);
68 _enum* p = reinterpret_cast<_enum*>(l);
69 if (id == p->id) {
70 SendMessageTimeout(h, p->m, p->w, p->l, SMTO_NORMAL, 1000, NULL);
71 }
72 return TRUE;
73 }
74 } enums = { m, w, l, GetCurrentProcessId() };
75 EnumWindows(_enum::proc, LPARAM(&enums));
76 }
77
78 bool
79 window::child() const
80 {
81 assert(_hwnd);
82 return (GetWindowLong(_hwnd, GWL_STYLE) & WS_CHILD) != 0;
83 }
84
85 void
86 window::close(bool root) const
87 {
88 assert(_hwnd);
89 PostMessage(root ? GetAncestor(_hwnd, GA_ROOT) : _hwnd, WM_CLOSE, 0, 0);
90 }
91
92 void
93 window::show(bool show, bool active) const
94 {
95 assert(_hwnd);
96 ShowWindow(_hwnd, show ? (active ? SW_SHOW : SW_SHOWNA) : SW_HIDE);
97 }
98
99 void
100 window::foreground(bool force) const
101 {
102 assert(_hwnd && !child());
103
104 if (IsIconic(_hwnd)) ShowWindow(_hwnd, SW_RESTORE);
105
106 if (force) {
107 DWORD tid = GetWindowThreadProcessId(_hwnd, NULL);
108 DWORD fore = GetWindowThreadProcessId(GetForegroundWindow(), NULL);
109 if (tid != fore && AttachThreadInput(tid, fore, TRUE)) {
110 DWORD save = 0;
111 SetActiveWindow(_hwnd);
112 SystemParametersInfo(SPI_GETFOREGROUNDLOCKTIMEOUT, 0, &save, 0);
113 SystemParametersInfo(SPI_SETFOREGROUNDLOCKTIMEOUT, 0, NULL, 0);
114 SetForegroundWindow(_hwnd);
115 SystemParametersInfo(SPI_SETFOREGROUNDLOCKTIMEOUT, 0, PVOID(ULONG_PTR(save)), 0);
116 AttachThreadInput(tid, fore, FALSE);
117 return;
118 }
119 }
120 SetForegroundWindow(_hwnd);
121 }
122
123 bool
124 window::topmost() const
125 {
126 assert(_hwnd);
127 return (GetWindowLong(_hwnd, GWL_EXSTYLE) & WS_EX_TOPMOST) != 0;
128 }
129
130 void
131 window::topmost(bool topmost)
132 {
133 assert(_hwnd && !child());
134 SetWindowPos(_hwnd, topmost ? HWND_TOPMOST : HWND_NOTOPMOST,
135 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
136 }
137
138 void
139 window::transparent(int alpha, COLORREF key)
140 {
141 assert(_hwnd);
142 SetLayeredWindowAttributes(_hwnd, key, BYTE(alpha),
143 key != COLORREF(-1) ? LWA_COLORKEY | LWA_ALPHA : LWA_ALPHA);
144 }
145
146 void
147 window::move(int x, int y, int w, int h) const
148 {
149 assert(_hwnd);
150 MoveWindow(_hwnd, x, y, w, h, TRUE);
151 }
152
153 void
154 window::move(const RECT& r) const
155 {
156 assert(_hwnd);
157 MoveWindow(_hwnd, r.left, r.top, r.right - r.left, r.bottom - r.top, TRUE);
158 }
159
160 bool
161 window::hascursor(bool child) const
162 {
163 assert(_hwnd);
164 POINT pt;
165 if (!GetCursorPos(&pt)) return false;
166 HWND h = WindowFromPoint(pt);
167 return h == _hwnd || (child && IsChild(_hwnd, h));
168 }
169
170 POINT
171 window::extent() const
172 {
173 assert(_hwnd);
174 RECT r;
175 GetClientRect(_hwnd, &r);
176 return (POINT&)r.right;
177 }
178
179 RECT
180 window::bounds() const
181 {
182 assert(_hwnd);
183 RECT r;
184 GetWindowRect(_hwnd, &r);
185 return r;
186 }
187
188 HWND
189 window::_new(LPCSTR classname, LPCSTR menu, HWND owner)
190 {
191 HMENU m = menu ? win32::valid(LoadMenu(win32::exe, menu)) : NULL;
192 return win32::valid(CreateWindow(classname, NULL, WS_OVERLAPPED,
193 CW_USEDEFAULT, CW_USEDEFAULT,
194 CW_USEDEFAULT, CW_USEDEFAULT,
195 owner, m, win32::exe, NULL));
196 }
197
198 HWND
199 window::_new(LPCSTR classname, const window& parent, int id)
200 {
201 return win32::valid(CreateWindow(classname, NULL, WS_CHILD, 0, 0, 1, 1,
202 parent.hwnd(), HMENU(LONG_PTR(id)),
203 win32::exe, NULL));
204 }
205
206 void
207 window::_initialize()
208 {
209 _callback = WNDPROC(GetWindowLongPtr(_hwnd, GWLP_WNDPROC));
210 SetWindowLongPtr(_hwnd, GWLP_USERDATA, LONG_PTR(this));
211 SetWindowLongPtr(_hwnd, GWLP_WNDPROC, LONG_PTR(_wndproc));
212 }
213
214 void
215 window::_release(bool destroy)
216 {
217 assert(_hwnd);
218 SetWindowLongPtr(_hwnd, GWLP_WNDPROC, LONG_PTR(_callback));
219 SetWindowLongPtr(_hwnd, GWLP_USERDATA, 0);
220 if (destroy) DestroyWindow(_hwnd);
221 _hwnd = NULL;
222 }
223
224 LRESULT CALLBACK
225 window::_wndproc(HWND h, UINT m, WPARAM w, LPARAM l)
226 {
227 LRESULT rc = 0;
228 window* wp = reinterpret_cast<window*>(GetWindowLongPtr(h, GWLP_USERDATA));
229 if (wp) {
230 try {
231 rc = wp->dispatch(m, w, l);
232 } catch (const exception& DBG(e)) {
233 LOG(e.what() << endl);
234 } catch (...) {
235 LOG("Unknown exception." << endl);
236 }
237 if (m == WM_DESTROY) wp->_release();
238 }
239 return rc;
240 }
241
242 namespace {
243 static const POINT smicon =
244 { GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON) };
245
246 HICON iconload(int id)
247 {
248 static const win32::dll shell32("shell32.dll", LOAD_LIBRARY_AS_DATAFILE);
249 HMODULE mod = id >= 0 ? win32::exe : (id = -id, shell32);
250 return HICON(LoadImage(mod, MAKEINTRESOURCE(id), IMAGE_ICON,
251 smicon.x, smicon.y, LR_DEFAULTCOLOR));
252 }
253
254 HBITMAP iconbmp(int id)
255 {
256 static bool xp = (GetVersion() & 255) <= 5;
257 if (xp) return HBMMENU_CALLBACK;
258 HICON h = iconload(id);
259 if (!h) return NULL;
260 BITMAPINFOHEADER bmi = { sizeof(BITMAPINFOHEADER) };
261 bmi.biWidth = smicon.x, bmi.biHeight = smicon.y;
262 bmi.biPlanes = 1, bmi.biBitCount = 32;
263 LPVOID bits;
264 HBITMAP bmp = CreateDIBSection(NULL, LPBITMAPINFO(&bmi),
265 DIB_RGB_COLORS, &bits, NULL, 0);
266 if (bmp) {
267 HDC hDC = CreateCompatibleDC(NULL);
268 HGDIOBJ save = SelectObject(hDC, bmp);
269 DrawIconEx(hDC, 0, 0, h, smicon.x, smicon.y, 0, NULL, DI_NORMAL);
270 SelectObject(hDC, save);
271 DeleteDC(hDC);
272 }
273 DestroyIcon(h);
274 return bmp;
275 }
276 }
277
278 void
279 window::_updatemenu(HMENU h)
280 {
281 #define STATUS (MFS_DISABLED | MFS_CHECKED | MFS_HILITE)
282 for (int i = GetMenuItemCount(h); --i >= 0;) {
283 MENUITEMINFO info = { sizeof(MENUITEMINFO) };
284 info.fMask = MIIM_STATE | MIIM_ID | MIIM_BITMAP;
285 if (!GetMenuItemInfo(h, i, TRUE, &info)) continue;
286 command* p = _cmd(info.wID);
287 if (!p) continue;
288 if (!info.hbmpItem && p->icon) info.hbmpItem = iconbmp(p->icon);
289 info.fState &= ~STATUS;
290 info.fState |= p->state(*this) & STATUS;
291 SetMenuItemInfo(h, i, TRUE, &info);
292 }
293 #undef STATUS
294 }
295
296 void
297 window::style(DWORD style, DWORD ex) const
298 {
299 assert(_hwnd);
300 style &= ~(WS_CHILD | WS_VISIBLE);
301 style |= GetWindowLong(_hwnd, GWL_STYLE) & (WS_CHILD | WS_VISIBLE);
302 SetWindowLong(_hwnd, GWL_STYLE, style);
303 if (ex) SetWindowLong(_hwnd, GWL_EXSTYLE, ex);
304 }
305
306 LRESULT
307 window::dispatch(UINT m, WPARAM w, LPARAM l)
308 {
309 switch (m) {
310 case WM_DESTROY:
311 release();
312 break;
313 case WM_SIZE:
314 resize(LOWORD(l), HIWORD(l));
315 break;
316 case WM_NOTIFY:
317 return notify(w, l);
318 case WM_COMMAND:
319 if (!GET_WM_COMMAND_HWND(w, l)) execute(GET_WM_COMMAND_CMD(w,l));
320 break;
321 case WM_MEASUREITEM:
322 if (callback(LPMEASUREITEMSTRUCT(l))) return TRUE;
323 break;
324 case WM_DRAWITEM:
325 if (callback(LPDRAWITEMSTRUCT(l))) return TRUE;
326 break;
327 }
328 return CallWindowProc(_callback, _hwnd, m, w, l);
329 }
330
331 LRESULT
332 window::notify(WPARAM w, LPARAM l)
333 {
334 return CallWindowProc(_callback, _hwnd, WM_NOTIFY, w, l);
335 }
336
337 bool
338 window::callback(LPMEASUREITEMSTRUCT misp)
339 {
340 if (misp->CtlType != ODT_MENU || !_cmd(misp->itemID)) return false;
341 misp->itemWidth += 2;
342 if (misp->itemHeight < UINT(smicon.y)) misp->itemHeight = smicon.y;
343 return true;
344 }
345
346 bool
347 window::callback(LPDRAWITEMSTRUCT disp)
348 {
349 if (disp->CtlType != ODT_MENU) return false;
350 command* p = _cmd(disp->itemID);
351 if (!p || !p->icon) return false;
352 HICON h = iconload(p->icon);
353 if (!h) return false;
354 DrawIconEx(disp->hDC, disp->rcItem.left - smicon.x - 2,
355 (disp->rcItem.top + disp->rcItem.bottom - smicon.y) / 2,
356 h, smicon.x, smicon.y, 0, NULL, DI_NORMAL);
357 DestroyIcon(h);
358 return true;
359 }
360
361 void
362 window::execute(int id)
363 {
364 command* p = _cmd(id);
365 if (p && !(p->state(*this) & MFS_DISABLED)) p->execute(*this);
366 }
367
368 window::command*
369 window::_cmd(int id)
370 {
371 for (cmdmap::iterator p = _cmdmap.begin(); p != _cmdmap.end(); ++p) {
372 if (p->first == id) return p->second.get();
373 }
374 return NULL;
375 }
376
377 void
378 window::addcmd(int id, cmdp cmd)
379 {
380 for (cmdmap::iterator p = _cmdmap.begin(); p != _cmdmap.end(); ++p) {
381 if (p->first != id) continue;
382 p->second = cmd;
383 return;
384 }
385 _cmdmap.push_back(pair<int, cmdp>(id, cmd));
386 }
387
388 void
389 window::execute(const menu& menu)
390 {
391 _updatemenu(menu);
392 UINT cmd = GetMenuDefaultItem(menu, FALSE, GMDI_GOINTOPOPUPS);
393 if (cmd != UINT(-1)) {
394 PostMessage(_hwnd, WM_COMMAND, GET_WM_COMMAND_MPS(0, 0, cmd));
395 }
396 }
397
398 bool
399 window::popup(const menu& menu, LPARAM pt)
400 {
401 _updatemenu(menu);
402 UINT cmd = UINT(TrackPopupMenu(menu, TPM_RIGHTBUTTON | TPM_RETURNCMD,
403 GET_X_LPARAM(pt), GET_Y_LPARAM(pt),
404 0, _hwnd, NULL));
405 PostMessage(_hwnd, WM_NULL, 0, 0);
406 if (!cmd) return false;
407 PostMessage(_hwnd, WM_COMMAND, GET_WM_COMMAND_MPS(0, 0, cmd));
408 return true;
409 }
410
411 /*
412 * Functions of the class window::commctrl
413 */
414 window::commctrl::commctrl(DWORD icc)
415 {
416 INITCOMMONCONTROLSEX icce = { sizeof(INITCOMMONCONTROLSEX), icc };
417 InitCommonControlsEx(&icce);
418 }
419
420 /*
421 * Functions of the class window::menu
422 */
423 window::menu::menu(LPCSTR name, int pos)
424 : _h(NULL)
425 {
426 HMENU bar = win32::valid(LoadMenu(win32::exe, name));
427 HMENU h = GetSubMenu(bar, pos);
428 if (h && !RemoveMenu(bar, pos, MF_BYPOSITION)) h = NULL;
429 DestroyMenu(bar);
430 _h = win32::valid(h);
431 }
432
433 /*
434 * Functions of the class window::timer
435 */
436 VOID CALLBACK
437 window::timer::_callback(HWND hwnd, UINT, UINT_PTR id, DWORD ticks)
438 {
439 timer& tm = *reinterpret_cast<timer*>(id);
440 if (tm._elapse) {
441 ticks -= tm._start;
442 if (ticks < tm._elapse) {
443 SetTimer(hwnd, id, tm._elapse - ticks, _callback);
444 } else {
445 tm._elapse = 0;
446 tm.wakeup(*reinterpret_cast<window*>
447 (GetWindowLongPtr(hwnd, GWLP_USERDATA)));
448 }
449 }
450 }
451
452 void
453 window::timer::operator()(HWND hwnd, UINT ms)
454 {
455 _elapse = ms;
456 if (ms) {
457 _start = GetTickCount();
458 SetTimer(hwnd, UINT_PTR(this), ms, _callback);
459 } else {
460 KillTimer(hwnd, UINT_PTR(this));
461 }
462 }
463
464 /*
465 * Functions of the class appwindow
466 */
467 LPCSTR
468 appwindow::_classname()
469 {
470 static const char name[] = "appwindow";
471 WNDCLASSEX wc = { sizeof(WNDCLASSEX) };
472 if (!GetClassInfoEx(win32::exe, name, &wc)) {
473 wc.lpfnWndProc = DefWindowProc;
474 wc.hInstance = win32::exe;
475 wc.hIcon = LoadIcon(wc.hInstance, MAKEINTRESOURCE(0));
476 wc.hCursor = LoadCursor(NULL, IDC_ARROW);
477 wc.lpszClassName = name;
478 wc.style = CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW;
479 win32::valid(RegisterClassEx(&wc));
480 }
481 return name;
482 }
483
484 LRESULT
485 appwindow::dispatch(UINT m, WPARAM w, LPARAM l)
486 {
487 switch (m) {
488 case WM_PAINT:
489 {
490 PAINTSTRUCT ps;
491 draw(BeginPaint(hwnd(), &ps));
492 EndPaint(hwnd(), &ps);
493 }
494 return 0;
495 case WM_ERASEBKGND:
496 erase(HDC(w));
497 return TRUE;
498 case WM_GETMINMAXINFO:
499 window::dispatch(m, w, l);
500 limit(LPMINMAXINFO(l));
501 return 0;
502 case WM_WINDOWPOSCHANGED:
503 if (!(PWINDOWPOS(l)->flags & SWP_NOZORDER)) raised(topmost());
504 break;
505 }
506 return window::dispatch(m, w, l);
507 }
508
509 LRESULT
510 appwindow::notify(WPARAM w, LPARAM l)
511 {
512 return LPNMHDR(l)->hwndFrom == hwnd() ? 0 :
513 SendMessage(LPNMHDR(l)->hwndFrom, WM_NOTIFY, w, l);
514 }
515
516 const RECT&
517 appwindow::adjust(RECT& bounds, int border) const
518 {
519 MONITORINFO info = { sizeof(info) };
520 GetMonitorInfo(MonitorFromRect(&bounds, MONITOR_DEFAULTTONEAREST), &info);
521 return adjust(bounds, info.rcMonitor, border);
522 }
523
524 const RECT&
525 appwindow::adjust(RECT& bounds, const RECT& monitor, int border) const
526 {
527 RECT r = monitor;
528 InflateRect(&r, -border, -border);
529 int w = bounds.right - bounds.left;
530 int h = bounds.bottom - bounds.top;
531 if (bounds.right < r.left) {
532 bounds.left = r.left - w, bounds.right = r.left;
533 } else if (bounds.left > r.right) {
534 bounds.left = r.right, bounds.right = r.right + w;
535 }
536 if (bounds.bottom < r.top) {
537 bounds.top = r.top - h, bounds.bottom = r.top;
538 } else if (bounds.top > r.bottom) {
539 bounds.top = r.bottom, bounds.bottom = r.bottom + h;
540 }
541 return bounds;
542 }

Back to OSDN">Back to OSDN
ViewVC Help
Powered by ViewVC 1.1.26