[gnome-power-manager] Provide a pkexec helper for systems that do not have xbacklight capability



commit d3594664f59ef31278f7d95f9f73e2d52fe3a3f6
Author: Richard Hughes <richard hughsie com>
Date:   Thu May 6 20:40:07 2010 +0100

    Provide a pkexec helper for systems that do not have xbacklight capability

 Makefile.am                      |    1 +
 configure.ac                     |    1 +
 po/POTFILES.in                   |    2 +
 policy/.gitignore                |    8 ++
 policy/Makefile.am               |   14 ++
 policy/org.gnome.power.policy.in |   32 +++++
 src/.gitignore                   |    1 +
 src/Makefile.am                  |   19 +++
 src/gpm-backlight-helper.c       |  247 ++++++++++++++++++++++++++++++++++++++
 src/gpm-brightness.c             |  128 +++++++++++++++++++-
 10 files changed, 446 insertions(+), 7 deletions(-)
---
diff --git a/Makefile.am b/Makefile.am
index 36f06a1..005b8a0 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -8,6 +8,7 @@ SUBDIRS = 						\
 	man						\
 	data						\
 	help						\
+	policy						\
 	tools
 
 if HAVE_APPLETS
diff --git a/configure.ac b/configure.ac
index 65a1f2d..0a38772 100644
--- a/configure.ac
+++ b/configure.ac
@@ -315,6 +315,7 @@ man/Makefile
 help/Makefile
 po/Makefile.in
 tools/Makefile
+policy/Makefile
 data/Makefile
 data/gnome-power-manager.desktop.in
 data/gnome-power-preferences.desktop.in
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 41e6ee0..dda8e2b 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -12,7 +12,9 @@ data/gnome-power-statistics.desktop.in.in
 [type: gettext/glade]data/gpm-feedback-widget.ui
 [type: gettext/glade]data/gpm-statistics.ui
 [type: gettext/glade]data/gpm-prefs.ui
+policy/org.gnome.power.policy.in
 src/gpm-backlight.c
+src/gpm-backlight-helper.c
 src/gpm-button.c
 src/gpm-control.c
 src/gpm-common.c
diff --git a/policy/.gitignore b/policy/.gitignore
new file mode 100644
index 0000000..c04f1d1
--- /dev/null
+++ b/policy/.gitignore
@@ -0,0 +1,8 @@
+.deps
+.libs
+Makefile
+Makefile.in
+*.o
+*~
+*.policy
+
diff --git a/policy/Makefile.am b/policy/Makefile.am
new file mode 100644
index 0000000..f7c03d1
--- /dev/null
+++ b/policy/Makefile.am
@@ -0,0 +1,14 @@
+polkit_policydir = $(datadir)/polkit-1/actions
+dist_polkit_policy_DATA =					\
+	org.gnome.power.policy
+
+# You will need a recent intltool or the patch from this bug
+# http://bugzilla.gnome.org/show_bug.cgi?id=462312
+ INTLTOOL_POLICY_RULE@
+
+EXTRA_DIST = org.gnome.power.policy.in
+DISTCLEANFILES = org.gnome.power.policy
+
+clean-local :
+	rm -f *~
+
diff --git a/policy/org.gnome.power.policy.in b/policy/org.gnome.power.policy.in
new file mode 100644
index 0000000..2135ba8
--- /dev/null
+++ b/policy/org.gnome.power.policy.in
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE policyconfig PUBLIC
+ "-//freedesktop//DTD PolicyKit Policy Configuration 1.0//EN"
+ "http://www.freedesktop.org/standards/PolicyKit/1.0/policyconfig.dtd";>
+<policyconfig>
+
+  <!--
+    Policy definitions for GNOME Power Manager system-wide actions.
+    Copyright (c) 2010 Richard Hughes <richard hughsie com>
+  -->
+
+  <vendor>GNOME Power Manager</vendor>
+  <vendor_url>http://www.gnome.org/projects/gnome-power-manager/</vendor_url>
+  <icon_name>battery</icon_name>
+
+  <action id="org.gnome.power.backlight-helper">
+    <!-- SECURITY:
+          - A normal active user on the local machine does not need permission
+            to change the backlight brightness.
+     -->
+    <_description>Modify the laptop brightness</_description>
+    <_message>Authentication is required to modify the laptop brightness</_message>
+    <defaults>
+      <allow_any>no</allow_any>
+      <allow_inactive>no</allow_inactive>
+      <allow_active>yes</allow_active>
+    </defaults>
+    <annotate key="org.freedesktop.policykit.exec.path">/usr/sbin/gnome-power-backlight-helper</annotate>
+  </action>
+
+</policyconfig>
+
diff --git a/src/.gitignore b/src/.gitignore
index 1aef318..eff119e 100644
--- a/src/.gitignore
+++ b/src/.gitignore
@@ -5,6 +5,7 @@ gnome-power-manager
 gnome-power-preferences
 gnome-power-statistics
 gnome-power-self-test
