source: psi/trunk/src/tools/trayicon/trayicon_win.cpp

Last change on this file was 2, checked in by dmik, 19 years ago

Imported original Psi 0.10 sources from Affinix

File size: 7.6 KB
Line 
1/*
2 * trayicon_win.cpp - Windows trayicon, adapted from Qt example
3 * Copyright (C) 2003 Justin Karneges
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 *
19 */
20
21#include "trayicon.h"
22
23#include <qwidget.h>
24#include <qapplication.h>
25#include <qimage.h>
26#include <qpixmap.h>
27#include <qbitmap.h>
28#include <qcursor.h>
29#include <qlibrary.h>
30
31#include <qt_windows.h>
32
33static uint WM_TASKBARCREATED = 0;
34#define WM_NOTIFYICON (WM_APP+101)
35
36typedef BOOL (WINAPI *PtrShell_NotifyIcon)(DWORD,PNOTIFYICONDATA);
37static PtrShell_NotifyIcon ptrShell_NotifyIcon = 0;
38
39static void resolveLibs()
40{
41 QLibrary lib("shell32");
42 lib.setAutoUnload( FALSE );
43 static bool triedResolve = FALSE;
44 if ( !ptrShell_NotifyIcon && !triedResolve ) {
45 triedResolve = TRUE;
46 ptrShell_NotifyIcon = (PtrShell_NotifyIcon) lib.resolve( "Shell_NotifyIconW" );
47 }
48}
49
50class TrayIcon::TrayIconPrivate : public QWidget
51{
52public:
53 HICON hIcon;
54 HBITMAP hMask;
55 TrayIcon *iconObject;
56
57 TrayIconPrivate( TrayIcon *object )
58 : QWidget( 0 ), hIcon( 0 ), hMask( 0 ), iconObject( object )
59 {
60 if ( !WM_TASKBARCREATED )
61 WM_TASKBARCREATED = RegisterWindowMessage( TEXT("TaskbarCreated") );
62 }
63
64 ~TrayIconPrivate()
65 {
66 if ( hMask ) {
67 DeleteObject( hMask );
68 hMask = 0; // michalj
69 }
70 if ( hIcon ) {
71 DestroyIcon( hIcon );
72 hIcon = 0; // michalj
73 }
74 }
75
76 // the unavoidable A/W versions. Don't forget to keep them in sync!
77 bool trayMessageA( DWORD msg )
78 {
79 NOTIFYICONDATAA tnd;
80 ZeroMemory( &tnd, sizeof(NOTIFYICONDATAA) );
81 tnd.cbSize = sizeof(NOTIFYICONDATAA);
82 tnd.hWnd = winId();
83 tnd.uID = 1; // michalj
84
85 if ( msg != NIM_DELETE ) {
86 tnd.uFlags = NIF_MESSAGE|NIF_ICON|NIF_TIP;
87 tnd.uCallbackMessage= WM_NOTIFYICON;
88 tnd.hIcon = hIcon;
89 if ( !iconObject->toolTip().isNull() ) {
90 // Tip is limited to 63 + NULL; lstrcpyn appends a NULL terminator.
91 QString tip = iconObject->toolTip().left( 63 ) + QChar();
92 lstrcpynA(tnd.szTip, (const char*)tip.local8Bit(), QMIN( tip.length()+1, 64 ) );
93 }
94 }
95
96 return Shell_NotifyIconA(msg, &tnd);
97 }
98
99#ifdef UNICODE
100 bool trayMessageW( DWORD msg )
101 {
102 resolveLibs();
103 if ( ! (ptrShell_NotifyIcon && qWinVersion() & Qt::WV_NT_based) )
104 return trayMessageA( msg );
105
106 NOTIFYICONDATAW tnd;
107 ZeroMemory( &tnd, sizeof(NOTIFYICONDATAW) );
108 tnd.cbSize = sizeof(NOTIFYICONDATAW);
109 tnd.hWnd = winId();
110 tnd.uID = 1; // michalj
111
112 if ( msg != NIM_DELETE ) {
113 tnd.uFlags = NIF_MESSAGE|NIF_ICON|NIF_TIP;
114 tnd.uCallbackMessage= WM_NOTIFYICON;
115 tnd.hIcon = hIcon;
116 if ( !iconObject->toolTip().isNull() ) {
117 // Tip is limited to 63 + NULL; lstrcpyn appends a NULL terminator.
118 QString tip = iconObject->toolTip().left( 63 ) + QChar();
119 lstrcpynW(tnd.szTip, (TCHAR*)tip.unicode(), QMIN( tip.length()+1, 64 ) );
120 // lstrcpynW(tnd.szTip, (TCHAR*)qt_winTchar( tip, FALSE ), QMIN( tip.length()+1, 64 ) );
121 }
122 }
123 return ptrShell_NotifyIcon(msg, &tnd);
124 }
125#endif
126
127 bool trayMessage( DWORD msg )
128 {
129 QT_WA(
130 return trayMessageW(msg);
131 ,
132 return trayMessageA(msg);
133 )
134 }
135
136 bool iconDrawItem(LPDRAWITEMSTRUCT lpdi)
137 {
138 if (!hIcon)
139 return FALSE;
140
141 DrawIconEx(lpdi->hDC, lpdi->rcItem.left, lpdi->rcItem.top, hIcon, 0, 0, 0, NULL, DI_NORMAL );
142 return TRUE;
143 }
144
145 bool winEvent( MSG *m )
146 {
147 switch(m->message) {
148 case WM_DRAWITEM:
149 return iconDrawItem( (LPDRAWITEMSTRUCT)m->lParam );
150 case WM_NOTIFYICON:
151 {
152 QMouseEvent *e = 0;
153 QPoint gpos = QCursor::pos();
154 switch (m->lParam) {
155 case WM_MOUSEMOVE: e = new QMouseEvent( QEvent::MouseMove, mapFromGlobal( gpos ), gpos, 0, 0 ); break;
156 case WM_LBUTTONDOWN: e = new QMouseEvent( QEvent::MouseButtonPress, mapFromGlobal( gpos ), gpos, LeftButton, LeftButton ); break;
157 case WM_LBUTTONUP: e = new QMouseEvent( QEvent::MouseButtonRelease, mapFromGlobal( gpos ), gpos, LeftButton, LeftButton ); break;
158 case WM_LBUTTONDBLCLK: e = new QMouseEvent( QEvent::MouseButtonDblClick, mapFromGlobal( gpos ), gpos, LeftButton, LeftButton ); break;
159 case WM_RBUTTONDOWN: e = new QMouseEvent( QEvent::MouseButtonPress, mapFromGlobal( gpos ), gpos, RightButton, RightButton ); break;
160 case WM_RBUTTONUP: e = new QMouseEvent( QEvent::MouseButtonRelease, mapFromGlobal( gpos ), gpos, RightButton, RightButton ); break;
161 case WM_RBUTTONDBLCLK: e = new QMouseEvent( QEvent::MouseButtonDblClick, mapFromGlobal( gpos ), gpos, RightButton, RightButton ); break;
162 case WM_MBUTTONDOWN: e = new QMouseEvent( QEvent::MouseButtonPress, mapFromGlobal( gpos ), gpos, MidButton, MidButton ); break;
163 case WM_MBUTTONUP: e = new QMouseEvent( QEvent::MouseButtonRelease, mapFromGlobal( gpos ), gpos, MidButton, MidButton ); break;
164 case WM_MBUTTONDBLCLK: e = new QMouseEvent( QEvent::MouseButtonDblClick, mapFromGlobal( gpos ), gpos, MidButton, MidButton ); break;
165 case WM_CONTEXTMENU: e = new QMouseEvent( QEvent::MouseButtonRelease, mapFromGlobal( gpos ), gpos, RightButton, RightButton ); break;
166 }
167 if ( e ) {
168 bool res = QApplication::sendEvent( iconObject, e );
169 delete e;
170 return res;
171 }
172 }
173 break;
174 default:
175 if ( m->message == WM_TASKBARCREATED ) trayMessage( NIM_ADD );
176 }
177 return QWidget::winEvent( m );
178 }
179};
180
181static HBITMAP createIconMask( const QPixmap &qp )
182{
183 QImage bm = qp.convertToImage();
184 int w = bm.width();
185 int h = bm.height();
186 int bpl = ((w+15)/16)*2; // bpl, 16 bit alignment
187 uchar *bits = new uchar[bpl*h];
188 bm.invertPixels();
189 for ( int y=0; y<h; y++ )
190 memcpy( bits+y*bpl, bm.scanLine(y), bpl );
191 HBITMAP hbm = CreateBitmap( w, h, 1, 1, bits );
192 delete [] bits;
193 return hbm;
194}
195
196static HICON createIcon( const QPixmap &pm, HBITMAP &hbm )
197{
198 QPixmap maskpm( pm.size(), pm.depth(), QPixmap::NormalOptim );
199 QBitmap mask( pm.size(), FALSE, QPixmap::NormalOptim );
200 if ( pm.mask() ) {
201 maskpm.fill( Qt::black ); // make masked area black
202 bitBlt( &mask, 0, 0, pm.mask() );
203 } else
204 maskpm.fill( Qt::color1 );
205
206 bitBlt( &maskpm, 0, 0, &pm);
207 ICONINFO iconInfo;
208 iconInfo.fIcon = TRUE;
209 iconInfo.hbmMask = hbm = createIconMask(mask);
210 iconInfo.hbmColor = maskpm.hbm();
211
212 HICON icon = CreateIconIndirect( &iconInfo );
213 DeleteObject(iconInfo.hbmMask);
214 iconInfo.hbmMask = hbm = 0; // michalj
215 return icon;
216}
217
218void TrayIcon::sysInstall()
219{
220 if ( !d ) {
221 d = new TrayIconPrivate( this );
222 d->hIcon = createIcon( pm, d->hMask );
223
224 d->trayMessage( NIM_ADD );
225 }
226}
227
228void TrayIcon::sysRemove()
229{
230 if ( d ) {
231 d->trayMessage( NIM_DELETE );
232
233 delete d;
234 d = 0;
235 }
236}
237
238void TrayIcon::sysUpdateIcon()
239{
240 if ( d ) {
241 if ( d->hMask ) {
242 DeleteObject( d->hMask );
243 d->hMask = 0; // michalj
244 }
245 if ( d->hIcon ) {
246 DestroyIcon( d->hIcon );
247 d->hIcon = 0; // michalj
248 }
249
250 d->hIcon = createIcon( pm, d->hMask );
251 d->trayMessage( NIM_MODIFY );
252 }
253}
254
255void TrayIcon::sysUpdateToolTip()
256{
257 if ( d )
258 d->trayMessage( NIM_MODIFY );
259}
Note: See TracBrowser for help on using the repository browser.