Skip to content

Commit 9daeccb

Browse files
committed
feat: refine dock interactions and left plugins
Refine dock interactions for the fashion mode workflow. Extend and harden the behavior of the left side plugins.
1 parent 738217c commit 9daeccb

7 files changed

Lines changed: 1750 additions & 107 deletions

File tree

frame/layershell/x11dlayershellemulation.cpp

Lines changed: 18 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// SPDX-FileCopyrightText: 2023 - 2026 UnionTech Software Technology Co., Ltd.
1+
// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd.
22
//
33
// SPDX-License-Identifier: GPL-3.0-or-later
44

@@ -17,7 +17,6 @@
1717
#include <xcb/xcb.h>
1818
#include <xcb/xcb_ewmh.h>
1919
#include <xcb/xcb_icccm.h>
20-
#include <xcb/shape.h>
2120

2221
DS_BEGIN_NAMESPACE
2322

@@ -30,11 +29,16 @@ LayerShellEmulation::LayerShellEmulation(QWindow* window, QObject *parent)
3029
{
3130
onLayerChanged();
3231
connect(m_dlayerShellWindow, &DLayerShellWindow::layerChanged, this, &LayerShellEmulation::onLayerChanged);
32+
connect(m_window, &QWindow::visibleChanged, this, [this](bool) {
33+
onLayerChanged();
34+
});
35+
connect(m_window, &QWindow::visibilityChanged, this, [this](QWindow::Visibility) {
36+
onLayerChanged();
37+
});
3338

3439
onPositionChanged();
3540
connect(m_dlayerShellWindow, &DLayerShellWindow::anchorsChanged, this, &LayerShellEmulation::onPositionChanged);
3641
connect(m_dlayerShellWindow, &DLayerShellWindow::marginsChanged, this, &LayerShellEmulation::onPositionChanged);
37-
connect(m_dlayerShellWindow, &DLayerShellWindow::geometryHintsChanged, this, &LayerShellEmulation::onPositionChanged);
3842

3943
onExclusionZoneChanged();
4044
m_exclusionZoneChangedTimer.setSingleShot(true);
@@ -72,9 +76,6 @@ LayerShellEmulation::LayerShellEmulation(QWindow* window, QObject *parent)
7276
onScopeChanged();
7377
connect(m_dlayerShellWindow, &DLayerShellWindow::scopeChanged, this, &LayerShellEmulation::onScopeChanged);
7478

75-
onInputRegionChanged();
76-
connect(m_dlayerShellWindow, &DLayerShellWindow::inputRegionChanged, this, &LayerShellEmulation::onInputRegionChanged);
77-
7879
// connect(m_dlayerShellWindow, &DS_NAMESPACE::DLayerShellWindow::keyboardInteractivityChanged, this, &LayerShellEmulation::onKeyboardInteractivityChanged);
7980
}
8081