+gnome-power-backlight-helper
 gpm-marshal.c
 gpm-marshal.h
 org.gnome.PowerManager.Backlight.h
diff --git a/src/Makefile.am b/src/Makefile.am
index 1e7f1f4..5aea83e 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -43,6 +43,10 @@ bin_PROGRAMS =						\
 	gnome-power-statistics				\
 	$(NULL)
 
+sbin_PROGRAMS =						\
+	gnome-power-backlight-helper			\
+	$(NULL)
+
 check_PROGRAMS =					\
 	gnome-power-self-test
 
@@ -66,6 +70,8 @@ libgpmshared_a_SOURCES =				\
 	egg-dbus-monitor.c				\
 	egg-discrete.h					\
 	egg-discrete.c					\
+	egg-string.h					\
+	egg-string.c					\
 	egg-console-kit.h				\
 	egg-console-kit.c				\
 	gpm-common.h					\
@@ -76,6 +82,19 @@ libgpmshared_a_SOURCES =				\
 	gpm-upower.h					\
 	$(NULL)
 
+gnome_power_backlight_helper_SOURCES =			\
+	gpm-backlight-helper.c				\
+	$(NULL)
+
+gnome_power_backlight_helper_LDADD =			\
+	libgpmshared.a					\
+	$(GLIB_LIBS)					\
+	-lm
+
+gnome_power_backlight_helper_CFLAGS =			\
+	$(WARNINGFLAGS)					\
+	$(NULL)
+
 gnome_power_statistics_SOURCES =			\
 	gpm-statistics.c				\
 	gpm-point-obj.c					\
