Renaming fiels/classes to fit the System Status name.
[system_status.git] / applet / system_status.cpp
blob45caf4872a502ba6108307dcde800269df97a5ab
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>
28 #include <QPainter>
30 #include <cmath>
32 SystemStatus::SystemStatus(QObject *parent, const QVariantList &args)
33 : Plasma::Applet(parent, args),
34 m_ramfree(0),
35 m_ramused(0),
36 m_rambuffers(0),
37 m_ramcached(0),
38 m_ramtotal(1),
39 m_swapfree(0),
40 m_swapused(0),
41 m_swaptotal(1)
44 m_cpuInfo.resize(1);
45 setHasConfigurationInterface(true);
46 resize(100, 100);
49 SystemStatus::~SystemStatus()
52 if (hasFailedToLaunch()) {
54 } else {
60 void SystemStatus::init()
63 readConfig();
65 sys_mon = dataEngine("systemmonitor");
66 connect(sys_mon, SIGNAL(sourceAdded(const QString &)), this, SLOT(sourcesAdded(const QString &)));
67 reconnectSources();
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);
99 } else {
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.
106 return ;
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);
151 } else {
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);
213 } else {
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);
243 break;
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);
248 break;
249 case(int)NoBackground:
250 uiGeneral.kcmbBackground->setCurrentIndex(2);
251 break;
252 default:
253 Q_ASSERT("Unknown background hints!");
254 break;
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();
333 update();
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!");
376 return ;
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) {
417 m_swaptotal = 1;
421 update();
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) {
447 m_ramtotal = 1;
455 void SystemStatus::paintCPUUsage(QPainter *p, const QStyleOptionGraphicsItem *option, const QRect& contentsRect, const cpuInfo &cpu)
458 Q_UNUSED(option)
460 p->save();
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));
491 p->restore();
495 void SystemStatus::paintSwapUsage(QPainter *p, const QStyleOptionGraphicsItem *option, const QRect& contentsRect)
498 Q_UNUSED(option)
500 p->save();
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));
510 p->restore();
514 void SystemStatus::paintRAMUsage(QPainter *p, const QStyleOptionGraphicsItem *option, const QRect& contentsRect)
517 Q_UNUSED(option)
519 p->save();
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));
543 p->restore();
547 void SystemStatus::paintFrontGlass(QPainter* p, const QStyleOptionGraphicsItem *option, const QRect& contentsRect)
550 Q_UNUSED(option);
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));
555 p->setBrush(grad);
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();
578 double widthDivisor;
579 if (m_showMultiCPU) {
581 widthDivisor = 1.0 / (double)(m_numCPUs + 2);
583 } else {
585 widthDivisor = 0.33;
589 if (m_useOxygen) {
590 rotatedContentsRect.setWidth(rotatedContentsRect.width() * (widthDivisor - 0.005));
591 rotatedContentsRect.moveLeft(rotatedContentsRect.left() + origWidth * 0.009);
592 } else {
593 rotatedContentsRect.setWidth(rotatedContentsRect.width() * widthDivisor);
596 if (!m_showMultiCPU) {
597 paintCPUUsage(p, option, rotatedContentsRect, m_cpuInfo[0]);
598 if (m_useOxygen) {
599 paintFrontGlass(p, option, rotatedContentsRect);
601 rotatedContentsRect.moveLeft(rotatedContentsRect.left() + widthDivisor*origWidth);
602 } else {
604 for (uint i = 0; i < m_numCPUs;++i) {
606 paintCPUUsage(p, option, rotatedContentsRect, m_cpuInfo[i]);
607 if (m_useOxygen) {
608 paintFrontGlass(p, option, rotatedContentsRect);
610 rotatedContentsRect.moveLeft(rotatedContentsRect.left() + widthDivisor*origWidth);
617 paintRAMUsage(p, option, rotatedContentsRect);
618 if (m_useOxygen) {
619 paintFrontGlass(p, option, rotatedContentsRect);
621 rotatedContentsRect.moveLeft(rotatedContentsRect.left() + widthDivisor*origWidth);
623 paintSwapUsage(p, option, rotatedContentsRect);
624 if (m_useOxygen) {
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"