forked from github_mirror/framelesshelper
Merge pull request #84 from altairwei/2.0-linux
framelesshelper v2.0 Core API Linux 端的实现
This commit is contained in:
commit
6a0dc5052c
|
@ -50,6 +50,7 @@ else()
|
|||
if(MACOS)
|
||||
list(APPEND SOURCES utilities_macos.mm)
|
||||
else()
|
||||
find_package(Qt${QT_VERSION_MAJOR} COMPONENTS X11Extras REQUIRED)
|
||||
list(APPEND SOURCES utilities_linux.cpp)
|
||||
endif()
|
||||
endif()
|
||||
|
@ -87,6 +88,14 @@ if(WIN32)
|
|||
target_link_libraries(${PROJECT_NAME} PRIVATE
|
||||
dwmapi
|
||||
)
|
||||
else()
|
||||
if(MACOS)
|
||||
#TODO
|
||||
else()
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE
|
||||
Qt${QT_VERSION_MAJOR}::X11Extras
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE
|
||||
|
|
|
@ -4,6 +4,7 @@ find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Widgets)
|
|||
if(TARGET Qt${QT_VERSION_MAJOR}::Widgets)
|
||||
add_subdirectory(widget)
|
||||
add_subdirectory(mainwindow)
|
||||
add_subdirectory(minimal)
|
||||
endif()
|
||||
|
||||
if(TARGET Qt${QT_VERSION_MAJOR}::Quick)
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
set(CMAKE_INCLUDE_CURRENT_DIR ON)
|
||||
|
||||
set(CMAKE_AUTOUIC ON)
|
||||
set(CMAKE_AUTOMOC ON)
|
||||
set(CMAKE_AUTORCC ON)
|
||||
|
||||
find_package(QT NAMES Qt6 Qt5 COMPONENTS Widgets REQUIRED)
|
||||
find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Widgets REQUIRED)
|
||||
|
||||
set(SOURCES
|
||||
../images.qrc
|
||||
main.cpp
|
||||
flwindow.h
|
||||
flwindow.cpp
|
||||
)
|
||||
|
||||
if(WIN32)
|
||||
enable_language(RC)
|
||||
list(APPEND SOURCES ../example.rc ../example.manifest)
|
||||
endif()
|
||||
|
||||
add_executable(minimal WIN32 ${SOURCES})
|
||||
|
||||
target_link_libraries(minimal PRIVATE
|
||||
Qt${QT_VERSION_MAJOR}::Widgets
|
||||
wangwenx190::FramelessHelper
|
||||
)
|
||||
|
||||
target_compile_definitions(minimal PRIVATE
|
||||
QT_NO_CAST_FROM_ASCII
|
||||
QT_NO_CAST_TO_ASCII
|
||||
QT_NO_KEYWORDS
|
||||
QT_DEPRECATED_WARNINGS
|
||||
QT_DISABLE_DEPRECATED_BEFORE=0x060100
|
||||
)
|
||||
|
||||
if(WIN32)
|
||||
target_link_libraries(minimal PRIVATE dwmapi)
|
||||
endif()
|
|
@ -0,0 +1,92 @@
|
|||
#include "flwindow.h"
|
||||
#include "../../framelesshelper.h"
|
||||
|
||||
#include <QScreen>
|
||||
#include <QVBoxLayout>
|
||||
#include <QPushButton>
|
||||
|
||||
FRAMELESSHELPER_USE_NAMESPACE
|
||||
|
||||
FLWindow::FLWindow(QWidget *parent) : QWidget(parent)
|
||||
{
|
||||
setWindowFlags(Qt::FramelessWindowHint);
|
||||
setupUi();
|
||||
|
||||
move(screen()->geometry().center() - frameGeometry().center());
|
||||
}
|
||||
|
||||
FLWindow::~FLWindow()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void FLWindow::initFramelessWindow()
|
||||
{
|
||||
FramelessHelper* helper = new FramelessHelper(windowHandle());
|
||||
helper->setResizeBorderThickness(4);
|
||||
helper->setTitleBarHeight(m_titleBarWidget->height());
|
||||
helper->setResizable(true);
|
||||
helper->setHitTestVisible(m_minimizeButton);
|
||||
helper->setHitTestVisible(m_maximizeButton);
|
||||
helper->setHitTestVisible(m_closeButton);
|
||||
helper->install();
|
||||
}
|
||||
|
||||
void FLWindow::showEvent(QShowEvent *event)
|
||||
{
|
||||
QWidget::showEvent(event);
|
||||
|
||||
static bool inited = false;
|
||||
if (!inited) {
|
||||
inited = true;
|
||||
initFramelessWindow();
|
||||
}
|
||||
}
|
||||
|
||||
void FLWindow::setupUi()
|
||||
{
|
||||
resize(800, 600);
|
||||
|
||||
m_titleBarWidget = new QWidget(this);
|
||||
m_titleBarWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
|
||||
m_titleBarWidget->setFixedHeight(40);
|
||||
m_titleBarWidget->setStyleSheet(QString::fromLatin1("background:grey"));
|
||||
|
||||
m_minimizeButton = new QPushButton(m_titleBarWidget);
|
||||
m_minimizeButton->setText(QStringLiteral("Min"));
|
||||
m_minimizeButton->setObjectName(QStringLiteral("MinimizeButton"));
|
||||
connect(m_minimizeButton, &QPushButton::clicked, this, &QWidget::showMinimized);
|
||||
|
||||
m_maximizeButton = new QPushButton(m_titleBarWidget);
|
||||
m_maximizeButton->setText(QStringLiteral("Max"));
|
||||
m_maximizeButton->setObjectName(QStringLiteral("MaximizeButton"));
|
||||
connect(m_maximizeButton, &QPushButton::clicked, this, [this](){
|
||||
if (isMaximized() || isFullScreen()) {
|
||||
showNormal();
|
||||
} else {
|
||||
showMaximized();
|
||||
}
|
||||
});
|
||||
|
||||
m_closeButton = new QPushButton(m_titleBarWidget);
|
||||
m_closeButton->setText(QStringLiteral("Close"));
|
||||
m_closeButton->setObjectName(QStringLiteral("CloseButton"));
|
||||
connect(m_closeButton, &QPushButton::clicked, this, &QWidget::close);
|
||||
|
||||
const auto titleBarLayout = new QHBoxLayout(m_titleBarWidget);
|
||||
titleBarLayout->setContentsMargins(0, 0, 0, 0);
|
||||
titleBarLayout->setSpacing(10);
|
||||
titleBarLayout->addStretch();
|
||||
titleBarLayout->addWidget(m_minimizeButton);
|
||||
titleBarLayout->addWidget(m_maximizeButton);
|
||||
titleBarLayout->addWidget(m_closeButton);
|
||||
titleBarLayout->addStretch();
|
||||
m_titleBarWidget->setLayout(titleBarLayout);
|
||||
|
||||
const auto mainLayout = new QVBoxLayout(this);
|
||||
mainLayout->setContentsMargins(0, 0, 0, 0);
|
||||
mainLayout->setSpacing(0);
|
||||
mainLayout->addWidget(m_titleBarWidget);
|
||||
mainLayout->addStretch();
|
||||
setLayout(mainLayout);
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
#pragma once
|
||||
|
||||
#include <QWidget>
|
||||
|
||||
class QPushButton;
|
||||
|
||||
class FLWindow : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit FLWindow(QWidget *parent = nullptr);
|
||||
~FLWindow();
|
||||
|
||||
protected:
|
||||
void showEvent(QShowEvent *event) override;
|
||||
|
||||
private:
|
||||
void initFramelessWindow();
|
||||
void setupUi();
|
||||
|
||||
private:
|
||||
QWidget *m_titleBarWidget = nullptr;
|
||||
QPushButton *m_minimizeButton = nullptr;
|
||||
QPushButton *m_maximizeButton = nullptr;
|
||||
QPushButton *m_closeButton = nullptr;
|
||||
};
|
|
@ -0,0 +1,22 @@
|
|||
#include <QtWidgets/qapplication.h>
|
||||
#include "flwindow.h"
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
#if 1
|
||||
QCoreApplication::setAttribute(Qt::AA_DontCreateNativeWidgetSiblings);
|
||||
#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
|
||||
QGuiApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
|
||||
QGuiApplication::setAttribute(Qt::AA_UseHighDpiPixmaps);
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0))
|
||||
QGuiApplication::setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy::PassThrough);
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
QApplication application(argc, argv);
|
||||
|
||||
FLWindow win;
|
||||
win.show();
|
||||
|
||||
return QApplication::exec();
|
||||
}
|
|
@ -31,6 +31,7 @@
|
|||
#include <QtWidgets/qpushbutton.h>
|
||||
#include "../../utilities.h"
|
||||
#include "../../framelesswindowsmanager.h"
|
||||
#include "../../framelesshelper.h"
|
||||
|
||||
FRAMELESSHELPER_USE_NAMESPACE
|
||||
|
||||
|
|
|
@ -29,182 +29,460 @@
|
|||
#include <QtCore/qdebug.h>
|
||||
#include <QtGui/qevent.h>
|
||||
#include <QtGui/qwindow.h>
|
||||
#include <QtGui/qscreen.h>
|
||||
#include "framelesswindowsmanager.h"
|
||||
#include "utilities.h"
|
||||
|
||||
FRAMELESSHELPER_BEGIN_NAMESPACE
|
||||
|
||||
FramelessHelper::FramelessHelper(QObject *parent) : QObject(parent) {}
|
||||
|
||||
void FramelessHelper::removeWindowFrame(QWindow *window)
|
||||
FramelessHelper::FramelessHelper(QWindow *window)
|
||||
: QObject(window)
|
||||
, m_window(window)
|
||||
, m_hoveredFrameSection(Qt::NoSection)
|
||||
, m_clickedFrameSection(Qt::NoSection)
|
||||
{
|
||||
Q_ASSERT(window);
|
||||
if (!window) {
|
||||
return;
|
||||
}
|
||||
window->setFlags(window->flags() | Qt::FramelessWindowHint);
|
||||
window->installEventFilter(this);
|
||||
window->setProperty(Constants::kFramelessModeFlag, true);
|
||||
Q_ASSERT(window != nullptr && window->isTopLevel());
|
||||
}
|
||||
|
||||
void FramelessHelper::bringBackWindowFrame(QWindow *window)
|
||||
/*!
|
||||
Setup the window, make it frameless.
|
||||
*/
|
||||
void FramelessHelper::install()
|
||||
{
|
||||
Q_ASSERT(window);
|
||||
if (!window) {
|
||||
QRect origRect = m_window->geometry();
|
||||
m_origWindowFlags = m_window->flags();
|
||||
|
||||
#ifdef Q_OS_MAC
|
||||
m_window->setFlags(Qt::Window);
|
||||
#else
|
||||
m_window->setFlags(m_origWindowFlags | Qt::FramelessWindowHint);
|
||||
#endif
|
||||
|
||||
m_window->setGeometry(origRect);
|
||||
resizeWindow(origRect.size());
|
||||
|
||||
m_window->installEventFilter(this);
|
||||
}
|
||||
|
||||
/*!
|
||||
Restore the window to its original state
|
||||
*/
|
||||
void FramelessHelper::uninstall()
|
||||
{
|
||||
m_window->setFlags(m_origWindowFlags);
|
||||
m_origWindowFlags = Qt::WindowFlags();
|
||||
resizeWindow(QSize());
|
||||
|
||||
m_window->removeEventFilter(this);
|
||||
}
|
||||
|
||||
/*!
|
||||
Resize non-client area
|
||||
*/
|
||||
void FramelessHelper::resizeWindow(const QSize& windowSize)
|
||||
{
|
||||
if (windowSize == this->windowSize())
|
||||
return;
|
||||
|
||||
setWindowSize(windowSize);
|
||||
}
|
||||
|
||||
QRect FramelessHelper::titleBarRect()
|
||||
{
|
||||
return QRect(0, 0, windowSize().width(), titleBarHeight());
|
||||
}
|
||||
|
||||
|
||||
QRegion FramelessHelper::titleBarRegion()
|
||||
{
|
||||
QRegion region(titleBarRect());
|
||||
|
||||
for (const auto obj : m_HTVObjects) {
|
||||
if (!obj || !(obj->isWidgetType() || obj->inherits("QQuickItem"))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!obj->property("visible").toBool()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
region -= getHTVObjectRect(obj);
|
||||
}
|
||||
window->removeEventFilter(this);
|
||||
window->setFlags(window->flags() & ~Qt::FramelessWindowHint);
|
||||
window->setProperty(Constants::kFramelessModeFlag, false);
|
||||
|
||||
return region;
|
||||
}
|
||||
|
||||
QRect FramelessHelper::clientRect()
|
||||
{
|
||||
QRect rect(0, 0, windowSize().width(), windowSize().height());
|
||||
rect = rect.adjusted(
|
||||
resizeBorderThickness(), titleBarHeight(),
|
||||
-resizeBorderThickness(), -resizeBorderThickness()
|
||||
);
|
||||
return rect;
|
||||
}
|
||||
|
||||
QRegion FramelessHelper::nonClientRegion()
|
||||
{
|
||||
QRegion region(QRect(QPoint(0, 0), windowSize()));
|
||||
region -= clientRect();
|
||||
|
||||
for (const auto obj : m_HTVObjects) {
|
||||
if (!obj || !(obj->isWidgetType() || obj->inherits("QQuickItem"))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!obj->property("visible").toBool()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
region -= getHTVObjectRect(obj);
|
||||
}
|
||||
|
||||
return region;
|
||||
}
|
||||
|
||||
bool FramelessHelper::isInTitlebarArea(const QPoint& pos)
|
||||
{
|
||||
return titleBarRegion().contains(pos);
|
||||
}
|
||||
|
||||
const int kCornerFactor = 2;
|
||||
|
||||
/*!
|
||||
\brief Determine window frame section by coordinates.
|
||||
|
||||
Returns the window frame section at position \a pos, or \c Qt::NoSection
|
||||
if there is no window frame section at this position.
|
||||
|
||||
*/
|
||||
Qt::WindowFrameSection FramelessHelper::mapPosToFrameSection(const QPoint& pos)
|
||||
{
|
||||
int border = 0;
|
||||
|
||||
// TODO: get system default resize border
|
||||
const int sysBorder = Utilities::getSystemMetric(m_window, SystemMetric::ResizeBorderThickness, false);
|
||||
|
||||
Qt::WindowStates states = m_window->windowState();
|
||||
// Resizing is disabled when WindowMaximized or WindowFullScreen
|
||||
if (!(states & Qt::WindowMaximized) && !(states & Qt::WindowFullScreen))
|
||||
{
|
||||
border = resizeBorderThickness();
|
||||
border = qMin(border, sysBorder);
|
||||
}
|
||||
|
||||
QRect windowRect(0, 0, windowSize().width(), windowSize().height());
|
||||
|
||||
if (windowRect.contains(pos))
|
||||
{
|
||||
QPoint mappedPos = pos - windowRect.topLeft();
|
||||
|
||||
// The corner is kCornerFactor times the size of the border
|
||||
if (QRect(0, 0, border * kCornerFactor, border * kCornerFactor).contains(mappedPos))
|
||||
return Qt::TopLeftSection;
|
||||
|
||||
if (QRect(border * kCornerFactor, 0, windowRect.width() - border * 2 * kCornerFactor, border).contains(mappedPos))
|
||||
return Qt::TopSection;
|
||||
|
||||
if (QRect(windowRect.width() - border * kCornerFactor, 0, border * kCornerFactor, border * kCornerFactor).contains(mappedPos))
|
||||
return Qt::TopRightSection;
|
||||
|
||||
if (QRect(windowRect.width() - border, border * kCornerFactor, border, windowRect.height() - border * 2 * kCornerFactor).contains(mappedPos))
|
||||
return Qt::RightSection;
|
||||
|
||||
if (QRect(windowRect.width() - border * kCornerFactor, windowRect.height() - border * kCornerFactor, border * kCornerFactor, border * kCornerFactor).contains(mappedPos))
|
||||
return Qt::BottomRightSection;
|
||||
|
||||
if (QRect(border * kCornerFactor, windowRect.height() - border, windowRect.width() - border * 2 * kCornerFactor, border).contains(mappedPos))
|
||||
return Qt::BottomSection;
|
||||
|
||||
if (QRect(0, windowRect.height() - border * kCornerFactor, border * kCornerFactor, border * kCornerFactor).contains(mappedPos))
|
||||
return Qt::BottomLeftSection;
|
||||
|
||||
if (QRect(0, border * kCornerFactor, border, windowRect.height() - border * 2 * kCornerFactor).contains(mappedPos))
|
||||
return Qt::LeftSection;
|
||||
|
||||
// Determining window frame secion is the highest priority,
|
||||
// so the determination of the title bar area can be simpler.
|
||||
if (isInTitlebarArea(pos))
|
||||
return Qt::TitleBarArea;
|
||||
}
|
||||
|
||||
return Qt::NoSection;
|
||||
}
|
||||
|
||||
bool FramelessHelper::isHoverResizeHandler()
|
||||
{
|
||||
return m_hoveredFrameSection == Qt::LeftSection ||
|
||||
m_hoveredFrameSection == Qt::RightSection ||
|
||||
m_hoveredFrameSection == Qt::TopSection ||
|
||||
m_hoveredFrameSection == Qt::BottomSection ||
|
||||
m_hoveredFrameSection == Qt::TopLeftSection ||
|
||||
m_hoveredFrameSection == Qt::TopRightSection ||
|
||||
m_hoveredFrameSection == Qt::BottomLeftSection ||
|
||||
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;
|
||||
|
||||
switch (frameSection)
|
||||
{
|
||||
case Qt::LeftSection:
|
||||
case Qt::RightSection:
|
||||
cursor = Qt::SizeHorCursor;
|
||||
break;
|
||||
case Qt::BottomSection:
|
||||
case Qt::TopSection:
|
||||
cursor = Qt::SizeVerCursor;
|
||||
break;
|
||||
case Qt::TopLeftSection:
|
||||
case Qt::BottomRightSection:
|
||||
cursor = Qt::SizeFDiagCursor;
|
||||
break;
|
||||
case Qt::TopRightSection:
|
||||
case Qt::BottomLeftSection:
|
||||
cursor = Qt::SizeBDiagCursor;
|
||||
break;
|
||||
case Qt::TitleBarArea:
|
||||
cursor = Qt::ArrowCursor;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return QCursor(cursor);
|
||||
}
|
||||
|
||||
void FramelessHelper::setCursor(const QCursor& cursor)
|
||||
{
|
||||
m_window->setCursor(cursor);
|
||||
m_cursorChanged = true;
|
||||
}
|
||||
|
||||
void FramelessHelper::unsetCursor()
|
||||
{
|
||||
if (!m_cursorChanged)
|
||||
return;
|
||||
|
||||
m_window->unsetCursor();
|
||||
m_cursorChanged = false;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
updateHoverStates(pos);
|
||||
updateCursor();
|
||||
}
|
||||
|
||||
void FramelessHelper::updateHoverStates(const QPoint& pos)
|
||||
{
|
||||
m_hoveredFrameSection = mapPosToFrameSection(pos);
|
||||
}
|
||||
|
||||
void FramelessHelper::startMove(const QPoint &globalPos)
|
||||
{
|
||||
#ifdef Q_OS_LINUX
|
||||
// On HiDPI screen, X11 ButtonRelease is likely to trigger
|
||||
// a QEvent::MouseMove, so we reset m_clickedFrameSection in advance.
|
||||
m_clickedFrameSection = Qt::NoSection;
|
||||
Utilities::sendX11ButtonReleaseEvent(m_window, globalPos);
|
||||
Utilities::startX11Moving(m_window, globalPos);
|
||||
#endif
|
||||
}
|
||||
|
||||
void FramelessHelper::startResize(const QPoint &globalPos, Qt::WindowFrameSection frameSection)
|
||||
{
|
||||
#ifdef Q_OS_LINUX
|
||||
// On HiDPI screen, X11 ButtonRelease is likely to trigger
|
||||
// a QEvent::MouseMove, so we reset m_clickedFrameSection in advance.
|
||||
m_clickedFrameSection = Qt::NoSection;
|
||||
Utilities::sendX11ButtonReleaseEvent(m_window, globalPos);
|
||||
Utilities::startX11Resizing(m_window, globalPos, frameSection);
|
||||
#endif
|
||||
}
|
||||
|
||||
void FramelessHelper::setHitTestVisible(QObject *obj)
|
||||
{
|
||||
m_HTVObjects.push_back(obj);
|
||||
}
|
||||
|
||||
bool FramelessHelper::isHitTestVisible(QObject *obj)
|
||||
{
|
||||
return m_HTVObjects.contains(obj);
|
||||
}
|
||||
|
||||
QRect FramelessHelper::getHTVObjectRect(QObject *obj)
|
||||
{
|
||||
const QPoint originPoint = m_window->mapFromGlobal(
|
||||
Utilities::mapOriginPointToWindow(obj).toPoint());
|
||||
const int width = obj->property("width").toInt();
|
||||
const int height = obj->property("height").toInt();
|
||||
|
||||
return QRect(originPoint, QSize(width, height));
|
||||
}
|
||||
|
||||
bool FramelessHelper::eventFilter(QObject *object, QEvent *event)
|
||||
{
|
||||
Q_ASSERT(object);
|
||||
Q_ASSERT(event);
|
||||
if (!object || !event) {
|
||||
return false;
|
||||
}
|
||||
// Only monitor window events.
|
||||
if (!object->isWindowType()) {
|
||||
return false;
|
||||
}
|
||||
const QEvent::Type type = event->type();
|
||||
// We are only interested in mouse events.
|
||||
if ((type != QEvent::MouseButtonDblClick) && (type != QEvent::MouseButtonPress)
|
||||
&& (type != QEvent::MouseMove)) {
|
||||
return false;
|
||||
}
|
||||
const auto window = qobject_cast<QWindow *>(object);
|
||||
const int resizeBorderThickness = FramelessWindowsManager::getResizeBorderThickness(window);
|
||||
const int titleBarHeight = FramelessWindowsManager::getTitleBarHeight(window);
|
||||
const bool resizable = FramelessWindowsManager::getResizable(window);
|
||||
const int windowWidth = window->width();
|
||||
const auto mouseEvent = static_cast<QMouseEvent *>(event);
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
|
||||
const QPoint localMousePosition = mouseEvent->position().toPoint();
|
||||
#else
|
||||
const QPoint localMousePosition = mouseEvent->windowPos().toPoint();
|
||||
#endif
|
||||
const Qt::Edges edges = [window, resizeBorderThickness, windowWidth, &localMousePosition] {
|
||||
const int windowHeight = window->height();
|
||||
if (localMousePosition.y() <= resizeBorderThickness) {
|
||||
if (localMousePosition.x() <= resizeBorderThickness) {
|
||||
return Qt::TopEdge | Qt::LeftEdge;
|
||||
}
|
||||
if (localMousePosition.x() >= (windowWidth - resizeBorderThickness)) {
|
||||
return Qt::TopEdge | Qt::RightEdge;
|
||||
}
|
||||
return Qt::Edges{Qt::TopEdge};
|
||||
}
|
||||
if (localMousePosition.y() >= (windowHeight - resizeBorderThickness)) {
|
||||
if (localMousePosition.x() <= resizeBorderThickness) {
|
||||
return Qt::BottomEdge | Qt::LeftEdge;
|
||||
}
|
||||
if (localMousePosition.x() >= (windowWidth - resizeBorderThickness)) {
|
||||
return Qt::BottomEdge | Qt::RightEdge;
|
||||
}
|
||||
return Qt::Edges{Qt::BottomEdge};
|
||||
}
|
||||
if (localMousePosition.x() <= resizeBorderThickness) {
|
||||
return Qt::Edges{Qt::LeftEdge};
|
||||
}
|
||||
if (localMousePosition.x() >= (windowWidth - resizeBorderThickness)) {
|
||||
return Qt::Edges{Qt::RightEdge};
|
||||
}
|
||||
return Qt::Edges{};
|
||||
} ();
|
||||
const bool hitTestVisible = Utilities::isHitTestVisibleInChrome(window);
|
||||
bool isInTitlebarArea = false;
|
||||
if ((window->windowState() == Qt::WindowMaximized)
|
||||
|| (window->windowState() == Qt::WindowFullScreen)) {
|
||||
isInTitlebarArea = (localMousePosition.y() >= 0)
|
||||
&& (localMousePosition.y() <= titleBarHeight)
|
||||
&& (localMousePosition.x() >= 0)
|
||||
&& (localMousePosition.x() <= windowWidth)
|
||||
&& !hitTestVisible;
|
||||
}
|
||||
if (window->windowState() == Qt::WindowNoState) {
|
||||
isInTitlebarArea = (localMousePosition.y() > resizeBorderThickness)
|
||||
&& (localMousePosition.y() <= titleBarHeight)
|
||||
&& (localMousePosition.x() > resizeBorderThickness)
|
||||
&& (localMousePosition.x() < (windowWidth - resizeBorderThickness))
|
||||
&& !hitTestVisible;
|
||||
}
|
||||
bool filterOut = false;
|
||||
|
||||
// Determine if the mouse click occurred in the title bar
|
||||
static bool titlebarClicked = false;
|
||||
if (type == QEvent::MouseButtonPress) {
|
||||
if (isInTitlebarArea)
|
||||
titlebarClicked = true;
|
||||
else
|
||||
titlebarClicked = false;
|
||||
}
|
||||
|
||||
if (type == QEvent::MouseButtonDblClick) {
|
||||
if (mouseEvent->button() != Qt::MouseButton::LeftButton) {
|
||||
return false;
|
||||
}
|
||||
if (isInTitlebarArea) {
|
||||
if (window->windowState() == Qt::WindowState::WindowFullScreen) {
|
||||
return false;
|
||||
}
|
||||
if (window->windowState() == Qt::WindowState::WindowMaximized) {
|
||||
window->showNormal();
|
||||
} else {
|
||||
window->showMaximized();
|
||||
}
|
||||
window->setCursor(Qt::ArrowCursor);
|
||||
}
|
||||
} else if (type == QEvent::MouseMove) {
|
||||
// Display resize indicators
|
||||
static bool cursorChanged = false;
|
||||
if ((window->windowState() == Qt::WindowState::WindowNoState) && resizable) {
|
||||
if (((edges & Qt::TopEdge) && (edges & Qt::LeftEdge))
|
||||
|| ((edges & Qt::BottomEdge) && (edges & Qt::RightEdge))) {
|
||||
window->setCursor(Qt::SizeFDiagCursor);
|
||||
cursorChanged = true;
|
||||
} else if (((edges & Qt::TopEdge) && (edges & Qt::RightEdge))
|
||||
|| ((edges & Qt::BottomEdge) && (edges & Qt::LeftEdge))) {
|
||||
window->setCursor(Qt::SizeBDiagCursor);
|
||||
cursorChanged = true;
|
||||
} else if ((edges & Qt::TopEdge) || (edges & Qt::BottomEdge)) {
|
||||
window->setCursor(Qt::SizeVerCursor);
|
||||
cursorChanged = true;
|
||||
} else if ((edges & Qt::LeftEdge) || (edges & Qt::RightEdge)) {
|
||||
window->setCursor(Qt::SizeHorCursor);
|
||||
cursorChanged = true;
|
||||
} else {
|
||||
if (cursorChanged) {
|
||||
window->setCursor(Qt::ArrowCursor);
|
||||
cursorChanged = false;
|
||||
}
|
||||
}
|
||||
if (object == m_window) {
|
||||
switch (event->type())
|
||||
{
|
||||
case QEvent::Resize:
|
||||
{
|
||||
QResizeEvent* re = static_cast<QResizeEvent *>(event);
|
||||
resizeWindow(re->size());
|
||||
break;
|
||||
}
|
||||
|
||||
if ((mouseEvent->buttons() & Qt::LeftButton) && titlebarClicked) {
|
||||
if (edges == Qt::Edges{}) {
|
||||
if (isInTitlebarArea) {
|
||||
if (!window->startSystemMove()) {
|
||||
// ### FIXME: TO BE IMPLEMENTED!
|
||||
qWarning() << "Current OS doesn't support QWindow::startSystemMove().";
|
||||
}
|
||||
}
|
||||
case QEvent::NonClientAreaMouseMove:
|
||||
case QEvent::MouseMove:
|
||||
{
|
||||
auto ev = static_cast<QMouseEvent *>(event);
|
||||
updateMouse(ev->pos());
|
||||
|
||||
if (m_clickedFrameSection == Qt::TitleBarArea
|
||||
&& isInTitlebarArea(ev->pos())) {
|
||||
// Start system move
|
||||
startMove(ev->globalPos());
|
||||
ev->accept();
|
||||
filterOut = true;
|
||||
} else if (isClickResizeHandler() && isHoverResizeHandler()) {
|
||||
// Start system resize
|
||||
startResize(ev->globalPos(), m_hoveredFrameSection);
|
||||
ev->accept();
|
||||
filterOut = true;
|
||||
}
|
||||
|
||||
// This case takes into account that the mouse moves outside the window boundary
|
||||
QRect windowRect(0, 0, windowSize().width(), windowSize().height());
|
||||
if (isClickResizeHandler() && !windowRect.contains(ev->pos())) {
|
||||
startResize(ev->globalPos(), m_clickedFrameSection);
|
||||
ev->accept();
|
||||
filterOut = true;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case QEvent::Leave:
|
||||
{
|
||||
updateMouse(m_window->mapFromGlobal(QCursor::pos()));
|
||||
break;
|
||||
}
|
||||
case QEvent::NonClientAreaMouseButtonPress:
|
||||
case QEvent::MouseButtonPress:
|
||||
{
|
||||
auto ev = static_cast<QMouseEvent *>(event);
|
||||
|
||||
if (ev->button() == Qt::LeftButton)
|
||||
m_clickedFrameSection = m_hoveredFrameSection;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
} else if (type == QEvent::MouseButtonPress) {
|
||||
if (edges != Qt::Edges{}) {
|
||||
if ((window->windowState() == Qt::WindowState::WindowNoState) && !hitTestVisible && resizable) {
|
||||
if (!window->startSystemResize(edges)) {
|
||||
// ### FIXME: TO BE IMPLEMENTED!
|
||||
qWarning() << "Current OS doesn't support QWindow::startSystemResize().";
|
||||
}
|
||||
case QEvent::NonClientAreaMouseButtonRelease:
|
||||
case QEvent::MouseButtonRelease:
|
||||
{
|
||||
m_clickedFrameSection = Qt::NoSection;
|
||||
break;
|
||||
}
|
||||
|
||||
case QEvent::NonClientAreaMouseButtonDblClick:
|
||||
case QEvent::MouseButtonDblClick:
|
||||
{
|
||||
auto ev = static_cast<QMouseEvent *>(event);
|
||||
if (isHoverResizeHandler() && ev->button() == Qt::LeftButton) {
|
||||
// double click resize handler
|
||||
handleResizeHandlerDblClicked();
|
||||
} else 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();
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
return filterOut;
|
||||
}
|
||||
|
||||
void FramelessHelper::handleResizeHandlerDblClicked()
|
||||
{
|
||||
QRect screenRect = m_window->screen()->availableGeometry();
|
||||
QRect winRect = m_window->geometry();
|
||||
|
||||
switch (m_clickedFrameSection)
|
||||
{
|
||||
case Qt::TopSection:
|
||||
m_window->setGeometry(winRect.x(), 0, winRect.width(), winRect.height() + winRect.y());
|
||||
break;
|
||||
case Qt::BottomSection:
|
||||
m_window->setGeometry(winRect.x(), winRect.y(), winRect.width(), screenRect.height() - winRect.y());
|
||||
break;
|
||||
case Qt::LeftSection:
|
||||
m_window->setGeometry(0, winRect.y(), winRect.x() + winRect.width(), winRect.height());
|
||||
break;
|
||||
case Qt::RightSection:
|
||||
m_window->setGeometry(winRect.x(), winRect.y(), screenRect.width() - winRect.x(), winRect.height());
|
||||
break;
|
||||
case Qt::TopLeftSection:
|
||||
m_window->setGeometry(0, 0, winRect.x() + winRect.width(), winRect.y() + winRect.height());
|
||||
break;
|
||||
case Qt::TopRightSection:
|
||||
m_window->setGeometry(winRect.x(), 0, screenRect.width() - winRect.x(), winRect.y() + winRect.height());
|
||||
break;
|
||||
case Qt::BottomLeftSection:
|
||||
m_window->setGeometry(0, winRect.y(), winRect.x() + winRect.width(), screenRect.height() - winRect.y());
|
||||
break;
|
||||
case Qt::BottomRightSection:
|
||||
m_window->setGeometry(winRect.x(), winRect.y(), screenRect.width() - winRect.x(), screenRect.height() - winRect.y());
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
FRAMELESSHELPER_END_NAMESPACE
|
||||
|
|
|
@ -29,9 +29,11 @@
|
|||
#if (QT_VERSION >= QT_VERSION_CHECK(5, 15, 0))
|
||||
|
||||
#include <QtCore/qobject.h>
|
||||
#include <QtCore/qsize.h>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
QT_FORWARD_DECLARE_CLASS(QWindow)
|
||||
QT_FORWARD_DECLARE_CLASS(QMouseEvent)
|
||||
QT_END_NAMESPACE
|
||||
|
||||
FRAMELESSHELPER_BEGIN_NAMESPACE
|
||||
|
@ -42,14 +44,68 @@ class FRAMELESSHELPER_API FramelessHelper : public QObject
|
|||
Q_DISABLE_COPY_MOVE(FramelessHelper)
|
||||
|
||||
public:
|
||||
explicit FramelessHelper(QObject *parent = nullptr);
|
||||
explicit FramelessHelper(QWindow *window);
|
||||
~FramelessHelper() override = default;
|
||||
|
||||
void removeWindowFrame(QWindow *window);
|
||||
void bringBackWindowFrame(QWindow *window);
|
||||
void install();
|
||||
void uninstall();
|
||||
|
||||
QWindow *window() { return m_window; }
|
||||
|
||||
QSize windowSize() { return m_windowSize; }
|
||||
void setWindowSize(const QSize& size) { m_windowSize = size; }
|
||||
void resizeWindow(const QSize& windowSize);
|
||||
|
||||
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; }
|
||||
|
||||
bool resizable() { return m_resizable; }
|
||||
void setResizable(bool resizable) { m_resizable = resizable; }
|
||||
|
||||
QRect clientRect();
|
||||
QRegion nonClientRegion();
|
||||
|
||||
bool isInTitlebarArea(const QPoint& pos);
|
||||
Qt::WindowFrameSection mapPosToFrameSection(const QPoint& pos);
|
||||
|
||||
bool isHoverResizeHandler();
|
||||
bool isClickResizeHandler();
|
||||
|
||||
QCursor cursorForFrameSection(Qt::WindowFrameSection frameSection);
|
||||
void setCursor(const QCursor& cursor);
|
||||
void unsetCursor();
|
||||
void updateCursor();
|
||||
|
||||
void updateMouse(const QPoint& pos);
|
||||
void updateHoverStates(const QPoint& pos);
|
||||
|
||||
void startMove(const QPoint &globalPos);
|
||||
void startResize(const QPoint &globalPos, Qt::WindowFrameSection frameSection);
|
||||
|
||||
void setHitTestVisible(QObject *obj);
|
||||
bool isHitTestVisible(QObject *obj);
|
||||
QRect getHTVObjectRect(QObject *obj);
|
||||
|
||||
protected:
|
||||
bool eventFilter(QObject *object, QEvent *event) override;
|
||||
void handleResizeHandlerDblClicked();
|
||||
|
||||
private:
|
||||
QWindow *m_window;
|
||||
QSize m_windowSize;
|
||||
int m_titleBarHeight;
|
||||
int m_resizeBorderThickness;
|
||||
bool m_resizable;
|
||||
Qt::WindowFlags m_origWindowFlags;
|
||||
bool m_cursorChanged;
|
||||
Qt::WindowFrameSection m_hoveredFrameSection;
|
||||
Qt::WindowFrameSection m_clickedFrameSection;
|
||||
QList<QObject*> m_HTVObjects;
|
||||
};
|
||||
|
||||
FRAMELESSHELPER_END_NAMESPACE
|
||||
|
|
|
@ -38,7 +38,7 @@
|
|||
FRAMELESSHELPER_BEGIN_NAMESPACE
|
||||
|
||||
#ifdef FRAMELESSHELPER_USE_UNIX_VERSION
|
||||
Q_GLOBAL_STATIC(FramelessHelper, framelessHelperUnix)
|
||||
//Q_GLOBAL_STATIC(FramelessHelper, framelessHelperUnix)
|
||||
#endif
|
||||
|
||||
void FramelessWindowsManager::addWindow(QWindow *window)
|
||||
|
@ -51,7 +51,7 @@ void FramelessWindowsManager::addWindow(QWindow *window)
|
|||
QCoreApplication::setAttribute(Qt::AA_DontCreateNativeWidgetSiblings);
|
||||
}
|
||||
#ifdef FRAMELESSHELPER_USE_UNIX_VERSION
|
||||
framelessHelperUnix()->removeWindowFrame(window);
|
||||
//framelessHelperUnix()->removeWindowFrame(window);
|
||||
#else
|
||||
FramelessHelperWin::addFramelessWindow(window);
|
||||
// Work-around a Win32 multi-monitor bug.
|
||||
|
@ -165,7 +165,7 @@ void FramelessWindowsManager::removeWindow(QWindow *window)
|
|||
return;
|
||||
}
|
||||
#ifdef FRAMELESSHELPER_USE_UNIX_VERSION
|
||||
framelessHelperUnix()->bringBackWindowFrame(window);
|
||||
//framelessHelperUnix()->bringBackWindowFrame(window);
|
||||
#else
|
||||
FramelessHelperWin::removeFramelessWindow(window);
|
||||
#endif
|
||||
|
|
10
utilities.h
10
utilities.h
|
@ -58,6 +58,16 @@ FRAMELESSHELPER_API void updateQtFrameMargins(QWindow *window, const bool enable
|
|||
[[nodiscard]] FRAMELESSHELPER_API QString getSystemErrorMessage(const QString &function);
|
||||
#endif
|
||||
|
||||
#ifdef Q_OS_LINUX
|
||||
FRAMELESSHELPER_API void sendX11ButtonReleaseEvent(QWindow *w, const QPoint &globalPos);
|
||||
FRAMELESSHELPER_API void sendX11MoveResizeEvent(QWindow *w, const QPoint &globalPos, int section);
|
||||
FRAMELESSHELPER_API void startX11Moving(QWindow *w, const QPoint &globalPos);
|
||||
FRAMELESSHELPER_API void startX11Resizing(QWindow *w, const QPoint &globalPos, 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
|
||||
|
||||
}
|
||||
|
||||
FRAMELESSHELPER_END_NAMESPACE
|
||||
|
|
|
@ -25,9 +25,26 @@
|
|||
#include "utilities.h"
|
||||
|
||||
#include <QtCore/qvariant.h>
|
||||
#include <QtCore/qdebug.h>
|
||||
#include <QtGui/qscreen.h>
|
||||
#include <QtX11Extras/qx11info_x11.h>
|
||||
#include <X11/Xlib.h>
|
||||
|
||||
FRAMELESSHELPER_BEGIN_NAMESPACE
|
||||
|
||||
#define _NET_WM_MOVERESIZE_SIZE_TOPLEFT 0
|
||||
#define _NET_WM_MOVERESIZE_SIZE_TOP 1
|
||||
#define _NET_WM_MOVERESIZE_SIZE_TOPRIGHT 2
|
||||
#define _NET_WM_MOVERESIZE_SIZE_RIGHT 3
|
||||
#define _NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT 4
|
||||
#define _NET_WM_MOVERESIZE_SIZE_BOTTOM 5
|
||||
#define _NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT 6
|
||||
#define _NET_WM_MOVERESIZE_SIZE_LEFT 7
|
||||
#define _NET_WM_MOVERESIZE_MOVE 8 /* movement only */
|
||||
#define _NET_WM_MOVERESIZE_SIZE_KEYBOARD 9 /* size via keyboard */
|
||||
#define _NET_WM_MOVERESIZE_MOVE_KEYBOARD 10 /* move via keyboard */
|
||||
#define _NET_WM_MOVERESIZE_CANCEL 11 /* cancel operation */
|
||||
|
||||
static constexpr int kDefaultResizeBorderThickness = 8;
|
||||
static constexpr int kDefaultCaptionHeight = 23;
|
||||
|
||||
|
@ -106,7 +123,8 @@ bool Utilities::shouldAppsUseDarkMode()
|
|||
ColorizationArea Utilities::getColorizationArea()
|
||||
{
|
||||
// ### TO BE IMPLEMENTED
|
||||
return ColorizationArea::None;
|
||||
//return ColorizationArea::None; // ‘None’ has been defined as a macro in X11 headers.
|
||||
return ColorizationArea::All;
|
||||
}
|
||||
|
||||
bool Utilities::isThemeChanged(const void *data)
|
||||
|
@ -132,4 +150,178 @@ bool Utilities::showSystemMenu(const WId winId, const QPointF &pos)
|
|||
return false;
|
||||
}
|
||||
|
||||
FRAMELESSHELPER_END_NAMESPACE
|
||||
void Utilities::sendX11ButtonReleaseEvent(QWindow *w, const QPoint &globalPos)
|
||||
{
|
||||
const QPoint pos = w->mapFromGlobal(globalPos);
|
||||
const auto display = QX11Info::display();
|
||||
const auto screen = QX11Info::appScreen();
|
||||
|
||||
XEvent xevent;
|
||||
memset(&xevent, 0, sizeof(XEvent));
|
||||
|
||||
xevent.type = ButtonRelease;
|
||||
xevent.xbutton.time = CurrentTime;
|
||||
xevent.xbutton.button = 0;
|
||||
xevent.xbutton.same_screen = True;
|
||||
xevent.xbutton.send_event = True;
|
||||
xevent.xbutton.window = w->winId();
|
||||
xevent.xbutton.root = QX11Info::appRootWindow(screen);
|
||||
xevent.xbutton.x = pos.x() * w->screen()->devicePixelRatio();
|
||||
xevent.xbutton.y = pos.y() * w->screen()->devicePixelRatio();
|
||||
xevent.xbutton.x_root = globalPos.x() * w->screen()->devicePixelRatio();
|
||||
xevent.xbutton.y_root = globalPos.y() * w->screen()->devicePixelRatio();
|
||||
xevent.xbutton.display = display;
|
||||
|
||||
if (XSendEvent(display, w->winId(), True, ButtonReleaseMask, &xevent) == 0)
|
||||
qWarning() << "Failed to send ButtonRelease event.";
|
||||
XFlush(display);
|
||||
}
|
||||
|
||||
void Utilities::sendX11MoveResizeEvent(QWindow *w, const QPoint &globalPos, int section)
|
||||
{
|
||||
const auto display = QX11Info::display();
|
||||
const auto winId = w->winId();
|
||||
const auto screen = QX11Info::appScreen();
|
||||
|
||||
XUngrabPointer(display, CurrentTime);
|
||||
|
||||
XEvent xev;
|
||||
memset(&xev, 0x00, sizeof(xev));
|
||||
const Atom netMoveResize = XInternAtom(display, "_NET_WM_MOVERESIZE", False);
|
||||
xev.xclient.type = ClientMessage;
|
||||
xev.xclient.message_type = netMoveResize;
|
||||
xev.xclient.serial = 0;
|
||||
xev.xclient.display = display;
|
||||
xev.xclient.send_event = True;
|
||||
xev.xclient.window = winId;
|
||||
xev.xclient.format = 32;
|
||||
|
||||
xev.xclient.data.l[0] = globalPos.x() * w->screen()->devicePixelRatio();
|
||||
xev.xclient.data.l[1] = globalPos.y() * w->screen()->devicePixelRatio();
|
||||
xev.xclient.data.l[2] = section;
|
||||
xev.xclient.data.l[3] = Button1;
|
||||
xev.xclient.data.l[4] = 0;
|
||||
|
||||
if(XSendEvent(display, QX11Info::appRootWindow(screen),
|
||||
False, SubstructureRedirectMask | SubstructureNotifyMask, &xev) == 0)
|
||||
qWarning("Failed to send Move or Resize event.");
|
||||
XFlush(display);
|
||||
}
|
||||
|
||||
void Utilities::startX11Moving(QWindow *w, const QPoint &pos)
|
||||
{
|
||||
sendX11MoveResizeEvent(w, pos, _NET_WM_MOVERESIZE_MOVE);
|
||||
}
|
||||
|
||||
void Utilities::startX11Resizing(QWindow *w, const QPoint &pos, Qt::WindowFrameSection frameSection)
|
||||
{
|
||||
int section = -1;
|
||||
|
||||
switch (frameSection)
|
||||
{
|
||||
case Qt::LeftSection:
|
||||
section = _NET_WM_MOVERESIZE_SIZE_LEFT;
|
||||
break;
|
||||
case Qt::TopLeftSection:
|
||||
section = _NET_WM_MOVERESIZE_SIZE_TOPLEFT;
|
||||
break;
|
||||
case Qt::TopSection:
|
||||
section = _NET_WM_MOVERESIZE_SIZE_TOP;
|
||||
break;
|
||||
case Qt::TopRightSection:
|
||||
section = _NET_WM_MOVERESIZE_SIZE_TOPRIGHT;
|
||||
break;
|
||||
case Qt::RightSection:
|
||||
section = _NET_WM_MOVERESIZE_SIZE_RIGHT;
|
||||
break;
|
||||
case Qt::BottomRightSection:
|
||||
section = _NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT;
|
||||
break;
|
||||
case Qt::BottomSection:
|
||||
section = _NET_WM_MOVERESIZE_SIZE_BOTTOM;
|
||||
break;
|
||||
case Qt::BottomLeftSection:
|
||||
section = _NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (section != -1)
|
||||
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