File indexing completed on 2024-04-28 16:50:01

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     if (currentIoSched >= 0) { // negative means none of these
0082         QAbstractButton *iosched = ioScheduler->button(currentIoSched);
0083         if (iosched)
0084             iosched->setChecked(true); // Check the current io scheduler
0085     }
0086 
0087     ioScheduler->setExclusive(true);
0088 
0089     setSliderRange(); // Update the slider ranges before trying to set their current values
0090     if (ioniceSupported)
0091         ui->sliderIO->setValue(currentIoPrio);
0092     ui->sliderCPU->setValue(currentCpuPrio);
0093 
0094     ui->imgCPU->setPixmap(QIcon::fromTheme(QStringLiteral("cpu")).pixmap(128, 128));
0095     ui->imgIO->setPixmap(QIcon::fromTheme(QStringLiteral("drive-harddisk")).pixmap(128, 128));
0096 
0097     newCPUPriority = 40;
0098 
0099     connect(cpuScheduler, SIGNAL(buttonClicked(int)), this, SLOT(cpuSchedulerChanged(int)));
0100     connect(ioScheduler, SIGNAL(buttonClicked(int)), this, SLOT(updateUi()));
0101     connect(ui->sliderCPU, &QAbstractSlider::valueChanged, this, &ReniceDlg::cpuSliderChanged);
0102     connect(ui->sliderIO, &QAbstractSlider::valueChanged, this, &ReniceDlg::ioSliderChanged);
0103 
0104     updateUi();
0105 
0106     mainLayout->addWidget(buttonBox);
0107 }
0108 
0109 ReniceDlg::~ReniceDlg()
0110 {
0111     delete ui;
0112 }
0113 
0114 void ReniceDlg::ioSliderChanged(int value)
0115 {
0116     ui->sliderIO->setToolTip(QString::number(value));
0117 }
0118 
0119 void ReniceDlg::cpuSchedulerChanged(int value)
0120 {
0121     if (value != previous_cpuscheduler) {
0122         if ((value == (int)KSysGuard::Process::Other || value == KSysGuard::Process::Batch)
0123             && (previous_cpuscheduler == (int)KSysGuard::Process::Fifo || previous_cpuscheduler == (int)KSysGuard::Process::RoundRobin)) {
0124             int slider = -ui->sliderCPU->value() * 2 / 5 + 20;
0125             setSliderRange();
0126             ui->sliderCPU->setValue(slider);
0127         } else if ((previous_cpuscheduler == (int)KSysGuard::Process::Other || previous_cpuscheduler == KSysGuard::Process::Batch)
0128                    && (value == (int)KSysGuard::Process::Fifo || value == (int)KSysGuard::Process::RoundRobin)) {
0129             int slider = (-ui->sliderCPU->value() + 20) * 5 / 2;
0130             setSliderRange();
0131             ui->sliderCPU->setValue(slider);
0132         }
0133     }
0134     previous_cpuscheduler = value;
0135     updateUi();
0136 }
0137 
0138 void ReniceDlg::cpuSliderChanged(int value)
0139 {
0140     if (ioniceSupported) {
0141         if (cpuScheduler->checkedId() == (int)KSysGuard::Process::Other || cpuScheduler->checkedId() == (int)KSysGuard::Process::Batch) {
0142             if (ioScheduler->checkedId() == -1 || ioScheduler->checkedId() == (int)KSysGuard::Process::None) {
0143                 // ionice is 'Normal', thus automatically calculated based on cpunice
0144                 ui->sliderIO->setValue((value + 20) / 5);
0145             }
0146         }
0147     }
0148     ui->sliderCPU->setToolTip(QString::number(value));
0149 }
0150 
0151 void ReniceDlg::updateUi()
0152 {
0153     bool cpuPrioEnabled = (cpuScheduler->checkedId() != -1);
0154     bool ioPrioEnabled = (ioniceSupported && ioScheduler->checkedId() != -1 && ioScheduler->checkedId() != (int)KSysGuard::Process::Idle
0155                           && ioScheduler->checkedId() != (int)KSysGuard::Process::None);
0156 
0157     ui->sliderCPU->setEnabled(cpuPrioEnabled);
0158     ui->lblCpuLow->setEnabled(cpuPrioEnabled);
0159     ui->lblCpuHigh->setEnabled(cpuPrioEnabled);
0160 
0161     ui->sliderIO->setEnabled(ioPrioEnabled);
0162     ui->lblIOLow->setEnabled(ioPrioEnabled);
0163     ui->lblIOHigh->setEnabled(ioPrioEnabled);
0164 
0165     ui->radioIONormal->setEnabled(ioniceSupported);
0166     ui->radioIdle->setEnabled(ioniceSupported);
0167     ui->radioRealTime->setEnabled(ioniceSupported);
0168     ui->radioBestEffort->setEnabled(ioniceSupported);
0169 
0170     setSliderRange();
0171     cpuSliderChanged(ui->sliderCPU->value());
0172     ioSliderChanged(ui->sliderIO->value());
0173 }
0174 
0175 void ReniceDlg::setSliderRange()
0176 {
0177     if (cpuScheduler->checkedId() == (int)KSysGuard::Process::Other || cpuScheduler->checkedId() == (int)KSysGuard::Process::Batch
0178         || cpuScheduler->checkedId() == (int)KSysGuard::Process::Interactive) {
0179         // 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
0180         // later
0181         if (ui->sliderCPU->value() > 20)
0182             ui->sliderCPU->setValue(20);
0183         ui->sliderCPU->setInvertedAppearance(true);
0184         ui->sliderCPU->setMinimum(-20);
0185         ui->sliderCPU->setMaximum(19);
0186         ui->sliderCPU->setTickInterval(5);
0187     } else {
0188         if (ui->sliderCPU->value() < 1)
0189             ui->sliderCPU->setValue(1);
0190         ui->sliderCPU->setInvertedAppearance(false);
0191         ui->sliderCPU->setMinimum(1);
0192         ui->sliderCPU->setMaximum(99);
0193         ui->sliderCPU->setTickInterval(12);
0194     }
0195 }
0196 
0197 void ReniceDlg::slotOk()
0198 {
0199     newCPUPriority = ui->sliderCPU->value();
0200     newIOPriority = ui->sliderIO->value();
0201     newCPUSched = cpuScheduler->checkedId();
0202     newIOSched = ioScheduler->checkedId();
0203     accept();
0204 }