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);