diff --git a/src/gpm-backlight-helper.c b/src/gpm-backlight-helper.c
new file mode 100644
index 0000000..2b7646c
--- /dev/null
+++ b/src/gpm-backlight-helper.c
@@ -0,0 +1,247 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2010 Richard Hughes <richard hughsie 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 <unistd.h>
+#include <glib-object.h>
+#include <glib/gi18n.h>
+#include <locale.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#define GCM_BACKLIGHT_HELPER_EXIT_CODE_SUCCESS			0
+#define GCM_BACKLIGHT_HELPER_EXIT_CODE_FAILED			1
+#define GCM_BACKLIGHT_HELPER_EXIT_CODE_ARGUMENTS_INVALID	3
+#define GCM_BACKLIGHT_HELPER_EXIT_CODE_INVALID_USER		4
+
+/**
+ * gcm_backlight_helper_get_best_backlight:
+ **/
+static gchar *
+gcm_backlight_helper_get_best_backlight ()
+{
+	gchar *filename = NULL;
+	guint i;
+	gboolean ret;
+
+	/* available kernel interfaces in priority order */
+	static const gchar *backlight_interfaces[] = {
+		"asus-laptop",
+		"eeepc",
+		"thinkpad_screen",
+		"acpi_video1",
+		"mbp_backlight",
+		"acpi_video0",
+		"fujitsu-laptop",
+		"sony",
+		"samsung",
+		NULL,
+	};
+
+	/* search each one */
+	for (i=0; backlight_interfaces[i] != NULL; i++) {
+		filename = g_build_filename ("/sys/class/backlight", backlight_interfaces[i], NULL);
+		ret = g_file_test (filename, G_FILE_TEST_EXISTS);
+		if (ret)
+			return filename;
+		g_free (filename);
+	}
+	return NULL;
+}
+
+/**
+ * gcm_backlight_helper_write:
+ **/
+static gboolean
+gcm_backlight_helper_write (const gchar *filename, gint value, GError **error)
+{
+	gchar *text = NULL;
+	gint retval;
+	gint length;
+	gint fd = -1;
+	gboolean ret = TRUE;
+
+	fd = open (filename, O_WRONLY);
+	if (fd < 0) {
+		ret = FALSE;
+		g_set_error (error, 1, 0, "failed to open filename: %s", filename);
+		goto out;
+	}
+
+	/* convert to text */
+	text = g_strdup_printf ("%i", value);
+	length = strlen (text);
+
+	/* write to device file */
+	retval = write (fd, text, length);
+	if (retval != length) {
+		ret = FALSE;
+		g_set_error (error, 1, 0, "writing '%s' to %s failed", text, filename);
+		goto out;
+	}
+out:
+	if (fd >= 0)
+		close (fd);
+	g_free (text);
+	return ret;
+}
+
+/**
+ * main:
+ **/
+gint
+main (gint argc, gchar *argv[])
+{
+	GOptionContext *context;
+	gint uid;
+	gint euid;
+	guint retval = 0;
+	const gchar *pkexec_uid_str;
+	GError *error = NULL;
+	gboolean ret = FALSE;
+	gint set_brightness = -1;
+	gboolean get_brightness = FALSE;
+	gboolean get_max_brightness = FALSE;
+	gchar *filename = NULL;
+	gchar *filename_file = NULL;
+	gchar *contents = NULL;
+
+	const GOptionEntry options[] = {
+		{ "set-brightness", '\0', 0, G_OPTION_ARG_INT, &set_brightness,
+		   /* command line argument */
+		  _("Set the current brightness"), NULL },
+		{ "get-brightness", '\0', 0, G_OPTION_ARG_NONE, &get_brightness,
+		   /* command line argument */
+		  _("Get the current brightness"), NULL },
+		{ "get-max-brightness", '\0', 0, G_OPTION_ARG_NONE, &get_max_brightness,
+		   /* command line argument */
+		  _("Get the number of brightness levels supported"), NULL },
+		{ NULL}
+	};
+
+	/* setup translations */
+	setlocale (LC_ALL, "");
+	bindtextdomain (GETTEXT_PACKAGE, GNOMELOCALEDIR);
+	bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
+	textdomain (GETTEXT_PACKAGE);
+
+	/* setup type system */
+	g_type_init ();
+
+	context = g_option_context_new (NULL);
+	/* TRANSLATORS: tool that is used when copying profiles system-wide */
+	g_option_context_set_summary (context, _("GNOME Power Manager Backlight Helper"));
+	g_option_context_add_main_entries (context, options, NULL);
+	g_option_context_parse (context, &argc, &argv, NULL);
+	g_option_context_free (context);
+
+	/* no input */
+	if (set_brightness == -1 && !get_brightness && !get_max_brightness) {
+		/* TRANSLATORS: user did not specify valid options */
+		g_print ("%s\n", _("No valid option was specified"));
+		retval = GCM_BACKLIGHT_HELPER_EXIT_CODE_ARGUMENTS_INVALID;
+		goto out;
+	}
+
+	/* get calling process */
+	uid = getuid ();
+	euid = geteuid ();
+	if (uid != 0 || euid != 0) {
+		/* TRANSLATORS: only able to install profiles as root */
+		g_print ("%s\n", _("This program can only be used by the root user"));
+		retval = GCM_BACKLIGHT_HELPER_EXIT_CODE_ARGUMENTS_INVALID;
+		goto out;
+	}
+
+	/* check we're not being spoofed */
+	pkexec_uid_str = g_getenv ("PKEXEC_UID");
+	if (pkexec_uid_str == NULL) {
+		/* TRANSLATORS: the program must never be directly run */
+		g_print ("%s\n", _("This program must only be run through pkexec"));
+		retval = GCM_BACKLIGHT_HELPER_EXIT_CODE_INVALID_USER;
+		goto out;
+	}
+
+	/* find device */
+	filename = gcm_backlight_helper_get_best_backlight ();
+	if (filename == NULL) {
+		/* TRANSLATORS: no backlights found */
+		g_print ("%s\n", _("No backlights were found on your system"));
+		retval = GCM_BACKLIGHT_HELPER_EXIT_CODE_INVALID_USER;
+		goto out;
+	}
+
+	/* GetBrightness */
+	if (get_brightness) {
+		filename_file = g_build_filename (filename, "brightness", NULL);
+		ret = g_file_get_contents (filename_file, &contents, NULL, &error);
+		if (!ret) {
+			/* TRANSLATORS: failed to access backlight file */
+			g_print ("%s: %s\n", _("Could not get the value of the backlight"), error->message);
+			g_error_free (error);
+			retval = GCM_BACKLIGHT_HELPER_EXIT_CODE_ARGUMENTS_INVALID;
+			goto out;
+		}
+
+		/* just print the contents to stdout */
+		g_print ("%s", contents);
+	}
+
+	/* GetSteps */
+	if (get_max_brightness) {
+		filename_file = g_build_filename (filename, "max_brightness", NULL);
+		ret = g_file_get_contents (filename_file, &contents, NULL, &error);
+		if (!ret) {
+			/* TRANSLATORS: failed to access backlight file */
+			g_print ("%s: %s\n", _("Could not get the maximum value of the backlight"), error->message);
+			g_error_free (error);
+			retval = GCM_BACKLIGHT_HELPER_EXIT_CODE_ARGUMENTS_INVALID;
+			goto out;
+		}
+
+		/* just print the contents to stdout */
+		g_print ("%s", contents);
+	}
+
+	/* SetBrightness */
+	if (set_brightness != -1) {
+		filename_file = g_build_filename (filename, "brightness", NULL);
+		ret = gcm_backlight_helper_write (filename_file, set_brightness, &error);
+		if (!ret) {
+			/* TRANSLATORS: failed to access backlight file */
+			g_print ("%s: %s\n", _("Could not set the value of the backlight"), error->message);
+			g_error_free (error);
+			retval = GCM_BACKLIGHT_HELPER_EXIT_CODE_ARGUMENTS_INVALID;
+			goto out;
+		}
+	}
+
+	/* success */
+	retval = GCM_BACKLIGHT_HELPER_EXIT_CODE_SUCCESS;
+out:
+	g_free (filename);
+	g_free (filename_file);
+	g_free (contents);
+	return retval;
+}
+
diff --git a/src/gpm-brightness.c b/src/gpm-brightness.c
index 5396966..c39cad9 100644
--- a/src/gpm-brightness.c
+++ b/src/gpm-brightness.c
@@ -42,6 +42,7 @@
 
 #include "egg-discrete.h"
 #include "egg-debug.h"
