kbd_backlight add device ok

This commit is contained in:
Kate Hsuan 2025-02-21 15:56:45 +08:00
parent c6a0748005
commit f82b7b501b
11 changed files with 1019 additions and 80 deletions

View file

@ -18,6 +18,8 @@ upshared += { 'linux': static_library('upshared',
'up-device-wup.h',
'up-device-bluez.c',
'up-device-bluez.h',
'up-kbd-backlight.c',
'up-kbd-backlight.h',
'up-input.c',
'up-input.h',
'up-backend.c',

View file

@ -433,13 +433,17 @@ up_device_disconnected_cb (GObject *gobject,
}
static void
udev_device_added_cb (UpBackend *backend, UpDevice *device)
udev_device_added_cb (UpBackend *backend, GObject *device)
{
g_debug ("Got new device from udev enumerator: %p", device);
g_signal_connect (device, "notify::disconnected",
G_CALLBACK (up_device_disconnected_cb), backend);
if (update_added_duplicate_device (backend, device))
if (UP_IS_DEVICE (device)) {
if (update_added_duplicate_device (backend, UP_DEVICE (device)))
g_signal_emit (backend, signals[SIGNAL_DEVICE_ADDED], 0, device);
} else {
g_signal_emit (backend, signals[SIGNAL_DEVICE_ADDED], 0, device);
}
}
static void
@ -775,7 +779,7 @@ up_backend_class_init (UpBackendClass *klass)
G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (UpBackendClass, device_added),
NULL, NULL, NULL,
G_TYPE_NONE, 1, UP_TYPE_DEVICE);
G_TYPE_NONE, 1, G_TYPE_OBJECT);
signals [SIGNAL_DEVICE_REMOVED] =
g_signal_new ("device-removed",
G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,

View file

@ -31,6 +31,7 @@
#include "up-device-supply-battery.h"
#include "up-device-hid.h"
#include "up-device-wup.h"
#include "up-kbd-backlight.h"
#ifdef HAVE_IDEVICE
#include "up-device-idevice.h"
#endif /* HAVE_IDEVICE */
@ -168,6 +169,8 @@ device_new (UpEnumeratorUdev *self, GUdevDevice *native)
native_path = g_udev_device_get_sysfs_path (native);
if (g_strrstr (native_path, "kbd_backlight") != NULL)
g_warning ("native path %s (%s) hit leds device", native_path, subsys);
return NULL;
} else {
native_path = g_udev_device_get_sysfs_path (native);
@ -216,19 +219,120 @@ emit_changes_for_siblings (UpEnumeratorUdev *self,
}
}
static void
power_supply_add_helper (UpEnumeratorUdev *self,
const gchar *action,
GUdevDevice *device,
GUdevClient *client,
GObject *obj,
char *device_key)
{
g_autoptr(UpDevice) up_dev = NULL;
g_autofree char *parent_id = NULL;
up_dev = device_new (self, device);
/* We work with `obj` further down, which is the UpDevice
* if we have it, or the GUdevDevice if not. */
if (up_dev)
obj = G_OBJECT (up_dev);
else
obj = G_OBJECT (device);
g_hash_table_insert (self->known, (char*) device_key, g_object_ref (obj));
/* Fire relevant sibling events and insert into lookup table */
parent_id = device_parent_id (device);
g_debug ("device %s has parent id: %s", device_key, parent_id);
if (parent_id) {
GPtrArray *devices = NULL;
char *parent_id_key = NULL;
int i;
g_hash_table_lookup_extended (self->siblings, parent_id,
(gpointer*)&parent_id_key, (gpointer*)&devices);
if (!devices)
devices = g_ptr_array_new_with_free_func (g_object_unref);
for (i = 0; i < devices->len; i++) {
GObject *sibling = g_ptr_array_index (devices, i);
if (up_dev) {
g_autoptr(GUdevDevice) d = get_latest_udev_device (self, sibling);
if (d)
up_device_sibling_discovered (up_dev, G_OBJECT (d));
}
if (UP_IS_DEVICE (sibling))
up_device_sibling_discovered (UP_DEVICE (sibling), obj);
}
g_ptr_array_add (devices, g_object_ref (obj));
if (!parent_id_key) {
parent_id_key = g_strdup (parent_id);
g_hash_table_insert (self->siblings, parent_id_key, devices);
}
/* Just a reference to the hash table key */
g_object_set_data (obj, "udev-parent-id", parent_id_key);
}
if (up_dev)
g_signal_emit_by_name (self, "device-added", up_dev);
}
static void
kbd_backlight_add_helper (UpEnumeratorUdev *self,
const gchar *action,
GUdevDevice *device,
GUdevClient *client,
GObject *obj,
char *device_key)
{
UpDaemon *daemon;
g_autoptr(UpDeviceKbdBacklight) up_dev = NULL;
g_autofree char *parent_id = NULL;
daemon = up_enumerator_get_daemon (UP_ENUMERATOR (self));
g_debug ("KBD new");
up_dev = g_initable_new (UP_TYPE_KBD_BACKLIGHT, NULL, NULL,
"daemon", daemon,
"native", device,
NULL);
/* We work with `obj` further down, which is the UpDevice
* if we have it, or the GUdevDevice if not. */
if (up_dev)
obj = G_OBJECT (up_dev);
else
obj = G_OBJECT (device);
g_hash_table_insert (self->known, (char*) device_key, g_object_ref (obj));
g_debug ("KBD add emit");
if (up_dev)
g_signal_emit_by_name (self, "device-added", G_OBJECT (up_dev));
}
static void
uevent_signal_handler_cb (UpEnumeratorUdev *self,
const gchar *action,
GUdevDevice *device,
GUdevClient *client)
const gchar *action,
GUdevDevice *device,
GUdevClient *client)
{
const char *device_key = g_udev_device_get_sysfs_path (device);
gboolean is_kbd_backlight = FALSE;
g_debug ("Received uevent %s on device %s", action, device_key);
/* Work around the fact that we don't get a REMOVE event in some cases. */
if (g_strcmp0 (g_udev_device_get_subsystem (device), "power_supply") == 0)
device_key = g_udev_device_get_name (device);
else if (g_strcmp0 (g_udev_device_get_subsystem (device), "leds") == 0) {
if (g_strrstr (device_key, "kbd_backlight") == NULL)
return;
is_kbd_backlight = TRUE;
}
g_debug ("uevent subsystem %s", g_udev_device_get_subsystem (device));
/* It appears that we may not always receive an "add" event. As such,
* treat "add"/"change" in the same way, by first checking if we have
@ -250,57 +354,13 @@ uevent_signal_handler_cb (UpEnumeratorUdev *self,
}
if (!obj) {
g_autoptr(UpDevice) up_dev = NULL;
g_autofree char *parent_id = NULL;
up_dev = device_new (self, device);
/* We work with `obj` further down, which is the UpDevice
* if we have it, or the GUdevDevice if not. */
if (up_dev)
obj = G_OBJECT (up_dev);
else
obj = G_OBJECT (device);
g_hash_table_insert (self->known, (char*) device_key, g_object_ref (obj));
/* Fire relevant sibling events and insert into lookup table */
parent_id = device_parent_id (device);
g_debug ("device %s has parent id: %s", device_key, parent_id);
if (parent_id) {
GPtrArray *devices = NULL;
char *parent_id_key = NULL;
int i;
g_hash_table_lookup_extended (self->siblings, parent_id,
(gpointer*)&parent_id_key, (gpointer*)&devices);
if (!devices)
devices = g_ptr_array_new_with_free_func (g_object_unref);
for (i = 0; i < devices->len; i++) {
GObject *sibling = g_ptr_array_index (devices, i);
if (up_dev) {
g_autoptr(GUdevDevice) d = get_latest_udev_device (self, sibling);
if (d)
up_device_sibling_discovered (up_dev, G_OBJECT (d));
}
if (UP_IS_DEVICE (sibling))
up_device_sibling_discovered (UP_DEVICE (sibling), obj);
}
g_ptr_array_add (devices, g_object_ref (obj));
if (!parent_id_key) {
parent_id_key = g_strdup (parent_id);
g_hash_table_insert (self->siblings, parent_id_key, devices);
}
/* Just a reference to the hash table key */
g_object_set_data (obj, "udev-parent-id", parent_id_key);
if (is_kbd_backlight) {
g_debug ("uevent KDB backlight add.");
kbd_backlight_add_helper (self, action, device, client, obj, device_key);
} else {
power_supply_add_helper (self, action, device, client, obj, device_key);
}
if (up_dev)
g_signal_emit_by_name (self, "device-added", up_dev);
} else {
if (!UP_IS_DEVICE (obj)) {
g_autoptr(GUdevDevice) d = get_latest_udev_device (self, obj);

View file

@ -0,0 +1,277 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
*
* Copyright (C) 2025 Kate Hsuan <p.hsuan@gmail.com>
*
* Licensed under the GNU General Public License Version 2
*
* 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, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "config.h"
#include <glib.h>
#include <glib/gi18n.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <dirent.h>
#include <errno.h>
#include "up-kbd-backlight.h"
#include "up-daemon.h"
#include "up-native.h"
#include "up-types.h"
static void up_kbd_backlight_finalize (GObject *object);
struct UpKbdBacklightPrivate
{
gint max_brightness;
guint brightness;
};
G_DEFINE_TYPE_WITH_PRIVATE (UpKbdBacklight, up_kbd_backlight, UP_TYPE_DEVICE_KBD_BACKLIGHT)
/**
* up_kbd_backlight_emit_change:
**/
static void
up_kbd_backlight_emit_change(UpKbdBacklight *kbd_backlight, int value, const char *source)
{
up_exported_kbd_backlight_emit_brightness_changed (UP_EXPORTED_KBD_BACKLIGHT (kbd_backlight), value);
up_exported_kbd_backlight_emit_brightness_changed_with_source (UP_EXPORTED_KBD_BACKLIGHT (kbd_backlight), value, source);
}
/**
* up_kbd_backlight_brightness_write:
**/
static gboolean
up_kbd_backlight_brightness_write (UpDeviceKbdBacklight *kbd_backlight, const gchar *native_path, gint value)
{
UpKbdBacklight *kbd;
UpKbdBacklightPrivate *priv;
g_autoptr (GString) value_str = g_string_new (NULL);
g_return_val_if_fail (UP_IS_DEVICE_KBD_BACKLIGHT (kbd_backlight), FALSE);
kbd = UP_KBD_BACKLIGHT (kbd_backlight);
priv = up_kbd_backlight_get_instance_private (kbd);
g_string_printf (value_str, "%d", CLAMP (value, 0, priv->max_brightness));
if (!g_file_set_contents_full (native_path, value_str->str, value_str->len,
G_FILE_SET_CONTENTS_ONLY_EXISTING, 0644, NULL))
return FALSE;
return TRUE;
}
/**
* up_kbd_backlight_brightness_read:
**/
static gint
up_kbd_backlight_brightness_read (UpDeviceKbdBacklight *kbd_backlight, const gchar *native_path)
{
GObject *native = NULL;
g_autofree gchar *buf = NULL;
gint64 brightness = -1;
g_return_val_if_fail (UP_IS_DEVICE_KBD_BACKLIGHT (kbd_backlight), brightness);
if (!g_file_get_contents (native_path, &buf, NULL, NULL))
return -1;
brightness = g_ascii_strtoll (buf, NULL, 10);
if (brightness < 0) {
g_warning ("failed to convert brightness: %s", buf);
return -1;
}
return brightness;
}
/**
* up_kbd_backlight_set_brightness:
**/
static gboolean
up_kbd_backlight_set_brightness (UpDeviceKbdBacklight *kbd_backlight, gint value)
{
GObject *native;
g_autofree gchar *filename = NULL;
const gchar *native_path;
gboolean ret = FALSE;
native = up_device_kbd_backlight_get_native (UP_DEVICE_KBD_BACKLIGHT (kbd_backlight));
g_return_val_if_fail (native != NULL, FALSE);
native_path = up_native_get_native_path (native);
g_return_val_if_fail (native_path != NULL, FALSE);
filename = g_build_filename (native_path, "brightness", NULL);
g_debug ("setting brightness to %i", value);
ret = up_kbd_backlight_brightness_write (kbd_backlight, filename, value);
return ret;
}
/**
* up_kbd_backlight_get_brightness:
*
* Gets the current brightness
**/
static gint
up_kbd_backlight_get_brightness (UpDeviceKbdBacklight *kbd_backlight)
{
GObject *native;
const gchar *native_path;
g_autofree gchar *filename = NULL;
gint brightness = -1;
native = up_device_kbd_backlight_get_native (UP_DEVICE_KBD_BACKLIGHT (kbd_backlight));
g_return_val_if_fail (native != NULL, brightness);
native_path = up_native_get_native_path (native);
g_return_val_if_fail (native_path != NULL, brightness);
filename = g_build_filename (native_path, "brightness", NULL);
brightness = up_kbd_backlight_brightness_read (kbd_backlight, filename);
return brightness;
}
/**
* up_kbd_backlight_get_max_brightness:
*
* Gets the max brightness
**/
static gint
up_kbd_backlight_get_max_brightness (UpDeviceKbdBacklight *kbd_backlight)
{
UpKbdBacklight *kbd = UP_KBD_BACKLIGHT (kbd_backlight);
UpKbdBacklightPrivate *priv = up_kbd_backlight_get_instance_private (kbd);
return priv->max_brightness;
}
/**
* up_kbd_backlight_coldplug:
*
* Initial max brightness
**/
static gboolean
up_kbd_backlight_coldplug (UpDeviceKbdBacklight *kbd_backlight)
{
UpKbdBacklight *kbd;
UpKbdBacklightPrivate *priv;
GObject *native;
g_autofree gchar *filename = NULL;
const gchar *native_path = NULL;
g_return_val_if_fail (UP_IS_DEVICE_KBD_BACKLIGHT (kbd_backlight), FALSE);
kbd = UP_KBD_BACKLIGHT (kbd_backlight);
priv = up_kbd_backlight_get_instance_private (kbd);
native = up_device_kbd_backlight_get_native (kbd_backlight);
if (native == NULL) {
priv->max_brightness = 0;
return FALSE;
}
g_debug ("coldplug kbd backlight");
native_path = up_native_get_native_path (native);
filename = g_build_filename (native_path, "max_brightness", NULL);
g_debug ("LED Max brightness path %s", filename);
priv->max_brightness = up_kbd_backlight_brightness_read (kbd_backlight, filename);
return TRUE;
}
/**
* up_kbd_backlight_finalize:
**/
static void
up_kbd_backlight_finalize (GObject *object)
{
UpKbdBacklight *kbd_backlight;
#if 0
g_return_if_fail (object != NULL);
g_return_if_fail (UP_IS_KBD_BACKLIGHT (object));
kbd_backlight = UP_KBD_BACKLIGHT (object);
kbd_backlight->priv = up_kbd_backlight_get_instance_private (kbd_backlight);
if (kbd_backlight->priv->channel_hw_changed) {
g_io_channel_shutdown (kbd_backlight->priv->channel_hw_changed, FALSE, NULL);
g_io_channel_unref (kbd_backlight->priv->channel_hw_changed);
}
if (kbd_backlight->priv->fd_hw_changed >= 0)
close (kbd_backlight->priv->fd_hw_changed);
/* close file */
if (kbd_backlight->priv->fd >= 0)
close (kbd_backlight->priv->fd);
G_OBJECT_CLASS (up_kbd_backlight_parent_class)->finalize (object);
#endif
}
/**
* up_kbd_backlight_class_init:
**/
static void
up_kbd_backlight_class_init (UpKbdBacklightClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
UpDeviceKbdBacklightClass *dev_kbd_klass = UP_DEVICE_KBD_BACKLIGHT_CLASS (klass);
object_class->finalize = up_kbd_backlight_finalize;
dev_kbd_klass->coldplug = up_kbd_backlight_coldplug;
dev_kbd_klass->get_max_brightness = up_kbd_backlight_get_max_brightness;
dev_kbd_klass->get_brightness = up_kbd_backlight_get_brightness;
dev_kbd_klass->set_brightness = up_kbd_backlight_set_brightness;
}
/**
* up_kbd_backlight_init:
**/
static void
up_kbd_backlight_init (UpKbdBacklight *kbd_backlight)
{
UpKbdBacklightPrivate *priv = up_kbd_backlight_get_instance_private (kbd_backlight);
kbd_backlight->priv = up_kbd_backlight_get_instance_private (kbd_backlight);
}
/**
* up_kbd_backlight_new:
**/
UpKbdBacklight *
up_kbd_backlight_new (void)
{
return g_object_new (UP_TYPE_KBD_BACKLIGHT, NULL);
}

View file

@ -0,0 +1,55 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
*
* Copyright (C) 2025 Kate Hsuan <p.hsuan@gmail.com>
*
* Licensed under the GNU General Public License Version 2
*
* 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, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef __UP_KBD_BACKLIGHT_H
#define __UP_KBD_BACKLIGHT_H
#include <glib-object.h>
#include "up-device-kbd-backlight.h"
G_BEGIN_DECLS
#define UP_TYPE_KBD_BACKLIGHT (up_kbd_backlight_get_type ())
#define UP_KBD_BACKLIGHT(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), UP_TYPE_KBD_BACKLIGHT, UpKbdBacklight))
#define UP_KBD_BACKLIGHT_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), UP_TYPE_KBD_BACKLIGHT, UpKbdBacklightClass))
#define UP_IS_KBD_BACKLIGHT(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), UP_TYPE_KBD_BACKLIGHT))
#define UP_IS_KBD_BACKLIGHT_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), UP_TYPE_KBD_BACKLIGHT))
#define UP_KBD_BACKLIGHT_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), UP_TYPE_KBD_BACKLIGHT, UpKbdBacklightClass))
typedef struct UpKbdBacklightPrivate UpKbdBacklightPrivate;
typedef struct
{
UpDeviceKbdBacklight parent;
UpKbdBacklightPrivate *priv;
} UpKbdBacklight;
typedef struct
{
UpDeviceKbdBacklightClass parent_class;
} UpKbdBacklightClass;
UpKbdBacklight *up_kbd_backlight_new (void);
GType up_kbd_backlight_get_type (void);
G_END_DECLS
#endif /* __UP_KBD_BACKLIGHT_H */

View file

@ -38,8 +38,8 @@ upowerd_private = static_library('upowerd-private',
'up-device-list.c',
'up-enumerator.c',
'up-enumerator.h',
'up-kbd-backlight.h',
'up-kbd-backlight.c',
'up-device-kbd-backlight.h',
'up-device-kbd-backlight.c',
'up-history.h',
'up-history.c',
'up-backend.h',

View file

@ -33,6 +33,7 @@
#include "up-polkit.h"
#include "up-device-list.h"
#include "up-device.h"
#include "up-device-kbd-backlight.h"
#include "up-backend.h"
#include "up-daemon.h"
@ -43,6 +44,7 @@ struct UpDaemonPrivate
UpPolkit *polkit;
UpBackend *backend;
UpDeviceList *power_devices;
UpDeviceList *kbd_backlight_devices;
guint action_timeout_id;
guint refresh_batteries_id;
guint warning_level_id;
@ -582,6 +584,7 @@ up_daemon_shutdown (UpDaemon *daemon)
/* forget about discovered devices */
up_device_list_clear (daemon->priv->power_devices);
up_device_list_clear (daemon->priv->kbd_backlight_devices);
/* release UpDaemon reference */
g_object_run_dispose (G_OBJECT (daemon->priv->display_device));
@ -1015,35 +1018,52 @@ up_daemon_get_env_override (UpDaemon *self)
* up_daemon_device_added_cb:
**/
static void
up_daemon_device_added_cb (UpBackend *backend, UpDevice *device, UpDaemon *daemon)
up_daemon_device_added_cb (UpBackend *backend, GObject *device, UpDaemon *daemon)
{
const gchar *object_path;
UpDaemonPrivate *priv = daemon->priv;
g_return_if_fail (UP_IS_DAEMON (daemon));
g_return_if_fail (UP_IS_DEVICE (device));
g_return_if_fail (UP_IS_DEVICE (device) || UP_IS_DEVICE_KBD_BACKLIGHT (device));
/* add to device list */
up_device_list_insert (priv->power_devices, device);
g_warning ("daemon device added");
/* connect, so we get changes */
g_signal_connect (device, "notify",
G_CALLBACK (up_daemon_device_changed_cb), daemon);
if (UP_IS_DEVICE (device)) {
/* power_supply */
/* add to device list */
up_device_list_insert (priv->power_devices, device);
/* emit */
object_path = up_device_get_object_path (device);
if (object_path == NULL) {
g_debug ("Device %s was unregistered before it was on the bus",
up_exported_device_get_native_path (UP_EXPORTED_DEVICE (device)));
return;
/* connect, so we get changes */
g_signal_connect (device, "notify",
G_CALLBACK (up_daemon_device_changed_cb), daemon);
/* emit */
object_path = up_device_get_object_path (UP_DEVICE (device));
if (object_path == NULL) {
g_debug ("Device %s was unregistered before it was on the bus",
up_exported_device_get_native_path (UP_EXPORTED_DEVICE (device)));
return;
}
/* Ensure we poll the new device if needed */
g_source_set_ready_time (daemon->priv->poll_source, 0);
g_debug ("emitting added: %s", object_path);
up_daemon_update_warning_level (daemon);
up_exported_daemon_emit_device_added (UP_EXPORTED_DAEMON (daemon), object_path);
} else {
/*leds*/
g_debug ("Add a leds to list");
/* emit */
object_path = up_device_kbd_backlight_get_object_path (UP_DEVICE_KBD_BACKLIGHT (device));
if (object_path == NULL) {
g_debug ("Device %s was unregistered before it was on the bus",
up_exported_kbd_backlight_get_native_path (UP_EXPORTED_KBD_BACKLIGHT (device)));
return;
}
up_device_list_insert (priv->kbd_backlight_devices, G_OBJECT (device));
up_exported_daemon_emit_device_added (UP_EXPORTED_DAEMON (daemon), object_path);
}
/* Ensure we poll the new device if needed */
g_source_set_ready_time (daemon->priv->poll_source, 0);
g_debug ("emitting added: %s", object_path);
up_daemon_update_warning_level (daemon);
up_exported_daemon_emit_device_added (UP_EXPORTED_DAEMON (daemon), object_path);
}
/**
@ -1135,6 +1155,7 @@ up_daemon_init (UpDaemon *daemon)
daemon->priv->polkit = up_polkit_new ();
daemon->priv->config = up_config_new ();
daemon->priv->power_devices = up_device_list_new ();
daemon->priv->kbd_backlight_devices = up_device_list_new ();
daemon->priv->display_device = up_device_new (daemon, NULL);
daemon->priv->poll_source = g_source_new (&poll_source_funcs, sizeof (GSource));
@ -1219,6 +1240,7 @@ up_daemon_finalize (GObject *object)
g_clear_pointer (&daemon->priv->poll_source, g_source_destroy);
g_object_unref (priv->power_devices);
g_object_unref (priv->kbd_backlight_devices);
g_object_unref (priv->display_device);
g_object_unref (priv->polkit);
g_object_unref (priv->config);

View file

@ -0,0 +1,439 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
*
* Copyright (C) 2025 Kate Hsuan <hpa@redhat.com>
*
* 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, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#include "config.h"
#include <string.h>
#include <glib.h>
#include <glib/gstdio.h>
#include <glib/gi18n-lib.h>
#include <glib-object.h>
#include "up-native.h"
#include "up-device.h"
#include "up-device-kbd-backlight.h"
#include "up-history.h"
#include "up-history-item.h"
#include "up-stats-item.h"
typedef struct
{
UpDaemon *daemon;
/* native == NULL implies display device */
GObject *native;
gint fd_hw_changed;
GIOChannel *channel_hw_changed;
} UpDeviceKbdBacklightPrivate;
static void up_device_kbd_backlight_initable_iface_init (GInitableIface *iface);
G_DEFINE_TYPE_EXTENDED (UpDeviceKbdBacklight, up_device_kbd_backlight, UP_TYPE_EXPORTED_KBD_BACKLIGHT_SKELETON, 0,
G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE,
up_device_kbd_backlight_initable_iface_init)
G_ADD_PRIVATE (UpDeviceKbdBacklight))
enum {
PROP_0,
PROP_DAEMON,
PROP_NATIVE,
N_PROPS
};
#define UP_DEVICES_KBD_BACKLIGHT_DBUS_PATH "/org/freedesktop/UPower/KbdBacklight"
static GParamSpec *properties[N_PROPS];
/**
* up_kbd_backlight_emit_change:
**/
static void
up_kbd_backlight_emit_change(UpDeviceKbdBacklight *kbd_backlight, int value, const char *source)
{
up_exported_kbd_backlight_emit_brightness_changed (UP_EXPORTED_KBD_BACKLIGHT (kbd_backlight), value);
up_exported_kbd_backlight_emit_brightness_changed_with_source (UP_EXPORTED_KBD_BACKLIGHT (kbd_backlight), value, source);
}
/**
* up_kbd_backlight_get_brightness:
*
* Gets the current brightness
**/
static gboolean
up_kbd_backlight_get_brightness (UpExportedKbdBacklight *skeleton,
GDBusMethodInvocation *invocation,
UpDeviceKbdBacklight *kbd_backlight)
{
UpDeviceKbdBacklightClass *klass;
gint brightness = 0;
g_return_val_if_fail (UP_IS_DEVICE_KBD_BACKLIGHT (kbd_backlight), FALSE);
klass = UP_DEVICE_KBD_BACKLIGHT_GET_CLASS (kbd_backlight);
brightness = klass->get_brightness (kbd_backlight);
if (brightness >= 0) {
up_exported_kbd_backlight_complete_get_brightness (skeleton, invocation,
brightness);
} else {
g_dbus_method_invocation_return_error (invocation,
UP_DAEMON_ERROR, UP_DAEMON_ERROR_GENERAL,
"error reading brightness");
}
return TRUE;
}
/**
* up_kbd_backlight_get_max_brightness:
*
* Gets the max brightness
**/
static gboolean
up_kbd_backlight_get_max_brightness (UpExportedKbdBacklight *skeleton,
GDBusMethodInvocation *invocation,
UpDeviceKbdBacklight *kbd_backlight)
{
UpDeviceKbdBacklightClass *klass;
gint brightness = -1;
g_return_val_if_fail (UP_IS_DEVICE_KBD_BACKLIGHT (kbd_backlight), FALSE);
klass = UP_DEVICE_KBD_BACKLIGHT_GET_CLASS (kbd_backlight);
if (klass->get_max_brightness != NULL)
brightness = klass->get_max_brightness (kbd_backlight);
if (brightness >= 0) {
up_exported_kbd_backlight_complete_get_max_brightness (skeleton, invocation,
brightness);
} else {
g_dbus_method_invocation_return_error (invocation,
UP_DAEMON_ERROR, UP_DAEMON_ERROR_GENERAL,
"error reading brightness");
}
return TRUE;
}
/**
* up_kbd_backlight_set_brightness:
**/
static gboolean
up_kbd_backlight_set_brightness (UpExportedKbdBacklight *skeleton,
GDBusMethodInvocation *invocation,
gint value,
UpDeviceKbdBacklight *kbd_backlight)
{
UpDeviceKbdBacklightClass *klass;
gboolean ret = FALSE;
g_return_val_if_fail (UP_IS_DEVICE_KBD_BACKLIGHT (kbd_backlight), FALSE);
klass = UP_DEVICE_KBD_BACKLIGHT_GET_CLASS (kbd_backlight);
if (klass->set_brightness == NULL) {
g_dbus_method_invocation_return_error (invocation,
UP_DAEMON_ERROR, UP_DAEMON_ERROR_GENERAL,
"setting brightness is unsupported");
return TRUE;
}
ret = klass->set_brightness (kbd_backlight, value);
if (ret) {
up_exported_kbd_backlight_complete_set_brightness (skeleton, invocation);
up_kbd_backlight_emit_change (kbd_backlight, value, "external");
} else {
g_dbus_method_invocation_return_error (invocation,
UP_DAEMON_ERROR, UP_DAEMON_ERROR_GENERAL,
"error writing brightness %d", value);
}
return TRUE;
}
GObject *
up_device_kbd_backlight_get_native (UpDeviceKbdBacklight *device)
{
UpDeviceKbdBacklightPrivate *priv = up_device_kbd_backlight_get_instance_private (device);
g_return_val_if_fail (UP_IS_DEVICE_KBD_BACKLIGHT (device), NULL);
return priv->native;
}
static gchar *
up_device_kbd_backlight_compute_object_path (UpDeviceKbdBacklight *device)
{
UpDeviceKbdBacklightPrivate *priv = up_device_kbd_backlight_get_instance_private (device);
gchar *basename;
gchar *id;
gchar *object_path;
const gchar *native_path;
guint i;
if (priv->native == NULL) {
return g_build_filename (UP_DEVICES_KBD_BACKLIGHT_DBUS_PATH, "KbdBacklight", NULL);
}
native_path = up_exported_kbd_backlight_get_native_path (UP_EXPORTED_KBD_BACKLIGHT (device));
basename = g_path_get_basename (native_path);
id = g_strjoin ("_", basename, NULL);
/* make DBUS valid path */
for (i=0; id[i] != '\0'; i++) {
if (id[i] == '-')
id[i] = '_';
if (id[i] == '.')
id[i] = 'x';
if (id[i] == ':')
id[i] = 'o';
if (id[i] == '@')
id[i] = '_';
}
object_path = g_build_filename (UP_DEVICES_KBD_BACKLIGHT_DBUS_PATH, id, NULL);
g_free (basename);
g_free (id);
return object_path;
}
static void
up_device_kbd_backlight_export_skeleton (UpDeviceKbdBacklight *device,
const gchar *object_path)
{
UpDeviceKbdBacklightPrivate *priv = up_device_kbd_backlight_get_instance_private (device);
GError *error = NULL;
g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (device),
g_dbus_interface_skeleton_get_connection (G_DBUS_INTERFACE_SKELETON (priv->daemon)),
object_path,
&error);
if (error != NULL) {
g_critical ("error registering device on system bus: %s", error->message);
g_error_free (error);
}
}
gboolean
up_device_kbd_backlight_register (UpDeviceKbdBacklight *device)
{
g_autofree char *computed_object_path = NULL;
if (g_dbus_interface_skeleton_get_object_path (G_DBUS_INTERFACE_SKELETON (device)) != NULL)
return FALSE;
computed_object_path = up_device_kbd_backlight_compute_object_path (device);
g_debug ("Exported UpDevice with path %s", computed_object_path);
up_device_kbd_backlight_export_skeleton (device, computed_object_path);
return TRUE;
}
const gchar *
up_device_kbd_backlight_get_object_path (UpDeviceKbdBacklight *device)
{
g_return_val_if_fail (UP_IS_DEVICE_KBD_BACKLIGHT (device), NULL);
return g_dbus_interface_skeleton_get_object_path (G_DBUS_INTERFACE_SKELETON (device));
}
static void
up_device_kbd_backlight_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
UpDeviceKbdBacklight *device = UP_DEVICE_KBD_BACKLIGHT (object);
UpDeviceKbdBacklightPrivate *priv = up_device_kbd_backlight_get_instance_private (device);
g_debug ("kbd property set");
switch (prop_id)
{
case PROP_DAEMON:
priv->daemon = g_value_dup_object (value);
break;
case PROP_NATIVE:
g_debug ("Set kbd native");
priv->native = g_value_dup_object (value);
if (priv->native == NULL)
g_warning ("KBD native is NULL");
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static void
up_device_kbd_backlight_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
UpDeviceKbdBacklight *device = UP_DEVICE_KBD_BACKLIGHT (object);
UpDeviceKbdBacklightPrivate *priv = up_device_kbd_backlight_get_instance_private (device);
return;
switch (prop_id)
{
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static gboolean
up_device_kbd_backlight_initable_init (GInitable *initable,
GCancellable *cancellable,
GError **error)
{
UpDeviceKbdBacklight *device = UP_DEVICE_KBD_BACKLIGHT (initable);
UpDeviceKbdBacklightPrivate *priv = up_device_kbd_backlight_get_instance_private (device);
const gchar *native_path = "KbdDevice";
UpDeviceKbdBacklightClass *klass = UP_DEVICE_KBD_BACKLIGHT_GET_CLASS (device);
int ret;
g_return_val_if_fail (UP_IS_DEVICE_KBD_BACKLIGHT (device), FALSE);
if (priv->native) {
native_path = up_native_get_native_path (priv->native);
up_exported_kbd_backlight_set_native_path (UP_EXPORTED_KBD_BACKLIGHT (device), native_path);
}
/* coldplug source */
if (klass->coldplug != NULL) {
ret = klass->coldplug (device);
if (!ret) {
g_debug ("failed to coldplug %s", native_path);
g_propagate_error (error, g_error_new (G_IO_ERROR, G_IO_ERROR_FAILED,
"Failed to coldplug %s", native_path));
return FALSE;
}
}
register_device:
/* put on the bus */
up_device_kbd_backlight_register (device);
return TRUE;
}
static void
up_device_kbd_backlight_initable_iface_init (GInitableIface *iface)
{
iface->init = up_device_kbd_backlight_initable_init;
}
/**
* up_kbd_backlight_init:
**/
static void
up_device_kbd_backlight_init (UpDeviceKbdBacklight *kbd_backlight)
{
//kbd_backlight->priv = up_device_kbd_backlight_get_instance_private (kbd_backlight);
g_signal_connect (kbd_backlight, "handle-get-brightness",
G_CALLBACK (up_kbd_backlight_get_brightness), kbd_backlight);
g_signal_connect (kbd_backlight, "handle-get-max-brightness",
G_CALLBACK (up_kbd_backlight_get_max_brightness), kbd_backlight);
g_signal_connect (kbd_backlight, "handle-set-brightness",
G_CALLBACK (up_kbd_backlight_set_brightness), kbd_backlight);
}
/**
* up_kbd_backlight_finalize:
**/
static void
up_device_kbd_backlight_finalize (GObject *object)
{
UpDeviceKbdBacklight *kbd_backlight = NULL;
UpDeviceKbdBacklightPrivate *priv = up_device_kbd_backlight_get_instance_private (kbd_backlight);
g_return_if_fail (object != NULL);
g_return_if_fail (UP_IS_DEVICE_KBD_BACKLIGHT (object));
kbd_backlight = UP_DEVICE_KBD_BACKLIGHT (object);
//kbd_backlight->priv = up_device_kbd_backlight_get_instance_private (kbd_backlight);
//if (kbd_backlight->priv->channel_hw_changed) {
// g_io_channel_shutdown (kbd_backlight->priv->channel_hw_changed, FALSE, NULL);
// g_io_channel_unref (kbd_backlight->priv->channel_hw_changed);
//}
//if (kbd_backlight->priv->fd_hw_changed >= 0)
// close (kbd_backlight->priv->fd_hw_changed);
/* close file */
//if (kbd_backlight->priv->fd >= 0)
// close (kbd_backlight->priv->fd);
G_OBJECT_CLASS (up_device_kbd_backlight_parent_class)->finalize (object);
}
static void
up_device_kbd_backlight_class_init (UpDeviceKbdBacklightClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
//object_class->notify = up_device_notify;
object_class->finalize = up_device_kbd_backlight_finalize;
//object_class->dispose = up_device_dispose;
object_class->set_property = up_device_kbd_backlight_set_property;
object_class->get_property = up_device_kbd_backlight_get_property;
properties[PROP_DAEMON] =
g_param_spec_object ("daemon",
"UpDaemon",
"UpDaemon reference",
UP_TYPE_DAEMON,
G_PARAM_STATIC_STRINGS | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY);
properties[PROP_NATIVE] =
g_param_spec_object ("native",
"Native",
"Native Object",
G_TYPE_OBJECT,
G_PARAM_STATIC_STRINGS | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY);
g_object_class_install_properties (object_class, N_PROPS, properties);
}
/**
* up_kbd_backlight_new:
**/
UpDeviceKbdBacklight *
up_device_kbd_backlight_new (UpDaemon *daemon, GObject *native)
{
return UP_DEVICE_KBD_BACKLIGHT (g_object_new (UP_TYPE_DEVICE_KBD_BACKLIGHT,
"daemon", daemon,
"native", native,
NULL));
}

View file

@ -0,0 +1,77 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
*
* Copyright (C) 2025 Kate Hsuan <hpa@redhat.com>
*
* 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, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#ifndef __UP_DEVICE_KBD_BACKLIGHT_H__
#define __UP_DEVICE_KBD_BACKLIGHT_H__
#include <dbus/up-kbd-backlight-generated.h>
#include "up-daemon.h"
G_BEGIN_DECLS
#define UP_TYPE_DEVICE_KBD_BACKLIGHT (up_device_kbd_backlight_get_type ())
G_DECLARE_DERIVABLE_TYPE (UpDeviceKbdBacklight, up_device_kbd_backlight, UP, DEVICE_KBD_BACKLIGHT, UpExportedKbdBacklightSkeleton)
struct _UpDeviceKbdBacklightClass
{
UpExportedKbdBacklightSkeletonClass parent_class;
/* vtable */
gboolean (*coldplug) (UpDeviceKbdBacklight *device);
gint (*get_max_brightness) (UpDeviceKbdBacklight *device);
gint (*get_brightness) (UpDeviceKbdBacklight *device);
gboolean (*set_brightness) (UpDeviceKbdBacklight *device, gint brightness);
};
GType up_device_kbd_backlight_get_type (void);
const gchar * up_device_kbd_backlight_get_object_path (UpDeviceKbdBacklight *device);
GObject * up_device_kbd_backlight_get_native (UpDeviceKbdBacklight *device);
UpDeviceKbdBacklight *up_device_kbd_backlight_new (UpDaemon *daemon,
GObject *native);
gboolean up_device_kbd_backlight_register (UpDeviceKbdBacklight *device);
#if 0
UpDaemon *up_device_get_daemon (UpDevice *device);
GObject *up_device_get_native (UpDevice *device);
const gchar *up_device_get_object_path (UpDevice *device);
gboolean up_device_get_online (UpDevice *device,
gboolean *online);
const gchar *up_device_get_state_dir_override (UpDevice *device);
gboolean up_device_polkit_is_allowed (UpDevice *device,
GDBusMethodInvocation *invocation);
void up_device_sibling_discovered (UpDevice *device,
GObject *sibling);
gboolean up_device_refresh_internal (UpDevice *device,
UpRefreshReason reason);
void up_device_unregister (UpDevice *device);
gboolean up_device_is_registered (UpDevice *device);
#endif
G_END_DECLS
#endif /* __UP_DEVICE_KBD_BACKLIGHT_H__ */

View file

@ -28,6 +28,7 @@
#include "up-native.h"
#include "up-device-list.h"
#include "up-device.h"
#include "up-device-kbd-backlight.h"
static void up_device_list_finalize (GObject *object);
@ -80,7 +81,10 @@ up_device_list_insert (UpDeviceList *list, gpointer device)
g_return_val_if_fail (UP_IS_DEVICE_LIST (list), FALSE);
g_return_val_if_fail (device != NULL, FALSE);
native = up_device_get_native (UP_DEVICE (device));
if (UP_IS_DEVICE_KBD_BACKLIGHT (device))
native = up_device_kbd_backlight_get_native (UP_DEVICE_KBD_BACKLIGHT (device));
else
native = up_device_get_native (UP_DEVICE (device));
g_return_val_if_fail (native != NULL, FALSE);
native_path = up_native_get_native_path (native);

View file

@ -62,7 +62,6 @@ up_state_new (void)
{
UpState *state = g_new0 (UpState, 1);
state->kbd_backlight = up_kbd_backlight_new ();
state->daemon = up_daemon_new ();
state->loop = g_main_loop_new (NULL, FALSE);
@ -79,7 +78,7 @@ up_main_bus_acquired (GDBusConnection *connection,
{
UpState *state = user_data;
up_kbd_backlight_register (state->kbd_backlight, connection);
//up_kbd_backlight_register (state->kbd_backlight, connection);
if (!up_daemon_startup (state->daemon, connection)) {
g_warning ("Could not startup; bailing out");
g_main_loop_quit (state->loop);