/* BEGIN_COMMON_COPYRIGHT_HEADER * (c)LGPL2+ * * Copyright: 2011 Razor team * 2014 LXQt team * Authors: * Alexander Sokoloff * Maciej Płaza * Kuzma Shapran * * Copyright: 2019 Tianjin KYLIN Information Technology Co., Ltd. * * * This program or library is free software; you can redistribute it * and/or modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * You should have received a copy of the GNU Lesser General * Public License along with this library; if not, write to the * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301 USA * * END_COMMON_COPYRIGHT_HEADER */ #include #include #include #include #include #include #include #include #include #include #include #include #include "../panel/common/ukuigridlayout.h" #include #include "ukuitaskbar.h" #include "ukuitaskgroup.h" using namespace UKUi; /************************************************ ************************************************/ UKUITaskBar::UKUITaskBar(IUKUIPanelPlugin *plugin, QWidget *parent) : QFrame(parent), mSignalMapper(new QSignalMapper(this)), mButtonStyle(Qt::ToolButtonIconOnly), mButtonWidth(400), mButtonHeight(100), mCloseOnMiddleClick(true), mRaiseOnCurrentDesktop(true), mShowOnlyOneDesktopTasks(true), mShowDesktopNum(0), mShowOnlyCurrentScreenTasks(false), mShowOnlyMinimizedTasks(false), mAutoRotate(true), mGroupingEnabled(true), mShowGroupOnHover(true), mIconByClass(false), mCycleOnWheelScroll(true), mPlugin(plugin), mPlaceHolder(new QWidget(this)), mStyle(new LeftAlignedTextStyle()) { qDebug()<<"Plugin-Taskbar :: UKUITaskBar start"; taskstatus=NORMAL; setAttribute(Qt::WA_TranslucentBackground);//设置窗口背景透明 setWindowFlags(Qt::FramelessWindowHint); //设置无边框窗口 //setStyle(mStyle); mLayout = new UKUi::GridLayout(this); setLayout(mLayout); mLayout->setMargin(0); mLayout->setStretch(UKUi::GridLayout::StretchHorizontal | UKUi::GridLayout::StretchVertical); realign(); mPlaceHolder->setMinimumSize(1, 1); mPlaceHolder->setMaximumSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX); mPlaceHolder->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding)); mLayout->addWidget(mPlaceHolder); QTimer::singleShot(0,[this] {refreshPlaceholderVisibility();}); // QTimer::singleShot(0, this, SLOT(settingsChanged())); settingsChanged(); // setButtonStyle(Qt::ToolButtonIconOnly); setAcceptDrops(true); QGSettings *changeTheme; const QByteArray id_Theme("org.ukui.style"); if(QGSettings::isSchemaInstalled(id_Theme)){ changeTheme = new QGSettings(id_Theme); } connect(changeTheme, &QGSettings::changed, this, [=] (const QString &key){ if(key=="iconThemeName"){ sleep(1); for(auto it= mKnownWindows.begin(); it != mKnownWindows.end();it++) { UKUITaskGroup *group = it.value(); group->updateIcon(); } } }); connect(mSignalMapper, static_cast(&QSignalMapper::mapped), this, &UKUITaskBar::activateTask); QTimer::singleShot(0, this, &UKUITaskBar::registerShortcuts); connect(KWindowSystem::self(), static_cast(&KWindowSystem::windowChanged) , this, &UKUITaskBar::onWindowChanged); connect(KWindowSystem::self(), &KWindowSystem::windowAdded, this, &UKUITaskBar::onWindowAdded); connect(KWindowSystem::self(), &KWindowSystem::windowRemoved, this, &UKUITaskBar::onWindowRemoved); //龙芯机器的最小化任务窗口的预览窗口的特殊处理 system("cat /proc/cpuinfo >> /tmp/_tmp_cpu_info_cat_"); QFile file("/tmp/_tmp_cpu_info_cat_"); if (!file.open(QIODevice::ReadOnly)) qDebug() << "Read CpuInfo Failed."; while (CpuInfoFlg && !file.atEnd()) { QByteArray line = file.readLine(); QString str(line); if (str.contains("Loongson")) CpuInfoFlg = false; } file.close(); /**/ QDBusConnection::sessionBus().unregisterService("com.ukui.panel.plugins.service"); QDBusConnection::sessionBus().registerService("com.ukui.panel.plugins.service"); QDBusConnection::sessionBus().registerObject("/taskbar/click", this,QDBusConnection :: ExportAllSlots | QDBusConnection :: ExportAllSignals); qDebug()<<"Plugin-Taskbar :: UKUITaskBar end"; } /************************************************ ************************************************/ UKUITaskBar::~UKUITaskBar() { delete mStyle; } /************************************************ ************************************************/ bool UKUITaskBar::acceptWindow(WId window) const { QFlags ignoreList; ignoreList |= NET::DesktopMask; ignoreList |= NET::DockMask; ignoreList |= NET::SplashMask; ignoreList |= NET::ToolbarMask; ignoreList |= NET::MenuMask; ignoreList |= NET::PopupMenuMask; ignoreList |= NET::NotificationMask; ignoreList |= NET::UtilityMask; KWindowInfo info(window, NET::WMWindowType | NET::WMState, NET::WM2TransientFor); if (!info.valid()) return false; if (NET::typeMatchesMask(info.windowType(NET::AllTypesMask), ignoreList)) return false; if (info.state() & NET::SkipTaskbar) return false; // WM_TRANSIENT_FOR hint not set - normal window WId transFor = info.transientFor(); if (transFor == 0 || transFor == window || transFor == (WId) QX11Info::appRootWindow()) return true; info = KWindowInfo(transFor, NET::WMWindowType); QFlags normalFlag; normalFlag |= NET::NormalMask; normalFlag |= NET::DialogMask; normalFlag |= NET::UtilityMask; return !NET::typeMatchesMask(info.windowType(NET::AllTypesMask), normalFlag); } bool UKUITaskBar::ignoreSymbolCMP(QString filename,QString groupname) { if (filename.isEmpty()) return false; groupname.replace(" ", ""); groupname.replace("-", "."); groupname.replace(".demo", ""); groupname.replace(".py", ""); groupname.replace("org.", ""); groupname.replace(".qt", ""); filename.replace(" ", ""); filename.replace("-", "."); filename.replace("org.", ""); filename.replace(".desktop", ""); if (groupname.toLower().contains(filename.toLower(), Qt::CaseInsensitive)) return true; if (filename.toLower().contains(groupname.toLower(), Qt::CaseInsensitive)) return true; if (groupname.toLower().contains("kylinweather") && filename.toLower().contains("china.weather")) return true; if (groupname.toLower().contains("srhuijian") && filename.toLower().contains("huijian")) return true; if (groupname.contains("用户手册") && filename.toLower().contains("kylin.user.guid")) return true; if (groupname.toLower().contains("wpsoffice") && filename.toLower().contains("wps.office.prometheus")) return true; if (groupname.toLower().contains("ukuisystemmonitor") && filename.toLower().contains("ukui.system.monitor")) return true; return false; } /************************************************ ************************************************/ void UKUITaskBar::dragEnterEvent(QDragEnterEvent* event) { if (event->mimeData()->hasFormat(UKUITaskGroup::mimeDataFormat())) { event->acceptProposedAction(); buttonMove(nullptr, qobject_cast(event->source()), event->pos()); } else event->ignore(); QWidget::dragEnterEvent(event); } /************************************************ ************************************************/ void UKUITaskBar::dragMoveEvent(QDragMoveEvent * event) { //we don't get any dragMoveEvents if dragEnter wasn't accepted buttonMove(nullptr, qobject_cast(event->source()), event->pos()); QWidget::dragMoveEvent(event); } /************************************************ ************************************************/ void UKUITaskBar::buttonMove(UKUITaskGroup * dst, UKUITaskGroup * src, QPoint const & pos) { int src_index; if (!src || -1 == (src_index = mLayout->indexOf(src))) { qDebug() << "Dropped invalid"; return; } const int size = mLayout->count(); Q_ASSERT(0 < size); //dst is nullptr in case the drop occured on empty space in taskbar int dst_index; if (nullptr == dst) { //moving based on taskbar (not signaled by button) QRect occupied = mLayout->occupiedGeometry(); QRect last_empty_row{occupied}; const QRect last_item_geometry = mLayout->itemAt(size - 1)->geometry(); if (mPlugin->panel()->isHorizontal()) { if (isRightToLeft()) { last_empty_row.setTopRight(last_item_geometry.topLeft()); } else { last_empty_row.setTopLeft(last_item_geometry.topRight()); } } else { if (isRightToLeft()) { last_empty_row.setTopRight(last_item_geometry.topRight()); } else { last_empty_row.setTopLeft(last_item_geometry.topLeft()); } } if (occupied.contains(pos) && !last_empty_row.contains(pos)) return; dst_index = size; } else { //moving based on signal from child button dst_index = mLayout->indexOf(dst); } //moving lower index to higher one => consider as the QList::move => insert(to, takeAt(from)) if (src_index < dst_index) { if (size == dst_index || src_index + 1 != dst_index) { --dst_index; } else { //switching positions of next standing const int tmp_index = src_index; src_index = dst_index; dst_index = tmp_index; } } if (dst_index == src_index || mLayout->animatedMoveInProgress() ) return; mLayout->moveItem(src_index, dst_index, true); } /************************************************ ************************************************/ void UKUITaskBar::groupBecomeEmptySlot() { //group now contains no buttons - clean up in hash and delete the group UKUITaskGroup * const group = qobject_cast(sender()); Q_ASSERT(group); for (auto i = mKnownWindows.begin(); mKnownWindows.end() != i; ) { if (group == *i) i = mKnownWindows.erase(i); else ++i; } mLayout->removeWidget(group); group->deleteLater(); } /************************************************ ************************************************/ void UKUITaskBar::addWindow(WId window) { // If grouping disabled group behaves like regular button const QString group_id = mGroupingEnabled ? KWindowInfo(window, 0, NET::WM2WindowClass).windowClassClass() : QString("%1").arg(window); //针对ukui-menu和ukui-sidebar做的特殊处理,及时窗口是普通窗口,也不在任务栏显示 QStringList ignoreWindow; ignoreWindow<<"ukui-menu"<<"ukui-sidebar"<<"ukui-search"; if(ignoreWindow.contains(group_id)) { qDebug()<<"ignoreWindow.contains(group_id)"; return; } UKUITaskGroup *group = nullptr; auto i_group = mKnownWindows.find(window); if (mKnownWindows.end() != i_group) { if ((*i_group)->groupName() == group_id) group = *i_group; else (*i_group)->onWindowRemoved(window); } /*check if window belongs to some existing group * 安卓兼容应用的组名为kydroid-display-window * 需要将安卓兼容目录的分组特性关闭 */ QStringList andriod_window_list; andriod_window_list<<"kydroid-display-window"<<"kylin-kmre-window"; if (!group && mGroupingEnabled && !andriod_window_list.contains(group_id)) { for (auto i = mKnownWindows.cbegin(), i_e = mKnownWindows.cend(); i != i_e; ++i) { if ((*i)->groupName() == group_id) { group = *i; break; } } } if (!group) { group = new UKUITaskGroup(group_id, window, this); connect(group, SIGNAL(groupBecomeEmpty(QString)), this, SLOT(groupBecomeEmptySlot())); connect(group, SIGNAL(visibilityChanged(bool)), this, SLOT(refreshPlaceholderVisibility())); connect(group, &UKUITaskGroup::popupShown, this, &UKUITaskBar::popupShown); connect(group, &UKUITaskButton::dragging, this, [this] (QObject * dragSource, QPoint const & pos) { buttonMove(qobject_cast(sender()), qobject_cast(dragSource), pos); }); //group->setFixedSize(panel()->panelSize(),panel()->panelSize()); mLayout->addWidget(group); group->setToolButtonsStyle(mButtonStyle); } mKnownWindows[window] = group; group->addWindow(window); group->groupName(); } /************************************************ ************************************************/ auto UKUITaskBar::removeWindow(windowMap_t::iterator pos) -> windowMap_t::iterator { WId const window = pos.key(); UKUITaskGroup * const group = *pos; auto ret = mKnownWindows.erase(pos); group->onWindowRemoved(window); return ret; } /************************************************ ************************************************/ void UKUITaskBar::refreshTaskList() { QList new_list; // Just add new windows to groups, deleting is up to the groups const auto wnds = KWindowSystem::stackingOrder(); for (auto const wnd: wnds) { if (acceptWindow(wnd)) { new_list << wnd; addWindow(wnd); } } //emulate windowRemoved if known window not reported by KWindowSystem for (auto i = mKnownWindows.begin(), i_e = mKnownWindows.end(); i != i_e; ) { if (0 > new_list.indexOf(i.key())) { i = removeWindow(i); } else ++i; } refreshPlaceholderVisibility(); } /************************************************ ************************************************/ void UKUITaskBar::onWindowChanged(WId window, NET::Properties prop, NET::Properties2 prop2) { auto i = mKnownWindows.find(window); if (mKnownWindows.end() != i) { if (!(*i)->onWindowChanged(window, prop, prop2) && acceptWindow(window)) { // window is removed from a group because of class change, so we should add it again addWindow(window); } } } void UKUITaskBar::onWindowAdded(WId window) { auto const pos = mKnownWindows.find(window); if (mKnownWindows.end() == pos && acceptWindow(window)) addWindow(window); } /************************************************ ************************************************/ void UKUITaskBar::onWindowRemoved(WId window) { auto const pos = mKnownWindows.find(window); if (mKnownWindows.end() != pos) { removeWindow(pos); } } /************************************************ ************************************************/ void UKUITaskBar::refreshButtonRotation() { bool autoRotate = mAutoRotate && (mButtonStyle != Qt::ToolButtonIconOnly); IUKUIPanel::Position panelPosition = mPlugin->panel()->position(); // emit buttonRotationRefreshed(autoRotate, panelPosition); } /************************************************ ************************************************/ void UKUITaskBar::refreshPlaceholderVisibility() { // if no visible group button show placeholder widget bool haveVisibleWindow = false; for (auto i = mKnownWindows.cbegin(), i_e = mKnownWindows.cend(); i_e != i; ++i) { if ((*i)->isVisible()) { haveVisibleWindow = true; break; } } mPlaceHolder->setVisible(!haveVisibleWindow); if (haveVisibleWindow) mPlaceHolder->setFixedSize(0, 0); else { mPlaceHolder->setMinimumSize(1, 1); mPlaceHolder->setMaximumSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX); } } /************************************************ ************************************************/ void UKUITaskBar::setButtonStyle(Qt::ToolButtonStyle buttonStyle) { emit buttonStyleRefreshed(mButtonStyle); } void UKUITaskBar::settingsChanged() { bool groupingEnabledOld = mGroupingEnabled; bool showOnlyOneDesktopTasksOld = mShowOnlyOneDesktopTasks; const int showDesktopNumOld = mShowDesktopNum; bool showOnlyCurrentScreenTasksOld = mShowOnlyCurrentScreenTasks; bool showOnlyMinimizedTasksOld = mShowOnlyMinimizedTasks; const bool iconByClassOld = mIconByClass; mButtonWidth = mPlugin->settings()->value("buttonWidth", 400).toInt(); mButtonHeight = mPlugin->settings()->value("buttonHeight", 100).toInt(); QString s = mPlugin->settings()->value("buttonStyle").toString().toUpper(); if (s == "ICON") setButtonStyle(Qt::ToolButtonIconOnly); else if (s == "TEXT") setButtonStyle(Qt::ToolButtonTextOnly); else setButtonStyle(Qt::ToolButtonIconOnly); mShowOnlyOneDesktopTasks = mPlugin->settings()->value("showOnlyOneDesktopTasks", mShowOnlyOneDesktopTasks).toBool(); mShowDesktopNum = mPlugin->settings()->value("showDesktopNum", mShowDesktopNum).toInt(); mShowOnlyCurrentScreenTasks = mPlugin->settings()->value("showOnlyCurrentScreenTasks", mShowOnlyCurrentScreenTasks).toBool(); mShowOnlyMinimizedTasks = mPlugin->settings()->value("showOnlyMinimizedTasks", mShowOnlyMinimizedTasks).toBool(); mAutoRotate = mPlugin->settings()->value("autoRotate", true).toBool(); mCloseOnMiddleClick = mPlugin->settings()->value("closeOnMiddleClick", true).toBool(); mRaiseOnCurrentDesktop = mPlugin->settings()->value("raiseOnCurrentDesktop", false).toBool(); mGroupingEnabled = mPlugin->settings()->value("groupingEnabled",true).toBool(); mShowGroupOnHover = mPlugin->settings()->value("showGroupOnHover",true).toBool(); mIconByClass = mPlugin->settings()->value("iconByClass", false).toBool(); mCycleOnWheelScroll = mPlugin->settings()->value("cycleOnWheelScroll", true).toBool(); // Delete all groups if grouping feature toggled and start over if (groupingEnabledOld != mGroupingEnabled) { for (int i = mLayout->count() - 1; 0 <= i; --i) { UKUITaskGroup * group = qobject_cast(mLayout->itemAt(i)->widget()); if (nullptr != group) { mLayout->takeAt(i); group->deleteLater(); } } mKnownWindows.clear(); } if (showOnlyOneDesktopTasksOld != mShowOnlyOneDesktopTasks || (mShowOnlyOneDesktopTasks && showDesktopNumOld != mShowDesktopNum) || showOnlyCurrentScreenTasksOld != mShowOnlyCurrentScreenTasks || showOnlyMinimizedTasksOld != mShowOnlyMinimizedTasks ) emit showOnlySettingChanged(); if (iconByClassOld != mIconByClass) emit iconByClassChanged(); refreshTaskList(); } void UKUITaskBar::setShowGroupOnHover(bool bFlag) { mShowGroupOnHover = bFlag; } void UKUITaskBar::realign() { mLayout->setEnabled(false); refreshButtonRotation(); IUKUIPanel *panel = mPlugin->panel(); //set taskbar width by panel QSize maxSize = QSize(mPlugin->panel()->panelSize(), mPlugin->panel()->panelSize()); QSize minSize = QSize(mPlugin->panel()->iconSize()/2, mPlugin->panel()->iconSize()/2); int iconsize = panel->iconSize(); int panelsize = panel->panelSize(); bool rotated = false; if (panel->isHorizontal()) { mLayout->setRowCount(panel->lineCount()); mLayout->setColumnCount(0); } else { mLayout->setRowCount(0); if (mButtonStyle == Qt::ToolButtonIconOnly) { // Vertical + Icons mLayout->setColumnCount(panel->lineCount()); } else { rotated = mAutoRotate && (panel->position() == IUKUIPanel::PositionLeft || panel->position() == IUKUIPanel::PositionRight); // Vertical + Text if (rotated) { maxSize.rwidth() = mButtonHeight; maxSize.rheight() = mButtonWidth; mLayout->setColumnCount(panel->lineCount()); } else { mLayout->setColumnCount(1); } } } for(auto it= mKnownWindows.begin(); it != mKnownWindows.end();it++) { UKUITaskGroup *group = it.value(); //group->setFixedSize(panelsize, panelsize); group->setIconSize(QSize(iconsize,iconsize)); // group->updateIcon(); } mLayout->setCellMinimumSize(minSize); mLayout->setCellMaximumSize(maxSize); mLayout->setDirection(rotated ? UKUi::GridLayout::TopToBottom : UKUi::GridLayout::LeftToRight); mLayout->setEnabled(true); //our placement on screen could have been changed emit showOnlySettingChanged(); emit refreshIconGeometry(); } /************************************************ ************************************************/ void UKUITaskBar::wheelEvent(QWheelEvent* event) { #if 0 if (!mCycleOnWheelScroll) return QFrame::wheelEvent(event); static int threshold = 0; threshold += abs(event->delta()); if (threshold < 300) return QFrame::wheelEvent(event); else threshold = 0; int delta = event->delta() < 0 ? 1 : -1; // create temporary list of visible groups in the same order like on the layout QList list; UKUITaskGroup *group = NULL; for (int i = 0; i < mLayout->count(); i++) { QWidget * o = mLayout->itemAt(i)->widget(); UKUITaskGroup * g = qobject_cast(o); if (!g) continue; if (g->isVisible()) list.append(g); if (g->isChecked()) group = g; } if (list.isEmpty()) return QFrame::wheelEvent(event); if (!group) group = list.at(0); UKUITaskButton *button = NULL; // switching between groups from temporary list in modulo addressing while (!button)conSize() { button = group->getNextPrevChildButton(delta == 1, !(list.count() - 1)); if (button) button->raiseApplication(); int idx = (list.indexOf(group) + delta + list.count()) % list.count(); group = list.at(idx); } QFrame::wheelEvent(event); #endif } /************************************************ ************************************************/ void UKUITaskBar::resizeEvent(QResizeEvent* event) { emit refreshIconGeometry(); return QWidget::resizeEvent(event); } /************************************************ ************************************************/ void UKUITaskBar::changeEvent(QEvent* event) { // if current style is changed, reset the base style of the proxy style // so we can apply the new style correctly to task buttons. if(event->type() == QEvent::StyleChange) mStyle->setBaseStyle(NULL); QFrame::changeEvent(event); } /************************************************ ************************************************/ void UKUITaskBar::registerShortcuts() { // Register shortcuts to switch to the task // mPlaceHolder is always at position 0 // tasks are at positions 1..10 // GlobalKeyShortcut::Action * gshortcut; // QString path; // QString description; // for (int i = 1; i <= 10; ++i) // { // path = QString("/panel/%1/task_%2").arg(mPlugin->settings()->group()).arg(i); // description = tr("Activate task %1").arg(i); // gshortcut = GlobalKeyShortcut::Client::instance()->addAction(QStringLiteral(), path, description, this); // if (nullptr != gshortcut) // { // mKeys << gshortcut; // connect(gshortcut, &GlobalKeyShortcut::Action::registrationFinished, this, &UKUITaskBar::shortcutRegistered); // connect(gshortcut, &GlobalKeyShortcut::Action::activated, mSignalMapper, static_cast(&QSignalMapper::map)); // mSignalMapper->setMapping(gshortcut, i); // } // } } void UKUITaskBar::shortcutRegistered() { // GlobalKeyShortcut::Action * const shortcut = qobject_cast(sender()); // disconnect(shortcut, &GlobalKeyShortcut::Action::registrationFinished, this, &UKUITaskBar::shortcutRegistered); // const int i = mKeys.indexOf(shortcut); // Q_ASSERT(-1 != i); // if (shortcut->shortcut().isEmpty()) // { // // Shortcuts come in order they were registered // // starting from index 0 // const int key = (i + 1) % 10; // shortcut->changeShortcut(QStringLiteral("Meta+%1").arg(key)); // } } void UKUITaskBar::activateTask(int pos) { for (int i = 1; i < mLayout->count(); ++i) { QWidget * o = mLayout->itemAt(i)->widget(); UKUITaskGroup * g = qobject_cast(o); if (g && g->isVisible()) { pos--; if (pos == 0) { g->raiseApplication(); break; } } } } void UKUITaskBar::enterEvent(QEvent *) { taskstatus=HOVER; update(); } void UKUITaskBar::leaveEvent(QEvent *) { taskstatus=NORMAL; update(); } void UKUITaskBar::paintEvent(QPaintEvent *) { QStyleOption opt; opt.initFrom(this); QPainter p(this); switch(taskstatus) { case NORMAL: { // p.setBrush(QBrush(QColor(0xFF,0xFF,0xFF,0x19))); p.setPen(Qt::NoPen); break; } case HOVER: { // p.setBrush(QBrush(QColor(0xFF,0xFF,0xFF,0x19))); p.setPen(Qt::NoPen); break; } case PRESS: { // p.setBrush(QBrush(QColor(0x13,0x14,0x14,0xb2))); p.setPen(Qt::NoPen); break; } } p.setRenderHint(QPainter::Antialiasing); p.drawRoundedRect(opt.rect,6,6); style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this); } void UKUITaskBar::mousePressEvent(QMouseEvent *) { /*创建QT的DBus信号*/ QDBusMessage message =QDBusMessage::createSignal("/taskbar/click", "com.ukui.panel.plugins.taskbar", "sendToUkuiDEApp"); /* * 发射信号,此处不给信号赋值  message << QString("clicked");的原因是 * 侧边栏和开始菜单仅需要点击信号 * 若后期有特殊的设计需求,例如对鼠标左键,右键,滚轮 进行不同的处理就需要给信号赋值 * tr: * Transmit the signal, the signal is not assigned here The reason is * The sidebar and start menu only need to click the signal * If there are special design requirements in the later stage, * such as different processing for the left mouse button, right mouse button, and scroll wheel, * the signal needs to be assigned and processed * * 需要此点击信号的应用需要做如下绑定 * QDBusConnection::sessionBus().connect(QString(), QString("/taskbar/click"), "com.ukui.panel.plugins.taskbar", "sendToUkuiDEApp", this, SLOT(client_get(void))); * 在槽函数client_get(void) 中处理接受到的点击信号 * tr: * Applications that require this click signal need to do the following binding * Process the received click signal in the slot function client_get (void) * NOTE:https://blog.csdn.net/czhzasui/article/details/81071383    */ QDBusConnection::sessionBus().send(message); }