src/gui/kernel/qcocoawindowdelegate_mac.mm
changeset 0 1918ee327afb
child 3 41300fa6a67c
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 #import "private/qcocoawindowdelegate_mac_p.h"
       
    43 #ifdef QT_MAC_USE_COCOA
       
    44 #include <private/qwidget_p.h>
       
    45 #include <private/qapplication_p.h>
       
    46 #include <private/qt_cocoa_helpers_mac_p.h>
       
    47 #include <qevent.h>
       
    48 #include <qlayout.h>
       
    49 #include <qcoreapplication.h>
       
    50 #include <qmenubar.h>
       
    51 
       
    52 QT_BEGIN_NAMESPACE
       
    53 extern QWidgetData *qt_qwidget_data(QWidget *); // qwidget.cpp
       
    54 extern void onApplicationWindowChangedActivation(QWidget *, bool); //qapplication_mac.mm
       
    55 extern bool qt_sendSpontaneousEvent(QObject *, QEvent *); // qapplication.cpp
       
    56 QT_END_NAMESPACE
       
    57 
       
    58 QT_USE_NAMESPACE
       
    59 
       
    60 static QT_MANGLE_NAMESPACE(QCocoaWindowDelegate) *sharedCocoaWindowDelegate = nil;
       
    61 
       
    62 // This is a singleton, but unlike most Cocoa singletons, it lives in a library and could be
       
    63 // pontentially loaded and unloaded. This means we should at least attempt to do the
       
    64 // memory management correctly.
       
    65 
       
    66 static void cleanupCocoaWindowDelegate()
       
    67 {
       
    68     [sharedCocoaWindowDelegate release];
       
    69 }
       
    70 
       
    71 @implementation QT_MANGLE_NAMESPACE(QCocoaWindowDelegate)
       
    72 
       
    73 - (id)init
       
    74 {
       
    75     self = [super init];
       
    76     if (self != nil) {
       
    77         m_windowHash = new QHash<NSWindow *, QWidget *>();
       
    78         m_drawerHash = new QHash<NSDrawer *, QWidget *>();
       
    79     }
       
    80     return self;
       
    81 }
       
    82 
       
    83 - (void)dealloc
       
    84 {
       
    85     sharedCocoaWindowDelegate = nil;
       
    86     QHash<NSWindow *, QWidget *>::const_iterator windowIt = m_windowHash->constBegin();
       
    87     while (windowIt != m_windowHash->constEnd()) {
       
    88         [windowIt.key() setDelegate:nil];
       
    89         ++windowIt;
       
    90     }
       
    91     delete m_windowHash;
       
    92     QHash<NSDrawer *, QWidget *>::const_iterator drawerIt = m_drawerHash->constBegin();
       
    93     while (drawerIt != m_drawerHash->constEnd()) {
       
    94         [drawerIt.key() setDelegate:nil];
       
    95         ++drawerIt;
       
    96     }
       
    97     delete m_drawerHash;
       
    98     [super dealloc];
       
    99 }
       
   100 
       
   101 + (id)allocWithZone:(NSZone *)zone
       
   102 {
       
   103     @synchronized(self) {
       
   104         if (sharedCocoaWindowDelegate == nil) {
       
   105             sharedCocoaWindowDelegate = [super allocWithZone:zone];
       
   106             return sharedCocoaWindowDelegate;
       
   107             qAddPostRoutine(cleanupCocoaWindowDelegate);
       
   108         }
       
   109     }
       
   110     return nil;
       
   111 }
       
   112 
       
   113 + (QT_MANGLE_NAMESPACE(QCocoaWindowDelegate)*)sharedDelegate
       
   114 {
       
   115     @synchronized(self) {
       
   116         if (sharedCocoaWindowDelegate == nil)
       
   117             [[self alloc] init];
       
   118     }
       
   119     return [[sharedCocoaWindowDelegate retain] autorelease];
       
   120 }
       
   121 
       
   122 -(void)syncSizeForWidget:(QWidget *)qwidget toSize:(const QSize &)newSize fromSize:(const QSize &)oldSize
       
   123 {
       
   124     qt_qwidget_data(qwidget)->crect.setSize(newSize);
       
   125     // ### static contents optimization needs to go here
       
   126     const OSViewRef view = qt_mac_nativeview_for(qwidget);
       
   127     [view setFrameSize:NSMakeSize(newSize.width(), newSize.height())];
       
   128     if (!qwidget->isVisible()) {
       
   129         qwidget->setAttribute(Qt::WA_PendingResizeEvent, true);
       
   130     } else {
       
   131         QResizeEvent qre(newSize, oldSize);
       
   132         if (qwidget->testAttribute(Qt::WA_PendingResizeEvent)) {
       
   133             qwidget->setAttribute(Qt::WA_PendingResizeEvent, false);
       
   134             QApplication::sendEvent(qwidget, &qre);
       
   135         } else {
       
   136             qt_sendSpontaneousEvent(qwidget, &qre);
       
   137         }
       
   138     }
       
   139 }
       
   140 
       
   141 - (void)dumpMaximizedStateforWidget:(QWidget*)qwidget window:(NSWindow *)window;
       
   142 {
       
   143     if (!window)
       
   144         return; // Nothing to do.
       
   145     QWidgetData *widgetData = qt_qwidget_data(qwidget);
       
   146     if ((widgetData->window_state & Qt::WindowMaximized) && ![window isZoomed]) {
       
   147         widgetData->window_state &= ~Qt::WindowMaximized;
       
   148         QWindowStateChangeEvent e(Qt::WindowState(widgetData->window_state | Qt::WindowMaximized));
       
   149         qt_sendSpontaneousEvent(qwidget, &e);
       
   150     }
       
   151 }
       
   152 
       
   153 - (NSSize)closestAcceptableSizeForWidget:(QWidget *)qwidget window:(NSWindow *)window
       
   154                              withNewSize:(NSSize)proposedSize
       
   155 {
       
   156     [self dumpMaximizedStateforWidget:qwidget window:window];
       
   157     QSize newSize = QLayout::closestAcceptableSize(qwidget, 
       
   158                                                    QSize(proposedSize.width, proposedSize.height));
       
   159     return [NSWindow frameRectForContentRect:
       
   160             NSMakeRect(0., 0., newSize.width(), newSize.height())
       
   161                                    styleMask:[window styleMask]].size;
       
   162 }
       
   163 
       
   164 - (NSSize)windowWillResize:(NSWindow *)windowToResize toSize:(NSSize)proposedFrameSize
       
   165 {
       
   166     QWidget *qwidget = m_windowHash->value(windowToResize);
       
   167     return [self closestAcceptableSizeForWidget:qwidget window:windowToResize
       
   168                                     withNewSize:[NSWindow contentRectForFrameRect:
       
   169                                                  NSMakeRect(0, 0, 
       
   170                                                             proposedFrameSize.width,
       
   171                                                             proposedFrameSize.height) 
       
   172                                                     styleMask:[windowToResize styleMask]].size];
       
   173 }
       
   174 
       
   175 - (NSSize)drawerWillResizeContents:(NSDrawer *)sender toSize:(NSSize)contentSize
       
   176 {
       
   177     QWidget *qwidget = m_drawerHash->value(sender);
       
   178     return [self closestAcceptableSizeForWidget:qwidget window:nil withNewSize:contentSize];
       
   179 }
       
   180 
       
   181 -(void)windowDidMiniaturize:(NSNotification*)notification
       
   182 {
       
   183     QWidget *qwidget = m_windowHash->value([notification object]);
       
   184     if (!qwidget->isMinimized()) {
       
   185         QWidgetData *widgetData = qt_qwidget_data(qwidget);
       
   186         widgetData->window_state = widgetData->window_state | Qt::WindowMinimized;
       
   187         QWindowStateChangeEvent e(Qt::WindowStates(widgetData->window_state & ~Qt::WindowMinimized));
       
   188         qt_sendSpontaneousEvent(qwidget, &e);
       
   189     }
       
   190     // Send hide to match Qt on X11 and Windows
       
   191     QEvent e(QEvent::Hide);
       
   192     qt_sendSpontaneousEvent(qwidget, &e);
       
   193 }
       
   194 
       
   195 - (void)windowDidResize:(NSNotification *)notification
       
   196 {
       
   197     NSWindow *window = [notification object];
       
   198     QWidget *qwidget = m_windowHash->value(window);
       
   199     QWidgetData *widgetData = qt_qwidget_data(qwidget);
       
   200     if (!(qwidget->windowState() & (Qt::WindowMaximized | Qt::WindowFullScreen)) && [window isZoomed]) {
       
   201         widgetData->window_state = widgetData->window_state | Qt::WindowMaximized;
       
   202         QWindowStateChangeEvent e(Qt::WindowStates(widgetData->window_state
       
   203                                                    & ~Qt::WindowMaximized));
       
   204         qt_sendSpontaneousEvent(qwidget, &e);
       
   205     }
       
   206     NSRect rect = [[window contentView] frame];
       
   207     const QSize newSize(rect.size.width, rect.size.height);
       
   208     const QSize &oldSize = widgetData->crect.size();
       
   209     if (newSize != oldSize) {
       
   210         QWidgetPrivate::qt_mac_update_sizer(qwidget);
       
   211         [self syncSizeForWidget:qwidget toSize:newSize fromSize:oldSize];
       
   212     }
       
   213 }
       
   214 
       
   215 - (void)windowDidMove:(NSNotification *)notification
       
   216 {
       
   217     // The code underneath needs to translate the window location
       
   218     // from bottom left (which is the origin used by Cocoa) to
       
   219     // upper left (which is the origin used by Qt):
       
   220     NSWindow *window = [notification object];
       
   221     NSRect newRect = [window frame];
       
   222     QWidget *qwidget = m_windowHash->value(window);
       
   223     QPoint qtPoint = flipPoint(NSMakePoint(newRect.origin.x,
       
   224                                            newRect.origin.y + newRect.size.height)).toPoint();
       
   225     const QRect &oldRect = qwidget->frameGeometry();
       
   226 
       
   227     if (qtPoint.x() != oldRect.x() || qtPoint.y() != oldRect.y()) {
       
   228         QWidgetData *widgetData = qt_qwidget_data(qwidget);
       
   229         QRect oldCRect = widgetData->crect;
       
   230         QWidgetPrivate *widgetPrivate = qt_widget_private(qwidget);
       
   231         const QRect &fStrut = widgetPrivate->frameStrut();
       
   232         widgetData->crect.moveTo(qtPoint.x() + fStrut.left(), qtPoint.y() + fStrut.top());
       
   233         if (!qwidget->isVisible()) {
       
   234             qwidget->setAttribute(Qt::WA_PendingMoveEvent, true);
       
   235         } else {
       
   236             QMoveEvent qme(qtPoint, oldRect.topLeft());
       
   237             qt_sendSpontaneousEvent(qwidget, &qme);
       
   238         }
       
   239     }
       
   240 }
       
   241 
       
   242 -(BOOL)windowShouldClose:(id)windowThatWantsToClose
       
   243 {
       
   244     QWidget *qwidget = m_windowHash->value(windowThatWantsToClose);
       
   245     QScopedLoopLevelCounter counter(qt_widget_private(qwidget)->threadData);
       
   246     return qt_widget_private(qwidget)->close_helper(QWidgetPrivate::CloseWithSpontaneousEvent);
       
   247 }
       
   248 
       
   249 -(void)windowDidDeminiaturize:(NSNotification *)notification
       
   250 {
       
   251     QWidget *qwidget = m_windowHash->value([notification object]);
       
   252     QWidgetData *widgetData = qt_qwidget_data(qwidget);
       
   253     Qt::WindowStates currState = Qt::WindowStates(widgetData->window_state);
       
   254     Qt::WindowStates newState = currState;
       
   255     if (currState & Qt::WindowMinimized)
       
   256         newState &= ~Qt::WindowMinimized;
       
   257     if (!(currState & Qt::WindowActive))
       
   258         newState |= Qt::WindowActive;
       
   259     if (newState != currState) {
       
   260         widgetData->window_state = newState;
       
   261         QWindowStateChangeEvent e(currState);
       
   262         qt_sendSpontaneousEvent(qwidget, &e);
       
   263     }
       
   264     QShowEvent qse;
       
   265     qt_sendSpontaneousEvent(qwidget, &qse);
       
   266 }
       
   267 
       
   268 -(void)windowDidBecomeMain:(NSNotification*)notification
       
   269 {
       
   270     QWidget *qwidget = m_windowHash->value([notification object]);
       
   271     Q_ASSERT(qwidget);
       
   272     if (qwidget->isActiveWindow())
       
   273         return;  // Widget is already active, no need to go through re-activation.
       
   274 
       
   275     onApplicationWindowChangedActivation(qwidget, true);
       
   276 }
       
   277 
       
   278 -(void)windowDidResignMain:(NSNotification*)notification
       
   279 {
       
   280     QWidget *qwidget = m_windowHash->value([notification object]);
       
   281     Q_ASSERT(qwidget);
       
   282     onApplicationWindowChangedActivation(qwidget, false);
       
   283 }
       
   284 
       
   285 // These are the same as main, but they are probably better to keep separate since there is a
       
   286 // tiny difference between main and key windows.
       
   287 -(void)windowDidBecomeKey:(NSNotification*)notification
       
   288 {
       
   289     QWidget *qwidget = m_windowHash->value([notification object]);
       
   290     Q_ASSERT(qwidget);
       
   291     if (qwidget->isActiveWindow())
       
   292         return;  // Widget is already active, no need to go through re-activation
       
   293 
       
   294 
       
   295     onApplicationWindowChangedActivation(qwidget, true);
       
   296 }
       
   297 
       
   298 -(void)windowDidResignKey:(NSNotification*)notification
       
   299 {
       
   300     QWidget *qwidget = m_windowHash->value([notification object]);
       
   301     Q_ASSERT(qwidget);
       
   302     onApplicationWindowChangedActivation(qwidget, false);
       
   303 }
       
   304 
       
   305 -(QWidget *)qt_qwidgetForWindow:(NSWindow *)window
       
   306 {
       
   307     return m_windowHash->value(window);
       
   308 }
       
   309 
       
   310 - (NSRect)windowWillUseStandardFrame:(NSWindow *)window defaultFrame:(NSRect)defaultFrame
       
   311 {
       
   312     NSRect frameToReturn = defaultFrame;
       
   313     QWidget *qwidget = m_windowHash->value(window);
       
   314     QSizeF size = qwidget->maximumSize();
       
   315     frameToReturn.size.width = qMin<CGFloat>(frameToReturn.size.width, size.width());
       
   316     frameToReturn.size.height = qMin<CGFloat>(frameToReturn.size.height, size.height());
       
   317     return frameToReturn;
       
   318 }
       
   319 
       
   320 - (void)becomeDelegteForWindow:(NSWindow *)window  widget:(QWidget *)widget
       
   321 {
       
   322     m_windowHash->insert(window, widget);
       
   323     [window setDelegate:self];
       
   324 }
       
   325 
       
   326 - (void)resignDelegateForWindow:(NSWindow *)window
       
   327 {
       
   328     [window setDelegate:nil];
       
   329     m_windowHash->remove(window);
       
   330 }
       
   331 
       
   332 - (void)becomeDelegateForDrawer:(NSDrawer *)drawer widget:(QWidget *)widget
       
   333 {
       
   334     m_drawerHash->insert(drawer, widget);
       
   335     [drawer setDelegate:self];
       
   336     NSWindow *window = [[drawer contentView] window];
       
   337     [self becomeDelegteForWindow:window widget:widget];
       
   338 }
       
   339 
       
   340 - (void)resignDelegateForDrawer:(NSDrawer *)drawer
       
   341 {
       
   342     QWidget *widget = m_drawerHash->value(drawer);
       
   343     [drawer setDelegate:nil];
       
   344     if (widget)
       
   345         [self resignDelegateForWindow:[[drawer contentView] window]];
       
   346     m_drawerHash->remove(drawer);
       
   347 }
       
   348 
       
   349 @end
       
   350 #endif// QT_MAC_USE_COCOA