+#include "egg-string.h"
 
 #include "gpm-brightness.h"
 #include "gpm-common.h"
@@ -66,6 +67,8 @@ struct GpmBrightnessPrivate
 	gboolean		 hw_changed;
 	/* A cache of XRRScreenResources is used as XRRGetScreenResources is expensive */
 	GPtrArray		*resources;
+	gint			 extension_levels;
+	gint			 extension_current;
 };
 
 enum {
@@ -85,6 +88,65 @@ static guint signals [LAST_SIGNAL] = { 0 };
 static gpointer gpm_brightness_object = NULL;
 
 /**
+ * gpm_brightness_helper_get_value:
+ **/
+static gint
+gpm_brightness_helper_get_value (const gchar *argument)
+{
+	gboolean ret;
+	GError *error = NULL;
+	gchar *stdout_data = NULL;
+	gint exit_status = 0;
+	gint value = -1;
+	gchar *command = NULL;
+
+	/* get the data */
+	command = g_strdup_printf ("pkexec /usr/sbin/gnome-power-backlight-helper --%s", argument);
+	ret = g_spawn_command_line_sync (command,
+					 &stdout_data, NULL, &exit_status, &error);
+	if (!ret) {
+		egg_error ("failed to get value: %s", error->message);
+		g_error_free (error);
+		goto out;
+	}
+	egg_debug ("executing %s retval: %i", command, exit_status);
+
+	/* parse for a number */
+	ret = egg_strtoint (stdout_data, &value);
+	if (!ret)
+		goto out;
+out:
+	g_free (command);
+	g_free (stdout_data);
+	return value;
+}
+
+/**
+ * gpm_brightness_helper_set_value:
+ **/
+static gboolean
+gpm_brightness_helper_set_value (const gchar *argument, gint value)
+{
+	gboolean ret;
+	GError *error = NULL;
+	gint exit_status = 0;
+	gchar *command = NULL;
+
+	/* get the data */
+	command = g_strdup_printf ("pkexec /usr/sbin/gnome-power-backlight-helper --%s %i", argument, value);
+	ret = g_spawn_command_line_sync (command, NULL, NULL, &exit_status, &error);
+	if (!ret) {
+		egg_error ("failed to get value: %s", error->message);
+		g_error_free (error);
+		goto out;
+	}
+	egg_debug ("executing %s retval: %i", command, exit_status);
+out:
+	g_free (command);
+	return ret;
+}
+
+/**
  * gpm_brightness_get_step:
  * @levels: The number of levels supported
  * Return value: the amount of hardware steps to do on each increment or decrement
@@ -456,6 +518,8 @@ gpm_brightness_foreach_screen (GpmBrightness *brightness, GpmXRandROp op)
 
 	g_return_val_if_fail (GPM_IS_BRIGHTNESS (brightness), FALSE);
 
+	return FALSE;
+
 	/* do for each screen */
 	length = brightness->priv->resources->len;
 	for (i=0; i<length; i++) {
@@ -523,6 +587,14 @@ gpm_brightness_set (GpmBrightness *brightness, guint percentage, gboolean *hw_ch
 	brightness->priv->hw_changed = FALSE;
 	ret = gpm_brightness_foreach_screen (brightness, ACTION_BACKLIGHT_SET);
 
+	/* legacy fallback */
+	if (!ret) {
+		if (brightness->priv->extension_levels < 0)
+			brightness->priv->extension_levels = gpm_brightness_helper_get_value ("get-max-brightness");
+		brightness->priv->extension_current = egg_discrete_from_percent (percentage, brightness->priv->extension_levels+1);
+		ret = gpm_brightness_helper_set_value ("set-brightness", brightness->priv->extension_current);
+	}
+
 	/* did the hardware have to be modified? */
 	if (ret && hw_changed != NULL)
 		*hw_changed = brightness->priv->hw_changed;
@@ -563,10 +635,19 @@ gpm_brightness_get (GpmBrightness *brightness, guint *percentage)
 	ret = gpm_brightness_foreach_screen (brightness, ACTION_BACKLIGHT_GET);
 	percentage_local = brightness->priv->shared_value;
 
+	/* legacy fallback */
+	if (!ret) {
+		if (brightness->priv->extension_levels < 0)
+			brightness->priv->extension_levels = gpm_brightness_helper_get_value ("get-max-brightness");
+		brightness->priv->extension_current = gpm_brightness_helper_get_value ("get-brightness");
+		percentage_local = egg_discrete_to_percent (brightness->priv->extension_current, brightness->priv->extension_levels+1);
+		ret = TRUE;
+	}
+
 	/* valid? */
 	if (percentage_local > 100) {
-		egg_warning ("percentage value of %i will be ignored", percentage_local);
-		ret = FALSE;
+		egg_warning ("percentage value of %i will be truncated", percentage_local);
+		percentage_local = 100;
 	}
 
 	/* a new value is always trusted if the method and checks succeed */
@@ -607,6 +688,19 @@ gpm_brightness_up (GpmBrightness *brightness, gboolean *hw_changed)
 	if (ret)
 		brightness->priv->cache_trusted = FALSE;
 
+	/* legacy fallback */
+	if (!ret) {
+		if (brightness->priv->extension_levels < 0)
+			brightness->priv->extension_levels = gpm_brightness_helper_get_value ("get-max-brightness");
+		brightness->priv->extension_current = gpm_brightness_helper_get_value ("get-brightness");
+		if (brightness->priv->extension_current < brightness->priv->extension_levels)
+			ret = gpm_brightness_helper_set_value ("set-brightness", ++brightness->priv->extension_current);
+		if (hw_changed != NULL)
+			*hw_changed = ret;
+		brightness->priv->cache_trusted = FALSE;
+		goto out;
+	}
+out:
 	return ret;
 }
 
@@ -637,6 +731,17 @@ gpm_brightness_down (GpmBrightness *brightness, gboolean *hw_changed)
 	if (ret)
 		brightness->priv->cache_trusted = FALSE;
 
+	/* legacy fallback */
+	if (!ret) {
+		brightness->priv->extension_current = gpm_brightness_helper_get_value ("get-brightness");
+		if (brightness->priv->extension_current > 0)
+			ret = gpm_brightness_helper_set_value ("set-brightness", --brightness->priv->extension_current);
+		if (hw_changed != NULL)
+			*hw_changed = ret;
+		brightness->priv->cache_trusted = FALSE;
+		goto out;
+	}
+out:
 	return ret;
 }
 
@@ -746,7 +851,17 @@ gboolean
 gpm_brightness_has_hw (GpmBrightness *brightness)
 {
 	g_return_val_if_fail (GPM_IS_BRIGHTNESS (brightness), FALSE);
-	return brightness->priv->has_extension;
+
+	/* use XRandR first */
+	if (brightness->priv->has_extension)
+		return TRUE;
+
+	/* fallback to legacy access */
+	if (brightness->priv->extension_levels < 0)
+		brightness->priv->extension_levels = gpm_brightness_helper_get_value ("get-max-brightness");
+	if (brightness->priv->extension_levels > 0)
+		return TRUE;
+	return FALSE;
 }
 
 /**
@@ -801,6 +916,7 @@ gpm_brightness_init (GpmBrightness *brightness)
 	brightness->priv->has_changed_events = FALSE;
 	brightness->priv->cache_percentage = 0;
 	brightness->priv->hw_changed = FALSE;
+	brightness->priv->extension_levels = -1;
 	brightness->priv->resources = g_ptr_array_new_with_free_func ((GDestroyNotify) XRRFreeScreenResources);
 
 	/* can we do this */
@@ -808,10 +924,8 @@ gpm_brightness_init (GpmBrightness *brightness)
 #ifdef HAVE_XRANDR_13
 	brightness->priv->has_randr13 = gpm_brightness_setup_version (brightness);
 #endif
-	if (brightness->priv->has_extension == FALSE) {
-		egg_debug ("no XRANDR extension, so aborting init");
-		return;
-	}
+	if (brightness->priv->has_extension == FALSE)
+		egg_debug ("no XRANDR extension");
 
 	screen = gdk_screen_get_default ();
 	window = gdk_screen_get_root_window (screen);



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