├── HTYDock ├── preview.png ├── launcher.png ├── res.qrc ├── install.sh ├── main.cpp ├── datetimewidget.h ├── HTYDock.pro ├── netspeedwidget.h ├── README.md ├── trashwidget.h ├── appwidget.h ├── mainwindow.h ├── appwidget.cpp ├── trashwidget.cpp ├── netspeedwidget.cpp ├── datetimewidget.cpp └── mainwindow.cpp /HTYDock: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sonichy/HTYDock_KWin/HEAD/HTYDock -------------------------------------------------------------------------------- /preview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sonichy/HTYDock_KWin/HEAD/preview.png -------------------------------------------------------------------------------- /launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sonichy/HTYDock_KWin/HEAD/launcher.png -------------------------------------------------------------------------------- /res.qrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | launcher.png 4 | 5 | 6 | -------------------------------------------------------------------------------- /install.sh: -------------------------------------------------------------------------------- 1 | s="[Desktop Entry]\nName=海天鹰Dock\nComment=HTY Dock\nExec=`pwd`/HTYDock\nIcon=`pwd`/launcher.png\nPath=`pwd`\nType=Application\nTerminal=false\nCategories=System;" 2 | echo -e $s > HTYDock.desktop 3 | cp `pwd`/HTYDock.desktop ~/.local/share/applications/HTYDock.desktop -------------------------------------------------------------------------------- /main.cpp: -------------------------------------------------------------------------------- 1 | #include "mainwindow.h" 2 | #include 3 | 4 | int main(int argc, char *argv[]) 5 | { 6 | qSetMessagePattern("[ %{file}: %{line} ] %{message}"); 7 | QApplication a(argc, argv); 8 | a.setOrganizationName("HTY"); 9 | a.setApplicationName("HTYDock"); 10 | MainWindow w; 11 | w.show(); 12 | return a.exec(); 13 | } -------------------------------------------------------------------------------- /datetimewidget.h: -------------------------------------------------------------------------------- 1 | #ifndef DATETIMEWIDGET_H 2 | #define DATETIMEWIDGET_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | class DatetimeWidget : public QWidget 9 | { 10 | Q_OBJECT 11 | public: 12 | explicit DatetimeWidget(QWidget *parent = 0); 13 | 14 | private: 15 | QString clock_type; 16 | bool isMouseOn = false; 17 | QCalendarWidget *calendar; 18 | 19 | protected: 20 | void paintEvent(QPaintEvent *event); 21 | void enterEvent(QEvent *event); 22 | void leaveEvent(QEvent *event); 23 | void mousePressEvent(QMouseEvent *event); 24 | 25 | signals: 26 | 27 | public slots: 28 | 29 | }; 30 | 31 | #endif // DATETIMEWIDGET_H -------------------------------------------------------------------------------- /HTYDock.pro: -------------------------------------------------------------------------------- 1 | #------------------------------------------------- 2 | # 3 | # Project created by QtCreator 2020-03-27T11:29:29 4 | # 5 | #------------------------------------------------- 6 | 7 | QT += core gui KWindowSystem x11extras 8 | 9 | greaterThan(QT_MAJOR_VERSION, 4): QT += widgets 10 | 11 | TARGET = HTYDock 12 | TEMPLATE = app 13 | 14 | CONFIG += c++11 15 | 16 | SOURCES += main.cpp\ 17 | mainwindow.cpp \ 18 | datetimewidget.cpp \ 19 | appwidget.cpp \ 20 | netspeedwidget.cpp \ 21 | trashwidget.cpp 22 | 23 | HEADERS += mainwindow.h \ 24 | datetimewidget.h \ 25 | appwidget.h \ 26 | netspeedwidget.h \ 27 | trashwidget.h 28 | 29 | RESOURCES += \ 30 | res.qrc -------------------------------------------------------------------------------- /netspeedwidget.h: -------------------------------------------------------------------------------- 1 | #ifndef NETSPEEDWIDGET_H 2 | #define NETSPEEDWIDGET_H 3 | 4 | #include 5 | #include 6 | 7 | class NetSpeedWidget : public QWidget 8 | { 9 | Q_OBJECT 10 | public: 11 | explicit NetSpeedWidget(QWidget *parent = 0); 12 | 13 | private: 14 | long int i, db, ub, dbt, ubt, dbt1, ubt1, dbt0, ubt0, tt0, idle0; 15 | QString KB(long k); 16 | QString NB(long b); 17 | QString BS(long b); 18 | QString startup; 19 | bool isMouseOn = false; 20 | QLabel *label; 21 | 22 | protected: 23 | void paintEvent(QPaintEvent *event); 24 | void enterEvent(QEvent *event); 25 | void leaveEvent(QEvent *event); 26 | 27 | signals: 28 | 29 | public slots: 30 | 31 | }; 32 | 33 | #endif // NETSPEEDWIDGET_H -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 基于 Qt 和 KWindowSystem(窗管、背景模糊)的 Dock 程序。 2 | 已编译的 HTYDock 适用 64 位 Linux Qt>5.11。 3 | 4 | ![alt](preview.png) 5 | ### 运行依赖 6 | libkf5windowsystem5 7 | 8 | ### 编译依赖 9 | libkf5windowsystem-dev qmake make libqt5extras5-dev 10 | 11 | ### 参考 12 | https://github.com/linuxdeepin/dde-dock 13 | https://github.com/pandaos/panda-dock 14 | https://github.com/KDE/latte-dock 15 | [非系统程序获取图标](https://github.com/linuxdeepin/deepin-system-monitor/blob/117a3b90cb02ecca4990f2136400147c59801dc5/src/utils.cpp#L379) 16 | [为QWidget创建鼠标点击信号](https://blog.csdn.net/l285345042/article/details/8161320) 17 | 18 | ### KWindowSystem API 19 | https://api.kde.org/frameworks/kwindowsystem/html/index.html 20 | 21 | ### 版本日志 22 | V2.0 (2020-04) 23 | 自定义 QWidget 实现悬浮预览窗。 24 | 25 | V1.0 (2020-03) 26 | 使用 QPushButton 做按钮。 27 | 28 | ### 已知问题 29 | 预览窗截图不对:除了深度文管,其他窗口最小化以后都截屏。 -------------------------------------------------------------------------------- /trashwidget.h: -------------------------------------------------------------------------------- 1 | #ifndef TRASHWIDGET_H 2 | #define TRASHWIDGET_H 3 | 4 | #include 5 | #include 6 | 7 | class TrashWidget : public QWidget 8 | { 9 | Q_OBJECT 10 | public: 11 | explicit TrashWidget(QWidget *parent = 0); 12 | QPixmap pixmap_icon, pixmap; 13 | 14 | private: 15 | bool isMouseOn = false; 16 | QPixmap pixmap_dragEnter; 17 | QPoint point_mouse; 18 | QString dir_trash; 19 | 20 | protected: 21 | void paintEvent(QPaintEvent *event); 22 | void enterEvent(QEvent *event); 23 | void leaveEvent(QEvent *event); 24 | void mousePressEvent(QMouseEvent *event); 25 | void mouseReleaseEvent(QMouseEvent *event); 26 | void dragEnterEvent(QDragEnterEvent *event); 27 | void dragLeaveEvent(QDragLeaveEvent *event); 28 | void dropEvent(QDropEvent *event); 29 | 30 | signals: 31 | 32 | public slots: 33 | void trashChanged(QString path); 34 | 35 | }; 36 | 37 | #endif // TRASHWIDGET_H -------------------------------------------------------------------------------- /appwidget.h: -------------------------------------------------------------------------------- 1 | #ifndef APPWIDGET_H 2 | #define APPWIDGET_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | struct Dock : QObjectUserData 12 | { 13 | WId wid; 14 | }; 15 | 16 | class AppWidget : public QWidget 17 | { 18 | Q_OBJECT 19 | public: 20 | explicit AppWidget(QWidget *parent = 0); 21 | QList list_wid; 22 | int index=0; 23 | QButtonGroup *buttonGroup; 24 | QString name, className; 25 | QPixmap icon; 26 | bool isActive = false; 27 | void addPreview(WId wid); 28 | void removePreview(WId wid); 29 | 30 | private: 31 | bool isMouseOn = false; 32 | QWidget *widget_preview; 33 | QBoxLayout *boxLayout; 34 | QPoint point_mouse; 35 | QTimer *timer; 36 | 37 | protected: 38 | void paintEvent(QPaintEvent *event); 39 | void enterEvent(QEvent *event); 40 | void leaveEvent(QEvent *event); 41 | void mousePressEvent(QMouseEvent *event); 42 | void mouseReleaseEvent(QMouseEvent *event); 43 | 44 | signals: 45 | void clicked(); 46 | 47 | public slots: 48 | 49 | }; 50 | 51 | #endif // APPWIDGET_H -------------------------------------------------------------------------------- /mainwindow.h: -------------------------------------------------------------------------------- 1 | #ifndef MAINWINDOW_H 2 | #define MAINWINDOW_H 3 | 4 | #include "datetimewidget.h" 5 | #include "netspeedwidget.h" 6 | #include "appwidget.h" 7 | #include "trashwidget.h" 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | class MainWindow : public QMainWindow 16 | { 17 | Q_OBJECT 18 | 19 | public: 20 | MainWindow(QWidget *parent = 0); 21 | ~MainWindow(); 22 | 23 | protected: 24 | void paintEvent(QPaintEvent *event); 25 | 26 | private: 27 | int h, count_plugin=0; 28 | QString qss, mode, position; 29 | QWidget *widget_app; 30 | QPushButton *pushButton_launcher, *pushButton_desktop; 31 | QBoxLayout *boxLayout, *boxLayout_app; 32 | QSize size; 33 | QList list_appWidget; 34 | NET::Properties properties = NET::WMState | NET::XAWMState | NET::WMDesktop | NET::WMVisibleName | NET::WMGeometry | NET::WMWindowType; 35 | NET::Properties2 properties2 = NET::WM2WindowClass | NET::WM2AllowedActions | NET::WM2DesktopFileName; 36 | QSettings settings; 37 | DatetimeWidget *datetimeWidget; 38 | NetSpeedWidget *netSpeedWidget; 39 | TrashWidget *trashWidget; 40 | void addMenus(); 41 | void refit(); 42 | void resizeIcon(int w); 43 | 44 | private slots: 45 | void buttonClicked(AppWidget *appWidget); 46 | void windowAdded(WId wid); 47 | void windowRemoved(WId wid); 48 | void activeWindowChanged(WId wid); 49 | void windowChanged(WId wid, NET::Properties properties, NET::Properties2 properties2); 50 | 51 | }; 52 | 53 | #endif // MAINWINDOW_H -------------------------------------------------------------------------------- /appwidget.cpp: -------------------------------------------------------------------------------- 1 | #include "appwidget.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | AppWidget::AppWidget(QWidget *parent) : QWidget(parent) 9 | { 10 | widget_preview = new QWidget; 11 | boxLayout = new QBoxLayout(QBoxLayout::LeftToRight); 12 | widget_preview->setLayout(boxLayout); 13 | widget_preview->setWindowFlags(Qt::Tool | Qt::FramelessWindowHint); 14 | buttonGroup = new QButtonGroup; 15 | timer = new QTimer(this); 16 | connect(timer, SIGNAL(timeout()), widget_preview, SLOT(show())); 17 | timer->setSingleShot(true); 18 | } 19 | 20 | void AppWidget::enterEvent(QEvent *event) 21 | { 22 | Q_UNUSED(event); 23 | isMouseOn = true; 24 | update(); 25 | QScreen *screen = QApplication::primaryScreen(); 26 | for (int i=0; ibuttons().count(); i++) { 27 | QAbstractButton *button = buttonGroup->buttons().at(i); 28 | Dock *dock = static_cast(button->userData(Qt::UserRole)); 29 | button->setIcon(QIcon(screen->grabWindow(dock->wid,0,0,-1,-1).scaled(widget_preview->size(), Qt::KeepAspectRatio))); 30 | } 31 | QSettings settings(QCoreApplication::organizationName(), QCoreApplication::applicationName()); 32 | QString position = settings.value("Position", "Bottom").toString(); 33 | int x1=0, y1=0; 34 | if (position == "Bottom") { 35 | x1 = mapToGlobal(QPoint(0,0)).x() + width()/2 - widget_preview->width()/2; 36 | y1 = mapToGlobal(QPoint(0,0)).y() - widget_preview->height(); 37 | } else if (position == "Top") { 38 | x1 = mapToGlobal(QPoint(0,0)).x() + width()/2 - widget_preview->width()/2; 39 | y1 = height(); 40 | } else if (position == "Left") { 41 | x1 = width(); 42 | y1 = mapToGlobal(QPoint(0,0)).y() + height()/2 - widget_preview->height()/2; 43 | } else if (position == "Right") { 44 | x1 = QApplication::desktop()->width() - width() - widget_preview->width(); 45 | y1 = mapToGlobal(QPoint(0,0)).y() + height()/2 - widget_preview->height()/2; 46 | } 47 | widget_preview->move(x1, y1); 48 | timer->start(1000); 49 | } 50 | 51 | void AppWidget::leaveEvent(QEvent *event) 52 | { 53 | Q_UNUSED(event); 54 | isMouseOn = false; 55 | update(); 56 | if(widget_preview->isHidden()) 57 | timer->stop(); 58 | else 59 | widget_preview->hide(); 60 | } 61 | 62 | void AppWidget::paintEvent(QPaintEvent *event) 63 | { 64 | Q_UNUSED(event); 65 | QPainter painter(this); 66 | painter.setRenderHint(QPainter::Antialiasing, true); 67 | painter.setRenderHint(QPainter::SmoothPixmapTransform, true); 68 | painter.setPen(Qt::NoPen); 69 | if (isActive) { 70 | //渐变色失败 71 | // QRadialGradient radialGradient(width()/2,height()/2,width()/3,width()/2,height()/2); 72 | // radialGradient.setColorAt(0.0,Qt::white); 73 | // radialGradient.setColorAt(1.0,Qt::blue); 74 | // painter.setBrush(QBrush(radialGradient)); 75 | //painter.setBrush(QColor(48,140,198,200));//下划线 76 | //painter.drawRect(rect().adjusted(10, height()-2, -10, 0)); 77 | painter.setBrush(QColor(255,255,255,30));//蒙板 78 | painter.drawRoundRect(rect(), 50, 50); 79 | } 80 | if (isMouseOn) { 81 | painter.setBrush(QColor(255,255,255,30)); 82 | painter.drawRoundRect(rect(), 50, 50); 83 | } 84 | painter.drawPixmap(rect().adjusted(3,3,-3,-3), icon); 85 | if (list_wid.count() > 1) { 86 | painter.setBrush(QColor(255,0,0,100)); 87 | painter.drawEllipse(QRect(0,0,11,11)); 88 | painter.setPen(Qt::white); 89 | QFont font = this->font(); 90 | font.setPointSize(6); 91 | painter.setFont(font); 92 | painter.drawText(QRect(0,0,10,10), Qt::AlignCenter, QString::number(list_wid.count())); 93 | } 94 | } 95 | 96 | void AppWidget::mousePressEvent(QMouseEvent *event) 97 | { 98 | point_mouse = QPoint(event->x(), event->y()); 99 | widget_preview->hide(); 100 | } 101 | 102 | void AppWidget::mouseReleaseEvent(QMouseEvent *ev) 103 | { 104 | if (point_mouse == QPoint(ev->x(), ev->y())) 105 | emit clicked(); 106 | } 107 | 108 | void AppWidget::addPreview(WId wid) 109 | { 110 | QPushButton *button = new QPushButton; 111 | button->setFixedSize(150,100); 112 | button->setIconSize(button->size()); 113 | Dock *dock = new Dock; 114 | dock->wid = wid; 115 | button->setUserData(Qt::UserRole, dock); 116 | buttonGroup->addButton(button); 117 | boxLayout->addWidget(button); 118 | } 119 | 120 | void AppWidget::removePreview(WId wid) 121 | { 122 | for (int i=0; ibuttons().count(); i++) { 123 | QAbstractButton *button = buttonGroup->buttons().at(i); 124 | Dock *dock = static_cast(button->userData(Qt::UserRole)); 125 | if (dock->wid == wid) { 126 | //qDebug() << dock->wid; 127 | boxLayout->removeWidget(button); 128 | buttonGroup->removeButton(button); 129 | button->deleteLater(); 130 | } 131 | } 132 | } -------------------------------------------------------------------------------- /trashwidget.cpp: -------------------------------------------------------------------------------- 1 | #include "trashwidget.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | TrashWidget::TrashWidget(QWidget *parent) : QWidget(parent) 15 | { 16 | pixmap_icon = QIcon::fromTheme("user-trash").pixmap(size()); 17 | pixmap = pixmap_icon; 18 | pixmap_dragEnter = QIcon::fromTheme("user-trash-full-opened").pixmap(size()); 19 | setAcceptDrops(true); 20 | 21 | QFileSystemWatcher *FSW = new QFileSystemWatcher; 22 | dir_trash = QDir::homePath() + "/.local/share/Trash/files"; 23 | FSW->addPath(dir_trash); 24 | connect(FSW, SIGNAL(directoryChanged(QString)), this, SLOT(trashChanged(QString))); 25 | trashChanged(""); 26 | 27 | setContextMenuPolicy(Qt::CustomContextMenu); 28 | connect(this, &QWidget::customContextMenuRequested, [=](){ 29 | //[&](const QPoint& pos) 30 | QMenu *menu = new QMenu; 31 | menu->setStyleSheet("QMenu { color:white; background: rgba(0,0,0,100);}" 32 | "QMenu::item:selected { background: rgba(48,140,198,255);}"); 33 | menu->setAttribute(Qt::WA_TranslucentBackground, true); 34 | menu->setAutoFillBackground(true); 35 | QAction *action_empty_trash = new QAction("清空", this); 36 | connect(action_empty_trash, &QAction::triggered, [](){ 37 | QProcess::startDetached("gio", QStringList() << "trash" << "--empty"); 38 | }); 39 | menu->addAction(action_empty_trash); 40 | menu->adjustSize();//不加会到屏幕中间 41 | //menu->exec(mapToGlobal(pos)); 42 | int x1=0, y1=0; 43 | QSettings settings(QApplication::organizationName(), QApplication::applicationName()); 44 | QString position = settings.value("Position", "Bottom").toString(); 45 | if (position == "Top") { 46 | x1 = QPoint(mapToGlobal(QPoint(0,0))).x() + width()/2 - menu->width()/2; 47 | y1 = height(); 48 | } else if (position == "Bottom") { 49 | x1 = QPoint(mapToGlobal(QPoint(0,0))).x() + width()/2 - menu->width()/2; 50 | y1 = QPoint(mapToGlobal(QPoint(0,0))).y() - menu->height(); 51 | } else if (position == "Left") { 52 | x1 = width(); 53 | y1 = QPoint(mapToGlobal(QPoint(0,0))).y() + height()/2 - menu->height()/2; 54 | } else if (position == "Right") { 55 | x1 = QApplication::desktop()->width() - width() - menu->width(); 56 | y1 = QPoint(mapToGlobal(QPoint(0,0))).y() + height()/2 - menu->height()/2; 57 | } 58 | menu->exec(QPoint(x1, y1)); 59 | }); 60 | } 61 | 62 | void TrashWidget::enterEvent(QEvent *event) 63 | { 64 | Q_UNUSED(event); 65 | isMouseOn = true; 66 | update(); 67 | } 68 | 69 | void TrashWidget::leaveEvent(QEvent *event) 70 | { 71 | Q_UNUSED(event); 72 | isMouseOn = false; 73 | update(); 74 | } 75 | 76 | void TrashWidget::paintEvent(QPaintEvent *event) 77 | { 78 | Q_UNUSED(event); 79 | QPainter painter(this); 80 | painter.setRenderHint(QPainter::Antialiasing, true); 81 | painter.setRenderHint(QPainter::SmoothPixmapTransform, true); 82 | painter.setPen(Qt::NoPen); 83 | if (isMouseOn) { 84 | painter.setBrush(QColor(255,255,255,30)); 85 | painter.drawRoundRect(rect(), 50, 50); 86 | } 87 | painter.drawPixmap(rect().adjusted(3,3,-3,-3), pixmap); 88 | } 89 | 90 | void TrashWidget::dragEnterEvent(QDragEnterEvent *event) 91 | { 92 | qDebug() << event->mimeData(); 93 | if(event->mimeData()->hasFormat("text/uri-list")){ 94 | pixmap = pixmap_dragEnter; 95 | update(); 96 | event->acceptProposedAction(); 97 | } 98 | } 99 | 100 | void TrashWidget::dragLeaveEvent(QDragLeaveEvent *event) 101 | { 102 | Q_UNUSED(event); 103 | pixmap = pixmap_icon; 104 | update(); 105 | } 106 | 107 | void TrashWidget::dropEvent(QDropEvent *event) 108 | { 109 | QList urls = event->mimeData()->urls(); 110 | if (urls.isEmpty()) 111 | return ; 112 | 113 | foreach (QUrl u, urls) { 114 | qDebug() << "trash" << u.toString(); 115 | QProcess::startDetached("gio", QStringList() << "trash" << u.toString()); 116 | } 117 | qDebug() << urls.size(); 118 | trashChanged(""); 119 | } 120 | 121 | void TrashWidget::mousePressEvent(QMouseEvent *event) 122 | { 123 | point_mouse = QPoint(event->x(), event->y()); 124 | } 125 | 126 | void TrashWidget::mouseReleaseEvent(QMouseEvent *event) 127 | { 128 | if (point_mouse == QPoint(event->x(), event->y())) { 129 | QProcess::startDetached("gio", QStringList() << "open" << "trash:///"); 130 | } 131 | } 132 | 133 | void TrashWidget::trashChanged(QString path) 134 | { 135 | Q_UNUSED(path); 136 | QDir dir(dir_trash); 137 | int count = dir.entryList(QDir::AllEntries | QDir::Hidden | QDir::NoDotAndDotDot).count(); 138 | if (count == 0) { 139 | setToolTip("回收站"); 140 | pixmap_icon = QIcon::fromTheme("user-trash").pixmap(size()); 141 | } else { 142 | setToolTip("回收站 - " + QString::number(count) + "个文件"); 143 | pixmap_icon = QIcon::fromTheme("user-trash-full").pixmap(size()); 144 | } 145 | pixmap = pixmap_icon; 146 | update(); 147 | } -------------------------------------------------------------------------------- /netspeedwidget.cpp: -------------------------------------------------------------------------------- 1 | #include "netspeedwidget.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | NetSpeedWidget::NetSpeedWidget(QWidget *parent) : QWidget(parent) 13 | { 14 | i=db=ub=dbt=ubt=dbt1=ubt1=dbt0=ubt0=0; 15 | 16 | // Boot time 17 | QProcess *process = new QProcess; 18 | process->start("systemd-analyze"); 19 | process->waitForFinished(); 20 | QString PO = process->readAllStandardOutput(); 21 | QString SD = PO.mid(PO.indexOf("=") + 1, PO.indexOf("\n") - PO.indexOf("=") - 1); 22 | startup = "SUT: " + SD; 23 | 24 | QTimer *timer = new QTimer(this); 25 | connect(timer, SIGNAL(timeout()), this, SLOT(update())); 26 | timer->start(1000); 27 | 28 | label = new QLabel; 29 | label->setMargin(5); 30 | label->setWindowFlags(Qt::Tool | Qt::FramelessWindowHint); 31 | } 32 | 33 | void NetSpeedWidget::enterEvent(QEvent *event) 34 | { 35 | Q_UNUSED(event); 36 | isMouseOn = true; 37 | update(); 38 | QSettings settings(QCoreApplication::organizationName(), QCoreApplication::applicationName()); 39 | QString position = settings.value("Position", "Bottom").toString(); 40 | int x1=0, y1=0; 41 | if (position == "Bottom") { 42 | x1 = mapToGlobal(QPoint(0,0)).x() + width()/2 - label->width()/2; 43 | y1 = mapToGlobal(QPoint(0,0)).y() - label->height(); 44 | } else if (position == "Top") { 45 | x1 = mapToGlobal(QPoint(0,0)).x() + width()/2 - label->width()/2; 46 | y1 = height(); 47 | } else if (position == "Left") { 48 | x1 = width(); 49 | y1 = mapToGlobal(QPoint(0,0)).y() + height()/2 - label->height()/2; 50 | } else if (position == "Right") { 51 | x1 = QApplication::desktop()->width() - width() - label->width(); 52 | y1 = mapToGlobal(QPoint(0,0)).y() + height()/2 - label->height()/2; 53 | } 54 | label->move(x1, y1); 55 | label->show(); 56 | } 57 | 58 | void NetSpeedWidget::leaveEvent(QEvent *event) 59 | { 60 | Q_UNUSED(event); 61 | isMouseOn = false; 62 | update(); 63 | label->hide(); 64 | } 65 | 66 | void NetSpeedWidget::paintEvent(QPaintEvent *event) 67 | { 68 | Q_UNUSED(event); 69 | QSettings settings(QCoreApplication::organizationName(), QCoreApplication::applicationName()); 70 | bool b = settings.value("isShowNetSpeed", true).toBool(); 71 | if (!b) 72 | return; 73 | 74 | // uptime 75 | QFile file("/proc/uptime"); 76 | file.open(QIODevice::ReadOnly); 77 | QString l = file.readLine(); 78 | file.close(); 79 | QTime t(0,0,0); 80 | t = t.addSecs(l.left(l.indexOf(".")).toInt()); 81 | QString uptime = "UTM: " + t.toString("hh:mm:ss"); 82 | 83 | // memory 84 | file.setFileName("/proc/meminfo"); 85 | file.open(QIODevice::ReadOnly); 86 | l = file.readLine(); 87 | long mt = l.replace("MemTotal:","").replace("kB","").replace(" ","").toLong(); 88 | l = file.readLine(); 89 | l = file.readLine(); 90 | long ma = l.replace("MemAvailable:","").replace("kB","").replace(" ","").toLong(); 91 | l = file.readLine(); 92 | l = file.readLine(); 93 | file.close(); 94 | long mu = mt - ma; 95 | int mp = static_cast(mu*100/mt); 96 | QString mem = "MEM: " + QString("%1 / %2 = %3").arg(KB(mu)).arg(KB(mt)).arg(QString::number(mp) + "%"); 97 | 98 | // CPU 99 | file.setFileName("/proc/stat"); 100 | file.open(QIODevice::ReadOnly); 101 | l = file.readLine(); 102 | QByteArray ba; 103 | ba = l.toLatin1(); 104 | const char *ch; 105 | ch = ba.constData(); 106 | char cpu[5]; 107 | long user,nice,sys,idle,iowait,irq,softirq,tt; 108 | sscanf(ch,"%s%ld%ld%ld%ld%ld%ld%ld",cpu,&user,&nice,&sys,&idle,&iowait,&irq,&softirq); 109 | tt = user + nice + sys + idle + iowait + irq + softirq; 110 | file.close(); 111 | QString cusage = ""; 112 | int cp = 0; 113 | if (tt != tt0) 114 | cp = static_cast(((tt-tt0)-(idle-idle0))*100/(tt-tt0)); 115 | if (i > 0) 116 | cusage = "CPU: " + QString::number(cp) + "%"; 117 | idle0 = idle; 118 | tt0 = tt; 119 | 120 | // net 121 | file.setFileName("/proc/net/dev"); 122 | file.open(QIODevice::ReadOnly); 123 | l = file.readLine(); 124 | l = file.readLine(); 125 | dbt1 = ubt1 = 0; 126 | while(!file.atEnd()){ 127 | l = file.readLine(); 128 | QStringList list = l.split(QRegExp("\\s{1,}")); 129 | db = list.at(1).toLong(); 130 | ub = list.at(9).toLong(); 131 | dbt1 += db; 132 | ubt1 += ub; 133 | } 134 | file.close(); 135 | QString dss = ""; 136 | QString uss = ""; 137 | if (i > 0) { 138 | long ds = dbt1 - dbt0; 139 | long us = ubt1 - ubt0; 140 | dss = NB(ds) + "/s"; 141 | uss = NB(us) + "/s"; 142 | dbt0 = dbt1; 143 | ubt0 = ubt1; 144 | } 145 | QString netspeed = "↑" + uss + "\n↓" + dss; 146 | QString net = "UPB: " + BS(ubt1) + " " + uss + "\nDNB: " + BS(dbt1) + " " + dss; 147 | 148 | i++; 149 | if (i>2) i = 2; 150 | 151 | QPainter painter(this); 152 | painter.setRenderHint(QPainter::Antialiasing, true); 153 | //mouseover 154 | if (isMouseOn) { 155 | painter.setPen(Qt::NoPen); 156 | painter.setBrush(QColor(255,255,255,30)); 157 | painter.drawRoundRect(rect(), 50, 50); 158 | } 159 | //内存使用率竖条 160 | painter.setPen(Qt::gray); 161 | if (mp < 90) { 162 | painter.setBrush(QColor(0,255,0,150)); 163 | } else { 164 | painter.setBrush(QColor(255,0,0,150)); 165 | } 166 | painter.drawRect(rect().adjusted(0,height()*(100-mp)/100,-width()/2,0)); 167 | //CPU使用率竖条 168 | if (cp < 90) { 169 | painter.setBrush(QColor(0,255,0,150)); 170 | } else { 171 | painter.setBrush(QColor(255,0,0,150)); 172 | } 173 | painter.drawRect(rect().adjusted(width()/2,height()*(100-cp)/100,0,0)); 174 | //netspeed 175 | painter.setPen(Qt::white); 176 | QFont font = this->font(); 177 | font.setFamily("Noto Mono"); 178 | font.setPointSize(7); 179 | painter.setFont(font); 180 | painter.drawText(rect(), Qt::AlignCenter, netspeed); 181 | //tooltip 182 | label->setText(startup + "\n" + uptime + "\n" + cusage + "\n" + mem + "\n" + net); 183 | } 184 | 185 | QString NetSpeedWidget::KB(long k) 186 | { 187 | QString s = ""; 188 | if(k > 999999){ 189 | s = QString::number(k/(1024*1024.0),'f',2) + "GB"; 190 | }else{ 191 | if(k > 999){ 192 | s = QString::number(k/1024.0,'f',2) + "MB"; 193 | }else{ 194 | s = QString::number(k/1.0,'f',2) + "KB"; 195 | } 196 | } 197 | return s; 198 | } 199 | 200 | QString NetSpeedWidget::NB(long b) 201 | { 202 | QString s = ""; 203 | if (b>999) { 204 | s = QString("%1").arg(b/1024, 5, 'f', 0, QLatin1Char(' ')) + "KB"; 205 | } else { // <1K => 0 206 | s = QString("%1").arg(0, 5, 'f', 0, QLatin1Char(' ')) + "KB"; 207 | } 208 | return s; 209 | } 210 | 211 | QString NetSpeedWidget::BS(long b) 212 | { 213 | QString s = ""; 214 | if (b > 999999999) { 215 | //s = QString("%1").arg(b/(1024*1024*1024.0), 6, 'f', 2, QLatin1Char(' ')) + "GB"; 216 | s = QString::number(b/(1024*1024*1024.0), 'f', 2) + "GB"; 217 | } else { 218 | if (b > 999999) { 219 | //s = QString("%1").arg(b/(1024*1024.0), 6, 'f', 2, QLatin1Char(' ')) + "MB"; 220 | s = QString::number(b/(1024*1024.0), 'f', 2) + "MB"; 221 | } else { 222 | if (b > 999) { 223 | //s = QString("%1").arg(b/1024.0, 6, 'f', 2, QLatin1Char(' ')) + "KB"; 224 | s = QString::number(b/(1024.0), 'f',2) + "KB"; 225 | } else { 226 | s = QString::number(b) + "B"; 227 | } 228 | } 229 | } 230 | return s; 231 | } -------------------------------------------------------------------------------- /datetimewidget.cpp: -------------------------------------------------------------------------------- 1 | #include "datetimewidget.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | DatetimeWidget::DatetimeWidget(QWidget *parent) : QWidget(parent) 14 | { 15 | setAttribute(Qt::WA_TranslucentBackground, true); 16 | setStyleSheet("QMenu { color:white; background: rgba(0,0,0,100);}" 17 | "QMenu::item:selected { background: rgba(48,140,198,200);}"); 18 | 19 | QTimer *timer = new QTimer(this); 20 | connect(timer, SIGNAL(timeout()), this, SLOT(update())); 21 | timer->start(1000); 22 | 23 | QSettings settings(QApplication::organizationName(), QApplication::applicationName()); 24 | clock_type = settings.value("ClockType", "TEXT_CLOCK").toString(); 25 | 26 | calendar = new QCalendarWidget; 27 | calendar->setWindowFlags(Qt::Tool | Qt::FramelessWindowHint); 28 | 29 | setContextMenuPolicy(Qt::CustomContextMenu); 30 | connect(this, &QWidget::customContextMenuRequested, [=](){ 31 | //[&](const QPoint& pos) 32 | QMenu *menu = new QMenu; 33 | menu->setStyleSheet("QMenu { color:white; background: rgba(0,0,0,100);}" 34 | "QMenu::item:selected { background: rgba(48,140,198,255);}"); 35 | menu->setAttribute(Qt::WA_TranslucentBackground, true); 36 | menu->setAutoFillBackground(true); 37 | QAction *action_text = new QAction("文字", this); 38 | connect(action_text, &QAction::triggered, [=](){ 39 | clock_type = "TEXT_CLOCK"; 40 | QSettings settings(QApplication::organizationName(), QApplication::applicationName()); 41 | settings.setValue("ClockType", clock_type); 42 | update(); 43 | }); 44 | menu->addAction(action_text); 45 | QAction *action_digital = new QAction("数字", this); 46 | connect(action_digital, &QAction::triggered, [=](){ 47 | clock_type = "DIGITAL_CLOCK"; 48 | QSettings settings(QApplication::organizationName(), QApplication::applicationName()); 49 | settings.setValue("ClockType", clock_type); 50 | update(); 51 | }); 52 | menu->addAction(action_digital); 53 | QAction *action_analog = new QAction("模拟", this); 54 | connect(action_analog, &QAction::triggered, [=](){ 55 | clock_type = "ANALOG_CLOCK"; 56 | QSettings settings(QApplication::organizationName(), QApplication::applicationName()); 57 | settings.setValue("ClockType", clock_type); 58 | update(); 59 | }); 60 | menu->addAction(action_analog); 61 | menu->adjustSize();//不加会到屏幕中间 62 | //menu->exec(mapToGlobal(pos)); 63 | int x1=0, y1=0; 64 | QSettings settings(QApplication::organizationName(), QApplication::applicationName()); 65 | QString position = settings.value("Position", "Bottom").toString(); 66 | if (position == "Top") { 67 | x1 = QPoint(mapToGlobal(QPoint(0,0))).x() + width()/2 - menu->width()/2; 68 | y1 = height(); 69 | } else if (position == "Bottom") { 70 | x1 = QPoint(mapToGlobal(QPoint(0,0))).x() + width()/2 - menu->width()/2; 71 | y1 = QPoint(mapToGlobal(QPoint(0,0))).y() - menu->height(); 72 | } else if (position == "Left") { 73 | x1 = width(); 74 | y1 = QPoint(mapToGlobal(QPoint(0,0))).y() + height()/2 - menu->height()/2; 75 | } else if (position == "Right") { 76 | x1 = QApplication::desktop()->width() - width() - menu->width(); 77 | y1 = QPoint(mapToGlobal(QPoint(0,0))).y() + height()/2 - menu->height()/2; 78 | } 79 | menu->exec(QPoint(x1, y1)); 80 | }); 81 | } 82 | 83 | void DatetimeWidget::enterEvent(QEvent *event) 84 | { 85 | Q_UNUSED(event); 86 | isMouseOn = true; 87 | update(); 88 | } 89 | 90 | void DatetimeWidget::leaveEvent(QEvent *event) 91 | { 92 | Q_UNUSED(event); 93 | isMouseOn = false; 94 | update(); 95 | } 96 | 97 | void DatetimeWidget::paintEvent(QPaintEvent *event) 98 | { 99 | Q_UNUSED(event); 100 | QSettings settings(QCoreApplication::organizationName(), QCoreApplication::applicationName()); 101 | bool b = settings.value("isShowClock", true).toBool(); 102 | if (!b) 103 | return; 104 | QDateTime dateTime = QDateTime::currentDateTime(); 105 | setToolTip(dateTime.toString("yyyy/MM/dd HH:mm:ss ddd")); 106 | QPainter painter(this); 107 | if (isMouseOn) { 108 | painter.setPen(Qt::NoPen); 109 | painter.setBrush(QColor(255,255,255,30)); 110 | painter.drawRoundRect(rect(), 50, 50); 111 | } 112 | painter.setRenderHint(QPainter::Antialiasing, true); 113 | if (clock_type == "TEXT_CLOCK") { 114 | painter.setPen(Qt::white); 115 | QFont font = this->font(); 116 | font.setPointSize(7); 117 | painter.setFont(font); 118 | painter.drawText(rect(), Qt::AlignCenter, dateTime.toString("HH:mm ddd\nyyyy/MM/dd")); 119 | } else if(clock_type == "DIGITAL_CLOCK") { 120 | painter.setPen(Qt::white); 121 | QFont font = this->font(); 122 | font.setPointSize(14); 123 | painter.setFont(font); 124 | painter.drawText(rect(), Qt::AlignCenter, dateTime.toString("HH:mm")); 125 | } else if(clock_type == "ANALOG_CLOCK") { 126 | int w = width() - 6; 127 | int h = height() - 6; 128 | QPixmap pixmap(w, h); 129 | pixmap.fill(Qt::transparent); 130 | QPainter painter1(&pixmap); 131 | painter1.setRenderHint(QPainter::Antialiasing, true); 132 | QTime time = QTime::currentTime(); 133 | int hour = time.hour(); 134 | int m = time.minute(); 135 | int s = time.second(); 136 | // face 137 | painter1.setPen(QPen(Qt::black, 2)); 138 | painter1.setBrush(QBrush(Qt::white)); 139 | painter1.drawEllipse(QPoint(w/2,h/2), (int)(w/2*0.9), (int)(h/2*0.9)); 140 | painter1.setBrush(QBrush(Qt::black)); 141 | painter1.drawEllipse(QPoint(w/2,h/2), (int)(w*0.015), (int)(h*0.015)); 142 | qreal da = 2 * M_PI / 60; 143 | // second hand 144 | int x = w * 0.4 * qCos(M_PI/2 - s * da) + w / 2; 145 | int y = - h * 0.4 * qSin(M_PI/2 - s * da) + h / 2; 146 | painter1.setPen(QPen(Qt::black, 1)); 147 | painter1.drawLine(QPoint(w/2,h/2), QPoint(x,y)); 148 | // minute hand 149 | x = w * 0.35 * qCos(M_PI/2 - m * da - s * da / 60) + w / 2; 150 | y = - h * 0.35 * qSin(M_PI/2 - m * da - s * da / 60) + h / 2; 151 | painter1.setPen(QPen(Qt::black, 2)); 152 | painter1.drawLine(QPoint(w/2,h/2), QPoint(x,y)); 153 | // hour hand 154 | da = 2 * M_PI / 12; 155 | if(hour >= 12) hour -= 12; 156 | x = w*0.25 * qCos(M_PI/2 - hour * da - m * da / 60) + w/2; 157 | y = - h*0.25 * qSin(M_PI/2 - hour * da - m * da / 60) + h/2; 158 | //qDebug() << "x =" << x << ", y =" << y; 159 | painter1.setPen(QPen(Qt::black, 2)); 160 | painter1.drawLine(QPoint(w/2,h/2), QPoint(x,y)); 161 | painter.drawPixmap(rect().center() - pixmap.rect().center(), pixmap); 162 | } 163 | } 164 | 165 | void DatetimeWidget::mousePressEvent(QMouseEvent *event) 166 | { 167 | if(event->button() == Qt::LeftButton){ 168 | QSettings settings(QCoreApplication::organizationName(), QCoreApplication::applicationName()); 169 | QString position = settings.value("Position", "Bottom").toString(); 170 | if (calendar->isHidden()) { 171 | int x1, y1; 172 | if (position == "Bottom") { 173 | x1 = mapToGlobal(QPoint(0,0)).x() + width()/2 - calendar->width()/2; 174 | y1 = mapToGlobal(QPoint(0,0)).y() - calendar->height(); 175 | } else if (position == "Top") { 176 | x1 = mapToGlobal(QPoint(0,0)).x() + width()/2 - calendar->width()/2; 177 | y1 = height(); 178 | } else if (position == "Left") { 179 | x1 = width(); 180 | y1 = mapToGlobal(QPoint(0,0)).y() + height()/2 - calendar->height()/2; 181 | } else if (position == "Right") { 182 | x1 = QApplication::desktop()->width() - width() - calendar->width(); 183 | y1 = mapToGlobal(QPoint(0,0)).y() + height()/2 - calendar->height()/2; 184 | } 185 | qDebug() << "QCalendarWidget" << x1 << y1; 186 | calendar->move(x1, y1); 187 | calendar->setSelectedDate(QDate::currentDate()); 188 | calendar->show(); 189 | } else { 190 | calendar->hide(); 191 | } 192 | } else { 193 | calendar->hide(); 194 | } 195 | } -------------------------------------------------------------------------------- /mainwindow.cpp: -------------------------------------------------------------------------------- 1 | #include "mainwindow.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | MainWindow::MainWindow(QWidget *parent) 19 | : QMainWindow(parent) 20 | ,settings(QApplication::organizationName(), QApplication::applicationName()) 21 | { 22 | setStyleSheet("background-color:white;"); 23 | int w = settings.value("IconSize", 40).toInt(); 24 | mode = settings.value("Mode", "Fashion").toString(); 25 | position = settings.value("Position", "Bottom").toString(); 26 | size.setWidth(w); 27 | size.setHeight(w); 28 | h = w + 20; 29 | qss = ".CurrentButton { background-color: rgba(48,140,198,0.5); border-radius:10px; }" 30 | ".CurrentButton:hover { background-color: rgba(48,140,198,0.5); }" 31 | "QTooltip { color: white; border: 1px solid white; background-color: white; }" 32 | "QPushButton { border: none; }" 33 | "QPushButton:hover { color: rgba(0, 0, 0, 0.1); background-color: rgba(255,255,255,0.1); border-radius:10px; }"; 34 | setStyleSheet(qss); 35 | setWindowFlags(Qt::FramelessWindowHint); 36 | setAttribute(Qt::WA_TranslucentBackground, true); 37 | //setAttribute(Qt::WA_X11NetWmWindowTypeDock, true); 38 | KWindowSystem::setOnDesktop(winId(), NET::OnAllDesktops); 39 | KWindowSystem::setType(winId(), NET::Dock); 40 | setFixedHeight(h); 41 | QWidget *widget = new QWidget; 42 | QBoxLayout::Direction direction = QBoxLayout::LeftToRight; 43 | if (position == "Top" || position == "Bottom") { 44 | direction = QBoxLayout::LeftToRight; 45 | } else if (position == "Left" || position == "Right") { 46 | direction = QBoxLayout::TopToBottom; 47 | } 48 | boxLayout = new QBoxLayout(direction); 49 | boxLayout->setMargin(0); 50 | widget->setLayout(boxLayout); 51 | setCentralWidget(widget); 52 | 53 | pushButton_launcher = new QPushButton(QIcon(":/launcher.png"), nullptr); 54 | pushButton_launcher->setFixedSize(size + QSize(6,6)); 55 | pushButton_launcher->setIconSize(size); 56 | pushButton_launcher->setToolTip("启动器"); 57 | pushButton_launcher->setFocusPolicy(Qt::NoFocus); 58 | connect(pushButton_launcher, &QPushButton::pressed, [](){ 59 | QProcess::startDetached("HTYStartMenu"); 60 | }); 61 | boxLayout->addWidget(pushButton_launcher); 62 | 63 | widget_app = new QWidget; 64 | boxLayout_app = new QBoxLayout(direction); 65 | boxLayout_app->setMargin(0); 66 | widget_app->setLayout(boxLayout_app); 67 | boxLayout->addWidget(widget_app); 68 | 69 | boxLayout->addStretch(); 70 | 71 | trashWidget = new TrashWidget; 72 | trashWidget->setFixedSize(size + QSize(6,6)); 73 | boxLayout->addWidget(trashWidget); 74 | 75 | datetimeWidget = new DatetimeWidget; 76 | datetimeWidget->setFixedSize(size + QSize(6,6)); 77 | boxLayout->addWidget(datetimeWidget); 78 | 79 | netSpeedWidget = new NetSpeedWidget; 80 | netSpeedWidget->setFixedSize(size + QSize(6,6)); 81 | boxLayout->addWidget(netSpeedWidget); 82 | 83 | pushButton_desktop = new QPushButton(QIcon::fromTheme("computer"), nullptr); 84 | pushButton_desktop->setFixedSize(size + QSize(6,6)); 85 | pushButton_desktop->setIconSize(size); 86 | pushButton_desktop->setToolTip("显示桌面"); 87 | pushButton_desktop->setFocusPolicy(Qt::NoFocus); 88 | connect(pushButton_desktop, &QPushButton::pressed, [](){ 89 | KWindowSystem::setShowingDesktop(!KWindowSystem::showingDesktop()); 90 | }); 91 | boxLayout->addWidget(pushButton_desktop); 92 | 93 | connect(KWindowSystem::self(), &KWindowSystem::windowAdded, this, &MainWindow::windowAdded); 94 | connect(KWindowSystem::self(), &KWindowSystem::windowRemoved, this, &MainWindow::windowRemoved); 95 | //这2个差不多 96 | connect(KWindowSystem::self(), static_cast(&KWindowSystem::windowChanged), this, &MainWindow::windowChanged); 97 | connect(KWindowSystem::self(), &KWindowSystem::activeWindowChanged, this, &MainWindow::activeWindowChanged); 98 | 99 | addMenus(); 100 | refit(); 101 | } 102 | 103 | MainWindow::~MainWindow() 104 | { 105 | 106 | } 107 | 108 | void MainWindow::addMenus() 109 | { 110 | //右键菜单 111 | QAction *action = new QAction("模式", this); 112 | QMenu *menu = new QMenu; 113 | QAction *action_mode_fashion = new QAction("时尚", menu); 114 | QAction *action_mode_efficient = new QAction("高效", menu); 115 | action_mode_fashion->setCheckable(true); 116 | action_mode_efficient->setCheckable(true); 117 | if (mode == "Fashion") 118 | action_mode_fashion->setChecked(true); 119 | else if (mode == "Efficient") 120 | action_mode_efficient->setChecked(true); 121 | connect(action_mode_fashion, &QAction::triggered, [=](){ 122 | mode = "Fashion"; 123 | settings.setValue("Mode", mode); 124 | refit(); 125 | }); 126 | connect(action_mode_efficient, &QAction::triggered, [=](){ 127 | mode = "Efficient"; 128 | settings.setValue("Mode", mode); 129 | refit(); 130 | }); 131 | QActionGroup *actionGroup = new QActionGroup(this); 132 | menu->addAction(actionGroup->addAction(action_mode_fashion)); 133 | menu->addAction(actionGroup->addAction(action_mode_efficient)); 134 | action->setMenu(menu); 135 | addAction(action); 136 | 137 | action = new QAction("位置", this); 138 | menu = new QMenu; 139 | QAction *action_position_top = new QAction("上", menu); 140 | QAction *action_position_bottom = new QAction("下", menu); 141 | QAction *action_position_left = new QAction("左", menu); 142 | QAction *action_position_right = new QAction("右", menu); 143 | action_position_top->setCheckable(true); 144 | action_position_bottom->setCheckable(true); 145 | action_position_left->setCheckable(true); 146 | action_position_right->setCheckable(true); 147 | if (position == "Top") 148 | action_position_top->setChecked(true); 149 | else if (position == "Bottom") 150 | action_position_bottom->setChecked(true); 151 | else if (position == "Left") 152 | action_position_left->setChecked(true); 153 | else if (position == "Right") 154 | action_position_right->setChecked(true); 155 | connect(action_position_top, &QAction::triggered, [=](){ 156 | position = "Top"; 157 | settings.setValue("Position", position); 158 | refit(); 159 | }); 160 | connect(action_position_bottom, &QAction::triggered, [=](){ 161 | position = "Bottom"; 162 | settings.setValue("Position", position); 163 | refit(); 164 | }); 165 | connect(action_position_left, &QAction::triggered, [=](){ 166 | position = "Left"; 167 | settings.setValue("Position", position); 168 | refit(); 169 | }); 170 | connect(action_position_right, &QAction::triggered, [=](){ 171 | position = "Right"; 172 | settings.setValue("Position", position); 173 | refit(); 174 | }); 175 | actionGroup = new QActionGroup(this); 176 | menu->addAction(actionGroup->addAction(action_position_top)); 177 | menu->addAction(actionGroup->addAction(action_position_bottom)); 178 | menu->addAction(actionGroup->addAction(action_position_left)); 179 | menu->addAction(actionGroup->addAction(action_position_right)); 180 | action->setMenu(menu); 181 | addAction(action); 182 | 183 | action = new QAction("大小", this); 184 | QAction *action_size_big = new QAction("大", menu); 185 | QAction *action_size_medium = new QAction("中", menu); 186 | QAction *action_size_small = new QAction("小", menu); 187 | action_size_big->setCheckable(true); 188 | action_size_medium->setCheckable(true); 189 | action_size_small->setCheckable(true); 190 | int w = settings.value("IconSize", 40).toInt(); 191 | if (w == 50) { 192 | action_size_big->setChecked(true); 193 | } else if (w == 40) { 194 | action_size_medium->setChecked(true); 195 | } else if (w == 30) { 196 | action_size_small->setChecked(true); 197 | } 198 | connect(action_size_big, &QAction::triggered, [=](){ 199 | resizeIcon(50); 200 | settings.setValue("IconSize", 50); 201 | }); 202 | connect(action_size_medium, &QAction::triggered, [=](){ 203 | resizeIcon(40); 204 | settings.setValue("IconSize", 40); 205 | }); 206 | connect(action_size_small, &QAction::triggered, [=](){ 207 | resizeIcon(30); 208 | settings.setValue("IconSize", 30); 209 | }); 210 | actionGroup = new QActionGroup(this); 211 | menu = new QMenu; 212 | menu->addAction(actionGroup->addAction(action_size_big)); 213 | menu->addAction(actionGroup->addAction(action_size_medium)); 214 | menu->addAction(actionGroup->addAction(action_size_small)); 215 | action->setMenu(menu); 216 | addAction(action); 217 | 218 | action = new QAction("状态", this); 219 | QAction *action_always_show = new QAction("总是显示", menu); 220 | QAction *action_always_hide = new QAction("总是隐藏", menu); 221 | QAction *action_smart_hide = new QAction("智能隐藏", menu); 222 | action_always_show->setCheckable(true); 223 | action_always_hide->setCheckable(true); 224 | action_smart_hide->setCheckable(true); 225 | actionGroup = new QActionGroup(this); 226 | menu = new QMenu; 227 | menu->addAction(actionGroup->addAction(action_always_show)); 228 | menu->addAction(actionGroup->addAction(action_always_hide)); 229 | menu->addAction(actionGroup->addAction(action_smart_hide)); 230 | action->setMenu(menu); 231 | addAction(action); 232 | 233 | action = new QAction("插件", this); 234 | QAction *action_plugin_trash = new QAction("回收站", menu); 235 | QAction *action_plugin_clock = new QAction("时钟", menu); 236 | QAction *action_plugin_netspeed = new QAction("网速", menu); 237 | action_plugin_trash->setCheckable(true); 238 | action_plugin_clock->setCheckable(true); 239 | action_plugin_netspeed->setCheckable(true); 240 | 241 | connect(action_plugin_trash, &QAction::triggered, [=](bool b){ 242 | if (b) { 243 | trashWidget->show(); 244 | settings.setValue("isShowTrash", true); 245 | count_plugin++; 246 | } else { 247 | trashWidget->hide(); 248 | settings.setValue("isShowTrash", false); 249 | count_plugin--; 250 | } 251 | refit(); 252 | }); 253 | 254 | connect(action_plugin_clock, &QAction::triggered, [=](bool b){ 255 | if (b){ 256 | datetimeWidget->show(); 257 | settings.setValue("isShowClock", true); 258 | count_plugin++; 259 | } else { 260 | datetimeWidget->hide(); 261 | settings.setValue("isShowClock", false); 262 | count_plugin--; 263 | } 264 | refit(); 265 | }); 266 | 267 | connect(action_plugin_netspeed, &QAction::triggered, [=](bool b){ 268 | if (b){ 269 | netSpeedWidget->show(); 270 | settings.setValue("isShowNetSpeed", true); 271 | count_plugin++; 272 | } else { 273 | netSpeedWidget->hide(); 274 | settings.setValue("isShowNetSpeed", false); 275 | count_plugin--; 276 | } 277 | refit(); 278 | }); 279 | 280 | bool b = settings.value("isShowTrash", true).toBool(); 281 | if (b) { 282 | action_plugin_trash->setChecked(true); 283 | count_plugin++; 284 | } else { 285 | trashWidget->hide(); 286 | } 287 | 288 | b = settings.value("isShowClock", true).toBool(); 289 | if (b) { 290 | action_plugin_clock->setChecked(true); 291 | count_plugin++; 292 | } else { 293 | datetimeWidget->hide(); 294 | } 295 | 296 | b = settings.value("isShowNetSpeed", true).toBool(); 297 | if (b) { 298 | action_plugin_netspeed->setChecked(true); 299 | count_plugin++; 300 | } else { 301 | netSpeedWidget->hide(); 302 | } 303 | 304 | menu = new QMenu; 305 | menu->addAction(action_plugin_trash); 306 | menu->addAction(action_plugin_clock); 307 | menu->addAction(action_plugin_netspeed); 308 | action->setMenu(menu); 309 | addAction(action); 310 | 311 | action = new QAction("系统监视器", this); 312 | connect(action, &QAction::triggered, []{ 313 | QProcess::startDetached("deepin-system-monitor"); 314 | }); 315 | addAction(action); 316 | 317 | setContextMenuPolicy(Qt::ActionsContextMenu); 318 | } 319 | 320 | void MainWindow::resizeIcon(int w) 321 | { 322 | size.setWidth(w); 323 | size.setHeight(w); 324 | if (w == 50) 325 | h = w + 20; 326 | else if (w == 40) 327 | h = w + 10; 328 | else if (w == 30) 329 | h = w + 6; 330 | for (int i=0; isetFixedSize(size + QSize(w/10,w/10)); 332 | } 333 | pushButton_launcher->setFixedSize(size + QSize(w/10,w/10)); 334 | pushButton_launcher->setIconSize(size); 335 | trashWidget->setFixedSize(size + QSize(w/10,w/10)); 336 | pushButton_desktop->setFixedSize(size+ QSize(w/10,w/10)); 337 | pushButton_desktop->setIconSize(size); 338 | datetimeWidget->setFixedSize(size); 339 | netSpeedWidget->setFixedSize(size); 340 | refit(); 341 | } 342 | 343 | void MainWindow::refit() 344 | { 345 | //qDebug() << count_plugin; 346 | int w=0, x1=0, y1=0; 347 | if (position == "Bottom") { 348 | boxLayout->setDirection(QBoxLayout::LeftToRight); 349 | boxLayout_app->setDirection(QBoxLayout::LeftToRight); 350 | if (mode == "Fashion") 351 | w = (list_appWidget.count() + count_plugin + 3) * size.width(); 352 | else if (mode == "Efficient") 353 | w = QApplication::desktop()->width(); 354 | int sh = size.height(); 355 | if (sh == 50) 356 | h = sh + 20; 357 | else if (sh == 40) 358 | h = sh + 10; 359 | else if (sh == 30) 360 | h = sh + 6; 361 | x1 = QApplication::desktop()->width()/2 - w/2; 362 | y1 = QApplication::desktop()->height() - h; 363 | } else if (position == "Top") { 364 | boxLayout->setDirection(QBoxLayout::LeftToRight); 365 | boxLayout_app->setDirection(QBoxLayout::LeftToRight); 366 | if (mode == "Fashion") 367 | w = (list_appWidget.count() + count_plugin + 3) * size.width(); 368 | else if (mode == "Efficient") 369 | w = QApplication::desktop()->width(); 370 | h = size.height(); 371 | x1 = QApplication::desktop()->width()/2 - w/2; 372 | y1 = 0; 373 | } else if (position == "Left") { 374 | boxLayout->setDirection(QBoxLayout::TopToBottom); 375 | boxLayout_app->setDirection(QBoxLayout::TopToBottom); 376 | w = size.width(); 377 | if (mode == "Fashion") 378 | h = (list_appWidget.count() + count_plugin + 3) * size.height(); 379 | else if (mode == "Efficient") 380 | h = QApplication::desktop()->height(); 381 | x1 = 0; 382 | y1 = QApplication::desktop()->height()/2 - h/2; 383 | } else if (position == "Right") { 384 | boxLayout->setDirection(QBoxLayout::TopToBottom); 385 | boxLayout_app->setDirection(QBoxLayout::TopToBottom); 386 | w = size.width(); 387 | if (mode == "Fashion") 388 | h = (list_appWidget.count() + count_plugin + 3) * size.width(); 389 | else if (mode == "Efficient") 390 | h = QApplication::desktop()->height(); 391 | x1 = QApplication::desktop()->width() - size.width(); 392 | y1 = QApplication::desktop()->height()/2 - h/2; 393 | } 394 | resize(w, h); 395 | setFixedSize(w, h); 396 | move(x1, y1); 397 | //qDebug() << position << x1 << y1 << w << h; 398 | 399 | //区域模糊 400 | //QRegion region(rect()); //矩形 401 | //KWindowEffects::enableBlurBehind(winId(), true, region); 402 | int r = qMin(width(), height()) / 3; 403 | QPainterPath PP; 404 | PP.addRoundedRect(rect(), r, r); //圆角矩形 405 | KWindowEffects::enableBlurBehind(winId(), true, PP.toFillPolygon().toPolygon()); 406 | 407 | //挤开桌面。为什么只需要3个参数?从各边减去width。 408 | NETExtendedStrut strut; 409 | if (position == "Bottom") { 410 | strut.bottom_width = height(); 411 | strut.bottom_start = x(); 412 | strut.bottom_end = x() + width(); 413 | } else if (position == "Top") { 414 | strut.top_width = height(); 415 | strut.top_start = x(); 416 | strut.top_end = x() + width(); 417 | } else if (position == "Left") { 418 | strut.left_width = width(); 419 | strut.left_start = y(); 420 | strut.left_end = y() + height(); 421 | } else if (position == "Right") { 422 | strut.right_width = width(); 423 | strut.right_start = y(); 424 | strut.right_end = y() + height(); 425 | } 426 | KWindowSystem::setExtendedStrut(winId(), 427 | strut.left_width, strut.left_start, strut.left_end, 428 | strut.right_width, strut.right_start, strut.right_end, 429 | strut.top_width, strut.top_start, strut.top_end, 430 | strut.bottom_width, strut.bottom_start, strut.bottom_end); 431 | } 432 | 433 | void MainWindow::windowAdded(WId wid) 434 | { 435 | KWindowInfo winInfo(wid, NET::WMWindowType | NET::WMVisibleName, NET::WM2WindowClass |NET::WM2DesktopFileName); 436 | //DDE 系列的值是 NET::OverrideMask 437 | if (!NET::typeMatchesMask(winInfo.windowType(NET::AllTypesMask), NET::NormalMask | NET::OverrideMask)) { 438 | //QMetaEnum metaEnum = QMetaEnum::fromType(); 439 | //metaEnum.valueToKey(winInfo.windowType(NET::AllTypesMask)); 440 | //qDebug() << winInfo.windowClassClass() << winInfo.windowType(NET::AllTypesMask); 441 | return; 442 | } 443 | qDebug() << winInfo.name() << winInfo.windowClassClass(); 444 | if (winInfo.windowClassClass() == "") 445 | return; 446 | for(int i=0; iclassName == winInfo.windowClassClass()){ 448 | if(!list_appWidget.at(i)->list_wid.contains(wid)){ 449 | list_appWidget.at(i)->list_wid.append(wid); 450 | list_appWidget.at(i)->addPreview(wid); 451 | list_appWidget.at(i)->update(); 452 | } 453 | return; 454 | } 455 | } 456 | 457 | AppWidget *appWidget = new AppWidget; 458 | appWidget->setFixedSize(size); 459 | appWidget->list_wid.append(wid); 460 | appWidget->name = winInfo.name(); 461 | appWidget->className = winInfo.windowClassClass(); 462 | appWidget->icon = KWindowSystem::icon(wid); 463 | appWidget->setToolTip(winInfo.name()); 464 | appWidget->addPreview(wid); 465 | connect(appWidget, &AppWidget::clicked, [=](){ 466 | buttonClicked(appWidget); 467 | }); 468 | appWidget->setContextMenuPolicy(Qt::CustomContextMenu); 469 | connect(appWidget, &AppWidget::customContextMenuRequested, [=](){ 470 | QMenu *menu = new QMenu; 471 | menu->setStyleSheet("QMenu { color:white; background: rgba(0,0,0,100);}" 472 | "QMenu::item:selected { background: rgba(48,140,198,255);}"); 473 | menu->setAttribute(Qt::WA_TranslucentBackground, true); 474 | menu->setAutoFillBackground(true); 475 | QAction *action_close = new QAction("关闭", this); 476 | connect(action_close, &QAction::triggered, [=](){ 477 | NETRootInfo(QX11Info::connection(), NET::CloseWindow).closeWindowRequest(static_cast(wid)); 478 | }); 479 | menu->addAction(action_close); 480 | menu->adjustSize();//不加会到屏幕中间 481 | int x1=0, y1=0; 482 | if (position == "Top") { 483 | x1 = QPoint(appWidget->mapToGlobal(QPoint(0,0))).x() + appWidget->width()/2 - menu->width()/2; 484 | y1 = height(); 485 | } else if (position == "Bottom") { 486 | x1 = QPoint(appWidget->mapToGlobal(QPoint(0,0))).x() + appWidget->width()/2 - menu->width()/2; 487 | y1 = y() - menu->height(); 488 | } else if (position == "Left") { 489 | x1 = width(); 490 | y1 = QPoint(appWidget->mapToGlobal(QPoint(0,0))).y() + appWidget->height()/2 - menu->height()/2; 491 | } else if (position == "Right") { 492 | x1 = QApplication::desktop()->width() - width() - menu->width(); 493 | y1 = QPoint(appWidget->mapToGlobal(QPoint(0,0))).y() + appWidget->height()/2 - menu->height()/2; 494 | } 495 | menu->exec(QPoint(x1, y1)); 496 | }); 497 | boxLayout_app->addWidget(appWidget); 498 | list_appWidget.append(appWidget); 499 | refit(); 500 | } 501 | 502 | void MainWindow::windowRemoved(WId wid) 503 | { 504 | for (int i=0; ilist_wid.contains(wid)) { 507 | //qDebug() << dock->wid; 508 | if (appWidget->list_wid.count() > 1) { 509 | appWidget->list_wid.removeOne(wid); 510 | if(appWidget->index > 0) 511 | appWidget->index--; 512 | appWidget->removePreview(wid); 513 | } else { 514 | boxLayout_app->removeWidget(appWidget); 515 | list_appWidget.removeAt(i); 516 | //connect(appWidget, &AppWidget::destroyed, [=](){ 517 | // refit(); 518 | //}); 519 | appWidget->deleteLater(); 520 | refit(); 521 | } 522 | } 523 | } 524 | } 525 | 526 | void MainWindow::windowChanged(WId wid, NET::Properties properties, NET::Properties2 properties2) 527 | { 528 | KWindowInfo winInfo(wid, properties, properties2); 529 | //qDebug() << wid << winInfo.name() << winInfo.windowClassClass();// wid,空值,空值 530 | } 531 | 532 | void MainWindow::activeWindowChanged(WId wid) 533 | { 534 | for (int i=0; ilist_wid.contains(wid)) { 537 | appWidget->isActive = true; 538 | } else { 539 | appWidget->isActive = false; 540 | } 541 | appWidget->update(); 542 | } 543 | } 544 | 545 | void MainWindow::buttonClicked(AppWidget *appWidget) 546 | { 547 | for (int i=0; iisActive = false; 549 | list_appWidget.at(i)->update(); 550 | } 551 | appWidget->isActive = true; 552 | appWidget->update(); 553 | KWindowInfo winInfo(appWidget->list_wid.at(appWidget->index), NET::WMState | NET::XAWMState | NET::WMDesktop | NET::WMVisibleName); 554 | appWidget->setToolTip(winInfo.name()); 555 | if (winInfo.isMinimized()) { 556 | KWindowSystem::unminimizeWindow(appWidget->list_wid.at(appWidget->index)); 557 | KWindowSystem::activateWindow(appWidget->list_wid.at(appWidget->index)); 558 | } else { 559 | if (KWindowSystem::activeWindow() == appWidget->list_wid.at(appWidget->index)) { 560 | if (appWidget->index < appWidget->list_wid.count() -1) { 561 | appWidget->index++; 562 | KWindowSystem::activateWindow(appWidget->list_wid.at(appWidget->index)); 563 | } else { 564 | for(int i=0; ilist_wid.count(); i++){ 565 | KWindowSystem::minimizeWindow(appWidget->list_wid.at(i)); 566 | } 567 | appWidget->index = 0; 568 | } 569 | } else { 570 | KWindowSystem::activateWindow(appWidget->list_wid.at(appWidget->index)); 571 | } 572 | } 573 | } 574 | 575 | void MainWindow::paintEvent(QPaintEvent *event) 576 | { 577 | Q_UNUSED(event); 578 | QPainter painter(this); 579 | painter.setRenderHint(QPainter::Antialiasing); 580 | painter.setPen(Qt::NoPen); 581 | painter.setBrush(QColor(0,0,0,50)); 582 | int r = qMin(width(), height()) / 3; 583 | painter.drawRoundedRect(rect(), r, r); 584 | } --------------------------------------------------------------------------------