src/gui/dialogs/qnspanelproxy_mac.mm
changeset 0 1918ee327afb
child 4 3b1da2848fc7
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the QtGui module of the Qt Toolkit.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    15 **
       
    16 ** GNU Lesser General Public License Usage
       
    17 ** Alternatively, this file may be used under the terms of the GNU Lesser
       
    18 ** General Public License version 2.1 as published by the Free Software
       
    19 ** Foundation and appearing in the file LICENSE.LGPL included in the
       
    20 ** packaging of this file.  Please review the following information to
       
    21 ** ensure the GNU Lesser General Public License version 2.1 requirements
       
    22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    23 **
       
    24 ** In addition, as a special exception, Nokia gives you certain additional
       
    25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    27 **
       
    28 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    38 ** $QT_END_LICENSE$
       
    39 **
       
    40 ****************************************************************************/
       
    41 
       
    42 #include <qdialogbuttonbox.h>
       
    43 #if defined(Q_WS_MAC)
       
    44 #include <private/qt_mac_p.h>
       
    45 #import <AppKit/AppKit.h>
       
    46 #import <Foundation/Foundation.h>
       
    47 #import <objc/objc-class.h>
       
    48 
       
    49 QT_BEGIN_NAMESPACE
       
    50 static QWidget *currentWindow = 0;
       
    51 QT_END_NAMESPACE
       
    52 
       
    53 QT_USE_NAMESPACE
       
    54 
       
    55 @class QNSPanelProxy;
       
    56 
       
    57 @interface QNSPanelProxy : NSWindow {
       
    58 }
       
    59 - (id)initWithContentRect:(NSRect)contentRect styleMask:(NSUInteger)windowStyle
       
    60     backing:(NSBackingStoreType)bufferingType defer:(BOOL)deferCreation;
       
    61 - (id)initWithContentRect:(NSRect)contentRect styleMask:(NSUInteger)windowStyle
       
    62     backing:(NSBackingStoreType)bufferingType defer:(BOOL)deferCreation screen:(NSScreen *)screen;
       
    63 - (id)qt_fakeInitWithContentRect:(NSRect)contentRect styleMask:(NSUInteger)windowStyle
       
    64     backing:(NSBackingStoreType)bufferingType defer:(BOOL)deferCreation;
       
    65 - (id)qt_fakeInitWithContentRect:(NSRect)contentRect styleMask:(NSUInteger)windowStyle
       
    66     backing:(NSBackingStoreType)bufferingType defer:(BOOL)deferCreation screen:(NSScreen *)screen;
       
    67 @end
       
    68 
       
    69 @implementation QNSPanelProxy
       
    70 - (id)initWithContentRect:(NSRect)contentRect styleMask:(NSUInteger)windowStyle
       
    71       backing:(NSBackingStoreType)bufferingType defer:(BOOL)deferCreation
       
    72 {
       
    73     // remove evil flag
       
    74     windowStyle &= ~NSUtilityWindowMask;
       
    75 	self = [self qt_fakeInitWithContentRect:contentRect styleMask:windowStyle
       
    76 	                                backing:bufferingType defer:deferCreation];
       
    77     return self;
       
    78 }
       
    79 
       
    80 - (id)initWithContentRect:(NSRect)contentRect styleMask:(NSUInteger)windowStyle
       
    81       backing:(NSBackingStoreType)bufferingType defer:(BOOL)deferCreation screen:(NSScreen *)screen
       
    82 {
       
    83     // remove evil flag
       
    84     windowStyle &= ~NSUtilityWindowMask;
       
    85 	return [self qt_fakeInitWithContentRect:contentRect styleMask:windowStyle
       
    86 	                                backing:bufferingType defer:deferCreation screen:screen];
       
    87 }
       
    88 
       
    89 - (id)qt_fakeInitWithContentRect:(NSRect)contentRect styleMask:(NSUInteger)windowStyle
       
    90     backing:(NSBackingStoreType)bufferingType defer:(BOOL)deferCreation
       
    91 {
       
    92     Q_UNUSED(contentRect);
       
    93     Q_UNUSED(windowStyle);
       
    94     Q_UNUSED(bufferingType);
       
    95     Q_UNUSED(deferCreation);
       
    96     return nil;
       
    97 }
       
    98 
       
    99 - (id)qt_fakeInitWithContentRect:(NSRect)contentRect styleMask:(NSUInteger)windowStyle
       
   100     backing:(NSBackingStoreType)bufferingType defer:(BOOL)deferCreation screen:(NSScreen *)screen
       
   101 {
       
   102     Q_UNUSED(contentRect);
       
   103     Q_UNUSED(windowStyle);
       
   104     Q_UNUSED(bufferingType);
       
   105     Q_UNUSED(deferCreation);
       
   106     Q_UNUSED(screen);
       
   107     return nil;
       
   108 }
       
   109 @end
       
   110 
       
   111 @class QNSWindowProxy;
       
   112 
       
   113 @interface QNSWindowProxy : NSWindow {
       
   114 }
       
   115 - (void)setTitle:(NSString *)title;
       
   116 - (void)qt_fakeSetTitle:(NSString *)title;
       
   117 @end
       
   118 
       
   119 @implementation QNSWindowProxy
       
   120 - (void)setTitle:(NSString *)title
       
   121 {
       
   122     QCFString cftitle(currentWindow->windowTitle());
       
   123 
       
   124     // evil reverse engineering
       
   125     if ([title isEqualToString:@"Print"]
       
   126             || [title isEqualToString:@"Page Setup"]
       
   127             || [[self className] isEqualToString:@"PMPrintingWindow"])
       
   128         title = (NSString *)(static_cast<CFStringRef>(cftitle));
       
   129     return [self qt_fakeSetTitle:title];
       
   130 }
       
   131 
       
   132 - (void)qt_fakeSetTitle:(NSString *)title
       
   133 {
       
   134     Q_UNUSED(title);
       
   135 }
       
   136 @end
       
   137 
       
   138 QT_BEGIN_NAMESPACE
       
   139 
       
   140 void macStartIntercept(SEL originalSel, SEL fakeSel, Class baseClass, Class proxyClass)
       
   141 {
       
   142 #ifndef QT_MAC_USE_COCOA
       
   143     if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_5)
       
   144 #endif
       
   145     {
       
   146 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
       
   147         // The following code replaces the _implementation_ for the selector we want to hack
       
   148         // (originalSel) with the implementation found in proxyClass. Then it creates
       
   149         // a new 'backup' method inside baseClass containing the old, original,
       
   150         // implementation (fakeSel). You can let the proxy implementation of originalSel
       
   151         // call fakeSel if needed (similar approach to calling a super class implementation).
       
   152         // fakeSel must also be implemented in proxyClass, as the signature is used
       
   153         // as template for the method one we add into baseClass.
       
   154         // NB: You will typically never create any instances of proxyClass; we use it
       
   155         // only for stealing its contents and put it into baseClass. 
       
   156         Method originalMethod = class_getInstanceMethod(baseClass, originalSel);
       
   157         Method newMethod = class_getInstanceMethod(proxyClass, originalSel);
       
   158         Method fakeMethod = class_getInstanceMethod(proxyClass, fakeSel);
       
   159 
       
   160         IMP originalImp = method_setImplementation(originalMethod, method_getImplementation(newMethod));
       
   161         class_addMethod(baseClass, fakeSel, originalImp, method_getTypeEncoding(fakeMethod));
       
   162 #endif
       
   163     }
       
   164 }
       
   165 
       
   166 void macStopIntercept(SEL originalSel, SEL fakeSel, Class baseClass, Class /* proxyClass */)
       
   167 {
       
   168 #ifndef QT_MAC_USE_COCOA
       
   169     if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_5)
       
   170 #endif
       
   171     {
       
   172 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
       
   173         Method originalMethod = class_getInstanceMethod(baseClass, originalSel);
       
   174         Method fakeMethodInBaseClass = class_getInstanceMethod(baseClass, fakeSel);
       
   175         method_setImplementation(originalMethod, method_getImplementation(fakeMethodInBaseClass));
       
   176 #endif
       
   177     }
       
   178 }
       
   179 
       
   180 /*
       
   181     Intercept the NSColorPanel constructor if the shared
       
   182     color panel doesn't exist yet. What's going on here is
       
   183     quite wacky, because we want to override the NSPanel
       
   184     constructor and at the same time call the old NSPanel
       
   185     constructor. So what we do is we effectively rename the
       
   186     old NSPanel constructor qt_fakeInitWithContentRect:...
       
   187     and have the new one call the old one.
       
   188 */
       
   189 void macStartInterceptNSPanelCtor()
       
   190 {
       
   191     macStartIntercept(@selector(initWithContentRect:styleMask:backing:defer:),
       
   192                       @selector(qt_fakeInitWithContentRect:styleMask:backing:defer:),
       
   193                       [NSPanel class], [QNSPanelProxy class]);
       
   194     macStartIntercept(@selector(initWithContentRect:styleMask:backing:defer:screen:),
       
   195                       @selector(qt_fakeInitWithContentRect:styleMask:backing:defer:screen:),
       
   196                       [NSPanel class], [QNSPanelProxy class]);
       
   197 }
       
   198 
       
   199 /*
       
   200     Restore things as they were.
       
   201 */
       
   202 void macStopInterceptNSPanelCtor()
       
   203 {
       
   204     macStopIntercept(@selector(initWithContentRect:styleMask:backing:defer:screen:),
       
   205                      @selector(qt_fakeInitWithContentRect:styleMask:backing:defer:screen:),
       
   206                      [NSPanel class], [QNSPanelProxy class]);
       
   207     macStopIntercept(@selector(initWithContentRect:styleMask:backing:defer:),
       
   208                      @selector(qt_fakeInitWithContentRect:styleMask:backing:defer:),
       
   209                      [NSPanel class], [QNSPanelProxy class]);
       
   210 }
       
   211 
       
   212 /*
       
   213     Intercept the NSPrintPanel and NSPageLayout setTitle: calls. The
       
   214     hack is similar as for NSColorPanel above.
       
   215 */
       
   216 void macStartInterceptWindowTitle(QWidget *window)
       
   217 {
       
   218     currentWindow = window;
       
   219     macStartIntercept(@selector(setTitle:), @selector(qt_fakeSetTitle:),
       
   220                       [NSWindow class], [QNSWindowProxy class]);
       
   221 }
       
   222 
       
   223 /*
       
   224     Restore things as they were.
       
   225 */
       
   226 void macStopInterceptWindowTitle()
       
   227 {
       
   228     currentWindow = 0;
       
   229     macStopIntercept(@selector(setTitle:), @selector(qt_fakeSetTitle:),
       
   230                      [NSWindow class], [QNSWindowProxy class]);
       
   231 }
       
   232 
       
   233 /*
       
   234     Doesn't really belong in here.
       
   235 */
       
   236 NSButton *macCreateButton(const char *text, NSView *superview)
       
   237 {
       
   238     static const NSRect buttonFrameRect = { { 0.0, 0.0 }, { 0.0, 0.0 } };
       
   239 
       
   240     NSButton *button = [[NSButton alloc] initWithFrame:buttonFrameRect];
       
   241     [button setButtonType:NSMomentaryLightButton];
       
   242     [button setBezelStyle:NSRoundedBezelStyle];
       
   243     [button setTitle:(NSString*)(CFStringRef)QCFString(QDialogButtonBox::tr(text)
       
   244                                                        .remove(QLatin1Char('&')))];
       
   245     [[button cell] setFont:[NSFont systemFontOfSize:
       
   246             [NSFont systemFontSizeForControlSize:NSRegularControlSize]]];
       
   247     [superview addSubview:button];
       
   248     return button;
       
   249 }
       
   250 
       
   251 QT_END_NAMESPACE
       
   252 
       
   253 #endif