summaryrefslogtreecommitdiffstats
path: root/src/gui/kernel/qcocoaview_mac.mm
diff options
context:
space:
mode:
Diffstat (limited to 'src/gui/kernel/qcocoaview_mac.mm')
-rw-r--r--src/gui/kernel/qcocoaview_mac.mm224
1 files changed, 174 insertions, 50 deletions
diff --git a/src/gui/kernel/qcocoaview_mac.mm b/src/gui/kernel/qcocoaview_mac.mm
index 9eca29d..7693ca7 100644
--- a/src/gui/kernel/qcocoaview_mac.mm
+++ b/src/gui/kernel/qcocoaview_mac.mm
@@ -49,6 +49,8 @@
#include <private/qt_cocoa_helpers_mac_p.h>
#include <private/qdnd_p.h>
#include <private/qmacinputcontext_p.h>
+#include <private/qmultitouch_mac_p.h>
+#include <private/qevent_p.h>
#include <qscrollarea.h>
#include <qhash.h>
@@ -100,7 +102,7 @@ static dndenum_mapper dnd_enums[] = {
{ NSDragOperationCopy, Qt::CopyAction, true },
{ NSDragOperationGeneric, Qt::CopyAction, false },
{ NSDragOperationEvery, Qt::ActionMask, false },
- { NSDragOperationNone, Qt::IgnoreAction, false }
+ { NSDragOperationNone, Qt::IgnoreAction, false }
};
static NSDragOperation qt_mac_mapDropAction(Qt::DropAction action)
@@ -196,6 +198,7 @@ extern "C" {
if (self) {
[self finishInitWithQWidget:widget widgetPrivate:widgetprivate];
}
+ composingText = new QString();
composing = false;
sendKeyEvents = true;
currentCustomTypes = 0;
@@ -224,14 +227,14 @@ extern "C" {
currentCustomTypes = new QStringList();
*currentCustomTypes = customTypes;
const NSString* mimeTypeGeneric = @"com.trolltech.qt.MimeTypeName";
- NSMutableArray *supportedTypes = [NSMutableArray arrayWithObjects:NSColorPboardType,
- NSFilenamesPboardType, NSStringPboardType,
- NSFilenamesPboardType, NSPostScriptPboardType, NSTIFFPboardType,
- NSRTFPboardType, NSTabularTextPboardType, NSFontPboardType,
- NSRulerPboardType, NSFileContentsPboardType, NSColorPboardType,
- NSRTFDPboardType, NSHTMLPboardType, NSPICTPboardType,
+ NSMutableArray *supportedTypes = [NSMutableArray arrayWithObjects:NSColorPboardType,
+ NSFilenamesPboardType, NSStringPboardType,
+ NSFilenamesPboardType, NSPostScriptPboardType, NSTIFFPboardType,
+ NSRTFPboardType, NSTabularTextPboardType, NSFontPboardType,
+ NSRulerPboardType, NSFileContentsPboardType, NSColorPboardType,
+ NSRTFDPboardType, NSHTMLPboardType, NSPICTPboardType,
NSURLPboardType, NSPDFPboardType, NSVCardPboardType,
- NSFilesPromisePboardType, NSInkTextPboardType,
+ NSFilesPromisePboardType, NSInkTextPboardType,
NSMultipleTextSelectionPboardType, mimeTypeGeneric, nil];
// Add custom types supported by the application.
for (int i = 0; i < customTypes.size(); i++) {
@@ -276,16 +279,16 @@ extern "C" {
dropData = 0;
}
}
-
-- (void)addDropData:(id <NSDraggingInfo>)sender
+
+- (void)addDropData:(id <NSDraggingInfo>)sender
{
[self removeDropData];
- CFStringRef dropPasteboard = (CFStringRef) [[sender draggingPasteboard] name];
+ CFStringRef dropPasteboard = (CFStringRef) [[sender draggingPasteboard] name];
dropData = new QCocoaDropData(dropPasteboard);
-}
+}
-- (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender
-{
+- (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender
+{
if (qwidget->testAttribute(Qt::WA_DropSiteRegistered) == false)
return NSDragOperationNone;
NSPoint windowPoint = [sender draggingLocation];
@@ -303,7 +306,7 @@ extern "C" {
NSPoint globalPoint = [[sender draggingDestinationWindow] convertBaseToScreen:windowPoint];
NSPoint localPoint = [self convertPoint:windowPoint fromView:nil];
QPoint posDrag(localPoint.x, localPoint.y);
- NSDragOperation nsActions = [sender draggingSourceOperationMask];
+ NSDragOperation nsActions = [sender draggingSourceOperationMask];
Qt::DropActions qtAllowed = qt_mac_mapNSDragOperations(nsActions);
QT_PREPEND_NAMESPACE(qt_mac_dnd_answer_rec.lastOperation) = nsActions;
Qt::KeyboardModifiers modifiers = Qt::NoModifier;
@@ -332,8 +335,8 @@ extern "C" {
qDMEvent.accept(); // accept by default, since enter event was accepted.
QApplication::sendEvent(qwidget, &qDMEvent);
if (!qDMEvent.isAccepted() || qDMEvent.dropAction() == Qt::IgnoreAction) {
- // since we accepted the drag enter event, the widget expects
- // future drage move events.
+ // since we accepted the drag enter event, the widget expects
+ // future drage move events.
// ### check if we need to treat this like the drag enter event.
nsActions = QT_PREPEND_NAMESPACE(qt_mac_mapDropAction)(qDEEvent.dropAction());
} else {
@@ -341,7 +344,7 @@ extern "C" {
}
QT_PREPEND_NAMESPACE(qt_mac_copy_answer_rect)(qDMEvent);
return nsActions;
- }
+ }
}
- (NSDragOperation)draggingUpdated:(id < NSDraggingInfo >)sender
@@ -369,7 +372,7 @@ extern "C" {
if (qt_mac_mouse_inside_answer_rect(posDrag)
&& QT_PREPEND_NAMESPACE(qt_mac_dnd_answer_rec.lastOperation) == nsActions)
return QT_PREPEND_NAMESPACE(qt_mac_mapDropActions)(QT_PREPEND_NAMESPACE(qt_mac_dnd_answer_rec.lastAction));
- // send drag move event to the widget
+ // send drag move event to the widget
QT_PREPEND_NAMESPACE(qt_mac_dnd_answer_rec.lastOperation) = nsActions;
Qt::DropActions qtAllowed = QT_PREPEND_NAMESPACE(qt_mac_mapNSDragOperations)(nsActions);
Qt::KeyboardModifiers modifiers = Qt::NoModifier;
@@ -432,7 +435,7 @@ extern "C" {
NSPoint localPoint = [self convertPoint:windowPoint fromView:nil];
QPoint posDrop(localPoint.x, localPoint.y);
- NSDragOperation nsActions = [sender draggingSourceOperationMask];
+ NSDragOperation nsActions = [sender draggingSourceOperationMask];
Qt::DropActions qtAllowed = qt_mac_mapNSDragOperations(nsActions);
QMimeData *mimeData = dropData;
if (QDragManager::self()->source())
@@ -453,6 +456,7 @@ extern "C" {
- (void)dealloc
{
+ delete composingText;
[[NSNotificationCenter defaultCenter] removeObserver:self];
delete currentCustomTypes;
[self unregisterDraggedTypes];
@@ -547,15 +551,7 @@ extern "C" {
qwidget->objectName().local8Bit().data());
#endif
QPainter p(qwidget);
- QAbstractScrollArea *scrollArea = qobject_cast<QAbstractScrollArea *>(qwidget->parent());
- QPoint scrollAreaOffset;
- if (scrollArea && scrollArea->viewport() == qwidget) {
- QAbstractScrollAreaPrivate *priv
- = static_cast<QAbstractScrollAreaPrivate *>(qt_widget_private(scrollArea));
- scrollAreaOffset = priv->contentsOffset();
- p.translate(-scrollAreaOffset);
- }
- qwidgetprivate->paintBackground(&p, qrgn, scrollAreaOffset,
+ qwidgetprivate->paintBackground(&p, qrgn,
qwidget->isWindow() ? QWidgetPrivate::DrawAsRoot : 0);
p.end();
}
@@ -566,11 +562,6 @@ extern "C" {
qt_sendSpontaneousEvent(qwidget, &e);
if (!redirectionOffset.isNull())
QPainter::restoreRedirected(qwidget);
-#ifdef QT_RASTER_PAINTENGINE
- if(engine && engine->type() == QPaintEngine::Raster)
- static_cast<QRasterPaintEngine*>(engine)->flush(qwidget,
- qrgn.boundingRect().topLeft());
-#endif
if (engine)
engine->setSystemClip(QRegion());
qwidget->setAttribute(Qt::WA_WState_InPaintEvent, false);
@@ -641,7 +632,7 @@ extern "C" {
QHoverEvent he(QEvent::HoverEnter, QPoint(viewPoint.x, viewPoint.y), QPoint(-1, -1));
QApplicationPrivate::instance()->notify_helper(qwidget, &he);
}
- }
+ }
}
- (void)mouseExited:(NSEvent *)event
@@ -650,7 +641,7 @@ extern "C" {
NSPoint globalPoint = [[event window] convertBaseToScreen:[event locationInWindow]];
if (!qAppInstance()->activeModalWidget() || QApplicationPrivate::tryModalHelper(qwidget, 0)) {
QApplication::sendEvent(qwidget, &leaveEvent);
-
+
// ### Think about if it is necessary to update the cursor, should only be for a few cases.
qt_mac_update_cursor_at_global_pos(flipPoint(globalPoint).toPoint());
if (qwidget->testAttribute(Qt::WA_Hover)
@@ -675,14 +666,22 @@ extern "C" {
- (void)mouseMoved:(NSEvent *)theEvent
{
- qt_mac_handleMouseEvent(self, theEvent, QEvent::MouseMove, Qt::NoButton);
+ // We always enable mouse tracking for all QCocoaView-s. In cases where we have
+ // child views, we will receive mouseMoved for both parent & the child (if
+ // mouse is over the child). We need to ignore the parent mouseMoved in such
+ // cases.
+ NSPoint windowPoint = [theEvent locationInWindow];
+ NSView *candidateView = [[[self window] contentView] hitTest:windowPoint];
+ if (candidateView && candidateView == self) {
+ qt_mac_handleMouseEvent(self, theEvent, QEvent::MouseMove, Qt::NoButton);
+ }
}
- (void)mouseDown:(NSEvent *)theEvent
{
qt_mac_handleMouseEvent(self, theEvent, QEvent::MouseButtonPress, Qt::LeftButton);
// Don't call super here. This prevents us from getting the mouseUp event,
- // which we need to send even if the mouseDown event was not accepted.
+ // which we need to send even if the mouseDown event was not accepted.
// (this is standard Qt behavior.)
}
@@ -696,7 +695,7 @@ extern "C" {
}
- (void)rightMouseDown:(NSEvent *)theEvent
-{
+{
bool mouseOK = qt_mac_handleMouseEvent(self, theEvent, QEvent::MouseButtonPress, Qt::RightButton);
if (!mouseOK)
@@ -845,6 +844,102 @@ extern "C" {
[super tabletPoint:tabletEvent];
}
+#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
+- (void)touchesBeganWithEvent:(NSEvent *)event;
+{
+ bool all = qwidget->testAttribute(Qt::WA_TouchPadAcceptSingleTouchEvents);
+ qt_translateRawTouchEvent(qwidget, QTouchEvent::TouchPad, QCocoaTouch::getCurrentTouchPointList(event, all));
+}
+
+- (void)touchesMovedWithEvent:(NSEvent *)event;
+{
+ bool all = qwidget->testAttribute(Qt::WA_TouchPadAcceptSingleTouchEvents);
+ qt_translateRawTouchEvent(qwidget, QTouchEvent::TouchPad, QCocoaTouch::getCurrentTouchPointList(event, all));
+}
+
+- (void)touchesEndedWithEvent:(NSEvent *)event;
+{
+ bool all = qwidget->testAttribute(Qt::WA_TouchPadAcceptSingleTouchEvents);
+ qt_translateRawTouchEvent(qwidget, QTouchEvent::TouchPad, QCocoaTouch::getCurrentTouchPointList(event, all));
+}
+
+- (void)touchesCancelledWithEvent:(NSEvent *)event;
+{
+ bool all = qwidget->testAttribute(Qt::WA_TouchPadAcceptSingleTouchEvents);
+ qt_translateRawTouchEvent(qwidget, QTouchEvent::TouchPad, QCocoaTouch::getCurrentTouchPointList(event, all));
+}
+
+- (void)magnifyWithEvent:(NSEvent *)event;
+{
+ if (!QApplicationPrivate::tryModalHelper(qwidget, 0))
+ return;
+
+ QNativeGestureEvent qNGEvent;
+ qNGEvent.gestureType = QNativeGestureEvent::Zoom;
+ NSPoint p = [[event window] convertBaseToScreen:[event locationInWindow]];
+ qNGEvent.position = flipPoint(p).toPoint();
+ qNGEvent.percentage = [event magnification];
+ qt_sendSpontaneousEvent(qwidget, &qNGEvent);
+}
+
+- (void)rotateWithEvent:(NSEvent *)event;
+{
+ if (!QApplicationPrivate::tryModalHelper(qwidget, 0))
+ return;
+
+ QNativeGestureEvent qNGEvent;
+ qNGEvent.gestureType = QNativeGestureEvent::Rotate;
+ NSPoint p = [[event window] convertBaseToScreen:[event locationInWindow]];
+ qNGEvent.position = flipPoint(p).toPoint();
+ qNGEvent.percentage = -[event rotation];
+ qt_sendSpontaneousEvent(qwidget, &qNGEvent);
+}
+
+- (void)swipeWithEvent:(NSEvent *)event;
+{
+ if (!QApplicationPrivate::tryModalHelper(qwidget, 0))
+ return;
+
+ QNativeGestureEvent qNGEvent;
+ qNGEvent.gestureType = QNativeGestureEvent::Swipe;
+ NSPoint p = [[event window] convertBaseToScreen:[event locationInWindow]];
+ qNGEvent.position = flipPoint(p).toPoint();
+ if ([event deltaX] == 1)
+ qNGEvent.angle = 180.0f;
+ else if ([event deltaX] == -1)
+ qNGEvent.angle = 0.0f;
+ else if ([event deltaY] == 1)
+ qNGEvent.angle = 90.0f;
+ else if ([event deltaY] == -1)
+ qNGEvent.angle = 270.0f;
+ qt_sendSpontaneousEvent(qwidget, &qNGEvent);
+}
+
+- (void)beginGestureWithEvent:(NSEvent *)event;
+{
+ if (!QApplicationPrivate::tryModalHelper(qwidget, 0))
+ return;
+
+ QNativeGestureEvent qNGEvent;
+ qNGEvent.gestureType = QNativeGestureEvent::GestureBegin;
+ NSPoint p = [[event window] convertBaseToScreen:[event locationInWindow]];
+ qNGEvent.position = flipPoint(p).toPoint();
+ qt_sendSpontaneousEvent(qwidget, &qNGEvent);
+}
+
+- (void)endGestureWithEvent:(NSEvent *)event;
+{
+ if (!QApplicationPrivate::tryModalHelper(qwidget, 0))
+ return;
+
+ QNativeGestureEvent qNGEvent;
+ qNGEvent.gestureType = QNativeGestureEvent::GestureEnd;
+ NSPoint p = [[event window] convertBaseToScreen:[event locationInWindow]];
+ qNGEvent.position = flipPoint(p).toPoint();
+ qt_sendSpontaneousEvent(qwidget, &qNGEvent);
+}
+#endif // MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
+
- (void)frameDidChange:(NSNotification *)note
{
Q_UNUSED(note);
@@ -887,6 +982,15 @@ extern "C" {
return qwidget->focusPolicy() != Qt::NoFocus;
}
+- (BOOL)resignFirstResponder
+{
+ // Seems like the following test only triggers if this
+ // view is inside a QMacNativeWidget:
+ if (qwidget == QApplication::focusWidget())
+ QApplicationPrivate::setFocusWidget(0, Qt::OtherFocusReason);
+ return YES;
+}
+
- (NSDragOperation)draggingSourceOperationMaskForLocal:(BOOL)isLocal
{
Q_UNUSED(isLocal);
@@ -988,20 +1092,31 @@ extern "C" {
- (void) insertText:(id)aString
{
- if (composing) {
- // Send the commit string to the widget.
- QString commitText;
+ QString commitText;
+ if ([aString length]) {
if ([aString isKindOfClass:[NSAttributedString class]]) {
- commitText = QCFString::toQString(reinterpret_cast<CFStringRef>([aString string]));
+ commitText = QCFString::toQString(reinterpret_cast<CFStringRef>([aString string]));
} else {
commitText = QCFString::toQString(reinterpret_cast<CFStringRef>(aString));
};
+ }
+
+ if ([aString length] && composing) {
+ // Send the commit string to the widget.
composing = false;
sendKeyEvents = false;
QInputMethodEvent e;
e.setCommitString(commitText);
qt_sendSpontaneousEvent(qwidget, &e);
+ } else {
+ // The key sequence "`q" on a French Keyboard will generate two calls to insertText before
+ // it returns from interpretKeyEvents. The first call will turn off 'composing' and accept
+ // the "`" key. The last keyDown event needs to be processed by the widget to get the
+ // character "q". The string parameter is ignored for the second call.
+ sendKeyEvents = true;
}
+
+ composingText->clear();
}
- (void) setMarkedText:(id)aString selectedRange:(NSRange)selRange
@@ -1023,7 +1138,7 @@ extern "C" {
while (index < composingLength) {
NSRange effectiveRange;
NSRange range = NSMakeRange(index, composingLength-index);
- NSDictionary *attributes = [aString attributesAtIndex:index
+ NSDictionary *attributes = [aString attributesAtIndex:index
longestEffectiveRange:&effectiveRange
inRange:range];
NSNumber *underlineStyle = [attributes objectForKey:NSUnderlineStyleAttributeName];
@@ -1032,7 +1147,7 @@ extern "C" {
NSColor *color = [attributes objectForKey:NSUnderlineColorAttributeName];
if (color) {
clr = colorFrom(color);
- }
+ }
QTextCharFormat format;
format.setFontUnderline(true);
format.setUnderlineColor(clr);
@@ -1055,12 +1170,21 @@ extern "C" {
attrs<<QInputMethodEvent::Attribute(QInputMethodEvent::TextFormat,
0, composingLength, format);
}
+ *composingText = qtText;
QInputMethodEvent e(qtText, attrs);
qt_sendSpontaneousEvent(qwidget, &e);
+ if (!composingLength)
+ composing = false;
}
- (void) unmarkText
{
+ if (composing) {
+ QInputMethodEvent e;
+ e.setCommitString(*composingText);
+ qt_sendSpontaneousEvent(qwidget, &e);
+ }
+ composingText->clear();
composing = false;
}
@@ -1099,7 +1223,7 @@ extern "C" {
- (NSRange) markedRange
{
- NSRange range;
+ NSRange range;
if (composing) {
range.location = 0;
range.length = composingLength;
@@ -1124,13 +1248,13 @@ extern "C" {
selRange.length = 0;
}
return selRange;
-
+
}
- (NSRect) firstRectForCharacterRange:(NSRange)theRange
{
Q_UNUSED(theRange);
- // The returned rect is always based on the internal cursor.
+ // The returned rect is always based on the internal cursor.
QRect mr(qwidget->inputMethodQuery(Qt::ImMicroFocus).toRect());
QPoint mp(qwidget->mapToGlobal(QPoint(mr.bottomLeft())));
NSRect rect ;
@@ -1278,7 +1402,7 @@ Qt::DropAction QDragManager::drag(QDrag *o)
NSImage *image = (NSImage *)qt_mac_create_nsimage(pix);
[image retain];
DnDParams *dndParams = [QT_MANGLE_NAMESPACE(QCocoaView) currentMouseEvent];
- // save supported actions
+ // save supported actions
[dndParams->view setSupportedActions: qt_mac_mapDropActions(dragPrivate()->possible_actions)];
NSPoint imageLoc = {dndParams->localPoint.x - hotspot.x(),
dndParams->localPoint.y + pix.height() - hotspot.y()};
@@ -1302,7 +1426,7 @@ Qt::DropAction QDragManager::drag(QDrag *o)
Qt::DropAction performedAction(qt_mac_mapNSDragOperation(dndParams->performedAction));
// do post drag processing, if required.
if(performedAction != Qt::IgnoreAction) {
- // check if the receiver points us to a file location.
+ // check if the receiver points us to a file location.
// if so, we need to do the file copy/move ourselves.
QCFType<CFURLRef> pasteLocation = 0;
PasteboardCopyPasteLocation(dragBoard.pasteBoard(), &pasteLocation);