diff options
author | Paul Olav Tvete <paul.tvete@nokia.com> | 2010-03-01 13:03:22 (GMT) |
---|---|---|
committer | Paul Olav Tvete <paul.tvete@nokia.com> | 2010-03-01 13:17:53 (GMT) |
commit | 19095f432ef7ef424ea8dc89b19e43ed9f031b3e (patch) | |
tree | 159654fbd2066eaea6d6fe78efc9726b5959eb3d /src/gui | |
parent | 196e1484c22f6347061fa433987a86d90e178a55 (diff) | |
parent | 236c3ad7bacf165069b834b62fede6b147cfaf03 (diff) | |
download | Qt-19095f432ef7ef424ea8dc89b19e43ed9f031b3e.zip Qt-19095f432ef7ef424ea8dc89b19e43ed9f031b3e.tar.gz Qt-19095f432ef7ef424ea8dc89b19e43ed9f031b3e.tar.bz2 |
Merge remote branch 'qt/4.7' into lighthouse-4.7
Conflicts:
configure
src/gui/egl/qegl.cpp
src/gui/kernel/qdnd_p.h
Diffstat (limited to 'src/gui')
239 files changed, 6682 insertions, 2783 deletions
diff --git a/src/gui/dialogs/dialogs.pri b/src/gui/dialogs/dialogs.pri index 6c21390..20bdabc 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/qcolordialog.cpp b/src/gui/dialogs/qcolordialog.cpp index 83ecc30..e6abf7f 100644 --- a/src/gui/dialogs/qcolordialog.cpp +++ b/src/gui/dialogs/qcolordialog.cpp @@ -1078,8 +1078,7 @@ QColorShower::QColorShower(QColorDialog *parent) #ifdef QT_SMALL_COLORDIALOG # ifdef Q_WS_S60 - QS60Data s60Data = QS60Data(); - const bool nonTouchUI = !s60Data.hasTouchscreen; + const bool nonTouchUI = !S60->hasTouchscreen; # elif defined Q_WS_MAEMO_5 const bool nonTouchUI = false; # endif @@ -1506,8 +1505,7 @@ void QColorDialogPrivate::init(const QColor &initial) #if defined(QT_SMALL_COLORDIALOG) # if defined(Q_WS_S60) - QS60Data s60Data = QS60Data(); - const bool nonTouchUI = !s60Data.hasTouchscreen; + const bool nonTouchUI = !S60->hasTouchscreen; # elif defined(Q_WS_MAEMO_5) const bool nonTouchUI = false; # endif diff --git a/src/gui/dialogs/qcolordialog_mac.mm b/src/gui/dialogs/qcolordialog_mac.mm index bdcb872..8af0d2b 100644 --- a/src/gui/dialogs/qcolordialog_mac.mm +++ b/src/gui/dialogs/qcolordialog_mac.mm @@ -96,6 +96,7 @@ QT_USE_NAMESPACE - (void)finishOffWithCode:(NSInteger)result; - (void)showColorPanel; - (void)exec; +- (void)setResultSet:(BOOL)result; @end @implementation QCocoaColorPanelDelegate @@ -158,6 +159,11 @@ QT_USE_NAMESPACE [super dealloc]; } +- (void)setResultSet:(BOOL)result +{ + mResultSet = result; +} + - (BOOL)windowShouldClose:(id)window { Q_UNUSED(window); @@ -320,7 +326,7 @@ QT_USE_NAMESPACE } else { mPriv->colorDialog()->accept(); } - } + } } } @@ -433,7 +439,7 @@ void QColorDialogPrivate::openCocoaColorPanel(const QColor &initial, priv:this]; [colorPanel setDelegate:static_cast<QCocoaColorPanelDelegate *>(delegate)]; } - + [delegate setResultSet:false]; setCocoaPanelColor(initial); [static_cast<QCocoaColorPanelDelegate *>(delegate) showColorPanel]; } 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/qfontdialog.cpp b/src/gui/dialogs/qfontdialog.cpp index 56580a9..a4bf15d 100644 --- a/src/gui/dialogs/qfontdialog.cpp +++ b/src/gui/dialogs/qfontdialog.cpp @@ -989,34 +989,24 @@ void QFontDialog::open(QObject *receiver, const char *member) void QFontDialog::setVisible(bool visible) { Q_D(QFontDialog); - if (visible) - d->selectedFont = QFont(); - -#if defined(Q_WS_MAC) - bool isCurrentlyVisible = (isVisible() || d->delegate); - - if (!visible == !isCurrentlyVisible) - return; - if (visible) { - if (!(d->opts & DontUseNativeDialog) && QFontDialogPrivate::sharedFontPanelAvailable) { - d->delegate = QFontDialogPrivate::openCocoaFontPanel( - currentFont(), parentWidget(), windowTitle(), options(), d); - QFontDialogPrivate::sharedFontPanelAvailable = false; - return; - } - - setWindowFlags(windowModality() == Qt::WindowModal ? Qt::Sheet : DefaultWindowFlags); - } else { - if (d->delegate) { - QFontDialogPrivate::closeCocoaFontPanel(d->delegate); - d->delegate = 0; - QFontDialogPrivate::sharedFontPanelAvailable = true; + if (testAttribute(Qt::WA_WState_ExplicitShowHide) && !testAttribute(Qt::WA_WState_Hidden)) return; + } else if (testAttribute(Qt::WA_WState_ExplicitShowHide) && testAttribute(Qt::WA_WState_Hidden)) + return; +#ifdef Q_WS_MAC + if (d->canBeNativeDialog()){ + if (d->setVisible_sys(visible)){ + d->nativeDialogInUse = true; + // Set WA_DontShowOnScreen so that QDialog::setVisible(visible) below + // updates the state correctly, but skips showing the non-native version: + setAttribute(Qt::WA_DontShowOnScreen, true); + } else { + d->nativeDialogInUse = false; + setAttribute(Qt::WA_DontShowOnScreen, false); } } -#endif - +#endif // Q_WS_MAC QDialog::setVisible(visible); } @@ -1032,11 +1022,14 @@ void QFontDialog::done(int result) Q_D(QFontDialog); QDialog::done(result); if (result == Accepted) { - d->selectedFont = currentFont(); + // We check if this is the same font we had before, if so we emit currentFontChanged + QFont selectedFont = currentFont(); + if(selectedFont != d->selectedFont) + emit(currentFontChanged(selectedFont)); + d->selectedFont = selectedFont; emit fontSelected(d->selectedFont); - } else { + } else d->selectedFont = QFont(); - } if (d->receiverToDisconnectOnClose) { disconnect(this, SIGNAL(fontSelected(QFont)), d->receiverToDisconnectOnClose, d->memberToDisconnectOnClose); @@ -1045,6 +1038,23 @@ void QFontDialog::done(int result) d->memberToDisconnectOnClose.clear(); } +#ifdef Q_WS_MAC +bool QFontDialogPrivate::canBeNativeDialog() +{ + Q_Q(QFontDialog); + if (nativeDialogInUse) + return true; + if (q->testAttribute(Qt::WA_DontShowOnScreen)) + return false; + if (opts & QFontDialog::DontUseNativeDialog) + return false; + + QLatin1String staticName(QFontDialog::staticMetaObject.className()); + QLatin1String dynamicName(q->metaObject()->className()); + return (staticName == dynamicName); +} +#endif // Q_WS_MAC + /*! \fn QFont QFontDialog::getFont(bool *ok, const QFont &initial, QWidget* parent, const char* name) \since 4.5 diff --git a/src/gui/dialogs/qfontdialog.h b/src/gui/dialogs/qfontdialog.h index e6f209e..6035a3a 100644 --- a/src/gui/dialogs/qfontdialog.h +++ b/src/gui/dialogs/qfontdialog.h @@ -131,6 +131,9 @@ private: Q_PRIVATE_SLOT(d_func(), void _q_styleHighlighted(int)) Q_PRIVATE_SLOT(d_func(), void _q_sizeHighlighted(int)) Q_PRIVATE_SLOT(d_func(), void _q_updateSample()) +#if defined(Q_WS_MAC) + Q_PRIVATE_SLOT(d_func(), void _q_macRunNativeAppModalPanel()) +#endif }; Q_DECLARE_OPERATORS_FOR_FLAGS(QFontDialog::FontDialogOptions) diff --git a/src/gui/dialogs/qfontdialog_mac.mm b/src/gui/dialogs/qfontdialog_mac.mm index 68f5f00..67d32b8 100644 --- a/src/gui/dialogs/qfontdialog_mac.mm +++ b/src/gui/dialogs/qfontdialog_mac.mm @@ -49,6 +49,7 @@ #include <private/qfontengine_p.h> #include <private/qt_cocoa_helpers_mac_p.h> #include <private/qt_mac_p.h> +#include <qabstracteventdispatcher.h> #include <qdebug.h> #import <AppKit/AppKit.h> #import <Foundation/Foundation.h> @@ -372,7 +373,12 @@ static QFont qfontForCocoaFont(NSFont *cocoaFont, const QFont &resolveFont) [NSApp endModalSession:mModalSession]; mModalSession = 0; } - + // Hack alert! + // Since this code path was never intended to be followed when starting from exec + // we need to force the dialog to communicate the new font, otherwise the signal + // won't get emitted. + if(code == NSOKButton) + mPriv->sampleEdit->setFont([self qtFont]); mPriv->done((code == NSOKButton) ? QDialog::Accepted : QDialog::Rejected); } else { [NSApp stopModalWithCode:code]; @@ -567,7 +573,6 @@ void *QFontDialogPrivate::openCocoaFontPanel(const QFont &initial, [ourPanel makeKeyAndOrderFront:ourPanel]; } } - return delegate; } @@ -640,6 +645,145 @@ void QFontDialogPrivate::setFont(void *delegate, const QFont &font) [static_cast<QCocoaFontPanelDelegate *>(delegate) setQtFont:font]; } +void *QFontDialogPrivate::_q_constructNativePanel() +{ + QMacCocoaAutoReleasePool pool; + + bool sharedFontPanelExisted = [NSFontPanel sharedFontPanelExists]; + NSFontPanel *sharedFontPanel = [NSFontPanel sharedFontPanel]; + [sharedFontPanel setHidesOnDeactivate:false]; + + // hack to ensure that QCocoaApplication's validModesForFontPanel: + // implementation is honored + if (!sharedFontPanelExisted) { + [sharedFontPanel makeKeyAndOrderFront:sharedFontPanel]; + [sharedFontPanel close]; + } + + NSPanel *ourPanel = 0; + NSView *stolenContentView = 0; + NSButton *okButton = 0; + NSButton *cancelButton = 0; + + CGFloat dialogExtraWidth = 0.0; + CGFloat dialogExtraHeight = 0.0; + + // compute dialogExtra{Width,Height} + dialogExtraWidth = 2.0 * DialogSideMargin; + dialogExtraHeight = DialogTopMargin + ButtonTopMargin + ButtonMinHeight + + ButtonBottomMargin; + + // compute initial contents rectangle + NSRect contentRect = [sharedFontPanel contentRectForFrameRect:[sharedFontPanel frame]]; + contentRect.size.width += dialogExtraWidth; + contentRect.size.height += dialogExtraHeight; + + // create the new panel + ourPanel = [[NSPanel alloc] initWithContentRect:contentRect + styleMask:StyleMask + backing:NSBackingStoreBuffered + defer:YES]; + [ourPanel setReleasedWhenClosed:YES]; + + stolenContentView = [sharedFontPanel contentView]; + + // steal the font panel's contents view + [stolenContentView retain]; + [sharedFontPanel setContentView:0]; + + { + // create a new content view and add the stolen one as a subview + NSRect frameRect = { { 0.0, 0.0 }, { 0.0, 0.0 } }; + NSView *ourContentView = [[NSView alloc] initWithFrame:frameRect]; + [ourContentView addSubview:stolenContentView]; + + // create OK and Cancel buttons and add these as subviews + okButton = macCreateButton("&OK", ourContentView); + cancelButton = macCreateButton("Cancel", ourContentView); + + [ourPanel setContentView:ourContentView]; + [ourPanel setDefaultButtonCell:[okButton cell]]; + } + // create a delegate and set it + QCocoaFontPanelDelegate *delegate = + [[QCocoaFontPanelDelegate alloc] initWithFontPanel:sharedFontPanel + stolenContentView:stolenContentView + okButton:okButton + cancelButton:cancelButton + priv:this + extraWidth:dialogExtraWidth + extraHeight:dialogExtraHeight]; + [ourPanel setDelegate:delegate]; + [[NSFontManager sharedFontManager] setDelegate:delegate]; +#ifdef QT_MAC_USE_COCOA + [[NSFontManager sharedFontManager] setTarget:delegate]; +#endif + setFont(delegate, QApplication::font()); + + { + // hack to get correct initial layout + NSRect frameRect = [ourPanel frame]; + frameRect.size.width += 1.0; + [ourPanel setFrame:frameRect display:NO]; + frameRect.size.width -= 1.0; + frameRect.size = [delegate windowWillResize:ourPanel toSize:frameRect.size]; + [ourPanel setFrame:frameRect display:NO]; + [ourPanel center]; + } + NSString *title = @"Select font"; + [ourPanel setTitle:title]; + + [delegate setModalSession:[NSApp beginModalSessionForWindow:ourPanel]]; + return delegate; +} + +void QFontDialogPrivate::mac_nativeDialogModalHelp() +{ + // Copied from QFileDialogPrivate + // Do a queued meta-call to open the native modal dialog so it opens after the new + // event loop has started to execute (in QDialog::exec). Using a timer rather than + // a queued meta call is intentional to ensure that the call is only delivered when + // [NSApp run] runs (timers are handeled special in cocoa). If NSApp is not + // running (which is the case if e.g a top-most QEventLoop has been + // interrupted, and the second-most event loop has not yet been reactivated (regardless + // if [NSApp run] is still on the stack)), showing a native modal dialog will fail. + if (nativeDialogInUse) { + Q_Q(QFontDialog); + QTimer::singleShot(1, q, SLOT(_q_macRunNativeAppModalPanel())); + } +} + +// The problem with the native font dialog is that OS X does not +// offer a proper dialog, but a panel (i.e. without Ok and Cancel buttons). +// This means we need to "construct" a native dialog by taking the panel +// and "adding" the buttons. +void QFontDialogPrivate::_q_macRunNativeAppModalPanel() +{ + QBoolBlocker nativeDialogOnTop(QApplicationPrivate::native_modal_dialog_active); + Q_Q(QFontDialog); + QCocoaFontPanelDelegate *delegate = (QCocoaFontPanelDelegate *)_q_constructNativePanel(); + NSWindow *ourPanel = [delegate actualPanel]; + [ourPanel retain]; + int rval = [NSApp runModalForWindow:ourPanel]; + QAbstractEventDispatcher::instance()->interrupt(); + [ourPanel release]; + [delegate cleanUpAfterMyself]; + [delegate release]; + bool isOk = (rval == NSOKButton); + if(isOk) + rescode = QDialog::Accepted; + else + rescode = QDialog::Rejected; +} + +bool QFontDialogPrivate::setVisible_sys(bool visible) +{ + Q_Q(QFontDialog); + if (!visible == q->isHidden()) + return false; + return visible; +} + QT_END_NAMESPACE #endif diff --git a/src/gui/dialogs/qfontdialog_p.h b/src/gui/dialogs/qfontdialog_p.h index ca2b10b..7654a80 100644 --- a/src/gui/dialogs/qfontdialog_p.h +++ b/src/gui/dialogs/qfontdialog_p.h @@ -152,6 +152,12 @@ public: inline QFontDialog *fontDialog() { return q_func(); } void *delegate; + bool nativeDialogInUse; + bool canBeNativeDialog(); + bool setVisible_sys(bool visible); + void *_q_constructNativePanel(); + void _q_macRunNativeAppModalPanel(); + void mac_nativeDialogModalHelp(); static bool sharedFontPanelAvailable; #endif 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/effects/qgraphicseffect.cpp b/src/gui/effects/qgraphicseffect.cpp index 10ef5ea..ce4ce6a 100644 --- a/src/gui/effects/qgraphicseffect.cpp +++ b/src/gui/effects/qgraphicseffect.cpp @@ -699,12 +699,17 @@ void QGraphicsColorizeEffect::draw(QPainter *painter) if (sourceIsPixmap()) { // No point in drawing in device coordinates (pixmap will be scaled anyways). const QPixmap pixmap = sourcePixmap(Qt::LogicalCoordinates, &offset, NoPad); - d->filter->draw(painter, offset, pixmap); + if (!pixmap.isNull()) + d->filter->draw(painter, offset, pixmap); + return; } // Draw pixmap in deviceCoordinates to avoid pixmap scaling. const QPixmap pixmap = sourcePixmap(Qt::DeviceCoordinates, &offset); + if (pixmap.isNull()) + return; + QTransform restoreTransform = painter->worldTransform(); painter->setWorldTransform(QTransform()); d->filter->draw(painter, offset, pixmap); @@ -721,7 +726,8 @@ void QGraphicsColorizeEffect::draw(QPainter *painter) elements. The level of detail can be modified using the setBlurRadius() function. Use setBlurHints() to choose the blur hints. - By default, the blur radius is 5 pixels. + By default, the blur radius is 5 pixels. The blur radius is specified in + device coordinates. \img graphicseffect-blur.png @@ -776,6 +782,9 @@ QGraphicsBlurEffect::~QGraphicsBlurEffect() radius results in a more blurred appearance. By default, the blur radius is 5 pixels. + + The radius is given in device coordinates, meaning it is + unaffected by scale. */ qreal QGraphicsBlurEffect::blurRadius() const { @@ -858,9 +867,11 @@ void QGraphicsBlurEffect::draw(QPainter *painter) if (painter->paintEngine()->type() == QPaintEngine::OpenGL2) mode = NoPad; - // Draw pixmap in device coordinates to avoid pixmap scaling. QPoint offset; QPixmap pixmap = sourcePixmap(Qt::LogicalCoordinates, &offset, mode); + if (pixmap.isNull()) + return; + d->filter->draw(painter, offset, pixmap); } @@ -877,7 +888,8 @@ void QGraphicsBlurEffect::draw(QPainter *painter) By default, the drop shadow is a semi-transparent dark gray (QColor(63, 63, 63, 180)) shadow, blurred with a radius of 1 at an offset - of 8 pixels towards the lower right. + of 8 pixels towards the lower right. The drop shadow offset is specified + in device coordinates. \img graphicseffect-drop-shadow.png @@ -906,6 +918,9 @@ QGraphicsDropShadowEffect::~QGraphicsDropShadowEffect() By default, the offset is 8 pixels towards the lower right. + The offset is given in device coordinates, which means it is + unaffected by scale. + \sa xOffset(), yOffset(), blurRadius(), color() */ QPointF QGraphicsDropShadowEffect::offset() const @@ -1047,6 +1062,9 @@ void QGraphicsDropShadowEffect::draw(QPainter *painter) // Draw pixmap in device coordinates to avoid pixmap scaling. QPoint offset; const QPixmap pixmap = sourcePixmap(Qt::DeviceCoordinates, &offset, mode); + if (pixmap.isNull()) + return; + QTransform restoreTransform = painter->worldTransform(); painter->setWorldTransform(QTransform()); d->filter->draw(painter, offset, pixmap); diff --git a/src/gui/egl/qegl.cpp b/src/gui/egl/qegl.cpp index ef441b2..921bf2d 100644 --- a/src/gui/egl/qegl.cpp +++ b/src/gui/egl/qegl.cpp @@ -54,9 +54,10 @@ QT_BEGIN_NAMESPACE static QEglContext * volatile currentGLContext = 0; static QEglContext * volatile currentVGContext = 0; +EGLDisplay QEglContext::dpy = EGL_NO_DISPLAY; + QEglContext::QEglContext() : apiType(QEgl::OpenGL) - , dpy(EGL_NO_DISPLAY) , ctx(EGL_NO_CONTEXT) , cfg(0) , currentSurface(EGL_NO_SURFACE) @@ -68,7 +69,7 @@ QEglContext::QEglContext() QEglContext::~QEglContext() { - destroy(); + destroyContext(); if (currentGLContext == this) currentGLContext = 0; @@ -86,14 +87,6 @@ bool QEglContext::isCurrent() const return current; } -// Open the EGL display associated with "device". -bool QEglContext::openDisplay(QPaintDevice *device) -{ - if (dpy == EGL_NO_DISPLAY) - dpy = defaultDisplay(device); - return (dpy != EGL_NO_DISPLAY); -} - // Choose a configuration that matches "properties". bool QEglContext::chooseConfig (const QEglProperties& properties, QEgl::PixelFormatMatch match) @@ -102,13 +95,13 @@ bool QEglContext::chooseConfig do { // Get the number of matching configurations for this set of properties. EGLint matching = 0; - if (!eglChooseConfig(dpy, props.properties(), 0, 0, &matching) || !matching) + if (!eglChooseConfig(display(), props.properties(), 0, 0, &matching) || !matching) continue; // If we want the best pixel format, then return the first // matching configuration. if (match == QEgl::BestPixelFormat) { - eglChooseConfig(dpy, props.properties(), &cfg, 1, &matching); + eglChooseConfig(display(), props.properties(), &cfg, 1, &matching); if (matching < 1) continue; return true; @@ -118,13 +111,13 @@ bool QEglContext::chooseConfig // first that matches the pixel format we wanted. EGLint size = matching; EGLConfig *configs = new EGLConfig [size]; - eglChooseConfig(dpy, props.properties(), configs, size, &matching); + eglChooseConfig(display(), props.properties(), configs, size, &matching); for (EGLint index = 0; index < size; ++index) { EGLint red, green, blue, alpha; - eglGetConfigAttrib(dpy, configs[index], EGL_RED_SIZE, &red); - eglGetConfigAttrib(dpy, configs[index], EGL_GREEN_SIZE, &green); - eglGetConfigAttrib(dpy, configs[index], EGL_BLUE_SIZE, &blue); - eglGetConfigAttrib(dpy, configs[index], EGL_ALPHA_SIZE, &alpha); + eglGetConfigAttrib(display(), configs[index], EGL_RED_SIZE, &red); + eglGetConfigAttrib(display(), configs[index], EGL_GREEN_SIZE, &green); + eglGetConfigAttrib(display(), configs[index], EGL_BLUE_SIZE, &blue); + eglGetConfigAttrib(display(), configs[index], EGL_ALPHA_SIZE, &alpha); if (red == props.value(EGL_RED_SIZE) && green == props.value(EGL_GREEN_SIZE) && blue == props.value(EGL_BLUE_SIZE) && @@ -179,7 +172,7 @@ bool QEglContext::createContext(QEglContext *shareContext, const QEglProperties if (shareContext && shareContext->ctx == EGL_NO_CONTEXT) shareContext = 0; if (shareContext) { - ctx = eglCreateContext(dpy, cfg, shareContext->ctx, contextProps.properties()); + ctx = eglCreateContext(display(), cfg, shareContext->ctx, contextProps.properties()); if (ctx == EGL_NO_CONTEXT) { qWarning() << "QEglContext::createContext(): Could not share context:" << errorString(eglGetError()); shareContext = 0; @@ -188,7 +181,7 @@ bool QEglContext::createContext(QEglContext *shareContext, const QEglProperties } } if (ctx == EGL_NO_CONTEXT) { - ctx = eglCreateContext(dpy, cfg, EGL_NO_CONTEXT, contextProps.properties()); + ctx = eglCreateContext(display(), cfg, EGL_NO_CONTEXT, contextProps.properties()); if (ctx == EGL_NO_CONTEXT) { qWarning() << "QEglContext::createContext(): Unable to create EGL context:" << errorString(eglGetError()); return false; @@ -204,16 +197,15 @@ void QEglContext::destroySurface(EGLSurface surface) if (surface != EGL_NO_SURFACE) { if (surface == currentSurface) doneCurrent(); - eglDestroySurface(dpy, surface); + eglDestroySurface(display(), surface); } } // Destroy the context. Note: this does not destroy the surface. -void QEglContext::destroy() +void QEglContext::destroyContext() { if (ctx != EGL_NO_CONTEXT && ownsContext) - eglDestroyContext(dpy, ctx); - dpy = EGL_NO_DISPLAY; + eglDestroyContext(display(), ctx); ctx = EGL_NO_CONTEXT; cfg = 0; } @@ -248,7 +240,7 @@ bool QEglContext::makeCurrent(EGLSurface surface) eglBindAPI(EGL_OPENVG_API); #endif - bool ok = eglMakeCurrent(dpy, surface, surface, ctx); + bool ok = eglMakeCurrent(display(), surface, surface, ctx); if (!ok) qWarning() << "QEglContext::makeCurrent():" << errorString(eglGetError()); return ok; @@ -277,7 +269,7 @@ bool QEglContext::doneCurrent() eglBindAPI(EGL_OPENVG_API); #endif - bool ok = eglMakeCurrent(dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + bool ok = eglMakeCurrent(display(), EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); if (!ok) qWarning() << "QEglContext::doneCurrent():" << errorString(eglGetError()); return ok; @@ -299,7 +291,7 @@ bool QEglContext::swapBuffers(EGLSurface surface) if(ctx == EGL_NO_CONTEXT) return false; - bool ok = eglSwapBuffers(dpy, surface); + bool ok = eglSwapBuffers(display(), surface); if (!ok) qWarning() << "QEglContext::swapBuffers():" << errorString(eglGetError()); return ok; @@ -338,7 +330,7 @@ void QEglContext::waitClient() // Query the value of a configuration attribute. bool QEglContext::configAttrib(int name, EGLint *value) const { - return eglGetConfigAttrib(dpy, cfg, name, value); + return eglGetConfigAttrib(display(), cfg, name, value); } // Retrieve all of the properties on "cfg". If zero, return @@ -350,34 +342,45 @@ QEglProperties QEglContext::configProperties(EGLConfig cfg) const QEglProperties props; for (int name = 0x3020; name <= 0x304F; ++name) { EGLint value; - if (name != EGL_NONE && eglGetConfigAttrib(dpy, cfg, name, &value)) + if (name != EGL_NONE && eglGetConfigAttrib(display(), cfg, name, &value)) props.setValue(name, value); } eglGetError(); // Clear the error state. return props; } -// Initialize and return the default display. -EGLDisplay QEglContext::defaultDisplay(QPaintDevice *device) +EGLDisplay QEglContext::display() { - static EGLDisplay dpy = EGL_NO_DISPLAY; - if (dpy == EGL_NO_DISPLAY) { - dpy = getDisplay(device); + static bool openedDisplay = false; + + if (!openedDisplay) { + dpy = eglGetDisplay(nativeDisplay()); + openedDisplay = true; + if (dpy == EGL_NO_DISPLAY) { + qWarning("QEglContext::display(): Falling back to EGL_DEFAULT_DISPLAY"); + dpy = eglGetDisplay(EGLNativeDisplayType(EGL_DEFAULT_DISPLAY)); + } if (dpy == EGL_NO_DISPLAY) { - qWarning() << "QEglContext::defaultDisplay(): Cannot open EGL display"; + qWarning("QEglContext::display(): Can't even open the default display"); return EGL_NO_DISPLAY; } + if (!eglInitialize(dpy, NULL, NULL)) { - qWarning() << "QEglContext::defaultDisplay(): Cannot initialize EGL display:" << errorString(eglGetError()); + qWarning() << "QEglContext::display(): Cannot initialize EGL display:" << errorString(eglGetError()); return EGL_NO_DISPLAY; } -#ifdef EGL_OPENGL_ES_API - eglBindAPI(EGL_OPENGL_ES_API); -#endif } + return dpy; } +#if !defined(Q_WS_X11) && !defined(Q_WS_WINCE) // WinCE & X11 implement this properly +EGLNativeDisplayType QEglContext::nativeDisplay() +{ + return EGL_DEFAULT_DISPLAY; +} +#endif + // Return the error string associated with a specific code. QString QEglContext::errorString(EGLint code) { @@ -410,10 +413,10 @@ void QEglContext::dumpAllConfigs() { QEglProperties props; EGLint count = 0; - if (!eglGetConfigs(dpy, 0, 0, &count) || count < 1) + if (!eglGetConfigs(display(), 0, 0, &count) || count < 1) return; EGLConfig *configs = new EGLConfig [count]; - eglGetConfigs(dpy, configs, count, &count); + eglGetConfigs(display(), configs, count, &count); for (EGLint index = 0; index < count; ++index) { props = configProperties(configs[index]); qWarning() << props.toString(); @@ -423,7 +426,7 @@ void QEglContext::dumpAllConfigs() QString QEglContext::extensions() { - const char* exts = eglQueryString(QEglContext::defaultDisplay(0), EGL_EXTENSIONS); + const char* exts = eglQueryString(QEglContext::display(), EGL_EXTENSIONS); return QString(QLatin1String(exts)); } @@ -431,7 +434,7 @@ bool QEglContext::hasExtension(const char* extensionName) { QList<QByteArray> extensions = QByteArray(reinterpret_cast<const char *> - (eglQueryString(QEglContext::defaultDisplay(0), EGL_EXTENSIONS))).split(' '); + (eglQueryString(QEglContext::display(), EGL_EXTENSIONS))).split(' '); return extensions.contains(extensionName); } diff --git a/src/gui/egl/qegl_p.h b/src/gui/egl/qegl_p.h index a7de9c8..87ed818 100644 --- a/src/gui/egl/qegl_p.h +++ b/src/gui/egl/qegl_p.h @@ -86,14 +86,12 @@ public: QEgl::API api() const { return apiType; } void setApi(QEgl::API api) { apiType = api; } - bool openDisplay(QPaintDevice *device); bool chooseConfig(const QEglProperties& properties, QEgl::PixelFormatMatch match = QEgl::ExactPixelFormat); bool createContext(QEglContext *shareContext = 0, const QEglProperties *properties = 0); + void destroyContext(); EGLSurface createSurface(QPaintDevice *device, const QEglProperties *properties = 0); void destroySurface(EGLSurface surface); - void destroy(); - bool makeCurrent(EGLSurface surface); bool doneCurrent(); bool lazyDoneCurrent(); @@ -108,7 +106,7 @@ public: static EGLint error() { return eglGetError(); } static QString errorString(EGLint code); - EGLDisplay display() const { return dpy; } + static EGLDisplay display(); EGLContext context() const { return ctx; } void setContext(EGLContext context) { ctx = context; ownsContext = false;} @@ -118,8 +116,6 @@ public: QEglProperties configProperties(EGLConfig cfg = 0) const; - static EGLDisplay defaultDisplay(QPaintDevice *device); - void dumpAllConfigs(); static QString extensions(); @@ -127,7 +123,6 @@ public: private: QEgl::API apiType; - EGLDisplay dpy; EGLContext ctx; EGLConfig cfg; EGLSurface currentSurface; @@ -135,7 +130,8 @@ private: bool ownsContext; bool sharing; - static EGLDisplay getDisplay(QPaintDevice *device); + static EGLDisplay dpy; + static EGLNativeDisplayType nativeDisplay(); static QEglContext *currentContext(QEgl::API api); static void setCurrentContext(QEgl::API api, QEglContext *context); diff --git a/src/gui/egl/qegl_qws.cpp b/src/gui/egl/qegl_qws.cpp index e999e0b..2a61beb 100644 --- a/src/gui/egl/qegl_qws.cpp +++ b/src/gui/egl/qegl_qws.cpp @@ -64,12 +64,6 @@ EGLSurface QEglContext::createSurface(QPaintDevice *device, const QEglProperties return EGL_NO_SURFACE; } -EGLDisplay QEglContext::getDisplay(QPaintDevice *device) -{ - Q_UNUSED(device); - return eglGetDisplay(EGLNativeDisplayType(EGL_DEFAULT_DISPLAY)); -} - static QScreen *screenForDevice(QPaintDevice *device) { QScreen *screen = qt_screen; diff --git a/src/gui/egl/qegl_symbian.cpp b/src/gui/egl/qegl_symbian.cpp index 44ecd19..5a010cd 100644 --- a/src/gui/egl/qegl_symbian.cpp +++ b/src/gui/egl/qegl_symbian.cpp @@ -78,22 +78,14 @@ EGLSurface QEglContext::createSurface(QPaintDevice *device, const QEglProperties props = 0; EGLSurface surf; if (devType == QInternal::Widget) - surf = eglCreateWindowSurface(dpy, cfg, windowDrawable, 0); + surf = eglCreateWindowSurface(dpy, cfg, windowDrawable, props); else - surf = eglCreatePixmapSurface(dpy, cfg, pixmapDrawable, 0); + surf = eglCreatePixmapSurface(dpy, cfg, pixmapDrawable, props); if (surf == EGL_NO_SURFACE) qWarning("QEglContext::createSurface(): Unable to create EGL surface, error = 0x%x", eglGetError()); return surf; } -EGLDisplay QEglContext::getDisplay(QPaintDevice *device) -{ - EGLDisplay dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY); - if (dpy == EGL_NO_DISPLAY) - qWarning("QEglContext::defaultDisplay(): Falling back to EGL_DEFAULT_DISPLAY"); - return dpy; -} - // Set pixel format and other properties based on a paint device. void QEglProperties::setPaintDeviceFormat(QPaintDevice *dev) { diff --git a/src/gui/egl/qegl_wince.cpp b/src/gui/egl/qegl_wince.cpp index 026a7b1..c9c9773 100644 --- a/src/gui/egl/qegl_wince.cpp +++ b/src/gui/egl/qegl_wince.cpp @@ -87,20 +87,15 @@ EGLSurface QEglContext::createSurface(QPaintDevice *device, const QEglProperties return surf; } -EGLDisplay QEglContext::getDisplay(QPaintDevice *device) +EGLNativeDisplayType QEglContext::nativeDisplay() { - EGLDisplay dpy = 0; HWND win = (static_cast<QWidget*>(device))->winId(); HDC myDc = GetDC(win); if (!myDc) { - qWarning("QEglContext::defaultDisplay(): WinCE display is not open"); + qWarning("QEglContext::nativeDisplay(): WinCE display is not open"); + return EGL_DEFAULT_DISPLAY; } - dpy = eglGetDisplay(EGLNativeDisplayType(myDc)); - if (dpy == EGL_NO_DISPLAY) { - qWarning("QEglContext::defaultDisplay(): Falling back to EGL_DEFAULT_DISPLAY"); - dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY); - } - return dpy; + return EGLNativeDisplayType(myDc); } // Set pixel format and other properties based on a paint device. diff --git a/src/gui/egl/qegl_x11.cpp b/src/gui/egl/qegl_x11.cpp index 2cf4e33..634ff13 100644 --- a/src/gui/egl/qegl_x11.cpp +++ b/src/gui/egl/qegl_x11.cpp @@ -93,15 +93,14 @@ EGLSurface QEglContext::createSurface(QPaintDevice *device, const QEglProperties return surf; } -EGLDisplay QEglContext::getDisplay(QPaintDevice *device) +EGLNativeDisplayType QEglContext::nativeDisplay() { - Q_UNUSED(device); Display *xdpy = QX11Info::display(); if (!xdpy) { qWarning("QEglContext::getDisplay(): X11 display is not open"); - return EGL_NO_DISPLAY; + return EGLNativeDisplayType(EGL_DEFAULT_DISPLAY); } - return eglGetDisplay(EGLNativeDisplayType(xdpy)); + return EGLNativeDisplayType(xdpy); } static int countBits(unsigned long mask) diff --git a/src/gui/egl/qeglproperties.cpp b/src/gui/egl/qeglproperties.cpp index 2915fb9..236ec37 100644 --- a/src/gui/egl/qeglproperties.cpp +++ b/src/gui/egl/qeglproperties.cpp @@ -60,7 +60,7 @@ QEglProperties::QEglProperties(EGLConfig cfg) props.append(EGL_NONE); for (int name = 0x3020; name <= 0x304F; ++name) { EGLint value; - if (name != EGL_NONE && eglGetConfigAttrib(QEglContext::defaultDisplay(0), cfg, name, &value)) + if (name != EGL_NONE && eglGetConfigAttrib(QEglContext::display(), cfg, name, &value)) setValue(name, value); } eglGetError(); // Clear the error state. @@ -273,12 +273,12 @@ static void addTag(QString& str, const QString& tag) void QEglProperties::dumpAllConfigs() { EGLint count = 0; - eglGetConfigs(QEglContext::defaultDisplay(0), 0, 0, &count); + eglGetConfigs(QEglContext::display(), 0, 0, &count); if (count < 1) return; EGLConfig *configs = new EGLConfig [count]; - eglGetConfigs(QEglContext::defaultDisplay(0), configs, count, &count); + eglGetConfigs(QEglContext::display(), configs, count, &count); for (EGLint index = 0; index < count; ++index) qWarning() << QEglProperties(configs[index]).toString(); delete [] configs; 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 b4e19d1..5735cd6 100644 --- a/src/gui/graphicsview/qgraphicsitem.cpp +++ b/src/gui/graphicsview/qgraphicsitem.cpp @@ -319,7 +319,7 @@ QGraphicsItem::keyPressEvent() and QGraphicsItem::keyReleaseEvent(). \value ItemClipsToShape The item clips to its own shape. The item cannot - draw or receive mouse, tablet, drag and drop or hover events outside ts + draw or receive mouse, tablet, drag and drop or hover events outside its shape. It is disabled by default. This behavior is enforced by QGraphicsView::drawItems() or QGraphicsScene::drawItems(). This flag was introduced in Qt 4.3. @@ -357,19 +357,22 @@ default, child items are stacked on top of the parent item. But setting this flag, the child will be stacked behind it. This flag is useful for drop shadow effects and for decoration objects that follow the parent - item's geometry without drawing on top of it. + item's geometry without drawing on top of it. This flag was introduced + in Qt 4.5. \value ItemUsesExtendedStyleOption The item makes use of either - \l{QStyleOptionGraphicsItem::}{exposedRect} or - \l{QStyleOptionGraphicsItem::}{matrix} in QStyleOptionGraphicsItem. By default, - the \l{QStyleOptionGraphicsItem::}{exposedRect} is initialized to the item's - boundingRect() and the \l{QStyleOptionGraphicsItem::}{matrix} is untransformed. - You can enable this flag for the style options to be set up with more - fine-grained values. - Note that QStyleOptionGraphicsItem::levelOfDetail is unaffected by this flag + \l{QStyleOptionGraphicsItem::} {exposedRect} or + \l{QStyleOptionGraphicsItem::} {matrix} in + QStyleOptionGraphicsItem. By default, the + \l{QStyleOptionGraphicsItem::} {exposedRect} is initialized to the + item's boundingRect() and the + \l{QStyleOptionGraphicsItem::}{matrix} is untransformed. You can + enable this flag for the style options to be set up with more + fine-grained values. Note that + QStyleOptionGraphicsItem::levelOfDetail is unaffected by this flag and always initialized to 1. Use - QStyleOptionGraphicsItem::levelOfDetailFromTransform() if you need a higher - value. + QStyleOptionGraphicsItem::levelOfDetailFromTransform() if you need + a higher value. This flag was introduced in Qt 4.6. \value ItemHasNoContents The item does not paint anything (i.e., calling paint() on the item has no effect). You should set this flag on items that @@ -387,9 +390,10 @@ used for Asian languages. This flag was introduced in Qt 4.6. - \value ItemNegativeZStacksBehindParent The item automatically stacks behind - it's parent if it's z-value is negative. This flag enables setZValue() to - toggle ItemStacksBehindParent. + \value ItemNegativeZStacksBehindParent The item automatically + stacks behind it's parent if it's z-value is negative. This flag + enables setZValue() to toggle ItemStacksBehindParent. This flag + was introduced in Qt 4.6. \value ItemIsPanel The item is a panel. A panel provides activation and contained focus handling. Only one panel can be active at a time (see @@ -410,12 +414,6 @@ /*! \enum QGraphicsItem::GraphicsItemChange - ItemVisibleHasChanged, - ItemEnabledHasChanged, - ItemSelectedHasChanged, - ItemParentHasChanged, - ItemSceneHasChanged - This enum describes the state changes that are notified by QGraphicsItem::itemChange(). The notifications are sent as the state changes, and in some cases, adjustments can be made (see the documentation @@ -643,9 +641,16 @@ are children of a modal panel are not blocked. The values are: - \value NonModal The panel is not modal and does not block input to other panels. - \value PanelModal The panel is modal to a single item hierarchy and blocks input to its parent pane, all grandparent panels, and all siblings of its parent and grandparent panels. - \value SceneModal The window is modal to the entire scene and blocks input to all panels. + + \value NonModal The panel is not modal and does not block input to + other panels. This is the default value for panels. + + \value PanelModal The panel is modal to a single item hierarchy + and blocks input to its parent pane, all grandparent panels, and + all siblings of its parent and grandparent panels. + + \value SceneModal The window is modal to the entire scene and + blocks input to all panels. \sa QGraphicsItem::setPanelModality(), QGraphicsItem::panelModality(), QGraphicsItem::ItemIsPanel */ @@ -668,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> @@ -1392,7 +1398,8 @@ QGraphicsItem::~QGraphicsItem() } delete d_ptr->transformData; - qt_dataStore()->data.remove(this); + if (QGraphicsItemCustomDataStore *dataStore = qt_dataStore()) + dataStore->data.remove(this); } /*! @@ -3172,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) { @@ -3441,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())); } @@ -3465,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..4c4bfaf 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; @@ -608,7 +609,7 @@ public: return item->type() == QGraphicsPixmapItem::Type && !(item->flags() & QGraphicsItem::ItemIsSelectable) && item->d_ptr->children.size() == 0; - //|| (item->d_ptr->isObject && qobject_cast<QmlGraphicsImage *>(q_func())); + //|| (item->d_ptr->isObject && qobject_cast<QDeclarativeImage *>(q_func())); } inline const QStyleOption *styleOption() const diff --git a/src/gui/graphicsview/qgraphicsscene.cpp b/src/gui/graphicsview/qgraphicsscene.cpp index 66707fc..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); } /*! @@ -801,7 +813,8 @@ void QGraphicsScenePrivate::setFocusItemHelper(QGraphicsItem *item, // do it ourselves. if (item) { for (int i = 0; i < views.size(); ++i) - views.at(i)->inputContext()->reset(); + if (views.at(i)->inputContext()) + views.at(i)->inputContext()->reset(); } } #endif //QT_NO_IM @@ -4238,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); @@ -4678,7 +4693,8 @@ void QGraphicsScenePrivate::drawSubtreeRecursive(QGraphicsItem *item, QPainter * if (widget) item->d_ptr->paintedViewBoundingRects.insert(widget, viewBoundingRect); viewBoundingRect.adjust(-1, -1, 1, 1); - drawItem = exposedRegion ? exposedRegion->intersects(viewBoundingRect) : !viewBoundingRect.isEmpty(); + drawItem = exposedRegion ? exposedRegion->intersects(viewBoundingRect) + : !viewBoundingRect.normalized().isEmpty(); if (!drawItem) { if (!itemHasChildren) return; @@ -5132,6 +5148,8 @@ void QGraphicsScenePrivate::processDirtyItemsRecursive(QGraphicsItem *item, bool } /*! + \obsolete + Paints the given \a items using the provided \a painter, after the background has been drawn, and before the foreground has been drawn. All painting is done in \e scene coordinates. Before @@ -5154,7 +5172,7 @@ void QGraphicsScenePrivate::processDirtyItemsRecursive(QGraphicsItem *item, bool \snippet doc/src/snippets/graphicssceneadditemsnippet.cpp 0 - \obsolete Since Qt 4.6, this function is not called anymore unless + Since Qt 4.6, this function is not called anymore unless the QGraphicsView::IndirectPainting flag is given as an Optimization flag. @@ -5710,8 +5728,15 @@ void QGraphicsScenePrivate::touchEventHandler(QTouchEvent *sceneTouchEvent) item->d_ptr->acceptedTouchBeginEvent = true; bool res = sendTouchBeginEvent(item, &touchEvent) && touchEvent.isAccepted(); - if (!res) + if (!res) { + // forget about these touch points, we didn't handle them + for (int i = 0; i < touchEvent.touchPoints().count(); ++i) { + const QTouchEvent::TouchPoint &touchPoint = touchEvent.touchPoints().at(i); + itemForTouchPointId.remove(touchPoint.id()); + sceneCurrentTouchPoints.remove(touchPoint.id()); + } ignoreSceneTouchEvent = false; + } break; } default: @@ -5889,37 +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) { - QGraphicsObject *item = items.at(j)->toGraphicsObject(); - if (!item) - continue; + 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); + + if (QGraphicsObject *itemobj = item->toGraphicsObject()) { QGraphicsItemPrivate *d = item->QGraphicsItem::d_func(); - if (d->gestureContext.contains(gestureType)) { - result.append(item); + 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); } } - 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) @@ -5927,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); } } @@ -6135,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); @@ -6193,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.cpp b/src/gui/graphicsview/qgraphicsview.cpp index 96b9373..1ced3d7 100644 --- a/src/gui/graphicsview/qgraphicsview.cpp +++ b/src/gui/graphicsview/qgraphicsview.cpp @@ -3400,6 +3400,13 @@ void QGraphicsView::paintEvent(QPaintEvent *event) if (!d->scene->d_func()->painterStateProtection) painter.setWorldTransform(viewTransform); } else { + // Make sure we don't have unpolished items before we draw + if (!d->scene->d_func()->unpolishedItems.isEmpty()) + d->scene->d_func()->_q_polishItems(); + // We reset updateAll here (after we've issued polish events) + // so that we can discard update requests coming from polishEvent(). + d->scene->d_func()->updateAll = false; + // Find all exposed items bool allItems = false; QList<QGraphicsItem *> itemList = d->findItems(d->exposedRegion, &allItems, viewTransform); @@ -3408,9 +3415,25 @@ void QGraphicsView::paintEvent(QPaintEvent *event) const int numItems = itemList.size(); QGraphicsItem **itemArray = &itemList[0]; // Relies on QList internals, but is perfectly valid. QStyleOptionGraphicsItem *styleOptionArray = d->allocStyleOptionsArray(numItems); + QTransform transform(Qt::Uninitialized); for (int i = 0; i < numItems; ++i) { - itemArray[i]->d_ptr->initStyleOption(&styleOptionArray[i], viewTransform, - d->exposedRegion, allItems); + QGraphicsItem *item = itemArray[i]; + QGraphicsItemPrivate *itemd = item->d_ptr.data(); + itemd->initStyleOption(&styleOptionArray[i], viewTransform, d->exposedRegion, allItems); + // Cache the item's area in view coordinates. + // Note that we have to do this here in case the base class implementation + // (QGraphicsScene::drawItems) is not called. If it is, we'll do this + // operation twice, but that's the price one has to pay for using indirect + // painting :-/. + const QRectF brect = adjustedItemEffectiveBoundingRect(item); + if (!itemd->itemIsUntransformable()) { + transform = item->sceneTransform(); + if (viewTransformed) + transform *= viewTransform; + } else { + transform = item->deviceTransform(viewTransform); + } + itemd->paintedViewBoundingRects.insert(d->viewport, transform.mapRect(brect).toRect()); } // Draw the items. drawItems(&painter, numItems, itemArray, styleOptionArray); @@ -3609,6 +3632,8 @@ void QGraphicsView::drawForeground(QPainter *painter, const QRectF &rect) } /*! + \obsolete + Draws the items \a items in the scene using \a painter, after the background and before the foreground are drawn. \a numItems is the number of items in \a items and options in \a options. \a options is a list of @@ -3617,7 +3642,7 @@ void QGraphicsView::drawForeground(QPainter *painter, const QRectF &rect) The default implementation calls the scene's drawItems() function. - \obsolete Since Qt 4.6, this function is not called anymore unless + Since Qt 4.6, this function is not called anymore unless the QGraphicsView::IndirectPainting flag is given as an Optimization flag. 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/gui.pro b/src/gui/gui.pro index e57aa60..b03977c 100644 --- a/src/gui/gui.pro +++ b/src/gui/gui.pro @@ -51,8 +51,27 @@ contains(DEFINES,QT_EVAL):include($$QT_SOURCE_TREE/src/corelib/eval.pri) QMAKE_DYNAMIC_LIST_FILE = $$PWD/QtGui.dynlist DEFINES += Q_INTERNAL_QAPP_SRC -symbian:TARGET.UID3=0x2001B2DD +symbian: { + TARGET.UID3=0x2001B2DD + + # ro-section in gui can exceed default allocated space, so move rw-section a little further + QMAKE_LFLAGS.ARMCC += --rw-base 0x800000 + QMAKE_LFLAGS.GCCE += -Tdata 0xC00000 + + # Partial upgrade SIS file + vendorinfo = \ + "&EN" \ + "; Localised Vendor name" \ + "%{\"Nokia, Qt\"}" \ + " " \ + "; Unique Vendor name" \ + ":\"Nokia, Qt\"" \ + " " + pu_header = "; Partial upgrade package for testing QtGui changes without reinstalling everything" \ + "$${LITERAL_HASH}{\"Qt gui\"}, (0x2001E61C), $${QT_MAJOR_VERSION},$${QT_MINOR_VERSION},$${QT_PATCH_VERSION}, TYPE=PU" + partial_upgrade.pkg_prerules = pu_header vendorinfo + partial_upgrade.sources = qtgui.dll + partial_upgrade.path = c:/sys/bin + DEPLOYMENT = partial_upgrade $$DEPLOYMENT +} -# ro-section in gui can exceed default allocated space, so more rw-section little further -symbian-sbsv2: QMAKE_LFLAGS.ARMCC += --rw-base 0x800000 -symbian: QMAKE_LFLAGS.GCCE += -Tdata 0xC00000 diff --git a/src/gui/image/image.pri b/src/gui/image/image.pri index 10a073b..1aee4f0 100644 --- a/src/gui/image/image.pri +++ b/src/gui/image/image.pri @@ -101,6 +101,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 \ @@ -117,8 +118,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/qicon.cpp b/src/gui/image/qicon.cpp index ac1d303..bf6eb8d 100644 --- a/src/gui/image/qicon.cpp +++ b/src/gui/image/qicon.cpp @@ -104,6 +104,15 @@ QT_BEGIN_NAMESPACE static QBasicAtomicInt serialNumCounter = Q_BASIC_ATOMIC_INITIALIZER(1); +static void qt_cleanup_icon_cache(); +typedef QCache<QString, QIcon> IconCache; +Q_GLOBAL_STATIC_WITH_INITIALIZER(IconCache, qtIconCache, qAddPostRoutine(qt_cleanup_icon_cache)) + +static void qt_cleanup_icon_cache() +{ + qtIconCache()->clear(); +} + QIconPrivate::QIconPrivate() : engine(0), ref(1), serialNum(serialNumCounter.fetchAndAddRelaxed(1)), @@ -963,15 +972,13 @@ QString QIcon::themeName() */ QIcon QIcon::fromTheme(const QString &name, const QIcon &fallback) { - static QCache <QString, QIcon> iconCache; - QIcon icon; - if (iconCache.contains(name)) { - icon = *iconCache.object(name); + if (qtIconCache()->contains(name)) { + icon = *qtIconCache()->object(name); } else { QIcon *cachedIcon = new QIcon(new QIconLoaderEngine(name)); - iconCache.insert(name, cachedIcon); + qtIconCache()->insert(name, cachedIcon); icon = *cachedIcon; } 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 58bf868..742be86 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/qimagepixmapcleanuphooks.cpp b/src/gui/image/qimagepixmapcleanuphooks.cpp index ace4bb6..517fcb0 100644 --- a/src/gui/image/qimagepixmapcleanuphooks.cpp +++ b/src/gui/image/qimagepixmapcleanuphooks.cpp @@ -122,19 +122,32 @@ void QImagePixmapCleanupHooks::executeImageHooks(qint64 key) qt_image_cleanup_hook_64(key); } -void QImagePixmapCleanupHooks::enableCleanupHooks(const QPixmap &pixmap) -{ - enableCleanupHooks(const_cast<QPixmap &>(pixmap).data_ptr().data()); -} void QImagePixmapCleanupHooks::enableCleanupHooks(QPixmapData *pixmapData) { pixmapData->is_cached = true; } +void QImagePixmapCleanupHooks::enableCleanupHooks(const QPixmap &pixmap) +{ + enableCleanupHooks(const_cast<QPixmap &>(pixmap).data_ptr().data()); +} + void QImagePixmapCleanupHooks::enableCleanupHooks(const QImage &image) { const_cast<QImage &>(image).data_ptr()->is_cached = true; } +bool QImagePixmapCleanupHooks::isImageCached(const QImage &image) +{ + return const_cast<QImage &>(image).data_ptr()->is_cached; +} + +bool QImagePixmapCleanupHooks::isPixmapCached(const QPixmap &pixmap) +{ + return const_cast<QPixmap&>(pixmap).data_ptr().data()->is_cached; +} + + + QT_END_NAMESPACE diff --git a/src/gui/image/qimagepixmapcleanuphooks_p.h b/src/gui/image/qimagepixmapcleanuphooks_p.h index 88dd3a6..eae11f4 100644 --- a/src/gui/image/qimagepixmapcleanuphooks_p.h +++ b/src/gui/image/qimagepixmapcleanuphooks_p.h @@ -72,6 +72,9 @@ public: static void enableCleanupHooks(const QPixmap &pixmap); static void enableCleanupHooks(QPixmapData *pixmapData); + static bool isImageCached(const QImage &image); + static bool isPixmapCached(const QPixmap &pixmap); + // Gets called when a pixmap data is about to be modified: void addPixmapDataModificationHook(_qt_pixmap_cleanup_hook_pmd); diff --git a/src/gui/image/qimagereader.cpp b/src/gui/image/qimagereader.cpp index c9e015c..9320cfc 100644 --- a/src/gui/image/qimagereader.cpp +++ b/src/gui/image/qimagereader.cpp @@ -263,25 +263,37 @@ static QImageIOHandler *createReadHandlerHelper(QIODevice *device, device->seek(pos); } - if (!handler && !testFormat.isEmpty() && autoDetectImageFormat && !ignoresFormatAndExtension) { + if (!handler && !testFormat.isEmpty() && !ignoresFormatAndExtension) { // check if any plugin supports the format (they are not allowed to // read from the device yet). const qint64 pos = device ? device->pos() : 0; - for (int i = 0; i < keys.size(); ++i) { - if (i != suffixPluginIndex) { - QImageIOPlugin *plugin = qobject_cast<QImageIOPlugin *>(l->instance(keys.at(i))); - if (plugin && plugin->capabilities(device, testFormat) & QImageIOPlugin::CanRead) { + + if (autoDetectImageFormat) { + for (int i = 0; i < keys.size(); ++i) { + if (i != suffixPluginIndex) { + QImageIOPlugin *plugin = qobject_cast<QImageIOPlugin *>(l->instance(keys.at(i))); + if (plugin && plugin->capabilities(device, testFormat) & QImageIOPlugin::CanRead) { #ifdef QIMAGEREADER_DEBUG - qDebug() << "QImageReader::createReadHandler: the" << keys.at(i) << "plugin can read this format"; + qDebug() << "QImageReader::createReadHandler: the" << keys.at(i) << "plugin can read this format"; #endif - handler = plugin->create(device, testFormat); - break; + handler = plugin->create(device, testFormat); + break; + } } } + } else { + QImageIOPlugin *plugin = qobject_cast<QImageIOPlugin *>(l->instance(QLatin1String(testFormat))); + if (plugin && plugin->capabilities(device, testFormat) & QImageIOPlugin::CanRead) { +#ifdef QIMAGEREADER_DEBUG + qDebug() << "QImageReader::createReadHandler: the" << testFormat << "plugin can read this format"; +#endif + handler = plugin->create(device, testFormat); + } } if (device && !device->isSequential()) device->seek(pos); } + #endif // QT_NO_LIBRARY // if we don't have a handler yet, check if we have built-in support for diff --git a/src/gui/image/qnativeimage.cpp b/src/gui/image/qnativeimage.cpp index 2226901..8446387 100644 --- a/src/gui/image/qnativeimage.cpp +++ b/src/gui/image/qnativeimage.cpp @@ -182,7 +182,7 @@ QNativeImage::QNativeImage(int width, int height, QImage::Format format,bool /* qWarning() << "Error while marking the shared memory segment to be destroyed"; ok = (xshminfo.shmaddr != (char*)-1); if (ok) - image = QImage((uchar *)xshmimg->data, width, height, systemFormat()); + image = QImage((uchar *)xshmimg->data, width, height, format); } xshminfo.readOnly = false; if (ok) 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 2e2e9e4..985380a 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 @@ -1670,10 +1690,9 @@ QPixmap QPixmap::transformed(const QMatrix &matrix, Qt::TransformationMode mode) \o The hasAlphaChannel() returns true if the pixmap has a format that - respects the alpha channel, otherwise returns false, while the - hasAlpha() function returns true if the pixmap has an alpha - channel \e or a mask (otherwise false). The mask() function returns - the mask as a QBitmap object, which can be set using setMask(). + respects the alpha channel, otherwise returns false. The hasAlpha(), + setMask() and mask() functions are legacy and should not be used. + They are potentially very slow. The createHeuristicMask() function creates and returns a 1-bpp heuristic mask (i.e. a QBitmap) for this pixmap. It works by @@ -1760,6 +1779,8 @@ QPixmap QPixmap::transformed(const QMatrix &matrix, Qt::TransformationMode mode) Returns true if this pixmap has an alpha channel, \e or has a mask, otherwise returns false. + \warning This is potentially an expensive operation. + \sa hasAlphaChannel(), mask() */ bool QPixmap::hasAlpha() 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/qpixmapfilter.cpp b/src/gui/image/qpixmapfilter.cpp index 37a6a18..2792e45 100644 --- a/src/gui/image/qpixmapfilter.cpp +++ b/src/gui/image/qpixmapfilter.cpp @@ -422,6 +422,9 @@ void QPixmapConvolutionFilter::draw(QPainter *painter, const QPointF &p, const Q if(d->kernelWidth<=0 || d->kernelHeight <= 0) return; + if (src.isNull()) + return; + QPixmapFilter *filter = painter->paintEngine() && painter->paintEngine()->isExtended() ? static_cast<QPaintEngineEx *>(painter->paintEngine())->pixmapFilter(type(), this) : 0; QPixmapConvolutionFilter *convolutionFilter = static_cast<QPixmapConvolutionFilter*>(filter); @@ -710,7 +713,8 @@ void expblur(QImage &img, qreal radius, bool improvedQuality = false, int transp radius *= qreal(0.5); Q_ASSERT(img.format() == QImage::Format_ARGB32_Premultiplied - || img.format() == QImage::Format_RGB32); + || img.format() == QImage::Format_RGB32 + || img.format() == QImage::Format_Indexed8); // choose the alpha such that pixels at radius distance from a fully // saturated pixel will have an alpha component of no greater than @@ -902,6 +906,9 @@ void QPixmapBlurFilter::draw(QPainter *painter, const QPointF &p, const QPixmap if (!painter->isActive()) return; + if (src.isNull()) + return; + QRectF srcRect = rect; if (srcRect.isNull()) srcRect = src.rect(); @@ -1082,6 +1089,10 @@ void QPixmapColorizeFilter::setStrength(qreal strength) void QPixmapColorizeFilter::draw(QPainter *painter, const QPointF &dest, const QPixmap &src, const QRectF &srcRect) const { Q_D(const QPixmapColorizeFilter); + + if (src.isNull()) + return; + QPixmapFilter *filter = painter->paintEngine() && painter->paintEngine()->isExtended() ? static_cast<QPaintEngineEx *>(painter->paintEngine())->pixmapFilter(type(), this) : 0; QPixmapColorizeFilter *colorizeFilter = static_cast<QPixmapColorizeFilter*>(filter); @@ -1312,6 +1323,10 @@ void QPixmapDropShadowFilter::draw(QPainter *p, const QRectF &src) const { Q_D(const QPixmapDropShadowFilter); + + if (px.isNull()) + return; + QPixmapFilter *filter = p->paintEngine() && p->paintEngine()->isExtended() ? static_cast<QPaintEngineEx *>(p->paintEngine())->pixmapFilter(type(), this) : 0; QPixmapDropShadowFilter *dropShadowFilter = static_cast<QPixmapDropShadowFilter*>(filter); 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/qcoefepinputcontext_s60.cpp b/src/gui/inputmethod/qcoefepinputcontext_s60.cpp index 2b91711..1ac8ace 100644 --- a/src/gui/inputmethod/qcoefepinputcontext_s60.cpp +++ b/src/gui/inputmethod/qcoefepinputcontext_s60.cpp @@ -113,7 +113,7 @@ void QCoeFepInputContext::update() updateHints(false); // For pre-5.0 SDKs, we don't do text updates on S60 side. - if (QSysInfo::s60Version() != QSysInfo::SV_S60_5_0) { + if (QSysInfo::s60Version() < QSysInfo::SV_S60_5_0) { return; } @@ -740,6 +740,9 @@ void QCoeFepInputContext::GetScreenCoordinatesForFepL(TPoint& aLeftSideOfBaseLin void QCoeFepInputContext::DoCommitFepInlineEditL() { commitCurrentString(false); + if (QSysInfo::s60Version() > QSysInfo::SV_S60_5_0) + ReportAknEdStateEvent(QT_EAknCursorPositionChanged); + } void QCoeFepInputContext::commitCurrentString(bool cancelFepTransaction) 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/qabstractitemview.cpp b/src/gui/itemviews/qabstractitemview.cpp index cbd9a8a..bc6db90 100644 --- a/src/gui/itemviews/qabstractitemview.cpp +++ b/src/gui/itemviews/qabstractitemview.cpp @@ -1540,6 +1540,11 @@ bool QAbstractItemView::event(QEvent *event) case QEvent::FontChange: d->doDelayedItemsLayout(); // the size of the items will change break; +#ifdef QT_SOFTKEYS_ENABLED + case QEvent::LanguageChange: + d->doneSoftKey->setText(QSoftKeyManager::standardSoftKeyText(QSoftKeyManager::DoneSoftKey)); + break; +#endif default: break; } @@ -2114,6 +2119,11 @@ void QAbstractItemView::focusOutEvent(QFocusEvent *event) Q_D(QAbstractItemView); QAbstractScrollArea::focusOutEvent(event); d->viewport->update(); + +#ifdef QT_SOFTKEYS_ENABLED + if(!hasEditFocus()) + removeAction(d->doneSoftKey); +#endif } /*! @@ -2139,7 +2149,12 @@ void QAbstractItemView::keyPressEvent(QKeyEvent *event) if (!hasEditFocus()) { setEditFocus(true); #ifdef QT_SOFTKEYS_ENABLED - addAction(d->doneSoftKey); + // If we can't keypad navigate to any direction, there is no sense to add + // "Done" softkey, since it basically does nothing when there is + // only one widget in screen + if(QWidgetPrivate::canKeypadNavigate(Qt::Horizontal) + || QWidgetPrivate::canKeypadNavigate(Qt::Vertical)) + addAction(d->doneSoftKey); #endif return; } @@ -2155,6 +2170,26 @@ void QAbstractItemView::keyPressEvent(QKeyEvent *event) event->ignore(); } return; + case Qt::Key_Down: + case Qt::Key_Up: + // Let's ignore vertical navigation events, only if there is no other widget + // what can take the focus in vertical direction. This means widget can handle navigation events + // even the widget don't have edit focus, and there is no other widget in requested direction. + if(QApplication::keypadNavigationEnabled() && !hasEditFocus() + && QWidgetPrivate::canKeypadNavigate(Qt::Vertical)) { + event->ignore(); + return; + } + break; + case Qt::Key_Left: + case Qt::Key_Right: + // Similar logic as in up and down events + if(QApplication::keypadNavigationEnabled() && !hasEditFocus() + && (QWidgetPrivate::canKeypadNavigate(Qt::Horizontal) || QWidgetPrivate::inTabWidget(this))) { + event->ignore(); + return; + } + break; default: if (QApplication::keypadNavigationEnabled() && !hasEditFocus()) { event->ignore(); @@ -2240,7 +2275,7 @@ void QAbstractItemView::keyPressEvent(QKeyEvent *event) case Qt::Key_Down: case Qt::Key_Up: #ifdef QT_KEYPAD_NAVIGATION - if (QApplication::keypadNavigationEnabled()) { + if (QApplication::keypadNavigationEnabled() && QWidgetPrivate::canKeypadNavigate(Qt::Vertical)) { event->accept(); // don't change focus break; } @@ -2248,8 +2283,10 @@ void QAbstractItemView::keyPressEvent(QKeyEvent *event) case Qt::Key_Left: case Qt::Key_Right: #ifdef QT_KEYPAD_NAVIGATION - if (QApplication::navigationMode() == Qt::NavigationModeKeypadDirectional) { - event->accept(); // don't change horizontal focus in directional mode + if (QApplication::navigationMode() == Qt::NavigationModeKeypadDirectional + && (QWidgetPrivate::canKeypadNavigate(Qt::Horizontal) + || (QWidgetPrivate::inTabWidget(this) && d->model->columnCount(d->root) > 1))) { + event->accept(); // don't change focus break; } #endif // QT_KEYPAD_NAVIGATION diff --git a/src/gui/itemviews/qabstractproxymodel.cpp b/src/gui/itemviews/qabstractproxymodel.cpp index 40345a7..43a1327 100644 --- a/src/gui/itemviews/qabstractproxymodel.cpp +++ b/src/gui/itemviews/qabstractproxymodel.cpp @@ -127,6 +127,7 @@ void QAbstractProxyModel::setSourceModel(QAbstractItemModel *sourceModel) } else { d->model = QAbstractItemModelPrivate::staticEmptyModel(); } + d->roleNames = d->model->roleNames(); } /*! 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/qlistview.cpp b/src/gui/itemviews/qlistview.cpp index 19b1e8c..b2def39 100644 --- a/src/gui/itemviews/qlistview.cpp +++ b/src/gui/itemviews/qlistview.cpp @@ -2160,7 +2160,7 @@ void QListModeViewBase::scrollContentsBy(int dx, int dy, bool scrollElasticBand) } else { if (flowPositions.isEmpty()) return; - const int max = flowPositions.count() - 1; + const int max = scrollValueMap.count() - 1; if (vertical && flow() == QListView::TopToBottom && dy != 0) { int currentValue = qBound(0, verticalValue, max); int previousValue = qBound(0, currentValue + dy, max); 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 d0fa22d..37168eb 100644 --- a/src/gui/itemviews/qtreeview.cpp +++ b/src/gui/itemviews/qtreeview.cpp @@ -2474,10 +2474,11 @@ void QTreeView::rowsInserted(const QModelIndex &parent, int start, int end) QVector<QTreeViewItem> insertedItems(delta); for (int i = 0; i < delta; ++i) { - insertedItems[i].index = d->model->index(i + start, 0, parent); - insertedItems[i].level = childLevel; - insertedItems[i].hasChildren = d->hasVisibleChildren(insertedItems[i].index); - insertedItems[i].hasMoreSiblings = !((i == delta - 1) && (parentRowCount == end +1)); + QTreeViewItem &item = insertedItems[i]; + item.index = d->model->index(i + start, 0, parent); + item.level = childLevel; + item.hasChildren = d->hasVisibleChildren(item.index); + item.hasMoreSiblings = !((i == delta - 1) && (parentRowCount == end +1)); } if (d->viewItems.isEmpty()) d->defaultItemHeight = indexRowSizeHint(insertedItems[0].index); @@ -3769,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 51167d4..96892d2 100644 --- a/src/gui/kernel/kernel.pri +++ b/src/gui/kernel/kernel.pri @@ -237,6 +237,7 @@ embedded_lite { 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 94f1863..455b2c9 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; } @@ -927,7 +940,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. @@ -1034,6 +1047,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; @@ -5258,10 +5280,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; @@ -5701,6 +5733,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 e8b821af..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); @@ -2143,6 +2168,7 @@ QApplicationPrivate::globalEventProcessor(EventHandlerCallRef er, EventRef event } if (wheel_deltaX || wheel_deltaY) { +#ifndef QT_NO_WHEELEVENT if (wheel_deltaX) { QWheelEvent qwe(plocal, p, wheel_deltaX, buttons, modifiers, Qt::Horizontal); QApplication::sendSpontaneousEvent(widget, &qwe); @@ -2165,6 +2191,7 @@ QApplicationPrivate::globalEventProcessor(EventHandlerCallRef er, EventRef event handled_event = false; } } +#endif // QT_NO_WHEELEVENT } else { #ifdef QMAC_SPEAK_TO_ME const int speak_keys = Qt::AltModifier | Qt::ShiftModifier; @@ -2455,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 @@ -2717,6 +2766,7 @@ int QApplication::keyboardInputInterval() return QApplicationPrivate::keyboard_input_time; } +#ifndef QT_NO_WHEELEVENT void QApplication::setWheelScrollLines(int n) { QApplicationPrivate::wheel_scroll_lines = n; @@ -2726,6 +2776,7 @@ int QApplication::wheelScrollLines() { return QApplicationPrivate::wheel_scroll_lines; } +#endif void QApplication::setEffectEnabled(Qt::UIEffect effect, bool enable) { @@ -2888,9 +2939,11 @@ bool QApplicationPrivate::qt_mac_apply_settings() QApplication::cursorFlashTime()).toInt(); QApplication::setCursorFlashTime(num); +#ifndef QT_NO_WHEELEVENT num = settings.value(QLatin1String("wheelScrollLines"), QApplication::wheelScrollLines()).toInt(); QApplication::setWheelScrollLines(num); +#endif QString colorspec = settings.value(QLatin1String("colorSpec"), QVariant(QLatin1String("default"))).toString(); @@ -3002,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 273e9ea..5172828 100644 --- a/src/gui/kernel/qapplication_p.h +++ b/src/gui/kernel/qapplication_p.h @@ -432,7 +432,9 @@ public: static int cursor_flash_time; static int mouse_double_click_time; static int keyboard_input_time; +#ifndef QT_NO_WHEELEVENT static int wheel_scroll_lines; +#endif static bool animate_ui; static bool animate_menu; @@ -462,6 +464,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 @@ -529,6 +537,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 bf3ad71..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) @@ -597,7 +597,9 @@ TKeyResponse QSymbianControl::OfferKeyEvent(const TKeyEvent& keyEvent, TEventCod TUint s60Keysym = QApplicationPrivate::resolveS60ScanCode(keyEvent.iScanCode, keyEvent.iCode); int keyCode; - if (s60Keysym >= 0x20 && s60Keysym < ENonCharacterKeyBase) { + if (s60Keysym == EKeyNull){ //some key events have 0 in iCode, for them iScanCode should be used + keyCode = qt_keymapper_private()->mapS60ScanCodesToQt(keyEvent.iScanCode); + } else if (s60Keysym >= 0x20 && s60Keysym < ENonCharacterKeyBase) { // Normal characters keys. keyCode = s60Keysym; } else { @@ -1146,6 +1148,10 @@ void qt_init(QApplicationPrivate * /* priv */, int) #endif S60->wsSession().SetAutoFlush(ETrue); +#ifdef Q_SYMBIAN_WINDOW_SIZE_CACHE + TRAP_IGNORE(S60->wsSession().EnableWindowSizeCacheL()); +#endif + S60->updateScreenSize(); diff --git a/src/gui/kernel/qapplication_win.cpp b/src/gui/kernel/qapplication_win.cpp index 3355272..131b9bb 100644 --- a/src/gui/kernel/qapplication_win.cpp +++ b/src/gui/kernel/qapplication_win.cpp @@ -928,7 +928,11 @@ const QString qt_reg_winclass(QWidget *w) // register window class uint style; bool icon; QString cname; - if (flags & Qt::MSWindowsOwnDC) { + if (qt_widget_private(w)->isGLWidget) { + cname = QLatin1String("QGLWidget"); + style = CS_DBLCLKS; + icon = true; + } else if (flags & Qt::MSWindowsOwnDC) { cname = QLatin1String("QWidgetOwnDC"); style = CS_DBLCLKS; #ifndef Q_WS_WINCE @@ -1021,7 +1025,7 @@ const QString qt_reg_winclass(QWidget *w) // register window class } wc.hCursor = 0; #ifndef Q_WS_WINCE - wc.hbrBackground = (HBRUSH)GetSysColorBrush(COLOR_WINDOW); + wc.hbrBackground = qt_widget_private(w)->isGLWidget ? 0 : (HBRUSH)GetSysColorBrush(COLOR_WINDOW); #else wc.hbrBackground = 0; #endif @@ -1901,8 +1905,13 @@ LRESULT CALLBACK QtWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam break; if (!msg.wParam) { +#ifdef Q_WS_WINCE + // On Windows CE, lParam parameter is a constant, not a char pointer. + if (msg.lParam == INI_INTL) { +#else QString area = QString::fromWCharArray((wchar_t*)msg.lParam); if (area == QLatin1String("intl")) { +#endif QLocalePrivate::updateSystemPrivate(); if (!widget->testAttribute(Qt::WA_SetLocale)) widget->dptr()->setLocale_helper(QLocale(), true); @@ -2547,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; @@ -2969,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); @@ -3616,13 +3639,19 @@ bool QETWidget::translatePaintEvent(const MSG &msg) return true; setAttribute(Qt::WA_PendingUpdate, false); - const QRegion dirtyInBackingStore(qt_dirtyRegion(this)); - // Make sure the invalidated region contains the region we're about to repaint. - // BeginPaint will set the clip to the invalidated region and it is impossible - // to enlarge it afterwards (only shrink it). Using GetDCEx is not suffient - // as it may return an invalid context (especially on Windows Vista). - if (!dirtyInBackingStore.isEmpty()) - InvalidateRgn(internalWinId(), dirtyInBackingStore.handle(), false); + + if (d_func()->isGLWidget) { + if (d_func()->usesDoubleBufferedGLContext) + InvalidateRect(internalWinId(), 0, false); + } else { + const QRegion dirtyInBackingStore(qt_dirtyRegion(this)); + // Make sure the invalidated region contains the region we're about to repaint. + // BeginPaint will set the clip to the invalidated region and it is impossible + // to enlarge it afterwards (only shrink it). Using GetDCEx is not suffient + // as it may return an invalid context (especially on Windows Vista). + if (!dirtyInBackingStore.isEmpty()) + InvalidateRgn(internalWinId(), dirtyInBackingStore.handle(), false); + } PAINTSTRUCT ps; d_func()->hd = BeginPaint(internalWinId(), &ps); diff --git a/src/gui/kernel/qapplication_x11.cpp b/src/gui/kernel/qapplication_x11.cpp index 2a1f655..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? :/ @@ -944,10 +944,12 @@ bool QApplicationPrivate::x11_apply_settings() QApplication::cursorFlashTime()).toInt(); QApplication::setCursorFlashTime(num); +#ifndef QT_NO_WHEELEVENT num = settings.value(QLatin1String("wheelScrollLines"), QApplication::wheelScrollLines()).toInt(); QApplication::setWheelScrollLines(num); +#endif QString colorspec = settings.value(QLatin1String("colorSpec"), QVariant(QLatin1String("default"))).toString(); @@ -2215,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) { @@ -4401,8 +4382,10 @@ bool QETWidget::translateWheelEvent(int global_x, int global_y, int delta, QWidget* popup = qApp->activePopupWidget(); if (popup && window() != popup) popup->close(); +#ifndef QT_NO_WHEELEVENT QWheelEvent e(pos, globalPos, delta, buttons, modifiers, orient); if (QApplication::sendSpontaneousEvent(widget, &e)) +#endif return true; } @@ -4413,8 +4396,10 @@ bool QETWidget::translateWheelEvent(int global_x, int global_y, int delta, QWidget* popup = qApp->activePopupWidget(); if (popup && widget != popup) popup->hide(); +#ifndef QT_NO_WHEELEVENT QWheelEvent e(pos, globalPos, delta, buttons, modifiers, orient); if (QApplication::sendSpontaneousEvent(widget, &e)) +#endif return true; } return false; @@ -5313,6 +5298,7 @@ int QApplication::keyboardInputInterval() return QApplicationPrivate::keyboard_input_time; } +#ifndef QT_NO_WHEELEVENT void QApplication::setWheelScrollLines(int n) { QApplicationPrivate::wheel_scroll_lines = n; @@ -5322,6 +5308,7 @@ int QApplication::wheelScrollLines() { return QApplicationPrivate::wheel_scroll_lines; } +#endif void QApplication::setEffectEnabled(Qt::UIEffect effect, bool enable) { diff --git a/src/gui/kernel/qclipboard_mac.cpp b/src/gui/kernel/qclipboard_mac.cpp index f3a971d..49a6cc8 100644 --- a/src/gui/kernel/qclipboard_mac.cpp +++ b/src/gui/kernel/qclipboard_mac.cpp @@ -388,6 +388,18 @@ QMacPasteboard::setMimeData(QMimeData *mime_src) clear_helper(); QStringList formats = mime_src->formats(); +#ifdef QT_MAC_USE_COCOA + // QMimeData sub classes reimplementing the formats() might not expose the + // temporary "application/x-qt-mime-type-name" mimetype. So check the existence + // of this mime type while doing drag and drop. + QString dummyMimeType(QLatin1String("application/x-qt-mime-type-name")); + if (!formats.contains(dummyMimeType)) { + QByteArray dummyType = mime_src->data(dummyMimeType); + if (!dummyType.isEmpty()) { + formats.append(dummyMimeType); + } + } +#endif for(int f = 0; f < formats.size(); ++f) { QString mimeType = formats.at(f); for (QList<QMacPasteboardMime *>::Iterator it = availableConverters.begin(); it != availableConverters.end(); ++it) { 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 2c35be2..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 @@ -828,6 +807,7 @@ extern "C" { deltaZ = qBound(-120, int([theEvent deltaZ] * 10000), 120); } +#ifndef QT_NO_WHEELEVENT if (deltaX != 0) { QWheelEvent qwe(qlocal, qglobal, deltaX, buttons, keyMods, Qt::Horizontal); qt_sendSpontaneousEvent(widgetToGetMouse, &qwe); @@ -868,6 +848,8 @@ extern "C" { wheelOK = qwe2.isAccepted(); } } +#endif //QT_NO_WHEELEVENT + if (!wheelOK) { return [super scrollWheel:theEvent]; } @@ -983,6 +965,8 @@ extern "C" { - (void)frameDidChange:(NSNotification *)note { Q_UNUSED(note); + if (!qwidget) + return; if (qwidget->isWindow()) return; NSRect newFrame = [self frame]; @@ -1006,7 +990,7 @@ extern "C" { { QMacCocoaAutoReleasePool pool; [super setEnabled:flag]; - if (qwidget->isEnabled() != flag) + if (qwidget && qwidget->isEnabled() != flag) qwidget->setEnabled(flag); } @@ -1017,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; @@ -1024,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()) @@ -1059,6 +1047,12 @@ extern "C" { return qwidget; } +- (void) qt_clearQWidget +{ + qwidget = 0; + qwidgetprivate = 0; +} + - (BOOL)qt_leftButtonIsRightButton { return leftButtonIsRightButton; @@ -1112,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); } @@ -1122,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; @@ -1317,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. @@ -1404,7 +1406,7 @@ Qt::DropAction QDragManager::drag(QDrag *o) // setup the data QMacPasteboard dragBoard((CFStringRef) NSDragPboard, QMacPasteboardMime::MIME_DND); - dragPrivate()->data->setData(QLatin1String("application/x-qt-mime-type-name"), QByteArray()); + dragPrivate()->data->setData(QLatin1String("application/x-qt-mime-type-name"), QByteArray("dummy")); dragBoard.setMimeData(dragPrivate()->data); // create the image 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 1c2b845..3989979 100644 --- a/src/gui/kernel/qdnd_p.h +++ b/src/gui/kernel/qdnd_p.h @@ -261,13 +261,11 @@ public: #endif private: - QPixmap *pm_cursor; - int n_cursor; #if defined(Q_WS_QWS) || defined(Q_WS_LITE) Qt::DropAction currentActionForOverrideCursor; #endif #ifdef Q_OS_SYMBIAN -#ifndef QT_NO_CURSOR +#ifndef QT_NO_CURSOR QCursor overrideCursor; #endif #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 c7c7caf..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 @@ -492,6 +497,14 @@ static bool IsMouseOrKeyEvent( NSEvent* event ) case NSOtherMouseDown: case NSOtherMouseUp: case NSOtherMouseDragged: +#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6 + case NSEventTypeGesture: // touch events + case NSEventTypeMagnify: + case NSEventTypeSwipe: + case NSEventTypeRotate: + case NSEventTypeBeginGesture: + case NSEventTypeEndGesture: +#endif result = true; break; @@ -540,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(); @@ -554,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(); @@ -583,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; @@ -682,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; } @@ -729,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; } @@ -775,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]; @@ -804,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; } @@ -844,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. @@ -852,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(); @@ -869,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) { } @@ -959,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); } } @@ -975,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); } @@ -983,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); @@ -992,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 } @@ -1046,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(); } @@ -1064,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_p.h b/src/gui/kernel/qkeymapper_p.h index 09c36c88..3e42d6e 100644 --- a/src/gui/kernel/qkeymapper_p.h +++ b/src/gui/kernel/qkeymapper_p.h @@ -207,12 +207,12 @@ public: KeyboardLayoutItem *keyLayout[256]; #elif defined(Q_WS_QWS) #elif defined(Q_OS_SYMBIAN) -private: - QHash<TUint, int> s60ToQtKeyMap; - void fillKeyMap(); public: QString translateKeyEvent(int keySym, Qt::KeyboardModifiers modifiers); int mapS60KeyToQt(TUint s60key); + int mapS60ScanCodesToQt(TUint s60key); + int mapQtToS60Key(int qtKey); + int mapQtToS60ScanCodes(int qtKey); #endif }; diff --git a/src/gui/kernel/qkeymapper_s60.cpp b/src/gui/kernel/qkeymapper_s60.cpp index 6e21420..fd263ef 100644 --- a/src/gui/kernel/qkeymapper_s60.cpp +++ b/src/gui/kernel/qkeymapper_s60.cpp @@ -46,7 +46,6 @@ QT_BEGIN_NAMESPACE QKeyMapperPrivate::QKeyMapperPrivate() { - fillKeyMap(); } QKeyMapperPrivate::~QKeyMapperPrivate() @@ -74,174 +73,145 @@ QString QKeyMapperPrivate::translateKeyEvent(int keySym, Qt::KeyboardModifiers / return QString(QChar(keySym)); } -void QKeyMapperPrivate::fillKeyMap() +#include <e32keys.h> +struct KeyMapping{ + TKeyCode s60KeyCode; + TStdScanCode s60ScanCode; + Qt::Key qtKey; +}; + +using namespace Qt; + +static const KeyMapping keyMapping[] = { + {EKeyBackspace, EStdKeyBackspace, Key_Backspace}, + {EKeyTab, EStdKeyTab, Key_Tab}, + {EKeyEnter, EStdKeyEnter, Key_Enter}, + {EKeyEscape, EStdKeyEscape, Key_Escape}, + {EKeySpace, EStdKeySpace, Key_Space}, + {EKeyDelete, EStdKeyDelete, Key_Delete}, + {EKeyPrintScreen, EStdKeyPrintScreen, Key_SysReq}, + {EKeyPause, EStdKeyPause, Key_Pause}, + {EKeyHome, EStdKeyHome, Key_Home}, + {EKeyEnd, EStdKeyEnd, Key_End}, + {EKeyPageUp, EStdKeyPageUp, Key_PageUp}, + {EKeyPageDown, EStdKeyPageDown, Key_PageDown}, + {EKeyInsert, EStdKeyInsert, Key_Insert}, + {EKeyLeftArrow, EStdKeyLeftArrow, Key_Left}, + {EKeyRightArrow, EStdKeyRightArrow, Key_Right}, + {EKeyUpArrow, EStdKeyUpArrow, Key_Up}, + {EKeyDownArrow, EStdKeyDownArrow, Key_Down}, + {EKeyLeftShift, EStdKeyLeftShift, Key_Shift}, + {EKeyRightShift, EStdKeyRightShift, Key_Shift}, + {EKeyLeftAlt, EStdKeyLeftAlt, Key_Alt}, + {EKeyRightAlt, EStdKeyRightAlt, Key_AltGr}, + {EKeyLeftCtrl, EStdKeyLeftCtrl, Key_Control}, + {EKeyRightCtrl, EStdKeyRightCtrl, Key_Control}, + {EKeyLeftFunc, EStdKeyLeftFunc, Key_Super_L}, + {EKeyRightFunc, EStdKeyRightFunc, Key_Super_R}, + {EKeyCapsLock, EStdKeyCapsLock, Key_CapsLock}, + {EKeyNumLock, EStdKeyNumLock, Key_NumLock}, + {EKeyScrollLock, EStdKeyScrollLock, Key_ScrollLock}, + {EKeyF1, EStdKeyF1, Key_F1}, + {EKeyF2, EStdKeyF2, Key_F2}, + {EKeyF3, EStdKeyF3, Key_F3}, + {EKeyF4, EStdKeyF4, Key_F4}, + {EKeyF5, EStdKeyF5, Key_F5}, + {EKeyF6, EStdKeyF6, Key_F6}, + {EKeyF7, EStdKeyF7, Key_F7}, + {EKeyF8, EStdKeyF8, Key_F8}, + {EKeyF9, EStdKeyF9, Key_F9}, + {EKeyF10, EStdKeyF10, Key_F10}, + {EKeyF11, EStdKeyF11, Key_F11}, + {EKeyF12, EStdKeyF12, Key_F12}, + {EKeyF13, EStdKeyF13, Key_F13}, + {EKeyF14, EStdKeyF14, Key_F14}, + {EKeyF15, EStdKeyF15, Key_F15}, + {EKeyF16, EStdKeyF16, Key_F16}, + {EKeyF17, EStdKeyF17, Key_F17}, + {EKeyF18, EStdKeyF18, Key_F18}, + {EKeyF19, EStdKeyF19, Key_F19}, + {EKeyF20, EStdKeyF20, Key_F20}, + {EKeyF21, EStdKeyF21, Key_F21}, + {EKeyF22, EStdKeyF22, Key_F22}, + {EKeyF23, EStdKeyF23, Key_F23}, + {EKeyF24, EStdKeyF24, Key_F24}, + {EKeyOff, EStdKeyOff, Key_PowerOff}, +// {EKeyMenu, EStdKeyMenu, Key_Menu}, // Menu is EKeyApplication0 + {EKeyHelp, EStdKeyHelp, Key_Help}, + {EKeyDial, EStdKeyDial, Key_Call}, + {EKeyIncVolume, EStdKeyIncVolume, Key_VolumeUp}, + {EKeyDecVolume, EStdKeyDecVolume, Key_VolumeDown}, + {EKeyDevice0, EStdKeyDevice0, Key_Context1}, // Found by manual testing. + {EKeyDevice1, EStdKeyDevice1, Key_Context2}, // Found by manual testing. + {EKeyDevice3, EStdKeyDevice3, Key_Select}, +// {EKeyDevice7, EStdKeyDevice7, Key_Camera}, //not supported by qt yet + {EKeyApplication0, EStdKeyApplication0, Key_Menu}, // Found by manual testing. + {EKeyApplication1, EStdKeyApplication1, Key_Launch1}, // Found by manual testing. + {EKeyApplication2, EStdKeyApplication2, Key_MediaPlay}, // Found by manual testing. + {EKeyApplication3, EStdKeyApplication3, Key_MediaStop}, // Found by manual testing. + {EKeyApplication4, EStdKeyApplication4, Key_MediaNext}, // Found by manual testing. + {EKeyApplication5, EStdKeyApplication5, Key_MediaPrevious}, // Found by manual testing. + {EKeyApplication6, EStdKeyApplication6, Key_Launch6}, + {EKeyApplication7, EStdKeyApplication7, Key_Launch7}, + {EKeyApplication8, EStdKeyApplication8, Key_Launch8}, + {EKeyApplication9, EStdKeyApplication9, Key_Launch9}, + {EKeyApplicationA, EStdKeyApplicationA, Key_LaunchA}, + {EKeyApplicationB, EStdKeyApplicationB, Key_LaunchB}, + {EKeyApplicationC, EStdKeyApplicationC, Key_LaunchC}, + {EKeyApplicationD, EStdKeyApplicationD, Key_LaunchD}, + {EKeyApplicationE, EStdKeyApplicationE, Key_LaunchE}, + {EKeyApplicationF, EStdKeyApplicationF, Key_LaunchF}, +// {EKeyApplication19, EStdKeyApplication19, Key_CameraFocus}, //not supported by qt yet + {EKeyYes, EStdKeyYes, Key_Yes}, + {EKeyNo, EStdKeyNo, Key_No}, + {TKeyCode(0), TStdScanCode(0), Qt::Key(0)} +}; + +int QKeyMapperPrivate::mapS60KeyToQt(TUint s60key) { - using namespace Qt; - static const struct { - TUint s60Key; - int qtKey; - } map[] = { - {EKeyBell, Key_unknown}, - {EKeyBackspace, Key_Backspace}, - {EKeyTab, Key_Tab}, - {EKeyLineFeed, Key_unknown}, - {EKeyVerticalTab, Key_unknown}, - {EKeyFormFeed, Key_unknown}, - {EKeyEnter, Key_Enter}, - {EKeyEscape, Key_Escape}, - {EKeySpace, Key_Space}, - {EKeyDelete, Key_Delete}, - {EKeyPrintScreen, Key_SysReq}, - {EKeyPause, Key_Pause}, - {EKeyHome, Key_Home}, - {EKeyEnd, Key_End}, - {EKeyPageUp, Key_PageUp}, - {EKeyPageDown, Key_PageDown}, - {EKeyInsert, Key_Insert}, - {EKeyLeftArrow, Key_Left}, - {EKeyRightArrow, Key_Right}, - {EKeyUpArrow, Key_Up}, - {EKeyDownArrow, Key_Down}, - {EKeyLeftShift, Key_Shift}, - {EKeyRightShift, Key_Shift}, - {EKeyLeftAlt, Key_Alt}, - {EKeyRightAlt, Key_AltGr}, - {EKeyLeftCtrl, Key_Control}, - {EKeyRightCtrl, Key_Control}, - {EKeyLeftFunc, Key_Super_L}, - {EKeyRightFunc, Key_Super_R}, - {EKeyCapsLock, Key_CapsLock}, - {EKeyNumLock, Key_NumLock}, - {EKeyScrollLock, Key_ScrollLock}, - {EKeyF1, Key_F1}, - {EKeyF2, Key_F2}, - {EKeyF3, Key_F3}, - {EKeyF4, Key_F4}, - {EKeyF5, Key_F5}, - {EKeyF6, Key_F6}, - {EKeyF7, Key_F7}, - {EKeyF8, Key_F8}, - {EKeyF9, Key_F9}, - {EKeyF10, Key_F10}, - {EKeyF11, Key_F11}, - {EKeyF12, Key_F12}, - {EKeyF13, Key_F13}, - {EKeyF14, Key_F14}, - {EKeyF15, Key_F15}, - {EKeyF16, Key_F16}, - {EKeyF17, Key_F17}, - {EKeyF18, Key_F18}, - {EKeyF19, Key_F19}, - {EKeyF20, Key_F20}, - {EKeyF21, Key_F21}, - {EKeyF22, Key_F22}, - {EKeyF23, Key_F23}, - {EKeyF24, Key_F24}, - {EKeyOff, Key_unknown}, - {EKeyIncContrast, Key_unknown}, - {EKeyDecContrast, Key_unknown}, - {EKeyBacklightOn, Key_unknown}, - {EKeyBacklightOff, Key_unknown}, - {EKeyBacklightToggle, Key_unknown}, - {EKeySliderDown, Key_unknown}, - {EKeySliderUp, Key_unknown}, - {EKeyMenu, Key_Menu}, - {EKeyDictaphonePlay, Key_unknown}, - {EKeyDictaphoneStop, Key_unknown}, - {EKeyDictaphoneRecord, Key_unknown}, - {EKeyHelp, Key_unknown}, - {EKeyDial, Key_Call}, - {EKeyScreenDimension0, Key_unknown}, - {EKeyScreenDimension1, Key_unknown}, - {EKeyScreenDimension2, Key_unknown}, - {EKeyScreenDimension3, Key_unknown}, - {EKeyIncVolume, Key_unknown}, - {EKeyDecVolume, Key_unknown}, - {EKeyDevice0, Key_Context1}, // Found by manual testing, left softkey. - {EKeyDevice1, Key_Context2}, // Found by manual testing. - {EKeyDevice2, Key_unknown}, - {EKeyDevice3, Key_Select}, // Found by manual testing. - {EKeyDevice4, Key_unknown}, - {EKeyDevice5, Key_unknown}, - {EKeyDevice6, Key_unknown}, - {EKeyDevice7, Key_unknown}, - {EKeyDevice8, Key_unknown}, - {EKeyDevice9, Key_unknown}, - {EKeyDeviceA, Key_unknown}, - {EKeyDeviceB, Key_unknown}, - {EKeyDeviceC, Key_unknown}, - {EKeyDeviceD, Key_unknown}, - {EKeyDeviceE, Key_unknown}, - {EKeyDeviceF, Key_unknown}, - {EKeyApplication0, Key_Launch0}, - {EKeyApplication1, Key_Launch1}, - {EKeyApplication2, Key_Launch2}, - {EKeyApplication3, Key_Launch3}, - {EKeyApplication4, Key_Launch4}, - {EKeyApplication5, Key_Launch5}, - {EKeyApplication6, Key_Launch6}, - {EKeyApplication7, Key_Launch7}, - {EKeyApplication8, Key_Launch8}, - {EKeyApplication9, Key_Launch9}, - {EKeyApplicationA, Key_LaunchA}, - {EKeyApplicationB, Key_LaunchB}, - {EKeyApplicationC, Key_LaunchC}, - {EKeyApplicationD, Key_LaunchD}, - {EKeyApplicationE, Key_LaunchE}, - {EKeyApplicationF, Key_LaunchF}, - {EKeyYes, Key_Yes}, - {EKeyNo, Key_No}, - {EKeyIncBrightness, Key_unknown}, - {EKeyDecBrightness, Key_unknown}, - {EKeyKeyboardExtend, Key_unknown}, - {EKeyDevice10, Key_unknown}, - {EKeyDevice11, Key_unknown}, - {EKeyDevice12, Key_unknown}, - {EKeyDevice13, Key_unknown}, - {EKeyDevice14, Key_unknown}, - {EKeyDevice15, Key_unknown}, - {EKeyDevice16, Key_unknown}, - {EKeyDevice17, Key_unknown}, - {EKeyDevice18, Key_unknown}, - {EKeyDevice19, Key_unknown}, - {EKeyDevice1A, Key_unknown}, - {EKeyDevice1B, Key_unknown}, - {EKeyDevice1C, Key_unknown}, - {EKeyDevice1D, Key_unknown}, - {EKeyDevice1E, Key_unknown}, - {EKeyDevice1F, Key_unknown}, - {EKeyApplication10, Key_unknown}, - {EKeyApplication11, Key_unknown}, - {EKeyApplication12, Key_unknown}, - {EKeyApplication13, Key_unknown}, - {EKeyApplication14, Key_unknown}, - {EKeyApplication15, Key_unknown}, - {EKeyApplication16, Key_unknown}, - {EKeyApplication17, Key_unknown}, - {EKeyApplication18, Key_unknown}, - {EKeyApplication19, Key_unknown}, - {EKeyApplication1A, Key_unknown}, - {EKeyApplication1B, Key_unknown}, - {EKeyApplication1C, Key_unknown}, - {EKeyApplication1D, Key_unknown}, - {EKeyApplication1E, Key_unknown}, - {EKeyApplication1F, Key_unknown} - }; - const int mapSize = int(sizeof(map)/sizeof(map[0])); - s60ToQtKeyMap.reserve(mapSize + 5); // +5? docs: Ideally, slightly more than number of items - for (int i = 0; i < mapSize; ++i) - s60ToQtKeyMap.insert(map[i].s60Key, map[i].qtKey); + int res = Qt::Key_unknown; + for (int i = 0; keyMapping[i].s60KeyCode != 0; i++) { + if (keyMapping[i].s60KeyCode == s60key) { + res = keyMapping[i].qtKey; + break; + } + } + return res; } -int QKeyMapperPrivate::mapS60KeyToQt(TUint s60key) +int QKeyMapperPrivate::mapS60ScanCodesToQt(TUint s60scanCode) { - QHash<TUint, int>::const_iterator mapping; - mapping = s60ToQtKeyMap.find(s60key); - if (mapping != s60ToQtKeyMap.end()) { - return *mapping; - } else { - return Qt::Key_unknown; + int res = Qt::Key_unknown; + for (int i = 0; keyMapping[i].s60KeyCode != 0; i++) { + if (keyMapping[i].s60ScanCode == s60scanCode) { + res = keyMapping[i].qtKey; + break; + } } + return res; } +int QKeyMapperPrivate::mapQtToS60Key(int qtKey) +{ + int res = KErrUnknown; + for (int i = 0; keyMapping[i].s60KeyCode != 0; i++) { + if (keyMapping[i].qtKey == qtKey) { + res = keyMapping[i].s60KeyCode; + break; + } + } + return res; +} + +int QKeyMapperPrivate::mapQtToS60ScanCodes(int qtKey) +{ + int res = KErrUnknown; + for (int i = 0; keyMapping[i].s60KeyCode != 0; i++) { + if (keyMapping[i].qtKey == qtKey) { + res = keyMapping[i].s60ScanCode; + break; + } + } + return res; +} 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/qsoftkeymanager.cpp b/src/gui/kernel/qsoftkeymanager.cpp index 6d108b0..c9a94ee 100644 --- a/src/gui/kernel/qsoftkeymanager.cpp +++ b/src/gui/kernel/qsoftkeymanager.cpp @@ -55,24 +55,24 @@ QT_BEGIN_NAMESPACE QSoftKeyManager *QSoftKeyManagerPrivate::self = 0; -const char *QSoftKeyManager::standardSoftKeyText(StandardSoftKey standardKey) +QString QSoftKeyManager::standardSoftKeyText(StandardSoftKey standardKey) { - const char *softKeyText = 0; + QString softKeyText; switch (standardKey) { case OkSoftKey: - softKeyText = QT_TRANSLATE_NOOP("QSoftKeyManager", "Ok"); + softKeyText = QSoftKeyManager::tr("Ok"); break; case SelectSoftKey: - softKeyText = QT_TRANSLATE_NOOP("QSoftKeyManager", "Select"); + softKeyText = QSoftKeyManager::tr("Select"); break; case DoneSoftKey: - softKeyText = QT_TRANSLATE_NOOP("QSoftKeyManager", "Done"); + softKeyText = QSoftKeyManager::tr("Done"); break; case MenuSoftKey: - softKeyText = QT_TRANSLATE_NOOP("QSoftKeyManager", "Options"); + softKeyText = QSoftKeyManager::tr("Options"); break; case CancelSoftKey: - softKeyText = QT_TRANSLATE_NOOP("QSoftKeyManager", "Cancel"); + softKeyText = QSoftKeyManager::tr("Cancel"); break; default: break; @@ -100,8 +100,7 @@ QSoftKeyManager::QSoftKeyManager() : QAction *QSoftKeyManager::createAction(StandardSoftKey standardKey, QWidget *actionWidget) { - const char* text = standardSoftKeyText(standardKey); - QAction *action = new QAction(QSoftKeyManager::tr(text), actionWidget); + QAction *action = new QAction(standardSoftKeyText(standardKey), actionWidget); QAction::SoftKeyRole softKeyRole = QAction::NoSoftKey; switch (standardKey) { case MenuSoftKey: // FALL-THROUGH @@ -211,13 +210,11 @@ bool QSoftKeyManager::handleUpdateSoftKeys() d->requestedSoftKeyActions.clear(); bool recursiveMerging = false; QWidget *source = softkeySource(NULL, recursiveMerging); - do { - if (source) { - bool added = appendSoftkeys(*source, level); - source = softkeySource(source, recursiveMerging); - level = added ? ++level : level; - } - } while (source); + while (source) { + if (appendSoftkeys(*source, level)) + ++level; + source = softkeySource(source, recursiveMerging); + } d->updateSoftKeys_sys(); return true; diff --git a/src/gui/kernel/qsoftkeymanager_p.h b/src/gui/kernel/qsoftkeymanager_p.h index ce902fe..a6fe17e 100644 --- a/src/gui/kernel/qsoftkeymanager_p.h +++ b/src/gui/kernel/qsoftkeymanager_p.h @@ -87,6 +87,7 @@ public: static QAction *createAction(StandardSoftKey standardKey, QWidget *actionWidget); static QAction *createKeyedAction(StandardSoftKey standardKey, Qt::Key key, QWidget *actionWidget); + static QString standardSoftKeyText(StandardSoftKey standardKey); protected: bool event(QEvent *e); @@ -94,7 +95,6 @@ protected: private: QSoftKeyManager(); static QSoftKeyManager *instance(); - static const char *standardSoftKeyText(StandardSoftKey standardKey); bool appendSoftkeys(const QWidget &source, int level); QWidget *softkeySource(QWidget *previousSource, bool& recursiveMerging); bool handleUpdateSoftKeys(); diff --git a/src/gui/kernel/qsoftkeymanager_s60.cpp b/src/gui/kernel/qsoftkeymanager_s60.cpp index af84a8f..8ac1e31 100644 --- a/src/gui/kernel/qsoftkeymanager_s60.cpp +++ b/src/gui/kernel/qsoftkeymanager_s60.cpp @@ -66,17 +66,18 @@ QSoftKeyManagerPrivateS60::QSoftKeyManagerPrivateS60() cachedCbaIconSize[1] = QSize(0,0); cachedCbaIconSize[2] = QSize(0,0); cachedCbaIconSize[3] = QSize(0,0); - skipNextUpdate = false; } bool QSoftKeyManagerPrivateS60::skipCbaUpdate() { - // lets not update softkeys if + // Lets not update softkeys if // 1. We don't have application panes, i.e. cba - // 2. S60 native dialog or menu is shown - if (QApplication::testAttribute(Qt::AA_S60DontConstructApplicationPanes) || - CCoeEnv::Static()->AppUi()->IsDisplayingMenuOrDialog() || skipNextUpdate) { - skipNextUpdate = false; + // 2. Our CBA is not active, i.e. S60 native dialog or menu with custom CBA is shown + // Note: Cannot use IsDisplayingMenuOrDialog since CBA update can be triggered before + // menu/dialog CBA is actually displayed i.e. it is being costructed. + CEikButtonGroupContainer *appUiCba = S60->buttonGroupContainer(); + CEikButtonGroupContainer *currentCba = CEikButtonGroupContainer::Current(); + if (QApplication::testAttribute(Qt::AA_S60DontConstructApplicationPanes) || appUiCba != currentCba) { return true; } return false; @@ -384,9 +385,6 @@ bool QSoftKeyManagerPrivateS60::handleCommand(int command) } qt_symbian_next_menu_from_action(actionContainer); QT_TRAP_THROWING(S60->menuBar()->TryDisplayMenuBarL()); - // TODO: hack remove, it can happen that IsDisplayingMenuOrDialog return false - // in updateSoftKeys_sys, and we will override menu CBA with our own - skipNextUpdate = true; } else { Q_ASSERT(action->softKeyRole() != QAction::NoSoftKey); QWidget *actionParent = action->parentWidget(); diff --git a/src/gui/kernel/qsoftkeymanager_s60_p.h b/src/gui/kernel/qsoftkeymanager_s60_p.h index f8bd6d9..823a2db 100644 --- a/src/gui/kernel/qsoftkeymanager_s60_p.h +++ b/src/gui/kernel/qsoftkeymanager_s60_p.h @@ -98,7 +98,6 @@ private: private: QHash<int, QAction*> realSoftKeyActions; QSize cachedCbaIconSize[4]; - bool skipNextUpdate; }; 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 fcd9343..aca2b7e 100644 --- a/src/gui/kernel/qwidget.cpp +++ b/src/gui/kernel/qwidget.cpp @@ -118,6 +118,10 @@ #include "private/qgraphicssystem_p.h" #include "private/qgesturemanager_p.h" +#ifdef QT_KEYPAD_NAVIGATION +#include "qtabwidget.h" // Needed in inTabWidget() +#endif // QT_KEYPAD_NAVIGATION + // widget/widget data creation count //#define QWIDGET_EXTRA_DEBUG //#define ALIEN_DEBUG @@ -192,6 +196,7 @@ QWidgetPrivate::QWidgetPrivate(int version) , inDirtyList(0) , isScrolled(0) , isMoved(0) + , isGLWidget(0) , usesDoubleBufferedGLContext(0) #if defined(Q_WS_X11) , picture(0) @@ -200,7 +205,6 @@ QWidgetPrivate::QWidgetPrivate(int version) , nativeGesturePanEnabled(0) #elif defined(Q_WS_MAC) , needWindowChange(0) - , isGLWidget(0) , window_event(0) , qd_hd(0) #endif @@ -1468,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(); @@ -4882,90 +4895,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); } /*! @@ -5411,6 +5341,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 @@ -7598,23 +7619,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(); @@ -8277,7 +8296,7 @@ bool QWidget::event(QEvent *event) } #ifdef QT_SOFTKEYS_ENABLED - if (isWindow() && isActiveWindow()) + if (isWindow()) QSoftKeyManager::updateSoftKeys(); #endif @@ -11637,6 +11656,45 @@ QWidget *QWidgetPrivate::widgetInNavigationDirection(Direction direction) } return targetWidget; } + +/*! + \internal + + Tells us if it there is currently a reachable widget by keypad navigation in + a certain \a orientation. + If no navigation is possible, occuring key events in that \a orientation may + be used to interact with the value in the focussed widget, even though it + currently has not the editFocus. + + \sa QWidgetPrivate::widgetInNavigationDirection(), QWidget::hasEditFocus() +*/ +bool QWidgetPrivate::canKeypadNavigate(Qt::Orientation orientation) +{ + return orientation == Qt::Horizontal? + (QWidgetPrivate::widgetInNavigationDirection(QWidgetPrivate::DirectionEast) + || QWidgetPrivate::widgetInNavigationDirection(QWidgetPrivate::DirectionWest)) + :(QWidgetPrivate::widgetInNavigationDirection(QWidgetPrivate::DirectionNorth) + || QWidgetPrivate::widgetInNavigationDirection(QWidgetPrivate::DirectionSouth)); +} +/*! + \internal + + Checks, if the \a widget is inside a QTabWidget. If is is inside + one, left/right key events will be used to switch between tabs in keypad + navigation. If there is no QTabWidget, the horizontal key events can be used +to + interact with the value in the focussed widget, even though it currently has + not the editFocus. + + \sa QWidget::hasEditFocus() +*/ +bool QWidgetPrivate::inTabWidget(QWidget *widget) +{ + for (QWidget *tabWidget = widget; tabWidget; tabWidget = tabWidget->parentWidget()) + if (qobject_cast<const QTabWidget*>(tabWidget)) + return true; + return false; +} #endif /*! diff --git a/src/gui/kernel/qwidget_mac.mm b/src/gui/kernel/qwidget_mac.mm index 9e7517f..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); @@ -4475,8 +4543,20 @@ void QWidgetPrivate::scroll_sys(int dx, int dy, const QRect &r) } } + // ### Scroll the dirty regions as well, the following is not correct. + QRegion displayRegion = r.isNull() ? dirtyOnWidget : (dirtyOnWidget & r); + const QVector<QRect> &rects = dirtyOnWidget.rects(); + const QVector<QRect>::const_iterator end = rects.end(); + QVector<QRect>::const_iterator it = rects.begin(); + while (it != end) { + const QRect rect = *it; + const NSRect dirtyRect = NSMakeRect(rect.x() + dx, rect.y() + dy, + rect.width(), rect.height()); + [view setNeedsDisplayInRect:dirtyRect]; + ++it; + } + NSSize deltaSize = NSMakeSize(dx, dy); - [view translateRectsNeedingDisplayInRect:scrollRect by:deltaSize]; [view scrollRect:scrollRect by:deltaSize]; [view setNeedsDisplayInRect:deltaXRect]; [view setNeedsDisplayInRect:deltaYRect]; @@ -4605,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 } @@ -4761,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(); @@ -4778,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 e06316a..ae228dc 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); @@ -472,6 +475,8 @@ public: #ifdef QT_KEYPAD_NAVIGATION static bool navigateToDirection(Direction direction); static QWidget *widgetInNavigationDirection(Direction direction); + static bool canKeypadNavigate(Qt::Orientation orientation); + static bool inTabWidget(QWidget *widget); #endif void setWindowIconText_sys(const QString &cap); @@ -683,6 +688,7 @@ public: uint inDirtyList : 1; uint isScrolled : 1; uint isMoved : 1; + uint isGLWidget : 1; uint usesDoubleBufferedGLContext : 1; // *************************** Platform specific ************************************ @@ -714,7 +720,6 @@ public: #elif defined(Q_WS_MAC) // <--------------------------------------------------------- MAC // This is new stuff uint needWindowChange : 1; - uint isGLWidget : 1; // Each wiget keeps a list of all its child and grandchild OpenGL widgets. // This list is used to update the gl context whenever a parent and a granparent @@ -761,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/qcups.cpp b/src/gui/painting/qcups.cpp index 7903762..ac41692 100644 --- a/src/gui/painting/qcups.cpp +++ b/src/gui/painting/qcups.cpp @@ -342,7 +342,9 @@ bool QCUPSSupport::printerHasPPD(const char *printerName) { if (!isAvailable()) return false; - return _cupsGetPPD(printerName) != 0; + const char *ppdFile = _cupsGetPPD(printerName); + unlink(ppdFile); + return (ppdFile != 0); } QString QCUPSSupport::unicodeString(const char *s) 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 7a3da20..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>; @@ -8092,20 +7897,43 @@ void qInitDrawhelperAsm() qDrawHelper[QImage::Format_ARGB32_Premultiplied].blendColor = qt_blend_color_argb_sse3dnow; } #endif // 3DNOW - extern void qt_blend_rgb32_on_rgb32_sse(uchar *destPixels, int dbpl, - const uchar *srcPixels, int sbpl, - int w, int h, - int const_alpha); - extern void qt_blend_argb32_on_argb32_sse(uchar *destPixels, int dbpl, - const uchar *srcPixels, int sbpl, - int w, int h, - int const_alpha); - qBlendFunctions[QImage::Format_RGB32][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb32_sse; - qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb32_sse; - qBlendFunctions[QImage::Format_RGB32][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32_sse; - qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32_sse; - } + +#ifdef QT_HAVE_SSE2 + if (features & SSE2) { + extern void qt_blend_rgb32_on_rgb32_sse2(uchar *destPixels, int dbpl, + const uchar *srcPixels, int sbpl, + int w, int h, + int const_alpha); + extern void qt_blend_argb32_on_argb32_sse2(uchar *destPixels, int dbpl, + const uchar *srcPixels, int sbpl, + int w, int h, + int const_alpha); + + + qBlendFunctions[QImage::Format_RGB32][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb32_sse2; + qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb32_sse2; + qBlendFunctions[QImage::Format_RGB32][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32_sse2; + qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32_sse2; + } else +#endif + { + extern void qt_blend_rgb32_on_rgb32_sse(uchar *destPixels, int dbpl, + const uchar *srcPixels, int sbpl, + int w, int h, + int const_alpha); + extern void qt_blend_argb32_on_argb32_sse(uchar *destPixels, int dbpl, + const uchar *srcPixels, int sbpl, + int w, int h, + int const_alpha); + + + qBlendFunctions[QImage::Format_RGB32][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb32_sse; + qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb32_sse; + qBlendFunctions[QImage::Format_RGB32][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32_sse; + qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32_sse; + } +} #endif // SSE #ifdef QT_HAVE_IWMMXT diff --git a/src/gui/painting/qdrawhelper_neon.cpp b/src/gui/painting/qdrawhelper_neon.cpp index 25860a0..77c5202 100644 --- a/src/gui/painting/qdrawhelper_neon.cpp +++ b/src/gui/painting/qdrawhelper_neon.cpp @@ -48,43 +48,43 @@ QT_BEGIN_NAMESPACE -static inline int16x8_t qvdiv_255_s16(int16x8_t x, int16x8_t half) +static inline uint16x8_t qvdiv_255_u16(uint16x8_t x, uint16x8_t half) { // result = (x + (x >> 8) + 0x80) >> 8 - const int16x8_t temp = vshrq_n_s16(x, 8); // x >> 8 - const int16x8_t sum_part = vaddq_s16(x, half); // x + 0x80 - const int16x8_t sum = vaddq_s16(temp, sum_part); + const uint16x8_t temp = vshrq_n_u16(x, 8); // x >> 8 + const uint16x8_t sum_part = vaddq_u16(x, half); // x + 0x80 + const uint16x8_t sum = vaddq_u16(temp, sum_part); - return vreinterpretq_s16_u16(vshrq_n_u16(vreinterpretq_u16_s16(sum), 8)); + return vshrq_n_u16(sum, 8); } -static inline int16x8_t qvbyte_mul_s16(int16x8_t x, int16x8_t alpha, int16x8_t half) +static inline uint16x8_t qvbyte_mul_u16(uint16x8_t x, uint16x8_t alpha, uint16x8_t half) { // t = qRound(x * alpha / 255.0) - const int16x8_t t = vmulq_s16(x, alpha); // t - return qvdiv_255_s16(t, half); + const uint16x8_t t = vmulq_u16(x, alpha); // t + return qvdiv_255_u16(t, half); } -static inline int16x8_t qvinterpolate_pixel_255(int16x8_t x, int16x8_t a, int16x8_t y, int16x8_t b, int16x8_t half) +static inline uint16x8_t qvinterpolate_pixel_255(uint16x8_t x, uint16x8_t a, uint16x8_t y, uint16x8_t b, uint16x8_t half) { // t = x * a + y * b - const int16x8_t ta = vmulq_s16(x, a); - const int16x8_t tb = vmulq_s16(y, b); + const uint16x8_t ta = vmulq_u16(x, a); + const uint16x8_t tb = vmulq_u16(y, b); - return qvdiv_255_s16(vaddq_s16(ta, tb), half); + return qvdiv_255_u16(vaddq_u16(ta, tb), half); } -static inline int16x8_t qvsource_over_s16(int16x8_t src16, int16x8_t dst16, int16x8_t half, int16x8_t full) +static inline uint16x8_t qvsource_over_u16(uint16x8_t src16, uint16x8_t dst16, uint16x8_t half, uint16x8_t full) { - const int16x4_t alpha16_high = vdup_lane_s16(vget_high_s16(src16), 3); - const int16x4_t alpha16_low = vdup_lane_s16(vget_low_s16(src16), 3); + const uint16x4_t alpha16_high = vdup_lane_u16(vget_high_u16(src16), 3); + const uint16x4_t alpha16_low = vdup_lane_u16(vget_low_u16(src16), 3); - const int16x8_t alpha16 = vsubq_s16(full, vcombine_s16(alpha16_low, alpha16_high)); + const uint16x8_t alpha16 = vsubq_u16(full, vcombine_u16(alpha16_low, alpha16_high)); - return vaddq_s16(src16, qvbyte_mul_s16(dst16, alpha16, half)); + return vaddq_u16(src16, qvbyte_mul_u16(dst16, alpha16, half)); } void qt_blend_argb32_on_argb32_neon(uchar *destPixels, int dbpl, @@ -94,21 +94,21 @@ void qt_blend_argb32_on_argb32_neon(uchar *destPixels, int dbpl, { const uint *src = (const uint *) srcPixels; uint *dst = (uint *) destPixels; - int16x8_t half = vdupq_n_s16(0x80); - int16x8_t full = vdupq_n_s16(0xff); + uint16x8_t half = vdupq_n_u16(0x80); + uint16x8_t full = vdupq_n_u16(0xff); if (const_alpha == 256) { for (int y = 0; y < h; ++y) { int x = 0; for (; x < w-3; x += 4) { - int32x4_t src32 = vld1q_s32((int32_t *)&src[x]); + uint32x4_t src32 = vld1q_u32((uint32_t *)&src[x]); if ((src[x] & src[x+1] & src[x+2] & src[x+3]) >= 0xff000000) { // all opaque - vst1q_s32((int32_t *)&dst[x], src32); + vst1q_u32((uint32_t *)&dst[x], src32); } else if (src[x] | src[x+1] | src[x+2] | src[x+3]) { - int32x4_t dst32 = vld1q_s32((int32_t *)&dst[x]); + uint32x4_t dst32 = vld1q_u32((uint32_t *)&dst[x]); - const uint8x16_t src8 = vreinterpretq_u8_s32(src32); - const uint8x16_t dst8 = vreinterpretq_u8_s32(dst32); + const uint8x16_t src8 = vreinterpretq_u8_u32(src32); + const uint8x16_t dst8 = vreinterpretq_u8_u32(dst32); const uint8x8_t src8_low = vget_low_u8(src8); const uint8x8_t dst8_low = vget_low_u8(dst8); @@ -116,19 +116,19 @@ void qt_blend_argb32_on_argb32_neon(uchar *destPixels, int dbpl, const uint8x8_t src8_high = vget_high_u8(src8); const uint8x8_t dst8_high = vget_high_u8(dst8); - const int16x8_t src16_low = vreinterpretq_s16_u16(vmovl_u8(src8_low)); - const int16x8_t dst16_low = vreinterpretq_s16_u16(vmovl_u8(dst8_low)); + const uint16x8_t src16_low = vmovl_u8(src8_low); + const uint16x8_t dst16_low = vmovl_u8(dst8_low); - const int16x8_t src16_high = vreinterpretq_s16_u16(vmovl_u8(src8_high)); - const int16x8_t dst16_high = vreinterpretq_s16_u16(vmovl_u8(dst8_high)); + const uint16x8_t src16_high = vmovl_u8(src8_high); + const uint16x8_t dst16_high = vmovl_u8(dst8_high); - const int16x8_t result16_low = qvsource_over_s16(src16_low, dst16_low, half, full); - const int16x8_t result16_high = qvsource_over_s16(src16_high, dst16_high, half, full); + const uint16x8_t result16_low = qvsource_over_u16(src16_low, dst16_low, half, full); + const uint16x8_t result16_high = qvsource_over_u16(src16_high, dst16_high, half, full); - const int32x2_t result32_low = vreinterpret_s32_s8(vmovn_s16(result16_low)); - const int32x2_t result32_high = vreinterpret_s32_s8(vmovn_s16(result16_high)); + const uint32x2_t result32_low = vreinterpret_u32_u8(vmovn_u16(result16_low)); + const uint32x2_t result32_high = vreinterpret_u32_u8(vmovn_u16(result16_high)); - vst1q_s32((int32_t *)&dst[x], vcombine_s32(result32_low, result32_high)); + vst1q_u32((uint32_t *)&dst[x], vcombine_u32(result32_low, result32_high)); } } for (; x<w; ++x) { @@ -143,16 +143,16 @@ void qt_blend_argb32_on_argb32_neon(uchar *destPixels, int dbpl, } } else if (const_alpha != 0) { const_alpha = (const_alpha * 255) >> 8; - int16x8_t const_alpha16 = vdupq_n_s16(const_alpha); + uint16x8_t const_alpha16 = vdupq_n_u16(const_alpha); for (int y = 0; y < h; ++y) { int x = 0; for (; x < w-3; x += 4) { if (src[x] | src[x+1] | src[x+2] | src[x+3]) { - int32x4_t src32 = vld1q_s32((int32_t *)&src[x]); - int32x4_t dst32 = vld1q_s32((int32_t *)&dst[x]); + uint32x4_t src32 = vld1q_u32((uint32_t *)&src[x]); + uint32x4_t dst32 = vld1q_u32((uint32_t *)&dst[x]); - const uint8x16_t src8 = vreinterpretq_u8_s32(src32); - const uint8x16_t dst8 = vreinterpretq_u8_s32(dst32); + const uint8x16_t src8 = vreinterpretq_u8_u32(src32); + const uint8x16_t dst8 = vreinterpretq_u8_u32(dst32); const uint8x8_t src8_low = vget_low_u8(src8); const uint8x8_t dst8_low = vget_low_u8(dst8); @@ -160,22 +160,22 @@ void qt_blend_argb32_on_argb32_neon(uchar *destPixels, int dbpl, const uint8x8_t src8_high = vget_high_u8(src8); const uint8x8_t dst8_high = vget_high_u8(dst8); - const int16x8_t src16_low = vreinterpretq_s16_u16(vmovl_u8(src8_low)); - const int16x8_t dst16_low = vreinterpretq_s16_u16(vmovl_u8(dst8_low)); + const uint16x8_t src16_low = vmovl_u8(src8_low); + const uint16x8_t dst16_low = vmovl_u8(dst8_low); - const int16x8_t src16_high = vreinterpretq_s16_u16(vmovl_u8(src8_high)); - const int16x8_t dst16_high = vreinterpretq_s16_u16(vmovl_u8(dst8_high)); + const uint16x8_t src16_high = vmovl_u8(src8_high); + const uint16x8_t dst16_high = vmovl_u8(dst8_high); - const int16x8_t srcalpha16_low = qvbyte_mul_s16(src16_low, const_alpha16, half); - const int16x8_t srcalpha16_high = qvbyte_mul_s16(src16_high, const_alpha16, half); + const uint16x8_t srcalpha16_low = qvbyte_mul_u16(src16_low, const_alpha16, half); + const uint16x8_t srcalpha16_high = qvbyte_mul_u16(src16_high, const_alpha16, half); - const int16x8_t result16_low = qvsource_over_s16(srcalpha16_low, dst16_low, half, full); - const int16x8_t result16_high = qvsource_over_s16(srcalpha16_high, dst16_high, half, full); + const uint16x8_t result16_low = qvsource_over_u16(srcalpha16_low, dst16_low, half, full); + const uint16x8_t result16_high = qvsource_over_u16(srcalpha16_high, dst16_high, half, full); - const int32x2_t result32_low = vreinterpret_s32_s8(vmovn_s16(result16_low)); - const int32x2_t result32_high = vreinterpret_s32_s8(vmovn_s16(result16_high)); + const uint32x2_t result32_low = vreinterpret_u32_u8(vmovn_u16(result16_low)); + const uint32x2_t result32_high = vreinterpret_u32_u8(vmovn_u16(result16_high)); - vst1q_s32((int32_t *)&dst[x], vcombine_s32(result32_low, result32_high)); + vst1q_u32((uint32_t *)&dst[x], vcombine_u32(result32_low, result32_high)); } } for (; x<w; ++x) { @@ -206,19 +206,19 @@ void qt_blend_rgb32_on_rgb32_neon(uchar *destPixels, int dbpl, if (const_alpha != 0) { const uint *src = (const uint *) srcPixels; uint *dst = (uint *) destPixels; - int16x8_t half = vdupq_n_s16(0x80); + uint16x8_t half = vdupq_n_u16(0x80); const_alpha = (const_alpha * 255) >> 8; int one_minus_const_alpha = 255 - const_alpha; - int16x8_t const_alpha16 = vdupq_n_s16(const_alpha); - int16x8_t one_minus_const_alpha16 = vdupq_n_s16(255 - const_alpha); + uint16x8_t const_alpha16 = vdupq_n_u16(const_alpha); + uint16x8_t one_minus_const_alpha16 = vdupq_n_u16(255 - const_alpha); for (int y = 0; y < h; ++y) { int x = 0; for (; x < w-3; x += 4) { - int32x4_t src32 = vld1q_s32((int32_t *)&src[x]); - int32x4_t dst32 = vld1q_s32((int32_t *)&dst[x]); + uint32x4_t src32 = vld1q_u32((uint32_t *)&src[x]); + uint32x4_t dst32 = vld1q_u32((uint32_t *)&dst[x]); - const uint8x16_t src8 = vreinterpretq_u8_s32(src32); - const uint8x16_t dst8 = vreinterpretq_u8_s32(dst32); + const uint8x16_t src8 = vreinterpretq_u8_u32(src32); + const uint8x16_t dst8 = vreinterpretq_u8_u32(dst32); const uint8x8_t src8_low = vget_low_u8(src8); const uint8x8_t dst8_low = vget_low_u8(dst8); @@ -226,19 +226,19 @@ void qt_blend_rgb32_on_rgb32_neon(uchar *destPixels, int dbpl, const uint8x8_t src8_high = vget_high_u8(src8); const uint8x8_t dst8_high = vget_high_u8(dst8); - const int16x8_t src16_low = vreinterpretq_s16_u16(vmovl_u8(src8_low)); - const int16x8_t dst16_low = vreinterpretq_s16_u16(vmovl_u8(dst8_low)); + const uint16x8_t src16_low = vmovl_u8(src8_low); + const uint16x8_t dst16_low = vmovl_u8(dst8_low); - const int16x8_t src16_high = vreinterpretq_s16_u16(vmovl_u8(src8_high)); - const int16x8_t dst16_high = vreinterpretq_s16_u16(vmovl_u8(dst8_high)); + const uint16x8_t src16_high = vmovl_u8(src8_high); + const uint16x8_t dst16_high = vmovl_u8(dst8_high); - const int16x8_t result16_low = qvinterpolate_pixel_255(src16_low, const_alpha16, dst16_low, one_minus_const_alpha16, half); - const int16x8_t result16_high = qvinterpolate_pixel_255(src16_high, const_alpha16, dst16_high, one_minus_const_alpha16, half); + const uint16x8_t result16_low = qvinterpolate_pixel_255(src16_low, const_alpha16, dst16_low, one_minus_const_alpha16, half); + const uint16x8_t result16_high = qvinterpolate_pixel_255(src16_high, const_alpha16, dst16_high, one_minus_const_alpha16, half); - const int32x2_t result32_low = vreinterpret_s32_s8(vmovn_s16(result16_low)); - const int32x2_t result32_high = vreinterpret_s32_s8(vmovn_s16(result16_high)); + const uint32x2_t result32_low = vreinterpret_u32_u8(vmovn_u16(result16_low)); + const uint32x2_t result32_high = vreinterpret_u32_u8(vmovn_u16(result16_high)); - vst1q_s32((int32_t *)&dst[x], vcombine_s32(result32_low, result32_high)); + vst1q_u32((uint32_t *)&dst[x], vcombine_u32(result32_low, result32_high)); } for (; x<w; ++x) { uint s = src[x]; 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/qdrawhelper_sse2.cpp b/src/gui/painting/qdrawhelper_sse2.cpp index dd6fa1b..6ac64d3 100644 --- a/src/gui/painting/qdrawhelper_sse2.cpp +++ b/src/gui/painting/qdrawhelper_sse2.cpp @@ -57,6 +57,217 @@ QT_BEGIN_NAMESPACE +/* + * Multiply the components of pixelVector by alphaChannel + * Each 32bits components of alphaChannel must be in the form 0x00AA00AA + * colorMask must have 0x00ff00ff on each 32 bits component + * half must have the value 128 (0x80) for each 32 bits compnent + */ +#define BYTE_MUL_SSE2(result, pixelVector, alphaChannel, colorMask, half) \ +{ \ + /* 1. separate the colors in 2 vectors so each color is on 16 bits \ + (in order to be multiplied by the alpha \ + each 32 bit of dstVectorAG are in the form 0x00AA00GG \ + each 32 bit of dstVectorRB are in the form 0x00RR00BB */\ + __m128i pixelVectorAG = _mm_srli_epi16(pixelVector, 8); \ + __m128i pixelVectorRB = _mm_and_si128(pixelVector, colorMask); \ + \ + /* 2. multiply the vectors by the alpha channel */\ + pixelVectorAG = _mm_mullo_epi16(pixelVectorAG, alphaChannel); \ + pixelVectorRB = _mm_mullo_epi16(pixelVectorRB, alphaChannel); \ + \ + /* 3. devide by 255, that's the tricky part. \ + we do it like for BYTE_MUL(), with bit shift: X/255 ~= (X + X/256 + rounding)/256 */ \ + /** so first (X + X/256 + rounding) */\ + pixelVectorRB = _mm_add_epi16(pixelVectorRB, _mm_srli_epi16(pixelVectorRB, 8)); \ + pixelVectorRB = _mm_add_epi16(pixelVectorRB, half); \ + pixelVectorAG = _mm_add_epi16(pixelVectorAG, _mm_srli_epi16(pixelVectorAG, 8)); \ + pixelVectorAG = _mm_add_epi16(pixelVectorAG, half); \ + \ + /** second devide by 256 */\ + pixelVectorRB = _mm_srli_epi16(pixelVectorRB, 8); \ + /** for AG, we could >> 8 to divide followed by << 8 to put the \ + bytes in the correct position. By masking instead, we execute \ + only one instruction */\ + pixelVectorAG = _mm_andnot_si128(colorMask, pixelVectorAG); \ + \ + /* 4. combine the 2 pairs of colors */ \ + result = _mm_or_si128(pixelVectorAG, pixelVectorRB); \ +} + +/* + * Each 32bits components of alphaChannel must be in the form 0x00AA00AA + * oneMinusAlphaChannel must be 255 - alpha for each 32 bits component + * colorMask must have 0x00ff00ff on each 32 bits component + * half must have the value 128 (0x80) for each 32 bits compnent + */ +#define INTERPOLATE_PIXEL_255_SSE2(result, srcVector, dstVector, alphaChannel, oneMinusAlphaChannel, colorMask, half) { \ + /* interpolate AG */\ + __m128i srcVectorAG = _mm_srli_epi16(srcVector, 8); \ + __m128i dstVectorAG = _mm_srli_epi16(dstVector, 8); \ + __m128i srcVectorAGalpha = _mm_mullo_epi16(srcVectorAG, alphaChannel); \ + __m128i dstVectorAGoneMinusAlphalpha = _mm_mullo_epi16(dstVectorAG, oneMinusAlphaChannel); \ + __m128i finalAG = _mm_add_epi16(srcVectorAGalpha, dstVectorAGoneMinusAlphalpha); \ + finalAG = _mm_add_epi16(finalAG, _mm_srli_epi16(finalAG, 8)); \ + finalAG = _mm_add_epi16(finalAG, half); \ + finalAG = _mm_andnot_si128(colorMask, finalAG); \ + \ + /* interpolate RB */\ + __m128i srcVectorRB = _mm_and_si128(srcVector, colorMask); \ + __m128i dstVectorRB = _mm_and_si128(dstVector, colorMask); \ + __m128i srcVectorRBalpha = _mm_mullo_epi16(srcVectorRB, alphaChannel); \ + __m128i dstVectorRBoneMinusAlphalpha = _mm_mullo_epi16(dstVectorRB, oneMinusAlphaChannel); \ + __m128i finalRB = _mm_add_epi16(srcVectorRBalpha, dstVectorRBoneMinusAlphalpha); \ + finalRB = _mm_add_epi16(finalRB, _mm_srli_epi16(finalRB, 8)); \ + finalRB = _mm_add_epi16(finalRB, half); \ + finalRB = _mm_srli_epi16(finalRB, 8); \ + \ + /* combine */\ + result = _mm_or_si128(finalAG, finalRB); \ +} + +void qt_blend_argb32_on_argb32_sse2(uchar *destPixels, int dbpl, + const uchar *srcPixels, int sbpl, + int w, int h, + int const_alpha) +{ + const quint32 *src = (const quint32 *) srcPixels; + quint32 *dst = (uint *) destPixels; + if (const_alpha == 256) { + const __m128i alphaMask = _mm_set1_epi32(0xff000000); + const __m128i nullVector = _mm_set1_epi32(0); + const __m128i half = _mm_set1_epi16(0x80); + const __m128i one = _mm_set1_epi16(0xff); + const __m128i colorMask = _mm_set1_epi32(0x00ff00ff); + for (int y = 0; y < h; ++y) { + int x = 0; + for (; x < w-3; x += 4) { + const __m128i srcVector = _mm_loadu_si128((__m128i *)&src[x]); + const __m128i srcVectorAlpha = _mm_and_si128(srcVector, alphaMask); + if (_mm_movemask_epi8(_mm_cmpeq_epi32(srcVectorAlpha, alphaMask)) == 0xffff) { + // all opaque + _mm_storeu_si128((__m128i *)&dst[x], srcVector); + } else if (_mm_movemask_epi8(_mm_cmpeq_epi32(srcVectorAlpha, nullVector)) != 0xffff) { + // not fully transparent + // result = s + d * (1-alpha) + + // extract the alpha channel on 2 x 16 bits + // so we have room for the multiplication + // each 32 bits will be in the form 0x00AA00AA + // with A being the 1 - alpha + __m128i alphaChannel = _mm_srli_epi32(srcVector, 24); + alphaChannel = _mm_or_si128(alphaChannel, _mm_slli_epi32(alphaChannel, 16)); + alphaChannel = _mm_sub_epi16(one, alphaChannel); + + const __m128i dstVector = _mm_loadu_si128((__m128i *)&dst[x]); + __m128i destMultipliedByOneMinusAlpha; + BYTE_MUL_SSE2(destMultipliedByOneMinusAlpha, dstVector, alphaChannel, colorMask, half); + + // result = s + d * (1-alpha) + const __m128i result = _mm_add_epi8(srcVector, destMultipliedByOneMinusAlpha); + _mm_storeu_si128((__m128i *)&dst[x], result); + } + } + for (; x<w; ++x) { + uint s = src[x]; + if (s >= 0xff000000) + dst[x] = s; + else if (s != 0) + dst[x] = s + BYTE_MUL(dst[x], qAlpha(~s)); + } + dst = (quint32 *)(((uchar *) dst) + dbpl); + src = (const quint32 *)(((const uchar *) src) + sbpl); + } + } else if (const_alpha != 0) { + // dest = (s + d * sia) * ca + d * cia + // = s * ca + d * (sia * ca + cia) + // = s * ca + d * (1 - sa*ca) + const_alpha = (const_alpha * 255) >> 8; + const __m128i nullVector = _mm_set1_epi32(0); + const __m128i half = _mm_set1_epi16(0x80); + const __m128i one = _mm_set1_epi16(0xff); + const __m128i colorMask = _mm_set1_epi32(0x00ff00ff); + const __m128i constAlphaVector = _mm_set1_epi16(const_alpha); + for (int y = 0; y < h; ++y) { + int x = 0; + for (; x < w-3; x += 4) { + __m128i srcVector = _mm_loadu_si128((__m128i *)&src[x]); + if (_mm_movemask_epi8(_mm_cmpeq_epi32(srcVector, nullVector)) != 0xffff) { + BYTE_MUL_SSE2(srcVector, srcVector, constAlphaVector, colorMask, half); + + __m128i alphaChannel = _mm_srli_epi32(srcVector, 24); + alphaChannel = _mm_or_si128(alphaChannel, _mm_slli_epi32(alphaChannel, 16)); + alphaChannel = _mm_sub_epi16(one, alphaChannel); + + const __m128i dstVector = _mm_loadu_si128((__m128i *)&dst[x]); + __m128i destMultipliedByOneMinusAlpha; + BYTE_MUL_SSE2(destMultipliedByOneMinusAlpha, dstVector, alphaChannel, colorMask, half); + + const __m128i result = _mm_add_epi8(srcVector, destMultipliedByOneMinusAlpha); + _mm_storeu_si128((__m128i *)&dst[x], result); + } + } + for (; x<w; ++x) { + quint32 s = src[x]; + if (s != 0) { + s = BYTE_MUL(s, const_alpha); + dst[x] = s + BYTE_MUL(dst[x], qAlpha(~s)); + } + } + dst = (quint32 *)(((uchar *) dst) + dbpl); + src = (const quint32 *)(((const uchar *) src) + sbpl); + } + } +} + +// qblendfunctions.cpp +void qt_blend_rgb32_on_rgb32(uchar *destPixels, int dbpl, + const uchar *srcPixels, int sbpl, + int w, int h, + int const_alpha); + +void qt_blend_rgb32_on_rgb32_sse2(uchar *destPixels, int dbpl, + const uchar *srcPixels, int sbpl, + int w, int h, + int const_alpha) +{ + const quint32 *src = (const quint32 *) srcPixels; + quint32 *dst = (uint *) destPixels; + if (const_alpha != 256) { + if (const_alpha != 0) { + const __m128i nullVector = _mm_set1_epi32(0); + const __m128i half = _mm_set1_epi16(0x80); + const __m128i colorMask = _mm_set1_epi32(0x00ff00ff); + + const_alpha = (const_alpha * 255) >> 8; + int one_minus_const_alpha = 255 - const_alpha; + const __m128i constAlphaVector = _mm_set1_epi16(const_alpha); + const __m128i oneMinusConstAlpha = _mm_set1_epi16(one_minus_const_alpha); + for (int y = 0; y < h; ++y) { + int x = 0; + for (; x < w-3; x += 4) { + __m128i srcVector = _mm_loadu_si128((__m128i *)&src[x]); + if (_mm_movemask_epi8(_mm_cmpeq_epi32(srcVector, nullVector)) != 0xffff) { + const __m128i dstVector = _mm_loadu_si128((__m128i *)&dst[x]); + __m128i result; + INTERPOLATE_PIXEL_255_SSE2(result, srcVector, dstVector, constAlphaVector, oneMinusConstAlpha, colorMask, half); + _mm_storeu_si128((__m128i *)&dst[x], result); + } + } + for (; x<w; ++x) { + quint32 s = src[x]; + s = BYTE_MUL(s, const_alpha); + dst[x] = INTERPOLATE_PIXEL_255(src[x], const_alpha, dst[x], one_minus_const_alpha); + } + dst = (quint32 *)(((uchar *) dst) + dbpl); + src = (const quint32 *)(((const uchar *) src) + sbpl); + } + } + } else { + qt_blend_rgb32_on_rgb32(destPixels, dbpl, srcPixels, sbpl, w, h, const_alpha); + } +} + void qt_memfill32_sse2(quint32 *dest, quint32 value, int count) { if (count < 7) { diff --git a/src/gui/painting/qdrawhelper_x86_p.h b/src/gui/painting/qdrawhelper_x86_p.h index 30aadd0..d7282a7 100644 --- a/src/gui/painting/qdrawhelper_x86_p.h +++ b/src/gui/painting/qdrawhelper_x86_p.h @@ -114,6 +114,14 @@ void qt_bitmapblit32_sse2(QRasterBuffer *rasterBuffer, int x, int y, void qt_bitmapblit16_sse2(QRasterBuffer *rasterBuffer, int x, int y, quint32 color, const uchar *src, int width, int height, int stride); +void qt_blend_argb32_on_argb32_sse2(uchar *destPixels, int dbpl, + const uchar *srcPixels, int sbpl, + int w, int h, + int const_alpha); +void qt_blend_rgb32_on_rgb32_sse2(uchar *destPixels, int dbpl, + const uchar *srcPixels, int sbpl, + int w, int h, + int const_alpha); #endif // QT_HAVE_SSE2 #ifdef QT_HAVE_IWMMXT 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 eb13543..c3e3ad0 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" @@ -100,10 +101,6 @@ #endif #include <limits.h> -#if defined(QT_NO_FPU) || (_MSC_VER >= 1300 && _MSC_VER < 1400) -# define FLOATING_POINT_BUGGY_OR_NO_FPU -#endif - QT_BEGIN_NAMESPACE extern bool qt_scaleForTransform(const QTransform &transform, qreal *scale); // qtransform.cpp @@ -3006,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(); @@ -3044,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; @@ -3222,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) @@ -3269,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; } @@ -3679,9 +3693,6 @@ void QRasterPaintEngine::drawEllipse(const QRectF &rect) if (((qpen_style(s->lastPen) == Qt::SolidLine && s->flags.fast_pen) || (qpen_style(s->lastPen) == Qt::NoPen && !s->flags.antialiased)) && qMax(rect.width(), rect.height()) < QT_RASTER_COORD_LIMIT -#ifdef FLOATING_POINT_BUGGY_OR_NO_FPU - && qMax(rect.width(), rect.height()) < 128 // integer math breakdown -#endif && s->matrix.type() <= QTransform::TxScale) // no shear { ensureBrush(); @@ -6054,15 +6065,9 @@ static void drawEllipse_midpoint_i(const QRect &rect, const QRect &clip, ProcessSpans pen_func, ProcessSpans brush_func, QSpanData *pen_data, QSpanData *brush_data) { -#ifdef FLOATING_POINT_BUGGY_OR_NO_FPU // no fpu, so use fixed point - const QFixed a = QFixed(rect.width()) >> 1; - const QFixed b = QFixed(rect.height()) >> 1; - QFixed d = b*b - (a*a*b) + ((a*a) >> 2); -#else const qreal a = qreal(rect.width()) / 2; const qreal b = qreal(rect.height()) / 2; qreal d = b*b - (a*a*b) + 0.25*a*a; -#endif int x = 0; int y = (rect.height() + 1) / 2; @@ -6085,12 +6090,7 @@ static void drawEllipse_midpoint_i(const QRect &rect, const QRect &clip, pen_func, brush_func, pen_data, brush_data); // region 2 -#ifdef FLOATING_POINT_BUGGY_OR_NO_FPU - d = b*b*(x + (QFixed(1) >> 1))*(x + (QFixed(1) >> 1)) - + a*a*((y - 1)*(y - 1) - b*b); -#else d = b*b*(x + 0.5)*(x + 0.5) + a*a*((y - 1)*(y - 1) - b*b); -#endif const int miny = rect.height() & 0x1; while (y > miny) { if (d < 0) { // select SE diff --git a/src/gui/painting/qpaintengine_raster_p.h b/src/gui/painting/qpaintengine_raster_p.h index 6148b52..a21560c 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 @@ -259,7 +261,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/qpaintengine_x11.cpp b/src/gui/painting/qpaintengine_x11.cpp index 147491e..da48fcb 100644 --- a/src/gui/painting/qpaintengine_x11.cpp +++ b/src/gui/painting/qpaintengine_x11.cpp @@ -1989,6 +1989,9 @@ void QX11PaintEngine::drawPixmap(const QRectF &r, const QPixmap &px, const QRect } XFillRectangle(d->dpy, d->hd, d->gc, x, y, sw, sh); restore_clip = true; + } else if (mono_dst && !mono_src) { + QBitmap bitmap(pixmap); + XCopyArea(d->dpy, bitmap.handle(), d->hd, d->gc, sx, sy, sw, sh, x, y); } else { XCopyArea(d->dpy, pixmap.handle(), d->hd, d->gc, sx, sy, sw, sh, x, y); } 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 bf12c6b..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 @@ -708,13 +711,14 @@ void QPainterPrivate::updateEmulationSpecifier(QPainterState *s) bool penTextureAlpha = false; if (penBrush.style() == Qt::TexturePattern) penTextureAlpha = qHasPixmapTexture(penBrush) - ? penBrush.texture().hasAlpha() + ? (penBrush.texture().depth() > 1) && penBrush.texture().hasAlpha() : penBrush.textureImage().hasAlphaChannel(); bool brushTextureAlpha = false; - if (s->brush.style() == Qt::TexturePattern) + if (s->brush.style() == Qt::TexturePattern) { brushTextureAlpha = qHasPixmapTexture(s->brush) - ? s->brush.texture().hasAlpha() + ? (s->brush.texture().depth() > 1) && s->brush.texture().hasAlpha() : s->brush.textureImage().hasAlphaChannel(); + } if (((penBrush.style() == Qt::TexturePattern && penTextureAlpha) || (s->brush.style() == Qt::TexturePattern && brushTextureAlpha)) && !engine->hasFeature(QPaintEngine::MaskedBrush)) @@ -1986,12 +1990,25 @@ QPaintEngine *QPainter::paintEngine() const endNativePainting(). Note that only the states the underlying paint engine changes will be reset - to their respective default states. If, for example, the OpenGL polygon - mode is changed by the user inside a beginNativePaint()/endNativePainting() - block, it will not be reset to the default state by endNativePainting(). + to their respective default states. The states we reset may change from + release to release. The following states are currently reset in the OpenGL + 2 engine: + + \list + \i blending is disabled + \i the depth, stencil and scissor tests are disabled + \i the active texture unit is reset to 0 + \i the depth mask, depth function and the clear depth are reset to their + default values + \i the stencil mask, stencil operation and stencil function are reset to + their default values + \i the current color is reset to solid white + \endlist - Here is an example that shows intermixing of painter commands - and raw OpenGL commands: + If, for example, the OpenGL polygon mode is changed by the user inside a + beginNativePaint()/endNativePainting() block, it will not be reset to the + default state by endNativePainting(). Here is an example that shows + intermixing of painter commands and raw OpenGL commands: \snippet doc/src/snippets/code/src_gui_painting_qpainter.cpp 21 @@ -5683,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) @@ -5706,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) @@ -8695,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/painting/qwindowsurface_s60.cpp b/src/gui/painting/qwindowsurface_s60.cpp index 6cbf3d9..028ec48 100644 --- a/src/gui/painting/qwindowsurface_s60.cpp +++ b/src/gui/painting/qwindowsurface_s60.cpp @@ -149,11 +149,19 @@ void QS60WindowSurface::flush(QWidget *widget, const QRegion ®ion, const QPoi Q_ASSERT(window); QTLWExtra *topExtra = window->d_func()->maybeTopData(); Q_ASSERT(topExtra); + QRect qr = region.boundingRect(); if (!topExtra->inExpose) { topExtra->inExpose = true; // Prevent DrawNow() from calling syncBackingStore() again - TRect tr = qt_QRect2TRect(region.boundingRect()); + TRect tr = qt_QRect2TRect(qr); widget->winId()->DrawNow(tr); topExtra->inExpose = false; + } else { + // This handles the case when syncBackingStore updates content outside of the + // original drawing rectangle. This might happen if there are pending update() + // events at the same time as we get a Draw() from Symbian. + QRect drawRect = qt_TRect2QRect(widget->winId()->DrawableWindow()->GetDrawRect()); + if (!drawRect.contains(qr)) + widget->winId()->DrawDeferred(); } } 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 78074c7..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); @@ -3749,7 +3760,7 @@ void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter QPalette np = tab->palette; np.setColor(QPalette::WindowText, QColor(255, 255, 255, 75)); QRect nr = subElementRect(SE_TabBarTabText, opt, w); - nr.moveTop(+1); + nr.moveTop(-1); int alignment = Qt::AlignCenter | Qt::TextShowMnemonic | Qt::TextHideMnemonic; proxy()->drawItemText(p, nr, alignment, np, tab->state & State_Enabled, tab->text, QPalette::WindowText); diff --git a/src/gui/styles/qs60style.cpp b/src/gui/styles/qs60style.cpp index 9025e5b..565cc2c 100644 --- a/src/gui/styles/qs60style.cpp +++ b/src/gui/styles/qs60style.cpp @@ -120,6 +120,8 @@ QPixmap *QS60StylePrivate::m_background = 0; // theme palette QPalette *QS60StylePrivate::m_themePalette = 0; +qint64 QS60StylePrivate::m_webPaletteKey = 0; + const struct QS60StylePrivate::frameElementCenter QS60StylePrivate::m_frameElementsData[] = { {SE_ButtonNormal, QS60StyleEnums::SP_QsnFrButtonTbCenter}, {SE_ButtonPressed, QS60StyleEnums::SP_QsnFrButtonTbCenterPressed}, @@ -289,6 +291,9 @@ void QS60StylePrivate::drawSkinElement(SkinElements element, QPainter *painter, case SE_Editor: drawFrame(SF_FrameLineEdit, painter, rect, flags | SF_PointNorth); break; + case SE_DropArea: + drawPart(QS60StyleEnums::SP_QgnGrafOrgBgGrid, painter, rect, flags | SF_PointNorth); + break; default: break; } @@ -804,8 +809,12 @@ void QS60StylePrivate::setThemePaletteHash(QPalette *palette) const QPalette webPalette = *palette; webPalette.setColor(QPalette::WindowText, Qt::black); webPalette.setColor(QPalette::Text, Qt::black); + webPalette.setBrush(QPalette::Base, Qt::white); + QApplication::setPalette(webPalette, "QWebView"); QApplication::setPalette(webPalette, "QGraphicsWebView"); + + m_webPaletteKey = webPalette.cacheKey(); } QSize QS60StylePrivate::partSize(QS60StyleEnums::SkinParts part, SkinElementFlags flags) @@ -844,15 +853,18 @@ QSize QS60StylePrivate::partSize(QS60StyleEnums::SkinParts part, SkinElementFlag result.setWidth(pixelMetric(PM_Custom_FrameCornerWidth)); break; - case QS60StyleEnums::SP_QsnCpScrollHandleBottomPressed: case QS60StyleEnums::SP_QsnCpScrollHandleTopPressed: - case QS60StyleEnums::SP_QsnCpScrollHandleMiddlePressed: case QS60StyleEnums::SP_QsnCpScrollBgBottom: - case QS60StyleEnums::SP_QsnCpScrollBgMiddle: case QS60StyleEnums::SP_QsnCpScrollBgTop: case QS60StyleEnums::SP_QsnCpScrollHandleBottom: - case QS60StyleEnums::SP_QsnCpScrollHandleMiddle: case QS60StyleEnums::SP_QsnCpScrollHandleTop: + case QS60StyleEnums::SP_QsnCpScrollHandleBottomPressed: + result.setHeight(pixelMetric(QStyle::PM_ScrollBarExtent)); + result.setWidth(pixelMetric(QStyle::PM_ScrollBarExtent)); + break; + case QS60StyleEnums::SP_QsnCpScrollHandleMiddlePressed: + case QS60StyleEnums::SP_QsnCpScrollBgMiddle: + case QS60StyleEnums::SP_QsnCpScrollHandleMiddle: result.setHeight(pixelMetric(QStyle::PM_ScrollBarExtent)); result.setWidth(pixelMetric(QStyle::PM_ScrollBarSliderMin)); break; @@ -890,8 +902,11 @@ QSize QS60StylePrivate::partSize(QS60StyleEnums::SkinParts part, SkinElementFlag return result; } -bool QS60StylePrivate::canDrawThemeBackground(const QBrush &backgroundBrush) +bool QS60StylePrivate::canDrawThemeBackground(const QBrush &backgroundBrush, const QWidget *widget) { + // Always return true for web pages. + if (widget && m_webPaletteKey == QApplication::palette(widget).cacheKey()) + return true; //If brush is not changed from style's default values, draw theme graphics. return (backgroundBrush.color() == Qt::transparent || backgroundBrush.style() == Qt::NoBrush) ? true : false; @@ -1895,7 +1910,7 @@ void QS60Style::drawControl(ControlElement element, const QStyleOption *option, case CE_ShapedFrame: if (const QTextEdit *textEdit = qobject_cast<const QTextEdit *>(widget)) { const QStyleOptionFrame *frame = qstyleoption_cast<const QStyleOptionFrame *>(option); - if (QS60StylePrivate::canDrawThemeBackground(frame->palette.base())) + if (QS60StylePrivate::canDrawThemeBackground(frame->palette.base(), widget)) QS60StylePrivate::drawSkinElement(QS60StylePrivate::SE_Editor, painter, option->rect, flags); else QCommonStyle::drawControl(element, option, painter, widget); @@ -2007,7 +2022,7 @@ void QS60Style::drawPrimitive(PrimitiveElement element, const QStyleOption *opti if (widget && qobject_cast<const QComboBox *>(widget->parentWidget())) break; #endif - if (QS60StylePrivate::canDrawThemeBackground(option->palette.base())) + if (QS60StylePrivate::canDrawThemeBackground(option->palette.base(), widget)) QS60StylePrivate::drawSkinElement(QS60StylePrivate::SE_FrameLineEdit, painter, option->rect, flags); else commonStyleDraws = true; @@ -2087,7 +2102,7 @@ void QS60Style::drawPrimitive(PrimitiveElement element, const QStyleOption *opti case PE_PanelButtonTool: case PE_PanelButtonBevel: case PE_FrameButtonBevel: - if (QS60StylePrivate::canDrawThemeBackground(option->palette.base())) { + if (QS60StylePrivate::canDrawThemeBackground(option->palette.base(), widget)) { const bool isPressed = option->state & State_Sunken; const QS60StylePrivate::SkinElements skinElement = isPressed ? QS60StylePrivate::SE_ButtonPressed : QS60StylePrivate::SE_ButtonNormal; @@ -2119,7 +2134,7 @@ void QS60Style::drawPrimitive(PrimitiveElement element, const QStyleOption *opti case PE_IndicatorSpinDown: case PE_IndicatorSpinUp: if (const QStyleOptionSpinBox *spinBox = qstyleoption_cast<const QStyleOptionSpinBox *>(option)) { - if (QS60StylePrivate::canDrawThemeBackground(spinBox->palette.base())) { + if (QS60StylePrivate::canDrawThemeBackground(spinBox->palette.base(), widget)) { QStyleOptionSpinBox optionSpinBox = *spinBox; const QS60StyleEnums::SkinParts part = (element == PE_IndicatorSpinUp) ? QS60StyleEnums::SP_QgnGrafScrollArrowUp : @@ -2134,7 +2149,7 @@ void QS60Style::drawPrimitive(PrimitiveElement element, const QStyleOption *opti #endif //QT_NO_SPINBOX #ifndef QT_NO_COMBOBOX if (const QStyleOptionFrame *cmb = qstyleoption_cast<const QStyleOptionFrame *>(option)) { - if (QS60StylePrivate::canDrawThemeBackground( option->palette.base())) { + if (QS60StylePrivate::canDrawThemeBackground( option->palette.base(), widget)) { // We want to draw down arrow here for comboboxes as well. QStyleOptionFrame optionsComboBox = *cmb; const QS60StyleEnums::SkinParts part = QS60StyleEnums::SP_QgnGrafScrollArrowDown; @@ -2173,7 +2188,7 @@ void QS60Style::drawPrimitive(PrimitiveElement element, const QStyleOption *opti #endif //QT_NO_MENU ) { //Need extra check since dialogs have their own theme background - if (QS60StylePrivate::canDrawThemeBackground(option->palette.base()) && + if (QS60StylePrivate::canDrawThemeBackground(option->palette.base(), widget) && option->palette.window().texture().cacheKey() == QS60StylePrivate::m_themePalette->window().texture().cacheKey()) QS60StylePrivate::drawSkinElement(QS60StylePrivate::SE_OptionsMenu, painter, option->rect, flags); @@ -2271,14 +2286,16 @@ void QS60Style::drawPrimitive(PrimitiveElement element, const QStyleOption *opti QS60StyleEnums::SkinParts skinPart = (option->state & State_Open) ? QS60StyleEnums::SP_QgnIndiHlColSuper : QS60StyleEnums::SP_QgnIndiHlExpSuper; int minDimension = qMin(option->rect.width(), option->rect.height()); - const int resizeValue = minDimension >> 1; - minDimension += resizeValue; // Adjust the icon bigger because of empty space in svg icon. QRect iconRect(option->rect.topLeft(), QSize(minDimension, minDimension)); - int verticalMagic(0); - // magic values for positioning svg icon. - if (option->rect.width() <= option->rect.height()) - verticalMagic = 3; - iconRect.translate(3, verticalMagic - resizeValue); + const int magicTweak = 3; + int resizeValue = minDimension >> 1; + if (!QS60StylePrivate::isTouchSupported()) { + minDimension += resizeValue; // Adjust the icon bigger because of empty space in svg icon. + iconRect.setSize(QSize(minDimension, minDimension)); + const int verticalMagic = (option->rect.width() <= option->rect.height()) ? magicTweak : 0; + resizeValue = verticalMagic - resizeValue; + } + iconRect.translate(magicTweak, resizeValue); QS60StylePrivate::drawSkinPart(skinPart, painter, iconRect, flags); } } @@ -2302,7 +2319,12 @@ void QS60Style::drawPrimitive(PrimitiveElement element, const QStyleOption *opti break; case PE_PanelScrollAreaCorner: break; - + case PE_IndicatorItemViewItemDrop: + if (QS60StylePrivate::isTouchSupported()) + QS60StylePrivate::drawSkinElement(QS60StylePrivate::SE_DropArea, painter, option->rect, flags); + else + commonStyleDraws = true; + break; // todo: items are below with #ifdefs "just in case". in final version, remove all non-required cases case PE_FrameLineEdit: case PE_IndicatorDockWidgetResizeHandle: @@ -2323,7 +2345,6 @@ void QS60Style::drawPrimitive(PrimitiveElement element, const QStyleOption *opti #endif //QT_NO_TOOLBAR #ifndef QT_NO_COLUMNVIEW case PE_IndicatorColumnViewArrow: - case PE_IndicatorItemViewItemDrop: #endif //QT_NO_COLUMNVIEW case PE_FrameTabBarBase: // since tabs are in S60 always in navipane, let's use common style for tab base in Qt. default: @@ -2375,10 +2396,20 @@ QSize QS60Style::sizeFromContents(ContentsType ct, const QStyleOption *opt, case CT_PushButton: sz = QCommonStyle::sizeFromContents( ct, opt, csz, widget); //FIXME properly - style should calculate the location of border frame-part - sz += QSize(2 * pixelMetric(PM_ButtonMargin), 2 * pixelMetric(PM_ButtonMargin)); - if (const QAbstractButton *buttonWidget = (qobject_cast<const QAbstractButton *>(widget))) + if (const QAbstractButton *buttonWidget = (qobject_cast<const QAbstractButton *>(widget))) { if (buttonWidget->isCheckable()) sz += QSize(pixelMetric(PM_IndicatorWidth) + pixelMetric(PM_CheckBoxLabelSpacing), 0); + const int iconHeight = (!buttonWidget->icon().isNull()) ? buttonWidget->iconSize().height() : 0; + const int textHeight = (buttonWidget->text().length() > 0) ? + buttonWidget->fontMetrics().size(Qt::TextSingleLine, buttonWidget->text()).height() : 0; + const int decoratorHeight = (buttonWidget->isCheckable()) ? pixelMetric(PM_IndicatorHeight) : 0; + + const int contentHeight = + qMax(qMax(iconHeight, decoratorHeight) + pixelMetric(PM_ButtonMargin), + textHeight + 2*pixelMetric(PM_ButtonMargin)); + sz.setHeight(contentHeight); + sz += QSize(2 * pixelMetric(PM_ButtonMargin), 0); + } break; case CT_LineEdit: if (const QStyleOptionFrame *f = qstyleoption_cast<const QStyleOptionFrame *>(opt)) @@ -2481,6 +2512,9 @@ int QS60Style::styleHint(StyleHint sh, const QStyleOption *opt, const QWidget *w case SH_FormLayoutWrapPolicy: retValue = QFormLayout::WrapLongRows; break; + case SH_ScrollBar_ContextMenu: + retValue = false; + break; default: retValue = QCommonStyle::styleHint(sh, opt, widget, hret); break; @@ -2559,11 +2593,11 @@ QRect QS60Style::subControlRect(ComplexControl control, const QStyleOptionComple if (const QStyleOptionSpinBox *spinbox = qstyleoption_cast<const QStyleOptionSpinBox *>(option)) { const int frameThickness = spinbox->frame ? pixelMetric(PM_SpinBoxFrameWidth, spinbox, widget) : 0; const int buttonMargin = spinbox->frame ? 2 : 0; - const int buttonWidth = QS60StylePrivate::pixelMetric(PM_ButtonIconSize) + 2 * buttonMargin; + const int buttonContentWidth = QS60StylePrivate::pixelMetric(PM_ButtonIconSize) + 2 * buttonMargin; QSize buttonSize; buttonSize.setHeight(qMax(8, spinbox->rect.height() - frameThickness)); //width should at least be equal to height - buttonSize.setWidth(qMax(buttonSize.height(), buttonWidth)); + buttonSize.setWidth(qMax(buttonSize.height(), buttonContentWidth)); buttonSize = buttonSize.expandedTo(QApplication::globalStrut()); const int y = frameThickness + spinbox->rect.y(); diff --git a/src/gui/styles/qs60style_p.h b/src/gui/styles/qs60style_p.h index eae2291..16d82e7 100644 --- a/src/gui/styles/qs60style_p.h +++ b/src/gui/styles/qs60style_p.h @@ -131,6 +131,7 @@ public: SP_QgnGrafBarFrameSideL, SP_QgnGrafBarFrameSideR, SP_QgnGrafBarProgress, + SP_QgnGrafOrgBgGrid, SP_QgnGrafScrollArrowDown, SP_QgnGrafScrollArrowLeft, SP_QgnGrafScrollArrowRight, @@ -428,6 +429,7 @@ public: SE_ScrollBarHandlePressedVertical, SE_ButtonInactive, SE_Editor, + SE_DropArea }; enum SkinFrameElements { @@ -540,7 +542,7 @@ public: //Checks that the current brush is transparent or has BrushStyle NoBrush, //so that theme graphic background can be drawn. - static bool canDrawThemeBackground(const QBrush &backgroundBrush); + static bool canDrawThemeBackground(const QBrush &backgroundBrush, const QWidget *widget); static int currentAnimationFrame(QS60StyleEnums::SkinParts part); #ifdef Q_WS_S60 @@ -594,6 +596,7 @@ private: QPalette m_originalPalette; QPointer<QFocusFrame> m_focusFrame; + static qint64 m_webPaletteKey; #ifdef Q_WS_S60 //list of progress bars having animation running diff --git a/src/gui/styles/qs60style_s60.cpp b/src/gui/styles/qs60style_s60.cpp index 872bc2b..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> @@ -178,6 +178,8 @@ const partMapEntry QS60StyleModeSpecifics::m_partMap[] = { /* SP_QgnGrafBarFrameSideL */ {KAknsIIDQgnGrafBarFrameSideL, EDrawIcon, ES60_All, -1,-1}, /* SP_QgnGrafBarFrameSideR */ {KAknsIIDQgnGrafBarFrameSideR, EDrawIcon, ES60_All, -1,-1}, /* SP_QgnGrafBarProgress */ {KAknsIIDQgnGrafBarProgress, EDrawIcon, ES60_All, -1,-1}, + // No drop area for 3.x non-touch devices + /* SP_QgnGrafOrgBgGrid */ {KAknsIIDNone, EDrawIcon, ES60_3_X, EAknsMajorGeneric ,0x1eba}, //KAknsIIDQgnGrafOrgBgGrid /* SP_QgnGrafScrollArrowDown */ {KAknsIIDQgnGrafScrollArrowDown, EDrawGulIcon, ES60_All, -1,-1}, /* SP_QgnGrafScrollArrowLeft */ {KAknsIIDQgnGrafScrollArrowLeft, EDrawGulIcon, ES60_All, -1,-1}, /* SP_QgnGrafScrollArrowRight */ {KAknsIIDQgnGrafScrollArrowRight, EDrawGulIcon, ES60_All, -1,-1}, 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 b36294a..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()) @@ -5743,6 +5749,13 @@ QRect QStyleSheetStyle::subElementRect(SubElement se, const QStyleOption *opt, c return positionRect(w, subRule, subRule2, pe, opt->rect, opt->direction); } +#ifndef QT_NO_TOOLBAR + case SE_ToolBarHandle: + if (hasStyleRule(w, PseudoElement_ToolBarHandle)) + return ParentStyle::subElementRect(se, opt, w); + break; +#endif //QT_NO_TOOLBAR + default: break; } diff --git a/src/gui/text/qfont.cpp b/src/gui/text/qfont.cpp index b20fd9b..01e4ef6 100644 --- a/src/gui/text/qfont.cpp +++ b/src/gui/text/qfont.cpp @@ -633,8 +633,9 @@ QFontEngineData::~QFontEngineData() Returns the name of the font within the underlying window system. - Only on X11 when Qt was built without FontConfig support the XLFD (X Logical Font Description) - is returned; otherwise an empty string. + On X11, this function will return an empty string if Qt is built with + FontConfig support; otherwise the XLFD (X Logical Font Description) is + returned. Using the return value of this function is usually \e not \e portable. diff --git a/src/gui/text/qfont.h b/src/gui/text/qfont.h index a44c6cf..d71828d 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 05c8f08..c50d363 100644 --- a/src/gui/text/qfontdatabase_win.cpp +++ b/src/gui/text/qfontdatabase_win.cpp @@ -336,8 +336,18 @@ void addFontToDatabase(QString familyName, const QString &scriptName, signature->fsCsb[0], signature->fsCsb[1] }; QList<QFontDatabase::WritingSystem> systems = determineWritingSystemsFromTrueTypeBits(unicodeRange, codePageRange); - for (int i = 0; i < systems.count(); ++i) - family->writingSystems[systems.at(i)] = QtFontFamily::Supported; + + for (int i = 0; i < systems.count(); ++i) { + QFontDatabase::WritingSystem writingSystem = systems.at(i); + + // ### Hack to work around problem with Thai text on Windows 7. Segoe UI contains + // the symbol for Baht, and Windows thus reports that it supports the Thai script. + // Since it's the default UI font on this platform, most widgets will be unable to + // display Thai text by default. As a temporary work around, we special case Segoe UI + // and remove the Thai script from its list of supported writing systems. + if (writingSystem != QFontDatabase::Thai || familyName != QLatin1String("Segoe UI")) + family->writingSystems[writingSystem] = QtFontFamily::Supported; + } } else if (!family->writingSystemCheck) { //qDebug("family='%s' script=%s", family->name.latin1(), script.latin1()); if (scriptName == QLatin1String("Western") @@ -1101,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 0dd8f4b..4063749 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.cpp b/src/gui/text/qfontengine_s60.cpp index 9dd4af7..3ea084b 100644 --- a/src/gui/text/qfontengine_s60.cpp +++ b/src/gui/text/qfontengine_s60.cpp @@ -44,7 +44,7 @@ #include "qglobal.h" #include <private/qapplication_p.h> #include "qimage.h" -#include "qt_s60_p.h" +#include <private/qt_s60_p.h> #include <e32base.h> #include <e32std.h> 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/qtextlayout.cpp b/src/gui/text/qtextlayout.cpp index 26c7c1e..af91603 100644 --- a/src/gui/text/qtextlayout.cpp +++ b/src/gui/text/qtextlayout.cpp @@ -1331,7 +1331,7 @@ void QTextLayout::drawCursor(QPainter *p, const QPointF &pos, int cursorPosition QTextLine l(line, d); const QScriptLine &sl = d->lines[line]; - const qreal x = position.x() + l.cursorToX(cursorPosition); + qreal x = position.x() + l.cursorToX(cursorPosition); int itm = d->findItem(cursorPosition - 1); QFixed base = sl.base(); @@ -1350,6 +1350,10 @@ void QTextLayout::drawCursor(QPainter *p, const QPointF &pos, int cursorPosition && (p->transform().type() > QTransform::TxTranslate); if (toggleAntialiasing) p->setRenderHint(QPainter::Antialiasing); +#if defined(QT_MAC_USE_COCOA) + // Always draw the cursor aligned to pixel boundary. + x = qRound(x); +#endif p->fillRect(QRectF(x, y, qreal(width), (base + descent + 1).toReal()), p->pen().brush()); if (toggleAntialiasing) p->setRenderHint(QPainter::Antialiasing, false); 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 a6b5084..f1d5534 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 319c4b0..65b998f 100644 --- a/src/gui/util/qdesktopservices_s60.cpp +++ b/src/gui/util/qdesktopservices_s60.cpp @@ -48,7 +48,6 @@ #include <qurl.h> #include <private/qcore_symbian_p.h> -#include <miutset.h> // KUidMsgTypeSMTP #include <txtrich.h> // CRichText #include <f32file.h> // TDriveUnit etc #include <eikenv.h> // CEikonEnv @@ -57,6 +56,9 @@ #include <rsendas.h> // RSendAs #include <rsendasmessage.h> // RSendAsMessage +// copied from miutset.h, so we don't get a dependency into the app layer +const TUid KUidMsgTypeSMTP = {0x10001028}; // 268439592 + #ifdef Q_WS_S60 # include <pathinfo.h> // PathInfo # ifdef USE_DOCUMENTHANDLER @@ -413,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_p.h b/src/gui/util/qsystemtrayicon_p.h index b881f68..e8bf197 100644 --- a/src/gui/util/qsystemtrayicon_p.h +++ b/src/gui/util/qsystemtrayicon_p.h @@ -164,7 +164,9 @@ protected: bool x11Event(XEvent *event); void mousePressEvent(QMouseEvent *event); void mouseDoubleClickEvent(QMouseEvent *event); +#ifndef QT_NO_WHEELEVENT void wheelEvent(QWheelEvent *event); +#endif bool event(QEvent *e); private: 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/util/qsystemtrayicon_x11.cpp b/src/gui/util/qsystemtrayicon_x11.cpp index a645050..82b4325 100644 --- a/src/gui/util/qsystemtrayicon_x11.cpp +++ b/src/gui/util/qsystemtrayicon_x11.cpp @@ -308,10 +308,12 @@ void QSystemTrayIconSys::mouseDoubleClickEvent(QMouseEvent *ev) emit q->activated(QSystemTrayIcon::DoubleClick); } +#ifndef QT_NO_WHEELEVENT void QSystemTrayIconSys::wheelEvent(QWheelEvent *e) { QApplication::sendEvent(q, e); } +#endif bool QSystemTrayIconSys::event(QEvent *e) { 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/qabstractslider.cpp b/src/gui/widgets/qabstractslider.cpp index 73c17db..2888490 100644 --- a/src/gui/widgets/qabstractslider.cpp +++ b/src/gui/widgets/qabstractslider.cpp @@ -47,9 +47,6 @@ #ifndef QT_NO_ACCESSIBILITY #include "qaccessible.h" #endif -#ifdef QT_KEYPAD_NAVIGATION -#include "qtabwidget.h" // Needed in inTabWidget() -#endif // QT_KEYPAD_NAVIGATION #include <limits.h> QT_BEGIN_NAMESPACE @@ -702,10 +699,14 @@ bool QAbstractSliderPrivate::scrollByDelta(Qt::Orientation orientation, Qt::Keyb stepsToScroll = qBound(-pageStep, int(offset * pageStep), pageStep); offset_accumulated = 0; } else { - // Calculate how many lines to scroll. Depending on what delta is (and + // Calculate how many lines to scroll. Depending on what delta is (and // offset), we might end up with a fraction (e.g. scroll 1.3 lines). We can // only scroll whole lines, so we keep the reminder until next event. - qreal stepsToScrollF = offset * QApplication::wheelScrollLines() * effectiveSingleStep(); + qreal stepsToScrollF = +#ifndef QT_NO_WHEELEVENT + QApplication::wheelScrollLines() * +#endif + offset * effectiveSingleStep(); // Check if wheel changed direction since last event: if (offset_accumulated != 0 && (offset / offset_accumulated) < 0) offset_accumulated = 0; @@ -745,45 +746,7 @@ void QAbstractSlider::wheelEvent(QWheelEvent * e) } #endif -#ifdef QT_KEYPAD_NAVIGATION -/*! - \internal - - Tells us if it there is currently a reachable widget by keypad navigation in - a certain \a orientation. - If no navigation is possible, occuring key events in that \a orientation may - be used to interact with the value in the focussed widget, even though it - currently has not the editFocus. - \sa QWidgetPrivate::widgetInNavigationDirection(), QWidget::hasEditFocus() -*/ -inline static bool canKeypadNavigate(Qt::Orientation orientation) -{ - return orientation == Qt::Horizontal? - (QWidgetPrivate::widgetInNavigationDirection(QWidgetPrivate::DirectionEast) - || QWidgetPrivate::widgetInNavigationDirection(QWidgetPrivate::DirectionWest)) - :(QWidgetPrivate::widgetInNavigationDirection(QWidgetPrivate::DirectionNorth) - || QWidgetPrivate::widgetInNavigationDirection(QWidgetPrivate::DirectionSouth)); -} -/*! - \internal - - Checks, if the \a widget is inside a QTabWidget. If is is inside - one, left/right key events will be used to switch between tabs in keypad - navigation. If there is no QTabWidget, the horizontal key events can be used to - interact with the value in the focussed widget, even though it currently has - not the editFocus. - - \sa QWidget::hasEditFocus() -*/ -inline static bool inTabWidget(QWidget *widget) -{ - for (QWidget *tabWidget = widget; tabWidget; tabWidget = tabWidget->parentWidget()) - if (qobject_cast<const QTabWidget*>(tabWidget)) - return true; - return false; -} -#endif // QT_KEYPAD_NAVIGATION /*! \reimp */ @@ -849,7 +812,8 @@ void QAbstractSlider::keyPressEvent(QKeyEvent *ev) if (QApplication::keypadNavigationEnabled() && (!hasEditFocus() && QApplication::navigationMode() == Qt::NavigationModeKeypadTabOrder || d->orientation == Qt::Vertical - || !hasEditFocus() && (canKeypadNavigate(Qt::Horizontal) || inTabWidget(this)))) { + || !hasEditFocus() + && (QWidgetPrivate::canKeypadNavigate(Qt::Horizontal) || QWidgetPrivate::inTabWidget(this)))) { ev->ignore(); return; } @@ -868,7 +832,8 @@ void QAbstractSlider::keyPressEvent(QKeyEvent *ev) if (QApplication::keypadNavigationEnabled() && (!hasEditFocus() && QApplication::navigationMode() == Qt::NavigationModeKeypadTabOrder || d->orientation == Qt::Vertical - || !hasEditFocus() && (canKeypadNavigate(Qt::Horizontal) || inTabWidget(this)))) { + || !hasEditFocus() + && (QWidgetPrivate::canKeypadNavigate(Qt::Horizontal) || QWidgetPrivate::inTabWidget(this)))) { ev->ignore(); return; } @@ -888,7 +853,7 @@ void QAbstractSlider::keyPressEvent(QKeyEvent *ev) if (QApplication::keypadNavigationEnabled() && (QApplication::navigationMode() == Qt::NavigationModeKeypadTabOrder || d->orientation == Qt::Horizontal - || !hasEditFocus() && canKeypadNavigate(Qt::Vertical))) { + || !hasEditFocus() && QWidgetPrivate::canKeypadNavigate(Qt::Vertical))) { ev->ignore(); break; } @@ -901,7 +866,7 @@ void QAbstractSlider::keyPressEvent(QKeyEvent *ev) if (QApplication::keypadNavigationEnabled() && (QApplication::navigationMode() == Qt::NavigationModeKeypadTabOrder || d->orientation == Qt::Horizontal - || !hasEditFocus() && canKeypadNavigate(Qt::Vertical))) { + || !hasEditFocus() && QWidgetPrivate::canKeypadNavigate(Qt::Vertical))) { ev->ignore(); break; } diff --git a/src/gui/widgets/qabstractspinbox.h b/src/gui/widgets/qabstractspinbox.h index 059943a..6c062c0 100644 --- a/src/gui/widgets/qabstractspinbox.h +++ b/src/gui/widgets/qabstractspinbox.h @@ -137,7 +137,9 @@ protected: void resizeEvent(QResizeEvent *event); void keyPressEvent(QKeyEvent *event); void keyReleaseEvent(QKeyEvent *event); +#ifndef QT_NO_WHEELEVENT void wheelEvent(QWheelEvent *event); +#endif void focusInEvent(QFocusEvent *event); void focusOutEvent(QFocusEvent *event); void contextMenuEvent(QContextMenuEvent *event); 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 72f32dc..f71d250 100644 --- a/src/gui/widgets/qcombobox.cpp +++ b/src/gui/widgets/qcombobox.cpp @@ -607,7 +607,13 @@ void QComboBoxPrivateContainer::changeEvent(QEvent *e) view->setMouseTracking(combo->style()->styleHint(QStyle::SH_ComboBox_ListMouseTracking, &opt, combo) || combo->style()->styleHint(QStyle::SH_ComboBox_Popup, &opt, combo)); setFrameStyle(combo->style()->styleHint(QStyle::SH_ComboBox_PopupFrameStyle, &opt, combo)); +#ifdef QT_SOFTKEYS_ENABLED + } else if (e->type() == QEvent::LanguageChange) { + selectAction->setText(QSoftKeyManager::standardSoftKeyText(QSoftKeyManager::SelectSoftKey)); + cancelAction->setText(QSoftKeyManager::standardSoftKeyText(QSoftKeyManager::CancelSoftKey)); +#endif } + QWidget::changeEvent(e); } @@ -1268,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 { @@ -2348,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/qcombobox.h b/src/gui/widgets/qcombobox.h index f332d31..9b19a66 100644 --- a/src/gui/widgets/qcombobox.h +++ b/src/gui/widgets/qcombobox.h @@ -245,7 +245,9 @@ protected: void mouseReleaseEvent(QMouseEvent *e); void keyPressEvent(QKeyEvent *e); void keyReleaseEvent(QKeyEvent *e); +#ifndef QT_NO_WHEELEVENT void wheelEvent(QWheelEvent *e); +#endif void contextMenuEvent(QContextMenuEvent *e); void inputMethodEvent(QInputMethodEvent *); QVariant inputMethodQuery(Qt::InputMethodQuery) const; 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 d754800..c1b1ea3 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; @@ -2635,7 +2637,7 @@ void QDockAreaLayout::getGrid(QVector<QLayoutStruct> *_ver_struct_list, QSize bottom_max = docks[QInternal::BottomDock].maximumSize(); bottom_hint = bottom_hint.boundedTo(bottom_max).expandedTo(bottom_min); - fallbackToSizeHints = !have_central; + fallbackToSizeHints = false; if (_ver_struct_list != 0) { QVector<QLayoutStruct> &ver_struct_list = *_ver_struct_list; @@ -2991,8 +2993,7 @@ bool QDockAreaLayout::restoreDockWidget(QDockWidget *dockWidget) QRect r = constrainedRect(placeHolder->topLevelRect, desktop.screenGeometry(dockWidget)); dockWidget->d_func()->setWindowState(true, true, r); } - dockWidget->show(); -// dockWidget->setVisible(!placeHolder->hidden); + dockWidget->setVisible(!placeHolder->hidden); #ifdef Q_WS_X11 if (placeHolder->window) // gets rid of the X11BypassWindowManager window flag dockWidget->d_func()->setWindowState(true); @@ -3028,7 +3029,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 +3325,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/qlinecontrol.cpp b/src/gui/widgets/qlinecontrol.cpp index 9ab4569..544c903 100644 --- a/src/gui/widgets/qlinecontrol.cpp +++ b/src/gui/widgets/qlinecontrol.cpp @@ -1371,6 +1371,8 @@ bool QLineControl::processEvent(QEvent* ev) processInputMethodEvent(static_cast<QInputMethodEvent*>(ev)); break; #ifndef QT_NO_SHORTCUT case QEvent::ShortcutOverride:{ + if (isReadOnly()) + return false; QKeyEvent* ke = static_cast<QKeyEvent*>(ev); if (ke == QKeySequence::Copy || ke == QKeySequence::Paste 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/qlineedit_p.cpp b/src/gui/widgets/qlineedit_p.cpp index 1aa7a2b..2c76a5c 100644 --- a/src/gui/widgets/qlineedit_p.cpp +++ b/src/gui/widgets/qlineedit_p.cpp @@ -129,7 +129,7 @@ void QLineEditPrivate::_q_editFocusChange(bool e) void QLineEditPrivate::_q_selectionChanged() { Q_Q(QLineEdit); - if (control->preeditAreaText().isEmpty()) { + if (!control->text().isEmpty() && control->preeditAreaText().isEmpty()) { QStyleOptionFrameV2 opt; q->initStyleOption(&opt); bool showCursor = control->hasSelectedText() ? diff --git a/src/gui/widgets/qmainwindow.cpp b/src/gui/widgets/qmainwindow.cpp index 269cd12..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; @@ -1426,6 +1427,11 @@ bool QMainWindow::event(QEvent *event) } break; #endif +#ifdef QT_SOFTKEYS_ENABLED + case QEvent::LanguageChange: + d->menuBarAction->setText(QSoftKeyManager::standardSoftKeyText(QSoftKeyManager::MenuSoftKey)); + break; +#endif default: break; } @@ -1554,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/qmainwindowlayout.cpp b/src/gui/widgets/qmainwindowlayout.cpp index fc75c92..593e391 100644 --- a/src/gui/widgets/qmainwindowlayout.cpp +++ b/src/gui/widgets/qmainwindowlayout.cpp @@ -1772,6 +1772,7 @@ void QMainWindowLayout::setCentralWidget(QWidget *widget) if (savedState.isValid()) { #ifndef QT_NO_DOCKWIDGET savedState.dockAreaLayout.centralWidgetItem = layoutState.dockAreaLayout.centralWidgetItem; + savedState.dockAreaLayout.fallbackToSizeHints = true; #else savedState.centralWidgetItem = layoutState.centralWidgetItem; #endif diff --git a/src/gui/widgets/qmenu.cpp b/src/gui/widgets/qmenu.cpp index 8ce7cc0..e2cf25b 100644 --- a/src/gui/widgets/qmenu.cpp +++ b/src/gui/widgets/qmenu.cpp @@ -117,7 +117,7 @@ public: if (parentWidget->parentWidget()) parentWidget = parentWidget->parentWidget(); setParent(parentWidget, Qt::Window | Qt::Tool); - setAttribute(Qt::WA_DeleteOnClose, true); + setAttribute(Qt::WA_DeleteOnClose, true); setAttribute(Qt::WA_X11NetWmWindowTypeMenu, true); setWindowTitle(p->windowTitle()); setEnabled(p->isEnabled()); @@ -1226,7 +1226,7 @@ void QMenu::initStyleOption(QStyleOptionMenuItem *option, const QAction *action) else if (action->isSeparator()) option->menuItemType = QStyleOptionMenuItem::Separator; else if (d->defaultAction == action) - option->menuItemType = QStyleOptionMenuItem::DefaultItem; + option->menuItemType = QStyleOptionMenuItem::DefaultItem; else option->menuItemType = QStyleOptionMenuItem::Normal; if (action->isIconVisibleInMenu()) @@ -1719,7 +1719,14 @@ bool QMenu::isEmpty() const void QMenu::clear() { QList<QAction*> acts = actions(); + for(int i = 0; i < acts.size(); i++) { +#ifdef QT_SOFTKEYS_ENABLED + Q_D(QMenu); + // Lets not touch to our internal softkey actions + if(acts[i] == d->selectAction || acts[i] == d->cancelAction) + continue; +#endif removeAction(acts[i]); if (acts[i]->parent() == this && acts[i]->d_func()->widgets.isEmpty()) delete acts[i]; @@ -2302,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) @@ -2408,6 +2413,13 @@ QMenu::event(QEvent *e) } return true; #endif +#ifdef QT_SOFTKEYS_ENABLED + case QEvent::LanguageChange: { + d->selectAction->setText(QSoftKeyManager::standardSoftKeyText(QSoftKeyManager::SelectSoftKey)); + d->cancelAction->setText(QSoftKeyManager::standardSoftKeyText(QSoftKeyManager::CancelSoftKey)); + } + break; +#endif default: break; } @@ -2919,7 +2931,7 @@ void QMenu::actionEvent(QActionEvent *e) #endif if (isVisible()) { d->updateActionRects(); - resize(sizeHint()); + resize(sizeHint()); update(); } } diff --git a/src/gui/widgets/qmenu.h b/src/gui/widgets/qmenu.h index 5a6a5c7..a040afa 100644 --- a/src/gui/widgets/qmenu.h +++ b/src/gui/widgets/qmenu.h @@ -162,7 +162,9 @@ protected: void mouseReleaseEvent(QMouseEvent *); void mousePressEvent(QMouseEvent *); void mouseMoveEvent(QMouseEvent *); +#ifndef QT_NO_WHEELEVENT void wheelEvent(QWheelEvent *); +#endif void enterEvent(QEvent *); void leaveEvent(QEvent *); void hideEvent(QHideEvent *); @@ -415,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/qscrollbar.cpp b/src/gui/widgets/qscrollbar.cpp index 3eed3a9..4eff260 100644 --- a/src/gui/widgets/qscrollbar.cpp +++ b/src/gui/widgets/qscrollbar.cpp @@ -521,6 +521,7 @@ bool QScrollBar::event(QEvent *event) if (const QHoverEvent *he = static_cast<const QHoverEvent *>(event)) d_func()->updateHoverControl(he->pos()); break; +#ifndef QT_NO_WHEELEVENT case QEvent::Wheel: { // override wheel event without adding virtual function override QWheelEvent *ev = static_cast<QWheelEvent *>(event); @@ -537,6 +538,7 @@ bool QScrollBar::event(QEvent *event) event->accept(); return true; } +#endif default: break; } 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(); |