monitor-manager: Add new backlight D-Bus API
It is intended to replace using GetResources() and ChangeBacklight(). It moves from a normalized 1-100 numbers, to directly exposing the hardware. This more closely maps to how gsd-backlight.c in gnome-settings-daemon normally works, and simplifies the API a bit to not have to deal with rounding issues. There is still no KMS uAPI for this, so it still only hooks up to XRANDR. Being private API, it doesn't try very hard to predict how the KMS uAPI will look. When that day comes, it will likely need some adaptations. Part of the motivation here is to get something for gsd-backlight.c to use where it can work more similarly to how the current common case (sysefs) works, while attempting to migrate away from libgnome-rr. Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/3861>
This commit is contained in:
parent
332c4a1bf0
commit
cc0ec14712
5 changed files with 423 additions and 1 deletions
|
@ -210,12 +210,42 @@
|
|||
Returns the new value after rounding.
|
||||
-->
|
||||
<method name="ChangeBacklight">
|
||||
<annotation name="org.freedesktop.DBus.Deprecated" value="true"/>
|
||||
<arg name="serial" direction="in" type="u" />
|
||||
<arg name="output" direction="in" type="u" />
|
||||
<arg name="value" direction="in" type="i" />
|
||||
<arg name="new_value" direction="out" type="i" />
|
||||
</method>
|
||||
|
||||
<!--
|
||||
SetBacklight:
|
||||
@serial: configuration serial
|
||||
@connector: the connector name
|
||||
@value: the new backlight value
|
||||
|
||||
Changes the backlight of @output to @value.
|
||||
-->
|
||||
<method name="SetBacklight">
|
||||
<arg name="serial" direction="in" type="u" />
|
||||
<arg name="connector" direction="in" type="s" />
|
||||
<arg name="value" direction="in" type="i" />
|
||||
</method>
|
||||
|
||||
<!--
|
||||
Backlight:
|
||||
|
||||
A set of backlights. Each backlight is a dictionary with the following
|
||||
entries. If an entry is only a connector, it means there is no way to
|
||||
control it via this D-Bus interface.
|
||||
|
||||
* 'connector' (s) - An associated monitor connector
|
||||
* 'active' (s) - True if the monitor is active
|
||||
* 'value' (i) - Current value (optional)
|
||||
|
||||
The initial 'u' is a serial number used when setting the backlight.
|
||||
-->
|
||||
<property name="Backlight" type="(uaa{sv})" access="read" />
|
||||
|
||||
<!--
|
||||
GetCrtcGamma:
|
||||
@serial: configuration serial
|
||||
|
|
|
@ -120,6 +120,8 @@ typedef struct _MetaMonitorManagerPrivate
|
|||
|
||||
guint reload_monitor_manager_id;
|
||||
guint switch_config_handle_id;
|
||||
|
||||
uint32_t backlight_serial;
|
||||
} MetaMonitorManagerPrivate;
|
||||
|
||||
G_DEFINE_TYPE_WITH_PRIVATE (MetaMonitorManager, meta_monitor_manager,
|
||||
|
@ -139,6 +141,9 @@ static gboolean
|
|||
is_global_scale_matching_in_config (MetaMonitorsConfig *config,
|
||||
float scale);
|
||||
|
||||
static void update_backlight (MetaMonitorManager *manager,
|
||||
gboolean bump_serial);
|
||||
|
||||
MetaBackend *
|
||||
meta_monitor_manager_get_backend (MetaMonitorManager *manager)
|
||||
{
|
||||
|
@ -1205,6 +1210,8 @@ meta_monitor_manager_notify_monitors_changed (MetaMonitorManager *manager)
|
|||
{
|
||||
meta_backend_monitors_changed (manager->backend);
|
||||
|
||||
update_backlight (manager, TRUE);
|
||||
|
||||
g_signal_emit (manager, signals[MONITORS_CHANGED_INTERNAL], 0);
|
||||
g_signal_emit (manager, signals[MONITORS_CHANGED], 0);
|
||||
|
||||
|
@ -1240,6 +1247,8 @@ meta_monitor_manager_setup (MetaMonitorManager *manager)
|
|||
|
||||
meta_monitor_manager_notify_monitors_changed (manager);
|
||||
|
||||
update_backlight (manager, TRUE);
|
||||
|
||||
manager->in_init = FALSE;
|
||||
}
|
||||
|
||||
|
@ -2365,7 +2374,7 @@ meta_monitor_manager_is_config_complete (MetaMonitorManager *manager,
|
|||
|
||||
static MetaMonitor *
|
||||
find_monitor_from_connector (MetaMonitorManager *manager,
|
||||
char *connector)
|
||||
const char *connector)
|
||||
{
|
||||
GList *monitors;
|
||||
GList *l;
|
||||
|
@ -2910,9 +2919,72 @@ meta_monitor_manager_handle_change_backlight (MetaDBusDisplayConfig *skeleton,
|
|||
meta_output_set_backlight (output, value);
|
||||
renormalized_value = normalize_backlight (output, value);
|
||||
|
||||
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
|
||||
meta_dbus_display_config_complete_change_backlight (skeleton,
|
||||
invocation,
|
||||
renormalized_value);
|
||||
G_GNUC_END_IGNORE_DEPRECATIONS
|
||||
|
||||
|
||||
update_backlight (manager, FALSE);
|
||||
|
||||
return G_DBUS_METHOD_INVOCATION_HANDLED;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
meta_monitor_manager_handle_set_backlight (MetaDBusDisplayConfig *skeleton,
|
||||
GDBusMethodInvocation *invocation,
|
||||
uint32_t serial,
|
||||
const char * connector,
|
||||
int value,
|
||||
MetaMonitorManager *monitor_manager)
|
||||
{
|
||||
MetaMonitorManagerPrivate *priv =
|
||||
meta_monitor_manager_get_instance_private (monitor_manager);
|
||||
MetaMonitor *monitor;
|
||||
int backlight_min;
|
||||
int backlight_max;
|
||||
|
||||
if (serial != priv->backlight_serial)
|
||||
{
|
||||
g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
|
||||
G_DBUS_ERROR_INVALID_ARGS,
|
||||
"Invalid backlight serial");
|
||||
return G_DBUS_METHOD_INVOCATION_HANDLED;
|
||||
}
|
||||
|
||||
monitor = find_monitor_from_connector (monitor_manager, connector);
|
||||
if (!monitor)
|
||||
{
|
||||
g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
|
||||
G_DBUS_ERROR_INVALID_ARGS,
|
||||
"Unknown monitor");
|
||||
return G_DBUS_METHOD_INVOCATION_HANDLED;
|
||||
}
|
||||
|
||||
if (!meta_monitor_get_backlight_info (monitor,
|
||||
&backlight_min,
|
||||
&backlight_max))
|
||||
{
|
||||
g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
|
||||
G_DBUS_ERROR_INVALID_ARGS,
|
||||
"Monitor doesn't support changing backlight");
|
||||
return G_DBUS_METHOD_INVOCATION_HANDLED;
|
||||
}
|
||||
|
||||
if (value < backlight_min || value > backlight_max)
|
||||
{
|
||||
g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
|
||||
G_DBUS_ERROR_INVALID_ARGS,
|
||||
"Invalid backlight value");
|
||||
return G_DBUS_METHOD_INVOCATION_HANDLED;
|
||||
}
|
||||
|
||||
meta_monitor_set_backlight (monitor, value);
|
||||
|
||||
meta_dbus_display_config_complete_set_backlight (skeleton, invocation);
|
||||
|
||||
update_backlight (monitor_manager, FALSE);
|
||||
|
||||
return G_DBUS_METHOD_INVOCATION_HANDLED;
|
||||
}
|
||||
|
@ -3099,6 +3171,9 @@ monitor_manager_setup_dbus_config_handlers (MetaMonitorManager *manager)
|
|||
g_signal_connect_object (manager->display_config, "handle-change-backlight",
|
||||
G_CALLBACK (meta_monitor_manager_handle_change_backlight),
|
||||
manager, 0);
|
||||
g_signal_connect_object (manager->display_config, "handle-set-backlight",
|
||||
G_CALLBACK (meta_monitor_manager_handle_set_backlight),
|
||||
manager, 0);
|
||||
g_signal_connect_object (manager->display_config, "handle-get-crtc-gamma",
|
||||
G_CALLBACK (meta_monitor_manager_handle_get_crtc_gamma),
|
||||
manager, 0);
|
||||
|
@ -3594,6 +3669,68 @@ meta_monitor_manager_read_current_state (MetaMonitorManager *manager)
|
|||
manager_class->read_current_state (manager);
|
||||
}
|
||||
|
||||
static void
|
||||
update_backlight (MetaMonitorManager *manager,
|
||||
gboolean bump_serial)
|
||||
{
|
||||
MetaMonitorManagerPrivate *priv =
|
||||
meta_monitor_manager_get_instance_private (manager);
|
||||
GList *l;
|
||||
GVariantBuilder backlight_builder;
|
||||
g_autoptr (GVariant) backlight = NULL;
|
||||
|
||||
if (bump_serial)
|
||||
priv->backlight_serial++;
|
||||
|
||||
g_variant_builder_init (&backlight_builder, G_VARIANT_TYPE ("(uaa{sv})"));
|
||||
g_variant_builder_add (&backlight_builder, "u", priv->backlight_serial);
|
||||
|
||||
g_variant_builder_open (&backlight_builder, G_VARIANT_TYPE ("aa{sv}"));
|
||||
|
||||
for (l = manager->monitors; l; l = l->next)
|
||||
{
|
||||
MetaMonitor *monitor = META_MONITOR (l->data);
|
||||
const char *connector;
|
||||
gboolean active;
|
||||
int value;
|
||||
|
||||
if (!meta_monitor_is_laptop_panel (monitor))
|
||||
continue;
|
||||
|
||||
g_variant_builder_open (&backlight_builder,
|
||||
G_VARIANT_TYPE_VARDICT);
|
||||
|
||||
connector = meta_monitor_get_connector (monitor);
|
||||
active = meta_monitor_is_active (monitor);
|
||||
g_variant_builder_add (&backlight_builder, "{sv}",
|
||||
"connector", g_variant_new_string (connector));
|
||||
g_variant_builder_add (&backlight_builder, "{sv}",
|
||||
"active", g_variant_new_boolean (active));
|
||||
|
||||
if (meta_monitor_get_backlight (monitor, &value))
|
||||
{
|
||||
int min, max;
|
||||
|
||||
meta_monitor_get_backlight_info (monitor, &min, &max);
|
||||
g_variant_builder_add (&backlight_builder, "{sv}",
|
||||
"min", g_variant_new_int32 (min));
|
||||
g_variant_builder_add (&backlight_builder, "{sv}",
|
||||
"max", g_variant_new_int32 (max));
|
||||
g_variant_builder_add (&backlight_builder, "{sv}",
|
||||
"value", g_variant_new_int32 (value));
|
||||
}
|
||||
|
||||
g_variant_builder_close (&backlight_builder);
|
||||
}
|
||||
|
||||
g_variant_builder_close (&backlight_builder);
|
||||
|
||||
backlight = g_variant_builder_end (&backlight_builder);
|
||||
|
||||
meta_dbus_display_config_set_backlight (manager->display_config,
|
||||
g_steal_pointer (&backlight));
|
||||
}
|
||||
|
||||
static void
|
||||
set_logical_monitor_modes (MetaMonitorManager *manager,
|
||||
MetaLogicalMonitorConfig *logical_monitor_config)
|
||||
|
|
|
@ -335,6 +335,23 @@ screen_cast_client = executable('mutter-screen-cast-client',
|
|||
install_rpath: pkglibdir,
|
||||
)
|
||||
|
||||
backlight_client = executable('monitor-backlight-client',
|
||||
sources: [
|
||||
'monitor-backlight-client.c',
|
||||
built_dbus_sources['meta-dbus-display-config'],
|
||||
],
|
||||
include_directories: tests_includes,
|
||||
c_args: [
|
||||
tests_c_args,
|
||||
'-DG_LOG_DOMAIN="mutter-monitor-backlight-test-client"',
|
||||
],
|
||||
dependencies: [
|
||||
gio_dep,
|
||||
],
|
||||
install: have_installed_tests,
|
||||
install_dir: mutter_installed_tests_libexecdir,
|
||||
)
|
||||
|
||||
input_capture_client = executable('mutter-input-capture-test-client',
|
||||
sources: [
|
||||
'input-capture-test-client.c',
|
||||
|
|
179
src/tests/monitor-backlight-client.c
Normal file
179
src/tests/monitor-backlight-client.c
Normal file
|
@ -0,0 +1,179 @@
|
|||
/*
|
||||
* Copyright (C) 2025 Red Hat, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <glib.h>
|
||||
#include <gio/gio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "meta-dbus-display-config.h"
|
||||
|
||||
static void
|
||||
backlight_changed_cb (MetaDBusDisplayConfig *proxy,
|
||||
GParamSpec *pspec,
|
||||
int *new_value)
|
||||
{
|
||||
GVariant *backlight_variant = NULL;
|
||||
uint32_t serial;
|
||||
g_autoptr (GVariant) backlights = NULL;
|
||||
g_autoptr (GVariant) backlight_monitor = NULL;
|
||||
int value;
|
||||
|
||||
backlight_variant = meta_dbus_display_config_get_backlight (proxy);
|
||||
g_variant_get (backlight_variant, "(u@aa{sv})",
|
||||
&serial, &backlights);
|
||||
g_variant_get_child (backlights, 0, "@a{sv}",
|
||||
&backlight_monitor);
|
||||
g_variant_lookup (backlight_monitor, "value", "i", &value);
|
||||
|
||||
*new_value = value;
|
||||
}
|
||||
|
||||
static void
|
||||
test_legacy_backlight (MetaDBusDisplayConfig *proxy)
|
||||
{
|
||||
g_autoptr (GVariant) resources_variant = NULL;
|
||||
g_autoptr (GError) error = NULL;
|
||||
unsigned int serial;
|
||||
g_autoptr (GVariant) crtcs = NULL;
|
||||
g_autoptr (GVariant) outputs = NULL;
|
||||
g_autoptr (GVariant) modes = NULL;
|
||||
int max_screen_width, max_screen_height;
|
||||
int output_id;
|
||||
g_autoptr (GVariant) output_properties = NULL;
|
||||
int normalized_backlight;
|
||||
gulong handler_id;
|
||||
int new_value = -1;
|
||||
|
||||
g_debug ("Running %s test", __func__);
|
||||
|
||||
meta_dbus_display_config_call_get_resources_sync (proxy,
|
||||
&serial,
|
||||
&crtcs,
|
||||
&outputs,
|
||||
&modes,
|
||||
&max_screen_width,
|
||||
&max_screen_height,
|
||||
NULL,
|
||||
&error);
|
||||
g_assert_no_error (error);
|
||||
|
||||
g_assert_cmpint (g_variant_n_children (outputs), ==, 2);
|
||||
|
||||
g_variant_get_child (outputs, 0,
|
||||
"(uxiausauau@a{sv})",
|
||||
&output_id,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
&output_properties);
|
||||
g_variant_lookup (output_properties,
|
||||
"backlight", "i",
|
||||
&normalized_backlight);
|
||||
g_assert_cmpint (normalized_backlight, >=, 0);
|
||||
g_assert_cmpint (normalized_backlight, <=, 100);
|
||||
|
||||
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
|
||||
meta_dbus_display_config_call_change_backlight_sync (proxy,
|
||||
serial,
|
||||
output_id,
|
||||
1,
|
||||
NULL,
|
||||
NULL, &error);
|
||||
G_GNUC_END_IGNORE_DEPRECATIONS
|
||||
|
||||
g_debug ("Checking denormalization");
|
||||
|
||||
handler_id = g_signal_connect (proxy, "notify::backlight",
|
||||
G_CALLBACK (backlight_changed_cb), &new_value);
|
||||
while (new_value == -1)
|
||||
g_main_context_iteration (NULL, TRUE);
|
||||
g_assert_cmpint (new_value, ==, 3);
|
||||
|
||||
g_signal_handler_disconnect (proxy, handler_id);
|
||||
}
|
||||
|
||||
static void
|
||||
test_set_backlight (MetaDBusDisplayConfig *proxy)
|
||||
{
|
||||
g_autoptr (GError) error = NULL;
|
||||
GVariant *backlight_variant;
|
||||
uint32_t serial;
|
||||
g_autoptr (GVariant) backlights = NULL;
|
||||
g_autoptr (GVariant) backlight_monitor = NULL;
|
||||
g_autofree char *connector = NULL;
|
||||
int min;
|
||||
int max;
|
||||
int value;
|
||||
gulong handler_id;
|
||||
int new_value = -1;
|
||||
|
||||
g_debug ("Running %s test", __func__);
|
||||
|
||||
backlight_variant = meta_dbus_display_config_get_backlight (proxy);
|
||||
g_variant_get (backlight_variant, "(u@aa{sv})",
|
||||
&serial, &backlights);
|
||||
g_variant_get_child (backlights, 0, "@a{sv}",
|
||||
&backlight_monitor);
|
||||
g_variant_lookup (backlight_monitor, "connector", "s", &connector);
|
||||
g_variant_lookup (backlight_monitor, "min", "i", &min);
|
||||
g_variant_lookup (backlight_monitor, "max", "i", &max);
|
||||
g_variant_lookup (backlight_monitor, "value", "i", &value);
|
||||
|
||||
g_assert_cmpint (min, ==, 0);
|
||||
g_assert_cmpint (max, ==, 300);
|
||||
|
||||
handler_id = g_signal_connect (proxy, "notify::backlight",
|
||||
G_CALLBACK (backlight_changed_cb), &new_value);
|
||||
meta_dbus_display_config_call_set_backlight_sync (proxy,
|
||||
serial,
|
||||
connector,
|
||||
value - 10,
|
||||
NULL, &error);
|
||||
g_assert_no_error (error);
|
||||
while (new_value == -1)
|
||||
g_main_context_iteration (NULL, TRUE);
|
||||
g_assert_cmpint (new_value, ==, value - 10);
|
||||
|
||||
g_signal_handler_disconnect (proxy, handler_id);
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc,
|
||||
char **argv)
|
||||
{
|
||||
g_autoptr (MetaDBusDisplayConfig) proxy = NULL;
|
||||
g_autoptr (GError) error = NULL;
|
||||
|
||||
proxy = meta_dbus_display_config_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION,
|
||||
G_DBUS_PROXY_FLAGS_NONE,
|
||||
"org.gnome.Mutter.DisplayConfig",
|
||||
"/org/gnome/Mutter/DisplayConfig",
|
||||
NULL, &error);
|
||||
g_assert_no_error (error);
|
||||
g_assert_nonnull (proxy);
|
||||
|
||||
test_set_backlight (proxy);
|
||||
test_legacy_backlight (proxy);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
|
@ -22,6 +22,8 @@
|
|||
#include "tests/meta-test/meta-context-test.h"
|
||||
#include "tests/meta-monitor-test-utils.h"
|
||||
|
||||
#include "meta-dbus-display-config.h"
|
||||
|
||||
static MonitorTestCaseSetup initial_test_case_setup = {
|
||||
.modes = {
|
||||
{
|
||||
|
@ -129,6 +131,62 @@ meta_test_backlight_sanity (void)
|
|||
g_assert_cmpint (output_info->backlight_max, ==, 0);
|
||||
}
|
||||
|
||||
static char *
|
||||
get_test_client_path (const char *test_client_name)
|
||||
{
|
||||
return g_test_build_filename (G_TEST_BUILT,
|
||||
test_client_name,
|
||||
NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
subprocess_wait_check_cb (GObject *source_object,
|
||||
GAsyncResult *res,
|
||||
gpointer user_data)
|
||||
{
|
||||
g_autoptr (GError) error = NULL;
|
||||
gboolean *exited = user_data;
|
||||
|
||||
g_assert_true (g_subprocess_wait_check_finish (G_SUBPROCESS (source_object),
|
||||
res,
|
||||
&error));
|
||||
g_assert_no_error (error);
|
||||
|
||||
*exited = TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
meta_test_backlight_api (void)
|
||||
{
|
||||
g_autoptr (GSubprocessLauncher) launcher = NULL;
|
||||
g_autoptr (GSubprocess) subprocess = NULL;
|
||||
g_autoptr (GError) error = NULL;
|
||||
g_autofree char *test_client_path = NULL;
|
||||
gboolean exited = FALSE;
|
||||
|
||||
launcher = g_subprocess_launcher_new (G_SUBPROCESS_FLAGS_NONE);
|
||||
g_subprocess_launcher_setenv (launcher,
|
||||
"G_MESSAGES_DEBUG", "all",
|
||||
TRUE);
|
||||
g_subprocess_launcher_setenv (launcher,
|
||||
"G_DEBUG", "fatal-warnings",
|
||||
TRUE);
|
||||
test_client_path = get_test_client_path ("monitor-backlight-client");
|
||||
subprocess =
|
||||
g_subprocess_launcher_spawn (launcher,
|
||||
&error,
|
||||
test_client_path,
|
||||
NULL);
|
||||
g_assert_no_error (error);
|
||||
g_assert_nonnull (subprocess);
|
||||
|
||||
g_subprocess_wait_check_async (subprocess, NULL,
|
||||
subprocess_wait_check_cb,
|
||||
&exited);
|
||||
while (!exited)
|
||||
g_main_context_iteration (NULL, TRUE);
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc,
|
||||
char *argv[])
|
||||
|
@ -143,6 +201,7 @@ main (int argc,
|
|||
|
||||
meta_init_monitor_test_setup (create_test_setup);
|
||||
g_test_add_func ("/backends/backlight/sanity", meta_test_backlight_sanity);
|
||||
g_test_add_func ("/backends/backlight/api", meta_test_backlight_api);
|
||||
|
||||
return meta_context_test_run_tests (META_CONTEXT_TEST (context),
|
||||
META_TEST_RUN_FLAG_NONE);
|
||||
|
|
Loading…
Reference in a new issue