Skip to content

Commit ed3f4dd

Browse files
committed
gitfeat: add dynamic position updates for notification bubbles
Added requestPositionUpdate method to DLayerShellWindow to allow QML components to trigger window position recalculations with custom dimensions. This enables the notification panel to dynamically adjust its position based on content height changes. Key changes: 1. Added Q_INVOKABLE requestPositionUpdate method in DLayerShellWindow 2. Implemented onPositionUpdateRequested slot in LayerShellEmulation to handle custom width/height calculations 3. Modified notification bubble panel to update window height based on content changes 4. Added smooth removal animations for notification bubbles 5. Fixed window visibility handling with delayed hiding when empty The position calculation now properly accounts for anchor constraints and margins when using custom dimensions, ensuring correct window placement regardless of content size changes. Log: Improved notification panel positioning and animations Influence: 1. Test notification display with varying numbers of bubbles 2. Verify window position updates correctly when content height changes 3. Check smooth animations when adding/removing notifications 4. Validate window hides properly after last notification is dismissed 5. Test with different screen resolutions and scaling factors 6. Verify anchor constraints work correctly with dynamic sizing PMS: BUG-284659
1 parent ce1afa5 commit ed3f4dd

6 files changed

Lines changed: 107 additions & 6 deletions

File tree

frame/layershell/dlayershellwindow.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,11 @@ DLayerShellWindow* DLayerShellWindow::get(QWindow* window)
231231
return new DLayerShellWindow(window);
232232
}
233233

