diff options
Diffstat (limited to 'src/gui')
186 files changed, 5370 insertions, 2196 deletions
diff --git a/src/gui/dialogs/dialogs.pri b/src/gui/dialogs/dialogs.pri index 63f64a2..4e1b9a7 100644 --- a/src/gui/dialogs/dialogs.pri +++ b/src/gui/dialogs/dialogs.pri @@ -50,7 +50,8 @@ HEADERS += \ } win32 { - HEADERS += dialogs/qwizard_win_p.h + HEADERS += dialogs/qwizard_win_p.h \ + dialogs/qfiledialog_win_p.h SOURCES += dialogs/qdialogsbinarycompat_win.cpp \ dialogs/qfiledialog_win.cpp \ dialogs/qpagesetupdialog_win.cpp \ diff --git a/src/gui/dialogs/qdialog.cpp b/src/gui/dialogs/qdialog.cpp index 9ff2ad8..fb0dba4 100644 --- a/src/gui/dialogs/qdialog.cpp +++ b/src/gui/dialogs/qdialog.cpp @@ -648,13 +648,14 @@ void QDialog::contextMenuEvent(QContextMenuEvent *e) while (w && w->whatsThis().size() == 0 && !w->testAttribute(Qt::WA_CustomWhatsThis)) w = w->isWindow() ? 0 : w->parentWidget(); if (w) { - QMenu p(this); - QAction *wt = p.addAction(tr("What's This?")); - if (p.exec(e->globalPos()) == wt) { + QWeakPointer<QMenu> p = new QMenu(this); + QAction *wt = p.data()->addAction(tr("What's This?")); + if (p.data()->exec(e->globalPos()) == wt) { QHelpEvent e(QEvent::WhatsThis, w->rect().center(), w->mapToGlobal(w->rect().center())); QApplication::sendEvent(w, &e); } + delete p.data(); } #endif } diff --git a/src/gui/dialogs/qfiledialog_win.cpp b/src/gui/dialogs/qfiledialog_win.cpp index 5a7ace9..3120938 100644 --- a/src/gui/dialogs/qfiledialog_win.cpp +++ b/src/gui/dialogs/qfiledialog_win.cpp @@ -53,53 +53,27 @@ #include <qdir.h> #include <qstringlist.h> #include <qlibrary.h> +#include "qfiledialog_win_p.h" #ifndef QT_NO_THREAD # include <private/qmutexpool_p.h> #endif -#include <shlobj.h> -//At some point we can hope that mingw will support that interface -#if !defined(Q_WS_WINCE) && !defined(Q_CC_MINGW) -#include <shobjidl.h> -#endif - -#include <objbase.h> - -#if defined(__IFileDialog_INTERFACE_DEFINED__) \ - && defined(__IFileOpenDialog_INTERFACE_DEFINED__) -#define USE_COMMON_ITEM_DIALOG -#endif - #ifdef Q_WS_WINCE +#include <shlobj.h> #include <commdlg.h> -# ifndef BFFM_SETSELECTION -# define BFFM_SETSELECTION (WM_USER + 102) -# endif -// Windows Mobile has a broken definition for BROWSEINFO -// Only compile fix -typedef struct qt_priv_browseinfo { - HWND hwndOwner; - LPCITEMIDLIST pidlRoot; - LPWSTR pszDisplayName; - LPCWSTR lpszTitle; - UINT ulFlags; - BFFCALLBACK lpfn; - LPARAM lParam; - int iImage; -} qt_BROWSEINFO; bool qt_priv_ptr_valid = false; +#else +//we have to declare them here because they're not present for all SDK/compilers +static const IID QT_IID_IFileOpenDialog = {0xd57c7288, 0xd4ad, 0x4768, {0xbe, 0x02, 0x9d, 0x96, 0x95, 0x32, 0xd9, 0x60} }; +static const IID QT_IID_IShellItem = {0x43826d1e, 0xe718, 0x42ee, {0xbc, 0x55, 0xa1, 0xe2, 0x61, 0xc3, 0x7b, 0xfe} }; +static const CLSID QT_CLSID_FileOpenDialog = {0xdc1c5a9c, 0xe88a, 0x4dde, {0xa5, 0xa1, 0x60, 0xf8, 0x2a, 0x20, 0xae, 0xf7} }; #endif -// Don't remove the lines below! -// -// resolving the W methods manually is needed, because Windows 95 doesn't include -// these methods in Shell32.lib (not even stubs!), so you'd get an unresolved symbol -// when Qt calls getExistingDirectory(), etc. -typedef LPITEMIDLIST (WINAPI *PtrSHBrowseForFolder)(BROWSEINFO*); +typedef qt_LPITEMIDLIST (WINAPI *PtrSHBrowseForFolder)(qt_BROWSEINFO*); static PtrSHBrowseForFolder ptrSHBrowseForFolder = 0; -typedef BOOL (WINAPI *PtrSHGetPathFromIDList)(LPITEMIDLIST,LPWSTR); +typedef BOOL (WINAPI *PtrSHGetPathFromIDList)(qt_LPITEMIDLIST, LPWSTR); static PtrSHGetPathFromIDList ptrSHGetPathFromIDList = 0; typedef HRESULT (WINAPI *PtrSHGetMalloc)(LPMALLOC *); static PtrSHGetMalloc ptrSHGetMalloc = 0; @@ -132,7 +106,7 @@ static void qt_win_resolve_libs() ptrSHGetMalloc = (PtrSHGetMalloc) lib.resolve("SHGetMalloc"); #else // CE stores them in a different lib and does not use unicode version - HINSTANCE handle = LoadLibraryW(L"Ceshell"); + HINSTANCE handle = LoadLibrary(L"Ceshell"); ptrSHBrowseForFolder = (PtrSHBrowseForFolder)GetProcAddress(handle, L"SHBrowseForFolder"); ptrSHGetPathFromIDList = (PtrSHGetPathFromIDList)GetProcAddress(handle, L"SHGetPathFromIDList"); ptrSHGetMalloc = (PtrSHGetMalloc)GetProcAddress(handle, L"SHGetMalloc"); @@ -421,7 +395,7 @@ QString qt_win_get_save_file_name(const QFileDialogArgs &args, } -#if defined(USE_COMMON_ITEM_DIALOG) +#ifndef Q_WS_WINCE typedef HRESULT (WINAPI *PtrSHCreateItemFromParsingName)(PCWSTR pszPath, IBindCtx *pbc, REFIID riid, void **ppv); static PtrSHCreateItemFromParsingName pSHCreateItemFromParsingName = 0; @@ -469,7 +443,7 @@ static bool qt_win_set_IFileDialogOptions(IFileDialog *pfd, // Add the filters to the file dialog. if (numFilters) { wchar_t *szData = (wchar_t*)winfilters.utf16(); - COMDLG_FILTERSPEC *filterSpec = new COMDLG_FILTERSPEC[numFilters]; + qt_COMDLG_FILTERSPEC *filterSpec = new qt_COMDLG_FILTERSPEC[numFilters]; for(int i = 0; i<numFilters; i++) { filterSpec[i].pszName = szData+offsets[i*2]; filterSpec[i].pszSpec = szData+offsets[(i*2)+1]; @@ -481,9 +455,8 @@ static bool qt_win_set_IFileDialogOptions(IFileDialog *pfd, tInitDir = QDir::toNativeSeparators(initialDirectory); if (!tInitDir.isEmpty()) { IShellItem *psiDefaultFolder; - hr = pSHCreateItemFromParsingName((wchar_t*)tInitDir.utf16(), - NULL, - IID_PPV_ARGS(&psiDefaultFolder)); + hr = pSHCreateItemFromParsingName((wchar_t*)tInitDir.utf16(), NULL, QT_IID_IShellItem, + reinterpret_cast<void**>(&psiDefaultFolder)); if (SUCCEEDED(hr)) { hr = pfd->SetFolder(psiDefaultFolder); @@ -522,7 +495,7 @@ static bool qt_win_set_IFileDialogOptions(IFileDialog *pfd, return SUCCEEDED(hr); } -QStringList qt_win_CID_get_open_file_names(const QFileDialogArgs &args, +static QStringList qt_win_CID_get_open_file_names(const QFileDialogArgs &args, QString *initialDirectory, const QStringList &filterList, QString *selectedFilter, @@ -535,10 +508,8 @@ QStringList qt_win_CID_get_open_file_names(const QFileDialogArgs &args, QApplicationPrivate::enterModal(&modal_widget); // Multiple selection is allowed only in IFileOpenDialog. IFileOpenDialog *pfd = 0; - HRESULT hr = CoCreateInstance(CLSID_FileOpenDialog, - NULL, - CLSCTX_INPROC_SERVER, - IID_PPV_ARGS(&pfd)); + HRESULT hr = CoCreateInstance(QT_CLSID_FileOpenDialog, NULL, CLSCTX_INPROC_SERVER, QT_IID_IFileOpenDialog, + reinterpret_cast<void**>(&pfd)); if (SUCCEEDED(hr)) { qt_win_set_IFileDialogOptions(pfd, args.selection, @@ -643,7 +614,7 @@ QStringList qt_win_get_open_file_names(const QFileDialogArgs &args, // multiple files belonging to different folders from these search results, the // GetOpenFileName() will return only one folder name for all the files. To retrieve // the correct path for all selected files, we have to use Common Item Dialog interfaces. -#if defined(USE_COMMON_ITEM_DIALOG) +#ifndef Q_WS_WINCE if (QSysInfo::WindowsVersion >= QSysInfo::WV_VISTA && QSysInfo::WindowsVersion < QSysInfo::WV_NT_based) return qt_win_CID_get_open_file_names(args, initialDirectory, filterLst, selectedFilter, idx); #endif @@ -716,7 +687,7 @@ static int __stdcall winGetExistDirCallbackProc(HWND hwnd, qt_win_resolve_libs(); if (ptrSHGetPathFromIDList) { wchar_t path[MAX_PATH]; - ptrSHGetPathFromIDList(LPITEMIDLIST(lParam), path); + ptrSHGetPathFromIDList(qt_LPITEMIDLIST(lParam), path); QString tmpStr = QString::fromWCharArray(path); if (!tmpStr.isEmpty()) SendMessage(hwnd, BFFM_ENABLEOK, 1, 1); @@ -728,11 +699,6 @@ static int __stdcall winGetExistDirCallbackProc(HWND hwnd, return 0; } -#ifndef BIF_NEWDIALOGSTYLE -#define BIF_NEWDIALOGSTYLE 0x0040 // Use the new dialog layout with the ability to resize -#endif - - QString qt_win_get_existing_directory(const QFileDialogArgs &args) { QString currentDir = QDir::currentPath(); @@ -757,11 +723,7 @@ QString qt_win_get_existing_directory(const QFileDialogArgs &args) path[0] = 0; tTitle = args.caption; -#if !defined(Q_WS_WINCE) - BROWSEINFO bi; -#else qt_BROWSEINFO bi; -#endif Q_ASSERT(!parent ||parent->testAttribute(Qt::WA_WState_Created)); bi.hwndOwner = (parent ? parent->winId() : 0); @@ -775,7 +737,7 @@ QString qt_win_get_existing_directory(const QFileDialogArgs &args) qt_win_resolve_libs(); if (ptrSHBrowseForFolder) { - LPITEMIDLIST pItemIDList = ptrSHBrowseForFolder((BROWSEINFO*)&bi); + qt_LPITEMIDLIST pItemIDList = ptrSHBrowseForFolder(&bi); if (pItemIDList) { ptrSHGetPathFromIDList(pItemIDList, path); IMalloc *pMalloc; diff --git a/src/gui/dialogs/qfiledialog_win_p.h b/src/gui/dialogs/qfiledialog_win_p.h new file mode 100644 index 0000000..44b7e43 --- /dev/null +++ b/src/gui/dialogs/qfiledialog_win_p.h @@ -0,0 +1,243 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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 <objbase.h> +#ifndef QFILEDIAG_WIN_P_H +#define QFILEDIAG_WIN_P_H + +//these are the interface declarations needed for the file dialog on Vista and up + +//At some point we can hope that all compilers/sdk will support that interface +//and we won't have to declare it ourselves + +//declarations +#define FOS_OVERWRITEPROMPT 0x2 +#define FOS_STRICTFILETYPES 0x4 +#define FOS_NOCHANGEDIR 0x8 +#define FOS_PICKFOLDERS 0x20 +#define FOS_FORCEFILESYSTEM 0x40 +#define FOS_ALLNONSTORAGEITEMS 0x80 +#define FOS_NOVALIDATE 0x100 +#define FOS_ALLOWMULTISELECT 0x200 +#define FOS_PATHMUSTEXIST 0x800 +#define FOS_FILEMUSTEXIST 0x1000 +#define FOS_CREATEPROMPT 0x2000 +#define FOS_SHAREAWARE 0x4000 +#define FOS_NOREADONLYRETURN 0x8000 +#define FOS_NOTESTFILECREATE 0x10000 +#define FOS_HIDEMRUPLACES 0x20000 +#define FOS_HIDEPINNEDPLACES 0x40000 +#define FOS_NODEREFERENCELINKS 0x100000 +#define FOS_DONTADDTORECENT 0x2000000 +#define FOS_FORCESHOWHIDDEN 0x10000000 +#define FOS_DEFAULTNOMINIMODE 0x20000000 +#define FOS_FORCEPREVIEWPANEON 0x40000000 + +typedef int GETPROPERTYSTOREFLAGS; +#define GPS_DEFAULT 0x00000000 +#define GPS_HANDLERPROPERTIESONLY 0x00000001 +#define GPS_READWRITE 0x00000002 +#define GPS_TEMPORARY 0x00000004 +#define GPS_FASTPROPERTIESONLY 0x00000008 +#define GPS_OPENSLOWITEM 0x00000010 +#define GPS_DELAYCREATION 0x00000020 +#define GPS_BESTEFFORT 0x00000040 +#define GPS_MASK_VALID 0x0000007F + +typedef int (CALLBACK* BFFCALLBACK)(HWND hwnd, UINT uMsg, LPARAM lParam, LPARAM lpData); +// message from browser +#define BFFM_INITIALIZED 1 +#define BFFM_SELCHANGED 2 +#define BFFM_ENABLEOK (WM_USER + 101) +#define BFFM_SETSELECTION (WM_USER + 103) +#define BFFM_SETSTATUSTEXT (WM_USER + 104) + +// Browsing for directory. +#define BIF_RETURNONLYFSDIRS 0x0001 +#define BIF_DONTGOBELOWDOMAIN 0x0002 +#define BIF_STATUSTEXT 0x0004 +#define BIF_RETURNFSANCESTORS 0x0008 +#define BIF_EDITBOX 0x0010 +#define BIF_VALIDATE 0x0020 +#define BIF_NEWDIALOGSTYLE 0x0040 +#define BIF_BROWSEINCLUDEURLS 0x0080 +#define BIF_UAHINT 0x0100 +#define BIF_NONEWFOLDERBUTTON 0x0200 +#define BIF_NOTRANSLATETARGETS 0x0400 +#define BIF_BROWSEFORCOMPUTER 0x1000 +#define BIF_BROWSEFORPRINTER 0x2000 +#define BIF_BROWSEINCLUDEFILES 0x4000 +#define BIF_SHAREABLE 0x8000 + +//the enums +typedef enum { + SIATTRIBFLAGS_AND = 0x1, + SIATTRIBFLAGS_OR = 0x2, + SIATTRIBFLAGS_APPCOMPAT = 0x3, + SIATTRIBFLAGS_MASK = 0x3 +} SIATTRIBFLAGS; +typedef enum { + SIGDN_NORMALDISPLAY = 0x00000000, + SIGDN_PARENTRELATIVEPARSING = 0x80018001, + SIGDN_PARENTRELATIVEFORADDRESSBAR = 0x8001c001, + SIGDN_DESKTOPABSOLUTEPARSING = 0x80028000, + SIGDN_PARENTRELATIVEEDITING = 0x80031001, + SIGDN_DESKTOPABSOLUTEEDITING = 0x8004c000, + SIGDN_FILESYSPATH = 0x80058000, + SIGDN_URL = 0x80068000 +} SIGDN; +typedef enum { + FDAP_BOTTOM = 0x00000000, + FDAP_TOP = 0x00000001 +} FDAP; +typedef enum { + FDESVR_DEFAULT = 0x00000000, + FDESVR_ACCEPT = 0x00000001, + FDESVR_REFUSE = 0x00000002 +} FDE_SHAREVIOLATION_RESPONSE; +typedef FDE_SHAREVIOLATION_RESPONSE FDE_OVERWRITE_RESPONSE; + +//the structs +typedef struct { + LPCWSTR pszName; + LPCWSTR pszSpec; +} qt_COMDLG_FILTERSPEC; +typedef struct { + GUID fmtid; + DWORD pid; +} qt_PROPERTYKEY; + +typedef struct { + USHORT cb; + BYTE abID[1]; +} qt_SHITEMID, *qt_LPSHITEMID; +typedef struct { + qt_SHITEMID mkid; +} qt_ITEMIDLIST, *qt_LPITEMIDLIST; +typedef const qt_ITEMIDLIST *qt_LPCITEMIDLIST; +typedef struct { + HWND hwndOwner; + qt_LPCITEMIDLIST pidlRoot; + LPWSTR pszDisplayName; + LPCWSTR lpszTitle; + UINT ulFlags; + BFFCALLBACK lpfn; + LPARAM lParam; + int iImage; +} qt_BROWSEINFO; + +DECLARE_INTERFACE(IFileDialogEvents); +DECLARE_INTERFACE_(IShellItem, IUnknown) +{ + STDMETHOD(BindToHandler)(THIS_ IBindCtx *pbc, REFGUID bhid, REFIID riid, void **ppv) PURE; + STDMETHOD(GetParent)(THIS_ IShellItem **ppsi) PURE; + STDMETHOD(GetDisplayName)(THIS_ SIGDN sigdnName, LPWSTR *ppszName) PURE; + STDMETHOD(GetAttributes)(THIS_ ULONG sfgaoMask, ULONG *psfgaoAttribs) PURE; + STDMETHOD(Compare)(THIS_ IShellItem *psi, DWORD hint, int *piOrder) PURE; +}; +DECLARE_INTERFACE_(IShellItemFilter, IUnknown) +{ + STDMETHOD(IncludeItem)(THIS_ IShellItem *psi) PURE; + STDMETHOD(GetEnumFlagsForItem)(THIS_ IShellItem *psi, DWORD *pgrfFlags) PURE; +}; +DECLARE_INTERFACE_(IEnumShellItems, IUnknown) +{ + STDMETHOD(Next)(THIS_ ULONG celt, IShellItem **rgelt, ULONG *pceltFetched) PURE; + STDMETHOD(Skip)(THIS_ ULONG celt) PURE; + STDMETHOD(Reset)(THIS_) PURE; + STDMETHOD(Clone)(THIS_ IEnumShellItems **ppenum) PURE; +}; +DECLARE_INTERFACE_(IShellItemArray, IUnknown) +{ + STDMETHOD(BindToHandler)(THIS_ IBindCtx *pbc, REFGUID rbhid, REFIID riid, void **ppvOut) PURE; + STDMETHOD(GetPropertyStore)(THIS_ GETPROPERTYSTOREFLAGS flags, REFIID riid, void **ppv) PURE; + STDMETHOD(GetPropertyDescriptionList)(THIS_ const qt_PROPERTYKEY *keyType, REFIID riid, void **ppv) PURE; + STDMETHOD(GetAttributes)(THIS_ SIATTRIBFLAGS dwAttribFlags, ULONG sfgaoMask, ULONG *psfgaoAttribs) PURE; + STDMETHOD(GetCount)(THIS_ DWORD *pdwNumItems) PURE; + STDMETHOD(GetItemAt)(THIS_ DWORD dwIndex, IShellItem **ppsi) PURE; + STDMETHOD(EnumItems)(THIS_ IEnumShellItems **ppenumShellItems) PURE; +}; +DECLARE_INTERFACE_(IModalWindow, IUnknown) +{ + STDMETHOD(Show)(THIS_ HWND hwndParent) PURE; +}; +DECLARE_INTERFACE_(IFileDialog, IModalWindow) +{ + STDMETHOD(SetFileTypes)(THIS_ UINT cFileTypes, const qt_COMDLG_FILTERSPEC *rgFilterSpec) PURE; + STDMETHOD(SetFileTypeIndex)(THIS_ UINT iFileType) PURE; + STDMETHOD(GetFileTypeIndex)(THIS_ UINT *piFileType) PURE; + STDMETHOD(Advise)(THIS_ IFileDialogEvents *pfde, DWORD *pdwCookie) PURE; + STDMETHOD(Unadvise)(THIS_ DWORD dwCookie) PURE; + STDMETHOD(SetOptions)(THIS_ DWORD fos) PURE; + STDMETHOD(GetOptions)(THIS_ DWORD *pfos) PURE; + STDMETHOD(SetDefaultFolder)(THIS_ IShellItem *psi) PURE; + STDMETHOD(SetFolder)(THIS_ IShellItem *psi) PURE; + STDMETHOD(GetFolder)(THIS_ IShellItem **ppsi) PURE; + STDMETHOD(GetCurrentSelection)(THIS_ IShellItem **ppsi) PURE; + STDMETHOD(SetFileName)(THIS_ LPCWSTR pszName) PURE; + STDMETHOD(GetFileName)(THIS_ LPWSTR *pszName) PURE; + STDMETHOD(SetTitle)(THIS_ LPCWSTR pszTitle) PURE; + STDMETHOD(SetOkButtonLabel)(THIS_ LPCWSTR pszText) PURE; + STDMETHOD(SetFileNameLabel)(THIS_ LPCWSTR pszLabel) PURE; + STDMETHOD(GetResult)(THIS_ IShellItem **ppsi) PURE; + STDMETHOD(AddPlace)(THIS_ IShellItem *psi, FDAP fdap) PURE; + STDMETHOD(SetDefaultExtension)(THIS_ LPCWSTR pszDefaultExtension) PURE; + STDMETHOD(Close)(THIS_ HRESULT hr) PURE; + STDMETHOD(SetClientGuid)(THIS_ REFGUID guid) PURE; + STDMETHOD(ClearClientData)(THIS_) PURE; + STDMETHOD(SetFilter)(THIS_ IShellItemFilter *pFilter) PURE; +}; +DECLARE_INTERFACE_(IFileDialogEvents, IUnknown) +{ + STDMETHOD(OnFileOk)(THIS_ IFileDialog *pfd) PURE; + STDMETHOD(OnFolderChanging)(THIS_ IFileDialog *pfd, IShellItem *psiFolder) PURE; + STDMETHOD(OnFolderChange)(THIS_ IFileDialog *pfd) PURE; + STDMETHOD(OnSelectionChange)(THIS_ IFileDialog *pfd) PURE; + STDMETHOD(OnShareViolation)(THIS_ IFileDialog *pfd, IShellItem *psi, FDE_SHAREVIOLATION_RESPONSE *pResponse) PURE; + STDMETHOD(OnTypeChange)(THIS_ IFileDialog *pfd) PURE; + STDMETHOD(OnOverwrite)(THIS_ IFileDialog *pfd, IShellItem *psi, FDE_OVERWRITE_RESPONSE *pResponse) PURE; +}; +DECLARE_INTERFACE_(IFileOpenDialog, IFileDialog) +{ + STDMETHOD(GetResults)(THIS_ IShellItemArray **ppenum) PURE; + STDMETHOD(GetSelectedItems)(THIS_ IShellItemArray **ppsai) PURE; +}; +#endif
\ No newline at end of file diff --git a/src/gui/dialogs/qfileinfogatherer.cpp b/src/gui/dialogs/qfileinfogatherer.cpp index 1f61957..c75cdfd 100644 --- a/src/gui/dialogs/qfileinfogatherer.cpp +++ b/src/gui/dialogs/qfileinfogatherer.cpp @@ -354,6 +354,7 @@ void QFileInfoGatherer::getFileInfos(const QString &path, const QStringList &fil } if (!updatedFiles.isEmpty()) emit updates(path, updatedFiles); + emit directoryLoaded(path); } void QFileInfoGatherer::fetch(const QFileInfo &fileInfo, QTime &base, bool &firstTime, QList<QPair<QString, QFileInfo> > &updatedFiles, const QString &path) { diff --git a/src/gui/dialogs/qfileinfogatherer_p.h b/src/gui/dialogs/qfileinfogatherer_p.h index 0242178..b8b58a2 100644 --- a/src/gui/dialogs/qfileinfogatherer_p.h +++ b/src/gui/dialogs/qfileinfogatherer_p.h @@ -155,6 +155,7 @@ Q_SIGNALS: void updates(const QString &directory, const QList<QPair<QString, QFileInfo> > &updates); void newListOfFiles(const QString &directory, const QStringList &listOfFiles) const; void nameResolved(const QString &fileName, const QString &resolvedName) const; + void directoryLoaded(const QString &path); public: QFileInfoGatherer(QObject *parent = 0); diff --git a/src/gui/dialogs/qfilesystemmodel.cpp b/src/gui/dialogs/qfilesystemmodel.cpp index 6fd947c..ba0a560 100644 --- a/src/gui/dialogs/qfilesystemmodel.cpp +++ b/src/gui/dialogs/qfilesystemmodel.cpp @@ -51,6 +51,9 @@ #ifdef Q_OS_WIN #include <qt_windows.h> #endif +#ifdef Q_OS_WIN32 +#include <QtCore/QVarLengthArray> +#endif QT_BEGIN_NAMESPACE @@ -150,6 +153,14 @@ QT_BEGIN_NAMESPACE */ /*! + \since 4.7 + \fn void QFileSystemModel::directoryLoaded(const QString &path) + + This signal is emitted when the gatherer thread has finished to load the \a path. + +*/ + +/*! \fn bool QFileSystemModel::remove(const QModelIndex &index) const Removes the model item \a index from the file system model and \bold{deletes the @@ -270,53 +281,38 @@ QFileSystemModelPrivate::QFileSystemNode *QFileSystemModelPrivate::node(const QM return indexNode; } -#ifdef Q_OS_WIN +#ifdef Q_OS_WIN32 static QString qt_GetLongPathName(const QString &strShortPath) { - QString longPath; - int i = 0; - if (strShortPath == QLatin1String(".") - || (strShortPath.startsWith(QLatin1String("//"))) - || (strShortPath.startsWith(QLatin1String("\\\\")))) // unc + if (strShortPath.isEmpty() + || strShortPath == QLatin1String(".") || strShortPath == QLatin1String("..")) return strShortPath; - QString::const_iterator it = strShortPath.constBegin(); - QString::const_iterator constEnd = strShortPath.constEnd(); - do { - bool isSep = (*it == QLatin1Char('\\') || *it == QLatin1Char('/')); - if (isSep || it == constEnd) { - QString section = (it == constEnd ? strShortPath : strShortPath.left(i)); - // FindFirstFile does not handle volumes ("C:"), so we have to catch that ourselves. - if (section.endsWith(QLatin1Char(':'))) { - longPath.append(section.toUpper()); - } else { - HANDLE h; -#ifndef Q_OS_WINCE - //We add the extend length prefix to handle long path - QString longSection = QLatin1String("\\\\?\\")+QDir::toNativeSeparators(section); -#else - QString longSection = QDir::toNativeSeparators(section); -#endif - WIN32_FIND_DATA findData; - h = ::FindFirstFile((wchar_t*)longSection.utf16(), &findData); - if (h != INVALID_HANDLE_VALUE) { - longPath.append(QString::fromWCharArray(findData.cFileName)); - ::FindClose(h); - } else { - longPath.append(section); - break; - } - } - if (it != constEnd) - longPath.append(*it); - else - break; - } - ++it; - if (isSep && it == constEnd) // break out if the last character is a separator - break; - ++i; - } while (true); - return longPath; + if (strShortPath.length() == 2 && strShortPath.endsWith(QLatin1Char(':'))) + return strShortPath.toUpper(); + const QString absPath = QDir(strShortPath).absolutePath(); + if (absPath.startsWith(QLatin1String("//")) + || absPath.startsWith(QLatin1String("\\\\"))) // unc + return QDir::fromNativeSeparators(absPath); + if (absPath.startsWith(QLatin1Char('/'))) + return QString(); + const QString inputString = QLatin1String("\\\\?\\") + QDir::toNativeSeparators(absPath); + QVarLengthArray<TCHAR, MAX_PATH> buffer(MAX_PATH); + DWORD result = ::GetLongPathName((wchar_t*)inputString.utf16(), + buffer.data(), + buffer.size()); + if (result > DWORD(buffer.size())) { + buffer.resize(result); + result = ::GetLongPathName((wchar_t*)inputString.utf16(), + buffer.data(), + buffer.size()); + } + if (result > 4) { + QString longPath = QString::fromWCharArray(buffer.data() + 4); // ignoring prefix + longPath[0] = longPath.at(0).toUpper(); // capital drive letters + return QDir::fromNativeSeparators(longPath); + } else { + return QDir::fromNativeSeparators(strShortPath); + } } #endif @@ -334,7 +330,7 @@ QFileSystemModelPrivate::QFileSystemNode *QFileSystemModelPrivate::node(const QS // Construct the nodes up to the new root path if they need to be built QString absolutePath; -#ifdef Q_OS_WIN +#ifdef Q_OS_WIN32 QString longPath = qt_GetLongPathName(path); #else QString longPath = path; @@ -673,7 +669,7 @@ QVariant QFileSystemModel::data(const QModelIndex &index, int role) const case Qt::EditRole: case Qt::DisplayRole: switch (index.column()) { - case 0: return d->name(index); + case 0: return d->displayName(index); case 1: return d->size(index); case 2: return d->type(index); case 3: return d->time(index); @@ -789,13 +785,25 @@ QString QFileSystemModelPrivate::name(const QModelIndex &index) const if (resolvedSymLinks.contains(fullPath)) return resolvedSymLinks[fullPath]; } - // ### TODO it would be nice to grab the volume name if dirNode->parent == root return dirNode->fileName; } /*! \internal */ +QString QFileSystemModelPrivate::displayName(const QModelIndex &index) const +{ +#if defined(Q_OS_WIN) && !defined(Q_OS_WINCE) + QFileSystemNode *dirNode = node(index); + if (!dirNode->volumeName.isNull()) + return dirNode->volumeName + QLatin1String(" (") + name(index) + QLatin1Char(')'); +#endif + return name(index); +} + +/*! + \internal +*/ QIcon QFileSystemModelPrivate::icon(const QModelIndex &index) const { if (!index.isValid()) @@ -1337,7 +1345,11 @@ QModelIndex QFileSystemModel::setRootPath(const QString &newPath) { Q_D(QFileSystemModel); #ifdef Q_OS_WIN - QString longNewPath = QDir::fromNativeSeparators(qt_GetLongPathName(newPath)); +#ifdef Q_OS_WIN32 + QString longNewPath = qt_GetLongPathName(newPath); +#else + QString longNewPath = QDir::fromNativeSeparators(newPath); +#endif #else QString longNewPath = newPath; #endif @@ -1640,6 +1652,18 @@ QFileSystemModelPrivate::QFileSystemNode* QFileSystemModelPrivate::addNode(QFile #ifndef QT_NO_FILESYSTEMWATCHER node->populate(info); #endif +#if defined(Q_OS_WIN) && !defined(Q_OS_WINCE) + //The parentNode is "" so we are listing the drives + if (parentNode->fileName.isEmpty()) { + wchar_t name[MAX_PATH + 1]; + //GetVolumeInformation requires to add trailing backslash + const QString nodeName = fileName + QLatin1String("\\"); + BOOL success = ::GetVolumeInformation((wchar_t *)(nodeName.utf16()), + name, MAX_PATH + 1, NULL, 0, NULL, NULL, 0); + if (success && name[0]) + node->volumeName = QString::fromWCharArray(name); + } +#endif parentNode->children.insert(fileName, node); return node; } @@ -1869,6 +1893,8 @@ void QFileSystemModelPrivate::init() q, SLOT(_q_fileSystemChanged(QString,QList<QPair<QString,QFileInfo> >))); q->connect(&fileInfoGatherer, SIGNAL(nameResolved(QString,QString)), q, SLOT(_q_resolvedName(QString,QString))); + q->connect(&fileInfoGatherer, SIGNAL(directoryLoaded(QString)), + q, SIGNAL(directoryLoaded(QString))); q->connect(&delayedSortTimer, SIGNAL(timeout()), q, SLOT(_q_performDelayedSort()), Qt::QueuedConnection); } diff --git a/src/gui/dialogs/qfilesystemmodel.h b/src/gui/dialogs/qfilesystemmodel.h index 4dcfe26..d8178c7 100644 --- a/src/gui/dialogs/qfilesystemmodel.h +++ b/src/gui/dialogs/qfilesystemmodel.h @@ -70,6 +70,7 @@ class Q_GUI_EXPORT QFileSystemModel : public QAbstractItemModel Q_SIGNALS: void rootPathChanged(const QString &newPath); void fileRenamed(const QString &path, const QString &oldName, const QString &newName); + void directoryLoaded(const QString &path); public: enum Roles { diff --git a/src/gui/dialogs/qfilesystemmodel_p.h b/src/gui/dialogs/qfilesystemmodel_p.h index 6c85a7c..03e0bfb 100644 --- a/src/gui/dialogs/qfilesystemmodel_p.h +++ b/src/gui/dialogs/qfilesystemmodel_p.h @@ -97,6 +97,9 @@ public: } QString fileName; +#if defined(Q_OS_WIN) && !defined(Q_OS_WINCE) + QString volumeName; +#endif inline qint64 size() const { if (info && !info->isDir()) return info->size(); return 0; } inline QString type() const { if (info) return info->displayType; return QLatin1String(""); } @@ -278,6 +281,7 @@ public: QIcon icon(const QModelIndex &index) const; QString name(const QModelIndex &index) const; + QString displayName(const QModelIndex &index) const; QString filePath(const QModelIndex &index) const; QString size(const QModelIndex &index) const; static QString size(qint64 bytes); diff --git a/src/gui/dialogs/qmessagebox.cpp b/src/gui/dialogs/qmessagebox.cpp index d1b2e3f..ed437ff 100644 --- a/src/gui/dialogs/qmessagebox.cpp +++ b/src/gui/dialogs/qmessagebox.cpp @@ -92,8 +92,8 @@ public: { #ifndef QT_NO_CONTEXTMENU QMenu *menu = createStandardContextMenu(); - menu->exec(e->globalPos()); - delete menu; + menu->setAttribute(Qt::WA_DeleteOnClose); + menu->popup(e->globalPos()); #else Q_UNUSED(e); #endif diff --git a/src/gui/dialogs/qprintdialog_qws.cpp b/src/gui/dialogs/qprintdialog_qws.cpp index 6b531a2..1336c04 100644 --- a/src/gui/dialogs/qprintdialog_qws.cpp +++ b/src/gui/dialogs/qprintdialog_qws.cpp @@ -163,7 +163,7 @@ void QPrintDialogPrivate::_q_okClicked() printer->setPaperSize(pageSize); printer->setPageOrder(pageOrder2); printer->setColorMode(colorMode2); - printer->setNumCopies(numCopies); + printer->setCopyCount(numCopies); switch ((rangeCombo->itemData(rangeCombo->currentIndex())).toInt()){ case (int)QPrintDialog::AllPages: @@ -479,8 +479,8 @@ void QPrintDialogPrivate::setPrinter(QPrinter *p, bool pickUpSettings) printGray->setChecked(true); // number of copies - copies->setValue(p->numCopies()); - _q_setNumCopies(p->numCopies()); + copies->setValue(p->copyCount()); + _q_setNumCopies(p->copyCount()); } if (p) { diff --git a/src/gui/dialogs/qprintdialog_unix.cpp b/src/gui/dialogs/qprintdialog_unix.cpp index 23f5831..2d169cf 100644 --- a/src/gui/dialogs/qprintdialog_unix.cpp +++ b/src/gui/dialogs/qprintdialog_unix.cpp @@ -72,8 +72,6 @@ QT_BEGIN_NAMESPACE -extern int qt_printerRealNumCopies(QPaintEngine *); - class QOptionTreeItem; class QPPDOptionsModel; @@ -439,7 +437,7 @@ void QPrintDialogPrivate::applyPrinterProperties(QPrinter *p) case QPrinter::DuplexShortSide: options.duplexShort->setChecked(true); break; } - options.copies->setValue(qt_printerRealNumCopies(p->paintEngine())); + options.copies->setValue(p->copyCount()); options.collate->setChecked(p->collateCopies()); options.reverse->setChecked(p->pageOrder() == QPrinter::LastPageFirst); top->d->applyPrinterProperties(p); @@ -510,7 +508,7 @@ void QPrintDialogPrivate::setupPrinter() } // copies - p->setNumCopies(options.copies->value()); + p->setCopyCount(options.copies->value()); p->setCollateCopies(options.collate->isChecked()); top->d->setupPrinter(); diff --git a/src/gui/dialogs/qprintdialog_win.cpp b/src/gui/dialogs/qprintdialog_win.cpp index 5ccd33d..fa0c99f 100644 --- a/src/gui/dialogs/qprintdialog_win.cpp +++ b/src/gui/dialogs/qprintdialog_win.cpp @@ -52,7 +52,7 @@ #include <private/qprintengine_win_p.h> #include <private/qprinter_p.h> -#if defined(Q_CC_MINGW) && !defined(PD_NOCURRENTPAGE) +#if !defined(PD_NOCURRENTPAGE) #define PD_NOCURRENTPAGE 0x00800000 #define PD_RESULT_PRINT 1 #define PD_RESULT_APPLY 2 diff --git a/src/gui/embedded/directfb.pri b/src/gui/embedded/directfb.pri index bd1d947..d6d77b4 100644 --- a/src/gui/embedded/directfb.pri +++ b/src/gui/embedded/directfb.pri @@ -15,7 +15,7 @@ #DEFINES += QT_DIRECTFB_TIMING #DEFINES += QT_NO_DIRECTFB_OPAQUE_DETECTION #DEFINES += QT_NO_DIRECTFB_STRETCHBLIT -#DIRECTFB_DRAWINGOPERATIONS=DRAW_RECTS|DRAW_LINES|DRAW_IMAGE|DRAW_PIXMAP|DRAW_TILED_PIXMAP|STROKE_PATH|DRAW_PATH|DRAW_POINTS|DRAW_ELLIPSE|DRAW_POLYGON|DRAW_TEXT|FILL_PATH|FILL_RECT|DRAW_COLORSPANS|DRAW_ROUNDED_RECT +#DIRECTFB_DRAWINGOPERATIONS=DRAW_RECTS|DRAW_LINES|DRAW_IMAGE|DRAW_PIXMAP|DRAW_TILED_PIXMAP|STROKE_PATH|DRAW_PATH|DRAW_POINTS|DRAW_ELLIPSE|DRAW_POLYGON|DRAW_TEXT|FILL_PATH|FILL_RECT|DRAW_COLORSPANS|DRAW_ROUNDED_RECT|DRAW_STATICTEXT #DEFINES += \"QT_DIRECTFB_WARN_ON_RASTERFALLBACKS=$$DIRECTFB_DRAWINGOPERATIONS\" #DEFINES += \"QT_DIRECTFB_DISABLE_RASTERFALLBACKS=$$DIRECTFB_DRAWINGOPERATIONS\" diff --git a/src/gui/embedded/qscreen_qws.cpp b/src/gui/embedded/qscreen_qws.cpp index 8eb8123..65a3fb5 100644 --- a/src/gui/embedded/qscreen_qws.cpp +++ b/src/gui/embedded/qscreen_qws.cpp @@ -39,6 +39,7 @@ ** ****************************************************************************/ +#include "qplatformdefs.h" #include "qscreen_qws.h" #include "qcolormap.h" @@ -3223,13 +3224,13 @@ QScreen * qt_probe_bus() return qt_dodriver("unaccel.so",0,0); } - DIR * dirptr=opendir("/proc/bus/pci"); + QT_DIR *dirptr = QT_OPENDIR("/proc/bus/pci"); if(!dirptr) return qt_dodriver("unaccel.so",0,0); - DIR * dirptr2; - dirent * cards; + QT_DIR * dirptr2; + QT_DIRENT *cards; - dirent * busses=readdir(dirptr); + QT_DIRENT *busses = QT_READDIR(dirptr); while(busses) { if(busses->d_name[0]!='.') { @@ -3237,9 +3238,9 @@ QScreen * qt_probe_bus() strcpy(buf,"/proc/bus/pci/"); qstrcpy(buf+14,busses->d_name); int p=strlen(buf); - dirptr2=opendir(buf); + dirptr2 = QT_OPENDIR(buf); if(dirptr2) { - cards=readdir(dirptr2); + cards = QT_READDIR(dirptr2); while(cards) { if(cards->d_name[0]!='.') { buf[p]='/'; @@ -3248,14 +3249,14 @@ QScreen * qt_probe_bus() if(ret) return ret; } - cards=readdir(dirptr2); + cards = QT_READDIR(dirptr2); } - closedir(dirptr2); + QT_CLOSEDIR(dirptr2); } } - busses=readdir(dirptr); + busses = QT_READDIR(dirptr); } - closedir(dirptr); + QT_CLOSEDIR(dirptr); return qt_dodriver("unaccel.so",0,0); } diff --git a/src/gui/graphicsview/qgraphicsitem.cpp b/src/gui/graphicsview/qgraphicsitem.cpp index bd214e1..5735cd6 100644 --- a/src/gui/graphicsview/qgraphicsitem.cpp +++ b/src/gui/graphicsview/qgraphicsitem.cpp @@ -673,6 +673,7 @@ #include <QtCore/qtimer.h> #include <QtCore/qvariant.h> #include <QtCore/qvarlengtharray.h> +#include <QtCore/qnumeric.h> #include <QtGui/qapplication.h> #include <QtGui/qbitmap.h> #include <QtGui/qpainter.h> @@ -3178,8 +3179,9 @@ void QGraphicsItemPrivate::setFocusHelper(Qt::FocusReason focusReason, bool clim */ void QGraphicsItem::clearFocus() { - // Pass focus to the closest parent focus scope. - if (!d_ptr->inDestructor) { + // Pass focus to the closest parent focus scope when clearing focus + // from a focus scope. + if (!d_ptr->inDestructor && (d_ptr->flags & ItemIsFocusScope)) { QGraphicsItem *p = d_ptr->parent; while (p) { if (p->flags() & ItemIsFocusScope) { @@ -3447,6 +3449,9 @@ void QGraphicsItem::setX(qreal x) if (d_ptr->inDestructor) return; + if (qIsNaN(x)) + return; + d_ptr->setPosHelper(QPointF(x, d_ptr->pos.y())); } @@ -3471,6 +3476,9 @@ void QGraphicsItem::setY(qreal y) if (d_ptr->inDestructor) return; + if (qIsNaN(y)) + return; + d_ptr->setPosHelper(QPointF(d_ptr->pos.x(), y)); } diff --git a/src/gui/graphicsview/qgraphicsitem_p.h b/src/gui/graphicsview/qgraphicsitem_p.h index b3ca3b5..2c92364 100644 --- a/src/gui/graphicsview/qgraphicsitem_p.h +++ b/src/gui/graphicsview/qgraphicsitem_p.h @@ -156,8 +156,8 @@ public: needSortChildren(0), allChildrenDirty(0), fullUpdatePending(0), - flags(0), dirtyChildrenBoundingRect(1), + flags(0), paintedViewBoundingRectsNeedRepaint(0), dirtySceneTransform(1), geometryChanged(1), @@ -474,11 +474,11 @@ public: quint32 inSetPosHelper : 1; quint32 needSortChildren : 1; quint32 allChildrenDirty : 1; + quint32 fullUpdatePending : 1; + quint32 dirtyChildrenBoundingRect : 1; // Packed 32 bits - quint32 fullUpdatePending : 1; quint32 flags : 17; - quint32 dirtyChildrenBoundingRect : 1; quint32 paintedViewBoundingRectsNeedRepaint : 1; quint32 dirtySceneTransform : 1; quint32 geometryChanged : 1; @@ -492,10 +492,10 @@ public: quint32 sceneTransformTranslateOnly : 1; quint32 notifyBoundingRectChanged : 1; quint32 notifyInvalidated : 1; - - // New 32 bits quint32 mouseSetsFocus : 1; quint32 explicitActivate : 1; + + // New 32 bits quint32 wantsActive : 1; quint32 holesInSiblingIndex : 1; quint32 sequentialOrdering : 1; @@ -503,6 +503,7 @@ public: quint32 scenePosDescendants : 1; quint32 pendingPolish : 1; quint32 mayHaveChildWithGraphicsEffect : 1; + quint32 padding : 25; // Optional stacking order int globalStackingOrder; diff --git a/src/gui/graphicsview/qgraphicsscene.cpp b/src/gui/graphicsview/qgraphicsscene.cpp index afea082..365afdd 100644 --- a/src/gui/graphicsview/qgraphicsscene.cpp +++ b/src/gui/graphicsview/qgraphicsscene.cpp @@ -693,6 +693,18 @@ void QGraphicsScenePrivate::removeItemHelper(QGraphicsItem *item) --selectionChanging; if (!selectionChanging && selectedItems.size() != oldSelectedItemsSize) emit q->selectionChanged(); + + QHash<QGesture *, QGraphicsObject *>::iterator it; + for (it = gestureTargets.begin(); it != gestureTargets.end();) { + if (it.value() == item) + it = gestureTargets.erase(it); + else + ++it; + } + QGraphicsObject *dummy = static_cast<QGraphicsObject *>(item); + cachedTargetItems.removeOne(dummy); + cachedItemGestures.remove(dummy); + cachedAlreadyDeliveredGestures.remove(dummy); } /*! @@ -4239,6 +4251,8 @@ static void _q_paintItem(QGraphicsItem *item, QPainter *painter, widgetItem->paintWindowFrame(painter, option, widget); if (painterStateProtection) painter->restore(); + } else if (widgetItem->autoFillBackground()) { + painter->fillRect(option->exposedRect, widgetItem->palette().window()); } widgetItem->paint(painter, option, widget); @@ -5900,45 +5914,51 @@ void QGraphicsScenePrivate::leaveModal(QGraphicsItem *panel) dispatchHoverEvent(&hoverEvent); } -void QGraphicsScenePrivate::getGestureTargets(const QSet<QGesture *> &gestures, - QWidget *viewport, - QMap<Qt::GestureType, QGesture *> *conflictedGestures, - QList<QList<QGraphicsObject *> > *conflictedItems, - QHash<QGesture *, QGraphicsObject *> *normalGestures) +void QGraphicsScenePrivate::gestureTargetsAtHotSpots(const QSet<QGesture *> &gestures, + Qt::GestureFlag flag, + QHash<QGraphicsObject *, QSet<QGesture *> > *targets, + QSet<QGraphicsObject *> *itemsSet, + QSet<QGesture *> *normal, + QSet<QGesture *> *conflicts) { + QSet<QGesture *> normalGestures; // that are not in conflicted state. foreach (QGesture *gesture, gestures) { - Qt::GestureType gestureType = gesture->gestureType(); - if (gesture->hasHotSpot()) { - QPoint screenPos = gesture->hotSpot().toPoint(); - QList<QGraphicsItem *> items = itemsAtPosition(screenPos, QPointF(), viewport); - QList<QGraphicsObject *> result; - for (int j = 0; j < items.size(); ++j) { - QGraphicsItem *item = items.at(j); + if (!gesture->hasHotSpot()) + continue; + const Qt::GestureType gestureType = gesture->gestureType(); + QList<QGraphicsItem *> items = itemsAtPosition(QPoint(), gesture->d_func()->sceneHotSpot, 0); + for (int j = 0; j < items.size(); ++j) { + QGraphicsItem *item = items.at(j); - // Check if the item is blocked by a modal panel and use it as - // a target instead of this item. - (void) item->isBlockedByModalPanel(&item); + // Check if the item is blocked by a modal panel and use it as + // a target instead of this item. + (void) item->isBlockedByModalPanel(&item); - if (QGraphicsObject *itemobj = item->toGraphicsObject()) { - QGraphicsItemPrivate *d = item->d_func(); - if (d->gestureContext.contains(gestureType)) { - result.append(itemobj); + if (QGraphicsObject *itemobj = item->toGraphicsObject()) { + QGraphicsItemPrivate *d = item->QGraphicsItem::d_func(); + QMap<Qt::GestureType, Qt::GestureFlags>::const_iterator it = + d->gestureContext.find(gestureType); + if (it != d->gestureContext.end() && (!flag || (it.value() & flag))) { + if (normalGestures.contains(gesture)) { + normalGestures.remove(gesture); + if (conflicts) + conflicts->insert(gesture); + } else { + normalGestures.insert(gesture); } + if (targets) + (*targets)[itemobj].insert(gesture); + if (itemsSet) + (*itemsSet).insert(itemobj); } - // Don't propagate through panels. - if (item->isPanel()) - break; - } - DEBUG() << "QGraphicsScenePrivate::getGestureTargets:" - << gesture << result; - if (result.size() == 1) { - normalGestures->insert(gesture, result.first()); - } else if (!result.isEmpty()) { - conflictedGestures->insert(gestureType, gesture); - conflictedItems->append(result); } + // Don't propagate through panels. + if (item->isPanel()) + break; } } + if (normal) + *normal = normalGestures; } void QGraphicsScenePrivate::gestureEventHandler(QGestureEvent *event) @@ -5946,200 +5966,215 @@ void QGraphicsScenePrivate::gestureEventHandler(QGestureEvent *event) QWidget *viewport = event->widget(); if (!viewport) return; + QGraphicsView *graphicsView = qobject_cast<QGraphicsView *>(viewport->parent()); + if (!graphicsView) + return; + QList<QGesture *> allGestures = event->gestures(); DEBUG() << "QGraphicsScenePrivate::gestureEventHandler:" << "Delivering gestures:" << allGestures; - typedef QHash<QGraphicsObject *, QList<QGesture *> > GesturesPerItem; - GesturesPerItem gesturesPerItem; - QSet<QGesture *> startedGestures; + QPoint delta = graphicsView->mapFromGlobal(QPoint()); + QTransform toScene = QTransform::fromTranslate(delta.x(), delta.y()) + * graphicsView->viewportTransform().inverted(); foreach (QGesture *gesture, allGestures) { + // cache scene coordinates of the hot spot + if (gesture->hasHotSpot()) { + gesture->d_func()->sceneHotSpot = toScene.map(gesture->hotSpot()); + } else { + gesture->d_func()->sceneHotSpot = QPointF(); + } + QGraphicsObject *target = gestureTargets.value(gesture, 0); if (!target) { // when we are not in started mode but don't have a target // then the only one interested in gesture is the view/scene if (gesture->state() == Qt::GestureStarted) startedGestures.insert(gesture); - } else { - gesturesPerItem[target].append(gesture); } } - QMap<Qt::GestureType, QGesture *> conflictedGestures; - QList<QList<QGraphicsObject *> > conflictedItems; - QHash<QGesture *, QGraphicsObject *> normalGestures; - getGestureTargets(startedGestures, viewport, &conflictedGestures, &conflictedItems, - &normalGestures); - DEBUG() << "QGraphicsScenePrivate::gestureEventHandler:" - << "Conflicting gestures:" << conflictedGestures.values() << conflictedItems; - Q_ASSERT((conflictedGestures.isEmpty() && conflictedItems.isEmpty()) || - (!conflictedGestures.isEmpty() && !conflictedItems.isEmpty())); - - // gestures that were sent as override events, but no one accepted them - QHash<QGesture *, QGraphicsObject *> ignoredConflictedGestures; - - // deliver conflicted gestures as override events first - while (!conflictedGestures.isEmpty() && !conflictedItems.isEmpty()) { - // get the topmost item to deliver the override event - Q_ASSERT(!conflictedItems.isEmpty()); - Q_ASSERT(!conflictedItems.first().isEmpty()); - QGraphicsObject *topmost = conflictedItems.first().first(); - for (int i = 1; i < conflictedItems.size(); ++i) { - QGraphicsObject *item = conflictedItems.at(i).first(); - if (qt_closestItemFirst(item, topmost)) { - topmost = item; - } - } - // get a list of gestures to send to the item - QList<Qt::GestureType> grabbedGestures = - topmost->QGraphicsItem::d_func()->gestureContext.keys(); - QList<QGesture *> gestures; - for (int i = 0; i < grabbedGestures.size(); ++i) { - if (QGesture *g = conflictedGestures.value(grabbedGestures.at(i), 0)) { - gestures.append(g); - if (!ignoredConflictedGestures.contains(g)) - ignoredConflictedGestures.insert(g, topmost); - } - } - - // send gesture override to the topmost item - QGestureEvent ev(gestures); - ev.t = QEvent::GestureOverride; - ev.setWidget(event->widget()); - // mark event and individual gestures as ignored - ev.ignore(); - foreach(QGesture *g, gestures) - ev.setAccepted(g, false); + if (!startedGestures.isEmpty()) { + QSet<QGesture *> normalGestures; // that have just one target + QSet<QGesture *> conflictedGestures; // that have multiple possible targets + gestureTargetsAtHotSpots(startedGestures, Qt::GestureFlag(0), &cachedItemGestures, 0, + &normalGestures, &conflictedGestures); + cachedTargetItems = cachedItemGestures.keys(); + qSort(cachedTargetItems.begin(), cachedTargetItems.end(), qt_closestItemFirst); DEBUG() << "QGraphicsScenePrivate::gestureEventHandler:" - << "delivering override to" - << topmost << gestures; - sendEvent(topmost, &ev); - // mark all accepted gestures to deliver them as normal gesture events - foreach (QGesture *g, gestures) { - if (ev.isAccepted() || ev.isAccepted(g)) { - conflictedGestures.remove(g->gestureType()); - gestureTargets.remove(g); - // add the gesture to the list of normal delivered gestures - normalGestures.insert(g, topmost); + << "Conflicting gestures:" << conflictedGestures; + + // deliver conflicted gestures as override events AND remember + // initial gesture targets + if (!conflictedGestures.isEmpty()) { + for (int i = 0; i < cachedTargetItems.size(); ++i) { + QWeakPointer<QGraphicsObject> item = cachedTargetItems.at(i); + + // get gestures to deliver to the current item + QSet<QGesture *> gestures = conflictedGestures & cachedItemGestures.value(item.data()); + if (gestures.isEmpty()) + continue; + DEBUG() << "QGraphicsScenePrivate::gestureEventHandler:" - << "override was accepted:" - << g << topmost; - ignoredConflictedGestures.remove(g); + << "delivering override to" + << item.data() << gestures; + // send gesture override + QGestureEvent ev(gestures.toList()); + ev.t = QEvent::GestureOverride; + ev.setWidget(event->widget()); + // mark event and individual gestures as ignored + ev.ignore(); + foreach(QGesture *g, gestures) + ev.setAccepted(g, false); + sendEvent(item.data(), &ev); + // mark all accepted gestures to deliver them as normal gesture events + foreach (QGesture *g, gestures) { + if (ev.isAccepted() || ev.isAccepted(g)) { + conflictedGestures.remove(g); + // mark the item as a gesture target + if (item) + gestureTargets.insert(g, item.data()); + DEBUG() << "QGraphicsScenePrivate::gestureEventHandler:" + << "override was accepted:" + << g << item.data(); + } + // remember the first item that received the override event + // as it most likely become a target if noone else accepts + // the override event + if (!gestureTargets.contains(g) && item) + gestureTargets.insert(g, item.data()); + + } + if (conflictedGestures.isEmpty()) + break; } } - // remove the item that we've already delivered from the list - for (int i = 0; i < conflictedItems.size(); ) { - QList<QGraphicsObject *> &items = conflictedItems[i]; - if (items.first() == topmost) { - items.removeFirst(); - if (items.isEmpty()) { - conflictedItems.removeAt(i); - continue; + // remember the initial target item for each gesture that was not in + // the conflicted state. + if (!normalGestures.isEmpty()) { + for (int i = 0; i < cachedTargetItems.size() && !normalGestures.isEmpty(); ++i) { + QGraphicsObject *item = cachedTargetItems.at(i); + + // get gestures to deliver to the current item + foreach (QGesture *g, cachedItemGestures.value(item)) { + if (!gestureTargets.contains(g)) { + gestureTargets.insert(g, item); + normalGestures.remove(g); + } } } - ++i; } } - // put back those started gestures that are not in the conflicted state - // and remember their targets - QHash<QGesture *, QGraphicsObject *>::const_iterator it = normalGestures.begin(), - e = normalGestures.end(); - for (; it != e; ++it) { - QGesture *g = it.key(); - QGraphicsObject *receiver = it.value(); - Q_ASSERT(!gestureTargets.contains(g)); - gestureTargets.insert(g, receiver); - gesturesPerItem[receiver].append(g); - } - it = ignoredConflictedGestures.begin(); - e = ignoredConflictedGestures.end(); - for (; it != e; ++it) { - QGesture *g = it.key(); - QGraphicsObject *receiver = it.value(); - Q_ASSERT(!gestureTargets.contains(g)); - gestureTargets.insert(g, receiver); - gesturesPerItem[receiver].append(g); - } - - DEBUG() << "QGraphicsScenePrivate::gestureEventHandler:" - << "Started gestures:" << normalGestures.keys() - << "All gestures:" << gesturesPerItem.values(); - - // deliver all events - QList<QGesture *> alreadyIgnoredGestures; - QHash<QGraphicsObject *, QSet<QGesture *> > itemIgnoredGestures; - QList<QGraphicsObject *> targetItems = gesturesPerItem.keys(); - qSort(targetItems.begin(), targetItems.end(), qt_closestItemFirst); - for (int i = 0; i < targetItems.size(); ++i) { - QGraphicsObject *item = targetItems.at(i); - QList<QGesture *> gestures = gesturesPerItem.value(item); - // remove gestures that were already delivered once and were ignored - DEBUG() << "QGraphicsScenePrivate::gestureEventHandler:" - << "already ignored gestures for item" - << item << ":" << itemIgnoredGestures.value(item); - if (itemIgnoredGestures.contains(item)) // don't deliver twice to the same item - continue; - - QGraphicsItemPrivate *gid = item->QGraphicsItem::d_func(); - foreach(QGesture *g, alreadyIgnoredGestures) { - QMap<Qt::GestureType, Qt::GestureFlags>::iterator contextit = - gid->gestureContext.find(g->gestureType()); - bool deliver = contextit != gid->gestureContext.end() && - (g->state() == Qt::GestureStarted || - (contextit.value() & Qt::ReceivePartialGestures)); - if (deliver) - gestures += g; + // deliver all gesture events + QSet<QGesture *> undeliveredGestures; + QSet<QGesture *> parentPropagatedGestures; + foreach (QGesture *gesture, allGestures) { + if (QGraphicsObject *target = gestureTargets.value(gesture, 0)) { + cachedItemGestures[target].insert(gesture); + cachedTargetItems.append(target); + undeliveredGestures.insert(gesture); + QGraphicsItemPrivate *d = target->QGraphicsItem::d_func(); + const Qt::GestureFlags flags = d->gestureContext.value(gesture->gestureType()); + if (flags & Qt::IgnoredGesturesPropagateToParent) + parentPropagatedGestures.insert(gesture); } + } + qSort(cachedTargetItems.begin(), cachedTargetItems.end(), qt_closestItemFirst); + for (int i = 0; i < cachedTargetItems.size(); ++i) { + QWeakPointer<QGraphicsObject> receiver = cachedTargetItems.at(i); + QSet<QGesture *> gestures = + undeliveredGestures & cachedItemGestures.value(receiver.data()); + gestures -= cachedAlreadyDeliveredGestures.value(receiver.data()); + if (gestures.isEmpty()) continue; + + cachedAlreadyDeliveredGestures[receiver.data()] += gestures; + const bool isPanel = receiver.data()->isPanel(); + DEBUG() << "QGraphicsScenePrivate::gestureEventHandler:" << "delivering to" - << item << gestures; - QGestureEvent ev(gestures); + << receiver.data() << gestures; + QGestureEvent ev(gestures.toList()); ev.setWidget(event->widget()); - sendEvent(item, &ev); + sendEvent(receiver.data(), &ev); QSet<QGesture *> ignoredGestures; foreach (QGesture *g, gestures) { if (!ev.isAccepted() && !ev.isAccepted(g)) { - ignoredGestures.insert(g); + // if the gesture was ignored by its target, we will update the + // targetItems list with a possible target items (items that + // want to receive partial gestures). + // ### wont' work if the target was destroyed in the event + // we will just stop delivering it. + if (receiver && receiver.data() == gestureTargets.value(g, 0)) + ignoredGestures.insert(g); } else { - if (g->state() == Qt::GestureStarted) - gestureTargets[g] = item; + if (receiver && g->state() == Qt::GestureStarted) { + // someone accepted the propagated initial GestureStarted + // event, let it be the new target for all following events. + gestureTargets[g] = receiver.data(); + } + undeliveredGestures.remove(g); } } - if (!ignoredGestures.isEmpty()) { - // get a list of items under the (current) hotspot of each ignored - // gesture and start delivery again from the beginning - DEBUG() << "QGraphicsScenePrivate::gestureEventHandler:" - << "item has ignored the event, will propagate." - << item << ignoredGestures; - itemIgnoredGestures[item] += ignoredGestures; - QMap<Qt::GestureType, QGesture *> conflictedGestures; - QList<QList<QGraphicsObject *> > itemsForConflictedGestures; - QHash<QGesture *, QGraphicsObject *> normalGestures; - getGestureTargets(ignoredGestures, viewport, - &conflictedGestures, &itemsForConflictedGestures, - &normalGestures); - QSet<QGraphicsObject *> itemsSet = targetItems.toSet(); - for (int k = 0; k < itemsForConflictedGestures.size(); ++k) - itemsSet += itemsForConflictedGestures.at(k).toSet(); - targetItems = itemsSet.toList(); - qSort(targetItems.begin(), targetItems.end(), qt_closestItemFirst); - alreadyIgnoredGestures = conflictedGestures.values(); + if (undeliveredGestures.isEmpty()) + break; + + // ignoredGestures list is only filled when delivering to the gesture + // target item, so it is safe to assume item == target. + if (!ignoredGestures.isEmpty() && !isPanel) { + // look for new potential targets for gestures that were ignored + // and should be propagated. + + QSet<QGraphicsObject *> targetsSet = cachedTargetItems.toSet(); + + if (receiver) { + // first if the gesture should be propagated to parents only + for (QSet<QGesture *>::iterator it = ignoredGestures.begin(); + it != ignoredGestures.end();) { + if (parentPropagatedGestures.contains(*it)) { + QGesture *gesture = *it; + const Qt::GestureType gestureType = gesture->gestureType(); + QGraphicsItem *item = receiver.data(); + while (item) { + if (QGraphicsObject *obj = item->toGraphicsObject()) { + if (item->d_func()->gestureContext.contains(gestureType)) { + targetsSet.insert(obj); + cachedItemGestures[obj].insert(gesture); + } + } + if (item->isPanel()) + break; + item = item->parentItem(); + } + + it = ignoredGestures.erase(it); + continue; + } + ++it; + } + } + + gestureTargetsAtHotSpots(ignoredGestures, Qt::ReceivePartialGestures, + &cachedItemGestures, &targetsSet, 0, 0); + + cachedTargetItems = targetsSet.toList(); + qSort(cachedTargetItems.begin(), cachedTargetItems.end(), qt_closestItemFirst); DEBUG() << "QGraphicsScenePrivate::gestureEventHandler:" - << "new targets:" << targetItems; + << "new targets:" << cachedTargetItems; i = -1; // start delivery again continue; } } + foreach (QGesture *g, startedGestures) { if (g->gestureCancelPolicy() == QGesture::CancelAllInContext) { DEBUG() << "lets try to cancel some"; // find gestures in context in Qt::GestureStarted or Qt::GestureUpdated state and cancel them - cancelGesturesForChildren(g, event->widget()); + cancelGesturesForChildren(g); } } @@ -6154,9 +6189,13 @@ void QGraphicsScenePrivate::gestureEventHandler(QGestureEvent *event) break; } } + + cachedTargetItems.clear(); + cachedItemGestures.clear(); + cachedAlreadyDeliveredGestures.clear(); } -void QGraphicsScenePrivate::cancelGesturesForChildren(QGesture *original, QWidget *viewport) +void QGraphicsScenePrivate::cancelGesturesForChildren(QGesture *original) { Q_ASSERT(original); QGraphicsItem *originalItem = gestureTargets.value(original); @@ -6212,8 +6251,7 @@ void QGraphicsScenePrivate::cancelGesturesForChildren(QGesture *original, QWidge if (!g->hasHotSpot()) continue; - QPoint screenPos = g->hotSpot().toPoint(); - QList<QGraphicsItem *> items = itemsAtPosition(screenPos, QPointF(), viewport); + QList<QGraphicsItem *> items = itemsAtPosition(QPoint(), g->d_func()->sceneHotSpot, 0); for (int j = 0; j < items.size(); ++j) { QGraphicsObject *item = items.at(j)->toGraphicsObject(); if (!item) diff --git a/src/gui/graphicsview/qgraphicsscene_p.h b/src/gui/graphicsview/qgraphicsscene_p.h index 04ffe0f..ca8b829 100644 --- a/src/gui/graphicsview/qgraphicsscene_p.h +++ b/src/gui/graphicsview/qgraphicsscene_p.h @@ -294,13 +294,18 @@ public: bool allItemsIgnoreTouchEvents; void enableTouchEventsOnViews(); + QList<QGraphicsObject *> cachedTargetItems; + QHash<QGraphicsObject *, QSet<QGesture *> > cachedItemGestures; + QHash<QGraphicsObject *, QSet<QGesture *> > cachedAlreadyDeliveredGestures; QHash<QGesture *, QGraphicsObject *> gestureTargets; void gestureEventHandler(QGestureEvent *event); - void getGestureTargets(const QSet<QGesture *> &gestures, QWidget *viewport, - QMap<Qt::GestureType, QGesture *> *conflictedGestures, - QList<QList<QGraphicsObject *> > *conflictedItems, - QHash<QGesture *, QGraphicsObject *> *normalGestures); - void cancelGesturesForChildren(QGesture *original, QWidget *viewport); + void gestureTargetsAtHotSpots(const QSet<QGesture *> &gestures, + Qt::GestureFlag flag, + QHash<QGraphicsObject *, QSet<QGesture *> > *targets, + QSet<QGraphicsObject *> *itemsSet = 0, + QSet<QGesture *> *normal = 0, + QSet<QGesture *> *conflicts = 0); + void cancelGesturesForChildren(QGesture *original); void updateInputMethodSensitivityInViews(); diff --git a/src/gui/graphicsview/qgraphicsview_p.h b/src/gui/graphicsview/qgraphicsview_p.h index 9d3edcb..729837a 100644 --- a/src/gui/graphicsview/qgraphicsview_p.h +++ b/src/gui/graphicsview/qgraphicsview_p.h @@ -65,7 +65,7 @@ QT_BEGIN_NAMESPACE -class Q_AUTOTEST_EXPORT QGraphicsViewPrivate : public QAbstractScrollAreaPrivate +class Q_GUI_EXPORT QGraphicsViewPrivate : public QAbstractScrollAreaPrivate { Q_DECLARE_PUBLIC(QGraphicsView) public: diff --git a/src/gui/graphicsview/qgraphicswidget.cpp b/src/gui/graphicsview/qgraphicswidget.cpp index 5e01785..87416b4 100644 --- a/src/gui/graphicsview/qgraphicswidget.cpp +++ b/src/gui/graphicsview/qgraphicswidget.cpp @@ -967,6 +967,36 @@ void QGraphicsWidget::setPalette(const QPalette &palette) } /*! + \property QGraphicsWidget::autoFillBackground + \brief whether the widget background is filled automatically + \since 4.7 + + If enabled, this property will cause Qt to fill the background of the + widget before invoking the paint() method. The color used is defined by the + QPalette::Window color role from the widget's \l{QPalette}{palette}. + + In addition, Windows are always filled with QPalette::Window, unless the + WA_OpaquePaintEvent or WA_NoSystemBackground attributes are set. + + By default, this property is false. + + \sa Qt::WA_OpaquePaintEvent, Qt::WA_NoSystemBackground, +*/ +bool QGraphicsWidget::autoFillBackground() const +{ + Q_D(const QGraphicsWidget); + return d->autoFillBackground; +} +void QGraphicsWidget::setAutoFillBackground(bool enabled) +{ + Q_D(QGraphicsWidget); + if (d->autoFillBackground != enabled) { + d->autoFillBackground = enabled; + update(); + } +} + +/*! If this widget is currently managed by a layout, this function notifies the layout that the widget's size hints have changed and the layout may need to resize and reposition the widget accordingly. diff --git a/src/gui/graphicsview/qgraphicswidget.h b/src/gui/graphicsview/qgraphicswidget.h index f1d382b..4bea5be 100644 --- a/src/gui/graphicsview/qgraphicswidget.h +++ b/src/gui/graphicsview/qgraphicswidget.h @@ -82,6 +82,7 @@ class Q_GUI_EXPORT QGraphicsWidget : public QGraphicsObject, public QGraphicsLay Q_PROPERTY(Qt::WindowFlags windowFlags READ windowFlags WRITE setWindowFlags) Q_PROPERTY(QString windowTitle READ windowTitle WRITE setWindowTitle) Q_PROPERTY(QRectF geometry READ geometry WRITE setGeometry) + Q_PROPERTY(bool autoFillBackground READ autoFillBackground WRITE setAutoFillBackground) public: QGraphicsWidget(QGraphicsItem *parent = 0, Qt::WindowFlags wFlags = 0); ~QGraphicsWidget(); @@ -103,6 +104,9 @@ public: QPalette palette() const; void setPalette(const QPalette &palette); + bool autoFillBackground() const; + void setAutoFillBackground(bool enabled); + void resize(const QSizeF &size); inline void resize(qreal w, qreal h) { resize(QSizeF(w, h)); } QSizeF size() const; diff --git a/src/gui/graphicsview/qgraphicswidget_p.h b/src/gui/graphicsview/qgraphicswidget_p.h index 2c5b3bf..3ab8737 100644 --- a/src/gui/graphicsview/qgraphicswidget_p.h +++ b/src/gui/graphicsview/qgraphicswidget_p.h @@ -80,6 +80,7 @@ public: inSetGeometry(0), polished(0), inSetPos(0), + autoFillBackground(0), focusPolicy(Qt::NoFocus), focusNext(0), focusPrev(0), @@ -172,6 +173,7 @@ public: quint32 inSetGeometry : 1; quint32 polished: 1; quint32 inSetPos : 1; + quint32 autoFillBackground : 1; // Focus Qt::FocusPolicy focusPolicy; diff --git a/src/gui/image/image.pri b/src/gui/image/image.pri index b67be55..8d75fdd 100644 --- a/src/gui/image/image.pri +++ b/src/gui/image/image.pri @@ -96,6 +96,7 @@ SOURCES += \ unix:LIBS_PRIVATE += -lpng win32:LIBS += libpng.lib } else { + DEFINES *= QT_USE_BUNDLED_LIBPNG !isEqual(QT_ARCH, i386):!isEqual(QT_ARCH, x86_64):DEFINES += PNG_NO_ASSEMBLER_CODE INCLUDEPATH += ../3rdparty/libpng ../3rdparty/zlib SOURCES += ../3rdparty/libpng/png.c \ @@ -112,8 +113,7 @@ SOURCES += \ ../3rdparty/libpng/pngwio.c \ ../3rdparty/libpng/pngwrite.c \ ../3rdparty/libpng/pngwtran.c \ - ../3rdparty/libpng/pngwutil.c \ - ../3rdparty/libpng/pnggccrd.c + ../3rdparty/libpng/pngwutil.c } } else { DEFINES *= QT_NO_IMAGEFORMAT_PNG diff --git a/src/gui/image/qimage.cpp b/src/gui/image/qimage.cpp index 4f5efa1..6bcf72b 100644 --- a/src/gui/image/qimage.cpp +++ b/src/gui/image/qimage.cpp @@ -1835,7 +1835,7 @@ void QImage::setColor(int i, QRgb c) qAlpha() to access the pixels. \sa bytesPerLine(), bits(), {QImage#Pixel Manipulation}{Pixel - Manipulation} + Manipulation}, constScanLine() */ uchar *QImage::scanLine(int i) { @@ -1865,6 +1865,28 @@ const uchar *QImage::scanLine(int i) const /*! + Returns a pointer to the pixel data at the scanline with index \a + i. The first scanline is at index 0. + + The scanline data is aligned on a 32-bit boundary. + + Note that QImage uses \l{Implicit Data Sharing} {implicit data + sharing}, but this function does \e not perform a deep copy of the + shared pixel data, because the returned data is const. + + \sa scanLine(), constBits() + \since 4.7 +*/ +const uchar *QImage::constScanLine(int i) const +{ + if (!d) + return 0; + + Q_ASSERT(i >= 0 && i < height()); + return d->data + i * d->bytes_per_line; +} + +/*! Returns a pointer to the first pixel data. This is equivalent to scanLine(0). @@ -1873,7 +1895,7 @@ const uchar *QImage::scanLine(int i) const data, thus ensuring that this QImage is the only one using the current return value. - \sa scanLine(), byteCount() + \sa scanLine(), byteCount(), constBits() */ uchar *QImage::bits() { @@ -1901,6 +1923,20 @@ const uchar *QImage::bits() const } +/*! + Returns a pointer to the first pixel data. + + Note that QImage uses \l{Implicit Data Sharing} {implicit data + sharing}, but this function does \e not perform a deep copy of the + shared pixel data, because the returned data is const. + + \sa bits(), constScanLine() + \since 4.7 +*/ +const uchar *QImage::constBits() const +{ + return d ? d->data : 0; +} /*! \fn void QImage::reset() diff --git a/src/gui/image/qimage.h b/src/gui/image/qimage.h index ac973a1..dd13782 100644 --- a/src/gui/image/qimage.h +++ b/src/gui/image/qimage.h @@ -182,6 +182,7 @@ public: uchar *bits(); const uchar *bits() const; + const uchar *constBits() const; #ifdef QT_DEPRECATED QT_DEPRECATED int numBytes() const; #endif @@ -189,6 +190,7 @@ public: uchar *scanLine(int); const uchar *scanLine(int) const; + const uchar *constScanLine(int) const; int bytesPerLine() const; bool valid(int x, int y) const; diff --git a/src/gui/image/qpaintengine_pic.cpp b/src/gui/image/qpaintengine_pic.cpp index 1aeb524..029154b 100644 --- a/src/gui/image/qpaintengine_pic.cpp +++ b/src/gui/image/qpaintengine_pic.cpp @@ -486,8 +486,11 @@ void QPicturePaintEngine::drawTextItem(const QPointF &p , const QTextItem &ti) qDebug() << " -> drawTextItem():" << p << ti.text(); #endif + const QTextItemInt &si = static_cast<const QTextItemInt &>(ti); + if (si.chars == 0) + QPaintEngine::drawTextItem(p, ti); // Draw as path + if (d->pic_d->formatMajor >= 9) { - const QTextItemInt &si = static_cast<const QTextItemInt &>(ti); int pos; SERIALIZE_CMD(QPicturePrivate::PdcDrawTextItem); QFont fnt = ti.font(); diff --git a/src/gui/image/qpicture.cpp b/src/gui/image/qpicture.cpp index fb70e36..3220a67 100644 --- a/src/gui/image/qpicture.cpp +++ b/src/gui/image/qpicture.cpp @@ -440,36 +440,6 @@ bool QPicture::play(QPainter *painter) return true; // no end-command } - -// -// QFakeDevice is used to create fonts with a custom DPI -// -class QFakeDevice : public QPaintDevice -{ -public: - QFakeDevice() { dpi_x = qt_defaultDpiX(); dpi_y = qt_defaultDpiY(); } - void setDpiX(int dpi) { dpi_x = dpi; } - void setDpiY(int dpi) { dpi_y = dpi; } - QPaintEngine *paintEngine() const { return 0; } - int metric(PaintDeviceMetric m) const - { - switch(m) { - case PdmPhysicalDpiX: - case PdmDpiX: - return dpi_x; - case PdmPhysicalDpiY: - case PdmDpiY: - return dpi_y; - default: - return QPaintDevice::metric(m); - } - } - -private: - int dpi_x; - int dpi_y; -}; - /*! \internal Iterates over the internal picture data and draws the picture using @@ -679,30 +649,29 @@ bool QPicture::exec(QPainter *painter, QDataStream &s, int nrecords) if (d->formatMajor >= 9) { s >> dbl; - QFont fnt(font); - if (dbl != 1.0) { - QFakeDevice fake; - fake.setDpiX(qRound(dbl*qt_defaultDpiX())); - fake.setDpiY(qRound(dbl*qt_defaultDpiY())); - fnt = QFont(font, &fake); - } + QFont fnt(font, painter->device()); + + qreal scale = painter->device()->logicalDpiY() / (dbl*qt_defaultDpiY()); + painter->save(); + painter->scale(1/scale, 1/scale); qreal justificationWidth; s >> justificationWidth; int flags = Qt::TextSingleLine | Qt::TextDontClip | Qt::TextForceLeftToRight; - QSizeF size(1, 1); + QSizeF size(scale, scale); if (justificationWidth > 0) { - size.setWidth(justificationWidth); + size.setWidth(justificationWidth*scale); flags |= Qt::TextJustificationForced; flags |= Qt::AlignJustify; } QFontMetrics fm(fnt); - QPointF pt(p.x(), p.y() - fm.ascent()); + QPointF pt(p.x()*scale, p.y()*scale - fm.ascent()); qt_format_text(fnt, QRectF(pt, size), flags, /*opt*/0, str, /*brect=*/0, /*tabstops=*/0, /*...*/0, /*tabarraylen=*/0, painter); + painter->restore(); } else { qt_format_text(font, QRectF(p, QSizeF(1, 1)), Qt::TextSingleLine | Qt::TextDontClip, /*opt*/0, str, /*brect=*/0, /*tabstops=*/0, /*...*/0, /*tabarraylen=*/0, painter); diff --git a/src/gui/image/qpixmap.cpp b/src/gui/image/qpixmap.cpp index 1df7946..ae62f06 100644 --- a/src/gui/image/qpixmap.cpp +++ b/src/gui/image/qpixmap.cpp @@ -1078,6 +1078,9 @@ QPixmap QPixmap::grabWidget(QWidget * widget, const QRect &rect) if (widget->testAttribute(Qt::WA_PendingResizeEvent) || !widget->testAttribute(Qt::WA_WState_Created)) sendResizeEvents(widget); + widget->d_func()->prepareToRender(QRegion(), + QWidget::DrawWindowBackground | QWidget::DrawChildren | QWidget::IgnoreMask); + QRect r(rect); if (r.width() < 0) r.setWidth(widget->width() - rect.x()); @@ -1088,8 +1091,8 @@ QPixmap QPixmap::grabWidget(QWidget * widget, const QRect &rect) return QPixmap(); QPixmap res(r.size()); - widget->render(&res, QPoint(), r, - QWidget::DrawWindowBackground | QWidget::DrawChildren | QWidget::IgnoreMask); + widget->d_func()->render(&res, QPoint(), r, QWidget::DrawWindowBackground + | QWidget::DrawChildren | QWidget::IgnoreMask, true); return res; } @@ -1370,10 +1373,27 @@ void QPixmap::deref() */ /*! - \fn bool QPixmap::convertFromImage(const QImage &image, Qt::ImageConversionFlags flags) + Replaces this pixmap's data with the given \a image using the + specified \a flags to control the conversion. The \a flags + argument is a bitwise-OR of the \l{Qt::ImageConversionFlags}. + Passing 0 for \a flags sets all the default options. Returns true + if the result is that this pixmap is not null. - Use the static fromImage() function instead. + Note: this function was part of Qt 3 support in Qt 4.6 and earlier. + It has been promoted to official API status in 4.7 to support updating + the pixmap's image without creating a new QPixmap as fromImage() would. + + \sa fromImage() + \since 4.7 */ +bool QPixmap::convertFromImage(const QImage &image, Qt::ImageConversionFlags flags) +{ + if (image.isNull() || !data) + *this = QPixmap::fromImage(image, flags); + else + data->fromImage(image, flags); + return !isNull(); +} /*! \fn QPixmap QPixmap::xForm(const QMatrix &matrix) const diff --git a/src/gui/image/qpixmap.h b/src/gui/image/qpixmap.h index 46363f0..180af3b 100644 --- a/src/gui/image/qpixmap.h +++ b/src/gui/image/qpixmap.h @@ -141,6 +141,8 @@ public: bool save(const QString& fileName, const char* format = 0, int quality = -1) const; bool save(QIODevice* device, const char* format = 0, int quality = -1) const; + bool convertFromImage(const QImage &img, Qt::ImageConversionFlags flags = Qt::AutoColor); + #if defined(Q_WS_WIN) enum HBitmapFormat { NoAlpha, @@ -224,8 +226,6 @@ public: QT3_SUPPORT QPixmap &operator=(const QImage &); inline QT3_SUPPORT QImage convertToImage() const { return toImage(); } QT3_SUPPORT bool convertFromImage(const QImage &, ColorMode mode); - QT3_SUPPORT bool convertFromImage(const QImage &img, Qt::ImageConversionFlags flags = Qt::AutoColor) - { (*this) = fromImage(img, flags); return !isNull(); } inline QT3_SUPPORT operator QImage() const { return toImage(); } inline QT3_SUPPORT QPixmap xForm(const QMatrix &matrix) const { return transformed(QTransform(matrix)); } inline QT3_SUPPORT bool selfMask() const { return false; } diff --git a/src/gui/image/qpixmap_x11.cpp b/src/gui/image/qpixmap_x11.cpp index e1e8a0d..b976376 100644 --- a/src/gui/image/qpixmap_x11.cpp +++ b/src/gui/image/qpixmap_x11.cpp @@ -1142,7 +1142,7 @@ void QX11PixmapData::fromImage(const QImage &img, } } -void QX11PixmapData::bitmapFromImage(const QImage &image) +Qt::HANDLE QX11PixmapData::createBitmapFromImage(const QImage &image) { QImage img = image.convertToFormat(QImage::Format_MonoLSB); const QRgb c0 = QColor(Qt::black).rgb(); @@ -1155,10 +1155,8 @@ void QX11PixmapData::bitmapFromImage(const QImage &image) char *bits; uchar *tmp_bits; - w = img.width(); - h = img.height(); - d = 1; - is_null = (w <= 0 || h <= 0); + int w = img.width(); + int h = img.height(); int bpl = (w + 7) / 8; int ibpl = img.bytesPerLine(); if (bpl != ibpl) { @@ -1177,18 +1175,26 @@ void QX11PixmapData::bitmapFromImage(const QImage &image) bits = (char *)img.bits(); tmp_bits = 0; } - hd = (Qt::HANDLE)XCreateBitmapFromData(xinfo.display(), - RootWindow(xinfo.display(), xinfo.screen()), + Qt::HANDLE hd = (Qt::HANDLE)XCreateBitmapFromData(X11->display, + QX11Info::appRootWindow(), bits, w, h); + if (tmp_bits) // Avoid purify complaint + delete [] tmp_bits; + return hd; +} +void QX11PixmapData::bitmapFromImage(const QImage &image) +{ + w = image.width(); + h = image.height(); + d = 1; + is_null = (w <= 0 || h <= 0); + hd = createBitmapFromImage(image); #ifndef QT_NO_XRENDER if (X11->use_xrender) picture = XRenderCreatePicture(X11->display, hd, XRenderFindStandardFormat(X11->display, PictStandardA1), 0, 0); #endif // QT_NO_XRENDER - - if (tmp_bits) // Avoid purify complaint - delete [] tmp_bits; } void QX11PixmapData::fill(const QColor &fillColor) diff --git a/src/gui/image/qpixmap_x11_p.h b/src/gui/image/qpixmap_x11_p.h index 20fb654..0c0a9bd 100644 --- a/src/gui/image/qpixmap_x11_p.h +++ b/src/gui/image/qpixmap_x11_p.h @@ -92,6 +92,8 @@ public: Qt::HANDLE handle() const { return hd; } Qt::HANDLE x11ConvertToDefaultDepth(); + static Qt::HANDLE createBitmapFromImage(const QImage &image); + protected: int metric(QPaintDevice::PaintDeviceMetric metric) const; diff --git a/src/gui/image/qpnghandler.cpp b/src/gui/image/qpnghandler.cpp index d5406cb..dd31834 100644 --- a/src/gui/image/qpnghandler.cpp +++ b/src/gui/image/qpnghandler.cpp @@ -50,8 +50,13 @@ #include <qvariant.h> #include <qvector.h> +#ifdef QT_USE_BUNDLED_LIBPNG +#include <../../3rdparty/libpng/png.h> +#include <../../3rdparty/libpng/pngconf.h> +#else #include <png.h> #include <pngconf.h> +#endif #ifdef Q_OS_WINCE #define CALLBACK_CALL_TYPE __cdecl @@ -162,11 +167,16 @@ void setup_qt(QImage& image, png_structp png_ptr, png_infop info_ptr, float scre png_uint_32 height; int bit_depth; int color_type; + png_bytep trans_alpha = 0; + png_color_16p trans_color_p = 0; + int num_trans; + png_colorp palette = 0; + int num_palette; png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, 0, 0, 0); if (color_type == PNG_COLOR_TYPE_GRAY) { // Black & White or 8-bit grayscale - if (bit_depth == 1 && info_ptr->channels == 1) { + if (bit_depth == 1 && png_get_channels(png_ptr, info_ptr) == 1) { png_set_invert_mono(png_ptr); png_read_update_info(png_ptr, info_ptr); if (image.size() != QSize(width, height) || image.format() != QImage::Format_Mono) { @@ -207,20 +217,16 @@ void setup_qt(QImage& image, png_structp png_ptr, png_infop info_ptr, float scre int c = i*255/(ncols-1); image.setColor(i, qRgba(c,c,c,0xff)); } - if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { -#if PNG_LIBPNG_VER_MAJOR < 1 || (PNG_LIBPNG_VER_MAJOR == 1 && PNG_LIBPNG_VER_MINOR < 4) - const int g = info_ptr->trans_values.gray; -#else - const int g = info_ptr->trans_color.gray; -#endif + if (png_get_tRNS(png_ptr, info_ptr, &trans_alpha, &num_trans, &trans_color_p) && trans_color_p) { + const int g = trans_color_p->gray; if (g < ncols) { image.setColor(g, 0); } } } } else if (color_type == PNG_COLOR_TYPE_PALETTE - && png_get_valid(png_ptr, info_ptr, PNG_INFO_PLTE) - && info_ptr->num_palette <= 256) + && png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette) + && num_palette <= 256) { // 1-bit and 8-bit color if (bit_depth != 1) @@ -233,29 +239,26 @@ void setup_qt(QImage& image, png_structp png_ptr, png_infop info_ptr, float scre if (image.isNull()) return; } - image.setColorCount(info_ptr->num_palette); + png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette); + image.setColorCount(num_palette); int i = 0; - if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { - while (i < info_ptr->num_trans) { + if (png_get_tRNS(png_ptr, info_ptr, &trans_alpha, &num_trans, &trans_color_p) && trans_alpha) { + while (i < num_trans) { image.setColor(i, qRgba( - info_ptr->palette[i].red, - info_ptr->palette[i].green, - info_ptr->palette[i].blue, -#if PNG_LIBPNG_VER_MAJOR < 1 || (PNG_LIBPNG_VER_MAJOR == 1 && PNG_LIBPNG_VER_MINOR < 4) - info_ptr->trans[i] -#else - info_ptr->trans_alpha[i] -#endif + palette[i].red, + palette[i].green, + palette[i].blue, + trans_alpha[i] ) ); i++; } } - while (i < info_ptr->num_palette) { + while (i < num_palette) { image.setColor(i, qRgba( - info_ptr->palette[i].red, - info_ptr->palette[i].green, - info_ptr->palette[i].blue, + palette[i].red, + palette[i].green, + palette[i].blue, 0xff ) ); @@ -531,33 +534,36 @@ QImage::Format QPngHandlerPrivate::readImageFormat() QImage::Format format = QImage::Format_Invalid; png_uint_32 width, height; int bit_depth, color_type; - if (info_ptr->color_type == PNG_COLOR_TYPE_GRAY) { + png_colorp palette; + int num_palette; + png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, 0, 0, 0); + if (color_type == PNG_COLOR_TYPE_GRAY) { // Black & White or 8-bit grayscale - if (info_ptr->bit_depth == 1 && info_ptr->channels == 1) { + if (bit_depth == 1 && png_get_channels(png_ptr, info_ptr) == 1) { format = QImage::Format_Mono; - } else if (info_ptr->bit_depth == 16 && png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { + } else if (bit_depth == 16 && png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { format = QImage::Format_ARGB32; } else { format = QImage::Format_Indexed8; } - } else if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE - && png_get_valid(png_ptr, info_ptr, PNG_INFO_PLTE) - && info_ptr->num_palette <= 256) + } else if (color_type == PNG_COLOR_TYPE_PALETTE + && png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette) + && num_palette <= 256) { // 1-bit and 8-bit color - if (info_ptr->bit_depth != 1) + if (bit_depth != 1) png_set_packing(png_ptr); png_read_update_info(png_ptr, info_ptr); png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, 0, 0, 0); format = bit_depth == 1 ? QImage::Format_Mono : QImage::Format_Indexed8; } else { // 32-bit - if (info_ptr->bit_depth == 16) + if (bit_depth == 16) png_set_strip_16(png_ptr); format = QImage::Format_ARGB32; // Only add filler if no alpha, or we can get 5 channel data. - if (!(info_ptr->color_type & PNG_COLOR_MASK_ALPHA) + if (!(color_type & PNG_COLOR_MASK_ALPHA) && !png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { // We want 4 bytes, but it isn't an alpha channel format = QImage::Format_RGB32; @@ -648,7 +654,7 @@ static void set_text(const QImage &image, png_structp png_ptr, png_infop info_pt text_ptr[i].text = qstrdup(value.constData()); text_ptr[i].text_length = 0; text_ptr[i].itxt_length = value.size(); - text_ptr[i].lang = "UTF-8"; + text_ptr[i].lang = const_cast<char*>("UTF-8"); text_ptr[i].lang_key = qstrdup(it.key().toUtf8().constData()); #endif ++i; @@ -735,64 +741,51 @@ bool Q_INTERNAL_WIN_NO_THROW QPNGImageWriter::writeImage(const QImage& image_in, png_set_compression_level(png_ptr, quality); } - if (gamma != 0.0) { - png_set_gAMA(png_ptr, info_ptr, 1.0/gamma); - } - png_set_write_fn(png_ptr, (void*)this, qpiw_write_fn, qpiw_flush_fn); - info_ptr->channels = - (image.depth() == 32) - ? (image.format() == QImage::Format_RGB32 ? 3 : 4) - : 1; - png_set_IHDR(png_ptr, info_ptr, image.width(), image.height(), image.depth() == 1 ? 1 : 8 /* per channel */, image.depth() == 32 ? image.format() == QImage::Format_RGB32 ? PNG_COLOR_TYPE_RGB : PNG_COLOR_TYPE_RGB_ALPHA - : PNG_COLOR_TYPE_PALETTE, 0, 0, 0); + : PNG_COLOR_TYPE_PALETTE, 0, 0, 0); // also sets #channels + if (gamma != 0.0) { + png_set_gAMA(png_ptr, info_ptr, 1.0/gamma); + } - //png_set_sBIT(png_ptr, info_ptr, 8); - info_ptr->sig_bit.red = 8; - info_ptr->sig_bit.green = 8; - info_ptr->sig_bit.blue = 8; + png_color_8 sig_bit; + sig_bit.red = 8; + sig_bit.green = 8; + sig_bit.blue = 8; + sig_bit.alpha = image.hasAlphaChannel() ? 8 : 0; + png_set_sBIT(png_ptr, info_ptr, &sig_bit); if (image.format() == QImage::Format_MonoLSB) png_set_packswap(png_ptr); - png_colorp palette = 0; - png_bytep copy_trans = 0; if (image.colorCount()) { // Paletted - int num_palette = image.colorCount(); - palette = new png_color[num_palette]; - png_set_PLTE(png_ptr, info_ptr, palette, num_palette); - int* trans = new int[num_palette]; + int num_palette = qMin(256, image.colorCount()); + png_color palette[256]; + png_byte trans[256]; int num_trans = 0; for (int i=0; i<num_palette; i++) { - QRgb rgb=image.color(i); - info_ptr->palette[i].red = qRed(rgb); - info_ptr->palette[i].green = qGreen(rgb); - info_ptr->palette[i].blue = qBlue(rgb); - trans[i] = rgb >> 24; + QRgb rgba=image.color(i); + palette[i].red = qRed(rgba); + palette[i].green = qGreen(rgba); + palette[i].blue = qBlue(rgba); + trans[i] = qAlpha(rgba); if (trans[i] < 255) { num_trans = i+1; } } + png_set_PLTE(png_ptr, info_ptr, palette, num_palette); + if (num_trans) { - copy_trans = new png_byte[num_trans]; - for (int i=0; i<num_trans; i++) - copy_trans[i] = trans[i]; - png_set_tRNS(png_ptr, info_ptr, copy_trans, num_trans, 0); + png_set_tRNS(png_ptr, info_ptr, trans, num_trans, 0); } - delete [] trans; - } - - if (image.format() != QImage::Format_RGB32) { - info_ptr->sig_bit.alpha = 8; } // Swap ARGB to RGBA (normal PNG format) before saving on @@ -868,11 +861,6 @@ bool Q_INTERNAL_WIN_NO_THROW QPNGImageWriter::writeImage(const QImage& image_in, png_write_end(png_ptr, info_ptr); frames_written++; - if (palette) - delete [] palette; - if (copy_trans) - delete [] copy_trans; - png_destroy_write_struct(&png_ptr, &info_ptr); return true; @@ -958,7 +946,8 @@ QVariant QPngHandler::option(ImageOption option) const else if (option == Description) return d->description; else if (option == Size) - return QSize(d->info_ptr->width, d->info_ptr->height); + return QSize(png_get_image_width(d->png_ptr, d->info_ptr), + png_get_image_height(d->png_ptr, d->info_ptr)); else if (option == ImageFormat) return d->readImageFormat(); return 0; diff --git a/src/gui/inputmethod/qwininputcontext_p.h b/src/gui/inputmethod/qwininputcontext_p.h index 08cc3d2..d5bedf4 100644 --- a/src/gui/inputmethod/qwininputcontext_p.h +++ b/src/gui/inputmethod/qwininputcontext_p.h @@ -56,7 +56,7 @@ #include "QtGui/qinputcontext.h" #include "QtCore/qt_windows.h" -#if defined(Q_CC_MINGW) && !defined(IMR_RECONVERTSTRING) +#if !defined(IMR_RECONVERTSTRING) typedef struct tagRECONVERTSTRING { DWORD dwSize; DWORD dwVersion; diff --git a/src/gui/itemviews/qdirmodel.cpp b/src/gui/itemviews/qdirmodel.cpp index ea608c1..378a238 100644 --- a/src/gui/itemviews/qdirmodel.cpp +++ b/src/gui/itemviews/qdirmodel.cpp @@ -185,12 +185,12 @@ void QDirModelPrivate::invalidate() /*! \class QDirModel - + \obsolete \brief The QDirModel class provides a data model for the local filesystem. \ingroup model-view - \note The usage of QDirModel is not recommended anymore. The + The usage of QDirModel is not recommended anymore. The QFileSystemModel class is a more performant alternative. This class provides access to the local filesystem, providing functions diff --git a/src/gui/itemviews/qfileiconprovider.cpp b/src/gui/itemviews/qfileiconprovider.cpp index fcc61e5..f321ab3 100644 --- a/src/gui/itemviews/qfileiconprovider.cpp +++ b/src/gui/itemviews/qfileiconprovider.cpp @@ -73,7 +73,7 @@ QT_BEGIN_NAMESPACE /*! \class QFileIconProvider - \brief The QFileIconProvider class provides file icons for the QDirModel class. + \brief The QFileIconProvider class provides file icons for the QDirModel and the QFileSystemModel classes. */ /*! diff --git a/src/gui/itemviews/qheaderview.cpp b/src/gui/itemviews/qheaderview.cpp index 8a456e6..5128b64 100644 --- a/src/gui/itemviews/qheaderview.cpp +++ b/src/gui/itemviews/qheaderview.cpp @@ -1853,11 +1853,9 @@ void QHeaderViewPrivate::_q_layoutChanged() persistentHiddenSections.clear(); return; } + + QBitArray oldSectionHidden = sectionHidden; bool sectionCountChanged = false; - for (int i = 0; i < sectionHidden.count(); ++i) { - if (sectionHidden.testBit(i)) - q->setSectionHidden(logicalIndex(i), false); - } for (int i = 0; i < persistentHiddenSections.count(); ++i) { QModelIndex index = persistentHiddenSections.at(i); @@ -1866,6 +1864,7 @@ void QHeaderViewPrivate::_q_layoutChanged() ? index.column() : index.row()); q->setSectionHidden(logical, true); + oldSectionHidden.setBit(logical, false); } else if (!sectionCountChanged && (modelSectionCount() != sectionCount)) { sectionCountChanged = true; break; @@ -1873,6 +1872,11 @@ void QHeaderViewPrivate::_q_layoutChanged() } persistentHiddenSections.clear(); + for (int i = 0; i < oldSectionHidden.count(); ++i) { + if (oldSectionHidden.testBit(i)) + q->setSectionHidden(logicalIndex(i), false); + } + // the number of sections changed; we need to reread the state of the model if (sectionCountChanged) q->initializeSections(); @@ -2217,7 +2221,8 @@ void QHeaderView::mouseMoveEvent(QMouseEvent *e) return; } case QHeaderViewPrivate::MoveSection: { - if (qAbs(pos - d->firstPos) >= QApplication::startDragDistance()) { + if (qAbs(pos - d->firstPos) >= QApplication::startDragDistance() + || !d->sectionIndicator->isHidden()) { int indicatorCenter = (d->orientation == Qt::Horizontal ? d->sectionIndicator->width() : d->sectionIndicator->height()) / 2; @@ -2229,12 +2234,6 @@ void QHeaderView::mouseMoveEvent(QMouseEvent *e) return; d->target = d->logicalIndex(visual); d->updateSectionIndicator(d->section, pos); - } else { - int visual = visualIndexAt(d->firstPos); - if (visual == -1) - return; - d->target = d->logicalIndex(visual); - d->updateSectionIndicator(d->section, d->firstPos); } return; } @@ -2300,7 +2299,7 @@ void QHeaderView::mouseReleaseEvent(QMouseEvent *e) int section = logicalIndexAt(pos); if (section != -1 && section == d->pressed) { d->flipSortIndicator(section); - emit sectionClicked(logicalIndexAt(pos)); + emit sectionClicked(section); } if (d->pressed != -1) updateSection(d->pressed); diff --git a/src/gui/itemviews/qsortfilterproxymodel.cpp b/src/gui/itemviews/qsortfilterproxymodel.cpp index 41c984e..c63a07b 100644 --- a/src/gui/itemviews/qsortfilterproxymodel.cpp +++ b/src/gui/itemviews/qsortfilterproxymodel.cpp @@ -270,6 +270,11 @@ void QSortFilterProxyModelPrivate::clear_mapping() qDeleteAll(source_index_mapping); source_index_mapping.clear(); + if (dynamic_sortfilter && update_source_sort_column()) { + //update_source_sort_column might have created wrong mapping so we have to clear it again + qDeleteAll(source_index_mapping); + source_index_mapping.clear(); + } // update the persistent indexes update_persistent_indexes(source_indexes); @@ -558,7 +563,7 @@ QVector<QPair<int, QVector<int > > > QSortFilterProxyModelPrivate::proxy_interva int proxy_item = 0; int source_items_index = 0; QVector<int> source_items_in_interval; - bool compare = (orient == Qt::Vertical && source_sort_column >= 0); + bool compare = (orient == Qt::Vertical && source_sort_column >= 0 && dynamic_sortfilter); while (source_items_index < source_items.size()) { source_items_in_interval.clear(); int first_new_source_item = source_items.at(source_items_index); @@ -1208,11 +1213,6 @@ void QSortFilterProxyModelPrivate::_q_sourceLayoutAboutToBeChanged() void QSortFilterProxyModelPrivate::_q_sourceLayoutChanged() { Q_Q(QSortFilterProxyModel); - if (saved_persistent_indexes.isEmpty()) { - clear_mapping(); - emit q->layoutChanged(); - return; - } qDeleteAll(source_index_mapping); source_index_mapping.clear(); @@ -1220,7 +1220,11 @@ void QSortFilterProxyModelPrivate::_q_sourceLayoutChanged() update_persistent_indexes(saved_persistent_indexes); saved_persistent_indexes.clear(); - update_source_sort_column(); + if (dynamic_sortfilter && update_source_sort_column()) { + //update_source_sort_column might have created wrong mapping so we have to clear it again + qDeleteAll(source_index_mapping); + source_index_mapping.clear(); + } emit q->layoutChanged(); } @@ -1240,7 +1244,7 @@ void QSortFilterProxyModelPrivate::_q_sourceRowsInserted( const QModelIndex &source_parent, int start, int end) { source_items_inserted(source_parent, start, end, Qt::Vertical); - if (update_source_sort_column()) //previous call to update_source_sort_column may fail if the model has no column. + if (update_source_sort_column() && dynamic_sortfilter) //previous call to update_source_sort_column may fail if the model has no column. sort(); // now it should succeed so we need to make sure to sort again } @@ -1277,8 +1281,8 @@ void QSortFilterProxyModelPrivate::_q_sourceColumnsInserted( if (source_parent.isValid()) return; //we sort according to the root column only if (source_sort_column == -1) { - //we update the source_sort_column depending on the prox_sort_column - if (update_source_sort_column()) + //we update the source_sort_column depending on the proxy_sort_column + if (update_source_sort_column() && dynamic_sortfilter) sort(); } else { if (start <= source_sort_column) @@ -1481,7 +1485,6 @@ QSortFilterProxyModel::QSortFilterProxyModel(QObject *parent) d->filter_column = 0; d->filter_role = Qt::DisplayRole; d->dynamic_sortfilter = false; - connect(this, SIGNAL(modelReset()), this, SLOT(invalidate())); } /*! diff --git a/src/gui/itemviews/qtreeview.cpp b/src/gui/itemviews/qtreeview.cpp index 706d2a8..37168eb 100644 --- a/src/gui/itemviews/qtreeview.cpp +++ b/src/gui/itemviews/qtreeview.cpp @@ -3770,10 +3770,15 @@ void QTreeViewPrivate::rowsRemoved(const QModelIndex &parent, if (previousSibiling != -1 && after && model->rowCount(parent) == start) viewItems[previousSibiling].hasMoreSiblings = false; - - updateChildCount(parentItem, -removedCount); - if (parentItem != -1 && viewItems.at(parentItem).total == 0) - viewItems[parentItem].hasChildren = false; //every children have been removed; + if (parentItem != -1) { + if (viewItems.at(parentItem).expanded) { + updateChildCount(parentItem, -removedCount); + if (viewItems.at(parentItem).total == 0) + viewItems[parentItem].hasChildren = false; //every children have been removed; + } else if (viewItems[parentItem].hasChildren && !hasVisibleChildren(parent)) { + viewItems[parentItem].hasChildren = false; + } + } if (after) { q->updateGeometries(); viewport->update(); diff --git a/src/gui/kernel/kernel.pri b/src/gui/kernel/kernel.pri index 0993b86..6fd45ad 100644 --- a/src/gui/kernel/kernel.pri +++ b/src/gui/kernel/kernel.pri @@ -206,6 +206,7 @@ embedded { OBJECTIVE_HEADERS += \ qcocoawindow_mac_p.h \ + qcocoapanel_mac_p.h \ qcocoawindowdelegate_mac_p.h \ qcocoaview_mac_p.h \ qcocoaapplication_mac_p.h \ diff --git a/src/gui/kernel/qaction.h b/src/gui/kernel/qaction.h index 4341367..538b04f 100644 --- a/src/gui/kernel/qaction.h +++ b/src/gui/kernel/qaction.h @@ -246,6 +246,9 @@ private: friend class QMenuBar; friend class QShortcutMap; friend class QToolButton; +#ifdef Q_WS_MAC + friend void qt_mac_clear_status_text(QAction *action); +#endif }; QT_BEGIN_INCLUDE_NAMESPACE diff --git a/src/gui/kernel/qapplication.cpp b/src/gui/kernel/qapplication.cpp index 4fe3900..4ec2ae2 100644 --- a/src/gui/kernel/qapplication.cpp +++ b/src/gui/kernel/qapplication.cpp @@ -122,15 +122,19 @@ extern bool qt_wince_is_pocket_pc(); //qguifunctions_wince.cpp static void initResources() { #if defined(Q_WS_WINCE) + Q_INIT_RESOURCE_EXTERN(qstyle_wince) Q_INIT_RESOURCE(qstyle_wince); #elif defined(Q_OS_SYMBIAN) + Q_INIT_RESOURCE_EXTERN(qstyle_s60) Q_INIT_RESOURCE(qstyle_s60); #else + Q_INIT_RESOURCE_EXTERN(qstyle) Q_INIT_RESOURCE(qstyle); #endif - + Q_INIT_RESOURCE_EXTERN(qmessagebox) Q_INIT_RESOURCE(qmessagebox); #if !defined(QT_NO_PRINTDIALOG) + Q_INIT_RESOURCE_EXTERN(qprintdialog) Q_INIT_RESOURCE(qprintdialog); #endif @@ -182,6 +186,15 @@ QApplicationPrivate::QApplicationPrivate(int &argc, char **argv, QApplication::T gestureManager = 0; gestureWidget = 0; +#if defined(Q_WS_X11) || defined(Q_WS_WIN) + move_cursor = 0; + copy_cursor = 0; + link_cursor = 0; +#endif +#if defined(Q_WS_WIN) + ignore_cursor = 0; +#endif + if (!self) self = this; } @@ -925,7 +938,7 @@ void QApplicationPrivate::initialize() // Set up which span functions should be used in raster engine... qInitDrawhelperAsm(); - + #if !defined(Q_WS_X11) && !defined(Q_WS_QWS) // initialize the graphics system - on X11 this is initialized inside // qt_init() in qapplication_x11.cpp because of several reasons. @@ -1032,6 +1045,15 @@ QApplication::~QApplication() qt_clipboard = 0; #endif +#if defined(Q_WS_X11) || defined(Q_WS_WIN) + delete d->move_cursor; d->move_cursor = 0; + delete d->copy_cursor; d->copy_cursor = 0; + delete d->link_cursor; d->link_cursor = 0; +#endif +#if defined(Q_WS_WIN) + delete d->ignore_cursor; d->ignore_cursor = 0; +#endif + delete QWidgetPrivate::mapper; QWidgetPrivate::mapper = 0; @@ -5246,10 +5268,20 @@ QInputContext *QApplication::inputContext() const qic = QInputContextFactory::create(QLatin1String("xim"), that); that->d_func()->inputContext = qic; } -#elif defined(Q_WS_S60) +#elif defined(Q_OS_SYMBIAN) if (!d->inputContext) { QApplication *that = const_cast<QApplication *>(this); - that->d_func()->inputContext = QInputContextFactory::create(QString::fromLatin1("coefep"), that); + const QStringList keys = QInputContextFactory::keys(); + // Try hbim and coefep first, then try others. + if (keys.contains("hbim")) { + that->d_func()->inputContext = QInputContextFactory::create(QLatin1String("hbim"), that); + } else if (keys.contains("coefep")) { + that->d_func()->inputContext = QInputContextFactory::create(QLatin1String("coefep"), that); + } else { + for (int c = 0; c < keys.size() && !d->inputContext; ++c) { + that->d_func()->inputContext = QInputContextFactory::create(keys[c], that); + } + } } #endif return d->inputContext; @@ -5689,6 +5721,228 @@ QGestureManager* QGestureManager::instance() return qAppPriv->gestureManager; } +// These pixmaps approximate the images in the Windows User Interface Guidelines. + +// XPM + +static const char * const move_xpm[] = { +"11 20 3 1", +". c None", +#if defined(Q_WS_WIN) +"a c #000000", +"X c #FFFFFF", // Windows cursor is traditionally white +#else +"a c #FFFFFF", +"X c #000000", // X11 cursor is traditionally black +#endif +"aa.........", +"aXa........", +"aXXa.......", +"aXXXa......", +"aXXXXa.....", +"aXXXXXa....", +"aXXXXXXa...", +"aXXXXXXXa..", +"aXXXXXXXXa.", +"aXXXXXXXXXa", +"aXXXXXXaaaa", +"aXXXaXXa...", +"aXXaaXXa...", +"aXa..aXXa..", +"aa...aXXa..", +"a.....aXXa.", +"......aXXa.", +".......aXXa", +".......aXXa", +"........aa."}; + +#ifdef Q_WS_WIN +/* XPM */ +static const char * const ignore_xpm[] = { +"24 30 3 1", +". c None", +"a c #000000", +"X c #FFFFFF", +"aa......................", +"aXa.....................", +"aXXa....................", +"aXXXa...................", +"aXXXXa..................", +"aXXXXXa.................", +"aXXXXXXa................", +"aXXXXXXXa...............", +"aXXXXXXXXa..............", +"aXXXXXXXXXa.............", +"aXXXXXXaaaa.............", +"aXXXaXXa................", +"aXXaaXXa................", +"aXa..aXXa...............", +"aa...aXXa...............", +"a.....aXXa..............", +"......aXXa.....XXXX.....", +".......aXXa..XXaaaaXX...", +".......aXXa.XaaaaaaaaX..", +"........aa.XaaaXXXXaaaX.", +"...........XaaaaX..XaaX.", +"..........XaaXaaaX..XaaX", +"..........XaaXXaaaX.XaaX", +"..........XaaX.XaaaXXaaX", +"..........XaaX..XaaaXaaX", +"...........XaaX..XaaaaX.", +"...........XaaaXXXXaaaX.", +"............XaaaaaaaaX..", +".............XXaaaaXX...", +"...............XXXX....."}; +#endif + +/* XPM */ +static const char * const copy_xpm[] = { +"24 30 3 1", +". c None", +"a c #000000", +"X c #FFFFFF", +#if defined(Q_WS_WIN) // Windows cursor is traditionally white +"aa......................", +"aXa.....................", +"aXXa....................", +"aXXXa...................", +"aXXXXa..................", +"aXXXXXa.................", +"aXXXXXXa................", +"aXXXXXXXa...............", +"aXXXXXXXXa..............", +"aXXXXXXXXXa.............", +"aXXXXXXaaaa.............", +"aXXXaXXa................", +"aXXaaXXa................", +"aXa..aXXa...............", +"aa...aXXa...............", +"a.....aXXa..............", +"......aXXa..............", +".......aXXa.............", +".......aXXa.............", +"........aa...aaaaaaaaaaa", +#else +"XX......................", +"XaX.....................", +"XaaX....................", +"XaaaX...................", +"XaaaaX..................", +"XaaaaaX.................", +"XaaaaaaX................", +"XaaaaaaaX...............", +"XaaaaaaaaX..............", +"XaaaaaaaaaX.............", +"XaaaaaaXXXX.............", +"XaaaXaaX................", +"XaaXXaaX................", +"XaX..XaaX...............", +"XX...XaaX...............", +"X.....XaaX..............", +"......XaaX..............", +".......XaaX.............", +".......XaaX.............", +"........XX...aaaaaaaaaaa", +#endif +".............aXXXXXXXXXa", +".............aXXXXXXXXXa", +".............aXXXXaXXXXa", +".............aXXXXaXXXXa", +".............aXXaaaaaXXa", +".............aXXXXaXXXXa", +".............aXXXXaXXXXa", +".............aXXXXXXXXXa", +".............aXXXXXXXXXa", +".............aaaaaaaaaaa"}; + +/* XPM */ +static const char * const link_xpm[] = { +"24 30 3 1", +". c None", +"a c #000000", +"X c #FFFFFF", +#if defined(Q_WS_WIN) // Windows cursor is traditionally white +"aa......................", +"aXa.....................", +"aXXa....................", +"aXXXa...................", +"aXXXXa..................", +"aXXXXXa.................", +"aXXXXXXa................", +"aXXXXXXXa...............", +"aXXXXXXXXa..............", +"aXXXXXXXXXa.............", +"aXXXXXXaaaa.............", +"aXXXaXXa................", +"aXXaaXXa................", +"aXa..aXXa...............", +"aa...aXXa...............", +"a.....aXXa..............", +"......aXXa..............", +".......aXXa.............", +".......aXXa.............", +"........aa...aaaaaaaaaaa", +#else +"XX......................", +"XaX.....................", +"XaaX....................", +"XaaaX...................", +"XaaaaX..................", +"XaaaaaX.................", +"XaaaaaaX................", +"XaaaaaaaX...............", +"XaaaaaaaaX..............", +"XaaaaaaaaaX.............", +"XaaaaaaXXXX.............", +"XaaaXaaX................", +"XaaXXaaX................", +"XaX..XaaX...............", +"XX...XaaX...............", +"X.....XaaX..............", +"......XaaX..............", +".......XaaX.............", +".......XaaX.............", +"........XX...aaaaaaaaaaa", +#endif +".............aXXXXXXXXXa", +".............aXXXaaaaXXa", +".............aXXXXaaaXXa", +".............aXXXaaaaXXa", +".............aXXaaaXaXXa", +".............aXXaaXXXXXa", +".............aXXaXXXXXXa", +".............aXXXaXXXXXa", +".............aXXXXXXXXXa", +".............aaaaaaaaaaa"}; + +QPixmap QApplicationPrivate::getPixmapCursor(Qt::CursorShape cshape) +{ + if (!move_cursor) { + move_cursor = new QPixmap((const char **)move_xpm); + copy_cursor = new QPixmap((const char **)copy_xpm); + link_cursor = new QPixmap((const char **)link_xpm); +#ifdef Q_WS_WIN + ignore_cursor = new QPixmap((const char **)ignore_xpm); +#endif + } + + switch (cshape) { + case Qt::DragMoveCursor: + return *move_cursor; + case Qt::DragCopyCursor: + return *copy_cursor; + case Qt::DragLinkCursor: + return *link_cursor; +#ifdef Q_WS_WIN + case Qt::ForbiddenCursor: + return *ignore_cursor; +#endif + default: + break; + } + return QPixmap(); +} + QT_END_NAMESPACE #include "moc_qapplication.cpp" diff --git a/src/gui/kernel/qapplication_mac.mm b/src/gui/kernel/qapplication_mac.mm index 54a4901..e511c3a 100644 --- a/src/gui/kernel/qapplication_mac.mm +++ b/src/gui/kernel/qapplication_mac.mm @@ -1237,7 +1237,7 @@ void qt_init(QApplicationPrivate *priv, int) // Cocoa application delegate #ifdef QT_MAC_USE_COCOA - NSApplication *cocoaApp = [NSApplication sharedApplication]; + NSApplication *cocoaApp = [QNSApplication sharedApplication]; QMacCocoaAutoReleasePool pool; NSObject *oldDelegate = [cocoaApp delegate]; QT_MANGLE_NAMESPACE(QCocoaApplicationDelegate) *newDelegate = [QT_MANGLE_NAMESPACE(QCocoaApplicationDelegate) sharedDelegate]; @@ -1258,10 +1258,6 @@ void qt_init(QApplicationPrivate *priv, int) [cocoaApp setMenu:[qtMenuLoader menu]]; [newDelegate setMenuLoader:qtMenuLoader]; [qtMenuLoader release]; - - NSAppleEventManager *eventManager = [NSAppleEventManager sharedAppleEventManager]; - [eventManager setEventHandler:newDelegate andSelector:@selector(getUrl:withReplyEvent:) - forEventClass:kInternetEventClass andEventID:kAEGetURL]; } #endif // Register for Carbon tablet proximity events on the event monitor target. @@ -1361,12 +1357,39 @@ void QApplication::setMainWidget(QWidget *mainWidget) /***************************************************************************** QApplication cursor stack *****************************************************************************/ +#ifdef QT_MAC_USE_COCOA +void QApplicationPrivate::disableUsageOfCursorRects(bool disable) +{ + // In Cocoa there are two competing ways of setting the cursor; either + // by using cursor rects (see qcocoaview_mac.mm), or by pushing/popping + // the cursor manually. When we use override cursors, it makes most sense + // to use the latter. But then we need to tell cocoa to stop using the + // first approach so it doesn't change the cursor back when hovering over + // a cursor rect: + QWidgetList topLevels = qApp->topLevelWidgets(); + for (int i=0; i<topLevels.size(); ++i) { + if (NSWindow *window = qt_mac_window_for(topLevels.at(i))) + disable ? [window disableCursorRects] : [window enableCursorRects]; + } +} + +void QApplicationPrivate::updateOverrideCursor() +{ + // Sometimes Cocoa forgets that we have set a Cursor + // manually. In those cases, remind it again: + if (QCursor *override = qApp->overrideCursor()) + [static_cast<NSCursor *>(qt_mac_nsCursorForQCursor(*override)) set]; +} +#endif + void QApplication::setOverrideCursor(const QCursor &cursor) { qApp->d_func()->cursor_list.prepend(cursor); #ifdef QT_MAC_USE_COCOA QMacCocoaAutoReleasePool pool; + if (qApp->d_func()->cursor_list.size() == 1) + qApp->d_func()->disableUsageOfCursorRects(true); [static_cast<NSCursor *>(qt_mac_nsCursorForQCursor(cursor)) push]; #else if (qApp && qApp->activeWindow()) @@ -1383,6 +1406,8 @@ void QApplication::restoreOverrideCursor() #ifdef QT_MAC_USE_COCOA QMacCocoaAutoReleasePool pool; [NSCursor pop]; + if (qApp->d_func()->cursor_list.isEmpty()) + qApp->d_func()->disableUsageOfCursorRects(false); #else if (qApp && qApp->activeWindow()) { const QCursor def(Qt::ArrowCursor); @@ -2457,6 +2482,28 @@ QApplicationPrivate::globalEventProcessor(EventHandlerCallRef er, EventRef event #endif } +#ifdef QT_MAC_USE_COCOA +void QApplicationPrivate::qt_initAfterNSAppStarted() +{ + setupAppleEvents(); + updateOverrideCursor(); +} + +void QApplicationPrivate::setupAppleEvents() +{ + // This function is called from the event dispatcher when NSApplication has + // finished initialization, which appears to be just after [NSApplication run] has + // started to execute. By setting up our apple events handlers this late, we override + // the ones set up by NSApplication. + QT_MANGLE_NAMESPACE(QCocoaApplicationDelegate) *newDelegate = [QT_MANGLE_NAMESPACE(QCocoaApplicationDelegate) sharedDelegate]; + NSAppleEventManager *eventManager = [NSAppleEventManager sharedAppleEventManager]; + [eventManager setEventHandler:newDelegate andSelector:@selector(appleEventQuit:withReplyEvent:) + forEventClass:kCoreEventClass andEventID:kAEQuitApplication]; + [eventManager setEventHandler:newDelegate andSelector:@selector(getUrl:withReplyEvent:) + forEventClass:kInternetEventClass andEventID:kAEGetURL]; +} +#endif + // In Carbon this is your one stop for apple events. // In Cocoa, it ISN'T. This is the catch-all Apple Event handler that exists // for the time between instantiating the NSApplication, but before the @@ -3008,7 +3055,7 @@ void onApplicationWindowChangedActivation(QWidget *widget, bool activated) } QMenuBar::macUpdateMenuBar(); - + QApplicationPrivate::updateOverrideCursor(); #else Q_UNUSED(widget); Q_UNUSED(activated); diff --git a/src/gui/kernel/qapplication_p.h b/src/gui/kernel/qapplication_p.h index b3ec732..e0a6103 100644 --- a/src/gui/kernel/qapplication_p.h +++ b/src/gui/kernel/qapplication_p.h @@ -459,6 +459,12 @@ public: static OSStatus globalEventProcessor(EventHandlerCallRef, EventRef, void *); static OSStatus globalAppleEventProcessor(const AppleEvent *, AppleEvent *, long); static OSStatus tabletProximityCallback(EventHandlerCallRef, EventRef, void *); +#ifdef QT_MAC_USE_COCOA + static void qt_initAfterNSAppStarted(); + static void setupAppleEvents(); + static void updateOverrideCursor(); + static void disableUsageOfCursorRects(bool disable); +#endif static bool qt_mac_apply_settings(); #endif @@ -514,6 +520,13 @@ public: QGestureManager *gestureManager; QWidget *gestureWidget; + QPixmap *move_cursor; + QPixmap *copy_cursor; + QPixmap *link_cursor; +#if defined(Q_WS_WIN) + QPixmap *ignore_cursor; +#endif + QPixmap getPixmapCursor(Qt::CursorShape cshape); QMap<int, QWeakPointer<QWidget> > widgetForTouchPointId; QMap<int, QTouchEvent::TouchPoint> appCurrentTouchPoints; diff --git a/src/gui/kernel/qapplication_s60.cpp b/src/gui/kernel/qapplication_s60.cpp index 2eecd56..baefdfd 100644 --- a/src/gui/kernel/qapplication_s60.cpp +++ b/src/gui/kernel/qapplication_s60.cpp @@ -63,7 +63,7 @@ #include "private/qsoftkeymanager_p.h" #include "apgwgnam.h" // For CApaWindowGroupName -#include <MdaAudioTonePlayer.h> // For CMdaAudioToneUtility +#include <mdaaudiotoneplayer.h> // For CMdaAudioToneUtility #if defined(Q_WS_S60) # if !defined(QT_NO_IM) diff --git a/src/gui/kernel/qapplication_win.cpp b/src/gui/kernel/qapplication_win.cpp index aac834d..131b9bb 100644 --- a/src/gui/kernel/qapplication_win.cpp +++ b/src/gui/kernel/qapplication_win.cpp @@ -2556,6 +2556,17 @@ LRESULT CALLBACK QtWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam result = true; break; } +#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; @@ -2978,7 +2989,10 @@ bool QETWidget::translateMouseEvent(const MSG &msg) // most recent one. msgPtr->lParam = mouseMsg.lParam; msgPtr->wParam = mouseMsg.wParam; - msgPtr->pt = mouseMsg.pt; + // 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); diff --git a/src/gui/kernel/qapplication_x11.cpp b/src/gui/kernel/qapplication_x11.cpp index afd927b..3c2c743 100644 --- a/src/gui/kernel/qapplication_x11.cpp +++ b/src/gui/kernel/qapplication_x11.cpp @@ -208,11 +208,8 @@ static const char * x11_atomnames = { "_MOTIF_WM_HINTS\0" "DTWM_IS_RUNNING\0" - "KDE_FULL_SESSION\0" - "KWIN_RUNNING\0" - "KWM_RUNNING\0" - "GNOME_BACKGROUND_PROPERTIES\0" "ENLIGHTENMENT_DESKTOP\0" + "_DT_SAVE_MODE\0" "_SGI_DESKS_MANAGER\0" // EWMH (aka NETWM) @@ -614,6 +611,11 @@ static int (*original_xio_errhandler)(Display *dpy); static int qt_x_errhandler(Display *dpy, XErrorEvent *err) { + if (X11->display != dpy) { + // only handle X errors for our display + return 0; + } + switch (err->error_code) { case BadAtom: if (err->request_code == 20 /* X_GetProperty */ @@ -621,8 +623,6 @@ static int qt_x_errhandler(Display *dpy, XErrorEvent *err) || err->resourceid == XA_RGB_DEFAULT_MAP || err->resourceid == ATOM(_NET_SUPPORTED) || err->resourceid == ATOM(_NET_SUPPORTING_WM_CHECK) - || err->resourceid == ATOM(KDE_FULL_SESSION) - || err->resourceid == ATOM(KWIN_RUNNING) || err->resourceid == ATOM(XdndProxy) || err->resourceid == ATOM(XdndAware))) { // Perhaps we're running under SECURITY reduction? :/ @@ -2217,87 +2217,66 @@ void qt_init(QApplicationPrivate *priv, int, X11->desktopEnvironment = DE_UNKNOWN; X11->desktopVersion = 0; - // See if the current window manager is using the freedesktop.org spec to give its name - Window windowManagerWindow = XNone; - Atom typeReturned; - int formatReturned; - unsigned long nitemsReturned; - unsigned long unused; - unsigned char *data = 0; - if (XGetWindowProperty(QX11Info::display(), QX11Info::appRootWindow(), - ATOM(_NET_SUPPORTING_WM_CHECK), - 0, 1024, False, XA_WINDOW, &typeReturned, - &formatReturned, &nitemsReturned, &unused, &data) - == Success) { - if (typeReturned == XA_WINDOW && formatReturned == 32) - windowManagerWindow = *((Window*) data); - if (data) - XFree(data); + Atom type; + int format; + unsigned long length, after; + uchar *data = 0; + int rc; - if (windowManagerWindow != XNone) { - QString wmName; - Atom utf8atom = ATOM(UTF8_STRING); - if (XGetWindowProperty(QX11Info::display(), windowManagerWindow, ATOM(_NET_WM_NAME), - 0, 1024, False, utf8atom, &typeReturned, - &formatReturned, &nitemsReturned, &unused, &data) - == Success) { - if (typeReturned == utf8atom && formatReturned == 8) - wmName = QString::fromUtf8((const char*)data); - if (data) - XFree(data); - if (wmName == QLatin1String("KWin")) - X11->desktopEnvironment = DE_KDE; - if (wmName == QLatin1String("Metacity")) - X11->desktopEnvironment = DE_GNOME; - } + do { + if (!qgetenv("KDE_FULL_SESSION").isEmpty()) { + X11->desktopEnvironment = DE_KDE; + X11->desktopVersion = qgetenv("KDE_SESSION_VERSION").toInt(); + break; } - } - // Running a different/newer/older window manager? Try some other things - if (X11->desktopEnvironment == DE_UNKNOWN){ - Atom type; - int format; - unsigned long length, after; - uchar *data = 0; + if (qgetenv("DESKTOP_SESSION") == "gnome") { + X11->desktopEnvironment = DE_GNOME; + break; + } - QString session = QString::fromLocal8Bit(qgetenv("DESKTOP_SESSION")); - if (session == QLatin1String("kde")) { - X11->desktopEnvironment = DE_KDE; - } else if (session == QLatin1String("gnome") || session == QLatin1String("xfce")) { + // GNOME_DESKTOP_SESSION_ID is deprecated for some reason, but still check it + if (!qgetenv("GNOME_DESKTOP_SESSION_ID").isEmpty()) { X11->desktopEnvironment = DE_GNOME; - } else if (XGetWindowProperty(X11->display, QX11Info::appRootWindow(), ATOM(DTWM_IS_RUNNING), - 0, 1, False, AnyPropertyType, &type, &format, &length, - &after, &data) == Success && length) { + break; + } + + rc = XGetWindowProperty(X11->display, QX11Info::appRootWindow(), ATOM(_DT_SAVE_MODE), + 0, 2, False, XA_STRING, &type, &format, &length, + &after, &data); + if (rc == Success && length) { + if (!strcmp(reinterpret_cast<char *>(data), "xfce4")) { + // Pretend that xfce4 is gnome, as it uses the same libraries. + // The detection above is stolen from xdg-open. + X11->desktopEnvironment = DE_GNOME; + break; + } + + // We got the property but it wasn't xfce4. Free data before it gets overwritten. + XFree(data); + data = 0; + } + + rc = XGetWindowProperty(X11->display, QX11Info::appRootWindow(), ATOM(DTWM_IS_RUNNING), + 0, 1, False, AnyPropertyType, &type, &format, &length, + &after, &data); + if (rc == Success && length) { // DTWM is running, meaning most likely CDE is running... X11->desktopEnvironment = DE_CDE; - } else if (XGetWindowProperty(X11->display, QX11Info::appRootWindow(), - ATOM(GNOME_BACKGROUND_PROPERTIES), 0, 1, False, AnyPropertyType, - &type, &format, &length, &after, &data) == Success && length) { - X11->desktopEnvironment = DE_GNOME; - } else if (!qgetenv("GNOME_DESKTOP_SESSION_ID").isEmpty()) { - X11->desktopEnvironment = DE_GNOME; - } else if ((XGetWindowProperty(X11->display, QX11Info::appRootWindow(), ATOM(KDE_FULL_SESSION), - 0, 1, False, AnyPropertyType, &type, &format, &length, &after, &data) == Success - && length) - || (XGetWindowProperty(X11->display, QX11Info::appRootWindow(), ATOM(KWIN_RUNNING), - 0, 1, False, AnyPropertyType, &type, &format, &length, - &after, &data) == Success - && length) - || (XGetWindowProperty(X11->display, QX11Info::appRootWindow(), ATOM(KWM_RUNNING), - 0, 1, False, AnyPropertyType, &type, &format, &length, - &after, &data) == Success && length)) { - X11->desktopEnvironment = DE_KDE; - } else if (XGetWindowProperty(X11->display, QX11Info::appRootWindow(), ATOM(_SGI_DESKS_MANAGER), - 0, 1, False, XA_WINDOW, &type, &format, &length, &after, &data) == Success - && length) { + break; + } + + rc = XGetWindowProperty(X11->display, QX11Info::appRootWindow(), + ATOM(_SGI_DESKS_MANAGER), 0, 1, False, XA_WINDOW, + &type, &format, &length, &after, &data); + if (rc == Success && length) { X11->desktopEnvironment = DE_4DWM; + break; } - if (data) - XFree((char *)data); - } + } while(0); - if (X11->desktopEnvironment == DE_KDE) - X11->desktopVersion = QString::fromLocal8Bit(qgetenv("KDE_SESSION_VERSION")).toInt(); + if (data) + XFree((char *)data); #if !defined(QT_NO_STYLE_GTK) if (X11->desktopEnvironment == DE_GNOME) { diff --git a/src/gui/kernel/qcocoaapplication_mac.mm b/src/gui/kernel/qcocoaapplication_mac.mm index 5b98420..4962863 100644 --- a/src/gui/kernel/qcocoaapplication_mac.mm +++ b/src/gui/kernel/qcocoaapplication_mac.mm @@ -79,6 +79,8 @@ #include <private/qcocoaapplicationdelegate_mac_p.h> #include <private/qt_cocoa_helpers_mac_p.h> +QT_USE_NAMESPACE + @implementation NSApplication (QT_MANGLE_NAMESPACE(QApplicationIntegration)) - (void)QT_MANGLE_NAMESPACE(qt_setDockMenu):(NSMenu *)newMenu @@ -107,5 +109,49 @@ | NSFontPanelStrikethroughEffectModeMask; } +- (void)qt_sendPostedMessage:(NSEvent *)event +{ + // WARNING: data1 and data2 is truncated to from 64-bit to 32-bit on OS 10.5! + // That is why we need to split the address in two parts: + quint64 lower = [event data1]; + quint64 upper = [event data2]; + QCocoaPostMessageArgs *args = reinterpret_cast<QCocoaPostMessageArgs *>(lower | (upper << 32)); + [args->target performSelector:args->selector]; + delete args; +} + +- (BOOL)qt_sendEvent:(NSEvent *)event +{ + if ([event type] == NSApplicationDefined) { + switch ([event subtype]) { + case QtCocoaEventSubTypePostMessage: + [NSApp qt_sendPostedMessage:event]; + return true; + default: + break; + } + } + return false; +} + @end + +@implementation QNSApplication + +// WARNING: If Qt did not create NSApplication (this can e.g. +// happend if Qt is used as a plugin from a 3rd-party cocoa +// application), QNSApplication::sendEvent will never be called. +// SO DO NOT RELY ON THIS FUNCTION BEING AVAILABLE. +// Plugin developers that _do_ control the NSApplication sub-class +// implementation of the 3rd-party application can call qt_sendEvent +// from the sub-class event handler (like we do here) to work around +// any issues. +- (void)sendEvent:(NSEvent *)event +{ + if (![self qt_sendEvent:event]) + [super sendEvent:event]; +} + +@end + #endif diff --git a/src/gui/kernel/qcocoaapplication_mac_p.h b/src/gui/kernel/qcocoaapplication_mac_p.h index e845d58..5569feb 100644 --- a/src/gui/kernel/qcocoaapplication_mac_p.h +++ b/src/gui/kernel/qcocoaapplication_mac_p.h @@ -99,5 +99,13 @@ QT_FORWARD_DECLARE_CLASS(QApplicationPrivate) - (QApplicationPrivate *)QT_MANGLE_NAMESPACE(qt_qappPrivate); - (QT_MANGLE_NAMESPACE(QCocoaMenuLoader) *)QT_MANGLE_NAMESPACE(qt_qcocoamenuLoader); - (int)QT_MANGLE_NAMESPACE(qt_validModesForFontPanel):(NSFontPanel *)fontPanel; + +- (void)qt_sendPostedMessage:(NSEvent *)event; +- (BOOL)qt_sendEvent:(NSEvent *)event; +@end + +@interface QNSApplication : NSApplication { +} @end + #endif diff --git a/src/gui/kernel/qcocoaapplicationdelegate_mac.mm b/src/gui/kernel/qcocoaapplicationdelegate_mac.mm index 47a8026..ab71a05 100644 --- a/src/gui/kernel/qcocoaapplicationdelegate_mac.mm +++ b/src/gui/kernel/qcocoaapplicationdelegate_mac.mm @@ -317,5 +317,12 @@ static void cleanupCocoaApplicationDelegate() qt_sendSpontaneousEvent(qAppInstance(), &qtEvent); } +- (void)appleEventQuit:(NSAppleEventDescriptor *)event withReplyEvent:(NSAppleEventDescriptor *)replyEvent +{ + Q_UNUSED(event); + Q_UNUSED(replyEvent); + [NSApp terminate:self]; +} + @end #endif diff --git a/src/gui/kernel/qcocoamenuloader_mac.mm b/src/gui/kernel/qcocoamenuloader_mac.mm index 18b3772..573b763 100644 --- a/src/gui/kernel/qcocoamenuloader_mac.mm +++ b/src/gui/kernel/qcocoamenuloader_mac.mm @@ -46,6 +46,7 @@ #include <private/qcocoamenuloader_mac_p.h> #include <private/qapplication_p.h> #include <private/qt_mac_p.h> +#include <private/qmenubar_p.h> #include <qmenubar.h> QT_FORWARD_DECLARE_CLASS(QCFString) @@ -208,6 +209,11 @@ QT_USE_NAMESPACE [NSApp hide:sender]; } +- (void)qtUpdateMenubar +{ + QMenuBarPrivate::macUpdateMenuBarImmediatly(); +} + - (IBAction)qtDispatcherToQAction:(id)sender { QScopedLoopLevelCounter loopLevelCounter(QApplicationPrivate::instance()->threadData); diff --git a/src/gui/kernel/qcocoamenuloader_mac_p.h b/src/gui/kernel/qcocoamenuloader_mac_p.h index 81c136e..2504b8c 100644 --- a/src/gui/kernel/qcocoamenuloader_mac_p.h +++ b/src/gui/kernel/qcocoamenuloader_mac_p.h @@ -85,6 +85,7 @@ - (IBAction)unhideAllApplications:(id)sender; - (IBAction)hide:(id)sender; - (IBAction)qtDispatcherToQAction:(id)sender; +- (void)qtUpdateMenubar; @end #endif // QT_MAC_USE_COCOA diff --git a/src/gui/kernel/qcocoapanel_mac.mm b/src/gui/kernel/qcocoapanel_mac.mm index 5e24c84..0b48efd 100644 --- a/src/gui/kernel/qcocoapanel_mac.mm +++ b/src/gui/kernel/qcocoapanel_mac.mm @@ -46,6 +46,7 @@ #import <private/qcocoawindowdelegate_mac_p.h> #import <private/qcocoaview_mac_p.h> #import <private/qcocoawindowcustomthemeframe_mac_p.h> +#import <private/qcocoaapplication_mac_p.h> #include <private/qapplication_p.h> #include <private/qbackingstore_p.h> diff --git a/src/gui/kernel/qcocoapanel_mac_p.h b/src/gui/kernel/qcocoapanel_mac_p.h index fc83bd8..3678f81 100644 --- a/src/gui/kernel/qcocoapanel_mac_p.h +++ b/src/gui/kernel/qcocoapanel_mac_p.h @@ -54,10 +54,16 @@ #ifdef QT_MAC_USE_COCOA #import <Cocoa/Cocoa.h> +QT_FORWARD_DECLARE_CLASS(QStringList); + @interface QT_MANGLE_NAMESPACE(QCocoaPanel) : NSPanel { bool leftButtonIsRightButton; + QStringList *currentCustomDragTypes; } + (Class)frameViewClassForStyleMask:(NSUInteger)styleMask; +- (void)registerDragTypes; + @end #endif + diff --git a/src/gui/kernel/qcocoasharedwindowmethods_mac_p.h b/src/gui/kernel/qcocoasharedwindowmethods_mac_p.h index d2b74d7..9fe5ae0 100644 --- a/src/gui/kernel/qcocoasharedwindowmethods_mac_p.h +++ b/src/gui/kernel/qcocoasharedwindowmethods_mac_p.h @@ -57,8 +57,32 @@ QT_BEGIN_NAMESPACE extern Qt::MouseButton cocoaButton2QtButton(NSInteger buttonNum); // qcocoaview.mm extern QPointer<QWidget> qt_button_down; //qapplication_mac.cpp +extern const QStringList& qEnabledDraggedTypes(); // qmime_mac.cpp +extern bool qt_blockCocoaSettingModalWindowLevel; // qeventdispatcher_mac_p.h + +Q_GLOBAL_STATIC(QPointer<QWidget>, currentDragTarget); + QT_END_NAMESPACE +- (id)initWithContentRect:(NSRect)contentRect + styleMask:(NSUInteger)windowStyle + backing:(NSBackingStoreType)bufferingType + defer:(BOOL)deferCreation +{ + self = [super initWithContentRect:contentRect styleMask:windowStyle + backing:bufferingType defer:deferCreation]; + if (self) { + currentCustomDragTypes = 0; + } + return self; +} + +- (void)dealloc +{ + delete currentCustomDragTypes; + [super dealloc]; +} + - (BOOL)canBecomeKeyWindow { QWidget *widget = [self QT_MANGLE_NAMESPACE(qt_qwidget)]; @@ -68,6 +92,40 @@ QT_END_NAMESPACE return !(isPopup || isToolTip); } +- (BOOL)canBecomeMainWindow +{ + QWidget *widget = [self QT_MANGLE_NAMESPACE(qt_qwidget)]; + + bool isToolTip = (widget->windowType() == Qt::ToolTip); + bool isPopup = (widget->windowType() == Qt::Popup); + bool isTool = (widget->windowType() == Qt::Tool); + return !(isPopup || isToolTip || isTool); +} + +- (void)orderWindow:(NSWindowOrderingMode)orderingMode relativeTo:(NSInteger)otherWindowNumber +{ + if (qt_blockCocoaSettingModalWindowLevel) { + // To avoid windows popping in front while restoring modal sessions + // in the event dispatcher, we block cocoa from ordering this window + // to front. The result of not doing this can be seen if executing + // a native color dialog on top of another executing dialog. + return; + } + [super orderWindow:orderingMode relativeTo:otherWindowNumber]; +} + +- (void)setLevel:(NSInteger)windowLevel +{ + if (qt_blockCocoaSettingModalWindowLevel) { + // To avoid windows popping in front while restoring modal sessions + // in the event dispatcher, we block cocoa from ordering this window + // to front. The result of not doing this can be seen if executing + // a native color dialog on top of another executing dialog. + return; + } + [super setLevel:windowLevel]; +} + - (void)toggleToolbarShown:(id)sender { macSendToolbarChangeEvent([self QT_MANGLE_NAMESPACE(qt_qwidget)]); @@ -106,10 +164,37 @@ QT_END_NAMESPACE qt_dispatchTabletProximityEvent(tabletEvent); } +- (void)qtDispatcherToQAction:(id)sender +{ + // If this window is modal, the menu bar will be modally shaddowed. + // In that case, since the window will be in the first responder chain, + // we can still catch the trigger here and forward it to the menu bar. + // This is needed as a single modal dialog on Qt should be able to access + // the application menu (e.g. quit). + [[NSApp QT_MANGLE_NAMESPACE(qt_qcocoamenuLoader)] qtDispatcherToQAction:sender]; +} + +- (void)terminate:(id)sender +{ + // This function is called from the quit item in the menubar when this window + // is in the first responder chain (see also qtDispatcherToQAction above) + [NSApp terminate:sender]; +} + - (void)sendEvent:(NSEvent *)event { - QWidget *widget = [[QT_MANGLE_NAMESPACE(QCocoaWindowDelegate) sharedDelegate] qt_qwidgetForWindow:self]; + if ([event type] == NSApplicationDefined) { + switch ([event subtype]) { + case QtCocoaEventSubTypePostMessage: + [NSApp qt_sendPostedMessage:event]; + return; + default: + break; + } + return; + } + QWidget *widget = [[QT_MANGLE_NAMESPACE(QCocoaWindowDelegate) sharedDelegate] qt_qwidgetForWindow:self]; // Cocoa can hold onto the window after we've disavowed its knowledge. So, // if we get sent an event afterwards just have it go through the super's // version and don't do any stuff with Qt. @@ -133,7 +218,7 @@ QT_END_NAMESPACE qt_button_down = widget; handled = qt_mac_handleMouseEvent(view, event, QEvent::MouseButtonPress, mouseButton); // Don't call super here. This prevents us from getting the mouseUp event, - // which we need to send even if the mouseDown event was not accepted. + // which we need to send even if the mouseDown event was not accepted. // (this is standard Qt behavior.) break; case NSRightMouseDown: @@ -188,6 +273,115 @@ QT_END_NAMESPACE return [super frameViewClassForStyleMask:styleMask]; } +-(void)registerDragTypes +{ + // Calling registerForDraggedTypes below is slow, so only do + // it once for each window, or when the custom types change. + QMacCocoaAutoReleasePool pool; + const QStringList& customTypes = qEnabledDraggedTypes(); + if (currentCustomDragTypes == 0 || *currentCustomDragTypes != customTypes) { + if (currentCustomDragTypes == 0) + currentCustomDragTypes = new QStringList(); + *currentCustomDragTypes = customTypes; + const NSString* mimeTypeGeneric = @"com.trolltech.qt.MimeTypeName"; + NSMutableArray *supportedTypes = [NSMutableArray arrayWithObjects:NSColorPboardType, + NSFilenamesPboardType, NSStringPboardType, + NSFilenamesPboardType, NSPostScriptPboardType, NSTIFFPboardType, + NSRTFPboardType, NSTabularTextPboardType, NSFontPboardType, + NSRulerPboardType, NSFileContentsPboardType, NSColorPboardType, + NSRTFDPboardType, NSHTMLPboardType, NSPICTPboardType, + NSURLPboardType, NSPDFPboardType, NSVCardPboardType, + NSFilesPromisePboardType, NSInkTextPboardType, + NSMultipleTextSelectionPboardType, mimeTypeGeneric, nil]; + // Add custom types supported by the application. + for (int i = 0; i < customTypes.size(); i++) { + [supportedTypes addObject:reinterpret_cast<const NSString *>(QCFString::toCFStringRef(customTypes[i]))]; + } + [self registerForDraggedTypes:supportedTypes]; + } +} + +- (QWidget *)dragTargetHitTest:(id <NSDraggingInfo>)sender +{ + // Do a hittest to find the NSView under the + // mouse, and return the corresponding QWidget: + NSPoint windowPoint = [sender draggingLocation]; + NSView *candidateView = [[self contentView] hitTest:windowPoint]; + if (![candidateView isKindOfClass:[QT_MANGLE_NAMESPACE(QCocoaView) class]]) + return 0; + return [static_cast<QT_MANGLE_NAMESPACE(QCocoaView) *>(candidateView) qt_qwidget]; +} + +- (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender +{ + // The user dragged something into the window. Send a draggingEntered message + // to the QWidget under the mouse. As the drag moves over the window, and over + // different widgets, we will handle enter and leave events from within + // draggingUpdated below. The reason why we handle this ourselves rather than + // subscribing for drag events directly in QCocoaView is that calling + // registerForDraggedTypes on the views will severly degrade initialization time + // for an application that uses a lot of drag subscribing widgets. + + QWidget *target = [self dragTargetHitTest:sender]; + if (!target) + return [super draggingEntered:sender]; + if (target->testAttribute(Qt::WA_DropSiteRegistered) == false) + return NSDragOperationNone; + + *currentDragTarget() = target; + return [reinterpret_cast<NSView *>((*currentDragTarget())->winId()) draggingEntered:sender]; + } + +- (NSDragOperation)draggingUpdated:(id < NSDraggingInfo >)sender +{ + QWidget *target = [self dragTargetHitTest:sender]; + if (!target) + return [super draggingUpdated:sender]; + + if (target == *currentDragTarget()) { + // The drag continues to move over the widget that we have sendt + // a draggingEntered message to. So just update the view: + return [reinterpret_cast<NSView *>((*currentDragTarget())->winId()) draggingUpdated:sender]; + } else { + // The widget under the mouse has changed. + // So we need to fake enter/leave events: + if (*currentDragTarget()) + [reinterpret_cast<NSView *>((*currentDragTarget())->winId()) draggingExited:sender]; + if (target->testAttribute(Qt::WA_DropSiteRegistered) == false) { + *currentDragTarget() = 0; + return NSDragOperationNone; + } + *currentDragTarget() = target; + return [reinterpret_cast<NSView *>((*currentDragTarget())->winId()) draggingEntered:sender]; + } +} + +- (void)draggingExited:(id < NSDraggingInfo >)sender +{ + QWidget *target = [self dragTargetHitTest:sender]; + if (!target) + return [super draggingExited:sender]; + + if (*currentDragTarget()) { + [reinterpret_cast<NSView *>((*currentDragTarget())->winId()) draggingExited:sender]; + *currentDragTarget() = 0; + } +} + +- (BOOL)performDragOperation:(id < NSDraggingInfo >)sender +{ + QWidget *target = [self dragTargetHitTest:sender]; + if (!target) + return [super performDragOperation:sender]; + + BOOL dropResult = NO; + if (*currentDragTarget()) { + dropResult = [reinterpret_cast<NSView *>((*currentDragTarget())->winId()) performDragOperation:sender]; + *currentDragTarget() = 0; + } + return dropResult; +} + - (void)displayIfNeeded { @@ -203,5 +397,3 @@ QT_END_NAMESPACE } [super displayIfNeeded]; } - - diff --git a/src/gui/kernel/qcocoaview_mac.mm b/src/gui/kernel/qcocoaview_mac.mm index ad64a91..6a16403 100644 --- a/src/gui/kernel/qcocoaview_mac.mm +++ b/src/gui/kernel/qcocoaview_mac.mm @@ -81,24 +81,9 @@ Q_GLOBAL_STATIC(DnDParams, qMacDnDParams); extern void qt_mac_update_cursor_at_global_pos(const QPoint &globalPos); // qcursor_mac.mm extern bool qt_sendSpontaneousEvent(QObject *, QEvent *); // qapplication.cpp extern OSViewRef qt_mac_nativeview_for(const QWidget *w); // qwidget_mac.mm -extern const QStringList& qEnabledDraggedTypes(); // qmime_mac.cpp extern QPointer<QWidget> qt_mouseover; //qapplication_mac.mm extern QPointer<QWidget> qt_button_down; //qapplication_mac.cpp - -Qt::MouseButton cocoaButton2QtButton(NSInteger buttonNum) -{ - if (buttonNum == 0) - return Qt::LeftButton; - if (buttonNum == 1) - return Qt::RightButton; - if (buttonNum == 2) - return Qt::MidButton; - if (buttonNum == 3) - return Qt::XButton1; - if (buttonNum == 4) - return Qt::XButton2; - return Qt::NoButton; -} +extern Qt::MouseButton cocoaButton2QtButton(NSInteger buttonNum); struct dndenum_mapper { @@ -212,7 +197,6 @@ extern "C" { composingText = new QString(); composing = false; sendKeyEvents = true; - currentCustomTypes = 0; [self setHidden:YES]; return self; } @@ -227,36 +211,12 @@ extern "C" { object:self]; } --(void)registerDragTypes -{ - QMacCocoaAutoReleasePool pool; - // Calling registerForDraggedTypes is slow, so only do it once for each widget - // or when the custom types change. - const QStringList& customTypes = qEnabledDraggedTypes(); - if (currentCustomTypes == 0 || *currentCustomTypes != customTypes) { - if (currentCustomTypes == 0) - currentCustomTypes = new QStringList(); - *currentCustomTypes = customTypes; - const NSString* mimeTypeGeneric = @"com.trolltech.qt.MimeTypeName"; - NSMutableArray *supportedTypes = [NSMutableArray arrayWithObjects:NSColorPboardType, - NSFilenamesPboardType, NSStringPboardType, - NSFilenamesPboardType, NSPostScriptPboardType, NSTIFFPboardType, - NSRTFPboardType, NSTabularTextPboardType, NSFontPboardType, - NSRulerPboardType, NSFileContentsPboardType, NSColorPboardType, - NSRTFDPboardType, NSHTMLPboardType, NSPICTPboardType, - NSURLPboardType, NSPDFPboardType, NSVCardPboardType, - NSFilesPromisePboardType, NSInkTextPboardType, - NSMultipleTextSelectionPboardType, mimeTypeGeneric, nil]; - // Add custom types supported by the application. - for (int i = 0; i < customTypes.size(); i++) { - [supportedTypes addObject:reinterpret_cast<const NSString *>(QCFString::toCFStringRef(customTypes[i]))]; - } - [self registerForDraggedTypes:supportedTypes]; - } -} - - (void)resetCursorRects { + // [NSView addCursorRect] is slow, so bail out early if we can: + if (NSIsEmptyRect([self visibleRect])) + return; + QWidget *cursorWidget = qwidget; if (cursorWidget->testAttribute(Qt::WA_TransparentForMouseEvents)) @@ -300,15 +260,9 @@ extern "C" { - (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender { - if (qwidget->testAttribute(Qt::WA_DropSiteRegistered) == false) - return NSDragOperationNone; + // NB: This function is called from QCoocaWindow/QCocoaPanel rather than directly + // from Cocoa. They modify the drag target, and might fake enter/leave events. NSPoint windowPoint = [sender draggingLocation]; - if (qwidget->testAttribute(Qt::WA_TransparentForMouseEvents)) { - // pass the drag enter event to the view underneath. - NSView *candidateView = [[[self window] contentView] hitTest:windowPoint]; - if (candidateView && candidateView != self) - return [candidateView draggingEntered:sender]; - } dragEnterSequence = [sender draggingSequenceNumber]; [self addDropData:sender]; QMimeData *mimeData = dropData; @@ -361,13 +315,9 @@ extern "C" { } - (NSDragOperation)draggingUpdated:(id < NSDraggingInfo >)sender { + // NB: This function is called from QCoocaWindow/QCocoaPanel rather than directly + // from Cocoa. They modify the drag target, and might fake enter/leave events. NSPoint windowPoint = [sender draggingLocation]; - if (qwidget->testAttribute(Qt::WA_TransparentForMouseEvents)) { - // pass the drag move event to the view underneath. - NSView *candidateView = [[[self window] contentView] hitTest:windowPoint]; - if (candidateView && candidateView != self) - return [candidateView draggingUpdated:sender]; - } // in cases like QFocusFrame, the view under the mouse might // not have received the drag enter. Generate a synthetic // drag enter event for that view. @@ -417,14 +367,10 @@ extern "C" { - (void)draggingExited:(id < NSDraggingInfo >)sender { + // NB: This function is called from QCoocaWindow/QCocoaPanel rather than directly + // from Cocoa. They modify the drag target, and might fake enter/leave events. + Q_UNUSED(sender); dragEnterSequence = -1; - if (qwidget->testAttribute(Qt::WA_TransparentForMouseEvents)) { - // try sending the leave event to the last view which accepted drag enter. - DnDParams *dndParams = [QT_MANGLE_NAMESPACE(QCocoaView) currentMouseEvent]; - NSView *candidateView = [[[self window] contentView] hitTest:dndParams->activeDragEnterPos]; - if (candidateView && candidateView != self) - return [candidateView draggingExited:sender]; - } // drag enter event was rejected, so ignore the move event. if (dropData) { QDragLeaveEvent de; @@ -435,14 +381,10 @@ extern "C" { - (BOOL)performDragOperation:(id <NSDraggingInfo>)sender { + // NB: This function is called from QCoocaWindow/QCocoaPanel rather than directly + // from Cocoa. They modify the drag target, and might fake enter/leave events. NSPoint windowPoint = [sender draggingLocation]; dragEnterSequence = -1; - if (qwidget->testAttribute(Qt::WA_TransparentForMouseEvents)) { - // pass the drop event to the view underneath. - NSView *candidateView = [[[self window] contentView] hitTest:windowPoint]; - if (candidateView && candidateView != self) - return [candidateView performDragOperation:sender]; - } [self addDropData:sender]; NSPoint globalPoint = [[sender draggingDestinationWindow] convertBaseToScreen:windowPoint]; @@ -472,13 +414,13 @@ extern "C" { { delete composingText; [[NSNotificationCenter defaultCenter] removeObserver:self]; - delete currentCustomTypes; - [self unregisterDraggedTypes]; [super dealloc]; } - (BOOL)isOpaque; { + if (!qwidgetprivate) + return [super isOpaque]; return qwidgetprivate->isOpaque; } @@ -510,7 +452,7 @@ extern "C" { } // Make sure the opengl context is updated on resize. - if (qwidgetprivate->isGLWidget) { + if (qwidgetprivate && qwidgetprivate->isGLWidget) { qwidgetprivate->needWindowChange = true; QEvent event(QEvent::MacGLWindowChange); qApp->sendEvent(qwidget, &event); @@ -519,11 +461,15 @@ extern "C" { - (void)drawRect:(NSRect)aRect { + if (!qwidget) + return; + if (QApplicationPrivate::graphicsSystem() != 0) { if (QWidgetBackingStore *bs = qwidgetprivate->maybeBackingStore()) { // Drawing is handled on the window level - // See qcocoasharedwindowmethods_mac_p. - return; + // See qcocoasharedwindowmethods_mac_p.h + if (!qwidget->testAttribute(Qt::WA_PaintOnScreen)) + return; } } CGContextRef cg = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort]; @@ -535,7 +481,15 @@ extern "C" { qWarning("QWidget::repaint: Recursive repaint detected"); const QRect qrect = QRect(aRect.origin.x, aRect.origin.y, aRect.size.width, aRect.size.height); - QRegion qrgn(qrect); + QRegion qrgn; + + const NSRect *rects; + NSInteger count; + [self getRectsBeingDrawn:&rects count:&count]; + for (int i = 0; i < count; ++i) { + QRect tmpRect = QRect(rects[i].origin.x, rects[i].origin.y, rects[i].size.width, rects[i].size.height); + qrgn += tmpRect; + } if (!qwidget->isWindow() && !qobject_cast<QAbstractScrollArea *>(qwidget->parent())) { const QRegion &parentMask = qwidget->window()->mask(); @@ -603,12 +557,18 @@ extern "C" { - (BOOL)acceptsFirstMouse:(NSEvent *)theEvent { + if (!qwidget) + return NO; + Q_UNUSED(theEvent); return !qwidget->testAttribute(Qt::WA_MacNoClickThrough); } - (NSView *)hitTest:(NSPoint)aPoint { + if (!qwidget) + return [super hitTest:aPoint]; + if (qwidget->testAttribute(Qt::WA_TransparentForMouseEvents)) return nil; // You cannot hit a transparent for mouse event widget. return [super hitTest:aPoint]; @@ -616,6 +576,13 @@ extern "C" { - (void)updateTrackingAreas { + if (!qwidget) + return; + + // [NSView addTrackingArea] is slow, so bail out early if we can: + if (NSIsEmptyRect([self visibleRect])) + return; + QMacCocoaAutoReleasePool pool; if (NSArray *trackingArray = [self trackingAreas]) { NSUInteger size = [trackingArray count]; @@ -645,6 +612,9 @@ extern "C" { - (void)mouseEntered:(NSEvent *)event { + if (!qwidget) + return; + if (qwidgetprivate->data.in_destructor) return; QEvent enterEvent(QEvent::Enter); @@ -667,6 +637,9 @@ extern "C" { - (void)mouseExited:(NSEvent *)event { + if (!qwidget) + return; + QEvent leaveEvent(QEvent::Leave); NSPoint globalPoint = [[event window] convertBaseToScreen:[event locationInWindow]]; if (!qAppInstance()->activeModalWidget() || QApplicationPrivate::tryModalHelper(qwidget, 0)) { @@ -685,6 +658,9 @@ extern "C" { - (void)flagsChanged:(NSEvent *)theEvent { + if (!qwidget) + return; + QWidget *widgetToGetKey = qwidget; QWidget *popup = qAppInstance()->activePopupWidget(); @@ -696,6 +672,9 @@ extern "C" { - (void)mouseMoved:(NSEvent *)theEvent { + if (!qwidget) + return; + // We always enable mouse tracking for all QCocoaView-s. In cases where we have // child views, we will receive mouseMoved for both parent & the child (if // mouse is over the child). We need to ignore the parent mouseMoved in such @@ -986,6 +965,8 @@ extern "C" { - (void)frameDidChange:(NSNotification *)note { Q_UNUSED(note); + if (!qwidget) + return; if (qwidget->isWindow()) return; NSRect newFrame = [self frame]; @@ -1009,7 +990,7 @@ extern "C" { { QMacCocoaAutoReleasePool pool; [super setEnabled:flag]; - if (qwidget->isEnabled() != flag) + if (qwidget && qwidget->isEnabled() != flag) qwidget->setEnabled(flag); } @@ -1020,6 +1001,8 @@ extern "C" { - (BOOL)acceptsFirstResponder { + if (!qwidget) + return NO; if (qwidget->isWindow()) return YES; // Always do it, so that windows can accept key press events. return qwidget->focusPolicy() != Qt::NoFocus; @@ -1027,6 +1010,8 @@ extern "C" { - (BOOL)resignFirstResponder { + if (!qwidget) + return NO; // Seems like the following test only triggers if this // view is inside a QMacNativeWidget: if (qwidget == QApplication::focusWidget()) @@ -1062,6 +1047,12 @@ extern "C" { return qwidget; } +- (void) qt_clearQWidget +{ + qwidget = 0; + qwidgetprivate = 0; +} + - (BOOL)qt_leftButtonIsRightButton { return leftButtonIsRightButton; @@ -1115,9 +1106,11 @@ extern "C" { - (void)viewWillMoveToWindow:(NSWindow *)window { + if (qwidget == 0) + return; + if (qwidget->windowFlags() & Qt::MSWindowsOwnDC && (window != [self window])) { // OpenGL Widget - // Create a stupid ClearDrawable Event QEvent event(QEvent::MacGLClearDrawable); qApp->sendEvent(qwidget, &event); } @@ -1125,6 +1118,9 @@ extern "C" { - (void)viewDidMoveToWindow { + if (qwidget == 0) + return; + if (qwidget->windowFlags() & Qt::MSWindowsOwnDC && [self window]) { // call update paint event qwidgetprivate->needWindowChange = true; @@ -1320,6 +1316,9 @@ extern "C" { - (NSArray*) validAttributesForMarkedText { + if (qwidget == 0) + return nil; + if (!qwidget->testAttribute(Qt::WA_InputMethodEnabled)) return nil; // Not sure if that's correct, but it's saves a malloc. diff --git a/src/gui/kernel/qcocoaview_mac_p.h b/src/gui/kernel/qcocoaview_mac_p.h index 797b4d5..33aaa24 100644 --- a/src/gui/kernel/qcocoaview_mac_p.h +++ b/src/gui/kernel/qcocoaview_mac_p.h @@ -87,7 +87,6 @@ Q_GUI_EXPORT int composingLength; bool sendKeyEvents; QString *composingText; - QStringList *currentCustomTypes; NSInteger dragEnterSequence; } - (id)initWithQWidget:(QWidget *)widget widgetPrivate:(QWidgetPrivate *)widgetprivate; @@ -97,7 +96,6 @@ Q_GUI_EXPORT - (NSDragOperation)draggingUpdated:(id < NSDraggingInfo >)sender; - (void)draggingExited:(id < NSDraggingInfo >)sender; - (BOOL)performDragOperation:(id <NSDraggingInfo>)sender; -- (void)registerDragTypes; - (void)removeDropData; - (void)addDropData:(id <NSDraggingInfo>)sender; - (void)setSupportedActions:(NSDragOperation)actions; @@ -105,6 +103,7 @@ Q_GUI_EXPORT - (void)draggedImage:(NSImage *)anImage endedAt:(NSPoint)aPoint operation:(NSDragOperation)operation; - (BOOL)isComposing; - (QWidget *)qt_qwidget; +- (void) qt_clearQWidget; - (BOOL)qt_leftButtonIsRightButton; - (void)qt_setLeftButtonIsRightButton:(BOOL)isSwapped; + (DnDParams*)currentMouseEvent; diff --git a/src/gui/kernel/qcocoawindow_mac.mm b/src/gui/kernel/qcocoawindow_mac.mm index a644dfe..f1b642b 100644 --- a/src/gui/kernel/qcocoawindow_mac.mm +++ b/src/gui/kernel/qcocoawindow_mac.mm @@ -46,6 +46,7 @@ #import <private/qcocoaview_mac_p.h> #import <private/qt_cocoa_helpers_mac_p.h> #import <private/qcocoawindowcustomthemeframe_mac_p.h> +#import <private/qcocoaapplication_mac_p.h> #include <QtGui/QWidget> diff --git a/src/gui/kernel/qcocoawindow_mac_p.h b/src/gui/kernel/qcocoawindow_mac_p.h index 0474882..21f82df 100644 --- a/src/gui/kernel/qcocoawindow_mac_p.h +++ b/src/gui/kernel/qcocoawindow_mac_p.h @@ -73,9 +73,12 @@ QT_FORWARD_DECLARE_CLASS(QStringList); @interface QT_MANGLE_NAMESPACE(QCocoaWindow) : NSWindow { bool leftButtonIsRightButton; + QStringList *currentCustomDragTypes; } + (Class)frameViewClassForStyleMask:(NSUInteger)styleMask; +- (void)registerDragTypes; + @end #endif diff --git a/src/gui/kernel/qcocoawindowdelegate_mac.mm b/src/gui/kernel/qcocoawindowdelegate_mac.mm index db87491..24498f8 100644 --- a/src/gui/kernel/qcocoawindowdelegate_mac.mm +++ b/src/gui/kernel/qcocoawindowdelegate_mac.mm @@ -269,9 +269,6 @@ static void cleanupCocoaWindowDelegate() { QWidget *qwidget = m_windowHash->value([notification object]); Q_ASSERT(qwidget); - if (qwidget->isActiveWindow()) - return; // Widget is already active, no need to go through re-activation. - onApplicationWindowChangedActivation(qwidget, true); } @@ -288,10 +285,6 @@ static void cleanupCocoaWindowDelegate() { QWidget *qwidget = m_windowHash->value([notification object]); Q_ASSERT(qwidget); - if (qwidget->isActiveWindow()) - return; // Widget is already active, no need to go through re-activation - - onApplicationWindowChangedActivation(qwidget, true); } diff --git a/src/gui/kernel/qcursor.cpp b/src/gui/kernel/qcursor.cpp index 0f0470c..f38e4f5 100644 --- a/src/gui/kernel/qcursor.cpp +++ b/src/gui/kernel/qcursor.cpp @@ -141,6 +141,12 @@ QT_BEGIN_NAMESPACE \o Qt::WhatsThisCursor \o \c whats_this \o \inlineimage cursor-closedhand.png \o Qt::ClosedHandCursor \o \c closedhand + \row \o + \o Qt::DragMoveCursor \o \c dnd-move or \c move + \o + \o Qt::DragCopyCursor \o \c dnd-copy or \c copy + \row \o + \o Qt::DragLinkCursor \o \c dnd-link or \c link \endtable \sa QWidget, {fowler}{GUI Design Handbook: Cursors} diff --git a/src/gui/kernel/qcursor_mac.mm b/src/gui/kernel/qcursor_mac.mm index 48bb9cc..cfebf60 100644 --- a/src/gui/kernel/qcursor_mac.mm +++ b/src/gui/kernel/qcursor_mac.mm @@ -424,6 +424,18 @@ void QCursorData::update() type = QCursorData::TYPE_ThemeCursor; curs.cp.nscursor = [NSCursor closedHandCursor]; break; + case Qt::DragCopyCursor: + type = QCursorData::TYPE_ThemeCursor; + curs.cp.nscursor = [NSCursor dragCopyCursor]; + break; + case Qt::DragMoveCursor: + type = QCursorData::TYPE_ThemeCursor; + curs.cp.nscursor = [NSCursor arrowCursor]; + break; + case Qt::DragLinkCursor: + type = QCursorData::TYPE_ThemeCursor; + curs.cp.nscursor = [NSCursor dragLinkCursor]; + break; #define QT_USE_APPROXIMATE_CURSORS #ifdef QT_USE_APPROXIMATE_CURSORS case Qt::SizeVerCursor: @@ -519,6 +531,18 @@ void QCursorData::update() type = QCursorData::TYPE_ThemeCursor; curs.tc.curs = kThemeClosedHandCursor; break; + case Qt::DragMoveCursor: + type = QCursorData::TYPE_ThemeCursor; + curs.tc.curs = kThemeArrowCursor; + break; + case Qt::DragCopyCursor: + type = QCursorData::TYPE_ThemeCursor; + curs.tc.curs = kThemeCopyArrowCursor; + break; + case Qt::DragLinkCursor: + type = QCursorData::TYPE_ThemeCursor; + curs.tc.curs = kThemeAliasArrowCursor; + break; #define QT_USE_APPROXIMATE_CURSORS #ifdef QT_USE_APPROXIMATE_CURSORS case Qt::SizeVerCursor: diff --git a/src/gui/kernel/qcursor_win.cpp b/src/gui/kernel/qcursor_win.cpp index 6f651d4..ae1c004 100644 --- a/src/gui/kernel/qcursor_win.cpp +++ b/src/gui/kernel/qcursor_win.cpp @@ -47,6 +47,7 @@ #include <qimage.h> #include <qt_windows.h> +#include <private/qapplication_p.h> QT_BEGIN_NAMESPACE @@ -470,6 +471,12 @@ void QCursorData::update() #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; diff --git a/src/gui/kernel/qcursor_x11.cpp b/src/gui/kernel/qcursor_x11.cpp index 3e83363..4e871a6 100644 --- a/src/gui/kernel/qcursor_x11.cpp +++ b/src/gui/kernel/qcursor_x11.cpp @@ -39,9 +39,11 @@ ** ****************************************************************************/ +#include <qdebug.h> #include <qdatastream.h> #include <private/qcursor_p.h> #include <private/qt_x11_p.h> +#include <private/qapplication_p.h> #include <qbitmap.h> #include <qcursor.h> #include <X11/cursorfont.h> @@ -57,6 +59,7 @@ #endif // QT_NO_XFIXES #include "qx11info_x11.h" +#include <private/qpixmap_x11_p.h> QT_BEGIN_NAMESPACE @@ -262,12 +265,31 @@ void QCursorData::update() "whats_this", "left_ptr_watch", "openhand", - "closedhand" + "closedhand", + "copy", + "move", + "link" }; #ifndef QT_NO_XCURSOR - if (X11->ptrXcursorLibraryLoadCursor) - hcurs = X11->ptrXcursorLibraryLoadCursor(dpy, cursorNames[cshape]); + if (X11->ptrXcursorLibraryLoadCursor) { + // special case for non-standard dnd-* cursors + switch (cshape) { + case Qt::DragCopyCursor: + hcurs = X11->ptrXcursorLibraryLoadCursor(dpy, "dnd-copy"); + break; + case Qt::DragMoveCursor: + hcurs = X11->ptrXcursorLibraryLoadCursor(dpy, "dnd-move"); + break; + case Qt::DragLinkCursor: + hcurs = X11->ptrXcursorLibraryLoadCursor(dpy, "dnd-link"); + break; + default: + break; + } + if (!hcurs) + hcurs = X11->ptrXcursorLibraryLoadCursor(dpy, cursorNames[cshape]); + } if (hcurs) return; #endif // QT_NO_XCURSOR @@ -504,6 +526,19 @@ void QCursorData::update() pm = XCreateBitmapFromData(dpy, rootwin, open ? openhand_bits : closedhand_bits, 16, 16); pmm = XCreateBitmapFromData(dpy, rootwin, open ? openhandm_bits : closedhandm_bits, 16, 16); hcurs = XCreatePixmapCursor(dpy, pm, pmm, &fg, &bg, 8, 8); + } else if (cshape == Qt::DragCopyCursor || cshape == Qt::DragMoveCursor + || cshape == Qt::DragLinkCursor) { + XColor bg, fg; + bg.red = 255 << 8; + bg.green = 255 << 8; + bg.blue = 255 << 8; + fg.red = 0; + fg.green = 0; + fg.blue = 0; + QImage image = QApplicationPrivate::instance()->getPixmapCursor(cshape).toImage(); + pm = QX11PixmapData::createBitmapFromImage(image); + pmm = QX11PixmapData::createBitmapFromImage(image.createAlphaMask().convertToFormat(QImage::Format_MonoLSB)); + hcurs = XCreatePixmapCursor(dpy, pm, pmm, &fg, &bg, 8, 8); } if (hcurs) @@ -577,6 +612,15 @@ void QCursorData::update() case Qt::BusyCursor: sh = XC_watch; break; + case Qt::DragCopyCursor: + sh = XC_tcross; + break; + case Qt::DragLinkCursor: + sh = XC_center_ptr; + break; + case Qt::DragMoveCursor: + sh = XC_top_left_arrow; + break; #endif /* QT_USE_APPROXIMATE_CURSORS */ default: qWarning("QCursor::update: Invalid cursor shape %d", cshape); diff --git a/src/gui/kernel/qdnd.cpp b/src/gui/kernel/qdnd.cpp index 21438a8..2b3a3d0 100644 --- a/src/gui/kernel/qdnd.cpp +++ b/src/gui/kernel/qdnd.cpp @@ -60,204 +60,12 @@ #include "qdebug.h" #include <ctype.h> +#include <private/qapplication_p.h> + #ifndef QT_NO_DRAGANDDROP QT_BEGIN_NAMESPACE -// These pixmaps approximate the images in the Windows User Interface Guidelines. - -// XPM - -static const char * const move_xpm[] = { -"11 20 3 1", -". c None", -#if defined(Q_WS_WIN) -"a c #000000", -"X c #FFFFFF", // Windows cursor is traditionally white -#else -"a c #FFFFFF", -"X c #000000", // X11 cursor is traditionally black -#endif -"aa.........", -"aXa........", -"aXXa.......", -"aXXXa......", -"aXXXXa.....", -"aXXXXXa....", -"aXXXXXXa...", -"aXXXXXXXa..", -"aXXXXXXXXa.", -"aXXXXXXXXXa", -"aXXXXXXaaaa", -"aXXXaXXa...", -"aXXaaXXa...", -"aXa..aXXa..", -"aa...aXXa..", -"a.....aXXa.", -"......aXXa.", -".......aXXa", -".......aXXa", -"........aa."}; - -#ifdef Q_WS_WIN -/* XPM */ -static const char * const ignore_xpm[] = { -"24 30 3 1", -". c None", -"a c #000000", -"X c #FFFFFF", -"aa......................", -"aXa.....................", -"aXXa....................", -"aXXXa...................", -"aXXXXa..................", -"aXXXXXa.................", -"aXXXXXXa................", -"aXXXXXXXa...............", -"aXXXXXXXXa..............", -"aXXXXXXXXXa.............", -"aXXXXXXaaaa.............", -"aXXXaXXa................", -"aXXaaXXa................", -"aXa..aXXa...............", -"aa...aXXa...............", -"a.....aXXa..............", -"......aXXa.....XXXX.....", -".......aXXa..XXaaaaXX...", -".......aXXa.XaaaaaaaaX..", -"........aa.XaaaXXXXaaaX.", -"...........XaaaaX..XaaX.", -"..........XaaXaaaX..XaaX", -"..........XaaXXaaaX.XaaX", -"..........XaaX.XaaaXXaaX", -"..........XaaX..XaaaXaaX", -"...........XaaX..XaaaaX.", -"...........XaaaXXXXaaaX.", -"............XaaaaaaaaX..", -".............XXaaaaXX...", -"...............XXXX....."}; -#endif - -/* XPM */ -static const char * const copy_xpm[] = { -"24 30 3 1", -". c None", -"a c #000000", -"X c #FFFFFF", -#if defined(Q_WS_WIN) // Windows cursor is traditionally white -"aa......................", -"aXa.....................", -"aXXa....................", -"aXXXa...................", -"aXXXXa..................", -"aXXXXXa.................", -"aXXXXXXa................", -"aXXXXXXXa...............", -"aXXXXXXXXa..............", -"aXXXXXXXXXa.............", -"aXXXXXXaaaa.............", -"aXXXaXXa................", -"aXXaaXXa................", -"aXa..aXXa...............", -"aa...aXXa...............", -"a.....aXXa..............", -"......aXXa..............", -".......aXXa.............", -".......aXXa.............", -"........aa...aaaaaaaaaaa", -#else -"XX......................", -"XaX.....................", -"XaaX....................", -"XaaaX...................", -"XaaaaX..................", -"XaaaaaX.................", -"XaaaaaaX................", -"XaaaaaaaX...............", -"XaaaaaaaaX..............", -"XaaaaaaaaaX.............", -"XaaaaaaXXXX.............", -"XaaaXaaX................", -"XaaXXaaX................", -"XaX..XaaX...............", -"XX...XaaX...............", -"X.....XaaX..............", -"......XaaX..............", -".......XaaX.............", -".......XaaX.............", -"........XX...aaaaaaaaaaa", -#endif -".............aXXXXXXXXXa", -".............aXXXXXXXXXa", -".............aXXXXaXXXXa", -".............aXXXXaXXXXa", -".............aXXaaaaaXXa", -".............aXXXXaXXXXa", -".............aXXXXaXXXXa", -".............aXXXXXXXXXa", -".............aXXXXXXXXXa", -".............aaaaaaaaaaa"}; - -/* XPM */ -static const char * const link_xpm[] = { -"24 30 3 1", -". c None", -"a c #000000", -"X c #FFFFFF", -#if defined(Q_WS_WIN) // Windows cursor is traditionally white -"aa......................", -"aXa.....................", -"aXXa....................", -"aXXXa...................", -"aXXXXa..................", -"aXXXXXa.................", -"aXXXXXXa................", -"aXXXXXXXa...............", -"aXXXXXXXXa..............", -"aXXXXXXXXXa.............", -"aXXXXXXaaaa.............", -"aXXXaXXa................", -"aXXaaXXa................", -"aXa..aXXa...............", -"aa...aXXa...............", -"a.....aXXa..............", -"......aXXa..............", -".......aXXa.............", -".......aXXa.............", -"........aa...aaaaaaaaaaa", -#else -"XX......................", -"XaX.....................", -"XaaX....................", -"XaaaX...................", -"XaaaaX..................", -"XaaaaaX.................", -"XaaaaaaX................", -"XaaaaaaaX...............", -"XaaaaaaaaX..............", -"XaaaaaaaaaX.............", -"XaaaaaaXXXX.............", -"XaaaXaaX................", -"XaaXXaaX................", -"XaX..XaaX...............", -"XX...XaaX...............", -"X.....XaaX..............", -"......XaaX..............", -".......XaaX.............", -".......XaaX.............", -"........XX...aaaaaaaaaaa", -#endif -".............aXXXXXXXXXa", -".............aXXXaaaaXXa", -".............aXXXXaaaXXa", -".............aXXXaaaaXXa", -".............aXXaaaXaXXa", -".............aXXaaXXXXXa", -".............aXXaXXXXXXa", -".............aXXXaXXXXXa", -".............aXXXXXXXXXa", -".............aaaaaaaaaaa"}; - #ifndef QT_NO_DRAGANDDROP //#define QDND_DEBUG @@ -326,22 +134,9 @@ QDragManager::QDragManager() { Q_ASSERT(!instance); -#ifdef Q_WS_WIN - n_cursor = 4; -#else - n_cursor = 3; -#endif - #ifdef Q_WS_QWS currentActionForOverrideCursor = Qt::IgnoreAction; #endif - pm_cursor = new QPixmap[n_cursor]; - pm_cursor[0] = QPixmap((const char **)move_xpm); - pm_cursor[1] = QPixmap((const char **)copy_xpm); - pm_cursor[2] = QPixmap((const char **)link_xpm); -#ifdef Q_WS_WIN - pm_cursor[3] = QPixmap((const char **)ignore_xpm); -#endif object = 0; beingCancelled = false; restoreCursor = false; @@ -362,7 +157,6 @@ QDragManager::~QDragManager() QApplication::restoreOverrideCursor(); #endif instance = 0; - delete [] pm_cursor; delete dropData; } @@ -379,14 +173,14 @@ QPixmap QDragManager::dragCursor(Qt::DropAction action) const if (d && d->customCursors.contains(action)) return d->customCursors[action]; else if (action == Qt::MoveAction) - return pm_cursor[0]; + return QApplicationPrivate::instance()->getPixmapCursor(Qt::DragMoveCursor); else if (action == Qt::CopyAction) - return pm_cursor[1]; + return QApplicationPrivate::instance()->getPixmapCursor(Qt::DragCopyCursor); else if (action == Qt::LinkAction) - return pm_cursor[2]; + return QApplicationPrivate::instance()->getPixmapCursor(Qt::DragLinkCursor); #ifdef Q_WS_WIN else if (action == Qt::IgnoreAction) - return pm_cursor[3]; + return QApplicationPrivate::instance()->getPixmapCursor(Qt::ForbiddenCursor); #endif return QPixmap(); } diff --git a/src/gui/kernel/qdnd_p.h b/src/gui/kernel/qdnd_p.h index d70b983..033e6a6 100644 --- a/src/gui/kernel/qdnd_p.h +++ b/src/gui/kernel/qdnd_p.h @@ -261,8 +261,6 @@ public: #endif private: - QPixmap *pm_cursor; - int n_cursor; #ifdef Q_WS_QWS Qt::DropAction currentActionForOverrideCursor; #endif diff --git a/src/gui/kernel/qdnd_s60.cpp b/src/gui/kernel/qdnd_s60.cpp index 24f0090..1aa30af 100644 --- a/src/gui/kernel/qdnd_s60.cpp +++ b/src/gui/kernel/qdnd_s60.cpp @@ -52,7 +52,7 @@ #include "qdnd_p.h" #include "qt_s60_p.h" -#include <COECNTRL.H> +#include <coecntrl.h> // pointer cursor #include <w32std.h> #include <gdi.h> diff --git a/src/gui/kernel/qdnd_x11.cpp b/src/gui/kernel/qdnd_x11.cpp index 33968bd..9591b9a 100644 --- a/src/gui/kernel/qdnd_x11.cpp +++ b/src/gui/kernel/qdnd_x11.cpp @@ -1340,9 +1340,9 @@ void QDragManager::updateCursor() if (!noDropCursor) { #ifndef QT_NO_CURSOR noDropCursor = new QCursor(Qt::ForbiddenCursor); - moveCursor = new QCursor(dragCursor(Qt::MoveAction), 0,0); - copyCursor = new QCursor(dragCursor(Qt::CopyAction), 0,0); - linkCursor = new QCursor(dragCursor(Qt::LinkAction), 0,0); + moveCursor = new QCursor(Qt::DragMoveCursor); + copyCursor = new QCursor(Qt::DragCopyCursor); + linkCursor = new QCursor(Qt::DragLinkCursor); #endif } diff --git a/src/gui/kernel/qeventdispatcher_mac.mm b/src/gui/kernel/qeventdispatcher_mac.mm index df09185..afea3ec 100644 --- a/src/gui/kernel/qeventdispatcher_mac.mm +++ b/src/gui/kernel/qeventdispatcher_mac.mm @@ -90,11 +90,16 @@ #ifndef QT_NO_THREAD # include "qmutex.h" +#endif QT_BEGIN_NAMESPACE QT_USE_NAMESPACE -#endif + +/***************************************************************************** + Internal variables and functions + *****************************************************************************/ +bool qt_blockCocoaSettingModalWindowLevel = false; /***************************************************************************** Externals @@ -548,6 +553,12 @@ bool QEventDispatcherMac::processEvents(QEventLoop::ProcessEventsFlags flags) { Q_D(QEventDispatcherMac); d->interrupt = false; + +#ifdef QT_MAC_USE_COCOA + bool interruptLater = false; + QtMacInterruptDispatcherHelp::cancelInterruptLater(); +#endif + // In case we end up recursing while we now process events, make sure // that we send remaining posted Qt events before this call returns: wakeUp(); @@ -562,25 +573,37 @@ bool QEventDispatcherMac::processEvents(QEventLoop::ProcessEventsFlags flags) QMacCocoaAutoReleasePool pool; NSEvent* event = 0; - // If Qt is used as a plugin, or just added into a native cocoa - // application, we should not run or stop NSApplication; - // This will be done from outside Qt. - // And if processEvents is called manually (rather than from QEventLoop), we - // cannot enter a tight loop and block the call, but instead return after one flush: - bool canExec_3rdParty = d->nsAppRunCalledByQt || ![NSApp isRunning]; - bool canExec_Qt = flags & QEventLoop::DialogExec || flags & QEventLoop::EventLoopExec; + // First, send all previously excluded input events, if any: + if (!(flags & QEventLoop::ExcludeUserInputEvents)) { + while (!d->queuedUserInputEvents.isEmpty()) { + event = static_cast<NSEvent *>(d->queuedUserInputEvents.takeFirst()); + if (!filterEvent(event)) { + qt_mac_send_event(flags, event, 0); + retVal = true; + } + [event release]; + } + } + + // If Qt is used as a plugin, or as an extension in a native cocoa + // application, we should not run or stop NSApplication; This will be + // done from the application itself. And if processEvents is called + // manually (rather than from a QEventLoop), we cannot enter a tight + // loop and block this call, but instead we need to return after one flush: + const bool canExec_3rdParty = d->nsAppRunCalledByQt || ![NSApp isRunning]; + const bool canExec_Qt = flags & QEventLoop::DialogExec || flags & QEventLoop::EventLoopExec; if (canExec_Qt && canExec_3rdParty) { // We can use exec-mode, meaning that we can stay in a tight loop until - // interrupted. This is mostly an optimization, but it also allow us - // to use [NSApp run], which is the recommended way of running applications - // in cocoa. [NSApp run] should be called at least once for any cocoa app. + // interrupted. This is mostly an optimization, but it allow us to use + // [NSApp run], which is the normal code path for cocoa applications. if (NSModalSession session = d->currentModalSession()) { QBoolBlocker execGuard(d->currentExecIsNSAppRun, false); while ([NSApp runModalSession:session] == NSRunContinuesResponse && !d->interrupt) qt_mac_waitForMoreModalSessionEvents(); + if (!d->interrupt && session == d->currentModalSessionCached) { - // INVARIANT: Someone called e.g. [NSApp stopModal:] from outside the event + // Someone called [NSApp stopModal:] from outside the event // dispatcher (e.g to stop a native dialog). But that call wrongly stopped // 'session' as well. As a result, we need to restart all internal sessions: d->temporarilyStopAllModalSessions(); @@ -591,54 +614,47 @@ bool QEventDispatcherMac::processEvents(QEventLoop::ProcessEventsFlags flags) [NSApp run]; } retVal = true; - } else do { - // INVARIANT: We cannot block the thread (and run in a tight loop). + } else { + // We cannot block the thread (and run in a tight loop). // Instead we will process all current pending events and return. - bool mustRelease = false; - - if (!(flags & QEventLoop::ExcludeUserInputEvents) && !d->queuedUserInputEvents.isEmpty()) { - // Process a pending user input event - mustRelease = true; - event = static_cast<NSEvent *>(d->queuedUserInputEvents.takeFirst()); - } else { - if (NSModalSession session = d->currentModalSession()) { - if (flags & QEventLoop::WaitForMoreEvents) - qt_mac_waitForMoreModalSessionEvents(); - NSInteger status = [NSApp runModalSession:session]; - if (status != NSRunContinuesResponse && session == d->currentModalSessionCached) { - // INVARIANT: Someone called e.g. [NSApp stopModal:] from outside the event - // dispatcher (e.g to stop a native dialog). But that call wrongly stopped - // 'session' as well. As a result, we need to restart all internal sessions: - d->temporarilyStopAllModalSessions(); - } - retVal = true; - break; - } else { - event = [NSApp nextEventMatchingMask:NSAnyEventMask - untilDate:nil - inMode:NSDefaultRunLoopMode - dequeue: YES]; - - if (event != nil) { - if (flags & QEventLoop::ExcludeUserInputEvents) { - if (IsMouseOrKeyEvent(event)) { - // retain event here? - [event retain]; - d->queuedUserInputEvents.append(event); - continue; - } + d->ensureNSAppInitialized(); + if (NSModalSession session = d->currentModalSession()) { + if (flags & QEventLoop::WaitForMoreEvents) + qt_mac_waitForMoreModalSessionEvents(); + NSInteger status = [NSApp runModalSession:session]; + if (status != NSRunContinuesResponse && session == d->currentModalSessionCached) { + // INVARIANT: Someone called [NSApp stopModal:] from outside the event + // dispatcher (e.g to stop a native dialog). But that call wrongly stopped + // 'session' as well. As a result, we need to restart all internal sessions: + d->temporarilyStopAllModalSessions(); + } + retVal = true; + } else do { + event = [NSApp nextEventMatchingMask:NSAnyEventMask + untilDate:nil + inMode:NSDefaultRunLoopMode + dequeue: YES]; + + if (event) { + if (flags & QEventLoop::ExcludeUserInputEvents) { + if (IsMouseOrKeyEvent(event)) { + [event retain]; + d->queuedUserInputEvents.append(event); + continue; } } + if (!filterEvent(event) && qt_mac_send_event(flags, event, 0)) + retVal = true; } - } - if (event) { - if (!filterEvent(event) && qt_mac_send_event(flags, event, 0)) - retVal = true; - if (mustRelease) - [event release]; - } - } while(!d->interrupt && event != nil); - + } while (!d->interrupt && event != nil); + + // Since the window that holds modality might have changed while processing + // events, we we need to interrupt when we return back the previous process + // event recursion to ensure that we spin the correct modal session. + // We do the interruptLater at the end of the function to ensure that we don't + // disturb the 'wait for more events' below (as deleteLater will post an event): + interruptLater = true; + } #else do { EventRef event; @@ -690,25 +706,19 @@ bool QEventDispatcherMac::processEvents(QEventLoop::ProcessEventsFlags flags) } } + // If we're interrupted, we need to interrupt the _current_ + // recursion as well to check if it is still supposed to be + // executing. This way we wind down the stack until we land + // on a recursion that again calls processEvents (typically + // from QEventLoop), and set interrupt to false: + if (d->interrupt) + interrupt(); + #ifdef QT_MAC_USE_COCOA - // In case we _now_ process events using [NSApp run], we need to stop it to - // ensure that: - // 1. the QEventLoop that called us is still executing, or - // 2. we have a modal session that needs to be spun instead. - // In case this is a plain call to processEvents (perhaps from a loop) - // from the application (rather than from a QEventLoop), we delay the - // interrupting until we/ actually enter a lower loop level (hence the - // deffered delete of the object below): - QtMacInterruptDispatcherHelp::interruptLater(); + if (interruptLater) + QtMacInterruptDispatcherHelp::interruptLater(); #endif - if (d->interrupt) { - // We should continue to leave all recursion to processEvents until - // processEvents is called again (e.g. from a QEventLoop that - // was not yet told to quit: - interrupt(); - } - return retVal; } @@ -737,39 +747,60 @@ void QEventDispatcherMac::flush() *****************************************************************************/ MacTimerHash QEventDispatcherMacPrivate::macTimerHash; bool QEventDispatcherMacPrivate::blockSendPostedEvents = false; +bool QEventDispatcherMacPrivate::interrupt = false; #ifdef QT_MAC_USE_COCOA QStack<QCocoaModalSessionInfo> QEventDispatcherMacPrivate::cocoaModalSessionStack; bool QEventDispatcherMacPrivate::currentExecIsNSAppRun = false; +bool QEventDispatcherMacPrivate::modalSessionsTemporarilyStopped = false; bool QEventDispatcherMacPrivate::nsAppRunCalledByQt = false; +bool QEventDispatcherMacPrivate::cleanupModalSessionsNeeded = false; NSModalSession QEventDispatcherMacPrivate::currentModalSessionCached = 0; -int QEventDispatcherMacPrivate::activeModalSessionCount() +void QEventDispatcherMacPrivate::ensureNSAppInitialized() { - // Returns the number of modal sessions created - // (and not just pushed onto the stack, pending to be created) - int count = 0; - for (int i=cocoaModalSessionStack.size()-1; i>=0; --i) { - QCocoaModalSessionInfo &info = cocoaModalSessionStack[i]; - if (info.session) - ++count; - } - return count; + // Some elements in Cocoa require NSApplication to be running before + // they get fully initialized, in particular the menu bar. This + // function is intended for cases where a dialog is told to execute before + // QApplication::exec is called, or the application spins the events loop + // manually rather than calling QApplication:exec. + // The function makes sure that NSApplication starts running, but stops + // it again as soon as the send posted events callback is called. That way + // we let Cocoa finish the initialization it seems to need. We'll only + // apply this trick at most once for any application, and we avoid doing it + // for the common case where main just starts QApplication::exec. + if (nsAppRunCalledByQt || [NSApp isRunning]) + return; + nsAppRunCalledByQt = true; + QBoolBlocker block1(interrupt, true); + QBoolBlocker block2(currentExecIsNSAppRun, true); + [NSApp run]; } void QEventDispatcherMacPrivate::temporarilyStopAllModalSessions() { - // Stop all created modal session, and as such, make then - // pending again. The next call to currentModalSession will - // recreate the session on top again: + // Flush, and Stop, all created modal session, and as + // such, make them pending again. The next call to + // currentModalSession will recreate them again. The + // reason to stop all session like this is that otherwise + // a call [NSApp stop] would not stop NSApp, but rather + // the current modal session. So if we need to stop NSApp + // we need to stop all the modal session first. To avoid changing + // the stacking order of the windows while doing so, we put + // up a block that is used in QCocoaWindow and QCocoaPanel: + QBoolBlocker block1(blockSendPostedEvents, true); + QBoolBlocker block2(qt_blockCocoaSettingModalWindowLevel, true); + int stackSize = cocoaModalSessionStack.size(); for (int i=stackSize-1; i>=0; --i) { QCocoaModalSessionInfo &info = cocoaModalSessionStack[i]; if (info.session) { + [NSApp runModalSession:info.session]; [NSApp endModalSession:info.session]; info.session = 0; } } + modalSessionsTemporarilyStopped = true; currentModalSessionCached = 0; } @@ -783,23 +814,6 @@ NSModalSession QEventDispatcherMacPrivate::currentModalSession() if (cocoaModalSessionStack.isEmpty()) return 0; - // Since this code will end up calling our Qt event handler - // (also from beginModalSessionForWindow), we need to block - // that to avoid side effects of events beeing delivered: - QBoolBlocker block(blockSendPostedEvents, true); - - if (![NSApp isRunning]) { - // Sadly, we need to introduce this little event flush - // to stop dialogs from blinking/poping in front if a - // modal session restart was needed: - while (NSEvent *event = [NSApp nextEventMatchingMask:0 - untilDate:nil - inMode:NSDefaultRunLoopMode - dequeue: YES]) { - qt_mac_send_event(0, event, 0); - } - } - int sessionCount = cocoaModalSessionStack.size(); for (int i=0; i<sessionCount; ++i) { QCocoaModalSessionInfo &info = cocoaModalSessionStack[i]; @@ -812,11 +826,28 @@ NSModalSession QEventDispatcherMacPrivate::currentModalSession() NSWindow *window = qt_mac_window_for(info.widget); if (!window) continue; + + ensureNSAppInitialized(); + QBoolBlocker block1(blockSendPostedEvents, true); info.session = [NSApp beginModalSessionForWindow:window]; } currentModalSessionCached = info.session; } + if (modalSessionsTemporarilyStopped && currentModalSessionCached) { + // After a call to temporarilyStopAllModalSessions, cocoa have + // now posted events to restore ended modal session windows to + // the correct window level. Those events will be processed + // _after_ our new calls to beginModalSessionForWindow have + // taken effect, which will end up stacking the windows wrong on + // screen. To work around this, we block cocoa from changing the + // stacking order of the windows, and flush out the pending events + // (the block is used in QCocoaWindow and QCocoaPanel): + QBoolBlocker block1(blockSendPostedEvents, true); + QBoolBlocker block2(qt_blockCocoaSettingModalWindowLevel, true); + [NSApp runModalSession:currentModalSessionCached]; + } + modalSessionsTemporarilyStopped = false; return currentModalSessionCached; } @@ -852,6 +883,34 @@ void QEventDispatcherMacPrivate::updateChildrenWorksWhenModal() } } +void QEventDispatcherMacPrivate::cleanupModalSessions() +{ + // Go through the list of modal sessions, and end those + // that no longer has a widget assosiated; no widget means + // the the session has logically ended. The reason we wait like + // this to actually end the sessions for real (rather than at the + // point they were marked as stopped), is that ending a session + // when no other session runs below it on the stack will make cocoa + // drop some events on the floor. + QMacCocoaAutoReleasePool pool; + int stackSize = cocoaModalSessionStack.size(); + + for (int i=stackSize-1; i>=0; --i) { + QCocoaModalSessionInfo &info = cocoaModalSessionStack[i]; + if (info.widget) { + currentModalSessionCached = info.session; + break; + } + cocoaModalSessionStack.remove(i); + currentModalSessionCached = 0; + if (info.session) + [NSApp endModalSession:info.session]; + } + + updateChildrenWorksWhenModal(); + cleanupModalSessionsNeeded = false; +} + void QEventDispatcherMacPrivate::beginModalSession(QWidget *widget) { // Add a new, empty (null), NSModalSession to the stack. @@ -860,7 +919,7 @@ void QEventDispatcherMacPrivate::beginModalSession(QWidget *widget) // is non-zero, and the session pointer is zero (it will become active upon a call to // currentModalSession). A QCocoaModalSessionInfo is considered pending to be stopped if // the widget pointer is zero, and the session pointer is non-zero (it will be fully - // stopped in endModalSession(). + // stopped in cleanupModalSessions()). QCocoaModalSessionInfo info = {widget, 0}; cocoaModalSessionStack.push(info); updateChildrenWorksWhenModal(); @@ -877,38 +936,21 @@ void QEventDispatcherMacPrivate::endModalSession(QWidget *widget) int stackSize = cocoaModalSessionStack.size(); for (int i=stackSize-1; i>=0; --i) { QCocoaModalSessionInfo &info = cocoaModalSessionStack[i]; - if (info.widget == widget) + if (info.widget == widget) { info.widget = 0; - } - - // Now we stop, and remove, all sessions marked as pending - // to be stopped on _top_ of the stack, if any: - bool needToInterruptEventDispatcher = false; - bool needToUpdateChildrenWorksWhenModal = false; - - for (int i=stackSize-1; i>=0; --i) { - QCocoaModalSessionInfo &info = cocoaModalSessionStack[i]; - if (info.widget) - break; - cocoaModalSessionStack.remove(i); - needToUpdateChildrenWorksWhenModal = true; - currentModalSessionCached = 0; - if (info.session) { - [NSApp endModalSession:info.session]; - needToInterruptEventDispatcher = true; + if (i == stackSize-1) { + // The top sessions ended. Interrupt the event dispatcher + // to start spinning the correct session immidiatly: + cleanupModalSessionsNeeded = true; + QEventDispatcherMac::instance()->interrupt(); + } } } - - if (needToUpdateChildrenWorksWhenModal) - updateChildrenWorksWhenModal(); - if (needToInterruptEventDispatcher) - QEventDispatcherMac::instance()->interrupt(); } #endif QEventDispatcherMacPrivate::QEventDispatcherMacPrivate() - : interrupt(false) { } @@ -967,13 +1009,39 @@ Boolean QEventDispatcherMacPrivate::postedEventSourceEqualCallback(const void *i inline static void processPostedEvents(QEventDispatcherMacPrivate *const d, const bool blockSendPostedEvents) { - if (blockSendPostedEvents || d->interrupt) { + if (blockSendPostedEvents) { + // We're told to not send posted events (because the event dispatcher + // is currently working on setting up the correct session to run). But + // we still need to make sure that we don't fall asleep until pending events + // are sendt, so we just signal this need, and return: CFRunLoopSourceSignal(d->postedEventsSource); - } else { - if (!d->threadData->canWait || (d->serialNumber != d->lastSerial)) { - d->lastSerial = d->serialNumber; - QApplicationPrivate::sendPostedEvents(0, 0, d->threadData); + return; + } + +#ifdef QT_MAC_USE_COCOA + if (d->cleanupModalSessionsNeeded) + d->cleanupModalSessions(); +#endif + + if (d->interrupt) { +#ifdef QT_MAC_USE_COCOA + if (d->currentExecIsNSAppRun) { + // The event dispatcher has been interrupted. But since + // [NSApplication run] is running the event loop, we + // delayed stopping it until now (to let cocoa process + // pending cocoa events first). + if (d->currentModalSessionCached) + d->temporarilyStopAllModalSessions(); + [NSApp stop:NSApp]; + d->cancelWaitForMoreEvents(); } +#endif + return; + } + + if (!d->threadData->canWait || (d->serialNumber != d->lastSerial)) { + d->lastSerial = d->serialNumber; + QApplicationPrivate::sendPostedEvents(0, 0, d->threadData); } } @@ -983,6 +1051,9 @@ void QEventDispatcherMacPrivate::firstLoopEntry(CFRunLoopObserverRef ref, { Q_UNUSED(ref); Q_UNUSED(activity); +#ifdef QT_MAC_USE_COCOA + QApplicationPrivate::qt_initAfterNSAppStarted(); +#endif processPostedEvents(static_cast<QEventDispatcherMacPrivate *>(info), blockSendPostedEvents); } @@ -991,6 +1062,18 @@ void QEventDispatcherMacPrivate::postedEventsSourcePerformCallback(void *info) processPostedEvents(static_cast<QEventDispatcherMacPrivate *>(info), blockSendPostedEvents); } +#ifdef QT_MAC_USE_COCOA +void QEventDispatcherMacPrivate::cancelWaitForMoreEvents() +{ + // In case the event dispatcher is waiting for more + // events somewhere, we post a dummy event to wake it up: + QMacCocoaAutoReleasePool pool; + [NSApp postEvent:[NSEvent otherEventWithType:NSApplicationDefined location:NSZeroPoint + modifierFlags:0 timestamp:0. windowNumber:0 context:0 + subtype:QtCocoaEventSubTypeWakeup data1:0 data2:0] atStart:NO]; +} +#endif + void QEventDispatcherMac::interrupt() { Q_D(QEventDispatcherMac); @@ -1000,20 +1083,14 @@ void QEventDispatcherMac::interrupt() #ifndef QT_MAC_USE_COCOA CFRunLoopStop(mainRunLoop()); #else - QMacCocoaAutoReleasePool pool; - // In case we wait for more events inside - // processEvents (or NSApp run), post a dummy to wake it up: - static const short NSAppShouldStopForQt = SHRT_MAX; - [NSApp postEvent:[NSEvent otherEventWithType:NSApplicationDefined location:NSZeroPoint - modifierFlags:0 timestamp:0. windowNumber:0 context:0 - subtype:NSAppShouldStopForQt data1:0 data2:0] atStart:NO]; - - if (d->activeModalSessionCount() == 0) { - // We should only stop NSApp if we actually started it (and - // not some 3rd party application, e.g. if we are a plugin). - if (d->nsAppRunCalledByQt) - [NSApp stop:NSApp]; - } + // We do nothing more here than setting d->interrupt = true, and + // poke the event loop if it is sleeping. Actually stopping + // NSApp, or the current modal session, is done inside the send + // posted events callback. We do this to ensure that all current pending + // cocoa events gets delivered before we stop. Otherwise, if we now stop + // the last event loop recursion, cocoa will just drop pending posted + // events on the floor before we get a chance to reestablish a new session. + d->cancelWaitForMoreEvents(); #endif } @@ -1054,17 +1131,18 @@ QEventDispatcherMac::~QEventDispatcherMac() CFRelease(d->firstTimeObserver); } -///////////////////////////////////////////////////////////////////////////// - #ifdef QT_MAC_USE_COCOA QtMacInterruptDispatcherHelp* QtMacInterruptDispatcherHelp::instance = 0; QtMacInterruptDispatcherHelp::QtMacInterruptDispatcherHelp() : cancelled(false) { - // This is the whole point of encapsulation this code - // inside a class; we can make the code (inside destructor) - // execute on lower loop level: + // The whole point of this class is that we enable a way to interrupt + // the event dispatcher when returning back to a lower recursion level + // than where interruptLater was called. This is needed to detect if + // [NSApp run] should still be running at the recursion level it is at. + // Since the interrupt is canceled if processEvents is called before + // this object gets deleted, we also avoid interrupting unnecessary. deleteLater(); } @@ -1072,34 +1150,26 @@ QtMacInterruptDispatcherHelp::~QtMacInterruptDispatcherHelp() { if (cancelled) return; - instance = 0; - - if (QEventDispatcherMacPrivate::currentExecIsNSAppRun) { - int activeCount = QEventDispatcherMacPrivate::activeModalSessionCount(); - if (activeCount > 0) { - // The problem we now have hit: [NSApp stop] will not stop NSApp - // if a session is active; it will stop the session instead. - // So to stop NSApp, we need to temporarily stop all the - // sessions, then stop NSApp, then restart the session on top again. - // We need to do this to ensure that we're not stuck inside - // [NSApp run] when we really should be running a modal session: - QEventDispatcherMacPrivate::temporarilyStopAllModalSessions(); - } - } - // Always interrupt once more in case the modal session stack changed - // while processEvents was called manually from within the application: QEventDispatcherMac::instance()->interrupt(); } -void QtMacInterruptDispatcherHelp::interruptLater() { - if (instance) { - instance->cancelled = true; - delete instance; - } +void QtMacInterruptDispatcherHelp::cancelInterruptLater() +{ + if (!instance) + return; + instance->cancelled = true; + delete instance; + instance = 0; +} + +void QtMacInterruptDispatcherHelp::interruptLater() +{ + cancelInterruptLater(); instance = new QtMacInterruptDispatcherHelp; } #endif QT_END_NAMESPACE + diff --git a/src/gui/kernel/qeventdispatcher_mac_p.h b/src/gui/kernel/qeventdispatcher_mac_p.h index a335f16..e932532 100644 --- a/src/gui/kernel/qeventdispatcher_mac_p.h +++ b/src/gui/kernel/qeventdispatcher_mac_p.h @@ -174,13 +174,17 @@ public: static QStack<QCocoaModalSessionInfo> cocoaModalSessionStack; static bool currentExecIsNSAppRun; static bool nsAppRunCalledByQt; + static bool cleanupModalSessionsNeeded; + static bool modalSessionsTemporarilyStopped; static NSModalSession currentModalSessionCached; - static void updateChildrenWorksWhenModal(); static NSModalSession currentModalSession(); - static int activeModalSessionCount(); + static void updateChildrenWorksWhenModal(); static void temporarilyStopAllModalSessions(); static void beginModalSession(QWidget *widget); static void endModalSession(QWidget *widget); + static void cancelWaitForMoreEvents(); + static void cleanupModalSessions(); + static void ensureNSAppInitialized(); #endif MacSocketHash macSockets; @@ -190,7 +194,7 @@ public: CFRunLoopObserverRef firstTimeObserver; QAtomicInt serialNumber; int lastSerial; - bool interrupt; + static bool interrupt; private: static Boolean postedEventSourceEqualCallback(const void *info1, const void *info2); static void postedEventsSourcePerformCallback(void *info); @@ -211,6 +215,7 @@ class QtMacInterruptDispatcherHelp : public QObject public: static void interruptLater(); + static void cancelInterruptLater(); }; #endif diff --git a/src/gui/kernel/qgesture_p.h b/src/gui/kernel/qgesture_p.h index dee5592..649a310 100644 --- a/src/gui/kernel/qgesture_p.h +++ b/src/gui/kernel/qgesture_p.h @@ -69,13 +69,13 @@ public: QGesturePrivate() : gestureType(Qt::CustomGesture), state(Qt::NoGesture), isHotSpotSet(false), gestureCancelPolicy(0) - { } Qt::GestureType gestureType; Qt::GestureState state; QPointF hotSpot; + QPointF sceneHotSpot; uint isHotSpotSet : 1; uint gestureCancelPolicy : 2; }; diff --git a/src/gui/kernel/qgesturerecognizer.cpp b/src/gui/kernel/qgesturerecognizer.cpp index 8735d27..c88a9a7 100644 --- a/src/gui/kernel/qgesturerecognizer.cpp +++ b/src/gui/kernel/qgesturerecognizer.cpp @@ -181,6 +181,7 @@ void QGestureRecognizer::reset(QGesture *gesture) QGesturePrivate *d = gesture->d_func(); d->state = Qt::NoGesture; d->hotSpot = QPointF(); + d->sceneHotSpot = QPointF(); d->isHotSpotSet = false; } } diff --git a/src/gui/kernel/qguieventdispatcher_glib.cpp b/src/gui/kernel/qguieventdispatcher_glib.cpp index 7b30741..ac2b5f7 100644 --- a/src/gui/kernel/qguieventdispatcher_glib.cpp +++ b/src/gui/kernel/qguieventdispatcher_glib.cpp @@ -216,4 +216,9 @@ void QGuiEventDispatcherGlib::startingUp() g_source_add_poll(&d->x11EventSource->source, &d->x11EventSource->pollfd); } +void QGuiEventDispatcherGlib::flush() +{ + XFlush(X11->display); +} + QT_END_NAMESPACE diff --git a/src/gui/kernel/qguieventdispatcher_glib_p.h b/src/gui/kernel/qguieventdispatcher_glib_p.h index ff778cc..758650b 100644 --- a/src/gui/kernel/qguieventdispatcher_glib_p.h +++ b/src/gui/kernel/qguieventdispatcher_glib_p.h @@ -71,6 +71,7 @@ public: bool processEvents(QEventLoop::ProcessEventsFlags flags); void startingUp(); + void flush(); }; QT_END_NAMESPACE diff --git a/src/gui/kernel/qkeymapper_win.cpp b/src/gui/kernel/qkeymapper_win.cpp index 578f32a..e555c5c 100644 --- a/src/gui/kernel/qkeymapper_win.cpp +++ b/src/gui/kernel/qkeymapper_win.cpp @@ -619,7 +619,7 @@ void QKeyMapperPrivate::clearMappings() /* MAKELCID()'s first argument is a WORD, and GetKeyboardLayout() * returns a DWORD. */ - LCID newLCID = MAKELCID((DWORD)GetKeyboardLayout(0), SORT_DEFAULT); + LCID newLCID = MAKELCID((quintptr)GetKeyboardLayout(0), SORT_DEFAULT); // keyboardInputLocale = qt_localeFromLCID(newLCID); bool bidi = false; diff --git a/src/gui/kernel/qkeysequence.cpp b/src/gui/kernel/qkeysequence.cpp index 2a13546..99bf971 100644 --- a/src/gui/kernel/qkeysequence.cpp +++ b/src/gui/kernel/qkeysequence.cpp @@ -861,6 +861,8 @@ QKeySequence::QKeySequence() Up to four key codes may be entered by separating them with commas, e.g. "Alt+X,Ctrl+S,Q". + \a key should be in NativeText format. + This constructor is typically used with \link QObject::tr() tr \endlink(), so that shortcut keys can be replaced in translations: @@ -877,6 +879,16 @@ QKeySequence::QKeySequence(const QString &key) } /*! + \since 4.x + Creates a key sequence from the \a key string based on \a format. +*/ +QKeySequence::QKeySequence(const QString &key, QKeySequence::SequenceFormat format) +{ + d = new QKeySequencePrivate(); + assign(key, format); +} + +/*! Constructs a key sequence with up to 4 keys \a k1, \a k2, \a k3 and \a k4. @@ -1055,9 +1067,24 @@ QKeySequence QKeySequence::mnemonic(const QString &text) contain up to four key codes, provided they are separated by a comma; for example, "Alt+X,Ctrl+S,Z". The return value is the number of key codes added. + \a keys should be in NativeText format. */ int QKeySequence::assign(const QString &ks) { + return assign(ks, NativeText); +} + +/*! + \fn int QKeySequence::assign(const QString &keys, QKeySequence::SequenceFormat format) + \since 4.x + + Adds the given \a keys to the key sequence (based on \a format). + \a keys may contain up to four key codes, provided they are + separated by a comma; for example, "Alt+X,Ctrl+S,Z". The return + value is the number of key codes added. +*/ +int QKeySequence::assign(const QString &ks, QKeySequence::SequenceFormat format) +{ QString keyseq = ks; QString part; int n = 0; @@ -1086,7 +1113,7 @@ int QKeySequence::assign(const QString &ks) } part = keyseq.left(-1 == p ? keyseq.length() : p - diff); keyseq = keyseq.right(-1 == p ? 0 : keyseq.length() - (p + 1)); - d->key[n] = decodeString(part); + d->key[n] = QKeySequencePrivate::decodeString(part, format); ++n; } return n; @@ -1557,12 +1584,7 @@ QString QKeySequence::toString(SequenceFormat format) const */ QKeySequence QKeySequence::fromString(const QString &str, SequenceFormat format) { - QStringList sl = str.split(QLatin1String(", ")); - int keys[4] = {0, 0, 0, 0}; - int total = qMin(sl.count(), 4); - for (int i = 0; i < total; ++i) - keys[i] = QKeySequencePrivate::decodeString(sl[i], format); - return QKeySequence(keys[0], keys[1], keys[2], keys[3]); + return QKeySequence(str, format); } /***************************************************************************** diff --git a/src/gui/kernel/qkeysequence.h b/src/gui/kernel/qkeysequence.h index 1409e28..5a973e3 100644 --- a/src/gui/kernel/qkeysequence.h +++ b/src/gui/kernel/qkeysequence.h @@ -141,8 +141,14 @@ public: Quit }; + enum SequenceFormat { + NativeText, + PortableText + }; + QKeySequence(); QKeySequence(const QString &key); + QKeySequence(const QString &key, SequenceFormat format); QKeySequence(int k1, int k2 = 0, int k3 = 0, int k4 = 0); QKeySequence(const QKeySequence &ks); QKeySequence(StandardKey key); @@ -160,11 +166,6 @@ public: #endif }; - enum SequenceFormat { - NativeText, - PortableText - }; - QString toString(SequenceFormat format = PortableText) const; static QKeySequence fromString(const QString &str, SequenceFormat format = PortableText); @@ -194,6 +195,7 @@ private: static int decodeString(const QString &ks); static QString encodeString(int key); int assign(const QString &str); + int assign(const QString &str, SequenceFormat format); void setKey(int key, int index); QKeySequencePrivate *d; diff --git a/src/gui/kernel/qmime_mac.cpp b/src/gui/kernel/qmime_mac.cpp index 071f80d..c6fd184 100644 --- a/src/gui/kernel/qmime_mac.cpp +++ b/src/gui/kernel/qmime_mac.cpp @@ -154,6 +154,7 @@ CFStringRef qt_mac_mime_typeUTI = CFSTR("com.pasteboard.trolltech.marker"); \i public.url - converts to "text/uri-list" \i public.file-url - converts to "text/uri-list" \i public.tiff - converts to "application/x-qt-image" + \i public.vcard - converts to "text/plain" \i com.apple.traditional-mac-plain-text - converts to "text/plain" \i com.apple.pict - converts to "application/x-qt-image" \endlist @@ -909,6 +910,61 @@ QList<QByteArray> QMacPasteboardMimeUrl::convertFromMime(const QString &mime, QV return ret; } +class QMacPasteboardMimeVCard : public QMacPasteboardMime +{ +public: + QMacPasteboardMimeVCard() : QMacPasteboardMime(MIME_ALL){ } + QString convertorName(); + + QString flavorFor(const QString &mime); + QString mimeFor(QString flav); + bool canConvert(const QString &mime, QString flav); + QVariant convertToMime(const QString &mime, QList<QByteArray> data, QString flav); + QList<QByteArray> convertFromMime(const QString &mime, QVariant data, QString flav); +}; + +QString QMacPasteboardMimeVCard::convertorName() +{ + return QString("VCard"); +} + +bool QMacPasteboardMimeVCard::canConvert(const QString &mime, QString flav) +{ + return mimeFor(flav) == mime; +} + +QString QMacPasteboardMimeVCard::flavorFor(const QString &mime) +{ + if(mime.startsWith(QLatin1String("text/plain"))) + return QLatin1String("public.vcard"); + return QString(); +} + +QString QMacPasteboardMimeVCard::mimeFor(QString flav) +{ + if (flav == QLatin1String("public.vcard")) + return QLatin1String("text/plain"); + return QString(); +} + +QVariant QMacPasteboardMimeVCard::convertToMime(const QString &mime, QList<QByteArray> data, QString) +{ + QByteArray cards; + if (mime == QLatin1String("text/plain")) { + for (int i=0; i<data.size(); ++i) + cards += data[i]; + } + return QVariant(cards); +} + +QList<QByteArray> QMacPasteboardMimeVCard::convertFromMime(const QString &mime, QVariant data, QString) +{ + QList<QByteArray> ret; + if (mime == QLatin1String("text/plain")) + ret.append(data.toString().toUtf8()); + return ret; +} + #ifdef QT3_SUPPORT class QMacPasteboardMimeQt3Any : public QMacPasteboardMime { private: @@ -1116,6 +1172,7 @@ void QMacPasteboardMime::initialize() new QMacPasteboardMimeFileUri; new QMacPasteboardMimeUrl; new QMacPasteboardMimeTypeName; + new QMacPasteboardMimeVCard; //make sure our "non-standard" types are always last! --Sam new QMacPasteboardMimeAny; #ifdef QT3_SUPPORT diff --git a/src/gui/kernel/qnsthemeframe_mac_p.h b/src/gui/kernel/qnsthemeframe_mac_p.h index 77a6963..d061b1b 100644 --- a/src/gui/kernel/qnsthemeframe_mac_p.h +++ b/src/gui/kernel/qnsthemeframe_mac_p.h @@ -157,7 +157,7 @@ - (void)resetCursorRects; - (char)shouldBeTreatedAsInkEvent:fp8; - (char)_shouldBeTreatedAsInkEventInInactiveWindow:fp8; -- hitTest:(struct _NSPoint)fp8; +//- hitTest:(struct _NSPoint)fp8; // collides with hittest in qcocoasharedwindowmethods_mac_p.h - (NSRect)_leftGroupRect; - (NSRect)_rightGroupRect; - (void)_updateWidgets; diff --git a/src/gui/kernel/qsound_s60.cpp b/src/gui/kernel/qsound_s60.cpp index 1832b85..df2830b 100644 --- a/src/gui/kernel/qsound_s60.cpp +++ b/src/gui/kernel/qsound_s60.cpp @@ -51,7 +51,7 @@ #include <private/qcore_symbian_p.h> #include <e32std.h> -#include <MdaAudioSamplePlayer.h> +#include <mdaaudiosampleplayer.h> QT_BEGIN_NAMESPACE diff --git a/src/gui/kernel/qt_cocoa_helpers_mac.mm b/src/gui/kernel/qt_cocoa_helpers_mac.mm index 65c04e5..9560952 100644 --- a/src/gui/kernel/qt_cocoa_helpers_mac.mm +++ b/src/gui/kernel/qt_cocoa_helpers_mac.mm @@ -83,6 +83,7 @@ #include <private/qt_cocoa_helpers_mac_p.h> #include <private/qt_mac_p.h> #include <private/qapplication_p.h> +#include <private/qcocoaapplication_mac_p.h> #include <private/qcocoawindow_mac_p.h> #include <private/qcocoaview_mac_p.h> #include <private/qkeymapper_p.h> @@ -137,7 +138,6 @@ void QMacWindowFader::performFade() } extern bool qt_sendSpontaneousEvent(QObject *receiver, QEvent *event); // qapplication.cpp; -extern Qt::MouseButton cocoaButton2QtButton(NSInteger buttonNum); // qcocoaview.mm extern QWidget * mac_mouse_grabber; extern QPointer<QWidget> qt_button_down; //qapplication_mac.cpp @@ -369,6 +369,16 @@ QMacTabletHash *qt_mac_tablet_hash() } #ifdef QT_MAC_USE_COCOA + +// Clears the QWidget pointer that each QCocoaView holds. +void qt_mac_clearCocoaViewQWidgetPointers(QWidget *widget) +{ + QCocoaView *cocoaView = reinterpret_cast<QCocoaView *>(qt_mac_nativeview_for(widget)); + if (cocoaView && [cocoaView respondsToSelector:@selector(qt_qwidget)]) { + [cocoaView qt_clearQWidget]; + } +} + void qt_dispatchTabletProximityEvent(void * /*NSEvent * */ tabletEvent) { NSEvent *proximityEvent = static_cast<NSEvent *>(tabletEvent); @@ -647,6 +657,21 @@ bool qt_dispatchKeyEventWithCocoa(void * /*NSEvent * */ keyEvent, QWidget *widge } #endif +Qt::MouseButton cocoaButton2QtButton(NSInteger buttonNum) +{ + if (buttonNum == 0) + return Qt::LeftButton; + if (buttonNum == 1) + return Qt::RightButton; + if (buttonNum == 2) + return Qt::MidButton; + if (buttonNum == 3) + return Qt::XButton1; + if (buttonNum == 4) + return Qt::XButton2; + return Qt::NoButton; +} + // Helper to share code between QCocoaWindow and QCocoaView bool qt_dispatchKeyEvent(void * /*NSEvent * */ keyEvent, QWidget *widgetToGetEvent) { @@ -955,7 +980,7 @@ bool qt_mac_handleMouseEvent(void * /* NSView * */view, void * /* NSEvent * */ev #ifndef QT_NAMESPACE Q_ASSERT(clickCount > 0); #endif - if (clickCount % 2 == 0) + if (clickCount % 2 == 0 && buttons == button) eventType = QEvent::MouseButtonDblClick; if (button == Qt::LeftButton && (keyMods & Qt::MetaModifier)) { button = Qt::RightButton; @@ -967,6 +992,7 @@ bool qt_mac_handleMouseEvent(void * /* NSView * */view, void * /* NSEvent * */ev button = Qt::RightButton; [theView qt_setLeftButtonIsRightButton: false]; } + qt_button_down = 0; break; } [QT_MANGLE_NAMESPACE(QCocoaView) currentMouseEvent]->localPoint = localPoint; @@ -1279,6 +1305,41 @@ void qt_cocoaChangeOverrideCursor(const QCursor &cursor) QMacCocoaAutoReleasePool pool; [static_cast<NSCursor *>(qt_mac_nsCursorForQCursor(cursor)) set]; } + +// WARNING: If Qt did not create NSApplication (e.g. in case it is +// used as a plugin), and at the same time, there is no window on +// screen (or the window that the event is sendt to becomes hidden etc +// before the event gets delivered), the message will not be performed. +bool qt_cocoaPostMessage(id target, SEL selector) +{ + if (!target) + return false; + + NSInteger windowNumber = 0; + if (![NSApp isMemberOfClass:[QNSApplication class]]) { + // INVARIANT: Cocoa is not using our NSApplication subclass. That means + // we don't control the main event handler either. So target the event + // for one of the windows on screen: + NSWindow *nswin = [NSApp mainWindow]; + if (!nswin) { + nswin = [NSApp keyWindow]; + if (!nswin) + return false; + } + windowNumber = [nswin windowNumber]; + } + + // WARNING: data1 and data2 is truncated to from 64-bit to 32-bit on OS 10.5! + // That is why we need to split the address in two parts: + QCocoaPostMessageArgs *args = new QCocoaPostMessageArgs(target, selector); + quint32 lower = quintptr(args); + quint32 upper = quintptr(args) >> 32; + NSEvent *e = [NSEvent otherEventWithType:NSApplicationDefined + location:NSZeroPoint modifierFlags:0 timestamp:0 windowNumber:windowNumber + context:nil subtype:QtCocoaEventSubTypePostMessage data1:lower data2:upper]; + [NSApp postEvent:e atStart:NO]; + return true; +} #endif QMacCocoaAutoReleasePool::QMacCocoaAutoReleasePool() diff --git a/src/gui/kernel/qt_cocoa_helpers_mac_p.h b/src/gui/kernel/qt_cocoa_helpers_mac_p.h index 6f0c4ce..c43ea55 100644 --- a/src/gui/kernel/qt_cocoa_helpers_mac_p.h +++ b/src/gui/kernel/qt_cocoa_helpers_mac_p.h @@ -114,6 +114,12 @@ typedef struct CGPoint NSPoint; #endif QT_BEGIN_NAMESPACE + +enum { + QtCocoaEventSubTypeWakeup = SHRT_MAX, + QtCocoaEventSubTypePostMessage = SHRT_MAX-1 +}; + Qt::MouseButtons qt_mac_get_buttons(int buttons); Qt::MouseButton qt_mac_get_button(EventMouseButton button); void macWindowFade(void * /*OSWindowRef*/ window, float durationSeconds = 0.15); @@ -181,6 +187,25 @@ inline QString qt_mac_NSStringToQString(const NSString *nsstr) inline NSString *qt_mac_QStringToNSString(const QString &qstr) { return [reinterpret_cast<const NSString *>(QCFString::toCFStringRef(qstr)) autorelease]; } + +#ifdef QT_MAC_USE_COCOA +class QCocoaPostMessageArgs { +public: + id target; + SEL selector; + QCocoaPostMessageArgs(id target, SEL selector) : target(target), selector(selector) + { + [target retain]; + } + + ~QCocoaPostMessageArgs() + { + [target release]; + } +}; +bool qt_cocoaPostMessage(id target, SEL selector); +#endif + #endif QT_END_NAMESPACE diff --git a/src/gui/kernel/qt_x11_p.h b/src/gui/kernel/qt_x11_p.h index d110084..167557b 100644 --- a/src/gui/kernel/qt_x11_p.h +++ b/src/gui/kernel/qt_x11_p.h @@ -331,7 +331,7 @@ struct QXdndDropTransaction class QMimeData; struct QX11Data; -extern QX11Data *qt_x11Data; +extern Q_GUI_EXPORT QX11Data *qt_x11Data; enum DesktopEnvironment { DE_UNKNOWN, @@ -564,11 +564,8 @@ struct QX11Data _MOTIF_WM_HINTS, DTWM_IS_RUNNING, - KDE_FULL_SESSION, - KWIN_RUNNING, - KWM_RUNNING, - GNOME_BACKGROUND_PROPERTIES, ENLIGHTENMENT_DESKTOP, + _DT_SAVE_MODE, _SGI_DESKS_MANAGER, // EWMH (aka NETWM) diff --git a/src/gui/kernel/qwidget.cpp b/src/gui/kernel/qwidget.cpp index d3340df..2f6ec6b 100644 --- a/src/gui/kernel/qwidget.cpp +++ b/src/gui/kernel/qwidget.cpp @@ -1472,6 +1472,15 @@ QWidget::~QWidget() d->declarativeData = 0; // don't activate again in ~QObject } +#ifdef QT_MAC_USE_COCOA + // QCocoaView holds a pointer back to this widget. Clear it now + // to make sure it's not followed later on. The lifetime of the + // QCocoaView might exceed the lifetime of this widget in cases + // where Cocoa itself holds references to it. + extern void qt_mac_clearCocoaViewQWidgetPointers(QWidget *); + qt_mac_clearCocoaViewQWidgetPointers(this); +#endif + if (!d->children.isEmpty()) d->deleteChildren(); @@ -4880,90 +4889,7 @@ void QWidget::unsetCursor() void QWidget::render(QPaintDevice *target, const QPoint &targetOffset, const QRegion &sourceRegion, RenderFlags renderFlags) { - Q_D(QWidget); - if (!target) { - qWarning("QWidget::render: null pointer to paint device"); - return; - } - - const bool inRenderWithPainter = d->extra && d->extra->inRenderWithPainter; - QRegion paintRegion = !inRenderWithPainter ? d->prepareToRender(sourceRegion, renderFlags) - : sourceRegion; - if (paintRegion.isEmpty()) - return; - -#ifndef Q_WS_MAC - QPainter *oldSharedPainter = inRenderWithPainter ? d->sharedPainter() : 0; - - // Use the target's shared painter if set (typically set when doing - // "other->render(widget);" in the widget's paintEvent. - if (target->devType() == QInternal::Widget) { - QWidgetPrivate *targetPrivate = static_cast<QWidget *>(target)->d_func(); - if (targetPrivate->extra && targetPrivate->extra->inRenderWithPainter) { - QPainter *targetPainter = targetPrivate->sharedPainter(); - if (targetPainter && targetPainter->isActive()) - d->setSharedPainter(targetPainter); - } - } -#endif - - // Use the target's redirected device if set and adjust offset and paint - // region accordingly. This is typically the case when people call render - // from the paintEvent. - QPoint offset = targetOffset; - offset -= paintRegion.boundingRect().topLeft(); - QPoint redirectionOffset; - QPaintDevice *redirected = 0; - - if (target->devType() == QInternal::Widget) - redirected = static_cast<QWidget *>(target)->d_func()->redirected(&redirectionOffset); - if (!redirected) - redirected = QPainter::redirected(target, &redirectionOffset); - - if (redirected) { - target = redirected; - offset -= redirectionOffset; - } - - if (!inRenderWithPainter) { // Clip handled by shared painter (in qpainter.cpp). - if (QPaintEngine *targetEngine = target->paintEngine()) { - const QRegion targetSystemClip = targetEngine->systemClip(); - if (!targetSystemClip.isEmpty()) - paintRegion &= targetSystemClip.translated(-offset); - } - } - - // Set backingstore flags. - int flags = QWidgetPrivate::DrawPaintOnScreen | QWidgetPrivate::DrawInvisible; - if (renderFlags & DrawWindowBackground) - flags |= QWidgetPrivate::DrawAsRoot; - - if (renderFlags & DrawChildren) - flags |= QWidgetPrivate::DrawRecursive; - else - flags |= QWidgetPrivate::DontSubtractOpaqueChildren; - -#ifdef Q_WS_QWS - flags |= QWidgetPrivate::DontSetCompositionMode; -#endif - - if (target->devType() == QInternal::Printer) { - QPainter p(target); - d->render_helper(&p, targetOffset, paintRegion, renderFlags); - return; - } - -#ifndef Q_WS_MAC - // Render via backingstore. - d->drawWidget(target, paintRegion, offset, flags, d->sharedPainter()); - - // Restore shared painter. - if (oldSharedPainter) - d->setSharedPainter(oldSharedPainter); -#else - // Render via backingstore (no shared painter). - d->drawWidget(target, paintRegion, offset, flags, 0); -#endif + d_func()->render(target, targetOffset, sourceRegion, renderFlags, false); } /*! @@ -5409,6 +5335,97 @@ void QWidgetPrivate::drawWidget(QPaintDevice *pdev, const QRegion &rgn, const QP } } +void QWidgetPrivate::render(QPaintDevice *target, const QPoint &targetOffset, + const QRegion &sourceRegion, QWidget::RenderFlags renderFlags, + bool readyToRender) +{ + Q_Q(QWidget); + if (!target) { + qWarning("QWidget::render: null pointer to paint device"); + return; + } + + const bool inRenderWithPainter = extra && extra->inRenderWithPainter; + QRegion paintRegion = !inRenderWithPainter && !readyToRender + ? prepareToRender(sourceRegion, renderFlags) + : sourceRegion; + if (paintRegion.isEmpty()) + return; + +#ifndef Q_WS_MAC + QPainter *oldSharedPainter = inRenderWithPainter ? sharedPainter() : 0; + + // Use the target's shared painter if set (typically set when doing + // "other->render(widget);" in the widget's paintEvent. + if (target->devType() == QInternal::Widget) { + QWidgetPrivate *targetPrivate = static_cast<QWidget *>(target)->d_func(); + if (targetPrivate->extra && targetPrivate->extra->inRenderWithPainter) { + QPainter *targetPainter = targetPrivate->sharedPainter(); + if (targetPainter && targetPainter->isActive()) + setSharedPainter(targetPainter); + } + } +#endif + + // Use the target's redirected device if set and adjust offset and paint + // region accordingly. This is typically the case when people call render + // from the paintEvent. + QPoint offset = targetOffset; + offset -= paintRegion.boundingRect().topLeft(); + QPoint redirectionOffset; + QPaintDevice *redirected = 0; + + if (target->devType() == QInternal::Widget) + redirected = static_cast<QWidget *>(target)->d_func()->redirected(&redirectionOffset); + if (!redirected) + redirected = QPainter::redirected(target, &redirectionOffset); + + if (redirected) { + target = redirected; + offset -= redirectionOffset; + } + + if (!inRenderWithPainter) { // Clip handled by shared painter (in qpainter.cpp). + if (QPaintEngine *targetEngine = target->paintEngine()) { + const QRegion targetSystemClip = targetEngine->systemClip(); + if (!targetSystemClip.isEmpty()) + paintRegion &= targetSystemClip.translated(-offset); + } + } + + // Set backingstore flags. + int flags = DrawPaintOnScreen | DrawInvisible; + if (renderFlags & QWidget::DrawWindowBackground) + flags |= DrawAsRoot; + + if (renderFlags & QWidget::DrawChildren) + flags |= DrawRecursive; + else + flags |= DontSubtractOpaqueChildren; + +#ifdef Q_WS_QWS + flags |= DontSetCompositionMode; +#endif + + if (target->devType() == QInternal::Printer) { + QPainter p(target); + render_helper(&p, targetOffset, paintRegion, renderFlags); + return; + } + +#ifndef Q_WS_MAC + // Render via backingstore. + drawWidget(target, paintRegion, offset, flags, sharedPainter()); + + // Restore shared painter. + if (oldSharedPainter) + setSharedPainter(oldSharedPainter); +#else + // Render via backingstore (no shared painter). + drawWidget(target, paintRegion, offset, flags, 0); +#endif +} + void QWidgetPrivate::paintSiblingsRecursive(QPaintDevice *pdev, const QObjectList& siblings, int index, const QRegion &rgn, const QPoint &offset, int flags #ifdef Q_BACKINGSTORE_SUBSURFACES @@ -7596,23 +7613,21 @@ bool QWidgetPrivate::close_helper(CloseMode mode) if (isMain) QApplication::quit(); #endif - // Attempt to close the application only if this widget has the - // WA_QuitOnClose flag set set and has a non-visible parent - quitOnClose = quitOnClose && (parentWidget.isNull() || !parentWidget->isVisible() || parentWidget->testAttribute(Qt::WA_DontShowOnScreen)); + // Attempt to close the application only if this has WA_QuitOnClose set and a non-visible parent + quitOnClose = quitOnClose && (parentWidget.isNull() || !parentWidget->isVisible()); if (quitOnClose) { - // If there is no non-withdrawn primary window left (except - // the ones without QuitOnClose or with WA_DontShowOnScreen), - // we emit the lastWindowClosed signal + /* if there is no non-withdrawn primary window left (except + the ones without QuitOnClose), we emit the lastWindowClosed + signal */ QWidgetList list = QApplication::topLevelWidgets(); bool lastWindowClosed = true; for (int i = 0; i < list.size(); ++i) { QWidget *w = list.at(i); - if ((w->isVisible() && !w->testAttribute(Qt::WA_DontShowOnScreen)) - && !w->parentWidget() && w->testAttribute(Qt::WA_QuitOnClose)) { - lastWindowClosed = false; - break; - } + if (!w->isVisible() || w->parentWidget() || !w->testAttribute(Qt::WA_QuitOnClose)) + continue; + lastWindowClosed = false; + break; } if (lastWindowClosed) QApplicationPrivate::emitLastWindowClosed(); diff --git a/src/gui/kernel/qwidget_mac.mm b/src/gui/kernel/qwidget_mac.mm index f78596e..dcb87fc 100644 --- a/src/gui/kernel/qwidget_mac.mm +++ b/src/gui/kernel/qwidget_mac.mm @@ -1917,13 +1917,15 @@ void QWidgetPrivate::determineWindowClass() wclass = kDocumentWindowClass; else if(popup || (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_5 && type == Qt::SplashScreen)) wclass = kModalWindowClass; - else if(q->testAttribute(Qt::WA_ShowModal) || type == Qt::Dialog) + else if(type == Qt::Dialog) wclass = kMovableModalWindowClass; else if(type == Qt::ToolTip) wclass = kHelpWindowClass; else if(type == Qt::Tool || (QSysInfo::MacintoshVersion < QSysInfo::MV_10_5 && type == Qt::SplashScreen)) wclass = kFloatingWindowClass; + else if(q->testAttribute(Qt::WA_ShowModal)) + wclass = kMovableModalWindowClass; else wclass = kDocumentWindowClass; @@ -2027,8 +2029,6 @@ void QWidgetPrivate::determineWindowClass() for(int i = 0; tmp_wattr && known_attribs[i].name; i++) { if((tmp_wattr & known_attribs[i].tag) == known_attribs[i].tag) { tmp_wattr ^= known_attribs[i].tag; - qDebug("Qt: internal: * %s %s", known_attribs[i].name, - (GetAvailableWindowAttributes(wclass) & known_attribs[i].tag) ? "" : "(*)"); } } if(tmp_wattr) @@ -2223,6 +2223,41 @@ void QWidgetPrivate::finishCreateWindow_sys_Carbon(OSWindowRef windowRef) applyMaxAndMinSizeOnWindow(); } #else // QT_MAC_USE_COCOA + +void QWidgetPrivate::setWindowLevel() +{ + Q_Q(QWidget); + const QWidget * const windowParent = q->window()->parentWidget(); + const QWidget * const primaryWindow = windowParent ? windowParent->window() : 0; + NSInteger winLevel = -1; + + if (q->windowType() == Qt::Popup) { + winLevel = NSPopUpMenuWindowLevel; + // Popup should be in at least the same level as its parent. + if (primaryWindow) { + OSWindowRef parentRef = qt_mac_window_for(primaryWindow); + winLevel = qMax([parentRef level], winLevel); + } + } else if (q->windowType() == Qt::Tool) { + winLevel = NSFloatingWindowLevel; + } else if (q->windowType() == Qt::Dialog) { + // Correct modality level (NSModalPanelWindowLevel) will be + // set by cocoa when creating a modal session later. + winLevel = NSNormalWindowLevel; + } + + // StayOnTop window should appear above Tool windows. + if (data.window_flags & Qt::WindowStaysOnTopHint) + winLevel = NSPopUpMenuWindowLevel; + // Tooltips should appear above StayOnTop windows. + if (q->windowType() == Qt::ToolTip) + winLevel = NSScreenSaverWindowLevel; + // All other types are Normal level. + if (winLevel == -1) + winLevel = NSNormalWindowLevel; + [qt_mac_window_for(q) setLevel:winLevel]; +} + void QWidgetPrivate::finishCreateWindow_sys_Cocoa(void * /*NSWindow * */ voidWindowRef) { Q_Q(QWidget); @@ -2295,6 +2330,10 @@ void QWidgetPrivate::finishCreateWindow_sys_Cocoa(void * /*NSWindow * */ voidWin q->setAttribute(Qt::WA_WState_WindowOpacitySet, false); } + if (qApp->overrideCursor()) + [windowRef disableCursorRects]; + + setWindowLevel(); macUpdateHideOnSuspend(); macUpdateOpaqueSizeGrip(); macUpdateIgnoreMouseEvents(); @@ -2725,6 +2764,35 @@ void QWidgetPrivate::transferChildren() } } +#ifdef QT_MAC_USE_COCOA +void QWidgetPrivate::setSubWindowStacking(bool set) +{ + Q_Q(QWidget); + if (!q->isWindow() || !q->testAttribute(Qt::WA_WState_Created)) + return; + + if (QWidget *parent = q->parentWidget()) { + if (parent->testAttribute(Qt::WA_WState_Created)) { + if (set) + [qt_mac_window_for(parent) addChildWindow:qt_mac_window_for(q) ordered:NSWindowAbove]; + else + [qt_mac_window_for(parent) removeChildWindow:qt_mac_window_for(q)]; + } + } + + QList<QWidget *> widgets = q->findChildren<QWidget *>(); + for (int i=0; i<widgets.size(); ++i) { + QWidget *child = widgets.at(i); + if (child->isWindow() && child->testAttribute(Qt::WA_WState_Created)) { + if (set) + [qt_mac_window_for(q) addChildWindow:qt_mac_window_for(child) ordered:NSWindowAbove]; + else + [qt_mac_window_for(q) removeChildWindow:qt_mac_window_for(child)]; + } + } +} +#endif + void QWidgetPrivate::setParent_sys(QWidget *parent, Qt::WindowFlags f) { Q_Q(QWidget); @@ -2785,13 +2853,14 @@ void QWidgetPrivate::setParent_sys(QWidget *parent, Qt::WindowFlags f) //recreate and setup flags QObjectPrivate::setParent_helper(parent); - QPoint pt = q->pos(); bool explicitlyHidden = q->testAttribute(Qt::WA_WState_Hidden) && q->testAttribute(Qt::WA_WState_ExplicitShowHide); if (wasCreated && !qt_isGenuineQWidget(q)) return; - if ((data.window_flags & Qt::Sheet) && topData && topData->opacity == 242) + if (!q->testAttribute(Qt::WA_WState_WindowOpacitySet)) { q->setWindowOpacity(1.0f); + q->setAttribute(Qt::WA_WState_WindowOpacitySet, false); + } setWinId(0); //do after the above because they may want the id @@ -2879,7 +2948,6 @@ void QWidgetPrivate::setParent_sys(QWidget *parent, Qt::WindowFlags f) current = current->parentWidget(); } } - invalidateBuffer(q->rect()); qt_event_request_window_change(q); } @@ -3185,10 +3253,10 @@ void QWidget::activateWindow() || windowActive) { #ifndef QT_MAC_USE_COCOA ActivateWindow(win, true); + qApp->setActiveWindow(tlw); #else [win makeKeyWindow]; #endif - qApp->setActiveWindow(tlw); } else if(!isMinimized()) { #ifndef QT_MAC_USE_COCOA SelectWindow(win); @@ -3279,38 +3347,20 @@ void QWidgetPrivate::show_sys() return; bool realWindow = isRealWindow(); +#ifndef QT_MAC_USE_COCOA if (realWindow && !q->testAttribute(Qt::WA_Moved)) { + if (qt_mac_is_macsheet(q)) + recreateMacWindow(); q->createWinId(); if (QWidget *p = q->parentWidget()) { p->createWinId(); -#ifndef QT_MAC_USE_COCOA RepositionWindow(qt_mac_window_for(q), qt_mac_window_for(p), kWindowCenterOnParentWindow); -#else - CGRect parentFrame = NSRectToCGRect([qt_mac_window_for(p) frame]); - OSWindowRef windowRef = qt_mac_window_for(q); - NSRect windowFrame = [windowRef frame]; - NSPoint parentCenter = NSMakePoint(CGRectGetMidX(parentFrame), CGRectGetMidY(parentFrame)); - [windowRef setFrameTopLeftPoint:NSMakePoint(parentCenter.x - (windowFrame.size.width / 2), - (parentCenter.y + (windowFrame.size.height / 2)))]; -#endif } else { -#ifndef QT_MAC_USE_COCOA RepositionWindow(qt_mac_window_for(q), 0, kWindowCenterOnMainScreen); -#else - // Ideally we would do a "center" here, but NSWindow's center is more equivalent to - // kWindowAlertPositionOnMainScreen instead of kWindowCenterOnMainScreen. - QRect availGeo = QApplication::desktop()->availableGeometry(q); - // Center the content only. - data.crect.moveCenter(availGeo.center()); - QRect fStrut = frameStrut(); - QRect frameRect(data.crect.x() - fStrut.left(), data.crect.y() - fStrut.top(), - fStrut.left() + fStrut.right() + data.crect.width(), - fStrut.top() + fStrut.bottom() + data.crect.height()); - NSRect cocoaFrameRect = NSMakeRect(frameRect.x(), flipYCoordinate(frameRect.bottom() + 1), frameRect.width(), frameRect.height()); - [qt_mac_window_for(q) setFrame:cocoaFrameRect display:NO]; -#endif } } +#endif + data.fstrut_dirty = true; if (realWindow) { // Delegates can change window state, so record some things earlier. @@ -3341,13 +3391,23 @@ void QWidgetPrivate::show_sys() #else // sync the opacity value back (in case of a fade). [window setAlphaValue:q->windowOpacity()]; - [window makeKeyAndOrderFront:window]; - - // If this window is app modal, we need to start spinning - // a modal session for it. Interrupting - // the event dispatcher will make this happend: - if (data.window_modality == Qt::ApplicationModal) - QEventDispatcherMac::instance()->interrupt(); + setSubWindowStacking(true); + + QWidget *top = 0; + if (QApplicationPrivate::tryModalHelper(q, &top)) { + [window makeKeyAndOrderFront:window]; + // If this window is app modal, we need to start spinning + // a modal session for it. Interrupting + // the event dispatcher will make this happend: + if (data.window_modality == Qt::ApplicationModal) + QEventDispatcherMac::instance()->interrupt(); + } else { + // The window is modally shaddowed, so we need to make + // sure that we don't pop in front of the modal window: + [window orderFront:window]; + if (NSWindow *modalWin = qt_mac_window_for(top)) + [modalWin orderFront:window]; + } #endif if (q->windowType() == Qt::Popup) { if (q->focusWidget()) @@ -3366,8 +3426,6 @@ void QWidgetPrivate::show_sys() } else if (!q->testAttribute(Qt::WA_ShowWithoutActivating)) { #ifndef QT_MAC_USE_COCOA qt_event_request_activate(q); -#else - [qt_mac_window_for(q) makeKeyWindow]; #endif } } else if(topData()->embedded || !q->parentWidget() || q->parentWidget()->isVisible()) { @@ -3410,6 +3468,9 @@ void QWidgetPrivate::hide_sys() QMacCocoaAutoReleasePool pool; if(q->isWindow()) { +#ifdef QT_MAC_USE_COCOA + setSubWindowStacking(false); +#endif OSWindowRef window = qt_mac_window_for(q); if(qt_mac_is_macsheet(q)) { #ifndef QT_MAC_USE_COCOA @@ -3475,12 +3536,15 @@ void QWidgetPrivate::hide_sys() } #endif } - if(q->isActiveWindow() && !(q->windowType() == Qt::Popup)) { +#ifndef QT_MAC_USE_COCOA + // If the window we now hide was the active window, we need + // to find, and activate another window on screen. NB: Cocoa takes care of this + // logic for us (and distinquishes between main windows and key windows) + if (q->isActiveWindow() && !(q->windowType() == Qt::Popup)) { QWidget *w = 0; if(q->parentWidget()) w = q->parentWidget()->window(); if(!w || (!w->isVisible() && !w->isMinimized())) { -#ifndef QT_MAC_USE_COCOA for (WindowPtr wp = GetFrontWindowOfClass(kMovableModalWindowClass, true); wp; wp = GetNextWindowOfClass(wp, kMovableModalWindowClass, true)) { if((w = qt_mac_find_window(wp))) @@ -3500,24 +3564,12 @@ void QWidgetPrivate::hide_sys() break; } } -#else - NSArray *windows = [NSApp windows]; - NSUInteger totalWindows = [windows count]; - for (NSUInteger i = 0; i < totalWindows; ++i) { - OSWindowRef wp = [windows objectAtIndex:i]; - if ((w = qt_mac_find_window(wp))) - break; - } -#endif } if(w && w->isVisible() && !w->isMinimized()) { -#ifndef QT_MAC_USE_COCOA - qt_event_request_activate(w); -#else - [qt_mac_window_for(w) makeKeyWindow]; -#endif + qt_event_request_activate(w); } } +#endif } else { invalidateBuffer(q->rect()); #ifndef QT_MAC_USE_COCOA @@ -4201,6 +4253,22 @@ void QWidgetPrivate::setGeometry_sys(int x, int y, int w, int h, bool isMove) setGeometry_sys_helper(x, y, w, h, isMove); } #else + if (!isMove && !q->testAttribute(Qt::WA_Moved) && !q->isVisible()) { + // INVARIANT: The location of the window has not yet been set. The default will + // instead be to center it on the desktop, or over the parent, if any. Since we now + // resize the window, we need to adjust the top left position to keep the window + // centeralized. And we need to to this now (and before show) in case the positioning + // of other windows (e.g. sub-windows) depend on this position: + if (QWidget *p = q->parentWidget()) { + x = p->geometry().center().x() - (w / 2); + y = p->geometry().center().y() - (h / 2); + } else { + QRect availGeo = QApplication::desktop()->availableGeometry(q); + x = availGeo.center().x() - (w / 2); + y = availGeo.center().y() - (h / 2); + } + } + QSize olds = q->size(); const bool isResize = (olds != QSize(w, h)); NSWindow *window = qt_mac_window_for(q); @@ -4617,9 +4685,12 @@ void QWidgetPrivate::registerDropSite(bool on) #ifndef QT_MAC_USE_COCOA SetControlDragTrackingEnabled(qt_mac_nativeview_for(q), on); #else - NSView *view = qt_mac_nativeview_for(q); - if (on && [view isKindOfClass:[QT_MANGLE_NAMESPACE(QCocoaView) class]]) { - [static_cast<QT_MANGLE_NAMESPACE(QCocoaView) *>(view) registerDragTypes]; + NSWindow *win = qt_mac_window_for(q); + if (on) { + if ([win isKindOfClass:[QT_MANGLE_NAMESPACE(QCocoaWindow) class]]) + [static_cast<QT_MANGLE_NAMESPACE(QCocoaWindow) *>(win) registerDragTypes]; + else if ([win isKindOfClass:[QT_MANGLE_NAMESPACE(QCocoaPanel) class]]) + [static_cast<QT_MANGLE_NAMESPACE(QCocoaPanel) *>(win) registerDragTypes]; } #endif } @@ -4773,7 +4844,7 @@ void QWidgetPrivate::setModal_sys() bool alreadySheet = [windowRef styleMask] & NSDocModalWindowMask; if (windowParent && q->windowModality() == Qt::WindowModal){ - // Window should be window-modal, which implies a sheet. + // INVARIANT: Window should be window-modal (which implies a sheet). if (!alreadySheet) { // NB: the following call will call setModal_sys recursivly: recreateMacWindow(); @@ -4790,47 +4861,19 @@ void QWidgetPrivate::setModal_sys() [static_cast<NSPanel *>(windowRef) setWorksWhenModal:YES]; } } else { - // Window shold not be window-modal, and as such, not a sheet. + // INVARIANT: Window shold _not_ be window-modal (and as such, not a sheet). if (alreadySheet){ // NB: the following call will call setModal_sys recursivly: recreateMacWindow(); windowRef = qt_mac_window_for(q); } - if (q->windowModality() == Qt::ApplicationModal) { - [windowRef setLevel:NSModalPanelWindowLevel]; - } else if (primaryWindow && primaryWindow->windowModality() == Qt::ApplicationModal) { - // INVARIANT: Our window is a dialog that has a dialog parent that is - // application modal, or . This means that q is supposed to be on top of this - // dialog and not be modally shaddowed: - [windowRef setLevel:NSModalPanelWindowLevel]; + if (q->windowModality() == Qt::NonModal + && primaryWindow && primaryWindow->windowModality() == Qt::ApplicationModal) { + // INVARIANT: Our window has a parent that is application modal. + // This means that q is supposed to be on top of this window and + // not be modally shaddowed: if ([windowRef isKindOfClass:[NSPanel class]]) [static_cast<NSPanel *>(windowRef) setWorksWhenModal:YES]; - } else { - // INVARIANT: q should not be modal. - NSInteger winLevel = -1; - if (q->windowType() == Qt::Popup) { - winLevel = NSPopUpMenuWindowLevel; - // Popup should be in at least the same level as its parent. - if (primaryWindow) { - OSWindowRef parentRef = qt_mac_window_for(primaryWindow); - winLevel = qMax([parentRef level], winLevel); - } - } else if (q->windowType() == Qt::Tool) { - winLevel = NSFloatingWindowLevel; - } else if (q->windowType() == Qt::Dialog) { - winLevel = NSModalPanelWindowLevel; - } - - // StayOnTop window should appear above Tool windows. - if (data.window_flags & Qt::WindowStaysOnTopHint) - winLevel = NSPopUpMenuWindowLevel; - // Tooltips should appear above StayOnTop windows. - if (q->windowType() == Qt::ToolTip) - winLevel = NSScreenSaverWindowLevel; - // All other types are Normal level. - if (winLevel == -1) - winLevel = NSNormalWindowLevel; - [windowRef setLevel:winLevel]; } } diff --git a/src/gui/kernel/qwidget_p.h b/src/gui/kernel/qwidget_p.h index 1bbc057..efd9a0a 100644 --- a/src/gui/kernel/qwidget_p.h +++ b/src/gui/kernel/qwidget_p.h @@ -158,6 +158,7 @@ struct QTLWExtra { quint32 newCounterValueLo; #endif #elif defined(Q_WS_WIN) // <--------------------------------------------------------- WIN + uint hotkeyRegistered: 1; // Hot key from the STARTUPINFO has been registered. HICON winIconBig; // internal big Windows icon HICON winIconSmall; // internal small Windows icon #elif defined(Q_WS_MAC) // <--------------------------------------------------------- MAC @@ -385,6 +386,8 @@ public: QRegion prepareToRender(const QRegion ®ion, QWidget::RenderFlags renderFlags); void render_helper(QPainter *painter, const QPoint &targetOffset, const QRegion &sourceRegion, QWidget::RenderFlags renderFlags); + void render(QPaintDevice *target, const QPoint &targetOffset, const QRegion &sourceRegion, + QWidget::RenderFlags renderFlags, bool readyToRender); void drawWidget(QPaintDevice *pdev, const QRegion &rgn, const QPoint &offset, int flags, QPainter *sharedPainter = 0, QWidgetBackingStore *backingStore = 0); @@ -763,6 +766,8 @@ public: void initWindowPtr(); void finishCreateWindow_sys_Carbon(OSWindowRef windowRef); #else + void setSubWindowStacking(bool set); + void setWindowLevel(); void finishCreateWindow_sys_Cocoa(void * /*NSWindow * */ windowRef); void syncCocoaMask(); void finishCocoaMaskSetup(); diff --git a/src/gui/kernel/qwidget_win.cpp b/src/gui/kernel/qwidget_win.cpp index 10522ed..8cab387 100644 --- a/src/gui/kernel/qwidget_win.cpp +++ b/src/gui/kernel/qwidget_win.cpp @@ -1094,6 +1094,21 @@ void QWidgetPrivate::show_sys() 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()) { @@ -1141,6 +1156,11 @@ void QWidgetPrivate::show_sys() 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() || !q->parentWidget()->isActiveWindow())) + q->activateWindow(); } winSetupGestures(); @@ -1687,6 +1707,7 @@ void QWidgetPrivate::deleteSysExtra() void QWidgetPrivate::createTLSysExtra() { + extra->topextra->hotkeyRegistered = 0; extra->topextra->savedFlags = 0; extra->topextra->winIconBig = 0; extra->topextra->winIconSmall = 0; diff --git a/src/gui/mac/qt_menu.nib/classes.nib b/src/gui/mac/qt_menu.nib/classes.nib index fed50a3..0031e0e 100644 --- a/src/gui/mac/qt_menu.nib/classes.nib +++ b/src/gui/mac/qt_menu.nib/classes.nib @@ -5,14 +5,6 @@ <key>IBClasses</key> <array> <dict> - <key>CLASS</key> - <string>FirstResponder</string> - <key>LANGUAGE</key> - <string>ObjC</string> - <key>SUPERCLASS</key> - <string>NSObject</string> - </dict> - <dict> <key>ACTIONS</key> <dict> <key>hide</key> @@ -52,6 +44,14 @@ <key>SUPERCLASS</key> <string>NSResponder</string> </dict> + <dict> + <key>CLASS</key> + <string>FirstResponder</string> + <key>LANGUAGE</key> + <string>ObjC</string> + <key>SUPERCLASS</key> + <string>NSObject</string> + </dict> </array> <key>IBVersion</key> <string>1</string> diff --git a/src/gui/mac/qt_menu.nib/info.nib b/src/gui/mac/qt_menu.nib/info.nib index 768cb8b..02e5cca 100644 --- a/src/gui/mac/qt_menu.nib/info.nib +++ b/src/gui/mac/qt_menu.nib/info.nib @@ -3,7 +3,7 @@ <plist version="1.0"> <dict> <key>IBFramework Version</key> - <string>670</string> + <string>672</string> <key>IBOldestOS</key> <integer>5</integer> <key>IBOpenObjects</key> @@ -11,7 +11,7 @@ <integer>57</integer> </array> <key>IBSystem Version</key> - <string>9G55</string> + <string>9L31a</string> <key>targetFramework</key> <string>IBCocoaFramework</string> </dict> diff --git a/src/gui/mac/qt_menu.nib/keyedobjects.nib b/src/gui/mac/qt_menu.nib/keyedobjects.nib Binary files differindex 18a6648..3edb0ed 100644 --- a/src/gui/mac/qt_menu.nib/keyedobjects.nib +++ b/src/gui/mac/qt_menu.nib/keyedobjects.nib diff --git a/src/gui/math3d/qmatrix4x4.h b/src/gui/math3d/qmatrix4x4.h index f9902d7..0671fa8 100644 --- a/src/gui/math3d/qmatrix4x4.h +++ b/src/gui/math3d/qmatrix4x4.h @@ -208,6 +208,8 @@ private: friend class QGraphicsRotation; }; +Q_DECLARE_TYPEINFO(QMatrix4x4, Q_MOVABLE_TYPE); + inline QMatrix4x4::QMatrix4x4 (qreal m11, qreal m12, qreal m13, qreal m14, qreal m21, qreal m22, qreal m23, qreal m24, diff --git a/src/gui/math3d/qquaternion.h b/src/gui/math3d/qquaternion.h index a446f28..16aa5d0 100644 --- a/src/gui/math3d/qquaternion.h +++ b/src/gui/math3d/qquaternion.h @@ -136,6 +136,8 @@ private: qreal wp, xp, yp, zp; }; +Q_DECLARE_TYPEINFO(QQuaternion, Q_MOVABLE_TYPE); + inline QQuaternion::QQuaternion() : wp(1.0f), xp(0.0f), yp(0.0f), zp(0.0f) {} inline QQuaternion::QQuaternion(qreal aScalar, qreal xpos, qreal ypos, qreal zpos) : wp(aScalar), xp(xpos), yp(ypos), zp(zpos) {} diff --git a/src/gui/math3d/qvector2d.h b/src/gui/math3d/qvector2d.h index d76f35a..c92c5e0 100644 --- a/src/gui/math3d/qvector2d.h +++ b/src/gui/math3d/qvector2d.h @@ -126,6 +126,8 @@ private: friend class QVector4D; }; +Q_DECLARE_TYPEINFO(QVector2D, Q_MOVABLE_TYPE); + inline QVector2D::QVector2D() : xp(0.0f), yp(0.0f) {} inline QVector2D::QVector2D(float xpos, float ypos, int) : xp(xpos), yp(ypos) {} diff --git a/src/gui/math3d/qvector3d.h b/src/gui/math3d/qvector3d.h index 80c7152..2fdd1d3 100644 --- a/src/gui/math3d/qvector3d.h +++ b/src/gui/math3d/qvector3d.h @@ -141,6 +141,8 @@ private: #endif }; +Q_DECLARE_TYPEINFO(QVector3D, Q_MOVABLE_TYPE); + inline QVector3D::QVector3D() : xp(0.0f), yp(0.0f), zp(0.0f) {} inline QVector3D::QVector3D(qreal xpos, qreal ypos, qreal zpos) : xp(xpos), yp(ypos), zp(zpos) {} diff --git a/src/gui/math3d/qvector4d.h b/src/gui/math3d/qvector4d.h index 4af2961..a383fbb 100644 --- a/src/gui/math3d/qvector4d.h +++ b/src/gui/math3d/qvector4d.h @@ -138,6 +138,8 @@ private: #endif }; +Q_DECLARE_TYPEINFO(QVector4D, Q_MOVABLE_TYPE); + inline QVector4D::QVector4D() : xp(0.0f), yp(0.0f), zp(0.0f), wp(0.0f) {} inline QVector4D::QVector4D(qreal xpos, qreal ypos, qreal zpos, qreal wpos) : xp(xpos), yp(ypos), zp(zpos), wp(wpos) {} diff --git a/src/gui/painting/qbezier.cpp b/src/gui/painting/qbezier.cpp index bbffda1..ea7fe4f 100644 --- a/src/gui/painting/qbezier.cpp +++ b/src/gui/painting/qbezier.cpp @@ -112,6 +112,11 @@ QPolygonF QBezier::toPolygon() const return polygon; } +QBezier QBezier::mapBy(const QTransform &transform) const +{ + return QBezier::fromPoints(transform.map(pt1()), transform.map(pt2()), transform.map(pt3()), transform.map(pt4())); +} + //0.5 is really low static const qreal flatness = 0.5; @@ -140,6 +145,25 @@ static inline void flattenBezierWithoutInflections(QBezier &bez, } } +QBezier QBezier::getSubRange(qreal t0, qreal t1) const +{ + QBezier result; + QBezier temp; + + // cut at t1 + if (qFuzzyIsNull(t1 - qreal(1.))) { + result = *this; + } else { + temp = *this; + temp.parameterSplitLeft(t1, &result); + } + + // cut at t0 + if (!qFuzzyIsNull(t0)) + result.parameterSplitLeft(t0 / t1, &temp); + + return result; +} static inline int quadraticRoots(qreal a, qreal b, qreal c, qreal *x1, qreal *x2) @@ -1018,13 +1042,19 @@ int QBezier::stationaryYPoints(qreal &t0, qreal &t1) const const qreal b = 2 * y1 - 4 * y2 + 2 * y3; const qreal c = -y1 + y2; - qreal reciprocal = b * b - 4 * a * c; + if (qFuzzyIsNull(a)) { + if (qFuzzyIsNull(b)) + return 0; - QList<qreal> result; + t0 = -c / b; + return t0 > 0 && t0 < 1; + } + + qreal reciprocal = b * b - 4 * a * c; if (qFuzzyIsNull(reciprocal)) { t0 = -b / (2 * a); - return 1; + return t0 > 0 && t0 < 1; } else if (reciprocal > 0) { qreal temp = qSqrt(reciprocal); diff --git a/src/gui/painting/qbezier_p.h b/src/gui/painting/qbezier_p.h index 3409bc7..f015ea8 100644 --- a/src/gui/painting/qbezier_p.h +++ b/src/gui/painting/qbezier_p.h @@ -59,6 +59,7 @@ #include "QtCore/qvector.h" #include "QtCore/qlist.h" #include "QtCore/qpair.h" +#include "QtGui/qtransform.h" QT_BEGIN_NAMESPACE @@ -96,6 +97,8 @@ public: QPointF pt3() const { return QPointF(x3, y3); } QPointF pt4() const { return QPointF(x4, y4); } + QBezier mapBy(const QTransform &transform) const; + inline QPointF midPoint() const; inline QLineF midTangent() const; @@ -104,6 +107,7 @@ public: inline void parameterSplitLeft(qreal t, QBezier *left); inline void split(QBezier *firstHalf, QBezier *secondHalf) const; + int shifted(QBezier *curveSegments, int maxSegmets, qreal offset, float threshold) const; @@ -117,6 +121,8 @@ public: static bool findIntersections(const QBezier &a, const QBezier &b, QVector<QPair<qreal, qreal> > *t); + QBezier getSubRange(qreal t0, qreal t1) const; + qreal x1, y1, x2, y2, x3, y3, x4, y4; }; diff --git a/src/gui/painting/qbrush.cpp b/src/gui/painting/qbrush.cpp index 1a83b1d..a82d0f9 100644 --- a/src/gui/painting/qbrush.cpp +++ b/src/gui/painting/qbrush.cpp @@ -912,7 +912,7 @@ void QBrush::setTransform(const QTransform &matrix) otherwise returns false. Two brushes are different if they have different styles, colors or - pixmaps. + transforms or different pixmaps or gradients depending on the style. \sa operator==() */ @@ -924,7 +924,7 @@ void QBrush::setTransform(const QTransform &matrix) otherwise returns false. Two brushes are equal if they have equal styles, colors and - pixmaps. + transforms and equal pixmaps or gradients depending on the style. \sa operator!=() */ @@ -933,26 +933,26 @@ bool QBrush::operator==(const QBrush &b) const { if (b.d == d) return true; - if (b.d->style == d->style && b.d->color == d->color) { - switch (d->style) { - case Qt::TexturePattern: { - QPixmap &us = (static_cast<QTexturedBrushData *>(d.data()))->pixmap(); - QPixmap &them = (static_cast<QTexturedBrushData *>(b.d.data()))->pixmap(); + if (b.d->style != d->style || b.d->color != d->color || b.d->transform != d->transform) + return false; + switch (d->style) { + case Qt::TexturePattern: + { + const QPixmap &us = (static_cast<QTexturedBrushData *>(d.data()))->pixmap(); + const QPixmap &them = (static_cast<QTexturedBrushData *>(b.d.data()))->pixmap(); return ((us.isNull() && them.isNull()) || us.cacheKey() == them.cacheKey()); } - case Qt::LinearGradientPattern: - case Qt::RadialGradientPattern: - case Qt::ConicalGradientPattern: - { - QGradientBrushData *d1 = static_cast<QGradientBrushData *>(d.data()); - QGradientBrushData *d2 = static_cast<QGradientBrushData *>(b.d.data()); - return d1->gradient == d2->gradient; - } - default: - return true; + case Qt::LinearGradientPattern: + case Qt::RadialGradientPattern: + case Qt::ConicalGradientPattern: + { + const QGradientBrushData *d1 = static_cast<QGradientBrushData *>(d.data()); + const QGradientBrushData *d2 = static_cast<QGradientBrushData *>(b.d.data()); + return d1->gradient == d2->gradient; } + default: + return true; } - return false; } /*! diff --git a/src/gui/painting/qdatabuffer_p.h b/src/gui/painting/qdatabuffer_p.h index a7834ea..bc5f1ef 100644 --- a/src/gui/painting/qdatabuffer_p.h +++ b/src/gui/painting/qdatabuffer_p.h @@ -81,7 +81,9 @@ public: inline Type &at(int i) { Q_ASSERT(i >= 0 && i < siz); return buffer[i]; } inline const Type &at(int i) const { Q_ASSERT(i >= 0 && i < siz); return buffer[i]; } + inline Type &last() { Q_ASSERT(!isEmpty()); return buffer[siz-1]; } inline const Type &last() const { Q_ASSERT(!isEmpty()); return buffer[siz-1]; } + inline Type &first() { Q_ASSERT(!isEmpty()); return buffer[0]; } inline const Type &first() const { Q_ASSERT(!isEmpty()); return buffer[0]; } inline void add(const Type &t) { @@ -90,6 +92,11 @@ public: ++siz; } + inline void pop_back() { + Q_ASSERT(siz > 0); + --siz; + } + inline void resize(int size) { reserve(size); siz = size; diff --git a/src/gui/painting/qdrawhelper.cpp b/src/gui/painting/qdrawhelper.cpp index 070491d..891f4c2 100644 --- a/src/gui/painting/qdrawhelper.cpp +++ b/src/gui/painting/qdrawhelper.cpp @@ -46,6 +46,7 @@ #include <private/qdrawhelper_armv6_p.h> #include <private/qdrawhelper_neon_p.h> #include <private/qmath_p.h> +#include <private/qsimd_p.h> #include <qmath.h> QT_BEGIN_NAMESPACE @@ -3700,7 +3701,7 @@ template <> Q_STATIC_TEMPLATE_SPECIALIZATION inline quint32 alpha_4(const qargb8555 *src) { - Q_ASSERT((long(src) & 0x3) == 0); + Q_ASSERT((quintptr(src) & 0x3) == 0); const quint8 *src8 = reinterpret_cast<const quint8*>(src); return src8[0] << 24 | src8[3] << 16 | src8[6] << 8 | src8[9]; } @@ -4026,8 +4027,8 @@ template <> inline void interpolate_pixel_4(qargb8565 *dest, const qargb8565 *src, quint32 alpha) { - Q_ASSERT((long(dest) & 0x3) == 0); - Q_ASSERT((long(src) & 0x3) == 0); + Q_ASSERT((quintptr(dest) & 0x3) == 0); + Q_ASSERT((quintptr(src) & 0x3) == 0); const quint32 a = eff_alpha_4(alpha, dest); const quint32 ia = eff_ialpha_4(alpha, dest); @@ -4122,8 +4123,8 @@ template <> inline void interpolate_pixel_4(qargb8555 *dest, const qargb8555 *src, quint32 alpha) { - Q_ASSERT((long(dest) & 0x3) == 0); - Q_ASSERT((long(src) & 0x3) == 0); + Q_ASSERT((quintptr(dest) & 0x3) == 0); + Q_ASSERT((quintptr(src) & 0x3) == 0); const quint32 a = eff_alpha_4(alpha, dest); @@ -4218,8 +4219,8 @@ template <> inline void interpolate_pixel_4(qrgb888 *dest, const qrgb888 *src, quint32 alpha) { - Q_ASSERT((long(dest) & 0x3) == 0); - Q_ASSERT((long(src) & 0x3) == 0); + Q_ASSERT((quintptr(dest) & 0x3) == 0); + Q_ASSERT((quintptr(src) & 0x3) == 0); const quint32 a = eff_alpha_4(alpha, dest); const quint32 ia = eff_ialpha_4(alpha, dest); @@ -4291,8 +4292,8 @@ template <class DST, class SRC> inline void interpolate_pixel_4(DST *dest, quint8 a, const SRC *src, quint8 b) { - Q_ASSERT((long(dest) & 0x3) == 0); - Q_ASSERT((long(src) & 0x3) == 0); + Q_ASSERT((quintptr(dest) & 0x3) == 0); + Q_ASSERT((quintptr(src) & 0x3) == 0); dest[0] = dest[0].byte_mul(a) + DST(src[0]).byte_mul(b); dest[1] = dest[1].byte_mul(a) + DST(src[1]).byte_mul(b); @@ -4303,8 +4304,8 @@ inline void interpolate_pixel_4(DST *dest, quint8 a, template <class DST, class SRC> inline void blend_sourceOver_4(DST *dest, const SRC *src) { - Q_ASSERT((long(dest) & 0x3) == 0); - Q_ASSERT((long(src) & 0x3) == 0); + Q_ASSERT((quintptr(dest) & 0x3) == 0); + Q_ASSERT((quintptr(src) & 0x3) == 0); const quint32 a = alpha_4(src); if (a == 0xffffffff) { @@ -4319,8 +4320,8 @@ inline void blend_sourceOver_4(DST *dest, const SRC *src) template <> inline void blend_sourceOver_4(qargb8565 *dest, const qargb8565 *src) { - Q_ASSERT((long(dest) & 0x3) == 0); - Q_ASSERT((long(src) & 0x3) == 0); + Q_ASSERT((quintptr(dest) & 0x3) == 0); + Q_ASSERT((quintptr(src) & 0x3) == 0); const quint32 a = alpha_4(src); if (a == 0xffffffff) { @@ -4333,8 +4334,8 @@ inline void blend_sourceOver_4(qargb8565 *dest, const qargb8565 *src) template <> inline void blend_sourceOver_4(qargb8555 *dest, const qargb8555 *src) { - Q_ASSERT((long(dest) & 0x3) == 0); - Q_ASSERT((long(src) & 0x3) == 0); + Q_ASSERT((quintptr(dest) & 0x3) == 0); + Q_ASSERT((quintptr(src) & 0x3) == 0); const quint32 a = alpha_4(src); if (a == 0xffffffff) { @@ -4347,8 +4348,8 @@ inline void blend_sourceOver_4(qargb8555 *dest, const qargb8555 *src) template <> inline void blend_sourceOver_4(qargb6666 *dest, const qargb6666 *src) { - Q_ASSERT((long(dest) & 0x3) == 0); - Q_ASSERT((long(src) & 0x3) == 0); + Q_ASSERT((quintptr(dest) & 0x3) == 0); + Q_ASSERT((quintptr(src) & 0x3) == 0); const quint32 a = alpha_4(src); if (a == 0xffffffff) { @@ -7720,199 +7721,6 @@ static void qt_memfill16_setup(quint16 *dest, quint16 value, int count); qt_memfill32_func qt_memfill32 = qt_memfill32_setup; qt_memfill16_func qt_memfill16 = qt_memfill16_setup; -enum CPUFeatures { - None = 0, - MMX = 0x1, - MMXEXT = 0x2, - MMX3DNOW = 0x4, - MMX3DNOWEXT = 0x8, - SSE = 0x10, - SSE2 = 0x20, - CMOV = 0x40, - IWMMXT = 0x80, - NEON = 0x100 -}; - -static uint detectCPUFeatures() -{ -#if defined (Q_OS_WINCE) -#if defined (ARM) - if (IsProcessorFeaturePresent(PF_ARM_INTEL_WMMX)) - return IWMMXT; -#elif defined(_X86_) - uint features = 0; -#if defined QT_HAVE_MMX - if (IsProcessorFeaturePresent(PF_MMX_INSTRUCTIONS_AVAILABLE)) - features |= MMX; -#endif -#if defined QT_HAVE_3DNOW - if (IsProcessorFeaturePresent(PF_3DNOW_INSTRUCTIONS_AVAILABLE)) - features |= MMX3DNOW; -#endif - return features; -#endif - return 0; -#elif defined(QT_HAVE_IWMMXT) - // runtime detection only available when running as a previlegied process - static const bool doIWMMXT = !qgetenv("QT_NO_IWMMXT").toInt(); - return doIWMMXT ? IWMMXT : 0; -#elif defined(QT_HAVE_NEON) - static const bool doNEON = !qgetenv("QT_NO_NEON").toInt(); - return doNEON ? NEON : 0; -#else - uint features = 0; -#if defined(__x86_64__) || defined(Q_OS_WIN64) - features = MMX|SSE|SSE2|CMOV; -#elif defined(__ia64__) - features = MMX|SSE|SSE2; -#elif defined(__i386__) || defined(_M_IX86) - unsigned int extended_result = 0; - uint result = 0; - /* see p. 118 of amd64 instruction set manual Vol3 */ -#if defined(Q_CC_GNU) - asm ("push %%ebx\n" - "pushf\n" - "pop %%eax\n" - "mov %%eax, %%ebx\n" - "xor $0x00200000, %%eax\n" - "push %%eax\n" - "popf\n" - "pushf\n" - "pop %%eax\n" - "xor %%edx, %%edx\n" - "xor %%ebx, %%eax\n" - "jz 1f\n" - - "mov $0x00000001, %%eax\n" - "cpuid\n" - "1:\n" - "pop %%ebx\n" - "mov %%edx, %0\n" - : "=r" (result) - : - : "%eax", "%ecx", "%edx" - ); - - asm ("push %%ebx\n" - "pushf\n" - "pop %%eax\n" - "mov %%eax, %%ebx\n" - "xor $0x00200000, %%eax\n" - "push %%eax\n" - "popf\n" - "pushf\n" - "pop %%eax\n" - "xor %%edx, %%edx\n" - "xor %%ebx, %%eax\n" - "jz 2f\n" - - "mov $0x80000000, %%eax\n" - "cpuid\n" - "cmp $0x80000000, %%eax\n" - "jbe 2f\n" - "mov $0x80000001, %%eax\n" - "cpuid\n" - "2:\n" - "pop %%ebx\n" - "mov %%edx, %0\n" - : "=r" (extended_result) - : - : "%eax", "%ecx", "%edx" - ); -#elif defined (Q_OS_WIN) - _asm { - push eax - push ebx - push ecx - push edx - pushfd - pop eax - mov ebx, eax - xor eax, 00200000h - push eax - popfd - pushfd - pop eax - mov edx, 0 - xor eax, ebx - jz skip - - mov eax, 1 - cpuid - mov result, edx - skip: - pop edx - pop ecx - pop ebx - pop eax - } - - _asm { - push eax - push ebx - push ecx - push edx - pushfd - pop eax - mov ebx, eax - xor eax, 00200000h - push eax - popfd - pushfd - pop eax - mov edx, 0 - xor eax, ebx - jz skip2 - - mov eax, 80000000h - cpuid - cmp eax, 80000000h - jbe skip2 - mov eax, 80000001h - cpuid - mov extended_result, edx - skip2: - pop edx - pop ecx - pop ebx - pop eax - } -#endif - - // result now contains the standard feature bits - if (result & (1u << 15)) - features |= CMOV; - if (result & (1u << 23)) - features |= MMX; - if (extended_result & (1u << 22)) - features |= MMXEXT; - if (extended_result & (1u << 31)) - features |= MMX3DNOW; - if (extended_result & (1u << 30)) - features |= MMX3DNOWEXT; - if (result & (1u << 25)) - features |= SSE; - if (result & (1u << 26)) - features |= SSE2; -#endif // i386 - - if (qgetenv("QT_NO_MMX").toInt()) - features ^= MMX; - if (qgetenv("QT_NO_MMXEXT").toInt()) - features ^= MMXEXT; - if (qgetenv("QT_NO_3DNOW").toInt()) - features ^= MMX3DNOW; - if (qgetenv("QT_NO_3DNOWEXT").toInt()) - features ^= MMX3DNOWEXT; - if (qgetenv("QT_NO_SSE").toInt()) - features ^= SSE; - if (qgetenv("QT_NO_SSE2").toInt()) - features ^= SSE2; - - return features; -#endif -} - #if defined(Q_CC_RVCT) && defined(QT_HAVE_ARMV6) // Move these to qdrawhelper_arm.c when all // functions are implemented using arm assembly. @@ -8005,10 +7813,7 @@ static void qt_blend_color_argb_armv6(int count, const QSpan *spans, void *userD void qInitDrawhelperAsm() { - static uint features = 0xffffffff; - if (features != 0xffffffff) - return; - features = detectCPUFeatures(); + const uint features = qDetectCPUFeatures(); qt_memfill32 = qt_memfill_template<quint32, quint32>; qt_memfill16 = qt_memfill_quint16; //qt_memfill_template<quint16, quint16>; diff --git a/src/gui/painting/qdrawhelper_p.h b/src/gui/painting/qdrawhelper_p.h index cb0db4f..f5b17ea 100644 --- a/src/gui/painting/qdrawhelper_p.h +++ b/src/gui/painting/qdrawhelper_p.h @@ -67,15 +67,6 @@ #include "QtGui/qscreen_qws.h" #endif -// Disable MMX and SSE on Mac/PPC builds, or if the compiler -// does not support -Xarch argument passing -#if defined(QT_NO_MAC_XARCH) || (defined(Q_OS_DARWIN) && (defined(__ppc__) || defined(__ppc64__))) -#undef QT_HAVE_SSE2 -#undef QT_HAVE_SSE -#undef QT_HAVE_3DNOW -#undef QT_HAVE_MMX -#endif - QT_BEGIN_NAMESPACE #if defined(Q_CC_MSVC) && _MSCVER <= 1300 && !defined(Q_CC_INTEL) @@ -1649,7 +1640,7 @@ inline void qt_memconvert(qrgb666 *dest, const quint32 *src, int count) return; } - const int align = (long(dest) & 3); + const int align = (quintptr(dest) & 3); switch (align) { case 1: *dest++ = qrgb666(*src++); --count; case 2: *dest++ = qrgb666(*src++); --count; diff --git a/src/gui/painting/qdrawutil.cpp b/src/gui/painting/qdrawutil.cpp index 5619a2e..d76c709 100644 --- a/src/gui/painting/qdrawutil.cpp +++ b/src/gui/painting/qdrawutil.cpp @@ -1081,7 +1081,7 @@ void qDrawItem(QPainter *p, Qt::GUIStyle gs, according to the \a margins structure. */ -typedef QVarLengthArray<QDrawPixmaps::Data, 16> QDrawPixmapsDataArray; +typedef QVarLengthArray<QPainter::Fragment, 16> QPixmapFragmentsArray; /*! \since 4.6 @@ -1102,12 +1102,12 @@ void qDrawBorderPixmap(QPainter *painter, const QRect &targetRect, const QMargin const QPixmap &pixmap, const QRect &sourceRect,const QMargins &sourceMargins, const QTileRules &rules, QDrawBorderPixmap::DrawingHints hints) { - QDrawPixmaps::Data d; + QPainter::Fragment d; d.opacity = 1.0; d.rotation = 0.0; - QDrawPixmapsDataArray opaqueData; - QDrawPixmapsDataArray translucentData; + QPixmapFragmentsArray opaqueData; + QPixmapFragmentsArray translucentData; // source center const int sourceCenterTop = sourceRect.top() + sourceMargins.top(); @@ -1182,44 +1182,56 @@ void qDrawBorderPixmap(QPainter *painter, const QRect &targetRect, const QMargin // corners if (targetMargins.top() > 0 && targetMargins.left() > 0 && sourceMargins.top() > 0 && sourceMargins.left() > 0) { // top left - d.point.setX(0.5 * (xTarget[1] + xTarget[0])); - d.point.setY(0.5 * (yTarget[1] + yTarget[0])); - d.source = QRectF(sourceRect.left(), sourceRect.top(), sourceMargins.left(), sourceMargins.top()); - d.scaleX = qreal(xTarget[1] - xTarget[0]) / d.source.width(); - d.scaleY = qreal(yTarget[1] - yTarget[0]) / d.source.height(); + d.x = (0.5 * (xTarget[1] + xTarget[0])); + d.y = (0.5 * (yTarget[1] + yTarget[0])); + d.sourceLeft = sourceRect.left(); + d.sourceTop = sourceRect.top(); + d.width = sourceMargins.left(); + d.height = sourceMargins.top(); + d.scaleX = qreal(xTarget[1] - xTarget[0]) / d.width; + d.scaleY = qreal(yTarget[1] - yTarget[0]) / d.height; if (hints & QDrawBorderPixmap::OpaqueTopLeft) opaqueData.append(d); else translucentData.append(d); } if (targetMargins.top() > 0 && targetMargins.right() > 0 && sourceMargins.top() > 0 && sourceMargins.right() > 0) { // top right - d.point.setX(0.5 * (xTarget[columns] + xTarget[columns - 1])); - d.point.setY(0.5 * (yTarget[1] + yTarget[0])); - d.source = QRectF(sourceCenterRight, sourceRect.top(), sourceMargins.right(), sourceMargins.top()); - d.scaleX = qreal(xTarget[columns] - xTarget[columns - 1]) / d.source.width(); - d.scaleY = qreal(yTarget[1] - yTarget[0]) / d.source.height(); + d.x = (0.5 * (xTarget[columns] + xTarget[columns - 1])); + d.y = (0.5 * (yTarget[1] + yTarget[0])); + d.sourceLeft = sourceCenterRight; + d.sourceTop = sourceRect.top(); + d.width = sourceMargins.right(); + d.height = sourceMargins.top(); + d.scaleX = qreal(xTarget[columns] - xTarget[columns - 1]) / d.width; + d.scaleY = qreal(yTarget[1] - yTarget[0]) / d.height; if (hints & QDrawBorderPixmap::OpaqueTopRight) opaqueData.append(d); else translucentData.append(d); } if (targetMargins.bottom() > 0 && targetMargins.left() > 0 && sourceMargins.bottom() > 0 && sourceMargins.left() > 0) { // bottom left - d.point.setX(0.5 * (xTarget[1] + xTarget[0])); - d.point.setY(0.5 * (yTarget[rows] + yTarget[rows - 1])); - d.source = QRectF(sourceRect.left(), sourceCenterBottom, sourceMargins.left(), sourceMargins.bottom()); - d.scaleX = qreal(xTarget[1] - xTarget[0]) / d.source.width(); - d.scaleY = qreal(yTarget[rows] - yTarget[rows - 1]) / d.source.height(); + d.x = (0.5 * (xTarget[1] + xTarget[0])); + d.y =(0.5 * (yTarget[rows] + yTarget[rows - 1])); + d.sourceLeft = sourceRect.left(); + d.sourceTop = sourceCenterBottom; + d.width = sourceMargins.left(); + d.height = sourceMargins.bottom(); + d.scaleX = qreal(xTarget[1] - xTarget[0]) / d.width; + d.scaleY = qreal(yTarget[rows] - yTarget[rows - 1]) / d.height; if (hints & QDrawBorderPixmap::OpaqueBottomLeft) opaqueData.append(d); else translucentData.append(d); } if (targetMargins.bottom() > 0 && targetMargins.right() > 0 && sourceMargins.bottom() > 0 && sourceMargins.right() > 0) { // bottom right - d.point.setX(0.5 * (xTarget[columns] + xTarget[columns - 1])); - d.point.setY(0.5 * (yTarget[rows] + yTarget[rows - 1])); - d.source = QRectF(sourceCenterRight, sourceCenterBottom, sourceMargins.right(), sourceMargins.bottom()); - d.scaleX = qreal(xTarget[columns] - xTarget[columns - 1]) / d.source.width(); - d.scaleY = qreal(yTarget[rows] - yTarget[rows - 1]) / d.source.height(); + d.x = (0.5 * (xTarget[columns] + xTarget[columns - 1])); + d.y = (0.5 * (yTarget[rows] + yTarget[rows - 1])); + d.sourceLeft = sourceCenterRight; + d.sourceTop = sourceCenterBottom; + d.width = sourceMargins.right(); + d.height = sourceMargins.bottom(); + d.scaleX = qreal(xTarget[columns] - xTarget[columns - 1]) / d.width; + d.scaleY = qreal(yTarget[rows] - yTarget[rows - 1]) / d.height; if (hints & QDrawBorderPixmap::OpaqueBottomRight) opaqueData.append(d); else @@ -1229,151 +1241,107 @@ void qDrawBorderPixmap(QPainter *painter, const QRect &targetRect, const QMargin // horizontal edges if (targetCenterWidth > 0 && sourceCenterWidth > 0) { if (targetMargins.top() > 0 && sourceMargins.top() > 0) { // top - QDrawPixmapsDataArray &data = hints & QDrawBorderPixmap::OpaqueTop ? opaqueData : translucentData; - d.source = QRectF(sourceCenterLeft, sourceRect.top(), sourceCenterWidth, sourceMargins.top()); - d.point.setY(0.5 * (yTarget[1] + yTarget[0])); - d.scaleX = dx / d.source.width(); - d.scaleY = qreal(yTarget[1] - yTarget[0]) / d.source.height(); + QPixmapFragmentsArray &data = hints & QDrawBorderPixmap::OpaqueTop ? opaqueData : translucentData; + d.sourceLeft = sourceCenterLeft; + d.sourceTop = sourceRect.top(); + d.width = sourceCenterWidth; + d.height = sourceMargins.top(); + d.y = (0.5 * (yTarget[1] + yTarget[0])); + d.scaleX = dx / d.width; + d.scaleY = qreal(yTarget[1] - yTarget[0]) / d.height; for (int i = 1; i < columns - 1; ++i) { - d.point.setX(0.5 * (xTarget[i + 1] + xTarget[i])); + d.x = (0.5 * (xTarget[i + 1] + xTarget[i])); data.append(d); } if (rules.horizontal == Qt::RepeatTile) - data[data.size() - 1].source.setWidth((xTarget[columns - 1] - xTarget[columns - 2]) / d.scaleX); + data[data.size() - 1].width = ((xTarget[columns - 1] - xTarget[columns - 2]) / d.scaleX); } if (targetMargins.bottom() > 0 && sourceMargins.bottom() > 0) { // bottom - QDrawPixmapsDataArray &data = hints & QDrawBorderPixmap::OpaqueBottom ? opaqueData : translucentData; - d.source = QRectF(sourceCenterLeft, sourceCenterBottom, sourceCenterWidth, sourceMargins.bottom());; - d.point.setY(0.5 * (yTarget[rows] + yTarget[rows - 1])); - d.scaleX = dx / d.source.width(); - d.scaleY = qreal(yTarget[rows] - yTarget[rows - 1]) / d.source.height(); + QPixmapFragmentsArray &data = hints & QDrawBorderPixmap::OpaqueBottom ? opaqueData : translucentData; + d.sourceLeft = sourceCenterLeft; + d.sourceTop = sourceCenterBottom; + d.width = sourceCenterWidth; + d.height = sourceMargins.bottom(); + d.y = (0.5 * (yTarget[rows] + yTarget[rows - 1])); + d.scaleX = dx / d.width; + d.scaleY = qreal(yTarget[rows] - yTarget[rows - 1]) / d.height; for (int i = 1; i < columns - 1; ++i) { - d.point.setX(0.5 * (xTarget[i + 1] + xTarget[i])); + d.x = (0.5 * (xTarget[i + 1] + xTarget[i])); data.append(d); } if (rules.horizontal == Qt::RepeatTile) - data[data.size() - 1].source.setWidth((xTarget[columns - 1] - xTarget[columns - 2]) / d.scaleX); + data[data.size() - 1].width = ((xTarget[columns - 1] - xTarget[columns - 2]) / d.scaleX); } } // vertical edges if (targetCenterHeight > 0 && sourceCenterHeight > 0) { if (targetMargins.left() > 0 && sourceMargins.left() > 0) { // left - QDrawPixmapsDataArray &data = hints & QDrawBorderPixmap::OpaqueLeft ? opaqueData : translucentData; - d.source = QRectF(sourceRect.left(), sourceCenterTop, sourceMargins.left(), sourceCenterHeight); - d.point.setX(0.5 * (xTarget[1] + xTarget[0])); - d.scaleX = qreal(xTarget[1] - xTarget[0]) / d.source.width(); - d.scaleY = dy / d.source.height(); + QPixmapFragmentsArray &data = hints & QDrawBorderPixmap::OpaqueLeft ? opaqueData : translucentData; + d.sourceLeft = sourceRect.left(); + d.sourceTop = sourceCenterTop; + d.width = sourceMargins.left(); + d.height = sourceCenterHeight; + d.x = (0.5 * (xTarget[1] + xTarget[0])); + d.scaleX = qreal(xTarget[1] - xTarget[0]) / d.width; + d.scaleY = dy / d.height; for (int i = 1; i < rows - 1; ++i) { - d.point.setY(0.5 * (yTarget[i + 1] + yTarget[i])); + d.y = (0.5 * (yTarget[i + 1] + yTarget[i])); data.append(d); } if (rules.vertical == Qt::RepeatTile) - data[data.size() - 1].source.setHeight((yTarget[rows - 1] - yTarget[rows - 2]) / d.scaleY); + data[data.size() - 1].height = ((yTarget[rows - 1] - yTarget[rows - 2]) / d.scaleY); } if (targetMargins.right() > 0 && sourceMargins.right() > 0) { // right - QDrawPixmapsDataArray &data = hints & QDrawBorderPixmap::OpaqueRight ? opaqueData : translucentData; - d.source = QRectF(sourceCenterRight, sourceCenterTop, sourceMargins.right(), sourceCenterHeight); - d.point.setX(0.5 * (xTarget[columns] + xTarget[columns - 1])); - d.scaleX = qreal(xTarget[columns] - xTarget[columns - 1]) / d.source.width(); - d.scaleY = dy / d.source.height(); + QPixmapFragmentsArray &data = hints & QDrawBorderPixmap::OpaqueRight ? opaqueData : translucentData; + d.sourceLeft = sourceCenterRight; + d.sourceTop = sourceCenterTop; + d.width = sourceMargins.right(); + d.height = sourceCenterHeight; + d.x = (0.5 * (xTarget[columns] + xTarget[columns - 1])); + d.scaleX = qreal(xTarget[columns] - xTarget[columns - 1]) / d.width; + d.scaleY = dy / d.height; for (int i = 1; i < rows - 1; ++i) { - d.point.setY(0.5 * (yTarget[i + 1] + yTarget[i])); + d.y = (0.5 * (yTarget[i + 1] + yTarget[i])); data.append(d); } if (rules.vertical == Qt::RepeatTile) - data[data.size() - 1].source.setHeight((yTarget[rows - 1] - yTarget[rows - 2]) / d.scaleY); + data[data.size() - 1].height = ((yTarget[rows - 1] - yTarget[rows - 2]) / d.scaleY); } } // center if (targetCenterWidth > 0 && targetCenterHeight > 0 && sourceCenterWidth > 0 && sourceCenterHeight > 0) { - QDrawPixmapsDataArray &data = hints & QDrawBorderPixmap::OpaqueCenter ? opaqueData : translucentData; - d.source = QRectF(sourceCenterLeft, sourceCenterTop, sourceCenterWidth, sourceCenterHeight); - d.scaleX = dx / d.source.width(); - d.scaleY = dy / d.source.height(); + QPixmapFragmentsArray &data = hints & QDrawBorderPixmap::OpaqueCenter ? opaqueData : translucentData; + d.sourceLeft = sourceCenterLeft; + d.sourceTop = sourceCenterTop; + d.width = sourceCenterWidth; + d.height = sourceCenterHeight; + d.scaleX = dx / d.width; + d.scaleY = dy / d.height; qreal repeatWidth = (xTarget[columns - 1] - xTarget[columns - 2]) / d.scaleX; qreal repeatHeight = (yTarget[rows - 1] - yTarget[rows - 2]) / d.scaleY; for (int j = 1; j < rows - 1; ++j) { - d.point.setY(0.5 * (yTarget[j + 1] + yTarget[j])); + d.y = (0.5 * (yTarget[j + 1] + yTarget[j])); for (int i = 1; i < columns - 1; ++i) { - d.point.setX(0.5 * (xTarget[i + 1] + xTarget[i])); + d.x = (0.5 * (xTarget[i + 1] + xTarget[i])); data.append(d); } if (rules.horizontal == Qt::RepeatTile) - data[data.size() - 1].source.setWidth(repeatWidth); + data[data.size() - 1].width = repeatWidth; } if (rules.vertical == Qt::RepeatTile) { for (int i = 1; i < columns - 1; ++i) - data[data.size() - i].source.setHeight(repeatHeight); + data[data.size() - i].height = repeatHeight; } } if (opaqueData.size()) - qDrawPixmaps(painter, opaqueData.data(), opaqueData.size(), pixmap, QDrawPixmaps::OpaqueHint); + painter->drawPixmapFragments(opaqueData.data(), opaqueData.size(), pixmap, QPainter::OpaqueHint); if (translucentData.size()) - qDrawPixmaps(painter, translucentData.data(), translucentData.size(), pixmap); -} - -/*! - \class QDrawPixmaps::Data - \since 4.6 - \internal - - This structure is used with the qDrawPixmaps() function. - - QPointF point: Specifies the center of the target rectangle. - QRectF source: Specifies the source rectangle in the pixmap passed into the qDrawPixmaps() call. - qreal scaleX: Specifies the horizontal scale of the target rectangle. - qreal scaleY: Specifies the vertical scale of the target rectangle. - qreal rotation: Specifies the rotation of the target rectangle in degrees. - The target rectangle is rotated after scaling. - qreal opacity: Specifies the opacity of the rectangle. -*/ - -/*! - \enum QDrawPixmaps::DrawingHint - \internal -*/ - -/*! - \internal - \since 4.6 - - This function is used to draw \a pixmap, or a sub-rectangle of \a pixmap, at multiple positions - with different scale, rotation and opacity on \a painter. \a drawingData is an array of \a - dataCount elements specifying the parameters used to draw each pixmap instance. - This can be used for example to implement a particle system. -*/ -void qDrawPixmaps(QPainter *painter, const QDrawPixmaps::Data *drawingData, int dataCount, const QPixmap &pixmap, QDrawPixmaps::DrawingHints hints) -{ - QPaintEngine *engine = painter->paintEngine(); - if (!engine) - return; - - if (engine->isExtended()) { - static_cast<QPaintEngineEx *>(engine)->drawPixmaps(drawingData, dataCount, pixmap, hints); - } else { - qreal oldOpacity = painter->opacity(); - QTransform oldTransform = painter->transform(); - - for (int i = 0; i < dataCount; ++i) { - QTransform transform = oldTransform; - transform.translate(drawingData[i].point.x(), drawingData[i].point.y()); - transform.rotate(drawingData[i].rotation); - painter->setOpacity(oldOpacity * drawingData[i].opacity); - painter->setTransform(transform); - - qreal w = drawingData[i].scaleX * drawingData[i].source.width(); - qreal h = drawingData[i].scaleY * drawingData[i].source.height(); - painter->drawPixmap(QRectF(-0.5 * w, -0.5 * h, w, h), pixmap, drawingData[i].source); - } - - painter->setOpacity(oldOpacity); - painter->setTransform(oldTransform); - } + painter->drawPixmapFragments(translucentData.data(), translucentData.size(), pixmap); } QT_END_NAMESPACE diff --git a/src/gui/painting/qdrawutil.h b/src/gui/painting/qdrawutil.h index 2801b2f..31e352f 100644 --- a/src/gui/painting/qdrawutil.h +++ b/src/gui/painting/qdrawutil.h @@ -188,31 +188,6 @@ inline void qDrawBorderPixmap(QPainter *painter, qDrawBorderPixmap(painter, target, margins, pixmap, pixmap.rect(), margins); } -// For internal use only. -namespace QDrawPixmaps -{ - struct Data - { - QPointF point; - QRectF source; - qreal scaleX; - qreal scaleY; - qreal rotation; - qreal opacity; - }; - - enum DrawingHint - { - OpaqueHint = 0x01 - }; - - Q_DECLARE_FLAGS(DrawingHints, DrawingHint) -} - -// This function is private and may change without notice. Do not use outside Qt!!! -Q_GUI_EXPORT void qDrawPixmaps(QPainter *painter, const QDrawPixmaps::Data *drawingData, - int dataCount, const QPixmap &pixmap, QDrawPixmaps::DrawingHints hints = 0); - QT_END_NAMESPACE QT_END_HEADER diff --git a/src/gui/painting/qemulationpaintengine.cpp b/src/gui/painting/qemulationpaintengine.cpp index f2f0c73..0510b10 100644 --- a/src/gui/painting/qemulationpaintengine.cpp +++ b/src/gui/painting/qemulationpaintengine.cpp @@ -172,9 +172,44 @@ void QEmulationPaintEngine::drawTextItem(const QPointF &p, const QTextItem &text QRectF rect(p.x(), p.y() - ti.ascent.toReal(), ti.width.toReal(), (ti.ascent + ti.descent + 1).toReal()); fillBGRect(rect); } + + QPainterState *s = state(); + Qt::BrushStyle style = qbrush_style(s->pen.brush()); + if (style >= Qt::LinearGradientPattern && style <= Qt::ConicalGradientPattern) + { + QPen savedPen = s->pen; + QGradient g = *s->pen.brush().gradient(); + + if (g.coordinateMode() > QGradient::LogicalMode) { + QTransform mat = s->pen.brush().transform(); + if (g.coordinateMode() == QGradient::StretchToDeviceMode) { + mat.scale(real_engine->painter()->device()->width(), real_engine->painter()->device()->height()); + } else if (g.coordinateMode() == QGradient::ObjectBoundingMode) { + const QTextItemInt &ti = static_cast<const QTextItemInt &>(textItem); + QRectF r(p.x(), p.y() - ti.ascent.toReal(), ti.width.toReal(), (ti.ascent + ti.descent + 1).toReal()); + mat.translate(r.x(), r.y()); + mat.scale(r.width(), r.height()); + } + g.setCoordinateMode(QGradient::LogicalMode); + QBrush brush(g); + brush.setTransform(mat); + s->pen.setBrush(brush); + penChanged(); + real_engine->drawTextItem(p, textItem); + s->pen = savedPen; + penChanged(); + return; + } + } + real_engine->drawTextItem(p, textItem); } +void QEmulationPaintEngine::drawStaticTextItem(QStaticTextItem *item) +{ + real_engine->drawStaticTextItem(item); +} + void QEmulationPaintEngine::drawTiledPixmap(const QRectF &r, const QPixmap &pixmap, const QPointF &s) { if (state()->bgMode == Qt::OpaqueMode && pixmap.isQBitmap()) diff --git a/src/gui/painting/qemulationpaintengine_p.h b/src/gui/painting/qemulationpaintengine_p.h index 0ed641b..5835f10 100644 --- a/src/gui/painting/qemulationpaintengine_p.h +++ b/src/gui/painting/qemulationpaintengine_p.h @@ -78,6 +78,7 @@ public: virtual void drawPixmap(const QRectF &r, const QPixmap &pm, const QRectF &sr); virtual void drawTextItem(const QPointF &p, const QTextItem &textItem); + virtual void drawStaticTextItem(QStaticTextItem *item); virtual void drawTiledPixmap(const QRectF &r, const QPixmap &pixmap, const QPointF &s); virtual void drawImage(const QRectF &r, const QImage &pm, const QRectF &sr, Qt::ImageConversionFlags flags); diff --git a/src/gui/painting/qpaintbuffer.cpp b/src/gui/painting/qpaintbuffer.cpp index 2344c04..39b76c8 100644 --- a/src/gui/painting/qpaintbuffer.cpp +++ b/src/gui/painting/qpaintbuffer.cpp @@ -45,6 +45,8 @@ #include <private/qfontengine_p.h> #include <private/qemulationpaintengine_p.h> #include <private/qimage_p.h> +#include <qstatictext.h> +#include <private/qstatictext_p.h> #include <QDebug> @@ -306,6 +308,8 @@ public: Q_Q(QPaintBufferEngine); q->buffer->addCommand(QPaintBufferPrivate::Cmd_SystemStateChanged, QVariant(systemClip)); } + + QTransform last; }; @@ -492,6 +496,32 @@ void QPaintBufferEngine::renderHintsChanged() void QPaintBufferEngine::transformChanged() { + Q_D(QPaintBufferEngine); + const QTransform &transform = state()->matrix; + + QTransform delta; + + bool invertible = false; + if (transform.type() <= QTransform::TxScale && transform.type() == d->last.type()) + delta = transform * d->last.inverted(&invertible); + + d->last = transform; + + if (invertible && delta.type() == QTransform::TxNone) + return; + + if (invertible && delta.type() == QTransform::TxTranslate) { +#ifdef QPAINTBUFFER_DEBUG_DRAW + qDebug() << "QPaintBufferEngine: transformChanged (translate only) " << state()->matrix; +#endif + QPaintBufferCommand *cmd = + buffer->addCommand(QPaintBufferPrivate::Cmd_Translate); + + qreal data[] = { delta.dx(), delta.dy() }; + cmd->extra = buffer->addData((qreal *) data, 2); + return; + } + // ### accumulate, like in QBrush case... if (!buffer->commands.isEmpty() && buffer->commands.last().id == QPaintBufferPrivate::Cmd_SetTransform) { @@ -960,6 +990,18 @@ void QPaintBufferEngine::drawTiledPixmap(const QRectF &r, const QPixmap &pm, con buffer->updateBoundingRect(r); } +void QPaintBufferEngine::drawStaticTextItem(QStaticTextItem *staticTextItem) +{ + QString text = QString(staticTextItem->chars, staticTextItem->numChars); + + QStaticText staticText(text); + staticText.prepare(state()->matrix, staticTextItem->font); + + QVariantList variants; + variants << QVariant(staticTextItem->font) << QVariant::fromValue(staticText); + buffer->addCommand(QPaintBufferPrivate::Cmd_DrawStaticText, QVariant(variants)); +} + void QPaintBufferEngine::drawTextItem(const QPointF &pos, const QTextItem &ti) { #ifdef QPAINTBUFFER_DEBUG_DRAW @@ -999,6 +1041,7 @@ void QPaintBufferEngine::drawTextItem(const QPointF &pos, const QTextItem &ti) void QPaintBufferEngine::setState(QPainterState *s) { + Q_D(QPaintBufferEngine); if (m_begin_detected) { #ifdef QPAINTBUFFER_DEBUG_DRAW qDebug() << "QPaintBufferEngine: setState: begin, ignoring."; @@ -1017,6 +1060,8 @@ void QPaintBufferEngine::setState(QPainterState *s) buffer->addCommand(QPaintBufferPrivate::Cmd_Restore); } + d->last = s->matrix; + QPaintEngineEx::setState(s); } @@ -1138,6 +1183,15 @@ void QPainterReplayer::process(const QPaintBufferCommand &cmd) painter->setTransform(xform * m_world_matrix); break; } + case QPaintBufferPrivate::Cmd_Translate: { + QPointF delta(d->floats.at(cmd.extra), d->floats.at(cmd.extra+1)); +#ifdef QPAINTBUFFER_DEBUG_DRAW + qDebug() << " -> Cmd_Translate, offset: " << cmd.offset << delta; +#endif + painter->translate(delta.x(), delta.y()); + return; + } + case QPaintBufferPrivate::Cmd_SetCompositionMode: { QPainter::CompositionMode mode = (QPainter::CompositionMode) cmd.extra; #ifdef QPAINTBUFFER_DEBUG_DRAW @@ -1425,6 +1479,19 @@ void QPainterReplayer::process(const QPaintBufferCommand &cmd) #endif painter->setClipRegion(region, Qt::ClipOperation(cmd.extra)); break; } + + case QPaintBufferPrivate::Cmd_DrawStaticText: { + + QVariantList variants(d->variants.at(cmd.offset).value<QVariantList>()); + + QFont font(variants.at(0).value<QFont>()); + QStaticText text(variants.at(0).value<QStaticText>()); + + painter->setFont(font); + painter->drawStaticText(QPointF(0, 0), text); + + break; + } case QPaintBufferPrivate::Cmd_DrawText: { QPointF pos(d->floats.at(cmd.extra), d->floats.at(cmd.extra+1)); @@ -1770,8 +1837,28 @@ struct QPaintBufferCacheEntry QVariant::Type type; quint64 cacheKey; }; + +struct QPaintBufferCacheEntryV2 +{ + enum Type { + ImageKey, + PixmapKey + }; + + struct Flags { + uint type : 8; + uint key : 24; + }; + + union { + Flags flags; + uint bits; + }; +}; + QT_END_NAMESPACE Q_DECLARE_METATYPE(QPaintBufferCacheEntry) +Q_DECLARE_METATYPE(QPaintBufferCacheEntryV2) QT_BEGIN_NAMESPACE QDataStream &operator<<(QDataStream &stream, const QPaintBufferCacheEntry &entry) @@ -1784,10 +1871,22 @@ QDataStream &operator>>(QDataStream &stream, QPaintBufferCacheEntry &entry) return stream >> entry.type >> entry.cacheKey; } +QDataStream &operator<<(QDataStream &stream, const QPaintBufferCacheEntryV2 &entry) +{ + return stream << entry.bits; +} + +QDataStream &operator>>(QDataStream &stream, QPaintBufferCacheEntryV2 &entry) +{ + return stream >> entry.bits; +} + static int qRegisterPaintBufferMetaTypes() { qRegisterMetaType<QPaintBufferCacheEntry>(); qRegisterMetaTypeStreamOperators<QPaintBufferCacheEntry>("QPaintBufferCacheEntry"); + qRegisterMetaType<QPaintBufferCacheEntryV2>(); + qRegisterMetaTypeStreamOperators<QPaintBufferCacheEntryV2>("QPaintBufferCacheEntryV2"); return 0; // something } @@ -1796,6 +1895,9 @@ Q_CONSTRUCTOR_FUNCTION(qRegisterPaintBufferMetaTypes) QDataStream &operator<<(QDataStream &stream, const QPaintBuffer &buffer) { + QHash<qint64, uint> pixmapKeys; + QHash<qint64, uint> imageKeys; + QHash<qint64, QPixmap> pixmaps; QHash<qint64, QImage> images; @@ -1804,19 +1906,33 @@ QDataStream &operator<<(QDataStream &stream, const QPaintBuffer &buffer) const QVariant &v = variants.at(i); if (v.type() == QVariant::Image) { const QImage image(v.value<QImage>()); - images[image.cacheKey()] = image; - QPaintBufferCacheEntry entry; - entry.type = QVariant::Image; - entry.cacheKey = image.cacheKey(); + QPaintBufferCacheEntryV2 entry; + entry.flags.type = QPaintBufferCacheEntryV2::ImageKey; + + QHash<qint64, uint>::iterator it = imageKeys.find(image.cacheKey()); + if (it != imageKeys.end()) { + entry.flags.key = *it; + } else { + imageKeys[image.cacheKey()] = entry.flags.key = images.size(); + images[images.size()] = image; + } + variants[i] = QVariant::fromValue(entry); } else if (v.type() == QVariant::Pixmap) { const QPixmap pixmap(v.value<QPixmap>()); - pixmaps[pixmap.cacheKey()] = pixmap; - QPaintBufferCacheEntry entry; - entry.type = QVariant::Pixmap; - entry.cacheKey = pixmap.cacheKey(); + QPaintBufferCacheEntryV2 entry; + entry.flags.type = QPaintBufferCacheEntryV2::PixmapKey; + + QHash<qint64, uint>::iterator it = pixmapKeys.find(pixmap.cacheKey()); + if (it != pixmapKeys.end()) { + entry.flags.key = *it; + } else { + pixmapKeys[pixmap.cacheKey()] = entry.flags.key = pixmaps.size(); + pixmaps[pixmaps.size()] = pixmap; + } + variants[i] = QVariant::fromValue(entry); } } @@ -1858,6 +1974,15 @@ QDataStream &operator>>(QDataStream &stream, QPaintBuffer &buffer) variants[i] = QVariant(images.value(entry.cacheKey)); else variants[i] = QVariant(pixmaps.value(entry.cacheKey)); + } else if (v.canConvert<QPaintBufferCacheEntryV2>()) { + QPaintBufferCacheEntryV2 entry = v.value<QPaintBufferCacheEntryV2>(); + + if (entry.flags.type == QPaintBufferCacheEntryV2::ImageKey) + variants[i] = QVariant(images.value(entry.flags.key)); + else if (entry.flags.type == QPaintBufferCacheEntryV2::PixmapKey) + variants[i] = QVariant(pixmaps.value(entry.flags.key)); + else + qWarning() << "operator<<(QDataStream &stream, QPaintBuffer &buffer): unrecognized cache entry type:" << entry.flags.type; } } diff --git a/src/gui/painting/qpaintbuffer_p.h b/src/gui/painting/qpaintbuffer_p.h index 79d7b35..0fde290 100644 --- a/src/gui/painting/qpaintbuffer_p.h +++ b/src/gui/painting/qpaintbuffer_p.h @@ -183,6 +183,10 @@ public: Cmd_DrawTiledPixmap, Cmd_SystemStateChanged, + Cmd_Translate, + Cmd_DrawStaticText, + + // new commands must be added above this line Cmd_LastCommand }; @@ -394,6 +398,7 @@ public: virtual void drawTiledPixmap(const QRectF &r, const QPixmap &pixmap, const QPointF &s); virtual void drawTextItem(const QPointF &pos, const QTextItem &ti); + virtual void drawStaticTextItem(QStaticTextItem *staticTextItem); virtual void setState(QPainterState *s); virtual uint flags() const {return QPaintEngineEx::DoNotEmulate;} diff --git a/src/gui/painting/qpaintengine_raster.cpp b/src/gui/painting/qpaintengine_raster.cpp index 3c2cc8c..a7c2a0b 100644 --- a/src/gui/painting/qpaintengine_raster.cpp +++ b/src/gui/painting/qpaintengine_raster.cpp @@ -67,6 +67,7 @@ // #include <private/qpolygonclipper_p.h> // #include <private/qrasterizer_p.h> #include <private/qimage_p.h> +#include <private/qstatictext_p.h> #include "qpaintengine_raster_p.h" // #include "qbezier_p.h" @@ -3002,27 +3003,22 @@ void QRasterPaintEngine::alphaPenBlt(const void* src, int bpl, int depth, int rx blend(current, spans, &s->penData); } -void QRasterPaintEngine::drawCachedGlyphs(const QPointF &p, const QTextItemInt &ti) +void QRasterPaintEngine::drawCachedGlyphs(int numGlyphs, const glyph_t *glyphs, + const QFixedPoint *positions, QFontEngine *fontEngine) { Q_D(QRasterPaintEngine); QRasterPaintEngineState *s = state(); - QVarLengthArray<QFixedPoint> positions; - QVarLengthArray<glyph_t> glyphs; - QTransform matrix = s->matrix; - matrix.translate(p.x(), p.y()); - ti.fontEngine->getGlyphPositions(ti.glyphs, matrix, ti.flags, glyphs, positions); - - QFontEngineGlyphCache::Type glyphType = ti.fontEngine->glyphFormat >= 0 ? QFontEngineGlyphCache::Type(ti.fontEngine->glyphFormat) : d->glyphCacheType; + QFontEngineGlyphCache::Type glyphType = fontEngine->glyphFormat >= 0 ? QFontEngineGlyphCache::Type(fontEngine->glyphFormat) : d->glyphCacheType; QImageTextureGlyphCache *cache = - (QImageTextureGlyphCache *) ti.fontEngine->glyphCache(0, glyphType, s->matrix); + static_cast<QImageTextureGlyphCache *>(fontEngine->glyphCache(0, glyphType, s->matrix)); if (!cache) { cache = new QImageTextureGlyphCache(glyphType, s->matrix); - ti.fontEngine->setGlyphCache(0, cache); + fontEngine->setGlyphCache(0, cache); } - cache->populate(ti, glyphs, positions); + cache->populate(fontEngine, numGlyphs, glyphs, positions); const QImage &image = cache->image(); int bpl = image.bytesPerLine(); @@ -3040,7 +3036,7 @@ void QRasterPaintEngine::drawCachedGlyphs(const QPointF &p, const QTextItemInt & const QFixed offs = QFixed::fromReal(aliasedCoordinateDelta); const uchar *bits = image.bits(); - for (int i=0; i<glyphs.size(); ++i) { + for (int i=0; i<numGlyphs; ++i) { const QTextureGlyphCache::Coord &c = cache->coords.value(glyphs[i]); int x = qFloor(positions[i].x + offs) + c.baseLineX - margin; int y = qFloor(positions[i].y + offs) - c.baseLineY - margin; @@ -3218,6 +3214,18 @@ QRasterPaintEnginePrivate::getPenFunc(const QRectF &rect, } /*! + \reimp +*/ +void QRasterPaintEngine::drawStaticTextItem(QStaticTextItem *textItem) +{ + ensurePen(); + ensureState(); + + drawCachedGlyphs(textItem->numGlyphs, textItem->glyphs, textItem->glyphPositions, + textItem->fontEngine); +} + +/*! \reimp */ void QRasterPaintEngine::drawTextItem(const QPointF &p, const QTextItem &textItem) @@ -3265,7 +3273,17 @@ void QRasterPaintEngine::drawTextItem(const QPointF &p, const QTextItem &textIte drawCached = false; #endif if (drawCached) { - drawCachedGlyphs(p, ti); + QRasterPaintEngineState *s = state(); + + QVarLengthArray<QFixedPoint> positions; + QVarLengthArray<glyph_t> glyphs; + + QTransform matrix = s->matrix; + matrix.translate(p.x(), p.y()); + + ti.fontEngine->getGlyphPositions(ti.glyphs, matrix, ti.flags, glyphs, positions); + + drawCachedGlyphs(glyphs.size(), glyphs.constData(), positions.constData(), ti.fontEngine); return; } diff --git a/src/gui/painting/qpaintengine_raster_p.h b/src/gui/painting/qpaintengine_raster_p.h index a1c73cc..55eb82e 100644 --- a/src/gui/painting/qpaintengine_raster_p.h +++ b/src/gui/painting/qpaintengine_raster_p.h @@ -203,6 +203,8 @@ public: void clip(const QRect &rect, Qt::ClipOperation op); void clip(const QRegion ®ion, Qt::ClipOperation op); + void drawStaticTextItem(QStaticTextItem *textItem); + enum ClipType { RectClip, ComplexClip @@ -257,7 +259,8 @@ private: void fillRect(const QRectF &rect, QSpanData *data); void drawBitmap(const QPointF &pos, const QImage &image, QSpanData *fill); - void drawCachedGlyphs(const QPointF &p, const QTextItemInt &ti); + void drawCachedGlyphs(int numGlyphs, const glyph_t *glyphs, const QFixedPoint *positions, + QFontEngine *fontEngine); #if defined(Q_OS_SYMBIAN) && defined(QT_NO_FREETYPE) void drawGlyphsS60(const QPointF &p, const QTextItemInt &ti); diff --git a/src/gui/painting/qpaintengineex.cpp b/src/gui/painting/qpaintengineex.cpp index 4f2fffa..98762f0 100644 --- a/src/gui/painting/qpaintengineex.cpp +++ b/src/gui/painting/qpaintengineex.cpp @@ -893,7 +893,7 @@ void QPaintEngineEx::drawPoints(const QPoint *points, int pointCount) for (int i=0; i<count; ++i) { pts[++oset] = points[i].x(); pts[++oset] = points[i].y(); - pts[++oset] = points[i].x() + 1/63; + pts[++oset] = points[i].x() + 1/63.; pts[++oset] = points[i].y(); } QVectorPath path(pts, count * 2, qpaintengineex_line_types_16, QVectorPath::LinesHint); @@ -970,23 +970,26 @@ void QPaintEngineEx::drawTiledPixmap(const QRectF &r, const QPixmap &pixmap, con fill(path, brush); } -void QPaintEngineEx::drawPixmaps(const QDrawPixmaps::Data *drawingData, int dataCount, const QPixmap &pixmap, QDrawPixmaps::DrawingHints /*hints*/) +void QPaintEngineEx::drawPixmapFragments(const QPainter::Fragment *fragments, int fragmentCount, + const QPixmap &pixmap, QPainter::FragmentHints /*hints*/) { qreal oldOpacity = state()->opacity; QTransform oldTransform = state()->matrix; - for (int i = 0; i < dataCount; ++i) { + for (int i = 0; i < fragmentCount; ++i) { QTransform transform = oldTransform; - transform.translate(drawingData[i].point.x(), drawingData[i].point.y()); - transform.rotate(drawingData[i].rotation); - state()->opacity = oldOpacity * drawingData[i].opacity; + transform.translate(fragments[i].x, fragments[i].y); + transform.rotate(fragments[i].rotation); + state()->opacity = oldOpacity * fragments[i].opacity; state()->matrix = transform; opacityChanged(); transformChanged(); - qreal w = drawingData[i].scaleX * drawingData[i].source.width(); - qreal h = drawingData[i].scaleY * drawingData[i].source.height(); - drawPixmap(QRectF(-0.5 * w, -0.5 * h, w, h), pixmap, drawingData[i].source); + qreal w = fragments[i].scaleX * fragments[i].width; + qreal h = fragments[i].scaleY * fragments[i].height; + QRectF sourceRect(fragments[i].sourceLeft, fragments[i].sourceTop, + fragments[i].width, fragments[i].height); + drawPixmap(QRectF(-0.5 * w, -0.5 * h, w, h), pixmap, sourceRect); } state()->opacity = oldOpacity; diff --git a/src/gui/painting/qpaintengineex_p.h b/src/gui/painting/qpaintengineex_p.h index fccd1dc..2401b94 100644 --- a/src/gui/painting/qpaintengineex_p.h +++ b/src/gui/painting/qpaintengineex_p.h @@ -70,6 +70,7 @@ QT_MODULE(Gui) class QPainterState; class QPaintEngineExPrivate; +class QStaticTextItem; struct StrokeHandler; struct QIntRect { @@ -196,10 +197,12 @@ public: virtual void drawTiledPixmap(const QRectF &r, const QPixmap &pixmap, const QPointF &s); - virtual void drawPixmaps(const QDrawPixmaps::Data *drawingData, int dataCount, const QPixmap &pixmap, QFlags<QDrawPixmaps::DrawingHint> hints); + virtual void drawPixmapFragments(const QPainter::Fragment *fragments, int fragmentCount, const QPixmap &pixmap, QFlags<QPainter::FragmentHint> hints); virtual void updateState(const QPaintEngineState &state); + virtual void drawStaticTextItem(QStaticTextItem *) = 0; + virtual void setState(QPainterState *s); inline QPainterState *state() { return static_cast<QPainterState *>(QPaintEngine::state); } inline const QPainterState *state() const { return static_cast<const QPainterState *>(QPaintEngine::state); } diff --git a/src/gui/painting/qpainter.cpp b/src/gui/painting/qpainter.cpp index 075c457..dc96c17 100644 --- a/src/gui/painting/qpainter.cpp +++ b/src/gui/painting/qpainter.cpp @@ -38,6 +38,7 @@ ** $QT_END_LICENSE$ ** ****************************************************************************/ + // QtCore #include <qdebug.h> #include <qmath.h> @@ -69,6 +70,8 @@ #include <private/qwidget_p.h> #include <private/qpaintengine_raster_p.h> #include <private/qmath_p.h> +#include <qstatictext.h> +#include <private/qstatictext_p.h> QT_BEGIN_NAMESPACE @@ -5697,6 +5700,78 @@ void QPainter::drawImage(const QRectF &targetRect, const QImage &image, const QR d->engine->drawImage(QRectF(x, y, w, h), image, QRectF(sx, sy, sw, sh), flags); } + +void qt_draw_glyphs(QPainter *painter, const quint32 *glyphArray, const QPointF *positionArray, + int glyphCount) +{ + QPainterPrivate *painter_d = QPainterPrivate::get(painter); + painter_d->drawGlyphs(glyphArray, positionArray, glyphCount); +} + +void QPainterPrivate::drawGlyphs(const quint32 *glyphArray, const QPointF *positionArray, + int glyphCount) +{ + updateState(state); + + QFontEngine *fontEngine = state->font.d->engineForScript(QUnicodeTables::Common); + + QVarLengthArray<QFixedPoint, 128> positions; + for (int i=0; i<glyphCount; ++i) { + QFixedPoint fp = QFixedPoint::fromPointF(positionArray[i]); + positions.append(fp); + } + + if (extended != 0) { + QStaticTextItem staticTextItem; + staticTextItem.color = state->pen.color(); + staticTextItem.font = state->font; + staticTextItem.fontEngine = fontEngine; + staticTextItem.numGlyphs = glyphCount; + staticTextItem.glyphs = reinterpret_cast<glyph_t *>(const_cast<glyph_t *>(glyphArray)); + staticTextItem.glyphPositions = positions.data(); + + extended->drawStaticTextItem(&staticTextItem); + } else { + QTextItemInt textItem; + textItem.f = &state->font; + textItem.fontEngine = fontEngine; + + QVarLengthArray<QFixed, 128> advances(glyphCount); + QVarLengthArray<QGlyphJustification, 128> glyphJustifications(glyphCount); + QVarLengthArray<HB_GlyphAttributes, 128> glyphAttributes(glyphCount); + qMemSet(glyphAttributes.data(), 0, glyphAttributes.size() * sizeof(HB_GlyphAttributes)); + qMemSet(advances.data(), 0, advances.size() * sizeof(QFixed)); + qMemSet(glyphJustifications.data(), 0, glyphJustifications.size() * sizeof(QGlyphJustification)); + + textItem.glyphs.numGlyphs = glyphCount; + textItem.glyphs.glyphs = reinterpret_cast<HB_Glyph *>(const_cast<quint32 *>(glyphArray)); + textItem.glyphs.offsets = positions.data(); + textItem.glyphs.advances_x = advances.data(); + textItem.glyphs.advances_y = advances.data(); + textItem.glyphs.justifications = glyphJustifications.data(); + textItem.glyphs.attributes = glyphAttributes.data(); + + engine->drawTextItem(QPointF(0, 0), textItem); + } +} + +/*! + + \fn void QPainter::drawStaticText(const QPoint &position, const QStaticText &staticText) + + \since 4.7 + + \overload +*/ + +/*! + \fn void QPainter::drawStaticText(int x, int y, const QStaticText &staticText) + + \since 4.7 + + \overload +*/ + /*! \fn void QPainter::drawText(const QPointF &position, const QString &text) @@ -5720,6 +5795,124 @@ void QPainter::drawText(const QPointF &p, const QString &str) } /*! + \since 4.7 + + Draws the given \a staticText at the given \a position. + + The text will be drawn using the font and the transformation set on the painter. If the + font and/or transformation set on the painter are different from the ones used to initialize + the layout of the QStaticText, then the layout will have to be recalculated. Use + QStaticText::prepare() to initialize \a staticText with the font and transformation with which + it will later be drawn. + + If \a position is not the same as when \a staticText was initialized, or when it was last drawn, + then there will be a slight overhead when translating the text to its new position. + + \note If the painter's transformation is not affine, then \a staticText will be drawn using regular + calls to drawText(), losing any potential performance improvement. + + \sa QStaticText +*/ +void QPainter::drawStaticText(const QPointF &position, const QStaticText &staticText) +{ + Q_D(QPainter); + if (!d->engine || staticText.text().isEmpty() || pen().style() == Qt::NoPen) + return; + + QStaticTextPrivate *staticText_d = + const_cast<QStaticTextPrivate *>(QStaticTextPrivate::get(&staticText)); + + // If we don't have an extended paint engine, or if the painter is projected, + // we go through standard code path + if (d->extended == 0 || !d->state->matrix.isAffine()) { + staticText_d->paintText(position, this); + return; + } + + // Don't recalculate entire layout because of translation, rather add the dx and dy + // into the position to move each text item the correct distance. + QPointF transformedPosition = position * d->state->matrix; + QTransform matrix = d->state->matrix; + + // The translation has been applied to transformedPosition. Remove translation + // component from matrix. + if (d->state->matrix.isTranslating()) { + qreal m11 = d->state->matrix.m11(); + qreal m12 = d->state->matrix.m12(); + qreal m13 = d->state->matrix.m13(); + qreal m21 = d->state->matrix.m21(); + qreal m22 = d->state->matrix.m22(); + qreal m23 = d->state->matrix.m23(); + qreal m33 = d->state->matrix.m33(); + + d->state->matrix.setMatrix(m11, m12, m13, + m21, m22, m23, + 0.0, 0.0, m33); + } + + // If the transform is not identical to the text transform, + // we have to relayout the text (for other transformations than plain translation) + bool staticTextNeedsReinit = false; + if (staticText_d->matrix != d->state->matrix) { + staticText_d->matrix = d->state->matrix; + staticTextNeedsReinit = true; + } + + bool restoreWhenFinished = false; + if (staticText_d->needsClipRect) { + save(); + setClipRect(QRectF(position, staticText_d->maximumSize)); + + restoreWhenFinished = true; + } + + if (font() != staticText_d->font) { + staticText_d->font = font(); + staticTextNeedsReinit = true; + } + + // Recreate the layout of the static text because the matrix or font has changed + if (staticTextNeedsReinit) + staticText_d->init(); + + if (transformedPosition != staticText_d->position) { // Translate to actual position + QFixed fx = QFixed::fromReal(transformedPosition.x()); + QFixed fy = QFixed::fromReal(transformedPosition.y()); + QFixed oldX = QFixed::fromReal(staticText_d->position.x()); + QFixed oldY = QFixed::fromReal(staticText_d->position.y()); + for (int item=0; item<staticText_d->itemCount;++item) { + QStaticTextItem *textItem = staticText_d->items + item; + for (int i=0; i<textItem->numGlyphs; ++i) { + textItem->glyphPositions[i].x += fx - oldX; + textItem->glyphPositions[i].y += fy - oldY; + } + textItem->userDataNeedsUpdate = true; + } + + staticText_d->position = transformedPosition; + } + + QPen oldPen = d->state->pen; + QColor currentColor = oldPen.color(); + for (int i=0; i<staticText_d->itemCount; ++i) { + QStaticTextItem *item = staticText_d->items + i; + if (currentColor != item->color) { + setPen(item->color); + currentColor = item->color; + } + d->extended->drawStaticTextItem(item); + } + if (currentColor != oldPen.color()) + setPen(oldPen); + + if (restoreWhenFinished) + restore(); + + if (matrix.isTranslating()) + d->state->matrix = matrix; +} + +/*! \internal */ void QPainter::drawText(const QPointF &p, const QString &str, int tf, int justificationPadding) @@ -8709,6 +8902,160 @@ QTransform QPainter::combinedTransform() const return d->state->worldMatrix * d->viewTransform(); } +/*! + \since 4.7 + + This function is used to draw \a pixmap, or a sub-rectangle of \a pixmap, + at multiple positions with different scale, rotation and opacity. \a + fragments is an array of \a fragmentCount elements specifying the + parameters used to draw each pixmap fragment. The \a hints + parameter can be used to pass in drawing hints. + + This function is potentially faster than multiple calls to drawPixmap(), + since the backend can optimize state changes. + + \sa QPainter::Fragment, QPainter::FragmentHint +*/ + +void QPainter::drawPixmapFragments(const Fragment *fragments, int fragmentCount, + const QPixmap &pixmap, FragmentHints hints) +{ + Q_D(QPainter); + + if (!d->engine) + return; + + if (d->engine->isExtended()) { + d->extended->drawPixmapFragments(fragments, fragmentCount, pixmap, hints); + } else { + qreal oldOpacity = opacity(); + QTransform oldTransform = transform(); + + for (int i = 0; i < fragmentCount; ++i) { + QTransform transform = oldTransform; + transform.translate(fragments[i].x, fragments[i].y); + transform.rotate(fragments[i].rotation); + setOpacity(oldOpacity * fragments[i].opacity); + setTransform(transform); + + qreal w = fragments[i].scaleX * fragments[i].width; + qreal h = fragments[i].scaleY * fragments[i].height; + QRectF sourceRect(fragments[i].sourceLeft, fragments[i].sourceTop, + fragments[i].width, fragments[i].height); + drawPixmap(QRectF(-0.5 * w, -0.5 * h, w, h), pixmap, sourceRect); + } + + setOpacity(oldOpacity); + setTransform(oldTransform); + } +} + +/*! + \since 4.7 + \class QPainter::Fragment + + \brief This class is used in conjunction with the + QPainter::drawPixmapFragments() function to specify how a pixmap, or + sub-rect of a pixmap, is drawn. + + The \a sourceLeft, \a sourceTop, \a width and \a height variables are used + as a source rectangle within the pixmap passed into the + QPainter::drawPixmapFragments() function. The variables \a x, \a y, \a + width and \a height are used to calculate the target rectangle that is + drawn. \a x and \a y denotes the center of the target rectangle. The \a + width and \a heigth in the target rectangle is scaled by the \a scaleX and + \a scaleY values. The resulting target rectangle is then rotated \a + rotation degrees around the \a x, \a y center point. + + \sa QPainter::drawPixmapFragments() +*/ + +/*! + \since 4.7 + + This is a convenience function that returns a QPainter::Fragment that is + initialized with the \a pos, \a sourceRect, \a scaleX, \a scaleY, \a + rotation, \a opacity parameters. +*/ + +QPainter::Fragment QPainter::Fragment::create(const QPointF &pos, const QRectF &sourceRect, + qreal scaleX, qreal scaleY, qreal rotation, + qreal opacity) +{ + Fragment fragment = {pos.x(), pos.y(), sourceRect.x(), sourceRect.y(), sourceRect.width(), + sourceRect.height(), scaleX, scaleY, rotation, opacity}; + return fragment; +} + +/*! + \variable QPainter::Fragment::x + \brief the x coordinate of center point in the target rectangle. +*/ + +/*! + \variable QPainter::Fragment::y + \brief the y coordinate of the center point in the target rectangle. +*/ + +/*! + \variable QPainter::Fragment::sourceLeft + \brief the left coordinate of the source rectangle. +*/ + +/*! + \variable QPainter::Fragment::sourceTop + \brief the top coordinate of the source rectangle. +*/ + +/*! + \variable QPainter::Fragment::width + + \brief the width of the source rectangle and is used to calculate the width + of the target rectangle. +*/ + +/*! + \variable QPainter::Fragment::height + + \brief the height of the source rectangle and is used to calculate the + height of the target rectangle. +*/ + +/*! + \variable QPainter::Fragment::scaleX + \brief the horizontal scale of the target rectangle. +*/ + +/*! + \variable QPainter::Fragment::scaleY + \brief the vertical scale of the target rectangle. +*/ + +/*! + \variable QPainter::Fragment::rotation + + \brief the rotation of the target rectangle in degrees. The target + rectangle is rotated after it has been scaled. +*/ + +/*! + \variable QPainter::Fragment::opacity + + \brief the opacity of the target rectangle, where 0.0 is fully transparent + and 1.0 is fully opaque. +*/ + +/*! + \since 4.7 + + \enum QPainter::FragmentHint + + \value OpaqueHint Indicates that the pixmap fragments to be drawn are + opaque. Opaque fragments are potentially faster to draw. + + \sa QPainter::drawPixmapFragments(), QPainter::Fragment +*/ + void qt_draw_helper(QPainterPrivate *p, const QPainterPath &path, QPainterPrivate::DrawOperation operation) { p->draw_helper(path, operation); diff --git a/src/gui/painting/qpainter.h b/src/gui/painting/qpainter.h index ffddcba..bcb0b50 100644 --- a/src/gui/painting/qpainter.h +++ b/src/gui/painting/qpainter.h @@ -78,6 +78,7 @@ class QPolygon; class QTextItem; class QMatrix; class QTransform; +class QStaticText; class QPainterPrivateDeleter; @@ -98,6 +99,29 @@ public: Q_DECLARE_FLAGS(RenderHints, RenderHint) + class Fragment { + public: + qreal x; + qreal y; + qreal sourceLeft; + qreal sourceTop; + qreal width; + qreal height; + qreal scaleX; + qreal scaleY; + qreal rotation; + qreal opacity; + static Fragment Q_GUI_EXPORT create(const QPointF &pos, const QRectF &sourceRect, + qreal scaleX = 1, qreal scaleY = 1, + qreal rotation = 0, qreal opacity = 1); + }; + + enum FragmentHint { + OpaqueHint = 0x01 + }; + + Q_DECLARE_FLAGS(FragmentHints, FragmentHint) + QPainter(); explicit QPainter(QPaintDevice *); ~QPainter(); @@ -351,6 +375,9 @@ public: inline void drawPixmap(const QRect &r, const QPixmap &pm); inline void drawPixmap(int x, int y, int w, int h, const QPixmap &pm); + void drawPixmapFragments(const Fragment *fragments, int fragmentCount, + const QPixmap &pixmap, FragmentHints hints = 0); + void drawImage(const QRectF &targetRect, const QImage &image, const QRectF &sourceRect, Qt::ImageConversionFlags flags = Qt::AutoColor); inline void drawImage(const QRect &targetRect, const QImage &image, const QRect &sourceRect, @@ -369,6 +396,10 @@ public: void setLayoutDirection(Qt::LayoutDirection direction); Qt::LayoutDirection layoutDirection() const; + void drawStaticText(const QPointF &p, const QStaticText &staticText); + inline void drawStaticText(const QPoint &p, const QStaticText &staticText); + inline void drawStaticText(int x, int y, const QStaticText &staticText); + void drawText(const QPointF &p, const QString &s); inline void drawText(const QPoint &p, const QString &s); inline void drawText(int x, int y, const QString &s); @@ -896,6 +927,16 @@ inline void QPainter::drawImage(int x, int y, const QImage &image, int sx, int s drawImage(QRectF(x, y, -1, -1), image, QRectF(sx, sy, sw, sh), flags); } +inline void QPainter::drawStaticText(const QPoint &p, const QStaticText &staticText) +{ + drawStaticText(QPointF(p), staticText); +} + +inline void QPainter::drawStaticText(int x, int y, const QStaticText &staticText) +{ + drawStaticText(QPointF(x, y), staticText); +} + inline void QPainter::drawTextItem(const QPoint &p, const QTextItem &ti) { drawTextItem(QPointF(p), ti); diff --git a/src/gui/painting/qpainter_p.h b/src/gui/painting/qpainter_p.h index 02a91aa..9362dbe 100644 --- a/src/gui/painting/qpainter_p.h +++ b/src/gui/painting/qpainter_p.h @@ -228,6 +228,7 @@ public: void draw_helper(const QPainterPath &path, DrawOperation operation = StrokeAndFillDraw); void drawStretchedGradient(const QPainterPath &path, DrawOperation operation); void drawOpaqueBackground(const QPainterPath &path, DrawOperation operation); + void drawGlyphs(const quint32 *glyphArray, const QPointF *positionArray, int glyphCount); void updateMatrix(); void updateInvMatrix(); @@ -238,6 +239,11 @@ public: void checkEmulation(); + static QPainterPrivate *get(QPainter *painter) + { + return painter->d_ptr.data(); + } + QTransform viewTransform() const; static bool attachPainterPrivate(QPainter *q, QPaintDevice *pdev); void detachPainterPrivate(QPainter *q); @@ -252,6 +258,8 @@ public: }; Q_GUI_EXPORT void qt_draw_helper(QPainterPrivate *p, const QPainterPath &path, QPainterPrivate::DrawOperation operation); +Q_GUI_EXPORT void qt_draw_glyphs(QPainter *painter, const quint32 *glyphArray, + const QPointF *positionArray, int glyphCount); QString qt_generate_brush_key(const QBrush &brush); diff --git a/src/gui/painting/qpainterpath.cpp b/src/gui/painting/qpainterpath.cpp index fba3595..f78de34 100644 --- a/src/gui/painting/qpainterpath.cpp +++ b/src/gui/painting/qpainterpath.cpp @@ -1257,6 +1257,8 @@ Qt::FillRule QPainterPath::fillRule() const void QPainterPath::setFillRule(Qt::FillRule fillRule) { ensureData(); + if (d_func()->fillRule == fillRule) + return; detach(); d_func()->fillRule = fillRule; diff --git a/src/gui/painting/qpathclipper.cpp b/src/gui/painting/qpathclipper.cpp index bc81514..949a820 100644 --- a/src/gui/painting/qpathclipper.cpp +++ b/src/gui/painting/qpathclipper.cpp @@ -1705,6 +1705,9 @@ QPainterPath QPathClipper::clip(Operation operation) if (subjectPath == clipPath) return op == BoolSub ? QPainterPath() : subjectPath; + bool subjectIsRect = pathToRect(subjectPath, 0); + bool clipIsRect = pathToRect(clipPath, 0); + const QRectF clipBounds = clipPath.boundingRect(); const QRectF subjectBounds = subjectPath.boundingRect(); @@ -1732,8 +1735,7 @@ QPainterPath QPathClipper::clip(Operation operation) } if (clipBounds.contains(subjectBounds)) { - QRectF clipRect; - if (pathToRect(clipPath, &clipRect) && clipRect.contains(subjectBounds)) { + if (clipIsRect) { switch (op) { case BoolSub: return QPainterPath(); @@ -1746,17 +1748,16 @@ QPainterPath QPathClipper::clip(Operation operation) } } } else if (subjectBounds.contains(clipBounds)) { - QRectF subjectRect; - if (pathToRect(subjectPath, &subjectRect) && subjectRect.contains(clipBounds)) { + if (subjectIsRect) { switch (op) { case BoolSub: if (clipPath.fillRule() == Qt::OddEvenFill) { QPainterPath result = clipPath; - result.addRect(subjectRect); + result.addRect(subjectBounds); return result; } else { QPainterPath result = clipPath.simplified(); - result.addRect(subjectRect); + result.addRect(subjectBounds); return result; } break; @@ -1769,6 +1770,13 @@ QPainterPath QPathClipper::clip(Operation operation) } } } + + if (op == BoolAnd) { + if (subjectIsRect) + return intersect(clipPath, subjectBounds); + else if (clipIsRect) + return intersect(subjectPath, clipBounds); + } } QWingedEdge list(subjectPath, clipPath); @@ -2052,4 +2060,243 @@ bool QPathClipper::handleCrossingEdges(QWingedEdge &list, qreal y, ClipperMode m return false; } +namespace { + +QList<QPainterPath> toSubpaths(const QPainterPath &path) +{ + + QList<QPainterPath> subpaths; + if (path.isEmpty()) + return subpaths; + + QPainterPath current; + for (int i = 0; i < path.elementCount(); ++i) { + const QPainterPath::Element &e = path.elementAt(i); + switch (e.type) { + case QPainterPath::MoveToElement: + if (current.elementCount() > 1) + subpaths += current; + current = QPainterPath(); + current.moveTo(e); + break; + case QPainterPath::LineToElement: + current.lineTo(e); + break; + case QPainterPath::CurveToElement: { + current.cubicTo(e, path.elementAt(i + 1), path.elementAt(i + 2)); + i+=2; + break; + } + case QPainterPath::CurveToDataElement: + Q_ASSERT(!"toSubpaths(), bad element type"); + break; + } + } + + if (current.elementCount() > 1) + subpaths << current; + + return subpaths; +} + +enum Edge +{ + Left, Top, Right, Bottom +}; + +static bool isVertical(Edge edge) +{ + return edge == Left || edge == Right; +} + +template <Edge edge> +bool compare(const QPointF &p, qreal t) +{ + switch (edge) + { + case Left: + return p.x() < t; + case Right: + return p.x() > t; + case Top: + return p.y() < t; + default: + return p.y() > t; + } +} + +template <Edge edge> +QPointF intersectLine(const QPointF &a, const QPointF &b, qreal t) +{ + QLineF line(a, b); + switch (edge) { + case Left: // fall-through + case Right: + return line.pointAt((t - a.x()) / (b.x() - a.x())); + default: + return line.pointAt((t - a.y()) / (b.y() - a.y())); + } +} + +void addLine(QPainterPath &path, const QLineF &line) +{ + if (path.elementCount() > 0) + path.lineTo(line.p1()); + else + path.moveTo(line.p1()); + + path.lineTo(line.p2()); +} + +template <Edge edge> +void clipLine(const QPointF &a, const QPointF &b, qreal t, QPainterPath &result) +{ + bool outA = compare<edge>(a, t); + bool outB = compare<edge>(b, t); + if (outA && outB) + return; + + if (outA) + addLine(result, QLineF(intersectLine<edge>(a, b, t), b)); + else if(outB) + addLine(result, QLineF(a, intersectLine<edge>(a, b, t))); + else + addLine(result, QLineF(a, b)); +} + +void addBezier(QPainterPath &path, const QBezier &bezier) +{ + if (path.elementCount() > 0) + path.lineTo(bezier.pt1()); + else + path.moveTo(bezier.pt1()); + + path.cubicTo(bezier.pt2(), bezier.pt3(), bezier.pt4()); +} + +template <Edge edge> +void clipBezier(const QPointF &a, const QPointF &b, const QPointF &c, const QPointF &d, qreal t, QPainterPath &result) +{ + QBezier bezier = QBezier::fromPoints(a, b, c, d); + + bool outA = compare<edge>(a, t); + bool outB = compare<edge>(b, t); + bool outC = compare<edge>(c, t); + bool outD = compare<edge>(d, t); + + int outCount = int(outA) + int(outB) + int(outC) + int(outD); + + if (outCount == 4) + return; + + if (outCount == 0) { + addBezier(result, bezier); + return; + } + + QTransform flip = isVertical(edge) ? QTransform(0, 1, 1, 0, 0, 0) : QTransform(); + QBezier unflipped = bezier; + QBezier flipped = bezier.mapBy(flip); + + qreal t0 = 0, t1 = 1; + int stationary = flipped.stationaryYPoints(t0, t1); + + qreal segments[4]; + QPointF points[4]; + points[0] = unflipped.pt1(); + segments[0] = 0; + + int segmentCount = 0; + if (stationary > 0) { + ++segmentCount; + segments[segmentCount] = t0; + points[segmentCount] = unflipped.pointAt(t0); + } + if (stationary > 1) { + ++segmentCount; + segments[segmentCount] = t1; + points[segmentCount] = unflipped.pointAt(t1); + } + ++segmentCount; + segments[segmentCount] = 1; + points[segmentCount] = unflipped.pt4(); + + qreal lastIntersection = 0; + for (int i = 0; i < segmentCount; ++i) { + outA = compare<edge>(points[i], t); + outB = compare<edge>(points[i+1], t); + + if (outA != outB) { + qreal intersection = flipped.tForY(segments[i], segments[i+1], t); + + if (outB) + addBezier(result, unflipped.getSubRange(lastIntersection, intersection)); + + lastIntersection = intersection; + } + } + + if (!outB) + addBezier(result, unflipped.getSubRange(lastIntersection, 1)); +} + +// clips a single subpath against a single edge +template <Edge edge> +QPainterPath clip(const QPainterPath &path, qreal t) +{ + QPainterPath result; + for (int i = 1; i < path.elementCount(); ++i) { + const QPainterPath::Element &element = path.elementAt(i); + Q_ASSERT(!element.isMoveTo()); + if (element.isLineTo()) { + clipLine<edge>(path.elementAt(i-1), path.elementAt(i), t, result); + } else { + clipBezier<edge>(path.elementAt(i-1), path.elementAt(i), path.elementAt(i+1), path.elementAt(i+2), t, result); + i += 2; + } + } + + int last = path.elementCount() - 1; + if (QPointF(path.elementAt(last)) != QPointF(path.elementAt(0))) + clipLine<edge>(path.elementAt(last), path.elementAt(0), t, result); + + return result; +} + +QPainterPath intersectPath(const QPainterPath &path, const QRectF &rect) +{ + QList<QPainterPath> subpaths = toSubpaths(path); + + QPainterPath result; + result.setFillRule(path.fillRule()); + for (int i = 0; i < subpaths.size(); ++i) { + QPainterPath subPath = subpaths.at(i); + QRectF bounds = subPath.boundingRect(); + if (bounds.intersects(rect)) { + if (bounds.left() < rect.left()) + subPath = clip<Left>(subPath, rect.left()); + if (bounds.right() > rect.right()) + subPath = clip<Right>(subPath, rect.right()); + + bounds = subPath.boundingRect(); + + if (bounds.top() < rect.top()) + subPath = clip<Top>(subPath, rect.top()); + if (bounds.bottom() > rect.bottom()) + subPath = clip<Bottom>(subPath, rect.bottom()); + + if (subPath.elementCount() > 1) + result.addPath(subPath); + } + } + return result; +} + +} + +QPainterPath QPathClipper::intersect(const QPainterPath &path, const QRectF &rect) +{ + return intersectPath(path, rect); +} + QT_END_NAMESPACE diff --git a/src/gui/painting/qpathclipper_p.h b/src/gui/painting/qpathclipper_p.h index b900862..b42dc1d 100644 --- a/src/gui/painting/qpathclipper_p.h +++ b/src/gui/painting/qpathclipper_p.h @@ -87,6 +87,7 @@ public: bool contains(); static bool pathToRect(const QPainterPath &path, QRectF *rect = 0); + static QPainterPath intersect(const QPainterPath &path, const QRectF &rect); private: Q_DISABLE_COPY(QPathClipper) diff --git a/src/gui/painting/qpdf.cpp b/src/gui/painting/qpdf.cpp index dd516b1..dcf745f 100644 --- a/src/gui/painting/qpdf.cpp +++ b/src/gui/painting/qpdf.cpp @@ -1415,6 +1415,7 @@ void QPdfBaseEngine::setProperty(PrintEnginePropertyKey key, const QVariant &val case PPK_FullPage: d->fullPage = value.toBool(); break; + case PPK_CopyCount: // fallthrough case PPK_NumberOfCopies: d->copies = value.toInt(); break; @@ -1504,6 +1505,17 @@ QVariant QPdfBaseEngine::property(PrintEnginePropertyKey key) const case PPK_FullPage: ret = d->fullPage; break; + case PPK_CopyCount: + ret = d->copies; + break; + case PPK_SupportsMultipleCopies: +#if !defined(QT_NO_CUPS) && !defined(QT_NO_LIBRARY) + if (QCUPSSupport::isAvailable()) + ret = true; + else +#endif + ret = false; + break; case PPK_NumberOfCopies: #if !defined(QT_NO_CUPS) && !defined(QT_NO_LIBRARY) if (QCUPSSupport::isAvailable()) diff --git a/src/gui/painting/qpdf_p.h b/src/gui/painting/qpdf_p.h index f79c5cc..9c4d05d 100644 --- a/src/gui/painting/qpdf_p.h +++ b/src/gui/painting/qpdf_p.h @@ -216,8 +216,6 @@ public: private: void updateClipPath(const QPainterPath & path, Qt::ClipOperation op); - - friend int qt_printerRealNumCopies(QPaintEngine *); }; class QPdfBaseEnginePrivate : public QAlphaPaintEnginePrivate diff --git a/src/gui/painting/qprintengine.h b/src/gui/painting/qprintengine.h index 35715fb..71ff954 100644 --- a/src/gui/painting/qprintengine.h +++ b/src/gui/painting/qprintengine.h @@ -86,6 +86,8 @@ public: PPK_PaperSources, PPK_CustomPaperSize, PPK_PageMargins, + PPK_CopyCount, + PPK_SupportsMultipleCopies, PPK_PaperSize = PPK_PageSize, PPK_CustomBase = 0xff00 diff --git a/src/gui/painting/qprintengine_mac.mm b/src/gui/painting/qprintengine_mac.mm index 7195c63..3d5d1d5 100644 --- a/src/gui/painting/qprintengine_mac.mm +++ b/src/gui/painting/qprintengine_mac.mm @@ -685,6 +685,7 @@ void QMacPrintEngine::setProperty(PrintEnginePropertyKey key, const QVariant &va case PPK_FullPage: d->fullPage = value.toBool(); break; + case PPK_CopyCount: // fallthrough case PPK_NumberOfCopies: PMSetCopies(d->settings, value.toInt(), false); break; @@ -787,6 +788,15 @@ QVariant QMacPrintEngine::property(PrintEnginePropertyKey key) const case PPK_NumberOfCopies: ret = 1; break; + case PPK_CopyCount: { + UInt32 copies = 1; + PMGetCopies(d->settings, &copies); + ret = (uint) copies; + break; + } + case PPK_SupportsMultipleCopies: + ret = true; + break; case PPK_Orientation: PMOrientation orientation; PMGetOrientation(d->format, &orientation); diff --git a/src/gui/painting/qprintengine_qws.cpp b/src/gui/painting/qprintengine_qws.cpp index 2d355b8..396d712 100644 --- a/src/gui/painting/qprintengine_qws.cpp +++ b/src/gui/painting/qprintengine_qws.cpp @@ -268,9 +268,13 @@ QVariant QtopiaPrintEngine::property(PrintEnginePropertyKey key) const case PPK_FullPage: ret = d->fullPage; break; + case PPK_CopyCount: // fallthrough case PPK_NumberOfCopies: ret = d->numCopies; break; + case PPK_SupportsMultipleCopies: + ret = false; + break; case PPK_Orientation: ret = d->orientation; break; @@ -329,6 +333,7 @@ void QtopiaPrintEngine::setProperty(PrintEnginePropertyKey key, const QVariant & case PPK_FullPage: d->fullPage = value.toBool(); break; + case PPK_CopyCount: // fallthrough case PPK_NumberOfCopies: d->numCopies = value.toInt(); break; diff --git a/src/gui/painting/qprintengine_win.cpp b/src/gui/painting/qprintengine_win.cpp index 374bfa0..ea9dc5d 100644 --- a/src/gui/painting/qprintengine_win.cpp +++ b/src/gui/painting/qprintengine_win.cpp @@ -368,7 +368,8 @@ void QWin32PrintEngine::drawTextItem(const QPointF &p, const QTextItem &textItem } // We only want to convert the glyphs to text if the entire string is compatible with ASCII - bool convertToText = true; + // 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; @@ -1240,6 +1241,7 @@ void QWin32PrintEngine::setProperty(PrintEnginePropertyKey key, const QVariant & d->updateOrigin(); break; + case PPK_CopyCount: // fallthrough case PPK_NumberOfCopies: if (!d->devMode) break; @@ -1406,6 +1408,14 @@ QVariant QWin32PrintEngine::property(PrintEnginePropertyKey key) const value = d->fullPage; break; + case PPK_CopyCount: + value = d->num_copies; + break; + + case PPK_SupportsMultipleCopies: + value = true; + break; + case PPK_NumberOfCopies: value = 1; break; diff --git a/src/gui/painting/qprintengine_win_p.h b/src/gui/painting/qprintengine_win_p.h index a3271cb..d435831 100644 --- a/src/gui/painting/qprintengine_win_p.h +++ b/src/gui/painting/qprintengine_win_p.h @@ -108,7 +108,6 @@ public: private: friend class QPrintDialog; friend class QPageSetupDialog; - friend int qt_printerRealNumCopies(QPaintEngine *); }; class QWin32PrintEnginePrivate : public QAlphaPaintEnginePrivate diff --git a/src/gui/painting/qprinter.cpp b/src/gui/painting/qprinter.cpp index 4d2b50a..edf224d 100644 --- a/src/gui/painting/qprinter.cpp +++ b/src/gui/painting/qprinter.cpp @@ -158,27 +158,6 @@ QSizeF qt_printerPaperSize(QPrinter::Orientation orientation, (qt_paperSizes[paperSize][height_index] * 72 / 25.4) / multiplier); } - -// returns the actual num copies set on a printer, not -// the number that is documented in QPrinter::numCopies() -int qt_printerRealNumCopies(QPaintEngine *engine) -{ - int numCopies = 1; - if (engine->type() == QPaintEngine::PostScript - || engine->type() == QPaintEngine::Pdf) - { - QPdfBaseEngine *base = static_cast<QPdfBaseEngine *>(engine); - numCopies = base->d_func()->copies; - } -#ifdef Q_WS_WIN - else if (engine->type() == QPaintEngine::Windows) { - QWin32PrintEngine *base = static_cast<QWin32PrintEngine *>(engine); - numCopies = base->d_func()->num_copies; - } -#endif - return numCopies; -} - void QPrinterPrivate::createDefaultEngines() { QPrinter::OutputFormat realOutputFormat = outputFormat; @@ -302,7 +281,7 @@ void QPrinterPrivate::addToManualSetList(QPrintEngine::PrintEnginePropertyKey ke printer to provide, in dots per inch (DPI). \i setFullPage() tells QPrinter whether you want to deal with the full page or just with the part the printer can draw on. - \i setNumCopies() tells QPrinter how many copies of the document + \i setCopyCount() tells QPrinter how many copies of the document it should print. \endlist @@ -748,7 +727,6 @@ void QPrinter::setOutputFormat(OutputFormat format) d->outputFormat = format; QPrintEngine *oldPrintEngine = d->printEngine; - QPaintEngine *oldPaintEngine = d->paintEngine; // same as the above - shouldn't be deleted const bool def_engine = d->use_default_engine; d->printEngine = 0; @@ -761,7 +739,7 @@ void QPrinter::setOutputFormat(OutputFormat format) // PPK_NumberOfCopies need special treatmeant since it in most cases // will return 1, disregarding the actual value that was set if (key == QPrintEngine::PPK_NumberOfCopies) - prop = QVariant(qt_printerRealNumCopies(oldPaintEngine)); + prop = QVariant(copyCount()); else prop = oldPrintEngine->property(key); if (prop.isValid()) @@ -1263,6 +1241,7 @@ QPrinter::ColorMode QPrinter::colorMode() const /*! + \obsolete Returns the number of copies to be printed. The default value is 1. On Windows, Mac OS X and X11 systems that support CUPS, this will always @@ -1275,6 +1254,8 @@ QPrinter::ColorMode QPrinter::colorMode() const buffering up the copies and in those cases the application must make an explicit call to the print code for each copy. + Use copyCount() in conjunction with supportsMultipleCopies() instead. + \sa setNumCopies(), actualNumCopies() */ @@ -1286,6 +1267,7 @@ int QPrinter::numCopies() const /*! + \obsolete \since 4.6 Returns the number of copies that will be printed. The default @@ -1294,22 +1276,26 @@ int QPrinter::numCopies() const This function always returns the actual value specified in the print dialog or using setNumCopies(). + Use copyCount() instead. + \sa setNumCopies(), numCopies() */ int QPrinter::actualNumCopies() const { - Q_D(const QPrinter); - return qt_printerRealNumCopies(d->paintEngine); + return copyCount(); } /*! + \obsolete Sets the number of copies to be printed to \a numCopies. The printer driver reads this setting and prints the specified number of copies. + Use setCopyCount() instead. + \sa numCopies() */ @@ -1321,6 +1307,58 @@ void QPrinter::setNumCopies(int numCopies) d->addToManualSetList(QPrintEngine::PPK_NumberOfCopies); } +/*! + \since 4.7 + + Sets the number of copies to be printed to \a count. + + The printer driver reads this setting and prints the specified number of + copies. + + \sa copyCount(), supportsMultipleCopies() +*/ + +void QPrinter::setCopyCount(int count) +{ + Q_D(QPrinter); + ABORT_IF_ACTIVE("QPrinter::setCopyCount;"); + d->printEngine->setProperty(QPrintEngine::PPK_CopyCount, count); + d->addToManualSetList(QPrintEngine::PPK_CopyCount); +} + +/*! + \since 4.7 + + Returns the number of copies that will be printed. The default value is 1. + + \sa setCopyCount(), supportsMultipleCopies() +*/ + +int QPrinter::copyCount() const +{ + Q_D(const QPrinter); + return d->printEngine->property(QPrintEngine::PPK_CopyCount).toInt(); +} + +/*! + \since 4.7 + + Returns true if the printer supports printing multiple copies of the same + document in one job; otherwise false is returned. + + On most systems this function will return true. However, on X11 systems + that do not support CUPS, this function will return false. That means the + application has to handle the number of copies by printing the same + document the required number of times. + + \sa setCopyCount(), copyCount() +*/ + +bool QPrinter::supportsMultipleCopies() const +{ + Q_D(const QPrinter); + return d->printEngine->property(QPrintEngine::PPK_SupportsMultipleCopies).toBool(); +} /*! \since 4.1 @@ -2262,8 +2300,8 @@ bool QPrinter::isOptionEnabled( PrinterOption option ) const \value PPK_FullPage A boolean describing if the printer should be full page or not. - \value PPK_NumberOfCopies An integer specifying the number of - copies + \value PPK_NumberOfCopies Obsolete. An integer specifying the number of + copies. Use PPK_CopyCount instead. \value PPK_Orientation Specifies a QPrinter::Orientation value. @@ -2310,6 +2348,11 @@ bool QPrinter::isOptionEnabled( PrinterOption option ) const \value PPK_PageMargins A QList<QVariant> containing the left, top, right and bottom margin values. + \value PPK_CopyCount An integer specifying the number of copies to print. + + \value PPK_SupportsMultipleCopies A boolean value indicating whether or not + the printer supports printing multiple copies in one job. + \value PPK_CustomBase Basis for extension. */ diff --git a/src/gui/painting/qprinter.h b/src/gui/painting/qprinter.h index 5aa891e..6636179 100644 --- a/src/gui/painting/qprinter.h +++ b/src/gui/painting/qprinter.h @@ -199,6 +199,10 @@ public: int actualNumCopies() const; + void setCopyCount(int); + int copyCount() const; + bool supportsMultipleCopies() const; + void setPaperSource(PaperSource); PaperSource paperSource() const; diff --git a/src/gui/painting/qtextureglyphcache.cpp b/src/gui/painting/qtextureglyphcache.cpp index 7b7f325..cf3957b 100644 --- a/src/gui/painting/qtextureglyphcache.cpp +++ b/src/gui/painting/qtextureglyphcache.cpp @@ -55,29 +55,42 @@ QT_BEGIN_NAMESPACE // #define CACHE_DEBUG -void QTextureGlyphCache::populate(const QTextItemInt &ti, - const QVarLengthArray<glyph_t> &glyphs, - const QVarLengthArray<QFixedPoint> &) +// returns the highest number closest to v, which is a power of 2 +// NB! assumes 32 bit ints +int qt_next_power_of_two(int v) +{ + v--; + v |= v >> 1; + v |= v >> 2; + v |= v >> 4; + v |= v >> 8; + v |= v >> 16; + ++v; + return v; +} + +void QTextureGlyphCache::populate(QFontEngine *fontEngine, int numGlyphs, const glyph_t *glyphs, + const QFixedPoint *) { #ifdef CACHE_DEBUG printf("Populating with '%s'\n", QString::fromRawData(ti.chars, ti.num_chars).toLatin1().data()); qDebug() << " -> current transformation: " << m_transform; #endif - m_current_textitem = &ti; + m_current_fontengine = fontEngine; const int margin = glyphMargin(); QHash<glyph_t, Coord> listItemCoordinates; int rowHeight = 0; // check each glyph for its metrics and get the required rowHeight. - for (int i=0; i < glyphs.size(); ++i) { + for (int i=0; i < numGlyphs; ++i) { const glyph_t glyph = glyphs[i]; if (coords.contains(glyph)) continue; if (listItemCoordinates.contains(glyph)) continue; - glyph_metrics_t metrics = ti.fontEngine->boundingBox(glyph, m_transform); + glyph_metrics_t metrics = fontEngine->boundingBox(glyph, m_transform); #ifdef CACHE_DEBUG printf("'%c' (%4x): w=%.2f, h=%.2f, xoff=%.2f, yoff=%.2f, x=%.2f, y=%.2f, ti.ascent=%.2f, ti.descent=%.2f\n", @@ -116,7 +129,7 @@ void QTextureGlyphCache::populate(const QTextItemInt &ti, rowHeight += margin * 2; if (isNull()) - createCache(QT_DEFAULT_TEXTURE_GLYPH_CACHE_WIDTH, rowHeight); + createCache(QT_DEFAULT_TEXTURE_GLYPH_CACHE_WIDTH, qt_next_power_of_two(rowHeight)); // now actually use the coords and paint the wanted glyps into cache. QHash<glyph_t, Coord>::iterator iter = listItemCoordinates.begin(); @@ -129,13 +142,9 @@ void QTextureGlyphCache::populate(const QTextItemInt &ti, m_cy = m_h; } if (m_cy + c.h > m_h) { - int new_height; - if (m_cx == 0) { // add a whole row - new_height = m_h + rowHeight; - m_cy = m_h; - } else { // just extend row - new_height = m_cy + rowHeight; - } + int new_height = m_h*2; + while (new_height < m_cy + c.h) + new_height *= 2; // if no room in the current texture - realloc a larger texture resizeTextureData(m_w, new_height); m_h = new_height; @@ -182,7 +191,7 @@ QImage QTextureGlyphCache::textureMapForGlyph(glyph_t g) const break; }; - QFontEngineFT *ft = static_cast<QFontEngineFT*> (m_current_textitem->fontEngine); + QFontEngineFT *ft = static_cast<QFontEngineFT*> (m_current_fontengine); QFontEngineFT::QGlyphSet *gset = ft->loadTransformedGlyphSet(m_transform); if (gset && ft->loadGlyphs(gset, &g, 1, format)) { @@ -194,9 +203,9 @@ QImage QTextureGlyphCache::textureMapForGlyph(glyph_t g) const } else #endif if (m_type == QFontEngineGlyphCache::Raster_RGBMask) - return m_current_textitem->fontEngine->alphaRGBMapForGlyph(g, glyphMargin(), m_transform); + return m_current_fontengine->alphaRGBMapForGlyph(g, glyphMargin(), m_transform); else - return m_current_textitem->fontEngine->alphaMapForGlyph(g, m_transform); + return m_current_fontengine->alphaMapForGlyph(g, m_transform); return QImage(); } diff --git a/src/gui/painting/qtextureglyphcache_p.h b/src/gui/painting/qtextureglyphcache_p.h index d347e61..803e71b 100644 --- a/src/gui/painting/qtextureglyphcache_p.h +++ b/src/gui/painting/qtextureglyphcache_p.h @@ -76,7 +76,9 @@ class Q_GUI_EXPORT QTextureGlyphCache : public QFontEngineGlyphCache { public: QTextureGlyphCache(QFontEngineGlyphCache::Type type, const QTransform &matrix) - : QFontEngineGlyphCache(matrix, type), m_w(0), m_h(0), m_cx(0), m_cy(0) { } + : QFontEngineGlyphCache(matrix, type), m_current_fontengine(0), + m_w(0), m_h(0), m_cx(0), m_cy(0) + { } virtual ~QTextureGlyphCache() { } @@ -90,9 +92,8 @@ public: int baseLineY; }; - void populate(const QTextItemInt &ti, - const QVarLengthArray<glyph_t> &glyphs, - const QVarLengthArray<QFixedPoint> &positions); + void populate(QFontEngine *fontEngine, int numGlyphs, const glyph_t *glyphs, + const QFixedPoint *positions); virtual void createTextureData(int width, int height) = 0; virtual void resizeTextureData(int width, int height) = 0; @@ -113,7 +114,7 @@ public: QImage textureMapForGlyph(glyph_t g) const; protected: - const QTextItemInt *m_current_textitem; + QFontEngine *m_current_fontengine; int m_w; // image width int m_h; // image height diff --git a/src/gui/statemachine/qguistatemachine.cpp b/src/gui/statemachine/qguistatemachine.cpp index 70f152d..63ad94e 100644 --- a/src/gui/statemachine/qguistatemachine.cpp +++ b/src/gui/statemachine/qguistatemachine.cpp @@ -469,12 +469,6 @@ static QEvent *cloneEvent(QEvent *e) case QEvent::UngrabKeyboard: return new QEvent(*e); -#ifdef QT_MAC_USE_COCOA - case QEvent::CocoaRequestModal: - Q_ASSERT_X(false, "cloneEvent()", "not implemented"); - break; -#endif - case QEvent::TouchBegin: case QEvent::TouchUpdate: case QEvent::TouchEnd: diff --git a/src/gui/styles/qcommonstyle.cpp b/src/gui/styles/qcommonstyle.cpp index b1924e7..f8464cc 100644 --- a/src/gui/styles/qcommonstyle.cpp +++ b/src/gui/styles/qcommonstyle.cpp @@ -5662,10 +5662,16 @@ QIcon QCommonStyle::standardIconImplementation(StandardPixmap standardIcon, cons OSType iconType = 0; switch (standardIcon) { case QStyle::SP_MessageBoxQuestion: + iconType = kQuestionMarkIcon; + break; case QStyle::SP_MessageBoxInformation: + iconType = kAlertNoteIcon; + break; case QStyle::SP_MessageBoxWarning: + iconType = kAlertCautionIcon; + break; case QStyle::SP_MessageBoxCritical: - iconType = kGenericApplicationIcon; + iconType = kAlertStopIcon; break; case SP_DesktopIcon: iconType = kDesktopIcon; @@ -5755,88 +5761,88 @@ QIcon QCommonStyle::standardIconImplementation(StandardPixmap standardIcon, cons switch (standardIcon) { #ifndef QT_NO_IMAGEFORMAT_PNG case SP_FileDialogNewFolder: - icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/newdirectory-16.png")); - icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/newdirectory-32.png")); - icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/newdirectory-128.png")); + icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/newdirectory-16.png"), QSize(16, 16)); + icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/newdirectory-32.png"), QSize(32, 32)); + icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/newdirectory-128.png"), QSize(128, 128)); break; case SP_FileDialogBack: return standardIconImplementation(SP_ArrowBack, option, widget); case SP_FileDialogToParent: return standardIconImplementation(SP_ArrowUp, option, widget); case SP_FileDialogDetailedView: - icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/viewdetailed-16.png")); - icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/viewdetailed-32.png")); - icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/viewdetailed-128.png")); + icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/viewdetailed-16.png"), QSize(16, 16)); + icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/viewdetailed-32.png"), QSize(32, 32)); + icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/viewdetailed-128.png"), QSize(128, 128)); break; case SP_FileDialogInfoView: - icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/fileinfo-16.png")); - icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/fileinfo-32.png")); - icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/fileinfo-128.png")); + icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/fileinfo-16.png"), QSize(16, 16)); + icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/fileinfo-32.png"), QSize(32, 32)); + icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/fileinfo-128.png"), QSize(128, 128)); break; case SP_FileDialogContentsView: - icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/filecontents-16.png")); - icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/filecontents-32.png")); - icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/filecontents-128.png")); + icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/filecontents-16.png"), QSize(16, 16)); + icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/filecontents-32.png"), QSize(32, 32)); + icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/filecontents-128.png"), QSize(128, 128)); break; case SP_FileDialogListView: - icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/viewlist-16.png")); - icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/viewlist-32.png")); - icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/viewlist-128.png")); + icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/viewlist-16.png"), QSize(16, 16)); + icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/viewlist-32.png"), QSize(32, 32)); + icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/viewlist-128.png"), QSize(128, 128)); break; case SP_DialogOkButton: - icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/standardbutton-ok-16.png")); - icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/standardbutton-ok-32.png")); - icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/standardbutton-ok-128.png")); + icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/standardbutton-ok-16.png"), QSize(16, 16)); + icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/standardbutton-ok-32.png"), QSize(32, 32)); + icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/standardbutton-ok-128.png"), QSize(128, 128)); break; case SP_DialogCancelButton: - icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/standardbutton-cancel-16.png")); - icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/standardbutton-cancel-32.png")); - icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/standardbutton-cancel-128.png")); + icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/standardbutton-cancel-16.png"), QSize(16, 16)); + icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/standardbutton-cancel-32.png"), QSize(32, 32)); + icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/standardbutton-cancel-128.png"), QSize(128, 128)); break; case SP_DialogHelpButton: - icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/standardbutton-help-16.png")); - icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/standardbutton-help-32.png")); - icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/standardbutton-help-128.png")); + icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/standardbutton-help-16.png"), QSize(16, 16)); + icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/standardbutton-help-32.png"), QSize(32, 32)); + icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/standardbutton-help-128.png"), QSize(128, 128)); break; case SP_DialogOpenButton: - icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/standardbutton-open-16.png")); - icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/standardbutton-open-32.png")); - icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/standardbutton-open-128.png")); + icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/standardbutton-open-16.png"), QSize(16, 16)); + icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/standardbutton-open-32.png"), QSize(32, 32)); + icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/standardbutton-open-128.png"), QSize(128, 128)); break; case SP_DialogSaveButton: - icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/standardbutton-save-16.png")); - icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/standardbutton-save-32.png")); - icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/standardbutton-save-128.png")); + icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/standardbutton-save-16.png"), QSize(16, 16)); + icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/standardbutton-save-32.png"), QSize(32, 32)); + icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/standardbutton-save-128.png"), QSize(128, 128)); break; case SP_DialogCloseButton: - icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/standardbutton-close-16.png")); - icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/standardbutton-close-32.png")); - icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/standardbutton-close-128.png")); + icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/standardbutton-close-16.png"), QSize(16, 16)); + icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/standardbutton-close-32.png"), QSize(32, 32)); + icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/standardbutton-close-128.png"), QSize(128, 128)); break; case SP_DialogApplyButton: - icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/standardbutton-apply-16.png")); - icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/standardbutton-apply-32.png")); - icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/standardbutton-apply-128.png")); + icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/standardbutton-apply-16.png"), QSize(16, 16)); + icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/standardbutton-apply-32.png"), QSize(32, 32)); + icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/standardbutton-apply-128.png"), QSize(128, 128)); break; case SP_DialogResetButton: - icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/standardbutton-clear-16.png")); - icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/standardbutton-clear-32.png")); - icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/standardbutton-clear-128.png")); + icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/standardbutton-clear-16.png"), QSize(16, 16)); + icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/standardbutton-clear-32.png"), QSize(32, 32)); + icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/standardbutton-clear-128.png"), QSize(128, 128)); break; case SP_DialogDiscardButton: - icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/standardbutton-delete-16.png")); - icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/standardbutton-delete-32.png")); - icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/standardbutton-delete-128.png")); + icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/standardbutton-delete-16.png"), QSize(16, 16)); + icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/standardbutton-delete-32.png"), QSize(32, 32)); + icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/standardbutton-delete-128.png"), QSize(128, 128)); break; case SP_DialogYesButton: - icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/standardbutton-yes-16.png")); - icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/standardbutton-yes-32.png")); - icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/standardbutton-yes-128.png")); + icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/standardbutton-yes-16.png"), QSize(16, 16)); + icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/standardbutton-yes-32.png"), QSize(32, 32)); + icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/standardbutton-yes-128.png"), QSize(128, 128)); break; case SP_DialogNoButton: - icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/standardbutton-no-16.png")); - icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/standardbutton-no-32.png")); - icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/standardbutton-no-128.png")); + icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/standardbutton-no-16.png"), QSize(16, 16)); + icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/standardbutton-no-32.png"), QSize(32, 32)); + icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/standardbutton-no-128.png"), QSize(128, 128)); break; case SP_ArrowForward: if (rtl) @@ -5847,24 +5853,24 @@ QIcon QCommonStyle::standardIconImplementation(StandardPixmap standardIcon, cons return standardIconImplementation(SP_ArrowRight, option, widget); return standardIconImplementation(SP_ArrowLeft, option, widget); case SP_ArrowLeft: - icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/left-16.png")); - icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/left-32.png")); - icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/left-128.png")); + icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/left-16.png"), QSize(16, 16)); + icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/left-32.png"), QSize(32, 32)); + icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/left-128.png"), QSize(128, 128)); break; case SP_ArrowRight: - icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/right-16.png")); - icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/right-32.png")); - icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/right-128.png")); + icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/right-16.png"), QSize(16, 16)); + icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/right-32.png"), QSize(32, 32)); + icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/right-128.png"), QSize(128, 128)); break; case SP_ArrowUp: - icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/up-16.png")); - icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/up-32.png")); - icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/up-128.png")); + icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/up-16.png"), QSize(16, 16)); + icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/up-32.png"), QSize(32, 32)); + icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/up-128.png"), QSize(128, 128)); break; case SP_ArrowDown: - icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/down-16.png")); - icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/down-32.png")); - icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/down-128.png")); + icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/down-16.png"), QSize(16, 16)); + icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/down-32.png"), QSize(32, 32)); + icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/down-128.png"), QSize(128, 128)); break; case SP_DirHomeIcon: case SP_DirIcon: @@ -5882,71 +5888,71 @@ QIcon QCommonStyle::standardIconImplementation(StandardPixmap standardIcon, cons QSize(128, 128), QIcon::Normal, QIcon::On); break; case SP_DriveCDIcon: - icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/cdr-16.png")); - icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/cdr-32.png")); - icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/cdr-128.png")); + icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/cdr-16.png"), QSize(16, 16)); + icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/cdr-32.png"), QSize(32, 32)); + icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/cdr-128.png"), QSize(128, 128)); break; case SP_DriveDVDIcon: - icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/dvd-16.png")); - icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/dvd-32.png")); - icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/dvd-128.png")); + icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/dvd-16.png"), QSize(16, 16)); + icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/dvd-32.png"), QSize(32, 32)); + icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/dvd-128.png"), QSize(128, 128)); break; case SP_FileIcon: - icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/file-16.png")); - icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/file-32.png")); - icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/file-128.png")); + icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/file-16.png"), QSize(16, 16)); + icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/file-32.png"), QSize(32, 32)); + icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/file-128.png"), QSize(128, 128)); break; case SP_FileLinkIcon: - icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/filelink-16.png")); - icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/filelink-32.png")); - icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/filelink-128.png")); + icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/filelink-16.png"), QSize(16, 16)); + icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/filelink-32.png"), QSize(32, 32)); + icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/filelink-128.png"), QSize(128, 128)); break; case SP_TrashIcon: - icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/trash-16.png")); - icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/trash-32.png")); - icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/trash-128.png")); + icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/trash-16.png"), QSize(16, 16)); + icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/trash-32.png"), QSize(32, 32)); + icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/trash-128.png"), QSize(128, 128)); break; case SP_BrowserReload: - icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/refresh-24.png")); - icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/refresh-32.png")); + icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/refresh-24.png"), QSize(24, 24)); + icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/refresh-32.png"), QSize(32, 32)); break; case SP_BrowserStop: - icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/stop-24.png")); - icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/stop-32.png")); + icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/stop-24.png"), QSize(24, 24)); + icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/stop-32.png"), QSize(32, 32)); break; case SP_MediaPlay: - icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/media-play-16.png")); - icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/media-play-32.png")); + icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/media-play-16.png"), QSize(16, 16)); + icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/media-play-32.png"), QSize(32, 32)); break; case SP_MediaPause: - icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/media-pause-16.png")); - icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/media-pause-32.png")); + icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/media-pause-16.png"), QSize(16, 16)); + icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/media-pause-32.png"), QSize(32, 32)); break; case SP_MediaStop: - icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/media-stop-16.png")); - icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/media-stop-32.png")); + icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/media-stop-16.png"), QSize(16, 16)); + icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/media-stop-32.png"), QSize(32, 32)); break; case SP_MediaSeekForward: - icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/media-seek-forward-16.png")); - icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/media-seek-forward-32.png")); + icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/media-seek-forward-16.png"), QSize(16, 16)); + icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/media-seek-forward-32.png"), QSize(32, 32)); break; case SP_MediaSeekBackward: - icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/media-seek-backward-16.png")); - icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/media-seek-backward-32.png")); + icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/media-seek-backward-16.png"), QSize(16, 16)); + icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/media-seek-backward-32.png"), QSize(32, 32)); break; case SP_MediaSkipForward: - icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/media-skip-forward-16.png")); - icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/media-skip-forward-32.png")); + icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/media-skip-forward-16.png"), QSize(16, 16)); + icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/media-skip-forward-32.png"), QSize(32, 32)); break; case SP_MediaSkipBackward: - icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/media-skip-backward-16.png")); - icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/media-skip-backward-32.png")); + icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/media-skip-backward-16.png"), QSize(16, 16)); + icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/media-skip-backward-32.png"), QSize(32, 32)); break; case SP_MediaVolume: - icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/media-volume-16.png")); + icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/media-volume-16.png"), QSize(16, 16)); break; case SP_MediaVolumeMuted: - icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/media-volume-muted-16.png")); + icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/media-volume-muted-16.png"), QSize(16, 16)); break; #endif // QT_NO_IMAGEFORMAT_PNG default: diff --git a/src/gui/styles/qmacstyle_mac.mm b/src/gui/styles/qmacstyle_mac.mm index 5bd939f..116b03e 100644 --- a/src/gui/styles/qmacstyle_mac.mm +++ b/src/gui/styles/qmacstyle_mac.mm @@ -3146,6 +3146,18 @@ void QMacStyle::drawPrimitive(PrimitiveElement pe, const QStyleOption *opt, QPai break; case PE_PanelLineEdit: QWindowsStyle::drawPrimitive(pe, opt, p, w); + // Draw the focus frame for widgets other than QLineEdit (e.g. for line edits in Webkit). + // Focus frame is drawn outside the rectangle passed in the option-rect. + if (const QStyleOptionFrame *panel = qstyleoption_cast<const QStyleOptionFrame *>(opt)) { + if ((opt->state & State_HasFocus) && !qobject_cast<const QLineEdit*>(w)) { + int vmargin = pixelMetric(QStyle::PM_FocusFrameVMargin); + int hmargin = pixelMetric(QStyle::PM_FocusFrameHMargin); + QStyleOptionFrame focusFrame = *panel; + focusFrame.rect = panel->rect.adjusted(-hmargin, -vmargin, hmargin, vmargin); + drawControl(CE_FocusFrame, &focusFrame, p, w); + } + } + break; case PE_FrameTabWidget: if (const QStyleOptionTabWidgetFrame *twf @@ -3169,7 +3181,6 @@ void QMacStyle::drawPrimitive(PrimitiveElement pe, const QStyleOption *opt, QPai p->drawLine(opt->rect.topLeft(), opt->rect.bottomLeft()); } break; case PE_FrameStatusBarItem: - QCommonStyle::drawPrimitive(pe, opt, p, w); break; case PE_IndicatorTabClose: { bool hover = (opt->state & State_MouseOver); diff --git a/src/gui/styles/qs60style_s60.cpp b/src/gui/styles/qs60style_s60.cpp index d57b187..cb49fbc 100644 --- a/src/gui/styles/qs60style_s60.cpp +++ b/src/gui/styles/qs60style_s60.cpp @@ -58,8 +58,8 @@ #include <aknsskininstance.h> #include <aknsbasicbackgroundcontrolcontext.h> #include <avkon.mbg> -#include <AknFontAccess.h> -#include <AknLayoutFont.h> +#include <aknfontaccess.h> +#include <aknlayoutfont.h> #include <aknutils.h> #include <aknnavi.h> #include <gulicon.h> diff --git a/src/gui/styles/qs60style_simulated.cpp b/src/gui/styles/qs60style_simulated.cpp index f87cf28..3f09ebc 100644 --- a/src/gui/styles/qs60style_simulated.cpp +++ b/src/gui/styles/qs60style_simulated.cpp @@ -94,12 +94,12 @@ bool saveThemeToBlob(const QString &themeBlob, dataOut << color; } - const int picturesCount = partPictures.count(); - dataOut << picturesCount; - foreach (const QString &key, partPictures.keys()) { - const QPicture picture = partPictures.value(key); - dataOut << key; - dataOut << picture; + dataOut << partPictures.count(); + QHashIterator<QString, QPicture> i(partPictures); + while (i.hasNext()) { + i.next(); + dataOut << i.key(); + dataOut << i.value(); // the QPicture } QDataStream blobOut(&blob); diff --git a/src/gui/styles/qstylesheetstyle.cpp b/src/gui/styles/qstylesheetstyle.cpp index c550938..bc1bece 100644 --- a/src/gui/styles/qstylesheetstyle.cpp +++ b/src/gui/styles/qstylesheetstyle.cpp @@ -1065,7 +1065,7 @@ QRect QRenderRule::boxRect(const QRect& cr, int flags) const r.adjust(-p[LeftEdge], -p[TopEdge], p[RightEdge], p[BottomEdge]); } } - if (!hasNativeBorder() && (flags & Border)) { + if (hasBorder() && (flags & Border)) { const int *b = border()->borders; r.adjust(-b[LeftEdge], -b[TopEdge], b[RightEdge], b[BottomEdge]); } @@ -1352,6 +1352,12 @@ void QRenderRule::configurePalette(QPalette *p, QPalette::ColorRole fr, QPalette if (br != QPalette::NoRole) p->setBrush(br, bg->brush); p->setBrush(QPalette::Window, bg->brush); + if (bg->brush.style() == Qt::SolidPattern) { + p->setBrush(QPalette::Light, bg->brush.color().lighter(115)); + p->setBrush(QPalette::Midlight, bg->brush.color().lighter(107)); + p->setBrush(QPalette::Dark, bg->brush.color().darker(150)); + p->setBrush(QPalette::Shadow, bg->brush.color().darker(300)); + } } if (!hasPalette()) diff --git a/src/gui/text/qfont.h b/src/gui/text/qfont.h index a2fff70..5adf237 100644 --- a/src/gui/text/qfont.h +++ b/src/gui/text/qfont.h @@ -291,6 +291,7 @@ private: friend class QFontMetricsF; friend class QFontInfo; friend class QPainter; + friend class QPainterPrivate; friend class QPSPrintEngineFont; friend class QApplication; friend class QWidget; diff --git a/src/gui/text/qfontdatabase_s60.cpp b/src/gui/text/qfontdatabase_s60.cpp index 7e5397d..87a73df 100644 --- a/src/gui/text/qfontdatabase_s60.cpp +++ b/src/gui/text/qfontdatabase_s60.cpp @@ -50,7 +50,7 @@ #include "qendian.h" #include <private/qcore_symbian_p.h> #if defined(QT_NO_FREETYPE) -#include <OPENFONT.H> +#include <openfont.h> #ifdef SYMBIAN_ENABLE_SPLIT_HEADERS #include <graphics/openfontrasterizer.h> // COpenFontRasterizer has moved to a new header file #endif // SYMBIAN_ENABLE_SPLIT_HEADERS diff --git a/src/gui/text/qfontdatabase_win.cpp b/src/gui/text/qfontdatabase_win.cpp index a6ceee1..c50d363 100644 --- a/src/gui/text/qfontdatabase_win.cpp +++ b/src/gui/text/qfontdatabase_win.cpp @@ -1111,7 +1111,6 @@ static void registerFont(QFontDatabasePrivate::ApplicationFont *fnt) if (AddFontResource((LPCWSTR)fnt->fileName.utf16()) == 0) return; #else - // supported from 2000 on, so no need to deal with the *A variant PtrAddFontResourceExW ptrAddFontResourceExW = (PtrAddFontResourceExW)QLibrary::resolve(QLatin1String("gdi32"), "AddFontResourceExW"); if (!ptrAddFontResourceExW diff --git a/src/gui/text/qfontengine.cpp b/src/gui/text/qfontengine.cpp index c000457..e5975d2 100644 --- a/src/gui/text/qfontengine.cpp +++ b/src/gui/text/qfontengine.cpp @@ -587,8 +587,9 @@ QImage QFontEngine::alphaMapForGlyph(glyph_t glyph, const QTransform &t) { QImage i = alphaMapForGlyph(glyph); if (t.type() > QTransform::TxTranslate) - i = i.transformed(t); + i = i.transformed(t).convertToFormat(QImage::Format_Indexed8); Q_ASSERT(i.depth() <= 8); // To verify that transformed didn't change the format... + return i; } @@ -597,11 +598,14 @@ QImage QFontEngine::alphaRGBMapForGlyph(glyph_t glyph, int /* margin */, const Q QImage alphaMask = alphaMapForGlyph(glyph, t); QImage rgbMask(alphaMask.width(), alphaMask.height(), QImage::Format_RGB32); + QVector<QRgb> colorTable = alphaMask.colorTable(); for (int y=0; y<alphaMask.height(); ++y) { uint *dst = (uint *) rgbMask.scanLine(y); uchar *src = (uchar *) alphaMask.scanLine(y); - for (int x=0; x<alphaMask.width(); ++x) - dst[x] = qRgb(src[x], src[x], src[x]); + for (int x=0; x<alphaMask.width(); ++x) { + int val = qAlpha(colorTable.at(src[x])); + dst[x] = qRgb(val, val, val); + } } return rgbMask; diff --git a/src/gui/text/qfontengine_s60_p.h b/src/gui/text/qfontengine_s60_p.h index 78f8a9a..5834cc4 100644 --- a/src/gui/text/qfontengine_s60_p.h +++ b/src/gui/text/qfontengine_s60_p.h @@ -56,7 +56,7 @@ #include "qconfig.h" #include "qfontengine_p.h" #include "qsize.h" -#include <OPENFONT.H> +#include <openfont.h> class CFont; diff --git a/src/gui/text/qfontengine_win.cpp b/src/gui/text/qfontengine_win.cpp index 1a815d3..55e93bd 100644 --- a/src/gui/text/qfontengine_win.cpp +++ b/src/gui/text/qfontengine_win.cpp @@ -208,7 +208,7 @@ void QFontEngineWin::getCMap() unitsPerEm = otm->otmEMSquare; x_height = (int)otm->otmsXHeight; loadKerningPairs(designToDevice); - _faceId.filename = QString::fromWCharArray((wchar_t *)((char *)otm + (int)otm->otmpFullName)).toLatin1(); + _faceId.filename = QString::fromWCharArray((wchar_t *)((char *)otm + (quintptr)otm->otmpFullName)).toLatin1(); lineWidth = otm->otmsUnderscoreSize; fsType = otm->otmfsType; free(otm); @@ -1006,8 +1006,8 @@ QFontEngine::Properties QFontEngineWin::properties() const Properties p; p.emSquare = unitsPerEm; p.italicAngle = otm->otmItalicAngle; - p.postscriptName = QString::fromWCharArray((wchar_t *)((char *)otm + (int)otm->otmpFamilyName)).toLatin1(); - p.postscriptName += QString::fromWCharArray((wchar_t *)((char *)otm + (int)otm->otmpStyleName)).toLatin1(); + p.postscriptName = QString::fromWCharArray((wchar_t *)((char *)otm + (quintptr)otm->otmpFamilyName)).toLatin1(); + p.postscriptName += QString::fromWCharArray((wchar_t *)((char *)otm + (quintptr)otm->otmpStyleName)).toLatin1(); #ifndef QT_NO_PRINTER p.postscriptName = QPdf::stripSpecialCharacters(p.postscriptName); #endif diff --git a/src/gui/text/qstatictext.cpp b/src/gui/text/qstatictext.cpp new file mode 100644 index 0000000..8fe4c47 --- /dev/null +++ b/src/gui/text/qstatictext.cpp @@ -0,0 +1,614 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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 "qstatictext.h" +#include "qstatictext_p.h" +#include <private/qtextengine_p.h> +#include <private/qfontengine_p.h> + +#include <QtGui/qapplication.h> + +QT_BEGIN_NAMESPACE + +/*! + \class QStaticText + \brief The QStaticText class enables optimized drawing of text when the text and its layout + is updated rarely. + \since 4.7 + + \ingroup multimedia + \ingroup text + \mainclass + + QStaticText provides a way to cache layout data for a block of text so that it can be drawn + more efficiently than by using QPainter::drawText() in which the layout information is + recalculated with every call. + + The class primarily provides an optimization for cases where the text, its font and the + transformations on the painter are static over several paint events. If the text or its layout + is changed for every iteration, QPainter::drawText() is the more efficient alternative, since + the static text's layout would have to be recalculated to take the new state into consideration. + + Translating the painter will not cause the layout of the text to be recalculated, but will cause + a very small performance impact on drawStaticText(). Altering any other parts of the painter's + transformation or the painter's font will cause the layout of the static text to be + recalculated. This should be avoided as often as possible to maximize the performance + benefit of using QStaticText. + + In addition, only affine transformations are supported by drawStaticText(). Calling + drawStaticText() on a projected painter will perform slightly worse than using the regular + drawText() call, so this should be avoided. + + \code + class MyWidget: public QWidget + { + public: + MyWidget(QWidget *parent = 0) : QWidget(parent), m_staticText("This is static text") + + protected: + void paintEvent(QPaintEvent *) + { + QPainter painter(this); + painter.drawStaticText(0, 0, m_staticText); + } + + private: + QStaticText m_staticText; + }; + \endcode + + The QStaticText class can be used to mimic the behavior of QPainter::drawText() to a specific + point with no boundaries, and also when QPainter::drawText() is called with a bounding + rectangle. + + If a bounding rectangle is not required, create a QStaticText object without setting a maximum + size. The text will then occupy a single line. + + If you set a maximum size on the QStaticText object, this will bound the text. The text will + be formatted so that no line exceeds the given width. When the object is painted, it will + be clipped at the given size. The position of the text is decided by the argument + passed to QPainter::drawStaticText() and can change from call to call with a minimal impact + on performance. + + QStaticText will attempt to guess the format of the input text using Qt::mightBeRichText(). + To force QStaticText to display its contents as either plain text or rich text, use the + function QStaticText::setTextFormat() and pass in, respectively, Qt::PlainText and + Qt::RichText. + + \sa QPainter::drawText(), QPainter::drawStaticText(), QTextLayout, QTextDocument +*/ + +/*! + \enum QStaticText::PerformanceHint + + This enum the different performance hints that can be set on the QStaticText. These hints + can be used to indicate that the QStaticText should use additional caches, if possible, + to improve performance at the expense of memory. In particular, setting the performance hint + AggressiveCaching on the QStaticText will improve performance when using the OpenGL graphics + system or when drawing to a QGLWidget. + + \value ModerateCaching Do basic caching for high performance at a low memory cost. + \value AggressiveCaching Use additional caching when available. This may improve performance + at a higher memory cost. +*/ + +/*! + Constructs an empty QStaticText +*/ +QStaticText::QStaticText() + : data(new QStaticTextPrivate) +{ +} + +/*! + Constructs a QStaticText object with the given \a text and bounded by the given \a size. + + If an invalid size is passed for \a size the text will be unbounded. +*/ +QStaticText::QStaticText(const QString &text, const QSizeF &size) + : data(new QStaticTextPrivate) +{ + data->text = text; + data->maximumSize = size; + data->init(); +} + +/*! + Constructs a QStaticText object which is a copy of \a other. +*/ +QStaticText::QStaticText(const QStaticText &other) +{ + data = other.data; +} + +/*! + Destroys the QStaticText. +*/ +QStaticText::~QStaticText() +{ + Q_ASSERT(!data || data->ref >= 1); +} + +/*! + \internal +*/ +void QStaticText::detach() +{ + if (data->ref != 1) + data.detach(); +} + +/*! + Prepares the QStaticText object for being painted with the given \a matrix and the given + \a font to avoid overhead when the actual drawStaticText() call is made. + + When drawStaticText() is called, the layout of the QStaticText will be recalculated if the + painter's font or matrix is different from the one used for the currently cached layout. By + default, QStaticText will use a default constructed QFont and an identity matrix to create + its layout. + + To avoid the overhead of creating the layout the first time you draw the QStaticText with + a painter whose matrix or font are different from the defaults, you can use the prepare() + function and pass in the matrix and font you expect to use when drawing the text. + + \sa QPainter::setFont(), QPainter::setMatrix() +*/ +void QStaticText::prepare(const QTransform &matrix, const QFont &font) +{ + data->matrix = matrix; + data->font = font; + data->init(); +} + + +/*! + Assigns \a other to this QStaticText. +*/ +QStaticText &QStaticText::operator=(const QStaticText &other) +{ + data = other.data; + return *this; +} + +/*! + Compares \a other to this QStaticText. Returns true if the texts, fonts and maximum sizes + are equal. +*/ +bool QStaticText::operator==(const QStaticText &other) const +{ + return (data == other.data + || (data->text == other.data->text + && data->font == other.data->font + && data->maximumSize == other.data->maximumSize)); +} + +/*! + Compares \a other to this QStaticText. Returns true if the texts, fonts or maximum sizes + are different. +*/ +bool QStaticText::operator!=(const QStaticText &other) const +{ + return !(*this == other); +} + +/*! + Sets the text of the QStaticText to \a text. + + \note This function will cause the layout of the text to be recalculated. + + \sa text() +*/ +void QStaticText::setText(const QString &text) +{ + detach(); + data->text = text; + data->init(); +} + +/*! + Sets the text format of the QStaticText to \a textFormat. If \a textFormat is set to + Qt::AutoText (the default), the format of the text will try to be determined using the + function Qt::mightBeRichText(). If the text format is Qt::PlainText, then the text will be + displayed as is, whereas it will be interpreted as HTML if the format is Qt::RichText. HTML tags + that alter the font of the text, its color, or its layout are supported by QStaticText. + + \note This function will cause the layout of the text to be recalculated. + + \sa textFormat(), setText(), text() +*/ +void QStaticText::setTextFormat(Qt::TextFormat textFormat) +{ + detach(); + data->textFormat = textFormat; + data->init(); +} + +/*! + Returns the text format of the QStaticText. + + \sa setTextFormat(), setText(), text() +*/ +Qt::TextFormat QStaticText::textFormat() const +{ + return Qt::TextFormat(data->textFormat); +} + +/*! + Returns the text of the QStaticText. + + \sa setText() +*/ +QString QStaticText::text() const +{ + return data->text; +} + +/*! + Sets the performance hint of the QStaticText. This hint can be used to customize how much + caching is done internally to improve performance. + + The default is QStaticText::ModerateCaching. + + \note This function will cause the layout of the text to be recalculated. + + \sa performanceHint() +*/ +void QStaticText::setPerformanceHint(PerformanceHint performanceHint) +{ + if ((performanceHint == ModerateCaching && !data->useBackendOptimizations) + || (performanceHint == AggressiveCaching && data->useBackendOptimizations)) { + return; + } + detach(); + data->useBackendOptimizations = (performanceHint == AggressiveCaching); + data->init(); +} + +/*! + Returns which performance hint is set for the QStaticText. + + \sa setPerformanceHint() +*/ +QStaticText::PerformanceHint QStaticText::performanceHint() const +{ + return data->useBackendOptimizations ? AggressiveCaching : ModerateCaching; +} + +/*! + Sets the maximum size of the QStaticText to \a size. + + \note This function will cause the layout of the text to be recalculated. + + \sa maximumSize(), size() +*/ +void QStaticText::setMaximumSize(const QSizeF &size) +{ + detach(); + data->maximumSize = size; + data->init(); +} + +/*! + Returns the maximum size of the QStaticText. + + \sa setMaximumSize() +*/ +QSizeF QStaticText::maximumSize() const +{ + return data->maximumSize; +} + +/*! + Returns the size of the bounding rect for this QStaticText. + + \sa maximumSize() +*/ +QSizeF QStaticText::size() const +{ + return data->actualSize; +} + +QStaticTextPrivate::QStaticTextPrivate() + : items(0), itemCount(0), glyphPool(0), positionPool(0), needsClipRect(false), + useBackendOptimizations(false), textFormat(Qt::AutoText) +{ +} + +QStaticTextPrivate::QStaticTextPrivate(const QStaticTextPrivate &other) + : text(other.text), font(other.font), maximumSize(other.maximumSize), matrix(other.matrix), + items(0), itemCount(0), glyphPool(0), positionPool(0), needsClipRect(false), + useBackendOptimizations(other.useBackendOptimizations), textFormat(other.textFormat) +{ +} + +QStaticTextPrivate::~QStaticTextPrivate() +{ + delete[] items; + delete[] glyphPool; + delete[] positionPool; +} + +QStaticTextPrivate *QStaticTextPrivate::get(const QStaticText *q) +{ + return q->data.data(); +} + +extern int qt_defaultDpiX(); +extern int qt_defaultDpiY(); + +namespace { + + class DrawTextItemRecorder: public QPaintEngine + { + public: + DrawTextItemRecorder(int expectedItemCount, QStaticTextItem *items, + int expectedGlyphCount, QFixedPoint *positionPool, glyph_t *glyphPool) + : m_items(items), + m_itemCount(0), m_glyphCount(0), + m_expectedItemCount(expectedItemCount), + m_expectedGlyphCount(expectedGlyphCount), + m_glyphPool(glyphPool), + m_positionPool(positionPool) + { + } + + virtual void drawTextItem(const QPointF &position, const QTextItem &textItem) + { + const QTextItemInt &ti = static_cast<const QTextItemInt &>(textItem); + + m_itemCount++; + m_glyphCount += ti.glyphs.numGlyphs; + if (m_items == 0) + return; + + Q_ASSERT(m_itemCount <= m_expectedItemCount); + Q_ASSERT(m_glyphCount <= m_expectedGlyphCount); + + QStaticTextItem *currentItem = (m_items + (m_itemCount - 1)); + currentItem->fontEngine = ti.fontEngine; + currentItem->font = ti.font(); + currentItem->chars = ti.chars; + currentItem->numChars = ti.num_chars; + currentItem->numGlyphs = ti.glyphs.numGlyphs; + currentItem->glyphs = m_glyphPool; + currentItem->glyphPositions = m_positionPool; + currentItem->color = state->pen().color(); + + QTransform matrix = state->transform(); + matrix.translate(position.x(), position.y()); + + QVarLengthArray<glyph_t> glyphs; + QVarLengthArray<QFixedPoint> positions; + ti.fontEngine->getGlyphPositions(ti.glyphs, matrix, ti.flags, glyphs, positions); + + int size = glyphs.size(); + Q_ASSERT(size == ti.glyphs.numGlyphs); + Q_ASSERT(size == positions.size()); + + memmove(currentItem->glyphs, glyphs.constData(), sizeof(glyph_t) * size); + memmove(currentItem->glyphPositions, positions.constData(), sizeof(QFixedPoint) * size); + + m_glyphPool += size; + m_positionPool += size; + } + + + virtual bool begin(QPaintDevice *) { return true; } + virtual bool end() { return true; } + virtual void updateState(const QPaintEngineState &) {} + virtual void drawPixmap(const QRectF &, const QPixmap &, const QRectF &) {} + virtual Type type() const + { + return User; + } + + int itemCount() const + { + return m_itemCount; + } + + int glyphCount() const + { + return m_glyphCount; + } + + private: + QStaticTextItem *m_items; + int m_itemCount; + int m_glyphCount; + int m_expectedItemCount; + int m_expectedGlyphCount; + + glyph_t *m_glyphPool; + QFixedPoint *m_positionPool; + }; + + class DrawTextItemDevice: public QPaintDevice + { + public: + DrawTextItemDevice(int expectedItemCount = -1, QStaticTextItem *items = 0, + int expectedGlyphCount = -1, QFixedPoint *positionPool = 0, + glyph_t *glyphPool = 0) + { + m_paintEngine = new DrawTextItemRecorder(expectedItemCount, items, + expectedGlyphCount, positionPool, glyphPool); + } + + ~DrawTextItemDevice() + { + delete m_paintEngine; + } + + int metric(PaintDeviceMetric m) const + { + int val; + switch (m) { + case PdmWidth: + case PdmHeight: + case PdmWidthMM: + case PdmHeightMM: + val = 0; + break; + case PdmDpiX: + case PdmPhysicalDpiX: + val = qt_defaultDpiX(); + break; + case PdmDpiY: + case PdmPhysicalDpiY: + val = qt_defaultDpiY(); + break; + case PdmNumColors: + val = 16777216; + break; + case PdmDepth: + val = 24; + break; + default: + val = 0; + qWarning("DrawTextItemDevice::metric: Invalid metric command"); + } + return val; + } + + virtual QPaintEngine *paintEngine() const + { + return m_paintEngine; + } + + int itemCount() const + { + return m_paintEngine->itemCount(); + } + + int glyphCount() const + { + return m_paintEngine->glyphCount(); + } + + private: + DrawTextItemRecorder *m_paintEngine; + }; +} + +void QStaticTextPrivate::paintText(const QPointF &pos, QPainter *p) +{ + bool preferRichText = textFormat == Qt::RichText + || (textFormat == Qt::AutoText && Qt::mightBeRichText(text)); + + if (!preferRichText) { + if (maximumSize.isValid()) { + QRectF boundingRect; + p->drawText(QRectF(pos, maximumSize), Qt::TextWordWrap, text, &boundingRect); + + actualSize = boundingRect.size(); + needsClipRect = boundingRect.width() > maximumSize.width() + || boundingRect.height() > maximumSize.height(); + } else { + p->drawText(pos, text); + needsClipRect = false; + + QFontMetrics fm(font); + actualSize = fm.boundingRect(text).size(); + } + } else { + QTextDocument document; + document.setDefaultFont(font); + document.setHtml(text); + + QRectF rect = maximumSize.isValid() ? QRectF(pos, maximumSize) : QRectF(); + document.adjustSize(); + p->save(); + p->translate(pos); + document.drawContents(p, rect); + p->restore(); + actualSize = document.size(); + needsClipRect = maximumSize.isValid() + && (actualSize.width() > maximumSize.width() + || actualSize.height() > maximumSize.height()); + } +} + +void QStaticTextPrivate::init() +{ + delete[] items; + delete[] glyphPool; + delete[] positionPool; + + position = QPointF(0, 0); + + // Draw once to count number of items and glyphs, so that we can use as little memory + // as possible to store the data + DrawTextItemDevice counterDevice; + { + QPainter painter(&counterDevice); + painter.setFont(font); + painter.setTransform(matrix); + + paintText(QPointF(0, 0), &painter); + + } + + itemCount = counterDevice.itemCount(); + items = new QStaticTextItem[itemCount]; + + if (useBackendOptimizations) { + for (int i=0; i<itemCount; ++i) + items[i].useBackendOptimizations = true; + } + + + int glyphCount = counterDevice.glyphCount(); + glyphPool = new glyph_t[glyphCount]; + positionPool = new QFixedPoint[glyphCount]; + + // Draw again to actually record the items and glyphs + DrawTextItemDevice recorderDevice(itemCount, items, glyphCount, positionPool, glyphPool); + { + QPainter painter(&recorderDevice); + painter.setFont(font); + painter.setTransform(matrix); + + paintText(QPointF(0, 0), &painter); + } + +} + +QT_END_NAMESPACE diff --git a/src/gui/text/qstatictext.h b/src/gui/text/qstatictext.h new file mode 100644 index 0000000..00d42e0 --- /dev/null +++ b/src/gui/text/qstatictext.h @@ -0,0 +1,106 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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$ +** +****************************************************************************/ + +#ifndef QSTATICTEXT_H +#define QSTATICTEXT_H + +#include <QtCore/qsize.h> +#include <QtCore/qstring.h> +#include <QtCore/qmetatype.h> + +#include <QtGui/qtransform.h> +#include <QtGui/qfont.h> + + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Gui) + +class QStaticTextPrivate; +class Q_GUI_EXPORT QStaticText +{ +public: + enum PerformanceHint { + ModerateCaching, + AggressiveCaching + }; + + QStaticText(); + QStaticText(const QString &text, const QSizeF &maximumSize = QSizeF()); + QStaticText(const QStaticText &other); + ~QStaticText(); + + void setText(const QString &text); + QString text() const; + + void setTextFormat(Qt::TextFormat textFormat); + Qt::TextFormat textFormat() const; + + void setMaximumSize(const QSizeF &maximumSize); + QSizeF maximumSize() const; + + QSizeF size() const; + + void prepare(const QTransform &matrix, const QFont &font); + + void setPerformanceHint(PerformanceHint performanceHint); + PerformanceHint performanceHint() const; + + QStaticText &operator=(const QStaticText &); + bool operator==(const QStaticText &) const; + bool operator!=(const QStaticText &) const; + +private: + void detach(); + + QExplicitlySharedDataPointer<QStaticTextPrivate> data; + friend class QStaticTextPrivate; +}; + +QT_END_NAMESPACE + +Q_DECLARE_METATYPE(QStaticText) + +QT_END_HEADER + +#endif // QSTATICTEXT_H diff --git a/src/gui/text/qstatictext_p.h b/src/gui/text/qstatictext_p.h new file mode 100644 index 0000000..e758244 --- /dev/null +++ b/src/gui/text/qstatictext_p.h @@ -0,0 +1,146 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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$ +** +****************************************************************************/ + +#ifndef QSTATICTEXT_P_H +#define QSTATICTEXT_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of internal files. This header file may change from version to version +// without notice, or even be removed. +// +// We mean it. +// + +#include <private/qtextureglyphcache_p.h> +#include <QtGui/qcolor.h> + +QT_BEGIN_NAMESPACE + +class QStaticTextUserData +{ +public: + enum Type { + NoUserData, + OpenGLUserData + }; + + QStaticTextUserData(Type t) : type(t) {} + virtual ~QStaticTextUserData() {} + + Type type; +}; + +class Q_GUI_EXPORT QStaticTextItem +{ +public: + QStaticTextItem() : chars(0), numChars(0), fontEngine(0), userData(0), + useBackendOptimizations(false), userDataNeedsUpdate(0) {} + ~QStaticTextItem() { delete userData; } + + void setUserData(QStaticTextUserData *newUserData) + { + if (userData == newUserData) + return; + + delete userData; + userData = newUserData; + } + + QFixedPoint *glyphPositions; // 8 bytes per glyph + glyph_t *glyphs; // 4 bytes per glyph + const QChar *chars; // 2 bytes per glyph + // ================= + // 14 bytes per glyph + + // 12 bytes for pointers + int numGlyphs; // 4 bytes per item + int numChars; // 4 bytes per item + QFontEngine *fontEngine; // 4 bytes per item + QFont font; // 8 bytes per item + QColor color; // 10 bytes per item + QStaticTextUserData *userData; // 8 bytes per item + char useBackendOptimizations : 1; // 1 byte per item + char userDataNeedsUpdate : 1; // + // ================ + // 51 bytes per item +}; + +class QStaticText; +class Q_AUTOTEST_EXPORT QStaticTextPrivate +{ +public: + QStaticTextPrivate(); + QStaticTextPrivate(const QStaticTextPrivate &other); + ~QStaticTextPrivate(); + + void init(); + void paintText(const QPointF &pos, QPainter *p); + + QAtomicInt ref; // 4 bytes per text + + QString text; // 4 bytes per text + QFont font; // 8 bytes per text + QSizeF maximumSize; // 16 bytes per text + QSizeF actualSize; // 16 bytes per text + QPointF position; // 16 bytes per text + + QTransform matrix; // 80 bytes per text + QStaticTextItem *items; // 4 bytes per text + int itemCount; // 4 bytes per text + glyph_t *glyphPool; // 4 bytes per text + QFixedPoint *positionPool; // 4 bytes per text + + unsigned char needsClipRect : 1; // 1 byte per text + unsigned char useBackendOptimizations : 1; + unsigned char textFormat : 2; + // ================ + // 171 bytes per text + + static QStaticTextPrivate *get(const QStaticText *q); +}; + +QT_END_NAMESPACE + +#endif // QSTATICTEXT_P_H diff --git a/src/gui/text/qtextcontrol.cpp b/src/gui/text/qtextcontrol.cpp index aaaa3ca..f345cd1 100644 --- a/src/gui/text/qtextcontrol.cpp +++ b/src/gui/text/qtextcontrol.cpp @@ -441,7 +441,6 @@ void QTextControlPrivate::setContent(Qt::TextFormat format, const QString &text, QObject::connect(doc, SIGNAL(documentLayoutChanged()), q, SLOT(_q_documentLayoutChanged())); // convenience signal forwards - QObject::connect(doc, SIGNAL(contentsChanged()), q, SIGNAL(textChanged())); QObject::connect(doc, SIGNAL(undoAvailable(bool)), q, SIGNAL(undoAvailable(bool))); QObject::connect(doc, SIGNAL(redoAvailable(bool)), q, SIGNAL(redoAvailable(bool))); QObject::connect(doc, SIGNAL(modificationChanged(bool)), q, SIGNAL(modificationChanged(bool))); @@ -452,8 +451,11 @@ void QTextControlPrivate::setContent(Qt::TextFormat format, const QString &text, if (!document) doc->setUndoRedoEnabled(false); + //Saving the index save some time. + static int contentsChangedIndex = QTextDocument::staticMetaObject.indexOfSignal("contentsChanged()"); + static int textChangedIndex = QTextControl::staticMetaObject.indexOfSignal("textChanged()"); // avoid multiple textChanged() signals being emitted - QObject::disconnect(doc, SIGNAL(contentsChanged()), q, SIGNAL(textChanged())); + QMetaObject::disconnect(doc, contentsChangedIndex, q, textChangedIndex); if (!text.isEmpty()) { // clear 'our' cursor for insertion to prevent @@ -488,7 +490,7 @@ void QTextControlPrivate::setContent(Qt::TextFormat format, const QString &text, } cursor.setCharFormat(charFormatForInsertion); - QObject::connect(doc, SIGNAL(contentsChanged()), q, SIGNAL(textChanged())); + QMetaObject::connect(doc, contentsChangedIndex, q, textChangedIndex); emit q->textChanged(); if (!document) doc->setUndoRedoEnabled(previousUndoRedoState); @@ -1762,8 +1764,8 @@ void QTextControlPrivate::contextMenuEvent(const QPoint &screenPos, const QPoint QMenu *menu = q->createStandardContextMenu(docPos, contextWidget); if (!menu) return; - menu->exec(screenPos); - delete menu; + menu->setAttribute(Qt::WA_DeleteOnClose); + menu->popup(screenPos); #endif } diff --git a/src/gui/text/qtextcursor.cpp b/src/gui/text/qtextcursor.cpp index c81d538..c91df3c 100644 --- a/src/gui/text/qtextcursor.cpp +++ b/src/gui/text/qtextcursor.cpp @@ -1145,7 +1145,7 @@ void QTextCursor::setPosition(int pos, MoveMode m) Returns the absolute position of the cursor within the document. The cursor is positioned between characters. - \sa setPosition() movePosition() anchor() + \sa setPosition() movePosition() anchor() positionInBlock() */ int QTextCursor::position() const { @@ -1155,6 +1155,22 @@ int QTextCursor::position() const } /*! + \since 4.7 + Returns the relative position of the cursor within the block. + The cursor is positioned between characters. + + This is equivalent to \c{ position() - block().position()}. + + \sa position() +*/ +int QTextCursor::positionInBlock() const +{ + if (!d || !d->priv) + return 0; + return d->position - d->block().position(); +} + +/*! Returns the anchor position; this is the same as position() unless there is a selection in which case position() marks one end of the selection and anchor() marks the other end. Just like the cursor @@ -2414,9 +2430,17 @@ int QTextCursor::blockNumber() const return d->block().blockNumber(); } + /*! \since 4.2 Returns the position of the cursor within its containing line. + + Note that this is the column number relative to a wrapped line, + not relative to the block (i.e. the paragraph). + + You probably want to call positionInBlock() instead. + + \sa positionInBlock() */ int QTextCursor::columnNumber() const { diff --git a/src/gui/text/qtextcursor.h b/src/gui/text/qtextcursor.h index 38bc39d..3e968a3 100644 --- a/src/gui/text/qtextcursor.h +++ b/src/gui/text/qtextcursor.h @@ -89,6 +89,7 @@ public: void setPosition(int pos, MoveMode mode = MoveAnchor); int position() const; + int positionInBlock() const; int anchor() const; diff --git a/src/gui/text/qtextdocument.cpp b/src/gui/text/qtextdocument.cpp index 21f3189..9a1b70c 100644 --- a/src/gui/text/qtextdocument.cpp +++ b/src/gui/text/qtextdocument.cpp @@ -61,6 +61,7 @@ #include <qapplication.h> #include "qtextcontrol_p.h" #include "private/qtextedit_p.h" +#include "private/qdataurl_p.h" #include "qtextdocument_p.h" #include <private/qprinter_p.h> @@ -434,6 +435,30 @@ void QTextDocument::redo(QTextCursor *cursor) } } +/*! \enum QTextDocument::Stacks + + \value UndoStack The undo stack. + \value RedoStack The redo stack. + \value UndoAndRedoStacks Both the undo and redo stacks. +*/ + +/*! + \since 4.7 + Clears the stacks specified by \a stacksToClear. + + This method clears any commands on the undo stack, the redo stack, + or both (the default). If commands are cleared, the appropriate + signals are emitted, QTextDocument::undoAvailable() or + QTextDocument::redoAvailable(). + + \sa QTextDocument::undoAvailable() QTextDocument::redoAvailable() +*/ +void QTextDocument::clearUndoRedoStacks(Stacks stacksToClear) +{ + Q_D(QTextDocument); + d->clearUndoRedoStacks(stacksToClear, true); +} + /*! \overload @@ -1749,9 +1774,9 @@ void QTextDocument::print(QPrinter *printer) const int pageCopies; if (printer->collateCopies() == true){ docCopies = 1; - pageCopies = printer->numCopies(); + pageCopies = printer->supportsMultipleCopies() ? 1 : printer->copyCount(); } else { - docCopies = printer->numCopies(); + docCopies = printer->supportsMultipleCopies() ? 1 : printer->copyCount(); pageCopies = 1; } @@ -1924,6 +1949,10 @@ QVariant QTextDocument::loadResource(int type, const QUrl &name) } #endif + // handle data: URLs + if (r.isNull() && name.scheme() == QLatin1String("data")) + r = qDecodeDataUrl(name).second; + // if resource was not loaded try to load it here if (!doc && r.isNull() && name.isRelative()) { QUrl currentURL = d->url; diff --git a/src/gui/text/qtextdocument.h b/src/gui/text/qtextdocument.h index b5bcb41..0140772 100644 --- a/src/gui/text/qtextdocument.h +++ b/src/gui/text/qtextdocument.h @@ -256,6 +256,13 @@ public: void undo(QTextCursor *cursor); void redo(QTextCursor *cursor); + enum Stacks { + UndoStack = 0x01, + RedoStack = 0x02, + UndoAndRedoStacks = UndoStack | RedoStack + }; + void clearUndoRedoStacks(Stacks historyToClear = UndoAndRedoStacks); + int maximumBlockCount() const; void setMaximumBlockCount(int maximum); diff --git a/src/gui/text/qtextdocument_p.cpp b/src/gui/text/qtextdocument_p.cpp index 372b9dc..969d5b4 100644 --- a/src/gui/text/qtextdocument_p.cpp +++ b/src/gui/text/qtextdocument_p.cpp @@ -259,8 +259,7 @@ void QTextDocumentPrivate::clear() objects.clear(); title.clear(); - undoState = 0; - truncateUndoStack(); + clearUndoRedoStacks(QTextDocument::UndoAndRedoStacks); text = QString(); unreachableCharacterCount = 0; modifiedState = 0; @@ -292,7 +291,7 @@ QTextDocumentPrivate::~QTextDocumentPrivate() cursors.clear(); undoState = 0; undoEnabled = true; - truncateUndoStack(); + clearUndoRedoStacks(QTextDocument::RedoStack); } void QTextDocumentPrivate::setLayout(QAbstractTextDocumentLayout *layout) @@ -1027,7 +1026,7 @@ void QTextDocumentPrivate::appendUndoItem(const QTextUndoCommand &c) if (!undoEnabled) return; if (undoState < undoStack.size()) - truncateUndoStack(); + clearUndoRedoStacks(QTextDocument::RedoStack); if (!undoStack.isEmpty() && modified) { QTextUndoCommand &last = undoStack[undoState - 1]; @@ -1050,26 +1049,46 @@ void QTextDocumentPrivate::appendUndoItem(const QTextUndoCommand &c) emit document()->undoCommandAdded(); } -void QTextDocumentPrivate::truncateUndoStack() +void QTextDocumentPrivate::clearUndoRedoStacks(QTextDocument::Stacks stacksToClear, + bool emitSignals) { - if (undoState == undoStack.size()) - return; - - for (int i = undoState; i < undoStack.size(); ++i) { - QTextUndoCommand c = undoStack[i]; - if (c.command & QTextUndoCommand::Removed) { - // ######## -// QTextFragment *f = c.fragment_list; -// while (f) { -// QTextFragment *n = f->right; -// delete f; -// f = n; -// } - } else if (c.command & QTextUndoCommand::Custom) { - delete c.custom; + bool undoCommandsAvailable = undoState != 0; + bool redoCommandsAvailable = undoState != undoStack.size(); + if (stacksToClear == QTextDocument::UndoStack && undoCommandsAvailable) { + for (int i = 0; i < undoState; ++i) { + QTextUndoCommand c = undoStack[undoState]; + if (c.command & QTextUndoCommand::Custom) + delete c.custom; } + undoStack.remove(0, undoState); + undoStack.resize(undoStack.size() - undoState); + undoState = 0; + if (emitSignals) + emitUndoAvailable(false); + } else if (stacksToClear == QTextDocument::RedoStack + && redoCommandsAvailable) { + for (int i = undoState; i < undoStack.size(); ++i) { + QTextUndoCommand c = undoStack[i]; + if (c.command & QTextUndoCommand::Custom) + delete c.custom; + } + undoStack.resize(undoState); + if (emitSignals) + emitRedoAvailable(false); + } else if (stacksToClear == QTextDocument::UndoAndRedoStacks + && !undoStack.isEmpty()) { + for (int i = 0; i < undoStack.size(); ++i) { + QTextUndoCommand c = undoStack[i]; + if (c.command & QTextUndoCommand::Custom) + delete c.custom; + } + undoState = 0; + undoStack.resize(0); + if (emitSignals && undoCommandsAvailable) + emitUndoAvailable(false); + if (emitSignals && redoCommandsAvailable) + emitRedoAvailable(false); } - undoStack.resize(undoState); } void QTextDocumentPrivate::emitUndoAvailable(bool available) @@ -1097,7 +1116,7 @@ void QTextDocumentPrivate::enableUndoRedo(bool enable) if (!enable) { undoState = 0; - truncateUndoStack(); + clearUndoRedoStacks(QTextDocument::RedoStack); emitUndoAvailable(false); emitRedoAvailable(false); } diff --git a/src/gui/text/qtextdocument_p.h b/src/gui/text/qtextdocument_p.h index 4ecc2fa..ac5ed3c 100644 --- a/src/gui/text/qtextdocument_p.h +++ b/src/gui/text/qtextdocument_p.h @@ -252,10 +252,11 @@ public: inline QFont defaultFont() const { return formats.defaultFont(); } inline void setDefaultFont(const QFont &f) { formats.setDefaultFont(f); } + void clearUndoRedoStacks(QTextDocument::Stacks stacksToClear, bool emitSignals = false); + private: bool split(int pos); bool unite(uint f); - void truncateUndoStack(); void insert_string(int pos, uint strPos, uint length, int format, QTextUndoCommand::Operation op); int insert_block(int pos, uint strPos, int format, int blockformat, QTextUndoCommand::Operation op, int command); diff --git a/src/gui/text/qzipreader_p.h b/src/gui/text/qzipreader_p.h index 67a2ace..9b73373 100644 --- a/src/gui/text/qzipreader_p.h +++ b/src/gui/text/qzipreader_p.h @@ -62,7 +62,7 @@ QT_BEGIN_NAMESPACE class QZipReaderPrivate; -class Q_AUTOTEST_EXPORT QZipReader +class Q_GUI_EXPORT QZipReader { public: QZipReader(const QString &fileName, QIODevice::OpenMode mode = QIODevice::ReadOnly ); @@ -73,7 +73,7 @@ public: bool isReadable() const; bool exists() const; - struct Q_AUTOTEST_EXPORT FileInfo + struct Q_GUI_EXPORT FileInfo { FileInfo(); FileInfo(const FileInfo &other); diff --git a/src/gui/text/text.pri b/src/gui/text/text.pri index b7615a4..9ec3142 100644 --- a/src/gui/text/text.pri +++ b/src/gui/text/text.pri @@ -37,7 +37,9 @@ HEADERS += \ text/qtexttable_p.h \ text/qzipreader_p.h \ text/qzipwriter_p.h \ - text/qtextodfwriter_p.h + text/qtextodfwriter_p.h \ + text/qstatictext_p.h \ + text/qstatictext.h SOURCES += \ text/qfont.cpp \ @@ -66,7 +68,8 @@ SOURCES += \ text/qsyntaxhighlighter.cpp \ text/qcssparser.cpp \ text/qzip.cpp \ - text/qtextodfwriter.cpp + text/qtextodfwriter.cpp \ + text/qstatictext.cpp win32 { SOURCES += \ diff --git a/src/gui/util/qcompleter.cpp b/src/gui/util/qcompleter.cpp index cefdb27..b7be967 100644 --- a/src/gui/util/qcompleter.cpp +++ b/src/gui/util/qcompleter.cpp @@ -62,7 +62,7 @@ \snippet doc/src/snippets/code/src_gui_util_qcompleter.cpp 0 - A QDirModel can be used to provide auto completion of file names. + A QFileSystemModel can be used to provide auto completion of file names. For example: \snippet doc/src/snippets/code/src_gui_util_qcompleter.cpp 1 @@ -120,7 +120,7 @@ completion is then performed one level at a time. Let's take the example of a user typing in a file system path. - The model is a (hierarchical) QDirModel. The completion + The model is a (hierarchical) QFileSystemModel. The completion occurs for every element in the path. For example, if the current text is \c C:\Wind, QCompleter might suggest \c Windows to complete the current path element. Similarly, if the current text @@ -130,12 +130,12 @@ split the path into a list of strings that are matched at each level. For \c C:\Windows\Sy, it needs to be split as "C:", "Windows" and "Sy". The default implementation of splitPath(), splits the completionPrefix - using QDir::separator() if the model is a QDirModel. + using QDir::separator() if the model is a QFileSystemModel. To provide completions, QCompleter needs to know the path from an index. This is provided by pathFromIndex(). The default implementation of pathFromIndex(), returns the data for the \l{Qt::EditRole}{edit role} - for list models and the absolute file path if the mode is a QDirModel. + for list models and the absolute file path if the mode is a QFileSystemModel. \sa QAbstractItemModel, QLineEdit, QComboBox, {Completer Example} */ @@ -147,6 +147,7 @@ #include "QtGui/qscrollbar.h" #include "QtGui/qstringlistmodel.h" #include "QtGui/qdirmodel.h" +#include "QtGui/qfilesystemmodel.h" #include "QtGui/qheaderview.h" #include "QtGui/qlistview.h" #include "QtGui/qapplication.h" @@ -470,9 +471,13 @@ QMatchData QCompletionEngine::filterHistory() QAbstractItemModel *source = c->proxy->sourceModel(); if (curParts.count() <= 1 || c->proxy->showAll || !source) return QMatchData(); - bool dirModel = false; + bool isDirModel = false; + bool isFsModel = false; #ifndef QT_NO_DIRMODEL - dirModel = (qobject_cast<QDirModel *>(source) != 0); + isDirModel = (qobject_cast<QDirModel *>(source) != 0); +#endif +#ifndef QT_NO_FILESYSTEMMODEL + isFsModel = (qobject_cast<QFileSystemModel *>(source) != 0); #endif QVector<int> v; QIndexMapper im(v); @@ -482,7 +487,7 @@ QMatchData QCompletionEngine::filterHistory() QString str = source->index(i, c->column).data().toString(); if (str.startsWith(c->prefix, c->cs) #if (!defined(Q_OS_WIN) || defined(Q_OS_WINCE)) && !defined(Q_OS_SYMBIAN) - && (!dirModel || QDir::toNativeSeparators(str) != QDir::separator()) + && ((!isFsModel && !isDirModel) || QDir::toNativeSeparators(str) != QDir::separator()) #endif ) m.indices.append(i); @@ -838,6 +843,13 @@ void QCompleterPrivate::_q_complete(QModelIndex index, bool highlighted) completion += QDir::separator(); } #endif +#ifndef QT_NO_FILESYSTEMMODEL + // add a trailing separator in inline + if (mode == QCompleter::InlineCompletion) { + if (qobject_cast<QFileSystemModel *>(proxy->sourceModel()) && QFileInfo(completion).isDir()) + completion += QDir::separator(); + } +#endif } if (highlighted) { @@ -891,6 +903,14 @@ void QCompleterPrivate::showPopup(const QRect& rect) popup->show(); } +void QCompleterPrivate::_q_fileSystemModelDirectoryLoaded(const QString &path) +{ + Q_Q(QCompleter); + //the path given by QFileSystemModel does not end with / + if (q->completionPrefix() != path + QLatin1Char('/')) + q->complete(); +} + /*! Constructs a completer object with the given \a parent. */ @@ -971,7 +991,7 @@ QWidget *QCompleter::widget() const be list model or a tree model. If a model has been already previously set and it has the QCompleter as its parent, it is deleted. - For convenience, if \a model is a QDirModel, QCompleter switches its + For convenience, if \a model is a QFileSystemModel, QCompleter switches its caseSensitivity to Qt::CaseInsensitive on Windows and Qt::CaseSensitive on other platforms. @@ -995,6 +1015,18 @@ void QCompleter::setModel(QAbstractItemModel *model) #endif } #endif // QT_NO_DIRMODEL +#ifndef QT_NO_FILESYSTEMMODEL + QFileSystemModel *fsModel = qobject_cast<QFileSystemModel *>(model); + if (fsModel) { +#if (defined(Q_OS_WIN) && !defined(Q_OS_WINCE)) || defined(Q_OS_SYMBIAN) + setCaseSensitivity(Qt::CaseInsensitive); +#else + setCaseSensitivity(Qt::CaseSensitive); +#endif + setCompletionRole(QFileSystemModel::FileNameRole); + connect(fsModel, SIGNAL(directoryLoaded(QString)), this, SLOT(_q_fileSystemModelDirectoryLoaded(QString))); + } +#endif // QT_NO_FILESYSTEMMODEL } /*! @@ -1626,10 +1658,11 @@ QAbstractItemModel *QCompleter::completionModel() const The default implementation returns the \l{Qt::EditRole}{edit role} of the item for list models. It returns the absolute file path if the model is a - QDirModel. + QFileSystemModel. \sa splitPath() */ + QString QCompleter::pathFromIndex(const QModelIndex& index) const { Q_D(const QCompleter); @@ -1639,16 +1672,25 @@ QString QCompleter::pathFromIndex(const QModelIndex& index) const QAbstractItemModel *sourceModel = d->proxy->sourceModel(); if (!sourceModel) return QString(); + bool isDirModel = false; + bool isFsModel = false; #ifndef QT_NO_DIRMODEL - QDirModel *dirModel = qobject_cast<QDirModel *>(sourceModel); - if (!dirModel) + isDirModel = qobject_cast<QDirModel *>(d->proxy->sourceModel()) != 0; +#endif +#ifndef QT_NO_FILESYSTEMMODEL + isFsModel = qobject_cast<QFileSystemModel *>(d->proxy->sourceModel()) != 0; #endif + if (!isDirModel && !isFsModel) return sourceModel->data(index, d->role).toString(); QModelIndex idx = index; QStringList list; do { - QString t = sourceModel->data(idx, Qt::EditRole).toString(); + QString t; + if (isDirModel) + t = sourceModel->data(idx, Qt::EditRole).toString(); + else + t = sourceModel->data(idx, QFileSystemModel::FileNameRole).toString(); list.prepend(t); QModelIndex parent = idx.parent(); idx = parent.sibling(parent.row(), index.column()); @@ -1668,7 +1710,7 @@ QString QCompleter::pathFromIndex(const QModelIndex& index) const in the model(). The default implementation of splitPath() splits a file system path based on - QDir::separator() when the sourceModel() is a QDirModel. + QDir::separator() when the sourceModel() is a QFileSystemModel. When used with list models, the first item in the returned list is used for matching. @@ -1678,12 +1720,19 @@ QString QCompleter::pathFromIndex(const QModelIndex& index) const QStringList QCompleter::splitPath(const QString& path) const { bool isDirModel = false; + bool isFsModel = false; #ifndef QT_NO_DIRMODEL Q_D(const QCompleter); isDirModel = qobject_cast<QDirModel *>(d->proxy->sourceModel()) != 0; #endif +#ifndef QT_NO_FILESYSTEMMODEL +#ifdef QT_NO_DIRMODEL + Q_D(const QCompleter); +#endif + isFsModel = qobject_cast<QFileSystemModel *>(d->proxy->sourceModel()) != 0; +#endif - if (!isDirModel || path.isEmpty()) + if ((!isDirModel && !isFsModel) || path.isEmpty()) return QStringList(completionPrefix()); QString pathCopy = QDir::toNativeSeparators(path); diff --git a/src/gui/util/qcompleter.h b/src/gui/util/qcompleter.h index 5123a40..0cef9be 100644 --- a/src/gui/util/qcompleter.h +++ b/src/gui/util/qcompleter.h @@ -159,6 +159,7 @@ private: Q_PRIVATE_SLOT(d_func(), void _q_complete(QModelIndex)) Q_PRIVATE_SLOT(d_func(), void _q_completionSelected(const QItemSelection&)) Q_PRIVATE_SLOT(d_func(), void _q_autoResizePopup()) + Q_PRIVATE_SLOT(d_func(), void _q_fileSystemModelDirectoryLoaded(const QString&)) }; #endif // QT_NO_COMPLETER diff --git a/src/gui/util/qcompleter_p.h b/src/gui/util/qcompleter_p.h index 44be4c0..8f00793 100644 --- a/src/gui/util/qcompleter_p.h +++ b/src/gui/util/qcompleter_p.h @@ -98,6 +98,7 @@ public: void _q_complete(QModelIndex, bool = false); void _q_completionSelected(const QItemSelection&); void _q_autoResizePopup(); + void _q_fileSystemModelDirectoryLoaded(const QString &path); void setCurrentIndex(QModelIndex, bool = true); }; diff --git a/src/gui/util/qdesktopservices_s60.cpp b/src/gui/util/qdesktopservices_s60.cpp index adc4fc1..65b998f 100644 --- a/src/gui/util/qdesktopservices_s60.cpp +++ b/src/gui/util/qdesktopservices_s60.cpp @@ -415,11 +415,11 @@ QString QDesktopServices::storageLocation(StandardLocation type) //return QDir::homePath(); break; break; case DataLocation: - CEikonEnv::Static()->FsSession().PrivatePath(path); + qt_s60GetRFs().PrivatePath(path); path.Insert(0, writableExeDrive().Name()); break; case CacheLocation: - CEikonEnv::Static()->FsSession().PrivatePath(path); + qt_s60GetRFs().PrivatePath(path); path.Insert(0, writableExeDrive().Name()); path.Append(KCacheSubDir); break; diff --git a/src/gui/util/qdesktopservices_win.cpp b/src/gui/util/qdesktopservices_win.cpp index 9f3b6e1..aab7e16 100644 --- a/src/gui/util/qdesktopservices_win.cpp +++ b/src/gui/util/qdesktopservices_win.cpp @@ -59,7 +59,7 @@ # endif #endif -#if defined(Q_CC_MINGW) && !defined(CSIDL_MYMUSIC) +#ifndef CSIDL_MYMUSIC #define CSIDL_MYMUSIC 13 #define CSIDL_MYVIDEO 14 #endif @@ -97,19 +97,19 @@ static bool launchWebBrowser(const QUrl &url) if (url.scheme() == QLatin1String("mailto")) { //Retrieve the commandline for the default mail client //the default key used below is the command line for the mailto: shell command - DWORD bufferSize = 2 * MAX_PATH; + DWORD bufferSize = sizeof(wchar_t) * MAX_PATH; long returnValue = -1; QString command; HKEY handle; LONG res; - wchar_t keyValue[2 * MAX_PATH] = {0}; + wchar_t keyValue[MAX_PATH] = {0}; QString keyName(QLatin1String("mailto")); //Check if user has set preference, otherwise use default. - res = RegOpenKeyExW(HKEY_CURRENT_USER, - L"Software\\Microsoft\\Windows\\Shell\\Associations\\UrlAssociations\\mailto\\UserChoice", - 0, KEY_READ, &handle); + res = RegOpenKeyEx(HKEY_CURRENT_USER, + L"Software\\Microsoft\\Windows\\Shell\\Associations\\UrlAssociations\\mailto\\UserChoice", + 0, KEY_READ, &handle); if (res == ERROR_SUCCESS) { returnValue = RegQueryValueEx(handle, L"Progid", 0, 0, reinterpret_cast<unsigned char*>(keyValue), &bufferSize); if (!returnValue) @@ -121,8 +121,8 @@ static bool launchWebBrowser(const QUrl &url) if (res != ERROR_SUCCESS) return false; - bufferSize = 2 * MAX_PATH; - returnValue = RegQueryValueExW(handle, L"", 0, 0, reinterpret_cast<unsigned char*>(keyValue), &bufferSize); + bufferSize = sizeof(wchar_t) * MAX_PATH; + returnValue = RegQueryValueEx(handle, L"", 0, 0, reinterpret_cast<unsigned char*>(keyValue), &bufferSize); if (!returnValue) command = QString::fromRawData((QChar*)keyValue, bufferSize); RegCloseKey(handle); diff --git a/src/gui/util/qsystemtrayicon_mac.mm b/src/gui/util/qsystemtrayicon_mac.mm index 0265a83..348657e 100644 --- a/src/gui/util/qsystemtrayicon_mac.mm +++ b/src/gui/util/qsystemtrayicon_mac.mm @@ -93,6 +93,7 @@ extern bool qt_mac_execute_apple_script(const QString &script, AEDesc *ret); //q extern void qtsystray_sendActivated(QSystemTrayIcon *i, int r); //qsystemtrayicon.cpp extern NSString *keySequenceToKeyEqivalent(const QKeySequence &accel); // qmenu_mac.mm extern NSUInteger keySequenceModifierMask(const QKeySequence &accel); // qmenu_mac.mm +extern Qt::MouseButton cocoaButton2QtButton(NSInteger buttonNum); QT_END_NAMESPACE QT_USE_NAMESPACE @@ -110,7 +111,7 @@ QT_USE_NAMESPACE -(QSystemTrayIcon*)icon; -(NSStatusItem*)item; -(QRectF)geometry; -- (void)triggerSelector:(id)sender; +- (void)triggerSelector:(id)sender button:(Qt::MouseButton)mouseButton; - (void)doubleClickSelector:(id)sender; @end @@ -121,7 +122,7 @@ QT_USE_NAMESPACE -(id)initWithParent:(QNSStatusItem*)myParent; -(QSystemTrayIcon*)icon; -(void)menuTrackingDone:(NSNotification*)notification; --(void)mousePressed:(NSEvent *)mouseEvent; +-(void)mousePressed:(NSEvent *)mouseEvent button:(Qt::MouseButton)mouseButton; @end @@ -333,12 +334,10 @@ QT_END_NAMESPACE [self setNeedsDisplay:YES]; } --(void)mousePressed:(NSEvent *)mouseEvent +-(void)mousePressed:(NSEvent *)mouseEvent button:(Qt::MouseButton)mouseButton { - int clickCount = [mouseEvent clickCount]; - down = !down; - if(!down && [self icon]->contextMenu()) - [self icon]->contextMenu()->hide(); + down = YES; + int clickCount = [mouseEvent clickCount]; [self setNeedsDisplay:YES]; #ifndef QT_MAC_USE_COCOA @@ -348,47 +347,52 @@ QT_END_NAMESPACE const short scale = hgt - 4; #endif - if( down && ![self icon]->icon().isNull() ) { + if (![self icon]->icon().isNull() ) { NSImage *nsaltimage = static_cast<NSImage *>(qt_mac_create_nsimage([self icon]->icon().pixmap(QSize(scale, scale), QIcon::Selected))); [self setImage: nsaltimage]; [nsaltimage release]; } - - if (down) - [parent triggerSelector:self]; - else if ((clickCount%2)) + if ((clickCount == 2)) { + [self menuTrackingDone:nil]; [parent doubleClickSelector:self]; - while (down) { - mouseEvent = [[self window] nextEventMatchingMask:NSLeftMouseDownMask | NSLeftMouseUpMask - | NSLeftMouseDraggedMask | NSRightMouseDownMask | NSRightMouseUpMask - | NSRightMouseDraggedMask]; - switch ([mouseEvent type]) { - case NSRightMouseDown: - case NSRightMouseUp: - case NSLeftMouseDown: - case NSLeftMouseUp: - [self menuTrackingDone:nil]; - break; - case NSRightMouseDragged: - case NSLeftMouseDragged: - default: - /* Ignore any other kind of event. */ - break; - } - }; + } else { + [parent triggerSelector:self button:mouseButton]; + } } -(void)mouseDown:(NSEvent *)mouseEvent { - [self mousePressed:mouseEvent]; + [self mousePressed:mouseEvent button:Qt::LeftButton]; +} + +-(void)mouseUp:(NSEvent *)mouseEvent +{ + Q_UNUSED(mouseEvent); + [self menuTrackingDone:nil]; } - (void)rightMouseDown:(NSEvent *)mouseEvent { - [self mousePressed:mouseEvent]; + [self mousePressed:mouseEvent button:Qt::RightButton]; +} + +-(void)rightMouseUp:(NSEvent *)mouseEvent +{ + Q_UNUSED(mouseEvent); + [self menuTrackingDone:nil]; } +- (void)otherMouseDown:(NSEvent *)mouseEvent +{ + [self mousePressed:mouseEvent button:cocoaButton2QtButton([mouseEvent buttonNumber])]; +} + +-(void)otherMouseUp:(NSEvent *)mouseEvent +{ + Q_UNUSED(mouseEvent); + [self menuTrackingDone:nil]; +} -(void)drawRect:(NSRect)rect { [[parent item] drawStatusBarBackgroundInRect:rect withHighlight:down]; @@ -433,45 +437,40 @@ QT_END_NAMESPACE } return QRectF(); } -- (void)triggerSelector:(id)sender { + +- (void)triggerSelector:(id)sender button:(Qt::MouseButton)mouseButton { Q_UNUSED(sender); - if(!icon) + if (!icon) return; - qtsystray_sendActivated(icon, QSystemTrayIcon::Trigger); + + if (mouseButton == Qt::MidButton) + qtsystray_sendActivated(icon, QSystemTrayIcon::MiddleClick); + else + qtsystray_sendActivated(icon, QSystemTrayIcon::Trigger); + if (icon->contextMenu()) { -#if 0 - const QRectF geom = [self geometry]; - if(!geom.isNull()) { - [[NSNotificationCenter defaultCenter] addObserver:imageCell - selector:@selector(menuTrackingDone:) - name:nil - object:self]; - icon->contextMenu()->exec(geom.topLeft().toPoint(), 0); - [imageCell menuTrackingDone:nil]; - } else -#endif - { #ifndef QT_MAC_USE_COCOA - [[[self item] view] removeAllToolTips]; - iconPrivate->updateToolTip_sys(); + [[[self item] view] removeAllToolTips]; + iconPrivate->updateToolTip_sys(); #endif - NSMenu *m = [[QNSMenu alloc] initWithQMenu:icon->contextMenu()]; - [m setAutoenablesItems: NO]; - [[NSNotificationCenter defaultCenter] addObserver:imageCell - selector:@selector(menuTrackingDone:) - name:NSMenuDidEndTrackingNotification - object:m]; - [item popUpStatusItemMenu: m]; - [m release]; - } + NSMenu *m = [[QNSMenu alloc] initWithQMenu:icon->contextMenu()]; + [m setAutoenablesItems: NO]; + [[NSNotificationCenter defaultCenter] addObserver:imageCell + selector:@selector(menuTrackingDone:) + name:NSMenuDidEndTrackingNotification + object:m]; + [item popUpStatusItemMenu: m]; + [m release]; } } + - (void)doubleClickSelector:(id)sender { Q_UNUSED(sender); if(!icon) return; qtsystray_sendActivated(icon, QSystemTrayIcon::DoubleClick); } + @end class QSystemTrayIconQMenu : public QMenu diff --git a/src/gui/util/qsystemtrayicon_win.cpp b/src/gui/util/qsystemtrayicon_win.cpp index 6db158e..8e482e0 100644 --- a/src/gui/util/qsystemtrayicon_win.cpp +++ b/src/gui/util/qsystemtrayicon_win.cpp @@ -53,7 +53,6 @@ #include <qt_windows.h> #include <commctrl.h> -#include <shlwapi.h> #include <QBitmap> #include <QLibrary> #include <QApplication> @@ -326,8 +325,6 @@ bool QSystemTrayIconSys::winEvent( MSG *m, long *result ) q->contextMenu()->move(gpos); } #endif - q->contextMenu()->activateWindow(); - //Must be activated for proper keyboardfocus and menu closing on windows: } emit q->activated(QSystemTrayIcon::Context); break; diff --git a/src/gui/widgets/qabstractscrollarea_p.h b/src/gui/widgets/qabstractscrollarea_p.h index 7c72859..9a0d66f 100644 --- a/src/gui/widgets/qabstractscrollarea_p.h +++ b/src/gui/widgets/qabstractscrollarea_p.h @@ -62,7 +62,7 @@ QT_BEGIN_NAMESPACE class QScrollBar; class QAbstractScrollAreaScrollBarContainer; -class Q_AUTOTEST_EXPORT QAbstractScrollAreaPrivate: public QFramePrivate +class Q_GUI_EXPORT QAbstractScrollAreaPrivate: public QFramePrivate { Q_DECLARE_PUBLIC(QAbstractScrollArea) diff --git a/src/gui/widgets/qcocoamenu_mac.mm b/src/gui/widgets/qcocoamenu_mac.mm index a7e0b79..ce85919 100644 --- a/src/gui/widgets/qcocoamenu_mac.mm +++ b/src/gui/widgets/qcocoamenu_mac.mm @@ -46,6 +46,7 @@ #import <private/qcocoamenuloader_mac_p.h> #include <private/qt_cocoa_helpers_mac_p.h> #include <private/qapplication_p.h> +#include <private/qaction_p.h> #include <QtGui/QMenu> @@ -70,6 +71,7 @@ QT_USE_NAMESPACE self = [super init]; if (self) { qmenu = menu; + previousAction = 0; [self setAutoenablesItems:NO]; [self setDelegate:self]; } @@ -81,13 +83,20 @@ QT_USE_NAMESPACE Q_UNUSED(menu); if (!item) { - // ### According to the docs everything will be highlighted. Not sure what we should do in - // Qt, so just return. + if (previousAction) { + qt_mac_clear_status_text(previousAction); + previousAction = 0; + } return; } - if (QAction *action = reinterpret_cast<QAction *>([item tag])) + if (QAction *action = reinterpret_cast<QAction *>([item tag])) { + QMenu *qtmenu = static_cast<QT_MANGLE_NAMESPACE(QCocoaMenu) *>(menu)->qmenu; + previousAction = action; action->activate(QAction::Hover); + qt_mac_menu_emit_hovered(qtmenu, action); + action->showStatusText(0); // 0 widget -> action's parent + } } - (void)menuWillOpen:(NSMenu*)menu; @@ -100,9 +109,13 @@ QT_USE_NAMESPACE qt_mac_menu_collapseSeparators(menu, qtmenu->separatorsCollapsible()); } -- (void)menuWillClose:(NSMenu*)menu; +- (void)menuDidClose:(NSMenu*)menu; { qt_mac_emit_menuSignals(((QT_MANGLE_NAMESPACE(QCocoaMenu) *)menu)->qmenu, false); + if (previousAction) { + qt_mac_clear_status_text(previousAction); + previousAction = 0; + } } - (BOOL)hasShortcut:(NSMenu *)menu forKey:(NSString *)key forModifiers:(NSUInteger)modifier @@ -194,6 +207,18 @@ void qt_mac_emit_menuSignals(QMenu *menu, bool show) } qt_mac_menus_open_count += delta; } + +void qt_mac_clear_status_text(QAction *action) +{ + action->d_func()->showStatusText(0, QString()); +} + +void qt_mac_menu_emit_hovered(QMenu *menu, QAction *action) +{ + emit menu->hovered(action); +} + + QT_END_NAMESPACE #endif diff --git a/src/gui/widgets/qcocoamenu_mac_p.h b/src/gui/widgets/qcocoamenu_mac_p.h index 9f50c40..d6ac8c5 100644 --- a/src/gui/widgets/qcocoamenu_mac_p.h +++ b/src/gui/widgets/qcocoamenu_mac_p.h @@ -55,13 +55,14 @@ #import <Cocoa/Cocoa.h> QT_FORWARD_DECLARE_CLASS(QMenu) +QT_FORWARD_DECLARE_CLASS(QAction) #if MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_5 @protocol NSMenuDelegate <NSObject> - (void)menu:(NSMenu*)menu willHighlightItem:(NSMenuItem*)item; - (void)menuWillOpen:(NSMenu*)menu; -- (void)menuWillClose:(NSMenu*)menu; +- (void)menuDidClose:(NSMenu*)menu; - (BOOL)hasShortcut:(NSMenu *)menu forKey:(NSString *)key forModifiers:(NSUInteger)modifier whichItem:(NSMenuItem**)outItem; @end @@ -71,6 +72,7 @@ QT_FORWARD_DECLARE_CLASS(QMenu) @interface QT_MANGLE_NAMESPACE(QCocoaMenu) : NSMenu <NSMenuDelegate> { QMenu *qmenu; + QAction *previousAction; } - (id)initWithQMenu:(QMenu*)menu; - (BOOL)menuHasKeyEquivalent:(NSMenu *)menu forEvent:(NSEvent *)event target:(id *)target action:(SEL *)action; diff --git a/src/gui/widgets/qcombobox.cpp b/src/gui/widgets/qcombobox.cpp index 585db70..f71d250 100644 --- a/src/gui/widgets/qcombobox.cpp +++ b/src/gui/widgets/qcombobox.cpp @@ -1274,7 +1274,8 @@ QComboBox::~QComboBox() By default, this property has a value of 10. - \note This property is ignored for non-editable comboboxes in Mac style. + \note This property is ignored for non-editable comboboxes in styles that returns + false for QStyle::SH_ComboBox_Popup such as the Mac style or the Gtk+ Style. */ int QComboBox::maxVisibleItems() const { @@ -2354,7 +2355,7 @@ void QComboBox::showPopup() toCheck.push(idx); #endif ++count; - if (!usePopup && count > d->maxVisibleItems) { + if (!usePopup && count >= d->maxVisibleItems) { toCheck.clear(); break; } diff --git a/src/gui/widgets/qdatetimeedit.cpp b/src/gui/widgets/qdatetimeedit.cpp index 762db86..50fa9c9 100644 --- a/src/gui/widgets/qdatetimeedit.cpp +++ b/src/gui/widgets/qdatetimeedit.cpp @@ -1175,7 +1175,7 @@ void QDateTimeEdit::keyPressEvent(QKeyEvent *event) return; } } QAbstractSpinBox::keyPressEvent(event); - if (select && !(event->modifiers() & Qt::ShiftModifier) && !d->edit->hasSelectedText()) { + if (select && !d->edit->hasSelectedText()) { if (inserted && d->sectionAt(d->edit->cursorPosition()) == QDateTimeParser::NoSectionIndex) { QString str = d->displayText(); int pos = d->edit->cursorPosition(); diff --git a/src/gui/widgets/qdialogbuttonbox.cpp b/src/gui/widgets/qdialogbuttonbox.cpp index 6a0e363..cc74a53 100644 --- a/src/gui/widgets/qdialogbuttonbox.cpp +++ b/src/gui/widgets/qdialogbuttonbox.cpp @@ -103,7 +103,7 @@ QT_BEGIN_NAMESPACE You can mix and match normal buttons and standard buttons. Currently the buttons are laid out in the following way if the button box is horizontal: - \table 100% + \table \row \o \inlineimage buttonbox-gnomelayout-horizontal.png GnomeLayout Horizontal \o Button box laid out in horizontal GnomeLayout \row \o \inlineimage buttonbox-kdelayout-horizontal.png KdeLayout Horizontal @@ -116,25 +116,23 @@ QT_BEGIN_NAMESPACE The buttons are laid out the following way if the button box is vertical: - \table 100% + \table + \row \o GnomeLayout + \o KdeLayout + \o MacLayout + \o WinLayout \row \o \inlineimage buttonbox-gnomelayout-vertical.png GnomeLayout Vertical - \o Button box laid out in vertical GnomeLayout - \row \o \inlineimage buttonbox-kdelayout-vertical.png KdeLayout Vertical - \o Button box laid out in vertical KdeLayout - \row \o \inlineimage buttonbox-maclayout-vertical.png MacLayout Vertical - \o Button box laid out in vertical MacLayout - \row \o \inlineimage buttonbox-winlayout-vertical.png WinLayout Vertical - \o Button box laid out in vertical WinLayout + \o \inlineimage buttonbox-kdelayout-vertical.png KdeLayout Vertical + \o \inlineimage buttonbox-maclayout-vertical.png MacLayout Vertical + \o \inlineimage buttonbox-winlayout-vertical.png WinLayout Vertical \endtable Additionally, button boxes that contain only buttons with ActionRole or - HelpRole can be considered modeless and have an alternate look on the mac: + HelpRole can be considered modeless and have an alternate look on Mac OS X: - \table 100% - \row \o \inlineimage buttonbox-mac-modeless-horizontal.png Screenshot of modeless horizontal MacLayout - \o modeless horizontal MacLayout - \row \o \inlineimage buttonbox-mac-modeless-vertical.png Screenshot of modeless vertical MacLayout - \o modeless vertical MacLayout + \table + \row \o modeless horizontal MacLayout + \o \inlineimage buttonbox-mac-modeless-horizontal.png Screenshot of modeless horizontal MacLayout \endtable When a button is clicked in the button box, the clicked() signal is emitted diff --git a/src/gui/widgets/qdockarealayout.cpp b/src/gui/widgets/qdockarealayout.cpp index 0c39f42..2b8cf59 100644 --- a/src/gui/widgets/qdockarealayout.cpp +++ b/src/gui/widgets/qdockarealayout.cpp @@ -220,15 +220,17 @@ static quintptr tabId(const QDockAreaLayoutItem &item) } #endif +static const int zero = 0; + QDockAreaLayoutInfo::QDockAreaLayoutInfo() - : sep(0), dockPos(QInternal::LeftDock), o(Qt::Horizontal), mainWindow(0) + : sep(&zero), dockPos(QInternal::LeftDock), o(Qt::Horizontal), mainWindow(0) #ifndef QT_NO_TABBAR , tabbed(false), tabBar(0), tabBarShape(QTabBar::RoundedSouth), tabBarVisible(false) #endif { } -QDockAreaLayoutInfo::QDockAreaLayoutInfo(int _sep, QInternal::DockPosition _dockPos, +QDockAreaLayoutInfo::QDockAreaLayoutInfo(const int *_sep, QInternal::DockPosition _dockPos, Qt::Orientation _o, int tbshape, QMainWindow *window) : sep(_sep), dockPos(_dockPos), o(_o), mainWindow(window) @@ -281,7 +283,7 @@ QSize QDockAreaLayoutInfo::minimumSize() const #endif { if (!first) - a += sep; + a += *sep; a += pick(o, min_size); } b = qMax(b, perp(o, min_size)); @@ -349,7 +351,7 @@ QSize QDockAreaLayoutInfo::maximumSize() const #endif { if (!first) - a += sep; + a += *sep; a += pick(o, max_size); } b = qMin(b, perp(o, max_size)); @@ -415,7 +417,7 @@ QSize QDockAreaLayoutInfo::sizeHint() const { if (previous && !gap && !(previous->flags & QDockAreaLayoutItem::GapItem) && !previous->hasFixedSize(o)) { - a += sep; + a += *sep; } a += gap ? item.size : pick(o, size_hint); } @@ -491,7 +493,7 @@ static int realMinSize(const QDockAreaLayoutInfo &info) min = pick(info.o, item.minimumSize()); if (!first) - result += info.sep; + result += *info.sep; result += min; first = false; @@ -516,7 +518,7 @@ static int realMaxSize(const QDockAreaLayoutInfo &info) max = pick(info.o, item.maximumSize()); if (!first) - result += info.sep; + result += *info.sep; result += max; if (result >= QWIDGETSIZE_MAX) @@ -555,7 +557,7 @@ void QDockAreaLayoutInfo::fitItems() if (!(previous->flags & QDockAreaLayoutItem::GapItem)) { QLayoutStruct &ls = layout_struct_list[j++]; ls.init(); - ls.minimumSize = ls.maximumSize = ls.sizeHint = previous->hasFixedSize(o) ? 0 : sep; + ls.minimumSize = ls.maximumSize = ls.sizeHint = previous->hasFixedSize(o) ? 0 : *sep; ls.empty = false; } } @@ -938,7 +940,7 @@ int QDockAreaLayoutInfo::separatorMove(int index, int delta) if (item.skip()) { ls.empty = true; } else { - const int separatorSpace = item.hasFixedSize(o) ? 0 : sep; + const int separatorSpace = item.hasFixedSize(o) ? 0 : *sep; ls.empty = false; ls.pos = item.pos; ls.size = item.size + separatorSpace; @@ -956,7 +958,7 @@ int QDockAreaLayoutInfo::separatorMove(int index, int delta) if (item.skip()) continue; QLayoutStruct &ls = list[i]; - const int separatorSpace = item.hasFixedSize(o) ? 0 : sep; + const int separatorSpace = item.hasFixedSize(o) ? 0 : *sep; item.size = ls.size - separatorSpace; item.pos = ls.pos; if (item.subinfo != 0) { @@ -1041,11 +1043,11 @@ QLayoutItem *QDockAreaLayoutInfo::plug(const QList<int> &path) int next = this->next(index); if (prev != -1 && !(item_list.at(prev).flags & QDockAreaLayoutItem::GapItem)) { - item.pos += sep; - item.size -= sep; + item.pos += *sep; + item.size -= *sep; } if (next != -1 && !(item_list.at(next).flags & QDockAreaLayoutItem::GapItem)) - item.size -= sep; + item.size -= *sep; QPoint pos; rpick(o, pos) = item.pos; @@ -1083,11 +1085,11 @@ QLayoutItem *QDockAreaLayoutInfo::unplug(const QList<int> &path) #endif { if (prev != -1 && !(item_list.at(prev).flags & QDockAreaLayoutItem::GapItem)) { - item.pos -= sep; - item.size += sep; + item.pos -= *sep; + item.size += *sep; } if (next != -1 && !(item_list.at(next).flags & QDockAreaLayoutItem::GapItem)) - item.size += sep; + item.size += *sep; } return item.widgetItem; @@ -1255,9 +1257,9 @@ bool QDockAreaLayoutInfo::insertGap(const QList<int> &path, QLayoutItem *dockWid QRect r = dockedGeometry(dockWidgetItem->widget()); gap_size = pick(o, r.size()); if (prev != -1 && !(item_list.at(prev).flags & QDockAreaLayoutItem::GapItem)) - sep_size += sep; + sep_size += *sep; if (next != -1 && !(item_list.at(next).flags & QDockAreaLayoutItem::GapItem)) - sep_size += sep; + sep_size += *sep; } if (gap_size + sep_size > space) gap_size = pick(o, gap_item.minimumSize()); @@ -1364,7 +1366,7 @@ QRect QDockAreaLayoutInfo::separatorRect(int index) const QPoint pos = rect.topLeft(); rpick(o, pos) = item.pos + item.size; QSize s = rect.size(); - rpick(o, s) = sep; + rpick(o, s) = *sep; return QRect(pos, s); } @@ -1413,7 +1415,7 @@ QList<int> QDockAreaLayoutInfo::findSeparator(const QPoint &_pos) const continue; QRect sepRect = separatorRect(i); - if (!sepRect.isNull() && sep == 1) + if (!sepRect.isNull() && *sep == 1) sepRect.adjust(-2, -2, 2, 2); //we also make sure we don't find a separator that's not there if (sepRect.contains(_pos) && !item.hasFixedSize(o)) { @@ -1560,7 +1562,7 @@ void QDockAreaLayoutInfo::apply(bool animate) } } #ifndef QT_NO_TABBAR - if (sep == 1) + if (*sep == 1) updateSeparatorWidgets(); #endif //QT_NO_TABBAR } @@ -2010,7 +2012,7 @@ bool QDockAreaLayoutInfo::restoreState(QDataStream &stream, QList<QDockWidget*> updateTabBar(); setCurrentTabId(tabId(item_list.at(index))); } - if (!testing && sep == 1) + if (!testing && *sep == 1) updateSeparatorWidgets(); #endif @@ -2273,13 +2275,13 @@ QDockAreaLayout::QDockAreaLayout(QMainWindow *win) : fallbackToSizeHints(true) const int tabShape = 0; #endif docks[QInternal::LeftDock] - = QDockAreaLayoutInfo(sep, QInternal::LeftDock, Qt::Vertical, tabShape, win); + = QDockAreaLayoutInfo(&sep, QInternal::LeftDock, Qt::Vertical, tabShape, win); docks[QInternal::RightDock] - = QDockAreaLayoutInfo(sep, QInternal::RightDock, Qt::Vertical, tabShape, win); + = QDockAreaLayoutInfo(&sep, QInternal::RightDock, Qt::Vertical, tabShape, win); docks[QInternal::TopDock] - = QDockAreaLayoutInfo(sep, QInternal::TopDock, Qt::Horizontal, tabShape, win); + = QDockAreaLayoutInfo(&sep, QInternal::TopDock, Qt::Horizontal, tabShape, win); docks[QInternal::BottomDock] - = QDockAreaLayoutInfo(sep, QInternal::BottomDock, Qt::Horizontal, tabShape, win); + = QDockAreaLayoutInfo(&sep, QInternal::BottomDock, Qt::Horizontal, tabShape, win); centralWidgetItem = 0; @@ -3028,7 +3030,7 @@ void QDockAreaLayout::addDockWidget(QInternal::DockPosition pos, QDockWidget *do #else int tbshape = 0; #endif - QDockAreaLayoutInfo new_info(sep, pos, orientation, tbshape, mainWindow); + QDockAreaLayoutInfo new_info(&sep, pos, orientation, tbshape, mainWindow); new_info.item_list.append(new QDockAreaLayoutInfo(info)); new_info.item_list.append(dockWidgetItem); info = new_info; @@ -3324,6 +3326,12 @@ void QDockAreaLayout::keepSize(QDockWidget *w) item.flags |= QDockAreaLayoutItem::KeepSize; } +void QDockAreaLayout::styleChangedEvent() +{ + sep = mainWindow->style()->pixelMetric(QStyle::PM_DockWidgetSeparatorExtent, 0, mainWindow); + fitLayout(); +} + QT_END_NAMESPACE #endif // QT_NO_DOCKWIDGET diff --git a/src/gui/widgets/qdockarealayout_p.h b/src/gui/widgets/qdockarealayout_p.h index 0bc1aa9..0088f00 100644 --- a/src/gui/widgets/qdockarealayout_p.h +++ b/src/gui/widgets/qdockarealayout_p.h @@ -128,7 +128,7 @@ class Q_AUTOTEST_EXPORT QDockAreaLayoutInfo { public: QDockAreaLayoutInfo(); - QDockAreaLayoutInfo(int _sep, QInternal::DockPosition _dockPos, Qt::Orientation _o, + QDockAreaLayoutInfo(const int *_sep, QInternal::DockPosition _dockPos, Qt::Orientation _o, int tbhape, QMainWindow *window); QSize minimumSize() const; @@ -189,7 +189,7 @@ public: QMainWindowLayout *mainWindowLayout() const; - int sep; + const int *sep; mutable QVector<QWidget*> separatorWidgets; QInternal::DockPosition dockPos; Qt::Orientation o; @@ -300,6 +300,7 @@ public: QSet<QTabBar*> usedTabBars() const; QSet<QWidget*> usedSeparatorWidgets() const; #endif //QT_NO_TABBAR + void styleChangedEvent(); }; QT_END_NAMESPACE diff --git a/src/gui/widgets/qdockwidget.cpp b/src/gui/widgets/qdockwidget.cpp index fdace46..54189de 100644 --- a/src/gui/widgets/qdockwidget.cpp +++ b/src/gui/widgets/qdockwidget.cpp @@ -1010,7 +1010,7 @@ void QDockWidgetPrivate::setWindowState(bool floating, bool unplug, const QRect if (!floating && parent) { QMainWindowLayout *mwlayout = qobject_cast<QMainWindowLayout *>(q->parentWidget()->layout()); - if (!mwlayout || mwlayout->dockWidgetArea(q) == Qt::NoDockWidgetArea) + if (mwlayout && mwlayout->dockWidgetArea(q) == Qt::NoDockWidgetArea) return; // this dockwidget can't be redocked } diff --git a/src/gui/widgets/qfocusframe.cpp b/src/gui/widgets/qfocusframe.cpp index d9cd5bb..4f20bce0 100644 --- a/src/gui/widgets/qfocusframe.cpp +++ b/src/gui/widgets/qfocusframe.cpp @@ -53,11 +53,14 @@ class QFocusFramePrivate : public QWidgetPrivate { Q_DECLARE_PUBLIC(QFocusFrame) QWidget *widget; - + QWidget *frameParent; + bool showFrameAboveWidget; public: QFocusFramePrivate() { widget = 0; + frameParent = 0; sendChildEvents = false; + showFrameAboveWidget = false; } void updateSize(); void update(); @@ -66,10 +69,10 @@ public: void QFocusFramePrivate::update() { Q_Q(QFocusFrame); - q->setParent(widget->parentWidget()); + q->setParent(frameParent); updateSize(); if (q->parentWidget()->rect().intersects(q->geometry())) { - if (q->style()->styleHint(QStyle::SH_FocusFrame_AboveWidget, 0, q)) + if (showFrameAboveWidget) q->raise(); else q->stackUnder(widget); @@ -84,7 +87,10 @@ void QFocusFramePrivate::updateSize() Q_Q(QFocusFrame); int vmargin = q->style()->pixelMetric(QStyle::PM_FocusFrameVMargin), hmargin = q->style()->pixelMetric(QStyle::PM_FocusFrameHMargin); - QRect geom(widget->x()-hmargin, widget->y()-vmargin, + QPoint pos(widget->x(), widget->y()); + if (q->parentWidget() != widget->parentWidget()) + pos = widget->parentWidget()->mapTo(q->parentWidget(), pos); + QRect geom(pos.x()-hmargin, pos.y()-vmargin, widget->width()+(hmargin*2), widget->height()+(vmargin*2)); if(q->geometry() == geom) return; @@ -176,14 +182,52 @@ void QFocusFrame::setWidget(QWidget *widget) { Q_D(QFocusFrame); - if(widget == d->widget) - return; - if(d->widget) - d->widget->removeEventFilter(this); - if(widget && !widget->isWindow() && widget->parentWidget()->windowType() != Qt::SubWindow) { + if (style()->styleHint(QStyle::SH_FocusFrame_AboveWidget, 0, this)) + d->showFrameAboveWidget = true; + else + d->showFrameAboveWidget = false; + + if (widget == d->widget) + return; + if (d->widget) { + // Remove event filters from the widget hierarchy. + QWidget *p = d->widget; + do { + p->removeEventFilter(this); + if (!d->showFrameAboveWidget || p == d->frameParent) + break; + p = p->parentWidget(); + }while (p); + } + if (widget && !widget->isWindow() && widget->parentWidget()->windowType() != Qt::SubWindow) { d->widget = widget; - widget->installEventFilter(this); + d->widget->installEventFilter(this); + QWidget *p = widget->parentWidget(); + QWidget *prev = 0; + if (d->showFrameAboveWidget) { + // Find the right parent for the focus frame. + while (p) { + // Traverse the hirerarchy of the 'widget' for setting event filter. + // During this if come across toolbar or a top level, use that + // as the parent for the focus frame. If we find a scroll area + // use its viewport as the parent. + bool isScrollArea = false; + if (p->isWindow() || p->inherits("QToolBar") || (isScrollArea = p->inherits("QAbstractScrollArea"))) { + d->frameParent = p; + // The previous one in the hierarchy will be the viewport. + if (prev && isScrollArea) + d->frameParent = prev; + break; + } else { + p->installEventFilter(this); + prev = p; + p = p->parentWidget(); + } + } + } else { + d->frameParent = p; + } d->update(); } else { d->widget = 0; @@ -210,9 +254,15 @@ QFocusFrame::widget() const void QFocusFrame::paintEvent(QPaintEvent *) { + Q_D(QFocusFrame); QStylePainter p(this); QStyleOption option; initStyleOption(&option); + int vmargin = style()->pixelMetric(QStyle::PM_FocusFrameVMargin); + int hmargin = style()->pixelMetric(QStyle::PM_FocusFrameHMargin); + QWidgetPrivate *wd = qt_widget_private(d->widget); + QRect rect = wd->clipRect().adjusted(0, 0, hmargin*2, vmargin*2); + p.setClipRect(rect); p.drawControl(QStyle::CE_FocusFrame, option); } @@ -233,7 +283,13 @@ QFocusFrame::eventFilter(QObject *o, QEvent *e) hide(); break; case QEvent::ParentChange: - d->update(); + if (d->showFrameAboveWidget) { + QWidget *w = d->widget; + setWidget(0); + setWidget(w); + } else { + d->update(); + } break; case QEvent::Show: d->update(); @@ -254,6 +310,19 @@ QFocusFrame::eventFilter(QObject *o, QEvent *e) default: break; } + } else if (d->showFrameAboveWidget) { + // Handle changes in the parent widgets we are monitoring. + switch(e->type()) { + case QEvent::Move: + case QEvent::Resize: + d->updateSize(); + break; + case QEvent::ZOrderChange: + raise(); + break; + default: + break; + } } return false; } diff --git a/src/gui/widgets/qlabel.cpp b/src/gui/widgets/qlabel.cpp index 8428ad7..b81f04f 100644 --- a/src/gui/widgets/qlabel.cpp +++ b/src/gui/widgets/qlabel.cpp @@ -781,6 +781,95 @@ Qt::TextInteractionFlags QLabel::textInteractionFlags() const return d->textInteractionFlags; } +/*! + Selects text from position \a start and for \a length characters. + + \sa selectedText() + + \bold{Note:} The textInteractionFlags set on the label need to include + either TextSelectableByMouse or TextSelectableByKeyboard. + + \since 4.7 +*/ +void QLabel::setSelection(int start, int length) +{ + Q_D(QLabel); + if (d->control) { + d->ensureTextPopulated(); + QTextCursor cursor = d->control->textCursor(); + cursor.setPosition(start); + cursor.setPosition(start + length, QTextCursor::KeepAnchor); + d->control->setTextCursor(cursor); + } +} + +/*! + \property QLabel::hasSelectedText + \brief whether there is any text selected + + hasSelectedText() returns true if some or all of the text has been + selected by the user; otherwise returns false. + + By default, this property is false. + + \sa selectedText() + + \bold{Note:} The textInteractionFlags set on the label need to include + either TextSelectableByMouse or TextSelectableByKeyboard. + + \since 4.7 +*/ +bool QLabel::hasSelectedText() const +{ + Q_D(const QLabel); + if (d->control) + return d->control->textCursor().hasSelection(); + return false; +} + +/*! + \property QLabel::selectedText + \brief the selected text + + If there is no selected text this property's value is + an empty string. + + By default, this property contains an empty string. + + \sa hasSelectedText() + + \bold{Note:} The textInteractionFlags set on the label need to include + either TextSelectableByMouse or TextSelectableByKeyboard. + + \since 4.7 +*/ +QString QLabel::selectedText() const +{ + Q_D(const QLabel); + if (d->control) + return d->control->textCursor().selectedText(); + return QString(); +} + +/*! + selectionStart() returns the index of the first selected character in the + label or -1 if no text is selected. + + \sa selectedText() + + \bold{Note:} The textInteractionFlags set on the label need to include + either TextSelectableByMouse or TextSelectableByKeyboard. + + \since 4.7 +*/ +int QLabel::selectionStart() const +{ + Q_D(const QLabel); + if (d->control && d->control->textCursor().hasSelection()) + return d->control->textCursor().selectionStart(); + return -1; +} + /*!\reimp */ QSize QLabel::sizeHint() const @@ -862,8 +951,8 @@ void QLabel::contextMenuEvent(QContextMenuEvent *ev) return; } ev->accept(); - menu->exec(ev->globalPos()); - delete menu; + menu->setAttribute(Qt::WA_DeleteOnClose); + menu->popup(ev->globalPos()); #endif } diff --git a/src/gui/widgets/qlabel.h b/src/gui/widgets/qlabel.h index d916078..54babb1 100644 --- a/src/gui/widgets/qlabel.h +++ b/src/gui/widgets/qlabel.h @@ -65,6 +65,8 @@ class Q_GUI_EXPORT QLabel : public QFrame Q_PROPERTY(int indent READ indent WRITE setIndent) Q_PROPERTY(bool openExternalLinks READ openExternalLinks WRITE setOpenExternalLinks) Q_PROPERTY(Qt::TextInteractionFlags textInteractionFlags READ textInteractionFlags WRITE setTextInteractionFlags) + Q_PROPERTY(bool hasSelectedText READ hasSelectedText) + Q_PROPERTY(QString selectedText READ selectedText) public: explicit QLabel(QWidget *parent=0, Qt::WindowFlags f=0); @@ -111,6 +113,11 @@ public: void setTextInteractionFlags(Qt::TextInteractionFlags flags); Qt::TextInteractionFlags textInteractionFlags() const; + void setSelection(int, int); + bool hasSelectedText() const; + QString selectedText() const; + int selectionStart() const; + public Q_SLOTS: void setText(const QString &); void setPixmap(const QPixmap &); diff --git a/src/gui/widgets/qlineedit.cpp b/src/gui/widgets/qlineedit.cpp index 2d2df92..0ba8b9f 100644 --- a/src/gui/widgets/qlineedit.cpp +++ b/src/gui/widgets/qlineedit.cpp @@ -1637,12 +1637,8 @@ void QLineEdit::keyPressEvent(QKeyEvent *event) if (!hasEditFocus() && !(event->modifiers() & Qt::ControlModifier)) { if (!event->text().isEmpty() && event->text().at(0).isPrint() && !isReadOnly()) - { setEditFocus(true); -#ifndef Q_OS_SYMBIAN - clear(); -#endif - } else { + else { event->ignore(); return; } @@ -1698,12 +1694,8 @@ void QLineEdit::inputMethodEvent(QInputMethodEvent *e) // commit text as they focus out without interfering with focus if (QApplication::keypadNavigationEnabled() && hasFocus() && !hasEditFocus() - && !e->preeditString().isEmpty()) { + && !e->preeditString().isEmpty()) setEditFocus(true); -#ifndef Q_OS_SYMBIAN - selectAll(); // so text is replaced rather than appended to -#endif - } #endif d->control->processInputMethodEvent(e); @@ -2046,9 +2038,9 @@ void QLineEdit::dropEvent(QDropEvent* e) */ void QLineEdit::contextMenuEvent(QContextMenuEvent *event) { - QPointer<QMenu> menu = createStandardContextMenu(); - menu->exec(event->globalPos()); - delete menu; + QMenu *menu = createStandardContextMenu(); + menu->setAttribute(Qt::WA_DeleteOnClose); + menu->popup(event->globalPos()); } #if defined(Q_WS_WIN) diff --git a/src/gui/widgets/qmainwindow.cpp b/src/gui/widgets/qmainwindow.cpp index e7c4f45..4620597 100644 --- a/src/gui/widgets/qmainwindow.cpp +++ b/src/gui/widgets/qmainwindow.cpp @@ -1393,6 +1393,7 @@ bool QMainWindow::event(QEvent *event) #endif // QT_NO_STATUSTIP case QEvent::StyleChange: + d->layout->layoutState.dockAreaLayout.styleChangedEvent(); if (!d->explicitIconSize) setIconSize(QSize()); break; @@ -1559,11 +1560,15 @@ void QMainWindow::contextMenuEvent(QContextMenuEvent *event) #ifndef QT_NO_MENU QMenu *popup = createPopupMenu(); - if (popup && !popup->isEmpty()) { - popup->exec(event->globalPos()); - event->accept(); + if (popup) { + if (!popup->isEmpty()) { + popup->setAttribute(Qt::WA_DeleteOnClose); + popup->popup(event->globalPos()); + event->accept(); + } else { + delete popup; + } } - delete popup; #endif } #endif // QT_NO_CONTEXTMENU diff --git a/src/gui/widgets/qmenu.cpp b/src/gui/widgets/qmenu.cpp index 42b7406..e2cf25b 100644 --- a/src/gui/widgets/qmenu.cpp +++ b/src/gui/widgets/qmenu.cpp @@ -2309,9 +2309,7 @@ void QMenu::mouseReleaseEvent(QMouseEvent *e) QAction *action = d->actionAt(e->pos()); if (action && action == d->currentAction) { - if (action->menu()) - action->menu()->d_func()->setFirstActionActive(); - else { + if (!action->menu()){ #if defined(Q_WS_WIN) //On Windows only context menus can be activated with the right button if (e->button() == Qt::LeftButton || d->topCausedWidget() == 0) diff --git a/src/gui/widgets/qmenu.h b/src/gui/widgets/qmenu.h index 47dff2b..a040afa 100644 --- a/src/gui/widgets/qmenu.h +++ b/src/gui/widgets/qmenu.h @@ -417,6 +417,7 @@ private: friend OSStatus qt_mac_menu_event(EventHandlerCallRef, EventRef, void *); friend bool qt_mac_activate_action(OSMenuRef, uint, QAction::ActionEvent, bool); friend void qt_mac_emit_menuSignals(QMenu *, bool); + friend void qt_mac_menu_emit_hovered(QMenu *menu, QAction *action); #endif }; diff --git a/src/gui/widgets/qmenu_mac.mm b/src/gui/widgets/qmenu_mac.mm index 7e4bbb5..99c550f 100644 --- a/src/gui/widgets/qmenu_mac.mm +++ b/src/gui/widgets/qmenu_mac.mm @@ -247,7 +247,7 @@ bool qt_mac_activate_action(MenuRef menu, uint command, QAction::ActionEvent act //now walk up firing for each "caused" widget (like in the platform independent menu) QWidget *caused = 0; - if (GetMenuItemProperty(menu, 0, kMenuCreatorQt, kMenuPropertyCausedQWidget, sizeof(caused), 0, &caused) == noErr) { + if (action_e == QAction::Hover && GetMenuItemProperty(menu, 0, kMenuCreatorQt, kMenuPropertyCausedQWidget, sizeof(caused), 0, &caused) == noErr) { MenuRef caused_menu = 0; if (QMenu *qmenu2 = qobject_cast<QMenu*>(caused)) caused_menu = qmenu2->macMenu(); @@ -260,25 +260,17 @@ bool qt_mac_activate_action(MenuRef menu, uint command, QAction::ActionEvent act QWidget *widget = 0; GetMenuItemProperty(caused_menu, 0, kMenuCreatorQt, kMenuPropertyQWidget, sizeof(widget), 0, &widget); if (QMenu *qmenu = qobject_cast<QMenu*>(widget)) { - if (action_e == QAction::Trigger) { - emit qmenu->triggered(action->action); - } else if (action_e == QAction::Hover) { - action->action->showStatusText(widget); - emit qmenu->hovered(action->action); - } + action->action->showStatusText(widget); + emit qmenu->hovered(action->action); } else if (QMenuBar *qmenubar = qobject_cast<QMenuBar*>(widget)) { - if (action_e == QAction::Trigger) { - emit qmenubar->triggered(action->action); - } else if (action_e == QAction::Hover) { - action->action->showStatusText(widget); - emit qmenubar->hovered(action->action); - } + action->action->showStatusText(widget); + emit qmenubar->hovered(action->action); break; //nothing more.. } //walk up if (GetMenuItemProperty(caused_menu, 0, kMenuCreatorQt, kMenuPropertyCausedQWidget, - sizeof(caused), 0, &caused) != noErr) + sizeof(caused), 0, &caused) != noErr) break; if (QMenu *qmenu2 = qobject_cast<QMenu*>(caused)) caused_menu = qmenu2->macMenu(); @@ -649,7 +641,7 @@ static NSMenuItem *createNSMenuItem(const QString &title) NSMenuItem *item = [[NSMenuItem alloc] initWithTitle:qt_mac_QStringToNSString(title) action:@selector(qtDispatcherToQAction:) keyEquivalent:@""]; - [item setTarget:getMenuLoader()]; + [item setTarget:nil]; return item; } #endif @@ -749,32 +741,6 @@ bool qt_mac_menubar_is_open() return qt_mac_menus_open_count > 0; } -void qt_mac_clear_menubar() -{ - if (QApplication::testAttribute(Qt::AA_MacPluginApplication)) - return; - -#ifndef QT_MAC_USE_COCOA - MenuRef clear_menu = 0; - if (CreateNewMenu(0, 0, &clear_menu) == noErr) { - SetRootMenu(clear_menu); - ReleaseMenu(clear_menu); - } else { - qWarning("QMenu: Internal error at %s:%d", __FILE__, __LINE__); - } - ClearMenuBar(); - qt_mac_command_set_enabled(0, kHICommandPreferences, false); - InvalMenuBar(); -#else - QMacCocoaAutoReleasePool pool; - QT_MANGLE_NAMESPACE(QCocoaMenuLoader) *loader = getMenuLoader(); - NSMenu *menu = [loader menu]; - [loader ensureAppMenuInMenu:menu]; - [NSApp setMainMenu:menu]; -#endif -} - - QMacMenuAction::~QMacMenuAction() { #ifdef QT_MAC_USE_COCOA @@ -1130,7 +1096,7 @@ QMenuPrivate::QMacMenuPrivate::addAction(QMacMenuAction *action, QMacMenuAction action->menu = merge; [cmd retain]; [cmd setAction:@selector(qtDispatcherToQAction:)]; - [cmd setTarget:getMenuLoader()]; + [cmd setTarget:nil]; [action->menuItem release]; action->menuItem = cmd; QMenuMergeList *list = QMenuPrivate::mergeMenuItemsHash.value(merge); @@ -1936,43 +1902,53 @@ static bool qt_mac_is_ancestor(QWidget* possibleAncestor, QWidget *child) Returns true if the entries of menuBar should be disabled, based on the modality type of modalWidget. */ -static bool qt_mac_should_disable_menu(QMenuBar *menuBar, QWidget *modalWidget) +static bool qt_mac_should_disable_menu(QMenuBar *menuBar) { - if (modalWidget == 0 || menuBar == 0) + QWidget *modalWidget = qApp->activeModalWidget(); + if (!modalWidget) return false; - // If there is an application modal window on - // screen, the entries of the menubar should be disabled: + if (menuBar && menuBar == menubars()->value(modalWidget)) + // The menu bar is owned by the modal widget. + // In that case we should enable it: + return false; + + // When there is an application modal window on screen, the entries of + // the menubar should be disabled. The exception in Qt is that if the + // modal window is the only window on screen, then we enable the menu bar. QWidget *w = modalWidget; + QWidgetList topLevelWidgets = QApplication::topLevelWidgets(); while (w) { - if (w->isVisible() && w->windowModality() == Qt::ApplicationModal) - return true; + if (w->isVisible() && w->windowModality() == Qt::ApplicationModal) { + for (int i=0; i<topLevelWidgets.size(); ++i) { + QWidget *top = topLevelWidgets.at(i); + if (w != top && [qt_mac_window_for(top) isVisible]) { + // INVARIANT: we found another visible window + // on screen other than our modalWidget. We therefore + // disable the menu bar to follow normal modality logic: + return true; + } + } + // INVARIANT: We have only one window on screen that happends + // to be application modal. We choose to enable the menu bar + // in that case to e.g. enable the quit menu item. + return false; + } w = w->parentWidget(); } // INVARIANT: modalWidget is window modal. Disable menu entries - // if the menu bar belongs to an ancestor of modalWidget: - return qt_mac_is_ancestor(menuBar->parentWidget(), modalWidget); + // if the menu bar belongs to an ancestor of modalWidget. If menuBar + // is nil, we understand it as the default menu bar set by the nib: + return menuBar ? qt_mac_is_ancestor(menuBar->parentWidget(), modalWidget) : false; } -/*! - \internal - - This function will update the current menu bar and set it as the - active menu bar in the Menu Manager. - - \warning This function is not portable. - - \sa QMenu::macMenu(), QMenuBar::macMenu() -*/ -bool QMenuBar::macUpdateMenuBar() +static QWidget *findWindowThatShouldDisplayMenubar() { - cancelAllMenuTracking(); - QMenuBar *mb = 0; - //find a menu bar QWidget *w = qApp->activeWindow(); - if (!w) { + // We have no active window on screen. Try to + // find a window from the list of top levels: QWidgetList tlws = QApplication::topLevelWidgets(); for(int i = 0; i < tlws.size(); ++i) { QWidget *tlw = tlws.at(i); @@ -1983,6 +1959,12 @@ bool QMenuBar::macUpdateMenuBar() } } } + return w; +} + +static QMenuBar *findMenubarForWindow(QWidget *w) +{ + QMenuBar *mb = 0; if (w) { mb = menubars()->value(w); #ifndef QT_NO_MAINWINDOW @@ -1996,11 +1978,77 @@ bool QMenuBar::macUpdateMenuBar() while(w && !mb) mb = menubars()->value((w = w->parentWidget())); } - if (!mb) + + if (!mb) { + // We could not find a menu bar for the window. Lets + // check if we have a global (parentless) menu bar instead: mb = fallback; - //now set it + } + + return mb; +} + +void qt_mac_clear_menubar() +{ + if (QApplication::testAttribute(Qt::AA_MacPluginApplication)) + return; + +#ifndef QT_MAC_USE_COCOA + MenuRef clear_menu = 0; + if (CreateNewMenu(0, 0, &clear_menu) == noErr) { + SetRootMenu(clear_menu); + ReleaseMenu(clear_menu); + } else { + qWarning("QMenu: Internal error at %s:%d", __FILE__, __LINE__); + } + ClearMenuBar(); + qt_mac_command_set_enabled(0, kHICommandPreferences, false); + InvalMenuBar(); +#else + QMacCocoaAutoReleasePool pool; + QT_MANGLE_NAMESPACE(QCocoaMenuLoader) *loader = getMenuLoader(); + NSMenu *menu = [loader menu]; + [loader ensureAppMenuInMenu:menu]; + [NSApp setMainMenu:menu]; + const bool modal = qt_mac_should_disable_menu(0); + if (qt_mac_current_menubar.qmenubar || modal != qt_mac_current_menubar.modal) + qt_mac_set_modal_state(menu, modal); + qt_mac_current_menubar.qmenubar = 0; + qt_mac_current_menubar.modal = modal; +#endif +} + +/*! + \internal + + This function will update the current menu bar and set it as the + active menu bar in the Menu Manager. + + \warning This function is not portable. + + \sa QMenu::macMenu(), QMenuBar::macMenu() +*/ +bool QMenuBar::macUpdateMenuBar() +{ +#ifdef QT_MAC_USE_COCOA + QMacCocoaAutoReleasePool pool; + if (!qt_cocoaPostMessage(getMenuLoader(), @selector(qtUpdateMenubar))) + return QMenuBarPrivate::macUpdateMenuBarImmediatly(); + return true; +#else + return QMenuBarPrivate::macUpdateMenuBarImmediatly(); +#endif +} + +bool QMenuBarPrivate::macUpdateMenuBarImmediatly() +{ bool ret = false; + cancelAllMenuTracking(); + QWidget *w = findWindowThatShouldDisplayMenubar(); + QMenuBar *mb = findMenubarForWindow(w); + if (mb && mb->isNativeMenuBar()) { + bool modal = QApplicationPrivate::modalState(); #ifdef QT_MAC_USE_COCOA QMacCocoaAutoReleasePool pool; #endif @@ -2030,16 +2078,18 @@ bool QMenuBar::macUpdateMenuBar() } } #endif - QWidget *modalWidget = qApp->activeModalWidget(); - if (mb != menubars()->value(modalWidget)) { - qt_mac_set_modal_state(menu, qt_mac_should_disable_menu(mb, modalWidget)); - } + // Check if menu is modally shaddowed and should be disabled: + modal = qt_mac_should_disable_menu(mb); + if (mb != qt_mac_current_menubar.qmenubar || modal != qt_mac_current_menubar.modal) + qt_mac_set_modal_state(menu, modal); } qt_mac_current_menubar.qmenubar = mb; - qt_mac_current_menubar.modal = QApplicationPrivate::modalState(); + qt_mac_current_menubar.modal = modal; ret = true; } else if (qt_mac_current_menubar.qmenubar && qt_mac_current_menubar.qmenubar->isNativeMenuBar()) { - const bool modal = QApplicationPrivate::modalState(); + // INVARIANT: The currently active menu bar (if any) is not native. But we do have a + // native menu bar from before. So we need to decide whether or not is should be enabled: + const bool modal = qt_mac_should_disable_menu(qt_mac_current_menubar.qmenubar); if (modal != qt_mac_current_menubar.modal) { ret = true; if (OSMenuRef menu = qt_mac_current_menubar.qmenubar->macMenu()) { @@ -2051,16 +2101,15 @@ bool QMenuBar::macUpdateMenuBar() [NSApp setMainMenu:menu]; syncMenuBarItemsVisiblity(qt_mac_current_menubar.qmenubar->d_func()->mac_menubar); #endif - QWidget *modalWidget = qApp->activeModalWidget(); - if (qt_mac_current_menubar.qmenubar != menubars()->value(modalWidget)) { - qt_mac_set_modal_state(menu, qt_mac_should_disable_menu(mb, modalWidget)); - } + qt_mac_set_modal_state(menu, modal); } qt_mac_current_menubar.modal = modal; } } - if(!ret) + + if (!ret) { qt_mac_clear_menubar(); + } return ret; } diff --git a/src/gui/widgets/qmenubar_p.h b/src/gui/widgets/qmenubar_p.h index f2e5357..819aee4 100644 --- a/src/gui/widgets/qmenubar_p.h +++ b/src/gui/widgets/qmenubar_p.h @@ -196,6 +196,7 @@ public: return 0; } } *mac_menubar; + static bool macUpdateMenuBarImmediatly(); bool macWidgetHasNativeMenubar(QWidget *widget); void macCreateMenuBar(QWidget *); void macDestroyMenuBar(); diff --git a/src/gui/widgets/qplaintextedit.cpp b/src/gui/widgets/qplaintextedit.cpp index ab598d9..ef9fac3 100644 --- a/src/gui/widgets/qplaintextedit.cpp +++ b/src/gui/widgets/qplaintextedit.cpp @@ -911,6 +911,7 @@ void QPlainTextEditPrivate::pageUpDown(QTextCursor::MoveOperation op, QTextCurso setTopBlock(block.blockNumber(), line); if (moveCursor) { + cursor.setVisualNavigation(true); // move using movePosition to keep the cursor's x lastY += verticalOffset(); bool moved = false; @@ -1319,6 +1320,26 @@ QTextCursor QPlainTextEdit::textCursor() const return d->control->textCursor(); } +/*! + Returns the reference of the anchor at position \a pos, or an + empty string if no anchor exists at that point. + + \since 4.7 + */ +QString QPlainTextEdit::anchorAt(const QPoint &pos) const +{ + Q_D(const QPlainTextEdit); + int cursorPos = d->control->hitTest(pos + QPoint(d->horizontalOffset(), + d->verticalOffset()), + Qt::ExactHit); + if (cursorPos < 0) + return QString(); + + QTextDocumentPrivate *pieceTable = document()->docHandle(); + QTextDocumentPrivate::FragmentIterator it = pieceTable->find(cursorPos); + QTextCharFormat fmt = pieceTable->formatCollection()->charFormat(it->format); + return fmt.anchorHref(); +} /*! Undoes the last operation. @@ -2393,7 +2414,7 @@ void QPlainTextEdit::setReadOnly(bool ro) then the focus policy is also automatically set to Qt::ClickFocus. The default value depends on whether the QPlainTextEdit is read-only - or editable, and whether it is a QTextBrowser or not. + or editable. */ void QPlainTextEdit::setTextInteractionFlags(Qt::TextInteractionFlags flags) diff --git a/src/gui/widgets/qplaintextedit.h b/src/gui/widgets/qplaintextedit.h index 15cf0967..106ae6d 100644 --- a/src/gui/widgets/qplaintextedit.h +++ b/src/gui/widgets/qplaintextedit.h @@ -159,6 +159,8 @@ public: QRect cursorRect(const QTextCursor &cursor) const; QRect cursorRect() const; + QString anchorAt(const QPoint &pos) const; + bool overwriteMode() const; void setOverwriteMode(bool overwrite); diff --git a/src/gui/widgets/qtabbar.cpp b/src/gui/widgets/qtabbar.cpp index 22e8255..7559311 100644 --- a/src/gui/widgets/qtabbar.cpp +++ b/src/gui/widgets/qtabbar.cpp @@ -1947,7 +1947,8 @@ void QTabBar::changeEvent(QEvent *event) { Q_D(QTabBar); if (event->type() == QEvent::StyleChange) { - d->elideMode = Qt::TextElideMode(style()->styleHint(QStyle::SH_TabBar_ElideMode, 0, this)); + if (!d->elideModeSetByUser) + d->elideMode = Qt::TextElideMode(style()->styleHint(QStyle::SH_TabBar_ElideMode, 0, this)); if (!d->useScrollButtonsSetByUser) d->useScrollButtons = !style()->styleHint(QStyle::SH_TabBar_PreferNoArrows, 0, this); d->refresh(); @@ -1980,6 +1981,7 @@ void QTabBar::setElideMode(Qt::TextElideMode mode) { Q_D(QTabBar); d->elideMode = mode; + d->elideModeSetByUser = true; d->refresh(); } diff --git a/src/gui/widgets/qtabbar_p.h b/src/gui/widgets/qtabbar_p.h index 7588035..83636e6 100644 --- a/src/gui/widgets/qtabbar_p.h +++ b/src/gui/widgets/qtabbar_p.h @@ -75,7 +75,7 @@ class QTabBarPrivate : public QWidgetPrivate public: QTabBarPrivate() :currentIndex(-1), pressedIndex(-1), shape(QTabBar::RoundedNorth), layoutDirty(false), - drawBase(true), scrollOffset(0), useScrollButtonsSetByUser(false) , expanding(true), closeButtonOnTabs(false), + drawBase(true), scrollOffset(0), elideModeSetByUser(false), useScrollButtonsSetByUser(false), expanding(true), closeButtonOnTabs(false), selectionBehaviorOnRemove(QTabBar::SelectRightTab), paintWithOffsets(true), movable(false), dragInProgress(false), documentMode(false), movingTab(0) #ifdef Q_WS_MAC @@ -186,6 +186,7 @@ public: void makeVisible(int index); QSize iconSize; Qt::TextElideMode elideMode; + bool elideModeSetByUser; bool useScrollButtons; bool useScrollButtonsSetByUser; diff --git a/src/gui/widgets/qtextedit.cpp b/src/gui/widgets/qtextedit.cpp index b6886b4..4541730 100644 --- a/src/gui/widgets/qtextedit.cpp +++ b/src/gui/widgets/qtextedit.cpp @@ -1212,12 +1212,9 @@ void QTextEdit::keyPressEvent(QKeyEvent *e) default: if (QApplication::keypadNavigationEnabled()) { if (!hasEditFocus() && !(e->modifiers() & Qt::ControlModifier)) { - if (e->text()[0].isPrint()) { + if (e->text()[0].isPrint()) setEditFocus(true); -#ifndef Q_OS_SYMBIAN - clear(); -#endif - } else { + else { e->ignore(); return; } @@ -1677,12 +1674,8 @@ void QTextEdit::inputMethodEvent(QInputMethodEvent *e) #ifdef QT_KEYPAD_NAVIGATION if (d->control->textInteractionFlags() & Qt::TextEditable && QApplication::keypadNavigationEnabled() - && !hasEditFocus()) { + && !hasEditFocus()) setEditFocus(true); -#ifndef Q_OS_SYMBIAN - selectAll(); // so text is replaced rather than appended to -#endif - } #endif d->sendControlEvent(e); ensureCursorVisible(); diff --git a/src/gui/widgets/qtoolbar.cpp b/src/gui/widgets/qtoolbar.cpp index 8beda55..7ed27ea 100644 --- a/src/gui/widgets/qtoolbar.cpp +++ b/src/gui/widgets/qtoolbar.cpp @@ -533,6 +533,14 @@ void QToolBarPrivate::plug(const QRect &r) /*! + \fn void QToolBar::visibilityChanged(bool visible) + \since 4.7 + + This signal is emitted when the toolbar becomes \a visible (or + invisible). This happens when the widget is hidden or shown. +*/ + +/*! Constructs a QToolBar with the given \a parent. */ QToolBar::QToolBar(QWidget *parent) @@ -1122,6 +1130,7 @@ bool QToolBar::event(QEvent *event) // fallthrough intended case QEvent::Show: d->toggleViewAction->setChecked(event->type() == QEvent::Show); + emit visibilityChanged(event->type() == QEvent::Show); #if defined(Q_WS_MAC) if (toolbarInUnifiedToolBar(this)) { // I can static_cast because I did the qobject_cast in the if above, therefore diff --git a/src/gui/widgets/qtoolbar.h b/src/gui/widgets/qtoolbar.h index 90f20dd..b733477 100644 --- a/src/gui/widgets/qtoolbar.h +++ b/src/gui/widgets/qtoolbar.h @@ -143,6 +143,7 @@ Q_SIGNALS: void iconSizeChanged(const QSize &iconSize); void toolButtonStyleChanged(Qt::ToolButtonStyle toolButtonStyle); void topLevelChanged(bool topLevel); + void visibilityChanged(bool visible); protected: void actionEvent(QActionEvent *event); diff --git a/src/gui/widgets/qvalidator.cpp b/src/gui/widgets/qvalidator.cpp index a5276d3..0b5cc5a 100644 --- a/src/gui/widgets/qvalidator.cpp +++ b/src/gui/widgets/qvalidator.cpp @@ -400,8 +400,10 @@ QValidator::State QIntValidator::validate(QString & input, int&) const qlonglong entered = QLocalePrivate::bytearrayToLongLong(buff.constData(), 10, &ok, &overflow); if (overflow || !ok) return Invalid; - if (entered >= b && entered <= t) - return Acceptable; + if (entered >= b && entered <= t) { + locale().toInt(input, &ok); + return ok ? Acceptable : Intermediate; + } if (entered >= 0) { // the -entered < b condition is necessary to allow people to type @@ -412,6 +414,20 @@ QValidator::State QIntValidator::validate(QString & input, int&) const } } +/*! \reimp */ +void QIntValidator::fixup(QString &input) const +{ + QByteArray buff; + if (!locale().d()->validateChars(input, QLocalePrivate::IntegerMode, &buff)) { + QLocale cl(QLocale::C); + if (!cl.d()->validateChars(input, QLocalePrivate::IntegerMode, &buff)) + return; + } + bool ok, overflow; + qlonglong entered = QLocalePrivate::bytearrayToLongLong(buff.constData(), 10, &ok, &overflow); + if (ok && !overflow) + input = locale().toString(entered); +} /*! Sets the range of the validator to only accept integers between \a diff --git a/src/gui/widgets/qvalidator.h b/src/gui/widgets/qvalidator.h index 30afbd6..63734ca 100644 --- a/src/gui/widgets/qvalidator.h +++ b/src/gui/widgets/qvalidator.h @@ -105,6 +105,7 @@ public: ~QIntValidator(); QValidator::State validate(QString &, int &) const; + void fixup(QString &input) const; void setBottom(int); void setTop(int); @@ -136,10 +137,11 @@ class Q_GUI_EXPORT QDoubleValidator : public QValidator Q_PROPERTY(double bottom READ bottom WRITE setBottom) Q_PROPERTY(double top READ top WRITE setTop) Q_PROPERTY(int decimals READ decimals WRITE setDecimals) + Q_ENUMS(Notation) Q_PROPERTY(Notation notation READ notation WRITE setNotation) public: - explicit QDoubleValidator(QObject * parent); + explicit QDoubleValidator(QObject * parent = 0); QDoubleValidator(double bottom, double top, int decimals, QObject * parent); ~QDoubleValidator(); @@ -183,7 +185,7 @@ class Q_GUI_EXPORT QRegExpValidator : public QValidator Q_PROPERTY(QRegExp regExp READ regExp WRITE setRegExp) public: - explicit QRegExpValidator(QObject *parent); + explicit QRegExpValidator(QObject *parent = 0); QRegExpValidator(const QRegExp& rx, QObject *parent); ~QRegExpValidator(); |