src/gui/kernel/qcocoaview_mac.mm
changeset 30 5dc02b23752f
parent 18 2f34d5167611
child 33 3e2da88830cd
equal deleted inserted replaced
29:b72c6db6890b 30:5dc02b23752f
    79 Q_GLOBAL_STATIC(DnDParams, qMacDnDParams);
    79 Q_GLOBAL_STATIC(DnDParams, qMacDnDParams);
    80 
    80 
    81 extern void qt_mac_update_cursor_at_global_pos(const QPoint &globalPos); // qcursor_mac.mm
    81 extern void qt_mac_update_cursor_at_global_pos(const QPoint &globalPos); // qcursor_mac.mm
    82 extern bool qt_sendSpontaneousEvent(QObject *, QEvent *); // qapplication.cpp
    82 extern bool qt_sendSpontaneousEvent(QObject *, QEvent *); // qapplication.cpp
    83 extern OSViewRef qt_mac_nativeview_for(const QWidget *w); // qwidget_mac.mm
    83 extern OSViewRef qt_mac_nativeview_for(const QWidget *w); // qwidget_mac.mm
    84 extern const QStringList& qEnabledDraggedTypes(); // qmime_mac.cpp
       
    85 extern QPointer<QWidget> qt_mouseover; //qapplication_mac.mm
    84 extern QPointer<QWidget> qt_mouseover; //qapplication_mac.mm
    86 extern QPointer<QWidget> qt_button_down; //qapplication_mac.cpp
    85 extern QPointer<QWidget> qt_button_down; //qapplication_mac.cpp
    87 
    86 extern Qt::MouseButton cocoaButton2QtButton(NSInteger buttonNum);
    88 Qt::MouseButton cocoaButton2QtButton(NSInteger buttonNum)
       
    89 {
       
    90     if (buttonNum == 0)
       
    91         return Qt::LeftButton;
       
    92     if (buttonNum == 1)
       
    93         return Qt::RightButton;
       
    94     if (buttonNum == 2)
       
    95         return Qt::MidButton;
       
    96     if (buttonNum == 3)
       
    97         return Qt::XButton1;
       
    98     if (buttonNum == 4)
       
    99         return Qt::XButton2;
       
   100     return Qt::NoButton;
       
   101 }
       
   102 
    87 
   103 struct dndenum_mapper
    88 struct dndenum_mapper
   104 {
    89 {
   105     NSDragOperation mac_code;
    90     NSDragOperation mac_code;
   106     Qt::DropAction qt_code;
    91     Qt::DropAction qt_code;
   198 QT_USE_NAMESPACE
   183 QT_USE_NAMESPACE
   199 extern "C" {
   184 extern "C" {
   200     extern NSString *NSTextInputReplacementRangeAttributeName;
   185     extern NSString *NSTextInputReplacementRangeAttributeName;
   201 }
   186 }
   202 
   187 
       
   188 #ifdef ALIEN_DEBUG
       
   189 static int qCocoaViewCount = 0;
       
   190 #endif
   203 
   191 
   204 @implementation QT_MANGLE_NAMESPACE(QCocoaView)
   192 @implementation QT_MANGLE_NAMESPACE(QCocoaView)
   205 
   193 
   206 - (id)initWithQWidget:(QWidget *)widget widgetPrivate:(QWidgetPrivate *)widgetprivate
   194 - (id)initWithQWidget:(QWidget *)widget widgetPrivate:(QWidgetPrivate *)widgetprivate
   207 {
   195 {
   208     self = [super init];
   196     self = [super init];
   209     if (self) {
   197     if (self) {
   210         [self finishInitWithQWidget:widget widgetPrivate:widgetprivate];
   198         [self finishInitWithQWidget:widget widgetPrivate:widgetprivate];
   211     }
   199     }
       
   200     [self setFocusRingType:NSFocusRingTypeNone];
   212     composingText = new QString();
   201     composingText = new QString();
       
   202 
       
   203 #ifdef ALIEN_DEBUG
       
   204     ++qCocoaViewCount;
       
   205     qDebug() << "init: qCocoaViewCount is" << qCocoaViewCount;
       
   206 #endif
       
   207 
   213     composing = false;
   208     composing = false;
   214     sendKeyEvents = true;
   209     sendKeyEvents = true;
   215     currentCustomTypes = 0;
       
   216     [self setHidden:YES];
   210     [self setHidden:YES];
   217     return self;
   211     return self;
   218 }
   212 }
   219 
   213 
   220 - (void) finishInitWithQWidget:(QWidget *)widget widgetPrivate:(QWidgetPrivate *)widgetprivate
   214 - (void) finishInitWithQWidget:(QWidget *)widget widgetPrivate:(QWidgetPrivate *)widgetprivate
   225                                              selector:@selector(frameDidChange:)
   219                                              selector:@selector(frameDidChange:)
   226                                                  name:@"NSViewFrameDidChangeNotification"
   220                                                  name:@"NSViewFrameDidChangeNotification"
   227                                                object:self];
   221                                                object:self];
   228 }
   222 }
   229 
   223 
   230 -(void)registerDragTypes
       
   231 {
       
   232     QMacCocoaAutoReleasePool pool;
       
   233     // Calling registerForDraggedTypes is slow, so only do it once for each widget
       
   234     // or when the custom types change.
       
   235     const QStringList& customTypes = qEnabledDraggedTypes();
       
   236     if (currentCustomTypes == 0 || *currentCustomTypes != customTypes) {
       
   237         if (currentCustomTypes == 0)
       
   238             currentCustomTypes = new QStringList();
       
   239         *currentCustomTypes = customTypes;
       
   240         const NSString* mimeTypeGeneric = @"com.trolltech.qt.MimeTypeName";
       
   241 	NSMutableArray *supportedTypes = [NSMutableArray arrayWithObjects:NSColorPboardType,
       
   242                                    NSFilenamesPboardType, NSStringPboardType,
       
   243                                    NSFilenamesPboardType, NSPostScriptPboardType, NSTIFFPboardType,
       
   244                                    NSRTFPboardType, NSTabularTextPboardType, NSFontPboardType,
       
   245                                    NSRulerPboardType, NSFileContentsPboardType, NSColorPboardType,
       
   246                                    NSRTFDPboardType, NSHTMLPboardType, NSPICTPboardType,
       
   247                                    NSURLPboardType, NSPDFPboardType, NSVCardPboardType,
       
   248                                    NSFilesPromisePboardType, NSInkTextPboardType,
       
   249                                    NSMultipleTextSelectionPboardType, mimeTypeGeneric, nil];
       
   250         // Add custom types supported by the application.
       
   251         for (int i = 0; i < customTypes.size(); i++) {
       
   252            [supportedTypes addObject:reinterpret_cast<const NSString *>(QCFString::toCFStringRef(customTypes[i]))];
       
   253         }
       
   254         [self registerForDraggedTypes:supportedTypes];
       
   255     }
       
   256 }
       
   257 
       
   258 - (void)resetCursorRects
   224 - (void)resetCursorRects
   259 {
   225 {
       
   226     // [NSView addCursorRect] is slow, so bail out early if we can:
       
   227     if (NSIsEmptyRect([self visibleRect]))
       
   228         return;
       
   229 
   260     QWidget *cursorWidget = qwidget;
   230     QWidget *cursorWidget = qwidget;
   261 
   231 
   262     if (cursorWidget->testAttribute(Qt::WA_TransparentForMouseEvents))
   232     if (cursorWidget->testAttribute(Qt::WA_TransparentForMouseEvents))
   263         cursorWidget = QApplication::widgetAt(qwidget->mapToGlobal(qwidget->rect().center()));
   233         cursorWidget = QApplication::widgetAt(qwidget->mapToGlobal(qwidget->rect().center()));
   264 
   234 
   270         return;
   240         return;
   271     }
   241     }
   272 
   242 
   273     QRegion mask = qt_widget_private(cursorWidget)->extra->mask;
   243     QRegion mask = qt_widget_private(cursorWidget)->extra->mask;
   274     NSCursor *nscursor = static_cast<NSCursor *>(qt_mac_nsCursorForQCursor(cursorWidget->cursor()));
   244     NSCursor *nscursor = static_cast<NSCursor *>(qt_mac_nsCursorForQCursor(cursorWidget->cursor()));
   275     if (mask.isEmpty()) {
   245     // The mask could have the WA_MouseNoMask attribute set and that means that we have to ignore the mask.
       
   246     if (mask.isEmpty() || cursorWidget->testAttribute(Qt::WA_MouseNoMask)) {
   276         [self addCursorRect:[qt_mac_nativeview_for(cursorWidget) visibleRect] cursor:nscursor];
   247         [self addCursorRect:[qt_mac_nativeview_for(cursorWidget) visibleRect] cursor:nscursor];
   277     } else {
   248     } else {
   278         const QVector<QRect> &rects = mask.rects();
   249         const QVector<QRect> &rects = mask.rects();
   279         for (int i = 0; i < rects.size(); ++i) {
   250         for (int i = 0; i < rects.size(); ++i) {
   280             const QRect &rect = rects.at(i);
   251             const QRect &rect = rects.at(i);
   298     dropData = new QCocoaDropData(dropPasteboard);
   269     dropData = new QCocoaDropData(dropPasteboard);
   299 }
   270 }
   300 
   271 
   301 - (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender
   272 - (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender
   302 {
   273 {
   303     if (qwidget->testAttribute(Qt::WA_DropSiteRegistered) == false)
   274     // NB: This function is called from QCoocaWindow/QCocoaPanel rather than directly
   304         return NSDragOperationNone;
   275     // from Cocoa. They modify the drag target, and might fake enter/leave events.
   305     NSPoint windowPoint = [sender draggingLocation];
   276     NSPoint windowPoint = [sender draggingLocation];
   306     if (qwidget->testAttribute(Qt::WA_TransparentForMouseEvents)) {
       
   307         // pass the drag enter event to the view underneath.
       
   308         NSView *candidateView = [[[self window] contentView] hitTest:windowPoint];
       
   309         if (candidateView && candidateView != self)
       
   310             return [candidateView draggingEntered:sender];
       
   311     }
       
   312     dragEnterSequence = [sender draggingSequenceNumber];
   277     dragEnterSequence = [sender draggingSequenceNumber];
   313     [self addDropData:sender];
   278     [self addDropData:sender];
   314     QMimeData *mimeData = dropData;
   279     QMimeData *mimeData = dropData;
   315     if (QDragManager::self()->source())
   280     if (QDragManager::self()->source())
   316         mimeData = QDragManager::self()->dragPrivate()->data;
   281         mimeData = QDragManager::self()->dragPrivate()->data;
   359         return nsActions;
   324         return nsActions;
   360     }
   325     }
   361  }
   326  }
   362 - (NSDragOperation)draggingUpdated:(id < NSDraggingInfo >)sender
   327 - (NSDragOperation)draggingUpdated:(id < NSDraggingInfo >)sender
   363 {
   328 {
       
   329     // NB: This function is called from QCoocaWindow/QCocoaPanel rather than directly
       
   330     // from Cocoa. They modify the drag target, and might fake enter/leave events.
   364     NSPoint windowPoint = [sender draggingLocation];
   331     NSPoint windowPoint = [sender draggingLocation];
   365     if (qwidget->testAttribute(Qt::WA_TransparentForMouseEvents)) {
       
   366         // pass the drag move event to the view underneath.
       
   367         NSView *candidateView = [[[self window] contentView] hitTest:windowPoint];
       
   368         if (candidateView && candidateView != self)
       
   369             return [candidateView draggingUpdated:sender];
       
   370     }
       
   371     // in cases like QFocusFrame, the view under the mouse might
   332     // in cases like QFocusFrame, the view under the mouse might
   372     // not have received the drag enter. Generate a synthetic
   333     // not have received the drag enter. Generate a synthetic
   373     // drag enter event for that view.
   334     // drag enter event for that view.
   374     if (dragEnterSequence != [sender draggingSequenceNumber])
   335     if (dragEnterSequence != [sender draggingSequenceNumber])
   375         [self draggingEntered:sender];
   336         [self draggingEntered:sender];
   415     return operation;
   376     return operation;
   416 }
   377 }
   417 
   378 
   418 - (void)draggingExited:(id < NSDraggingInfo >)sender
   379 - (void)draggingExited:(id < NSDraggingInfo >)sender
   419 {
   380 {
       
   381     // NB: This function is called from QCoocaWindow/QCocoaPanel rather than directly
       
   382     // from Cocoa. They modify the drag target, and might fake enter/leave events.
       
   383     Q_UNUSED(sender);
   420     dragEnterSequence = -1;
   384     dragEnterSequence = -1;
   421     if (qwidget->testAttribute(Qt::WA_TransparentForMouseEvents)) {
       
   422         // try sending the leave event to the last view which accepted drag enter.
       
   423         DnDParams *dndParams = [QT_MANGLE_NAMESPACE(QCocoaView) currentMouseEvent];
       
   424         NSView *candidateView = [[[self window] contentView] hitTest:dndParams->activeDragEnterPos];
       
   425         if (candidateView && candidateView != self)
       
   426             return [candidateView draggingExited:sender];
       
   427     }
       
   428     // drag enter event was rejected, so ignore the move event.
   385     // drag enter event was rejected, so ignore the move event.
   429     if (dropData) {
   386     if (dropData) {
   430         QDragLeaveEvent de;
   387         QDragLeaveEvent de;
   431         QApplication::sendEvent(qwidget, &de);
   388         QApplication::sendEvent(qwidget, &de);
   432         [self removeDropData];
   389         [self removeDropData];
   433     }
   390     }
   434 }
   391 }
   435 
   392 
   436 - (BOOL)performDragOperation:(id <NSDraggingInfo>)sender
   393 - (BOOL)performDragOperation:(id <NSDraggingInfo>)sender
   437 {
   394 {
       
   395     // NB: This function is called from QCoocaWindow/QCocoaPanel rather than directly
       
   396     // from Cocoa. They modify the drag target, and might fake enter/leave events.
   438     NSPoint windowPoint = [sender draggingLocation];
   397     NSPoint windowPoint = [sender draggingLocation];
   439     dragEnterSequence = -1;
   398     dragEnterSequence = -1;
   440     if (qwidget->testAttribute(Qt::WA_TransparentForMouseEvents)) {
       
   441         // pass the drop event to the view underneath.
       
   442         NSView *candidateView = [[[self window] contentView] hitTest:windowPoint];
       
   443         if (candidateView && candidateView != self)
       
   444             return [candidateView performDragOperation:sender];
       
   445     }
       
   446     [self addDropData:sender];
   399     [self addDropData:sender];
   447 
   400 
   448     NSPoint globalPoint = [[sender draggingDestinationWindow] convertBaseToScreen:windowPoint];
   401     NSPoint globalPoint = [[sender draggingDestinationWindow] convertBaseToScreen:windowPoint];
   449     NSPoint localPoint = [self convertPoint:windowPoint fromView:nil];
   402     NSPoint localPoint = [self convertPoint:windowPoint fromView:nil];
   450     QPoint posDrop(localPoint.x, localPoint.y);
   403     QPoint posDrop(localPoint.x, localPoint.y);
   470 
   423 
   471 - (void)dealloc
   424 - (void)dealloc
   472 {
   425 {
   473     delete composingText;
   426     delete composingText;
   474     [[NSNotificationCenter defaultCenter] removeObserver:self];
   427     [[NSNotificationCenter defaultCenter] removeObserver:self];
   475     delete currentCustomTypes;
   428 
   476     [self unregisterDraggedTypes];
   429 #ifdef ALIEN_DEBUG
       
   430     --qCocoaViewCount;
       
   431     qDebug() << "qCocoaViewCount is" << qCocoaViewCount;
       
   432 #endif
       
   433 
   477     [super dealloc];
   434     [super dealloc];
   478 }
   435 }
   479 
   436 
   480 - (BOOL)isOpaque;
   437 - (BOOL)isOpaque;
   481 {
   438 {
       
   439     if (!qwidgetprivate)
       
   440         return [super isOpaque];
   482     return qwidgetprivate->isOpaque;
   441     return qwidgetprivate->isOpaque;
   483 }
   442 }
   484 
   443 
   485 - (BOOL)isFlipped;
   444 - (BOOL)isFlipped;
   486 {
   445 {
   487     return YES;
   446     return YES;
   488 }
   447 }
   489 
   448 
   490 - (BOOL) preservesContentDuringLiveResize;
   449 // We preserve the content of the view if WA_StaticContents is defined.
       
   450 //
       
   451 // More info in the Cocoa documentation:
       
   452 // http://developer.apple.com/mac/library/documentation/cocoa/conceptual/CocoaViewsGuide/Optimizing/Optimizing.html
       
   453 - (BOOL) preservesContentDuringLiveResize
   491 {
   454 {
   492     return qwidget->testAttribute(Qt::WA_StaticContents);
   455     return qwidget->testAttribute(Qt::WA_StaticContents);
   493 }
   456 }
   494 
   457 
   495 - (void) setFrameSize:(NSSize)newSize
   458 - (void) setFrameSize:(NSSize)newSize
   508     } else {
   471     } else {
   509         [self setNeedsDisplay:YES];
   472         [self setNeedsDisplay:YES];
   510     }
   473     }
   511 
   474 
   512     // Make sure the opengl context is updated on resize.
   475     // Make sure the opengl context is updated on resize.
   513     if (qwidgetprivate->isGLWidget) {
   476     if (qwidgetprivate && qwidgetprivate->isGLWidget) {
   514         qwidgetprivate->needWindowChange = true;
   477         qwidgetprivate->needWindowChange = true;
   515         QEvent event(QEvent::MacGLWindowChange);
   478         QEvent event(QEvent::MacGLWindowChange);
   516         qApp->sendEvent(qwidget, &event);
   479         qApp->sendEvent(qwidget, &event);
   517     }
   480     }
   518 }
   481 }
   519 
   482 
       
   483 // We catch the 'setNeedsDisplay:' message in order to avoid a useless full repaint.
       
   484 // During the resize, the top of the widget is repainted, probably because of the
       
   485 // change of coordinate space (Quartz vs Qt). This is then followed by this message:
       
   486 // -[NSView _setNeedsDisplayIfTopLeftChanged]
       
   487 // which force a full repaint by sending the message 'setNeedsDisplay:'.
       
   488 // That is what we are preventing here.
       
   489 - (void)setNeedsDisplay:(BOOL)flag {
       
   490     if (![self inLiveResize] || !(qwidget->testAttribute(Qt::WA_StaticContents))) {
       
   491         [super setNeedsDisplay:flag];
       
   492     }
       
   493 }
       
   494 
   520 - (void)drawRect:(NSRect)aRect
   495 - (void)drawRect:(NSRect)aRect
   521 {
   496 {
       
   497     if (!qwidget)
       
   498         return;
       
   499 
   522     if (QApplicationPrivate::graphicsSystem() != 0) {
   500     if (QApplicationPrivate::graphicsSystem() != 0) {
   523         if (QWidgetBackingStore *bs = qwidgetprivate->maybeBackingStore()) {
   501         if (qwidgetprivate->maybeBackingStore()) {
   524             // Drawing is handled on the window level
   502             // Drawing is handled on the window level
   525             // See qcocoasharedwindowmethods_mac_p.
   503             // See qcocoasharedwindowmethods_mac_p.h
   526             return;
   504             if (!qwidget->testAttribute(Qt::WA_PaintOnScreen))
       
   505                 return;
   527         }
   506         }
   528     }
   507     }
   529     CGContextRef cg = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort];
   508     CGContextRef cg = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort];
   530     qwidgetprivate->hd = cg;
   509     qwidgetprivate->hd = cg;
   531     CGContextSaveGState(cg);
   510     CGContextSaveGState(cg);
   533     if (qwidget->isVisible() && qwidget->updatesEnabled()) { //process the actual paint event.
   512     if (qwidget->isVisible() && qwidget->updatesEnabled()) { //process the actual paint event.
   534         if (qwidget->testAttribute(Qt::WA_WState_InPaintEvent))
   513         if (qwidget->testAttribute(Qt::WA_WState_InPaintEvent))
   535             qWarning("QWidget::repaint: Recursive repaint detected");
   514             qWarning("QWidget::repaint: Recursive repaint detected");
   536 
   515 
   537         const QRect qrect = QRect(aRect.origin.x, aRect.origin.y, aRect.size.width, aRect.size.height);
   516         const QRect qrect = QRect(aRect.origin.x, aRect.origin.y, aRect.size.width, aRect.size.height);
   538         QRegion qrgn(qrect);
   517         QRegion qrgn;
       
   518 
       
   519 	const NSRect *rects;
       
   520 	NSInteger count;
       
   521 	[self getRectsBeingDrawn:&rects count:&count];
       
   522 	for (int i = 0; i < count; ++i) {
       
   523 	    QRect tmpRect = QRect(rects[i].origin.x, rects[i].origin.y, rects[i].size.width, rects[i].size.height);
       
   524 	    qrgn += tmpRect;
       
   525 	}
   539 
   526 
   540         if (!qwidget->isWindow() && !qobject_cast<QAbstractScrollArea *>(qwidget->parent())) {
   527         if (!qwidget->isWindow() && !qobject_cast<QAbstractScrollArea *>(qwidget->parent())) {
   541             const QRegion &parentMask = qwidget->window()->mask();
   528             const QRegion &parentMask = qwidget->window()->mask();
   542             if (!parentMask.isEmpty()) {
   529             if (!parentMask.isEmpty()) {
   543                 const QPoint mappedPoint = qwidget->mapTo(qwidget->window(), qrect.topLeft());
   530                 const QPoint mappedPoint = qwidget->mapTo(qwidget->window(), qrect.topLeft());
   567         if (qwidget->isWindow() && !qwidgetprivate->isOpaque
   554         if (qwidget->isWindow() && !qwidgetprivate->isOpaque
   568                 && !qwidget->testAttribute(Qt::WA_MacBrushedMetal)) {
   555                 && !qwidget->testAttribute(Qt::WA_MacBrushedMetal)) {
   569             CGContextClearRect(cg, NSRectToCGRect(aRect));
   556             CGContextClearRect(cg, NSRectToCGRect(aRect));
   570         }
   557         }
   571 
   558 
       
   559         // Check for alien widgets, use qwidgetPrivate->drawWidget() to draw the widget if this
       
   560         // is the case. This makes sure child widgets are drawn as well, Cocoa does not know about
       
   561         // those and wont send them drawRect calls.
       
   562         if (qwidget->testAttribute(Qt::WA_NativeWindow) && qt_widget_private(qwidget)->hasAlienChildren == false) {
   572         if (engine && !qwidget->testAttribute(Qt::WA_NoSystemBackground)
   563         if (engine && !qwidget->testAttribute(Qt::WA_NoSystemBackground)
   573             && (qwidget->isWindow() || qwidget->autoFillBackground())
   564             && (qwidget->isWindow() || qwidget->autoFillBackground())
   574                 || qwidget->testAttribute(Qt::WA_TintedBackground)
   565                 || qwidget->testAttribute(Qt::WA_TintedBackground)
   575                 || qwidget->testAttribute(Qt::WA_StyledBackground)) {
   566                 || qwidget->testAttribute(Qt::WA_StyledBackground)) {
   576 #ifdef DEBUG_WIDGET_PAINT
   567 #ifdef DEBUG_WIDGET_PAINT
   586         QPaintEvent e(qrgn);
   577         QPaintEvent e(qrgn);
   587 #ifdef QT3_SUPPORT
   578 #ifdef QT3_SUPPORT
   588         e.setErased(true);
   579         e.setErased(true);
   589 #endif
   580 #endif
   590         qt_sendSpontaneousEvent(qwidget, &e);
   581         qt_sendSpontaneousEvent(qwidget, &e);
       
   582         } else {
       
   583            qwidget->setAttribute(Qt::WA_WState_InPaintEvent, false); // QWidgetPrivate::drawWidget sets this
       
   584            QWidgetPrivate *qwidgetPrivate = qt_widget_private(qwidget);
       
   585            qwidgetPrivate->drawWidget(qwidget, qrgn, QPoint(), QWidgetPrivate::DrawAsRoot | QWidgetPrivate::DrawPaintOnScreen | QWidgetPrivate::DrawRecursive, 0);
       
   586         }
       
   587 
   591         if (!redirectionOffset.isNull())
   588         if (!redirectionOffset.isNull())
   592             QPainter::restoreRedirected(qwidget);
   589             QPainter::restoreRedirected(qwidget);
   593         if (engine)
   590         if (engine)
   594             engine->setSystemClip(QRegion());
   591             engine->setSystemClip(QRegion());
   595         qwidget->setAttribute(Qt::WA_WState_InPaintEvent, false);
   592         qwidget->setAttribute(Qt::WA_WState_InPaintEvent, false);
   601     CGContextRestoreGState(cg);
   598     CGContextRestoreGState(cg);
   602 }
   599 }
   603 
   600 
   604 - (BOOL)acceptsFirstMouse:(NSEvent *)theEvent
   601 - (BOOL)acceptsFirstMouse:(NSEvent *)theEvent
   605 {
   602 {
       
   603     if (!qwidget)
       
   604         return NO;
       
   605 
   606     Q_UNUSED(theEvent);
   606     Q_UNUSED(theEvent);
   607     return !qwidget->testAttribute(Qt::WA_MacNoClickThrough);
   607     return !qwidget->testAttribute(Qt::WA_MacNoClickThrough);
   608 }
   608 }
   609 
   609 
   610 - (NSView *)hitTest:(NSPoint)aPoint
   610 - (NSView *)hitTest:(NSPoint)aPoint
   611 {
   611 {
       
   612     if (!qwidget)
       
   613         return [super hitTest:aPoint];
       
   614 
   612     if (qwidget->testAttribute(Qt::WA_TransparentForMouseEvents))
   615     if (qwidget->testAttribute(Qt::WA_TransparentForMouseEvents))
   613         return nil; // You cannot hit a transparent for mouse event widget.
   616         return nil; // You cannot hit a transparent for mouse event widget.
   614     return [super hitTest:aPoint];
   617     return [super hitTest:aPoint];
   615 }
   618 }
   616 
   619 
   617 - (void)updateTrackingAreas
   620 - (void)updateTrackingAreas
   618 {
   621 {
       
   622     if (!qwidget)
       
   623         return;
       
   624 
       
   625     // [NSView addTrackingArea] is slow, so bail out early if we can:
       
   626     if (NSIsEmptyRect([self visibleRect]))
       
   627         return;
       
   628 
   619     QMacCocoaAutoReleasePool pool;
   629     QMacCocoaAutoReleasePool pool;
   620     if (NSArray *trackingArray = [self trackingAreas]) {
   630     if (NSArray *trackingArray = [self trackingAreas]) {
   621         NSUInteger size = [trackingArray count];
   631         NSUInteger size = [trackingArray count];
   622         for (NSUInteger i = 0; i < size; ++i) {
   632         for (NSUInteger i = 0; i < size; ++i) {
   623             NSTrackingArea *t = [trackingArray objectAtIndex:i];
   633             NSTrackingArea *t = [trackingArray objectAtIndex:i];
   643     [ta release];
   653     [ta release];
   644 }
   654 }
   645 
   655 
   646 - (void)mouseEntered:(NSEvent *)event
   656 - (void)mouseEntered:(NSEvent *)event
   647 {
   657 {
       
   658     if (!qwidget)
       
   659         return;
   648     if (qwidgetprivate->data.in_destructor)
   660     if (qwidgetprivate->data.in_destructor)
   649         return;
   661         return;
   650     QEvent enterEvent(QEvent::Enter);
   662 
   651     NSPoint windowPoint = [event locationInWindow];
       
   652     NSPoint globalPoint = [[event window] convertBaseToScreen:windowPoint];
       
   653     NSPoint viewPoint = [self convertPoint:windowPoint fromView:nil];
       
   654     if (!qAppInstance()->activeModalWidget() || QApplicationPrivate::tryModalHelper(qwidget, 0)) {
   663     if (!qAppInstance()->activeModalWidget() || QApplicationPrivate::tryModalHelper(qwidget, 0)) {
       
   664         QEvent enterEvent(QEvent::Enter);
       
   665         NSPoint windowPoint = [event locationInWindow];
       
   666         NSPoint globalPoint = [[event window] convertBaseToScreen:windowPoint];
       
   667         NSPoint viewPoint = [self convertPoint:windowPoint fromView:nil];
   655         QApplication::sendEvent(qwidget, &enterEvent);
   668         QApplication::sendEvent(qwidget, &enterEvent);
   656         qt_mouseover = qwidget;
   669         qt_mouseover = qwidget;
   657 
   670 
   658         // Update cursor and dispatch hover events.
   671         // Update cursor icon:
   659         qt_mac_update_cursor_at_global_pos(flipPoint(globalPoint).toPoint());
   672         qt_mac_update_cursor_at_global_pos(flipPoint(globalPoint).toPoint());
   660         if (qwidget->testAttribute(Qt::WA_Hover) &&
   673 
   661             (!qAppInstance()->activePopupWidget() || qAppInstance()->activePopupWidget() == qwidget->window())) {
   674         // Send mouse move and hover events as well:
   662             QHoverEvent he(QEvent::HoverEnter, QPoint(viewPoint.x, viewPoint.y), QPoint(-1, -1));
   675         if (!qAppInstance()->activePopupWidget() || qAppInstance()->activePopupWidget() == qwidget->window()) {
   663             QApplicationPrivate::instance()->notify_helper(qwidget, &he);
   676             // This mouse move event should be sendt, even when mouse
       
   677             // tracking is switched off (to trigger tooltips):
       
   678             NSEvent *mouseEvent = [NSEvent mouseEventWithType:NSMouseMoved
       
   679                 location:windowPoint modifierFlags:[event modifierFlags] timestamp:[event timestamp]
       
   680                 windowNumber:[event windowNumber] context:[event context] eventNumber:[event eventNumber]
       
   681                 clickCount:0 pressure:0];
       
   682             qt_mac_handleMouseEvent(self, mouseEvent, QEvent::MouseMove, Qt::NoButton);
       
   683 
       
   684             if (qwidget->testAttribute(Qt::WA_Hover)) {
       
   685                 QHoverEvent he(QEvent::HoverEnter, QPoint(viewPoint.x, viewPoint.y), QPoint(-1, -1));
       
   686                 QApplicationPrivate::instance()->notify_helper(qwidget, &he);
       
   687             }
   664         }
   688         }
   665     }
   689     }
   666 }
   690 }
   667 
   691 
   668 - (void)mouseExited:(NSEvent *)event
   692 - (void)mouseExited:(NSEvent *)event
   669 {
   693 {
       
   694     if (!qwidget)
       
   695         return;
       
   696 
   670     QEvent leaveEvent(QEvent::Leave);
   697     QEvent leaveEvent(QEvent::Leave);
   671     NSPoint globalPoint = [[event window] convertBaseToScreen:[event locationInWindow]];
   698     NSPoint globalPoint = [[event window] convertBaseToScreen:[event locationInWindow]];
   672     if (!qAppInstance()->activeModalWidget() || QApplicationPrivate::tryModalHelper(qwidget, 0)) {
   699     if (!qAppInstance()->activeModalWidget() || QApplicationPrivate::tryModalHelper(qwidget, 0)) {
   673         QApplication::sendEvent(qwidget, &leaveEvent);
   700         QApplication::sendEvent(qwidget, &leaveEvent);
   674 
   701 
   683     }
   710     }
   684 }
   711 }
   685 
   712 
   686 - (void)flagsChanged:(NSEvent *)theEvent
   713 - (void)flagsChanged:(NSEvent *)theEvent
   687 {
   714 {
       
   715     if (!qwidget)
       
   716         return;
       
   717 
   688     QWidget *widgetToGetKey = qwidget;
   718     QWidget *widgetToGetKey = qwidget;
   689 
   719 
   690     QWidget *popup = qAppInstance()->activePopupWidget();
   720     QWidget *popup = qAppInstance()->activePopupWidget();
   691     if (popup && popup != qwidget->window())
   721     if (popup && popup != qwidget->window())
   692         widgetToGetKey = popup->focusWidget() ? popup->focusWidget() : popup;
   722         widgetToGetKey = popup->focusWidget() ? popup->focusWidget() : popup;
   694     [super flagsChanged:theEvent];
   724     [super flagsChanged:theEvent];
   695 }
   725 }
   696 
   726 
   697 - (void)mouseMoved:(NSEvent *)theEvent
   727 - (void)mouseMoved:(NSEvent *)theEvent
   698 {
   728 {
       
   729     if (!qwidget)
       
   730         return;
       
   731 
   699     // We always enable mouse tracking for all QCocoaView-s. In cases where we have
   732     // We always enable mouse tracking for all QCocoaView-s. In cases where we have
   700     // child views, we will receive mouseMoved for both parent & the child (if
   733     // child views, we will receive mouseMoved for both parent & the child (if
   701     // mouse is over the child). We need to ignore the parent mouseMoved in such
   734     // mouse is over the child). We need to ignore the parent mouseMoved in such
   702     // cases.
   735     // cases.
   703     NSPoint windowPoint = [theEvent locationInWindow];
   736     NSPoint windowPoint = [theEvent locationInWindow];
   813 
   846 
   814     if (scrollEvent) {
   847     if (scrollEvent) {
   815         // The mouse device containts pixel scroll wheel support (Mighty Mouse, Trackpad).
   848         // The mouse device containts pixel scroll wheel support (Mighty Mouse, Trackpad).
   816         // Since deviceDelta is delivered as pixels rather than degrees, we need to
   849         // Since deviceDelta is delivered as pixels rather than degrees, we need to
   817         // convert from pixels to degrees in a sensible manner.
   850         // convert from pixels to degrees in a sensible manner.
   818         // It looks like four degrees per pixel behaves most native.
   851         // It looks like 1/4 degrees per pixel behaves most native.
   819         // Qt expects the unit for delta to be 1/8 of a degree:
   852         // (NB: Qt expects the unit for delta to be 8 per degree):
   820         deltaX = [theEvent deviceDeltaX];
   853         const int pixelsToDegrees = 2; // 8 * 1/4
   821         deltaY = [theEvent deviceDeltaY];
   854         deltaX = [theEvent deviceDeltaX] * pixelsToDegrees;
   822         deltaZ = [theEvent deviceDeltaZ];
   855         deltaY = [theEvent deviceDeltaY] * pixelsToDegrees;
       
   856         deltaZ = [theEvent deviceDeltaZ] * pixelsToDegrees;
   823     } else {
   857     } else {
   824         // carbonEventKind == kEventMouseWheelMoved
   858         // carbonEventKind == kEventMouseWheelMoved
   825         // Remove acceleration, and use either -120 or 120 as delta:
   859         // Remove acceleration, and use either -120 or 120 as delta:
   826         deltaX = qBound(-120, int([theEvent deltaX] * 10000), 120);
   860         deltaX = qBound(-120, int([theEvent deltaX] * 10000), 120);
   827         deltaY = qBound(-120, int([theEvent deltaY] * 10000), 120);
   861         deltaY = qBound(-120, int([theEvent deltaY] * 10000), 120);
   984 }
  1018 }
   985 
  1019 
   986 - (void)frameDidChange:(NSNotification *)note
  1020 - (void)frameDidChange:(NSNotification *)note
   987 {
  1021 {
   988     Q_UNUSED(note);
  1022     Q_UNUSED(note);
       
  1023     if (!qwidget)
       
  1024         return;
   989     if (qwidget->isWindow())
  1025     if (qwidget->isWindow())
   990         return;
  1026         return;
   991     NSRect newFrame = [self frame];
  1027     NSRect newFrame = [self frame];
   992     QRect newGeo(newFrame.origin.x, newFrame.origin.y, newFrame.size.width, newFrame.size.height);
  1028     QRect newGeo(newFrame.origin.x, newFrame.origin.y, newFrame.size.width, newFrame.size.height);
   993     bool moved = qwidget->testAttribute(Qt::WA_Moved);
  1029     bool moved = qwidget->testAttribute(Qt::WA_Moved);
  1007 
  1043 
  1008 - (void)setEnabled:(BOOL)flag
  1044 - (void)setEnabled:(BOOL)flag
  1009 {
  1045 {
  1010     QMacCocoaAutoReleasePool pool;
  1046     QMacCocoaAutoReleasePool pool;
  1011     [super setEnabled:flag];
  1047     [super setEnabled:flag];
  1012     if (qwidget->isEnabled() != flag)
  1048     if (qwidget && qwidget->isEnabled() != flag)
  1013         qwidget->setEnabled(flag);
  1049         qwidget->setEnabled(flag);
  1014 }
  1050 }
  1015 
  1051 
  1016 + (Class)cellClass
  1052 + (Class)cellClass
  1017 {
  1053 {
  1018     return [NSActionCell class];
  1054     return [NSActionCell class];
  1019 }
  1055 }
  1020 
  1056 
  1021 - (BOOL)acceptsFirstResponder
  1057 - (BOOL)acceptsFirstResponder
  1022 {
  1058 {
  1023     if (qwidget->isWindow())
  1059     if (!qwidget)
       
  1060         return NO;
       
  1061     // disabled widget shouldn't get focus even if it's a window.
       
  1062     // hence disabled windows will not get any key or mouse events.
       
  1063     if (!qwidget->isEnabled())
       
  1064         return NO;
       
  1065     // Before accepting the focus for a window, we check that
       
  1066     // the focusWidget (if any) is not contained in the same window.
       
  1067     if (qwidget->isWindow() && !qt_widget_private(qwidget)->topData()->embedded
       
  1068         && (!qApp->focusWidget() || qApp->focusWidget()->window() != qwidget)) {
  1024         return YES;  // Always do it, so that windows can accept key press events.
  1069         return YES;  // Always do it, so that windows can accept key press events.
       
  1070     }
  1025     return qwidget->focusPolicy() != Qt::NoFocus;
  1071     return qwidget->focusPolicy() != Qt::NoFocus;
  1026 }
  1072 }
  1027 
  1073 
  1028 - (BOOL)resignFirstResponder
  1074 - (BOOL)resignFirstResponder
  1029 {
  1075 {
       
  1076     if (!qwidget)
       
  1077         return NO;
  1030     // Seems like the following test only triggers if this
  1078     // Seems like the following test only triggers if this
  1031     // view is inside a QMacNativeWidget:
  1079     // view is inside a QMacNativeWidget:
  1032     if (qwidget == QApplication::focusWidget())
  1080     if (qwidget == QApplication::focusWidget())
  1033         QApplicationPrivate::setFocusWidget(0, Qt::OtherFocusReason);
  1081         qwidget->clearFocus();
       
  1082     return YES;
       
  1083 }
       
  1084 
       
  1085 - (BOOL)becomeFirstResponder
       
  1086 {
       
  1087     // see the comment in the acceptsFirstResponder - if the window "stole" focus
       
  1088     // let it become the responder, but don't tell Qt
       
  1089     if (qwidget && qt_widget_private(qwidget->window())->topData()->embedded
       
  1090         && !QApplication::focusWidget() && qwidget->focusPolicy() != Qt::NoFocus)
       
  1091         qwidget->setFocus(Qt::OtherFocusReason);
  1034     return YES;
  1092     return YES;
  1035 }
  1093 }
  1036 
  1094 
  1037 - (NSDragOperation)draggingSourceOperationMaskForLocal:(BOOL)isLocal
  1095 - (NSDragOperation)draggingSourceOperationMaskForLocal:(BOOL)isLocal
  1038 {
  1096 {
  1060 - (QWidget *)qt_qwidget
  1118 - (QWidget *)qt_qwidget
  1061 {
  1119 {
  1062     return qwidget;
  1120     return qwidget;
  1063 }
  1121 }
  1064 
  1122 
       
  1123 - (void) qt_clearQWidget
       
  1124 {
       
  1125     qwidget = 0;
       
  1126     qwidgetprivate = 0;
       
  1127 }
       
  1128 
  1065 - (BOOL)qt_leftButtonIsRightButton
  1129 - (BOOL)qt_leftButtonIsRightButton
  1066 {
  1130 {
  1067     return leftButtonIsRightButton;
  1131     return leftButtonIsRightButton;
  1068 }
  1132 }
  1069 
  1133 
  1096                  || widgetToGetKey->inputMethodHints() & Qt::ImhHiddenText)) {
  1160                  || widgetToGetKey->inputMethodHints() & Qt::ImhHiddenText)) {
  1097         [qt_mac_nativeview_for(widgetToGetKey) interpretKeyEvents:[NSArray arrayWithObject: theEvent]];
  1161         [qt_mac_nativeview_for(widgetToGetKey) interpretKeyEvents:[NSArray arrayWithObject: theEvent]];
  1098     }
  1162     }
  1099     if (sendKeyEvents && !composing) {
  1163     if (sendKeyEvents && !composing) {
  1100         bool keyOK = qt_dispatchKeyEvent(theEvent, widgetToGetKey);
  1164         bool keyOK = qt_dispatchKeyEvent(theEvent, widgetToGetKey);
  1101         if (!keyOK && !sendToPopup)
  1165         if (!keyOK && !sendToPopup) {
  1102             [super keyDown:theEvent];
  1166             // find the first responder that is not created by Qt and forward
       
  1167             // the event to it (for example if Qt widget is embedded into native).
       
  1168             QWidget *toplevel = qwidget->window();
       
  1169             if (toplevel && qt_widget_private(toplevel)->topData()->embedded) {
       
  1170                 if (NSResponder *w = [qt_mac_nativeview_for(toplevel) superview])
       
  1171                     [w keyDown:theEvent];
       
  1172             }
       
  1173         }
  1103     }
  1174     }
  1104 }
  1175 }
  1105 
  1176 
  1106 
  1177 
  1107 - (void)keyUp:(NSEvent *)theEvent
  1178 - (void)keyUp:(NSEvent *)theEvent
  1108 {
  1179 {
  1109     if (sendKeyEvents) {
  1180     if (sendKeyEvents) {
  1110         bool keyOK = qt_dispatchKeyEvent(theEvent, qwidget);
  1181         bool keyOK = qt_dispatchKeyEvent(theEvent, qwidget);
  1111         if (!keyOK)
  1182         if (!keyOK) {
  1112             [super keyUp:theEvent];
  1183             QWidget *toplevel = qwidget->window();
       
  1184             if (toplevel && qt_widget_private(toplevel)->topData()->embedded) {
       
  1185                 if (NSResponder *w = [qt_mac_nativeview_for(toplevel) superview])
       
  1186                     [w keyUp:theEvent];
       
  1187             }
       
  1188         }
  1113     }
  1189     }
  1114 }
  1190 }
  1115 
  1191 
  1116 - (void)viewWillMoveToWindow:(NSWindow *)window
  1192 - (void)viewWillMoveToWindow:(NSWindow *)window
  1117 {
  1193 {
       
  1194     if (qwidget == 0)
       
  1195         return;
       
  1196 
  1118     if (qwidget->windowFlags() & Qt::MSWindowsOwnDC
  1197     if (qwidget->windowFlags() & Qt::MSWindowsOwnDC
  1119           && (window != [self window])) { // OpenGL Widget
  1198           && (window != [self window])) { // OpenGL Widget
  1120         // Create a stupid ClearDrawable Event
       
  1121         QEvent event(QEvent::MacGLClearDrawable);
  1199         QEvent event(QEvent::MacGLClearDrawable);
  1122         qApp->sendEvent(qwidget, &event);
  1200         qApp->sendEvent(qwidget, &event);
  1123     }
  1201     }
  1124 }
  1202 }
  1125 
  1203 
  1126 - (void)viewDidMoveToWindow
  1204 - (void)viewDidMoveToWindow
  1127 {
  1205 {
       
  1206     if (qwidget == 0)
       
  1207         return;
       
  1208 
  1128     if (qwidget->windowFlags() & Qt::MSWindowsOwnDC && [self window]) {
  1209     if (qwidget->windowFlags() & Qt::MSWindowsOwnDC && [self window]) {
  1129         // call update paint event
  1210         // call update paint event
  1130         qwidgetprivate->needWindowChange = true;
  1211         qwidgetprivate->needWindowChange = true;
  1131         QEvent event(QEvent::MacGLWindowChange);
  1212         QEvent event(QEvent::MacGLWindowChange);
  1132         qApp->sendEvent(qwidget, &event);
  1213         qApp->sendEvent(qwidget, &event);
  1318     return NSNotFound;
  1399     return NSNotFound;
  1319 }
  1400 }
  1320 
  1401 
  1321 - (NSArray*) validAttributesForMarkedText
  1402 - (NSArray*) validAttributesForMarkedText
  1322 {
  1403 {
       
  1404     if (qwidget == 0)
       
  1405         return nil;
       
  1406 
  1323     if (!qwidget->testAttribute(Qt::WA_InputMethodEnabled))
  1407     if (!qwidget->testAttribute(Qt::WA_InputMethodEnabled))
  1324         return nil;  // Not sure if that's correct, but it's saves a malloc.
  1408         return nil;  // Not sure if that's correct, but it's saves a malloc.
  1325 
  1409 
  1326     // Support only underline color/style.
  1410     // Support only underline color/style.
  1327     return [NSArray arrayWithObjects:NSUnderlineColorAttributeName,
  1411     return [NSArray arrayWithObjects:NSUnderlineColorAttributeName,
  1468     // reset the implicit grab widget when drag ends because we will not
  1552     // reset the implicit grab widget when drag ends because we will not
  1469     // receive the mouse release event when DND is active.
  1553     // receive the mouse release event when DND is active.
  1470     qt_button_down = 0;
  1554     qt_button_down = 0;
  1471     [dndParams.view release];
  1555     [dndParams.view release];
  1472     [image release];
  1556     [image release];
  1473     dragPrivate()->executed_action = Qt::IgnoreAction;
  1557     if (dragPrivate())
       
  1558         dragPrivate()->executed_action = Qt::IgnoreAction;
  1474     object = 0;
  1559     object = 0;
  1475     Qt::DropAction performedAction(qt_mac_mapNSDragOperation(qMacDnDParams()->performedAction));
  1560     Qt::DropAction performedAction(qt_mac_mapNSDragOperation(qMacDnDParams()->performedAction));
  1476     // do post drag processing, if required.
  1561     // do post drag processing, if required.
  1477     if(performedAction != Qt::IgnoreAction) {
  1562     if(performedAction != Qt::IgnoreAction) {
  1478         // check if the receiver points us to a file location.
  1563         // check if the receiver points us to a file location.