mirror of
https://github.com/linuxdeepin/dde-dock.git
synced 2025-06-04 17:33:05 +00:00

1.通过略缩图关闭驻留应用,任务栏崩溃.由于使用了野指针,导致概率性崩溃。 2.非驻留时,关闭最后一个预览时AppItem对象被析构,但是之前connect没有指定receiver。导致信号还是被响应,使用了野指针。 Log: 修复任务栏在缩略图状态下关闭应用崩溃问题 Bug: https://pms.uniontech.com/zentao/bug-view-89275.html Change-Id: Ib652beb4698193c33df9ed465cf843ceefeaa6ec
203 lines
6.3 KiB
C++
203 lines
6.3 KiB
C++
/*
|
||
* Copyright (C) 2011 ~ 2018 Deepin Technology Co., Ltd.
|
||
*
|
||
* Author: sbw <sbw@sbw.so>
|
||
*
|
||
* Maintainer: sbw <sbw@sbw.so>
|
||
*
|
||
* This program is free software: you can redistribute it and/or modify
|
||
* it under the terms of the GNU General Public License as published by
|
||
* the Free Software Foundation, either version 3 of the License, or
|
||
* any later version.
|
||
*
|
||
* This program is distributed in the hope that it will be useful,
|
||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
* GNU General Public License for more details.
|
||
*
|
||
* You should have received a copy of the GNU General Public License
|
||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||
*/
|
||
|
||
#include "floatingpreview.h"
|
||
#include "appsnapshot.h"
|
||
#include "previewcontainer.h"
|
||
|
||
#include <DStyle>
|
||
|
||
#include <QGraphicsEffect>
|
||
#include <QPainter>
|
||
#include <QVBoxLayout>
|
||
|
||
#define BORDER_MARGIN 8
|
||
#define TITLE_MARGIN 20
|
||
#define BTN_TITLE_MARGIN 6
|
||
|
||
FloatingPreview::FloatingPreview(QWidget *parent)
|
||
: QWidget(parent)
|
||
, m_closeBtn3D(new DIconButton(this))
|
||
, m_titleBtn(new DPushButton(this))
|
||
{
|
||
m_closeBtn3D->setObjectName("closebutton-3d");
|
||
m_closeBtn3D->setFixedSize(24, 24);
|
||
m_closeBtn3D->setIconSize(QSize(24, 24));
|
||
m_closeBtn3D->setIcon(QIcon(":/icons/resources/close_round_normal.svg"));
|
||
m_closeBtn3D->setFlat(true);
|
||
m_closeBtn3D->installEventFilter(this);
|
||
|
||
m_titleBtn->setBackgroundRole(QPalette::Base);
|
||
m_titleBtn->setForegroundRole(QPalette::Text);
|
||
m_titleBtn->setFocusPolicy(Qt::NoFocus);
|
||
m_titleBtn->setAttribute(Qt::WA_TransparentForMouseEvents);
|
||
|
||
QVBoxLayout *centralLayout = new QVBoxLayout;
|
||
centralLayout->addWidget(m_closeBtn3D);
|
||
centralLayout->setAlignment(m_closeBtn3D, Qt::AlignRight | Qt::AlignTop);
|
||
centralLayout->addWidget(m_titleBtn);
|
||
centralLayout->setAlignment(m_titleBtn, Qt::AlignCenter | Qt::AlignBottom);
|
||
centralLayout->addSpacing(TITLE_MARGIN);
|
||
centralLayout->setMargin(0);
|
||
centralLayout->setSpacing(0);
|
||
|
||
setLayout(centralLayout);
|
||
setFixedSize(SNAP_WIDTH, SNAP_HEIGHT);
|
||
|
||
connect(m_closeBtn3D, &DIconButton::clicked, this, &FloatingPreview::onCloseBtnClicked);
|
||
}
|
||
|
||
WId FloatingPreview::trackedWid() const
|
||
{
|
||
Q_ASSERT(!m_tracked.isNull());
|
||
|
||
return m_tracked->wid();
|
||
}
|
||
|
||
AppSnapshot *FloatingPreview::trackedWindow()
|
||
{
|
||
return m_tracked;
|
||
}
|
||
|
||
void FloatingPreview::trackWindow(AppSnapshot *const snap)
|
||
{
|
||
if (!snap)
|
||
return;
|
||
|
||
if (!m_tracked.isNull())
|
||
m_tracked->removeEventFilter(this);
|
||
|
||
snap->installEventFilter(this);
|
||
m_tracked = snap;
|
||
|
||
m_closeBtn3D->setVisible(m_tracked->closeAble());
|
||
|
||
QFontMetrics fm(m_titleBtn->font());
|
||
int textWidth = fm.width(m_tracked->title()) + 10 + BTN_TITLE_MARGIN;
|
||
int titleWidth = width() - (TITLE_MARGIN * 2 + BORDER_MARGIN);
|
||
|
||
if (textWidth < titleWidth) {
|
||
m_titleBtn->setFixedWidth(textWidth);
|
||
m_titleBtn->setText(m_tracked->title());
|
||
} else {
|
||
QString str = m_tracked->title();
|
||
/*某些特殊字符只显示一半 如"Q"," W",所以加一个空格保证字符显示完整,*/
|
||
str.insert(0, " ");
|
||
QString strTtile = m_titleBtn->fontMetrics().elidedText(str, Qt::ElideRight, titleWidth - BTN_TITLE_MARGIN);
|
||
m_titleBtn->setText(strTtile);
|
||
m_titleBtn->setFixedWidth(titleWidth + BTN_TITLE_MARGIN);
|
||
}
|
||
|
||
QTimer::singleShot(0, this, [ = ] {
|
||
// 此处获取的snap->geometry()有可能是错误的,所以做个判断并且在resizeEvent中也做处理
|
||
if(snap->width() == SNAP_WIDTH)
|
||
setGeometry(snap->geometry());
|
||
});
|
||
}
|
||
|
||
void FloatingPreview::paintEvent(QPaintEvent *e)
|
||
{
|
||
QWidget::paintEvent(e);
|
||
|
||
if (m_tracked.isNull())
|
||
return;
|
||
|
||
const QImage &snapshot = m_tracked->snapshot();
|
||
const QRectF &snapshot_geometry = m_tracked->snapshotGeometry();
|
||
|
||
if (snapshot.isNull())
|
||
return;
|
||
|
||
QPainter painter(this);
|
||
painter.setRenderHint(QPainter::Antialiasing);
|
||
|
||
const QRectF r = rect().marginsRemoved(QMargins(BORDER_MARGIN, BORDER_MARGIN, BORDER_MARGIN, BORDER_MARGIN));
|
||
const auto ratio = devicePixelRatioF();
|
||
|
||
const qreal offset_x = width() / 2.0 - snapshot_geometry.width() / ratio / 2 - snapshot_geometry.left() / ratio;
|
||
const qreal offset_y = height() / 2.0 - snapshot_geometry.height() / ratio / 2 - snapshot_geometry.top() / ratio;
|
||
|
||
DStyleHelper dstyle(style());
|
||
const int radius = dstyle.pixelMetric(DStyle::PM_FrameRadius);
|
||
|
||
// 选中外框
|
||
QPen pen;
|
||
pen.setColor(palette().highlight().color());
|
||
pen.setWidth(dstyle.pixelMetric(DStyle::PM_FocusBorderWidth));
|
||
painter.setPen(pen);
|
||
painter.setBrush(Qt::NoBrush);
|
||
painter.drawRoundedRect(r, radius, radius);
|
||
}
|
||
|
||
void FloatingPreview::mouseReleaseEvent(QMouseEvent *e)
|
||
{
|
||
QWidget::mouseReleaseEvent(e);
|
||
|
||
if (m_tracked) {
|
||
emit m_tracked->clicked(m_tracked->wid());
|
||
}
|
||
}
|
||
|
||
bool FloatingPreview::eventFilter(QObject *watched, QEvent *event)
|
||
{
|
||
if(watched == m_closeBtn3D) {
|
||
if(watched == m_closeBtn3D && (event->type() == QEvent::HoverEnter || event->type() == QEvent::HoverMove)) {
|
||
m_closeBtn3D->setIcon(QIcon(":/icons/resources/close_round_hover.svg"));
|
||
}
|
||
else if (watched == m_closeBtn3D && event->type() == QEvent::HoverLeave) {
|
||
m_closeBtn3D->setIcon(QIcon(":/icons/resources/close_round_normal.svg"));
|
||
}
|
||
else if (watched == m_closeBtn3D && event->type() == QEvent::MouseButtonPress) {
|
||
m_closeBtn3D->setIcon(QIcon(":/icons/resources/close_round_press.svg"));
|
||
}
|
||
}
|
||
|
||
if (watched == m_tracked) {
|
||
if (event->type() == QEvent::Destroy) {
|
||
// 此处需要置空,否则当Destroy事件响应结束后,会在FloatingPreview::hideEvent使用m_tracked野指针
|
||
m_tracked = nullptr;
|
||
hide();
|
||
}
|
||
|
||
if (event->type() == QEvent::Resize && m_tracked->width() == SNAP_WIDTH)
|
||
setGeometry(m_tracked->geometry());
|
||
}
|
||
|
||
return QWidget::eventFilter(watched, event);
|
||
}
|
||
|
||
void FloatingPreview::hideEvent(QHideEvent *event)
|
||
{
|
||
if (m_tracked) {
|
||
m_tracked->setContentsMargins(0, 0, 0, 0);
|
||
m_tracked->setWindowState();
|
||
}
|
||
|
||
QWidget::hideEvent(event);
|
||
}
|
||
|
||
void FloatingPreview::onCloseBtnClicked()
|
||
{
|
||
Q_ASSERT(!m_tracked.isNull());
|
||
|
||
m_tracked->closeWindow();
|
||
}
|