summaryrefslogtreecommitdiffstats
path: root/src/gui/dialogs
diff options
context:
space:
mode:
authorCarlos Manuel Duclos Vergara <carlos.duclos@nokia.com>2010-02-22 13:58:41 (GMT)
committerCarlos Manuel Duclos Vergara <carlos.duclos@nokia.com>2010-02-22 14:01:48 (GMT)
commit976a2b6ad1f95175d8d0be2d1eb7603cf4e4026a (patch)
treed8413137eb7f1307c2a15c6eb9d2e253ba59a681 /src/gui/dialogs
parent5e95e1bb510d24b9b7889191144a4842fd8569c1 (diff)
downloadQt-976a2b6ad1f95175d8d0be2d1eb7603cf4e4026a.zip
Qt-976a2b6ad1f95175d8d0be2d1eb7603cf4e4026a.tar.gz
Qt-976a2b6ad1f95175d8d0be2d1eb7603cf4e4026a.tar.bz2
QFontDialog::exec() never returns on OSX
The problem is the fact that this dialog is never meant to be used this way. Instead it should be called through the static function ::getFont(...). I reimplemented this code path and made sure that this works. Task-number: QTBUG-7769 Reviewed-by: Richard Moe Gustavsen
Diffstat (limited to 'src/gui/dialogs')
-rw-r--r--src/gui/dialogs/qfontdialog.cpp58
-rw-r--r--src/gui/dialogs/qfontdialog.h3
-rw-r--r--src/gui/dialogs/qfontdialog_mac.mm148
-rw-r--r--src/gui/dialogs/qfontdialog_p.h6
4 files changed, 188 insertions, 27 deletions
diff --git a/src/gui/dialogs/qfontdialog.cpp b/src/gui/dialogs/qfontdialog.cpp
index 56580a9..4358313 100644
--- a/src/gui/dialogs/qfontdialog.cpp
+++ b/src/gui/dialogs/qfontdialog.cpp
@@ -989,33 +989,23 @@ void QFontDialog::open(QObject *receiver, const char *member)
void QFontDialog::setVisible(bool visible)
{
Q_D(QFontDialog);
- if (visible)
- d->selectedFont = QFont();
-
-#if defined(Q_WS_MAC)
- bool isCurrentlyVisible = (isVisible() || d->delegate);
-
- if (!visible == !isCurrentlyVisible)
- return;
-
if (visible) {
- if (!(d->opts & DontUseNativeDialog) && QFontDialogPrivate::sharedFontPanelAvailable) {
- d->delegate = QFontDialogPrivate::openCocoaFontPanel(
- currentFont(), parentWidget(), windowTitle(), options(), d);
- QFontDialogPrivate::sharedFontPanelAvailable = false;
+ if (testAttribute(Qt::WA_WState_ExplicitShowHide) && !testAttribute(Qt::WA_WState_Hidden))
return;
- }
+ } else if (testAttribute(Qt::WA_WState_ExplicitShowHide) && testAttribute(Qt::WA_WState_Hidden))
+ return;
- setWindowFlags(windowModality() == Qt::WindowModal ? Qt::Sheet : DefaultWindowFlags);
- } else {
- if (d->delegate) {
- QFontDialogPrivate::closeCocoaFontPanel(d->delegate);
- d->delegate = 0;
- QFontDialogPrivate::sharedFontPanelAvailable = true;
- return;
+ if (d->canBeNativeDialog()){
+ if (d->setVisible_sys(visible)){
+ d->nativeDialogInUse = true;
+ // Set WA_DontShowOnScreen so that QDialog::setVisible(visible) below
+ // updates the state correctly, but skips showing the non-native version:
+ setAttribute(Qt::WA_DontShowOnScreen, true);
+ } else {
+ d->nativeDialogInUse = false;
+ setAttribute(Qt::WA_DontShowOnScreen, false);
}
}
-#endif
QDialog::setVisible(visible);
}
@@ -1032,11 +1022,14 @@ void QFontDialog::done(int result)
Q_D(QFontDialog);
QDialog::done(result);
if (result == Accepted) {
- d->selectedFont = currentFont();
+ // We check if this is the same font we had before, if so we emit currentFontChanged
+ QFont selectedFont = currentFont();
+ if(selectedFont != d->selectedFont)
+ emit(currentFontChanged(selectedFont));
+ d->selectedFont = selectedFont;
emit fontSelected(d->selectedFont);
- } else {
+ } else
d->selectedFont = QFont();
- }
if (d->receiverToDisconnectOnClose) {
disconnect(this, SIGNAL(fontSelected(QFont)),
d->receiverToDisconnectOnClose, d->memberToDisconnectOnClose);
@@ -1045,6 +1038,21 @@ void QFontDialog::done(int result)
d->memberToDisconnectOnClose.clear();
}
+bool QFontDialogPrivate::canBeNativeDialog()
+{
+ Q_Q(QFontDialog);
+ if (nativeDialogInUse)
+ return true;
+ if (q->testAttribute(Qt::WA_DontShowOnScreen))
+ return false;
+ if (opts & QFontDialog::DontUseNativeDialog)
+ return false;
+
+ QLatin1String staticName(QFontDialog::staticMetaObject.className());
+ QLatin1String dynamicName(q->metaObject()->className());
+ return (staticName == dynamicName);
+}
+
/*!
\fn QFont QFontDialog::getFont(bool *ok, const QFont &initial, QWidget* parent, const char* name)
\since 4.5
diff --git a/src/gui/dialogs/qfontdialog.h b/src/gui/dialogs/qfontdialog.h
index e6f209e..6035a3a 100644
--- a/src/gui/dialogs/qfontdialog.h
+++ b/src/gui/dialogs/qfontdialog.h
@@ -131,6 +131,9 @@ private:
Q_PRIVATE_SLOT(d_func(), void _q_styleHighlighted(int))
Q_PRIVATE_SLOT(d_func(), void _q_sizeHighlighted(int))
Q_PRIVATE_SLOT(d_func(), void _q_updateSample())
+#if defined(Q_WS_MAC)
+ Q_PRIVATE_SLOT(d_func(), void _q_macRunNativeAppModalPanel())
+#endif
};
Q_DECLARE_OPERATORS_FOR_FLAGS(QFontDialog::FontDialogOptions)
diff --git a/src/gui/dialogs/qfontdialog_mac.mm b/src/gui/dialogs/qfontdialog_mac.mm
index 68f5f00..67d32b8 100644
--- a/src/gui/dialogs/qfontdialog_mac.mm
+++ b/src/gui/dialogs/qfontdialog_mac.mm
@@ -49,6 +49,7 @@
#include <private/qfontengine_p.h>
#include <private/qt_cocoa_helpers_mac_p.h>
#include <private/qt_mac_p.h>
+#include <qabstracteventdispatcher.h>
#include <qdebug.h>
#import <AppKit/AppKit.h>
#import <Foundation/Foundation.h>
@@ -372,7 +373,12 @@ static QFont qfontForCocoaFont(NSFont *cocoaFont, const QFont &resolveFont)
[NSApp endModalSession:mModalSession];
mModalSession = 0;
}
-
+ // Hack alert!
+ // Since this code path was never intended to be followed when starting from exec
+ // we need to force the dialog to communicate the new font, otherwise the signal
+ // won't get emitted.
+ if(code == NSOKButton)
+ mPriv->sampleEdit->setFont([self qtFont]);
mPriv->done((code == NSOKButton) ? QDialog::Accepted : QDialog::Rejected);
} else {
[NSApp stopModalWithCode:code];
@@ -567,7 +573,6 @@ void *QFontDialogPrivate::openCocoaFontPanel(const QFont &initial,
[ourPanel makeKeyAndOrderFront:ourPanel];
}
}
-
return delegate;
}
@@ -640,6 +645,145 @@ void QFontDialogPrivate::setFont(void *delegate, const QFont &font)
[static_cast<QCocoaFontPanelDelegate *>(delegate) setQtFont:font];
}
+void *QFontDialogPrivate::_q_constructNativePanel()
+{
+ QMacCocoaAutoReleasePool pool;
+
+ bool sharedFontPanelExisted = [NSFontPanel sharedFontPanelExists];
+ NSFontPanel *sharedFontPanel = [NSFontPanel sharedFontPanel];
+ [sharedFontPanel setHidesOnDeactivate:false];
+
+ // hack to ensure that QCocoaApplication's validModesForFontPanel:
+ // implementation is honored
+ if (!sharedFontPanelExisted) {
+ [sharedFontPanel makeKeyAndOrderFront:sharedFontPanel];
+ [sharedFontPanel close];
+ }
+
+ NSPanel *ourPanel = 0;
+ NSView *stolenContentView = 0;
+ NSButton *okButton = 0;
+ NSButton *cancelButton = 0;
+
+ CGFloat dialogExtraWidth = 0.0;
+ CGFloat dialogExtraHeight = 0.0;
+
+ // compute dialogExtra{Width,Height}
+ dialogExtraWidth = 2.0 * DialogSideMargin;
+ dialogExtraHeight = DialogTopMargin + ButtonTopMargin + ButtonMinHeight
+ + ButtonBottomMargin;
+
+ // compute initial contents rectangle
+ NSRect contentRect = [sharedFontPanel contentRectForFrameRect:[sharedFontPanel frame]];
+ contentRect.size.width += dialogExtraWidth;
+ contentRect.size.height += dialogExtraHeight;
+
+ // create the new panel
+ ourPanel = [[NSPanel alloc] initWithContentRect:contentRect
+ styleMask:StyleMask
+ backing:NSBackingStoreBuffered
+ defer:YES];
+ [ourPanel setReleasedWhenClosed:YES];
+
+ stolenContentView = [sharedFontPanel contentView];
+
+ // steal the font panel's contents view
+ [stolenContentView retain];
+ [sharedFontPanel setContentView:0];
+
+ {
+ // create a new content view and add the stolen one as a subview
+ NSRect frameRect = { { 0.0, 0.0 }, { 0.0, 0.0 } };
+ NSView *ourContentView = [[NSView alloc] initWithFrame:frameRect];
+ [ourContentView addSubview:stolenContentView];
+
+ // create OK and Cancel buttons and add these as subviews
+ okButton = macCreateButton("&OK", ourContentView);
+ cancelButton = macCreateButton("Cancel", ourContentView);
+
+ [ourPanel setContentView:ourContentView];
+ [ourPanel setDefaultButtonCell:[okButton cell]];
+ }
+ // create a delegate and set it
+ QCocoaFontPanelDelegate *delegate =
+ [[QCocoaFontPanelDelegate alloc] initWithFontPanel:sharedFontPanel
+ stolenContentView:stolenContentView
+ okButton:okButton
+ cancelButton:cancelButton
+ priv:this
+ extraWidth:dialogExtraWidth
+ extraHeight:dialogExtraHeight];
+ [ourPanel setDelegate:delegate];
+ [[NSFontManager sharedFontManager] setDelegate:delegate];
+#ifdef QT_MAC_USE_COCOA
+ [[NSFontManager sharedFontManager] setTarget:delegate];
+#endif
+ setFont(delegate, QApplication::font());
+
+ {
+ // hack to get correct initial layout
+ NSRect frameRect = [ourPanel frame];
+ frameRect.size.width += 1.0;
+ [ourPanel setFrame:frameRect display:NO];
+ frameRect.size.width -= 1.0;
+ frameRect.size = [delegate windowWillResize:ourPanel toSize:frameRect.size];
+ [ourPanel setFrame:frameRect display:NO];
+ [ourPanel center];
+ }
+ NSString *title = @"Select font";
+ [ourPanel setTitle:title];
+
+ [delegate setModalSession:[NSApp beginModalSessionForWindow:ourPanel]];
+ return delegate;
+}
+
+void QFontDialogPrivate::mac_nativeDialogModalHelp()
+{
+ // Copied from QFileDialogPrivate
+ // Do a queued meta-call to open the native modal dialog so it opens after the new
+ // event loop has started to execute (in QDialog::exec). Using a timer rather than
+ // a queued meta call is intentional to ensure that the call is only delivered when
+ // [NSApp run] runs (timers are handeled special in cocoa). If NSApp is not
+ // running (which is the case if e.g a top-most QEventLoop has been
+ // interrupted, and the second-most event loop has not yet been reactivated (regardless
+ // if [NSApp run] is still on the stack)), showing a native modal dialog will fail.
+ if (nativeDialogInUse) {
+ Q_Q(QFontDialog);
+ QTimer::singleShot(1, q, SLOT(_q_macRunNativeAppModalPanel()));
+ }
+}
+
+// The problem with the native font dialog is that OS X does not
+// offer a proper dialog, but a panel (i.e. without Ok and Cancel buttons).
+// This means we need to "construct" a native dialog by taking the panel
+// and "adding" the buttons.
+void QFontDialogPrivate::_q_macRunNativeAppModalPanel()
+{
+ QBoolBlocker nativeDialogOnTop(QApplicationPrivate::native_modal_dialog_active);
+ Q_Q(QFontDialog);
+ QCocoaFontPanelDelegate *delegate = (QCocoaFontPanelDelegate *)_q_constructNativePanel();
+ NSWindow *ourPanel = [delegate actualPanel];
+ [ourPanel retain];
+ int rval = [NSApp runModalForWindow:ourPanel];
+ QAbstractEventDispatcher::instance()->interrupt();
+ [ourPanel release];
+ [delegate cleanUpAfterMyself];
+ [delegate release];
+ bool isOk = (rval == NSOKButton);
+ if(isOk)
+ rescode = QDialog::Accepted;
+ else
+ rescode = QDialog::Rejected;
+}
+
+bool QFontDialogPrivate::setVisible_sys(bool visible)
+{
+ Q_Q(QFontDialog);
+ if (!visible == q->isHidden())
+ return false;
+ return visible;
+}
+
QT_END_NAMESPACE
#endif
diff --git a/src/gui/dialogs/qfontdialog_p.h b/src/gui/dialogs/qfontdialog_p.h
index ca2b10b..7654a80 100644
--- a/src/gui/dialogs/qfontdialog_p.h
+++ b/src/gui/dialogs/qfontdialog_p.h
@@ -152,6 +152,12 @@ public:
inline QFontDialog *fontDialog() { return q_func(); }
void *delegate;
+ bool nativeDialogInUse;
+ bool canBeNativeDialog();
+ bool setVisible_sys(bool visible);
+ void *_q_constructNativePanel();
+ void _q_macRunNativeAppModalPanel();
+ void mac_nativeDialogModalHelp();
static bool sharedFontPanelAvailable;
#endif