forked from github_mirror/framelesshelper
fix move and resize determination
This commit is contained in:
parent
1aed38e882
commit
96f49ded2f
|
@ -21,7 +21,7 @@ FLWindow::~FLWindow()
|
||||||
void FLWindow::initFramelessWindow()
|
void FLWindow::initFramelessWindow()
|
||||||
{
|
{
|
||||||
FramelessHelper* helper = new FramelessHelper(windowHandle());
|
FramelessHelper* helper = new FramelessHelper(windowHandle());
|
||||||
helper->setResizeBorderThickness(8);
|
helper->setResizeBorderThickness(4);
|
||||||
helper->setTitleBarHeight(40);
|
helper->setTitleBarHeight(40);
|
||||||
helper->setResizable(true);
|
helper->setResizable(true);
|
||||||
helper->install();
|
helper->install();
|
||||||
|
|
|
@ -37,6 +37,8 @@ FRAMELESSHELPER_BEGIN_NAMESPACE
|
||||||
FramelessHelper::FramelessHelper(QWindow *window)
|
FramelessHelper::FramelessHelper(QWindow *window)
|
||||||
: QObject(window)
|
: QObject(window)
|
||||||
, m_window(window)
|
, m_window(window)
|
||||||
|
, m_hoveredFrameSection(Qt::NoSection)
|
||||||
|
, m_clickedFrameSection(Qt::NoSection)
|
||||||
{
|
{
|
||||||
Q_ASSERT(window != nullptr && window->isTopLevel());
|
Q_ASSERT(window != nullptr && window->isTopLevel());
|
||||||
}
|
}
|
||||||
|
@ -89,6 +91,14 @@ QRect FramelessHelper::titleBarRect()
|
||||||
return QRect(0, 0, windowSize().width(), titleBarHeight());
|
return QRect(0, 0, windowSize().width(), titleBarHeight());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
QRegion FramelessHelper::titleBarRegion()
|
||||||
|
{
|
||||||
|
// TODO: consider HitTestVisibleObject
|
||||||
|
QRegion region(titleBarRect());
|
||||||
|
return region;
|
||||||
|
}
|
||||||
|
|
||||||
QRect FramelessHelper::clientRect()
|
QRect FramelessHelper::clientRect()
|
||||||
{
|
{
|
||||||
QRect rect(0, 0, windowSize().width(), windowSize().height());
|
QRect rect(0, 0, windowSize().width(), windowSize().height());
|
||||||
|
@ -101,6 +111,7 @@ QRect FramelessHelper::clientRect()
|
||||||
|
|
||||||
QRegion FramelessHelper::nonClientRegion()
|
QRegion FramelessHelper::nonClientRegion()
|
||||||
{
|
{
|
||||||
|
// TODO: consider HitTestVisibleObject
|
||||||
QRegion region(QRect(QPoint(0, 0), windowSize()));
|
QRegion region(QRect(QPoint(0, 0), windowSize()));
|
||||||
region -= clientRect();
|
region -= clientRect();
|
||||||
return region;
|
return region;
|
||||||
|
@ -108,7 +119,7 @@ QRegion FramelessHelper::nonClientRegion()
|
||||||
|
|
||||||
bool FramelessHelper::isInTitlebarArea(const QPoint& pos)
|
bool FramelessHelper::isInTitlebarArea(const QPoint& pos)
|
||||||
{
|
{
|
||||||
return nonClientRegion().contains(pos);
|
return titleBarRegion().contains(pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
Qt::WindowFrameSection FramelessHelper::mapPosToFrameSection(const QPoint& pos)
|
Qt::WindowFrameSection FramelessHelper::mapPosToFrameSection(const QPoint& pos)
|
||||||
|
@ -173,6 +184,18 @@ bool FramelessHelper::isHoverResizeHandler()
|
||||||
m_hoveredFrameSection == Qt::BottomRightSection;
|
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)
|
QCursor FramelessHelper::cursorForFrameSection(Qt::WindowFrameSection frameSection)
|
||||||
{
|
{
|
||||||
Qt::CursorShape cursor = Qt::ArrowCursor;
|
Qt::CursorShape cursor = Qt::ArrowCursor;
|
||||||
|
@ -222,11 +245,24 @@ void FramelessHelper::unsetCursor()
|
||||||
|
|
||||||
void FramelessHelper::updateCursor()
|
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()) {
|
if (isHoverResizeHandler()) {
|
||||||
setCursor(cursorForFrameSection(m_hoveredFrameSection));
|
setCursor(cursorForFrameSection(m_hoveredFrameSection));
|
||||||
} else {
|
} else {
|
||||||
unsetCursor();
|
unsetCursor();
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void FramelessHelper::updateMouse(const QPoint& pos)
|
void FramelessHelper::updateMouse(const QPoint& pos)
|
||||||
|
@ -279,41 +315,57 @@ bool FramelessHelper::eventFilter(QObject *object, QEvent *event)
|
||||||
{
|
{
|
||||||
auto ev = static_cast<QMouseEvent *>(event);
|
auto ev = static_cast<QMouseEvent *>(event);
|
||||||
updateMouse(ev->pos());
|
updateMouse(ev->pos());
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case QEvent::NonClientAreaMouseButtonPress:
|
if (m_clickedFrameSection == Qt::TitleBarArea
|
||||||
case QEvent::MouseButtonPress:
|
&& isInTitlebarArea(ev->pos())) {
|
||||||
{
|
|
||||||
auto ev = static_cast<QMouseEvent *>(event);
|
|
||||||
if (isHoverResizeHandler()) {
|
|
||||||
// Start system resize
|
|
||||||
startResize(ev, m_hoveredFrameSection);
|
|
||||||
filterOut = true;
|
|
||||||
} else if (isInTitlebarArea(ev->pos())) {
|
|
||||||
// Start system move
|
// Start system move
|
||||||
startMove(ev);
|
startMove(ev);
|
||||||
filterOut = true;
|
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;
|
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::NonClientAreaMouseButtonRelease:
|
||||||
case QEvent::MouseButtonRelease:
|
case QEvent::MouseButtonRelease:
|
||||||
|
{
|
||||||
|
m_clickedFrameSection = Qt::NoSection;
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case QEvent::NonClientAreaMouseButtonDblClick:
|
case QEvent::NonClientAreaMouseButtonDblClick:
|
||||||
case QEvent::MouseButtonDblClick:
|
case QEvent::MouseButtonDblClick:
|
||||||
{
|
{
|
||||||
auto ev = static_cast<QMouseEvent *>(event);
|
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();
|
Qt::WindowStates states = m_window->windowState();
|
||||||
if (states & Qt::WindowMaximized)
|
if (states & Qt::WindowMaximized)
|
||||||
m_window->showNormal();
|
m_window->showNormal();
|
||||||
else
|
else
|
||||||
m_window->showMaximized();
|
m_window->showMaximized();
|
||||||
}
|
}
|
||||||
|
// TODO: double click resize handler
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -59,6 +59,7 @@ public:
|
||||||
int titleBarHeight() { return m_titleBarHeight; }
|
int titleBarHeight() { return m_titleBarHeight; }
|
||||||
int setTitleBarHeight(int height) { m_titleBarHeight = height; }
|
int setTitleBarHeight(int height) { m_titleBarHeight = height; }
|
||||||
QRect titleBarRect();
|
QRect titleBarRect();
|
||||||
|
QRegion titleBarRegion();
|
||||||
|
|
||||||
int resizeBorderThickness() { return m_resizeBorderThickness; }
|
int resizeBorderThickness() { return m_resizeBorderThickness; }
|
||||||
void setResizeBorderThickness(int thickness) { m_resizeBorderThickness = thickness; }
|
void setResizeBorderThickness(int thickness) { m_resizeBorderThickness = thickness; }
|
||||||
|
@ -73,6 +74,7 @@ public:
|
||||||
Qt::WindowFrameSection mapPosToFrameSection(const QPoint& pos);
|
Qt::WindowFrameSection mapPosToFrameSection(const QPoint& pos);
|
||||||
|
|
||||||
bool isHoverResizeHandler();
|
bool isHoverResizeHandler();
|
||||||
|
bool isClickResizeHandler();
|
||||||
|
|
||||||
QCursor cursorForFrameSection(Qt::WindowFrameSection frameSection);
|
QCursor cursorForFrameSection(Qt::WindowFrameSection frameSection);
|
||||||
void setCursor(const QCursor& cursor);
|
void setCursor(const QCursor& cursor);
|
||||||
|
@ -97,6 +99,7 @@ private:
|
||||||
Qt::WindowFlags m_origWindowFlags;
|
Qt::WindowFlags m_origWindowFlags;
|
||||||
bool m_cursorChanged;
|
bool m_cursorChanged;
|
||||||
Qt::WindowFrameSection m_hoveredFrameSection;
|
Qt::WindowFrameSection m_hoveredFrameSection;
|
||||||
|
Qt::WindowFrameSection m_clickedFrameSection;
|
||||||
};
|
};
|
||||||
|
|
||||||
FRAMELESSHELPER_END_NAMESPACE
|
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 sendX11MoveResizeEvent(QWindow *w, const QPoint &pos, int section);
|
||||||
FRAMELESSHELPER_API void startX11Moving(QWindow *w, const QPoint &pos);
|
FRAMELESSHELPER_API void startX11Moving(QWindow *w, const QPoint &pos);
|
||||||
FRAMELESSHELPER_API void startX11Resizing(QWindow *w, const QPoint &pos, Qt::WindowFrameSection frameSection);
|
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
|
#endif
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -173,7 +173,7 @@ void Utilities::sendX11ButtonReleaseEvent(QWindow *w, const QPoint &pos)
|
||||||
event.xbutton.time = CurrentTime;
|
event.xbutton.time = CurrentTime;
|
||||||
|
|
||||||
if (XSendEvent(display, window, True, ButtonReleaseMask, &event) == 0)
|
if (XSendEvent(display, window, True, ButtonReleaseMask, &event) == 0)
|
||||||
qWarning() << "Cant send ButtonRelease event.";
|
qWarning() << "Failed to send ButtonRelease event.";
|
||||||
XFlush(display);
|
XFlush(display);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -202,7 +202,7 @@ void Utilities::sendX11MoveResizeEvent(QWindow *w, const QPoint &pos, int sectio
|
||||||
event.xclient.data.l[4] = 0;
|
event.xclient.data.l[4] = 0;
|
||||||
if (XSendEvent(display, rootWindow,
|
if (XSendEvent(display, rootWindow,
|
||||||
False, SubstructureRedirectMask | SubstructureNotifyMask, &event) == 0)
|
False, SubstructureRedirectMask | SubstructureNotifyMask, &event) == 0)
|
||||||
qWarning("Cant send Move or Resize event.");
|
qWarning("Failed to send Move or Resize event.");
|
||||||
XFlush(display);
|
XFlush(display);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -249,4 +249,77 @@ void Utilities::startX11Resizing(QWindow *w, const QPoint &pos, Qt::WindowFrameS
|
||||||
sendX11MoveResizeEvent(w, pos, section);
|
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
|
FRAMELESSHELPER_END_NAMESPACE
|
Loading…
Reference in New Issue