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, 22.08.2003
29 #include "../utility/utility.h"
31 #include "../explorer.h"
32 #include "../globals.h"
34 #include "traynotify.h"
37 NotifyIconIndex::NotifyIconIndex(NOTIFYICONDATA
* pnid
)
42 // special handling for windows task manager
47 NotifyIconIndex::NotifyIconIndex()
54 NotifyInfo::NotifyInfo()
59 _uCallbackMessage
= 0;
62 NotifyInfo
& NotifyInfo::operator=(NOTIFYICONDATA
* pnid
)
67 if (pnid
->uFlags
& NIF_MESSAGE
)
68 _uCallbackMessage
= pnid
->uCallbackMessage
;
70 if (pnid
->uFlags
& NIF_ICON
)
73 #ifdef NIF_STATE // currently (as of 21.08.2003) missing in MinGW headers
74 if (pnid
->uFlags
& NIF_STATE
)
75 _dwState
= (_dwState
&~pnid
->dwStateMask
) | (pnid
->dwState
&pnid
->dwStateMask
);
78 //TODO: store and display tool tip texts
84 NotifyArea::NotifyArea(HWND hwnd
)
90 LRESULT
NotifyArea::Init(LPCREATESTRUCT pcs
)
95 // create clock window
96 _hwndClock
= ClockWindow::Create(_hwnd
);
98 SetTimer(_hwnd
, 0, 1000, NULL
);
103 NotifyArea::~NotifyArea()
108 HWND
NotifyArea::Create(HWND hwndParent
)
110 ClientRect
clnt(hwndParent
);
112 return Window::Create(WINDOW_CREATOR(NotifyArea
), WS_EX_STATICEDGE
,
113 BtnWindowClass(CLASSNAME_TRAYNOTIFY
,CS_DBLCLKS
), TITLE_TRAYNOTIFY
, WS_CHILD
|WS_VISIBLE
,
114 clnt
.right
-(NOTIFYAREA_WIDTH
+1), 1, NOTIFYAREA_WIDTH
, clnt
.bottom
-2, hwndParent
);
117 LRESULT
NotifyArea::WndProc(UINT nmsg
, WPARAM wparam
, LPARAM lparam
)
127 ClockWindow
* clock_window
= GET_WINDOW(ClockWindow
, _hwndClock
);
130 clock_window
->TimerTick();
134 if (nmsg
>=WM_MOUSEFIRST
&& nmsg
<=WM_MOUSELAST
) {
135 // close startup menu and other popup menus
136 // This functionality is missing in MS Windows.
137 if (nmsg
==WM_LBUTTONDOWN
|| nmsg
==WM_MBUTTONDOWN
|| nmsg
==WM_RBUTTONDOWN
138 #ifdef WM_XBUTTONDOWN
139 || nmsg
==WM_XBUTTONDOWN
144 NotifyIconSet::iterator found
= IconHitTest(Point(lparam
));
146 if (found
!= _sorted_icons
.end()) {
147 NotifyInfo
& entry
= const_cast<NotifyInfo
&>(*found
); // Why does GCC 3.3 need this additional const_cast ?!
149 //TODO: AttachThreadInput() für SetForegroundWindow() in Client-Prozess
151 // Notify the message if the owner if it's still alive
152 if (IsWindow(entry
._hWnd
))
153 PostMessage(entry
._hWnd
, entry
._uCallbackMessage
, entry
._uID
, nmsg
);
154 else if (_icon_map
.erase(entry
)) // delete icons without valid owner window
159 return super::WndProc(nmsg
, wparam
, lparam
);
165 void NotifyArea::CancelModes()
167 PostMessage(HWND_BROADCAST
, WM_CANCELMODE
, 0, 0);
169 for(NotifyIconSet::const_iterator it
=_sorted_icons
.begin(); it
!=_sorted_icons
.end(); ++it
)
170 PostMessage(it
->_hWnd
, WM_CANCELMODE
, 0, 0);
173 LRESULT
NotifyArea::ProcessTrayNotification(int notify_code
, NOTIFYICONDATA
* pnid
)
175 switch(notify_code
) {
178 if ((int)pnid
->uID
>= 0) { //TODO: fix for windows task manager
179 NotifyInfo
& entry
= _icon_map
[pnid
] = pnid
;
182 if (entry
._idx
== -1)
183 entry
._idx
= ++_next_idx
;
185 Refresh(); //TODO: call only if really changes occurred
190 if (_icon_map
.erase(pnid
))
194 #if NOTIFYICON_VERSION>=3 // currently (as of 21.08.2003) missing in MinGW headers
206 void NotifyArea::Refresh()
208 _sorted_icons
.clear();
210 // sort icon infos by display index
211 for(NotifyIconMap::const_iterator it
=_icon_map
.begin(); it
!=_icon_map
.end(); ++it
) {
212 const NotifyInfo
& entry
= it
->second
;
214 #ifdef NIF_STATE // currently (as of 21.08.2003) missing in MinGW headers
215 if (!(entry
._dwState
& NIS_HIDDEN
))
217 _sorted_icons
.insert(entry
);
220 InvalidateRect(_hwnd
, NULL
, FALSE
); // refresh icon display
224 void NotifyArea::Paint()
226 BufferedPaintCanvas
canvas(_hwnd
);
228 // first fill with the background color
229 FillRect(canvas
, &canvas
.rcPaint
, GetSysColorBrush(COLOR_BTNFACE
));
235 for(NotifyIconSet::const_iterator it
=_sorted_icons
.begin(); it
!=_sorted_icons
.end(); ++it
) {
236 DrawIconEx(canvas
, x
, y
, it
->_hIcon
, 16, 16, 0, 0, DI_NORMAL
);
241 void NotifyArea::TimerTick()
243 bool do_refresh
= false;
245 // Look for task icons without valid owner window.
246 // This is an advanced feature, which is missing in MS Windows.
247 for(NotifyIconSet::const_iterator it
=_sorted_icons
.begin(); it
!=_sorted_icons
.end(); ++it
) {
248 const NotifyInfo
& entry
= *it
;
250 if (!IsWindow(entry
._hWnd
))
251 if (_icon_map
.erase(entry
)) // delete icons without valid owner window
259 /// search for a icon at a given client coordinate position
260 NotifyIconSet::iterator
NotifyArea::IconHitTest(const POINT
& pos
)
262 if (pos
.y
<2 || pos
.y
>=2+16)
263 return _sorted_icons
.end();
265 NotifyIconSet::iterator it
= _sorted_icons
.begin();
269 for(; it
!=_sorted_icons
.end(); ++it
) {
270 //NotifyInfo& entry = const_cast<NotifyInfo&>(*it); // Why does GCC 3.3 need this additional const_cast ?!
272 if (pos
.x
>=x
&& pos
.x
<x
+16)
282 ClockWindow::ClockWindow(HWND hwnd
)
289 _tooltip
.add(_hwnd
, _hwnd
);
292 HWND
ClockWindow::Create(HWND hwndParent
)
294 ClientRect
clnt(hwndParent
);
296 return Window::Create(WINDOW_CREATOR(ClockWindow
), 0,
297 BtnWindowClass(CLASSNAME_CLOCKWINDOW
,CS_DBLCLKS
), NULL
, WS_CHILD
|WS_VISIBLE
,
298 clnt
.right
-(CLOCKWINDOW_WIDTH
+1), 1, CLOCKWINDOW_WIDTH
, clnt
.bottom
-2, hwndParent
);
301 LRESULT
ClockWindow::WndProc(UINT nmsg
, WPARAM wparam
, LPARAM lparam
)
308 case WM_LBUTTONDBLCLK
:
309 //launch_file(_hwnd, _T("timedate.cpl"), SW_SHOWNORMAL); // This would be enough, but we want the fastest solution.
310 //launch_file(_hwnd, _T("rundll32.exe /d shell32.dll,Control_RunDLL timedate.cpl"), SW_SHOWNORMAL);
311 RunDLL(_hwnd
, _T("shell32"), "Control_RunDLL", _T("timedate.cpl"), SW_SHOWNORMAL
);
315 return super::WndProc(nmsg
, wparam
, lparam
);
321 int ClockWindow::Notify(int id
, NMHDR
* pnmh
)
323 if (pnmh
->code
== TTN_GETDISPINFO
) {
324 LPNMTTDISPINFO pdi
= (LPNMTTDISPINFO
)pnmh
;
329 GetLocalTime(&systime
);
330 GetDateFormat(LOCALE_USER_DEFAULT
, DATE_LONGDATE
, &systime
, NULL
, buffer
, 64);
332 _tcscpy(pdi
->szText
, buffer
);
338 void ClockWindow::TimerTick()
341 InvalidateRect(_hwnd
, NULL
, TRUE
); // refresh displayed time
344 bool ClockWindow::FormatTime()
349 GetLocalTime(&systime
);
351 //_stprintf(buffer, TEXT("%02d:%02d:%02d"), systime.wHour, systime.wMinute, systime.wSecond);
352 _stprintf(buffer
, TEXT("%02d:%02d"), systime
.wHour
, systime
.wMinute
);
354 if (_tcscmp(buffer
, _time
)) {
355 _tcscpy(_time
, buffer
);
356 return true; // The text to display has changed.
359 return false; // no change
362 void ClockWindow::Paint()
364 PaintCanvas
canvas(_hwnd
);
366 BkMode
bkmode(canvas
, TRANSPARENT
);
367 FontSelection
font(canvas
, GetStockFont(ANSI_VAR_FONT
));
369 DrawText(canvas
, _time
, -1, ClientRect(_hwnd
), DT_SINGLELINE
|DT_VCENTER
|DT_NOPREFIX
);