screenbrightnessplugin: Extract from initialstart and use in shell

This is partially an emergency fix also for
https://invent.kde.org/plasma/plasma-mobile/-/issues/404, which was
potentially introduced by https://invent.kde.org/plasma/plasma-mobile/-/merge_requests/582

This MR extracts the screen brightness implementation from initialstart
to a QML plugin, and also ports the action drawer brightness slider
implementation to it. This avoids importing the powerdevil screen
brightness plugin on the lockscreen, which apparently has a race
condition that causes it to sometimes segfault.
This commit is contained in:
Devin Lin 2024-10-08 22:47:30 -07:00
parent 050ce9e5b8
commit c7e5003596
11 changed files with 204 additions and 142 deletions

View file

@ -11,3 +11,4 @@ add_subdirectory(windowplugin)
add_subdirectory(shellsettingsplugin) add_subdirectory(shellsettingsplugin)
add_subdirectory(wallpaperimageplugin) add_subdirectory(wallpaperimageplugin)
add_subdirectory(dpmsplugin) add_subdirectory(dpmsplugin)
add_subdirectory(screenbrightnessplugin)

View file

@ -12,16 +12,15 @@ import org.kde.kirigami 2.20 as Kirigami
import org.kde.plasma.core as PlasmaCore import org.kde.plasma.core as PlasmaCore
import org.kde.plasma.components 3.0 as PC3 import org.kde.plasma.components 3.0 as PC3
import org.kde.plasma.private.mobileshell.screenbrightnessplugin as ScreenBrightness
Item { Item {
id: root id: root
implicitHeight: brightnessRow.implicitHeight implicitHeight: brightnessRow.implicitHeight
property alias value: brightnessSlider.value ScreenBrightness.ScreenBrightnessUtil {
property alias maximumValue: brightnessSlider.to id: screenBrightness
}
signal moved()
RowLayout { RowLayout {
id: brightnessRow id: brightnessRow
@ -42,10 +41,18 @@ Item {
PC3.Slider { PC3.Slider {
id: brightnessSlider id: brightnessSlider
Layout.fillWidth: true Layout.fillWidth: true
Layout.alignment: Qt.AlignVCenter
from: 1 from: 1
to: screenBrightness.maxBrightness
value: screenBrightness.brightness
onMoved: screenBrightness.brightness = value;
onMoved: root.moved() // HACK: for some reason, the slider initial value doesn't set without being done after the component completes loading
Timer {
interval: 0
running: true
repeat: false
onTriggered: brightnessSlider.value = Qt.binding(() => screenBrightness.brightness)
}
} }
Kirigami.Icon { Kirigami.Icon {

View file

@ -14,7 +14,6 @@ import org.kde.plasma.private.mobileshell as MobileShell
import org.kde.plasma.components 3.0 as PlasmaComponents import org.kde.plasma.components 3.0 as PlasmaComponents
import org.kde.plasma.private.mobileshell.quicksettingsplugin as QS import org.kde.plasma.private.mobileshell.quicksettingsplugin as QS
import org.kde.kirigami 2.20 as Kirigami import org.kde.kirigami 2.20 as Kirigami
import org.kde.plasma.private.brightnesscontrolplugin as BC
/** /**
* Quick settings elements layout, change the height to clip. * Quick settings elements layout, change the height to clip.
@ -107,29 +106,11 @@ Item {
sourceComponent: root.mode === QuickSettings.Pages ? swipeViewComponent : scrollViewComponent sourceComponent: root.mode === QuickSettings.Pages ? swipeViewComponent : scrollViewComponent
} }
BC.ScreenBrightnessControl { BrightnessItem {
id: screenBrightnessControl Layout.bottomMargin: Kirigami.Units.smallSpacing * 2
} Layout.leftMargin: Kirigami.Units.smallSpacing
Layout.rightMargin: Kirigami.Units.smallSpacing
Repeater { Layout.fillWidth: true
id: brightnessRepeater
model: screenBrightnessControl.displays
BrightnessItem {
required property string displayName
required property int brightness
required property int maxBrightness
Layout.bottomMargin: Kirigami.Units.smallSpacing * 2
Layout.leftMargin: Kirigami.Units.smallSpacing
Layout.rightMargin: Kirigami.Units.smallSpacing
Layout.fillWidth: true
value: brightness
maximumValue: maxBrightness
onMoved: screenBrightnessControl.setBrightness(displayName, value)
}
} }
} }

View file

@ -0,0 +1,25 @@
# SPDX-FileCopyrightText: 2024 Devin Lin <devin@kde.org>
# SPDX-License-Identifier: GPL-2.0-or-later
ecm_add_qml_module(screenbrightnessplugin URI org.kde.plasma.private.mobileshell.screenbrightnessplugin GENERATE_PLUGIN_SOURCE)
qt_add_dbus_interfaces(DBUS_SRCS dbus/org.kde.Solid.PowerManagement.Actions.BrightnessControl.xml)
target_sources(screenbrightnessplugin PRIVATE
screenbrightnessutil.cpp
${DBUS_SRCS}
)
target_link_libraries(screenbrightnessplugin PRIVATE
Qt::Qml
Qt::DBus
Qt::Gui
Qt::Quick
KF6::CoreAddons
KF6::ConfigCore
KF6::ConfigGui
KF6::I18n
KF6::Screen
)
ecm_finalize_qml_module(screenbrightnessplugin)

View file

@ -0,0 +1,97 @@
// SPDX-FileCopyrightText: 2024 Devin Lin <devin@kde.org>
// SPDX-License-Identifier: GPL-2.0-or-later
#include "screenbrightnessutil.h"
#include <QDBusPendingCallWatcher>
#include <QDBusPendingReply>
ScreenBrightnessUtil::ScreenBrightnessUtil(QObject *parent)
: QObject{parent}
{
m_brightnessInterface =
new org::kde::Solid::PowerManagement::Actions::BrightnessControl(QStringLiteral("org.kde.Solid.PowerManagement"),
QStringLiteral("/org/kde/Solid/PowerManagement/Actions/BrightnessControl"),
QDBusConnection::sessionBus(),
this);
fetchBrightness();
fetchMaxBrightness();
connect(m_brightnessInterface,
&org::kde::Solid::PowerManagement::Actions::BrightnessControl::brightnessChanged,
this,
&ScreenBrightnessUtil::fetchBrightness);
connect(m_brightnessInterface,
&org::kde::Solid::PowerManagement::Actions::BrightnessControl::brightnessMaxChanged,
this,
&ScreenBrightnessUtil::fetchMaxBrightness);
// watch for brightness interface
m_brightnessInterfaceWatcher = new QDBusServiceWatcher(QStringLiteral("org.kde.Solid.PowerManagement.Actions.BrightnessControl"),
QDBusConnection::sessionBus(),
QDBusServiceWatcher::WatchForOwnerChange,
this);
connect(m_brightnessInterfaceWatcher, &QDBusServiceWatcher::serviceRegistered, this, [this]() -> void {
Q_EMIT brightnessAvailableChanged();
});
connect(m_brightnessInterfaceWatcher, &QDBusServiceWatcher::serviceUnregistered, this, [this]() -> void {
Q_EMIT brightnessAvailableChanged();
});
}
int ScreenBrightnessUtil::brightness() const
{
return m_brightness;
}
void ScreenBrightnessUtil::setBrightness(int brightness)
{
m_brightnessInterface->setBrightness(brightness);
}
int ScreenBrightnessUtil::maxBrightness() const
{
return m_maxBrightness;
}
bool ScreenBrightnessUtil::brightnessAvailable() const
{
return m_brightnessInterface->isValid();
}
void ScreenBrightnessUtil::fetchBrightness()
{
QDBusPendingReply<int> reply = m_brightnessInterface->brightness();
QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(reply, this);
connect(watcher, &QDBusPendingCallWatcher::finished, this, [this](QDBusPendingCallWatcher *watcher) {
QDBusPendingReply<int> reply = *watcher;
if (reply.isError()) {
qWarning() << "Getting brightness failed:" << reply.error().name() << reply.error().message();
} else if (m_brightness != reply.value()) {
m_brightness = reply.value();
Q_EMIT brightnessChanged();
}
watcher->deleteLater();
});
}
void ScreenBrightnessUtil::fetchMaxBrightness()
{
QDBusPendingReply<int> reply = m_brightnessInterface->brightnessMax();
QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(reply, this);
connect(watcher, &QDBusPendingCallWatcher::finished, this, [this](QDBusPendingCallWatcher *watcher) {
QDBusPendingReply<int> reply = *watcher;
if (reply.isError()) {
qWarning() << "Getting max brightness failed:" << reply.error().name() << reply.error().message();
} else if (m_maxBrightness != reply.value()) {
m_maxBrightness = reply.value();
Q_EMIT maxBrightnessChanged();
}
watcher->deleteLater();
});
}

View file

@ -0,0 +1,50 @@
// SPDX-FileCopyrightText: 2024 Devin Lin <devin@kde.org>
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <QDBusServiceWatcher>
#include <QObject>
#include <qqmlregistration.h>
#include "brightnesscontrolinterface.h"
/**
* Utility class that provides useful functions related to screen brightness.
*
* @author Devin Lin <devin@kde.org>
**/
class ScreenBrightnessUtil : public QObject
{
Q_OBJECT
Q_PROPERTY(int brightness READ brightness WRITE setBrightness NOTIFY brightnessChanged);
Q_PROPERTY(int maxBrightness READ maxBrightness NOTIFY maxBrightnessChanged)
Q_PROPERTY(bool brightnessAvailable READ brightnessAvailable NOTIFY brightnessAvailableChanged)
QML_ELEMENT
public:
ScreenBrightnessUtil(QObject *parent = nullptr);
int brightness() const;
void setBrightness(int brightness);
int maxBrightness() const;
bool brightnessAvailable() const;
Q_SIGNALS:
void brightnessChanged();
void maxBrightnessChanged();
void brightnessAvailableChanged();
private Q_SLOTS:
void fetchBrightness();
void fetchMaxBrightness();
private:
int m_brightness;
int m_maxBrightness;
org::kde::Solid::PowerManagement::Actions::BrightnessControl *m_brightnessInterface;
QDBusServiceWatcher *m_brightnessInterfaceWatcher;
};

View file

@ -1,12 +1,9 @@
# SPDX-FileCopyrightText: 2023 Devin Lin <devin@kde.org> # SPDX-FileCopyrightText: 2023 Devin Lin <devin@kde.org>
# SPDX-License-Identifier: GPL-2.0-or-later # SPDX-License-Identifier: GPL-2.0-or-later
qt_add_dbus_interfaces(DBUS_SRCS dbus/org.kde.Solid.PowerManagement.Actions.BrightnessControl.xml)
set(prepareplugin_SRCS set(prepareplugin_SRCS
prepareplugin.cpp prepareplugin.cpp
prepareutil.cpp prepareutil.cpp
${DBUS_SRCS}
) )
kconfig_add_kcfg_files(prepareplugin_SRCS colorssettings.kcfgc GENERATE_MOC) kconfig_add_kcfg_files(prepareplugin_SRCS colorssettings.kcfgc GENERATE_MOC)

View file

@ -8,6 +8,7 @@ import QtQuick.Layouts 1.15
import org.kde.kirigami 2.20 as Kirigami import org.kde.kirigami 2.20 as Kirigami
import org.kde.kirigamiaddons.formcard 1.0 as FormCard import org.kde.kirigamiaddons.formcard 1.0 as FormCard
import org.kde.plasma.mobileinitialstart.prepare 1.0 as Prepare import org.kde.plasma.mobileinitialstart.prepare 1.0 as Prepare
import org.kde.plasma.private.mobileshell.screenbrightnessplugin as ScreenBrightness
Item { Item {
id: root id: root
@ -15,6 +16,10 @@ Item {
readonly property real cardWidth: Math.min(Kirigami.Units.gridUnit * 30, root.width - Kirigami.Units.gridUnit * 2) readonly property real cardWidth: Math.min(Kirigami.Units.gridUnit * 30, root.width - Kirigami.Units.gridUnit * 2)
ScreenBrightness.ScreenBrightnessUtil {
id: screenBrightness
}
ScrollView { ScrollView {
anchors { anchors {
fill: parent fill: parent
@ -34,7 +39,7 @@ Item {
Layout.alignment: Qt.AlignTop Layout.alignment: Qt.AlignTop
Layout.fillWidth: true Layout.fillWidth: true
visible: Prepare.PrepareUtil.brightnessAvailable visible: screenBrightness.brightnessAvailable
wrapMode: Text.Wrap wrapMode: Text.Wrap
horizontalAlignment: Text.AlignHCenter horizontalAlignment: Text.AlignHCenter
text: i18n("Adjust the screen brightness to be comfortable for the installation process.") text: i18n("Adjust the screen brightness to be comfortable for the installation process.")
@ -42,7 +47,7 @@ Item {
FormCard.FormCard { FormCard.FormCard {
id: brightnessCard id: brightnessCard
visible: Prepare.PrepareUtil.brightnessAvailable visible: screenBrightness.brightnessAvailable
maximumWidth: root.cardWidth maximumWidth: root.cardWidth
Layout.alignment: Qt.AlignTop | Qt.AlignHCenter Layout.alignment: Qt.AlignTop | Qt.AlignHCenter
@ -63,16 +68,16 @@ Item {
id: brightnessSlider id: brightnessSlider
Layout.fillWidth: true Layout.fillWidth: true
from: 1 from: 1
to: Prepare.PrepareUtil.maxBrightness to: screenBrightness.maxBrightness
value: Prepare.PrepareUtil.brightness value: screenBrightness.brightness
onMoved: Prepare.PrepareUtil.brightness = value; onMoved: screenBrightness.brightness = value;
// HACK: for some reason, the slider initial value doesn't set without being done after the component completes loading // HACK: for some reason, the slider initial value doesn't set without being done after the component completes loading
Timer { Timer {
interval: 0 interval: 0
running: true running: true
repeat: false repeat: false
onTriggered: brightnessSlider.value = Qt.binding(() => Prepare.PrepareUtil.brightness) onTriggered: brightnessSlider.value = Qt.binding(() => screenBrightness.brightness)
} }
} }

View file

@ -10,23 +10,12 @@
#include <QDBusPendingCallWatcher> #include <QDBusPendingCallWatcher>
#include <QDBusPendingReply> #include <QDBusPendingReply>
#include <QProcess>
PrepareUtil::PrepareUtil(QObject *parent) PrepareUtil::PrepareUtil(QObject *parent)
: QObject{parent} : QObject{parent}
, m_colorsSettings{new ColorsSettings(this)} , m_colorsSettings{new ColorsSettings(this)}
{ {
m_brightnessInterface =
new org::kde::Solid::PowerManagement::Actions::BrightnessControl(QStringLiteral("org.kde.Solid.PowerManagement"),
QStringLiteral("/org/kde/Solid/PowerManagement/Actions/BrightnessControl"),
QDBusConnection::sessionBus(),
this);
fetchBrightness();
fetchMaxBrightness();
connect(m_brightnessInterface, &org::kde::Solid::PowerManagement::Actions::BrightnessControl::brightnessChanged, this, &PrepareUtil::fetchBrightness);
connect(m_brightnessInterface, &org::kde::Solid::PowerManagement::Actions::BrightnessControl::brightnessMaxChanged, this, &PrepareUtil::fetchMaxBrightness);
connect(new KScreen::GetConfigOperation(), &KScreen::GetConfigOperation::finished, this, [this](auto *op) { connect(new KScreen::GetConfigOperation(), &KScreen::GetConfigOperation::finished, this, [this](auto *op) {
m_config = qobject_cast<KScreen::GetConfigOperation *>(op)->config(); m_config = qobject_cast<KScreen::GetConfigOperation *>(op)->config();
@ -45,20 +34,6 @@ PrepareUtil::PrepareUtil(QObject *parent)
Q_EMIT scalingChanged(); Q_EMIT scalingChanged();
}); });
// watch for brightness interface
m_brightnessInterfaceWatcher = new QDBusServiceWatcher(QStringLiteral("org.kde.Solid.PowerManagement.Actions.BrightnessControl"),
QDBusConnection::sessionBus(),
QDBusServiceWatcher::WatchForOwnerChange,
this);
connect(m_brightnessInterfaceWatcher, &QDBusServiceWatcher::serviceRegistered, this, [this]() -> void {
Q_EMIT brightnessAvailableChanged();
});
connect(m_brightnessInterfaceWatcher, &QDBusServiceWatcher::serviceUnregistered, this, [this]() -> void {
Q_EMIT brightnessAvailableChanged();
});
// set property initially // set property initially
m_usingDarkTheme = m_colorsSettings->colorScheme() == "BreezeDark"; m_usingDarkTheme = m_colorsSettings->colorScheme() == "BreezeDark";
} }
@ -93,26 +68,6 @@ QStringList PrepareUtil::scalingOptions()
return {"50%", "75%", "100%", "125%", "150%", "175%", "200%", "225%", "250%", "275%", "300%"}; return {"50%", "75%", "100%", "125%", "150%", "175%", "200%", "225%", "250%", "275%", "300%"};
} }
int PrepareUtil::brightness() const
{
return m_brightness;
}
void PrepareUtil::setBrightness(int brightness)
{
m_brightnessInterface->setBrightness(brightness);
}
int PrepareUtil::maxBrightness() const
{
return m_maxBrightness;
}
bool PrepareUtil::brightnessAvailable() const
{
return m_brightnessInterface->isValid();
}
bool PrepareUtil::usingDarkTheme() const bool PrepareUtil::usingDarkTheme() const
{ {
return m_usingDarkTheme; return m_usingDarkTheme;
@ -130,37 +85,3 @@ void PrepareUtil::setUsingDarkTheme(bool usingDarkTheme)
m_usingDarkTheme = usingDarkTheme; m_usingDarkTheme = usingDarkTheme;
Q_EMIT usingDarkThemeChanged(); Q_EMIT usingDarkThemeChanged();
} }
void PrepareUtil::fetchBrightness()
{
QDBusPendingReply<int> reply = m_brightnessInterface->brightness();
QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(reply, this);
connect(watcher, &QDBusPendingCallWatcher::finished, this, [this](QDBusPendingCallWatcher *watcher) {
QDBusPendingReply<int> reply = *watcher;
if (reply.isError()) {
qWarning() << "Getting brightness failed:" << reply.error().name() << reply.error().message();
} else if (m_brightness != reply.value()) {
m_brightness = reply.value();
Q_EMIT brightnessChanged();
}
watcher->deleteLater();
});
}
void PrepareUtil::fetchMaxBrightness()
{
QDBusPendingReply<int> reply = m_brightnessInterface->brightnessMax();
QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(reply, this);
connect(watcher, &QDBusPendingCallWatcher::finished, this, [this](QDBusPendingCallWatcher *watcher) {
QDBusPendingReply<int> reply = *watcher;
if (reply.isError()) {
qWarning() << "Getting max brightness failed:" << reply.error().name() << reply.error().message();
} else if (m_maxBrightness != reply.value()) {
m_maxBrightness = reply.value();
Q_EMIT maxBrightnessChanged();
}
watcher->deleteLater();
});
}

View file

@ -8,7 +8,6 @@
#include <kscreen/config.h> #include <kscreen/config.h>
#include "brightnesscontrolinterface.h"
#include "colorssettings.h" #include "colorssettings.h"
class PrepareUtil : public QObject class PrepareUtil : public QObject
@ -16,9 +15,6 @@ class PrepareUtil : public QObject
Q_OBJECT Q_OBJECT
Q_PROPERTY(int scaling READ scaling WRITE setScaling NOTIFY scalingChanged); Q_PROPERTY(int scaling READ scaling WRITE setScaling NOTIFY scalingChanged);
Q_PROPERTY(QStringList scalingOptions READ scalingOptions CONSTANT); Q_PROPERTY(QStringList scalingOptions READ scalingOptions CONSTANT);
Q_PROPERTY(int brightness READ brightness WRITE setBrightness NOTIFY brightnessChanged);
Q_PROPERTY(int maxBrightness READ maxBrightness NOTIFY maxBrightnessChanged)
Q_PROPERTY(bool brightnessAvailable READ brightnessAvailable NOTIFY brightnessAvailableChanged)
Q_PROPERTY(bool usingDarkTheme READ usingDarkTheme WRITE setUsingDarkTheme NOTIFY usingDarkThemeChanged) Q_PROPERTY(bool usingDarkTheme READ usingDarkTheme WRITE setUsingDarkTheme NOTIFY usingDarkThemeChanged)
public: public:
@ -29,35 +25,17 @@ public:
QStringList scalingOptions(); QStringList scalingOptions();
int brightness() const;
void setBrightness(int brightness);
int maxBrightness() const;
bool brightnessAvailable() const;
bool usingDarkTheme() const; bool usingDarkTheme() const;
void setUsingDarkTheme(bool usingDarkTheme); void setUsingDarkTheme(bool usingDarkTheme);
Q_SIGNALS: Q_SIGNALS:
void scalingChanged(); void scalingChanged();
void brightnessChanged();
void maxBrightnessChanged();
void brightnessAvailableChanged();
void usingDarkThemeChanged(); void usingDarkThemeChanged();
private Q_SLOTS:
void fetchBrightness();
void fetchMaxBrightness();
private: private:
int m_scaling; int m_scaling;
int m_brightness;
int m_maxBrightness;
bool m_usingDarkTheme; bool m_usingDarkTheme;
ColorsSettings *m_colorsSettings; ColorsSettings *m_colorsSettings;
KScreen::ConfigPtr m_config; KScreen::ConfigPtr m_config;
org::kde::Solid::PowerManagement::Actions::BrightnessControl *m_brightnessInterface;
QDBusServiceWatcher *m_brightnessInterfaceWatcher;
}; };