Cocoa: Improve cursor setting.
Implement cursor setting in terms of [NSCursor set] and [NSView cursorUpdate] using the window tracking area. Refactor cursor conversion into QCocoaCursor:: convertCursor. Rename QCoocaWindow::m_underMouseWindow to m_enterLeaveTargetWindow since it's set according to spesific enter/leave logic. Add m_windowUnderMouse which tracks mouseEntered/mouseExited state. Task-number: QTBUG-33961 Change-Id: Id5e12594f5db365e09c9926a4c08d748a9afb935 Reviewed-by: Gabriel de Dietrich <gabriel.dedietrich@digia.com>
This commit is contained in:
parent
d0f8ba748e
commit
d1114669e3
@ -55,12 +55,13 @@ public:
|
||||
QCocoaCursor();
|
||||
~QCocoaCursor();
|
||||
|
||||
virtual void changeCursor(QCursor * widgetCursor, QWindow * widget);
|
||||
virtual void changeCursor(QCursor *cursor, QWindow *window);
|
||||
virtual QPoint pos() const;
|
||||
virtual void setPos(const QPoint &position);
|
||||
private:
|
||||
QHash<Qt::CursorShape, NSCursor *> m_cursors;
|
||||
NSCursor *createCursorData(QCursor *);
|
||||
NSCursor *convertCursor(QCursor *cursor);
|
||||
NSCursor *createCursorData(QCursor * cursor);
|
||||
NSCursor *createCursorFromBitmap(const QBitmap *bitmap, const QBitmap *mask, const QPoint hotspot = QPoint());
|
||||
NSCursor *createCursorFromPixmap(const QPixmap pixmap, const QPoint hotspot = QPoint());
|
||||
};
|
||||
|
@ -40,6 +40,7 @@
|
||||
****************************************************************************/
|
||||
|
||||
#include "qcocoacursor.h"
|
||||
#include "qcocoawindow.h"
|
||||
#include "qcocoahelpers.h"
|
||||
#include "qcocoaautoreleasepool.h"
|
||||
|
||||
@ -63,65 +64,10 @@ QCocoaCursor::~QCocoaCursor()
|
||||
|
||||
void QCocoaCursor::changeCursor(QCursor *cursor, QWindow *window)
|
||||
{
|
||||
Q_UNUSED(window);
|
||||
NSCursor * cocoaCursor = convertCursor(cursor);
|
||||
|
||||
const Qt::CursorShape newShape = cursor ? cursor->shape() : Qt::ArrowCursor;
|
||||
// Check for a suitable built-in NSCursor first:
|
||||
switch (newShape) {
|
||||
case Qt::ArrowCursor:
|
||||
[[NSCursor arrowCursor] set];
|
||||
break;
|
||||
case Qt::CrossCursor:
|
||||
[[NSCursor crosshairCursor] set];
|
||||
break;
|
||||
case Qt::IBeamCursor:
|
||||
[[NSCursor IBeamCursor] set];
|
||||
break;
|
||||
case Qt::WhatsThisCursor: //for now just use the pointing hand
|
||||
case Qt::PointingHandCursor:
|
||||
[[NSCursor pointingHandCursor] set];
|
||||
break;
|
||||
case Qt::SplitVCursor:
|
||||
[[NSCursor resizeUpDownCursor] set];
|
||||
break;
|
||||
case Qt::SplitHCursor:
|
||||
[[NSCursor resizeLeftRightCursor] set];
|
||||
break;
|
||||
case Qt::OpenHandCursor:
|
||||
[[NSCursor openHandCursor] set];
|
||||
break;
|
||||
case Qt::ClosedHandCursor:
|
||||
[[NSCursor closedHandCursor] set];
|
||||
break;
|
||||
case Qt::DragMoveCursor:
|
||||
[[NSCursor crosshairCursor] set];
|
||||
break;
|
||||
case Qt::DragCopyCursor:
|
||||
[[NSCursor crosshairCursor] set];
|
||||
break;
|
||||
case Qt::DragLinkCursor:
|
||||
[[NSCursor dragLinkCursor] set];
|
||||
break;
|
||||
default : {
|
||||
// No suitable OS cursor exist, use cursors provided
|
||||
// by Qt for the rest. Check for a cached cursor:
|
||||
NSCursor *cocoaCursor = m_cursors.value(newShape);
|
||||
if (cocoaCursor && cursor->shape() == Qt::BitmapCursor) {
|
||||
[cocoaCursor release];
|
||||
cocoaCursor = 0;
|
||||
}
|
||||
if (cocoaCursor == 0) {
|
||||
cocoaCursor = createCursorData(cursor);
|
||||
if (cocoaCursor == 0) {
|
||||
[[NSCursor arrowCursor] set];
|
||||
return;
|
||||
}
|
||||
m_cursors.insert(newShape, cocoaCursor);
|
||||
}
|
||||
|
||||
[cocoaCursor set];
|
||||
break; }
|
||||
}
|
||||
if (QPlatformWindow * platformWindow = window->handle())
|
||||
static_cast<QCocoaWindow *>(platformWindow)->setWindowCursor(cocoaCursor);
|
||||
}
|
||||
|
||||
QPoint QCocoaCursor::pos() const
|
||||
@ -140,6 +86,69 @@ void QCocoaCursor::setPos(const QPoint &position)
|
||||
CFRelease(e);
|
||||
}
|
||||
|
||||
NSCursor *QCocoaCursor::convertCursor(QCursor * cursor)
|
||||
{
|
||||
const Qt::CursorShape newShape = cursor ? cursor->shape() : Qt::ArrowCursor;
|
||||
NSCursor *cocoaCursor;
|
||||
|
||||
// Check for a suitable built-in NSCursor first:
|
||||
switch (newShape) {
|
||||
case Qt::ArrowCursor:
|
||||
cocoaCursor= [NSCursor arrowCursor];
|
||||
break;
|
||||
case Qt::CrossCursor:
|
||||
cocoaCursor = [NSCursor crosshairCursor];
|
||||
break;
|
||||
case Qt::IBeamCursor:
|
||||
cocoaCursor = [NSCursor IBeamCursor];
|
||||
break;
|
||||
case Qt::WhatsThisCursor: //for now just use the pointing hand
|
||||
case Qt::PointingHandCursor:
|
||||
cocoaCursor = [NSCursor pointingHandCursor];
|
||||
break;
|
||||
case Qt::SplitVCursor:
|
||||
cocoaCursor = [NSCursor resizeUpDownCursor];
|
||||
break;
|
||||
case Qt::SplitHCursor:
|
||||
cocoaCursor = [NSCursor resizeLeftRightCursor];
|
||||
break;
|
||||
case Qt::OpenHandCursor:
|
||||
cocoaCursor = [NSCursor openHandCursor];
|
||||
break;
|
||||
case Qt::ClosedHandCursor:
|
||||
cocoaCursor = [NSCursor closedHandCursor];
|
||||
break;
|
||||
case Qt::DragMoveCursor:
|
||||
cocoaCursor = [NSCursor crosshairCursor];
|
||||
break;
|
||||
case Qt::DragCopyCursor:
|
||||
cocoaCursor = [NSCursor crosshairCursor];
|
||||
break;
|
||||
case Qt::DragLinkCursor:
|
||||
cocoaCursor = [NSCursor dragLinkCursor];
|
||||
break;
|
||||
default : {
|
||||
// No suitable OS cursor exist, use cursors provided
|
||||
// by Qt for the rest. Check for a cached cursor:
|
||||
cocoaCursor = m_cursors.value(newShape);
|
||||
if (cocoaCursor && cursor->shape() == Qt::BitmapCursor) {
|
||||
[cocoaCursor release];
|
||||
cocoaCursor = 0;
|
||||
}
|
||||
if (cocoaCursor == 0) {
|
||||
cocoaCursor = createCursorData(cursor);
|
||||
if (cocoaCursor == 0)
|
||||
return [NSCursor arrowCursor];
|
||||
|
||||
m_cursors.insert(newShape, cocoaCursor);
|
||||
}
|
||||
|
||||
break; }
|
||||
}
|
||||
return cocoaCursor;
|
||||
}
|
||||
|
||||
|
||||
// Creates an NSCursor for the given QCursor.
|
||||
NSCursor *QCocoaCursor::createCursorData(QCursor *cursor)
|
||||
{
|
||||
|
@ -154,6 +154,8 @@ public:
|
||||
void setMenubar(QCocoaMenuBar *mb);
|
||||
QCocoaMenuBar *menubar() const;
|
||||
|
||||
void setWindowCursor(NSCursor *cursor);
|
||||
|
||||
void registerTouch(bool enable);
|
||||
|
||||
qreal devicePixelRatio() const;
|
||||
@ -190,11 +192,13 @@ public: // for QNSView
|
||||
Qt::WindowState m_synchedWindowState;
|
||||
Qt::WindowModality m_windowModality;
|
||||
QPointer<QWindow> m_activePopupWindow;
|
||||
QPointer<QWindow> m_underMouseWindow;
|
||||
QPointer<QWindow> m_enterLeaveTargetWindow;
|
||||
bool m_windowUnderMouse;
|
||||
|
||||
bool m_inConstructor;
|
||||
QCocoaGLContext *m_glContext;
|
||||
QCocoaMenuBar *m_menubar;
|
||||
NSCursor *m_windowCursor;
|
||||
|
||||
bool m_hasModalSession;
|
||||
bool m_frameStrutEventsEnabled;
|
||||
|
@ -206,9 +206,11 @@ QCocoaWindow::QCocoaWindow(QWindow *tlw)
|
||||
, m_nsWindowDelegate(0)
|
||||
, m_synchedWindowState(Qt::WindowActive)
|
||||
, m_windowModality(Qt::NonModal)
|
||||
, m_windowUnderMouse(false)
|
||||
, m_inConstructor(true)
|
||||
, m_glContext(0)
|
||||
, m_menubar(0)
|
||||
, m_windowCursor(0)
|
||||
, m_hasModalSession(false)
|
||||
, m_frameStrutEventsEnabled(false)
|
||||
, m_isExposed(false)
|
||||
@ -1030,6 +1032,23 @@ QCocoaMenuBar *QCocoaWindow::menubar() const
|
||||
return m_menubar;
|
||||
}
|
||||
|
||||
void QCocoaWindow::setWindowCursor(NSCursor *cursor)
|
||||
{
|
||||
// This function is called (via QCocoaCursor) by Qt to set
|
||||
// the cursor for this window. It can be called for a window
|
||||
// that is not currenly under the mouse pointer (for example
|
||||
// for a popup window.) Qt expects the set cursor to "stick":
|
||||
// it should be accociated with the window until a different
|
||||
// cursor is set.
|
||||
|
||||
// Cocoa has different abstractions. We can set the cursor *now*:
|
||||
if (m_windowUnderMouse)
|
||||
[cursor set];
|
||||
// or we can set the cursor on mouse enter/leave using tracking
|
||||
// areas. This is done in QNSView, save the cursor:
|
||||
m_windowCursor = cursor;
|
||||
}
|
||||
|
||||
void QCocoaWindow::registerTouch(bool enable)
|
||||
{
|
||||
m_registerTouchCount += enable ? 1 : -1;
|
||||
|
@ -671,7 +671,7 @@ static QTouchDevice *touchDevice = 0;
|
||||
// mouse moves delivered to it (Apple recommends keeping it OFF because there
|
||||
// is a performance hit). So it goes.
|
||||
NSUInteger trackingOptions = NSTrackingMouseEnteredAndExited | NSTrackingActiveInActiveApp
|
||||
| NSTrackingInVisibleRect | NSTrackingMouseMoved;
|
||||
| NSTrackingInVisibleRect | NSTrackingMouseMoved | NSTrackingCursorUpdate;
|
||||
NSTrackingArea *ta = [[[NSTrackingArea alloc] initWithRect:[self frame]
|
||||
options:trackingOptions
|
||||
owner:self
|
||||
@ -680,6 +680,13 @@ static QTouchDevice *touchDevice = 0;
|
||||
[self addTrackingArea:ta];
|
||||
}
|
||||
|
||||
-(void)cursorUpdate:(NSEvent *)theEvent
|
||||
{
|
||||
Q_UNUSED(theEvent)
|
||||
if (m_platformWindow->m_windowCursor)
|
||||
[m_platformWindow->m_windowCursor set];
|
||||
}
|
||||
|
||||
- (void)mouseMoved:(NSEvent *)theEvent
|
||||
{
|
||||
if (m_window->flags() & Qt::WindowTransparentForInput)
|
||||
@ -696,9 +703,9 @@ static QTouchDevice *touchDevice = 0;
|
||||
// handling mouseEnter and mouseLeave envents, since they are sent
|
||||
// individually to different views.
|
||||
if (m_platformWindow->m_nsWindow && childWindow) {
|
||||
if (childWindow != m_platformWindow->m_underMouseWindow) {
|
||||
QWindowSystemInterface::handleEnterLeaveEvent(childWindow, m_platformWindow->m_underMouseWindow, windowPoint, screenPoint);
|
||||
m_platformWindow->m_underMouseWindow = childWindow;
|
||||
if (childWindow != m_platformWindow->m_enterLeaveTargetWindow) {
|
||||
QWindowSystemInterface::handleEnterLeaveEvent(childWindow, m_platformWindow->m_enterLeaveTargetWindow, windowPoint, screenPoint);
|
||||
m_platformWindow->m_enterLeaveTargetWindow = childWindow;
|
||||
}
|
||||
}
|
||||
|
||||
@ -712,6 +719,8 @@ static QTouchDevice *touchDevice = 0;
|
||||
|
||||
- (void)mouseEntered:(NSEvent *)theEvent
|
||||
{
|
||||
m_platformWindow->m_windowUnderMouse = true;
|
||||
|
||||
if (m_window->flags() & Qt::WindowTransparentForInput)
|
||||
return [super mouseEntered:theEvent];
|
||||
|
||||
@ -722,12 +731,14 @@ static QTouchDevice *touchDevice = 0;
|
||||
QPointF windowPoint;
|
||||
QPointF screenPoint;
|
||||
[self convertFromScreen:[NSEvent mouseLocation] toWindowPoint:&windowPoint andScreenPoint:&screenPoint];
|
||||
m_platformWindow->m_underMouseWindow = m_platformWindow->childWindowAt(windowPoint.toPoint());
|
||||
QWindowSystemInterface::handleEnterEvent(m_platformWindow->m_underMouseWindow, windowPoint, screenPoint);
|
||||
m_platformWindow->m_enterLeaveTargetWindow = m_platformWindow->childWindowAt(windowPoint.toPoint());
|
||||
QWindowSystemInterface::handleEnterEvent(m_platformWindow->m_enterLeaveTargetWindow, windowPoint, screenPoint);
|
||||
}
|
||||
|
||||
- (void)mouseExited:(NSEvent *)theEvent
|
||||
{
|
||||
m_platformWindow->m_windowUnderMouse = false;
|
||||
|
||||
if (m_window->flags() & Qt::WindowTransparentForInput)
|
||||
return [super mouseExited:theEvent];
|
||||
Q_UNUSED(theEvent);
|
||||
@ -736,8 +747,8 @@ static QTouchDevice *touchDevice = 0;
|
||||
if (!m_platformWindow->m_nsWindow)
|
||||
return;
|
||||
|
||||
QWindowSystemInterface::handleLeaveEvent(m_platformWindow->m_underMouseWindow);
|
||||
m_platformWindow->m_underMouseWindow = 0;
|
||||
QWindowSystemInterface::handleLeaveEvent(m_platformWindow->m_enterLeaveTargetWindow);
|
||||
m_platformWindow->m_enterLeaveTargetWindow = 0;
|
||||
}
|
||||
|
||||
- (void)rightMouseDown:(NSEvent *)theEvent
|
||||
|
Loading…
x
Reference in New Issue
Block a user