Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

sync: from linuxdeepin/dtkgui #80

Merged
merged 1 commit into from
Nov 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
158 changes: 129 additions & 29 deletions src/kernel/dplatformhandle.cpp
Original file line number Diff line number Diff line change
@@ -1,21 +1,29 @@
// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd.
// SPDX-FileCopyrightText: 2022-2024 UnionTech Software Technology Co., Ltd.
//
// SPDX-License-Identifier: LGPL-3.0-or-later

#define protected public
#include <QWindow>
#undef protected

#include "dguiapplicationhelper.h"
#include "dplatformhandle.h"
#include "dplatformtheme.h"
#include "dwindowmanagerhelper.h"
#include "dvtablehook.h"
#ifndef DTK_DISABLE_TREELAND
#include "wayland/personalizationwaylandclientextension.h"
#endif
#include <private/qwaylandwindow_p.h>
#include <QtWaylandClient/private/qwaylandwindow_p.h>
#include <dtkcore_global.h>

#include <QWindow>
#include <QGuiApplication>
#include <QDebug>
#include <QPlatformSurfaceEvent>
#include <QStyleHints>

DCORE_USE_NAMESPACE

DGUI_BEGIN_NAMESPACE

Expand Down Expand Up @@ -635,39 +643,123 @@ class Q_DECL_HIDDEN CreatorWindowEventFilter : public QObject {
}
};

