mirror of
https://github.com/barry-ran/QtScrcpy.git
synced 2025-08-03 22:28:39 +00:00
feat: add framelesshelper
This commit is contained in:
parent
960fccda8c
commit
b0d68c49a8
5 changed files with 315 additions and 28 deletions
|
@ -2,21 +2,30 @@ import QtQuick 2.12
|
||||||
import QtQuick.Window 2.12
|
import QtQuick.Window 2.12
|
||||||
|
|
||||||
Window {
|
Window {
|
||||||
id: window
|
id: root
|
||||||
visible: true
|
visible: true
|
||||||
flags: Qt.Window |Qt.FramelessWindowHint
|
flags: Qt.Window | Qt.FramelessWindowHint | Qt.WindowMaximizeButtonHint
|
||||||
width: 800
|
width: 800
|
||||||
height: 600
|
height: 600
|
||||||
color: "transparent"
|
color: "transparent"
|
||||||
|
|
||||||
// bg
|
property real backgroundRadius: 4
|
||||||
BorderImage {
|
property bool backgroundHasBorder: true
|
||||||
id: background
|
property color backgroundColor: "#2E2F30"
|
||||||
|
property color backgroundBorderColor: "#555656"
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: backgroundView
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
source: "qrc:/image/mainwindow/bg.png"
|
color: root.backgroundColor
|
||||||
border { left: 30; top: 30; right: 30; bottom: 30 }
|
radius: root.backgroundRadius
|
||||||
horizontalTileMode: BorderImage.Stretch
|
clip: true
|
||||||
verticalTileMode: BorderImage.Stretch
|
antialiasing: true
|
||||||
|
|
||||||
|
border {
|
||||||
|
color: root.backgroundHasBorder ? root.backgroundBorderColor : "transparent"
|
||||||
|
width: root.backgroundHasBorder ? 1 : 0
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
|
@ -28,23 +37,7 @@ Window {
|
||||||
|
|
||||||
DragHandler {
|
DragHandler {
|
||||||
grabPermissions: TapHandler.CanTakeOverFromAnything
|
grabPermissions: TapHandler.CanTakeOverFromAnything
|
||||||
onActiveChanged: if (active) { window.startSystemMove(); }
|
onActiveChanged: if (active) { root.startSystemMove(); }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DragHandler {
|
|
||||||
id: resizeHandler
|
|
||||||
grabPermissions: TapHandler.TakeOverForbidden
|
|
||||||
target: null
|
|
||||||
onActiveChanged:
|
|
||||||
if (active) {
|
|
||||||
const p = resizeHandler.centroid.position;
|
|
||||||
let e = 0;
|
|
||||||
if (p.x / width < 0.10) { e |= Qt.LeftEdge }
|
|
||||||
if (p.x / width > 0.90) { e |= Qt.RightEdge }
|
|
||||||
if (p.y / height > 0.90) { e |= Qt.BottomEdge }
|
|
||||||
console.log("RESIZING", e);
|
|
||||||
window.startSystemResize(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
#include "dialog.h"
|
#include "dialog.h"
|
||||||
#include "mousetap/mousetap.h"
|
#include "mousetap/mousetap.h"
|
||||||
#include "stream.h"
|
#include "stream.h"
|
||||||
|
#include "windowframelesshelper.h"
|
||||||
|
|
||||||
static Dialog *g_mainDlg = Q_NULLPTR;
|
static Dialog *g_mainDlg = Q_NULLPTR;
|
||||||
|
|
||||||
|
@ -75,6 +76,10 @@ int main(int argc, char *argv[])
|
||||||
QApplication app(argc, argv);
|
QApplication app(argc, argv);
|
||||||
QQmlApplicationEngine engine("qrc:/MainWindow.qml");
|
QQmlApplicationEngine engine("qrc:/MainWindow.qml");
|
||||||
|
|
||||||
|
#ifdef Q_OS_WIN32
|
||||||
|
WindowFramelessHelper::Instance()->Init();
|
||||||
|
#endif
|
||||||
|
|
||||||
// windows下通过qmake VERSION变量或者rc设置版本号和应用名称后,这里可以直接拿到
|
// windows下通过qmake VERSION变量或者rc设置版本号和应用名称后,这里可以直接拿到
|
||||||
// mac下拿到的是CFBundleVersion的值
|
// mac下拿到的是CFBundleVersion的值
|
||||||
qDebug() << app.applicationVersion();
|
qDebug() << app.applicationVersion();
|
||||||
|
|
|
@ -2,8 +2,11 @@ FORMS +=
|
||||||
|
|
||||||
HEADERS += \
|
HEADERS += \
|
||||||
$$PWD/keepratiowidget.h \
|
$$PWD/keepratiowidget.h \
|
||||||
$$PWD/magneticwidget.h
|
$$PWD/magneticwidget.h \
|
||||||
|
$$PWD/windowframelesshelper.h
|
||||||
|
|
||||||
|
|
||||||
SOURCES += \
|
SOURCES += \
|
||||||
$$PWD/keepratiowidget.cpp \
|
$$PWD/keepratiowidget.cpp \
|
||||||
$$PWD/magneticwidget.cpp
|
$$PWD/magneticwidget.cpp \
|
||||||
|
$$PWD/windowframelesshelper.cpp
|
||||||
|
|
254
QtScrcpy/uibase/windowframelesshelper.cpp
Normal file
254
QtScrcpy/uibase/windowframelesshelper.cpp
Normal file
|
@ -0,0 +1,254 @@
|
||||||
|
#include "windowframelesshelper.h"
|
||||||
|
|
||||||
|
#if defined(Q_OS_WIN)
|
||||||
|
#include <QCursor>
|
||||||
|
#include <QDebug>
|
||||||
|
#include <QGuiApplication>
|
||||||
|
#include <windows.h>
|
||||||
|
#include <windowsx.h>
|
||||||
|
|
||||||
|
WindowFramelessHelper::WindowFramelessHelper() {}
|
||||||
|
|
||||||
|
WindowFramelessHelper::~WindowFramelessHelper()
|
||||||
|
{
|
||||||
|
// do nothing, because this object is static instance
|
||||||
|
}
|
||||||
|
|
||||||
|
WindowFramelessHelper *WindowFramelessHelper::Instance()
|
||||||
|
{
|
||||||
|
static WindowFramelessHelper g_windowNativeEventFilter;
|
||||||
|
return &g_windowNativeEventFilter;
|
||||||
|
}
|
||||||
|
|
||||||
|
void WindowFramelessHelper::Init()
|
||||||
|
{
|
||||||
|
if (!m_inited) {
|
||||||
|
m_inited = true;
|
||||||
|
QGuiApplication::instance()->installNativeEventFilter(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WindowFramelessHelper::nativeEventFilter(const QByteArray &eventType, void *message, long *result)
|
||||||
|
{
|
||||||
|
Q_UNUSED(eventType);
|
||||||
|
|
||||||
|
MSG *param = static_cast<MSG *>(message);
|
||||||
|
if (!param) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (param->message) {
|
||||||
|
case WM_NCHITTEST: {
|
||||||
|
if (processNcHitTest(message, result)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
case WM_NCLBUTTONDOWN: {
|
||||||
|
if (processNcLButtonDown(message, result)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
case WM_SETCURSOR: {
|
||||||
|
if (processSetCursor(message, result)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WindowFramelessHelper::processNcHitTest(void *message, long *result)
|
||||||
|
{
|
||||||
|
MSG *param = static_cast<MSG *>(message);
|
||||||
|
if (!param) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
QWindow *window = getWindow((WId)param->hwnd);
|
||||||
|
if (!window) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 没有最大化&全屏按钮,则认为是固定尺寸窗口
|
||||||
|
if (!(window->flags() & Qt::WindowMaximizeButtonHint) && !(window->flags() & Qt::WindowFullscreenButtonHint)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
qreal dpi = window->devicePixelRatio();
|
||||||
|
if (dpi <= 0.99) {
|
||||||
|
dpi = 1.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
QPoint ptCursor = QCursor::pos();
|
||||||
|
int nX = ptCursor.x() - window->geometry().x();
|
||||||
|
int nY = ptCursor.y() - window->geometry().y();
|
||||||
|
|
||||||
|
*result = HTCLIENT;
|
||||||
|
|
||||||
|
if (Qt::WindowMaximized == window->windowState()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((window->windowStates() & Qt::WindowMaximized) || (window->windowStates() & Qt::WindowFullScreen)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
qDebug() << "processNcHitTest:" << ptCursor << window->geometry() << "d:" << nX;
|
||||||
|
int borderWidth = 5;
|
||||||
|
if ((nX > m_windowMargin.left()) && (nX < m_windowMargin.left() + borderWidth) && (nY > m_windowMargin.top())
|
||||||
|
&& (nY < m_windowMargin.top() + borderWidth)) {
|
||||||
|
*result = HTTOPLEFT;
|
||||||
|
} else if (
|
||||||
|
(nX > window->width() - m_windowMargin.right() - borderWidth) && (nX < window->width() - m_windowMargin.right()) && (nY > m_windowMargin.top())
|
||||||
|
&& (nY < m_windowMargin.top() + borderWidth)) {
|
||||||
|
*result = HTTOPRIGHT;
|
||||||
|
} else if (
|
||||||
|
(nX > m_windowMargin.left()) && (nX < m_windowMargin.left() + borderWidth) && (nY > window->height() - m_windowMargin.bottom() - borderWidth)
|
||||||
|
&& (nY < window->height() - m_windowMargin.bottom())) {
|
||||||
|
*result = HTBOTTOMLEFT;
|
||||||
|
} else if (
|
||||||
|
(nX > window->width() - m_windowMargin.right() - borderWidth) && (nX < window->width() - m_windowMargin.right())
|
||||||
|
&& (nY > window->height() - m_windowMargin.bottom() - borderWidth) && (nY < window->height() - m_windowMargin.bottom())) {
|
||||||
|
*result = HTBOTTOMRIGHT;
|
||||||
|
} else if ((nX > m_windowMargin.left()) && (nX < m_windowMargin.left() + borderWidth)) {
|
||||||
|
*result = HTLEFT;
|
||||||
|
} else if ((nX > window->width() - m_windowMargin.right() - borderWidth) && (nX < window->width() - m_windowMargin.right())) {
|
||||||
|
*result = HTRIGHT;
|
||||||
|
} else if ((nY > m_windowMargin.top()) && (nY < m_windowMargin.top() + borderWidth)) {
|
||||||
|
*result = HTTOP;
|
||||||
|
} else if ((nY > window->height() - m_windowMargin.bottom() - borderWidth) && (nY < window->height() - m_windowMargin.bottom())) {
|
||||||
|
*result = HTBOTTOM;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WindowFramelessHelper::processNcLButtonDown(void *message, long *result)
|
||||||
|
{
|
||||||
|
Q_UNUSED(result);
|
||||||
|
|
||||||
|
MSG *param = static_cast<MSG *>(message);
|
||||||
|
if (!param) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
QWindow *window = getWindow((WId)param->hwnd);
|
||||||
|
if (!window) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(window->flags() & Qt::WindowMaximizeButtonHint) && !(window->flags() & Qt::WindowFullscreenButtonHint)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((window->windowStates() & Qt::WindowMaximized) || (window->windowStates() & Qt::WindowFullScreen)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
HWND hwnd = param->hwnd;
|
||||||
|
WPARAM nHitTest = param->wParam;
|
||||||
|
if (nHitTest == HTTOP) {
|
||||||
|
::PostMessage(hwnd, WM_SYSCOMMAND, SC_SIZE | WMSZ_TOP, param->lParam);
|
||||||
|
} else if (nHitTest == HTBOTTOM) {
|
||||||
|
::PostMessage(hwnd, WM_SYSCOMMAND, SC_SIZE | WMSZ_BOTTOM, param->lParam);
|
||||||
|
} else if (nHitTest == HTLEFT) {
|
||||||
|
::PostMessage(hwnd, WM_SYSCOMMAND, SC_SIZE | WMSZ_LEFT, param->lParam);
|
||||||
|
} else if (nHitTest == HTRIGHT) {
|
||||||
|
::PostMessage(hwnd, WM_SYSCOMMAND, SC_SIZE | WMSZ_RIGHT, param->lParam);
|
||||||
|
} else if (nHitTest == HTTOPLEFT) {
|
||||||
|
::PostMessage(hwnd, WM_SYSCOMMAND, SC_SIZE | WMSZ_TOPLEFT, param->lParam);
|
||||||
|
} else if (nHitTest == HTTOPRIGHT) {
|
||||||
|
::PostMessage(hwnd, WM_SYSCOMMAND, SC_SIZE | WMSZ_TOPRIGHT, param->lParam);
|
||||||
|
} else if (nHitTest == HTBOTTOMLEFT) {
|
||||||
|
::PostMessage(hwnd, WM_SYSCOMMAND, SC_SIZE | WMSZ_BOTTOMLEFT, param->lParam);
|
||||||
|
} else if (nHitTest == HTBOTTOMRIGHT) {
|
||||||
|
::PostMessage(hwnd, WM_SYSCOMMAND, SC_SIZE | WMSZ_BOTTOMRIGHT, param->lParam);
|
||||||
|
} else if (nHitTest == HTCAPTION) {
|
||||||
|
::PostMessage(hwnd, WM_SYSCOMMAND, SC_MOVE + 1, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WindowFramelessHelper::processSetCursor(void *message, long *result)
|
||||||
|
{
|
||||||
|
Q_UNUSED(result);
|
||||||
|
|
||||||
|
MSG *param = static_cast<MSG *>(message);
|
||||||
|
if (!param) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
QWindow *window = getWindow((WId)param->hwnd);
|
||||||
|
if (!window) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(window->flags() & Qt::WindowMaximizeButtonHint) && !(window->flags() & Qt::WindowFullscreenButtonHint)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((window->windowStates() & Qt::WindowMaximized) || (window->windowStates() & Qt::WindowFullScreen)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// is invisible window
|
||||||
|
HWND hwnd = param->hwnd;
|
||||||
|
if (!::IsWindowVisible(hwnd)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// is not enabled window
|
||||||
|
if (!::IsWindowEnabled(hwnd)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// set cursor
|
||||||
|
HCURSOR hCursor = nullptr;
|
||||||
|
LPARAM hittest = LOWORD(param->lParam);
|
||||||
|
switch (hittest) {
|
||||||
|
case HTRIGHT:
|
||||||
|
case HTLEFT:
|
||||||
|
hCursor = LoadCursor(nullptr, IDC_SIZEWE);
|
||||||
|
break;
|
||||||
|
case HTTOP:
|
||||||
|
case HTBOTTOM:
|
||||||
|
hCursor = LoadCursor(nullptr, IDC_SIZENS);
|
||||||
|
break;
|
||||||
|
case HTTOPLEFT:
|
||||||
|
case HTBOTTOMRIGHT:
|
||||||
|
hCursor = LoadCursor(nullptr, IDC_SIZENWSE);
|
||||||
|
break;
|
||||||
|
case HTTOPRIGHT:
|
||||||
|
case HTBOTTOMLEFT:
|
||||||
|
hCursor = LoadCursor(nullptr, IDC_SIZENESW);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!hCursor) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
::SetCursor(hCursor);
|
||||||
|
::DestroyCursor(hCursor);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
QWindow *WindowFramelessHelper::getWindow(WId wndId)
|
||||||
|
{
|
||||||
|
QWindowList windows = QGuiApplication::topLevelWindows();
|
||||||
|
for (int i = 0; i < windows.size(); ++i) {
|
||||||
|
if (windows.at(i)->winId() == wndId) {
|
||||||
|
return windows.at(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif //(Q_OS_WIN)
|
32
QtScrcpy/uibase/windowframelesshelper.h
Normal file
32
QtScrcpy/uibase/windowframelesshelper.h
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
#pragma once
|
||||||
|
#include <QWindow>
|
||||||
|
|
||||||
|
#if defined(Q_OS_WIN)
|
||||||
|
#include <QAbstractNativeEventFilter>
|
||||||
|
#include <QMargins>
|
||||||
|
|
||||||
|
class WindowFramelessHelper : public QAbstractNativeEventFilter
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
WindowFramelessHelper();
|
||||||
|
~WindowFramelessHelper() override;
|
||||||
|
|
||||||
|
public:
|
||||||
|
static WindowFramelessHelper *Instance();
|
||||||
|
|
||||||
|
void Init();
|
||||||
|
bool nativeEventFilter(const QByteArray &eventType, void *message, long *result) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool processNcHitTest(void *message, long *result);
|
||||||
|
bool processNcLButtonDown(void *message, long *result);
|
||||||
|
bool processSetCursor(void *message, long *result);
|
||||||
|
|
||||||
|
QWindow *getWindow(WId wndId);
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool m_inited = false;
|
||||||
|
QMargins m_windowMargin = QMargins(0, 0, 0, 0);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // Q_OS_WIN
|
Loading…
Add table
Add a link
Reference in a new issue