1 /***********************************************************************************
2 * System Monitor: Plasmoid and data engines to monitor CPU/Memory/Swap Usage.
3 * Copyright (C) 2008 Matthew Dawson
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version 2
8 * of the License, or (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 ***********************************************************************************/
21 #include "system_status.h"
23 #include <Plasma/ToolTipManager>
24 #include <Plasma/ToolTipContent>
26 #include <KConfigDialog>
32 SystemStatus::SystemStatus(QObject
*parent
, const QVariantList
&args
)
33 : Plasma::Applet(parent
, args
),
45 setHasConfigurationInterface(true);
49 SystemStatus::~SystemStatus()
52 if (hasFailedToLaunch()) {
60 void SystemStatus::init()
65 sys_mon
= dataEngine("systemmonitor");
66 connect(sys_mon
, SIGNAL(sourceAdded(const QString
&)), this, SLOT(sourcesAdded(const QString
&)));
69 Plasma::ToolTipManager::self()->registerWidget(this);
73 void SystemStatus::reconnectSources()
76 reconnectCPUSources();
78 sys_mon
->connectSource("mem/physical/used", this, 500);
79 sys_mon
->connectSource("mem/physical/free", this, 500);
80 sys_mon
->connectSource("mem/physical/buf", this, 500);
81 sys_mon
->connectSource("mem/physical/cached", this, 500);
83 sys_mon
->connectSource("mem/swap/used", this, 500);
84 sys_mon
->connectSource("mem/swap/free", this, 500);
88 void SystemStatus::reconnectCPUSources()
91 if (!m_showMultiCPU
) {
93 sys_mon
->connectSource("cpu/system/user", this, 500);
94 sys_mon
->connectSource("cpu/system/sys", this, 500);
95 sys_mon
->connectSource("cpu/system/nice", this, 500);
96 sys_mon
->connectSource("cpu/system/wait", this, 500);
97 sys_mon
->connectSource("cpu/system/idle", this, 500);
101 sys_mon
->connectSource("system/cores", this, 500);
103 m_numCPUs
= sys_mon
->query("system/cores")["value"].toUInt();
104 if (m_numCPUs
== 0) {
105 //If we have zero, either the sources doesn't exist or theres a problem.
109 m_cpuInfo
.resize(m_numCPUs
);
111 for (uint i
= 0; i
< m_numCPUs
; ++i
) {
113 sys_mon
->connectSource(QString("cpu/cpu%1/user").arg(i
), this, 500);
114 sys_mon
->connectSource(QString("cpu/cpu%1/sys").arg(i
), this, 500);
115 sys_mon
->connectSource(QString("cpu/cpu%1/nice").arg(i
), this, 500);
116 sys_mon
->connectSource(QString("cpu/cpu%1/wait").arg(i
), this, 500);
117 sys_mon
->connectSource(QString("cpu/cpu%1/idle").arg(i
), this, 500);
125 void SystemStatus::disconnectSources()
128 disconnectCPUSources();
130 sys_mon
->disconnectSource("mem/physical/used", this);
131 sys_mon
->disconnectSource("mem/physical/free", this);
132 sys_mon
->disconnectSource("mem/physical/buf", this);
133 sys_mon
->disconnectSource("mem/physical/cached", this);
135 sys_mon
->disconnectSource("mem/swap/used", this);
136 sys_mon
->disconnectSource("mem/swap/free", this);
140 void SystemStatus::disconnectCPUSources()
143 if (!m_showMultiCPU
) {
145 sys_mon
->disconnectSource("cpu/system/user", this);
146 sys_mon
->disconnectSource("cpu/system/sys", this);
147 sys_mon
->disconnectSource("cpu/system/nice", this);
148 sys_mon
->disconnectSource("cpu/system/wait", this);
149 sys_mon
->disconnectSource("cpu/system/idle", this);
153 for (uint i
= 0; i
< m_numCPUs
; ++i
) {
155 sys_mon
->disconnectSource(QString("cpu/cpu%1/user").arg(i
), this);
156 sys_mon
->disconnectSource(QString("cpu/cpu%1/sys").arg(i
), this);
157 sys_mon
->disconnectSource(QString("cpu/cpu%1/nice").arg(i
), this);
158 sys_mon
->disconnectSource(QString("cpu/cpu%1/wait").arg(i
), this);
159 sys_mon
->disconnectSource(QString("cpu/cpu%1/idle").arg(i
), this);
167 void SystemStatus::sourcesAdded(const QString
&source
)
170 if (source
== "system/cores") {
172 reconnectCPUSources();
174 } else if (source
.startsWith("cpu/system/") && !m_showMultiCPU
) {
176 if (source
.endsWith("/user") || source
.endsWith("/sys") || source
.endsWith("/nice") || source
.endsWith("/wait") || source
.endsWith("/idle")) {
178 sys_mon
->connectSource(source
, this, 500);
182 } else if (source
.startsWith("cpu/cpu") && m_showMultiCPU
) {
184 if (source
.endsWith("/user") || source
.endsWith("/sys") || source
.endsWith("/nice") || source
.endsWith("/wait") || source
.endsWith("/idle")) {
186 sys_mon
->connectSource(source
, this, 500);
190 } else if (source
.startsWith("mem/swap")) {
192 sys_mon
->connectSource(source
, this, 500);
194 } else if (source
.startsWith("mem/physical/")) {
196 if (!source
.endsWith("application")) {
198 sys_mon
->connectSource(source
, this, 500);
206 void SystemStatus::constraintsEvent(Plasma::Constraints constraints
)
209 if (constraints
.testFlag(Plasma::FormFactorConstraint
)) {
211 if (formFactor() == Plasma::Planar
|| formFactor() == Plasma::MediaCenter
) {
212 setAspectRatioMode(Plasma::IgnoreAspectRatio
);
214 setAspectRatioMode(Plasma::ConstrainedSquare
);
217 //If only StandardBackground is set, it should be completely transparent. (it gets
218 //set in Plasma::Applet on certain conditions.
219 if (backgroundHints() == StandardBackground
) {
220 setBackgroundHints(NoBackground
);
227 void SystemStatus::createConfigurationInterface(KConfigDialog
*parent
)
230 QWidget
*widGeneral
= new QWidget();
231 uiGeneral
.setupUi(widGeneral
);
233 uiGeneral
.chkIsVertical
->setChecked(m_isVertical
);
234 uiGeneral
.chkUseOxygen
->setChecked(m_useOxygen
);
235 uiGeneral
.kcmbBackground
->setItemData(0, DefaultBackground
);
236 uiGeneral
.kcmbBackground
->setItemData(1, TranslucentBackground
);
237 uiGeneral
.kcmbBackground
->setItemData(2, NoBackground
);
239 switch ((int)backgroundHints()) {
241 case(int)DefaultBackground
:
242 uiGeneral
.kcmbBackground
->setCurrentIndex(0);
244 //StandardBackground may get set. Doesn't effect drawing, so this just makes sure we catch it.
245 case(int)TranslucentBackground
:
246 case(int)TranslucentBackground
| StandardBackground
:
247 uiGeneral
.kcmbBackground
->setCurrentIndex(1);
249 case(int)NoBackground
:
250 uiGeneral
.kcmbBackground
->setCurrentIndex(2);
253 Q_ASSERT("Unknown background hints!");
258 QWidget
*widColours
= new QWidget();
259 uiColours
.setupUi(widColours
);
261 uiColours
.kcbCpuUser
->setColor(this->m_cpuUserColour
);
262 uiColours
.kcbCpuNice
->setColor(this->m_cpuNiceColour
);
263 uiColours
.kcbCpuDisk
->setColor(this->m_cpuDiskColour
);
264 uiColours
.kcbCpuSystem
->setColor(this->m_cpuSysColour
);
265 uiColours
.kcbRamBuffers
->setColor(this->m_ramBuffersColour
);
266 uiColours
.kcbRamCached
->setColor(this->m_ramCachedColour
);
267 uiColours
.kcbRamUser
->setColor(this->m_ramUsedColour
);
268 uiColours
.kcbSwap
->setColor(this->m_swapUsedColour
);
270 parent
->setButtons(KDialog::Ok
| KDialog::Cancel
| KDialog::Apply
);
271 connect(parent
, SIGNAL(applyClicked()), this, SLOT(configUpdated()));
272 connect(parent
, SIGNAL(okClicked()), this, SLOT(configUpdated()));
274 parent
->addPage(widGeneral
, "General", icon(), QString(), false);
275 parent
->addPage(widColours
, "Colours", icon(), QString(), false);
277 parent
->setFaceType(KConfigDialog::Tabbed
);
281 void SystemStatus::configUpdated()
284 KConfigGroup cg
= config();
286 if (uiGeneral
.kcmbBackground
->itemData(uiGeneral
.kcmbBackground
->currentIndex()).toInt() != (int)this->backgroundHints()) {
287 this->setBackgroundHints(QFlag(uiGeneral
.kcmbBackground
->itemData(uiGeneral
.kcmbBackground
->currentIndex()).toInt()));
288 cg
.writeEntry("background", (int)this->backgroundHints());
291 if (uiGeneral
.chkIsVertical
->isChecked() != this->m_isVertical
) {
292 this->m_isVertical
= uiGeneral
.chkIsVertical
->isChecked();
293 cg
.writeEntry("vertical", this->m_isVertical
);
295 if (uiGeneral
.chkUseOxygen
->isChecked() != this->m_useOxygen
) {
296 this->m_useOxygen
= uiGeneral
.chkUseOxygen
->isChecked();
297 cg
.writeEntry("use_oxygen", this->m_useOxygen
);
299 if (uiColours
.kcbCpuUser
->color() != this->m_cpuUserColour
) {
300 this->m_cpuUserColour
= uiColours
.kcbCpuUser
->color();
301 cg
.writeEntry("colour_cpu_user", this->m_cpuUserColour
.name());
303 if (uiColours
.kcbCpuNice
->color() != this->m_cpuNiceColour
) {
304 this->m_cpuNiceColour
= uiColours
.kcbCpuNice
->color();
305 cg
.writeEntry("colour_cpu_nice", this->m_cpuNiceColour
.name());
307 if (uiColours
.kcbCpuDisk
->color() != this->m_cpuDiskColour
) {
308 this->m_cpuDiskColour
= uiColours
.kcbCpuDisk
->color();
309 cg
.writeEntry("colour_cpu_disk", this->m_cpuDiskColour
.name());
311 if (uiColours
.kcbCpuSystem
->color() != this->m_cpuSysColour
) {
312 this->m_cpuSysColour
= uiColours
.kcbCpuSystem
->color();
313 cg
.writeEntry("colour_cpu_sys", this->m_cpuSysColour
.name());
315 if (uiColours
.kcbRamCached
->color() != this->m_ramCachedColour
) {
316 this->m_ramCachedColour
= uiColours
.kcbRamCached
->color();
317 cg
.writeEntry("colour_ram_cached", this->m_ramCachedColour
.name());
319 if (uiColours
.kcbRamBuffers
->color() != this->m_ramBuffersColour
) {
320 this->m_ramBuffersColour
= uiColours
.kcbRamBuffers
->color();
321 cg
.writeEntry("colour_ram_buffers", this->m_ramBuffersColour
.name());
323 if (uiColours
.kcbRamUser
->color() != this->m_ramUsedColour
) {
324 this->m_ramUsedColour
= uiColours
.kcbRamUser
->color();
325 cg
.writeEntry("colour_ram_used", this->m_ramUsedColour
.name());
327 if (uiColours
.kcbSwap
->color() != this->m_swapUsedColour
) {
328 this->m_swapUsedColour
= uiColours
.kcbSwap
->color();
329 cg
.writeEntry("colour_swap_used", this->m_swapUsedColour
.name());
332 emit
configNeedsSaving();
337 void SystemStatus::dataUpdated(const QString
& source
, const Plasma::DataEngine::Data
&data
)
340 if (source
== "system/cores" && m_showMultiCPU
) {
342 if (data
["value"].toUInt() != m_numCPUs
) {
343 reconnectCPUSources();
346 } else if (source
.startsWith("cpu/system/") && !m_showMultiCPU
) {
348 if (source
.endsWith("/user")) {
350 m_cpuInfo
[0].user
= (data
["value"].toString().toDouble()) / 100;
352 } else if (source
.endsWith("/sys")) {
354 m_cpuInfo
[0].sys
= (data
["value"].toString().toDouble()) / 100;
356 } else if (source
.endsWith("/nice")) {
358 m_cpuInfo
[0].nice
= (data
["value"].toString().toDouble()) / 100;
360 } else if (source
.endsWith("/wait")) {
362 m_cpuInfo
[0].disk
= (data
["value"].toString().toDouble()) / 100;
364 } else if (source
.endsWith("/idle")) {
366 m_cpuInfo
[0].idle
= (data
["value"].toString().toDouble()) / 100;
370 } else if (source
.startsWith("cpu/") && m_showMultiCPU
) {
372 int cpu
= source
.split('/')[1].mid(3).toInt();
374 if (cpu
>= m_cpuInfo
.size()) {
375 Q_ASSERT("CPU is not supposed to exist!");
379 if (source
.endsWith("/user")) {
381 m_cpuInfo
[cpu
].user
= (data
["value"].toString().toDouble()) / 100;
383 } else if (source
.endsWith("/sys")) {
385 m_cpuInfo
[cpu
].sys
= (data
["value"].toString().toDouble()) / 100;
387 } else if (source
.endsWith("/nice")) {
389 m_cpuInfo
[cpu
].nice
= (data
["value"].toString().toDouble()) / 100;
391 } else if (source
.endsWith("/wait")) {
393 m_cpuInfo
[cpu
].disk
= (data
["value"].toString().toDouble()) / 100;
395 } else if (source
.endsWith("/idle")) {
397 m_cpuInfo
[cpu
].idle
= (data
["value"].toString().toDouble()) / 100;
401 } else if (source
.startsWith("mem/swap")) {
403 if (source
.endsWith("/used")) {
405 m_swapused
= data
["value"].toDouble() / 100;
407 } else if (source
.endsWith("/free")) {
409 m_swapfree
= data
["value"].toDouble() / 100;
413 m_swaptotal
= m_swapfree
+ m_swapused
;
415 if (m_swaptotal
== 0) {
423 } else if (source
.startsWith("mem/physical/")) {
425 if (source
.endsWith("/used")) {
427 m_ramused
= data
["value"].toDouble();
429 } else if (source
.endsWith("/cached")) {
431 m_ramcached
= data
["value"].toDouble();
433 } else if (source
.endsWith("/buf")) {
435 m_rambuffers
= data
["value"].toDouble();
437 } else if (source
.endsWith("/free")) {
439 m_ramfree
= data
["value"].toDouble();
443 m_ramtotal
= m_ramused
+ m_ramcached
+ m_rambuffers
+ m_ramfree
;
445 if (m_ramtotal
== 0) {
455 void SystemStatus::paintCPUUsage(QPainter
*p
, const QStyleOptionGraphicsItem
*option
, const QRect
& contentsRect
, const cpuInfo
&cpu
)
462 p
->translate(0, contentsRect
.height() * cpu
.idle
);
465 p
->setBrush(this->m_cpuUserColour
);
466 p
->setPen(this->m_cpuUserColour
);
468 p
->drawRect(QRectF(contentsRect
.left(), contentsRect
.top(), contentsRect
.width(), contentsRect
.height() * cpu
.user
));
469 p
->translate(0, contentsRect
.height() * cpu
.user
);
472 p
->setBrush(this->m_cpuNiceColour
);
473 p
->setPen(this->m_cpuNiceColour
);
475 p
->drawRect(QRectF(contentsRect
.left(), contentsRect
.top(), contentsRect
.width(), contentsRect
.height() * cpu
.nice
));
476 p
->translate(0, contentsRect
.height() * cpu
.nice
);
479 p
->setBrush(this->m_cpuDiskColour
);
480 p
->setPen(this->m_cpuDiskColour
);
482 p
->drawRect(QRectF(contentsRect
.left(), contentsRect
.top(), contentsRect
.width(), contentsRect
.height() * cpu
.disk
));
483 p
->translate(0, contentsRect
.height() * cpu
.disk
);
486 p
->setBrush(this->m_cpuSysColour
);
487 p
->setPen(this->m_cpuSysColour
);
489 p
->drawRect(QRectF(contentsRect
.left(), contentsRect
.top(), contentsRect
.width(), contentsRect
.height() * cpu
.sys
));
495 void SystemStatus::paintSwapUsage(QPainter
*p
, const QStyleOptionGraphicsItem
*option
, const QRect
& contentsRect
)
502 p
->translate(0, contentsRect
.height() * m_swapfree
/ m_swaptotal
);
505 p
->setBrush(this->m_swapUsedColour
);
506 p
->setPen(this->m_swapUsedColour
);
508 p
->drawRect(QRectF(contentsRect
.left(), contentsRect
.top(), contentsRect
.width(), contentsRect
.height() * m_swapused
/ m_swaptotal
));
514 void SystemStatus::paintRAMUsage(QPainter
*p
, const QStyleOptionGraphicsItem
*option
, const QRect
& contentsRect
)
521 p
->translate(0, contentsRect
.height() * m_ramfree
/ m_ramtotal
);
524 p
->setBrush(this->m_ramCachedColour
);
525 p
->setPen(this->m_ramCachedColour
);
527 p
->drawRect(QRectF(contentsRect
.left(), contentsRect
.top(), contentsRect
.width(), contentsRect
.height() * m_ramcached
/ m_ramtotal
));
528 p
->translate(0, contentsRect
.height() * m_ramcached
/ m_ramtotal
);
531 p
->setBrush(this->m_ramBuffersColour
);
532 p
->setPen(this->m_ramBuffersColour
);
534 p
->drawRect(QRectF(contentsRect
.left(), contentsRect
.top(), contentsRect
.width(), contentsRect
.height() * m_rambuffers
/ m_ramtotal
));
535 p
->translate(0, contentsRect
.height() * m_rambuffers
/ m_ramtotal
);
538 p
->setBrush(this->m_ramUsedColour
);
539 p
->setPen(this->m_ramUsedColour
);
541 p
->drawRect(QRectF(contentsRect
.left(), contentsRect
.top(), contentsRect
.width(), contentsRect
.height() * m_ramused
/ m_ramtotal
));
547 void SystemStatus::paintFrontGlass(QPainter
* p
, const QStyleOptionGraphicsItem
*option
, const QRect
& contentsRect
)
552 QLinearGradient
grad(0, contentsRect
.top(), 0, contentsRect
.bottom());
553 grad
.setColorAt(0, QColor(255, 255, 255, 30));
554 grad
.setColorAt(1, QColor(0, 0, 0, 150));
556 p
->setPen(QColor(0, 0, 0, 100));
557 p
->drawRect(contentsRect
);
561 void SystemStatus::paintInterface(QPainter
*p
, const QStyleOptionGraphicsItem
*option
, const QRect
& contentsRect
)
564 p
->setRenderHint(QPainter::SmoothPixmapTransform
);
565 p
->setRenderHint(QPainter::Antialiasing
);
567 QRect
rotatedContentsRect(contentsRect
);
570 if (!this->m_isVertical
&& (this->formFactor() == Plasma::Horizontal
|| this->formFactor() == Plasma::Vertical
)) {
571 p
->setWorldTransform(QTransform().rotate(90).translate(0, -(contentsRect
.width() + contentsRect
.x() * 2)));
572 rotatedContentsRect
.setWidth(contentsRect
.height());
573 rotatedContentsRect
.setHeight(contentsRect
.width());
576 int origWidth
= rotatedContentsRect
.width();
579 if (m_showMultiCPU
) {
581 widthDivisor
= 1.0 / (double)(m_numCPUs
+ 2);
590 rotatedContentsRect
.setWidth(rotatedContentsRect
.width() * (widthDivisor
- 0.005));
591 rotatedContentsRect
.moveLeft(rotatedContentsRect
.left() + origWidth
* 0.009);
593 rotatedContentsRect
.setWidth(rotatedContentsRect
.width() * widthDivisor
);
596 if (!m_showMultiCPU
) {
597 paintCPUUsage(p
, option
, rotatedContentsRect
, m_cpuInfo
[0]);
599 paintFrontGlass(p
, option
, rotatedContentsRect
);
601 rotatedContentsRect
.moveLeft(rotatedContentsRect
.left() + widthDivisor
*origWidth
);
604 for (uint i
= 0; i
< m_numCPUs
;++i
) {
606 paintCPUUsage(p
, option
, rotatedContentsRect
, m_cpuInfo
[i
]);
608 paintFrontGlass(p
, option
, rotatedContentsRect
);
610 rotatedContentsRect
.moveLeft(rotatedContentsRect
.left() + widthDivisor
*origWidth
);
617 paintRAMUsage(p
, option
, rotatedContentsRect
);
619 paintFrontGlass(p
, option
, rotatedContentsRect
);
621 rotatedContentsRect
.moveLeft(rotatedContentsRect
.left() + widthDivisor
*origWidth
);
623 paintSwapUsage(p
, option
, rotatedContentsRect
);
625 paintFrontGlass(p
, option
, rotatedContentsRect
);
631 void SystemStatus::readConfig()
634 KConfigGroup cg
= config();
636 this->m_isVertical
= cg
.readEntry("vertical", true);
637 this->m_useOxygen
= cg
.readEntry("use_oxygen", false);
638 this->m_showMultiCPU
= cg
.readEntry("show_multiple_cpus", false);
640 this->m_cpuUserColour
= QColor(cg
.readEntry("colour_cpu_user", QString("#0000FF")));
641 this->m_cpuNiceColour
= QColor(cg
.readEntry("colour_cpu_nice", QString("#FFFF00")));
642 this->m_cpuDiskColour
= QColor(cg
.readEntry("colour_cpu_disk", QString("#006400")));
643 this->m_cpuSysColour
= QColor(cg
.readEntry("colour_cpu_sys", QString("#FF0000")));
644 this->m_ramCachedColour
= QColor(cg
.readEntry("colour_ram_cached", QString("#007800")));
645 this->m_ramBuffersColour
= QColor(cg
.readEntry("colour_ram_buffers", QString("#FFFF00")));
646 this->m_ramUsedColour
= QColor(cg
.readEntry("colour_ram_used", QString("#0000B1")));
647 this->m_swapUsedColour
= QColor(cg
.readEntry("colour_swap_used", QString("#00CDCD")));
649 this->setBackgroundHints(QFlag(cg
.readEntry("background", (int)(TranslucentBackground
))));
653 QList
<QAction
*> SystemStatus::contextualActions()
656 QAction
*swapMultiCPUShow
= new QAction("Show multiple CPUs Status", this);
658 swapMultiCPUShow
->setCheckable(true);
659 swapMultiCPUShow
->setChecked(m_showMultiCPU
);
661 connect(swapMultiCPUShow
, SIGNAL(toggled(bool)), this, SLOT(swapShowingMultiCPU()));
663 return QList
<QAction
*>() << swapMultiCPUShow
;
667 void SystemStatus::swapShowingMultiCPU()
670 disconnectCPUSources();
672 m_showMultiCPU
= !m_showMultiCPU
;
673 config().writeEntry("show_multiple_cpus", m_showMultiCPU
);
675 reconnectCPUSources();
679 void SystemStatus::toolTipAboutToShow()
682 Plasma::ToolTipManager::self()->setContent(this, Plasma::ToolTipContent("System Status:", QString("CPU usage: %1%<br>Ram Usage: %2%<br>Swap Usage: %3%").arg(round((1 - m_cpuInfo
[0].idle
) * 100)).arg(round((1 - m_ramfree
/ m_ramtotal
) * 100)).arg(round((1 - m_swapfree
/ m_swaptotal
) * 100))));
686 #include "system_status.moc"