[gnome-power-manager] Add keyboard backlight support including dimming on idle and keyboard control



commit 7e5fedb32bfb9dc6428c5b0eb21ef48a27602a27
Author: Alex Murray <murray alex gmail com>
Date:   Wed Feb 23 22:04:26 2011 +1030

    Add keyboard backlight support including dimming on idle and keyboard control
    
    This patch is a rehash of a patch originally written by Alex Launi but
    which addresses the comments made for that original patch.
    
    Signed-off-by: Richard Hughes <richard hughsie com>

 data/org.gnome.power-manager.gschema.xml.in |   20 +
 src/Makefile.am                             |    4 +-
 src/gpm-backlight.h                         |    2 +-
 src/gpm-common.c                            |    1 -
 src/gpm-common.h                            |    7 +
 src/gpm-kbd-backlight.c                     |  733 +++++++++++++++++++++++++++
 src/gpm-kbd-backlight.h                     |   78 +++
 src/gpm-manager.c                           |   12 +
 8 files changed, 854 insertions(+), 3 deletions(-)
---
diff --git a/data/org.gnome.power-manager.gschema.xml.in b/data/org.gnome.power-manager.gschema.xml.in
index 58c7644..c773de6 100644
--- a/data/org.gnome.power-manager.gschema.xml.in
+++ b/data/org.gnome.power-manager.gschema.xml.in
@@ -27,6 +27,26 @@
       <_summary>LCD brightness when on AC</_summary>
       <_description>The brightness of the display when on AC power. Possible values are between 0.0 and 1.0.</_description>
     </key>
+    <key name="kbd-backlight-battery-reduce" type="b">
+      <default>true</default>
+      <_summary>Reduce the keyboard backlight when on battery power</_summary>
+      <_description>If the keyboard backlight brightness should be reduced when the computer is on battery power</_description>
+    </key>
+    <key name="kbd-brightness-on-ac" type="i">
+      <default>100</default>
+      <_summary>Keyboard backlight brightness when on AC power.</_summary>
+      <_description>Percent brightness to set keyboard backlight at when on AC power. Legal values are between 0 and 100.</_description>
+    </key>
+    <key name="kbd-brightness-dim-by-on-battery" type="i">
+      <default>50</default>
+      <_summary>Percent to reduce keyboard backlight by when on battery power.</summary>
+      <_description>The percentage to reduce the keyboard backlight by when on battery power. For example, if set to '60', the backlight will be cut by 40% on battery power. Legal values are between 0 and 100.</_description>
+    </key>
+    <key name="kbd-brightness-dim-by-on-idle" type="i">
+      <default>75</default>
+      <_summary>Percent to reduce keyboard backlight by when idle.</summary>
+      <_description>The percentage to reduce the keyboard backlight by when idle. For example, if set to '60', the backlight will be cut by 40% when idle. Legal values are between 0 and 100.</_description>
+    </key>
     <key name="use-time-for-policy" type="b">
       <default>true</default>
       <_summary>Whether to use time-based notifications</_summary>
diff --git a/src/Makefile.am b/src/Makefile.am
index 2459fe1..009e7a8 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -32,7 +32,7 @@ bin_PROGRAMS =						\
 	gnome-power-statistics
 
 sbin_PROGRAMS =						\
-	gnome-power-backlight-helper			\
+	gnome-power-backlight-helper	\
 	$(NULL)
 
 check_PROGRAMS =					\
@@ -101,6 +101,8 @@ gnome_power_manager_SOURCES =				\
 	gpm-control.c					\
 	gpm-button.h					\
 	gpm-button.c					\
+	gpm-kbd-backlight.h				\
+	gpm-kbd-backlight.c				\
 	gpm-main.c					\
 	gpm-manager.h					\
 	gpm-manager.c					\
diff --git a/src/gpm-backlight.h b/src/gpm-backlight.h
index bf0c6a9..e8f2879 100644
--- a/src/gpm-backlight.h
+++ b/src/gpm-backlight.h
@@ -38,7 +38,7 @@ typedef struct GpmBacklightPrivate GpmBacklightPrivate;
 
 typedef struct
 {
-	GObject			 parent;
+	GObject		     parent;
 	GpmBacklightPrivate *priv;
 } GpmBacklight;
 
diff --git a/src/gpm-common.c b/src/gpm-common.c
index 69a77c0..dc05944 100644
--- a/src/gpm-common.c
+++ b/src/gpm-common.c
@@ -258,4 +258,3 @@ gpm_color_to_rgb (guint32 color, guint8 *red, guint8 *green, guint8 *blue)
 	*green = (color & 0x00ff00) / 0x100;
 	*blue = color & 0x0000ff;
 }
