From 85b056cf19dcb56a052e3870b88e476e7484af18 Mon Sep 17 00:00:00 2001 From: dengzhongyuan Date: Mon, 18 May 2026 14:13:20 +0800 Subject: [PATCH] fix(main_window): enhance tool bar management and cleanup - Refactor tool bar handling to ensure proper initialization and destruction, preventing potential memory leaks and dangling pointers. - Implement checks for tool bar existence before performing actions, improving stability during screen capture operations. - Add a new method to destroy the tool bar, allowing for better resource management when reselecting capture regions. This update addresses issues related to tool bar visibility and lifecycle, enhancing the overall user experience during screen recording. TASK: https://pms.uniontech.com/task-view-389563.html --- src/main_window.cpp | 144 ++++++++++++++++++++++++++------------ src/main_window.h | 3 + src/widgets/imagemenu.cpp | 55 +++++++++++---- src/widgets/imagemenu.h | 5 +- src/widgets/toolbar.cpp | 32 ++++++--- 5 files changed, 168 insertions(+), 71 deletions(-) diff --git a/src/main_window.cpp b/src/main_window.cpp index 776c9ff14..4cf516673 100755 --- a/src/main_window.cpp +++ b/src/main_window.cpp @@ -342,10 +342,7 @@ void MainWindow::initTreelandtAttributes() //initTreelandtAttributes installEventFilter(this); createWinId(); - //构建截屏工具栏和相关组件 - m_toolBar =new ToolBar(this); - m_toolBar->move(100,128); - m_toolBar->show(); + // Treeland 截图工具栏在 sourceReady(captureRegionChanged) 后由 updateCaptureRegion 创建 m_sideBar = new SideBar(this); m_sideBar->initSideBar(this); @@ -367,8 +364,6 @@ void MainWindow::initTreelandtAttributes() //initTreelandtAttributes } m_zoomIndicator->hideMagnifier(); } - // 设置窗口大小和位置 - connect(m_toolBar, &ToolBar::currentFunctionToMain, this, &MainWindow::changeFunctionButton); m_backgroundRect = rootWindowRect; m_backgroundRect = QRect(m_backgroundRect.topLeft() / m_pixelRatio, m_backgroundRect.size()); move(m_backgroundRect.topLeft() * m_pixelRatio); @@ -915,9 +910,11 @@ void MainWindow::checkIsLockScreen() qCInfo(dsrApp) << "Current Screen is LockScreen?" << isLockScreen; if (isLockScreen) { pinScreenshotsLockScreen(isLockScreen); - m_toolBar->setScrollShotDisabled(true); - m_toolBar->setOcrScreenshotsEnable(false); - m_toolBar->setButEnableOnLockScreen(false); + if (m_toolBar) { + m_toolBar->setScrollShotDisabled(true); + m_toolBar->setOcrScreenshotsEnable(false); + m_toolBar->setButEnableOnLockScreen(false); + } } // 电源界面判断接口 QDBusInterface ddeLockFront( @@ -935,9 +932,11 @@ void MainWindow::checkIsLockScreen() qCInfo(dsrApp) << "Current Screen is Powersource UI?" << isLockFront; if (isLockFront) { pinScreenshotsLockScreen(isLockScreen); - m_toolBar->setScrollShotDisabled(true); - m_toolBar->setOcrScreenshotsEnable(false); - m_toolBar->setButEnableOnLockScreen(false); + if (m_toolBar) { + m_toolBar->setScrollShotDisabled(true); + m_toolBar->setOcrScreenshotsEnable(false); + m_toolBar->setButEnableOnLockScreen(false); + } } } void MainWindow::initDynamicLibPath() @@ -1407,30 +1406,36 @@ void MainWindow::initScreenShot() // 构建截屏工具栏按钮 by zyg if (m_firstShot == 0) { qCDebug(dsrApp) << "initScreenShot m_firstShot == 0"; - m_toolBar->hide(); + if (m_toolBar) { + m_toolBar->hide(); + } m_sideBar->hide(); // m_recordButton->hide(); // m_shotButton->hide(); m_sizeTips->hide(); - } - - else { + } else { qCDebug(dsrApp) << "initScreenShot m_firstShot != 0"; - m_toolBar->show(); + if (m_toolBar) { + m_toolBar->show(); + } m_sideBar->hide(); // m_recordButton->hide(); // m_shotButton->show(); m_sizeTips->show(); - updateToolBarPos(); + if (m_toolBar) { + updateToolBarPos(); + } // updateShotButtonPos(); m_sizeTips->setRecorderTipsInfo(false); m_sizeTips->updateTips(QPoint(recordX, recordY), QSize(recordWidth, recordHeight)); } - m_toolBar->setFocus(); + if (m_toolBar) { + m_toolBar->setFocus(); + } qCDebug(dsrApp) << "initScreenShot end"; } @@ -1496,24 +1501,28 @@ void MainWindow::initScreenRecorder() // 构建截屏工具栏按钮 by zyg if (m_firstShot == 0) { qCDebug(dsrApp) << "initScreenRecorder m_firstShot == 0"; - m_toolBar->hide(); + if (m_toolBar) { + m_toolBar->hide(); + } m_sideBar->hide(); // m_recordButton->hide(); // m_shotButton->hide(); m_sizeTips->hide(); - } - - else { + } else { qCDebug(dsrApp) << "initScreenRecorder m_firstShot != 0"; - m_toolBar->show(); + if (m_toolBar) { + m_toolBar->show(); + } m_sideBar->hide(); // m_recordButton->show(); // m_shotButton->hide(); m_sizeTips->show(); - updateToolBarPos(); + if (m_toolBar) { + updateToolBarPos(); + } // updateRecordButtonPos(); m_sizeTips->setRecorderTipsInfo(true); m_sizeTips->updateTips(QPoint(recordX, recordY), QSize(recordWidth, recordHeight)); @@ -1533,7 +1542,9 @@ void MainWindow::initScreenRecorder() } } - m_toolBar->setFocus(); + if (m_toolBar) { + m_toolBar->setFocus(); + } qCDebug(dsrApp) << "initScreenRecorder end"; } @@ -2819,7 +2830,7 @@ void MainWindow::wheelEvent(QWheelEvent *event) void MainWindow::pinScreenshotsLockScreen(bool isLocked) { - if (m_toolBarInit) { + if (m_toolBar) { m_toolBar->setPinScreenshotsEnable(!isLocked); } } @@ -2915,7 +2926,10 @@ void MainWindow::compositeChanged() { // 滚动截图过程中动态切换为2D模式,直接结束 if (m_functionType == status::shot) { - m_toolBar->setScrollShotDisabled(!m_wmHelper->hasBlurWindow()); + // Treeland:工具栏在 sourceReady 后才创建,Wayland 初始化可能先触发 hasBlurWindowChanged + if (m_toolBar) { + m_toolBar->setScrollShotDisabled(!m_wmHelper->hasBlurWindow()); + } return; } if (!m_wmHelper->hasBlurWindow() && m_functionType == status::scrollshot) { @@ -2952,7 +2966,7 @@ void MainWindow::compositeChanged() void MainWindow::updateToolBarPos() { - if (m_shotflag == 1) { + if (m_shotflag == 1 || !m_toolBar) { return; } m_isToolBarInside = false; @@ -5243,16 +5257,18 @@ int MainWindow::mouseMoveEF(QMouseEvent *mouseEvent, bool &needRepaint) m_currentCursor = mouseEvent->pos(); // 没打开截图的编辑模式 if (!m_isShapesWidgetExist) { - if (m_toolBar->isVisible()) { + if (m_toolBar && m_toolBar->isVisible()) { updateToolBarPos(); - m_zoomIndicator->hideMagnifier(); + if (m_zoomIndicator) { + m_zoomIndicator->hideMagnifier(); + } } if (!isFirstMove) { isFirstMove = true; } else { if (status::shot == m_functionType) { - if (!m_toolBar->isVisible() && !isFirstReleaseButton) { + if (m_toolBar && !m_toolBar->isVisible() && !isFirstReleaseButton) { // QPoint curPos = this->cursor().pos(); 采用全局坐标,替换局部坐标 // mouseEvent->globalPos()此接口获取的光标坐标是已经缩放后的坐标,需还原 QPoint curPos = this->cursor().pos(); // 采用全局坐标,替换局部坐标 @@ -7748,7 +7764,7 @@ void MainWindow::initializeCapture() ); connect(manager->context(), &TreelandCaptureContext::captureRegionChanged, - this, &MainWindow::updateCaptureRegion); + this, &MainWindow::updateCaptureRegion, Qt::UniqueConnection); connect(manager, &TreelandCaptureManager::finishSelect, this, &MainWindow::handleCaptureFinish); @@ -7854,32 +7870,68 @@ void MainWindow::onFinishClicked() TreelandCaptureManager::instance()->finishSelect(); } +void MainWindow::destroyTreelandToolBar() +{ + if (!m_toolBar) { + return; + } + + ToolBar *toolBar = m_toolBar; + m_toolBar = nullptr; + m_toolBarInit = false; + + if (toolBar->windowHandle()) { + toolBar->windowHandle()->setParent(nullptr); + } + toolBar->blockSignals(true); + disconnect(toolBar, nullptr, nullptr, nullptr); + disconnect(nullptr, nullptr, toolBar, nullptr); + toolBar->hide(); + delete toolBar; + // 选项菜单里的边框子菜单由 ImageBorderHelper 缓存,需清理悬空指针 + ImageBorderHelper::instance()->pruneBorderMenus(); +} + void MainWindow::updateCaptureRegion() { auto context = TreelandCaptureManager::instance()->context(); - if (!context) return; - QRect region = context->captureRegion().toRect(); + if (!context) { + return; + } + + const QRect region = context->captureRegion().toRect(); + // 无效选区:只销毁旧工具栏,等下一次 sourceReady 再创建 + if (region.width() <= 0 || region.height() <= 0) { + destroyTreelandToolBar(); + return; + } + + // 每次重新选区:先析构上一块工具栏(含 Wayland subsurface),再按新选区 new + destroyTreelandToolBar(); m_toolBar = new ToolBar(this); + connect(m_toolBar, &ToolBar::currentFunctionToMain, this, &MainWindow::changeFunctionButton); m_toolBar->initToolBar(this, isHideToolBar); + m_toolBar->setRecordLaunchMode(m_functionType); + m_toolBarInit = true; m_toolBar->setAttribute(Qt::WA_TranslucentBackground); m_toolBar->setWindowFlags(Qt::FramelessWindowHint | Qt::Tool | Qt::WindowStaysOnTopHint); + recordX = region.x(); + recordY = region.y(); + recordWidth = region.width(); + recordHeight = region.height(); + m_toolBar->showWidget(); - QPoint pos(region.x(), qMin(region.bottom(), height() - 2 * m_toolBar->height())); + const QPoint pos(region.x(), qMin(region.bottom(), height() - 2 * m_toolBar->height())); m_toolBar->showAt(pos); - m_toolBar->showWidget(); - - if(windowHandle()&&m_toolBar->windowHandle()) - { - if(m_toolBar->windowHandle()->parent() != windowHandle()) - { - m_toolBar->windowHandle()->setParent(windowHandle()); - m_toolBar->hide(); - m_toolBar->show(); - } + if (windowHandle() && m_toolBar->windowHandle() + && m_toolBar->windowHandle()->parent() != windowHandle()) { + m_toolBar->windowHandle()->setParent(windowHandle()); + m_toolBar->hide(); + m_toolBar->show(); } } diff --git a/src/main_window.h b/src/main_window.h index 98d8a06c5..3c439124a 100755 --- a/src/main_window.h +++ b/src/main_window.h @@ -470,6 +470,9 @@ public slots: */ void updateCaptureRegion(); + /** Treeland:销毁当前工具栏(含 subsurface 解绑),便于重选区后重建 */ + void destroyTreelandToolBar(); + Q_SCRIPTABLE void stopRecord(); Q_SCRIPTABLE void stopApp(); diff --git a/src/widgets/imagemenu.cpp b/src/widgets/imagemenu.cpp index 30c328bd3..08d5423d0 100755 --- a/src/widgets/imagemenu.cpp +++ b/src/widgets/imagemenu.cpp @@ -254,15 +254,34 @@ ImageBorderHelper *ImageBorderHelper::instance() return m_imageBorderHelper; } +void ImageBorderHelper::pruneBorderMenus() +{ + for (auto it = m_allBorderMenu.begin(); it != m_allBorderMenu.end();) { + if (it.value().isNull()) { + it = m_allBorderMenu.erase(it); + } else { + ++it; + } + } +} + ImageMenu *ImageBorderHelper::getBorderMenu(const BorderType type, const QString title, QWidget *parent) { qCDebug(dsrApp) << "ImageBorderHelper::getBorderMenu called for type:" << type << ", title:" << title; - if (!m_allBorderMenu.contains(type)) { - qCDebug(dsrApp) << "Menu for type" << type << "not found, creating new one"; - m_allBorderMenu.insert(type, new ImageMenu(type, title, parent)); + pruneBorderMenus(); + + if (ImageMenu *cached = m_allBorderMenu.value(type)) { + if (cached->parent() == parent) { + return cached; + } + m_allBorderMenu.remove(type); + delete cached; } - qCDebug(dsrApp) << "Returning menu for type:" << type; - return m_allBorderMenu[type]; + + ImageMenu *menu = new ImageMenu(type, title, parent); + m_allBorderMenu.insert(type, menu); + qCDebug(dsrApp) << "Created border menu for type:" << type; + return menu; } void ImageBorderHelper::setActionState(const BorderType type, const bool isChecked) @@ -270,10 +289,14 @@ void ImageBorderHelper::setActionState(const BorderType type, const bool isCheck qCDebug(dsrApp) << "ImageBorderHelper::setActionState called for type:" << type << ", isChecked:" << isChecked; // 选中某边框,后清空其他类型的所有边框 for (auto itr = m_allBorderMenu.begin(); itr != m_allBorderMenu.end(); ++itr) { - qCDebug(dsrApp) << "Processing menu for border type:" << itr.value()->borderType(); - if (itr.value()->borderType() != type) { - qCDebug(dsrApp) << "Clearing action state for other border type:" << itr.value()->borderType(); - itr.value()->ActionChecked(nullptr); + ImageMenu *menu = itr.value(); + if (!menu) { + continue; + } + qCDebug(dsrApp) << "Processing menu for border type:" << menu->borderType(); + if (menu->borderType() != type) { + qCDebug(dsrApp) << "Clearing action state for other border type:" << menu->borderType(); + menu->ActionChecked(nullptr); } } @@ -287,6 +310,9 @@ int ImageBorderHelper::getBorderTypeDetail() int typeDetail = 0; for (auto itr = m_allBorderMenu.begin(); itr != m_allBorderMenu.end(); ++itr) { ImageMenu *menu = itr.value(); + if (!menu) { + continue; + } qCDebug(dsrApp) << "Getting border type detail for menu of type:" << menu->borderType(); typeDetail = menu->getBorderTypeDetail(); if (typeDetail != 0) { @@ -306,9 +332,9 @@ void ImageBorderHelper::setBorderTypeDetail(const int typeDetail) int id = typeDetail & 0xFF; qCDebug(dsrApp) << "Parsed type:" << type << ", ID:" << id; - if (m_allBorderMenu.contains(type)) { + if (ImageMenu *menu = m_allBorderMenu.value(type)) { qCDebug(dsrApp) << "Menu for type" << type << "found, setting border type detail"; - m_allBorderMenu[type]->setBorderTypeDetail(id); + menu->setBorderTypeDetail(id); } } @@ -387,9 +413,12 @@ ImageBorderHelper::~ImageBorderHelper() { qCDebug(dsrApp) << "ImageBorderHelper destructor entered"; for (auto itr = m_allBorderMenu.begin(); itr != m_allBorderMenu.end(); ++itr) { - qCDebug(dsrApp) << "Deleting border menu for type:" << itr.value()->borderType(); - delete *itr; + if (ImageMenu *menu = itr.value()) { + qCDebug(dsrApp) << "Deleting border menu for type:" << menu->borderType(); + delete menu; + } } + m_allBorderMenu.clear(); if (m_borderhandle != nullptr) { qCDebug(dsrApp) << "Deleting border handler"; delete m_borderhandle; diff --git a/src/widgets/imagemenu.h b/src/widgets/imagemenu.h index 0299fb4cd..23530ad47 100644 --- a/src/widgets/imagemenu.h +++ b/src/widgets/imagemenu.h @@ -9,6 +9,7 @@ #include #include #include +#include DWIDGET_USE_NAMESPACE class BorderProcessInterface; @@ -26,6 +27,8 @@ class ImageBorderHelper : public QObject static ImageBorderHelper *instance(); ImageMenu* getBorderMenu(const BorderType type, const QString title, QWidget *parent = nullptr); + /** 工具栏/选项菜单销毁后清理悬空缓存(如 Treeland 重选区重建工具栏) */ + void pruneBorderMenus(); void setActionState(const BorderType type, const bool isChecked); int getBorderTypeDetail(); void setBorderTypeDetail(const int typeDetail); @@ -41,7 +44,7 @@ class ImageBorderHelper : public QObject ~ImageBorderHelper(); private: static ImageBorderHelper *m_imageBorderHelper; - QMap m_allBorderMenu; + QMap> m_allBorderMenu; BorderProcessInterface *m_borderhandle; }; diff --git a/src/widgets/toolbar.cpp b/src/widgets/toolbar.cpp index f29ce0e1b..f01087eae 100755 --- a/src/widgets/toolbar.cpp +++ b/src/widgets/toolbar.cpp @@ -323,38 +323,44 @@ void ToolBar::mouseReleaseEvent(QMouseEvent *event) void ToolBar::setScrollShotDisabled(const bool state) { + if (!m_toolbarWidget) { + return; + } m_toolbarWidget->setScrollShotDisabled(state); } void ToolBar::setPinScreenshotsEnable(const bool &state) { - m_toolbarWidget->setPinScreenshotsEnable(state); + if (m_toolbarWidget) + m_toolbarWidget->setPinScreenshotsEnable(state); } void ToolBar::setOcrScreenshotsEnable(const bool &state) { - m_toolbarWidget->setOcrScreenshotsEnable(state); + if (m_toolbarWidget) + m_toolbarWidget->setOcrScreenshotsEnable(state); } void ToolBar::setButEnableOnLockScreen(const bool &state) { - m_toolbarWidget->setButEnableOnLockScreen(state); + if (m_toolbarWidget) + m_toolbarWidget->setButEnableOnLockScreen(state); } int ToolBar::getFuncSubToolX(QString &func) { - return m_toolbarWidget->getFuncSubToolX(func); + return m_toolbarWidget ? m_toolbarWidget->getFuncSubToolX(func) : 0; } QRect ToolBar::getAiButtonGlobalRect() const { - return m_toolbarWidget->getAiButtonGlobalRect(); + return m_toolbarWidget ? m_toolbarWidget->getAiButtonGlobalRect() : QRect(); } QPoint ToolBar::getAiButtonGlobalCenter() const { - return m_toolbarWidget->getAiButtonGlobalCenter(); + return m_toolbarWidget ? m_toolbarWidget->getAiButtonGlobalCenter() : QPoint(); } bool ToolBar::isDraged() @@ -414,18 +420,21 @@ void ToolBar::hideWidget(){ void ToolBar::setRecordButtonDisable() { - m_toolbarWidget->setRecordButtonDisable(); + if (m_toolbarWidget) + m_toolbarWidget->setRecordButtonDisable(); } void ToolBar::setRecordLaunchMode(const unsigned int funType) { qCDebug(dsrApp) << "Setting record launch mode:" << funType; - m_toolbarWidget->setRecordLaunchFromMain(funType); + if (m_toolbarWidget) + m_toolbarWidget->setRecordLaunchFromMain(funType); } void ToolBar::setVideoButtonInit() { - m_toolbarWidget->setVideoInitFromMain(); + if (m_toolbarWidget) + m_toolbarWidget->setVideoInitFromMain(); } void ToolBar::shapeClickedFromMain(QString shape) @@ -442,11 +451,12 @@ void ToolBar::shapeClickedFromMain(QString shape) void ToolBar::setCameraDeviceEnable(bool status) { qCDebug(dsrApp) << "Setting camera device enable:" << status; - m_toolbarWidget->setCameraDeviceEnable(status); + if (m_toolbarWidget) + m_toolbarWidget->setCameraDeviceEnable(status); } QRect ToolBar::getShotOptionRect(){ - return m_toolbarWidget->getShotOptionRect(); + return m_toolbarWidget ? m_toolbarWidget->getShotOptionRect() : QRect(); } ToolBar::~ToolBar() {