source: trunk/src/gui/kernel/qcocoaview_mac.mm@ 765

Last change on this file since 765 was 651, checked in by Dmitry A. Kuminov, 16 years ago

trunk: Merged in qt 4.6.2 sources.

File size: 54.4 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation ([email protected])
6**
7** This file is part of the QtGui module of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
15**
16** GNU Lesser General Public License Usage
17** Alternatively, this file may be used under the terms of the GNU Lesser
18** General Public License version 2.1 as published by the Free Software
19** Foundation and appearing in the file LICENSE.LGPL included in the
20** packaging of this file. Please review the following information to
21** ensure the GNU Lesser General Public License version 2.1 requirements
22** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23**
24** In addition, as a special exception, Nokia gives you certain additional
25** rights. These rights are described in the Nokia Qt LGPL Exception
26** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you have questions regarding the use of this file, please contact
37** Nokia at [email protected].
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
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/qmultitouch_mac_p.h>
53#include <private/qevent_p.h>
54#include <private/qbackingstore_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
77QT_BEGIN_NAMESPACE
78
79Q_GLOBAL_STATIC(DnDParams, qMacDnDParams);
80
81extern void qt_mac_update_cursor_at_global_pos(const QPoint &globalPos); // qcursor_mac.mm
82extern bool qt_sendSpontaneousEvent(QObject *, QEvent *); // qapplication.cpp
83extern OSViewRef qt_mac_nativeview_for(const QWidget *w); // qwidget_mac.mm
84extern const QStringList& qEnabledDraggedTypes(); // qmime_mac.cpp
85extern QPointer<QWidget> qt_mouseover; //qapplication_mac.mm
86extern QPointer<QWidget> qt_button_down; //qapplication_mac.cpp
87
88Qt::MouseButton cocoaButton2QtButton(NSInteger buttonNum)
89{
90 if (buttonNum == 0)
91 return Qt::LeftButton;
92 if (buttonNum == 1)
93 return Qt::RightButton;
94 if (buttonNum == 2)
95 return Qt::MidButton;
96 if (buttonNum == 3)
97 return Qt::XButton1;
98 if (buttonNum == 4)
99 return Qt::XButton2;
100 return Qt::NoButton;
101}
102
103struct dndenum_mapper
104{
105 NSDragOperation mac_code;
106 Qt::DropAction qt_code;
107 bool Qt2Mac;
108};
109
110static dndenum_mapper dnd_enums[] = {
111 { NSDragOperationLink, Qt::LinkAction, true },
112 { NSDragOperationMove, Qt::MoveAction, true },
113 { NSDragOperationCopy, Qt::CopyAction, true },
114 { NSDragOperationGeneric, Qt::CopyAction, false },
115 { NSDragOperationEvery, Qt::ActionMask, false },
116 { NSDragOperationNone, Qt::IgnoreAction, false }
117};
118
119static NSDragOperation qt_mac_mapDropAction(Qt::DropAction action)
120{
121 for (int i=0; dnd_enums[i].qt_code; i++) {
122 if (dnd_enums[i].Qt2Mac && (action & dnd_enums[i].qt_code)) {
123 return dnd_enums[i].mac_code;
124 }
125 }
126 return NSDragOperationNone;
127}
128
129static NSDragOperation qt_mac_mapDropActions(Qt::DropActions actions)
130{
131 NSDragOperation nsActions = NSDragOperationNone;
132 for (int i=0; dnd_enums[i].qt_code; i++) {
133 if (dnd_enums[i].Qt2Mac && (actions & dnd_enums[i].qt_code))
134 nsActions |= dnd_enums[i].mac_code;
135 }
136 return nsActions;
137}
138
139static Qt::DropAction qt_mac_mapNSDragOperation(NSDragOperation nsActions)
140{
141 Qt::DropAction action = Qt::IgnoreAction;
142 for (int i=0; dnd_enums[i].mac_code; i++) {
143 if (nsActions & dnd_enums[i].mac_code)
144 return dnd_enums[i].qt_code;
145 }
146 return action;
147}
148
149static Qt::DropActions qt_mac_mapNSDragOperations(NSDragOperation nsActions)
150{
151 Qt::DropActions actions = Qt::IgnoreAction;
152 for (int i=0; dnd_enums[i].mac_code; i++) {
153 if (nsActions & dnd_enums[i].mac_code)
154 actions |= dnd_enums[i].qt_code;
155 }
156 return actions;
157}
158
159static QColor colorFrom(NSColor *color)
160{
161 QColor qtColor;
162 NSString *colorSpace = [color colorSpaceName];
163 if (colorSpace == NSDeviceCMYKColorSpace) {
164 CGFloat cyan, magenta, yellow, black, alpha;
165 [color getCyan:&cyan magenta:&magenta yellow:&yellow black:&black alpha:&alpha];
166 qtColor.setCmykF(cyan, magenta, yellow, black, alpha);
167 } else {
168 NSColor *tmpColor;
169 tmpColor = [color colorUsingColorSpaceName:NSDeviceRGBColorSpace];
170 CGFloat red, green, blue, alpha;
171 [tmpColor getRed:&red green:&green blue:&blue alpha:&alpha];
172 qtColor.setRgbF(red, green, blue, alpha);
173 }
174 return qtColor;
175}
176
177QT_END_NAMESPACE
178
179QT_FORWARD_DECLARE_CLASS(QMacCocoaAutoReleasePool)
180QT_FORWARD_DECLARE_CLASS(QCFString)
181QT_FORWARD_DECLARE_CLASS(QDragManager)
182QT_FORWARD_DECLARE_CLASS(QMimeData)
183QT_FORWARD_DECLARE_CLASS(QPoint)
184QT_FORWARD_DECLARE_CLASS(QApplication)
185QT_FORWARD_DECLARE_CLASS(QApplicationPrivate)
186QT_FORWARD_DECLARE_CLASS(QDragEnterEvent)
187QT_FORWARD_DECLARE_CLASS(QDragMoveEvent)
188QT_FORWARD_DECLARE_CLASS(QStringList)
189QT_FORWARD_DECLARE_CLASS(QString)
190QT_FORWARD_DECLARE_CLASS(QRect)
191QT_FORWARD_DECLARE_CLASS(QRegion)
192QT_FORWARD_DECLARE_CLASS(QAbstractScrollArea)
193QT_FORWARD_DECLARE_CLASS(QAbstractScrollAreaPrivate)
194QT_FORWARD_DECLARE_CLASS(QPaintEvent)
195QT_FORWARD_DECLARE_CLASS(QPainter)
196QT_FORWARD_DECLARE_CLASS(QHoverEvent)
197QT_FORWARD_DECLARE_CLASS(QCursor)
198QT_USE_NAMESPACE
199extern "C" {
200 extern NSString *NSTextInputReplacementRangeAttributeName;
201}
202
203
204@implementation QT_MANGLE_NAMESPACE(QCocoaView)
205
206- (id)initWithQWidget:(QWidget *)widget widgetPrivate:(QWidgetPrivate *)widgetprivate
207{
208 self = [super init];
209 if (self) {
210 [self finishInitWithQWidget:widget widgetPrivate:widgetprivate];
211 }
212 composingText = new QString();
213 composing = false;
214 sendKeyEvents = true;
215 currentCustomTypes = 0;
216 [self setHidden:YES];
217 return self;
218}
219
220- (void) finishInitWithQWidget:(QWidget *)widget widgetPrivate:(QWidgetPrivate *)widgetprivate
221{
222 qwidget = widget;
223 qwidgetprivate = widgetprivate;
224 [[NSNotificationCenter defaultCenter] addObserver:self
225 selector:@selector(frameDidChange:)
226 name:@"NSViewFrameDidChangeNotification"
227 object:self];
228}
229
230-(void)registerDragTypes
231{
232 QMacCocoaAutoReleasePool pool;
233 // Calling registerForDraggedTypes is slow, so only do it once for each widget
234 // or when the custom types change.
235 const QStringList& customTypes = qEnabledDraggedTypes();
236 if (currentCustomTypes == 0 || *currentCustomTypes != customTypes) {
237 if (currentCustomTypes == 0)
238 currentCustomTypes = new QStringList();
239 *currentCustomTypes = customTypes;
240 const NSString* mimeTypeGeneric = @"com.trolltech.qt.MimeTypeName";
241 NSMutableArray *supportedTypes = [NSMutableArray arrayWithObjects:NSColorPboardType,
242 NSFilenamesPboardType, NSStringPboardType,
243 NSFilenamesPboardType, NSPostScriptPboardType, NSTIFFPboardType,
244 NSRTFPboardType, NSTabularTextPboardType, NSFontPboardType,
245 NSRulerPboardType, NSFileContentsPboardType, NSColorPboardType,
246 NSRTFDPboardType, NSHTMLPboardType, NSPICTPboardType,
247 NSURLPboardType, NSPDFPboardType, NSVCardPboardType,
248 NSFilesPromisePboardType, NSInkTextPboardType,
249 NSMultipleTextSelectionPboardType, mimeTypeGeneric, nil];
250 // Add custom types supported by the application.
251 for (int i = 0; i < customTypes.size(); i++) {
252 [supportedTypes addObject:reinterpret_cast<const NSString *>(QCFString::toCFStringRef(customTypes[i]))];
253 }
254 [self registerForDraggedTypes:supportedTypes];
255 }
256}
257
258- (void)resetCursorRects
259{
260 QWidget *cursorWidget = qwidget;
261
262 if (cursorWidget->testAttribute(Qt::WA_TransparentForMouseEvents))
263 cursorWidget = QApplication::widgetAt(qwidget->mapToGlobal(qwidget->rect().center()));
264
265 if (cursorWidget == 0)
266 return;
267
268 if (!cursorWidget->testAttribute(Qt::WA_SetCursor)) {
269 [super resetCursorRects];
270 return;
271 }
272
273 QRegion mask = qt_widget_private(cursorWidget)->extra->mask;
274 NSCursor *nscursor = static_cast<NSCursor *>(qt_mac_nsCursorForQCursor(cursorWidget->cursor()));
275 if (mask.isEmpty()) {
276 [self addCursorRect:[qt_mac_nativeview_for(cursorWidget) visibleRect] cursor:nscursor];
277 } else {
278 const QVector<QRect> &rects = mask.rects();
279 for (int i = 0; i < rects.size(); ++i) {
280 const QRect &rect = rects.at(i);
281 [self addCursorRect:NSMakeRect(rect.x(), rect.y(), rect.width(), rect.height()) cursor:nscursor];
282 }
283 }
284}
285
286- (void)removeDropData
287{
288 if (dropData) {
289 delete dropData;
290 dropData = 0;
291 }
292}
293
294- (void)addDropData:(id <NSDraggingInfo>)sender
295{
296 [self removeDropData];
297 CFStringRef dropPasteboard = (CFStringRef) [[sender draggingPasteboard] name];
298 dropData = new QCocoaDropData(dropPasteboard);
299}
300
301- (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender
302{
303 if (qwidget->testAttribute(Qt::WA_DropSiteRegistered) == false)
304 return NSDragOperationNone;
305 NSPoint windowPoint = [sender draggingLocation];
306 if (qwidget->testAttribute(Qt::WA_TransparentForMouseEvents)) {
307 // pass the drag enter event to the view underneath.
308 NSView *candidateView = [[[self window] contentView] hitTest:windowPoint];
309 if (candidateView && candidateView != self)
310 return [candidateView draggingEntered:sender];
311 }
312 dragEnterSequence = [sender draggingSequenceNumber];
313 [self addDropData:sender];
314 QMimeData *mimeData = dropData;
315 if (QDragManager::self()->source())
316 mimeData = QDragManager::self()->dragPrivate()->data;
317 NSPoint globalPoint = [[sender draggingDestinationWindow] convertBaseToScreen:windowPoint];
318 NSPoint localPoint = [self convertPoint:windowPoint fromView:nil];
319 QPoint posDrag(localPoint.x, localPoint.y);
320 NSDragOperation nsActions = [sender draggingSourceOperationMask];
321 Qt::DropActions qtAllowed = qt_mac_mapNSDragOperations(nsActions);
322 QT_PREPEND_NAMESPACE(qt_mac_dnd_answer_rec.lastOperation) = nsActions;
323 Qt::KeyboardModifiers modifiers = Qt::NoModifier;
324 if ([sender draggingSource] != nil) {
325 // modifier flags might have changed, update it here since we don't send any input events.
326 QApplicationPrivate::modifier_buttons = qt_cocoaModifiers2QtModifiers([[NSApp currentEvent] modifierFlags]);
327 modifiers = QApplication::keyboardModifiers();
328 } else {
329 // when the source is from another application the above technique will not work.
330 modifiers = qt_cocoaDragOperation2QtModifiers(nsActions);
331 }
332 // send the drag enter event to the widget.
333 QDragEnterEvent qDEEvent(posDrag, qtAllowed, mimeData, QApplication::mouseButtons(), modifiers);
334 QApplication::sendEvent(qwidget, &qDEEvent);
335 if (!qDEEvent.isAccepted()) {
336 // widget is not interested in this drag, so ignore this drop data.
337 [self removeDropData];
338 return NSDragOperationNone;
339 } else {
340 // save the mouse position, used by draggingExited handler.
341 DnDParams *dndParams = [QT_MANGLE_NAMESPACE(QCocoaView) currentMouseEvent];
342 dndParams->activeDragEnterPos = windowPoint;
343 // send a drag move event immediately after a drag enter event (as per documentation).
344 QDragMoveEvent qDMEvent(posDrag, qtAllowed, mimeData, QApplication::mouseButtons(), modifiers);
345 qDMEvent.setDropAction(qDEEvent.dropAction());
346 qDMEvent.accept(); // accept by default, since enter event was accepted.
347 QApplication::sendEvent(qwidget, &qDMEvent);
348 if (!qDMEvent.isAccepted() || qDMEvent.dropAction() == Qt::IgnoreAction) {
349 // since we accepted the drag enter event, the widget expects
350 // future drage move events.
351 // ### check if we need to treat this like the drag enter event.
352 nsActions = NSDragOperationNone;
353 // Save as ignored in the answer rect.
354 qDMEvent.setDropAction(Qt::IgnoreAction);
355 } else {
356 nsActions = QT_PREPEND_NAMESPACE(qt_mac_mapDropAction)(qDMEvent.dropAction());
357 }
358 QT_PREPEND_NAMESPACE(qt_mac_copy_answer_rect)(qDMEvent);
359 return nsActions;
360 }
361 }
362- (NSDragOperation)draggingUpdated:(id < NSDraggingInfo >)sender
363{
364 NSPoint windowPoint = [sender draggingLocation];
365 if (qwidget->testAttribute(Qt::WA_TransparentForMouseEvents)) {
366 // pass the drag move event to the view underneath.
367 NSView *candidateView = [[[self window] contentView] hitTest:windowPoint];
368 if (candidateView && candidateView != self)
369 return [candidateView draggingUpdated:sender];
370 }
371 // in cases like QFocusFrame, the view under the mouse might
372 // not have received the drag enter. Generate a synthetic
373 // drag enter event for that view.
374 if (dragEnterSequence != [sender draggingSequenceNumber])
375 [self draggingEntered:sender];
376 // drag enter event was rejected, so ignore the move event.
377 if (dropData == 0)
378 return NSDragOperationNone;
379 // return last value, if we are still in the answerRect.
380 NSPoint globalPoint = [[sender draggingDestinationWindow] convertBaseToScreen:windowPoint];
381 NSPoint localPoint = [self convertPoint:windowPoint fromView:nil];
382 NSDragOperation nsActions = [sender draggingSourceOperationMask];
383 QPoint posDrag(localPoint.x, localPoint.y);
384 if (qt_mac_mouse_inside_answer_rect(posDrag)
385 && QT_PREPEND_NAMESPACE(qt_mac_dnd_answer_rec.lastOperation) == nsActions)
386 return QT_PREPEND_NAMESPACE(qt_mac_mapDropActions)(QT_PREPEND_NAMESPACE(qt_mac_dnd_answer_rec.lastAction));
387 // send drag move event to the widget
388 QT_PREPEND_NAMESPACE(qt_mac_dnd_answer_rec.lastOperation) = nsActions;
389 Qt::DropActions qtAllowed = QT_PREPEND_NAMESPACE(qt_mac_mapNSDragOperations)(nsActions);
390 Qt::KeyboardModifiers modifiers = Qt::NoModifier;
391 if ([sender draggingSource] != nil) {
392 // modifier flags might have changed, update it here since we don't send any input events.
393 QApplicationPrivate::modifier_buttons = qt_cocoaModifiers2QtModifiers([[NSApp currentEvent] modifierFlags]);
394 modifiers = QApplication::keyboardModifiers();
395 } else {
396 // when the source is from another application the above technique will not work.
397 modifiers = qt_cocoaDragOperation2QtModifiers(nsActions);
398 }
399 QMimeData *mimeData = dropData;
400 if (QDragManager::self()->source())
401 mimeData = QDragManager::self()->dragPrivate()->data;
402 QDragMoveEvent qDMEvent(posDrag, qtAllowed, mimeData, QApplication::mouseButtons(), modifiers);
403 qDMEvent.setDropAction(QT_PREPEND_NAMESPACE(qt_mac_dnd_answer_rec).lastAction);
404 qDMEvent.accept();
405 QApplication::sendEvent(qwidget, &qDMEvent);
406
407 NSDragOperation operation = qt_mac_mapDropAction(qDMEvent.dropAction());
408 if (!qDMEvent.isAccepted() || qDMEvent.dropAction() == Qt::IgnoreAction) {
409 // ignore this event (we will still receive further notifications)
410 operation = NSDragOperationNone;
411 // Save as ignored in the answer rect.
412 qDMEvent.setDropAction(Qt::IgnoreAction);
413 }
414 qt_mac_copy_answer_rect(qDMEvent);
415 return operation;
416}
417
418- (void)draggingExited:(id < NSDraggingInfo >)sender
419{
420 dragEnterSequence = -1;
421 if (qwidget->testAttribute(Qt::WA_TransparentForMouseEvents)) {
422 // try sending the leave event to the last view which accepted drag enter.
423 DnDParams *dndParams = [QT_MANGLE_NAMESPACE(QCocoaView) currentMouseEvent];
424 NSView *candidateView = [[[self window] contentView] hitTest:dndParams->activeDragEnterPos];
425 if (candidateView && candidateView != self)
426 return [candidateView draggingExited:sender];
427 }
428 // drag enter event was rejected, so ignore the move event.
429 if (dropData) {
430 QDragLeaveEvent de;
431 QApplication::sendEvent(qwidget, &de);
432 [self removeDropData];
433 }
434}
435
436- (BOOL)performDragOperation:(id <NSDraggingInfo>)sender
437{
438 NSPoint windowPoint = [sender draggingLocation];
439 dragEnterSequence = -1;
440 if (qwidget->testAttribute(Qt::WA_TransparentForMouseEvents)) {
441 // pass the drop event to the view underneath.
442 NSView *candidateView = [[[self window] contentView] hitTest:windowPoint];
443 if (candidateView && candidateView != self)
444 return [candidateView performDragOperation:sender];
445 }
446 [self addDropData:sender];
447
448 NSPoint globalPoint = [[sender draggingDestinationWindow] convertBaseToScreen:windowPoint];
449 NSPoint localPoint = [self convertPoint:windowPoint fromView:nil];
450 QPoint posDrop(localPoint.x, localPoint.y);
451
452 NSDragOperation nsActions = [sender draggingSourceOperationMask];
453 Qt::DropActions qtAllowed = qt_mac_mapNSDragOperations(nsActions);
454 QMimeData *mimeData = dropData;
455 if (QDragManager::self()->source())
456 mimeData = QDragManager::self()->dragPrivate()->data;
457 // send the drop event to the widget.
458 QDropEvent de(posDrop, qtAllowed, mimeData,
459 QApplication::mouseButtons(), QApplication::keyboardModifiers());
460 if (QDragManager::self()->object)
461 QDragManager::self()->dragPrivate()->target = qwidget;
462 QApplication::sendEvent(qwidget, &de);
463 if (QDragManager::self()->object)
464 QDragManager::self()->dragPrivate()->executed_action = de.dropAction();
465 if (!de.isAccepted())
466 return NO;
467 else
468 return YES;
469}
470
471- (void)dealloc
472{
473 delete composingText;
474 [[NSNotificationCenter defaultCenter] removeObserver:self];
475 delete currentCustomTypes;
476 [self unregisterDraggedTypes];
477 [super dealloc];
478}
479
480- (BOOL)isOpaque;
481{
482 return qwidgetprivate->isOpaque;
483}
484
485- (BOOL)isFlipped;
486{
487 return YES;
488}
489
490- (BOOL) preservesContentDuringLiveResize;
491{
492 return qwidget->testAttribute(Qt::WA_StaticContents);
493}
494
495- (void) setFrameSize:(NSSize)newSize
496{
497 [super setFrameSize:newSize];
498
499 // A change in size has required the view to be invalidated.
500 if ([self inLiveResize]) {
501 NSRect rects[4];
502 NSInteger count;
503 [self getRectsExposedDuringLiveResize:rects count:&count];
504 while (count-- > 0)
505 {
506 [self setNeedsDisplayInRect:rects[count]];
507 }
508 } else {
509 [self setNeedsDisplay:YES];
510 }
511
512 // Make sure the opengl context is updated on resize.
513 if (qwidgetprivate->isGLWidget) {
514 qwidgetprivate->needWindowChange = true;
515 QEvent event(QEvent::MacGLWindowChange);
516 qApp->sendEvent(qwidget, &event);
517 }
518}
519
520- (void)drawRect:(NSRect)aRect
521{
522 if (QApplicationPrivate::graphicsSystem() != 0) {
523 if (QWidgetBackingStore *bs = qwidgetprivate->maybeBackingStore())
524 bs->markDirty(qwidget->rect(), qwidget);
525 qwidgetprivate->syncBackingStore(qwidget->rect());
526 return;
527 }
528 CGContextRef cg = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort];
529 qwidgetprivate->hd = cg;
530 CGContextSaveGState(cg);
531
532 if (qwidget->isVisible() && qwidget->updatesEnabled()) { //process the actual paint event.
533 if (qwidget->testAttribute(Qt::WA_WState_InPaintEvent))
534 qWarning("QWidget::repaint: Recursive repaint detected");
535
536 const QRect qrect = QRect(aRect.origin.x, aRect.origin.y, aRect.size.width, aRect.size.height);
537 QRegion qrgn(qrect);
538
539 if (!qwidget->isWindow() && !qobject_cast<QAbstractScrollArea *>(qwidget->parent())) {
540 const QRegion &parentMask = qwidget->window()->mask();
541 if (!parentMask.isEmpty()) {
542 const QPoint mappedPoint = qwidget->mapTo(qwidget->window(), qrect.topLeft());
543 qrgn.translate(mappedPoint);
544 qrgn &= parentMask;
545 qrgn.translate(-mappedPoint.x(), -mappedPoint.y());
546 }
547 }
548
549 QPoint redirectionOffset(0, 0);
550 //setup the context
551 qwidget->setAttribute(Qt::WA_WState_InPaintEvent);
552 QPaintEngine *engine = qwidget->paintEngine();
553 if (engine)
554 engine->setSystemClip(qrgn);
555 if (qwidgetprivate->extra && qwidgetprivate->extra->hasMask) {
556 CGRect widgetRect = CGRectMake(0, 0, qwidget->width(), qwidget->height());
557 CGContextTranslateCTM (cg, 0, widgetRect.size.height);
558 CGContextScaleCTM(cg, 1, -1);
559 if (qwidget->isWindow())
560 CGContextClearRect(cg, widgetRect);
561 CGContextClipToMask(cg, widgetRect, qwidgetprivate->extra->imageMask);
562 CGContextScaleCTM(cg, 1, -1);
563 CGContextTranslateCTM (cg, 0, -widgetRect.size.height);
564 }
565
566 if (qwidget->isWindow() && !qwidgetprivate->isOpaque
567 && !qwidget->testAttribute(Qt::WA_MacBrushedMetal)) {
568 CGContextClearRect(cg, NSRectToCGRect(aRect));
569 }
570
571 if (engine && !qwidget->testAttribute(Qt::WA_NoSystemBackground)
572 && (qwidget->isWindow() || qwidget->autoFillBackground())
573 || qwidget->testAttribute(Qt::WA_TintedBackground)
574 || qwidget->testAttribute(Qt::WA_StyledBackground)) {
575#ifdef DEBUG_WIDGET_PAINT
576 if(doDebug)
577 qDebug(" Handling erase for [%s::%s]", qwidget->metaObject()->className(),
578 qwidget->objectName().local8Bit().data());
579#endif
580 QPainter p(qwidget);
581 qwidgetprivate->paintBackground(&p, qrgn,
582 qwidget->isWindow() ? QWidgetPrivate::DrawAsRoot : 0);