src/gui/util/qsystemtrayicon_wince.cpp
changeset 25 e24348a560a6
child 30 5dc02b23752f
equal deleted inserted replaced
23:89e065397ea6 25:e24348a560a6
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the QtGui module of the Qt Toolkit.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    15 **
       
    16 ** GNU Lesser General Public License Usage
       
    17 ** Alternatively, this file may be used under the terms of the GNU Lesser
       
    18 ** General Public License version 2.1 as published by the Free Software
       
    19 ** Foundation and appearing in the file LICENSE.LGPL included in the
       
    20 ** packaging of this file.  Please review the following information to
       
    21 ** ensure the GNU Lesser General Public License version 2.1 requirements
       
    22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    23 **
       
    24 ** In addition, as a special exception, Nokia gives you certain additional
       
    25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    27 **
       
    28 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    38 ** $QT_END_LICENSE$
       
    39 **
       
    40 ****************************************************************************/
       
    41 
       
    42 #include "qsystemtrayicon_p.h"
       
    43 #ifndef QT_NO_SYSTEMTRAYICON
       
    44 #define _WIN32_IE 0x0600 //required for NOTIFYICONDATA_V2_SIZE
       
    45 
       
    46 #include <qt_windows.h>
       
    47 #include <shlwapi.h>
       
    48 #include <QApplication>
       
    49 
       
    50 QT_BEGIN_NAMESPACE
       
    51 
       
    52 static const UINT q_uNOTIFYICONID = 13;     // IDs from 0 to 12 are reserved on WinCE.
       
    53 #define MYWM_NOTIFYICON (WM_APP+101)
       
    54 
       
    55 struct Q_NOTIFYICONIDENTIFIER {
       
    56     DWORD cbSize;
       
    57     HWND hWnd;
       
    58     UINT uID;
       
    59     GUID guidItem;
       
    60 };
       
    61 
       
    62 class QSystemTrayIconSys : QWidget
       
    63 {
       
    64 public:
       
    65     QSystemTrayIconSys(QSystemTrayIcon *object);
       
    66     ~QSystemTrayIconSys();
       
    67     bool winEvent( MSG *m, long *result );
       
    68     bool trayMessage(DWORD msg);
       
    69     void setIconContents(NOTIFYICONDATA &data);
       
    70     void createIcon();
       
    71     QRect findTrayGeometry();
       
    72     HICON hIcon;
       
    73     QPoint globalPos;
       
    74     QSystemTrayIcon *q;
       
    75 private:
       
    76     uint notifyIconSize;
       
    77     int maxTipLength;
       
    78     bool ignoreNextMouseRelease;
       
    79 };
       
    80 
       
    81 QSystemTrayIconSys::QSystemTrayIconSys(QSystemTrayIcon *object)
       
    82     : hIcon(0), q(object), ignoreNextMouseRelease(false)
       
    83 
       
    84 {
       
    85     notifyIconSize = FIELD_OFFSET(NOTIFYICONDATA, szTip[64]); // NOTIFYICONDATAW_V1_SIZE;
       
    86     maxTipLength = 64;
       
    87 }
       
    88 
       
    89 QSystemTrayIconSys::~QSystemTrayIconSys()
       
    90 {
       
    91     if (hIcon)
       
    92         DestroyIcon(hIcon);
       
    93 }
       
    94 
       
    95 QRect QSystemTrayIconSys::findTrayGeometry()
       
    96 {
       
    97     // Use lower right corner as fallback
       
    98     QPoint brCorner = qApp->desktop()->screenGeometry().bottomRight();
       
    99     QRect ret(brCorner.x() - 10, brCorner.y() - 10, 10, 10);
       
   100     return ret;
       
   101 }
       
   102 
       
   103 void QSystemTrayIconSys::setIconContents(NOTIFYICONDATA &tnd)
       
   104 {
       
   105     tnd.uFlags = NIF_MESSAGE | NIF_ICON | NIF_TIP;
       
   106     tnd.uCallbackMessage = MYWM_NOTIFYICON;
       
   107     tnd.hIcon = hIcon;
       
   108     QString tip = q->toolTip();
       
   109 
       
   110     if (!tip.isNull()) {
       
   111         tip = tip.left(maxTipLength - 1) + QChar();
       
   112         memcpy(tnd.szTip, tip.utf16(), qMin(tip.length() + 1, maxTipLength) * sizeof(wchar_t));
       
   113     }
       
   114 }
       
   115 
       
   116 bool QSystemTrayIconSys::trayMessage(DWORD msg)
       
   117 {
       
   118     NOTIFYICONDATA tnd;
       
   119     memset(&tnd, 0, notifyIconSize);
       
   120     tnd.uID = q_uNOTIFYICONID;
       
   121     tnd.cbSize = notifyIconSize;
       
   122     tnd.hWnd = winId();
       
   123 
       
   124     Q_ASSERT(testAttribute(Qt::WA_WState_Created));
       
   125 
       
   126     if (msg != NIM_DELETE) {
       
   127         setIconContents(tnd);
       
   128     }
       
   129 
       
   130     return Shell_NotifyIcon(msg, &tnd);
       
   131 }
       
   132 
       
   133 void QSystemTrayIconSys::createIcon()
       
   134 {
       
   135     hIcon = 0;
       
   136     QIcon icon = q->icon();
       
   137     if (icon.isNull())
       
   138         return;
       
   139 
       
   140     //const QSize preferredSize(GetSystemMetrics(SM_CXSMICON) * 2, GetSystemMetrics(SM_CYSMICON) * 2);
       
   141     const QSize preferredSize(GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CYICON));
       
   142     QPixmap pm = icon.pixmap(preferredSize);
       
   143     if (pm.isNull())
       
   144         return;
       
   145 
       
   146     hIcon = pm.toWinHICON();
       
   147 }
       
   148 
       
   149 bool QSystemTrayIconSys::winEvent( MSG *m, long *result )
       
   150 {
       
   151     switch(m->message) {
       
   152     case WM_CREATE:
       
   153         SetWindowLong(winId(), GWL_USERDATA, (LONG)((CREATESTRUCTW*)m->lParam)->lpCreateParams);
       
   154         break;
       
   155 
       
   156     case MYWM_NOTIFYICON:
       
   157         {
       
   158             RECT r;
       
   159             GetWindowRect(winId(), &r);
       
   160             QEvent *e = 0;
       
   161             Qt::KeyboardModifiers keys = QApplication::keyboardModifiers();
       
   162             QPoint gpos = QCursor::pos();
       
   163 
       
   164             switch (m->lParam) {
       
   165             case WM_LBUTTONUP:
       
   166                 if (ignoreNextMouseRelease)
       
   167                     ignoreNextMouseRelease = false;
       
   168                 else
       
   169                     emit q->activated(QSystemTrayIcon::Trigger);
       
   170                 break;
       
   171 
       
   172             case WM_LBUTTONDBLCLK:
       
   173                 ignoreNextMouseRelease = true; // Since DBLCLICK Generates a second mouse 
       
   174                                                // release we must ignore it
       
   175                 emit q->activated(QSystemTrayIcon::DoubleClick);
       
   176                 break;
       
   177 
       
   178             case WM_RBUTTONUP:
       
   179                 if (q->contextMenu()) {
       
   180                     q->contextMenu()->popup(gpos);
       
   181 
       
   182                     // We must ensure that the popup menu doesn't show up behind the task bar.
       
   183                     QRect desktopRect = qApp->desktop()->availableGeometry();
       
   184                     int maxY = desktopRect.y() + desktopRect.height() - q->contextMenu()->height();
       
   185                     if (gpos.y() > maxY) {
       
   186                         gpos.ry() = maxY;
       
   187                         q->contextMenu()->move(gpos);
       
   188                     }
       
   189 
       
   190                     q->contextMenu()->activateWindow();
       
   191                     //Must be activated for proper keyboardfocus and menu closing on windows:
       
   192                 }
       
   193                 emit q->activated(QSystemTrayIcon::Context);
       
   194                 break;
       
   195 
       
   196             case WM_MBUTTONUP:
       
   197                 emit q->activated(QSystemTrayIcon::MiddleClick);
       
   198                 break;
       
   199             default:
       
   200                 break;
       
   201             }
       
   202             if (e) {
       
   203                 bool res = QApplication::sendEvent(q, e);
       
   204                 delete e;
       
   205                 return res;
       
   206             }
       
   207             break;
       
   208         }
       
   209     default:
       
   210         return QWidget::winEvent(m, result);
       
   211     }
       
   212     return 0;
       
   213 }
       
   214 
       
   215 void QSystemTrayIconPrivate::install_sys()
       
   216 {
       
   217     Q_Q(QSystemTrayIcon);
       
   218     if (!sys) {
       
   219         sys = new QSystemTrayIconSys(q);
       
   220         sys->createIcon();
       
   221         sys->trayMessage(NIM_ADD);
       
   222     }
       
   223 }
       
   224 
       
   225 void QSystemTrayIconPrivate::showMessage_sys(const QString &title, const QString &message, QSystemTrayIcon::MessageIcon type, int timeOut)
       
   226 {
       
   227     if (!sys)
       
   228         return;
       
   229 
       
   230     uint uSecs = 0;
       
   231     if ( timeOut < 0)
       
   232         uSecs = 10000; //10 sec default
       
   233     else uSecs = (int)timeOut;
       
   234 
       
   235     //message is limited to 255 chars + NULL
       
   236     QString messageString;
       
   237     if (message.isEmpty() && !title.isEmpty())
       
   238         messageString = QLatin1Char(' '); //ensures that the message shows when only title is set
       
   239     else
       
   240         messageString = message.left(255) + QChar();
       
   241 
       
   242     //title is limited to 63 chars + NULL
       
   243     QString titleString = title.left(63) + QChar();
       
   244 
       
   245     //show QBalloonTip
       
   246     QRect trayRect = sys->findTrayGeometry();
       
   247     QBalloonTip::showBalloon(type, title, message, sys->q, QPoint(trayRect.left(),
       
   248                              trayRect.center().y()), uSecs, false);
       
   249 }
       
   250 
       
   251 QRect QSystemTrayIconPrivate::geometry_sys() const
       
   252 {
       
   253     return QRect();
       
   254 }
       
   255 
       
   256 void QSystemTrayIconPrivate::remove_sys()
       
   257 {
       
   258     if (!sys)
       
   259         return;
       
   260 
       
   261     sys->trayMessage(NIM_DELETE);
       
   262     delete sys;
       
   263     sys = 0;
       
   264 }
       
   265 
       
   266 void QSystemTrayIconPrivate::updateIcon_sys()
       
   267 {
       
   268     if (!sys)
       
   269         return;
       
   270 
       
   271     HICON hIconToDestroy = sys->hIcon;
       
   272 
       
   273     sys->createIcon();
       
   274     sys->trayMessage(NIM_MODIFY);
       
   275 
       
   276     if (hIconToDestroy)
       
   277         DestroyIcon(hIconToDestroy);
       
   278 }
       
   279 
       
   280 void QSystemTrayIconPrivate::updateMenu_sys()
       
   281 {
       
   282 
       
   283 }
       
   284 
       
   285 void QSystemTrayIconPrivate::updateToolTip_sys()
       
   286 {
       
   287     // Calling sys->trayMessage(NIM_MODIFY) on an existing icon is broken on Windows CE.
       
   288     // So we need to call updateIcon_sys() which creates a new icon handle.
       
   289     updateIcon_sys();
       
   290 }
       
   291 
       
   292 bool QSystemTrayIconPrivate::isSystemTrayAvailable_sys()
       
   293 {
       
   294     return true;
       
   295 }
       
   296 
       
   297 QT_END_NAMESPACE
       
   298 
       
   299 #endif