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 |
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 { |
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); |
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. |