File indexing completed on 2024-04-28 05:31:43

0001 /*
0002     KSysGuard, the KDE System Guard
0003 
0004     SPDX-FileCopyrightText: 1999 Chris Schlaeger <cs@kde.org>
0005     SPDX-FileCopyrightText: 2007 John Tapsell <tapsell@kde.org>
0006 
0007     SPDX-License-Identifier: LGPL-2.0-or-later
0008 
0009 
0010 */
0011 #include "ReniceDlg.h"
0012 
0013 #include <klocalizedstring.h>
0014 
0015 #include "processcore/process.h"
0016 #include "ui_ReniceDlgUi.h"
0017 #include <QButtonGroup>
0018 #include <QDialogButtonBox>
0019 #include <QListWidget>
0020 #include <QPushButton>
0021 #include <QVBoxLayout>
0022 
0023 ReniceDlg::ReniceDlg(QWidget *parent, const QStringList &processes, int currentCpuPrio, int currentCpuSched, int currentIoPrio, int currentIoSched)
0024     : QDialog(parent)
0025 {
0026     setObjectName(QStringLiteral("Renice Dialog"));
0027     setModal(true);
0028     setWindowTitle(i18n("Set Priority"));
0029     QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this);
0030     previous_cpuscheduler = 0;
0031 
0032     if (currentIoSched == KSysGuard::Process::None) {
0033         // CurrentIoSched == 0 means that the priority is set automatically.
0034         // Using the formula given by the linux kernel Documentation/block/ioprio
0035         currentIoPrio = (currentCpuPrio + 20) / 5;
0036     }
0037     if (currentIoSched == (int)KSysGuard::Process::BestEffort && currentIoPrio == (currentCpuPrio + 20) / 5) {
0038         // Unfortunately, in linux you can't ever set a process back to being None.  So we fake it :)
0039         currentIoSched = KSysGuard::Process::None;
0040     }
0041     ioniceSupported = (currentIoPrio != -2);
0042 
0043     QVBoxLayout *mainLayout = new QVBoxLayout(this);
0044 
0045     QPushButton *okButton = buttonBox->button(QDialogButtonBox::Ok);
0046     okButton->setDefault(true);
0047     okButton->setShortcut(Qt::CTRL | Qt::Key_Return);
0048     connect(buttonBox, &QDialogButtonBox::accepted, this, &ReniceDlg::slotOk);
0049     connect(buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject);
0050 
0051     QWidget *widget = new QWidget(this);
0052     mainLayout->addWidget(widget);
0053     ui = new Ui_ReniceDlgUi();
0054     ui->setupUi(widget);
0055     ui->listWidget->insertItems(0, processes);
0056 
0057     cpuScheduler = new QButtonGroup(this);
0058     cpuScheduler->addButton(ui->radioNormal, (int)KSysGuard::Process::Other);
0059 #ifndef Q_OS_SOLARIS
0060     cpuScheduler->addButton(ui->radioBatch, (int)KSysGuard::Process::Batch);
0061 #else
0062     cpuScheduler->addButton(ui->radioBatch, (int)KSysGuard::Process::Interactive);
0063     ui->radioBatch->setText(i18nc("Scheduler", "Interactive"));
0064 #endif
0065     cpuScheduler->addButton(ui->radioFIFO, (int)KSysGuard::Process::Fifo);
0066     cpuScheduler->addButton(ui->radioRR, (int)KSysGuard::Process::RoundRobin);
0067     if (currentCpuSched >= 0) { // negative means none of these
0068         QAbstractButton *sched = cpuScheduler->button(currentCpuSched);
0069         if (sched) {
0070             sched->setChecked(true); // Check the current scheduler
0071             previous_cpuscheduler = currentCpuSched;
0072         }
0073     }
0074     cpuScheduler->setExclusive(true);
0075 
0076     ioScheduler = new QButtonGroup(this);
0077     ioScheduler->addButton(ui->radioIONormal, (int)KSysGuard::Process::None);
0078     ioScheduler->addButton(ui->radioIdle, (int)KSysGuard::Process::Idle);
0079     ioScheduler->addButton(ui->radioRealTime, (int)KSysGuard::Process::RealTime);
0080     ioScheduler->addButton(ui->radioBestEffort, (int)KSysGuard::Process::BestEffort);
0081     // negative means none of these
0082     if (currentIoSched >= 0) {
0083         QAbstractButton *iosched = ioScheduler->button(currentIoSched);
0084         if (iosched) {
0085             iosched->setChecked(true); // Check the current io scheduler
0086         }
0087     }
0088 
0089     ioScheduler->setExclusive(true);
0090 
0091     setSliderRange(); // Update the slider ranges before trying to set their current values
0092     if (ioniceSupported) {
0093         ui->sliderIO->setValue(currentIoPrio);
0094     }
0095     ui->sliderCPU->setValue(currentCpuPrio);
0096 
0097     ui->imgCPU->setPixmap(QIcon::fromTheme(QStringLiteral("cpu")).pixmap(128, 128));
0098     ui->imgIO->setPixmap(QIcon::fromTheme(QStringLiteral("drive-harddisk")).pixmap(128, 128));
0099 
0100     newCPUPriority = 40;
0101 
0102     connect(cpuScheduler, &QButtonGroup::idClicked, this, &ReniceDlg::cpuSchedulerChanged);
0103     connect(ioScheduler, &QButtonGroup::idClicked, this, &ReniceDlg::updateUi);
0104     connect(ui->sliderCPU, &QAbstractSlider::valueChanged, this, &ReniceDlg::cpuSliderChanged);
0105     connect(ui->sliderIO, &QAbstractSlider::valueChanged, this, &ReniceDlg::ioSliderChanged);
0106 
0107     updateUi();
0108 
0109     mainLayout->addWidget(buttonBox);
0110 }
0111 
0112 ReniceDlg::~ReniceDlg()
0113 {
0114     delete ui;
0115 }
0116 
0117 void ReniceDlg::ioSliderChanged(int value)
0118 {
0119     ui->sliderIO->setToolTip(QString::number(value));
0120 }
0121 
0122 void ReniceDlg::cpuSchedulerChanged(int value)
0123 {
0124     if (value != previous_cpuscheduler) {
0125         if ((value == (int)KSysGuard::Process::Other || value == KSysGuard::Process::Batch)
0126             && (previous_cpuscheduler == (int)KSysGuard::Process::Fifo || previous_cpuscheduler == (int)KSysGuard::Process::RoundRobin)) {
0127             int slider = -ui->sliderCPU->value() * 2 / 5 + 20;
0128             setSliderRange();
0129             ui->sliderCPU->setValue(slider);
0130         } else if ((previous_cpuscheduler == (int)KSysGuard::Process::Other || previous_cpuscheduler == KSysGuard::Process::Batch)
0131                    && (value == (int)KSysGuard::Process::Fifo || value == (int)KSysGuard::Process::RoundRobin)) {
0132             int slider = (-ui->sliderCPU->value() + 20) * 5 / 2;
0133             setSliderRange();
0134             ui->sliderCPU->setValue(slider);
0135         }
0136     }
0137     previous_cpuscheduler = value;
0138     updateUi();
0139 }
0140 
0141 void ReniceDlg::cpuSliderChanged(int value)
0142 {
0143     if (ioniceSupported) {
0144         if (cpuScheduler->checkedId() == (int)KSysGuard::Process::Other || cpuScheduler->checkedId() == (int)KSysGuard::Process::Batch) {
0145             if (ioScheduler->checkedId() == -1 || ioScheduler->checkedId() == (int)KSysGuard::Process::None) {
0146                 // ionice is 'Normal', thus automatically calculated based on cpunice
0147                 ui->sliderIO->setValue((value + 20) / 5);
0148             }
0149         }
0150     }
0151     ui->sliderCPU->setToolTip(QString::number(value));
0152 }
0153 
0154 void ReniceDlg::updateUi()
0155 {
0156     bool cpuPrioEnabled = (cpuScheduler->checkedId() != -1);
0157     bool ioPrioEnabled = (ioniceSupported && ioScheduler->checkedId() != -1 && ioScheduler->checkedId() != (int)KSysGuard::Process::Idle
0158                           && ioScheduler->checkedId() != (int)KSysGuard::Process::None);
0159 
0160     ui->sliderCPU->setEnabled(cpuPrioEnabled);
0161     ui->lblCpuLow->setEnabled(cpuPrioEnabled);
0162     ui->lblCpuHigh->setEnabled(cpuPrioEnabled);
0163 
0164     ui->sliderIO->setEnabled(ioPrioEnabled);
0165     ui->lblIOLow->setEnabled(ioPrioEnabled);
0166     ui->lblIOHigh->setEnabled(ioPrioEnabled);
0167 
0168     ui->radioIONormal->setEnabled(ioniceSupported);
0169     ui->radioIdle->setEnabled(ioniceSupported);
0170     ui->radioRealTime->setEnabled(ioniceSupported);
0171     ui->radioBestEffort->setEnabled(ioniceSupported);
0172 
0173     setSliderRange();
0174     cpuSliderChanged(ui->sliderCPU->value());
0175     ioSliderChanged(ui->sliderIO->value());
0176 }
0177 
0178 void ReniceDlg::setSliderRange()
0179 {
0180     if (cpuScheduler->checkedId() == (int)KSysGuard::Process::Other || cpuScheduler->checkedId() == (int)KSysGuard::Process::Batch
0181         || cpuScheduler->checkedId() == (int)KSysGuard::Process::Interactive) {
0182         // The slider is setting the priority, so goes from 19 to -20.  We cannot actually do this with a slider, so instead we go from -19 to 20, and negate
0183         // later
0184         if (ui->sliderCPU->value() > 20) {
0185             ui->sliderCPU->setValue(20);
0186         }
0187         ui->sliderCPU->setInvertedAppearance(true);
0188         ui->sliderCPU->setMinimum(-20);
0189         ui->sliderCPU->setMaximum(19);
0190         ui->sliderCPU->setTickInterval(5);
0191     } else {
0192         if (ui->sliderCPU->value() < 1) {
0193             ui->sliderCPU->setValue(1);
0194         }
0195         ui->sliderCPU->setInvertedAppearance(false);
0196         ui->sliderCPU->setMinimum(1);
0197         ui->sliderCPU->setMaximum(99);
0198         ui->sliderCPU->setTickInterval(12);
0199     }
0200 }
0201 
0202 void ReniceDlg::slotOk()
0203 {
0204     newCPUPriority = ui->sliderCPU->value();
0205     newIOPriority = ui->sliderIO->value();
0206     newCPUSched = cpuScheduler->checkedId();
0207     newIOSched = ioScheduler->checkedId();
0208     accept();
0209 }