~ubuntu-branches/ubuntu/karmic/psi/karmic

« back to all changes in this revision

Viewing changes to src/tools/trayicon/trayicon_win.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Jan Niehusmann
  • Date: 2006-01-20 00:20:36 UTC
  • mfrom: (1.2.2 upstream)
  • Revision ID: james.westby@ubuntu.com-20060120002036-7nw6yo6totip0ee5
Tags: 0.10-2
* Added upstream changelog (Closes: Bug#327748)
* Mention --no-gpg and --no-gpg-agent in manpage (Closes: Bug#204416)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
 
 
33
static uint WM_TASKBARCREATED = 0;
 
34
#define WM_NOTIFYICON   (WM_APP+101)
 
35
 
 
36
typedef BOOL (WINAPI *PtrShell_NotifyIcon)(DWORD,PNOTIFYICONDATA);
 
37
static PtrShell_NotifyIcon ptrShell_NotifyIcon = 0;
 
38
 
 
39
static 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
 
 
50
class TrayIcon::TrayIconPrivate : public QWidget
 
51
{
 
52
public:
 
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
 
 
181
static 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
 
 
196
static 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
 
 
218
void 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
 
 
228
void TrayIcon::sysRemove()
 
229
{
 
230
    if ( d ) {
 
231
                d->trayMessage( NIM_DELETE );
 
232
 
 
233
                delete d;
 
234
            d = 0;
 
235
        }
 
236
}
 
237
 
 
238
void 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
 
 
255
void TrayIcon::sysUpdateToolTip()
 
256
{
 
257
    if ( d )
 
258
                d->trayMessage( NIM_MODIFY );
 
259
}