// only for TreeLand
class Q_DECL_HIDDEN MoveWindowEventFilter : public QObject {
bool m_windowMoving = false;
public:
MoveWindowEventFilter(QObject *par= nullptr): QObject(par){}
class MoveWindowHelper : public QObject
{
public:
bool eventFilter(QObject *watched, QEvent *event) override {
if (auto *w = qobject_cast<QWindow *>(watched); w) {
bool is_mouse_move = event->type() == QEvent::MouseMove && static_cast<QMouseEvent*>(event)->buttons() == Qt::LeftButton;
explicit MoveWindowHelper(QWindow *w);
~MoveWindowHelper();

if (event->type() == QEvent::MouseButtonRelease) {
m_windowMoving = false;
}
if (event->type() == QEvent::MouseButtonPress) {
m_windowMoving = false;
}
static QHash<const QWindow*, MoveWindowHelper*> mapped;

// FIXME: We need to check whether the event is accepted.
// Only when the upper control does not accept the event,
// the window should be moved through the window.
// But every event here has been accepted. I don't know what happened.
if (is_mouse_move && w->geometry().contains(static_cast<QMouseEvent*>(event)->globalPos())) {
if (!m_windowMoving) {
m_windowMoving = true;
private:
static bool windowEvent(QWindow *w, QEvent *event);
void updateEnableSystemMoveFromProperty();

event->accept();
static_cast<QPlatformWindow *>(w->handle())->startSystemMove();
}
QWindow *m_window;
bool m_windowMoving;
bool m_enableSystemMove;
};

QHash<const QWindow*, MoveWindowHelper*> MoveWindowHelper::mapped;

MoveWindowHelper::MoveWindowHelper(QWindow *window)
: QObject(window)
, m_window(window)
{
mapped[window] = this;
updateEnableSystemMoveFromProperty();
}

MoveWindowHelper::~MoveWindowHelper()
{
if (DVtableHook::hasVtable(m_window)) {
DVtableHook::resetVtable(m_window);
}

mapped.remove(qobject_cast<QWindow*>(parent()));
}

void MoveWindowHelper::updateEnableSystemMoveFromProperty()
{
if (!m_window) {
return;
}
const QVariant &v = m_window->property("_d_enableSystemMove");

m_enableSystemMove = !v.isValid() || v.toBool();

if (m_enableSystemMove) {
DVtableHook::overrideVfptrFun(m_window, &QWindow::event, &MoveWindowHelper::windowEvent);
} else if (DVtableHook::hasVtable(m_window)) {
DVtableHook::resetVfptrFun(m_window, &QWindow::event);
}
}

bool MoveWindowHelper::windowEvent(QWindow *w, QEvent *event)
{
MoveWindowHelper *self = mapped.value(w);

if (!self)
return DVtableHook::callOriginalFun(w, &QWindow::event, event);
// m_window 的 event 被 override 以后,在 windowEvent 里面获取到的 this 就成 m_window 了,
// 而不是 DNoTitlebarWlWindowHelper,所以此处 windowEvent 改为 static 并传 self 进来
{
static bool isTouchDown = false;
static QPointF touchBeginPosition;
if (event->type() == QEvent::TouchBegin) {
isTouchDown = true;
}
if (event->type() == QEvent::TouchEnd || event->type() == QEvent::MouseButtonRelease) {
isTouchDown = false;
}
if (isTouchDown && event->type() == QEvent::MouseButtonPress) {
touchBeginPosition = static_cast<QMouseEvent*>(event)->globalPos();
}
// add some redundancy to distinguish trigger between system menu and system move
if (event->type() == QEvent::MouseMove) {
QPointF currentPos = static_cast<QMouseEvent*>(event)->globalPos();
QPointF delta = touchBeginPosition - currentPos;
if (delta.manhattanLength() < QGuiApplication::styleHints()->startDragDistance()) {
return DVtableHook::callOriginalFun(w, &QWindow::event, event);
}
}
return QObject::eventFilter(watched, event);
}
};

bool is_mouse_move = event->type() == QEvent::MouseMove && static_cast<QMouseEvent*>(event)->buttons() == Qt::LeftButton;

if (event->type() == QEvent::MouseButtonRelease) {
self->m_windowMoving = false;
}

if (!DVtableHook::callOriginalFun(w, &QWindow::event, event))
return false;

// workaround for kwin: Qt receives no release event when kwin finishes MOVE operation,
// which makes app hang in windowMoving state. when a press happens, there's no sense of
// keeping the moving state, we can just reset ti back to normal.
if (event->type() == QEvent::MouseButtonPress) {
self->m_windowMoving = false;
}

if (is_mouse_move && !event->isAccepted()
&& w->geometry().contains(static_cast<QMouseEvent*>(event)->globalPos())) {
if (!self->m_windowMoving && self->m_enableSystemMove) {
self->m_windowMoving = true;

event->accept();
if (w && w->handle()) {
#if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
static_cast<QPlatformWindow *>(w->handle())->startSystemMove(QCursor::pos());
#else
static_cast<QPlatformWindow *>(w->handle())->startSystemMove();
#endif
}
}
}

return true;
}


/*!
\brief DPlatformHandle::setEnabledNoTitlebarForWindow.
Expand All @@ -692,7 +784,9 @@ bool DPlatformHandle::setEnabledNoTitlebarForWindow(QWindow *window, bool enable
#ifndef DTK_DISABLE_TREELAND
if (window && DGuiApplicationHelper::testAttribute(DGuiApplicationHelper::IsWaylandPlatform)) {
window->installEventFilter(new CreatorWindowEventFilter(window));
window->installEventFilter(new MoveWindowEventFilter(window));
if (MoveWindowHelper::mapped.value(window))
return true;
Q_UNUSED(new MoveWindowHelper(window))
return true;
}
#endif
Expand Down Expand Up @@ -1281,6 +1375,12 @@ void DPlatformHandle::setEnableSystemMove(bool enableSystemMove)

void DPlatformHandle::setEnableBlurWindow(bool enableBlurWindow)
{
#ifndef DTK_DISABLE_TREELAND
if (DGuiApplicationHelper::testAttribute(DGuiApplicationHelper::IsWaylandPlatform)) {
PersonalizationManager::instance()->setEnableBlurWindow(m_window, enableBlurWindow);
return;
}
#endif
setWindowProperty(m_window, _enableBlurWindow, enableBlurWindow);
}

Expand Down
24 changes: 24 additions & 0 deletions src/wayland/personalizationwaylandclientextension.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,13 @@ PersonalizationManager::PersonalizationManager()
if (!m_isSupported) {
qWarning() << "PersonalizationManager is not support";
}

connect(this, &PersonalizationManager::activeChanged, this, [this] () {
for (auto window: m_pendingEnableBlurWindows.keys()) {
setEnableBlurWindow(window, m_pendingEnableBlurWindows[window]);
}
m_pendingEnableBlurWindows.clear();
});
}

PersonalizationManager::~PersonalizationManager()
Expand Down Expand Up @@ -139,6 +146,23 @@ void PersonalizationManager::setEnableTitleBar(QWindow *window, bool enable)
windowContext->setEnableTitleBar(enable);
}

void PersonalizationManager::setEnableBlurWindow(QWindow *window, bool enable)
{
if (!isActive()) {
m_pendingEnableBlurWindows[window] = enable;
connect(window, &QWindow::destroyed, this, [=] {
m_pendingEnableBlurWindows.remove(window);
});
return;
}
auto windowContext = getWindowContext(window);
if (!windowContext) {
qWarning() << "windowContext is nullptr!";
return;
}
windowContext->set_blend_mode(enable ? PersonalizationWindowContext::blend_mode_blur : PersonalizationWindowContext::blend_mode_transparent);
}

PersonalizationWindowContext::PersonalizationWindowContext(struct ::treeland_personalization_window_context_v1 *context)
: QWaylandClientExtensionTemplate<PersonalizationWindowContext>(treeland_personalization_window_context_v1_interface.version)
, QtWayland::treeland_personalization_window_context_v1(context)
Expand Down
2 changes: 2 additions & 0 deletions src/wayland/personalizationwaylandclientextension.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ class PersonalizationManager: public QWaylandClientExtensionTemplate<Personaliza
~PersonalizationManager();

void setEnableTitleBar(QWindow *window, bool enable);
void setEnableBlurWindow(QWindow *window, bool enable);
bool isSupported() const;

protected:
Expand All @@ -33,6 +34,7 @@ class PersonalizationManager: public QWaylandClientExtensionTemplate<Personaliza
void addListener();
void removeListener();
PersonalizationWindowContext *getWindowContext(QWindow *window);
QMap<QWindow*, bool> m_pendingEnableBlurWindows;

static void handleListenerGlobal(void *data, wl_registry *registry, uint32_t id, const QString &interface, uint32_t version);

Expand Down
Loading