-
diff --git a/src/gpm-common.h b/src/gpm-common.h
index 3f1b765..b540c05 100644
--- a/src/gpm-common.h
+++ b/src/gpm-common.h
@@ -31,6 +31,7 @@ G_BEGIN_DECLS
 #define	GPM_DBUS_INTERFACE_BACKLIGHT	"org.gnome.PowerManager.Backlight"
 #define	GPM_DBUS_PATH			"/org/gnome/PowerManager"
 #define	GPM_DBUS_PATH_BACKLIGHT		"/org/gnome/PowerManager/Backlight"
+#define GPM_DBUS_PATH_KBD_BACKLIGHT	"/org/gnome/PowerManager/KbdBacklight"
 
 /* common descriptions of this program */
 #define GPM_NAME 			_("Power Manager")
@@ -55,6 +56,12 @@ G_BEGIN_DECLS
 #define GPM_SETTINGS_BRIGHTNESS_AC			"brightness-ac"
 #define GPM_SETTINGS_BRIGHTNESS_DIM_BATT		"brightness-dim-battery"
 
+/* keyboard backlight */
+#define GPM_SETTINGS_KBD_BACKLIGHT_BATT_REDUCE		"kbd-backlight-battery-reduce"
+#define GPM_SETTINGS_KBD_BRIGHTNESS_ON_AC		"kbd-brightness-on-ac"
+#define GPM_SETTINGS_KBD_BRIGHTNESS_DIM_BY_ON_BATT      "kbd-brightness-dim-by-on-battery"
+#define GPM_SETTINGS_KBD_BRIGHTNESS_DIM_BY_ON_IDLE	"kbd-brightness-dim-by-on-idle"
+
 /* buttons */
 #define GSD_SETTINGS_BUTTON_LID_AC			"lid-close-ac-action"
 #define GSD_SETTINGS_BUTTON_LID_BATT			"lid-close-battery-action"
