diff options
Diffstat (limited to 'src/plugins/platforms/windows')
32 files changed, 1149 insertions, 806 deletions
diff --git a/src/plugins/platforms/windows/accessible/iaccessible2.cpp b/src/plugins/platforms/windows/accessible/iaccessible2.cpp index 164bd6eed9..7a28fd9074 100644 --- a/src/plugins/platforms/windows/accessible/iaccessible2.cpp +++ b/src/plugins/platforms/windows/accessible/iaccessible2.cpp @@ -44,7 +44,7 @@ #include "iaccessible2.h" #include "qwindowsaccessibility.h" -#include <QtGui/qaccessible2.h> +#include <QtGui/private/qaccessible2_p.h> #include <QtGui/qclipboard.h> #include <QtWidgets/qapplication.h> #include <QtCore/qdebug.h> @@ -230,6 +230,10 @@ HRESULT STDMETHODCALLTYPE AccessibleRelation::get_targets( **************************************************************/ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::QueryInterface(REFIID id, LPVOID *iface) { + QAccessibleInterface *accessible = accessibleInterface(); + if (!accessible) + return E_NOINTERFACE; + HRESULT hr = QWindowsMsaaAccessible::QueryInterface(id, iface); if (!SUCCEEDED(hr)) { if (id == IID_IServiceProvider) { @@ -301,10 +305,11 @@ ULONG STDMETHODCALLTYPE QWindowsIA2Accessible::Release() **************************************************************/ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_nRelations(long *nRelations) { + QAccessibleInterface *accessible = accessibleInterface(); accessibleDebugClientCalls(accessible); if (!nRelations) return E_INVALIDARG; - if (!accessible->isValid()) + if (!accessible) return E_FAIL; return getRelationsHelper(0, 0, 0, nRelations); @@ -312,10 +317,11 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_nRelations(long *nRelations HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_relation(long relationIndex, IAccessibleRelation **relation) { + QAccessibleInterface *accessible = accessibleInterface(); accessibleDebugClientCalls(accessible); if (!relation) return E_INVALIDARG; - if (!accessible->isValid()) + if (!accessible) return E_FAIL; return getRelationsHelper(relation, relationIndex, 1); @@ -330,8 +336,9 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_relations(long maxRelations IAccessibleRelation **relations, long *nRelations) { + QAccessibleInterface *accessible = accessibleInterface(); accessibleDebugClientCalls(accessible); - if (!accessible->isValid()) + if (!accessible) return E_FAIL; return getRelationsHelper(relations, 0, maxRelations, nRelations); @@ -340,8 +347,9 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_relations(long maxRelations HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::role(long *ia2role) { + QAccessibleInterface *accessible = accessibleInterface(); accessibleDebugClientCalls(accessible); - if (!accessible->isValid()) + if (!accessible) return E_FAIL; long r = accessible->role(); @@ -386,8 +394,9 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_groupPosition(long *groupLe HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_states(AccessibleStates *states) { + QAccessibleInterface *accessible = accessibleInterface(); accessibleDebugClientCalls(accessible); - if (!accessible->isValid()) + if (!accessible) return E_FAIL; if (!states) return E_POINTER; @@ -462,23 +471,23 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_localizedExtendedStates(lon HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_uniqueID(long *outUniqueID) { + QAccessibleInterface *accessible = accessibleInterface(); accessibleDebugClientCalls(accessible); - if (!accessible->isValid()) + if (!accessible) return E_FAIL; - // ### FIXME SERIOUSLY, NOT A STABLE SOLUTION IF NODES ARE DELETED ETC - // Return 0 if no object and no parent. This is really an error case. - uint uid = uniqueID(); - accessibleDebug("uniqueID: %08x", uid); - *outUniqueID = (long)uid; - return uid ? S_OK : S_FALSE; + accessibleDebug("uniqueID: %08x", id); + + *outUniqueID = (long)id; + return int(id) < 0 ? S_OK : S_FALSE; } HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_windowHandle(HWND *windowHandle) { + QAccessibleInterface *accessible = accessibleInterface(); accessibleDebugClientCalls(accessible); - if (!accessible->isValid()) + if (!accessible) return E_FAIL; return GetWindow(windowHandle); } @@ -486,8 +495,9 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_windowHandle(HWND *windowHa HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_indexInParent(long *indexInParent) { + QAccessibleInterface *accessible = accessibleInterface(); accessibleDebugClientCalls(accessible); - if (!accessible->isValid()) + if (!accessible) return E_FAIL; if (!indexInParent) return E_INVALIDARG; @@ -497,7 +507,6 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_indexInParent(long *indexIn return S_FALSE; } int indexOfChild = par->indexOfChild(accessible); - delete par; Q_ASSERT(indexOfChild >= 0); *indexInParent = indexOfChild; return S_OK; @@ -505,8 +514,9 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_indexInParent(long *indexIn HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_locale(IA2Locale *locale) { + QAccessibleInterface *accessible = accessibleInterface(); accessibleDebugClientCalls(accessible); - if (!accessible->isValid()) + if (!accessible) return E_FAIL; IA2Locale res; QLocale l; @@ -519,8 +529,9 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_locale(IA2Locale *locale) HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_attributes(BSTR *attributes) { + QAccessibleInterface *accessible = accessibleInterface(); accessibleDebugClientCalls(accessible); - if (!accessible->isValid()) + if (!accessible) return E_FAIL; *attributes = 0;//QStringToBSTR(QString()); return S_FALSE; @@ -531,8 +542,9 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_attributes(BSTR *attributes **************************************************************/ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::nActions(long *nActions) { + QAccessibleInterface *accessible = accessibleInterface(); accessibleDebugClientCalls(accessible); - if (!accessible->isValid()) + if (!accessible) return E_FAIL; *nActions = 0; @@ -543,8 +555,9 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::nActions(long *nActions) HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::doAction(long actionIndex) { + QAccessibleInterface *accessible = accessibleInterface(); accessibleDebugClientCalls(accessible); - if (!accessible->isValid()) + if (!accessible) return E_FAIL; if (QAccessibleActionInterface *actionIface = actionInterface()) { const QStringList actionNames = actionIface->actionNames(); @@ -559,8 +572,9 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::doAction(long actionIndex) HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_description(long actionIndex, BSTR *description) { + QAccessibleInterface *accessible = accessibleInterface(); accessibleDebugClientCalls(accessible); - if (!accessible->isValid()) + if (!accessible) return E_FAIL; *description = 0; if (QAccessibleActionInterface *actionIface = actionInterface()) { @@ -575,8 +589,9 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_description(long actionInde HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_keyBinding(long actionIndex, long nMaxBindings, BSTR **keyBindings, long *nBindings) { + QAccessibleInterface *accessible = accessibleInterface(); accessibleDebugClientCalls(accessible); - if (!accessible->isValid()) + if (!accessible) return E_FAIL; Q_UNUSED(nMaxBindings); BSTR *arrayOfBindingsToReturn = 0; @@ -603,8 +618,9 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_keyBinding(long actionIndex HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_name(long actionIndex, BSTR *name) { + QAccessibleInterface *accessible = accessibleInterface(); accessibleDebugClientCalls(accessible); - if (!accessible->isValid()) + if (!accessible) return E_FAIL; *name = 0; if (QAccessibleActionInterface *actionIface = actionInterface()) { @@ -619,8 +635,9 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_name(long actionIndex, BSTR HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_localizedName(long actionIndex, BSTR *localizedName) { + QAccessibleInterface *accessible = accessibleInterface(); accessibleDebugClientCalls(accessible); - if (!accessible->isValid()) + if (!accessible) return E_FAIL; *localizedName = 0; if (QAccessibleActionInterface *actionIface = actionInterface()) { @@ -639,13 +656,15 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_localizedName(long actionIn **************************************************************/ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_locationInParent(long *x, long *y) { + QAccessibleInterface *accessible = accessibleInterface(); accessibleDebugClientCalls(accessible); - if (!accessible->isValid()) + if (!accessible) return E_FAIL; QPoint topLeft = accessible->rect().topLeft(); - if (QAccessibleInterface *parentIface = accessible->parent()) + QAccessibleInterface *parentIface = accessible->parent(); + if (parentIface && parentIface->isValid()) topLeft -= parentIface->rect().topLeft(); *x = topLeft.x(); @@ -655,8 +674,9 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_locationInParent(long *x, l HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_foreground(IA2Color *foreground) { + QAccessibleInterface *accessible = accessibleInterface(); accessibleDebugClientCalls(accessible); - if (!accessible->isValid()) + if (!accessible) return E_FAIL; // IA2Color is a typedef for long @@ -666,8 +686,9 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_foreground(IA2Color *foregr HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_background(IA2Color *background) { + QAccessibleInterface *accessible = accessibleInterface(); accessibleDebugClientCalls(accessible); - if (!accessible->isValid()) + if (!accessible) return E_FAIL; // IA2Color is a typedef for long @@ -686,6 +707,8 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_background(IA2Color *backgr */ QString QWindowsIA2Accessible::textForRange(int startOffset, int endOffset) const { + QAccessibleInterface *accessible = accessibleInterface(); + if (QAccessibleTextInterface *textIface = accessible->textInterface()) { if (endOffset == IA2_TEXT_OFFSET_LENGTH) endOffset = textIface->characterCount(); @@ -703,6 +726,7 @@ QString QWindowsIA2Accessible::textForRange(int startOffset, int endOffset) cons */ void QWindowsIA2Accessible::replaceTextFallback(long startOffset, long endOffset, const QString &txt) { + QAccessibleInterface *accessible = accessibleInterface(); QString t = textForRange(0, -1); if (endOffset == IA2_TEXT_OFFSET_LENGTH) endOffset = t.length(); @@ -716,6 +740,7 @@ void QWindowsIA2Accessible::replaceTextFallback(long startOffset, long endOffset HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::copyText(long startOffset, long endOffset) { + QAccessibleInterface *accessible = accessibleInterface(); accessibleDebugClientCalls(accessible); #ifndef QT_NO_CLIPBOARD const QString t = textForRange(startOffset, endOffset); @@ -728,6 +753,7 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::copyText(long startOffset, long HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::deleteText(long startOffset, long endOffset) { + QAccessibleInterface *accessible = accessibleInterface(); accessibleDebugClientCalls(accessible); if (QAccessibleEditableTextInterface *editableTextIface = accessible->editableTextInterface()) editableTextIface->deleteText(startOffset, endOffset); @@ -738,6 +764,7 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::deleteText(long startOffset, lo HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::insertText(long offset, BSTR *text) { + QAccessibleInterface *accessible = accessibleInterface(); accessibleDebugClientCalls(accessible); const QString txt(BSTRToQString(*text)); if (QAccessibleEditableTextInterface *editableTextIface = accessible->editableTextInterface()) @@ -749,6 +776,7 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::insertText(long offset, BSTR *t HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::cutText(long startOffset, long endOffset) { + QAccessibleInterface *accessible = accessibleInterface(); accessibleDebugClientCalls(accessible); #ifndef QT_NO_CLIPBOARD const QString t = textForRange(startOffset, endOffset); @@ -765,6 +793,7 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::cutText(long startOffset, long HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::pasteText(long offset) { + QAccessibleInterface *accessible = accessibleInterface(); accessibleDebugClientCalls(accessible); #ifndef QT_NO_CLIPBOARD const QString txt = QGuiApplication::clipboard()->text(); @@ -780,6 +809,7 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::pasteText(long offset) HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::replaceText(long startOffset, long endOffset, BSTR *text) { + QAccessibleInterface *accessible = accessibleInterface(); accessibleDebugClientCalls(accessible); const QString txt(BSTRToQString(*text)); if (QAccessibleEditableTextInterface *editableTextIface = accessible->editableTextInterface()) @@ -800,8 +830,9 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::setAttributes(long /*startOffse **************************************************************/ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_cellAt( long row, long column, IUnknown **cell) { + QAccessibleInterface *accessible = accessibleInterface(); accessibleDebugClientCalls(accessible); - if (!accessible->isValid()) + if (!accessible) return E_FAIL; *cell = 0; @@ -816,8 +847,9 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_cellAt( long row, long colu HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_caption( IUnknown **captionInterface) { + QAccessibleInterface *accessible = accessibleInterface(); accessibleDebugClientCalls(accessible); - if (!accessible->isValid()) + if (!accessible) return E_FAIL; *captionInterface = 0; @@ -830,8 +862,9 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_caption( IUnknown **caption HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_columnDescription( long column, BSTR *description) { + QAccessibleInterface *accessible = accessibleInterface(); accessibleDebugClientCalls(accessible); - if (!accessible->isValid()) + if (!accessible) return E_FAIL; *description = 0; @@ -845,8 +878,9 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_columnDescription( long col HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_nColumns( long *columnCount) { + QAccessibleInterface *accessible = accessibleInterface(); accessibleDebugClientCalls(accessible); - if (!accessible->isValid()) + if (!accessible) return E_FAIL; if (QAccessibleTableInterface *tableIface = tableInterface()) { @@ -858,8 +892,9 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_nColumns( long *columnCount HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_nRows(long *rowCount) { + QAccessibleInterface *accessible = accessibleInterface(); accessibleDebugClientCalls(accessible); - if (!accessible->isValid()) + if (!accessible) return E_FAIL; if (QAccessibleTableInterface *tableIface = tableInterface()) { @@ -871,8 +906,9 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_nRows(long *rowCount) HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_nSelectedCells(long *cellCount) { + QAccessibleInterface *accessible = accessibleInterface(); accessibleDebugClientCalls(accessible); - if (!accessible->isValid()) + if (!accessible) return E_FAIL; if (QAccessibleTableInterface *tableIface = tableInterface()) { @@ -884,8 +920,9 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_nSelectedCells(long *cellCo HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_nSelectedColumns(long *columnCount) { + QAccessibleInterface *accessible = accessibleInterface(); accessibleDebugClientCalls(accessible); - if (!accessible->isValid()) + if (!accessible) return E_FAIL; if (QAccessibleTableInterface *tableIface = tableInterface()) { @@ -897,8 +934,9 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_nSelectedColumns(long *colu HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_nSelectedRows(long *rowCount) { + QAccessibleInterface *accessible = accessibleInterface(); accessibleDebugClientCalls(accessible); - if (!accessible->isValid()) + if (!accessible) return E_FAIL; if (QAccessibleTableInterface *tableIface = tableInterface()) { @@ -910,8 +948,9 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_nSelectedRows(long *rowCoun HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_rowDescription(long row, BSTR *description) { + QAccessibleInterface *accessible = accessibleInterface(); accessibleDebugClientCalls(accessible); - if (!accessible->isValid()) + if (!accessible) return E_FAIL; *description = 0; @@ -925,10 +964,11 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_rowDescription(long row, BS HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_selectedCells(IUnknown ***cells, long *nSelectedCells) { + QAccessibleInterface *accessible = accessibleInterface(); accessibleDebugClientCalls(accessible); Q_UNUSED(cells); Q_UNUSED(nSelectedCells); - if (!accessible->isValid()) + if (!accessible) return E_FAIL; QList<QAccessibleInterface*> selectedCells = tableInterface()->selectedCells(); @@ -937,8 +977,9 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_selectedCells(IUnknown ***c HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_selectedColumns(long **selectedColumns, long *nColumns) { + QAccessibleInterface *accessible = accessibleInterface(); accessibleDebugClientCalls(accessible); - if (!accessible->isValid()) + if (!accessible) return E_FAIL; if (QAccessibleTableInterface *tableIface = tableInterface()) { @@ -957,8 +998,9 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_selectedColumns(long **sele HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_selectedRows(long **selectedRows, long *nRows) { + QAccessibleInterface *accessible = accessibleInterface(); accessibleDebugClientCalls(accessible); - if (!accessible->isValid()) + if (!accessible) return E_FAIL; if (QAccessibleTableInterface *tableIface = tableInterface()) { @@ -977,8 +1019,9 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_selectedRows(long **selecte HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_summary(IUnknown **summaryInterface) { + QAccessibleInterface *accessible = accessibleInterface(); accessibleDebugClientCalls(accessible); - if (!accessible->isValid()) + if (!accessible) return E_FAIL; *summaryInterface = 0; @@ -991,8 +1034,9 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_summary(IUnknown **summaryI HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_isColumnSelected(long column, boolean *isSelected) { + QAccessibleInterface *accessible = accessibleInterface(); accessibleDebugClientCalls(accessible); - if (!accessible->isValid()) + if (!accessible) return E_FAIL; if (QAccessibleTableInterface *tableIface = tableInterface()) { @@ -1004,8 +1048,9 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_isColumnSelected(long colum HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_isRowSelected(long row, boolean *isSelected) { + QAccessibleInterface *accessible = accessibleInterface(); accessibleDebugClientCalls(accessible); - if (!accessible->isValid()) + if (!accessible) return E_FAIL; if (QAccessibleTableInterface *tableIface = tableInterface()) { @@ -1017,8 +1062,9 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_isRowSelected(long row, boo HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::selectRow(long row) { + QAccessibleInterface *accessible = accessibleInterface(); accessibleDebugClientCalls(accessible); - if (!accessible->isValid()) + if (!accessible) return E_FAIL; if (QAccessibleTableInterface *tableIface = tableInterface()) { @@ -1030,8 +1076,9 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::selectRow(long row) HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::selectColumn(long column) { + QAccessibleInterface *accessible = accessibleInterface(); accessibleDebugClientCalls(accessible); - if (!accessible->isValid()) + if (!accessible) return E_FAIL; if (QAccessibleTableInterface *tableIface = tableInterface()) { @@ -1043,8 +1090,9 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::selectColumn(long column) HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::unselectRow(long row) { + QAccessibleInterface *accessible = accessibleInterface(); accessibleDebugClientCalls(accessible); - if (!accessible->isValid()) + if (!accessible) return E_FAIL; if (QAccessibleTableInterface *tableIface = tableInterface()) { @@ -1056,8 +1104,9 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::unselectRow(long row) HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::unselectColumn(long column) { + QAccessibleInterface *accessible = accessibleInterface(); accessibleDebugClientCalls(accessible); - if (!accessible->isValid()) + if (!accessible) return E_FAIL; if (QAccessibleTableInterface *tableIface = tableInterface()) { @@ -1069,8 +1118,9 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::unselectColumn(long column) HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_modelChange( IA2TableModelChange * /*modelChange*/) { + QAccessibleInterface *accessible = accessibleInterface(); accessibleDebugClientCalls(accessible); - if (!accessible->isValid()) + if (!accessible) return E_FAIL; return E_NOTIMPL; } @@ -1080,8 +1130,9 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_modelChange( IA2TableModelC \**************************************************************/ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_columnExtent(long *nColumnsSpanned) { + QAccessibleInterface *accessible = accessibleInterface(); accessibleDebugClientCalls(accessible); - if (!accessible->isValid()) + if (!accessible) return E_FAIL; *nColumnsSpanned = tableCellInterface()->columnExtent(); @@ -1091,8 +1142,9 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_columnExtent(long *nColumns HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_columnHeaderCells(IUnknown ***cellAccessibles, long *nColumnHeaderCells) { + QAccessibleInterface *accessible = accessibleInterface(); accessibleDebugClientCalls(accessible); - if (!accessible->isValid()) + if (!accessible) return E_FAIL; const QList<QAccessibleInterface*> headerCells = tableCellInterface()->columnHeaderCells(); return wrapListOfCells(headerCells, cellAccessibles, nColumnHeaderCells); @@ -1100,8 +1152,9 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_columnHeaderCells(IUnknown HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_columnIndex(long *columnIndex) { + QAccessibleInterface *accessible = accessibleInterface(); accessibleDebugClientCalls(accessible); - if (!accessible->isValid()) + if (!accessible) return E_FAIL; *columnIndex = tableCellInterface()->columnIndex(); return S_OK; @@ -1109,8 +1162,9 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_columnIndex(long *columnInd HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_rowExtent(long *nRowsSpanned) { + QAccessibleInterface *accessible = accessibleInterface(); accessibleDebugClientCalls(accessible); - if (!accessible->isValid()) + if (!accessible) return E_FAIL; *nRowsSpanned = tableCellInterface()->rowExtent(); return S_OK; @@ -1119,8 +1173,9 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_rowExtent(long *nRowsSpanne HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_rowHeaderCells(IUnknown ***cellAccessibles, long *nRowHeaderCells) { + QAccessibleInterface *accessible = accessibleInterface(); accessibleDebugClientCalls(accessible); - if (!accessible->isValid()) + if (!accessible) return E_FAIL; const QList<QAccessibleInterface*> headerCells = tableCellInterface()->rowHeaderCells(); return wrapListOfCells(headerCells, cellAccessibles, nRowHeaderCells); @@ -1128,8 +1183,9 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_rowHeaderCells(IUnknown *** HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_rowIndex(long *rowIndex) { + QAccessibleInterface *accessible = accessibleInterface(); accessibleDebugClientCalls(accessible); - if (!accessible->isValid()) + if (!accessible) return E_FAIL; *rowIndex = tableCellInterface()->rowIndex(); return S_OK; @@ -1137,8 +1193,9 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_rowIndex(long *rowIndex) HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_isSelected( boolean *isSelected) { + QAccessibleInterface *accessible = accessibleInterface(); accessibleDebugClientCalls(accessible); - if (!accessible->isValid()) + if (!accessible) return E_FAIL; *isSelected = tableCellInterface()->isSelected(); return S_OK; @@ -1148,8 +1205,9 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_rowColumnExtents(long *row, long *rowExtents, long *columnExtents, boolean *isSelected) { + QAccessibleInterface *accessible = accessibleInterface(); accessibleDebugClientCalls(accessible); - if (!accessible->isValid()) + if (!accessible) return E_FAIL; tableCellInterface()->rowColumnExtents((int*)row, (int*)column, (int*)rowExtents, (int*)columnExtents, (bool*)isSelected); @@ -1158,8 +1216,9 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_rowColumnExtents(long *row, HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_table(IUnknown **table) { + QAccessibleInterface *accessible = accessibleInterface(); accessibleDebugClientCalls(accessible); - if (!accessible->isValid()) + if (!accessible) return E_FAIL; QAccessibleInterface *tableIface = tableCellInterface()->table(); @@ -1174,6 +1233,7 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_table(IUnknown **table) HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::addSelection(long startOffset, long endOffset) { + QAccessibleInterface *accessible = accessibleInterface(); accessibleDebugClientCalls(accessible); if (QAccessibleTextInterface *text = textInterface()) { text->addSelection(startOffset, endOffset); @@ -1187,6 +1247,7 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_attributes(long offset, long *endOffset, BSTR *textAttributes) { + QAccessibleInterface *accessible = accessibleInterface(); accessibleDebugClientCalls(accessible); if (QAccessibleTextInterface *text = textInterface()) { const QString attrs = text->attributes(offset, (int*)startOffset, (int*)endOffset); @@ -1198,6 +1259,7 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_attributes(long offset, HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_caretOffset(long *offset) { + QAccessibleInterface *accessible = accessibleInterface(); accessibleDebugClientCalls(accessible); if (QAccessibleTextInterface *text = textInterface()) { *offset = text->cursorPosition(); @@ -1214,6 +1276,7 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_characterExtents(long offse long *width, long *height) { + QAccessibleInterface *accessible = accessibleInterface(); accessibleDebugClientCalls(accessible); if (QAccessibleTextInterface *text = textInterface()) { QRect rect = text->characterRect(offset); @@ -1227,6 +1290,7 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_characterExtents(long offse HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_nSelections(long *nSelections) { + QAccessibleInterface *accessible = accessibleInterface(); accessibleDebugClientCalls(accessible); if (QAccessibleTextInterface *text = textInterface()) { *nSelections = text->selectionCount(); @@ -1240,6 +1304,7 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_offsetAtPoint(long x, enum IA2CoordinateType coordType, long *offset) { + QAccessibleInterface *accessible = accessibleInterface(); accessibleDebugClientCalls(accessible); if (QAccessibleTextInterface *text = textInterface()) { QPoint screenPos = mapToScreenPos(coordType, x, y); @@ -1254,6 +1319,7 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_selection(long selectionInd long *startOffset, long *endOffset) { + QAccessibleInterface *accessible = accessibleInterface(); accessibleDebugClientCalls(accessible); if (QAccessibleTextInterface *text = textInterface()) { text->selection(selectionIndex, (int*)startOffset, (int*)endOffset); @@ -1266,6 +1332,7 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_text(long startOffset, long endOffset, BSTR *text) { + QAccessibleInterface *accessible = accessibleInterface(); accessibleDebugClientCalls(accessible); if (QAccessibleTextInterface *textif = textInterface()) { const QString t = textif->text(startOffset, endOffset); @@ -1284,9 +1351,10 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_textBeforeOffset(long offse long *endOffset, BSTR *text) { + QAccessibleInterface *accessible = accessibleInterface(); accessibleDebugClientCalls(accessible); if (QAccessibleTextInterface *textIface = textInterface()) { - const QString txt = textIface->textBeforeOffset(offset, (QAccessible2::BoundaryType)boundaryType, (int*)startOffset, (int*)endOffset); + const QString txt = textIface->textBeforeOffset(offset, (QAccessible::TextBoundaryType)boundaryType, (int*)startOffset, (int*)endOffset); if (!txt.isEmpty()) { *text = QStringToBSTR(txt); return S_OK; @@ -1303,9 +1371,10 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_textAfterOffset( long *endOffset, BSTR *text) { + QAccessibleInterface *accessible = accessibleInterface(); accessibleDebugClientCalls(accessible); if (QAccessibleTextInterface *textIface = textInterface()) { - const QString txt = textIface->textAfterOffset(offset, (QAccessible2::BoundaryType)boundaryType, (int*)startOffset, (int*)endOffset); + const QString txt = textIface->textAfterOffset(offset, (QAccessible::TextBoundaryType)boundaryType, (int*)startOffset, (int*)endOffset); if (!txt.isEmpty()) { *text = QStringToBSTR(txt); return S_OK; @@ -1321,9 +1390,10 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_textAtOffset(long offset, long *endOffset, BSTR *text) { + QAccessibleInterface *accessible = accessibleInterface(); accessibleDebugClientCalls(accessible); if (QAccessibleTextInterface *textIface = textInterface()) { - const QString txt = textIface->textAtOffset(offset, (QAccessible2::BoundaryType)boundaryType, (int*)startOffset, (int*)endOffset); + const QString txt = textIface->textAtOffset(offset, (QAccessible::TextBoundaryType)boundaryType, (int*)startOffset, (int*)endOffset); if (!txt.isEmpty()) { *text = QStringToBSTR(txt); return S_OK; @@ -1335,6 +1405,7 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_textAtOffset(long offset, HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::removeSelection(long selectionIndex) { + QAccessibleInterface *accessible = accessibleInterface(); accessibleDebugClientCalls(accessible); if (QAccessibleTextInterface *textIface = textInterface()) { textIface->removeSelection(selectionIndex); @@ -1345,6 +1416,7 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::removeSelection(long selectionI HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::setCaretOffset(long offset) { + QAccessibleInterface *accessible = accessibleInterface(); accessibleDebugClientCalls(accessible); if (QAccessibleTextInterface *textIface = textInterface()) { textIface->setCursorPosition(offset); @@ -1357,6 +1429,7 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::setSelection(long selectionInde long startOffset, long endOffset) { + QAccessibleInterface *accessible = accessibleInterface(); accessibleDebugClientCalls(accessible); if (QAccessibleTextInterface *textIface = textInterface()) { textIface->setSelection(selectionIndex, startOffset, endOffset); @@ -1367,6 +1440,7 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::setSelection(long selectionInde HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_nCharacters(long *nCharacters) { + QAccessibleInterface *accessible = accessibleInterface(); accessibleDebugClientCalls(accessible); if (QAccessibleTextInterface *textIface = textInterface()) { *nCharacters = textIface->characterCount(); @@ -1379,6 +1453,7 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::scrollSubstringTo(long startInd long endIndex, enum IA2ScrollType scrollType) { + QAccessibleInterface *accessible = accessibleInterface(); accessibleDebugClientCalls(accessible); if (QAccessibleTextInterface *textIface = textInterface()) { Q_UNUSED(scrollType); //### @@ -1420,8 +1495,9 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_oldText(IA2TextSegment *old **************************************************************/ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_currentValue(VARIANT *currentValue) { + QAccessibleInterface *accessible = accessibleInterface(); accessibleDebugClientCalls(accessible); - if (!accessible->isValid()) + if (!accessible) return E_FAIL; if (QAccessibleValueInterface *valueIface = valueInterface()) { const QVariant var = valueIface->currentValue(); @@ -1435,8 +1511,9 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_currentValue(VARIANT *curre HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::setCurrentValue(VARIANT value) { + QAccessibleInterface *accessible = accessibleInterface(); accessibleDebugClientCalls(accessible); - if (!accessible->isValid()) + if (!accessible) return E_FAIL; HRESULT hr = S_FALSE; if (QAccessibleValueInterface *valueIface = valueInterface()) { @@ -1451,8 +1528,9 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::setCurrentValue(VARIANT value) HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_maximumValue(VARIANT *maximumValue) { + QAccessibleInterface *accessible = accessibleInterface(); accessibleDebugClientCalls(accessible); - if (!accessible->isValid()) + if (!accessible) return E_FAIL; if (QAccessibleValueInterface *valueIface = valueInterface()) { const QVariant var = valueIface->maximumValue(); @@ -1465,8 +1543,9 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_maximumValue(VARIANT *maxim HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_minimumValue(VARIANT *minimumValue) { + QAccessibleInterface *accessible = accessibleInterface(); accessibleDebugClientCalls(accessible); - if (!accessible->isValid()) + if (!accessible) return E_FAIL; if (QAccessibleValueInterface *valueIface = valueInterface()) { const QVariant var = valueIface->minimumValue(); @@ -1538,6 +1617,7 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::QueryService(REFGUID guidServic */ HRESULT QWindowsIA2Accessible::getRelationsHelper(IAccessibleRelation **relations, int startIndex, long maxRelations, long *nRelations /* = 0*/) { + QAccessibleInterface *accessible = accessibleInterface(); if (nRelations) *nRelations = 0; typedef QPair<QAccessibleInterface *, QAccessible::Relation> RelationEntry; @@ -1587,37 +1667,6 @@ HRESULT QWindowsIA2Accessible::wrapListOfCells(const QList<QAccessibleInterface* return count > 0 ? S_OK : S_FALSE; } -uint QWindowsIA2Accessible::uniqueID() const -{ - uint uid = 0; - if (QObject *obj = accessible->object()) - uid = qHash(obj); - - if (!uid) { - QAccessibleInterface *acc = accessible; - QVector<int> indexOfNodes; - while (acc && !acc->object()) { - QAccessibleInterface *par = acc->parent(); - indexOfNodes.append(par->indexOfChild(acc)); - if (acc != accessible) - delete acc; - acc = par; - } - if (acc) { - if (acc->object()) { - uid = qHash(acc->object()); - for (int i = 0; i < indexOfNodes.count(); ++i) - uid = qHash(uid + indexOfNodes.at(i)); - - } - if (acc != accessible) - delete acc; - } - } - return uid; -} - - #define IF_EQUAL_RETURN_IIDSTRING(id, iid) if (id == iid) return QByteArray(#iid) QByteArray QWindowsIA2Accessible::IIDToString(REFIID id) diff --git a/src/plugins/platforms/windows/accessible/iaccessible2.h b/src/plugins/platforms/windows/accessible/iaccessible2.h index af9698b9b2..a391d495f9 100644 --- a/src/plugins/platforms/windows/accessible/iaccessible2.h +++ b/src/plugins/platforms/windows/accessible/iaccessible2.h @@ -132,7 +132,7 @@ public: /* IAccessibleTable2 */ HRESULT STDMETHODCALLTYPE get_cellAt( long row, long column, IUnknown **cell); - HRESULT STDMETHODCALLTYPE get_caption( IUnknown **accessible); + HRESULT STDMETHODCALLTYPE get_caption( IUnknown **accessibleInterface); HRESULT STDMETHODCALLTYPE get_columnDescription( long column, BSTR *description); HRESULT STDMETHODCALLTYPE get_nColumns( long *columnCount); HRESULT STDMETHODCALLTYPE get_nRows( long *rowCount); @@ -143,7 +143,7 @@ public: HRESULT STDMETHODCALLTYPE get_selectedCells( IUnknown ***cells, long *nSelectedCells); HRESULT STDMETHODCALLTYPE get_selectedColumns( long **selectedColumns, long *nColumns); HRESULT STDMETHODCALLTYPE get_selectedRows( long **selectedRows, long *nRows); - HRESULT STDMETHODCALLTYPE get_summary( IUnknown **accessible); + HRESULT STDMETHODCALLTYPE get_summary( IUnknown **accessibleInterface); HRESULT STDMETHODCALLTYPE get_isColumnSelected( long column, boolean *isSelected); HRESULT STDMETHODCALLTYPE get_isRowSelected( long row, boolean *isSelected); HRESULT STDMETHODCALLTYPE selectRow( long row); @@ -206,22 +206,27 @@ public: /* private helper functions */ private: inline QAccessibleTextInterface *textInterface() const { - return accessible->isValid() ? accessible->textInterface() : static_cast<QAccessibleTextInterface *>(0); + QAccessibleInterface *accessible = accessibleInterface(); + return accessible ? accessible->textInterface() : static_cast<QAccessibleTextInterface *>(0); } inline QAccessibleActionInterface *actionInterface() const { + QAccessibleInterface *accessible = accessibleInterface(); return accessible->actionInterface(); } inline QAccessibleValueInterface *valueInterface() const { + QAccessibleInterface *accessible = accessibleInterface(); return accessible->valueInterface(); } inline QAccessibleTableInterface *tableInterface() const { + QAccessibleInterface *accessible = accessibleInterface(); return accessible->tableInterface(); } inline QAccessibleTableCellInterface *tableCellInterface() const { + QAccessibleInterface *accessible = accessibleInterface(); return accessible->tableCellInterface(); } @@ -231,6 +236,7 @@ private: \a x and \y (out) is in parent relative position if coordType == IA2_COORDTYPE_PARENT_RELATIVE */ void mapFromScreenPos(enum IA2CoordinateType coordType, const QPoint &screenPos, long *x, long *y) const { + QAccessibleInterface *accessible = accessibleInterface(); if (coordType == IA2_COORDTYPE_PARENT_RELATIVE) { // caller wants relative to parent if (QAccessibleInterface *parent = accessible->parent()) { @@ -250,6 +256,7 @@ private: \return a screen relative position */ QPoint mapToScreenPos(enum IA2CoordinateType coordType, long x, long y) const { + QAccessibleInterface *accessible = accessibleInterface(); if (coordType == IA2_COORDTYPE_PARENT_RELATIVE) { if (QAccessibleInterface *parent = accessible->parent()) { const QRect parentScreenRect = parent->rect(); @@ -261,7 +268,6 @@ private: HRESULT getRelationsHelper(IAccessibleRelation **relations, int startIndex, long maxRelations, long *nRelations = 0); HRESULT wrapListOfCells(const QList<QAccessibleInterface*> &inputCells, IUnknown ***outputAccessibles, long *nCellCount); - uint uniqueID() const; QByteArray IIDToString(REFIID id); QString textForRange(int startOffset, int endOffset) const; void replaceTextFallback(long startOffset, long endOffset, const QString &txt); diff --git a/src/plugins/platforms/windows/accessible/qwindowsaccessibility.cpp b/src/plugins/platforms/windows/accessible/qwindowsaccessibility.cpp index 3ccc6212a9..f222deeeac 100644 --- a/src/plugins/platforms/windows/accessible/qwindowsaccessibility.cpp +++ b/src/plugins/platforms/windows/accessible/qwindowsaccessibility.cpp @@ -51,7 +51,7 @@ #include <QtCore/qpointer.h> #include <QtCore/qsettings.h> #include <QtGui/qaccessible.h> -#include <QtGui/qaccessible2.h> +#include <QtGui/private/qaccessible2_p.h> #include <qpa/qplatformnativeinterface.h> #include <QtGui/qwindow.h> #include <QtGui/qguiapplication.h> @@ -86,14 +86,8 @@ #include "../qtwindows_additional.h" - -// This stuff is used for widgets/items with no window handle: -typedef QMap<int, QPair<QPointer<QObject>,int> > NotifyMap; -Q_GLOBAL_STATIC(NotifyMap, qAccessibleRecentSentEvents) - QT_BEGIN_NAMESPACE - /*! \!internal \class QWindowsAccessibility @@ -162,26 +156,16 @@ void QWindowsAccessibility::notifyAccessibilityUpdate(QAccessibleEvent *event) } } - typedef void (WINAPI *PtrNotifyWinEvent)(DWORD, HWND, LONG, LONG); - #if defined(Q_OS_WINCE) // ### TODO: check for NotifyWinEvent in CE 6.0 // There is no user32.lib nor NotifyWinEvent for CE return; #else - static PtrNotifyWinEvent ptrNotifyWinEvent = 0; - static bool resolvedNWE = false; - if (!resolvedNWE) { - resolvedNWE = true; - ptrNotifyWinEvent = (PtrNotifyWinEvent)QSystemLibrary::resolve(QLatin1String("user32"), "NotifyWinEvent"); - } - if (!ptrNotifyWinEvent) - return; - // An event has to be associated with a window, // so find the first parent that is a widget and that has a WId QAccessibleInterface *iface = event->accessibleInterface(); - QWindow *window = iface ? QWindowsAccessibility::windowHelper(iface) : 0; - delete iface; + if (!iface) // ### This should not happen, maybe make it an assert. + return; + QWindow *window = QWindowsAccessibility::windowHelper(iface); if (!window) { window = QGuiApplication::focusWindow(); @@ -194,27 +178,9 @@ void QWindowsAccessibility::notifyAccessibilityUpdate(QAccessibleEvent *event) return; HWND hWnd = (HWND)platform->nativeResourceForWindow("handle", window); - static int eventNum = 0; if (event->type() != QAccessible::MenuCommand && // MenuCommand is faked event->type() != QAccessible::ObjectDestroyed) { - /* In some rare occasions, the server (Qt) might get a ::get_accChild call with a - childId that references an entry in the cache where there was a dangling - QObject-pointer. Previously we crashed on this. - - There is no point in actually notifying the AT client that the object got destroyed, - because the AT client won't query for get_accChild if the event is ObjectDestroyed - anyway, and we have no other way of mapping the eventId argument to the actual - child/descendant object. (Firefox seems to simply completely ignore - EVENT_OBJECT_DESTROY). - - We therefore guard each QObject in the cache with a QPointer, and only notify the AT - client if the type is not ObjectDestroyed. - */ - eventNum %= 50; //[0..49] - int eventId = - (eventNum - 1); - qAccessibleRecentSentEvents()->insert(eventId, qMakePair(QPointer<QObject>(event->object()), event->child())); - ptrNotifyWinEvent(event->type(), hWnd, OBJID_CLIENT, eventId); - ++eventNum; + ::NotifyWinEvent(event->type(), hWnd, OBJID_CLIENT, QAccessible::uniqueId(iface)); } #endif // Q_OS_WINCE } @@ -224,10 +190,9 @@ QWindow *QWindowsAccessibility::windowHelper(const QAccessibleInterface *iface) QWindow *window = iface->window(); if (!window) { QAccessibleInterface *acc = iface->parent(); - while (acc && !window) { + while (acc && acc->isValid() && !window) { window = acc->window(); QAccessibleInterface *par = acc->parent(); - delete acc; acc = par; } } @@ -242,6 +207,11 @@ IAccessible *QWindowsAccessibility::wrap(QAccessibleInterface *acc) { if (!acc) return 0; + + // ### FIXME: maybe we should accept double insertions into the cache + if (!QAccessible::uniqueId(acc)) + QAccessible::registerAccessibleInterface(acc); + #ifdef Q_CC_MINGW QWindowsMsaaAccessible *wacc = new QWindowsMsaaAccessible(acc); #else @@ -252,15 +222,6 @@ IAccessible *QWindowsAccessibility::wrap(QAccessibleInterface *acc) return iacc; } -/*! - \internal -*/ -QPair<QObject*, int> QWindowsAccessibility::getCachedObject(int entryId) -{ - QPair<QPointer<QObject>, int> pair = qAccessibleRecentSentEvents()->value(entryId); - return qMakePair(pair.first.data(), pair.second); -} - /* void QWindowsAccessibility::setRootObject(QObject *o) { @@ -283,7 +244,7 @@ bool QWindowsAccessibility::handleAccessibleObjectFromWindowRequest(HWND hwnd, W { if (static_cast<long>(lParam) == static_cast<long>(UiaRootObjectId)) { /* For UI Automation */ - } else if ((DWORD)lParam == OBJID_CLIENT) { + } else if ((DWORD)lParam == DWORD(OBJID_CLIENT)) { #if 1 // Ignoring all requests while starting up // ### Maybe QPA takes care of this??? @@ -313,8 +274,6 @@ bool QWindowsAccessibility::handleAccessibleObjectFromWindowRequest(HWND hwnd, W iface->Release(); // the client will release the object again, and then it will destroy itself } return true; - } else { - delete acc; } } } diff --git a/src/plugins/platforms/windows/accessible/qwindowsaccessibility.h b/src/plugins/platforms/windows/accessible/qwindowsaccessibility.h index af0bd65c80..f25e2281a0 100644 --- a/src/plugins/platforms/windows/accessible/qwindowsaccessibility.h +++ b/src/plugins/platforms/windows/accessible/qwindowsaccessibility.h @@ -48,7 +48,6 @@ #include <oleacc.h> -QT_BEGIN_HEADER QT_BEGIN_NAMESPACE class QWindowsAccessibility : public QPlatformAccessibility @@ -64,11 +63,8 @@ public: */ static IAccessible *wrap(QAccessibleInterface *acc); static QWindow *windowHelper(const QAccessibleInterface *iface); - - static QPair<QObject*, int> getCachedObject(int entryId); }; QT_END_NAMESPACE -QT_END_HEADER #endif // QWINDOWSACCESSIBILITY_H diff --git a/src/plugins/platforms/windows/accessible/qwindowsmsaaaccessible.cpp b/src/plugins/platforms/windows/accessible/qwindowsmsaaaccessible.cpp index c23902014c..7eb1bd30c0 100644 --- a/src/plugins/platforms/windows/accessible/qwindowsmsaaaccessible.cpp +++ b/src/plugins/platforms/windows/accessible/qwindowsmsaaaccessible.cpp @@ -54,7 +54,7 @@ #include <QtCore/qpair.h> #include <QtCore/qsettings.h> #include <QtGui/qaccessible.h> -#include <QtGui/qaccessible2.h> +#include <QtGui/private/qaccessible2_p.h> #include <QtGui/qguiapplication.h> #include <qpa/qplatformnativeinterface.h> #include <QtGui/qwindow.h> @@ -186,21 +186,6 @@ HRESULT STDMETHODCALLTYPE QWindowsEnumerate::Skip(unsigned long celt) return S_OK; } -static bool compareAccessible(QAccessibleInterface *one, QAccessibleInterface *other) -{ - if (one == other) return true; - if (!one || !other) return false; - - if (one->object() && other->object() && (one->object() == other->object())) - return true; - QAIPointer onePar(one->parent()); - QAIPointer otherPar(other->parent()); - - if (compareAccessible(onePar.data(), otherPar.data())) - return onePar->indexOfChild(one) == otherPar->indexOfChild(other); - return false; -} - #ifndef QT_NO_DEBUG bool debug_accessibility() { @@ -232,7 +217,9 @@ HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::QueryInterface(REFIID id, LPVO QByteArray strIID = IIDToString(id); if (!strIID.isEmpty()) { - QString ss; QDebug dbg(&ss); dbg << accessible; + QString ss; + QDebug dbg(&ss); + dbg << accessibleInterface(); accessibleDebug("QWindowsIA2Accessible::QI() - IID:%s, iface:%s ", strIID.constData(), qPrintable(ss)); } if (id == IID_IUnknown) { @@ -533,8 +520,9 @@ IAccessible::accHitTest documents the value returned in pvarID like this: */ HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::accHitTest(long xLeft, long yTop, VARIANT *pvarID) { + QAccessibleInterface *accessible = accessibleInterface(); accessibleDebugClientCalls(accessible); - if (!accessible->isValid()) + if (!accessible) return E_FAIL; QAccessibleInterface *child = accessible->childAt(xLeft, yTop); @@ -571,14 +559,15 @@ HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::accHitTest(long xLeft, long yT // moz: [important] HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::accLocation(long *pxLeft, long *pyTop, long *pcxWidth, long *pcyHeight, VARIANT varID) { + QAccessibleInterface *accessible = accessibleInterface(); accessibleDebugClientCalls(accessible); - if (!accessible->isValid()) + if (!accessible) return E_FAIL; QRect rect; if (varID.lVal) { - QAIPointer child(childPointer(varID)); - if (!child) + QAccessibleInterface *child = accessible->child(varID.lVal - 1); + if (!child || !child->isValid()) return E_FAIL; rect = child->rect(); } else { @@ -596,8 +585,9 @@ HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::accLocation(long *pxLeft, long // moz: [important, but no need to implement up/down/left/right] HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::accNavigate(long navDir, VARIANT varStart, VARIANT *pvarEnd) { + QAccessibleInterface *accessible = accessibleInterface(); accessibleDebugClientCalls(accessible); - if (!accessible->isValid()) + if (!accessible) return E_FAIL; QAccessibleInterface *acc = 0; @@ -612,12 +602,11 @@ HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::accNavigate(long navDir, VARIA case NAVDIR_PREVIOUS: if (!varStart.lVal){ QAccessibleInterface *parent = accessible->parent(); - if (parent) { + if (parent && parent->isValid()) { int index = parent->indexOfChild(accessible); index += (navDir == NAVDIR_NEXT) ? 1 : -1; if (index >= 0 && index < parent->childCount()) acc = parent->child(index); - delete parent; } } else { int index = varStart.lVal; @@ -631,8 +620,9 @@ HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::accNavigate(long navDir, VARIA case NAVDIR_UP: case NAVDIR_DOWN: case NAVDIR_LEFT: - case NAVDIR_RIGHT: - if (QAccessibleInterface *pIface = accessible->parent()) { + case NAVDIR_RIGHT: { + QAccessibleInterface *pIface = accessible->parent(); + if (pIface && pIface->isValid()) { const int indexOfOurself = pIface->indexOfChild(accessible); QRect startg = accessible->rect(); QPoint startc = startg.center(); @@ -645,7 +635,6 @@ HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::accNavigate(long navDir, VARIA Q_ASSERT(sibling); if (i == indexOfOurself || sibling->state().invisible) { //ignore ourself and invisible siblings - delete sibling; continue; } @@ -659,7 +648,6 @@ HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::accNavigate(long navDir, VARIA startp = QPoint(startg.left(), startg.top() + startg.height() / 2); sibp = QPoint(sibg.right(), sibg.top() + sibg.height() / 2); if (QPoint(sibc - startc).x() >= 0) { - delete sibling; continue; } distp = sibp - startp; @@ -668,7 +656,6 @@ HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::accNavigate(long navDir, VARIA startp = QPoint(startg.right(), startg.top() + startg.height() / 2); sibp = QPoint(sibg.left(), sibg.top() + sibg.height() / 2); if (QPoint(sibc - startc).x() <= 0) { - delete sibling; continue; } distp = sibp - startp; @@ -677,7 +664,6 @@ HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::accNavigate(long navDir, VARIA startp = QPoint(startg.left() + startg.width() / 2, startg.top()); sibp = QPoint(sibg.left() + sibg.width() / 2, sibg.bottom()); if (QPoint(sibc - startc).y() >= 0) { - delete sibling; continue; } distp = sibp - startp; @@ -686,7 +672,6 @@ HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::accNavigate(long navDir, VARIA startp = QPoint(startg.left() + startg.width() / 2, startg.bottom()); sibp = QPoint(sibg.left() + sibg.width() / 2, sibg.top()); if (QPoint(sibc - startc).y() <= 0) { - delete sibling; continue; } distp = sibp - startp; @@ -699,16 +684,13 @@ HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::accNavigate(long navDir, VARIA // squared distance, (thus, no need to take the sqrt()). unsigned dist = distp.x() * distp.x() + distp.y() * distp.y(); if (dist < mindist) { - delete candidate; candidate = sibling; mindist = dist; - } else { - delete sibling; } } - delete pIface; acc = candidate; } + } break; default: break; @@ -722,9 +704,6 @@ HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::accNavigate(long navDir, VARIA (*pvarEnd).vt = VT_DISPATCH; (*pvarEnd).pdispVal = iface; return S_OK; - } else { - if (acc != accessible) - delete acc; } (*pvarEnd).vt = VT_EMPTY; @@ -734,8 +713,9 @@ HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::accNavigate(long navDir, VARIA // moz: [important] HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::get_accChild(VARIANT varChildID, IDispatch** ppdispChild) { + QAccessibleInterface *accessible = accessibleInterface(); accessibleDebugClientCalls(accessible); - if (!accessible->isValid()) + if (!accessible) return E_FAIL; if (varChildID.vt != VT_I4) @@ -743,38 +723,18 @@ HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::get_accChild(VARIANT varChildI int childIndex = varChildID.lVal; + QAccessibleInterface *acc = 0; - if (childIndex < 0) { - const int entry = childIndex; - QPair<QObject*, int> ref = QWindowsAccessibility::getCachedObject(entry); - if (ref.first) { - acc = QAccessible::queryAccessibleInterface(ref.first); - if (acc && ref.second >= 0) { - QAccessibleInterface *res = acc->child(ref.second); - delete acc; - if (!res) - return E_INVALIDARG; - acc = res; - } - } else { - qWarning("get_accChild got a negative varChildID (%d), but did not find it in cache", childIndex); - } + + if (childIndex == 0) { + // Yes, some AT clients (Active Accessibility Object Inspector) + // actually ask for the same object. As a consequence, we need to clone ourselves: + acc = accessible; + } else if (childIndex < 0) { + acc = QAccessible::accessibleInterface((QAccessible::Id)childIndex); } else { - if (childIndex) { - acc = accessible->child(childIndex - 1); - } else { - // Yes, some AT clients (Active Accessibility Object Inspector) - // actually ask for the same object. As a consequence, we need to clone ourselves: - if (QAccessibleInterface *par = accessible->parent()) { - const int indexOf = par->indexOfChild(accessible); - if (indexOf == -1) - qWarning() << "inconsistent hierarchy, parent:" << par << "child:" << accessible; - else - acc = par->child(indexOf); - delete par; - } - } + acc = accessible->child(childIndex - 1); } if (acc) { @@ -788,8 +748,9 @@ HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::get_accChild(VARIANT varChildI // moz: [important] HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::get_accChildCount(long* pcountChildren) { + QAccessibleInterface *accessible = accessibleInterface(); accessibleDebugClientCalls(accessible); - if (!accessible->isValid()) + if (!accessible) return E_FAIL; *pcountChildren = accessible->childCount(); @@ -799,8 +760,9 @@ HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::get_accChildCount(long* pcount // moz: [important] HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::get_accParent(IDispatch** ppdispParent) { + QAccessibleInterface *accessible = accessibleInterface(); accessibleDebugClientCalls(accessible); - if (!accessible->isValid()) + if (!accessible) return E_FAIL; QAccessibleInterface *acc = accessible->parent(); @@ -808,8 +770,6 @@ HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::get_accParent(IDispatch** ppdi if (IAccessible *iface = QWindowsAccessibility::wrap(acc)) { *ppdispParent = iface; return S_OK; - } else { - delete acc; } } @@ -823,8 +783,9 @@ HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::get_accParent(IDispatch** ppdi HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::accDoDefaultAction(VARIANT varID) { Q_UNUSED(varID); + QAccessibleInterface *accessible = accessibleInterface(); accessibleDebugClientCalls(accessible); - if (!accessible->isValid()) + if (!accessible) return E_FAIL; if (QAccessibleActionInterface *actionIface = accessible->actionInterface()) { @@ -840,8 +801,9 @@ HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::accDoDefaultAction(VARIANT var HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::get_accDefaultAction(VARIANT varID, BSTR* pszDefaultAction) { Q_UNUSED(varID); + QAccessibleInterface *accessible = accessibleInterface(); accessibleDebugClientCalls(accessible); - if (!accessible->isValid()) + if (!accessible) return E_FAIL; *pszDefaultAction = 0; @@ -855,14 +817,15 @@ HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::get_accDefaultAction(VARIANT v HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::get_accDescription(VARIANT varID, BSTR* pszDescription) { + QAccessibleInterface *accessible = accessibleInterface(); accessibleDebugClientCalls(accessible); - if (!accessible->isValid()) + if (!accessible) return E_FAIL; QString descr; if (varID.lVal) { - QAIPointer child = childPointer(varID); + QAccessibleInterface *child = childPointer(varID); if (!child) return E_FAIL; descr = child->text(QAccessible::Description); @@ -880,13 +843,14 @@ HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::get_accDescription(VARIANT var HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::get_accHelp(VARIANT varID, BSTR *pszHelp) { + QAccessibleInterface *accessible = accessibleInterface(); accessibleDebugClientCalls(accessible); - if (!accessible->isValid()) + if (!accessible) return E_FAIL; QString help; if (varID.lVal) { - QAIPointer child = childPointer(varID); + QAccessibleInterface *child = childPointer(varID); if (!child) return E_FAIL; help = child->text(QAccessible::Help); @@ -910,8 +874,9 @@ HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::get_accHelpTopic(BSTR *, VARIA HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::get_accKeyboardShortcut(VARIANT varID, BSTR *pszKeyboardShortcut) { Q_UNUSED(varID); + QAccessibleInterface *accessible = accessibleInterface(); accessibleDebugClientCalls(accessible); - if (!accessible->isValid()) + if (!accessible) return E_FAIL; *pszKeyboardShortcut = 0; @@ -931,29 +896,26 @@ static QAccessibleInterface *relatedInterface(QAccessibleInterface *iface, QAcce typedef QPair<QAccessibleInterface *, QAccessible::Relation> RelationPair; QVector<RelationPair> rels = iface->relations(flag); - for (int i = 1; i < rels.count(); ++i) - delete rels.at(i).first; - return rels.value(0).first; } // moz: [important] HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::get_accName(VARIANT varID, BSTR* pszName) { + QAccessibleInterface *accessible = accessibleInterface(); accessibleDebugClientCalls(accessible); - if (!accessible->isValid()) + if (!accessible) return E_FAIL; QString name; if (varID.lVal) { - QAIPointer child = childPointer(varID); + QAccessibleInterface *child = childPointer(varID); if (!child) return E_FAIL; name = child->text(QAccessible::Name); if (name.isEmpty()) { - if (QAccessibleInterface *labelInterface = relatedInterface(child.data(), QAccessible::Label)) { + if (QAccessibleInterface *labelInterface = relatedInterface(child, QAccessible::Label)) { name = labelInterface->text(QAccessible::Name); - delete labelInterface; } } } else { @@ -961,7 +923,6 @@ HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::get_accName(VARIANT varID, BST if (name.isEmpty()) { if (QAccessibleInterface *labelInterface = relatedInterface(accessible, QAccessible::Label)) { name = labelInterface->text(QAccessible::Name); - delete labelInterface; } } } @@ -976,6 +937,7 @@ HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::get_accName(VARIANT varID, BST HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::put_accName(VARIANT, BSTR) { + QAccessibleInterface *accessible = accessibleInterface(); accessibleDebugClientCalls(accessible); return DISP_E_MEMBERNOTFOUND; } @@ -983,13 +945,14 @@ HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::put_accName(VARIANT, BSTR) // moz: [important] HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::get_accRole(VARIANT varID, VARIANT *pvarRole) { + QAccessibleInterface *accessible = accessibleInterface(); accessibleDebugClientCalls(accessible); - if (!accessible->isValid()) + if (!accessible) return E_FAIL; QAccessible::Role role; if (varID.lVal) { - QAIPointer child = childPointer(varID); + QAccessibleInterface *child = childPointer(varID); if (!child) return E_FAIL; role = child->role(); @@ -1017,14 +980,15 @@ HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::get_accRole(VARIANT varID, VAR // moz: [important] HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::get_accState(VARIANT varID, VARIANT *pvarState) { + QAccessibleInterface *accessible = accessibleInterface(); accessibleDebugClientCalls(accessible); - if (!accessible->isValid()) + if (!accessible) return E_FAIL; QAccessible::State state; if (varID.lVal) { - QAIPointer child = childPointer(varID); - if (!child.data()) + QAccessibleInterface *child = childPointer(varID); + if (!child) return E_FAIL; state = child->state(); } else { @@ -1093,11 +1057,12 @@ HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::get_accState(VARIANT varID, VA // moz: [important] HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::get_accValue(VARIANT varID, BSTR* pszValue) { + QAccessibleInterface *accessible = accessibleInterface(); accessibleDebugClientCalls(accessible); if (varID.vt != VT_I4) return E_INVALIDARG; - if (!accessible->isValid() || varID.lVal) { + if (!accessible || !accessible->isValid() || varID.lVal) { return E_FAIL; } @@ -1119,6 +1084,7 @@ HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::get_accValue(VARIANT varID, BS HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::put_accValue(VARIANT, BSTR) { + QAccessibleInterface *accessible = accessibleInterface(); accessibleDebugClientCalls(accessible); return DISP_E_MEMBERNOTFOUND; } @@ -1128,8 +1094,9 @@ HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::accSelect(long flagsSelect, VA { Q_UNUSED(flagsSelect); Q_UNUSED(varID); + QAccessibleInterface *accessible = accessibleInterface(); accessibleDebugClientCalls(accessible); - if (!accessible->isValid()) + if (!accessible) return E_FAIL; bool res = false; @@ -1139,17 +1106,17 @@ HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::accSelect(long flagsSelect, VA ### and if there are no ia2 interfaces we should do nothing?? if (flagsSelect & SELFLAG_TAKEFOCUS) - res = accessible->doAction(SetFocus, varID.lVal, QVariantList()); + res = accessible()->doAction(SetFocus, varID.lVal, QVariantList()); if (flagsSelect & SELFLAG_TAKESELECTION) { - accessible->doAction(ClearSelection, 0, QVariantList()); - res = accessible->doAction(AddToSelection, varID.lVal, QVariantList()); + accessible()->doAction(ClearSelection, 0, QVariantList()); + res = accessible()->doAction(AddToSelection, varID.lVal, QVariantList()); } if (flagsSelect & SELFLAG_EXTENDSELECTION) - res = accessible->doAction(ExtendSelection, varID.lVal, QVariantList()); + res = accessible()->doAction(ExtendSelection, varID.lVal, QVariantList()); if (flagsSelect & SELFLAG_ADDSELECTION) - res = accessible->doAction(AddToSelection, varID.lVal, QVariantList()); + res = accessible()->doAction(AddToSelection, varID.lVal, QVariantList()); if (flagsSelect & SELFLAG_REMOVESELECTION) - res = accessible->doAction(RemoveSelection, varID.lVal, QVariantList()); + res = accessible()->doAction(RemoveSelection, varID.lVal, QVariantList()); */ return res ? S_OK : S_FALSE; } @@ -1172,15 +1139,15 @@ HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::accSelect(long flagsSelect, VA */ HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::get_accFocus(VARIANT *pvarID) { + QAccessibleInterface *accessible = accessibleInterface(); accessibleDebugClientCalls(accessible); - if (!accessible->isValid()) + if (!accessible) return E_FAIL; if (QAccessibleInterface *acc = accessible->focusChild()) { - if (compareAccessible(acc, accessible)) { + if (acc == accessible) { (*pvarID).vt = VT_I4; (*pvarID).lVal = CHILDID_SELF; - delete acc; return S_OK; } else { if (IAccessible *iface = QWindowsAccessibility::wrap(acc)) { @@ -1189,7 +1156,6 @@ HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::get_accFocus(VARIANT *pvarID) return S_OK; } } - delete acc; } (*pvarID).vt = VT_EMPTY; return S_FALSE; @@ -1197,8 +1163,9 @@ HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::get_accFocus(VARIANT *pvarID) HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::get_accSelection(VARIANT *pvarChildren) { + QAccessibleInterface *accessible = accessibleInterface(); accessibleDebugClientCalls(accessible); - if (!accessible->isValid()) + if (!accessible) return E_FAIL; int cc = accessible->childCount(); @@ -1209,7 +1176,6 @@ HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::get_accSelection(VARIANT *pvar QAccessibleInterface *child = accessible->child(i); if (child) { isSelected = child->state().selected; - delete child; } if (isSelected) sel[selIndex++] = i+1; @@ -1239,11 +1205,10 @@ HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::get_accSelection(VARIANT *pvar HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::GetWindow(HWND *phwnd) { *phwnd = 0; + QAccessibleInterface *accessible = accessibleInterface(); accessibleDebugClientCalls(accessible); - if (!accessible->isValid()) + if (!accessible) return E_FAIL; - if (!accessible->isValid()) - return E_UNEXPECTED; QWindow *window = QWindowsAccessibility::windowHelper(accessible); if (!window) diff --git a/src/plugins/platforms/windows/accessible/qwindowsmsaaaccessible.h b/src/plugins/platforms/windows/accessible/qwindowsmsaaaccessible.h index ecb2e2bc18..ef17acf3e9 100644 --- a/src/plugins/platforms/windows/accessible/qwindowsmsaaaccessible.h +++ b/src/plugins/platforms/windows/accessible/qwindowsmsaaaccessible.h @@ -76,8 +76,6 @@ void accessibleDebugClientCalls_helper(const char* funcName, const QAccessibleIn # define accessibleDebugClientCalls(iface) #endif -typedef QSharedPointer<QAccessibleInterface> QAIPointer; - QWindow *window_helper(const QAccessibleInterface *iface); /**************************************************************\ @@ -93,14 +91,13 @@ class QWindowsMsaaAccessible : public { public: QWindowsMsaaAccessible(QAccessibleInterface *a) - : accessible(a) - , ref(0) + : ref(0) { + id = QAccessible::uniqueId(a); } virtual ~QWindowsMsaaAccessible() { - delete accessible; } /* IUnknown */ @@ -146,11 +143,23 @@ public: protected: virtual QByteArray IIDToString(REFIID id); - QAccessibleInterface *accessible; + QAccessible::Id id; + + QAccessibleInterface *accessibleInterface() const + { + QAccessibleInterface *iface = QAccessible::accessibleInterface(id); + if (iface && iface->isValid()) + return iface; + return 0; + } - QAIPointer childPointer(VARIANT varID) + QAccessibleInterface *childPointer(VARIANT varID) { - return QAIPointer(accessible->child(varID.lVal - 1)); + // -1 since windows API always uses 1 for the first child + QAccessibleInterface *iface = accessibleInterface(); + if (iface) + return accessibleInterface()->child(varID.lVal - 1); + return 0; } private: diff --git a/src/plugins/platforms/windows/qtwindows_additional.h b/src/plugins/platforms/windows/qtwindows_additional.h index 8d59fbd7c6..3b2e9787a2 100644 --- a/src/plugins/platforms/windows/qtwindows_additional.h +++ b/src/plugins/platforms/windows/qtwindows_additional.h @@ -126,6 +126,10 @@ typedef struct tagUPDATELAYEREDWINDOWINFO { // IME. #define IMR_CONFIRMRECONVERTSTRING 0x0005 +#ifndef MAPVK_VK_TO_CHAR +# define MAPVK_VK_TO_CHAR 2 +#endif + #endif // if defined(Q_CC_MINGW) /* Touch is supported from Windows 7 onwards and data structures diff --git a/src/plugins/platforms/windows/qwindowscontext.cpp b/src/plugins/platforms/windows/qwindowscontext.cpp index 88c9bf448d..545484de8d 100644 --- a/src/plugins/platforms/windows/qwindowscontext.cpp +++ b/src/plugins/platforms/windows/qwindowscontext.cpp @@ -372,56 +372,53 @@ void QWindowsContext::setKeyGrabber(QWindow *w) } // Window class registering code (from qapplication_win.cpp) -// If 0 is passed as the widget pointer, register a window class -// for QWidget as default. This is used in QGLTemporaryContext -// during GL initialization, where we don't want to use temporary -// QWidgets or QGLWidgets, neither do we want to have separate code -// to register window classes. QString QWindowsContext::registerWindowClass(const QWindow *w, bool isGL) { - const Qt::WindowFlags flags = w ? w->flags() : (Qt::WindowFlags)0; + Q_ASSERT(w); + const Qt::WindowFlags flags = w->flags(); const Qt::WindowFlags type = flags & Qt::WindowType_Mask; - - uint style = 0; - bool icon = false; - QString cname = QStringLiteral("Qt5"); - if (w && isGL) { - cname += QStringLiteral("QGLWindow"); - style = CS_DBLCLKS|CS_OWNDC; - icon = true; - } else if (w && (flags & Qt::MSWindowsOwnDC)) { - cname += QStringLiteral("QWindowOwnDC"); - style = CS_DBLCLKS|CS_OWNDC; - icon = true; - } else if (w && (type == Qt::Tool || type == Qt::ToolTip)) { - style = CS_DBLCLKS; - if (w->inherits("QTipLabel") || w->inherits("QAlphaWidget")) { - if ((QSysInfo::WindowsVersion >= QSysInfo::WV_XP - && (QSysInfo::WindowsVersion & QSysInfo::WV_NT_based))) { - style |= CS_DROPSHADOW; - } - cname += QStringLiteral("QToolTip"); - } else { - cname += QStringLiteral("QTool"); - } - style |= CS_SAVEBITS; - icon = false; - } else if (w && (type == Qt::Popup)) { - cname += QStringLiteral("QPopup"); - style = CS_DBLCLKS|CS_SAVEBITS; - if ((QSysInfo::WindowsVersion >= QSysInfo::WV_XP - && (QSysInfo::WindowsVersion & QSysInfo::WV_NT_based))) - style |= CS_DROPSHADOW; + // Determine style and icon. + uint style = CS_DBLCLKS; + bool icon = true; + if (isGL || (flags & Qt::MSWindowsOwnDC)) + style |= CS_OWNDC; + if ((QSysInfo::WindowsVersion & QSysInfo::WV_NT_based) + && (type == Qt::Popup || w->property("_q_windowsDropShadow").toBool())) { + style |= CS_DROPSHADOW; + } + if (type == Qt::Tool || type == Qt::ToolTip || type == Qt::Popup) { + style |= CS_SAVEBITS; // Save/restore background icon = false; - } else { - cname += QStringLiteral("QWindow"); - style = CS_DBLCLKS; - icon = true; } + // Create a unique name for the flag combination + QString cname = QStringLiteral("Qt5QWindow"); + switch (type) { + case Qt::Tool: + cname += QStringLiteral("Tool"); + break; + case Qt::ToolTip: + cname += QStringLiteral("ToolTip"); + break; + case Qt::Popup: + cname += QStringLiteral("Popup"); + break; + default: + break; + } + if (isGL) + cname += QStringLiteral("GL"); + if (style & CS_DROPSHADOW) + cname += QStringLiteral("DropShadow"); + if (style & CS_SAVEBITS) + cname += QStringLiteral("SaveBits"); + if (style & CS_OWNDC) + cname += QStringLiteral("OwnDC"); + if (icon) + cname += QStringLiteral("Icon"); HBRUSH brush = 0; - if (w && !isGL) + if (!isGL) brush = GetSysColorBrush(COLOR_WINDOW); return registerWindowClass(cname, qWindowsWndProc, style, brush, icon); } @@ -787,7 +784,7 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message, d->m_creationContext->obtainedGeometry.moveTo(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); return true; case QtWindows::CalculateSize: - return false; + return QWindowsGeometryHint::handleCalculateSize(d->m_creationContext->customMargins, msg, result); default: break; } @@ -822,12 +819,7 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message, platformWindow->getSizeHints(reinterpret_cast<MINMAXINFO *>(lParam)); return true;// maybe available on some SDKs revisit WM_NCCALCSIZE case QtWindows::CalculateSize: - // NCCALCSIZE_PARAMS structure if wParam==TRUE - if (wParam && QWindowsContext::verboseWindows) { - const NCCALCSIZE_PARAMS *ncp = reinterpret_cast<NCCALCSIZE_PARAMS *>(lParam); - qDebug() << platformWindow->window() << *ncp; - } - break; + return QWindowsGeometryHint::handleCalculateSize(platformWindow->customMargins(), msg, result); #endif case QtWindows::ExposeEvent: return platformWindow->handleWmPaint(hwnd, message, wParam, lParam); @@ -858,10 +850,10 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message, return true; case QtWindows::ShowEvent: platformWindow->handleShown(); - return true; + return false; // Indicate transient children should be shown by windows (SW_PARENTOPENING) case QtWindows::HideEvent: platformWindow->handleHidden(); - return true; + return false;// Indicate transient children should be hidden by windows (SW_PARENTCLOSING) case QtWindows::CloseEvent: QWindowSystemInterface::handleCloseEvent(platformWindow->window()); return true; diff --git a/src/plugins/platforms/windows/qwindowscursor.cpp b/src/plugins/platforms/windows/qwindowscursor.cpp index 4dc9af61d8..5b2a3acbae 100644 --- a/src/plugins/platforms/windows/qwindowscursor.cpp +++ b/src/plugins/platforms/windows/qwindowscursor.cpp @@ -395,6 +395,19 @@ QWindowsWindowCursor QWindowsCursor::standardWindowCursor(Qt::CursorShape shape) } /*! + \brief Return cached pixmap cursor or create new one. +*/ + +QWindowsWindowCursor QWindowsCursor::pixmapWindowCursor(const QCursor &c) +{ + const qint64 cacheKey = c.pixmap().cacheKey(); + PixmapCursorCache::iterator it = m_pixmapCursorCache.find(cacheKey); + if (it == m_pixmapCursorCache.end()) + it = m_pixmapCursorCache.insert(cacheKey, QWindowsWindowCursor(c)); + return it.value(); +} + +/*! \brief Set a cursor on a window. This is called frequently as the mouse moves over widgets in the window @@ -406,11 +419,15 @@ void QWindowsCursor::changeCursor(QCursor *cursorIn, QWindow *window) if (QWindowsContext::verboseWindows > 1) qDebug() << __FUNCTION__ << cursorIn << window; - if (!cursorIn || !window) + if (!window) + return; + if (!cursorIn) { + QWindowsWindow::baseWindowOf(window)->setCursor(QWindowsWindowCursor()); return; + } const QWindowsWindowCursor wcursor = cursorIn->shape() == Qt::BitmapCursor ? - QWindowsWindowCursor(*cursorIn) : standardWindowCursor(cursorIn->shape()); + pixmapWindowCursor(*cursorIn) : standardWindowCursor(cursorIn->shape()); if (wcursor.handle()) { QWindowsWindow::baseWindowOf(window)->setCursor(wcursor); } else { @@ -449,6 +466,7 @@ void QWindowsCursor::setPos(const QPoint &pos) class QWindowsWindowCursorData : public QSharedData { public: + QWindowsWindowCursorData() : m_cursor(Qt::ArrowCursor), m_handle(0) {} explicit QWindowsWindowCursorData(const QCursor &c); ~QWindowsWindowCursorData(); @@ -464,7 +482,13 @@ QWindowsWindowCursorData::QWindowsWindowCursorData(const QCursor &c) : QWindowsWindowCursorData::~QWindowsWindowCursorData() { - DestroyCursor(m_handle); + if (m_handle) + DestroyCursor(m_handle); +} + +QWindowsWindowCursor::QWindowsWindowCursor() : + m_data(new QWindowsWindowCursorData) +{ } QWindowsWindowCursor::QWindowsWindowCursor(const QCursor &c) : @@ -488,6 +512,11 @@ QWindowsWindowCursor & QWindowsWindowCursor::operator =(const QWindowsWindowCurs return *this; } +bool QWindowsWindowCursor::isNull() const +{ + return m_data->m_handle == 0; +} + QCursor QWindowsWindowCursor::cursor() const { return m_data->m_cursor; diff --git a/src/plugins/platforms/windows/qwindowscursor.h b/src/plugins/platforms/windows/qwindowscursor.h index b0256d4203..1e818bc9b8 100644 --- a/src/plugins/platforms/windows/qwindowscursor.h +++ b/src/plugins/platforms/windows/qwindowscursor.h @@ -55,11 +55,13 @@ class QWindowsWindowCursorData; class QWindowsWindowCursor { public: + QWindowsWindowCursor(); explicit QWindowsWindowCursor(const QCursor &c); ~QWindowsWindowCursor(); QWindowsWindowCursor(const QWindowsWindowCursor &c); QWindowsWindowCursor &operator=(const QWindowsWindowCursor &c); + bool isNull() const; QCursor cursor() const; HCURSOR handle() const; @@ -81,11 +83,14 @@ public: static QPoint mousePosition(); QWindowsWindowCursor standardWindowCursor(Qt::CursorShape s = Qt::ArrowCursor); + QWindowsWindowCursor pixmapWindowCursor(const QCursor &c); private: typedef QHash<Qt::CursorShape, QWindowsWindowCursor> StandardCursorCache; + typedef QHash<qint64, QWindowsWindowCursor> PixmapCursorCache; StandardCursorCache m_standardCursorCache; + PixmapCursorCache m_pixmapCursorCache; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp b/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp index daa4369d88..5b84725edf 100644 --- a/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp +++ b/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp @@ -58,6 +58,10 @@ #include <QtCore/QObject> #include <QtCore/QThread> #include <QtCore/QSysInfo> +#include <QtCore/QSharedData> +#include <QtCore/QExplicitlySharedDataPointer> +#include <QtCore/QMutex> +#include <QtCore/QMutexLocker> #include <QtCore/private/qsystemlibrary_p.h> #include "qtwindows_additional.h" @@ -82,6 +86,8 @@ static const IID q_IID_IShellItem = {0x43826d1e, 0xe718, 0x42ee, {0xbc, 0 #define IID_IShellItem q_IID_IShellItem #else static const IID IID_IShellItem = {0x43826d1e, 0xe718, 0x42ee, {0xbc, 0x55, 0xa1, 0xe2, 0x61, 0xc3, 0x7b, 0xfe}}; +static const IID IID_IShellItemArray = {0xb63ea76d, 0x1f85, 0x456f, {0xa1, 0x9c, 0x48, 0x15, 0x9e, 0xfa, 0x85, 0x8b}}; +# define LFF_FORCEFILESYSTEM 1 #endif static const IID IID_IFileDialogEvents = {0x973510db, 0x7d7f, 0x452b,{0x89, 0x75, 0x74, 0xa8, 0x58, 0x28, 0xd3, 0x54}}; static const CLSID CLSID_FileOpenDialog = {0xdc1c5a9c, 0xe88a, 0x4dde, {0xa5, 0xa1, 0x60, 0xf8, 0x2a, 0x20, 0xae, 0xf7}}; @@ -249,6 +255,34 @@ DECLARE_INTERFACE_(IShellItemArray, IUnknown) }; #endif +#ifndef __IShellLibrary_INTERFACE_DEFINED__ + +enum LIBRARYOPTIONFLAGS {}; +enum DEFAULTSAVEFOLDERTYPE { DSFT_DETECT = 1 }; +enum LIBRARYSAVEFLAGS {}; + +DECLARE_INTERFACE_(IShellLibrary, IUnknown) +{ + STDMETHOD(LoadLibraryFromItem)(THIS_ IShellItem *psiLibrary, DWORD grfMode) PURE; + STDMETHOD(LoadLibraryFromKnownFolder)(THIS_ const GUID &kfidLibrary, DWORD grfMode) PURE; + STDMETHOD(AddFolder)(THIS_ IShellItem *psiLocation) PURE; + STDMETHOD(RemoveFolder)(THIS_ IShellItem *psiLocation) PURE; + STDMETHOD(GetFolders)(THIS_ int lff, REFIID riid, void **ppv) PURE; + STDMETHOD(ResolveFolder)(THIS_ IShellItem *psiFolderToResolve, DWORD dwTimeout, REFIID riid, void **ppv) PURE; + STDMETHOD(GetDefaultSaveFolder)(THIS_ DEFAULTSAVEFOLDERTYPE dsft, REFIID riid, void **ppv) PURE; + STDMETHOD(SetDefaultSaveFolder)(THIS_ DEFAULTSAVEFOLDERTYPE dsft, IShellItem *psi) PURE; + STDMETHOD(GetOptions)(THIS_ LIBRARYOPTIONFLAGS *plofOptions) PURE; + STDMETHOD(SetOptions)(THIS_ LIBRARYOPTIONFLAGS lofMask, LIBRARYOPTIONFLAGS lofOptions) PURE; + STDMETHOD(GetFolderType)(THIS_ GUID *pftid) PURE; + STDMETHOD(SetFolderType)(THIS_ const GUID &ftid) PURE; + STDMETHOD(GetIcon)(THIS_ LPWSTR *ppszIcon) PURE; + STDMETHOD(SetIcon)(THIS_ LPCWSTR pszIcon) PURE; + STDMETHOD(Commit)(THIS_) PURE; + STDMETHOD(Save)(THIS_ IShellItem *psiFolderToSaveIn, LPCWSTR pszLibraryName, LIBRARYSAVEFLAGS lsf, IShellItem **ppsiSavedTo) PURE; + STDMETHOD(SaveInKnownFolder)(THIS_ const GUID &kfidToSaveIn, LPCWSTR pszLibraryName, LIBRARYSAVEFLAGS lsf,IShellItem **ppsiSavedTo) PURE; +}; +#endif + #ifndef __IModalWindow_INTERFACE_DEFINED__ DECLARE_INTERFACE_(IModalWindow, IUnknown) { @@ -387,6 +421,9 @@ void eatMouseMove() Vista on) that mimick the behaviour of their QDialog counterparts as close as possible. + Instances of derived classes are controlled by + QWindowsDialogHelperBase-derived classes. + A major difference is that there is only an exec(), which is a modal, blocking call; there is no non-blocking show(). There 2 types of native dialogs: @@ -401,6 +438,7 @@ void eatMouseMove() like close() can be called on them from event handlers. \endlist + \sa QWindowsDialogHelperBase \internal \ingroup qt-lighthouse-win */ @@ -411,7 +449,6 @@ class QWindowsNativeDialogBase : public QObject public: virtual void setWindowTitle(const QString &title) = 0; virtual void exec(HWND owner = 0) = 0; - virtual QPlatformDialogHelper::DialogCode result() const = 0; signals: void accepted(); @@ -432,12 +469,10 @@ protected: The native dialog is created in setVisible_sys() since then modality and the state of DontUseNativeDialog is known. - Modal dialogs are then started via the platformNativeDialogModalHelp(), - platformNativeDialogModalHelp() slots. - Non-modal dialogs are shown using a separate thread should - they support it. + Modal dialogs are then run by exec(). Non-modal dialogs are shown using a + separate thread started in show() should they support it. - \sa QWindowsDialogThread + \sa QWindowsDialogThread, QWindowsNativeDialogBase \internal \ingroup qt-lighthouse-win */ @@ -445,17 +480,12 @@ protected: template <class BaseClass> QWindowsDialogHelperBase<BaseClass>::QWindowsDialogHelperBase() : m_nativeDialog(0), - m_ownerWindow(0) + m_ownerWindow(0), + m_timerId(0) { } template <class BaseClass> -QWindowsDialogHelperBase<BaseClass>::~QWindowsDialogHelperBase() -{ - delete m_nativeDialog; -} - -template <class BaseClass> QWindowsNativeDialogBase *QWindowsDialogHelperBase<BaseClass>::nativeDialog() const { if (!m_nativeDialog) { @@ -466,6 +496,19 @@ QWindowsNativeDialogBase *QWindowsDialogHelperBase<BaseClass>::nativeDialog() co } template <class BaseClass> +void QWindowsDialogHelperBase<BaseClass>::deleteNativeDialog() +{ + delete m_nativeDialog; + m_nativeDialog = 0; +} + +template <class BaseClass> +void QWindowsDialogHelperBase<BaseClass>::timerEvent(QTimerEvent *) +{ + startDialogThread(); +} + +template <class BaseClass> QWindowsNativeDialogBase *QWindowsDialogHelperBase<BaseClass>::ensureNativeDialog() { // Create dialog and apply common settings. @@ -486,22 +529,18 @@ QWindowsNativeDialogBase *QWindowsDialogHelperBase<BaseClass>::ensureNativeDialo class QWindowsDialogThread : public QThread { public: - QWindowsDialogThread(QWindowsNativeDialogBase *dialog, - HWND owner = 0) : - m_dialog(dialog), m_owner(owner) {} - + QWindowsDialogThread(QPlatformDialogHelper *h) : m_helper(h) {} void run(); private: - QWindowsNativeDialogBase *m_dialog; - const HWND m_owner; + QPlatformDialogHelper *m_helper; }; void QWindowsDialogThread::run() { if (QWindowsContext::verboseDialogs) qDebug(">%s" , __FUNCTION__); - m_dialog->exec(m_owner); + m_helper->exec(); deleteLater(); if (QWindowsContext::verboseDialogs) qDebug("<%s" , __FUNCTION__); @@ -512,7 +551,7 @@ bool QWindowsDialogHelperBase<BaseClass>::show(Qt::WindowFlags, Qt::WindowModality windowModality, QWindow *parent) { - const bool modal = (windowModality == Qt::ApplicationModal); + const bool modal = (windowModality != Qt::NonModal); if (parent) { m_ownerWindow = QWindowsWindow::handleOf(parent); } else { @@ -521,18 +560,40 @@ bool QWindowsDialogHelperBase<BaseClass>::show(Qt::WindowFlags, if (QWindowsContext::verboseDialogs) qDebug("%s modal=%d native=%p parent=%p" , __FUNCTION__, modal, m_nativeDialog, m_ownerWindow); - if (!modal && !supportsNonModalDialog()) + if (!modal && !supportsNonModalDialog(parent)) return false; // Was it changed in-between? if (!ensureNativeDialog()) return false; - if (!modal) { // Modal dialogs are shown in separate slot. - QWindowsDialogThread *thread = new QWindowsDialogThread(m_nativeDialog, m_ownerWindow); - thread->start(); + // Start a background thread to show the dialog. For modal dialogs, + // a subsequent call to exec() may follow. So, start an idle timer + // which will start the dialog thread. If exec() is then called, the + // timer is stopped and dialog->exec() is called directly. + if (modal) { + m_timerId = this->startTimer(0); + } else { + startDialogThread(); } return true; } template <class BaseClass> +void QWindowsDialogHelperBase<BaseClass>::startDialogThread() +{ + QWindowsDialogThread *thread = new QWindowsDialogThread(this); + thread->start(); + stopTimer(); +} + +template <class BaseClass> +void QWindowsDialogHelperBase<BaseClass>::stopTimer() +{ + if (m_timerId) { + this->killTimer(m_timerId); + m_timerId = 0; + } +} + +template <class BaseClass> void QWindowsDialogHelperBase<BaseClass>::hide() { if (m_nativeDialog) @@ -545,8 +606,11 @@ void QWindowsDialogHelperBase<BaseClass>::exec() { if (QWindowsContext::verboseDialogs) qDebug("%s" , __FUNCTION__); - if (QWindowsNativeDialogBase *nd = nativeDialog()) + stopTimer(); + if (QWindowsNativeDialogBase *nd = nativeDialog()) { nd->exec(m_ownerWindow); + deleteNativeDialog(); + } } static inline bool snapToDefaultButtonHint() @@ -568,6 +632,101 @@ QVariant QWindowsDialogHelperBase<BaseClass>::styleHint(QPlatformDialogHelper::S } /*! + \class QWindowsFileDialogSharedData + \brief Explicitly shared file dialog parameters that are not in QFileDialogOptions. + + Contain Parameters that need to be cached while the native dialog does not + exist yet. In addition, the data are updated by the change notifications of the + IFileDialogEvent, as querying them after the dialog has closed + does not reliably work. Provides thread-safe setters (for the non-modal case). + + \internal + \ingroup qt-lighthouse-win + \sa QFileDialogOptions +*/ + +class QWindowsFileDialogSharedData +{ +public: + QWindowsFileDialogSharedData() : m_data(new Data) {} + void fromOptions(const QSharedPointer<QFileDialogOptions> &o); + + QString directory() const; + void setDirectory(const QString &); + QString selectedNameFilter() const; + void setSelectedNameFilter(const QString &); + QStringList selectedFiles() const; + void setSelectedFiles(const QStringList &); + QString selectedFile() const; + +private: + class Data : public QSharedData { + public: + QString directory; + QString selectedNameFilter; + QStringList selectedFiles; + QMutex mutex; + }; + QExplicitlySharedDataPointer<Data> m_data; +}; + +inline QString QWindowsFileDialogSharedData::directory() const +{ + m_data->mutex.lock(); + const QString result = m_data->directory; + m_data->mutex.unlock(); + return result; +} + +inline void QWindowsFileDialogSharedData::setDirectory(const QString &d) +{ + QMutexLocker (&m_data->mutex); + m_data->directory = d; +} + +inline QString QWindowsFileDialogSharedData::selectedNameFilter() const +{ + m_data->mutex.lock(); + const QString result = m_data->selectedNameFilter; + m_data->mutex.unlock(); + return result; +} + +inline void QWindowsFileDialogSharedData::setSelectedNameFilter(const QString &f) +{ + QMutexLocker (&m_data->mutex); + m_data->selectedNameFilter = f; +} + +inline QStringList QWindowsFileDialogSharedData::selectedFiles() const +{ + m_data->mutex.lock(); + const QStringList result = m_data->selectedFiles; + m_data->mutex.unlock(); + return result; +} + +inline QString QWindowsFileDialogSharedData::selectedFile() const +{ + const QStringList files = selectedFiles(); + return files.isEmpty() ? QString() : files.front(); +} + +inline void QWindowsFileDialogSharedData::setSelectedFiles(const QStringList &f) +{ + QMutexLocker (&m_data->mutex); + m_data->selectedFiles = f; +} + +inline void QWindowsFileDialogSharedData::fromOptions(const QSharedPointer<QFileDialogOptions> &o) +{ + QMutexLocker (&m_data->mutex); + m_data->directory = o->initialDirectory(); + m_data->selectedFiles = o->initiallySelectedFiles(); + m_data->selectedNameFilter = o->initiallySelectedNameFilter(); +} + +/*! \class QWindowsNativeFileDialogEventHandler \brief Listens to IFileDialog events and forwards them to QWindowsNativeFileDialogBase @@ -609,7 +768,7 @@ public: } // IFileDialogEvents methods - IFACEMETHODIMP OnFileOk(IFileDialog *) { return S_OK; } + IFACEMETHODIMP OnFileOk(IFileDialog *); IFACEMETHODIMP OnFolderChange(IFileDialog *) { return S_OK; } IFACEMETHODIMP OnFolderChanging(IFileDialog *, IShellItem *); IFACEMETHODIMP OnHelp(IFileDialog *) { return S_OK; } @@ -658,15 +817,17 @@ class QWindowsNativeFileDialogBase : public QWindowsNativeDialogBase public: ~QWindowsNativeFileDialogBase(); - inline static QWindowsNativeFileDialogBase *create(QFileDialogOptions::AcceptMode am); + inline static QWindowsNativeFileDialogBase *create(QFileDialogOptions::AcceptMode am, const QWindowsFileDialogSharedData &data); virtual void setWindowTitle(const QString &title); inline void setMode(QFileDialogOptions::FileMode mode, QFileDialogOptions::FileDialogOptions options); inline void setDirectory(const QString &directory); + inline void updateDirectory() { setDirectory(m_data.directory()); } inline QString directory() const; virtual void exec(HWND owner = 0); inline void setNameFilters(const QStringList &f); inline void selectNameFilter(const QString &filter); + inline void updateSelectedNameFilter() { selectNameFilter(m_data.selectedNameFilter()); } inline QString selectedNameFilter() const; void selectFile(const QString &fileName) const; bool hideFiltersDetails() const { return m_hideFiltersDetails; } @@ -674,14 +835,16 @@ public: void setDefaultSuffix(const QString &s); inline void setLabelText(QFileDialogOptions::DialogLabel l, const QString &text); - virtual QPlatformDialogHelper::DialogCode result() const - { return fileResult(); } - virtual QPlatformDialogHelper::DialogCode fileResult(QStringList *fileResult = 0) const = 0; + // Return the selected files for tracking in OnSelectionChanged(). virtual QStringList selectedFiles() const = 0; + // Return the result for tracking in OnFileOk(). Differs from selection for + // example by appended default suffixes, etc. + virtual QStringList dialogResult() const = 0; inline void onFolderChange(IShellItem *); inline void onSelectionChange(); inline void onTypeChange(); + inline bool onFileOk(); signals: void directoryEntered(const QString& directory); @@ -692,23 +855,30 @@ public slots: virtual void close() { m_fileDialog->Close(S_OK); } protected: - QWindowsNativeFileDialogBase(); + explicit QWindowsNativeFileDialogBase(const QWindowsFileDialogSharedData &data); bool init(const CLSID &clsId, const IID &iid); inline IFileDialog * fileDialog() const { return m_fileDialog; } static QString itemPath(IShellItem *item); + static QStringList libraryItemFolders(IShellItem *item); + static QString libraryItemDefaultSaveFolder(IShellItem *item); static int itemPaths(IShellItemArray *items, QStringList *fileResult = 0); static IShellItem *shellItem(const QString &path); + const QWindowsFileDialogSharedData &data() const { return m_data; } + QWindowsFileDialogSharedData &data() { return m_data; } + private: IFileDialog *m_fileDialog; IFileDialogEvents *m_dialogEvents; DWORD m_cookie; QStringList m_nameFilters; bool m_hideFiltersDetails; + QWindowsFileDialogSharedData m_data; }; -QWindowsNativeFileDialogBase::QWindowsNativeFileDialogBase() : - m_fileDialog(0), m_dialogEvents(0), m_cookie(0), m_hideFiltersDetails(false) +QWindowsNativeFileDialogBase::QWindowsNativeFileDialogBase(const QWindowsFileDialogSharedData &data) : + m_fileDialog(0), m_dialogEvents(0), m_cookie(0), m_hideFiltersDetails(false), + m_data(data) { } @@ -764,15 +934,17 @@ IShellItem *QWindowsNativeFileDialogBase::shellItem(const QString &path) return result; } #endif - qErrnoWarning("%s: SHCreateItemFromParsingName()) failed", __FUNCTION__); + qErrnoWarning("%s: SHCreateItemFromParsingName(%s)) failed", __FUNCTION__, qPrintable(path)); return 0; } void QWindowsNativeFileDialogBase::setDirectory(const QString &directory) { - if (IShellItem *psi = QWindowsNativeFileDialogBase::shellItem(directory)) { - m_fileDialog->SetFolder(psi); - psi->Release(); + if (!directory.isEmpty()) { + if (IShellItem *psi = QWindowsNativeFileDialogBase::shellItem(directory)) { + m_fileDialog->SetFolder(psi); + psi->Release(); + } } } @@ -832,17 +1004,94 @@ void QWindowsNativeFileDialogBase::setMode(QFileDialogOptions::FileMode mode, QF qErrnoWarning("%s: SetOptions() failed", __FUNCTION__); } -QString QWindowsNativeFileDialogBase::itemPath(IShellItem *item) +#if !defined(Q_OS_WINCE) && defined(__IShellLibrary_INTERFACE_DEFINED__) // Windows SDK 7 + +// Helper for "Libraries": collections of folders appearing from Windows 7 +// on, visible in the file dialogs. + +// Load a library from a IShellItem (sanitized copy of the inline function +// SHLoadLibraryFromItem from ShObjIdl.h, which does not exist for MinGW). +static IShellLibrary *sHLoadLibraryFromItem(IShellItem *libraryItem, DWORD mode) +{ + // ID symbols present from Windows 7 on: + static const CLSID classId_ShellLibrary = {0xd9b3211d, 0xe57f, 0x4426, {0xaa, 0xef, 0x30, 0xa8, 0x6, 0xad, 0xd3, 0x97}}; + static const IID iId_IShellLibrary = {0x11a66efa, 0x382e, 0x451a, {0x92, 0x34, 0x1e, 0xe, 0x12, 0xef, 0x30, 0x85}}; + + IShellLibrary *helper = 0; + IShellLibrary *result = 0; + if (SUCCEEDED(CoCreateInstance(classId_ShellLibrary, NULL, CLSCTX_INPROC_SERVER, iId_IShellLibrary, reinterpret_cast<void **>(&helper)))) + if (SUCCEEDED(helper->LoadLibraryFromItem(libraryItem, mode))) + helper->QueryInterface(iId_IShellLibrary, reinterpret_cast<void **>(&result)); + if (helper) + helper->Release(); + return result; +} + +// Return all folders of a library-type item. +QStringList QWindowsNativeFileDialogBase::libraryItemFolders(IShellItem *item) +{ + QStringList result; + if (IShellLibrary *library = sHLoadLibraryFromItem(item, STGM_READ | STGM_SHARE_DENY_WRITE)) { + IShellItemArray *itemArray = 0; + if (SUCCEEDED(library->GetFolders(LFF_FORCEFILESYSTEM, IID_IShellItemArray, reinterpret_cast<void **>(&itemArray)))) { + QWindowsNativeFileDialogBase::itemPaths(itemArray, &result); + itemArray->Release(); + } + library->Release(); + } + return result; +} + +// Return default save folders of a library-type item. +QString QWindowsNativeFileDialogBase::libraryItemDefaultSaveFolder(IShellItem *item) { QString result; - LPWSTR name = 0; - if (SUCCEEDED(item->GetDisplayName(SIGDN_FILESYSPATH, &name))) { - result = QDir::cleanPath(QString::fromWCharArray(name)); - CoTaskMemFree(name); + if (IShellLibrary *library = sHLoadLibraryFromItem(item, STGM_READ | STGM_SHARE_DENY_WRITE)) { + IShellItem *item = 0; + if (SUCCEEDED(library->GetDefaultSaveFolder(DSFT_DETECT, IID_IShellItem, reinterpret_cast<void **>(&item)))) { + result = QWindowsNativeFileDialogBase::itemPath(item); + item->Release(); + } + library->Release(); } return result; } +#else // !Q_OS_WINCE && __IShellLibrary_INTERFACE_DEFINED__ + +QStringList QWindowsNativeFileDialogBase::libraryItemFolders(IShellItem *) +{ + return QStringList(); +} + +QString QWindowsNativeFileDialogBase::libraryItemDefaultSaveFolder(IShellItem *) +{ + return QString(); +} + +#endif // Q_OS_WINCE || !__IShellLibrary_INTERFACE_DEFINED__ + +QString QWindowsNativeFileDialogBase::itemPath(IShellItem *item) +{ + SFGAOF attributes = 0; + // Check whether it has a file system representation? + if (FAILED(item->GetAttributes(SFGAO_FILESYSTEM, &attributes))) + return QString(); + if (attributes & SFGAO_FILESYSTEM) { + LPWSTR name = 0; + QString result; + if (SUCCEEDED(item->GetDisplayName(SIGDN_FILESYSPATH, &name))) { + result = QDir::cleanPath(QString::fromWCharArray(name)); + CoTaskMemFree(name); + } + return result; + } + // Check for a "Library" item + if ((QSysInfo::windowsVersion() & QSysInfo::WV_NT_based) && QSysInfo::windowsVersion() >= QSysInfo::WV_WINDOWS7) + return QWindowsNativeFileDialogBase::libraryItemDefaultSaveFolder(item); + return QString(); +} + int QWindowsNativeFileDialogBase::itemPaths(IShellItemArray *items, QStringList *result /* = 0 */) { @@ -983,14 +1232,16 @@ static int indexOfNameFilter(const QStringList &filters, const QString &needle) void QWindowsNativeFileDialogBase::selectNameFilter(const QString &filter) { + if (filter.isEmpty()) + return; const int index = indexOfNameFilter(m_nameFilters, filter); - if (index >= 0) { - m_fileDialog->SetFileTypeIndex(index + 1); // one-based. - } else { + if (index < 0) { qWarning("%s: Invalid parameter '%s' not found in '%s'.", __FUNCTION__, qPrintable(filter), qPrintable(m_nameFilters.join(QStringLiteral(", ")))); + return; } + m_fileDialog->SetFileTypeIndex(index + 1); // one-based. } QString QWindowsNativeFileDialogBase::selectedNameFilter() const @@ -1008,6 +1259,7 @@ void QWindowsNativeFileDialogBase::onFolderChange(IShellItem *item) { if (item) { const QString directory = QWindowsNativeFileDialogBase::itemPath(item); + m_data.setDirectory(directory); emit directoryEntered(directory); } } @@ -1015,13 +1267,23 @@ void QWindowsNativeFileDialogBase::onFolderChange(IShellItem *item) void QWindowsNativeFileDialogBase::onSelectionChange() { const QStringList current = selectedFiles(); + m_data.setSelectedFiles(current); if (current.size() == 1) emit currentChanged(current.front()); } void QWindowsNativeFileDialogBase::onTypeChange() { - emit filterSelected(selectedNameFilter()); + const QString filter = selectedNameFilter(); + m_data.setSelectedNameFilter(filter); + emit filterSelected(filter); +} + +bool QWindowsNativeFileDialogBase::onFileOk() +{ + // Store selected files as GetResults() returns invalid data after the dialog closes. + m_data.setSelectedFiles(dialogResult()); + return true; } HRESULT QWindowsNativeFileDialogEventHandler::OnFolderChanging(IFileDialog *, IShellItem *item) @@ -1042,6 +1304,11 @@ HRESULT QWindowsNativeFileDialogEventHandler::OnTypeChange(IFileDialog *) return S_OK; } +HRESULT QWindowsNativeFileDialogEventHandler::OnFileOk(IFileDialog *) +{ + return m_nativeFileDialog->onFileOk() ? S_OK : S_FALSE; +} + /*! \class QWindowsNativeSaveFileDialog \brief Windows native file save dialog wrapper around IFileSaveDialog. @@ -1055,8 +1322,10 @@ HRESULT QWindowsNativeFileDialogEventHandler::OnTypeChange(IFileDialog *) class QWindowsNativeSaveFileDialog : public QWindowsNativeFileDialogBase { public: - virtual QPlatformDialogHelper::DialogCode fileResult(QStringList *fileResult = 0) const; + explicit QWindowsNativeSaveFileDialog(const QWindowsFileDialogSharedData &data) : + QWindowsNativeFileDialogBase(data) {} virtual QStringList selectedFiles() const; + virtual QStringList dialogResult() const; }; // Append a suffix from the name filter "Foo files (*.foo;*.bar)" @@ -1081,17 +1350,13 @@ static inline QString appendSuffix(const QString &fileName, const QString &filte return fileName + QLatin1Char('.') + filter.mid(suffixPos, endPos - suffixPos); } -QPlatformDialogHelper::DialogCode QWindowsNativeSaveFileDialog::fileResult(QStringList *result /* = 0 */) const +QStringList QWindowsNativeSaveFileDialog::dialogResult() const { - if (result) - result->clear(); + QStringList result; IShellItem *item = 0; - const HRESULT hr = fileDialog()->GetResult(&item); - if (FAILED(hr) || !item) - return QPlatformDialogHelper::Rejected; - if (result) - result->push_back(appendSuffix(QWindowsNativeFileDialogBase::itemPath(item), selectedNameFilter())); - return QPlatformDialogHelper::Accepted; + if (SUCCEEDED(fileDialog()->GetResult(&item)) && item) + result.push_back(appendSuffix(QWindowsNativeFileDialogBase::itemPath(item), selectedNameFilter())); + return result; } QStringList QWindowsNativeSaveFileDialog::selectedFiles() const @@ -1117,23 +1382,23 @@ QStringList QWindowsNativeSaveFileDialog::selectedFiles() const class QWindowsNativeOpenFileDialog : public QWindowsNativeFileDialogBase { public: - virtual QPlatformDialogHelper::DialogCode fileResult(QStringList *fileResult = 0) const; + explicit QWindowsNativeOpenFileDialog(const QWindowsFileDialogSharedData &data) : + QWindowsNativeFileDialogBase(data) {} virtual QStringList selectedFiles() const; + virtual QStringList dialogResult() const; private: inline IFileOpenDialog *openFileDialog() const { return static_cast<IFileOpenDialog *>(fileDialog()); } }; -QPlatformDialogHelper::DialogCode QWindowsNativeOpenFileDialog::fileResult(QStringList *result /* = 0 */) const +QStringList QWindowsNativeOpenFileDialog::dialogResult() const { - if (result) - result->clear(); + QStringList result; IShellItemArray *items = 0; - const HRESULT hr = openFileDialog()->GetResults(&items); - if (SUCCEEDED(hr) && items && QWindowsNativeFileDialogBase::itemPaths(items, result) > 0) - return QPlatformDialogHelper::Accepted; - return QPlatformDialogHelper::Rejected; + if (SUCCEEDED(openFileDialog()->GetResults(&items)) && items) + QWindowsNativeFileDialogBase::itemPaths(items, &result); + return result; } QStringList QWindowsNativeOpenFileDialog::selectedFiles() const @@ -1152,17 +1417,18 @@ QStringList QWindowsNativeOpenFileDialog::selectedFiles() const QFileDialog::AcceptMode. */ -QWindowsNativeFileDialogBase *QWindowsNativeFileDialogBase::create(QFileDialogOptions::AcceptMode am) +QWindowsNativeFileDialogBase *QWindowsNativeFileDialogBase::create(QFileDialogOptions::AcceptMode am, + const QWindowsFileDialogSharedData &data) { QWindowsNativeFileDialogBase *result = 0; if (am == QFileDialogOptions::AcceptOpen) { - result = new QWindowsNativeOpenFileDialog; + result = new QWindowsNativeOpenFileDialog(data); if (!result->init(CLSID_FileOpenDialog, IID_IFileOpenDialog)) { delete result; return 0; } } else { - result = new QWindowsNativeSaveFileDialog; + result = new QWindowsNativeSaveFileDialog(data); if (!result->init(CLSID_FileSaveDialog, IID_IFileSaveDialog)) { delete result; return 0; @@ -1171,16 +1437,17 @@ QWindowsNativeFileDialogBase *QWindowsNativeFileDialogBase::create(QFileDialogOp return result; } +static inline bool isQQuickWindow(const QWindow *w = 0) +{ + return w && w->inherits("QQuickWindow"); +} + /*! \class QWindowsFileDialogHelper \brief Helper for native Windows file dialogs - Non-modal dialogs are disabled for now. The functionality is - implemented in principle, however there are failures - when querying the results from a dialog run in another thread. - This could probably be fixed be calling CoInitializeEx() with - the right parameters from each thread. The problem is though - that calls to CoInitialize() occur in several places in Qt. + For Qt 4 compatibility, do not create native non-modal dialogs on widgets, + but only on QQuickWindows, which do not have a fallback. \internal \ingroup qt-lighthouse-win @@ -1190,8 +1457,7 @@ class QWindowsFileDialogHelper : public QWindowsDialogHelperBase<QPlatformFileDi { public: QWindowsFileDialogHelper() {} - virtual bool supportsNonModalDialog() const { return false; } - + virtual bool supportsNonModalDialog(const QWindow * /* parent */ = 0) const { return false; } virtual bool defaultNameFilterDisables() const { return true; } virtual void setDirectory(const QString &directory); @@ -1207,11 +1473,14 @@ private: virtual QWindowsNativeDialogBase *createNativeDialog(); inline QWindowsNativeFileDialogBase *nativeFileDialog() const { return static_cast<QWindowsNativeFileDialogBase *>(nativeDialog()); } + + // Cache for the case no native dialog is created. + QWindowsFileDialogSharedData m_data; }; QWindowsNativeDialogBase *QWindowsFileDialogHelper::createNativeDialog() { - QWindowsNativeFileDialogBase *result = QWindowsNativeFileDialogBase::create(options()->acceptMode()); + QWindowsNativeFileDialogBase *result = QWindowsNativeFileDialogBase::create(options()->acceptMode(), m_data); if (!result) return 0; QObject::connect(result, SIGNAL(accepted()), this, SIGNAL(accept())); @@ -1225,8 +1494,10 @@ QWindowsNativeDialogBase *QWindowsFileDialogHelper::createNativeDialog() // Apply settings. const QSharedPointer<QFileDialogOptions> &opts = options(); + m_data.fromOptions(opts); + const QFileDialogOptions::FileMode mode = opts->fileMode(); result->setWindowTitle(opts->windowTitle()); - result->setMode(opts->fileMode(), opts->options()); + result->setMode(mode, opts->options()); result->setHideFiltersDetails(opts->testOption(QFileDialogOptions::HideNameFilterDetails)); const QStringList nameFilters = opts->nameFilters(); if (!nameFilters.isEmpty()) @@ -1235,18 +1506,20 @@ QWindowsNativeDialogBase *QWindowsFileDialogHelper::createNativeDialog() result->setLabelText(QFileDialogOptions::FileName, opts->labelText(QFileDialogOptions::FileName)); if (opts->isLabelExplicitlySet(QFileDialogOptions::Accept)) result->setLabelText(QFileDialogOptions::Accept, opts->labelText(QFileDialogOptions::Accept)); - const QString initialDirectory = opts->initialDirectory(); - if (!initialDirectory.isEmpty()) - result->setDirectory(initialDirectory); + result->updateDirectory(); + result->updateSelectedNameFilter(); const QStringList initialSelection = opts->initiallySelectedFiles(); if (initialSelection.size() > 0) { QFileInfo info(initialSelection.front()); if (!info.isDir()) result->selectFile(info.fileName()); } - const QString initialNameFilter = opts->initiallySelectedNameFilter(); - if (!initialNameFilter.isEmpty()) - result->selectNameFilter(initialNameFilter); + // No need to select initialNameFilter if mode is Dir + if (mode != QFileDialogOptions::Directory && mode != QFileDialogOptions::DirectoryOnly) { + const QString initialNameFilter = opts->initiallySelectedNameFilter(); + if (!initialNameFilter.isEmpty()) + result->selectNameFilter(initialNameFilter); + } const QString defaultSuffix = opts->defaultSuffix(); if (!defaultSuffix.isEmpty()) result->setDefaultSuffix(defaultSuffix); @@ -1258,15 +1531,14 @@ void QWindowsFileDialogHelper::setDirectory(const QString &directory) if (QWindowsContext::verboseDialogs) qDebug("%s %s" , __FUNCTION__, qPrintable(directory)); - if (QWindowsNativeFileDialogBase *nfd = nativeFileDialog()) - nfd->setDirectory(directory); + m_data.setDirectory(directory); + if (hasNativeDialog()) + nativeFileDialog()->updateDirectory(); } QString QWindowsFileDialogHelper::directory() const { - if (const QWindowsNativeFileDialogBase *nfd = nativeFileDialog()) - return nfd->directory(); - return QString(); + return m_data.directory(); } void QWindowsFileDialogHelper::selectFile(const QString &fileName) @@ -1280,13 +1552,7 @@ void QWindowsFileDialogHelper::selectFile(const QString &fileName) QStringList QWindowsFileDialogHelper::selectedFiles() const { - QStringList files; - if (const QWindowsNativeFileDialogBase *nfd = nativeFileDialog()) - nfd->fileResult(&files); - if (QWindowsContext::verboseDialogs) - qDebug("%s files='%s'" , __FUNCTION__, - qPrintable(files.join(QStringLiteral(", ")))); - return files; + return m_data.selectedFiles(); } void QWindowsFileDialogHelper::setFilter() @@ -1305,15 +1571,14 @@ void QWindowsFileDialogHelper::setNameFilters(const QStringList &filters) void QWindowsFileDialogHelper::selectNameFilter(const QString &filter) { - if (QWindowsNativeFileDialogBase *nfd = nativeFileDialog()) - nfd->selectNameFilter(filter); + m_data.setSelectedNameFilter(filter); + if (hasNativeDialog()) + nativeFileDialog()->updateSelectedNameFilter(); } QString QWindowsFileDialogHelper::selectedNameFilter() const { - if (const QWindowsNativeFileDialogBase *nfd = nativeFileDialog()) - return nfd->selectedNameFilter(); - return QString(); + return m_data.selectedNameFilter(); } #ifndef Q_OS_WINCE @@ -1337,20 +1602,12 @@ class QWindowsXpNativeFileDialog : public QWindowsNativeDialogBase public: typedef QSharedPointer<QFileDialogOptions> OptionsPtr; - static QWindowsXpNativeFileDialog *create(const OptionsPtr &options); + static QWindowsXpNativeFileDialog *create(const OptionsPtr &options, const QWindowsFileDialogSharedData &data); virtual void setWindowTitle(const QString &t) { m_title = t; } virtual void exec(HWND owner = 0); virtual QPlatformDialogHelper::DialogCode result() const { return m_result; } - void setDirectory(const QString &d) { m_directory = d; } - QString directory() const { return m_directory; } - void selectFile(const QString &f) { m_initialFile = f; } - QStringList selectedFiles() const { return m_selectedFiles; } - void setNameFilters(const QStringList &n) { m_nameFilters = n; } - void selectNameFilter(const QString &f); - QString selectedNameFilter() const { return m_selectedNameFilter; } - int existingDirCallback(HWND hwnd, UINT uMsg, LPARAM lParam); public slots: @@ -1360,19 +1617,15 @@ private: typedef BOOL (APIENTRY *PtrGetOpenFileNameW)(LPOPENFILENAMEW); typedef BOOL (APIENTRY *PtrGetSaveFileNameW)(LPOPENFILENAMEW); - explicit QWindowsXpNativeFileDialog(const OptionsPtr &options); + explicit QWindowsXpNativeFileDialog(const OptionsPtr &options, const QWindowsFileDialogSharedData &data); void populateOpenFileName(OPENFILENAME *ofn, HWND owner) const; QStringList execExistingDir(HWND owner); QStringList execFileNames(HWND owner, int *selectedFilterIndex) const; const OptionsPtr m_options; QString m_title; - QString m_directory; - QString m_initialFile; - QStringList m_selectedFiles; - QString m_selectedNameFilter; - QStringList m_nameFilters; QPlatformDialogHelper::DialogCode m_result; + QWindowsFileDialogSharedData m_data; static PtrGetOpenFileNameW m_getOpenFileNameW; static PtrGetSaveFileNameW m_getSaveFileNameW; @@ -1381,7 +1634,7 @@ private: QWindowsXpNativeFileDialog::PtrGetOpenFileNameW QWindowsXpNativeFileDialog::m_getOpenFileNameW = 0; QWindowsXpNativeFileDialog::PtrGetSaveFileNameW QWindowsXpNativeFileDialog::m_getSaveFileNameW = 0; -QWindowsXpNativeFileDialog *QWindowsXpNativeFileDialog::create(const OptionsPtr &options) +QWindowsXpNativeFileDialog *QWindowsXpNativeFileDialog::create(const OptionsPtr &options, const QWindowsFileDialogSharedData &data) { // GetOpenFileNameW() GetSaveFileName() are resolved // dynamically as not to create a dependency on Comdlg32, which @@ -1392,51 +1645,33 @@ QWindowsXpNativeFileDialog *QWindowsXpNativeFileDialog::create(const OptionsPtr m_getSaveFileNameW = (PtrGetSaveFileNameW)(library.resolve("GetSaveFileNameW")); } if (m_getOpenFileNameW && m_getSaveFileNameW) - return new QWindowsXpNativeFileDialog(options); + return new QWindowsXpNativeFileDialog(options, data); return 0; } -QWindowsXpNativeFileDialog::QWindowsXpNativeFileDialog(const OptionsPtr &options) : - m_options(options), m_result(QPlatformDialogHelper::Rejected) +QWindowsXpNativeFileDialog::QWindowsXpNativeFileDialog(const OptionsPtr &options, + const QWindowsFileDialogSharedData &data) : + m_options(options), m_result(QPlatformDialogHelper::Rejected), m_data(data) { - const QStringList nameFilters = m_options->nameFilters(); - if (!nameFilters.isEmpty()) - setNameFilters(nameFilters); - const QString initialDirectory = m_options->initialDirectory(); - if (!initialDirectory.isEmpty()) - setDirectory(initialDirectory); - const QString initialNameFilter = m_options->initiallySelectedNameFilter(); - if (!initialNameFilter.isEmpty()) - selectNameFilter(initialNameFilter); - const QStringList selectedFiles = m_options->initiallySelectedFiles(); - if (!selectedFiles.isEmpty()) - selectFile(selectedFiles.front()); setWindowTitle(m_options->windowTitle()); } -void QWindowsXpNativeFileDialog::selectNameFilter(const QString &f) -{ - const int index = indexOfNameFilter(m_nameFilters, f); - if (index >= 0) - m_selectedNameFilter = m_nameFilters.at(index); -} - void QWindowsXpNativeFileDialog::exec(HWND owner) { int selectedFilterIndex = -1; - m_selectedFiles = m_options->fileMode() == QFileDialogOptions::DirectoryOnly ? + const QStringList selectedFiles = + m_options->fileMode() == QFileDialogOptions::DirectoryOnly ? execExistingDir(owner) : execFileNames(owner, &selectedFilterIndex); + m_data.setSelectedFiles(selectedFiles); QWindowsDialogs::eatMouseMove(); - if (m_selectedFiles.isEmpty()) { + if (selectedFiles.isEmpty()) { m_result = QPlatformDialogHelper::Rejected; emit rejected(); } else { - if (selectedFilterIndex >= 0 && selectedFilterIndex < m_nameFilters.size()) { - m_selectedNameFilter = m_nameFilters.at(selectedFilterIndex); - } else { - m_selectedNameFilter.clear(); - } - m_directory = QFileInfo(m_selectedFiles.front()).absolutePath(); + const QStringList nameFilters = m_options->nameFilters(); + if (selectedFilterIndex >= 0 && selectedFilterIndex < nameFilters.size()) + m_data.setSelectedNameFilter(nameFilters.at(selectedFilterIndex)); + m_data.setDirectory(QFileInfo(selectedFiles.front()).absolutePath()); m_result = QPlatformDialogHelper::Accepted; emit accepted(); } @@ -1460,9 +1695,11 @@ typedef PIDLIST_ABSOLUTE qt_LpItemIdList; int QWindowsXpNativeFileDialog::existingDirCallback(HWND hwnd, UINT uMsg, LPARAM lParam) { switch (uMsg) { - case BFFM_INITIALIZED: - if (!m_initialFile.isEmpty()) - SendMessage(hwnd, BFFM_SETSELECTION, TRUE, LPARAM(m_initialFile.utf16())); + case BFFM_INITIALIZED: { + const QString initialFile = m_data.selectedFile(); + if (!initialFile.isEmpty()) + SendMessage(hwnd, BFFM_SETSELECTION, TRUE, LPARAM(initialFile.utf16())); + } break; case BFFM_SELCHANGED: { wchar_t path[MAX_PATH]; @@ -1534,7 +1771,7 @@ void QWindowsXpNativeFileDialog::populateOpenFileName(OPENFILENAME *ofn, HWND ow *ptr++ = 0; } *ptr = 0; - const int nameFilterIndex = indexOfNameFilter(m_nameFilters, m_selectedNameFilter); + const int nameFilterIndex = indexOfNameFilter(m_options->nameFilters(), m_data.selectedNameFilter()); if (nameFilterIndex >= 0) ofn->nFilterIndex = nameFilterIndex + 1; // 1..n based. // lpstrFile receives the initial selection and is the buffer @@ -1542,10 +1779,10 @@ void QWindowsXpNativeFileDialog::populateOpenFileName(OPENFILENAME *ofn, HWND ow // will not show. ofn->nMaxFile = 65535; const QString initiallySelectedFile = - QDir::toNativeSeparators(m_initialFile).remove(QLatin1Char('<')). + QDir::toNativeSeparators(m_data.selectedFile()).remove(QLatin1Char('<')). remove(QLatin1Char('>')).remove(QLatin1Char('"')).remove(QLatin1Char('|')); ofn->lpstrFile = qStringToWCharArray(initiallySelectedFile, ofn->nMaxFile); - ofn->lpstrInitialDir = qStringToWCharArray(QDir::toNativeSeparators(m_directory)); + ofn->lpstrInitialDir = qStringToWCharArray(QDir::toNativeSeparators(m_data.directory())); ofn->lpstrTitle = (wchar_t*)m_title.utf16(); // Determine lpstrDefExt. Note that the current MSDN docs document this // member wrong. It should rather be documented as "the default extension @@ -1614,8 +1851,7 @@ class QWindowsXpFileDialogHelper : public QWindowsDialogHelperBase<QPlatformFile { public: QWindowsXpFileDialogHelper() {} - virtual bool supportsNonModalDialog() const { return false; } - + virtual bool supportsNonModalDialog(const QWindow * /* parent */ = 0) const { return false; } virtual bool defaultNameFilterDisables() const { return true; } virtual void setDirectory(const QString &directory); @@ -1631,11 +1867,14 @@ private: virtual QWindowsNativeDialogBase *createNativeDialog(); inline QWindowsXpNativeFileDialog *nativeFileDialog() const { return static_cast<QWindowsXpNativeFileDialog *>(nativeDialog()); } + + QWindowsFileDialogSharedData m_data; }; QWindowsNativeDialogBase *QWindowsXpFileDialogHelper::createNativeDialog() { - if (QWindowsNativeDialogBase *result = QWindowsXpNativeFileDialog::create(options())) { + m_data.fromOptions(options()); + if (QWindowsXpNativeFileDialog *result = QWindowsXpNativeFileDialog::create(options(), m_data)) { QObject::connect(result, SIGNAL(accepted()), this, SIGNAL(accept())); QObject::connect(result, SIGNAL(rejected()), this, SIGNAL(reject())); return result; @@ -1645,47 +1884,37 @@ QWindowsNativeDialogBase *QWindowsXpFileDialogHelper::createNativeDialog() void QWindowsXpFileDialogHelper::setDirectory(const QString &directory) { - if (QWindowsXpNativeFileDialog *nfd = nativeFileDialog()) - nfd->setDirectory(directory); + m_data.setDirectory(directory); // Dialog cannot be updated at run-time. } QString QWindowsXpFileDialogHelper::directory() const { - if (const QWindowsXpNativeFileDialog *nfd = nativeFileDialog()) - return nfd->directory(); - return QString(); + return m_data.directory(); } void QWindowsXpFileDialogHelper::selectFile(const QString &filename) { - if (QWindowsXpNativeFileDialog *nfd = nativeFileDialog()) - nfd->selectFile(filename); + m_data.setSelectedFiles(QStringList(filename)); // Dialog cannot be updated at run-time. } QStringList QWindowsXpFileDialogHelper::selectedFiles() const { - if (const QWindowsXpNativeFileDialog *nfd = nativeFileDialog()) - return nfd->selectedFiles(); - return QStringList(); + return m_data.selectedFiles(); } -void QWindowsXpFileDialogHelper::setNameFilters(const QStringList &n) +void QWindowsXpFileDialogHelper::setNameFilters(const QStringList &) { - if (QWindowsXpNativeFileDialog *nfd = nativeFileDialog()) - nfd->setNameFilters(n); + // Dialog cannot be updated at run-time. } void QWindowsXpFileDialogHelper::selectNameFilter(const QString &f) { - if (QWindowsXpNativeFileDialog *nfd = nativeFileDialog()) - nfd->selectNameFilter(f); + m_data.setSelectedNameFilter(f); // Dialog cannot be updated at run-time. } QString QWindowsXpFileDialogHelper::selectedNameFilter() const { - if (const QWindowsXpNativeFileDialog *nfd = nativeFileDialog()) - return nfd->selectedNameFilter(); - return QString(); + return m_data.selectedNameFilter(); } #endif // Q_OS_WINCE diff --git a/src/plugins/platforms/windows/qwindowsdialoghelpers.h b/src/plugins/platforms/windows/qwindowsdialoghelpers.h index 07f105cb35..7884f398f3 100644 --- a/src/plugins/platforms/windows/qwindowsdialoghelpers.h +++ b/src/plugins/platforms/windows/qwindowsdialoghelpers.h @@ -65,6 +65,7 @@ template <class BaseClass> class QWindowsDialogHelperBase : public BaseClass { public: + ~QWindowsDialogHelperBase() { deleteNativeDialog(); } virtual void exec(); virtual bool show(Qt::WindowFlags windowFlags, @@ -73,19 +74,24 @@ public: virtual void hide(); virtual QVariant styleHint(QPlatformDialogHelper::StyleHint) const; - virtual bool supportsNonModalDialog() const { return true; } + virtual bool supportsNonModalDialog(const QWindow * /* parent */ = 0) const { return true; } protected: QWindowsDialogHelperBase(); - ~QWindowsDialogHelperBase(); QWindowsNativeDialogBase *nativeDialog() const; + inline bool hasNativeDialog() const { return m_nativeDialog; } + void deleteNativeDialog(); + void timerEvent(QTimerEvent *); private: virtual QWindowsNativeDialogBase *createNativeDialog() = 0; inline QWindowsNativeDialogBase *ensureNativeDialog(); + inline void startDialogThread(); + inline void stopTimer(); QWindowsNativeDialogBase *m_nativeDialog; HWND m_ownerWindow; + int m_timerId; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/windows/qwindowsdrag.cpp b/src/plugins/platforms/windows/qwindowsdrag.cpp index 1286f5c106..fedda750d9 100644 --- a/src/plugins/platforms/windows/qwindowsdrag.cpp +++ b/src/plugins/platforms/windows/qwindowsdrag.cpp @@ -304,10 +304,10 @@ private: class DragCursorHandle { Q_DISABLE_COPY(DragCursorHandle) public: - DragCursorHandle(HCURSOR c, quint64 k) : cursor(c), cacheKey(k) {} + DragCursorHandle(HCURSOR c, qint64 k) : cursor(c), cacheKey(k) {} ~DragCursorHandle() { DestroyCursor(cursor); } HCURSOR cursor; - quint64 cacheKey; + qint64 cacheKey; }; typedef QMap <Qt::DropAction, QSharedPointer<DragCursorHandle> > ActionCursorMap; @@ -490,7 +490,7 @@ QWindowsOleDropSource::GiveFeedback(DWORD dwEffect) qDebug("%s dwEffect=%lu, action=%d", __FUNCTION__, dwEffect, action); QSharedPointer<DragCursorHandle> cursorHandler = m_cursors.value(action); - quint64 currentCacheKey = m_drag->currentDrag()->dragCursor(action).cacheKey(); + qint64 currentCacheKey = m_drag->currentDrag()->dragCursor(action).cacheKey(); if (cursorHandler.isNull() || currentCacheKey != cursorHandler->cacheKey) createCursors(); diff --git a/src/plugins/platforms/windows/qwindowsfontdatabase.cpp b/src/plugins/platforms/windows/qwindowsfontdatabase.cpp index b4fb19e8e8..5fa954cb12 100644 --- a/src/plugins/platforms/windows/qwindowsfontdatabase.cpp +++ b/src/plugins/platforms/windows/qwindowsfontdatabase.cpp @@ -606,130 +606,6 @@ QDebug operator<<(QDebug d, const QFontDef &def) return d; } -/* From QFontDatabase.cpp, qt_determine_writing_systems_from_truetype_bits(). - * Fixme: Make public? */ - -// see the Unicode subset bitfields in the MSDN docs -static int requiredUnicodeBits[QFontDatabase::WritingSystemsCount][2] = { - // Any, - { 127, 127 }, - // Latin, - { 0, 127 }, - // Greek, - { 7, 127 }, - // Cyrillic, - { 9, 127 }, - // Armenian, - { 10, 127 }, - // Hebrew, - { 11, 127 }, - // Arabic, - { 13, 127 }, - // Syriac, - { 71, 127 }, - //Thaana, - { 72, 127 }, - //Devanagari, - { 15, 127 }, - //Bengali, - { 16, 127 }, - //Gurmukhi, - { 17, 127 }, - //Gujarati, - { 18, 127 }, - //Oriya, - { 19, 127 }, - //Tamil, - { 20, 127 }, - //Telugu, - { 21, 127 }, - //Kannada, - { 22, 127 }, - //Malayalam, - { 23, 127 }, - //Sinhala, - { 73, 127 }, - //Thai, - { 24, 127 }, - //Lao, - { 25, 127 }, - //Tibetan, - { 70, 127 }, - //Myanmar, - { 74, 127 }, - // Georgian, - { 26, 127 }, - // Khmer, - { 80, 127 }, - // SimplifiedChinese, - { 126, 127 }, - // TraditionalChinese, - { 126, 127 }, - // Japanese, - { 126, 127 }, - // Korean, - { 56, 127 }, - // Vietnamese, - { 0, 127 }, // same as latin1 - // Other, - { 126, 127 }, - // Ogham, - { 78, 127 }, - // Runic, - { 79, 127 }, - // Nko, - { 14, 127 }, -}; - -enum -{ - SimplifiedChineseCsbBit = 18, - TraditionalChineseCsbBit = 20, - JapaneseCsbBit = 17, - KoreanCsbBit = 21 -}; - -static inline void writingSystemsFromTrueTypeBits(quint32 unicodeRange[4], - quint32 codePageRange[2], - QSupportedWritingSystems *ws) -{ - bool hasScript = false; - for(int i = 0; i < QFontDatabase::WritingSystemsCount; i++) { - int bit = requiredUnicodeBits[i][0]; - int index = bit/32; - int flag = 1 << (bit&31); - if (bit != 126 && unicodeRange[index] & flag) { - bit = requiredUnicodeBits[i][1]; - index = bit/32; - - flag = 1 << (bit&31); - if (bit == 127 || unicodeRange[index] & flag) { - ws->setSupported(QFontDatabase::WritingSystem(i), true); - hasScript = true; - } - } - } - if(codePageRange[0] & (1 << SimplifiedChineseCsbBit)) { - ws->setSupported(QFontDatabase::SimplifiedChinese, true); - hasScript = true; - } - if(codePageRange[0] & (1 << TraditionalChineseCsbBit)) { - ws->setSupported(QFontDatabase::TraditionalChinese, true); - hasScript = true; - } - if(codePageRange[0] & (1 << JapaneseCsbBit)) { - ws->setSupported(QFontDatabase::Japanese, true); - hasScript = true; - //qDebug("font %s supports Japanese", familyName.latin1()); - } - if(codePageRange[0] & (1 << KoreanCsbBit)) { - ws->setSupported(QFontDatabase::Korean, true); - hasScript = true; - } - if (!hasScript) - ws->setSupported(QFontDatabase::Symbol, true); -} - // convert 0 ~ 1000 integer to QFont::Weight static inline QFont::Weight weightFromInteger(long weight) { @@ -744,36 +620,43 @@ static inline QFont::Weight weightFromInteger(long weight) return QFont::Black; } -static inline QFontDatabase::WritingSystem writingSystemFromScript(const QString &scriptName) +static inline QFontDatabase::WritingSystem writingSystemFromCharSet(uchar charSet) { - if (scriptName == QStringLiteral("Western") - || scriptName == QStringLiteral("Baltic") - || scriptName == QStringLiteral("Central European") - || scriptName == QStringLiteral("Turkish") - || scriptName == QStringLiteral("Vietnamese") - || scriptName == QStringLiteral("OEM/Dos")) + switch (charSet) { + case ANSI_CHARSET: + case EASTEUROPE_CHARSET: + case BALTIC_CHARSET: + case TURKISH_CHARSET: + case OEM_CHARSET: return QFontDatabase::Latin; - if (scriptName == QStringLiteral("Thai")) + case GREEK_CHARSET: + return QFontDatabase::Greek; + case RUSSIAN_CHARSET: + return QFontDatabase::Cyrillic; + case HEBREW_CHARSET: + return QFontDatabase::Hebrew; + case ARABIC_CHARSET: + return QFontDatabase::Arabic; + case THAI_CHARSET: return QFontDatabase::Thai; - if (scriptName == QStringLiteral("Symbol") - || scriptName == QStringLiteral("Other")) - return QFontDatabase::Symbol; - if (scriptName == QStringLiteral("CHINESE_GB2312")) + case GB2312_CHARSET: return QFontDatabase::SimplifiedChinese; - if (scriptName == QStringLiteral("CHINESE_BIG5")) + case CHINESEBIG5_CHARSET: return QFontDatabase::TraditionalChinese; - if (scriptName == QStringLiteral("Cyrillic")) - return QFontDatabase::Cyrillic; - if (scriptName == QStringLiteral("Hangul")) - return QFontDatabase::Korean; - if (scriptName == QStringLiteral("Hebrew")) - return QFontDatabase::Hebrew; - if (scriptName == QStringLiteral("Greek")) - return QFontDatabase::Greek; - if (scriptName == QStringLiteral("Japanese")) + case SHIFTJIS_CHARSET: return QFontDatabase::Japanese; - if (scriptName == QStringLiteral("Arabic")) - return QFontDatabase::Arabic; + case HANGUL_CHARSET: + case JOHAB_CHARSET: + return QFontDatabase::Korean; + case VIETNAMESE_CHARSET: + return QFontDatabase::Vietnamese; + case SYMBOL_CHARSET: + return QFontDatabase::Symbol; + // ### case MAC_CHARSET: + // ### case DEFAULT_CHARSET: + default: + break; + } return QFontDatabase::Any; } @@ -957,7 +840,7 @@ error: Q_GUI_EXPORT void qt_registerAliasToFontFamily(const QString &familyName, const QString &alias); -static bool addFontToDatabase(QString familyName, const QString &scriptName, +static bool addFontToDatabase(const QString &familyName, uchar charSet, const TEXTMETRIC *textmetric, const FONTSIGNATURE *signature, int type) @@ -981,7 +864,7 @@ static bool addFontToDatabase(QString familyName, const QString &scriptName, #ifndef QT_NO_DEBUG_OUTPUT if (QWindowsContext::verboseFonts > 2) { QDebug nospace = qDebug().nospace(); - nospace << __FUNCTION__ << familyName << scriptName + nospace << __FUNCTION__ << familyName << charSet << "TTF=" << ttf; if (type & DEVICE_FONTTYPE) nospace << " DEVICE"; @@ -1001,6 +884,7 @@ static bool addFontToDatabase(QString familyName, const QString &scriptName, QSupportedWritingSystems writingSystems; if (type & TRUETYPE_FONTTYPE) { + Q_ASSERT(signature); quint32 unicodeRange[4] = { signature->fsUsb[0], signature->fsUsb[1], signature->fsUsb[2], signature->fsUsb[3] @@ -1019,7 +903,7 @@ static bool addFontToDatabase(QString familyName, const QString &scriptName, unicodeRange[3] = 0xffffffff; } #endif - writingSystemsFromTrueTypeBits(unicodeRange, codePageRange, &writingSystems); + writingSystems = QPlatformFontDatabase::writingSystemsFromTrueTypeBits(unicodeRange, codePageRange); // ### 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 @@ -1029,7 +913,7 @@ static bool addFontToDatabase(QString familyName, const QString &scriptName, familyName == QStringLiteral("Segoe UI")) writingSystems.setSupported(QFontDatabase::Thai, false); } else { - const QFontDatabase::WritingSystem ws = writingSystemFromScript(scriptName); + const QFontDatabase::WritingSystem ws = writingSystemFromCharSet(charSet); if (ws != QFontDatabase::Any) writingSystems.setSupported(ws); } @@ -1058,14 +942,14 @@ static int CALLBACK storeFont(ENUMLOGFONTEX* f, NEWTEXTMETRICEX *textmetric, { typedef QSet<QString> StringSet; const QString familyName = QString::fromWCharArray(f->elfLogFont.lfFaceName); - const QString script = QString::fromWCharArray(f->elfScript); + const uchar charSet = f->elfLogFont.lfCharSet; const FONTSIGNATURE signature = textmetric->ntmFontSig; // NEWTEXTMETRICEX is a NEWTEXTMETRIC, which according to the documentation is // identical to a TEXTMETRIC except for the last four members, which we don't use // anyway - if (addFontToDatabase(familyName, script, (TEXTMETRIC *)textmetric, &signature, type)) + if (addFontToDatabase(familyName, charSet, (TEXTMETRIC *)textmetric, &signature, type)) reinterpret_cast<StringSet *>(namesSetIn)->insert(familyName); // keep on enumerating @@ -1160,9 +1044,7 @@ QWindowsFontDatabase::~QWindowsFontDatabase() removeApplicationFonts(); } -QFontEngine * QWindowsFontDatabase::fontEngine(const QFontDef &fontDef, - QUnicodeTables::Script script, - void *handle) +QFontEngine * QWindowsFontDatabase::fontEngine(const QFontDef &fontDef, QChar::Script script, void *handle) { QFontEngine *fe = QWindowsFontDatabase::createEngine(script, fontDef, 0, QWindowsContext::instance()->defaultDPI(), false, @@ -1215,7 +1097,7 @@ QFontEngine *QWindowsFontDatabase::fontEngine(const QByteArray &fontData, qreal request.styleStrategy = QFont::NoFontMerging | QFont::PreferMatch; request.hintingPreference = hintingPreference; - fontEngine = QWindowsFontDatabase::createEngine(QUnicodeTables::Common, request, 0, + fontEngine = QWindowsFontDatabase::createEngine(QChar::Script_Common, request, 0, QWindowsContext::instance()->defaultDPI(), false, QStringList(), sharedFontData()); @@ -1223,11 +1105,11 @@ QFontEngine *QWindowsFontDatabase::fontEngine(const QByteArray &fontData, qreal if (request.family != fontEngine->fontDef.family) { qWarning("%s: Failed to load font. Got fallback instead: %s", __FUNCTION__, qPrintable(fontEngine->fontDef.family)); - if (fontEngine->cache_count == 0 && fontEngine->ref.load() == 0) + if (fontEngine->ref.load() == 0) delete fontEngine; fontEngine = 0; } else { - Q_ASSERT(fontEngine->cache_count == 0 && fontEngine->ref.load() == 0); + Q_ASSERT(fontEngine->ref.load() == 0); // Override the generated font name static_cast<QWindowsFontEngine *>(fontEngine)->setUniqueFamilyName(uniqueFamilyName); @@ -1439,7 +1321,7 @@ QStringList QWindowsFontDatabase::addApplicationFont(const QByteArray &fontData, TEXTMETRIC textMetrics; GetTextMetrics(hdc, &textMetrics); - addFontToDatabase(familyName, QString(), &textMetrics, &signatures.at(j), + addFontToDatabase(familyName, lf.lfCharSet, &textMetrics, &signatures.at(j), TRUETYPE_FONTTYPE); SelectObject(hdc, oldobj); @@ -1529,8 +1411,8 @@ HFONT QWindowsFontDatabase::systemFont() static inline bool scriptRequiresOpenType(int script) { - return ((script >= QUnicodeTables::Syriac && script <= QUnicodeTables::Sinhala) - || script == QUnicodeTables::Khmer || script == QUnicodeTables::Nko); + return ((script >= QChar::Script_Syriac && script <= QChar::Script_Sinhala) + || script == QChar::Script_Khmer || script == QChar::Script_Nko); } static const char *other_tryFonts[] = { @@ -1715,7 +1597,7 @@ static QStringList extraTryFontsForFamily(const QString& family) return result; } -QStringList QWindowsFontDatabase::fallbacksForFamily(const QString family, const QFont::Style &style, const QFont::StyleHint &styleHint, const QUnicodeTables::Script &script) const +QStringList QWindowsFontDatabase::fallbacksForFamily(const QString &family, QFont::Style style, QFont::StyleHint styleHint, QChar::Script script) const { QStringList result = QPlatformFontDatabase::fallbacksForFamily(family, style, styleHint, script); if (!result.isEmpty()) @@ -1885,8 +1767,7 @@ QFontEngine *QWindowsFontDatabase::createEngine(int script, const QFontDef &requ // for scripts that do not require OpenType we should just look at the list of // supported writing systems in the font's OS/2 table. if (scriptRequiresOpenType(script)) { - HB_Face hbFace = few->harfbuzzFace(); - if (!hbFace || !hbFace->supported_scripts[script]) { + if (!few->supportsScript(QChar::Script(script))) { qWarning(" OpenType support missing for script\n"); delete few; return 0; @@ -1917,7 +1798,7 @@ QFontEngine *QWindowsFontDatabase::createEngine(int script, const QFontDef &requ directWriteFont->Release(); #endif - if (script == QUnicodeTables::Common + if ((script == QChar::Script_Common || script == QChar::Script_Han) && !(request.styleStrategy & QFont::NoFontMerging)) { QStringList extraFonts = extraTryFontsForFamily(request.family); if (extraFonts.size()) { diff --git a/src/plugins/platforms/windows/qwindowsfontdatabase.h b/src/plugins/platforms/windows/qwindowsfontdatabase.h index c14d6027c2..b9e6c38eaa 100644 --- a/src/plugins/platforms/windows/qwindowsfontdatabase.h +++ b/src/plugins/platforms/windows/qwindowsfontdatabase.h @@ -78,9 +78,9 @@ public: ~QWindowsFontDatabase(); virtual void populateFontDatabase(); - virtual QFontEngine *fontEngine(const QFontDef &fontDef, QUnicodeTables::Script script, void *handle); + virtual QFontEngine *fontEngine(const QFontDef &fontDef, QChar::Script script, void *handle); virtual QFontEngine *fontEngine(const QByteArray &fontData, qreal pixelSize, QFont::HintingPreference hintingPreference); - virtual QStringList fallbacksForFamily(const QString family, const QFont::Style &style, const QFont::StyleHint &styleHint, const QUnicodeTables::Script &script) const; + virtual QStringList fallbacksForFamily(const QString &family, QFont::Style style, QFont::StyleHint styleHint, QChar::Script script) const; virtual QStringList addApplicationFont(const QByteArray &fontData, const QString &fileName); virtual void releaseHandle(void *handle); virtual QString fontDir() const; diff --git a/src/plugins/platforms/windows/qwindowsfontdatabase_ft.cpp b/src/plugins/platforms/windows/qwindowsfontdatabase_ft.cpp index 406dc636b8..98b4e7af62 100644 --- a/src/plugins/platforms/windows/qwindowsfontdatabase_ft.cpp +++ b/src/plugins/platforms/windows/qwindowsfontdatabase_ft.cpp @@ -57,39 +57,6 @@ QT_BEGIN_NAMESPACE -static inline QFontDatabase::WritingSystem writingSystemFromScript(const QString &scriptName) -{ - if (scriptName == QStringLiteral("Western") - || scriptName == QStringLiteral("Baltic") - || scriptName == QStringLiteral("Central European") - || scriptName == QStringLiteral("Turkish") - || scriptName == QStringLiteral("Vietnamese") - || scriptName == QStringLiteral("OEM/Dos")) - return QFontDatabase::Latin; - if (scriptName == QStringLiteral("Thai")) - return QFontDatabase::Thai; - if (scriptName == QStringLiteral("Symbol") - || scriptName == QStringLiteral("Other")) - return QFontDatabase::Symbol; - if (scriptName == QStringLiteral("CHINESE_GB2312")) - return QFontDatabase::SimplifiedChinese; - if (scriptName == QStringLiteral("CHINESE_BIG5")) - return QFontDatabase::TraditionalChinese; - if (scriptName == QStringLiteral("Cyrillic")) - return QFontDatabase::Cyrillic; - if (scriptName == QStringLiteral("Hangul")) - return QFontDatabase::Korean; - if (scriptName == QStringLiteral("Hebrew")) - return QFontDatabase::Hebrew; - if (scriptName == QStringLiteral("Greek")) - return QFontDatabase::Greek; - if (scriptName == QStringLiteral("Japanese")) - return QFontDatabase::Japanese; - if (scriptName == QStringLiteral("Arabic")) - return QFontDatabase::Arabic; - return QFontDatabase::Any; -} - // convert 0 ~ 1000 integer to QFont::Weight static inline QFont::Weight weightFromInteger(long weight) { @@ -104,6 +71,46 @@ static inline QFont::Weight weightFromInteger(long weight) return QFont::Black; } +static inline QFontDatabase::WritingSystem writingSystemFromCharSet(uchar charSet) +{ + switch (charSet) { + case ANSI_CHARSET: + case EASTEUROPE_CHARSET: + case BALTIC_CHARSET: + case TURKISH_CHARSET: + case OEM_CHARSET: + return QFontDatabase::Latin; + case GREEK_CHARSET: + return QFontDatabase::Greek; + case RUSSIAN_CHARSET: + return QFontDatabase::Cyrillic; + case HEBREW_CHARSET: + return QFontDatabase::Hebrew; + case ARABIC_CHARSET: + return QFontDatabase::Arabic; + case THAI_CHARSET: + return QFontDatabase::Thai; + case GB2312_CHARSET: + return QFontDatabase::SimplifiedChinese; + case CHINESEBIG5_CHARSET: + return QFontDatabase::TraditionalChinese; + case SHIFTJIS_CHARSET: + return QFontDatabase::Japanese; + case HANGUL_CHARSET: + case JOHAB_CHARSET: + return QFontDatabase::Korean; + case VIETNAMESE_CHARSET: + return QFontDatabase::Vietnamese; + case SYMBOL_CHARSET: + return QFontDatabase::Symbol; + // ### case MAC_CHARSET: + // ### case DEFAULT_CHARSET: + default: + break; + } + return QFontDatabase::Any; +} + static FontFile * createFontFile(const QString &fileName, int index) { FontFile *fontFile = new FontFile; @@ -117,7 +124,7 @@ extern QString getEnglishName(const QString &familyName); Q_GUI_EXPORT void qt_registerAliasToFontFamily(const QString &familyName, const QString &alias); -static bool addFontToDatabase(QString familyName, const QString &scriptName, +static bool addFontToDatabase(const QString &familyName, uchar charSet, const TEXTMETRIC *textmetric, const FONTSIGNATURE *signature, int type) @@ -148,7 +155,7 @@ static bool addFontToDatabase(QString familyName, const QString &scriptName, #ifndef QT_NO_DEBUG_OUTPUT if (QWindowsContext::verboseFonts > 2) { QDebug nospace = qDebug().nospace(); - nospace << __FUNCTION__ << faceName << fullName << scriptName + nospace << __FUNCTION__ << familyName << faceName << fullName << charSet << "TTF=" << ttf; if (type & DEVICE_FONTTYPE) nospace << " DEVICE"; @@ -168,6 +175,7 @@ static bool addFontToDatabase(QString familyName, const QString &scriptName, QSupportedWritingSystems writingSystems; if (type & TRUETYPE_FONTTYPE) { + Q_ASSERT(signature); quint32 unicodeRange[4] = { signature->fsUsb[0], signature->fsUsb[1], signature->fsUsb[2], signature->fsUsb[3] @@ -175,7 +183,7 @@ static bool addFontToDatabase(QString familyName, const QString &scriptName, quint32 codePageRange[2] = { signature->fsCsb[0], signature->fsCsb[1] }; - writingSystems = QBasicFontDatabase::determineWritingSystemsFromTrueTypeBits(unicodeRange, codePageRange); + writingSystems = QPlatformFontDatabase::writingSystemsFromTrueTypeBits(unicodeRange, codePageRange); // ### 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 @@ -185,7 +193,7 @@ static bool addFontToDatabase(QString familyName, const QString &scriptName, faceName == QStringLiteral("Segoe UI")) writingSystems.setSupported(QFontDatabase::Thai, false); } else { - const QFontDatabase::WritingSystem ws = writingSystemFromScript(scriptName); + const QFontDatabase::WritingSystem ws = writingSystemFromCharSet(charSet); if (ws != QFontDatabase::Any) writingSystems.setSupported(ws); } @@ -308,14 +316,14 @@ static int CALLBACK storeFont(ENUMLOGFONTEX* f, NEWTEXTMETRICEX *textmetric, const QString familyName = QString::fromWCharArray(f->elfLogFont.lfFaceName) + QStringLiteral("::") + QString::fromWCharArray(f->elfFullName); - const QString script = QString::fromWCharArray(f->elfScript); + const uchar charSet = f->elfLogFont.lfCharSet; const FONTSIGNATURE signature = textmetric->ntmFontSig; // NEWTEXTMETRICEX is a NEWTEXTMETRIC, which according to the documentation is // identical to a TEXTMETRIC except for the last four members, which we don't use // anyway - if (addFontToDatabase(familyName, script, (TEXTMETRIC *)textmetric, &signature, type)) + if (addFontToDatabase(familyName, charSet, (TEXTMETRIC *)textmetric, &signature, type)) reinterpret_cast<StringSet *>(namesSetIn)->insert(familyName); // keep on enumerating @@ -362,7 +370,7 @@ void QWindowsFontDatabaseFT::populate(const QString &family) ReleaseDC(0, dummy); } -QFontEngine * QWindowsFontDatabaseFT::fontEngine(const QFontDef &fontDef, QUnicodeTables::Script script, void *handle) +QFontEngine * QWindowsFontDatabaseFT::fontEngine(const QFontDef &fontDef, QChar::Script script, void *handle) { QFontEngine *fe = QBasicFontDatabase::fontEngine(fontDef, script, handle); if (QWindowsContext::verboseFonts) @@ -430,9 +438,9 @@ static const char *kr_tryFonts[] = { static const char **tryFonts = 0; -QStringList QWindowsFontDatabaseFT::fallbacksForFamily(const QString family, const QFont::Style &style, const QFont::StyleHint &styleHint, const QUnicodeTables::Script &script) const +QStringList QWindowsFontDatabaseFT::fallbacksForFamily(const QString &family, QFont::Style style, QFont::StyleHint styleHint, QChar::Script script) const { - if(script == QUnicodeTables::Common) { + if (script == QChar::Script_Common || script == QChar::Script_Han) { // && !(request.styleStrategy & QFont::NoFontMerging)) { QFontDatabase db; if (!db.writingSystems(family).contains(QFontDatabase::Symbol)) { @@ -518,8 +526,8 @@ HFONT QWindowsFontDatabaseFT::systemFont() static inline bool scriptRequiresOpenType(int script) { - return ((script >= QUnicodeTables::Syriac && script <= QUnicodeTables::Sinhala) - || script == QUnicodeTables::Khmer || script == QUnicodeTables::Nko); + return ((script >= QChar::Script_Syriac && script <= QChar::Script_Sinhala) + || script == QChar::Script_Khmer || script == QChar::Script_Nko); } static inline int verticalDPI() diff --git a/src/plugins/platforms/windows/qwindowsfontdatabase_ft.h b/src/plugins/platforms/windows/qwindowsfontdatabase_ft.h index 2ce429d012..d3cbc0210a 100644 --- a/src/plugins/platforms/windows/qwindowsfontdatabase_ft.h +++ b/src/plugins/platforms/windows/qwindowsfontdatabase_ft.h @@ -52,10 +52,10 @@ class QWindowsFontDatabaseFT : public QBasicFontDatabase { public: void populateFontDatabase(); - QFontEngine *fontEngine(const QFontDef &fontDef, QUnicodeTables::Script script, void *handle); + QFontEngine *fontEngine(const QFontDef &fontDef, QChar::Script script, void *handle); QFontEngine *fontEngine(const QByteArray &fontData, qreal pixelSize, QFont::HintingPreference hintingPreference); - QStringList fallbacksForFamily(const QString family, const QFont::Style &style, const QFont::StyleHint &styleHint, const QUnicodeTables::Script &script) const; + QStringList fallbacksForFamily(const QString &family, QFont::Style style, QFont::StyleHint styleHint, QChar::Script script) const; virtual QString fontDir() const; virtual QFont defaultFont() const; diff --git a/src/plugins/platforms/windows/qwindowsfontengine.cpp b/src/plugins/platforms/windows/qwindowsfontengine.cpp index 7fcd9814bd..c402f00453 100644 --- a/src/plugins/platforms/windows/qwindowsfontengine.cpp +++ b/src/plugins/platforms/windows/qwindowsfontengine.cpp @@ -66,7 +66,6 @@ #include <QtCore/QThreadStorage> #include <QtCore/private/qsystemlibrary_p.h> -#include <QtCore/private/qunicodetables_p.h> #include <QtCore/QDebug> #include <limits.h> @@ -155,9 +154,20 @@ static OUTLINETEXTMETRIC *getOutlineTextMetric(HDC hdc) return otm; } +bool QWindowsFontEngine::hasCFFTable() const +{ + HDC hdc = m_fontEngineData->hdc; + SelectObject(hdc, hfont); + return GetFontData(hdc, MAKE_TAG('C', 'F', 'F', ' '), 0, 0, 0) != GDI_ERROR; +} + void QWindowsFontEngine::getCMap() { ttf = (bool)(tm.tmPitchAndFamily & TMPF_TRUETYPE); + + // TMPF_TRUETYPE is not set for fonts with CFF tables + cffTable = !ttf && hasCFFTable(); + HDC hdc = m_fontEngineData->hdc; SelectObject(hdc, hfont); bool symb = false; @@ -1041,7 +1051,7 @@ void QWindowsFontEngine::getUnscaledGlyph(glyph_t glyph, QPainterPath *path, gly bool QWindowsFontEngine::getSfntTableData(uint tag, uchar *buffer, uint *length) const { - if (!ttf) + if (!ttf && !cffTable) return false; HDC hdc = m_fontEngineData->hdc; SelectObject(hdc, hfont); @@ -1216,13 +1226,13 @@ QImage QWindowsFontEngine::alphaRGBMapForGlyph(glyph_t glyph, QFixed, const QTra { HFONT font = hfont; - int contrast; + UINT contrast; SystemParametersInfo(SPI_GETFONTSMOOTHINGCONTRAST, 0, &contrast, 0); SystemParametersInfo(SPI_SETFONTSMOOTHINGCONTRAST, 0, (void *) 1000, 0); int margin = glyphMargin(QFontEngineGlyphCache::Raster_RGBMask); QWindowsNativeImage *mask = drawGDIGlyph(font, glyph, margin, t, QImage::Format_RGB32); - SystemParametersInfo(SPI_SETFONTSMOOTHINGCONTRAST, 0, (void *) contrast, 0); + SystemParametersInfo(SPI_SETFONTSMOOTHINGCONTRAST, 0, (void *) quintptr(contrast), 0); if (mask == 0) return QImage(); @@ -1258,7 +1268,7 @@ QFontEngine *QWindowsFontEngine::cloneWithSize(qreal pixelSize) const request.styleStrategy |= QFont::NoFontMerging; QFontEngine *fontEngine = - QWindowsFontDatabase::createEngine(QUnicodeTables::Common, request, 0, + QWindowsFontDatabase::createEngine(QChar::Script_Common, request, 0, QWindowsContext::instance()->defaultDPI(), false, QStringList(), m_fontEngineData); diff --git a/src/plugins/platforms/windows/qwindowsfontengine.h b/src/plugins/platforms/windows/qwindowsfontengine.h index a23db2f235..2bf6ead503 100644 --- a/src/plugins/platforms/windows/qwindowsfontengine.h +++ b/src/plugins/platforms/windows/qwindowsfontengine.h @@ -145,6 +145,7 @@ public: private: QWindowsNativeImage *drawGDIGlyph(HFONT font, glyph_t, int margin, const QTransform &xform, QImage::Format mask_format); + bool hasCFFTable() const; const QSharedPointer<QWindowsFontEngineData> m_fontEngineData; @@ -155,6 +156,7 @@ private: uint stockFont : 1; uint ttf : 1; uint hasOutline : 1; + uint cffTable : 1; TEXTMETRIC tm; int lw; const unsigned char *cmap; diff --git a/src/plugins/platforms/windows/qwindowsfontenginedirectwrite.cpp b/src/plugins/platforms/windows/qwindowsfontenginedirectwrite.cpp index 183acedfc8..5b6ce695d8 100644 --- a/src/plugins/platforms/windows/qwindowsfontenginedirectwrite.cpp +++ b/src/plugins/platforms/windows/qwindowsfontenginedirectwrite.cpp @@ -376,10 +376,12 @@ void QWindowsFontEngineDirectWrite::recalcAdvances(QGlyphLayout *glyphs, QFontEn if (SUCCEEDED(hr)) { for (int i=0; i<glyphs->numGlyphs; ++i) { glyphs->advances_x[i] = DESIGN_TO_LOGICAL(glyphMetrics[i].advanceWidth); - if (fontDef.styleStrategy & QFont::ForceIntegerMetrics) - glyphs->advances_x[i] = glyphs->advances_x[i].round(); glyphs->advances_y[i] = 0; } + if (fontDef.styleStrategy & QFont::ForceIntegerMetrics) { + for (int i = 0; i < glyphs->numGlyphs; ++i) + glyphs->advances_x[i] = glyphs->advances_x[i].round(); + } } else { qErrnoWarning("%s: GetDesignGlyphMetrics failed", __FUNCTION__); } diff --git a/src/plugins/platforms/windows/qwindowsfontenginedirectwrite.h b/src/plugins/platforms/windows/qwindowsfontenginedirectwrite.h index 35ed6f3891..106087f757 100644 --- a/src/plugins/platforms/windows/qwindowsfontenginedirectwrite.h +++ b/src/plugins/platforms/windows/qwindowsfontenginedirectwrite.h @@ -42,6 +42,8 @@ #ifndef QWINDOWSFONTENGINEDIRECTWRITE_H #define QWINDOWSFONTENGINEDIRECTWRITE_H +#include <QtCore/qglobal.h> + #ifndef QT_NO_DIRECTWRITE #include <QtGui/private/qfontengine_p.h> diff --git a/src/plugins/platforms/windows/qwindowsglcontext.cpp b/src/plugins/platforms/windows/qwindowsglcontext.cpp index 081b42ce65..da3e2a6a6a 100644 --- a/src/plugins/platforms/windows/qwindowsglcontext.cpp +++ b/src/plugins/platforms/windows/qwindowsglcontext.cpp @@ -232,6 +232,7 @@ static QSurfaceFormat QWindowsOpenGLAdditionalFormat *additionalIn = 0) { QSurfaceFormat format; + format.setRenderableType(QSurfaceFormat::OpenGL); if (pfd.dwFlags & PFD_DOUBLEBUFFER) format.setSwapBehavior(QSurfaceFormat::DoubleBuffer); format.setDepthBufferSize(pfd.cDepthBits); @@ -278,7 +279,7 @@ static PIXELFORMATDESCRIPTOR if (format.stereo()) pfd.dwFlags |= PFD_STEREO; - if (format.swapBehavior() == QSurfaceFormat::DoubleBuffer && !isPixmap) + if (format.swapBehavior() != QSurfaceFormat::SingleBuffer && !isPixmap) pfd.dwFlags |= PFD_DOUBLEBUFFER; pfd.cDepthBits = format.depthBufferSize() >= 0 ? format.depthBufferSize() : 32; @@ -388,12 +389,11 @@ static int choosePixelFormat(HDC hdc, iAttributes[i++] = WGL_COLOR_BITS_ARB; iAttributes[i++] = 24; switch (format.swapBehavior()) { - case QSurfaceFormat::DefaultSwapBehavior: - break; case QSurfaceFormat::SingleBuffer: iAttributes[i++] = WGL_DOUBLE_BUFFER_ARB; iAttributes[i++] = FALSE; break; + case QSurfaceFormat::DefaultSwapBehavior: case QSurfaceFormat::DoubleBuffer: case QSurfaceFormat::TripleBuffer: iAttributes[i++] = WGL_DOUBLE_BUFFER_ARB; @@ -500,6 +500,7 @@ static QSurfaceFormat enum { attribSize =40 }; QSurfaceFormat result; + result.setRenderableType(QSurfaceFormat::OpenGL); if (!staticContext.hasExtensions()) return result; int iAttributes[attribSize]; @@ -875,6 +876,12 @@ QWindowsGLContext::QWindowsGLContext(const QOpenGLStaticContextPtr &staticContex m_renderingContext(0), m_pixelFormat(0), m_extensionsUsed(false) { + QSurfaceFormat format = context->format(); + if (format.renderableType() == QSurfaceFormat::DefaultRenderableType) + format.setRenderableType(QSurfaceFormat::OpenGL); + if (format.renderableType() != QSurfaceFormat::OpenGL) + return; + // workaround for matrox driver: // make a cheap call to opengl to force loading of DLL static bool opengl32dll = false; @@ -912,7 +919,7 @@ QWindowsGLContext::QWindowsGLContext(const QOpenGLStaticContextPtr &staticContex QWindowsOpenGLAdditionalFormat obtainedAdditional; if (tryExtensions) { m_pixelFormat = - ARB::choosePixelFormat(hdc, *m_staticContext, context->format(), + ARB::choosePixelFormat(hdc, *m_staticContext, format, requestedAdditional, &m_obtainedPixelFormatDescriptor); if (m_pixelFormat > 0) { m_obtainedFormat = @@ -922,7 +929,7 @@ QWindowsGLContext::QWindowsGLContext(const QOpenGLStaticContextPtr &staticContex } } // tryExtensions if (!m_pixelFormat) { // Failed, try GDI - m_pixelFormat = GDI::choosePixelFormat(hdc, context->format(), requestedAdditional, + m_pixelFormat = GDI::choosePixelFormat(hdc, format, requestedAdditional, &m_obtainedPixelFormatDescriptor); if (m_pixelFormat) m_obtainedFormat = @@ -945,7 +952,7 @@ QWindowsGLContext::QWindowsGLContext(const QOpenGLStaticContextPtr &staticContex if (m_extensionsUsed) m_renderingContext = ARB::createContext(*m_staticContext, hdc, - context->format(), + format, requestedAdditional, sharingRenderingContext); if (!m_renderingContext) diff --git a/src/plugins/platforms/windows/qwindowsintegration.cpp b/src/plugins/platforms/windows/qwindowsintegration.cpp index da4519199f..03e4925c3b 100644 --- a/src/plugins/platforms/windows/qwindowsintegration.cpp +++ b/src/plugins/platforms/windows/qwindowsintegration.cpp @@ -77,6 +77,7 @@ #include <QtCore/private/qeventdispatcher_win_p.h> #include <QtCore/QDebug> +#include <QtCore/QVariant> QT_BEGIN_NAMESPACE @@ -114,6 +115,11 @@ public: bool asyncExpose() const; void setAsyncExpose(bool value); + + QVariantMap windowProperties(QPlatformWindow *window) const; + QVariant windowProperty(QPlatformWindow *window, const QString &name) const; + QVariant windowProperty(QPlatformWindow *window, const QString &name, const QVariant &defaultValue) const; + void setWindowProperty(QPlatformWindow *window, const QString &name, const QVariant &value); }; void *QWindowsNativeInterface::nativeResourceForWindow(const QByteArray &resource, QWindow *window) @@ -150,6 +156,37 @@ void *QWindowsNativeInterface::nativeResourceForBackingStore(const QByteArray &r return 0; } +static const char customMarginPropertyC[] = "WindowsCustomMargins"; + +QVariant QWindowsNativeInterface::windowProperty(QPlatformWindow *window, const QString &name) const +{ + QWindowsWindow *platformWindow = static_cast<QWindowsWindow *>(window); + if (name == QLatin1String(customMarginPropertyC)) + return qVariantFromValue(platformWindow->customMargins()); + return QVariant(); +} + +QVariant QWindowsNativeInterface::windowProperty(QPlatformWindow *window, const QString &name, const QVariant &defaultValue) const +{ + const QVariant result = windowProperty(window, name); + return result.isValid() ? result : defaultValue; +} + +void QWindowsNativeInterface::setWindowProperty(QPlatformWindow *window, const QString &name, const QVariant &value) +{ + QWindowsWindow *platformWindow = static_cast<QWindowsWindow *>(window); + if (name == QLatin1String(customMarginPropertyC)) + platformWindow->setCustomMargins(qvariant_cast<QMargins>(value)); +} + +QVariantMap QWindowsNativeInterface::windowProperties(QPlatformWindow *window) const +{ + QVariantMap result; + const QString customMarginProperty = QLatin1String(customMarginPropertyC); + result.insert(customMarginProperty, windowProperty(window, customMarginProperty)); + return result; +} + #ifndef QT_NO_OPENGL void *QWindowsNativeInterface::nativeResourceForContext(const QByteArray &resource, QOpenGLContext *context) { @@ -372,6 +409,11 @@ QPlatformWindow *QWindowsIntegration::createPlatformWindow(QWindow *window) cons QWindowsWindow::WindowData requested; requested.flags = window->flags(); requested.geometry = window->geometry(); + // Apply custom margins (see QWindowsWindow::setCustomMargins())). + const QVariant customMarginsV = window->property("_q_windowsCustomMargins"); + if (customMarginsV.isValid()) + requested.customMargins = qvariant_cast<QMargins>(customMarginsV); + const QWindowsWindow::WindowData obtained = QWindowsWindow::WindowData::create(window, requested, window->title()); if (QWindowsContext::verboseIntegration || QWindowsContext::verboseWindows) @@ -499,7 +541,6 @@ QVariant QWindowsIntegration::styleHint(QPlatformIntegration::StyleHint hint) co case QPlatformIntegration::ShowIsFullScreen: case QPlatformIntegration::PasswordMaskDelay: case QPlatformIntegration::StartDragVelocity: - case QPlatformIntegration::SynthesizeMouseFromTouchEvents: break; // Not implemented case QPlatformIntegration::FontSmoothingGamma: return QVariant(QWindowsFontDatabase::fontSmoothingGamma()); @@ -509,6 +550,11 @@ QVariant QWindowsIntegration::styleHint(QPlatformIntegration::StyleHint hint) co break; case QPlatformIntegration::UseRtlExtensions: return QVariant(d->m_context.useRTLExtensions()); + case QPlatformIntegration::SynthesizeMouseFromTouchEvents: + // We do not want Qt to synthesize mouse events as Windows also does that. + // Alternatively, Windows-generated touch mouse events can be identified and + // ignored by checking GetMessageExtraInfo() for MI_WP_SIGNATURE (0xFF515700). + return false; } return QPlatformIntegration::styleHint(hint); } diff --git a/src/plugins/platforms/windows/qwindowsintegration.h b/src/plugins/platforms/windows/qwindowsintegration.h index 24dc01f0bd..ca484415be 100644 --- a/src/plugins/platforms/windows/qwindowsintegration.h +++ b/src/plugins/platforms/windows/qwindowsintegration.h @@ -78,7 +78,7 @@ public: # ifndef QT_NO_DRAGANDDROP virtual QPlatformDrag *drag() const; # endif -#endif !QT_NO_CLIPBOARD +#endif // !QT_NO_CLIPBOARD virtual QPlatformInputContext *inputContext() const; #ifndef QT_NO_ACCESSIBILITY virtual QPlatformAccessibility *accessibility() const; diff --git a/src/plugins/platforms/windows/qwindowskeymapper.cpp b/src/plugins/platforms/windows/qwindowskeymapper.cpp index 56deb27442..924d604641 100644 --- a/src/plugins/platforms/windows/qwindowskeymapper.cpp +++ b/src/plugins/platforms/windows/qwindowskeymapper.cpp @@ -856,9 +856,15 @@ bool QWindowsKeyMapper::translateKeyEventInternal(QWindow *window, const MSG &ms if (isNumpad && (nModifiers & AltAny)) { code = winceKeyBend(msg.wParam); } else if (!isDeadKey) { - unsigned char kbdBuffer[256]; // Will hold the complete keyboard state - GetKeyboardState(kbdBuffer); - code = toKeyOrUnicode(msg.wParam, scancode, kbdBuffer); + // QTBUG-8764, QTBUG-10032 + // Can't call toKeyOrUnicode because that would call ToUnicode, and, if a dead key + // is pressed at the moment, Windows would NOT use it to compose a character for the next + // WM_CHAR event. + + // Instead, use MapVirtualKey, which will provide adequate values. + code = MapVirtualKey(msg.wParam, MAPVK_VK_TO_CHAR); + if (code < 0x20 || code == 0x7f) // The same logic as in toKeyOrUnicode() + code = winceKeyBend(msg.wParam); } // Invert state logic: @@ -1120,7 +1126,7 @@ QList<int> QWindowsKeyMapper::possibleKeys(const QKeyEvent *e) const } result << int(baseKey + keyMods); // The base key is _always_ valid, of course - for (int i = 1; i < NumMods; ++i) { + for (size_t i = 1; i < NumMods; ++i) { Qt::KeyboardModifiers neededMods = ModsTbl[i]; quint32 key = kbItem.qtKey[i]; if (key && key != baseKey && ((keyMods & neededMods) == neededMods)) diff --git a/src/plugins/platforms/windows/qwindowsmime.cpp b/src/plugins/platforms/windows/qwindowsmime.cpp index 7fb32d3513..a8bacd631d 100644 --- a/src/plugins/platforms/windows/qwindowsmime.cpp +++ b/src/plugins/platforms/windows/qwindowsmime.cpp @@ -703,14 +703,14 @@ QWindowsMimeURI::QWindowsMimeURI() bool QWindowsMimeURI::canConvertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData) const { - if (getCf(formatetc) == CF_HDROP) { + if (mimeData->hasUrls() && getCf(formatetc) == CF_HDROP) { QList<QUrl> urls = mimeData->urls(); for (int i=0; i<urls.size(); i++) { if (!urls.at(i).toLocalFile().isEmpty()) return true; } } - return (getCf(formatetc) == CF_INETURL_W || getCf(formatetc) == CF_INETURL) && mimeData->hasFormat(QStringLiteral("text/uri-list")); + return (getCf(formatetc) == CF_INETURL_W || getCf(formatetc) == CF_INETURL) && mimeData->hasUrls(); } bool QWindowsMimeURI::convertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData, STGMEDIUM *pmedium) const diff --git a/src/plugins/platforms/windows/qwindowsmousehandler.cpp b/src/plugins/platforms/windows/qwindowsmousehandler.cpp index e1f4f4b143..dd16ea1c6f 100644 --- a/src/plugins/platforms/windows/qwindowsmousehandler.cpp +++ b/src/plugins/platforms/windows/qwindowsmousehandler.cpp @@ -49,6 +49,7 @@ #include <qpa/qwindowsysteminterface.h> #include <QtGui/QGuiApplication> #include <QtGui/QScreen> +#include <QtGui/QWindow> #include <QtCore/QDebug> #include <QtCore/QScopedArrayPointer> @@ -236,6 +237,9 @@ bool QWindowsMouseHandler::translateMouseEvent(QWindow *window, HWND hwnd, platformWindow->setFlag(QWindowsWindow::AutoMouseCapture); if (QWindowsContext::verboseEvents) qDebug() << "Automatic mouse capture " << window; + // Implement "Click to focus" for native child windows. + if (!window->isTopLevel() && QGuiApplication::focusWindow() != window) + window->requestActivate(); } else if (platformWindow->hasMouseCapture() && platformWindow->testFlag(QWindowsWindow::AutoMouseCapture) && (msg.message == WM_LBUTTONUP || msg.message == WM_MBUTTONUP diff --git a/src/plugins/platforms/windows/qwindowsmousehandler.h b/src/plugins/platforms/windows/qwindowsmousehandler.h index b3bfa03380..caf30e6b1a 100644 --- a/src/plugins/platforms/windows/qwindowsmousehandler.h +++ b/src/plugins/platforms/windows/qwindowsmousehandler.h @@ -109,6 +109,8 @@ Qt::KeyboardModifiers QWindowsMouseHandler::keyStateToModifiers(int wParam) mods |= Qt::ControlModifier; if (wParam & MK_SHIFT) mods |= Qt::ShiftModifier; + if (GetKeyState(VK_MENU) < 0) + mods |= Qt::AltModifier; return mods; } diff --git a/src/plugins/platforms/windows/qwindowsservices.cpp b/src/plugins/platforms/windows/qwindowsservices.cpp index bcae2e0816..250fea56b1 100644 --- a/src/plugins/platforms/windows/qwindowsservices.cpp +++ b/src/plugins/platforms/windows/qwindowsservices.cpp @@ -44,6 +44,7 @@ #include <QtCore/QUrl> #include <QtCore/QDebug> +#include <QtCore/QDir> #include <shlobj.h> #ifndef Q_OS_WINCE @@ -57,7 +58,8 @@ enum { debug = 0 }; static inline bool shellExecute(const QString &file) { #ifndef Q_OS_WINCE - const quintptr result = (quintptr)ShellExecute(0, 0, (wchar_t*)file.utf16(), 0, 0, SW_SHOWNORMAL); + const QString nativeFilePath = QDir::toNativeSeparators(file); + const quintptr result = (quintptr)ShellExecute(0, 0, (wchar_t*)nativeFilePath.utf16(), 0, 0, SW_SHOWNORMAL); // ShellExecute returns a value greater than 32 if successful if (result <= 32) { qWarning("ShellExecute '%s' failed (error %s).", qPrintable(file), qPrintable(QString::number(result))); diff --git a/src/plugins/platforms/windows/qwindowswindow.cpp b/src/plugins/platforms/windows/qwindowswindow.cpp index 07dc668b3f..9b2b67619d 100644 --- a/src/plugins/platforms/windows/qwindowswindow.cpp +++ b/src/plugins/platforms/windows/qwindowswindow.cpp @@ -64,6 +64,11 @@ QT_BEGIN_NAMESPACE +enum { + defaultWindowWidth = 160, + defaultWindowHeight = 160 +}; + Q_GUI_EXPORT HICON qt_pixmapToWinHICON(const QPixmap &); static QByteArray debugWinStyle(DWORD style) @@ -198,17 +203,16 @@ static inline QSize clientSize(HWND hwnd) return qSizeOfRect(rect); } -// from qwidget_win.cpp/maximum layout size check removed. -static bool shouldShowMaximizeButton(Qt::WindowFlags flags) +// from qwidget_win.cpp +static bool shouldShowMaximizeButton(const QWindow *w) { - if (flags & Qt::MSWindowsFixedSizeDialogHint) + const Qt::WindowFlags flags = w->flags(); + if ((flags & Qt::MSWindowsFixedSizeDialogHint) || !(flags & Qt::WindowMaximizeButtonHint)) return false; // if the user explicitly asked for the maximize button, we try to add // it even if the window has fixed size. - if (flags & Qt::CustomizeWindowHint && - flags & Qt::WindowMaximizeButtonHint) - return true; - return flags & Qt::WindowMaximizeButtonHint; + return (flags & Qt::CustomizeWindowHint) || + w->maximumSize() == QSize(QWINDOWSIZE_MAX, QWINDOWSIZE_MAX); } // Set the WS_EX_LAYERED flag on a HWND if required. This is required for @@ -253,6 +257,8 @@ static void setWindowOpacity(HWND hwnd, Qt::WindowFlags flags, bool hasAlpha, qr } else { QWindowsContext::user32dll.setLayeredWindowAttributes(hwnd, 0, (int)(level * 255), LWA_ALPHA); } + } else if (IsWindowVisible(hwnd)) { // Repaint when switching from layered. + InvalidateRect(hwnd, NULL, TRUE); } #endif // !Q_OS_WINCE } @@ -296,7 +302,7 @@ struct WindowCreationData tool(false), embedded(false), hasAlpha(false) {} void fromWindow(const QWindow *w, const Qt::WindowFlags flags, unsigned creationFlags = 0); - inline WindowData create(const QWindow *w, const QRect &geometry, QString title) const; + inline WindowData create(const QWindow *w, const WindowData &data, QString title) const; inline void applyWindowFlags(HWND hwnd) const; void initialize(HWND h, bool frameChange, qreal opacityLevel) const; @@ -427,7 +433,7 @@ void WindowCreationData::fromWindow(const QWindow *w, const Qt::WindowFlags flag style |= WS_SYSMENU; if (flags & Qt::WindowMinimizeButtonHint) style |= WS_MINIMIZEBOX; - if (shouldShowMaximizeButton(flags)) + if (shouldShowMaximizeButton(w)) style |= WS_MAXIMIZEBOX; if (tool) exStyle |= WS_EX_TOOLWINDOW; @@ -448,7 +454,7 @@ void WindowCreationData::fromWindow(const QWindow *w, const Qt::WindowFlags flag } QWindowsWindow::WindowData - WindowCreationData::create(const QWindow *w, const QRect &geometry, QString title) const + WindowCreationData::create(const QWindow *w, const WindowData &data, QString title) const { typedef QSharedPointer<QWindowCreationContext> QWindowCreationContextPtr; @@ -468,30 +474,38 @@ QWindowsWindow::WindowData const QString windowClassName = QWindowsContext::instance()->registerWindowClass(w, isGL); + QRect rect = QPlatformWindow::initialGeometry(w, data.geometry, defaultWindowWidth, defaultWindowHeight); + if (title.isEmpty() && (result.flags & Qt::WindowTitleHint)) title = topLevel ? qAppName() : w->objectName(); const wchar_t *titleUtf16 = reinterpret_cast<const wchar_t *>(title.utf16()); const wchar_t *classNameUtf16 = reinterpret_cast<const wchar_t *>(windowClassName.utf16()); - // Capture events before CreateWindowEx() returns. - const QWindowCreationContextPtr context(new QWindowCreationContext(w, geometry, style, exStyle)); + // Capture events before CreateWindowEx() returns. The context is cleared in + // the QWindowsWindow constructor. + const QWindowCreationContextPtr context(new QWindowCreationContext(w, rect, data.customMargins, style, exStyle)); QWindowsContext::instance()->setWindowCreationContext(context); + if (context->frameX < 0) + context->frameX = 0; + if (context->frameY < 0) + context->frameY = 0; + if (QWindowsContext::verboseWindows) qDebug().nospace() << "CreateWindowEx: " << w << *this << " class=" <<windowClassName << " title=" << title - << "\nrequested: " << geometry << ": " + << "\nrequested: " << rect << ": " << context->frameWidth << 'x' << context->frameHeight - << '+' << context->frameX << '+' << context->frameY; + << '+' << context->frameX << '+' << context->frameY + << " custom margins: " << context->customMargins; result.hwnd = CreateWindowEx(exStyle, classNameUtf16, titleUtf16, style, context->frameX, context->frameY, context->frameWidth, context->frameHeight, parentHandle, NULL, appinst, NULL); - QWindowsContext::instance()->setWindowCreationContext(QWindowCreationContextPtr()); if (QWindowsContext::verboseWindows) qDebug().nospace() << "CreateWindowEx: returns " << w << ' ' << result.hwnd << " obtained geometry: " @@ -505,6 +519,7 @@ QWindowsWindow::WindowData result.geometry = context->obtainedGeometry; result.frame = context->margins; result.embedded = embedded; + result.customMargins = context->customMargins; return result; } @@ -543,6 +558,8 @@ void WindowCreationData::initialize(HWND hwnd, bool frameChange, qreal opacityLe qWarning() << "QWidget: Incompatible window flags: the window can't be on top and on bottom at the same time"; } else if (flags & Qt::WindowStaysOnBottomHint) { SetWindowPos(hwnd, HWND_BOTTOM, 0, 0, 0, 0, swpFlags); + } else if (frameChange) { // Force WM_NCCALCSIZE with wParam=1 in case of custom margins. + SetWindowPos(hwnd, 0, 0, 0, 0, 0, swpFlags); } if (flags & (Qt::CustomizeWindowHint|Qt::WindowTitleHint)) { HMENU systemMenu = GetSystemMenu(hwnd, FALSE); @@ -571,9 +588,10 @@ void WindowCreationData::initialize(HWND hwnd, bool frameChange, qreal opacityLe #define QWINDOWSIZE_MAX ((1<<24)-1) -QWindowsGeometryHint::QWindowsGeometryHint(const QWindow *w) : +QWindowsGeometryHint::QWindowsGeometryHint(const QWindow *w, const QMargins &cm) : minimumSize(w->minimumSize()), - maximumSize(w->maximumSize()) + maximumSize(w->maximumSize()), + customMargins(cm) { } @@ -603,6 +621,33 @@ QMargins QWindowsGeometryHint::frame(DWORD style, DWORD exStyle) return result; } +bool QWindowsGeometryHint::handleCalculateSize(const QMargins &customMargins, const MSG &msg, LRESULT *result) +{ +#ifndef Q_OS_WINCE + // NCCALCSIZE_PARAMS structure if wParam==TRUE + if (!msg.wParam || customMargins.isNull()) + return false; + *result = DefWindowProc(msg.hwnd, msg.message, msg.wParam, msg.lParam); + NCCALCSIZE_PARAMS *ncp = reinterpret_cast<NCCALCSIZE_PARAMS *>(msg.lParam); + const RECT oldClientArea = ncp->rgrc[0]; + ncp->rgrc[0].left += customMargins.left(); + ncp->rgrc[0].top += customMargins.top(); + ncp->rgrc[0].right -= customMargins.right(); + ncp->rgrc[0].bottom -= customMargins.bottom(); + result = 0; + if (QWindowsContext::verboseWindows) + qDebug() << __FUNCTION__ << oldClientArea << '+' << customMargins << "-->" + << ncp->rgrc[0] << ' ' << ncp->rgrc[1] << ' ' << ncp->rgrc[2] + << ' ' << ncp->lppos->cx << ',' << ncp->lppos->cy; + return true; +#else + Q_UNUSED(customMargins) + Q_UNUSED(msg) + Q_UNUSED(result) + return false; +#endif +} + #ifndef Q_OS_WINCE void QWindowsGeometryHint::applyToMinMaxInfo(HWND hwnd, MINMAXINFO *mmi) const { @@ -619,8 +664,8 @@ void QWindowsGeometryHint::applyToMinMaxInfo(DWORD style, DWORD exStyle, MINMAXI << " in " << *mmi; const QMargins margins = QWindowsGeometryHint::frame(style, exStyle); - const int frameWidth = margins.left() + margins.right(); - const int frameHeight = margins.top() + margins.bottom(); + const int frameWidth = margins.left() + margins.right() + customMargins.left() + customMargins.right(); + const int frameHeight = margins.top() + margins.bottom() + customMargins.top() + customMargins.bottom(); if (minimumSize.width() > 0) mmi->ptMinTrackSize.x = minimumSize.width() + frameWidth; if (minimumSize.height() > 0) @@ -669,10 +714,11 @@ bool QWindowsGeometryHint::positionIncludesFrame(const QWindow *w) QWindowCreationContext::QWindowCreationContext(const QWindow *w, const QRect &geometry, + const QMargins &cm, DWORD style_, DWORD exStyle_) : - geometryHint(w), style(style_), exStyle(exStyle_), + geometryHint(w, cm), style(style_), exStyle(exStyle_), requestedGeometry(geometry), obtainedGeometry(geometry), - margins(QWindowsGeometryHint::frame(style, exStyle)), + margins(QWindowsGeometryHint::frame(style, exStyle)), customMargins(cm), frameX(CW_USEDEFAULT), frameY(CW_USEDEFAULT), frameWidth(CW_USEDEFAULT), frameHeight(CW_USEDEFAULT) { @@ -683,14 +729,16 @@ QWindowCreationContext::QWindowCreationContext(const QWindow *w, if (geometry.isValid()) { frameX = geometry.x(); frameY = geometry.y(); - frameWidth = margins.left() + geometry.width() + margins.right(); - frameHeight = margins.top() + geometry.height() + margins.bottom(); + const QMargins effectiveMargins = margins + customMargins; + frameWidth = effectiveMargins.left() + geometry.width() + effectiveMargins.right(); + frameHeight = effectiveMargins.top() + geometry.height() + effectiveMargins.bottom(); const bool isDefaultPosition = !frameX && !frameY && w->isTopLevel(); if (!QWindowsGeometryHint::positionIncludesFrame(w) && !isDefaultPosition) { - frameX -= margins.left(); - frameY -= margins.top(); + frameX -= effectiveMargins.left(); + frameY -= effectiveMargins.top(); } } + if (QWindowsContext::verboseWindows) qDebug().nospace() << __FUNCTION__ << ' ' << w << geometry @@ -698,7 +746,8 @@ QWindowCreationContext::QWindowCreationContext(const QWindow *w, << " frame: " << frameWidth << 'x' << frameHeight << '+' << frameX << '+' << frameY << " min" << geometryHint.minimumSize - << " max" << geometryHint.maximumSize; + << " max" << geometryHint.maximumSize + << " custom margins " << customMargins; } /*! @@ -730,9 +779,6 @@ QWindowsWindow::QWindowsWindow(QWindow *aWindow, const WindowData &data) : m_hdc(0), m_windowState(Qt::WindowNoState), m_opacity(1.0), -#ifndef QT_NO_CURSOR - m_cursor(QWindowsScreen::screenOf(aWindow)->windowsCursor()->standardWindowCursor()), -#endif m_dropTarget(0), m_savedStyle(0), m_format(aWindow->format()), @@ -745,11 +791,16 @@ QWindowsWindow::QWindowsWindow(QWindow *aWindow, const WindowData &data) : m_iconSmall(0), m_iconBig(0) { + // Clear the creation context as the window can be found in QWindowsContext's map. + QWindowsContext::instance()->setWindowCreationContext(QSharedPointer<QWindowCreationContext>()); + QWindowsContext::instance()->addWindow(m_data.hwnd, this); + const Qt::WindowType type = aWindow->type(); + if (type == Qt::Desktop) + return; // No further handling for Qt::Desktop if (aWindow->surfaceType() == QWindow::OpenGLSurface) setFlag(OpenGLSurface); - QWindowsContext::instance()->addWindow(m_data.hwnd, this); if (aWindow->isTopLevel()) { - switch (aWindow->type()) { + switch (type) { case Qt::Window: case Qt::Dialog: case Qt::Sheet: @@ -763,8 +814,13 @@ QWindowsWindow::QWindowsWindow(QWindow *aWindow, const WindowData &data) : } } #ifndef Q_OS_WINCE - if (QWindowsContext::instance()->systemInfo() & QWindowsContext::SI_SupportsTouch) - QWindowsContext::user32dll.registerTouchWindow(m_data.hwnd, 0); + if (QWindowsContext::instance()->systemInfo() & QWindowsContext::SI_SupportsTouch) { + if (QWindowsContext::user32dll.registerTouchWindow(m_data.hwnd, 0)) { + setFlag(TouchRegistered); + } else { + qErrnoWarning("RegisterTouchWindow() failed for window '%s'.", qPrintable(aWindow->objectName())); + } + } #endif // !Q_OS_WINCE setWindowState(aWindow->windowState()); const qreal opacity = qt_window_private(aWindow)->opacity; @@ -775,7 +831,8 @@ QWindowsWindow::QWindowsWindow(QWindow *aWindow, const WindowData &data) : QWindowsWindow::~QWindowsWindow() { #ifndef Q_OS_WINCE - if (QWindowsContext::instance()->systemInfo() & QWindowsContext::SI_SupportsTouch) + QWindowSystemInterface::flushWindowSystemEvents(); + if (testFlag(TouchRegistered)) QWindowsContext::user32dll.unregisterTouchWindow(m_data.hwnd); #endif // !Q_OS_WINCE destroyWindow(); @@ -872,8 +929,9 @@ QWindowsWindow::WindowData { WindowCreationData creationData; creationData.fromWindow(w, parameters.flags); - WindowData result = creationData.create(w, parameters.geometry, title); - creationData.initialize(result.hwnd, false, 1); + WindowData result = creationData.create(w, parameters, title); + // Force WM_NCCALCSIZE (with wParam=1) via SWP_FRAMECHANGED for custom margin. + creationData.initialize(result.hwnd, !parameters.customMargins.isNull(), 1); return result; } @@ -1060,7 +1118,7 @@ void QWindowsWindow::setGeometry(const QRect &rectIn) const QSize newSize = rect.size(); // Check on hint. if (newSize != oldSize) { - const QWindowsGeometryHint hint(window()); + const QWindowsGeometryHint hint(window(), m_data.customMargins); if (!hint.validSize(newSize)) { qWarning("%s: Attempt to set a size (%dx%d) violating the constraints" "(%dx%d - %dx%d) on window '%s'.", __FUNCTION__, @@ -1078,14 +1136,19 @@ void QWindowsWindow::setGeometry(const QRect &rectIn) if (m_data.geometry != rect) { qWarning("%s: Unable to set geometry %dx%d+%d+%d on '%s'." " Resulting geometry: %dx%d+%d+%d " - "(frame: %d, %d, %d, %d).", + "(frame: %d, %d, %d, %d, custom margin: %d, %d, %d, %d" + ", minimum size: %dx%d, maximum size: %dx%d).", __FUNCTION__, rect.width(), rect.height(), rect.x(), rect.y(), qPrintable(window()->objectName()), m_data.geometry.width(), m_data.geometry.height(), m_data.geometry.x(), m_data.geometry.y(), m_data.frame.left(), m_data.frame.top(), - m_data.frame.right(), m_data.frame.bottom()); + m_data.frame.right(), m_data.frame.bottom(), + m_data.customMargins.left(), m_data.customMargins.top(), + m_data.customMargins.right(), m_data.customMargins.bottom(), + window()->minimumWidth(), window()->minimumHeight(), + window()->maximumWidth(), window()->maximumHeight()); } } else { QPlatformWindow::setGeometry(rect); @@ -1163,7 +1226,7 @@ QRect QWindowsWindow::frameGeometry_sys() const QRect QWindowsWindow::geometry_sys() const { - return frameGeometry_sys() - frameMargins(); + return frameGeometry_sys().marginsRemoved(frameMargins()); } /*! @@ -1490,7 +1553,7 @@ QMargins QWindowsWindow::frameMargins() const m_data.frame = QWindowsGeometryHint::frame(style(), exStyle()); clearFlag(FrameDirty); } - return m_data.frame; + return m_data.frame + m_data.customMargins; } void QWindowsWindow::setOpacity(qreal level) @@ -1648,13 +1711,23 @@ void QWindowsWindow::setFrameStrutEventsEnabled(bool enabled) #ifndef Q_OS_WINCE // maybe available on some SDKs revisit WM_GETMINMAXINFO void QWindowsWindow::getSizeHints(MINMAXINFO *mmi) const { - const QWindowsGeometryHint hint(window()); + const QWindowsGeometryHint hint(window(), m_data.customMargins); hint.applyToMinMaxInfo(m_data.hwnd, mmi); if (QWindowsContext::verboseWindows) qDebug() << __FUNCTION__ << window() << *mmi; } #endif // !Q_OS_WINCE +// Return the default cursor (Arrow) from QWindowsCursor's cache. +static inline QWindowsWindowCursor defaultCursor(const QWindow *w) +{ + if (QScreen *screen = w->screen()) + if (const QPlatformScreen *platformScreen = screen->handle()) + if (QPlatformCursor *cursor = platformScreen->cursor()) + return static_cast<QWindowsCursor *>(cursor)->standardWindowCursor(Qt::ArrowCursor); + return QWindowsWindowCursor(Qt::ArrowCursor); +} + /*! \brief Applies to cursor property set on the window to the global cursor. @@ -1664,20 +1737,45 @@ void QWindowsWindow::getSizeHints(MINMAXINFO *mmi) const void QWindowsWindow::applyCursor() { #ifndef QT_NO_CURSOR - SetCursor(m_cursor.handle()); + if (m_cursor.isNull()) { // Recurse up to parent with non-null cursor. Set default for toplevel. + if (const QWindow *p = window()->parent()) { + QWindowsWindow::baseWindowOf(p)->applyCursor(); + } else { + SetCursor(defaultCursor(window()).handle()); + } + } else { + SetCursor(m_cursor.handle()); + } #endif } +// Check whether to apply a new cursor. Either the window in question is +// currently under mouse, or it is the parent of the window under mouse and +// there is no other window with an explicitly set cursor in-between. +static inline bool applyNewCursor(const QWindow *w) +{ + const QWindow *underMouse = QWindowsContext::instance()->windowUnderMouse(); + if (underMouse == w) + return true; + for (const QWindow *p = underMouse; p ; p = p->parent()) { + if (p == w) + return true; + if (!QWindowsWindow::baseWindowOf(p)->cursor().isNull()) + return false; + } + return false; +} + void QWindowsWindow::setCursor(const QWindowsWindowCursor &c) { #ifndef QT_NO_CURSOR if (c.handle() != m_cursor.handle()) { - const bool underMouse = QWindowsContext::instance()->windowUnderMouse() == window(); + const bool apply = applyNewCursor(window()); if (QWindowsContext::verboseWindows) qDebug() << window() << __FUNCTION__ << "Shape=" << c.cursor().shape() - << " isWUM=" << underMouse; + << " doApply=" << apply; m_cursor = c; - if (underMouse) + if (apply) applyCursor(); } #endif @@ -1850,4 +1948,32 @@ void QWindowsWindow::setWindowIcon(const QIcon &icon) } } +/*! + \brief Sets custom margins to be added to the default margins determined by + the windows style in the handling of the WM_NCCALCSIZE message. + + This is currently used to give the Aero-style QWizard a smaller top margin. + The property can be set using QPlatformNativeInterface::setWindowProperty() or, + before platform window creation, by setting a dynamic property + on the QWindow (see QWindowsIntegration::createPlatformWindow()). +*/ + +void QWindowsWindow::setCustomMargins(const QMargins &newCustomMargins) +{ + if (newCustomMargins != m_data.customMargins) { + const QMargins oldCustomMargins = m_data.customMargins; + m_data.customMargins = newCustomMargins; + // Re-trigger WM_NCALCSIZE with wParam=1 by passing SWP_FRAMECHANGED + const QRect currentFrameGeometry = frameGeometry_sys(); + const QPoint topLeft = currentFrameGeometry.topLeft(); + QRect newFrame = currentFrameGeometry.marginsRemoved(oldCustomMargins) + m_data.customMargins; + newFrame.moveTo(topLeft); + setFlag(FrameDirty); + if (QWindowsContext::verboseWindows) + qDebug() << __FUNCTION__ << oldCustomMargins << "->" << newCustomMargins + << currentFrameGeometry << "->" << newFrame; + SetWindowPos(m_data.hwnd, 0, newFrame.x(), newFrame.y(), newFrame.width(), newFrame.height(), SWP_NOZORDER | SWP_FRAMECHANGED); + } +} + QT_END_NAMESPACE diff --git a/src/plugins/platforms/windows/qwindowswindow.h b/src/plugins/platforms/windows/qwindowswindow.h index f3b480b0af..1148440f05 100644 --- a/src/plugins/platforms/windows/qwindowswindow.h +++ b/src/plugins/platforms/windows/qwindowswindow.h @@ -67,8 +67,9 @@ class QWindowsEGLStaticContext; struct QWindowsGeometryHint { QWindowsGeometryHint() {} - explicit QWindowsGeometryHint(const QWindow *w); + explicit QWindowsGeometryHint(const QWindow *w, const QMargins &customMargins); static QMargins frame(DWORD style, DWORD exStyle); + static bool handleCalculateSize(const QMargins &customMargins, const MSG &msg, LRESULT *result); #ifndef Q_OS_WINCE //MinMax maybe define struct if not available void applyToMinMaxInfo(DWORD style, DWORD exStyle, MINMAXINFO *mmi) const; void applyToMinMaxInfo(HWND hwnd, MINMAXINFO *mmi) const; @@ -84,11 +85,13 @@ struct QWindowsGeometryHint QSize minimumSize; QSize maximumSize; + QMargins customMargins; }; struct QWindowCreationContext { QWindowCreationContext(const QWindow *w, const QRect &r, + const QMargins &customMargins, DWORD style, DWORD exStyle); #ifndef Q_OS_WINCE //MinMax maybe define struct if not available void applyToMinMaxInfo(MINMAXINFO *mmi) const @@ -101,6 +104,7 @@ struct QWindowCreationContext QRect requestedGeometry; QRect obtainedGeometry; QMargins margins; + QMargins customMargins; // User-defined, additional frame for WM_NCCALCSIZE int frameX; // Passed on to CreateWindowEx(), including frame. int frameY; int frameWidth; @@ -127,7 +131,8 @@ public: FrameStrutEventsEnabled = 0x200, SynchronousGeometryChangeEvent = 0x400, WithinSetStyle = 0x800, - WithinDestroy = 0x1000 + WithinDestroy = 0x1000, + TouchRegistered = 0x2000 }; struct WindowData @@ -137,6 +142,7 @@ public: Qt::WindowFlags flags; QRect geometry; QMargins frame; // Do not use directly for windows, see FrameDirty. + QMargins customMargins; // User-defined, additional frame for NCCALCSIZE HWND hwnd; bool embedded; @@ -191,6 +197,9 @@ public: void setFrameStrutEventsEnabled(bool enabled); bool frameStrutEventsEnabled() const { return testFlag(FrameStrutEventsEnabled); } + QMargins customMargins() const { return m_data.customMargins; } + void setCustomMargins(const QMargins &m); + #ifdef QT_OPENGL_ES_2 EGLSurface eglSurfaceHandle() const { return m_eglSurface;} EGLSurface ensureEglSurfaceHandle(const QWindowsEGLStaticContextPtr &staticContext, EGLConfig config); @@ -290,17 +299,6 @@ private: HICON m_iconBig; }; -// Conveniences for window frames. -inline QRect operator+(const QRect &r, const QMargins &m) -{ - return r.adjusted(-m.left(), -m.top(), m.right(), m.bottom()); -} - -inline QRect operator-(const QRect &r, const QMargins &m) -{ - return r.adjusted(m.left(), m.top(), -m.right(), -m.bottom()); -} - // Debug QDebug operator<<(QDebug d, const RECT &r); #ifndef Q_OS_WINCE // maybe available on some SDKs revisit WM_GETMINMAXINFO/WM_NCCALCSIZE @@ -371,4 +369,6 @@ inline void QWindowsWindow::destroyIcon() QT_END_NAMESPACE +Q_DECLARE_METATYPE(QMargins) + #endif // QWINDOWSWINDOW_H diff --git a/src/plugins/platforms/windows/windows.pro b/src/plugins/platforms/windows/windows.pro index ff162e2d41..3aa9caaa0f 100644 --- a/src/plugins/platforms/windows/windows.pro +++ b/src/plugins/platforms/windows/windows.pro @@ -102,12 +102,8 @@ contains(QT_CONFIG, opengles2) { } } -# Enable access to HB_Face in harfbuzz includes included by qfontengine_p.h. -DEFINES *= QT_COMPILES_IN_HARFBUZZ - contains(QT_CONFIG, freetype) { DEFINES *= QT_NO_FONTCONFIG - DEFINES *= QT_COMPILES_IN_HARFBUZZ QT_FREETYPE_DIR = $$QT_SOURCE_TREE/src/3rdparty/freetype HEADERS += \ |