summaryrefslogtreecommitdiffstats
path: root/src/gui/kernel
diff options
context:
space:
mode:
authorRohan McGovern <rohan.mcgovern@nokia.com>2010-02-01 06:02:59 (GMT)
committerRohan McGovern <rohan.mcgovern@nokia.com>2010-02-01 06:02:59 (GMT)
commitdc1cab966938edc5463f26189607ece134549a22 (patch)
treeecaab6c64758f41fa9cb5b376b395831a77e6c83 /src/gui/kernel
parent4915439de467d1119a46af66ea08dbe161d2f336 (diff)
parentbde40a9fa852107c237ac408f93a33b5955b9290 (diff)
downloadQt-dc1cab966938edc5463f26189607ece134549a22.zip
Qt-dc1cab966938edc5463f26189607ece134549a22.tar.gz
Qt-dc1cab966938edc5463f26189607ece134549a22.tar.bz2
Merge commit 'oslo1/master' into oslo1-master
Conflicts: doc/src/getting-started/installation.qdoc src/gui/dialogs/qfiledialog_win.cpp tools/assistant/tools/assistant/centralwidget.cpp tools/assistant/tools/assistant/helpviewer.cpp
Diffstat (limited to 'src/gui/kernel')
-rw-r--r--src/gui/kernel/kernel.pri1
-rw-r--r--src/gui/kernel/qapplication.cpp8
-rw-r--r--src/gui/kernel/qapplication_mac.mm57
-rw-r--r--src/gui/kernel/qapplication_p.h6
-rw-r--r--src/gui/kernel/qapplication_s60.cpp2
-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.h183
-rw-r--r--src/gui/kernel/qcocoaview_mac.mm78
-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/qdnd_s60.cpp2
-rw-r--r--src/gui/kernel/qeventdispatcher_mac.mm418
-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/qsound_s60.cpp2
-rw-r--r--src/gui/kernel/qt_cocoa_helpers_mac.mm18
-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_mac.mm180
-rw-r--r--src/gui/kernel/qwidget_p.h2
29 files changed, 780 insertions, 332 deletions
diff --git a/src/gui/kernel/kernel.pri b/src/gui/kernel/kernel.pri
index f2bd288..30cb043 100644
--- a/src/gui/kernel/kernel.pri
+++ b/src/gui/kernel/kernel.pri
@@ -201,6 +201,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/qapplication.cpp b/src/gui/kernel/qapplication.cpp
index 9a639c1..65840c8 100644
--- a/src/gui/kernel/qapplication.cpp
+++ b/src/gui/kernel/qapplication.cpp
@@ -923,14 +923,6 @@ void QApplicationPrivate::initialize()
// Set up which span functions should be used in raster engine...
qInitDrawhelperAsm();
-
-#ifdef QT_MAC_USE_COCOA
- // Use the raster graphics system by default on Cocoa, override with
- // -graphicssystem native
- if (graphics_system_name.isEmpty()) {
- graphics_system_name = QLatin1String("raster");
- }
-#endif
#if !defined(Q_WS_X11) && !defined(Q_WS_QWS)
// initialize the graphics system - on X11 this is initialized inside
diff --git a/src/gui/kernel/qapplication_mac.mm b/src/gui/kernel/qapplication_mac.mm
index 6aebef5..961a3f6 100644
--- a/src/gui/kernel/qapplication_mac.mm
+++ b/src/gui/kernel/qapplication_mac.mm
@@ -1239,10 +1239,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.
@@ -1341,12 +1337,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())
@@ -1363,6 +1386,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);
@@ -2435,6 +2460,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
@@ -2982,7 +3029,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 9c001ab..59565d4 100644
--- a/src/gui/kernel/qapplication_p.h
+++ b/src/gui/kernel/qapplication_p.h
@@ -457,6 +457,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
diff --git a/src/gui/kernel/qapplication_s60.cpp b/src/gui/kernel/qapplication_s60.cpp
index 6caac9f..20b8030 100644
--- a/src/gui/kernel/qapplication_s60.cpp
+++ b/src/gui/kernel/qapplication_s60.cpp
@@ -63,7 +63,7 @@
#include "private/qsoftkeymanager_p.h"
#include "apgwgnam.h" // For CApaWindowGroupName
-#include <MdaAudioTonePlayer.h> // For CMdaAudioToneUtility
+#include <mdaaudiotoneplayer.h> // For CMdaAudioToneUtility
#if defined(Q_WS_S60)
# if !defined(QT_NO_IM)
diff --git a/src/gui/kernel/qapplication_x11.cpp b/src/gui/kernel/qapplication_x11.cpp
index 2a1f655..667db39 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 e535aac..3012093 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 <QtGui/QWidget>
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 1a265d0..2117551 100644
--- a/src/gui/kernel/qcocoasharedwindowmethods_mac_p.h
+++ b/src/gui/kernel/qcocoasharedwindowmethods_mac_p.h
@@ -54,8 +54,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)];
@@ -65,6 +89,39 @@ 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);
+ return !(isPopup || isToolTip);
+}
+
+- (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)]);
@@ -103,6 +160,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];
@@ -185,3 +259,112 @@ 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;
+}
+
diff --git a/src/gui/kernel/qcocoaview_mac.mm b/src/gui/kernel/qcocoaview_mac.mm
index f61d2fe..8c5d166 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];
}
@@ -615,6 +569,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];
@@ -644,6 +602,8 @@ extern "C" {
- (void)mouseEntered:(NSEvent *)event
{
+ if (qwidgetprivate->data.in_destructor)
+ return;
QEvent enterEvent(QEvent::Enter);
NSPoint windowPoint = [event locationInWindow];
NSPoint globalPoint = [[event window] convertBaseToScreen:windowPoint];
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 c0d8252..403a1a5 100644
--- a/src/gui/kernel/qcocoawindow_mac_p.h
+++ b/src/gui/kernel/qcocoawindow_mac_p.h
@@ -70,9 +70,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/qdnd_s60.cpp b/src/gui/kernel/qdnd_s60.cpp
index 24f0090..1aa30af 100644
--- a/src/gui/kernel/qdnd_s60.cpp
+++ b/src/gui/kernel/qdnd_s60.cpp
@@ -52,7 +52,7 @@
#include "qdnd_p.h"
#include "qt_s60_p.h"
-#include <COECNTRL.H>
+#include <coecntrl.h>
// pointer cursor
#include <w32std.h>
#include <gdi.h>
diff --git a/src/gui/kernel/qeventdispatcher_mac.mm b/src/gui/kernel/qeventdispatcher_mac.mm
index eda75db..2a1da41 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,26 @@ 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 (!d->interrupt && [NSApp runModalSession:session] == NSRunContinuesResponse)
+
+ 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 +595,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 +703,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 +744,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 +811,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 +823,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 +880,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 +916,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 +933,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 +1006,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 +1048,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 +1059,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 +1081,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 +1129,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 +1148,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 0431f2f..775bf1b 100644
--- a/src/gui/kernel/qmime_mac.cpp
+++ b/src/gui/kernel/qmime_mac.cpp
@@ -154,6 +154,7 @@ CFStringRef qt_mac_mime_typeUTI = CFSTR("com.pasteboard.trolltech.marker");
\i public.url - converts to "text/uri-list"
\i public.file-url - converts to "text/uri-list"
\i public.tiff - converts to "application/x-qt-image"
+ \i public.vcard - converts to "text/plain"
\i com.apple.traditional-mac-plain-text - converts to "text/plain"
\i com.apple.pict - converts to "application/x-qt-image"
\endlist
@@ -909,6 +910,61 @@ QList<QByteArray> QMacPasteboardMimeUrl::convertFromMime(const QString &mime, QV
return ret;
}
+class QMacPasteboardMimeVCard : public QMacPasteboardMime
+{
+public:
+ QMacPasteboardMimeVCard() : QMacPasteboardMime(MIME_ALL){ }
+ QString convertorName();
+
+ QString flavorFor(const QString &mime);
+ QString mimeFor(QString flav);
+ bool canConvert(const QString &mime, QString flav);
+ QVariant convertToMime(const QString &mime, QList<QByteArray> data, QString flav);
+ QList<QByteArray> convertFromMime(const QString &mime, QVariant data, QString flav);
+};
+
+QString QMacPasteboardMimeVCard::convertorName()
+{
+ return QString("VCard");
+}
+
+bool QMacPasteboardMimeVCard::canConvert(const QString &mime, QString flav)
+{
+ return mimeFor(flav) == mime;
+}
+
+QString QMacPasteboardMimeVCard::flavorFor(const QString &mime)
+{
+ if(mime.startsWith(QLatin1String("text/plain")))
+ return QLatin1String("public.vcard");
+ return QString();
+}
+
+QString QMacPasteboardMimeVCard::mimeFor(QString flav)
+{
+ if (flav == QLatin1String("public.vcard"))
+ return QLatin1String("text/plain");
+ return QString();
+}
+
+QVariant QMacPasteboardMimeVCard::convertToMime(const QString &mime, QList<QByteArray> data, QString)
+{
+ QByteArray cards;
+ if (mime == QLatin1String("text/plain")) {
+ for (int i=0; i<data.size(); ++i)
+ cards += data[i];
+ }
+ return QVariant(cards);
+}
+
+QList<QByteArray> QMacPasteboardMimeVCard::convertFromMime(const QString &mime, QVariant data, QString)
+{
+ QList<QByteArray> ret;
+ if (mime == QLatin1String("text/plain"))
+ ret.append(data.toString().toUtf8());
+ return ret;
+}
+
#ifdef QT3_SUPPORT
class QMacPasteboardMimeQt3Any : public QMacPasteboardMime {
private:
@@ -1116,6 +1172,7 @@ void QMacPasteboardMime::initialize()
new QMacPasteboardMimeFileUri;
new QMacPasteboardMimeUrl;
new QMacPasteboardMimeTypeName;
+ new QMacPasteboardMimeVCard;
//make sure our "non-standard" types are always last! --Sam
new QMacPasteboardMimeAny;
#ifdef QT3_SUPPORT
diff --git a/src/gui/kernel/qnsthemeframe_mac_p.h b/src/gui/kernel/qnsthemeframe_mac_p.h
index 77a6963..d061b1b 100644
--- a/src/gui/kernel/qnsthemeframe_mac_p.h
+++ b/src/gui/kernel/qnsthemeframe_mac_p.h
@@ -157,7 +157,7 @@
- (void)resetCursorRects;
- (char)shouldBeTreatedAsInkEvent:fp8;
- (char)_shouldBeTreatedAsInkEventInInactiveWindow:fp8;
-- hitTest:(struct _NSPoint)fp8;
+//- hitTest:(struct _NSPoint)fp8; // collides with hittest in qcocoasharedwindowmethods_mac_p.h
- (NSRect)_leftGroupRect;
- (NSRect)_rightGroupRect;
- (void)_updateWidgets;
diff --git a/src/gui/kernel/qsound_s60.cpp b/src/gui/kernel/qsound_s60.cpp
index 1832b85..df2830b 100644
--- a/src/gui/kernel/qsound_s60.cpp
+++ b/src/gui/kernel/qsound_s60.cpp
@@ -51,7 +51,7 @@
#include <private/qcore_symbian_p.h>
#include <e32std.h>
-#include <MdaAudioSamplePlayer.h>
+#include <mdaaudiosampleplayer.h>
QT_BEGIN_NAMESPACE
diff --git a/src/gui/kernel/qt_cocoa_helpers_mac.mm b/src/gui/kernel/qt_cocoa_helpers_mac.mm
index e36ab9b..13c25fd 100644
--- a/src/gui/kernel/qt_cocoa_helpers_mac.mm
+++ b/src/gui/kernel/qt_cocoa_helpers_mac.mm
@@ -143,6 +143,9 @@ extern QPointer<QWidget> qt_button_down; //qapplication_mac.cpp
void macWindowFade(void * /*OSWindowRef*/ window, float durationSeconds)
{
+#ifdef QT_MAC_USE_COCOA
+ QMacCocoaAutoReleasePool pool;
+#endif
OSWindowRef wnd = static_cast<OSWindowRef>(window);
if (wnd) {
QWidget *widget;
@@ -1278,4 +1281,19 @@ 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
+
QT_END_NAMESPACE
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_mac.mm b/src/gui/kernel/qwidget_mac.mm
index 3dbc843..3ff46f5 100644
--- a/src/gui/kernel/qwidget_mac.mm
+++ b/src/gui/kernel/qwidget_mac.mm
@@ -1898,13 +1898,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;
@@ -2008,8 +2010,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)
@@ -2204,6 +2204,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);
@@ -2276,6 +2311,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();
@@ -2706,6 +2745,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);
@@ -2860,7 +2928,6 @@ void QWidgetPrivate::setParent_sys(QWidget *parent, Qt::WindowFlags f)
current = current->parentWidget();
}
}
-
invalidateBuffer(q->rect());
qt_event_request_window_change(q);
}
@@ -3322,13 +3389,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())
@@ -3347,8 +3424,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()) {
@@ -3391,6 +3466,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
@@ -3456,12 +3534,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)))
@@ -3481,24 +3562,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
@@ -3510,6 +3579,8 @@ void QWidgetPrivate::hide_sys()
if (!QWidget::mouseGrabber()){
QWidget *enterWidget = QApplication::widgetAt(QCursor::pos());
+ if (enterWidget && enterWidget->data->in_destructor)
+ enterWidget = 0;
QApplicationPrivate::dispatchEnterLeave(enterWidget, qt_mouseover);
qt_mouseover = enterWidget;
}
@@ -4584,9 +4655,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
}
@@ -4740,7 +4814,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();
@@ -4757,47 +4831,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 c9d655c..d3bc2d8 100644
--- a/src/gui/kernel/qwidget_p.h
+++ b/src/gui/kernel/qwidget_p.h
@@ -762,6 +762,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();