Merge remote-tracking branch 'origin/4.7' into qt-4.8-from-4.7
[qt:qt.git] / src / gui / kernel / qcocoasharedwindowmethods_mac_p.h
1 /****************************************************************************
2 **
3 ** Copyright (C) 2011 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 /****************************************************************************
43  NB: This is not a header file, dispite the file name suffix. This file is
44  included directly into the source code of qcocoawindow_mac.mm and
45  qcocoapanel_mac.mm to avoid manually doing copy and paste of the exact
46  same code needed at both places. This solution makes it more difficult
47  to e.g fix a bug in qcocoawindow_mac.mm, but forget to do the same in
48  qcocoapanel_mac.mm.
49  The reason we need to do copy and paste in the first place, rather than
50  resolve to method overriding, is that QCocoaPanel needs to inherit from
51  NSPanel, while QCocoaWindow needs to inherit NSWindow rather than NSPanel).
52 ****************************************************************************/
53
54 // WARNING: Don't include any header files from within this file. Put them
55 // directly into qcocoawindow_mac_p.h and qcocoapanel_mac_p.h
56
57 QT_BEGIN_NAMESPACE
58 extern Qt::MouseButton cocoaButton2QtButton(NSInteger buttonNum); // qcocoaview.mm
59 extern QPointer<QWidget> qt_button_down; //qapplication_mac.cpp
60 extern const QStringList& qEnabledDraggedTypes(); // qmime_mac.cpp
61 extern void qt_event_request_window_change(QWidget *); // qapplication_mac.mm
62 extern void qt_mac_send_posted_gl_updates(QWidget *widget); // qapplication_mac.mm
63
64 Q_GLOBAL_STATIC(QPointer<QWidget>, currentDragTarget);
65 QT_END_NAMESPACE
66
67 - (id)initWithContentRect:(NSRect)contentRect
68     styleMask:(NSUInteger)windowStyle
69     backing:(NSBackingStoreType)bufferingType
70     defer:(BOOL)deferCreation
71 {
72     self = [super initWithContentRect:contentRect styleMask:windowStyle
73         backing:bufferingType defer:deferCreation];
74     if (self) {
75         currentCustomDragTypes = 0;
76     }
77     return self;
78 }
79
80 - (void)dealloc
81 {
82     delete currentCustomDragTypes;
83     [super dealloc];
84 }
85
86 - (BOOL)canBecomeKeyWindow
87 {
88     QWidget *widget = [self QT_MANGLE_NAMESPACE(qt_qwidget)];
89     if (!widget)
90         return NO; // This should happen only for qt_root_win
91     if (QApplicationPrivate::isBlockedByModal(widget))
92         return NO;
93
94     bool isToolTip = (widget->windowType() == Qt::ToolTip);
95     bool isPopup = (widget->windowType() == Qt::Popup);
96     return !(isPopup || isToolTip);
97 }
98
99 - (BOOL)canBecomeMainWindow
100 {
101     QWidget *widget = [self QT_MANGLE_NAMESPACE(qt_qwidget)];
102     if (!widget)
103         return NO; // This should happen only for qt_root_win
104     if ([self isSheet])
105         return NO;
106
107     bool isToolTip = (widget->windowType() == Qt::ToolTip);
108     bool isPopup = (widget->windowType() == Qt::Popup);
109     bool isTool = (widget->windowType() == Qt::Tool);
110     return !(isPopup || isToolTip || isTool);
111 }
112
113 - (void)becomeMainWindow
114 {
115     [super becomeMainWindow];
116     // Cocoa sometimes tell a hidden window to become the
117     // main window (and as such, show it). This can e.g
118     // happend when the application gets activated. If
119     // this is the case, we tell it to hide again:
120     if (![self isVisible])
121         [self orderOut:self];
122 }
123
124 - (void)toggleToolbarShown:(id)sender
125 {
126     macSendToolbarChangeEvent([self QT_MANGLE_NAMESPACE(qt_qwidget)]);
127     [super toggleToolbarShown:sender];
128 }
129
130 - (void)flagsChanged:(NSEvent *)theEvent
131 {
132     qt_dispatchModifiersChanged(theEvent, [self QT_MANGLE_NAMESPACE(qt_qwidget)]);
133     [super flagsChanged:theEvent];
134 }
135
136
137 - (void)tabletProximity:(NSEvent *)tabletEvent
138 {
139     qt_dispatchTabletProximityEvent(tabletEvent);
140 }
141
142 - (void)terminate:(id)sender
143 {
144     // This function is called from the quit item in the menubar when this window
145     // is in the first responder chain (see also qtDispatcherToQAction above)
146     [NSApp terminate:sender];
147 }
148
149 - (void)setLevel:(NSInteger)windowLevel
150 {
151     // Cocoa will upon activating/deactivating applications level modal
152     // windows up and down, regardsless of any explicit set window level.
153     // To ensure that modal stays-on-top dialogs actually stays on top after
154     // the application is activated (and therefore stacks in front of
155     // other stays-on-top windows), we need to add this little special-case override:
156     QWidget *widget = [[QT_MANGLE_NAMESPACE(QCocoaWindowDelegate) sharedDelegate] qt_qwidgetForWindow:self];
157     if (widget && widget->isModal() && (widget->windowFlags() & Qt::WindowStaysOnTopHint))
158         [super setLevel:NSPopUpMenuWindowLevel];
159     else
160         [super setLevel:windowLevel];
161 }
162
163 - (void)sendEvent:(NSEvent *)event
164 {
165     [self retain];
166
167     bool handled = false;
168     switch([event type]) {
169     case NSMouseMoved:
170         // Cocoa sends move events to a parent and all its children under the mouse, much
171         // like Qt handles hover events. But we only want to handle the move event once, so
172         // to optimize a bit (since we subscribe for move event for all views), we handle it
173         // here before this logic happends. Note: it might be tempting to do this shortcut for
174         // all mouse events. The problem is that Cocoa does more than just find the correct view
175         // when sending the event, like raising windows etc. So avoid it as much as possible:
176         handled = qt_mac_handleMouseEvent(event, QEvent::MouseMove, Qt::NoButton, 0);
177         break;
178     default:
179         break;
180     }
181
182     if (!handled) {
183         [super sendEvent:event];
184         qt_mac_handleNonClientAreaMouseEvent(self, event);
185     }
186     [self release];
187 }
188
189 - (void)setInitialFirstResponder:(NSView *)view
190 {
191     // This method is called the first time the window is placed on screen and
192     // is the earliest point in time we can connect OpenGL contexts to NSViews.
193     QWidget *qwidget = [[QT_MANGLE_NAMESPACE(QCocoaWindowDelegate) sharedDelegate] qt_qwidgetForWindow:self];
194     if (qwidget) {
195         qt_event_request_window_change(qwidget);
196         qt_mac_send_posted_gl_updates(qwidget);
197     }
198
199     [super setInitialFirstResponder:view];
200 }
201
202 - (BOOL)makeFirstResponder:(NSResponder *)responder
203 {
204     // For some reason Cocoa wants to flip the first responder
205     // when Qt doesn't want to, sorry, but "No" :-)
206     if (responder == nil && qApp->focusWidget())
207         return NO;
208     return [super makeFirstResponder:responder];
209 }
210
211 + (Class)frameViewClassForStyleMask:(NSUInteger)styleMask
212 {
213     if (styleMask & QtMacCustomizeWindow)
214         return [QT_MANGLE_NAMESPACE(QCocoaWindowCustomThemeFrame) class];
215     return [super frameViewClassForStyleMask:styleMask];
216 }
217
218 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
219 - (void)touchesBeganWithEvent:(NSEvent *)event;
220 {
221     QPoint qlocal, qglobal;
222     QWidget *widgetToGetTouch = 0;
223     qt_mac_getTargetForMouseEvent(event, QEvent::Gesture, qlocal, qglobal, 0, &widgetToGetTouch);
224     if (!widgetToGetTouch)
225         return;
226
227     bool all = widgetToGetTouch->testAttribute(Qt::WA_TouchPadAcceptSingleTouchEvents);
228     qt_translateRawTouchEvent(widgetToGetTouch, QTouchEvent::TouchPad, QCocoaTouch::getCurrentTouchPointList(event, all));
229 }
230
231 - (void)touchesMovedWithEvent:(NSEvent *)event;
232 {
233     QPoint qlocal, qglobal;
234     QWidget *widgetToGetTouch = 0;
235     qt_mac_getTargetForMouseEvent(event, QEvent::Gesture, qlocal, qglobal, 0, &widgetToGetTouch);
236     if (!widgetToGetTouch)
237         return;
238
239     bool all = widgetToGetTouch->testAttribute(Qt::WA_TouchPadAcceptSingleTouchEvents);
240     qt_translateRawTouchEvent(widgetToGetTouch, QTouchEvent::TouchPad, QCocoaTouch::getCurrentTouchPointList(event, all));
241 }
242
243 - (void)touchesEndedWithEvent:(NSEvent *)event;
244 {
245     QPoint qlocal, qglobal;
246     QWidget *widgetToGetTouch = 0;
247     qt_mac_getTargetForMouseEvent(event, QEvent::Gesture, qlocal, qglobal, 0, &widgetToGetTouch);
248     if (!widgetToGetTouch)
249         return;
250
251     bool all = widgetToGetTouch->testAttribute(Qt::WA_TouchPadAcceptSingleTouchEvents);
252     qt_translateRawTouchEvent(widgetToGetTouch, QTouchEvent::TouchPad, QCocoaTouch::getCurrentTouchPointList(event, all));
253 }
254
255 - (void)touchesCancelledWithEvent:(NSEvent *)event;
256 {
257     QPoint qlocal, qglobal;
258     QWidget *widgetToGetTouch = 0;
259     qt_mac_getTargetForMouseEvent(event, QEvent::Gesture, qlocal, qglobal, 0, &widgetToGetTouch);
260     if (!widgetToGetTouch)
261         return;
262
263     bool all = widgetToGetTouch->testAttribute(Qt::WA_TouchPadAcceptSingleTouchEvents);
264     qt_translateRawTouchEvent(widgetToGetTouch, QTouchEvent::TouchPad, QCocoaTouch::getCurrentTouchPointList(event, all));
265 }
266 #endif // MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
267
268 -(void)registerDragTypes
269 {
270     // Calling registerForDraggedTypes below is slow, so only do
271     // it once for each window, or when the custom types change.
272     QMacCocoaAutoReleasePool pool;
273     const QStringList& customTypes = qEnabledDraggedTypes();
274     if (currentCustomDragTypes == 0 || *currentCustomDragTypes != customTypes) {
275         if (currentCustomDragTypes == 0)
276             currentCustomDragTypes = new QStringList();
277         *currentCustomDragTypes = customTypes;
278         const NSString* mimeTypeGeneric = @"com.trolltech.qt.MimeTypeName";
279         NSMutableArray *supportedTypes = [NSMutableArray arrayWithObjects:NSColorPboardType,
280                        NSFilenamesPboardType, NSStringPboardType,
281                        NSFilenamesPboardType, NSPostScriptPboardType, NSTIFFPboardType,
282                        NSRTFPboardType, NSTabularTextPboardType, NSFontPboardType,
283                        NSRulerPboardType, NSFileContentsPboardType, NSColorPboardType,
284                        NSRTFDPboardType, NSHTMLPboardType, NSPICTPboardType,
285                        NSURLPboardType, NSPDFPboardType, NSVCardPboardType,
286                        NSFilesPromisePboardType, NSInkTextPboardType,
287                        NSMultipleTextSelectionPboardType, mimeTypeGeneric, nil];
288         // Add custom types supported by the application.
289         for (int i = 0; i < customTypes.size(); i++) {
290            [supportedTypes addObject:qt_mac_QStringToNSString(customTypes[i])];
291         }
292         [self registerForDraggedTypes:supportedTypes];
293     }
294 }
295
296 - (void)removeDropData
297 {
298     if (dropData) {
299         delete dropData;
300         dropData = 0;
301     }
302 }
303
304 - (void)addDropData:(id <NSDraggingInfo>)sender
305 {
306     [self removeDropData];
307     CFStringRef dropPasteboard = (CFStringRef) [[sender draggingPasteboard] name];
308     dropData = new QCocoaDropData(dropPasteboard);
309 }
310
311 - (void)changeDraggingCursor:(NSDragOperation)newOperation
312 {
313     static SEL action = nil;
314     static bool operationSupported = false;
315     if (action == nil) {
316         action = NSSelectorFromString(@"operationNotAllowedCursor");
317         if ([NSCursor respondsToSelector:action]) {
318             operationSupported = true;
319         }
320     }
321     if (operationSupported) {
322         NSCursor *notAllowedCursor = [NSCursor performSelector:action];
323         bool isNotAllowedCursor = ([NSCursor currentCursor] == notAllowedCursor);
324         if (newOperation == NSDragOperationNone && !isNotAllowedCursor) {
325             [notAllowedCursor push];
326         } else if (newOperation != NSDragOperationNone && isNotAllowedCursor) {
327             [notAllowedCursor pop];
328         }
329
330     }
331 }
332
333 - (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender
334 {
335     // The user dragged something into the window. Send a draggingEntered message
336     // to the QWidget under the mouse. As the drag moves over the window, and over
337     // different widgets, we will handle enter and leave events from within
338     // draggingUpdated below. The reason why we handle this ourselves rather than
339     // subscribing for drag events directly in QCocoaView is that calling
340     // registerForDraggedTypes on the views will severly degrade initialization time
341     // for an application that uses a lot of drag subscribing widgets.
342
343     NSPoint nswindowPoint = [sender draggingLocation];
344     NSPoint nsglobalPoint = [[sender draggingDestinationWindow] convertBaseToScreen:nswindowPoint];
345     QPoint globalPoint = flipPoint(nsglobalPoint).toPoint();
346
347     QWidget *qwidget = QApplication::widgetAt(globalPoint);
348     *currentDragTarget() = qwidget;
349     if (!qwidget)
350         return NSDragOperationNone;
351     if (qwidget->testAttribute(Qt::WA_DropSiteRegistered) == false)
352         return NSDragOperationNone;
353
354     [self addDropData:sender];
355
356     QMimeData *mimeData = dropData;
357     if (QDragManager::self()->source())
358         mimeData = QDragManager::self()->dragPrivate()->data;
359
360     NSDragOperation nsActions = [sender draggingSourceOperationMask];
361     Qt::DropActions qtAllowed = qt_mac_mapNSDragOperations(nsActions);
362     QT_PREPEND_NAMESPACE(qt_mac_dnd_answer_rec.lastOperation) = nsActions;
363     Qt::KeyboardModifiers modifiers = Qt::NoModifier;
364
365     if ([sender draggingSource] != nil) {
366         // modifier flags might have changed, update it here since we don't send any input events.
367         QApplicationPrivate::modifier_buttons = qt_cocoaModifiers2QtModifiers([[NSApp currentEvent] modifierFlags]);
368         modifiers = QApplication::keyboardModifiers();
369     } else {
370         // when the source is from another application the above technique will not work.
371         modifiers = qt_cocoaDragOperation2QtModifiers(nsActions);
372     }
373
374     // send the drag enter event to the widget.
375     QPoint localPoint(qwidget->mapFromGlobal(globalPoint));
376     QDragEnterEvent qDEEvent(localPoint, qtAllowed, mimeData, QApplication::mouseButtons(), modifiers);
377     QApplication::sendEvent(qwidget, &qDEEvent);
378
379     if (!qDEEvent.isAccepted()) {
380         // The enter event was not accepted. We mark this by removing
381         // the drop data so we don't send subsequent drag move events:
382         [self removeDropData];
383         [self changeDraggingCursor:NSDragOperationNone];
384         return NSDragOperationNone;
385     } else {
386         // Send a drag move event immediately after a drag enter event (as per documentation).
387         QDragMoveEvent qDMEvent(localPoint, qtAllowed, mimeData, QApplication::mouseButtons(), modifiers);
388         qDMEvent.setDropAction(qDEEvent.dropAction());
389         qDMEvent.accept(); // accept by default, since enter event was accepted.
390         QApplication::sendEvent(qwidget, &qDMEvent);
391
392         if (!qDMEvent.isAccepted() || qDMEvent.dropAction() == Qt::IgnoreAction) {
393             // Since we accepted the drag enter event, the widget expects
394             // future drage move events.
395             nsActions = NSDragOperationNone;
396             // Save as ignored in the answer rect.
397             qDMEvent.setDropAction(Qt::IgnoreAction);
398         } else {
399             nsActions = QT_PREPEND_NAMESPACE(qt_mac_mapDropAction)(qDMEvent.dropAction());
400         }
401
402         QT_PREPEND_NAMESPACE(qt_mac_copy_answer_rect)(qDMEvent);
403         [self changeDraggingCursor:nsActions];
404         return nsActions;
405     }
406  }
407
408 - (NSDragOperation)draggingUpdated:(id <NSDraggingInfo>)sender
409 {
410     NSPoint nswindowPoint = [sender draggingLocation];
411     NSPoint nsglobalPoint = [[sender draggingDestinationWindow] convertBaseToScreen:nswindowPoint];
412     QPoint globalPoint = flipPoint(nsglobalPoint).toPoint();
413
414     QWidget *qwidget = QApplication::widgetAt(globalPoint);
415     if (!qwidget)
416         return NSDragOperationNone;
417
418     // First, check if the widget under the mouse has changed since the
419     // last drag move events. If so, we need to change target, and dispatch
420     // syntetic drag enter/leave events:
421     if (qwidget != *currentDragTarget()) {
422         if (*currentDragTarget() && dropData) {
423             QDragLeaveEvent de;
424             QApplication::sendEvent(*currentDragTarget(), &de);
425             [self removeDropData];
426         }
427         return [self draggingEntered:sender];
428     }
429
430     if (qwidget->testAttribute(Qt::WA_DropSiteRegistered) == false)
431         return NSDragOperationNone;
432
433     // If we have no drop data (which will be assigned inside draggingEntered), it means
434     // that the current drag target did not accept the enter event. If so, we ignore
435     // subsequent move events as well:
436     if (dropData == 0) {
437         [self changeDraggingCursor:NSDragOperationNone];
438         return NSDragOperationNone;
439     }
440
441     // If the mouse is still within the accepted rect (provided by
442     // the application on a previous event), we follow the optimization
443     // and just return the answer given at that point:
444     NSDragOperation nsActions = [sender draggingSourceOperationMask];
445     QPoint localPoint(qwidget->mapFromGlobal(globalPoint));
446     if (qt_mac_mouse_inside_answer_rect(localPoint)
447         && QT_PREPEND_NAMESPACE(qt_mac_dnd_answer_rec.lastOperation) == nsActions) {
448         NSDragOperation operation = QT_PREPEND_NAMESPACE(qt_mac_mapDropActions)(QT_PREPEND_NAMESPACE(qt_mac_dnd_answer_rec.lastAction));
449         [self changeDraggingCursor:operation];
450         return operation;
451     }
452
453     QT_PREPEND_NAMESPACE(qt_mac_dnd_answer_rec.lastOperation) = nsActions;
454     Qt::DropActions qtAllowed = QT_PREPEND_NAMESPACE(qt_mac_mapNSDragOperations)(nsActions);
455     Qt::KeyboardModifiers modifiers  = Qt::NoModifier;
456
457     // Update modifiers:
458     if ([sender draggingSource] != nil) {
459         QApplicationPrivate::modifier_buttons = qt_cocoaModifiers2QtModifiers([[NSApp currentEvent] modifierFlags]);
460         modifiers = QApplication::keyboardModifiers();
461     } else {
462         modifiers = qt_cocoaDragOperation2QtModifiers(nsActions);
463     }
464
465     QMimeData *mimeData = dropData;
466     if (QDragManager::self()->source())
467         mimeData = QDragManager::self()->dragPrivate()->data;
468
469     // Insert the same drop action on the event according to
470     // what the application told us it should be on the previous event:
471     QDragMoveEvent qDMEvent(localPoint, qtAllowed, mimeData, QApplication::mouseButtons(), modifiers);
472     if (QT_PREPEND_NAMESPACE(qt_mac_dnd_answer_rec).lastAction != Qt::IgnoreAction
473         && QT_PREPEND_NAMESPACE(qt_mac_dnd_answer_rec).buttons == qDMEvent.mouseButtons()
474         && QT_PREPEND_NAMESPACE(qt_mac_dnd_answer_rec).modifiers == qDMEvent.keyboardModifiers())
475         qDMEvent.setDropAction(QT_PREPEND_NAMESPACE(qt_mac_dnd_answer_rec).lastAction);
476
477     // Now, end the drag move event to the widget:
478     qDMEvent.accept();
479     QApplication::sendEvent(qwidget, &qDMEvent);
480
481     NSDragOperation operation = qt_mac_mapDropAction(qDMEvent.dropAction());
482     if (!qDMEvent.isAccepted() || qDMEvent.dropAction() == Qt::IgnoreAction) {
483         // Ignore this event (we will still receive further
484         // notifications), save as ignored in the answer rect:
485         operation = NSDragOperationNone;
486         qDMEvent.setDropAction(Qt::IgnoreAction);
487     }
488
489     qt_mac_copy_answer_rect(qDMEvent);
490     [self changeDraggingCursor:operation];
491
492     return operation;
493 }
494
495 - (void)draggingExited:(id <NSDraggingInfo>)sender
496 {
497     NSPoint nswindowPoint = [sender draggingLocation];
498     NSPoint nsglobalPoint = [[sender draggingDestinationWindow] convertBaseToScreen:nswindowPoint];
499     QPoint globalPoint = flipPoint(nsglobalPoint).toPoint();
500
501     QWidget *qwidget = *currentDragTarget();
502     if (!qwidget)
503         return;
504
505     if (dropData) {
506         QDragLeaveEvent de;
507         QApplication::sendEvent(qwidget, &de);
508         [self removeDropData];
509     }
510
511     // Clean-up:
512     [self removeDropData];
513     *currentDragTarget() = 0;
514     [self changeDraggingCursor:NSDragOperationEvery];
515 }
516
517 - (BOOL)performDragOperation:(id <NSDraggingInfo>)sender
518 {
519     QWidget *qwidget = *currentDragTarget();
520     if (!qwidget)
521         return NO;
522
523     *currentDragTarget() = 0;
524     NSPoint nswindowPoint = [sender draggingLocation];
525     NSPoint nsglobalPoint = [[sender draggingDestinationWindow] convertBaseToScreen:nswindowPoint];
526     QPoint globalPoint = flipPoint(nsglobalPoint).toPoint();
527
528     [self addDropData:sender];
529
530     NSDragOperation nsActions = [sender draggingSourceOperationMask];
531     Qt::DropActions qtAllowed = qt_mac_mapNSDragOperations(nsActions);
532     QMimeData *mimeData = dropData;
533
534     if (QDragManager::self()->source())
535         mimeData = QDragManager::self()->dragPrivate()->data;
536     if (QDragManager::self()->object)
537         QDragManager::self()->dragPrivate()->target = qwidget;
538
539     QPoint localPoint(qwidget->mapFromGlobal(globalPoint));
540     QDropEvent de(localPoint, qtAllowed, mimeData,
541                   QApplication::mouseButtons(), QApplication::keyboardModifiers());
542     QApplication::sendEvent(qwidget, &de);
543
544     if (QDragManager::self()->object)
545         QDragManager::self()->dragPrivate()->executed_action = de.dropAction();
546
547     return de.isAccepted();
548 }
549
550 // This is a hack and it should be removed once we find the real cause for
551 // the painting problems.
552 // We have a static variable that signals if we have been called before or not.
553 static bool firstDrawingInvocation = true;
554
555 // The method below exists only as a workaround to draw/not draw the baseline
556 // in the title bar. This is to support unifiedToolbar look.
557
558 // This method is very special. To begin with, it is a
559 // method that will get called only if we enable documentMode.
560 // Furthermore, it won't get called as a normal method, we swap
561 // this method with the normal implementation of drawRect in
562 // _NSThemeFrame. When this method is active, its mission is to
563 // first call the original drawRect implementation so the widget
564 // gets proper painting. After that, it needs to detect if there
565 // is a toolbar or not, in order to decide how to handle the unified
566 // look. The distinction is important since the presence and
567 // visibility of a toolbar change the way we enter into unified mode.
568 // When there is a toolbar and that toolbar is visible, the problem
569 // is as simple as to tell the toolbar not to draw its baseline.
570 // However when there is not toolbar or the toolbar is not visible,
571 // we need to draw a line on top of the baseline, because the baseline
572 // in that case will belong to the title. For this case we need to draw
573 // a line on top of the baseline.
574 // As usual, there is a special case. When we first are called, we might
575 // need to repaint ourselves one more time. We only need that if we
576 // didn't get the activation, i.e. when we are launched via the command
577 // line. And this only if the toolbar is visible from the beginning,
578 // so we have a special flag that signals if we need to repaint or not.
579 - (void)drawRectSpecial:(NSRect)rect
580 {
581     // Call the original drawing method.
582     [id(self) drawRectOriginal:rect];
583     NSWindow *window = [id(self) window];
584     NSToolbar *toolbar = [window toolbar];
585     if(!toolbar) {
586         // There is no toolbar, we have to draw a line on top of the line drawn by Cocoa.
587         macDrawRectOnTop((void *)window);
588     } else {
589         if([toolbar isVisible]) {
590             // We tell Cocoa to avoid drawing the line at the end.
591             if(firstDrawingInvocation) {
592                 firstDrawingInvocation = false;
593                 macSyncDrawingOnFirstInvocation((void *)window);
594             } else
595                 [toolbar setShowsBaselineSeparator:NO];
596         } else {
597             // There is a toolbar but it is not visible so
598             // we have to draw a line on top of the line drawn by Cocoa.
599             macDrawRectOnTop((void *)window);
600         }
601     }
602 }
603
604 - (void)drawRectOriginal:(NSRect)rect
605 {
606     Q_UNUSED(rect)
607     // This method implementation is here to silenct the compiler.
608     // See drawRectSpecial for information.
609 }
610