Skip to content

No battery icon #428

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ set(SOURCES
main.cpp
powermanagementd.cpp
trayicon.cpp
trayiconbattery.cpp
iconproducer.cpp
powerbutton.cpp
../config/powermanagementsettings.cpp
Expand Down
29 changes: 1 addition & 28 deletions src/batterywatcher.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -69,11 +69,6 @@ BatteryWatcher::BatteryWatcher(QObject *parent) : Watcher(parent)

settingsChanged();
batteryChanged();

// pause timer
mPauseTimer.setSingleShot(true);
mPauseTimer.setTimerType(Qt::VeryCoarseTimer);
connect(&mPauseTimer, &QTimer::timeout, this, &BatteryWatcher::onPauseTimeout);
}

BatteryWatcher::~BatteryWatcher()
Expand Down Expand Up @@ -177,31 +172,9 @@ void BatteryWatcher::settingsChanged()
{
for (Solid::Battery *battery : std::as_const(mBatteries))
{
mTrayIcons.append(new TrayIcon(battery, this));
mTrayIcons.append(new TrayIconBattery(battery, this));
connect(mTrayIcons.last(), &TrayIcon::toggleShowInfo, mBatteryInfoDialog, &BatteryInfoDialog::toggleShow);
connect(mTrayIcons.last(), &TrayIcon::pauseChanged, this, &BatteryWatcher::setPause);
mTrayIcons.last()->show();
}
}
}

void BatteryWatcher::onPauseTimeout()
{
for (const auto &trayIcon : std::as_const(mTrayIcons))
trayIcon->setPause(TrayIcon::PAUSE::None);
}

void BatteryWatcher::setPause(TrayIcon::PAUSE duration)
{
if (duration == TrayIcon::PAUSE::None)
{
onPauseTimeout();
mPauseTimer.stop();
}
else
{
for (const auto &trayIcon : std::as_const(mTrayIcons))
trayIcon->setPause(duration);
mPauseTimer.start(TrayIcon::getPauseInterval(duration));
}
}
7 changes: 2 additions & 5 deletions src/batterywatcher.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
#define BATTERYWATCHER_H

#include "watcher.h"
#include "trayicon.h"
#include "trayiconbattery.h"
#include "batteryinfodialog.h"
#include "../config/powermanagementsettings.h"

Expand All @@ -47,13 +47,10 @@ class BatteryWatcher : public Watcher
private slots:
void batteryChanged();
void settingsChanged();
void onPauseTimeout();
void setPause(TrayIcon::PAUSE duration);

private:
QList<Solid::Battery*> mBatteries;
QList<TrayIcon*> mTrayIcons;
QTimer mPauseTimer;
QList<TrayIconBattery*> mTrayIcons;

PowerManagementSettings mSettings;
BatteryInfoDialog *mBatteryInfoDialog;
Expand Down
12 changes: 12 additions & 0 deletions src/powermanagementd.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ PowerManagementd::PowerManagementd() :
mBatterywatcherd(nullptr),
mLidwatcherd(nullptr),
mIdlenesswatcherd(nullptr),
mPowerButton(nullptr),
mTrayIcon(nullptr),
mSettings()
{
connect(&mSettings, &PowerManagementSettings::settingsChanged, this, &PowerManagementd::settingsChanged);
Expand Down Expand Up @@ -70,6 +72,16 @@ void PowerManagementd::settingsChanged()
mBatterywatcherd->deleteLater();
mBatterywatcherd = nullptr;
}
if (!mTrayIcon && (!mBatterywatcherd || !mSettings.isShowIcon()))
{
mTrayIcon = new TrayIcon(this);
mTrayIcon->show();
} else if (mBatterywatcherd && mSettings.isShowIcon() && mTrayIcon)
{
mTrayIcon->hide();
mTrayIcon->deleteLater();
mTrayIcon = nullptr;
}

