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(wallpaperimageplugin)
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.components 3.0 as PC3
import org.kde.plasma.private.mobileshell.screenbrightnessplugin as ScreenBrightness
Item {
id: root
implicitHeight: brightnessRow.implicitHeight
property alias value: brightnessSlider.value
property alias maximumValue: brightnessSlider.to
signal moved()
ScreenBrightness.ScreenBrightnessUtil {
id: screenBrightness
}
RowLayout {
id: brightnessRow
@ -42,10 +41,18 @@ Item {
PC3.Slider {
id: brightnessSlider
Layout.fillWidth: true
Layout.alignment: Qt.AlignVCenter
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 {

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.private.mobileshell.quicksettingsplugin as QS
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.
@ -107,29 +106,11 @@ Item {
sourceComponent: root.mode === QuickSettings.Pages ? swipeViewComponent : scrollViewComponent
}
BC.ScreenBrightnessControl {
id: screenBrightnessControl
}
Repeater {
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)
}
BrightnessItem {
Layout.bottomMargin: Kirigami.Units.smallSpacing * 2
Layout.leftMargin: Kirigami.Units.smallSpacing
Layout.rightMargin: Kirigami.Units.smallSpacing
Layout.fillWidth: true
}
}

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-License-Identifier: GPL-2.0-or-later
qt_add_dbus_interfaces(DBUS_SRCS dbus/org.kde.Solid.PowerManagement.Actions.BrightnessControl.xml)
set(prepareplugin_SRCS
prepareplugin.cpp
prepareutil.cpp
${DBUS_SRCS}
)
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.kirigamiaddons.formcard 1.0 as FormCard
import org.kde.plasma.mobileinitialstart.prepare 1.0 as Prepare
import org.kde.plasma.private.mobileshell.screenbrightnessplugin as ScreenBrightness
Item {
id: root
@ -15,6 +16,10 @@ Item {
readonly property real cardWidth: Math.min(Kirigami.Units.gridUnit * 30, root.width - Kirigami.Units.gridUnit * 2)
ScreenBrightness.ScreenBrightnessUtil {
id: screenBrightness
}
ScrollView {
anchors {
fill: parent
@ -34,7 +39,7 @@ Item {
Layout.alignment: Qt.AlignTop
Layout.fillWidth: true
visible: Prepare.PrepareUtil.brightnessAvailable
visible: screenBrightness.brightnessAvailable
wrapMode: Text.Wrap
horizontalAlignment: Text.AlignHCenter
text: i18n("Adjust the screen brightness to be comfortable for the installation process.")
@ -42,7 +47,7 @@ Item {
FormCard.FormCard {
id: brightnessCard
visible: Prepare.PrepareUtil.brightnessAvailable
visible: screenBrightness.brightnessAvailable
maximumWidth: root.cardWidth
Layout.alignment: Qt.AlignTop | Qt.AlignHCenter
@ -63,16 +68,16 @@ Item {
id: brightnessSlider
Layout.fillWidth: true
from: 1
to: Prepare.PrepareUtil.maxBrightness
value: Prepare.PrepareUtil.brightness
onMoved: Prepare.PrepareUtil.brightness = value;
to: screenBrightness.maxBrightness
value: screenBrightness.brightness
onMoved: screenBrightness.brightness = value;
// 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(() => Prepare.PrepareUtil.brightness)
onTriggered: brightnessSlider.value = Qt.binding(() => screenBrightness.brightness)
}
}

View file

@ -10,23 +10,12 @@
#include <QDBusPendingCallWatcher>
#include <QDBusPendingReply>
#include <QProcess>
PrepareUtil::PrepareUtil(QObject *parent)
: QObject{parent}
, 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) {
m_config = qobject_cast<KScreen::GetConfigOperation *>(op)->config();
@ -45,20 +34,6 @@ PrepareUtil::PrepareUtil(QObject *parent)
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
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%"};
}
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
{
return m_usingDarkTheme;
@ -130,37 +85,3 @@ void PrepareUtil::setUsingDarkTheme(bool usingDarkTheme)
m_usingDarkTheme = usingDarkTheme;
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 "brightnesscontrolinterface.h"
#include "colorssettings.h"
class PrepareUtil : public QObject
@ -16,9 +15,6 @@ class PrepareUtil : public QObject
Q_OBJECT
Q_PROPERTY(int scaling READ scaling WRITE setScaling NOTIFY scalingChanged);
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)
public:
@ -29,35 +25,17 @@ public:
QStringList scalingOptions();
int brightness() const;
void setBrightness(int brightness);
int maxBrightness() const;
bool brightnessAvailable() const;
bool usingDarkTheme() const;
void setUsingDarkTheme(bool usingDarkTheme);
Q_SIGNALS:
void scalingChanged();
void brightnessChanged();
void maxBrightnessChanged();
void brightnessAvailableChanged();
void usingDarkThemeChanged();
private Q_SLOTS:
void fetchBrightness();
void fetchMaxBrightness();
private:
int m_scaling;
int m_brightness;
int m_maxBrightness;
bool m_usingDarkTheme;
ColorsSettings *m_colorsSettings;
KScreen::ConfigPtr m_config;
org::kde::Solid::PowerManagement::Actions::BrightnessControl *m_brightnessInterface;
QDBusServiceWatcher *m_brightnessInterfaceWatcher;
};