[Xfce4-commits] <xfce4-power-manager:master> Fix some issues with low power notifications.

Ali Abdallah noreply at xfce.org
Sat Jan 30 02:18:06 CET 2010


Updating branch refs/heads/master
         to df7818730f752678a89baf9625f798943401b95f (commit)
       from 805ac7034c1ace6ba2e417e4a9bded100c24920d (commit)

commit df7818730f752678a89baf9625f798943401b95f
Author: Ali Abdallah <ali at ali-xfce.org>
Date:   Fri Nov 6 10:46:18 2009 +0100

    Fix some issues with low power notifications.
    
    Brightness control now should be fully working, control of the lcd
    backlight is done using xrandr by default but if this fails and if
    HAL support is compiled then fallback, but still probably we need
    to provide a key to force the power manager to use HAL when HAL
    support is compiled because sometimes xrand reports that everything
    is fine but it fails silently to change the brightness level, uhh
    still too much suckiness in the backlight control on Linux.

 TODO                                         |    2 -
 common/xfpm-brightness.c                     |  276 ++++++++++++---
 common/xfpm-brightness.h                     |   23 +-
 panel-plugins/brightness/brightness-button.c |   10 +-
 src/Makefile.am                              |    4 +
 src/xfpm-backlight.c                         |  492 ++++++++++++++++++++++++++
 src/{xfpm-xfconf.h => xfpm-backlight.h}      |   30 +-
 src/xfpm-battery-info.c                      |    2 +-
 src/xfpm-battery.c                           |   27 +-
 src/xfpm-button.c                            |   16 +-
 src/xfpm-dkp.c                               |   33 ++-
 src/xfpm-idle.c                              |  382 ++++++++++++++++++++
 src/xfpm-idle.h                              |   77 ++++
 src/xfpm-manager.c                           |   19 +-
 src/xfpm-notify.c                            |    4 +-
 15 files changed, 1295 insertions(+), 102 deletions(-)

diff --git a/TODO b/TODO
index dd1ba55..23a6f0a 100644
--- a/TODO
+++ b/TODO
@@ -1,7 +1,5 @@
-* Reimplement critical battery action
 * Make xrandr brightness control working.
 * Reimplement the org.freedesktop.PowerManagement interface.
-* Battery information.
 * Hard drive spinning.
 * Survive D-Bus restarts.
 * Probably provide a PermissionDenied error on the inhibit interface?
diff --git a/common/xfpm-brightness.c b/common/xfpm-brightness.c
index 15bd984..fdee10d 100644
--- a/common/xfpm-brightness.c
+++ b/common/xfpm-brightness.c
@@ -57,12 +57,15 @@ struct XfpmBrightnessPrivate
     gint 		output;
     gboolean		xrandr_has_hw;
     
+    guint		max_level;
+    guint		current_level;
+    guint		min_level;
+    guint		step;
+    
 #ifdef WITH_HAL
     DBusGProxy         *hal_proxy;
     gboolean		hal_brightness_in_hw;
     gboolean		hal_hw_found;
-    guint		hal_max_level;
-    guint		hal_step;
 #endif
 };
 
@@ -97,8 +100,8 @@ out:
     return ret;
 }
 
-static gboolean G_GNUC_UNUSED
-xfpm_brightness_xrandr_get_current (XfpmBrightness *brightness, RROutput output, guint *current)
+static gboolean
+xfpm_brightness_xrandr_get_level (XfpmBrightness *brightness, RROutput output, guint *current)
 {
     unsigned long nitems;
     unsigned long bytes_after;
@@ -128,6 +131,27 @@ xfpm_brightness_xrandr_get_current (XfpmBrightness *brightness, RROutput output,
 }
 
 static gboolean
+xfpm_brightness_xrandr_set_level (XfpmBrightness *brightness, RROutput output, guint level)
+{
+    gboolean ret = TRUE;
+
+    gdk_error_trap_push ();
+    XRRChangeOutputProperty (GDK_DISPLAY (), output, brightness->priv->backlight, XA_INTEGER, 32,
+			     PropModeReplace, (unsigned char *) &level, 1);
+			     
+    XFlush (GDK_DISPLAY ());
+    gdk_flush ();
+    
+    if ( gdk_error_trap_pop () ) 
+    {
+	    g_warning ("failed to XRRChangeOutputProperty for brightness %i", level);
+	    ret = FALSE;
+    }
+    
+    return ret;
+}
+
+static gboolean
 xfpm_brightness_setup_xrandr (XfpmBrightness *brightness)
 {
     GdkScreen *screen;
@@ -180,10 +204,65 @@ xfpm_brightness_setup_xrandr (XfpmBrightness *brightness)
 	}
 	XRRFreeOutputInfo (info);
     }
+    return ret;
+}
+
+static gboolean
+xfpm_brightness_xrand_up (XfpmBrightness *brightness, guint *new_level)
+{
+    guint hw_level;
+    gboolean ret;
+    
+    ret = xfpm_brightness_xrandr_get_level (brightness, brightness->priv->output, &hw_level);
+    
+    if ( !ret )
+	return FALSE;
+	
+    if ( hw_level + brightness->priv->step <= brightness->priv->max_level)
+	ret = xfpm_brightness_xrandr_set_level (brightness, brightness->priv->output, hw_level + brightness->priv->step);
+    else
+	ret = xfpm_brightness_xrandr_set_level (brightness, brightness->priv->output, brightness->priv->max_level);
+	
+    ret = xfpm_brightness_xrandr_get_level (brightness, brightness->priv->output, new_level);
+    
+    if ( !ret )
+	return FALSE;
+	
+    /* Nothing changed in the hardware*/
+    if ( *new_level == hw_level )
+	return FALSE;
     
     return ret;
 }
 
+static gboolean
+xfpm_brightness_xrand_down (XfpmBrightness *brightness, guint *new_level)
+{
+    guint hw_level;
+    gboolean ret;
+    
+    ret = xfpm_brightness_xrandr_get_level (brightness, brightness->priv->output, &hw_level);
+    
+    if ( !ret )
+	return FALSE;
+	
+    if ( hw_level - brightness->priv->step >= brightness->priv->min_level)
+	ret = xfpm_brightness_xrandr_set_level (brightness, brightness->priv->output, hw_level - brightness->priv->step);
+    else
+	ret = xfpm_brightness_xrandr_set_level (brightness, brightness->priv->output, brightness->priv->min_level);
+	
+    ret = xfpm_brightness_xrandr_get_level (brightness, brightness->priv->output, new_level);
+    
+    if ( !ret )
+	return FALSE;
+    
+    /* Nothing changed in the hardware*/
+    if ( *new_level == hw_level )
+	return FALSE;
+    
+    return ret;
+
+}
 
 /*
  * Begin HAL optional brightness code. 
@@ -191,16 +270,15 @@ xfpm_brightness_setup_xrandr (XfpmBrightness *brightness)
  */
 
 #ifdef WITH_HAL
-static gint 
-xfpm_brightness_hal_get_level (XfpmBrightness *brg)
+static gboolean
+xfpm_brightness_hal_get_level (XfpmBrightness *brg, guint *level)
 {
     GError *error = NULL;
-    gint level = 0;
     gboolean ret = FALSE;
     
     ret = dbus_g_proxy_call (brg->priv->hal_proxy, "GetBrightness", &error,
 	 		     G_TYPE_INVALID,
-			     G_TYPE_INT, &level,
+			     G_TYPE_INT, level,
 			     G_TYPE_INVALID);
 
     if (error)
@@ -208,7 +286,8 @@ xfpm_brightness_hal_get_level (XfpmBrightness *brg)
 	g_warning ("GetBrightness failed : %s\n", error->message);
 	g_error_free (error);
     }
-    return level;
+    
+    return ret;
 }
 
 static gboolean
@@ -242,31 +321,50 @@ xfpm_brightness_hal_set_level (XfpmBrightness *brg, gint level)
 }
 
 
-static void
+static gboolean
 xfpm_brightness_hal_up (XfpmBrightness *brightness)
 {
-    gint hw_level;
+    guint hw_level;
+    gboolean ret = TRUE;
     
-    hw_level = xfpm_brightness_hal_get_level (brightness);
+    ret = xfpm_brightness_hal_get_level (brightness, &hw_level);
     
-    if ( hw_level != 0 )
+    if ( !ret )
+	return FALSE;
+	
+    if ( hw_level + brightness->priv->step <= brightness->priv->max_level )
     {
-	xfpm_brightness_hal_set_level (brightness, hw_level + brightness->priv->hal_step);
+	ret = xfpm_brightness_hal_set_level (brightness, hw_level + brightness->priv->step);
     }
+    else
+    {
+	ret = xfpm_brightness_hal_set_level (brightness, brightness->priv->max_level);
+    }
+    
+    return ret;
 }
 
