Compare commits

..

No commits in common. "9dd9d10049e31d4b5abf6a49706d40c78dd9e100" and "217ceabbaa8518a9df924c3a5f2df46585ad41c8" have entirely different histories.

6 changed files with 58 additions and 233 deletions

View File

@ -13,7 +13,6 @@ static inline QByteArray qtNativeEventType()
static const auto result = "windows_generic_MSG";
return result;
}
static inline bool isCompositionEnabled(){
typedef HRESULT (WINAPI* DwmIsCompositionEnabledPtr)(BOOL *pfEnabled);
HMODULE module = LoadLibraryW(L"dwmapi.dll");
@ -33,7 +32,7 @@ static inline bool isCompositionEnabled(){
static inline void showShadow(HWND hwnd){
if(isCompositionEnabled()){
const MARGINS shadow = { 1, 0, 0, 0 };
const MARGINS shadow = { 1, 1, 1, 1 };
typedef HRESULT (WINAPI* DwmExtendFrameIntoClientAreaPtr)(HWND hWnd, const MARGINS *pMarInset);
HMODULE module = LoadLibraryW(L"dwmapi.dll");
if (module)
@ -53,14 +52,14 @@ static inline void showShadow(HWND hwnd){
#endif
FramelessEventFilter::FramelessEventFilter(FluFramelessHelper* helper){
_helper = helper;
_current = _helper->window->winId();
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 || _helper.isNull() || _helper->window.isNull()) {
if ((eventType != qtNativeEventType()) || !message || !result || !_window) {
return false;
}
const auto msg = static_cast<const MSG *>(message);
@ -103,27 +102,6 @@ bool FramelessEventFilter::nativeEventFilter(const QByteArray &eventType, void *
return true;
}
return false;
}else if(uMsg == WM_NCHITTEST){
if(_helper->hoverMaxBtn() && _helper->resizeable()){
if (*result == HTNOWHERE) {
*result = HTZOOM;
}
return true;
}
return false;
}else if(uMsg == WM_NCLBUTTONDBLCLK || uMsg == WM_NCLBUTTONDOWN){
if(_helper->hoverMaxBtn() && _helper->resizeable()){
QMouseEvent event = QMouseEvent(QEvent::MouseButtonPress, QPoint(), QPoint(), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier);
QGuiApplication::sendEvent(_helper->maximizeButton(),&event);
return true;
}
return false;
}else if(uMsg == WM_NCLBUTTONUP || uMsg == WM_NCRBUTTONUP){
if(_helper->hoverMaxBtn() && _helper->resizeable()){
QMouseEvent event = QMouseEvent(QEvent::MouseButtonRelease, QPoint(), QPoint(), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier);
QGuiApplication::sendEvent(_helper->maximizeButton(),&event);
}
return false;
}
return false;
#endif
@ -133,60 +111,56 @@ bool FramelessEventFilter::nativeEventFilter(const QByteArray &eventType, void *
FluFramelessHelper::FluFramelessHelper(QObject *parent)
: QObject{parent}
{
}
void FluFramelessHelper::classBegin(){
}
void FluFramelessHelper::_updateCursor(int edges){
void FluFramelessHelper::updateCursor(int edges){
switch (edges) {
case 0:
window->setCursor(Qt::ArrowCursor);
_window->setCursor(Qt::ArrowCursor);
break;
case Qt::LeftEdge:
case Qt::RightEdge:
window->setCursor(Qt::SizeHorCursor);
_window->setCursor(Qt::SizeHorCursor);
break;
case Qt::TopEdge:
case Qt::BottomEdge:
window->setCursor(Qt::SizeVerCursor);
_window->setCursor(Qt::SizeVerCursor);
break;
case Qt::LeftEdge | Qt::TopEdge:
case Qt::RightEdge | Qt::BottomEdge:
window->setCursor(Qt::SizeFDiagCursor);
_window->setCursor(Qt::SizeFDiagCursor);
break;
case Qt::RightEdge | Qt::TopEdge:
case Qt::LeftEdge | Qt::BottomEdge:
window->setCursor(Qt::SizeBDiagCursor);
_window->setCursor(Qt::SizeBDiagCursor);
break;
}
}
bool FluFramelessHelper::eventFilter(QObject *obj, QEvent *ev){
if (!window.isNull() && window->flags() & Qt::FramelessWindowHint) {
if (!_window.isNull() && _window->flags() & Qt::FramelessWindowHint) {
static int edges = 0;
const int margin = 8;
switch (ev->type()) {
case QEvent::MouseButtonPress:
if(edges!=0){
QMouseEvent *event = static_cast<QMouseEvent*>(ev);
if(event->button() == Qt::LeftButton){
_updateCursor(edges);
window->startSystemResize(Qt::Edges(edges));
}
updateCursor(edges);
_window->startSystemResize(Qt::Edges(edges));
}
break;
case QEvent::MouseButtonRelease:
edges = 0;
_updateCursor(edges);
updateCursor(edges);
break;
case QEvent::MouseMove: {
if(_maximized() || _fullScreen()){
if(_window->visibility() == QWindow::Maximized || _window->visibility() == QWindow::FullScreen){
break;
}
if(!resizeable()){
if(_window->width() == _window->maximumWidth() && _window->width() == _window->minimumWidth() && _window->height() == _window->maximumHeight() && _window->height() == _window->minimumHeight()){
break;
}
QMouseEvent *event = static_cast<QMouseEvent*>(ev);
@ -196,10 +170,10 @@ bool FluFramelessHelper::eventFilter(QObject *obj, QEvent *ev){
#else
event->position().toPoint();
#endif
if(p.x() >= margin && p.x() <= (window->width() - margin) && p.y() >= margin && p.y() <= (window->height() - margin)){
if(p.x() >= margin && p.x() <= (_window->width() - margin) && p.y() >= margin && p.y() <= (_window->height() - margin)){
if(edges != 0){
edges = 0;
_updateCursor(edges);
updateCursor(edges);
}
break;
}
@ -207,16 +181,16 @@ bool FluFramelessHelper::eventFilter(QObject *obj, QEvent *ev){
if ( p.x() < margin ) {
edges |= Qt::LeftEdge;
}
if ( p.x() > (window->width() - margin) ) {
if ( p.x() > (_window->width() - margin) ) {
edges |= Qt::RightEdge;
}
if ( p.y() < margin ) {
edges |= Qt::TopEdge;
}
if ( p.y() > (window->height() - margin) ) {
if ( p.y() > (_window->height() - margin) ) {
edges |= Qt::BottomEdge;
}
_updateCursor(edges);
updateCursor(edges);
break;
}
default:
@ -229,66 +203,39 @@ bool FluFramelessHelper::eventFilter(QObject *obj, QEvent *ev){
void FluFramelessHelper::componentComplete(){
auto o = parent();
while (nullptr != o) {
window = (QQuickWindow*)o;
_window = (QQuickWindow*)o;
o = o->parent();
}
if(!window.isNull()){
window->setFlags(Qt::FramelessWindowHint|Qt::Window|Qt::WindowTitleHint|Qt::WindowMinMaxButtonsHint|Qt::WindowCloseButtonHint);
if(!_window.isNull()){
_window->setFlags(Qt::FramelessWindowHint|Qt::Window|Qt::WindowTitleHint|Qt::WindowMinMaxButtonsHint|Qt::WindowCloseButtonHint);
#ifdef Q_OS_WIN
_nativeEvent =new FramelessEventFilter(this);
_nativeEvent =new FramelessEventFilter(_window);
qApp->installNativeEventFilter(_nativeEvent);
HWND hwnd = reinterpret_cast<HWND>(window->winId());
HWND hwnd = reinterpret_cast<HWND>(_window->winId());
SetWindowPos(hwnd,0,0,0,0,0,SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED | SWP_NOOWNERZORDER);
showShadow(hwnd);
#endif
_stayTop = QQmlProperty(window,"stayTop");
_stayTop = QQmlProperty(_window,"stayTop");
_onStayTopChange();
_stayTop.connectNotifySignal(this,SLOT(_onStayTopChange()));
_screen = QQmlProperty(window,"screen");
_screen = QQmlProperty(_window,"screen");
_screen.connectNotifySignal(this,SLOT(_onScreenChanged()));
window->installEventFilter(this);
_window->installEventFilter(this);
}
}
void FluFramelessHelper::_onScreenChanged(){
#ifdef Q_OS_WIN
HWND hwnd = reinterpret_cast<HWND>(window->winId());
HWND hwnd = reinterpret_cast<HWND>(_window->winId());
SetWindowPos(hwnd,0,0,0,0,0,SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED | SWP_NOOWNERZORDER);
RedrawWindow(hwnd, NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW);
#endif
}
void FluFramelessHelper::showSystemMenu(){
#ifdef Q_OS_WIN
QPoint point = QCursor::pos();
HWND hwnd = reinterpret_cast<HWND>(window->winId());
DWORD style = GetWindowLongPtr(hwnd,GWL_STYLE);
SetWindowLongPtr(hwnd, GWL_STYLE, style | WS_THICKFRAME | WS_CAPTION | WS_SYSMENU | WS_MAXIMIZEBOX);
const HMENU hMenu = ::GetSystemMenu(hwnd, FALSE);
DeleteMenu(hMenu, SC_MOVE, MF_BYCOMMAND);
DeleteMenu(hMenu, SC_SIZE, MF_BYCOMMAND);
if(_maximized() || _fullScreen()){
EnableMenuItem(hMenu,SC_RESTORE,MFS_ENABLED);
}else{
EnableMenuItem(hMenu,SC_RESTORE,MFS_DISABLED);
}
if(resizeable() && !_maximized() && !_fullScreen()){
EnableMenuItem(hMenu,SC_MAXIMIZE,MFS_ENABLED);
}else{
EnableMenuItem(hMenu,SC_MAXIMIZE,MFS_DISABLED);
}
const int result = TrackPopupMenu(hMenu, (TPM_RETURNCMD | (QGuiApplication::isRightToLeft() ? TPM_RIGHTALIGN : TPM_LEFTALIGN)), point.x(), point.y(), 0, hwnd, nullptr);
if (result != FALSE) {
PostMessageW(hwnd, WM_SYSCOMMAND, result, 0);
}
SetWindowLongPtr(hwnd, GWL_STYLE, style | WS_THICKFRAME | WS_CAPTION &~ WS_SYSMENU);
#endif
}
void FluFramelessHelper::_onStayTopChange(){
bool isStayTop = _stayTop.read().toBool();
#ifdef Q_OS_WIN
HWND hwnd = reinterpret_cast<HWND>(window->winId());
HWND hwnd = reinterpret_cast<HWND>(_window->winId());
DWORD style = GetWindowLongPtr(hwnd,GWL_STYLE);
SetWindowLongPtr(hwnd, GWL_STYLE, style | WS_THICKFRAME | WS_CAPTION &~ WS_SYSMENU);
if(isStayTop){
@ -297,55 +244,16 @@ void FluFramelessHelper::_onStayTopChange(){
SetWindowPos(hwnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
}
#else
window->setFlag(Qt::WindowStaysOnTopHint,isStayTop);
_window->setFlag(Qt::WindowStaysOnTopHint,isStayTop);
#endif
}
FluFramelessHelper::~FluFramelessHelper(){
if (!window.isNull()) {
window->setFlags(Qt::Window);
if (!_window.isNull()) {
_window->setFlags(Qt::Window);
#ifdef Q_OS_WIN
qApp->removeNativeEventFilter(_nativeEvent);
delete _nativeEvent;
#endif
window->removeEventFilter(this);
_window->removeEventFilter(this);
}
}
bool FluFramelessHelper::hoverMaxBtn(){
QVariant appBar = window->property("appBar");
if(appBar.isNull()){
return false;
}
QVariant var;
QMetaObject::invokeMethod(appBar.value<QObject*>(), "maximizeButtonHover",Q_RETURN_ARG(QVariant, var));
if(var.isNull()){
return false;
}
return var.toBool();
}
QObject* FluFramelessHelper::maximizeButton(){
QVariant appBar = window->property("appBar");
if(appBar.isNull()){
return nullptr;
}
QVariant var;
QMetaObject::invokeMethod(appBar.value<QObject*>(), "maximizeButton",Q_RETURN_ARG(QVariant, var));
if(var.isNull()){
return nullptr;
}
return var.value<QObject*>();
}
bool FluFramelessHelper::resizeable(){
return !(window->width() == window->maximumWidth() && window->width() == window->minimumWidth() && window->height() == window->maximumHeight() && window->height() == window->minimumHeight());
}
bool FluFramelessHelper::_maximized(){
return window->visibility() == QWindow::Maximized;
}
bool FluFramelessHelper::_fullScreen(){
return window->visibility() == QWindow::FullScreen;
}

View File

@ -15,15 +15,13 @@ using QT_NATIVE_EVENT_RESULT_TYPE = long;
using QT_ENTER_EVENT_TYPE = QEvent;
#endif
class FluFramelessHelper;
class FramelessEventFilter : public QAbstractNativeEventFilter
{
public:
FramelessEventFilter(FluFramelessHelper* helper);
FramelessEventFilter(QQuickWindow* window);
bool nativeEventFilter(const QByteArray &eventType, void *message, QT_NATIVE_EVENT_RESULT_TYPE *result) override;
public:
QPointer<FluFramelessHelper> _helper = nullptr;
QQuickWindow* _window = nullptr;
qint64 _current = 0;
};
@ -36,21 +34,14 @@ public:
~FluFramelessHelper();
void classBegin() override;
void componentComplete() override;
bool hoverMaxBtn();
bool resizeable();
QObject* maximizeButton();
Q_INVOKABLE void showSystemMenu();
protected:
bool eventFilter(QObject *obj, QEvent *event) override;
private:
void _updateCursor(int edges);
bool _maximized();
bool _fullScreen();
void updateCursor(int edges);
Q_SLOT void _onStayTopChange();
Q_SLOT void _onScreenChanged();
public:
QPointer<QQuickWindow> window = nullptr;
private:
QPointer<QQuickWindow> _window = nullptr;
FramelessEventFilter* _nativeEvent = nullptr;
QQmlProperty _stayTop;
QQmlProperty _screen;

View File

@ -64,11 +64,6 @@ Rectangle{
FluTheme.darkMode = FluThemeType.Dark
}
}
property var systemMenuListener: function(){
if(d.win instanceof FluWindow){
d.win.showSystemMenu()
}
}
id:control
color: Qt.rgba(0,0,0,0)
height: visible ? 30 : 0
@ -76,7 +71,6 @@ Rectangle{
z: 65535
Item{
id:d
property bool hoverMaxBtn: false
property var win: Window.window
property bool stayTop: {
if(d.win instanceof FluWindow){
@ -89,23 +83,14 @@ Rectangle{
}
MouseArea{
anchors.fill: parent
onPositionChanged:
(mouse)=>{
onPositionChanged: {
d.win.startSystemMove()
}
onDoubleClicked:
(mouse)=>{
if(d.resizable && Qt.LeftButton){
onDoubleClicked: {
if(d.resizable){
btn_maximize.clicked()
}
}
acceptedButtons: Qt.LeftButton|Qt.RightButton
onClicked:
(mouse)=>{
if (mouse.button === Qt.RightButton){
control.systemMenuListener()
}
}
}
Row{
anchors{
@ -233,9 +218,6 @@ Rectangle{
if(pressed){
return maximizePressColor
}
if(FluTools.isWin() && !FluApp.useSystemAppBar){
return d.hoverMaxBtn ? maximizeHoverColor : maximizeNormalColor
}
return hovered ? maximizeHoverColor : maximizeNormalColor
}
Layout.alignment: Qt.AlignVCenter
@ -281,17 +263,4 @@ Rectangle{
function darkButton(){
return btn_dark
}
function maximizeButtonHover(){
var hover = false;
var pos = btn_maximize.mapToGlobal(0,0)
if(btn_maximize.visible){
var rect = Qt.rect(pos.x,pos.y,btn_maximize.width,btn_maximize.height)
pos = FluTools.cursorPos()
if(pos.x>rect.x && pos.x<(rect.x+rect.width) && pos.y>rect.y && pos.y<(rect.y+rect.height)){
hover = true;
}
}
d.hoverMaxBtn = hover
return hover;
}
}

View File

@ -50,7 +50,6 @@ Window {
event.accepted = false
}
}
signal showSystemMenu
signal initArgument(var argument)
signal firstVisible()
id:window
@ -59,7 +58,7 @@ Window {
moveWindowToDesktopCenter()
useSystemAppBar = FluApp.useSystemAppBar
if(!useSystemAppBar){
loader_frameless_helper.sourceComponent = com_frameless
loader_frameless.sourceComponent = com_frameless
}
lifecycle.onCompleted(window)
initArgument(argument)
@ -72,11 +71,6 @@ Window {
Component.onDestruction: {
lifecycle.onDestruction()
}
onShowSystemMenu: {
if(loader_frameless_helper.item){
loader_frameless_helper.item.showSystemMenu()
}
}
onVisibleChanged: {
if(visible && d.isFirstVisible){
window.firstVisible()
@ -171,7 +165,7 @@ Window {
}
}
FluLoader{
id:loader_frameless_helper
id:loader_frameless
}
Item{
id:layout_container

View File

@ -64,11 +64,6 @@ Rectangle{
FluTheme.darkMode = FluThemeType.Dark
}
}
property var systemMenuListener: function(){
if(d.win instanceof FluWindow){
d.win.showSystemMenu()
}
}
id:control
color: Qt.rgba(0,0,0,0)
height: visible ? 30 : 0
@ -76,7 +71,6 @@ Rectangle{
z: 65535
Item{
id:d
property bool hoverMaxBtn: false
property var win: Window.window
property bool stayTop: {
if(d.win instanceof FluWindow){
@ -89,23 +83,14 @@ Rectangle{
}
MouseArea{
anchors.fill: parent
onPositionChanged:
(mouse)=>{
onPositionChanged: {
d.win.startSystemMove()
}
onDoubleClicked:
(mouse)=>{
if(d.resizable && Qt.LeftButton){
onDoubleClicked: {
if(d.resizable){
btn_maximize.clicked()
}
}
acceptedButtons: Qt.LeftButton|Qt.RightButton
onClicked:
(mouse)=>{
if (mouse.button === Qt.RightButton){
control.systemMenuListener()
}
}
}
Row{
anchors{
@ -233,9 +218,6 @@ Rectangle{
if(pressed){
return maximizePressColor
}
if(FluTools.isWin() && !FluApp.useSystemAppBar){
return d.hoverMaxBtn ? maximizeHoverColor : maximizeNormalColor
}
return hovered ? maximizeHoverColor : maximizeNormalColor
}
Layout.alignment: Qt.AlignVCenter
@ -281,17 +263,4 @@ Rectangle{
function darkButton(){
return btn_dark
}
function maximizeButtonHover(){
var hover = false;
var pos = btn_maximize.mapToGlobal(0,0)
if(btn_maximize.visible){
var rect = Qt.rect(pos.x,pos.y,btn_maximize.width,btn_maximize.height)
pos = FluTools.cursorPos()
if(pos.x>rect.x && pos.x<(rect.x+rect.width) && pos.y>rect.y && pos.y<(rect.y+rect.height)){
hover = true;
}
}
d.hoverMaxBtn = hover
return hover;
}
}

View File

@ -49,7 +49,6 @@ Window {
event.accepted = false
}
}
signal showSystemMenu
signal initArgument(var argument)
signal firstVisible()
id:window
@ -58,7 +57,7 @@ Window {
moveWindowToDesktopCenter()
useSystemAppBar = FluApp.useSystemAppBar
if(!useSystemAppBar){
loader_frameless_helper.sourceComponent = com_frameless
loader_frameless.sourceComponent = com_frameless
}
lifecycle.onCompleted(window)
initArgument(argument)
@ -71,11 +70,6 @@ Window {
Component.onDestruction: {
lifecycle.onDestruction()
}
onShowSystemMenu: {
if(loader_frameless_helper.item){
loader_frameless_helper.item.showSystemMenu()
}
}
onVisibleChanged: {
if(visible && d.isFirstVisible){
window.firstVisible()
@ -170,7 +164,7 @@ Window {
}
}
FluLoader{
id:loader_frameless_helper
id:loader_frameless
}
Item{
id:layout_container