if (mSettings.isLidWatcherEnabled() && !mLidwatcherd)
{
Expand Down
4 changes: 3 additions & 1 deletion src/powermanagementd.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ class BatteryWatcher;
class LidWatcher;
class IdlenessWatcher;
class PowerButton;
class TrayIcon;

class PowerManagementd : public QObject
{
Expand All @@ -36,7 +37,8 @@ private slots:
BatteryWatcher* mBatterywatcherd;
LidWatcher* mLidwatcherd;
IdlenessWatcher* mIdlenesswatcherd;
PowerButton *mPowerButton;
PowerButton* mPowerButton;
TrayIcon* mTrayIcon;

PowerManagementSettings mSettings;
LXQt::Notification mNotification;
Expand Down
155 changes: 81 additions & 74 deletions src/trayicon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@
* https://lxqt.org
*
* Copyright: 2011 Razor team
* 2025~ LXQt team
* Authors:
* Christian Surlykke <[email protected]>
* Palo Kisa <[email protected]>
*
* This program or library is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser General Public
Expand All @@ -25,100 +27,109 @@
*
* END_COMMON_COPYRIGHT_HEADER */

#include <QDebug>
#include <QApplication>
#include <QProcess>
#include <QActionGroup>
#include <QMessageBox>
#include <QToolTip>
#include <QHelpEvent>
#include <QPixmapCache>
#include <QPainter>
#include <QtSvg/QSvgRenderer>
#include <Solid/Battery>
#include <Solid/Device>
#include <QIcon>
#include <QStringBuilder>
#include <QGlobalStatic>

#include "trayicon.h"
#include "batteryhelper.h"
#include "../config/powermanagementsettings.h"

#include <LXQt/Globals>
#include <LXQt/Notification>
#include "PowerProfiles.h"
#include <QTimer>

TrayIcon::TrayIcon(Solid::Battery *battery, QObject *parent)
QList<TrayIcon *> TrayIcon::msInstances;
std::unique_ptr<QMenu> TrayIcon::msContextMenu{nullptr};
std::unique_ptr<QTimer> TrayIcon::msPauseTimer{nullptr};
std::unique_ptr<QActionGroup> TrayIcon::msPauseActions{nullptr};

TrayIcon::TrayIcon(QObject *parent)
: QSystemTrayIcon(parent),
mBattery(battery),
mIconProducer(battery),
mContextMenu(),
mBaseIcon(QIcon::fromTheme(QL1S("preferences-system-power-management"))),
mHasPauseEmblem(false)
{
connect(mBattery, &Solid::Battery::chargePercentChanged, this, &TrayIcon::updateTooltip);
connect(mBattery, &Solid::Battery::chargeStateChanged, this, &TrayIcon::updateTooltip);
connect(mBattery, &Solid::Battery::timeToEmptyChanged, this, &TrayIcon::updateTooltip);
connect(mBattery, &Solid::Battery::timeToFullChanged, this, &TrayIcon::updateTooltip);
updateTooltip();

connect(&mIconProducer, &IconProducer::iconChanged, this, &TrayIcon::iconChanged);
iconChanged();

connect(this, &TrayIcon::activated, this, &TrayIcon::onActivated);

mContextMenu.addAction(QIcon::fromTheme(QStringLiteral("configure")), tr("Configure"),
this, &TrayIcon::onConfigureTriggered);
if (!msPauseTimer)
{
msPauseTimer.reset(new QTimer);
msPauseTimer->setSingleShot(true);
msPauseTimer->setTimerType(Qt::VeryCoarseTimer);
connect(msPauseTimer.get(), &QTimer::timeout, [] { onPauseTimeout(); });
}
if (!msContextMenu) {
msContextMenu.reset(new QMenu);
connect(msContextMenu->addAction(QIcon::fromTheme(QStringLiteral("configure")), tr("Configure")), &QAction::triggered, [] { onConfigureTriggered(); });

// pause actions
mPauseActions = new QActionGroup(this);
mPauseActions->setExclusionPolicy(QActionGroup::ExclusionPolicy::ExclusiveOptional);
connect(mPauseActions, &QActionGroup::triggered, this, &TrayIcon::onPauseTriggered);
// pause actions
msPauseActions.reset(new QActionGroup{nullptr});
msPauseActions->setExclusionPolicy(QActionGroup::ExclusionPolicy::ExclusiveOptional);
connect(msPauseActions.get(), &QActionGroup::triggered, [] (QAction * action) { onPauseTriggered(action); });

QAction *a = new QAction(tr("30 minutes"), mPauseActions);
a->setCheckable(true);
a->setData(PAUSE::Half);
QAction *a = new QAction(tr("30 minutes"), msPauseActions.get());
a->setCheckable(true);
a->setData(PAUSE::Half);

a = new QAction(tr("1 hour"), mPauseActions);
a->setCheckable(true);
a->setData(PAUSE::One);
a = new QAction(tr("1 hour"), msPauseActions.get());
a->setCheckable(true);
a->setData(PAUSE::One);

a = new QAction(tr("2 hours"), mPauseActions);
a->setCheckable(true);
a->setData(PAUSE::Two);
a = new QAction(tr("2 hours"), msPauseActions.get());
a->setCheckable(true);
a->setData(PAUSE::Two);

a = new QAction(tr("3 hours"), mPauseActions);
a->setCheckable(true);
a->setData(PAUSE::Three);
a = new QAction(tr("3 hours"), msPauseActions.get());
a->setCheckable(true);
a->setData(PAUSE::Three);

a = new QAction(tr("4 hours"), mPauseActions);
a->setCheckable(true);
a->setData(PAUSE::Four);
a = new QAction(tr("4 hours"), msPauseActions.get());
a->setCheckable(true);
a->setData(PAUSE::Four);

QMenu *pauseMenu = mContextMenu.addMenu(QIcon::fromTheme(QStringLiteral("media-playback-pause")),
tr("Pause idleness checks"));
pauseMenu->addActions(mPauseActions->actions());
QMenu *pauseMenu = msContextMenu->addMenu(QIcon::fromTheme(QStringLiteral("media-playback-pause")),
tr("Pause idleness checks"));
pauseMenu->addActions(msPauseActions->actions());

// power-profiles actions
mContextMenu.addAction(LXQt::PowerProfiles::instance().menuAction());
// power-profiles actions
msContextMenu->addAction(LXQt::PowerProfiles::instance().menuAction());

mContextMenu.addSeparator();
msContextMenu->addSeparator();

mContextMenu.addAction(QIcon::fromTheme(QStringLiteral("help-about")), tr("About"),
this, &TrayIcon::onAboutTriggered);
mContextMenu.addAction(QIcon::fromTheme(QStringLiteral("edit-delete")), tr("Disable icon"),
this, &TrayIcon::onDisableIconTriggered);
setContextMenu(&mContextMenu);
connect(msContextMenu->addAction(QIcon::fromTheme(QStringLiteral("help-about")), tr("About")), &QAction::triggered, [] { TrayIcon::onAboutTriggered(); });
connect(msContextMenu->addAction(QIcon::fromTheme(QStringLiteral("edit-delete")), tr("Disable icon")), &QAction::triggered, [] { TrayIcon::onDisableIconTriggered(); });
}
setContextMenu(msContextMenu.get());
msInstances.push_back(this);
}

TrayIcon::~TrayIcon()
{
msInstances.removeOne(this);
if (msInstances.empty())
{
msPauseTimer.reset(nullptr);
msPauseActions.reset(nullptr);
msContextMenu.reset(nullptr);
}
}

/*virtual*/ const QIcon & TrayIcon::getIcon() const
{
return mBaseIcon;
}

void TrayIcon::iconChanged()
{
mHasPauseEmblem = PowerManagementSettings().isIdlenessWatcherPaused();
setIcon(mHasPauseEmblem ? emblemizedIcon() : mIconProducer.mIcon);
setIcon(mHasPauseEmblem ? emblemizedIcon() : getIcon());
}

QIcon TrayIcon::emblemizedIcon()
Expand All @@ -131,7 +142,7 @@ QIcon TrayIcon::emblemizedIcon()
);

const QSize icnSize(200, 200); // NOTE: QSystemTrayIcon::geometry() gives an empty rectangle
QPixmap icnPix = mIconProducer.mIcon.pixmap(icnSize);
QPixmap icnPix = getIcon().pixmap(icnSize);
const qreal pixelRatio = icnPix.devicePixelRatio();
const QSize icnPixSize((QSizeF(icnSize) * pixelRatio).toSize());

Expand Down Expand Up @@ -162,24 +173,10 @@ QIcon TrayIcon::emblemizedIcon()
return QIcon(pix);
}