234+
void DLayerShellWindow::requestPositionUpdate(int width, int height)
235+
{
236+
Q_EMIT positionUpdateRequested(width, height);
237+
}
238+
234239
DLayerShellWindow* DLayerShellWindow::qmlAttachedProperties(QObject *object)
235240
{
236241
auto window = qobject_cast<QWindow*>(object);

frame/layershell/dlayershellwindow.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,14 @@ class DS_SHARE DLayerShellWindow : public QObject
130130
void setCloseOnDismissed(bool close);
131131
bool closeOnDismissed() const;
132132

133+
/**
134+
* Request position update with specified width and height
135+
* This can be called from QML to trigger a position recalculation
136+
* @param width The window width to use for position calculation
137+
* @param height The window height to use for position calculation
138+
*/
139+
Q_INVOKABLE void requestPositionUpdate(int width, int height);
140+
133141
/**
134142
* Gets the LayerShell Window for a given Qt Window
135143
* Ownership is not transferred
@@ -145,6 +153,7 @@ class DS_SHARE DLayerShellWindow : public QObject
145153
void keyboardInteractivityChanged();
146154
void layerChanged();
147155
void scopeChanged();
156+
void positionUpdateRequested(int width, int height);
148157

149158
private:
150159
DLayerShellWindow(QWindow* window);

frame/layershell/x11dlayershellemulation.cpp

Lines changed: 45 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ LayerShellEmulation::LayerShellEmulation(QWindow* window, QObject *parent)
3333
onPositionChanged();
3434
connect(m_dlayerShellWindow, &DLayerShellWindow::anchorsChanged, this, &LayerShellEmulation::onPositionChanged);
3535
connect(m_dlayerShellWindow, &DLayerShellWindow::marginsChanged, this, &LayerShellEmulation::onPositionChanged);
36+
connect(m_dlayerShellWindow, &DLayerShellWindow::positionUpdateRequested, this, &LayerShellEmulation::onPositionUpdateRequested);
3637

3738
onExclusionZoneChanged();
3839
m_exclusionZoneChangedTimer.setSingleShot(true);
@@ -120,14 +121,17 @@ void LayerShellEmulation::onPositionChanged()
120121
auto screenRect = screen->geometry();
121122
auto x = screenRect.left() + (screenRect.width() - m_window->width()) / 2;
122123
auto y = screenRect.top() + (screenRect.height() - m_window->height()) / 2;
124+
125+
qWarning() << "caimengci position x=" << x << "y=" << y << "window width=" << m_window->width() << "window height=" << m_window->height();
126+
123127
if (anchors & DLayerShellWindow::AnchorRight) {
124128
// https://doc.qt.io/qt-6/qrect.html#right
125-
x = (screen->geometry().right() + 1 - m_window->width() - m_dlayerShellWindow->rightMargin());
129+
x = (screen->geometry().right() - m_window->width() - m_dlayerShellWindow->rightMargin());
126130
}
127131

128132
if (anchors & DLayerShellWindow::AnchorBottom) {
129133
// https://doc.qt.io/qt-6/qrect.html#bottom
130-
y = (screen->geometry().bottom() + 1 - m_window->height() - m_dlayerShellWindow->bottomMargin());
134+
y = (screen->geometry().bottom() - m_window->height() - m_dlayerShellWindow->bottomMargin());
131135
}
132136
if (anchors & DLayerShellWindow::AnchorLeft) {
133137
x = (screen->geometry().left() + m_dlayerShellWindow->leftMargin());
@@ -153,6 +157,45 @@ void LayerShellEmulation::onPositionChanged()
153157
m_window->setGeometry(rect);
154158
}
155159

160+
void LayerShellEmulation::onPositionUpdateRequested(int width, int height)
161+
{
162+
auto anchors = m_dlayerShellWindow->anchors();
163+
auto screen = m_window->screen();
164+
auto screenRect = screen->geometry();
165+
auto x = screenRect.left() + (screenRect.width() - width) / 2;
166+
auto y = screenRect.top() + (screenRect.height() - height) / 2;
167+
168+
if (anchors & DLayerShellWindow::AnchorRight) {
169+
x = (screen->geometry().right() - width - m_dlayerShellWindow->rightMargin());
170+
}
171+
172+
if (anchors & DLayerShellWindow::AnchorBottom) {
173+
y = (screen->geometry().bottom() - height - m_dlayerShellWindow->bottomMargin());
174+
}
175+
if (anchors & DLayerShellWindow::AnchorLeft) {
176+
x = (screen->geometry().left() + m_dlayerShellWindow->leftMargin());
177+
}
178+
if (anchors & DLayerShellWindow::AnchorTop) {
179+
y = (screen->geometry().top() + m_dlayerShellWindow->topMargin());
180+
}
181+
182+
QRect rect(x, y, width, height);
183+
184+
const bool horizontallyConstrained = anchors.testFlags({DLayerShellWindow::AnchorLeft, DLayerShellWindow::AnchorRight});
185+
const bool verticallyConstrained = anchors.testFlags({DLayerShellWindow::AnchorTop, DLayerShellWindow::AnchorBottom});
186+
187+
if (horizontallyConstrained) {
188+
rect.setX(screen->geometry().left() + m_dlayerShellWindow->leftMargin());
189+
rect.setWidth(screen->geometry().width() - m_dlayerShellWindow->leftMargin() - m_dlayerShellWindow->rightMargin());
190+
}
191+
if (verticallyConstrained) {
192+
rect.setY(screen->geometry().top() + m_dlayerShellWindow->topMargin());
193+
rect.setHeight(screen->geometry().height() - m_dlayerShellWindow->topMargin() - m_dlayerShellWindow->bottomMargin());
194+
}
195+
196+
m_window->setGeometry(rect);
197+
}
198+
156199
/**
157200
* https://specifications.freedesktop.org/wm-spec/wm-spec-1.4.html#idm45649101327728
158201
*/

frame/layershell/x11dlayershellemulation.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ private slots:
2626
void onLayerChanged();
2727
// margins or anchor changed
2828
void onPositionChanged();
29+
void onPositionUpdateRequested(int width, int height);
2930
void onExclusionZoneChanged();
3031
void onScopeChanged();
3132
// void onKeyboardInteractivityChanged();

panels/notification/bubble/bubblepanel.cpp

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#include "bubblemodel.h"
88
#include "dataaccessorproxy.h"
99
#include "pluginfactory.h"
10+
#include <qtimer.h>
1011

1112
#include <QTimer>
1213
#include <QLoggingCategory>
@@ -54,6 +55,7 @@ bool BubblePanel::init()
5455
connect(m_bubbles, &BubbleModel::rowsInserted, this, &BubblePanel::onBubbleCountChanged);
5556
connect(m_bubbles, &BubbleModel::rowsRemoved, this, &BubblePanel::onBubbleCountChanged);
5657

58+
setVisible(true);
5759
return true;
5860
}
5961