@@ -90,6 +91,10 @@ LayerShellEmulation::LayerShellEmulation(QWindow* window, QObject *parent)
9091
void LayerShellEmulation::onLayerChanged()
9192
{
9293
auto xcbWindow = dynamic_cast<QNativeInterface::Private::QXcbWindow*>(m_window->handle());
94+
if (!xcbWindow) {
95+
return;
96+
}
97+
9398
switch (m_dlayerShellWindow->layer()) {
9499
case DLayerShellWindow::LayerBackground: {
95100
m_window->setFlags(m_window->flags() & ~Qt::WindowStaysOnBottomHint);
@@ -122,30 +127,17 @@ void LayerShellEmulation::onPositionChanged()
122127
{
123128
auto anchors = m_dlayerShellWindow->anchors();
124129
auto screen = m_window->screen();
125-
if (!screen) {
126-
return;
127-
}
128-
129-
int targetWidth = m_window->width();
130-
int targetHeight = m_window->height();
131-
if (m_dlayerShellWindow->preferredWidth() > 0) {
132-
targetWidth = m_dlayerShellWindow->preferredWidth();
133-
}
134-
if (m_dlayerShellWindow->preferredHeight() > 0) {
135-
targetHeight = m_dlayerShellWindow->preferredHeight();
136-
}
137-
138130
auto screenRect = screen->geometry();
139-
auto x = screenRect.left() + (screenRect.width() - targetWidth) / 2;
140-
auto y = screenRect.top() + (screenRect.height() - targetHeight) / 2;
131+
auto x = screenRect.left() + (screenRect.width() - m_window->width()) / 2;
132+
auto y = screenRect.top() + (screenRect.height() - m_window->height()) / 2;
141133
if (anchors & DLayerShellWindow::AnchorRight) {
142134
// https://doc.qt.io/qt-6/qrect.html#right
143-
x = (screen->geometry().right() + 1 - targetWidth - m_dlayerShellWindow->rightMargin());
135+
x = (screen->geometry().right() + 1 - m_window->width() - m_dlayerShellWindow->rightMargin());
144136
}
145137

146138
if (anchors & DLayerShellWindow::AnchorBottom) {
147139
// https://doc.qt.io/qt-6/qrect.html#bottom
148-
y = (screen->geometry().bottom() + 1 - targetHeight - m_dlayerShellWindow->bottomMargin());
140+
y = (screen->geometry().bottom() + 1 - m_window->height() - m_dlayerShellWindow->bottomMargin());
149141
}
150142
if (anchors & DLayerShellWindow::AnchorLeft) {
151143
x = (screen->geometry().left() + m_dlayerShellWindow->leftMargin());
@@ -154,7 +146,7 @@ void LayerShellEmulation::onPositionChanged()
154146
y = (screen->geometry().top() + m_dlayerShellWindow->topMargin());
155147
}
156148

157-
QRect rect(x, y, targetWidth, targetHeight);
149+
QRect rect(x, y, m_window->width(), m_window->height());
158150

159151
const bool horizontallyConstrained = anchors.testFlags({DLayerShellWindow::AnchorLeft, DLayerShellWindow::AnchorRight});
160152
const bool verticallyConstrained = anchors.testFlags({DLayerShellWindow::AnchorTop, DLayerShellWindow::AnchorBottom});
@@ -168,9 +160,8 @@ void LayerShellEmulation::onPositionChanged()
168160
rect.setHeight(screen->geometry().height() - m_dlayerShellWindow->topMargin() - m_dlayerShellWindow->bottomMargin());
169161
}
170162

171-
if (m_window->geometry() != rect) {
172-
m_window->setGeometry(rect);
173-
}
163+
m_window->setGeometry(rect);
164+
onLayerChanged();
174165
}
175166

176167
/**
@@ -325,41 +316,6 @@ void LayerShellEmulation::onScopeChanged()
325316
qCDebug(layershell) << "Set WM_CLASS for window" << m_window->winId() << " wm_class:" << wmClassData;
326317
}
327318

328-
void LayerShellEmulation::onInputRegionChanged()
329-
{
330-
auto *x11Application = qGuiApp->nativeInterface<QNativeInterface::QX11Application>();
331-
if (!x11Application || !m_window->winId() || !m_dlayerShellWindow) {
332-
return;
333-
}
334-
335-
if (m_dlayerShellWindow->inputRegion().isNull()) {
336-
// Reset input region (no shape constraint)
337-
xcb_shape_mask(x11Application->connection(), XCB_SHAPE_SO_SET, XCB_SHAPE_SK_INPUT, m_window->winId(), 0, 0, XCB_NONE);
338-
xcb_flush(x11Application->connection());
339-
return;
340-
}
341-
342-
QRegion region = m_dlayerShellWindow->inputRegion();
343-
qreal scaleFactor = qGuiApp->devicePixelRatio();
344-
345-
QVector<xcb_rectangle_t> rects;
346-
for (const QRect &r : region) {
347-
xcb_rectangle_t rect;
348-
rect.x = r.x() * scaleFactor;
349-
rect.y = r.y() * scaleFactor;
350-
rect.width = r.width() * scaleFactor;
351-
rect.height = r.height() * scaleFactor;
352-
rects.append(rect);
353-
}
354-
355-
// Set the input shape via XCB
356-
// If rects vector is empty, the window will become completely transparent to input clicks (unclickable)
357-
xcb_shape_rectangles(x11Application->connection(), XCB_SHAPE_SO_SET, XCB_SHAPE_SK_INPUT,
358-
XCB_CLIP_ORDERING_UNSORTED, m_window->winId(), 0, 0,
359-
rects.size(), rects.data());
360-
xcb_flush(x11Application->connection());
361-
}
362-
363319
// void X11Emulation::onKeyboardInteractivityChanged()
364320
// {
365321
// // kwin no implentation on wayland

panels/dock/dockpanel.cpp

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,14 @@
2525
#include <QDBusReply>
2626
#include <QDBusVariant>
2727
#include <QIcon>
28+
#include <QtGui/qguiapplication_platform.h>
2829
#include <DGuiApplicationHelper>
2930
#include <DPlatformTheme>
3031

32+
#if defined(BUILD_WITH_X11)
33+
#include <xcb/xcb.h>
34+
#endif
35+
3136
#define SETTINGS DockSettings::instance()
3237

3338
Q_LOGGING_CATEGORY(dockLog, "org.deepin.dde.shell.dock")
@@ -120,6 +125,56 @@ QString readAppearanceStringProperty(const QString &propertyName)
120125
return reply.isValid() ? reply.value().variant().toString() : QString();
121126
}
122127

128+
#if defined(BUILD_WITH_X11)
129+
xcb_window_t nativeTopLevelWindow(xcb_connection_t *connection, xcb_window_t window)
130+
{
131+
xcb_window_t current = window;
132+
133+
while (current != XCB_WINDOW_NONE) {
134+
xcb_query_tree_reply_t *reply = xcb_query_tree_reply(connection, xcb_query_tree(connection, current), nullptr);
135+
if (!reply) {
136+
return current;
137+
}
138+
139+
const bool isTopLevel = reply->parent == reply->root || reply->parent == XCB_WINDOW_NONE;
140+
const xcb_window_t parent = reply->parent;
141+
free(reply);
142+
143+
if (isTopLevel) {
144+
return current;
145+
}
146+
147+
current = parent;
148+
}
149+
150+
return window;
151+
}
152+
153+
bool raiseX11Window(QWindow *window)
154+
{
155+
if (!window) {
156+
return false;
157+
}
158+
159+
window->create();
160+
const auto windowId = static_cast<xcb_window_t>(window->winId());
161+
if (windowId == XCB_WINDOW_NONE) {
162+
return false;
163+
}
164+
165+
auto *x11App = qGuiApp->nativeInterface<QNativeInterface::QX11Application>();
166+
if (!x11App || !x11App->connection()) {
167+
return false;
168+
}
169+
170+
const auto nativeWindowId = nativeTopLevelWindow(x11App->connection(), windowId);
171+
const uint32_t values[] = { XCB_STACK_MODE_ABOVE };
172+
xcb_configure_window(x11App->connection(), nativeWindowId, XCB_CONFIG_WINDOW_STACK_MODE, values);
173+
xcb_flush(x11App->connection());
174+
return true;
175+
}
176+
#endif
177+
123178
void syncApplicationTheme(Dtk::Gui::DGuiApplicationHelper *helper,
124179
const QString &globalThemeName,
125180
const QString &gtkThemeName,
@@ -169,6 +224,8 @@ DockPanel::DockPanel(QObject *parent)
169224
, m_compositorReady(false)
170225
, m_launcherShown(false)
171226
, m_themeSyncTimer(new QTimer(this))
227+
, m_launcherRaiseTimer(new QTimer(this))
228+
, m_launcherRaisePasses(0)
172229
, m_contextDragging(false)
173230
, m_containsMouse(false)
174231
, m_reportedContainsMouse(false)
@@ -180,6 +237,26 @@ DockPanel::DockPanel(QObject *parent)
180237
m_themeSyncTimer->setInterval(80);
181238
connect(m_themeSyncTimer, &QTimer::timeout, this, &DockPanel::syncColorThemeWithSystem);
182239

240+
m_launcherRaiseTimer->setInterval(80);
241+
connect(m_launcherRaiseTimer, &QTimer::timeout, this, [this] {
242+
if (!m_launcherShown || m_launcherRaisePasses <= 0) {
243+
m_launcherRaiseTimer->stop();
244+
return;
245+
}
246+
247+
if (window()) {
248+
window()->raise();
249+
#if defined(BUILD_WITH_X11)
250+
raiseX11Window(window());
251+
#endif
252+
}
253+
254+
--m_launcherRaisePasses;
255+
if (m_launcherRaisePasses <= 0) {
256+
m_launcherRaiseTimer->stop();
257+
}
258+
});
259+
183260
connect(this, &DockPanel::compositorReadyChanged, this, [this] {
184261
if (!m_compositorReady) return;
185262
m_loadTrayPlugins->loadDockPlugins();
@@ -617,6 +694,14 @@ void DockPanel::launcherVisibleChanged(bool visible)
617694
if (newHideState != oldHideState) {
618695
Q_EMIT hideStateChanged(newHideState);
619696
}
697+
698+
if (m_launcherShown) {
699+
m_launcherRaisePasses = 10;
700+
m_launcherRaiseTimer->start();
701+
} else {
702+
m_launcherRaisePasses = 0;
703+
m_launcherRaiseTimer->stop();
704+
}
620705
}
621706

622707
void DockPanel::updateDockScreen()

panels/dock/dockpanel.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,8 @@ private Q_SLOTS:
164164
bool m_compositorReady;
165165
bool m_launcherShown;
166166
QTimer *m_themeSyncTimer;
167+
QTimer *m_launcherRaiseTimer;
168+
int m_launcherRaisePasses;
167169
bool m_contextDragging;
168170
bool m_containsMouse;
169171
bool m_reportedContainsMouse;

0 commit comments

Comments
 (0)