summaryrefslogtreecommitdiffstats
path: root/src/gui/platforms/win
diff options
context:
space:
mode:
authorLars Knoll <lars.knoll@nokia.com>2011-05-04 14:37:50 +0200
committerLars Knoll <lars.knoll@nokia.com>2011-05-04 14:39:19 +0200
commitbd8d12b7f68ea8aa05a86cc9ed65dd660a6b075d (patch)
treea2da73cfac60aa2b86fee223b5c28d813dcc69cd /src/gui/platforms/win
parentdc0f9f02a5c390f4a7919db4c32d22cebaf71d1c (diff)
move platform specific files out of the way
Keep the files as reference to implement the lighthouse plugins, but move them away from the main directory hierachy as they won't be part of Qt5 in any case.
Diffstat (limited to 'src/gui/platforms/win')
-rw-r--r--src/gui/platforms/win/qapplication_win.cpp4243
-rw-r--r--src/gui/platforms/win/qclipboard_win.cpp398
-rw-r--r--src/gui/platforms/win/qcolormap_win.cpp201
-rw-r--r--src/gui/platforms/win/qcursor_win.cpp492
-rw-r--r--src/gui/platforms/win/qdesktopwidget_win.cpp387
-rw-r--r--src/gui/platforms/win/qdnd_win.cpp1027
-rw-r--r--src/gui/platforms/win/qfont_win.cpp166
-rw-r--r--src/gui/platforms/win/qfontdatabase_win.cpp1348
-rw-r--r--src/gui/platforms/win/qfontengine_win.cpp1339
-rw-r--r--src/gui/platforms/win/qfontengine_win_p.h164
-rw-r--r--src/gui/platforms/win/qguifunctions_wince.cpp408
-rw-r--r--src/gui/platforms/win/qguifunctions_wince.h151
-rw-r--r--src/gui/platforms/win/qkeymapper_win.cpp1207
-rw-r--r--src/gui/platforms/win/qmime_win.cpp1556
-rw-r--r--src/gui/platforms/win/qole_win.cpp255
-rw-r--r--src/gui/platforms/win/qpaintdevice_win.cpp62
-rw-r--r--src/gui/platforms/win/qpixmap_win.cpp477
-rw-r--r--src/gui/platforms/win/qprintengine_win.cpp1776
-rw-r--r--src/gui/platforms/win/qprintengine_win_p.h261
-rw-r--r--src/gui/platforms/win/qprinterinfo_win.cpp122
-rw-r--r--src/gui/platforms/win/qrawfont_win.cpp707
-rw-r--r--src/gui/platforms/win/qregion_win.cpp149
-rw-r--r--src/gui/platforms/win/qsound_win.cpp205
-rw-r--r--src/gui/platforms/win/qwidget_win.cpp2139
-rw-r--r--src/gui/platforms/win/qwidget_wince.cpp675
-rw-r--r--src/gui/platforms/win/qwindowdefs_win.h132
-rw-r--r--src/gui/platforms/win/qwinnativepangesturerecognizer_win.cpp133
-rw-r--r--src/gui/platforms/win/qwinnativepangesturerecognizer_win_p.h80
28 files changed, 20260 insertions, 0 deletions
diff --git a/src/gui/platforms/win/qapplication_win.cpp b/src/gui/platforms/win/qapplication_win.cpp
new file mode 100644
index 0000000000..72a05afbd0
--- /dev/null
+++ b/src/gui/platforms/win/qapplication_win.cpp
@@ -0,0 +1,4243 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifdef Q_WS_WINCE
+#include "qguifunctions_wince.h"
+#include "qmenubar.h"
+extern bool qt_wince_is_mobile(); //defined in qguifunctions_wince.cpp
+extern bool qt_wince_is_high_dpi(); //defined in qguifunctions_wince.cpp
+extern bool qt_wince_is_smartphone(); //defined in qguifunctions_wince.cpp
+extern bool qt_wince_is_pocket_pc(); //defined in qguifunctions_wince.cpp
+extern void qt_wince_hide_taskbar(HWND hwnd); //defined in qguifunctions_wince.cpp
+#endif
+#ifdef Q_WS_WINCE_WM
+#include <windowsm.h>
+#include <tpcshell.h>
+#ifdef QT_WINCE_GESTURES
+#ifndef QT_NO_GESTURES
+#include <gesture.h>
+#endif
+#endif
+#endif
+
+#include "qapplication.h"
+#include "qdesktopwidget.h"
+#include "qevent.h"
+#include "private/qeventdispatcher_win_p.h"
+#include "qeventloop.h"
+#include "qclipboard.h"
+#include "qcursor.h"
+#include "qdatetime.h"
+#include "qpointer.h"
+#include "qhash.h"
+#include "qmetaobject.h"
+#include "qmime.h"
+#include "qpainter.h"
+#include "qpixmapcache.h"
+#include "qsessionmanager.h"
+#include "qstyle.h"
+#include "qwhatsthis.h" // ######## dependency
+#include "qwidget.h"
+#include "qcolormap.h"
+#include "qlayout.h"
+#include "qtooltip.h"
+#include "qt_windows.h"
+#include "qscrollbar.h"
+#if defined(QT_NON_COMMERCIAL)
+#include "qnc_win.h"
+#endif
+#include "private/qwininputcontext_p.h"
+#include "private/qcursor_p.h"
+#include "private/qmath_p.h"
+#include "private/qapplication_p.h"
+#include "private/qbackingstore_p.h"
+#include "private/qwindowsurface_raster_p.h"
+#include "qdebug.h"
+#include <private/qkeymapper_p.h>
+#include <private/qlocale_p.h>
+#include <private/qsystemlibrary_p.h>
+#include "qevent_p.h"
+
+//#define ALIEN_DEBUG
+
+#ifndef QT_NO_THREAD
+#include "qmutex.h"
+#endif
+
+#ifndef QT_NO_ACCESSIBILITY
+#include "qaccessible.h"
+
+#include <oleacc.h>
+#ifndef WM_GETOBJECT
+#define WM_GETOBJECT 0x003D
+#endif
+#endif // QT_NO_ACCESSIBILITY
+
+#if !defined(WINABLEAPI)
+# if defined(Q_WS_WINCE)
+# include <bldver.h>
+# endif
+# if !defined(Q_WS_WINCE)
+# include <winable.h>
+# endif
+#endif
+
+#ifndef QT_NO_GESTURES
+# ifndef GID_ZOOM
+# define GID_ZOOM 3
+# define GID_TWOFINGERTAP 6
+# define GID_PRESSANDTAP 7
+# define GID_ROLLOVER GID_PRESSANDTAP
+# endif
+#endif
+
+#ifndef WM_TOUCH
+# define WM_TOUCH 0x0240
+#endif
+
+#ifndef TOUCHEVENTF_MOVE
+# define TOUCHEVENTF_MOVE 0x0001
+# define TOUCHEVENTF_DOWN 0x0002
+# define TOUCHEVENTF_UP 0x0004
+# define TOUCHEVENTF_INRANGE 0x0008
+# define TOUCHEVENTF_PRIMARY 0x0010
+# define TOUCHEVENTF_NOCOALESCE 0x0020
+# define TOUCHEVENTF_PEN 0x0040
+# define TOUCHEVENTF_PALM 0x0080
+
+# define TOUCHINPUTMASKF_TIMEFROMSYSTEM 0x0001
+# define TOUCHINPUTMASKF_EXTRAINFO 0x0002
+# define TOUCHINPUTMASKF_CONTACTAREA 0x0004
+
+typedef struct tagTOUCHINPUT
+{
+ LONG x;
+ LONG y;
+ HANDLE hSource;
+ DWORD dwID;
+ DWORD dwFlags;
+ DWORD dwMask;
+ DWORD dwTime;
+ ULONG_PTR dwExtraInfo;
+ DWORD cxContact;
+ DWORD cyContact;
+} TOUCHINPUT, *PTOUCHINPUT;
+
+#endif
+
+#include <windowsx.h>
+#include <limits.h>
+#include <string.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <math.h>
+
+#define PACKETDATA (PK_X | PK_Y | PK_BUTTONS | PK_NORMAL_PRESSURE | PK_TANGENT_PRESSURE \
+ | PK_ORIENTATION | PK_CURSOR | PK_Z)
+#define PACKETMODE 0
+
+#include <wintab.h>
+#ifndef CSR_TYPE
+#define CSR_TYPE 20 // Some old Wacom wintab.h may not provide this constant.
+#endif
+#include <pktdef.h>
+
+#if defined(__CYGWIN32__)
+#define __INSIDE_CYGWIN32__
+#include <mywinsock.h>
+#endif
+
+#ifndef IMR_RECONVERTSTRING
+#define IMR_RECONVERTSTRING 4
+#endif
+
+#ifndef IMR_CONFIRMRECONVERTSTRING
+#define IMR_CONFIRMRECONVERTSTRING 0x0005
+#endif
+QT_BEGIN_NAMESPACE
+
+#ifdef Q_WS_WINCE
+#ifndef SHRG_RETURNCMD
+struct SHRGINFO {
+ DWORD cbSize;
+ HWND hwndClient;
+ POINT ptDown;
+ DWORD dwFlags;
+};
+#define GN_CONTEXTMENU 1000
+#define SHRG_RETURNCMD 0x00000001
+#define SHRG_NOANIMATION 0x00000010
+#endif
+
+#ifndef SPI_SETSIPINFO
+#define SPI_SETSIPINFO 224
+#endif
+
+#ifndef QT_NO_GESTURES
+typedef DWORD (API *AygRecognizeGesture)(SHRGINFO*);
+static AygRecognizeGesture ptrRecognizeGesture = 0;
+static bool aygResolved = false;
+static void resolveAygLibs()
+{
+ if (!aygResolved) {
+ aygResolved = true;
+ QSystemLibrary ayglib(QLatin1String("aygshell"));
+ ptrRecognizeGesture = (AygRecognizeGesture) ayglib.resolve("SHRecognizeGesture");
+ }
+}
+#endif // QT_NO_GESTURES
+
+#endif
+
+#ifndef SPI_SETFONTSMOOTHINGTYPE
+# define SPI_SETFONTSMOOTHINGTYPE 0x200B
+#endif
+#ifndef SPI_GETFONTSMOOTHINGTYPE
+# define SPI_GETFONTSMOOTHINGTYPE 0x200A
+#endif
+#ifndef FE_FONTSMOOTHINGCLEARTYPE
+# define FE_FONTSMOOTHINGCLEARTYPE 0x0002
+#endif
+
+Q_GUI_EXPORT qreal qt_fontsmoothing_gamma;
+Q_GUI_EXPORT bool qt_cleartype_enabled;
+Q_GUI_EXPORT bool qt_win_owndc_required; // CS_OWNDC is required if we use the GL graphicssystem as default
+
+typedef HCTX (API *PtrWTOpen)(HWND, LPLOGCONTEXT, BOOL);
+typedef BOOL (API *PtrWTClose)(HCTX);
+typedef UINT (API *PtrWTInfo)(UINT, UINT, LPVOID);
+typedef BOOL (API *PtrWTEnable)(HCTX, BOOL);
+typedef BOOL (API *PtrWTOverlap)(HCTX, BOOL);
+typedef int (API *PtrWTPacketsGet)(HCTX, int, LPVOID);
+typedef BOOL (API *PtrWTGet)(HCTX, LPLOGCONTEXT);
+typedef int (API *PtrWTQueueSizeGet)(HCTX);
+typedef BOOL (API *PtrWTQueueSizeSet)(HCTX, int);
+
+static PtrWTInfo ptrWTInfo = 0;
+static PtrWTEnable ptrWTEnable = 0;
+static PtrWTOverlap ptrWTOverlap = 0;
+static PtrWTPacketsGet ptrWTPacketsGet = 0;
+static PtrWTGet ptrWTGet = 0;
+
+static PACKET localPacketBuf[QT_TABLET_NPACKETQSIZE]; // our own tablet packet queue.
+HCTX qt_tablet_context; // the hardware context for the tablet (like a window handle)
+bool qt_tablet_tilt_support;
+
+#ifndef QT_NO_TABLETEVENT
+static void tabletInit(const quint64 uniqueId, const UINT csr_type, HCTX hTab);
+static void tabletUpdateCursor(QTabletDeviceData &tdd, const UINT currentCursor);
+static void initWinTabFunctions(); // resolve the WINTAB api functions
+#endif // QT_NO_TABLETEVENT
+
+
+#ifndef QT_NO_ACCESSIBILITY
+extern IAccessible *qt_createWindowsAccessible(QAccessibleInterface *object);
+#endif // QT_NO_ACCESSIBILITY
+
+extern bool qt_tabletChokeMouse;
+extern QWidget* qt_get_tablet_widget();
+extern bool qt_sendSpontaneousEvent(QObject*, QEvent*);
+extern QRegion qt_dirtyRegion(QWidget *);
+
+typedef QHash<quint64, QTabletDeviceData> QTabletCursorInfo;
+Q_GLOBAL_STATIC(QTabletCursorInfo, tCursorInfo)
+QTabletDeviceData currentTabletPointer;
+
+// from qregion_win.cpp
+extern HRGN qt_tryCreateRegion(QRegion::RegionType type, int left, int top, int right, int bottom);
+
+// support for on-the-fly changes of the XP theme engine
+#ifndef WM_THEMECHANGED
+#define WM_THEMECHANGED 0x031A
+#endif
+#ifndef COLOR_MENUHILIGHT
+#define COLOR_MENUHILIGHT 29
+#define COLOR_MENUBAR 30
+#endif
+
+// support for xbuttons
+#ifndef WM_XBUTTONDOWN
+#define WM_XBUTTONDOWN 0x020B
+#define WM_XBUTTONUP 0x020C
+#define WM_XBUTTONDBLCLK 0x020D
+#endif
+#ifndef GET_KEYSTATE_WPARAM
+#define GET_KEYSTATE_WPARAM(wParam) (LOWORD(wParam))
+#define GET_XBUTTON_WPARAM(wParam) (HIWORD(wParam))
+#define XBUTTON1 0x0001
+#define XBUTTON2 0x0002
+#endif
+#ifndef MK_XBUTTON1
+#define MK_XBUTTON1 0x0020
+#define MK_XBUTTON2 0x0040
+#endif
+
+// support for multi-media-keys
+#ifndef WM_APPCOMMAND
+#define WM_APPCOMMAND 0x0319
+#endif
+
+#ifndef FAPPCOMMAND_MOUSE
+#define FAPPCOMMAND_MOUSE 0x8000
+#define FAPPCOMMAND_KEY 0
+#define FAPPCOMMAND_OEM 0x1000
+#define FAPPCOMMAND_MASK 0xF000
+#define GET_APPCOMMAND_LPARAM(lParam) ((short)(HIWORD(lParam) & ~FAPPCOMMAND_MASK))
+#define GET_DEVICE_LPARAM(lParam) ((WORD)(HIWORD(lParam) & FAPPCOMMAND_MASK))
+#define GET_MOUSEORKEY_LPARAM GET_DEVICE_LPARAM
+#define GET_FLAGS_LPARAM(lParam) (LOWORD(lParam))
+#define GET_KEYSTATE_LPARAM(lParam) GET_FLAGS_LPARAM(lParam)
+
+#define APPCOMMAND_BROWSER_BACKWARD 1
+#define APPCOMMAND_BROWSER_FORWARD 2
+#define APPCOMMAND_BROWSER_REFRESH 3
+#define APPCOMMAND_BROWSER_STOP 4
+#define APPCOMMAND_BROWSER_SEARCH 5
+#define APPCOMMAND_BROWSER_FAVORITES 6
+#define APPCOMMAND_BROWSER_HOME 7
+#define APPCOMMAND_VOLUME_MUTE 8
+#define APPCOMMAND_VOLUME_DOWN 9
+#define APPCOMMAND_VOLUME_UP 10
+#define APPCOMMAND_MEDIA_NEXTTRACK 11
+#define APPCOMMAND_MEDIA_PREVIOUSTRACK 12
+#define APPCOMMAND_MEDIA_STOP 13
+#define APPCOMMAND_MEDIA_PLAY_PAUSE 14
+#define APPCOMMAND_LAUNCH_MAIL 15
+#define APPCOMMAND_LAUNCH_MEDIA_SELECT 16
+#define APPCOMMAND_LAUNCH_APP1 17
+#define APPCOMMAND_LAUNCH_APP2 18
+#define APPCOMMAND_BASS_DOWN 19
+#define APPCOMMAND_BASS_BOOST 20
+#define APPCOMMAND_BASS_UP 21
+#define APPCOMMAND_TREBLE_DOWN 22
+#define APPCOMMAND_TREBLE_UP 23
+#endif // FAPPCOMMAND_MOUSE
+
+// New commands from Windows XP (some even Sp1)
+#ifndef APPCOMMAND_MICROPHONE_VOLUME_MUTE
+#define APPCOMMAND_MICROPHONE_VOLUME_MUTE 24
+#define APPCOMMAND_MICROPHONE_VOLUME_DOWN 25
+#define APPCOMMAND_MICROPHONE_VOLUME_UP 26
+#define APPCOMMAND_HELP 27
+#define APPCOMMAND_FIND 28
+#define APPCOMMAND_NEW 29
+#define APPCOMMAND_OPEN 30
+#define APPCOMMAND_CLOSE 31
+#define APPCOMMAND_SAVE 32
+#define APPCOMMAND_PRINT 33
+#define APPCOMMAND_UNDO 34
+#define APPCOMMAND_REDO 35
+#define APPCOMMAND_COPY 36
+#define APPCOMMAND_CUT 37
+#define APPCOMMAND_PASTE 38
+#define APPCOMMAND_REPLY_TO_MAIL 39
+#define APPCOMMAND_FORWARD_MAIL 40
+#define APPCOMMAND_SEND_MAIL 41
+#define APPCOMMAND_SPELL_CHECK 42
+#define APPCOMMAND_DICTATE_OR_COMMAND_CONTROL_TOGGLE 43
+#define APPCOMMAND_MIC_ON_OFF_TOGGLE 44
+#define APPCOMMAND_CORRECTION_LIST 45
+#define APPCOMMAND_MEDIA_PLAY 46
+#define APPCOMMAND_MEDIA_PAUSE 47
+#define APPCOMMAND_MEDIA_RECORD 48
+#define APPCOMMAND_MEDIA_FAST_FORWARD 49
+#define APPCOMMAND_MEDIA_REWIND 50
+#define APPCOMMAND_MEDIA_CHANNEL_UP 51
+#define APPCOMMAND_MEDIA_CHANNEL_DOWN 52
+#endif // APPCOMMAND_MICROPHONE_VOLUME_MUTE
+
+#if (_WIN32_WINNT < 0x0400)
+// This struct is defined in winuser.h if the _WIN32_WINNT >= 0x0400 -- in the
+// other cases we have to define it on our own.
+typedef struct tagTRACKMOUSEEVENT {
+ DWORD cbSize;
+ DWORD dwFlags;
+ HWND hwndTrack;
+ DWORD dwHoverTime;
+} TRACKMOUSEEVENT, *LPTRACKMOUSEEVENT;
+#endif
+#ifndef WM_MOUSELEAVE
+#define WM_MOUSELEAVE 0x02A3
+#endif
+
+QT_BEGIN_INCLUDE_NAMESPACE
+#include "private/qwidget_p.h"
+QT_END_INCLUDE_NAMESPACE
+
+static int translateButtonState(int s, int type, int button);
+
+// ##### get rid of this!
+QRgb qt_colorref2qrgb(COLORREF col)
+{
+ return qRgb(GetRValue(col),GetGValue(col),GetBValue(col));
+}
+
+
+/*****************************************************************************
+ Internal variables and functions
+ *****************************************************************************/
+
+static HWND curWin = 0; // current window
+static HDC displayDC = 0; // display device context
+
+// Session management
+static bool sm_blockUserInput = false;
+static bool sm_smActive = false;
+extern QSessionManager* qt_session_manager_self;
+static bool sm_cancel;
+
+static bool replayPopupMouseEvent = false; // replay handling when popups close
+
+// ignore the next release event if return from a modal widget
+Q_GUI_EXPORT bool qt_win_ignoreNextMouseReleaseEvent = false;
+
+
+#if defined(QT_DEBUG)
+static bool appNoGrab = false; // mouse/keyboard grabbing
+#endif
+
+static bool app_do_modal = false; // modal mode
+extern QWidgetList *qt_modal_stack;
+extern QDesktopWidget *qt_desktopWidget;
+static QPointer<QWidget> popupButtonFocus;
+static bool qt_try_modal(QWidget *, MSG *, int& ret);
+
+QWidget *qt_button_down = 0; // widget got last button-down
+QPointer<QWidget> qt_last_mouse_receiver = 0;
+
+static HWND autoCaptureWnd = 0;
+static HWND imeParentWnd = 0;
+static void setAutoCapture(HWND); // automatic capture
+static void releaseAutoCapture();
+
+static void unregWinClasses();
+
+extern QCursor *qt_grab_cursor();
+
+#if defined(Q_WS_WIN)
+#define __export
+#endif
+
+extern "C" LRESULT QT_WIN_CALLBACK QtWndProc(HWND, UINT, WPARAM, LPARAM);
+
+class QETWidget : public QWidget // event translator widget
+{
+public:
+ QWExtra *xtra() { return d_func()->extraData(); }
+ QTLWExtra *topData() { return d_func()->topData(); }
+ QTLWExtra *maybeTopData() { return d_func()->maybeTopData(); }
+ void syncBackingStore(const QRegion &rgn) { d_func()->syncBackingStore(rgn); }
+ void syncBackingStore() { d_func()->syncBackingStore(); }
+ QWidgetData *dataPtr() { return data; }
+ QWidgetPrivate *dptr() { return d_func(); }
+ QRect frameStrut() const { return d_func()->frameStrut(); }
+ bool winEvent(MSG *m, long *r) { return QWidget::winEvent(m, r); }
+ void markFrameStrutDirty() { data->fstrut_dirty = 1; }
+ bool translateMouseEvent(const MSG &msg);
+ bool translateWheelEvent(const MSG &msg);
+ bool translatePaintEvent(const MSG &msg);
+ bool translateConfigEvent(const MSG &msg);
+ bool translateCloseEvent(const MSG &msg);
+ bool translateTabletEvent(const MSG &msg, PACKET *localPacketBuf, int numPackets);
+#ifndef QT_NO_GESTURES
+ bool translateGestureEvent(const MSG &msg, const GESTUREINFO &gi);
+#endif
+ void repolishStyle(QStyle &style);
+ inline void showChildren(bool spontaneous) { d_func()->showChildren(spontaneous); }
+ inline void hideChildren(bool spontaneous) { d_func()->hideChildren(spontaneous); }
+ inline uint testWindowState(uint teststate){ return dataPtr()->window_state & teststate; }
+ inline void setWindowTitle_helper(const QString &title) { d_func()->setWindowTitle_helper(title); }
+ inline void forceUpdate() {
+ QTLWExtra *tlwExtra = window()->d_func()->maybeTopData();
+ if (tlwExtra && tlwExtra->backingStore)
+ tlwExtra->backingStore->markDirty(rect(), this, true, true);
+ }
+};
+
+// need to get default font?
+extern bool qt_app_has_font;
+
+extern QFont qt_LOGFONTtoQFont(LOGFONT& lf,bool scale);
+
+static void qt_set_windows_color_resources()
+{
+ // Do the color settings
+ QPalette pal;
+ pal.setColor(QPalette::WindowText,
+ QColor(qt_colorref2qrgb(GetSysColor(COLOR_WINDOWTEXT))));
+ pal.setColor(QPalette::Button,
+ QColor(qt_colorref2qrgb(GetSysColor(COLOR_BTNFACE))));
+ pal.setColor(QPalette::Light,
+ QColor(qt_colorref2qrgb(GetSysColor(COLOR_BTNHIGHLIGHT))));
+ pal.setColor(QPalette::Dark,
+ QColor(qt_colorref2qrgb(GetSysColor(COLOR_BTNSHADOW))));
+ pal.setColor(QPalette::Mid, pal.button().color().darker(150));
+ pal.setColor(QPalette::Text,
+ QColor(qt_colorref2qrgb(GetSysColor(COLOR_WINDOWTEXT))));
+ pal.setColor(QPalette::BrightText,
+ QColor(qt_colorref2qrgb(GetSysColor(COLOR_BTNHIGHLIGHT))));
+ pal.setColor(QPalette::Base,
+ QColor(qt_colorref2qrgb(GetSysColor(COLOR_WINDOW))));
+ pal.setColor(QPalette::Window,
+ QColor(qt_colorref2qrgb(GetSysColor(COLOR_BTNFACE))));
+ pal.setColor(QPalette::ButtonText,
+ QColor(qt_colorref2qrgb(GetSysColor(COLOR_BTNTEXT))));
+ pal.setColor(QPalette::Midlight,
+ QColor(qt_colorref2qrgb(GetSysColor(COLOR_3DLIGHT))));
+ pal.setColor(QPalette::Shadow,
+ QColor(qt_colorref2qrgb(GetSysColor(COLOR_3DDKSHADOW))));
+ pal.setColor(QPalette::Highlight,
+ QColor(qt_colorref2qrgb(GetSysColor(COLOR_HIGHLIGHT))));
+ pal.setColor(QPalette::HighlightedText,
+ QColor(qt_colorref2qrgb(GetSysColor(COLOR_HIGHLIGHTTEXT))));
+
+#if defined(Q_WS_WINCE)
+ // ### hardcoded until I find out how to get it from the system settings.
+ pal.setColor(QPalette::LinkVisited, pal.highlight().color().dark(150));
+ pal.setColor(QPalette::Link, pal.highlight().color().light(130));
+ // Background == Base on Windows CE
+ if (qt_wince_is_smartphone() || qt_wince_is_pocket_pc())
+ pal.setColor(QPalette::Background, pal.base().color());
+#else
+ pal.setColor(QPalette::Link, Qt::blue);
+ pal.setColor(QPalette::LinkVisited, Qt::magenta);
+#endif
+
+
+
+ pal.setColor(QPalette::Inactive, QPalette::Button, pal.button().color());
+ pal.setColor(QPalette::Inactive, QPalette::Window, pal.background().color());
+ pal.setColor(QPalette::Inactive, QPalette::Light, pal.light().color());
+ pal.setColor(QPalette::Inactive, QPalette::Dark, pal.dark().color());
+
+ if (pal.midlight() == pal.button())
+ pal.setColor(QPalette::Midlight, pal.button().color().lighter(110));
+ if (pal.background() != pal.base()) {
+ pal.setColor(QPalette::Inactive, QPalette::Highlight, pal.color(QPalette::Inactive, QPalette::Window));
+ pal.setColor(QPalette::Inactive, QPalette::HighlightedText, pal.color(QPalette::Inactive, QPalette::Text));
+ }
+
+ const QColor bg = pal.background().color();
+ const QColor fg = pal.foreground().color(), btn = pal.button().color();
+ QColor disabled((fg.red()+btn.red())/2,(fg.green()+btn.green())/2,
+ (fg.blue()+btn.blue())/2);
+ pal.setColorGroup(QPalette::Disabled, pal.foreground(), pal.button(), pal.light(),
+ pal.dark(), pal.mid(), pal.text(), pal.brightText(), pal.base(), pal.background() );
+ pal.setColor(QPalette::Disabled, QPalette::WindowText, disabled);
+ pal.setColor(QPalette::Disabled, QPalette::Text, disabled);
+ pal.setColor(QPalette::Disabled, QPalette::ButtonText, disabled);
+ pal.setColor(QPalette::Disabled, QPalette::Highlight,
+ QColor(qt_colorref2qrgb(GetSysColor(COLOR_HIGHLIGHT))));
+ pal.setColor(QPalette::Disabled, QPalette::HighlightedText,
+ QColor(qt_colorref2qrgb(GetSysColor(COLOR_HIGHLIGHTTEXT))));
+ pal.setColor(QPalette::Disabled, QPalette::Base, bg);
+
+ QApplicationPrivate::setSystemPalette(pal);
+
+ QApplicationPrivate::initializeWidgetPaletteHash();
+
+ QColor ttip(qt_colorref2qrgb(GetSysColor(COLOR_INFOBK)));
+
+ QColor ttipText(qt_colorref2qrgb(GetSysColor(COLOR_INFOTEXT)));
+ {
+#ifndef QT_NO_TOOLTIP
+ QPalette tiplabel(pal);
+ tiplabel.setColor(QPalette::All, QPalette::Button, ttip);
+ tiplabel.setColor(QPalette::All, QPalette::Window, ttip);
+ tiplabel.setColor(QPalette::All, QPalette::Text, ttipText);
+ tiplabel.setColor(QPalette::All, QPalette::WindowText, ttipText);
+ tiplabel.setColor(QPalette::All, QPalette::ButtonText, ttipText);
+ tiplabel.setColor(QPalette::All, QPalette::Button, ttip);
+ tiplabel.setColor(QPalette::All, QPalette::Window, ttip);
+ tiplabel.setColor(QPalette::All, QPalette::Text, ttipText);
+ tiplabel.setColor(QPalette::All, QPalette::WindowText, ttipText);
+ tiplabel.setColor(QPalette::All, QPalette::ButtonText, ttipText);
+ const QColor fg = tiplabel.foreground().color(), btn = tiplabel.button().color();
+ QColor disabled((fg.red()+btn.red())/2,(fg.green()+btn.green())/2,
+ (fg.blue()+btn.blue())/2);
+ tiplabel.setColor(QPalette::Disabled, QPalette::WindowText, disabled);
+ tiplabel.setColor(QPalette::Disabled, QPalette::Text, disabled);
+ tiplabel.setColor(QPalette::Disabled, QPalette::Base, Qt::white);
+ tiplabel.setColor(QPalette::Disabled, QPalette::BrightText, Qt::white);
+ QToolTip::setPalette(tiplabel);
+#endif //QT_NO_TOOLTIP
+ }
+}
+
+static void qt_set_windows_font_resources()
+{
+#ifndef Q_WS_WINCE
+ NONCLIENTMETRICS ncm;
+ ncm.cbSize = FIELD_OFFSET(NONCLIENTMETRICS, lfMessageFont) + sizeof(LOGFONT);
+ SystemParametersInfo(SPI_GETNONCLIENTMETRICS, ncm.cbSize , &ncm, 0);
+
+ QFont menuFont = qt_LOGFONTtoQFont(ncm.lfMenuFont, true);
+ QFont messageFont = qt_LOGFONTtoQFont(ncm.lfMessageFont, true);
+ QFont statusFont = qt_LOGFONTtoQFont(ncm.lfStatusFont, true);
+ QFont titleFont = qt_LOGFONTtoQFont(ncm.lfCaptionFont, true);
+
+ LOGFONT lfIconTitleFont;
+ SystemParametersInfo(SPI_GETICONTITLELOGFONT, sizeof(lfIconTitleFont), &lfIconTitleFont, 0);
+ QFont iconTitleFont = qt_LOGFONTtoQFont(lfIconTitleFont, true);
+
+ QApplication::setFont(menuFont, "QMenu");
+ QApplication::setFont(menuFont, "QMenuBar");
+ QApplication::setFont(messageFont, "QMessageBox");
+ QApplication::setFont(statusFont, "QTipLabel");
+ QApplication::setFont(statusFont, "QStatusBar");
+ QApplication::setFont(titleFont, "Q3TitleBar");
+ QApplication::setFont(titleFont, "QWorkspaceTitleBar");
+ QApplication::setFont(iconTitleFont, "QAbstractItemView");
+ QApplication::setFont(iconTitleFont, "QDockWidgetTitle");
+
+#else
+ LOGFONT lf;
+ HGDIOBJ stockFont = GetStockObject(SYSTEM_FONT);
+ GetObject(stockFont, sizeof(lf), &lf);
+ QFont systemFont = qt_LOGFONTtoQFont(lf, true);
+ QApplicationPrivate::setSystemFont(systemFont);
+ QFont smallerFont = systemFont;
+ if (qt_wince_is_mobile()) {
+ smallerFont.setPointSize(systemFont.pointSize()-1);
+ QApplication::setFont(smallerFont, "QTabBar");
+ smallerFont.setBold(true);
+ QApplication::setFont(smallerFont, "QAbstractButton");
+ }
+#endif// Q_WS_WINCE
+}
+
+static void qt_win_read_cleartype_settings()
+{
+ UINT result = 0;
+#ifdef Q_OS_WINCE
+ if (SystemParametersInfo(SPI_GETFONTSMOOTHING, 0, &result, 0))
+ qt_cleartype_enabled = result;
+#else
+ if (SystemParametersInfo(SPI_GETFONTSMOOTHINGTYPE, 0, &result, 0))
+ qt_cleartype_enabled = (result == FE_FONTSMOOTHINGCLEARTYPE);
+#endif
+
+ int winSmooth;
+ if (SystemParametersInfo(0x200C /* SPI_GETFONTSMOOTHINGCONTRAST */, 0, &winSmooth, 0)) {
+ qt_fontsmoothing_gamma = winSmooth / qreal(1000.0);
+ } else {
+ qt_fontsmoothing_gamma = 1.0;
+ }
+
+ // Safeguard ourselves against corrupt registry values...
+ if (qt_fontsmoothing_gamma > 5 || qt_fontsmoothing_gamma < 1)
+ qt_fontsmoothing_gamma = qreal(1.4);
+}
+
+static void qt_set_windows_resources()
+{
+ if (QApplication::type() != QApplication::Tty)
+ (void) QApplication::style(); // trigger creation of application style
+ qt_set_windows_font_resources();
+ qt_set_windows_color_resources();
+}
+
+void QApplicationPrivate::initializeWidgetPaletteHash()
+{
+ QPalette pal = *QApplicationPrivate::sys_pal;
+ QColor menuCol(qt_colorref2qrgb(GetSysColor(COLOR_MENU)));
+ QColor menuText(qt_colorref2qrgb(GetSysColor(COLOR_MENUTEXT)));
+ BOOL isFlat = false;
+ if ((QSysInfo::WindowsVersion >= QSysInfo::WV_XP
+ && QSysInfo::WindowsVersion < QSysInfo::WV_NT_based))
+ SystemParametersInfo(SPI_GETFLATMENU, 0, &isFlat, 0);
+ QPalette menu(pal);
+ // we might need a special color group for the menu.
+ menu.setColor(QPalette::Active, QPalette::Button, menuCol);
+ menu.setColor(QPalette::Active, QPalette::Text, menuText);
+ menu.setColor(QPalette::Active, QPalette::WindowText, menuText);
+ menu.setColor(QPalette::Active, QPalette::ButtonText, menuText);
+ const QColor fg = menu.foreground().color(), btn = menu.button().color();
+ QColor disabled(qt_colorref2qrgb(GetSysColor(COLOR_GRAYTEXT)));
+ menu.setColor(QPalette::Disabled, QPalette::WindowText, disabled);
+ menu.setColor(QPalette::Disabled, QPalette::Text, disabled);
+ menu.setColor(QPalette::Disabled, QPalette::Highlight,
+ QColor(qt_colorref2qrgb(GetSysColor(
+ (QSysInfo::WindowsVersion >= QSysInfo::WV_XP
+ && QSysInfo::WindowsVersion < QSysInfo::WV_NT_based)
+ && isFlat ? COLOR_MENUHILIGHT : COLOR_HIGHLIGHT))));
+ menu.setColor(QPalette::Disabled, QPalette::HighlightedText, disabled);
+ menu.setColor(QPalette::Disabled, QPalette::Button,
+ menu.color(QPalette::Active, QPalette::Button));
+ menu.setColor(QPalette::Inactive, QPalette::Button,
+ menu.color(QPalette::Active, QPalette::Button));
+ menu.setColor(QPalette::Inactive, QPalette::Text,
+ menu.color(QPalette::Active, QPalette::Text));
+ menu.setColor(QPalette::Inactive, QPalette::WindowText,
+ menu.color(QPalette::Active, QPalette::WindowText));
+ menu.setColor(QPalette::Inactive, QPalette::ButtonText,
+ menu.color(QPalette::Active, QPalette::ButtonText));
+ menu.setColor(QPalette::Inactive, QPalette::Highlight,
+ menu.color(QPalette::Active, QPalette::Highlight));
+ menu.setColor(QPalette::Inactive, QPalette::HighlightedText,
+ menu.color(QPalette::Active, QPalette::HighlightedText));
+ menu.setColor(QPalette::Inactive, QPalette::ButtonText,
+ pal.color(QPalette::Inactive, QPalette::Dark));
+ QApplication::setPalette(menu, "QMenu");
+
+ if ((QSysInfo::WindowsVersion >= QSysInfo::WV_XP
+ && QSysInfo::WindowsVersion < QSysInfo::WV_NT_based) && isFlat) {
+ QColor menubar(qt_colorref2qrgb(GetSysColor(COLOR_MENUBAR)));
+ menu.setColor(QPalette::Active, QPalette::Button, menubar);
+ menu.setColor(QPalette::Disabled, QPalette::Button, menubar);
+ menu.setColor(QPalette::Inactive, QPalette::Button, menubar);
+ }
+ QApplication::setPalette(menu, "QMenuBar");
+}
+
+static void qt_set_windows_updateScrollBar(QWidget *widget)
+{
+ QList<QObject*> children = widget->children();
+ for (int i = 0; i < children.size(); ++i) {
+ QObject *o = children.at(i);
+ if(!o->isWidgetType())
+ continue;
+ if (QWidget *w = static_cast<QWidget *>(o))
+ qt_set_windows_updateScrollBar(w);
+ }
+#ifndef QT_NO_SCROLLBAR
+ if (qobject_cast<QScrollBar*>(widget))
+ widget->updateGeometry();
+#endif
+}
+
+
+/*****************************************************************************
+ qt_init() - initializes Qt for Windows
+ *****************************************************************************/
+
+typedef BOOL (WINAPI *PtrSetProcessDPIAware) (VOID);
+static PtrSetProcessDPIAware ptrSetProcessDPIAware = 0;
+PtrUpdateLayeredWindow ptrUpdateLayeredWindow = 0;
+PtrUpdateLayeredWindowIndirect ptrUpdateLayeredWindowIndirect = 0;
+static BOOL WINAPI qt_updateLayeredWindowIndirect(HWND hwnd, const Q_UPDATELAYEREDWINDOWINFO *info)
+{
+ return (*ptrUpdateLayeredWindow)(hwnd, info->hdcDst, info->pptDst, info->psize, info->hdcSrc,
+ info->pptSrc, info->crKey, info->pblend, info->dwFlags);
+}
+
+void qt_init(QApplicationPrivate *priv, int)
+{
+
+ int argc = priv->argc;
+ char **argv = priv->argv;
+ int i, j;
+
+ // Get command line params
+
+ j = argc ? 1 : 0;
+ for (i=1; i<argc; i++) {
+ if (argv[i] && *argv[i] != '-') {
+ argv[j++] = argv[i];
+ continue;
+ }
+#if defined(QT_DEBUG)
+ if (qstrcmp(argv[i], "-nograb") == 0)
+ appNoGrab = !appNoGrab;
+ else
+#endif // QT_DEBUG
+ argv[j++] = argv[i];
+ }
+ if(j < priv->argc) {
+ priv->argv[j] = 0;
+ priv->argc = j;
+ }
+
+#ifndef Q_WS_WINCE
+ // No message boxes but important ones
+ SetErrorMode(SetErrorMode(0) | SEM_FAILCRITICALERRORS|SEM_NOOPENFILEERRORBOX);
+#endif
+
+#ifndef Q_WS_WINCE
+ // Initialize OLE/COM
+ // S_OK means success and S_FALSE means that it has already
+ // been initialized
+ HRESULT r;
+ r = OleInitialize(0);
+ if (r != S_OK && r != S_FALSE) {
+ qWarning("Qt: Could not initialize OLE (error %x)", (unsigned int)r);
+ }
+#endif
+
+ // Misc. initialization
+#if defined(QT_DEBUG) && !defined(Q_WS_WINCE)
+ GdiSetBatchLimit(1);
+#endif
+
+ // initialize key mapper
+ QKeyMapper::changeKeyboard();
+
+ QColormap::initialize();
+ QFont::initialize();
+#ifndef QT_NO_CURSOR
+ QCursorData::initialize();
+#endif
+ qApp->setObjectName(priv->appName());
+
+ // default font
+#ifndef Q_WS_WINCE
+ HGDIOBJ stockFont = GetStockObject(DEFAULT_GUI_FONT);
+#else
+ HGDIOBJ stockFont = GetStockObject(SYSTEM_FONT);
+#endif
+
+ LOGFONT lf;
+ GetObject(stockFont, sizeof(lf), &lf);
+ QFont systemFont = qt_LOGFONTtoQFont(lf, true);
+
+#ifndef Q_WS_WINCE
+ if (systemFont.family() == QLatin1String("MS Shell Dlg")) {
+ systemFont.setFamily(QLatin1String("MS Shell Dlg 2"));
+ }
+#endif
+
+ QApplicationPrivate::setSystemFont(systemFont);
+
+ // QFont::locale_init(); ### Uncomment when it does something on Windows
+
+ if (QApplication::desktopSettingsAware())
+ qt_set_windows_resources();
+
+#ifndef QT_NO_TABLETEVENT
+ initWinTabFunctions();
+#endif // QT_NO_TABLETEVENT
+ QApplicationPrivate::inputContext = new QWinInputContext(0);
+
+ // Read the initial cleartype settings...
+ qt_win_read_cleartype_settings();
+ qt_win_owndc_required = false;
+
+ extern void qt_win_initialize_directdraw();
+ qt_win_initialize_directdraw();
+
+#ifndef Q_OS_WINCE
+ ptrUpdateLayeredWindowIndirect =
+ (PtrUpdateLayeredWindowIndirect) QSystemLibrary::resolve(QLatin1String("user32"),
+ "UpdateLayeredWindowIndirect");
+ ptrUpdateLayeredWindow =
+ (PtrUpdateLayeredWindow) QSystemLibrary::resolve(QLatin1String("user32"),
+ "UpdateLayeredWindow");
+
+ if (ptrUpdateLayeredWindow && !ptrUpdateLayeredWindowIndirect)
+ ptrUpdateLayeredWindowIndirect = qt_updateLayeredWindowIndirect;
+
+ // Notify Vista and Windows 7 that we support highter DPI settings
+ ptrSetProcessDPIAware = (PtrSetProcessDPIAware)
+ QSystemLibrary::resolve(QLatin1String("user32"), "SetProcessDPIAware");
+ if (ptrSetProcessDPIAware)
+ ptrSetProcessDPIAware();
+#endif
+
+#ifndef QT_NO_GESTURES
+ priv->GetGestureInfo = 0;
+ priv->GetGestureExtraArgs = 0;
+ priv->CloseGestureInfoHandle = 0;
+ priv->SetGestureConfig = 0;
+ priv->GetGestureConfig = 0;
+ priv->BeginPanningFeedback = 0;
+ priv->UpdatePanningFeedback = 0;
+ priv->EndPanningFeedback = 0;
+
+#if defined(Q_WS_WINCE_WM) && defined(QT_WINCE_GESTURES)
+ priv->GetGestureInfo = (PtrGetGestureInfo) &TKGetGestureInfo;
+ priv->GetGestureExtraArgs = (PtrGetGestureExtraArgs) &TKGetGestureExtraArguments;
+#elif !defined(Q_WS_WINCE)
+ #if !defined(QT_NO_NATIVE_GESTURES)
+ priv->GetGestureInfo =
+ (PtrGetGestureInfo)QSystemLibrary::resolve(QLatin1String("user32"),
+ "GetGestureInfo");
+ priv->GetGestureExtraArgs =
+ (PtrGetGestureExtraArgs)QSystemLibrary::resolve(QLatin1String("user32"),
+ "GetGestureExtraArgs");
+ priv->CloseGestureInfoHandle =
+ (PtrCloseGestureInfoHandle)QSystemLibrary::resolve(QLatin1String("user32"),
+ "CloseGestureInfoHandle");
+ priv->SetGestureConfig =
+ (PtrSetGestureConfig)QSystemLibrary::resolve(QLatin1String("user32"),
+ "SetGestureConfig");
+ priv->GetGestureConfig =
+ (PtrGetGestureConfig)QSystemLibrary::resolve(QLatin1String("user32"),
+ "GetGestureConfig");
+ #endif // QT_NO_NATIVE_GESTURES
+ QSystemLibrary libTheme(QLatin1String("uxtheme"));
+ priv->BeginPanningFeedback =
+ (PtrBeginPanningFeedback)libTheme.resolve("BeginPanningFeedback");
+ priv->UpdatePanningFeedback =
+ (PtrUpdatePanningFeedback)libTheme.resolve("UpdatePanningFeedback");
+ priv->EndPanningFeedback =
+ (PtrEndPanningFeedback)libTheme.resolve("EndPanningFeedback");
+#endif
+#endif // QT_NO_GESTURES
+}
+
+/*****************************************************************************
+ qt_cleanup() - cleans up when the application is finished
+ *****************************************************************************/
+
+void qt_cleanup()
+{
+ unregWinClasses();
+ QPixmapCache::clear();
+
+#ifndef QT_NO_CURSOR
+ QCursorData::cleanup();
+#endif
+ QFont::cleanup();
+ QColormap::cleanup();
+ if (displayDC) {
+ ReleaseDC(0, displayDC);
+ displayDC = 0;
+ }
+
+ delete QApplicationPrivate::inputContext;
+ QApplicationPrivate::inputContext = 0;
+
+#ifndef Q_WS_WINCE
+ // Deinitialize OLE/COM
+ OleUninitialize();
+#endif
+}
+
+
+/*****************************************************************************
+ Platform specific global and internal functions
+ *****************************************************************************/
+
+Q_GUI_EXPORT HDC qt_win_display_dc() // get display DC
+{
+ Q_ASSERT(qApp && qApp->thread() == QThread::currentThread());
+ if (!displayDC)
+ displayDC = GetDC(0);
+ return displayDC;
+}
+
+bool qt_nograb() // application no-grab option
+{
+#if defined(QT_DEBUG)
+ return appNoGrab;
+#else
+ return false;
+#endif
+}
+
+typedef QHash<QString, int> WinClassNameHash;
+Q_GLOBAL_STATIC(WinClassNameHash, winclassNames)
+
+//
+// If 0 is passed as the widget pointer, register a window class
+// for QWidget as default. This is used in QGLTemporaryContext
+// during GL initialization, where we don't want to use temporary
+// QWidgets or QGLWidgets, neither do we want to have separate code
+// to register window classes.
+//
+const QString qt_reg_winclass(QWidget *w) // register window class
+{
+ Qt::WindowFlags flags = w ? w->windowFlags() : (Qt::WindowFlags)0;
+ Qt::WindowFlags type = flags & Qt::WindowType_Mask;
+
+ uint style;
+ bool icon;
+ QString cname;
+ if (w && qt_widget_private(w)->isGLWidget) {
+ cname = QLatin1String("QGLWidget");
+ style = CS_DBLCLKS;
+#ifndef Q_WS_WINCE
+ style |= CS_OWNDC;
+#endif
+ icon = true;
+ } else if (w && (flags & Qt::MSWindowsOwnDC)) {
+ cname = QLatin1String("QWidgetOwnDC");
+ style = CS_DBLCLKS;
+#ifndef Q_WS_WINCE
+ style |= CS_OWNDC;
+#endif
+ icon = true;
+ } else if (w && (type == Qt::Tool || type == Qt::ToolTip)) {
+ style = CS_DBLCLKS;
+ if (w->inherits("QTipLabel") || w->inherits("QAlphaWidget")) {
+ if ((QSysInfo::WindowsVersion >= QSysInfo::WV_XP
+ && QSysInfo::WindowsVersion < QSysInfo::WV_NT_based)) {
+ style |= CS_DROPSHADOW;
+ }
+ cname = QLatin1String("QToolTip");
+ } else {
+ cname = QLatin1String("QTool");
+ }
+#ifndef Q_WS_WINCE
+ style |= CS_SAVEBITS;
+#endif
+ icon = false;
+ } else if (w && (type == Qt::Popup)) {
+ cname = QLatin1String("QPopup");
+ style = CS_DBLCLKS;
+#ifndef Q_WS_WINCE
+ style |= CS_SAVEBITS;
+#endif
+ if ((QSysInfo::WindowsVersion >= QSysInfo::WV_XP
+ && QSysInfo::WindowsVersion < QSysInfo::WV_NT_based))
+ style |= CS_DROPSHADOW;
+ icon = false;
+ } else {
+ cname = QLatin1String("QWidget");
+ style = CS_DBLCLKS;
+ icon = true;
+ }
+
+#ifndef Q_WS_WINCE
+ // force CS_OWNDC when the GL graphics system is
+ // used as the default renderer
+ if (qt_win_owndc_required)
+ style |= CS_OWNDC;
+#endif
+
+#ifdef Q_OS_WINCE
+ // We need to register the classes with the
+ // unique ID on WinCE to make sure we can
+ // move the windows to the front when starting
+ // a second instance.
+ wchar_t uniqueAppID[MAX_PATH];
+ GetModuleFileName(0, uniqueAppID, MAX_PATH);
+ cname = QString::number(RegisterWindowMessage(
+ (const wchar_t *) QString::fromWCharArray(uniqueAppID).toLower().replace(QLatin1Char('\\'),
+ QLatin1Char('_')).utf16()));
+#endif
+
+ // since multiple Qt versions can be used in one process
+ // each one has to have window class names with a unique name
+ // The first instance gets the unmodified name; if the class
+ // has already been registered by another instance of Qt then
+ // add an instance-specific ID, the address of the window proc.
+ static int classExists = -1;
+
+ if (classExists == -1) {
+ WNDCLASS wcinfo;
+ classExists = GetClassInfo((HINSTANCE)qWinAppInst(), (wchar_t*)cname.utf16(), &wcinfo);
+ classExists = classExists && wcinfo.lpfnWndProc != QtWndProc;
+ }
+
+ if (classExists)
+ cname += QString::number((quintptr)QtWndProc);
+
+ if (winclassNames()->contains(cname)) // already registered in our list
+ return cname;
+
+#ifndef Q_WS_WINCE
+ WNDCLASSEX wc;
+ wc.cbSize = sizeof(WNDCLASSEX);
+#else
+ WNDCLASS wc;
+#endif
+ wc.style = style;
+ wc.lpfnWndProc = (WNDPROC)QtWndProc;
+ wc.cbClsExtra = 0;
+ wc.cbWndExtra = 0;
+ wc.hInstance = qWinAppInst();
+ if (icon) {
+ wc.hIcon = (HICON)LoadImage(qWinAppInst(), L"IDI_ICON1", IMAGE_ICON, 0, 0, LR_DEFAULTSIZE);
+#ifndef Q_WS_WINCE
+ if (wc.hIcon) {
+ int sw = GetSystemMetrics(SM_CXSMICON);
+ int sh = GetSystemMetrics(SM_CYSMICON);
+ wc.hIconSm = (HICON)LoadImage(qWinAppInst(), L"IDI_ICON1", IMAGE_ICON, sw, sh, 0);
+ } else {
+ wc.hIcon = (HICON)LoadImage(0, IDI_APPLICATION, IMAGE_ICON, 0, 0, LR_DEFAULTSIZE | LR_SHARED);
+ wc.hIconSm = 0;
+ }
+#endif
+ } else {
+ wc.hIcon = 0;
+#ifndef Q_WS_WINCE
+ wc.hIconSm = 0;
+#endif
+ }
+ wc.hCursor = 0;
+#ifndef Q_WS_WINCE
+ HBRUSH brush = 0;
+ if (w && !qt_widget_private(w)->isGLWidget)
+ brush = (HBRUSH)GetSysColorBrush(COLOR_WINDOW);
+ wc.hbrBackground = brush;
+#else
+ wc.hbrBackground = 0;
+#endif
+ wc.lpszMenuName = 0;
+ wc.lpszClassName = (wchar_t*)cname.utf16();
+
+#ifndef Q_WS_WINCE
+ ATOM atom = RegisterClassEx(&wc);
+#else
+ ATOM atom = RegisterClass(&wc);
+#endif
+
+#ifndef QT_NO_DEBUG
+ if (!atom)
+ qErrnoWarning("QApplication::regClass: Registering window class failed.");
+#else
+ Q_UNUSED(atom);
+#endif
+
+ winclassNames()->insert(cname, 1);
+ return cname;
+}
+
+Q_GUI_EXPORT const QString qt_getRegisteredWndClass()
+{
+ return qt_reg_winclass(0);
+}
+
+static void unregWinClasses()
+{
+ WinClassNameHash *hash = winclassNames();
+ QHash<QString, int>::ConstIterator it = hash->constBegin();
+ while (it != hash->constEnd()) {
+ UnregisterClass((wchar_t*)it.key().utf16(), qWinAppInst());
+ ++it;
+ }
+ hash->clear();
+}
+
+
+/*****************************************************************************
+ Safe configuration (move,resize,setGeometry) mechanism to avoid
+ recursion when processing messages.
+ *****************************************************************************/
+
+struct QWinConfigRequest {
+ WId id; // widget to be configured
+ int req; // 0=move, 1=resize, 2=setGeo
+ int x, y, w, h; // request parameters
+};
+
+static QList<QWinConfigRequest*> *configRequests = 0;
+
+void qWinRequestConfig(WId id, int req, int x, int y, int w, int h)
+{
+ if (!configRequests) // create queue
+ configRequests = new QList<QWinConfigRequest*>;
+ QWinConfigRequest *r = new QWinConfigRequest;
+ r->id = id; // create new request
+ r->req = req;
+ r->x = x;
+ r->y = y;
+ r->w = w;
+ r->h = h;
+ configRequests->append(r); // store request in queue
+}
+
+static void qWinProcessConfigRequests() // perform requests in queue
+{
+ if (!configRequests)
+ return;
+ QWinConfigRequest *r;
+ for (;;) {
+ if (configRequests->isEmpty())
+ break;
+ r = configRequests->takeLast();
+ QWidget *w = QWidget::find(r->id);
+ QRect rect(r->x, r->y, r->w, r->h);
+ int req = r->req;
+ delete r;
+
+ if ( w ) { // widget exists
+ if (w->testAttribute(Qt::WA_WState_ConfigPending))
+ return; // biting our tail
+ if (req == 0)
+ w->move(rect.topLeft());
+ else if (req == 1)
+ w->resize(rect.size());
+ else
+ w->setGeometry(rect);
+ }
+ }
+ delete configRequests;
+ configRequests = 0;
+}
+
+
+/*****************************************************************************
+ GUI event dispatcher
+ *****************************************************************************/
+
+class QGuiEventDispatcherWin32 : public QEventDispatcherWin32
+{
+ Q_DECLARE_PRIVATE(QEventDispatcherWin32)
+public:
+ QGuiEventDispatcherWin32(QObject *parent = 0);
+ bool processEvents(QEventLoop::ProcessEventsFlags flags);
+};
+
+QGuiEventDispatcherWin32::QGuiEventDispatcherWin32(QObject *parent)
+ : QEventDispatcherWin32(parent)
+{
+ createInternalHwnd();
+}
+
+bool QGuiEventDispatcherWin32::processEvents(QEventLoop::ProcessEventsFlags flags)
+{
+ if (!QEventDispatcherWin32::processEvents(flags))
+ return false;
+
+ if (configRequests) // any pending configs?
+ qWinProcessConfigRequests();
+
+ return true;
+}
+
+void QApplicationPrivate::createEventDispatcher()
+{
+ Q_Q(QApplication);
+ if (q->type() != QApplication::Tty)
+ eventDispatcher = new QGuiEventDispatcherWin32(q);
+ else
+ eventDispatcher = new QEventDispatcherWin32(q);
+}
+
+/*****************************************************************************
+ Platform specific QApplication members
+ *****************************************************************************/
+
+#ifdef QT3_SUPPORT
+void QApplication::setMainWidget(QWidget *mainWidget)
+{
+ QApplicationPrivate::main_widget = mainWidget;
+ if (QApplicationPrivate::main_widget && windowIcon().isNull()
+ && QApplicationPrivate::main_widget->testAttribute(Qt::WA_SetWindowIcon))
+ setWindowIcon(QApplicationPrivate::main_widget->windowIcon());
+}
+#endif
+
+#ifndef QT_NO_CURSOR
+
+/*****************************************************************************
+ QApplication cursor stack
+ *****************************************************************************/
+
+void QApplication::setOverrideCursor(const QCursor &cursor)
+{
+ qApp->d_func()->cursor_list.prepend(cursor);
+ SetCursor(qApp->d_func()->cursor_list.first().handle());
+}
+
+void QApplication::restoreOverrideCursor()
+{
+ if (qApp->d_func()->cursor_list.isEmpty())
+ return;
+ qApp->d_func()->cursor_list.removeFirst();
+
+ if (!qApp->d_func()->cursor_list.isEmpty()) {
+ SetCursor(qApp->d_func()->cursor_list.first().handle());
+ } else {
+ QWidget *w = QWidget::find(curWin);
+ if (w)
+ SetCursor(w->cursor().handle());
+ else
+ SetCursor(QCursor(Qt::ArrowCursor).handle());
+ }
+}
+
+#endif
+
+/*
+ Internal function called from QWidget::setCursor()
+ force is true if this function is called from dispatchEnterLeave, it means that the
+ mouse is actually directly under this widget.
+*/
+
+#ifndef QT_NO_CURSOR
+void qt_win_set_cursor(QWidget *w, bool force)
+{
+ static QPointer<QWidget> lastUnderMouse = 0;
+ if (force) {
+ lastUnderMouse = w;
+ } else if (w->testAttribute(Qt::WA_WState_Created) && lastUnderMouse
+ && lastUnderMouse->effectiveWinId() == w->effectiveWinId()) {
+ w = lastUnderMouse;
+ }
+
+ if (!curWin && w && w->internalWinId())
+ return;
+ QWidget* cW = w && !w->internalWinId() ? w : QWidget::find(curWin);
+ if (!cW || cW->window() != w->window() ||
+ !cW->isVisible() || !cW->underMouse() || QApplication::overrideCursor())
+ return;
+
+ SetCursor(cW->cursor().handle());
+}
+#endif // QT_NO_CURSOR
+
+Qt::KeyboardModifiers qt_win_getKeyboardModifiers()
+{
+ Qt::KeyboardModifiers modifiers = Qt::NoModifier;
+ if (GetKeyState(VK_SHIFT) < 0)
+ modifiers |= Qt::ShiftModifier;
+ if (GetKeyState(VK_CONTROL) < 0)
+ modifiers |= Qt::ControlModifier;
+ if (GetKeyState(VK_MENU) < 0)
+ modifiers |= Qt::AltModifier;
+ return modifiers;
+}
+
+/*****************************************************************************
+ Routines to find a Qt widget from a screen position
+ *****************************************************************************/
+
+QWidget *QApplication::topLevelAt(const QPoint &pos)
+{
+ POINT p;
+ HWND win;
+ QWidget *w;
+ p.x = pos.x();
+ p.y = pos.y();
+ win = WindowFromPoint(p);
+ if (!win)
+ return 0;
+
+ w = QWidget::find(win);
+ while (!w && win) {
+ win = GetParent(win);
+ w = QWidget::find(win);
+ }
+ return w ? w->window() : 0;
+}
+
+void QApplication::beep()
+{
+ MessageBeep(MB_OK);
+}
+
+static void alert_widget(QWidget *widget, int duration)
+{
+#ifdef Q_OS_WINCE
+ Q_UNUSED(widget);
+ Q_UNUSED(duration);
+#else
+ bool stopFlash = duration < 0;
+
+ if (widget && (!widget->isActiveWindow() || stopFlash)) {
+ DWORD timeOut = GetCaretBlinkTime();
+ if (timeOut <= 0)
+ timeOut = 250;
+
+ UINT flashCount;
+ if (duration == 0)
+ flashCount = 10;
+ else
+ flashCount = duration/timeOut;
+
+ FLASHWINFO info;
+ info.cbSize = sizeof(info);
+ info.hwnd = widget->window()->winId();
+ info.dwFlags = stopFlash ? FLASHW_STOP : FLASHW_TRAY;
+ info.dwTimeout = stopFlash ? 0 : timeOut;
+ info.uCount = stopFlash ? 0 : flashCount;
+
+ FlashWindowEx(&info);
+ }
+#endif
+}
+
+void QApplication::alert(QWidget *widget, int duration)
+{
+ if (!QApplicationPrivate::checkInstance("alert"))
+ return;
+
+ if (widget) {
+ alert_widget(widget, duration);
+ } else {
+ const QWidgetList toplevels(topLevelWidgets());
+ for (int i = 0; i < toplevels.count(); ++i) {
+ QWidget *topLevel = toplevels.at(i);
+ alert_widget(topLevel, duration);
+ }
+ }
+}
+
+QString QApplicationPrivate::appName() const
+{
+ return QCoreApplicationPrivate::appName();
+}
+
+
+/*****************************************************************************
+ Main event loop
+ *****************************************************************************/
+
+extern uint qGlobalPostedEventsCount();
+
+void QApplication::winFocus(QWidget *widget, bool gotFocus)
+{
+ if (d_func()->inPopupMode()) // some delayed focus event to ignore
+ return;
+ if (gotFocus) {
+ setActiveWindow(widget);
+ if (QApplicationPrivate::active_window
+ && (QApplicationPrivate::active_window->windowType() == Qt::Dialog)) {
+ // raise the entire application, not just the dialog
+ QWidget* mw = QApplicationPrivate::active_window;
+#ifndef Q_WS_WINCE
+ while(mw->parentWidget() && (mw->windowType() == Qt::Dialog))
+ mw = mw->parentWidget()->window();
+ if (mw->testAttribute(Qt::WA_WState_Created) && mw != QApplicationPrivate::active_window)
+ SetWindowPos(mw->internalWinId(), HWND_TOP, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);
+#else
+ // On Desktop Windows, we set the first parent of the dialog on top
+ // Child windows will be automatically set above again.
+ // On Windows CE we pass no parent in CreateWindowEx as otherwise
+ // dialogs get embedded into the parent window. Thus we need to
+ // manually iterate and reactivate all windows from bottom up.
+ QList<QWidget*> raiseList;
+ raiseList.push_back(mw);
+ while(mw->parentWidget() && (mw->windowType() == Qt::Dialog)) {
+ mw = mw->parentWidget()->window();
+ raiseList.push_back(mw);
+ }
+ while(!raiseList.isEmpty()) {
+ mw = raiseList.takeLast();
+ if (mw->testAttribute(Qt::WA_WState_Created)) {
+ HWND state = HWND_TOP;
+ if (mw->windowFlags() & Qt::WindowStaysOnBottomHint)
+ state = HWND_BOTTOM;
+ else if (mw->windowFlags() & Qt::WindowStaysOnTopHint)
+ state = HWND_TOPMOST;
+ SetWindowPos(mw->internalWinId(), state, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);
+ }
+ }
+#endif
+ }
+ } else {
+ setActiveWindow(0);
+ }
+}
+
+
+//
+// QtWndProc() receives all messages from the main event loop
+//
+
+static bool inLoop = false;
+static int inputcharset = CP_ACP;
+
+#define RETURN(x) { inLoop=false;return x; }
+
+static bool qt_is_translatable_mouse_event(UINT message)
+{
+ return (((message >= WM_MOUSEFIRST && message <= WM_MOUSELAST) ||
+ (message >= WM_XBUTTONDOWN && message <= WM_XBUTTONDBLCLK))
+ && message != WM_MOUSEWHEEL
+ && message != WM_MOUSEHWHEEL)
+
+#ifndef Q_WS_WINCE
+ || (message >= WM_NCMOUSEMOVE && message <= WM_NCMBUTTONDBLCLK)
+#endif
+ ;
+}
+
+extern "C" LRESULT QT_WIN_CALLBACK QtWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ bool result = true;
+ QEvent::Type evt_type = QEvent::None;
+ QETWidget *widget = 0;
+
+ // there is no need to process pakcets from tablet unless
+ // it is actually on the tablet, a flag to let us know...
+ int nPackets; // the number of packets we get from the queue
+
+ long res = 0;
+ if (!qApp) // unstable app state
+ RETURN(QWinInputContext::DefWindowProc(hwnd,message,wParam,lParam))
+
+ QScopedLoopLevelCounter loopLevelCounter(QThreadData::get2(qApp->thread()));
+
+#if 0
+ // make sure we update widgets also when the user resizes
+ if (inLoop && qApp->loopLevel())
+ qApp->sendPostedEvents(0, QEvent::Paint);
+#endif
+
+ inLoop = true;
+
+ MSG msg;
+ msg.hwnd = hwnd; // create MSG structure
+ msg.message = message; // time and pt fields ignored
+ msg.wParam = wParam;
+ msg.lParam = lParam;
+ msg.pt.x = GET_X_LPARAM(lParam);
+ msg.pt.y = GET_Y_LPARAM(lParam);
+ // If it's a non-client-area message the coords are screen coords, otherwise they are
+ // client coords.
+#ifndef Q_WS_WINCE
+ if (message < WM_NCMOUSEMOVE || message > WM_NCMBUTTONDBLCLK)
+#endif
+ ClientToScreen(msg.hwnd, &msg.pt);
+
+ /*
+ // sometimes the autograb is not released, so the clickevent is sent
+ // to the wrong window. We ignore this for now, because it doesn't
+ // cause any problems.
+ if (msg.message == WM_LBUTTONDOWN || msg.message == WM_RBUTTONDOWN || msg.message == WM_MBUTTONDOWN) {
+ HWND handle = WindowFromPoint(msg.pt);
+ if (msg.hwnd != handle) {
+ msg.hwnd = handle;
+ hwnd = handle;
+ }
+ }
+ */
+
+#if defined(QT_NON_COMMERCIAL)
+ QT_NC_WNDPROC
+#endif
+
+ // send through app filter
+ if (qApp->filterEvent(&msg, &res))
+ return res;
+
+ // close any opened ime candidate window (enabled only on a popup widget)
+ if (imeParentWnd && QApplication::activePopupWidget()
+ && (message == WM_MBUTTONDOWN || message == WM_XBUTTONDOWN
+ || message == WM_LBUTTONDOWN || message == WM_RBUTTONDOWN
+#ifndef Q_WS_WINCE
+ || message == WM_NCMBUTTONDOWN || message == WM_NCLBUTTONDOWN
+ || message == WM_NCRBUTTONDOWN)) {
+#else
+ )) {
+#endif
+ ::SendMessage(imeParentWnd, WM_IME_ENDCOMPOSITION, 0, 0);
+ }
+
+ switch (message) {
+#ifndef Q_WS_WINCE
+#ifndef QT_NO_SESSIONMANAGER
+ case WM_QUERYENDSESSION: {
+ if (sm_smActive) // bogus message from windows
+ RETURN(true);
+
+ sm_smActive = true;
+ sm_blockUserInput = true; // prevent user-interaction outside interaction windows
+ sm_cancel = false;
+ if (qt_session_manager_self)
+ qApp->commitData(*qt_session_manager_self);
+ if (lParam & ENDSESSION_LOGOFF) {
+ _flushall();
+ }
+ RETURN(!sm_cancel);
+ }
+ case WM_ENDSESSION: {
+ sm_smActive = false;
+ sm_blockUserInput = false;
+ bool endsession = (bool) wParam;
+
+ // we receive the message for each toplevel window included internal hidden ones,
+ // but the aboutToQuit signal should be emitted only once.
+ QApplicationPrivate *qAppPriv = QApplicationPrivate::instance();
+ if (endsession && !qAppPriv->aboutToQuitEmitted) {
+ qAppPriv->aboutToQuitEmitted = true;
+ int index = QApplication::staticMetaObject.indexOfSignal("aboutToQuit()");
+ qApp->qt_metacall(QMetaObject::InvokeMetaMethod, index,0);
+ // since the process will be killed immediately quit() has no real effect
+ QApplication::quit();
+ }
+
+ RETURN(0);
+ }
+#endif
+ case WM_DISPLAYCHANGE:
+ if (QApplication::type() == QApplication::Tty)
+ break;
+ if (qt_desktopWidget) {
+ qt_desktopWidget->move(GetSystemMetrics(76), GetSystemMetrics(77));
+ QSize sz(GetSystemMetrics(78), GetSystemMetrics(79));
+ if (sz == qt_desktopWidget->size()) {
+ // a screen resized without changing size of the virtual desktop
+ QResizeEvent rs(sz, qt_desktopWidget->size());
+ QApplication::sendEvent(qt_desktopWidget, &rs);
+ } else {
+ qt_desktopWidget->resize(sz);
+ }
+ }
+ break;
+#endif
+
+ case WM_SETTINGCHANGE:
+#ifdef Q_WS_WINCE
+ // CE SIP hide/show
+ if (qt_desktopWidget && wParam == SPI_SETSIPINFO) {
+ QResizeEvent re(QSize(0, 0), QSize(0, 0)); // Calculated by QDesktopWidget
+ QApplication::sendEvent(qt_desktopWidget, &re);
+ break;
+ }
+#endif
+ // ignore spurious XP message when user logs in again after locking
+ if (QApplication::type() == QApplication::Tty)
+ break;
+ if (QApplication::desktopSettingsAware() && wParam != SPI_SETWORKAREA) {
+ widget = (QETWidget*)QWidget::find(hwnd);
+ if (widget) {
+ if (wParam == SPI_SETNONCLIENTMETRICS)
+ widget->markFrameStrutDirty();
+ }
+ }
+ else if (qt_desktopWidget && wParam == SPI_SETWORKAREA) {
+ qt_desktopWidget->move(GetSystemMetrics(76), GetSystemMetrics(77));
+ QSize sz(GetSystemMetrics(78), GetSystemMetrics(79));
+ if (sz == qt_desktopWidget->size()) {
+ // a screen resized without changing size of the virtual desktop
+ QResizeEvent rs(sz, qt_desktopWidget->size());
+ QApplication::sendEvent(qt_desktopWidget, &rs);
+ } else {
+ qt_desktopWidget->resize(sz);
+ }
+ }
+
+ if (wParam == SPI_SETFONTSMOOTHINGTYPE) {
+ qt_win_read_cleartype_settings();
+ foreach (QWidget *w, QApplication::topLevelWidgets()) {
+ if (!w->isVisible())
+ continue;
+ ((QETWidget *) w)->forceUpdate();
+ }
+ }
+
+ break;
+ case WM_SYSCOLORCHANGE:
+ if (QApplication::type() == QApplication::Tty)
+ break;
+ if (QApplication::desktopSettingsAware()) {
+ widget = (QETWidget*)QWidget::find(hwnd);
+ if (widget && !widget->parentWidget())
+ qt_set_windows_color_resources();
+ }
+ break;
+
+ case WM_LBUTTONDOWN:
+ case WM_MBUTTONDOWN:
+ case WM_RBUTTONDOWN:
+ case WM_XBUTTONDOWN:
+ case WM_LBUTTONDBLCLK:
+ case WM_RBUTTONDBLCLK:
+ case WM_MBUTTONDBLCLK:
+ case WM_XBUTTONDBLCLK:
+ if (qt_win_ignoreNextMouseReleaseEvent)
+ qt_win_ignoreNextMouseReleaseEvent = false;
+ break;
+
+ case WM_LBUTTONUP:
+ case WM_MBUTTONUP:
+ case WM_RBUTTONUP:
+ case WM_XBUTTONUP:
+ if (qt_win_ignoreNextMouseReleaseEvent) {
+ qt_win_ignoreNextMouseReleaseEvent = false;
+ if (qt_button_down && qt_button_down->internalWinId() == autoCaptureWnd) {
+ releaseAutoCapture();
+ qt_button_down = 0;
+ }
+
+ RETURN(0);
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ if (!widget)
+ widget = (QETWidget*)QWidget::find(hwnd);
+ if (!widget) // don't know this widget
+ goto do_default;
+
+ if (app_do_modal) { // modal event handling
+ int ret = 0;
+ if (!qt_try_modal(widget, &msg, ret))
+ RETURN(ret);
+ }
+
+ res = 0;
+ if (widget->winEvent(&msg, &res)) // send through widget filter
+ RETURN(res);
+
+ if (qt_is_translatable_mouse_event(message)) {
+ if (QApplication::activePopupWidget() != 0) { // in popup mode
+ POINT curPos = msg.pt;
+ QWidget* w = QApplication::widgetAt(curPos.x, curPos.y);
+ if (w)
+ widget = (QETWidget*)w;
+ }
+
+ if (!qt_tabletChokeMouse) {
+ result = widget->translateMouseEvent(msg); // mouse event
+#if defined(Q_WS_WINCE) && !defined(QT_NO_CONTEXTMENU)
+ if (message == WM_LBUTTONDOWN && widget != QApplication::activePopupWidget()) {
+ QWidget* alienWidget = widget;
+ if ((alienWidget != QApplication::activePopupWidget()) && (alienWidget->contextMenuPolicy() != Qt::PreventContextMenu)) {
+ QPoint pos(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
+ QPoint globalPos(msg.pt.x, msg.pt.y);
+ // In case we are using Alien, then the widget to
+ // send the context menu event is a different one
+ if (!alienWidget->testAttribute(Qt::WA_NativeWindow) && !alienWidget->testAttribute(Qt::WA_PaintOnScreen)) {
+ alienWidget = QApplication::widgetAt(globalPos);
+ if (alienWidget)
+ pos = alienWidget->mapFromGlobal(globalPos);
+ }
+ if (alienWidget) {
+ SHRGINFO shrg;
+ shrg.cbSize = sizeof(shrg);
+ shrg.hwndClient = hwnd;
+ shrg.ptDown.x = GET_X_LPARAM(lParam);
+ shrg.ptDown.y = GET_Y_LPARAM(lParam);
+ shrg.dwFlags = SHRG_RETURNCMD | SHRG_NOANIMATION;
+ resolveAygLibs();
+#ifndef QT_NO_GESTURES
+ if (ptrRecognizeGesture && (ptrRecognizeGesture(&shrg) == GN_CONTEXTMENU)) {
+ if (QApplication::activePopupWidget())
+ QApplication::activePopupWidget()->close();
+ QContextMenuEvent e(QContextMenuEvent::Mouse, pos, globalPos);
+ result = qt_sendSpontaneousEvent(alienWidget, &e);
+ }
+#endif // QT_NO_GESTURES
+ }
+ }
+ }
+#endif
+ } else {
+ // Sometimes we only get a WM_MOUSEMOVE message
+ // and sometimes we get both a WM_MOUSEMOVE and
+ // a WM_LBUTTONDOWN/UP, this creates a spurious mouse
+ // press/release event, using the PeekMessage
+ // will help us fix this. This leaves us with a
+ // question:
+ // This effectively kills using the mouse AND the
+ // tablet simultaneously, well creates wacky input.
+ // Is this going to be a problem? (probably not)
+ bool next_is_button = false;
+ bool is_mouse_move = (message == WM_MOUSEMOVE);
+ if (is_mouse_move) {
+ MSG msg1;
+ if (PeekMessage(&msg1, msg.hwnd, WM_MOUSEFIRST,
+ WM_MOUSELAST, PM_NOREMOVE))
+ next_is_button = (msg1.message == WM_LBUTTONUP
+ || msg1.message == WM_LBUTTONDOWN);
+ }
+ if (!is_mouse_move || (is_mouse_move && !next_is_button))
+ qt_tabletChokeMouse = false;
+ }
+ } else {
+ switch (message) {
+ case WM_TOUCH:
+ result = QApplicationPrivate::instance()->translateTouchEvent(msg);
+ break;
+ case WM_KEYDOWN: // keyboard event
+ case WM_SYSKEYDOWN:
+ qt_keymapper_private()->updateKeyMap(msg);
+ // fall-through intended
+ case WM_KEYUP:
+ case WM_SYSKEYUP:
+#if Q_OS_WINCE_WM
+ case WM_HOTKEY:
+ if(HIWORD(msg.lParam) == VK_TBACK) {
+ const bool hotKeyDown = !(LOWORD(msg.lParam) & MOD_KEYUP);
+ msg.lParam = 0x69 << 16;
+ msg.wParam = VK_BACK;
+ if (hotKeyDown) {
+ msg.message = WM_KEYDOWN;
+ qt_keymapper_private()->updateKeyMap(msg);
+ } else {
+ msg.message = WM_KEYUP;
+ }
+ }
+ // fall-through intended
+#endif
+ case WM_IME_CHAR:
+ case WM_IME_KEYDOWN:
+ case WM_CHAR: {
+ MSG msg1;
+ bool anyMsg = PeekMessage(&msg1, msg.hwnd, 0, 0, PM_NOREMOVE);
+ if (anyMsg && msg1.message == WM_DEADCHAR) {
+ result = true; // consume event since there is a dead char next
+ break;
+ }
+ QWidget *g = QWidget::keyboardGrabber();
+ if (g && qt_get_tablet_widget() && hwnd == qt_get_tablet_widget()->winId()) {
+ // if we get an event for the internal tablet widget,
+ // then don't send it to the keyboard grabber, but
+ // send it to the widget itself (we don't use it right
+ // now, just in case).
+ g = 0;
+ }
+ if (g)
+ widget = (QETWidget*)g;
+ else if (QApplication::activePopupWidget())
+ widget = (QETWidget*)QApplication::activePopupWidget()->focusWidget()
+ ? (QETWidget*)QApplication::activePopupWidget()->focusWidget()
+ : (QETWidget*)QApplication::activePopupWidget();
+ else if (QApplication::focusWidget())
+ widget = (QETWidget*)QApplication::focusWidget();
+ else if (!widget || widget->internalWinId() == GetFocus()) // We faked the message to go to exactly that widget.
+ widget = (QETWidget*)widget->window();
+ if (widget->isEnabled())
+ result = sm_blockUserInput
+ ? true
+ : qt_keymapper_private()->translateKeyEvent(widget, msg, g != 0);
+ break;
+ }
+ case WM_SYSCHAR:
+ result = true; // consume event
+ break;
+
+ case WM_MOUSEWHEEL:
+ case WM_MOUSEHWHEEL:
+ result = widget->translateWheelEvent(msg);
+ break;
+
+ case WM_APPCOMMAND:
+ {
+ uint cmd = GET_APPCOMMAND_LPARAM(lParam);
+ uint uDevice = GET_DEVICE_LPARAM(lParam);
+ uint dwKeys = GET_KEYSTATE_LPARAM(lParam);
+
+ int state = translateButtonState(dwKeys, QEvent::KeyPress, 0);
+
+ switch (uDevice) {
+ case FAPPCOMMAND_KEY:
+ {
+ int key = 0;
+
+ switch(cmd) {
+ case APPCOMMAND_BASS_BOOST:
+ key = Qt::Key_BassBoost;
+ break;
+ case APPCOMMAND_BASS_DOWN:
+ key = Qt::Key_BassDown;
+ break;
+ case APPCOMMAND_BASS_UP:
+ key = Qt::Key_BassUp;
+ break;
+ case APPCOMMAND_TREBLE_DOWN:
+ key = Qt::Key_TrebleDown;
+ break;
+ case APPCOMMAND_TREBLE_UP:
+ key = Qt::Key_TrebleUp;
+ break;
+ case APPCOMMAND_HELP:
+ key = Qt::Key_Help;
+ break;
+ case APPCOMMAND_FIND:
+ key = Qt::Key_Search;
+ break;
+ default:
+ break;
+ }
+ if (key) {
+ bool res = false;
+ QWidget *g = QWidget::keyboardGrabber();
+ if (g)
+ widget = (QETWidget*)g;
+ else if (QApplication::focusWidget())
+ widget = (QETWidget*)QApplication::focusWidget();
+ else
+ widget = (QETWidget*)widget->window();
+ if (widget->isEnabled()) {
+ res = QKeyMapper::sendKeyEvent(widget, g != 0, QEvent::KeyPress, key,
+ Qt::KeyboardModifier(state),
+ QString(), false, 0, 0, 0, 0);
+ }
+ if (res)
+ return true;
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ result = false;
+ }
+ break;
+
+#ifndef Q_WS_WINCE
+ case WM_NCHITTEST:
+ if (widget->isWindow()) {
+ QPoint pos = widget->mapFromGlobal(QPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)));
+ // don't show resize-cursors for fixed-size widgets
+ QRect fs = widget->frameStrut();
+ if (!widget->isMinimized()) {
+ if (widget->minimumHeight() == widget->maximumHeight()) {
+ if (pos.y() < -(fs.top() - fs.left()))
+ return HTCAPTION;
+ if (pos.y() >= widget->height())
+ return HTBORDER;
+ }
+ if (widget->minimumWidth() == widget->maximumWidth() && (pos.x() < 0 || pos.x() >= widget->width()))
+ return HTBORDER;
+ }
+ }
+
+ result = false;
+ break;
+#endif
+
+ case WM_SYSCOMMAND: {
+#ifndef Q_WS_WINCE
+ bool window_state_change = false;
+ Qt::WindowStates oldstate = Qt::WindowStates(widget->dataPtr()->window_state);
+ // MSDN:In WM_SYSCOMMAND messages, the four low-order bits of the wParam parameter are
+ // used internally by the system. To obtain the correct result when testing the value of
+ // wParam, an application must combine the value 0xFFF0 with the wParam value by using
+ // the bitwise AND operator.
+ switch(0xfff0 & wParam) {
+ case SC_CONTEXTHELP:
+#ifndef QT_NO_WHATSTHIS
+ QWhatsThis::enterWhatsThisMode();
+#endif
+ DefWindowProc(hwnd, WM_NCPAINT, 1, 0);
+ break;
+#if defined(QT_NON_COMMERCIAL)
+ QT_NC_SYSCOMMAND
+#endif
+ case SC_MINIMIZE:
+ window_state_change = true;
+ widget->dataPtr()->window_state |= Qt::WindowMinimized;
+ if (widget->isVisible()) {
+ QHideEvent e;
+ qt_sendSpontaneousEvent(widget, &e);
+ widget->hideChildren(true);
+ const QString title = widget->windowIconText();
+ if (!title.isEmpty())
+ widget->setWindowTitle_helper(title);
+ }
+ result = false;
+ break;
+ case SC_MAXIMIZE:
+ if(widget->isWindow())
+ widget->topData()->normalGeometry = widget->geometry();
+ case SC_RESTORE:
+ window_state_change = true;
+ if ((0xfff0 & wParam) == SC_MAXIMIZE)
+ widget->dataPtr()->window_state |= Qt::WindowMaximized;
+ else if (!widget->isMinimized())
+ widget->dataPtr()->window_state &= ~Qt::WindowMaximized;
+
+ if (widget->isMinimized()) {
+ widget->dataPtr()->window_state &= ~Qt::WindowMinimized;
+ widget->showChildren(true);
+ QShowEvent e;
+ qt_sendSpontaneousEvent(widget, &e);
+ const QString title = widget->windowTitle();
+ if (!title.isEmpty())
+ widget->setWindowTitle_helper(title);
+ }
+ result = false;
+ break;
+ default:
+ result = false;
+ break;
+ }
+
+ if (window_state_change) {
+ QWindowStateChangeEvent e(oldstate);
+ qt_sendSpontaneousEvent(widget, &e);
+ }
+#endif // #ifndef Q_OS_WINCE
+
+ break;
+ }
+
+ case WM_SETTINGCHANGE:
+ if ( QApplication::type() == QApplication::Tty )
+ break;
+
+ if (!msg.wParam) {
+#ifdef Q_WS_WINCE
+ // On Windows CE, lParam parameter is a constant, not a char pointer.
+ if (msg.lParam == INI_INTL) {
+#else
+ QString area = QString::fromWCharArray((wchar_t*)msg.lParam);
+ if (area == QLatin1String("intl")) {
+#endif
+ QLocalePrivate::updateSystemPrivate();
+ if (!widget->testAttribute(Qt::WA_SetLocale))
+ widget->dptr()->setLocale_helper(QLocale(), true);
+ QEvent e(QEvent::LocaleChange);
+ QApplication::sendEvent(qApp, &e);
+ }
+ }
+ else if (msg.wParam == SPI_SETICONTITLELOGFONT) {
+ if (QApplication::desktopSettingsAware()) {
+ widget = (QETWidget*)QWidget::find(hwnd);
+ if (widget && !widget->parentWidget()) {
+ qt_set_windows_font_resources();
+ }
+ }
+ }
+ else if (msg.wParam == SPI_SETNONCLIENTMETRICS) {
+ widget = (QETWidget*)QWidget::find(hwnd);
+ if (widget && !widget->parentWidget()) {
+ qt_set_windows_updateScrollBar(widget);
+ QEvent e(QEvent::LayoutRequest);
+ QApplication::sendEvent(widget, &e);
+ }
+ }
+
+ break;
+
+ case WM_PAINT: // paint event
+ case WM_ERASEBKGND: // erase window background
+ result = widget->translatePaintEvent(msg);
+ break;
+
+#ifndef Q_WS_WINCE
+ case WM_ENTERSIZEMOVE:
+ autoCaptureWnd = hwnd;
+ break;
+ case WM_EXITSIZEMOVE:
+ autoCaptureWnd = 0;
+ break;
+#endif
+ case WM_MOVE: // move window
+ case WM_SIZE: // resize window
+ result = widget->translateConfigEvent(msg);
+ break;
+
+ case WM_ACTIVATEAPP:
+ if (wParam == FALSE) {
+ QApplication::setActiveWindow(0);
+ // Another application was activated while our popups are open,
+ // then close all popups. In case some popup refuses to close,
+ // we give up after 1024 attempts (to avoid an infinite loop).
+ int maxiter = 1024;
+ QWidget *popup;
+ while ((popup=QApplication::activePopupWidget()) && maxiter--)
+ popup->close();
+ }
+ break;
+
+ case WM_ACTIVATE:
+ if ( QApplication::type() == QApplication::Tty )
+ break;
+
+ if (ptrWTOverlap && ptrWTEnable) {
+ // cooperate with other tablet applications, but when
+ // we get focus, I want to use the tablet...
+ if (qt_tablet_context && GET_WM_ACTIVATE_STATE(wParam, lParam)) {
+ if (ptrWTEnable(qt_tablet_context, true))
+ ptrWTOverlap(qt_tablet_context, true);
+ }
+ }
+ if (QApplication::activePopupWidget() && LOWORD(wParam) == WA_INACTIVE &&
+ QWidget::find((HWND)lParam) == 0) {
+ // Another application was activated while our popups are open,
+ // then close all popups. In case some popup refuses to close,
+ // we give up after 1024 attempts (to avoid an infinite loop).
+ int maxiter = 1024;
+ QWidget *popup;
+ while ((popup=QApplication::activePopupWidget()) && maxiter--)
+ popup->close();
+ }
+
+ if (LOWORD(wParam) != WA_INACTIVE) {
+ // WM_ACTIVATEAPP handles the "true" false case, as this is only when the application
+ // loses focus. Doing it here would result in the widget getting focus to not know
+ // where it got it from; it would simply get a 0 value as the old focus widget.
+#ifdef Q_WS_WINCE
+ {
+#ifdef Q_WS_WINCE_WM
+ // On Windows mobile we do not receive WM_SYSCOMMAND / SC_MINIMIZE messages.
+ // Thus we have to unset the minimized state explicitly. We must do this for all
+ // top-level widgets, because we get the HWND of a random widget here.
+ foreach (QWidget* tlw, QApplication::topLevelWidgets()) {
+ if (tlw->isMinimized())
+ tlw->setWindowState(tlw->windowState() & ~Qt::WindowMinimized);
+ }
+#else
+ // On Windows CE we do not receive WM_SYSCOMMAND / SC_MINIMIZE messages.
+ // Thus we have to unset the minimized state explicitly.
+ if (widget->windowState() & Qt::WindowMinimized)
+ widget->setWindowState(widget->windowState() & ~Qt::WindowMinimized);
+#endif // Q_WS_WINCE_WM
+
+#else
+ if (!(widget->windowState() & Qt::WindowMinimized)) {
+#endif
+ // Ignore the activate message send by WindowsXP to a minimized window
+#ifdef Q_WS_WINCE_WM
+ if (widget->windowState() & Qt::WindowFullScreen)
+ qt_wince_hide_taskbar(widget->winId());
+#endif
+ qApp->winFocus(widget, true);
+ // reset any window alert flashes
+ alert_widget(widget, -1);
+ }
+ }
+
+ // Windows tries to activate a modally blocked window.
+ // This happens when restoring an application after "Show Desktop"
+ if (app_do_modal && LOWORD(wParam) == WA_ACTIVE) {
+ QWidget *top = 0;
+ if (!QApplicationPrivate::tryModalHelper(widget, &top) && top && widget != top) {
+ if (top->isVisible()) {
+ top->activateWindow();
+ } else {
+ // This is the case when native file dialogs are shown
+ QWidget *p = (top->parentWidget() ? top->parentWidget()->window() : 0);
+ if (p && p->isVisible())
+ p->activateWindow();
+ }
+ }
+ }
+ break;
+
+#ifndef Q_WS_WINCE
+ case WM_MOUSEACTIVATE:
+ if (widget->window()->windowType() == Qt::Tool) {
+ QWidget *w = widget;
+ if (!w->window()->focusWidget()) {
+ while (w && (w->focusPolicy() & Qt::ClickFocus) == 0) {
+ if (w->isWindow()) {
+ QWidget *fw = w;
+ while ((fw = fw->nextInFocusChain()) != w && fw->focusPolicy() == Qt::NoFocus)
+ ;
+ if (fw != w)
+ break;
+ QWidget *pw = w->parentWidget();
+ while (pw) {
+ pw = pw->window();
+ if (pw && pw->isVisible() && pw->focusWidget()) {
+ Q_ASSERT(pw->testAttribute(Qt::WA_WState_Created));
+ SetWindowPos(pw->internalWinId(), HWND_TOP, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
+ break;
+ }
+ pw = pw->parentWidget();
+ }
+ RETURN(MA_NOACTIVATE);
+ }
+ w = w->parentWidget();
+ }
+ }
+ }
+ RETURN(MA_ACTIVATE);
+ break;
+#endif
+ case WM_SHOWWINDOW:
+ if (lParam == SW_PARENTOPENING) {
+ if (widget->testAttribute(Qt::WA_WState_Hidden))
+ RETURN(0);
+ }
+ if (widget->isWindow() && widget->testAttribute(Qt::WA_WState_Visible)
+ && !widget->testWindowState(Qt::WindowMinimized)) {
+ if (lParam == SW_PARENTOPENING) {
+ QShowEvent e;
+ qt_sendSpontaneousEvent(widget, &e);
+ widget->showChildren(true);
+ } else if (lParam == SW_PARENTCLOSING) {
+ QHideEvent e;
+ qt_sendSpontaneousEvent(widget, &e);
+ widget->hideChildren(true);
+ }
+ }
+ if (!wParam && autoCaptureWnd == widget->internalWinId())
+ releaseAutoCapture();
+ result = false;
+ break;
+
+ case WM_PALETTECHANGED: // our window changed palette
+ if (QColormap::hPal() && (WId)wParam == widget->internalWinId())
+ RETURN(0); // otherwise: FALL THROUGH!
+ // FALL THROUGH
+ case WM_QUERYNEWPALETTE: // realize own palette
+ if (QColormap::hPal()) {
+ Q_ASSERT(widget->testAttribute(Qt::WA_WState_Created));
+ HDC hdc = GetDC(widget->internalWinId());
+ HPALETTE hpalOld = SelectPalette(hdc, QColormap::hPal(), FALSE);
+ uint n = RealizePalette(hdc);
+ if (n)
+ InvalidateRect(widget->internalWinId(), 0, TRUE);
+ SelectPalette(hdc, hpalOld, TRUE);
+ RealizePalette(hdc);
+ ReleaseDC(widget->internalWinId(), hdc);
+ RETURN(n);
+ }
+ break;
+ case WM_CLOSE: // close window
+ widget->translateCloseEvent(msg);
+ RETURN(0); // always handled
+
+ case WM_DESTROY: // destroy window
+ if (hwnd == curWin) {
+ QWidget *enter = QWidget::mouseGrabber();
+ if (enter == widget)
+ enter = 0;
+ QApplicationPrivate::dispatchEnterLeave(enter, widget);
+ curWin = enter ? enter->effectiveWinId() : 0;
+ qt_last_mouse_receiver = enter;
+ }
+ if (widget == popupButtonFocus)
+ popupButtonFocus = 0;
+ result = false;
+ break;
+
+#ifndef Q_WS_WINCE
+ case WM_WINDOWPOSCHANGING:
+ {
+ result = false;
+ if (widget->isWindow()) {
+ WINDOWPOS *winPos = (WINDOWPOS *)lParam;
+ if (widget->layout() && widget->layout()->hasHeightForWidth()
+ && !(winPos->flags & (SWP_NOCOPYBITS | SWP_NOSIZE))) {
+ QRect fs = widget->frameStrut();
+ QRect rect = widget->geometry();
+ QRect newRect = QRect(winPos->x + fs.left(),
+ winPos->y + fs.top(),
+ winPos->cx - fs.left() - fs.right(),
+ winPos->cy - fs.top() - fs.bottom());
+
+ QSize newSize = QLayout::closestAcceptableSize(widget, newRect.size());
+
+ int dh = newSize.height() - newRect.height();
+ int dw = newSize.width() - newRect.width();
+ if (!dw && ! dh)
+ break; // Size OK
+
+ if (rect.y() != newRect.y()) {
+ newRect.setTop(newRect.top() - dh);
+ } else {
+ newRect.setBottom(newRect.bottom() + dh);
+ }
+
+ if (rect.x() != newRect.x()) {
+ newRect.setLeft(newRect.left() - dw);
+ } else {
+ newRect.setRight(newRect.right() + dw);
+ }
+
+ winPos->x = newRect.x() - fs.left();
+ winPos->y = newRect.y() - fs.top();
+ winPos->cx = newRect.width() + fs.left() + fs.right();
+ winPos->cy = newRect.height() + fs.top() + fs.bottom();
+
+ RETURN(0);
+ }
+ if (widget->windowFlags() & Qt::WindowStaysOnBottomHint) {
+ winPos->hwndInsertAfter = HWND_BOTTOM;
+ }
+ }
+ }
+ break;
+
+ case WM_GETMINMAXINFO:
+ if (widget->xtra()) {
+ MINMAXINFO *mmi = (MINMAXINFO *)lParam;
+ QWExtra *x = widget->xtra();
+ QRect fs = widget->frameStrut();
+ if ( x->minw > 0 )
+ mmi->ptMinTrackSize.x = x->minw + fs.right() + fs.left();
+ if ( x->minh > 0 )
+ mmi->ptMinTrackSize.y = x->minh + fs.top() + fs.bottom();
+ qint32 maxw = (x->maxw >= x->minw) ? x->maxw : x->minw;
+ qint32 maxh = (x->maxh >= x->minh) ? x->maxh : x->minh;
+ if ( maxw < QWIDGETSIZE_MAX ) {
+ mmi->ptMaxTrackSize.x = maxw + fs.right() + fs.left();
+ // windows with title bar have an implicit size limit of 112 pixels
+ if (widget->windowFlags() & Qt::WindowTitleHint)
+ mmi->ptMaxTrackSize.x = qMax<long>(mmi->ptMaxTrackSize.x, 112);
+ }
+ if ( maxh < QWIDGETSIZE_MAX )
+ mmi->ptMaxTrackSize.y = maxh + fs.top() + fs.bottom();
+ RETURN(0);
+ }
+ break;
+
+#ifndef QT_NO_CONTEXTMENU
+ case WM_CONTEXTMENU:
+ {
+ // it's not VK_APPS or Shift+F10, but a click in the NC area
+ if (lParam != (int)0xffffffff) {
+ result = false;
+ break;
+ }
+
+ QWidget *fw = QWidget::keyboardGrabber();
+ if (!fw) {
+ if (QApplication::activePopupWidget())
+ fw = (QApplication::activePopupWidget()->focusWidget()
+ ? QApplication::activePopupWidget()->focusWidget()
+ : QApplication::activePopupWidget());
+ else if (QApplication::focusWidget())
+ fw = QApplication::focusWidget();
+ else if (widget)
+ fw = widget->window();
+ }
+ if (fw && fw->isEnabled()) {
+ QPoint pos = fw->inputMethodQuery(Qt::ImMicroFocus).toRect().center();
+ QContextMenuEvent e(QContextMenuEvent::Keyboard, pos, fw->mapToGlobal(pos),
+ qt_win_getKeyboardModifiers());
+ result = qt_sendSpontaneousEvent(fw, &e);
+ }
+ }
+ break;
+#endif
+#endif
+
+ case WM_IME_STARTCOMPOSITION:
+ case WM_IME_ENDCOMPOSITION:
+ case WM_IME_COMPOSITION: {
+ QWidget *fw = QApplication::focusWidget();
+ QWinInputContext *im = fw ? qobject_cast<QWinInputContext *>(fw->inputContext()) : 0;
+ if (fw && im) {
+ if(message == WM_IME_STARTCOMPOSITION)
+ result = im->startComposition();
+ else if (message == WM_IME_ENDCOMPOSITION)
+ result = im->endComposition();
+ else if (message == WM_IME_COMPOSITION)
+ result = im->composition(lParam);
+ }
+ break;
+ }
+ case WM_IME_REQUEST: {
+ QWidget *fw = QApplication::focusWidget();
+ QWinInputContext *im = fw ? qobject_cast<QWinInputContext *>(fw->inputContext()) : 0;
+ if (fw && im) {
+ if(wParam == IMR_RECONVERTSTRING) {
+ int ret = im->reconvertString((RECONVERTSTRING *)lParam);
+ if (ret == -1) {
+ result = false;
+ } else {
+ return ret;
+ }
+ } else if (wParam == IMR_CONFIRMRECONVERTSTRING) {
+ RETURN(TRUE);
+ } else {
+ // in all other cases, call DefWindowProc()
+ result = false;
+ }
+ }
+ break;
+ }
+#ifndef Q_WS_WINCE
+ case WM_CHANGECBCHAIN:
+ case WM_DRAWCLIPBOARD:
+#endif
+ case WM_RENDERFORMAT:
+ case WM_RENDERALLFORMATS:
+#ifndef QT_NO_CLIPBOARD
+ case WM_DESTROYCLIPBOARD:
+ if (qt_clipboard) {
+ QClipboardEvent e(reinterpret_cast<QEventPrivate *>(&msg));
+ qt_sendSpontaneousEvent(qt_clipboard, &e);
+ RETURN(0);
+ }
+ result = false;
+ break;
+#endif //QT_NO_CLIPBOARD
+#ifndef QT_NO_ACCESSIBILITY
+ case WM_GETOBJECT:
+ {
+ // Ignoring all requests while starting up
+ if (QApplication::startingUp() || QApplication::closingDown() || lParam != (LPARAM)OBJID_CLIENT) {
+ result = false;
+ break;
+ }
+
+ typedef LRESULT (WINAPI *PtrLresultFromObject)(REFIID, WPARAM, LPUNKNOWN);
+ static PtrLresultFromObject ptrLresultFromObject = 0;
+ static bool oleaccChecked = false;
+
+ if (!oleaccChecked) {
+ oleaccChecked = true;
+#if !defined(Q_OS_WINCE)
+ ptrLresultFromObject = (PtrLresultFromObject)QSystemLibrary::resolve(QLatin1String("oleacc"), "LresultFromObject");
+#endif
+ }
+ if (ptrLresultFromObject) {
+ QAccessibleInterface *acc = QAccessible::queryAccessibleInterface(widget);
+ if (!acc) {
+ result = false;
+ break;
+ }
+
+ // and get an instance of the IAccessibile implementation
+ IAccessible *iface = qt_createWindowsAccessible(acc);
+ res = ptrLresultFromObject(IID_IAccessible, wParam, iface); // ref == 2
+ iface->Release(); // the client will release the object again, and then it will destroy itself
+
+ if (res > 0)
+ RETURN(res);
+ }
+ }
+ result = false;
+ break;
+ case WM_GETTEXT:
+ if (!widget->isWindow()) {
+ int ret = 0;
+ QAccessibleInterface *acc = QAccessible::queryAccessibleInterface(widget);
+ if (acc) {
+ QString text = acc->text(QAccessible::Name, 0);
+ if (text.isEmpty())
+ text = widget->objectName();
+ ret = qMin<int>(wParam - 1, text.size());
+ text.resize(ret);
+ memcpy((void *)lParam, text.utf16(), (text.size() + 1) * sizeof(ushort));
+ delete acc;
+ }
+ if (!ret) {
+ result = false;
+ break;
+ }
+ RETURN(ret);
+ }
+ result = false;
+ break;
+#endif
+ case WT_PACKET:
+ if (ptrWTPacketsGet) {
+ if ((nPackets = ptrWTPacketsGet(qt_tablet_context, QT_TABLET_NPACKETQSIZE, &localPacketBuf))) {
+ result = widget->translateTabletEvent(msg, localPacketBuf, nPackets);
+ }
+ }
+ break;
+ case WT_PROXIMITY:
+
+ #ifndef QT_NO_TABLETEVENT
+ if (ptrWTPacketsGet && ptrWTInfo) {
+ const bool enteredProximity = LOWORD(lParam) != 0;
+ PACKET proximityBuffer[1]; // we are only interested in the first packet in this case
+ const int totalPacks = ptrWTPacketsGet(qt_tablet_context, 1, proximityBuffer);
+ if (totalPacks > 0) {
+ const UINT currentCursor = proximityBuffer[0].pkCursor;
+
+ UINT csr_physid;
+ ptrWTInfo(WTI_CURSORS + currentCursor, CSR_PHYSID, &csr_physid);
+ UINT csr_type;
+ ptrWTInfo(WTI_CURSORS + currentCursor, CSR_TYPE, &csr_type);
+ const UINT deviceIdMask = 0xFF6; // device type mask && device color mask
+ quint64 uniqueId = (csr_type & deviceIdMask);
+ uniqueId = (uniqueId << 32) | csr_physid;
+
+ // initialising and updating the cursor should be done in response to
+ // WT_CSRCHANGE. We do it in WT_PROXIMITY because some wintab never send
+ // the event WT_CSRCHANGE even if asked with CXO_CSRMESSAGES
+ const QTabletCursorInfo *const globalCursorInfo = tCursorInfo();
+ if (!globalCursorInfo->contains(uniqueId))
+ tabletInit(uniqueId, csr_type, qt_tablet_context);
+
+ currentTabletPointer = globalCursorInfo->value(uniqueId);
+ tabletUpdateCursor(currentTabletPointer, currentCursor);
+ }
+ qt_tabletChokeMouse = false;
+
+ QTabletEvent tabletProximity(enteredProximity ? QEvent::TabletEnterProximity
+ : QEvent::TabletLeaveProximity,
+ QPoint(), QPoint(), QPointF(), currentTabletPointer.currentDevice, currentTabletPointer.currentPointerType, 0, 0,
+ 0, 0, 0, 0, 0, currentTabletPointer.llId);
+ QApplication::sendEvent(qApp, &tabletProximity);
+ }
+ #endif // QT_NO_TABLETEVENT
+
+ break;
+#ifdef Q_WS_WINCE_WM
+ case WM_SETFOCUS: {
+ HIMC hC;
+ hC = ImmGetContext(hwnd);
+ ImmSetOpenStatus(hC, TRUE);
+ ImmEscape(NULL, hC, IME_ESC_SET_MODE, (LPVOID)IM_SPELL);
+ result = false;
+ }
+ break;
+#endif
+ case WM_KILLFOCUS:
+ if (!QWidget::find((HWND)wParam)) { // we don't get focus, so unset it now
+ if (!widget->hasFocus()) // work around Windows bug after minimizing/restoring
+ widget = (QETWidget*)QApplication::focusWidget();
+ HWND focus = ::GetFocus();
+ //if there is a current widget and the new widget belongs to the same toplevel window
+ //or if the current widget was embedded into non-qt window (i.e. we won't get WM_ACTIVATEAPP)
+ //then we clear the focus on the widget
+ //in case the new widget belongs to a different widget hierarchy, clearing the focus
+ //will be handled because the active window will change
+ const bool embedded = widget && ((QETWidget*)widget->window())->topData()->embedded;
+ if (widget && (embedded || ::IsChild(widget->window()->internalWinId(), focus))) {
+ widget->clearFocus();
+ result = true;
+ } else {
+ result = false;
+ }
+ } else {
+ result = false;
+ }
+ break;
+ case WM_THEMECHANGED:
+ if ((widget->windowType() == Qt::Desktop) || !qApp || QApplication::closingDown()
+ || QApplication::type() == QApplication::Tty)
+ break;
+
+ if (widget->testAttribute(Qt::WA_WState_Polished))
+ QApplication::style()->unpolish(widget);
+
+ if (widget->testAttribute(Qt::WA_WState_Polished))
+ QApplication::style()->polish(widget);
+ widget->repolishStyle(*QApplication::style());
+ if (widget->isVisible())
+ widget->update();
+ break;
+
+#ifndef Q_WS_WINCE
+ case WM_INPUTLANGCHANGE: {
+ wchar_t info[7];
+ if (!GetLocaleInfo(MAKELCID(lParam, SORT_DEFAULT), LOCALE_IDEFAULTANSICODEPAGE, info, 6)) {
+ inputcharset = CP_ACP;
+ } else {
+ inputcharset = QString::fromWCharArray(info).toInt();
+ }
+ QKeyMapper::changeKeyboard();
+ break;
+ }
+#else
+ case WM_COMMAND: {
+ bool OkCommand = (LOWORD(wParam) == 0x1);
+ bool CancelCommand = (LOWORD(wParam) == 0x2);
+ if (OkCommand)
+ QApplication::postEvent(widget, new QEvent(QEvent::OkRequest));
+ if (CancelCommand)
+ widget->showMinimized();
+ else
+#ifndef QT_NO_MENUBAR
+ QMenuBar::wceCommands(LOWORD(wParam));
+#endif
+ result = true;
+ }
+ break;
+ case WM_HELP:
+ QApplication::postEvent(widget, new QEvent(QEvent::HelpRequest));
+ result = true;
+ break;
+#endif
+
+ case WM_MOUSELEAVE:
+ // We receive a mouse leave for curWin, meaning
+ // the mouse was moved outside our widgets
+ if (widget->internalWinId() == curWin) {
+ bool dispatch = !widget->underMouse();
+ // hasMouse is updated when dispatching enter/leave,
+ // so test if it is actually up-to-date
+ if (!dispatch) {
+ QRect geom = widget->geometry();
+ if (widget->parentWidget() && !widget->isWindow()) {
+ QPoint gp = widget->parentWidget()->mapToGlobal(widget->pos());
+ geom.setX(gp.x());
+ geom.setY(gp.y());
+ }
+ QPoint cpos = QCursor::pos();
+ dispatch = !geom.contains(cpos);
+ if ( !dispatch && !QWidget::mouseGrabber()) {
+ QWidget *hittest = QApplication::widgetAt(cpos);
+ dispatch = !hittest || hittest->internalWinId() != curWin;
+ }
+ if (!dispatch) {
+ HRGN hrgn = qt_tryCreateRegion(QRegion::Rectangle, 0,0,0,0);
+ if (GetWindowRgn(curWin, hrgn) != ERROR) {
+ QPoint lcpos = widget->mapFromGlobal(cpos);
+ dispatch = !PtInRegion(hrgn, lcpos.x(), lcpos.y());
+ }
+ DeleteObject(hrgn);
+ }
+ }
+ if (dispatch) {
+ if (qt_last_mouse_receiver && !qt_last_mouse_receiver->internalWinId())
+ QApplicationPrivate::dispatchEnterLeave(0, qt_last_mouse_receiver);
+ else
+ QApplicationPrivate::dispatchEnterLeave(0, QWidget::find((WId)curWin));
+ curWin = 0;
+ qt_last_mouse_receiver = 0;
+ }
+ }
+ break;
+
+ case WM_CANCELMODE:
+ {
+ // this goes through QMenuBar's event filter
+ QEvent e(QEvent::ActivationChange);
+ QApplication::sendEvent(qApp, &e);
+ }
+ break;
+
+ case WM_IME_NOTIFY:
+ // special handling for ime, only for widgets in a popup
+ if (wParam == IMN_OPENCANDIDATE) {
+ imeParentWnd = hwnd;
+ if (QApplication::activePopupWidget()) {
+ // temporarily disable the mouse grab to allow mouse input in
+ // the ime candidate window. The actual handle is untouched
+ if (autoCaptureWnd)
+ ReleaseCapture();
+ }
+ } else if (wParam == IMN_CLOSECANDIDATE) {
+ imeParentWnd = 0;
+ if (QApplication::activePopupWidget()) {
+ // undo the action above, when candidate window is closed
+ if (autoCaptureWnd)
+ SetCapture(autoCaptureWnd);
+ }
+ }
+ result = false;
+ break;
+#ifndef QT_NO_GESTURES
+#if !defined(Q_WS_WINCE) || defined(QT_WINCE_GESTURES)
+ case WM_GESTURE: {
+ GESTUREINFO gi;
+ memset(&gi, 0, sizeof(GESTUREINFO));
+ gi.cbSize = sizeof(GESTUREINFO);
+
+ QApplicationPrivate *qAppPriv = QApplicationPrivate::instance();
+ BOOL bResult = false;
+ if (qAppPriv->GetGestureInfo)
+ bResult = qAppPriv->GetGestureInfo((HANDLE)msg.lParam, &gi);
+ if (bResult) {
+ if (gi.dwID == GID_BEGIN) {
+ // find the alien widget for the gesture position.
+ // This might not be accurate as the position is the center
+ // point of two fingers for multi-finger gestures.
+ QPoint pt(gi.ptsLocation.x, gi.ptsLocation.y);
+ QWidget *w = widget->childAt(widget->mapFromGlobal(pt));
+ qAppPriv->gestureWidget = w ? w : widget;
+ }
+ if (qAppPriv->gestureWidget)
+ static_cast<QETWidget*>(qAppPriv->gestureWidget)->translateGestureEvent(msg, gi);
+ if (qAppPriv->CloseGestureInfoHandle)
+ qAppPriv->CloseGestureInfoHandle((HANDLE)msg.lParam);
+ if (gi.dwID == GID_END)
+ qAppPriv->gestureWidget = 0;
+ } else {
+ DWORD dwErr = GetLastError();
+ if (dwErr > 0)
+ qWarning() << "translateGestureEvent: error = " << dwErr;
+ }
+ result = true;
+ break;
+ }
+#endif // !defined(Q_WS_WINCE) || defined(QT_WINCE_GESTURES)
+#endif // QT_NO_GESTURES
+#ifndef QT_NO_CURSOR
+ case WM_SETCURSOR: {
+ QCursor *ovr = QApplication::overrideCursor();
+ if (ovr) {
+ SetCursor(ovr->handle());
+ RETURN(TRUE);
+ }
+ result = false;
+ break;
+ }
+#endif
+ default:
+ result = false; // event was not processed
+ break;
+ }
+ }
+
+ if (evt_type != QEvent::None) { // simple event
+ QEvent e(evt_type);
+ result = qt_sendSpontaneousEvent(widget, &e);
+ }
+
+ if (result)
+ RETURN(false);
+
+do_default:
+ RETURN(QWinInputContext::DefWindowProc(hwnd,message,wParam,lParam))
+}
+
+
+/*****************************************************************************
+ Modal widgets; We have implemented our own modal widget mechanism
+ to get total control.
+ A modal widget without a parent becomes application-modal.
+ A modal widget with a parent becomes modal to its parent and grandparents..
+
+ QApplicationPrivate::enterModal()
+ Enters modal state
+ Arguments:
+ QWidget *widget A modal widget
+
+ QApplicationPrivate::leaveModal()
+ Leaves modal state for a widget
+ Arguments:
+ QWidget *widget A modal widget
+ *****************************************************************************/
+
+bool QApplicationPrivate::modalState()
+{
+ return app_do_modal;
+}
+
+void QApplicationPrivate::enterModal_sys(QWidget *widget)
+{
+ if (!qt_modal_stack)
+ qt_modal_stack = new QWidgetList;
+
+ releaseAutoCapture();
+ ClipCursor(0);
+ QWidget *leave = qt_last_mouse_receiver;
+ if (!leave)
+ leave = QWidget::find((WId)curWin);
+ QApplicationPrivate::dispatchEnterLeave(0, leave);
+ qt_modal_stack->insert(0, widget);
+ app_do_modal = true;
+ curWin = 0;
+ qt_last_mouse_receiver = 0;
+ qt_win_ignoreNextMouseReleaseEvent = false;
+}
+
+void QApplicationPrivate::leaveModal_sys(QWidget *widget)
+{
+ if (qt_modal_stack && qt_modal_stack->removeAll(widget)) {
+ if (qt_modal_stack->isEmpty()) {
+ delete qt_modal_stack;
+ qt_modal_stack = 0;
+ QPoint p(QCursor::pos());
+ app_do_modal = false; // necessary, we may get recursively into qt_try_modal below
+ QWidget* w = QApplication::widgetAt(p.x(), p.y());
+ QWidget *leave = qt_last_mouse_receiver;
+ if (!leave)
+ leave = QWidget::find((WId)curWin);
+ if (QWidget *grabber = QWidget::mouseGrabber()) {
+ w = grabber;
+ if (leave == w)
+ leave = 0;
+ }
+ QApplicationPrivate::dispatchEnterLeave(w, leave); // send synthetic enter event
+ curWin = w ? w->effectiveWinId() : 0;
+ qt_last_mouse_receiver = w;
+ }
+ qt_win_ignoreNextMouseReleaseEvent = true;
+ }
+ app_do_modal = qt_modal_stack != 0;
+}
+
+bool qt_try_modal(QWidget *widget, MSG *msg, int& ret)
+{
+#if defined(Q_OS_WINCE)
+ Q_UNUSED(ret);
+#endif
+ QWidget * top = 0;
+
+ if (QApplicationPrivate::tryModalHelper(widget, &top))
+ return true;
+
+ int type = msg->message;
+
+ bool block_event = false;
+#ifndef Q_WS_WINCE
+ if (type != WM_NCHITTEST) {
+#endif
+ if ((type >= WM_MOUSEFIRST && type <= WM_MOUSELAST) ||
+ type == WM_MOUSEWHEEL || type == WM_MOUSEHWHEEL ||
+ type == WM_MOUSELEAVE ||
+ (type >= WM_KEYFIRST && type <= WM_KEYLAST)
+#ifndef Q_WS_WINCE
+ || type == WM_NCMOUSEMOVE
+#endif
+ ) {
+ if (type == WM_MOUSEMOVE
+#ifndef Q_WS_WINCE
+ || type == WM_NCMOUSEMOVE
+#endif
+ ) {
+#ifndef QT_NO_CURSOR
+ QCursor *c = qt_grab_cursor();
+ if (!c)
+ c = QApplication::overrideCursor();
+ if (c) // application cursor defined
+ SetCursor(c->handle());
+ else
+ SetCursor(QCursor(Qt::ArrowCursor).handle());
+#endif // QT_NO_CURSOR
+ }
+ block_event = true;
+ } else if (type == WM_CLOSE) {
+ block_event = true;
+ }
+#ifndef Q_WS_WINCE
+ else if (type == WM_MOUSEACTIVATE || type == WM_NCLBUTTONDOWN){
+ if (!top->isActiveWindow()) {
+ top->activateWindow();
+ } else {
+ QApplication::beep();
+ }
+ block_event = true;
+ ret = MA_NOACTIVATEANDEAT;
+ } else if (type == WM_SYSCOMMAND) {
+ if (!(msg->wParam == SC_RESTORE && widget->isMinimized()))
+ block_event = true;
+ }
+ }
+#endif
+
+ return !block_event;
+}
+
+
+/*****************************************************************************
+ Popup widget mechanism
+
+ openPopup()
+ Adds a widget to the list of popup widgets
+ Arguments:
+ QWidget *widget The popup widget to be added
+
+ closePopup()
+ Removes a widget from the list of popup widgets
+ Arguments:
+ QWidget *widget The popup widget to be removed
+ *****************************************************************************/
+
+void QApplicationPrivate::openPopup(QWidget *popup)
+{
+ if (!QApplicationPrivate::popupWidgets)
+ QApplicationPrivate::popupWidgets = new QWidgetList;
+ QApplicationPrivate::popupWidgets->append(popup);
+ if (!popup->isEnabled())
+ return;
+
+ // close any opened 'ime candidate window'
+ if (imeParentWnd)
+ ::SendMessage(imeParentWnd, WM_IME_ENDCOMPOSITION, 0, 0);
+
+ if (QApplicationPrivate::popupWidgets->count() == 1 && !qt_nograb()) {
+ Q_ASSERT(popup->testAttribute(Qt::WA_WState_Created));
+ setAutoCapture(popup->internalWinId()); // grab mouse/keyboard
+ }
+ // Popups are not focus-handled by the window system (the first
+ // popup grabbed the keyboard), so we have to do that manually: A
+ // new popup gets the focus
+ if (popup->focusWidget()) {
+ popup->focusWidget()->setFocus(Qt::PopupFocusReason);
+ } else if (QApplicationPrivate::popupWidgets->count() == 1) { // this was the first popup
+ if (QWidget *fw = QApplication::focusWidget()) {
+ QFocusEvent e(QEvent::FocusOut, Qt::PopupFocusReason);
+ QApplication::sendEvent(fw, &e);
+ }
+ }
+}
+
+void QApplicationPrivate::closePopup(QWidget *popup)
+{
+ if (!QApplicationPrivate::popupWidgets)
+ return;
+ QApplicationPrivate::popupWidgets->removeAll(popup);
+ POINT curPos;
+ GetCursorPos(&curPos);
+
+ // close any opened 'ime candidate window'
+ if (imeParentWnd)
+ ::SendMessage(imeParentWnd, WM_IME_ENDCOMPOSITION, 0, 0);
+
+ if (QApplicationPrivate::popupWidgets->isEmpty()) { // this was the last popup
+ delete QApplicationPrivate::popupWidgets;
+ QApplicationPrivate::popupWidgets = 0;
+ replayPopupMouseEvent = (!popup->geometry().contains(QPoint(curPos.x, curPos.y))
+ && !popup->testAttribute(Qt::WA_NoMouseReplay));
+ if (!popup->isEnabled())
+ return;
+ if (!qt_nograb()) // grabbing not disabled
+ releaseAutoCapture();
+ QWidget *fw = QApplicationPrivate::active_window ? QApplicationPrivate::active_window->focusWidget()
+ : QApplication::focusWidget();
+ if (fw) {
+ if (fw != QApplication::focusWidget()) {
+ fw->setFocus(Qt::PopupFocusReason);
+ } else {
+ QFocusEvent e(QEvent::FocusIn, Qt::PopupFocusReason);
+ QApplication::sendEvent(fw, &e);
+ }
+ }
+ } else {
+ // Popups are not focus-handled by the window system (the
+ // first popup grabbed the keyboard), so we have to do that
+ // manually: A popup was closed, so the previous popup gets
+ // the focus.
+ QWidget* aw = QApplicationPrivate::popupWidgets->last();
+ if (QApplicationPrivate::popupWidgets->count() == 1) {
+ Q_ASSERT(aw->testAttribute(Qt::WA_WState_Created));
+ setAutoCapture(aw->internalWinId());
+ }
+ if (QWidget *fw = aw->focusWidget())
+ fw->setFocus(Qt::PopupFocusReason);
+ }
+}
+
+
+
+
+/*****************************************************************************
+ Event translation; translates Windows events to Qt events
+ *****************************************************************************/
+
+//
+// Auto-capturing for mouse press and mouse release
+//
+
+static void setAutoCapture(HWND h)
+{
+ if (autoCaptureWnd)
+ releaseAutoCapture();
+ autoCaptureWnd = h;
+ SetCapture(h);
+}
+
+static void releaseAutoCapture()
+{
+ if (autoCaptureWnd) {
+ ReleaseCapture();
+ autoCaptureWnd = 0;
+ }
+}
+
+
+//
+// Mouse event translation
+//
+// Non-client mouse messages are not translated
+//
+
+static const ushort mouseTbl[] = {
+ WM_MOUSEMOVE, QEvent::MouseMove, 0,
+ WM_LBUTTONDOWN, QEvent::MouseButtonPress, Qt::LeftButton,
+ WM_LBUTTONUP, QEvent::MouseButtonRelease, Qt::LeftButton,
+ WM_LBUTTONDBLCLK, QEvent::MouseButtonDblClick, Qt::LeftButton,
+ WM_RBUTTONDOWN, QEvent::MouseButtonPress, Qt::RightButton,
+ WM_RBUTTONUP, QEvent::MouseButtonRelease, Qt::RightButton,
+ WM_RBUTTONDBLCLK, QEvent::MouseButtonDblClick, Qt::RightButton,
+ WM_MBUTTONDOWN, QEvent::MouseButtonPress, Qt::MidButton,
+ WM_MBUTTONUP, QEvent::MouseButtonRelease, Qt::MidButton,
+ WM_MBUTTONDBLCLK, QEvent::MouseButtonDblClick, Qt::MidButton,
+ // use XButton1 for now, the real X button is decided later
+ WM_XBUTTONDOWN, QEvent::MouseButtonPress, Qt::XButton1,
+ WM_XBUTTONUP, QEvent::MouseButtonRelease, Qt::XButton1,
+ WM_XBUTTONDBLCLK, QEvent::MouseButtonDblClick, Qt::XButton1,
+
+#ifndef Q_WS_WINCE
+ WM_NCMOUSEMOVE, QEvent::NonClientAreaMouseMove, 0,
+ WM_NCLBUTTONDOWN, QEvent::NonClientAreaMouseButtonPress, Qt::LeftButton,
+ WM_NCLBUTTONUP, QEvent::NonClientAreaMouseButtonRelease, Qt::LeftButton,
+ WM_NCLBUTTONDBLCLK, QEvent::NonClientAreaMouseButtonDblClick, Qt::LeftButton,
+ WM_NCRBUTTONDOWN, QEvent::NonClientAreaMouseButtonPress, Qt::RightButton,
+ WM_NCRBUTTONUP, QEvent::NonClientAreaMouseButtonRelease, Qt::RightButton,
+ WM_NCRBUTTONDBLCLK, QEvent::NonClientAreaMouseButtonDblClick, Qt::RightButton,
+ WM_NCMBUTTONDOWN, QEvent::NonClientAreaMouseButtonPress, Qt::MidButton,
+ WM_NCMBUTTONUP, QEvent::NonClientAreaMouseButtonRelease, Qt::MidButton,
+ WM_NCMBUTTONDBLCLK, QEvent::NonClientAreaMouseButtonDblClick, Qt::MidButton,
+#endif
+
+ 0, 0, 0
+};
+
+static int translateButtonState(int s, int type, int button)
+{
+ Q_UNUSED(type);
+ Q_UNUSED(button);
+ int bst = 0;
+ if (s & MK_LBUTTON)
+ bst |= Qt::LeftButton;
+ if (s & MK_MBUTTON)
+ bst |= Qt::MidButton;
+ if (s & MK_RBUTTON)
+ bst |= Qt::RightButton;
+ if (s & MK_SHIFT)
+ bst |= Qt::ShiftModifier;
+ if (s & MK_CONTROL)
+ bst |= Qt::ControlModifier;
+
+ if (s & MK_XBUTTON1)
+ bst |= Qt::XButton1;
+ if (s & MK_XBUTTON2)
+ bst |= Qt::XButton2;
+
+ if (GetKeyState(VK_MENU) < 0)
+ bst |= Qt::AltModifier;
+
+ if ((GetKeyState(VK_LWIN) < 0) ||
+ (GetKeyState(VK_RWIN) < 0))
+ bst |= Qt::MetaModifier;
+
+ return bst;
+}
+
+void qt_win_eatMouseMove()
+{
+ // after closing a windows dialog with a double click (i.e. open a file)
+ // the message queue still contains a dubious WM_MOUSEMOVE message where
+ // the left button is reported to be down (wParam != 0).
+ // remove all those messages (usually 1) and post the last one with a
+ // reset button state
+
+ MSG msg = {0, 0, 0, 0, 0, {0, 0} };
+ while (PeekMessage(&msg, 0, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_REMOVE))
+ ;
+ if (msg.message == WM_MOUSEMOVE)
+ PostMessage(msg.hwnd, msg.message, 0, msg.lParam);
+}
+
+// In DnD, the mouse release event never appears, so the
+// mouse button state machine must be manually reset
+void QApplication::winMouseButtonUp()
+{
+ qt_button_down = 0;
+ releaseAutoCapture();
+}
+
+void QETWidget::repolishStyle(QStyle &)
+{
+ QEvent e(QEvent::StyleChange);
+ QApplication::sendEvent(this, &e);
+}
+
+bool QETWidget::translateMouseEvent(const MSG &msg)
+{
+ if (!isWindow() && testAttribute(Qt::WA_NativeWindow))
+ Q_ASSERT(internalWinId());
+
+ static QPoint pos;
+ static POINT gpos={-1,-1};
+ QEvent::Type type; // event parameters
+ int button;
+ int state;
+ int i;
+
+ if (sm_blockUserInput) //block user interaction during session management
+ return true;
+
+ // Compress mouse move events
+ if (msg.message == WM_MOUSEMOVE) {
+ MSG mouseMsg;
+ while (PeekMessage(&mouseMsg, msg.hwnd, WM_MOUSEFIRST,
+ WM_MOUSELAST, PM_NOREMOVE)) {
+ if (mouseMsg.message == WM_MOUSEMOVE) {
+#define PEEKMESSAGE_IS_BROKEN 1
+#ifdef PEEKMESSAGE_IS_BROKEN
+ // Since the Windows PeekMessage() function doesn't
+ // correctly return the wParam for WM_MOUSEMOVE events
+ // if there is a key release event in the queue
+ // _before_ the mouse event, we have to also consider
+ // key release events (kls 2003-05-13):
+ MSG keyMsg;
+ bool done = false;
+ while (PeekMessage(&keyMsg, 0, WM_KEYFIRST, WM_KEYLAST,
+ PM_NOREMOVE)) {
+ if (keyMsg.time < mouseMsg.time) {
+ if ((keyMsg.lParam & 0xC0000000) == 0x40000000) {
+ PeekMessage(&keyMsg, 0, keyMsg.message,
+ keyMsg.message, PM_REMOVE);
+ } else {
+ done = true;
+ break;
+ }
+ } else {
+ break; // no key event before the WM_MOUSEMOVE event
+ }
+ }
+ if (done)
+ break;
+#else
+ // Actually the following 'if' should work instead of
+ // the above key event checking, but apparently
+ // PeekMessage() is broken :-(
+ if (mouseMsg.wParam != msg.wParam)
+ break; // leave the message in the queue because
+ // the key state has changed
+#endif
+ MSG *msgPtr = (MSG *)(&msg);
+ // Update the passed in MSG structure with the
+ // most recent one.
+ msgPtr->lParam = mouseMsg.lParam;
+ msgPtr->wParam = mouseMsg.wParam;
+ // Extract the x,y coordinates from the lParam as we do in the WndProc
+ msgPtr->pt.x = GET_X_LPARAM(mouseMsg.lParam);
+ msgPtr->pt.y = GET_Y_LPARAM(mouseMsg.lParam);
+ ClientToScreen(msg.hwnd, &(msgPtr->pt));
+ // Remove the mouse move message
+ PeekMessage(&mouseMsg, msg.hwnd, WM_MOUSEMOVE,
+ WM_MOUSEMOVE, PM_REMOVE);
+ } else {
+ break; // there was no more WM_MOUSEMOVE event
+ }
+ }
+ }
+
+ for (i=0; (UINT)mouseTbl[i] != msg.message && mouseTbl[i]; i += 3)
+ ;
+ if (!mouseTbl[i])
+ return false;
+ type = (QEvent::Type)mouseTbl[++i]; // event type
+ button = mouseTbl[++i]; // which button
+ if (button == Qt::XButton1) {
+ switch(GET_XBUTTON_WPARAM(msg.wParam)) {
+ case XBUTTON1:
+ button = Qt::XButton1;
+ break;
+ case XBUTTON2:
+ button = Qt::XButton2;
+ break;
+ }
+ }
+#ifndef Q_OS_WINCE
+ static bool trackMouseEventLookup = false;
+ typedef BOOL (WINAPI *PtrTrackMouseEvent)(LPTRACKMOUSEEVENT);
+ static PtrTrackMouseEvent ptrTrackMouseEvent = 0;
+#endif
+ state = translateButtonState(msg.wParam, type, button); // button state
+ const QPoint widgetPos = mapFromGlobal(QPoint(msg.pt.x, msg.pt.y));
+ QWidget *alienWidget = !internalWinId() ? this : childAt(widgetPos);
+ if (alienWidget && alienWidget->internalWinId())
+ alienWidget = 0;
+
+ if (type == QEvent::MouseMove || type == QEvent::NonClientAreaMouseMove
+ || type == QEvent::TabletMove) {
+
+ if (!(state & Qt::MouseButtonMask))
+ qt_button_down = 0;
+#ifndef QT_NO_CURSOR
+ QCursor *c = qt_grab_cursor();
+ if (!c)
+ c = QApplication::overrideCursor();
+ if (c) // application cursor defined
+ SetCursor(c->handle());
+ else if (type != QEvent::NonClientAreaMouseMove && !qt_button_down) {
+ // use widget cursor if widget is enabled
+ QWidget *w = alienWidget ? alienWidget : this;
+ while (!w->isWindow() && !w->isEnabled())
+ w = w->parentWidget();
+ SetCursor(w->cursor().handle());
+ }
+#endif // QT_NO_CURSOR
+
+ HWND id = effectiveWinId();
+ QWidget *mouseGrabber = QWidget::mouseGrabber();
+ QWidget *activePopupWidget = QApplication::activePopupWidget();
+ if (mouseGrabber) {
+ if (!activePopupWidget || (activePopupWidget == this && !rect().contains(widgetPos)))
+ id = mouseGrabber->effectiveWinId();
+ } else if (type == QEvent::NonClientAreaMouseMove) {
+ id = 0;
+ }
+
+ if (curWin != id) { // new current window
+ if (id == 0) {
+ QWidget *leave = qt_last_mouse_receiver;
+ if (!leave)
+ leave = QWidget::find(curWin);
+ QApplicationPrivate::dispatchEnterLeave(0, leave);
+ qt_last_mouse_receiver = 0;
+ curWin = 0;
+ } else {
+ QWidget *leave = 0;
+ if (curWin && qt_last_mouse_receiver)
+ leave = qt_last_mouse_receiver;
+ else
+ leave = QWidget::find(curWin);
+ QWidget *enter = alienWidget ? alienWidget : this;
+ if (mouseGrabber && activePopupWidget) {
+ if (leave != mouseGrabber)
+ enter = mouseGrabber;
+ else
+ enter = activePopupWidget == this ? this : mouseGrabber;
+ }
+ QApplicationPrivate::dispatchEnterLeave(enter, leave);
+ qt_last_mouse_receiver = enter;
+ curWin = enter ? enter->effectiveWinId() : 0;
+ }
+#ifndef Q_OS_WINCE
+
+ if (curWin != 0) {
+ if (!trackMouseEventLookup) {
+ trackMouseEventLookup = true;
+ ptrTrackMouseEvent = (PtrTrackMouseEvent)QSystemLibrary::resolve(QLatin1String("comctl32"), "_TrackMouseEvent");
+ }
+ if (ptrTrackMouseEvent && !qApp->d_func()->inPopupMode()) {
+ // We always have to set the tracking, since
+ // Windows detects more leaves than we do..
+ TRACKMOUSEEVENT tme;
+ tme.cbSize = sizeof(TRACKMOUSEEVENT);
+ tme.dwFlags = 0x00000002; // TME_LEAVE
+ tme.hwndTrack = curWin; // Track on window receiving msgs
+ tme.dwHoverTime = (DWORD)-1; // HOVER_DEFAULT
+ ptrTrackMouseEvent(&tme);
+ }
+ }
+#endif // Q_OS_WINCE
+ }
+
+ POINT curPos = msg.pt;
+ if (curPos.x == gpos.x && curPos.y == gpos.y)
+ return true; // same global position
+ gpos = curPos;
+
+ Q_ASSERT(testAttribute(Qt::WA_WState_Created));
+ ScreenToClient(internalWinId(), &curPos);
+
+ pos.rx() = curPos.x;
+ pos.ry() = curPos.y;
+ pos = d_func()->mapFromWS(pos);
+ } else {
+ gpos = msg.pt;
+ pos = mapFromGlobal(QPoint(gpos.x, gpos.y));
+
+ // mouse button pressed
+ if (!qt_button_down && (type == QEvent::MouseButtonPress || type == QEvent::MouseButtonDblClick)) {
+ QWidget *tlw = window();
+ if (QWidget *child = tlw->childAt(mapTo(tlw, pos)))
+ qt_button_down = child;
+ else
+ qt_button_down = this;
+ }
+ }
+
+ bool res = false;
+
+ bool nonClientAreaEvent = type >= QEvent::NonClientAreaMouseMove
+ && type <= QEvent::NonClientAreaMouseButtonDblClick;
+
+ if (qApp->d_func()->inPopupMode()) { // in popup mode
+
+ if (nonClientAreaEvent)
+ return false;
+
+ replayPopupMouseEvent = false;
+ QWidget* activePopupWidget = QApplication::activePopupWidget();
+ QWidget *target = activePopupWidget;
+ const QPoint globalPos(gpos.x, gpos.y);
+
+ if (target != this) {
+ if ((windowType() == Qt::Popup) && rect().contains(pos) && 0)
+ target = this;
+ else // send to last popup
+ pos = target->mapFromGlobal(globalPos);
+ }
+ QWidget *popupChild = target->childAt(pos);
+ bool releaseAfter = false;
+ switch (type) {
+ case QEvent::MouseButtonPress:
+ case QEvent::MouseButtonDblClick:
+ popupButtonFocus = popupChild;
+ break;
+ case QEvent::MouseButtonRelease:
+ case QEvent::TabletRelease:
+
+ releaseAfter = true;
+ break;
+ default:
+ break; // nothing for mouse move
+ }
+
+ if (target->isEnabled()) {
+ if (popupButtonFocus) {
+ target = popupButtonFocus;
+ } else if (popupChild) {
+ target = popupChild;
+ }
+
+ pos = target->mapFromGlobal(globalPos);
+ QMouseEvent e(type, pos, globalPos,
+ Qt::MouseButton(button),
+ Qt::MouseButtons(state & Qt::MouseButtonMask),
+ Qt::KeyboardModifiers(state & Qt::KeyboardModifierMask));
+ res = QApplicationPrivate::sendMouseEvent(target, &e, alienWidget, this, &qt_button_down,
+ qt_last_mouse_receiver);
+ res = res && e.isAccepted();
+ } else {
+ // close disabled popups when a mouse button is pressed or released
+ switch (type) {
+ case QEvent::MouseButtonPress:
+ case QEvent::MouseButtonDblClick:
+ case QEvent::MouseButtonRelease:
+ target->close();
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (releaseAfter) {
+ popupButtonFocus = 0;
+ qt_button_down = 0;
+ }
+
+#ifndef Q_OS_WINCE
+ if (type == QEvent::MouseButtonPress
+ && QApplication::activePopupWidget() != activePopupWidget
+ && ptrTrackMouseEvent
+ && curWin) {
+ // Since curWin is already the window we clicked on,
+ // we have to setup the mouse tracking here.
+ TRACKMOUSEEVENT tme;
+ tme.cbSize = sizeof(TRACKMOUSEEVENT);
+ tme.dwFlags = 0x00000002; // TME_LEAVE
+ tme.hwndTrack = curWin; // Track on window receiving msgs
+ tme.dwHoverTime = (DWORD)-1; // HOVER_DEFAULT
+ ptrTrackMouseEvent(&tme);
+ }
+#endif
+ if (type == QEvent::MouseButtonPress
+ && QApplication::activePopupWidget() != activePopupWidget
+ && replayPopupMouseEvent) {
+ // the popup disappeared. Replay the event
+ QWidget* w = QApplication::widgetAt(gpos.x, gpos.y);
+ if (w && !QApplicationPrivate::isBlockedByModal(w)) {
+ Q_ASSERT(w->testAttribute(Qt::WA_WState_Created));
+ HWND hwndTarget = w->effectiveWinId();
+ if (QWidget::mouseGrabber() == 0)
+ setAutoCapture(hwndTarget);
+ if (!w->isActiveWindow())
+ w->activateWindow();
+ POINT widgetpt = gpos;
+ ScreenToClient(hwndTarget, &widgetpt);
+ LPARAM lParam = MAKELPARAM(widgetpt.x, widgetpt.y);
+ PostMessage(hwndTarget, msg.message, msg.wParam, lParam);
+ }
+ } else if (type == QEvent::MouseButtonRelease && button == Qt::RightButton
+ && QApplication::activePopupWidget() == activePopupWidget) {
+ // popup still alive and received right-button-release
+#if !defined(QT_NO_CONTEXTMENU)
+ QContextMenuEvent e2(QContextMenuEvent::Mouse, pos, globalPos,
+ qt_win_getKeyboardModifiers());
+ bool res2 = QApplication::sendSpontaneousEvent( target, &e2 );
+ if (!res) // RMB not accepted
+ res = res2 && e2.isAccepted();
+#endif
+ }
+ } else { // not popup mode
+ int bs = state & Qt::MouseButtonMask;
+ if ((type == QEvent::MouseButtonPress ||
+ type == QEvent::MouseButtonDblClick) && bs == button) {
+ Q_ASSERT(testAttribute(Qt::WA_WState_Created));
+ if (QWidget::mouseGrabber() == 0)
+ setAutoCapture(internalWinId());
+ } else if (type == QEvent::MouseButtonRelease && bs == 0) {
+ if (QWidget::mouseGrabber() == 0)
+ releaseAutoCapture();
+ }
+
+ const QPoint globalPos(gpos.x,gpos.y);
+ QWidget *widget = QApplicationPrivate::pickMouseReceiver(this, globalPos, pos, type,
+ Qt::MouseButtons(bs),
+ qt_button_down, alienWidget);
+ if (!widget)
+ return false; // don't send event
+
+ QMouseEvent e(type, pos, globalPos, Qt::MouseButton(button),
+ Qt::MouseButtons(state & Qt::MouseButtonMask),
+ Qt::KeyboardModifiers(state & Qt::KeyboardModifierMask));
+
+ res = QApplicationPrivate::sendMouseEvent(widget, &e, alienWidget, this, &qt_button_down,
+ qt_last_mouse_receiver);
+
+ // non client area events are only informational, you cannot "handle" them
+ res = res && e.isAccepted() && !nonClientAreaEvent;
+#if !defined(QT_NO_CONTEXTMENU)
+ if (type == QEvent::MouseButtonRelease && button == Qt::RightButton) {
+ QContextMenuEvent e2(QContextMenuEvent::Mouse, pos, globalPos,
+ qt_win_getKeyboardModifiers());
+ bool res2 = QApplication::sendSpontaneousEvent(widget, &e2);
+ if (!res)
+ res = res2 && e2.isAccepted();
+ }
+#endif
+
+ if (type != QEvent::MouseMove)
+ pos.rx() = pos.ry() = -9999; // init for move compression
+ }
+ return res;
+}
+
+bool QETWidget::translateWheelEvent(const MSG &msg)
+{
+ int state = 0;
+
+ if (sm_blockUserInput) // block user interaction during session management
+ return true;
+
+ state = translateButtonState(GET_KEYSTATE_WPARAM(msg.wParam), 0, 0);
+
+ int delta;
+ if (msg.message == WM_MOUSEWHEEL || msg.message == WM_MOUSEHWHEEL)
+ delta = (short) HIWORD (msg.wParam);
+ else
+ delta = (int) msg.wParam;
+
+ Qt::Orientation orient = (msg.message == WM_MOUSEHWHEEL || state&Qt::AltModifier
+#if 0
+ // disabled for now - Trenton's one-wheel mouse makes trouble...
+ // "delta" for usual wheels is +-120. +-240 seems to indicate
+ // the second wheel see more recent MSDN for WM_MOUSEWHEEL
+
+ ( // <- parantheses added to make update happy, remove if the
+ // #if 0 is removed
+ || delta == 240 || delta == -240)?Qt::Horizontal:Vertical;
+ if (delta == 240 || delta == -240)
+ delta /= 2;
+#endif
+ ) ? Qt::Horizontal : Qt::Vertical;
+
+ // according to the MSDN documentation on WM_MOUSEHWHEEL:
+ // a positive value indicates that the wheel was rotated to the right;
+ // a negative value indicates that the wheel was rotated to the left.
+ // Qt defines this value as the exact opposite, so we have to flip the value!
+ if (msg.message == WM_MOUSEHWHEEL)
+ delta = -delta;
+
+ QPoint globalPos;
+
+ globalPos.rx() = (short)LOWORD (msg.lParam);
+ globalPos.ry() = (short)HIWORD (msg.lParam);
+
+
+ // if there is a widget under the mouse and it is not shadowed
+ // by modality, we send the event to it first
+ int ret = 0;
+ QWidget* w = QApplication::widgetAt(globalPos);
+ if (!w || !qt_try_modal(w, (MSG*)&msg, ret)) {
+ //synaptics touchpad shows its own widget at this position
+ //so widgetAt() will fail with that HWND, try child of this widget
+ w = this->childAt(this->mapFromGlobal(globalPos));
+ if (!w)
+ w = this;
+ }
+
+ // send the event to the widget or its ancestors
+ {
+ QWidget* popup = QApplication::activePopupWidget();
+ if (popup && w->window() != popup)
+ popup->close();
+#ifndef QT_NO_WHEELEVENT
+ QWheelEvent e(w->mapFromGlobal(globalPos), globalPos, delta,
+ Qt::MouseButtons(state & Qt::MouseButtonMask),
+ Qt::KeyboardModifier(state & Qt::KeyboardModifierMask), orient);
+
+ if (QApplication::sendSpontaneousEvent(w, &e))
+#else
+ Q_UNUSED(orient);
+#endif //QT_NO_WHEELEVENT
+ return true;
+ }
+
+ // send the event to the widget that has the focus or its ancestors, if different
+ if (w != QApplication::focusWidget() && (w = QApplication::focusWidget())) {
+ QWidget* popup = QApplication::activePopupWidget();
+ if (popup && w->window() != popup)
+ popup->close();
+#ifndef QT_NO_WHEELEVENT
+ QWheelEvent e(w->mapFromGlobal(globalPos), globalPos, delta,
+ Qt::MouseButtons(state & Qt::MouseButtonMask),
+ Qt::KeyboardModifier(state & Qt::KeyboardModifierMask), orient);
+ if (QApplication::sendSpontaneousEvent(w, &e))
+#endif //QT_NO_WHEELEVENT
+ return true;
+ }
+ return false;
+}
+
+
+//
+// Windows Wintab to QTabletEvent translation
+//
+
+// the following is adapted from the wintab syspress example (public domain)
+/* -------------------------------------------------------------------------- */
+// Initialize the "static" information of a cursor device (pen, airbrush, etc).
+// The QTabletDeviceData is initialized with the data that do not change in time
+// (number of button, type of device, etc) but do not initialize the variable data
+// (e.g.: pen or eraser)
+#ifndef QT_NO_TABLETEVENT
+
+static void tabletInit(const quint64 uniqueId, const UINT csr_type, HCTX hTab)
+{
+ Q_ASSERT(ptrWTInfo);
+ Q_ASSERT(ptrWTGet);
+
+ Q_ASSERT(!tCursorInfo()->contains(uniqueId));
+
+ /* browse WinTab's many info items to discover pressure handling. */
+ AXIS np;
+ LOGCONTEXT lc;
+
+ /* get the current context for its device variable. */
+ ptrWTGet(hTab, &lc);
+
+ /* get the size of the pressure axis. */
+ QTabletDeviceData tdd;
+ tdd.llId = uniqueId;
+
+ ptrWTInfo(WTI_DEVICES + lc.lcDevice, DVC_NPRESSURE, &np);
+ tdd.minPressure = int(np.axMin);
+ tdd.maxPressure = int(np.axMax);
+
+ ptrWTInfo(WTI_DEVICES + lc.lcDevice, DVC_TPRESSURE, &np);
+ tdd.minTanPressure = int(np.axMin);
+ tdd.maxTanPressure = int(np.axMax);
+
+ LOGCONTEXT lcMine;
+
+ /* get default region */
+ ptrWTInfo(WTI_DEFCONTEXT, 0, &lcMine);
+
+ tdd.minX = 0;
+ tdd.maxX = int(lcMine.lcInExtX) - int(lcMine.lcInOrgX);
+
+ tdd.minY = 0;
+ tdd.maxY = int(lcMine.lcInExtY) - int(lcMine.lcInOrgY);
+
+ tdd.minZ = 0;
+ tdd.maxZ = int(lcMine.lcInExtZ) - int(lcMine.lcInOrgZ);
+
+ const uint cursorTypeBitMask = 0x0F06; // bitmask to find the specific cursor type (see Wacom FAQ)
+ if (((csr_type & 0x0006) == 0x0002) && ((csr_type & cursorTypeBitMask) != 0x0902)) {
+ tdd.currentDevice = QTabletEvent::Stylus;
+ } else {
+ switch (csr_type & cursorTypeBitMask) {
+ case 0x0802:
+ tdd.currentDevice = QTabletEvent::Stylus;
+ break;
+ case 0x0902:
+ tdd.currentDevice = QTabletEvent::Airbrush;
+ break;
+ case 0x0004:
+ tdd.currentDevice = QTabletEvent::FourDMouse;
+ break;
+ case 0x0006:
+ tdd.currentDevice = QTabletEvent::Puck;
+ break;
+ case 0x0804:
+ tdd.currentDevice = QTabletEvent::RotationStylus;
+ break;
+ default:
+ tdd.currentDevice = QTabletEvent::NoDevice;
+ }
+ }
+ tCursorInfo()->insert(uniqueId, tdd);
+}
+#endif // QT_NO_TABLETEVENT
+
+// Update the "dynamic" information of a cursor device (pen, airbrush, etc).
+// The dynamic information is the information of QTabletDeviceData that can change
+// in time (eraser or pen if a device is turned around).
+#ifndef QT_NO_TABLETEVENT
+
+static void tabletUpdateCursor(QTabletDeviceData &tdd, const UINT currentCursor)
+{
+ switch (currentCursor % 3) { // %3 for dual track
+ case 0:
+ tdd.currentPointerType = QTabletEvent::Cursor;
+ break;
+ case 1:
+ tdd.currentPointerType = QTabletEvent::Pen;
+ break;
+ case 2:
+ tdd.currentPointerType = QTabletEvent::Eraser;
+ break;
+ default:
+ tdd.currentPointerType = QTabletEvent::UnknownPointer;
+ }
+}
+#endif // QT_NO_TABLETEVENT
+
+bool QETWidget::translateTabletEvent(const MSG &msg, PACKET *localPacketBuf,
+ int numPackets)
+{
+ Q_UNUSED(msg);
+ POINT ptNew;
+ static DWORD btnNew, btnOld, btnChange;
+ qreal prsNew;
+ ORIENTATION ort;
+ static bool button_pressed = false;
+ int i,
+ tiltX,
+ tiltY;
+ bool sendEvent = false;
+ QEvent::Type t;
+ int z = 0;
+ qreal rotation = 0.0;
+ qreal tangentialPressure;
+
+ // the most common event that we get...
+ t = QEvent::TabletMove;
+ for (i = 0; i < numPackets; i++) {
+ // get the unique ID of the device...
+ btnOld = btnNew;
+ btnNew = localPacketBuf[i].pkButtons;
+ btnChange = btnOld ^ btnNew;
+
+ if (btnNew & btnChange) {
+ button_pressed = true;
+ t = QEvent::TabletPress;
+ }
+ ptNew.x = UINT(localPacketBuf[i].pkX);
+ ptNew.y = UINT(localPacketBuf[i].pkY);
+#ifndef QT_NO_TABLETEVENT
+ z = (currentTabletPointer.currentDevice == QTabletEvent::FourDMouse) ? UINT(localPacketBuf[i].pkZ) : 0;
+#else
+ Q_UNUSED(z);
+#endif // QT_NO_TABLETEVENT
+ prsNew = 0.0;
+ QRect desktopArea = QApplication::desktop()->geometry();
+ QPointF hiResGlobal = currentTabletPointer.scaleCoord(ptNew.x, ptNew.y, desktopArea.left(),
+ desktopArea.width(), desktopArea.top(),
+ desktopArea.height());
+
+ if (btnNew) {
+#ifndef QT_NO_TABLETEVENT
+ if (currentTabletPointer.currentPointerType == QTabletEvent::Pen || currentTabletPointer.currentPointerType == QTabletEvent::Eraser)
+ prsNew = localPacketBuf[i].pkNormalPressure
+ / qreal(currentTabletPointer.maxPressure
+ - currentTabletPointer.minPressure);
+ else
+#endif // QT_NO_TABLETEVENT
+ prsNew = 0;
+ } else if (button_pressed) {
+ // One button press, should only give one button release
+ t = QEvent::TabletRelease;
+ button_pressed = false;
+ }
+ QPoint globalPos(qRound(hiResGlobal.x()), qRound(hiResGlobal.y()));
+
+ if (t == QEvent::TabletPress)
+ {
+ qt_button_down = QApplication::widgetAt(globalPos);
+ }
+
+ // make sure the tablet event get's sent to the proper widget...
+ QWidget *w = 0;
+
+ if (qt_button_down)
+ w = qt_button_down; // Pass it to the thing that's grabbed it.
+ else
+ w = QApplication::widgetAt(globalPos);
+
+ if (!w)
+ w = this;
+
+ if (t == QEvent::TabletRelease)
+ {
+ if (qt_win_ignoreNextMouseReleaseEvent) {
+ qt_win_ignoreNextMouseReleaseEvent = false;
+ if (qt_button_down && qt_button_down->internalWinId() == autoCaptureWnd) {
+ releaseAutoCapture();
+ qt_button_down = 0;
+ }
+ }
+
+ }
+
+ QPoint localPos = w->mapFromGlobal(globalPos);
+#ifndef QT_NO_TABLETEVENT
+ if (currentTabletPointer.currentDevice == QTabletEvent::Airbrush) {
+ tangentialPressure = localPacketBuf[i].pkTangentPressure
+ / qreal(currentTabletPointer.maxTanPressure
+ - currentTabletPointer.minTanPressure);
+ } else {
+ tangentialPressure = 0.0;
+ }
+#else
+ tangentialPressure = 0.0;
+#endif // QT_NO_TABLETEVENT
+
+ if (!qt_tablet_tilt_support) {
+ tiltX = tiltY = 0;
+ rotation = 0.0;
+ } else {
+ ort = localPacketBuf[i].pkOrientation;
+ // convert from azimuth and altitude to x tilt and y tilt
+ // what follows is the optimized version. Here are the equations
+ // I used to get to this point (in case things change :)
+ // X = sin(azimuth) * cos(altitude)
+ // Y = cos(azimuth) * cos(altitude)
+ // Z = sin(altitude)
+ // X Tilt = arctan(X / Z)
+ // Y Tilt = arctan(Y / Z)
+ double radAzim = (ort.orAzimuth / 10) * (Q_PI / 180);
+ //double radAlt = abs(ort.orAltitude / 10) * (Q_PI / 180);
+ double tanAlt = tan((abs(ort.orAltitude / 10)) * (Q_PI / 180));
+
+ double degX = atan(sin(radAzim) / tanAlt);
+ double degY = atan(cos(radAzim) / tanAlt);
+ tiltX = int(degX * (180 / Q_PI));
+ tiltY = int(-degY * (180 / Q_PI));
+ rotation = ort.orTwist;
+ }
+#ifndef QT_NO_TABLETEVENT
+ QTabletEvent e(t, localPos, globalPos, hiResGlobal, currentTabletPointer.currentDevice,
+ currentTabletPointer.currentPointerType, prsNew, tiltX, tiltY,
+ tangentialPressure, rotation, z, QApplication::keyboardModifiers(), currentTabletPointer.llId);
+ sendEvent = QApplication::sendSpontaneousEvent(w, &e);
+#endif // QT_NO_TABLETEVENT
+ }
+ return sendEvent;
+}
+
+extern bool qt_is_gui_used;
+
+
+#ifndef QT_NO_TABLETEVENT
+
+static void initWinTabFunctions()
+{
+#if defined(Q_OS_WINCE)
+ return;
+#else
+ if (!qt_is_gui_used)
+ return;
+
+ QSystemLibrary library(QLatin1String("wintab32"));
+ ptrWTInfo = (PtrWTInfo)library.resolve("WTInfoW");
+ ptrWTGet = (PtrWTGet)library.resolve("WTGetW");
+ ptrWTEnable = (PtrWTEnable)library.resolve("WTEnable");
+ ptrWTOverlap = (PtrWTEnable)library.resolve("WTOverlap");
+ ptrWTPacketsGet = (PtrWTPacketsGet)library.resolve("WTPacketsGet");
+#endif // Q_OS_WINCE
+}
+#endif // QT_NO_TABLETEVENT
+
+
+//
+// Paint event translation
+//
+bool QETWidget::translatePaintEvent(const MSG &msg)
+{
+ if (!isWindow() && testAttribute(Qt::WA_NativeWindow))
+ Q_ASSERT(internalWinId());
+
+ Q_ASSERT(testAttribute(Qt::WA_WState_Created));
+ if (!GetUpdateRect(internalWinId(), 0, FALSE)) { // The update bounding rect is invalid
+ d_func()->hd = 0;
+ setAttribute(Qt::WA_PendingUpdate, false);
+ return false;
+ }
+
+ if (msg.message == WM_ERASEBKGND)
+ return true;
+
+ setAttribute(Qt::WA_PendingUpdate, false);
+
+ if (d_func()->isGLWidget) {
+ if (d_func()->usesDoubleBufferedGLContext)
+ InvalidateRect(internalWinId(), 0, false);
+ } else {
+ const QRegion dirtyInBackingStore(qt_dirtyRegion(this));
+ // Make sure the invalidated region contains the region we're about to repaint.
+ // BeginPaint will set the clip to the invalidated region and it is impossible
+ // to enlarge it afterwards (only shrink it). Using GetDCEx is not suffient
+ // as it may return an invalid context (especially on Windows Vista).
+ if (!dirtyInBackingStore.isEmpty())
+ InvalidateRgn(internalWinId(), dirtyInBackingStore.handle(), false);
+ }
+ PAINTSTRUCT ps;
+ d_func()->hd = BeginPaint(internalWinId(), &ps);
+
+ const QRect updateRect(QPoint(ps.rcPaint.left, ps.rcPaint.top),
+ QPoint(ps.rcPaint.right, ps.rcPaint.bottom));
+
+ // Mapping region from system to qt (32 bit) coordinate system.
+ d_func()->syncBackingStore(updateRect.translated(data->wrect.topLeft()));
+
+ d_func()->hd = 0;
+ EndPaint(internalWinId(), &ps);
+
+ return true;
+}
+
+//
+// Window move and resize (configure) events
+//
+
+bool QETWidget::translateConfigEvent(const MSG &msg)
+{
+ if (!testAttribute(Qt::WA_WState_Created)) // in QWidget::create()
+ return true;
+ if (testAttribute(Qt::WA_WState_ConfigPending))
+ return true;
+ if (testAttribute(Qt::WA_DontShowOnScreen))
+ return true;
+ if (!isWindow())
+ return true;
+ setAttribute(Qt::WA_WState_ConfigPending); // set config flag
+ QRect cr = geometry();
+ if (msg.message == WM_SIZE) { // resize event
+ WORD a = LOWORD(msg.lParam);
+ WORD b = HIWORD(msg.lParam);
+ QSize oldSize = size();
+ QSize newSize(a, b);
+#ifdef Q_WS_WINCE_WM
+ if (isFullScreen() && (oldSize.width() == newSize.height()) && (oldSize.height() == newSize.width()))
+ qt_wince_hide_taskbar(internalWinId());
+#endif
+ cr.setSize(newSize);
+ if (msg.wParam != SIZE_MINIMIZED)
+ data->crect = cr;
+ if (isWindow()) { // update title/icon text
+ d_func()->createTLExtra();
+ // Capture SIZE_MINIMIZED without preceding WM_SYSCOMMAND
+ // (like Windows+M)
+ if (msg.wParam == SIZE_MINIMIZED && !isMinimized()) {
+#ifndef Q_WS_WINCE
+ const QString title = windowIconText();
+ if (!title.isEmpty())
+ d_func()->setWindowTitle_helper(title);
+#endif
+ data->window_state |= Qt::WindowMinimized;
+ if (isVisible()) {
+ QHideEvent e;
+ QApplication::sendSpontaneousEvent(this, &e);
+ hideChildren(true);
+ }
+ } else if (msg.wParam != SIZE_MINIMIZED) {
+ bool window_state_changed = false;
+ Qt::WindowStates oldstate = Qt::WindowStates(dataPtr()->window_state);
+ if (isMinimized()) {
+#ifndef Q_WS_WINCE
+ const QString title = windowTitle();
+ if (!title.isEmpty())
+ d_func()->setWindowTitle_helper(title);
+#endif
+ data->window_state &= ~Qt::WindowMinimized;
+ showChildren(true);
+ QShowEvent e;
+ QApplication::sendSpontaneousEvent(this, &e);
+ // Capture SIZE_MAXIMIZED and SIZE_RESTORED without preceding WM_SYSCOMMAND
+ // (Aero Snap on Win7)
+ } else if (msg.wParam == SIZE_MAXIMIZED && !isMaximized()) {
+ data->window_state |= Qt::WindowMaximized;
+ window_state_changed = true;
+ } else if (msg.wParam == SIZE_RESTORED && isMaximized()) {
+ data->window_state &= ~(Qt::WindowMaximized);
+ window_state_changed = true;
+ }
+ if (window_state_changed) {
+ QWindowStateChangeEvent e(oldstate);
+ QApplication::sendSpontaneousEvent(this, &e);
+ }
+ }
+ }
+ if (msg.wParam != SIZE_MINIMIZED && oldSize != newSize) {
+ if (isVisible()) {
+ QTLWExtra *tlwExtra = maybeTopData();
+ static bool slowResize = qgetenv("QT_SLOW_TOPLEVEL_RESIZE").toInt();
+ const bool hasStaticContents = tlwExtra && tlwExtra->backingStore
+ && tlwExtra->backingStore->hasStaticContents();
+ // If we have a backing store with static contents, we have to disable the top-level
+ // resize optimization in order to get invalidated regions for resized widgets.
+ // The optimization discards all invalidateBuffer() calls since we're going to
+ // repaint everything anyways, but that's not the case with static contents.
+ if (!slowResize && tlwExtra && !hasStaticContents)
+ tlwExtra->inTopLevelResize = true;
+ QResizeEvent e(newSize, oldSize);
+ QApplication::sendSpontaneousEvent(this, &e);
+ if (d_func()->paintOnScreen()) {
+ QRegion updateRegion(rect());
+ if (testAttribute(Qt::WA_StaticContents))
+ updateRegion -= QRect(0, 0, oldSize.width(), oldSize.height());
+ d_func()->syncBackingStore(updateRegion);
+ } else {
+ d_func()->syncBackingStore();
+ }
+ if (!slowResize && tlwExtra)
+ tlwExtra->inTopLevelResize = false;
+ } else {
+ QResizeEvent *e = new QResizeEvent(newSize, oldSize);
+ QApplication::postEvent(this, e);
+ }
+ }
+ } else if (msg.message == WM_MOVE) { // move event
+ int a = (int) (short) LOWORD(msg.lParam);
+ int b = (int) (short) HIWORD(msg.lParam);
+ QPoint oldPos = geometry().topLeft();
+ QPoint newCPos(a, b);
+ // Ignore silly Windows move event to wild pos after iconify.
+#if !defined(Q_WS_WINCE)
+ if (!IsIconic(internalWinId()) && newCPos != oldPos) {
+#endif
+ cr.moveTopLeft(newCPos);
+ data->crect = cr;
+ if (isVisible()) {
+ QMoveEvent e(newCPos, oldPos); // cpos (client position)
+ QApplication::sendSpontaneousEvent(this, &e);
+ } else {
+ QMoveEvent * e = new QMoveEvent(newCPos, oldPos);
+ QApplication::postEvent(this, e);
+ }
+#if !defined(Q_WS_WINCE)
+ }
+#endif
+ }
+ setAttribute(Qt::WA_WState_ConfigPending, false); // clear config flag
+ return true;
+}
+
+
+//
+// Close window event translation.
+//
+// This class is a friend of QApplication because it needs to emit the
+// lastWindowClosed() signal when the last top level widget is closed.
+//
+
+bool QETWidget::translateCloseEvent(const MSG &)
+{
+ return d_func()->close_helper(QWidgetPrivate::CloseWithSpontaneousEvent);
+}
+
+#ifndef QT_NO_GESTURES
+bool QETWidget::translateGestureEvent(const MSG &, const GESTUREINFO &gi)
+{
+ const QPoint widgetPos = QPoint(gi.ptsLocation.x, gi.ptsLocation.y);
+ QWidget *alienWidget = !internalWinId() ? this : childAt(widgetPos);
+ if (alienWidget && alienWidget->internalWinId())
+ alienWidget = 0;
+ QWidget *widget = alienWidget ? alienWidget : this;
+
+ QNativeGestureEvent event;
+ event.sequenceId = gi.dwSequenceID;
+ event.position = QPoint(gi.ptsLocation.x, gi.ptsLocation.y);
+ event.argument = gi.ullArguments;
+
+ switch (gi.dwID) {
+ case GID_BEGIN:
+ event.gestureType = QNativeGestureEvent::GestureBegin;
+ break;
+ case GID_END:
+ event.gestureType = QNativeGestureEvent::GestureEnd;
+ break;
+ case GID_ZOOM:
+ event.gestureType = QNativeGestureEvent::Zoom;
+ break;
+ case GID_PAN:
+ event.gestureType = QNativeGestureEvent::Pan;
+ break;
+ case GID_ROTATE:
+ event.gestureType = QNativeGestureEvent::Rotate;
+ break;
+ case GID_TWOFINGERTAP:
+ case GID_ROLLOVER:
+ default:
+ break;
+ }
+ if (event.gestureType != QNativeGestureEvent::None)
+ qt_sendSpontaneousEvent(widget, &event);
+ return true;
+}
+#endif // QT_NO_GESTURES
+
+void QApplication::setCursorFlashTime(int msecs)
+{
+ SetCaretBlinkTime(msecs / 2);
+ QApplicationPrivate::cursor_flash_time = msecs;
+}
+
+
+int QApplication::cursorFlashTime()
+{
+ int blink = (int)GetCaretBlinkTime();
+ if (!blink)
+ return QApplicationPrivate::cursor_flash_time;
+ if (blink > 0)
+ return 2*blink;
+ return 0;
+}
+
+
+void QApplication::setDoubleClickInterval(int ms)
+{
+#ifndef Q_WS_WINCE
+ SetDoubleClickTime(ms);
+#endif
+ QApplicationPrivate::mouse_double_click_time = ms;
+}
+
+int QApplication::doubleClickInterval()
+{
+ int ms = GetDoubleClickTime();
+ if (ms != 0)
+ return ms;
+ return QApplicationPrivate::mouse_double_click_time;
+}
+
+
+void QApplication::setKeyboardInputInterval(int ms)
+{
+ QApplicationPrivate::keyboard_input_time = ms;
+}
+
+int QApplication::keyboardInputInterval()
+{
+ // FIXME: get from the system
+ return QApplicationPrivate::keyboard_input_time;
+}
+
+#ifndef QT_NO_WHEELEVENT
+void QApplication::setWheelScrollLines(int n)
+{
+#ifdef SPI_SETWHEELSCROLLLINES
+ if (n < 0)
+ n = 0;
+ SystemParametersInfo(SPI_SETWHEELSCROLLLINES, (uint)n, 0, 0);
+#else
+ QApplicationPrivate::wheel_scroll_lines = n;
+#endif
+}
+
+int QApplication::wheelScrollLines()
+{
+#ifdef SPI_GETWHEELSCROLLLINES
+ uint i = 3;
+ SystemParametersInfo(SPI_GETWHEELSCROLLLINES, sizeof(uint), &i, 0);
+ if (i > INT_MAX)
+ i = INT_MAX;
+ return i;
+#else
+ return QApplicationPrivate::wheel_scroll_lines;
+#endif
+}
+#endif //QT_NO_WHEELEVENT
+
+static bool effect_override = false;
+
+void QApplication::setEffectEnabled(Qt::UIEffect effect, bool enable)
+{
+ effect_override = true;
+ switch (effect) {
+ case Qt::UI_AnimateMenu:
+ QApplicationPrivate::animate_menu = enable;
+ break;
+ case Qt::UI_FadeMenu:
+ QApplicationPrivate::fade_menu = enable;
+ break;
+ case Qt::UI_AnimateCombo:
+ QApplicationPrivate::animate_combo = enable;
+ break;
+ case Qt::UI_AnimateTooltip:
+ QApplicationPrivate::animate_tooltip = enable;
+ break;
+ case Qt::UI_FadeTooltip:
+ QApplicationPrivate::fade_tooltip = enable;
+ break;
+ case Qt::UI_AnimateToolBox:
+ QApplicationPrivate::animate_toolbox = enable;
+ break;
+ default:
+ QApplicationPrivate::animate_ui = enable;
+ break;
+ }
+}
+
+bool QApplication::isEffectEnabled(Qt::UIEffect effect)
+{
+ if (QColormap::instance().depth() < 16)
+ return false;
+
+ if (!effect_override && desktopSettingsAware()) {
+ // we know that they can be used when we are here
+ BOOL enabled = false;
+ UINT api;
+ switch (effect) {
+ case Qt::UI_AnimateMenu:
+ api = SPI_GETMENUANIMATION;
+ break;
+ case Qt::UI_FadeMenu:
+ api = SPI_GETMENUFADE;
+ break;
+ case Qt::UI_AnimateCombo:
+ api = SPI_GETCOMBOBOXANIMATION;
+ break;
+ case Qt::UI_AnimateTooltip:
+ api = SPI_GETTOOLTIPANIMATION;
+ break;
+ case Qt::UI_FadeTooltip:
+ api = SPI_GETTOOLTIPFADE;
+ break;
+ default:
+ api = SPI_GETUIEFFECTS;
+ break;
+ }
+ SystemParametersInfo(api, 0, &enabled, 0);
+ return enabled;
+ }
+
+ switch(effect) {
+ case Qt::UI_AnimateMenu:
+ return QApplicationPrivate::animate_menu;
+ case Qt::UI_FadeMenu:
+ return QApplicationPrivate::fade_menu;
+ case Qt::UI_AnimateCombo:
+ return QApplicationPrivate::animate_combo;
+ case Qt::UI_AnimateTooltip:
+ return QApplicationPrivate::animate_tooltip;
+ case Qt::UI_FadeTooltip:
+ return QApplicationPrivate::fade_tooltip;
+ case Qt::UI_AnimateToolBox:
+ return QApplicationPrivate::animate_toolbox;
+ default:
+ return QApplicationPrivate::animate_ui;
+ }
+}
+
+#ifndef QT_NO_SESSIONMANAGER
+
+bool QSessionManager::allowsInteraction()
+{
+ sm_blockUserInput = false;
+ return true;
+}
+
+bool QSessionManager::allowsErrorInteraction()
+{
+ sm_blockUserInput = false;
+ return true;
+}
+
+void QSessionManager::release()
+{
+ if (sm_smActive)
+ sm_blockUserInput = true;
+}
+
+void QSessionManager::cancel()
+{
+ sm_cancel = true;
+}
+
+#endif //QT_NO_SESSIONMANAGER
+
+
+bool QApplicationPrivate::HasTouchSupport = false;
+PtrRegisterTouchWindow QApplicationPrivate::RegisterTouchWindow = 0;
+PtrGetTouchInputInfo QApplicationPrivate::GetTouchInputInfo = 0;
+PtrCloseTouchInputHandle QApplicationPrivate::CloseTouchInputHandle = 0;
+
+void QApplicationPrivate::initializeMultitouch_sys()
+{
+ if (QSysInfo::windowsVersion() >= QSysInfo::WV_WINDOWS7) {
+ static const int QT_SM_DIGITIZER = 94;
+ int value = GetSystemMetrics(QT_SM_DIGITIZER);
+ static const int QT_NID_INTEGRATED_TOUCH = 0x01;
+ static const int QT_NID_EXTERNAL_TOUCH = 0x02;
+ static const int QT_NID_MULTI_INPUT = 0x40;
+ QApplicationPrivate::HasTouchSupport =
+ value & (QT_NID_INTEGRATED_TOUCH | QT_NID_EXTERNAL_TOUCH | QT_NID_MULTI_INPUT);
+ }
+
+ QSystemLibrary library(QLatin1String("user32"));
+ // MinGW (g++ 3.4.5) accepts only C casts.
+ RegisterTouchWindow = (PtrRegisterTouchWindow)(library.resolve("RegisterTouchWindow"));
+ GetTouchInputInfo = (PtrGetTouchInputInfo)(library.resolve("GetTouchInputInfo"));
+ CloseTouchInputHandle = (PtrCloseTouchInputHandle)(library.resolve("CloseTouchInputHandle"));
+
+ touchInputIDToTouchPointID.clear();
+}
+
+void QApplicationPrivate::cleanupMultitouch_sys()
+{
+ touchInputIDToTouchPointID.clear();
+}
+
+bool QApplicationPrivate::translateTouchEvent(const MSG &msg)
+{
+ QWidget *widgetForHwnd = QWidget::find(msg.hwnd);
+ if (!widgetForHwnd)
+ return false;
+
+ QRect screenGeometry = QApplication::desktop()->screenGeometry(widgetForHwnd);
+
+ QList<QTouchEvent::TouchPoint> touchPoints;
+
+ QVector<TOUCHINPUT> winTouchInputs(msg.wParam);
+ memset(winTouchInputs.data(), 0, sizeof(TOUCHINPUT) * winTouchInputs.count());
+ Qt::TouchPointStates allStates = 0;
+ QApplicationPrivate::GetTouchInputInfo((HANDLE) msg.lParam, msg.wParam, winTouchInputs.data(), sizeof(TOUCHINPUT));
+ for (int i = 0; i < winTouchInputs.count(); ++i) {
+ const TOUCHINPUT &touchInput = winTouchInputs.at(i);
+
+ int touchPointID = touchInputIDToTouchPointID.value(touchInput.dwID, -1);
+ if (touchPointID == -1) {
+ touchPointID = touchInputIDToTouchPointID.count();
+ touchInputIDToTouchPointID.insert(touchInput.dwID, touchPointID);
+ }
+
+ QTouchEvent::TouchPoint touchPoint(touchPointID);
+
+ // update state
+ QPointF screenPos(qreal(touchInput.x) / qreal(100.), qreal(touchInput.y) / qreal(100.));
+ QRectF screenRect;
+ if (touchInput.dwMask & TOUCHINPUTMASKF_CONTACTAREA)
+ screenRect.setSize(QSizeF(qreal(touchInput.cxContact) / qreal(100.),
+ qreal(touchInput.cyContact) / qreal(100.)));
+ screenRect.moveCenter(screenPos);
+
+ Qt::TouchPointStates state;
+ if (touchInput.dwFlags & TOUCHEVENTF_DOWN) {
+ state = Qt::TouchPointPressed;
+ } else if (touchInput.dwFlags & TOUCHEVENTF_UP) {
+ state = Qt::TouchPointReleased;
+ } else {
+ state = (screenPos == touchPoint.screenPos()
+ ? Qt::TouchPointStationary
+ : Qt::TouchPointMoved);
+ }
+ if (touchInput.dwFlags & TOUCHEVENTF_PRIMARY)
+ state |= Qt::TouchPointPrimary;
+ touchPoint.setState(state);
+ touchPoint.setScreenRect(screenRect);
+ touchPoint.setNormalizedPos(QPointF(screenPos.x() / screenGeometry.width(),
+ screenPos.y() / screenGeometry.height()));
+
+ allStates |= state;
+
+ touchPoints.append(touchPoint);
+ }
+ QApplicationPrivate::CloseTouchInputHandle((HANDLE) msg.lParam);
+
+ if ((allStates & Qt::TouchPointStateMask) == Qt::TouchPointReleased) {
+ // all touch points released, forget the ids we've seen, they may not be reused
+ touchInputIDToTouchPointID.clear();
+ }
+
+ translateRawTouchEvent(widgetForHwnd, QTouchEvent::TouchScreen, touchPoints);
+ return true;
+}
+
+QT_END_NAMESPACE
diff --git a/src/gui/platforms/win/qclipboard_win.cpp b/src/gui/platforms/win/qclipboard_win.cpp
new file mode 100644
index 0000000000..ea41165b9c
--- /dev/null
+++ b/src/gui/platforms/win/qclipboard_win.cpp
@@ -0,0 +1,398 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qclipboard.h"
+
+#ifndef QT_NO_CLIPBOARD
+
+#include "qapplication.h"
+#include "qapplication_p.h"
+#include "qeventloop.h"
+#include "qwidget.h"
+#include "qevent.h"
+#include "qmime.h"
+#include "qt_windows.h"
+#include "qdnd_p.h"
+#include <private/qwidget_p.h>
+#include <private/qsystemlibrary_p.h>
+
+QT_BEGIN_NAMESPACE
+
+#if defined(Q_OS_WINCE)
+QT_BEGIN_INCLUDE_NAMESPACE
+#include "qguifunctions_wince.h"
+QT_END_INCLUDE_NAMESPACE
+
+HRESULT QtCeGetClipboard(IDataObject** obj);
+HRESULT QtCeSetClipboard(IDataObject* obj);
+void QtCeFlushClipboard();
+
+#define OleGetClipboard QtCeGetClipboard
+#define OleSetClipboard QtCeSetClipboard
+#define OleFlushClipboard QtCeFlushClipboard
+
+#endif
+
+typedef BOOL (WINAPI *PtrIsHungAppWindow)(HWND);
+
+static PtrIsHungAppWindow ptrIsHungAppWindow = 0;
+
+class QClipboardWatcher : public QInternalMimeData {
+public:
+ QClipboardWatcher()
+ : QInternalMimeData()
+ {
+ }
+
+ bool hasFormat_sys(const QString &mimetype) const;
+ QStringList formats_sys() const;
+ QVariant retrieveData_sys(const QString &mimetype, QVariant::Type preferredType) const;
+};
+
+
+bool QClipboardWatcher::hasFormat_sys(const QString &mime) const
+{
+ IDataObject * pDataObj = 0;
+
+ if (OleGetClipboard(&pDataObj) != S_OK && !pDataObj) // Sanity
+ return false;
+
+ bool has = QWindowsMime::converterToMime(mime, pDataObj) != 0;
+
+ pDataObj->Release();
+
+ return has;
+}
+
+QStringList QClipboardWatcher::formats_sys() const
+{
+ QStringList fmts;
+ IDataObject * pDataObj = 0;
+
+ if (OleGetClipboard(&pDataObj) != S_OK && !pDataObj) // Sanity
+ return QStringList();
+
+ fmts = QWindowsMime::allMimesForFormats(pDataObj);
+
+ pDataObj->Release();
+
+ return fmts;
+}
+
+QVariant QClipboardWatcher::retrieveData_sys(const QString &mimeType, QVariant::Type type) const
+{
+ QVariant result;
+ IDataObject * pDataObj = 0;
+
+ if (OleGetClipboard(&pDataObj) != S_OK && !pDataObj) // Sanity
+ return result;
+
+ QWindowsMime *converter = QWindowsMime::converterToMime(mimeType, pDataObj);
+
+ if (converter)
+ result = converter->convertToMime(mimeType, pDataObj, type);
+
+ pDataObj->Release();
+
+ return result;
+}
+
+class QClipboardData
+{
+public:
+ QClipboardData()
+ : iData(0)
+ , nextClipboardViewer(0)
+ {
+ clipBoardViewer = new QWidget();
+ clipBoardViewer->createWinId();
+ clipBoardViewer->setObjectName(QLatin1String("internal clipboard owner"));
+ // We don't need this internal widget to appear in QApplication::topLevelWidgets()
+ if (QWidgetPrivate::allWidgets)
+ QWidgetPrivate::allWidgets->remove(clipBoardViewer);
+ }
+
+ ~QClipboardData()
+ {
+ Q_ASSERT(clipBoardViewer->testAttribute(Qt::WA_WState_Created));
+ ChangeClipboardChain(clipBoardViewer->internalWinId(), nextClipboardViewer);
+ delete clipBoardViewer;
+ releaseIData();
+ }
+
+ void releaseIData()
+ {
+ if (iData) {
+ delete iData->mimeData();
+ iData->releaseQt();
+ iData->Release();
+ iData = 0;
+ }
+ }
+
+ QOleDataObject * iData;
+ QWidget *clipBoardViewer;
+ HWND nextClipboardViewer;
+ QClipboardWatcher watcher;
+};
+
+static QClipboardData *ptrClipboardData = 0;
+
+static QClipboardData *clipboardData()
+{
+ if (ptrClipboardData == 0) {
+ ptrClipboardData = new QClipboardData;
+ // this needs to be done here to avoid recursion
+ Q_ASSERT(ptrClipboardData->clipBoardViewer->testAttribute(Qt::WA_WState_Created));
+ ptrClipboardData->nextClipboardViewer = SetClipboardViewer(ptrClipboardData->clipBoardViewer->internalWinId());
+ }
+ return ptrClipboardData;
+}
+
+static void cleanupClipboardData()
+{
+ delete ptrClipboardData;
+ ptrClipboardData = 0;
+}
+
+#if defined(Q_OS_WINCE)
+HRESULT QtCeGetClipboard(IDataObject** obj)
+{
+ HWND owner = ptrClipboardData->clipBoardViewer->internalWinId();
+ if (!OpenClipboard(owner))
+ return !S_OK;
+
+ if (!IsClipboardFormatAvailable(CF_TEXT) && !IsClipboardFormatAvailable(CF_UNICODETEXT))
+ return !S_OK;
+
+ HANDLE clipData = GetClipboardData(CF_TEXT);
+ QString clipText;
+ if (clipData == 0) {
+ clipData = GetClipboardData(CF_UNICODETEXT);
+ if (clipData != 0)
+ clipText = QString::fromWCharArray((wchar_t *)clipData);
+ } else {
+ clipText = QString::fromLatin1((const char*)clipData);
+ }
+
+ QMimeData *mimeData = new QMimeData();
+ mimeData->setText(clipText);
+ QOleDataObject* data = new QOleDataObject(mimeData);
+ *obj = data;
+ CloseClipboard();
+ return S_OK;
+}
+
+HRESULT QtCeSetClipboard(IDataObject* obj)
+{
+ HWND owner = ptrClipboardData->clipBoardViewer->internalWinId();
+ if (!OpenClipboard(owner))
+ return !S_OK;
+
+ bool result = false;
+ if (obj == 0) {
+ result = true;
+ EmptyClipboard();
+ CloseClipboard();
+ } else {
+ QOleDataObject* qobj = static_cast<QOleDataObject*>(obj);
+
+ const QMimeData* data = qobj->mimeData();
+ if (data->hasText()) {
+ EmptyClipboard();
+ result = SetClipboardData(CF_UNICODETEXT, wcsdup(reinterpret_cast<const wchar_t *> (data->text().utf16()))) != NULL;
+ CloseClipboard();
+ result = true;
+ }
+ }
+ return result ? S_OK : !S_OK;
+}
+
+void QtCeFlushClipboard() { }
+#endif
+
+
+
+QClipboard::~QClipboard()
+{
+ cleanupClipboardData();
+}
+
+void QClipboard::setMimeData(QMimeData *src, Mode mode)
+{
+ if (mode != Clipboard)
+ return;
+ QClipboardData *d = clipboardData();
+
+ if (!(d->iData && d->iData->mimeData() == src)) {
+ d->releaseIData();
+ d->iData = new QOleDataObject(src);
+ }
+
+ if (OleSetClipboard(d->iData) != S_OK) {
+ d->releaseIData();
+ qErrnoWarning("QClipboard::setMimeData: Failed to set data on clipboard");
+ return;
+ }
+#if defined(Q_OS_WINCE)
+ // As WinCE does not support notifications we send the signal here
+ // We will get no event when the clipboard changes outside...
+ emit dataChanged();
+ emit changed(Clipboard);
+#endif
+}
+
+void QClipboard::clear(Mode mode)
+{
+ if (mode != Clipboard) return;
+
+ QClipboardData *d = clipboardData();
+
+ d->releaseIData();
+
+ if (OleSetClipboard(0) != S_OK) {
+ qErrnoWarning("QClipboard::clear: Failed to clear data on clipboard");
+ return;
+ }
+#if defined(Q_OS_WINCE)
+ // As WinCE does not support notifications we send the signal here
+ // We will get no event when the clipboard changes outside...
+ emit dataChanged();
+ emit changed(Clipboard);
+#endif
+}
+
+bool QClipboard::event(QEvent *e)
+{
+ if (e->type() != QEvent::Clipboard)
+ return QObject::event(e);
+
+ QClipboardData *d = clipboardData();
+
+ MSG *m = (MSG *)((QClipboardEvent*)e)->data();
+ if (!m) {
+ // this is sent to render all formats at app shut down
+ if (ownsClipboard()) {
+ OleFlushClipboard();
+ d->releaseIData();
+ }
+ return true;
+ }
+
+ bool propagate = false;
+
+ if (m->message == WM_CHANGECBCHAIN) {
+ if ((HWND)m->wParam == d->nextClipboardViewer)
+ d->nextClipboardViewer = (HWND)m->lParam;
+ else
+ propagate = true;
+ } else if (m->message == WM_DRAWCLIPBOARD) {
+ emitChanged(QClipboard::Clipboard);
+ if (!ownsClipboard() && d->iData)
+ // clean up the clipboard object if we no longer own the clipboard
+ d->releaseIData();
+ propagate = true;
+ }
+ if (propagate && d->nextClipboardViewer) {
+ if (ptrIsHungAppWindow == 0) {
+ QSystemLibrary library(QLatin1String("User32"));
+ ptrIsHungAppWindow = (PtrIsHungAppWindow)library.resolve("IsHungAppWindow");
+ }
+ if (ptrIsHungAppWindow && ptrIsHungAppWindow(d->nextClipboardViewer)) {
+ qWarning("%s: Cowardly refusing to send clipboard message to hung application...", Q_FUNC_INFO);
+ } else {
+ SendMessage(d->nextClipboardViewer, m->message, m->wParam, m->lParam);
+ }
+ }
+
+ return true;
+}
+
+void QClipboard::connectNotify(const char *signal)
+{
+ if (qstrcmp(signal,SIGNAL(dataChanged())) == 0) {
+ // ensure we are up and running but block signals so the dataChange signal
+ // is not emitted while being connected to.
+ bool blocked = blockSignals(true);
+ QClipboardData *d = clipboardData();
+ blockSignals(blocked);
+ Q_UNUSED(d);
+ }
+}
+
+const QMimeData *QClipboard::mimeData(Mode mode) const
+{
+ if (mode != Clipboard)
+ return 0;
+
+ QClipboardData *data = clipboardData();
+ // sort cut for local copy / paste
+ if (ownsClipboard() && data->iData->mimeData())
+ return data->iData->mimeData();
+ return &data->watcher;
+}
+
+bool QClipboard::supportsMode(Mode mode) const
+{
+ return (mode == Clipboard);
+}
+
+bool QClipboard::ownsMode(Mode mode) const
+{
+ if (mode == Clipboard) {
+ QClipboardData *d = clipboardData();
+#if !defined(Q_OS_WINCE)
+ return d->iData && OleIsCurrentClipboard(d->iData) == S_OK;
+#else
+ return d->iData && GetClipboardOwner() == d->clipBoardViewer->internalWinId();
+#endif
+ } else {
+ return false;
+ }
+}
+
+void QClipboard::ownerDestroyed()
+{
+}
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_CLIPBOARD
diff --git a/src/gui/platforms/win/qcolormap_win.cpp b/src/gui/platforms/win/qcolormap_win.cpp
new file mode 100644
index 0000000000..1773f717c0
--- /dev/null
+++ b/src/gui/platforms/win/qcolormap_win.cpp
@@ -0,0 +1,201 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qcolor.h"
+#include "qcolormap.h"
+#include "qvector.h"
+#include "qt_windows.h"
+
+#if defined(Q_WS_WINCE)
+#include "qguifunctions_wince.h"
+#endif
+
+QT_BEGIN_NAMESPACE
+
+class QColormapPrivate
+{
+public:
+ inline QColormapPrivate()
+ : ref(1), mode(QColormap::Direct), depth(0), hpal(0)
+ { }
+
+ QAtomicInt ref;
+
+ QColormap::Mode mode;
+ int depth;
+ int numcolors;
+
+ HPALETTE hpal;
+ QVector<QColor> palette;
+};
+
+static QColormapPrivate *screenMap = 0;
+
+void QColormap::initialize()
+{
+ HDC dc = qt_win_display_dc();
+
+ screenMap = new QColormapPrivate;
+ screenMap->depth = GetDeviceCaps(dc, BITSPIXEL);
+
+ screenMap->numcolors = -1;
+ if (GetDeviceCaps(dc, RASTERCAPS) & RC_PALETTE)
+ screenMap->numcolors = GetDeviceCaps(dc, SIZEPALETTE);
+
+ if (screenMap->numcolors <= 16 || screenMap->numcolors > 256) // no need to create palette
+ return;
+
+ LOGPALETTE* pal = 0;
+ int numPalEntries = 6*6*6; // color cube
+
+ pal = (LOGPALETTE*)malloc(sizeof(LOGPALETTE) + numPalEntries * sizeof(PALETTEENTRY));
+ // Make 6x6x6 color cube
+ int idx = 0;
+ for(int ir = 0x0; ir <= 0xff; ir+=0x33) {
+ for(int ig = 0x0; ig <= 0xff; ig+=0x33) {
+ for(int ib = 0x0; ib <= 0xff; ib+=0x33) {
+ pal->palPalEntry[idx].peRed = ir;
+ pal->palPalEntry[idx].peGreen = ig;
+ pal->palPalEntry[idx].peBlue = ib;
+ pal->palPalEntry[idx].peFlags = 0;
+ idx++;
+ }
+ }
+ }
+
+ pal->palVersion = 0x300;
+ pal->palNumEntries = numPalEntries;
+
+ screenMap->hpal = CreatePalette(pal);
+ if (!screenMap->hpal)
+ qErrnoWarning("QColor::initialize: Failed to create logical palette");
+ free (pal);
+
+ SelectPalette(dc, screenMap->hpal, FALSE);
+ RealizePalette(dc);
+
+ PALETTEENTRY paletteEntries[256];
+ screenMap->numcolors = GetPaletteEntries(screenMap->hpal, 0, 255, paletteEntries);
+
+ screenMap->palette.resize(screenMap->numcolors);
+ for (int i = 0; i < screenMap->numcolors; i++) {
+ screenMap->palette[i] = qRgb(paletteEntries[i].peRed,
+ paletteEntries[i].peGreen,
+ paletteEntries[i].peBlue);
+ }
+}
+
+void QColormap::cleanup()
+{
+ if (!screenMap)
+ return;
+
+ if (screenMap->hpal) { // delete application global
+ DeleteObject(screenMap->hpal); // palette
+ screenMap->hpal = 0;
+ }
+
+ delete screenMap;
+ screenMap = 0;
+}
+
+QColormap QColormap::instance(int)
+{
+ Q_ASSERT_X(screenMap, "QColormap",
+ "A QApplication object needs to be constructed before QColormap is used.");
+ return QColormap();
+}
+
+QColormap::QColormap()
+ : d(screenMap)
+{ d->ref.ref(); }
+
+QColormap::QColormap(const QColormap &colormap)
+ :d (colormap.d)
+{ d->ref.ref(); }
+
+QColormap::~QColormap()
+{
+ if (!d->ref.deref())
+ delete d;
+}
+
+QColormap::Mode QColormap::mode() const
+{ return d->mode; }
+
+int QColormap::depth() const
+{ return d->depth; }
+
+int QColormap::size() const
+{ return d->numcolors; }
+
+uint QColormap::pixel(const QColor &color) const
+{
+ const QColor c = color.toRgb();
+ COLORREF rgb = RGB(c.red(), c.green(), c.blue());
+ if (d->hpal)
+ return PALETTEINDEX(GetNearestPaletteIndex(d->hpal, rgb));
+ return rgb;
+}
+
+const QColor QColormap::colorAt(uint pixel) const
+{
+ if (d->hpal) {
+ if (pixel < uint(d->numcolors))
+ return d->palette.at(pixel);
+ return QColor();
+ }
+ return QColor(GetRValue(pixel), GetGValue(pixel), GetBValue(pixel));
+}
+
+
+HPALETTE QColormap::hPal()
+{ return screenMap ? screenMap->hpal : 0; }
+
+
+const QVector<QColor> QColormap::colormap() const
+{ return d->palette; }
+
+QColormap &QColormap::operator=(const QColormap &colormap)
+{ qAtomicAssign(d, colormap.d); return *this; }
+
+
+QT_END_NAMESPACE
diff --git a/src/gui/platforms/win/qcursor_win.cpp b/src/gui/platforms/win/qcursor_win.cpp
new file mode 100644
index 0000000000..8a9362ebfc
--- /dev/null
+++ b/src/gui/platforms/win/qcursor_win.cpp
@@ -0,0 +1,492 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <private/qcursor_p.h>
+#include <qbitmap.h>
+#include <qcursor.h>
+
+#ifndef QT_NO_CURSOR
+
+#include <qimage.h>
+#include <qt_windows.h>
+#include <private/qapplication_p.h>
+
+QT_BEGIN_NAMESPACE
+
+/*****************************************************************************
+ Internal QCursorData class
+ *****************************************************************************/
+
+QCursorData::QCursorData(Qt::CursorShape s)
+ : cshape(s), bm(0), bmm(0), hx(0), hy(0), hcurs(0)
+{
+ ref = 1;
+}
+
+QCursorData::~QCursorData()
+{
+ delete bm;
+ delete bmm;
+#if !defined(Q_WS_WINCE) || defined(GWES_ICONCURS)
+ if (hcurs)
+ DestroyCursor(hcurs);
+#endif
+}
+
+
+QCursorData *QCursorData::setBitmap(const QBitmap &bitmap, const QBitmap &mask, int hotX, int hotY)
+{
+ if (!QCursorData::initialized)
+ QCursorData::initialize();
+ if (bitmap.depth() != 1 || mask.depth() != 1 || bitmap.size() != mask.size()) {
+ qWarning("QCursor: Cannot create bitmap cursor; invalid bitmap(s)");
+ QCursorData *c = qt_cursorTable[0];
+ c->ref.ref();
+ return c;
+ }
+ QCursorData *d = new QCursorData;
+ d->bm = new QBitmap(bitmap);
+ d->bmm = new QBitmap(mask);
+ d->hcurs = 0;
+ d->cshape = Qt::BitmapCursor;
+ d->hx = hotX >= 0 ? hotX : bitmap.width()/2;
+ d->hy = hotY >= 0 ? hotY : bitmap.height()/2;
+ return d;
+}
+
+HCURSOR QCursor::handle() const
+{
+ if (!QCursorData::initialized)
+ QCursorData::initialize();
+ if (!d->hcurs)
+ d->update();
+ return d->hcurs;
+}
+
+QCursor::QCursor(HCURSOR handle)
+{
+ d = new QCursorData(Qt::CustomCursor);
+ d->hcurs = handle;
+}
+
+#endif //QT_NO_CURSOR
+
+QPoint QCursor::pos()
+{
+ POINT p;
+ GetCursorPos(&p);
+ return QPoint(p.x, p.y);
+}
+
+void QCursor::setPos(int x, int y)
+{
+ SetCursorPos(x, y);
+}
+
+#ifndef QT_NO_CURSOR
+
+extern HBITMAP qt_createIconMask(const QBitmap &bitmap);
+
+static HCURSOR create32BitCursor(const QPixmap &pixmap, int hx, int hy)
+{
+ HCURSOR cur = 0;
+#if !defined(Q_WS_WINCE)
+ QBitmap mask = pixmap.mask();
+ if (mask.isNull()) {
+ mask = QBitmap(pixmap.size());
+ mask.fill(Qt::color1);
+ }
+
+ HBITMAP ic = pixmap.toWinHBITMAP(QPixmap::Alpha);
+ HBITMAP im = qt_createIconMask(mask);
+
+ ICONINFO ii;
+ ii.fIcon = 0;
+ ii.xHotspot = hx;
+ ii.yHotspot = hy;
+ ii.hbmMask = im;
+ ii.hbmColor = ic;
+
+ cur = CreateIconIndirect(&ii);
+
+ DeleteObject(ic);
+ DeleteObject(im);
+#elif defined(GWES_ICONCURS)
+ QImage bbits, mbits;
+ bool invb, invm;
+ bbits = pixmap.toImage().convertToFormat(QImage::Format_Mono);
+ mbits = pixmap.toImage().convertToFormat(QImage::Format_Mono);
+ invb = bbits.colorCount() > 1 && qGray(bbits.color(0)) < qGray(bbits.color(1));
+ invm = mbits.colorCount() > 1 && qGray(mbits.color(0)) < qGray(mbits.color(1));
+
+ int sysW = GetSystemMetrics(SM_CXCURSOR);
+ int sysH = GetSystemMetrics(SM_CYCURSOR);
+ int sysN = qMax(1, sysW / 8);
+ int n = qMax(1, bbits.width() / 8);
+ int h = bbits.height();
+
+ uchar* xBits = new uchar[sysH * sysN];
+ uchar* xMask = new uchar[sysH * sysN];
+ int x = 0;
+ for (int i = 0; i < sysH; ++i) {
+ if (i >= h) {
+ memset(&xBits[x] , 255, sysN);
+ memset(&xMask[x] , 0, sysN);
+ x += sysN;
+ } else {
+ int fillWidth = n > sysN ? sysN : n;
+ uchar *bits = bbits.scanLine(i);
+ uchar *mask = mbits.scanLine(i);
+ for (int j = 0; j < fillWidth; ++j) {
+ uchar b = bits[j];
+ uchar m = mask[j];
+ if (invb)
+ b ^= 0xFF;
+ if (invm)
+ m ^= 0xFF;
+ xBits[x] = ~m;
+ xMask[x] = b ^ m;
+ ++x;
+ }
+ for (int j = fillWidth; j < sysN; ++j ) {
+ xBits[x] = 255;
+ xMask[x] = 0;
+ ++x;
+ }
+ }
+ }
+
+ cur = CreateCursor(qWinAppInst(), hx, hy, sysW, sysH,
+ xBits, xMask);
+#else
+ Q_UNUSED(pixmap);
+ Q_UNUSED(hx);
+ Q_UNUSED(hy);
+#endif
+ return cur;
+}
+
+void QCursorData::update()
+{
+ if (!QCursorData::initialized)
+ QCursorData::initialize();
+ if (hcurs)
+ return;
+
+ if (cshape == Qt::BitmapCursor && !pixmap.isNull()) {
+ hcurs = create32BitCursor(pixmap, hx, hy);
+ if (hcurs)
+ return;
+ }
+
+
+ // Non-standard Windows cursors are created from bitmaps
+
+ static const uchar vsplit_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x80, 0x00, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0xe0, 0x03, 0x00,
+ 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00,
+ 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0xff, 0x7f, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x7f, 0x00,
+ 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00,
+ 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0xe0, 0x03, 0x00,
+ 0x00, 0xc0, 0x01, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+ static const uchar vsplitm_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00,
+ 0x00, 0xc0, 0x01, 0x00, 0x00, 0xe0, 0x03, 0x00, 0x00, 0xf0, 0x07, 0x00,
+ 0x00, 0xf8, 0x0f, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0xc0, 0x01, 0x00,
+ 0x00, 0xc0, 0x01, 0x00, 0x80, 0xff, 0xff, 0x00, 0x80, 0xff, 0xff, 0x00,
+ 0x80, 0xff, 0xff, 0x00, 0x80, 0xff, 0xff, 0x00, 0x80, 0xff, 0xff, 0x00,
+ 0x80, 0xff, 0xff, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0xc0, 0x01, 0x00,
+ 0x00, 0xc0, 0x01, 0x00, 0x00, 0xf8, 0x0f, 0x00, 0x00, 0xf0, 0x07, 0x00,
+ 0x00, 0xe0, 0x03, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0x80, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+ static const uchar hsplit_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x02, 0x00, 0x00, 0x40, 0x02, 0x00,
+ 0x00, 0x40, 0x02, 0x00, 0x00, 0x40, 0x02, 0x00, 0x00, 0x40, 0x02, 0x00,
+ 0x00, 0x41, 0x82, 0x00, 0x80, 0x41, 0x82, 0x01, 0xc0, 0x7f, 0xfe, 0x03,
+ 0x80, 0x41, 0x82, 0x01, 0x00, 0x41, 0x82, 0x00, 0x00, 0x40, 0x02, 0x00,
+ 0x00, 0x40, 0x02, 0x00, 0x00, 0x40, 0x02, 0x00, 0x00, 0x40, 0x02, 0x00,
+ 0x00, 0x40, 0x02, 0x00, 0x00, 0x40, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+ static const uchar hsplitm_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xe0, 0x07, 0x00, 0x00, 0xe0, 0x07, 0x00, 0x00, 0xe0, 0x07, 0x00,
+ 0x00, 0xe0, 0x07, 0x00, 0x00, 0xe2, 0x47, 0x00, 0x00, 0xe3, 0xc7, 0x00,
+ 0x80, 0xe3, 0xc7, 0x01, 0xc0, 0xff, 0xff, 0x03, 0xe0, 0xff, 0xff, 0x07,
+ 0xc0, 0xff, 0xff, 0x03, 0x80, 0xe3, 0xc7, 0x01, 0x00, 0xe3, 0xc7, 0x00,
+ 0x00, 0xe2, 0x47, 0x00, 0x00, 0xe0, 0x07, 0x00, 0x00, 0xe0, 0x07, 0x00,
+ 0x00, 0xe0, 0x07, 0x00, 0x00, 0xe0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+ static const uchar phand_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x80, 0x04, 0x00, 0x00,
+ 0x80, 0x04, 0x00, 0x00, 0x80, 0x04, 0x00, 0x00, 0x80, 0x04, 0x00, 0x00,
+ 0x80, 0x1c, 0x00, 0x00, 0x80, 0xe4, 0x00, 0x00, 0x80, 0x24, 0x03, 0x00,
+ 0x80, 0x24, 0x05, 0x00, 0xb8, 0x24, 0x09, 0x00, 0xc8, 0x00, 0x09, 0x00,
+ 0x88, 0x00, 0x08, 0x00, 0x90, 0x00, 0x08, 0x00, 0xa0, 0x00, 0x08, 0x00,
+ 0x20, 0x00, 0x08, 0x00, 0x40, 0x00, 0x08, 0x00, 0x40, 0x00, 0x04, 0x00,
+ 0x80, 0x00, 0x04, 0x00, 0x80, 0x00, 0x04, 0x00, 0x00, 0x01, 0x02, 0x00,
+ 0x00, 0x01, 0x02, 0x00, 0x00, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+
+ static const uchar phandm_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x80, 0x07, 0x00, 0x00,
+ 0x80, 0x07, 0x00, 0x00, 0x80, 0x07, 0x00, 0x00, 0x80, 0x07, 0x00, 0x00,
+ 0x80, 0x1f, 0x00, 0x00, 0x80, 0xff, 0x00, 0x00, 0x80, 0xff, 0x03, 0x00,
+ 0x80, 0xff, 0x07, 0x00, 0xb8, 0xff, 0x0f, 0x00, 0xf8, 0xff, 0x0f, 0x00,
+ 0xf8, 0xff, 0x0f, 0x00, 0xf0, 0xff, 0x0f, 0x00, 0xe0, 0xff, 0x0f, 0x00,
+ 0xe0, 0xff, 0x0f, 0x00, 0xc0, 0xff, 0x0f, 0x00, 0xc0, 0xff, 0x07, 0x00,
+ 0x80, 0xff, 0x07, 0x00, 0x80, 0xff, 0x07, 0x00, 0x00, 0xff, 0x03, 0x00,
+ 0x00, 0xff, 0x03, 0x00, 0x00, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+
+ static const uchar openhand_bits[] = {
+ 0x80,0x01,0x58,0x0e,0x64,0x12,0x64,0x52,0x48,0xb2,0x48,0x92,
+ 0x16,0x90,0x19,0x80,0x11,0x40,0x02,0x40,0x04,0x40,0x04,0x20,
+ 0x08,0x20,0x10,0x10,0x20,0x10,0x00,0x00};
+ static const uchar openhandm_bits[] = {
+ 0x80,0x01,0xd8,0x0f,0xfc,0x1f,0xfc,0x5f,0xf8,0xff,0xf8,0xff,
+ 0xf6,0xff,0xff,0xff,0xff,0x7f,0xfe,0x7f,0xfc,0x7f,0xfc,0x3f,
+ 0xf8,0x3f,0xf0,0x1f,0xe0,0x1f,0x00,0x00};
+ static const uchar closedhand_bits[] = {
+ 0x00,0x00,0x00,0x00,0x00,0x00,0xb0,0x0d,0x48,0x32,0x08,0x50,
+ 0x10,0x40,0x18,0x40,0x04,0x40,0x04,0x20,0x08,0x20,0x10,0x10,
+ 0x20,0x10,0x20,0x10,0x00,0x00,0x00,0x00};
+ static const uchar closedhandm_bits[] = {
+ 0x00,0x00,0x00,0x00,0x00,0x00,0xb0,0x0d,0xf8,0x3f,0xf8,0x7f,
+ 0xf0,0x7f,0xf8,0x7f,0xfc,0x7f,0xfc,0x3f,0xf8,0x3f,0xf0,0x1f,
+ 0xe0,0x1f,0xe0,0x1f,0x00,0x00,0x00,0x00};
+
+ static const uchar * const cursor_bits32[] = {
+ vsplit_bits, vsplitm_bits, hsplit_bits, hsplitm_bits,
+ phand_bits, phandm_bits
+ };
+
+ wchar_t *sh = 0;
+ switch (cshape) { // map to windows cursor
+ case Qt::ArrowCursor:
+ sh = IDC_ARROW;
+ break;
+ case Qt::UpArrowCursor:
+ sh = IDC_UPARROW;
+ break;
+ case Qt::CrossCursor:
+ sh = IDC_CROSS;
+ break;
+ case Qt::WaitCursor:
+ sh = IDC_WAIT;
+ break;
+ case Qt::IBeamCursor:
+ sh = IDC_IBEAM;
+ break;
+ case Qt::SizeVerCursor:
+ sh = IDC_SIZENS;
+ break;
+ case Qt::SizeHorCursor:
+ sh = IDC_SIZEWE;
+ break;
+ case Qt::SizeBDiagCursor:
+ sh = IDC_SIZENESW;
+ break;
+ case Qt::SizeFDiagCursor:
+ sh = IDC_SIZENWSE;
+ break;
+ case Qt::SizeAllCursor:
+ sh = IDC_SIZEALL;
+ break;
+ case Qt::ForbiddenCursor:
+ sh = IDC_NO;
+ break;
+ case Qt::WhatsThisCursor:
+ sh = IDC_HELP;
+ break;
+ case Qt::BusyCursor:
+ sh = IDC_APPSTARTING;
+ break;
+ case Qt::PointingHandCursor:
+ sh = IDC_HAND;
+ break;
+ case Qt::BlankCursor:
+ case Qt::SplitVCursor:
+ case Qt::SplitHCursor:
+ case Qt::OpenHandCursor:
+ case Qt::ClosedHandCursor:
+ case Qt::BitmapCursor: {
+ QImage bbits, mbits;
+ bool invb, invm;
+ if (cshape == Qt::BlankCursor) {
+ bbits = QImage(32, 32, QImage::Format_Mono);
+ bbits.fill(0); // ignore color table
+ mbits = bbits.copy();
+ hx = hy = 16;
+ invb = invm = false;
+ } else if (cshape == Qt::OpenHandCursor || cshape == Qt::ClosedHandCursor) {
+ bool open = cshape == Qt::OpenHandCursor;
+ QBitmap cb = QBitmap::fromData(QSize(16, 16), open ? openhand_bits : closedhand_bits);
+ QBitmap cm = QBitmap::fromData(QSize(16, 16), open ? openhandm_bits : closedhandm_bits);
+ bbits = cb.toImage().convertToFormat(QImage::Format_Mono);
+ mbits = cm.toImage().convertToFormat(QImage::Format_Mono);
+ hx = hy = 8;
+ invb = invm = false;
+ } else if (cshape != Qt::BitmapCursor) {
+ int i = cshape - Qt::SplitVCursor;
+ QBitmap cb = QBitmap::fromData(QSize(32, 32), cursor_bits32[i * 2]);
+ QBitmap cm = QBitmap::fromData(QSize(32, 32), cursor_bits32[i * 2 + 1]);
+ bbits = cb.toImage().convertToFormat(QImage::Format_Mono);
+ mbits = cm.toImage().convertToFormat(QImage::Format_Mono);
+ if (cshape == Qt::PointingHandCursor) {
+ hx = 7;
+ hy = 0;
+ } else
+ hx = hy = 16;
+ invb = invm = false;
+ } else {
+ bbits = bm->toImage().convertToFormat(QImage::Format_Mono);
+ mbits = bmm->toImage().convertToFormat(QImage::Format_Mono);
+ invb = bbits.colorCount() > 1 && qGray(bbits.color(0)) < qGray(bbits.color(1));
+ invm = mbits.colorCount() > 1 && qGray(mbits.color(0)) < qGray(mbits.color(1));
+ }
+ int n = qMax(1, bbits.width() / 8);
+ int h = bbits.height();
+#if !defined(Q_WS_WINCE)
+ uchar* xBits = new uchar[h * n];
+ uchar* xMask = new uchar[h * n];
+ int x = 0;
+ for (int i = 0; i < h; ++i) {
+ uchar *bits = bbits.scanLine(i);
+ uchar *mask = mbits.scanLine(i);
+ for (int j = 0; j < n; ++j) {
+ uchar b = bits[j];
+ uchar m = mask[j];
+ if (invb)
+ b ^= 0xff;
+ if (invm)
+ m ^= 0xff;
+ xBits[x] = ~m;
+ xMask[x] = b ^ m;
+ ++x;
+ }
+ }
+ hcurs = CreateCursor(qWinAppInst(), hx, hy, bbits.width(), bbits.height(),
+ xBits, xMask);
+ delete [] xBits;
+ delete [] xMask;
+#elif defined(GWES_ICONCURS) // Q_WS_WINCE
+ // Windows CE only supports fixed cursor size.
+ int sysW = GetSystemMetrics(SM_CXCURSOR);
+ int sysH = GetSystemMetrics(SM_CYCURSOR);
+ int sysN = qMax(1, sysW / 8);
+ uchar* xBits = new uchar[sysH * sysN];
+ uchar* xMask = new uchar[sysH * sysN];
+ int x = 0;
+ for (int i = 0; i < sysH; ++i) {
+ if (i >= h) {
+ memset(&xBits[x] , 255, sysN);
+ memset(&xMask[x] , 0, sysN);
+ x += sysN;
+ } else {
+ int fillWidth = n > sysN ? sysN : n;
+ uchar *bits = bbits.scanLine(i);
+ uchar *mask = mbits.scanLine(i);
+ for (int j = 0; j < fillWidth; ++j) {
+ uchar b = bits[j];
+ uchar m = mask[j];
+ if (invb)
+ b ^= 0xFF;
+ if (invm)
+ m ^= 0xFF;
+ xBits[x] = ~m;
+ xMask[x] = b ^ m;
+ ++x;
+ }
+ for (int j = fillWidth; j < sysN; ++j ) {
+ xBits[x] = 255;
+ xMask[x] = 0;
+ ++x;
+ }
+ }
+ }
+
+ hcurs = CreateCursor(qWinAppInst(), hx, hy, sysW, sysH,
+ xBits, xMask);
+ delete [] xBits;
+ delete [] xMask;
+#else
+ Q_UNUSED(n);
+ Q_UNUSED(h);
+#endif
+ return;
+ }
+ case Qt::DragCopyCursor:
+ case Qt::DragMoveCursor:
+ case Qt::DragLinkCursor: {
+ QPixmap pixmap = QApplicationPrivate::instance()->getPixmapCursor(cshape);
+ hcurs = create32BitCursor(pixmap, hx, hy);
+ }
+ default:
+ qWarning("QCursor::update: Invalid cursor shape %d", cshape);
+ return;
+ }
+#ifdef Q_WS_WINCE
+ hcurs = LoadCursor(0, sh);
+#else
+ hcurs = (HCURSOR)LoadImage(0, sh, IMAGE_CURSOR, 0, 0, LR_DEFAULTSIZE | LR_SHARED);
+#endif
+}
+
+QT_END_NAMESPACE
+#endif // QT_NO_CURSOR
diff --git a/src/gui/platforms/win/qdesktopwidget_win.cpp b/src/gui/platforms/win/qdesktopwidget_win.cpp
new file mode 100644
index 0000000000..d57b355ef4
--- /dev/null
+++ b/src/gui/platforms/win/qdesktopwidget_win.cpp
@@ -0,0 +1,387 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qdesktopwidget.h"
+#include "qt_windows.h"
+#include "qapplication_p.h"
+#include <private/qsystemlibrary_p.h>
+#include <qvector.h>
+#include <limits.h>
+#ifdef Q_WS_WINCE
+#include <sipapi.h>
+#endif
+#include "qwidget_p.h"
+#include "qdebug.h"
+
+QT_BEGIN_NAMESPACE
+
+class QDesktopWidgetPrivate : public QWidgetPrivate
+{
+public:
+ QDesktopWidgetPrivate();
+ ~QDesktopWidgetPrivate();
+
+ static void init(QDesktopWidget *that);
+ static void cleanup();
+ static int screenCount;
+ static int primaryScreen;
+
+ static QVector<QRect> *rects;
+ static QVector<QRect> *workrects;
+
+ struct MONITORINFO
+ {
+ DWORD cbSize;
+ RECT rcMonitor;
+ RECT rcWork;
+ DWORD dwFlags;
+ };
+
+ typedef BOOL (WINAPI *InfoFunc)(HMONITOR, MONITORINFO*);
+ typedef BOOL (QT_WIN_CALLBACK *EnumProc)(HMONITOR, HDC, LPRECT, LPARAM);
+ typedef BOOL (WINAPI *EnumFunc)(HDC, LPCRECT, EnumProc, LPARAM);
+
+ static EnumFunc enumDisplayMonitors;
+ static InfoFunc getMonitorInfo;
+ static int refcount;
+};
+
+int QDesktopWidgetPrivate::screenCount = 1;
+int QDesktopWidgetPrivate::primaryScreen = 0;
+QDesktopWidgetPrivate::EnumFunc QDesktopWidgetPrivate::enumDisplayMonitors = 0;
+QDesktopWidgetPrivate::InfoFunc QDesktopWidgetPrivate::getMonitorInfo = 0;
+QVector<QRect> *QDesktopWidgetPrivate::rects = 0;
+QVector<QRect> *QDesktopWidgetPrivate::workrects = 0;
+static int screen_number = 0;
+int QDesktopWidgetPrivate::refcount = 0;
+#ifdef Q_WS_WINCE_WM
+// Use SIP information, if available
+// SipGetInfo is not supported by SSDK (no definition!).
+static inline void qt_get_sip_info(QRect &rect)
+{
+ SIPINFO sip;
+ memset(&sip, 0, sizeof(SIPINFO));
+ sip.cbSize = sizeof(SIPINFO);
+ if (SipGetInfo(&sip))
+ rect = QRect(QPoint(sip.rcVisibleDesktop.left, sip.rcVisibleDesktop.top),
+ QPoint(sip.rcVisibleDesktop.right - 1, sip.rcVisibleDesktop.bottom - 1));
+}
+#endif
+
+
+BOOL QT_WIN_CALLBACK enumCallback(HMONITOR hMonitor, HDC, LPRECT, LPARAM)
+{
+ QDesktopWidgetPrivate::screenCount++;
+ QDesktopWidgetPrivate::rects->resize(QDesktopWidgetPrivate::screenCount);
+ QDesktopWidgetPrivate::workrects->resize(QDesktopWidgetPrivate::screenCount);
+ // Get the MONITORINFO block
+ QDesktopWidgetPrivate::MONITORINFO info;
+ memset(&info, 0, sizeof(QDesktopWidgetPrivate::MONITORINFO));
+ info.cbSize = sizeof(QDesktopWidgetPrivate::MONITORINFO);
+ BOOL res = QDesktopWidgetPrivate::getMonitorInfo(hMonitor, &info);
+ if (!res) {
+ (*QDesktopWidgetPrivate::rects)[screen_number] = QRect();
+ (*QDesktopWidgetPrivate::workrects)[screen_number] = QRect();
+ return true;
+ }
+
+ // Fill list of rects
+ RECT r = info.rcMonitor;
+ QRect qr(QPoint(r.left, r.top), QPoint(r.right - 1, r.bottom - 1));
+ (*QDesktopWidgetPrivate::rects)[screen_number] = qr;
+
+ r = info.rcWork;
+ qr = QRect(QPoint(r.left, r.top), QPoint(r.right - 1, r.bottom - 1));
+ (*QDesktopWidgetPrivate::workrects)[screen_number] = qr;
+
+ if (info.dwFlags & 0x00000001) //MONITORINFOF_PRIMARY
+ QDesktopWidgetPrivate::primaryScreen = screen_number;
+
+ ++screen_number;
+ // Stop the enumeration if we have them all
+ return true;
+}
+
+QDesktopWidgetPrivate::QDesktopWidgetPrivate()
+{
+ ++refcount;
+}
+
+void QDesktopWidgetPrivate::init(QDesktopWidget *that)
+{
+ if (rects)
+ return;
+
+ rects = new QVector<QRect>();
+ workrects = new QVector<QRect>();
+ screenCount = 0;
+
+#ifndef Q_OS_WINCE
+ QSystemLibrary user32Lib(QLatin1String("user32"));
+ enumDisplayMonitors = (EnumFunc)user32Lib.resolve("EnumDisplayMonitors");
+ getMonitorInfo = (InfoFunc)user32Lib.resolve("GetMonitorInfoW");
+
+ if (!enumDisplayMonitors || !getMonitorInfo) {
+ screenCount = GetSystemMetrics(80); // SM_CMONITORS
+ rects->resize(screenCount);
+ for (int i = 0; i < screenCount; ++i)
+ rects->replace(i, that->rect());
+ return;
+ }
+ // Calls enumCallback
+ enumDisplayMonitors(0, 0, enumCallback, 0);
+ enumDisplayMonitors = 0;
+ getMonitorInfo = 0;
+#else
+ QSystemLibrary coreLib(QLatin1String("coredll"));
+ // CE >= 4.0 case
+ enumDisplayMonitors = (EnumFunc)coreLib.resolve("EnumDisplayMonitors");
+ getMonitorInfo = (InfoFunc)coreLib.resolve("GetMonitorInfo");
+
+ if ((!enumDisplayMonitors || !getMonitorInfo)) {
+ screenCount = GetSystemMetrics(SM_CMONITORS);
+ return;
+ }
+
+ if (!coreLib.isLoaded() || !enumDisplayMonitors || !getMonitorInfo) {
+ rects->resize(screenCount);
+ for (int i = 0; i < screenCount; ++i)
+ (*rects)[i] = that->rect();
+
+ RECT r;
+ SystemParametersInfo(SPI_GETWORKAREA, 0, &r, 0);
+ QRect qr = QRect(QPoint(r.left, r.top), QPoint(r.right - 1, r.bottom - 1));
+
+#if defined(Q_WS_WINCE_WM)
+ qt_get_sip_info(qr);
+#endif
+
+ workrects->resize(screenCount);
+ for (int j = 0; j < screenCount; ++j)
+ (*workrects)[j] = qr;
+ return;
+ }
+
+ // Calls enumCallback
+ enumDisplayMonitors(0, 0, enumCallback, 0);
+ enumDisplayMonitors = 0;
+ getMonitorInfo = 0;
+#endif // Q_WS_WINCE
+}
+
+QDesktopWidgetPrivate::~QDesktopWidgetPrivate()
+{
+ if (!--refcount)
+ cleanup();
+}
+
+void QDesktopWidgetPrivate::cleanup()
+{
+ screen_number = 0;
+ screenCount = 1;
+ primaryScreen = 0;
+ enumDisplayMonitors = 0;
+ getMonitorInfo = 0;
+ delete rects;
+ rects = 0;
+ delete workrects;
+ workrects = 0;
+}
+
+/*
+ \omit
+ Function is commented out in header
+ \fn void *QDesktopWidget::handle(int screen) const
+
+ Returns the window system handle of the display device with the
+ index \a screen, for low-level access. Using this function is not
+ portable.
+
+ The return type varies with platform; see qwindowdefs.h for details.
+
+ \sa x11Display(), QPaintDevice::handle()
+ \endomit
+*/
+
+QDesktopWidget::QDesktopWidget()
+ : QWidget(*new QDesktopWidgetPrivate, 0, Qt::Desktop)
+{
+ setObjectName(QLatin1String("desktop"));
+ QDesktopWidgetPrivate::init(this);
+}
+
+QDesktopWidget::~QDesktopWidget()
+{
+}
+
+bool QDesktopWidget::isVirtualDesktop() const
+{
+ return true;
+}
+
+int QDesktopWidget::primaryScreen() const
+{
+ return d_func()->primaryScreen;
+}
+
+int QDesktopWidget::numScreens() const
+{
+ return d_func()->screenCount;
+}
+
+QWidget *QDesktopWidget::screen(int /* screen */)
+{
+ // It seems that a Qt::WType_Desktop cannot be moved?
+ return this;
+}
+
+//
+// MSVC 7.10 warns that d (the result of the expanded Q_D macro) as a local variable that is not referenced.
+// Therefore, we ignore that warning with the following pragmas
+// I've also tried to eliminate the macro, but to no use...
+// We pop it further down
+#ifdef Q_CC_MSVC
+# pragma warning(push)
+# pragma warning(disable : 4189)
+#endif
+const QRect QDesktopWidget::availableGeometry(int screen) const
+{
+ Q_D(const QDesktopWidget);
+#ifdef Q_WS_WINCE_WM
+ for(int i=0; i < d->workrects->size(); ++i)
+ qt_get_sip_info((*d->workrects)[i]);
+#endif
+ if (screen < 0 || screen >= d->screenCount)
+ screen = d->primaryScreen;
+
+ return d->workrects->at(screen);
+}
+
+const QRect QDesktopWidget::screenGeometry(int screen) const
+{
+ const QDesktopWidgetPrivate *d = d_func();
+ if (screen < 0 || screen >= d->screenCount)
+ screen = d->primaryScreen;
+
+ return d->rects->at(screen);
+}
+
+int QDesktopWidget::screenNumber(const QWidget *widget) const
+{
+ Q_D(const QDesktopWidget);
+ if (!widget)
+ return d->primaryScreen;
+
+ QRect frame = widget->frameGeometry();
+ if (!widget->isWindow())
+ frame.moveTopLeft(widget->mapToGlobal(QPoint(0,0)));
+
+ int maxSize = -1;
+ int maxScreen = -1;
+
+ for (int i = 0; i < d->screenCount; ++i) {
+ QRect sect = d->rects->at(i).intersected(frame);
+ int size = sect.width() * sect.height();
+ if (size > maxSize && sect.width() > 0 && sect.height() > 0) {
+ maxSize = size;
+ maxScreen = i;
+ }
+ }
+
+ return maxScreen;
+}
+
+int QDesktopWidget::screenNumber(const QPoint &point) const
+{
+ Q_D(const QDesktopWidget);
+
+ int closestScreen = -1;
+ int shortestDistance = INT_MAX;
+
+ for (int i = 0; i < d->screenCount; ++i) {
+ int thisDistance = d->pointToRect(point, d->rects->at(i));
+ if (thisDistance < shortestDistance) {
+ shortestDistance = thisDistance;
+ closestScreen = i;
+ }
+ }
+
+ return closestScreen;
+}
+
+void QDesktopWidget::resizeEvent(QResizeEvent *)
+{
+ Q_D(QDesktopWidget);
+ const QVector<QRect> oldrects(*d->rects);
+ const QVector<QRect> oldworkrects(*d->workrects);
+ int oldscreencount = d->screenCount;
+
+ QDesktopWidgetPrivate::cleanup();
+ QDesktopWidgetPrivate::init(this);
+#ifdef Q_WS_WINCE_WM
+ for(int i=0; i < d->workrects->size(); ++i)
+ qt_get_sip_info((*d->workrects)[i]);
+#endif
+
+ for (int i = 0; i < qMin(oldscreencount, d->screenCount); ++i) {
+ const QRect oldrect = oldrects[i];
+ const QRect newrect = d->rects->at(i);
+ if (oldrect != newrect)
+ emit resized(i);
+ }
+
+ for (int j = 0; j < qMin(oldscreencount, d->screenCount); ++j) {
+ const QRect oldrect = oldworkrects[j];
+ const QRect newrect = d->workrects->at(j);
+ if (oldrect != newrect)
+ emit workAreaResized(j);
+ }
+
+ if (oldscreencount != d->screenCount) {
+ emit screenCountChanged(d->screenCount);
+ }
+}
+
+#ifdef Q_CC_MSVC
+# pragma warning(pop)
+#endif
+
+QT_END_NAMESPACE
diff --git a/src/gui/platforms/win/qdnd_win.cpp b/src/gui/platforms/win/qdnd_win.cpp
new file mode 100644
index 0000000000..176e3cef7f
--- /dev/null
+++ b/src/gui/platforms/win/qdnd_win.cpp
@@ -0,0 +1,1027 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qapplication.h"
+
+#include "qapplication_p.h"
+#include "qevent.h"
+#include "qpainter.h"
+#include "qwidget.h"
+#include "qbuffer.h"
+#include "qdatastream.h"
+#include "qcursor.h"
+#include "qt_windows.h"
+#include <shlobj.h>
+#ifndef QT_NO_ACCESSIBILITY
+#include "qaccessible.h"
+#endif
+#include "qdnd_p.h"
+#include "qdebug.h"
+
+#if defined(Q_OS_WINCE)
+#include "qguifunctions_wince.h"
+#endif
+
+// support for xbuttons
+#ifndef MK_XBUTTON1
+#define MK_XBUTTON1 0x0020
+#define MK_XBUTTON2 0x0040
+#endif
+
+QT_BEGIN_NAMESPACE
+
+#if !(defined(QT_NO_DRAGANDDROP) && defined(QT_NO_CLIPBOARD))
+
+//---------------------------------------------------------------------
+// QOleDataObject Constructor
+//---------------------------------------------------------------------
+
+QOleDataObject::QOleDataObject(QMimeData *mimeData)
+{
+ m_refs = 1;
+ data = mimeData;
+ CF_PERFORMEDDROPEFFECT = RegisterClipboardFormat(CFSTR_PERFORMEDDROPEFFECT);
+ performedEffect = DROPEFFECT_NONE;
+}
+
+QOleDataObject::~QOleDataObject()
+{
+}
+
+void QOleDataObject::releaseQt()
+{
+ data = 0;
+}
+
+const QMimeData *QOleDataObject::mimeData() const
+{
+ return data;
+}
+
+DWORD QOleDataObject::reportedPerformedEffect() const
+{
+ return performedEffect;
+}
+
+//---------------------------------------------------------------------
+// IUnknown Methods
+//---------------------------------------------------------------------
+
+STDMETHODIMP
+QOleDataObject::QueryInterface(REFIID iid, void FAR* FAR* ppv)
+{
+ if (iid == IID_IUnknown || iid == IID_IDataObject) {
+ *ppv = this;
+ AddRef();
+ return NOERROR;
+ }
+ *ppv = NULL;
+ return ResultFromScode(E_NOINTERFACE);
+}
+
+STDMETHODIMP_(ULONG)
+QOleDataObject::AddRef(void)
+{
+ return ++m_refs;
+}
+
+STDMETHODIMP_(ULONG)
+QOleDataObject::Release(void)
+{
+ if (--m_refs == 0) {
+ releaseQt();
+ delete this;
+ return 0;
+ }
+ return m_refs;
+}
+
+//---------------------------------------------------------------------
+// IDataObject Methods
+//
+// The following methods are NOT supported for data transfer using the
+// clipboard or drag-drop:
+//
+// IDataObject::SetData -- return E_NOTIMPL
+// IDataObject::DAdvise -- return OLE_E_ADVISENOTSUPPORTED
+// ::DUnadvise
+// ::EnumDAdvise
+// IDataObject::GetCanonicalFormatEtc -- return E_NOTIMPL
+// (NOTE: must set pformatetcOut->ptd = NULL)
+//---------------------------------------------------------------------
+
+STDMETHODIMP
+QOleDataObject::GetData(LPFORMATETC pformatetc, LPSTGMEDIUM pmedium)
+{
+#ifdef QDND_DEBUG
+ qDebug("QOleDataObject::GetData(LPFORMATETC pformatetc, LPSTGMEDIUM pmedium)");
+#ifndef Q_OS_WINCE
+ wchar_t buf[256] = {0};
+ GetClipboardFormatName(pformatetc->cfFormat, buf, 255);
+ qDebug("CF = %d : %s", pformatetc->cfFormat, QString::fromWCharArray(buf));
+#endif
+#endif
+
+ if (!data)
+ return ResultFromScode(DATA_E_FORMATETC);
+
+ QWindowsMime *converter = QWindowsMime::converterFromMime(*pformatetc, data);
+
+ if (converter && converter->convertFromMime(*pformatetc, data, pmedium))
+ return ResultFromScode(S_OK);
+ else
+ return ResultFromScode(DATA_E_FORMATETC);
+}
+
+STDMETHODIMP
+QOleDataObject::GetDataHere(LPFORMATETC, LPSTGMEDIUM)
+{
+ return ResultFromScode(DATA_E_FORMATETC);
+}
+
+STDMETHODIMP
+QOleDataObject::QueryGetData(LPFORMATETC pformatetc)
+{
+#ifdef QDND_DEBUG
+ qDebug("QOleDataObject::QueryGetData(LPFORMATETC pformatetc)");
+#endif
+
+ if (!data)
+ return ResultFromScode(DATA_E_FORMATETC);
+
+ if (QWindowsMime::converterFromMime(*pformatetc, data))
+ return ResultFromScode(S_OK);
+ return ResultFromScode(S_FALSE);
+}
+
+STDMETHODIMP
+QOleDataObject::GetCanonicalFormatEtc(LPFORMATETC, LPFORMATETC pformatetcOut)
+{
+ pformatetcOut->ptd = NULL;
+ return ResultFromScode(E_NOTIMPL);
+}
+
+STDMETHODIMP
+QOleDataObject::SetData(LPFORMATETC pFormatetc, STGMEDIUM *pMedium, BOOL fRelease)
+{
+ if (pFormatetc->cfFormat == CF_PERFORMEDDROPEFFECT && pMedium->tymed == TYMED_HGLOBAL) {
+ DWORD * val = (DWORD*)GlobalLock(pMedium->hGlobal);
+ performedEffect = *val;
+ GlobalUnlock(pMedium->hGlobal);
+ if (fRelease)
+ ReleaseStgMedium(pMedium);
+ return ResultFromScode(S_OK);
+ }
+ return ResultFromScode(E_NOTIMPL);
+}
+
+
+STDMETHODIMP
+QOleDataObject::EnumFormatEtc(DWORD dwDirection, LPENUMFORMATETC FAR* ppenumFormatEtc)
+{
+#ifdef QDND_DEBUG
+ qDebug("QOleDataObject::EnumFormatEtc(DWORD dwDirection, LPENUMFORMATETC FAR* ppenumFormatEtc)");
+#endif
+
+ if (!data)
+ return ResultFromScode(DATA_E_FORMATETC);
+
+ SCODE sc = S_OK;
+
+ QVector<FORMATETC> fmtetcs;
+ if (dwDirection == DATADIR_GET) {
+ fmtetcs = QWindowsMime::allFormatsForMime(data);
+ } else {
+ FORMATETC formatetc;
+ formatetc.cfFormat = CF_PERFORMEDDROPEFFECT;
+ formatetc.dwAspect = DVASPECT_CONTENT;
+ formatetc.lindex = -1;
+ formatetc.ptd = NULL;
+ formatetc.tymed = TYMED_HGLOBAL;
+ fmtetcs.append(formatetc);
+ }
+
+ QOleEnumFmtEtc *enumFmtEtc = new QOleEnumFmtEtc(fmtetcs);
+ *ppenumFormatEtc = enumFmtEtc;
+ if (enumFmtEtc->isNull()) {
+ delete enumFmtEtc;
+ *ppenumFormatEtc = NULL;
+ sc = E_OUTOFMEMORY;
+ }
+
+ return ResultFromScode(sc);
+}
+
+STDMETHODIMP
+QOleDataObject::DAdvise(FORMATETC FAR*, DWORD,
+ LPADVISESINK, DWORD FAR*)
+{
+ return ResultFromScode(OLE_E_ADVISENOTSUPPORTED);
+}
+
+
+STDMETHODIMP
+QOleDataObject::DUnadvise(DWORD)
+{
+ return ResultFromScode(OLE_E_ADVISENOTSUPPORTED);
+}
+
+STDMETHODIMP
+QOleDataObject::EnumDAdvise(LPENUMSTATDATA FAR*)
+{
+ return ResultFromScode(OLE_E_ADVISENOTSUPPORTED);
+}
+
+#endif // QT_NO_DRAGANDDROP && QT_NO_CLIPBOARD
+
+#ifndef QT_NO_DRAGANDDROP
+
+//#define QDND_DEBUG
+
+#ifdef QDND_DEBUG
+extern QString dragActionsToString(Qt::DropActions actions);
+#endif
+
+Qt::DropActions translateToQDragDropActions(DWORD pdwEffects)
+{
+ Qt::DropActions actions = Qt::IgnoreAction;
+ if (pdwEffects & DROPEFFECT_LINK)
+ actions |= Qt::LinkAction;
+ if (pdwEffects & DROPEFFECT_COPY)
+ actions |= Qt::CopyAction;
+ if (pdwEffects & DROPEFFECT_MOVE)
+ actions |= Qt::MoveAction;
+ return actions;
+}
+
+Qt::DropAction translateToQDragDropAction(DWORD pdwEffect)
+{
+ if (pdwEffect & DROPEFFECT_LINK)
+ return Qt::LinkAction;
+ if (pdwEffect & DROPEFFECT_COPY)
+ return Qt::CopyAction;
+ if (pdwEffect & DROPEFFECT_MOVE)
+ return Qt::MoveAction;
+ return Qt::IgnoreAction;
+}
+
+DWORD translateToWinDragEffects(Qt::DropActions action)
+{
+ DWORD effect = DROPEFFECT_NONE;
+ if (action & Qt::LinkAction)
+ effect |= DROPEFFECT_LINK;
+ if (action & Qt::CopyAction)
+ effect |= DROPEFFECT_COPY;
+ if (action & Qt::MoveAction)
+ effect |= DROPEFFECT_MOVE;
+ return effect;
+}
+
+Qt::KeyboardModifiers toQtKeyboardModifiers(DWORD keyState)
+{
+ Qt::KeyboardModifiers modifiers = Qt::NoModifier;
+
+ if (keyState & MK_SHIFT)
+ modifiers |= Qt::ShiftModifier;
+ if (keyState & MK_CONTROL)
+ modifiers |= Qt::ControlModifier;
+ if (keyState & MK_ALT)
+ modifiers |= Qt::AltModifier;
+
+ return modifiers;
+}
+
+Qt::MouseButtons toQtMouseButtons(DWORD keyState)
+{
+ Qt::MouseButtons buttons = Qt::NoButton;
+
+ if (keyState & MK_LBUTTON)
+ buttons |= Qt::LeftButton;
+ if (keyState & MK_RBUTTON)
+ buttons |= Qt::RightButton;
+ if (keyState & MK_MBUTTON)
+ buttons |= Qt::MidButton;
+
+ return buttons;
+}
+
+class QOleDropSource : public IDropSource
+{
+public:
+ QOleDropSource();
+ virtual ~QOleDropSource();
+
+ void createCursors();
+
+ // IUnknown methods
+ STDMETHOD(QueryInterface)(REFIID riid, void ** ppvObj);
+ STDMETHOD_(ULONG,AddRef)(void);
+ STDMETHOD_(ULONG,Release)(void);
+
+ // IDropSource methods
+ STDMETHOD(QueryContinueDrag)(BOOL fEscapePressed, DWORD grfKeyState);
+ STDMETHOD(GiveFeedback)(DWORD dwEffect);
+
+private:
+ Qt::MouseButtons currentButtons;
+ Qt::DropAction currentAction;
+ QMap <Qt::DropAction, QCursor> cursors;
+
+ ULONG m_refs;
+};
+
+
+QOleDropSource::QOleDropSource()
+{
+ currentButtons = Qt::NoButton;
+ m_refs = 1;
+ currentAction = Qt::IgnoreAction;
+}
+
+QOleDropSource::~QOleDropSource()
+{
+}
+
+void QOleDropSource::createCursors()
+{
+ QDragManager *manager = QDragManager::self();
+ if (manager && manager->object
+ && (!manager->object->pixmap().isNull()
+ || manager->hasCustomDragCursors())) {
+ QPixmap pm = manager->object->pixmap();
+ QList<Qt::DropAction> actions;
+ actions << Qt::MoveAction << Qt::CopyAction << Qt::LinkAction;
+ if (!manager->object->pixmap().isNull())
+ actions << Qt::IgnoreAction;
+ QPoint hotSpot = manager->object->hotSpot();
+ for (int cnum = 0; cnum < actions.size(); ++cnum) {
+ QPixmap cpm = manager->dragCursor(actions.at(cnum));
+ int w = cpm.width();
+ int h = cpm.height();
+
+ if (!pm.isNull()) {
+ int x1 = qMin(-hotSpot.x(), 0);
+ int x2 = qMax(pm.width() - hotSpot.x(), cpm.width());
+ int y1 = qMin(-hotSpot.y(), 0);
+ int y2 = qMax(pm.height() - hotSpot.y(), cpm.height());
+
+ w = x2 - x1 + 1;
+ h = y2 - y1 + 1;
+ }
+
+ QRect srcRect = pm.rect();
+ QPoint pmDest = QPoint(qMax(0, -hotSpot.x()), qMax(0, -hotSpot.y()));
+ QPoint newHotSpot = hotSpot;
+
+#if defined(Q_OS_WINCE)
+ // Limited cursor size
+ int reqw = GetSystemMetrics(SM_CXCURSOR);
+ int reqh = GetSystemMetrics(SM_CYCURSOR);
+
+ QPoint hotspotInPM = newHotSpot - pmDest;
+ if (reqw < w) {
+ // Not wide enough - move objectpm right
+ qreal r = qreal(newHotSpot.x()) / w;
+ newHotSpot = QPoint(int(r * reqw), newHotSpot.y());
+ if (newHotSpot.x() + cpm.width() > reqw)
+ newHotSpot.setX(reqw - cpm.width());
+
+ srcRect = QRect(QPoint(hotspotInPM.x() - newHotSpot.x(), srcRect.top()), QSize(reqw, srcRect.height()));
+ }
+ if (reqh < h) {
+ qreal r = qreal(newHotSpot.y()) / h;
+ newHotSpot = QPoint(newHotSpot.x(), int(r * reqh));
+ if (newHotSpot.y() + cpm.height() > reqh)
+ newHotSpot.setY(reqh - cpm.height());
+
+ srcRect = QRect(QPoint(srcRect.left(), hotspotInPM.y() - newHotSpot.y()), QSize(srcRect.width(), reqh));
+ }
+ // Always use system cursor size
+ w = reqw;
+ h = reqh;
+#endif
+
+ QPixmap newCursor(w, h);
+ if (!pm.isNull()) {
+ newCursor.fill(QColor(0, 0, 0, 0));
+ QPainter p(&newCursor);
+ p.drawPixmap(pmDest, pm, srcRect);
+ p.drawPixmap(qMax(0,newHotSpot.x()),qMax(0,newHotSpot.y()),cpm);
+ } else {
+ newCursor = cpm;
+ }
+
+#ifndef QT_NO_CURSOR
+ cursors[actions.at(cnum)] = QCursor(newCursor, pm.isNull() ? 0 : qMax(0,newHotSpot.x()),
+ pm.isNull() ? 0 : qMax(0,newHotSpot.y()));
+#endif
+ }
+ }
+}
+
+
+
+//---------------------------------------------------------------------
+// IUnknown Methods
+//---------------------------------------------------------------------
+
+
+STDMETHODIMP
+QOleDropSource::QueryInterface(REFIID iid, void FAR* FAR* ppv)
+{
+ if(iid == IID_IUnknown || iid == IID_IDropSource)
+ {
+ *ppv = this;
+ ++m_refs;
+ return NOERROR;
+ }
+ *ppv = NULL;
+ return ResultFromScode(E_NOINTERFACE);
+}
+
+
+STDMETHODIMP_(ULONG)
+QOleDropSource::AddRef(void)
+{
+ return ++m_refs;
+}
+
+
+STDMETHODIMP_(ULONG)
+QOleDropSource::Release(void)
+{
+ if(--m_refs == 0)
+ {
+ delete this;
+ return 0;
+ }
+ return m_refs;
+}
+
+static inline Qt::MouseButtons keystate_to_mousebutton(DWORD grfKeyState)
+{
+ Qt::MouseButtons result;
+ if (grfKeyState & MK_LBUTTON)
+ result |= Qt::LeftButton;
+ if (grfKeyState & MK_MBUTTON)
+ result |= Qt::MidButton;
+ if (grfKeyState & MK_RBUTTON)
+ result |= Qt::RightButton;
+ if (grfKeyState & MK_XBUTTON1)
+ result |= Qt::XButton1;
+ if (grfKeyState & MK_XBUTTON2)
+ result |= Qt::XButton2;
+ return result;
+}
+
+//---------------------------------------------------------------------
+// IDropSource Methods
+//---------------------------------------------------------------------
+QT_ENSURE_STACK_ALIGNED_FOR_SSE STDMETHODIMP
+QOleDropSource::QueryContinueDrag(BOOL fEscapePressed, DWORD grfKeyState)
+{
+#ifdef QDND_DEBUG
+ qDebug("QOleDropSource::QueryContinueDrag(fEscapePressed %d, grfKeyState %d)", fEscapePressed, grfKeyState);
+#endif
+
+ if (fEscapePressed) {
+ return ResultFromScode(DRAGDROP_S_CANCEL);
+ } else if ((GetAsyncKeyState(VK_LBUTTON) == 0)
+ && (GetAsyncKeyState(VK_MBUTTON) == 0)
+ && (GetAsyncKeyState(VK_RBUTTON) == 0)) {
+ // grfKeyState is broken on CE & some Windows XP versions,
+ // therefore we need to check the state manually
+ return ResultFromScode(DRAGDROP_S_DROP);
+ } else {
+#if !defined(Q_OS_WINCE)
+ if (currentButtons == Qt::NoButton) {
+ currentButtons = keystate_to_mousebutton(grfKeyState);
+ } else {
+ Qt::MouseButtons buttons = keystate_to_mousebutton(grfKeyState);
+ if (!(currentButtons & buttons))
+ return ResultFromScode(DRAGDROP_S_DROP);
+ }
+#endif
+ QApplication::processEvents();
+ return NOERROR;
+ }
+}
+
+QT_ENSURE_STACK_ALIGNED_FOR_SSE STDMETHODIMP
+QOleDropSource::GiveFeedback(DWORD dwEffect)
+{
+ Qt::DropAction action = translateToQDragDropAction(dwEffect);
+
+#ifdef QDND_DEBUG
+ qDebug("QOleDropSource::GiveFeedback(DWORD dwEffect)");
+ qDebug("dwEffect = %s", dragActionsToString(action).toLatin1().data());
+#endif
+
+ if (currentAction != action) {
+ currentAction = action;
+ QDragManager::self()->emitActionChanged(currentAction);
+ }
+
+ if (cursors.contains(currentAction)) {
+#ifndef QT_NO_CURSOR
+ SetCursor(cursors[currentAction].handle());
+#endif
+ return ResultFromScode(S_OK);
+ }
+
+ return ResultFromScode(DRAGDROP_S_USEDEFAULTCURSORS);
+}
+
+//---------------------------------------------------------------------
+// QOleDropTarget
+//---------------------------------------------------------------------
+
+QOleDropTarget::QOleDropTarget(QWidget* w)
+: widget(w)
+{
+ m_refs = 1;
+}
+
+void QOleDropTarget::releaseQt()
+{
+ widget = 0;
+}
+
+//---------------------------------------------------------------------
+// IUnknown Methods
+//---------------------------------------------------------------------
+
+
+STDMETHODIMP
+QOleDropTarget::QueryInterface(REFIID iid, void FAR* FAR* ppv)
+{
+ if(iid == IID_IUnknown || iid == IID_IDropTarget)
+ {
+ *ppv = this;
+ AddRef();
+ return NOERROR;
+ }
+ *ppv = NULL;
+ return ResultFromScode(E_NOINTERFACE);
+}
+
+
+STDMETHODIMP_(ULONG)
+QOleDropTarget::AddRef(void)
+{
+ return ++m_refs;
+}
+
+
+STDMETHODIMP_(ULONG)
+QOleDropTarget::Release(void)
+{
+ if(--m_refs == 0)
+ {
+ delete this;
+ return 0;
+ }
+ return m_refs;
+}
+
+//---------------------------------------------------------------------
+// IDropTarget Methods
+//---------------------------------------------------------------------
+
+QT_ENSURE_STACK_ALIGNED_FOR_SSE STDMETHODIMP
+QOleDropTarget::DragEnter(LPDATAOBJECT pDataObj, DWORD grfKeyState, POINTL pt, LPDWORD pdwEffect)
+{
+#ifdef QDND_DEBUG
+ qDebug("QOleDropTarget::DragEnter(LPDATAOBJECT pDataObj, DWORD grfKeyState, POINTL pt, LPDWORD pdwEffect)");
+#endif
+
+ if (!QApplicationPrivate::tryModalHelper(widget)) {
+ *pdwEffect = DROPEFFECT_NONE;
+ return NOERROR;
+ }
+
+ QDragManager *manager = QDragManager::self();
+ manager->dropData->currentDataObject = pDataObj;
+ manager->dropData->currentDataObject->AddRef();
+ sendDragEnterEvent(widget, grfKeyState, pt, pdwEffect);
+ *pdwEffect = chosenEffect;
+
+ return NOERROR;
+}
+
+void QOleDropTarget::sendDragEnterEvent(QWidget *dragEnterWidget, DWORD grfKeyState,
+ POINTL pt, LPDWORD pdwEffect)
+{
+ Q_ASSERT(dragEnterWidget);
+ lastPoint = dragEnterWidget->mapFromGlobal(QPoint(pt.x,pt.y));
+ lastKeyState = grfKeyState;
+
+ chosenEffect = DROPEFFECT_NONE;
+ currentWidget = dragEnterWidget;
+
+ QDragManager *manager = QDragManager::self();
+ QMimeData * md = manager->source() ? manager->dragPrivate()->data : manager->dropData;
+ QDragEnterEvent enterEvent(lastPoint, translateToQDragDropActions(*pdwEffect), md,
+ toQtMouseButtons(grfKeyState), toQtKeyboardModifiers(grfKeyState));
+ QApplication::sendEvent(dragEnterWidget, &enterEvent);
+ answerRect = enterEvent.answerRect();
+
+ if (enterEvent.isAccepted()) {
+ chosenEffect = translateToWinDragEffects(enterEvent.dropAction());
+ }
+
+ // Documentation states that a drag move event is sendt immidiatly after
+ // a drag enter event. This will honor widgets overriding dragMoveEvent only:
+ if (enterEvent.isAccepted()) {
+ QDragMoveEvent moveEvent(lastPoint, translateToQDragDropActions(*pdwEffect), md,
+ toQtMouseButtons(grfKeyState), toQtKeyboardModifiers(grfKeyState));
+ answerRect = enterEvent.answerRect();
+ moveEvent.setDropAction(enterEvent.dropAction());
+ moveEvent.accept(); // accept by default, since enter event was accepted.
+
+ QApplication::sendEvent(dragEnterWidget, &moveEvent);
+ if (moveEvent.isAccepted()) {
+ answerRect = moveEvent.answerRect();
+ chosenEffect = translateToWinDragEffects(moveEvent.dropAction());
+ } else {
+ chosenEffect = DROPEFFECT_NONE;
+ }
+ }
+
+}
+
+QT_ENSURE_STACK_ALIGNED_FOR_SSE STDMETHODIMP
+QOleDropTarget::DragOver(DWORD grfKeyState, POINTL pt, LPDWORD pdwEffect)
+{
+#ifdef QDND_DEBUG
+ qDebug("QOleDropTarget::DragOver(grfKeyState %d, pt (%d,%d), pdwEffect %d)", grfKeyState, pt.x, pt.y, pdwEffect);
+#endif
+
+ QWidget *dragOverWidget = widget->childAt(widget->mapFromGlobal(QPoint(pt.x, pt.y)));
+ if (!dragOverWidget)
+ dragOverWidget = widget;
+
+
+ if (!QApplicationPrivate::tryModalHelper(dragOverWidget)
+ || !dragOverWidget->testAttribute(Qt::WA_DropSiteRegistered)) {
+ *pdwEffect = DROPEFFECT_NONE;
+ return NOERROR;
+ }
+
+ QPoint tmpPoint = dragOverWidget->mapFromGlobal(QPoint(pt.x, pt.y));
+ // see if we should compress this event
+ if ((tmpPoint == lastPoint || answerRect.contains(tmpPoint)) && lastKeyState == grfKeyState) {
+ *pdwEffect = chosenEffect;
+ return NOERROR;
+ }
+
+ if (!dragOverWidget->internalWinId() && dragOverWidget != currentWidget) {
+ QPointer<QWidget> dragOverWidgetGuard(dragOverWidget);
+ // Send drag leave event to the previous drag widget.
+ QDragLeaveEvent dragLeave;
+ if (currentWidget)
+ QApplication::sendEvent(currentWidget, &dragLeave);
+ if (!dragOverWidgetGuard) {
+ dragOverWidget = widget->childAt(widget->mapFromGlobal(QPoint(pt.x, pt.y)));
+ if (!dragOverWidget)
+ dragOverWidget = widget;
+ }
+ // Send drag enter event to the current drag widget.
+ sendDragEnterEvent(dragOverWidget, grfKeyState, pt, pdwEffect);
+ }
+
+ QDragManager *manager = QDragManager::self();
+ QMimeData *md = manager->source() ? manager->dragPrivate()->data : manager->dropData;
+
+ QDragMoveEvent oldEvent(lastPoint, translateToQDragDropActions(*pdwEffect), md,
+ toQtMouseButtons(lastKeyState), toQtKeyboardModifiers(lastKeyState));
+
+
+ lastPoint = tmpPoint;
+ lastKeyState = grfKeyState;
+
+ QDragMoveEvent e(lastPoint, translateToQDragDropActions(*pdwEffect), md,
+ toQtMouseButtons(grfKeyState), toQtKeyboardModifiers(grfKeyState));
+ if (chosenEffect != DROPEFFECT_NONE) {
+ if (oldEvent.dropAction() == e.dropAction() &&
+ oldEvent.keyboardModifiers() == e.keyboardModifiers())
+ e.setDropAction(translateToQDragDropAction(chosenEffect));
+ e.accept();
+ }
+ QApplication::sendEvent(dragOverWidget, &e);
+
+ answerRect = e.answerRect();
+ if (e.isAccepted())
+ chosenEffect = translateToWinDragEffects(e.dropAction());
+ else
+ chosenEffect = DROPEFFECT_NONE;
+ *pdwEffect = chosenEffect;
+
+ return NOERROR;
+}
+
+QT_ENSURE_STACK_ALIGNED_FOR_SSE STDMETHODIMP
+QOleDropTarget::DragLeave()
+{
+#ifdef QDND_DEBUG
+ qDebug("QOleDropTarget::DragLeave()");
+#endif
+
+ if (!QApplicationPrivate::tryModalHelper(widget)) {
+ return NOERROR;
+ }
+
+ currentWidget = 0;
+ QDragLeaveEvent e;
+ QApplication::sendEvent(widget, &e);
+
+ QDragManager *manager = QDragManager::self();
+
+ if (manager->dropData->currentDataObject) { // Sanity
+ manager->dropData->currentDataObject->Release();
+ manager->dropData->currentDataObject = 0;
+ }
+
+ return NOERROR;
+}
+
+#define KEY_STATE_BUTTON_MASK (MK_LBUTTON | MK_MBUTTON | MK_RBUTTON)
+
+QT_ENSURE_STACK_ALIGNED_FOR_SSE STDMETHODIMP
+QOleDropTarget::Drop(LPDATAOBJECT /*pDataObj*/, DWORD grfKeyState, POINTL pt, LPDWORD pdwEffect)
+{
+#ifdef QDND_DEBUG
+ qDebug("QOleDropTarget::Drop(LPDATAOBJECT /*pDataObj*/, grfKeyState %d, POINTL pt, LPDWORD pdwEffect)", grfKeyState);
+#endif
+
+ QWidget *dropWidget = widget->childAt(widget->mapFromGlobal(QPoint(pt.x, pt.y)));
+ if (!dropWidget)
+ dropWidget = widget;
+
+ if (!QApplicationPrivate::tryModalHelper(dropWidget)
+ || !dropWidget->testAttribute(Qt::WA_DropSiteRegistered)) {
+ *pdwEffect = DROPEFFECT_NONE;
+ return NOERROR;
+ }
+
+ lastPoint = dropWidget->mapFromGlobal(QPoint(pt.x,pt.y));
+ // grfKeyState does not all ways contain button state in the drop so if
+ // it doesn't then use the last known button state;
+ if ((grfKeyState & KEY_STATE_BUTTON_MASK) == 0)
+ grfKeyState |= lastKeyState & KEY_STATE_BUTTON_MASK;
+ lastKeyState = grfKeyState;
+
+ QDragManager *manager = QDragManager::self();
+ QMimeData *md = manager->source() ? manager->dragPrivate()->data : manager->dropData;
+ QDropEvent e(lastPoint, translateToQDragDropActions(*pdwEffect), md,
+ toQtMouseButtons(grfKeyState), toQtKeyboardModifiers(grfKeyState));
+ if (chosenEffect != DROPEFFECT_NONE) {
+ e.setDropAction(translateToQDragDropAction(chosenEffect));
+ }
+ QApplication::sendEvent(dropWidget, &e);
+
+ if (chosenEffect != DROPEFFECT_NONE) {
+ e.accept();
+ }
+
+
+ if (e.isAccepted()) {
+ if (e.dropAction() == Qt::MoveAction || e.dropAction() == Qt::TargetMoveAction) {
+ if (e.dropAction() == Qt::MoveAction)
+ chosenEffect = DROPEFFECT_MOVE;
+ else
+ chosenEffect = DROPEFFECT_COPY;
+ HGLOBAL hData = GlobalAlloc(0, sizeof(DWORD));
+ if (hData) {
+ DWORD *moveEffect = (DWORD *)GlobalLock(hData);;
+ *moveEffect = DROPEFFECT_MOVE;
+ GlobalUnlock(hData);
+ STGMEDIUM medium;
+ memset(&medium, 0, sizeof(STGMEDIUM));
+ medium.tymed = TYMED_HGLOBAL;
+ medium.hGlobal = hData;
+ FORMATETC format;
+ format.cfFormat = RegisterClipboardFormat(CFSTR_PERFORMEDDROPEFFECT);
+ format.tymed = TYMED_HGLOBAL;
+ format.ptd = 0;
+ format.dwAspect = 1;
+ format.lindex = -1;
+ manager->dropData->currentDataObject->SetData(&format, &medium, true);
+ }
+ } else {
+ chosenEffect = translateToWinDragEffects(e.dropAction());
+ }
+ } else {
+ chosenEffect = DROPEFFECT_NONE;
+ }
+ *pdwEffect = chosenEffect;
+
+
+ if (manager->dropData->currentDataObject) {
+ manager->dropData->currentDataObject->Release();
+ manager->dropData->currentDataObject = 0;
+ }
+
+ return NOERROR;
+
+ // We won't get any mouserelease-event, so manually adjust qApp state:
+///### test this QApplication::winMouseButtonUp();
+}
+
+//---------------------------------------------------------------------
+// QDropData
+//---------------------------------------------------------------------
+
+bool QDropData::hasFormat_sys(const QString &mimeType) const
+{
+ if (!currentDataObject) // Sanity
+ return false;
+
+ return QWindowsMime::converterToMime(mimeType, currentDataObject) != 0;
+}
+
+QStringList QDropData::formats_sys() const
+{
+ QStringList fmts;
+ if (!currentDataObject) // Sanity
+ return fmts;
+
+ fmts = QWindowsMime::allMimesForFormats(currentDataObject);
+
+ return fmts;
+}
+
+QVariant QDropData::retrieveData_sys(const QString &mimeType, QVariant::Type type) const
+{
+ QVariant result;
+
+ if (!currentDataObject) // Sanity
+ return result;
+
+ QWindowsMime *converter = QWindowsMime::converterToMime(mimeType, currentDataObject);
+
+ if (converter)
+ result = converter->convertToMime(mimeType, currentDataObject, type);
+
+ return result;
+}
+
+Qt::DropAction QDragManager::drag(QDrag *o)
+
+{
+#ifdef QDND_DEBUG
+ qDebug("QDragManager::drag(QDrag *drag)");
+#endif
+
+ if (object == o || !o || !o->d_func()->source)
+ return Qt::IgnoreAction;
+
+ if (object) {
+ cancel();
+ qApp->removeEventFilter(this);
+ beingCancelled = false;
+ }
+
+ object = o;
+
+#ifdef QDND_DEBUG
+ qDebug("actions = %s", dragActionsToString(dragPrivate()->possible_actions).toLatin1().data());
+#endif
+
+ dragPrivate()->target = 0;
+
+#ifndef QT_NO_ACCESSIBILITY
+ QAccessible::updateAccessibility(this, 0, QAccessible::DragDropStart);
+#endif
+
+ DWORD resultEffect;
+ QOleDropSource *src = new QOleDropSource();
+ src->createCursors();
+ QOleDataObject *obj = new QOleDataObject(o->mimeData());
+ DWORD allowedEffects = translateToWinDragEffects(dragPrivate()->possible_actions);
+
+#if !defined(Q_OS_WINCE) || defined(GWES_ICONCURS)
+ HRESULT r = DoDragDrop(obj, src, allowedEffects, &resultEffect);
+#else
+ HRESULT r = DRAGDROP_S_CANCEL;
+ resultEffect = DROPEFFECT_MOVE;
+#endif
+
+ Qt::DropAction ret = Qt::IgnoreAction;
+ if (r == DRAGDROP_S_DROP) {
+ if (obj->reportedPerformedEffect() == DROPEFFECT_MOVE && resultEffect != DROPEFFECT_MOVE) {
+ ret = Qt::TargetMoveAction;
+ resultEffect = DROPEFFECT_MOVE;
+ } else {
+ ret = translateToQDragDropAction(resultEffect);
+ }
+ // Force it to be a copy if an unsupported operation occurred.
+ // This indicates a bug in the drop target.
+ if (resultEffect != DROPEFFECT_NONE && !(resultEffect & allowedEffects))
+ ret = Qt::CopyAction;
+ } else {
+ dragPrivate()->target = 0;
+ }
+
+ // clean up
+ obj->releaseQt();
+ obj->Release(); // Will delete obj if refcount becomes 0
+ src->Release(); // Will delete src if refcount becomes 0
+ object = 0;
+ o->setMimeData(0);
+ o->deleteLater();
+
+#ifndef QT_NO_ACCESSIBILITY
+ QAccessible::updateAccessibility(this, 0, QAccessible::DragDropEnd);
+#endif
+
+ return ret;
+}
+
+void QDragManager::cancel(bool /* deleteSource */)
+{
+ if (object) {
+ beingCancelled = true;
+ object = 0;
+ }
+
+#ifndef QT_NO_CURSOR
+ // insert cancel code here ######## todo
+
+ if (restoreCursor) {
+ QApplication::restoreOverrideCursor();
+ restoreCursor = false;
+ }
+#endif
+#ifndef QT_NO_ACCESSIBILITY
+ QAccessible::updateAccessibility(this, 0, QAccessible::DragDropEnd);
+#endif
+}
+
+void QDragManager::updatePixmap()
+{
+ // not used in windows implementation
+}
+
+bool QDragManager::eventFilter(QObject *, QEvent *)
+{
+ // not used in windows implementation
+ return false;
+}
+
+void QDragManager::timerEvent(QTimerEvent*)
+{
+ // not used in windows implementation
+}
+
+void QDragManager::move(const QPoint &)
+{
+ // not used in windows implementation
+}
+
+void QDragManager::drop()
+{
+ // not used in windows implementation
+}
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_DRAGANDDROP
diff --git a/src/gui/platforms/win/qfont_win.cpp b/src/gui/platforms/win/qfont_win.cpp
new file mode 100644
index 0000000000..3ef761bfa5
--- /dev/null
+++ b/src/gui/platforms/win/qfont_win.cpp
@@ -0,0 +1,166 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qfont.h"
+#include "qfont_p.h"
+#include "qfontengine_p.h"
+#include "qtextengine_p.h"
+#include "qfontmetrics.h"
+#include "qfontinfo.h"
+
+#include "qwidget.h"
+#include "qpainter.h"
+#include <limits.h>
+#include "qt_windows.h"
+#include <private/qapplication_p.h>
+#include "qapplication.h"
+#include <private/qunicodetables_p.h>
+#include <qfontdatabase.h>
+
+QT_BEGIN_NAMESPACE
+
+extern HDC shared_dc(); // common dc for all fonts
+extern QFont::Weight weightFromInteger(int weight); // qfontdatabase.cpp
+
+// ### maybe move to qapplication_win
+QFont qt_LOGFONTtoQFont(LOGFONT& lf, bool /*scale*/)
+{
+ QString family = QString::fromWCharArray(lf.lfFaceName);
+ QFont qf(family);
+ qf.setItalic(lf.lfItalic);
+ if (lf.lfWeight != FW_DONTCARE)
+ qf.setWeight(weightFromInteger(lf.lfWeight));
+ int lfh = qAbs(lf.lfHeight);
+ qf.setPointSizeF(lfh * 72.0 / GetDeviceCaps(shared_dc(),LOGPIXELSY));
+ qf.setUnderline(false);
+ qf.setOverline(false);
+ qf.setStrikeOut(false);
+ return qf;
+}
+
+
+static inline float pixelSize(const QFontDef &request, int dpi)
+{
+ float pSize;
+ if (request.pointSize != -1)
+ pSize = request.pointSize * dpi/ 72.;
+ else
+ pSize = request.pixelSize;
+ return pSize;
+}
+
+static inline float pointSize(const QFontDef &fd, int dpi)
+{
+ float pSize;
+ if (fd.pointSize < 0)
+ pSize = fd.pixelSize * 72. / ((float)dpi);
+ else
+ pSize = fd.pointSize;
+ return pSize;
+}
+
+/*****************************************************************************
+ QFont member functions
+ *****************************************************************************/
+
+void QFont::initialize()
+{
+}
+
+void QFont::cleanup()
+{
+ QFontCache::cleanup();
+}
+
+HFONT QFont::handle() const
+{
+ QFontEngine *engine = d->engineForScript(QUnicodeTables::Common);
+ Q_ASSERT(engine != 0);
+ if (engine->type() == QFontEngine::Multi)
+ engine = static_cast<QFontEngineMulti *>(engine)->engine(0);
+ if (engine->type() == QFontEngine::Win)
+ return static_cast<QFontEngineWin *>(engine)->hfont;
+ return 0;
+}
+
+QString QFont::rawName() const
+{
+ return family();
+}
+
+void QFont::setRawName(const QString &name)
+{
+ setFamily(name);
+}
+
+QString QFont::defaultFamily() const
+{
+ switch(d->request.styleHint) {
+ case QFont::Times:
+ return QString::fromLatin1("Times New Roman");
+ case QFont::Courier:
+ case QFont::Monospace:
+ return QString::fromLatin1("Courier New");
+ case QFont::Decorative:
+ return QString::fromLatin1("Bookman Old Style");
+ case QFont::Cursive:
+ return QString::fromLatin1("Comic Sans MS");
+ case QFont::Fantasy:
+ return QString::fromLatin1("Impact");
+ case QFont::Helvetica:
+ return QString::fromLatin1("Arial");
+ case QFont::System:
+ default:
+ return QString::fromLatin1("MS Sans Serif");
+ }
+}
+
+QString QFont::lastResortFamily() const
+{
+ return QString::fromLatin1("helvetica");
+}
+
+QString QFont::lastResortFont() const
+{
+ return QString::fromLatin1("arial");
+}
+
+QT_END_NAMESPACE
diff --git a/src/gui/platforms/win/qfontdatabase_win.cpp b/src/gui/platforms/win/qfontdatabase_win.cpp
new file mode 100644
index 0000000000..05b7509bf6
--- /dev/null
+++ b/src/gui/platforms/win/qfontdatabase_win.cpp
@@ -0,0 +1,1348 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qt_windows.h"
+#include <qmath.h>
+#include <private/qapplication_p.h>
+#include "qfont_p.h"
+#include "qfontengine_p.h"
+#include "qpaintdevice.h"
+#include <private/qsystemlibrary_p.h>
+#include "qabstractfileengine.h"
+#include "qendian.h"
+
+#if !defined(QT_NO_DIRECTWRITE)
+# include "qsettings.h"
+# include "qfontenginedirectwrite_p.h"
+#endif
+
+#ifdef Q_OS_WINCE
+# include <QTemporaryFile>
+#endif
+
+QT_BEGIN_NAMESPACE
+
+extern HDC shared_dc(); // common dc for all fonts
+
+#ifdef MAKE_TAG
+#undef MAKE_TAG
+#endif
+// GetFontData expects the tags in little endian ;(
+#define MAKE_TAG(ch1, ch2, ch3, ch4) (\
+ (((quint32)(ch4)) << 24) | \
+ (((quint32)(ch3)) << 16) | \
+ (((quint32)(ch2)) << 8) | \
+ ((quint32)(ch1)) \
+ )
+
+static HFONT stock_sysfont = 0;
+
+static bool localizedName(const QString &name)
+{
+ const QChar *c = name.unicode();
+ for(int i = 0; i < name.length(); ++i) {
+ if(c[i].unicode() >= 0x100)
+ return true;
+ }
+ return false;
+}
+
+static inline quint16 getUShort(const unsigned char *p)
+{
+ quint16 val;
+ val = *p++ << 8;
+ val |= *p;
+
+ return val;
+}
+
+static QString getEnglishName(const uchar *table, quint32 bytes)
+{
+ QString i18n_name;
+ enum {
+ NameRecordSize = 12,
+ FamilyId = 1,
+ MS_LangIdEnglish = 0x009
+ };
+
+ // get the name table
+ quint16 count;
+ quint16 string_offset;
+ const unsigned char *names;
+
+ int microsoft_id = -1;
+ int apple_id = -1;
+ int unicode_id = -1;
+
+ if(getUShort(table) != 0)
+ goto error;
+
+ count = getUShort(table+2);
+ string_offset = getUShort(table+4);
+ names = table + 6;
+
+ if(string_offset >= bytes || 6 + count*NameRecordSize > string_offset)
+ goto error;
+
+ for(int i = 0; i < count; ++i) {
+ // search for the correct name entry
+
+ quint16 platform_id = getUShort(names + i*NameRecordSize);
+ quint16 encoding_id = getUShort(names + 2 + i*NameRecordSize);
+ quint16 language_id = getUShort(names + 4 + i*NameRecordSize);
+ quint16 name_id = getUShort(names + 6 + i*NameRecordSize);
+
+ if(name_id != FamilyId)
+ continue;
+
+ enum {
+ PlatformId_Unicode = 0,
+ PlatformId_Apple = 1,
+ PlatformId_Microsoft = 3
+ };
+
+ quint16 length = getUShort(names + 8 + i*NameRecordSize);
+ quint16 offset = getUShort(names + 10 + i*NameRecordSize);
+ if(DWORD(string_offset + offset + length) >= bytes)
+ continue;
+
+ if ((platform_id == PlatformId_Microsoft
+ && (encoding_id == 0 || encoding_id == 1))
+ && (language_id & 0x3ff) == MS_LangIdEnglish
+ && microsoft_id == -1)
+ microsoft_id = i;
+ // not sure if encoding id 4 for Unicode is utf16 or ucs4...
+ else if(platform_id == PlatformId_Unicode && encoding_id < 4 && unicode_id == -1)
+ unicode_id = i;
+ else if(platform_id == PlatformId_Apple && encoding_id == 0 && language_id == 0)
+ apple_id = i;
+ }
+ {
+ bool unicode = false;
+ int id = -1;
+ if(microsoft_id != -1) {
+ id = microsoft_id;
+ unicode = true;
+ } else if(apple_id != -1) {
+ id = apple_id;
+ unicode = false;
+ } else if (unicode_id != -1) {
+ id = unicode_id;
+ unicode = true;
+ }
+ if(id != -1) {
+ quint16 length = getUShort(names + 8 + id*NameRecordSize);
+ quint16 offset = getUShort(names + 10 + id*NameRecordSize);
+ if(unicode) {
+ // utf16
+
+ length /= 2;
+ i18n_name.resize(length);
+ QChar *uc = (QChar *) i18n_name.unicode();
+ const unsigned char *string = table + string_offset + offset;
+ for(int i = 0; i < length; ++i)
+ uc[i] = getUShort(string + 2*i);
+ } else {
+ // Apple Roman
+
+ i18n_name.resize(length);
+ QChar *uc = (QChar *) i18n_name.unicode();
+ const unsigned char *string = table + string_offset + offset;
+ for(int i = 0; i < length; ++i)
+ uc[i] = QLatin1Char(string[i]);
+ }
+ }
+ }
+ error:
+ //qDebug("got i18n name of '%s' for font '%s'", i18n_name.latin1(), familyName.toLocal8Bit().data());
+ return i18n_name;
+}
+
+static QString getEnglishName(const QString &familyName)
+{
+ QString i18n_name;
+
+ HDC hdc = GetDC( 0 );
+ LOGFONT lf;
+ memset(&lf, 0, sizeof(LOGFONT));
+ memcpy(lf.lfFaceName, familyName.utf16(), qMin(LF_FACESIZE, familyName.length()) * sizeof(wchar_t));
+ lf.lfCharSet = DEFAULT_CHARSET;
+ HFONT hfont = CreateFontIndirect(&lf);
+
+ if(!hfont) {
+ ReleaseDC(0, hdc);
+ return QString();
+ }
+
+ HGDIOBJ oldobj = SelectObject( hdc, hfont );
+
+ const DWORD name_tag = MAKE_TAG( 'n', 'a', 'm', 'e' );
+
+ // get the name table
+ unsigned char *table = 0;
+
+ DWORD bytes = GetFontData( hdc, name_tag, 0, 0, 0 );
+ if ( bytes == GDI_ERROR ) {
+ // ### Unused variable
+ /* int err = GetLastError(); */
+ goto error;
+ }
+
+ table = new unsigned char[bytes];
+ GetFontData(hdc, name_tag, 0, table, bytes);
+ if ( bytes == GDI_ERROR )
+ goto error;
+
+ i18n_name = getEnglishName(table, bytes);
+error:
+ delete [] table;
+ SelectObject( hdc, oldobj );
+ DeleteObject( hfont );
+ ReleaseDC( 0, hdc );
+
+ //qDebug("got i18n name of '%s' for font '%s'", i18n_name.latin1(), familyName.toLocal8Bit().data());
+ return i18n_name;
+}
+
+extern QFont::Weight weightFromInteger(int weight); // qfontdatabase.cpp
+
+static
+void addFontToDatabase(QString familyName, const QString &scriptName,
+ TEXTMETRIC *textmetric,
+ const FONTSIGNATURE *signature,
+ int type)
+{
+ const int script = -1;
+ const QString foundryName;
+ Q_UNUSED(script);
+
+ bool italic = false;
+ int weight;
+ bool fixed;
+ bool ttf;
+ bool scalable;
+ int size;
+
+// QString escript = QString::fromWCharArray(f->elfScript);
+// qDebug("script=%s", escript.latin1());
+
+ NEWTEXTMETRIC *tm = (NEWTEXTMETRIC *)textmetric;
+ fixed = !(tm->tmPitchAndFamily & TMPF_FIXED_PITCH);
+ ttf = (tm->tmPitchAndFamily & TMPF_TRUETYPE);
+ scalable = tm->tmPitchAndFamily & (TMPF_VECTOR|TMPF_TRUETYPE);
+ size = scalable ? SMOOTH_SCALABLE : tm->tmHeight;
+ italic = tm->tmItalic;
+ weight = tm->tmWeight;
+
+ // the "@family" fonts are just the same as "family". Ignore them.
+ if (familyName[0] != QLatin1Char('@') && !familyName.startsWith(QLatin1String("WST_"))) {
+ QtFontStyle::Key styleKey;
+ styleKey.style = italic ? QFont::StyleItalic : QFont::StyleNormal;
+ styleKey.weight = weightFromInteger(weight);
+
+ QtFontFamily *family = privateDb()->family(familyName, true);
+
+ if(ttf && localizedName(familyName) && family->english_name.isEmpty())
+ family->english_name = getEnglishName(familyName);
+
+ QtFontFoundry *foundry = family->foundry(foundryName, true);
+ QtFontStyle *style = foundry->style(styleKey, true);
+ style->smoothScalable = scalable;
+ style->pixelSize( size, TRUE);
+
+ // add fonts windows can generate for us:
+ if (styleKey.weight <= QFont::DemiBold) {
+ QtFontStyle::Key key(styleKey);
+ key.weight = QFont::Bold;
+ QtFontStyle *style = foundry->style(key, true);
+ style->smoothScalable = scalable;
+ style->pixelSize( size, TRUE);
+ }
+ if (styleKey.style != QFont::StyleItalic) {
+ QtFontStyle::Key key(styleKey);
+ key.style = QFont::StyleItalic;
+ QtFontStyle *style = foundry->style(key, true);
+ style->smoothScalable = scalable;
+ style->pixelSize( size, TRUE);
+ }
+ if (styleKey.weight <= QFont::DemiBold && styleKey.style != QFont::StyleItalic) {
+ QtFontStyle::Key key(styleKey);
+ key.weight = QFont::Bold;
+ key.style = QFont::StyleItalic;
+ QtFontStyle *style = foundry->style(key, true);
+ style->smoothScalable = scalable;
+ style->pixelSize( size, TRUE);
+ }
+
+ family->fixedPitch = fixed;
+
+ if (!family->writingSystemCheck && type & TRUETYPE_FONTTYPE) {
+ quint32 unicodeRange[4] = {
+ signature->fsUsb[0], signature->fsUsb[1],
+ signature->fsUsb[2], signature->fsUsb[3]
+ };
+#ifdef Q_WS_WINCE
+ if (signature->fsUsb[0] == 0) {
+ // If the unicode ranges bit mask is zero then
+ // EnumFontFamiliesEx failed to determine it properly.
+ // In this case we just pretend that the font supports all languages.
+ unicodeRange[0] = 0xbfffffff; // second most significant bit must be zero
+ unicodeRange[1] = 0xffffffff;
+ unicodeRange[2] = 0xffffffff;
+ unicodeRange[3] = 0xffffffff;
+ }
+#endif
+ quint32 codePageRange[2] = {
+ signature->fsCsb[0], signature->fsCsb[1]
+ };
+ QList<QFontDatabase::WritingSystem> systems = qt_determine_writing_systems_from_truetype_bits(unicodeRange, codePageRange);
+
+ for (int i = 0; i < systems.count(); ++i) {
+ QFontDatabase::WritingSystem writingSystem = systems.at(i);
+
+ // ### Hack to work around problem with Thai text on Windows 7. Segoe UI contains
+ // the symbol for Baht, and Windows thus reports that it supports the Thai script.
+ // Since it's the default UI font on this platform, most widgets will be unable to
+ // display Thai text by default. As a temporary work around, we special case Segoe UI
+ // and remove the Thai script from its list of supported writing systems.
+ if (writingSystem != QFontDatabase::Thai || familyName != QLatin1String("Segoe UI"))
+ family->writingSystems[writingSystem] = QtFontFamily::Supported;
+ }
+ } else if (!family->writingSystemCheck) {
+ //qDebug("family='%s' script=%s", family->name.latin1(), script.latin1());
+ if (scriptName == QLatin1String("Western")
+ || scriptName == QLatin1String("Baltic")
+ || scriptName == QLatin1String("Central European")
+ || scriptName == QLatin1String("Turkish")
+ || scriptName == QLatin1String("Vietnamese"))
+ family->writingSystems[QFontDatabase::Latin] = QtFontFamily::Supported;
+ else if (scriptName == QLatin1String("Thai"))
+ family->writingSystems[QFontDatabase::Thai] = QtFontFamily::Supported;
+ else if (scriptName == QLatin1String("Symbol")
+ || scriptName == QLatin1String("Other"))
+ family->writingSystems[QFontDatabase::Symbol] = QtFontFamily::Supported;
+ else if (scriptName == QLatin1String("OEM/Dos"))
+ family->writingSystems[QFontDatabase::Latin] = QtFontFamily::Supported;
+ else if (scriptName == QLatin1String("CHINESE_GB2312"))
+ family->writingSystems[QFontDatabase::SimplifiedChinese] = QtFontFamily::Supported;
+ else if (scriptName == QLatin1String("CHINESE_BIG5"))
+ family->writingSystems[QFontDatabase::TraditionalChinese] = QtFontFamily::Supported;
+ else if (scriptName == QLatin1String("Cyrillic"))
+ family->writingSystems[QFontDatabase::Cyrillic] = QtFontFamily::Supported;
+ else if (scriptName == QLatin1String("Hangul"))
+ family->writingSystems[QFontDatabase::Korean] = QtFontFamily::Supported;
+ else if (scriptName == QLatin1String("Hebrew"))
+ family->writingSystems[QFontDatabase::Hebrew] = QtFontFamily::Supported;
+ else if (scriptName == QLatin1String("Greek"))
+ family->writingSystems[QFontDatabase::Greek] = QtFontFamily::Supported;
+ else if (scriptName == QLatin1String("Japanese"))
+ family->writingSystems[QFontDatabase::Japanese] = QtFontFamily::Supported;
+ else if (scriptName == QLatin1String("Arabic"))
+ family->writingSystems[QFontDatabase::Arabic] = QtFontFamily::Supported;
+ }
+ }
+}
+
+static
+int CALLBACK
+storeFont(ENUMLOGFONTEX* f, NEWTEXTMETRICEX *textmetric, int type, LPARAM /*p*/)
+{
+ QString familyName = QString::fromWCharArray(f->elfLogFont.lfFaceName);
+ QString script = QString::fromWCharArray(f->elfScript);
+
+ FONTSIGNATURE signature = textmetric->ntmFontSig;
+
+ // NEWTEXTMETRICEX is a NEWTEXTMETRIC, which according to the documentation is
+ // identical to a TEXTMETRIC except for the last four members, which we don't use
+ // anyway
+ addFontToDatabase(familyName, script, (TEXTMETRIC *)textmetric, &signature, type);
+ // keep on enumerating
+ return 1;
+}
+
+static
+void populate_database(const QString& fam)
+{
+ QFontDatabasePrivate *d = privateDb();
+ if (!d)
+ return;
+
+ QtFontFamily *family = 0;
+ if(!fam.isEmpty()) {
+ family = d->family(fam);
+ if(family && family->loaded)
+ return;
+ } else if (d->count) {
+ return;
+ }
+
+ HDC dummy = GetDC(0);
+
+ LOGFONT lf;
+ lf.lfCharSet = DEFAULT_CHARSET;
+ if (fam.isNull()) {
+ lf.lfFaceName[0] = 0;
+ } else {
+ memcpy(lf.lfFaceName, fam.utf16(), sizeof(wchar_t) * qMin(fam.length() + 1, 32)); // 32 = Windows hard-coded
+ }
+ lf.lfPitchAndFamily = 0;
+
+ EnumFontFamiliesEx(dummy, &lf,
+ (FONTENUMPROC)storeFont, (LPARAM)privateDb(), 0);
+
+ ReleaseDC(0, dummy);
+
+ for (int i = 0; i < d->applicationFonts.count(); ++i) {
+ QFontDatabasePrivate::ApplicationFont fnt = d->applicationFonts.at(i);
+ if (!fnt.memoryFont)
+ continue;
+ for (int j = 0; j < fnt.families.count(); ++j) {
+ const QString familyName = fnt.families.at(j);
+ HDC hdc = GetDC(0);
+ LOGFONT lf;
+ memset(&lf, 0, sizeof(LOGFONT));
+ memcpy(lf.lfFaceName, familyName.utf16(), sizeof(wchar_t) * qMin(LF_FACESIZE, familyName.size()));
+ lf.lfCharSet = DEFAULT_CHARSET;
+ HFONT hfont = CreateFontIndirect(&lf);
+ HGDIOBJ oldobj = SelectObject(hdc, hfont);
+
+ TEXTMETRIC textMetrics;
+ GetTextMetrics(hdc, &textMetrics);
+
+ addFontToDatabase(familyName, QString(),
+ &textMetrics,
+ &fnt.signatures.at(j),
+ TRUETYPE_FONTTYPE);
+
+ SelectObject(hdc, oldobj);
+ DeleteObject(hfont);
+ ReleaseDC(0, hdc);
+ }
+ }
+
+ if(!fam.isEmpty()) {
+ family = d->family(fam);
+ if(family) {
+ if(!family->writingSystemCheck) {
+ }
+ family->loaded = true;
+ }
+ }
+}
+
+static void initializeDb()
+{
+ QFontDatabasePrivate *db = privateDb();
+ if (!db || db->count)
+ return;
+
+ populate_database(QString());
+
+#ifdef QFONTDATABASE_DEBUG
+ // print the database
+ for (int f = 0; f < db->count; f++) {
+ QtFontFamily *family = db->families[f];
+ qDebug(" %s: %p", qPrintable(family->name), family);
+ populate_database(family->name);
+
+#if 0
+ qDebug(" scripts supported:");
+ for (int i = 0; i < QUnicodeTables::ScriptCount; i++)
+ if(family->writingSystems[i] & QtFontFamily::Supported)
+ qDebug(" %d", i);
+ for (int fd = 0; fd < family->count; fd++) {
+ QtFontFoundry *foundry = family->foundries[fd];
+ qDebug(" %s", foundry->name.latin1());
+ for (int s = 0; s < foundry->count; s++) {
+ QtFontStyle *style = foundry->styles[s];
+ qDebug(" style: style=%d weight=%d smooth=%d", style->key.style,
+ style->key.weight, style->smoothScalable );
+ if(!style->smoothScalable) {
+ for(int i = 0; i < style->count; ++i) {
+ qDebug(" %d", style->pixelSizes[i].pixelSize);
+ }
+ }
+ }
+ }
+#endif
+ }
+#endif // QFONTDATABASE_DEBUG
+
+}
+
+static inline void load(const QString &family = QString(), int = -1)
+{
+ populate_database(family);
+}
+
+
+
+
+
+// --------------------------------------------------------------------------------------
+// font loader
+// --------------------------------------------------------------------------------------
+
+
+
+static void initFontInfo(QFontEngineWin *fe, const QFontDef &request, HDC fontHdc, int dpi)
+{
+ fe->fontDef = request; // most settings are equal
+
+ HDC dc = ((request.styleStrategy & QFont::PreferDevice) && fontHdc) ? fontHdc : shared_dc();
+ SelectObject(dc, fe->hfont);
+ wchar_t n[64];
+ GetTextFace(dc, 64, n);
+ fe->fontDef.family = QString::fromWCharArray(n);
+ fe->fontDef.fixedPitch = !(fe->tm.tmPitchAndFamily & TMPF_FIXED_PITCH);
+ if (fe->fontDef.pointSize < 0) {
+ fe->fontDef.pointSize = fe->fontDef.pixelSize * 72. / dpi;
+ } else if (fe->fontDef.pixelSize == -1) {
+ fe->fontDef.pixelSize = qRound(fe->fontDef.pointSize * dpi / 72.);
+ }
+}
+
+#if !defined(QT_NO_DIRECTWRITE)
+static void initFontInfo(QFontEngineDirectWrite *fe, const QFontDef &request,
+ int dpi, IDWriteFont *font)
+{
+ fe->fontDef = request;
+
+ IDWriteFontFamily *fontFamily = NULL;
+ HRESULT hr = font->GetFontFamily(&fontFamily);
+
+ IDWriteLocalizedStrings *familyNames = NULL;
+ if (SUCCEEDED(hr))
+ hr = fontFamily->GetFamilyNames(&familyNames);
+
+ UINT32 index = 0;
+ BOOL exists = false;
+
+ wchar_t localeName[LOCALE_NAME_MAX_LENGTH];
+
+ if (SUCCEEDED(hr)) {
+ int defaultLocaleSuccess = GetUserDefaultLocaleName(localeName, LOCALE_NAME_MAX_LENGTH);
+
+ if (defaultLocaleSuccess)
+ hr = familyNames->FindLocaleName(localeName, &index, &exists);
+
+ if (SUCCEEDED(hr) && !exists)
+ hr = familyNames->FindLocaleName(L"en-us", &index, &exists);
+ }
+
+ if (!exists)
+ index = 0;
+
+ UINT32 length = 0;
+ if (SUCCEEDED(hr))
+ hr = familyNames->GetStringLength(index, &length);
+
+ wchar_t *name = new (std::nothrow) wchar_t[length+1];
+ if (name == NULL)
+ hr = E_OUTOFMEMORY;
+
+ // Get the family name.
+ if (SUCCEEDED(hr))
+ hr = familyNames->GetString(index, name, length + 1);
+
+ if (SUCCEEDED(hr))
+ fe->fontDef.family = QString::fromWCharArray(name);
+
+ delete[] name;
+ if (familyNames != NULL)
+ familyNames->Release();
+
+ if (FAILED(hr))
+ qErrnoWarning(hr, "initFontInfo: Failed to get family name");
+
+ if (fe->fontDef.pointSize < 0)
+ fe->fontDef.pointSize = fe->fontDef.pixelSize * 72. / dpi;
+ else if (fe->fontDef.pixelSize == -1)
+ fe->fontDef.pixelSize = qRound(fe->fontDef.pointSize * dpi / 72.);
+}
+#endif
+
+static const char *other_tryFonts[] = {
+ "Arial",
+ "MS UI Gothic",
+ "Gulim",
+ "SimSun",
+ "PMingLiU",
+ "Arial Unicode MS",
+ 0
+};
+
+static const char *jp_tryFonts [] = {
+ "MS UI Gothic",
+ "Arial",
+ "Gulim",
+ "SimSun",
+ "PMingLiU",
+ "Arial Unicode MS",
+ 0
+};
+
+static const char *ch_CN_tryFonts [] = {
+ "SimSun",
+ "Arial",
+ "PMingLiU",
+ "Gulim",
+ "MS UI Gothic",
+ "Arial Unicode MS",
+ 0
+};
+
+static const char *ch_TW_tryFonts [] = {
+ "PMingLiU",
+ "Arial",
+ "SimSun",
+ "Gulim",
+ "MS UI Gothic",
+ "Arial Unicode MS",
+ 0
+};
+
+static const char *kr_tryFonts[] = {
+ "Gulim",
+ "Arial",
+ "PMingLiU",
+ "SimSun",
+ "MS UI Gothic",
+ "Arial Unicode MS",
+ 0
+};
+
+static const char **tryFonts = 0;
+
+#if !defined(QT_NO_DIRECTWRITE)
+static QString fontNameSubstitute(const QString &familyName)
+{
+ QLatin1String key("HKEY_LOCAL_MACHINE\\Software\\Microsoft\\Windows NT\\CurrentVersion\\"
+ "FontSubstitutes");
+ return QSettings(key, QSettings::NativeFormat).value(familyName, familyName).toString();
+}
+#endif
+
+static inline HFONT systemFont()
+{
+ if (stock_sysfont == 0)
+ stock_sysfont = (HFONT)GetStockObject(SYSTEM_FONT);
+ return stock_sysfont;
+}
+
+#if !defined(DEFAULT_GUI_FONT)
+#define DEFAULT_GUI_FONT 17
+#endif
+
+static QFontEngine *loadEngine(int script, const QFontDef &request,
+ HDC fontHdc, int dpi, bool rawMode,
+ const QtFontDesc *desc,
+ const QStringList &family_list)
+{
+ LOGFONT lf;
+ memset(&lf, 0, sizeof(LOGFONT));
+
+ bool useDevice = (request.styleStrategy & QFont::PreferDevice) && fontHdc;
+
+ HDC hdc = shared_dc();
+ QString font_name = desc != 0 ? desc->family->name : request.family;
+
+ if (useDevice) {
+ hdc = fontHdc;
+ font_name = request.family;
+ }
+
+ bool stockFont = false;
+ bool preferClearTypeAA = false;
+
+ HFONT hfont = 0;
+
+
+#if !defined(QT_NO_DIRECTWRITE)
+ bool useDirectWrite = (request.hintingPreference == QFont::PreferNoHinting)
+ || (request.hintingPreference == QFont::PreferVerticalHinting);
+ IDWriteFont *directWriteFont = 0;
+#else
+ bool useDirectWrite = false;
+#endif
+
+ if (rawMode) { // will choose a stock font
+ int f, deffnt = SYSTEM_FONT;
+ QString fam = desc != 0 ? desc->family->name.toLower() : request.family.toLower();
+ if (fam == QLatin1String("default"))
+ f = deffnt;
+ else if (fam == QLatin1String("system"))
+ f = SYSTEM_FONT;
+#ifndef Q_WS_WINCE
+ else if (fam == QLatin1String("system_fixed"))
+ f = SYSTEM_FIXED_FONT;
+ else if (fam == QLatin1String("ansi_fixed"))
+ f = ANSI_FIXED_FONT;
+ else if (fam == QLatin1String("ansi_var"))
+ f = ANSI_VAR_FONT;
+ else if (fam == QLatin1String("device_default"))
+ f = DEVICE_DEFAULT_FONT;
+ else if (fam == QLatin1String("oem_fixed"))
+ f = OEM_FIXED_FONT;
+#endif
+ else if (fam[0] == QLatin1Char('#'))
+ f = fam.right(fam.length()-1).toInt();
+ else
+ f = deffnt;
+ hfont = (HFONT)GetStockObject(f);
+ if (!hfont) {
+ qErrnoWarning("QFontEngine::loadEngine: GetStockObject failed");
+ hfont = systemFont();
+ }
+ stockFont = true;
+ } else {
+
+ int hint = FF_DONTCARE;
+ switch (request.styleHint) {
+ case QFont::Helvetica:
+ hint = FF_SWISS;
+ break;
+ case QFont::Times:
+ hint = FF_ROMAN;
+ break;
+ case QFont::Courier:
+ hint = FF_MODERN;
+ break;
+ case QFont::OldEnglish:
+ hint = FF_DECORATIVE;
+ break;
+ case QFont::System:
+ hint = FF_MODERN;
+ break;
+ default:
+ break;
+ }
+
+ lf.lfHeight = -qRound(request.pixelSize);
+ lf.lfWidth = 0;
+ lf.lfEscapement = 0;
+ lf.lfOrientation = 0;
+ if (desc == 0 || desc->style->key.weight == 50)
+ lf.lfWeight = FW_DONTCARE;
+ else
+ lf.lfWeight = (desc->style->key.weight*900)/99;
+ lf.lfItalic = (desc != 0 && desc->style->key.style != QFont::StyleNormal);
+ lf.lfCharSet = DEFAULT_CHARSET;
+
+ int strat = OUT_DEFAULT_PRECIS;
+ if (request.styleStrategy & QFont::PreferBitmap) {
+ strat = OUT_RASTER_PRECIS;
+#ifndef Q_WS_WINCE
+ } else if (request.styleStrategy & QFont::PreferDevice) {
+ strat = OUT_DEVICE_PRECIS;
+ } else if (request.styleStrategy & QFont::PreferOutline) {
+ strat = OUT_OUTLINE_PRECIS;
+ } else if (request.styleStrategy & QFont::ForceOutline) {
+ strat = OUT_TT_ONLY_PRECIS;
+#endif
+ }
+
+ lf.lfOutPrecision = strat;
+
+ int qual = DEFAULT_QUALITY;
+
+ if (request.styleStrategy & QFont::PreferMatch)
+ qual = DRAFT_QUALITY;
+#ifndef Q_WS_WINCE
+ else if (request.styleStrategy & QFont::PreferQuality)
+ qual = PROOF_QUALITY;
+#endif
+
+ if (request.styleStrategy & QFont::PreferAntialias) {
+ if (QSysInfo::WindowsVersion >= QSysInfo::WV_XP) {
+ qual = CLEARTYPE_QUALITY;
+ preferClearTypeAA = true;
+ } else {
+ qual = ANTIALIASED_QUALITY;
+ }
+ } else if (request.styleStrategy & QFont::NoAntialias) {
+ qual = NONANTIALIASED_QUALITY;
+ }
+
+ lf.lfQuality = qual;
+
+ lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
+ lf.lfPitchAndFamily = DEFAULT_PITCH | hint;
+
+ QString fam = font_name;
+
+ if(fam.isEmpty())
+ fam = QLatin1String("MS Sans Serif");
+
+ if ((fam == QLatin1String("MS Sans Serif"))
+ && (request.style == QFont::StyleItalic || (-lf.lfHeight > 18 && -lf.lfHeight != 24))) {
+ fam = QLatin1String("Arial"); // MS Sans Serif has bearing problems in italic, and does not scale
+ }
+ if (fam == QLatin1String("Courier") && !(request.styleStrategy & QFont::PreferBitmap))
+ fam = QLatin1String("Courier New");
+
+ memcpy(lf.lfFaceName, fam.utf16(), sizeof(wchar_t) * qMin(fam.length() + 1, 32)); // 32 = Windows hard-coded
+
+ hfont = CreateFontIndirect(&lf);
+ if (!hfont)
+ qErrnoWarning("QFontEngine::loadEngine: CreateFontIndirect failed");
+
+ stockFont = (hfont == 0);
+ bool ttf = false;
+ int avWidth = 0;
+ BOOL res;
+ HGDIOBJ oldObj = SelectObject(hdc, hfont);
+
+ TEXTMETRIC tm;
+ res = GetTextMetrics(hdc, &tm);
+ avWidth = tm.tmAveCharWidth;
+ ttf = tm.tmPitchAndFamily & TMPF_TRUETYPE;
+ SelectObject(hdc, oldObj);
+
+ if (!ttf || !useDirectWrite) {
+ useDirectWrite = false;
+
+ if (hfont && (!ttf || request.stretch != 100)) {
+ DeleteObject(hfont);
+ if (!res)
+ qErrnoWarning("QFontEngine::loadEngine: GetTextMetrics failed");
+ lf.lfWidth = avWidth * request.stretch/100;
+ hfont = CreateFontIndirect(&lf);
+ if (!hfont)
+ qErrnoWarning("QFontEngine::loadEngine: CreateFontIndirect with stretch failed");
+ }
+
+#ifndef Q_WS_WINCE
+ if (hfont == 0) {
+ hfont = (HFONT)GetStockObject(ANSI_VAR_FONT);
+ stockFont = true;
+ }
+#else
+ if (hfont == 0) {
+ hfont = (HFONT)GetStockObject(SYSTEM_FONT);
+ stockFont = true;
+ }
+#endif
+
+ }
+
+#if !defined(QT_NO_DIRECTWRITE)
+ else {
+ // Default to false for DirectWrite (and re-enable once/if everything
+ // turns out okay)
+ useDirectWrite = false;
+
+ QFontDatabasePrivate *db = privateDb();
+ if (db->directWriteFactory == 0) {
+ HRESULT hr = DWriteCreateFactory(
+ DWRITE_FACTORY_TYPE_SHARED,
+ __uuidof(IDWriteFactory),
+ reinterpret_cast<IUnknown **>(&db->directWriteFactory)
+ );
+ if (FAILED(hr)) {
+ qErrnoWarning("QFontEngine::loadEngine: DWriteCreateFactory failed");
+ } else {
+ hr = db->directWriteFactory->GetGdiInterop(&db->directWriteGdiInterop);
+ if (FAILED(hr))
+ qErrnoWarning("QFontEngine::loadEngine: GetGdiInterop failed");
+ }
+ }
+
+ if (db->directWriteGdiInterop != 0) {
+ QString nameSubstitute = fontNameSubstitute(QString::fromWCharArray(lf.lfFaceName));
+ memcpy(lf.lfFaceName, nameSubstitute.utf16(),
+ sizeof(wchar_t) * qMin(nameSubstitute.length() + 1, LF_FACESIZE));
+
+ HRESULT hr = db->directWriteGdiInterop->CreateFontFromLOGFONT(
+ &lf,
+ &directWriteFont);
+ if (FAILED(hr)) {
+#ifndef QT_NO_DEBUG
+ qErrnoWarning("QFontEngine::loadEngine: CreateFontFromLOGFONT failed "
+ "for %ls (0x%lx)",
+ lf.lfFaceName, hr);
+#endif
+ } else {
+ DeleteObject(hfont);
+ useDirectWrite = true;
+ }
+ }
+ }
+#endif
+
+ }
+
+ QFontEngine *fe = 0;
+ if (!useDirectWrite) {
+ QFontEngineWin *few = new QFontEngineWin(font_name, hfont, stockFont, lf);
+ if (preferClearTypeAA)
+ few->glyphFormat = QFontEngineGlyphCache::Raster_RGBMask;
+
+ // Also check for OpenType tables when using complex scripts
+ // ### TODO: This only works for scripts that require OpenType. More generally
+ // for scripts that do not require OpenType we should just look at the list of
+ // supported writing systems in the font's OS/2 table.
+ if (scriptRequiresOpenType(script)) {
+ HB_Face hbFace = few->harfbuzzFace();
+ if (!hbFace || !hbFace->supported_scripts[script]) {
+ FM_DEBUG(" OpenType support missing for script\n");
+ delete few;
+ return 0;
+ }
+ }
+
+ initFontInfo(few, request, fontHdc, dpi);
+ fe = few;
+ }
+
+#if !defined(QT_NO_DIRECTWRITE)
+ else {
+ QFontDatabasePrivate *db = privateDb();
+
+ IDWriteFontFace *directWriteFontFace = NULL;
+ HRESULT hr = directWriteFont->CreateFontFace(&directWriteFontFace);
+ if (SUCCEEDED(hr)) {
+ QFontEngineDirectWrite *fedw = new QFontEngineDirectWrite(db->directWriteFactory,
+ directWriteFontFace,
+ request.pixelSize);
+
+ initFontInfo(fedw, request, dpi, directWriteFont);
+
+ fe = fedw;
+ } else {
+ qErrnoWarning(hr, "QFontEngine::loadEngine: CreateFontFace failed");
+ }
+ }
+
+ if (directWriteFont != 0)
+ directWriteFont->Release();
+#endif
+
+ if(script == QUnicodeTables::Common
+ && !(request.styleStrategy & QFont::NoFontMerging)
+ && desc != 0
+ && !(desc->family->writingSystems[QFontDatabase::Symbol] & QtFontFamily::Supported)) {
+ if(!tryFonts) {
+ LANGID lid = GetUserDefaultLangID();
+ switch( lid&0xff ) {
+ case LANG_CHINESE: // Chinese (Taiwan)
+ if ( lid == 0x0804 ) // Taiwan
+ tryFonts = ch_TW_tryFonts;
+ else
+ tryFonts = ch_CN_tryFonts;
+ break;
+ case LANG_JAPANESE:
+ tryFonts = jp_tryFonts;
+ break;
+ case LANG_KOREAN:
+ tryFonts = kr_tryFonts;
+ break;
+ default:
+ tryFonts = other_tryFonts;
+ break;
+ }
+ }
+ QStringList fm = QFontDatabase().families();
+ QStringList list = family_list;
+ const char **tf = tryFonts;
+ while(tf && *tf) {
+ if(fm.contains(QLatin1String(*tf)))
+ list << QLatin1String(*tf);
+ ++tf;
+ }
+ QFontEngine *mfe = new QFontEngineMultiWin(fe, list);
+ mfe->fontDef = fe->fontDef;
+ fe = mfe;
+ }
+ return fe;
+}
+
+QFontEngine *qt_load_font_engine_win(const QFontDef &request)
+{
+ // From qfont.cpp
+ extern int qt_defaultDpi();
+
+ QFontCache::Key key(request, QUnicodeTables::Common);
+ QFontEngine *fe = QFontCache::instance()->findEngine(key);
+ if (fe != 0)
+ return fe;
+ else
+ return loadEngine(QUnicodeTables::Common, request, 0, qt_defaultDpi(), false, 0,
+ QStringList());
+}
+
+const char *styleHint(const QFontDef &request)
+{
+ const char *stylehint = 0;
+ switch (request.styleHint) {
+ case QFont::SansSerif:
+ stylehint = "Arial";
+ break;
+ case QFont::Serif:
+ stylehint = "Times New Roman";
+ break;
+ case QFont::TypeWriter:
+ stylehint = "Courier New";
+ break;
+ default:
+ if (request.fixedPitch)
+ stylehint = "Courier New";
+ break;
+ }
+ return stylehint;
+}
+
+static QFontEngine *loadWin(const QFontPrivate *d, int script, const QFontDef &req)
+{
+ // list of families to try
+ QStringList family_list = familyList(req);
+
+ const char *stylehint = styleHint(d->request);
+ if (stylehint)
+ family_list << QLatin1String(stylehint);
+
+ // append the default fallback font for the specified script
+ // family_list << ... ; ###########
+
+ // add the default family
+ QString defaultFamily = QApplication::font().family();
+ if (! family_list.contains(defaultFamily))
+ family_list << defaultFamily;
+
+ // add QFont::defaultFamily() to the list, for compatibility with
+ // previous versions
+ family_list << QApplication::font().defaultFamily();
+
+ // null family means find the first font matching the specified script
+ family_list << QString();
+
+ QtFontDesc desc;
+ QFontEngine *fe = 0;
+ QList<int> blacklistedFamilies;
+
+ while (!fe) {
+ for (int i = 0; i < family_list.size(); ++i) {
+ QString family, foundry;
+ parseFontName(family_list.at(i), foundry, family);
+ FM_DEBUG("loadWin: >>>>>>>>>>>>>>trying to match '%s'", family.toLatin1().data());
+ QT_PREPEND_NAMESPACE(match)(script, req, family, foundry, -1, &desc, blacklistedFamilies);
+ if (desc.family)
+ break;
+ }
+ if (!desc.family)
+ break;
+ fe = loadEngine(script, req, d->hdc, d->dpi, d->rawMode, &desc, family_list);
+ if (!fe)
+ blacklistedFamilies.append(desc.familyIndex);
+ }
+ return fe;
+}
+
+void QFontDatabase::load(const QFontPrivate *d, int script)
+{
+ // sanity checks
+ if (!qApp)
+ qWarning("QFontDatabase::load: Must construct QApplication first");
+ Q_ASSERT(script >= 0 && script < QUnicodeTables::ScriptCount);
+
+ // normalize the request to get better caching
+ QFontDef req = d->request;
+ if (req.pixelSize <= 0)
+ req.pixelSize = floor((100.0 * req.pointSize * d->dpi) / 72. + 0.5) / 100;
+ if (req.pixelSize < 1)
+ req.pixelSize = 1;
+ if (req.weight == 0)
+ req.weight = QFont::Normal;
+ if (req.stretch == 0)
+ req.stretch = 100;
+
+ QFontCache::Key key(req, d->rawMode ? QUnicodeTables::Common : script, d->screen);
+ if (!d->engineData)
+ getEngineData(d, key);
+
+ // the cached engineData could have already loaded the engine we want
+ if (d->engineData->engines[script])
+ return;
+
+ QFontEngine *fe = QFontCache::instance()->findEngine(key);
+
+ // set it to the actual pointsize, so QFontInfo will do the right thing
+ if (req.pointSize < 0)
+ req.pointSize = req.pixelSize*72./d->dpi;
+
+ if (!fe) {
+ if (qt_enable_test_font && req.family == QLatin1String("__Qt__Box__Engine__")) {
+ fe = new QTestFontEngine(req.pixelSize);
+ fe->fontDef = req;
+ } else {
+ QMutexLocker locker(fontDatabaseMutex());
+ if (!privateDb()->count)
+ initializeDb();
+ fe = loadWin(d, script, req);
+ }
+ if (!fe) {
+ fe = new QFontEngineBox(req.pixelSize);
+ fe->fontDef = QFontDef();
+ }
+ }
+ d->engineData->engines[script] = fe;
+ fe->ref.ref();
+ QFontCache::instance()->insertEngine(key, fe);
+}
+
+#if !defined(FR_PRIVATE)
+#define FR_PRIVATE 0x10
+#endif
+
+typedef int (WINAPI *PtrAddFontResourceExW)(LPCWSTR, DWORD, PVOID);
+typedef HANDLE (WINAPI *PtrAddFontMemResourceEx)(PVOID, DWORD, PVOID, DWORD *);
+typedef BOOL (WINAPI *PtrRemoveFontResourceExW)(LPCWSTR, DWORD, PVOID);
+typedef BOOL (WINAPI *PtrRemoveFontMemResourceEx)(HANDLE);
+
+static QList<quint32> getTrueTypeFontOffsets(const uchar *fontData)
+{
+ QList<quint32> offsets;
+ const quint32 headerTag = *reinterpret_cast<const quint32 *>(fontData);
+ if (headerTag != MAKE_TAG('t', 't', 'c', 'f')) {
+ if (headerTag != MAKE_TAG(0, 1, 0, 0)
+ && headerTag != MAKE_TAG('O', 'T', 'T', 'O')
+ && headerTag != MAKE_TAG('t', 'r', 'u', 'e')
+ && headerTag != MAKE_TAG('t', 'y', 'p', '1'))
+ return offsets;
+ offsets << 0;
+ return offsets;
+ }
+ const quint32 numFonts = qFromBigEndian<quint32>(fontData + 8);
+ for (uint i = 0; i < numFonts; ++i) {
+ offsets << qFromBigEndian<quint32>(fontData + 12 + i * 4);
+ }
+ return offsets;
+}
+
+static void getFontTable(const uchar *fileBegin, const uchar *data, quint32 tag, const uchar **table, quint32 *length)
+{
+ const quint16 numTables = qFromBigEndian<quint16>(data + 4);
+ for (uint i = 0; i < numTables; ++i) {
+ const quint32 offset = 12 + 16 * i;
+ if (*reinterpret_cast<const quint32 *>(data + offset) == tag) {
+ *table = fileBegin + qFromBigEndian<quint32>(data + offset + 8);
+ *length = qFromBigEndian<quint32>(data + offset + 12);
+ return;
+ }
+ }
+ *table = 0;
+ *length = 0;
+ return;
+}
+
+static void getFamiliesAndSignatures(const QByteArray &fontData, QFontDatabasePrivate::ApplicationFont *appFont)
+{
+ const uchar *data = reinterpret_cast<const uchar *>(fontData.constData());
+
+ QList<quint32> offsets = getTrueTypeFontOffsets(data);
+ if (offsets.isEmpty())
+ return;
+
+ for (int i = 0; i < offsets.count(); ++i) {
+ const uchar *font = data + offsets.at(i);
+ const uchar *table;
+ quint32 length;
+ getFontTable(data, font, MAKE_TAG('n', 'a', 'm', 'e'), &table, &length);
+ if (!table)
+ continue;
+ QString name = getEnglishName(table, length);
+ if (name.isEmpty())
+ continue;
+
+ appFont->families << name;
+ FONTSIGNATURE signature;
+ getFontTable(data, font, MAKE_TAG('O', 'S', '/', '2'), &table, &length);
+ if (table && length >= 86) {
+ // See also qfontdatabase_mac.cpp, offsets taken from OS/2 table in the TrueType spec
+ signature.fsUsb[0] = qFromBigEndian<quint32>(table + 42);
+ signature.fsUsb[1] = qFromBigEndian<quint32>(table + 46);
+ signature.fsUsb[2] = qFromBigEndian<quint32>(table + 50);
+ signature.fsUsb[3] = qFromBigEndian<quint32>(table + 54);
+
+ signature.fsCsb[0] = qFromBigEndian<quint32>(table + 78);
+ signature.fsCsb[1] = qFromBigEndian<quint32>(table + 82);
+ } else {
+ memset(&signature, 0, sizeof(signature));
+ }
+ appFont->signatures << signature;
+ }
+}
+
+static void registerFont(QFontDatabasePrivate::ApplicationFont *fnt)
+{
+ if(!fnt->data.isEmpty()) {
+#ifndef Q_OS_WINCE
+ PtrAddFontMemResourceEx ptrAddFontMemResourceEx = (PtrAddFontMemResourceEx)QSystemLibrary::resolve(QLatin1String("gdi32"),
+ "AddFontMemResourceEx");
+ if (!ptrAddFontMemResourceEx)
+ return;
+#endif
+ getFamiliesAndSignatures(fnt->data, fnt);
+ if (fnt->families.isEmpty())
+ return;
+
+#ifdef Q_OS_WINCE
+ HANDLE handle = 0;
+
+ {
+#ifdef QT_NO_TEMPORARYFILE
+ wchar_t lpBuffer[MAX_PATH];
+ GetTempPath(MAX_PATH, lpBuffer);
+ QString s = QString::fromWCharArray(lpBuffer);
+ QFile tempfile(s + QLatin1String("/font") + QString::number(GetTickCount()) + QLatin1String(".ttf"));
+ if (!tempfile.open(QIODevice::ReadWrite))
+#else
+ QTemporaryFile tempfile(QLatin1String("XXXXXXXX.ttf"));
+ if (!tempfile.open())
+#endif // QT_NO_TEMPORARYFILE
+ return;
+ if (tempfile.write(fnt->data) == -1)
+ return;
+
+#ifndef QT_NO_TEMPORARYFILE
+ tempfile.setAutoRemove(false);
+#endif
+ fnt->fileName = QFileInfo(tempfile.fileName()).absoluteFilePath();
+ }
+
+ if (AddFontResource((LPCWSTR)fnt->fileName.utf16()) == 0) {
+ QFile(fnt->fileName).remove();
+ return;
+ }
+#else
+ DWORD dummy = 0;
+ HANDLE handle = ptrAddFontMemResourceEx((void *)fnt->data.constData(), fnt->data.size(), 0,
+ &dummy);
+ if (handle == 0)
+ return;
+#endif // Q_OS_WINCE
+
+ fnt->handle = handle;
+ fnt->data = QByteArray();
+ fnt->memoryFont = true;
+ } else {
+ QFile f(fnt->fileName);
+ if (!f.open(QIODevice::ReadOnly))
+ return;
+ QByteArray data = f.readAll();
+ f.close();
+ getFamiliesAndSignatures(data, fnt);
+
+#ifdef Q_OS_WINCE
+ QFileInfo fileinfo(fnt->fileName);
+ fnt->fileName = fileinfo.absoluteFilePath();
+ if (AddFontResource((LPCWSTR)fnt->fileName.utf16()) == 0)
+ return;
+#else
+ PtrAddFontResourceExW ptrAddFontResourceExW = (PtrAddFontResourceExW)QSystemLibrary::resolve(QLatin1String("gdi32"),
+ "AddFontResourceExW");
+ if (!ptrAddFontResourceExW
+ || ptrAddFontResourceExW((wchar_t*)fnt->fileName.utf16(), FR_PRIVATE, 0) == 0)
+ return;
+#endif // Q_OS_WINCE
+
+ fnt->memoryFont = false;
+ }
+}
+
+bool QFontDatabase::removeApplicationFont(int handle)
+{
+ QMutexLocker locker(fontDatabaseMutex());
+
+ QFontDatabasePrivate *db = privateDb();
+ if (handle < 0 || handle >= db->applicationFonts.count())
+ return false;
+
+ const QFontDatabasePrivate::ApplicationFont font = db->applicationFonts.at(handle);
+ db->applicationFonts[handle] = QFontDatabasePrivate::ApplicationFont();
+ if (font.memoryFont) {
+#ifdef Q_OS_WINCE
+ bool removeSucceeded = RemoveFontResource((LPCWSTR)font.fileName.utf16());
+ QFile tempfile(font.fileName);
+ tempfile.remove();
+ if (!removeSucceeded)
+ return false;
+#else
+ PtrRemoveFontMemResourceEx ptrRemoveFontMemResourceEx = (PtrRemoveFontMemResourceEx)QSystemLibrary::resolve(QLatin1String("gdi32"),
+ "RemoveFontMemResourceEx");
+ if (!ptrRemoveFontMemResourceEx
+ || !ptrRemoveFontMemResourceEx(font.handle))
+ return false;
+#endif // Q_OS_WINCE
+ } else {
+#ifdef Q_OS_WINCE
+ if (!RemoveFontResource((LPCWSTR)font.fileName.utf16()))
+ return false;
+#else
+ PtrRemoveFontResourceExW ptrRemoveFontResourceExW = (PtrRemoveFontResourceExW)QSystemLibrary::resolve(QLatin1String("gdi32"),
+ "RemoveFontResourceExW");
+ if (!ptrRemoveFontResourceExW
+ || !ptrRemoveFontResourceExW((LPCWSTR)font.fileName.utf16(), FR_PRIVATE, 0))
+ return false;
+#endif // Q_OS_WINCE
+ }
+
+ db->invalidate();
+ return true;
+}
+
+bool QFontDatabase::removeAllApplicationFonts()
+{
+ QMutexLocker locker(fontDatabaseMutex());
+
+ QFontDatabasePrivate *db = privateDb();
+ for (int i = 0; i < db->applicationFonts.count(); ++i)
+ if (!removeApplicationFont(i))
+ return false;
+ return true;
+}
+
+bool QFontDatabase::supportsThreadedFontRendering()
+{
+ return true;
+}
+
+QT_END_NAMESPACE
diff --git a/src/gui/platforms/win/qfontengine_win.cpp b/src/gui/platforms/win/qfontengine_win.cpp
new file mode 100644
index 0000000000..54d7ec2980
--- /dev/null
+++ b/src/gui/platforms/win/qfontengine_win.cpp
@@ -0,0 +1,1339 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#if _WIN32_WINNT < 0x0500
+#undef _WIN32_WINNT
+#define _WIN32_WINNT 0x0500
+#endif
+
+#include "qfontengine_p.h"
+#include "qtextengine_p.h"
+#include <qglobal.h>
+#include "qt_windows.h"
+#include <private/qapplication_p.h>
+
+#include <private/qsystemlibrary_p.h>
+#include <qpaintdevice.h>
+#include <qpainter.h>
+#include <limits.h>
+
+#include <qendian.h>
+#include <qmath.h>
+#include <qthreadstorage.h>
+
+#include <private/qunicodetables_p.h>
+#include <qbitmap.h>
+
+#include <private/qpainter_p.h>
+#include "qpaintengine.h"
+#include "qvarlengtharray.h"
+#include <private/qpaintengine_raster_p.h>
+#include <private/qnativeimage_p.h>
+
+#if defined(Q_WS_WINCE)
+#include "qguifunctions_wince.h"
+#endif
+
+//### mingw needed define
+#ifndef TT_PRIM_CSPLINE
+#define TT_PRIM_CSPLINE 3
+#endif
+
+#ifdef MAKE_TAG
+#undef MAKE_TAG
+#endif
+// GetFontData expects the tags in little endian ;(
+#define MAKE_TAG(ch1, ch2, ch3, ch4) (\
+ (((quint32)(ch4)) << 24) | \
+ (((quint32)(ch3)) << 16) | \
+ (((quint32)(ch2)) << 8) | \
+ ((quint32)(ch1)) \
+ )
+
+// common DC for all fonts
+
+QT_BEGIN_NAMESPACE
+
+class QtHDC
+{
+ HDC _hdc;
+public:
+ QtHDC()
+ {
+ HDC displayDC = GetDC(0);
+ _hdc = CreateCompatibleDC(displayDC);
+ ReleaseDC(0, displayDC);
+ }
+ ~QtHDC()
+ {
+ if (_hdc)
+ DeleteDC(_hdc);
+ }
+ HDC hdc() const
+ {
+ return _hdc;
+ }
+};
+
+#ifndef QT_NO_THREAD
+Q_GLOBAL_STATIC(QThreadStorage<QtHDC *>, local_shared_dc)
+HDC shared_dc()
+{
+ QtHDC *&hdc = local_shared_dc()->localData();
+ if (!hdc)
+ hdc = new QtHDC;
+ return hdc->hdc();
+}
+#else
+HDC shared_dc()
+{
+ return 0;
+}
+#endif
+
+#ifndef Q_WS_WINCE
+typedef BOOL (WINAPI *PtrGetCharWidthI)(HDC, UINT, UINT, LPWORD, LPINT);
+static PtrGetCharWidthI ptrGetCharWidthI = 0;
+static bool resolvedGetCharWidthI = false;
+
+static void resolveGetCharWidthI()
+{
+ if (resolvedGetCharWidthI)
+ return;
+ resolvedGetCharWidthI = true;
+ ptrGetCharWidthI = (PtrGetCharWidthI)QSystemLibrary::resolve(QLatin1String("gdi32"), "GetCharWidthI");
+}
+#endif // !defined(Q_WS_WINCE)
+
+// defined in qtextengine_win.cpp
+typedef void *SCRIPT_CACHE;
+typedef HRESULT (WINAPI *fScriptFreeCache)(SCRIPT_CACHE *);
+extern fScriptFreeCache ScriptFreeCache;
+
+static inline quint32 getUInt(unsigned char *p)
+{
+ quint32 val;
+ val = *p++ << 24;
+ val |= *p++ << 16;
+ val |= *p++ << 8;
+ val |= *p;
+
+ return val;
+}
+
+static inline quint16 getUShort(unsigned char *p)
+{
+ quint16 val;
+ val = *p++ << 8;
+ val |= *p;
+
+ return val;
+}
+
+// general font engine
+
+QFixed QFontEngineWin::lineThickness() const
+{
+ if(lineWidth > 0)
+ return lineWidth;
+
+ return QFontEngine::lineThickness();
+}
+
+static OUTLINETEXTMETRIC *getOutlineTextMetric(HDC hdc)
+{
+ int size;
+ size = GetOutlineTextMetrics(hdc, 0, 0);
+ OUTLINETEXTMETRIC *otm = (OUTLINETEXTMETRIC *)malloc(size);
+ GetOutlineTextMetrics(hdc, size, otm);
+ return otm;
+}
+
+void QFontEngineWin::getCMap()
+{
+ ttf = (bool)(tm.tmPitchAndFamily & TMPF_TRUETYPE);
+ HDC hdc = shared_dc();
+ SelectObject(hdc, hfont);
+ bool symb = false;
+ if (ttf) {
+ cmapTable = getSfntTable(qbswap<quint32>(MAKE_TAG('c', 'm', 'a', 'p')));
+ int size = 0;
+ cmap = QFontEngine::getCMap(reinterpret_cast<const uchar *>(cmapTable.constData()),
+ cmapTable.size(), &symb, &size);
+ }
+ if (!cmap) {
+ ttf = false;
+ symb = false;
+ }
+ symbol = symb;
+ designToDevice = 1;
+ _faceId.index = 0;
+ if(cmap) {
+ OUTLINETEXTMETRIC *otm = getOutlineTextMetric(hdc);
+ designToDevice = QFixed((int)otm->otmEMSquare)/int(otm->otmTextMetrics.tmHeight);
+ unitsPerEm = otm->otmEMSquare;
+ x_height = (int)otm->otmsXHeight;
+ loadKerningPairs(designToDevice);
+ _faceId.filename = QString::fromWCharArray((wchar_t *)((char *)otm + (quintptr)otm->otmpFullName)).toLatin1();
+ lineWidth = otm->otmsUnderscoreSize;
+ fsType = otm->otmfsType;
+ free(otm);
+ } else {
+ unitsPerEm = tm.tmHeight;
+ }
+}
+
+
+inline unsigned int getChar(const QChar *str, int &i, const int len)
+{
+ unsigned int uc = str[i].unicode();
+ if (uc >= 0xd800 && uc < 0xdc00 && i < len-1) {
+ uint low = str[i+1].unicode();
+ if (low >= 0xdc00 && low < 0xe000) {
+ uc = (uc - 0xd800)*0x400 + (low - 0xdc00) + 0x10000;
+ ++i;
+ }
+ }
+ return uc;
+}
+
+int QFontEngineWin::getGlyphIndexes(const QChar *str, int numChars, QGlyphLayout *glyphs, bool mirrored) const
+{
+ int i = 0;
+ int glyph_pos = 0;
+ if (mirrored) {
+#if defined(Q_WS_WINCE)
+ {
+#else
+ if (symbol) {
+ for (; i < numChars; ++i, ++glyph_pos) {
+ unsigned int uc = getChar(str, i, numChars);
+ glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, uc);
+ if (!glyphs->glyphs[glyph_pos] && uc < 0x100)
+ glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, uc + 0xf000);
+ }
+ } else if (ttf) {
+ for (; i < numChars; ++i, ++glyph_pos) {
+ unsigned int uc = getChar(str, i, numChars);
+ glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, QChar::mirroredChar(uc));
+ }
+ } else {
+#endif
+ wchar_t first = tm.tmFirstChar;
+ wchar_t last = tm.tmLastChar;
+
+ for (; i < numChars; ++i, ++glyph_pos) {
+ uint ucs = QChar::mirroredChar(getChar(str, i, numChars));
+ if (
+#ifdef Q_WS_WINCE
+ tm.tmFirstChar > 60000 || // see line 375
+#endif
+ ucs >= first && ucs <= last)
+ glyphs->glyphs[glyph_pos] = ucs;
+ else
+ glyphs->glyphs[glyph_pos] = 0;
+ }
+ }
+ } else {
+#if defined(Q_WS_WINCE)
+ {
+#else
+ if (symbol) {
+ for (; i < numChars; ++i, ++glyph_pos) {
+ unsigned int uc = getChar(str, i, numChars);
+ glyphs->glyphs[i] = getTrueTypeGlyphIndex(cmap, uc);
+ if(!glyphs->glyphs[glyph_pos] && uc < 0x100)
+ glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, uc + 0xf000);
+ }
+ } else if (ttf) {
+ for (; i < numChars; ++i, ++glyph_pos) {
+ unsigned int uc = getChar(str, i, numChars);
+ glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, uc);
+ }
+ } else {
+#endif
+ wchar_t first = tm.tmFirstChar;
+ wchar_t last = tm.tmLastChar;
+
+ for (; i < numChars; ++i, ++glyph_pos) {
+ uint uc = getChar(str, i, numChars);
+ if (
+#ifdef Q_WS_WINCE
+ tm.tmFirstChar > 60000 || // see comment in QFontEngineWin
+#endif
+ uc >= first && uc <= last)
+ glyphs->glyphs[glyph_pos] = uc;
+ else
+ glyphs->glyphs[glyph_pos] = 0;
+ }
+ }
+ }
+ glyphs->numGlyphs = glyph_pos;
+ return glyph_pos;
+}
+
+
+QFontEngineWin::QFontEngineWin(const QString &name, HFONT _hfont, bool stockFont, LOGFONT lf)
+{
+ //qDebug("regular windows font engine created: font='%s', size=%d", name, lf.lfHeight);
+
+ _name = name;
+
+ cmap = 0;
+ hfont = _hfont;
+ logfont = lf;
+ HDC hdc = shared_dc();
+ SelectObject(hdc, hfont);
+ this->stockFont = stockFont;
+ fontDef.pixelSize = -lf.lfHeight;
+
+ lbearing = SHRT_MIN;
+ rbearing = SHRT_MIN;
+ synthesized_flags = -1;
+ lineWidth = -1;
+ x_height = -1;
+
+ BOOL res = GetTextMetrics(hdc, &tm);
+ fontDef.fixedPitch = !(tm.tmPitchAndFamily & TMPF_FIXED_PITCH);
+ if (!res) {
+ qErrnoWarning("QFontEngineWin: GetTextMetrics failed");
+ ZeroMemory(&tm, sizeof(TEXTMETRIC));
+ }
+
+ cache_cost = tm.tmHeight * tm.tmAveCharWidth * 2000;
+ getCMap();
+
+ widthCache = 0;
+ widthCacheSize = 0;
+ designAdvances = 0;
+ designAdvancesSize = 0;
+
+#ifndef Q_WS_WINCE
+ if (!resolvedGetCharWidthI)
+ resolveGetCharWidthI();
+#endif
+}
+
+QFontEngineWin::~QFontEngineWin()
+{
+ if (designAdvances)
+ free(designAdvances);
+
+ if (widthCache)
+ free(widthCache);
+
+ // make sure we aren't by accident still selected
+ SelectObject(shared_dc(), (HFONT)GetStockObject(SYSTEM_FONT));
+
+ if (!stockFont) {
+ if (!DeleteObject(hfont))
+ qErrnoWarning("QFontEngineWin: failed to delete non-stock font...");
+ }
+}
+
+HGDIOBJ QFontEngineWin::selectDesignFont() const
+{
+ LOGFONT f = logfont;
+ f.lfHeight = unitsPerEm;
+ HFONT designFont = CreateFontIndirect(&f);
+ return SelectObject(shared_dc(), designFont);
+}
+
+bool QFontEngineWin::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, QTextEngine::ShaperFlags flags) const
+{
+ if (*nglyphs < len) {
+ *nglyphs = len;
+ return false;
+ }
+
+ *nglyphs = getGlyphIndexes(str, len, glyphs, flags & QTextEngine::RightToLeft);
+
+ if (flags & QTextEngine::GlyphIndicesOnly)
+ return true;
+
+ recalcAdvances(glyphs, flags);
+ return true;
+}
+
+inline void calculateTTFGlyphWidth(HDC hdc, UINT glyph, int &width)
+{
+#if defined(Q_WS_WINCE)
+ GetCharWidth32(hdc, glyph, glyph, &width);
+#else
+ if (ptrGetCharWidthI)
+ ptrGetCharWidthI(hdc, glyph, 1, 0, &width);
+#endif
+}
+
+void QFontEngineWin::recalcAdvances(QGlyphLayout *glyphs, QTextEngine::ShaperFlags flags) const
+{
+ HGDIOBJ oldFont = 0;
+ HDC hdc = shared_dc();
+ if (ttf && (flags & QTextEngine::DesignMetrics)) {
+ for(int i = 0; i < glyphs->numGlyphs; i++) {
+ unsigned int glyph = glyphs->glyphs[i];
+ if(int(glyph) >= designAdvancesSize) {
+ int newSize = (glyph + 256) >> 8 << 8;
+ designAdvances = q_check_ptr((QFixed *)realloc(designAdvances,
+ newSize*sizeof(QFixed)));
+ for(int i = designAdvancesSize; i < newSize; ++i)
+ designAdvances[i] = -1000000;
+ designAdvancesSize = newSize;
+ }
+ if (designAdvances[glyph] < -999999) {
+ if (!oldFont)
+ oldFont = selectDesignFont();
+
+ int width = 0;
+ calculateTTFGlyphWidth(hdc, glyph, width);
+ designAdvances[glyph] = QFixed(width) / designToDevice;
+ }
+ glyphs->advances_x[i] = designAdvances[glyph];
+ glyphs->advances_y[i] = 0;
+ }
+ if(oldFont)
+ DeleteObject(SelectObject(hdc, oldFont));
+ } else {
+ for(int i = 0; i < glyphs->numGlyphs; i++) {
+ unsigned int glyph = glyphs->glyphs[i];
+
+ glyphs->advances_y[i] = 0;
+
+ if (glyph >= widthCacheSize) {
+ int newSize = (glyph + 256) >> 8 << 8;
+ widthCache = q_check_ptr((unsigned char *)realloc(widthCache,
+ newSize*sizeof(QFixed)));
+ memset(widthCache + widthCacheSize, 0, newSize - widthCacheSize);
+ widthCacheSize = newSize;
+ }
+ glyphs->advances_x[i] = widthCache[glyph];
+ // font-width cache failed
+ if (glyphs->advances_x[i] == 0) {
+ int width = 0;
+ if (!oldFont)
+ oldFont = SelectObject(hdc, hfont);
+
+ if (!ttf) {
+ QChar ch[2] = { ushort(glyph), 0 };
+ int chrLen = 1;
+ if (glyph > 0xffff) {
+ ch[0] = QChar::highSurrogate(glyph);
+ ch[1] = QChar::lowSurrogate(glyph);
+ ++chrLen;
+ }
+ SIZE size = {0, 0};
+ GetTextExtentPoint32(hdc, (wchar_t *)ch, chrLen, &size);
+ width = size.cx;
+ } else {
+ calculateTTFGlyphWidth(hdc, glyph, width);
+ }
+ glyphs->advances_x[i] = width;
+ // if glyph's within cache range, store it for later
+ if (width > 0 && width < 0x100)
+ widthCache[glyph] = width;
+ }
+ }
+
+ if (oldFont)
+ SelectObject(hdc, oldFont);
+ }
+}
+
+glyph_metrics_t QFontEngineWin::boundingBox(const QGlyphLayout &glyphs)
+{
+ if (glyphs.numGlyphs == 0)
+ return glyph_metrics_t();
+
+ QFixed w = 0;
+ for (int i = 0; i < glyphs.numGlyphs; ++i)
+ w += glyphs.effectiveAdvance(i);
+
+ return glyph_metrics_t(0, -tm.tmAscent, w - lastRightBearing(glyphs), tm.tmHeight, w, 0);
+}
+
+#ifndef Q_WS_WINCE
+bool QFontEngineWin::getOutlineMetrics(glyph_t glyph, const QTransform &t, glyph_metrics_t *metrics) const
+{
+ Q_ASSERT(metrics != 0);
+
+ HDC hdc = shared_dc();
+
+ GLYPHMETRICS gm;
+ DWORD res = 0;
+ MAT2 mat;
+ mat.eM11.value = mat.eM22.value = 1;
+ mat.eM11.fract = mat.eM22.fract = 0;
+ mat.eM21.value = mat.eM12.value = 0;
+ mat.eM21.fract = mat.eM12.fract = 0;
+
+ if (t.type() > QTransform::TxTranslate) {
+ // We need to set the transform using the HDC's world
+ // matrix rather than using the MAT2 above, because the
+ // results provided when transforming via MAT2 does not
+ // match the glyphs that are drawn using a WorldTransform
+ XFORM xform;
+ xform.eM11 = t.m11();
+ xform.eM12 = t.m12();
+ xform.eM21 = t.m21();
+ xform.eM22 = t.m22();
+ xform.eDx = 0;
+ xform.eDy = 0;
+ SetGraphicsMode(hdc, GM_ADVANCED);
+ SetWorldTransform(hdc, &xform);
+ }
+
+ uint format = GGO_METRICS;
+ if (ttf)
+ format |= GGO_GLYPH_INDEX;
+ res = GetGlyphOutline(hdc, glyph, format, &gm, 0, 0, &mat);
+
+ if (t.type() > QTransform::TxTranslate) {
+ XFORM xform;
+ xform.eM11 = xform.eM22 = 1;
+ xform.eM12 = xform.eM21 = xform.eDx = xform.eDy = 0;
+ SetWorldTransform(hdc, &xform);
+ SetGraphicsMode(hdc, GM_COMPATIBLE);
+ }
+
+ if (res != GDI_ERROR) {
+ *metrics = glyph_metrics_t(gm.gmptGlyphOrigin.x, -gm.gmptGlyphOrigin.y,
+ (int)gm.gmBlackBoxX, (int)gm.gmBlackBoxY, gm.gmCellIncX, gm.gmCellIncY);
+ return true;
+ } else {
+ return false;
+ }
+}
+#endif
+
+glyph_metrics_t QFontEngineWin::boundingBox(glyph_t glyph, const QTransform &t)
+{
+#ifndef Q_WS_WINCE
+ HDC hdc = shared_dc();
+ SelectObject(hdc, hfont);
+
+ glyph_metrics_t glyphMetrics;
+ bool success = getOutlineMetrics(glyph, t, &glyphMetrics);
+
+ if (!ttf && !success) {
+ // Bitmap fonts
+ wchar_t ch = glyph;
+ ABCFLOAT abc;
+ GetCharABCWidthsFloat(hdc, ch, ch, &abc);
+ int width = qRound(abc.abcfB);
+
+ return glyph_metrics_t(QFixed::fromReal(abc.abcfA), -tm.tmAscent, width, tm.tmHeight, width, 0).transformed(t);
+ }
+
+ return glyphMetrics;
+#else
+ HDC hdc = shared_dc();
+ HGDIOBJ oldFont = SelectObject(hdc, hfont);
+
+ ABC abc;
+ int width;
+ int advance;
+#ifdef GWES_MGTT // true type fonts
+ if (GetCharABCWidths(hdc, glyph, glyph, &abc)) {
+ width = qAbs(abc.abcA) + abc.abcB + qAbs(abc.abcC);
+ advance = abc.abcA + abc.abcB + abc.abcC;
+ }
+ else
+#endif
+#if defined(GWES_MGRAST) || defined(GWES_MGRAST2) // raster fonts
+ if (GetCharWidth32(hdc, glyph, glyph, &width)) {
+ advance = width;
+ }
+ else
+#endif
+ { // fallback
+ width = tm.tmMaxCharWidth;
+ advance = width;
+ }
+
+ SelectObject(hdc, oldFont);
+ return glyph_metrics_t(0, -tm.tmAscent, width, tm.tmHeight, advance, 0).transformed(t);
+#endif
+}
+
+QFixed QFontEngineWin::ascent() const
+{
+ return tm.tmAscent;
+}
+
+QFixed QFontEngineWin::descent() const
+{
+ // ### we substract 1 to even out the historical +1 in QFontMetrics's
+ // ### height=asc+desc+1 equation. Fix in Qt5.
+ return tm.tmDescent - 1;
+}
+
+QFixed QFontEngineWin::leading() const
+{
+ return tm.tmExternalLeading;
+}
+
+
+QFixed QFontEngineWin::xHeight() const
+{
+ if(x_height >= 0)
+ return x_height;
+ return QFontEngine::xHeight();
+}
+
+QFixed QFontEngineWin::averageCharWidth() const
+{
+ return tm.tmAveCharWidth;
+}
+
+qreal QFontEngineWin::maxCharWidth() const
+{
+ return tm.tmMaxCharWidth;
+}
+
+enum { max_font_count = 256 };
+static const ushort char_table[] = {
+ 40,
+ 67,
+ 70,
+ 75,
+ 86,
+ 88,
+ 89,
+ 91,
+ 102,
+ 114,
+ 124,
+ 127,
+ 205,
+ 645,
+ 884,
+ 922,
+ 1070,
+ 12386,
+ 0
+};
+
+static const int char_table_entries = sizeof(char_table)/sizeof(ushort);
+
+#ifndef Q_CC_MINGW
+void QFontEngineWin::getGlyphBearings(glyph_t glyph, qreal *leftBearing, qreal *rightBearing)
+{
+ HDC hdc = shared_dc();
+ SelectObject(hdc, hfont);
+
+#ifndef Q_WS_WINCE
+ if (ttf)
+#endif
+
+ {
+ ABC abcWidths;
+ GetCharABCWidthsI(hdc, glyph, 1, 0, &abcWidths);
+ if (leftBearing)
+ *leftBearing = abcWidths.abcA;
+ if (rightBearing)
+ *rightBearing = abcWidths.abcC;
+ }
+
+#ifndef Q_WS_WINCE
+ else {
+ QFontEngine::getGlyphBearings(glyph, leftBearing, rightBearing);
+ }
+#endif
+}
+#endif // Q_CC_MINGW
+
+qreal QFontEngineWin::minLeftBearing() const
+{
+ if (lbearing == SHRT_MIN)
+ minRightBearing(); // calculates both
+
+ return lbearing;
+}
+
+qreal QFontEngineWin::minRightBearing() const
+{
+#ifdef Q_WS_WINCE
+ if (rbearing == SHRT_MIN) {
+ int ml = 0;
+ int mr = 0;
+ HDC hdc = shared_dc();
+ SelectObject(hdc, hfont);
+ if (ttf) {
+ ABC *abc = 0;
+ int n = tm.tmLastChar - tm.tmFirstChar;
+ if (n <= max_font_count) {
+ abc = new ABC[n+1];
+ GetCharABCWidths(hdc, tm.tmFirstChar, tm.tmLastChar, abc);
+ } else {
+ abc = new ABC[char_table_entries+1];
+ for(int i = 0; i < char_table_entries; i++)
+ GetCharABCWidths(hdc, char_table[i], char_table[i], abc+i);
+ n = char_table_entries;
+ }
+ ml = abc[0].abcA;
+ mr = abc[0].abcC;
+ for (int i = 1; i < n; i++) {
+ if (abc[i].abcA + abc[i].abcB + abc[i].abcC != 0) {
+ ml = qMin(ml,abc[i].abcA);
+ mr = qMin(mr,abc[i].abcC);
+ }
+ }
+ delete [] abc;
+ }
+ lbearing = ml;
+ rbearing = mr;
+ }
+
+ return rbearing;
+#else
+ if (rbearing == SHRT_MIN) {
+ int ml = 0;
+ int mr = 0;
+ HDC hdc = shared_dc();
+ SelectObject(hdc, hfont);
+ if (ttf) {
+ ABC *abc = 0;
+ int n = tm.tmLastChar - tm.tmFirstChar;
+ if (n <= max_font_count) {
+ abc = new ABC[n+1];
+ GetCharABCWidths(hdc, tm.tmFirstChar, tm.tmLastChar, abc);
+ } else {
+ abc = new ABC[char_table_entries+1];
+ for(int i = 0; i < char_table_entries; i++)
+ GetCharABCWidths(hdc, char_table[i], char_table[i], abc + i);
+ n = char_table_entries;
+ }
+ ml = abc[0].abcA;
+ mr = abc[0].abcC;
+ for (int i = 1; i < n; i++) {
+ if (abc[i].abcA + abc[i].abcB + abc[i].abcC != 0) {
+ ml = qMin(ml,abc[i].abcA);
+ mr = qMin(mr,abc[i].abcC);
+ }
+ }
+ delete [] abc;
+ } else {
+ ABCFLOAT *abc = 0;
+ int n = tm.tmLastChar - tm.tmFirstChar+1;
+ if (n <= max_font_count) {
+ abc = new ABCFLOAT[n];
+ GetCharABCWidthsFloat(hdc, tm.tmFirstChar, tm.tmLastChar, abc);
+ } else {
+ abc = new ABCFLOAT[char_table_entries];
+ for(int i = 0; i < char_table_entries; i++)
+ GetCharABCWidthsFloat(hdc, char_table[i], char_table[i], abc+i);
+ n = char_table_entries;
+ }
+ float fml = abc[0].abcfA;
+ float fmr = abc[0].abcfC;
+ for (int i=1; i<n; i++) {
+ if (abc[i].abcfA + abc[i].abcfB + abc[i].abcfC != 0) {
+ fml = qMin(fml,abc[i].abcfA);
+ fmr = qMin(fmr,abc[i].abcfC);
+ }
+ }
+ ml = int(fml - 0.9999);
+ mr = int(fmr - 0.9999);
+ delete [] abc;
+ }
+ lbearing = ml;
+ rbearing = mr;
+ }
+
+ return rbearing;
+#endif
+}
+
+
+const char *QFontEngineWin::name() const
+{
+ return 0;
+}
+
+bool QFontEngineWin::canRender(const QChar *string, int len)
+{
+ if (symbol) {
+ for (int i = 0; i < len; ++i) {
+ unsigned int uc = getChar(string, i, len);
+ if (getTrueTypeGlyphIndex(cmap, uc) == 0) {
+ if (uc < 0x100) {
+ if (getTrueTypeGlyphIndex(cmap, uc + 0xf000) == 0)
+ return false;
+ } else {
+ return false;
+ }
+ }
+ }
+ } else if (ttf) {
+ for (int i = 0; i < len; ++i) {
+ unsigned int uc = getChar(string, i, len);
+ if (getTrueTypeGlyphIndex(cmap, uc) == 0)
+ return false;
+ }
+ } else {
+ while(len--) {
+ if (tm.tmFirstChar > string->unicode() || tm.tmLastChar < string->unicode())
+ return false;
+ }
+ }
+ return true;
+}
+
+QFontEngine::Type QFontEngineWin::type() const
+{
+ return QFontEngine::Win;
+}
+
+static inline double qt_fixed_to_double(const FIXED &p) {
+ return ((p.value << 16) + p.fract) / 65536.0;
+}
+
+static inline QPointF qt_to_qpointf(const POINTFX &pt, qreal scale) {
+ return QPointF(qt_fixed_to_double(pt.x) * scale, -qt_fixed_to_double(pt.y) * scale);
+}
+
+#ifndef GGO_UNHINTED
+#define GGO_UNHINTED 0x0100
+#endif
+
+static bool addGlyphToPath(glyph_t glyph, const QFixedPoint &position, HDC hdc,
+ QPainterPath *path, bool ttf, glyph_metrics_t *metric = 0, qreal scale = 1)
+{
+#if defined(Q_WS_WINCE)
+ Q_UNUSED(glyph);
+ Q_UNUSED(hdc);
+#endif
+ MAT2 mat;
+ mat.eM11.value = mat.eM22.value = 1;
+ mat.eM11.fract = mat.eM22.fract = 0;
+ mat.eM21.value = mat.eM12.value = 0;
+ mat.eM21.fract = mat.eM12.fract = 0;
+ uint glyphFormat = GGO_NATIVE;
+
+ if (ttf)
+ glyphFormat |= GGO_GLYPH_INDEX;
+
+ GLYPHMETRICS gMetric;
+ memset(&gMetric, 0, sizeof(GLYPHMETRICS));
+ int bufferSize = GDI_ERROR;
+#if !defined(Q_WS_WINCE)
+ bufferSize = GetGlyphOutline(hdc, glyph, glyphFormat, &gMetric, 0, 0, &mat);
+#endif
+ if ((DWORD)bufferSize == GDI_ERROR) {
+ return false;
+ }
+
+ void *dataBuffer = new char[bufferSize];
+ DWORD ret = GDI_ERROR;
+#if !defined(Q_WS_WINCE)
+ ret = GetGlyphOutline(hdc, glyph, glyphFormat, &gMetric, bufferSize, dataBuffer, &mat);
+#endif
+ if (ret == GDI_ERROR) {
+ delete [](char *)dataBuffer;
+ return false;
+ }
+
+ if(metric) {
+ // #### obey scale
+ *metric = glyph_metrics_t(gMetric.gmptGlyphOrigin.x, -gMetric.gmptGlyphOrigin.y,
+ (int)gMetric.gmBlackBoxX, (int)gMetric.gmBlackBoxY,
+ gMetric.gmCellIncX, gMetric.gmCellIncY);
+ }
+
+ int offset = 0;
+ int headerOffset = 0;
+ TTPOLYGONHEADER *ttph = 0;
+
+ QPointF oset = position.toPointF();
+ while (headerOffset < bufferSize) {
+ ttph = (TTPOLYGONHEADER*)((char *)dataBuffer + headerOffset);
+
+ QPointF lastPoint(qt_to_qpointf(ttph->pfxStart, scale));
+ path->moveTo(lastPoint + oset);
+ offset += sizeof(TTPOLYGONHEADER);
+ TTPOLYCURVE *curve;
+ while (offset<int(headerOffset + ttph->cb)) {
+ curve = (TTPOLYCURVE*)((char*)(dataBuffer) + offset);
+ switch (curve->wType) {
+ case TT_PRIM_LINE: {
+ for (int i=0; i<curve->cpfx; ++i) {
+ QPointF p = qt_to_qpointf(curve->apfx[i], scale) + oset;
+ path->lineTo(p);
+ }
+ break;
+ }
+ case TT_PRIM_QSPLINE: {
+ const QPainterPath::Element &elm = path->elementAt(path->elementCount()-1);
+ QPointF prev(elm.x, elm.y);
+ QPointF endPoint;
+ for (int i=0; i<curve->cpfx - 1; ++i) {
+ QPointF p1 = qt_to_qpointf(curve->apfx[i], scale) + oset;
+ QPointF p2 = qt_to_qpointf(curve->apfx[i+1], scale) + oset;
+ if (i < curve->cpfx - 2) {
+ endPoint = QPointF((p1.x() + p2.x()) / 2, (p1.y() + p2.y()) / 2);
+ } else {
+ endPoint = p2;
+ }
+
+ path->quadTo(p1, endPoint);
+ prev = endPoint;
+ }
+
+ break;
+ }
+ case TT_PRIM_CSPLINE: {
+ for (int i=0; i<curve->cpfx; ) {
+ QPointF p2 = qt_to_qpointf(curve->apfx[i++], scale) + oset;
+ QPointF p3 = qt_to_qpointf(curve->apfx[i++], scale) + oset;
+ QPointF p4 = qt_to_qpointf(curve->apfx[i++], scale) + oset;
+ path->cubicTo(p2, p3, p4);
+ }
+ break;
+ }
+ default:
+ qWarning("QFontEngineWin::addOutlineToPath, unhandled switch case");
+ }
+ offset += sizeof(TTPOLYCURVE) + (curve->cpfx-1) * sizeof(POINTFX);
+ }
+ path->closeSubpath();
+ headerOffset += ttph->cb;
+ }
+ delete [] (char*)dataBuffer;
+
+ return true;
+}
+
+void QFontEngineWin::addGlyphsToPath(glyph_t *glyphs, QFixedPoint *positions, int nglyphs,
+ QPainterPath *path, QTextItem::RenderFlags)
+{
+ LOGFONT lf = logfont;
+ // The sign must be negative here to make sure we match against character height instead of
+ // hinted cell height. This ensures that we get linear matching, and we need this for
+ // paths since we later on apply a scaling transform to the glyph outline to get the
+ // font at the correct pixel size.
+ lf.lfHeight = -unitsPerEm;
+ lf.lfWidth = 0;
+ HFONT hf = CreateFontIndirect(&lf);
+ HDC hdc = shared_dc();
+ HGDIOBJ oldfont = SelectObject(hdc, hf);
+
+ for(int i = 0; i < nglyphs; ++i) {
+ if (!addGlyphToPath(glyphs[i], positions[i], hdc, path, ttf, /*metric*/0,
+ qreal(fontDef.pixelSize) / unitsPerEm)) {
+ // Some windows fonts, like "Modern", are vector stroke
+ // fonts, which are reported as TMPF_VECTOR but do not
+ // support GetGlyphOutline, and thus we set this bit so
+ // that addOutLineToPath can check it and return safely...
+ hasOutline = false;
+ break;
+ }
+ }
+ DeleteObject(SelectObject(hdc, oldfont));
+}
+
+void QFontEngineWin::addOutlineToPath(qreal x, qreal y, const QGlyphLayout &glyphs,
+ QPainterPath *path, QTextItem::RenderFlags flags)
+{
+#if !defined(Q_WS_WINCE)
+ if(tm.tmPitchAndFamily & (TMPF_TRUETYPE | TMPF_VECTOR)) {
+ hasOutline = true;
+ QFontEngine::addOutlineToPath(x, y, glyphs, path, flags);
+ if (hasOutline) {
+ // has_outline is set to false if addGlyphToPath gets
+ // false from GetGlyphOutline, meaning its not an outline
+ // font.
+ return;
+ }
+ }
+#endif
+ QFontEngine::addBitmapFontToPath(x, y, glyphs, path, flags);
+}
+
+QFontEngine::FaceId QFontEngineWin::faceId() const
+{
+ return _faceId;
+}
+
+QT_BEGIN_INCLUDE_NAMESPACE
+#include <qdebug.h>
+QT_END_INCLUDE_NAMESPACE
+
+int QFontEngineWin::synthesized() const
+{
+ if(synthesized_flags == -1) {
+ synthesized_flags = 0;
+ if(ttf) {
+ const DWORD HEAD = MAKE_TAG('h', 'e', 'a', 'd');
+ HDC hdc = shared_dc();
+ SelectObject(hdc, hfont);
+ uchar data[4];
+ GetFontData(hdc, HEAD, 44, &data, 4);
+ USHORT macStyle = getUShort(data);
+ if (tm.tmItalic && !(macStyle & 2))
+ synthesized_flags = SynthesizedItalic;
+ if (fontDef.stretch != 100 && ttf)
+ synthesized_flags |= SynthesizedStretch;
+ if (tm.tmWeight >= 500 && !(macStyle & 1))
+ synthesized_flags |= SynthesizedBold;
+ //qDebug() << "font is" << _name <<
+ // "it=" << (macStyle & 2) << fontDef.style << "flags=" << synthesized_flags;
+ }
+ }
+ return synthesized_flags;
+}
+
+QFixed QFontEngineWin::emSquareSize() const
+{
+ return unitsPerEm;
+}
+
+QFontEngine::Properties QFontEngineWin::properties() const
+{
+ LOGFONT lf = logfont;
+ lf.lfHeight = unitsPerEm;
+ HFONT hf = CreateFontIndirect(&lf);
+ HDC hdc = shared_dc();
+ HGDIOBJ oldfont = SelectObject(hdc, hf);
+ OUTLINETEXTMETRIC *otm = getOutlineTextMetric(hdc);
+ Properties p;
+ p.emSquare = unitsPerEm;
+ p.italicAngle = otm->otmItalicAngle;
+ p.postscriptName = QString::fromWCharArray((wchar_t *)((char *)otm + (quintptr)otm->otmpFamilyName)).toLatin1();
+ p.postscriptName += QString::fromWCharArray((wchar_t *)((char *)otm + (quintptr)otm->otmpStyleName)).toLatin1();
+ p.postscriptName = QFontEngine::convertToPostscriptFontFamilyName(p.postscriptName);
+ p.boundingBox = QRectF(otm->otmrcFontBox.left, -otm->otmrcFontBox.top,
+ otm->otmrcFontBox.right - otm->otmrcFontBox.left,
+ otm->otmrcFontBox.top - otm->otmrcFontBox.bottom);
+ p.ascent = otm->otmAscent;
+ p.descent = -otm->otmDescent;
+ p.leading = (int)otm->otmLineGap;
+ p.capHeight = 0;
+ p.lineWidth = otm->otmsUnderscoreSize;
+ free(otm);
+ DeleteObject(SelectObject(hdc, oldfont));
+ return p;
+}
+
+void QFontEngineWin::getUnscaledGlyph(glyph_t glyph, QPainterPath *path, glyph_metrics_t *metrics)
+{
+ LOGFONT lf = logfont;
+ lf.lfHeight = unitsPerEm;
+ int flags = synthesized();
+ if(flags & SynthesizedItalic)
+ lf.lfItalic = false;
+ lf.lfWidth = 0;
+ HFONT hf = CreateFontIndirect(&lf);
+ HDC hdc = shared_dc();
+ HGDIOBJ oldfont = SelectObject(hdc, hf);
+ QFixedPoint p;
+ p.x = 0;
+ p.y = 0;
+ addGlyphToPath(glyph, p, hdc, path, ttf, metrics);
+ DeleteObject(SelectObject(hdc, oldfont));
+}
+
+bool QFontEngineWin::getSfntTableData(uint tag, uchar *buffer, uint *length) const
+{
+ if (!ttf)
+ return false;
+ HDC hdc = shared_dc();
+ SelectObject(hdc, hfont);
+ DWORD t = qbswap<quint32>(tag);
+ *length = GetFontData(hdc, t, 0, buffer, *length);
+ return *length != GDI_ERROR;
+}
+
+#if !defined(CLEARTYPE_QUALITY)
+# define CLEARTYPE_QUALITY 5
+#endif
+
+extern bool qt_cleartype_enabled;
+
+QNativeImage *QFontEngineWin::drawGDIGlyph(HFONT font, glyph_t glyph, int margin,
+ const QTransform &t, QImage::Format mask_format)
+{
+ Q_UNUSED(mask_format)
+ glyph_metrics_t gm = boundingBox(glyph);
+
+// printf(" -> for glyph %4x\n", glyph);
+
+ int gx = gm.x.toInt();
+ int gy = gm.y.toInt();
+ int iw = gm.width.toInt();
+ int ih = gm.height.toInt();
+
+ if (iw <= 0 || iw <= 0)
+ return 0;
+
+ bool has_transformation = t.type() > QTransform::TxTranslate;
+
+#ifndef Q_WS_WINCE
+ unsigned int options = ttf ? ETO_GLYPH_INDEX : 0;
+ XFORM xform;
+
+ if (has_transformation) {
+ xform.eM11 = t.m11();
+ xform.eM12 = t.m12();
+ xform.eM21 = t.m21();
+ xform.eM22 = t.m22();
+ xform.eDx = margin;
+ xform.eDy = margin;
+
+ QtHDC qthdc;
+ HDC hdc = qthdc.hdc();
+
+ SetGraphicsMode(hdc, GM_ADVANCED);
+ SetWorldTransform(hdc, &xform);
+ HGDIOBJ old_font = SelectObject(hdc, font);
+
+ int ggo_options = GGO_METRICS | (ttf ? GGO_GLYPH_INDEX : 0);
+ GLYPHMETRICS tgm;
+ MAT2 mat;
+ memset(&mat, 0, sizeof(mat));
+ mat.eM11.value = mat.eM22.value = 1;
+
+ if (GetGlyphOutline(hdc, glyph, ggo_options, &tgm, 0, 0, &mat) == GDI_ERROR) {
+ qWarning("QWinFontEngine: unable to query transformed glyph metrics...");
+ return 0;
+ }
+
+ iw = tgm.gmBlackBoxX;
+ ih = tgm.gmBlackBoxY;
+
+ xform.eDx -= tgm.gmptGlyphOrigin.x;
+ xform.eDy += tgm.gmptGlyphOrigin.y;
+
+ SetGraphicsMode(hdc, GM_COMPATIBLE);
+ SelectObject(hdc, old_font);
+ }
+#else // else winc
+ unsigned int options = 0;
+#ifdef DEBUG
+ Q_ASSERT(!has_transformation);
+#else
+ Q_UNUSED(has_transformation);
+#endif
+#endif
+
+ QNativeImage *ni = new QNativeImage(iw + 2 * margin + 4,
+ ih + 2 * margin + 4,
+ QNativeImage::systemFormat(), !qt_cleartype_enabled);
+
+ /*If cleartype is enabled we use the standard system format even on Windows CE
+ and not the special textbuffer format we have to use if cleartype is disabled*/
+
+ ni->image.fill(0xffffffff);
+
+ HDC hdc = ni->hdc;
+
+ SelectObject(hdc, GetStockObject(NULL_BRUSH));
+ SelectObject(hdc, GetStockObject(BLACK_PEN));
+ SetTextColor(hdc, RGB(0,0,0));
+ SetBkMode(hdc, TRANSPARENT);
+ SetTextAlign(hdc, TA_BASELINE);
+
+ HGDIOBJ old_font = SelectObject(hdc, font);
+
+#ifndef Q_OS_WINCE
+ if (has_transformation) {
+ SetGraphicsMode(hdc, GM_ADVANCED);
+ SetWorldTransform(hdc, &xform);
+ ExtTextOut(hdc, 0, 0, options, 0, (LPCWSTR) &glyph, 1, 0);
+ } else
+#endif
+ {
+ ExtTextOut(hdc, -gx + margin, -gy + margin, options, 0, (LPCWSTR) &glyph, 1, 0);
+ }
+
+ SelectObject(hdc, old_font);
+ return ni;
+}
+
+
+extern uint qt_pow_gamma[256];
+
+QImage QFontEngineWin::alphaMapForGlyph(glyph_t glyph, const QTransform &xform)
+{
+ HFONT font = hfont;
+ if (qt_cleartype_enabled) {
+ LOGFONT lf = logfont;
+ lf.lfQuality = ANTIALIASED_QUALITY;
+ font = CreateFontIndirect(&lf);
+ }
+ QImage::Format mask_format = QNativeImage::systemFormat();
+#ifndef Q_OS_WINCE
+ mask_format = QImage::Format_RGB32;
+#endif
+
+ QNativeImage *mask = drawGDIGlyph(font, glyph, 0, xform, mask_format);
+ if (mask == 0)
+ return QImage();
+
+ QImage indexed(mask->width(), mask->height(), QImage::Format_Indexed8);
+
+ // ### This part is kinda pointless, but we'll crash later if we don't because some
+ // code paths expects there to be colortables for index8-bit...
+ QVector<QRgb> colors(256);
+ for (int i=0; i<256; ++i)
+ colors[i] = qRgba(0, 0, 0, i);
+ indexed.setColorTable(colors);
+
+ // Copy data... Cannot use QPainter here as GDI has messed up the
+ // Alpha channel of the ni.image pixels...
+ for (int y=0; y<mask->height(); ++y) {
+ uchar *dest = indexed.scanLine(y);
+ if (mask->image.format() == QImage::Format_RGB16) {
+ const qint16 *src = (qint16 *) ((const QImage &) mask->image).scanLine(y);
+ for (int x=0; x<mask->width(); ++x)
+ dest[x] = 255 - qGray(src[x]);
+ } else {
+ const uint *src = (uint *) ((const QImage &) mask->image).scanLine(y);
+ for (int x=0; x<mask->width(); ++x) {
+#ifdef Q_OS_WINCE
+ dest[x] = 255 - qGray(src[x]);
+#else
+ if (QNativeImage::systemFormat() == QImage::Format_RGB16)
+ dest[x] = 255 - qGray(src[x]);
+ else
+ dest[x] = 255 - (qt_pow_gamma[qGray(src[x])] * 255. / 2047.);
+#endif
+ }
+ }
+ }
+
+ // Cleanup...
+ delete mask;
+ if (qt_cleartype_enabled) {
+ DeleteObject(font);
+ }
+
+ return indexed;
+}
+
+#define SPI_GETFONTSMOOTHINGCONTRAST 0x200C
+#define SPI_SETFONTSMOOTHINGCONTRAST 0x200D
+
+QImage QFontEngineWin::alphaRGBMapForGlyph(glyph_t glyph, QFixed, int margin, const QTransform &t)
+{
+ HFONT font = hfont;
+
+ int contrast;
+ SystemParametersInfo(SPI_GETFONTSMOOTHINGCONTRAST, 0, &contrast, 0);
+ SystemParametersInfo(SPI_SETFONTSMOOTHINGCONTRAST, 0, (void *) 1000, 0);
+
+ QNativeImage *mask = drawGDIGlyph(font, glyph, margin, t, QImage::Format_RGB32);
+ SystemParametersInfo(SPI_SETFONTSMOOTHINGCONTRAST, 0, (void *) contrast, 0);
+
+ if (mask == 0)
+ return QImage();
+
+ // Gracefully handle the odd case when the display is 16-bit
+ const QImage source = mask->image.depth() == 32
+ ? mask->image
+ : mask->image.convertToFormat(QImage::Format_RGB32);
+
+ QImage rgbMask(mask->width(), mask->height(), QImage::Format_RGB32);
+ for (int y=0; y<mask->height(); ++y) {
+ uint *dest = (uint *) rgbMask.scanLine(y);
+ const uint *src = (uint *) source.scanLine(y);
+ for (int x=0; x<mask->width(); ++x) {
+ dest[x] = 0xffffffff - (0x00ffffff & src[x]);
+ }
+ }
+
+ delete mask;
+
+ return rgbMask;
+}
+
+// From qfontdatabase_win.cpp
+extern QFontEngine *qt_load_font_engine_win(const QFontDef &request);
+QFontEngine *QFontEngineWin::cloneWithSize(qreal pixelSize) const
+{
+ QFontDef request = fontDef;
+ QString actualFontName = request.family;
+ if (!uniqueFamilyName.isEmpty())
+ request.family = uniqueFamilyName;
+ request.pixelSize = pixelSize;
+
+ QFontEngine *fontEngine = qt_load_font_engine_win(request);
+ if (fontEngine != NULL)
+ fontEngine->fontDef.family = actualFontName;
+
+ return fontEngine;
+}
+
+// -------------------------------------- Multi font engine
+
+QFontEngineMultiWin::QFontEngineMultiWin(QFontEngine *first, const QStringList &fallbacks)
+ : QFontEngineMulti(fallbacks.size()+1),
+ fallbacks(fallbacks)
+{
+ engines[0] = first;
+ first->ref.ref();
+ fontDef = engines[0]->fontDef;
+ cache_cost = first->cache_cost;
+}
+
+void QFontEngineMultiWin::loadEngine(int at)
+{
+ Q_ASSERT(at < engines.size());
+ Q_ASSERT(engines.at(at) == 0);
+
+ QString fam = fallbacks.at(at-1);
+
+ LOGFONT lf = static_cast<QFontEngineWin *>(engines.at(0))->logfont;
+ memcpy(lf.lfFaceName, fam.utf16(), sizeof(wchar_t) * qMin(fam.length() + 1, 32)); // 32 = Windows hard-coded
+ HFONT hfont = CreateFontIndirect(&lf);
+
+ bool stockFont = false;
+ if (hfont == 0) {
+ hfont = (HFONT)GetStockObject(ANSI_VAR_FONT);
+ stockFont = true;
+ }
+ engines[at] = new QFontEngineWin(fam, hfont, stockFont, lf);
+ engines[at]->ref.ref();
+ engines[at]->fontDef = fontDef;
+
+ // TODO: increase cost in QFontCache for the font engine loaded here
+}
+
+QT_END_NAMESPACE
diff --git a/src/gui/platforms/win/qfontengine_win_p.h b/src/gui/platforms/win/qfontengine_win_p.h
new file mode 100644
index 0000000000..114149d61f
--- /dev/null
+++ b/src/gui/platforms/win/qfontengine_win_p.h
@@ -0,0 +1,164 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QFONTENGINE_WIN_P_H
+#define QFONTENGINE_WIN_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/qconfig.h>
+
+QT_BEGIN_NAMESPACE
+
+class QNativeImage;
+
+class QFontEngineWin : public QFontEngine
+{
+public:
+ QFontEngineWin(const QString &name, HFONT, bool, LOGFONT);
+ ~QFontEngineWin();
+
+ virtual QFixed lineThickness() const;
+ virtual Properties properties() const;
+ virtual void getUnscaledGlyph(glyph_t glyph, QPainterPath *path, glyph_metrics_t *metrics);
+ virtual FaceId faceId() const;
+ virtual bool getSfntTableData(uint tag, uchar *buffer, uint *length) const;
+ virtual int synthesized() const;
+ virtual QFixed emSquareSize() const;
+
+ virtual bool stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, QTextEngine::ShaperFlags flags) const;
+ virtual void recalcAdvances(QGlyphLayout *glyphs, QTextEngine::ShaperFlags) const;
+
+ virtual void addOutlineToPath(qreal x, qreal y, const QGlyphLayout &glyphs, QPainterPath *path, QTextItem::RenderFlags flags);
+ virtual void addGlyphsToPath(glyph_t *glyphs, QFixedPoint *positions, int nglyphs,
+ QPainterPath *path, QTextItem::RenderFlags flags);
+
+ HGDIOBJ selectDesignFont() const;
+
+ virtual glyph_metrics_t boundingBox(const QGlyphLayout &glyphs);
+ virtual glyph_metrics_t boundingBox(glyph_t g) { return boundingBox(g, QTransform()); }
+ virtual glyph_metrics_t boundingBox(glyph_t g, const QTransform &t);
+
+
+ virtual QFixed ascent() const;
+ virtual QFixed descent() const;
+ virtual QFixed leading() const;
+ virtual QFixed xHeight() const;
+ virtual QFixed averageCharWidth() const;
+ virtual qreal maxCharWidth() const;
+ virtual qreal minLeftBearing() const;
+ virtual qreal minRightBearing() const;
+
+ virtual const char *name() const;
+
+ bool canRender(const QChar *string, int len);
+
+ Type type() const;
+
+ virtual QImage alphaMapForGlyph(glyph_t t) { return alphaMapForGlyph(t, QTransform()); }
+ virtual QImage alphaMapForGlyph(glyph_t, const QTransform &xform);
+ virtual QImage alphaRGBMapForGlyph(glyph_t t, QFixed subPixelPosition, int margin, const QTransform &xform);
+
+ virtual QFontEngine *cloneWithSize(qreal pixelSize) const;
+
+#ifndef Q_CC_MINGW
+ virtual void getGlyphBearings(glyph_t glyph, qreal *leftBearing = 0, qreal *rightBearing = 0);
+#endif
+
+ int getGlyphIndexes(const QChar *ch, int numChars, QGlyphLayout *glyphs, bool mirrored) const;
+ void getCMap();
+
+#ifndef Q_WS_WINCE
+ bool getOutlineMetrics(glyph_t glyph, const QTransform &t, glyph_metrics_t *metrics) const;
+#endif
+
+ QString _name;
+ QString uniqueFamilyName;
+ HFONT hfont;
+ LOGFONT logfont;
+ uint stockFont : 1;
+ uint ttf : 1;
+ uint hasOutline : 1;
+ TEXTMETRIC tm;
+ int lw;
+ const unsigned char *cmap;
+ QByteArray cmapTable;
+ mutable qreal lbearing;
+ mutable qreal rbearing;
+ QFixed designToDevice;
+ int unitsPerEm;
+ QFixed x_height;
+ FaceId _faceId;
+
+ mutable int synthesized_flags;
+ mutable QFixed lineWidth;
+ mutable unsigned char *widthCache;
+ mutable uint widthCacheSize;
+ mutable QFixed *designAdvances;
+ mutable int designAdvancesSize;
+
+private:
+ QNativeImage *drawGDIGlyph(HFONT font, glyph_t, int margin, const QTransform &xform,
+ QImage::Format mask_format);
+
+};
+
+class QFontEngineMultiWin : public QFontEngineMulti
+{
+public:
+ QFontEngineMultiWin(QFontEngine *first, const QStringList &fallbacks);
+ void loadEngine(int at);
+
+ QStringList fallbacks;
+};
+
+QT_END_NAMESPACE
+
+#endif // QFONTENGINE_WIN_P_H
diff --git a/src/gui/platforms/win/qguifunctions_wince.cpp b/src/gui/platforms/win/qguifunctions_wince.cpp
new file mode 100644
index 0000000000..bb4ed11589
--- /dev/null
+++ b/src/gui/platforms/win/qguifunctions_wince.cpp
@@ -0,0 +1,408 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include "qguifunctions_wince.h"
+#include <shellapi.h>
+#include <QtCore/qlibrary.h>
+
+QT_USE_NAMESPACE
+
+struct AygSHINITDLGINFO
+{
+ DWORD dwMask;
+ HWND hDlg;
+ DWORD dwFlags;
+};
+
+struct AygSIPINFO
+{
+ DWORD cbSize;
+ DWORD fdwFlags;
+ RECT rcVisibleDesktop;
+ RECT rcSipRect;
+ DWORD dwImDataSize;
+ void *pvImData;
+};
+
+#ifndef SHIDIF_CANCELBUTTON
+#define SHIDIF_CANCELBUTTON 0x0080
+#endif
+
+#ifndef SHIDIM_FLAGS
+#define SHIDIM_FLAGS 0x0001
+#endif
+
+#ifndef SHIDIF_DONEBUTTON
+#define SHIDIF_DONEBUTTON 0x0001
+#endif
+#ifndef SHIDIF_SIZEDLGFULLSCREEN
+#define SHIDIF_SIZEDLGFULLSCREEN 0x0004
+#endif
+
+#ifndef SHDB_HIDE
+#define SHDB_HIDE 0x0002
+#endif
+
+#ifndef SHFS_SHOWTASKBAR
+#define SHFS_SHOWTASKBAR 0x0001
+#endif
+#ifndef SHFS_HIDETASKBAR
+#define SHFS_HIDETASKBAR 0x0002
+#endif
+#ifndef SHFS_SHOWSIPBUTTON
+#define SHFS_SHOWSIPBUTTON 0x0004
+#endif
+#ifndef SHFS_HIDESIPBUTTON
+#define SHFS_HIDESIPBUTTON 0x0008
+#endif
+#ifndef SHFS_SHOWSTARTICON
+#define SHFS_SHOWSTARTICON 0x0010
+#endif
+#ifndef SHFS_HIDESTARTICON
+#define SHFS_HIDESTARTICON 0x0020
+#endif
+
+#ifndef SIPF_OFF
+#define SIPF_OFF 0x00000000
+#endif
+#ifndef SIPF_ON
+#define SIPF_ON 0x00000001
+#endif
+
+#ifndef SPI_SETSIPINFO
+#define SPI_SETSIPINFO 224
+#endif
+#ifndef SPI_GETSIPINFO
+#define SPI_GETSIPINFO 225
+#endif
+#ifndef SPI_GETPLATFORMTYPE
+#define SPI_GETPLATFORMTYPE 257
+#endif
+
+typedef BOOL (*AygInitDialog)(AygSHINITDLGINFO*);
+typedef BOOL (*AygFullScreen)(HWND, DWORD);
+typedef BOOL (*AygSHSipInfo)(UINT, UINT, PVOID, UINT);
+typedef BOOL (*AygSHDoneButton)(HWND, DWORD);
+
+static AygInitDialog ptrAygInitDialog = 0;
+static AygFullScreen ptrAygFullScreen = 0;
+static AygSHSipInfo ptrAygSHSipInfo = 0;
+static AygSHDoneButton ptrAygSHDoneButton = 0;
+static bool aygResolved = false;
+
+static void resolveAygLibs()
+{
+ if (!aygResolved) {
+ aygResolved = true;
+ QLibrary ayglib(QLatin1String("aygshell"));
+ ptrAygInitDialog = (AygInitDialog) ayglib.resolve("SHInitDialog");
+ ptrAygFullScreen = (AygFullScreen) ayglib.resolve("SHFullScreen");
+ ptrAygSHSipInfo = (AygSHSipInfo) ayglib.resolve("SHSipInfo");
+ ptrAygSHDoneButton = (AygSHDoneButton) ayglib.resolve("SHDoneButton");
+ }
+}
+
+int qt_wince_GetDIBits(HDC /*hdc*/ , HBITMAP hSourceBitmap, uint, uint, LPVOID lpvBits, LPBITMAPINFO, uint)
+{
+ if (!lpvBits) {
+ qWarning("::GetDIBits(), lpvBits NULL");
+ return 0;
+ }
+ BITMAP bm;
+ GetObject(hSourceBitmap, sizeof(BITMAP), &bm);
+ bm.bmHeight = qAbs(bm.bmHeight);
+
+ HBITMAP hTargetBitmap;
+ void *pixels;
+
+ BITMAPINFO dibInfo;
+ memset(&dibInfo, 0, sizeof(dibInfo));
+ dibInfo.bmiHeader.biBitCount = 32;
+ dibInfo.bmiHeader.biClrImportant = 0;
+ dibInfo.bmiHeader.biClrUsed = 0;
+ dibInfo.bmiHeader.biCompression = BI_RGB;;
+ dibInfo.bmiHeader.biHeight = -bm.bmHeight;
+ dibInfo.bmiHeader.biWidth = bm.bmWidth;
+ dibInfo.bmiHeader.biPlanes = 1;
+ dibInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
+ dibInfo.bmiHeader.biSizeImage = bm.bmWidth * bm.bmHeight * 4;
+
+ HDC displayDC = GetDC(NULL);
+ if (!displayDC) {
+ qWarning("::GetDIBits(), failed to GetDC");
+ return 0;
+ }
+
+ int ret = bm.bmHeight;
+
+ hTargetBitmap = CreateDIBSection(displayDC, (const BITMAPINFO*) &dibInfo, DIB_RGB_COLORS,
+ (void**)&pixels, NULL, 0);
+ if (!hTargetBitmap) {
+ qWarning("::GetDIBits(), failed to CreateDIBSection");
+ return 0;
+ }
+
+ HDC hdcSrc = CreateCompatibleDC(displayDC);
+ HDC hdcDst = CreateCompatibleDC(displayDC);
+
+ if (!(hdcDst && hdcSrc)) {
+ qWarning("::GetDIBits(), failed to CreateCompatibleDC");
+ ret = 0;
+ }
+
+ HBITMAP hOldBitmap1 = (HBITMAP) SelectObject(hdcSrc, hSourceBitmap);
+ HBITMAP hOldBitmap2 = (HBITMAP) SelectObject(hdcDst, hTargetBitmap);
+
+ if (!(hOldBitmap1 && hOldBitmap2)) {
+ qWarning("::GetDIBits(), failed to SelectObject for bitmaps");
+ ret = 0;
+ }
+
+ if (!BitBlt(hdcDst, 0, 0, bm.bmWidth, bm.bmHeight, hdcSrc, 0, 0, SRCCOPY)) {
+ qWarning("::GetDIBits(), BitBlt failed");
+ ret = 0;
+ }
+
+ SelectObject(hdcSrc, hOldBitmap1);
+ SelectObject(hdcDst, hOldBitmap2);
+
+ DeleteDC(hdcSrc);
+ DeleteDC(hdcDst);
+
+ ReleaseDC(NULL, displayDC);
+
+ memcpy(lpvBits, pixels, dibInfo.bmiHeader.biSizeImage);
+
+ DeleteObject(hTargetBitmap);
+ return ret;
+}
+
+HINSTANCE qt_wince_ShellExecute(HWND hwnd, LPCWSTR, LPCWSTR file, LPCWSTR params, LPCWSTR dir, int showCmd)
+{
+ SHELLEXECUTEINFO info;
+ info.hwnd = hwnd;
+ info.lpVerb = L"Open";
+ info.lpFile = file;
+ info.lpParameters = params;
+ info.lpDirectory = dir;
+ info.nShow = showCmd;
+ info.cbSize = sizeof(info);
+ ShellExecuteEx(&info);
+ return info.hInstApp;
+}
+
+// Clipboard --------------------------------------------------------
+BOOL qt_wince_ChangeClipboardChain( HWND /*hWndRemove*/, HWND /*hWndNewNext*/ )
+{
+ return FALSE;
+}
+
+HWND qt_wince_SetClipboardViewer( HWND /*hWndNewViewer*/ )
+{
+ return NULL;
+}
+
+
+// Graphics ---------------------------------------------------------
+COLORREF qt_wince_PALETTEINDEX( WORD /*wPaletteIndex*/)
+{
+ return 0;
+}
+
+// Internal Qt -----------------------------------------------------
+bool qt_wince_is_platform(const QString &platformString) {
+ wchar_t tszPlatform[64];
+ if (SystemParametersInfo(SPI_GETPLATFORMTYPE, sizeof(tszPlatform) / sizeof(wchar_t), tszPlatform, 0))
+ if (0 == _tcsicmp(reinterpret_cast<const wchar_t *> (platformString.utf16()), tszPlatform))
+ return true;
+ return false;
+}
+
+int qt_wince_get_build()
+{
+ OSVERSIONINFO osvi;
+ osvi.dwOSVersionInfoSize = sizeof(osvi);
+ if (GetVersionEx(&osvi)) {
+ return osvi.dwBuildNumber;
+ }
+ return 0;
+}
+
+int qt_wince_get_version()
+{
+ OSVERSIONINFO osvi;
+ osvi.dwOSVersionInfoSize = sizeof(osvi);
+ if (GetVersionEx(&osvi)) {
+ return (osvi.dwMajorVersion * 10 + osvi.dwMinorVersion);
+ }
+ return 0;
+}
+
+bool qt_wince_is_windows_mobile_65()
+{
+ const DWORD dwFirstWM65BuildNumber = 21139;
+ OSVERSIONINFO osvi;
+ osvi.dwOSVersionInfoSize = sizeof(osvi);
+ if (!GetVersionEx(&osvi))
+ return false;
+ return osvi.dwMajorVersion > 5
+ || (osvi.dwMajorVersion == 5 && (osvi.dwMinorVersion > 2 ||
+ (osvi.dwMinorVersion == 2 && osvi.dwBuildNumber >= dwFirstWM65BuildNumber)));
+}
+
+bool qt_wince_is_pocket_pc() {
+ return qt_wince_is_platform(QString::fromLatin1("PocketPC"));
+}
+
+bool qt_wince_is_smartphone() {
+ return qt_wince_is_platform(QString::fromLatin1("Smartphone"));
+}
+bool qt_wince_is_mobile() {
+ return (qt_wince_is_smartphone() || qt_wince_is_pocket_pc());
+}
+
+bool qt_wince_is_high_dpi() {
+ if (!qt_wince_is_pocket_pc())
+ return false;
+ HDC deviceContext = GetDC(0);
+ int dpi = GetDeviceCaps(deviceContext, LOGPIXELSX);
+ ReleaseDC(0, deviceContext);
+ if ((dpi < 1000) && (dpi > 0))
+ return dpi > 96;
+ else
+ return false;
+}
+
+void qt_wince_maximize(QWidget *widget)
+{
+ HWND hwnd = widget->winId();
+ if (qt_wince_is_mobile()) {
+ AygSHINITDLGINFO shidi;
+ shidi.dwMask = SHIDIM_FLAGS;
+ shidi.hDlg = hwnd;
+ shidi.dwFlags = SHIDIF_SIZEDLGFULLSCREEN;
+ if (widget->windowFlags() & Qt::WindowCancelButtonHint)
+ shidi.dwFlags |= SHIDIF_CANCELBUTTON;
+ if (widget->windowFlags() & Qt::WindowOkButtonHint)
+ shidi.dwFlags |= SHIDIF_DONEBUTTON;
+ if (!(widget->windowFlags() & (Qt::WindowCancelButtonHint | Qt::WindowOkButtonHint)))
+ shidi.dwFlags |= SHIDIF_CANCELBUTTON;
+ resolveAygLibs();
+ if (ptrAygInitDialog)
+ ptrAygInitDialog(&shidi);
+ } else {
+ RECT r;
+ SystemParametersInfo(SPI_GETWORKAREA, 0, &r, 0);
+ MoveWindow(hwnd, r.top, r.left, r.right - r.left, r.bottom - r.top, true);
+ SetWindowLong(hwnd, GWL_EXSTYLE, GetWindowLong (hwnd, GWL_EXSTYLE) | WS_EX_NODRAG);
+ }
+}
+
+void qt_wince_unmaximize(QWidget *widget)
+{
+ if (ptrAygSHDoneButton && qt_wince_is_mobile()
+ && !(widget->windowFlags() & (Qt::WindowCancelButtonHint | Qt::WindowOkButtonHint)))
+ {
+ // Hide the [X] button, we've added in qt_wince_maximize.
+ ptrAygSHDoneButton(widget->winId(), SHDB_HIDE);
+ }
+}
+
+void qt_wince_minimize(HWND hwnd)
+{
+#ifdef Q_OS_WINCE_WM
+ ShowWindow(hwnd, SW_HIDE);
+#else
+ if (!IsWindowVisible(hwnd)) {
+ // Hack for an initial showMinimized.
+ // Without it, our widget doesn't appear in the task bar.
+ ShowWindow(hwnd, SW_SHOW);
+ }
+ ShowWindow(hwnd, SW_MINIMIZE);
+#endif
+}
+
+void qt_wince_hide_taskbar(HWND hwnd) {
+ if (ptrAygFullScreen)
+ ptrAygFullScreen(hwnd, SHFS_HIDETASKBAR | SHFS_HIDESIPBUTTON | SHFS_HIDESTARTICON);
+}
+
+void qt_wince_full_screen(HWND hwnd, bool fullScreen, UINT swpf) {
+ resolveAygLibs();
+ if (fullScreen) {
+ QRect r = qApp->desktop()->screenGeometry(QWidget::find(hwnd));
+ SetWindowPos(hwnd, HWND_TOP, r.left(), r.top(), r.width(), r.height(), swpf);
+ if (ptrAygFullScreen)
+ ptrAygFullScreen(hwnd, SHFS_HIDETASKBAR | SHFS_HIDESIPBUTTON | SHFS_HIDESTARTICON);
+ if (!qt_wince_is_mobile()) {
+ HWND handle = FindWindow(L"HHTaskBar", L"");
+ if (handle) {
+ ShowWindow(handle, 0);
+ EnableWindow(handle, false);
+ }
+ }
+ } else {
+ if (ptrAygFullScreen)
+ ptrAygFullScreen(hwnd, SHFS_SHOWTASKBAR | SHFS_SHOWSIPBUTTON | SHFS_SHOWSTARTICON);
+ SetWindowPos(hwnd, 0, 0, 0, 0, 0, swpf);
+ if (!qt_wince_is_mobile()) {
+ HWND handle = FindWindow(L"HHTaskBar", L"");
+ if (handle) {
+ ShowWindow(handle, 1);
+ EnableWindow(handle, true);
+ }
+ }
+ }
+}
+
+void qt_wince_show_SIP(bool show)
+{
+ resolveAygLibs();
+ if (!ptrAygSHSipInfo)
+ return;
+
+ AygSIPINFO si;
+ memset(&si, 0, sizeof(si));
+ si.cbSize = sizeof(si);
+ ptrAygSHSipInfo(SPI_GETSIPINFO, 0, &si, 0);
+ si.cbSize = sizeof(si);
+ si.fdwFlags = (show ? SIPF_ON : SIPF_OFF);
+ ptrAygSHSipInfo(SPI_SETSIPINFO, 0, &si, 0);
+}
diff --git a/src/gui/platforms/win/qguifunctions_wince.h b/src/gui/platforms/win/qguifunctions_wince.h
new file mode 100644
index 0000000000..2e14de0693
--- /dev/null
+++ b/src/gui/platforms/win/qguifunctions_wince.h
@@ -0,0 +1,151 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#ifndef QGUIFUNCTIONS_WCE_H
+#define QGUIFUNCTIONS_WCE_H
+#ifdef Q_OS_WINCE
+#include <QtCore/qfunctions_wince.h>
+#define UNDER_NT
+#include <wingdi.h>
+
+#ifdef QT_BUILD_GUI_LIB
+QT_BEGIN_HEADER
+QT_BEGIN_NAMESPACE
+QT_MODULE(Gui)
+QT_END_NAMESPACE
+QT_END_HEADER
+#endif
+
+// application defines
+#define SPI_SETNONCLIENTMETRICS 72
+#define SPI_SETICONTITLELOGFONT 0x0022
+#define WM_ACTIVATEAPP 0x001c
+#define SW_PARENTCLOSING 1
+#define SW_OTHERMAXIMIZED 2
+#define SW_PARENTOPENING 3
+#define SW_OTHERRESTORED 4
+#define GET_XBUTTON_WPARAM(wParam) (HIWORD(wParam))
+
+// drag n drop
+#ifndef CFSTR_PERFORMEDDROPEFFECT
+#define CFSTR_PERFORMEDDROPEFFECT TEXT("Performed DropEffect")
+#endif
+int qt_wince_GetDIBits(HDC, HBITMAP, uint, uint, void*, LPBITMAPINFO, uint);
+#define GetDIBits(a,b,c,d,e,f,g) qt_wince_GetDIBits(a,b,c,d,e,f,g)
+
+// QWidget
+#define SW_SHOWMINIMIZED SW_MINIMIZE
+
+// QRegion
+#define ALTERNATE 0
+#define WINDING 1
+
+// QFontEngine
+typedef struct _FIXED {
+ WORD fract;
+ short value;
+} FIXED;
+
+typedef struct tagPOINTFX {
+ FIXED x;
+ FIXED y;
+} POINTFX;
+
+typedef struct _MAT2 {
+ FIXED eM11;
+ FIXED eM12;
+ FIXED eM21;
+ FIXED eM22;
+} MAT2;
+
+typedef struct _GLYPHMETRICS {
+ UINT gmBlackBoxX;
+ UINT gmBlackBoxY;
+ POINT gmptGlyphOrigin;
+ short gmCellIncX;
+ short gmCellIncY;
+} GLYPHMETRICS;
+
+typedef struct tagTTPOLYGONHEADER
+{
+ DWORD cb;
+ DWORD dwType;
+ POINTFX pfxStart;
+} TTPOLYGONHEADER;
+
+typedef struct tagTTPOLYCURVE
+{
+ WORD wType;
+ WORD cpfx;
+ POINTFX apfx[1];
+} TTPOLYCURVE;
+
+#define GGO_NATIVE 2
+#define GGO_GLYPH_INDEX 0x0080
+#define TT_PRIM_LINE 1
+#define TT_PRIM_QSPLINE 2
+#define TT_PRIM_CSPLINE 3
+#define ANSI_VAR_FONT 12
+
+HINSTANCE qt_wince_ShellExecute(HWND hwnd, LPCWSTR operation, LPCWSTR file, LPCWSTR params, LPCWSTR dir, int showCmd);
+#define ShellExecute(a,b,c,d,e,f) qt_wince_ShellExecute(a,b,c,d,e,f)
+
+
+// Clipboard --------------------------------------------------------
+#define WM_CHANGECBCHAIN 1
+#define WM_DRAWCLIPBOARD 2
+
+BOOL qt_wince_ChangeClipboardChain(
+ HWND hWndRemove, // handle to window to remove
+ HWND hWndNewNext // handle to next window
+);
+#define ChangeClipboardChain(a,b) qt_wince_ChangeClipboardChain(a,b);
+
+HWND qt_wince_SetClipboardViewer(
+ HWND hWndNewViewer // handle to clipboard viewer window
+);
+#define SetClipboardViewer(a) qt_wince_SetClipboardViewer(a)
+
+// Graphics ---------------------------------------------------------
+COLORREF qt_wince_PALETTEINDEX( WORD wPaletteIndex );
+#define PALETTEINDEX(a) qt_wince_PALETTEINDEX(a)
+
+#endif // Q_OS_WINCE
+#endif // QGUIFUNCTIONS_WCE_H
diff --git a/src/gui/platforms/win/qkeymapper_win.cpp b/src/gui/platforms/win/qkeymapper_win.cpp
new file mode 100644
index 0000000000..92fa582617
--- /dev/null
+++ b/src/gui/platforms/win/qkeymapper_win.cpp
@@ -0,0 +1,1207 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qkeymapper_p.h"
+
+#include <qt_windows.h>
+#include <qdebug.h>
+#include <private/qevent_p.h>
+#include <private/qlocale_p.h>
+#include <private/qapplication_p.h>
+#include <qwidget.h>
+#include <qapplication.h>
+#include <ctype.h>
+
+QT_BEGIN_NAMESPACE
+
+// Uncommend, to show debugging information for the keymapper
+//#define DEBUG_KEYMAPPER
+
+// Implemented elsewhere
+extern "C" LRESULT QT_WIN_CALLBACK QtWndProc(HWND, UINT, WPARAM, LPARAM);
+
+extern Q_CORE_EXPORT QLocale qt_localeFromLCID(LCID id);
+#ifndef LANG_PASHTO
+#define LANG_PASHTO 0x63
+#endif
+#ifndef LANG_SYRIAC
+#define LANG_SYRIAC 0x5a
+#endif
+#ifndef LANG_DIVEHI
+#define LANG_DIVEHI 0x65
+#endif
+#ifndef VK_OEM_PLUS
+#define VK_OEM_PLUS 0xBB
+#endif
+#ifndef VK_OEM_3
+#define VK_OEM_3 0xC0
+#endif
+
+#if defined(Q_OS_WINCE)
+bool GetKeyboardState(unsigned char* kbuffer)
+{
+ for (int i=0; i< 256; ++i)
+ kbuffer[i] = GetAsyncKeyState(i);
+ return true;
+}
+#endif
+// Key recorder ------------------------------------------------------------------------[ start ] --
+struct KeyRecord {
+ KeyRecord(int c, int a, int s, const QString &t) : code(c), ascii(a), state(s), text(t) {}
+ KeyRecord() {}
+
+ int code;
+ int ascii;
+ int state;
+ QString text;
+};
+
+static const int QT_MAX_KEY_RECORDINGS = 64; // User has LOTS of fingers...
+struct KeyRecorder
+{
+ KeyRecorder() : nrecs(0) {}
+
+ inline KeyRecord *findKey(int code, bool remove);
+ inline void storeKey(int code, int ascii, int state, const QString& text);
+ inline void clearKeys();
+
+ int nrecs;
+ KeyRecord deleted_record; // A copy of last entry removed from records[]
+ KeyRecord records[QT_MAX_KEY_RECORDINGS];
+};
+static KeyRecorder key_recorder;
+
+KeyRecord *KeyRecorder::findKey(int code, bool remove)
+{
+ KeyRecord *result = 0;
+ for (int i = 0; i < nrecs; ++i) {
+ if (records[i].code == code) {
+ if (remove) {
+ deleted_record = records[i];
+ // Move rest down, and decrease count
+ while (i + 1 < nrecs) {
+ records[i] = records[i + 1];
+ ++i;
+ }
+ --nrecs;
+ result = &deleted_record;
+ } else {
+ result = &records[i];
+ }
+ break;
+ }
+ }
+ return result;
+}
+
+void KeyRecorder::storeKey(int code, int ascii, int state, const QString& text)
+{
+ Q_ASSERT_X(nrecs != QT_MAX_KEY_RECORDINGS,
+ "Internal KeyRecorder",
+ "Keyboard recorder buffer overflow, consider increasing QT_MAX_KEY_RECORDINGS");
+
+ if (nrecs == QT_MAX_KEY_RECORDINGS) {
+ qWarning("Qt: Internal keyboard buffer overflow");
+ return;
+ }
+ records[nrecs++] = KeyRecord(code,ascii,state,text);
+}
+
+void KeyRecorder::clearKeys()
+{
+ nrecs = 0;
+}
+// Key recorder --------------------------------------------------------------------------[ end ] --
+
+
+// Key translation ---------------------------------------------------------------------[ start ] --
+// Meaning of values:
+// 0 = Character output key, needs keyboard driver mapping
+// Key_unknown = Unknown Virtual Key, no translation possible, ignore
+static const uint KeyTbl[] = { // Keyboard mapping table
+ // Dec | Hex | Windows Virtual key
+ Qt::Key_unknown, // 0 0x00
+ Qt::Key_unknown, // 1 0x01 VK_LBUTTON | Left mouse button
+ Qt::Key_unknown, // 2 0x02 VK_RBUTTON | Right mouse button
+ Qt::Key_Cancel, // 3 0x03 VK_CANCEL | Control-Break processing
+ Qt::Key_unknown, // 4 0x04 VK_MBUTTON | Middle mouse button
+ Qt::Key_unknown, // 5 0x05 VK_XBUTTON1 | X1 mouse button
+ Qt::Key_unknown, // 6 0x06 VK_XBUTTON2 | X2 mouse button
+ Qt::Key_unknown, // 7 0x07 -- unassigned --
+ Qt::Key_Backspace, // 8 0x08 VK_BACK | BackSpace key
+ Qt::Key_Tab, // 9 0x09 VK_TAB | Tab key
+ Qt::Key_unknown, // 10 0x0A -- reserved --
+ Qt::Key_unknown, // 11 0x0B -- reserved --
+ Qt::Key_Clear, // 12 0x0C VK_CLEAR | Clear key
+ Qt::Key_Return, // 13 0x0D VK_RETURN | Enter key
+ Qt::Key_unknown, // 14 0x0E -- unassigned --
+ Qt::Key_unknown, // 15 0x0F -- unassigned --
+ Qt::Key_Shift, // 16 0x10 VK_SHIFT | Shift key
+ Qt::Key_Control, // 17 0x11 VK_CONTROL | Ctrl key
+ Qt::Key_Alt, // 18 0x12 VK_MENU | Alt key
+ Qt::Key_Pause, // 19 0x13 VK_PAUSE | Pause key
+ Qt::Key_CapsLock, // 20 0x14 VK_CAPITAL | Caps-Lock
+ Qt::Key_unknown, // 21 0x15 VK_KANA / VK_HANGUL | IME Kana or Hangul mode
+ Qt::Key_unknown, // 22 0x16 -- unassigned --
+ Qt::Key_unknown, // 23 0x17 VK_JUNJA | IME Junja mode
+ Qt::Key_unknown, // 24 0x18 VK_FINAL | IME final mode
+ Qt::Key_unknown, // 25 0x19 VK_HANJA / VK_KANJI | IME Hanja or Kanji mode
+ Qt::Key_unknown, // 26 0x1A -- unassigned --
+ Qt::Key_Escape, // 27 0x1B VK_ESCAPE | Esc key
+ Qt::Key_unknown, // 28 0x1C VK_CONVERT | IME convert
+ Qt::Key_unknown, // 29 0x1D VK_NONCONVERT | IME non-convert
+ Qt::Key_unknown, // 30 0x1E VK_ACCEPT | IME accept
+ Qt::Key_Mode_switch,// 31 0x1F VK_MODECHANGE | IME mode change request
+ Qt::Key_Space, // 32 0x20 VK_SPACE | Spacebar
+ Qt::Key_PageUp, // 33 0x21 VK_PRIOR | Page Up key
+ Qt::Key_PageDown, // 34 0x22 VK_NEXT | Page Down key
+ Qt::Key_End, // 35 0x23 VK_END | End key
+ Qt::Key_Home, // 36 0x24 VK_HOME | Home key
+ Qt::Key_Left, // 37 0x25 VK_LEFT | Left arrow key
+ Qt::Key_Up, // 38 0x26 VK_UP | Up arrow key
+ Qt::Key_Right, // 39 0x27 VK_RIGHT | Right arrow key
+ Qt::Key_Down, // 40 0x28 VK_DOWN | Down arrow key
+ Qt::Key_Select, // 41 0x29 VK_SELECT | Select key
+ Qt::Key_Printer, // 42 0x2A VK_PRINT | Print key
+ Qt::Key_Execute, // 43 0x2B VK_EXECUTE | Execute key
+ Qt::Key_Print, // 44 0x2C VK_SNAPSHOT | Print Screen key
+ Qt::Key_Insert, // 45 0x2D VK_INSERT | Ins key
+ Qt::Key_Delete, // 46 0x2E VK_DELETE | Del key
+ Qt::Key_Help, // 47 0x2F VK_HELP | Help key
+ 0, // 48 0x30 (VK_0) | 0 key
+ 0, // 49 0x31 (VK_1) | 1 key
+ 0, // 50 0x32 (VK_2) | 2 key
+ 0, // 51 0x33 (VK_3) | 3 key
+ 0, // 52 0x34 (VK_4) | 4 key
+ 0, // 53 0x35 (VK_5) | 5 key
+ 0, // 54 0x36 (VK_6) | 6 key
+ 0, // 55 0x37 (VK_7) | 7 key
+ 0, // 56 0x38 (VK_8) | 8 key
+ 0, // 57 0x39 (VK_9) | 9 key
+ Qt::Key_unknown, // 58 0x3A -- unassigned --
+ Qt::Key_unknown, // 59 0x3B -- unassigned --
+ Qt::Key_unknown, // 60 0x3C -- unassigned --
+ Qt::Key_unknown, // 61 0x3D -- unassigned --
+ Qt::Key_unknown, // 62 0x3E -- unassigned --
+ Qt::Key_unknown, // 63 0x3F -- unassigned --
+ Qt::Key_unknown, // 64 0x40 -- unassigned --
+ 0, // 65 0x41 (VK_A) | A key
+ 0, // 66 0x42 (VK_B) | B key
+ 0, // 67 0x43 (VK_C) | C key
+ 0, // 68 0x44 (VK_D) | D key
+ 0, // 69 0x45 (VK_E) | E key
+ 0, // 70 0x46 (VK_F) | F key
+ 0, // 71 0x47 (VK_G) | G key
+ 0, // 72 0x48 (VK_H) | H key
+ 0, // 73 0x49 (VK_I) | I key
+ 0, // 74 0x4A (VK_J) | J key
+ 0, // 75 0x4B (VK_K) | K key
+ 0, // 76 0x4C (VK_L) | L key
+ 0, // 77 0x4D (VK_M) | M key
+ 0, // 78 0x4E (VK_N) | N key
+ 0, // 79 0x4F (VK_O) | O key
+ 0, // 80 0x50 (VK_P) | P key
+ 0, // 81 0x51 (VK_Q) | Q key
+ 0, // 82 0x52 (VK_R) | R key
+ 0, // 83 0x53 (VK_S) | S key
+ 0, // 84 0x54 (VK_T) | T key
+ 0, // 85 0x55 (VK_U) | U key
+ 0, // 86 0x56 (VK_V) | V key
+ 0, // 87 0x57 (VK_W) | W key
+ 0, // 88 0x58 (VK_X) | X key
+ 0, // 89 0x59 (VK_Y) | Y key
+ 0, // 90 0x5A (VK_Z) | Z key
+ Qt::Key_Meta, // 91 0x5B VK_LWIN | Left Windows - MS Natural kbd
+ Qt::Key_Meta, // 92 0x5C VK_RWIN | Right Windows - MS Natural kbd
+ Qt::Key_Menu, // 93 0x5D VK_APPS | Application key-MS Natural kbd
+ Qt::Key_unknown, // 94 0x5E -- reserved --
+ Qt::Key_Sleep, // 95 0x5F VK_SLEEP
+ Qt::Key_0, // 96 0x60 VK_NUMPAD0 | Numeric keypad 0 key
+ Qt::Key_1, // 97 0x61 VK_NUMPAD1 | Numeric keypad 1 key
+ Qt::Key_2, // 98 0x62 VK_NUMPAD2 | Numeric keypad 2 key
+ Qt::Key_3, // 99 0x63 VK_NUMPAD3 | Numeric keypad 3 key
+ Qt::Key_4, // 100 0x64 VK_NUMPAD4 | Numeric keypad 4 key
+ Qt::Key_5, // 101 0x65 VK_NUMPAD5 | Numeric keypad 5 key
+ Qt::Key_6, // 102 0x66 VK_NUMPAD6 | Numeric keypad 6 key
+ Qt::Key_7, // 103 0x67 VK_NUMPAD7 | Numeric keypad 7 key
+ Qt::Key_8, // 104 0x68 VK_NUMPAD8 | Numeric keypad 8 key
+ Qt::Key_9, // 105 0x69 VK_NUMPAD9 | Numeric keypad 9 key
+ Qt::Key_Asterisk, // 106 0x6A VK_MULTIPLY | Multiply key
+ Qt::Key_Plus, // 107 0x6B VK_ADD | Add key
+ Qt::Key_Comma, // 108 0x6C VK_SEPARATOR | Separator key
+ Qt::Key_Minus, // 109 0x6D VK_SUBTRACT | Subtract key
+ Qt::Key_Period, // 110 0x6E VK_DECIMAL | Decimal key
+ Qt::Key_Slash, // 111 0x6F VK_DIVIDE | Divide key
+ Qt::Key_F1, // 112 0x70 VK_F1 | F1 key
+ Qt::Key_F2, // 113 0x71 VK_F2 | F2 key
+ Qt::Key_F3, // 114 0x72 VK_F3 | F3 key
+ Qt::Key_F4, // 115 0x73 VK_F4 | F4 key
+ Qt::Key_F5, // 116 0x74 VK_F5 | F5 key
+ Qt::Key_F6, // 117 0x75 VK_F6 | F6 key
+ Qt::Key_F7, // 118 0x76 VK_F7 | F7 key
+ Qt::Key_F8, // 119 0x77 VK_F8 | F8 key
+ Qt::Key_F9, // 120 0x78 VK_F9 | F9 key
+ Qt::Key_F10, // 121 0x79 VK_F10 | F10 key
+ Qt::Key_F11, // 122 0x7A VK_F11 | F11 key
+ Qt::Key_F12, // 123 0x7B VK_F12 | F12 key
+ Qt::Key_F13, // 124 0x7C VK_F13 | F13 key
+ Qt::Key_F14, // 125 0x7D VK_F14 | F14 key
+ Qt::Key_F15, // 126 0x7E VK_F15 | F15 key
+ Qt::Key_F16, // 127 0x7F VK_F16 | F16 key
+ Qt::Key_F17, // 128 0x80 VK_F17 | F17 key
+ Qt::Key_F18, // 129 0x81 VK_F18 | F18 key
+ Qt::Key_F19, // 130 0x82 VK_F19 | F19 key
+ Qt::Key_F20, // 131 0x83 VK_F20 | F20 key
+ Qt::Key_F21, // 132 0x84 VK_F21 | F21 key
+ Qt::Key_F22, // 133 0x85 VK_F22 | F22 key
+ Qt::Key_F23, // 134 0x86 VK_F23 | F23 key
+ Qt::Key_F24, // 135 0x87 VK_F24 | F24 key
+ Qt::Key_unknown, // 136 0x88 -- unassigned --
+ Qt::Key_unknown, // 137 0x89 -- unassigned --
+ Qt::Key_unknown, // 138 0x8A -- unassigned --
+ Qt::Key_unknown, // 139 0x8B -- unassigned --
+ Qt::Key_unknown, // 140 0x8C -- unassigned --
+ Qt::Key_unknown, // 141 0x8D -- unassigned --
+ Qt::Key_unknown, // 142 0x8E -- unassigned --
+ Qt::Key_unknown, // 143 0x8F -- unassigned --
+ Qt::Key_NumLock, // 144 0x90 VK_NUMLOCK | Num Lock key
+ Qt::Key_ScrollLock, // 145 0x91 VK_SCROLL | Scroll Lock key
+ // Fujitsu/OASYS kbd --------------------
+ 0, //Qt::Key_Jisho, // 146 0x92 VK_OEM_FJ_JISHO | 'Dictionary' key /
+ // VK_OEM_NEC_EQUAL = key on numpad on NEC PC-9800 kbd
+ Qt::Key_Massyo, // 147 0x93 VK_OEM_FJ_MASSHOU | 'Unregister word' key
+ Qt::Key_Touroku, // 148 0x94 VK_OEM_FJ_TOUROKU | 'Register word' key
+ 0, //Qt::Key_Oyayubi_Left,//149 0x95 VK_OEM_FJ_LOYA | 'Left OYAYUBI' key
+ 0, //Qt::Key_Oyayubi_Right,//150 0x96 VK_OEM_FJ_ROYA | 'Right OYAYUBI' key
+ Qt::Key_unknown, // 151 0x97 -- unassigned --
+ Qt::Key_unknown, // 152 0x98 -- unassigned --
+ Qt::Key_unknown, // 153 0x99 -- unassigned --
+ Qt::Key_unknown, // 154 0x9A -- unassigned --
+ Qt::Key_unknown, // 155 0x9B -- unassigned --
+ Qt::Key_unknown, // 156 0x9C -- unassigned --
+ Qt::Key_unknown, // 157 0x9D -- unassigned --
+ Qt::Key_unknown, // 158 0x9E -- unassigned --
+ Qt::Key_unknown, // 159 0x9F -- unassigned --
+ Qt::Key_Shift, // 160 0xA0 VK_LSHIFT | Left Shift key
+ Qt::Key_Shift, // 161 0xA1 VK_RSHIFT | Right Shift key
+ Qt::Key_Control, // 162 0xA2 VK_LCONTROL | Left Ctrl key
+ Qt::Key_Control, // 163 0xA3 VK_RCONTROL | Right Ctrl key
+ Qt::Key_Alt, // 164 0xA4 VK_LMENU | Left Menu key
+ Qt::Key_Alt, // 165 0xA5 VK_RMENU | Right Menu key
+ Qt::Key_Back, // 166 0xA6 VK_BROWSER_BACK | Browser Back key
+ Qt::Key_Forward, // 167 0xA7 VK_BROWSER_FORWARD | Browser Forward key
+ Qt::Key_Refresh, // 168 0xA8 VK_BROWSER_REFRESH | Browser Refresh key
+ Qt::Key_Stop, // 169 0xA9 VK_BROWSER_STOP | Browser Stop key
+ Qt::Key_Search, // 170 0xAA VK_BROWSER_SEARCH | Browser Search key
+ Qt::Key_Favorites, // 171 0xAB VK_BROWSER_FAVORITES| Browser Favorites key
+ Qt::Key_HomePage, // 172 0xAC VK_BROWSER_HOME | Browser Start and Home key
+ Qt::Key_VolumeMute, // 173 0xAD VK_VOLUME_MUTE | Volume Mute key
+ Qt::Key_VolumeDown, // 174 0xAE VK_VOLUME_DOWN | Volume Down key
+ Qt::Key_VolumeUp, // 175 0xAF VK_VOLUME_UP | Volume Up key
+ Qt::Key_MediaNext, // 176 0xB0 VK_MEDIA_NEXT_TRACK | Next Track key
+ Qt::Key_MediaPrevious, //177 0xB1 VK_MEDIA_PREV_TRACK | Previous Track key
+ Qt::Key_MediaStop, // 178 0xB2 VK_MEDIA_STOP | Stop Media key
+ Qt::Key_MediaPlay, // 179 0xB3 VK_MEDIA_PLAY_PAUSE | Play/Pause Media key
+ Qt::Key_LaunchMail, // 180 0xB4 VK_LAUNCH_MAIL | Start Mail key
+ Qt::Key_LaunchMedia,// 181 0xB5 VK_LAUNCH_MEDIA_SELECT Select Media key
+ Qt::Key_Launch0, // 182 0xB6 VK_LAUNCH_APP1 | Start Application 1 key
+ Qt::Key_Launch1, // 183 0xB7 VK_LAUNCH_APP2 | Start Application 2 key
+ Qt::Key_unknown, // 184 0xB8 -- reserved --
+ Qt::Key_unknown, // 185 0xB9 -- reserved --
+ 0, // 186 0xBA VK_OEM_1 | ';:' for US
+ 0, // 187 0xBB VK_OEM_PLUS | '+' any country
+ 0, // 188 0xBC VK_OEM_COMMA | ',' any country
+ 0, // 189 0xBD VK_OEM_MINUS | '-' any country
+ 0, // 190 0xBE VK_OEM_PERIOD | '.' any country
+ 0, // 191 0xBF VK_OEM_2 | '/?' for US
+ 0, // 192 0xC0 VK_OEM_3 | '`~' for US
+ Qt::Key_unknown, // 193 0xC1 -- reserved --
+ Qt::Key_unknown, // 194 0xC2 -- reserved --
+ Qt::Key_unknown, // 195 0xC3 -- reserved --
+ Qt::Key_unknown, // 196 0xC4 -- reserved --
+ Qt::Key_unknown, // 197 0xC5 -- reserved --
+ Qt::Key_unknown, // 198 0xC6 -- reserved --
+ Qt::Key_unknown, // 199 0xC7 -- reserved --
+ Qt::Key_unknown, // 200 0xC8 -- reserved --
+ Qt::Key_unknown, // 201 0xC9 -- reserved --
+ Qt::Key_unknown, // 202 0xCA -- reserved --
+ Qt::Key_unknown, // 203 0xCB -- reserved --
+ Qt::Key_unknown, // 204 0xCC -- reserved --
+ Qt::Key_unknown, // 205 0xCD -- reserved --
+ Qt::Key_unknown, // 206 0xCE -- reserved --
+ Qt::Key_unknown, // 207 0xCF -- reserved --
+ Qt::Key_unknown, // 208 0xD0 -- reserved --
+ Qt::Key_unknown, // 209 0xD1 -- reserved --
+ Qt::Key_unknown, // 210 0xD2 -- reserved --
+ Qt::Key_unknown, // 211 0xD3 -- reserved --
+ Qt::Key_unknown, // 212 0xD4 -- reserved --
+ Qt::Key_unknown, // 213 0xD5 -- reserved --
+ Qt::Key_unknown, // 214 0xD6 -- reserved --
+ Qt::Key_unknown, // 215 0xD7 -- reserved --
+ Qt::Key_unknown, // 216 0xD8 -- unassigned --
+ Qt::Key_unknown, // 217 0xD9 -- unassigned --
+ Qt::Key_unknown, // 218 0xDA -- unassigned --
+ 0, // 219 0xDB VK_OEM_4 | '[{' for US
+ 0, // 220 0xDC VK_OEM_5 | '\|' for US
+ 0, // 221 0xDD VK_OEM_6 | ']}' for US
+ 0, // 222 0xDE VK_OEM_7 | ''"' for US
+ 0, // 223 0xDF VK_OEM_8
+ Qt::Key_unknown, // 224 0xE0 -- reserved --
+ Qt::Key_unknown, // 225 0xE1 VK_OEM_AX | 'AX' key on Japanese AX kbd
+ Qt::Key_unknown, // 226 0xE2 VK_OEM_102 | "<>" or "\|" on RT 102-key kbd
+ Qt::Key_unknown, // 227 0xE3 VK_ICO_HELP | Help key on ICO
+ Qt::Key_unknown, // 228 0xE4 VK_ICO_00 | 00 key on ICO
+ Qt::Key_unknown, // 229 0xE5 VK_PROCESSKEY | IME Process key
+ Qt::Key_unknown, // 230 0xE6 VK_ICO_CLEAR |
+ Qt::Key_unknown, // 231 0xE7 VK_PACKET | Unicode char as keystrokes
+ Qt::Key_unknown, // 232 0xE8 -- unassigned --
+ // Nokia/Ericsson definitions ---------------
+ Qt::Key_unknown, // 233 0xE9 VK_OEM_RESET
+ Qt::Key_unknown, // 234 0xEA VK_OEM_JUMP
+ Qt::Key_unknown, // 235 0xEB VK_OEM_PA1
+ Qt::Key_unknown, // 236 0xEC VK_OEM_PA2
+ Qt::Key_unknown, // 237 0xED VK_OEM_PA3
+ Qt::Key_unknown, // 238 0xEE VK_OEM_WSCTRL
+ Qt::Key_unknown, // 239 0xEF VK_OEM_CUSEL
+ Qt::Key_unknown, // 240 0xF0 VK_OEM_ATTN
+ Qt::Key_unknown, // 241 0xF1 VK_OEM_FINISH
+ Qt::Key_unknown, // 242 0xF2 VK_OEM_COPY
+ Qt::Key_unknown, // 243 0xF3 VK_OEM_AUTO
+ Qt::Key_unknown, // 244 0xF4 VK_OEM_ENLW
+ Qt::Key_unknown, // 245 0xF5 VK_OEM_BACKTAB
+ Qt::Key_unknown, // 246 0xF6 VK_ATTN | Attn key
+ Qt::Key_unknown, // 247 0xF7 VK_CRSEL | CrSel key
+ Qt::Key_unknown, // 248 0xF8 VK_EXSEL | ExSel key
+ Qt::Key_unknown, // 249 0xF9 VK_EREOF | Erase EOF key
+ Qt::Key_Play, // 250 0xFA VK_PLAY | Play key
+ Qt::Key_Zoom, // 251 0xFB VK_ZOOM | Zoom key
+ Qt::Key_unknown, // 252 0xFC VK_NONAME | Reserved
+ Qt::Key_unknown, // 253 0xFD VK_PA1 | PA1 key
+ Qt::Key_Clear, // 254 0xFE VK_OEM_CLEAR | Clear key
+ 0
+};
+
+// Possible modifier states.
+// NOTE: The order of these states match the order in QKeyMapperPrivate::updatePossibleKeyCodes()!
+static const Qt::KeyboardModifiers ModsTbl[] = {
+ Qt::NoModifier, // 0
+ Qt::ShiftModifier, // 1
+ Qt::ControlModifier, // 2
+ Qt::ControlModifier | Qt::ShiftModifier, // 3
+ Qt::AltModifier, // 4
+ Qt::AltModifier | Qt::ShiftModifier, // 5
+ Qt::AltModifier | Qt::ControlModifier, // 6
+ Qt::AltModifier | Qt::ShiftModifier | Qt::ControlModifier, // 7
+ Qt::NoModifier, // Fall-back to raw Key_*
+};
+
+/**
+ Remap return or action key to select key for windows mobile.
+*/
+inline int winceKeyBend(int keyCode)
+{
+#if defined(Q_OS_WINCE_WM) && defined(QT_KEYPAD_NAVIGATION)
+ // remap return or action key to select key for windows mobile.
+ // will be changed to a table remapping function in the next version (4.6/7).
+ if (keyCode == VK_RETURN && QApplication::keypadNavigationEnabled())
+ return Qt::Key_Select;
+ else
+ return KeyTbl[keyCode];
+#else
+ return KeyTbl[keyCode];
+#endif
+}
+
+#if defined(Q_OS_WINCE)
+ // Use the KeyTbl to resolve a Qt::Key out of the virtual keys.
+ // In case it is not resolvable, continue using the virtual key itself.
+
+QT_BEGIN_INCLUDE_NAMESPACE
+
+int ToUnicode(UINT vk, int /*scancode*/, unsigned char* /*kbdBuffer*/, LPWSTR unicodeBuffer, int, int)
+{
+ QT_USE_NAMESPACE
+ QChar* buf = reinterpret_cast< QChar*>(unicodeBuffer);
+ if (KeyTbl[vk] == 0) {
+ buf[0] = vk;
+ return 1;
+ }
+ return 0;
+}
+
+int ToAscii(UINT vk, int scancode, unsigned char *kbdBuffer, LPWORD unicodeBuffer, int flag)
+{
+ return ToUnicode(vk, scancode, kbdBuffer, (LPWSTR) unicodeBuffer, 0, flag);
+
+}
+QT_END_INCLUDE_NAMESPACE
+
+#endif
+
+// Translate a VK into a Qt key code, or unicode character
+static inline int toKeyOrUnicode(int vk, int scancode, unsigned char *kbdBuffer, bool *isDeadkey = 0)
+{
+ Q_ASSERT(vk > 0 && vk < 256);
+ int code = 0;
+ QChar unicodeBuffer[5];
+ int res = ToUnicode(vk, scancode, kbdBuffer, reinterpret_cast<LPWSTR>(unicodeBuffer), 5, 0);
+ if (res)
+ code = unicodeBuffer[0].toUpper().unicode();
+
+ // Qt::Key_*'s are not encoded below 0x20, so try again, and DEL keys (0x7f) is encoded with a
+ // proper Qt::Key_ code
+ if (code < 0x20 || code == 0x7f) // Handles res==0 too
+ code = winceKeyBend(vk);
+
+ if (isDeadkey)
+ *isDeadkey = (res == -1);
+
+ return code == Qt::Key_unknown ? 0 : code;
+}
+
+Q_GUI_EXPORT int qt_translateKeyCode(int vk)
+{
+ int code = winceKeyBend((vk < 0 || vk > 255) ? 0 : vk);
+ return code == Qt::Key_unknown ? 0 : code;
+}
+
+static inline int asciiToKeycode(char a, int state)
+{
+ if (a >= 'a' && a <= 'z')
+ a = toupper(a);
+ if ((state & Qt::ControlModifier) != 0) {
+ if (a >= 0 && a <= 31) // Ctrl+@..Ctrl+A..CTRL+Z..Ctrl+_
+ a += '@'; // to @..A..Z.._
+ }
+ return a & 0xff;
+}
+
+static inline bool isModifierKey(int code)
+{
+ return (code >= Qt::Key_Shift) && (code <= Qt::Key_ScrollLock);
+}
+// Key translation -----------------------------------------------------------------------[ end ]---
+
+
+static void qt_show_system_menu(QWidget* tlw)
+{
+ Q_ASSERT(tlw->testAttribute(Qt::WA_WState_Created));
+ HMENU menu = GetSystemMenu(tlw->internalWinId(), FALSE);
+ if (!menu)
+ return; // no menu for this window
+
+#define enabled (MF_BYCOMMAND | MF_ENABLED)
+#define disabled (MF_BYCOMMAND | MF_GRAYED)
+
+#ifndef Q_OS_WINCE
+ EnableMenuItem(menu, SC_MINIMIZE, (tlw->windowFlags() & Qt::WindowMinimizeButtonHint)?enabled:disabled);
+ bool maximized = IsZoomed(tlw->internalWinId());
+
+ EnableMenuItem(menu, SC_MAXIMIZE, ! (tlw->windowFlags() & Qt::WindowMaximizeButtonHint) || maximized?disabled:enabled);
+ EnableMenuItem(menu, SC_RESTORE, maximized?enabled:disabled);
+
+ // We should _not_ check with the setFixedSize(x,y) case here, since Windows is not able to check
+ // this and our menu here would be out-of-sync with the menu produced by mouse-click on the
+ // System Menu, or right-click on the title bar.
+ EnableMenuItem(menu, SC_SIZE, (tlw->windowFlags() & Qt::MSWindowsFixedSizeDialogHint) || maximized?disabled:enabled);
+ EnableMenuItem(menu, SC_MOVE, maximized?disabled:enabled);
+ EnableMenuItem(menu, SC_CLOSE, enabled);
+ // Set bold on close menu item
+ MENUITEMINFO closeItem;
+ closeItem.cbSize = sizeof(MENUITEMINFO);
+ closeItem.fMask = MIIM_STATE;
+ closeItem.fState = MFS_DEFAULT;
+ SetMenuItemInfo(menu, SC_CLOSE, FALSE, &closeItem);
+#endif
+
+#undef enabled
+#undef disabled
+ int ret = TrackPopupMenuEx(menu,
+ TPM_LEFTALIGN | TPM_TOPALIGN | TPM_NONOTIFY | TPM_RETURNCMD,
+ tlw->geometry().x(), tlw->geometry().y(),
+ tlw->internalWinId(),
+ 0);
+ if (ret)
+ QtWndProc(tlw->internalWinId(), WM_SYSCOMMAND, ret, 0);
+}
+
+
+// QETWidget class is only for accessing the sendSpontaneousEvent function in QApplication
+class QETWidget : public QWidget {
+public:
+ static bool sendSpontaneousEvent(QObject *r, QEvent *e)
+ { return QApplication::sendSpontaneousEvent(r, e); }
+};
+
+
+// Keyboard map private ----------------------------------------------------------------[ start ]---
+
+/*
+ \internal
+ A Windows KeyboardLayoutItem has 8 possible states:
+ 1. Unmodified
+ 2. Shift
+ 3. Control
+ 4. Control + Shift
+ 5. Alt
+ 6. Alt + Shift
+ 7. Alt + Control
+ 8. Alt + Control + Shift
+*/
+struct KeyboardLayoutItem {
+ bool dirty;
+ quint8 deadkeys;
+ quint32 qtKey[9]; // Can by any Qt::Key_<foo>, or unicode character
+};
+
+QKeyMapperPrivate::QKeyMapperPrivate()
+{
+ memset(keyLayout, 0, sizeof(keyLayout));
+}
+
+QKeyMapperPrivate::~QKeyMapperPrivate()
+{
+ deleteLayouts();
+}
+
+void QKeyMapperPrivate::deleteLayouts()
+{
+ for (int i = 0; i < 255; ++i) {
+ if (keyLayout[i]) {
+ delete keyLayout[i];
+ keyLayout[i] = 0;
+ }
+ }
+}
+
+void QKeyMapperPrivate::clearMappings()
+{
+ deleteLayouts();
+
+ /* MAKELCID()'s first argument is a WORD, and GetKeyboardLayout()
+ * returns a DWORD. */
+
+ LCID newLCID = MAKELCID((quintptr)GetKeyboardLayout(0), SORT_DEFAULT);
+// keyboardInputLocale = qt_localeFromLCID(newLCID);
+
+ bool bidi = false;
+ wchar_t LCIDFontSig[16];
+ if (GetLocaleInfo(newLCID, LOCALE_FONTSIGNATURE, LCIDFontSig, sizeof(LCIDFontSig) / sizeof(wchar_t))
+ && (LCIDFontSig[7] & (wchar_t)0x0800))
+ bidi = true;
+
+ keyboardInputDirection = bidi ? Qt::RightToLeft : Qt::LeftToRight;
+}
+
+void QKeyMapperPrivate::clearRecordedKeys()
+{
+ key_recorder.clearKeys();
+}
+
+
+inline void setKbdState(unsigned char *kbd, bool shift, bool ctrl, bool alt)
+{
+ kbd[VK_LSHIFT ] = (shift ? 0x80 : 0);
+ kbd[VK_SHIFT ] = (shift ? 0x80 : 0);
+ kbd[VK_LCONTROL] = (ctrl ? 0x80 : 0);
+ kbd[VK_CONTROL ] = (ctrl ? 0x80 : 0);
+ kbd[VK_RMENU ] = (alt ? 0x80 : 0);
+ kbd[VK_MENU ] = (alt ? 0x80 : 0);
+}
+
+void QKeyMapperPrivate::updateKeyMap(const MSG &msg)
+{
+ unsigned char kbdBuffer[256]; // Will hold the complete keyboard state
+ GetKeyboardState(kbdBuffer);
+ quint32 scancode = (msg.lParam >> 16) & 0xfff;
+ updatePossibleKeyCodes(kbdBuffer, scancode, msg.wParam);
+}
+
+void QKeyMapperPrivate::updatePossibleKeyCodes(unsigned char *kbdBuffer, quint32 scancode,
+ quint32 vk_key)
+{
+ if (!vk_key || (keyLayout[vk_key] && !keyLayout[vk_key]->dirty))
+ return;
+
+ if (!keyLayout[vk_key])
+ keyLayout[vk_key] = new KeyboardLayoutItem;
+
+ // Copy keyboard state, so we can modify and query output for each possible permutation
+ unsigned char buffer[256];
+ memcpy(buffer, kbdBuffer, sizeof(buffer));
+ // Always 0, as Windows doesn't treat these as modifiers;
+ buffer[VK_LWIN ] = 0;
+ buffer[VK_RWIN ] = 0;
+ buffer[VK_CAPITAL ] = 0;
+ buffer[VK_NUMLOCK ] = 0;
+ buffer[VK_SCROLL ] = 0;
+ // Always 0, since we'll only change the other versions
+ buffer[VK_RSHIFT ] = 0;
+ buffer[VK_RCONTROL] = 0;
+ buffer[VK_LMENU ] = 0; // Use right Alt, since left Ctrl + right Alt is considered AltGraph
+
+ bool isDeadKey = false;
+ keyLayout[vk_key]->deadkeys = 0;
+ keyLayout[vk_key]->dirty = false;
+ setKbdState(buffer, false, false, false);
+ keyLayout[vk_key]->qtKey[0] = toKeyOrUnicode(vk_key, scancode, buffer, &isDeadKey);
+ keyLayout[vk_key]->deadkeys |= isDeadKey ? 0x01 : 0;
+ setKbdState(buffer, true, false, false);
+ keyLayout[vk_key]->qtKey[1] = toKeyOrUnicode(vk_key, scancode, buffer, &isDeadKey);
+ keyLayout[vk_key]->deadkeys |= isDeadKey ? 0x02 : 0;
+ setKbdState(buffer, false, true, false);
+ keyLayout[vk_key]->qtKey[2] = toKeyOrUnicode(vk_key, scancode, buffer, &isDeadKey);
+ keyLayout[vk_key]->deadkeys |= isDeadKey ? 0x04 : 0;
+ setKbdState(buffer, true, true, false);
+ keyLayout[vk_key]->qtKey[3] = toKeyOrUnicode(vk_key, scancode, buffer, &isDeadKey);
+ keyLayout[vk_key]->deadkeys |= isDeadKey ? 0x08 : 0;
+ setKbdState(buffer, false, false, true);
+ keyLayout[vk_key]->qtKey[4] = toKeyOrUnicode(vk_key, scancode, buffer, &isDeadKey);
+ keyLayout[vk_key]->deadkeys |= isDeadKey ? 0x10 : 0;
+ setKbdState(buffer, true, false, true);
+ keyLayout[vk_key]->qtKey[5] = toKeyOrUnicode(vk_key, scancode, buffer, &isDeadKey);
+ keyLayout[vk_key]->deadkeys |= isDeadKey ? 0x20 : 0;
+ setKbdState(buffer, false, true, true);
+ keyLayout[vk_key]->qtKey[6] = toKeyOrUnicode(vk_key, scancode, buffer, &isDeadKey);
+ keyLayout[vk_key]->deadkeys |= isDeadKey ? 0x40 : 0;
+ setKbdState(buffer, true, true, true);
+ keyLayout[vk_key]->qtKey[7] = toKeyOrUnicode(vk_key, scancode, buffer, &isDeadKey);
+ keyLayout[vk_key]->deadkeys |= isDeadKey ? 0x80 : 0;
+ // Add a fall back key for layouts which don't do composition and show non-latin1 characters
+ int fallbackKey = winceKeyBend(vk_key);
+ if (!fallbackKey || fallbackKey == Qt::Key_unknown) {
+ fallbackKey = 0;
+ if (vk_key != keyLayout[vk_key]->qtKey[0] && vk_key < 0x5B && vk_key > 0x2F)
+ fallbackKey = vk_key;
+ }
+ keyLayout[vk_key]->qtKey[8] = fallbackKey;
+
+ // If this vk_key a Dead Key
+ if (MapVirtualKey(vk_key, 2) & 0x80000000) {
+ // Push a Space, then the original key through the low-level ToAscii functions.
+ // We do this because these functions (ToAscii / ToUnicode) will alter the internal state of
+ // the keyboard driver By doing the following, we set the keyboard driver state back to what
+ // it was before we wrecked it with the code above.
+ // We need to push the space with an empty keystate map, since the driver checks the map for
+ // transitions in modifiers, so this helps us capture all possible deadkeys.
+ unsigned char emptyBuffer[256];
+ memset(emptyBuffer, 0, sizeof(emptyBuffer));
+ ::ToAscii(VK_SPACE, 0, emptyBuffer, reinterpret_cast<LPWORD>(&buffer), 0);
+ ::ToAscii(vk_key, scancode, kbdBuffer, reinterpret_cast<LPWORD>(&buffer), 0);
+ }
+
+#ifdef DEBUG_KEYMAPPER
+ qDebug("updatePossibleKeyCodes for virtual key = 0x%02x!", vk_key);
+ for (int i = 0; i < 9; ++i) {
+ qDebug(" [%d] (%d,0x%02x,'%c') %s", i,
+ keyLayout[vk_key]->qtKey[i],
+ keyLayout[vk_key]->qtKey[i],
+ keyLayout[vk_key]->qtKey[i] ? keyLayout[vk_key]->qtKey[i] : 0x03,
+ keyLayout[vk_key]->deadkeys & (1<<i) ? "deadkey" : "");
+ }
+#endif // DEBUG_KEYMAPPER
+}
+
+bool QKeyMapperPrivate::isADeadKey(unsigned int vk_key, unsigned int modifiers)
+{
+ if (keyLayout && (vk_key < 256) && keyLayout[vk_key]) {
+ for(register int i = 0; i < 9; ++i) {
+ if (uint(ModsTbl[i]) == modifiers)
+ return bool(keyLayout[vk_key]->deadkeys & 1<<i);
+ }
+ }
+ return false;
+}
+
+extern bool qt_use_rtl_extensions;
+
+QList<int> QKeyMapperPrivate::possibleKeys(QKeyEvent *e)
+{
+ QList<int> result;
+
+ KeyboardLayoutItem *kbItem = keyLayout[e->nativeVirtualKey()];
+ if(!kbItem)
+ return result;
+
+ quint32 baseKey = kbItem->qtKey[0];
+ Qt::KeyboardModifiers keyMods = e->modifiers();
+ if (baseKey == Qt::Key_Return && (e->nativeModifiers() & ExtendedKey)) {
+ result << int(Qt::Key_Enter + keyMods);
+ return result;
+ }
+ result << int(baseKey + keyMods); // The base key is _always_ valid, of course
+
+ for(int i = 1; i < 9; ++i) {
+ Qt::KeyboardModifiers neededMods = ModsTbl[i];
+ quint32 key = kbItem->qtKey[i];
+ if (key && key != baseKey && ((keyMods & neededMods) == neededMods))
+ result << int(key + (keyMods & ~neededMods));
+ }
+
+ return result;
+}
+
+bool QKeyMapperPrivate::translateKeyEvent(QWidget *widget, const MSG &msg, bool grab)
+{
+ Q_Q(QKeyMapper);
+ Q_UNUSED(q); // Strange, but the compiler complains on q not being referenced, even if it is..
+ bool k0 = false;
+ bool k1 = false;
+ int msgType = msg.message;
+
+ quint32 scancode = (msg.lParam >> 16) & 0xfff;
+ quint32 vk_key = MapVirtualKey(scancode, 1);
+ bool isNumpad = (msg.wParam >= VK_NUMPAD0 && msg.wParam <= VK_NUMPAD9);
+ quint32 nModifiers = 0;
+
+#if defined(Q_OS_WINCE)
+ nModifiers |= (GetKeyState(VK_SHIFT ) < 0 ? ShiftAny : 0);
+ nModifiers |= (GetKeyState(VK_CONTROL) < 0 ? ControlAny : 0);
+ nModifiers |= (GetKeyState(VK_MENU ) < 0 ? AltAny : 0);
+ nModifiers |= (GetKeyState(VK_LWIN ) < 0 ? MetaLeft : 0);
+ nModifiers |= (GetKeyState(VK_RWIN ) < 0 ? MetaRight : 0);
+#else
+ // Map native modifiers to some bit representation
+ nModifiers |= (GetKeyState(VK_LSHIFT ) & 0x80 ? ShiftLeft : 0);
+ nModifiers |= (GetKeyState(VK_RSHIFT ) & 0x80 ? ShiftRight : 0);
+ nModifiers |= (GetKeyState(VK_LCONTROL) & 0x80 ? ControlLeft : 0);
+ nModifiers |= (GetKeyState(VK_RCONTROL) & 0x80 ? ControlRight : 0);
+ nModifiers |= (GetKeyState(VK_LMENU ) & 0x80 ? AltLeft : 0);
+ nModifiers |= (GetKeyState(VK_RMENU ) & 0x80 ? AltRight : 0);
+ nModifiers |= (GetKeyState(VK_LWIN ) & 0x80 ? MetaLeft : 0);
+ nModifiers |= (GetKeyState(VK_RWIN ) & 0x80 ? MetaRight : 0);
+ // Add Lock keys to the same bits
+ nModifiers |= (GetKeyState(VK_CAPITAL ) & 0x01 ? CapsLock : 0);
+ nModifiers |= (GetKeyState(VK_NUMLOCK ) & 0x01 ? NumLock : 0);
+ nModifiers |= (GetKeyState(VK_SCROLL ) & 0x01 ? ScrollLock : 0);
+#endif // Q_OS_WINCE
+
+ if (msg.lParam & ExtendedKey)
+ nModifiers |= msg.lParam & ExtendedKey;
+
+ // Get the modifier states (may be altered later, depending on key code)
+ int state = 0;
+ state |= (nModifiers & ShiftAny ? Qt::ShiftModifier : 0);
+ state |= (nModifiers & ControlAny ? Qt::ControlModifier : 0);
+ state |= (nModifiers & AltAny ? Qt::AltModifier : 0);
+ state |= (nModifiers & MetaAny ? Qt::MetaModifier : 0);
+
+ // Now we know enough to either have MapVirtualKey or our own keymap tell us if it's a deadkey
+ bool isDeadKey = isADeadKey(msg.wParam, state)
+ || MapVirtualKey(msg.wParam, 2) & 0x80000000;
+
+ // A multi-character key not found by our look-ahead
+ if (msgType == WM_CHAR) {
+ QString s;
+ QChar ch = QChar((ushort)msg.wParam);
+ if (!ch.isNull())
+ s += ch;
+
+ k0 = q->sendKeyEvent(widget, grab, QEvent::KeyPress, 0, Qt::KeyboardModifier(state), s, false, 0, scancode, vk_key, nModifiers);
+ k1 = q->sendKeyEvent(widget, grab, QEvent::KeyRelease, 0, Qt::KeyboardModifier(state), s, false, 0, scancode, vk_key, nModifiers);
+ }
+
+ // Input method characters not found by our look-ahead
+ else if (msgType == WM_IME_CHAR) {
+ QString s;
+ QChar ch = QChar((ushort)msg.wParam);
+ if (!ch.isNull())
+ s += ch;
+
+ k0 = q->sendKeyEvent(widget, grab, QEvent::KeyPress, 0, Qt::KeyboardModifier(state), s, false, 0, scancode, vk_key, nModifiers);
+ k1 = q->sendKeyEvent(widget, grab, QEvent::KeyRelease, 0, Qt::KeyboardModifier(state), s, false, 0, scancode, vk_key, nModifiers);
+ }
+
+ else {
+ // handle Directionality changes (BiDi) with RTL extensions
+ if (qt_use_rtl_extensions) {
+ static int dirStatus = 0;
+ if (!dirStatus && state == Qt::ControlModifier
+ && msg.wParam == VK_CONTROL
+ && msgType == WM_KEYDOWN) {
+ if (GetKeyState(VK_LCONTROL) < 0)
+ dirStatus = VK_LCONTROL;
+ else if (GetKeyState(VK_RCONTROL) < 0)
+ dirStatus = VK_RCONTROL;
+ } else if (dirStatus) {
+ if (msgType == WM_KEYDOWN) {
+ if (msg.wParam == VK_SHIFT) {
+ if (dirStatus == VK_LCONTROL && GetKeyState(VK_LSHIFT) < 0)
+ dirStatus = VK_LSHIFT;
+ else if (dirStatus == VK_RCONTROL && GetKeyState(VK_RSHIFT) < 0)
+ dirStatus = VK_RSHIFT;
+ } else {
+ dirStatus = 0;
+ }
+ } else if (msgType == WM_KEYUP) {
+ if (dirStatus == VK_LSHIFT
+ && ((msg.wParam == VK_SHIFT && GetKeyState(VK_LCONTROL))
+ || (msg.wParam == VK_CONTROL && GetKeyState(VK_LSHIFT)))) {
+ k0 = q->sendKeyEvent(widget, grab, QEvent::KeyPress, Qt::Key_Direction_L, 0,
+ QString(), false, 0,
+ scancode, msg.wParam, nModifiers);
+ k1 = q->sendKeyEvent(widget, grab, QEvent::KeyRelease, Qt::Key_Direction_L, 0,
+ QString(), false, 0,
+ scancode, msg.wParam, nModifiers);
+ dirStatus = 0;
+ } else if (dirStatus == VK_RSHIFT
+ && ( (msg.wParam == VK_SHIFT && GetKeyState(VK_RCONTROL))
+ || (msg.wParam == VK_CONTROL && GetKeyState(VK_RSHIFT)))) {
+ k0 = q->sendKeyEvent(widget, grab, QEvent::KeyPress, Qt::Key_Direction_R,
+ 0, QString(), false, 0,
+ scancode, msg.wParam, nModifiers);
+ k1 = q->sendKeyEvent(widget, grab, QEvent::KeyRelease, Qt::Key_Direction_R,
+ 0, QString(), false, 0,
+ scancode, msg.wParam, nModifiers);
+ dirStatus = 0;
+ } else {
+ dirStatus = 0;
+ }
+ } else {
+ dirStatus = 0;
+ }
+ }
+ }
+
+ // IME will process these keys, so simply return
+ if(msg.wParam == VK_PROCESSKEY)
+ return true;
+
+ // Ignore invalid virtual keycodes (see bugs 127424, QTBUG-3630)
+ if (msg.wParam == 0 || msg.wParam == 0xFF)
+ return true;
+
+ // Translate VK_* (native) -> Key_* (Qt) keys
+ // If it's a dead key, we cannot use the toKeyOrUnicode() function, since that will change
+ // the internal state of the keyboard driver, resulting in that dead keys no longer works.
+ // ..also if we're typing numbers on the keypad, while holding down the Alt modifier.
+ int code = 0;
+ if (isNumpad && (nModifiers & AltAny)) {
+ code = winceKeyBend(msg.wParam);
+ } else if (!isDeadKey) {
+ unsigned char kbdBuffer[256]; // Will hold the complete keyboard state
+ GetKeyboardState(kbdBuffer);
+ code = toKeyOrUnicode(msg.wParam, scancode, kbdBuffer);
+ }
+
+ // Invert state logic:
+ // If the key actually pressed is a modifier key, then we remove its modifier key from the
+ // state, since a modifier-key can't have itself as a modifier
+ if (code == Qt::Key_Control)
+ state = state ^ Qt::ControlModifier;
+ else if (code == Qt::Key_Shift)
+ state = state ^ Qt::ShiftModifier;
+ else if (code == Qt::Key_Alt)
+ state = state ^ Qt::AltModifier;
+
+ // If the bit 24 of lParm is set you received a enter,
+ // otherwise a Return. (This is the extended key bit)
+ if ((code == Qt::Key_Return) && (msg.lParam & 0x1000000))
+ code = Qt::Key_Enter;
+
+ // All cursor keys without extended bit
+ if (!(msg.lParam & 0x1000000)) {
+ switch (code) {
+ case Qt::Key_Left:
+ case Qt::Key_Right:
+ case Qt::Key_Up:
+ case Qt::Key_Down:
+ case Qt::Key_PageUp:
+ case Qt::Key_PageDown:
+ case Qt::Key_Home:
+ case Qt::Key_End:
+ case Qt::Key_Insert:
+ case Qt::Key_Delete:
+ case Qt::Key_Asterisk:
+ case Qt::Key_Plus:
+ case Qt::Key_Minus:
+ case Qt::Key_Period:
+ case Qt::Key_0:
+ case Qt::Key_1:
+ case Qt::Key_2:
+ case Qt::Key_3:
+ case Qt::Key_4:
+ case Qt::Key_5:
+ case Qt::Key_6:
+ case Qt::Key_7:
+ case Qt::Key_8:
+ case Qt::Key_9:
+ state |= ((msg.wParam >= '0' && msg.wParam <= '9')
+ || (msg.wParam >= VK_OEM_PLUS && msg.wParam <= VK_OEM_3))
+ ? 0 : Qt::KeypadModifier;
+ default:
+ if ((uint)msg.lParam == 0x004c0001 || (uint)msg.lParam == 0xc04c0001)
+ state |= Qt::KeypadModifier;
+ break;
+ }
+ }
+ // Other keys with with extended bit
+ else {
+ switch (code) {
+ case Qt::Key_Enter:
+ case Qt::Key_Slash:
+ case Qt::Key_NumLock:
+ state |= Qt::KeypadModifier;
+ default:
+ break;
+ }
+ }
+
+ // KEYDOWN ---------------------------------------------------------------------------------
+ if (msgType == WM_KEYDOWN || msgType == WM_IME_KEYDOWN || msgType == WM_SYSKEYDOWN) {
+ // Get the last record of this key press, so we can validate the current state
+ // The record is not removed from the list
+ KeyRecord *rec = key_recorder.findKey(msg.wParam, false);
+
+ // If rec's state doesn't match the current state, something has changed behind our back
+ // (Consumed by modal widget is one possibility) So, remove the record from the list
+ // This will stop the auto-repeat of the key, should a modifier change, for example
+ if (rec && rec->state != state) {
+ key_recorder.findKey(msg.wParam, true);
+ rec = 0;
+ }
+
+ // Find unicode character from Windows Message Queue
+ MSG wm_char;
+ UINT charType = (msgType == WM_KEYDOWN
+ ? WM_CHAR
+ : msgType == WM_IME_KEYDOWN ? WM_IME_CHAR : WM_SYSCHAR);
+
+ QChar uch;
+ if (PeekMessage(&wm_char, 0, charType, charType, PM_REMOVE)) {
+ // Found a ?_CHAR
+ uch = QChar((ushort)wm_char.wParam);
+ if (msgType == WM_SYSKEYDOWN && uch.isLetter() && (msg.lParam & KF_ALTDOWN))
+ uch = uch.toLower(); // (See doc of WM_SYSCHAR) Alt-letter
+ if (!code && !uch.row())
+ code = asciiToKeycode(uch.cell(), state);
+ }
+
+ // Special handling for the WM_IME_KEYDOWN message. Microsoft IME (Korean) will not
+ // generate a WM_IME_CHAR message corresponding to this message. We might get wrong
+ // results, if we map this virtual key-code directly (for eg '?' US layouts). So try
+ // to find the correct key using the current message parameters & keyboard state.
+ if (uch.isNull() && msgType == WM_IME_KEYDOWN) {
+ BYTE keyState[256];
+ wchar_t newKey[3] = {0};
+ GetKeyboardState(keyState);
+ int val = ToUnicode(vk_key, scancode, keyState, newKey, 2, 0);
+ if (val == 1) {
+ uch = QChar(newKey[0]);
+ } else {
+ // If we are still not able to find a unicode key, pass the WM_IME_KEYDOWN
+ // message to DefWindowProc() for generating a proper WM_KEYDOWN.
+ return false;
+ }
+ }
+
+ // If no ?_CHAR was found in the queue; deduct character from the ?_KEYDOWN parameters
+ if (uch.isNull()) {
+ if (msg.wParam == VK_DELETE) {
+ uch = QChar(QLatin1Char(0x7f)); // Windows doesn't know this one.
+ } else {
+ if (msgType != WM_SYSKEYDOWN || !code) {
+ UINT map = MapVirtualKey(msg.wParam, 2);
+ // If the high bit of the return value is set, it's a deadkey
+ if (!(map & 0x80000000))
+ uch = QChar((ushort)map);
+ }
+ }
+ if (!code && !uch.row())
+ code = asciiToKeycode(uch.cell(), state);
+ }
+
+ // Special handling of global Windows hotkeys
+ if (state == Qt::AltModifier) {
+ switch (code) {
+ case Qt::Key_Escape:
+ case Qt::Key_Tab:
+ case Qt::Key_Enter:
+ case Qt::Key_F4:
+ return false; // Send the event on to Windows
+ case Qt::Key_Space:
+ // do not pass this key to windows, we will process it ourselves
+ qt_show_system_menu(widget->window());
+ return true;
+ default:
+ break;
+ }
+ }
+
+ // Map SHIFT + Tab to SHIFT + BackTab, QShortcutMap knows about this translation
+ if (code == Qt::Key_Tab && (state & Qt::ShiftModifier) == Qt::ShiftModifier)
+ code = Qt::Key_Backtab;
+
+ // If we have a record, it means that the key is already pressed, the state is the same
+ // so, we have an auto-repeating key
+ if (rec) {
+ if (code < Qt::Key_Shift || code > Qt::Key_ScrollLock) {
+ k0 = q->sendKeyEvent(widget, grab, QEvent::KeyRelease, code,
+ Qt::KeyboardModifier(state), rec->text, true, 0,
+ scancode, msg.wParam, nModifiers);
+ k1 = q->sendKeyEvent(widget, grab, QEvent::KeyPress, code,
+ Qt::KeyboardModifier(state), rec->text, true, 0,
+ scancode, msg.wParam, nModifiers);
+ }
+ }
+ // No record of the key being previous pressed, so we now send a QEvent::KeyPress event,
+ // and store the key data into our records.
+ else {
+ QString text;
+ if (!uch.isNull())
+ text += uch;
+ char a = uch.row() ? 0 : uch.cell();
+ key_recorder.storeKey(msg.wParam, a, state, text);
+ k0 = q->sendKeyEvent(widget, grab, QEvent::KeyPress, code, Qt::KeyboardModifier(state),
+ text, false, 0, scancode, msg.wParam, nModifiers);
+
+ bool store = true;
+ // Alt+<alphanumerical> go to the Win32 menu system if unhandled by Qt
+#if !defined(Q_OS_WINCE)
+ if (msgType == WM_SYSKEYDOWN && !k0 && a) {
+ HWND parent = GetParent(widget->internalWinId());
+ while (parent) {
+ if (GetMenu(parent)) {
+ SendMessage(parent, WM_SYSCOMMAND, SC_KEYMENU, a);
+ store = false;
+ k0 = true;
+ break;
+ }
+ parent = GetParent(parent);
+ }
+ }
+#endif
+ if (!store)
+ key_recorder.findKey(msg.wParam, true);
+ }
+ }
+
+ // KEYUP -----------------------------------------------------------------------------------
+ else {
+ // Try to locate the key in our records, and remove it if it exists.
+ // The key may not be in our records if, for example, the down event was handled by
+ // win32 natively, or our window gets focus while a key is already press, but now gets
+ // the key release event.
+ KeyRecord* rec = key_recorder.findKey(msg.wParam, true);
+ if (!rec && !(code == Qt::Key_Shift
+ || code == Qt::Key_Control
+ || code == Qt::Key_Meta
+ || code == Qt::Key_Alt)) {
+ // Someone ate the key down event
+ } else {
+ if (!code)
+ code = asciiToKeycode(rec->ascii ? rec->ascii : msg.wParam, state);
+
+ // Map SHIFT + Tab to SHIFT + BackTab, QShortcutMap knows about this translation
+ if (code == Qt::Key_Tab && (state & Qt::ShiftModifier) == Qt::ShiftModifier)
+ code = Qt::Key_Backtab;
+
+ k0 = q->sendKeyEvent(widget, grab, QEvent::KeyRelease, code, Qt::KeyboardModifier(state),
+ (rec ? rec->text : QString()), false, 0, scancode, msg.wParam, nModifiers);
+
+ // don't pass Alt to Windows unless we are embedded in a non-Qt window
+#if !defined(Q_OS_WINCE)
+ if (code == Qt::Key_Alt) {
+ k0 = true;
+ HWND parent = GetParent(widget->internalWinId());
+ while (parent) {
+ if (!QWidget::find(parent) && GetMenu(parent)) {
+ k0 = false;
+ break;
+ }
+ parent = GetParent(parent);
+ }
+ }
+#endif
+ }
+ }
+ }
+
+ // Return true, if a QKeyEvent was sent to a widget
+ return k0 || k1;
+}
+
+
+// QKeyMapper (Windows) implementation -------------------------------------------------[ start ]---
+
+bool QKeyMapper::sendKeyEvent(QWidget *widget, bool grab,
+ QEvent::Type type, int code, Qt::KeyboardModifiers modifiers,
+ const QString &text, bool autorepeat, int count,
+ quint32 nativeScanCode, quint32 nativeVirtualKey, quint32 nativeModifiers,
+ bool *)
+{
+#if defined(Q_OS_WINCE)
+ Q_UNUSED(grab);
+#endif
+ Q_UNUSED(count);
+#if defined QT3_SUPPORT && !defined(QT_NO_SHORTCUT)
+ if (type == QEvent::KeyPress
+ && !grab
+ && QApplicationPrivate::instance()->use_compat()) {
+ // send accel events if the keyboard is not grabbed
+ QKeyEventEx a(type, code, modifiers,
+ text, autorepeat, qMax(1, int(text.length())),
+ nativeScanCode, nativeVirtualKey, nativeModifiers);
+ if (QApplicationPrivate::instance()->qt_tryAccelEvent(widget, &a))
+ return true;
+ }
+#else
+ Q_UNUSED(grab);
+#endif
+ if (!widget->isEnabled())
+ return false;
+
+ QKeyEventEx e(type, code, modifiers,
+ text, autorepeat, qMax(1, int(text.length())),
+ nativeScanCode, nativeVirtualKey, nativeModifiers);
+ QETWidget::sendSpontaneousEvent(widget, &e);
+
+ if (!isModifierKey(code)
+ && modifiers == Qt::AltModifier
+ && ((code >= Qt::Key_A && code <= Qt::Key_Z) || (code >= Qt::Key_0 && code <= Qt::Key_9))
+ && type == QEvent::KeyPress
+ && !e.isAccepted())
+ QApplication::beep(); // Emulate windows behavior
+
+ return e.isAccepted();
+}
+
+QT_END_NAMESPACE
diff --git a/src/gui/platforms/win/qmime_win.cpp b/src/gui/platforms/win/qmime_win.cpp
new file mode 100644
index 0000000000..feb8b78eca
--- /dev/null
+++ b/src/gui/platforms/win/qmime_win.cpp
@@ -0,0 +1,1556 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qmime.h"
+
+#include "qimagereader.h"
+#include "qimagewriter.h"
+#include "qdatastream.h"
+#include "qbuffer.h"
+#include "qt_windows.h"
+#include "qapplication_p.h"
+#include "qtextcodec.h"
+#include "qregexp.h"
+#include "qalgorithms.h"
+#include "qmap.h"
+#include "qdnd_p.h"
+#include <shlobj.h>
+#include "qurl.h"
+#include "qvariant.h"
+#include "qtextdocument.h"
+#include "qdir.h"
+
+#if defined(Q_OS_WINCE)
+#include "qguifunctions_wince.h"
+#endif
+
+QT_BEGIN_NAMESPACE
+
+#ifndef QT_NO_IMAGEFORMAT_BMP
+#ifndef CF_DIBV5
+#define CF_DIBV5 17
+#endif
+/* The MSVC compilers allows multi-byte characters, that has the behavior of
+ * that each character gets shifted into position. 0x73524742 below is for MSVC
+ * equivalent to doing 'sRGB', but this does of course not work
+ * on conformant C++ compilers. */
+#define BMP_LCS_sRGB 0x73524742
+#define BMP_LCS_GM_IMAGES 0x00000004L
+
+struct _CIEXYZ {
+ long ciexyzX, ciexyzY, ciexyzZ;
+};
+
+struct _CIEXYZTRIPLE {
+ _CIEXYZ ciexyzRed, ciexyzGreen, ciexyzBlue;
+};
+
+struct BMP_BITMAPV5HEADER {
+ DWORD bV5Size;
+ LONG bV5Width;
+ LONG bV5Height;
+ WORD bV5Planes;
+ WORD bV5BitCount;
+ DWORD bV5Compression;
+ DWORD bV5SizeImage;
+ LONG bV5XPelsPerMeter;
+ LONG bV5YPelsPerMeter;
+ DWORD bV5ClrUsed;
+ DWORD bV5ClrImportant;
+ DWORD bV5RedMask;
+ DWORD bV5GreenMask;
+ DWORD bV5BlueMask;
+ DWORD bV5AlphaMask;
+ DWORD bV5CSType;
+ _CIEXYZTRIPLE bV5Endpoints;
+ DWORD bV5GammaRed;
+ DWORD bV5GammaGreen;
+ DWORD bV5GammaBlue;
+ DWORD bV5Intent;
+ DWORD bV5ProfileData;
+ DWORD bV5ProfileSize;
+ DWORD bV5Reserved;
+};
+static const int BMP_BITFIELDS = 3;
+
+extern bool qt_read_dib(QDataStream&, QImage&); // qimage.cpp
+extern bool qt_write_dib(QDataStream&, QImage); // qimage.cpp
+static bool qt_write_dibv5(QDataStream &s, QImage image);
+static bool qt_read_dibv5(QDataStream &s, QImage &image);
+#endif
+
+//#define QMIME_DEBUG
+
+
+// helpers for using global memory
+
+static int getCf(const FORMATETC &formatetc)
+{
+ return formatetc.cfFormat;
+}
+
+static FORMATETC setCf(int cf)
+{
+ FORMATETC formatetc;
+ formatetc.cfFormat = cf;
+ formatetc.dwAspect = DVASPECT_CONTENT;
+ formatetc.lindex = -1;
+ formatetc.ptd = NULL;
+ formatetc.tymed = TYMED_HGLOBAL;
+ return formatetc;
+}
+
+static bool setData(const QByteArray &data, STGMEDIUM *pmedium)
+{
+ HGLOBAL hData = GlobalAlloc(0, data.size());
+ if (!hData)
+ return false;
+
+ void *out = GlobalLock(hData);
+ memcpy(out, data.data(), data.size());
+ GlobalUnlock(hData);
+ pmedium->tymed = TYMED_HGLOBAL;
+ pmedium->hGlobal = hData;
+ pmedium->pUnkForRelease = 0;
+ return true;
+}
+
+static QByteArray getData(int cf, IDataObject *pDataObj)
+{
+ QByteArray data;
+ FORMATETC formatetc = setCf(cf);
+ STGMEDIUM s;
+ if (pDataObj->GetData(&formatetc, &s) == S_OK) {
+ DWORD * val = (DWORD*)GlobalLock(s.hGlobal);
+ data = QByteArray::fromRawData((char*)val, GlobalSize(s.hGlobal));
+ data.detach();
+ GlobalUnlock(s.hGlobal);
+ ReleaseStgMedium(&s);
+ } else {
+ //Try reading IStream data
+ formatetc.tymed = TYMED_ISTREAM;
+ if (pDataObj->GetData(&formatetc, &s) == S_OK) {
+ char szBuffer[4096];
+ ULONG actualRead = 0;
+ LARGE_INTEGER pos = {{0, 0}};
+ //Move to front (can fail depending on the data model implemented)
+ HRESULT hr = s.pstm->Seek(pos, STREAM_SEEK_SET, NULL);
+ while(SUCCEEDED(hr)){
+ hr = s.pstm->Read(szBuffer, sizeof(szBuffer), &actualRead);
+ if (SUCCEEDED(hr) && actualRead > 0) {
+ data += QByteArray::fromRawData(szBuffer, actualRead);
+ }
+ if (actualRead != sizeof(szBuffer))
+ break;
+ }
+ data.detach();
+ ReleaseStgMedium(&s);
+ }
+ }
+ return data;
+}
+
+static bool canGetData(int cf, IDataObject * pDataObj)
+{
+ FORMATETC formatetc = setCf(cf);
+ if (pDataObj->QueryGetData(&formatetc) != S_OK){
+ formatetc.tymed = TYMED_ISTREAM;
+ return pDataObj->QueryGetData(&formatetc) == S_OK;
+ }
+ return true;
+}
+
+class QWindowsMimeList
+{
+public:
+ QWindowsMimeList();
+ ~QWindowsMimeList();
+ void addWindowsMime(QWindowsMime * mime);
+ void removeWindowsMime(QWindowsMime * mime);
+ QList<QWindowsMime*> windowsMimes();
+
+private:
+ void init();
+ bool initialized;
+ QList<QWindowsMime*> mimes;
+};
+
+Q_GLOBAL_STATIC(QWindowsMimeList, theMimeList);
+
+
+/*!
+ \class QWindowsMime
+ \brief The QWindowsMime class maps open-standard MIME to Window Clipboard formats.
+ \ingroup draganddrop
+
+ Qt's drag-and-drop and clipboard facilities use the MIME standard.
+ On X11, this maps trivially to the Xdnd protocol, but on Windows
+ although some applications use MIME types to describe clipboard
+ formats, others use arbitrary non-standardized naming conventions,
+ or unnamed built-in formats of Windows.
+
+ By instantiating subclasses of QWindowsMime that provide conversions
+ between Windows Clipboard and MIME formats, you can convert
+ proprietary clipboard formats to MIME formats.
+
+ Qt has predefined support for the following Windows Clipboard formats:
+
+ \table
+ \header \o Windows Format \o Equivalent MIME type
+ \row \o \c CF_UNICODETEXT \o \c text/plain
+ \row \o \c CF_TEXT \o \c text/plain
+ \row \o \c CF_DIB \o \c{image/xyz}, where \c xyz is
+ a \l{QImageWriter::supportedImageFormats()}{Qt image format}
+ \row \o \c CF_HDROP \o \c text/uri-list
+ \row \o \c CF_INETURL \o \c text/uri-list
+ \row \o \c CF_HTML \o \c text/html
+ \endtable
+
+ An example use of this class would be to map the Windows Metafile
+ clipboard format (\c CF_METAFILEPICT) to and from the MIME type
+ \c{image/x-wmf}. This conversion might simply be adding or removing
+ a header, or even just passing on the data. See \l{Drag and Drop}
+ for more information on choosing and definition MIME types.
+
+ You can check if a MIME type is convertible using canConvertFromMime() and
+ can perform conversions with convertToMime() and convertFromMime().
+*/
+
+/*!
+Constructs a new conversion object, adding it to the globally accessed
+list of available converters.
+*/
+QWindowsMime::QWindowsMime()
+{
+ theMimeList()->addWindowsMime(this);
+}
+
+/*!
+Destroys a conversion object, removing it from the global
+list of available converters.
+*/
+QWindowsMime::~QWindowsMime()
+{
+ theMimeList()->removeWindowsMime(this);
+}
+
+
+/*!
+ Registers the MIME type \a mime, and returns an ID number
+ identifying the format on Windows.
+*/
+int QWindowsMime::registerMimeType(const QString &mime)
+{
+ int f = RegisterClipboardFormat(reinterpret_cast<const wchar_t *> (mime.utf16()));
+ if (!f)
+ qErrnoWarning("QWindowsMime::registerMimeType: Failed to register clipboard format");
+
+ return f;
+}
+
+
+/*!
+\fn bool QWindowsMime::canConvertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData) const
+
+ Returns true if the converter can convert from the \a mimeData to
+ the format specified in \a formatetc.
+
+ All subclasses must reimplement this pure virtual function.
+*/
+
+/*!
+ \fn bool QWindowsMime::canConvertToMime(const QString &mimeType, IDataObject *pDataObj) const
+
+ Returns true if the converter can convert to the \a mimeType from
+ the available formats in \a pDataObj.
+
+ All subclasses must reimplement this pure virtual function.
+*/
+
+/*!
+\fn QString QWindowsMime::mimeForFormat(const FORMATETC &formatetc) const
+
+ Returns the mime type that will be created form the format specified
+ in \a formatetc, or an empty string if this converter does not support
+ \a formatetc.
+
+ All subclasses must reimplement this pure virtual function.
+*/
+
+/*!
+\fn QVector<FORMATETC> QWindowsMime::formatsForMime(const QString &mimeType, const QMimeData *mimeData) const
+
+ Returns a QVector of FORMATETC structures representing the different windows clipboard
+ formats that can be provided for the \a mimeType from the \a mimeData.
+
+ All subclasses must reimplement this pure virtual function.
+*/
+
+/*!
+ \fn QVariant QWindowsMime::convertToMime(const QString &mimeType, IDataObject *pDataObj,
+ QVariant::Type preferredType) const
+
+ Returns a QVariant containing the converted data for \a mimeType from \a pDataObj.
+ If possible the QVariant should be of the \a preferredType to avoid needless conversions.
+
+ All subclasses must reimplement this pure virtual function.
+*/
+
+/*!
+\fn bool QWindowsMime::convertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData, STGMEDIUM * pmedium) const
+
+ Convert the \a mimeData to the format specified in \a formatetc.
+ The converted data should then be placed in \a pmedium structure.
+
+ Return true if the conversion was successful.
+
+ All subclasses must reimplement this pure virtual function.
+*/
+
+
+QWindowsMime *QWindowsMime::converterFromMime(const FORMATETC &formatetc, const QMimeData *mimeData)
+{
+ QList<QWindowsMime*> mimes = theMimeList()->windowsMimes();
+ for (int i=mimes.size()-1; i>=0; --i) {
+ if (mimes.at(i)->canConvertFromMime(formatetc, mimeData))
+ return mimes.at(i);
+ }
+ return 0;
+}
+
+QWindowsMime *QWindowsMime::converterToMime(const QString &mimeType, IDataObject *pDataObj)
+{
+ QList<QWindowsMime*> mimes = theMimeList()->windowsMimes();
+ for (int i=mimes.size()-1; i>=0; --i) {
+ if (mimes.at(i)->canConvertToMime(mimeType, pDataObj))
+ return mimes.at(i);
+ }
+ return 0;
+}
+
+QVector<FORMATETC> QWindowsMime::allFormatsForMime(const QMimeData *mimeData)
+{
+ QList<QWindowsMime*> mimes = theMimeList()->windowsMimes();
+ QVector<FORMATETC> formatics;
+ formatics.reserve(20);
+#ifndef QT_NO_DRAGANDDROP
+ QStringList formats = QInternalMimeData::formatsHelper(mimeData);
+ for (int f=0; f<formats.size(); ++f) {
+ for (int i=mimes.size()-1; i>=0; --i)
+ formatics += mimes.at(i)->formatsForMime(formats.at(f), mimeData);
+ }
+#else
+ Q_UNUSED(mimeData);
+#endif //QT_NO_DRAGANDDROP
+ return formatics;
+}
+
+QStringList QWindowsMime::allMimesForFormats(IDataObject *pDataObj)
+{
+ QList<QWindowsMime*> mimes = theMimeList()->windowsMimes();
+ QStringList formats;
+ LPENUMFORMATETC FAR fmtenum;
+ HRESULT hr = pDataObj->EnumFormatEtc(DATADIR_GET, &fmtenum);
+
+ if (hr == NOERROR) {
+ FORMATETC fmtetc;
+ while (S_OK == fmtenum->Next(1, &fmtetc, 0)) {
+#if defined(QMIME_DEBUG) && !defined(Q_OS_WINCE)
+ qDebug("QWindowsMime::allMimesForFormats()");
+ wchar_t buf[256] = {0};
+ GetClipboardFormatName(fmtetc.cfFormat, buf, 255);
+ qDebug("CF = %d : %s", fmtetc.cfFormat, QString::fromWCharArray(buf));
+#endif
+ for (int i=mimes.size()-1; i>=0; --i) {
+ QString format = mimes.at(i)->mimeForFormat(fmtetc);
+ if (!format.isEmpty() && !formats.contains(format)) {
+ formats += format;
+ }
+ }
+ // as documented in MSDN to avoid possible memleak
+ if (fmtetc.ptd)
+ CoTaskMemFree(fmtetc.ptd);
+ }
+ fmtenum->Release();
+ }
+
+ return formats;
+}
+
+
+class QWindowsMimeText : public QWindowsMime
+{
+public:
+ bool canConvertToMime(const QString &mimeType, IDataObject *pDataObj) const;
+ QVariant convertToMime(const QString &mime, LPDATAOBJECT pDataObj, QVariant::Type preferredType) const;
+ QString mimeForFormat(const FORMATETC &formatetc) const;
+ bool canConvertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData) const;
+ bool convertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData, STGMEDIUM *pmedium) const;
+ QVector<FORMATETC> formatsForMime(const QString &mimeType, const QMimeData *mimeData) const;
+};
+
+bool QWindowsMimeText::canConvertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData) const
+{
+ int cf = getCf(formatetc);
+ return (cf == CF_UNICODETEXT || cf == CF_TEXT) && mimeData->hasText();
+}
+
+/*
+text/plain is defined as using CRLF, but so many programs don't,
+and programmers just look for '\n' in strings.
+Windows really needs CRLF, so we ensure it here.
+*/
+bool QWindowsMimeText::convertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData, STGMEDIUM *pmedium) const
+{
+ if (canConvertFromMime(formatetc, mimeData)) {
+ QByteArray data;
+ int cf = getCf(formatetc);
+ if (cf == CF_TEXT) {
+ data = mimeData->text().toLocal8Bit();
+ // Anticipate required space for CRLFs at 1/40
+ int maxsize=data.size()+data.size()/40+3;
+ QByteArray r(maxsize, '\0');
+ char* o = r.data();
+ const char* d = data.data();
+ const int s = data.size();
+ bool cr=false;
+ int j=0;
+ for (int i=0; i<s; i++) {
+ char c = d[i];
+ if (c=='\r')
+ cr=true;
+ else {
+ if (c=='\n') {
+ if (!cr)
+ o[j++]='\r';
+ }
+ cr=false;
+ }
+ o[j++]=c;
+ if (j+3 >= maxsize) {
+ maxsize += maxsize/4;
+ r.resize(maxsize);
+ o = r.data();
+ }
+ }
+ o[j]=0;
+ return setData(r, pmedium);
+ } else if (cf == CF_UNICODETEXT) {
+ QString str = mimeData->text();
+ const QChar *u = str.unicode();
+ QString res;
+ const int s = str.length();
+ int maxsize = s + s/40 + 3;
+ res.resize(maxsize);
+ int ri = 0;
+ bool cr = false;
+ for (int i=0; i < s; ++i) {
+ if (*u == QLatin1Char('\r'))
+ cr = true;
+ else {
+ if (*u == QLatin1Char('\n') && !cr)
+ res[ri++] = QLatin1Char('\r');
+ cr = false;
+ }
+ res[ri++] = *u;
+ if (ri+3 >= maxsize) {
+ maxsize += maxsize/4;
+ res.resize(maxsize);
+ }
+ ++u;
+ }
+ res.truncate(ri);
+ const int byteLength = res.length() * sizeof(ushort);
+ QByteArray r(byteLength + 2, '\0');
+ memcpy(r.data(), res.unicode(), byteLength);
+ r[byteLength] = 0;
+ r[byteLength+1] = 0;
+ return setData(r, pmedium);
+ }
+ }
+ return false;
+}
+
+bool QWindowsMimeText::canConvertToMime(const QString &mimeType, IDataObject *pDataObj) const
+{
+ return mimeType.startsWith(QLatin1String("text/plain"))
+ && (canGetData(CF_UNICODETEXT, pDataObj)
+ || canGetData(CF_TEXT, pDataObj));
+}
+
+QString QWindowsMimeText::mimeForFormat(const FORMATETC &formatetc) const
+{
+ int cf = getCf(formatetc);
+ if (cf == CF_UNICODETEXT || cf == CF_TEXT)
+ return QLatin1String("text/plain");
+ return QString();
+}
+
+
+QVector<FORMATETC> QWindowsMimeText::formatsForMime(const QString &mimeType, const QMimeData *mimeData) const
+{
+ QVector<FORMATETC> formatics;
+ if (mimeType.startsWith(QLatin1String("text/plain")) && mimeData->hasText()) {
+ formatics += setCf(CF_UNICODETEXT);
+ formatics += setCf(CF_TEXT);
+ }
+ return formatics;
+}
+
+QVariant QWindowsMimeText::convertToMime(const QString &mime, LPDATAOBJECT pDataObj, QVariant::Type preferredType) const
+{
+ QVariant ret;
+
+ if (canConvertToMime(mime, pDataObj)) {
+ QString str;
+ QByteArray data = getData(CF_UNICODETEXT, pDataObj);
+ if (!data.isEmpty()) {
+ str = QString::fromWCharArray((const wchar_t *)data.data());
+ str.replace(QLatin1String("\r\n"), QLatin1String("\n"));
+ } else {
+ data = getData(CF_TEXT, pDataObj);
+ if (!data.isEmpty()) {
+ const char* d = data.data();
+ const int s = qstrlen(d);
+ QByteArray r(data.size()+1, '\0');
+ char* o = r.data();
+ int j=0;
+ for (int i=0; i<s; i++) {
+ char c = d[i];
+ if (c!='\r')
+ o[j++]=c;
+ }
+ o[j]=0;
+ str = QString::fromLocal8Bit(r);
+ }
+ }
+ if (preferredType == QVariant::String)
+ ret = str;
+ else
+ ret = str.toUtf8();
+ }
+
+ return ret;
+}
+
+class QWindowsMimeURI : public QWindowsMime
+{
+public:
+ QWindowsMimeURI();
+ bool canConvertToMime(const QString &mimeType, IDataObject *pDataObj) const;
+ QVariant convertToMime(const QString &mime, LPDATAOBJECT pDataObj, QVariant::Type preferredType) const;
+ QString mimeForFormat(const FORMATETC &formatetc) const;
+ bool canConvertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData) const;
+ bool convertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData, STGMEDIUM *pmedium) const;
+ QVector<FORMATETC> formatsForMime(const QString &mimeType, const QMimeData *mimeData) const;
+private:
+ int CF_INETURL_W; // wide char version
+ int CF_INETURL;
+};
+
+QWindowsMimeURI::QWindowsMimeURI()
+{
+ CF_INETURL_W = QWindowsMime::registerMimeType(QLatin1String("UniformResourceLocatorW"));
+ CF_INETURL = QWindowsMime::registerMimeType(QLatin1String("UniformResourceLocator"));
+}
+
+bool QWindowsMimeURI::canConvertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData) const
+{
+ if (getCf(formatetc) == CF_HDROP) {
+ QList<QUrl> urls = mimeData->urls();
+ for (int i=0; i<urls.size(); i++) {
+ if (!urls.at(i).toLocalFile().isEmpty())
+ return true;
+ }
+ }
+ return (getCf(formatetc) == CF_INETURL_W || getCf(formatetc) == CF_INETURL) && mimeData->hasFormat(QLatin1String("text/uri-list"));
+}
+
+bool QWindowsMimeURI::convertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData, STGMEDIUM *pmedium) const
+{
+ if (canConvertFromMime(formatetc, mimeData)) {
+ if (getCf(formatetc) == CF_HDROP) {
+ QList<QUrl> urls = mimeData->urls();
+ QStringList fileNames;
+ int size = sizeof(DROPFILES)+2;
+ for (int i=0; i<urls.size(); i++) {
+ QString fn = QDir::toNativeSeparators(urls.at(i).toLocalFile());
+ if (!fn.isEmpty()) {
+ size += sizeof(ushort) * (fn.length() + 1);
+ fileNames.append(fn);
+ }
+ }
+
+ QByteArray result(size, '\0');
+ DROPFILES* d = (DROPFILES*)result.data();
+ d->pFiles = sizeof(DROPFILES);
+ GetCursorPos(&d->pt); // try
+ d->fNC = true;
+ char* files = ((char*)d) + d->pFiles;
+
+ d->fWide = true;
+ wchar_t* f = (wchar_t*)files;
+ for (int i=0; i<fileNames.size(); i++) {
+ int l = fileNames.at(i).length();
+ memcpy(f, fileNames.at(i).utf16(), l * sizeof(ushort));
+ f += l;
+ *f++ = 0;
+ }
+ *f = 0;
+
+ return setData(result, pmedium);
+ } else if (getCf(formatetc) == CF_INETURL_W) {
+ QList<QUrl> urls = mimeData->urls();
+ QByteArray result;
+ if (!urls.isEmpty()) {
+ QString url = urls.at(0).toString();
+ result = QByteArray((const char *)url.utf16(), url.length() * sizeof(ushort));
+ }
+ result.append('\0');
+ result.append('\0');
+ return setData(result, pmedium);
+ } else if (getCf(formatetc) == CF_INETURL) {
+ QList<QUrl> urls = mimeData->urls();
+ QByteArray result;
+ if (!urls.isEmpty())
+ result = urls.at(0).toString().toLocal8Bit();
+ return setData(result, pmedium);
+ }
+ }
+
+ return false;
+}
+
+bool QWindowsMimeURI::canConvertToMime(const QString &mimeType, IDataObject *pDataObj) const
+{
+ return mimeType == QLatin1String("text/uri-list")
+ && (canGetData(CF_HDROP, pDataObj) || canGetData(CF_INETURL_W, pDataObj) || canGetData(CF_INETURL, pDataObj));
+}
+
+QString QWindowsMimeURI::mimeForFormat(const FORMATETC &formatetc) const
+{
+ QString format;
+ if (getCf(formatetc) == CF_HDROP || getCf(formatetc) == CF_INETURL_W || getCf(formatetc) == CF_INETURL)
+ format = QLatin1String("text/uri-list");
+ return format;
+}
+
+QVector<FORMATETC> QWindowsMimeURI::formatsForMime(const QString &mimeType, const QMimeData *mimeData) const
+{
+ QVector<FORMATETC> formatics;
+ if (mimeType == QLatin1String("text/uri-list")) {
+ if (canConvertFromMime(setCf(CF_HDROP), mimeData))
+ formatics += setCf(CF_HDROP);
+ if (canConvertFromMime(setCf(CF_INETURL_W), mimeData))
+ formatics += setCf(CF_INETURL_W);
+ if (canConvertFromMime(setCf(CF_INETURL), mimeData))
+ formatics += setCf(CF_INETURL);
+ }
+ return formatics;
+}
+
+QVariant QWindowsMimeURI::convertToMime(const QString &mimeType, LPDATAOBJECT pDataObj, QVariant::Type preferredType) const
+{
+ if (mimeType == QLatin1String("text/uri-list")) {
+ if (canGetData(CF_HDROP, pDataObj)) {
+ QByteArray texturi;
+ QList<QVariant> urls;
+
+ QByteArray data = getData(CF_HDROP, pDataObj);
+ if (data.isEmpty())
+ return QVariant();
+
+ LPDROPFILES hdrop = (LPDROPFILES)data.data();
+ if (hdrop->fWide) {
+ const wchar_t* filesw = (const wchar_t *)(data.data() + hdrop->pFiles);
+ int i = 0;
+ while (filesw[i]) {
+ QString fileurl = QString::fromWCharArray(filesw + i);
+ urls += QUrl::fromLocalFile(fileurl);
+ i += fileurl.length()+1;
+ }
+ } else {
+ const char* files = (const char *)data.data() + hdrop->pFiles;
+ int i=0;
+ while (files[i]) {
+ urls += QUrl::fromLocalFile(QString::fromLocal8Bit(files+i));
+ i += int(strlen(files+i))+1;
+ }
+ }
+
+ if (preferredType == QVariant::Url && urls.size() == 1)
+ return urls.at(0);
+ else if (!urls.isEmpty())
+ return urls;
+ } else if (canGetData(CF_INETURL_W, pDataObj)) {
+ QByteArray data = getData(CF_INETURL_W, pDataObj);
+ if (data.isEmpty())
+ return QVariant();
+ return QUrl(QString::fromWCharArray((const wchar_t *)data.constData()));
+ } else if (canGetData(CF_INETURL, pDataObj)) {
+ QByteArray data = getData(CF_INETURL, pDataObj);
+ if (data.isEmpty())
+ return QVariant();
+ return QUrl(QString::fromLocal8Bit(data.constData()));
+ }
+ }
+ return QVariant();
+}
+
+class QWindowsMimeHtml : public QWindowsMime
+{
+public:
+ QWindowsMimeHtml();
+
+ // for converting from Qt
+ bool canConvertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData) const;
+ bool convertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData, STGMEDIUM * pmedium) const;
+ QVector<FORMATETC> formatsForMime(const QString &mimeType, const QMimeData *mimeData) const;
+
+ // for converting to Qt
+ bool canConvertToMime(const QString &mimeType, IDataObject *pDataObj) const;
+ QVariant convertToMime(const QString &mime, IDataObject *pDataObj, QVariant::Type preferredType) const;
+ QString mimeForFormat(const FORMATETC &formatetc) const;
+
+private:
+ int CF_HTML;
+};
+
+QWindowsMimeHtml::QWindowsMimeHtml()
+{
+ CF_HTML = QWindowsMime::registerMimeType(QLatin1String("HTML Format"));
+}
+
+QVector<FORMATETC> QWindowsMimeHtml::formatsForMime(const QString &mimeType, const QMimeData *mimeData) const
+{
+ QVector<FORMATETC> formatetcs;
+ if (mimeType == QLatin1String("text/html") && (!mimeData->html().isEmpty()))
+ formatetcs += setCf(CF_HTML);
+ return formatetcs;
+}
+
+QString QWindowsMimeHtml::mimeForFormat(const FORMATETC &formatetc) const
+{
+ if (getCf(formatetc) == CF_HTML)
+ return QLatin1String("text/html");
+ return QString();
+}
+
+bool QWindowsMimeHtml::canConvertToMime(const QString &mimeType, IDataObject *pDataObj) const
+{
+ return mimeType == QLatin1String("text/html") && canGetData(CF_HTML, pDataObj);
+}
+
+
+bool QWindowsMimeHtml::canConvertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData) const
+{
+ return getCf(formatetc) == CF_HTML && (!mimeData->html().isEmpty());
+}
+
+/*
+The windows HTML clipboard format is as follows (xxxxxxxxxx is a 10 integer number giving the positions
+in bytes). Charset used is mostly utf8, but can be different, ie. we have to look for the <meta> charset tag
+
+ Version: 1.0
+ StartHTML:xxxxxxxxxx
+ EndHTML:xxxxxxxxxx
+ StartFragment:xxxxxxxxxx
+ EndFragment:xxxxxxxxxx
+ ...html...
+
+*/
+QVariant QWindowsMimeHtml::convertToMime(const QString &mime, IDataObject *pDataObj, QVariant::Type preferredType) const
+{
+ Q_UNUSED(preferredType);
+ QVariant result;
+ if (canConvertToMime(mime, pDataObj)) {
+ QByteArray html = getData(CF_HTML, pDataObj);
+#ifdef QMIME_DEBUG
+ qDebug("QWindowsMimeHtml::convertToMime");
+ qDebug("raw :");
+ qDebug(html);
+#endif
+ int start = html.indexOf("StartFragment:");
+ int end = html.indexOf("EndFragment:");
+
+ if (start != -1) {
+ int startOffset = start + 14;
+ int i = startOffset;
+ while (html.at(i) != '\r' && html.at(i) != '\n')
+ ++i;
+ QByteArray bytecount = html.mid(startOffset, i - startOffset);
+ start = bytecount.toInt();
+ }
+
+ if (end != -1) {
+ int endOffset = end + 12;
+ int i = endOffset ;
+ while (html.at(i) != '\r' && html.at(i) != '\n')
+ ++i;
+ QByteArray bytecount = html.mid(endOffset , i - endOffset);
+ end = bytecount.toInt();
+ }
+
+ if (end > start && start > 0) {
+ html = "<!--StartFragment-->" + html.mid(start, end - start);
+ html += "<!--EndFragment-->";
+ html.replace('\r', "");
+ result = QString::fromUtf8(html);
+ }
+ }
+ return result;
+}
+
+bool QWindowsMimeHtml::convertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData, STGMEDIUM * pmedium) const
+{
+ if (canConvertFromMime(formatetc, mimeData)) {
+ QByteArray data = mimeData->html().toUtf8();
+ QByteArray result =
+ "Version:1.0\r\n" // 0-12
+ "StartHTML:0000000105\r\n" // 13-35
+ "EndHTML:0000000000\r\n" // 36-55
+ "StartFragment:0000000000\r\n" // 58-86
+ "EndFragment:0000000000\r\n\r\n"; // 87-105
+
+ if (data.indexOf("<!--StartFragment-->") == -1)
+ result += "<!--StartFragment-->";
+ result += data;
+ if (data.indexOf("<!--EndFragment-->") == -1)
+ result += "<!--EndFragment-->";
+
+ // set the correct number for EndHTML
+ QByteArray pos = QString::number(result.size()).toLatin1();
+ memcpy((char *)(result.data() + 53 - pos.length()), pos.constData(), pos.length());
+
+ // set correct numbers for StartFragment and EndFragment
+ pos = QString::number(result.indexOf("<!--StartFragment-->") + 20).toLatin1();
+ memcpy((char *)(result.data() + 79 - pos.length()), pos.constData(), pos.length());
+ pos = QString::number(result.indexOf("<!--EndFragment-->")).toLatin1();
+ memcpy((char *)(result.data() + 103 - pos.length()), pos.constData(), pos.length());
+
+ return setData(result, pmedium);
+ }
+ return false;
+}
+
+
+#ifndef QT_NO_IMAGEFORMAT_BMP
+class QWindowsMimeImage : public QWindowsMime
+{
+public:
+ QWindowsMimeImage();
+ // for converting from Qt
+ bool canConvertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData) const;
+ bool convertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData, STGMEDIUM * pmedium) const;
+ QVector<FORMATETC> formatsForMime(const QString &mimeType, const QMimeData *mimeData) const;
+
+ // for converting to Qt
+ bool canConvertToMime(const QString &mimeType, IDataObject *pDataObj) const;
+ QVariant convertToMime(const QString &mime, IDataObject *pDataObj, QVariant::Type preferredType) const;
+ QString mimeForFormat(const FORMATETC &formatetc) const;
+private:
+ bool hasOriginalDIBV5(IDataObject *pDataObj) const;
+ UINT CF_PNG;
+};
+
+QWindowsMimeImage::QWindowsMimeImage()
+{
+ CF_PNG = RegisterClipboardFormat(L"PNG");
+}
+
+QVector<FORMATETC> QWindowsMimeImage::formatsForMime(const QString &mimeType, const QMimeData *mimeData) const
+{
+ QVector<FORMATETC> formatetcs;
+ if (mimeData->hasImage() && mimeType == QLatin1String("application/x-qt-image")) {
+ //add DIBV5 if image has alpha channel
+ QImage image = qvariant_cast<QImage>(mimeData->imageData());
+ if (!image.isNull() && image.hasAlphaChannel())
+ formatetcs += setCf(CF_DIBV5);
+ formatetcs += setCf(CF_DIB);
+ }
+ return formatetcs;
+}
+
+QString QWindowsMimeImage::mimeForFormat(const FORMATETC &formatetc) const
+{
+ int cf = getCf(formatetc);
+ if (cf == CF_DIB || cf == CF_DIBV5 || cf == int(CF_PNG))
+ return QLatin1String("application/x-qt-image");
+ return QString();
+}
+
+bool QWindowsMimeImage::canConvertToMime(const QString &mimeType, IDataObject *pDataObj) const
+{
+ if ((mimeType == QLatin1String("application/x-qt-image")) &&
+ (canGetData(CF_DIB, pDataObj) || canGetData(CF_PNG, pDataObj)))
+ return true;
+ return false;
+}
+
+bool QWindowsMimeImage::canConvertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData) const
+{
+ int cf = getCf(formatetc);
+ if (mimeData->hasImage()) {
+ if (cf == CF_DIB)
+ return true;
+ else if (cf == CF_DIBV5) {
+ //support DIBV5 conversion only if the image has alpha channel
+ QImage image = qvariant_cast<QImage>(mimeData->imageData());
+ if (!image.isNull() && image.hasAlphaChannel())
+ return true;
+ }
+ }
+ return false;
+}
+
+bool QWindowsMimeImage::convertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData, STGMEDIUM * pmedium) const
+{
+ int cf = getCf(formatetc);
+ if ((cf == CF_DIB || cf == CF_DIBV5) && mimeData->hasImage()) {
+ QImage img = qvariant_cast<QImage>(mimeData->imageData());
+ if (img.isNull())
+ return false;
+ QByteArray ba;
+ QDataStream s(&ba, QIODevice::WriteOnly);
+ s.setByteOrder(QDataStream::LittleEndian);// Intel byte order ####
+ if (cf == CF_DIB) {
+ if (img.format() > QImage::Format_ARGB32)
+ img = img.convertToFormat(QImage::Format_RGB32);
+ if (qt_write_dib(s, img))
+ return setData(ba, pmedium);
+ } else {
+ if (qt_write_dibv5(s, img))
+ return setData(ba, pmedium);
+ }
+ }
+ return false;
+}
+
+bool QWindowsMimeImage::hasOriginalDIBV5(IDataObject *pDataObj) const
+{
+ bool isSynthesized = true;
+ IEnumFORMATETC *pEnum =NULL;
+ HRESULT res = pDataObj->EnumFormatEtc(1, &pEnum);
+ if (res == S_OK && pEnum) {
+ FORMATETC fc;
+ while ((res = pEnum->Next(1, &fc, 0)) == S_OK) {
+ if (fc.ptd)
+ CoTaskMemFree(fc.ptd);
+ if (fc.cfFormat == CF_DIB)
+ break;
+ else if (fc.cfFormat == CF_DIBV5) {
+ isSynthesized = false;
+ break;
+ }
+ }
+ pEnum->Release();
+ }
+ return !isSynthesized;
+}
+
+QVariant QWindowsMimeImage::convertToMime(const QString &mimeType, IDataObject *pDataObj, QVariant::Type preferredType) const
+{
+ Q_UNUSED(preferredType);
+ QVariant result;
+ if (mimeType != QLatin1String("application/x-qt-image"))
+ return result;
+ //Try to convert from a format which has more data
+ //DIBV5, use only if its is not synthesized
+ if (canGetData(CF_DIBV5, pDataObj) && hasOriginalDIBV5(pDataObj)) {
+ QImage img;
+ QByteArray data = getData(CF_DIBV5, pDataObj);
+ QDataStream s(&data, QIODevice::ReadOnly);
+ s.setByteOrder(QDataStream::LittleEndian);
+ if (qt_read_dibv5(s, img)) { // #### supports only 32bit DIBV5
+ return img;
+ }
+ }
+ //PNG, MS Office place this (undocumented)
+ if (canGetData(CF_PNG, pDataObj)) {
+ QImage img;
+ QByteArray data = getData(CF_PNG, pDataObj);
+ if (img.loadFromData(data, "PNG")) {
+ return img;
+ }
+ }
+ //Fallback to DIB
+ if (canGetData(CF_DIB, pDataObj)) {
+ QImage img;
+ QByteArray data = getData(CF_DIB, pDataObj);
+ QDataStream s(&data, QIODevice::ReadOnly);
+ s.setByteOrder(QDataStream::LittleEndian);// Intel byte order ####
+ if (qt_read_dib(s, img)) { // ##### encaps "-14"
+ return img;
+ }
+ }
+ // Failed
+ return result;
+}
+#endif
+
+class QBuiltInMimes : public QWindowsMime
+{
+public:
+ QBuiltInMimes();
+
+ // for converting from Qt
+ bool canConvertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData) const;
+ bool convertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData, STGMEDIUM * pmedium) const;
+ QVector<FORMATETC> formatsForMime(const QString &mimeType, const QMimeData *mimeData) const;
+
+ // for converting to Qt
+ bool canConvertToMime(const QString &mimeType, IDataObject *pDataObj) const;
+ QVariant convertToMime(const QString &mime, IDataObject *pDataObj, QVariant::Type preferredType) const;
+ QString mimeForFormat(const FORMATETC &formatetc) const;
+
+private:
+ QMap<int, QString> outFormats;
+ QMap<int, QString> inFormats;
+};
+
+QBuiltInMimes::QBuiltInMimes()
+: QWindowsMime()
+{
+ outFormats.insert(QWindowsMime::registerMimeType(QLatin1String("application/x-color")), QLatin1String("application/x-color"));
+ inFormats.insert(QWindowsMime::registerMimeType(QLatin1String("application/x-color")), QLatin1String("application/x-color"));
+}
+
+bool QBuiltInMimes::canConvertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData) const
+{
+ // really check
+ return formatetc.tymed & TYMED_HGLOBAL
+ && outFormats.contains(formatetc.cfFormat)
+ && mimeData->formats().contains(outFormats.value(formatetc.cfFormat));
+}
+
+bool QBuiltInMimes::convertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData, STGMEDIUM * pmedium) const
+{
+ if (canConvertFromMime(formatetc, mimeData)) {
+ QByteArray data;
+ if (outFormats.value(getCf(formatetc)) == QLatin1String("text/html")) {
+ // text/html is in wide chars on windows (compatible with mozillia)
+ QString html = mimeData->html();
+ // same code as in the text converter up above
+ const QChar *u = html.unicode();
+ QString res;
+ const int s = html.length();
+ int maxsize = s + s/40 + 3;
+ res.resize(maxsize);
+ int ri = 0;
+ bool cr = false;
+ for (int i=0; i < s; ++i) {
+ if (*u == QLatin1Char('\r'))
+ cr = true;
+ else {
+ if (*u == QLatin1Char('\n') && !cr)
+ res[ri++] = QLatin1Char('\r');
+ cr = false;
+ }
+ res[ri++] = *u;
+ if (ri+3 >= maxsize) {
+ maxsize += maxsize/4;
+ res.resize(maxsize);
+ }
+ ++u;
+ }
+ res.truncate(ri);
+ const int byteLength = res.length() * sizeof(ushort);
+ QByteArray r(byteLength + 2, '\0');
+ memcpy(r.data(), res.unicode(), byteLength);
+ r[byteLength] = 0;
+ r[byteLength+1] = 0;
+ data = r;
+ } else {
+#ifndef QT_NO_DRAGANDDROP
+ data = QInternalMimeData::renderDataHelper(outFormats.value(getCf(formatetc)), mimeData);
+#endif //QT_NO_DRAGANDDROP
+ }
+ return setData(data, pmedium);
+ }
+ return false;
+}
+
+QVector<FORMATETC> QBuiltInMimes::formatsForMime(const QString &mimeType, const QMimeData *mimeData) const
+{
+ QVector<FORMATETC> formatetcs;
+ if (!outFormats.keys(mimeType).isEmpty() && mimeData->formats().contains(mimeType))
+ formatetcs += setCf(outFormats.key(mimeType));
+ return formatetcs;
+}
+
+bool QBuiltInMimes::canConvertToMime(const QString &mimeType, IDataObject *pDataObj) const
+{
+ return (!inFormats.keys(mimeType).isEmpty())
+ && canGetData(inFormats.key(mimeType), pDataObj);
+}
+
+QVariant QBuiltInMimes::convertToMime(const QString &mimeType, IDataObject *pDataObj, QVariant::Type preferredType) const
+{
+ QVariant val;
+ if (canConvertToMime(mimeType, pDataObj)) {
+ QByteArray data = getData(inFormats.key(mimeType), pDataObj);
+ if (!data.isEmpty()) {
+#ifdef QMIME_DEBUG
+ qDebug("QBuiltInMimes::convertToMime()");
+#endif
+ if (mimeType == QLatin1String("text/html") && preferredType == QVariant::String) {
+ // text/html is in wide chars on windows (compatible with Mozilla)
+ val = QString::fromWCharArray((const wchar_t *)data.data());
+ } else {
+ val = data; // it should be enough to return the data and let QMimeData do the rest.
+ }
+ }
+ }
+ return val;
+}
+
+QString QBuiltInMimes::mimeForFormat(const FORMATETC &formatetc) const
+{
+ return inFormats.value(getCf(formatetc));
+}
+
+
+class QLastResortMimes : public QWindowsMime
+{
+public:
+
+ QLastResortMimes();
+ // for converting from Qt
+ bool canConvertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData) const;
+ bool convertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData, STGMEDIUM * pmedium) const;
+ QVector<FORMATETC> formatsForMime(const QString &mimeType, const QMimeData *mimeData) const;
+
+ // for converting to Qt
+ bool canConvertToMime(const QString &mimeType, IDataObject *pDataObj) const;
+ QVariant convertToMime(const QString &mime, IDataObject *pDataObj, QVariant::Type preferredType) const;
+ QString mimeForFormat(const FORMATETC &formatetc) const;
+
+private:
+ QMap<int, QString> formats;
+ static QStringList ianaTypes;
+ static QStringList excludeList;
+};
+
+QStringList QLastResortMimes::ianaTypes;
+QStringList QLastResortMimes::excludeList;
+
+QLastResortMimes::QLastResortMimes()
+{
+ //MIME Media-Types
+ if (!ianaTypes.size()) {
+ ianaTypes.append(QLatin1String("application/"));
+ ianaTypes.append(QLatin1String("audio/"));
+ ianaTypes.append(QLatin1String("example/"));
+ ianaTypes.append(QLatin1String("image/"));
+ ianaTypes.append(QLatin1String("message/"));
+ ianaTypes.append(QLatin1String("model/"));
+ ianaTypes.append(QLatin1String("multipart/"));
+ ianaTypes.append(QLatin1String("text/"));
+ ianaTypes.append(QLatin1String("video/"));
+ }
+ //Types handled by other classes
+ if (!excludeList.size()) {
+ excludeList.append(QLatin1String("HTML Format"));
+ excludeList.append(QLatin1String("UniformResourceLocator"));
+ excludeList.append(QLatin1String("text/html"));
+ excludeList.append(QLatin1String("text/plain"));
+ excludeList.append(QLatin1String("text/uri-list"));
+ excludeList.append(QLatin1String("application/x-qt-image"));
+ excludeList.append(QLatin1String("application/x-color"));
+ }
+}
+
+bool QLastResortMimes::canConvertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData) const
+{
+ // really check
+#ifndef QT_NO_DRAGANDDROP
+ return formatetc.tymed & TYMED_HGLOBAL
+ && (formats.contains(formatetc.cfFormat)
+ && QInternalMimeData::hasFormatHelper(formats.value(formatetc.cfFormat), mimeData));
+#else
+ Q_UNUSED(mimeData);
+ Q_UNUSED(formatetc);
+ return formatetc.tymed & TYMED_HGLOBAL
+ && formats.contains(formatetc.cfFormat);
+#endif //QT_NO_DRAGANDDROP
+}
+
+bool QLastResortMimes::convertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData, STGMEDIUM * pmedium) const
+{
+#ifndef QT_NO_DRAGANDDROP
+ return canConvertFromMime(formatetc, mimeData)
+ && setData(QInternalMimeData::renderDataHelper(formats.value(getCf(formatetc)), mimeData), pmedium);
+#else
+ Q_UNUSED(mimeData);
+ Q_UNUSED(formatetc);
+ Q_UNUSED(pmedium);
+ return false;
+#endif //QT_NO_DRAGANDDROP
+}
+
+QVector<FORMATETC> QLastResortMimes::formatsForMime(const QString &mimeType, const QMimeData * /*mimeData*/) const
+{
+ QVector<FORMATETC> formatetcs;
+ if (!formats.keys(mimeType).isEmpty()) {
+ formatetcs += setCf(formats.key(mimeType));
+ } else if (!excludeList.contains(mimeType, Qt::CaseInsensitive)){
+ // register any other available formats
+ int cf = QWindowsMime::registerMimeType(mimeType);
+ QLastResortMimes *that = const_cast<QLastResortMimes *>(this);
+ that->formats.insert(cf, mimeType);
+ formatetcs += setCf(cf);
+ }
+ return formatetcs;
+}
+static const char x_qt_windows_mime[] = "application/x-qt-windows-mime;value=\"";
+
+static bool isCustomMimeType(const QString &mimeType)
+{
+ return mimeType.startsWith(QLatin1String(x_qt_windows_mime), Qt::CaseInsensitive);
+}
+
+static QString customMimeType(const QString &mimeType)
+{
+ int len = sizeof(x_qt_windows_mime) - 1;
+ int n = mimeType.lastIndexOf(QLatin1Char('\"'))-len;
+ return mimeType.mid(len, n);
+}
+
+bool QLastResortMimes::canConvertToMime(const QString &mimeType, IDataObject *pDataObj) const
+{
+ if (isCustomMimeType(mimeType)) {
+ QString clipFormat = customMimeType(mimeType);
+ int cf = RegisterClipboardFormat(reinterpret_cast<const wchar_t *> (clipFormat.utf16()));
+ return canGetData(cf, pDataObj);
+ } else if (formats.keys(mimeType).isEmpty()) {
+ // if it is not in there then register it an see if we can get it
+ int cf = QWindowsMime::registerMimeType(mimeType);
+ return canGetData(cf, pDataObj);
+ } else {
+ return canGetData(formats.key(mimeType), pDataObj);
+ }
+ return false;
+}
+
+QVariant QLastResortMimes::convertToMime(const QString &mimeType, IDataObject *pDataObj, QVariant::Type preferredType) const
+{
+ Q_UNUSED(preferredType);
+ QVariant val;
+ if (canConvertToMime(mimeType, pDataObj)) {
+ QByteArray data;
+ if (isCustomMimeType(mimeType)) {
+ QString clipFormat = customMimeType(mimeType);
+ int cf = RegisterClipboardFormat(reinterpret_cast<const wchar_t *> (clipFormat.utf16()));
+ data = getData(cf, pDataObj);
+ } else if (formats.keys(mimeType).isEmpty()) {
+ int cf = QWindowsMime::registerMimeType(mimeType);
+ data = getData(cf, pDataObj);
+ } else {
+ data = getData(formats.key(mimeType), pDataObj);
+ }
+ if (!data.isEmpty())
+ val = data; // it should be enough to return the data and let QMimeData do the rest.
+ }
+ return val;
+}
+
+QString QLastResortMimes::mimeForFormat(const FORMATETC &formatetc) const
+{
+ QString format = formats.value(getCf(formatetc));
+ if (!format.isEmpty())
+ return format;
+
+ wchar_t buffer[256];
+ int len = GetClipboardFormatName(getCf(formatetc), buffer, 256);
+
+ if (len) {
+ QString clipFormat = QString::fromWCharArray(buffer, len);
+#ifndef QT_NO_DRAGANDDROP
+ if (QInternalMimeData::canReadData(clipFormat))
+ format = clipFormat;
+ else if((formatetc.cfFormat >= 0xC000)){
+ //create the mime as custom. not registered.
+ if (!excludeList.contains(clipFormat, Qt::CaseInsensitive)) {
+ //check if this is a mime type
+ bool ianaType = false;
+ int sz = ianaTypes.size();
+ for (int i = 0; i < sz; i++) {
+ if (clipFormat.startsWith(ianaTypes[i], Qt::CaseInsensitive)) {
+ ianaType = true;
+ break;
+ }
+ }
+ if (!ianaType)
+ format = QLatin1String(x_qt_windows_mime) + clipFormat + QLatin1Char('\"');
+ else
+ format = clipFormat;
+ }
+ }
+#endif //QT_NO_DRAGANDDROP
+ }
+
+ return format;
+}
+
+QWindowsMimeList::QWindowsMimeList()
+ : initialized(false)
+{
+}
+
+QWindowsMimeList::~QWindowsMimeList()
+{
+ while (mimes.size())
+ delete mimes.first();
+}
+
+
+void QWindowsMimeList::init()
+{
+ if (!initialized) {
+ initialized = true;
+#ifndef QT_NO_IMAGEFORMAT_BMP
+ new QWindowsMimeImage;
+#endif
+ new QLastResortMimes;
+ new QWindowsMimeText;
+ new QWindowsMimeURI;
+
+ new QWindowsMimeHtml;
+ new QBuiltInMimes;
+ }
+}
+
+void QWindowsMimeList::addWindowsMime(QWindowsMime * mime)
+{
+ init();
+ mimes.append(mime);
+}
+
+void QWindowsMimeList::removeWindowsMime(QWindowsMime * mime)
+{
+ init();
+ mimes.removeAll(mime);
+}
+
+QList<QWindowsMime*> QWindowsMimeList::windowsMimes()
+{
+ init();
+ return mimes;
+}
+
+#ifndef QT_NO_IMAGEFORMAT_BMP
+static bool qt_write_dibv5(QDataStream &s, QImage image)
+{
+ QIODevice* d = s.device();
+ if (!d->isWritable())
+ return false;
+
+ //depth will be always 32
+ int bpl_bmp = image.width()*4;
+
+ BMP_BITMAPV5HEADER bi ={0};
+ bi.bV5Size = sizeof(BMP_BITMAPV5HEADER);
+ bi.bV5Width = image.width();
+ bi.bV5Height = image.height();
+ bi.bV5Planes = 1;
+ bi.bV5BitCount = 32;
+ bi.bV5Compression = BI_BITFIELDS;
+ bi.bV5SizeImage = bpl_bmp*image.height();
+ bi.bV5XPelsPerMeter = 0;
+ bi.bV5YPelsPerMeter = 0;
+ bi.bV5ClrUsed = 0;
+ bi.bV5ClrImportant = 0;
+ bi.bV5BlueMask = 0x000000ff;
+ bi.bV5GreenMask = 0x0000ff00;
+ bi.bV5RedMask = 0x00ff0000;
+ bi.bV5AlphaMask = 0xff000000;
+ bi.bV5CSType = BMP_LCS_sRGB; //LCS_sRGB
+ bi.bV5Intent = BMP_LCS_GM_IMAGES; //LCS_GM_IMAGES
+
+ d->write(reinterpret_cast<const char*>(&bi), bi.bV5Size);
+ if (s.status() != QDataStream::Ok)
+ return false;
+
+ DWORD colorSpace[3] = {0x00ff0000,0x0000ff00,0x000000ff};
+ d->write(reinterpret_cast<const char*>(colorSpace), sizeof(colorSpace));
+ if (s.status() != QDataStream::Ok)
+ return false;
+
+ if (image.format() != QImage::Format_ARGB32)
+ image = image.convertToFormat(QImage::Format_ARGB32);
+
+ uchar *buf = new uchar[bpl_bmp];
+ uchar *b;
+
+ memset(buf, 0, bpl_bmp);
+ for (int y=image.height()-1; y>=0; y--) {
+ // write the image bits
+ QRgb *p = (QRgb *)image.scanLine(y);
+ QRgb *end = p + image.width();
+ b = buf;
+ while (p < end) {
+ int alpha = qAlpha(*p);
+ if (alpha) {
+ *b++ = qBlue(*p);
+ *b++ = qGreen(*p);
+ *b++ = qRed(*p);
+ } else {
+ //white for fully transparent pixels.
+ *b++ = 0xff;
+ *b++ = 0xff;
+ *b++ = 0xff;
+ }
+ *b++ = alpha;
+ p++;
+ }
+ d->write((char*)buf, bpl_bmp);
+ if (s.status() != QDataStream::Ok) {
+ delete[] buf;
+ return false;
+ }
+ }
+ delete[] buf;
+ return true;
+}
+
+static int calc_shift(int mask)
+{
+ int result = 0;
+ while (!(mask & 1)) {
+ result++;
+ mask >>= 1;
+ }
+ return result;
+}
+
+//Supports only 32 bit DIBV5
+static bool qt_read_dibv5(QDataStream &s, QImage &image)
+{
+ BMP_BITMAPV5HEADER bi;
+ QIODevice* d = s.device();
+ if (d->atEnd())
+ return false;
+
+ d->read((char *)&bi, sizeof(bi)); // read BITMAPV5HEADER header
+ if (s.status() != QDataStream::Ok)
+ return false;
+
+ int nbits = bi.bV5BitCount;
+ int comp = bi.bV5Compression;
+ if (nbits != 32 || bi.bV5Planes != 1 || comp != BMP_BITFIELDS)
+ return false; //Unsupported DIBV5 format
+
+ int w = bi.bV5Width, h = bi.bV5Height;
+ int red_mask = bi.bV5RedMask;
+ int green_mask = bi.bV5GreenMask;
+ int blue_mask = bi.bV5BlueMask;
+ int alpha_mask = bi.bV5AlphaMask;
+ int red_shift = 0;
+ int green_shift = 0;
+ int blue_shift = 0;
+ int alpha_shift = 0;
+ QImage::Format format = QImage::Format_ARGB32;
+
+ if (bi.bV5Height < 0)
+ h = -h; // support images with negative height
+ if (image.size() != QSize(w, h) || image.format() != format) {
+ image = QImage(w, h, format);
+ if (image.isNull()) // could not create image
+ return false;
+ }
+ image.setDotsPerMeterX(bi.bV5XPelsPerMeter);
+ image.setDotsPerMeterY(bi.bV5YPelsPerMeter);
+ // read color table
+ DWORD colorSpace[3];
+ if (d->read((char *)colorSpace, sizeof(colorSpace)) != sizeof(colorSpace))
+ return false;
+
+ red_shift = calc_shift(red_mask);
+ green_shift = calc_shift(green_mask);
+ blue_shift = calc_shift(blue_mask);
+ if (alpha_mask) {
+ alpha_shift = calc_shift(alpha_mask);
+ }
+
+ int bpl = image.bytesPerLine();
+ uchar *data = image.bits();
+ register QRgb *p;
+ QRgb *end;
+ uchar *buf24 = new uchar[bpl];
+ int bpl24 = ((w*nbits+31)/32)*4;
+ uchar *b;
+ unsigned int c;
+
+ while (--h >= 0) {
+ p = (QRgb *)(data + h*bpl);
+ end = p + w;
+ if (d->read((char *)buf24,bpl24) != bpl24)
+ break;
+ b = buf24;
+ while (p < end) {
+ c = *b | (*(b+1))<<8 | (*(b+2))<<16 | (*(b+3))<<24;
+ *p++ = qRgba(((c & red_mask) >> red_shift) ,
+ ((c & green_mask) >> green_shift),
+ ((c & blue_mask) >> blue_shift),
+ ((c & alpha_mask) >> alpha_shift));
+ b += 4;
+ }
+ }
+ delete[] buf24;
+
+ if (bi.bV5Height < 0) {
+ // Flip the image
+ uchar *buf = new uchar[bpl];
+ h = -bi.bV5Height;
+ for (int y = 0; y < h/2; ++y) {
+ memcpy(buf, data + y*bpl, bpl);
+ memcpy(data + y*bpl, data + (h-y-1)*bpl, bpl);
+ memcpy(data + (h-y-1)*bpl, buf, bpl);
+ }
+ delete [] buf;
+ }
+
+ return true;
+}
+
+#endif
+
+QT_END_NAMESPACE
diff --git a/src/gui/platforms/win/qole_win.cpp b/src/gui/platforms/win/qole_win.cpp
new file mode 100644
index 0000000000..24e2d5b292
--- /dev/null
+++ b/src/gui/platforms/win/qole_win.cpp
@@ -0,0 +1,255 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qdnd_p.h"
+
+#if !(defined(QT_NO_DRAGANDDROP) && defined(QT_NO_CLIPBOARD))
+
+#if defined(Q_OS_WINCE)
+#include <shlobj.h>
+#include "qguifunctions_wince.h"
+#endif
+
+QT_BEGIN_NAMESPACE
+
+QOleEnumFmtEtc::QOleEnumFmtEtc(const QVector<FORMATETC> &fmtetcs)
+{
+ m_isNull = false;
+ m_dwRefs = 1;
+ m_nIndex = 0;
+
+ for (int idx = 0; idx < fmtetcs.count(); ++idx) {
+ LPFORMATETC destetc = new FORMATETC();
+ if (copyFormatEtc(destetc, (LPFORMATETC)&(fmtetcs.at(idx)))) {
+ m_lpfmtetcs.append(destetc);
+ } else {
+ m_isNull = true;
+ delete destetc;
+ break;
+ }
+ }
+}
+
+QOleEnumFmtEtc::QOleEnumFmtEtc(const QVector<LPFORMATETC> &lpfmtetcs)
+{
+ m_isNull = false;
+ m_dwRefs = 1;
+ m_nIndex = 0;
+
+ for (int idx = 0; idx < lpfmtetcs.count(); ++idx) {
+ LPFORMATETC srcetc = lpfmtetcs.at(idx);
+ LPFORMATETC destetc = new FORMATETC();
+ if (copyFormatEtc(destetc, srcetc)) {
+ m_lpfmtetcs.append(destetc);
+ } else {
+ m_isNull = true;
+ delete destetc;
+ break;
+ }
+ }
+}
+
+QOleEnumFmtEtc::~QOleEnumFmtEtc()
+{
+ LPMALLOC pmalloc;
+
+#if !defined(Q_OS_WINCE)
+ if (CoGetMalloc(MEMCTX_TASK, &pmalloc) == NOERROR) {
+#else
+ if (SHGetMalloc(&pmalloc) == NOERROR) {
+#endif
+ for (int idx = 0; idx < m_lpfmtetcs.count(); ++idx) {
+ LPFORMATETC tmpetc = m_lpfmtetcs.at(idx);
+ if (tmpetc->ptd)
+ pmalloc->Free(tmpetc->ptd);
+ delete tmpetc;
+ }
+
+ pmalloc->Release();
+ }
+ m_lpfmtetcs.clear();
+}
+
+bool QOleEnumFmtEtc::isNull() const
+{
+ return m_isNull;
+}
+
+// IUnknown methods
+STDMETHODIMP
+QOleEnumFmtEtc::QueryInterface(REFIID riid, void FAR* FAR* ppvObj)
+{
+ if (riid == IID_IUnknown || riid == IID_IEnumFORMATETC) {
+ *ppvObj = this;
+ AddRef();
+ return NOERROR;
+ }
+ *ppvObj = NULL;
+ return ResultFromScode(E_NOINTERFACE);
+}
+
+STDMETHODIMP_(ULONG)
+QOleEnumFmtEtc::AddRef(void)
+{
+ return ++m_dwRefs;
+}
+
+STDMETHODIMP_(ULONG)
+QOleEnumFmtEtc::Release(void)
+{
+ if (--m_dwRefs == 0) {
+ delete this;
+ return 0;
+ }
+ return m_dwRefs;
+}
+
+// IEnumFORMATETC methods
+STDMETHODIMP
+QOleEnumFmtEtc::Next(ULONG celt, LPFORMATETC rgelt, ULONG FAR* pceltFetched)
+{
+ ULONG i=0;
+ ULONG nOffset;
+
+ if (rgelt == NULL)
+ return ResultFromScode(E_INVALIDARG);
+
+ while (i < celt) {
+ nOffset = m_nIndex + i;
+
+ if (nOffset < ULONG(m_lpfmtetcs.count())) {
+ copyFormatEtc((LPFORMATETC)&(rgelt[i]), m_lpfmtetcs.at(nOffset));
+ i++;
+ } else {
+ break;
+ }
+ }
+
+ m_nIndex += (WORD)i;
+
+ if (pceltFetched != NULL)
+ *pceltFetched = i;
+
+ if (i != celt)
+ return ResultFromScode(S_FALSE);
+
+ return NOERROR;
+}
+
+STDMETHODIMP
+QOleEnumFmtEtc::Skip(ULONG celt)
+{
+ ULONG i=0;
+ ULONG nOffset;
+
+ while (i < celt) {
+ nOffset = m_nIndex + i;
+
+ if (nOffset < ULONG(m_lpfmtetcs.count())) {
+ i++;
+ } else {
+ break;
+ }
+ }
+
+ m_nIndex += (WORD)i;
+
+ if (i != celt)
+ return ResultFromScode(S_FALSE);
+
+ return NOERROR;
+}
+
+STDMETHODIMP
+QOleEnumFmtEtc::Reset()
+{
+ m_nIndex = 0;
+ return NOERROR;
+}
+
+STDMETHODIMP
+QOleEnumFmtEtc::Clone(LPENUMFORMATETC FAR* newEnum)
+{
+ if (newEnum == NULL)
+ return ResultFromScode(E_INVALIDARG);
+
+ QOleEnumFmtEtc *result = new QOleEnumFmtEtc(m_lpfmtetcs);
+ result->m_nIndex = m_nIndex;
+
+ if (result->isNull()) {
+ delete result;
+ return ResultFromScode(E_OUTOFMEMORY);
+ } else {
+ *newEnum = result;
+ }
+
+ return NOERROR;
+}
+
+bool QOleEnumFmtEtc::copyFormatEtc(LPFORMATETC dest, LPFORMATETC src) const
+{
+ if (dest == NULL || src == NULL)
+ return false;
+
+ *dest = *src;
+
+ if (src->ptd) {
+ LPVOID pout;
+ LPMALLOC pmalloc;
+
+#if !defined(Q_OS_WINCE)
+ if (CoGetMalloc(MEMCTX_TASK, &pmalloc) != NOERROR)
+#else
+ if (SHGetMalloc(&pmalloc) != NOERROR)
+#endif
+ return false;
+
+ pout = (LPVOID)pmalloc->Alloc(src->ptd->tdSize);
+ memcpy(dest->ptd, src->ptd, size_t(src->ptd->tdSize));
+
+ pmalloc->Release();
+ }
+
+ return true;
+}
+
+QT_END_NAMESPACE
+#endif // QT_NO_DRAGANDDROP && QT_NO_CLIPBOARD
diff --git a/src/gui/platforms/win/qpaintdevice_win.cpp b/src/gui/platforms/win/qpaintdevice_win.cpp
new file mode 100644
index 0000000000..3dbe97492a
--- /dev/null
+++ b/src/gui/platforms/win/qpaintdevice_win.cpp
@@ -0,0 +1,62 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qpaintdevice.h"
+#include "qpainter.h"
+#include "qwidget.h"
+#include "qbitmap.h"
+#include "qapplication.h"
+#include <private/qapplication_p.h>
+#include "qt_windows.h"
+#include "qprinter.h"
+
+QT_BEGIN_NAMESPACE
+
+HDC QPaintDevice::getDC() const
+{
+ return 0;
+}
+
+void QPaintDevice::releaseDC(HDC) const
+{
+}
+
+QT_END_NAMESPACE
diff --git a/src/gui/platforms/win/qpixmap_win.cpp b/src/gui/platforms/win/qpixmap_win.cpp
new file mode 100644
index 0000000000..9c14ac7726
--- /dev/null
+++ b/src/gui/platforms/win/qpixmap_win.cpp
@@ -0,0 +1,477 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qpixmap.h"
+#include "qpixmap_raster_p.h"
+
+#include "qbitmap.h"
+#include "qimage.h"
+#include "qwidget.h"
+#include "qpainter.h"
+#include "qdatastream.h"
+#include "qbuffer.h"
+#include "qapplication.h"
+#include "qevent.h"
+#include "qfile.h"
+#include "qfileinfo.h"
+#include "qdatetime.h"
+#include "qpixmapcache.h"
+#include "qimagereader.h"
+#include "qimagewriter.h"
+#include "qdebug.h"
+#include "qt_windows.h"
+
+#if defined(Q_WS_WINCE)
+#include <winbase.h>
+#include "qguifunctions_wince.h"
+extern bool qt_wince_is_high_dpi();
+extern bool qt_wince_is_pocket_pc();
+#endif
+
+#ifndef CAPTUREBLT
+#define CAPTUREBLT ((DWORD)0x40000000)
+#endif
+
+QT_BEGIN_NAMESPACE
+
+QPixmap QPixmap::grabWindow(WId winId, int x, int y, int w, int h )
+{
+ RECT r;
+ GetClientRect(winId, &r);
+
+ if (w < 0) w = r.right - r.left;
+ if (h < 0) h = r.bottom - r.top;
+
+#ifdef Q_WS_WINCE_WM
+ if (qt_wince_is_pocket_pc()) {
+ QWidget *widget = QWidget::find(winId);
+ if (qobject_cast<QDesktopWidget *>(widget)) {
+ RECT rect = {0,0,0,0};
+ AdjustWindowRectEx(&rect, WS_BORDER | WS_CAPTION, FALSE, 0);
+ int magicNumber = qt_wince_is_high_dpi() ? 4 : 2;
+ y += rect.top - magicNumber;
+ }
+ }
+#endif
+
+ // Create and setup bitmap
+ HDC display_dc = GetDC(0);
+ HDC bitmap_dc = CreateCompatibleDC(display_dc);
+ HBITMAP bitmap = CreateCompatibleBitmap(display_dc, w, h);
+ HGDIOBJ null_bitmap = SelectObject(bitmap_dc, bitmap);
+
+ // copy data
+ HDC window_dc = GetDC(winId);
+ BitBlt(bitmap_dc, 0, 0, w, h, window_dc, x, y, SRCCOPY
+#ifndef Q_WS_WINCE
+ | CAPTUREBLT
+#endif
+ );
+
+ // clean up all but bitmap
+ ReleaseDC(winId, window_dc);
+ SelectObject(bitmap_dc, null_bitmap);
+ DeleteDC(bitmap_dc);
+
+ QPixmap pixmap = QPixmap::fromWinHBITMAP(bitmap);
+
+ DeleteObject(bitmap);
+ ReleaseDC(0, display_dc);
+
+ return pixmap;
+}
+
+HBITMAP QPixmap::toWinHBITMAP(HBitmapFormat format) const
+{
+ if (isNull())
+ return 0;
+
+ HBITMAP bitmap = 0;
+ if (data->classId() == QPixmapData::RasterClass) {
+ QRasterPixmapData* d = static_cast<QRasterPixmapData*>(data.data());
+ int w = d->image.width();
+ int h = d->image.height();
+
+ HDC display_dc = GetDC(0);
+
+ // Define the header
+ BITMAPINFO bmi;
+ memset(&bmi, 0, sizeof(bmi));
+ bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
+ bmi.bmiHeader.biWidth = w;
+ bmi.bmiHeader.biHeight = -h;
+ bmi.bmiHeader.biPlanes = 1;
+ bmi.bmiHeader.biBitCount = 32;
+ bmi.bmiHeader.biCompression = BI_RGB;
+ bmi.bmiHeader.biSizeImage = w * h * 4;
+
+ // Create the pixmap
+ uchar *pixels = 0;
+ bitmap = CreateDIBSection(display_dc, &bmi, DIB_RGB_COLORS, (void **) &pixels, 0, 0);
+ ReleaseDC(0, display_dc);
+ if (!bitmap) {
+ qErrnoWarning("QPixmap::toWinHBITMAP(), failed to create dibsection");
+ return 0;
+ }
+ if (!pixels) {
+ qErrnoWarning("QPixmap::toWinHBITMAP(), did not allocate pixel data");
+ return 0;
+ }
+
+ // Copy over the data
+ QImage::Format imageFormat = QImage::Format_ARGB32;
+ if (format == NoAlpha)
+ imageFormat = QImage::Format_RGB32;
+ else if (format == PremultipliedAlpha)
+ imageFormat = QImage::Format_ARGB32_Premultiplied;
+ const QImage image = d->image.convertToFormat(imageFormat);
+ int bytes_per_line = w * 4;
+ for (int y=0; y<h; ++y)
+ memcpy(pixels + y * bytes_per_line, image.scanLine(y), bytes_per_line);
+
+ } else {
+ QPixmapData *data = new QRasterPixmapData(depth() == 1 ?
+ QPixmapData::BitmapType : QPixmapData::PixmapType);
+ data->fromImage(toImage(), Qt::AutoColor);
+ return QPixmap(data).toWinHBITMAP(format);
+ }
+ return bitmap;
+}
+
+QPixmap QPixmap::fromWinHBITMAP(HBITMAP bitmap, HBitmapFormat format)
+{
+ // Verify size
+ BITMAP bitmap_info;
+ memset(&bitmap_info, 0, sizeof(BITMAP));
+
+ int res = GetObject(bitmap, sizeof(BITMAP), &bitmap_info);
+ if (!res) {
+ qErrnoWarning("QPixmap::fromWinHBITMAP(), failed to get bitmap info");
+ return QPixmap();
+ }
+ int w = bitmap_info.bmWidth;
+ int h = bitmap_info.bmHeight;
+
+ BITMAPINFO bmi;
+ memset(&bmi, 0, sizeof(bmi));
+ bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
+ bmi.bmiHeader.biWidth = w;
+ bmi.bmiHeader.biHeight = -h;
+ bmi.bmiHeader.biPlanes = 1;
+ bmi.bmiHeader.biBitCount = 32;
+ bmi.bmiHeader.biCompression = BI_RGB;
+ bmi.bmiHeader.biSizeImage = w * h * 4;
+
+ QImage result;
+ // Get bitmap bits
+ uchar *data = (uchar *) qMalloc(bmi.bmiHeader.biSizeImage);
+
+ HDC display_dc = GetDC(0);
+ if (GetDIBits(display_dc, bitmap, 0, h, data, &bmi, DIB_RGB_COLORS)) {
+
+ QImage::Format imageFormat = QImage::Format_ARGB32_Premultiplied;
+ uint mask = 0;
+ if (format == NoAlpha) {
+ imageFormat = QImage::Format_RGB32;
+ mask = 0xff000000;
+ }
+
+ // Create image and copy data into image.
+ QImage image(w, h, imageFormat);
+ if (!image.isNull()) { // failed to alloc?
+ int bytes_per_line = w * sizeof(QRgb);
+ for (int y=0; y<h; ++y) {
+ QRgb *dest = (QRgb *) image.scanLine(y);
+ const QRgb *src = (const QRgb *) (data + y * bytes_per_line);
+ for (int x=0; x<w; ++x) {
+ const uint pixel = src[x];
+ if ((pixel & 0xff000000) == 0 && (pixel & 0x00ffffff) != 0)
+ dest[x] = pixel | 0xff000000;
+ else
+ dest[x] = pixel | mask;
+ }
+ }
+ }
+ result = image;
+ } else {
+ qWarning("QPixmap::fromWinHBITMAP(), failed to get bitmap bits");
+ }
+ ReleaseDC(0, display_dc);
+ qFree(data);
+ return fromImage(result);
+}
+
+HBITMAP qt_createIconMask(const QBitmap &bitmap)
+{
+ QImage bm = bitmap.toImage().convertToFormat(QImage::Format_Mono);
+ int w = bm.width();
+ int h = bm.height();
+ int bpl = ((w+15)/16)*2; // bpl, 16 bit alignment
+ uchar *bits = new uchar[bpl*h];
+ bm.invertPixels();
+ for (int y=0; y<h; y++)
+ memcpy(bits+y*bpl, bm.scanLine(y), bpl);
+ HBITMAP hbm = CreateBitmap(w, h, 1, 1, bits);
+ delete [] bits;
+ return hbm;
+}
+
+HICON QPixmap::toWinHICON() const
+{
+ QBitmap maskBitmap = mask();
+ if (maskBitmap.isNull()) {
+ maskBitmap= QBitmap(size());
+ maskBitmap.fill(Qt::color1);
+ }
+
+ ICONINFO ii;
+ ii.fIcon = true;
+ ii.hbmMask = qt_createIconMask(maskBitmap);
+ ii.hbmColor = toWinHBITMAP(QPixmap::Alpha);
+ ii.xHotspot = 0;
+ ii.yHotspot = 0;
+
+ HICON hIcon = CreateIconIndirect(&ii);
+
+ DeleteObject(ii.hbmColor);
+ DeleteObject(ii.hbmMask);
+
+ return hIcon;
+}
+
+#ifdef Q_WS_WIN
+#ifndef Q_WS_WINCE
+
+static QImage qt_fromWinHBITMAP(HDC hdc, HBITMAP bitmap, int w, int h)
+{
+ BITMAPINFO bmi;
+ memset(&bmi, 0, sizeof(bmi));
+ bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
+ bmi.bmiHeader.biWidth = w;
+ bmi.bmiHeader.biHeight = -h;
+ bmi.bmiHeader.biPlanes = 1;
+ bmi.bmiHeader.biBitCount = 32;
+ bmi.bmiHeader.biCompression = BI_RGB;
+ bmi.bmiHeader.biSizeImage = w * h * 4;
+
+ QImage image(w, h, QImage::Format_ARGB32_Premultiplied);
+ if (image.isNull())
+ return image;
+
+ // Get bitmap bits
+ uchar *data = (uchar *) qMalloc(bmi.bmiHeader.biSizeImage);
+
+ if (GetDIBits(hdc, bitmap, 0, h, data, &bmi, DIB_RGB_COLORS)) {
+ // Create image and copy data into image.
+ for (int y=0; y<h; ++y) {
+ void *dest = (void *) image.scanLine(y);
+ void *src = data + y * image.bytesPerLine();
+ memcpy(dest, src, image.bytesPerLine());
+ }
+ } else {
+ qWarning("qt_fromWinHBITMAP(), failed to get bitmap bits");
+ }
+ qFree(data);
+
+ return image;
+}
+
+QPixmap QPixmap::fromWinHICON(HICON icon)
+{
+ bool foundAlpha = false;
+ HDC screenDevice = GetDC(0);
+ HDC hdc = CreateCompatibleDC(screenDevice);
+ ReleaseDC(0, screenDevice);
+
+ ICONINFO iconinfo;
+ bool result = GetIconInfo(icon, &iconinfo); //x and y Hotspot describes the icon center
+ if (!result)
+ qWarning("QPixmap::fromWinHICON(), failed to GetIconInfo()");
+
+ int w = iconinfo.xHotspot * 2;
+ int h = iconinfo.yHotspot * 2;
+
+ BITMAPINFOHEADER bitmapInfo;
+ bitmapInfo.biSize = sizeof(BITMAPINFOHEADER);
+ bitmapInfo.biWidth = w;
+ bitmapInfo.biHeight = h;
+ bitmapInfo.biPlanes = 1;
+ bitmapInfo.biBitCount = 32;
+ bitmapInfo.biCompression = BI_RGB;
+ bitmapInfo.biSizeImage = 0;
+ bitmapInfo.biXPelsPerMeter = 0;
+ bitmapInfo.biYPelsPerMeter = 0;
+ bitmapInfo.biClrUsed = 0;
+ bitmapInfo.biClrImportant = 0;
+ DWORD* bits;
+
+ HBITMAP winBitmap = CreateDIBSection(hdc, (BITMAPINFO*)&bitmapInfo, DIB_RGB_COLORS, (VOID**)&bits, NULL, 0);
+ HGDIOBJ oldhdc = (HBITMAP)SelectObject(hdc, winBitmap);
+ DrawIconEx( hdc, 0, 0, icon, iconinfo.xHotspot * 2, iconinfo.yHotspot * 2, 0, 0, DI_NORMAL);
+ QImage image = qt_fromWinHBITMAP(hdc, winBitmap, w, h);
+
+ for (int y = 0 ; y < h && !foundAlpha ; y++) {
+ QRgb *scanLine= reinterpret_cast<QRgb *>(image.scanLine(y));
+ for (int x = 0; x < w ; x++) {
+ if (qAlpha(scanLine[x]) != 0) {
+ foundAlpha = true;
+ break;
+ }
+ }
+ }
+ if (!foundAlpha) {
+ //If no alpha was found, we use the mask to set alpha values
+ DrawIconEx( hdc, 0, 0, icon, w, h, 0, 0, DI_MASK);
+ QImage mask = qt_fromWinHBITMAP(hdc, winBitmap, w, h);
+
+ for (int y = 0 ; y < h ; y++){
+ QRgb *scanlineImage = reinterpret_cast<QRgb *>(image.scanLine(y));
+ QRgb *scanlineMask = mask.isNull() ? 0 : reinterpret_cast<QRgb *>(mask.scanLine(y));
+ for (int x = 0; x < w ; x++){
+ if (scanlineMask && qRed(scanlineMask[x]) != 0)
+ scanlineImage[x] = 0; //mask out this pixel
+ else
+ scanlineImage[x] |= 0xff000000; // set the alpha channel to 255
+ }
+ }
+ }
+ //dispose resources created by iconinfo call
+ DeleteObject(iconinfo.hbmMask);
+ DeleteObject(iconinfo.hbmColor);
+
+ SelectObject(hdc, oldhdc); //restore state
+ DeleteObject(winBitmap);
+ DeleteDC(hdc);
+ return QPixmap::fromImage(image);
+}
+#else //ifndef Q_WS_WINCE
+QPixmap QPixmap::fromWinHICON(HICON icon)
+{
+ HDC screenDevice = GetDC(0);
+ HDC hdc = CreateCompatibleDC(screenDevice);
+ ReleaseDC(0, screenDevice);
+
+ ICONINFO iconinfo;
+ bool result = GetIconInfo(icon, &iconinfo);
+ if (!result)
+ qWarning("QPixmap::fromWinHICON(), failed to GetIconInfo()");
+
+ int w = 0;
+ int h = 0;
+ if (!iconinfo.xHotspot || !iconinfo.yHotspot) {
+ // We could not retrieve the icon size via GetIconInfo,
+ // so we try again using the icon bitmap.
+ BITMAP bm;
+ int result = GetObject(iconinfo.hbmColor, sizeof(BITMAP), &bm);
+ if (!result) result = GetObject(iconinfo.hbmMask, sizeof(BITMAP), &bm);
+ if (!result) {
+ qWarning("QPixmap::fromWinHICON(), failed to retrieve icon size");
+ return QPixmap();
+ }
+ w = bm.bmWidth;
+ h = bm.bmHeight;
+ } else {
+ // x and y Hotspot describes the icon center
+ w = iconinfo.xHotspot * 2;
+ h = iconinfo.yHotspot * 2;
+ }
+ const DWORD dwImageSize = w * h * 4;
+
+ BITMAPINFO bmi;
+ memset(&bmi, 0, sizeof(bmi));
+ bmi.bmiHeader.biSize = sizeof(BITMAPINFO);
+ bmi.bmiHeader.biWidth = w;
+ bmi.bmiHeader.biHeight = -h;
+ bmi.bmiHeader.biPlanes = 1;
+ bmi.bmiHeader.biBitCount = 32;
+ bmi.bmiHeader.biCompression = BI_RGB;
+ bmi.bmiHeader.biSizeImage = dwImageSize;
+
+ uchar* bits;
+
+ HBITMAP winBitmap = CreateDIBSection(hdc, &bmi, DIB_RGB_COLORS, (void**) &bits, 0, 0);
+ if (winBitmap )
+ memset(bits, 0xff, dwImageSize);
+ if (!winBitmap) {
+ qWarning("QPixmap::fromWinHICON(), failed to CreateDIBSection()");
+ return QPixmap();
+ }
+
+ HGDIOBJ oldhdc = (HBITMAP)SelectObject(hdc, winBitmap);
+ if (!DrawIconEx( hdc, 0, 0, icon, w, h, 0, 0, DI_NORMAL))
+ qWarning("QPixmap::fromWinHICON(), failed to DrawIcon()");
+
+ uint mask = 0xff000000;
+ // Create image and copy data into image.
+ QImage image(w, h, QImage::Format_ARGB32);
+
+ if (!image.isNull()) { // failed to alloc?
+ int bytes_per_line = w * sizeof(QRgb);
+ for (int y=0; y < h; ++y) {
+ QRgb *dest = (QRgb *) image.scanLine(y);
+ const QRgb *src = (const QRgb *) (bits + y * bytes_per_line);
+ for (int x=0; x < w; ++x) {
+ dest[x] = src[x];
+ }
+ }
+ }
+ if (!DrawIconEx( hdc, 0, 0, icon, w, h, 0, 0, DI_MASK))
+ qWarning("QPixmap::fromWinHICON(), failed to DrawIcon()");
+ if (!image.isNull()) { // failed to alloc?
+ int bytes_per_line = w * sizeof(QRgb);
+ for (int y=0; y < h; ++y) {
+ QRgb *dest = (QRgb *) image.scanLine(y);
+ const QRgb *src = (const QRgb *) (bits + y * bytes_per_line);
+ for (int x=0; x < w; ++x) {
+ if (!src[x])
+ dest[x] = dest[x] | mask;
+ }
+ }
+ }
+ SelectObject(hdc, oldhdc); //restore state
+ DeleteObject(winBitmap);
+ DeleteDC(hdc);
+ return QPixmap::fromImage(image);
+}
+#endif //ifndef Q_WS_WINCE
+#endif //ifdef Q_WS_WIN
+
+QT_END_NAMESPACE
diff --git a/src/gui/platforms/win/qprintengine_win.cpp b/src/gui/platforms/win/qprintengine_win.cpp
new file mode 100644
index 0000000000..07d66f5bd0
--- /dev/null
+++ b/src/gui/platforms/win/qprintengine_win.cpp
@@ -0,0 +1,1776 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QT_NO_PRINTER
+
+#include "qprinter_p.h"
+#include "qprintengine_win_p.h"
+
+#include <limits.h>
+
+#include <private/qfont_p.h>
+#include <private/qfontengine_p.h>
+#include <private/qpainter_p.h>
+
+#include <qbitmap.h>
+#include <qdebug.h>
+#include <qvector.h>
+#include <qpicture.h>
+#include <private/qpicture_p.h>
+
+QT_BEGIN_NAMESPACE
+
+extern QPainterPath qt_regionToPath(const QRegion &region);
+
+// #define QT_DEBUG_DRAW
+
+static void draw_text_item_win(const QPointF &_pos, const QTextItemInt &ti, HDC hdc,
+ bool convertToText, const QTransform &xform, const QPointF &topLeft);
+
+static const struct {
+ int winSizeName;
+ QPrinter::PaperSize qtSizeName;
+} dmMapping[] = {
+ { DMPAPER_LETTER, QPrinter::Letter },
+ { DMPAPER_LETTERSMALL, QPrinter::Letter },
+ { DMPAPER_TABLOID, QPrinter::Tabloid },
+ { DMPAPER_LEDGER, QPrinter::Ledger },
+ { DMPAPER_LEGAL, QPrinter::Legal },
+ { DMPAPER_EXECUTIVE, QPrinter::Executive },
+ { DMPAPER_A3, QPrinter::A3 },
+ { DMPAPER_A4, QPrinter::A4 },
+ { DMPAPER_A4SMALL, QPrinter::A4 },
+ { DMPAPER_A5, QPrinter::A5 },
+ { DMPAPER_B4, QPrinter::B4 },
+ { DMPAPER_B5, QPrinter::B5 },
+ { DMPAPER_FOLIO, QPrinter::Folio },
+ { DMPAPER_ENV_10, QPrinter::Comm10E },
+ { DMPAPER_ENV_DL, QPrinter::DLE },
+ { DMPAPER_ENV_C3, QPrinter::C5E },
+ { DMPAPER_LETTER_EXTRA, QPrinter::Letter },
+ { DMPAPER_LEGAL_EXTRA, QPrinter::Legal },
+ { DMPAPER_TABLOID_EXTRA, QPrinter::Tabloid },
+ { DMPAPER_A4_EXTRA, QPrinter::A4},
+ { DMPAPER_LETTER_TRANSVERSE, QPrinter::Letter},
+ { DMPAPER_A4_TRANSVERSE, QPrinter::A4},
+ { DMPAPER_LETTER_EXTRA_TRANSVERSE, QPrinter::Letter },
+ { DMPAPER_A_PLUS, QPrinter::A4 },
+ { DMPAPER_B_PLUS, QPrinter::A3 },
+ { DMPAPER_LETTER_PLUS, QPrinter::Letter },
+ { DMPAPER_A4_PLUS, QPrinter::A4 },
+ { DMPAPER_A5_TRANSVERSE, QPrinter::A5 },
+ { DMPAPER_B5_TRANSVERSE, QPrinter::B5 },
+ { DMPAPER_A3_EXTRA, QPrinter::A3 },
+ { DMPAPER_A5_EXTRA, QPrinter::A5 },
+ { DMPAPER_B5_EXTRA, QPrinter::B5 },
+ { DMPAPER_A2, QPrinter::A2 },
+ { DMPAPER_A3_TRANSVERSE, QPrinter::A3 },
+ { DMPAPER_A3_EXTRA_TRANSVERSE,QPrinter::A3 },
+ { 0, QPrinter::Custom }
+};
+
+QPrinter::PaperSize mapDevmodePaperSize(int s)
+{
+ int i = 0;
+ while ((dmMapping[i].winSizeName > 0) && (dmMapping[i].winSizeName != s))
+ i++;
+ return dmMapping[i].qtSizeName;
+}
+
+static int mapPaperSizeDevmode(QPrinter::PaperSize s)
+{
+ int i = 0;
+ while ((dmMapping[i].winSizeName > 0) && (dmMapping[i].qtSizeName != s))
+ i++;
+ return dmMapping[i].winSizeName;
+}
+
+static const struct {
+ int winSourceName;
+ QPrinter::PaperSource qtSourceName;
+} sources[] = {
+ { DMBIN_ONLYONE, QPrinter::OnlyOne },
+ { DMBIN_LOWER, QPrinter::Lower },
+ { DMBIN_MIDDLE, QPrinter::Middle },
+ { DMBIN_MANUAL, QPrinter::Manual },
+ { DMBIN_ENVELOPE, QPrinter::Envelope },
+ { DMBIN_ENVMANUAL, QPrinter::EnvelopeManual },
+ { DMBIN_AUTO, QPrinter::Auto },
+ { DMBIN_TRACTOR, QPrinter::Tractor },
+ { DMBIN_SMALLFMT, QPrinter::SmallFormat },
+ { DMBIN_LARGEFMT, QPrinter::LargeFormat },
+ { DMBIN_LARGECAPACITY, QPrinter::LargeCapacity },
+ { DMBIN_CASSETTE, QPrinter::Cassette },
+ { DMBIN_FORMSOURCE, QPrinter::FormSource },
+ { 0, (QPrinter::PaperSource) -1 }
+};
+
+static QPrinter::PaperSource mapDevmodePaperSource(int s)
+{
+ int i = 0;
+ while ((sources[i].winSourceName > 0) && (sources[i].winSourceName != s))
+ i++;
+ return sources[i].winSourceName ? sources[i].qtSourceName : (QPrinter::PaperSource) s;
+}
+
+static int mapPaperSourceDevmode(QPrinter::PaperSource s)
+{
+ int i = 0;
+ while ((sources[i].qtSourceName >= 0) && (sources[i].qtSourceName != s))
+ i++;
+ return sources[i].winSourceName ? sources[i].winSourceName : s;
+}
+
+QWin32PrintEngine::QWin32PrintEngine(QPrinter::PrinterMode mode)
+ : QAlphaPaintEngine(*(new QWin32PrintEnginePrivate),
+ PaintEngineFeatures(PrimitiveTransform
+ | PixmapTransform
+ | PerspectiveTransform
+ | PainterPaths
+ | Antialiasing
+ | PaintOutsidePaintEvent))
+{
+ Q_D(QWin32PrintEngine);
+ d->docName = QLatin1String("document1");
+ d->mode = mode;
+ d->queryDefault();
+ d->initialize();
+}
+
+bool QWin32PrintEngine::begin(QPaintDevice *pdev)
+{
+ Q_D(QWin32PrintEngine);
+
+ QAlphaPaintEngine::begin(pdev);
+ if (!continueCall())
+ return true;
+
+ if (d->reinit) {
+ d->resetDC();
+ d->reinit = false;
+ }
+
+ // ### set default colors and stuff...
+
+ bool ok = d->state == QPrinter::Idle;
+
+ if (!d->hdc)
+ return false;
+
+ // Assign the FILE: to get the query...
+ if (d->printToFile && d->fileName.isEmpty())
+ d->fileName = d->port;
+
+ d->devMode->dmCopies = d->num_copies;
+
+ DOCINFO di;
+ memset(&di, 0, sizeof(DOCINFO));
+ di.cbSize = sizeof(DOCINFO);
+ di.lpszDocName = reinterpret_cast<const wchar_t *>(d->docName.utf16());
+ if (d->printToFile && !d->fileName.isEmpty())
+ di.lpszOutput = reinterpret_cast<const wchar_t *>(d->fileName.utf16());
+ if (ok && StartDoc(d->hdc, &di) == SP_ERROR) {
+ qErrnoWarning("QWin32PrintEngine::begin: StartDoc failed");
+ ok = false;
+ }
+
+ if (StartPage(d->hdc) <= 0) {
+ qErrnoWarning("QWin32PrintEngine::begin: StartPage failed");
+ ok = false;
+ }
+
+ if (!ok) {
+ d->state = QPrinter::Idle;
+ } else {
+ d->state = QPrinter::Active;
+ }
+
+ d->matrix = QTransform();
+ d->has_pen = true;
+ d->pen = QColor(Qt::black);
+ d->has_brush = false;
+
+ d->complex_xform = false;
+
+ updateMatrix(d->matrix);
+
+ if (!ok)
+ cleanUp();
+
+ return ok;
+}
+
+bool QWin32PrintEngine::end()
+{
+ Q_D(QWin32PrintEngine);
+
+ if (d->hdc) {
+ if (d->state == QPrinter::Aborted) {
+ cleanUp();
+ AbortDoc(d->hdc);
+ return true;
+ }
+ }
+
+ QAlphaPaintEngine::end();
+ if (!continueCall())
+ return true;
+
+ if (d->hdc) {
+ EndPage(d->hdc); // end; printing done
+ EndDoc(d->hdc);
+ }
+
+ d->state = QPrinter::Idle;
+ d->reinit = true;
+ return true;
+}
+
+bool QWin32PrintEngine::newPage()
+{
+ Q_D(QWin32PrintEngine);
+ Q_ASSERT(isActive());
+
+ Q_ASSERT(d->hdc);
+
+ flushAndInit();
+
+ bool transparent = GetBkMode(d->hdc) == TRANSPARENT;
+
+ if (!EndPage(d->hdc)) {
+ qErrnoWarning("QWin32PrintEngine::newPage: EndPage failed");
+ return false;
+ }
+
+ if (d->reinit) {
+ if (!d->resetDC()) {
+ qErrnoWarning("QWin32PrintEngine::newPage: ResetDC failed");
+ return false;
+ }
+ d->reinit = false;
+ }
+
+ if (!StartPage(d->hdc)) {
+ qErrnoWarning("Win32PrintEngine::newPage: StartPage failed");
+ return false;
+ }
+
+ SetTextAlign(d->hdc, TA_BASELINE);
+ if (transparent)
+ SetBkMode(d->hdc, TRANSPARENT);
+
+ // ###
+ return true;
+
+ bool success = false;
+ if (d->hdc && d->state == QPrinter::Active) {
+ if (EndPage(d->hdc) != SP_ERROR) {
+ // reinitialize the DC before StartPage if needed,
+ // because resetdc is disabled between calls to the StartPage and EndPage functions
+ // (see StartPage documentation in the Platform SDK:Windows GDI)
+// state = PST_ACTIVEDOC;
+// reinit();
+// state = PST_ACTIVE;
+ // start the new page now
+ if (d->reinit) {
+ if (!d->resetDC())
+ qErrnoWarning("QWin32PrintEngine::newPage(), ResetDC failed (2)");
+ d->reinit = false;
+ }
+ success = (StartPage(d->hdc) != SP_ERROR);
+ }
+ if (!success) {
+ d->state = QPrinter::Aborted;
+ return false;
+ }
+ }
+ return true;
+}
+
+bool QWin32PrintEngine::abort()
+{
+ // do nothing loop.
+ return false;
+}
+
+void QWin32PrintEngine::drawTextItem(const QPointF &p, const QTextItem &textItem)
+{
+ Q_D(const QWin32PrintEngine);
+
+ QAlphaPaintEngine::drawTextItem(p, textItem);
+ if (!continueCall())
+ return;
+
+ const QTextItemInt &ti = static_cast<const QTextItemInt &>(textItem);
+ QRgb brushColor = state->pen().brush().color().rgb();
+ bool fallBack = state->pen().brush().style() != Qt::SolidPattern
+ || qAlpha(brushColor) != 0xff
+ || d->txop >= QTransform::TxProject
+ || ti.fontEngine->type() != QFontEngine::Win;
+
+
+ if (!fallBack) {
+ QFontEngineWin *fe = static_cast<QFontEngineWin *>(ti.fontEngine);
+
+ // Try selecting the font to see if we get a substitution font
+ SelectObject(d->hdc, fe->hfont);
+
+ if (GetDeviceCaps(d->hdc, TECHNOLOGY) != DT_CHARSTREAM) {
+ wchar_t n[64];
+ GetTextFace(d->hdc, 64, n);
+ fallBack = QString::fromWCharArray(n)
+ != QString::fromWCharArray(fe->logfont.lfFaceName);
+ }
+ }
+
+
+ if (fallBack) {
+ QPaintEngine::drawTextItem(p, textItem);
+ return ;
+ }
+
+ // We only want to convert the glyphs to text if the entire string is compatible with ASCII
+ // and if we actually have access to the chars.
+ bool convertToText = ti.chars != 0;
+ for (int i=0; i < ti.num_chars; ++i) {
+ if (ti.chars[i].unicode() >= 0x80) {
+ convertToText = false;
+ break;
+ }
+
+ if (ti.logClusters[i] != i) {
+ convertToText = false;
+ break;
+ }
+ }
+
+ COLORREF cf = RGB(qRed(brushColor), qGreen(brushColor), qBlue(brushColor));
+ SelectObject(d->hdc, CreateSolidBrush(cf));
+ SelectObject(d->hdc, CreatePen(PS_SOLID, 1, cf));
+ SetTextColor(d->hdc, cf);
+
+ draw_text_item_win(p, ti, d->hdc, convertToText, d->matrix, d->devPaperRect.topLeft());
+ DeleteObject(SelectObject(d->hdc,GetStockObject(HOLLOW_BRUSH)));
+ DeleteObject(SelectObject(d->hdc,GetStockObject(BLACK_PEN)));
+}
+
+static inline qreal mmToInches(double mm)
+{
+ return mm*0.039370147;
+}
+
+static inline qreal inchesToMM(double in)
+{
+ return in/0.039370147;
+}
+
+int QWin32PrintEngine::metric(QPaintDevice::PaintDeviceMetric m) const
+{
+ Q_D(const QWin32PrintEngine);
+
+ if (!d->hdc)
+ return 0;
+
+ int val;
+ int res = d->resolution;
+
+ switch (m) {
+ case QPaintDevice::PdmWidth:
+ if (d->has_custom_paper_size) {
+ val = qRound(d->paper_size.width() * res / 72.0);
+ } else {
+ int logPixelsX = GetDeviceCaps(d->hdc, LOGPIXELSX);
+ if (logPixelsX == 0) {
+ qWarning("QWin32PrintEngine::metric: GetDeviceCaps() failed, "
+ "might be a driver problem");
+ logPixelsX = 600; // Reasonable default
+ }
+ val = res
+ * GetDeviceCaps(d->hdc, d->fullPage ? PHYSICALWIDTH : HORZRES)
+ / logPixelsX;
+ }
+ if (d->pageMarginsSet)
+ val -= int(mmToInches((d->previousDialogMargins.left() +
+ d->previousDialogMargins.width()) / 100.0) * res);
+ break;
+ case QPaintDevice::PdmHeight:
+ if (d->has_custom_paper_size) {
+ val = qRound(d->paper_size.height() * res / 72.0);
+ } else {
+ int logPixelsY = GetDeviceCaps(d->hdc, LOGPIXELSY);
+ if (logPixelsY == 0) {
+ qWarning("QWin32PrintEngine::metric: GetDeviceCaps() failed, "
+ "might be a driver problem");
+ logPixelsY = 600; // Reasonable default
+ }
+ val = res
+ * GetDeviceCaps(d->hdc, d->fullPage ? PHYSICALHEIGHT : VERTRES)
+ / logPixelsY;
+ }
+ if (d->pageMarginsSet)
+ val -= int(mmToInches((d->previousDialogMargins.top() +
+ d->previousDialogMargins.height()) / 100.0) * res);
+ break;
+ case QPaintDevice::PdmDpiX:
+ val = res;
+ break;
+ case QPaintDevice::PdmDpiY:
+ val = res;
+ break;
+ case QPaintDevice::PdmPhysicalDpiX:
+ val = GetDeviceCaps(d->hdc, LOGPIXELSX);
+ break;
+ case QPaintDevice::PdmPhysicalDpiY:
+ val = GetDeviceCaps(d->hdc, LOGPIXELSY);
+ break;
+ case QPaintDevice::PdmWidthMM:
+ if (d->has_custom_paper_size) {
+ val = qRound(d->paper_size.width()*25.4/72);
+ } else {
+ if (!d->fullPage) {
+ val = GetDeviceCaps(d->hdc, HORZSIZE);
+ } else {
+ float wi = 25.4 * GetDeviceCaps(d->hdc, PHYSICALWIDTH);
+ int logPixelsX = GetDeviceCaps(d->hdc, LOGPIXELSX);
+ if (logPixelsX == 0) {
+ qWarning("QWin32PrintEngine::metric: GetDeviceCaps() failed, "
+ "might be a driver problem");
+ logPixelsX = 600; // Reasonable default
+ }
+ val = qRound(wi / logPixelsX);
+ }
+ }
+ if (d->pageMarginsSet)
+ val -= (d->previousDialogMargins.left() +
+ d->previousDialogMargins.width()) / 100.0;
+ break;
+ case QPaintDevice::PdmHeightMM:
+ if (d->has_custom_paper_size) {
+ val = qRound(d->paper_size.height()*25.4/72);
+ } else {
+ if (!d->fullPage) {
+ val = GetDeviceCaps(d->hdc, VERTSIZE);
+ } else {
+ float hi = 25.4 * GetDeviceCaps(d->hdc, PHYSICALHEIGHT);
+ int logPixelsY = GetDeviceCaps(d->hdc, LOGPIXELSY);
+ if (logPixelsY == 0) {
+ qWarning("QWin32PrintEngine::metric: GetDeviceCaps() failed, "
+ "might be a driver problem");
+ logPixelsY = 600; // Reasonable default
+ }
+ val = qRound(hi / logPixelsY);
+ }
+ }
+ if (d->pageMarginsSet)
+ val -= (d->previousDialogMargins.top() +
+ d->previousDialogMargins.height()) / 100.0;
+ break;
+ case QPaintDevice::PdmNumColors:
+ {
+ int bpp = GetDeviceCaps(d->hdc, BITSPIXEL);
+ if(bpp==32)
+ val = INT_MAX;
+ else if(bpp<=8)
+ val = GetDeviceCaps(d->hdc, NUMCOLORS);
+ else
+ val = 1 << (bpp * GetDeviceCaps(d->hdc, PLANES));
+ }
+ break;
+ case QPaintDevice::PdmDepth:
+ val = GetDeviceCaps(d->hdc, PLANES);
+ break;
+ default:
+ qWarning("QPrinter::metric: Invalid metric command");
+ return 0;
+ }
+ return val;
+}
+
+void QWin32PrintEngine::updateState(const QPaintEngineState &state)
+{
+ Q_D(QWin32PrintEngine);
+
+ QAlphaPaintEngine::updateState(state);
+ if (!continueCall())
+ return;
+
+ if (state.state() & DirtyTransform) {
+ updateMatrix(state.transform());
+ }
+
+ if (state.state() & DirtyPen) {
+ d->pen = state.pen();
+ d->has_pen = d->pen.style() != Qt::NoPen && d->pen.isSolid();
+ }
+
+ if (state.state() & DirtyBrush) {
+ QBrush brush = state.brush();
+ d->has_brush = brush.style() == Qt::SolidPattern;
+ d->brush_color = brush.color();
+ }
+
+ if (state.state() & DirtyClipEnabled) {
+ if (state.isClipEnabled())
+ updateClipPath(painter()->clipPath(), Qt::ReplaceClip);
+ else
+ updateClipPath(QPainterPath(), Qt::NoClip);
+ }
+
+ if (state.state() & DirtyClipPath) {
+ updateClipPath(state.clipPath(), state.clipOperation());
+ }
+
+ if (state.state() & DirtyClipRegion) {
+ QRegion clipRegion = state.clipRegion();
+ QPainterPath clipPath = qt_regionToPath(clipRegion);
+ updateClipPath(clipPath, state.clipOperation());
+ }
+}
+
+void QWin32PrintEngine::updateClipPath(const QPainterPath &clipPath, Qt::ClipOperation op)
+{
+ Q_D(QWin32PrintEngine);
+
+ bool doclip = true;
+ if (op == Qt::NoClip) {
+ SelectClipRgn(d->hdc, 0);
+ doclip = false;
+ }
+
+ if (doclip) {
+ QPainterPath xformed = clipPath * d->matrix;
+
+ if (xformed.isEmpty()) {
+ QRegion empty(-0x1000000, -0x1000000, 1, 1);
+ SelectClipRgn(d->hdc, empty.handle());
+ } else {
+ d->composeGdiPath(xformed);
+ const int ops[] = {
+ -1, // Qt::NoClip, covered above
+ RGN_COPY, // Qt::ReplaceClip
+ RGN_AND, // Qt::IntersectClip
+ RGN_OR // Qt::UniteClip
+ };
+ Q_ASSERT(op > 0 && unsigned(op) <= sizeof(ops) / sizeof(int));
+ SelectClipPath(d->hdc, ops[op]);
+ }
+ }
+
+ QPainterPath aclip = qt_regionToPath(alphaClipping());
+ if (!aclip.isEmpty()) {
+ QTransform tx(d->stretch_x, 0, 0, d->stretch_y, d->origin_x, d->origin_y);
+ d->composeGdiPath(tx.map(aclip));
+ SelectClipPath(d->hdc, RGN_DIFF);
+ }
+}
+
+void QWin32PrintEngine::updateMatrix(const QTransform &m)
+{
+ Q_D(QWin32PrintEngine);
+
+ QTransform stretch(d->stretch_x, 0, 0, d->stretch_y, d->origin_x, d->origin_y);
+ d->painterMatrix = m;
+ d->matrix = d->painterMatrix * stretch;
+ d->txop = d->matrix.type();
+ d->complex_xform = (d->txop > QTransform::TxScale);
+}
+
+void QWin32PrintEngine::drawPixmap(const QRectF &targetRect,
+ const QPixmap &originalPixmap,
+ const QRectF &sourceRect)
+{
+ Q_D(QWin32PrintEngine);
+
+ QAlphaPaintEngine::drawPixmap(targetRect, originalPixmap, sourceRect);
+ if (!continueCall())
+ return;
+
+ const int tileSize = 2048;
+
+ QRectF r = targetRect;
+ QRectF sr = sourceRect;
+
+ QPixmap pixmap = originalPixmap;
+ if (sr.size() != pixmap.size()) {
+ pixmap = pixmap.copy(sr.toRect());
+ }
+
+ qreal scaleX = 1.0f;
+ qreal scaleY = 1.0f;
+
+ QTransform scaleMatrix = QTransform::fromScale(r.width() / pixmap.width(), r.height() / pixmap.height());
+ QTransform adapted = QPixmap::trueMatrix(d->painterMatrix * scaleMatrix,
+ pixmap.width(), pixmap.height());
+
+ qreal xform_offset_x = adapted.dx();
+ qreal xform_offset_y = adapted.dy();
+
+ if (d->complex_xform) {
+ pixmap = pixmap.transformed(adapted);
+ scaleX = d->stretch_x;
+ scaleY = d->stretch_y;
+ } else {
+ scaleX = d->stretch_x * (r.width() / pixmap.width()) * d->painterMatrix.m11();
+ scaleY = d->stretch_y * (r.height() / pixmap.height()) * d->painterMatrix.m22();
+ }
+
+ QPointF topLeft = r.topLeft() * d->painterMatrix;
+ int tx = int(topLeft.x() * d->stretch_x + d->origin_x);
+ int ty = int(topLeft.y() * d->stretch_y + d->origin_y);
+ int tw = qAbs(int(pixmap.width() * scaleX));
+ int th = qAbs(int(pixmap.height() * scaleY));
+
+ xform_offset_x *= d->stretch_x;
+ xform_offset_y *= d->stretch_y;
+
+ int dc_state = SaveDC(d->hdc);
+
+ int tilesw = pixmap.width() / tileSize;
+ int tilesh = pixmap.height() / tileSize;
+ ++tilesw;
+ ++tilesh;
+
+ int txinc = tileSize*scaleX;
+ int tyinc = tileSize*scaleY;
+
+ for (int y = 0; y < tilesh; ++y) {
+ int tposy = ty + (y * tyinc);
+ int imgh = tileSize;
+ int height = tyinc;
+ if (y == (tilesh - 1)) {
+ imgh = pixmap.height() - (y * tileSize);
+ height = (th - (y * tyinc));
+ }
+ for (int x = 0; x < tilesw; ++x) {
+ int tposx = tx + (x * txinc);
+ int imgw = tileSize;
+ int width = txinc;
+ if (x == (tilesw - 1)) {
+ imgw = pixmap.width() - (x * tileSize);
+ width = (tw - (x * txinc));
+ }
+
+ QPixmap p = pixmap.copy(tileSize * x, tileSize * y, imgw, imgh);
+ HBITMAP hbitmap = p.toWinHBITMAP(QPixmap::NoAlpha);
+ HDC display_dc = GetDC(0);
+ HDC hbitmap_hdc = CreateCompatibleDC(display_dc);
+ HGDIOBJ null_bitmap = SelectObject(hbitmap_hdc, hbitmap);
+
+ ReleaseDC(0, display_dc);
+
+ if (!StretchBlt(d->hdc, qRound(tposx - xform_offset_x), qRound(tposy - xform_offset_y), width, height,
+ hbitmap_hdc, 0, 0, p.width(), p.height(), SRCCOPY))
+ qErrnoWarning("QWin32PrintEngine::drawPixmap, StretchBlt failed");
+
+ SelectObject(hbitmap_hdc, null_bitmap);
+ DeleteObject(hbitmap);
+ DeleteDC(hbitmap_hdc);
+ }
+ }
+
+ RestoreDC(d->hdc, dc_state);
+}
+
+
+void QWin32PrintEngine::drawTiledPixmap(const QRectF &r, const QPixmap &pm, const QPointF &pos)
+{
+ Q_D(QWin32PrintEngine);
+
+ QAlphaPaintEngine::drawTiledPixmap(r, pm, pos);
+ if (!continueCall())
+ return;
+
+ if (d->complex_xform || !pos.isNull()) {
+ QPaintEngine::drawTiledPixmap(r, pm, pos);
+ } else {
+ int dc_state = SaveDC(d->hdc);
+
+ HDC display_dc = GetDC(0);
+ HBITMAP hbitmap = pm.toWinHBITMAP(QPixmap::NoAlpha);
+ HDC hbitmap_hdc = CreateCompatibleDC(display_dc);
+ HGDIOBJ null_bitmap = SelectObject(hbitmap_hdc, hbitmap);
+
+ ReleaseDC(0, display_dc);
+
+ QRectF trect = d->painterMatrix.mapRect(r);
+ int tx = int(trect.left() * d->stretch_x + d->origin_x);
+ int ty = int(trect.top() * d->stretch_y + d->origin_y);
+
+ int xtiles = int(trect.width() / pm.width()) + 1;
+ int ytiles = int(trect.height() / pm.height()) + 1;
+ int xinc = int(pm.width() * d->stretch_x);
+ int yinc = int(pm.height() * d->stretch_y);
+
+ for (int y = 0; y < ytiles; ++y) {
+ int ity = ty + (yinc * y);
+ int ith = pm.height();
+ if (y == (ytiles - 1)) {
+ ith = int(trect.height() - (pm.height() * y));
+ }
+
+ for (int x = 0; x < xtiles; ++x) {
+ int itx = tx + (xinc * x);
+ int itw = pm.width();
+ if (x == (xtiles - 1)) {
+ itw = int(trect.width() - (pm.width() * x));
+ }
+
+ if (!StretchBlt(d->hdc, itx, ity, int(itw * d->stretch_x), int(ith * d->stretch_y),
+ hbitmap_hdc, 0, 0, itw, ith, SRCCOPY))
+ qErrnoWarning("QWin32PrintEngine::drawPixmap, StretchBlt failed");
+
+ }
+ }
+
+ SelectObject(hbitmap_hdc, null_bitmap);
+ DeleteObject(hbitmap);
+ DeleteDC(hbitmap_hdc);
+
+ RestoreDC(d->hdc, dc_state);
+ }
+}
+
+
+void QWin32PrintEnginePrivate::composeGdiPath(const QPainterPath &path)
+{
+ if (!BeginPath(hdc))
+ qErrnoWarning("QWin32PrintEnginePrivate::drawPath: BeginPath failed");
+
+ // Drawing the subpaths
+ int start = -1;
+ for (int i=0; i<path.elementCount(); ++i) {
+ const QPainterPath::Element &elm = path.elementAt(i);
+ switch (elm.type) {
+ case QPainterPath::MoveToElement:
+ if (start >= 0
+ && path.elementAt(start).x == path.elementAt(i-1).x
+ && path.elementAt(start).y == path.elementAt(i-1).y)
+ CloseFigure(hdc);
+ start = i;
+ MoveToEx(hdc, qRound(elm.x), qRound(elm.y), 0);
+ break;
+ case QPainterPath::LineToElement:
+ LineTo(hdc, qRound(elm.x), qRound(elm.y));
+ break;
+ case QPainterPath::CurveToElement: {
+ POINT pts[3] = {
+ { qRound(elm.x), qRound(elm.y) },
+ { qRound(path.elementAt(i+1).x), qRound(path.elementAt(i+1).y) },
+ { qRound(path.elementAt(i+2).x), qRound(path.elementAt(i+2).y) }
+ };
+ i+=2;
+ PolyBezierTo(hdc, pts, 3);
+ break;
+ }
+ default:
+ qFatal("QWin32PaintEngine::drawPath: Unhandled type: %d", elm.type);
+ }
+ }
+
+ if (start >= 0
+ && path.elementAt(start).x == path.elementAt(path.elementCount()-1).x
+ && path.elementAt(start).y == path.elementAt(path.elementCount()-1).y)
+ CloseFigure(hdc);
+
+ if (!EndPath(hdc))
+ qErrnoWarning("QWin32PaintEngine::drawPath: EndPath failed");
+
+ SetPolyFillMode(hdc, path.fillRule() == Qt::WindingFill ? WINDING : ALTERNATE);
+}
+
+
+void QWin32PrintEnginePrivate::fillPath_dev(const QPainterPath &path, const QColor &color)
+{
+#ifdef QT_DEBUG_DRAW
+ qDebug() << " --- QWin32PrintEnginePrivate::fillPath() bound:" << path.boundingRect() << color;
+#endif
+
+ composeGdiPath(path);
+
+ HBRUSH brush = CreateSolidBrush(RGB(color.red(), color.green(), color.blue()));
+ HGDIOBJ old_brush = SelectObject(hdc, brush);
+ FillPath(hdc);
+ DeleteObject(SelectObject(hdc, old_brush));
+}
+
+void QWin32PrintEnginePrivate::strokePath_dev(const QPainterPath &path, const QColor &color, qreal penWidth)
+{
+ composeGdiPath(path);
+ LOGBRUSH brush;
+ brush.lbStyle = BS_SOLID;
+ brush.lbColor = RGB(color.red(), color.green(), color.blue());
+ DWORD capStyle = PS_ENDCAP_SQUARE;
+ DWORD joinStyle = PS_JOIN_BEVEL;
+ if (pen.capStyle() == Qt::FlatCap)
+ capStyle = PS_ENDCAP_FLAT;
+ else if (pen.capStyle() == Qt::RoundCap)
+ capStyle = PS_ENDCAP_ROUND;
+
+ if (pen.joinStyle() == Qt::MiterJoin)
+ joinStyle = PS_JOIN_MITER;
+ else if (pen.joinStyle() == Qt::RoundJoin)
+ joinStyle = PS_JOIN_ROUND;
+
+ HPEN pen = ExtCreatePen(((penWidth == 0) ? PS_COSMETIC : PS_GEOMETRIC)
+ | PS_SOLID | capStyle | joinStyle,
+ (penWidth == 0) ? 1 : penWidth, &brush, 0, 0);
+
+ HGDIOBJ old_pen = SelectObject(hdc, pen);
+ StrokePath(hdc);
+ DeleteObject(SelectObject(hdc, old_pen));
+}
+
+
+void QWin32PrintEnginePrivate::fillPath(const QPainterPath &path, const QColor &color)
+{
+ fillPath_dev(path * matrix, color);
+}
+
+void QWin32PrintEnginePrivate::strokePath(const QPainterPath &path, const QColor &color)
+{
+ QPainterPathStroker stroker;
+ if (pen.style() == Qt::CustomDashLine) {
+ stroker.setDashPattern(pen.dashPattern());
+ stroker.setDashOffset(pen.dashOffset());
+ } else {
+ stroker.setDashPattern(pen.style());
+ }
+ stroker.setCapStyle(pen.capStyle());
+ stroker.setJoinStyle(pen.joinStyle());
+ stroker.setMiterLimit(pen.miterLimit());
+
+ QPainterPath stroke;
+ qreal width = pen.widthF();
+ if (pen.style() == Qt::SolidLine && (pen.isCosmetic() || matrix.type() < QTransform::TxScale)) {
+ strokePath_dev(path * matrix, color, width);
+ } else {
+ stroker.setWidth(width);
+ if (pen.isCosmetic()) {
+ stroke = stroker.createStroke(path * matrix);
+ } else {
+ stroke = stroker.createStroke(path) * painterMatrix;
+ QTransform stretch(stretch_x, 0, 0, stretch_y, origin_x, origin_y);
+ stroke = stroke * stretch;
+ }
+
+ if (stroke.isEmpty())
+ return;
+
+ fillPath_dev(stroke, color);
+ }
+}
+
+
+void QWin32PrintEngine::drawPath(const QPainterPath &path)
+{
+#ifdef QT_DEBUG_DRAW
+ qDebug() << " - QWin32PrintEngine::drawPath(), bounds: " << path.boundingRect();
+#endif
+
+ Q_D(QWin32PrintEngine);
+
+ QAlphaPaintEngine::drawPath(path);
+ if (!continueCall())
+ return;
+
+ if (d->has_brush)
+ d->fillPath(path, d->brush_color);
+
+ if (d->has_pen)
+ d->strokePath(path, d->pen.color());
+}
+
+
+void QWin32PrintEngine::drawPolygon(const QPointF *points, int pointCount, PolygonDrawMode mode)
+{
+#ifdef QT_DEBUG_DRAW
+ qDebug() << " - QWin32PrintEngine::drawPolygon(), pointCount: " << pointCount;
+#endif
+
+ QAlphaPaintEngine::drawPolygon(points, pointCount, mode);
+ if (!continueCall())
+ return;
+
+ Q_ASSERT(pointCount > 1);
+
+ QPainterPath path(points[0]);
+
+ for (int i=1; i<pointCount; ++i) {
+ path.lineTo(points[i]);
+ }
+
+ Q_D(QWin32PrintEngine);
+
+ bool has_brush = d->has_brush;
+
+ if (mode == PolylineMode)
+ d->has_brush = false; // No brush for polylines
+ else
+ path.closeSubpath(); // polygons are should always be closed.
+
+ drawPath(path);
+ d->has_brush = has_brush;
+}
+
+void QWin32PrintEnginePrivate::queryDefault()
+{
+ /* Read the default printer name, driver and port with the intuitive function
+ * Strings "windows" and "device" are specified in the MSDN under EnumPrinters()
+ */
+ QString noPrinters(QLatin1String("qt_no_printers"));
+ wchar_t buffer[256];
+ GetProfileString(L"windows", L"device",
+ reinterpret_cast<const wchar_t *>(noPrinters.utf16()),
+ buffer, 256);
+ QString output = QString::fromWCharArray(buffer);
+ if (output.isEmpty() || output == noPrinters) // no printers
+ return;
+
+ QStringList info = output.split(QLatin1Char(','));
+ int infoSize = info.size();
+ if (infoSize > 0) {
+ if (name.isEmpty())
+ name = info.at(0);
+ if (program.isEmpty() && infoSize > 1)
+ program = info.at(1);
+ if (port.isEmpty() && infoSize > 2)
+ port = info.at(2);
+ }
+}
+
+QWin32PrintEnginePrivate::~QWin32PrintEnginePrivate()
+{
+ if (hdc)
+ release();
+}
+
+void QWin32PrintEnginePrivate::initialize()
+{
+ if (hdc)
+ release();
+ Q_ASSERT(!hPrinter);
+ Q_ASSERT(!hdc);
+ Q_ASSERT(!devMode);
+ Q_ASSERT(!pInfo);
+
+ if (name.isEmpty())
+ return;
+
+ txop = QTransform::TxNone;
+
+ bool ok = OpenPrinter((LPWSTR)name.utf16(), (LPHANDLE)&hPrinter, 0);
+ if (!ok) {
+ qErrnoWarning("QWin32PrintEngine::initialize: OpenPrinter failed");
+ return;
+ }
+
+ // Fetch the PRINTER_INFO_2 with DEVMODE data containing the
+ // printer settings.
+ DWORD infoSize, numBytes;
+ GetPrinter(hPrinter, 2, NULL, 0, &infoSize);
+ hMem = GlobalAlloc(GHND, infoSize);
+ pInfo = (PRINTER_INFO_2*) GlobalLock(hMem);
+ ok = GetPrinter(hPrinter, 2, (LPBYTE)pInfo, infoSize, &numBytes);
+
+ if (!ok) {
+ qErrnoWarning("QWin32PrintEngine::initialize: GetPrinter failed");
+ GlobalUnlock(pInfo);
+ GlobalFree(hMem);
+ ClosePrinter(hPrinter);
+ pInfo = 0;
+ hMem = 0;
+ hPrinter = 0;
+ return;
+ }
+
+ devMode = pInfo->pDevMode;
+ hdc = CreateDC(reinterpret_cast<const wchar_t *>(program.utf16()),
+ reinterpret_cast<const wchar_t *>(name.utf16()), 0, devMode);
+
+ Q_ASSERT(hPrinter);
+ Q_ASSERT(pInfo);
+
+ if (devMode) {
+ num_copies = devMode->dmCopies;
+ }
+
+ initHDC();
+
+#ifdef QT_DEBUG_DRAW
+ qDebug() << "QWin32PrintEngine::initialize()" << endl
+ << " - paperRect" << devPaperRect << endl
+ << " - pageRect" << devPageRect << endl
+ << " - stretch_x" << stretch_x << endl
+ << " - stretch_y" << stretch_y << endl
+ << " - origin_x" << origin_x << endl
+ << " - origin_y" << origin_y << endl;
+#endif
+}
+
+void QWin32PrintEnginePrivate::initHDC()
+{
+ Q_ASSERT(hdc);
+
+ HDC display_dc = GetDC(0);
+ dpi_x = GetDeviceCaps(hdc, LOGPIXELSX);
+ dpi_y = GetDeviceCaps(hdc, LOGPIXELSY);
+ dpi_display = GetDeviceCaps(display_dc, LOGPIXELSY);
+ ReleaseDC(0, display_dc);
+ if (dpi_display == 0) {
+ qWarning("QWin32PrintEngine::metric: GetDeviceCaps() failed, "
+ "might be a driver problem");
+ dpi_display = 96; // Reasonable default
+ }
+
+ switch(mode) {
+ case QPrinter::ScreenResolution:
+ resolution = dpi_display;
+ stretch_x = dpi_x / double(dpi_display);
+ stretch_y = dpi_y / double(dpi_display);
+ break;
+ case QPrinter::PrinterResolution:
+ case QPrinter::HighResolution:
+ resolution = dpi_y;
+ stretch_x = 1;
+ stretch_y = 1;
+ break;
+ default:
+ break;
+ }
+
+ initDevRects();
+}
+
+void QWin32PrintEnginePrivate::initDevRects()
+{
+ devPaperRect = QRect(0, 0,
+ GetDeviceCaps(hdc, PHYSICALWIDTH),
+ GetDeviceCaps(hdc, PHYSICALHEIGHT));
+ devPhysicalPageRect = QRect(GetDeviceCaps(hdc, PHYSICALOFFSETX),
+ GetDeviceCaps(hdc, PHYSICALOFFSETY),
+ GetDeviceCaps(hdc, HORZRES),
+ GetDeviceCaps(hdc, VERTRES));
+ if (!pageMarginsSet)
+ devPageRect = devPhysicalPageRect;
+ else
+ devPageRect = devPaperRect.adjusted(qRound(mmToInches(previousDialogMargins.left() / 100.0) * dpi_x),
+ qRound(mmToInches(previousDialogMargins.top() / 100.0) * dpi_y),
+ -qRound(mmToInches(previousDialogMargins.width() / 100.0) * dpi_x),
+ -qRound(mmToInches(previousDialogMargins.height() / 100.0) * dpi_y));
+ updateOrigin();
+}
+
+void QWin32PrintEnginePrivate::setPageMargins(int marginLeft, int marginTop, int marginRight, int marginBottom)
+{
+ pageMarginsSet = true;
+ previousDialogMargins = QRect(marginLeft, marginTop, marginRight, marginBottom);
+
+ devPageRect = devPaperRect.adjusted(qRound(mmToInches(marginLeft / 100.0) * dpi_x),
+ qRound(mmToInches(marginTop / 100.0) * dpi_y),
+ - qRound(mmToInches(marginRight / 100.0) * dpi_x),
+ - qRound(mmToInches(marginBottom / 100.0) * dpi_y));
+ updateOrigin();
+}
+
+QRect QWin32PrintEnginePrivate::getPageMargins() const
+{
+ if (pageMarginsSet)
+ return previousDialogMargins;
+ else
+ return QRect(qRound(inchesToMM(devPhysicalPageRect.left()) * 100.0 / dpi_x),
+ qRound(inchesToMM(devPhysicalPageRect.top()) * 100.0 / dpi_y),
+ qRound(inchesToMM(devPaperRect.right() - devPhysicalPageRect.right()) * 100.0 / dpi_x),
+ qRound(inchesToMM(devPaperRect.bottom() - devPhysicalPageRect.bottom()) * 100.0 / dpi_y));
+}
+
+void QWin32PrintEnginePrivate::release()
+{
+ if (hdc == 0)
+ return;
+
+ if (globalDevMode) { // Devmode comes from print dialog
+ GlobalUnlock(globalDevMode);
+ } else { // Devmode comes from initialize...
+ // devMode is a part of the same memory block as pInfo so one free is enough...
+ GlobalUnlock(hMem);
+ GlobalFree(hMem);
+ }
+ if (hPrinter)
+ ClosePrinter(hPrinter);
+ DeleteDC(hdc);
+
+ hdc = 0;
+ hPrinter = 0;
+ pInfo = 0;
+ hMem = 0;
+ devMode = 0;
+}
+
+QList<QVariant> QWin32PrintEnginePrivate::queryResolutions() const
+{
+ // Read the supported resolutions of the printer.
+ QList<QVariant> list;
+
+ DWORD numRes = DeviceCapabilities(reinterpret_cast<const wchar_t *>(name.utf16()),
+ reinterpret_cast<const wchar_t *>(port.utf16()),
+ DC_ENUMRESOLUTIONS, 0, 0);
+ if (numRes == (DWORD)-1)
+ return list;
+
+ LONG *enumRes = (LONG*)malloc(numRes * 2 * sizeof(LONG));
+ DWORD errRes = DeviceCapabilities(reinterpret_cast<const wchar_t *>(name.utf16()),
+ reinterpret_cast<const wchar_t *>(port.utf16()),
+ DC_ENUMRESOLUTIONS, (LPWSTR)enumRes, 0);
+
+ if (errRes == (DWORD)-1) {
+ qErrnoWarning("QWin32PrintEngine::queryResolutions: DeviceCapabilities failed");
+ return list;
+ }
+
+ for (uint i=0; i<numRes; ++i)
+ list.append(int(enumRes[i * 2]));
+
+ return list;
+}
+
+void QWin32PrintEnginePrivate::doReinit()
+{
+ if (state == QPrinter::Active) {
+ reinit = true;
+ } else {
+ resetDC();
+ initDevRects();
+ reinit = false;
+ }
+}
+
+void QWin32PrintEnginePrivate::updateOrigin()
+{
+ if (fullPage) {
+ // subtract physical margins to make (0,0) absolute top corner of paper
+ // then add user defined margins
+ origin_x = -devPhysicalPageRect.x();
+ origin_y = -devPhysicalPageRect.y();
+ if (pageMarginsSet) {
+ origin_x += devPageRect.left();
+ origin_y += devPageRect.top();
+ }
+ } else {
+ origin_x = 0;
+ origin_y = 0;
+ if (pageMarginsSet) {
+ origin_x = devPageRect.left() - devPhysicalPageRect.x();
+ origin_y = devPageRect.top() - devPhysicalPageRect.y();
+ }
+ }
+}
+
+void QWin32PrintEngine::setProperty(PrintEnginePropertyKey key, const QVariant &value)
+{
+ Q_D(QWin32PrintEngine);
+ switch (key) {
+ case PPK_CollateCopies:
+ {
+ if (!d->devMode)
+ break;
+ d->devMode->dmCollate = value.toBool() ? DMCOLLATE_TRUE : DMCOLLATE_FALSE;
+ d->doReinit();
+ }
+ break;
+
+ case PPK_ColorMode:
+ {
+ if (!d->devMode)
+ break;
+ d->devMode->dmColor = (value.toInt() == QPrinter::Color) ? DMCOLOR_COLOR : DMCOLOR_MONOCHROME;
+ d->doReinit();
+ }
+ break;
+
+ case PPK_Creator:
+
+ break;
+
+ case PPK_DocumentName:
+ if (isActive()) {
+ qWarning("QWin32PrintEngine: Cannot change document name while printing is active");
+ return;
+ }
+ d->docName = value.toString();
+ break;
+
+ case PPK_FullPage:
+ d->fullPage = value.toBool();
+ d->updateOrigin();
+ break;
+
+ case PPK_CopyCount: // fallthrough
+ case PPK_NumberOfCopies:
+ if (!d->devMode)
+ break;
+ d->num_copies = value.toInt();
+ d->devMode->dmCopies = d->num_copies;
+ d->doReinit();
+ break;
+
+ case PPK_Orientation:
+ {
+ if (!d->devMode)
+ break;
+ int orientation = value.toInt() == QPrinter::Landscape ? DMORIENT_LANDSCAPE : DMORIENT_PORTRAIT;
+ int old_orientation = d->devMode->dmOrientation;
+ d->devMode->dmOrientation = orientation;
+ if (d->has_custom_paper_size && old_orientation != orientation)
+ d->paper_size = QSizeF(d->paper_size.height(), d->paper_size.width());
+ d->doReinit();
+ }
+ break;
+
+ case PPK_OutputFileName:
+ if (isActive()) {
+ qWarning("QWin32PrintEngine: Cannot change filename while printing");
+ } else {
+ d->fileName = value.toString();
+ d->printToFile = !value.toString().isEmpty();
+ }
+ break;
+
+ case PPK_PaperSize:
+ if (!d->devMode)
+ break;
+ d->devMode->dmPaperSize = mapPaperSizeDevmode(QPrinter::PaperSize(value.toInt()));
+ d->has_custom_paper_size = (QPrinter::PaperSize(value.toInt()) == QPrinter::Custom);
+ d->doReinit();
+ break;
+
+ case PPK_PaperSource:
+ {
+ if (!d->devMode)
+ break;
+ int dmMapped = DMBIN_AUTO;
+
+ QList<QVariant> v = property(PPK_PaperSources).toList();
+ if (v.contains(value))
+ dmMapped = mapPaperSourceDevmode(QPrinter::PaperSource(value.toInt()));
+
+ d->devMode->dmDefaultSource = dmMapped;
+ d->doReinit();
+ }
+ break;
+
+ case PPK_PrinterName:
+ d->name = value.toString();
+ if(d->name.isEmpty())
+ d->queryDefault();
+ d->initialize();
+ break;
+
+ case PPK_Resolution:
+ {
+ d->resolution = value.toInt();
+
+ d->stretch_x = d->dpi_x / double(d->resolution);
+ d->stretch_y = d->dpi_y / double(d->resolution);
+ }
+ break;
+
+ case PPK_SelectionOption:
+
+ break;
+
+ case PPK_SupportedResolutions:
+
+ break;
+
+
+ case PPK_WindowsPageSize:
+ if (!d->devMode)
+ break;
+ d->has_custom_paper_size = false;
+ d->devMode->dmPaperSize = value.toInt();
+ d->doReinit();
+ break;
+
+ case PPK_CustomPaperSize:
+ {
+ d->has_custom_paper_size = true;
+ d->paper_size = value.toSizeF();
+ if (!d->devMode)
+ break;
+ int orientation = d->devMode->dmOrientation;
+ DWORD needed = 0;
+ DWORD returned = 0;
+ if (!EnumForms(d->hPrinter, 1, 0, 0, &needed, &returned)) {
+ BYTE *forms = (BYTE *) malloc(needed);
+ if (EnumForms(d->hPrinter, 1, forms, needed, &needed, &returned)) {
+ for (DWORD i=0; i< returned; ++i) {
+ FORM_INFO_1 *formArray = reinterpret_cast<FORM_INFO_1 *>(forms);
+ // the form sizes are specified in 1000th of a mm,
+ // convert the size to Points
+ QSizeF size((formArray[i].Size.cx * 72/25.4)/1000.0,
+ (formArray[i].Size.cy * 72/25.4)/1000.0);
+ if (qAbs(d->paper_size.width() - size.width()) <= 2
+ && qAbs(d->paper_size.height() - size.height()) <= 2)
+ {
+ d->devMode->dmPaperSize = i + 1;
+ break;
+ }
+ }
+ }
+ free(forms);
+ }
+ if (orientation != DMORIENT_PORTRAIT)
+ d->paper_size = QSizeF(d->paper_size.height(), d->paper_size.width());
+ break;
+ }
+
+ case PPK_PageMargins:
+ {
+ QList<QVariant> margins(value.toList());
+ Q_ASSERT(margins.size() == 4);
+ int left, top, right, bottom;
+ // specified in 1/100 mm
+ left = (margins.at(0).toReal()*25.4/72.0) * 100;
+ top = (margins.at(1).toReal()*25.4/72.0) * 100;
+ right = (margins.at(2).toReal()*25.4/72.0) * 100;
+ bottom = (margins.at(3).toReal()*25.4/72.0) * 100;
+ d->setPageMargins(left, top, right, bottom);
+ break;
+ }
+ default:
+ // Do nothing
+ break;
+ }
+}
+
+QVariant QWin32PrintEngine::property(PrintEnginePropertyKey key) const
+{
+ Q_D(const QWin32PrintEngine);
+ QVariant value;
+ switch (key) {
+
+ case PPK_CollateCopies:
+ value = false;
+ break;
+
+ case PPK_ColorMode:
+ {
+ if (!d->devMode) {
+ value = QPrinter::Color;
+ } else {
+ value = (d->devMode->dmColor == DMCOLOR_COLOR) ? QPrinter::Color : QPrinter::GrayScale;
+ }
+ }
+ break;
+
+ case PPK_DocumentName:
+ value = d->docName;
+ break;
+
+ case PPK_FullPage:
+ value = d->fullPage;
+ break;
+
+ case PPK_CopyCount:
+ value = d->num_copies;
+ break;
+
+ case PPK_SupportsMultipleCopies:
+ value = true;
+ break;
+
+ case PPK_NumberOfCopies:
+ value = 1;
+ break;
+
+ case PPK_Orientation:
+ {
+ if (!d->devMode) {
+ value = QPrinter::Portrait;
+ } else {
+ value = (d->devMode->dmOrientation == DMORIENT_LANDSCAPE) ? QPrinter::Landscape : QPrinter::Portrait;
+ }
+ }
+ break;
+
+ case PPK_OutputFileName:
+ value = d->fileName;
+ break;
+
+ case PPK_PageRect:
+ if (d->has_custom_paper_size) {
+ QRect rect(0, 0,
+ qRound(d->paper_size.width() * d->resolution / 72.0),
+ qRound(d->paper_size.height() * d->resolution / 72.0));
+ if (d->pageMarginsSet) {
+ rect = rect.adjusted(qRound(mmToInches(d->previousDialogMargins.left()/100.0) * d->resolution),
+ qRound(mmToInches(d->previousDialogMargins.top()/100.0) * d->resolution),
+ -qRound(mmToInches(d->previousDialogMargins.width()/100.0) * d->resolution),
+ -qRound(mmToInches(d->previousDialogMargins.height()/100.0) * d->resolution));
+ }
+ value = rect;
+ } else {
+ value = QTransform(1/d->stretch_x, 0, 0, 1/d->stretch_y, 0, 0)
+ .mapRect(d->fullPage ? d->devPhysicalPageRect : d->devPageRect);
+ }
+ break;
+
+ case PPK_PaperSize:
+ if (d->has_custom_paper_size) {
+ value = QPrinter::Custom;
+ } else {
+ if (!d->devMode) {
+ value = QPrinter::A4;
+ } else {
+ value = mapDevmodePaperSize(d->devMode->dmPaperSize);
+ }
+ }
+ break;
+
+ case PPK_PaperRect:
+ if (d->has_custom_paper_size) {
+ value = QRect(0, 0,
+ qRound(d->paper_size.width() * d->resolution / 72.0),
+ qRound(d->paper_size.height() * d->resolution / 72.0));
+ } else {
+ value = QTransform(1/d->stretch_x, 0, 0, 1/d->stretch_y, 0, 0).mapRect(d->devPaperRect);
+ }
+ break;
+
+ case PPK_PaperSource:
+ if (!d->devMode) {
+ value = QPrinter::Auto;
+ } else {
+ value = mapDevmodePaperSource(d->devMode->dmDefaultSource);
+ }
+ break;
+
+ case PPK_PrinterName:
+ value = d->name;
+ break;
+
+ case PPK_Resolution:
+ if (d->resolution || !d->name.isEmpty())
+ value = d->resolution;
+ break;
+
+ case PPK_SupportedResolutions:
+ value = d->queryResolutions();
+ break;
+
+ case PPK_WindowsPageSize:
+ if (!d->devMode) {
+ value = -1;
+ } else {
+ value = d->devMode->dmPaperSize;
+ }
+ break;
+
+ case PPK_PaperSources:
+ {
+ int available = DeviceCapabilities((const wchar_t *)d->name.utf16(),
+ (const wchar_t *)d->port.utf16(), DC_BINS, 0, d->devMode);
+
+ if (available <= 0)
+ break;
+
+ wchar_t *data = new wchar_t[available];
+ int count = DeviceCapabilities((const wchar_t *)d->name.utf16(),
+ (const wchar_t *)d->port.utf16(), DC_BINS, data, d->devMode);
+
+ QList<QVariant> out;
+ for (int i=0; i<count; ++i) {
+ QPrinter::PaperSource src = mapDevmodePaperSource(data[i]);
+ if (src != -1)
+ out << (int) src;
+ }
+ value = out;
+
+ delete [] data;
+ }
+ break;
+
+ case PPK_CustomPaperSize:
+ value = d->paper_size;
+ break;
+
+ case PPK_PageMargins:
+ {
+ QList<QVariant> margins;
+ QRect pageMargins(d->getPageMargins());
+
+ // specified in 1/100 mm
+ margins << (mmToInches(pageMargins.left()/100.0) * 72)
+ << (mmToInches(pageMargins.top()/100.0) * 72)
+ << (mmToInches(pageMargins.width()/100.0) * 72)
+ << (mmToInches(pageMargins.height()/100.0) * 72);
+ value = margins;
+ break;
+ }
+ default:
+ // Do nothing
+ break;
+ }
+ return value;
+}
+
+QPrinter::PrinterState QWin32PrintEngine::printerState() const
+{
+ return d_func()->state;
+}
+
+HDC QWin32PrintEngine::getDC() const
+{
+ return d_func()->hdc;
+}
+
+void QWin32PrintEngine::releaseDC(HDC) const
+{
+
+}
+
+HGLOBAL *QWin32PrintEnginePrivate::createDevNames()
+{
+ int size = sizeof(DEVNAMES)
+ + program.length() * 2 + 2
+ + name.length() * 2 + 2
+ + port.length() * 2 + 2;
+ HGLOBAL *hGlobal = (HGLOBAL *) GlobalAlloc(GMEM_MOVEABLE, size);
+ DEVNAMES *dn = (DEVNAMES*) GlobalLock(hGlobal);
+
+ dn->wDriverOffset = sizeof(DEVNAMES) / sizeof(wchar_t);
+ dn->wDeviceOffset = dn->wDriverOffset + program.length() + 1;
+ dn->wOutputOffset = dn->wDeviceOffset + name.length() + 1;
+
+ memcpy((ushort*)dn + dn->wDriverOffset, program.utf16(), program.length() * 2 + 2);
+ memcpy((ushort*)dn + dn->wDeviceOffset, name.utf16(), name.length() * 2 + 2);
+ memcpy((ushort*)dn + dn->wOutputOffset, port.utf16(), port.length() * 2 + 2);
+ dn->wDefault = 0;
+
+ GlobalUnlock(hGlobal);
+
+// printf("QPrintDialogWinPrivate::createDevNames()\n"
+// " -> wDriverOffset: %d\n"
+// " -> wDeviceOffset: %d\n"
+// " -> wOutputOffset: %d\n",
+// dn->wDriverOffset,
+// dn->wDeviceOffset,
+// dn->wOutputOffset);
+
+// printf("QPrintDialogWinPrivate::createDevNames(): %s, %s, %s\n",
+// QString::fromWCharArray((wchar_t*)(dn) + dn->wDriverOffset).latin1(),
+// QString::fromWCharArray((wchar_t*)(dn) + dn->wDeviceOffset).latin1(),
+// QString::fromWCharArray((wchar_t*)(dn) + dn->wOutputOffset).latin1());
+
+ return hGlobal;
+}
+
+void QWin32PrintEnginePrivate::readDevnames(HGLOBAL globalDevnames)
+{
+ if (globalDevnames) {
+ DEVNAMES *dn = (DEVNAMES*) GlobalLock(globalDevnames);
+ name = QString::fromWCharArray((wchar_t*)(dn) + dn->wDeviceOffset);
+ port = QString::fromWCharArray((wchar_t*)(dn) + dn->wOutputOffset);
+ program = QString::fromWCharArray((wchar_t*)(dn) + dn->wDriverOffset);
+ GlobalUnlock(globalDevnames);
+ }
+}
+
+void QWin32PrintEnginePrivate::readDevmode(HGLOBAL globalDevmode)
+{
+ if (globalDevmode) {
+ DEVMODE *dm = (DEVMODE*) GlobalLock(globalDevmode);
+ release();
+ globalDevMode = globalDevmode;
+ devMode = dm;
+ hdc = CreateDC(reinterpret_cast<const wchar_t *>(program.utf16()),
+ reinterpret_cast<const wchar_t *>(name.utf16()), 0, dm);
+
+ num_copies = devMode->dmCopies;
+ if (!OpenPrinter((wchar_t*)name.utf16(), &hPrinter, 0))
+ qWarning("QPrinter: OpenPrinter() failed after reading DEVMODE.");
+ }
+
+ if (hdc)
+ initHDC();
+}
+
+static void draw_text_item_win(const QPointF &pos, const QTextItemInt &ti, HDC hdc,
+ bool convertToText, const QTransform &xform, const QPointF &topLeft)
+{
+ QFontEngine *fe = ti.fontEngine;
+ QPointF baseline_pos = xform.inverted().map(xform.map(pos) - topLeft);
+
+ SetTextAlign(hdc, TA_BASELINE);
+ SetBkMode(hdc, TRANSPARENT);
+
+ bool has_kerning = ti.f && ti.f->kerning();
+ QFontEngineWin *winfe = (fe->type() == QFontEngine::Win) ? static_cast<QFontEngineWin *>(fe) : 0;
+
+ HFONT hfont;
+ bool ttf = false;
+
+ if (winfe) {
+ hfont = winfe->hfont;
+ ttf = winfe->ttf;
+ } else {
+ hfont = (HFONT)GetStockObject(ANSI_VAR_FONT);
+ }
+
+ HGDIOBJ old_font = SelectObject(hdc, hfont);
+ unsigned int options = (ttf && !convertToText) ? ETO_GLYPH_INDEX : 0;
+ wchar_t *convertedGlyphs = (wchar_t *)ti.chars;
+ QGlyphLayout glyphs = ti.glyphs;
+
+ bool fast = !has_kerning && !(ti.flags & QTextItem::RightToLeft);
+ for (int i = 0; fast && i < glyphs.numGlyphs; i++) {
+ if (glyphs.offsets[i].x != 0 || glyphs.offsets[i].y != 0 || glyphs.justifications[i].space_18d6 != 0
+ || glyphs.attributes[i].dontPrint) {
+ fast = false;
+ break;
+ }
+ }
+
+#if !defined(Q_OS_WINCE)
+ // Scale, rotate and translate here.
+ XFORM win_xform;
+ win_xform.eM11 = xform.m11();
+ win_xform.eM12 = xform.m12();
+ win_xform.eM21 = xform.m21();
+ win_xform.eM22 = xform.m22();
+ win_xform.eDx = xform.dx();
+ win_xform.eDy = xform.dy();
+
+ SetGraphicsMode(hdc, GM_ADVANCED);
+ SetWorldTransform(hdc, &win_xform);
+#endif
+
+ if (fast) {
+ // fast path
+ QVarLengthArray<wchar_t> g(glyphs.numGlyphs);
+ for (int i = 0; i < glyphs.numGlyphs; ++i)
+ g[i] = glyphs.glyphs[i];
+ ExtTextOut(hdc,
+ qRound(baseline_pos.x() + glyphs.offsets[0].x.toReal()),
+ qRound(baseline_pos.y() + glyphs.offsets[0].y.toReal()),
+ options, 0, convertToText ? convertedGlyphs : g.data(), glyphs.numGlyphs, 0);
+ } else {
+ QVarLengthArray<QFixedPoint> positions;
+ QVarLengthArray<glyph_t> _glyphs;
+
+ QTransform matrix = QTransform::fromTranslate(baseline_pos.x(), baseline_pos.y());
+ ti.fontEngine->getGlyphPositions(ti.glyphs, matrix, ti.flags,
+ _glyphs, positions);
+ if (_glyphs.size() == 0) {
+ SelectObject(hdc, old_font);
+ return;
+ }
+
+ convertToText = convertToText && glyphs.numGlyphs == _glyphs.size();
+ bool outputEntireItem = _glyphs.size() > 0;
+
+ if (outputEntireItem) {
+ options |= ETO_PDY;
+ QVarLengthArray<INT> glyphDistances(_glyphs.size() * 2);
+ QVarLengthArray<wchar_t> g(_glyphs.size());
+ for (int i=0; i<_glyphs.size() - 1; ++i) {
+ glyphDistances[i * 2] = qRound(positions[i + 1].x) - qRound(positions[i].x);
+ glyphDistances[i * 2 + 1] = qRound(positions[i + 1].y) - qRound(positions[i].y);
+ g[i] = _glyphs[i];
+ }
+ glyphDistances[(_glyphs.size() - 1) * 2] = 0;
+ glyphDistances[(_glyphs.size() - 1) * 2 + 1] = 0;
+ g[_glyphs.size() - 1] = _glyphs[_glyphs.size() - 1];
+ ExtTextOut(hdc, qRound(positions[0].x), qRound(positions[0].y), options, 0,
+ convertToText ? convertedGlyphs : g.data(), _glyphs.size(),
+ glyphDistances.data());
+ } else {
+ int i = 0;
+ while(i < _glyphs.size()) {
+ wchar_t g = _glyphs[i];
+
+ ExtTextOut(hdc, qRound(positions[i].x),
+ qRound(positions[i].y), options, 0,
+ convertToText ? convertedGlyphs + i : &g, 1, 0);
+ ++i;
+ }
+ }
+ }
+
+#if !defined(Q_OS_WINCE)
+ win_xform.eM11 = win_xform.eM22 = 1.0;
+ win_xform.eM12 = win_xform.eM21 = win_xform.eDx = win_xform.eDy = 0.0;
+ SetWorldTransform(hdc, &win_xform);
+#endif
+
+ SelectObject(hdc, old_font);
+}
+
+
+void QWin32PrintEnginePrivate::updateCustomPaperSize()
+{
+ uint paperSize = devMode->dmPaperSize;
+ if (paperSize > 0 && mapDevmodePaperSize(paperSize) == QPrinter::Custom) {
+ has_custom_paper_size = true;
+ DWORD needed = 0;
+ DWORD returned = 0;
+ if (!EnumForms(hPrinter, 1, 0, 0, &needed, &returned)) {
+ BYTE *forms = (BYTE *) malloc(needed);
+ if (EnumForms(hPrinter, 1, forms, needed, &needed, &returned)) {
+ if (paperSize <= returned) {
+ FORM_INFO_1 *formArray = (FORM_INFO_1 *) forms;
+ int width = formArray[paperSize - 1].Size.cx; // 1/1000 of a mm
+ int height = formArray[paperSize - 1].Size.cy; // 1/1000 of a mm
+ paper_size = QSizeF((width * 72 /25.4) / 1000.0, (height * 72 / 25.4) / 1000.0);
+ } else {
+ has_custom_paper_size = false;
+ }
+ }
+ free(forms);
+ }
+ } else {
+ has_custom_paper_size = false;
+ }
+}
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_PRINTER
diff --git a/src/gui/platforms/win/qprintengine_win_p.h b/src/gui/platforms/win/qprintengine_win_p.h
new file mode 100644
index 0000000000..b4d0670e7b
--- /dev/null
+++ b/src/gui/platforms/win/qprintengine_win_p.h
@@ -0,0 +1,261 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QPRINTENGINE_WIN_P_H
+#define QPRINTENGINE_WIN_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of other Qt classes. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#ifndef QT_NO_PRINTER
+
+#include "QtGui/qprinter.h"
+#include "QtGui/qprintengine.h"
+#include "QtGui/qpaintengine.h"
+#include "QtCore/qt_windows.h"
+#include "private/qpaintengine_alpha_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class QWin32PrintEnginePrivate;
+class QPrinterPrivate;
+class QPainterState;
+
+class QWin32PrintEngine : public QAlphaPaintEngine, public QPrintEngine
+{
+ Q_DECLARE_PRIVATE(QWin32PrintEngine)
+public:
+ QWin32PrintEngine(QPrinter::PrinterMode mode);
+
+ // override QWin32PaintEngine
+ bool begin(QPaintDevice *dev);
+ bool end();
+
+ void updateState(const QPaintEngineState &state);
+
+ void updateMatrix(const QTransform &matrix);
+ void updateClipPath(const QPainterPath &clip, Qt::ClipOperation op);
+
+ void drawPath(const QPainterPath &path);
+ void drawPolygon(const QPointF *points, int pointCount, PolygonDrawMode mode);
+ void drawTextItem(const QPointF &p, const QTextItem &textItem);
+
+ void drawPixmap(const QRectF &r, const QPixmap &pm, const QRectF &sr);
+ void drawTiledPixmap(const QRectF &r, const QPixmap &pm, const QPointF &p);
+ void setProperty(PrintEnginePropertyKey key, const QVariant &value);
+ QVariant property(PrintEnginePropertyKey key) const;
+
+ bool newPage();
+ bool abort();
+ int metric(QPaintDevice::PaintDeviceMetric) const;
+
+ QPrinter::PrinterState printerState() const;
+
+ QPaintEngine::Type type() const { return Windows; }
+
+ HDC getDC() const;
+ void releaseDC(HDC) const;
+
+ HDC getPrinterDC() const { return getDC(); }
+ void releasePrinterDC(HDC dc) const { releaseDC(dc); }
+
+private:
+ friend class QPrintDialog;
+ friend class QPageSetupDialog;
+};
+
+class QWin32PrintEnginePrivate : public QAlphaPaintEnginePrivate
+{
+ Q_DECLARE_PUBLIC(QWin32PrintEngine)
+public:
+ QWin32PrintEnginePrivate() :
+ hPrinter(0),
+ globalDevMode(0),
+ devMode(0),
+ pInfo(0),
+ hdc(0),
+ mode(QPrinter::ScreenResolution),
+ state(QPrinter::Idle),
+ resolution(0),
+ pageMarginsSet(false),
+ num_copies(1),
+ printToFile(false),
+ fullPage(false),
+ reinit(false),
+ has_custom_paper_size(false)
+ {
+ }
+
+ ~QWin32PrintEnginePrivate();
+
+
+ /* Reads the default printer name and its driver (printerProgram) into
+ the engines private data. */
+ void queryDefault();
+
+ /* Initializes the printer data based on the current printer name. This
+ function creates a DEVMODE struct, HDC and a printer handle. If these
+ structures are already in use, they are freed using release
+ */
+ void initialize();
+
+ /* Initializes data in the print engine whenever the HDC has been renewed
+ */
+ void initHDC();
+
+ /* Releases all the handles the printer currently holds, HDC, DEVMODE,
+ etc and resets the corresponding members to 0. */
+ void release();
+
+ /* Queries the resolutions for the current printer, and returns them
+ in a list. */
+ QList<QVariant> queryResolutions() const;
+
+ /* Resets the DC with changes in devmode. If the printer is active
+ this function only sets the reinit variable to true so it
+ is handled in the next begin or newpage. */
+ void doReinit();
+
+ /* Used by print/page setup dialogs */
+ HGLOBAL *createDevNames();
+
+ void readDevmode(HGLOBAL globalDevmode);
+ void readDevnames(HGLOBAL globalDevnames);
+
+ inline bool resetDC() {
+ hdc = ResetDC(hdc, devMode);
+ return hdc != 0;
+ }
+
+ void strokePath(const QPainterPath &path, const QColor &color);
+ void fillPath(const QPainterPath &path, const QColor &color);
+
+ void composeGdiPath(const QPainterPath &path);
+ void fillPath_dev(const QPainterPath &path, const QColor &color);
+ void strokePath_dev(const QPainterPath &path, const QColor &color, qreal width);
+
+ void updateOrigin();
+
+ void initDevRects();
+ void setPageMargins(int margin_left, int margin_top, int margin_right, int margin_bottom);
+ QRect getPageMargins() const;
+ void updateCustomPaperSize();
+
+ // Windows GDI printer references.
+ HANDLE hPrinter;
+
+ HGLOBAL globalDevMode;
+ DEVMODE *devMode;
+ PRINTER_INFO_2 *pInfo;
+ HGLOBAL hMem;
+
+ HDC hdc;
+
+ QPrinter::PrinterMode mode;
+
+ // Printer info
+ QString name;
+ QString program;
+ QString port;
+
+ // Document info
+ QString docName;
+ QString fileName;
+
+ QPrinter::PrinterState state;
+ int resolution;
+
+ // This QRect is used to store the exact values
+ // entered into the PageSetup Dialog because those are
+ // entered in mm but are since converted to device coordinates.
+ // If they were to be converted back when displaying the dialog
+ // again, there would be inaccuracies so when the user entered 10
+ // it may show up as 9.99 the next time the dialog is opened.
+ // We don't want that confusion.
+ QRect previousDialogMargins;
+
+ bool pageMarginsSet;
+ QRect devPageRect;
+ QRect devPhysicalPageRect;
+ QRect devPaperRect;
+ qreal stretch_x;
+ qreal stretch_y;
+ int origin_x;
+ int origin_y;
+
+ int dpi_x;
+ int dpi_y;
+ int dpi_display;
+ int num_copies;
+
+ uint printToFile : 1;
+ uint fullPage : 1;
+ uint reinit : 1;
+
+ uint complex_xform : 1;
+ uint has_pen : 1;
+ uint has_brush : 1;
+ uint has_custom_paper_size : 1;
+
+ uint txop;
+
+ QColor brush_color;
+ QPen pen;
+ QColor pen_color;
+ QSizeF paper_size;
+
+ QTransform painterMatrix;
+ QTransform matrix;
+};
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_PRINTER
+
+#endif // QPRINTENGINE_WIN_P_H
diff --git a/src/gui/platforms/win/qprinterinfo_win.cpp b/src/gui/platforms/win/qprinterinfo_win.cpp
new file mode 100644
index 0000000000..2c4014d8dc
--- /dev/null
+++ b/src/gui/platforms/win/qprinterinfo_win.cpp
@@ -0,0 +1,122 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qprinterinfo.h"
+#include "qprinterinfo_p.h"
+
+#include <qstringlist.h>
+
+#include <qt_windows.h>
+
+QT_BEGIN_NAMESPACE
+
+#ifndef QT_NO_PRINTER
+
+extern QPrinter::PaperSize mapDevmodePaperSize(int s);
+
+QList<QPrinterInfo> QPrinterInfo::availablePrinters()
+{
+ QList<QPrinterInfo> printers;
+
+ DWORD needed = 0;
+ DWORD returned = 0;
+ if (!EnumPrinters(PRINTER_ENUM_LOCAL | PRINTER_ENUM_CONNECTIONS, NULL, 4, 0, 0, &needed, &returned)) {
+ LPBYTE buffer = new BYTE[needed];
+ if (EnumPrinters(PRINTER_ENUM_LOCAL | PRINTER_ENUM_CONNECTIONS, NULL, 4, buffer, needed, &needed, &returned)) {
+ PPRINTER_INFO_4 infoList = reinterpret_cast<PPRINTER_INFO_4>(buffer);
+ QPrinterInfo defPrn = defaultPrinter();
+ for (uint i = 0; i < returned; ++i) {
+ QString printerName(QString::fromWCharArray(infoList[i].pPrinterName));
+
+ QPrinterInfo printerInfo(printerName);
+ if (printerInfo.printerName() == defPrn.printerName())
+ printerInfo.d_ptr->isDefault = true;
+ printers.append(printerInfo);
+ }
+ }
+ delete [] buffer;
+ }
+
+ return printers;
+}
+
+QPrinterInfo QPrinterInfo::defaultPrinter()
+{
+ QString noPrinters(QLatin1String("qt_no_printers"));
+ wchar_t buffer[256];
+ GetProfileString(L"windows", L"device", (wchar_t*)noPrinters.utf16(), buffer, 256);
+ QString output = QString::fromWCharArray(buffer);
+ if (output != noPrinters) {
+ // Filter out the name of the printer, which should be everything before a comma.
+ QString printerName = output.split(QLatin1Char(',')).value(0);
+ QPrinterInfo printerInfo(printerName);
+ printerInfo.d_ptr->isDefault = true;
+ return printerInfo;
+ }
+
+ return QPrinterInfo();
+}
+
+QList<QPrinter::PaperSize> QPrinterInfo::supportedPaperSizes() const
+{
+ const Q_D(QPrinterInfo);
+
+ QList<QPrinter::PaperSize> paperSizes;
+ if (isNull())
+ return paperSizes;
+
+ DWORD size = DeviceCapabilities(reinterpret_cast<const wchar_t*>(d->name.utf16()),
+ NULL, DC_PAPERS, NULL, NULL);
+ if ((int)size != -1) {
+ wchar_t *papers = new wchar_t[size];
+ size = DeviceCapabilities(reinterpret_cast<const wchar_t*>(d->name.utf16()),
+ NULL, DC_PAPERS, papers, NULL);
+ for (int c = 0; c < (int)size; ++c)
+ paperSizes.append(mapDevmodePaperSize(papers[c]));
+ delete [] papers;
+ }
+
+ return paperSizes;
+}
+
+#endif // QT_NO_PRINTER
+
+QT_END_NAMESPACE
diff --git a/src/gui/platforms/win/qrawfont_win.cpp b/src/gui/platforms/win/qrawfont_win.cpp
new file mode 100644
index 0000000000..d8acf57431
--- /dev/null
+++ b/src/gui/platforms/win/qrawfont_win.cpp
@@ -0,0 +1,707 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qrawfont_p.h"
+#include <private/qsystemlibrary_p.h>
+
+#if !defined(QT_NO_DIRECTWRITE)
+# include "qfontenginedirectwrite_p.h"
+# include <dwrite.h>
+#endif
+
+#if !defined(QT_NO_RAWFONT)
+
+QT_BEGIN_NAMESPACE
+
+namespace {
+
+ template<typename T>
+ struct BigEndian
+ {
+ quint8 data[sizeof(T)];
+
+ operator T() const
+ {
+ T littleEndian = 0;
+ for (int i=0; i<sizeof(T); ++i) {
+ littleEndian |= data[i] << ((sizeof(T) - i - 1) * 8);
+ }
+
+ return littleEndian;
+ }
+
+ BigEndian<T> &operator=(const T &t)
+ {
+ for (int i=0; i<sizeof(T); ++i) {
+ data[i] = ((t >> (sizeof(T) - i - 1) * 8) & 0xff);
+ }
+
+ return *this;
+ }
+ };
+
+# pragma pack(1)
+
+ // Common structure for all formats of the "name" table
+ struct NameTable
+ {
+ BigEndian<quint16> format;
+ BigEndian<quint16> count;
+ BigEndian<quint16> stringOffset;
+ };
+
+ struct NameRecord
+ {
+ BigEndian<quint16> platformID;
+ BigEndian<quint16> encodingID;
+ BigEndian<quint16> languageID;
+ BigEndian<quint16> nameID;
+ BigEndian<quint16> length;
+ BigEndian<quint16> offset;
+ };
+
+ struct OffsetSubTable
+ {
+ BigEndian<quint32> scalerType;
+ BigEndian<quint16> numTables;
+ BigEndian<quint16> searchRange;
+ BigEndian<quint16> entrySelector;
+ BigEndian<quint16> rangeShift;
+ };
+
+ struct TableDirectory
+ {
+ BigEndian<quint32> identifier;
+ BigEndian<quint32> checkSum;
+ BigEndian<quint32> offset;
+ BigEndian<quint32> length;
+ };
+
+ struct OS2Table
+ {
+ BigEndian<quint16> version;
+ BigEndian<qint16> avgCharWidth;
+ BigEndian<quint16> weightClass;
+ BigEndian<quint16> widthClass;
+ BigEndian<quint16> type;
+ BigEndian<qint16> subscriptXSize;
+ BigEndian<qint16> subscriptYSize;
+ BigEndian<qint16> subscriptXOffset;
+ BigEndian<qint16> subscriptYOffset;
+ BigEndian<qint16> superscriptXSize;
+ BigEndian<qint16> superscriptYSize;
+ BigEndian<qint16> superscriptXOffset;
+ BigEndian<qint16> superscriptYOffset;
+ BigEndian<qint16> strikeOutSize;
+ BigEndian<qint16> strikeOutPosition;
+ BigEndian<qint16> familyClass;
+ quint8 panose[10];
+ BigEndian<quint32> unicodeRanges[4];
+ quint8 vendorID[4];
+ BigEndian<quint16> selection;
+ BigEndian<quint16> firstCharIndex;
+ BigEndian<quint16> lastCharIndex;
+ BigEndian<qint16> typoAscender;
+ BigEndian<qint16> typoDescender;
+ BigEndian<qint16> typoLineGap;
+ BigEndian<quint16> winAscent;
+ BigEndian<quint16> winDescent;
+ BigEndian<quint32> codepageRanges[2];
+ BigEndian<qint16> height;
+ BigEndian<qint16> capHeight;
+ BigEndian<quint16> defaultChar;
+ BigEndian<quint16> breakChar;
+ BigEndian<quint16> maxContext;
+ };
+
+# pragma pack()
+
+ class EmbeddedFont
+ {
+ public:
+ EmbeddedFont(const QByteArray &fontData);
+
+ QString changeFamilyName(const QString &newFamilyName);
+ QByteArray data() const { return m_fontData; }
+ TableDirectory *tableDirectoryEntry(const QByteArray &tagName);
+ QString familyName(TableDirectory *nameTableDirectory = 0);
+
+ private:
+ QByteArray m_fontData;
+ };
+
+ EmbeddedFont::EmbeddedFont(const QByteArray &fontData) : m_fontData(fontData)
+ {
+ }
+
+ TableDirectory *EmbeddedFont::tableDirectoryEntry(const QByteArray &tagName)
+ {
+ Q_ASSERT(tagName.size() == 4);
+
+ const BigEndian<quint32> *tagIdPtr =
+ reinterpret_cast<const BigEndian<quint32> *>(tagName.constData());
+ quint32 tagId = *tagIdPtr;
+
+ OffsetSubTable *offsetSubTable = reinterpret_cast<OffsetSubTable *>(m_fontData.data());
+ TableDirectory *tableDirectory = reinterpret_cast<TableDirectory *>(offsetSubTable + 1);
+
+ TableDirectory *nameTableDirectoryEntry = 0;
+ for (int i=0; i<offsetSubTable->numTables; ++i, ++tableDirectory) {
+ if (tableDirectory->identifier == tagId) {
+ nameTableDirectoryEntry = tableDirectory;
+ break;
+ }
+ }
+
+ return nameTableDirectoryEntry;
+ }
+
+ QString EmbeddedFont::familyName(TableDirectory *nameTableDirectoryEntry)
+ {
+ QString name;
+
+ if (nameTableDirectoryEntry == 0)
+ nameTableDirectoryEntry = tableDirectoryEntry("name");
+
+ if (nameTableDirectoryEntry != 0) {
+ NameTable *nameTable = reinterpret_cast<NameTable *>(m_fontData.data()
+ + nameTableDirectoryEntry->offset);
+ NameRecord *nameRecord = reinterpret_cast<NameRecord *>(nameTable + 1);
+ for (int i=0; i<nameTable->count; ++i, ++nameRecord) {
+ if (nameRecord->nameID == 1
+ && nameRecord->platformID == 3 // Windows
+ && nameRecord->languageID == 0x0409) { // US English
+ const void *ptr = reinterpret_cast<const quint8 *>(nameTable)
+ + nameTable->stringOffset
+ + nameRecord->offset;
+
+ const BigEndian<quint16> *s = reinterpret_cast<const BigEndian<quint16> *>(ptr);
+ for (int j=0; j<nameRecord->length / sizeof(quint16); ++j)
+ name += QChar(s[j]);
+
+ break;
+ }
+ }
+ }
+
+ return name;
+ }
+
+ QString EmbeddedFont::changeFamilyName(const QString &newFamilyName)
+ {
+ TableDirectory *nameTableDirectoryEntry = tableDirectoryEntry("name");
+ if (nameTableDirectoryEntry == 0)
+ return QString();
+
+ QString oldFamilyName = familyName(nameTableDirectoryEntry);
+
+ // Reserve size for name table header, five required name records and string
+ const int requiredRecordCount = 5;
+ quint16 nameIds[requiredRecordCount] = { 1, 2, 3, 4, 6 };
+
+ int sizeOfHeader = sizeof(NameTable) + sizeof(NameRecord) * requiredRecordCount;
+ int newFamilyNameSize = newFamilyName.size() * sizeof(quint16);
+
+ const QString regularString = QString::fromLatin1("Regular");
+ int regularStringSize = regularString.size() * sizeof(quint16);
+
+ // Align table size of table to 32 bits (pad with 0)
+ int fullSize = ((sizeOfHeader + newFamilyNameSize + regularStringSize) & ~3) + 4;
+
+ QByteArray newNameTable(fullSize, char(0));
+
+ {
+ NameTable *nameTable = reinterpret_cast<NameTable *>(newNameTable.data());
+ nameTable->count = requiredRecordCount;
+ nameTable->stringOffset = sizeOfHeader;
+
+ NameRecord *nameRecord = reinterpret_cast<NameRecord *>(nameTable + 1);
+ for (int i=0; i<requiredRecordCount; ++i, nameRecord++) {
+ nameRecord->nameID = nameIds[i];
+ nameRecord->encodingID = 1;
+ nameRecord->languageID = 0x0409;
+ nameRecord->platformID = 3;
+ nameRecord->length = newFamilyNameSize;
+
+ // Special case for sub-family
+ if (nameIds[i] == 4) {
+ nameRecord->offset = newFamilyNameSize;
+ nameRecord->length = regularStringSize;
+ }
+ }
+
+ // nameRecord now points to string data
+ BigEndian<quint16> *stringStorage = reinterpret_cast<BigEndian<quint16> *>(nameRecord);
+ const quint16 *sourceString = newFamilyName.utf16();
+ for (int i=0; i<newFamilyName.size(); ++i)
+ stringStorage[i] = sourceString[i];
+ stringStorage += newFamilyName.size();
+
+ sourceString = regularString.utf16();
+ for (int i=0; i<regularString.size(); ++i)
+ stringStorage[i] = sourceString[i];
+ }
+
+ quint32 *p = reinterpret_cast<quint32 *>(newNameTable.data());
+ quint32 *tableEnd = reinterpret_cast<quint32 *>(newNameTable.data() + fullSize);
+
+ quint32 checkSum = 0;
+ while (p < tableEnd)
+ checkSum += *(p++);
+
+ nameTableDirectoryEntry->checkSum = checkSum;
+ nameTableDirectoryEntry->offset = m_fontData.size();
+ nameTableDirectoryEntry->length = fullSize;
+
+ m_fontData.append(newNameTable);
+
+ return oldFamilyName;
+ }
+
+#if !defined(QT_NO_DIRECTWRITE)
+
+ class DirectWriteFontFileStream: public IDWriteFontFileStream
+ {
+ public:
+ DirectWriteFontFileStream(const QByteArray &fontData)
+ : m_fontData(fontData)
+ , m_referenceCount(0)
+ {
+ }
+
+ ~DirectWriteFontFileStream()
+ {
+ }
+
+ HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void **object);
+ ULONG STDMETHODCALLTYPE AddRef();
+ ULONG STDMETHODCALLTYPE Release();
+
+ HRESULT STDMETHODCALLTYPE ReadFileFragment(const void **fragmentStart, UINT64 fileOffset,
+ UINT64 fragmentSize, OUT void **fragmentContext);
+ void STDMETHODCALLTYPE ReleaseFileFragment(void *fragmentContext);
+ HRESULT STDMETHODCALLTYPE GetFileSize(OUT UINT64 *fileSize);
+ HRESULT STDMETHODCALLTYPE GetLastWriteTime(OUT UINT64 *lastWriteTime);
+
+ private:
+ QByteArray m_fontData;
+ ULONG m_referenceCount;
+ };
+
+ HRESULT STDMETHODCALLTYPE DirectWriteFontFileStream::QueryInterface(REFIID iid, void **object)
+ {
+ if (iid == IID_IUnknown || iid == __uuidof(IDWriteFontFileStream)) {
+ *object = this;
+ AddRef();
+ return S_OK;
+ } else {
+ *object = NULL;
+ return E_NOINTERFACE;
+ }
+ }
+
+ ULONG STDMETHODCALLTYPE DirectWriteFontFileStream::AddRef()
+ {
+ return InterlockedIncrement(&m_referenceCount);
+ }
+
+ ULONG STDMETHODCALLTYPE DirectWriteFontFileStream::Release()
+ {
+ ULONG newCount = InterlockedDecrement(&m_referenceCount);
+ if (newCount == 0)
+ delete this;
+ return newCount;
+ }
+
+ HRESULT STDMETHODCALLTYPE DirectWriteFontFileStream::ReadFileFragment(
+ const void **fragmentStart,
+ UINT64 fileOffset,
+ UINT64 fragmentSize,
+ OUT void **fragmentContext)
+ {
+ *fragmentContext = NULL;
+ if (fragmentSize + fileOffset <= m_fontData.size()) {
+ *fragmentStart = m_fontData.data() + fileOffset;
+ return S_OK;
+ } else {
+ *fragmentStart = NULL;
+ return E_FAIL;
+ }
+ }
+
+ void STDMETHODCALLTYPE DirectWriteFontFileStream::ReleaseFileFragment(void *)
+ {
+ }
+
+ HRESULT STDMETHODCALLTYPE DirectWriteFontFileStream::GetFileSize(UINT64 *fileSize)
+ {
+ *fileSize = m_fontData.size();
+ return S_OK;
+ }
+
+ HRESULT STDMETHODCALLTYPE DirectWriteFontFileStream::GetLastWriteTime(UINT64 *lastWriteTime)
+ {
+ *lastWriteTime = 0;
+ return E_NOTIMPL;
+ }
+
+ class DirectWriteFontFileLoader: public IDWriteFontFileLoader
+ {
+ public:
+ DirectWriteFontFileLoader() : m_referenceCount(0) {}
+
+ ~DirectWriteFontFileLoader()
+ {
+ }
+
+ inline void addKey(const void *key, const QByteArray &fontData)
+ {
+ Q_ASSERT(!m_fontDatas.contains(key));
+ m_fontDatas.insert(key, fontData);
+ }
+
+ inline void removeKey(const void *key)
+ {
+ m_fontDatas.remove(key);
+ }
+
+ HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void **object);
+ ULONG STDMETHODCALLTYPE AddRef();
+ ULONG STDMETHODCALLTYPE Release();
+
+ HRESULT STDMETHODCALLTYPE CreateStreamFromKey(void const *fontFileReferenceKey,
+ UINT32 fontFileReferenceKeySize,
+ OUT IDWriteFontFileStream **fontFileStream);
+
+ private:
+ ULONG m_referenceCount;
+ QHash<const void *, QByteArray> m_fontDatas;
+ };
+
+ HRESULT STDMETHODCALLTYPE DirectWriteFontFileLoader::QueryInterface(const IID &iid,
+ void **object)
+ {
+ if (iid == IID_IUnknown || iid == __uuidof(IDWriteFontFileLoader)) {
+ *object = this;
+ AddRef();
+ return S_OK;
+ } else {
+ *object = NULL;
+ return E_NOINTERFACE;
+ }
+ }
+
+ ULONG STDMETHODCALLTYPE DirectWriteFontFileLoader::AddRef()
+ {
+ return InterlockedIncrement(&m_referenceCount);
+ }
+
+ ULONG STDMETHODCALLTYPE DirectWriteFontFileLoader::Release()
+ {
+ ULONG newCount = InterlockedDecrement(&m_referenceCount);
+ if (newCount == 0)
+ delete this;
+ return newCount;
+ }
+
+ HRESULT STDMETHODCALLTYPE DirectWriteFontFileLoader::CreateStreamFromKey(
+ void const *fontFileReferenceKey,
+ UINT32 fontFileReferenceKeySize,
+ IDWriteFontFileStream **fontFileStream)
+ {
+ Q_UNUSED(fontFileReferenceKeySize);
+
+ if (fontFileReferenceKeySize != sizeof(const void *)) {
+ qWarning("DirectWriteFontFileLoader::CreateStreamFromKey: Wrong key size");
+ return E_FAIL;
+ }
+
+ const void *key = *reinterpret_cast<void * const *>(fontFileReferenceKey);
+ *fontFileStream = NULL;
+ if (!m_fontDatas.contains(key))
+ return E_FAIL;
+
+ QByteArray fontData = m_fontDatas.value(key);
+ DirectWriteFontFileStream *stream = new DirectWriteFontFileStream(fontData);
+ stream->AddRef();
+ *fontFileStream = stream;
+
+ return S_OK;
+ }
+
+ class CustomFontFileLoader
+ {
+ public:
+ CustomFontFileLoader() : m_directWriteFactory(0), m_directWriteFontFileLoader(0)
+ {
+ HRESULT hres = DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED,
+ __uuidof(IDWriteFactory),
+ reinterpret_cast<IUnknown **>(&m_directWriteFactory));
+ if (FAILED(hres)) {
+ qErrnoWarning(hres, "CustomFontFileLoader::CustomFontFileLoader: "
+ "DWriteCreateFactory failed.");
+ } else {
+ m_directWriteFontFileLoader = new DirectWriteFontFileLoader();
+ m_directWriteFactory->RegisterFontFileLoader(m_directWriteFontFileLoader);
+ }
+ }
+
+ ~CustomFontFileLoader()
+ {
+ if (m_directWriteFactory != 0 && m_directWriteFontFileLoader != 0)
+ m_directWriteFactory->UnregisterFontFileLoader(m_directWriteFontFileLoader);
+
+ if (m_directWriteFactory != 0)
+ m_directWriteFactory->Release();
+ }
+
+ void addKey(const void *key, const QByteArray &fontData)
+ {
+ if (m_directWriteFontFileLoader != 0)
+ m_directWriteFontFileLoader->addKey(key, fontData);
+ }
+
+ void removeKey(const void *key)
+ {
+ if (m_directWriteFontFileLoader != 0)
+ m_directWriteFontFileLoader->removeKey(key);
+ }
+
+ IDWriteFontFileLoader *loader() const
+ {
+ return m_directWriteFontFileLoader;
+ }
+
+ private:
+ IDWriteFactory *m_directWriteFactory;
+ DirectWriteFontFileLoader *m_directWriteFontFileLoader;
+ };
+
+#endif
+
+} // Anonymous namespace
+
+
+// From qfontdatabase_win.cpp
+extern QFontEngine *qt_load_font_engine_win(const QFontDef &request);
+// From qfontdatabase.cpp
+extern QFont::Weight weightFromInteger(int weight);
+
+void QRawFontPrivate::platformCleanUp()
+{
+ if (fontHandle != NULL) {
+ if (ptrRemoveFontMemResourceEx == NULL) {
+ void *func = QSystemLibrary::resolve(QLatin1String("gdi32"), "RemoveFontMemResourceEx");
+ ptrRemoveFontMemResourceEx =
+ reinterpret_cast<QRawFontPrivate::PtrRemoveFontMemResourceEx>(func);
+ }
+
+ if (ptrRemoveFontMemResourceEx == NULL) {
+ qWarning("QRawFont::platformCleanUp: Can't find RemoveFontMemResourceEx in gdi32");
+ fontHandle = NULL;
+ } else {
+ ptrRemoveFontMemResourceEx(fontHandle);
+ fontHandle = NULL;
+ }
+ }
+}
+
+void QRawFontPrivate::platformLoadFromData(const QByteArray &_fontData,
+ int pixelSize,
+ QFont::HintingPreference hintingPreference)
+{
+ QByteArray fontData(_fontData);
+ EmbeddedFont font(fontData);
+
+#if !defined(QT_NO_DIRECTWRITE)
+ if (hintingPreference == QFont::PreferDefaultHinting
+ || hintingPreference == QFont::PreferFullHinting)
+#endif
+ {
+ GUID guid;
+ CoCreateGuid(&guid);
+
+ QString uniqueFamilyName = QString::fromLatin1("f")
+ + QString::number(guid.Data1, 36) + QLatin1Char('-')
+ + QString::number(guid.Data2, 36) + QLatin1Char('-')
+ + QString::number(guid.Data3, 36) + QLatin1Char('-')
+ + QString::number(*reinterpret_cast<quint64 *>(guid.Data4), 36);
+
+ QString actualFontName = font.changeFamilyName(uniqueFamilyName);
+ if (actualFontName.isEmpty()) {
+ qWarning("QRawFont::platformLoadFromData: Can't change family name of font");
+ return;
+ }
+
+ if (ptrAddFontMemResourceEx == NULL || ptrRemoveFontMemResourceEx == NULL) {
+ void *func = QSystemLibrary::resolve(QLatin1String("gdi32"), "RemoveFontMemResourceEx");
+ ptrRemoveFontMemResourceEx =
+ reinterpret_cast<QRawFontPrivate::PtrRemoveFontMemResourceEx>(func);
+
+ func = QSystemLibrary::resolve(QLatin1String("gdi32"), "AddFontMemResourceEx");
+ ptrAddFontMemResourceEx =
+ reinterpret_cast<QRawFontPrivate::PtrAddFontMemResourceEx>(func);
+ }
+
+ Q_ASSERT(fontHandle == NULL);
+ if (ptrAddFontMemResourceEx != NULL && ptrRemoveFontMemResourceEx != NULL) {
+ DWORD count = 0;
+ fontData = font.data();
+ fontHandle = ptrAddFontMemResourceEx(fontData.data(), fontData.size(), 0, &count);
+
+ if (count == 0 && fontHandle != NULL) {
+ ptrRemoveFontMemResourceEx(fontHandle);
+ fontHandle = NULL;
+ }
+ }
+
+ if (fontHandle == NULL) {
+ qWarning("QRawFont::platformLoadFromData: AddFontMemResourceEx failed");
+ } else {
+ QFontDef request;
+ request.family = uniqueFamilyName;
+ request.pixelSize = pixelSize;
+ request.styleStrategy = QFont::NoFontMerging | QFont::PreferMatch;
+ request.hintingPreference = hintingPreference;
+
+ fontEngine = qt_load_font_engine_win(request);
+ if (request.family != fontEngine->fontDef.family) {
+ qWarning("QRawFont::platformLoadFromData: Failed to load font. "
+ "Got fallback instead: %s", qPrintable(fontEngine->fontDef.family));
+ if (fontEngine->cache_count == 0 && fontEngine->ref == 0)
+ delete fontEngine;
+ fontEngine = 0;
+ } else {
+ Q_ASSERT(fontEngine->cache_count == 0 && fontEngine->ref == 0);
+
+ // Override the generated font name
+ static_cast<QFontEngineWin *>(fontEngine)->uniqueFamilyName = uniqueFamilyName;
+ fontEngine->fontDef.family = actualFontName;
+ fontEngine->ref.ref();
+ }
+ }
+ }
+#if !defined(QT_NO_DIRECTWRITE)
+ else {
+ CustomFontFileLoader fontFileLoader;
+ fontFileLoader.addKey(this, fontData);
+
+ IDWriteFactory *factory = NULL;
+ HRESULT hres = DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED,
+ __uuidof(IDWriteFactory),
+ reinterpret_cast<IUnknown **>(&factory));
+ if (FAILED(hres)) {
+ qErrnoWarning(hres, "QRawFont::platformLoadFromData: DWriteCreateFactory failed");
+ return;
+ }
+
+ IDWriteFontFile *fontFile = NULL;
+ void *key = this;
+
+ hres = factory->CreateCustomFontFileReference(&key, sizeof(void *),
+ fontFileLoader.loader(), &fontFile);
+ if (FAILED(hres)) {
+ qErrnoWarning(hres, "QRawFont::platformLoadFromData: "
+ "CreateCustomFontFileReference failed");
+ factory->Release();
+ return;
+ }
+
+ BOOL isSupportedFontType;
+ DWRITE_FONT_FILE_TYPE fontFileType;
+ DWRITE_FONT_FACE_TYPE fontFaceType;
+ UINT32 numberOfFaces;
+ fontFile->Analyze(&isSupportedFontType, &fontFileType, &fontFaceType, &numberOfFaces);
+ if (!isSupportedFontType) {
+ fontFile->Release();
+ factory->Release();
+ return;
+ }
+
+ IDWriteFontFace *directWriteFontFace = NULL;
+ hres = factory->CreateFontFace(fontFaceType, 1, &fontFile, 0, DWRITE_FONT_SIMULATIONS_NONE,
+ &directWriteFontFace);
+ if (FAILED(hres)) {
+ qErrnoWarning(hres, "QRawFont::platformLoadFromData: CreateFontFace failed");
+ fontFile->Release();
+ factory->Release();
+ return;
+ }
+
+ fontFile->Release();
+
+ fontEngine = new QFontEngineDirectWrite(factory, directWriteFontFace, pixelSize);
+
+ // Get font family from font data
+ fontEngine->fontDef.family = font.familyName();
+ fontEngine->ref.ref();
+
+ directWriteFontFace->Release();
+ factory->Release();
+ }
+#endif
+
+ // Get style and weight info
+ if (fontEngine != 0) {
+ TableDirectory *os2TableEntry = font.tableDirectoryEntry("OS/2");
+ if (os2TableEntry != 0) {
+ const OS2Table *os2Table =
+ reinterpret_cast<const OS2Table *>(fontData.constData()
+ + os2TableEntry->offset);
+
+ bool italic = os2Table->selection & 1;
+ bool oblique = os2Table->selection & 128;
+
+ if (italic)
+ fontEngine->fontDef.style = QFont::StyleItalic;
+ else if (oblique)
+ fontEngine->fontDef.style = QFont::StyleOblique;
+ else
+ fontEngine->fontDef.style = QFont::StyleNormal;
+
+ fontEngine->fontDef.weight = weightFromInteger(os2Table->weightClass);
+ }
+ }
+}
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_RAWFONT
diff --git a/src/gui/platforms/win/qregion_win.cpp b/src/gui/platforms/win/qregion_win.cpp
new file mode 100644
index 0000000000..3466b62cbd
--- /dev/null
+++ b/src/gui/platforms/win/qregion_win.cpp
@@ -0,0 +1,149 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qatomic.h"
+#include "qbitmap.h"
+#include "qbuffer.h"
+#include "qimage.h"
+#include "qpolygon.h"
+#include "qregion.h"
+#include "qt_windows.h"
+#include "qpainterpath.h"
+
+QT_BEGIN_NAMESPACE
+
+QRegion::QRegionData QRegion::shared_empty = { Q_BASIC_ATOMIC_INITIALIZER(1), 0, 0 };
+
+HRGN qt_tryCreateRegion(QRegion::RegionType type, int left, int top, int right, int bottom)
+{
+ const int tries = 10;
+ for (int i = 0; i < tries; ++i) {
+ HRGN region = 0;
+ switch (type) {
+ case QRegion::Rectangle:
+ region = CreateRectRgn(left, top, right, bottom);
+ break;
+ case QRegion::Ellipse:
+#ifndef Q_OS_WINCE
+ region = CreateEllipticRgn(left, top, right, bottom);
+#endif
+ break;
+ }
+ if (region) {
+ if (GetRegionData(region, 0, 0))
+ return region;
+ else
+ DeleteObject(region);
+ }
+ }
+ return 0;
+}
+
+QRegion qt_region_from_HRGN(HRGN rgn)
+{
+ int numBytes = GetRegionData(rgn, 0, 0);
+ if (numBytes == 0)
+ return QRegion();
+
+ char *buf = new char[numBytes];
+ if (buf == 0)
+ return QRegion();
+
+ RGNDATA *rd = reinterpret_cast<RGNDATA*>(buf);
+ if (GetRegionData(rgn, numBytes, rd) == 0) {
+ delete [] buf;
+ return QRegion();
+ }
+
+ QRegion region;
+ RECT *r = reinterpret_cast<RECT*>(rd->Buffer);
+ for (uint i = 0; i < rd->rdh.nCount; ++i) {
+ QRect rect;
+ rect.setCoords(r->left, r->top, r->right - 1, r->bottom - 1);
+ ++r;
+ region |= rect;
+ }
+
+ delete [] buf;
+
+ return region;
+}
+
+void qt_win_dispose_rgn(HRGN r)
+{
+ if (r)
+ DeleteObject(r);
+}
+
+static void qt_add_rect(HRGN &winRegion, QRect r)
+{
+ HRGN rgn = CreateRectRgn(r.left(), r.top(), r.x() + r.width(), r.y() + r.height());
+ if (rgn) {
+ HRGN dest = CreateRectRgn(0,0,0,0);
+ int result = CombineRgn(dest, winRegion, rgn, RGN_OR);
+ if (result) {
+ DeleteObject(winRegion);
+ winRegion = dest;
+ }
+ DeleteObject(rgn);
+ }
+}
+
+void QRegion::ensureHandle() const
+{
+ if (d->rgn)
+ DeleteObject(d->rgn);
+ d->rgn = CreateRectRgn(0,0,0,0);
+ if (d->qt_rgn) {
+ if (d->qt_rgn->numRects == 1) {
+ QRect r = d->qt_rgn->extents;
+ qt_add_rect(d->rgn, r);
+ return;
+ }
+ for (int i = 0;i < d->qt_rgn->numRects;i++) {
+ QRect r = d->qt_rgn->rects.at(i);
+ qt_add_rect(d->rgn, r);
+ }
+ }
+}
+
+
+QT_END_NAMESPACE
diff --git a/src/gui/platforms/win/qsound_win.cpp b/src/gui/platforms/win/qsound_win.cpp
new file mode 100644
index 0000000000..c11482d608
--- /dev/null
+++ b/src/gui/platforms/win/qsound_win.cpp
@@ -0,0 +1,205 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsound.h"
+
+#ifndef QT_NO_SOUND
+
+#include "qapplication.h"
+#include "qapplication_p.h"
+#include <qfile.h>
+#include "qpointer.h"
+#include "qsound_p.h"
+
+#include <qt_windows.h>
+
+QT_BEGIN_NAMESPACE
+
+class QAuServerWindows : public QAuServer {
+ Q_OBJECT
+
+public:
+ QAuServerWindows(QObject* parent);
+ ~QAuServerWindows();
+
+ void playHelper(const QString &filename, int loop, QSound *snd);
+ void play(const QString& filename, int loop);
+ void play(QSound*);
+
+ void stop(QSound*);
+ bool okay();
+
+ int decLoop(QSound *snd) { return QAuServer::decLoop(snd); }
+
+ HANDLE current;
+ HANDLE mutex;
+ HANDLE event;
+};
+
+QAuServerWindows::QAuServerWindows(QObject* parent) :
+ QAuServer(parent), current(0)
+{
+ mutex = CreateMutex(0, 0, 0);
+ event = CreateEvent(0, FALSE, FALSE, 0);
+}
+
+QAuServerWindows::~QAuServerWindows()
+{
+ HANDLE mtx = mutex;
+ WaitForSingleObject(mtx, INFINITE);
+ mutex = 0;
+
+ ReleaseMutex(mtx);
+ CloseHandle(mtx);
+ CloseHandle(event);
+}
+
+struct SoundInfo
+{
+ SoundInfo(const QString &fn, int lp, QSound *snd, QAuServerWindows *srv)
+ : sound(snd), server(srv), filename(fn), loops(lp)
+ {
+ }
+
+ QSound *sound;
+ QAuServerWindows *server;
+ QString filename;
+ int loops;
+};
+
+DWORD WINAPI SoundPlayProc(LPVOID param)
+{
+ SoundInfo *info = (SoundInfo*)param;
+
+ // copy data before waking up GUI thread
+ QAuServerWindows *server = info->server;
+ QSound *sound = info->sound;
+ int loops = info->loops;
+ QString filename = info->filename;
+ HANDLE mutex = server->mutex;
+ HANDLE event = server->event;
+ info = 0;
+
+ // server must not be destroyed until thread finishes
+ // and all other sounds have to wait
+ WaitForSingleObject(mutex, INFINITE);
+
+ if (loops <= 1) {
+ server->current = 0;
+ int flags = SND_FILENAME|SND_ASYNC;
+ if (loops == -1)
+ flags |= SND_LOOP;
+
+ PlaySound((wchar_t*)filename.utf16(), 0, flags);
+ if (sound && loops == 1)
+ server->decLoop(sound);
+
+ // GUI thread continues, but we are done as well.
+ SetEvent(event);
+ } else {
+ // signal GUI thread to continue - sound might be reset!
+ QPointer<QSound> guarded_sound = sound;
+ SetEvent(event);
+
+ for (int l = 0; l < loops && server->current; ++l) {
+ PlaySound((wchar_t*)filename.utf16(), 0, SND_FILENAME | SND_SYNC);
+
+ if (guarded_sound)
+ server->decLoop(guarded_sound);
+ }
+ server->current = 0;
+ }
+ ReleaseMutex(mutex);
+
+ return 0;
+}
+
+void QAuServerWindows::playHelper(const QString &filename, int loop, QSound *snd)
+{
+ if (loop == 0)
+ return;
+ // busy?
+ if (WaitForSingleObject(mutex, 0) == WAIT_TIMEOUT)
+ return;
+ ReleaseMutex(mutex);
+
+ DWORD threadid = 0;
+ SoundInfo info(filename, loop, snd, this);
+ current = CreateThread(0, 0, SoundPlayProc, &info, 0, &threadid);
+ CloseHandle(current);
+
+ WaitForSingleObject(event, INFINITE);
+}
+
+void QAuServerWindows::play(const QString& filename, int loop)
+{
+ playHelper(filename, loop, 0);
+}
+
+void QAuServerWindows::play(QSound* s)
+{
+ playHelper(s->fileName(), s->loops(), s);
+}
+
+void QAuServerWindows::stop(QSound*)
+{
+ // stop unlooped sound
+ if (!current)
+ PlaySound(0, 0, 0);
+ // stop after loop is done
+ current = 0;
+}
+
+bool QAuServerWindows::okay()
+{
+ return true;
+}
+
+QAuServer* qt_new_audio_server()
+{
+ return new QAuServerWindows(qApp);
+}
+
+QT_END_NAMESPACE
+
+#include "qsound_win.moc"
+
+#endif // QT_NO_SOUND
diff --git a/src/gui/platforms/win/qwidget_win.cpp b/src/gui/platforms/win/qwidget_win.cpp
new file mode 100644
index 0000000000..a02c5ba008
--- /dev/null
+++ b/src/gui/platforms/win/qwidget_win.cpp
@@ -0,0 +1,2139 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qapplication.h"
+#include "qapplication_p.h"
+#include "qbitmap.h"
+#include "qcursor.h"
+#include "qdesktopwidget.h"
+#include "qevent.h"
+#include "qimage.h"
+#include "qlayout.h"
+#include "qpainter.h"
+#include "qstack.h"
+#include "qt_windows.h"
+#include "qwidget.h"
+#include "qwidget_p.h"
+#include "private/qbackingstore_p.h"
+#include "private/qwindowsurface_raster_p.h"
+
+#include "qscrollbar.h"
+#include "qabstractscrollarea.h"
+#include <private/qabstractscrollarea_p.h>
+
+#include <qdebug.h>
+
+#include <private/qapplication_p.h>
+#include <private/qwininputcontext_p.h>
+#include <private/qpaintengine_raster_p.h>
+#include <private/qsystemlibrary_p.h>
+
+#if defined(Q_WS_WINCE)
+#include "qguifunctions_wince.h"
+QT_USE_NAMESPACE
+extern void qt_wince_maximize(QWidget *widget); //defined in qguifunctions_wince.cpp
+extern void qt_wince_unmaximize(QWidget *widget); //defined in qguifunctions_wince.cpp
+extern void qt_wince_minimize(HWND hwnd); //defined in qguifunctions_wince.cpp
+extern void qt_wince_full_screen(HWND hwnd, bool fullScreen, UINT swpf); //defined in qguifunctions_wince.cpp
+extern bool qt_wince_is_mobile(); //defined in qguifunctions_wince.cpp
+#endif
+
+typedef BOOL (WINAPI *PtrSetLayeredWindowAttributes)(HWND hwnd, COLORREF crKey, BYTE bAlpha, DWORD dwFlags);
+static PtrSetLayeredWindowAttributes ptrSetLayeredWindowAttributes = 0;
+
+#ifndef QT_NO_DIRECTDRAW
+#include <ddraw.h>
+#include <private/qimage_p.h>
+static IDirectDraw *qt_ddraw_object;
+static IDirectDrawSurface *qt_ddraw_primary;
+#endif
+
+
+
+#if defined(QT_NON_COMMERCIAL)
+#include "qnc_win.h"
+#endif
+
+#if !defined(WS_EX_TOOLWINDOW)
+#define WS_EX_TOOLWINDOW 0x00000080
+#endif
+
+#if !defined(GWLP_WNDPROC)
+#define GWLP_WNDPROC GWL_WNDPROC
+#endif
+
+//#define TABLET_DEBUG
+#define PACKETDATA (PK_X | PK_Y | PK_BUTTONS | PK_NORMAL_PRESSURE | PK_TANGENT_PRESSURE \
+ | PK_ORIENTATION | PK_CURSOR | PK_Z)
+#define PACKETMODE 0
+#include <wintab.h>
+#include <pktdef.h>
+
+QT_BEGIN_NAMESPACE
+
+typedef HCTX (API *PtrWTOpen)(HWND, LPLOGCONTEXT, BOOL);
+typedef BOOL (API *PtrWTClose)(HCTX);
+typedef UINT (API *PtrWTInfo)(UINT, UINT, LPVOID);
+typedef BOOL (API *PtrWTEnable)(HCTX, BOOL);
+typedef BOOL (API *PtrWTOverlap)(HCTX, BOOL);
+typedef int (API *PtrWTPacketsGet)(HCTX, int, LPVOID);
+typedef BOOL (API *PtrWTGet)(HCTX, LPLOGCONTEXT);
+typedef int (API *PtrWTQueueSizeGet)(HCTX);
+typedef BOOL (API *PtrWTQueueSizeSet)(HCTX, int);
+
+static PtrWTOpen ptrWTOpen = 0;
+static PtrWTClose ptrWTClose = 0;
+static PtrWTInfo ptrWTInfo = 0;
+static PtrWTQueueSizeGet ptrWTQueueSizeGet = 0;
+static PtrWTQueueSizeSet ptrWTQueueSizeSet = 0;
+#ifndef QT_NO_TABLETEVENT
+static void init_wintab_functions();
+static void qt_tablet_init();
+static void qt_tablet_cleanup();
+#endif // QT_NO_TABLETEVENT
+extern HCTX qt_tablet_context;
+extern bool qt_tablet_tilt_support;
+
+static QWidget *qt_tablet_widget = 0;
+QWidget* qt_get_tablet_widget()
+{
+ return qt_tablet_widget;
+}
+
+extern bool qt_is_gui_used;
+
+#ifndef QT_NO_TABLETEVENT
+static void init_wintab_functions()
+{
+#if defined(Q_OS_WINCE)
+ return;
+#else
+ if (!qt_is_gui_used)
+ return;
+ QSystemLibrary library(QLatin1String("wintab32"));
+ ptrWTOpen = (PtrWTOpen)library.resolve("WTOpenW");
+ ptrWTInfo = (PtrWTInfo)library.resolve("WTInfoW");
+ ptrWTClose = (PtrWTClose)library.resolve("WTClose");
+ ptrWTQueueSizeGet = (PtrWTQueueSizeGet)library.resolve("WTQueueSizeGet");
+ ptrWTQueueSizeSet = (PtrWTQueueSizeSet)library.resolve("WTQueueSizeSet");
+#endif // Q_OS_WINCE
+}
+
+static void qt_tablet_init()
+{
+ static bool firstTime = true;
+ if (!firstTime)
+ return;
+ firstTime = false;
+ qt_tablet_widget = new QWidget(0);
+ qt_tablet_widget->createWinId();
+ qt_tablet_widget->setObjectName(QLatin1String("Qt internal tablet widget"));
+ // We don't need this internal widget to appear in QApplication::topLevelWidgets()
+ if (QWidgetPrivate::allWidgets)
+ QWidgetPrivate::allWidgets->remove(qt_tablet_widget);
+ LOGCONTEXT lcMine;
+ qAddPostRoutine(qt_tablet_cleanup);
+ struct tagAXIS tpOri[3];
+ init_wintab_functions();
+ if (ptrWTInfo && ptrWTOpen && ptrWTQueueSizeGet && ptrWTQueueSizeSet) {
+ // make sure we have WinTab
+ if (!ptrWTInfo(0, 0, NULL)) {
+#ifdef TABLET_DEBUG
+ qWarning("QWidget: Wintab services not available");
+#endif
+ return;
+ }
+
+ // some tablets don't support tilt, check if it is possible,
+ qt_tablet_tilt_support = ptrWTInfo(WTI_DEVICES, DVC_ORIENTATION, &tpOri);
+ if (qt_tablet_tilt_support) {
+ // check for azimuth and altitude
+ qt_tablet_tilt_support = tpOri[0].axResolution && tpOri[1].axResolution;
+ }
+ // build our context from the default context
+ ptrWTInfo(WTI_DEFSYSCTX, 0, &lcMine);
+ // Go for the raw coordinates, the tablet event will return good stuff
+ lcMine.lcOptions |= CXO_MESSAGES | CXO_CSRMESSAGES;
+ lcMine.lcPktData = PACKETDATA;
+ lcMine.lcPktMode = PACKETMODE;
+ lcMine.lcMoveMask = PACKETDATA;
+ lcMine.lcOutOrgX = 0;
+ lcMine.lcOutExtX = lcMine.lcInExtX;
+ lcMine.lcOutOrgY = 0;
+ lcMine.lcOutExtY = -lcMine.lcInExtY;
+ qt_tablet_context = ptrWTOpen(qt_tablet_widget->winId(), &lcMine, true);
+#ifdef TABLET_DEBUG
+ qDebug("Tablet is %p", qt_tablet_context);
+#endif
+ if (!qt_tablet_context) {
+#ifdef TABLET_DEBUG
+ qWarning("QWidget: Failed to open the tablet");
+#endif
+ return;
+ }
+ // Set the size of the Packet Queue to the correct size...
+ int currSize = ptrWTQueueSizeGet(qt_tablet_context);
+ if (!ptrWTQueueSizeSet(qt_tablet_context, QT_TABLET_NPACKETQSIZE)) {
+ // Ideally one might want to use a smaller
+ // multiple, but for now, since we managed to destroy
+ // the existing Q with the previous call, set it back
+ // to the other size, which should work. If not,
+ // there will be trouble.
+ if (!ptrWTQueueSizeSet(qt_tablet_context, currSize)) {
+ Q_ASSERT_X(0, "Qt::Internal", "There is no packet queue for"
+ " the tablet. The tablet will not work");
+ }
+ }
+ }
+}
+
+static void qt_tablet_cleanup()
+{
+ if (ptrWTClose)
+ ptrWTClose(qt_tablet_context);
+ delete qt_tablet_widget;
+ qt_tablet_widget = 0;
+}
+#endif // QT_NO_TABLETEVENT
+
+const QString qt_reg_winclass(QWidget *w); // defined in qapplication_win.cpp
+
+#ifndef QT_NO_DRAGANDDROP
+void qt_olednd_unregister(QWidget* widget, QOleDropTarget *dst); // dnd_win
+QOleDropTarget* qt_olednd_register(QWidget* widget);
+#endif
+
+extern bool qt_nograb();
+extern HRGN qt_win_bitmapToRegion(const QBitmap& bitmap);
+
+static QWidget *mouseGrb = 0;
+static QCursor *mouseGrbCur = 0;
+static QWidget *keyboardGrb = 0;
+static HHOOK journalRec = 0;
+
+extern "C" LRESULT QT_WIN_CALLBACK QtWndProc(HWND, UINT, WPARAM, LPARAM);
+
+#define XCOORD_MAX 16383
+#define WRECT_MAX 16383
+
+/*****************************************************************************
+ QWidget member functions
+ *****************************************************************************/
+
+#ifndef Q_WS_WINCE
+void QWidgetPrivate::create_sys(WId window, bool initializeWindow, bool destroyOldWindow)
+{
+ Q_Q(QWidget);
+ static int sw = -1, sh = -1;
+
+ Qt::WindowType type = q->windowType();
+ Qt::WindowFlags flags = data.window_flags;
+
+ bool topLevel = (flags & Qt::Window);
+ bool popup = (type == Qt::Popup);
+ bool dialog = (type == Qt::Dialog
+ || type == Qt::Sheet
+ || (flags & Qt::MSWindowsFixedSizeDialogHint));
+ bool desktop = (type == Qt::Desktop);
+ bool tool = (type == Qt::Tool || type == Qt::Drawer);
+
+ HINSTANCE appinst = qWinAppInst();
+ HWND parentw, destroyw = 0;
+ WId id = 0;
+
+ QString windowClassName = qt_reg_winclass(q);
+
+ if (!window) // always initialize
+ initializeWindow = true;
+
+ if (popup)
+ flags |= Qt::WindowStaysOnTopHint; // a popup stays on top
+
+ if (sw < 0) { // get the (primary) screen size
+ sw = GetSystemMetrics(SM_CXSCREEN);
+ sh = GetSystemMetrics(SM_CYSCREEN);
+ }
+
+ if (desktop && !q->testAttribute(Qt::WA_DontShowOnScreen)) { // desktop widget
+ popup = false; // force this flags off
+ data.crect.setRect(GetSystemMetrics(76 /* SM_XVIRTUALSCREEN */), GetSystemMetrics(77 /* SM_YVIRTUALSCREEN */),
+ GetSystemMetrics(78 /* SM_CXVIRTUALSCREEN */), GetSystemMetrics(79 /* SM_CYVIRTUALSCREEN */));
+ }
+
+ parentw = q->parentWidget() ? q->parentWidget()->effectiveWinId() : 0;
+
+ QString title;
+ int style = WS_CHILD;
+ int exsty = 0;
+
+ if (window) {
+ style = GetWindowLong(window, GWL_STYLE);
+ if (!style)
+ qErrnoWarning("QWidget::create: GetWindowLong failed");
+ topLevel = false; // #### needed for some IE plugins??
+ } else if (popup || (type == Qt::ToolTip) || (type == Qt::SplashScreen)) {
+ style = WS_POPUP;
+ } else if (topLevel && !desktop) {
+ if (flags & Qt::FramelessWindowHint)
+ style = WS_POPUP; // no border
+ else if (flags & Qt::WindowTitleHint)
+ style = WS_OVERLAPPED;
+ else
+ style = 0;
+ }
+ if (!desktop) {
+ // if (!testAttribute(Qt::WA_PaintUnclipped))
+ // ### Commented out for now as it causes some problems, but
+ // this should be correct anyway, so dig some more into this
+#ifndef Q_FLATTEN_EXPOSE
+ style |= WS_CLIPSIBLINGS | WS_CLIPCHILDREN ;
+#endif
+ if (topLevel) {
+ if ((type == Qt::Window || dialog || tool)) {
+ if (!(flags & Qt::FramelessWindowHint)) {
+ style |= WS_POPUP;
+ if (!(flags & Qt::MSWindowsFixedSizeDialogHint))
+ style |= WS_THICKFRAME;
+ else
+ style |= WS_DLGFRAME;
+ }
+ if (flags & Qt::WindowTitleHint)
+ style |= WS_CAPTION;
+ if (flags & Qt::WindowSystemMenuHint)
+ style |= WS_SYSMENU;
+ if (flags & Qt::WindowMinimizeButtonHint)
+ style |= WS_MINIMIZEBOX;
+ if (shouldShowMaximizeButton())
+ style |= WS_MAXIMIZEBOX;
+ if (tool)
+ exsty |= WS_EX_TOOLWINDOW;
+ if (flags & Qt::WindowContextHelpButtonHint)
+ exsty |= WS_EX_CONTEXTHELP;
+ } else {
+ exsty |= WS_EX_TOOLWINDOW;
+ }
+ }
+ }
+
+ if (flags & Qt::WindowTitleHint) {
+ title = q->isWindow() ? qAppName() : q->objectName();
+ }
+
+ // The Qt::WA_WState_Created flag is checked by translateConfigEvent() in
+ // qapplication_win.cpp. We switch it off temporarily to avoid move
+ // and resize events during creationt
+ q->setAttribute(Qt::WA_WState_Created, false);
+
+ if (window) { // override the old window
+ if (destroyOldWindow)
+ destroyw = data.winid;
+ id = window;
+ setWinId(window);
+ LONG res = SetWindowLong(window, GWL_STYLE, style);
+ if (!res)
+ qErrnoWarning("QWidget::create: Failed to set window style");
+#ifdef _WIN64
+ res = SetWindowLongPtr( window, GWLP_WNDPROC, (LONG_PTR)QtWndProc );
+#else
+ res = SetWindowLong( window, GWL_WNDPROC, (LONG)QtWndProc );
+#endif
+ if (!res)
+ qErrnoWarning("QWidget::create: Failed to set window procedure");
+ } else if (desktop) { // desktop widget
+ id = GetDesktopWindow();
+// QWidget *otherDesktop = QWidget::find(id); // is there another desktop?
+// if (otherDesktop && otherDesktop->testWFlags(Qt::WPaintDesktop)) {
+// otherDesktop->d_func()->setWinId(0); // remove id from widget mapper
+// d->setWinId(id); // make sure otherDesktop is
+// otherDesktop->d_func()->setWinId(id); // found first
+// } else {
+ setWinId(id);
+// }
+ } else if (topLevel) { // create top-level widget
+ if (popup)
+ parentw = 0;
+
+ const bool wasMoved = q->testAttribute(Qt::WA_Moved);
+ int x = wasMoved ? data.crect.left() : CW_USEDEFAULT;
+ int y = wasMoved ? data.crect.top() : CW_USEDEFAULT;
+ int w = CW_USEDEFAULT;
+ int h = CW_USEDEFAULT;
+
+ // Adjust for framestrut when needed
+ RECT rect = {0,0,0,0};
+ bool isVisibleOnScreen = !q->testAttribute(Qt::WA_DontShowOnScreen);
+ if (isVisibleOnScreen && AdjustWindowRectEx(&rect, style & ~WS_OVERLAPPED, FALSE, exsty)) {
+ QTLWExtra *td = maybeTopData();
+ if (wasMoved && (td && !td->posFromMove)) {
+ x = data.crect.x() + rect.left;
+ y = data.crect.y() + rect.top;
+ }
+
+ if (q->testAttribute(Qt::WA_Resized)) {
+ w = data.crect.width() + (rect.right - rect.left);
+ h = data.crect.height() + (rect.bottom - rect.top);
+ }
+ }
+ //update position & initial size of POPUP window
+ if (isVisibleOnScreen && topLevel && initializeWindow && (style & WS_POPUP)) {
+ if (!q->testAttribute(Qt::WA_Resized)) {
+ w = sw/2;
+ h = 4*sh/10;
+ if (extra) {
+ int dx = rect.right - rect.left;
+ int dy = rect.bottom - rect.top;
+ w = qMin(w, extra->maxw + dx);
+ h = qMin(h, extra->maxh + dy);
+ w = qMax(w, extra->minw + dx);
+ h = qMax(h, extra->minh + dy);
+ }
+ }
+ if (!wasMoved) {
+ x = sw/2 - w/2;
+ y = sh/2 - h/2;
+ }
+ }
+
+ id = CreateWindowEx(exsty, reinterpret_cast<const wchar_t *>(windowClassName.utf16()),
+ reinterpret_cast<const wchar_t *>(title.utf16()), style,
+ x, y, w, h,
+ parentw, NULL, appinst, NULL);
+ if (!id)
+ qErrnoWarning("QWidget::create: Failed to create window");
+ setWinId(id);
+ if ((flags & Qt::WindowStaysOnTopHint) || (type == Qt::ToolTip)) {
+ SetWindowPos(id, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);
+ if (flags & Qt::WindowStaysOnBottomHint)
+ qWarning() << "QWidget: Incompatible window flags: the window can't be on top and on bottom at the same time";
+ } else if (flags & Qt::WindowStaysOnBottomHint)
+ SetWindowPos(id, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);
+ winUpdateIsOpaque();
+ } else if (q->testAttribute(Qt::WA_NativeWindow) || paintOnScreen()) { // create child widget
+ id = CreateWindowEx(exsty, reinterpret_cast<const wchar_t *>(windowClassName.utf16()),
+ reinterpret_cast<const wchar_t *>(title.utf16()), style,
+ data.crect.left(), data.crect.top(), data.crect.width(), data.crect.height(),
+ parentw, NULL, appinst, NULL);
+ if (!id)
+ qErrnoWarning("QWidget::create: Failed to create window");
+ SetWindowPos(id, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
+ setWinId(id);
+ }
+
+ if (desktop) {
+ q->setAttribute(Qt::WA_WState_Visible);
+ } else if (topLevel && !q->testAttribute(Qt::WA_DontShowOnScreen)) {
+ RECT cr;
+ GetClientRect(id, &cr);
+ // one cannot trust cr.left and cr.top, use a correction POINT instead
+ POINT pt;
+ pt.x = 0;
+ pt.y = 0;
+ ClientToScreen(id, &pt);
+
+ if (data.crect.width() == 0 || data.crect.height() == 0) {
+ data.crect = QRect(pt.x, pt.y, data.crect.width(), data.crect.height());
+ } else {
+ data.crect = QRect(QPoint(pt.x, pt.y),
+ QPoint(pt.x + cr.right - 1, pt.y + cr.bottom - 1));
+ }
+
+ if (data.fstrut_dirty) {
+ // be nice to activeqt
+ updateFrameStrut();
+ }
+ }
+
+ if (topLevel) {
+ if (data.window_flags & Qt::CustomizeWindowHint
+ && data.window_flags & Qt::WindowTitleHint) {
+ HMENU systemMenu = GetSystemMenu((HWND)q->internalWinId(), FALSE);
+ if (data.window_flags & Qt::WindowCloseButtonHint)
+ EnableMenuItem(systemMenu, SC_CLOSE, MF_BYCOMMAND|MF_ENABLED);
+ else
+ EnableMenuItem(systemMenu, SC_CLOSE, MF_BYCOMMAND|MF_GRAYED);
+ }
+ }
+
+ q->setAttribute(Qt::WA_WState_Created); // accept move/resize events
+ hd = 0; // no display context
+
+ if (q->testAttribute(Qt::WA_AcceptTouchEvents))
+ registerTouchWindow();
+
+ if (window) { // got window from outside
+ if (IsWindowVisible(window))
+ q->setAttribute(Qt::WA_WState_Visible);
+ else
+ q->setAttribute(Qt::WA_WState_Visible, false);
+ }
+
+ if (extra && !extra->mask.isEmpty())
+ setMask_sys(extra->mask);
+
+#if defined(QT_NON_COMMERCIAL)
+ QT_NC_WIDGET_CREATE
+#endif
+
+ if (q->hasFocus() && q->testAttribute(Qt::WA_InputMethodEnabled))
+ q->inputContext()->setFocusWidget(q);
+
+ if (destroyw) {
+ DestroyWindow(destroyw);
+ }
+
+#ifndef QT_NO_TABLETEVENT
+ if (q != qt_tablet_widget && QWidgetPrivate::mapper)
+ qt_tablet_init();
+#endif // QT_NO_TABLETEVENT
+
+ if (q->testAttribute(Qt::WA_DropSiteRegistered))
+ registerDropSite(true);
+
+ if (maybeTopData() && maybeTopData()->opacity != 255)
+ q->setWindowOpacity(maybeTopData()->opacity/255.);
+
+ if (topLevel && (data.crect.width() == 0 || data.crect.height() == 0)) {
+ q->setAttribute(Qt::WA_OutsideWSRange, true);
+ }
+
+ if (!topLevel && q->testAttribute(Qt::WA_NativeWindow) && q->testAttribute(Qt::WA_Mapped)) {
+ Q_ASSERT(q->internalWinId());
+ ShowWindow(q->internalWinId(), SW_SHOW);
+ }
+}
+
+#endif //Q_WS_WINCE
+
+
+void QWidget::destroy(bool destroyWindow, bool destroySubWindows)
+{
+ Q_D(QWidget);
+ d->aboutToDestroy();
+ if (!isWindow() && parentWidget())
+ parentWidget()->d_func()->invalidateBuffer(d->effectiveRectFor(geometry()));
+ d->deactivateWidgetCleanup();
+ if (testAttribute(Qt::WA_WState_Created)) {
+ setAttribute(Qt::WA_WState_Created, false);
+ for(int i = 0; i < d->children.size(); ++i) { // destroy all widget children
+ register QObject *obj = d->children.at(i);
+ if (obj->isWidgetType())
+ ((QWidget*)obj)->destroy(destroySubWindows,
+ destroySubWindows);
+ }
+ if (mouseGrb == this)
+ releaseMouse();
+ if (keyboardGrb == this)
+ releaseKeyboard();
+ if (testAttribute(Qt::WA_ShowModal)) // just be sure we leave modal
+ QApplicationPrivate::leaveModal(this);
+ else if ((windowType() == Qt::Popup))
+ qApp->d_func()->closePopup(this);
+ if (destroyWindow && !(windowType() == Qt::Desktop) && internalWinId()) {
+ DestroyWindow(internalWinId());
+ }
+#ifdef Q_WS_WINCE
+ if (destroyWindow && (windowType() == Qt::Desktop) && !GetDesktopWindow()) {
+ DestroyWindow(internalWinId());
+ }
+
+#endif
+ QT_TRY {
+ d->setWinId(0);
+ } QT_CATCH (const std::bad_alloc &) {
+ // swallow - destructors must not throw
+ }
+ }
+}
+
+void QWidgetPrivate::reparentChildren()
+{
+ Q_Q(QWidget);
+ QObjectList chlist = q->children();
+ for(int i = 0; i < chlist.size(); ++i) { // reparent children
+ QObject *obj = chlist.at(i);
+ if (obj->isWidgetType()) {
+ QWidget *w = (QWidget *)obj;
+ if ((w->windowType() == Qt::Popup)) {
+ ;
+ } else if (w->isWindow()) {
+ bool showIt = w->isVisible();
+ QPoint old_pos = w->pos();
+ w->setParent(q, w->windowFlags());
+ w->move(old_pos);
+ if (showIt)
+ w->show();
+ } else {
+ w->d_func()->invalidateBuffer(w->rect());
+ SetParent(w->effectiveWinId(), q->effectiveWinId());
+ w->d_func()->reparentChildren();
+ }
+ }
+ }
+}
+
+void QWidgetPrivate::setParent_sys(QWidget *parent, Qt::WindowFlags f)
+{
+ Q_Q(QWidget);
+ bool wasCreated = q->testAttribute(Qt::WA_WState_Created);
+ if (q->isVisible() && q->parentWidget() && parent != q->parentWidget())
+ q->parentWidget()->d_func()->invalidateBuffer(effectiveRectFor(q->geometry()));
+
+ WId old_winid = data.winid;
+ // hide and reparent our own window away. Otherwise we might get
+ // destroyed when emitting the child remove event below. See QWorkspace.
+ if (q->isVisible() && data.winid) {
+ ShowWindow(data.winid, SW_HIDE);
+ SetParent(data.winid, 0);
+ }
+ bool dropSiteWasRegistered = false;
+ if (q->testAttribute(Qt::WA_DropSiteRegistered)) {
+ dropSiteWasRegistered = true;
+ q->setAttribute(Qt::WA_DropSiteRegistered, false); // ole dnd unregister (we will register again below)
+ }
+
+ if ((q->windowType() == Qt::Desktop))
+ old_winid = 0;
+ setWinId(0);
+
+ QObjectPrivate::setParent_helper(parent);
+ bool explicitlyHidden = q->testAttribute(Qt::WA_WState_Hidden) && q->testAttribute(Qt::WA_WState_ExplicitShowHide);
+
+ data.window_flags = f;
+ data.fstrut_dirty = true;
+ q->setAttribute(Qt::WA_WState_Created, false);
+ q->setAttribute(Qt::WA_WState_Visible, false);
+ q->setAttribute(Qt::WA_WState_Hidden, false);
+ adjustFlags(data.window_flags, q);
+ // keep compatibility with previous versions, we need to preserve the created state
+ // (but we recreate the winId for the widget being reparented, again for compatibility)
+ if (wasCreated || (!q->isWindow() && parent->testAttribute(Qt::WA_WState_Created)))
+ createWinId();
+ if (q->isWindow() || (!parent || parent->isVisible()) || explicitlyHidden)
+ q->setAttribute(Qt::WA_WState_Hidden);
+ q->setAttribute(Qt::WA_WState_ExplicitShowHide, explicitlyHidden);
+
+ if (wasCreated) {
+ reparentChildren();
+ }
+
+ if (extra && !extra->mask.isEmpty()) {
+ QRegion r = extra->mask;
+ extra->mask = QRegion();
+ q->setMask(r);
+ }
+ if (extra && extra->topextra && !extra->topextra->caption.isEmpty()) {
+ setWindowIcon_sys(true);
+ setWindowTitle_helper(extra->topextra->caption);
+ }
+ if (old_winid)
+ DestroyWindow(old_winid);
+
+ if (q->testAttribute(Qt::WA_AcceptDrops) || dropSiteWasRegistered
+ || (!q->isWindow() && q->parentWidget() && q->parentWidget()->testAttribute(Qt::WA_DropSiteRegistered)))
+ q->setAttribute(Qt::WA_DropSiteRegistered, true);
+
+#ifdef Q_WS_WINCE
+ // Show borderless toplevel windows in tasklist & NavBar
+ if (!parent) {
+ QString txt = q->windowTitle().isEmpty()?qAppName():q->windowTitle();
+ SetWindowText(q->internalWinId(), (wchar_t*)txt.utf16());
+ }
+#endif
+ invalidateBuffer(q->rect());
+}
+
+
+QPoint QWidget::mapToGlobal(const QPoint &pos) const
+{
+ Q_D(const QWidget);
+ QWidget *parentWindow = window();
+ QWExtra *extra = parentWindow->d_func()->extra;
+ if (!isVisible() || parentWindow->isMinimized() || !testAttribute(Qt::WA_WState_Created) || !internalWinId()
+ || (extra
+#ifndef QT_NO_GRAPHICSVIEW
+ && extra->proxyWidget
+#endif //QT_NO_GRAPHICSVIEW
+ )) {
+ if (extra && extra->topextra && extra->topextra->embedded) {
+ QPoint pt = mapTo(parentWindow, pos);
+ POINT p = {pt.x(), pt.y()};
+ ClientToScreen(parentWindow->effectiveWinId(), &p);
+ return QPoint(p.x, p.y);
+ } else {
+ QPoint toGlobal = mapTo(parentWindow, pos) + parentWindow->pos();
+ // Adjust for window decorations
+ toGlobal += parentWindow->geometry().topLeft() - parentWindow->frameGeometry().topLeft();
+ return toGlobal;
+ }
+ }
+ POINT p;
+ QPoint tmp = d->mapToWS(pos);
+ p.x = tmp.x();
+ p.y = tmp.y();
+ ClientToScreen(internalWinId(), &p);
+ return QPoint(p.x, p.y);
+}
+
+QPoint QWidget::mapFromGlobal(const QPoint &pos) const
+{
+ Q_D(const QWidget);
+ QWidget *parentWindow = window();
+ QWExtra *extra = parentWindow->d_func()->extra;
+ if (!isVisible() || parentWindow->isMinimized() || !testAttribute(Qt::WA_WState_Created) || !internalWinId()
+ || (extra
+#ifndef QT_NO_GRAPHICSVIEW
+ && extra->proxyWidget
+#endif //QT_NO_GRAPHICSVIEW
+ )) {
+ if (extra && extra->topextra && extra->topextra->embedded) {
+ POINT p = {pos.x(), pos.y()};
+ ScreenToClient(parentWindow->effectiveWinId(), &p);
+ return mapFrom(parentWindow, QPoint(p.x, p.y));
+ } else {
+ QPoint fromGlobal = mapFrom(parentWindow, pos - parentWindow->pos());
+ // Adjust for window decorations
+ fromGlobal -= parentWindow->geometry().topLeft() - parentWindow->frameGeometry().topLeft();
+ return fromGlobal;
+ }
+ }
+ POINT p;
+ p.x = pos.x();
+ p.y = pos.y();
+ ScreenToClient(internalWinId(), &p);
+ return d->mapFromWS(QPoint(p.x, p.y));
+}
+
+void QWidgetPrivate::updateSystemBackground() {}
+
+#ifndef QT_NO_CURSOR
+void QWidgetPrivate::setCursor_sys(const QCursor &cursor)
+{
+ Q_UNUSED(cursor);
+ Q_Q(QWidget);
+ qt_win_set_cursor(q, false);
+}
+
+void QWidgetPrivate::unsetCursor_sys()
+{
+ Q_Q(QWidget);
+ qt_win_set_cursor(q, false);
+}
+#endif
+
+void QWidgetPrivate::setWindowTitle_sys(const QString &caption)
+{
+ Q_Q(QWidget);
+ if (!q->isWindow())
+ return;
+
+ Q_ASSERT(q->testAttribute(Qt::WA_WState_Created));
+ SetWindowText(q->internalWinId(), (wchar_t*)caption.utf16());
+}
+
+HICON qt_createIcon(QIcon icon, int xSize, int ySize, QPixmap **cache)
+{
+ HICON result = 0;
+ if (!icon.isNull()) { // valid icon
+ QSize size = icon.actualSize(QSize(xSize, ySize));
+ QPixmap pm = icon.pixmap(size);
+ if (pm.isNull())
+ return 0;
+
+ result = pm.toWinHICON();
+
+ if (cache) {
+ delete *cache;
+ *cache = new QPixmap(pm);;
+ }
+ }
+ return result;
+}
+
+void QWidgetPrivate::setWindowIcon_sys(bool forceReset)
+{
+ Q_Q(QWidget);
+ if (!q->testAttribute(Qt::WA_WState_Created) || !q->isWindow())
+ return;
+ QTLWExtra* x = topData();
+ if (x->iconPixmap && !forceReset)
+ // already been set
+ return;
+
+ if (x->winIconBig) {
+ DestroyIcon(x->winIconBig);
+ x->winIconBig = 0;
+ }
+ if (x->winIconSmall) {
+ DestroyIcon(x->winIconSmall);
+ x->winIconSmall = 0;
+ }
+
+ x->winIconSmall = qt_createIcon(q->windowIcon(),
+ GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON),
+ &(x->iconPixmap));
+ x->winIconBig = qt_createIcon(q->windowIcon(),
+ GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CYICON),
+ &(x->iconPixmap));
+ if (x->winIconBig) {
+ SendMessage(q->internalWinId(), WM_SETICON, 0 /* ICON_SMALL */, (LPARAM)x->winIconSmall);
+ SendMessage(q->internalWinId(), WM_SETICON, 1 /* ICON_BIG */, (LPARAM)x->winIconBig);
+ } else {
+ SendMessage(q->internalWinId(), WM_SETICON, 0 /* ICON_SMALL */, (LPARAM)x->winIconSmall);
+ SendMessage(q->internalWinId(), WM_SETICON, 1 /* ICON_BIG */, (LPARAM)x->winIconSmall);
+ }
+}
+
+
+void QWidgetPrivate::setWindowIconText_sys(const QString &iconText)
+{
+ Q_UNUSED(iconText);
+}
+
+
+QCursor *qt_grab_cursor()
+{
+ return mouseGrbCur;
+}
+
+// The procedure does nothing, but is required for mousegrabbing to work
+#ifndef Q_WS_WINCE
+LRESULT QT_WIN_CALLBACK qJournalRecordProc(int nCode, WPARAM wParam, LPARAM lParam)
+{
+ return CallNextHookEx(journalRec, nCode, wParam, lParam);
+}
+#endif //Q_WS_WINCE
+
+/* Works only as long as pointer is inside the application's window,
+ which is good enough for QDockWidget.
+
+ Doesn't call SetWindowsHookEx() - this function causes a system-wide
+ freeze if any other app on the system installs a hook and fails to
+ process events. */
+void QWidgetPrivate::grabMouseWhileInWindow()
+{
+ Q_Q(QWidget);
+ if (!qt_nograb()) {
+ if (mouseGrb)
+ mouseGrb->releaseMouse();
+ Q_ASSERT(q->testAttribute(Qt::WA_WState_Created));
+ SetCapture(q->effectiveWinId());
+ mouseGrb = q;
+#ifndef QT_NO_CURSOR
+ mouseGrbCur = new QCursor(mouseGrb->cursor());
+#endif
+ }
+}
+
+#ifndef Q_WS_WINCE
+void QWidget::grabMouse()
+{
+ if (!qt_nograb()) {
+ if (mouseGrb)
+ mouseGrb->releaseMouse();
+ journalRec = SetWindowsHookEx(WH_JOURNALRECORD, (HOOKPROC)qJournalRecordProc, GetModuleHandle(0), 0);
+ Q_ASSERT(testAttribute(Qt::WA_WState_Created));
+ SetCapture(effectiveWinId());
+ mouseGrb = this;
+#ifndef QT_NO_CURSOR
+ mouseGrbCur = new QCursor(mouseGrb->cursor());
+#endif
+ }
+}
+
+#ifndef QT_NO_CURSOR
+void QWidget::grabMouse(const QCursor &cursor)
+{
+ if (!qt_nograb()) {
+ if (mouseGrb)
+ mouseGrb->releaseMouse();
+ journalRec = SetWindowsHookEx(WH_JOURNALRECORD, (HOOKPROC)qJournalRecordProc, GetModuleHandle(0), 0);
+ Q_ASSERT(testAttribute(Qt::WA_WState_Created));
+ SetCapture(effectiveWinId());
+ mouseGrbCur = new QCursor(cursor);
+ SetCursor(mouseGrbCur->handle());
+ mouseGrb = this;
+ }
+}
+#endif
+
+void QWidget::releaseMouse()
+{
+ if (!qt_nograb() && mouseGrb == this) {
+ ReleaseCapture();
+ if (journalRec) {
+ UnhookWindowsHookEx(journalRec);
+ journalRec = 0;
+ }
+ if (mouseGrbCur) {
+ delete mouseGrbCur;
+ mouseGrbCur = 0;
+ }
+ mouseGrb = 0;
+ }
+}
+#endif
+
+void QWidget::grabKeyboard()
+{
+ if (!qt_nograb()) {
+ if (keyboardGrb)
+ keyboardGrb->releaseKeyboard();
+ keyboardGrb = this;
+ }
+}
+
+void QWidget::releaseKeyboard()
+{
+ if (!qt_nograb() && keyboardGrb == this)
+ keyboardGrb = 0;
+}
+
+
+QWidget *QWidget::mouseGrabber()
+{
+ return mouseGrb;
+}
+
+QWidget *QWidget::keyboardGrabber()
+{
+ return keyboardGrb;
+}
+
+void QWidget::activateWindow()
+{
+ window()->createWinId();
+ SetForegroundWindow(window()->internalWinId());
+}
+
+#ifndef Q_WS_WINCE
+void QWidget::setWindowState(Qt::WindowStates newstate)
+{
+ Q_D(QWidget);
+ Qt::WindowStates oldstate = windowState();
+ if (oldstate == newstate)
+ return;
+
+ int max = SW_MAXIMIZE;
+ int min = SW_MINIMIZE;
+
+ int normal = SW_SHOWNOACTIVATE;
+ if (newstate & Qt::WindowActive) {
+ max = SW_SHOWMAXIMIZED;
+ min = SW_SHOWMINIMIZED;
+ normal = SW_SHOWNORMAL;
+ }
+
+ if (isWindow()) {
+ createWinId();
+ Q_ASSERT(testAttribute(Qt::WA_WState_Created));
+
+ // Ensure the initial size is valid, since we store it as normalGeometry below.
+ if (!testAttribute(Qt::WA_Resized) && !isVisible())
+ adjustSize();
+
+ if ((oldstate & Qt::WindowMaximized) != (newstate & Qt::WindowMaximized)) {
+ if (newstate & Qt::WindowMaximized && !(oldstate & Qt::WindowFullScreen))
+ d->topData()->normalGeometry = geometry();
+ if (isVisible() && !(newstate & Qt::WindowMinimized)) {
+ ShowWindow(internalWinId(), (newstate & Qt::WindowMaximized) ? max : normal);
+ if (!(newstate & Qt::WindowFullScreen)) {
+ QRect r = d->topData()->normalGeometry;
+ if (!(newstate & Qt::WindowMaximized) && r.width() >= 0) {
+ if (pos() != r.topLeft() || size() !=r.size()) {
+ d->topData()->normalGeometry = QRect(0,0,-1,-1);
+ setGeometry(r);
+ }
+ }
+ } else {
+ d->updateFrameStrut();
+ }
+ }
+ }
+
+ if ((oldstate & Qt::WindowFullScreen) != (newstate & Qt::WindowFullScreen)) {
+ if (newstate & Qt::WindowFullScreen) {
+ if (d->topData()->normalGeometry.width() < 0 && !(oldstate & Qt::WindowMaximized))
+ d->topData()->normalGeometry = geometry();
+ d->topData()->savedFlags = Qt::WindowFlags(GetWindowLong(internalWinId(), GWL_STYLE));
+#ifndef Q_FLATTEN_EXPOSE
+ UINT style = WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_POPUP;
+#else
+ UINT style = WS_POPUP;
+#endif
+ if (ulong(d->topData()->savedFlags) & WS_SYSMENU)
+ style |= WS_SYSMENU;
+ if (isVisible())
+ style |= WS_VISIBLE;
+ SetWindowLong(internalWinId(), GWL_STYLE, style);
+ QRect r = QApplication::desktop()->screenGeometry(this);
+ UINT swpf = SWP_FRAMECHANGED;
+ if (newstate & Qt::WindowActive)
+ swpf |= SWP_NOACTIVATE;
+
+ SetWindowPos(internalWinId(), HWND_TOP, r.left(), r.top(), r.width(), r.height(), swpf);
+ d->updateFrameStrut();
+ } else {
+ UINT style = d->topData()->savedFlags;
+ if (isVisible())
+ style |= WS_VISIBLE;
+ SetWindowLong(internalWinId(), GWL_STYLE, style);
+
+ UINT swpf = SWP_FRAMECHANGED | SWP_NOZORDER | SWP_NOSIZE | SWP_NOMOVE;
+ if (newstate & Qt::WindowActive)
+ swpf |= SWP_NOACTIVATE;
+ SetWindowPos(internalWinId(), 0, 0, 0, 0, 0, swpf);
+ d->updateFrameStrut();
+
+ // preserve maximized state
+ if (isVisible())
+ ShowWindow(internalWinId(), (newstate & Qt::WindowMaximized) ? max : normal);
+
+ if (!(newstate & Qt::WindowMaximized)) {
+ QRect r = d->topData()->normalGeometry;
+ d->topData()->normalGeometry = QRect(0,0,-1,-1);
+ if (r.isValid())
+ setGeometry(r);
+ }
+ }
+ }
+
+ if ((oldstate & Qt::WindowMinimized) != (newstate & Qt::WindowMinimized)) {
+ if (isVisible())
+ ShowWindow(internalWinId(), (newstate & Qt::WindowMinimized) ? min :
+ (newstate & Qt::WindowMaximized) ? max : normal);
+ }
+ }
+ data->window_state = newstate;
+ QWindowStateChangeEvent e(oldstate);
+ QApplication::sendEvent(this, &e);
+}
+#endif //Q_WS_WINCE
+
+
+/*
+ \internal
+ Platform-specific part of QWidget::hide().
+*/
+
+void QWidgetPrivate::hide_sys()
+{
+ Q_Q(QWidget);
+ deactivateWidgetCleanup();
+ Q_ASSERT(q->testAttribute(Qt::WA_WState_Created));
+#ifdef Q_WS_WINCE
+ if (!qt_wince_is_mobile() && q->isFullScreen()) {
+ HWND handle = FindWindow(L"HHTaskBar", L"");
+ if (handle) {
+ ShowWindow(handle, 1);
+ EnableWindow(handle, true);
+ }
+ }
+#endif
+ if (q->windowFlags() != Qt::Desktop) {
+ if ((q->windowFlags() & Qt::Popup) && q->internalWinId())
+ ShowWindow(q->internalWinId(), SW_HIDE);
+ else if (q->internalWinId())
+ SetWindowPos(q->internalWinId(),0, 0,0,0,0, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER);
+ }
+ if (q->isWindow()) {
+ if (QWidgetBackingStore *bs = maybeBackingStore())
+ bs->releaseBuffer();
+ } else {
+ invalidateBuffer(q->rect());
+ }
+ q->setAttribute(Qt::WA_Mapped, false);
+}
+
+
+/*
+ \internal
+ Platform-specific part of QWidget::show().
+*/
+#ifndef Q_WS_WINCE
+void QWidgetPrivate::show_sys()
+{
+ Q_Q(QWidget);
+#if defined(QT_NON_COMMERCIAL)
+ QT_NC_SHOW_WINDOW
+#endif
+ if (q->testAttribute(Qt::WA_OutsideWSRange))
+ return;
+ q->setAttribute(Qt::WA_Mapped);
+ Q_ASSERT(q->testAttribute(Qt::WA_WState_Created));
+
+ if (q->testAttribute(Qt::WA_DontShowOnScreen)) {
+ invalidateBuffer(q->rect());
+ return;
+ }
+
+ if (data.window_flags & Qt::Window) {
+ QTLWExtra *extra = topData();
+ if (!extra->hotkeyRegistered) {
+ // Try to set the hotkey using information from STARTUPINFO
+ STARTUPINFO startupInfo;
+ GetStartupInfo(&startupInfo);
+ // If STARTF_USEHOTKEY is set, hStdInput is the virtual keycode
+ if (startupInfo.dwFlags & 0x00000200) {
+ WPARAM hotKey = (WPARAM)startupInfo.hStdInput;
+ SendMessage(data.winid, WM_SETHOTKEY, hotKey, 0);
+ }
+ extra->hotkeyRegistered = 1;
+ }
+ }
+
+ int sm = SW_SHOWNORMAL;
+ bool fakedMaximize = false;
+ if (q->isWindow()) {
+ if (q->isMinimized()) {
+ sm = SW_SHOWMINIMIZED;
+ if (!IsWindowVisible(q->internalWinId()))
+ sm = SW_SHOWMINNOACTIVE;
+ } else if (q->isMaximized()) {
+ sm = SW_SHOWMAXIMIZED;
+ // Windows will not behave correctly when we try to maximize a window which does not
+ // have minimize nor maximize buttons in the window frame. Windows would then ignore
+ // non-available geometry, and rather maximize the widget to the full screen, minus the
+ // window frame (caption). So, we do a trick here, by adding a maximize button before
+ // maximizing the widget, and then remove the maximize button afterwards.
+ Qt::WindowFlags &flags = data.window_flags;
+ if (flags & Qt::WindowTitleHint &&
+ !(flags & (Qt::WindowMinMaxButtonsHint | Qt::FramelessWindowHint))) {
+ fakedMaximize = TRUE;
+ int style = GetWindowLong(q->internalWinId(), GWL_STYLE);
+ SetWindowLong(q->internalWinId(), GWL_STYLE, style | WS_MAXIMIZEBOX);
+ }
+ }
+ }
+ if (q->testAttribute(Qt::WA_ShowWithoutActivating)
+ || (q->windowType() == Qt::Popup)
+ || (q->windowType() == Qt::ToolTip)
+ || (q->windowType() == Qt::Tool)) {
+ sm = SW_SHOWNOACTIVATE;
+ }
+
+
+ if (q->internalWinId())
+ ShowWindow(q->internalWinId(), sm);
+
+ if (fakedMaximize) {
+ int style = GetWindowLong(q->internalWinId(), GWL_STYLE);
+ SetWindowLong(q->internalWinId(), GWL_STYLE, style & ~WS_MAXIMIZEBOX);
+ SetWindowPos(q->internalWinId(), 0, 0, 0, 0, 0,
+ SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOOWNERZORDER
+ | SWP_FRAMECHANGED);
+ }
+
+ if (q->internalWinId()) {
+ if (IsIconic(q->internalWinId()))
+ data.window_state |= Qt::WindowMinimized;
+ if (IsZoomed(q->internalWinId()))
+ data.window_state |= Qt::WindowMaximized;
+ // This is to resolve the problem where popups are opened from the
+ // system tray and not being implicitly activated
+ if (q->windowType() == Qt::Popup &&
+ !q->parentWidget() && !qApp->activeWindow())
+ q->activateWindow();
+ }
+
+ winSetupGestures();
+
+ invalidateBuffer(q->rect());
+}
+#endif //Q_WS_WINCE
+
+void QWidgetPrivate::setFocus_sys()
+{
+ Q_Q(QWidget);
+ if (q->testAttribute(Qt::WA_WState_Created) && q->window()->windowType() != Qt::Popup)
+ SetFocus(q->effectiveWinId());
+}
+
+void QWidgetPrivate::raise_sys()
+{
+ Q_Q(QWidget);
+ Q_ASSERT(q->testAttribute(Qt::WA_WState_Created));
+ if (q->internalWinId())
+ SetWindowPos(q->internalWinId(), HWND_TOP, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);
+}
+
+void QWidgetPrivate::lower_sys()
+{
+ Q_Q(QWidget);
+ Q_ASSERT(q->testAttribute(Qt::WA_WState_Created));
+ if (q->internalWinId())
+ SetWindowPos(q->internalWinId(), HWND_BOTTOM, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);
+ invalidateBuffer(q->rect());
+}
+
+void QWidgetPrivate::stackUnder_sys(QWidget* w)
+{
+ Q_Q(QWidget);
+ Q_ASSERT(q->testAttribute(Qt::WA_WState_Created));
+ if (q->internalWinId() && w->internalWinId())
+ SetWindowPos(q->internalWinId(), w->internalWinId() , 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
+ invalidateBuffer(q->rect());
+}
+
+
+/*
+ Helper function for non-toplevel widgets. Helps to map Qt's 32bit
+ coordinate system to Windpws's 16bit coordinate system.
+
+ This code is duplicated from the X11 code, so any changes there
+ should also (most likely) be reflected here.
+
+ (In all comments below: s/X/Windows/g)
+ */
+
+void QWidgetPrivate::setWSGeometry(bool dontShow, const QRect &)
+{
+ Q_Q(QWidget);
+ Q_ASSERT(q->testAttribute(Qt::WA_WState_Created));
+
+ /*
+ There are up to four different coordinate systems here:
+ Qt coordinate system for this widget.
+ X coordinate system for this widget (relative to wrect).
+ Qt coordinate system for parent
+ X coordinate system for parent (relative to parent's wrect).
+ */
+ QRect validRange(-XCOORD_MAX,-XCOORD_MAX, 2*XCOORD_MAX, 2*XCOORD_MAX);
+ QRect wrectRange(-WRECT_MAX,-WRECT_MAX, 2*WRECT_MAX, 2*WRECT_MAX);
+ QRect wrect;
+ //xrect is the X geometry of my X widget. (starts out in parent's Qt coord sys, and ends up in parent's X coord sys)
+ QRect xrect = data.crect;
+
+ const QWidget *const parent = q->parentWidget();
+ QRect parentWRect = parent->data->wrect;
+
+ if (parentWRect.isValid()) {
+ // parent is clipped, and we have to clip to the same limit as parent
+ if (!parentWRect.contains(xrect)) {
+ xrect &= parentWRect;
+ wrect = xrect;
+ //translate from parent's to my Qt coord sys
+ wrect.translate(-data.crect.topLeft());
+ }
+ //translate from parent's Qt coords to parent's X coords
+ xrect.translate(-parentWRect.topLeft());
+
+ } else {
+ // parent is not clipped, we may or may not have to clip
+
+ if (data.wrect.isValid() && QRect(QPoint(),data.crect.size()).contains(data.wrect)) {
+ // This is where the main optimization is: we are already
+ // clipped, and if our clip is still valid, we can just
+ // move our window, and do not need to move or clip
+ // children
+
+ QRect vrect = xrect & parent->rect();
+ vrect.translate(-data.crect.topLeft()); //the part of me that's visible through parent, in my Qt coords
+ if (data.wrect.contains(vrect)) {
+ xrect = data.wrect;
+ xrect.translate(data.crect.topLeft());
+ if (q->internalWinId())
+ MoveWindow(q->internalWinId(), xrect.x(), xrect.y(), xrect.width(), xrect.height(), true);
+ return;
+ }
+ }
+
+ if (!validRange.contains(xrect)) {
+ // we are too big, and must clip
+ xrect &=wrectRange;
+ wrect = xrect;
+ wrect.translate(-data.crect.topLeft());
+ //parent's X coord system is equal to parent's Qt coord
+ //sys, so we don't need to map xrect.
+ }
+
+ }
+
+
+ // unmap if we are outside the valid window system coord system
+ bool outsideRange = !xrect.isValid();
+ bool mapWindow = false;
+ if (q->testAttribute(Qt::WA_OutsideWSRange) != outsideRange) {
+ q->setAttribute(Qt::WA_OutsideWSRange, outsideRange);
+ if (outsideRange) {
+ if (q->internalWinId())
+ ShowWindow(q->internalWinId(), SW_HIDE);
+ q->setAttribute(Qt::WA_Mapped, false);
+ } else if (!q->isHidden()) {
+ mapWindow = true;
+ }
+ }
+
+ if (outsideRange)
+ return;
+
+ bool jump = (data.wrect != wrect);
+ data.wrect = wrect;
+
+ // and now recursively for all children...
+ for (int i = 0; i < children.size(); ++i) {
+ QObject *object = children.at(i);
+ if (object->isWidgetType()) {
+ QWidget *w = static_cast<QWidget *>(object);
+ if (!w->isWindow() && w->testAttribute(Qt::WA_WState_Created))
+ w->d_func()->setWSGeometry();
+ }
+ }
+
+ // move ourselves to the new position and map (if necessary) after
+ // the movement. Rationale: moving unmapped windows is much faster
+ // than moving mapped windows
+ if (q->internalWinId()) {
+ if (!parent->internalWinId())
+ xrect.translate(parent->mapTo(q->nativeParentWidget(), QPoint(0, 0)));
+ MoveWindow(q->internalWinId(), xrect.x(), xrect.y(), xrect.width(), xrect.height(), !jump);
+ }
+ if (mapWindow && !dontShow) {
+ q->setAttribute(Qt::WA_Mapped);
+ if (q->internalWinId())
+ ShowWindow(q->internalWinId(), SW_SHOWNOACTIVATE);
+ }
+
+ if (jump && q->internalWinId())
+ InvalidateRect(q->internalWinId(), 0, false);
+
+}
+
+//
+// The internal qWinRequestConfig, defined in qapplication_win.cpp, stores move,
+// resize and setGeometry requests for a widget that is already
+// processing a config event. The purpose is to avoid recursion.
+//
+void qWinRequestConfig(WId, int, int, int, int, int);
+
+void QWidgetPrivate::setGeometry_sys(int x, int y, int w, int h, bool isMove)
+{
+ Q_Q(QWidget);
+ Q_ASSERT(q->testAttribute(Qt::WA_WState_Created));
+ if (extra) { // any size restrictions?
+ w = qMin(w,extra->maxw);
+ h = qMin(h,extra->maxh);
+ w = qMax(w,extra->minw);
+ h = qMax(h,extra->minh);
+ }
+ if (q->isWindow())
+ topData()->normalGeometry = QRect(0, 0, -1, -1);
+
+ QSize oldSize(q->size());
+ QPoint oldPos(q->pos());
+
+ if (!q->isWindow())
+ isMove = (data.crect.topLeft() != QPoint(x, y));
+ bool isResize = w != oldSize.width() || h != oldSize.height();
+
+ if (!isMove && !isResize)
+ return;
+
+ if (isResize && !q->testAttribute(Qt::WA_StaticContents) && q->internalWinId())
+ ValidateRgn(q->internalWinId(), 0);
+
+#ifdef Q_WS_WINCE
+ // On Windows CE we can't just fiddle around with the window state.
+ // Too much magic in setWindowState.
+ if (isResize && q->isMaximized())
+ q->setWindowState(q->windowState() & ~Qt::WindowMaximized);
+#else
+ if (isResize)
+ data.window_state &= ~Qt::WindowMaximized;
+#endif
+
+ if (data.window_state & Qt::WindowFullScreen) {
+ QTLWExtra *top = topData();
+
+ if (q->isWindow()) {
+ // We need to update these flags when we remove the full screen state
+ // or the frame will not be updated
+ UINT style = top->savedFlags;
+ if (q->isVisible())
+ style |= WS_VISIBLE;
+ SetWindowLong(q->internalWinId(), GWL_STYLE, style);
+
+ UINT swpf = SWP_FRAMECHANGED | SWP_NOZORDER | SWP_NOSIZE | SWP_NOMOVE;
+ if (data.window_state & Qt::WindowActive)
+ swpf |= SWP_NOACTIVATE;
+ SetWindowPos(q->internalWinId(), 0, 0, 0, 0, 0, swpf);
+ updateFrameStrut();
+ }
+ data.window_state &= ~Qt::WindowFullScreen;
+ topData()->savedFlags = 0;
+ }
+
+ QTLWExtra *tlwExtra = q->window()->d_func()->maybeTopData();
+ const bool inTopLevelResize = tlwExtra ? tlwExtra->inTopLevelResize : false;
+ const bool isTranslucentWindow = !isOpaque && ptrUpdateLayeredWindowIndirect && (data.window_flags & Qt::FramelessWindowHint)
+ && GetWindowLong(q->internalWinId(), GWL_EXSTYLE) & Q_WS_EX_LAYERED;
+
+ if (q->testAttribute(Qt::WA_WState_ConfigPending)) { // processing config event
+ if (q->internalWinId())
+ qWinRequestConfig(q->internalWinId(), isMove ? 2 : 1, x, y, w, h);
+ } else {
+ if (!q->testAttribute(Qt::WA_DontShowOnScreen))
+ q->setAttribute(Qt::WA_WState_ConfigPending);
+ if (q->windowType() == Qt::Desktop) {
+ data.crect.setRect(x, y, w, h);
+ } else if (q->isWindow()) {
+ QRect fs(frameStrut());
+ if (extra) {
+ fs.setLeft(x - fs.left());
+ fs.setTop(y - fs.top());
+ fs.setRight((x + w - 1) + fs.right());
+ fs.setBottom((y + h - 1) + fs.bottom());
+ }
+ if (w == 0 || h == 0) {
+ q->setAttribute(Qt::WA_OutsideWSRange, true);
+ if (q->isVisible() && q->testAttribute(Qt::WA_Mapped))
+ hide_sys();
+ data.crect = QRect(x, y, w, h);
+ } else if (q->isVisible() && q->testAttribute(Qt::WA_OutsideWSRange)) {
+ q->setAttribute(Qt::WA_OutsideWSRange, false);
+
+ // put the window in its place and show it
+ MoveWindow(q->internalWinId(), fs.x(), fs.y(), fs.width(), fs.height(), true);
+ RECT rect;
+ if (!q->testAttribute(Qt::WA_DontShowOnScreen)) {
+ GetClientRect(q->internalWinId(), &rect);
+ data.crect.setRect(x, y, rect.right - rect.left, rect.bottom - rect.top);
+ } else {
+ data.crect.setRect(x, y, w, h);
+ }
+
+ show_sys();
+ } else if (!q->testAttribute(Qt::WA_DontShowOnScreen)) {
+ q->setAttribute(Qt::WA_OutsideWSRange, false);
+#ifndef Q_WS_WINCE
+ // If the window is hidden and in maximized state or minimized, instead of moving the
+ // window, set the normal position of the window.
+ WINDOWPLACEMENT wndpl;
+ GetWindowPlacement(q->internalWinId(), &wndpl);
+ if ((wndpl.showCmd == SW_MAXIMIZE && !IsWindowVisible(q->internalWinId())) || wndpl.showCmd == SW_SHOWMINIMIZED) {
+ RECT normal = {fs.x(), fs.y(), fs.x()+fs.width(), fs.y()+fs.height()};
+ wndpl.rcNormalPosition = normal;
+ wndpl.showCmd = wndpl.showCmd == SW_SHOWMINIMIZED ? SW_SHOWMINIMIZED : SW_HIDE;
+ SetWindowPlacement(q->internalWinId(), &wndpl);
+ } else {
+#else
+ if (data.window_state & Qt::WindowMaximized) {
+ qt_wince_maximize(q);
+ } else {
+#endif
+ MoveWindow(q->internalWinId(), fs.x(), fs.y(), fs.width(), fs.height(), true);
+ }
+ if (!q->isVisible())
+ InvalidateRect(q->internalWinId(), 0, FALSE);
+ RECT rect;
+ // If the layout has heightForWidth, the MoveWindow() above can
+ // change the size/position, so refresh them.
+
+ if (isTranslucentWindow) {
+ data.crect.setRect(x, y, w, h);
+ } else {
+ GetClientRect(q->internalWinId(), &rect);
+ RECT rcNormalPosition ={0};
+ // Use (0,0) as window position for embedded ActiveQt controls.
+ if (!tlwExtra || !tlwExtra->embedded)
+ GetWindowRect(q->internalWinId(), &rcNormalPosition);
+ QRect fStrut(frameStrut());
+ data.crect.setRect(rcNormalPosition.left + fStrut.left(),
+ rcNormalPosition.top + fStrut.top(),
+ rect.right - rect.left,
+ rect.bottom - rect.top);
+ isResize = data.crect.size() != oldSize;
+ }
+ } else {
+ q->setAttribute(Qt::WA_OutsideWSRange, false);
+ data.crect.setRect(x, y, w, h);
+ }
+ } else {
+ QRect oldGeom(data.crect);
+ data.crect.setRect(x, y, w, h);
+ if (q->isVisible() && (!inTopLevelResize || q->internalWinId())) {
+ // Top-level resize optimization does not work for native child widgets;
+ // disable it for this particular widget.
+ if (inTopLevelResize)
+ tlwExtra->inTopLevelResize = false;
+
+ if (!isResize)
+ moveRect(QRect(oldPos, oldSize), x - oldPos.x(), y - oldPos.y());
+ else
+ invalidateBuffer_resizeHelper(oldPos, oldSize);
+
+ if (inTopLevelResize)
+ tlwExtra->inTopLevelResize = true;
+ }
+ if (q->testAttribute(Qt::WA_WState_Created))
+ setWSGeometry();
+ }
+ q->setAttribute(Qt::WA_WState_ConfigPending, false);
+ }
+
+ if (q->isWindow() && q->isVisible() && isResize && !inTopLevelResize) {
+ invalidateBuffer(q->rect()); //after the resize
+ }
+
+ // Process events immediately rather than in translateConfigEvent to
+ // avoid windows message process delay.
+ if (q->isVisible()) {
+ if (isMove && q->pos() != oldPos) {
+ QMoveEvent e(q->pos(), oldPos);
+ QApplication::sendEvent(q, &e);
+ }
+ if (isResize) {
+ static bool slowResize = qgetenv("QT_SLOW_TOPLEVEL_RESIZE").toInt();
+ // If we have a backing store with static contents, we have to disable the top-level
+ // resize optimization in order to get invalidated regions for resized widgets.
+ // The optimization discards all invalidateBuffer() calls since we're going to
+ // repaint everything anyways, but that's not the case with static contents.
+ const bool setTopLevelResize = !slowResize && q->isWindow() && extra && extra->topextra
+ && !extra->topextra->inTopLevelResize
+ && (!extra->topextra->backingStore
+ || !extra->topextra->backingStore->hasStaticContents());
+ if (setTopLevelResize)
+ extra->topextra->inTopLevelResize = true;
+ QResizeEvent e(q->size(), oldSize);
+ QApplication::sendEvent(q, &e);
+ if (setTopLevelResize)
+ extra->topextra->inTopLevelResize = false;
+ }
+ } else {
+ if (isMove && q->pos() != oldPos)
+ q->setAttribute(Qt::WA_PendingMoveEvent, true);
+ if (isResize)
+ q->setAttribute(Qt::WA_PendingResizeEvent, true);
+ }
+}
+
+bool QWidgetPrivate::shouldShowMaximizeButton()
+{
+ if (data.window_flags & Qt::MSWindowsFixedSizeDialogHint)
+ return false;
+ // if the user explicitly asked for the maximize button, we try to add
+ // it even if the window has fixed size.
+ if (data.window_flags & Qt::CustomizeWindowHint &&
+ data.window_flags & Qt::WindowMaximizeButtonHint)
+ return true;
+ if (extra) {
+ if ((extra->maxw && extra->maxw != QWIDGETSIZE_MAX && extra->maxw != QLAYOUTSIZE_MAX)
+ || (extra->maxh && extra->maxh != QWIDGETSIZE_MAX && extra->maxh != QLAYOUTSIZE_MAX))
+ return false;
+ }
+ return data.window_flags & Qt::WindowMaximizeButtonHint;
+}
+
+void QWidgetPrivate::winUpdateIsOpaque()
+{
+#ifndef Q_WS_WINCE
+ Q_Q(QWidget);
+
+ if (!q->isWindow() || !q->testAttribute(Qt::WA_TranslucentBackground))
+ return;
+
+ if ((data.window_flags & Qt::FramelessWindowHint) == 0)
+ return;
+
+ if (!isOpaque && ptrUpdateLayeredWindowIndirect) {
+ SetWindowLong(q->internalWinId(), GWL_EXSTYLE,
+ GetWindowLong(q->internalWinId(), GWL_EXSTYLE) | Q_WS_EX_LAYERED);
+ } else {
+ SetWindowLong(q->internalWinId(), GWL_EXSTYLE,
+ GetWindowLong(q->internalWinId(), GWL_EXSTYLE) & ~Q_WS_EX_LAYERED);
+ }
+#endif
+}
+
+void QWidgetPrivate::setConstraints_sys()
+{
+#ifndef Q_WS_WINCE_WM
+ Q_Q(QWidget);
+ if (q->isWindow() && q->testAttribute(Qt::WA_WState_Created)) {
+ int style = GetWindowLong(q->internalWinId(), GWL_STYLE);
+ if (shouldShowMaximizeButton())
+ style |= WS_MAXIMIZEBOX;
+ else
+ style &= ~WS_MAXIMIZEBOX;
+ SetWindowLong(q->internalWinId(), GWL_STYLE, style);
+ }
+#endif
+}
+
+void QWidgetPrivate::scroll_sys(int dx, int dy)
+{
+ Q_Q(QWidget);
+ scrollChildren(dx, dy);
+
+ if (!paintOnScreen()) {
+ scrollRect(q->rect(), dx, dy);
+ } else {
+ UINT flags = SW_INVALIDATE;
+ if (!q->testAttribute(Qt::WA_OpaquePaintEvent))
+ flags |= SW_ERASE;
+ Q_ASSERT(q->testAttribute(Qt::WA_WState_Created));
+ ScrollWindowEx(q->internalWinId(), dx, dy, 0, 0, 0, 0, flags);
+ UpdateWindow(q->internalWinId());
+ }
+}
+
+void QWidgetPrivate::scroll_sys(int dx, int dy, const QRect &r)
+{
+ Q_Q(QWidget);
+
+ if (!paintOnScreen()) {
+ scrollRect(r, dx, dy);
+ } else {
+ RECT wr;
+ wr.top = r.top();
+ wr.left = r.left();
+ wr.bottom = r.bottom()+1;
+ wr.right = r.right()+1;
+
+ UINT flags = SW_INVALIDATE;
+ if (!q->testAttribute(Qt::WA_OpaquePaintEvent))
+ flags |= SW_ERASE;
+ Q_ASSERT(q->testAttribute(Qt::WA_WState_Created));
+ ScrollWindowEx(q->internalWinId(), dx, dy, &wr, &wr, 0, 0, flags);
+ UpdateWindow(q->internalWinId());
+ }
+}
+
+int QWidget::metric(PaintDeviceMetric m) const
+{
+ Q_D(const QWidget);
+ int val;
+ if (m == PdmWidth) {
+ val = data->crect.width();
+ } else if (m == PdmHeight) {
+ val = data->crect.height();
+ } else {
+ HDC gdc = GetDC(0);
+ switch (m) {
+ case PdmDpiX:
+ case PdmPhysicalDpiX:
+ if (d->extra && d->extra->customDpiX)
+ val = d->extra->customDpiX;
+ else if (d->parent)
+ val = static_cast<QWidget *>(d->parent)->metric(m);
+ else
+ val = GetDeviceCaps(gdc, LOGPIXELSX);
+ break;
+ case PdmDpiY:
+ case PdmPhysicalDpiY:
+ if (d->extra && d->extra->customDpiY)
+ val = d->extra->customDpiY;
+ else if (d->parent)
+ val = static_cast<QWidget *>(d->parent)->metric(m);
+ else
+ val = GetDeviceCaps(gdc, LOGPIXELSY);
+ break;
+ case PdmWidthMM:
+ val = data->crect.width()
+ * GetDeviceCaps(gdc, HORZSIZE)
+ / GetDeviceCaps(gdc, HORZRES);
+ break;
+ case PdmHeightMM:
+ val = data->crect.height()
+ * GetDeviceCaps(gdc, VERTSIZE)
+ / GetDeviceCaps(gdc, VERTRES);
+ break;
+ case PdmNumColors:
+ if (GetDeviceCaps(gdc, RASTERCAPS) & RC_PALETTE)
+ val = GetDeviceCaps(gdc, SIZEPALETTE);
+ else {
+ HDC hd = d->hd ? HDC(d->hd) : gdc;
+ int bpp = GetDeviceCaps(hd, BITSPIXEL);
+ if (bpp == 32)
+ val = INT_MAX; // ### this is bogus, it should be 2^24 colors for 32 bit as well
+ else if(bpp<=8)
+ val = GetDeviceCaps(hd, NUMCOLORS);
+ else
+ val = 1 << (bpp * GetDeviceCaps(hd, PLANES));
+ }
+ break;
+ case PdmDepth:
+ val = GetDeviceCaps(gdc, BITSPIXEL);
+ break;
+ default:
+ val = 0;
+ qWarning("QWidget::metric: Invalid metric command");
+ }
+ ReleaseDC(0, gdc);
+ }
+ return val;
+}
+
+void QWidgetPrivate::createSysExtra()
+{
+#ifndef QT_NO_DRAGANDDROP
+ extra->dropTarget = 0;
+#endif
+}
+
+#ifndef Q_WS_WINCE
+void QWidgetPrivate::deleteSysExtra()
+{
+}
+#endif //Q_WS_WINCE
+
+void QWidgetPrivate::createTLSysExtra()
+{
+ extra->topextra->hotkeyRegistered = 0;
+ extra->topextra->savedFlags = 0;
+ extra->topextra->winIconBig = 0;
+ extra->topextra->winIconSmall = 0;
+}
+
+void QWidgetPrivate::deleteTLSysExtra()
+{
+ if (extra->topextra->winIconSmall)
+ DestroyIcon(extra->topextra->winIconSmall);
+ if (extra->topextra->winIconBig)
+ DestroyIcon(extra->topextra->winIconBig);
+}
+
+void QWidgetPrivate::registerDropSite(bool on)
+{
+ Q_Q(QWidget);
+ if (!q->testAttribute(Qt::WA_WState_Created))
+ return;
+ // Enablement is defined by d->extra->dropTarget != 0.
+ if (on) {
+ // Turn on.
+ createExtra();
+#ifndef QT_NO_DRAGANDDROP
+ if (!q->internalWinId())
+ q->nativeParentWidget()->d_func()->createExtra();
+ QWExtra *extra = extraData();
+ if (!extra->dropTarget)
+ extra->dropTarget = registerOleDnd(q);
+#endif
+ } else {
+ // Turn off.
+ QWExtra *extra = extraData();
+#ifndef QT_NO_DRAGANDDROP
+ if (extra && extra->dropTarget) {
+ unregisterOleDnd(q, extra->dropTarget);
+ extra->dropTarget = 0;
+ }
+#endif
+ }
+}
+
+#ifndef QT_NO_DRAGANDDROP
+QOleDropTarget* QWidgetPrivate::registerOleDnd(QWidget *widget)
+{
+ QOleDropTarget *dropTarget = new QOleDropTarget(widget);
+ Q_ASSERT(widget->testAttribute(Qt::WA_WState_Created));
+ if (!widget->internalWinId()) {
+ QWidget *nativeParent = widget->nativeParentWidget();
+ Q_ASSERT(nativeParent);
+ QWExtra *nativeExtra = nativeParent->d_func()->extra;
+ Q_ASSERT(nativeExtra);
+ if (!nativeParent->acceptDrops())
+ nativeParent->setAcceptDrops(true);
+ if (!nativeExtra->oleDropWidgets.contains(widget))
+ nativeExtra->oleDropWidgets.append(widget);
+ if (!nativeExtra->dropTarget) {
+ nativeExtra->dropTarget = registerOleDnd(nativeParent);
+ Q_ASSERT(nativeExtra->dropTarget);
+#ifndef Q_OS_WINCE
+ CoLockObjectExternal(nativeExtra->dropTarget, false, true);
+#endif
+ RegisterDragDrop(nativeParent->internalWinId(), nativeExtra->dropTarget);
+ }
+ } else {
+ RegisterDragDrop(widget->internalWinId(), dropTarget);
+#ifndef Q_OS_WINCE
+ CoLockObjectExternal(dropTarget, true, true);
+#endif
+ }
+ return dropTarget;
+}
+
+void QWidgetPrivate::unregisterOleDnd(QWidget *widget, QOleDropTarget *dropTarget)
+{
+ dropTarget->releaseQt();
+ dropTarget->Release();
+ Q_ASSERT(widget->testAttribute(Qt::WA_WState_Created));
+ if (!widget->internalWinId()) {
+ QWidget *nativeParent = widget->nativeParentWidget();
+ Q_ASSERT(nativeParent);
+ QWExtra *nativeExtra = nativeParent->d_func()->extra;
+ Q_ASSERT(nativeExtra);
+ nativeExtra->oleDropWidgets.removeAll(widget);
+ nativeExtra->oleDropWidgets.removeAll(static_cast<QWidget *>(0));
+ if (nativeExtra->oleDropWidgets.isEmpty() && nativeExtra->dropTarget
+ && !nativeParent->testAttribute(Qt::WA_DropSiteRegistered)) {
+#ifndef Q_OS_WINCE
+ CoLockObjectExternal(nativeExtra->dropTarget, false, true);
+#endif
+ RevokeDragDrop(nativeParent->internalWinId());
+ nativeExtra->dropTarget = 0;
+ }
+ } else {
+#ifndef Q_OS_WINCE
+ CoLockObjectExternal(dropTarget, false, true);
+#endif
+ RevokeDragDrop(widget->internalWinId());
+ }
+}
+
+#endif //QT_NO_DRAGANDDROP
+
+// from qregion_win.cpp
+extern HRGN qt_tryCreateRegion(QRegion::RegionType type, int left, int top, int right, int bottom);
+void QWidgetPrivate::setMask_sys(const QRegion &region)
+{
+ Q_Q(QWidget);
+ if (!q->internalWinId())
+ return;
+
+ if (region.isEmpty()) {
+ SetWindowRgn(q->internalWinId(), 0, true);
+ return;
+ }
+
+ // Since SetWindowRegion takes ownership, and we need to translate,
+ // we take a copy.
+ HRGN wr = qt_tryCreateRegion(QRegion::Rectangle, 0,0,0,0);
+ CombineRgn(wr, region.handle(), 0, RGN_COPY);
+
+ QPoint offset = (q->isWindow()
+ ? frameStrut().topLeft()
+ : QPoint(0, 0));
+ OffsetRgn(wr, offset.x(), offset.y());
+
+ Q_ASSERT(q->testAttribute(Qt::WA_WState_Created));
+ if (!SetWindowRgn(data.winid, wr, true))
+ DeleteObject(wr);
+}
+
+void QWidgetPrivate::updateFrameStrut()
+{
+ Q_Q(QWidget);
+
+ if (!q->testAttribute(Qt::WA_WState_Created))
+ return;
+
+ if (!q->internalWinId()) {
+ data.fstrut_dirty = false;
+ return;
+ }
+
+ RECT rect = {0,0,0,0};
+
+ QTLWExtra *top = topData();
+ uint exstyle = GetWindowLong(q->internalWinId(), GWL_EXSTYLE);
+ uint style = GetWindowLong(q->internalWinId(), GWL_STYLE);
+#ifndef Q_WS_WINCE
+ if (AdjustWindowRectEx(&rect, style & ~(WS_OVERLAPPED), FALSE, exstyle)) {
+#else
+ if (AdjustWindowRectEx(&rect, style, FALSE, exstyle)) {
+#endif
+ top->frameStrut.setCoords(-rect.left, -rect.top, rect.right, rect.bottom);
+ data.fstrut_dirty = false;
+ }
+}
+
+#ifndef Q_WS_WINCE
+void QWidgetPrivate::setWindowOpacity_sys(qreal level)
+{
+ Q_Q(QWidget);
+
+ if (!isOpaque && ptrUpdateLayeredWindow && (data.window_flags & Qt::FramelessWindowHint)) {
+ if (GetWindowLong(q->internalWinId(), GWL_EXSTYLE) & Q_WS_EX_LAYERED) {
+ BLENDFUNCTION blend = {AC_SRC_OVER, 0, (int)(255.0 * level), AC_SRC_ALPHA};
+ ptrUpdateLayeredWindow(q->internalWinId(), NULL, NULL, NULL, NULL, NULL, 0, &blend, Q_ULW_ALPHA);
+ }
+ return;
+ }
+
+ static bool function_resolved = false;
+ if (!function_resolved) {
+ ptrSetLayeredWindowAttributes =
+ (PtrSetLayeredWindowAttributes) QSystemLibrary::resolve(QLatin1String("user32"),
+ "SetLayeredWindowAttributes");
+ function_resolved = true;
+ }
+
+ if (!ptrSetLayeredWindowAttributes)
+ return;
+
+ int wl = GetWindowLong(q->internalWinId(), GWL_EXSTYLE);
+
+ if (level != 1.0) {
+ if ((wl&Q_WS_EX_LAYERED) == 0)
+ SetWindowLong(q->internalWinId(), GWL_EXSTYLE, wl | Q_WS_EX_LAYERED);
+ } else if (wl&Q_WS_EX_LAYERED) {
+ SetWindowLong(q->internalWinId(), GWL_EXSTYLE, wl & ~Q_WS_EX_LAYERED);
+ }
+ ptrSetLayeredWindowAttributes(q->internalWinId(), 0, (int)(level * 255), Q_LWA_ALPHA);
+}
+#endif //Q_WS_WINCE
+
+// class QGlobalRasterPaintEngine: public QRasterPaintEngine
+// {
+// public:
+// inline QGlobalRasterPaintEngine() : QRasterPaintEngine() { setFlushOnEnd(false); }
+// };
+// Q_GLOBAL_STATIC(QGlobalRasterPaintEngine, globalRasterPaintEngine)
+
+
+#ifndef QT_NO_DIRECTDRAW
+static uchar *qt_primary_surface_bits;
+static int qt_primary_surface_stride;
+static QImage::Format qt_primary_surface_format;
+
+void qt_win_initialize_directdraw()
+{
+ HRESULT res;
+
+ // Some initialization...
+ if (!qt_ddraw_object) {
+ res = DirectDrawCreate(0, &qt_ddraw_object, 0);
+
+ if (res != DD_OK)
+ qWarning("DirectDrawCreate failed: %d", res);
+
+ qt_ddraw_object->SetCooperativeLevel(0, DDSCL_NORMAL);
+
+ DDSURFACEDESC surfaceDesc;
+ memset(&surfaceDesc, 0, sizeof(DDSURFACEDESC));
+
+ surfaceDesc.dwSize = sizeof(DDSURFACEDESC);
+ surfaceDesc.dwFlags = DDSD_CAPS;
+ surfaceDesc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
+
+ res = qt_ddraw_object->CreateSurface(&surfaceDesc, &qt_ddraw_primary, 0);
+ if (res != DD_OK)
+ qWarning("CreateSurface failed: %d", res);
+
+ memset(&surfaceDesc, 0, sizeof(DDSURFACEDESC));
+ surfaceDesc.dwSize = sizeof(DDSURFACEDESC);
+ res = qt_ddraw_primary->Lock(0, &surfaceDesc, DDLOCK_WAIT | DDLOCK_SURFACEMEMORYPTR, 0);
+ if (res != DD_OK)
+ qWarning("Locking surface failed: %d", res);
+
+ if (surfaceDesc.ddpfPixelFormat.dwFlags == DDPF_RGB) {
+ qt_primary_surface_bits = (uchar *) surfaceDesc.lpSurface;
+ qt_primary_surface_stride = surfaceDesc.lPitch;
+ qt_primary_surface_format = QImage::Format_RGB32;
+ } else {
+ qWarning("QWidget painting: unsupported device depth for onscreen painting...\n");
+ }
+
+ qt_ddraw_primary->Unlock(0);
+ }
+}
+
+class QOnScreenRasterPaintEngine : public QRasterPaintEngine
+{
+public:
+ // The image allocated here leaks... Fix if this code is ifdef'ed
+ // in
+ QOnScreenRasterPaintEngine()
+ : QRasterPaintEngine(new QImage(qt_primary_surface_bits,
+ QApplication::desktop()->width(),
+ QApplication::desktop()->height(),
+ qt_primary_surface_stride,
+ qt_primary_surface_format))
+ {
+ device = static_cast<QImage *>(d_func()->device);
+ }
+
+ bool begin(QPaintDevice *)
+ {
+ QRegion clip = systemClip();
+ originalSystemClip = clip;
+ clip.translate(widget->mapToGlobal(QPoint(0, 0)));
+ setSystemClip(clip);
+
+ QRect bounds = clip.boundingRect();
+ DDSURFACEDESC surface;
+ surface.dwSize = sizeof(DDSURFACEDESC);
+ HRESULT res = qt_ddraw_primary->Lock((RECT *) &bounds, &surface, DDLOCK_WAIT, 0);
+ if (res != DD_OK) {
+ qWarning("QWidget painting: locking onscreen bits failed: %d\n", res);
+ return false;
+ }
+
+ if (surface.lpSurface == qt_primary_surface_bits) {
+ qt_primary_surface_bits = (uchar *) surface.lpSurface;
+ device->data_ptr()->data = qt_primary_surface_bits;
+ }
+
+ return QRasterPaintEngine::begin(device);
+ }
+
+ bool end()
+ {
+ HRESULT res = qt_ddraw_primary->Unlock(0);
+ if (res != DD_OK)
+ qWarning("QWidget::paint, failed to unlock DirectDraw surface: %d", res);
+ bool ok = QRasterPaintEngine::end();
+ setSystemClip(originalSystemClip);
+ return ok;
+ }
+
+ QPoint coordinateOffset() const {
+ return -widget->mapToGlobal(QPoint(0, 0));
+ }
+
+ const QWidget *widget;
+ QImage *device;
+ QRegion originalSystemClip;
+};
+Q_GLOBAL_STATIC(QOnScreenRasterPaintEngine, onScreenPaintEngine)
+#else
+void qt_win_initialize_directdraw() { }
+#endif
+
+QPaintEngine *QWidget::paintEngine() const
+{
+#ifndef QT_NO_DIRECTDRAW
+ QOnScreenRasterPaintEngine *pe = onScreenPaintEngine();
+ pe->widget = this;
+ return pe;
+#endif
+
+ // We set this bit which is checked in setAttribute for
+ // Qt::WA_PaintOnScreen. We do this to allow these two scenarios:
+ //
+ // 1. Users accidentally set Qt::WA_PaintOnScreen on X and port to
+ // windows which would mean suddenly their widgets stop working.
+ //
+ // 2. Users set paint on screen and subclass paintEngine() to
+ // return 0, in which case we have a "hole" in the backingstore
+ // allowing use of GDI or DirectX directly.
+ //
+ // 1 is WRONG, but to minimize silent failures, we have set this
+ // bit to ignore the setAttribute call. 2. needs to be
+ // supported because its our only means of embeddeding native
+ // graphics stuff.
+ const_cast<QWidgetPrivate *>(d_func())->noPaintOnScreen = 1;
+
+ return 0;
+}
+
+QWindowSurface *QWidgetPrivate::createDefaultWindowSurface_sys()
+{
+ Q_Q(QWidget);
+ return new QRasterWindowSurface(q);
+}
+
+void QWidgetPrivate::setModal_sys()
+{
+}
+
+void QWidgetPrivate::registerTouchWindow()
+{
+ Q_Q(QWidget);
+
+ // enable WM_TOUCH* messages on our window
+ if (q->testAttribute(Qt::WA_WState_Created)
+ && QApplicationPrivate::RegisterTouchWindow
+ && q->windowType() != Qt::Desktop)
+ QApplicationPrivate::RegisterTouchWindow(q->effectiveWinId(), 0);
+}
+
+void QWidgetPrivate::winSetupGestures()
+{
+#if !defined(QT_NO_GESTURES) && !defined(QT_NO_NATIVE_GESTURES)
+ Q_Q(QWidget);
+ if (!q || !q->isVisible() || !nativeGesturePanEnabled)
+ return;
+
+ if (!QApplicationPrivate::HasTouchSupport)
+ return;
+ QApplicationPrivate *qAppPriv = QApplicationPrivate::instance();
+ if (!qAppPriv->SetGestureConfig)
+ return;
+ WId winid = q->internalWinId();
+
+ bool needh = false;
+ bool needv = false;
+ bool singleFingerPanEnabled = false;
+
+#ifndef QT_NO_SCROLLAREA
+ if (QAbstractScrollArea *asa = qobject_cast<QAbstractScrollArea*>(q->parent())) {
+ QScrollBar *hbar = asa->horizontalScrollBar();
+ QScrollBar *vbar = asa->verticalScrollBar();
+ Qt::ScrollBarPolicy hbarpolicy = asa->horizontalScrollBarPolicy();
+ Qt::ScrollBarPolicy vbarpolicy = asa->verticalScrollBarPolicy();
+ needh = (hbarpolicy == Qt::ScrollBarAlwaysOn ||
+ (hbarpolicy == Qt::ScrollBarAsNeeded && hbar->minimum() < hbar->maximum()));
+ needv = (vbarpolicy == Qt::ScrollBarAlwaysOn ||
+ (vbarpolicy == Qt::ScrollBarAsNeeded && vbar->minimum() < vbar->maximum()));
+ singleFingerPanEnabled = asa->d_func()->singleFingerPanEnabled;
+ if (!winid) {
+ winid = q->winId(); // enforces the native winid on the viewport
+ }
+ }
+#endif //QT_NO_SCROLLAREA
+ if (winid) {
+ GESTURECONFIG gc[1];
+ memset(gc, 0, sizeof(gc));
+ gc[0].dwID = GID_PAN;
+ if (nativeGesturePanEnabled) {
+ gc[0].dwWant = GC_PAN;
+ if (needv && singleFingerPanEnabled)
+ gc[0].dwWant |= GC_PAN_WITH_SINGLE_FINGER_VERTICALLY;
+ else
+ gc[0].dwBlock |= GC_PAN_WITH_SINGLE_FINGER_VERTICALLY;
+ if (needh && singleFingerPanEnabled)
+ gc[0].dwWant |= GC_PAN_WITH_SINGLE_FINGER_HORIZONTALLY;
+ else
+ gc[0].dwBlock |= GC_PAN_WITH_SINGLE_FINGER_HORIZONTALLY;
+ } else {
+ gc[0].dwBlock = GC_PAN;
+ }
+
+ qAppPriv->SetGestureConfig(winid, 0, sizeof(gc)/sizeof(gc[0]), gc, sizeof(gc[0]));
+ }
+#endif
+}
+
+QT_END_NAMESPACE
+
+#ifdef Q_WS_WINCE
+# include "qwidget_wince.cpp"
+#endif
diff --git a/src/gui/platforms/win/qwidget_wince.cpp b/src/gui/platforms/win/qwidget_wince.cpp
new file mode 100644
index 0000000000..7676182ef0
--- /dev/null
+++ b/src/gui/platforms/win/qwidget_wince.cpp
@@ -0,0 +1,675 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifdef Q_WS_WINCE
+
+#include "qguifunctions_wince.h"
+
+QT_BEGIN_NAMESPACE
+
+const QString qt_reg_winclass(QWidget *w); // defined in qapplication_win.cpp
+extern "C" LRESULT QT_WIN_CALLBACK QtWndProc(HWND, UINT, WPARAM, LPARAM);
+
+//#define TABLET_DEBUG
+#define PACKETDATA (PK_X | PK_Y | PK_BUTTONS | PK_NORMAL_PRESSURE | PK_TANGENT_PRESSURE \
+ | PK_ORIENTATION | PK_CURSOR | PK_Z)
+#define PACKETMODE 0
+
+typedef HCTX (API *PtrWTOpen)(HWND, LPLOGCONTEXT, BOOL);
+typedef BOOL (API *PtrWTClose)(HCTX);
+typedef UINT (API *PtrWTInfo)(UINT, UINT, LPVOID);
+typedef BOOL (API *PtrWTEnable)(HCTX, BOOL);
+typedef BOOL (API *PtrWTOverlap)(HCTX, BOOL);
+typedef int (API *PtrWTPacketsGet)(HCTX, int, LPVOID);
+typedef BOOL (API *PtrWTGet)(HCTX, LPLOGCONTEXT);
+typedef int (API *PtrWTQueueSizeGet)(HCTX);
+typedef BOOL (API *PtrWTQueueSizeSet)(HCTX, int);
+
+#ifndef QT_NO_TABLETEVENT
+static void qt_tablet_init_wce();
+static void qt_tablet_cleanup_wce();
+
+static void qt_tablet_init_wce() {
+ static bool firstTime = true;
+ if (!firstTime)
+ return;
+ firstTime = false;
+ qt_tablet_widget = new QWidget(0);
+ qt_tablet_widget->createWinId();
+ qt_tablet_widget->setObjectName(QLatin1String("Qt internal tablet widget"));
+ LOGCONTEXT lcMine;
+ qAddPostRoutine(qt_tablet_cleanup_wce);
+ struct tagAXIS tpOri[3];
+ if (ptrWTInfo && ptrWTOpen && ptrWTQueueSizeGet && ptrWTQueueSizeSet) {
+ // make sure we have WinTab
+ if (!ptrWTInfo(0, 0, NULL)) {
+#ifdef TABLET_DEBUG
+ qWarning("QWidget: Wintab services not available");
+#endif
+ return;
+ }
+
+ // some tablets don't support tilt, check if it is possible,
+ qt_tablet_tilt_support = ptrWTInfo(WTI_DEVICES, DVC_ORIENTATION, &tpOri);
+ if (qt_tablet_tilt_support) {
+ // check for azimuth and altitude
+ qt_tablet_tilt_support = tpOri[0].axResolution && tpOri[1].axResolution;
+ }
+ // build our context from the default context
+ ptrWTInfo(WTI_DEFSYSCTX, 0, &lcMine);
+ // Go for the raw coordinates, the tablet event will return good stuff
+ lcMine.lcOptions |= CXO_MESSAGES | CXO_CSRMESSAGES;
+ lcMine.lcPktData = PACKETDATA;
+ lcMine.lcPktMode = PACKETMODE;
+ lcMine.lcMoveMask = PACKETDATA;
+ lcMine.lcOutOrgX = 0;
+ lcMine.lcOutExtX = lcMine.lcInExtX;
+ lcMine.lcOutOrgY = 0;
+ lcMine.lcOutExtY = -lcMine.lcInExtY;
+ qt_tablet_context = ptrWTOpen(qt_tablet_widget->winId(), &lcMine, true);
+#ifdef TABLET_DEBUG
+ qDebug("Tablet is %p", qt_tablet_context);
+#endif
+ if (!qt_tablet_context) {
+#ifdef TABLET_DEBUG
+ qWarning("QWidget: Failed to open the tablet");
+#endif
+ return;
+ }
+ // Set the size of the Packet Queue to the correct size...
+ int currSize = ptrWTQueueSizeGet(qt_tablet_context);
+ if (!ptrWTQueueSizeSet(qt_tablet_context, QT_TABLET_NPACKETQSIZE)) {
+ // Ideally one might want to use a smaller
+ // multiple, but for now, since we managed to destroy
+ // the existing Q with the previous call, set it back
+ // to the other size, which should work. If not,
+ // there will be trouble.
+ if (!ptrWTQueueSizeSet(qt_tablet_context, currSize)) {
+ Q_ASSERT_X(0, "Qt::Internal", "There is no packet queue for"
+ " the tablet. The tablet will not work");
+ }
+ }
+ }
+}
+
+static void qt_tablet_cleanup_wce() {
+ if (ptrWTClose)
+ ptrWTClose(qt_tablet_context);
+ delete qt_tablet_widget;
+ qt_tablet_widget = 0;
+}
+#endif // QT_NO_TABLETEVENT
+
+
+// The internal qWinRequestConfig, defined in qapplication_win.cpp, stores move,
+// resize and setGeometry requests for a widget that is already
+// processing a config event. The purpose is to avoid recursion.
+//
+void qWinRequestConfig(WId, int, int, int, int, int);
+
+void QWidgetPrivate::create_sys(WId window, bool initializeWindow, bool destroyOldWindow) {
+ Q_Q(QWidget);
+ static int sw = -1, sh = -1;
+
+ Qt::WindowType type = q->windowType();
+ Qt::WindowFlags flags = data.window_flags;
+
+ bool topLevel = (flags & Qt::Window);
+ bool popup = (type == Qt::Popup);
+ bool dialog = (type == Qt::Dialog
+ || type == Qt::Sheet
+ || (flags & Qt::MSWindowsFixedSizeDialogHint));
+ bool desktop = (type == Qt::Desktop);
+ bool tool = (type == Qt::Tool || type == Qt::Drawer);
+
+ HINSTANCE appinst = qWinAppInst();
+ HWND parentw, destroyw = 0;
+ WId id;
+
+ QString windowClassName = qt_reg_winclass(q);
+
+ if (!window) // always initialize
+ initializeWindow = true;
+
+ if (popup)
+ flags |= Qt::WindowStaysOnTopHint; // a popup stays on top
+
+ if (flags & (Qt::WindowSystemMenuHint | Qt::WindowMinMaxButtonsHint | Qt::WindowContextHelpButtonHint)) {
+ flags |= Qt::WindowSystemMenuHint;
+ flags |= Qt::WindowTitleHint;
+ flags &= ~Qt::FramelessWindowHint;
+ }
+
+ if (sw < 0) { // get the (primary) screen size
+ sw = GetSystemMetrics(SM_CXSCREEN);
+ sh = GetSystemMetrics(SM_CYSCREEN);
+ }
+
+ if (desktop) { // desktop widget
+ popup = false; // force this flags off
+ data.crect.setRect(0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN));
+ }
+
+ parentw = q->parentWidget() ? q->parentWidget()->effectiveWinId() : 0;
+
+ QString title;
+ int style = WS_CHILD;
+ int exsty = WS_EX_NOPARENTNOTIFY;
+
+ if (topLevel) {
+ if (!(flags & Qt::FramelessWindowHint) && !tool && !q->testAttribute(Qt::WA_DontShowOnScreen))
+ style = (WS_OVERLAPPED) | WS_SYSMENU;
+ else
+ style = WS_POPUP;
+ if ((type == Qt::ToolTip) || (type == Qt::SplashScreen)) {
+ style = WS_POPUP;
+ exsty |= WS_EX_NOANIMATION;
+ } else {
+ if (flags & Qt::WindowTitleHint)
+ style |= WS_CAPTION;
+ if (flags & Qt::WindowSystemMenuHint)
+ style |= WS_SYSMENU;
+ if (flags & Qt::WindowContextHelpButtonHint)
+ exsty |= WS_EX_CONTEXTHELP;
+#ifndef Q_WS_WINCE_WM
+ if (flags & Qt::WindowMinimizeButtonHint)
+ style |= WS_MINIMIZEBOX;
+ if (shouldShowMaximizeButton())
+ style |= WS_MAXIMIZEBOX;
+#endif
+ if (tool)
+ exsty |= WS_EX_TOOLWINDOW;
+ }
+ }
+ if (dialog) {
+ style = WS_BORDER | WS_CAPTION;
+ if (flags & Qt::WindowOkButtonHint)
+ exsty |= WS_EX_CAPTIONOKBTN;
+ if (flags & Qt::WindowCancelButtonHint || flags & Qt::WA_DeleteOnClose)
+ style |= WS_SYSMENU;
+ if (flags & Qt::WindowContextHelpButtonHint)
+ exsty |= WS_EX_CONTEXTHELP;
+ }
+ if (popup) {
+ style = WS_POPUP;
+ exsty |= WS_EX_NOANIMATION;
+ }
+
+ if (flags & Qt::WindowTitleHint) {
+ title = q->isWindow() ? qAppName() : q->objectName();
+ }
+
+ // The Qt::WA_WState_Created flag is checked by translateConfigEvent() in
+ // qapplication_win.cpp. We switch it off temporarily to avoid move
+ // and resize events during creationt
+ q->setAttribute(Qt::WA_WState_Created, false);
+
+ if (window) { // override the old window
+ if (destroyOldWindow)
+ destroyw = data.winid;
+ id = window;
+ setWinId(window);
+ LONG res = SetWindowLong(window, GWL_STYLE, style);
+ if (!res)
+ qErrnoWarning("QWidget::create: Failed to set window style");
+
+ res = SetWindowLong( window, GWL_WNDPROC, (LONG)QtWndProc );
+
+ if (!res)
+ qErrnoWarning("QWidget::create: Failed to set window procedure");
+ } else if (desktop) { // desktop widget
+ id = GetDesktopWindow();
+ if (!id) { //Create a dummy desktop
+ RECT r;
+ SystemParametersInfo(SPI_GETWORKAREA, 0, &r, 0);
+ id = CreateWindow(reinterpret_cast<const wchar_t *>(windowClassName.utf16()),
+ reinterpret_cast<const wchar_t *>(title.utf16()), style,
+ r.left, r.top, r.right - r.left, r.bottom - r.top,
+ 0, 0, appinst, 0);
+ }
+ setWinId(id);
+ } else if (topLevel) { // create top-level widget
+ const bool wasMoved = q->testAttribute(Qt::WA_Moved);
+
+ int x, y;
+ if (qt_wince_is_mobile()) {
+ x = wasMoved ? data.crect.left() : CW_USEDEFAULT;
+ y = wasMoved ? data.crect.top() : CW_USEDEFAULT;
+ } else {
+ x = wasMoved ? data.crect.left() : 100;
+ y = wasMoved ? data.crect.top() : 100;
+ }
+
+ int w = CW_USEDEFAULT;
+ int h = CW_USEDEFAULT;
+
+ // Adjust for framestrut when needed
+ RECT rect = {0,0,0,0};
+ if (AdjustWindowRectEx(&rect, style, FALSE, exsty)) {
+ QTLWExtra *td = maybeTopData();
+ if (wasMoved && (td && !td->posFromMove)) {
+ x = data.crect.x() + rect.left;
+ y = data.crect.y() + rect.top;
+ }
+
+ if (q->testAttribute(Qt::WA_Resized)) {
+ w = data.crect.width() + (rect.right - rect.left);
+ h = data.crect.height() + (rect.bottom - rect.top);
+ }
+ }
+
+ id = CreateWindowEx(exsty, reinterpret_cast<const wchar_t *>(windowClassName.utf16()),
+ reinterpret_cast<const wchar_t *>(title.utf16()), style,
+ x, y, w, h,
+ 0, 0, appinst, 0);
+
+ if (!id)
+ qErrnoWarning("QWidget::create: Failed to create window");
+ setWinId(id);
+ if ((flags & Qt::WindowStaysOnTopHint) || (type == Qt::ToolTip))
+ SetWindowPos(id, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);
+ } else if (q->testAttribute(Qt::WA_NativeWindow) || paintOnScreen()) { // create child widget
+ id = CreateWindowEx(exsty, (wchar_t*)windowClassName.utf16(), (wchar_t*)title.utf16(), style,
+ data.crect.left(), data.crect.top(), data.crect.width(), data.crect.height(),
+ parentw, NULL, appinst, NULL);
+ if (!id)
+ qErrnoWarning("QWidget::create: Failed to create window");
+ SetWindowPos(id, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
+ setWinId(id);
+ }
+
+ if (desktop) {
+ q->setAttribute(Qt::WA_WState_Visible);
+ } else if (topLevel && !q->testAttribute(Qt::WA_DontShowOnScreen)) {
+ RECT cr;
+ GetClientRect(id, &cr);
+ // one cannot trust cr.left and cr.top, use a correction POINT instead
+ POINT pt;
+ pt.x = 0;
+ pt.y = 0;
+ if (!q->testAttribute(Qt::WA_DontShowOnScreen) || q->testAttribute(Qt::WA_Moved))
+ ClientToScreen(id, &pt);
+ data.crect = QRect(QPoint(pt.x, pt.y),
+ QPoint(pt.x + cr.right - 1, pt.y + cr.bottom - 1));
+
+ if (data.fstrut_dirty) {
+ // be nice to activeqt
+ updateFrameStrut();
+ }
+ }
+
+ q->setAttribute(Qt::WA_WState_Created); // accept move/resize events
+ hd = 0; // no display context
+
+ if (window) { // got window from outside
+ if (IsWindowVisible(window))
+ q->setAttribute(Qt::WA_WState_Visible);
+ else
+ q->setAttribute(Qt::WA_WState_Visible, false);
+ }
+
+ if (extra && !extra->mask.isEmpty())
+ setMask_sys(extra->mask);
+
+#if defined(QT_NON_COMMERCIAL)
+ QT_NC_WIDGET_CREATE
+#endif
+
+ if (q->hasFocus() && q->testAttribute(Qt::WA_InputMethodEnabled))
+ q->inputContext()->setFocusWidget(q);
+
+ if (destroyw) {
+ DestroyWindow(destroyw);
+ }
+
+#ifndef QT_NO_TABLETEVENT
+ if (q != qt_tablet_widget && QWidgetPrivate::mapper)
+ qt_tablet_init_wce();
+#endif // QT_NO_TABLETEVENT
+
+ if (q->testAttribute(Qt::WA_DropSiteRegistered))
+ registerDropSite(true);
+
+ if (maybeTopData() && maybeTopData()->opacity != 255)
+ q->setWindowOpacity(maybeTopData()->opacity/255.);
+
+ if (!topLevel && q->testAttribute(Qt::WA_NativeWindow) && q->testAttribute(Qt::WA_Mapped)) {
+ Q_ASSERT(q->internalWinId());
+ ShowWindow(q->internalWinId(), SW_SHOW);
+ }
+}
+
+/*
+ \internal
+ Platform-specific part of QWidget::show().
+*/
+void QWidgetPrivate::show_sys() {
+ Q_Q(QWidget);
+#if defined(QT_NON_COMMERCIAL)
+ QT_NC_SHOW_WINDOW
+#endif
+ if (q->testAttribute(Qt::WA_OutsideWSRange))
+ return;
+
+ q->setAttribute(Qt::WA_Mapped);
+
+ Q_ASSERT(q->testAttribute(Qt::WA_WState_Created));
+
+ if (q->testAttribute(Qt::WA_DontShowOnScreen)) {
+ invalidateBuffer(q->rect());
+ return;
+ }
+
+
+ int sm = SW_SHOW;
+ bool fakedMaximize = false;
+ if (q->isWindow()) {
+#ifndef Q_WS_WINCE_WM
+ if (q->isMinimized()) {
+ sm = SW_SHOWMINIMIZED;
+ } else if (q->isMaximized()) {
+ sm = SW_SHOWMAXIMIZED;
+ // Windows will not behave correctly when we try to maximize a window which does not
+ // have minimize nor maximize buttons in the window frame. Windows would then ignore
+ // non-available geometry, and rather maximize the widget to the full screen, minus the
+ // window frame (caption). So, we do a trick here, by adding a maximize button before
+ // maximizing the widget, and then remove the maximize button afterwards.
+ Qt::WindowFlags &flags = data.window_flags;
+ if (flags & Qt::WindowTitleHint &&
+ !(flags & (Qt::WindowMinMaxButtonsHint | Qt::FramelessWindowHint))) {
+ fakedMaximize = TRUE;
+ int style = GetWindowLong(q->internalWinId(), GWL_STYLE);
+ SetWindowLong(q->internalWinId(), GWL_STYLE, style | WS_MAXIMIZEBOX);
+ }
+ } else
+#else
+ // Imitate minimizing on Windows mobile by hiding the widget.
+ if (q->isMinimized())
+ sm = SW_HIDE;
+#endif
+ if (q->isHidden()) {
+ sm = SW_HIDE;
+ }
+ }
+ if (q->testAttribute(Qt::WA_ShowWithoutActivating)
+ || (q->windowType() == Qt::Popup)
+ || (q->windowType() == Qt::ToolTip)
+ || (q->windowType() == Qt::Tool)) {
+ sm = SW_SHOWNOACTIVATE;
+ }
+
+ ShowWindow(q->internalWinId(), sm);
+
+ if (q->isMaximized() && q->isWindow())
+ qt_wince_maximize(q);
+
+#ifndef Q_WS_WINCE_WM
+ if (!qt_wince_is_mobile() && q->isFullScreen()) {
+ HWND handle = FindWindow(L"HHTaskBar", L"");
+ if (handle) {
+ ShowWindow(handle, SW_HIDE);
+ EnableWindow(handle, false);
+ }
+ }
+
+ if (fakedMaximize) {
+ int style = GetWindowLong(q->internalWinId(), GWL_STYLE);
+ SetWindowLong(q->internalWinId(), GWL_STYLE, style & ~WS_MAXIMIZEBOX);
+ SetWindowPos(q->internalWinId(), 0, 0, 0, 0, 0,
+ SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOOWNERZORDER
+ | SWP_FRAMECHANGED);
+ }
+#else
+ Q_UNUSED(fakedMaximize);
+#endif
+
+ if (q->isWindow() && sm == SW_SHOW)
+ SetForegroundWindow(q->internalWinId());
+
+ invalidateBuffer(q->rect());
+}
+
+void QWidget::setWindowState(Qt::WindowStates newstate)
+{
+ Q_D(QWidget);
+ Qt::WindowStates oldstate = windowState();
+ if (oldstate == newstate)
+ return;
+
+ int max = SW_SHOWNORMAL;
+ int normal = SW_SHOWNOACTIVATE;
+
+ if ((oldstate & Qt::WindowMinimized) && !(newstate & Qt::WindowMinimized))
+ newstate |= Qt::WindowActive;
+ if (newstate & Qt::WindowActive)
+ normal = SW_SHOWNORMAL;
+ if (isWindow()) {
+ createWinId();
+ Q_ASSERT(testAttribute(Qt::WA_WState_Created));
+ // Ensure the initial size is valid, since we store it as normalGeometry below.
+ if ((!testAttribute(Qt::WA_Resized) && !isVisible()))
+ adjustSize();
+ if (!d->topData()->normalGeometry.isValid()) {
+ if (newstate & Qt::WindowMaximized && !(oldstate & Qt::WindowFullScreen))
+ d->topData()->normalGeometry = geometry();
+ if (newstate & Qt::WindowMinimized && !(oldstate & Qt::WindowFullScreen))
+ d->topData()->normalGeometry = geometry();
+ }
+ if ((oldstate & Qt::WindowMaximized) != (newstate & Qt::WindowMaximized)) {
+ if (!(newstate & Qt::WindowMaximized)) {
+ int style = GetWindowLong(internalWinId(), GWL_STYLE) | WS_BORDER | WS_POPUP | WS_CAPTION;
+ SetWindowLong(internalWinId(), GWL_STYLE, style);
+ SetWindowLong(internalWinId(), GWL_EXSTYLE, GetWindowLong (internalWinId(), GWL_EXSTYLE) & ~ WS_EX_NODRAG);
+ qt_wince_unmaximize(this);
+ }
+ if (isVisible() && newstate & Qt::WindowMaximized)
+ qt_wince_maximize(this);
+ if (isVisible() && !(newstate & Qt::WindowMinimized)) {
+ ShowWindow(internalWinId(), (newstate & Qt::WindowMaximized) ? max : normal);
+ if (!(newstate & Qt::WindowFullScreen)) {
+ QRect r = d->topData()->normalGeometry;
+ if (!(newstate & Qt::WindowMaximized) && r.width() >= 0) {
+ if (pos() != r.topLeft() || size() !=r.size()) {
+ d->topData()->normalGeometry = QRect(0,0,-1,-1);
+ setGeometry(r);
+ }
+ }
+ } else {
+ d->updateFrameStrut();
+ }
+ }
+ }
+ if ((oldstate & Qt::WindowFullScreen) != (newstate & Qt::WindowFullScreen)) {
+ if (newstate & Qt::WindowFullScreen) {
+ if (d->topData()->normalGeometry.width() < 0 && !(oldstate & Qt::WindowMaximized))
+ d->topData()->normalGeometry = geometry();
+ d->topData()->savedFlags = (Qt::WindowFlags)GetWindowLong(internalWinId(), GWL_STYLE);
+ UINT style = WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_POPUP;
+ if (isVisible())
+ style |= WS_VISIBLE;
+ SetWindowLong(internalWinId(), GWL_STYLE, style);
+ QRect r = qApp->desktop()->screenGeometry(this);
+ UINT swpf = SWP_FRAMECHANGED;
+ if (newstate & Qt::WindowActive)
+ swpf |= SWP_NOACTIVATE;
+ qt_wince_full_screen(internalWinId(), true, swpf);
+ d->updateFrameStrut();
+ } else {
+ UINT style = d->topData()->savedFlags;
+ if (isVisible())
+ style |= WS_VISIBLE;
+ SetWindowLong(internalWinId(), GWL_STYLE, style);
+ UINT swpf = SWP_FRAMECHANGED | SWP_NOZORDER | SWP_NOSIZE | SWP_NOMOVE;
+ if (newstate & Qt::WindowActive)
+ swpf |= SWP_NOACTIVATE;
+ qt_wince_full_screen(internalWinId(), false, swpf);
+ d->updateFrameStrut();
+
+ // preserve maximized state
+ if (isVisible()) {
+ ShowWindow(internalWinId(), (newstate & Qt::WindowMaximized) ? max : normal);
+ if (newstate & Qt::WindowMaximized)
+ qt_wince_maximize(this);
+ }
+ if (!(newstate & Qt::WindowMaximized)) {
+ QRect r = d->topData()->normalGeometry;
+ d->topData()->normalGeometry = QRect(0,0,-1,-1);
+ if (r.isValid())
+ setGeometry(r);
+ }
+ }
+ }
+ if ((oldstate & Qt::WindowMinimized) != (newstate & Qt::WindowMinimized)) {
+ if (newstate & Qt::WindowMinimized)
+ qt_wince_minimize(internalWinId());
+ else if (newstate & Qt::WindowMaximized) {
+ ShowWindow(internalWinId(), max);
+ qt_wince_maximize(this);
+ } else {
+ ShowWindow(internalWinId(), normal);
+ }
+ }
+ }
+ data->window_state = newstate;
+ QWindowStateChangeEvent e(oldstate);
+ QApplication::sendEvent(this, &e);
+}
+
+void QWidgetPrivate::deleteSysExtra()
+{
+ Q_Q(QWidget);
+ if (!qt_wince_is_mobile() && q->isFullScreen()) {
+ HWND handle = FindWindow(L"HHTaskBar", L"");
+ if (handle) {
+ ShowWindow(handle, SW_SHOWNORMAL);
+ EnableWindow(handle, true);
+ }
+ }
+}
+
+void QWidgetPrivate::setWindowOpacity_sys(qreal level) {
+ Q_UNUSED(level);
+ return;
+}
+
+// The procedure does nothing, but is required for mousegrabbing to work
+LRESULT QT_WIN_CALLBACK qJournalRecordProc(int nCode, WPARAM wParam, LPARAM lParam) {
+ Q_UNUSED(nCode);
+ Q_UNUSED(wParam);
+ Q_UNUSED(lParam);
+ return 0;
+}
+
+void QWidget::grabMouse() {
+ if (!qt_nograb()) {
+ if (mouseGrb)
+ mouseGrb->releaseMouse();
+ Q_ASSERT(testAttribute(Qt::WA_WState_Created));
+ SetCapture(internalWinId());
+ mouseGrb = this;
+ }
+}
+
+#ifndef QT_NO_CURSOR
+void QWidget::grabMouse(const QCursor &cursor) {
+ if (!qt_nograb()) {
+ if (mouseGrb)
+ mouseGrb->releaseMouse();
+ Q_ASSERT(testAttribute(Qt::WA_WState_Created));
+ SetCapture(internalWinId());
+ mouseGrbCur = new QCursor(cursor);
+ SetCursor(mouseGrbCur->handle());
+ mouseGrb = this;
+ }
+}
+#endif
+
+void QWidget::releaseMouse() {
+ if (!qt_nograb() && mouseGrb == this) {
+ ReleaseCapture();
+ if (journalRec) {
+ journalRec = 0;
+ }
+ if (mouseGrbCur) {
+ delete mouseGrbCur;
+ mouseGrbCur = 0;
+ }
+ mouseGrb = 0;
+ }
+}
+
+void QWidget::show()
+{
+ Qt::WindowFlags flags = windowFlags() & 0xff;
+ int threshold = qApp->autoMaximizeThreshold();
+ if ((threshold < 0) || (windowState() & Qt::WindowFullScreen) || (windowState() & Qt::WindowMaximized)) {
+ setVisible(true);
+ return;
+ }
+ int height = sizeHint().height();
+ int screenHeight = (qreal(threshold) / 100.0f * qApp->desktop()->screenGeometry(this).height());
+ bool maximize = height > screenHeight;
+ if (!maximize) {
+ // If we do not maximize yet we check the widget and its child widgets whether they are
+ //vertically expanding. If one of the widgets is expanding we maximize.
+ QList<QWidget *> list = findChildren<QWidget *>();
+ bool expandingChild = sizePolicy().verticalPolicy () == QSizePolicy::Expanding;
+ for (int i = 0; (i < list.size()) && !expandingChild; ++i) {
+ expandingChild = list.at(i)->sizePolicy().verticalPolicy () == QSizePolicy::Expanding;
+ }
+ maximize = expandingChild;
+ }
+ if ((minimumSizeHint().height() > qApp->desktop()->screenGeometry(this).height()) || (minimumSizeHint().width() > qApp->desktop()->screenGeometry(this).width()))
+ maximize = false;
+
+ if ((flags == Qt::Window || flags == Qt::Dialog) && maximize) {
+ setWindowState((windowState() & ~(Qt::WindowMinimized | Qt::WindowFullScreen))
+ | Qt::WindowMaximized);
+ setVisible(true);
+ }
+ else {
+ setVisible(true);
+ }
+}
+
+QT_END_NAMESPACE
+
+#endif // Q_WS_WINCE
diff --git a/src/gui/platforms/win/qwindowdefs_win.h b/src/gui/platforms/win/qwindowdefs_win.h
new file mode 100644
index 0000000000..a4dd38410c
--- /dev/null
+++ b/src/gui/platforms/win/qwindowdefs_win.h
@@ -0,0 +1,132 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QWINDOWDEFS_WIN_H
+#define QWINDOWDEFS_WIN_H
+
+#include <QtCore/qglobal.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Gui)
+
+QT_END_NAMESPACE
+
+#if !defined(Q_NOWINSTRICT)
+#define Q_WINSTRICT
+#endif
+
+#if defined(Q_WINSTRICT)
+
+#if !defined(STRICT)
+#define STRICT
+#endif
+#undef NO_STRICT
+#define Q_DECLARE_HANDLE(name) struct name##__; typedef struct name##__ *name
+
+#else
+
+#if !defined(NO_STRICT)
+#define NO_STRICT
+#endif
+#undef STRICT
+#define Q_DECLARE_HANDLE(name) typedef HANDLE name
+
+#endif
+
+#ifndef HINSTANCE
+Q_DECLARE_HANDLE(HINSTANCE);
+#endif
+#ifndef HDC
+Q_DECLARE_HANDLE(HDC);
+#endif
+#ifndef HWND
+Q_DECLARE_HANDLE(HWND);
+#endif
+#ifndef HFONT
+Q_DECLARE_HANDLE(HFONT);
+#endif
+#ifndef HPEN
+Q_DECLARE_HANDLE(HPEN);
+#endif
+#ifndef HBRUSH
+Q_DECLARE_HANDLE(HBRUSH);
+#endif
+#ifndef HBITMAP
+Q_DECLARE_HANDLE(HBITMAP);
+#endif
+#ifndef HICON
+Q_DECLARE_HANDLE(HICON);
+#endif
+#ifndef HCURSOR
+typedef HICON HCURSOR;
+#endif
+#ifndef HPALETTE
+Q_DECLARE_HANDLE(HPALETTE);
+#endif
+#ifndef HRGN
+Q_DECLARE_HANDLE(HRGN);
+#endif
+#ifndef HMONITOR
+Q_DECLARE_HANDLE(HMONITOR);
+#endif
+#ifndef HRESULT
+typedef long HRESULT;
+#endif
+
+typedef struct tagMSG MSG;
+typedef HWND WId;
+
+
+QT_BEGIN_NAMESPACE
+
+Q_CORE_EXPORT HINSTANCE qWinAppInst();
+Q_CORE_EXPORT HINSTANCE qWinAppPrevInst();
+Q_CORE_EXPORT int qWinAppCmdShow();
+Q_GUI_EXPORT HDC qt_win_display_dc();
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QWINDOWDEFS_WIN_H
diff --git a/src/gui/platforms/win/qwinnativepangesturerecognizer_win.cpp b/src/gui/platforms/win/qwinnativepangesturerecognizer_win.cpp
new file mode 100644
index 0000000000..0d13bafc0c
--- /dev/null
+++ b/src/gui/platforms/win/qwinnativepangesturerecognizer_win.cpp
@@ -0,0 +1,133 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "private/qwinnativepangesturerecognizer_win_p.h"
+
+#include "qevent.h"
+#include "qgraphicsitem.h"
+#include "qgesture.h"
+
+#include "private/qgesture_p.h"
+#include "private/qevent_p.h"
+#include "private/qapplication_p.h"
+#include "private/qwidget_p.h"
+
+#ifndef QT_NO_GESTURES
+
+QT_BEGIN_NAMESPACE
+
+#if !defined(QT_NO_NATIVE_GESTURES)
+
+QWinNativePanGestureRecognizer::QWinNativePanGestureRecognizer()
+{
+}
+
+QGesture *QWinNativePanGestureRecognizer::create(QObject *target)
+{
+ if (!target)
+ return new QPanGesture; // a special case
+ if (!target->isWidgetType())
+ return 0;
+ if (qobject_cast<QGraphicsObject *>(target))
+ return 0;
+
+ QWidget *q = static_cast<QWidget *>(target);
+ QWidgetPrivate *d = q->d_func();
+ d->nativeGesturePanEnabled = true;
+ d->winSetupGestures();
+
+ return new QPanGesture;
+}
+
+QGestureRecognizer::Result QWinNativePanGestureRecognizer::recognize(QGesture *state,
+ QObject *,
+ QEvent *event)
+{
+ QPanGesture *q = static_cast<QPanGesture*>(state);
+ QPanGesturePrivate *d = q->d_func();
+
+ QGestureRecognizer::Result result = QGestureRecognizer::Ignore;
+ if (event->type() == QEvent::NativeGesture) {
+ QNativeGestureEvent *ev = static_cast<QNativeGestureEvent*>(event);
+ switch(ev->gestureType) {
+ case QNativeGestureEvent::GestureBegin:
+ break;
+ case QNativeGestureEvent::Pan:
+ result = QGestureRecognizer::TriggerGesture;
+ event->accept();
+ break;
+ case QNativeGestureEvent::GestureEnd:
+ if (q->state() == Qt::NoGesture)
+ return QGestureRecognizer::Ignore; // some other gesture has ended
+ result = QGestureRecognizer::FinishGesture;
+ break;
+ default:
+ return QGestureRecognizer::Ignore;
+ }
+ if (q->state() == Qt::NoGesture) {
+ d->lastOffset = d->offset = QPointF();
+ d->startPosition = ev->position;
+ } else {
+ d->lastOffset = d->offset;
+ d->offset = QPointF(ev->position.x() - d->startPosition.x(),
+ ev->position.y() - d->startPosition.y());
+ }
+ }
+ return result;
+}
+
+void QWinNativePanGestureRecognizer::reset(QGesture *state)
+{
+ QPanGesture *pan = static_cast<QPanGesture*>(state);
+ QPanGesturePrivate *d = pan->d_func();
+
+ d->lastOffset = d->offset = QPointF();
+ d->startPosition = QPoint();
+ d->acceleration = 0;
+
+ QGestureRecognizer::reset(state);
+}
+
+#endif // QT_NO_NATIVE_GESTURES
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_GESTURES
diff --git a/src/gui/platforms/win/qwinnativepangesturerecognizer_win_p.h b/src/gui/platforms/win/qwinnativepangesturerecognizer_win_p.h
new file mode 100644
index 0000000000..6d23e41ce3
--- /dev/null
+++ b/src/gui/platforms/win/qwinnativepangesturerecognizer_win_p.h
@@ -0,0 +1,80 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QWINNATIVEPANGESTURERECOGNIZER_WIN_P_H
+#define QWINNATIVEPANGESTURERECOGNIZER_WIN_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of other Qt classes. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QGestureRecognizer>
+
+#ifndef QT_NO_GESTURES
+
+QT_BEGIN_NAMESPACE
+
+#if !defined(QT_NO_NATIVE_GESTURES)
+
+class QWinNativePanGestureRecognizer : public QGestureRecognizer
+{
+public:
+ QWinNativePanGestureRecognizer();
+
+ QGesture *create(QObject *target);
+ QGestureRecognizer::Result recognize(QGesture *state, QObject *watched, QEvent *event);
+ void reset(QGesture *state);
+};
+
+#endif // QT_NO_NATIVE_GESTURES
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_GESTURES
+
+#endif // QWINNATIVEPANGESTURERECOGNIZER_WIN_P_H