diff --git a/src/gpm-kbd-backlight.c b/src/gpm-kbd-backlight.c
new file mode 100644
index 0000000..5334607
--- /dev/null
+++ b/src/gpm-kbd-backlight.c
@@ -0,0 +1,733 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2010 Alex Launi <alex launi canonical 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 <gio/gio.h>
+#include <glib.h>
+#include <libupower-glib/upower.h>
+
+#include "gpm-button.h"
+#include "gpm-common.h"
+#include "gpm-control.h"
+#include "gpm-idle.h"
+#include "gpm-kbd-backlight.h"
+
+static const gchar *kbd_backlight_introspection = ""
+"<?xml version=\"1.0\" encoding=\"UTF-8\"?>""<node name=\"/\">"
+  "<interface name=\"org.gnome.PowerManager.Backlight\">"
+    "<method name=\"GetBrightness\">"
+      "<arg type=\"u\" name=\"percentage_brightness\" direction=\"out\"/>"
+    "</method>"
+    "<method name=\"SetBrightness\">"
+      "<arg type=\"u\" name=\"percentage_brightness\" direction=\"in\"/>"
+    "</method>"
+    "<signal name=\"BrightnessChanged\">"
+      "<arg type=\"u\" name=\"percentage_brightness\" direction=\"out\"/>"
+    "</signal>"
+  "</interface>"
+"</node>";
+
+#define GPM_KBD_BACKLIGHT_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GPM_TYPE_KBD_BACKLIGHT, GpmKbdBacklightPrivate))
+
+struct GpmKbdBacklightPrivate
+{
+	UpClient		*client;
+	GpmButton		*button;
+	GSettings		*settings;
+	GSettings		*settings_gsd;
+	GpmControl		*control;
+	GpmIdle			*idle;
+	gboolean		 can_dim;
+	gboolean		 system_is_idle;
+	GTimer			*idle_timer;
+	guint			 idle_dim_timeout;
+	guint			 master_percentage;
+	guint	 		 brightness;
+	guint	 		 max_brightness;
+	guint			 brightness_percent;
+	GDBusProxy		*upower_proxy;
+	GDBusConnection		*bus_connection;
+	guint			 bus_object_id;
+};
+
+enum {
+	BRIGHTNESS_CHANGED,
+	LAST_SIGNAL
+};
+
+static guint signals [LAST_SIGNAL] = { 0 };
+
+G_DEFINE_TYPE (GpmKbdBacklight, gpm_kbd_backlight, G_TYPE_OBJECT)
+
+/**
+ * gpm_kbd_backlight_error_quark:
+ * Return value: Our personal error quark.
+ **/
+GQuark
+gpm_kbd_backlight_error_quark (void)
+{
+	static GQuark quark = 0;
+	if (!quark)
+		quark = g_quark_from_static_string ("gpm_kbd_backlight_error");
+	return quark;
+}
+
+/**
+ * gpm_kbd_backlight_get_brightness:
+ * @backlight:
+ * @brightness:
+ * @error:
+ *
+ * Return value:
+ */
+gboolean
+gpm_kbd_backlight_get_brightness (GpmKbdBacklight *backlight,
+				  guint *brightness,
+				  GError **error)
+{
+	g_return_val_if_fail (backlight != NULL, FALSE);
+	g_return_val_if_fail (GPM_IS_KBD_BACKLIGHT (backlight), FALSE);
+	g_return_val_if_fail (brightness != NULL, FALSE);
+
+	if (backlight->priv->can_dim == FALSE) {
+		g_set_error_literal (error, gpm_kbd_backlight_error_quark (),
+				     GPM_KBD_BACKLIGHT_ERROR_HARDWARE_NOT_PRESENT,
+				     "Dim capable hardware not present");
+		return FALSE;
+	}
+
+	*brightness = backlight->priv->brightness_percent;
+	return TRUE;
+}
+
+static gboolean
+gpm_kbd_backlight_set (GpmKbdBacklight *backlight,
+		       guint percentage)
+{
+	gint scale;
+	guint goal;
+
+	g_return_val_if_fail (GPM_IS_KBD_BACKLIGHT (backlight), FALSE);
+	/* if we're setting the same we are, don't bother */
+	//g_return_val_if_fail (backlight->priv->brightness_percent != percentage, FALSE);
+
+	goal = gpm_discrete_from_percent (percentage, backlight->priv->max_brightness);
+	scale = percentage > backlight->priv->brightness_percent ? 1 : -1;
+
+	/* step loop down by 1 for a dimming effect */
+	while (backlight->priv->brightness != goal) {
+		backlight->priv->brightness += scale;
+		backlight->priv->brightness_percent = gpm_discrete_to_percent (backlight->priv->brightness, backlight->priv->max_brightness);
+
+		g_dbus_proxy_call (backlight->priv->upower_proxy,
+			           "SetBrightness",
+				    g_variant_new ("(i)", (gint) backlight->priv->brightness),
+				    G_DBUS_CALL_FLAGS_NONE,
+				    -1,
+				    NULL,
+				    NULL,
+				    NULL);
+	}
+
+	return TRUE;
+}
+
+/**
+ * gpm_kbd_backlight_brightness_up:
+ **/
+static gboolean
+gpm_kbd_backlight_brightness_up (GpmKbdBacklight *backlight)
+{
+	guint new;
+
+	new = MIN (backlight->priv->brightness_percent + GPM_KBD_BACKLIGHT_STEP, 100u);
+	return gpm_kbd_backlight_set (backlight, new);
+}
+
+/**
+ * gpm_kbd_backlight_brightness_down:
+ **/
+static gboolean
+gpm_kbd_backlight_brightness_down (GpmKbdBacklight *backlight)
+{
+	guint new;
+
+	// we can possibly go below 0 here, so by converting to a gint we avoid underflow errors.
+	new = MAX ((gint) backlight->priv->brightness_percent - GPM_KBD_BACKLIGHT_STEP, 0);
+	return gpm_kbd_backlight_set (backlight, new);
+}
+
+/**
+ * gpm_kbd_backlight_set_brightness:
+ * @backlight:
+ * @percentage:
+ * @error:
+ *
+ * Return value:
+ **/
+gboolean
+gpm_kbd_backlight_set_brightness (GpmKbdBacklight *backlight,
+				  guint percentage,
+				  GError **error)
+{
+	gboolean ret;
+
+	g_return_val_if_fail (backlight != NULL, FALSE);
+	g_return_val_if_fail (GPM_IS_KBD_BACKLIGHT (backlight), FALSE);
+
+	if (backlight->priv->can_dim == FALSE) {
+		g_set_error_literal (error, gpm_kbd_backlight_error_quark (),
+				     GPM_KBD_BACKLIGHT_ERROR_HARDWARE_NOT_PRESENT,
+				     "Dim capable hardware not present");
+		return FALSE;
+	}
+
+	backlight->priv->master_percentage = percentage;
+
+	ret = gpm_kbd_backlight_set (backlight, percentage);
+	if (!ret) {
+		g_set_error_literal (error, gpm_kbd_backlight_error_quark (),
+				     GPM_KBD_BACKLIGHT_ERROR_GENERAL,
+				     "Cannot set keyboard backlight brightness");
+	}
+
+	return ret;
+}
+
+static void
+gpm_kbd_backlight_on_brightness_changed (GpmKbdBacklight *backlight,
+					 guint value)
+{
+	backlight->priv->brightness = value;
+	backlight->priv->brightness_percent = gpm_discrete_to_percent (value, backlight->priv->max_brightness);
+	backlight->priv->master_percentage = backlight->priv->brightness_percent;
+	g_signal_emit (backlight, signals [BRIGHTNESS_CHANGED], 0, backlight->priv->brightness_percent);
+}
+
+/**
+ * gpm_kbd_backlight_on_dbus_signal:
+ **/
+static void
+gpm_kbd_backlight_on_dbus_signal (GDBusProxy *proxy,
+				  gchar      *sender_name,
+				  gchar      *signal_name,
+				  GVariant   *parameters,
+				  gpointer    user_data)
+{
+	guint value;
+	GpmKbdBacklight *backlight = GPM_KBD_BACKLIGHT (user_data);
+
+	if (g_strcmp0 (signal_name, "BrightnessChanged") == 0) {
+		g_variant_get (parameters, "(i)", &value);
+		gpm_kbd_backlight_on_brightness_changed (backlight, value);
+		return;
+	}
+
+	g_assert_not_reached ();
+}
+
+/**
+ * gpm_kbd_backlight_dbus_method_call:
+ * @connection:
+ * @object_path:
+ * @interface_name:
+ * @method_name:
+ * @parameters:
+ * @invocation:
+ * @user_data:
+ **/
+static void
+gpm_kbd_backlight_dbus_method_call (GDBusConnection *connection,
+				    const gchar *sender,
+				    const gchar *object_path,
+				    const gchar *interface_name,
+				    const gchar *method_name,
+				    GVariant *parameters,
+				    GDBusMethodInvocation *invocation,
+				    gpointer user_data)
+{
+	guint value;
+	gboolean ret;
+	GError *error = NULL;
+	GpmKbdBacklight *backlight = GPM_KBD_BACKLIGHT (user_data);
+
+	if (g_strcmp0 (method_name, "GetBrightness") == 0) {
+		ret = gpm_kbd_backlight_get_brightness (backlight, &value, &error);
+		if (!ret) {
+			g_dbus_method_invocation_return_gerror (invocation, error);
+			g_error_free (error);
+		} else {
+			g_dbus_method_invocation_return_value (invocation, g_variant_new ("(u)", value));
+		}
+		return;
+	}
+
+	if (g_strcmp0 (method_name, "SetBrightness") == 0) {
+		g_variant_get (parameters, "(u)", &value);
+		ret = gpm_kbd_backlight_set_brightness (backlight, value, &error);
+		if (!ret) {
+			g_dbus_method_invocation_return_gerror (invocation, error);
+			g_error_free (error);
+		} else {
+			g_dbus_method_invocation_return_value (invocation, NULL);
+		}
+		return;
+	}
+
+	g_assert_not_reached ();
+}
+
+
+/**
+ * gpm_kbd_backlight_dbus_property_get:
+ * @sender:
+ * @object_path:
+ * @interface_name:
+ * @property_name:
+ * @error:
+ * @user_data:
+ *
+ * Return value:
+ **/
+static GVariant *
+gpm_kbd_backlight_dbus_property_get (GDBusConnection *connection,
+				     const gchar *sender,
+				     const gchar *object_path,
+				     const gchar *interface_name,
+				     const gchar *property_name,
+				     GError **error,
+				     gpointer user_data)
+{
+	/* Do nothing, we have no props */
+	return NULL;
+}
+
+/**
+ * gpm_kbd_backlight_dbus_property_set:
+ * @connection:
+ * @sender:
+ * @object_path:
+ * @interface_name:
+ * @property_name:
+ *
+ * Return value:
+ **/
+static gboolean
+gpm_kbd_backlight_dbus_property_set (GDBusConnection *connection,
+				     const gchar *sender,
+				     const gchar *object_path,
+    				     const gchar *interface_name,
+    				     const gchar *property_name,
+				     GVariant *value,
+				     GError **error,
+				     gpointer user_data)
+{
+	/* do nothing, no properties defined */
+	return FALSE;
+}
+
+/**
+ * gpm_kbd_backlight_register_dbus:
+ * @backlight:
+ * @connection:
+ * @error:
+ **/
+void
+gpm_kbd_backlight_register_dbus (GpmKbdBacklight *backlight,
+				 GDBusConnection *connection,
+				 GError **error)
+{
+	GDBusNodeInfo *node_info;
+	GDBusInterfaceInfo *interface_info;
+	GDBusInterfaceVTable interface_vtable = {
+			gpm_kbd_backlight_dbus_method_call,
+			gpm_kbd_backlight_dbus_property_get,
+			gpm_kbd_backlight_dbus_property_set
+	};
+
+	node_info = g_dbus_node_info_new_for_xml (kbd_backlight_introspection, NULL);
+	interface_info = g_dbus_node_info_lookup_interface (node_info, GPM_DBUS_INTERFACE_BACKLIGHT);
+
+	backlight->priv->bus_connection = g_object_ref (connection);
+	backlight->priv->bus_object_id =
+		g_dbus_connection_register_object (connection,
+						   GPM_DBUS_PATH_KBD_BACKLIGHT,
+						   interface_info,
+						   &interface_vtable,
+						   backlight,
+						   NULL,
+						   error);
+	g_dbus_node_info_unref (node_info);
+}
+
+static gboolean
+gpm_kbd_backlight_evaluate_power_source_and_set (GpmKbdBacklight *backlight)
+{
+	gfloat brightness;
+	gfloat scale;
+	gboolean on_battery;
+	gboolean battery_reduce;
+	guint value;
+	gboolean ret;
+
+	brightness = backlight->priv->master_percentage;
+
+	g_object_get (backlight->priv->client,
+		      "on-battery",
+		      &on_battery,
+		      NULL);
+
+	battery_reduce = g_settings_get_boolean (backlight->priv->settings, GPM_SETTINGS_KBD_BACKLIGHT_BATT_REDUCE);
+
+	if (on_battery && battery_reduce) {
+		value = g_settings_get_int (backlight->priv->settings, GPM_SETTINGS_KBD_BRIGHTNESS_DIM_BY_ON_BATT);
+
+		if (value > 100) {
+			g_warning ("Cannot scale brightness down by more than 100%%. Scaling by 50%%");
+			value = 50;
+		}
+
+		scale = (100 - value) / 100.0f;
+		brightness *= scale;
+
+		value = (guint) brightness;
+
+	} else {
+		value = g_settings_get_int (backlight->priv->settings, GPM_SETTINGS_KBD_BRIGHTNESS_ON_AC);
+	}
+
+	ret = gpm_kbd_backlight_set (backlight, value);
+	return ret;
+}
+
+/**
+ * gpm_kbd_backlight_control_resume_cb:
+ * @control: The control class instance
+ * @backlight: This backlight class instance
+ *
+ * Just make sure that the backlight is back on
+ **/
+static void
+gpm_kbd_backlight_control_resume_cb (GpmControl *control,
+				     GpmControlAction action,
+				     GpmKbdBacklight *backlight)
+{
+	gboolean ret;
+
+	ret = gpm_kbd_backlight_evaluate_power_source_and_set (backlight);
+	if (!ret)
+		g_warning ("Failed to turn kbd brightness back on after resuming");
+}
+
+/**
+ * gpm_kbd_backlight_client_changed_cb:
+ * @client: The up_client class instance
+ * @backlight: This class instance
+ *
+ * Does the actions when the ac power source is inserted/removed.
+ **/
+static void
+gpm_kbd_backlight_client_changed_cb (UpClient *client,
+				     GpmKbdBacklight *backlight)
+{
+	gpm_kbd_backlight_evaluate_power_source_and_set (backlight);
+}
+
+/**
+ * gpm_kbd_backlight_button_pressed_cb:
+ * @power: The power class instance
+ * @type: The button type, but here we only care about keyboard brightness buttons
+ * @backlight: This class instance
+ **/
+static void
+gpm_kbd_backlight_button_pressed_cb (GpmButton *button,
+				     const gchar *type,
+				     GpmKbdBacklight *backlight)
+{
+	static guint saved_brightness;
+
+	saved_brightness = backlight->priv->master_percentage;
+
+	if (g_strcmp0 (type, GPM_BUTTON_KBD_BRIGHT_UP) == 0) {
+		gpm_kbd_backlight_brightness_up (backlight);
+
+	} else if (g_strcmp0 (type, GPM_BUTTON_KBD_BRIGHT_DOWN) == 0) {
+		gpm_kbd_backlight_brightness_down (backlight);
+
+	} else if (g_strcmp0 (type, GPM_BUTTON_KBD_BRIGHT_TOGGLE) == 0) {
+		if (backlight->priv->master_percentage == 0) {
+			/* backlight is off turn it back on */
+			gpm_kbd_backlight_set (backlight, saved_brightness);
+		} else {
+			/* backlight is on, turn it off and save current value */
+			saved_brightness = backlight->priv->master_percentage;
+			gpm_kbd_backlight_set (backlight, 0);
+		}
+	}
+}
+
+/**
+ * gpm_kbd_backlight_idle_changed_cb:
+ * @idle: The idle class instance
+ * @mode: The idle mode, e.g. GPM_IDLE_MODE_BLANK
+ * @backlight: This class instance
+ *
+ * This callback is called when gnome-screensaver detects that the idle state
+ * has changed. GPM_IDLE_MODE_BLANK is when the session has become inactive,
+ * and GPM_IDLE_MODE_SLEEP is where the session has become inactive, AND the
+ * session timeout has elapsed for the idle action.
+ **/
+static void
+gpm_kbd_backlight_idle_changed_cb (GpmIdle *idle,
+				   GpmIdleMode mode,
+				   GpmKbdBacklight *backlight)
+{
+	gfloat brightness;
+	gfloat scale;
+	guint value;
+	gboolean lid_closed;
+	gboolean on_battery;
+	gboolean enable_action;
+
+	lid_closed = gpm_button_is_lid_closed (backlight->priv->button);
+
+	if (lid_closed)
+		return;
+
+	g_object_get (backlight->priv->client,
+	              "on-battery",
+	              &on_battery,
+	              NULL);
+
+	enable_action = on_battery
+		? g_settings_get_boolean (backlight->priv->settings_gsd, GSD_SETTINGS_IDLE_DIM_BATT)
+		: g_settings_get_boolean (backlight->priv->settings_gsd, GSD_SETTINGS_IDLE_DIM_AC);
+
+	if (!enable_action)
+		return;
+
+	if (mode == GPM_IDLE_MODE_NORMAL) {
+		backlight->priv->master_percentage = 100;
+		gpm_kbd_backlight_evaluate_power_source_and_set (backlight);
+	} else if (mode == GPM_IDLE_MODE_DIM) {
+		brightness = backlight->priv->master_percentage;
+		value = g_settings_get_int (backlight->priv->settings, GPM_SETTINGS_KBD_BRIGHTNESS_DIM_BY_ON_IDLE);
+
+		if (value > 100) {
+			g_warning ("Cannot scale brightness down by more than 100%%. Scaling by 50%%");
+			value = 50;
+		}
+
+		scale = (100 - value) / 100.0f;
+		brightness *= scale;
+
+		value = (guint) brightness;
+		gpm_kbd_backlight_set (backlight, value);
+	} else if (mode == GPM_IDLE_MODE_BLANK) {
+		gpm_kbd_backlight_set (backlight, 0u);
+	}
+}
+
+/**
+ * gpm_kbd_backlight_finalize:
+ * @object:
+ **/
+static void
+gpm_kbd_backlight_finalize (GObject *object)
+{
+	GpmKbdBacklight *backlight;
+
+	g_return_if_fail (object != NULL);
+	g_return_if_fail (GPM_IS_KBD_BACKLIGHT (object));
+
+	backlight = GPM_KBD_BACKLIGHT (object);
+
+	if (backlight->priv->upower_proxy != NULL) {
+		g_object_unref (backlight->priv->upower_proxy);
+	}
+	if (backlight->priv->bus_connection != NULL) {
+		g_dbus_connection_unregister_object (backlight->priv->bus_connection,
+						     backlight->priv->bus_object_id);
+		g_object_unref (backlight->priv->bus_connection);
+	}
+
+	g_timer_destroy (backlight->priv->idle_timer);
+
+	g_object_unref (backlight->priv->control);
+	g_object_unref (backlight->priv->settings);
+	g_object_unref (backlight->priv->settings_gsd);
+	g_object_unref (backlight->priv->client);
+	g_object_unref (backlight->priv->button);
+	g_object_unref (backlight->priv->idle);
+
+	g_return_if_fail (backlight->priv != NULL);
+	G_OBJECT_CLASS (gpm_kbd_backlight_parent_class)->finalize (object);
+}
+
+/**
+ * gpm_kbd_backlight_class_init:
+ * @klass:
+ **/
+static void
+gpm_kbd_backlight_class_init (GpmKbdBacklightClass *klass)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (klass);
+	object_class->finalize = gpm_kbd_backlight_finalize;
+
+	signals [BRIGHTNESS_CHANGED] =
+		g_signal_new ("brightness-changed",
+			       G_TYPE_FROM_CLASS (object_class),
+			       G_SIGNAL_RUN_LAST,
+			       G_STRUCT_OFFSET (GpmKbdBacklightClass, brightness_changed),
+			       NULL,
+			       NULL,
+			       g_cclosure_marshal_VOID__UINT,
+			       G_TYPE_NONE,
+			       1,
+			       G_TYPE_UINT);
+
+	g_type_class_add_private (klass, sizeof (GpmKbdBacklightPrivate));
+}
+
+/**
+ * gpm_kbd_backlight_init:
+ * @backlight: This KbdBacklight class instance
+ *
+ * Initializes the KbdBacklight class.
+ **/
+static void
+gpm_kbd_backlight_init (GpmKbdBacklight *backlight)
+{
+	GVariant *u_brightness;
+	GVariant *u_max_brightness;
+	GError   *error = NULL;
+
+	backlight->priv = GPM_KBD_BACKLIGHT_GET_PRIVATE (backlight);
+
+	backlight->priv->upower_proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM,
+								       G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES,
+								       NULL,
+								       "org.freedesktop.UPower",
+								       "/org/freedesktop/UPower/KbdBacklight",
+								       "org.freedesktop.UPower.KbdBacklight",
+								       NULL,
+								       &error);
+	if (backlight->priv->upower_proxy == NULL) {
+		g_printerr ("Could not connect to UPower system bus: %s", error->message);
+		g_error_free (error);
+		goto err;
+	}
+
+	g_signal_connect (backlight->priv->upower_proxy,
+			  "g-signal",
+			  G_CALLBACK (gpm_kbd_backlight_on_dbus_signal),
+			  backlight);
+
+	u_brightness = g_dbus_proxy_call_sync (backlight->priv->upower_proxy,
+					       "GetBrightness",
+					       NULL,
+					       G_DBUS_CALL_FLAGS_NONE,
+					       -1,
+					       NULL,
+					       &error);
+	if (u_brightness == NULL) {
+		g_warning ("Failed to get brightness: %s", error->message);
+		g_error_free (error);
+		goto err;
+	}
+
+	error = NULL;
+	u_max_brightness = g_dbus_proxy_call_sync (backlight->priv->upower_proxy,
+						   "GetMaxBrightness",
+						   NULL,
+						   G_DBUS_CALL_FLAGS_NONE,
+						   -1,
+						   NULL,
+						   &error);
+	if (u_max_brightness == NULL) {
+		g_warning ("Failed to get max brightness: %s", error->message);
+		g_error_free (error);
+		g_variant_unref (u_brightness);
+		goto err;
+	}
+
+	g_variant_get (u_brightness, "(i)", &backlight->priv->brightness);
+	g_variant_get (u_max_brightness, "(i)", &backlight->priv->max_brightness);
+
+	backlight->priv->brightness_percent = gpm_discrete_to_percent (backlight->priv->brightness,
+								       backlight->priv->max_brightness);
+
+	g_variant_unref (u_brightness);
+	g_variant_unref (u_max_brightness);
+	goto noerr;
+
+err:
+	backlight->priv->brightness = 0;
+	backlight->priv->brightness_percent = 100;
+	backlight->priv->max_brightness = 0;
+
+noerr:
+	/* Initialize the master to full power. It will get scaled if needed */
+	backlight->priv->master_percentage = 100u;
+
+	backlight->priv->idle_timer = g_timer_new ();
+	backlight->priv->can_dim = backlight->priv->max_brightness > 1;
+
+	/* Use upower for ac changed signal */
+	backlight->priv->client = up_client_new ();
+	g_signal_connect (backlight->priv->client, "changed",
+			  G_CALLBACK (gpm_kbd_backlight_client_changed_cb), backlight);
+
+	backlight->priv->settings = g_settings_new (GPM_SETTINGS_SCHEMA);
+	backlight->priv->settings_gsd = g_settings_new (GSD_SETTINGS_SCHEMA);
+
+	/* watch for kbd brightness up and down button presses */
+	backlight->priv->button = gpm_button_new ();
+	g_signal_connect (backlight->priv->button, "button-pressed",
+			  G_CALLBACK (gpm_kbd_backlight_button_pressed_cb), backlight);
+
+	backlight->priv->idle = gpm_idle_new ();
+	g_signal_connect (backlight->priv->idle, "idle-changed",
+			  G_CALLBACK (gpm_kbd_backlight_idle_changed_cb), backlight);
+
+	/* since gpm is just starting we can pretty safely assume that we're not idle */
+	backlight->priv->system_is_idle = FALSE;
+	backlight->priv->idle_dim_timeout = g_settings_get_int (backlight->priv->settings_gsd, GSD_SETTINGS_IDLE_DIM_TIME);
+	gpm_idle_set_timeout_dim (backlight->priv->idle, backlight->priv->idle_dim_timeout);
+
+	/* make sure we turn the keyboard backlight back on after resuming */
+	backlight->priv->control = gpm_control_new ();
+	g_signal_connect (backlight->priv->control, "resume",
+			  G_CALLBACK (gpm_kbd_backlight_control_resume_cb), backlight);
+
+	/* set initial values for whether we're on AC or battery*/
+	gpm_kbd_backlight_evaluate_power_source_and_set (backlight);
+}
+
+/**
+ * gpm_kbd_backlight_new:
+ * Return value: A new GpmKbdBacklight class instance.
+ **/
+GpmKbdBacklight *
+gpm_kbd_backlight_new (void)
+{
+	GpmKbdBacklight *backlight = g_object_new (GPM_TYPE_KBD_BACKLIGHT, NULL);
+	return backlight;
+}
diff --git a/src/gpm-kbd-backlight.h b/src/gpm-kbd-backlight.h
new file mode 100644
index 0000000..02de46a
--- /dev/null
+++ b/src/gpm-kbd-backlight.h
@@ -0,0 +1,78 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2010 Alex Launi <alex launi canonical 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 __GPM_KBD_BACKLIGHT_H
+#define __GPM_KBD_BACKLIGHT_H
+
+#include <gio/gio.h>
+#include <glib.h>
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define GPM_TYPE_KBD_BACKLIGHT		(gpm_kbd_backlight_get_type ())
+#define GPM_KBD_BACKLIGHT(o)		(G_TYPE_CHECK_INSTANCE_CAST ((o), GPM_TYPE_KBD_BACKLIGHT, GpmKbdBacklight))
+#define GPM_KBD_BACKLIGHT_CLASS(k)	(G_TYPE_CHECK_CLASS_CAST((k), GPM_TYPE_KBD_BACKLIGHT, GpmKbdBacklightClass))
+#define GPM_IS_KBD_BACKLIGHT(o)		(G_TYPE_CHECK_INSTANCE_TYPE ((o), GPM_TYPE_KBD_BACKLIGHT))
+#define GPM_IS_KBD_BACKLIGHT_CLASS(k)	(G_TYPE_CHECK_CLASS_TYPE ((k), GPM_TYPE_KBD_BACKLIGHT))
+#define GPM_KBD_BACKLIGHT_GET_CLASS(o)	(G_TYPE_INSTANCE_GET_CLASS ((o), GPM_TYPE_KBD_BACKLIGHT, GpmKbdBacklightClass))
+
+#define GPM_KBD_BACKLIGHT_DIM_INTERVAL	5 /* ms */
+#define GPM_KBD_BACKLIGHT_STEP 10 /* change by 10% each step */
+
+typedef struct GpmKbdBacklightPrivate GpmKbdBacklightPrivate;
+
+typedef struct
+{
+	GObject			parent;
+	GpmKbdBacklightPrivate *priv;
+} GpmKbdBacklight;
+
+typedef struct
+{
+	GObjectClass parent_class;
+	void	     (* brightness_changed)	(GpmKbdBacklight *backlight,
+						 gint		  brightness);
+} GpmKbdBacklightClass;
+
+typedef enum
+{
+	 GPM_KBD_BACKLIGHT_ERROR_GENERAL,
+	 GPM_KBD_BACKLIGHT_ERROR_DATA_NOT_AVAILABLE,
+	 GPM_KBD_BACKLIGHT_ERROR_HARDWARE_NOT_PRESENT
+} GpmKbdBacklightError;
+
+GType		 	gpm_kbd_backlight_get_type 		(void);
+GQuark			gpm_kbd_backlight_error_quark		(void);
+GpmKbdBacklight	       *gpm_kbd_backlight_new			(void);
+gboolean		gpm_kbd_backlight_get_brightness	(GpmKbdBacklight *backlight,
+								 guint *brightness,
+								 GError **error);
+gboolean		gpm_kbd_backlight_set_brightness	(GpmKbdBacklight *backlight,
+								 guint brightness,
+								 GError **error);
+void			gpm_kbd_backlight_register_dbus		(GpmKbdBacklight *backlight,
+								 GDBusConnection *connection,
+								 GError **error);
+
+G_END_DECLS
+
+#endif /* __GPM_KBD_BACKLIGHT_H */
diff --git a/src/gpm-manager.c b/src/gpm-manager.c
index afa777c..d6f3de8 100644
--- a/src/gpm-manager.c
+++ b/src/gpm-manager.c
@@ -50,6 +50,7 @@
 #include "gpm-manager.h"
 #include "gpm-screensaver.h"
 #include "gpm-backlight.h"