void TrayIcon::updateTooltip()
void TrayIcon::onPauseTimeout()
{
QString stateStr = mBattery->chargePercent() <= 0 && mBattery->chargeState() == Solid::Battery::NoCharge ?
tr("Empty") : BatteryHelper::stateToString(mBattery->chargeState());
QString tooltip = stateStr % QString::fromLatin1(" (%1%)").arg(mBattery->chargePercent());
switch (mBattery->chargeState())
{
case Solid::Battery::Charging:
tooltip += QL1S(", ") % BatteryHelper::timeToFullString(mBattery->timeToFull());
break;
case Solid::Battery::Discharging:
tooltip += QL1S(", ") % BatteryHelper::timeToEmptyString(mBattery->timeToEmpty());
break;
default:
break;
}

setToolTip(tooltip);
for (const auto &trayIcon : std::as_const(msInstances))
trayIcon->setPause(TrayIcon::PAUSE::None);
}

void TrayIcon::onConfigureTriggered()
Expand All @@ -189,8 +186,18 @@ void TrayIcon::onConfigureTriggered()

void TrayIcon::onPauseTriggered(QAction *action)
{
emit pauseChanged(!action->isChecked() ? PAUSE::None
: static_cast<PAUSE>(action->data().toInt()));
const PAUSE duration = !action->isChecked() ? None : static_cast<PAUSE>(action->data().toInt());
if (duration == None)
{
onPauseTimeout();
msPauseTimer->stop();
}
else
{
for (const auto &trayIcon : std::as_const(msInstances))
trayIcon->setPause(duration);
msPauseTimer->start(getPauseInterval(duration));
}
}

void TrayIcon::onAboutTriggered()
Expand Down Expand Up @@ -236,7 +243,7 @@ void TrayIcon::onActivated(QSystemTrayIcon::ActivationReason reason)
void TrayIcon::setPause(PAUSE duration)
{
// add/remove the pause emblem and correct the checked action if needed
QAction *checked = mPauseActions->checkedAction();
QAction *checked = msPauseActions->checkedAction();
if (duration == PAUSE::None)
{
PowerManagementSettings().setIdlenessWatcherPaused(false);
Expand All @@ -252,7 +259,7 @@ void TrayIcon::setPause(PAUSE duration)
iconChanged(); // adds the pause emblem
if (checked == nullptr || checked->data().toInt() != duration)
{
const auto actions = mPauseActions->actions();
const auto actions = msPauseActions->actions();
for (const auto &a : actions)
{
if (a->data().toInt() == duration)
Expand Down
Loading