-static void
+static gboolean
 xfpm_brightness_hal_down (XfpmBrightness *brightness)
 {
-    gint hw_level;
+    guint hw_level;
+    gboolean ret = TRUE;
     
-    hw_level = xfpm_brightness_hal_get_level (brightness);
+    ret = xfpm_brightness_hal_get_level (brightness, &hw_level);
     
-    if ( hw_level != 0 )
+    if ( !ret )
+	return FALSE;
+    
+    if ( hw_level - brightness->priv->step >= brightness->priv->min_level  )
+    {
+	ret = xfpm_brightness_hal_set_level (brightness, hw_level - brightness->priv->step);
+    }
+    else
     {
-	xfpm_brightness_hal_set_level (brightness, hw_level - brightness->priv->hal_step);
+	ret = xfpm_brightness_hal_set_level (brightness, brightness->priv->min_level);
     }
     
+    return ret;
 }
 
 static gboolean
@@ -290,14 +388,15 @@ xfpm_brightness_setup_hal (XfpmBrightness *brightness)
     device = hal_device_new ();
     hal_device_set_udi (device, udi[0]);
     
-    brightness->priv->hal_max_level = hal_device_get_property_int (device, "laptop_panel.num_levels") -1;
-    brightness->priv->hal_step = brightness->priv->hal_max_level <= 20 ? 1 : brightness->priv->hal_max_level / 20;
+    brightness->priv->max_level = hal_device_get_property_int (device, "laptop_panel.num_levels") - 1;
+    brightness->priv->step = brightness->priv->max_level <= 20 ? 1 : brightness->priv->max_level / 20;
+    brightness->priv->min_level = brightness->priv->step;
     brightness->priv->hal_hw_found = TRUE;
     
     if ( hal_device_has_key (device, "laptop_panel.brightness_in_hardware") )
 	brightness->priv->hal_brightness_in_hw = hal_device_get_property_bool (device ,"laptop_panel.brightness_in_hardware");
 	
-    TRACE ("laptop_panel.num_levels=%d\n", brightness->priv->hal_max_level);
+    TRACE ("laptop_panel.num_levels=%d\n", brightness->priv->max_level);
     
     g_object_unref (device);
 
@@ -310,10 +409,14 @@ xfpm_brightness_setup_hal (XfpmBrightness *brightness)
 							     "org.freedesktop.Hal.Device.LaptopPanel");
      
     if ( !brightness->priv->hal_proxy )
+    {
 	g_warning ("Unable to get proxy for device %s\n", udi[0]);
+	brightness->priv->hal_hw_found = FALSE;
+    }
     
     hal_manager_free_string_array (udi);
-    return FALSE;
+    
+    return brightness->priv->hal_hw_found;
 }
 #endif /* WITH_HAL*/
 
@@ -333,7 +436,18 @@ xfpm_brightness_init (XfpmBrightness *brightness)
     brightness->priv = XFPM_BRIGHTNESS_GET_PRIVATE (brightness);
     
     brightness->priv->resource = NULL;
+    brightness->priv->xrandr_has_hw = FALSE;
+    brightness->priv->max_level = 0;
+    brightness->priv->min_level = 0;
+    brightness->priv->current_level = 0;
+    brightness->priv->output = 0;
+    brightness->priv->step = 0;
     
+#ifdef WITH_HAL
+    brightness->priv->hal_proxy = NULL;
+    brightness->priv->hal_brightness_in_hw = FALSE;
+    brightness->priv->hal_hw_found = FALSE;
+#endif
 }
 
 static void
@@ -361,31 +475,68 @@ gboolean
 xfpm_brightness_setup (XfpmBrightness *brightness)
 {
     brightness->priv->xrandr_has_hw = xfpm_brightness_setup_xrandr (brightness);
-    
-    if ( !brightness->priv->xrandr_has_hw )
+
+    if ( brightness->priv->xrandr_has_hw )
     {
-	TRACE ("Unable to control brightness via xrandr, trying to use HAL");
-	if ( !xfpm_brightness_setup_hal (brightness) )
-	    return FALSE;
+	xfpm_brightness_xrand_get_limit (brightness,
+					 brightness->priv->output, 
+					 &brightness->priv->min_level, 
+					 &brightness->priv->max_level);
+	g_debug ("Brightness controlled by xrandr, min_level=%u max_level=%u", 
+		 brightness->priv->min_level, 
+		 brightness->priv->max_level);
+		 
     }
+#ifdef WITH_HAL    
+    else if ( !brightness->priv->xrandr_has_hw )
+    {
+	g_debug ("Unable to control brightness via xrandr, trying to use HAL");
+	if ( xfpm_brightness_setup_hal (brightness) )
+	    return TRUE;
+    }
+#endif
     
-    return TRUE;
+    return brightness->priv->xrandr_has_hw;
 }
 
-void xfpm_brightness_up	(XfpmBrightness *brightness)
+gboolean xfpm_brightness_up (XfpmBrightness *brightness, guint *new_level)
 {
+    gboolean ret = FALSE;
+    
+    if ( brightness->priv->xrandr_has_hw )
+    {
+	ret = xfpm_brightness_xrand_up (brightness, new_level);
+    }	
 #ifdef WITH_HAL
-    if ( brightness->priv->hal_hw_found )
-	xfpm_brightness_hal_up (brightness);
+    else if ( brightness->priv->hal_hw_found )
+    {
+	ret = xfpm_brightness_hal_up (brightness);
+	if ( ret )
+	    ret = xfpm_brightness_hal_get_level (brightness, new_level);
+    }
 #endif
+    return ret;
 }
 
-void xfpm_brightness_down (XfpmBrightness *brightness)
+gboolean xfpm_brightness_down (XfpmBrightness *brightness, guint *new_level)
 {
+    gboolean ret = FALSE;
+    
+    if ( brightness->priv->xrandr_has_hw )
+    {
+	ret = xfpm_brightness_xrand_down (brightness, new_level);
+	if ( ret )
+	    ret = xfpm_brightness_xrandr_get_level (brightness, brightness->priv->output, new_level);
+    }	
 #ifdef WITH_HAL
-    if ( brightness->priv->hal_hw_found )
-	xfpm_brightness_hal_down (brightness);
+    else if ( brightness->priv->hal_hw_found )
+    {
+	ret = xfpm_brightness_hal_down (brightness);
+	if ( ret )
+	    ret = xfpm_brightness_hal_get_level (brightness, new_level);
+    }
 #endif
+    return ret;
 }
 
 gboolean xfpm_brightness_has_hw (XfpmBrightness *brightness)
@@ -400,25 +551,66 @@ gboolean xfpm_brightness_has_hw (XfpmBrightness *brightness)
 
 guint xfpm_brightness_get_max_level (XfpmBrightness *brightness)
 {
+    return brightness->priv->max_level;
+}
+
+gboolean xfpm_brightness_get_level	(XfpmBrightness *brightness, guint *level)
+{
+    gboolean ret = FALSE;
+    
+    if ( brightness->priv->xrandr_has_hw )
+	ret = xfpm_brightness_xrandr_get_level (brightness, brightness->priv->output, level);
 #ifdef WITH_HAL
-    return brightness->priv->hal_max_level;
+    else if ( brightness->priv->hal_hw_found )
+	ret = xfpm_brightness_hal_get_level (brightness, level);
 #endif
-    return 0;
+
+    return ret;
 }
 
-guint xfpm_brightness_get_level	(XfpmBrightness *brightness)
+gboolean xfpm_brightness_set_level (XfpmBrightness *brightness, guint level)
 {
+    gboolean ret = FALSE;
+    
+    if (brightness->priv->xrandr_has_hw )
+	ret = xfpm_brightness_xrandr_set_level (brightness, brightness->priv->output, level);
 #ifdef WITH_HAL
-    return xfpm_brightness_hal_get_level (brightness);
+    else if ( brightness->priv->hal_hw_found )
+	ret = xfpm_brightness_hal_set_level (brightness, level);
 #endif
-    return 0;
+    
+    return ret;
 }
 
-gboolean xfpm_brightness_set_level (XfpmBrightness *brightness, guint level)
+gboolean xfpm_brightness_dim_down (XfpmBrightness *brightness)
 {
+    gboolean ret = FALSE;
+    
+    if (brightness->priv->xrandr_has_hw )
+	ret = xfpm_brightness_xrandr_set_level (brightness, brightness->priv->output, brightness->priv->min_level);
 #ifdef WITH_HAL
-    return xfpm_brightness_hal_set_level (brightness, level);
+    else if ( brightness->priv->hal_hw_found )
+	ret = xfpm_brightness_hal_set_level (brightness, brightness->priv->min_level);
 #endif
     
+    return ret;
+}
+
+XfpmBrightnessControl xfpm_brightness_get_control (XfpmBrightness *brightness)
+{
+    if ( brightness->priv->xrandr_has_hw )
+	return XFPM_BRIGHTNESS_CONTROL_XRANDR;
+#ifdef WITH_HAL
+    else if ( brightness->priv->hal_hw_found )
+	return XFPM_BRIGHTNESS_CONTROL_HAL;
+#endif
+    return XFPM_BRIGHTNESS_CONTROL_UNKNOWN;
+}
+
+gboolean xfpm_brightness_in_hw	(XfpmBrightness *brightness)
+{
+#ifdef WITH_HAL
+    return brightness->priv->hal_brightness_in_hw;
+#endif
     return FALSE;
 }
