fix move and resize determination
This commit is contained in:
parent
1aed38e882
commit
96f49ded2f
|
@ -21,7 +21,7 @@ FLWindow::~FLWindow()
|
|||
void FLWindow::initFramelessWindow()
|
||||
{
|
||||
FramelessHelper* helper = new FramelessHelper(windowHandle());
|
||||
helper->setResizeBorderThickness(8);
|
||||
helper->setResizeBorderThickness(4);
|
||||
helper->setTitleBarHeight(40);
|
||||
helper->setResizable(true);
|
||||
helper->install();
|
||||
|
|
|
@ -37,6 +37,8 @@ FRAMELESSHELPER_BEGIN_NAMESPACE
|
|||
FramelessHelper::FramelessHelper(QWindow *window)
|
||||
: QObject(window)
|
||||
, m_window(window)
|
||||
, m_hoveredFrameSection(Qt::NoSection)
|
||||
, m_clickedFrameSection(Qt::NoSection)
|
||||
{
|
||||
Q_ASSERT(window != nullptr && window->isTopLevel());
|
||||
}
|
||||
|
@ -89,6 +91,14 @@ QRect FramelessHelper::titleBarRect()
|
|||
return QRect(0, 0, windowSize().width(), titleBarHeight());
|
||||
}
|
||||
|
||||
|
||||
QRegion FramelessHelper::titleBarRegion()
|
||||
{
|
||||
// TODO: consider HitTestVisibleObject
|
||||
QRegion region(titleBarRect());
|
||||
return region;
|
||||
}
|
||||
|
||||
QRect FramelessHelper::clientRect()
|
||||
{
|
||||
QRect rect(0, 0, windowSize().width(), windowSize().height());
|
||||
|
@ -101,6 +111,7 @@ QRect FramelessHelper::clientRect()
|
|||
|
||||
QRegion FramelessHelper::nonClientRegion()
|
||||
{
|
||||
// TODO: consider HitTestVisibleObject
|
||||
QRegion region(QRect(QPoint(0, 0), windowSize()));
|
||||
region -= clientRect();
|
||||
return region;
|
||||
|
@ -108,7 +119,7 @@ QRegion FramelessHelper::nonClientRegion()
|
|||
|
||||
bool FramelessHelper::isInTitlebarArea(const QPoint& pos)
|
||||
{
|
||||
return nonClientRegion().contains(pos);
|
||||
return titleBarRegion().contains(pos);
|
||||
}
|
||||
|
||||
Qt::WindowFrameSection FramelessHelper::mapPosToFrameSection(const QPoint& pos)
|
||||
|
@ -173,6 +184,18 @@ bool FramelessHelper::isHoverResizeHandler()
|
|||
m_hoveredFrameSection == Qt::BottomRightSection;
|
||||
}
|
||||
|
||||
bool FramelessHelper::isClickResizeHandler()
|
||||
{
|
||||
return m_clickedFrameSection == Qt::LeftSection ||
|
||||
m_clickedFrameSection == Qt::RightSection ||
|
||||
m_clickedFrameSection == Qt::TopSection ||
|
||||
m_clickedFrameSection == Qt::BottomSection ||
|
||||
m_clickedFrameSection == Qt::TopLeftSection ||
|
||||
m_clickedFrameSection == Qt::TopRightSection ||
|
||||
m_clickedFrameSection == Qt::BottomLeftSection ||
|
||||
m_clickedFrameSection == Qt::BottomRightSection;
|
||||
}
|
||||
|
||||
QCursor FramelessHelper::cursorForFrameSection(Qt::WindowFrameSection frameSection)
|
||||
{
|
||||
Qt::CursorShape cursor = Qt::ArrowCursor;
|
||||
|
@ -222,11 +245,24 @@ void FramelessHelper::unsetCursor()
|
|||
|
||||
void FramelessHelper::updateCursor()
|
||||
{
|
||||
#ifdef Q_OS_LINUX
|
||||
if (isHoverResizeHandler()) {
|
||||
Utilities::setX11CursorShape(m_window,
|
||||
Utilities::getX11CursorForFrameSection(m_hoveredFrameSection));
|
||||
m_cursorChanged = true;
|
||||
} else {
|
||||
if (!m_cursorChanged)
|
||||
return;
|
||||
Utilities::resetX1CursorShape(m_window);
|
||||
m_cursorChanged = false;
|
||||
}
|
||||
#else
|
||||
if (isHoverResizeHandler()) {
|
||||
setCursor(cursorForFrameSection(m_hoveredFrameSection));
|
||||
} else {
|
||||
unsetCursor();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void FramelessHelper::updateMouse(const QPoint& pos)
|
||||
|
@ -279,41 +315,57 @@ bool FramelessHelper::eventFilter(QObject *object, QEvent *event)
|
|||
{
|
||||
auto ev = static_cast<QMouseEvent *>(event);
|
||||
updateMouse(ev->pos());
|
||||
break;
|
||||
}
|
||||
|
||||
case QEvent::NonClientAreaMouseButtonPress:
|
||||
case QEvent::MouseButtonPress:
|
||||
{
|
||||
auto ev = static_cast<QMouseEvent *>(event);
|
||||
if (isHoverResizeHandler()) {
|
||||
// Start system resize
|
||||
startResize(ev, m_hoveredFrameSection);
|
||||
filterOut = true;
|
||||
} else if (isInTitlebarArea(ev->pos())) {
|
||||
if (m_clickedFrameSection == Qt::TitleBarArea
|
||||
&& isInTitlebarArea(ev->pos())) {
|
||||
// Start system move
|
||||
startMove(ev);
|
||||
filterOut = true;
|
||||
}
|
||||
|
||||
// We don't rely on the MouseMove event to determine the resize operation,
|
||||
// because when the mouse is moved out of the window, the resize cannot
|
||||
// be triggered.
|
||||
|
||||
break;
|
||||
}
|
||||
case QEvent::Leave:
|
||||
{
|
||||
updateMouse(m_window->mapFromGlobal(QCursor::pos()));
|
||||
break;
|
||||
}
|
||||
case QEvent::NonClientAreaMouseButtonPress:
|
||||
case QEvent::MouseButtonPress:
|
||||
{
|
||||
auto ev = static_cast<QMouseEvent *>(event);
|
||||
m_clickedFrameSection = m_hoveredFrameSection;
|
||||
if (isHoverResizeHandler()) {
|
||||
// Start system resize
|
||||
startResize(ev, m_hoveredFrameSection);
|
||||
filterOut = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case QEvent::NonClientAreaMouseButtonRelease:
|
||||
case QEvent::MouseButtonRelease:
|
||||
{
|
||||
m_clickedFrameSection = Qt::NoSection;
|
||||
break;
|
||||
}
|
||||
|
||||
case QEvent::NonClientAreaMouseButtonDblClick:
|
||||
case QEvent::MouseButtonDblClick:
|
||||
{
|
||||
auto ev = static_cast<QMouseEvent *>(event);
|
||||
if (ev->button() == Qt::LeftButton) {
|
||||
if (isInTitlebarArea(ev->pos()) && ev->button() == Qt::LeftButton) {
|
||||
Qt::WindowStates states = m_window->windowState();
|
||||
if (states & Qt::WindowMaximized)
|
||||
m_window->showNormal();
|
||||
else
|
||||
m_window->showMaximized();
|
||||
}
|
||||
// TODO: double click resize handler
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
@ -59,6 +59,7 @@ public:
|
|||
int titleBarHeight() { return m_titleBarHeight; }
|
||||
int setTitleBarHeight(int height) { m_titleBarHeight = height; }
|
||||
QRect titleBarRect();
|
||||
QRegion titleBarRegion();
|
||||
|
||||
int resizeBorderThickness() { return m_resizeBorderThickness; }
|
||||
void setResizeBorderThickness(int thickness) { m_resizeBorderThickness = thickness; }
|
||||
|
@ -73,6 +74,7 @@ public:
|
|||
Qt::WindowFrameSection mapPosToFrameSection(const QPoint& pos);
|
||||
|
||||
bool isHoverResizeHandler();
|
||||
bool isClickResizeHandler();
|
||||
|
||||
QCursor cursorForFrameSection(Qt::WindowFrameSection frameSection);
|
||||
void setCursor(const QCursor& cursor);
|
||||
|
@ -97,6 +99,7 @@ private:
|
|||
Qt::WindowFlags m_origWindowFlags;
|
||||
bool m_cursorChanged;
|
||||
Qt::WindowFrameSection m_hoveredFrameSection;
|
||||
Qt::WindowFrameSection m_clickedFrameSection;
|
||||
};
|
||||
|
||||
FRAMELESSHELPER_END_NAMESPACE
|
||||
|
|
|
@ -63,6 +63,9 @@ FRAMELESSHELPER_API void sendX11ButtonReleaseEvent(QWindow *w, const QPoint &pos
|
|||
FRAMELESSHELPER_API void sendX11MoveResizeEvent(QWindow *w, const QPoint &pos, int section);
|
||||
FRAMELESSHELPER_API void startX11Moving(QWindow *w, const QPoint &pos);
|
||||
FRAMELESSHELPER_API void startX11Resizing(QWindow *w, const QPoint &pos, Qt::WindowFrameSection frameSection);
|
||||
FRAMELESSHELPER_API void setX11CursorShape(QWindow *w, int cursorId);
|
||||
FRAMELESSHELPER_API void resetX1CursorShape(QWindow *w);
|
||||
FRAMELESSHELPER_API unsigned int getX11CursorForFrameSection(Qt::WindowFrameSection frameSection);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
|
|
@ -173,7 +173,7 @@ void Utilities::sendX11ButtonReleaseEvent(QWindow *w, const QPoint &pos)
|
|||
event.xbutton.time = CurrentTime;
|
||||
|
||||
if (XSendEvent(display, window, True, ButtonReleaseMask, &event) == 0)
|
||||
qWarning() << "Cant send ButtonRelease event.";
|
||||
qWarning() << "Failed to send ButtonRelease event.";
|
||||
XFlush(display);
|
||||
}
|
||||
|
||||
|
@ -202,7 +202,7 @@ void Utilities::sendX11MoveResizeEvent(QWindow *w, const QPoint &pos, int sectio
|
|||
event.xclient.data.l[4] = 0;
|
||||
if (XSendEvent(display, rootWindow,
|
||||
False, SubstructureRedirectMask | SubstructureNotifyMask, &event) == 0)
|
||||
qWarning("Cant send Move or Resize event.");
|
||||
qWarning("Failed to send Move or Resize event.");
|
||||
XFlush(display);
|
||||
}
|
||||
|
||||
|
@ -249,4 +249,77 @@ void Utilities::startX11Resizing(QWindow *w, const QPoint &pos, Qt::WindowFrameS
|
|||
sendX11MoveResizeEvent(w, pos, section);
|
||||
}
|
||||
|
||||
enum class X11CursorType
|
||||
{
|
||||
kArrow = 2,
|
||||
kTop = 138,
|
||||
kTopRight = 136,
|
||||
kRight = 96,
|
||||
kBottomRight = 14,
|
||||
kBottom = 16,
|
||||
kBottomLeft = 12,
|
||||
kLeft = 70,
|
||||
kTopLeft = 134,
|
||||
};
|
||||
|
||||
void Utilities::setX11CursorShape(QWindow *w, int cursorId)
|
||||
{
|
||||
const auto display = QX11Info::display();
|
||||
const WId window_id = w->winId();
|
||||
const Cursor cursor = XCreateFontCursor(display, cursorId);
|
||||
if (!cursor) {
|
||||
qWarning() << "Failed to set cursor.";
|
||||
}
|
||||
XDefineCursor(display, window_id, cursor);
|
||||
XFlush(display);
|
||||
}
|
||||
|
||||
void Utilities::resetX1CursorShape(QWindow *w)
|
||||
{
|
||||
const auto display = QX11Info::display();
|
||||
const WId window_id = w->winId();
|
||||
XUndefineCursor(display, window_id);
|
||||
XFlush(display);
|
||||
}
|
||||
|
||||
unsigned int Utilities::getX11CursorForFrameSection(Qt::WindowFrameSection frameSection)
|
||||
{
|
||||
X11CursorType cursor = X11CursorType::kArrow;
|
||||
|
||||
switch (frameSection)
|
||||
{
|
||||
case Qt::LeftSection:
|
||||
cursor = X11CursorType::kLeft;
|
||||
break;
|
||||
case Qt::RightSection:
|
||||
cursor = X11CursorType::kRight;
|
||||
break;
|
||||
case Qt::BottomSection:
|
||||
cursor = X11CursorType::kBottom;
|
||||
break;
|
||||
case Qt::TopSection:
|
||||
cursor = X11CursorType::kTop;
|
||||
break;
|
||||
case Qt::TopLeftSection:
|
||||
cursor = X11CursorType::kTopLeft;
|
||||
break;
|
||||
case Qt::BottomRightSection:
|
||||
cursor = X11CursorType::kBottomRight;
|
||||
break;
|
||||
case Qt::TopRightSection:
|
||||
cursor = X11CursorType::kTopRight;
|
||||
break;
|
||||
case Qt::BottomLeftSection:
|
||||
cursor = X11CursorType::kBottomLeft;
|
||||
break;
|
||||
case Qt::TitleBarArea:
|
||||
cursor = X11CursorType::kArrow;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return (unsigned int)cursor;
|
||||
}
|
||||
|
||||
FRAMELESSHELPER_END_NAMESPACE
|
Loading…
Reference in New Issue