2 * Copyright 2003, 2004 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
25 // Martin Fuchs, 22.08.2003
31 #include "../resource.h"
33 #include "desktopbar.h"
35 #include "startmenu.h"
36 #include "traynotify.h"
37 #include "quicklaunch.h"
39 #include "../dialogs/settings.h"
42 DesktopBar::DesktopBar(HWND hwnd
)
45 _trayIcon(hwnd
, ID_TRAY_VOLUME
)
47 WM_TASKBARCREATED(RegisterWindowMessage(WINMSG_TASKBARCREATED
))
50 SetWindowIcon(hwnd
, IDI_REACTOS
);
52 SystemParametersInfo(SPI_GETWORKAREA
, 0, &_work_area_org
, 0);
55 DesktopBar::~DesktopBar()
57 // restore work area to the previous size
58 SystemParametersInfo(SPI_SETWORKAREA
, 0, &_work_area_org
, 0);
59 PostMessage(HWND_BROADCAST
, WM_SETTINGCHANGE
, SPI_SETWORKAREA
, 0);
61 // exit application after destroying desktop window
66 HWND
DesktopBar::Create()
68 static BtnWindowClass
wcDesktopBar(CLASSNAME_EXPLORERBAR
);
72 rect
.left
= -2; // hide left border
74 rect
.top
= -2; // hide top border
76 rect
.top
= GetSystemMetrics(SM_CYSCREEN
) - DESKTOPBARBAR_HEIGHT
;
78 rect
.right
= GetSystemMetrics(SM_CXSCREEN
) + 2;
79 rect
.bottom
= rect
.top
+ DESKTOPBARBAR_HEIGHT
+ 2;
81 return Window::Create(WINDOW_CREATOR(DesktopBar
), WS_EX_PALETTEWINDOW
,
82 wcDesktopBar
, TITLE_EXPLORERBAR
,
83 WS_POPUP
|WS_THICKFRAME
|WS_CLIPCHILDREN
|WS_VISIBLE
,
84 rect
.left
, rect
.top
, rect
.right
-rect
.left
, rect
.bottom
-rect
.top
, 0);
88 LRESULT
DesktopBar::Init(LPCREATESTRUCT pcs
)
93 // create start button
94 ResString
start_str(IDS_START
);
95 WindowCanvas
canvas(_hwnd
);
96 FontSelection
font(canvas
, GetStockFont(ANSI_VAR_FONT
));
98 DrawText(canvas
, start_str
, -1, &rect
, DT_SINGLELINE
|DT_CALCRECT
);
99 int start_btn_width
= rect
.right
+16+8;
101 _taskbar_pos
= start_btn_width
+ 6;
103 // create "Start" button
104 HWND hwndStart
= Button(_hwnd
, start_str
, 1, 1, start_btn_width
, REBARBAND_HEIGHT
, IDC_START
, WS_VISIBLE
|WS_CHILD
|BS_OWNERDRAW
);
105 SetWindowFont(hwndStart
, GetStockFont(ANSI_VAR_FONT
), FALSE
);
106 new StartButton(hwndStart
);
108 /* Save the handle to the window, needed for push-state handling */
109 _hwndStartButton
= hwndStart
;
111 // disable double clicks
112 SetClassLongPtr(hwndStart
, GCL_STYLE
, GetClassLongPtr(hwndStart
, GCL_STYLE
) & ~CS_DBLCLKS
);
115 _hwndTaskBar
= TaskBar::Create(_hwnd
);
117 #ifndef __MINGW32__ // SHRestricted() missing in MinGW (as of 29.10.2003)
118 if (!g_Globals
._SHRestricted
|| !SHRestricted(REST_NOTRAYITEMSDISPLAY
))
120 // create tray notification area
121 _hwndNotify
= NotifyArea::Create(_hwnd
);
124 // notify all top level windows about the successfully created desktop bar
125 //@@ Use SendMessage() instead of PostMessage() to avoid problems with delayed created shell service objects?
126 PostMessage(HWND_BROADCAST
, WM_TASKBARCREATED
, 0, 0);
129 _hwndQuickLaunch
= QuickLaunchBar::Create(_hwnd
);
131 // create rebar window to manage task and quick launch bar
133 _hwndrebar
= CreateWindowEx(WS_EX_TOOLWINDOW
, REBARCLASSNAME
, NULL
,
134 WS_CHILD
|WS_VISIBLE
|WS_CLIPSIBLINGS
|WS_CLIPCHILDREN
|
135 RBS_VARHEIGHT
|RBS_AUTOSIZE
|RBS_DBLCLKTOGGLE
| //|RBS_REGISTERDROP
136 CCS_NODIVIDER
|CCS_NOPARENTALIGN
|CCS_TOP
,
137 0, 0, 0, 0, _hwnd
, 0, g_Globals
._hInstance
, 0);
139 REBARBANDINFO rbBand
;
141 rbBand
.cbSize
= sizeof(REBARBANDINFO
);
142 rbBand
.fMask
= RBBIM_TEXT
|RBBIM_STYLE
|RBBIM_CHILD
|RBBIM_CHILDSIZE
|RBBIM_SIZE
|RBBIM_ID
|RBBIM_IDEALSIZE
;
143 #ifndef RBBS_HIDETITLE // missing in MinGW headers as of 25.02.2004
144 #define RBBS_HIDETITLE 0x400
146 rbBand
.cyChild
= REBARBAND_HEIGHT
;
147 rbBand
.cyMaxChild
= (ULONG
)-1;
148 rbBand
.cyMinChild
= REBARBAND_HEIGHT
;
149 rbBand
.cyIntegral
= REBARBAND_HEIGHT
+ 3; //@@ OK?
150 rbBand
.fStyle
= RBBS_VARIABLEHEIGHT
|RBBS_GRIPPERALWAYS
|RBBS_HIDETITLE
;
152 TCHAR QuickLaunchBand
[] = _T("Quicklaunch");
153 rbBand
.lpText
= QuickLaunchBand
;
154 rbBand
.hwndChild
= _hwndQuickLaunch
;
156 rbBand
.cxMinChild
= 100;
157 rbBand
.wID
= IDW_QUICKLAUNCHBAR
;
158 SendMessage(_hwndrebar
, RB_INSERTBAND
, (WPARAM
)-1, (LPARAM
)&rbBand
);
160 TCHAR TaskbarBand
[] = _T("Taskbar");
161 rbBand
.lpText
= TaskbarBand
;
162 rbBand
.hwndChild
= _hwndTaskBar
;
163 rbBand
.cx
= 200; //pcs->cx-_taskbar_pos-quicklaunch_width-(notifyarea_width+1);
164 rbBand
.cxMinChild
= 50;
165 rbBand
.wID
= IDW_TASKTOOLBAR
;
166 SendMessage(_hwndrebar
, RB_INSERTBAND
, (WPARAM
)-1, (LPARAM
)&rbBand
);
172 // prepare Startmenu, but hide it for now
173 _startMenuRoot
= GET_WINDOW(StartMenuRoot
, StartMenuRoot::Create(_hwndStartButton
, STARTMENUROOT_ICON_SIZE
));
174 _startMenuRoot
->_hwndStartButton
= _hwndStartButton
;
180 StartButton::StartButton(HWND hwnd
)
181 : PictureButton(hwnd
, SmallIcon(IDI_STARTMENU
), GetSysColorBrush(COLOR_BTNFACE
))
185 LRESULT
StartButton::WndProc(UINT nmsg
, WPARAM wparam
, LPARAM lparam
)
188 // one click activation: handle button-down message, don't wait for button-up
190 if (!Button_GetState(_hwnd
)) {
191 Button_SetState(_hwnd
, TRUE
);
195 SendMessage(GetParent(_hwnd
), WM_COMMAND
, MAKEWPARAM(GetDlgCtrlID(_hwnd
),0), 0);
198 Button_SetState(_hwnd
, FALSE
);
201 // re-target mouse move messages while moving the mouse cursor through the start menu
203 if (GetCapture() == _hwnd
) {
204 POINT pt
= {GET_X_LPARAM(lparam
), GET_Y_LPARAM(lparam
)};
206 ClientToScreen(_hwnd
, &pt
);
207 HWND hwnd
= WindowFromPoint(pt
);
209 if (hwnd
&& hwnd
!=_hwnd
) {
210 ScreenToClient(hwnd
, &pt
);
211 SendMessage(hwnd
, WM_MOUSEMOVE
, 0, MAKELPARAM(pt
.x
, pt
.y
));
217 if (GetCapture() == _hwnd
) {
220 POINT pt
= {GET_X_LPARAM(lparam
), GET_Y_LPARAM(lparam
)};
222 ClientToScreen(_hwnd
, &pt
);
223 HWND hwnd
= WindowFromPoint(pt
);
225 if (hwnd
&& hwnd
!=_hwnd
) {
226 ScreenToClient(hwnd
, &pt
);
227 PostMessage(hwnd
, WM_LBUTTONDOWN
, 0, MAKELPARAM(pt
.x
, pt
.y
));
228 PostMessage(hwnd
, WM_LBUTTONUP
, 0, MAKELPARAM(pt
.x
, pt
.y
));
238 return super::WndProc(nmsg
, wparam
, lparam
);
245 void DesktopBar::RegisterHotkeys()
247 // register hotkey WIN+E opening explorer
248 RegisterHotKey(_hwnd
, 0, MOD_WIN
, 'E');
250 ///@todo register all common hotkeys
253 void DesktopBar::ProcessHotKey(int id_hotkey
)
256 case 0: explorer_show_frame(SW_SHOWNORMAL
);
259 ///@todo implement all common hotkeys
264 LRESULT
DesktopBar::WndProc(UINT nmsg
, WPARAM wparam
, LPARAM lparam
)
268 LRESULT res
= super::WndProc(nmsg
, wparam
, lparam
);
270 if (res
>=HTSIZEFIRST
&& res
<=HTSIZELAST
) {
271 #ifdef TASKBAR_AT_TOP
272 if (res
== HTBOTTOM
) // enable vertical resizing at the lower border
274 if (res
== HTTOP
) // enable vertical resizing at the upper border
278 return HTCLIENT
; // disable any other resizing
283 if ((wparam
&0xFFF0) == SC_SIZE
) {
284 #ifdef TASKBAR_AT_TOP
285 if (wparam
== SC_SIZE
+6)// enable vertical resizing at the lower border
287 if (wparam
== SC_SIZE
+3)// enable vertical resizing at the upper border
291 return 0; // disable any other resizing
292 } else if (wparam
== SC_TASKLIST
)
297 Resize(LOWORD(lparam
), HIWORD(lparam
));
301 ControlResize(wparam
, lparam
);
304 case PM_RESIZE_CHILDREN
: {
305 ClientRect
size(_hwnd
);
306 Resize(size
.right
, size
.bottom
);
310 ShowExitWindowsDialog(_hwnd
);
314 ProcessHotKey(wparam
);
318 return ProcessCopyData((COPYDATASTRUCT
*)lparam
);
320 case WM_CONTEXTMENU
: {
322 p
.x
= LOWORD(lparam
);
323 p
.y
= HIWORD(lparam
);
324 PopupMenu
menu(IDM_DESKTOPBAR
);
325 SetMenuDefaultItem(menu
, 0, MF_BYPOSITION
);
326 menu
.TrackPopupMenu(_hwnd
, p
);
329 case PM_GET_LAST_ACTIVE
:
331 return SendMessage(_hwndTaskBar
, nmsg
, wparam
, lparam
);
334 case PM_REFRESH_CONFIG
: ///@todo read desktop bar settings
335 SendMessage(_hwndNotify
, PM_REFRESH_CONFIG
, 0, 0);
339 if (wparam
== ID_TRAY_VOLUME
) {
340 KillTimer(_hwnd
, wparam
);
341 launch_file(_hwnd
, TEXT("sndvol32.exe"), SW_SHOWNORMAL
, TEXT("-t")); // launch volume control in small mode
345 case PM_GET_NOTIFYAREA
:
346 return (LRESULT
)(HWND
)_hwndNotify
;
349 return super::WndProc(nmsg
, wparam
, lparam
);
355 int DesktopBar::Notify(int id
, NMHDR
* pnmh
)
357 if (pnmh
->code
== RBN_CHILDSIZE
) {
358 /* align the task bands to the top, so it's in row with the Start button */
359 NMREBARCHILDSIZE
* childSize
= (NMREBARCHILDSIZE
*)pnmh
;
361 if (childSize
->wID
== IDW_TASKTOOLBAR
) {
362 int cy
= childSize
->rcChild
.top
- childSize
->rcBand
.top
;
365 childSize
->rcChild
.bottom
-= cy
;
366 childSize
->rcChild
.top
-= cy
;
374 void DesktopBar::Resize(int cx
, int cy
)
376 ///@todo general children resizing algorithm
377 int quicklaunch_width
= SendMessage(_hwndQuickLaunch
, PM_GET_WIDTH
, 0, 0);
378 int notifyarea_width
= SendMessage(_hwndNotify
, PM_GET_WIDTH
, 0, 0);
380 HDWP hdwp
= BeginDeferWindowPos(3);
383 DeferWindowPos(hdwp
, _hwndrebar
, 0, _taskbar_pos
, 1, cx
-_taskbar_pos
-(notifyarea_width
+1), cy
-2, SWP_NOZORDER
|SWP_NOACTIVATE
);
385 if (_hwndQuickLaunch
)
386 DeferWindowPos(hdwp
, _hwndQuickLaunch
, 0, _taskbar_pos
, 1, quicklaunch_width
, cy
-2, SWP_NOZORDER
|SWP_NOACTIVATE
);
389 DeferWindowPos(hdwp
, _hwndTaskBar
, 0, _taskbar_pos
+quicklaunch_width
, 0, cx
-_taskbar_pos
-quicklaunch_width
-(notifyarea_width
+1), cy
, SWP_NOZORDER
|SWP_NOACTIVATE
);
393 DeferWindowPos(hdwp
, _hwndNotify
, 0, cx
-(notifyarea_width
+1), 1, notifyarea_width
, cy
-2, SWP_NOZORDER
|SWP_NOACTIVATE
);
395 EndDeferWindowPos(hdwp
);
397 WindowRect
rect(_hwnd
);
398 RECT work_area
= {0, 0, GetSystemMetrics(SM_CXSCREEN
), rect
.top
};
399 SystemParametersInfo(SPI_SETWORKAREA
, 0, &work_area
, 0); // don't use SPIF_SENDCHANGE because then we have to wait for any message being delivered
400 PostMessage(HWND_BROADCAST
, WM_SETTINGCHANGE
, SPI_SETWORKAREA
, 0);
404 int DesktopBar::Command(int id
, int code
)
411 case ID_ABOUT_EXPLORER
:
412 explorer_about(g_Globals
._hwndDesktop
);
415 case ID_DESKTOPBAR_SETTINGS
:
416 ExplorerPropertySheet(g_Globals
._hwndDesktop
);
419 case ID_MINIMIZE_ALL
:
420 g_Globals
._desktops
.ToggleMinimize();
424 explorer_show_frame(SW_SHOWNORMAL
);
428 launch_file(_hwnd
, TEXT("taskmgr.exe"), SW_SHOWNORMAL
);
431 case ID_SWITCH_DESKTOP_1
:
432 case ID_SWITCH_DESKTOP_1
+1: {
433 int desktop_idx
= id
- ID_SWITCH_DESKTOP_1
;
435 g_Globals
._desktops
.SwitchToDesktop(desktop_idx
);
437 if (_hwndQuickLaunch
)
438 PostMessage(_hwndQuickLaunch
, PM_UPDATE_DESKTOP
, desktop_idx
, 0);
443 launch_file(_hwnd
, TEXT("sndvol32.exe"), SW_SHOWNORMAL
); // launch volume control application
446 case ID_VOLUME_PROPERTIES
:
447 launch_cpanel(_hwnd
, TEXT("mmsys.cpl"));
452 if (_hwndQuickLaunch
)
453 return SendMessage(_hwndQuickLaunch
, WM_COMMAND
, MAKEWPARAM(id
,code
), 0);
462 void DesktopBar::ShowStartMenu()
466 // set the Button, if not set
467 if (!Button_GetState(_hwndStartButton
))
468 Button_SetState(_hwndStartButton
, TRUE
);
470 _startMenuRoot
->TrackStartmenu();
472 // StartMenu was closed, release button state
473 Button_SetState(_hwndStartButton
, false);
478 /// copy data structure for tray notifications
479 struct TrayNotifyCDS
{
482 NOTIFYICONDATA nicon_data
;
485 LRESULT
DesktopBar::ProcessCopyData(COPYDATASTRUCT
* pcd
)
487 // Is this a tray notification message?
488 if (pcd
->dwData
== 1) {
489 TrayNotifyCDS
* ptr
= (TrayNotifyCDS
*) pcd
->lpData
;
491 NotifyArea
* notify_area
= GET_WINDOW(NotifyArea
, _hwndNotify
);
494 return notify_area
->ProcessTrayNotification(ptr
->notify_code
, &ptr
->nicon_data
);
501 void DesktopBar::ControlResize(WPARAM wparam
, LPARAM lparam
)
503 PRECT dragRect
= (PRECT
) lparam
;
504 //int screenWidth = GetSystemMetrics(SM_CXSCREEN);
505 int screenHeight
= GetSystemMetrics(SM_CYSCREEN
);
507 ///@todo write code for taskbar being at sides or top.
510 case WMSZ_BOTTOM
: ///@todo Taskbar is at the top of the screen
513 case WMSZ_TOP
: // Taskbar is at the bottom of the screen
514 dragRect
->top
= screenHeight
- (((screenHeight
- dragRect
->top
) + DESKTOPBARBAR_HEIGHT
/2) / DESKTOPBARBAR_HEIGHT
) * DESKTOPBARBAR_HEIGHT
;
515 if (dragRect
->top
< screenHeight
/ 2)
516 dragRect
->top
= screenHeight
- (screenHeight
/2 / DESKTOPBARBAR_HEIGHT
* DESKTOPBARBAR_HEIGHT
);
517 else if (dragRect
->top
> screenHeight
- 5)
518 dragRect
->top
= screenHeight
- 5;
521 case WMSZ_RIGHT
: ///@todo Taskbar is at the left of the screen
524 case WMSZ_LEFT
: ///@todo Taskbar is at the right of the screen
532 void DesktopBar::AddTrayIcons()
534 _trayIcon
.Add(SmallIcon(IDI_SPEAKER
), ResString(IDS_VOLUME
));
537 void DesktopBar::TrayClick(UINT id
, int btn
)
541 if (btn
== TRAYBUTTON_LEFT
)
542 SetTimer(_hwnd
, ID_TRAY_VOLUME
, 500, NULL
); // wait a bit to correctly handle double clicks
544 PopupMenu
menu(IDM_VOLUME
);
545 SetMenuDefaultItem(menu
, 0, MF_BYPOSITION
);
546 menu
.TrackPopupMenuAtPos(_hwnd
, GetMessagePos());
552 void DesktopBar::TrayDblClick(UINT id
, int btn
)
556 KillTimer(_hwnd
, ID_TRAY_VOLUME
); // finish one-click timer
557 launch_file(_hwnd
, TEXT("sndvol32.exe"), SW_SHOWNORMAL
); // launch volume control application