Move the tooltip out of the way of very large mouse cursors
Users that have large mouse pointers configured in their settings can not see tooltips, as they are obscured by the pointer. Native applications on Windows and macOS have the same problem, which includes the tooltips for the minimize/maximize/close controls in the window frame of e.g. Explorer. Introduce QPlatformCursor::size that returns a value that is based on the user's settings, or a default value. We can then use that value to move the tooltip out of the way. On Windows, the calculation of the cursor size is based on experimenting with the settings, which are in logical independent pixels. The placement of the tooltip attempts to keep existing behavior, and to not end up with a tooltip that's very far away from the tip of the arrow even for very large mouse cursors. [ChangeLog][QtWidgets][QToolTip] Make sure that the tooltip is not obscured by very large mouse pointers on Windows and macOS. Change-Id: I8e13b7a166bfe8b59cef4765c950f90fefeaef9d Fixes: QTBUG-79627 Reviewed-by: Friedemann Kleint <Friedemann.Kleint@qt.io> Reviewed-by: Morten Johan Sørvig <morten.sorvig@qt.io>bb10
parent
5272c35073
commit
baed8534bc
|
|
@ -131,6 +131,14 @@ void QPlatformCursor::setPos(const QPoint &pos)
|
|||
QWindowSystemInterface::handleMouseEvent(0, pos, pos, Qt::NoButton, Qt::NoButton, QEvent::MouseMove);
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the size of the cursor, in native pixels.
|
||||
*/
|
||||
QSize QPlatformCursor::size() const
|
||||
{
|
||||
return QSize(16, 16);
|
||||
}
|
||||
|
||||
// End of display and pointer event handling code
|
||||
// Beginning of built-in cursor graphics
|
||||
// from src/gui/embedded/QGraphicsSystemCursorImage_qws.cpp
|
||||
|
|
|
|||
|
|
@ -96,6 +96,7 @@ public:
|
|||
#endif // QT_NO_CURSOR
|
||||
virtual QPoint pos() const;
|
||||
virtual void setPos(const QPoint &pos);
|
||||
virtual QSize size() const;
|
||||
|
||||
static Capabilities capabilities() { return m_capabilities; }
|
||||
static void setCapabilities(Capabilities c) { m_capabilities = c; }
|
||||
|
|
|
|||
|
|
@ -56,6 +56,9 @@ public:
|
|||
void changeCursor(QCursor *cursor, QWindow *window) override;
|
||||
QPoint pos() const override;
|
||||
void setPos(const QPoint &position) override;
|
||||
|
||||
QSize size() const override;
|
||||
|
||||
private:
|
||||
QHash<Qt::CursorShape, NSCursor *> m_cursors;
|
||||
NSCursor *convertCursor(QCursor *cursor);
|
||||
|
|
|
|||
|
|
@ -85,6 +85,31 @@ void QCocoaCursor::setPos(const QPoint &position)
|
|||
CFRelease(e);
|
||||
}
|
||||
|
||||
|
||||
QSize QCocoaCursor::size() const
|
||||
{
|
||||
NSCursor *cocoaCursor = NSCursor.currentSystemCursor;
|
||||
if (!cocoaCursor)
|
||||
return QPlatformCursor::size();
|
||||
NSImage *cursorImage = cocoaCursor.image;
|
||||
if (!cursorImage)
|
||||
return QPlatformCursor::size();
|
||||
|
||||
QSizeF size = QSizeF::fromCGSize(cursorImage.size);
|
||||
NSUserDefaults *defaults = NSUserDefaults.standardUserDefaults;
|
||||
NSDictionary *accessSettings = [defaults persistentDomainForName:@"com.apple.universalaccess"];
|
||||
if (accessSettings == nil)
|
||||
return size.toSize();
|
||||
|
||||
float sizeScale = [accessSettings[@"mouseDriverCursorSize"] floatValue];
|
||||
if (sizeScale > 0) {
|
||||
size.rwidth() *= sizeScale;
|
||||
size.rheight() *= sizeScale;
|
||||
}
|
||||
|
||||
return size.toSize();
|
||||
}
|
||||
|
||||
NSCursor *QCocoaCursor::convertCursor(QCursor *cursor)
|
||||
{
|
||||
if (!cursor)
|
||||
|
|
|
|||
|
|
@ -50,6 +50,7 @@
|
|||
#include <QtGui/qscreen.h>
|
||||
#include <QtGui/private/qguiapplication_p.h> // getPixmapCursor()
|
||||
#include <QtGui/private/qhighdpiscaling_p.h>
|
||||
#include <QtCore/private/qwinregistry_p.h>
|
||||
|
||||
#include <QtCore/qdebug.h>
|
||||
#include <QtCore/qscopedpointer.h>
|
||||
|
|
@ -686,6 +687,30 @@ void QWindowsCursor::setPos(const QPoint &pos)
|
|||
SetCursorPos(pos.x() , pos.y());
|
||||
}
|
||||
|
||||
/*
|
||||
The standard size is 32x32, even though the cursor is actually just
|
||||
16 pixels large. If a large cursor is set in the accessibility settings,
|
||||
then the cursor increases with 8 pixels for each step.
|
||||
*/
|
||||
QSize QWindowsCursor::size() const
|
||||
{
|
||||
const QPair<DWORD,bool> cursorSizeSetting =
|
||||
QWinRegistryKey(HKEY_CURRENT_USER, LR"(Control Panel\Cursors)")
|
||||
.dwordValue(L"CursorBaseSize");
|
||||
const int baseSize = screenCursorSize(m_screen).width() / 2;
|
||||
if (!cursorSizeSetting.second)
|
||||
return QSize(baseSize / 2, baseSize / 2);
|
||||
|
||||
// The registry values are dpi-independent, so we need to scale the result.
|
||||
int cursorSizeValue = cursorSizeSetting.first * m_screen->logicalDpi().first
|
||||
/ m_screen->logicalBaseDpi().first;
|
||||
|
||||
// map from registry value 32-256 to 0-14, and from there to pixels
|
||||
cursorSizeValue = (cursorSizeValue - 2 * baseSize) / baseSize;
|
||||
const int cursorSize = baseSize + cursorSizeValue * (baseSize / 2);
|
||||
return QSize(cursorSize, cursorSize);
|
||||
}
|
||||
|
||||
QPixmap QWindowsCursor::dragDefaultCursor(Qt::DropAction action) const
|
||||
{
|
||||
switch (action) {
|
||||
|
|
|
|||
|
|
@ -113,6 +113,8 @@ public:
|
|||
QPoint pos() const override;
|
||||
void setPos(const QPoint &pos) override;
|
||||
|
||||
QSize size() const override;
|
||||
|
||||
static HCURSOR createPixmapCursor(QPixmap pixmap, const QPoint &hotSpot, qreal scaleFactor = 1);
|
||||
static HCURSOR createPixmapCursor(const PixmapCursor &pc, qreal scaleFactor = 1) { return createPixmapCursor(pc.pixmap, pc.hotSpot, scaleFactor); }
|
||||
static PixmapCursor customCursor(Qt::CursorShape cursorShape, const QPlatformScreen *screen = nullptr);
|
||||
|
|
|
|||
|
|
@ -53,11 +53,14 @@
|
|||
#endif
|
||||
#include <qtextdocument.h>
|
||||
#include <qdebug.h>
|
||||
#include <qpa/qplatformscreen.h>
|
||||
#include <qpa/qplatformcursor.h>
|
||||
#include <private/qstylesheetstyle_p.h>
|
||||
|
||||
#ifndef QT_NO_TOOLTIP
|
||||
#include <qlabel.h>
|
||||
#include <QtWidgets/private/qlabel_p.h>
|
||||
#include <QtGui/private/qhighdpiscaling_p.h>
|
||||
#include <qtooltip.h>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
|
@ -398,24 +401,34 @@ void QTipLabel::placeTip(const QPoint &pos, QWidget *w)
|
|||
}
|
||||
#endif //QT_NO_STYLE_STYLESHEET
|
||||
|
||||
|
||||
QRect screen = QDesktopWidgetPrivate::screenGeometry(getTipScreen(pos, w));
|
||||
|
||||
QPoint p = pos;
|
||||
p += QPoint(2, 16);
|
||||
int screenNumber = getTipScreen(pos, w);
|
||||
QScreen *screen = QGuiApplication::screens().at(screenNumber);
|
||||
if (screen) {
|
||||
const QPlatformScreen *platformScreen = screen->handle();
|
||||
const QSize cursorSize = QHighDpi::fromNativePixels(platformScreen->cursor()->size(),
|
||||
platformScreen);
|
||||
QPoint offset(2, cursorSize.height());
|
||||
// assuming an arrow shape, we can just move to the side for very large cursors
|
||||
if (cursorSize.height() > 2 * this->height())
|
||||
offset = QPoint(cursorSize.width() / 2, 0);
|
||||
|
||||
if (p.x() + this->width() > screen.x() + screen.width())
|
||||
p += offset;
|
||||
|
||||
QRect screenRect = screen->geometry();
|
||||
if (p.x() + this->width() > screenRect.x() + screenRect.width())
|
||||
p.rx() -= 4 + this->width();
|
||||
if (p.y() + this->height() > screen.y() + screen.height())
|
||||
if (p.y() + this->height() > screenRect.y() + screenRect.height())
|
||||
p.ry() -= 24 + this->height();
|
||||
if (p.y() < screen.y())
|
||||
p.setY(screen.y());
|
||||
if (p.x() + this->width() > screen.x() + screen.width())
|
||||
p.setX(screen.x() + screen.width() - this->width());
|
||||
if (p.x() < screen.x())
|
||||
p.setX(screen.x());
|
||||
if (p.y() + this->height() > screen.y() + screen.height())
|
||||
p.setY(screen.y() + screen.height() - this->height());
|
||||
if (p.y() < screenRect.y())
|
||||
p.setY(screenRect.y());
|
||||
if (p.x() + this->width() > screenRect.x() + screenRect.width())
|
||||
p.setX(screenRect.x() + screenRect.width() - this->width());
|
||||
if (p.x() < screenRect.x())
|
||||
p.setX(screenRect.x());
|
||||
if (p.y() + this->height() > screenRect.y() + screenRect.height())
|
||||
p.setY(screenRect.y() + screenRect.height() - this->height());
|
||||
}
|
||||
this->move(p);
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue