FluentUI/src/FluFrameless.cpp

222 lines
6.5 KiB
C++
Raw Normal View History

2023-12-11 23:47:03 +08:00
#include "FluFrameless.h"
#include <QGuiApplication>
2023-12-16 15:25:37 +08:00
#include <QOperatingSystemVersion>
2023-12-13 21:28:21 +08:00
#ifdef Q_OS_WIN
#pragma comment(lib, "user32.lib")
#include <windows.h>
static inline QByteArray qtNativeEventType()
{
static const auto result = "windows_generic_MSG";
return result;
}
2023-12-18 21:29:38 +08:00
static inline bool isCompositionEnabled(){
typedef HRESULT (WINAPI* DwmIsCompositionEnabledPtr)(BOOL *pfEnabled);
HMODULE module = LoadLibraryW(L"dwmapi.dll");
if (module)
{
BOOL composition_enabled = false;
DwmIsCompositionEnabledPtr dwm_is_composition_enabled;
dwm_is_composition_enabled= reinterpret_cast<DwmIsCompositionEnabledPtr>(GetProcAddress(module, "DwmIsCompositionEnabled"));
if (dwm_is_composition_enabled)
{
dwm_is_composition_enabled(&composition_enabled);
}
return composition_enabled;
}
return false;
}
2023-12-18 21:32:56 +08:00
#endif
2023-12-18 21:29:38 +08:00
2023-12-13 21:28:21 +08:00
FramelessEventFilter::FramelessEventFilter(QQuickWindow* window){
_window = window;
_current = window->winId();
}
bool FramelessEventFilter::nativeEventFilter(const QByteArray &eventType, void *message, QT_NATIVE_EVENT_RESULT_TYPE *result){
#ifdef Q_OS_WIN
if ((eventType != qtNativeEventType()) || !message || !result || !_window) {
return false;
}
const auto msg = static_cast<const MSG *>(message);
2023-12-18 21:29:38 +08:00
const HWND hwnd = msg->hwnd;
if (!hwnd) {
2023-12-13 21:28:21 +08:00
return false;
}
2023-12-18 21:29:38 +08:00
const qint64 wid = reinterpret_cast<qint64>(hwnd);
2023-12-13 21:28:21 +08:00
if(wid != _current){
return false;
}
const UINT uMsg = msg->message;
2023-12-18 21:29:38 +08:00
const WPARAM wParam = msg->wParam;
const LPARAM lParam = msg->lParam;
if (!msg || !hwnd)
2023-12-13 21:28:21 +08:00
{
return false;
}
if(uMsg == WM_WINDOWPOSCHANGING){
2023-12-18 21:29:38 +08:00
WINDOWPOS* wp = reinterpret_cast<WINDOWPOS*>(lParam);
2023-12-13 21:28:21 +08:00
if (wp != nullptr && (wp->flags & SWP_NOSIZE) == 0)
{
wp->flags |= SWP_NOCOPYBITS;
2023-12-18 21:29:38 +08:00
*result = DefWindowProc(hwnd, uMsg, wParam, lParam);
2023-12-13 21:28:21 +08:00
return true;
}
return false;
2023-12-15 11:25:54 +08:00
}else if(uMsg == WM_NCCALCSIZE){
*result = WVR_REDRAW;
return true;
2023-12-16 15:25:37 +08:00
}else if(uMsg == WM_NCPAINT){
2023-12-18 21:29:38 +08:00
if(!isCompositionEnabled()){
*result = WVR_REDRAW;
return true;
}
2023-12-16 15:25:37 +08:00
return false;
2023-12-18 21:29:38 +08:00
}else if(uMsg == WM_NCACTIVATE){
2023-12-18 23:56:28 +08:00
if(!isCompositionEnabled()){
*result = 1;
return true;
2023-12-18 21:29:38 +08:00
}
2023-12-18 23:56:28 +08:00
return false;
2023-12-13 21:28:21 +08:00
}
return false;
#endif
return false;
}
2023-12-11 23:47:03 +08:00
FluFrameless::FluFrameless(QObject *parent)
: QObject{parent}
{
}
void FluFrameless::classBegin(){
}
2023-12-13 16:20:09 +08:00
void FluFrameless::updateCursor(int edges){
2023-12-11 23:47:03 +08:00
switch (edges) {
case 0:
2023-12-13 23:43:01 +08:00
_window->setCursor(Qt::ArrowCursor);
2023-12-11 23:47:03 +08:00
break;
case Qt::LeftEdge:
case Qt::RightEdge:
2023-12-13 23:43:01 +08:00
_window->setCursor(Qt::SizeHorCursor);
2023-12-11 23:47:03 +08:00
break;
case Qt::TopEdge:
case Qt::BottomEdge:
2023-12-13 23:43:01 +08:00
_window->setCursor(Qt::SizeVerCursor);
2023-12-11 23:47:03 +08:00
break;
case Qt::LeftEdge | Qt::TopEdge:
case Qt::RightEdge | Qt::BottomEdge:
2023-12-13 23:43:01 +08:00
_window->setCursor(Qt::SizeFDiagCursor);
2023-12-11 23:47:03 +08:00
break;
case Qt::RightEdge | Qt::TopEdge:
case Qt::LeftEdge | Qt::BottomEdge:
2023-12-13 23:43:01 +08:00
_window->setCursor(Qt::SizeBDiagCursor);
2023-12-11 23:47:03 +08:00
break;
}
}
bool FluFrameless::eventFilter(QObject *obj, QEvent *ev){
2023-12-18 21:29:38 +08:00
if (!_window.isNull()) {
2023-12-16 15:25:37 +08:00
2023-12-13 16:20:09 +08:00
static int edges = 0;
2023-12-11 23:47:03 +08:00
const int margin = 8;
switch (ev->type()) {
case QEvent::MouseButtonPress:
2023-12-13 16:20:09 +08:00
if(edges!=0){
updateCursor(edges);
_window->startSystemResize(Qt::Edges(edges));
}
2023-12-11 23:47:03 +08:00
break;
case QEvent::MouseButtonRelease:
2023-12-13 21:28:21 +08:00
edges = 0;
2023-12-11 23:47:03 +08:00
updateCursor(edges);
break;
case QEvent::MouseMove: {
2023-12-13 16:20:09 +08:00
if(_window->visibility() == QWindow::Maximized || _window->visibility() == QWindow::FullScreen){
break;
}
if(_window->width() == _window->maximumWidth() && _window->width() == _window->minimumWidth() && _window->height() == _window->maximumHeight() && _window->height() == _window->minimumHeight()){
break;
}
2023-12-11 23:47:03 +08:00
QMouseEvent *event = static_cast<QMouseEvent*>(ev);
QPoint p =
#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
event->pos();
#else
event->position().toPoint();
#endif
2023-12-13 23:43:01 +08:00
if(p.x() >= margin && p.x() <= (_window->width() - margin) && p.y() >= margin && p.y() <= (_window->height() - margin)){
if(edges != 0){
edges = 0;
updateCursor(edges);
}
break;
}
edges = 0;
2023-12-11 23:47:03 +08:00
if ( p.x() < margin ) {
edges |= Qt::LeftEdge;
}
if ( p.x() > (_window->width() - margin) ) {
edges |= Qt::RightEdge;
}
if ( p.y() < margin ) {
edges |= Qt::TopEdge;
}
if ( p.y() > (_window->height() - margin) ) {
edges |= Qt::BottomEdge;
}
updateCursor(edges);
break;
}
default:
break;
}
}
return QObject::eventFilter(obj, ev);
}
void FluFrameless::componentComplete(){
auto o = parent();
while (nullptr != o) {
_window = (QQuickWindow*)o;
o = o->parent();
}
if(!_window.isNull()){
2023-12-13 21:28:21 +08:00
#ifdef Q_OS_WIN
_nativeEvent =new FramelessEventFilter(_window);
qApp->installNativeEventFilter(_nativeEvent);
2023-12-15 22:41:11 +08:00
HWND hwnd = reinterpret_cast<HWND>(_window->winId());
ULONG_PTR cNewStyle = GetClassLongPtr(hwnd, GCL_STYLE) | CS_DROPSHADOW;
SetClassLongPtr(hwnd, GCL_STYLE, cNewStyle);
2023-12-18 21:29:38 +08:00
DWORD style = GetWindowLongPtr(hwnd,GWL_STYLE);
SetWindowLongPtr(hwnd,GWL_STYLE,style &~ WS_SYSMENU);
2023-12-15 22:41:11 +08:00
SetWindowPos(hwnd,nullptr,0,0,0,0,SWP_NOZORDER | SWP_NOOWNERZORDER | SWP_NOMOVE | SWP_NOSIZE |SWP_FRAMECHANGED);
2023-12-18 22:24:24 +08:00
_stayTop = QQmlProperty(_window,"stayTop");
_stayTop.connectNotifySignal(this,SLOT(_stayTopChange()));
2023-12-18 21:29:38 +08:00
#else
_window->setFlag(Qt::FramelessWindowHint,true);
2023-12-13 21:28:21 +08:00
#endif
2023-12-18 21:29:38 +08:00
_window->installEventFilter(this);
2023-12-11 23:47:03 +08:00
}
}
2023-12-18 22:24:24 +08:00
void FluFrameless::_stayTopChange(){
#ifdef Q_OS_WIN
HWND hwnd = reinterpret_cast<HWND>(_window->winId());
DWORD style = GetWindowLongPtr(hwnd,GWL_STYLE);
SetWindowLongPtr(hwnd,GWL_STYLE,style &~ WS_SYSMENU);
#endif
}
2023-12-11 23:47:03 +08:00
FluFrameless::~FluFrameless(){
if (!_window.isNull()) {
2023-12-13 16:20:09 +08:00
_window->removeEventFilter(this);
2023-12-13 21:28:21 +08:00
#ifdef Q_OS_WIN
qApp->removeNativeEventFilter(_nativeEvent);
2023-12-18 21:29:38 +08:00
#else
_window->setFlag(Qt::FramelessWindowHint,false);
2023-12-13 21:28:21 +08:00
#endif
2023-12-11 23:47:03 +08:00
}
}