Skip to content
Open
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
5 changes: 5 additions & 0 deletions panels/notification/bubble/bubbleitem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,11 @@ int BubbleItem::urgency() const
return m_urgency;
}

int BubbleItem::timeout() const
{
return m_entity.timeout();
}

QString BubbleItem::bodyImagePath() const
{
return m_entity.bodyIcon();
Expand Down
1 change: 1 addition & 0 deletions panels/notification/bubble/bubbleitem.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ class BubbleItem : public QObject
uint replacesId() const;
bool isReplace() const;
int urgency() const;
int timeout() const;
QString bodyImagePath() const;
qint64 ctime() const;

Expand Down
118 changes: 115 additions & 3 deletions panels/notification/bubble/bubblemodel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@

namespace notification {

// Same defaults as the notification server: -1 means server default, 0 means never expire.
static const int DefaultTimeoutMSecs = 5000;
static const int BlockItemTimeout = 1000;

BubbleModel::BubbleModel(QObject *parent)
: QAbstractListModel(parent)
, m_updateTimeTipTimer(new QTimer(this))
Expand Down Expand Up @@ -82,6 +86,8 @@
beginInsertRows(QModelIndex(), 0, 0);
m_bubbles.prepend(bubble);
endInsertRows();

startTimeout(bubble);
}

bool BubbleModel::isReplaceBubble(const BubbleItem *bubble) const
Expand All @@ -95,9 +101,17 @@
const auto replaceIndex = replaceBubbleIndex(bubble);
const auto oldBubble = m_bubbles[replaceIndex];

stopTimeout(oldBubble->id());

m_bubbles.replace(replaceIndex, bubble);
Q_EMIT dataChanged(index(replaceIndex), index(replaceIndex));

startTimeout(bubble);

// If the replaced bubble was the hovered one, keep blocking the new one.
if (m_blockedId == oldBubble->id())
pauseTimeout(bubble->id());

return oldBubble;
}

Expand All @@ -109,6 +123,8 @@
qDeleteAll(m_pendingBubbles);
m_pendingBubbles.clear();

stopAllTimeouts();

if (m_bubbles.count() <= 0)
return;
beginResetModel();
Expand All @@ -129,11 +145,13 @@
if (index < 0 || index >= m_bubbles.size())
return;

auto bubble = m_bubbles.at(index);

Check warning on line 148 in panels/notification/bubble/bubblemodel.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Variable 'bubble' can be declared as pointer to const
stopTimeout(bubble->id());

beginRemoveRows(QModelIndex(), index, index);
auto bubble = m_bubbles.takeAt(index);
bubble->deleteLater();
auto bubbleTmp = m_bubbles.takeAt(index);
bubbleTmp->deleteLater();
endRemoveRows();

}

void BubbleModel::remove(const BubbleItem *bubble)
Expand Down Expand Up @@ -298,4 +316,98 @@
Q_EMIT dataChanged(index(0), index(m_bubbles.size() - 1), {BubbleModel::ContentRowCount});
}
}

void BubbleModel::setBlockedId(qint64 id)

Check warning on line 320 in panels/notification/bubble/bubblemodel.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

The function 'setBlockedId' is never used.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这样的话,进入了暂存区域的通知没有超时的机制了,

{
if (id == m_blockedId)
return;

if (m_blockedId != NotifyEntity::InvalidId)
resumeTimeout(m_blockedId);

m_blockedId = id;

if (id != NotifyEntity::InvalidId)
pauseTimeout(id);
}

int BubbleModel::timeoutInterval(const BubbleItem *bubble) const
{
// Critical notifications never expire.
if (bubble->urgency() == NotifyEntity::Critical)
return 0;

const int timeout = bubble->timeout();
if (timeout == 0)
return 0;

return timeout == -1 ? DefaultTimeoutMSecs : timeout;
}

void BubbleModel::startTimeout(BubbleItem *bubble)
{
const auto id = bubble->id();
stopTimeout(id);

const int interval = timeoutInterval(bubble);
if (interval <= 0)
return;

auto *timer = new QTimer(this);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这样每个通知都new 个超时的timer?

timer->setSingleShot(true);
timer->setInterval(interval);
connect(timer, &QTimer::timeout, this, [this, id, bubbleId = bubble->bubbleId()] {
m_timeoutTimers.remove(id);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

timer没delete?

m_pausedRemaining.remove(id);
Q_EMIT bubbleExpired(id, bubbleId);
});
m_timeoutTimers.insert(id, timer);
timer->start();
}

void BubbleModel::stopTimeout(qint64 id)
{
auto *timer = m_timeoutTimers.take(id);
if (timer) {
timer->stop();
timer->deleteLater();
}
m_pausedRemaining.remove(id);
}

void BubbleModel::pauseTimeout(qint64 id)
{
auto *timer = m_timeoutTimers.value(id);
if (!timer || !timer->isActive())
return;

m_pausedRemaining.insert(id, timer->remainingTime());
timer->stop();
}

