summaryrefslogtreecommitdiffstats
path: root/src/gui/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'src/gui/kernel')
-rw-r--r--src/gui/kernel/kernel.pri1
-rw-r--r--src/gui/kernel/qaction.h3
-rw-r--r--src/gui/kernel/qapplication.cpp256
-rw-r--r--src/gui/kernel/qapplication_mac.mm57
-rw-r--r--src/gui/kernel/qapplication_p.h13
-rw-r--r--src/gui/kernel/qapplication_x11.cpp5
-rw-r--r--src/gui/kernel/qcocoaapplicationdelegate_mac.mm7
-rw-r--r--src/gui/kernel/qcocoapanel_mac.mm1
-rw-r--r--src/gui/kernel/qcocoapanel_mac_p.h6
-rw-r--r--src/gui/kernel/qcocoasharedwindowmethods_mac_p.h188
-rw-r--r--src/gui/kernel/qcocoaview_mac.mm76
-rw-r--r--src/gui/kernel/qcocoaview_mac_p.h2
-rw-r--r--src/gui/kernel/qcocoawindow_mac.mm1
-rw-r--r--src/gui/kernel/qcocoawindow_mac_p.h3
-rw-r--r--src/gui/kernel/qcocoawindowdelegate_mac.mm7
-rw-r--r--src/gui/kernel/qcursor.cpp6
-rw-r--r--src/gui/kernel/qcursor_mac.mm24
-rw-r--r--src/gui/kernel/qcursor_win.cpp7
-rw-r--r--src/gui/kernel/qcursor_x11.cpp50
-rw-r--r--src/gui/kernel/qdnd.cpp218
-rw-r--r--src/gui/kernel/qdnd_p.h2
-rw-r--r--src/gui/kernel/qdnd_x11.cpp6
-rw-r--r--src/gui/kernel/qeventdispatcher_mac.mm415
-rw-r--r--src/gui/kernel/qeventdispatcher_mac_p.h11
-rw-r--r--src/gui/kernel/qguieventdispatcher_glib.cpp5
-rw-r--r--src/gui/kernel/qguieventdispatcher_glib_p.h1
-rw-r--r--src/gui/kernel/qkeysequence.cpp36
-rw-r--r--src/gui/kernel/qkeysequence.h12
-rw-r--r--src/gui/kernel/qmime_mac.cpp57
-rw-r--r--src/gui/kernel/qnsthemeframe_mac_p.h2
-rw-r--r--src/gui/kernel/qsoftkeymanager_s60.cpp16
-rw-r--r--src/gui/kernel/qsoftkeymanager_s60_p.h1
-rw-r--r--src/gui/kernel/qt_cocoa_helpers_mac.mm15
-rw-r--r--src/gui/kernel/qt_cocoa_helpers_mac_p.h4
-rw-r--r--src/gui/kernel/qt_x11_p.h2
-rw-r--r--src/gui/kernel/qwidget.cpp198
-rw-r--r--src/gui/kernel/qwidget_mac.mm180
-rw-r--r--src/gui/kernel/qwidget_p.h5
-rw-r--r--src/gui/kernel/qwidget_win.cpp21
39 files changed, 1260 insertions, 660 deletions
diff --git a/src/gui/kernel/kernel.pri b/src/gui/kernel/kernel.pri
index 0993b86..6fd45ad 100644
--- a/src/gui/kernel/kernel.pri
+++ b/src/gui/kernel/kernel.pri
@@ -206,6 +206,7 @@ embedded {
OBJECTIVE_HEADERS += \
qcocoawindow_mac_p.h \
+ qcocoapanel_mac_p.h \
qcocoawindowdelegate_mac_p.h \
qcocoaview_mac_p.h \
qcocoaapplication_mac_p.h \
diff --git a/src/gui/kernel/qaction.h b/src/gui/kernel/qaction.h
index 4341367..538b04f 100644
--- a/src/gui/kernel/qaction.h
+++ b/src/gui/kernel/qaction.h
@@ -246,6 +246,9 @@ private:
friend class QMenuBar;
friend class QShortcutMap;
friend class QToolButton;
+#ifdef Q_WS_MAC
+ friend void qt_mac_clear_status_text(QAction *action);
+#endif
};
QT_BEGIN_INCLUDE_NAMESPACE
diff --git a/src/gui/kernel/qapplication.cpp b/src/gui/kernel/qapplication.cpp
index 4fe3900..336be91 100644
--- a/src/gui/kernel/qapplication.cpp
+++ b/src/gui/kernel/qapplication.cpp
@@ -182,6 +182,15 @@ QApplicationPrivate::QApplicationPrivate(int &argc, char **argv, QApplication::T
gestureManager = 0;
gestureWidget = 0;
+#if defined(Q_WS_X11) || defined(Q_WS_WIN)
+ move_cursor = 0;
+ copy_cursor = 0;
+ link_cursor = 0;
+#endif
+#if defined(Q_WS_WIN)
+ ignore_cursor = 0;
+#endif
+
if (!self)
self = this;
}
@@ -925,7 +934,7 @@ void QApplicationPrivate::initialize()
// Set up which span functions should be used in raster engine...
qInitDrawhelperAsm();
-
+
#if !defined(Q_WS_X11) && !defined(Q_WS_QWS)
// initialize the graphics system - on X11 this is initialized inside
// qt_init() in qapplication_x11.cpp because of several reasons.
@@ -1032,6 +1041,15 @@ QApplication::~QApplication()
qt_clipboard = 0;
#endif
+#if defined(Q_WS_X11) || defined(Q_WS_WIN)
+ delete d->move_cursor; d->move_cursor = 0;
+ delete d->copy_cursor; d->copy_cursor = 0;
+ delete d->link_cursor; d->link_cursor = 0;
+#endif
+#if defined(Q_WS_WIN)
+ delete d->ignore_cursor; d->ignore_cursor = 0;
+#endif
+
delete QWidgetPrivate::mapper;
QWidgetPrivate::mapper = 0;
@@ -5246,10 +5264,20 @@ QInputContext *QApplication::inputContext() const
qic = QInputContextFactory::create(QLatin1String("xim"), that);
that->d_func()->inputContext = qic;
}
-#elif defined(Q_WS_S60)
+#elif defined(Q_OS_SYMBIAN)
if (!d->inputContext) {
QApplication *that = const_cast<QApplication *>(this);
- that->d_func()->inputContext = QInputContextFactory::create(QString::fromLatin1("coefep"), that);
+ const QStringList keys = QInputContextFactory::keys();
+ // Try hbim and coefep first, then try others.
+ if (keys.contains("hbim")) {
+ that->d_func()->inputContext = QInputContextFactory::create(QLatin1String("hbim"), that);
+ } else if (keys.contains("coefep")) {
+ that->d_func()->inputContext = QInputContextFactory::create(QLatin1String("coefep"), that);
+ } else {
+ for (int c = 0; c < keys.size() && !d->inputContext; ++c) {
+ that->d_func()->inputContext = QInputContextFactory::create(keys[c], that);
+ }
+ }
}
#endif
return d->inputContext;
@@ -5689,6 +5717,228 @@ QGestureManager* QGestureManager::instance()
return qAppPriv->gestureManager;
}
+// These pixmaps approximate the images in the Windows User Interface Guidelines.
+
+// XPM
+
+static const char * const move_xpm[] = {
+"11 20 3 1",
+". c None",
+#if defined(Q_WS_WIN)
+"a c #000000",
+"X c #FFFFFF", // Windows cursor is traditionally white
+#else
+"a c #FFFFFF",
+"X c #000000", // X11 cursor is traditionally black
+#endif
+"aa.........",
+"aXa........",
+"aXXa.......",
+"aXXXa......",
+"aXXXXa.....",
+"aXXXXXa....",
+"aXXXXXXa...",
+"aXXXXXXXa..",
+"aXXXXXXXXa.",
+"aXXXXXXXXXa",
+"aXXXXXXaaaa",
+"aXXXaXXa...",
+"aXXaaXXa...",
+"aXa..aXXa..",
+"aa...aXXa..",
+"a.....aXXa.",
+"......aXXa.",
+".......aXXa",
+".......aXXa",
+"........aa."};
+
+#ifdef Q_WS_WIN
+/* XPM */
+static const char * const ignore_xpm[] = {
+"24 30 3 1",
+". c None",
+"a c #000000",
+"X c #FFFFFF",
+"aa......................",
+"aXa.....................",
+"aXXa....................",
+"aXXXa...................",
+"aXXXXa..................",
+"aXXXXXa.................",
+"aXXXXXXa................",
+"aXXXXXXXa...............",
+"aXXXXXXXXa..............",
+"aXXXXXXXXXa.............",
+"aXXXXXXaaaa.............",
+"aXXXaXXa................",
+"aXXaaXXa................",
+"aXa..aXXa...............",
+"aa...aXXa...............",
+"a.....aXXa..............",
+"......aXXa.....XXXX.....",
+".......aXXa..XXaaaaXX...",
+".......aXXa.XaaaaaaaaX..",
+"........aa.XaaaXXXXaaaX.",
+"...........XaaaaX..XaaX.",
+"..........XaaXaaaX..XaaX",
+"..........XaaXXaaaX.XaaX",
+"..........XaaX.XaaaXXaaX",
+"..........XaaX..XaaaXaaX",
+"...........XaaX..XaaaaX.",
+"...........XaaaXXXXaaaX.",
+"............XaaaaaaaaX..",
+".............XXaaaaXX...",
+"...............XXXX....."};
+#endif
+
+/* XPM */
+static const char * const copy_xpm[] = {
+"24 30 3 1",
+". c None",
+"a c #000000",
+"X c #FFFFFF",
+#if defined(Q_WS_WIN) // Windows cursor is traditionally white
+"aa......................",
+"aXa.....................",
+"aXXa....................",
+"aXXXa...................",
+"aXXXXa..................",
+"aXXXXXa.................",
+"aXXXXXXa................",
+"aXXXXXXXa...............",
+"aXXXXXXXXa..............",
+"aXXXXXXXXXa.............",
+"aXXXXXXaaaa.............",
+"aXXXaXXa................",
+"aXXaaXXa................",
+"aXa..aXXa...............",
+"aa...aXXa...............",
+"a.....aXXa..............",
+"......aXXa..............",
+".......aXXa.............",
+".......aXXa.............",
+"........aa...aaaaaaaaaaa",
+#else
+"XX......................",
+"XaX.....................",
+"XaaX....................",
+"XaaaX...................",
+"XaaaaX..................",
+"XaaaaaX.................",
+"XaaaaaaX................",
+"XaaaaaaaX...............",
+"XaaaaaaaaX..............",
+"XaaaaaaaaaX.............",
+"XaaaaaaXXXX.............",
+"XaaaXaaX................",
+"XaaXXaaX................",
+"XaX..XaaX...............",
+"XX...XaaX...............",
+"X.....XaaX..............",
+"......XaaX..............",
+".......XaaX.............",
+".......XaaX.............",
+"........XX...aaaaaaaaaaa",
+#endif
+".............aXXXXXXXXXa",
+".............aXXXXXXXXXa",
+".............aXXXXaXXXXa",
+".............aXXXXaXXXXa",
+".............aXXaaaaaXXa",
+".............aXXXXaXXXXa",
+".............aXXXXaXXXXa",
+".............aXXXXXXXXXa",
+".............aXXXXXXXXXa",
+".............aaaaaaaaaaa"};
+
+/* XPM */
+static const char * const link_xpm[] = {
+"24 30 3 1",
+". c None",
+"a c #000000",
+"X c #FFFFFF",
+#if defined(Q_WS_WIN) // Windows cursor is traditionally white
+"aa......................",
+"aXa.....................",
+"aXXa....................",
+"aXXXa...................",
+"aXXXXa..................",
+"aXXXXXa.................",
+"aXXXXXXa................",
+"aXXXXXXXa...............",
+"aXXXXXXXXa..............",
+"aXXXXXXXXXa.............",
+"aXXXXXXaaaa.............",
+"aXXXaXXa................",
+"aXXaaXXa................",
+"aXa..aXXa...............",
+"aa...aXXa...............",
+"a.....aXXa..............",
+"......aXXa..............",
+".......aXXa.............",
+".......aXXa.............",
+"........aa...aaaaaaaaaaa",
+#else
+"XX......................",
+"XaX.....................",
+"XaaX....................",
+"XaaaX...................",
+"XaaaaX..................",
+"XaaaaaX.................",
+"XaaaaaaX................",
+"XaaaaaaaX...............",
+"XaaaaaaaaX..............",
+"XaaaaaaaaaX.............",
+"XaaaaaaXXXX.............",
+"XaaaXaaX................",
+"XaaXXaaX................",
+"XaX..XaaX...............",
+"XX...XaaX...............",
+"X.....XaaX..............",
+"......XaaX..............",
+".......XaaX.............",
+".......XaaX.............",
+"........XX...aaaaaaaaaaa",
+#endif
+".............aXXXXXXXXXa",
+".............aXXXaaaaXXa",
+".............aXXXXaaaXXa",
+".............aXXXaaaaXXa",
+".............aXXaaaXaXXa",
+".............aXXaaXXXXXa",
+".............aXXaXXXXXXa",
+".............aXXXaXXXXXa",
+".............aXXXXXXXXXa",
+".............aaaaaaaaaaa"};
+
+QPixmap QApplicationPrivate::getPixmapCursor(Qt::CursorShape cshape)
+{
+ if (!move_cursor) {
+ move_cursor = new QPixmap((const char **)move_xpm);
+ copy_cursor = new QPixmap((const char **)copy_xpm);
+ link_cursor = new QPixmap((const char **)link_xpm);
+#ifdef Q_WS_WIN
+ ignore_cursor = new QPixmap((const char **)ignore_xpm);
+#endif
+ }
+
+ switch (cshape) {
+ case Qt::DragMoveCursor:
+ return *move_cursor;
+ case Qt::DragCopyCursor:
+ return *copy_cursor;
+ case Qt::DragLinkCursor:
+ return *link_cursor;
+#ifdef Q_WS_WIN
+ case Qt::ForbiddenCursor:
+ return *ignore_cursor;
+#endif
+ default:
+ break;
+ }
+ return QPixmap();
+}
+
QT_END_NAMESPACE
#include "moc_qapplication.cpp"
diff --git a/src/gui/kernel/qapplication_mac.mm b/src/gui/kernel/qapplication_mac.mm
index 54a4901..25c98c5 100644
--- a/src/gui/kernel/qapplication_mac.mm
+++ b/src/gui/kernel/qapplication_mac.mm
@@ -1258,10 +1258,6 @@ void qt_init(QApplicationPrivate *priv, int)
[cocoaApp setMenu:[qtMenuLoader menu]];
[newDelegate setMenuLoader:qtMenuLoader];
[qtMenuLoader release];
-
- NSAppleEventManager *eventManager = [NSAppleEventManager sharedAppleEventManager];
- [eventManager setEventHandler:newDelegate andSelector:@selector(getUrl:withReplyEvent:)
- forEventClass:kInternetEventClass andEventID:kAEGetURL];
}
#endif
// Register for Carbon tablet proximity events on the event monitor target.
@@ -1361,12 +1357,39 @@ void QApplication::setMainWidget(QWidget *mainWidget)
/*****************************************************************************
QApplication cursor stack
*****************************************************************************/
+#ifdef QT_MAC_USE_COCOA
+void QApplicationPrivate::disableUsageOfCursorRects(bool disable)
+{
+ // In Cocoa there are two competing ways of setting the cursor; either
+ // by using cursor rects (see qcocoaview_mac.mm), or by pushing/popping
+ // the cursor manually. When we use override cursors, it makes most sense
+ // to use the latter. But then we need to tell cocoa to stop using the
+ // first approach so it doesn't change the cursor back when hovering over
+ // a cursor rect:
+ QWidgetList topLevels = qApp->topLevelWidgets();
+ for (int i=0; i<topLevels.size(); ++i) {
+ if (NSWindow *window = qt_mac_window_for(topLevels.at(i)))
+ disable ? [window disableCursorRects] : [window enableCursorRects];
+ }
+}
+
+void QApplicationPrivate::updateOverrideCursor()
+{
+ // Sometimes Cocoa forgets that we have set a Cursor
+ // manually. In those cases, remind it again:
+ if (QCursor *override = qApp->overrideCursor())
+ [static_cast<NSCursor *>(qt_mac_nsCursorForQCursor(*override)) set];
+}
+#endif
+
void QApplication::setOverrideCursor(const QCursor &cursor)
{
qApp->d_func()->cursor_list.prepend(cursor);
#ifdef QT_MAC_USE_COCOA
QMacCocoaAutoReleasePool pool;
+ if (qApp->d_func()->cursor_list.size() == 1)
+ qApp->d_func()->disableUsageOfCursorRects(true);
[static_cast<NSCursor *>(qt_mac_nsCursorForQCursor(cursor)) push];
#else
if (qApp && qApp->activeWindow())
@@ -1383,6 +1406,8 @@ void QApplication::restoreOverrideCursor()
#ifdef QT_MAC_USE_COCOA
QMacCocoaAutoReleasePool pool;
[NSCursor pop];
+ if (qApp->d_func()->cursor_list.isEmpty())
+ qApp->d_func()->disableUsageOfCursorRects(false);
#else
if (qApp && qApp->activeWindow()) {
const QCursor def(Qt::ArrowCursor);
@@ -2457,6 +2482,28 @@ QApplicationPrivate::globalEventProcessor(EventHandlerCallRef er, EventRef event
#endif
}
+#ifdef QT_MAC_USE_COCOA
+void QApplicationPrivate::qt_initAfterNSAppStarted()
+{
+ setupAppleEvents();
+ updateOverrideCursor();
+}
+
+void QApplicationPrivate::setupAppleEvents()
+{
+ // This function is called from the event dispatcher when NSApplication has
+ // finished initialization, which appears to be just after [NSApplication run] has
+ // started to execute. By setting up our apple events handlers this late, we override
+ // the ones set up by NSApplication.
+ QT_MANGLE_NAMESPACE(QCocoaApplicationDelegate) *newDelegate = [QT_MANGLE_NAMESPACE(QCocoaApplicationDelegate) sharedDelegate];
+ NSAppleEventManager *eventManager = [NSAppleEventManager sharedAppleEventManager];
+ [eventManager setEventHandler:newDelegate andSelector:@selector(appleEventQuit:withReplyEvent:)
+ forEventClass:kCoreEventClass andEventID:kAEQuitApplication];
+ [eventManager setEventHandler:newDelegate andSelector:@selector(getUrl:withReplyEvent:)
+ forEventClass:kInternetEventClass andEventID:kAEGetURL];
+}
+#endif
+
// In Carbon this is your one stop for apple events.
// In Cocoa, it ISN'T. This is the catch-all Apple Event handler that exists
// for the time between instantiating the NSApplication, but before the
@@ -3008,7 +3055,7 @@ void onApplicationWindowChangedActivation(QWidget *widget, bool activated)
}
QMenuBar::macUpdateMenuBar();
-
+ QApplicationPrivate::updateOverrideCursor();
#else
Q_UNUSED(widget);
Q_UNUSED(activated);
diff --git a/src/gui/kernel/qapplication_p.h b/src/gui/kernel/qapplication_p.h
index b3ec732..e0a6103 100644
--- a/src/gui/kernel/qapplication_p.h
+++ b/src/gui/kernel/qapplication_p.h
@@ -459,6 +459,12 @@ public:
static OSStatus globalEventProcessor(EventHandlerCallRef, EventRef, void *);
static OSStatus globalAppleEventProcessor(const AppleEvent *, AppleEvent *, long);
static OSStatus tabletProximityCallback(EventHandlerCallRef, EventRef, void *);
+#ifdef QT_MAC_USE_COCOA
+ static void qt_initAfterNSAppStarted();
+ static void setupAppleEvents();
+ static void updateOverrideCursor();
+ static void disableUsageOfCursorRects(bool disable);
+#endif
static bool qt_mac_apply_settings();
#endif
@@ -514,6 +520,13 @@ public:
QGestureManager *gestureManager;
QWidget *gestureWidget;
+ QPixmap *move_cursor;
+ QPixmap *copy_cursor;
+ QPixmap *link_cursor;
+#if defined(Q_WS_WIN)
+ QPixmap *ignore_cursor;
+#endif
+ QPixmap getPixmapCursor(Qt::CursorShape cshape);
QMap<int, QWeakPointer<QWidget> > widgetForTouchPointId;
QMap<int, QTouchEvent::TouchPoint> appCurrentTouchPoints;
diff --git a/src/gui/kernel/qapplication_x11.cpp b/src/gui/kernel/qapplication_x11.cpp
index afd927b..34865b5 100644
--- a/src/gui/kernel/qapplication_x11.cpp
+++ b/src/gui/kernel/qapplication_x11.cpp
@@ -614,6 +614,11 @@ static int (*original_xio_errhandler)(Display *dpy);
static int qt_x_errhandler(Display *dpy, XErrorEvent *err)
{
+ if (X11->display != dpy) {
+ // only handle X errors for our display
+ return 0;
+ }
+
switch (err->error_code) {
case BadAtom:
if (err->request_code == 20 /* X_GetProperty */
diff --git a/src/gui/kernel/qcocoaapplicationdelegate_mac.mm b/src/gui/kernel/qcocoaapplicationdelegate_mac.mm
index 47a8026..ab71a05 100644
--- a/src/gui/kernel/qcocoaapplicationdelegate_mac.mm
+++ b/src/gui/kernel/qcocoaapplicationdelegate_mac.mm
@@ -317,5 +317,12 @@ static void cleanupCocoaApplicationDelegate()
qt_sendSpontaneousEvent(qAppInstance(), &qtEvent);
}
+- (void)appleEventQuit:(NSAppleEventDescriptor *)event withReplyEvent:(NSAppleEventDescriptor *)replyEvent
+{
+ Q_UNUSED(event);
+ Q_UNUSED(replyEvent);
+ [NSApp terminate:self];
+}
+
@end
#endif
diff --git a/src/gui/kernel/qcocoapanel_mac.mm b/src/gui/kernel/qcocoapanel_mac.mm
index 5e24c84..0b48efd 100644
--- a/src/gui/kernel/qcocoapanel_mac.mm
+++ b/src/gui/kernel/qcocoapanel_mac.mm
@@ -46,6 +46,7 @@
#import <private/qcocoawindowdelegate_mac_p.h>
#import <private/qcocoaview_mac_p.h>
#import <private/qcocoawindowcustomthemeframe_mac_p.h>
+#import <private/qcocoaapplication_mac_p.h>
#include <private/qapplication_p.h>
#include <private/qbackingstore_p.h>
diff --git a/src/gui/kernel/qcocoapanel_mac_p.h b/src/gui/kernel/qcocoapanel_mac_p.h
index fc83bd8..3678f81 100644
--- a/src/gui/kernel/qcocoapanel_mac_p.h
+++ b/src/gui/kernel/qcocoapanel_mac_p.h
@@ -54,10 +54,16 @@
#ifdef QT_MAC_USE_COCOA
#import <Cocoa/Cocoa.h>
+QT_FORWARD_DECLARE_CLASS(QStringList);
+
@interface QT_MANGLE_NAMESPACE(QCocoaPanel) : NSPanel {
bool leftButtonIsRightButton;
+ QStringList *currentCustomDragTypes;
}
+ (Class)frameViewClassForStyleMask:(NSUInteger)styleMask;
+- (void)registerDragTypes;
+
@end
#endif
+
diff --git a/src/gui/kernel/qcocoasharedwindowmethods_mac_p.h b/src/gui/kernel/qcocoasharedwindowmethods_mac_p.h
index d2b74d7..a1d2c61 100644
--- a/src/gui/kernel/qcocoasharedwindowmethods_mac_p.h
+++ b/src/gui/kernel/qcocoasharedwindowmethods_mac_p.h
@@ -57,8 +57,32 @@
QT_BEGIN_NAMESPACE
extern Qt::MouseButton cocoaButton2QtButton(NSInteger buttonNum); // qcocoaview.mm
extern QPointer<QWidget> qt_button_down; //qapplication_mac.cpp
+extern const QStringList& qEnabledDraggedTypes(); // qmime_mac.cpp
+extern bool qt_blockCocoaSettingModalWindowLevel; // qeventdispatcher_mac_p.h
+
+Q_GLOBAL_STATIC(QPointer<QWidget>, currentDragTarget);
+
QT_END_NAMESPACE
+- (id)initWithContentRect:(NSRect)contentRect
+ styleMask:(NSUInteger)windowStyle
+ backing:(NSBackingStoreType)bufferingType
+ defer:(BOOL)deferCreation
+{
+ self = [super initWithContentRect:contentRect styleMask:windowStyle
+ backing:bufferingType defer:deferCreation];
+ if (self) {
+ currentCustomDragTypes = 0;
+ }
+ return self;
+}
+
+- (void)dealloc
+{
+ delete currentCustomDragTypes;
+ [super dealloc];
+}
+
- (BOOL)canBecomeKeyWindow
{
QWidget *widget = [self QT_MANGLE_NAMESPACE(qt_qwidget)];
@@ -68,6 +92,40 @@ QT_END_NAMESPACE
return !(isPopup || isToolTip);
}
+- (BOOL)canBecomeMainWindow
+{
+ QWidget *widget = [self QT_MANGLE_NAMESPACE(qt_qwidget)];
+
+ bool isToolTip = (widget->windowType() == Qt::ToolTip);
+ bool isPopup = (widget->windowType() == Qt::Popup);
+ bool isTool = (widget->windowType() == Qt::Tool);
+ return !(isPopup || isToolTip || isTool);
+}
+
+- (void)orderWindow:(NSWindowOrderingMode)orderingMode relativeTo:(NSInteger)otherWindowNumber
+{
+ if (qt_blockCocoaSettingModalWindowLevel) {
+ // To avoid windows popping in front while restoring modal sessions
+ // in the event dispatcher, we block cocoa from ordering this window
+ // to front. The result of not doing this can be seen if executing
+ // a native color dialog on top of another executing dialog.
+ return;
+ }
+ [super orderWindow:orderingMode relativeTo:otherWindowNumber];
+}
+
+- (void)setLevel:(NSInteger)windowLevel
+{
+ if (qt_blockCocoaSettingModalWindowLevel) {
+ // To avoid windows popping in front while restoring modal sessions
+ // in the event dispatcher, we block cocoa from ordering this window
+ // to front. The result of not doing this can be seen if executing
+ // a native color dialog on top of another executing dialog.
+ return;
+ }
+ [super setLevel:windowLevel];
+}
+
- (void)toggleToolbarShown:(id)sender
{
macSendToolbarChangeEvent([self QT_MANGLE_NAMESPACE(qt_qwidget)]);
@@ -106,6 +164,23 @@ QT_END_NAMESPACE
qt_dispatchTabletProximityEvent(tabletEvent);
}
+- (void)qtDispatcherToQAction:(id)sender
+{
+ // If this window is modal, the menu bar will be modally shaddowed.
+ // In that case, since the window will be in the first responder chain,
+ // we can still catch the trigger here and forward it to the menu bar.
+ // This is needed as a single modal dialog on Qt should be able to access
+ // the application menu (e.g. quit).
+ [[NSApp QT_MANGLE_NAMESPACE(qt_qcocoamenuLoader)] qtDispatcherToQAction:sender];
+}
+
+- (void)terminate:(id)sender
+{
+ // This function is called from the quit item in the menubar when this window
+ // is in the first responder chain (see also qtDispatcherToQAction above)
+ [NSApp terminate:sender];
+}
+
- (void)sendEvent:(NSEvent *)event
{
QWidget *widget = [[QT_MANGLE_NAMESPACE(QCocoaWindowDelegate) sharedDelegate] qt_qwidgetForWindow:self];
@@ -133,7 +208,7 @@ QT_END_NAMESPACE
qt_button_down = widget;
handled = qt_mac_handleMouseEvent(view, event, QEvent::MouseButtonPress, mouseButton);
// Don't call super here. This prevents us from getting the mouseUp event,
- // which we need to send even if the mouseDown event was not accepted.
+ // which we need to send even if the mouseDown event was not accepted.
// (this is standard Qt behavior.)
break;
case NSRightMouseDown:
@@ -188,6 +263,115 @@ QT_END_NAMESPACE
return [super frameViewClassForStyleMask:styleMask];
}
+-(void)registerDragTypes
+{
+ // Calling registerForDraggedTypes below is slow, so only do
+ // it once for each window, or when the custom types change.
+ QMacCocoaAutoReleasePool pool;
+ const QStringList& customTypes = qEnabledDraggedTypes();
+ if (currentCustomDragTypes == 0 || *currentCustomDragTypes != customTypes) {
+ if (currentCustomDragTypes == 0)
+ currentCustomDragTypes = new QStringList();
+ *currentCustomDragTypes = customTypes;
+ const NSString* mimeTypeGeneric = @"com.trolltech.qt.MimeTypeName";
+ NSMutableArray *supportedTypes = [NSMutableArray arrayWithObjects:NSColorPboardType,
+ NSFilenamesPboardType, NSStringPboardType,
+ NSFilenamesPboardType, NSPostScriptPboardType, NSTIFFPboardType,
+ NSRTFPboardType, NSTabularTextPboardType, NSFontPboardType,
+ NSRulerPboardType, NSFileContentsPboardType, NSColorPboardType,
+ NSRTFDPboardType, NSHTMLPboardType, NSPICTPboardType,
+ NSURLPboardType, NSPDFPboardType, NSVCardPboardType,
+ NSFilesPromisePboardType, NSInkTextPboardType,
+ NSMultipleTextSelectionPboardType, mimeTypeGeneric, nil];
+ // Add custom types supported by the application.
+ for (int i = 0; i < customTypes.size(); i++) {
+ [supportedTypes addObject:reinterpret_cast<const NSString *>(QCFString::toCFStringRef(customTypes[i]))];
+ }
+ [self registerForDraggedTypes:supportedTypes];
+ }
+}
+
+- (QWidget *)dragTargetHitTest:(id <NSDraggingInfo>)sender
+{
+ // Do a hittest to find the NSView under the
+ // mouse, and return the corresponding QWidget:
+ NSPoint windowPoint = [sender draggingLocation];
+ NSView *candidateView = [[self contentView] hitTest:windowPoint];
+ if (![candidateView isKindOfClass:[QT_MANGLE_NAMESPACE(QCocoaView) class]])
+ return 0;
+ return [static_cast<QT_MANGLE_NAMESPACE(QCocoaView) *>(candidateView) qt_qwidget];
+}
+
+- (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender
+{
+ // The user dragged something into the window. Send a draggingEntered message
+ // to the QWidget under the mouse. As the drag moves over the window, and over
+ // different widgets, we will handle enter and leave events from within
+ // draggingUpdated below. The reason why we handle this ourselves rather than
+ // subscribing for drag events directly in QCocoaView is that calling
+ // registerForDraggedTypes on the views will severly degrade initialization time
+ // for an application that uses a lot of drag subscribing widgets.
+
+ QWidget *target = [self dragTargetHitTest:sender];
+ if (!target)
+ return [super draggingEntered:sender];
+ if (target->testAttribute(Qt::WA_DropSiteRegistered) == false)
+ return NSDragOperationNone;
+
+ *currentDragTarget() = target;
+ return [reinterpret_cast<NSView *>((*currentDragTarget())->winId()) draggingEntered:sender];
+ }
+
+- (NSDragOperation)draggingUpdated:(id < NSDraggingInfo >)sender
+{
+ QWidget *target = [self dragTargetHitTest:sender];
+ if (!target)
+ return [super draggingUpdated:sender];
+
+ if (target == *currentDragTarget()) {
+ // The drag continues to move over the widget that we have sendt
+ // a draggingEntered message to. So just update the view:
+ return [reinterpret_cast<NSView *>((*currentDragTarget())->winId()) draggingUpdated:sender];
+ } else {
+ // The widget under the mouse has changed.
+ // So we need to fake enter/leave events:
+ if (*currentDragTarget())
+ [reinterpret_cast<NSView *>((*currentDragTarget())->winId()) draggingExited:sender];
+ if (target->testAttribute(Qt::WA_DropSiteRegistered) == false) {
+ *currentDragTarget() = 0;
+ return NSDragOperationNone;
+ }
+ *currentDragTarget() = target;
+ return [reinterpret_cast<NSView *>((*currentDragTarget())->winId()) draggingEntered:sender];
+ }
+}
+
+- (void)draggingExited:(id < NSDraggingInfo >)sender
+{
+ QWidget *target = [self dragTargetHitTest:sender];
+ if (!target)
+ return [super draggingExited:sender];
+
+ if (*currentDragTarget()) {
+ [reinterpret_cast<NSView *>((*currentDragTarget())->winId()) draggingExited:sender];
+ *currentDragTarget() = 0;
+ }
+}
+
+- (BOOL)performDragOperation:(id < NSDraggingInfo >)sender
+{
+ QWidget *target = [self dragTargetHitTest:sender];
+ if (!target)
+ return [super performDragOperation:sender];
+
+ BOOL dropResult = NO;
+ if (*currentDragTarget()) {
+ dropResult = [reinterpret_cast<NSView *>((*currentDragTarget())->winId()) performDragOperation:sender];
+ *currentDragTarget() = 0;
+ }
+ return dropResult;
+}
+
- (void)displayIfNeeded
{
@@ -203,5 +387,3 @@ QT_END_NAMESPACE
}
[super displayIfNeeded];
}
-
-
diff --git a/src/gui/kernel/qcocoaview_mac.mm b/src/gui/kernel/qcocoaview_mac.mm
index ad64a91..873fb7e 100644
--- a/src/gui/kernel/qcocoaview_mac.mm
+++ b/src/gui/kernel/qcocoaview_mac.mm
@@ -81,7 +81,6 @@ Q_GLOBAL_STATIC(DnDParams, qMacDnDParams);
extern void qt_mac_update_cursor_at_global_pos(const QPoint &globalPos); // qcursor_mac.mm
extern bool qt_sendSpontaneousEvent(QObject *, QEvent *); // qapplication.cpp
extern OSViewRef qt_mac_nativeview_for(const QWidget *w); // qwidget_mac.mm
-extern const QStringList& qEnabledDraggedTypes(); // qmime_mac.cpp
extern QPointer<QWidget> qt_mouseover; //qapplication_mac.mm
extern QPointer<QWidget> qt_button_down; //qapplication_mac.cpp
@@ -212,7 +211,6 @@ extern "C" {
composingText = new QString();
composing = false;
sendKeyEvents = true;
- currentCustomTypes = 0;
[self setHidden:YES];
return self;
}
@@ -227,36 +225,12 @@ extern "C" {
object:self];
}
--(void)registerDragTypes
-{
- QMacCocoaAutoReleasePool pool;
- // Calling registerForDraggedTypes is slow, so only do it once for each widget
- // or when the custom types change.
- const QStringList& customTypes = qEnabledDraggedTypes();
- if (currentCustomTypes == 0 || *currentCustomTypes != customTypes) {
- if (currentCustomTypes == 0)
- currentCustomTypes = new QStringList();
- *currentCustomTypes = customTypes;
- const NSString* mimeTypeGeneric = @"com.trolltech.qt.MimeTypeName";
- NSMutableArray *supportedTypes = [NSMutableArray arrayWithObjects:NSColorPboardType,
- NSFilenamesPboardType, NSStringPboardType,
- NSFilenamesPboardType, NSPostScriptPboardType, NSTIFFPboardType,
- NSRTFPboardType, NSTabularTextPboardType, NSFontPboardType,
- NSRulerPboardType, NSFileContentsPboardType, NSColorPboardType,
- NSRTFDPboardType, NSHTMLPboardType, NSPICTPboardType,
- NSURLPboardType, NSPDFPboardType, NSVCardPboardType,
- NSFilesPromisePboardType, NSInkTextPboardType,
- NSMultipleTextSelectionPboardType, mimeTypeGeneric, nil];
- // Add custom types supported by the application.
- for (int i = 0; i < customTypes.size(); i++) {
- [supportedTypes addObject:reinterpret_cast<const NSString *>(QCFString::toCFStringRef(customTypes[i]))];
- }
- [self registerForDraggedTypes:supportedTypes];
- }
-}
-
- (void)resetCursorRects
{
+ // [NSView addCursorRect] is slow, so bail out early if we can:
+ if (NSIsEmptyRect([self visibleRect]))
+ return;
+
QWidget *cursorWidget = qwidget;
if (cursorWidget->testAttribute(Qt::WA_TransparentForMouseEvents))
@@ -300,15 +274,9 @@ extern "C" {
- (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender
{
- if (qwidget->testAttribute(Qt::WA_DropSiteRegistered) == false)
- return NSDragOperationNone;
+ // NB: This function is called from QCoocaWindow/QCocoaPanel rather than directly
+ // from Cocoa. They modify the drag target, and might fake enter/leave events.
NSPoint windowPoint = [sender draggingLocation];
- if (qwidget->testAttribute(Qt::WA_TransparentForMouseEvents)) {
- // pass the drag enter event to the view underneath.
- NSView *candidateView = [[[self window] contentView] hitTest:windowPoint];
- if (candidateView && candidateView != self)
- return [candidateView draggingEntered:sender];
- }
dragEnterSequence = [sender draggingSequenceNumber];
[self addDropData:sender];
QMimeData *mimeData = dropData;
@@ -361,13 +329,9 @@ extern "C" {
}
- (NSDragOperation)draggingUpdated:(id < NSDraggingInfo >)sender
{
+ // NB: This function is called from QCoocaWindow/QCocoaPanel rather than directly
+ // from Cocoa. They modify the drag target, and might fake enter/leave events.
NSPoint windowPoint = [sender draggingLocation];
- if (qwidget->testAttribute(Qt::WA_TransparentForMouseEvents)) {
- // pass the drag move event to the view underneath.
- NSView *candidateView = [[[self window] contentView] hitTest:windowPoint];
- if (candidateView && candidateView != self)
- return [candidateView draggingUpdated:sender];
- }
// in cases like QFocusFrame, the view under the mouse might
// not have received the drag enter. Generate a synthetic
// drag enter event for that view.
@@ -417,14 +381,10 @@ extern "C" {
- (void)draggingExited:(id < NSDraggingInfo >)sender
{
+ // NB: This function is called from QCoocaWindow/QCocoaPanel rather than directly
+ // from Cocoa. They modify the drag target, and might fake enter/leave events.
+ Q_UNUSED(sender);
dragEnterSequence = -1;
- if (qwidget->testAttribute(Qt::WA_TransparentForMouseEvents)) {
- // try sending the leave event to the last view which accepted drag enter.
- DnDParams *dndParams = [QT_MANGLE_NAMESPACE(QCocoaView) currentMouseEvent];
- NSView *candidateView = [[[self window] contentView] hitTest:dndParams->activeDragEnterPos];
- if (candidateView && candidateView != self)
- return [candidateView draggingExited:sender];
- }
// drag enter event was rejected, so ignore the move event.
if (dropData) {
QDragLeaveEvent de;
@@ -435,14 +395,10 @@ extern "C" {
- (BOOL)performDragOperation:(id <NSDraggingInfo>)sender
{
+ // NB: This function is called from QCoocaWindow/QCocoaPanel rather than directly
+ // from Cocoa. They modify the drag target, and might fake enter/leave events.
NSPoint windowPoint = [sender draggingLocation];
dragEnterSequence = -1;
- if (qwidget->testAttribute(Qt::WA_TransparentForMouseEvents)) {
- // pass the drop event to the view underneath.
- NSView *candidateView = [[[self window] contentView] hitTest:windowPoint];
- if (candidateView && candidateView != self)
- return [candidateView performDragOperation:sender];
- }
[self addDropData:sender];
NSPoint globalPoint = [[sender draggingDestinationWindow] convertBaseToScreen:windowPoint];
@@ -472,8 +428,6 @@ extern "C" {
{
delete composingText;
[[NSNotificationCenter defaultCenter] removeObserver:self];
- delete currentCustomTypes;
- [self unregisterDraggedTypes];
[super dealloc];
}
@@ -616,6 +570,10 @@ extern "C" {
- (void)updateTrackingAreas
{
+ // [NSView addTrackingArea] is slow, so bail out early if we can:
+ if (NSIsEmptyRect([self visibleRect]))
+ return;
+
QMacCocoaAutoReleasePool pool;
if (NSArray *trackingArray = [self trackingAreas]) {
NSUInteger size = [trackingArray count];
diff --git a/src/gui/kernel/qcocoaview_mac_p.h b/src/gui/kernel/qcocoaview_mac_p.h
index 797b4d5..4bb10c5 100644
--- a/src/gui/kernel/qcocoaview_mac_p.h
+++ b/src/gui/kernel/qcocoaview_mac_p.h
@@ -87,7 +87,6 @@ Q_GUI_EXPORT
int composingLength;
bool sendKeyEvents;
QString *composingText;
- QStringList *currentCustomTypes;
NSInteger dragEnterSequence;
}
- (id)initWithQWidget:(QWidget *)widget widgetPrivate:(QWidgetPrivate *)widgetprivate;
@@ -97,7 +96,6 @@ Q_GUI_EXPORT
- (NSDragOperation)draggingUpdated:(id < NSDraggingInfo >)sender;
- (void)draggingExited:(id < NSDraggingInfo >)sender;
- (BOOL)performDragOperation:(id <NSDraggingInfo>)sender;
-- (void)registerDragTypes;
- (void)removeDropData;
- (void)addDropData:(id <NSDraggingInfo>)sender;
- (void)setSupportedActions:(NSDragOperation)actions;
diff --git a/src/gui/kernel/qcocoawindow_mac.mm b/src/gui/kernel/qcocoawindow_mac.mm
index a644dfe..f1b642b 100644
--- a/src/gui/kernel/qcocoawindow_mac.mm
+++ b/src/gui/kernel/qcocoawindow_mac.mm
@@ -46,6 +46,7 @@
#import <private/qcocoaview_mac_p.h>
#import <private/qt_cocoa_helpers_mac_p.h>
#import <private/qcocoawindowcustomthemeframe_mac_p.h>
+#import <private/qcocoaapplication_mac_p.h>
#include <QtGui/QWidget>
diff --git a/src/gui/kernel/qcocoawindow_mac_p.h b/src/gui/kernel/qcocoawindow_mac_p.h
index 0474882..21f82df 100644
--- a/src/gui/kernel/qcocoawindow_mac_p.h
+++ b/src/gui/kernel/qcocoawindow_mac_p.h
@@ -73,9 +73,12 @@ QT_FORWARD_DECLARE_CLASS(QStringList);
@interface QT_MANGLE_NAMESPACE(QCocoaWindow) : NSWindow {
bool leftButtonIsRightButton;
+ QStringList *currentCustomDragTypes;
}
+ (Class)frameViewClassForStyleMask:(NSUInteger)styleMask;
+- (void)registerDragTypes;
+
@end
#endif
diff --git a/src/gui/kernel/qcocoawindowdelegate_mac.mm b/src/gui/kernel/qcocoawindowdelegate_mac.mm
index db87491..24498f8 100644
--- a/src/gui/kernel/qcocoawindowdelegate_mac.mm
+++ b/src/gui/kernel/qcocoawindowdelegate_mac.mm
@@ -269,9 +269,6 @@ static void cleanupCocoaWindowDelegate()
{
QWidget *qwidget = m_windowHash->value([notification object]);
Q_ASSERT(qwidget);
- if (qwidget->isActiveWindow())
- return; // Widget is already active, no need to go through re-activation.
-
onApplicationWindowChangedActivation(qwidget, true);
}
@@ -288,10 +285,6 @@ static void cleanupCocoaWindowDelegate()
{
QWidget *qwidget = m_windowHash->value([notification object]);
Q_ASSERT(qwidget);
- if (qwidget->isActiveWindow())
- return; // Widget is already active, no need to go through re-activation
-
-
onApplicationWindowChangedActivation(qwidget, true);
}
diff --git a/src/gui/kernel/qcursor.cpp b/src/gui/kernel/qcursor.cpp
index 0f0470c..f38e4f5 100644
--- a/src/gui/kernel/qcursor.cpp
+++ b/src/gui/kernel/qcursor.cpp
@@ -141,6 +141,12 @@ QT_BEGIN_NAMESPACE
\o Qt::WhatsThisCursor \o \c whats_this
\o \inlineimage cursor-closedhand.png
\o Qt::ClosedHandCursor \o \c closedhand
+ \row \o
+ \o Qt::DragMoveCursor \o \c dnd-move or \c move
+ \o
+ \o Qt::DragCopyCursor \o \c dnd-copy or \c copy
+ \row \o
+ \o Qt::DragLinkCursor \o \c dnd-link or \c link
\endtable
\sa QWidget, {fowler}{GUI Design Handbook: Cursors}
diff --git a/src/gui/kernel/qcursor_mac.mm b/src/gui/kernel/qcursor_mac.mm
index 48bb9cc..cfebf60 100644
--- a/src/gui/kernel/qcursor_mac.mm
+++ b/src/gui/kernel/qcursor_mac.mm
@@ -424,6 +424,18 @@ void QCursorData::update()
type = QCursorData::TYPE_ThemeCursor;
curs.cp.nscursor = [NSCursor closedHandCursor];
break;
+ case Qt::DragCopyCursor:
+ type = QCursorData::TYPE_ThemeCursor;
+ curs.cp.nscursor = [NSCursor dragCopyCursor];
+ break;
+ case Qt::DragMoveCursor:
+ type = QCursorData::TYPE_ThemeCursor;
+ curs.cp.nscursor = [NSCursor arrowCursor];
+ break;
+ case Qt::DragLinkCursor:
+ type = QCursorData::TYPE_ThemeCursor;
+ curs.cp.nscursor = [NSCursor dragLinkCursor];
+ break;
#define QT_USE_APPROXIMATE_CURSORS
#ifdef QT_USE_APPROXIMATE_CURSORS
case Qt::SizeVerCursor:
@@ -519,6 +531,18 @@ void QCursorData::update()
type = QCursorData::TYPE_ThemeCursor;
curs.tc.curs = kThemeClosedHandCursor;
break;
+ case Qt::DragMoveCursor:
+ type = QCursorData::TYPE_ThemeCursor;
+ curs.tc.curs = kThemeArrowCursor;
+ break;
+ case Qt::DragCopyCursor:
+ type = QCursorData::TYPE_ThemeCursor;
+ curs.tc.curs = kThemeCopyArrowCursor;
+ break;
+ case Qt::DragLinkCursor:
+ type = QCursorData::TYPE_ThemeCursor;
+ curs.tc.curs = kThemeAliasArrowCursor;
+ break;
#define QT_USE_APPROXIMATE_CURSORS
#ifdef QT_USE_APPROXIMATE_CURSORS
case Qt::SizeVerCursor:
diff --git a/src/gui/kernel/qcursor_win.cpp b/src/gui/kernel/qcursor_win.cpp
index 6f651d4..ae1c004 100644
--- a/src/gui/kernel/qcursor_win.cpp
+++ b/src/gui/kernel/qcursor_win.cpp
@@ -47,6 +47,7 @@
#include <qimage.h>
#include <qt_windows.h>
+#include <private/qapplication_p.h>
QT_BEGIN_NAMESPACE
@@ -470,6 +471,12 @@ void QCursorData::update()
#endif
return;
}
+ case Qt::DragCopyCursor:
+ case Qt::DragMoveCursor:
+ case Qt::DragLinkCursor: {
+ QPixmap pixmap = QApplicationPrivate::instance()->getPixmapCursor(cshape);
+ hcurs = create32BitCursor(pixmap, hx, hy);
+ }
default:
qWarning("QCursor::update: Invalid cursor shape %d", cshape);
return;
diff --git a/src/gui/kernel/qcursor_x11.cpp b/src/gui/kernel/qcursor_x11.cpp
index 3e83363..4e871a6 100644
--- a/src/gui/kernel/qcursor_x11.cpp
+++ b/src/gui/kernel/qcursor_x11.cpp
@@ -39,9 +39,11 @@
**
****************************************************************************/
+#include <qdebug.h>
#include <qdatastream.h>
#include <private/qcursor_p.h>
#include <private/qt_x11_p.h>
+#include <private/qapplication_p.h>
#include <qbitmap.h>
#include <qcursor.h>
#include <X11/cursorfont.h>
@@ -57,6 +59,7 @@
#endif // QT_NO_XFIXES
#include "qx11info_x11.h"
+#include <private/qpixmap_x11_p.h>
QT_BEGIN_NAMESPACE
@@ -262,12 +265,31 @@ void QCursorData::update()
"whats_this",
"left_ptr_watch",
"openhand",
- "closedhand"
+ "closedhand",
+ "copy",
+ "move",
+ "link"
};
#ifndef QT_NO_XCURSOR
- if (X11->ptrXcursorLibraryLoadCursor)
- hcurs = X11->ptrXcursorLibraryLoadCursor(dpy, cursorNames[cshape]);
+ if (X11->ptrXcursorLibraryLoadCursor) {
+ // special case for non-standard dnd-* cursors
+ switch (cshape) {
+ case Qt::DragCopyCursor:
+ hcurs = X11->ptrXcursorLibraryLoadCursor(dpy, "dnd-copy");
+ break;
+ case Qt::DragMoveCursor:
+ hcurs = X11->ptrXcursorLibraryLoadCursor(dpy, "dnd-move");
+ break;
+ case Qt::DragLinkCursor:
+ hcurs = X11->ptrXcursorLibraryLoadCursor(dpy, "dnd-link");
+ break;
+ default:
+ break;
+ }
+ if (!hcurs)
+ hcurs = X11->ptrXcursorLibraryLoadCursor(dpy, cursorNames[cshape]);
+ }
if (hcurs)
return;
#endif // QT_NO_XCURSOR
@@ -504,6 +526,19 @@ void QCursorData::update()
pm = XCreateBitmapFromData(dpy, rootwin, open ? openhand_bits : closedhand_bits, 16, 16);
pmm = XCreateBitmapFromData(dpy, rootwin, open ? openhandm_bits : closedhandm_bits, 16, 16);
hcurs = XCreatePixmapCursor(dpy, pm, pmm, &fg, &bg, 8, 8);
+ } else if (cshape == Qt::DragCopyCursor || cshape == Qt::DragMoveCursor
+ || cshape == Qt::DragLinkCursor) {
+ XColor bg, fg;
+ bg.red = 255 << 8;
+ bg.green = 255 << 8;
+ bg.blue = 255 << 8;
+ fg.red = 0;
+ fg.green = 0;
+ fg.blue = 0;
+ QImage image = QApplicationPrivate::instance()->getPixmapCursor(cshape).toImage();
+ pm = QX11PixmapData::createBitmapFromImage(image);
+ pmm = QX11PixmapData::createBitmapFromImage(image.createAlphaMask().convertToFormat(QImage::Format_MonoLSB));
+ hcurs = XCreatePixmapCursor(dpy, pm, pmm, &fg, &bg, 8, 8);
}
if (hcurs)
@@ -577,6 +612,15 @@ void QCursorData::update()
case Qt::BusyCursor:
sh = XC_watch;
break;
+ case Qt::DragCopyCursor:
+ sh = XC_tcross;
+ break;
+ case Qt::DragLinkCursor:
+ sh = XC_center_ptr;
+ break;
+ case Qt::DragMoveCursor:
+ sh = XC_top_left_arrow;
+ break;
#endif /* QT_USE_APPROXIMATE_CURSORS */
default:
qWarning("QCursor::update: Invalid cursor shape %d", cshape);
diff --git a/src/gui/kernel/qdnd.cpp b/src/gui/kernel/qdnd.cpp
index 21438a8..2b3a3d0 100644
--- a/src/gui/kernel/qdnd.cpp
+++ b/src/gui/kernel/qdnd.cpp
@@ -60,204 +60,12 @@
#include "qdebug.h"
#include <ctype.h>
+#include <private/qapplication_p.h>
+
#ifndef QT_NO_DRAGANDDROP
QT_BEGIN_NAMESPACE
-// These pixmaps approximate the images in the Windows User Interface Guidelines.
-
-// XPM
-
-static const char * const move_xpm[] = {
-"11 20 3 1",
-". c None",
-#if defined(Q_WS_WIN)
-"a c #000000",
-"X c #FFFFFF", // Windows cursor is traditionally white
-#else
-"a c #FFFFFF",
-"X c #000000", // X11 cursor is traditionally black
-#endif
-"aa.........",
-"aXa........",
-"aXXa.......",
-"aXXXa......",
-"aXXXXa.....",
-"aXXXXXa....",
-"aXXXXXXa...",
-"aXXXXXXXa..",
-"aXXXXXXXXa.",
-"aXXXXXXXXXa",
-"aXXXXXXaaaa",
-"aXXXaXXa...",
-"aXXaaXXa...",
-"aXa..aXXa..",
-"aa...aXXa..",
-"a.....aXXa.",
-"......aXXa.",
-".......aXXa",
-".......aXXa",
-"........aa."};
-
-#ifdef Q_WS_WIN
-/* XPM */
-static const char * const ignore_xpm[] = {
-"24 30 3 1",
-". c None",
-"a c #000000",
-"X c #FFFFFF",
-"aa......................",
-"aXa.....................",
-"aXXa....................",
-"aXXXa...................",
-"aXXXXa..................",
-"aXXXXXa.................",
-"aXXXXXXa................",
-"aXXXXXXXa...............",
-"aXXXXXXXXa..............",
-"aXXXXXXXXXa.............",
-"aXXXXXXaaaa.............",
-"aXXXaXXa................",
-"aXXaaXXa................",
-"aXa..aXXa...............",
-"aa...aXXa...............",
-"a.....aXXa..............",
-"......aXXa.....XXXX.....",
-".......aXXa..XXaaaaXX...",
-".......aXXa.XaaaaaaaaX..",
-"........aa.XaaaXXXXaaaX.",
-"...........XaaaaX..XaaX.",
-"..........XaaXaaaX..XaaX",
-"..........XaaXXaaaX.XaaX",
-"..........XaaX.XaaaXXaaX",
-"..........XaaX..XaaaXaaX",
-"...........XaaX..XaaaaX.",
-"...........XaaaXXXXaaaX.",
-"............XaaaaaaaaX..",
-".............XXaaaaXX...",
-"...............XXXX....."};
-#endif
-
-/* XPM */
-static const char * const copy_xpm[] = {
-"24 30 3 1",
-". c None",
-"a c #000000",
-"X c #FFFFFF",
-#if defined(Q_WS_WIN) // Windows cursor is traditionally white
-"aa......................",
-"aXa.....................",
-"aXXa....................",
-"aXXXa...................",
-"aXXXXa..................",
-"aXXXXXa.................",
-"aXXXXXXa................",
-"aXXXXXXXa...............",
-"aXXXXXXXXa..............",
-"aXXXXXXXXXa.............",
-"aXXXXXXaaaa.............",
-"aXXXaXXa................",
-"aXXaaXXa................",
-"aXa..aXXa...............",
-"aa...aXXa...............",
-"a.....aXXa..............",
-"......aXXa..............",
-".......aXXa.............",
-".......aXXa.............",
-"........aa...aaaaaaaaaaa",
-#else
-"XX......................",
-"XaX.....................",
-"XaaX....................",
-"XaaaX...................",
-"XaaaaX..................",
-"XaaaaaX.................",
-"XaaaaaaX................",
-"XaaaaaaaX...............",
-"XaaaaaaaaX..............",
-"XaaaaaaaaaX.............",
-"XaaaaaaXXXX.............",
-"XaaaXaaX................",
-"XaaXXaaX................",
-"XaX..XaaX...............",
-"XX...XaaX...............",
-"X.....XaaX..............",
-"......XaaX..............",
-".......XaaX.............",
-".......XaaX.............",
-"........XX...aaaaaaaaaaa",
-#endif
-".............aXXXXXXXXXa",
-".............aXXXXXXXXXa",
-".............aXXXXaXXXXa",
-".............aXXXXaXXXXa",
-".............aXXaaaaaXXa",
-".............aXXXXaXXXXa",
-".............aXXXXaXXXXa",
-".............aXXXXXXXXXa",
-".............aXXXXXXXXXa",
-".............aaaaaaaaaaa"};
-
-/* XPM */
-static const char * const link_xpm[] = {
-"24 30 3 1",
-". c None",
-"a c #000000",
-"X c #FFFFFF",
-#if defined(Q_WS_WIN) // Windows cursor is traditionally white
-"aa......................",
-"aXa.....................",
-"aXXa....................",
-"aXXXa...................",
-"aXXXXa..................",
-"aXXXXXa.................",
-"aXXXXXXa................",
-"aXXXXXXXa...............",
-"aXXXXXXXXa..............",
-"aXXXXXXXXXa.............",
-"aXXXXXXaaaa.............",
-"aXXXaXXa................",
-"aXXaaXXa................",
-"aXa..aXXa...............",
-"aa...aXXa...............",
-"a.....aXXa..............",
-"......aXXa..............",
-".......aXXa.............",
-".......aXXa.............",
-"........aa...aaaaaaaaaaa",
-#else
-"XX......................",
-"XaX.....................",
-"XaaX....................",
-"XaaaX...................",
-"XaaaaX..................",
-"XaaaaaX.................",
-"XaaaaaaX................",
-"XaaaaaaaX...............",
-"XaaaaaaaaX..............",
-"XaaaaaaaaaX.............",
-"XaaaaaaXXXX.............",
-"XaaaXaaX................",
-"XaaXXaaX................",
-"XaX..XaaX...............",
-"XX...XaaX...............",
-"X.....XaaX..............",
-"......XaaX..............",
-".......XaaX.............",
-".......XaaX.............",
-"........XX...aaaaaaaaaaa",
-#endif
-".............aXXXXXXXXXa",
-".............aXXXaaaaXXa",
-".............aXXXXaaaXXa",
-".............aXXXaaaaXXa",
-".............aXXaaaXaXXa",
-".............aXXaaXXXXXa",
-".............aXXaXXXXXXa",
-".............aXXXaXXXXXa",
-".............aXXXXXXXXXa",
-".............aaaaaaaaaaa"};
-
#ifndef QT_NO_DRAGANDDROP
//#define QDND_DEBUG
@@ -326,22 +134,9 @@ QDragManager::QDragManager()
{
Q_ASSERT(!instance);
-#ifdef Q_WS_WIN
- n_cursor = 4;
-#else
- n_cursor = 3;
-#endif
-
#ifdef Q_WS_QWS
currentActionForOverrideCursor = Qt::IgnoreAction;
#endif
- pm_cursor = new QPixmap[n_cursor];
- pm_cursor[0] = QPixmap((const char **)move_xpm);
- pm_cursor[1] = QPixmap((const char **)copy_xpm);
- pm_cursor[2] = QPixmap((const char **)link_xpm);
-#ifdef Q_WS_WIN
- pm_cursor[3] = QPixmap((const char **)ignore_xpm);
-#endif
object = 0;
beingCancelled = false;
restoreCursor = false;
@@ -362,7 +157,6 @@ QDragManager::~QDragManager()
QApplication::restoreOverrideCursor();
#endif
instance = 0;
- delete [] pm_cursor;
delete dropData;
}
@@ -379,14 +173,14 @@ QPixmap QDragManager::dragCursor(Qt::DropAction action) const
if (d && d->customCursors.contains(action))
return d->customCursors[action];
else if (action == Qt::MoveAction)
- return pm_cursor[0];
+ return QApplicationPrivate::instance()->getPixmapCursor(Qt::DragMoveCursor);
else if (action == Qt::CopyAction)
- return pm_cursor[1];
+ return QApplicationPrivate::instance()->getPixmapCursor(Qt::DragCopyCursor);
else if (action == Qt::LinkAction)
- return pm_cursor[2];
+ return QApplicationPrivate::instance()->getPixmapCursor(Qt::DragLinkCursor);
#ifdef Q_WS_WIN
else if (action == Qt::IgnoreAction)
- return pm_cursor[3];
+ return QApplicationPrivate::instance()->getPixmapCursor(Qt::ForbiddenCursor);
#endif
return QPixmap();
}
diff --git a/src/gui/kernel/qdnd_p.h b/src/gui/kernel/qdnd_p.h
index d70b983..033e6a6 100644
--- a/src/gui/kernel/qdnd_p.h
+++ b/src/gui/kernel/qdnd_p.h
@@ -261,8 +261,6 @@ public:
#endif
private:
- QPixmap *pm_cursor;
- int n_cursor;
#ifdef Q_WS_QWS
Qt::DropAction currentActionForOverrideCursor;
#endif
diff --git a/src/gui/kernel/qdnd_x11.cpp b/src/gui/kernel/qdnd_x11.cpp
index 33968bd..9591b9a 100644
--- a/src/gui/kernel/qdnd_x11.cpp
+++ b/src/gui/kernel/qdnd_x11.cpp
@@ -1340,9 +1340,9 @@ void QDragManager::updateCursor()
if (!noDropCursor) {
#ifndef QT_NO_CURSOR
noDropCursor = new QCursor(Qt::ForbiddenCursor);
- moveCursor = new QCursor(dragCursor(Qt::MoveAction), 0,0);
- copyCursor = new QCursor(dragCursor(Qt::CopyAction), 0,0);
- linkCursor = new QCursor(dragCursor(Qt::LinkAction), 0,0);
+ moveCursor = new QCursor(Qt::DragMoveCursor);
+ copyCursor = new QCursor(Qt::DragCopyCursor);
+ linkCursor = new QCursor(Qt::DragLinkCursor);
#endif
}
diff --git a/src/gui/kernel/qeventdispatcher_mac.mm b/src/gui/kernel/qeventdispatcher_mac.mm
index c7c7caf..c7d042d 100644
--- a/src/gui/kernel/qeventdispatcher_mac.mm
+++ b/src/gui/kernel/qeventdispatcher_mac.mm
@@ -90,11 +90,16 @@
#ifndef QT_NO_THREAD
# include "qmutex.h"
+#endif
QT_BEGIN_NAMESPACE
QT_USE_NAMESPACE
-#endif
+
+/*****************************************************************************
+ Internal variables and functions
+ *****************************************************************************/
+bool qt_blockCocoaSettingModalWindowLevel = false;
/*****************************************************************************
Externals
@@ -540,6 +545,12 @@ bool QEventDispatcherMac::processEvents(QEventLoop::ProcessEventsFlags flags)
{
Q_D(QEventDispatcherMac);
d->interrupt = false;
+
+#ifdef QT_MAC_USE_COCOA
+ bool interruptLater = false;
+ QtMacInterruptDispatcherHelp::cancelInterruptLater();
+#endif
+
// In case we end up recursing while we now process events, make sure
// that we send remaining posted Qt events before this call returns:
wakeUp();
@@ -554,25 +565,25 @@ bool QEventDispatcherMac::processEvents(QEventLoop::ProcessEventsFlags flags)
QMacCocoaAutoReleasePool pool;
NSEvent* event = 0;
- // If Qt is used as a plugin, or just added into a native cocoa
- // application, we should not run or stop NSApplication;
- // This will be done from outside Qt.
- // And if processEvents is called manually (rather than from QEventLoop), we
- // cannot enter a tight loop and block the call, but instead return after one flush:
- bool canExec_3rdParty = d->nsAppRunCalledByQt || ![NSApp isRunning];
- bool canExec_Qt = flags & QEventLoop::DialogExec || flags & QEventLoop::EventLoopExec;
+ // If Qt is used as a plugin, or as an extension in a native cocoa
+ // application, we should not run or stop NSApplication; This will be
+ // done from the application itself. And if processEvents is called
+ // manually (rather than from a QEventLoop), we cannot enter a tight
+ // loop and block this call, but instead we need to return after one flush:
+ const bool canExec_3rdParty = d->nsAppRunCalledByQt || ![NSApp isRunning];
+ const bool canExec_Qt = flags & QEventLoop::DialogExec || flags & QEventLoop::EventLoopExec;
if (canExec_Qt && canExec_3rdParty) {
// We can use exec-mode, meaning that we can stay in a tight loop until
- // interrupted. This is mostly an optimization, but it also allow us
- // to use [NSApp run], which is the recommended way of running applications
- // in cocoa. [NSApp run] should be called at least once for any cocoa app.
+ // interrupted. This is mostly an optimization, but it allow us to use
+ // [NSApp run], which is the normal code path for cocoa applications.
if (NSModalSession session = d->currentModalSession()) {
QBoolBlocker execGuard(d->currentExecIsNSAppRun, false);
while ([NSApp runModalSession:session] == NSRunContinuesResponse && !d->interrupt)
qt_mac_waitForMoreModalSessionEvents();
+
if (!d->interrupt && session == d->currentModalSessionCached) {
- // INVARIANT: Someone called e.g. [NSApp stopModal:] from outside the event
+ // Someone called [NSApp stopModal:] from outside the event
// dispatcher (e.g to stop a native dialog). But that call wrongly stopped
// 'session' as well. As a result, we need to restart all internal sessions:
d->temporarilyStopAllModalSessions();
@@ -583,54 +594,63 @@ bool QEventDispatcherMac::processEvents(QEventLoop::ProcessEventsFlags flags)
[NSApp run];
}
retVal = true;
- } else do {
- // INVARIANT: We cannot block the thread (and run in a tight loop).
+ } else {
+ // We cannot block the thread (and run in a tight loop).
// Instead we will process all current pending events and return.
- bool mustRelease = false;
-
- if (!(flags & QEventLoop::ExcludeUserInputEvents) && !d->queuedUserInputEvents.isEmpty()) {
- // Process a pending user input event
- mustRelease = true;
- event = static_cast<NSEvent *>(d->queuedUserInputEvents.takeFirst());
- } else {
- if (NSModalSession session = d->currentModalSession()) {
- if (flags & QEventLoop::WaitForMoreEvents)
- qt_mac_waitForMoreModalSessionEvents();
- NSInteger status = [NSApp runModalSession:session];
- if (status != NSRunContinuesResponse && session == d->currentModalSessionCached) {
- // INVARIANT: Someone called e.g. [NSApp stopModal:] from outside the event
- // dispatcher (e.g to stop a native dialog). But that call wrongly stopped
- // 'session' as well. As a result, we need to restart all internal sessions:
- d->temporarilyStopAllModalSessions();
- }
- retVal = true;
- break;
+ d->ensureNSAppInitialized();
+ do {
+ bool releaseEvent = false;
+
+ if (!(flags & QEventLoop::ExcludeUserInputEvents)
+ && !d->queuedUserInputEvents.isEmpty()) {
+ // Process a pending user input event
+ releaseEvent = true;
+ event = static_cast<NSEvent *>(d->queuedUserInputEvents.takeFirst());
} else {
- event = [NSApp nextEventMatchingMask:NSAnyEventMask
- untilDate:nil
- inMode:NSDefaultRunLoopMode
- dequeue: YES];
-
- if (event != nil) {
- if (flags & QEventLoop::ExcludeUserInputEvents) {
- if (IsMouseOrKeyEvent(event)) {
- // retain event here?
- [event retain];
- d->queuedUserInputEvents.append(event);
- continue;
+ if (NSModalSession session = d->currentModalSession()) {
+ if (flags & QEventLoop::WaitForMoreEvents)
+ qt_mac_waitForMoreModalSessionEvents();
+ NSInteger status = [NSApp runModalSession:session];
+ if (status != NSRunContinuesResponse && session == d->currentModalSessionCached) {
+ // INVARIANT: Someone called [NSApp stopModal:] from outside the event
+ // dispatcher (e.g to stop a native dialog). But that call wrongly stopped
+ // 'session' as well. As a result, we need to restart all internal sessions:
+ d->temporarilyStopAllModalSessions();
+ }
+ retVal = true;
+ break;
+ } else {
+ event = [NSApp nextEventMatchingMask:NSAnyEventMask
+ untilDate:nil
+ inMode:NSDefaultRunLoopMode
+ dequeue: YES];
+
+ if (event != nil) {
+ if (flags & QEventLoop::ExcludeUserInputEvents) {
+ if (IsMouseOrKeyEvent(event)) {
+ [event retain];
+ d->queuedUserInputEvents.append(event);
+ continue;
+ }
}
}
}
}
- }
- if (event) {
- if (!filterEvent(event) && qt_mac_send_event(flags, event, 0))
- retVal = true;
- if (mustRelease)
- [event release];
- }
- } while(!d->interrupt && event != nil);
-
+ if (event) {
+ if (!filterEvent(event) && qt_mac_send_event(flags, event, 0))
+ retVal = true;
+ if (releaseEvent)
+ [event release];
+ }
+ } while (!d->interrupt && event != nil);
+
+ // Since the window that holds modality might have changed while processing
+ // events, we we need to interrupt when we return back the previous process
+ // event recursion to ensure that we spin the correct modal session.
+ // We do the interruptLater at the end of the function to ensure that we don't
+ // disturb the 'wait for more events' below (as deleteLater will post an event):
+ interruptLater = true;
+ }
#else
do {
EventRef event;
@@ -682,25 +702,19 @@ bool QEventDispatcherMac::processEvents(QEventLoop::ProcessEventsFlags flags)
}
}
+ // If we're interrupted, we need to interrupt the _current_
+ // recursion as well to check if it is still supposed to be
+ // executing. This way we wind down the stack until we land
+ // on a recursion that again calls processEvents (typically
+ // from QEventLoop), and set interrupt to false:
+ if (d->interrupt)
+ interrupt();
+
#ifdef QT_MAC_USE_COCOA
- // In case we _now_ process events using [NSApp run], we need to stop it to
- // ensure that:
- // 1. the QEventLoop that called us is still executing, or
- // 2. we have a modal session that needs to be spun instead.
- // In case this is a plain call to processEvents (perhaps from a loop)
- // from the application (rather than from a QEventLoop), we delay the
- // interrupting until we/ actually enter a lower loop level (hence the
- // deffered delete of the object below):
- QtMacInterruptDispatcherHelp::interruptLater();
+ if (interruptLater)
+ QtMacInterruptDispatcherHelp::interruptLater();
#endif
- if (d->interrupt) {
- // We should continue to leave all recursion to processEvents until
- // processEvents is called again (e.g. from a QEventLoop that
- // was not yet told to quit:
- interrupt();
- }
-
return retVal;
}
@@ -729,39 +743,60 @@ void QEventDispatcherMac::flush()
*****************************************************************************/
MacTimerHash QEventDispatcherMacPrivate::macTimerHash;
bool QEventDispatcherMacPrivate::blockSendPostedEvents = false;
+bool QEventDispatcherMacPrivate::interrupt = false;
#ifdef QT_MAC_USE_COCOA
QStack<QCocoaModalSessionInfo> QEventDispatcherMacPrivate::cocoaModalSessionStack;
bool QEventDispatcherMacPrivate::currentExecIsNSAppRun = false;
+bool QEventDispatcherMacPrivate::modalSessionsTemporarilyStopped = false;
bool QEventDispatcherMacPrivate::nsAppRunCalledByQt = false;
+bool QEventDispatcherMacPrivate::cleanupModalSessionsNeeded = false;
NSModalSession QEventDispatcherMacPrivate::currentModalSessionCached = 0;
-int QEventDispatcherMacPrivate::activeModalSessionCount()
+void QEventDispatcherMacPrivate::ensureNSAppInitialized()
{
- // Returns the number of modal sessions created
- // (and not just pushed onto the stack, pending to be created)
- int count = 0;
- for (int i=cocoaModalSessionStack.size()-1; i>=0; --i) {
- QCocoaModalSessionInfo &info = cocoaModalSessionStack[i];
- if (info.session)
- ++count;
- }
- return count;
+ // Some elements in Cocoa require NSApplication to be running before
+ // they get fully initialized, in particular the menu bar. This
+ // function is intended for cases where a dialog is told to execute before
+ // QApplication::exec is called, or the application spins the events loop
+ // manually rather than calling QApplication:exec.
+ // The function makes sure that NSApplication starts running, but stops
+ // it again as soon as the send posted events callback is called. That way
+ // we let Cocoa finish the initialization it seems to need. We'll only
+ // apply this trick at most once for any application, and we avoid doing it
+ // for the common case where main just starts QApplication::exec.
+ if (nsAppRunCalledByQt || [NSApp isRunning])
+ return;
+ nsAppRunCalledByQt = true;
+ QBoolBlocker block1(interrupt, true);
+ QBoolBlocker block2(currentExecIsNSAppRun, true);
+ [NSApp run];
}
void QEventDispatcherMacPrivate::temporarilyStopAllModalSessions()
{
- // Stop all created modal session, and as such, make then
- // pending again. The next call to currentModalSession will
- // recreate the session on top again:
+ // Flush, and Stop, all created modal session, and as
+ // such, make them pending again. The next call to
+ // currentModalSession will recreate them again. The
+ // reason to stop all session like this is that otherwise
+ // a call [NSApp stop] would not stop NSApp, but rather
+ // the current modal session. So if we need to stop NSApp
+ // we need to stop all the modal session first. To avoid changing
+ // the stacking order of the windows while doing so, we put
+ // up a block that is used in QCocoaWindow and QCocoaPanel:
+ QBoolBlocker block1(blockSendPostedEvents, true);
+ QBoolBlocker block2(qt_blockCocoaSettingModalWindowLevel, true);
+
int stackSize = cocoaModalSessionStack.size();
for (int i=stackSize-1; i>=0; --i) {
QCocoaModalSessionInfo &info = cocoaModalSessionStack[i];
if (info.session) {
+ [NSApp runModalSession:info.session];
[NSApp endModalSession:info.session];
info.session = 0;
}
}
+ modalSessionsTemporarilyStopped = true;
currentModalSessionCached = 0;
}
@@ -775,23 +810,6 @@ NSModalSession QEventDispatcherMacPrivate::currentModalSession()
if (cocoaModalSessionStack.isEmpty())
return 0;
- // Since this code will end up calling our Qt event handler
- // (also from beginModalSessionForWindow), we need to block
- // that to avoid side effects of events beeing delivered:
- QBoolBlocker block(blockSendPostedEvents, true);
-
- if (![NSApp isRunning]) {
- // Sadly, we need to introduce this little event flush
- // to stop dialogs from blinking/poping in front if a
- // modal session restart was needed:
- while (NSEvent *event = [NSApp nextEventMatchingMask:0
- untilDate:nil
- inMode:NSDefaultRunLoopMode
- dequeue: YES]) {
- qt_mac_send_event(0, event, 0);
- }
- }
-
int sessionCount = cocoaModalSessionStack.size();
for (int i=0; i<sessionCount; ++i) {
QCocoaModalSessionInfo &info = cocoaModalSessionStack[i];
@@ -804,11 +822,28 @@ NSModalSession QEventDispatcherMacPrivate::currentModalSession()
NSWindow *window = qt_mac_window_for(info.widget);
if (!window)
continue;
+
+ ensureNSAppInitialized();
+ QBoolBlocker block1(blockSendPostedEvents, true);
info.session = [NSApp beginModalSessionForWindow:window];
}
currentModalSessionCached = info.session;
}
+ if (modalSessionsTemporarilyStopped && currentModalSessionCached) {
+ // After a call to temporarilyStopAllModalSessions, cocoa have
+ // now posted events to restore ended modal session windows to
+ // the correct window level. Those events will be processed
+ // _after_ our new calls to beginModalSessionForWindow have
+ // taken effect, which will end up stacking the windows wrong on
+ // screen. To work around this, we block cocoa from changing the
+ // stacking order of the windows, and flush out the pending events
+ // (the block is used in QCocoaWindow and QCocoaPanel):
+ QBoolBlocker block1(blockSendPostedEvents, true);
+ QBoolBlocker block2(qt_blockCocoaSettingModalWindowLevel, true);
+ [NSApp runModalSession:currentModalSessionCached];
+ }
+ modalSessionsTemporarilyStopped = false;
return currentModalSessionCached;
}
@@ -844,6 +879,34 @@ void QEventDispatcherMacPrivate::updateChildrenWorksWhenModal()
}
}
+void QEventDispatcherMacPrivate::cleanupModalSessions()
+{
+ // Go through the list of modal sessions, and end those
+ // that no longer has a widget assosiated; no widget means
+ // the the session has logically ended. The reason we wait like
+ // this to actually end the sessions for real (rather than at the
+ // point they were marked as stopped), is that ending a session
+ // when no other session runs below it on the stack will make cocoa
+ // drop some events on the floor.
+ QMacCocoaAutoReleasePool pool;
+ int stackSize = cocoaModalSessionStack.size();
+
+ for (int i=stackSize-1; i>=0; --i) {
+ QCocoaModalSessionInfo &info = cocoaModalSessionStack[i];
+ if (info.widget) {
+ currentModalSessionCached = info.session;
+ break;
+ }
+ cocoaModalSessionStack.remove(i);
+ currentModalSessionCached = 0;
+ if (info.session)
+ [NSApp endModalSession:info.session];
+ }
+
+ updateChildrenWorksWhenModal();
+ cleanupModalSessionsNeeded = false;
+}
+
void QEventDispatcherMacPrivate::beginModalSession(QWidget *widget)
{
// Add a new, empty (null), NSModalSession to the stack.
@@ -852,7 +915,7 @@ void QEventDispatcherMacPrivate::beginModalSession(QWidget *widget)
// is non-zero, and the session pointer is zero (it will become active upon a call to
// currentModalSession). A QCocoaModalSessionInfo is considered pending to be stopped if
// the widget pointer is zero, and the session pointer is non-zero (it will be fully
- // stopped in endModalSession().
+ // stopped in cleanupModalSessions()).
QCocoaModalSessionInfo info = {widget, 0};
cocoaModalSessionStack.push(info);
updateChildrenWorksWhenModal();
@@ -869,38 +932,21 @@ void QEventDispatcherMacPrivate::endModalSession(QWidget *widget)
int stackSize = cocoaModalSessionStack.size();
for (int i=stackSize-1; i>=0; --i) {
QCocoaModalSessionInfo &info = cocoaModalSessionStack[i];
- if (info.widget == widget)
+ if (info.widget == widget) {
info.widget = 0;
- }
-
- // Now we stop, and remove, all sessions marked as pending
- // to be stopped on _top_ of the stack, if any:
- bool needToInterruptEventDispatcher = false;
- bool needToUpdateChildrenWorksWhenModal = false;
-
- for (int i=stackSize-1; i>=0; --i) {
- QCocoaModalSessionInfo &info = cocoaModalSessionStack[i];
- if (info.widget)
- break;
- cocoaModalSessionStack.remove(i);
- needToUpdateChildrenWorksWhenModal = true;
- currentModalSessionCached = 0;
- if (info.session) {
- [NSApp endModalSession:info.session];
- needToInterruptEventDispatcher = true;
+ if (i == stackSize-1) {
+ // The top sessions ended. Interrupt the event dispatcher
+ // to start spinning the correct session immidiatly:
+ cleanupModalSessionsNeeded = true;
+ QEventDispatcherMac::instance()->interrupt();
+ }
}
}
-
- if (needToUpdateChildrenWorksWhenModal)
- updateChildrenWorksWhenModal();
- if (needToInterruptEventDispatcher)
- QEventDispatcherMac::instance()->interrupt();
}
#endif
QEventDispatcherMacPrivate::QEventDispatcherMacPrivate()
- : interrupt(false)
{
}
@@ -959,13 +1005,39 @@ Boolean QEventDispatcherMacPrivate::postedEventSourceEqualCallback(const void *i
inline static void processPostedEvents(QEventDispatcherMacPrivate *const d, const bool blockSendPostedEvents)
{
- if (blockSendPostedEvents || d->interrupt) {
+ if (blockSendPostedEvents) {
+ // We're told to not send posted events (because the event dispatcher
+ // is currently working on setting up the correct session to run). But
+ // we still need to make sure that we don't fall asleep until pending events
+ // are sendt, so we just signal this need, and return:
CFRunLoopSourceSignal(d->postedEventsSource);
- } else {
- if (!d->threadData->canWait || (d->serialNumber != d->lastSerial)) {
- d->lastSerial = d->serialNumber;
- QApplicationPrivate::sendPostedEvents(0, 0, d->threadData);
+ return;
+ }
+
+#ifdef QT_MAC_USE_COCOA
+ if (d->cleanupModalSessionsNeeded)
+ d->cleanupModalSessions();
+#endif
+
+ if (d->interrupt) {
+#ifdef QT_MAC_USE_COCOA
+ if (d->currentExecIsNSAppRun) {
+ // The event dispatcher has been interrupted. But since
+ // [NSApplication run] is running the event loop, we
+ // delayed stopping it until now (to let cocoa process
+ // pending cocoa events first).
+ if (d->currentModalSessionCached)
+ d->temporarilyStopAllModalSessions();
+ [NSApp stop:NSApp];
+ d->cancelWaitForMoreEvents();
}
+#endif
+ return;
+ }
+
+ if (!d->threadData->canWait || (d->serialNumber != d->lastSerial)) {
+ d->lastSerial = d->serialNumber;
+ QApplicationPrivate::sendPostedEvents(0, 0, d->threadData);
}
}
@@ -975,6 +1047,9 @@ void QEventDispatcherMacPrivate::firstLoopEntry(CFRunLoopObserverRef ref,
{
Q_UNUSED(ref);
Q_UNUSED(activity);
+#ifdef QT_MAC_USE_COCOA
+ QApplicationPrivate::qt_initAfterNSAppStarted();
+#endif
processPostedEvents(static_cast<QEventDispatcherMacPrivate *>(info), blockSendPostedEvents);
}
@@ -983,6 +1058,19 @@ void QEventDispatcherMacPrivate::postedEventsSourcePerformCallback(void *info)
processPostedEvents(static_cast<QEventDispatcherMacPrivate *>(info), blockSendPostedEvents);
}
+#ifdef QT_MAC_USE_COCOA
+void QEventDispatcherMacPrivate::cancelWaitForMoreEvents()
+{
+ // In case the event dispatcher is waiting for more
+ // events somewhere, we post a dummy event to wake it up:
+ QMacCocoaAutoReleasePool pool;
+ static const short NSAppShouldStopForQt = SHRT_MAX;
+ [NSApp postEvent:[NSEvent otherEventWithType:NSApplicationDefined location:NSZeroPoint
+ modifierFlags:0 timestamp:0. windowNumber:0 context:0
+ subtype:NSAppShouldStopForQt data1:0 data2:0] atStart:NO];
+}
+#endif
+
void QEventDispatcherMac::interrupt()
{
Q_D(QEventDispatcherMac);
@@ -992,20 +1080,14 @@ void QEventDispatcherMac::interrupt()
#ifndef QT_MAC_USE_COCOA
CFRunLoopStop(mainRunLoop());
#else
- QMacCocoaAutoReleasePool pool;
- // In case we wait for more events inside
- // processEvents (or NSApp run), post a dummy to wake it up:
- static const short NSAppShouldStopForQt = SHRT_MAX;
- [NSApp postEvent:[NSEvent otherEventWithType:NSApplicationDefined location:NSZeroPoint
- modifierFlags:0 timestamp:0. windowNumber:0 context:0
- subtype:NSAppShouldStopForQt data1:0 data2:0] atStart:NO];
-
- if (d->activeModalSessionCount() == 0) {
- // We should only stop NSApp if we actually started it (and
- // not some 3rd party application, e.g. if we are a plugin).
- if (d->nsAppRunCalledByQt)
- [NSApp stop:NSApp];
- }
+ // We do nothing more here than setting d->interrupt = true, and
+ // poke the event loop if it is sleeping. Actually stopping
+ // NSApp, or the current modal session, is done inside the send
+ // posted events callback. We do this to ensure that all current pending
+ // cocoa events gets delivered before we stop. Otherwise, if we now stop
+ // the last event loop recursion, cocoa will just drop pending posted
+ // events on the floor before we get a chance to reestablish a new session.
+ d->cancelWaitForMoreEvents();
#endif
}
@@ -1046,17 +1128,18 @@ QEventDispatcherMac::~QEventDispatcherMac()
CFRelease(d->firstTimeObserver);
}
-/////////////////////////////////////////////////////////////////////////////
-
#ifdef QT_MAC_USE_COCOA
QtMacInterruptDispatcherHelp* QtMacInterruptDispatcherHelp::instance = 0;
QtMacInterruptDispatcherHelp::QtMacInterruptDispatcherHelp() : cancelled(false)
{
- // This is the whole point of encapsulation this code
- // inside a class; we can make the code (inside destructor)
- // execute on lower loop level:
+ // The whole point of this class is that we enable a way to interrupt
+ // the event dispatcher when returning back to a lower recursion level
+ // than where interruptLater was called. This is needed to detect if
+ // [NSApp run] should still be running at the recursion level it is at.
+ // Since the interrupt is canceled if processEvents is called before
+ // this object gets deleted, we also avoid interrupting unnecessary.
deleteLater();
}
@@ -1064,34 +1147,26 @@ QtMacInterruptDispatcherHelp::~QtMacInterruptDispatcherHelp()
{
if (cancelled)
return;
-
instance = 0;
-
- if (QEventDispatcherMacPrivate::currentExecIsNSAppRun) {
- int activeCount = QEventDispatcherMacPrivate::activeModalSessionCount();
- if (activeCount > 0) {
- // The problem we now have hit: [NSApp stop] will not stop NSApp
- // if a session is active; it will stop the session instead.
- // So to stop NSApp, we need to temporarily stop all the
- // sessions, then stop NSApp, then restart the session on top again.
- // We need to do this to ensure that we're not stuck inside
- // [NSApp run] when we really should be running a modal session:
- QEventDispatcherMacPrivate::temporarilyStopAllModalSessions();
- }
- }
- // Always interrupt once more in case the modal session stack changed
- // while processEvents was called manually from within the application:
QEventDispatcherMac::instance()->interrupt();
}
-void QtMacInterruptDispatcherHelp::interruptLater() {
- if (instance) {
- instance->cancelled = true;
- delete instance;
- }
+void QtMacInterruptDispatcherHelp::cancelInterruptLater()
+{
+ if (!instance)
+ return;
+ instance->cancelled = true;
+ delete instance;
+ instance = 0;
+}
+
+void QtMacInterruptDispatcherHelp::interruptLater()
+{
+ cancelInterruptLater();
instance = new QtMacInterruptDispatcherHelp;
}
#endif
QT_END_NAMESPACE
+
diff --git a/src/gui/kernel/qeventdispatcher_mac_p.h b/src/gui/kernel/qeventdispatcher_mac_p.h
index a335f16..e932532 100644
--- a/src/gui/kernel/qeventdispatcher_mac_p.h
+++ b/src/gui/kernel/qeventdispatcher_mac_p.h
@@ -174,13 +174,17 @@ public:
static QStack<QCocoaModalSessionInfo> cocoaModalSessionStack;
static bool currentExecIsNSAppRun;
static bool nsAppRunCalledByQt;
+ static bool cleanupModalSessionsNeeded;
+ static bool modalSessionsTemporarilyStopped;
static NSModalSession currentModalSessionCached;
- static void updateChildrenWorksWhenModal();
static NSModalSession currentModalSession();
- static int activeModalSessionCount();
+ static void updateChildrenWorksWhenModal();
static void temporarilyStopAllModalSessions();
static void beginModalSession(QWidget *widget);
static void endModalSession(QWidget *widget);
+ static void cancelWaitForMoreEvents();
+ static void cleanupModalSessions();
+ static void ensureNSAppInitialized();
#endif
MacSocketHash macSockets;
@@ -190,7 +194,7 @@ public:
CFRunLoopObserverRef firstTimeObserver;
QAtomicInt serialNumber;
int lastSerial;
- bool interrupt;
+ static bool interrupt;
private:
static Boolean postedEventSourceEqualCallback(const void *info1, const void *info2);
static void postedEventsSourcePerformCallback(void *info);
@@ -211,6 +215,7 @@ class QtMacInterruptDispatcherHelp : public QObject
public:
static void interruptLater();
+ static void cancelInterruptLater();
};
#endif
diff --git a/src/gui/kernel/qguieventdispatcher_glib.cpp b/src/gui/kernel/qguieventdispatcher_glib.cpp
index 7b30741..ac2b5f7 100644
--- a/src/gui/kernel/qguieventdispatcher_glib.cpp
+++ b/src/gui/kernel/qguieventdispatcher_glib.cpp
@@ -216,4 +216,9 @@ void QGuiEventDispatcherGlib::startingUp()
g_source_add_poll(&d->x11EventSource->source, &d->x11EventSource->pollfd);
}
+void QGuiEventDispatcherGlib::flush()
+{
+ XFlush(X11->display);
+}
+
QT_END_NAMESPACE
diff --git a/src/gui/kernel/qguieventdispatcher_glib_p.h b/src/gui/kernel/qguieventdispatcher_glib_p.h
index ff778cc..758650b 100644
--- a/src/gui/kernel/qguieventdispatcher_glib_p.h
+++ b/src/gui/kernel/qguieventdispatcher_glib_p.h
@@ -71,6 +71,7 @@ public:
bool processEvents(QEventLoop::ProcessEventsFlags flags);
void startingUp();
+ void flush();
};
QT_END_NAMESPACE
diff --git a/src/gui/kernel/qkeysequence.cpp b/src/gui/kernel/qkeysequence.cpp
index 2a13546..99bf971 100644
--- a/src/gui/kernel/qkeysequence.cpp
+++ b/src/gui/kernel/qkeysequence.cpp
@@ -861,6 +861,8 @@ QKeySequence::QKeySequence()
Up to four key codes may be entered by separating them with
commas, e.g. "Alt+X,Ctrl+S,Q".
+ \a key should be in NativeText format.
+
This constructor is typically used with \link QObject::tr() tr
\endlink(), so that shortcut keys can be replaced in
translations:
@@ -877,6 +879,16 @@ QKeySequence::QKeySequence(const QString &key)
}
/*!
+ \since 4.x
+ Creates a key sequence from the \a key string based on \a format.
+*/
+QKeySequence::QKeySequence(const QString &key, QKeySequence::SequenceFormat format)
+{
+ d = new QKeySequencePrivate();
+ assign(key, format);
+}
+
+/*!
Constructs a key sequence with up to 4 keys \a k1, \a k2,
\a k3 and \a k4.
@@ -1055,9 +1067,24 @@ QKeySequence QKeySequence::mnemonic(const QString &text)
contain up to four key codes, provided they are separated by a
comma; for example, "Alt+X,Ctrl+S,Z". The return value is the
number of key codes added.
+ \a keys should be in NativeText format.
*/
int QKeySequence::assign(const QString &ks)
{
+ return assign(ks, NativeText);
+}
+
+/*!
+ \fn int QKeySequence::assign(const QString &keys, QKeySequence::SequenceFormat format)
+ \since 4.x
+
+ Adds the given \a keys to the key sequence (based on \a format).
+ \a keys may contain up to four key codes, provided they are
+ separated by a comma; for example, "Alt+X,Ctrl+S,Z". The return
+ value is the number of key codes added.
+*/
+int QKeySequence::assign(const QString &ks, QKeySequence::SequenceFormat format)
+{
QString keyseq = ks;
QString part;
int n = 0;
@@ -1086,7 +1113,7 @@ int QKeySequence::assign(const QString &ks)
}
part = keyseq.left(-1 == p ? keyseq.length() : p - diff);
keyseq = keyseq.right(-1 == p ? 0 : keyseq.length() - (p + 1));
- d->key[n] = decodeString(part);
+ d->key[n] = QKeySequencePrivate::decodeString(part, format);
++n;
}
return n;
@@ -1557,12 +1584,7 @@ QString QKeySequence::toString(SequenceFormat format) const
*/
QKeySequence QKeySequence::fromString(const QString &str, SequenceFormat format)
{
- QStringList sl = str.split(QLatin1String(", "));
- int keys[4] = {0, 0, 0, 0};
- int total = qMin(sl.count(), 4);
- for (int i = 0; i < total; ++i)
- keys[i] = QKeySequencePrivate::decodeString(sl[i], format);
- return QKeySequence(keys[0], keys[1], keys[2], keys[3]);
+ return QKeySequence(str, format);
}
/*****************************************************************************
diff --git a/src/gui/kernel/qkeysequence.h b/src/gui/kernel/qkeysequence.h
index 1409e28..5a973e3 100644
--- a/src/gui/kernel/qkeysequence.h
+++ b/src/gui/kernel/qkeysequence.h
@@ -141,8 +141,14 @@ public:
Quit
};
+ enum SequenceFormat {
+ NativeText,
+ PortableText
+ };
+
QKeySequence();
QKeySequence(const QString &key);
+ QKeySequence(const QString &key, SequenceFormat format);
QKeySequence(int k1, int k2 = 0, int k3 = 0, int k4 = 0);
QKeySequence(const QKeySequence &ks);
QKeySequence(StandardKey key);
@@ -160,11 +166,6 @@ public:
#endif
};
- enum SequenceFormat {
- NativeText,
- PortableText
- };
-
QString toString(SequenceFormat format = PortableText) const;
static QKeySequence fromString(const QString &str, SequenceFormat format = PortableText);
@@ -194,6 +195,7 @@ private:
static int decodeString(const QString &ks);
static QString encodeString(int key);
int assign(const QString &str);
+ int assign(const QString &str, SequenceFormat format);
void setKey(int key, int index);
QKeySequencePrivate *d;
diff --git a/src/gui/kernel/qmime_mac.cpp b/src/gui/kernel/qmime_mac.cpp
index 071f80d..c6fd184 100644
--- a/src/gui/kernel/qmime_mac.cpp
+++ b/src/gui/kernel/qmime_mac.cpp
@@ -154,6 +154,7 @@ CFStringRef qt_mac_mime_typeUTI = CFSTR("com.pasteboard.trolltech.marker");
\i public.url - converts to "text/uri-list"
\i public.file-url - converts to "text/uri-list"
\i public.tiff - converts to "application/x-qt-image"
+ \i public.vcard - converts to "text/plain"
\i com.apple.traditional-mac-plain-text - converts to "text/plain"
\i com.apple.pict - converts to "application/x-qt-image"
\endlist
@@ -909,6 +910,61 @@ QList<QByteArray> QMacPasteboardMimeUrl::convertFromMime(const QString &mime, QV
return ret;
}
+class QMacPasteboardMimeVCard : public QMacPasteboardMime
+{
+public:
+ QMacPasteboardMimeVCard() : QMacPasteboardMime(MIME_ALL){ }
+ QString convertorName();
+
+ QString flavorFor(const QString &mime);
+ QString mimeFor(QString flav);
+ bool canConvert(const QString &mime, QString flav);
+ QVariant convertToMime(const QString &mime, QList<QByteArray> data, QString flav);
+ QList<QByteArray> convertFromMime(const QString &mime, QVariant data, QString flav);
+};
+
+QString QMacPasteboardMimeVCard::convertorName()
+{
+ return QString("VCard");
+}
+
+bool QMacPasteboardMimeVCard::canConvert(const QString &mime, QString flav)
+{
+ return mimeFor(flav) == mime;
+}
+
+QString QMacPasteboardMimeVCard::flavorFor(const QString &mime)
+{
+ if(mime.startsWith(QLatin1String("text/plain")))
+ return QLatin1String("public.vcard");
+ return QString();
+}
+
+QString QMacPasteboardMimeVCard::mimeFor(QString flav)
+{
+ if (flav == QLatin1String("public.vcard"))
+ return QLatin1String("text/plain");
+ return QString();
+}
+
+QVariant QMacPasteboardMimeVCard::convertToMime(const QString &mime, QList<QByteArray> data, QString)
+{
+ QByteArray cards;
+ if (mime == QLatin1String("text/plain")) {
+ for (int i=0; i<data.size(); ++i)
+ cards += data[i];
+ }
+ return QVariant(cards);
+}
+
+QList<QByteArray> QMacPasteboardMimeVCard::convertFromMime(const QString &mime, QVariant data, QString)
+{
+ QList<QByteArray> ret;
+ if (mime == QLatin1String("text/plain"))
+ ret.append(data.toString().toUtf8());
+ return ret;
+}
+
#ifdef QT3_SUPPORT
class QMacPasteboardMimeQt3Any : public QMacPasteboardMime {
private:
@@ -1116,6 +1172,7 @@ void QMacPasteboardMime::initialize()
new QMacPasteboardMimeFileUri;
new QMacPasteboardMimeUrl;
new QMacPasteboardMimeTypeName;
+ new QMacPasteboardMimeVCard;
//make sure our "non-standard" types are always last! --Sam
new QMacPasteboardMimeAny;
#ifdef QT3_SUPPORT
diff --git a/src/gui/kernel/qnsthemeframe_mac_p.h b/src/gui/kernel/qnsthemeframe_mac_p.h
index 77a6963..d061b1b 100644
--- a/src/gui/kernel/qnsthemeframe_mac_p.h
+++ b/src/gui/kernel/qnsthemeframe_mac_p.h
@@ -157,7 +157,7 @@
- (void)resetCursorRects;
- (char)shouldBeTreatedAsInkEvent:fp8;
- (char)_shouldBeTreatedAsInkEventInInactiveWindow:fp8;
-- hitTest:(struct _NSPoint)fp8;
+//- hitTest:(struct _NSPoint)fp8; // collides with hittest in qcocoasharedwindowmethods_mac_p.h
- (NSRect)_leftGroupRect;
- (NSRect)_rightGroupRect;
- (void)_updateWidgets;
diff --git a/src/gui/kernel/qsoftkeymanager_s60.cpp b/src/gui/kernel/qsoftkeymanager_s60.cpp
index af84a8f..8ac1e31 100644
--- a/src/gui/kernel/qsoftkeymanager_s60.cpp
+++ b/src/gui/kernel/qsoftkeymanager_s60.cpp
@@ -66,17 +66,18 @@ QSoftKeyManagerPrivateS60::QSoftKeyManagerPrivateS60()
cachedCbaIconSize[1] = QSize(0,0);
cachedCbaIconSize[2] = QSize(0,0);
cachedCbaIconSize[3] = QSize(0,0);
- skipNextUpdate = false;
}
bool QSoftKeyManagerPrivateS60::skipCbaUpdate()
{
- // lets not update softkeys if
+ // Lets not update softkeys if
// 1. We don't have application panes, i.e. cba
- // 2. S60 native dialog or menu is shown
- if (QApplication::testAttribute(Qt::AA_S60DontConstructApplicationPanes) ||
- CCoeEnv::Static()->AppUi()->IsDisplayingMenuOrDialog() || skipNextUpdate) {
- skipNextUpdate = false;
+ // 2. Our CBA is not active, i.e. S60 native dialog or menu with custom CBA is shown
+ // Note: Cannot use IsDisplayingMenuOrDialog since CBA update can be triggered before
+ // menu/dialog CBA is actually displayed i.e. it is being costructed.
+ CEikButtonGroupContainer *appUiCba = S60->buttonGroupContainer();
+ CEikButtonGroupContainer *currentCba = CEikButtonGroupContainer::Current();
+ if (QApplication::testAttribute(Qt::AA_S60DontConstructApplicationPanes) || appUiCba != currentCba) {
return true;
}
return false;
@@ -384,9 +385,6 @@ bool QSoftKeyManagerPrivateS60::handleCommand(int command)
}
qt_symbian_next_menu_from_action(actionContainer);
QT_TRAP_THROWING(S60->menuBar()->TryDisplayMenuBarL());
- // TODO: hack remove, it can happen that IsDisplayingMenuOrDialog return false
- // in updateSoftKeys_sys, and we will override menu CBA with our own
- skipNextUpdate = true;
} else {
Q_ASSERT(action->softKeyRole() != QAction::NoSoftKey);
QWidget *actionParent = action->parentWidget();
diff --git a/src/gui/kernel/qsoftkeymanager_s60_p.h b/src/gui/kernel/qsoftkeymanager_s60_p.h
index f8bd6d9..823a2db 100644
--- a/src/gui/kernel/qsoftkeymanager_s60_p.h
+++ b/src/gui/kernel/qsoftkeymanager_s60_p.h
@@ -98,7 +98,6 @@ private:
private:
QHash<int, QAction*> realSoftKeyActions;
QSize cachedCbaIconSize[4];
- bool skipNextUpdate;
};
diff --git a/src/gui/kernel/qt_cocoa_helpers_mac.mm b/src/gui/kernel/qt_cocoa_helpers_mac.mm
index 65c04e5..4e51cf4 100644
--- a/src/gui/kernel/qt_cocoa_helpers_mac.mm
+++ b/src/gui/kernel/qt_cocoa_helpers_mac.mm
@@ -1281,6 +1281,21 @@ void qt_cocoaChangeOverrideCursor(const QCursor &cursor)
}
#endif
+@implementation DebugNSApplication {
+}
+- (void)sendEvent:(NSEvent *)event
+{
+ NSLog(@"NSAppDebug: sendEvent: %@", event);
+ return [super sendEvent:event];
+}
+
+- (BOOL)sendAction:(SEL)anAction to:(id)aTarget from:(id)sender
+{
+ NSLog(@"NSAppDebug: sendAction: %s to %@ from %@", anAction, aTarget, sender);
+ return [super sendAction:anAction to:aTarget from:sender];
+}
+@end
+
QMacCocoaAutoReleasePool::QMacCocoaAutoReleasePool()
{
#ifndef QT_MAC_USE_COCOA
diff --git a/src/gui/kernel/qt_cocoa_helpers_mac_p.h b/src/gui/kernel/qt_cocoa_helpers_mac_p.h
index 6f0c4ce..ace8255 100644
--- a/src/gui/kernel/qt_cocoa_helpers_mac_p.h
+++ b/src/gui/kernel/qt_cocoa_helpers_mac_p.h
@@ -181,6 +181,10 @@ inline QString qt_mac_NSStringToQString(const NSString *nsstr)
inline NSString *qt_mac_QStringToNSString(const QString &qstr)
{ return [reinterpret_cast<const NSString *>(QCFString::toCFStringRef(qstr)) autorelease]; }
+
+@interface DebugNSApplication : NSApplication {}
+@end
+
#endif
QT_END_NAMESPACE
diff --git a/src/gui/kernel/qt_x11_p.h b/src/gui/kernel/qt_x11_p.h
index d110084..b2ce754 100644
--- a/src/gui/kernel/qt_x11_p.h
+++ b/src/gui/kernel/qt_x11_p.h
@@ -331,7 +331,7 @@ struct QXdndDropTransaction
class QMimeData;
struct QX11Data;
-extern QX11Data *qt_x11Data;
+extern Q_GUI_EXPORT QX11Data *qt_x11Data;
enum DesktopEnvironment {
DE_UNKNOWN,
diff --git a/src/gui/kernel/qwidget.cpp b/src/gui/kernel/qwidget.cpp
index 2a19d23..d433048 100644
--- a/src/gui/kernel/qwidget.cpp
+++ b/src/gui/kernel/qwidget.cpp
@@ -4876,90 +4876,7 @@ void QWidget::unsetCursor()
void QWidget::render(QPaintDevice *target, const QPoint &targetOffset,
const QRegion &sourceRegion, RenderFlags renderFlags)
{
- Q_D(QWidget);
- if (!target) {
- qWarning("QWidget::render: null pointer to paint device");
- return;
- }
-
- const bool inRenderWithPainter = d->extra && d->extra->inRenderWithPainter;
- QRegion paintRegion = !inRenderWithPainter ? d->prepareToRender(sourceRegion, renderFlags)
- : sourceRegion;
- if (paintRegion.isEmpty())
- return;
-
-#ifndef Q_WS_MAC
- QPainter *oldSharedPainter = inRenderWithPainter ? d->sharedPainter() : 0;
-
- // Use the target's shared painter if set (typically set when doing
- // "other->render(widget);" in the widget's paintEvent.
- if (target->devType() == QInternal::Widget) {
- QWidgetPrivate *targetPrivate = static_cast<QWidget *>(target)->d_func();
- if (targetPrivate->extra && targetPrivate->extra->inRenderWithPainter) {
- QPainter *targetPainter = targetPrivate->sharedPainter();
- if (targetPainter && targetPainter->isActive())
- d->setSharedPainter(targetPainter);
- }
- }
-#endif
-
- // Use the target's redirected device if set and adjust offset and paint
- // region accordingly. This is typically the case when people call render
- // from the paintEvent.
- QPoint offset = targetOffset;
- offset -= paintRegion.boundingRect().topLeft();
- QPoint redirectionOffset;
- QPaintDevice *redirected = 0;
-
- if (target->devType() == QInternal::Widget)
- redirected = static_cast<QWidget *>(target)->d_func()->redirected(&redirectionOffset);
- if (!redirected)
- redirected = QPainter::redirected(target, &redirectionOffset);
-
- if (redirected) {
- target = redirected;
- offset -= redirectionOffset;
- }
-
- if (!inRenderWithPainter) { // Clip handled by shared painter (in qpainter.cpp).
- if (QPaintEngine *targetEngine = target->paintEngine()) {
- const QRegion targetSystemClip = targetEngine->systemClip();
- if (!targetSystemClip.isEmpty())
- paintRegion &= targetSystemClip.translated(-offset);
- }
- }
-
- // Set backingstore flags.
- int flags = QWidgetPrivate::DrawPaintOnScreen | QWidgetPrivate::DrawInvisible;
- if (renderFlags & DrawWindowBackground)
- flags |= QWidgetPrivate::DrawAsRoot;
-
- if (renderFlags & DrawChildren)
- flags |= QWidgetPrivate::DrawRecursive;
- else
- flags |= QWidgetPrivate::DontSubtractOpaqueChildren;
-
-#ifdef Q_WS_QWS
- flags |= QWidgetPrivate::DontSetCompositionMode;
-#endif
-
- if (target->devType() == QInternal::Printer) {
- QPainter p(target);
- d->render_helper(&p, targetOffset, paintRegion, renderFlags);
- return;
- }
-
-#ifndef Q_WS_MAC
- // Render via backingstore.
- d->drawWidget(target, paintRegion, offset, flags, d->sharedPainter());
-
- // Restore shared painter.
- if (oldSharedPainter)
- d->setSharedPainter(oldSharedPainter);
-#else
- // Render via backingstore (no shared painter).
- d->drawWidget(target, paintRegion, offset, flags, 0);
-#endif
+ d_func()->render(target, targetOffset, sourceRegion, renderFlags, false);
}
/*!
@@ -5405,6 +5322,97 @@ void QWidgetPrivate::drawWidget(QPaintDevice *pdev, const QRegion &rgn, const QP
}
}
+void QWidgetPrivate::render(QPaintDevice *target, const QPoint &targetOffset,
+ const QRegion &sourceRegion, QWidget::RenderFlags renderFlags,
+ bool readyToRender)
+{
+ Q_Q(QWidget);
+ if (!target) {
+ qWarning("QWidget::render: null pointer to paint device");
+ return;
+ }
+
+ const bool inRenderWithPainter = extra && extra->inRenderWithPainter;
+ QRegion paintRegion = !inRenderWithPainter && !readyToRender
+ ? prepareToRender(sourceRegion, renderFlags)
+ : sourceRegion;
+ if (paintRegion.isEmpty())
+ return;
+
+#ifndef Q_WS_MAC
+ QPainter *oldSharedPainter = inRenderWithPainter ? sharedPainter() : 0;
+
+ // Use the target's shared painter if set (typically set when doing
+ // "other->render(widget);" in the widget's paintEvent.
+ if (target->devType() == QInternal::Widget) {
+ QWidgetPrivate *targetPrivate = static_cast<QWidget *>(target)->d_func();
+ if (targetPrivate->extra && targetPrivate->extra->inRenderWithPainter) {
+ QPainter *targetPainter = targetPrivate->sharedPainter();
+ if (targetPainter && targetPainter->isActive())
+ setSharedPainter(targetPainter);
+ }
+ }
+#endif
+
+ // Use the target's redirected device if set and adjust offset and paint
+ // region accordingly. This is typically the case when people call render
+ // from the paintEvent.
+ QPoint offset = targetOffset;
+ offset -= paintRegion.boundingRect().topLeft();
+ QPoint redirectionOffset;
+ QPaintDevice *redirected = 0;
+
+ if (target->devType() == QInternal::Widget)
+ redirected = static_cast<QWidget *>(target)->d_func()->redirected(&redirectionOffset);
+ if (!redirected)
+ redirected = QPainter::redirected(target, &redirectionOffset);
+
+ if (redirected) {
+ target = redirected;
+ offset -= redirectionOffset;
+ }
+
+ if (!inRenderWithPainter) { // Clip handled by shared painter (in qpainter.cpp).
+ if (QPaintEngine *targetEngine = target->paintEngine()) {
+ const QRegion targetSystemClip = targetEngine->systemClip();
+ if (!targetSystemClip.isEmpty())
+ paintRegion &= targetSystemClip.translated(-offset);
+ }
+ }
+
+ // Set backingstore flags.
+ int flags = DrawPaintOnScreen | DrawInvisible;
+ if (renderFlags & QWidget::DrawWindowBackground)
+ flags |= DrawAsRoot;
+
+ if (renderFlags & QWidget::DrawChildren)
+ flags |= DrawRecursive;
+ else
+ flags |= DontSubtractOpaqueChildren;
+
+#ifdef Q_WS_QWS
+ flags |= DontSetCompositionMode;
+#endif
+
+ if (target->devType() == QInternal::Printer) {
+ QPainter p(target);
+ render_helper(&p, targetOffset, paintRegion, renderFlags);
+ return;
+ }
+
+#ifndef Q_WS_MAC
+ // Render via backingstore.
+ drawWidget(target, paintRegion, offset, flags, sharedPainter());
+
+ // Restore shared painter.
+ if (oldSharedPainter)
+ setSharedPainter(oldSharedPainter);
+#else
+ // Render via backingstore (no shared painter).
+ drawWidget(target, paintRegion, offset, flags, 0);
+#endif
+}
+
void QWidgetPrivate::paintSiblingsRecursive(QPaintDevice *pdev, const QObjectList& siblings, int index, const QRegion &rgn,
const QPoint &offset, int flags
#ifdef Q_BACKINGSTORE_SUBSURFACES
@@ -7592,23 +7600,21 @@ bool QWidgetPrivate::close_helper(CloseMode mode)
if (isMain)
QApplication::quit();
#endif
- // Attempt to close the application only if this widget has the
- // WA_QuitOnClose flag set set and has a non-visible parent
- quitOnClose = quitOnClose && (parentWidget.isNull() || !parentWidget->isVisible() || parentWidget->testAttribute(Qt::WA_DontShowOnScreen));
+ // Attempt to close the application only if this has WA_QuitOnClose set and a non-visible parent
+ quitOnClose = quitOnClose && (parentWidget.isNull() || !parentWidget->isVisible());
if (quitOnClose) {
- // If there is no non-withdrawn primary window left (except
- // the ones without QuitOnClose or with WA_DontShowOnScreen),
- // we emit the lastWindowClosed signal
+ /* if there is no non-withdrawn primary window left (except
+ the ones without QuitOnClose), we emit the lastWindowClosed
+ signal */
QWidgetList list = QApplication::topLevelWidgets();
bool lastWindowClosed = true;
for (int i = 0; i < list.size(); ++i) {
QWidget *w = list.at(i);
- if ((w->isVisible() && !w->testAttribute(Qt::WA_DontShowOnScreen))
- && !w->parentWidget() && w->testAttribute(Qt::WA_QuitOnClose)) {
- lastWindowClosed = false;
- break;
- }
+ if (!w->isVisible() || w->parentWidget() || !w->testAttribute(Qt::WA_QuitOnClose))
+ continue;
+ lastWindowClosed = false;
+ break;
}
if (lastWindowClosed)
QApplicationPrivate::emitLastWindowClosed();
@@ -8271,7 +8277,7 @@ bool QWidget::event(QEvent *event)
}
#ifdef QT_SOFTKEYS_ENABLED
- if (isWindow() && isActiveWindow())
+ if (isWindow())
QSoftKeyManager::updateSoftKeys();
#endif
diff --git a/src/gui/kernel/qwidget_mac.mm b/src/gui/kernel/qwidget_mac.mm
index 9e7517f..a5633d3 100644
--- a/src/gui/kernel/qwidget_mac.mm
+++ b/src/gui/kernel/qwidget_mac.mm
@@ -1917,13 +1917,15 @@ void QWidgetPrivate::determineWindowClass()
wclass = kDocumentWindowClass;
else if(popup || (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_5 && type == Qt::SplashScreen))
wclass = kModalWindowClass;
- else if(q->testAttribute(Qt::WA_ShowModal) || type == Qt::Dialog)
+ else if(type == Qt::Dialog)
wclass = kMovableModalWindowClass;
else if(type == Qt::ToolTip)
wclass = kHelpWindowClass;
else if(type == Qt::Tool || (QSysInfo::MacintoshVersion < QSysInfo::MV_10_5
&& type == Qt::SplashScreen))
wclass = kFloatingWindowClass;
+ else if(q->testAttribute(Qt::WA_ShowModal))
+ wclass = kMovableModalWindowClass;
else
wclass = kDocumentWindowClass;
@@ -2027,8 +2029,6 @@ void QWidgetPrivate::determineWindowClass()
for(int i = 0; tmp_wattr && known_attribs[i].name; i++) {
if((tmp_wattr & known_attribs[i].tag) == known_attribs[i].tag) {
tmp_wattr ^= known_attribs[i].tag;
- qDebug("Qt: internal: * %s %s", known_attribs[i].name,
- (GetAvailableWindowAttributes(wclass) & known_attribs[i].tag) ? "" : "(*)");
}
}
if(tmp_wattr)
@@ -2223,6 +2223,41 @@ void QWidgetPrivate::finishCreateWindow_sys_Carbon(OSWindowRef windowRef)
applyMaxAndMinSizeOnWindow();
}
#else // QT_MAC_USE_COCOA
+
+void QWidgetPrivate::setWindowLevel()
+{
+ Q_Q(QWidget);
+ const QWidget * const windowParent = q->window()->parentWidget();
+ const QWidget * const primaryWindow = windowParent ? windowParent->window() : 0;
+ NSInteger winLevel = -1;
+
+ if (q->windowType() == Qt::Popup) {
+ winLevel = NSPopUpMenuWindowLevel;
+ // Popup should be in at least the same level as its parent.
+ if (primaryWindow) {
+ OSWindowRef parentRef = qt_mac_window_for(primaryWindow);
+ winLevel = qMax([parentRef level], winLevel);
+ }
+ } else if (q->windowType() == Qt::Tool) {
+ winLevel = NSFloatingWindowLevel;
+ } else if (q->windowType() == Qt::Dialog) {
+ // Correct modality level (NSModalPanelWindowLevel) will be
+ // set by cocoa when creating a modal session later.
+ winLevel = NSNormalWindowLevel;
+ }
+
+ // StayOnTop window should appear above Tool windows.
+ if (data.window_flags & Qt::WindowStaysOnTopHint)
+ winLevel = NSPopUpMenuWindowLevel;
+ // Tooltips should appear above StayOnTop windows.
+ if (q->windowType() == Qt::ToolTip)
+ winLevel = NSScreenSaverWindowLevel;
+ // All other types are Normal level.
+ if (winLevel == -1)
+ winLevel = NSNormalWindowLevel;
+ [qt_mac_window_for(q) setLevel:winLevel];
+}
+
void QWidgetPrivate::finishCreateWindow_sys_Cocoa(void * /*NSWindow * */ voidWindowRef)
{
Q_Q(QWidget);
@@ -2295,6 +2330,10 @@ void QWidgetPrivate::finishCreateWindow_sys_Cocoa(void * /*NSWindow * */ voidWin
q->setAttribute(Qt::WA_WState_WindowOpacitySet, false);
}
+ if (qApp->overrideCursor())
+ [windowRef disableCursorRects];
+
+ setWindowLevel();
macUpdateHideOnSuspend();
macUpdateOpaqueSizeGrip();
macUpdateIgnoreMouseEvents();
@@ -2725,6 +2764,35 @@ void QWidgetPrivate::transferChildren()
}
}
+#ifdef QT_MAC_USE_COCOA
+void QWidgetPrivate::setSubWindowStacking(bool set)
+{
+ Q_Q(QWidget);
+ if (!q->isWindow() || !q->testAttribute(Qt::WA_WState_Created))
+ return;
+
+ if (QWidget *parent = q->parentWidget()) {
+ if (parent->testAttribute(Qt::WA_WState_Created)) {
+ if (set)
+ [qt_mac_window_for(parent) addChildWindow:qt_mac_window_for(q) ordered:NSWindowAbove];
+ else
+ [qt_mac_window_for(parent) removeChildWindow:qt_mac_window_for(q)];
+ }
+ }
+
+ QList<QWidget *> widgets = q->findChildren<QWidget *>();
+ for (int i=0; i<widgets.size(); ++i) {
+ QWidget *child = widgets.at(i);
+ if (child->isWindow() && child->testAttribute(Qt::WA_WState_Created)) {
+ if (set)
+ [qt_mac_window_for(q) addChildWindow:qt_mac_window_for(child) ordered:NSWindowAbove];
+ else
+ [qt_mac_window_for(q) removeChildWindow:qt_mac_window_for(child)];
+ }
+ }
+}
+#endif
+
void QWidgetPrivate::setParent_sys(QWidget *parent, Qt::WindowFlags f)
{
Q_Q(QWidget);
@@ -2879,7 +2947,6 @@ void QWidgetPrivate::setParent_sys(QWidget *parent, Qt::WindowFlags f)
current = current->parentWidget();
}
}
-
invalidateBuffer(q->rect());
qt_event_request_window_change(q);
}
@@ -3185,10 +3252,10 @@ void QWidget::activateWindow()
|| windowActive) {
#ifndef QT_MAC_USE_COCOA
ActivateWindow(win, true);
+ qApp->setActiveWindow(tlw);
#else
[win makeKeyWindow];
#endif
- qApp->setActiveWindow(tlw);
} else if(!isMinimized()) {
#ifndef QT_MAC_USE_COCOA
SelectWindow(win);
@@ -3341,13 +3408,23 @@ void QWidgetPrivate::show_sys()
#else
// sync the opacity value back (in case of a fade).
[window setAlphaValue:q->windowOpacity()];
- [window makeKeyAndOrderFront:window];
-
- // If this window is app modal, we need to start spinning
- // a modal session for it. Interrupting
- // the event dispatcher will make this happend:
- if (data.window_modality == Qt::ApplicationModal)
- QEventDispatcherMac::instance()->interrupt();
+ setSubWindowStacking(true);
+
+ QWidget *top = 0;
+ if (QApplicationPrivate::tryModalHelper(q, &top)) {
+ [window makeKeyAndOrderFront:window];
+ // If this window is app modal, we need to start spinning
+ // a modal session for it. Interrupting
+ // the event dispatcher will make this happend:
+ if (data.window_modality == Qt::ApplicationModal)
+ QEventDispatcherMac::instance()->interrupt();
+ } else {
+ // The window is modally shaddowed, so we need to make
+ // sure that we don't pop in front of the modal window:
+ [window orderFront:window];
+ if (NSWindow *modalWin = qt_mac_window_for(top))
+ [modalWin orderFront:window];
+ }
#endif
if (q->windowType() == Qt::Popup) {
if (q->focusWidget())
@@ -3366,8 +3443,6 @@ void QWidgetPrivate::show_sys()
} else if (!q->testAttribute(Qt::WA_ShowWithoutActivating)) {
#ifndef QT_MAC_USE_COCOA
qt_event_request_activate(q);
-#else
- [qt_mac_window_for(q) makeKeyWindow];
#endif
}
} else if(topData()->embedded || !q->parentWidget() || q->parentWidget()->isVisible()) {
@@ -3410,6 +3485,9 @@ void QWidgetPrivate::hide_sys()
QMacCocoaAutoReleasePool pool;
if(q->isWindow()) {
+#ifdef QT_MAC_USE_COCOA
+ setSubWindowStacking(false);
+#endif
OSWindowRef window = qt_mac_window_for(q);
if(qt_mac_is_macsheet(q)) {
#ifndef QT_MAC_USE_COCOA
@@ -3475,12 +3553,15 @@ void QWidgetPrivate::hide_sys()
}
#endif
}
- if(q->isActiveWindow() && !(q->windowType() == Qt::Popup)) {
+#ifndef QT_MAC_USE_COCOA
+ // If the window we now hide was the active window, we need
+ // to find, and activate another window on screen. NB: Cocoa takes care of this
+ // logic for us (and distinquishes between main windows and key windows)
+ if (q->isActiveWindow() && !(q->windowType() == Qt::Popup)) {
QWidget *w = 0;
if(q->parentWidget())
w = q->parentWidget()->window();
if(!w || (!w->isVisible() && !w->isMinimized())) {
-#ifndef QT_MAC_USE_COCOA
for (WindowPtr wp = GetFrontWindowOfClass(kMovableModalWindowClass, true);
wp; wp = GetNextWindowOfClass(wp, kMovableModalWindowClass, true)) {
if((w = qt_mac_find_window(wp)))
@@ -3500,24 +3581,12 @@ void QWidgetPrivate::hide_sys()
break;
}
}
-#else
- NSArray *windows = [NSApp windows];
- NSUInteger totalWindows = [windows count];
- for (NSUInteger i = 0; i < totalWindows; ++i) {
- OSWindowRef wp = [windows objectAtIndex:i];
- if ((w = qt_mac_find_window(wp)))
- break;
- }
-#endif
}
if(w && w->isVisible() && !w->isMinimized()) {
-#ifndef QT_MAC_USE_COCOA
- qt_event_request_activate(w);
-#else
- [qt_mac_window_for(w) makeKeyWindow];
-#endif
+ qt_event_request_activate(w);
}
}
+#endif
} else {
invalidateBuffer(q->rect());
#ifndef QT_MAC_USE_COCOA
@@ -4605,9 +4674,12 @@ void QWidgetPrivate::registerDropSite(bool on)
#ifndef QT_MAC_USE_COCOA
SetControlDragTrackingEnabled(qt_mac_nativeview_for(q), on);
#else
- NSView *view = qt_mac_nativeview_for(q);
- if (on && [view isKindOfClass:[QT_MANGLE_NAMESPACE(QCocoaView) class]]) {
- [static_cast<QT_MANGLE_NAMESPACE(QCocoaView) *>(view) registerDragTypes];
+ NSWindow *win = qt_mac_window_for(q);
+ if (on) {
+ if ([win isKindOfClass:[QT_MANGLE_NAMESPACE(QCocoaWindow) class]])
+ [static_cast<QT_MANGLE_NAMESPACE(QCocoaWindow) *>(win) registerDragTypes];
+ else if ([win isKindOfClass:[QT_MANGLE_NAMESPACE(QCocoaPanel) class]])
+ [static_cast<QT_MANGLE_NAMESPACE(QCocoaPanel) *>(win) registerDragTypes];
}
#endif
}
@@ -4761,7 +4833,7 @@ void QWidgetPrivate::setModal_sys()
bool alreadySheet = [windowRef styleMask] & NSDocModalWindowMask;
if (windowParent && q->windowModality() == Qt::WindowModal){
- // Window should be window-modal, which implies a sheet.
+ // INVARIANT: Window should be window-modal (which implies a sheet).
if (!alreadySheet) {
// NB: the following call will call setModal_sys recursivly:
recreateMacWindow();
@@ -4778,47 +4850,19 @@ void QWidgetPrivate::setModal_sys()
[static_cast<NSPanel *>(windowRef) setWorksWhenModal:YES];
}
} else {
- // Window shold not be window-modal, and as such, not a sheet.
+ // INVARIANT: Window shold _not_ be window-modal (and as such, not a sheet).
if (alreadySheet){
// NB: the following call will call setModal_sys recursivly:
recreateMacWindow();
windowRef = qt_mac_window_for(q);
}
- if (q->windowModality() == Qt::ApplicationModal) {
- [windowRef setLevel:NSModalPanelWindowLevel];
- } else if (primaryWindow && primaryWindow->windowModality() == Qt::ApplicationModal) {
- // INVARIANT: Our window is a dialog that has a dialog parent that is
- // application modal, or . This means that q is supposed to be on top of this
- // dialog and not be modally shaddowed:
- [windowRef setLevel:NSModalPanelWindowLevel];
+ if (q->windowModality() == Qt::NonModal
+ && primaryWindow && primaryWindow->windowModality() == Qt::ApplicationModal) {
+ // INVARIANT: Our window has a parent that is application modal.
+ // This means that q is supposed to be on top of this window and
+ // not be modally shaddowed:
if ([windowRef isKindOfClass:[NSPanel class]])
[static_cast<NSPanel *>(windowRef) setWorksWhenModal:YES];
- } else {
- // INVARIANT: q should not be modal.
- NSInteger winLevel = -1;
- if (q->windowType() == Qt::Popup) {
- winLevel = NSPopUpMenuWindowLevel;
- // Popup should be in at least the same level as its parent.
- if (primaryWindow) {
- OSWindowRef parentRef = qt_mac_window_for(primaryWindow);
- winLevel = qMax([parentRef level], winLevel);
- }
- } else if (q->windowType() == Qt::Tool) {
- winLevel = NSFloatingWindowLevel;
- } else if (q->windowType() == Qt::Dialog) {
- winLevel = NSModalPanelWindowLevel;
- }
-
- // StayOnTop window should appear above Tool windows.
- if (data.window_flags & Qt::WindowStaysOnTopHint)
- winLevel = NSPopUpMenuWindowLevel;
- // Tooltips should appear above StayOnTop windows.
- if (q->windowType() == Qt::ToolTip)
- winLevel = NSScreenSaverWindowLevel;
- // All other types are Normal level.
- if (winLevel == -1)
- winLevel = NSNormalWindowLevel;
- [windowRef setLevel:winLevel];
}
}
diff --git a/src/gui/kernel/qwidget_p.h b/src/gui/kernel/qwidget_p.h
index b421d30..75b4c12 100644
--- a/src/gui/kernel/qwidget_p.h
+++ b/src/gui/kernel/qwidget_p.h
@@ -158,6 +158,7 @@ struct QTLWExtra {
quint32 newCounterValueLo;
#endif
#elif defined(Q_WS_WIN) // <--------------------------------------------------------- WIN
+ uint hotkeyRegistered: 1; // Hot key from the STARTUPINFO has been registered.
HICON winIconBig; // internal big Windows icon
HICON winIconSmall; // internal small Windows icon
#elif defined(Q_WS_MAC) // <--------------------------------------------------------- MAC
@@ -385,6 +386,8 @@ public:
QRegion prepareToRender(const QRegion &region, QWidget::RenderFlags renderFlags);
void render_helper(QPainter *painter, const QPoint &targetOffset, const QRegion &sourceRegion,
QWidget::RenderFlags renderFlags);
+ void render(QPaintDevice *target, const QPoint &targetOffset, const QRegion &sourceRegion,
+ QWidget::RenderFlags renderFlags, bool readyToRender);
void drawWidget(QPaintDevice *pdev, const QRegion &rgn, const QPoint &offset, int flags,
QPainter *sharedPainter = 0, QWidgetBackingStore *backingStore = 0);
@@ -761,6 +764,8 @@ public:
void initWindowPtr();
void finishCreateWindow_sys_Carbon(OSWindowRef windowRef);
#else
+ void setSubWindowStacking(bool set);
+ void setWindowLevel();
void finishCreateWindow_sys_Cocoa(void * /*NSWindow * */ windowRef);
void syncCocoaMask();
void finishCocoaMaskSetup();
diff --git a/src/gui/kernel/qwidget_win.cpp b/src/gui/kernel/qwidget_win.cpp
index 10522ed..8cab387 100644
--- a/src/gui/kernel/qwidget_win.cpp
+++ b/src/gui/kernel/qwidget_win.cpp
@@ -1094,6 +1094,21 @@ void QWidgetPrivate::show_sys()
return;
}
+ if (data.window_flags & Qt::Window) {
+ QTLWExtra *extra = topData();
+ if (!extra->hotkeyRegistered) {
+ // Try to set the hotkey using information from STARTUPINFO
+ STARTUPINFO startupInfo;
+ GetStartupInfo(&startupInfo);
+ // If STARTF_USEHOTKEY is set, hStdInput is the virtual keycode
+ if (startupInfo.dwFlags & 0x00000200) {
+ WPARAM hotKey = (WPARAM)startupInfo.hStdInput;
+ SendMessage(data.winid, WM_SETHOTKEY, hotKey, 0);
+ }
+ extra->hotkeyRegistered = 1;
+ }
+ }
+
int sm = SW_SHOWNORMAL;
bool fakedMaximize = false;
if (q->isWindow()) {
@@ -1141,6 +1156,11 @@ void QWidgetPrivate::show_sys()
data.window_state |= Qt::WindowMinimized;
if (IsZoomed(q->internalWinId()))
data.window_state |= Qt::WindowMaximized;
+ // This is to resolve the problem where popups are opened from the
+ // system tray and not being implicitly activated
+ if (q->windowType() == Qt::Popup &&
+ (!q->parentWidget() || !q->parentWidget()->isActiveWindow()))
+ q->activateWindow();
}
winSetupGestures();
@@ -1687,6 +1707,7 @@ void QWidgetPrivate::deleteSysExtra()
void QWidgetPrivate::createTLSysExtra()
{
+ extra->topextra->hotkeyRegistered = 0;
extra->topextra->savedFlags = 0;
extra->topextra->winIconBig = 0;
extra->topextra->winIconSmall = 0;