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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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
);
97 DrawText(canvas
, start_str
, -1, &rect
, DT_SINGLELINE
|DT_CALCRECT
);
98 int start_btn_width
= rect
.right
+16+8;
100 _taskbar_pos
= start_btn_width
+ 6;
102 // create "Start" button
103 HWND hwndStart
= Button(_hwnd
, start_str
, 1, 1, start_btn_width
, REBARBAND_HEIGHT
, IDC_START
, WS_VISIBLE
|WS_CHILD
|BS_OWNERDRAW
);
104 new StartButton(hwndStart
);
105 // disable double clicks
106 SetClassLong(hwndStart
, GCL_STYLE
, GetClassLong(hwndStart
, GCL_STYLE
) & ~CS_DBLCLKS
);
109 _hwndTaskBar
= TaskBar::Create(_hwnd
);
111 #ifndef __MINGW32__ // SHRestricted() missing in MinGW (as of 29.10.2003)
112 if (!g_Globals
._SHRestricted
|| !SHRestricted(REST_NOTRAYITEMSDISPLAY
))
114 // create tray notification area
115 _hwndNotify
= NotifyArea::Create(_hwnd
);
118 // notify all top level windows about the successfully created desktop bar
119 //@@ Use SendMessage() instead of PostMessage() to avoid problems with delayed created shell service objects?
120 PostMessage(HWND_BROADCAST
, WM_TASKBARCREATED
, 0, 0);
123 _hwndQuickLaunch
= QuickLaunchBar::Create(_hwnd
);
125 // create rebar window to manage task and quick launch bar
127 _hwndrebar
= CreateWindowEx(WS_EX_TOOLWINDOW
, REBARCLASSNAME
, NULL
,
128 WS_CHILD
|WS_VISIBLE
|WS_CLIPSIBLINGS
|WS_CLIPCHILDREN
|
129 RBS_VARHEIGHT
|RBS_AUTOSIZE
|RBS_DBLCLKTOGGLE
| //|RBS_REGISTERDROP
130 CCS_NODIVIDER
|CCS_NOPARENTALIGN
|CCS_TOP
,
131 0, 0, 0, 0, _hwnd
, 0, g_Globals
._hInstance
, 0);
133 REBARBANDINFO rbBand
;
135 rbBand
.cbSize
= sizeof(REBARBANDINFO
);
136 rbBand
.fMask
= RBBIM_TEXT
|RBBIM_STYLE
|RBBIM_CHILD
|RBBIM_CHILDSIZE
|RBBIM_SIZE
|RBBIM_ID
|RBBIM_IDEALSIZE
;
137 #ifndef RBBS_HIDETITLE // missing in MinGW headers as of 25.02.2004
138 #define RBBS_HIDETITLE 0x400
140 rbBand
.cyChild
= REBARBAND_HEIGHT
;
141 rbBand
.cyMaxChild
= (ULONG
)-1;
142 rbBand
.cyMinChild
= REBARBAND_HEIGHT
;
143 rbBand
.cyIntegral
= REBARBAND_HEIGHT
+ 3; //@@ OK?
144 rbBand
.cxMinChild
= rbBand
.cyIntegral
* 3;
145 rbBand
.fStyle
= RBBS_VARIABLEHEIGHT
|RBBS_GRIPPERALWAYS
|RBBS_HIDETITLE
;
147 rbBand
.lpText
= TEXT("Quicklaunch");
148 rbBand
.hwndChild
= _hwndQuickLaunch
;
150 rbBand
.wID
= IDW_QUICKLAUNCHBAR
;
151 SendMessage(_hwndrebar
, RB_INSERTBAND
, (WPARAM
)-1, (LPARAM
)&rbBand
);
153 rbBand
.lpText
= TEXT("Taskbar");
154 rbBand
.hwndChild
= _hwndTaskBar
;
155 rbBand
.cx
= 200; //pcs->cx-_taskbar_pos-quicklaunch_width-(notifyarea_width+1);
156 rbBand
.wID
= IDW_TASKTOOLBAR
;
157 SendMessage(_hwndrebar
, RB_INSERTBAND
, (WPARAM
)-1, (LPARAM
)&rbBand
);
163 // prepare Startmenu, but hide it for now
164 _startMenuRoot
= GET_WINDOW(StartMenuRoot
, StartMenuRoot::Create(_hwnd
, true)); //@@ _large_icons
170 StartButton::StartButton(HWND hwnd
)
171 : PictureButton(hwnd
, SmallIcon(IDI_STARTMENU
), GetSysColorBrush(COLOR_BTNFACE
))
175 LRESULT
StartButton::WndProc(UINT nmsg
, WPARAM wparam
, LPARAM lparam
)
178 // one click activation: handle button-down message, don't wait for button-up
180 if (!Button_GetState(_hwnd
)) {
181 Button_SetState(_hwnd
, TRUE
);
185 SendMessage(GetParent(_hwnd
), WM_COMMAND
, MAKEWPARAM(GetDlgCtrlID(_hwnd
),0), 0);
188 Button_SetState(_hwnd
, FALSE
);
191 // re-target mouse move messages while moving the mouse cursor through the start menu
193 if (GetCapture() == _hwnd
) {
194 POINT pt
= {GET_X_LPARAM(lparam
), GET_Y_LPARAM(lparam
)};
196 ClientToScreen(_hwnd
, &pt
);
197 HWND hwnd
= WindowFromPoint(pt
);
199 if (hwnd
&& hwnd
!=_hwnd
) {
200 ScreenToClient(hwnd
, &pt
);
201 SendMessage(hwnd
, WM_MOUSEMOVE
, 0, MAKELPARAM(pt
.x
, pt
.y
));
207 if (GetCapture() == _hwnd
) {
210 POINT pt
= {GET_X_LPARAM(lparam
), GET_Y_LPARAM(lparam
)};
212 ClientToScreen(_hwnd
, &pt
);
213 HWND hwnd
= WindowFromPoint(pt
);
215 if (hwnd
&& hwnd
!=_hwnd
) {
216 ScreenToClient(hwnd
, &pt
);
217 PostMessage(hwnd
, WM_LBUTTONDOWN
, 0, MAKELPARAM(pt
.x
, pt
.y
));
218 PostMessage(hwnd
, WM_LBUTTONUP
, 0, MAKELPARAM(pt
.x
, pt
.y
));
228 return super::WndProc(nmsg
, wparam
, lparam
);
235 void DesktopBar::RegisterHotkeys()
237 // register hotkey WIN+E opening explorer
238 RegisterHotKey(_hwnd
, 0, MOD_WIN
, 'E');
240 ///@todo register all common hotkeys
243 void DesktopBar::ProcessHotKey(int id_hotkey
)
246 case 0: explorer_show_frame(SW_SHOWNORMAL
);
249 ///@todo implement all common hotkeys
254 LRESULT
DesktopBar::WndProc(UINT nmsg
, WPARAM wparam
, LPARAM lparam
)
258 LRESULT res
= super::WndProc(nmsg
, wparam
, lparam
);
260 if (res
>=HTSIZEFIRST
&& res
<=HTSIZELAST
) {
261 #ifdef TASKBAR_AT_TOP
262 if (res
== HTBOTTOM
) // enable vertical resizing at the lower border
264 if (res
== HTTOP
) // enable vertical resizing at the upper border
268 return HTCLIENT
; // disable any other resizing
273 if ((wparam
&0xFFF0) == SC_SIZE
) {
274 #ifdef TASKBAR_AT_TOP
275 if (wparam
== SC_SIZE
+6)// enable vertical resizing at the lower border
277 if (wparam
== SC_SIZE
+3)// enable vertical resizing at the upper border
281 return 0; // disable any other resizing
282 } else if (wparam
== SC_TASKLIST
)
287 Resize(LOWORD(lparam
), HIWORD(lparam
));
291 ControlResize(wparam
, lparam
);
294 case PM_RESIZE_CHILDREN
: {
295 ClientRect
size(_hwnd
);
296 Resize(size
.right
, size
.bottom
);
300 ShowExitWindowsDialog(_hwnd
);
304 ProcessHotKey(wparam
);
308 return ProcessCopyData((COPYDATASTRUCT
*)lparam
);
310 case WM_CONTEXTMENU
: {
311 PopupMenu
menu(IDM_DESKTOPBAR
);
312 SetMenuDefaultItem(menu
, 0, MF_BYPOSITION
);
313 menu
.TrackPopupMenu(_hwnd
, MAKEPOINTS(lparam
));
316 case PM_GET_LAST_ACTIVE
:
318 return SendMessage(_hwndTaskBar
, nmsg
, wparam
, lparam
);
321 case PM_REFRESH_CONFIG
: ///@todo read desktop bar settings
322 SendMessage(_hwndNotify
, PM_REFRESH_CONFIG
, 0, 0);
326 if (wparam
== ID_TRAY_VOLUME
) {
327 KillTimer(_hwnd
, wparam
);
328 launch_file(_hwnd
, TEXT("sndvol32.exe"), SW_SHOWNORMAL
, TEXT("-t")); // launch volume control in small mode
332 case PM_GET_NOTIFYAREA
:
333 return (LRESULT
)(HWND
)_hwndNotify
;
336 return super::WndProc(nmsg
, wparam
, lparam
);
342 int DesktopBar::Notify(int id
, NMHDR
* pnmh
)
344 if (pnmh
->code
== RBN_CHILDSIZE
) {
345 /* align the task bands to the top, so it's in row with the Start button */
346 NMREBARCHILDSIZE
* childSize
= (NMREBARCHILDSIZE
*)pnmh
;
348 if (childSize
->wID
== IDW_TASKTOOLBAR
) {
349 int cy
= childSize
->rcChild
.top
- childSize
->rcBand
.top
;
352 childSize
->rcChild
.bottom
-= cy
;
353 childSize
->rcChild
.top
-= cy
;
361 void DesktopBar::Resize(int cx
, int cy
)
363 ///@todo general children resizing algorithm
364 int quicklaunch_width
= SendMessage(_hwndQuickLaunch
, PM_GET_WIDTH
, 0, 0);
365 int notifyarea_width
= SendMessage(_hwndNotify
, PM_GET_WIDTH
, 0, 0);
367 HDWP hdwp
= BeginDeferWindowPos(3);
370 DeferWindowPos(hdwp
, _hwndrebar
, 0, _taskbar_pos
, 1, cx
-_taskbar_pos
-(notifyarea_width
+1), cy
-2, SWP_NOZORDER
|SWP_NOACTIVATE
);
372 if (_hwndQuickLaunch
)
373 DeferWindowPos(hdwp
, _hwndQuickLaunch
, 0, _taskbar_pos
, 1, quicklaunch_width
, cy
-2, SWP_NOZORDER
|SWP_NOACTIVATE
);
376 DeferWindowPos(hdwp
, _hwndTaskBar
, 0, _taskbar_pos
+quicklaunch_width
, 0, cx
-_taskbar_pos
-quicklaunch_width
-(notifyarea_width
+1), cy
, SWP_NOZORDER
|SWP_NOACTIVATE
);
380 DeferWindowPos(hdwp
, _hwndNotify
, 0, cx
-(notifyarea_width
+1), 1, notifyarea_width
, cy
-2, SWP_NOZORDER
|SWP_NOACTIVATE
);
382 EndDeferWindowPos(hdwp
);
384 WindowRect
rect(_hwnd
);
385 RECT work_area
= {0, 0, GetSystemMetrics(SM_CXSCREEN
), rect
.top
};
386 SystemParametersInfo(SPI_SETWORKAREA
, 0, &work_area
, 0); // don't use SPIF_SENDCHANGE because then we have to wait for any message being delivered
387 PostMessage(HWND_BROADCAST
, WM_SETTINGCHANGE
, SPI_SETWORKAREA
, 0);
391 int DesktopBar::Command(int id
, int code
)
398 case ID_ABOUT_EXPLORER
:
399 explorer_about(_hwnd
);
402 case ID_DESKTOPBAR_SETTINGS
:
403 ExplorerPropertySheet(_hwnd
);
406 case ID_MINIMIZE_ALL
:
407 g_Globals
._desktops
.ToggleMinimize();
411 explorer_show_frame(SW_SHOWNORMAL
);
415 launch_file(_hwnd
, TEXT("taskmgr.exe"), SW_SHOWNORMAL
);
418 case ID_SWITCH_DESKTOP_1
:
419 case ID_SWITCH_DESKTOP_1
+1:
420 case ID_SWITCH_DESKTOP_1
+2:
421 case ID_SWITCH_DESKTOP_1
+3: {
422 int desktop_idx
= id
- ID_SWITCH_DESKTOP_1
;
424 g_Globals
._desktops
.SwitchToDesktop(desktop_idx
);
426 if (_hwndQuickLaunch
)
427 PostMessage(_hwndQuickLaunch
, PM_UPDATE_DESKTOP
, desktop_idx
, 0);
432 launch_file(_hwnd
, TEXT("sndvol32.exe"), SW_SHOWNORMAL
); // launch volume control application
435 case ID_VOLUME_PROPERTIES
:
436 launch_cpanel(_hwnd
, TEXT("mmsys.cpl"));
441 if (_hwndQuickLaunch
)
442 return SendMessage(_hwndQuickLaunch
, WM_COMMAND
, MAKEWPARAM(id
,code
), 0);
451 void DesktopBar::ShowStartMenu()
454 _startMenuRoot
->TrackStartmenu();
458 /// copy data structure for tray notifications
459 struct TrayNotifyCDS
{
462 NOTIFYICONDATA nicon_data
;
465 LRESULT
DesktopBar::ProcessCopyData(COPYDATASTRUCT
* pcd
)
467 // Is this a tray notification message?
468 if (pcd
->dwData
== 1) {
469 TrayNotifyCDS
* ptr
= (TrayNotifyCDS
*) pcd
->lpData
;
471 NotifyArea
* notify_area
= GET_WINDOW(NotifyArea
, _hwndNotify
);
474 return notify_area
->ProcessTrayNotification(ptr
->notify_code
, &ptr
->nicon_data
);
481 void DesktopBar::ControlResize(WPARAM wparam
, LPARAM lparam
)
483 PRECT dragRect
= (PRECT
) lparam
;
484 //int screenWidth = GetSystemMetrics(SM_CXSCREEN);
485 int screenHeight
= GetSystemMetrics(SM_CYSCREEN
);
487 ///@todo write code for taskbar being at sides or top.
490 case WMSZ_BOTTOM
: //@todo Taskbar is at the top of the screen
493 case WMSZ_TOP
: // Taskbar is at the bottom of the screen
494 dragRect
->top
= screenHeight
- (((screenHeight
- dragRect
->top
) + DESKTOPBARBAR_HEIGHT
/2) / DESKTOPBARBAR_HEIGHT
) * DESKTOPBARBAR_HEIGHT
;
495 if (dragRect
->top
< screenHeight
/ 2)
496 dragRect
->top
= screenHeight
- (screenHeight
/2 / DESKTOPBARBAR_HEIGHT
* DESKTOPBARBAR_HEIGHT
);
497 else if (dragRect
->top
> screenHeight
- 5)
498 dragRect
->top
= screenHeight
- 5;
501 case WMSZ_RIGHT
: //@todo Taskbar is at the left of the screen
504 case WMSZ_LEFT
: //@todo Taskbar is at the right of the screen
512 void DesktopBar::AddTrayIcons()
514 _trayIcon
.Add(SmallIcon(IDI_SPEAKER
), ResString(IDS_VOLUME
));
517 void DesktopBar::TrayClick(UINT id
, int btn
)
521 if (btn
== TRAYBUTTON_LEFT
)
522 SetTimer(_hwnd
, ID_TRAY_VOLUME
, 500, NULL
); // wait a bit to correctly handle double clicks
524 PopupMenu
menu(IDM_VOLUME
);
525 SetMenuDefaultItem(menu
, 0, MF_BYPOSITION
);
526 menu
.TrackPopupMenuAtPos(_hwnd
, GetMessagePos());
532 void DesktopBar::TrayDblClick(UINT id
, int btn
)
536 KillTimer(_hwnd
, ID_TRAY_VOLUME
); // finish one-click timer
537 launch_file(_hwnd
, TEXT("sndvol32.exe"), SW_SHOWNORMAL
); // launch volume control application