mirror of
https://github.com/barry-ran/QtScrcpy.git
synced 2025-04-21 03:55:04 +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
|
||||
|
||||
Window {
|
||||
id: window
|
||||
id: root
|
||||
visible: true
|
||||
flags: Qt.Window |Qt.FramelessWindowHint
|
||||
flags: Qt.Window | Qt.FramelessWindowHint | Qt.WindowMaximizeButtonHint
|
||||
width: 800
|
||||
height: 600
|
||||
color: "transparent"
|
||||
|
||||
// bg
|
||||
BorderImage {
|
||||
id: background
|
||||
property real backgroundRadius: 4
|
||||
property bool backgroundHasBorder: true
|
||||
property color backgroundColor: "#2E2F30"
|
||||
property color backgroundBorderColor: "#555656"
|
||||
|
||||
Rectangle {
|
||||
id: backgroundView
|
||||
anchors.fill: parent
|
||||
source: "qrc:/image/mainwindow/bg.png"
|
||||
border { left: 30; top: 30; right: 30; bottom: 30 }
|
||||
horizontalTileMode: BorderImage.Stretch
|
||||
verticalTileMode: BorderImage.Stretch
|
||||
color: root.backgroundColor
|
||||
radius: root.backgroundRadius
|
||||
clip: true
|
||||
antialiasing: true
|
||||
|
||||
border {
|
||||
color: root.backgroundHasBorder ? root.backgroundBorderColor : "transparent"
|
||||
width: root.backgroundHasBorder ? 1 : 0
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
|
@ -28,23 +37,7 @@ Window {
|
|||
|
||||
DragHandler {
|
||||
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 "mousetap/mousetap.h"
|
||||
#include "stream.h"
|
||||
#include "windowframelesshelper.h"
|
||||
|
||||
static Dialog *g_mainDlg = Q_NULLPTR;
|
||||
|
||||
|
@ -75,6 +76,10 @@ int main(int argc, char *argv[])
|
|||
QApplication app(argc, argv);
|
||||
QQmlApplicationEngine engine("qrc:/MainWindow.qml");
|
||||
|
||||
#ifdef Q_OS_WIN32
|
||||
WindowFramelessHelper::Instance()->Init();
|
||||
#endif
|
||||
|
||||
// windows下通过qmake VERSION变量或者rc设置版本号和应用名称后,这里可以直接拿到
|
||||
// mac下拿到的是CFBundleVersion的值
|
||||
qDebug() << app.applicationVersion();
|
||||
|
|
|
@ -2,8 +2,11 @@ FORMS +=
|
|||
|
||||
HEADERS += \
|
||||
$$PWD/keepratiowidget.h \
|
||||
$$PWD/magneticwidget.h
|
||||
$$PWD/magneticwidget.h \
|
||||
$$PWD/windowframelesshelper.h
|
||||
|
||||
|
||||
SOURCES += \
|
||||
$$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
Reference in a new issue