From eeffcfbd89a0b386c5757e8c67b76c5bccc84ffd Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Fri, 28 Jun 2013 17:26:27 +0200 Subject: Cocoa: fix shared color panel usage Task-number: QTBUG-31819 Change-Id: I60162f4c4af8aaae02ba7be11b2793ad29c5e2b5 Reviewed-by: Gabriel de Dietrich --- .../platforms/cocoa/qcocoacolordialoghelper.h | 9 - .../platforms/cocoa/qcocoacolordialoghelper.mm | 257 ++++++++++++--------- 2 files changed, 144 insertions(+), 122 deletions(-) (limited to 'src') diff --git a/src/plugins/platforms/cocoa/qcocoacolordialoghelper.h b/src/plugins/platforms/cocoa/qcocoacolordialoghelper.h index e30f1d7425..59e029769d 100644 --- a/src/plugins/platforms/cocoa/qcocoacolordialoghelper.h +++ b/src/plugins/platforms/cocoa/qcocoacolordialoghelper.h @@ -59,15 +59,6 @@ public: void setCurrentColor(const QColor&); QColor currentColor() const; - -public: - bool showCocoaColorPanel(Qt::WindowModality windowModality, QWindow *parent); - bool hideCocoaColorPanel(); - - void createNSColorPanelDelegate(); - -private: - void *mDelegate; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/cocoa/qcocoacolordialoghelper.mm b/src/plugins/platforms/cocoa/qcocoacolordialoghelper.mm index 594ad65a18..3379a26650 100644 --- a/src/plugins/platforms/cocoa/qcocoacolordialoghelper.mm +++ b/src/plugins/platforms/cocoa/qcocoacolordialoghelper.mm @@ -89,11 +89,14 @@ static NSButton *macCreateButton(const char *text, NSView *superview) @implementation QT_MANGLE_NAMESPACE(QNSColorPanelDelegate) -- (id)initWithDialogHelper:(QCocoaColorDialogHelper *)helper +- (id)init { self = [super init]; mColorPanel = [NSColorPanel sharedColorPanel]; - mHelper = helper; + mHelper = 0; + mStolenContentView = 0; + mOkButton = 0; + mCancelButton = 0; mResultCode = NSCancelButton; mDialogIsExecuting = false; mResultSet = false; @@ -103,11 +106,31 @@ static NSButton *macCreateButton(const char *text, NSView *superview) [mColorPanel setRestorable:NO]; #endif + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(colorChanged:) + name:NSColorPanelColorDidChangeNotification + object:mColorPanel]; + + [mColorPanel retain]; + return self; +} + +- (void)dealloc +{ + [self restoreOriginalContentView]; + [mColorPanel setDelegate:nil]; + [[NSNotificationCenter defaultCenter] removeObserver:self]; + + [super dealloc]; +} + +- (void)setDialogHelper:(QCocoaColorDialogHelper *)helper +{ + mHelper = helper; + [mColorPanel setShowsAlpha:mHelper->options()->testOption(QColorDialogOptions::ShowAlphaChannel)]; if (mHelper->options()->testOption(QColorDialogOptions::NoButtons)) { - mStolenContentView = 0; - mOkButton = 0; - mCancelButton = 0; - } else { + [self restoreOriginalContentView]; + } else if (!mStolenContentView) { // steal the color panel's contents view mStolenContentView = [mColorPanel contentView]; [mStolenContentView retain]; @@ -132,33 +155,6 @@ static NSButton *macCreateButton(const char *text, NSView *superview) [mCancelButton setAction:@selector(onCancelClicked)]; [mCancelButton setTarget:self]; } - - [[NSNotificationCenter defaultCenter] addObserver:self - selector:@selector(colorChanged:) - name:NSColorPanelColorDidChangeNotification - object:mColorPanel]; - - [mColorPanel retain]; - return self; -} - -- (void)dealloc -{ - if (mOkButton) { - NSView *ourContentView = [mColorPanel contentView]; - - // return stolen stuff to its rightful owner - [mStolenContentView removeFromSuperview]; - [mColorPanel setContentView:mStolenContentView]; - [mOkButton release]; - [mCancelButton release]; - [ourContentView release]; - } - - [mColorPanel setDelegate:nil]; - [[NSNotificationCenter defaultCenter] removeObserver:self]; - - [super dealloc]; } - (void)closePanel @@ -176,7 +172,25 @@ static NSButton *macCreateButton(const char *text, NSView *superview) { Q_UNUSED(notification); [self updateQtColor]; - emit mHelper->colorSelected(mQtColor); + if (mHelper) + emit mHelper->colorSelected(mQtColor); +} + +- (void)restoreOriginalContentView +{ + if (mStolenContentView) { + NSView *ourContentView = [mColorPanel contentView]; + + // return stolen stuff to its rightful owner + [mStolenContentView removeFromSuperview]; + [mColorPanel setContentView:mStolenContentView]; + [mOkButton release]; + [mCancelButton release]; + [ourContentView release]; + mOkButton = 0; + mCancelButton = 0; + mStolenContentView = 0; + } } - (void)relayout @@ -273,7 +287,8 @@ static NSButton *macCreateButton(const char *text, NSView *superview) mQtColor.setRgbF(red, green, blue, alpha); } } - emit mHelper->currentColorChanged(mQtColor); + if (mHelper) + emit mHelper->currentColorChanged(mQtColor); } - (void)showModelessPanel @@ -310,7 +325,8 @@ static NSButton *macCreateButton(const char *text, NSView *superview) [self finishOffWithCode:NSCancelButton]; } else { mResultSet = true; - emit mHelper->reject(); + if (mHelper) + emit mHelper->reject(); } return true; } @@ -345,27 +361,101 @@ static NSButton *macCreateButton(const char *text, NSView *superview) QT_BEGIN_NAMESPACE -QCocoaColorDialogHelper::QCocoaColorDialogHelper() : - mDelegate(0) +class QCocoaColorPanel +{ +public: + QCocoaColorPanel() + { + mDelegate = [[QT_MANGLE_NAMESPACE(QNSColorPanelDelegate) alloc] init]; + } + + ~QCocoaColorPanel() + { + [mDelegate release]; + } + + void init(QCocoaColorDialogHelper *helper) + { + [mDelegate setDialogHelper:helper]; + } + + void cleanup(QCocoaColorDialogHelper *helper) + { + if (mDelegate->mHelper == helper) + mDelegate->mHelper = 0; + } + + bool exec() + { + // Note: 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. + return [mDelegate runApplicationModalPanel]; + } + + bool show(Qt::WindowModality windowModality, QWindow *parent) + { + Q_UNUSED(parent); + if (windowModality != Qt::WindowModal) + [mDelegate showModelessPanel]; + // no need to show a Qt::WindowModal dialog here, because it's necessary to call exec() in that case + return true; + } + + void hide() + { + [mDelegate closePanel]; + } + + QColor currentColor() const + { + return mDelegate->mQtColor; + } + + void setCurrentColor(const QColor &color) + { + // make sure that if ShowAlphaChannel option is set then also setShowsAlpha + // needs to be set, otherwise alpha value is omitted + if (color.alpha() < 255) + [mDelegate->mColorPanel setShowsAlpha:YES]; + + NSColor *nsColor; + const QColor::Spec spec = color.spec(); + if (spec == QColor::Cmyk) { + nsColor = [NSColor colorWithDeviceCyan:color.cyanF() + magenta:color.magentaF() + yellow:color.yellowF() + black:color.blackF() + alpha:color.alphaF()]; + } else { + nsColor = [NSColor colorWithCalibratedRed:color.redF() + green:color.greenF() + blue:color.blueF() + alpha:color.alphaF()]; + } + mDelegate->mQtColor = color; + [mDelegate->mColorPanel setColor:nsColor]; + } + +private: + QT_MANGLE_NAMESPACE(QNSColorPanelDelegate) *mDelegate; +}; + +Q_GLOBAL_STATIC(QCocoaColorPanel, sharedColorPanel) + +QCocoaColorDialogHelper::QCocoaColorDialogHelper() { } QCocoaColorDialogHelper::~QCocoaColorDialogHelper() { - if (!mDelegate) - return; - [reinterpret_cast(mDelegate) release]; - mDelegate = 0; + sharedColorPanel()->cleanup(this); } void QCocoaColorDialogHelper::exec() { - // Note: 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. - QT_MANGLE_NAMESPACE(QNSColorPanelDelegate) *delegate = static_cast(mDelegate); - if ([delegate runApplicationModalPanel]) + if (sharedColorPanel()->exec()) emit accept(); else emit reject(); @@ -375,83 +465,24 @@ bool QCocoaColorDialogHelper::show(Qt::WindowFlags, Qt::WindowModality windowMod { if (windowModality == Qt::WindowModal) windowModality = Qt::ApplicationModal; - return showCocoaColorPanel(windowModality, parent); + sharedColorPanel()->init(this); + return sharedColorPanel()->show(windowModality, parent); } void QCocoaColorDialogHelper::hide() { - if (!mDelegate) - return; - [reinterpret_cast(mDelegate)->mColorPanel close]; + sharedColorPanel()->hide(); } void QCocoaColorDialogHelper::setCurrentColor(const QColor &color) { - if (!mDelegate) - createNSColorPanelDelegate(); - QT_MANGLE_NAMESPACE(QNSColorPanelDelegate) *delegate = static_cast(mDelegate); - - // make sure that if ShowAlphaChannel option is set then also setShowsAlpha - // needs to be set, otherwise alpha value is omitted - [delegate->mColorPanel setShowsAlpha:options()->testOption(QColorDialogOptions::ShowAlphaChannel)]; - - NSColor *nsColor; - const QColor::Spec spec = color.spec(); - if (spec == QColor::Cmyk) { - nsColor = [NSColor colorWithDeviceCyan:color.cyanF() - magenta:color.magentaF() - yellow:color.yellowF() - black:color.blackF() - alpha:color.alphaF()]; - } else { - nsColor = [NSColor colorWithCalibratedRed:color.redF() - green:color.greenF() - blue:color.blueF() - alpha:color.alphaF()]; - } - delegate->mQtColor = color; - [delegate->mColorPanel setColor:nsColor]; + sharedColorPanel()->init(this); + sharedColorPanel()->setCurrentColor(color); } QColor QCocoaColorDialogHelper::currentColor() const { - if (!mDelegate) - return QColor(); - return reinterpret_cast(mDelegate)->mQtColor; -} - -void QCocoaColorDialogHelper::createNSColorPanelDelegate() -{ - if (mDelegate) - return; - - QT_MANGLE_NAMESPACE(QNSColorPanelDelegate) *delegate = [[QT_MANGLE_NAMESPACE(QNSColorPanelDelegate) alloc] - initWithDialogHelper:this]; - - mDelegate = delegate; -} - -bool QCocoaColorDialogHelper::showCocoaColorPanel(Qt::WindowModality windowModality, QWindow *parent) -{ - Q_UNUSED(parent); - createNSColorPanelDelegate(); - QT_MANGLE_NAMESPACE(QNSColorPanelDelegate) *delegate = static_cast(mDelegate); - [delegate->mColorPanel setShowsAlpha:options()->testOption(QColorDialogOptions::ShowAlphaChannel)]; - if (windowModality != Qt::WindowModal) - [delegate showModelessPanel]; - // no need to show a Qt::WindowModal dialog here, because it's necessary to call exec() in that case - return true; -} - -bool QCocoaColorDialogHelper::hideCocoaColorPanel() -{ - if (!mDelegate){ - return false; - } else { - QT_MANGLE_NAMESPACE(QNSColorPanelDelegate) *delegate = static_cast(mDelegate); - [delegate closePanel]; - return true; - } + return sharedColorPanel()->currentColor(); } QT_END_NAMESPACE -- cgit v1.2.3