diff options
Diffstat (limited to 'src/plugins')
31 files changed, 744 insertions, 156 deletions
diff --git a/src/plugins/accessible/widgets/itemviews.cpp b/src/plugins/accessible/widgets/itemviews.cpp index 649863ed84..0aeff6e1a3 100644 --- a/src/plugins/accessible/widgets/itemviews.cpp +++ b/src/plugins/accessible/widgets/itemviews.cpp @@ -75,7 +75,7 @@ QAbstractItemView *QAccessibleTable::view() const int QAccessibleTable::logicalIndex(const QModelIndex &index) const { - if (!index.isValid()) + if (!view()->model() || !index.isValid()) return -1; int vHeader = verticalHeader() ? 1 : 0; int hHeader = horizontalHeader() ? 1 : 0; @@ -85,7 +85,7 @@ int QAccessibleTable::logicalIndex(const QModelIndex &index) const QAccessibleInterface *QAccessibleTable::childFromLogical(int logicalIndex) const { - if (!isValid()) + if (!view()->model()) return 0; logicalIndex--; // one based counting ftw @@ -179,6 +179,8 @@ QAccessibleTableCell *QAccessibleTable::cell(const QModelIndex &index) const QAccessibleInterface *QAccessibleTable::cellAt(int row, int column) const { + if (!view()->model()) + return 0; Q_ASSERT(role() != QAccessible::Tree); QModelIndex index = view()->model()->index(row, column, view()->rootIndex()); if (!index.isValid()) { @@ -195,42 +197,58 @@ QAccessibleInterface *QAccessibleTable::caption() const QString QAccessibleTable::columnDescription(int column) const { + if (!view()->model()) + return QString(); return view()->model()->headerData(column, Qt::Horizontal).toString(); } int QAccessibleTable::columnCount() const { + if (!view()->model()) + return 0; return view()->model()->columnCount(); } int QAccessibleTable::rowCount() const { + if (!view()->model()) + return 0; return view()->model()->rowCount(); } int QAccessibleTable::selectedCellCount() const { + if (!view()->selectionModel()) + return 0; return view()->selectionModel()->selectedIndexes().count(); } int QAccessibleTable::selectedColumnCount() const { + if (!view()->selectionModel()) + return 0; return view()->selectionModel()->selectedColumns().count(); } int QAccessibleTable::selectedRowCount() const { + if (!view()->selectionModel()) + return 0; return view()->selectionModel()->selectedRows().count(); } QString QAccessibleTable::rowDescription(int row) const { + if (!view()->model()) + return QString(); return view()->model()->headerData(row, Qt::Vertical).toString(); } QList<QAccessibleInterface *> QAccessibleTable::selectedCells() const { QList<QAccessibleInterface*> cells; + if (!view()->selectionModel()) + return cells; Q_FOREACH (const QModelIndex &index, view()->selectionModel()->selectedIndexes()) { cells.append(cell(index)); } @@ -239,6 +257,8 @@ QList<QAccessibleInterface *> QAccessibleTable::selectedCells() const QList<int> QAccessibleTable::selectedColumns() const { + if (!view()->selectionModel()) + return QList<int>(); QList<int> columns; Q_FOREACH (const QModelIndex &index, view()->selectionModel()->selectedColumns()) { columns.append(index.column()); @@ -248,6 +268,8 @@ QList<int> QAccessibleTable::selectedColumns() const QList<int> QAccessibleTable::selectedRows() const { + if (!view()->selectionModel()) + return QList<int>(); QList<int> rows; Q_FOREACH (const QModelIndex &index, view()->selectionModel()->selectedRows()) { rows.append(index.row()); @@ -262,16 +284,22 @@ QAccessibleInterface *QAccessibleTable::summary() const bool QAccessibleTable::isColumnSelected(int column) const { + if (!view()->selectionModel()) + return false; return view()->selectionModel()->isColumnSelected(column, QModelIndex()); } bool QAccessibleTable::isRowSelected(int row) const { + if (!view()->selectionModel()) + return false; return view()->selectionModel()->isRowSelected(row, QModelIndex()); } bool QAccessibleTable::selectRow(int row) { + if (!view()->model() || !view()->selectionModel()) + return false; QModelIndex index = view()->model()->index(row, 0, view()->rootIndex()); if (!index.isValid() || view()->selectionMode() & QAbstractItemView::NoSelection) return false; @@ -281,6 +309,8 @@ bool QAccessibleTable::selectRow(int row) bool QAccessibleTable::selectColumn(int column) { + if (!view()->model() || !view()->selectionModel()) + return false; QModelIndex index = view()->model()->index(0, column, view()->rootIndex()); if (!index.isValid() || view()->selectionMode() & QAbstractItemView::NoSelection) return false; @@ -290,6 +320,8 @@ bool QAccessibleTable::selectColumn(int column) bool QAccessibleTable::unselectRow(int row) { + if (!view()->model() || !view()->selectionModel()) + return false; QModelIndex index = view()->model()->index(row, 0, view()->rootIndex()); if (!index.isValid() || view()->selectionMode() & QAbstractItemView::NoSelection) return false; @@ -299,6 +331,8 @@ bool QAccessibleTable::unselectRow(int row) bool QAccessibleTable::unselectColumn(int column) { + if (!view()->model() || !view()->selectionModel()) + return false; QModelIndex index = view()->model()->index(0, column, view()->rootIndex()); if (!index.isValid() || view()->selectionMode() & QAbstractItemView::NoSelection) return false; @@ -340,6 +374,8 @@ int QAccessibleTable::childCount() const int QAccessibleTable::indexOfChild(const QAccessibleInterface *iface) const { + if (!view()->model()) + return -1; Q_ASSERT(iface->role() != QAccessible::TreeItem); // should be handled by tree class if (iface->role() == QAccessible::Cell || iface->role() == QAccessible::ListItem) { const QAccessibleTableCell* cell = static_cast<const QAccessibleTableCell*>(iface); @@ -403,7 +439,7 @@ void *QAccessibleTable::interface_cast(QAccessible::InterfaceType t) QModelIndex QAccessibleTree::indexFromLogical(int row, int column) const { - if (!isValid()) + if (!isValid() || !view()->model()) return QModelIndex(); const QTreeView *treeView = qobject_cast<const QTreeView*>(view()); @@ -421,6 +457,8 @@ QModelIndex QAccessibleTree::indexFromLogical(int row, int column) const QAccessibleInterface *QAccessibleTree::childAt(int x, int y) const { + if (!view()->model()) + return 0; QPoint viewportOffset = view()->viewport()->mapTo(view(), QPoint(0,0)); QPoint indexPosition = view()->mapFromGlobal(QPoint(x, y) - viewportOffset); @@ -451,7 +489,8 @@ int QAccessibleTree::childCount() const QAccessibleInterface *QAccessibleTree::child(int index) const { - Q_ASSERT(index >= 0); + if ((index < 0) || (!view()->model())) + return 0; int hHeader = horizontalHeader() ? 1 : 0; if (hHeader) { @@ -480,6 +519,8 @@ int QAccessibleTree::rowCount() const int QAccessibleTree::indexOfChild(const QAccessibleInterface *iface) const { + if (!view()->model()) + return -1; if (iface->role() == QAccessible::TreeItem) { const QAccessibleTableCell* cell = static_cast<const QAccessibleTableCell*>(iface); const QTreeView *treeView = qobject_cast<const QTreeView*>(view()); @@ -520,12 +561,16 @@ QString QAccessibleTree::rowDescription(int) const bool QAccessibleTree::isRowSelected(int row) const { + if (!view()->selectionModel()) + return false; QModelIndex index = indexFromLogical(row); return view()->selectionModel()->isRowSelected(index.row(), index.parent()); } bool QAccessibleTree::selectRow(int row) { + if (!view()->selectionModel()) + return false; QModelIndex index = indexFromLogical(row); if (!index.isValid() || view()->selectionMode() & QAbstractItemView::NoSelection) return false; diff --git a/src/plugins/platforms/cocoa/qcocoadrag.mm b/src/plugins/platforms/cocoa/qcocoadrag.mm index d98c49a1ce..67881d8680 100644 --- a/src/plugins/platforms/cocoa/qcocoadrag.mm +++ b/src/plugins/platforms/cocoa/qcocoadrag.mm @@ -119,7 +119,11 @@ Qt::DropAction QCocoaDrag::drag(QDrag *o) m_drag = o; m_executed_drop_action = Qt::IgnoreAction; - NSImage *nsimage = static_cast<NSImage *>(qt_mac_create_nsimage(m_drag->pixmap())); + QPixmap pm = m_drag->pixmap(); + if (pm.isNull()) + pm = defaultPixmap(); + + NSImage *nsimage = static_cast<NSImage *>(qt_mac_create_nsimage(pm)); QMacPasteboard dragBoard((CFStringRef) NSDragPboard, QMacPasteboardMime::MIME_DND); m_drag->mimeData()->setData(QLatin1String("application/x-qt-mime-type-name"), QByteArray("dummy")); diff --git a/src/plugins/platforms/cocoa/qcocoahelpers.h b/src/plugins/platforms/cocoa/qcocoahelpers.h index 050a2e69d1..45c35cccbf 100644 --- a/src/plugins/platforms/cocoa/qcocoahelpers.h +++ b/src/plugins/platforms/cocoa/qcocoahelpers.h @@ -73,9 +73,12 @@ NSImage *qt_mac_cgimage_to_nsimage(CGImageRef iamge); NSImage *qt_mac_create_nsimage(const QPixmap &pm); NSSize qt_mac_toNSSize(const QSize &qtSize); +NSRect qt_mac_toNSRect(const QRect &rect); +QRect qt_mac_toQRect(const NSRect &rect); QColor qt_mac_toQColor(const NSColor *color); + // Creates a mutable shape, it's the caller's responsibility to release. HIMutableShapeRef qt_mac_QRegionToHIMutableShape(const QRegion ®ion); diff --git a/src/plugins/platforms/cocoa/qcocoahelpers.mm b/src/plugins/platforms/cocoa/qcocoahelpers.mm index 8841a65844..bd89f26fca 100644 --- a/src/plugins/platforms/cocoa/qcocoahelpers.mm +++ b/src/plugins/platforms/cocoa/qcocoahelpers.mm @@ -135,7 +135,10 @@ NSImage *qt_mac_cgimage_to_nsimage(CGImageRef image) NSImage *qt_mac_create_nsimage(const QPixmap &pm) { QImage image = pm.toImage(); - return qt_mac_cgimage_to_nsimage(qt_mac_image_to_cgimage(image)); + CGImageRef cgImage = qt_mac_image_to_cgimage(image); + NSImage *nsImage = qt_mac_cgimage_to_nsimage(cgImage); + CGImageRelease(cgImage); + return nsImage; } HIMutableShapeRef qt_mac_QRegionToHIMutableShape(const QRegion ®ion) @@ -159,6 +162,16 @@ NSSize qt_mac_toNSSize(const QSize &qtSize) return NSMakeSize(qtSize.width(), qtSize.height()); } +NSRect qt_mac_toNSRect(const QRect &rect) +{ + return NSMakeRect(rect.x(), rect.y(), rect.width(), rect.height()); +} + +QRect qt_mac_toQRect(const NSRect &rect) +{ + return QRect(rect.origin.x, rect.origin.y, rect.size.width, rect.size.height); +} + QColor qt_mac_toQColor(const NSColor *color) { QColor qtColor; diff --git a/src/plugins/platforms/cocoa/qcocoamenu.mm b/src/plugins/platforms/cocoa/qcocoamenu.mm index e4baaab3d3..4d35b3202e 100644 --- a/src/plugins/platforms/cocoa/qcocoamenu.mm +++ b/src/plugins/platforms/cocoa/qcocoamenu.mm @@ -218,10 +218,9 @@ void QCocoaMenu::syncMenuItem(QPlatformMenuItem *menuItem) NSMenuItem *oldItem = [m_nativeMenu itemWithTag:(NSInteger) cocoaItem]; if (cocoaItem->sync() != oldItem) { - // native item was changed for some reason - if (!wasMerged) { + // native item was changed for some reason + if (!wasMerged && oldItem) [m_nativeMenu removeItem:oldItem]; - } QCocoaMenuItem* beforeItem = itemOrNull(m_menuItems.indexOf(cocoaItem) + 1); insertNative(cocoaItem, beforeItem); diff --git a/src/plugins/platforms/cocoa/qcocoatheme.h b/src/plugins/platforms/cocoa/qcocoatheme.h index a747a82d09..0ff160957f 100644 --- a/src/plugins/platforms/cocoa/qcocoatheme.h +++ b/src/plugins/platforms/cocoa/qcocoatheme.h @@ -67,6 +67,8 @@ public: const QPalette *palette(Palette type = SystemPalette) const; const QFont *font(Font type = SystemFont) const; + QPixmap standardPixmap(StandardPixmap sp, const QSizeF &size) const; + QPixmap fileIconPixmap(const QFileInfo &fileInfo, const QSizeF &size) const; QVariant themeHint(ThemeHint hint) const; diff --git a/src/plugins/platforms/cocoa/qcocoatheme.mm b/src/plugins/platforms/cocoa/qcocoatheme.mm index ddb550dd5f..967d65faec 100644 --- a/src/plugins/platforms/cocoa/qcocoatheme.mm +++ b/src/plugins/platforms/cocoa/qcocoatheme.mm @@ -54,7 +54,9 @@ #include "qcocoamenu.h" #include "qcocoamenubar.h" +#include <QtCore/qfileinfo.h> #include <QtGui/private/qguiapplication_p.h> +#include <QtGui/qpainter.h> #include <qpa/qplatformintegration.h> #include <qpa/qplatformnativeinterface.h> @@ -135,6 +137,143 @@ const QFont *QCocoaTheme::font(Font type) const return m_fonts.value(type, 0); } +// Defined in qpaintengine_mac.mm +extern CGContextRef qt_mac_cg_context(const QPaintDevice *pdev); + +//! \internal +QPixmap qt_mac_convert_iconref(const IconRef icon, int width, int height) +{ + QPixmap ret(width, height); + ret.fill(QColor(0, 0, 0, 0)); + + CGRect rect = CGRectMake(0, 0, width, height); + + CGContextRef ctx = qt_mac_cg_context(&ret); + CGAffineTransform old_xform = CGContextGetCTM(ctx); + CGContextConcatCTM(ctx, CGAffineTransformInvert(old_xform)); + CGContextConcatCTM(ctx, CGAffineTransformIdentity); + + ::RGBColor b; + b.blue = b.green = b.red = 255*255; + PlotIconRefInContext(ctx, &rect, kAlignNone, kTransformNone, &b, kPlotIconRefNormalFlags, icon); + CGContextRelease(ctx); + return ret; +} + +QPixmap QCocoaTheme::standardPixmap(StandardPixmap sp, const QSizeF &size) const +{ + OSType iconType = 0; + switch (sp) { + case MessageBoxQuestion: + iconType = kQuestionMarkIcon; + break; + case MessageBoxInformation: + iconType = kAlertNoteIcon; + break; + case MessageBoxWarning: + iconType = kAlertCautionIcon; + break; + case MessageBoxCritical: + iconType = kAlertStopIcon; + break; + case DesktopIcon: + iconType = kDesktopIcon; + break; + case TrashIcon: + iconType = kTrashIcon; + break; + case ComputerIcon: + iconType = kComputerIcon; + break; + case DriveFDIcon: + iconType = kGenericFloppyIcon; + break; + case DriveHDIcon: + iconType = kGenericHardDiskIcon; + break; + case DriveCDIcon: + case DriveDVDIcon: + iconType = kGenericCDROMIcon; + break; + case DriveNetIcon: + iconType = kGenericNetworkIcon; + break; + case DirOpenIcon: + iconType = kOpenFolderIcon; + break; + case DirClosedIcon: + case DirLinkIcon: + iconType = kGenericFolderIcon; + break; + case FileLinkIcon: + case FileIcon: + iconType = kGenericDocumentIcon; + break; + default: + break; + } + if (iconType != 0) { + QPixmap pixmap; + IconRef icon; + IconRef overlayIcon = 0; + if (iconType != kGenericApplicationIcon) { + GetIconRef(kOnSystemDisk, kSystemIconsCreator, iconType, &icon); + } else { + FSRef fsRef; + ProcessSerialNumber psn = { 0, kCurrentProcess }; + GetProcessBundleLocation(&psn, &fsRef); + GetIconRefFromFileInfo(&fsRef, 0, 0, 0, 0, kIconServicesNormalUsageFlag, &icon, 0); + if (sp == MessageBoxCritical) { + overlayIcon = icon; + GetIconRef(kOnSystemDisk, kSystemIconsCreator, kAlertCautionIcon, &icon); + } + } + + if (icon) { + pixmap = qt_mac_convert_iconref(icon, size.width(), size.height()); + ReleaseIconRef(icon); + } + + if (overlayIcon) { + QSizeF littleSize = size / 2; + QPixmap overlayPix = qt_mac_convert_iconref(overlayIcon, littleSize.width(), littleSize.height()); + QPainter painter(&pixmap); + painter.drawPixmap(littleSize.width(), littleSize.height(), overlayPix); + ReleaseIconRef(overlayIcon); + } + + return pixmap; + } + + return QPlatformTheme::standardPixmap(sp, size); +} + +QPixmap QCocoaTheme::fileIconPixmap(const QFileInfo &fileInfo, const QSizeF &size) const +{ + FSRef macRef; + OSStatus status = FSPathMakeRef(reinterpret_cast<const UInt8*>(fileInfo.canonicalFilePath().toUtf8().constData()), + &macRef, 0); + if (status != noErr) + return QPixmap(); + FSCatalogInfo info; + HFSUniStr255 macName; + status = FSGetCatalogInfo(&macRef, kIconServicesCatalogInfoMask, &info, &macName, 0, 0); + if (status != noErr) + return QPixmap(); + IconRef iconRef; + SInt16 iconLabel; + status = GetIconRefFromFileInfo(&macRef, macName.length, macName.unicode, + kIconServicesCatalogInfoMask, &info, kIconServicesNormalUsageFlag, + &iconRef, &iconLabel); + if (status != noErr) + return QPixmap(); + + QPixmap pixmap = qt_mac_convert_iconref(iconRef, size.width(), size.height()); + ReleaseIconRef(iconRef); + + return pixmap; +} + QVariant QCocoaTheme::themeHint(ThemeHint hint) const { switch (hint) { @@ -146,6 +285,11 @@ QVariant QCocoaTheme::themeHint(ThemeHint hint) const return QVariant(int(MacKeyboardScheme)); case TabAllWidgets: return QVariant(bool([[NSApplication sharedApplication] isFullKeyboardAccessEnabled])); + case IconPixmapSizes: { + QList<int> sizes; + sizes << 16 << 32 << 64 << 128; + return QVariant::fromValue(sizes); + } default: break; } diff --git a/src/plugins/platforms/cocoa/qcocoawindow.h b/src/plugins/platforms/cocoa/qcocoawindow.h index 014db378e7..d5dbe58de9 100644 --- a/src/plugins/platforms/cocoa/qcocoawindow.h +++ b/src/plugins/platforms/cocoa/qcocoawindow.h @@ -99,9 +99,10 @@ public: void setCocoaGeometry(const QRect &rect); void setVisible(bool visible); void setWindowFlags(Qt::WindowFlags flags); - Qt::WindowState setWindowState(Qt::WindowState state); + void setWindowState(Qt::WindowState state); void setWindowTitle(const QString &title); void setWindowFilePath(const QString &filePath); + void setWindowIcon(const QIcon &icon); void raise(); void lower(); void propagateSizeHints(); diff --git a/src/plugins/platforms/cocoa/qcocoawindow.mm b/src/plugins/platforms/cocoa/qcocoawindow.mm index f4a4936c28..b9ad35600e 100644 --- a/src/plugins/platforms/cocoa/qcocoawindow.mm +++ b/src/plugins/platforms/cocoa/qcocoawindow.mm @@ -400,12 +400,10 @@ void QCocoaWindow::setWindowFlags(Qt::WindowFlags flags) m_windowFlags = flags; } -Qt::WindowState QCocoaWindow::setWindowState(Qt::WindowState state) +void QCocoaWindow::setWindowState(Qt::WindowState state) { if ([m_nsWindow isVisible]) syncWindowState(state); // Window state set for hidden windows take effect when show() is called. - - return state; } void QCocoaWindow::setWindowTitle(const QString &title) @@ -429,6 +427,26 @@ void QCocoaWindow::setWindowFilePath(const QString &filePath) [m_nsWindow setRepresentedFilename: fi.exists() ? QCFString::toNSString(filePath) : @""]; } +void QCocoaWindow::setWindowIcon(const QIcon &icon) +{ + QCocoaAutoReleasePool pool; + + NSButton *iconButton = [m_nsWindow standardWindowButton:NSWindowDocumentIconButton]; + if (iconButton == nil) { + NSString *title = QCFString::toNSString(window()->windowTitle()); + [m_nsWindow setRepresentedURL:[NSURL fileURLWithPath:title]]; + iconButton = [m_nsWindow standardWindowButton:NSWindowDocumentIconButton]; + } + if (icon.isNull()) { + [iconButton setImage:nil]; + } else { + QPixmap pixmap = icon.pixmap(QSize(22, 22)); + NSImage *image = static_cast<NSImage *>(qt_mac_create_nsimage(pixmap)); + [iconButton setImage:image]; + [image release]; + } +} + void QCocoaWindow::raise() { //qDebug() << "raise" << this; @@ -695,6 +713,7 @@ void QCocoaWindow::setNSWindow(NSWindow *window) void QCocoaWindow::clearNSWindow(NSWindow *window) { + [window setContentView:nil]; [window setDelegate:nil]; [window clearPlatformWindow]; [[NSNotificationCenter defaultCenter] removeObserver:m_contentView]; diff --git a/src/plugins/platforms/cocoa/qnsview.mm b/src/plugins/platforms/cocoa/qnsview.mm index f23fd3045f..33d0fb4bae 100644 --- a/src/plugins/platforms/cocoa/qnsview.mm +++ b/src/plugins/platforms/cocoa/qnsview.mm @@ -89,6 +89,14 @@ static QTouchDevice *touchDevice = 0; return self; } +- (void)dealloc +{ + CGImageRelease(m_cgImage); + m_cgImage = 0; + m_window = 0; + [super dealloc]; +} + - (id)initWithQWindow:(QWindow *)window platformWindow:(QCocoaWindow *) platformWindow { self = [self init]; @@ -129,22 +137,29 @@ static QTouchDevice *touchDevice = 0; - (void)updateGeometry { - NSRect rect = [self frame]; - NSRect windowRect = [[self window] frame]; - QRect geo(windowRect.origin.x, qt_mac_flipYCoordinate(windowRect.origin.y + rect.size.height), rect.size.width, rect.size.height); + QRect geometry; + if (m_platformWindow->m_nsWindow) { + // top level window, get window rect and flip y. + NSRect rect = [self frame]; + NSRect windowRect = [[self window] frame]; + geometry = QRect(windowRect.origin.x, qt_mac_flipYCoordinate(windowRect.origin.y + rect.size.height), rect.size.width, rect.size.height); + } else { + // child window, use the frame rect + geometry = qt_mac_toQRect([self frame]); + } #ifdef QT_COCOA_ENABLE_WINDOW_DEBUG - qDebug() << "QNSView::udpateGeometry" << geo; + qDebug() << "QNSView::udpateGeometry" << m_platformWindow << geometry; #endif // Call setGeometry on QPlatformWindow. (not on QCocoaWindow, // doing that will initiate a geometry change it and possibly create // an infinite loop when this notification is triggered again.) - m_platformWindow->QPlatformWindow::setGeometry(geo); + m_platformWindow->QPlatformWindow::setGeometry(geometry); // Send a geometry change event to Qt, if it's ready to handle events if (!m_platformWindow->m_inConstructor) { - QWindowSystemInterface::handleGeometryChange(m_window, geo); + QWindowSystemInterface::handleGeometryChange(m_window, geometry); QWindowSystemInterface::flushWindowSystemEvents(); } } @@ -343,11 +358,15 @@ static QTouchDevice *touchDevice = 0; } NSWindow *window = [self window]; - int windowHeight = [window frame].size.height; NSPoint windowPoint = [theEvent locationInWindow]; + + int windowScreenY = [window frame].origin.y + [window frame].size.height; + int viewScreenY = [window convertBaseToScreen:[self convertPoint:[self frame].origin toView:nil]].y; + int titleBarHeight = windowScreenY - viewScreenY; + NSPoint nsViewPoint = [self convertPoint: windowPoint fromView: nil]; - QPoint qtWindowPoint = QPoint(nsViewPoint.x, windowHeight - nsViewPoint.y); - NSPoint screenPoint = [window convertBaseToScreen : windowPoint]; + QPoint qtWindowPoint = QPoint(nsViewPoint.x, titleBarHeight + nsViewPoint.y); + NSPoint screenPoint = [window convertBaseToScreen:windowPoint]; QPoint qtScreenPoint = QPoint(screenPoint.x, qt_mac_flipYCoordinate(screenPoint.y)); ulong timestamp = [theEvent timestamp] * 1000; diff --git a/src/plugins/platforms/eglfs/qeglfswindow.cpp b/src/plugins/platforms/eglfs/qeglfswindow.cpp index 9822262127..036b26a165 100644 --- a/src/plugins/platforms/eglfs/qeglfswindow.cpp +++ b/src/plugins/platforms/eglfs/qeglfswindow.cpp @@ -117,10 +117,9 @@ void QEglFSWindow::setGeometry(const QRect &) QPlatformWindow::setGeometry(rect); } -Qt::WindowState QEglFSWindow::setWindowState(Qt::WindowState) +void QEglFSWindow::setWindowState(Qt::WindowState) { setGeometry(QRect()); - return Qt::WindowFullScreen; } WId QEglFSWindow::winId() const diff --git a/src/plugins/platforms/eglfs/qeglfswindow.h b/src/plugins/platforms/eglfs/qeglfswindow.h index c9ef60ac9c..40a38fcb26 100644 --- a/src/plugins/platforms/eglfs/qeglfswindow.h +++ b/src/plugins/platforms/eglfs/qeglfswindow.h @@ -56,7 +56,7 @@ public: ~QEglFSWindow(); void setGeometry(const QRect &); - Qt::WindowState setWindowState(Qt::WindowState state); + void setWindowState(Qt::WindowState state); WId winId() const; EGLSurface surface() const { return m_surface; } diff --git a/src/plugins/platforms/qnx/qqnxsystemsettings.cpp b/src/plugins/platforms/qnx/qqnxsystemsettings.cpp index ae7cb67314..6194a61012 100644 --- a/src/plugins/platforms/qnx/qqnxsystemsettings.cpp +++ b/src/plugins/platforms/qnx/qqnxsystemsettings.cpp @@ -48,11 +48,13 @@ QT_BEGIN_NAMESPACE QHash<QPlatformTheme::Font, QFont *> qt_qnx_createRoleFonts(QPlatformFontDatabase *fontDatabase) { - // See http://docs.blackberry.com/en/developers/deliverables/27299/Text_tablet_1526156_11.jsp - // which recommends using normal font size of 21 pixels and 36 pixels for titles (not covered - // by the theme system). + // See http://docs.blackberry.com/en/developers/deliverables/41577/typography.jsp + // which recommends using + // - small font size of 6 points + // - normal font size of 8 points + // - 11 points for titles (not covered by the theme system). QFont baseFont = fontDatabase->defaultFont(); - baseFont.setPixelSize(21); + baseFont.setPointSize(8); QHash<QPlatformTheme::Font, QFont *> fonts; fonts.insert(QPlatformTheme::SystemFont, new QFont(baseFont)); @@ -70,7 +72,7 @@ QHash<QPlatformTheme::Font, QFont *> qt_qnx_createRoleFonts(QPlatformFontDatabas fonts.insert(QPlatformTheme::ComboLineEditFont, new QFont(baseFont)); QFont smallFont(baseFont); - smallFont.setPixelSize(15); + smallFont.setPointSize(6); fonts.insert(QPlatformTheme::SmallFont, new QFont(smallFont)); fonts.insert(QPlatformTheme::MiniFont, new QFont(smallFont)); diff --git a/src/plugins/platforms/qnx/qqnxwindow.cpp b/src/plugins/platforms/qnx/qqnxwindow.cpp index 9dd8ad7a71..097b5788f6 100644 --- a/src/plugins/platforms/qnx/qqnxwindow.cpp +++ b/src/plugins/platforms/qnx/qqnxwindow.cpp @@ -580,13 +580,13 @@ void QQnxWindow::requestActivateWindow() } -Qt::WindowState QQnxWindow::setWindowState(Qt::WindowState state) +void QQnxWindow::setWindowState(Qt::WindowState state) { qWindowDebug() << Q_FUNC_INFO << "state =" << state; // Prevent two calls with Qt::WindowFullScreen from changing m_unmaximizedGeometry if (m_windowState == state) - return state; + return; switch (state) { @@ -594,7 +594,7 @@ Qt::WindowState QQnxWindow::setWindowState(Qt::WindowState state) // WindowActive is not an accepted parameter according to the docs case Qt::WindowMinimized: case Qt::WindowActive: - return m_windowState; + return; case Qt::WindowMaximized: case Qt::WindowFullScreen: @@ -609,7 +609,6 @@ Qt::WindowState QQnxWindow::setWindowState(Qt::WindowState state) } m_windowState = state; - return state; } void QQnxWindow::gainedFocus() diff --git a/src/plugins/platforms/qnx/qqnxwindow.h b/src/plugins/platforms/qnx/qqnxwindow.h index d79c6785dd..90226bb9a4 100644 --- a/src/plugins/platforms/qnx/qqnxwindow.h +++ b/src/plugins/platforms/qnx/qqnxwindow.h @@ -101,7 +101,7 @@ public: void raise(); void lower(); void requestActivateWindow(); - Qt::WindowState setWindowState(Qt::WindowState state); + void setWindowState(Qt::WindowState state); void gainedFocus(); diff --git a/src/plugins/platforms/windows/main.cpp b/src/plugins/platforms/windows/main.cpp index d337234671..7557b80191 100644 --- a/src/plugins/platforms/windows/main.cpp +++ b/src/plugins/platforms/windows/main.cpp @@ -67,7 +67,7 @@ QT_BEGIN_NAMESPACE \section1 Tips \list - \li The environment variable \c QT_LIGHTHOUSE_WINDOWS_VERBOSE controls + \li The environment variable \c QT_QPA_VERBOSE controls the debug level. It takes the form \c{<keyword1>:<level1>,<keyword2>:<level2>}, where keyword is one of \c integration, \c windows, \c backingstore and @@ -112,9 +112,8 @@ public: QPlatformIntegration *QWindowsIntegrationPlugin::create(const QString& system, const QStringList& paramList) { - Q_UNUSED(paramList); if (system.compare(system, QStringLiteral("windows"), Qt::CaseInsensitive) == 0) - return new QWindowsIntegration; + return new QWindowsIntegration(paramList); return 0; } diff --git a/src/plugins/platforms/windows/qtwindows_additional.h b/src/plugins/platforms/windows/qtwindows_additional.h index f5ea2cf6bf..a35a513579 100644 --- a/src/plugins/platforms/windows/qtwindows_additional.h +++ b/src/plugins/platforms/windows/qtwindows_additional.h @@ -83,6 +83,21 @@ #define CHILDID_SELF 0 #define WM_GETOBJECT 0x003D +#ifndef SHGFI_ADDOVERLAYS // Shell structures for icons. +typedef struct _SHSTOCKICONINFO +{ + DWORD cbSize; + HICON hIcon; + int iSysImageIndex; + int iIcon; + WCHAR szPath[MAX_PATH]; +} SHSTOCKICONINFO; + +# define SIID_SHIELD 77 +# define SHGFI_ADDOVERLAYS 0x20 +# define SHGFI_OVERLAYINDEX 0x40 +#endif // SIID_SHIELD + #if !defined(__MINGW64_VERSION_MAJOR) #define STATE_SYSTEM_HASPOPUP 0x40000000 diff --git a/src/plugins/platforms/windows/qwindowscontext.cpp b/src/plugins/platforms/windows/qwindowscontext.cpp index 98c17deba9..3d4871d7a2 100644 --- a/src/plugins/platforms/windows/qwindowscontext.cpp +++ b/src/plugins/platforms/windows/qwindowscontext.cpp @@ -210,7 +210,9 @@ bool QWindowsUser32DLL::initTouch() \ingroup qt-lighthouse-win */ -QWindowsShell32DLL::QWindowsShell32DLL() : sHCreateItemFromParsingName(0) +QWindowsShell32DLL::QWindowsShell32DLL() + : sHCreateItemFromParsingName(0) + , sHGetStockIconInfo(0) { } @@ -218,6 +220,7 @@ void QWindowsShell32DLL::init() { QSystemLibrary library(QStringLiteral("shell32")); sHCreateItemFromParsingName = (SHCreateItemFromParsingName)(library.resolve("SHCreateItemFromParsingName")); + sHGetStockIconInfo = (SHGetStockIconInfo)library.resolve("SHGetStockIconInfo"); } QWindowsUser32DLL QWindowsContext::user32dll; diff --git a/src/plugins/platforms/windows/qwindowscontext.h b/src/plugins/platforms/windows/qwindowscontext.h index 450d6c8f4b..dcc636bfc0 100644 --- a/src/plugins/platforms/windows/qwindowscontext.h +++ b/src/plugins/platforms/windows/qwindowscontext.h @@ -49,6 +49,7 @@ #include <QtCore/QSharedPointer> struct IBindCtx; +struct _SHSTOCKICONINFO; QT_BEGIN_NAMESPACE @@ -99,8 +100,10 @@ struct QWindowsShell32DLL inline void init(); typedef HRESULT (WINAPI *SHCreateItemFromParsingName)(PCWSTR, IBindCtx *, const GUID&, void **); + typedef HRESULT (WINAPI *SHGetStockIconInfo)(int , int , _SHSTOCKICONINFO *); SHCreateItemFromParsingName sHCreateItemFromParsingName; + SHGetStockIconInfo sHGetStockIconInfo; }; #endif // Q_OS_WINCE @@ -115,7 +118,7 @@ public: SI_SupportsTouch = 0x2 }; - // Verbose flag set by environment variable QT_LIGHTHOUSE_WINDOWS_VERBOSE + // Verbose flag set by environment variable QT_QPA_VERBOSE static int verboseIntegration; static int verboseWindows; static int verboseBackingStore; diff --git a/src/plugins/platforms/windows/qwindowsglcontext.cpp b/src/plugins/platforms/windows/qwindowsglcontext.cpp index 1c9a7d36f5..b50a858f96 100644 --- a/src/plugins/platforms/windows/qwindowsglcontext.cpp +++ b/src/plugins/platforms/windows/qwindowsglcontext.cpp @@ -42,6 +42,7 @@ #include "qwindowsglcontext.h" #include "qwindowscontext.h" #include "qwindowswindow.h" +#include "qwindowsintegration.h" #include <QtCore/QDebug> #include <QtCore/QSysInfo> @@ -439,7 +440,7 @@ static int choosePixelFormat(HDC hdc, iAttributes[i++] = WGL_SAMPLES_ARB; samplesValuePosition = i; iAttributes[i++] = format.samples(); - } else if (samples == 0 || samples == 1 ) { + } else { iAttributes[i++] = WGL_SAMPLE_BUFFERS_ARB; iAttributes[i++] = FALSE; } @@ -855,16 +856,6 @@ QDebug operator<<(QDebug d, const QOpenGLStaticContext &s) return d; } -// Use ARB unless explicitly turned off on command line. -static inline bool useARB() -{ - const QVariant glExtension = qApp->platformNativeInterface()->property("gl"); - if (glExtension.type() == QVariant::String - && !glExtension.toString().compare(QStringLiteral("gdi"), Qt::CaseInsensitive)) - return false; - return true; -} - /*! \class QWindowsGLContext \brief Open GL context. @@ -914,12 +905,13 @@ QWindowsGLContext::QWindowsGLContext(const QOpenGLStaticContextPtr &staticContex if (QWindowsContext::verboseGL > 1) describeFormats(hdc); - // Preferably use direct rendering and ARB extensions (unless pixmap) + // Preferably use direct rendering and ARB extensions (unless pixmap + // or explicitly turned off on command line). const QWindowsOpenGLAdditionalFormat requestedAdditional(QWindowsGLDirectRendering); tryExtensions = m_staticContext->hasExtensions() && !testFlag(requestedAdditional.formatFlags, QWindowsGLRenderToPixmap) - && useARB(); + && !(QWindowsIntegration::instance()->options() & QWindowsIntegration::DisableArb); QWindowsOpenGLAdditionalFormat obtainedAdditional; if (tryExtensions) { m_pixelFormat = diff --git a/src/plugins/platforms/windows/qwindowsintegration.cpp b/src/plugins/platforms/windows/qwindowsintegration.cpp index 1f26ec5bab..50ffb85b01 100644 --- a/src/plugins/platforms/windows/qwindowsintegration.cpp +++ b/src/plugins/platforms/windows/qwindowsintegration.cpp @@ -187,6 +187,40 @@ void *QWindowsNativeInterface::createMessageWindow(const QString &classNameTempl \class QWindowsIntegration \brief QPlatformIntegration implementation for Windows. \internal + + \section1 Programming Considerations + + The platform plugin should run on Desktop Windows from Windows XP onwards + and Windows Embedded. + + It should compile with: + \list + \li Microsoft Visual Studio 2008 or later (using the Microsoft Windows SDK, + (\c Q_CC_MSVC). + \li Stock \l{http://mingw.org/}{MinGW} (\c Q_CC_MINGW). + This version ships with headers that are missing a lot of WinAPI. + \li MinGW distributions using GCC 4.7 or higher and a recent MinGW-w64 runtime API, + such as \l{http://tdm-gcc.tdragon.net/}{TDM-GCC}, or + \l{http://mingwbuilds.sourceforge.net/}{MinGW-builds} + (\c Q_CC_MINGW and \c __MINGW64_VERSION_MAJOR indicating the version). + MinGW-w64 provides more complete headers (compared to stock MinGW from mingw.org), + including a considerable part of the Windows SDK. + \li Visual Studio 2008 for Windows Embedded (\c Q_OS_WINCE). + \endlist + + The file \c qtwindows_additional.h contains defines and declarations that + are missing in MinGW. When encountering missing declarations, it should + be added there so that \c #ifdefs for MinGW can be avoided. Similarly, + \c qplatformfunctions_wince.h contains defines and declarations for + Windows Embedded. + + When using a function from the WinAPI, the minimum supported Windows version + and Windows Embedded support should be checked. If the function is not supported + on Windows XP or is not present in the MinGW-headers, it should be dynamically + resolved. For this purpose, QWindowsContext has static structs like + QWindowsUser32DLL and QWindowsShell32DLL. All function pointers should go to + these structs to avoid lookups in several places. + \ingroup qt-lighthouse-win */ @@ -198,9 +232,10 @@ struct QWindowsIntegrationPrivate typedef QSharedPointer<QOpenGLStaticContext> QOpenGLStaticContextPtr; #endif - QWindowsIntegrationPrivate(); + explicit QWindowsIntegrationPrivate(const QStringList ¶mList); ~QWindowsIntegrationPrivate(); + const unsigned m_options; QWindowsContext m_context; QPlatformFontDatabase *m_fontDatabase; QWindowsNativeInterface m_nativeInterface; @@ -221,8 +256,27 @@ struct QWindowsIntegrationPrivate QWindowsServices m_services; }; -QWindowsIntegrationPrivate::QWindowsIntegrationPrivate() - : m_fontDatabase(0), m_eventDispatcher(new QWindowsGuiEventDispatcher) +static inline unsigned parseOptions(const QStringList ¶mList) +{ + unsigned options = 0; + foreach (const QString ¶m, paramList) { + if (param.startsWith(QLatin1String("fontengine="))) { + if (param.endsWith(QLatin1String("freetype"))) { + options |= QWindowsIntegration::FontDatabaseFreeType; + } else if (param.endsWith(QLatin1String("native"))) { + options |= QWindowsIntegration::FontDatabaseNative; + } + } else if (param == QLatin1String("gl=gdi")) { + options |= QWindowsIntegration::DisableArb; + } + } + return options; +} + +QWindowsIntegrationPrivate::QWindowsIntegrationPrivate(const QStringList ¶mList) + : m_options(parseOptions(paramList)) + , m_fontDatabase(0) + , m_eventDispatcher(new QWindowsGuiEventDispatcher) { } @@ -232,8 +286,8 @@ QWindowsIntegrationPrivate::~QWindowsIntegrationPrivate() delete m_fontDatabase; } -QWindowsIntegration::QWindowsIntegration() : - d(new QWindowsIntegrationPrivate) +QWindowsIntegration::QWindowsIntegration(const QStringList ¶mList) : + d(new QWindowsIntegrationPrivate(paramList)) { QGuiApplicationPrivate::instance()->setEventDispatcher(d->m_eventDispatcher); #ifndef QT_NO_CLIPBOARD @@ -337,25 +391,6 @@ QPlatformOpenGLContext /* Workaround for QTBUG-24205: In 'Auto', pick the FreeType engine for * QML2 applications. */ -enum FontDatabaseOption { - FontDatabaseFreeType, - FontDatabaseNative, - FontDatabaseAuto -}; - -static inline FontDatabaseOption fontDatabaseOption(const QObject &nativeInterface) -{ - const QVariant argumentV = nativeInterface.property("fontengine"); - if (argumentV.isValid()) { - const QString argument = argumentV.toString(); - if (argument == QLatin1String("freetype")) - return FontDatabaseFreeType; - if (argument == QLatin1String("native")) - return FontDatabaseNative; - } - return FontDatabaseAuto; -} - #ifdef Q_OS_WINCE // It's not easy to detect if we are running a QML application // Let's try to do so by checking if the QtQuick module is loaded. @@ -377,10 +412,9 @@ QPlatformFontDatabase *QWindowsIntegration::fontDatabase() const #ifdef QT_NO_FREETYPE d->m_fontDatabase = new QWindowsFontDatabase(); #else // QT_NO_FREETYPE - FontDatabaseOption option = fontDatabaseOption(d->m_nativeInterface); - if (option == FontDatabaseFreeType) { + if (d->m_options & QWindowsIntegration::FontDatabaseFreeType) { d->m_fontDatabase = new QWindowsFontDatabaseFT; - } else if (option == FontDatabaseNative){ + } else if (d->m_options & QWindowsIntegration::FontDatabaseNative){ d->m_fontDatabase = new QWindowsFontDatabase; } else { #ifndef Q_OS_WINCE @@ -486,6 +520,11 @@ QWindowsIntegration *QWindowsIntegration::instance() return static_cast<QWindowsIntegration *>(QGuiApplicationPrivate::platformIntegration()); } +unsigned QWindowsIntegration::options() const +{ + return d->m_options; +} + QAbstractEventDispatcher * QWindowsIntegration::guiThreadEventDispatcher() const { return d->m_eventDispatcher; diff --git a/src/plugins/platforms/windows/qwindowsintegration.h b/src/plugins/platforms/windows/qwindowsintegration.h index 49780566dd..ca47dabb4b 100644 --- a/src/plugins/platforms/windows/qwindowsintegration.h +++ b/src/plugins/platforms/windows/qwindowsintegration.h @@ -53,7 +53,13 @@ struct QWindowsIntegrationPrivate; class QWindowsIntegration : public QPlatformIntegration { public: - QWindowsIntegration(); + enum Options { // Options to be passed on command line. + FontDatabaseFreeType = 0x1, + FontDatabaseNative = 0x2, + DisableArb = 0x4 + }; + + explicit QWindowsIntegration(const QStringList ¶mList); virtual ~QWindowsIntegration(); bool hasCapability(QPlatformIntegration::Capability cap) const; @@ -87,6 +93,8 @@ public: inline void emitScreenAdded(QPlatformScreen *s) { screenAdded(s); } + unsigned options() const; + private: QScopedPointer<QWindowsIntegrationPrivate> d; }; diff --git a/src/plugins/platforms/windows/qwindowskeymapper.cpp b/src/plugins/platforms/windows/qwindowskeymapper.cpp index b57a27acb4..c11bd8c53c 100644 --- a/src/plugins/platforms/windows/qwindowskeymapper.cpp +++ b/src/plugins/platforms/windows/qwindowskeymapper.cpp @@ -68,7 +68,6 @@ QWindowsKeyMapper::QWindowsKeyMapper() QWindowsKeyMapper::~QWindowsKeyMapper() { - deleteLayouts(); } #ifndef LANG_PASHTO @@ -436,6 +435,8 @@ static const Qt::KeyboardModifiers ModsTbl[] = { Qt::AltModifier | Qt::ShiftModifier | Qt::ControlModifier, // 7 Qt::NoModifier, // Fall-back to raw Key_* }; +static const size_t NumMods = sizeof ModsTbl / sizeof *ModsTbl; +Q_STATIC_ASSERT((NumMods == KeyboardLayoutItem::NumQtKeys)); /** Remap return or action key to select key for windows mobile. @@ -520,32 +521,10 @@ static inline bool isModifierKey(int code) // Keyboard map private ----------------------------------------------------------------[ start ]--- -/* - \internal - A Windows KeyboardLayoutItem has 8 possible states: - 1. Unmodified - 2. Shift - 3. Control - 4. Control + Shift - 5. Alt - 6. Alt + Shift - 7. Alt + Control - 8. Alt + Control + Shift -*/ -struct KeyboardLayoutItem { - bool dirty; - quint8 deadkeys; - quint32 qtKey[9]; // Can by any Qt::Key_<foo>, or unicode character -}; - void QWindowsKeyMapper::deleteLayouts() { - for (int i = 0; i < 255; ++i) { - if (keyLayout[i]) { - delete keyLayout[i]; - keyLayout[i] = 0; - } - } + for (size_t i = 0; i < NumKeyboardLayoutItems; ++i) + keyLayout[i].exists = false; } void QWindowsKeyMapper::changeKeyboard() @@ -594,12 +573,9 @@ void QWindowsKeyMapper::updateKeyMap(const MSG &msg) void QWindowsKeyMapper::updatePossibleKeyCodes(unsigned char *kbdBuffer, quint32 scancode, quint32 vk_key) { - if (!vk_key || (keyLayout[vk_key] && !keyLayout[vk_key]->dirty)) + if (!vk_key || (keyLayout[vk_key].exists && !keyLayout[vk_key].dirty)) return; - if (!keyLayout[vk_key]) - keyLayout[vk_key] = new KeyboardLayoutItem; - // Copy keyboard state, so we can modify and query output for each possible permutation unsigned char buffer[256]; memcpy(buffer, kbdBuffer, sizeof(buffer)); @@ -615,40 +591,41 @@ void QWindowsKeyMapper::updatePossibleKeyCodes(unsigned char *kbdBuffer, quint32 buffer[VK_LMENU ] = 0; // Use right Alt, since left Ctrl + right Alt is considered AltGraph bool isDeadKey = false; - keyLayout[vk_key]->deadkeys = 0; - keyLayout[vk_key]->dirty = false; + keyLayout[vk_key].deadkeys = 0; + keyLayout[vk_key].dirty = false; + keyLayout[vk_key].exists = true; setKbdState(buffer, false, false, false); - keyLayout[vk_key]->qtKey[0] = toKeyOrUnicode(vk_key, scancode, buffer, &isDeadKey); - keyLayout[vk_key]->deadkeys |= isDeadKey ? 0x01 : 0; + keyLayout[vk_key].qtKey[0] = toKeyOrUnicode(vk_key, scancode, buffer, &isDeadKey); + keyLayout[vk_key].deadkeys |= isDeadKey ? 0x01 : 0; setKbdState(buffer, true, false, false); - keyLayout[vk_key]->qtKey[1] = toKeyOrUnicode(vk_key, scancode, buffer, &isDeadKey); - keyLayout[vk_key]->deadkeys |= isDeadKey ? 0x02 : 0; + keyLayout[vk_key].qtKey[1] = toKeyOrUnicode(vk_key, scancode, buffer, &isDeadKey); + keyLayout[vk_key].deadkeys |= isDeadKey ? 0x02 : 0; setKbdState(buffer, false, true, false); - keyLayout[vk_key]->qtKey[2] = toKeyOrUnicode(vk_key, scancode, buffer, &isDeadKey); - keyLayout[vk_key]->deadkeys |= isDeadKey ? 0x04 : 0; + keyLayout[vk_key].qtKey[2] = toKeyOrUnicode(vk_key, scancode, buffer, &isDeadKey); + keyLayout[vk_key].deadkeys |= isDeadKey ? 0x04 : 0; setKbdState(buffer, true, true, false); - keyLayout[vk_key]->qtKey[3] = toKeyOrUnicode(vk_key, scancode, buffer, &isDeadKey); - keyLayout[vk_key]->deadkeys |= isDeadKey ? 0x08 : 0; + keyLayout[vk_key].qtKey[3] = toKeyOrUnicode(vk_key, scancode, buffer, &isDeadKey); + keyLayout[vk_key].deadkeys |= isDeadKey ? 0x08 : 0; setKbdState(buffer, false, false, true); - keyLayout[vk_key]->qtKey[4] = toKeyOrUnicode(vk_key, scancode, buffer, &isDeadKey); - keyLayout[vk_key]->deadkeys |= isDeadKey ? 0x10 : 0; + keyLayout[vk_key].qtKey[4] = toKeyOrUnicode(vk_key, scancode, buffer, &isDeadKey); + keyLayout[vk_key].deadkeys |= isDeadKey ? 0x10 : 0; setKbdState(buffer, true, false, true); - keyLayout[vk_key]->qtKey[5] = toKeyOrUnicode(vk_key, scancode, buffer, &isDeadKey); - keyLayout[vk_key]->deadkeys |= isDeadKey ? 0x20 : 0; + keyLayout[vk_key].qtKey[5] = toKeyOrUnicode(vk_key, scancode, buffer, &isDeadKey); + keyLayout[vk_key].deadkeys |= isDeadKey ? 0x20 : 0; setKbdState(buffer, false, true, true); - keyLayout[vk_key]->qtKey[6] = toKeyOrUnicode(vk_key, scancode, buffer, &isDeadKey); - keyLayout[vk_key]->deadkeys |= isDeadKey ? 0x40 : 0; + keyLayout[vk_key].qtKey[6] = toKeyOrUnicode(vk_key, scancode, buffer, &isDeadKey); + keyLayout[vk_key].deadkeys |= isDeadKey ? 0x40 : 0; setKbdState(buffer, true, true, true); - keyLayout[vk_key]->qtKey[7] = toKeyOrUnicode(vk_key, scancode, buffer, &isDeadKey); - keyLayout[vk_key]->deadkeys |= isDeadKey ? 0x80 : 0; + keyLayout[vk_key].qtKey[7] = toKeyOrUnicode(vk_key, scancode, buffer, &isDeadKey); + keyLayout[vk_key].deadkeys |= isDeadKey ? 0x80 : 0; // Add a fall back key for layouts which don't do composition and show non-latin1 characters int fallbackKey = winceKeyBend(vk_key); if (!fallbackKey || fallbackKey == Qt::Key_unknown) { fallbackKey = 0; - if (vk_key != keyLayout[vk_key]->qtKey[0] && vk_key < 0x5B && vk_key > 0x2F) + if (vk_key != keyLayout[vk_key].qtKey[0] && vk_key < 0x5B && vk_key > 0x2F) fallbackKey = vk_key; } - keyLayout[vk_key]->qtKey[8] = fallbackKey; + keyLayout[vk_key].qtKey[8] = fallbackKey; // If this vk_key a Dead Key if (MapVirtualKey(vk_key, 2) & 0x80000000) { @@ -666,22 +643,22 @@ void QWindowsKeyMapper::updatePossibleKeyCodes(unsigned char *kbdBuffer, quint32 if (QWindowsContext::verboseEvents > 1) { qDebug("updatePossibleKeyCodes for virtual key = 0x%02x!", vk_key); - for (int i = 0; i < 9; ++i) { - qDebug(" [%d] (%d,0x%02x,'%c') %s", i, - keyLayout[vk_key]->qtKey[i], - keyLayout[vk_key]->qtKey[i], - keyLayout[vk_key]->qtKey[i] ? keyLayout[vk_key]->qtKey[i] : 0x03, - keyLayout[vk_key]->deadkeys & (1<<i) ? "deadkey" : ""); + for (size_t i = 0; i < NumMods; ++i) { + qDebug(" [%d] (%d,0x%02x,'%c') %s", int(i), + keyLayout[vk_key].qtKey[i], + keyLayout[vk_key].qtKey[i], + keyLayout[vk_key].qtKey[i] ? keyLayout[vk_key].qtKey[i] : 0x03, + keyLayout[vk_key].deadkeys & (1<<i) ? "deadkey" : ""); } } } bool QWindowsKeyMapper::isADeadKey(unsigned int vk_key, unsigned int modifiers) { - if (keyLayout && (vk_key < 256) && keyLayout[vk_key]) { - for (register int i = 0; i < 9; ++i) { + if ((vk_key < NumKeyboardLayoutItems) && keyLayout[vk_key].exists) { + for (register size_t i = 0; i < NumMods; ++i) { if (uint(ModsTbl[i]) == modifiers) - return bool(keyLayout[vk_key]->deadkeys & 1<<i); + return bool(keyLayout[vk_key].deadkeys & 1<<i); } } return false; @@ -1123,11 +1100,11 @@ QList<int> QWindowsKeyMapper::possibleKeys(const QKeyEvent *e) const { QList<int> result; - KeyboardLayoutItem *kbItem = keyLayout[e->nativeVirtualKey()]; - if (!kbItem) + const KeyboardLayoutItem &kbItem = keyLayout[e->nativeVirtualKey()]; + if (!kbItem.exists) return result; - quint32 baseKey = kbItem->qtKey[0]; + quint32 baseKey = kbItem.qtKey[0]; Qt::KeyboardModifiers keyMods = e->modifiers(); if (baseKey == Qt::Key_Return && (e->nativeModifiers() & ExtendedKey)) { result << int(Qt::Key_Enter + keyMods); @@ -1135,9 +1112,9 @@ 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 < 9; ++i) { + for (int i = 1; i < NumMods; ++i) { Qt::KeyboardModifiers neededMods = ModsTbl[i]; - quint32 key = kbItem->qtKey[i]; + quint32 key = kbItem.qtKey[i]; if (key && key != baseKey && ((keyMods & neededMods) == neededMods)) result << int(key + (keyMods & ~neededMods)); } diff --git a/src/plugins/platforms/windows/qwindowskeymapper.h b/src/plugins/platforms/windows/qwindowskeymapper.h index 7b3f18a42d..6de255facf 100644 --- a/src/plugins/platforms/windows/qwindowskeymapper.h +++ b/src/plugins/platforms/windows/qwindowskeymapper.h @@ -51,7 +51,25 @@ QT_BEGIN_NAMESPACE class QKeyEvent; class QWindow; -struct KeyboardLayoutItem; +/* + \internal + A Windows KeyboardLayoutItem has 8 possible states: + 1. Unmodified + 2. Shift + 3. Control + 4. Control + Shift + 5. Alt + 6. Alt + Shift + 7. Alt + Control + 8. Alt + Control + Shift +*/ +struct KeyboardLayoutItem { + uint dirty : 1; + uint exists : 1; // whether this item has been initialized (by updatePossibleKeyCodes) + quint8 deadkeys; + static const size_t NumQtKeys = 9; + quint32 qtKey[NumQtKeys]; // Can by any Qt::Key_<foo>, or unicode character +}; class QWindowsKeyMapper { @@ -87,8 +105,9 @@ private: bool isADeadKey(unsigned int vk_key, unsigned int modifiers); void deleteLayouts(); - KeyboardLayoutItem *keyLayout[256]; QWindow *m_keyGrabber; + static const size_t NumKeyboardLayoutItems = 256; + KeyboardLayoutItem keyLayout[NumKeyboardLayoutItems]; }; enum WindowsNativeModifiers { diff --git a/src/plugins/platforms/windows/qwindowstheme.cpp b/src/plugins/platforms/windows/qwindowstheme.cpp index 7b3ffc633f..d9de911914 100644 --- a/src/plugins/platforms/windows/qwindowstheme.cpp +++ b/src/plugins/platforms/windows/qwindowstheme.cpp @@ -55,9 +55,13 @@ #include <QtCore/QDebug> #include <QtCore/QTextStream> #include <QtCore/QSysInfo> +#include <QtCore/QCache> #include <QtGui/QPalette> #include <QtGui/QGuiApplication> +#include <QtGui/QPainter> +#include <QtGui/QPixmapCache> #include <qpa/qwindowsysteminterface.h> +#include <private/qsystemlibrary_p.h> QT_BEGIN_NAMESPACE @@ -348,6 +352,11 @@ QVariant QWindowsTheme::themeHint(ThemeHint hint) const return QVariant(int(WindowsKeyboardScheme)); case UiEffects: return QVariant(uiEffects()); + case IconPixmapSizes: { + QList<int> sizes; + sizes << 16 << 32; + return QVariant::fromValue(sizes); + } default: break; } @@ -433,4 +442,225 @@ void QWindowsTheme::windowsThemeChanged(QWindow * window) QWindowSystemInterface::handleThemeChange(window); } +// Defined in qpixmap_win.cpp +Q_GUI_EXPORT QPixmap qt_pixmapFromWinHICON(HICON icon); + +static QPixmap loadIconFromShell32(int resourceId, QSizeF size) +{ +#ifdef Q_OS_WINCE + HMODULE hmod = LoadLibrary(L"ceshell"); +#else + HMODULE hmod = QSystemLibrary::load(L"shell32"); +#endif + if (hmod) { + HICON iconHandle = (HICON)LoadImage(hmod, MAKEINTRESOURCE(resourceId), IMAGE_ICON, size.width(), size.height(), 0); + if (iconHandle) { + QPixmap iconpixmap = qt_pixmapFromWinHICON(iconHandle); + DestroyIcon(iconHandle); + return iconpixmap; + } + } + return QPixmap(); +} + +QPixmap QWindowsTheme::standardPixmap(StandardPixmap sp, const QSizeF &size) const +{ + int resourceId = -1; + LPCTSTR iconName = 0; + switch (sp) { + case DriveCDIcon: + case DriveDVDIcon: + resourceId = 12; + break; + case DriveNetIcon: + resourceId = 10; + break; + case DriveHDIcon: + resourceId = 9; + break; + case DriveFDIcon: + resourceId = 7; + break; + case FileIcon: + case FileLinkIcon: + resourceId = 1; + break; + case DirIcon: + case DirLinkIcon: + case DirClosedIcon: + resourceId = 4; + break; + case DesktopIcon: + resourceId = 35; + break; + case ComputerIcon: + resourceId = 16; + break; + case DirOpenIcon: + case DirLinkOpenIcon: + resourceId = 5; + break; + case FileDialogNewFolder: + resourceId = 319; + break; + case DirHomeIcon: + resourceId = 235; + break; + case TrashIcon: + resourceId = 191; + break; + case MessageBoxInformation: + iconName = IDI_INFORMATION; + break; + case MessageBoxWarning: + iconName = IDI_WARNING; + break; + case MessageBoxCritical: + iconName = IDI_ERROR; + break; + case MessageBoxQuestion: + iconName = IDI_QUESTION; + break; + case VistaShield: + if (QSysInfo::WindowsVersion >= QSysInfo::WV_VISTA + && (QSysInfo::WindowsVersion & QSysInfo::WV_NT_based)) { + if (!QWindowsContext::shell32dll.sHGetStockIconInfo) + return QPixmap(); + QPixmap pixmap; + SHSTOCKICONINFO iconInfo; + memset(&iconInfo, 0, sizeof(iconInfo)); + iconInfo.cbSize = sizeof(iconInfo); + const int iconSize = size.width() > 16 ? SHGFI_LARGEICON : SHGFI_SMALLICON; + if (QWindowsContext::shell32dll.sHGetStockIconInfo(SIID_SHIELD, SHGFI_ICON | iconSize, &iconInfo) == S_OK) { + pixmap = qt_pixmapFromWinHICON(iconInfo.hIcon); + DestroyIcon(iconInfo.hIcon); + return pixmap; + } + } + break; + default: + break; + } + + if (resourceId != -1) { + QPixmap pixmap = loadIconFromShell32(resourceId, size); + if (!pixmap.isNull()) { + if (sp == FileLinkIcon || sp == DirLinkIcon || sp == DirLinkOpenIcon) { + QPainter painter(&pixmap); + QPixmap link = loadIconFromShell32(30, size); + painter.drawPixmap(0, 0, size.width(), size.height(), link); + } + return pixmap; + } + } + + if (iconName) { + HICON iconHandle = LoadIcon(NULL, iconName); + QPixmap pixmap = qt_pixmapFromWinHICON(iconHandle); + DestroyIcon(iconHandle); + if (!pixmap.isNull()) + return pixmap; + } + + return QPlatformTheme::standardPixmap(sp, size); +} + +static QString dirIconPixmapCacheKey(int iIcon, int iconSize) +{ + QString key = QLatin1String("qt_dir_") + QString::number(iIcon); + if (iconSize == SHGFI_LARGEICON) + key += QLatin1Char('l'); + return key; +} + +template <typename T> +class FakePointer +{ +public: + + Q_STATIC_ASSERT_X(sizeof(T) <= sizeof(void *), "FakePointers can only go that far."); + + static FakePointer *create(T thing) + { + return reinterpret_cast<FakePointer *>(thing); + } + + T operator * () const + { + return T(qintptr(this)); + } + + void operator delete (void *) {} +}; + +QPixmap QWindowsTheme::fileIconPixmap(const QFileInfo &fileInfo, const QSizeF &size) const +{ + /* We don't use the variable, but by storing it statically, we + * ensure CoInitialize is only called once. */ + static HRESULT comInit = CoInitialize(NULL); + Q_UNUSED(comInit); + + static QCache<QString, FakePointer<int> > dirIconEntryCache(1000); + static QMutex mx; + + QPixmap pixmap; + const QString filePath = QDir::toNativeSeparators(fileInfo.filePath()); + int iconSize = size.width() > 16 ? SHGFI_LARGEICON : SHGFI_SMALLICON; + + bool cacheableDirIcon = fileInfo.isDir() && !fileInfo.isRoot(); + if (cacheableDirIcon) { + QMutexLocker locker(&mx); + int iIcon = **dirIconEntryCache.object(filePath); + if (iIcon) { + QPixmapCache::find(dirIconPixmapCacheKey(iIcon, iconSize), pixmap); + if (pixmap.isNull()) // Let's keep both caches in sync + dirIconEntryCache.remove(filePath); + else + return pixmap; + } + } + + SHFILEINFO info; + unsigned int flags = +#ifndef Q_OS_WINCE + SHGFI_ICON|iconSize|SHGFI_SYSICONINDEX|SHGFI_ADDOVERLAYS|SHGFI_OVERLAYINDEX; +#else + iconSize|SHGFI_SYSICONINDEX; +#endif // Q_OS_WINCE + unsigned long val = SHGetFileInfo((const wchar_t *)filePath.utf16(), 0, + &info, sizeof(SHFILEINFO), flags); + + // Even if GetFileInfo returns a valid result, hIcon can be empty in some cases + if (val && info.hIcon) { + QString key; + if (cacheableDirIcon) { + //using the unique icon index provided by windows save us from duplicate keys + key = dirIconPixmapCacheKey(info.iIcon, iconSize); + QPixmapCache::find(key, pixmap); + if (!pixmap.isNull()) { + QMutexLocker locker(&mx); + dirIconEntryCache.insert(filePath, FakePointer<int>::create(info.iIcon)); + } + } + + if (pixmap.isNull()) { + pixmap = qt_pixmapFromWinHICON(info.hIcon); + if (!pixmap.isNull()) { + if (cacheableDirIcon) { + QMutexLocker locker(&mx); + QPixmapCache::insert(key, pixmap); + dirIconEntryCache.insert(filePath, FakePointer<int>::create(info.iIcon)); + } + } else { + qWarning("QWindowsTheme::fileIconPixmap() no icon found"); + } + } + DestroyIcon(info.hIcon); + } + + if (!pixmap.isNull()) + return pixmap; + return QPlatformTheme::fileIconPixmap(fileInfo, size); +} + QT_END_NAMESPACE diff --git a/src/plugins/platforms/windows/qwindowstheme.h b/src/plugins/platforms/windows/qwindowstheme.h index 7e885b8f3e..89ef527e76 100644 --- a/src/plugins/platforms/windows/qwindowstheme.h +++ b/src/plugins/platforms/windows/qwindowstheme.h @@ -67,6 +67,9 @@ public: virtual const QFont *font(Font type = SystemFont) const { return m_fonts[type]; } + virtual QPixmap standardPixmap(StandardPixmap sp, const QSizeF &size) const; + virtual QPixmap fileIconPixmap(const QFileInfo &fileInfo, const QSizeF &size) const; + void windowsThemeChanged(QWindow *window); static const char *name; diff --git a/src/plugins/platforms/windows/qwindowswindow.cpp b/src/plugins/platforms/windows/qwindowswindow.cpp index f3830eb962..99b8922768 100644 --- a/src/plugins/platforms/windows/qwindowswindow.cpp +++ b/src/plugins/platforms/windows/qwindowswindow.cpp @@ -61,6 +61,8 @@ QT_BEGIN_NAMESPACE +Q_GUI_EXPORT HICON qt_pixmapToWinHICON(const QPixmap &); + static QByteArray debugWinStyle(DWORD style) { QByteArray rc = "0x"; @@ -699,13 +701,15 @@ QWindowsWindow::QWindowsWindow(QWindow *aWindow, const WindowData &data) : m_cursor(QWindowsScreen::screenOf(aWindow)->windowsCursor()->standardWindowCursor()), m_dropTarget(0), m_savedStyle(0), - m_format(aWindow->format()) + m_format(aWindow->format()), #ifdef QT_OPENGL_ES_2 - , m_eglSurface(0) + m_eglSurface(0), #endif #ifdef Q_OS_WINCE - , m_previouslyHidden(false) + m_previouslyHidden(false), #endif + m_iconSmall(0), + m_iconBig(0) { if (aWindow->surfaceType() == QWindow::OpenGLSurface) setFlag(OpenGLSurface); @@ -730,6 +734,7 @@ QWindowsWindow::QWindowsWindow(QWindow *aWindow, const WindowData &data) : QWindowsWindow::~QWindowsWindow() { destroyWindow(); + destroyIcon(); } void QWindowsWindow::destroyWindow() @@ -1230,13 +1235,12 @@ void QWindowsWindow::handleWindowStateChange(Qt::WindowState state) QWindowSystemInterface::handleWindowStateChanged(window(), state); } -Qt::WindowState QWindowsWindow::setWindowState(Qt::WindowState state) +void QWindowsWindow::setWindowState(Qt::WindowState state) { if (m_data.hwnd) { setWindowState_sys(state); m_windowState = state; } - return state; } bool QWindowsWindow::isFullScreen_sys() const @@ -1754,4 +1758,32 @@ QByteArray QWindowsWindow::debugWindowFlags(Qt::WindowFlags wf) return rc; } +static HICON createHIcon(const QIcon &icon, int xSize, int ySize) +{ + if (!icon.isNull()) { + const QPixmap pm = icon.pixmap(icon.actualSize(QSize(xSize, ySize))); + if (!pm.isNull()) + return qt_pixmapToWinHICON(pm); + } + return 0; +} + +void QWindowsWindow::setWindowIcon(const QIcon &icon) +{ + if (m_data.hwnd) { + destroyIcon(); + + m_iconSmall = createHIcon(icon, GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON)); + m_iconBig = createHIcon(icon, GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CYICON)); + + if (m_iconBig) { + SendMessage(m_data.hwnd, WM_SETICON, 0 /* ICON_SMALL */, (LPARAM)m_iconSmall); + SendMessage(m_data.hwnd, WM_SETICON, 1 /* ICON_BIG */, (LPARAM)m_iconBig); + } else { + SendMessage(m_data.hwnd, WM_SETICON, 0 /* ICON_SMALL */, (LPARAM)m_iconSmall); + SendMessage(m_data.hwnd, WM_SETICON, 1 /* ICON_BIG */, (LPARAM)m_iconSmall); + } + } +} + QT_END_NAMESPACE diff --git a/src/plugins/platforms/windows/qwindowswindow.h b/src/plugins/platforms/windows/qwindowswindow.h index 3b7666cf32..978d1d5a53 100644 --- a/src/plugins/platforms/windows/qwindowswindow.h +++ b/src/plugins/platforms/windows/qwindowswindow.h @@ -160,7 +160,7 @@ public: virtual QPoint mapFromGlobal(const QPoint &pos) const; virtual void setWindowFlags(Qt::WindowFlags flags); - virtual Qt::WindowState setWindowState(Qt::WindowState state); + virtual void setWindowState(Qt::WindowState state); HWND handle() const { return m_data.hwnd; } @@ -238,6 +238,7 @@ public: void setEnabled(bool enabled); bool isEnabled() const; + void setWindowIcon(const QIcon &icon); #ifndef Q_OS_WINCE void alertWindow(int durationMs = 0); @@ -259,6 +260,7 @@ private: void unregisterDropSite(); void handleGeometryChange(); void handleWindowStateChange(Qt::WindowState state); + inline void destroyIcon(); mutable WindowData m_data; mutable unsigned m_flags; @@ -277,6 +279,8 @@ private: #ifdef Q_OS_WINCE bool m_previouslyHidden; #endif + HICON m_iconSmall; + HICON m_iconBig; }; // Conveniences for window frames. @@ -346,6 +350,18 @@ void QWindowsWindow::setUserDataOf(HWND hwnd, void *ud) SetWindowLongPtr(hwnd, GWLP_USERDATA, LONG_PTR(ud)); } +inline void QWindowsWindow::destroyIcon() +{ + if (m_iconBig) { + DestroyIcon(m_iconBig); + m_iconBig = 0; + } + if (m_iconSmall) { + DestroyIcon(m_iconSmall); + m_iconSmall = 0; + } +} + QT_END_NAMESPACE #endif // QWINDOWSWINDOW_H diff --git a/src/plugins/platforms/xcb/README b/src/plugins/platforms/xcb/README index 6254d68ae8..264d28c6b4 100644 --- a/src/plugins/platforms/xcb/README +++ b/src/plugins/platforms/xcb/README @@ -9,3 +9,7 @@ The packages for xcb-render-util can be installed manually from http://packages. On Ubuntu 12.04 icccm1 is replaced by icccm4 and xcb-render-util can be installed automatically: libxcb1 libxcb1-dev libx11-xcb1 libx11-xcb-dev libxcb-keysyms1 libxcb-keysyms1-dev libxcb-image0 libxcb-image0-dev libxcb-shm0 libxcb-shm0-dev libxcb-icccm4 libxcb-icccm4-dev libxcb-sync0 libxcb-sync0-dev libxcb-xfixes0-dev libxrender-dev libxcb-shape0-dev libxcb-randr0-dev libxcb-render-util0 libxcb-render-util0-dev + + +On Fedora, the following packages are required: +libxcb libxcb-devel libXrender libXrender-devel xcb-util-wm xcb-util-wm-devel xcb-util xcb-util-devel xcb-util-image xcb-util-image-devel xcb-util-keysyms xcb-util-keysyms-devel diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp index cefe1a7786..bab1884a9a 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.cpp +++ b/src/plugins/platforms/xcb/qxcbwindow.cpp @@ -847,10 +847,10 @@ void QXcbWindow::changeNetWmState(bool set, xcb_atom_t one, xcb_atom_t two) Q_XCB_CALL(xcb_send_event(xcb_connection(), 0, m_screen->root(), XCB_EVENT_MASK_STRUCTURE_NOTIFY | XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT, (const char *)&event)); } -Qt::WindowState QXcbWindow::setWindowState(Qt::WindowState state) +void QXcbWindow::setWindowState(Qt::WindowState state) { if (state == m_windowState) - return state; + return; // unset old state switch (m_windowState) { @@ -905,7 +905,6 @@ Qt::WindowState QXcbWindow::setWindowState(Qt::WindowState state) connection()->sync(); m_windowState = state; - return m_windowState; } void QXcbWindow::setNetWmWindowFlags(Qt::WindowFlags flags) diff --git a/src/plugins/platforms/xcb/qxcbwindow.h b/src/plugins/platforms/xcb/qxcbwindow.h index e2f62401dc..bd4d18a175 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.h +++ b/src/plugins/platforms/xcb/qxcbwindow.h @@ -82,7 +82,7 @@ public: void setVisible(bool visible); void setWindowFlags(Qt::WindowFlags flags); - Qt::WindowState setWindowState(Qt::WindowState state); + void setWindowState(Qt::WindowState state); WId winId() const; void setParent(const QPlatformWindow *window); |