Qt 4.8
qcocoaview_mac.mm
Go to the documentation of this file.
1 /****************************************************************************
2 **
3 ** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
5 **
6 ** This file is part of the QtGui module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and Digia. For licensing terms and
14 ** conditions see http://qt.digia.com/licensing. For further information
15 ** use the contact form at http://qt.digia.com/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 **
25 ** In addition, as a special exception, Digia gives you certain additional
26 ** rights. These rights are described in the Digia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 **
29 ** GNU General Public License Usage
30 ** Alternatively, this file may be used under the terms of the GNU
31 ** General Public License version 3.0 as published by the Free Software
32 ** Foundation and appearing in the file LICENSE.GPL included in the
33 ** packaging of this file. Please review the following information to
34 ** ensure the GNU General Public License version 3.0 requirements will be
35 ** met: http://www.gnu.org/copyleft/gpl.html.
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41 #include <qconfig.h>
42 #import <private/qcocoaview_mac_p.h>
43 #ifdef QT_MAC_USE_COCOA
44 
45 #include <private/qwidget_p.h>
46 #include <private/qt_mac_p.h>
47 #include <private/qapplication_p.h>
48 #include <private/qabstractscrollarea_p.h>
49 #include <private/qt_cocoa_helpers_mac_p.h>
50 #include <private/qdnd_p.h>
51 #include <private/qmacinputcontext_p.h>
52 #include <private/qevent_p.h>
53 #include <private/qbackingstore_p.h>
54 #include <private/qwindowsurface_raster_p.h>
55 #include <private/qunifiedtoolbarsurface_mac_p.h>
56 
57 #include <qscrollarea.h>
58 #include <qhash.h>
59 #include <qtextformat.h>
60 #include <qpaintengine.h>
61 #include <QUrl>
62 #include <QAccessible>
63 #include <QFileInfo>
64 #include <QFile>
65 
66 #include <qdebug.h>
67 
68 @interface NSEvent (Qt_Compile_Leopard_DeviceDelta)
69  // SnowLeopard:
70  - (CGFloat)deviceDeltaX;
71  - (CGFloat)deviceDeltaY;
72  - (CGFloat)deviceDeltaZ;
73  // Lion:
74  - (CGFloat)scrollingDeltaX;
75  - (CGFloat)scrollingDeltaY;
76  - (CGFloat)scrollingDeltaZ;
77 @end
78 
79 @interface NSEvent (Qt_Compile_Leopard_Gestures)
80  - (CGFloat)magnification;
81 @end
82 
84 
85 extern void qt_mac_update_cursor(); // qcursor_mac.mm
86 extern bool qt_sendSpontaneousEvent(QObject *, QEvent *); // qapplication.cpp
87 extern QPointer<QWidget> qt_last_mouse_receiver; // qapplication_mac.cpp
88 extern QPointer<QWidget> qt_last_native_mouse_receiver; // qt_cocoa_helpers_mac.mm
89 extern OSViewRef qt_mac_nativeview_for(const QWidget *w); // qwidget_mac.mm
90 extern OSViewRef qt_mac_effectiveview_for(const QWidget *w); // qwidget_mac.mm
91 extern QPointer<QWidget> qt_button_down; //qapplication_mac.cpp
92 extern Qt::MouseButton cocoaButton2QtButton(NSInteger buttonNum);
94 extern bool qt_mac_clearDirtyOnWidgetInsideDrawWidget; // qwidget.cpp
95 
96 static QColor colorFrom(NSColor *color)
97 {
98  QColor qtColor;
99  NSString *colorSpace = [color colorSpaceName];
100  if (colorSpace == NSDeviceCMYKColorSpace) {
101  CGFloat cyan, magenta, yellow, black, alpha;
102  [color getCyan:&cyan magenta:&magenta yellow:&yellow black:&black alpha:&alpha];
103  qtColor.setCmykF(cyan, magenta, yellow, black, alpha);
104  } else {
105  NSColor *tmpColor;
106  tmpColor = [color colorUsingColorSpaceName:NSDeviceRGBColorSpace];
107  CGFloat red, green, blue, alpha;
108  [tmpColor getRed:&red green:&green blue:&blue alpha:&alpha];
109  qtColor.setRgbF(red, green, blue, alpha);
110  }
111  return qtColor;
112 }
113 
115 
136 extern "C" {
137  extern NSString *NSTextInputReplacementRangeAttributeName;
138 }
139 
140 //#define ALIEN_DEBUG 1
141 #ifdef ALIEN_DEBUG
142 static int qCocoaViewCount = 0;
143 #endif
144 
145 @implementation QT_MANGLE_NAMESPACE(QCocoaView)
146 
147 - (id)initWithQWidget:(QWidget *)widget widgetPrivate:(QWidgetPrivate *)widgetprivate
148 {
149  self = [super init];
150  if (self) {
151  [self finishInitWithQWidget:widget widgetPrivate:widgetprivate];
152  }
153  [self setFocusRingType:NSFocusRingTypeNone];
154  composingText = new QString();
155 
156 #ifdef ALIEN_DEBUG
157  ++qCocoaViewCount;
158  qDebug() << "Alien: create native view for" << widget << ". qCocoaViewCount is:" << qCocoaViewCount;
159 #endif
160 
161  composing = false;
162  sendKeyEvents = true;
163  fromKeyDownEvent = false;
164  alienTouchCount = 0;
165 
166  [self setHidden:YES];
167  return self;
168 }
169 
170 - (void) finishInitWithQWidget:(QWidget *)widget widgetPrivate:(QWidgetPrivate *)widgetprivate
171 {
172  qwidget = widget;
173  qwidgetprivate = widgetprivate;
174  [[NSNotificationCenter defaultCenter] addObserver:self
175  selector:@selector(frameDidChange:)
176  name:@"NSViewFrameDidChangeNotification"
177  object:self];
178 }
179 
180 - (void)dealloc
181 {
183  delete composingText;
184  [[NSNotificationCenter defaultCenter] removeObserver:self];
185 
186 #ifdef ALIEN_DEBUG
187  --qCocoaViewCount;
188  qDebug() << "Alien: widget deallocated. qCocoaViewCount is:" << qCocoaViewCount;
189 #endif
190 
191  [super dealloc];
192 }
193 
194 - (BOOL)isOpaque
195 {
196  if (!qwidgetprivate)
197  return [super isOpaque];
198  return qwidgetprivate->isOpaque;
199 }
200 
201 - (BOOL)isFlipped
202 {
203  return YES;
204 }
205 
206 // We preserve the content of the view if WA_StaticContents is defined.
207 //
208 // More info in the Cocoa documentation:
209 // http://developer.apple.com/mac/library/documentation/cocoa/conceptual/CocoaViewsGuide/Optimizing/Optimizing.html
210 - (BOOL) preservesContentDuringLiveResize
211 {
212  return qwidget->testAttribute(Qt::WA_StaticContents);
213 }
214 
215 - (void) setFrameSize:(NSSize)newSize
216 {
217  [super setFrameSize:newSize];
218 
219  // A change in size has required the view to be invalidated.
220  if ([self inLiveResize]) {
221  NSRect rects[4];
222  NSInteger count;
223  [self getRectsExposedDuringLiveResize:rects count:&count];
224  while (count-- > 0)
225  {
226  [self setNeedsDisplayInRect:rects[count]];
227  }
228  } else {
229  [self setNeedsDisplay:YES];
230  }
231 
232  // Make sure the opengl context is updated on resize.
233  if (qwidgetprivate && qwidgetprivate->isGLWidget && [self window]) {
234  qwidgetprivate->needWindowChange = true;
236  qApp->sendEvent(qwidget, &event);
237  }
238 }
239 
240 // We catch the 'setNeedsDisplay:' message in order to avoid a useless full repaint.
241 // During the resize, the top of the widget is repainted, probably because of the
242 // change of coordinate space (Quartz vs Qt). This is then followed by this message:
243 // -[NSView _setNeedsDisplayIfTopLeftChanged]
244 // which force a full repaint by sending the message 'setNeedsDisplay:'.
245 // That is what we are preventing here.
246 - (void)setNeedsDisplay:(BOOL)flag {
247  if (![self inLiveResize] || !(qwidget->testAttribute(Qt::WA_StaticContents))) {
248  [super setNeedsDisplay:flag];
249  }
250 }
251 
252 - (void)drawRect:(NSRect)aRect
253 {
254  if (!qwidget)
255  return;
256 
257  // Getting context.
258  CGContextRef context = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort];
260 
261  // We use a different graphics system.
262  //
263  // Widgets that are set to paint on screen, specifically QGLWidget,
264  // requires the native engine to execute in order to be drawn.
265  if (QApplicationPrivate::graphicsSystem() != 0 && !qwidget->testAttribute(Qt::WA_PaintOnScreen)) {
266 
267  // Raster engine.
269 
270  if (!qwidgetprivate->isInUnifiedToolbar) {
271 
272  // Qt handles the painting occuring inside the window.
273  // Cocoa also keeps track of all widgets as NSView and therefore might
274  // ask for a repainting of a widget even if Qt is already taking care of it.
275  //
276  // The only valid reason for Cocoa to call drawRect: is for window manipulation
277  // (ie. resize, ...).
278  //
279  // Qt will then forward the update to the children.
280  if (!qwidget->isWindow()) {
282  return;
283  }
284 
285  QRasterWindowSurface *winSurface = dynamic_cast<QRasterWindowSurface *>(qwidget->windowSurface());
286  if (!winSurface || !winSurface->needsFlush) {
288  return;
289  }
290 
291  // Clip to region.
292  const QVector<QRect> &rects = winSurface->regionToFlush.rects();
293  for (int i = 0; i < rects.size(); ++i) {
294  const QRect &rect = rects.at(i);
295  CGContextAddRect(context, CGRectMake(rect.x(), rect.y(), rect.width(), rect.height()));
296  }
297  CGContextClip(context);
298 
299  QRect r = winSurface->regionToFlush.boundingRect();
300  const CGRect area = CGRectMake(r.x(), r.y(), r.width(), r.height());
301 
302  qt_mac_draw_image(context, winSurface->imageContext(), area, area);
303 
304  winSurface->needsFlush = false;
305  winSurface->regionToFlush = QRegion();
306 
307  } else {
308 
309  QUnifiedToolbarSurface *unifiedSurface = qwidgetprivate->unifiedSurface;
310  if (!unifiedSurface) {
312  return;
313  }
314 
315  int areaX = qwidgetprivate->toolbar_offset.x();
316  int areaY = qwidgetprivate->toolbar_offset.y();
317  int areaWidth = qwidget->geometry().width();
318  int areaHeight = qwidget->geometry().height();
319  const CGRect area = CGRectMake(areaX, areaY, areaWidth, areaHeight);
320  const CGRect drawingArea = CGRectMake(0, 0, areaWidth, areaHeight);
321 
322  qt_mac_draw_image(context, unifiedSurface->imageContext(), area, drawingArea);
323 
324  qwidgetprivate->flushRequested = false;
325 
326  }
327 
328  CGContextSynchronize(context);
330  return;
331  }
332 
333  // Qt handles the painting occuring inside the window.
334  // Cocoa also keeps track of all widgets as NSView and therefore might
335  // ask for a repainting of a widget even if Qt is already taking care of it.
336  //
337  // The only valid reason for Cocoa to call drawRect: is for window manipulation
338  // (ie. resize, ...).
339  //
340  // Qt will then forward the update to the children.
341  if (qwidget->isWindow()) {
342  qwidget->update(qwidget->rect());
343  qwidgetprivate->syncBackingStore(qwidget->rect());
344  }
345  }
346 
347  // Native engine.
348  qwidgetprivate->hd = context;
349 
350  if (qwidget->isVisible() && qwidget->updatesEnabled()) { //process the actual paint event.
351  if (qwidget->testAttribute(Qt::WA_WState_InPaintEvent))
352  qWarning("QWidget::repaint: Recursive repaint detected");
353 
354  const QRect qrect = QRect(aRect.origin.x, aRect.origin.y, aRect.size.width, aRect.size.height);
355  QRegion qrgn;
356 
357  const NSRect *rects;
358  NSInteger count;
359  [self getRectsBeingDrawn:&rects count:&count];
360  for (int i = 0; i < count; ++i) {
361  QRect tmpRect = QRect(rects[i].origin.x, rects[i].origin.y, rects[i].size.width, rects[i].size.height);
362  qrgn += tmpRect;
363  }
364 
365  if (!qwidget->isWindow() && !qobject_cast<QAbstractScrollArea *>(qwidget->parent())) {
366  const QRegion &parentMask = qwidget->window()->mask();
367  if (!parentMask.isEmpty()) {
368  const QPoint mappedPoint = qwidget->mapTo(qwidget->window(), qrect.topLeft());
369  qrgn.translate(mappedPoint);
370  qrgn &= parentMask;
371  qrgn.translate(-mappedPoint.x(), -mappedPoint.y());
372  }
373  }
374 
375  QPoint redirectionOffset(0, 0);
376  //setup the context
377  qwidget->setAttribute(Qt::WA_WState_InPaintEvent);
378  QPaintEngine *engine = qwidget->paintEngine();
379  if (engine)
380  engine->setSystemClip(qrgn);
381  if (qwidgetprivate->extra && qwidgetprivate->extra->hasMask) {
382  CGRect widgetRect = CGRectMake(0, 0, qwidget->width(), qwidget->height());
383  CGContextTranslateCTM (context, 0, widgetRect.size.height);
384  CGContextScaleCTM(context, 1, -1);
385  if (qwidget->isWindow())
386  CGContextClearRect(context, widgetRect);
387  CGContextClipToMask(context, widgetRect, qwidgetprivate->extra->imageMask);
388  CGContextScaleCTM(context, 1, -1);
389  CGContextTranslateCTM (context, 0, -widgetRect.size.height);
390  }
391 
392  if (qwidget->isWindow() && !qwidgetprivate->isOpaque
393  && !qwidget->testAttribute(Qt::WA_MacBrushedMetal)) {
394  CGContextClearRect(context, NSRectToCGRect(aRect));
395  }
396 
397  qwidget->setAttribute(Qt::WA_WState_InPaintEvent, false);
398  QWidgetPrivate *qwidgetPrivate = qt_widget_private(qwidget);
399 
400  // We specify that we want to draw the widget itself, and
401  // all its children recursive. But we skip native children, because
402  // they will receive drawRect calls by themselves as needed:
406 
407  if (qwidget->isWindow())
409 
410  // Start to draw:
411  qt_mac_clearDirtyOnWidgetInsideDrawWidget = true;
412  qwidgetPrivate->drawWidget(qwidget, qrgn, QPoint(), flags, 0);
413  qt_mac_clearDirtyOnWidgetInsideDrawWidget = false;
414 
415  if (!redirectionOffset.isNull())
417  if (engine)
418  engine->setSystemClip(QRegion());
419  qwidget->setAttribute(Qt::WA_WState_InPaintEvent, false);
420  if(!qwidget->testAttribute(Qt::WA_PaintOutsidePaintEvent) && qwidget->paintingActive())
421  qWarning("QWidget: It is dangerous to leave painters active on a"
422  " widget outside of the PaintEvent");
423  }
424  qwidgetprivate->hd = 0;
426 }
427 
428 - (BOOL)acceptsFirstMouse:(NSEvent *)theEvent
429 {
430  // Find the widget that should receive the event:
431  QPoint qlocal, qglobal;
432  QWidget *widgetToGetMouse = qt_mac_getTargetForMouseEvent(theEvent, QEvent::MouseButtonPress, qlocal, qglobal, qwidget, 0);
433  if (!widgetToGetMouse)
434  return NO;
435 
436  return !widgetToGetMouse->testAttribute(Qt::WA_MacNoClickThrough);
437 }
438 
439 - (NSView *)hitTest:(NSPoint)aPoint
440 {
441  if (!qwidget)
442  return [super hitTest:aPoint];
443 
444  if (qwidget->testAttribute(Qt::WA_TransparentForMouseEvents))
445  return nil; // You cannot hit a transparent for mouse event widget.
446  return [super hitTest:aPoint];
447 }
448 
449 - (void)updateTrackingAreas
450 {
451  if (!qwidget)
452  return;
453 
454  // [NSView addTrackingArea] is slow, so bail out early if we can:
455  if (NSIsEmptyRect([self visibleRect]))
456  return;
457 
459  if (NSArray *trackingArray = [self trackingAreas]) {
460  NSUInteger size = [trackingArray count];
461  for (NSUInteger i = 0; i < size; ++i) {
462  NSTrackingArea *t = [trackingArray objectAtIndex:i];
463  [self removeTrackingArea:t];
464  }
465  }
466 
467  // Ideally, we shouldn't have NSTrackingMouseMoved events included below, it should
468  // only be turned on if mouseTracking, hover is on or a tool tip is set.
469  // Unfortunately, Qt will send "tooltip" events on mouse moves, so we need to
470  // turn it on in ALL case. That means EVERY QCocoaView gets to pay the cost of
471  // mouse moves delivered to it (Apple recommends keeping it OFF because there
472  // is a performance hit). So it goes.
473  NSUInteger trackingOptions = NSTrackingMouseEnteredAndExited | NSTrackingActiveInActiveApp
474  | NSTrackingInVisibleRect | NSTrackingMouseMoved;
475  NSTrackingArea *ta = [[NSTrackingArea alloc] initWithRect:NSMakeRect(0, 0,
476  qwidget->width(),
477  qwidget->height())
478  options:trackingOptions
479  owner:self
480  userInfo:nil];
481  [self addTrackingArea:ta];
482  [ta release];
483 }
484 
485 - (void)mouseEntered:(NSEvent *)event
486 {
487  // Cocoa will not send a move event on mouseEnter. But since
488  // Qt expect this, we fake one now. See also mouseExited below
489  // for info about enter/leave event handling
490  NSEvent *nsmoveEvent = [NSEvent
491  mouseEventWithType:NSMouseMoved
492  location:[[self window] mouseLocationOutsideOfEventStream]
493  modifierFlags: [event modifierFlags]
494  timestamp: [event timestamp]
495  windowNumber: [event windowNumber]
496  context: [event context]
497  eventNumber: [event eventNumber]
498  clickCount: 0
499  pressure: 0];
500 
501  // Important: Cocoa sends us mouseEnter on all views under the mouse
502  // and not just the one on top. Therefore, to we cannot use qwidget
503  // as native widget for this case. Instead, we let qt_mac_handleMouseEvent
504  // resolve it (last argument set to 0):
505  qt_mac_handleMouseEvent(nsmoveEvent, QEvent::MouseMove, Qt::NoButton, 0, true);
506 }
507 
508 - (void)mouseExited:(NSEvent *)event
509 {
510  // Note: normal enter/leave handling is done from within mouseMove. This handler
511  // catches the case when the mouse moves out of the window (which mouseMove do not).
512  // Updating the mouse cursor follows the same logic as enter/leave. And we update
513  // neither if a grab exists (even if the grab points to this widget, it seems, ref X11)
514  Q_UNUSED(event);
515  if (self == [[self window] contentView] && !qt_button_down && !QWidget::mouseGrabber()) {
517  // If the mouse exits the content view, but qt_mac_getTargetForMouseEvent still
518  // reports a target, it means that either there is a grab involved, or the mouse
519  // hovered over another window in the application. In both cases, move events will
520  // cause qt_mac_handleMouseEvent to be called, which will handle enter/leave.
521  QPoint qlocal, qglobal;
522  QWidget *widgetUnderMouse = 0;
523  qt_mac_getTargetForMouseEvent(event, QEvent::Leave, qlocal, qglobal, qwidget, &widgetUnderMouse);
524 
525  if (widgetUnderMouse == 0) {
526  QApplicationPrivate::dispatchEnterLeave(0, qt_last_mouse_receiver);
527  qt_last_mouse_receiver = 0;
528  qt_last_native_mouse_receiver = 0;
529  }
530  }
531 }
532 
533 - (void)flagsChanged:(NSEvent *)theEvent
534 {
535  QWidget *widgetToGetKey = qt_mac_getTargetForKeyEvent(qwidget);
536  if (!widgetToGetKey)
537  return;
538 
539  qt_dispatchModifiersChanged(theEvent, widgetToGetKey);
540  [super flagsChanged:theEvent];
541 }
542 
543 - (void)mouseMoved:(NSEvent *)theEvent
544 {
545  // Important: this method will only be called when the view's window is _not_ inside
546  // QCocoaWindow/QCocoaPanel. Otherwise, [QCocoaWindow sendEvent] will handle the event
547  // before it ends up here. So, this method is added for supporting QMacNativeWidget.
548  // TODO: Cocoa send move events to all views under the mouse. So make sure we only
549  // handle the event for the widget on top when using QMacNativeWidget.
550  qt_mac_handleMouseEvent(theEvent, QEvent::MouseMove, Qt::NoButton, qwidget);
551 }
552 
553 - (void)mouseDown:(NSEvent *)theEvent
554 {
555  qt_mac_handleMouseEvent(theEvent, QEvent::MouseButtonPress, Qt::LeftButton, qwidget);
556  // Don't call super here. This prevents us from getting the mouseUp event,
557  // which we need to send even if the mouseDown event was not accepted.
558  // (this is standard Qt behavior.)
559 }
560 
561 - (void)mouseUp:(NSEvent *)theEvent
562 {
563  qt_mac_handleMouseEvent(theEvent, QEvent::MouseButtonRelease, Qt::LeftButton, qwidget);
564 }
565 
566 - (void)rightMouseDown:(NSEvent *)theEvent
567 {
568  qt_mac_handleMouseEvent(theEvent, QEvent::MouseButtonPress, Qt::RightButton, qwidget);
569 }
570 
571 - (void)rightMouseUp:(NSEvent *)theEvent
572 {
573  qt_mac_handleMouseEvent(theEvent, QEvent::MouseButtonRelease, Qt::RightButton, qwidget);
574 }
575 
576 - (void)otherMouseDown:(NSEvent *)theEvent
577 {
578  Qt::MouseButton mouseButton = cocoaButton2QtButton([theEvent buttonNumber]);
579  qt_mac_handleMouseEvent(theEvent, QEvent::MouseButtonPress, mouseButton, qwidget);
580 }
581 
582 - (void)otherMouseUp:(NSEvent *)theEvent
583 {
584  Qt::MouseButton mouseButton = cocoaButton2QtButton([theEvent buttonNumber]);
585  qt_mac_handleMouseEvent(theEvent, QEvent::MouseButtonRelease, mouseButton, qwidget);
586 }
587 
588 - (void)mouseDragged:(NSEvent *)theEvent
589 {
590  qt_mac_handleMouseEvent(theEvent, QEvent::MouseMove, Qt::NoButton, qwidget);
591 }
592 
593 - (void)rightMouseDragged:(NSEvent *)theEvent
594 {
595  qt_mac_handleMouseEvent(theEvent, QEvent::MouseMove, Qt::NoButton, qwidget);
596 }
597 
598 - (void)otherMouseDragged:(NSEvent *)theEvent
599 {
600  qt_mac_handleMouseEvent(theEvent, QEvent::MouseMove, Qt::NoButton, qwidget);
601 }
602 
603 - (void)scrollWheel:(NSEvent *)theEvent
604 {
605  // Give the Input Manager a chance to process the wheel event.
606  NSInputManager *currentIManager = [NSInputManager currentInputManager];
607  if (currentIManager && [currentIManager wantsToHandleMouseEvents]) {
608  [currentIManager handleMouseEvent:theEvent];
609  }
610 
611  Qt::MouseButtons buttons = QApplication::mouseButtons();
612  Qt::KeyboardModifiers keyMods = qt_cocoaModifiers2QtModifiers([theEvent modifierFlags]);
613 
614  // Find the widget that should receive the event:
615  QPoint qlocal, qglobal;
616  QWidget *widgetToGetMouse = qt_mac_getTargetForMouseEvent(theEvent, QEvent::Wheel, qlocal, qglobal, qwidget, 0);
617  if (!widgetToGetMouse)
618  return;
619 
620  int deltaX = 0;
621  int deltaY = 0;
622 
623  const EventRef carbonEvent = (EventRef)[theEvent eventRef];
624  const UInt32 carbonEventKind = carbonEvent ? ::GetEventKind(carbonEvent) : 0;
625  const bool scrollEvent = carbonEventKind == kEventMouseScroll;
626 
627  if (scrollEvent) {
628  // The mouse device containts pixel scroll wheel support (Mighty Mouse, Trackpad).
629  // Since deviceDelta is delivered as pixels rather than degrees, we need to
630  // convert from pixels to degrees in a sensible manner.
631  // It looks like 1/4 degrees per pixel behaves most native.
632  // (NB: Qt expects the unit for delta to be 8 per degree):
633  const int pixelsToDegrees = 2; // 8 * 1/4
635  // Mac OS 10.6
636  deltaX = [theEvent deviceDeltaX] * pixelsToDegrees;
637  deltaY = [theEvent deviceDeltaY] * pixelsToDegrees;
638  } else {
639  // Mac OS 10.7+
640  deltaX = [theEvent scrollingDeltaX] * pixelsToDegrees;
641  deltaY = [theEvent scrollingDeltaY] * pixelsToDegrees;
642  }
643  } else {
644  // carbonEventKind == kEventMouseWheelMoved
645  // Remove acceleration, and use either -120 or 120 as delta:
646  deltaX = qBound(-120, int([theEvent deltaX] * 10000), 120);
647  deltaY = qBound(-120, int([theEvent deltaY] * 10000), 120);
648  }
649 
650 #ifndef QT_NO_WHEELEVENT
651  // ### Qt 5: Send one QWheelEvent with dx, dy and dz
652 
653  if (deltaX != 0 && deltaY != 0)
655 
656  if (deltaX != 0) {
657  QWheelEvent qwe(qlocal, qglobal, deltaX, buttons, keyMods, Qt::Horizontal);
658  qt_sendSpontaneousEvent(widgetToGetMouse, &qwe);
659  }
660 
661  if (deltaY != 0) {
662  QWheelEvent qwe(qlocal, qglobal, deltaY, buttons, keyMods, Qt::Vertical);
663  qt_sendSpontaneousEvent(widgetToGetMouse, &qwe);
664  }
665 
666  if (deltaX != 0 && deltaY != 0)
668 #endif //QT_NO_WHEELEVENT
669 }
670 
671 - (void)tabletProximity:(NSEvent *)tabletEvent
672 {
673  qt_dispatchTabletProximityEvent(tabletEvent);
674 }
675 
676 - (void)tabletPoint:(NSEvent *)tabletEvent
677 {
678  if (!qt_mac_handleTabletEvent(self, tabletEvent))
679  [super tabletPoint:tabletEvent];
680 }
681 
682 - (void)magnifyWithEvent:(NSEvent *)event
683 {
684  QPoint qlocal, qglobal;
685  QWidget *widgetToGetGesture = 0;
686  qt_mac_getTargetForMouseEvent(event, QEvent::Gesture, qlocal, qglobal, qwidget, &widgetToGetGesture);
687  if (!widgetToGetGesture)
688  return;
689  if (!QApplicationPrivate::tryModalHelper(widgetToGetGesture, 0))
690  return;
691 
692 #ifndef QT_NO_GESTURES
693  QNativeGestureEvent qNGEvent;
695  NSPoint p = [[event window] convertBaseToScreen:[event locationInWindow]];
696  qNGEvent.position = flipPoint(p).toPoint();
697  qNGEvent.percentage = [event magnification];
698  qt_sendSpontaneousEvent(widgetToGetGesture, &qNGEvent);
699 #endif // QT_NO_GESTURES
700 }
701 
702 - (void)rotateWithEvent:(NSEvent *)event
703 {
704  QPoint qlocal, qglobal;
705  QWidget *widgetToGetGesture = 0;
706  qt_mac_getTargetForMouseEvent(event, QEvent::Gesture, qlocal, qglobal, qwidget, &widgetToGetGesture);
707  if (!widgetToGetGesture)
708  return;
709  if (!QApplicationPrivate::tryModalHelper(widgetToGetGesture, 0))
710  return;
711 
712 #ifndef QT_NO_GESTURES
713  QNativeGestureEvent qNGEvent;
715  NSPoint p = [[event window] convertBaseToScreen:[event locationInWindow]];
716  qNGEvent.position = flipPoint(p).toPoint();
717  qNGEvent.percentage = -[event rotation];
718  qt_sendSpontaneousEvent(widgetToGetGesture, &qNGEvent);
719 #endif // QT_NO_GESTURES
720 }
721 
722 - (void)swipeWithEvent:(NSEvent *)event
723 {
724  QPoint qlocal, qglobal;
725  QWidget *widgetToGetGesture = 0;
726  qt_mac_getTargetForMouseEvent(event, QEvent::Gesture, qlocal, qglobal, qwidget, &widgetToGetGesture);
727  if (!widgetToGetGesture)
728  return;
729  if (!QApplicationPrivate::tryModalHelper(widgetToGetGesture, 0))
730  return;
731 
732 #ifndef QT_NO_GESTURES
733  QNativeGestureEvent qNGEvent;
735  NSPoint p = [[event window] convertBaseToScreen:[event locationInWindow]];
736  qNGEvent.position = flipPoint(p).toPoint();
737  if ([event deltaX] == 1)
738  qNGEvent.angle = 180.0f;
739  else if ([event deltaX] == -1)
740  qNGEvent.angle = 0.0f;
741  else if ([event deltaY] == 1)
742  qNGEvent.angle = 90.0f;
743  else if ([event deltaY] == -1)
744  qNGEvent.angle = 270.0f;
745  qt_sendSpontaneousEvent(widgetToGetGesture, &qNGEvent);
746 #endif // QT_NO_GESTURES
747 }
748 
749 - (void)beginGestureWithEvent:(NSEvent *)event
750 {
751  QPoint qlocal, qglobal;
752  QWidget *widgetToGetGesture = 0;
753  qt_mac_getTargetForMouseEvent(event, QEvent::Gesture, qlocal, qglobal, qwidget, &widgetToGetGesture);
754  if (!widgetToGetGesture)
755  return;
756  if (!QApplicationPrivate::tryModalHelper(widgetToGetGesture, 0))
757  return;
758 
759 #ifndef QT_NO_GESTURES
760  QNativeGestureEvent qNGEvent;
762  NSPoint p = [[event window] convertBaseToScreen:[event locationInWindow]];
763  qNGEvent.position = flipPoint(p).toPoint();
764  qt_sendSpontaneousEvent(widgetToGetGesture, &qNGEvent);
765 #endif // QT_NO_GESTURES
766 }
767 
768 - (void)endGestureWithEvent:(NSEvent *)event
769 {
770  QPoint qlocal, qglobal;
771  QWidget *widgetToGetGesture = 0;
772  qt_mac_getTargetForMouseEvent(event, QEvent::Gesture, qlocal, qglobal, qwidget, &widgetToGetGesture);
773  if (!widgetToGetGesture)
774  return;
775  if (!QApplicationPrivate::tryModalHelper(widgetToGetGesture, 0))
776  return;
777 
778 #ifndef QT_NO_GESTURES
779  QNativeGestureEvent qNGEvent;
781  NSPoint p = [[event window] convertBaseToScreen:[event locationInWindow]];
782  qNGEvent.position = flipPoint(p).toPoint();
783  qt_sendSpontaneousEvent(widgetToGetGesture, &qNGEvent);
784 }
785 #endif // QT_NO_GESTURES
786 
787 - (void)frameDidChange:(NSNotification *)note
788 {
789  Q_UNUSED(note);
790  if (!qwidget)
791  return;
792  if (qwidget->isWindow())
793  return;
794  NSRect newFrame = [self frame];
795  QRect newGeo(newFrame.origin.x, newFrame.origin.y, newFrame.size.width, newFrame.size.height);
796  bool moved = qwidget->testAttribute(Qt::WA_Moved);
797  bool resized = qwidget->testAttribute(Qt::WA_Resized);
798  qwidget->setGeometry(newGeo);
799  qwidget->setAttribute(Qt::WA_Moved, moved);
800  qwidget->setAttribute(Qt::WA_Resized, resized);
801  qwidgetprivate->syncCocoaMask();
802 }
803 
804 - (BOOL)isEnabled
805 {
806  if (!qwidget)
807  return [super isEnabled];
808  return [super isEnabled] && qwidget->isEnabled();
809 }
810 
811 - (void)setEnabled:(BOOL)flag
812 {
814  [super setEnabled:flag];
815  if (qwidget && qwidget->isEnabled() != flag)
816  qwidget->setEnabled(flag);
817 }
818 
819 + (Class)cellClass
820 {
821  return [NSActionCell class];
822 }
823 
824 - (BOOL)acceptsFirstResponder
825 {
826  if (!qwidget)
827  return NO;
828 
829  // Disabled widget shouldn't get focus even if it's a window.
830  // hence disabled windows will not get any key or mouse events.
831  if (!qwidget->isEnabled())
832  return NO;
833 
834  if (qwidget->isWindow() && !qt_widget_private(qwidget)->topData()->embedded) {
835  QWidget *focusWidget = qApp->focusWidget();
836  if (!focusWidget) {
837  // There is no focus widget, but we still want to receive key events
838  // for shortcut handling etc. So we accept first responer for the
839  // content view as a last resort:
840  return YES;
841  }
842  if (!focusWidget->internalWinId() && focusWidget->nativeParentWidget() == qwidget) {
843  // The current focus widget is alien, and hence, cannot get acceptsFirstResponder
844  // calls. Since the focus widget is a child of qwidget, we let this view say YES:
845  return YES;
846  }
847  if (focusWidget->window() != qwidget) {
848  // The current focus widget is in another window. Since cocoa
849  // suggest that this window should be key now, we accept:
850  return YES;
851  }
852  }
853 
854  return qwidget->focusPolicy() != Qt::NoFocus;
855 }
856 
857 - (BOOL)resignFirstResponder
858 {
859  if (!qwidget)
860  return YES;
861 
862  // Seems like the following test only triggers if this
863  // view is inside a QMacNativeWidget:
864 // if (QWidget *fw = QApplication::focusWidget()) {
865 // if (qwidget == fw || qwidget == fw->nativeParentWidget())
866 // fw->clearFocus();
867 // }
868  return YES;
869 }
870 
871 - (BOOL)becomeFirstResponder
872 {
873  // see the comment in the acceptsFirstResponder - if the window "stole" focus
874  // let it become the responder, but don't tell Qt
875  if (qwidget && qt_widget_private(qwidget->window())->topData()->embedded
876  && !QApplication::focusWidget() && qwidget->focusPolicy() != Qt::NoFocus)
877  qwidget->setFocus(Qt::OtherFocusReason);
878  return YES;
879 }
880 
881 - (NSDragOperation)draggingSourceOperationMaskForLocal:(BOOL)isLocal
882 {
883  Q_UNUSED(isLocal);
884  return supportedActions;
885 }
886 
887 - (void)setSupportedActions:(NSDragOperation)actions
888 {
889  supportedActions = actions;
890 }
891 
892 - (void)draggedImage:(NSImage *)anImage endedAt:(NSPoint)aPoint operation:(NSDragOperation)operation
893 {
894  Q_UNUSED(anImage);
895  Q_UNUSED(aPoint);
896  macCurrentDnDParameters()->performedAction = operation;
897  if (QDragManager::self()->object
898  && QDragManager::self()->dragPrivate()->executed_action != Qt::ActionMask) {
899  macCurrentDnDParameters()->performedAction =
900  qt_mac_mapDropAction(QDragManager::self()->dragPrivate()->executed_action);
901  }
902 }
903 
904 - (QWidget *)qt_qwidget
905 {
906  return qwidget;
907 }
908 
909 - (void) qt_clearQWidget
910 {
911  qwidget = 0;
912  qwidgetprivate = 0;
913 }
914 
915 - (void)keyDown:(NSEvent *)theEvent
916 {
917  if (!qwidget)
918  return;
919  QWidget *widgetToGetKey = qt_mac_getTargetForKeyEvent(qwidget);
920  if (!widgetToGetKey)
921  return;
922 
923  sendKeyEvents = true;
924 
925  if (widgetToGetKey->testAttribute(Qt::WA_InputMethodEnabled)
926  && !(widgetToGetKey->inputMethodHints() & Qt::ImhDigitsOnly
927  || widgetToGetKey->inputMethodHints() & Qt::ImhFormattedNumbersOnly
928  || widgetToGetKey->inputMethodHints() & Qt::ImhHiddenText)) {
929  fromKeyDownEvent = true;
930  [qt_mac_nativeview_for(qwidget) interpretKeyEvents:[NSArray arrayWithObject: theEvent]];
931  fromKeyDownEvent = false;
932  }
933 
934  if (sendKeyEvents && !composing) {
935  bool keyEventEaten = qt_dispatchKeyEvent(theEvent, widgetToGetKey);
936  if (!keyEventEaten && qwidget) {
937  // The event is not yet eaten, and if Qt is embedded inside a native
938  // cocoa application, send it to first responder not owned by Qt.
939  // The exception is if widgetToGetKey was redirected to a popup.
940  QWidget *toplevel = qwidget->window();
941  if (toplevel == widgetToGetKey->window()) {
942  if (qt_widget_private(toplevel)->topData()->embedded) {
943  if (NSResponder *w = [qt_mac_nativeview_for(toplevel) superview])
944  [w keyDown:theEvent];
945  }
946  }
947  }
948  }
949 }
950 
951 
952 - (void)keyUp:(NSEvent *)theEvent
953 {
954  if (sendKeyEvents) {
955  QWidget *widgetToGetKey = qt_mac_getTargetForKeyEvent(qwidget);
956  if (!widgetToGetKey)
957  return;
958 
959  bool keyEventEaten = qt_dispatchKeyEvent(theEvent, widgetToGetKey);
960  if (!keyEventEaten && qwidget) {
961  // The event is not yet eaten, and if Qt is embedded inside a native
962  // cocoa application, send it to first responder not owned by Qt.
963  // The exception is if widgetToGetKey was redirected to a popup.
964  QWidget *toplevel = qwidget->window();
965  if (toplevel == widgetToGetKey->window()) {
966  if (qt_widget_private(toplevel)->topData()->embedded) {
967  if (NSResponder *w = [qt_mac_nativeview_for(toplevel) superview])
968  [w keyUp:theEvent];
969  }
970  }
971  }
972  }
973 }
974 
975 - (void)viewWillMoveToWindow:(NSWindow *)window
976 {
977  if (qwidget == 0)
978  return;
979 
980  if (qwidget->windowFlags() & Qt::MSWindowsOwnDC
981  && (window != [self window])) { // OpenGL Widget
983  qApp->sendEvent(qwidget, &event);
984  }
985 }
986 
987 - (void)viewDidMoveToWindow
988 {
989  if (qwidget == 0)
990  return;
991 
992  if (qwidget->windowFlags() & Qt::MSWindowsOwnDC && [self window]) {
993  // call update paint event
994  qwidgetprivate->needWindowChange = true;
996  qApp->sendEvent(qwidget, &event);
997  }
998 }
999 
1000 
1001 // NSTextInput Protocol implementation
1002 
1003 - (void) insertText:(id)aString
1004 {
1005  QString commitText;
1006  if ([aString length]) {
1007  if ([aString isKindOfClass:[NSAttributedString class]]) {
1008  commitText = QCFString::toQString(reinterpret_cast<CFStringRef>([aString string]));
1009  } else {
1010  commitText = QCFString::toQString(reinterpret_cast<CFStringRef>(aString));
1011  };
1012  }
1013 
1014  // When entering characters through Character Viewer or Keyboard Viewer, the text is passed
1015  // through this insertText method. Since we dont receive a keyDown Event in such cases, the
1016  // composing flag will be false.
1017  //
1018  // Characters can be sent through input method directly without composing process as well,
1019  // for instance a Chinese input method will send "," (U+FF0C) to insertText: when "," key
1020  // is pressed. In that case we want to set commit string directly instead of going through
1021  // key events handling again. Hence we only leave the string with Unicode value less than
1022  // 256 to the key events handling process.
1023  if (([aString length] && (composing || commitText.at(0).unicode() > 0xff)) || !fromKeyDownEvent) {
1024  // Send the commit string to the widget.
1026  e.setCommitString(commitText);
1027  QWidget *widgetToGetKey = 0;
1028  if (!composing || qApp->focusWidget())
1029  widgetToGetKey = qt_mac_getTargetForKeyEvent(qwidget);
1030 #ifndef QT_NO_IM
1031  else if (QMacInputContext *mic = qobject_cast<QMacInputContext *>(qApp->inputContext()))
1032  widgetToGetKey = mic->lastFocusWidget();
1033 #endif
1034  if (widgetToGetKey)
1035  qt_sendSpontaneousEvent(widgetToGetKey, &e);
1036  composing = false;
1037  sendKeyEvents = false;
1038  } else {
1039  // The key sequence "`q" on a French Keyboard will generate two calls to insertText before
1040  // it returns from interpretKeyEvents. The first call will turn off 'composing' and accept
1041  // the "`" key. The last keyDown event needs to be processed by the widget to get the
1042  // character "q". The string parameter is ignored for the second call.
1043  sendKeyEvents = true;
1044  }
1045 
1046  composingText->clear();
1047 }
1048 
1049 - (void) setMarkedText:(id)aString selectedRange:(NSRange)selRange
1050 {
1051  // Generate the QInputMethodEvent with preedit string and the attributes
1052  // for rendering it. The attributes handled here are 'underline',
1053  // 'underline color' and 'cursor position'.
1054  sendKeyEvents = false;
1055  composing = true;
1056  QString qtText;
1057  // Cursor position is retrived from the range.
1059  attrs<<QInputMethodEvent::Attribute(QInputMethodEvent::Cursor, selRange.location + selRange.length, 1, QVariant());
1060  if ([aString isKindOfClass:[NSAttributedString class]]) {
1061  qtText = QCFString::toQString(reinterpret_cast<CFStringRef>([aString string]));
1062  composingLength = qtText.length();
1063  int index = 0;
1064  // Create attributes for individual sections of preedit text
1065  while (index < composingLength) {
1066  NSRange effectiveRange;
1067  NSRange range = NSMakeRange(index, composingLength-index);
1068  NSDictionary *attributes = [aString attributesAtIndex:index
1069  longestEffectiveRange:&effectiveRange
1070  inRange:range];
1071  NSNumber *underlineStyle = [attributes objectForKey:NSUnderlineStyleAttributeName];
1072  if (underlineStyle) {
1073  QColor clr (Qt::black);
1074  NSColor *color = [attributes objectForKey:NSUnderlineColorAttributeName];
1075  if (color) {
1076  clr = colorFrom(color);
1077  }
1079  format.setFontUnderline(true);
1080  format.setUnderlineColor(clr);
1082  effectiveRange.location,
1083  effectiveRange.length,
1084  format);
1085  }
1086  index = effectiveRange.location + effectiveRange.length;
1087  }
1088  } else {
1089  // No attributes specified, take only the preedit text.
1090  qtText = QCFString::toQString(reinterpret_cast<CFStringRef>(aString));
1091  composingLength = qtText.length();
1092  }
1093  // Make sure that we have at least one text format.
1094  if (attrs.size() <= 1) {
1096  format.setFontUnderline(true);
1098  0, composingLength, format);
1099  }
1100  *composingText = qtText;
1101 
1102  QInputMethodEvent e(qtText, attrs);
1103  if (QWidget *widgetToGetKey = qt_mac_getTargetForKeyEvent(qwidget))
1104  qt_sendSpontaneousEvent(widgetToGetKey, &e);
1105 
1106  if (!composingLength)
1107  composing = false;
1108 }
1109 
1110 - (void) unmarkText
1111 {
1112  if (composing) {
1114  e.setCommitString(*composingText);
1115  if (QWidget *widgetToGetKey = qt_mac_getTargetForKeyEvent(qwidget))
1116  qt_sendSpontaneousEvent(widgetToGetKey, &e);
1117  }
1118  composingText->clear();
1119  composing = false;
1120 }
1121 
1122 - (BOOL) hasMarkedText
1123 {
1124  return (composing ? YES: NO);
1125 }
1126 
1127 - (void) doCommandBySelector:(SEL)aSelector
1128 {
1129  Q_UNUSED(aSelector);
1130 }
1131 
1132 - (BOOL)isComposing
1133 {
1134  return composing;
1135 }
1136 
1137 - (NSInteger) conversationIdentifier
1138 {
1139  // Return a unique identifier fot this ime conversation
1140  return (NSInteger)self;
1141 }
1142 
1143 - (NSAttributedString *) attributedSubstringFromRange:(NSRange)theRange
1144 {
1145  QString selectedText(qwidget->inputMethodQuery(Qt::ImCurrentSelection).toString());
1146  if (!selectedText.isEmpty()) {
1147  QCFString string(selectedText.mid(theRange.location, theRange.length));
1148  const NSString *tmpString = reinterpret_cast<const NSString *>((CFStringRef)string);
1149  return [[[NSAttributedString alloc] initWithString:const_cast<NSString *>(tmpString)] autorelease];
1150  } else {
1151  return nil;
1152  }
1153 }
1154 
1155 - (NSRange) markedRange
1156 {
1157  NSRange range;
1158  if (composing) {
1159  range.location = 0;
1160  range.length = composingLength;
1161  } else {
1162  range.location = NSNotFound;
1163  range.length = 0;
1164  }
1165  return range;
1166 }
1167 
1168 - (NSRange) selectedRange
1169 {
1170  NSRange selRange;
1171  QString selectedText(qwidget->inputMethodQuery(Qt::ImCurrentSelection).toString());
1172  if (!selectedText.isEmpty()) {
1173  // Consider only the selected text.
1174  selRange.location = 0;
1175  selRange.length = selectedText.length();
1176  } else {
1177  // No selected text.
1178  selRange.location = NSNotFound;
1179  selRange.length = 0;
1180  }
1181  return selRange;
1182 
1183 }
1184 
1185 - (NSRect) firstRectForCharacterRange:(NSRange)theRange
1186 {
1187  Q_UNUSED(theRange);
1188  // The returned rect is always based on the internal cursor.
1189  QWidget *widgetToGetKey = qt_mac_getTargetForKeyEvent(qwidget);
1190  if (!widgetToGetKey)
1191  return NSZeroRect;
1192 
1193  QRect mr(widgetToGetKey->inputMethodQuery(Qt::ImMicroFocus).toRect());
1194  QPoint mp(widgetToGetKey->mapToGlobal(QPoint(mr.bottomLeft())));
1195  NSRect rect ;
1196  rect.origin.x = mp.x();
1197  rect.origin.y = flipYCoordinate(mp.y());
1198  rect.size.width = mr.width();
1199  rect.size.height = mr.height();
1200  return rect;
1201 }
1202 
1203 - (NSUInteger)characterIndexForPoint:(NSPoint)thePoint
1204 {
1205  // We dont support cursor movements using mouse while composing.
1206  Q_UNUSED(thePoint);
1207  return NSNotFound;
1208 }
1209 
1210 - (NSArray*) validAttributesForMarkedText
1211 {
1212  QWidget *widgetToGetKey = qt_mac_getTargetForKeyEvent(qwidget);
1213  if (!widgetToGetKey)
1214  return nil;
1215 
1216  if (!widgetToGetKey->testAttribute(Qt::WA_InputMethodEnabled))
1217  return nil; // Not sure if that's correct, but it's saves a malloc.
1218 
1219  // Support only underline color/style.
1220  return [NSArray arrayWithObjects:NSUnderlineColorAttributeName,
1221  NSUnderlineStyleAttributeName, nil];
1222 }
1223 @end
1224 
1226 #ifndef QT_NO_IM
1228 {
1230  if (w) {
1231  NSView *view = qt_mac_effectiveview_for(w);
1232  if ([view isKindOfClass:[QT_MANGLE_NAMESPACE(QCocoaView) class]]) {
1234  QT_MANGLE_NAMESPACE(QCocoaView) *qc = static_cast<QT_MANGLE_NAMESPACE(QCocoaView) *>(view);
1235  NSInputManager *currentIManager = [NSInputManager currentInputManager];
1236  if (currentIManager) {
1237  [currentIManager markedTextAbandoned:view];
1238  [qc unmarkText];
1239  }
1240  }
1241  }
1242 }
1243 
1244 bool QMacInputContext::isComposing() const
1245 {
1247  if (w) {
1248  NSView *view = qt_mac_effectiveview_for(w);
1249  if ([view isKindOfClass:[QT_MANGLE_NAMESPACE(QCocoaView) class]]) {
1250  return [static_cast<QT_MANGLE_NAMESPACE(QCocoaView) *>(view) isComposing];
1251  }
1252  }
1253  return false;
1254 }
1255 #endif // QT_NO_IM
1256 
1257 extern bool qt_mac_in_drag;
1258 void * /*NSImage */qt_mac_create_nsimage(const QPixmap &pm);
1259 static const int default_pm_hotx = -2;
1260 static const int default_pm_hoty = -16;
1261 static const char* default_pm[] = {
1262  "13 9 3 1",
1263  ". c None",
1264  " c #000000",
1265  "X c #FFFFFF",
1266  "X X X X X X X",
1267  " X X X X X X ",
1268  "X ......... X",
1269  " X.........X ",
1270  "X ......... X",
1271  " X.........X ",
1272  "X ......... X",
1273  " X X X X X X ",
1274  "X X X X X X X",
1275 };
1276 
1278 {
1279  if(qt_mac_in_drag) { //just make sure..
1280  qWarning("Qt: Internal error: WH0A, unexpected condition reached");
1281  return Qt::IgnoreAction;
1282  }
1283  if(object == o)
1284  return Qt::IgnoreAction;
1285  /* At the moment it seems clear that Mac OS X does not want to drag with a non-left button
1286  so we just bail early to prevent it */
1287  if (!(GetCurrentEventButtonState() & kEventMouseButtonPrimary)) {
1288  o->setMimeData(0);
1289  o->deleteLater();
1290  return Qt::IgnoreAction;
1291  }
1292 
1293  if(object) {
1294  dragPrivate()->source->removeEventFilter(this);
1295  cancel();
1296  beingCancelled = false;
1297  }
1298 
1299  object = o;
1300  dragPrivate()->target = 0;
1301 
1302 #ifndef QT_NO_ACCESSIBILITY
1304 #endif
1305 
1306  // setup the data
1307  QMacPasteboard dragBoard((CFStringRef) NSDragPboard, QMacPasteboardMime::MIME_DND);
1308  dragPrivate()->data->setData(QLatin1String("application/x-qt-mime-type-name"), QByteArray("dummy"));
1309  dragBoard.setMimeData(dragPrivate()->data);
1310 
1311  // create the image
1312  QPoint hotspot;
1313  QPixmap pix = dragPrivate()->pixmap;
1314  if(pix.isNull()) {
1315  if(dragPrivate()->data->hasText() || dragPrivate()->data->hasUrls()) {
1316  // get the string
1317  QString s = dragPrivate()->data->hasText() ? dragPrivate()->data->text()
1318  : dragPrivate()->data->urls().first().toString();
1319  if(s.length() > 26)
1320  s = s.left(23) + QChar(0x2026);
1321  if(!s.isEmpty()) {
1322  // draw it
1323  QFont f(qApp->font());
1324  f.setPointSize(12);
1325  QFontMetrics fm(f);
1326  QPixmap tmp(fm.width(s), fm.height());
1327  if(!tmp.isNull()) {
1328  QPainter p(&tmp);
1329  p.fillRect(0, 0, tmp.width(), tmp.height(), Qt::color0);
1330  p.setPen(Qt::color1);
1331  p.setFont(f);
1332  p.drawText(0, fm.ascent(), s);
1333  // save it
1334  pix = tmp;
1335  hotspot = QPoint(tmp.width() / 2, tmp.height() / 2);
1336  }
1337  }
1338  } else {
1339  pix = QPixmap(default_pm);
1340  hotspot = QPoint(default_pm_hotx, default_pm_hoty);
1341  }
1342  } else {
1343  hotspot = dragPrivate()->hotspot;
1344  }
1345 
1346  // Convert the image to NSImage:
1347  NSImage *image = (NSImage *)qt_mac_create_nsimage(pix);
1348 
1349  DnDParams *dndParams = macCurrentDnDParameters();
1350  QT_MANGLE_NAMESPACE(QCocoaView) *theView = static_cast<QT_MANGLE_NAMESPACE(QCocoaView) *>(dndParams->view);
1351 
1352  // Save supported actions:
1353  [theView setSupportedActions: qt_mac_mapDropActions(dragPrivate()->possible_actions)];
1354  QPoint pointInView = [theView qt_qwidget]->mapFromGlobal(dndParams->globalPoint);
1355  NSPoint imageLoc = {pointInView.x() - hotspot.x(), pointInView.y() + pix.height() - hotspot.y()};
1356  NSSize mouseOffset = {0.0, 0.0};
1357  NSPasteboard *pboard = [NSPasteboard pasteboardWithName:NSDragPboard];
1358  dragPrivate()->executed_action = Qt::ActionMask;
1359 
1360  // Execute the drag:
1361  [theView retain];
1362  [theView dragImage:image
1363  at:imageLoc
1364  offset:mouseOffset
1365  event:dndParams->theEvent
1366  pasteboard:pboard
1367  source:theView
1368  slideBack:YES];
1369 
1370  // Reset the implicit grab widget when drag ends because we will not
1371  // receive the mouse release event when DND is active:
1372  qt_button_down = 0;
1373  [theView release];
1374  [image release];
1375  if (dragPrivate())
1376  dragPrivate()->executed_action = Qt::IgnoreAction;
1377  object = 0;
1378  Qt::DropAction performedAction(qt_mac_mapNSDragOperation(dndParams->performedAction));
1379 
1380  // Do post drag processing, if required.
1381  if (performedAction != Qt::IgnoreAction) {
1382  // Check if the receiver points us to a file location.
1383  // if so, we need to do the file copy/move ourselves.
1384  QCFType<CFURLRef> pasteLocation = 0;
1385  PasteboardCopyPasteLocation(dragBoard.pasteBoard(), &pasteLocation);
1386  if (pasteLocation) {
1387  QList<QUrl> urls = o->mimeData()->urls();
1388  for (int i = 0; i < urls.size(); ++i) {
1389  QUrl fromUrl = urls.at(i);
1390  QString filename = QFileInfo(fromUrl.path()).fileName();
1391  QUrl toUrl(QCFString::toQString(CFURLGetString(pasteLocation)) + filename);
1392  if (performedAction == Qt::MoveAction)
1393  QFile::rename(fromUrl.path(), toUrl.path());
1394  else if (performedAction == Qt::CopyAction)
1395  QFile::copy(fromUrl.path(), toUrl.path());
1396  }
1397  }
1398  }
1399 
1400  // Clean-up:
1401  o->setMimeData(0);
1402  o->deleteLater();
1403  return performedAction;
1404 }
1405 
1407 
1408 #endif // QT_MAC_USE_COCOA
The QVariant class acts like a union for the most common Qt data types.
Definition: qvariant.h:92
T qobject_cast(QObject *object)
Definition: qobject.h:375
The QPainter class performs low-level painting on widgets and other paint devices.
Definition: qpainter.h:86
virtual bool isComposing() const
This function indicates whether InputMethodStart event had been sent to the current focus widget...
The QColor class provides colors based on RGB, HSV or CMYK values.
Definition: qcolor.h:67
void setPointSize(int)
Sets the point size to pointSize.
Definition: qfont.cpp:1099
const struct __CFString * CFStringRef
static void updateAccessibility(QObject *, int who, Event reason)
Notifies accessibility clients about a change in object&#39;s accessibility information.
The QApplication class manages the GUI application&#39;s control flow and main settings.
Definition: qapplication.h:99
bool rename(const QString &newName)
Renames the file currently specified by fileName() to newName.
Definition: qfile.cpp:766
The QTextCharFormat class provides formatting information for characters in a QTextDocument.
Definition: qtextformat.h:372
The QCursor class provides a mouse cursor with an arbitrary shape.
Definition: qcursor.h:89
The QFontMetrics class provides font metrics information.
Definition: qfontmetrics.h:65
#define QT_END_NAMESPACE
This macro expands to.
Definition: qglobal.h:90
The QDrag class provides support for MIME-based drag and drop data transfer.
Definition: qdrag.h:61
void qt_mac_release_graphics_context(CGContextRef context)
EventRef event
void setMimeData(QMimeData *data)
Sets the data to be sent to the given MIME data.
Definition: qdrag.cpp:142
QPointer< QWidget > widget
The QInputMethodEvent::Attribute class stores an input method attribute.
Definition: qevent.h:441
const QChar at(int i) const
Returns the character at the given index position in the string.
Definition: qstring.h:698
ushort unicode() const
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition: qchar.h:251
int flipYCoordinate(int y)
void qt_dispatchTabletProximityEvent(const ::TabletProximityRec &proxRec)
The QWheelEvent class contains parameters that describe a wheel event.
Definition: qevent.h:139
The QByteArray class provides an array of bytes.
Definition: qbytearray.h:135
The QHoverEvent class contains parameters that describe a mouse event.
Definition: qevent.h:125
int length() const
Returns the number of characters in this string.
Definition: qstring.h:696
void setRgbF(qreal r, qreal g, qreal b, qreal a=1.0)
Sets the color channels of this color to r (red), g (green), b (blue) and a (alpha, transparency).
Definition: qcolor.cpp:954
static const int default_pm_hotx
Definition: qdnd_mac.mm:95
static Qt::MouseButtons buttons
Qt::FocusPolicy focusPolicy
the way the widget accepts keyboard focus
Definition: qwidget.h:187
The QWidget class is the base class of all user interface objects.
Definition: qwidget.h:150
static QString toQString(CFStringRef cfstr)
Definition: qcore_mac.cpp:47
void setCommitString(const QString &commitString, int replaceFrom=0, int replaceLength=0)
Sets the commit string to commitString.
Definition: qevent.cpp:2042
int width() const
Returns the width of the rectangle.
Definition: qrect.h:303
OSViewRef qt_mac_effectiveview_for(const QWidget *w)
Definition: qwidget_mac.mm:424
QLatin1String(DBUS_INTERFACE_DBUS))) Q_GLOBAL_STATIC_WITH_ARGS(QString
void * qt_mac_create_nsimage(const QPixmap &pm)
The QAbstractScrollArea widget provides a scrolling area with on-demand scroll bars.
void qt_mac_update_cursor()
Definition: qcursor_mac.mm:201
static const char *const default_pm[]
Definition: qdnd_mac.mm:98
virtual QVariant inputMethodQuery(Qt::InputMethodQuery) const
This method is only relevant for input widgets.
Definition: qwidget.cpp:9683
QPointF flipPoint(const NSPoint &p)
int height() const
Returns the height of the rectangle.
Definition: qrect.h:306
QWidget * focusWidget() const
Returns the widget that has an input focus for this input context.
The QUrl class provides a convenient interface for working with URLs.
Definition: qurl.h:61
The QString class provides a Unicode character string.
Definition: qstring.h:83
The QDragMoveEvent class provides an event which is sent while a drag and drop action is in progress...
Definition: qevent.h:530
static const int default_pm_hoty
Definition: qdnd_mac.mm:96
The QObject class is the base class of all Qt objects.
Definition: qobject.h:111
QPointer< QWidget > qt_last_mouse_receiver
The QChar class provides a 16-bit Unicode character.
Definition: qchar.h:72
QChar * data()
Returns a pointer to the data stored in the QString.
Definition: qstring.h:710
bool qt_mac_in_drag
Definition: qdnd_mac.mm:78
Qt::KeyboardModifiers qt_cocoaModifiers2QtModifiers(ulong modifierFlags)
uint embedded
Definition: qwidget_p.h:190
QString path() const
Returns the path of the URL.
Definition: qurl.cpp:4977
Qt::DropAction drag(QDrag *)
Definition: qdnd_mac.mm:530
virtual void reset()
This function can be reimplemented in a subclass to reset the state of the input method.
Q_CORE_EXPORT void qDebug(const char *,...)
#define QT_FORWARD_DECLARE_CLASS(name)
Definition: qglobal.h:95
NSWindow * window
void qt_dispatchModifiersChanged(void *flagsChangedEvent, QWidget *widgetToGetEvent)
#define QT_BEGIN_NAMESPACE
This macro expands to.
Definition: qglobal.h:89
QWidget * nativeParentWidget() const
Returns the native parent for this widget, i.
Definition: qwidget.cpp:4514
static void restoreRedirected(const QPaintDevice *device)
Using QWidget::render() obsoletes the use of this function.
Definition: qpainter.cpp:8344
QString left(int n) const Q_REQUIRED_RESULT
Returns a substring that contains the n leftmost characters of the string.
Definition: qstring.cpp:3664
static QWidget * mouseGrabber()
Returns the widget that is currently grabbing the mouse input.
bool testAttribute(Qt::WidgetAttribute) const
Returns true if attribute attribute is set on this widget; otherwise returns false.
Definition: qwidget.h:1041
QWidget * mac_mouse_grabber
Definition: qwidget_mac.mm:156
bool isEmpty() const
Returns true if the string has no characters; otherwise returns false.
Definition: qstring.h:704
bool isEmpty() const
Returns true if the region is empty; otherwise returns false.
Definition: qregion.cpp:4098
#define qApp
void drawWidget(QPaintDevice *pdev, const QRegion &rgn, const QPoint &offset, int flags, QPainter *sharedPainter=0, QWidgetBackingStore *backingStore=0)
Definition: qwidget.cpp:5679
const T & at(int i) const
Returns the item at index position i in the list.
Definition: qlist.h:468
void setCmykF(qreal c, qreal m, qreal y, qreal k, qreal a=1.0)
Sets the color to CMYK values, c (cyan), m (magenta), y (yellow), k (black), and a (alpha-channel...
Definition: qcolor.cpp:2276
The QStringList class provides a list of strings.
Definition: qstringlist.h:66
Q_CORE_EXPORT void qWarning(const char *,...)
static const char * data(const QByteArray &arr)
void setUnderlineColor(const QColor &color)
Sets the underline color used for the characters with this format to the color specified.
Definition: qtextformat.h:446
bool qt_mac_handleTabletEvent(void *view, void *tabletEvent)
The QRegion class specifies a clip region for a painter.
Definition: qregion.h:68
QList< QUrl > urls() const
Returns a list of URLs contained within the MIME data object.
Definition: qmimedata.cpp:310
DropAction
Definition: qnamespace.h:1597
bool qt_dispatchKeyEvent(void *keyEvent, QWidget *widgetToGetEvent)
QTLWExtra * topData() const
Definition: qwidget_p.h:1004
The QMimeData class provides a container for data that records information about its MIME type...
Definition: qmimedata.h:57
The QPaintEngine class provides an abstract definition of how QPainter draws to a given device on a g...
Definition: qpaintengine.h:90
void setSystemClip(const QRegion &baseClip)
Sets the system clip for this engine.
static QString graphics_system_name
struct OpaqueEventRef * EventRef
const T & at(int i) const
Returns the item at index position i in the vector.
Definition: qvector.h:350
static QDragManager * self()
Definition: qdnd.cpp:163
The QInputMethodEvent class provides parameters for input method events.
Definition: qevent.h:431
struct CGRect CGRect
static bool tryModalHelper(QWidget *widget, QWidget **rettop=0)
void qt_mac_draw_image(CGContextRef context, CGContextRef imageContext, CGRect area, CGRect drawingArea)
The QFont class specifies a font used for drawing text.
Definition: qfont.h:64
int y() const
Returns the y-coordinate of the rectangle&#39;s top edge.
Definition: qrect.h:255
QMimeData * mimeData() const
Returns the MIME data that is encapsulated by the drag object.
Definition: qdrag.cpp:155
QRect toRect() const
Returns the variant as a QRect if the variant has type() Rect ; otherwise returns an invalid QRect...
Definition: qvariant.cpp:2416
QPoint toPoint() const
Rounds the coordinates of this point to the nearest integer, and returns a QPoint object with the rou...
Definition: qpoint.h:376
#define QT_MANGLE_NAMESPACE(name)
Definition: qglobal.h:106
void setFontUnderline(bool underline)
If underline is true, sets the text format&#39;s font to be underlined; otherwise it is displayed non-und...
Definition: qtextformat.h:432
int x() const
Returns the x-coordinate of the rectangle&#39;s left edge.
Definition: qrect.h:252
QPointer< QWidget > qt_last_native_mouse_receiver
bool qt_sendSpontaneousEvent(QObject *, QEvent *)
struct CGPoint NSPoint
The QDragEnterEvent class provides an event which is sent to a widget when a drag and drop action ent...
Definition: qevent.h:555
The QPoint class defines a point in the plane using integer precision.
Definition: qpoint.h:53
Q_DECL_CONSTEXPR const T & qBound(const T &min, const T &val, const T &max)
Definition: qglobal.h:1219
int size() const
Returns the number of items in the list.
Definition: qlist.h:137
The QRect class defines a rectangle in the plane using integer precision.
Definition: qrect.h:58
OSViewRef qt_mac_nativeview_for(const QWidget *)
Definition: qwidget_mac.mm:419
WId internalWinId() const
Returns the window system identifier of the widget, or 0 if the widget is not created yet...
Definition: qwidget.h:244
static void dispatchEnterLeave(QWidget *enter, QWidget *leave)
bool copy(const QString &newName)
Copies the file currently specified by fileName() to a file called newName.
Definition: qfile.cpp:926
#define QT_USE_NAMESPACE
This macro expands to using QT_NAMESPACE if QT_NAMESPACE is defined and nothing otherwise.
Definition: qglobal.h:88
quint16 index
QWidget * qt_button_down
QWidget * window() const
Returns the window for this widget, i.e.
Definition: qwidget.cpp:4492
The QPixmap class is an off-screen image representation that can be used as a paint device...
Definition: qpixmap.h:71
static const MacVersion MacintoshVersion
the version of the Macintosh operating system on which the application is run (Mac only)...
Definition: qglobal.h:1646
void translate(int dx, int dy)
Translates (moves) the region dx along the X axis and dy along the Y axis.
Definition: qregion.cpp:4116
static Qt::MouseButtons mouseButtons()
Returns the current state of the buttons on the mouse.
int x() const
Returns the x coordinate of this point.
Definition: qpoint.h:128
Qt::MouseButton cocoaButton2QtButton(NSInteger buttonNum)
struct CGContext * CGContextRef
Q_GUI_EXPORT QWidgetPrivate * qt_widget_private(QWidget *widget)
Definition: qwidget.cpp:12920
HIViewRef OSViewRef
bool isNull() const
Returns true if this is a null pixmap; otherwise returns false.
Definition: qpixmap.cpp:615
static QGraphicsSystem * graphicsSystem()
Qt::InputMethodHints inputMethodHints
What input method specific hints the widget has.
Definition: qwidget.h:224
The QFileInfo class provides system-independent file information.
Definition: qfileinfo.h:60
The QPaintEvent class contains event parameters for paint events.
Definition: qevent.h:298
The QEvent class is the base class of all event classes.
Definition: qcoreevent.h:56
static QUrl toUrl(Register *reg, int type, QDeclarativeContextData *context, bool *ok=0)
static QWidget * focusWidget()
Returns the application widget that has the keyboard input focus, or 0 if no widget in this applicati...
#define Q_UNUSED(x)
Indicates to the compiler that the parameter with the specified name is not used in the body of a fun...
Definition: qglobal.h:1729
static QString fileName(const QString &fileUrl)
int size() const
Returns the number of items in the vector.
Definition: qvector.h:137
void deleteLater()
Schedules this object for deletion.
Definition: qobject.cpp:2145
QPoint mapToGlobal(const QPoint &) const
Translates the widget coordinate pos to global screen coordinates.
void qt_mac_retain_graphics_context(CGContextRef context)
qt_mac_getTargetForMouseEvent(event, QEvent::Gesture, qlocal, qglobal, 0, &widgetToGetTouch)
static int area(const QSize &s)
Definition: qicon.cpp:155
QWidget * target() const
Returns the target of the drag and drop operation.
Definition: qdrag.cpp:219
float CGFloat
QPoint topLeft() const
Returns the position of the rectangle&#39;s top-left corner.
Definition: qrect.h:288
MouseButton
Definition: qnamespace.h:150