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