@@ -111,7 +113,14 @@ void BubblePanel::onNotificationStateChanged(qint64 id, int processedType)
111113
void BubblePanel::onBubbleCountChanged()
112114
{
113115
bool isEmpty = m_bubbles->items().isEmpty();
114-
setVisible(!isEmpty && enabled());
116+
117+
if (isEmpty) {
118+
QTimer::singleShot(400, this, [this]() {
119+
setVisible(false);
120+
});
121+
} else {
122+
setVisible(!isEmpty && enabled());
123+
}
115124
}
116125

117126
void BubblePanel::addBubble(qint64 id)

panels/notification/bubble/package/main.qml

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -69,8 +69,8 @@ Window {
6969

7070
visible: Applet.visible
7171
width: 390
72-
height: Math.max(10, bubbleView.height + bubbleView.anchors.topMargin + bubbleView.anchors.bottomMargin)
73-
DLayerShellWindow.layer: DLayerShellWindow.LayerOverlay
72+
height: 0
73+
DLayerShellWindow.layer: DLayerShellWindow.LayerTop
7474
DLayerShellWindow.anchors: DLayerShellWindow.AnchorBottom | DLayerShellWindow.AnchorRight
7575
DLayerShellWindow.topMargin: windowMargin(0)
7676
DLayerShellWindow.rightMargin: windowMargin(1)
@@ -89,6 +89,11 @@ Window {
8989
root.screen = Qt.binding(function () { return Qt.application.screens[0]})
9090
}
9191

92+
// Function to trigger position update with custom width and height
93+
function updatePosition(width, height) {
94+
DLayerShellWindow.requestPositionUpdate(width, height)
95+
}
96+
9297
ListView {
9398
id: bubbleView
9499
width: 360
@@ -98,13 +103,19 @@ Window {
98103
bottom: parent.bottom
99104
bottomMargin: 10
100105
rightMargin: 10
101-
margins: 30
106+
topMargin: 10
107+
margins: 10
102108
}
103109

104110
spacing: 10
105111
model: Applet.bubbles
106112
interactive: false
107113
verticalLayoutDirection: ListView.BottomToTop
114+
115+
// Monitor height changes and update position
116+
onHeightChanged: {
117+
updatePosition(390, bubbleView.height + bubbleView.anchors.topMargin + bubbleView.anchors.bottomMargin)
118+
}
108119
add: Transition {
109120
id: addTrans
110121
// Before starting the new animation, forcibly complete the previous notification bubble's animation
@@ -129,8 +140,31 @@ Window {
129140
}
130141
}
131142
delegate: Bubble {
143+
id: delegateItem
132144
width: 360
133145
bubble: model
146+
147+
ListView.onRemove: SequentialAnimation {
148+
PropertyAction {
149+
target: delegateItem
150+
property: "ListView.delayRemove"
151+
value: true
152+
}
153+
ParallelAnimation {
154+
NumberAnimation {
155+
target: delegateItem
156+
property: "x"
157+
to: 360
158+
duration: 400
159+
easing.type: Easing.InExpo
160+
}
161+
}
162+
PropertyAction {
163+
target: delegateItem
164+
property: "ListView.delayRemove"
165+
value: false
166+
}
167+
}
134168
}
135169
}
136170
}

0 commit comments

Comments
 (0)