void BubbleModel::resumeTimeout(qint64 id)
{
auto *timer = m_timeoutTimers.value(id);
if (!timer)
return;

if (!timer->isActive()) {
int remaining = m_pausedRemaining.take(id);
if (remaining < BlockItemTimeout)
remaining = BlockItemTimeout;
timer->setInterval(remaining);
timer->start();
}
}

void BubbleModel::stopAllTimeouts()
{
m_blockedId = NotifyEntity::InvalidId;
m_pausedRemaining.clear();
const auto ids = m_timeoutTimers.keys();
for (const auto &id : ids) {
stopTimeout(id);
}
}

} // notification
19 changes: 19 additions & 0 deletions panels/notification/bubble/bubblemodel.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,11 @@
#pragma once

#include "dsglobal.h"
#include "notifyentity.h"

Check warning on line 8 in panels/notification/bubble/bubblemodel.h

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: "notifyentity.h" not found.

#include <QAbstractListModel>

Check warning on line 10 in panels/notification/bubble/bubblemodel.h

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: <QAbstractListModel> not found. Please note: Cppcheck does not need standard library headers to get proper results.
#include <QHash>

Check warning on line 11 in panels/notification/bubble/bubblemodel.h

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: <QHash> not found. Please note: Cppcheck does not need standard library headers to get proper results.
#include <QQueue>

Check warning on line 12 in panels/notification/bubble/bubblemodel.h

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: <QQueue> not found. Please note: Cppcheck does not need standard library headers to get proper results.

class QTimer;

Expand Down Expand Up @@ -38,6 +39,10 @@
explicit BubbleModel(QObject *parent = nullptr);
~BubbleModel() override;

Q_SIGNALS:
// Emitted when a bubble reaches its expire timeout and should be closed.
void bubbleExpired(qint64 id, uint bubbleId);

public:
void push(BubbleItem *bubble);

Expand All @@ -51,6 +56,10 @@
BubbleItem *removeById(qint64 id);
void clear();

// Pause/resume the expire timer of the hovered bubble so hovering
// keeps the bubble on screen (0 clears the blocked bubble).
void setBlockedId(qint64 id);

BubbleItem *bubbleItem(int bubbleIndex) const;

int rowCount(const QModelIndex &parent) const override;
Expand All @@ -68,11 +77,21 @@
void updateBubbleTimeTip();
void updateContentRowCount(int rowCount);

int timeoutInterval(const BubbleItem *bubble) const;
void startTimeout(BubbleItem *bubble);
void stopTimeout(qint64 id);
void pauseTimeout(qint64 id);
void resumeTimeout(qint64 id);
void stopAllTimeouts();

private:
QTimer *m_updateTimeTipTimer = nullptr;
QTimer *m_processPendingTimer = nullptr;
QList<BubbleItem *> m_bubbles;
QQueue<BubbleItem *> m_pendingBubbles;
QHash<qint64, QTimer *> m_timeoutTimers;
QHash<qint64, int> m_pausedRemaining;
qint64 m_blockedId = NotifyEntity::InvalidId;
int m_maxKeep{5};
int m_contentRowCount{6};
};
Expand Down
10 changes: 9 additions & 1 deletion panels/notification/bubble/bubblepanel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,14 @@ bool BubblePanel::init()

connect(m_bubbles, &BubbleModel::rowsInserted, this, &BubblePanel::onBubbleCountChanged);
connect(m_bubbles, &BubbleModel::rowsRemoved, this, &BubblePanel::onBubbleCountChanged);
// The bubble model runs one expire timer per shown bubble. When a bubble
// times out, close it and notify the server so it moves the notification
// from the in-memory store to the center database and emits the signals.
connect(m_bubbles, &BubbleModel::bubbleExpired, this, [this](qint64 id, uint bubbleId) {
closeBubble(id);
QMetaObject::invokeMethod(m_notificationServer, "notificationClosed", Qt::DirectConnection,
Q_ARG(qint64, id), Q_ARG(uint, bubbleId), Q_ARG(uint, NotifyEntity::Expired));
});

return true;
}
Expand Down Expand Up @@ -217,7 +225,7 @@ void BubblePanel::setEnabled(bool newEnabled)

void BubblePanel::setHoveredId(qint64 id)
{
QMetaObject::invokeMethod(m_notificationServer, "setBlockClosedId", Qt::DirectConnection, Q_ARG(qint64, id));
m_bubbles->setBlockedId(id);
}
}

Expand Down
5 changes: 5 additions & 0 deletions panels/notification/common/notifyentity.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,11 @@ bool NotifyEntity::isReplace() const
return d->replacesId != NoReplaceId;
}

int NotifyEntity::timeout() const
{
return d->expireTimeout;
}

qint64 NotifyEntity::cTime() const
{
return d->cTime;
Expand Down
3 changes: 3 additions & 0 deletions panels/notification/common/notifyentity.h
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,9 @@ class NotifyEntity
void setReplacesId(uint replacesId);
bool isReplace() const;

// Expire timeout in milliseconds passed in by the client (-1 means server default).
int timeout() const;

qint64 cTime() const;
void setCTime(qint64 cTime);

Expand Down
Loading
Loading