source: trunk/src/gui/kernel/qapplication_win.cpp

Last change on this file was 846, checked in by Dmitry A. Kuminov, 14 years ago

trunk: Merged in qt 4.7.2 sources from branches/vendor/nokia/qt.

File size: 152.6 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2011 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** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
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** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you have questions regarding the use of this file, please contact
37** Nokia at qt-info@nokia.com.
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#ifdef Q_WS_WINCE
43#include "qguifunctions_wince.h"
44#include "qmenubar.h"
45extern bool qt_wince_is_mobile(); //defined in qguifunctions_wince.cpp
46extern bool qt_wince_is_high_dpi(); //defined in qguifunctions_wince.cpp
47extern bool qt_wince_is_smartphone(); //defined in qguifunctions_wince.cpp
48extern bool qt_wince_is_pocket_pc(); //defined in qguifunctions_wince.cpp
49extern void qt_wince_hide_taskbar(HWND hwnd); //defined in qguifunctions_wince.cpp
50#endif
51#ifdef Q_WS_WINCE_WM
52#include <windowsm.h>
53#include <tpcshell.h>
54#ifdef QT_WINCE_GESTURES
55#ifndef QT_NO_GESTURES
56#include <gesture.h>
57#endif
58#endif
59#endif
60
61#include "qapplication.h"
62#include "qdesktopwidget.h"
63#include "qevent.h"
64#include "private/qeventdispatcher_win_p.h"
65#include "qeventloop.h"
66#include "qclipboard.h"
67#include "qcursor.h"
68#include "qdatetime.h"
69#include "qpointer.h"
70#include "qhash.h"
71#include "qmetaobject.h"
72#include "qmime.h"
73#include "qpainter.h"
74#include "qpixmapcache.h"
75#include "qsessionmanager.h"
76#include "qstyle.h"
77#include "qwhatsthis.h" // ######## dependency
78#include "qwidget.h"
79#include "qcolormap.h"
80#include "qlayout.h"
81#include "qtooltip.h"
82#include "qt_windows.h"
83#include "qscrollbar.h"
84#if defined(QT_NON_COMMERCIAL)
85#include "qnc_win.h"
86#endif
87#include "private/qwininputcontext_p.h"
88#include "private/qcursor_p.h"
89#include "private/qmath_p.h"
90#include "private/qapplication_p.h"
91#include "private/qbackingstore_p.h"
92#include "private/qwindowsurface_raster_p.h"
93#include "qdebug.h"
94#include <private/qkeymapper_p.h>
95#include <private/qlocale_p.h>
96#include <private/qsystemlibrary_p.h>
97#include "qevent_p.h"
98
99//#define ALIEN_DEBUG
100
101#ifndef QT_NO_THREAD
102#include "qmutex.h"
103#endif
104
105#ifndef QT_NO_ACCESSIBILITY
106#include "qaccessible.h"
107
108#include <oleacc.h>
109#ifndef WM_GETOBJECT
110#define WM_GETOBJECT 0x003D
111#endif
112#endif // QT_NO_ACCESSIBILITY
113
114#if !defined(WINABLEAPI)
115# if defined(Q_WS_WINCE)
116# include <bldver.h>
117# endif
118# include <winable.h>
119#endif
120
121#ifndef WM_TOUCH
122# define WM_TOUCH 0x0240
123
124# define TOUCHEVENTF_MOVE 0x0001
125# define TOUCHEVENTF_DOWN 0x0002
126# define TOUCHEVENTF_UP 0x0004
127# define TOUCHEVENTF_INRANGE 0x0008
128# define TOUCHEVENTF_PRIMARY 0x0010
129# define TOUCHEVENTF_NOCOALESCE 0x0020
130# define TOUCHEVENTF_PEN 0x0040
131# define TOUCHEVENTF_PALM 0x0080
132
133# define TOUCHINPUTMASKF_TIMEFROMSYSTEM 0x0001
134# define TOUCHINPUTMASKF_EXTRAINFO 0x0002
135# define TOUCHINPUTMASKF_CONTACTAREA 0x0004
136
137typedef struct tagTOUCHINPUT
138{
139 LONG x;
140 LONG y;
141 HANDLE hSource;
142 DWORD dwID;
143 DWORD dwFlags;
144 DWORD dwMask;
145 DWORD dwTime;
146 ULONG_PTR dwExtraInfo;
147 DWORD cxContact;
148 DWORD cyContact;
149} TOUCHINPUT, *PTOUCHINPUT;
150
151#endif
152
153#include <windowsx.h>
154#include <limits.h>
155#include <string.h>
156#include <ctype.h>
157#include <stdio.h>
158#include <math.h>
159
160#define PACKETDATA (PK_X | PK_Y | PK_BUTTONS | PK_NORMAL_PRESSURE | PK_TANGENT_PRESSURE \
161 | PK_ORIENTATION | PK_CURSOR | PK_Z)
162#define PACKETMODE 0
163
164#include <wintab.h>
165#ifndef CSR_TYPE
166#define CSR_TYPE 20 // Some old Wacom wintab.h may not provide this constant.
167#endif
168#include <pktdef.h>
169
170#if defined(__CYGWIN32__)
171#define __INSIDE_CYGWIN32__
172#include <mywinsock.h>
173#endif
174
175#ifndef IMR_RECONVERTSTRING
176#define IMR_RECONVERTSTRING 4
177#endif
178
179#ifndef IMR_CONFIRMRECONVERTSTRING
180#define IMR_CONFIRMRECONVERTSTRING 0x0005
181#endif
182QT_BEGIN_NAMESPACE
183
184#ifdef Q_WS_WINCE
185#ifndef SHRG_RETURNCMD
186struct SHRGINFO {
187 DWORD cbSize;
188 HWND hwndClient;
189 POINT ptDown;
190 DWORD dwFlags;
191};
192#define GN_CONTEXTMENU 1000
193#define SHRG_RETURNCMD 0x00000001
194#define SHRG_NOANIMATION 0x00000010
195#endif
196
197#ifndef SPI_SETSIPINFO
198#define SPI_SETSIPINFO 224
199#endif
200
201#ifndef QT_NO_GESTURES
202typedef DWORD (API *AygRecognizeGesture)(SHRGINFO*);
203static AygRecognizeGesture ptrRecognizeGesture = 0;
204static bool aygResolved = false;
205static void resolveAygLibs()
206{
207 if (!aygResolved) {
208 aygResolved = true;
209 QSystemLibrary ayglib(QLatin1String("aygshell"));
210 if (!ayglib.load())
211 return;
212 ptrRecognizeGesture = (AygRecognizeGesture) ayglib.resolve("SHRecognizeGesture");
213 }
214}
215#endif // QT_NO_GESTURES
216
217#endif
218
219#ifndef SPI_SETFONTSMOOTHINGTYPE
220# define SPI_SETFONTSMOOTHINGTYPE 0x200B
221#endif
222#ifndef SPI_GETFONTSMOOTHINGTYPE
223# define SPI_GETFONTSMOOTHINGTYPE 0x200A
224#endif
225#ifndef FE_FONTSMOOTHINGCLEARTYPE
226# define FE_FONTSMOOTHINGCLEARTYPE 0x0002
227#endif
228
229Q_GUI_EXPORT bool qt_cleartype_enabled;
230Q_GUI_EXPORT bool qt_win_owndc_required; // CS_OWNDC is required if we use the GL graphicssystem as default
231
232typedef HCTX (API *PtrWTOpen)(HWND, LPLOGCONTEXT, BOOL);
233typedef BOOL (API *PtrWTClose)(HCTX);
234typedef UINT (API *PtrWTInfo)(UINT, UINT, LPVOID);
235typedef BOOL (API *PtrWTEnable)(HCTX, BOOL);
236typedef BOOL (API *PtrWTOverlap)(HCTX, BOOL);
237typedef int (API *PtrWTPacketsGet)(HCTX, int, LPVOID);
238typedef BOOL (API *PtrWTGet)(HCTX, LPLOGCONTEXT);
239typedef int (API *PtrWTQueueSizeGet)(HCTX);
240typedef BOOL (API *PtrWTQueueSizeSet)(HCTX, int);
241
242static PtrWTInfo ptrWTInfo = 0;
243static PtrWTEnable ptrWTEnable = 0;
244static PtrWTOverlap ptrWTOverlap = 0;
245static PtrWTPacketsGet ptrWTPacketsGet = 0;
246static PtrWTGet ptrWTGet = 0;
247
248static PACKET localPacketBuf[QT_TABLET_NPACKETQSIZE]; // our own tablet packet queue.
249HCTX qt_tablet_context; // the hardware context for the tablet (like a window handle)
250bool qt_tablet_tilt_support;
251
252#ifndef QT_NO_TABLETEVENT
253static void tabletInit(const quint64 uniqueId, const UINT csr_type, HCTX hTab);
254static void tabletUpdateCursor(QTabletDeviceData &tdd, const UINT currentCursor);
255static void initWinTabFunctions(); // resolve the WINTAB api functions
256#endif // QT_NO_TABLETEVENT
257
258
259#ifndef QT_NO_ACCESSIBILITY
260extern IAccessible *qt_createWindowsAccessible(QAccessibleInterface *object);
261#endif // QT_NO_ACCESSIBILITY
262
263extern bool qt_tabletChokeMouse;
264extern QWidget* qt_get_tablet_widget();
265extern bool qt_sendSpontaneousEvent(QObject*, QEvent*);
266extern QRegion qt_dirtyRegion(QWidget *);
267
268typedef QHash<quint64, QTabletDeviceData> QTabletCursorInfo;
269Q_GLOBAL_STATIC(QTabletCursorInfo, tCursorInfo)
270QTabletDeviceData currentTabletPointer;
271
272// from qregion_win.cpp
273extern HRGN qt_tryCreateRegion(QRegion::RegionType type, int left, int top, int right, int bottom);
274
275// support for on-the-fly changes of the XP theme engine
276#ifndef WM_THEMECHANGED
277#define WM_THEMECHANGED 0x031A
278#endif
279#ifndef COLOR_MENUHILIGHT
280#define COLOR_MENUHILIGHT 29
281#define COLOR_MENUBAR 30
282#endif
283
284// support for xbuttons
285#ifndef WM_XBUTTONDOWN
286#define WM_XBUTTONDOWN 0x020B
287#define WM_XBUTTONUP 0x020C
288#define WM_XBUTTONDBLCLK 0x020D
289#endif
290#ifndef GET_KEYSTATE_WPARAM
291#define GET_KEYSTATE_WPARAM(wParam) (LOWORD(wParam))
292#define GET_XBUTTON_WPARAM(wParam) (HIWORD(wParam))
293#define XBUTTON1 0x0001
294#define XBUTTON2 0x0002
295#endif
296#ifndef MK_XBUTTON1
297#define MK_XBUTTON1 0x0020
298#define MK_XBUTTON2 0x0040
299#endif
300
301// support for multi-media-keys
302#ifndef WM_APPCOMMAND
303#define WM_APPCOMMAND 0x0319
304#endif
305
306#ifndef FAPPCOMMAND_MOUSE
307#define FAPPCOMMAND_MOUSE 0x8000
308#define FAPPCOMMAND_KEY 0
309#define FAPPCOMMAND_OEM 0x1000
310#define FAPPCOMMAND_MASK 0xF000
311#define GET_APPCOMMAND_LPARAM(lParam) ((short)(HIWORD(lParam) & ~FAPPCOMMAND_MASK))
312#define GET_DEVICE_LPARAM(lParam) ((WORD)(HIWORD(lParam) & FAPPCOMMAND_MASK))
313#define GET_MOUSEORKEY_LPARAM GET_DEVICE_LPARAM
314#define GET_FLAGS_LPARAM(lParam) (LOWORD(lParam))
315#define GET_KEYSTATE_LPARAM(lParam) GET_FLAGS_LPARAM(lParam)
316
317#define APPCOMMAND_BROWSER_BACKWARD 1
318#define APPCOMMAND_BROWSER_FORWARD 2
319#define APPCOMMAND_BROWSER_REFRESH 3
320#define APPCOMMAND_BROWSER_STOP 4
321#define APPCOMMAND_BROWSER_SEARCH 5
322#define APPCOMMAND_BROWSER_FAVORITES 6
323#define APPCOMMAND_BROWSER_HOME 7
324#define APPCOMMAND_VOLUME_MUTE 8
325#define APPCOMMAND_VOLUME_DOWN 9
326#define APPCOMMAND_VOLUME_UP 10
327#define APPCOMMAND_MEDIA_NEXTTRACK 11
328#define APPCOMMAND_MEDIA_PREVIOUSTRACK 12
329#define APPCOMMAND_MEDIA_STOP 13
330#define APPCOMMAND_MEDIA_PLAY_PAUSE 14
331#define APPCOMMAND_LAUNCH_MAIL 15
332#define APPCOMMAND_LAUNCH_MEDIA_SELECT 16
333#define APPCOMMAND_LAUNCH_APP1 17
334#define APPCOMMAND_LAUNCH_APP2 18
335#define APPCOMMAND_BASS_DOWN 19
336#define APPCOMMAND_BASS_BOOST 20
337#define APPCOMMAND_BASS_UP 21
338#define APPCOMMAND_TREBLE_DOWN 22
339#define APPCOMMAND_TREBLE_UP 23
340#endif // FAPPCOMMAND_MOUSE
341
342// New commands from Windows XP (some even Sp1)
343#ifndef APPCOMMAND_MICROPHONE_VOLUME_MUTE
344#define APPCOMMAND_MICROPHONE_VOLUME_MUTE 24
345#define APPCOMMAND_MICROPHONE_VOLUME_DOWN 25
346#define APPCOMMAND_MICROPHONE_VOLUME_UP 26
347#define APPCOMMAND_HELP 27
348#define APPCOMMAND_FIND 28
349#define APPCOMMAND_NEW 29
350#define APPCOMMAND_OPEN 30
351#define APPCOMMAND_CLOSE 31
352#define APPCOMMAND_SAVE 32
353#define APPCOMMAND_PRINT 33
354#define APPCOMMAND_UNDO 34
355#define APPCOMMAND_REDO 35
356#define APPCOMMAND_COPY 36
357#define APPCOMMAND_CUT 37
358#define APPCOMMAND_PASTE 38
359#define APPCOMMAND_REPLY_TO_MAIL 39
360#define APPCOMMAND_FORWARD_MAIL 40
361#define APPCOMMAND_SEND_MAIL 41
362#define APPCOMMAND_SPELL_CHECK 42
363#define APPCOMMAND_DICTATE_OR_COMMAND_CONTROL_TOGGLE 43
364#define APPCOMMAND_MIC_ON_OFF_TOGGLE 44
365#define APPCOMMAND_CORRECTION_LIST 45
366#define APPCOMMAND_MEDIA_PLAY 46
367#define APPCOMMAND_MEDIA_PAUSE 47
368#define APPCOMMAND_MEDIA_RECORD 48
369#define APPCOMMAND_MEDIA_FAST_FORWARD 49
370#define APPCOMMAND_MEDIA_REWIND 50
371#define APPCOMMAND_MEDIA_CHANNEL_UP 51
372#define APPCOMMAND_MEDIA_CHANNEL_DOWN 52
373#endif // APPCOMMAND_MICROPHONE_VOLUME_MUTE
374
375#if (_WIN32_WINNT < 0x0400)
376// This struct is defined in winuser.h if the _WIN32_WINNT >= 0x0400 -- in the
377// other cases we have to define it on our own.
378typedef struct tagTRACKMOUSEEVENT {
379 DWORD cbSize;
380 DWORD dwFlags;
381 HWND hwndTrack;
382 DWORD dwHoverTime;
383} TRACKMOUSEEVENT, *LPTRACKMOUSEEVENT;
384#endif
385#ifndef WM_MOUSELEAVE
386#define WM_MOUSELEAVE 0x02A3
387#endif
388
389QT_BEGIN_INCLUDE_NAMESPACE
390#include "private/qwidget_p.h"
391QT_END_INCLUDE_NAMESPACE
392
393static int translateButtonState(int s, int type, int button);
394
395// ##### get rid of this!
396QRgb qt_colorref2qrgb(COLORREF col)
397{
398 return qRgb(GetRValue(col),GetGValue(col),GetBValue(col));
399}
400
401
402/*****************************************************************************
403 Internal variables and functions
404 *****************************************************************************/
405
406static HWND curWin = 0; // current window
407static HDC displayDC = 0; // display device context
408
409// Session management
410static bool sm_blockUserInput = false;
411static bool sm_smActive = false;
412extern QSessionManager* qt_session_manager_self;
413static bool sm_cancel;
414
415static bool replayPopupMouseEvent = false; // replay handling when popups close
416
417// ignore the next release event if return from a modal widget
418Q_GUI_EXPORT bool qt_win_ignoreNextMouseReleaseEvent = false;
419
420
421#if defined(QT_DEBUG)
422static bool appNoGrab = false; // mouse/keyboard grabbing
423#endif
424
425static bool app_do_modal = false; // modal mode
426extern QWidgetList *qt_modal_stack;
427extern QDesktopWidget *qt_desktopWidget;
428static QPointer<QWidget> popupButtonFocus;
429static bool qt_try_modal(QWidget *, MSG *, int& ret);
430
431QWidget *qt_button_down = 0; // widget got last button-down
432QPointer<QWidget> qt_last_mouse_receiver = 0;
433
434static HWND autoCaptureWnd = 0;
435static HWND imeParentWnd = 0;
436static void setAutoCapture(HWND); // automatic capture
437static void releaseAutoCapture();
438
439static void unregWinClasses();
440
441extern QCursor *qt_grab_cursor();
442
443#if defined(Q_WS_WIN)
444#define __export
445#endif
446
447extern "C" LRESULT QT_WIN_CALLBACK QtWndProc(HWND, UINT, WPARAM, LPARAM);
448
449class QETWidget : public QWidget // event translator widget
450{
451public:
452 QWExtra *xtra() { return d_func()->extraData(); }
453 QTLWExtra *topData() { return d_func()->topData(); }
454 QTLWExtra *maybeTopData() { return d_func()->maybeTopData(); }
455 void syncBackingStore(const QRegion &rgn) { d_func()->syncBackingStore(rgn); }
456 void syncBackingStore() { d_func()->syncBackingStore(); }
457 QWidgetData *dataPtr() { return data; }
458 QWidgetPrivate *dptr() { return d_func(); }
459 QRect frameStrut() const { return d_func()->frameStrut(); }
460 bool winEvent(MSG *m, long *r) { return QWidget::winEvent(m, r); }
461 void markFrameStrutDirty() { data->fstrut_dirty = 1; }
462 bool translateMouseEvent(const MSG &msg);
463 bool translateWheelEvent(const MSG &msg);
464 bool translatePaintEvent(const MSG &msg);
465 bool translateConfigEvent(const MSG &msg);
466 bool translateCloseEvent(const MSG &msg);
467 bool translateTabletEvent(const MSG &msg, PACKET *localPacketBuf, int numPackets);
468#ifndef QT_NO_GESTURES
469 bool translateGestureEvent(const MSG &msg, const GESTUREINFO &gi);
470#endif
471 void repolishStyle(QStyle &style);
472 inline void showChildren(bool spontaneous) { d_func()->showChildren(spontaneous); }
473 inline void hideChildren(bool spontaneous) { d_func()->hideChildren(spontaneous); }
474 inline uint testWindowState(uint teststate){ return dataPtr()->window_state & teststate; }
475 inline void setWindowTitle_helper(const QString &title) { d_func()->setWindowTitle_helper(title); }
476 inline void forceUpdate() {
477 QTLWExtra *tlwExtra = window()->d_func()->maybeTopData();
478 if (tlwExtra && tlwExtra->backingStore)
479 tlwExtra->backingStore->markDirty(rect(), this, true, true);
480 }
481};
482
483// need to get default font?
484extern bool qt_app_has_font;
485
486extern QFont qt_LOGFONTtoQFont(LOGFONT& lf,bool scale);
487
488static void qt_set_windows_color_resources()
489{
490 // Do the color settings
491 QPalette pal;
492 pal.setColor(QPalette::WindowText,
493 QColor(qt_colorref2qrgb(GetSysColor(COLOR_WINDOWTEXT))));
494 pal.setColor(QPalette::Button,
495 QColor(qt_colorref2qrgb(GetSysColor(COLOR_BTNFACE))));
496 pal.setColor(QPalette::Light,
497 QColor(qt_colorref2qrgb(GetSysColor(COLOR_BTNHIGHLIGHT))));
498 pal.setColor(QPalette::Dark,
499 QColor(qt_colorref2qrgb(GetSysColor(COLOR_BTNSHADOW))));
500 pal.setColor(QPalette::Mid, pal.button().color().darker(150));
501 pal.setColor(QPalette::Text,
502 QColor(qt_colorref2qrgb(GetSysColor(COLOR_WINDOWTEXT))));
503 pal.setColor(QPalette::BrightText,
504 QColor(qt_colorref2qrgb(GetSysColor(COLOR_BTNHIGHLIGHT))));
505 pal.setColor(QPalette::Base,
506 QColor(qt_colorref2qrgb(GetSysColor(COLOR_WINDOW))));
507 pal.setColor(QPalette::Window,
508 QColor(qt_colorref2qrgb(GetSysColor(COLOR_BTNFACE))));
509 pal.setColor(QPalette::ButtonText,
510 QColor(qt_colorref2qrgb(GetSysColor(COLOR_BTNTEXT))));
511 pal.setColor(QPalette::Midlight,
512 QColor(qt_colorref2qrgb(GetSysColor(COLOR_3DLIGHT))));
513 pal.setColor(QPalette::Shadow,
514 QColor(qt_colorref2qrgb(GetSysColor(COLOR_3DDKSHADOW))));
515 pal.setColor(QPalette::Highlight,
516 QColor(qt_colorref2qrgb(GetSysColor(COLOR_HIGHLIGHT))));
517 pal.setColor(QPalette::HighlightedText,
518 QColor(qt_colorref2qrgb(GetSysColor(COLOR_HIGHLIGHTTEXT))));
519
520#if defined(Q_WS_WINCE)
521 // ### hardcoded until I find out how to get it from the system settings.
522 pal.setColor(QPalette::LinkVisited, pal.highlight().color().dark(150));
523 pal.setColor(QPalette::Link, pal.highlight().color().light(130));
524 // Background == Base on Windows CE
525 if (qt_wince_is_smartphone() || qt_wince_is_pocket_pc())
526 pal.setColor(QPalette::Background, pal.base().color());
527#else
528 pal.setColor(QPalette::Link, Qt::blue);
529 pal.setColor(QPalette::LinkVisited, Qt::magenta);
530#endif
531
532
533
534 pal.setColor(QPalette::Inactive, QPalette::Button, pal.button().color());
535 pal.setColor(QPalette::Inactive, QPalette::Window, pal.background().color());
536 pal.setColor(QPalette::Inactive, QPalette::Light, pal.light().color());
537 pal.setColor(QPalette::Inactive, QPalette::Dark, pal.dark().color());
538
539 if (pal.midlight() == pal.button())
540 pal.setColor(QPalette::Midlight, pal.button().color().lighter(110));
541 if (pal.background() != pal.base()) {
542 pal.setColor(QPalette::Inactive, QPalette::Highlight, pal.color(QPalette::Inactive, QPalette::Window));
543 pal.setColor(QPalette::Inactive, QPalette::HighlightedText, pal.color(QPalette::Inactive, QPalette::Text));
544 }
545
546 const QColor bg = pal.background().color();
547 const QColor fg = pal.foreground().color(), btn = pal.button().color();
548 QColor disabled((fg.red()+btn.red())/2,(fg.green()+btn.green())/2,
549 (fg.blue()+btn.blue())/2);
550 pal.setColorGroup(QPalette::Disabled, pal.foreground(), pal.button(), pal.light(),
551 pal.dark(), pal.mid(), pal.text(), pal.brightText(), pal.base(), pal.background() );
552 pal.setColor(QPalette::Disabled, QPalette::WindowText, disabled);
553 pal.setColor(QPalette::Disabled, QPalette::Text, disabled);
554 pal.setColor(QPalette::Disabled, QPalette::ButtonText, disabled);
555 pal.setColor(QPalette::Disabled, QPalette::Highlight,
556 QColor(qt_colorref2qrgb(GetSysColor(COLOR_HIGHLIGHT))));
557 pal.setColor(QPalette::Disabled, QPalette::HighlightedText,
558 QColor(qt_colorref2qrgb(GetSysColor(COLOR_HIGHLIGHTTEXT))));
559 pal.setColor(QPalette::Disabled, QPalette::Base, bg);
560
561 QApplicationPrivate::setSystemPalette(pal);
562
563 QApplicationPrivate::initializeWidgetPaletteHash();
564
565 QColor ttip(qt_colorref2qrgb(GetSysColor(COLOR_INFOBK)));
566
567 QColor ttipText(qt_colorref2qrgb(GetSysColor(COLOR_INFOTEXT)));
568 {
569#ifndef QT_NO_TOOLTIP
570 QPalette tiplabel(pal);
571 tiplabel.setColor(QPalette::All, QPalette::Button, ttip);
572 tiplabel.setColor(QPalette::All, QPalette::Window, ttip);
573 tiplabel.setColor(QPalette::All, QPalette::Text, ttipText);
574 tiplabel.setColor(QPalette::All, QPalette::WindowText, ttipText);
575 tiplabel.setColor(QPalette::All, QPalette::ButtonText, ttipText);
576 tiplabel.setColor(QPalette::All, QPalette::Button, ttip);
577 tiplabel.setColor(QPalette::All, QPalette::Window, ttip);
578 tiplabel.setColor(QPalette::All, QPalette::Text, ttipText);
579 tiplabel.setColor(QPalette::All, QPalette::WindowText, ttipText);
580 tiplabel.setColor(QPalette::All, QPalette::ButtonText, ttipText);
581 const QColor fg = tiplabel.foreground().color(), btn = tiplabel.button().color();
582 QColor disabled((fg.red()+btn.red())/2,(fg.green()+btn.green())/2,
583 (fg.blue()+btn.blue())/2);
584 tiplabel.setColor(QPalette::Disabled, QPalette::WindowText, disabled);
585 tiplabel.setColor(QPalette::Disabled, QPalette::Text, disabled);
586 tiplabel.setColor(QPalette::Disabled, QPalette::Base, Qt::white);
587 tiplabel.setColor(QPalette::Disabled, QPalette::BrightText, Qt::white);
588 QToolTip::setPalette(tiplabel);
589#endif //QT_NO_TOOLTIP
590 }
591}
592
593static void qt_set_windows_font_resources()
594{
595#ifndef Q_WS_WINCE
596 NONCLIENTMETRICS ncm;
597 ncm.cbSize = FIELD_OFFSET(NONCLIENTMETRICS, lfMessageFont) + sizeof(LOGFONT);
598 SystemParametersInfo(SPI_GETNONCLIENTMETRICS, ncm.cbSize , &ncm, 0);
599
600 QFont menuFont = qt_LOGFONTtoQFont(ncm.lfMenuFont, true);
601 QFont messageFont = qt_LOGFONTtoQFont(ncm.lfMessageFont, true);
602 QFont statusFont = qt_LOGFONTtoQFont(ncm.lfStatusFont, true);
603 QFont titleFont = qt_LOGFONTtoQFont(ncm.lfCaptionFont, true);
604
605 LOGFONT lfIconTitleFont;
606 SystemParametersInfo(SPI_GETICONTITLELOGFONT, sizeof(lfIconTitleFont), &lfIconTitleFont, 0);
607 QFont iconTitleFont = qt_LOGFONTtoQFont(lfIconTitleFont, true);
608
609 QApplication::setFont(menuFont, "QMenu");
610 QApplication::setFont(menuFont, "QMenuBar");
611 QApplication::setFont(messageFont, "QMessageBox");
612 QApplication::setFont(statusFont, "QTipLabel");
613 QApplication::setFont(statusFont, "QStatusBar");
614 QApplication::setFont(titleFont, "Q3TitleBar");
615 QApplication::setFont(titleFont, "QWorkspaceTitleBar");
616 QApplication::setFont(iconTitleFont, "QAbstractItemView");
617 QApplication::setFont(iconTitleFont, "QDockWidgetTitle");
618
619#else
620 LOGFONT lf;
621 HGDIOBJ stockFont = GetStockObject(SYSTEM_FONT);
622 GetObject(stockFont, sizeof(lf), &lf);
623 QFont systemFont = qt_LOGFONTtoQFont(lf, true);
624 QApplicationPrivate::setSystemFont(systemFont);
625 QFont smallerFont = systemFont;
626 if (qt_wince_is_mobile()) {
627 smallerFont.setPointSize(systemFont.pointSize()-1);
628 QApplication::setFont(smallerFont, "QTabBar");
629 smallerFont.setBold(true);
630 QApplication::setFont(smallerFont, "QAbstractButton");
631 }
632#endif// Q_WS_WINCE
633}
634
635static void qt_win_read_cleartype_settings()
636{
637 UINT result = 0;
638#ifdef Q_OS_WINCE
639 if (SystemParametersInfo(SPI_GETFONTSMOOTHING, 0, &result, 0))
640 qt_cleartype_enabled = result;
641#else
642 if (SystemParametersInfo(SPI_GETFONTSMOOTHINGTYPE, 0, &result, 0))
643 qt_cleartype_enabled = (result == FE_FONTSMOOTHINGCLEARTYPE);
644#endif
645}
646
647
648static void qt_set_windows_resources()
649{
650 if (QApplication::type() != QApplication::Tty)
651 (void) QApplication::style(); // trigger creation of application style
652 qt_set_windows_font_resources();
653 qt_set_windows_color_resources();
654}
655
656void QApplicationPrivate::initializeWidgetPaletteHash()
657{
658 QPalette pal = *QApplicationPrivate::sys_pal;
659 QColor menuCol(qt_colorref2qrgb(GetSysColor(COLOR_MENU)));
660 QColor menuText(qt_colorref2qrgb(GetSysColor(COLOR_MENUTEXT)));
661 BOOL isFlat = false;
662 if ((QSysInfo::WindowsVersion >= QSysInfo::WV_XP
663 && QSysInfo::WindowsVersion < QSysInfo::WV_NT_based))
664 SystemParametersInfo(SPI_GETFLATMENU, 0, &isFlat, 0);
665 QPalette menu(pal);
666 // we might need a special color group for the menu.
667 menu.setColor(QPalette::Active, QPalette::Button, menuCol);
668 menu.setColor(QPalette::Active, QPalette::Text, menuText);
669 menu.setColor(QPalette::Active, QPalette::WindowText, menuText);
670 menu.setColor(QPalette::Active, QPalette::ButtonText, menuText);
671 const QColor fg = menu.foreground().color(), btn = menu.button().color();
672 QColor disabled(qt_colorref2qrgb(GetSysColor(COLOR_GRAYTEXT)));
673 menu.setColor(QPalette::Disabled, QPalette::WindowText, disabled);
674 menu.setColor(QPalette::Disabled, QPalette::Text, disabled);
675 menu.setColor(QPalette::Disabled, QPalette::Highlight,
676 QColor(qt_colorref2qrgb(GetSysColor(
677 (QSysInfo::WindowsVersion >= QSysInfo::WV_XP
678 && QSysInfo::WindowsVersion < QSysInfo::WV_NT_based)
679 && isFlat ? COLOR_MENUHILIGHT : COLOR_HIGHLIGHT))));
680 menu.setColor(QPalette::Disabled, QPalette::HighlightedText, disabled);
681 menu.setColor(QPalette::Disabled, QPalette::Button,
682 menu.color(QPalette::Active, QPalette::Button));
683 menu.setColor(QPalette::Inactive, QPalette::Button,
684 menu.color(QPalette::Active, QPalette::Button));
685 menu.setColor(QPalette::Inactive, QPalette::Text,
686 menu.color(QPalette::Active, QPalette::Text));
687 menu.setColor(QPalette::Inactive, QPalette::WindowText,
688 menu.color(QPalette::Active, QPalette::WindowText));
689 menu.setColor(QPalette::Inactive, QPalette::ButtonText,
690 menu.color(QPalette::Active, QPalette::ButtonText));
691 menu.setColor(QPalette::Inactive, QPalette::Highlight,
692 menu.color(QPalette::Active, QPalette::Highlight));
693 menu.setColor(QPalette::Inactive, QPalette::HighlightedText,
694 menu.color(QPalette::Active, QPalette::HighlightedText));
695 menu.setColor(QPalette::Inactive, QPalette::ButtonText,
696 pal.color(QPalette::Inactive, QPalette::Dark));
697 QApplication::setPalette(menu, "QMenu");
698
699 if ((QSysInfo::WindowsVersion >= QSysInfo::WV_XP
700 && QSysInfo::WindowsVersion < QSysInfo::WV_NT_based) && isFlat) {
701 QColor menubar(qt_colorref2qrgb(GetSysColor(COLOR_MENUBAR)));
702 menu.setColor(QPalette::Active, QPalette::Button, menubar);
703 menu.setColor(QPalette::Disabled, QPalette::Button, menubar);
704 menu.setColor(QPalette::Inactive, QPalette::Button, menubar);
705 }
706 QApplication::setPalette(menu, "QMenuBar");
707}
708
709static void qt_set_windows_updateScrollBar(QWidget *widget)
710{
711 QList<QObject*> children = widget->children();
712 for (int i = 0; i < children.size(); ++i) {
713 QObject *o = children.at(i);
714 if(!o->isWidgetType())
715 continue;
716 if (QWidget *w = static_cast<QWidget *>(o))
717 qt_set_windows_updateScrollBar(w);
718 }
719#ifndef QT_NO_SCROLLBAR
720 if (qobject_cast<QScrollBar*>(widget))
721 widget->updateGeometry();
722#endif
723}
724
725
726/*****************************************************************************
727 qt_init() - initializes Qt for Windows
728 *****************************************************************************/
729
730typedef BOOL (WINAPI *PtrSetProcessDPIAware) (VOID);
731static PtrSetProcessDPIAware ptrSetProcessDPIAware = 0;
732PtrUpdateLayeredWindow ptrUpdateLayeredWindow = 0;
733PtrUpdateLayeredWindowIndirect ptrUpdateLayeredWindowIndirect = 0;
734static BOOL WINAPI qt_updateLayeredWindowIndirect(HWND hwnd, const Q_UPDATELAYEREDWINDOWINFO *info)
735{
736 return (*ptrUpdateLayeredWindow)(hwnd, info->hdcDst, info->pptDst, info->psize, info->hdcSrc,
737 info->pptSrc, info->crKey, info->pblend, info->dwFlags);
738}
739
740void qt_init(QApplicationPrivate *priv, int)
741{
742
743 int argc = priv->argc;
744 char **argv = priv->argv;
745 int i, j;
746
747 // Get command line params
748
749 j = argc ? 1 : 0;
750 for (i=1; i<argc; i++) {
751 if (argv[i] && *argv[i] != '-') {
752 argv[j++] = argv[i];
753 continue;
754 }
755#if defined(QT_DEBUG)
756 if (qstrcmp(argv[i], "-nograb") == 0)
757 appNoGrab = !appNoGrab;
758 else
759#endif // QT_DEBUG
760 argv[j++] = argv[i];
761 }
762 if(j < priv->argc) {
763 priv->argv[j] = 0;
764 priv->argc = j;
765 }
766
767#ifndef Q_WS_WINCE
768 // No message boxes but important ones
769 SetErrorMode(SetErrorMode(0) | SEM_FAILCRITICALERRORS|SEM_NOOPENFILEERRORBOX);
770#endif
771
772#ifndef Q_WS_WINCE
773 // Initialize OLE/COM
774 // S_OK means success and S_FALSE means that it has already
775 // been initialized
776 HRESULT r;
777 r = OleInitialize(0);
778 if (r != S_OK && r != S_FALSE) {
779 qWarning("Qt: Could not initialize OLE (error %x)", (unsigned int)r);
780 }
781#endif
782
783 // Misc. initialization
784#if defined(QT_DEBUG) && !defined(Q_WS_WINCE)
785 GdiSetBatchLimit(1);
786#endif
787
788 // initialize key mapper
789 QKeyMapper::changeKeyboard();
790
791 QColormap::initialize();
792 QFont::initialize();
793#ifndef QT_NO_CURSOR
794 QCursorData::initialize();
795#endif
796 qApp->setObjectName(priv->appName());
797
798 // default font
799#ifndef Q_WS_WINCE
800 HGDIOBJ stockFont = GetStockObject(DEFAULT_GUI_FONT);
801#else
802 HGDIOBJ stockFont = GetStockObject(SYSTEM_FONT);
803#endif
804
805 LOGFONT lf;
806 GetObject(stockFont, sizeof(lf), &lf);
807 QFont systemFont = qt_LOGFONTtoQFont(lf, true);
808
809#ifndef Q_WS_WINCE
810 if (systemFont.family() == QLatin1String("MS Shell Dlg")) {
811 systemFont.setFamily(QLatin1String("MS Shell Dlg 2"));
812 }
813#endif
814
815 QApplicationPrivate::setSystemFont(systemFont);
816
817 // QFont::locale_init(); ### Uncomment when it does something on Windows
818
819 if (QApplication::desktopSettingsAware())
820 qt_set_windows_resources();
821
822#ifndef QT_NO_TABLETEVENT
823 initWinTabFunctions();
824#endif // QT_NO_TABLETEVENT
825 QApplicationPrivate::inputContext = new QWinInputContext(0);
826
827 // Read the initial cleartype settings...
828 qt_win_read_cleartype_settings();
829 qt_win_owndc_required = false;
830
831 extern void qt_win_initialize_directdraw();
832 qt_win_initialize_directdraw();
833
834#ifndef Q_OS_WINCE
835 ptrUpdateLayeredWindowIndirect =
836 (PtrUpdateLayeredWindowIndirect) QSystemLibrary::resolve(QLatin1String("user32"),
837 "UpdateLayeredWindowIndirect");
838 ptrUpdateLayeredWindow =
839 (PtrUpdateLayeredWindow) QSystemLibrary::resolve(QLatin1String("user32"),
840 "UpdateLayeredWindow");
841
842 if (ptrUpdateLayeredWindow && !ptrUpdateLayeredWindowIndirect)
843 ptrUpdateLayeredWindowIndirect = qt_updateLayeredWindowIndirect;
844
845 // Notify Vista and Windows 7 that we support highter DPI settings
846 ptrSetProcessDPIAware = (PtrSetProcessDPIAware)
847 QSystemLibrary::resolve(QLatin1String("user32"), "SetProcessDPIAware");
848 if (ptrSetProcessDPIAware)
849 ptrSetProcessDPIAware();
850#endif
851
852#ifndef QT_NO_GESTURES
853 priv->GetGestureInfo = 0;
854 priv->GetGestureExtraArgs = 0;
855 priv->CloseGestureInfoHandle = 0;
856 priv->SetGestureConfig = 0;
857 priv->GetGestureConfig = 0;
858 priv->BeginPanningFeedback = 0;
859 priv->UpdatePanningFeedback = 0;
860 priv->EndPanningFeedback = 0;
861
862#if defined(Q_WS_WINCE_WM) && defined(QT_WINCE_GESTURES)
863 priv->GetGestureInfo = (PtrGetGestureInfo) &TKGetGestureInfo;
864 priv->GetGestureExtraArgs = (PtrGetGestureExtraArgs) &TKGetGestureExtraArguments;
865#elif !defined(Q_WS_WINCE)
866 #if !defined(QT_NO_NATIVE_GESTURES)
867 priv->GetGestureInfo =
868 (PtrGetGestureInfo)QSystemLibrary::resolve(QLatin1String("user32"),
869 "GetGestureInfo");
870 priv->GetGestureExtraArgs =
871 (PtrGetGestureExtraArgs)QSystemLibrary::resolve(QLatin1String("user32"),
872 "GetGestureExtraArgs");
873 priv->CloseGestureInfoHandle =
874 (PtrCloseGestureInfoHandle)QSystemLibrary::resolve(QLatin1String("user32"),
875 "CloseGestureInfoHandle");
876 priv->SetGestureConfig =
877 (PtrSetGestureConfig)QSystemLibrary::resolve(QLatin1String("user32"),
878 "SetGestureConfig");
879 priv->GetGestureConfig =
880 (PtrGetGestureConfig)QSystemLibrary::resolve(QLatin1String("user32"),
881 "GetGestureConfig");
882 #endif // QT_NO_NATIVE_GESTURES
883 QSystemLibrary libTheme(QLatin1String("uxtheme"));
884 priv->BeginPanningFeedback =
885 (PtrBeginPanningFeedback)libTheme.resolve("BeginPanningFeedback");
886 priv->UpdatePanningFeedback =
887 (PtrUpdatePanningFeedback)libTheme.resolve("UpdatePanningFeedback");
888 priv->EndPanningFeedback =
889 (PtrEndPanningFeedback)libTheme.resolve("EndPanningFeedback");
890#endif
891#endif // QT_NO_GESTURES
892}
893
894/*****************************************************************************
895 qt_cleanup() - cleans up when the application is finished
896 *****************************************************************************/
897
898void qt_cleanup()
899{
900 unregWinClasses();
901 QPixmapCache::clear();
902
903#ifndef QT_NO_CURSOR
904 QCursorData::cleanup();
905#endif
906 QFont::cleanup();
907 QColormap::cleanup();
908 if (displayDC) {
909 ReleaseDC(0, displayDC);
910 displayDC = 0;
911 }
912
913 delete QApplicationPrivate::inputContext;
914 QApplicationPrivate::inputContext = 0;
915
916#ifndef Q_WS_WINCE
917 // Deinitialize OLE/COM
918 OleUninitialize();
919#endif
920}
921
922
923/*****************************************************************************
924 Platform specific global and internal functions
925 *****************************************************************************/
926
927Q_GUI_EXPORT HDC qt_win_display_dc() // get display DC
928{
929 Q_ASSERT(qApp && qApp->thread() == QThread::currentThread());
930 if (!displayDC)
931 displayDC = GetDC(0);
932 return displayDC;
933}
934
935bool qt_nograb() // application no-grab option
936{
937#if defined(QT_DEBUG)
938 return appNoGrab;
939#else
940 return false;
941#endif
942}
943
944typedef QHash<QString, int> WinClassNameHash;
945Q_GLOBAL_STATIC(WinClassNameHash, winclassNames)
946
947const QString qt_reg_winclass(QWidget *w) // register window class
948{
949 int flags = w->windowFlags();
950 int type = flags & Qt::WindowType_Mask;
951
952 uint style;
953 bool icon;
954 QString cname;
955 if (qt_widget_private(w)->isGLWidget) {
956 cname = QLatin1String("QGLWidget");
957 style = CS_DBLCLKS;
958#ifndef Q_WS_WINCE
959 style |= CS_OWNDC;
960#endif
961 icon = true;
962 } else if (flags & Qt::MSWindowsOwnDC) {
963 cname = QLatin1String("QWidgetOwnDC");
964 style = CS_DBLCLKS;
965#ifndef Q_WS_WINCE
966 style |= CS_OWNDC;
967#endif
968 icon = true;
969 } else if (type == Qt::Tool || type == Qt::ToolTip){
970 style = CS_DBLCLKS;
971 if (w->inherits("QTipLabel") || w->inherits("QAlphaWidget")) {
972 if ((QSysInfo::WindowsVersion >= QSysInfo::WV_XP
973 && QSysInfo::WindowsVersion < QSysInfo::WV_NT_based)) {
974 style |= CS_DROPSHADOW;
975 }
976 cname = QLatin1String("QToolTip");
977 } else {
978 cname = QLatin1String("QTool");
979 }
980#ifndef Q_WS_WINCE
981 style |= CS_SAVEBITS;
982#endif
983 icon = false;
984 } else if (type == Qt::Popup) {
985 cname = QLatin1String("QPopup");
986 style = CS_DBLCLKS;
987#ifndef Q_WS_WINCE
988 style |= CS_SAVEBITS;
989#endif
990 if ((QSysInfo::WindowsVersion >= QSysInfo::WV_XP
991 && QSysInfo::WindowsVersion < QSysInfo::WV_NT_based))
992 style |= CS_DROPSHADOW;
993 icon = false;
994 } else {
995 cname = QLatin1String("QWidget");
996 style = CS_DBLCLKS;
997 icon = true;
998 }
999
1000#ifndef Q_WS_WINCE
1001 // force CS_OWNDC when the GL graphics system is
1002 // used as the default renderer
1003 if (qt_win_owndc_required)
1004 style |= CS_OWNDC;
1005#endif
1006
1007#ifdef Q_OS_WINCE
1008 // We need to register the classes with the
1009 // unique ID on WinCE to make sure we can
1010 // move the windows to the front when starting
1011 // a second instance.
1012 wchar_t uniqueAppID[MAX_PATH];
1013 GetModuleFileName(0, uniqueAppID, MAX_PATH);
1014 cname = QString::number(RegisterWindowMessage(
1015 (const wchar_t *) QString::fromWCharArray(uniqueAppID).toLower().replace(QLatin1Char('\\'),
1016 QLatin1Char('_')).utf16()));
1017#endif
1018
1019 // since multiple Qt versions can be used in one process
1020 // each one has to have window class names with a unique name
1021 // The first instance gets the unmodified name; if the class
1022 // has already been registered by another instance of Qt then
1023 // add an instance-specific ID, the address of the window proc.
1024 static int classExists = -1;
1025
1026 if (classExists == -1) {
1027 WNDCLASS wcinfo;
1028 classExists = GetClassInfo((HINSTANCE)qWinAppInst(), (wchar_t*)cname.utf16(), &wcinfo);
1029 classExists = classExists && wcinfo.lpfnWndProc != QtWndProc;
1030 }
1031
1032 if (classExists)
1033 cname += QString::number((quintptr)QtWndProc);
1034
1035 if (winclassNames()->contains(cname)) // already registered in our list
1036 return cname;
1037
1038 WNDCLASS wc;
1039 wc.style = style;
1040 wc.lpfnWndProc = (WNDPROC)QtWndProc;
1041 wc.cbClsExtra = 0;
1042 wc.cbWndExtra = 0;
1043 wc.hInstance = qWinAppInst();
1044 if (icon) {
1045 wc.hIcon = (HICON)LoadImage(qWinAppInst(), L"IDI_ICON1", IMAGE_ICON, 0, 0, LR_DEFAULTSIZE);
1046#ifndef Q_WS_WINCE
1047 if (!wc.hIcon)
1048 wc.hIcon = (HICON)LoadImage(0, IDI_APPLICATION, IMAGE_ICON, 0, 0, LR_DEFAULTSIZE | LR_SHARED);
1049#endif
1050 } else {
1051 wc.hIcon = 0;
1052 }
1053 wc.hCursor = 0;
1054#ifndef Q_WS_WINCE
1055 wc.hbrBackground = qt_widget_private(w)->isGLWidget ? 0 : (HBRUSH)GetSysColorBrush(COLOR_WINDOW);
1056#else
1057 wc.hbrBackground = 0;
1058#endif
1059 wc.lpszMenuName = 0;
1060 wc.lpszClassName = (wchar_t*)cname.utf16();
1061
1062 ATOM atom = RegisterClass(&wc);
1063
1064#ifndef QT_NO_DEBUG
1065 if (!atom)
1066 qErrnoWarning("QApplication::regClass: Registering window class failed.");
1067#else
1068 Q_UNUSED(atom);
1069#endif
1070
1071 winclassNames()->insert(cname, 1);
1072 return cname;
1073}
1074
1075Q_GUI_EXPORT const QString qt_getRegisteredWndClass()
1076{
1077 QWidget w;
1078 return qt_reg_winclass(&w);
1079}
1080
1081static void unregWinClasses()
1082{
1083 WinClassNameHash *hash = winclassNames();
1084 QHash<QString, int>::ConstIterator it = hash->constBegin();
1085 while (it != hash->constEnd()) {
1086 UnregisterClass((wchar_t*)it.key().utf16(), qWinAppInst());
1087 ++it;
1088 }
1089 hash->clear();
1090}
1091
1092
1093/*****************************************************************************
1094 Safe configuration (move,resize,setGeometry) mechanism to avoid
1095 recursion when processing messages.
1096 *****************************************************************************/
1097
1098struct QWinConfigRequest {
1099 WId id; // widget to be configured
1100 int req; // 0=move, 1=resize, 2=setGeo
1101 int x, y, w, h; // request parameters
1102};
1103
1104static QList<QWinConfigRequest*> *configRequests = 0;
1105
1106void qWinRequestConfig(WId id, int req, int x, int y, int w, int h)
1107{
1108 if (!configRequests) // create queue
1109 configRequests = new QList<QWinConfigRequest*>;
1110 QWinConfigRequest *r = new QWinConfigRequest;
1111 r->id = id; // create new request
1112 r->req = req;
1113 r->x = x;
1114 r->y = y;
1115 r->w = w;
1116 r->h = h;
1117 configRequests->append(r); // store request in queue
1118}
1119
1120static void qWinProcessConfigRequests() // perform requests in queue
1121{
1122 if (!configRequests)
1123 return;
1124 QWinConfigRequest *r;
1125 for (;;) {
1126 if (configRequests->isEmpty())
1127 break;
1128 r = configRequests->takeLast();
1129 QWidget *w = QWidget::find(r->id);
1130 QRect rect(r->x, r->y, r->w, r->h);
1131 int req = r->req;
1132 delete r;
1133
1134 if ( w ) { // widget exists
1135 if (w->testAttribute(Qt::WA_WState_ConfigPending))
1136 return; // biting our tail
1137 if (req == 0)
1138 w->move(rect.topLeft());
1139 else if (req == 1)
1140 w->resize(rect.size());
1141 else
1142 w->setGeometry(rect);
1143 }
1144 }
1145 delete configRequests;
1146 configRequests = 0;
1147}
1148
1149
1150/*****************************************************************************
1151 GUI event dispatcher
1152 *****************************************************************************/
1153
1154class QGuiEventDispatcherWin32 : public QEventDispatcherWin32
1155{
1156 Q_DECLARE_PRIVATE(QEventDispatcherWin32)
1157public:
1158 QGuiEventDispatcherWin32(QObject *parent = 0);
1159 bool processEvents(QEventLoop::ProcessEventsFlags flags);
1160};
1161
1162QGuiEventDispatcherWin32::QGuiEventDispatcherWin32(QObject *parent)
1163 : QEventDispatcherWin32(parent)
1164{
1165 createInternalHwnd();
1166}
1167
1168bool QGuiEventDispatcherWin32::processEvents(QEventLoop::ProcessEventsFlags flags)
1169{
1170 if (!QEventDispatcherWin32::processEvents(flags))
1171 return false;
1172
1173 if (configRequests) // any pending configs?
1174 qWinProcessConfigRequests();
1175
1176 return true;
1177}
1178
1179void QApplicationPrivate::createEventDispatcher()
1180{
1181 Q_Q(QApplication);
1182 if (q->type() != QApplication::Tty)
1183 eventDispatcher = new QGuiEventDispatcherWin32(q);
1184 else
1185 eventDispatcher = new QEventDispatcherWin32(q);
1186}
1187
1188/*****************************************************************************
1189 Platform specific QApplication members
1190 *****************************************************************************/
1191
1192#ifdef QT3_SUPPORT
1193void QApplication::setMainWidget(QWidget *mainWidget)
1194{
1195 QApplicationPrivate::main_widget = mainWidget;
1196 if (QApplicationPrivate::main_widget && windowIcon().isNull()
1197 && QApplicationPrivate::main_widget->testAttribute(Qt::WA_SetWindowIcon))
1198 setWindowIcon(QApplicationPrivate::main_widget->windowIcon());
1199}
1200#endif
1201
1202#ifndef QT_NO_CURSOR
1203
1204/*****************************************************************************
1205 QApplication cursor stack
1206 *****************************************************************************/
1207
1208void QApplication::setOverrideCursor(const QCursor &cursor)
1209{
1210 qApp->d_func()->cursor_list.prepend(cursor);
1211 SetCursor(qApp->d_func()->cursor_list.first().handle());
1212}
1213
1214void QApplication::restoreOverrideCursor()
1215{
1216 if (qApp->d_func()->cursor_list.isEmpty())
1217 return;
1218 qApp->d_func()->cursor_list.removeFirst();
1219
1220 if (!qApp->d_func()->cursor_list.isEmpty()) {
1221 SetCursor(qApp->d_func()->cursor_list.first().handle());
1222 } else {
1223 QWidget *w = QWidget::find(curWin);
1224 if (w)
1225 SetCursor(w->cursor().handle());
1226 else
1227 SetCursor(QCursor(Qt::ArrowCursor).handle());
1228 }
1229}
1230
1231#endif
1232
1233/*
1234 Internal function called from QWidget::setCursor()
1235 force is true if this function is called from dispatchEnterLeave, it means that the
1236 mouse is actually directly under this widget.
1237*/
1238
1239#ifndef QT_NO_CURSOR
1240void qt_win_set_cursor(QWidget *w, bool force)
1241{
1242 static QPointer<QWidget> lastUnderMouse = 0;
1243 if (force) {
1244 lastUnderMouse = w;
1245 } else if (w->testAttribute(Qt::WA_WState_Created) && lastUnderMouse
1246 && lastUnderMouse->effectiveWinId() == w->effectiveWinId()) {
1247 w = lastUnderMouse;
1248 }
1249
1250 if (!curWin && w && w->internalWinId())
1251 return;
1252 QWidget* cW = w && !w->internalWinId() ? w : QWidget::find(curWin);
1253 if (!cW || cW->window() != w->window() ||
1254 !cW->isVisible() || !cW->underMouse() || QApplication::overrideCursor())
1255 return;
1256
1257 SetCursor(cW->cursor().handle());
1258}
1259#endif // QT_NO_CURSOR
1260
1261Qt::KeyboardModifiers qt_win_getKeyboardModifiers()
1262{
1263 Qt::KeyboardModifiers modifiers = Qt::NoModifier;
1264 if (GetKeyState(VK_SHIFT) < 0)
1265 modifiers |= Qt::ShiftModifier;
1266 if (GetKeyState(VK_CONTROL) < 0)
1267 modifiers |= Qt::ControlModifier;
1268 if (GetKeyState(VK_MENU) < 0)
1269 modifiers |= Qt::AltModifier;
1270 return modifiers;
1271}
1272
1273/*****************************************************************************
1274 Routines to find a Qt widget from a screen position
1275 *****************************************************************************/
1276
1277QWidget *QApplication::topLevelAt(const QPoint &pos)
1278{
1279 POINT p;
1280 HWND win;
1281 QWidget *w;
1282 p.x = pos.x();
1283 p.y = pos.y();
1284 win = WindowFromPoint(p);
1285 if (!win)
1286 return 0;
1287
1288 w = QWidget::find(win);
1289 while (!w && win) {
1290 win = GetParent(win);
1291 w = QWidget::find(win);
1292 }
1293 return w ? w->window() : 0;
1294}
1295
1296void QApplication::beep()
1297{
1298 MessageBeep(MB_OK);
1299}
1300
1301static void alert_widget(QWidget *widget, int duration)
1302{
1303#ifdef Q_OS_WINCE
1304 Q_UNUSED(widget);
1305 Q_UNUSED(duration);
1306#else
1307 bool stopFlash = duration < 0;
1308
1309 if (widget && (!widget->isActiveWindow() || stopFlash)) {
1310 DWORD timeOut = GetCaretBlinkTime();
1311 if (timeOut <= 0)
1312 timeOut = 250;
1313
1314 UINT flashCount;
1315 if (duration == 0)
1316 flashCount = 10;
1317 else
1318 flashCount = duration/timeOut;
1319
1320 FLASHWINFO info;
1321 info.cbSize = sizeof(info);
1322 info.hwnd = widget->window()->winId();
1323 info.dwFlags = stopFlash ? FLASHW_STOP : FLASHW_TRAY;
1324 info.dwTimeout = stopFlash ? 0 : timeOut;
1325 info.uCount = stopFlash ? 0 : flashCount;
1326
1327 FlashWindowEx(&info);
1328 }
1329#endif
1330}
1331
1332void QApplication::alert(QWidget *widget, int duration)
1333{
1334 if (!QApplicationPrivate::checkInstance("alert"))
1335 return;
1336
1337 if (widget) {
1338 alert_widget(widget, duration);
1339 } else {
1340 const QWidgetList toplevels(topLevelWidgets());
1341 for (int i = 0; i < toplevels.count(); ++i) {
1342 QWidget *topLevel = toplevels.at(i);
1343 alert_widget(topLevel, duration);
1344 }
1345 }
1346}
1347
1348QString QApplicationPrivate::appName() const
1349{
1350 return QCoreApplicationPrivate::appName();
1351}
1352
1353
1354/*****************************************************************************
1355 Main event loop
1356 *****************************************************************************/
1357
1358extern uint qGlobalPostedEventsCount();
1359
1360void QApplication::winFocus(QWidget *widget, bool gotFocus)
1361{
1362 if (d_func()->inPopupMode()) // some delayed focus event to ignore
1363 return;
1364 if (gotFocus) {
1365 setActiveWindow(widget);
1366 if (QApplicationPrivate::active_window
1367 && (QApplicationPrivate::active_window->windowType() == Qt::Dialog)) {
1368 // raise the entire application, not just the dialog
1369 QWidget* mw = QApplicationPrivate::active_window;
1370#ifndef Q_WS_WINCE
1371 while(mw->parentWidget() && (mw->windowType() == Qt::Dialog))
1372 mw = mw->parentWidget()->window();
1373 if (mw->testAttribute(Qt::WA_WState_Created) && mw != QApplicationPrivate::active_window)
1374 SetWindowPos(mw->internalWinId(), HWND_TOP, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);
1375#else
1376 // On Desktop Windows, we set the first parent of the dialog on top
1377 // Child windows will be automatically set above again.
1378 // On Windows CE we pass no parent in CreateWindowEx as otherwise
1379 // dialogs get embedded into the parent window. Thus we need to
1380 // manually iterate and reactivate all windows from bottom up.
1381 QList<QWidget*> raiseList;
1382 raiseList.push_back(mw);
1383 while(mw->parentWidget() && (mw->windowType() == Qt::Dialog)) {
1384 mw = mw->parentWidget()->window();
1385 raiseList.push_back(mw);
1386 }
1387 while(!raiseList.isEmpty()) {
1388 mw = raiseList.takeLast();
1389 if (mw->testAttribute(Qt::WA_WState_Created)) {
1390 HWND state = HWND_TOP;
1391 if (mw->windowFlags() & Qt::WindowStaysOnBottomHint)
1392 state = HWND_BOTTOM;
1393 else if (mw->windowFlags() & Qt::WindowStaysOnTopHint)
1394 state = HWND_TOPMOST;
1395 SetWindowPos(mw->internalWinId(), state, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);
1396 }
1397 }
1398#endif
1399 }
1400 } else {
1401 setActiveWindow(0);
1402 }
1403}
1404
1405
1406//
1407// QtWndProc() receives all messages from the main event loop
1408//
1409
1410static bool inLoop = false;
1411static int inputcharset = CP_ACP;
1412
1413#define RETURN(x) { inLoop=false;return x; }
1414
1415static bool qt_is_translatable_mouse_event(UINT message)
1416{
1417 return (((message >= WM_MOUSEFIRST && message <= WM_MOUSELAST) ||
1418 (message >= WM_XBUTTONDOWN && message <= WM_XBUTTONDBLCLK))
1419 && message != WM_MOUSEWHEEL
1420 && message != WM_MOUSEHWHEEL)
1421
1422#ifndef Q_WS_WINCE
1423 || (message >= WM_NCMOUSEMOVE && message <= WM_NCMBUTTONDBLCLK)
1424#endif
1425 ;
1426}
1427
1428extern "C" LRESULT QT_WIN_CALLBACK QtWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
1429{
1430 bool result = true;
1431 QEvent::Type evt_type = QEvent::None;
1432 QETWidget *widget = 0;
1433
1434 // there is no need to process pakcets from tablet unless
1435 // it is actually on the tablet, a flag to let us know...
1436 int nPackets; // the number of packets we get from the queue
1437
1438 long res = 0;
1439 if (!qApp) // unstable app state
1440 RETURN(QWinInputContext::DefWindowProc(hwnd,message,wParam,lParam))
1441
1442 QScopedLoopLevelCounter loopLevelCounter(QThreadData::get2(qApp->thread()));
1443
1444#if 0
1445 // make sure we update widgets also when the user resizes
1446 if (inLoop && qApp->loopLevel())
1447 qApp->sendPostedEvents(0, QEvent::Paint);
1448#endif
1449
1450 inLoop = true;
1451
1452 MSG msg;
1453 msg.hwnd = hwnd; // create MSG structure
1454 msg.message = message; // time and pt fields ignored
1455 msg.wParam = wParam;
1456 msg.lParam = lParam;
1457 msg.pt.x = GET_X_LPARAM(lParam);
1458 msg.pt.y = GET_Y_LPARAM(lParam);
1459 // If it's a non-client-area message the coords are screen coords, otherwise they are
1460 // client coords.
1461#ifndef Q_WS_WINCE
1462 if (message < WM_NCMOUSEMOVE || message > WM_NCMBUTTONDBLCLK)
1463#endif
1464 ClientToScreen(msg.hwnd, &msg.pt);
1465
1466 /*
1467 // sometimes the autograb is not released, so the clickevent is sent
1468 // to the wrong window. We ignore this for now, because it doesn't
1469 // cause any problems.
1470 if (msg.message == WM_LBUTTONDOWN || msg.message == WM_RBUTTONDOWN || msg.message == WM_MBUTTONDOWN) {
1471 HWND handle = WindowFromPoint(msg.pt);
1472 if (msg.hwnd != handle) {
1473 msg.hwnd = handle;
1474 hwnd = handle;
1475 }
1476 }
1477 */
1478
1479#if defined(QT_NON_COMMERCIAL)
1480 QT_NC_WNDPROC
1481#endif
1482
1483 // send through app filter
1484 if (qApp->filterEvent(&msg, &res))
1485 return res;
1486
1487 // close any opened ime candidate window (enabled only on a popup widget)
1488 if (imeParentWnd && QApplication::activePopupWidget()
1489 && (message == WM_MBUTTONDOWN || message == WM_XBUTTONDOWN
1490 || message == WM_LBUTTONDOWN || message == WM_RBUTTONDOWN
1491#ifndef Q_WS_WINCE
1492 || message == WM_NCMBUTTONDOWN || message == WM_NCLBUTTONDOWN
1493 || message == WM_NCRBUTTONDOWN)) {
1494#else
1495 )) {
1496#endif
1497 ::SendMessage(imeParentWnd, WM_IME_ENDCOMPOSITION, 0, 0);
1498 }
1499
1500 switch (message) {
1501#ifndef Q_WS_WINCE
1502#ifndef QT_NO_SESSIONMANAGER
1503 case WM_QUERYENDSESSION: {
1504 if (sm_smActive) // bogus message from windows
1505 RETURN(true);
1506
1507 sm_smActive = true;
1508 sm_blockUserInput = true; // prevent user-interaction outside interaction windows
1509 sm_cancel = false;
1510 if (qt_session_manager_self)
1511 qApp->commitData(*qt_session_manager_self);
1512 if (lParam & ENDSESSION_LOGOFF) {
1513 _flushall();
1514 }
1515 RETURN(!sm_cancel);
1516 }
1517 case WM_ENDSESSION: {
1518 sm_smActive = false;
1519 sm_blockUserInput = false;
1520 bool endsession = (bool) wParam;
1521
1522 // we receive the message for each toplevel window included internal hidden ones,
1523 // but the aboutToQuit signal should be emitted only once.
1524 QApplicationPrivate *qAppPriv = QApplicationPrivate::instance();
1525 if (endsession && !qAppPriv->aboutToQuitEmitted) {
1526 qAppPriv->aboutToQuitEmitted = true;
1527 int index = QApplication::staticMetaObject.indexOfSignal("aboutToQuit()");
1528 qApp->qt_metacall(QMetaObject::InvokeMetaMethod, index,0);
1529 // since the process will be killed immediately quit() has no real effect
1530 QApplication::quit();
1531 }
1532
1533 RETURN(0);
1534 }
1535#endif
1536 case WM_DISPLAYCHANGE:
1537 if (QApplication::type() == QApplication::Tty)
1538 break;
1539 if (qt_desktopWidget) {
1540 qt_desktopWidget->move(GetSystemMetrics(76), GetSystemMetrics(77));
1541 QSize sz(GetSystemMetrics(78), GetSystemMetrics(79));
1542 if (sz == qt_desktopWidget->size()) {
1543 // a screen resized without changing size of the virtual desktop
1544 QResizeEvent rs(sz, qt_desktopWidget->size());
1545 QApplication::sendEvent(qt_desktopWidget, &rs);
1546 } else {
1547 qt_desktopWidget->resize(sz);
1548 }
1549 }
1550 break;
1551#endif
1552
1553 case WM_SETTINGCHANGE:
1554#ifdef Q_WS_WINCE
1555 // CE SIP hide/show
1556 if (qt_desktopWidget && wParam == SPI_SETSIPINFO) {
1557 QResizeEvent re(QSize(0, 0), QSize(0, 0)); // Calculated by QDesktopWidget
1558 QApplication::sendEvent(qt_desktopWidget, &re);
1559 break;
1560 }
1561#endif
1562 // ignore spurious XP message when user logs in again after locking
1563 if (QApplication::type() == QApplication::Tty)
1564 break;
1565 if (QApplication::desktopSettingsAware() && wParam != SPI_SETWORKAREA) {
1566 widget = (QETWidget*)QWidget::find(hwnd);
1567 if (widget) {
1568 if (wParam == SPI_SETNONCLIENTMETRICS)
1569 widget->markFrameStrutDirty();
1570 }
1571 }
1572 else if (qt_desktopWidget && wParam == SPI_SETWORKAREA) {
1573 qt_desktopWidget->move(GetSystemMetrics(76), GetSystemMetrics(77));
1574 QSize sz(GetSystemMetrics(78), GetSystemMetrics(79));
1575 if (sz == qt_desktopWidget->size()) {
1576 // a screen resized without changing size of the virtual desktop
1577 QResizeEvent rs(sz, qt_desktopWidget->size());
1578 QApplication::sendEvent(qt_desktopWidget, &rs);
1579 } else {
1580 qt_desktopWidget->resize(sz);
1581 }
1582 }
1583
1584 if (wParam == SPI_SETFONTSMOOTHINGTYPE) {
1585 qt_win_read_cleartype_settings();
1586 foreach (QWidget *w, QApplication::topLevelWidgets()) {
1587 if (!w->isVisible())
1588 continue;
1589 ((QETWidget *) w)->forceUpdate();
1590 }
1591 }
1592
1593 break;
1594 case WM_SYSCOLORCHANGE:
1595 if (QApplication::type() == QApplication::Tty)
1596 break;
1597 if (QApplication::desktopSettingsAware()) {
1598 widget = (QETWidget*)QWidget::find(hwnd);
1599 if (widget && !widget->parentWidget())
1600 qt_set_windows_color_resources();
1601 }
1602 break;
1603
1604 case WM_LBUTTONDOWN:
1605 case WM_MBUTTONDOWN:
1606 case WM_RBUTTONDOWN:
1607 case WM_XBUTTONDOWN:
1608 case WM_LBUTTONDBLCLK:
1609 case WM_RBUTTONDBLCLK:
1610 case WM_MBUTTONDBLCLK:
1611 case WM_XBUTTONDBLCLK:
1612 if (qt_win_ignoreNextMouseReleaseEvent)
1613 qt_win_ignoreNextMouseReleaseEvent = false;
1614 break;
1615
1616 case WM_LBUTTONUP:
1617 case WM_MBUTTONUP:
1618 case WM_RBUTTONUP:
1619 case WM_XBUTTONUP:
1620 if (qt_win_ignoreNextMouseReleaseEvent) {
1621 qt_win_ignoreNextMouseReleaseEvent = false;
1622 if (qt_button_down && qt_button_down->internalWinId() == autoCaptureWnd) {
1623 releaseAutoCapture();
1624 qt_button_down = 0;
1625 }
1626
1627 RETURN(0);
1628 }
1629 break;
1630
1631 default:
1632 break;
1633 }
1634
1635 if (!widget)
1636 widget = (QETWidget*)QWidget::find(hwnd);
1637 if (!widget) // don't know this widget
1638 goto do_default;
1639
1640 if (app_do_modal) { // modal event handling
1641 int ret = 0;
1642 if (!qt_try_modal(widget, &msg, ret))
1643 RETURN(ret);
1644 }
1645
1646 res = 0;
1647 if (widget->winEvent(&msg, &res)) // send through widget filter
1648 RETURN(res);
1649
1650 if (qt_is_translatable_mouse_event(message)) {
1651 if (QApplication::activePopupWidget() != 0) { // in popup mode
1652 POINT curPos = msg.pt;
1653 QWidget* w = QApplication::widgetAt(curPos.x, curPos.y);
1654 if (w)
1655 widget = (QETWidget*)w;
1656 }
1657
1658 if (!qt_tabletChokeMouse) {
1659 result = widget->translateMouseEvent(msg); // mouse event
1660#if defined(Q_WS_WINCE) && !defined(QT_NO_CONTEXTMENU)
1661 if (message == WM_LBUTTONDOWN && widget != QApplication::activePopupWidget()) {
1662 QWidget* alienWidget = widget;
1663 if ((alienWidget != QApplication::activePopupWidget()) && (alienWidget->contextMenuPolicy() != Qt::PreventContextMenu)) {
1664 QPoint pos(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
1665 QPoint globalPos(msg.pt.x, msg.pt.y);
1666 // In case we are using Alien, then the widget to
1667 // send the context menu event is a different one
1668 if (!alienWidget->testAttribute(Qt::WA_NativeWindow) && !alienWidget->testAttribute(Qt::WA_PaintOnScreen)) {
1669 alienWidget = QApplication::widgetAt(globalPos);
1670 if (alienWidget)
1671 pos = alienWidget->mapFromGlobal(globalPos);
1672 }
1673 if (alienWidget) {
1674 SHRGINFO shrg;
1675 shrg.cbSize = sizeof(shrg);
1676 shrg.hwndClient = hwnd;
1677 shrg.ptDown.x = GET_X_LPARAM(lParam);
1678 shrg.ptDown.y = GET_Y_LPARAM(lParam);
1679 shrg.dwFlags = SHRG_RETURNCMD | SHRG_NOANIMATION;
1680 resolveAygLibs();
1681#ifndef QT_NO_GESTURES
1682 if (ptrRecognizeGesture && (ptrRecognizeGesture(&shrg) == GN_CONTEXTMENU)) {
1683 if (QApplication::activePopupWidget())
1684 QApplication::activePopupWidget()->close();
1685 QContextMenuEvent e(QContextMenuEvent::Mouse, pos, globalPos);
1686 result = qt_sendSpontaneousEvent(alienWidget, &e);
1687 }
1688#endif // QT_NO_GESTURES
1689 }
1690 }
1691 }
1692#endif
1693 } else {
1694 // Sometimes we only get a WM_MOUSEMOVE message
1695 // and sometimes we get both a WM_MOUSEMOVE and
1696 // a WM_LBUTTONDOWN/UP, this creates a spurious mouse
1697 // press/release event, using the PeekMessage
1698 // will help us fix this. This leaves us with a
1699 // question:
1700 // This effectively kills using the mouse AND the
1701 // tablet simultaneously, well creates wacky input.
1702 // Is this going to be a problem? (probably not)
1703 bool next_is_button = false;
1704 bool is_mouse_move = (message == WM_MOUSEMOVE);
1705 if (is_mouse_move) {
1706 MSG msg1;
1707 if (PeekMessage(&msg1, msg.hwnd, WM_MOUSEFIRST,
1708 WM_MOUSELAST, PM_NOREMOVE))
1709 next_is_button = (msg1.message == WM_LBUTTONUP
1710 || msg1.message == WM_LBUTTONDOWN);
1711 }
1712 if (!is_mouse_move || (is_mouse_move && !next_is_button))
1713 qt_tabletChokeMouse = false;
1714 }
1715 } else {
1716 switch (message) {
1717 case WM_TOUCH:
1718 result = QApplicationPrivate::instance()->translateTouchEvent(msg);
1719 break;
1720 case WM_KEYDOWN: // keyboard event
1721 case WM_SYSKEYDOWN:
1722 qt_keymapper_private()->updateKeyMap(msg);
1723 // fall-through intended
1724 case WM_KEYUP:
1725 case WM_SYSKEYUP:
1726#if Q_OS_WINCE_WM
1727 case WM_HOTKEY:
1728 if(HIWORD(msg.lParam) == VK_TBACK) {
1729 const bool hotKeyDown = !(LOWORD(msg.lParam) & MOD_KEYUP);
1730 msg.lParam = 0x69 << 16;
1731 msg.wParam = VK_BACK;
1732 if (hotKeyDown) {
1733 msg.message = WM_KEYDOWN;
1734 qt_keymapper_private()->updateKeyMap(msg);
1735 } else {
1736 msg.message = WM_KEYUP;
1737 }
1738 }
1739 // fall-through intended
1740#endif
1741 case WM_IME_CHAR:
1742 case WM_IME_KEYDOWN:
1743 case WM_CHAR: {
1744 MSG msg1;
1745 bool anyMsg = PeekMessage(&msg1, msg.hwnd, 0, 0, PM_NOREMOVE);
1746 if (anyMsg && msg1.message == WM_DEADCHAR) {
1747 result = true; // consume event since there is a dead char next
1748 break;
1749 }
1750 QWidget *g = QWidget::keyboardGrabber();
1751 if (g && qt_get_tablet_widget() && hwnd == qt_get_tablet_widget()->winId()) {
1752 // if we get an event for the internal tablet widget,
1753 // then don't send it to the keyboard grabber, but
1754 // send it to the widget itself (we don't use it right
1755 // now, just in case).
1756 g = 0;
1757 }
1758 if (g)
1759 widget = (QETWidget*)g;
1760 else if (QApplication::activePopupWidget())
1761 widget = (QETWidget*)QApplication::activePopupWidget()->focusWidget()
1762 ? (QETWidget*)QApplication::activePopupWidget()->focusWidget()
1763 : (QETWidget*)QApplication::activePopupWidget();
1764 else if (QApplication::focusWidget())
1765 widget = (QETWidget*)QApplication::focusWidget();
1766 else if (!widget || widget->internalWinId() == GetFocus()) // We faked the message to go to exactly that widget.
1767 widget = (QETWidget*)widget->window();
1768 if (widget->isEnabled())
1769 result = sm_blockUserInput
1770 ? true
1771 : qt_keymapper_private()->translateKeyEvent(widget, msg, g != 0);
1772 break;
1773 }
1774 case WM_SYSCHAR:
1775 result = true; // consume event
1776 break;
1777
1778 case WM_MOUSEWHEEL:
1779 case WM_MOUSEHWHEEL:
1780 result = widget->translateWheelEvent(msg);
1781 break;
1782
1783 case WM_APPCOMMAND:
1784 {
1785 uint cmd = GET_APPCOMMAND_LPARAM(lParam);
1786 uint uDevice = GET_DEVICE_LPARAM(lParam);
1787 uint dwKeys = GET_KEYSTATE_LPARAM(lParam);
1788
1789 int state = translateButtonState(dwKeys, QEvent::KeyPress, 0);
1790
1791 switch (uDevice) {
1792 case FAPPCOMMAND_KEY:
1793 {
1794 int key = 0;
1795
1796 switch(cmd) {
1797 case APPCOMMAND_BASS_BOOST:
1798 key = Qt::Key_BassBoost;
1799 break;
1800 case APPCOMMAND_BASS_DOWN:
1801 key = Qt::Key_BassDown;
1802 break;
1803 case APPCOMMAND_BASS_UP:
1804 key = Qt::Key_BassUp;
1805 break;
1806 case APPCOMMAND_TREBLE_DOWN:
1807 key = Qt::Key_TrebleDown;
1808 break;
1809 case APPCOMMAND_TREBLE_UP:
1810 key = Qt::Key_TrebleUp;
1811 break;
1812 case APPCOMMAND_HELP:
1813 key = Qt::Key_Help;
1814 break;
1815 case APPCOMMAND_FIND:
1816 key = Qt::Key_Search;
1817 break;
1818 default:
1819 break;
1820 }
1821 if (key) {
1822 bool res = false;
1823 QWidget *g = QWidget::keyboardGrabber();
1824 if (g)
1825 widget = (QETWidget*)g;
1826 else if (QApplication::focusWidget())
1827 widget = (QETWidget*)QApplication::focusWidget();
1828 else
1829 widget = (QETWidget*)widget->window();
1830 if (widget->isEnabled()) {
1831 res = QKeyMapper::sendKeyEvent(widget, g != 0, QEvent::KeyPress, key,
1832 Qt::KeyboardModifier(state),
1833 QString(), false, 0, 0, 0, 0);
1834 }
1835 if (res)
1836 return true;
1837 }
1838 }
1839 break;
1840
1841 default:
1842 break;
1843 }
1844
1845 result = false;
1846 }
1847 break;
1848
1849#ifndef Q_WS_WINCE
1850 case WM_NCHITTEST:
1851 if (widget->isWindow()) {
1852 QPoint pos = widget->mapFromGlobal(QPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)));
1853 // don't show resize-cursors for fixed-size widgets
1854 QRect fs = widget->frameStrut();
1855 if (!widget->isMinimized()) {
1856 if (widget->minimumHeight() == widget->maximumHeight()) {
1857 if (pos.y() < -(fs.top() - fs.left()))
1858 return HTCAPTION;
1859 if (pos.y() >= widget->height())
1860 return HTBORDER;
1861 }
1862 if (widget->minimumWidth() == widget->maximumWidth() && (pos.x() < 0 || pos.x() >= widget->width()))
1863 return HTBORDER;
1864 }
1865 }
1866
1867 result = false;
1868 break;
1869#endif
1870
1871 case WM_SYSCOMMAND: {
1872#ifndef Q_WS_WINCE
1873 bool window_state_change = false;
1874 Qt::WindowStates oldstate = Qt::WindowStates(widget->dataPtr()->window_state);
1875 // MSDN:In WM_SYSCOMMAND messages, the four low-order bits of the wParam parameter are
1876 // used internally by the system. To obtain the correct result when testing the value of
1877 // wParam, an application must combine the value 0xFFF0 with the wParam value by using
1878 // the bitwise AND operator.
1879 switch(0xfff0 & wParam) {
1880 case SC_CONTEXTHELP:
1881#ifndef QT_NO_WHATSTHIS
1882 QWhatsThis::enterWhatsThisMode();
1883#endif
1884 DefWindowProc(hwnd, WM_NCPAINT, 1, 0);
1885 break;
1886#if defined(QT_NON_COMMERCIAL)
1887 QT_NC_SYSCOMMAND
1888#endif
1889 case SC_MINIMIZE:
1890 window_state_change = true;
1891 widget->dataPtr()->window_state |= Qt::WindowMinimized;
1892 if (widget->isVisible()) {
1893 QHideEvent e;
1894 qt_sendSpontaneousEvent(widget, &e);
1895 widget->hideChildren(true);
1896 const QString title = widget->windowIconText();
1897 if (!title.isEmpty())
1898 widget->setWindowTitle_helper(title);
1899 }
1900 result = false;
1901 break;
1902 case SC_MAXIMIZE:
1903 if(widget->isWindow())
1904 widget->topData()->normalGeometry = widget->geometry();
1905 case SC_RESTORE:
1906 window_state_change = true;
1907 if ((0xfff0 & wParam) == SC_MAXIMIZE)
1908 widget->dataPtr()->window_state |= Qt::WindowMaximized;
1909 else if (!widget->isMinimized())
1910 widget->dataPtr()->window_state &= ~Qt::WindowMaximized;
1911
1912 if (widget->isMinimized()) {
1913 widget->dataPtr()->window_state &= ~Qt::WindowMinimized;
1914 widget->showChildren(true);
1915 QShowEvent e;
1916 qt_sendSpontaneousEvent(widget, &e);
1917 const QString title = widget->windowTitle();
1918 if (!title.isEmpty())
1919 widget->setWindowTitle_helper(title);
1920 }
1921 result = false;
1922 break;
1923 default:
1924 result = false;
1925 break;
1926 }
1927
1928 if (window_state_change) {
1929 QWindowStateChangeEvent e(oldstate);
1930 qt_sendSpontaneousEvent(widget, &e);
1931 }
1932#endif // #ifndef Q_OS_WINCE
1933
1934 break;
1935 }
1936
1937 case WM_SETTINGCHANGE:
1938 if ( QApplication::type() == QApplication::Tty )
1939 break;
1940
1941 if (!msg.wParam) {
1942#ifdef Q_WS_WINCE
1943 // On Windows CE, lParam parameter is a constant, not a char pointer.
1944 if (msg.lParam == INI_INTL) {
1945#else
1946 QString area = QString::fromWCharArray((wchar_t*)msg.lParam);
1947 if (area == QLatin1String("intl")) {
1948#endif
1949 QLocalePrivate::updateSystemPrivate();
1950 if (!widget->testAttribute(Qt::WA_SetLocale))
1951 widget->dptr()->setLocale_helper(QLocale(), true);
1952 QEvent e(QEvent::LocaleChange);
1953 QApplication::sendEvent(qApp, &e);
1954 }
1955 }
1956 else if (msg.wParam == SPI_SETICONTITLELOGFONT) {
1957 if (QApplication::desktopSettingsAware()) {
1958 widget = (QETWidget*)QWidget::find(hwnd);
1959 if (widget && !widget->parentWidget()) {
1960 qt_set_windows_font_resources();
1961 }
1962 }
1963 }
1964 else if (msg.wParam == SPI_SETNONCLIENTMETRICS) {
1965 widget = (QETWidget*)QWidget::find(hwnd);
1966 if (widget && !widget->parentWidget()) {
1967 qt_set_windows_updateScrollBar(widget);
1968 QEvent e(QEvent::LayoutRequest);
1969 QApplication::sendEvent(widget, &e);
1970 }
1971 }
1972
1973 break;
1974
1975 case WM_PAINT: // paint event
1976 case WM_ERASEBKGND: // erase window background
1977 result = widget->translatePaintEvent(msg);
1978 break;
1979
1980#ifndef Q_WS_WINCE
1981 case WM_ENTERSIZEMOVE:
1982 autoCaptureWnd = hwnd;
1983 break;
1984 case WM_EXITSIZEMOVE:
1985 autoCaptureWnd = 0;
1986 break;
1987#endif
1988 case WM_MOVE: // move window
1989 case WM_SIZE: // resize window
1990 result = widget->translateConfigEvent(msg);
1991 break;
1992
1993 case WM_ACTIVATEAPP:
1994 if (wParam == FALSE) {
1995 QApplication::setActiveWindow(0);
1996 // Another application was activated while our popups are open,
1997 // then close all popups. In case some popup refuses to close,
1998 // we give up after 1024 attempts (to avoid an infinite loop).
1999 int maxiter = 1024;
2000 QWidget *popup;
2001 while ((popup=QApplication::activePopupWidget()) && maxiter--)
2002 popup->close();
2003 }
2004 break;
2005
2006 case WM_ACTIVATE:
2007 if ( QApplication::type() == QApplication::Tty )
2008 break;
2009
2010 if (ptrWTOverlap && ptrWTEnable) {
2011 // cooperate with other tablet applications, but when
2012 // we get focus, I want to use the tablet...
2013 if (qt_tablet_context && GET_WM_ACTIVATE_STATE(wParam, lParam)) {
2014 if (ptrWTEnable(qt_tablet_context, true))
2015 ptrWTOverlap(qt_tablet_context, true);
2016 }
2017 }
2018 if (QApplication::activePopupWidget() && LOWORD(wParam) == WA_INACTIVE &&
2019 QWidget::find((HWND)lParam) == 0) {
2020 // Another application was activated while our popups are open,
2021 // then close all popups. In case some popup refuses to close,
2022 // we give up after 1024 attempts (to avoid an infinite loop).
2023 int maxiter = 1024;
2024 QWidget *popup;
2025 while ((popup=QApplication::activePopupWidget()) && maxiter--)
2026 popup->close();
2027 }
2028
2029 if (LOWORD(wParam) != WA_INACTIVE) {
2030 // WM_ACTIVATEAPP handles the "true" false case, as this is only when the application
2031 // loses focus. Doing it here would result in the widget getting focus to not know
2032 // where it got it from; it would simply get a 0 value as the old focus widget.
2033#ifdef Q_WS_WINCE
2034 {
2035#ifdef Q_WS_WINCE_WM
2036 // On Windows mobile we do not receive WM_SYSCOMMAND / SC_MINIMIZE messages.
2037 // Thus we have to unset the minimized state explicitly. We must do this for all
2038 // top-level widgets, because we get the HWND of a random widget here.
2039 foreach (QWidget* tlw, QApplication::topLevelWidgets()) {
2040 if (tlw->isMinimized())
2041 tlw->setWindowState(tlw->windowState() & ~Qt::WindowMinimized);
2042 }
2043#else
2044 // On Windows CE we do not receive WM_SYSCOMMAND / SC_MINIMIZE messages.
2045 // Thus we have to unset the minimized state explicitly.
2046 if (widget->windowState() & Qt::WindowMinimized)
2047 widget->setWindowState(widget->windowState() & ~Qt::WindowMinimized);
2048#endif // Q_WS_WINCE_WM
2049
2050#else
2051 if (!(widget->windowState() & Qt::WindowMinimized)) {
2052#endif
2053 // Ignore the activate message send by WindowsXP to a minimized window
2054#ifdef Q_WS_WINCE_WM
2055 if (widget->windowState() & Qt::WindowFullScreen)
2056 qt_wince_hide_taskbar(widget->winId());
2057#endif
2058 qApp->winFocus(widget, true);
2059 // reset any window alert flashes
2060 alert_widget(widget, -1);
2061 }
2062 }
2063
2064 // Windows tries to activate a modally blocked window.
2065 // This happens when restoring an application after "Show Desktop"
2066 if (app_do_modal && LOWORD(wParam) == WA_ACTIVE) {
2067 QWidget *top = 0;
2068 if (!QApplicationPrivate::tryModalHelper(widget, &top) && top && widget != top) {
2069 if (top->isVisible()) {
2070 top->activateWindow();
2071 } else {
2072 // This is the case when native file dialogs are shown
2073 QWidget *p = (top->parentWidget() ? top->parentWidget()->window() : 0);
2074 if (p && p->isVisible())
2075 p->activateWindow();
2076 }
2077 }
2078 }
2079 break;
2080
2081#ifndef Q_WS_WINCE
2082 case WM_MOUSEACTIVATE:
2083 if (widget->window()->windowType() == Qt::Tool) {
2084 QWidget *w = widget;
2085 if (!w->window()->focusWidget()) {
2086 while (w && (w->focusPolicy() & Qt::ClickFocus) == 0) {
2087 if (w->isWindow()) {
2088 QWidget *fw = w;
2089 while ((fw = fw->nextInFocusChain()) != w && fw->focusPolicy() == Qt::NoFocus)
2090 ;
2091 if (fw != w)
2092 break;
2093 QWidget *pw = w->parentWidget();
2094 while (pw) {
2095 pw = pw->window();
2096 if (pw && pw->isVisible() && pw->focusWidget()) {
2097 Q_ASSERT(pw->testAttribute(Qt::WA_WState_Created));
2098 SetWindowPos(pw->internalWinId(), HWND_TOP, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
2099 break;
2100 }
2101 pw = pw->parentWidget();
2102 }
2103 RETURN(MA_NOACTIVATE);
2104 }
2105 w = w->parentWidget();
2106 }
2107 }
2108 }
2109 RETURN(MA_ACTIVATE);
2110 break;
2111#endif
2112 case WM_SHOWWINDOW:
2113 if (lParam == SW_PARENTOPENING) {
2114 if (widget->testAttribute(Qt::WA_WState_Hidden))
2115 RETURN(0);
2116 }
2117 if (widget->isWindow() && widget->testAttribute(Qt::WA_WState_Visible)
2118 && !widget->testWindowState(Qt::WindowMinimized)) {
2119 if (lParam == SW_PARENTOPENING) {
2120 QShowEvent e;
2121 qt_sendSpontaneousEvent(widget, &e);
2122 widget->showChildren(true);
2123 } else if (lParam == SW_PARENTCLOSING) {
2124 QHideEvent e;
2125 qt_sendSpontaneousEvent(widget, &e);
2126 widget->hideChildren(true);
2127 }
2128 }
2129 if (!wParam && autoCaptureWnd == widget->internalWinId())
2130 releaseAutoCapture();
2131 result = false;
2132 break;
2133
2134 case WM_PALETTECHANGED: // our window changed palette
2135 if (QColormap::hPal() && (WId)wParam == widget->internalWinId())
2136 RETURN(0); // otherwise: FALL THROUGH!
2137 // FALL THROUGH
2138 case WM_QUERYNEWPALETTE: // realize own palette
2139 if (QColormap::hPal()) {
2140 Q_ASSERT(widget->testAttribute(Qt::WA_WState_Created));
2141 HDC hdc = GetDC(widget->internalWinId());
2142 HPALETTE hpalOld = SelectPalette(hdc, QColormap::hPal(), FALSE);
2143 uint n = RealizePalette(hdc);
2144 if (n)
2145 InvalidateRect(widget->internalWinId(), 0, TRUE);
2146 SelectPalette(hdc, hpalOld, TRUE);
2147 RealizePalette(hdc);
2148 ReleaseDC(widget->internalWinId(), hdc);
2149 RETURN(n);
2150 }
2151 break;
2152 case WM_CLOSE: // close window
2153 widget->translateCloseEvent(msg);
2154 RETURN(0); // always handled
2155
2156 case WM_DESTROY: // destroy window
2157 if (hwnd == curWin) {
2158 QWidget *enter = QWidget::mouseGrabber();
2159 if (enter == widget)
2160 enter = 0;
2161 QApplicationPrivate::dispatchEnterLeave(enter, widget);
2162 curWin = enter ? enter->effectiveWinId() : 0;
2163 qt_last_mouse_receiver = enter;
2164 }
2165 if (widget == popupButtonFocus)
2166 popupButtonFocus = 0;
2167 result = false;
2168 break;
2169
2170#ifndef Q_WS_WINCE
2171 case WM_WINDOWPOSCHANGING:
2172 {
2173 result = false;
2174 if (widget->isWindow()) {
2175 WINDOWPOS *winPos = (WINDOWPOS *)lParam;
2176 if (widget->layout() && widget->layout()->hasHeightForWidth()
2177 && !(winPos->flags & (SWP_NOCOPYBITS | SWP_NOSIZE))) {
2178 QRect fs = widget->frameStrut();
2179 QRect rect = widget->geometry();
2180 QRect newRect = QRect(winPos->x + fs.left(),
2181 winPos->y + fs.top(),
2182 winPos->cx - fs.left() - fs.right(),
2183 winPos->cy - fs.top() - fs.bottom());
2184
2185 QSize newSize = QLayout::closestAcceptableSize(widget, newRect.size());
2186
2187 int dh = newSize.height() - newRect.height();
2188 int dw = newSize.width() - newRect.width();
2189 if (!dw && ! dh)
2190 break; // Size OK
2191
2192 if (rect.y() != newRect.y()) {
2193 newRect.setTop(newRect.top() - dh);
2194 } else {
2195 newRect.setBottom(newRect.bottom() + dh);
2196 }
2197
2198 if (rect.x() != newRect.x()) {
2199 newRect.setLeft(newRect.left() - dw);
2200 } else {
2201 newRect.setRight(newRect.right() + dw);
2202 }
2203
2204 winPos->x = newRect.x() - fs.left();
2205 winPos->y = newRect.y() - fs.top();
2206 winPos->cx = newRect.width() + fs.left() + fs.right();
2207 winPos->cy = newRect.height() + fs.top() + fs.bottom();
2208
2209 RETURN(0);
2210 }
2211 if (widget->windowFlags() & Qt::WindowStaysOnBottomHint) {
2212 winPos->hwndInsertAfter = HWND_BOTTOM;
2213 }
2214 }
2215 }
2216 break;
2217
2218 case WM_GETMINMAXINFO:
2219 if (widget->xtra()) {
2220 MINMAXINFO *mmi = (MINMAXINFO *)lParam;
2221 QWExtra *x = widget->xtra();
2222 QRect fs = widget->frameStrut();
2223 if ( x->minw > 0 )
2224 mmi->ptMinTrackSize.x = x->minw + fs.right() + fs.left();
2225 if ( x->minh > 0 )
2226 mmi->ptMinTrackSize.y = x->minh + fs.top() + fs.bottom();
2227 qint32 maxw = (x->maxw >= x->minw) ? x->maxw : x->minw;
2228 qint32 maxh = (x->maxh >= x->minh) ? x->maxh : x->minh;
2229 if ( maxw < QWIDGETSIZE_MAX ) {
2230 mmi->ptMaxTrackSize.x = maxw + fs.right() + fs.left();
2231 // windows with title bar have an implicit size limit of 112 pixels
2232 if (widget->windowFlags() & Qt::WindowTitleHint)
2233 mmi->ptMaxTrackSize.x = qMax<long>(mmi->ptMaxTrackSize.x, 112);
2234 }
2235 if ( maxh < QWIDGETSIZE_MAX )
2236 mmi->ptMaxTrackSize.y = maxh + fs.top() + fs.bottom();
2237 RETURN(0);
2238 }
2239 break;
2240
2241#ifndef QT_NO_CONTEXTMENU
2242 case WM_CONTEXTMENU:
2243 {
2244 // it's not VK_APPS or Shift+F10, but a click in the NC area
2245 if (lParam != (int)0xffffffff) {
2246 result = false;
2247 break;
2248 }
2249
2250 QWidget *fw = QWidget::keyboardGrabber();
2251 if (!fw) {
2252 if (QApplication::activePopupWidget())
2253 fw = (QApplication::activePopupWidget()->focusWidget()
2254 ? QApplication::activePopupWidget()->focusWidget()
2255 : QApplication::activePopupWidget());
2256 else if (QApplication::focusWidget())
2257 fw = QApplication::focusWidget();
2258 else if (widget)
2259 fw = widget->window();
2260 }
2261 if (fw && fw->isEnabled()) {
2262 QPoint pos = fw->inputMethodQuery(Qt::ImMicroFocus).toRect().center();
2263 QContextMenuEvent e(QContextMenuEvent::Keyboard, pos, fw->mapToGlobal(pos),
2264 qt_win_getKeyboardModifiers());
2265 result = qt_sendSpontaneousEvent(fw, &e);
2266 }
2267 }
2268 break;
2269#endif
2270#endif
2271
2272 case WM_IME_STARTCOMPOSITION:
2273 case WM_IME_ENDCOMPOSITION:
2274 case WM_IME_COMPOSITION: {
2275 QWidget *fw = QApplication::focusWidget();
2276 QWinInputContext *im = fw ? qobject_cast<QWinInputContext *>(fw->inputContext()) : 0;
2277 if (fw && im) {
2278 if(message == WM_IME_STARTCOMPOSITION)
2279 result = im->startComposition();
2280 else if (message == WM_IME_ENDCOMPOSITION)
2281 result = im->endComposition();
2282 else if (message == WM_IME_COMPOSITION)
2283 result = im->composition(lParam);
2284 }
2285 break;
2286 }
2287 case WM_IME_REQUEST: {
2288 QWidget *fw = QApplication::focusWidget();
2289 QWinInputContext *im = fw ? qobject_cast<QWinInputContext *>(fw->inputContext()) : 0;
2290 if (fw && im) {
2291 if(wParam == IMR_RECONVERTSTRING) {
2292 int ret = im->reconvertString((RECONVERTSTRING *)lParam);
2293 if (ret == -1) {
2294 result = false;
2295 } else {
2296 return ret;
2297 }
2298 } else if (wParam == IMR_CONFIRMRECONVERTSTRING) {
2299 RETURN(TRUE);
2300 } else {
2301 // in all other cases, call DefWindowProc()
2302 result = false;
2303 }
2304 }
2305 break;
2306 }
2307#ifndef Q_WS_WINCE
2308 case WM_CHANGECBCHAIN:
2309 case WM_DRAWCLIPBOARD:
2310#endif
2311 case WM_RENDERFORMAT:
2312 case WM_RENDERALLFORMATS:
2313#ifndef QT_NO_CLIPBOARD
2314 case WM_DESTROYCLIPBOARD:
2315 if (qt_clipboard) {
2316 QClipboardEvent e(reinterpret_cast<QEventPrivate *>(&msg));
2317 qt_sendSpontaneousEvent(qt_clipboard, &e);
2318 RETURN(0);
2319 }
2320 result = false;
2321 break;
2322#endif //QT_NO_CLIPBOARD
2323#ifndef QT_NO_ACCESSIBILITY
2324 case WM_GETOBJECT:
2325 {
2326 // Ignoring all requests while starting up
2327 if (QApplication::startingUp() || QApplication::closingDown() || (LONG)lParam != OBJID_CLIENT) {
2328 result = false;
2329 break;
2330 }
2331
2332 typedef LRESULT (WINAPI *PtrLresultFromObject)(REFIID, WPARAM, LPUNKNOWN);
2333 static PtrLresultFromObject ptrLresultFromObject = 0;
2334 static bool oleaccChecked = false;
2335
2336 if (!oleaccChecked) {
2337 oleaccChecked = true;
2338#if !defined(Q_OS_WINCE)
2339 ptrLresultFromObject = (PtrLresultFromObject)QSystemLibrary::resolve(QLatin1String("oleacc"), "LresultFromObject");
2340#endif
2341 }
2342 if (ptrLresultFromObject) {
2343 QAccessibleInterface *acc = QAccessible::queryAccessibleInterface(widget);
2344 if (!acc) {
2345 result = false;
2346 break;
2347 }
2348
2349 // and get an instance of the IAccessibile implementation
2350 IAccessible *iface = qt_createWindowsAccessible(acc);
2351 res = ptrLresultFromObject(IID_IAccessible, wParam, iface); // ref == 2
2352 iface->Release(); // the client will release the object again, and then it will destroy itself
2353
2354 if (res > 0)
2355 RETURN(res);
2356 }
2357 }
2358 result = false;
2359 break;
2360 case WM_GETTEXT:
2361 if (!widget->isWindow()) {
2362 int ret = 0;
2363 QAccessibleInterface *acc = QAccessible::queryAccessibleInterface(widget);
2364 if (acc) {
2365 QString text = acc->text(QAccessible::Name, 0);
2366 if (text.isEmpty())
2367 text = widget->objectName();
2368 ret = qMin<int>(wParam - 1, text.size());
2369 text.resize(ret);
2370 memcpy((void *)lParam, text.utf16(), (text.size() + 1) * sizeof(ushort));
2371 delete acc;
2372 }
2373 if (!ret) {
2374 result = false;
2375 break;
2376 }
2377 RETURN(ret);
2378 }
2379 result = false;
2380 break;
2381#endif
2382 case WT_PACKET:
2383 if (ptrWTPacketsGet) {
2384 if ((nPackets = ptrWTPacketsGet(qt_tablet_context, QT_TABLET_NPACKETQSIZE, &localPacketBuf))) {
2385 result = widget->translateTabletEvent(msg, localPacketBuf, nPackets);
2386 }
2387 }
2388 break;
2389 case WT_PROXIMITY:
2390
2391 #ifndef QT_NO_TABLETEVENT
2392 if (ptrWTPacketsGet && ptrWTInfo) {
2393 const bool enteredProximity = LOWORD(lParam) != 0;
2394 PACKET proximityBuffer[1]; // we are only interested in the first packet in this case
2395 const int totalPacks = ptrWTPacketsGet(qt_tablet_context, 1, proximityBuffer);
2396 if (totalPacks > 0) {
2397 const UINT currentCursor = proximityBuffer[0].pkCursor;
2398
2399 UINT csr_physid;
2400 ptrWTInfo(WTI_CURSORS + currentCursor, CSR_PHYSID, &csr_physid);
2401 UINT csr_type;
2402 ptrWTInfo(WTI_CURSORS + currentCursor, CSR_TYPE, &csr_type);
2403 const UINT deviceIdMask = 0xFF6; // device type mask && device color mask
2404 quint64 uniqueId = (csr_type & deviceIdMask);
2405 uniqueId = (uniqueId << 32) | csr_physid;
2406
2407 // initialising and updating the cursor should be done in response to
2408 // WT_CSRCHANGE. We do it in WT_PROXIMITY because some wintab never send
2409 // the event WT_CSRCHANGE even if asked with CXO_CSRMESSAGES
2410 const QTabletCursorInfo *const globalCursorInfo = tCursorInfo();
2411 if (!globalCursorInfo->contains(uniqueId))
2412 tabletInit(uniqueId, csr_type, qt_tablet_context);
2413
2414 currentTabletPointer = globalCursorInfo->value(uniqueId);
2415 tabletUpdateCursor(currentTabletPointer, currentCursor);
2416 }
2417 qt_tabletChokeMouse = false;
2418
2419 QTabletEvent tabletProximity(enteredProximity ? QEvent::TabletEnterProximity
2420 : QEvent::TabletLeaveProximity,
2421 QPoint(), QPoint(), QPointF(), currentTabletPointer.currentDevice, currentTabletPointer.currentPointerType, 0, 0,
2422 0, 0, 0, 0, 0, currentTabletPointer.llId);
2423 QApplication::sendEvent(qApp, &tabletProximity);
2424 }
2425 #endif // QT_NO_TABLETEVENT
2426
2427 break;
2428#ifdef Q_WS_WINCE_WM
2429 case WM_SETFOCUS: {
2430 HIMC hC;
2431 hC = ImmGetContext(hwnd);
2432 ImmSetOpenStatus(hC, TRUE);
2433 ImmEscape(NULL, hC, IME_ESC_SET_MODE, (LPVOID)IM_SPELL);
2434 result = false;
2435 }
2436 break;
2437#endif
2438 case WM_KILLFOCUS:
2439 if (!QWidget::find((HWND)wParam)) { // we don't get focus, so unset it now
2440 if (!widget->hasFocus()) // work around Windows bug after minimizing/restoring
2441 widget = (QETWidget*)QApplication::focusWidget();
2442 HWND focus = ::GetFocus();
2443 //if there is a current widget and the new widget belongs to the same toplevel window
2444 //or if the current widget was embedded into non-qt window (i.e. we won't get WM_ACTIVATEAPP)
2445 //then we clear the focus on the widget
2446 //in case the new widget belongs to a different widget hierarchy, clearing the focus
2447 //will be handled because the active window will change
2448 const bool embedded = widget && ((QETWidget*)widget->window())->topData()->embedded;
2449 if (widget && (embedded || ::IsChild(widget->window()->internalWinId(), focus))) {
2450 widget->clearFocus();
2451 result = true;
2452 } else {
2453 result = false;
2454 }
2455 } else {
2456 result = false;
2457 }
2458 break;
2459 case WM_THEMECHANGED:
2460 if ((widget->windowType() == Qt::Desktop) || !qApp || QApplication::closingDown()
2461 || QApplication::type() == QApplication::Tty)
2462 break;
2463
2464 if (widget->testAttribute(Qt::WA_WState_Polished))
2465 QApplication::style()->unpolish(widget);
2466
2467 if (widget->testAttribute(Qt::WA_WState_Polished))
2468 QApplication::style()->polish(widget);
2469 widget->repolishStyle(*QApplication::style());
2470 if (widget->isVisible())
2471 widget->update();
2472 break;
2473
2474#ifndef Q_WS_WINCE
2475 case WM_INPUTLANGCHANGE: {
2476 wchar_t info[7];
2477 if (!GetLocaleInfo(MAKELCID(lParam, SORT_DEFAULT), LOCALE_IDEFAULTANSICODEPAGE, info, 6)) {
2478 inputcharset = CP_ACP;
2479 } else {
2480 inputcharset = QString::fromWCharArray(info).toInt();
2481 }
2482 QKeyMapper::changeKeyboard();
2483 break;
2484 }
2485#else
2486 case WM_COMMAND: {
2487 bool OkCommand = (LOWORD(wParam) == 0x1);
2488 bool CancelCommand = (LOWORD(wParam) == 0x2);
2489 if (OkCommand)
2490 QApplication::postEvent(widget, new QEvent(QEvent::OkRequest));
2491 if (CancelCommand)
2492 widget->showMinimized();
2493 else
2494#ifndef QT_NO_MENUBAR
2495 QMenuBar::wceCommands(LOWORD(wParam));
2496#endif
2497 result = true;
2498 }
2499 break;
2500 case WM_HELP:
2501 QApplication::postEvent(widget, new QEvent(QEvent::HelpRequest));
2502 result = true;
2503 break;
2504#endif
2505
2506 case WM_MOUSELEAVE:
2507 // We receive a mouse leave for curWin, meaning
2508 // the mouse was moved outside our widgets
2509 if (widget->internalWinId() == curWin) {
2510 bool dispatch = !widget->underMouse();
2511 // hasMouse is updated when dispatching enter/leave,
2512 // so test if it is actually up-to-date
2513 if (!dispatch) {
2514 QRect geom = widget->geometry();
2515 if (widget->parentWidget() && !widget->isWindow()) {
2516 QPoint gp = widget->parentWidget()->mapToGlobal(widget->pos());
2517 geom.setX(gp.x());
2518 geom.setY(gp.y());
2519 }
2520 QPoint cpos = QCursor::pos();
2521 dispatch = !geom.contains(cpos);
2522 if ( !dispatch && !QWidget::mouseGrabber()) {
2523 QWidget *hittest = QApplication::widgetAt(cpos);
2524 dispatch = !hittest || hittest->internalWinId() != curWin;
2525 }
2526 if (!dispatch) {
2527 HRGN hrgn = qt_tryCreateRegion(QRegion::Rectangle, 0,0,0,0);
2528 if (GetWindowRgn(curWin, hrgn) != ERROR) {
2529 QPoint lcpos = widget->mapFromGlobal(cpos);
2530 dispatch = !PtInRegion(hrgn, lcpos.x(), lcpos.y());
2531 }
2532 DeleteObject(hrgn);
2533 }
2534 }
2535 if (dispatch) {
2536 if (qt_last_mouse_receiver && !qt_last_mouse_receiver->internalWinId())
2537 QApplicationPrivate::dispatchEnterLeave(0, qt_last_mouse_receiver);
2538 else
2539 QApplicationPrivate::dispatchEnterLeave(0, QWidget::find((WId)curWin));
2540 curWin = 0;
2541 qt_last_mouse_receiver = 0;
2542 }
2543 }
2544 break;
2545
2546 case WM_CANCELMODE:
2547 {
2548 // this goes through QMenuBar's event filter
2549 QEvent e(QEvent::ActivationChange);
2550 QApplication::sendEvent(qApp, &e);
2551 }
2552 break;
2553
2554 case WM_IME_NOTIFY:
2555 // special handling for ime, only for widgets in a popup
2556 if (wParam == IMN_OPENCANDIDATE) {
2557 imeParentWnd = hwnd;
2558 if (QApplication::activePopupWidget()) {
2559 // temporarily disable the mouse grab to allow mouse input in
2560 // the ime candidate window. The actual handle is untouched
2561 if (autoCaptureWnd)
2562 ReleaseCapture();
2563 }
2564 } else if (wParam == IMN_CLOSECANDIDATE) {
2565 imeParentWnd = 0;
2566 if (QApplication::activePopupWidget()) {
2567 // undo the action above, when candidate window is closed
2568 if (autoCaptureWnd)
2569 SetCapture(autoCaptureWnd);
2570 }
2571 }
2572 result = false;
2573 break;
2574#ifndef QT_NO_GESTURES
2575#if !defined(Q_WS_WINCE) || defined(QT_WINCE_GESTURES)
2576 case WM_GESTURE: {
2577 GESTUREINFO gi;
2578 memset(&gi, 0, sizeof(GESTUREINFO));
2579 gi.cbSize = sizeof(GESTUREINFO);
2580
2581 QApplicationPrivate *qAppPriv = QApplicationPrivate::instance();
2582 BOOL bResult = false;
2583 if (qAppPriv->GetGestureInfo)
2584 bResult = qAppPriv->GetGestureInfo((HANDLE)msg.lParam, &gi);
2585 if (bResult) {
2586 if (gi.dwID == GID_BEGIN) {
2587 // find the alien widget for the gesture position.
2588 // This might not be accurate as the position is the center
2589 // point of two fingers for multi-finger gestures.
2590 QPoint pt(gi.ptsLocation.x, gi.ptsLocation.y);
2591 QWidget *w = widget->childAt(widget->mapFromGlobal(pt));
2592 qAppPriv->gestureWidget = w ? w : widget;
2593 }
2594 if (qAppPriv->gestureWidget)
2595 static_cast<QETWidget*>(qAppPriv->gestureWidget)->translateGestureEvent(msg, gi);
2596 if (qAppPriv->CloseGestureInfoHandle)
2597 qAppPriv->CloseGestureInfoHandle((HANDLE)msg.lParam);
2598 if (gi.dwID == GID_END)
2599 qAppPriv->gestureWidget = 0;
2600 } else {
2601 DWORD dwErr = GetLastError();
2602 if (dwErr > 0)
2603 qWarning() << "translateGestureEvent: error = " << dwErr;
2604 }
2605 result = true;
2606 break;
2607 }
2608#endif // !defined(Q_WS_WINCE) || defined(QT_WINCE_GESTURES)
2609#endif // QT_NO_GESTURES
2610#ifndef QT_NO_CURSOR
2611 case WM_SETCURSOR: {
2612 QCursor *ovr = QApplication::overrideCursor();
2613 if (ovr) {
2614 SetCursor(ovr->handle());
2615 RETURN(TRUE);
2616 }
2617 result = false;
2618 break;
2619 }
2620#endif
2621 default:
2622 result = false; // event was not processed
2623 break;
2624 }
2625 }
2626
2627 if (evt_type != QEvent::None) { // simple event
2628 QEvent e(evt_type);
2629 result = qt_sendSpontaneousEvent(widget, &e);
2630 }
2631
2632 if (result)
2633 RETURN(false);
2634
2635do_default:
2636 RETURN(QWinInputContext::DefWindowProc(hwnd,message,wParam,lParam))
2637}
2638
2639
2640/*****************************************************************************
2641 Modal widgets; We have implemented our own modal widget mechanism
2642 to get total control.
2643 A modal widget without a parent becomes application-modal.
2644 A modal widget with a parent becomes modal to its parent and grandparents..
2645
2646 QApplicationPrivate::enterModal()
2647 Enters modal state
2648 Arguments:
2649 QWidget *widget A modal widget
2650
2651 QApplicationPrivate::leaveModal()
2652 Leaves modal state for a widget
2653 Arguments:
2654 QWidget *widget A modal widget
2655 *****************************************************************************/
2656
2657bool QApplicationPrivate::modalState()
2658{
2659 return app_do_modal;
2660}
2661
2662void QApplicationPrivate::enterModal_sys(QWidget *widget)
2663{
2664 if (!qt_modal_stack)
2665 qt_modal_stack = new QWidgetList;
2666
2667 releaseAutoCapture();
2668 ClipCursor(0);
2669 QWidget *leave = qt_last_mouse_receiver;
2670 if (!leave)
2671 leave = QWidget::find((WId)curWin);
2672 QApplicationPrivate::dispatchEnterLeave(0, leave);
2673 qt_modal_stack->insert(0, widget);
2674 app_do_modal = true;
2675 curWin = 0;
2676 qt_last_mouse_receiver = 0;
2677 qt_win_ignoreNextMouseReleaseEvent = false;
2678}
2679
2680void QApplicationPrivate::leaveModal_sys(QWidget *widget)
2681{
2682 if (qt_modal_stack && qt_modal_stack->removeAll(widget)) {
2683 if (qt_modal_stack->isEmpty()) {
2684 delete qt_modal_stack;
2685 qt_modal_stack = 0;
2686 QPoint p(QCursor::pos());
2687 app_do_modal = false; // necessary, we may get recursively into qt_try_modal below
2688 QWidget* w = QApplication::widgetAt(p.x(), p.y());
2689 QWidget *leave = qt_last_mouse_receiver;
2690 if (!leave)
2691 leave = QWidget::find((WId)curWin);
2692 if (QWidget *grabber = QWidget::mouseGrabber()) {
2693 w = grabber;
2694 if (leave == w)
2695 leave = 0;
2696 }
2697 QApplicationPrivate::dispatchEnterLeave(w, leave); // send synthetic enter event
2698 curWin = w ? w->effectiveWinId() : 0;
2699 qt_last_mouse_receiver = w;
2700 }
2701 qt_win_ignoreNextMouseReleaseEvent = true;
2702 }
2703 app_do_modal = qt_modal_stack != 0;
2704}
2705
2706bool qt_try_modal(QWidget *widget, MSG *msg, int& ret)
2707{
2708#if defined(Q_OS_WINCE)
2709 Q_UNUSED(ret);
2710#endif
2711 QWidget * top = 0;
2712
2713 if (QApplicationPrivate::tryModalHelper(widget, &top))
2714 return true;
2715
2716 int type = msg->message;
2717
2718 bool block_event = false;
2719#ifndef Q_WS_WINCE
2720 if (type != WM_NCHITTEST) {
2721#endif
2722 if ((type >= WM_MOUSEFIRST && type <= WM_MOUSELAST) ||
2723 type == WM_MOUSEWHEEL || type == WM_MOUSEHWHEEL ||
2724 type == WM_MOUSELEAVE ||
2725 (type >= WM_KEYFIRST && type <= WM_KEYLAST)
2726#ifndef Q_WS_WINCE
2727 || type == WM_NCMOUSEMOVE
2728#endif
2729 ) {
2730 if (type == WM_MOUSEMOVE
2731#ifndef Q_WS_WINCE
2732 || type == WM_NCMOUSEMOVE
2733#endif
2734 ) {
2735#ifndef QT_NO_CURSOR
2736 QCursor *c = qt_grab_cursor();
2737 if (!c)
2738 c = QApplication::overrideCursor();
2739 if (c) // application cursor defined
2740 SetCursor(c->handle());
2741 else
2742 SetCursor(QCursor(Qt::ArrowCursor).handle());
2743#endif // QT_NO_CURSOR
2744 }
2745 block_event = true;
2746 } else if (type == WM_CLOSE) {
2747 block_event = true;
2748 }
2749#ifndef Q_WS_WINCE
2750 else if (type == WM_MOUSEACTIVATE || type == WM_NCLBUTTONDOWN){
2751 if (!top->isActiveWindow()) {
2752 top->activateWindow();
2753 } else {
2754 QApplication::beep();
2755 }
2756 block_event = true;
2757 ret = MA_NOACTIVATEANDEAT;
2758 } else if (type == WM_SYSCOMMAND) {
2759 if (!(msg->wParam == SC_RESTORE && widget->isMinimized()))
2760 block_event = true;
2761 }
2762 }
2763#endif
2764
2765 return !block_event;
2766}
2767
2768
2769/*****************************************************************************
2770 Popup widget mechanism
2771
2772 openPopup()
2773 Adds a widget to the list of popup widgets
2774 Arguments:
2775 QWidget *widget The popup widget to be added
2776
2777 closePopup()
2778 Removes a widget from the list of popup widgets
2779 Arguments:
2780 QWidget *widget The popup widget to be removed
2781 *****************************************************************************/
2782
2783void QApplicationPrivate::openPopup(QWidget *popup)
2784{
2785 if (!QApplicationPrivate::popupWidgets)
2786 QApplicationPrivate::popupWidgets = new QWidgetList;
2787 QApplicationPrivate::popupWidgets->append(popup);
2788 if (!popup->isEnabled())
2789 return;
2790
2791 // close any opened 'ime candidate window'
2792 if (imeParentWnd)
2793 ::SendMessage(imeParentWnd, WM_IME_ENDCOMPOSITION, 0, 0);
2794
2795 if (QApplicationPrivate::popupWidgets->count() == 1 && !qt_nograb()) {
2796 Q_ASSERT(popup->testAttribute(Qt::WA_WState_Created));
2797 setAutoCapture(popup->internalWinId()); // grab mouse/keyboard
2798 }
2799 // Popups are not focus-handled by the window system (the first
2800 // popup grabbed the keyboard), so we have to do that manually: A
2801 // new popup gets the focus
2802 if (popup->focusWidget()) {
2803 popup->focusWidget()->setFocus(Qt::PopupFocusReason);
2804 } else if (QApplicationPrivate::popupWidgets->count() == 1) { // this was the first popup
2805 if (QWidget *fw = QApplication::focusWidget()) {
2806 QFocusEvent e(QEvent::FocusOut, Qt::PopupFocusReason);
2807 QApplication::sendEvent(fw, &e);
2808 }
2809 }
2810}
2811
2812void QApplicationPrivate::closePopup(QWidget *popup)
2813{
2814 if (!QApplicationPrivate::popupWidgets)
2815 return;
2816 QApplicationPrivate::popupWidgets->removeAll(popup);
2817 POINT curPos;
2818 GetCursorPos(&curPos);
2819
2820 // close any opened 'ime candidate window'
2821 if (imeParentWnd)
2822 ::SendMessage(imeParentWnd, WM_IME_ENDCOMPOSITION, 0, 0);
2823
2824 if (QApplicationPrivate::popupWidgets->isEmpty()) { // this was the last popup
2825 delete QApplicationPrivate::popupWidgets;
2826 QApplicationPrivate::popupWidgets = 0;
2827 replayPopupMouseEvent = (!popup->geometry().contains(QPoint(curPos.x, curPos.y))
2828 && !popup->testAttribute(Qt::WA_NoMouseReplay));
2829 if (!popup->isEnabled())
2830 return;
2831 if (!qt_nograb()) // grabbing not disabled
2832 releaseAutoCapture();
2833 QWidget *fw = QApplicationPrivate::active_window ? QApplicationPrivate::active_window->focusWidget()
2834 : QApplication::focusWidget();
2835 if (fw) {
2836 if (fw != QApplication::focusWidget()) {
2837 fw->setFocus(Qt::PopupFocusReason);
2838 } else {
2839 QFocusEvent e(QEvent::FocusIn, Qt::PopupFocusReason);
2840 QApplication::sendEvent(fw, &e);
2841 }
2842 }
2843 } else {
2844 // Popups are not focus-handled by the window system (the
2845 // first popup grabbed the keyboard), so we have to do that
2846 // manually: A popup was closed, so the previous popup gets
2847 // the focus.
2848 QWidget* aw = QApplicationPrivate::popupWidgets->last();
2849 if (QApplicationPrivate::popupWidgets->count() == 1) {
2850 Q_ASSERT(aw->testAttribute(Qt::WA_WState_Created));
2851 setAutoCapture(aw->internalWinId());
2852 }
2853 if (QWidget *fw = aw->focusWidget())
2854 fw->setFocus(Qt::PopupFocusReason);
2855 }
2856}
2857
2858
2859
2860
2861/*****************************************************************************
2862 Event translation; translates Windows events to Qt events
2863 *****************************************************************************/
2864
2865//
2866// Auto-capturing for mouse press and mouse release
2867//
2868
2869static void setAutoCapture(HWND h)
2870{
2871 if (autoCaptureWnd)
2872 releaseAutoCapture();
2873 autoCaptureWnd = h;
2874 SetCapture(h);
2875}
2876
2877static void releaseAutoCapture()
2878{
2879 if (autoCaptureWnd) {
2880 ReleaseCapture();
2881 autoCaptureWnd = 0;
2882 }
2883}
2884
2885
2886//
2887// Mouse event translation
2888//
2889// Non-client mouse messages are not translated
2890//
2891
2892static const ushort mouseTbl[] = {
2893 WM_MOUSEMOVE, QEvent::MouseMove, 0,
2894 WM_LBUTTONDOWN, QEvent::MouseButtonPress, Qt::LeftButton,
2895 WM_LBUTTONUP, QEvent::MouseButtonRelease, Qt::LeftButton,
2896 WM_LBUTTONDBLCLK, QEvent::MouseButtonDblClick, Qt::LeftButton,
2897 WM_RBUTTONDOWN, QEvent::MouseButtonPress, Qt::RightButton,
2898 WM_RBUTTONUP, QEvent::MouseButtonRelease, Qt::RightButton,
2899 WM_RBUTTONDBLCLK, QEvent::MouseButtonDblClick, Qt::RightButton,
2900 WM_MBUTTONDOWN, QEvent::MouseButtonPress, Qt::MidButton,
2901 WM_MBUTTONUP, QEvent::MouseButtonRelease, Qt::MidButton,
2902 WM_MBUTTONDBLCLK, QEvent::MouseButtonDblClick, Qt::MidButton,
2903 // use XButton1 for now, the real X button is decided later
2904 WM_XBUTTONDOWN, QEvent::MouseButtonPress, Qt::XButton1,
2905 WM_XBUTTONUP, QEvent::MouseButtonRelease, Qt::XButton1,
2906 WM_XBUTTONDBLCLK, QEvent::MouseButtonDblClick, Qt::XButton1,
2907
2908#ifndef Q_WS_WINCE
2909 WM_NCMOUSEMOVE, QEvent::NonClientAreaMouseMove, 0,
2910 WM_NCLBUTTONDOWN, QEvent::NonClientAreaMouseButtonPress, Qt::LeftButton,
2911 WM_NCLBUTTONUP, QEvent::NonClientAreaMouseButtonRelease, Qt::LeftButton,
2912 WM_NCLBUTTONDBLCLK, QEvent::NonClientAreaMouseButtonDblClick, Qt::LeftButton,
2913 WM_NCRBUTTONDOWN, QEvent::NonClientAreaMouseButtonPress, Qt::RightButton,
2914 WM_NCRBUTTONUP, QEvent::NonClientAreaMouseButtonRelease, Qt::RightButton,
2915 WM_NCRBUTTONDBLCLK, QEvent::NonClientAreaMouseButtonDblClick, Qt::RightButton,
2916 WM_NCMBUTTONDOWN, QEvent::NonClientAreaMouseButtonPress, Qt::MidButton,
2917 WM_NCMBUTTONUP, QEvent::NonClientAreaMouseButtonRelease, Qt::MidButton,
2918 WM_NCMBUTTONDBLCLK, QEvent::NonClientAreaMouseButtonDblClick, Qt::MidButton,
2919#endif
2920
2921 0, 0, 0
2922};
2923
2924static int translateButtonState(int s, int type, int button)
2925{
2926 Q_UNUSED(type);
2927 Q_UNUSED(button);
2928 int bst = 0;
2929 if (s & MK_LBUTTON)
2930 bst |= Qt::LeftButton;
2931 if (s & MK_MBUTTON)
2932 bst |= Qt::MidButton;
2933 if (s & MK_RBUTTON)
2934 bst |= Qt::RightButton;
2935 if (s & MK_SHIFT)
2936 bst |= Qt::ShiftModifier;
2937 if (s & MK_CONTROL)
2938 bst |= Qt::ControlModifier;
2939
2940 if (s & MK_XBUTTON1)
2941 bst |= Qt::XButton1;
2942 if (s & MK_XBUTTON2)
2943 bst |= Qt::XButton2;
2944
2945 if (GetKeyState(VK_MENU) < 0)
2946 bst |= Qt::AltModifier;
2947
2948 if ((GetKeyState(VK_LWIN) < 0) ||
2949 (GetKeyState(VK_RWIN) < 0))
2950 bst |= Qt::MetaModifier;
2951
2952 return bst;
2953}
2954
2955void qt_win_eatMouseMove()
2956{
2957 // after closing a windows dialog with a double click (i.e. open a file)
2958 // the message queue still contains a dubious WM_MOUSEMOVE message where
2959 // the left button is reported to be down (wParam != 0).
2960 // remove all those messages (usually 1) and post the last one with a
2961 // reset button state
2962
2963 MSG msg = {0, 0, 0, 0, 0, {0, 0} };
2964 while (PeekMessage(&msg, 0, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_REMOVE))
2965 ;
2966 if (msg.message == WM_MOUSEMOVE)
2967 PostMessage(msg.hwnd, msg.message, 0, msg.lParam);
2968}
2969
2970// In DnD, the mouse release event never appears, so the
2971// mouse button state machine must be manually reset
2972void QApplication::winMouseButtonUp()
2973{
2974 qt_button_down = 0;
2975 releaseAutoCapture();
2976}
2977
2978void QETWidget::repolishStyle(QStyle &)
2979{
2980 QEvent e(QEvent::StyleChange);
2981 QApplication::sendEvent(this, &e);
2982}
2983
2984bool QETWidget::translateMouseEvent(const MSG &msg)
2985{
2986 if (!isWindow() && testAttribute(Qt::WA_NativeWindow))
2987 Q_ASSERT(internalWinId());
2988
2989 static QPoint pos;
2990 static POINT gpos={-1,-1};
2991 QEvent::Type type; // event parameters
2992 int button;
2993 int state;
2994 int i;
2995
2996 if (sm_blockUserInput) //block user interaction during session management
2997 return true;
2998
2999 // Compress mouse move events
3000 if (msg.message == WM_MOUSEMOVE) {
3001 MSG mouseMsg;
3002 while (PeekMessage(&mouseMsg, msg.hwnd, WM_MOUSEFIRST,
3003 WM_MOUSELAST, PM_NOREMOVE)) {
3004 if (mouseMsg.message == WM_MOUSEMOVE) {
3005#define PEEKMESSAGE_IS_BROKEN 1
3006#ifdef PEEKMESSAGE_IS_BROKEN
3007 // Since the Windows PeekMessage() function doesn't
3008 // correctly return the wParam for WM_MOUSEMOVE events
3009 // if there is a key release event in the queue
3010 // _before_ the mouse event, we have to also consider
3011 // key release events (kls 2003-05-13):
3012 MSG keyMsg;
3013 bool done = false;
3014 while (PeekMessage(&keyMsg, 0, WM_KEYFIRST, WM_KEYLAST,
3015 PM_NOREMOVE)) {
3016 if (keyMsg.time < mouseMsg.time) {
3017 if ((keyMsg.lParam & 0xC0000000) == 0x40000000) {
3018 PeekMessage(&keyMsg, 0, keyMsg.message,
3019 keyMsg.message, PM_REMOVE);
3020 } else {
3021 done = true;
3022 break;
3023 }
3024 } else {
3025 break; // no key event before the WM_MOUSEMOVE event
3026 }
3027 }
3028 if (done)
3029 break;
3030#else
3031 // Actually the following 'if' should work instead of
3032 // the above key event checking, but apparently
3033 // PeekMessage() is broken :-(
3034 if (mouseMsg.wParam != msg.wParam)
3035 break; // leave the message in the queue because
3036 // the key state has changed
3037#endif
3038 MSG *msgPtr = (MSG *)(&msg);
3039 // Update the passed in MSG structure with the
3040 // most recent one.
3041 msgPtr->lParam = mouseMsg.lParam;
3042 msgPtr->wParam = mouseMsg.wParam;
3043 // Extract the x,y coordinates from the lParam as we do in the WndProc
3044 msgPtr->pt.x = GET_X_LPARAM(mouseMsg.lParam);
3045 msgPtr->pt.y = GET_Y_LPARAM(mouseMsg.lParam);
3046 ClientToScreen(msg.hwnd, &(msgPtr->pt));
3047 // Remove the mouse move message
3048 PeekMessage(&mouseMsg, msg.hwnd, WM_MOUSEMOVE,
3049 WM_MOUSEMOVE, PM_REMOVE);
3050 } else {
3051 break; // there was no more WM_MOUSEMOVE event
3052 }
3053 }
3054 }
3055
3056 for (i=0; (UINT)mouseTbl[i] != msg.message && mouseTbl[i]; i += 3)
3057 ;
3058 if (!mouseTbl[i])
3059 return false;
3060 type = (QEvent::Type)mouseTbl[++i]; // event type
3061 button = mouseTbl[++i]; // which button
3062 if (button == Qt::XButton1) {
3063 switch(GET_XBUTTON_WPARAM(msg.wParam)) {
3064 case XBUTTON1:
3065 button = Qt::XButton1;
3066 break;
3067 case XBUTTON2:
3068 button = Qt::XButton2;
3069 break;
3070 }
3071 }
3072#ifndef Q_OS_WINCE
3073 static bool trackMouseEventLookup = false;
3074 typedef BOOL (WINAPI *PtrTrackMouseEvent)(LPTRACKMOUSEEVENT);
3075 static PtrTrackMouseEvent ptrTrackMouseEvent = 0;
3076#endif
3077 state = translateButtonState(msg.wParam, type, button); // button state
3078 const QPoint widgetPos = mapFromGlobal(QPoint(msg.pt.x, msg.pt.y));
3079 QWidget *alienWidget = !internalWinId() ? this : childAt(widgetPos);
3080 if (alienWidget && alienWidget->internalWinId())
3081 alienWidget = 0;
3082
3083 if (type == QEvent::MouseMove || type == QEvent::NonClientAreaMouseMove
3084 || type == QEvent::TabletMove) {
3085
3086 if (!(state & Qt::MouseButtonMask))
3087 qt_button_down = 0;
3088#ifndef QT_NO_CURSOR
3089 QCursor *c = qt_grab_cursor();
3090 if (!c)
3091 c = QApplication::overrideCursor();
3092 if (c) // application cursor defined
3093 SetCursor(c->handle());
3094 else if (type != QEvent::NonClientAreaMouseMove && !qt_button_down) {
3095 // use widget cursor if widget is enabled
3096 QWidget *w = alienWidget ? alienWidget : this;
3097 while (!w->isWindow() && !w->isEnabled())
3098 w = w->parentWidget();
3099 SetCursor(w->cursor().handle());
3100 }
3101#endif // QT_NO_CURSOR
3102
3103 HWND id = effectiveWinId();
3104 QWidget *mouseGrabber = QWidget::mouseGrabber();
3105 QWidget *activePopupWidget = QApplication::activePopupWidget();
3106 if (mouseGrabber) {
3107 if (!activePopupWidget || (activePopupWidget == this && !rect().contains(widgetPos)))
3108 id = mouseGrabber->effectiveWinId();
3109 } else if (type == QEvent::NonClientAreaMouseMove) {
3110 id = 0;
3111 }
3112
3113 if (curWin != id) { // new current window
3114 if (id == 0) {
3115 QWidget *leave = qt_last_mouse_receiver;
3116 if (!leave)
3117 leave = QWidget::find(curWin);
3118 QApplicationPrivate::dispatchEnterLeave(0, leave);
3119 qt_last_mouse_receiver = 0;
3120 curWin = 0;
3121 } else {
3122 QWidget *leave = 0;
3123 if (curWin && qt_last_mouse_receiver)
3124 leave = qt_last_mouse_receiver;
3125 else
3126 leave = QWidget::find(curWin);
3127 QWidget *enter = alienWidget ? alienWidget : this;
3128 if (mouseGrabber && activePopupWidget) {
3129 if (leave != mouseGrabber)
3130 enter = mouseGrabber;
3131 else
3132 enter = activePopupWidget == this ? this : mouseGrabber;
3133 }
3134 QApplicationPrivate::dispatchEnterLeave(enter, leave);
3135 qt_last_mouse_receiver = enter;
3136 curWin = enter ? enter->effectiveWinId() : 0;
3137 }
3138#ifndef Q_OS_WINCE
3139
3140 if (curWin != 0) {
3141 if (!trackMouseEventLookup) {
3142 trackMouseEventLookup = true;
3143 ptrTrackMouseEvent = (PtrTrackMouseEvent)QSystemLibrary::resolve(QLatin1String("comctl32"), "_TrackMouseEvent");
3144 }
3145 if (ptrTrackMouseEvent && !qApp->d_func()->inPopupMode()) {
3146 // We always have to set the tracking, since
3147 // Windows detects more leaves than we do..
3148 TRACKMOUSEEVENT tme;
3149 tme.cbSize = sizeof(TRACKMOUSEEVENT);
3150 tme.dwFlags = 0x00000002; // TME_LEAVE
3151 tme.hwndTrack = curWin; // Track on window receiving msgs
3152 tme.dwHoverTime = (DWORD)-1; // HOVER_DEFAULT
3153 ptrTrackMouseEvent(&tme);
3154 }
3155 }
3156#endif // Q_OS_WINCE
3157 }
3158
3159 POINT curPos = msg.pt;
3160 if (curPos.x == gpos.x && curPos.y == gpos.y)
3161 return true; // same global position
3162 gpos = curPos;
3163
3164 Q_ASSERT(testAttribute(Qt::WA_WState_Created));
3165 ScreenToClient(internalWinId(), &curPos);
3166
3167 pos.rx() = curPos.x;
3168 pos.ry() = curPos.y;
3169 pos = d_func()->mapFromWS(pos);
3170 } else {
3171 gpos = msg.pt;
3172 pos = mapFromGlobal(QPoint(gpos.x, gpos.y));
3173
3174 // mouse button pressed
3175 if (!qt_button_down && (type == QEvent::MouseButtonPress || type == QEvent::MouseButtonDblClick)) {
3176 QWidget *tlw = window();
3177 if (QWidget *child = tlw->childAt(mapTo(tlw, pos)))
3178 qt_button_down = child;
3179 else
3180 qt_button_down = this;
3181 }
3182 }
3183
3184 bool res = false;
3185
3186 bool nonClientAreaEvent = type >= QEvent::NonClientAreaMouseMove
3187 && type <= QEvent::NonClientAreaMouseButtonDblClick;
3188
3189 if (qApp->d_func()->inPopupMode()) { // in popup mode
3190
3191 if (nonClientAreaEvent)
3192 return false;
3193
3194 replayPopupMouseEvent = false;
3195 QWidget* activePopupWidget = QApplication::activePopupWidget();
3196 QWidget *target = activePopupWidget;
3197 const QPoint globalPos(gpos.x, gpos.y);
3198
3199 if (target != this) {
3200 if ((windowType() == Qt::Popup) && rect().contains(pos) && 0)
3201 target = this;
3202 else // send to last popup
3203 pos = target->mapFromGlobal(globalPos);
3204 }
3205 QWidget *popupChild = target->childAt(pos);
3206 bool releaseAfter = false;
3207 switch (type) {
3208 case QEvent::MouseButtonPress:
3209 case QEvent::MouseButtonDblClick:
3210 popupButtonFocus = popupChild;
3211 break;
3212 case QEvent::MouseButtonRelease:
3213 case QEvent::TabletRelease:
3214
3215 releaseAfter = true;
3216 break;
3217 default:
3218 break; // nothing for mouse move
3219 }
3220
3221 if (target->isEnabled()) {
3222 if (popupButtonFocus) {
3223 target = popupButtonFocus;
3224 } else if (popupChild) {
3225 target = popupChild;
3226 }
3227
3228 pos = target->mapFromGlobal(globalPos);
3229 QMouseEvent e(type, pos, globalPos,
3230 Qt::MouseButton(button),
3231 Qt::MouseButtons(state & Qt::MouseButtonMask),
3232 Qt::KeyboardModifiers(state & Qt::KeyboardModifierMask));
3233 res = QApplicationPrivate::sendMouseEvent(target, &e, alienWidget, this, &qt_button_down,
3234 qt_last_mouse_receiver);
3235 res = res && e.isAccepted();
3236 } else {
3237 // close disabled popups when a mouse button is pressed or released
3238 switch (type) {
3239 case QEvent::MouseButtonPress:
3240 case QEvent::MouseButtonDblClick:
3241 case QEvent::MouseButtonRelease:
3242 target->close();
3243 break;
3244 default:
3245 break;
3246 }
3247 }
3248
3249 if (releaseAfter) {
3250 popupButtonFocus = 0;
3251 qt_button_down = 0;
3252 }
3253
3254#ifndef Q_OS_WINCE
3255 if (type == QEvent::MouseButtonPress
3256 && QApplication::activePopupWidget() != activePopupWidget
3257 && ptrTrackMouseEvent
3258 && curWin) {
3259 // Since curWin is already the window we clicked on,
3260 // we have to setup the mouse tracking here.
3261 TRACKMOUSEEVENT tme;
3262 tme.cbSize = sizeof(TRACKMOUSEEVENT);
3263 tme.dwFlags = 0x00000002; // TME_LEAVE
3264 tme.hwndTrack = curWin; // Track on window receiving msgs
3265 tme.dwHoverTime = (DWORD)-1; // HOVER_DEFAULT
3266 ptrTrackMouseEvent(&tme);
3267 }
3268#endif
3269 if (type == QEvent::MouseButtonPress
3270 && QApplication::activePopupWidget() != activePopupWidget
3271 && replayPopupMouseEvent) {
3272 // the popup disappeared. Replay the event
3273 QWidget* w = QApplication::widgetAt(gpos.x, gpos.y);
3274 if (w && !QApplicationPrivate::isBlockedByModal(w)) {
3275 Q_ASSERT(w->testAttribute(Qt::WA_WState_Created));
3276 HWND hwndTarget = w->effectiveWinId();
3277 if (QWidget::mouseGrabber() == 0)
3278 setAutoCapture(hwndTarget);
3279 if (!w->isActiveWindow())
3280 w->activateWindow();
3281 POINT widgetpt = gpos;
3282 ScreenToClient(hwndTarget, &widgetpt);
3283 LPARAM lParam = MAKELPARAM(widgetpt.x, widgetpt.y);
3284 PostMessage(hwndTarget, msg.message, msg.wParam, lParam);
3285 }
3286 } else if (type == QEvent::MouseButtonRelease && button == Qt::RightButton
3287 && QApplication::activePopupWidget() == activePopupWidget) {
3288 // popup still alive and received right-button-release
3289#if !defined(QT_NO_CONTEXTMENU)
3290 QContextMenuEvent e2(QContextMenuEvent::Mouse, pos, globalPos,
3291 qt_win_getKeyboardModifiers());
3292 bool res2 = QApplication::sendSpontaneousEvent( target, &e2 );
3293 if (!res) // RMB not accepted
3294 res = res2 && e2.isAccepted();
3295#endif
3296 }
3297 } else { // not popup mode
3298 int bs = state & Qt::MouseButtonMask;
3299 if ((type == QEvent::MouseButtonPress ||
3300 type == QEvent::MouseButtonDblClick) && bs == button) {
3301 Q_ASSERT(testAttribute(Qt::WA_WState_Created));
3302 if (QWidget::mouseGrabber() == 0)
3303 setAutoCapture(internalWinId());
3304 } else if (type == QEvent::MouseButtonRelease && bs == 0) {
3305 if (QWidget::mouseGrabber() == 0)
3306 releaseAutoCapture();
3307 }
3308
3309 const QPoint globalPos(gpos.x,gpos.y);
3310 QWidget *widget = QApplicationPrivate::pickMouseReceiver(this, globalPos, pos, type,
3311 Qt::MouseButtons(bs),
3312 qt_button_down, alienWidget);
3313 if (!widget)
3314 return false; // don't send event
3315
3316 QMouseEvent e(type, pos, globalPos, Qt::MouseButton(button),
3317 Qt::MouseButtons(state & Qt::MouseButtonMask),
3318 Qt::KeyboardModifiers(state & Qt::KeyboardModifierMask));
3319
3320 res = QApplicationPrivate::sendMouseEvent(widget, &e, alienWidget, this, &qt_button_down,
3321 qt_last_mouse_receiver);
3322
3323 // non client area events are only informational, you cannot "handle" them
3324 res = res && e.isAccepted() && !nonClientAreaEvent;
3325#if !defined(QT_NO_CONTEXTMENU)
3326 if (type == QEvent::MouseButtonRelease && button == Qt::RightButton) {
3327 QContextMenuEvent e2(QContextMenuEvent::Mouse, pos, globalPos,
3328 qt_win_getKeyboardModifiers());
3329 bool res2 = QApplication::sendSpontaneousEvent(widget, &e2);
3330 if (!res)
3331 res = res2 && e2.isAccepted();
3332 }
3333#endif
3334
3335 if (type != QEvent::MouseMove)
3336 pos.rx() = pos.ry() = -9999; // init for move compression
3337 }
3338 return res;
3339}
3340
3341bool QETWidget::translateWheelEvent(const MSG &msg)
3342{
3343 int state = 0;
3344
3345 if (sm_blockUserInput) // block user interaction during session management
3346 return true;
3347
3348 state = translateButtonState(GET_KEYSTATE_WPARAM(msg.wParam), 0, 0);
3349
3350 int delta;
3351 if (msg.message == WM_MOUSEWHEEL || msg.message == WM_MOUSEHWHEEL)
3352 delta = (short) HIWORD (msg.wParam);
3353 else
3354 delta = (int) msg.wParam;
3355
3356 Qt::Orientation orient = (msg.message == WM_MOUSEHWHEEL || state&Qt::AltModifier
3357#if 0
3358 // disabled for now - Trenton's one-wheel mouse makes trouble...
3359 // "delta" for usual wheels is +-120. +-240 seems to indicate
3360 // the second wheel see more recent MSDN for WM_MOUSEWHEEL
3361
3362 ( // <- parantheses added to make update happy, remove if the
3363 // #if 0 is removed
3364 || delta == 240 || delta == -240)?Qt::Horizontal:Vertical;
3365 if (delta == 240 || delta == -240)
3366 delta /= 2;
3367#endif
3368 ) ? Qt::Horizontal : Qt::Vertical;
3369
3370 // according to the MSDN documentation on WM_MOUSEHWHEEL:
3371 // a positive value indicates that the wheel was rotated to the right;
3372 // a negative value indicates that the wheel was rotated to the left.
3373 // Qt defines this value as the exact opposite, so we have to flip the value!
3374 if (msg.message == WM_MOUSEHWHEEL)
3375 delta = -delta;
3376
3377 QPoint globalPos;
3378
3379 globalPos.rx() = (short)LOWORD (msg.lParam);
3380 globalPos.ry() = (short)HIWORD (msg.lParam);
3381
3382
3383 // if there is a widget under the mouse and it is not shadowed
3384 // by modality, we send the event to it first
3385 int ret = 0;
3386 QWidget* w = QApplication::widgetAt(globalPos);
3387 if (!w || !qt_try_modal(w, (MSG*)&msg, ret)) {
3388 //synaptics touchpad shows its own widget at this position
3389 //so widgetAt() will fail with that HWND, try child of this widget
3390 w = this->childAt(this->mapFromGlobal(globalPos));
3391 if (!w)
3392 w = this;
3393 }
3394
3395 // send the event to the widget or its ancestors
3396 {
3397 QWidget* popup = QApplication::activePopupWidget();
3398 if (popup && w->window() != popup)
3399 popup->close();
3400#ifndef QT_NO_WHEELEVENT
3401 QWheelEvent e(w->mapFromGlobal(globalPos), globalPos, delta,
3402 Qt::MouseButtons(state & Qt::MouseButtonMask),
3403 Qt::KeyboardModifier(state & Qt::KeyboardModifierMask), orient);
3404
3405 if (QApplication::sendSpontaneousEvent(w, &e))
3406#else
3407 Q_UNUSED(orient);
3408#endif //QT_NO_WHEELEVENT
3409 return true;
3410 }
3411
3412 // send the event to the widget that has the focus or its ancestors, if different
3413 if (w != QApplication::focusWidget() && (w = QApplication::focusWidget())) {
3414 QWidget* popup = QApplication::activePopupWidget();
3415 if (popup && w->window() != popup)
3416 popup->close();
3417#ifndef QT_NO_WHEELEVENT
3418 QWheelEvent e(w->mapFromGlobal(globalPos), globalPos, delta,
3419 Qt::MouseButtons(state & Qt::MouseButtonMask),
3420 Qt::KeyboardModifier(state & Qt::KeyboardModifierMask), orient);
3421 if (QApplication::sendSpontaneousEvent(w, &e))
3422#endif //QT_NO_WHEELEVENT
3423 return true;
3424 }
3425 return false;
3426}
3427
3428
3429//
3430// Windows Wintab to QTabletEvent translation
3431//
3432
3433// the following is adapted from the wintab syspress example (public domain)
3434/* -------------------------------------------------------------------------- */
3435// Initialize the "static" information of a cursor device (pen, airbrush, etc).
3436// The QTabletDeviceData is initialized with the data that do not change in time
3437// (number of button, type of device, etc) but do not initialize the variable data
3438// (e.g.: pen or eraser)
3439#ifndef QT_NO_TABLETEVENT
3440
3441static void tabletInit(const quint64 uniqueId, const UINT csr_type, HCTX hTab)
3442{
3443 Q_ASSERT(ptrWTInfo);
3444 Q_ASSERT(ptrWTGet);
3445
3446 Q_ASSERT(!tCursorInfo()->contains(uniqueId));
3447
3448 /* browse WinTab's many info items to discover pressure handling. */
3449 AXIS np;
3450 LOGCONTEXT lc;
3451
3452 /* get the current context for its device variable. */
3453 ptrWTGet(hTab, &lc);
3454
3455 /* get the size of the pressure axis. */
3456 QTabletDeviceData tdd;
3457 tdd.llId = uniqueId;
3458
3459 ptrWTInfo(WTI_DEVICES + lc.lcDevice, DVC_NPRESSURE, &np);
3460 tdd.minPressure = int(np.axMin);
3461 tdd.maxPressure = int(np.axMax);
3462
3463 ptrWTInfo(WTI_DEVICES + lc.lcDevice, DVC_TPRESSURE, &np);
3464 tdd.minTanPressure = int(np.axMin);
3465 tdd.maxTanPressure = int(np.axMax);
3466
3467 LOGCONTEXT lcMine;
3468
3469 /* get default region */
3470 ptrWTInfo(WTI_DEFCONTEXT, 0, &lcMine);
3471
3472 tdd.minX = 0;
3473 tdd.maxX = int(lcMine.lcInExtX) - int(lcMine.lcInOrgX);
3474
3475 tdd.minY = 0;
3476 tdd.maxY = int(lcMine.lcInExtY) - int(lcMine.lcInOrgY);
3477
3478 tdd.minZ = 0;
3479 tdd.maxZ = int(lcMine.lcInExtZ) - int(lcMine.lcInOrgZ);
3480
3481 const uint cursorTypeBitMask = 0x0F06; // bitmask to find the specific cursor type (see Wacom FAQ)
3482 if (((csr_type & 0x0006) == 0x0002) && ((csr_type & cursorTypeBitMask) != 0x0902)) {
3483 tdd.currentDevice = QTabletEvent::Stylus;
3484 } else {
3485 switch (csr_type & cursorTypeBitMask) {
3486 case 0x0802:
3487 tdd.currentDevice = QTabletEvent::Stylus;
3488 break;
3489 case 0x0902:
3490 tdd.currentDevice = QTabletEvent::Airbrush;
3491 break;
3492 case 0x0004:
3493 tdd.currentDevice = QTabletEvent::FourDMouse;
3494 break;
3495 case 0x0006:
3496 tdd.currentDevice = QTabletEvent::Puck;
3497 break;
3498 case 0x0804:
3499 tdd.currentDevice = QTabletEvent::RotationStylus;
3500 break;
3501 default:
3502 tdd.currentDevice = QTabletEvent::NoDevice;
3503 }
3504 }
3505 tCursorInfo()->insert(uniqueId, tdd);
3506}
3507#endif // QT_NO_TABLETEVENT
3508
3509// Update the "dynamic" information of a cursor device (pen, airbrush, etc).
3510// The dynamic information is the information of QTabletDeviceData that can change
3511// in time (eraser or pen if a device is turned around).
3512#ifndef QT_NO_TABLETEVENT
3513
3514static void tabletUpdateCursor(QTabletDeviceData &tdd, const UINT currentCursor)
3515{
3516 switch (currentCursor % 3) { // %3 for dual track
3517 case 0:
3518 tdd.currentPointerType = QTabletEvent::Cursor;
3519 break;
3520 case 1:
3521 tdd.currentPointerType = QTabletEvent::Pen;
3522 break;
3523 case 2:
3524 tdd.currentPointerType = QTabletEvent::Eraser;
3525 break;
3526 default:
3527 tdd.currentPointerType = QTabletEvent::UnknownPointer;
3528 }
3529}
3530#endif // QT_NO_TABLETEVENT
3531
3532bool QETWidget::translateTabletEvent(const MSG &msg, PACKET *localPacketBuf,
3533 int numPackets)
3534{
3535 Q_UNUSED(msg);
3536 POINT ptNew;
3537 static DWORD btnNew, btnOld, btnChange;
3538 qreal prsNew;
3539 ORIENTATION ort;
3540 static bool button_pressed = false;
3541 int i,
3542 tiltX,
3543 tiltY;
3544 bool sendEvent = false;
3545 QEvent::Type t;
3546 int z = 0;
3547 qreal rotation = 0.0;
3548 qreal tangentialPressure;
3549
3550 // the most common event that we get...
3551 t = QEvent::TabletMove;
3552 for (i = 0; i < numPackets; i++) {
3553 // get the unique ID of the device...
3554 btnOld = btnNew;
3555 btnNew = localPacketBuf[i].pkButtons;
3556 btnChange = btnOld ^ btnNew;
3557
3558 if (btnNew & btnChange) {
3559 button_pressed = true;
3560 t = QEvent::TabletPress;
3561 }
3562 ptNew.x = UINT(localPacketBuf[i].pkX);
3563 ptNew.y = UINT(localPacketBuf[i].pkY);
3564#ifndef QT_NO_TABLETEVENT
3565 z = (currentTabletPointer.currentDevice == QTabletEvent::FourDMouse) ? UINT(localPacketBuf[i].pkZ) : 0;
3566#else
3567 Q_UNUSED(z);
3568#endif // QT_NO_TABLETEVENT
3569 prsNew = 0.0;
3570 QRect desktopArea = QApplication::desktop()->geometry();
3571 QPointF hiResGlobal = currentTabletPointer.scaleCoord(ptNew.x, ptNew.y, desktopArea.left(),
3572 desktopArea.width(), desktopArea.top(),
3573 desktopArea.height());
3574
3575 if (btnNew) {
3576#ifndef QT_NO_TABLETEVENT
3577 if (currentTabletPointer.currentPointerType == QTabletEvent::Pen || currentTabletPointer.currentPointerType == QTabletEvent::Eraser)
3578 prsNew = localPacketBuf[i].pkNormalPressure
3579 / qreal(currentTabletPointer.maxPressure
3580 - currentTabletPointer.minPressure);
3581 else
3582#endif // QT_NO_TABLETEVENT
3583 prsNew = 0;
3584 } else if (button_pressed) {
3585 // One button press, should only give one button release
3586 t = QEvent::TabletRelease;
3587 button_pressed = false;
3588 }
3589 QPoint globalPos(qRound(hiResGlobal.x()), qRound(hiResGlobal.y()));
3590
3591 if (t == QEvent::TabletPress)
3592 {
3593 qt_button_down = QApplication::widgetAt(globalPos);
3594 }
3595
3596 // make sure the tablet event get's sent to the proper widget...
3597 QWidget *w = 0;
3598
3599 if (qt_button_down)
3600 w = qt_button_down; // Pass it to the thing that's grabbed it.
3601 else
3602 w = QApplication::widgetAt(globalPos);
3603
3604 if (!w)
3605 w = this;
3606
3607 if (t == QEvent::TabletRelease)
3608 {
3609 if (qt_win_ignoreNextMouseReleaseEvent) {
3610 qt_win_ignoreNextMouseReleaseEvent = false;
3611 if (qt_button_down && qt_button_down->internalWinId() == autoCaptureWnd) {
3612 releaseAutoCapture();
3613 qt_button_down = 0;
3614 }
3615 }
3616
3617 }
3618
3619 QPoint localPos = w->mapFromGlobal(globalPos);
3620#ifndef QT_NO_TABLETEVENT
3621 if (currentTabletPointer.currentDevice == QTabletEvent::Airbrush) {
3622 tangentialPressure = localPacketBuf[i].pkTangentPressure
3623 / qreal(currentTabletPointer.maxTanPressure
3624 - currentTabletPointer.minTanPressure);
3625 } else {
3626 tangentialPressure = 0.0;
3627 }
3628#else
3629 tangentialPressure = 0.0;
3630#endif // QT_NO_TABLETEVENT
3631
3632 if (!qt_tablet_tilt_support) {
3633 tiltX = tiltY = 0;
3634 rotation = 0.0;
3635 } else {
3636 ort = localPacketBuf[i].pkOrientation;
3637 // convert from azimuth and altitude to x tilt and y tilt
3638 // what follows is the optimized version. Here are the equations
3639 // I used to get to this point (in case things change :)
3640 // X = sin(azimuth) * cos(altitude)
3641 // Y = cos(azimuth) * cos(altitude)
3642 // Z = sin(altitude)
3643 // X Tilt = arctan(X / Z)
3644 // Y Tilt = arctan(Y / Z)
3645 double radAzim = (ort.orAzimuth / 10) * (Q_PI / 180);
3646 //double radAlt = abs(ort.orAltitude / 10) * (Q_PI / 180);
3647 double tanAlt = tan((abs(ort.orAltitude / 10)) * (Q_PI / 180));
3648
3649 double degX = atan(sin(radAzim) / tanAlt);
3650 double degY = atan(cos(radAzim) / tanAlt);
3651 tiltX = int(degX * (180 / Q_PI));
3652 tiltY = int(-degY * (180 / Q_PI));
3653 rotation = ort.orTwist;
3654 }
3655#ifndef QT_NO_TABLETEVENT
3656 QTabletEvent e(t, localPos, globalPos, hiResGlobal, currentTabletPointer.currentDevice,
3657 currentTabletPointer.currentPointerType, prsNew, tiltX, tiltY,
3658 tangentialPressure, rotation, z, QApplication::keyboardModifiers(), currentTabletPointer.llId);
3659 sendEvent = QApplication::sendSpontaneousEvent(w, &e);
3660#endif // QT_NO_TABLETEVENT
3661 }
3662 return sendEvent;
3663}
3664
3665extern bool qt_is_gui_used;
3666
3667
3668#ifndef QT_NO_TABLETEVENT
3669
3670static void initWinTabFunctions()
3671{
3672#if defined(Q_OS_WINCE)
3673 return;
3674#else
3675 if (!qt_is_gui_used)
3676 return;
3677
3678 QSystemLibrary library(QLatin1String("wintab32"));
3679 if (library.load()) {
3680 ptrWTInfo = (PtrWTInfo)library.resolve("WTInfoW");
3681 ptrWTGet = (PtrWTGet)library.resolve("WTGetW");
3682 ptrWTEnable = (PtrWTEnable)library.resolve("WTEnable");
3683 ptrWTOverlap = (PtrWTEnable)library.resolve("WTOverlap");
3684 ptrWTPacketsGet = (PtrWTPacketsGet)library.resolve("WTPacketsGet");
3685 }
3686#endif // Q_OS_WINCE
3687}
3688#endif // QT_NO_TABLETEVENT
3689
3690
3691//
3692// Paint event translation
3693//
3694bool QETWidget::translatePaintEvent(const MSG &msg)
3695{
3696 if (!isWindow() && testAttribute(Qt::WA_NativeWindow))
3697 Q_ASSERT(internalWinId());
3698
3699 Q_ASSERT(testAttribute(Qt::WA_WState_Created));
3700 if (!GetUpdateRect(internalWinId(), 0, FALSE)) { // The update bounding rect is invalid
3701 d_func()->hd = 0;
3702 setAttribute(Qt::WA_PendingUpdate, false);
3703 return false;
3704 }
3705
3706 if (msg.message == WM_ERASEBKGND)
3707 return true;
3708
3709 setAttribute(Qt::WA_PendingUpdate, false);
3710
3711 if (d_func()->isGLWidget) {
3712 if (d_func()->usesDoubleBufferedGLContext)
3713 InvalidateRect(internalWinId(), 0, false);
3714 } else {
3715 const QRegion dirtyInBackingStore(qt_dirtyRegion(this));
3716 // Make sure the invalidated region contains the region we're about to repaint.
3717 // BeginPaint will set the clip to the invalidated region and it is impossible
3718 // to enlarge it afterwards (only shrink it). Using GetDCEx is not suffient
3719 // as it may return an invalid context (especially on Windows Vista).
3720 if (!dirtyInBackingStore.isEmpty())
3721 InvalidateRgn(internalWinId(), dirtyInBackingStore.handle(), false);
3722 }
3723 PAINTSTRUCT ps;
3724 d_func()->hd = BeginPaint(internalWinId(), &ps);
3725
3726 const QRect updateRect(QPoint(ps.rcPaint.left, ps.rcPaint.top),
3727 QPoint(ps.rcPaint.right, ps.rcPaint.bottom));
3728
3729 // Mapping region from system to qt (32 bit) coordinate system.
3730 d_func()->syncBackingStore(updateRect.translated(data->wrect.topLeft()));
3731
3732 d_func()->hd = 0;
3733 EndPaint(internalWinId(), &ps);
3734
3735 return true;
3736}
3737
3738//
3739// Window move and resize (configure) events
3740//
3741
3742bool QETWidget::translateConfigEvent(const MSG &msg)
3743{
3744 if (!testAttribute(Qt::WA_WState_Created)) // in QWidget::create()
3745 return true;
3746 if (testAttribute(Qt::WA_WState_ConfigPending))
3747 return true;
3748 if (testAttribute(Qt::WA_DontShowOnScreen))
3749 return true;
3750 if (!isWindow())
3751 return true;
3752 setAttribute(Qt::WA_WState_ConfigPending); // set config flag
3753 QRect cr = geometry();
3754 if (msg.message == WM_SIZE) { // resize event
3755 WORD a = LOWORD(msg.lParam);
3756 WORD b = HIWORD(msg.lParam);
3757 QSize oldSize = size();
3758 QSize newSize(a, b);
3759#ifdef Q_WS_WINCE_WM
3760 if (isFullScreen() && (oldSize.width() == newSize.height()) && (oldSize.height() == newSize.width()))
3761 qt_wince_hide_taskbar(internalWinId());
3762#endif
3763 cr.setSize(newSize);
3764 if (msg.wParam != SIZE_MINIMIZED)
3765 data->crect = cr;
3766 if (isWindow()) { // update title/icon text
3767 d_func()->createTLExtra();
3768 // Capture SIZE_MINIMIZED without preceding WM_SYSCOMMAND
3769 // (like Windows+M)
3770 if (msg.wParam == SIZE_MINIMIZED && !isMinimized()) {
3771#ifndef Q_WS_WINCE
3772 const QString title = windowIconText();
3773 if (!title.isEmpty())
3774 d_func()->setWindowTitle_helper(title);
3775#endif
3776 data->window_state |= Qt::WindowMinimized;
3777 if (isVisible()) {
3778 QHideEvent e;
3779 QApplication::sendSpontaneousEvent(this, &e);
3780 hideChildren(true);
3781 }
3782 } else if (msg.wParam != SIZE_MINIMIZED && isMinimized()) {
3783#ifndef Q_WS_WINCE
3784 const QString title = windowTitle();
3785 if (!title.isEmpty())
3786 d_func()->setWindowTitle_helper(title);
3787#endif
3788 data->window_state &= ~Qt::WindowMinimized;
3789 showChildren(true);
3790 QShowEvent e;
3791 QApplication::sendSpontaneousEvent(this, &e);
3792 }
3793 }
3794 if (msg.wParam != SIZE_MINIMIZED && oldSize != newSize) {
3795 if (isVisible()) {
3796 QTLWExtra *tlwExtra = maybeTopData();
3797 static bool slowResize = qgetenv("QT_SLOW_TOPLEVEL_RESIZE").toInt();
3798 const bool hasStaticContents = tlwExtra && tlwExtra->backingStore
3799 && tlwExtra->backingStore->hasStaticContents();
3800 // If we have a backing store with static contents, we have to disable the top-level
3801 // resize optimization in order to get invalidated regions for resized widgets.
3802 // The optimization discards all invalidateBuffer() calls since we're going to
3803 // repaint everything anyways, but that's not the case with static contents.
3804 if (!slowResize && tlwExtra && !hasStaticContents)
3805 tlwExtra->inTopLevelResize = true;
3806 QResizeEvent e(newSize, oldSize);
3807 QApplication::sendSpontaneousEvent(this, &e);
3808 if (d_func()->paintOnScreen()) {
3809 QRegion updateRegion(rect());
3810 if (testAttribute(Qt::WA_StaticContents))
3811 updateRegion -= QRect(0, 0, oldSize.width(), oldSize.height());
3812 d_func()->syncBackingStore(updateRegion);
3813 } else {
3814 d_func()->syncBackingStore();
3815 }
3816 if (!slowResize && tlwExtra)
3817 tlwExtra->inTopLevelResize = false;
3818 } else {
3819 QResizeEvent *e = new QResizeEvent(newSize, oldSize);
3820 QApplication::postEvent(this, e);
3821 }
3822 }
3823} else if (msg.message == WM_MOVE) { // move event
3824 int a = (int) (short) LOWORD(msg.lParam);
3825 int b = (int) (short) HIWORD(msg.lParam);
3826 QPoint oldPos = geometry().topLeft();
3827 QPoint newCPos(a, b);
3828 // Ignore silly Windows move event to wild pos after iconify.
3829#if !defined(Q_WS_WINCE)
3830 if (!IsIconic(internalWinId()) && newCPos != oldPos) {
3831#endif
3832 cr.moveTopLeft(newCPos);
3833 data->crect = cr;
3834 if (isVisible()) {
3835 QMoveEvent e(newCPos, oldPos); // cpos (client position)
3836 QApplication::sendSpontaneousEvent(this, &e);
3837 } else {
3838 QMoveEvent * e = new QMoveEvent(newCPos, oldPos);
3839 QApplication::postEvent(this, e);
3840 }
3841#if !defined(Q_WS_WINCE)
3842 }
3843#endif
3844 }
3845 setAttribute(Qt::WA_WState_ConfigPending, false); // clear config flag
3846 return true;
3847}
3848
3849
3850//
3851// Close window event translation.
3852//
3853// This class is a friend of QApplication because it needs to emit the
3854// lastWindowClosed() signal when the last top level widget is closed.
3855//
3856
3857bool QETWidget::translateCloseEvent(const MSG &)
3858{
3859 return d_func()->close_helper(QWidgetPrivate::CloseWithSpontaneousEvent);
3860}
3861
3862#ifndef QT_NO_GESTURES
3863bool QETWidget::translateGestureEvent(const MSG &, const GESTUREINFO &gi)
3864{
3865 const QPoint widgetPos = QPoint(gi.ptsLocation.x, gi.ptsLocation.y);
3866 QWidget *alienWidget = !internalWinId() ? this : childAt(widgetPos);
3867 if (alienWidget && alienWidget->internalWinId())
3868 alienWidget = 0;
3869 QWidget *widget = alienWidget ? alienWidget : this;
3870
3871 QNativeGestureEvent event;
3872 event.sequenceId = gi.dwSequenceID;
3873 event.position = QPoint(gi.ptsLocation.x, gi.ptsLocation.y);
3874 event.argument = gi.ullArguments;
3875
3876 switch (gi.dwID) {
3877 case GID_BEGIN:
3878 event.gestureType = QNativeGestureEvent::GestureBegin;
3879 break;
3880 case GID_END:
3881 event.gestureType = QNativeGestureEvent::GestureEnd;
3882 break;
3883 case GID_ZOOM:
3884 event.gestureType = QNativeGestureEvent::Zoom;
3885 break;
3886 case GID_PAN:
3887 event.gestureType = QNativeGestureEvent::Pan;
3888 break;
3889 case GID_ROTATE:
3890 event.gestureType = QNativeGestureEvent::Rotate;
3891 break;
3892 case GID_TWOFINGERTAP:
3893 case GID_ROLLOVER:
3894 default:
3895 break;
3896 }
3897 if (event.gestureType != QNativeGestureEvent::None)
3898 qt_sendSpontaneousEvent(widget, &event);
3899 return true;
3900}
3901#endif // QT_NO_GESTURES
3902
3903void QApplication::setCursorFlashTime(int msecs)
3904{
3905 SetCaretBlinkTime(msecs / 2);
3906 QApplicationPrivate::cursor_flash_time = msecs;
3907}
3908
3909
3910int QApplication::cursorFlashTime()
3911{
3912 int blink = (int)GetCaretBlinkTime();
3913 if (!blink)
3914 return QApplicationPrivate::cursor_flash_time;
3915 if (blink > 0)
3916 return 2*blink;
3917 return 0;
3918}
3919
3920
3921void QApplication::setDoubleClickInterval(int ms)
3922{
3923#ifndef Q_WS_WINCE
3924 SetDoubleClickTime(ms);
3925#endif
3926 QApplicationPrivate::mouse_double_click_time = ms;
3927}
3928
3929int QApplication::doubleClickInterval()
3930{
3931 int ms = GetDoubleClickTime();
3932 if (ms != 0)
3933 return ms;
3934 return QApplicationPrivate::mouse_double_click_time;
3935}
3936
3937
3938void QApplication::setKeyboardInputInterval(int ms)
3939{
3940 QApplicationPrivate::keyboard_input_time = ms;
3941}
3942
3943int QApplication::keyboardInputInterval()
3944{
3945 // FIXME: get from the system
3946 return QApplicationPrivate::keyboard_input_time;
3947}
3948
3949#ifndef QT_NO_WHEELEVENT
3950void QApplication::setWheelScrollLines(int n)
3951{
3952#ifdef SPI_SETWHEELSCROLLLINES
3953 if (n < 0)
3954 n = 0;
3955 SystemParametersInfo(SPI_SETWHEELSCROLLLINES, (uint)n, 0, 0);
3956#else
3957 QApplicationPrivate::wheel_scroll_lines = n;
3958#endif
3959}
3960
3961int QApplication::wheelScrollLines()
3962{
3963#ifdef SPI_GETWHEELSCROLLLINES
3964 uint i = 3;
3965 SystemParametersInfo(SPI_GETWHEELSCROLLLINES, sizeof(uint), &i, 0);
3966 if (i > INT_MAX)
3967 i = INT_MAX;
3968 return i;
3969#else
3970 return QApplicationPrivate::wheel_scroll_lines;
3971#endif
3972}
3973#endif //QT_NO_WHEELEVENT
3974
3975static bool effect_override = false;
3976
3977void QApplication::setEffectEnabled(Qt::UIEffect effect, bool enable)
3978{
3979 effect_override = true;
3980 switch (effect) {
3981 case Qt::UI_AnimateMenu:
3982 QApplicationPrivate::animate_menu = enable;
3983 break;
3984 case Qt::UI_FadeMenu:
3985 QApplicationPrivate::fade_menu = enable;
3986 break;
3987 case Qt::UI_AnimateCombo:
3988 QApplicationPrivate::animate_combo = enable;
3989 break;
3990 case Qt::UI_AnimateTooltip:
3991 QApplicationPrivate::animate_tooltip = enable;
3992 break;
3993 case Qt::UI_FadeTooltip:
3994 QApplicationPrivate::fade_tooltip = enable;
3995 break;
3996 case Qt::UI_AnimateToolBox:
3997 QApplicationPrivate::animate_toolbox = enable;
3998 break;
3999 default:
4000 QApplicationPrivate::animate_ui = enable;
4001 break;
4002 }
4003}
4004
4005bool QApplication::isEffectEnabled(Qt::UIEffect effect)
4006{
4007 if (QColormap::instance().depth() < 16)
4008 return false;
4009
4010 if (!effect_override && desktopSettingsAware()) {
4011 // we know that they can be used when we are here
4012 BOOL enabled = false;
4013 UINT api;
4014 switch (effect) {
4015 case Qt::UI_AnimateMenu:
4016 api = SPI_GETMENUANIMATION;
4017 break;
4018 case Qt::UI_FadeMenu:
4019 api = SPI_GETMENUFADE;
4020 break;
4021 case Qt::UI_AnimateCombo:
4022 api = SPI_GETCOMBOBOXANIMATION;
4023 break;
4024 case Qt::UI_AnimateTooltip:
4025 api = SPI_GETTOOLTIPANIMATION;
4026 break;
4027 case Qt::UI_FadeTooltip:
4028 api = SPI_GETTOOLTIPFADE;
4029 break;
4030 default:
4031 api = SPI_GETUIEFFECTS;
4032 break;
4033 }
4034 SystemParametersInfo(api, 0, &enabled, 0);
4035 return enabled;
4036 }
4037
4038 switch(effect) {
4039 case Qt::UI_AnimateMenu:
4040 return QApplicationPrivate::animate_menu;
4041 case Qt::UI_FadeMenu:
4042 return QApplicationPrivate::fade_menu;
4043 case Qt::UI_AnimateCombo:
4044 return QApplicationPrivate::animate_combo;
4045 case Qt::UI_AnimateTooltip:
4046 return QApplicationPrivate::animate_tooltip;
4047 case Qt::UI_FadeTooltip:
4048 return QApplicationPrivate::fade_tooltip;
4049 case Qt::UI_AnimateToolBox:
4050 return QApplicationPrivate::animate_toolbox;
4051 default:
4052 return QApplicationPrivate::animate_ui;
4053 }
4054}
4055
4056#ifndef QT_NO_SESSIONMANAGER
4057
4058bool QSessionManager::allowsInteraction()
4059{
4060 sm_blockUserInput = false;
4061 return true;
4062}
4063
4064bool QSessionManager::allowsErrorInteraction()
4065{
4066 sm_blockUserInput = false;
4067 return true;
4068}
4069
4070void QSessionManager::release()
4071{
4072 if (sm_smActive)
4073 sm_blockUserInput = true;
4074}
4075
4076void QSessionManager::cancel()
4077{
4078 sm_cancel = true;
4079}
4080
4081#endif //QT_NO_SESSIONMANAGER
4082
4083
4084bool QApplicationPrivate::HasTouchSupport = false;
4085PtrRegisterTouchWindow QApplicationPrivate::RegisterTouchWindow = 0;
4086PtrGetTouchInputInfo QApplicationPrivate::GetTouchInputInfo = 0;
4087PtrCloseTouchInputHandle QApplicationPrivate::CloseTouchInputHandle = 0;
4088
4089void QApplicationPrivate::initializeMultitouch_sys()
4090{
4091 if (QSysInfo::windowsVersion() >= QSysInfo::WV_WINDOWS7) {
4092 static const int QT_SM_DIGITIZER = 94;
4093 int value = GetSystemMetrics(QT_SM_DIGITIZER);
4094 static const int QT_NID_INTEGRATED_TOUCH = 0x01;
4095 static const int QT_NID_EXTERNAL_TOUCH = 0x02;
4096 static const int QT_NID_MULTI_INPUT = 0x40;
4097 QApplicationPrivate::HasTouchSupport =
4098 value & (QT_NID_INTEGRATED_TOUCH | QT_NID_EXTERNAL_TOUCH | QT_NID_MULTI_INPUT);
4099 }
4100
4101 QSystemLibrary library(QLatin1String("user32"));
4102 // MinGW (g++ 3.4.5) accepts only C casts.
4103 RegisterTouchWindow = (PtrRegisterTouchWindow)(library.resolve("RegisterTouchWindow"));
4104 GetTouchInputInfo = (PtrGetTouchInputInfo)(library.resolve("GetTouchInputInfo"));
4105 CloseTouchInputHandle = (PtrCloseTouchInputHandle)(library.resolve("CloseTouchInputHandle"));
4106
4107 touchInputIDToTouchPointID.clear();
4108}
4109
4110void QApplicationPrivate::cleanupMultitouch_sys()
4111{
4112 touchInputIDToTouchPointID.clear();
4113}
4114
4115bool QApplicationPrivate::translateTouchEvent(const MSG &msg)
4116{
4117 QWidget *widgetForHwnd = QWidget::find(msg.hwnd);
4118 if (!widgetForHwnd)
4119 return false;
4120
4121 QRect screenGeometry = QApplication::desktop()->screenGeometry(widgetForHwnd);
4122
4123 QList<QTouchEvent::TouchPoint> touchPoints;
4124
4125 QVector<TOUCHINPUT> winTouchInputs(msg.wParam);
4126 memset(winTouchInputs.data(), 0, sizeof(TOUCHINPUT) * winTouchInputs.count());
4127 Qt::TouchPointStates allStates = 0;
4128 QApplicationPrivate::GetTouchInputInfo((HANDLE) msg.lParam, msg.wParam, winTouchInputs.data(), sizeof(TOUCHINPUT));
4129 for (int i = 0; i < winTouchInputs.count(); ++i) {
4130 const TOUCHINPUT &touchInput = winTouchInputs.at(i);
4131
4132 int touchPointID = touchInputIDToTouchPointID.value(touchInput.dwID, -1);
4133 if (touchPointID == -1) {
4134 touchPointID = touchInputIDToTouchPointID.count();
4135 touchInputIDToTouchPointID.insert(touchInput.dwID, touchPointID);
4136 }
4137
4138 QTouchEvent::TouchPoint touchPoint(touchPointID);
4139
4140 // update state
4141 QPointF screenPos(qreal(touchInput.x) / qreal(100.), qreal(touchInput.y) / qreal(100.));
4142 QRectF screenRect;
4143 if (touchInput.dwMask & TOUCHINPUTMASKF_CONTACTAREA)
4144 screenRect.setSize(QSizeF(qreal(touchInput.cxContact) / qreal(100.),
4145 qreal(touchInput.cyContact) / qreal(100.)));
4146 screenRect.moveCenter(screenPos);
4147
4148 Qt::TouchPointStates state;
4149 if (touchInput.dwFlags & TOUCHEVENTF_DOWN) {
4150 state = Qt::TouchPointPressed;
4151 } else if (touchInput.dwFlags & TOUCHEVENTF_UP) {
4152 state = Qt::TouchPointReleased;
4153 } else {
4154 state = (screenPos == touchPoint.screenPos()
4155 ? Qt::TouchPointStationary
4156 : Qt::TouchPointMoved);
4157 }
4158 if (touchInput.dwFlags & TOUCHEVENTF_PRIMARY)
4159 state |= Qt::TouchPointPrimary;
4160 touchPoint.setState(state);
4161 touchPoint.setScreenRect(screenRect);
4162 touchPoint.setNormalizedPos(QPointF(screenPos.x() / screenGeometry.width(),
4163 screenPos.y() / screenGeometry.height()));
4164
4165 allStates |= state;
4166
4167 touchPoints.append(touchPoint);
4168 }
4169 QApplicationPrivate::CloseTouchInputHandle((HANDLE) msg.lParam);
4170
4171 if ((allStates & Qt::TouchPointStateMask) == Qt::TouchPointReleased) {
4172 // all touch points released, forget the ids we've seen, they may not be reused
4173 touchInputIDToTouchPointID.clear();
4174 }
4175
4176 translateRawTouchEvent(widgetForHwnd, QTouchEvent::TouchScreen, touchPoints);
4177 return true;
4178}
4179
4180QT_END_NAMESPACE
Note: See TracBrowser for help on using the repository browser.