diff --git a/common/xfpm-brightness.h b/common/xfpm-brightness.h
index 91ef694..ba799e3 100644
--- a/common/xfpm-brightness.h
+++ b/common/xfpm-brightness.h
@@ -29,6 +29,14 @@ G_BEGIN_DECLS
 #define XFPM_BRIGHTNESS(o)          (G_TYPE_CHECK_INSTANCE_CAST ((o), XFPM_TYPE_BRIGHTNESS, XfpmBrightness))
 #define XFPM_IS_BRIGHTNESS(o)       (G_TYPE_CHECK_INSTANCE_TYPE ((o), XFPM_TYPE_BRIGHTNESS))
 
+typedef enum
+{
+    XFPM_BRIGHTNESS_CONTROL_UNKNOWN,
+    XFPM_BRIGHTNESS_CONTROL_XRANDR,
+    XFPM_BRIGHTNESS_CONTROL_HAL
+    
+} XfpmBrightnessControl;
+
 typedef struct XfpmBrightnessPrivate XfpmBrightnessPrivate;
 
 typedef struct
@@ -50,19 +58,28 @@ XfpmBrightness       	       *xfpm_brightness_new             (void);
 
 gboolean			xfpm_brightness_setup 		(XfpmBrightness *brightness);
 
-void				xfpm_brightness_up		(XfpmBrightness *brightness);
+gboolean			xfpm_brightness_up		(XfpmBrightness *brightness,
+								 guint *new_level);
 
-void				xfpm_brightness_down		(XfpmBrightness *brightness);
+gboolean			xfpm_brightness_down		(XfpmBrightness *brightness,
+								 guint *new_level);
 
 gboolean			xfpm_brightness_has_hw 		(XfpmBrightness *brightness);
 
 guint 				xfpm_brightness_get_max_level   (XfpmBrightness *brightness);
 
-guint 				xfpm_brightness_get_level	(XfpmBrightness *brightness);
+gboolean			xfpm_brightness_get_level	(XfpmBrightness *brightness,
+								 guint *level);
 
 gboolean			xfpm_brightness_set_level	(XfpmBrightness *brightness,
 								 guint level);
 
+gboolean			xfpm_brightness_dim_down	(XfpmBrightness *brightness);
+
+XfpmBrightnessControl		xfpm_brightness_get_control	(XfpmBrightness *brightness);
+
+gboolean			xfpm_brightness_in_hw		(XfpmBrightness *brightness);
+
 G_END_DECLS
 
 #endif /* __XFPM_BRIGHTNESS_H */