+#include "gpm-kbd-backlight.h"
 #include "gpm-stock-icons.h"
 #include "gpm-tray-icon.h"
 #include "gpm-engine.h"
@@ -98,6 +99,7 @@ struct GpmManagerPrivate
 	GpmTrayIcon		*tray_icon;
 	GpmEngine		*engine;
 	GpmBacklight		*backlight;
+	GpmKbdBacklight		*kbd_backlight;
 	EggConsoleKit		*console;
 	guint32			 screensaver_ac_throttle_id;
 	guint32			 screensaver_dpms_throttle_id;
@@ -2229,6 +2231,12 @@ gpm_manager_bus_acquired_cb (GDBusConnection *connection,
 	if (manager->priv->backlight != NULL) {
 		gpm_backlight_register_dbus (manager->priv->backlight, connection);
 	}
+	
+	if (manager->priv->kbd_backlight != NULL) {
+		gpm_kbd_backlight_register_dbus (manager->priv->kbd_backlight,
+						 connection,
+						 NULL);
+	}
 }
 
 /**
@@ -2313,6 +2321,9 @@ gpm_manager_init (GpmManager *manager)
 
 	/* try an start an interactive service */
 	manager->priv->backlight = gpm_backlight_new ();
+	
+	/* try and start an interactive service */
+	manager->priv->kbd_backlight = gpm_kbd_backlight_new ();
 
 	manager->priv->idle = gpm_idle_new ();
 	g_signal_connect (manager->priv->idle, "idle-changed",
@@ -2419,6 +2430,7 @@ gpm_manager_finalize (GObject *object)
 	g_object_unref (manager->priv->control);
 	g_object_unref (manager->priv->button);
 	g_object_unref (manager->priv->backlight);
+	g_object_unref (manager->priv->kbd_backlight);
 	g_object_unref (manager->priv->console);
 	g_object_unref (manager->priv->client);
 	g_object_unref (manager->priv->status_icon);



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]