2 * Copyright 2003 Martin Fuchs
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 // Martin Fuchs, 23.07.2003
30 #include "shellclasses.h"
33 #include "../globals.h"
36 WindowClass::WindowClass(LPCTSTR classname, UINT style_, WNDPROC wndproc)
38 memset(this, 0, sizeof(WNDCLASSEX));
40 cbSize = sizeof(WNDCLASSEX);
42 hInstance = g_Globals._hInstance;
43 hCursor = LoadCursor(0, IDC_ARROW);
45 lpszClassName = classname;
46 lpfnWndProc = wndproc;
52 IconWindowClass::IconWindowClass(LPCTSTR classname, UINT nid, UINT style, WNDPROC wndproc)
53 : WindowClass(classname, style, wndproc)
56 hIconSm = SmallIcon(nid);
60 Window::WindowMap Window::s_wnd_map;
62 Window::CREATORFUNC Window::s_window_creator = NULL;
63 const void* Window::s_new_info = NULL;
65 HHOOK Window::s_hcbtHook = 0;
68 Window::StaticWindowData& Window::GetStaticWindowData()
70 static StaticWindowData s_initialized_data;
72 return s_initialized_data;
76 Window::Window(HWND hwnd)
79 Lock lock(GetStaticWindowData()._map_crit_sect); // protect access to s_wnd_map
81 s_wnd_map[_hwnd] = this;
86 Lock lock(GetStaticWindowData()._map_crit_sect); // protect access to s_wnd_map
88 s_wnd_map.erase(_hwnd);
92 HWND Window::Create(CREATORFUNC creator, DWORD dwExStyle,
93 LPCTSTR lpClassName, LPCTSTR lpWindowName,
94 DWORD dwStyle, int x, int y, int w, int h,
95 HWND hwndParent, HMENU hMenu, LPVOID lpParam)
97 Lock lock(GetStaticWindowData()._create_crit_sect); // protect access to s_window_creator and s_new_info
99 s_window_creator = creator;
102 return CreateWindowEx(dwExStyle, lpClassName, lpWindowName, dwStyle,
104 hwndParent, hMenu, g_Globals._hInstance, 0/*lpParam*/);
107 HWND Window::Create(CREATORFUNC creator, const void* info, DWORD dwExStyle,
108 LPCTSTR lpClassName, LPCTSTR lpWindowName,
109 DWORD dwStyle, int x, int y, int w, int h,
110 HWND hwndParent, HMENU hMenu, LPVOID lpParam)
112 Lock lock(GetStaticWindowData()._create_crit_sect); // protect access to s_window_creator and s_new_info
114 s_window_creator = creator;
117 return CreateWindowEx(dwExStyle, lpClassName, lpWindowName, dwStyle,
119 hwndParent, hMenu, g_Globals._hInstance, 0/*lpParam*/);
123 static Window* s_new_child_wnd = NULL;
125 Window* Window::create_mdi_child(HWND hmdiclient, const MDICREATESTRUCT& mcs, CREATORFUNC creator, const void* info)
127 Lock lock(GetStaticWindowData()._create_crit_sect); // protect access to s_window_creator and s_new_info
129 s_window_creator = creator;
131 s_new_child_wnd = NULL;
133 s_hcbtHook = SetWindowsHookEx(WH_CBT, CBTHookProc, 0, GetCurrentThreadId());
135 HWND hwnd = (HWND) SendMessage(hmdiclient, WM_MDICREATE, 0, (LPARAM)&mcs);
137 UnhookWindowsHookEx(s_hcbtHook);
139 Window* child = s_new_child_wnd;
141 s_new_child_wnd = NULL;
143 if (!hwnd || !child || !child->_hwnd)
149 LRESULT CALLBACK Window::CBTHookProc(int code, WPARAM wparam, LPARAM lparam)
151 if (code == HCBT_CREATEWND) {
152 // create Window controller and associate it with the window handle
153 Window* child = get_window((HWND)wparam);
156 s_new_child_wnd = child;
159 return CallNextHookEx(s_hcbtHook, code, wparam, lparam);
163 // get window controller from window handle
164 // if not already present, create a new controller
166 Window* Window::get_window(HWND hwnd)
169 Lock lock(GetStaticWindowData()._map_crit_sect); // protect access to s_wnd_map
171 WindowMap::const_iterator found = s_wnd_map.find(hwnd);
173 if (found!=s_wnd_map.end())
174 return found->second;
177 if (s_window_creator) { // protect for recursion
178 Lock lock(GetStaticWindowData()._create_crit_sect); // protect access to s_window_creator and s_new_info
180 const void* info = s_new_info;
183 CREATORFUNC window_creator = s_window_creator;
184 s_window_creator = NULL;
187 return window_creator(hwnd, info);
189 return CREATORFUNC_NO_INFO(window_creator)(hwnd);
196 LRESULT Window::Init(LPCREATESTRUCT pcs)
202 LRESULT CALLBACK Window::WindowWndProc(HWND hwnd, UINT nmsg, WPARAM wparam, LPARAM lparam)
204 Window* pThis = get_window(hwnd);
209 return pThis->Command(LOWORD(wparam), HIWORD(wparam));
212 return pThis->Notify(wparam, (NMHDR*)lparam);
215 return pThis->Init((LPCREATESTRUCT)lparam);
222 return pThis->WndProc(nmsg, wparam, lparam);
226 return DefWindowProc(hwnd, nmsg, wparam, lparam);
229 LRESULT Window::WndProc(UINT nmsg, WPARAM wparam, LPARAM lparam)
231 /*@@TODO: replaced by StartMenu::TrackStartmenu()
234 // close startup menu and other popup menus
235 // This functionality is for tray notification icons missing in MS Windows.
236 if (nmsg == WM_SETFOCUS)
237 CancelModes((HWND)wparam); // erronesly cancels desktop bar resize when switching from another process
240 return DefWindowProc(_hwnd, nmsg, wparam, lparam);
243 int Window::Command(int id, int code)
248 int Window::Notify(int id, NMHDR* pnmh)
253 void Window::CancelModes(HWND hwnd)
256 PostMessage(hwnd, WM_CANCELMODE, 0, 0);
258 PostMessage(HWND_BROADCAST, WM_CANCELMODE, 0, 0);
262 SubclassedWindow::SubclassedWindow(HWND hwnd)
265 _orgWndProc = SubclassWindow(_hwnd, WindowWndProc);
271 LRESULT SubclassedWindow::WndProc(UINT nmsg, WPARAM wparam, LPARAM lparam)
273 /*@@TODO: replaced by StartMenu::TrackStartmenu()
274 // close startup menu and other popup menus
275 // This functionality is for tray notification icons missing in MS Windows.
276 if (nmsg == WM_SETFOCUS)
277 CancelModes((HWND)wparam);
279 return CallWindowProc(_orgWndProc, _hwnd, nmsg, wparam, lparam);
283 ChildWindow::ChildWindow(HWND hwnd)
287 _split_pos = DEFAULT_SPLIT_POS;
288 _last_split = DEFAULT_SPLIT_POS;
292 ChildWindow* ChildWindow::create(HWND hmdiclient, const RECT& rect, CREATORFUNC creator, LPCTSTR classname, LPCTSTR title, const void* info)
296 mcs.szClass = classname;
298 mcs.hOwner = g_Globals._hInstance;
301 mcs.cx = rect.right - rect.left;
302 mcs.cy = rect.bottom - rect.top;
306 return static_cast<ChildWindow*>(create_mdi_child(hmdiclient, mcs, creator, info));
310 LRESULT ChildWindow::WndProc(UINT nmsg, WPARAM wparam, LPARAM lparam)
314 PaintCanvas canvas(_hwnd);
315 ClientRect rt(_hwnd);
316 rt.left = _split_pos-SPLIT_WIDTH/2;
317 rt.right = _split_pos+SPLIT_WIDTH/2+1;
318 HBRUSH lastBrush = SelectBrush(canvas, GetStockBrush(COLOR_SPLITBAR));
319 Rectangle(canvas, rt.left, rt.top-1, rt.right, rt.bottom+1);
320 SelectObject(canvas, lastBrush);
324 if (LOWORD(lparam) == HTCLIENT) {
327 ScreenToClient(_hwnd, &pt);
329 if (pt.x>=_split_pos-SPLIT_WIDTH/2 && pt.x<_split_pos+SPLIT_WIDTH/2+1) {
330 SetCursor(LoadCursor(0, IDC_SIZEWE));
337 if (wparam != SIZE_MINIMIZED)
338 resize_children(LOWORD(lparam), HIWORD(lparam));
341 case WM_GETMINMAXINFO:
342 DefMDIChildProc(_hwnd, nmsg, wparam, lparam);
344 {LPMINMAXINFO lpmmi = (LPMINMAXINFO)lparam;
346 lpmmi->ptMaxTrackSize.x <<= 1; // 2*GetSystemMetrics(SM_CXSCREEN) / SM_CXVIRTUALSCREEN
347 lpmmi->ptMaxTrackSize.y <<= 1; // 2*GetSystemMetrics(SM_CYSCREEN) / SM_CYVIRTUALSCREEN
350 case WM_LBUTTONDOWN: {
351 int x = GET_X_LPARAM(lparam);
353 ClientRect rt(_hwnd);
355 if (x>=_split_pos-SPLIT_WIDTH/2 && x<_split_pos+SPLIT_WIDTH/2+1) {
356 _last_split = _split_pos;
363 if (GetCapture() == _hwnd)
368 if (wparam == VK_ESCAPE)
369 if (GetCapture() == _hwnd) {
370 _split_pos = _last_split;
371 ClientRect rt(_hwnd);
372 resize_children(rt.right, rt.bottom);
375 SetCursor(LoadCursor(0, IDC_ARROW));
380 if (GetCapture() == _hwnd) {
381 int x = LOWORD(lparam);
383 ClientRect rt(_hwnd);
385 if (x>=0 && x<rt.right) {
387 resize_children(rt.right, rt.bottom);
388 rt.left = x-SPLIT_WIDTH/2;
389 rt.right = x+SPLIT_WIDTH/2+1;
390 InvalidateRect(_hwnd, &rt, FALSE);
391 UpdateWindow(_left_hwnd);
393 UpdateWindow(_right_hwnd);
398 case PM_DISPATCH_COMMAND:
402 return DefMDIChildProc(_hwnd, nmsg, wparam, lparam);
409 void ChildWindow::resize_children(int cx, int cy)
411 HDWP hdwp = BeginDeferWindowPos(4);
420 cx = _split_pos + SPLIT_WIDTH/2;
422 hdwp = DeferWindowPos(hdwp, _left_hwnd, 0, rt.left, rt.top, _split_pos-SPLIT_WIDTH/2-rt.left, rt.bottom-rt.top, SWP_NOZORDER|SWP_NOACTIVATE);
428 hdwp = DeferWindowPos(hdwp, _right_hwnd, 0, rt.left+cx+1, rt.top, rt.right-cx, rt.bottom-rt.top, SWP_NOZORDER|SWP_NOACTIVATE);
430 EndDeferWindowPos(hdwp);
434 WindowSet Window::s_pretranslate_windows;
436 void Window::register_pretranslate(HWND hwnd)
438 s_pretranslate_windows.insert(hwnd);
441 void Window::unregister_pretranslate(HWND hwnd)
443 s_pretranslate_windows.erase(hwnd);
446 BOOL Window::pretranslate_msg(LPMSG pmsg)
448 for(WindowSet::const_iterator it=Window::s_pretranslate_windows.begin(); it!=s_pretranslate_windows.end(); ++it)
449 if (SendMessage(*it, PM_TRANSLATE_MSG, 0, (LPARAM)pmsg))
456 WindowSet Window::s_dialogs;
458 void Window::register_dialog(HWND hwnd)
460 s_dialogs.insert(hwnd);
463 void Window::unregister_dialog(HWND hwnd)
465 s_dialogs.erase(hwnd);
468 BOOL Window::dispatch_dialog_msg(MSG* pmsg)
470 for(WindowSet::const_iterator it=Window::s_dialogs.begin(); it!=s_dialogs.end(); ++it)
471 if (IsDialogMessage(*it, pmsg))
478 int Window::MessageLoop()
482 while(GetMessage(&msg, 0, 0, 0)) {
484 if (pretranslate_msg(&msg))
487 if (dispatch_dialog_msg(&msg))
490 TranslateMessage(&msg);
493 DispatchMessage(&msg);
494 } catch(COMException& e) {
495 HandleException(e, g_Globals._hMainWnd);
497 } catch(COMException& e) {
498 HandleException(e, g_Globals._hMainWnd);
506 LRESULT Window::SendParent(UINT nmsg, WPARAM wparam, LPARAM lparam)
508 HWND parent = GetParent(_hwnd);
513 return SendMessage(parent, nmsg, wparam, lparam);
516 LRESULT Window::PostParent(UINT nmsg, WPARAM wparam, LPARAM lparam)
518 HWND parent = GetParent(_hwnd);
523 return PostMessage(parent, nmsg, wparam, lparam);
527 PreTranslateWindow::PreTranslateWindow(HWND hwnd)
530 register_pretranslate(hwnd);
533 PreTranslateWindow::~PreTranslateWindow()
535 unregister_pretranslate(_hwnd);
539 Dialog::Dialog(HWND hwnd)
542 register_dialog(hwnd);
547 unregister_dialog(_hwnd);
551 Button::Button(HWND parent, LPCTSTR title, int left, int top, int width, int height,
552 int id, DWORD flags, DWORD exStyle)
553 : WindowHandle(CreateWindowEx(exStyle, TEXT("BUTTON"), title, flags, left, top, width, height,
554 parent, (HMENU)id, g_Globals._hInstance, 0))
559 LRESULT OwnerdrawnButton::WndProc(UINT message, WPARAM wparam, LPARAM lparam)
561 if (message == PM_DISPATCH_DRAWITEM) {
562 DrawItem((LPDRAWITEMSTRUCT)lparam);
565 return super::WndProc(message, wparam, lparam);
569 Static::Static(HWND parent, LPCTSTR title, int left, int top, int width, int height,
570 int id, DWORD flags, DWORD exStyle)
571 : WindowHandle(CreateWindowEx(exStyle, TEXT("STATIC"), title, flags, left, top, width, height,
572 parent, (HMENU)id, g_Globals._hInstance, 0))
577 static RECT s_MyDrawText_Rect = {0, 0, 0, 0};
579 static BOOL CALLBACK MyDrawText(HDC hdc, LPARAM data, int cnt)
581 ::DrawText(hdc, (LPCTSTR)data, cnt, &s_MyDrawText_Rect, DT_SINGLELINE);
585 void OwnerdrawnButton::DrawGrayText(LPDRAWITEMSTRUCT dis, LPRECT pRect, LPCTSTR title, int dt_flags)
587 COLORREF gray = GetSysColor(COLOR_GRAYTEXT);
590 TextColor lcColor(dis->hDC, GetSysColor(COLOR_BTNHIGHLIGHT));
591 RECT shadowRect = {pRect->left+1, pRect->top+1, pRect->right+1, pRect->bottom+1};
592 DrawText(dis->hDC, title, -1, &shadowRect, dt_flags);
594 SetTextColor(dis->hDC, gray);
595 DrawText(dis->hDC, title, -1, pRect, dt_flags);
597 int old_r = pRect->right;
598 int old_b = pRect->bottom;
600 DrawText(dis->hDC, title, -1, pRect, dt_flags|DT_CALCRECT);
602 int x = pRect->left + (old_r-pRect->right)/2;
603 int y = pRect->top + (old_b-pRect->bottom)/2;
604 int w = pRect->right-pRect->left;
605 int h = pRect->bottom-pRect->top;
606 s_MyDrawText_Rect.right = w;
607 s_MyDrawText_Rect.bottom = h;
609 GrayString(dis->hDC, GetSysColorBrush(COLOR_GRAYTEXT), MyDrawText, (LPARAM)title, -1, x, y, w, h);
614 static BOOL DrawButton(HDC hdc, LPRECT prect, UINT state, HBRUSH hbrush)
616 FillRect(hdc, prect, hbrush);
617 DrawEdge(hdc, prect, EDGE_RAISED, BF_RECT|BF_SOFT);
624 void ColorButton::DrawItem(LPDRAWITEMSTRUCT dis)
626 UINT state = DFCS_BUTTONPUSH;
628 if (dis->itemState & ODS_DISABLED)
629 state |= DFCS_INACTIVE;
631 RECT textRect = {dis->rcItem.left+2, dis->rcItem.top+2, dis->rcItem.right-4, dis->rcItem.bottom-4};
633 if (dis->itemState & ODS_SELECTED) {
634 state |= DFCS_PUSHED;
635 ++textRect.left; ++textRect.top;
636 ++textRect.right; ++textRect.bottom;
639 DrawFrameControl(dis->hDC, &dis->rcItem, DFC_BUTTON, state);
640 //DrawButton(dis->hDC, &dis->rcItem, state, GetSysColorBrush(COLOR_BTNFACE));
642 TCHAR title[BUFFER_LEN];
643 GetWindowText(_hwnd, title, BUFFER_LEN);
645 BkMode bk_mode(dis->hDC, TRANSPARENT);
647 if (dis->itemState & (ODS_DISABLED|ODS_GRAYED))
648 DrawGrayText(dis, &textRect, title, DT_SINGLELINE|DT_VCENTER|DT_CENTER);
650 TextColor lcColor(dis->hDC, _textColor);
651 DrawText(dis->hDC, title, -1, &textRect, DT_SINGLELINE|DT_VCENTER|DT_CENTER);
654 if (dis->itemState & ODS_FOCUS) {
656 dis->rcItem.left+3, dis->rcItem.top+3,
657 dis->rcItem.right-dis->rcItem.left-4, dis->rcItem.bottom-dis->rcItem.top-4
659 if (dis->itemState & ODS_SELECTED) {
660 ++rect.left; ++rect.top;
661 ++rect.right; ++rect.bottom;
663 DrawFocusRect(dis->hDC, &rect);
669 void PictureButton::DrawItem(LPDRAWITEMSTRUCT dis)
671 UINT state = DFCS_BUTTONPUSH;
673 if (dis->itemState & ODS_DISABLED)
674 state |= DFCS_INACTIVE;
676 POINT iconPos = {dis->rcItem.left+2, (dis->rcItem.top+dis->rcItem.bottom-16)/2};
677 RECT textRect = {dis->rcItem.left+16+4, dis->rcItem.top+2, dis->rcItem.right-4, dis->rcItem.bottom-4};
679 if (dis->itemState & ODS_SELECTED) {
680 state |= DFCS_PUSHED;
681 ++iconPos.x; ++iconPos.y;
682 ++textRect.left; ++textRect.top;
683 ++textRect.right; ++textRect.bottom;
687 FillRect(dis->hDC, &dis->rcItem, _hBrush);
689 if (GetWindowStyle(_hwnd) & BS_FLAT) // Only with BS_FLAT set, there will be drawn a frame without highlight.
690 DrawEdge(dis->hDC, &dis->rcItem, EDGE_RAISED, BF_RECT|BF_FLAT);
692 //DrawFrameControl(dis->hDC, &dis->rcItem, DFC_BUTTON, state);
693 DrawButton(dis->hDC, &dis->rcItem, state, _hBrush);
695 DrawIconEx(dis->hDC, iconPos.x, iconPos.y, _hIcon, 16, 16, 0, _hBrush, DI_NORMAL);
697 TCHAR title[BUFFER_LEN];
698 GetWindowText(_hwnd, title, BUFFER_LEN);
700 BkMode bk_mode(dis->hDC, TRANSPARENT);
702 if (dis->itemState & (ODS_DISABLED|ODS_GRAYED))
703 DrawGrayText(dis, &textRect, title, DT_SINGLELINE|DT_VCENTER/*|DT_CENTER*/);
705 TextColor lcColor(dis->hDC, GetSysColor(COLOR_BTNTEXT));
706 DrawText(dis->hDC, title, -1, &textRect, DT_SINGLELINE|DT_VCENTER/*|DT_CENTER*/);
709 if (dis->itemState & ODS_FOCUS) {
711 dis->rcItem.left+3, dis->rcItem.top+3,
712 dis->rcItem.right-dis->rcItem.left-4, dis->rcItem.bottom-dis->rcItem.top-4
714 if (dis->itemState & ODS_SELECTED) {
715 ++rect.left; ++rect.top;
716 ++rect.right; ++rect.bottom;
718 DrawFocusRect(dis->hDC, &rect);
723 ToolTip::ToolTip(HWND owner)
724 : super(CreateWindowEx(WS_EX_TOPMOST|WS_EX_NOPARENTNOTIFY, TOOLTIPS_CLASS, 0,
725 WS_POPUP|TTS_NOPREFIX|TTS_ALWAYSTIP, CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,
726 owner, 0, g_Globals._hInstance, 0))