diff --git a/panel-plugins/brightness/brightness-button.c b/panel-plugins/brightness/brightness-button.c
index 833a981..839e697 100644
--- a/panel-plugins/brightness/brightness-button.c
+++ b/panel-plugins/brightness/brightness-button.c
@@ -186,7 +186,7 @@ static gboolean
 brightness_button_popup_win (GtkWidget *widget, GdkEvent *ev, guint32 ev_time)
 {
     gint x, y, orientation;
-    gint current_level;
+    guint current_level = 0;
     GdkDisplay *display;
     GdkScreen *screen;
     BrightnessButton *button;
@@ -304,7 +304,7 @@ brightness_button_popup_win (GtkWidget *widget, GdkEvent *ev, guint32 ev_time)
    
     gtk_window_move (GTK_WINDOW(button->priv->popup), x, y);
     TRACE("Displaying window on x=%d y=%d", x, y);
-    current_level = xfpm_brightness_get_level (button->priv->brightness);
+    xfpm_brightness_get_level (button->priv->brightness, &current_level);
     
     gtk_range_set_value (GTK_RANGE(button->priv->range), current_level);
     button->priv->popup_open = TRUE;
@@ -348,7 +348,7 @@ range_value_changed (GtkWidget *widget, BrightnessButton *button)
     
     range_level = (guint) gtk_range_get_value (GTK_RANGE (button->priv->range));
     
-    hw_level = xfpm_brightness_get_level (button->priv->brightness);
+    xfpm_brightness_get_level (button->priv->brightness, &hw_level);
     
     if ( hw_level != range_level )
     {
@@ -433,7 +433,7 @@ brightness_button_up (BrightnessButton *button)
     guint level;
     guint max_level;
     
-    level = xfpm_brightness_get_level (button->priv->brightness);
+    xfpm_brightness_get_level (button->priv->brightness, &level);
     max_level = xfpm_brightness_get_max_level (button->priv->brightness);
     
     if ( level != max_level )
@@ -446,7 +446,7 @@ static void
 brightness_button_down (BrightnessButton *button)
 {
     guint level;
-    level = xfpm_brightness_get_level (button->priv->brightness);
+    xfpm_brightness_get_level (button->priv->brightness, &level);
     
     if ( level != 0 )
     {
diff --git a/src/Makefile.am b/src/Makefile.am
index 8d53e75..ca99f27 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -15,6 +15,10 @@ xfce4_power_manager_SOURCES =                   \
 	xfpm-battery-info.h			\
 	xfpm-xfconf.c				\
 	xfpm-xfconf.h				\
+	xfpm-idle.c				\
+	xfpm-idle.h				\
+	xfpm-backlight.c			\
+	xfpm-backlight.h			\
 	xfpm-dpms.c				\
 	xfpm-dpms.h				\
 	xfpm-button.c				\
diff --git a/src/xfpm-backlight.c b/src/xfpm-backlight.c
new file mode 100644
index 0000000..b804fec
--- /dev/null
+++ b/src/xfpm-backlight.c
@@ -0,0 +1,492 @@
+/*
+ * * Copyright (C) 2009 Ali <aliov at xfce.org>
+ *
+ * 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
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <gtk/gtk.h>
+#include <libxfce4util/libxfce4util.h>
+
+#include "xfpm-backlight.h"
+#include "xfpm-idle.h"
+#include "xfpm-notify.h"
+#include "xfpm-xfconf.h"
+#include "xfpm-dkp.h"
+#include "xfpm-config.h"
+#include "xfpm-button.h"
+#include "xfpm-brightness.h"
+
+static void xfpm_backlight_finalize   (GObject *object);
+
+#define ALARM_DISABLED 9
+#define BRIGHTNESS_POPUP_SIZE	180
+
+#define XFPM_BACKLIGHT_GET_PRIVATE(o) \
+(G_TYPE_INSTANCE_GET_PRIVATE ((o), XFPM_TYPE_BACKLIGHT, XfpmBacklightPrivate))
+
+struct XfpmBacklightPrivate
+{
+    XfpmBrightness *brightness;
+    XfpmDkp        *dkp;
+    XfpmIdle       *idle;
+    XfpmXfconf     *conf;
+    XfpmButton     *button;
+    XfpmNotify     *notify;
+    
+    GtkWidget 	   *window;
+    GtkWidget      *progress_bar;
+    NotifyNotification *n;
+    
+    
+    gulong     	    timeout_id;
+    gulong	    destroy_id;
+    gboolean	    has_hw;
+    gboolean	    on_battery;
+    guint           last_level;
+    guint 	    max_level;
+#ifdef WITH_HAL
+    gboolean	    brightness_in_hw;
+#endif
+};
+
+G_DEFINE_TYPE (XfpmBacklight, xfpm_backlight, G_TYPE_OBJECT)
+
+static void
+xfpm_backlight_dim_brightness (XfpmBacklight *backlight)
+{
+    gboolean ret;
+    
+    ret = xfpm_brightness_get_level (backlight->priv->brightness, &backlight->priv->last_level);
+    
+    if ( !ret )
+    {
+	g_warning ("Unable to get current brightness level");
+	return;
+    }
+    TRACE ("Current brightness level : %u", brightness->priv->last_level);
+    
+    xfpm_brightness_dim_down (backlight->priv->brightness);
+}
+
+static gboolean
+xfpm_backlight_destroy_popup (gpointer data)
+{
+    XfpmBacklight *backlight;
+    
+    backlight = XFPM_BACKLIGHT (data);
+    
+    if ( backlight->priv->window )
+    {
+	gtk_widget_destroy (backlight->priv->window);
+	backlight->priv->window = NULL;
+    }
+    
+    if ( backlight->priv->n )
+    {
+	g_object_unref (backlight->priv->n);
+	backlight->priv->n = NULL;
+    }
+    
+    return FALSE;
+}
+
+static void
+xfpm_backlight_show_notification (XfpmBacklight *backlight, guint level, guint max_level)
+{
+    guint i;
+    gfloat value = 0;
+    NotifyNotification *n;
+    
+    static const char *display_icon_name[] = 
+    {
+	"notification-display-brightness-off",
+	"notification-display-brightness-low",
+	"notification-display-brightness-medium",
+	"notification-display-brightness-high",
+	"notification-display-brightness-full",
+	NULL
+    };
+    
+    if ( !backlight->priv->n )
+    {
+	n = xfpm_notify_new_notification (backlight->priv->notify, 
+					  NULL, 
+					  NULL, 
+					  NULL, 
+					  0, 
+					  XFPM_NOTIFY_NORMAL,
+					  NULL);
+    }
+    
+    value = (gfloat) 100 * level / max_level;
+    
+    i = (gint)value / 25;
+    
+    notify_notification_set_hint_int32  (n,
+					 "value",
+					 value);
+    
+    notify_notification_set_hint_string (n,
+					 "x-canonical-private-synchronous",
+					 "brightness");
+					 
+    notify_notification_update (n,
+			        " ",
+				"",
+				display_icon_name[i]);
+				
+    notify_notification_show (n, NULL);
+    backlight->priv->n = n;
+}
+
+static gboolean
+xfpm_backlight_hide_popup_timeout (XfpmBacklight *backlight)
+{
+    gtk_widget_hide (backlight->priv->window);
+    return FALSE;
+}
+
+static void
+xfpm_backlight_create_popup (XfpmBacklight *backlight)
+{
+    GtkWidget *vbox;
+    GtkWidget *img;
+    GtkWidget *align;
+    GtkObject *adj;
+    
+    if ( backlight->priv->window != NULL )
+	return;
+	
+    backlight->priv->window = gtk_window_new (GTK_WINDOW_POPUP);
+
+    g_object_set (G_OBJECT (backlight->priv->window), 
+		  "window-position", GTK_WIN_POS_CENTER_ALWAYS,
+		  "decorated", FALSE,
+		  "resizable", FALSE,
+		  "type-hint", GDK_WINDOW_TYPE_HINT_UTILITY,
+		  "app-paintable", TRUE,
+		  NULL);
+
+    gtk_window_set_default_size (GTK_WINDOW (backlight->priv->window), BRIGHTNESS_POPUP_SIZE, BRIGHTNESS_POPUP_SIZE);
+    
+    align = gtk_alignment_new (0., 0.5, 0, 0);
+    gtk_alignment_set_padding (GTK_ALIGNMENT (align), 5, 5, 5, 5);
+    
+    vbox = gtk_vbox_new (FALSE, 0);
+    
+    gtk_container_add (GTK_CONTAINER (backlight->priv->window), align);
+    gtk_container_add (GTK_CONTAINER (align), vbox);
+    
+    img = gtk_image_new_from_icon_name ("xfpm-brightness-lcd", GTK_ICON_SIZE_DIALOG);
+    
+    gtk_box_pack_start (GTK_BOX (vbox), img, TRUE, TRUE, 0);
+    
+    backlight->priv->progress_bar = gtk_progress_bar_new ();
+    
+    adj = gtk_adjustment_new (0., 0., backlight->priv->max_level, 1., 0., 0.);
+
+    g_object_set (G_OBJECT (backlight->priv->progress_bar),
+		  "adjustment", adj,
+		  NULL);
+    
+    gtk_box_pack_start (GTK_BOX (vbox), backlight->priv->progress_bar, TRUE, TRUE, 0);
+    
+    gtk_widget_show_all (align);
+}
+
+static void
+xfpm_backlight_show (XfpmBacklight *backlight, guint level)
+{
+    gboolean sync;
+    gboolean show_popup;
+    
+    g_debug ("Level %u", level);
+    
+    
+    g_object_get (G_OBJECT (backlight->priv->conf),
+                  SHOW_BRIGHTNESS_POPUP, &show_popup,
+                  NULL);
+		  
+    if ( !show_popup )
+	goto out;
+    
+    g_object_get (G_OBJECT (backlight->priv->notify),
+		  "sync", &sync,
+		  NULL);
+    
+    if ( sync )
+    {
+	xfpm_backlight_show_notification (backlight, level, backlight->priv->max_level);
+    }
+    else
+    {
+	GtkAdjustment *adj;
+	
+	xfpm_backlight_create_popup (backlight);
+	g_object_get (G_OBJECT (backlight->priv->progress_bar),
+		      "adjustment", &adj,
+		      NULL);
+	
+	gtk_adjustment_set_value (adj, level);
+	
+	if ( !GTK_WIDGET_VISIBLE (backlight->priv->window))
+	    gtk_window_present (GTK_WINDOW (backlight->priv->window));
+	
+	if ( backlight->priv->timeout_id != 0 )
+	    g_source_remove (backlight->priv->timeout_id);
+	    
+	backlight->priv->timeout_id = 
+	    g_timeout_add (900, (GSourceFunc) xfpm_backlight_hide_popup_timeout, backlight);
+    }
+    
+    if ( backlight->priv->destroy_id != 0 )
+    {
+	g_source_remove (backlight->priv->destroy_id);
+	backlight->priv->destroy_id = 0;
+    }
+    
+out:
+    /* Release the memory after 60 seconds */
+    backlight->priv->destroy_id = g_timeout_add_seconds (60, (GSourceFunc) xfpm_backlight_destroy_popup, backlight);
+}
+
+
+static void
+xfpm_backlight_alarm_timeout_cb (XfpmIdle *idle, guint id, XfpmBacklight *backlight)
+{
+    if ( id == TIMEOUT_BRIGHTNESS_ON_AC && !backlight->priv->on_battery)
+	xfpm_backlight_dim_brightness (backlight);
+    else if ( id == TIMEOUT_BRIGHTNESS_ON_BATTERY && backlight->priv->on_battery)
+	xfpm_backlight_dim_brightness (backlight);
+}
+
+static void
+xfpm_backlight_reset_cb (XfpmIdle *idle, XfpmBacklight *backlight)
+{
+    xfpm_brightness_set_level (backlight->priv->brightness, backlight->priv->last_level);
+}
+
+static void
+xfpm_backlight_button_pressed_cb (XfpmButton *button, XfpmButtonKey type, XfpmBacklight *backlight)
+{
+    guint level;
+    gboolean ret = TRUE;
+    
+    gboolean enable_brightness;
+    
+    g_object_get (G_OBJECT (backlight->priv->conf),
+                  ENABLE_BRIGHTNESS_CONTROL, &enable_brightness,
+                  NULL);
+    
+    if ( type == BUTTON_MON_BRIGHTNESS_UP )
+    {
+#ifdef WITH_HAL
+	if ( !backlight->priv->brightness_in_hw && enable_brightness)
+	    ret = xfpm_brightness_up (backlight->priv->brightness, &level);
+#else
+	if ( enable_brightness )
+	    ret = xfpm_brightness_up (backlight->priv->brightness, &level);
+#endif
+	if ( ret )
+	    xfpm_backlight_show (backlight, level);
+    }
+    else if ( type == BUTTON_MON_BRIGHTNESS_DOWN )
+    {
+#ifdef WITH_HAL
+	if ( !backlight->priv->brightness_in_hw && enable_brightness )
+	    ret = xfpm_brightness_down (backlight->priv->brightness, &level);
+#else
+	if ( enable_brightness )
+	    ret = xfpm_brightness_down (backlight->priv->brightness, &level);
+#endif
+	    
+	if ( ret )
+	    xfpm_backlight_show (backlight, level);
+    }
+}
+
+static void
+xfpm_backlight_brightness_on_ac_settings_changed (XfpmBacklight *backlight)
+{
+    guint timeout_on_ac;
+    
+    g_object_get (G_OBJECT (backlight->priv->conf),
+		  BRIGHTNESS_ON_AC, &timeout_on_ac,
+		  NULL);
+		  
+    if ( timeout_on_ac == ALARM_DISABLED )
+    {
+	xfpm_idle_free_alarm (backlight->priv->idle, TIMEOUT_BRIGHTNESS_ON_AC );
+    }
+    else
+    {
+	xfpm_idle_set_alarm (backlight->priv->idle, TIMEOUT_BRIGHTNESS_ON_AC, timeout_on_ac * 1000);
+    }
+}
+
+static void
+xfpm_backlight_brightness_on_battery_settings_changed (XfpmBacklight *backlight)
+{
+    guint timeout_on_battery ;
+    
+    g_object_get (G_OBJECT (backlight->priv->conf),
+		  BRIGHTNESS_ON_BATTERY, &timeout_on_battery,
+		  NULL);
+    
+    if ( timeout_on_battery == ALARM_DISABLED )
+    {
+	xfpm_idle_free_alarm (backlight->priv->idle, TIMEOUT_BRIGHTNESS_ON_BATTERY );
+    }
+    else
+    {
+	xfpm_idle_set_alarm (backlight->priv->idle, TIMEOUT_BRIGHTNESS_ON_BATTERY, timeout_on_battery * 1000);
+    } 
+}
+
+
+static void
+xfpm_backlight_set_timeouts (XfpmBacklight *backlight)
+{
+    xfpm_backlight_brightness_on_ac_settings_changed (backlight);
+    xfpm_backlight_brightness_on_battery_settings_changed (backlight);
+}
+
+static void
+xfpm_backlight_on_battery_changed_cb (XfpmDkp *dkp, gboolean on_battery, XfpmBacklight *backlight)
+{
+    backlight->priv->on_battery = on_battery;
+}
+
+static void
+xfpm_backlight_class_init (XfpmBacklightClass *klass)
+{
+    GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+    object_class->finalize = xfpm_backlight_finalize;
+
+    g_type_class_add_private (klass, sizeof (XfpmBacklightPrivate));
+}
+
+static void
+xfpm_backlight_init (XfpmBacklight *backlight)
+{
+    backlight->priv = XFPM_BACKLIGHT_GET_PRIVATE (backlight);
+    
+    backlight->priv->brightness = xfpm_brightness_new ();
+    backlight->priv->has_hw     = xfpm_brightness_setup (backlight->priv->brightness);
+    
+    backlight->priv->notify = NULL;
+    backlight->priv->idle   = NULL;
+    backlight->priv->conf   = NULL;
+    backlight->priv->button = NULL;
+    backlight->priv->dkp    = NULL;
+    backlight->priv->window = NULL;
+    backlight->priv->progress_bar = NULL;
+    backlight->priv->destroy_id = 0;
+    backlight->priv->timeout_id = 0;
+    
+    if ( !backlight->priv->has_hw )
+    {
+	g_object_unref (backlight->priv->brightness);
+	backlight->priv->brightness = NULL;
+    }
+    else
+    {
+	backlight->priv->idle   = xfpm_idle_new ();
+	backlight->priv->conf   = xfpm_xfconf_new ();
+	backlight->priv->button = xfpm_button_new ();
+	backlight->priv->dkp    = xfpm_dkp_get ();
+	backlight->priv->notify = xfpm_notify_new ();
+	backlight->priv->max_level = xfpm_brightness_get_max_level (backlight->priv->brightness);
+#ifdef WITH_HAL
+	if ( xfpm_brightness_get_control (backlight->priv->brightness) == XFPM_BRIGHTNESS_CONTROL_HAL )
+	    backlight->priv->brightness_in_hw = xfpm_brightness_in_hw (backlight->priv->brightness);
+#endif
+	g_signal_connect (backlight->priv->idle, "alarm-timeout",
+                          G_CALLBACK (xfpm_backlight_alarm_timeout_cb), backlight);
+        
+        g_signal_connect (backlight->priv->idle, "reset",
+                          G_CALLBACK(xfpm_backlight_reset_cb), backlight);
+			  
+	g_signal_connect (backlight->priv->button, "button-pressed",
+		          G_CALLBACK (xfpm_backlight_button_pressed_cb), backlight);
+			  
+	g_signal_connect_swapped (backlight->priv->conf, "notify::" BRIGHTNESS_ON_AC,
+				  G_CALLBACK (xfpm_backlight_brightness_on_ac_settings_changed), backlight);
+	
+	g_signal_connect_swapped (backlight->priv->conf, "notify::" BRIGHTNESS_ON_BATTERY,
+				  G_CALLBACK (xfpm_backlight_brightness_on_battery_settings_changed), backlight);
+				
+	g_signal_connect (backlight->priv->dkp, "on-battery-changed",
+			  G_CALLBACK (xfpm_backlight_on_battery_changed_cb), backlight);
+	g_object_get (G_OBJECT (backlight->priv->dkp),
+		      "on-battery", &backlight->priv->on_battery,
+		      NULL);
+	xfpm_backlight_set_timeouts (backlight);
+    }
+}
+
+static void
+xfpm_backlight_finalize (GObject *object)
+{
+    XfpmBacklight *backlight;
+
+    backlight = XFPM_BACKLIGHT (object);
+
+    xfpm_backlight_destroy_popup (backlight);
+
+    if ( backlight->priv->brightness )
+	g_object_unref (backlight->priv->brightness);
+
+    if ( backlight->priv->idle )
+	g_object_unref (backlight->priv->idle);
+
+    if ( backlight->priv->conf )
+	g_object_unref (backlight->priv->conf);
+
+    if ( backlight->priv->button )
+	g_object_unref (backlight->priv->button);
+
+    if ( backlight->priv->dkp )
+	g_object_unref (backlight->priv->dkp);
+
+    if ( backlight->priv->notify)
+	g_object_unref (backlight->priv->notify);
+
+    G_OBJECT_CLASS (xfpm_backlight_parent_class)->finalize (object);
+}
+
+XfpmBacklight *
+xfpm_backlight_new (void)
+{
+    XfpmBacklight *backlight = NULL;
+    backlight = g_object_new (XFPM_TYPE_BACKLIGHT, NULL);
+    return backlight;
+}
+
+gboolean xfpm_backlight_has_hw (XfpmBacklight *backlight)
+{
+    return backlight->priv->has_hw;
+}
diff --git a/src/xfpm-xfconf.h b/src/xfpm-backlight.h
similarity index 55%
copy from src/xfpm-xfconf.h
copy to src/xfpm-backlight.h
index 1fb4af1..3f9160d 100644
--- a/src/xfpm-xfconf.h
+++ b/src/xfpm-backlight.h
@@ -18,36 +18,38 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
  */
 
-#ifndef __XFPM_XFCONF_H
-#define __XFPM_XFCONF_H
+#ifndef __XFPM_BACKLIGHT_H
+#define __XFPM_BACKLIGHT_H
 
 #include <glib-object.h>
 
 G_BEGIN_DECLS
 
-#define XFPM_TYPE_XFCONF        (xfpm_xfconf_get_type () )
-#define XFPM_XFCONF(o)          (G_TYPE_CHECK_INSTANCE_CAST((o), XFPM_TYPE_XFCONF, XfpmXfconf))
-#define XFPM_IS_XFCONF(o)       (G_TYPE_CHECK_INSTANCE_TYPE((o), XFPM_TYPE_XFCONF))
+#define XFPM_TYPE_BACKLIGHT        (xfpm_backlight_get_type () )
+#define XFPM_BACKLIGHT(o)          (G_TYPE_CHECK_INSTANCE_CAST ((o), XFPM_TYPE_BACKLIGHT, XfpmBacklight))
+#define XFPM_IS_BACKLIGHT(o)       (G_TYPE_CHECK_INSTANCE_TYPE ((o), XFPM_TYPE_BACKLIGHT))
 
-typedef struct  XfpmXfconfPrivate XfpmXfconfPrivate;
+typedef struct XfpmBacklightPrivate XfpmBacklightPrivate;
 
 typedef struct
 {
-    GObject		  parent;
-    XfpmXfconfPrivate    *priv;
+    GObject         		parent;
+    XfpmBacklightPrivate       *priv;
     
-} XfpmXfconf;
+} XfpmBacklight;
 
 typedef struct
 {
-    GObjectClass	  parent_class;
+    GObjectClass 		parent_class;
     
-} XfpmXfconfClass;
+} XfpmBacklightClass;
 
-GType        		  xfpm_xfconf_get_type           	(void) G_GNUC_CONST;
+GType        			xfpm_backlight_get_type         (void) G_GNUC_CONST;
 
-XfpmXfconf       	 *xfpm_xfconf_new                 	(void);
+XfpmBacklight       	       *xfpm_backlight_new              (void);
+
+gboolean			xfpm_backlight_has_hw		(XfpmBacklight *backlight);
 
 G_END_DECLS
 
-#endif /* __XFPM_XFCONF_H */
+#endif /* __XFPM_BACKLIGHT_H */
diff --git a/src/xfpm-battery-info.c b/src/xfpm-battery-info.c
index 8042412..7dbf894 100644
--- a/src/xfpm-battery-info.c
+++ b/src/xfpm-battery-info.c
@@ -263,7 +263,7 @@ xfpm_battery_info (GHashTable *props)
     cstr = xfpm_battery_info_get_device_prop_string (props, "Serial");
     if ( cstr )
     {
-	xfpm_battery_info_add (table, pfd, _("Serial:"), cstr, i);
+	xfpm_battery_info_add (table, pfd, _("Serial number:"), cstr, i);
 	i++;
     }
     
diff --git a/src/xfpm-battery.c b/src/xfpm-battery.c
index b359bbd..ebc9a55 100644
--- a/src/xfpm-battery.c
+++ b/src/xfpm-battery.c
@@ -325,7 +325,7 @@ xfpm_battery_set_tooltip_primary (XfpmBattery *battery, GtkTooltip *tooltip)
 	if ( battery->priv->time_to_empty > 0 )
 	{
 	    est_time_str = xfpm_battery_get_time_string (battery->priv->time_to_empty);
-	    tip = g_strdup_printf (_("%s.\nYour %s is fully charged (%i%%).\nProvides %s runtime"), 
+	    tip = g_strdup_printf (_("%s\nYour %s is fully charged (%i%%).\nProvides %s runtime"), 
 				   power_status,
 				   battery_name, 
 				   battery->priv->percentage,
@@ -334,7 +334,7 @@ xfpm_battery_set_tooltip_primary (XfpmBattery *battery, GtkTooltip *tooltip)
 	}
 	else
 	{
-	    tip = g_strdup_printf (_("%s.\nYour %s is fully charged (%i%%)."), 
+	    tip = g_strdup_printf (_("%s\nYour %s is fully charged (%i%%)."), 
 				   power_status,
 				   battery_name,
 				   battery->priv->percentage);
@@ -345,7 +345,7 @@ xfpm_battery_set_tooltip_primary (XfpmBattery *battery, GtkTooltip *tooltip)
 	if ( battery->priv->time_to_full != 0 )
 	{
 	    est_time_str = xfpm_battery_get_time_string (battery->priv->time_to_full);
-	    tip = g_strdup_printf (_("%s.\nYour %s is charging (%i%%).\n%s until is fully charged."), 
+	    tip = g_strdup_printf (_("%s\nYour %s is charging (%i%%)\n%s until is fully charged."), 
 				   power_status,
 				   battery_name, 
 				   battery->priv->percentage, 
@@ -354,7 +354,7 @@ xfpm_battery_set_tooltip_primary (XfpmBattery *battery, GtkTooltip *tooltip)
 	}
 	else
 	{
-	    tip = g_strdup_printf (_("%s.\nYour %s is charging (%i%%)."),
+	    tip = g_strdup_printf (_("%s\nYour %s is charging (%i%%)."),
 				   power_status,
 				   battery_name,
 				   battery->priv->percentage);
@@ -365,7 +365,7 @@ xfpm_battery_set_tooltip_primary (XfpmBattery *battery, GtkTooltip *tooltip)
 	if ( battery->priv->time_to_empty != 0 )
 	{
 	    est_time_str = xfpm_battery_get_time_string (battery->priv->time_to_empty);
-	    tip = g_strdup_printf (_("%s.\nYour %s is discharging (%i%%).\n estimate time left is %s."), 
+	    tip = g_strdup_printf (_("%s\nYour %s is discharging (%i%%)\n estimate time left is %s."), 
 				   power_status,
 				   battery_name, 
 				   battery->priv->percentage, 
@@ -374,7 +374,7 @@ xfpm_battery_set_tooltip_primary (XfpmBattery *battery, GtkTooltip *tooltip)
 	}
 	else
 	{
-	    tip = g_strdup_printf (_("%s.\nYour %s is discharging (%i%%)."),
+	    tip = g_strdup_printf (_("%s\nYour %s is discharging (%i%%)."),
 				   power_status,
 				   battery_name,
 				   battery->priv->percentage);
@@ -383,15 +383,15 @@ xfpm_battery_set_tooltip_primary (XfpmBattery *battery, GtkTooltip *tooltip)
     }
     else if ( battery->priv->state == XFPM_DKP_DEVICE_STATE_PENDING_CHARGING )
     {
-	tip = g_strdup_printf (_("%s.\n%s waiting to discharge (%i%%)."), power_status, battery_name, battery->priv->percentage);
+	tip = g_strdup_printf (_("%s\n%s waiting to discharge (%i%%)."), power_status, battery_name, battery->priv->percentage);
     }
     else if ( battery->priv->state == XFPM_DKP_DEVICE_STATE_PENDING_DISCHARGING )
     {
-	tip = g_strdup_printf (_("%s.\n%s waiting to charge (%i%%)."), power_status, battery_name, battery->priv->percentage);
+	tip = g_strdup_printf (_("%s\n%s waiting to charge (%i%%)."), power_status, battery_name, battery->priv->percentage);
     }
     else if ( battery->priv->state == XFPM_DKP_DEVICE_STATE_EMPTY )
     {
-	tip = g_strdup_printf (_("%s.\nYour %s is empty"), power_status, battery_name);
+	tip = g_strdup_printf (_("%s\nYour %s is empty"), power_status, battery_name);
     }
     
     gtk_tooltip_set_text (tooltip, tip);
@@ -418,10 +418,15 @@ xfpm_battery_check_charge (XfpmBattery *battery)
     else if ( battery->priv->percentage <= critical_level )
 	charge = XFPM_BATTERY_CHARGE_CRITICAL;
 	
-    if ( charge != battery->priv->charge )
+    if ( charge != battery->priv->charge)
     {
 	battery->priv->charge = charge;
-	g_signal_emit (G_OBJECT (battery), signals [BATTERY_CHARGE_CHANGED], 0);
+	/*
+	 * only emit signal when when battery charge changes from ok->low->critical
+	 * and not the other way round.
+	 */
+	if ( battery->priv->charge != XFPM_BATTERY_CHARGE_CRITICAL || charge != XFPM_BATTERY_CHARGE_LOW )
+	    g_signal_emit (G_OBJECT (battery), signals [BATTERY_CHARGE_CHANGED], 0);
     }
 }
 
diff --git a/src/xfpm-button.c b/src/xfpm-button.c
index 1b10d3d..ed6cf52 100644
--- a/src/xfpm-button.c
+++ b/src/xfpm-button.c
@@ -258,9 +258,19 @@ xfpm_button_finalize (GObject *object)
 XfpmButton *
 xfpm_button_new (void)
 {
-    XfpmButton *button = NULL;
-    button = g_object_new (XFPM_TYPE_BUTTON, NULL);
-    return button;
+    static gpointer xfpm_button_object = NULL;
+    
+    if ( G_LIKELY (xfpm_button_object != NULL) )
+    {
+        g_object_ref (xfpm_button_object);
+    }
+    else
+    {
+        xfpm_button_object = g_object_new (XFPM_TYPE_BUTTON, NULL);
+        g_object_add_weak_pointer (xfpm_button_object, &xfpm_button_object);
+    }
+    
+    return XFPM_BUTTON (xfpm_button_object);
 }
 
 guint8 xfpm_button_get_mapped (XfpmButton *button)
diff --git a/src/xfpm-dkp.c b/src/xfpm-dkp.c
index 87c24ff..13b83ba 100644
--- a/src/xfpm-dkp.c
+++ b/src/xfpm-dkp.c
@@ -688,7 +688,12 @@ xfpm_dkp_show_critical_action_gtk (XfpmDkp *dkp)
     
     g_signal_connect_swapped (dialog, "destroy",
 			      G_CALLBACK (xfpm_dkp_close_critical_dialog), dkp);
-    
+    if ( dkp->priv->dialog )
+    {
+	gtk_widget_destroy (dkp->priv->dialog);
+	dkp->priv->dialog = NULL;
+	
+    }
     dkp->priv->dialog = dialog;
     gtk_widget_show_all (dialog);
 }
@@ -746,25 +751,39 @@ xfpm_dkp_system_on_low_power (XfpmDkp *dkp, XfpmBattery *battery)
 static void
 xfpm_dkp_battery_charge_changed_cb (XfpmBattery *battery, XfpmDkp *dkp)
 {
+    gboolean notify;
     XfpmBatteryCharge battery_charge;
     XfpmBatteryCharge current_charge;
     
     battery_charge = xfpm_battery_get_charge (battery);
     current_charge = xfpm_dkp_get_current_charge_state (dkp);
     
-    if ( current_charge == XFPM_BATTERY_CHARGE_CRITICAL )
+    if ( current_charge == XFPM_BATTERY_CHARGE_CRITICAL && dkp->priv->on_battery)
     {
 	xfpm_dkp_system_on_low_power (dkp, battery);
 	return;
     }
     
-    if ( battery_charge == XFPM_BATTERY_CHARGE_LOW )
+    g_object_get (G_OBJECT (dkp->priv->conf),
+		  GENERAL_NOTIFICATION_CFG, &notify,
+		  NULL);
+    
+    if ( current_charge == XFPM_BATTERY_CHARGE_LOW && dkp->priv->on_battery )
+    {
+	if ( notify )
+	    xfpm_notify_show_notification (dkp->priv->notify, 
+					   _("Xfce power manager"), 
+					   _("System is running on low power"), 
+					   gtk_status_icon_get_icon_name (GTK_STATUS_ICON (battery)),
+					   10000,
+					   FALSE,
+					   XFPM_NOTIFY_NORMAL,
+					   GTK_STATUS_ICON (battery));
+	
+    }
+    else if ( battery_charge == XFPM_BATTERY_CHARGE_LOW )
     {
-	gboolean notify;
 	
-	g_object_get (G_OBJECT (dkp->priv->conf),
-		      GENERAL_NOTIFICATION_CFG, &notify,
-		      NULL);
 	if ( notify )
 	    xfpm_notify_show_notification (dkp->priv->notify, 
 					   _("Xfce power manager"), 
diff --git a/src/xfpm-idle.c b/src/xfpm-idle.c
new file mode 100644
index 0000000..74d9af1
--- /dev/null
+++ b/src/xfpm-idle.c
@@ -0,0 +1,382 @@
+/*
+ * * Copyright (C) 2008-2009 Ali <aliov at xfce.org>
+ *
+ * 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
+ */
+
+/*
+ * Modified version of libidletime from gpm version 2.24.2
+ * Copyright (C) 2007 Richard Hughes <richard at hughsie.com>
+ */
+
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <glib.h>
+#include <X11/Xlib.h>
+#include <X11/extensions/sync.h>
+#include <gdk/gdkx.h>
+#include <gdk/gdk.h>
+
+#include "xfpm-idle.h"
+
+static void xfpm_idle_finalize   (GObject *object);
+
+#define XFPM_IDLE_GET_PRIVATE(o) \
+(G_TYPE_INSTANCE_GET_PRIVATE((o), XFPM_TYPE_IDLE, XfpmIdlePrivate))
+
+/*
+ * Undef and use the function instead of the macro
+ * as the macro is buggy.
+ */
+#ifdef XSyncValueAdd
+#undef XSyncValueAdd
+#endif
+
+struct XfpmIdlePrivate
+{
+    int 		sync_event;
+    XSyncCounter	idle_counter;
+    GPtrArray          *array;
+};
+
+typedef struct
+{
+    guint	id;
+    XSyncValue  timeout;
+    XSyncAlarm  xalarm;
+    
+} IdleAlarm;
+
+enum
+{
+    RESET,
+    ALARM_TIMEOUT,
+    LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
+G_DEFINE_TYPE(XfpmIdle, xfpm_idle, G_TYPE_OBJECT)
+
+static void
+xfpm_idle_class_init(XfpmIdleClass *klass)
+{
+    GObjectClass *object_class = G_OBJECT_CLASS(klass);
+
+     signals[RESET] =
+	    g_signal_new("reset",
+			 XFPM_TYPE_IDLE,
+			 G_SIGNAL_RUN_LAST,
+			 G_STRUCT_OFFSET(XfpmIdleClass, reset),
+			 NULL, NULL,
+			 g_cclosure_marshal_VOID__VOID,
+			 G_TYPE_NONE, 0, G_TYPE_NONE);
+
+    signals[ALARM_TIMEOUT] =
+	    g_signal_new("alarm-timeout",
+			 XFPM_TYPE_IDLE,
+			 G_SIGNAL_RUN_LAST,
+			 G_STRUCT_OFFSET(XfpmIdleClass, alarm_timeout),
+			 NULL, NULL,
+			 g_cclosure_marshal_VOID__INT,
+			 G_TYPE_NONE, 1, G_TYPE_INT);
+			 
+    object_class->finalize = xfpm_idle_finalize;
+
+    g_type_class_add_private(klass,sizeof(XfpmIdlePrivate));
+}
+
+static IdleAlarm *
+xfpm_idle_find_alarm (XfpmIdle *idle, guint id)
+{
+    guint i;
+    IdleAlarm *alarm;
+    for (i = 0; i<idle->priv->array->len; i++) 
+    {
+	alarm = g_ptr_array_index (idle->priv->array, i);
+	if (alarm->id == id)
+	{
+	    return alarm;
+	}
+    }
+    return NULL;
+}
+
+static void
+xfpm_idle_xsync_alarm_set (XfpmIdle *idle, IdleAlarm *alarm, gboolean positive)
+{
+    XSyncAlarmAttributes attr;
+    XSyncValue delta;
+    unsigned int flags;
+    XSyncTestType test;
+
+    if (positive) 
+	test = XSyncPositiveComparison;
+    else 
+	test = XSyncNegativeComparison;
+
+    XSyncIntToValue (&delta, 0);
+
+    attr.trigger.counter = idle->priv->idle_counter;
+    attr.trigger.value_type = XSyncAbsolute;
+    attr.trigger.test_type = test;
+    attr.trigger.wait_value = alarm->timeout;
+    attr.delta = delta;
+
+    flags = XSyncCACounter | XSyncCAValueType | XSyncCATestType | XSyncCAValue | XSyncCADelta;
+
+    if ( alarm->xalarm ) 
+	XSyncChangeAlarm ( GDK_DISPLAY (), alarm->xalarm, flags, &attr);
+    else 
+	alarm->xalarm = XSyncCreateAlarm (GDK_DISPLAY (), flags, &attr);
+}
+
+static void
+xfpm_idle_xsync_value_add_one (XSyncValue *from, XSyncValue *to)
+{
+    int overflow;
+    XSyncValue add;
+    XSyncIntToValue (&add, -1);
+    XSyncValueAdd (to, *from, add, &overflow);
+}
+
+static void
+xfpm_idle_x_set_reset (XfpmIdle *idle, XSyncAlarmNotifyEvent *alarm_event)
+{
+    IdleAlarm *alarm;
+    
+    alarm = xfpm_idle_find_alarm (idle, 0);
+    xfpm_idle_xsync_value_add_one (&alarm_event->counter_value, &alarm->timeout);
+    xfpm_idle_xsync_alarm_set (idle, alarm, FALSE);
+}
+
+static IdleAlarm *
+xfpm_idle_alarm_find_event (XfpmIdle *idle, XSyncAlarmNotifyEvent *alarm_event)
+{
+    guint i;
+    IdleAlarm *alarm;
+    
+    for (i=0; i<idle->priv->array->len; i++) 
+    {
+	alarm = g_ptr_array_index (idle->priv->array, i);
+	if (alarm_event->alarm == alarm->xalarm) 
+	{
+	    return alarm;
+	}
+    }
+    return NULL;
+}
+
+static GdkFilterReturn
+xfpm_idle_x_event_filter (GdkXEvent *gdkxevent, GdkEvent *event, gpointer data)
+{
+    IdleAlarm *alarm;
+    XfpmIdle *idle = (XfpmIdle *) data;
+    XEvent *xevent = ( XEvent *) gdkxevent;
+    XSyncAlarmNotifyEvent *alarm_event;
+    
+    if ( xevent->type != idle->priv->sync_event + XSyncAlarmNotify )
+        return GDK_FILTER_CONTINUE;
+    
+    alarm_event = (XSyncAlarmNotifyEvent *) xevent;
+    
+    alarm = xfpm_idle_alarm_find_event (idle, alarm_event);
+    
+    if ( alarm )
+    {
+	if (alarm->id != 0 )
+	{
+	    g_signal_emit (G_OBJECT(idle), signals[ALARM_TIMEOUT], 0, alarm->id );
+	    xfpm_idle_x_set_reset (idle, alarm_event);
+	    return GDK_FILTER_CONTINUE;
+	}
+	xfpm_idle_alarm_reset_all (idle);
+    }
+    
+    return GDK_FILTER_CONTINUE;
+}
+
+static IdleAlarm *
+xfpm_idle_new_alarm_internal (XfpmIdle *idle, guint id)
+{
+    IdleAlarm *alarm;
+    alarm = g_new0 (IdleAlarm, 1);
+    alarm->id = id;
+    g_ptr_array_add (idle->priv->array, alarm);
+    
+    return alarm;
+}
+
+static void
+xfpm_idle_init (XfpmIdle *idle)
+{
+    IdleAlarm *alarm;
+    int sync_error = 0;
+    int ncounters;
+    XSyncSystemCounter *counters;
+    int i;
+    
+    idle->priv = XFPM_IDLE_GET_PRIVATE(idle);
+    
+    idle->priv->array = g_ptr_array_new ();
+    idle->priv->sync_event = 0;
+    
+    if (!XSyncQueryExtension (GDK_DISPLAY (), &idle->priv->sync_event, &sync_error) )
+    {
+	g_warning ("No Sync extension.");
+	return;
+    }
+    
+    counters = XSyncListSystemCounters (GDK_DISPLAY (), &ncounters);
+    
+    for ( i = 0; i < ncounters && !idle->priv->idle_counter; i++)
+    {
+	if (!strcmp(counters[i].name, "IDLETIME"))
+	    idle->priv->idle_counter = counters[i].counter;
+    }
+    
+    XSyncFreeSystemCounterList (counters);
+    
+    if ( !idle->priv->idle_counter )
+    {
+	g_warning ("No idle counter.");
+	return;
+    }
+    
+    gdk_window_add_filter (NULL, xfpm_idle_x_event_filter, idle);
+    
+    alarm = xfpm_idle_new_alarm_internal (idle, 0);
+}
+
+static void
+xfpm_idle_free_alarm_internal (XfpmIdle *idle, IdleAlarm *alarm)
+{
+    gdk_error_trap_push ();
+    XSyncDestroyAlarm (GDK_DISPLAY(), alarm->xalarm);
+    gdk_flush ();
+    gdk_error_trap_pop ();
+    g_free(alarm);
+    g_ptr_array_remove (idle->priv->array, alarm);
+}
+
+static void
+xfpm_idle_finalize(GObject *object)
+{
+    guint i;
+    XfpmIdle *idle;
+    IdleAlarm *alarm;
+    
+    idle = XFPM_IDLE(object);
+
+    for ( i = 0; i<idle->priv->array->len; i++) 
+    {
+	alarm = g_ptr_array_index (idle->priv->array, i);
+	xfpm_idle_free_alarm_internal (idle, alarm);
+    }
+    g_ptr_array_free (idle->priv->array, TRUE);
+    
+    gdk_window_remove_filter (NULL, xfpm_idle_x_event_filter, idle);
+
+    G_OBJECT_CLASS(xfpm_idle_parent_class)->finalize(object);
+}
+
+XfpmIdle *
+xfpm_idle_new(void)
+{
+    XfpmIdle *idle = NULL;
+    idle = g_object_new (XFPM_TYPE_IDLE,NULL);
+    return idle;
+}
+
+gboolean 
+xfpm_idle_set_alarm (XfpmIdle *idle, guint id, gint timeout)
+{
+    IdleAlarm *alarm;
+    
+    g_return_val_if_fail (XFPM_IS_IDLE (idle), FALSE);
+    
+    if ( id == 0 )
+	return FALSE;
+	
+    if ( timeout == 0 )
+	return FALSE;
+    
+    alarm = xfpm_idle_find_alarm (idle, id);
+    
+    if ( !alarm )
+    {
+	alarm = xfpm_idle_new_alarm_internal (idle, id);
+    }
+    
+    XSyncIntToValue (&alarm->timeout, timeout);
+    xfpm_idle_xsync_alarm_set (idle, alarm, TRUE);
+    return TRUE;
+}
+
+void
+xfpm_idle_alarm_reset_all (XfpmIdle *idle)
+{
+    guint i;
+    IdleAlarm *alarm;
+
+    for ( i=1; i<idle->priv->array->len; i++) 
+    {
+	alarm = g_ptr_array_index (idle->priv->array, i);
+	xfpm_idle_xsync_alarm_set (idle, alarm, TRUE);
+    }
+	
+    g_signal_emit (G_OBJECT(idle), signals[RESET], 0 );
+}
+
+gboolean xfpm_idle_free_alarm (XfpmIdle *idle, guint id)
+{
+    IdleAlarm *alarm;
+    
+    g_return_val_if_fail (XFPM_IS_IDLE (idle), FALSE);
+    
+    if ( id == 0 )
+	return FALSE;
+	
+    alarm = xfpm_idle_find_alarm (idle, id);
+    
+    if ( alarm )
+    {
+	xfpm_idle_free_alarm_internal (idle, alarm);
+	return TRUE;
+    }
+    
+    return FALSE;
+}
+
+void xfpm_idle_reset_alarm (XfpmIdle *idle, guint id)
+{
+    IdleAlarm *alarm;
+    
+    alarm = xfpm_idle_find_alarm (idle, id);
+    
+    if ( alarm )
+    {
+	xfpm_idle_xsync_alarm_set (idle, alarm, TRUE);
+    }
+}
diff --git a/src/xfpm-idle.h b/src/xfpm-idle.h
new file mode 100644
index 0000000..03a70b8
--- /dev/null
+++ b/src/xfpm-idle.h
@@ -0,0 +1,77 @@
+/*
+ * * Copyright (C) 2008-2009 Ali <aliov at xfce.org>
+ *
+ * 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 __XFPM_IDLE_H
+#define __XFPM_IDLE_H
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define XFPM_TYPE_IDLE        (xfpm_idle_get_type () )
+#define XFPM_IDLE(o)          (G_TYPE_CHECK_INSTANCE_CAST((o), XFPM_TYPE_IDLE, XfpmIdle))
+#define XFPM_IS_IDLE(o)       (G_TYPE_CHECK_INSTANCE_TYPE((o), XFPM_TYPE_IDLE))
+
+enum
+{
+    TIMEOUT_INPUT = 0,
+    TIMEOUT_BRIGHTNESS_ON_AC,
+    TIMEOUT_BRIGHTNESS_ON_BATTERY,
+    TIMEOUT_INACTIVITY_ON_AC,
+    TIMEOUT_INACTIVITY_ON_BATTERY
+};
+
+typedef struct XfpmIdlePrivate XfpmIdlePrivate;
+
+typedef struct
+{
+    GObject		  parent;
+    XfpmIdlePrivate	 *priv;
+    
+} XfpmIdle;
+
+typedef struct
+{
+    GObjectClass 	  parent_class;
+    
+    void                 (*alarm_timeout)	    (XfpmIdle *idle,
+						     guint id);
+						     
+    void		 (*reset)		    (XfpmIdle *idle);
+    
+} XfpmIdleClass;
+
+GType        		  xfpm_idle_get_type        (void) G_GNUC_CONST;
+XfpmIdle       		 *xfpm_idle_new             (void);
+
+gboolean                  xfpm_idle_set_alarm       (XfpmIdle *idle,
+						     guint id,
+						     gint timeout);
+						     
+void                      xfpm_idle_alarm_reset_all (XfpmIdle *idle);
+
+gboolean                  xfpm_idle_free_alarm      (XfpmIdle *idle,
+						     guint id);
+					    
+void			  xfpm_idle_reset_alarm	    (XfpmIdle *idle,
+						     guint id);
+G_END_DECLS
+
+#endif /* __XFPM_IDLE_H */
diff --git a/src/xfpm-manager.c b/src/xfpm-manager.c
index 822b8b4..5366637 100644
--- a/src/xfpm-manager.c
+++ b/src/xfpm-manager.c
@@ -43,7 +43,7 @@
 #include "xfpm-dpms.h"
 #include "xfpm-manager.h"
 #include "xfpm-button.h"
-#include "xfpm-brightness.h"
+#include "xfpm-backlight.h"
 #include "xfpm-config.h"
 #include "xfpm-debug.h"
 #include "xfpm-xfconf.h"
@@ -74,7 +74,7 @@ struct XfpmManagerPrivate
     XfpmDkp         *dkp;
     XfpmButton      *button;
     XfpmXfconf      *conf;
-    XfpmBrightness  *brightness;
+    XfpmBacklight   *backlight;
 #ifdef HAVE_DPMS
     XfpmDpms        *dpms;
 #endif
@@ -125,8 +125,7 @@ xfpm_manager_finalize (GObject *object)
     g_object_unref (manager->priv->dpms);
 #endif
     
-    if ( manager->priv->brightness )
-	g_object_unref (manager->priv->brightness);
+    g_object_unref (manager->priv->backlight);
 	
     G_OBJECT_CLASS (xfpm_manager_parent_class)->finalize (object);
 }
@@ -359,18 +358,12 @@ void xfpm_manager_start (XfpmManager *manager)
     manager->priv->button = xfpm_button_new ();
     manager->priv->conf = xfpm_xfconf_new ();
    
-    manager->priv->brightness = xfpm_brightness_new ();
+    manager->priv->backlight = xfpm_backlight_new ();
     
 #ifdef HAVE_DPMS
     manager->priv->dpms = xfpm_dpms_new ();
 #endif
     
-    if ( !xfpm_brightness_setup (manager->priv->brightness) )
-    {
-	g_object_unref (manager->priv->brightness);
-	manager->priv->brightness = NULL;
-    }
-     
     g_signal_connect (manager->priv->button, "button_pressed",
 		      G_CALLBACK (xfpm_manager_button_pressed_cb), manager);
     
@@ -485,6 +478,7 @@ static gboolean xfpm_manager_dbus_get_config (XfpmManager *manager,
 		  NULL);
     
     has_battery = xfpm_dkp_has_battery (manager->priv->dkp);
+    has_lcd_brightness = xfpm_backlight_has_hw (manager->priv->backlight);
     
     mapped_buttons = xfpm_button_get_mapped (manager->priv->button);
     
@@ -506,9 +500,8 @@ static gboolean xfpm_manager_dbus_get_config (XfpmManager *manager,
     g_hash_table_insert (*OUT_config, g_strdup ("has-battery"), g_strdup (xfpm_bool_to_string (has_battery)));
     g_hash_table_insert (*OUT_config, g_strdup ("has-lid"), g_strdup (xfpm_bool_to_string (has_lid)));
     
-    /*
     g_hash_table_insert (*OUT_config, g_strdup ("has-brightness"), g_strdup (xfpm_bool_to_string (has_lcd_brightness)));
-    */
+    
     return TRUE;
 }
 					      
diff --git a/src/xfpm-notify.c b/src/xfpm-notify.c
index 38d5bef..17a896c 100644
--- a/src/xfpm-notify.c
+++ b/src/xfpm-notify.c
@@ -218,7 +218,9 @@ xfpm_notify_new_notification_internal (const gchar *title, const gchar *message,
     	notify_notification_attach_to_status_icon (n, icon);
 	
     notify_notification_set_urgency (n, (NotifyUrgency)urgency);
-    notify_notification_set_timeout (n, timeout);
+    
+    if ( timeout != 0)
+	notify_notification_set_timeout (n, timeout);
     
     return n;
 }



More information about the Xfce4-commits mailing list