--- gnome-power-manager-2.32.0-r1-orig/work/gnome-power-manager-2.32.0/src/Makefile.am 2010-08-06 15:31:02.000000000 +0100 +++ gnome-power-manager-2.32.0-r1-orig/work/gnome-power-manager-2.32.0/src/Makefile.am 2011-05-10 09:21:24.047312466 +0100 @@ -146,6 +146,8 @@ gpm-phone.c \ gpm-backlight.h \ gpm-backlight.c \ + gpm-backlight-kbd.h \ + gpm-backlight-kbd.c \ gpm-prefs-server.h \ gpm-prefs-server.c \ gpm-idle.h \ --- gnome-power-manager-2.32.0-r1-orig/work/gnome-power-manager-2.32.0/src/gpm-backlight-kbd.c 1970-01-01 01:00:00.000000000 +0100 +++ gnome-power-manager-2.32.0-r1-orig/work/gnome-power-manager-2.32.0/src/gpm-backlight-kbd.c 2011-05-10 09:42:22.287313091 +0100 @@ -0,0 +1,681 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- + * + * Copyright (C) 2010 Alex Murray + * Copyright (C) 2005-2009 Richard Hughes + * Copyright (C) 2005 William Jon McCann + * + * 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 +#endif + +#include +#include +#include +#include + +#include +#include +#include +#include +#ifdef HAVE_UNISTD_H +#include +#endif /* HAVE_UNISTD_H */ + +#include +#include +#include +#include + +#include "gpm-button.h" +#include "gpm-backlight-kbd.h" +#include "gpm-control.h" +#include "gpm-common.h" +#include "egg-debug.h" +#include "gsd-media-keys-window.h" +#include "gpm-dpms.h" +#include "gpm-idle.h" +#include "gpm-marshal.h" +#include "gpm-stock-icons.h" +#include "gpm-prefs-server.h" +#include "egg-console-kit.h" + +#define GPM_BACKLIGHT_KBD_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GPM_TYPE_BACKLIGHT_KBD, GpmBacklightKbdPrivate)) + +struct GpmBacklightKbdPrivate +{ + UpClient *client; + DBusGProxy *proxy; + GpmButton *button; + GConfClient *conf; + GtkWidget *popup; + GpmControl *control; + GpmDpms *dpms; + GpmIdle *idle; + EggConsoleKit *consolekit; + gboolean system_is_idle; + GTimer *idle_timer; + guint idle_dim_timeout; + gint master_percentage; + gint max_brightness; + gboolean off; +}; + +G_DEFINE_TYPE (GpmBacklightKbd, gpm_backlight_kbd, G_TYPE_OBJECT) + +#define BACKLIGHT_KBD_SERVICE "org.freedesktop.UPower" +#define BACKLIGHT_KBD_PATH "/org/freedesktop/UPower/KbdBacklight" +#define BACKLIGHT_KBD_INTERFACE "org.freedesktop.UPower.KbdBacklight" + +/** + * gpm_backlight_kbd_dialog_init: + * + * Initialises the popup, and makes sure that it matches the compositing of the screen. + **/ +static void +gpm_backlight_kbd_dialog_init (GpmBacklightKbd *backlight_kbd) +{ + if (backlight_kbd->priv->popup != NULL + && !gsd_media_keys_window_is_valid (GSD_MEDIA_KEYS_WINDOW (backlight_kbd->priv->popup))) { + gtk_widget_destroy (backlight_kbd->priv->popup); + backlight_kbd->priv->popup = NULL; + } + + if (backlight_kbd->priv->popup == NULL) { + backlight_kbd->priv->popup= gsd_media_keys_window_new (); + gsd_media_keys_window_set_action_custom (GSD_MEDIA_KEYS_WINDOW (backlight_kbd->priv->popup), + "gpm-brightness-kbd", + TRUE); + gtk_window_set_position (GTK_WINDOW (backlight_kbd->priv->popup), GTK_WIN_POS_NONE); + } +} + +/** + * gpm_backlight_kbd_dialog_show: + * + * Show the brightness popup, and place it nicely on the screen. + **/ +static void +gpm_backlight_kbd_dialog_show (GpmBacklightKbd *backlight_kbd) +{ + int orig_w; + int orig_h; + int screen_w; + int screen_h; + int x; + int y; + int pointer_x; + int pointer_y; + GtkRequisition win_req; + GdkScreen *pointer_screen; + GdkRectangle geometry; + int monitor; + + /* + * get the window size + * if the window hasn't been mapped, it doesn't necessarily + * know its true size, yet, so we need to jump through hoops + */ + gtk_window_get_default_size (GTK_WINDOW (backlight_kbd->priv->popup), &orig_w, &orig_h); + gtk_widget_size_request (backlight_kbd->priv->popup, &win_req); + + if (win_req.width > orig_w) { + orig_w = win_req.width; + } + if (win_req.height > orig_h) { + orig_h = win_req.height; + } + + pointer_screen = NULL; + gdk_display_get_pointer (gtk_widget_get_display (backlight_kbd->priv->popup), + &pointer_screen, + &pointer_x, + &pointer_y, + NULL); + monitor = gdk_screen_get_monitor_at_point (pointer_screen, + pointer_x, + pointer_y); + + gdk_screen_get_monitor_geometry (pointer_screen, + monitor, + &geometry); + + screen_w = geometry.width; + screen_h = geometry.height; + + x = ((screen_w - orig_w) / 2) + geometry.x; + y = geometry.y + (screen_h / 2) + (screen_h / 2 - orig_h) / 2; + + gtk_window_move (GTK_WINDOW (backlight_kbd->priv->popup), x, y); + + gtk_widget_show (backlight_kbd->priv->popup); + + gdk_display_sync (gtk_widget_get_display (backlight_kbd->priv->popup)); +} + +/** + * gpm_backlight_kbd_brightness_evaluate_and_set: + **/ +static gboolean +gpm_backlight_kbd_brightness_evaluate_and_set (GpmBacklightKbd *backlight_kbd, gboolean interactive) +{ + gfloat brightness; + gfloat scale; + gboolean ret; + gboolean on_battery; + gboolean do_laptop_lcd; + gboolean enable_action; + gboolean battery_reduce; + GError *error = NULL; + gint value; + gint old_value; + + if (backlight_kbd->priv->proxy == NULL) { + egg_warning ("no kbd backlight hardware"); + return FALSE; + } + + do_laptop_lcd = gconf_client_get_bool (backlight_kbd->priv->conf, GPM_CONF_BACKLIGHT_ENABLE, NULL); + if (do_laptop_lcd == FALSE) { + egg_warning ("policy is no dimming"); + return FALSE; + } + + /* get the last set brightness */ + brightness = backlight_kbd->priv->master_percentage / 100.0f; + egg_debug ("1. main brightness %f", brightness); + + /* get battery status */ + g_object_get (backlight_kbd->priv->client, + "on-battery", &on_battery, + NULL); + + /* reduce if on battery power if we should */ + battery_reduce = gconf_client_get_bool (backlight_kbd->priv->conf, GPM_CONF_BACKLIGHT_BATTERY_REDUCE, NULL); + if (on_battery && battery_reduce) { + value = gconf_client_get_int (backlight_kbd->priv->conf, GPM_CONF_BACKLIGHT_BRIGHTNESS_DIM_BATT, NULL); + if (value > 100) { + egg_warning ("cannot use battery brightness value %i, correcting to 50", value); + value = 50; + } + scale = (100 - value) / 100.0f; + brightness *= scale; + } else { + scale = 1.0f; + } + egg_debug ("2. battery scale %f, brightness %f", scale, brightness); + + /* reduce if system is momentarily idle */ + if (!on_battery) + enable_action = gconf_client_get_bool (backlight_kbd->priv->conf, GPM_CONF_BACKLIGHT_IDLE_DIM_AC, NULL); + else + enable_action = gconf_client_get_bool (backlight_kbd->priv->conf, GPM_CONF_BACKLIGHT_IDLE_DIM_BATT, NULL); + if (enable_action && backlight_kbd->priv->system_is_idle) { + value = gconf_client_get_int (backlight_kbd->priv->conf, GPM_CONF_BACKLIGHT_IDLE_BRIGHTNESS, NULL); + if (value > 100) { + egg_warning ("cannot use idle brightness value %i, correcting to 50", value); + value = 50; + } + scale = value / 100.0f; + brightness *= scale; + } else { + scale = 1.0f; + } + egg_debug ("3. idle scale %f, brightness %f", scale, brightness); + + /* convert to percentage */ + value = (gint) ((brightness * 100.0f) + 0.5); + + /* normalize to max brightness */ + value = value * backlight_kbd->priv->max_brightness / 100; + + if (backlight_kbd->priv->off) + value = 0; + + /* only do stuff if the brightness is different */ + ret = dbus_g_proxy_call (backlight_kbd->priv->proxy, + "GetBrightness", &error, + G_TYPE_INVALID, + G_TYPE_INT, &old_value, + G_TYPE_INVALID); + if (error) { + egg_debug ("ERROR: %s", error->message); + g_error_free (error); + } + if (!ret) { + egg_warning ("GetBrightness failed!"); + return FALSE; + } + if (old_value == value) { + egg_debug ("values are the same, no action"); + return FALSE; + } + + /* only show dialog if interactive */ + if (interactive) { + gpm_backlight_kbd_dialog_init (backlight_kbd); + gsd_media_keys_window_set_volume_level (GSD_MEDIA_KEYS_WINDOW (backlight_kbd->priv->popup), + round (brightness)); + gpm_backlight_kbd_dialog_show (backlight_kbd); + } + + egg_debug ("Setting brightness to %d", value); + return dbus_g_proxy_call (backlight_kbd->priv->proxy, + "SetBrightness", NULL, + G_TYPE_INT, value, + G_TYPE_INVALID, G_TYPE_INVALID); + return TRUE; +} + +/** + * gpm_conf_gconf_key_changed_cb: + * + * We might have to do things when the gconf keys change; do them here. + **/ +static void +gpm_conf_gconf_key_changed_cb (GConfClient *client, guint cnxn_id, GConfEntry *entry, GpmBacklightKbd *backlight_kbd) +{ + GConfValue *value; + gboolean on_battery; + + value = gconf_entry_get_value (entry); + if (value == NULL) + return; + + /* get battery status */ + g_object_get (backlight_kbd->priv->client, + "on-battery", &on_battery, + NULL); + + if (!on_battery && strcmp (entry->key, GPM_CONF_BACKLIGHT_BRIGHTNESS_AC) == 0) { + backlight_kbd->priv->master_percentage = gconf_value_get_int (value); + gpm_backlight_kbd_brightness_evaluate_and_set (backlight_kbd, FALSE); + + } else if (on_battery && strcmp (entry->key, GPM_CONF_BACKLIGHT_BRIGHTNESS_DIM_BATT) == 0) { + gpm_backlight_kbd_brightness_evaluate_and_set (backlight_kbd, FALSE); + + } else if (strcmp (entry->key, GPM_CONF_BACKLIGHT_IDLE_DIM_AC) == 0 || + strcmp (entry->key, GPM_CONF_BACKLIGHT_ENABLE) == 0 || + strcmp (entry->key, GPM_CONF_TIMEOUT_SLEEP_DISPLAY_BATT) == 0 || + strcmp (entry->key, GPM_CONF_BACKLIGHT_BATTERY_REDUCE) == 0 || + strcmp (entry->key, GPM_CONF_BACKLIGHT_IDLE_BRIGHTNESS) == 0) { + gpm_backlight_kbd_brightness_evaluate_and_set (backlight_kbd, FALSE); + + } else if (strcmp (entry->key, GPM_CONF_BACKLIGHT_IDLE_DIM_TIME) == 0) { + backlight_kbd->priv->idle_dim_timeout = gconf_value_get_int (value); + gpm_idle_set_timeout_dim (backlight_kbd->priv->idle, backlight_kbd->priv->idle_dim_timeout); + } else { + egg_debug ("unknown key %s", entry->key); + } +} + +/** + * gpm_backlight_kbd_client_changed_cb: + * @client: The up_client class instance + * @backlight_kbd: This class instance + * + * Does the actions when the ac power source is inserted/removed. + **/ +static void +gpm_backlight_kbd_client_changed_cb (UpClient *client, GpmBacklightKbd *backlight_kbd) +{ + gpm_backlight_kbd_brightness_evaluate_and_set (backlight_kbd, FALSE); +} + +/** + * gpm_backlight_kbd_button_pressed_cb: + * @power: The power class instance + * @type: The button type, e.g. "power" + * @state: The state, where TRUE is depressed or closed + * @brightness: This class instance + **/ +static void +gpm_backlight_kbd_button_pressed_cb (GpmButton *button, const gchar *type, GpmBacklightKbd *backlight_kbd) +{ + GError *error = NULL; + gboolean ret = FALSE; + gint percentage = -1, brightness; + egg_debug ("Button press event type=%s", type); + + if (strcmp (type, GPM_BUTTON_KBD_BRIGHT_UP) == 0) { + percentage = MIN(100, backlight_kbd->priv->master_percentage + 10); + brightness = percentage * backlight_kbd->priv->max_brightness / 100; + egg_debug ("Setting brightness to %d", brightness); + ret = dbus_g_proxy_call (backlight_kbd->priv->proxy, + "SetBrightness", &error, + G_TYPE_INT, brightness, + G_TYPE_INVALID, G_TYPE_INVALID); + } else if (strcmp (type, GPM_BUTTON_KBD_BRIGHT_DOWN) == 0) { + percentage = MAX(0, backlight_kbd->priv->master_percentage - 10); + brightness = percentage * backlight_kbd->priv->max_brightness / 100; + egg_debug ("Setting brightness to %d", brightness); + ret = dbus_g_proxy_call (backlight_kbd->priv->proxy, + "SetBrightness", &error, + G_TYPE_INT, brightness, + G_TYPE_INVALID, G_TYPE_INVALID); + } + if (ret) { + gpm_backlight_kbd_dialog_init (backlight_kbd); + gsd_media_keys_window_set_volume_level (GSD_MEDIA_KEYS_WINDOW (backlight_kbd->priv->popup), + percentage); + gpm_backlight_kbd_dialog_show (backlight_kbd); + /* save the new percentage */ + backlight_kbd->priv->master_percentage = percentage; + } else if (percentage >= 0) { + egg_warning ("failed to set brightness to %d: %s", brightness, error->message); + g_error_free (error); + } +} + +/** + * gpm_backlight_kbd_notify_system_idle_changed: + **/ +static gboolean +gpm_backlight_kbd_notify_system_idle_changed (GpmBacklightKbd *backlight_kbd, gboolean is_idle) +{ + gdouble elapsed; + + /* no point continuing */ + if (backlight_kbd->priv->system_is_idle == is_idle) { + egg_debug ("state not changed"); + return FALSE; + } + + /* get elapsed time and reset timer */ + elapsed = g_timer_elapsed (backlight_kbd->priv->idle_timer, NULL); + g_timer_reset (backlight_kbd->priv->idle_timer); + + if (is_idle == FALSE) { + egg_debug ("we have just been idle for %lfs", elapsed); + + /* The user immediatly undimmed the screen! + * We should double the timeout to avoid this happening again */ + if (elapsed < 10) { + /* double the event time */ + backlight_kbd->priv->idle_dim_timeout *= 2.0; + egg_debug ("increasing idle dim time to %is", backlight_kbd->priv->idle_dim_timeout); + gpm_idle_set_timeout_dim (backlight_kbd->priv->idle, backlight_kbd->priv->idle_dim_timeout); + } + + /* We reset the dimming after 2 minutes of idle, + * as the user will have changed tasks */ + if (elapsed > 2*60) { + /* reset back to our default dimming */ + backlight_kbd->priv->idle_dim_timeout = + gconf_client_get_int (backlight_kbd->priv->conf, + GPM_CONF_BACKLIGHT_IDLE_DIM_TIME, NULL); + egg_debug ("resetting idle dim time to %is", backlight_kbd->priv->idle_dim_timeout); + gpm_idle_set_timeout_dim (backlight_kbd->priv->idle, backlight_kbd->priv->idle_dim_timeout); + } + } else { + egg_debug ("we were active for %lfs", elapsed); + } + + egg_debug ("changing powersave idle status to %i", is_idle); + backlight_kbd->priv->system_is_idle = is_idle; + return TRUE; +} + +/** + * idle_changed_cb: + * @idle: The idle class instance + * @mode: The idle mode, e.g. GPM_IDLE_MODE_BLANK + * @manager: 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 +idle_changed_cb (GpmIdle *idle, GpmIdleMode mode, GpmBacklightKbd *backlight_kbd) +{ + /* don't dim or undim the screen when the lid is closed */ + if (gpm_button_is_lid_closed (backlight_kbd->priv->button)) + return; + + /* don't dim or undim the screen unless we are on the active console */ + if (!egg_console_kit_is_active (backlight_kbd->priv->consolekit)) { + egg_debug ("ignoring as not on active console"); + return; + } + + if (mode == GPM_IDLE_MODE_NORMAL || + mode == GPM_IDLE_MODE_DIM || + mode == GPM_IDLE_MODE_BLANK) { + /* sync brightness */ + gpm_backlight_kbd_notify_system_idle_changed (backlight_kbd, + mode != GPM_IDLE_MODE_NORMAL); + gpm_backlight_kbd_brightness_evaluate_and_set (backlight_kbd, FALSE); + } +} + +/** + * control_resume_cb: + * @control: The control class instance + * @action: The action + * @backlight_kbd: The keyboard backlight instance + * + * We want to ensure the keyboard backlight is on after resume + */ +static void +control_resume_cb (GpmControl *control, GpmControlAction action, GpmBacklightKbd *backlight_kbd) +{ + gpm_backlight_kbd_brightness_evaluate_and_set(backlight_kbd, FALSE); +} + +/** + * dpms_mode_changed_cb: + * @dpms: The dpms class instance + * @mode: The dpms mode + * @backlight_kbd: The keyboard backlight instance + * + * We want to stay in sync with screen dpms + */ +static void +dpms_mode_changed_cb (GpmDpms *dpms, GpmDpmsMode mode, GpmBacklightKbd *backlight_kbd) +{ + backlight_kbd->priv->off = (mode != GPM_DPMS_MODE_ON); + gpm_backlight_kbd_brightness_evaluate_and_set (backlight_kbd, FALSE); +} +/** + * gpm_backlight_kbd_finalize: + **/ +static void +gpm_backlight_kbd_finalize (GObject *object) +{ + GpmBacklightKbd *backlight_kbd; + g_return_if_fail (object != NULL); + g_return_if_fail (GPM_IS_BACKLIGHT_KBD (object)); + backlight_kbd = GPM_BACKLIGHT_KBD (object); + + g_timer_destroy (backlight_kbd->priv->idle_timer); + gtk_widget_destroy (backlight_kbd->priv->popup); + + g_object_unref (backlight_kbd->priv->dpms); + g_object_unref (backlight_kbd->priv->control); + g_object_unref (backlight_kbd->priv->conf); + g_object_unref (backlight_kbd->priv->client); + g_object_unref (backlight_kbd->priv->button); + g_object_unref (backlight_kbd->priv->idle); + g_object_unref (backlight_kbd->priv->proxy); + g_object_unref (backlight_kbd->priv->consolekit); + + g_return_if_fail (backlight_kbd->priv != NULL); + G_OBJECT_CLASS (gpm_backlight_kbd_parent_class)->finalize (object); +} + +/** + * gpm_backlight_kbd_class_init: + **/ +static void +gpm_backlight_kbd_class_init (GpmBacklightKbdClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + object_class->finalize = gpm_backlight_kbd_finalize; + + g_type_class_add_private (klass, sizeof (GpmBacklightKbdPrivate)); +} + +/** + * gpm_backlight_kbd_init: + * @brightness: This brightness class instance + * + * initialises the brightness class. NOTE: We expect laptop_panel objects + * to *NOT* be removed or added during the session. + * We only control the first laptop_panel object if there are more than one. + **/ +static void +gpm_backlight_kbd_init (GpmBacklightKbd *backlight_kbd) +{ + DBusGConnection *connection; + GError *error = NULL; + gboolean ret; + gint brightness; + + backlight_kbd->priv = GPM_BACKLIGHT_KBD_GET_PRIVATE (backlight_kbd); + + /* record our idle time */ + backlight_kbd->priv->idle_timer = g_timer_new (); + + /* we use up_client for the ac-adapter-changed signal */ + backlight_kbd->priv->client = up_client_new (); + g_signal_connect (backlight_kbd->priv->client, "changed", + G_CALLBACK (gpm_backlight_kbd_client_changed_cb), backlight_kbd); + + /* watch for dim value changes */ + backlight_kbd->priv->conf = gconf_client_get_default (); + + /* watch gnome-power-manager keys */ + gconf_client_add_dir (backlight_kbd->priv->conf, GPM_CONF_DIR, GCONF_CLIENT_PRELOAD_RECURSIVE, NULL); + gconf_client_notify_add (backlight_kbd->priv->conf, GPM_CONF_DIR, + (GConfClientNotifyFunc) gpm_conf_gconf_key_changed_cb, + backlight_kbd, NULL, NULL); + + /* set the main brightness, this is designed to be updated if the user changes the + * brightness so we can undim to the 'correct' value */ + backlight_kbd->priv->master_percentage = gconf_client_get_int (backlight_kbd->priv->conf, GPM_CONF_BACKLIGHT_BRIGHTNESS_AC, NULL); + + /* watch for brightness up and down buttons and also check lid state */ + backlight_kbd->priv->button = gpm_button_new (); + g_signal_connect (backlight_kbd->priv->button, "button-pressed", + G_CALLBACK (gpm_backlight_kbd_button_pressed_cb), backlight_kbd); + + /* watch for idle mode changes */ + backlight_kbd->priv->idle = gpm_idle_new (); + g_signal_connect (backlight_kbd->priv->idle, "idle-changed", + G_CALLBACK (idle_changed_cb), backlight_kbd); + + /* assumption */ + backlight_kbd->priv->system_is_idle = FALSE; + backlight_kbd->priv->idle_dim_timeout = gconf_client_get_int (backlight_kbd->priv->conf, GPM_CONF_BACKLIGHT_IDLE_DIM_TIME, NULL); + gpm_idle_set_timeout_dim (backlight_kbd->priv->idle, backlight_kbd->priv->idle_dim_timeout); + + /* use a visual widget */ + backlight_kbd->priv->popup = gsd_media_keys_window_new (); + gsd_media_keys_window_set_action_custom (GSD_MEDIA_KEYS_WINDOW (backlight_kbd->priv->popup), + "gpm-brightness-lcd", + TRUE); + gtk_window_set_position (GTK_WINDOW (backlight_kbd->priv->popup), GTK_WIN_POS_NONE); + + /* DPMS mode poll class */ + backlight_kbd->priv->dpms = gpm_dpms_new (); + g_signal_connect (backlight_kbd->priv->dpms, "mode-changed", + G_CALLBACK (dpms_mode_changed_cb), backlight_kbd); + + /* we refresh backlight on resume */ + backlight_kbd->priv->control = gpm_control_new (); + g_signal_connect (backlight_kbd->priv->control, "resume", + G_CALLBACK (control_resume_cb), backlight_kbd); + + /* Don't do dimming on inactive console */ + backlight_kbd->priv->consolekit = egg_console_kit_new (); + + connection = dbus_g_bus_get (DBUS_BUS_SYSTEM, NULL); + backlight_kbd->priv->proxy = dbus_g_proxy_new_for_name (connection, + BACKLIGHT_KBD_SERVICE, + BACKLIGHT_KBD_PATH, + BACKLIGHT_KBD_INTERFACE); + + if (!backlight_kbd->priv->proxy) { + egg_warning ("Failed to get proxy to kbdbacklight interface"); + return; + } + + ret = dbus_g_proxy_call (backlight_kbd->priv->proxy, + "GetBrightness", &error, + G_TYPE_INVALID, + G_TYPE_INT, &brightness, + G_TYPE_INVALID); + if (error) { + egg_debug ("ERROR: %s", error->message); + g_error_free (error); + } + if (!ret) { + egg_warning ("GetBrightness failed!"); + return; + } + + ret = dbus_g_proxy_call (backlight_kbd->priv->proxy, + "GetMaxBrightness", &error, + G_TYPE_INVALID, + G_TYPE_INT, &backlight_kbd->priv->max_brightness, + G_TYPE_INVALID); + if (error) { + egg_debug ("ERROR: %s", error->message); + g_error_free (error); + } + if (!ret) { + egg_warning ("GetMaxBrightness failed!"); + return; + } + + brightness = (backlight_kbd->priv->max_brightness * + backlight_kbd->priv->master_percentage / 100); + egg_debug ("Setting brightness to %d", brightness); + /* set initial brightness to max */ + ret = dbus_g_proxy_call (backlight_kbd->priv->proxy, + "SetBrightness", &error, + G_TYPE_INT, brightness, + G_TYPE_INVALID, G_TYPE_INVALID); + if (error) { + egg_debug ("ERROR: %s", error->message); + g_error_free (error); + } + if (!ret) { + egg_warning ("SetBrightness failed!"); + } + + /* sync at startup */ + gpm_backlight_kbd_brightness_evaluate_and_set (backlight_kbd, FALSE); + +} + + +/** + * gpm_backlight_kbd_new: + * Return value: A new brightness class instance. + **/ +GpmBacklightKbd * +gpm_backlight_kbd_new (void) +{ + GpmBacklightKbd *backlight_kbd = g_object_new (GPM_TYPE_BACKLIGHT_KBD, NULL); + return backlight_kbd; +} + --- gnome-power-manager-2.32.0-r1-orig/work/gnome-power-manager-2.32.0/src/gpm-backlight-kbd.h 1970-01-01 01:00:00.000000000 +0100 +++ gnome-power-manager-2.32.0-r1-orig/work/gnome-power-manager-2.32.0/src/gpm-backlight-kbd.h 2011-05-10 09:21:24.047312466 +0100 @@ -0,0 +1,57 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- + * + * Copyright (C) 2010 Alex Murray + * Copyright (C) 2005-2007 Richard Hughes + * Copyright (C) 2004-2005 William Jon McCann + * + * 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_BACKLIGHT_KBD_H +#define __GPM_BACKLIGHT_KBD_H + +#include + +G_BEGIN_DECLS + +#define GPM_TYPE_BACKLIGHT_KBD (gpm_backlight_kbd_get_type ()) +#define GPM_BACKLIGHT_KBD(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GPM_TYPE_BACKLIGHT_KBD, GpmBacklightKbd)) +#define GPM_BACKLIGHT_KBD_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GPM_TYPE_BACKLIGHT_KBD, GpmBacklightKbdClass)) +#define GPM_IS_BACKLIGHT_KBD(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GPM_TYPE_BACKLIGHT_KBD)) +#define GPM_IS_BACKLIGHT_KBD_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GPM_TYPE_BACKLIGHT_KBD)) +#define GPM_BACKLIGHT_KBD_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GPM_TYPE_BACKLIGHT_KBD, GpmBacklightKbdClass)) + +typedef struct GpmBacklightKbdPrivate GpmBacklightKbdPrivate; + +typedef struct +{ + GObject parent; + GpmBacklightKbdPrivate *priv; +} GpmBacklightKbd; + +typedef struct +{ + GObjectClass parent_class; +} GpmBacklightKbdClass; + +GType gpm_backlight_kbd_get_type (void); +GpmBacklightKbd *gpm_backlight_kbd_new (void); + +G_END_DECLS + +#endif /* __GPM_BACKLIGHT_KBD_H */ + --- gnome-power-manager-2.32.0-r1-orig/work/gnome-power-manager-2.32.0/src/gpm-manager.c 2010-09-22 12:02:17.000000000 +0100 +++ gnome-power-manager-2.32.0-r1-orig/work/gnome-power-manager-2.32.0/src/gpm-manager.c 2011-05-10 09:21:24.047312466 +0100 @@ -54,6 +54,7 @@ #include "gpm-manager.h" #include "gpm-screensaver.h" #include "gpm-backlight.h" +#include "gpm-backlight-kbd.h" #include "gpm-session.h" #include "gpm-stock-icons.h" #include "gpm-prefs-server.h" @@ -87,6 +88,7 @@ GpmTrayIcon *tray_icon; GpmEngine *engine; GpmBacklight *backlight; + GpmBacklightKbd *backlight_kbd; EggConsoleKit *console; guint32 screensaver_ac_throttle_id; guint32 screensaver_dpms_throttle_id; @@ -1993,6 +1995,7 @@ dbus_g_connection_register_g_object (connection, GPM_DBUS_PATH_BACKLIGHT, G_OBJECT (manager->priv->backlight)); } + manager->priv->backlight_kbd = gpm_backlight_kbd_new (); manager->priv->idle = gpm_idle_new (); g_signal_connect (manager->priv->idle, "idle-changed", @@ -2089,6 +2092,7 @@ g_object_unref (manager->priv->control); g_object_unref (manager->priv->button); g_object_unref (manager->priv->backlight); + g_object_unref (manager->priv->backlight_kbd); g_object_unref (manager->priv->console); g_object_unref (manager->priv->client); g_object_unref (manager->priv->status_icon); --- gnome-power-manager-2.32.0-r1-orig/work/gnome-power-manager-2.32.0/src/gpm-manager.c.orig 1970-01-01 01:00:00.000000000 +0100 +++ gnome-power-manager-2.32.0-r1-orig/work/gnome-power-manager-2.32.0/src/gpm-manager.c.orig 2010-09-22 12:02:17.000000000 +0100 @@ -0,0 +1,2110 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- + * + * Copyright (C) 2005 William Jon McCann + * Copyright (C) 2005-2008 Richard Hughes + * + * 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 +#include +#include +#include + +#include +#include +#include +#ifdef HAVE_UNISTD_H +#include +#endif /* HAVE_UNISTD_H */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "egg-debug.h" +#include "egg-console-kit.h" + +#include "gpm-button.h" +#include "gpm-control.h" +#include "gpm-common.h" +#include "gpm-dpms.h" +#include "gpm-idle.h" +#include "gpm-manager.h" +#include "gpm-screensaver.h" +#include "gpm-backlight.h" +#include "gpm-session.h" +#include "gpm-stock-icons.h" +#include "gpm-prefs-server.h" +#include "gpm-tray-icon.h" +#include "gpm-engine.h" +#include "gpm-upower.h" +#include "gpm-disks.h" + +#include "org.gnome.PowerManager.Backlight.h" + +static void gpm_manager_finalize (GObject *object); + +#define GPM_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GPM_TYPE_MANAGER, GpmManagerPrivate)) +#define GPM_MANAGER_RECALL_DELAY 30 /* seconds */ +#define GPM_MANAGER_NOTIFY_TIMEOUT_NEVER 0 /* ms */ +#define GPM_MANAGER_NOTIFY_TIMEOUT_SHORT 10 * 1000 /* ms */ +#define GPM_MANAGER_NOTIFY_TIMEOUT_LONG 30 * 1000 /* ms */ + +#define GPM_MANAGER_CRITICAL_ALERT_TIMEOUT 5 /* seconds */ + +struct GpmManagerPrivate +{ + GpmButton *button; + GConfClient *conf; + GpmDisks *disks; + GpmDpms *dpms; + GpmIdle *idle; + GpmPrefsServer *prefs_server; + GpmControl *control; + GpmScreensaver *screensaver; + GpmTrayIcon *tray_icon; + GpmEngine *engine; + GpmBacklight *backlight; + EggConsoleKit *console; + guint32 screensaver_ac_throttle_id; + guint32 screensaver_dpms_throttle_id; + guint32 screensaver_lid_throttle_id; + guint32 critical_alert_timeout_id; + ca_proplist *critical_alert_loop_props; + UpClient *client; + gboolean on_battery; + gboolean just_resumed; + GtkStatusIcon *status_icon; + NotifyNotification *notification_general; + NotifyNotification *notification_warning_low; + NotifyNotification *notification_discharging; + NotifyNotification *notification_fully_charged; +}; + +typedef enum { + GPM_MANAGER_SOUND_POWER_PLUG, + GPM_MANAGER_SOUND_POWER_UNPLUG, + GPM_MANAGER_SOUND_LID_OPEN, + GPM_MANAGER_SOUND_LID_CLOSE, + GPM_MANAGER_SOUND_BATTERY_CAUTION, + GPM_MANAGER_SOUND_BATTERY_LOW, + GPM_MANAGER_SOUND_BATTERY_FULL, + GPM_MANAGER_SOUND_SUSPEND_START, + GPM_MANAGER_SOUND_SUSPEND_RESUME, + GPM_MANAGER_SOUND_SUSPEND_ERROR, + GPM_MANAGER_SOUND_LAST +} GpmManagerSound; + +G_DEFINE_TYPE (GpmManager, gpm_manager, G_TYPE_OBJECT) + +/** + * gpm_manager_error_quark: + * Return value: Our personal error quark. + **/ +GQuark +gpm_manager_error_quark (void) +{ + static GQuark quark = 0; + if (!quark) + quark = g_quark_from_static_string ("gpm_manager_error"); + return quark; +} + +/** + * gpm_manager_error_get_type: + **/ +#define ENUM_ENTRY(NAME, DESC) { NAME, "" #NAME "", DESC } +GType +gpm_manager_error_get_type (void) +{ + static GType etype = 0; + + if (etype == 0) { + static const GEnumValue values[] = + { + ENUM_ENTRY (GPM_MANAGER_ERROR_DENIED, "PermissionDenied"), + ENUM_ENTRY (GPM_MANAGER_ERROR_NO_HW, "NoHardwareSupport"), + { 0, 0, 0 } + }; + etype = g_enum_register_static ("GpmManagerError", values); + } + return etype; +} + +/** + * gpm_manager_play_loop_timeout_cb: + **/ +static gboolean +gpm_manager_play_loop_timeout_cb (GpmManager *manager) +{ + ca_context *context; + context = ca_gtk_context_get_for_screen (gdk_screen_get_default ()); + ca_context_play_full (context, 0, + manager->priv->critical_alert_loop_props, + NULL, + NULL); + return TRUE; +} + +/** + * gpm_manager_play_loop_stop: + **/ +static gboolean +gpm_manager_play_loop_stop (GpmManager *manager) +{ + if (manager->priv->critical_alert_timeout_id == 0) { + egg_warning ("no sound loop present to stop"); + return FALSE; + } + + g_source_remove (manager->priv->critical_alert_timeout_id); + ca_proplist_destroy (manager->priv->critical_alert_loop_props); + + manager->priv->critical_alert_loop_props = NULL; + manager->priv->critical_alert_timeout_id = 0; + + return TRUE; +} + +/** + * gpm_manager_play_loop_start: + **/ +static gboolean +gpm_manager_play_loop_start (GpmManager *manager, GpmManagerSound action, gboolean force, guint timeout) +{ + const gchar *id = NULL; + const gchar *desc = NULL; + gboolean ret; + gint retval; + ca_context *context; + + ret = gconf_client_get_bool (manager->priv->conf, GPM_CONF_UI_ENABLE_SOUND, NULL); + if (!ret && !force) { + egg_debug ("ignoring sound due to policy"); + return FALSE; + } + + if (timeout == 0) { + egg_warning ("received invalid timeout"); + return FALSE; + } + + /* if a sound loop is already running, stop the existing loop */ + if (manager->priv->critical_alert_timeout_id != 0) { + egg_warning ("was instructed to play a sound loop with one already playing"); + gpm_manager_play_loop_stop (manager); + } + + if (action == GPM_MANAGER_SOUND_BATTERY_LOW) { + id = "battery-low"; + /* TRANSLATORS: this is the sound description */ + desc = _("Battery is very low"); + } + + /* no match */ + if (id == NULL) { + egg_warning ("no sound match for %i", action); + return FALSE; + } + + ca_proplist_create (&(manager->priv->critical_alert_loop_props)); + ca_proplist_sets (manager->priv->critical_alert_loop_props, + CA_PROP_EVENT_ID, id); + ca_proplist_sets (manager->priv->critical_alert_loop_props, + CA_PROP_EVENT_DESCRIPTION, desc); + + manager->priv->critical_alert_timeout_id = g_timeout_add_seconds (timeout, + (GSourceFunc) gpm_manager_play_loop_timeout_cb, + manager); + + /* play the sound, using sounds from the naming spec */ + context = ca_gtk_context_get_for_screen (gdk_screen_get_default ()); + retval = ca_context_play (context, 0, + CA_PROP_EVENT_ID, id, + CA_PROP_EVENT_DESCRIPTION, desc, NULL); + if (retval < 0) + egg_warning ("failed to play %s: %s", id, ca_strerror (retval)); + return TRUE; +} + +/** + * gpm_manager_play: + **/ +static gboolean +gpm_manager_play (GpmManager *manager, GpmManagerSound action, gboolean force) +{ + const gchar *id = NULL; + const gchar *desc = NULL; + gboolean ret; + gint retval; + ca_context *context; + + ret = gconf_client_get_bool (manager->priv->conf, GPM_CONF_UI_ENABLE_SOUND, NULL); + if (!ret && !force) { + egg_debug ("ignoring sound due to policy"); + return FALSE; + } + + if (action == GPM_MANAGER_SOUND_POWER_PLUG) { + id = "power-plug"; + /* TRANSLATORS: this is the sound description */ + desc = _("Power plugged in"); + } else if (action == GPM_MANAGER_SOUND_POWER_UNPLUG) { + id = "power-unplug"; + /* TRANSLATORS: this is the sound description */ + desc = _("Power unplugged"); + } else if (action == GPM_MANAGER_SOUND_LID_OPEN) { + id = "lid-open"; + /* TRANSLATORS: this is the sound description */ + desc = _("Lid has opened"); + } else if (action == GPM_MANAGER_SOUND_LID_CLOSE) { + id = "lid-close"; + /* TRANSLATORS: this is the sound description */ + desc = _("Lid has closed"); + } else if (action == GPM_MANAGER_SOUND_BATTERY_CAUTION) { + id = "battery-caution"; + /* TRANSLATORS: this is the sound description */ + desc = _("Battery is low"); + } else if (action == GPM_MANAGER_SOUND_BATTERY_LOW) { + id = "battery-low"; + /* TRANSLATORS: this is the sound description */ + desc = _("Battery is very low"); + } else if (action == GPM_MANAGER_SOUND_BATTERY_FULL) { + id = "battery-full"; + /* TRANSLATORS: this is the sound description */ + desc = _("Battery is full"); + } else if (action == GPM_MANAGER_SOUND_SUSPEND_START) { + id = "suspend-start"; + /* TRANSLATORS: this is the sound description */ + desc = _("Suspend started"); + } else if (action == GPM_MANAGER_SOUND_SUSPEND_RESUME) { + id = "suspend-resume"; + /* TRANSLATORS: this is the sound description */ + desc = _("Resumed"); + } else if (action == GPM_MANAGER_SOUND_SUSPEND_ERROR) { + id = "suspend-error"; + /* TRANSLATORS: this is the sound description */ + desc = _("Suspend failed"); + } + + /* no match */ + if (id == NULL) { + egg_warning ("no match"); + return FALSE; + } + + /* play the sound, using sounds from the naming spec */ + context = ca_gtk_context_get_for_screen (gdk_screen_get_default ()); + retval = ca_context_play (context, 0, + CA_PROP_EVENT_ID, id, + CA_PROP_EVENT_DESCRIPTION, desc, NULL); + if (retval < 0) + egg_warning ("failed to play %s: %s", id, ca_strerror (retval)); + return TRUE; +} + +/** + * gpm_manager_is_inhibit_valid: + * @manager: This class instance + * @action: The action we want to do, e.g. "suspend" + * + * Checks to see if the specific action has been inhibited by a program. + * + * Return value: TRUE if we can perform the action. + **/ +static gboolean +gpm_manager_is_inhibit_valid (GpmManager *manager, gboolean user_action, const char *action) +{ + return TRUE; +} + +/** + * gpm_manager_sync_policy_sleep: + * @manager: This class instance + * + * Changes the policy if required, setting brightness, display and computer + * timeouts. + * We have to make sure gnome-screensaver disables screensaving, and enables + * monitor DPMS instead when on batteries to save power. + **/ +static void +gpm_manager_sync_policy_sleep (GpmManager *manager) +{ + guint sleep_display; + guint sleep_computer; + + if (!manager->priv->on_battery) { + sleep_computer = gconf_client_get_int (manager->priv->conf, GPM_CONF_TIMEOUT_SLEEP_COMPUTER_AC, NULL); + sleep_display = gconf_client_get_int (manager->priv->conf, GPM_CONF_TIMEOUT_SLEEP_DISPLAY_AC, NULL); + } else { + sleep_computer = gconf_client_get_int (manager->priv->conf, GPM_CONF_TIMEOUT_SLEEP_COMPUTER_BATT, NULL); + sleep_display = gconf_client_get_int (manager->priv->conf, GPM_CONF_TIMEOUT_SLEEP_DISPLAY_BATT, NULL); + } + + /* set the new sleep (inactivity) value */ + gpm_idle_set_timeout_blank (manager->priv->idle, sleep_display); + gpm_idle_set_timeout_sleep (manager->priv->idle, sleep_computer); +} + +/** + * gpm_manager_blank_screen: + * @manager: This class instance + * + * Turn off the backlight of the LCD when we shut the lid, and lock + * if required. This is required because some laptops do not turn off the + * LCD backlight when the lid is closed. + * See http://bugzilla.gnome.org/show_bug.cgi?id=321313 + * + * Return value: Success. + **/ +static gboolean +gpm_manager_blank_screen (GpmManager *manager, GError **noerror) +{ + gboolean do_lock; + gboolean ret = TRUE; + GError *error = NULL; + + do_lock = gpm_control_get_lock_policy (manager->priv->control, + GPM_CONF_LOCK_ON_BLANK_SCREEN); + if (do_lock) { + if (!gpm_screensaver_lock (manager->priv->screensaver)) + egg_debug ("Could not lock screen via gnome-screensaver"); + } + gpm_dpms_set_mode (manager->priv->dpms, GPM_DPMS_MODE_OFF, &error); + if (error) { + egg_debug ("Unable to set DPMS mode: %s", error->message); + g_error_free (error); + ret = FALSE; + } + return ret; +} + +/** + * gpm_manager_unblank_screen: + * @manager: This class instance + * + * Unblank the screen after we have opened the lid of the laptop + * + * Return value: Success. + **/ +static gboolean +gpm_manager_unblank_screen (GpmManager *manager, GError **noerror) +{ + gboolean do_lock; + gboolean ret = TRUE; + GError *error = NULL; + + gpm_dpms_set_mode (manager->priv->dpms, GPM_DPMS_MODE_ON, &error); + if (error) { + egg_debug ("Unable to set DPMS mode: %s", error->message); + g_error_free (error); + ret = FALSE; + } + + do_lock = gpm_control_get_lock_policy (manager->priv->control, GPM_CONF_LOCK_ON_BLANK_SCREEN); + if (do_lock) + gpm_screensaver_poke (manager->priv->screensaver); + return ret; +} + +/** + * gpm_manager_notify_close: + **/ +static gboolean +gpm_manager_notify_close (GpmManager *manager, NotifyNotification *notification) +{ + gboolean ret = FALSE; + GError *error = NULL; + + /* exists? */ + if (notification == NULL) + goto out; + + /* try to close */ + ret = notify_notification_close (notification, &error); + if (!ret) { + egg_warning ("failed to close notification: %s", error->message); + g_error_free (error); + goto out; + } +out: + return ret; +} + +/** + * gpm_manager_notification_closed_cb: + **/ +static void +gpm_manager_notification_closed_cb (NotifyNotification *notification, NotifyNotification **notification_class) +{ + egg_debug ("caught notification closed signal %p", notification); + /* the object is already unreffed in _close_signal_handler */ + *notification_class = NULL; +} + +/** + * gpm_manager_notify: + **/ +static gboolean +gpm_manager_notify (GpmManager *manager, NotifyNotification **notification_class, + const gchar *title, const gchar *message, + guint timeout, const gchar *icon, NotifyUrgency urgency) +{ + gboolean ret; + GError *error = NULL; + NotifyNotification *notification; + GtkWidget *dialog; + + /* close any existing notification of this class */ + gpm_manager_notify_close (manager, *notification_class); + + /* if the status icon is hidden, don't point at it */ + if (manager->priv->status_icon != NULL && + gtk_status_icon_is_embedded (manager->priv->status_icon)) + notification = notify_notification_new_with_status_icon (title, message, icon, manager->priv->status_icon); + else + notification = notify_notification_new (title, message, icon, NULL); + notify_notification_set_timeout (notification, timeout); + notify_notification_set_urgency (notification, urgency); + g_signal_connect (notification, "closed", G_CALLBACK (gpm_manager_notification_closed_cb), notification_class); + + egg_debug ("notification %p: %s : %s", notification, title, message); + + /* try to show */ + ret = notify_notification_show (notification, &error); + if (!ret) { + egg_warning ("failed to show notification: %s", error->message); + g_error_free (error); + + /* show modal dialog as libnotify failed */ + dialog = gtk_message_dialog_new_with_markup (NULL, GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_INFO, GTK_BUTTONS_CLOSE, + "%s", title); + gtk_message_dialog_format_secondary_markup (GTK_MESSAGE_DIALOG (dialog), "%s", message); + + /* wait async for close */ + gtk_widget_show (dialog); + g_signal_connect_swapped (dialog, "response", G_CALLBACK (gtk_widget_destroy), dialog); + + g_object_unref (notification); + goto out; + } + + /* save this local instance as the class instance */ + g_object_add_weak_pointer (G_OBJECT (notification), (gpointer) ¬ification); + *notification_class = notification; +out: + return ret; +} + + +/** + * gpm_manager_sleep_failure_response_cb: + **/ +static void +gpm_manager_sleep_failure_response_cb (GtkDialog *dialog, gint response_id, GpmManager *manager) +{ + GdkScreen *screen; + GtkWidget *dialog_error; + GError *error = NULL; + gboolean ret; + gchar *uri = NULL; + + /* user clicked the help button */ + if (response_id == GTK_RESPONSE_HELP) { + uri = gconf_client_get_string (manager->priv->conf, GPM_CONF_NOTIFY_SLEEP_FAILED_URI, NULL); + screen = gdk_screen_get_default(); + ret = gtk_show_uri (screen, uri, gtk_get_current_event_time (), &error); + if (!ret) { + dialog_error = gtk_message_dialog_new (NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_INFO, GTK_BUTTONS_OK, + "Failed to show uri %s", error->message); + gtk_dialog_run (GTK_DIALOG (dialog_error)); + g_error_free (error); + } + } + + gtk_widget_destroy (GTK_WIDGET (dialog)); + g_free (uri); +} + +/** + * gpm_manager_sleep_failure: + **/ +static void +gpm_manager_sleep_failure (GpmManager *manager, gboolean is_suspend, const gchar *detail) +{ + gboolean show_sleep_failed; + GString *string = NULL; + const gchar *title; + gchar *uri = NULL; + const gchar *icon; + GtkWidget *dialog; + + /* only show this if specified in gconf */ + show_sleep_failed = gconf_client_get_bool (manager->priv->conf, GPM_CONF_NOTIFY_SLEEP_FAILED, NULL); + + egg_debug ("sleep failed"); + gpm_manager_play (manager, GPM_MANAGER_SOUND_SUSPEND_ERROR, TRUE); + + /* only emit if in GConf */ + if (!show_sleep_failed) + goto out; + + /* TRANSLATORS: window title: there was a problem putting the machine to sleep */ + string = g_string_new (""); + if (is_suspend) { + /* TRANSLATORS: message text */ + g_string_append (string, _("Computer failed to suspend.")); + /* TRANSLATORS: title text */ + title = _("Failed to suspend"); + icon = GPM_STOCK_SUSPEND; + } else { + /* TRANSLATORS: message text */ + g_string_append (string, _("Computer failed to hibernate.")); + /* TRANSLATORS: title text */ + title = _("Failed to hibernate"); + icon = GPM_STOCK_HIBERNATE; + } + + /* TRANSLATORS: message text */ + g_string_append_printf (string, "\n\n%s %s", _("Failure was reported as:"), detail); + + /* show modal dialog */ + dialog = gtk_message_dialog_new_with_markup (NULL, GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_INFO, GTK_BUTTONS_CLOSE, + "%s", title); + gtk_message_dialog_format_secondary_markup (GTK_MESSAGE_DIALOG (dialog), "%s", string->str); + gtk_window_set_icon_name (GTK_WINDOW(dialog), icon); + + /* show a button? */ + uri = gconf_client_get_string (manager->priv->conf, GPM_CONF_NOTIFY_SLEEP_FAILED_URI, NULL); + if (uri != NULL && uri[0] != '\0') { + /* TRANSLATORS: button text, visit the suspend help website */ + gtk_dialog_add_button (GTK_DIALOG (dialog), _("Visit help page"), GTK_RESPONSE_HELP); + } + + /* wait async for close */ + gtk_widget_show (dialog); + g_signal_connect (dialog, "response", G_CALLBACK (gpm_manager_sleep_failure_response_cb), manager); +out: + g_free (uri); + g_string_free (string, TRUE); +} + +/** + * gpm_manager_action_suspend: + **/ +static gboolean +gpm_manager_action_suspend (GpmManager *manager, const gchar *reason) +{ + gboolean ret; + GError *error = NULL; + + /* check to see if we are inhibited */ + if (gpm_manager_is_inhibit_valid (manager, FALSE, "suspend") == FALSE) + return FALSE; + + egg_debug ("suspending, reason: %s", reason); + ret = gpm_control_suspend (manager->priv->control, &error); + if (!ret) { + gpm_manager_sleep_failure (manager, TRUE, error->message); + g_error_free (error); + } + gpm_button_reset_time (manager->priv->button); + return TRUE; +} + +/** + * gpm_manager_action_hibernate: + **/ +static gboolean +gpm_manager_action_hibernate (GpmManager *manager, const gchar *reason) +{ + gboolean ret; + GError *error = NULL; + + /* check to see if we are inhibited */ + if (gpm_manager_is_inhibit_valid (manager, FALSE, "hibernate") == FALSE) + return FALSE; + + egg_debug ("hibernating, reason: %s", reason); + ret = gpm_control_hibernate (manager->priv->control, &error); + if (!ret) { + gpm_manager_sleep_failure (manager, TRUE, error->message); + g_error_free (error); + } + gpm_button_reset_time (manager->priv->button); + return TRUE; +} + +/** + * gpm_manager_perform_policy: + * @manager: This class instance + * @policy: The policy that we should do, e.g. "suspend" + * @reason: The reason we are performing the policy action, e.g. "battery critical" + * + * Does one of the policy actions specified in gconf. + **/ +static gboolean +gpm_manager_perform_policy (GpmManager *manager, const gchar *policy_key, const gchar *reason) +{ + gchar *action = NULL; + GpmActionPolicy policy; + + /* are we inhibited? */ + if (gpm_manager_is_inhibit_valid (manager, FALSE, "policy action") == FALSE) + return FALSE; + + action = gconf_client_get_string (manager->priv->conf, policy_key, NULL); + egg_debug ("action: %s set to %s (%s)", policy_key, action, reason); + policy = gpm_action_policy_from_string (action); + + if (policy == GPM_ACTION_POLICY_NOTHING) { + egg_debug ("doing nothing, reason: %s", reason); + } else if (policy == GPM_ACTION_POLICY_SUSPEND) { + gpm_manager_action_suspend (manager, reason); + + } else if (policy == GPM_ACTION_POLICY_HIBERNATE) { + gpm_manager_action_hibernate (manager, reason); + + } else if (policy == GPM_ACTION_POLICY_BLANK) { + gpm_manager_blank_screen (manager, NULL); + + } else if (policy == GPM_ACTION_POLICY_SHUTDOWN) { + egg_debug ("shutting down, reason: %s", reason); + gpm_control_shutdown (manager->priv->control, NULL); + + } else if (policy == GPM_ACTION_POLICY_INTERACTIVE) { + GpmSession *session; + egg_debug ("logout, reason: %s", reason); + session = gpm_session_new (); + gpm_session_logout (session); + g_object_unref (session); + } else { + egg_warning ("unknown action %s", action); + } + + g_free (action); + return TRUE; +} + +/** + * gpm_manager_get_preferences_options: + **/ +gboolean +gpm_manager_get_preferences_options (GpmManager *manager, gint *capability, GError **error) +{ + g_return_val_if_fail (manager != NULL, FALSE); + g_return_val_if_fail (GPM_IS_MANAGER (manager), FALSE); + return gpm_prefs_server_get_capability (manager->priv->prefs_server, capability); +} + +/** + * gpm_manager_idle_do_sleep: + * @manager: This class instance + * + * This callback is called when we want to sleep. Use the users + * preference from gconf, but change it if we can't do the action. + **/ +static void +gpm_manager_idle_do_sleep (GpmManager *manager) +{ + gchar *action = NULL; + gboolean ret; + GError *error = NULL; + GpmActionPolicy policy; + + if (!manager->priv->on_battery) + action = gconf_client_get_string (manager->priv->conf, GPM_CONF_ACTIONS_SLEEP_TYPE_AC, NULL); + else + action = gconf_client_get_string (manager->priv->conf, GPM_CONF_ACTIONS_SLEEP_TYPE_BATT, NULL); + policy = gpm_action_policy_from_string (action); + + if (policy == GPM_ACTION_POLICY_NOTHING) { + egg_debug ("doing nothing as system idle action"); + + } else if (policy == GPM_ACTION_POLICY_SUSPEND) { + egg_debug ("suspending, reason: System idle"); + ret = gpm_control_suspend (manager->priv->control, &error); + if (!ret) { + egg_warning ("cannot suspend (error: %s), so trying hibernate", error->message); + g_error_free (error); + error = NULL; + ret = gpm_control_hibernate (manager->priv->control, &error); + if (!ret) { + egg_warning ("cannot suspend or hibernate: %s", error->message); + g_error_free (error); + } + } + + } else if (policy == GPM_ACTION_POLICY_HIBERNATE) { + egg_debug ("hibernating, reason: System idle"); + ret = gpm_control_hibernate (manager->priv->control, &error); + if (!ret) { + egg_warning ("cannot hibernate (error: %s), so trying suspend", error->message); + g_error_free (error); + error = NULL; + ret = gpm_control_suspend (manager->priv->control, &error); + if (!ret) { + egg_warning ("cannot suspend or hibernate: %s", error->message); + g_error_free (error); + } + } + } + g_free (action); +} + +/** + * gpm_manager_idle_changed_cb: + * @idle: The idle class instance + * @mode: The idle mode, e.g. GPM_IDLE_MODE_BLANK + * @manager: This class instance + * + * This callback is called when the idle class 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_manager_idle_changed_cb (GpmIdle *idle, GpmIdleMode mode, GpmManager *manager) +{ + /* ConsoleKit says we are not on active console */ + if (!egg_console_kit_is_active (manager->priv->console)) { + egg_debug ("ignoring as not on active console"); + return; + } + + /* Ignore back-to-NORMAL events when the lid is closed, as the DPMS is + * already off, and we don't want to re-enable the screen when the user + * moves the mouse on systems that do not support hardware blanking. */ + if (gpm_button_is_lid_closed (manager->priv->button) && + mode == GPM_IDLE_MODE_NORMAL) { + egg_debug ("lid is closed, so we are ignoring ->NORMAL state changes"); + return; + } + + if (mode == GPM_IDLE_MODE_SLEEP) { + egg_debug ("Idle state changed: SLEEP"); + if (gpm_manager_is_inhibit_valid (manager, FALSE, "timeout action") == FALSE) + return; + gpm_manager_idle_do_sleep (manager); + } +} + +/** + * gpm_manager_lid_button_pressed: + * @manager: This class instance + * @state: TRUE for closed + * + * Does actions when the lid is closed, depending on if we are on AC or + * battery power. + **/ +static void +gpm_manager_lid_button_pressed (GpmManager *manager, gboolean pressed) +{ + if (pressed) + gpm_manager_play (manager, GPM_MANAGER_SOUND_LID_CLOSE, FALSE); + else + gpm_manager_play (manager, GPM_MANAGER_SOUND_LID_OPEN, FALSE); + + if (pressed == FALSE) { + /* we turn the lid dpms back on unconditionally */ + gpm_manager_unblank_screen (manager, NULL); + return; + } + + if (!manager->priv->on_battery) { + egg_debug ("Performing AC policy"); + gpm_manager_perform_policy (manager, GPM_CONF_BUTTON_LID_AC, + "The lid has been closed on ac power."); + return; + } + + egg_debug ("Performing battery policy"); + gpm_manager_perform_policy (manager, GPM_CONF_BUTTON_LID_BATT, + "The lid has been closed on battery power."); +} + +static void +gpm_manager_update_dpms_throttle (GpmManager *manager) +{ + GpmDpmsMode mode; + gpm_dpms_get_mode (manager->priv->dpms, &mode, NULL); + + /* Throttle the manager when DPMS is active since we can't see it anyway */ + if (mode == GPM_DPMS_MODE_ON) { + if (manager->priv->screensaver_dpms_throttle_id != 0) { + gpm_screensaver_remove_throttle (manager->priv->screensaver, manager->priv->screensaver_dpms_throttle_id); + manager->priv->screensaver_dpms_throttle_id = 0; + } + } else { + /* if throttle already exists then remove */ + if (manager->priv->screensaver_dpms_throttle_id != 0) { + gpm_screensaver_remove_throttle (manager->priv->screensaver, manager->priv->screensaver_dpms_throttle_id); + } + /* TRANSLATORS: this is the gnome-screensaver throttle */ + manager->priv->screensaver_dpms_throttle_id = gpm_screensaver_add_throttle (manager->priv->screensaver, _("Display DPMS activated")); + } +} + +static void +gpm_manager_update_ac_throttle (GpmManager *manager) +{ + /* Throttle the manager when we are not on AC power so we don't + waste the battery */ + if (!manager->priv->on_battery) { + if (manager->priv->screensaver_ac_throttle_id != 0) { + gpm_screensaver_remove_throttle (manager->priv->screensaver, manager->priv->screensaver_ac_throttle_id); + manager->priv->screensaver_ac_throttle_id = 0; + } + } else { + /* if throttle already exists then remove */ + if (manager->priv->screensaver_ac_throttle_id != 0) + gpm_screensaver_remove_throttle (manager->priv->screensaver, manager->priv->screensaver_ac_throttle_id); + /* TRANSLATORS: this is the gnome-screensaver throttle */ + manager->priv->screensaver_ac_throttle_id = gpm_screensaver_add_throttle (manager->priv->screensaver, _("On battery power")); + } +} + +static void +gpm_manager_update_lid_throttle (GpmManager *manager, gboolean lid_is_closed) +{ + /* Throttle the screensaver when the lid is close since we can't see it anyway + and it may overheat the laptop */ + if (lid_is_closed == FALSE) { + if (manager->priv->screensaver_lid_throttle_id != 0) { + gpm_screensaver_remove_throttle (manager->priv->screensaver, manager->priv->screensaver_lid_throttle_id); + manager->priv->screensaver_lid_throttle_id = 0; + } + } else { + /* if throttle already exists then remove */ + if (manager->priv->screensaver_lid_throttle_id != 0) + gpm_screensaver_remove_throttle (manager->priv->screensaver, manager->priv->screensaver_lid_throttle_id); + manager->priv->screensaver_lid_throttle_id = gpm_screensaver_add_throttle (manager->priv->screensaver, _("Laptop lid is closed")); + } +} + +/** + * gpm_manager_button_pressed_cb: + * @power: The power class instance + * @type: The button type, e.g. "power" + * @state: The state, where TRUE is depressed or closed + * @manager: This class instance + **/ +static void +gpm_manager_button_pressed_cb (GpmButton *button, const gchar *type, GpmManager *manager) +{ + gchar *message; + egg_debug ("Button press event type=%s", type); + + /* ConsoleKit says we are not on active console */ + if (!egg_console_kit_is_active (manager->priv->console)) { + egg_debug ("ignoring as not on active console"); + return; + } + + if (g_strcmp0 (type, GPM_BUTTON_POWER) == 0) { + gpm_manager_perform_policy (manager, GPM_CONF_BUTTON_POWER, "The power button has been pressed."); + } else if (g_strcmp0 (type, GPM_BUTTON_SLEEP) == 0) { + gpm_manager_perform_policy (manager, GPM_CONF_BUTTON_SUSPEND, "The suspend button has been pressed."); + } else if (g_strcmp0 (type, GPM_BUTTON_SUSPEND) == 0) { + gpm_manager_perform_policy (manager, GPM_CONF_BUTTON_SUSPEND, "The suspend button has been pressed."); + } else if (g_strcmp0 (type, GPM_BUTTON_HIBERNATE) == 0) { + gpm_manager_perform_policy (manager, GPM_CONF_BUTTON_HIBERNATE, "The hibernate button has been pressed."); + } else if (g_strcmp0 (type, GPM_BUTTON_LID_OPEN) == 0) { + gpm_manager_lid_button_pressed (manager, FALSE); + } else if (g_strcmp0 (type, GPM_BUTTON_LID_CLOSED) == 0) { + gpm_manager_lid_button_pressed (manager, TRUE); + } else if (g_strcmp0 (type, GPM_BUTTON_BATTERY) == 0) { + message = gpm_engine_get_summary (manager->priv->engine); + gpm_manager_notify (manager, &manager->priv->notification_general, + _("Power Information"), + message, + GPM_MANAGER_NOTIFY_TIMEOUT_LONG, + GTK_STOCK_DIALOG_INFO, + NOTIFY_URGENCY_NORMAL); + g_free (message); + } + + /* really belongs in gnome-screensaver */ + if (g_strcmp0 (type, GPM_BUTTON_LOCK) == 0) + gpm_screensaver_lock (manager->priv->screensaver); + + /* disable or enable the fancy screensaver, as we don't want + * this starting when the lid is shut */ + if (g_strcmp0 (type, GPM_BUTTON_LID_CLOSED) == 0) + gpm_manager_update_lid_throttle (manager, TRUE); + else if (g_strcmp0 (type, GPM_BUTTON_LID_OPEN) == 0) + gpm_manager_update_lid_throttle (manager, FALSE); +} + +/** + * gpm_manager_get_spindown_timeout: + **/ +static gint +gpm_manager_get_spindown_timeout (GpmManager *manager) +{ + gboolean enabled; + gint timeout; + + /* get policy */ + if (!manager->priv->on_battery) { + enabled = gconf_client_get_bool (manager->priv->conf, GPM_CONF_DISKS_SPINDOWN_ENABLE_AC, NULL); + timeout = gconf_client_get_int (manager->priv->conf, GPM_CONF_DISKS_SPINDOWN_TIMEOUT_AC, NULL); + } else { + enabled = gconf_client_get_bool (manager->priv->conf, GPM_CONF_DISKS_SPINDOWN_ENABLE_BATT, NULL); + timeout = gconf_client_get_int (manager->priv->conf, GPM_CONF_DISKS_SPINDOWN_TIMEOUT_BATT, NULL); + } + if (!enabled) + timeout = 0; + return timeout; +} + +/** + * gpm_manager_client_changed_cb: + **/ +static void +gpm_manager_client_changed_cb (UpClient *client, GpmManager *manager) +{ + gboolean event_when_closed; + gint timeout; + gboolean on_battery; + gboolean lid_is_closed; + + /* get the client state */ + g_object_get (client, + "on-battery", &on_battery, + "lid-is-closed", &lid_is_closed, + NULL); + if (on_battery == manager->priv->on_battery) { + egg_debug ("same state as before, ignoring"); + return; + } + + /* close any discharging notifications */ + if (!on_battery) { + egg_debug ("clearing notify due ac being present"); + gpm_manager_notify_close (manager, manager->priv->notification_warning_low); + gpm_manager_notify_close (manager, manager->priv->notification_discharging); + } + + /* if we are playing a critical charge sound loop, stop it */ + if (!on_battery && manager->priv->critical_alert_timeout_id) { + egg_debug ("stopping alert loop due to ac being present"); + gpm_manager_play_loop_stop (manager); + } + + /* save in local cache */ + manager->priv->on_battery = on_battery; + + /* ConsoleKit says we are not on active console */ + if (!egg_console_kit_is_active (manager->priv->console)) { + egg_debug ("ignoring as not on active console"); + return; + } + + egg_debug ("on_battery: %d", on_battery); + + /* set disk spindown threshold */ + timeout = gpm_manager_get_spindown_timeout (manager); + gpm_disks_set_spindown_timeout (manager->priv->disks, timeout); + + gpm_manager_sync_policy_sleep (manager); + + gpm_manager_update_ac_throttle (manager); + + /* simulate user input, but only when the lid is open */ + if (!lid_is_closed) + gpm_screensaver_poke (manager->priv->screensaver); + + if (!on_battery) + gpm_manager_play (manager, GPM_MANAGER_SOUND_POWER_PLUG, FALSE); + else + gpm_manager_play (manager, GPM_MANAGER_SOUND_POWER_UNPLUG, FALSE); + + /* We do the lid close on battery action if the ac adapter is removed + when the laptop is closed and on battery. Fixes #331655 */ + event_when_closed = gconf_client_get_bool (manager->priv->conf, GPM_CONF_ACTIONS_SLEEP_WHEN_CLOSED, NULL); + + /* We keep track of the lid state so we can do the + lid close on battery action if the ac adapter is removed when the laptop + is closed. Fixes #331655 */ + if (event_when_closed && on_battery && lid_is_closed) { + gpm_manager_perform_policy (manager, GPM_CONF_BUTTON_LID_BATT, + "The lid has been closed, and the ac adapter " + "removed (and gconf is okay)."); + } +} + +/** + * manager_critical_action_do: + * @manager: This class instance + * + * This is the stub function when we have waited a few seconds for the user to + * see the message, explaining what we are about to do. + * + * Return value: FALSE, as we don't want to repeat this action on resume. + **/ +static gboolean +manager_critical_action_do (GpmManager *manager) +{ + /* stop playing the alert as it's too late to do anything now */ + if (manager->priv->critical_alert_timeout_id) + gpm_manager_play_loop_stop (manager); + + gpm_manager_perform_policy (manager, GPM_CONF_ACTIONS_CRITICAL_BATT, "Battery is critically low."); + return FALSE; +} + +/** + * gpm_manager_class_init: + * @klass: The GpmManagerClass + **/ +static void +gpm_manager_class_init (GpmManagerClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + object_class->finalize = gpm_manager_finalize; + g_type_class_add_private (klass, sizeof (GpmManagerPrivate)); +} + +/** + * gpm_conf_gconf_key_changed_cb: + * + * We might have to do things when the gconf keys change; do them here. + **/ +static void +gpm_conf_gconf_key_changed_cb (GConfClient *client, guint cnxn_id, GConfEntry *entry, GpmManager *manager) +{ + GConfValue *value; + + value = gconf_entry_get_value (entry); + if (value == NULL) + return; + + if (g_strcmp0 (entry->key, GPM_CONF_TIMEOUT_SLEEP_COMPUTER_BATT) == 0 || + g_strcmp0 (entry->key, GPM_CONF_TIMEOUT_SLEEP_COMPUTER_AC) == 0 || + g_strcmp0 (entry->key, GPM_CONF_TIMEOUT_SLEEP_DISPLAY_BATT) == 0 || + g_strcmp0 (entry->key, GPM_CONF_TIMEOUT_SLEEP_DISPLAY_AC) == 0) + gpm_manager_sync_policy_sleep (manager); +} + +#if 0 +/** + * gpm_manager_screensaver_auth_request_cb: + * @manager: This manager class instance + * @auth: If we are trying to authenticate + * + * Called when the user is trying or has authenticated + **/ +static void +gpm_manager_screensaver_auth_request_cb (GpmScreensaver *screensaver, gboolean auth_begin, GpmManager *manager) +{ + GError *error = NULL; + + if (auth_begin) { + /* We turn on the monitor unconditionally, as we may be using + * a smartcard to authenticate and DPMS might still be on. + * See #350291 for more details */ + gpm_dpms_set_mode (manager->priv->dpms, GPM_DPMS_MODE_ON, &error); + if (error != NULL) { + egg_warning ("Failed to turn on DPMS: %s", error->message); + g_error_free (error); + error = NULL; + } + } +} +#endif + +/** + * gpm_manager_perhaps_recall_response_cb: + */ +static void +gpm_manager_perhaps_recall_response_cb (GtkDialog *dialog, gint response_id, GpmManager *manager) +{ + GdkScreen *screen; + GtkWidget *dialog_error; + GError *error = NULL; + gboolean ret; + const gchar *website; + + /* don't show this again */ + if (response_id == GTK_RESPONSE_CANCEL) { + gconf_client_set_bool (manager->priv->conf, GPM_CONF_NOTIFY_PERHAPS_RECALL, FALSE, NULL); + goto out; + } + + /* visit recall website */ + if (response_id == GTK_RESPONSE_OK) { + screen = gdk_screen_get_default(); + website = (const gchar *) g_object_get_data (G_OBJECT (manager), "recall-oem-website"); + ret = gtk_show_uri (screen, website, gtk_get_current_event_time (), &error); + if (!ret) { + dialog_error = gtk_message_dialog_new (NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_INFO, GTK_BUTTONS_OK, + "Failed to show url %s", error->message); + gtk_dialog_run (GTK_DIALOG (dialog_error)); + g_error_free (error); + } + goto out; + } +out: + gtk_widget_destroy (GTK_WIDGET (dialog)); + return; +} + +/** + * gpm_manager_perhaps_recall_delay_cb: + */ +static gboolean +gpm_manager_perhaps_recall_delay_cb (GpmManager *manager) +{ + const gchar *oem_vendor; + gchar *title = NULL; + gchar *message = NULL; + GtkWidget *dialog; + + oem_vendor = (const gchar *) g_object_get_data (G_OBJECT (manager), "recall-oem-vendor"); + + /* TRANSLATORS: the battery may be recalled by it's vendor */ + title = g_strdup_printf ("%s: %s", GPM_NAME, _("Battery may be recalled")); + message = g_strdup_printf (_("A battery in your computer may have been " + "recalled by %s and you may be at risk.\n\n" + "For more information visit the battery recall website."), oem_vendor); + dialog = gtk_message_dialog_new_with_markup (NULL, GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_INFO, GTK_BUTTONS_CLOSE, + "%s", title); + + gtk_message_dialog_format_secondary_markup (GTK_MESSAGE_DIALOG (dialog), "%s", message); + + /* TRANSLATORS: button text, visit the manufacturers recall website */ + gtk_dialog_add_button (GTK_DIALOG (dialog), _("Visit recall website"), GTK_RESPONSE_OK); + + /* TRANSLATORS: button text, do not show this bubble again */ + gtk_dialog_add_button (GTK_DIALOG (dialog), _("Do not show me this again"), GTK_RESPONSE_CANCEL); + + /* wait async for response */ + gtk_widget_show (dialog); + g_signal_connect (dialog, "response", G_CALLBACK (gpm_manager_perhaps_recall_response_cb), manager); + + g_free (title); + g_free (message); + + /* never repeat */ + return FALSE; +} + +/** + * gpm_manager_engine_perhaps_recall_cb: + */ +static void +gpm_manager_engine_perhaps_recall_cb (GpmEngine *engine, UpDevice *device, gchar *oem_vendor, gchar *website, GpmManager *manager) +{ + gboolean ret; + + /* don't show when running under GDM */ + if (g_getenv ("RUNNING_UNDER_GDM") != NULL) { + egg_debug ("running under gdm, so no notification"); + return; + } + + /* already shown, and dismissed */ + ret = gconf_client_get_bool (manager->priv->conf, GPM_CONF_NOTIFY_PERHAPS_RECALL, NULL); + if (!ret) { + egg_debug ("GConf prevents notification: %s", GPM_CONF_NOTIFY_PERHAPS_RECALL); + return; + } + + g_object_set_data_full (G_OBJECT (manager), "recall-oem-vendor", (gpointer) g_strdup (oem_vendor), (GDestroyNotify) g_free); + g_object_set_data_full (G_OBJECT (manager), "recall-oem-website", (gpointer) g_strdup (website), (GDestroyNotify) g_free); + + /* delay by a few seconds so the panel can load */ + g_timeout_add_seconds (GPM_MANAGER_RECALL_DELAY, (GSourceFunc) gpm_manager_perhaps_recall_delay_cb, manager); +} + +/** + * gpm_manager_engine_icon_changed_cb: + */ +static void +gpm_manager_engine_icon_changed_cb (GpmEngine *engine, gchar *icon, GpmManager *manager) +{ + gpm_tray_icon_set_icon (manager->priv->tray_icon, icon); +} + +/** + * gpm_manager_engine_summary_changed_cb: + */ +static void +gpm_manager_engine_summary_changed_cb (GpmEngine *engine, gchar *summary, GpmManager *manager) +{ + gpm_tray_icon_set_tooltip (manager->priv->tray_icon, summary); +} + +/** + * gpm_manager_engine_low_capacity_cb: + */ +static void +gpm_manager_engine_low_capacity_cb (GpmEngine *engine, UpDevice *device, GpmManager *manager) +{ + gchar *message = NULL; + const gchar *title; + gdouble capacity; + + /* don't show when running under GDM */ + if (g_getenv ("RUNNING_UNDER_GDM") != NULL) { + egg_debug ("running under gdm, so no notification"); + goto out; + } + + /* get device properties */ + g_object_get (device, + "capacity", &capacity, + NULL); + + /* We should notify the user if the battery has a low capacity, + * where capacity is the ratio of the last_full capacity with that of + * the design capacity. (#326740) */ + + /* TRANSLATORS: battery is old or broken */ + title = _("Battery may be broken"); + + /* TRANSLATORS: notify the user that that battery is broken as the capacity is very low */ + message = g_strdup_printf (_("Battery has a very low capacity (%1.1f%%), " + "which means that it may be old or broken."), capacity); + gpm_manager_notify (manager, &manager->priv->notification_general, title, message, GPM_MANAGER_NOTIFY_TIMEOUT_SHORT, + GTK_STOCK_DIALOG_INFO, NOTIFY_URGENCY_LOW); +out: + g_free (message); +} + +/** + * gpm_manager_engine_fully_charged_cb: + */ +static void +gpm_manager_engine_fully_charged_cb (GpmEngine *engine, UpDevice *device, GpmManager *manager) +{ + UpDeviceKind kind; + gchar *native_path = NULL; + gboolean ret; + guint plural = 1; + const gchar *title; + + /* only action this if specified in gconf */ + ret = gconf_client_get_bool (manager->priv->conf, GPM_CONF_NOTIFY_FULLY_CHARGED, NULL); + if (!ret) { + egg_debug ("no notification"); + goto out; + } + + /* don't show when running under GDM */ + if (g_getenv ("RUNNING_UNDER_GDM") != NULL) { + egg_debug ("running under gdm, so no notification"); + goto out; + } + + /* get device properties */ + g_object_get (device, + "kind", &kind, + "native-path", &native_path, + NULL); + + if (kind == UP_DEVICE_KIND_BATTERY) { + /* is this a dummy composite device, which is plural? */ + if (g_str_has_prefix (native_path, "dummy")) + plural = 2; + + /* hide the discharging notification */ + gpm_manager_notify_close (manager, manager->priv->notification_warning_low); + gpm_manager_notify_close (manager, manager->priv->notification_discharging); + + /* TRANSLATORS: show the charged notification */ + title = ngettext ("Battery Charged", "Batteries Charged", plural); + gpm_manager_notify (manager, &manager->priv->notification_fully_charged, + title, NULL, GPM_MANAGER_NOTIFY_TIMEOUT_SHORT, + GTK_STOCK_DIALOG_INFO, NOTIFY_URGENCY_LOW); + } +out: + g_free (native_path); +} + +/** + * gpm_manager_engine_discharging_cb: + */ +static void +gpm_manager_engine_discharging_cb (GpmEngine *engine, UpDevice *device, GpmManager *manager) +{ + UpDeviceKind kind; + gboolean ret; + const gchar *title; + const gchar *message; + gdouble percentage; + gint64 time_to_empty; + gchar *remaining_text = NULL; + gchar *icon = NULL; + const gchar *kind_desc; + + /* only action this if specified in gconf */ + ret = gconf_client_get_bool (manager->priv->conf, GPM_CONF_NOTIFY_DISCHARGING, NULL); + if (!ret) { + egg_debug ("no notification"); + goto out; + } + + /* get device properties */ + g_object_get (device, + "kind", &kind, + "percentage", &percentage, + "time-to-empty", &time_to_empty, + NULL); + + /* only show text if there is a valid time */ + if (time_to_empty > 0) + remaining_text = gpm_get_timestring (time_to_empty); + kind_desc = gpm_device_kind_to_localised_text (kind, 1); + + if (kind == UP_DEVICE_KIND_BATTERY) { + /* TRANSLATORS: laptop battery is now discharging */ + title = _("Battery Discharging"); + + if (remaining_text != NULL) { + /* TRANSLATORS: tell the user how much time they have got */ + message = g_strdup_printf (_("%s of battery power remaining (%.0f%%)"), remaining_text, percentage); + } else { + /* TRANSLATORS: the device is discharging, but we only have a percentage */ + message = g_strdup_printf (_("%s discharging (%.0f%%)"), + kind_desc, percentage); + } + } else if (kind == UP_DEVICE_KIND_UPS) { + /* TRANSLATORS: UPS is now discharging */ + title = _("UPS Discharging"); + + if (remaining_text != NULL) { + /* TRANSLATORS: tell the user how much time they have got */ + message = g_strdup_printf (_("%s of UPS backup power remaining (%.0f%%)"), remaining_text, percentage); + } else { + /* TRANSLATORS: the device is discharging, but we only have a percentage */ + message = g_strdup_printf (_("%s discharging (%.0f%%)"), + kind_desc, percentage); + } + } else { + /* nothing else of interest */ + goto out; + } + + icon = gpm_upower_get_device_icon (device); + /* show the notification */ + gpm_manager_notify (manager, &manager->priv->notification_discharging, title, message, GPM_MANAGER_NOTIFY_TIMEOUT_LONG, + icon, NOTIFY_URGENCY_NORMAL); +out: + g_free (icon); + g_free (remaining_text); + return; +} + +/** + * gpm_manager_engine_just_laptop_battery: + */ +static gboolean +gpm_manager_engine_just_laptop_battery (GpmManager *manager) +{ + UpDevice *device; + UpDeviceKind kind; + GPtrArray *array; + gboolean ret = TRUE; + guint i; + + /* find if there are any other device types that mean we have to + * be more specific in our wording */ + array = gpm_engine_get_devices (manager->priv->engine); + for (i=0; ilen; i++) { + device = g_ptr_array_index (array, i); + g_object_get (device, "kind", &kind, NULL); + if (kind != UP_DEVICE_KIND_BATTERY) { + ret = FALSE; + break; + } + } + g_ptr_array_unref (array); + return ret; +} + +/** + * gpm_manager_engine_charge_low_cb: + */ +static void +gpm_manager_engine_charge_low_cb (GpmEngine *engine, UpDevice *device, GpmManager *manager) +{ + const gchar *title = NULL; + gchar *message = NULL; + gchar *remaining_text; + gchar *icon = NULL; + UpDeviceKind kind; + gdouble percentage; + gint64 time_to_empty; + gboolean ret; + + /* get device properties */ + g_object_get (device, + "kind", &kind, + "percentage", &percentage, + "time-to-empty", &time_to_empty, + NULL); + + /* check to see if the batteries have not noticed we are on AC */ + if (kind == UP_DEVICE_KIND_BATTERY) { + if (!manager->priv->on_battery) { + egg_warning ("ignoring critically low message as we are not on battery power"); + goto out; + } + } + + if (kind == UP_DEVICE_KIND_BATTERY) { + + /* if the user has no other batteries, drop the "Laptop" wording */ + ret = gpm_manager_engine_just_laptop_battery (manager); + if (ret) { + /* TRANSLATORS: laptop battery low, and we only have one battery */ + title = _("Battery low"); + } else { + /* TRANSLATORS: laptop battery low, and we have more than one kind of battery */ + title = _("Laptop battery low"); + } + + remaining_text = gpm_get_timestring (time_to_empty); + + /* TRANSLATORS: tell the user how much time they have got */ + message = g_strdup_printf (_("Approximately %s remaining (%.0f%%)"), remaining_text, percentage); + + } else if (kind == UP_DEVICE_KIND_UPS) { + /* TRANSLATORS: UPS is starting to get a little low */ + title = _("UPS low"); + remaining_text = gpm_get_timestring (time_to_empty); + + /* TRANSLATORS: tell the user how much time they have got */ + message = g_strdup_printf (_("Approximately %s of remaining UPS backup power (%.0f%%)"), + remaining_text, percentage); + } else if (kind == UP_DEVICE_KIND_MOUSE) { + /* TRANSLATORS: mouse is getting a little low */ + title = _("Mouse battery low"); + + /* TRANSLATORS: tell user more details */ + message = g_strdup_printf (_("Wireless mouse is low in power (%.0f%%)"), percentage); + + } else if (kind == UP_DEVICE_KIND_KEYBOARD) { + /* TRANSLATORS: keyboard is getting a little low */ + title = _("Keyboard battery low"); + + /* TRANSLATORS: tell user more details */ + message = g_strdup_printf (_("Wireless keyboard is low in power (%.0f%%)"), percentage); + + } else if (kind == UP_DEVICE_KIND_PDA) { + /* TRANSLATORS: PDA is getting a little low */ + title = _("PDA battery low"); + + /* TRANSLATORS: tell user more details */ + message = g_strdup_printf (_("PDA is low in power (%.0f%%)"), percentage); + + } else if (kind == UP_DEVICE_KIND_PHONE) { + /* TRANSLATORS: cell phone (mobile) is getting a little low */ + title = _("Cell phone battery low"); + + /* TRANSLATORS: tell user more details */ + message = g_strdup_printf (_("Cell phone is low in power (%.0f%%)"), percentage); + +#if UP_CHECK_VERSION(0,9,5) + } else if (kind == UP_DEVICE_KIND_MEDIA_PLAYER) { + /* TRANSLATORS: media player, e.g. mp3 is getting a little low */ + title = _("Media player battery low"); + + /* TRANSLATORS: tell user more details */ + message = g_strdup_printf (_("Media player is low in power (%.0f%%)"), percentage); + + } else if (kind == UP_DEVICE_KIND_TABLET) { + /* TRANSLATORS: graphics tablet, e.g. wacom is getting a little low */ + title = _("Tablet battery low"); + + /* TRANSLATORS: tell user more details */ + message = g_strdup_printf (_("Tablet is low in power (%.0f%%)"), percentage); + + } else if (kind == UP_DEVICE_KIND_COMPUTER) { + /* TRANSLATORS: computer, e.g. ipad is getting a little low */ + title = _("Attached computer battery low"); + + /* TRANSLATORS: tell user more details */ + message = g_strdup_printf (_("Attached computer is low in power (%.0f%%)"), percentage); +#endif + } + + /* get correct icon */ + icon = gpm_upower_get_device_icon (device); + gpm_manager_notify (manager, &manager->priv->notification_warning_low, title, message, GPM_MANAGER_NOTIFY_TIMEOUT_LONG, icon, NOTIFY_URGENCY_NORMAL); + gpm_manager_play (manager, GPM_MANAGER_SOUND_BATTERY_CAUTION, TRUE); +out: + g_free (icon); + g_free (message); +} + +/** + * gpm_manager_engine_charge_critical_cb: + */ +static void +gpm_manager_engine_charge_critical_cb (GpmEngine *engine, UpDevice *device, GpmManager *manager) +{ + const gchar *title = NULL; + gchar *message = NULL; + gchar *action; + gchar *icon = NULL; + UpDeviceKind kind; + gdouble percentage; + gint64 time_to_empty; + GpmActionPolicy policy; + gboolean ret; + + /* get device properties */ + g_object_get (device, + "kind", &kind, + "percentage", &percentage, + "time-to-empty", &time_to_empty, + NULL); + + /* check to see if the batteries have not noticed we are on AC */ + if (kind == UP_DEVICE_KIND_BATTERY) { + if (!manager->priv->on_battery) { + egg_warning ("ignoring critically low message as we are not on battery power"); + goto out; + } + } + + if (kind == UP_DEVICE_KIND_BATTERY) { + + /* if the user has no other batteries, drop the "Laptop" wording */ + ret = gpm_manager_engine_just_laptop_battery (manager); + if (ret) { + /* TRANSLATORS: laptop battery critically low, and only have one kind of battery */ + title = _("Battery critically low"); + } else { + /* TRANSLATORS: laptop battery critically low, and we have more than one type of battery */ + title = _("Laptop battery critically low"); + } + + /* we have to do different warnings depending on the policy */ + action = gconf_client_get_string (manager->priv->conf, GPM_CONF_ACTIONS_CRITICAL_BATT, NULL); + policy = gpm_action_policy_from_string (action); + + /* use different text for different actions */ + if (policy == GPM_ACTION_POLICY_NOTHING) { + /* TRANSLATORS: tell the use to insert the plug, as we're not going to do anything */ + message = g_strdup (_("Plug in your AC adapter to avoid losing data.")); + + } else if (policy == GPM_ACTION_POLICY_SUSPEND) { + /* TRANSLATORS: give the user a ultimatum */ + message = g_strdup_printf (_("Computer will suspend very soon unless it is plugged in.")); + + } else if (policy == GPM_ACTION_POLICY_HIBERNATE) { + /* TRANSLATORS: give the user a ultimatum */ + message = g_strdup_printf (_("Computer will hibernate very soon unless it is plugged in.")); + + } else if (policy == GPM_ACTION_POLICY_SHUTDOWN) { + /* TRANSLATORS: give the user a ultimatum */ + message = g_strdup_printf (_("Computer will shutdown very soon unless it is plugged in.")); + } + + g_free (action); + } else if (kind == UP_DEVICE_KIND_UPS) { + gchar *remaining_text; + + /* TRANSLATORS: the UPS is very low */ + title = _("UPS critically low"); + remaining_text = gpm_get_timestring (time_to_empty); + + /* TRANSLATORS: give the user a ultimatum */ + message = g_strdup_printf (_("Approximately %s of remaining UPS power (%.0f%%). " + "Restore AC power to your computer to avoid losing data."), + remaining_text, percentage); + g_free (remaining_text); + } else if (kind == UP_DEVICE_KIND_MOUSE) { + /* TRANSLATORS: the mouse battery is very low */ + title = _("Mouse battery low"); + + /* TRANSLATORS: the device is just going to stop working */ + message = g_strdup_printf (_("Wireless mouse is very low in power (%.0f%%). " + "This device will soon stop functioning if not charged."), + percentage); + } else if (kind == UP_DEVICE_KIND_KEYBOARD) { + /* TRANSLATORS: the keyboard battery is very low */ + title = _("Keyboard battery low"); + + /* TRANSLATORS: the device is just going to stop working */ + message = g_strdup_printf (_("Wireless keyboard is very low in power (%.0f%%). " + "This device will soon stop functioning if not charged."), + percentage); + } else if (kind == UP_DEVICE_KIND_PDA) { + + /* TRANSLATORS: the PDA battery is very low */ + title = _("PDA battery low"); + + /* TRANSLATORS: the device is just going to stop working */ + message = g_strdup_printf (_("PDA is very low in power (%.0f%%). " + "This device will soon stop functioning if not charged."), + percentage); + + } else if (kind == UP_DEVICE_KIND_PHONE) { + + /* TRANSLATORS: the cell battery is very low */ + title = _("Cell phone battery low"); + + /* TRANSLATORS: the device is just going to stop working */ + message = g_strdup_printf (_("Cell phone is very low in power (%.0f%%). " + "This device will soon stop functioning if not charged."), + percentage); + +#if UP_CHECK_VERSION(0,9,5) + } else if (kind == UP_DEVICE_KIND_MEDIA_PLAYER) { + + /* TRANSLATORS: the cell battery is very low */ + title = _("Cell phone battery low"); + + /* TRANSLATORS: the device is just going to stop working */ + message = g_strdup_printf (_("Media player is very low in power (%.0f%%). " + "This device will soon stop functioning if not charged."), + percentage); + } else if (kind == UP_DEVICE_KIND_TABLET) { + + /* TRANSLATORS: the cell battery is very low */ + title = _("Tablet battery low"); + + /* TRANSLATORS: the device is just going to stop working */ + message = g_strdup_printf (_("Tablet is very low in power (%.0f%%). " + "This device will soon stop functioning if not charged."), + percentage); + } else if (kind == UP_DEVICE_KIND_COMPUTER) { + + /* TRANSLATORS: the cell battery is very low */ + title = _("Attached computer battery low"); + + /* TRANSLATORS: the device is just going to stop working */ + message = g_strdup_printf (_("Attached computer is very low in power (%.0f%%). " + "The device will soon shutdown if not charged."), + percentage); +#endif + } + + /* get correct icon */ + icon = gpm_upower_get_device_icon (device); + gpm_manager_notify (manager, &manager->priv->notification_warning_low, title, message, GPM_MANAGER_NOTIFY_TIMEOUT_NEVER, icon, NOTIFY_URGENCY_CRITICAL); + + switch (kind) { + + case UP_DEVICE_KIND_BATTERY: + case UP_DEVICE_KIND_UPS: + egg_debug ("critical charge level reached, starting sound loop"); + gpm_manager_play_loop_start (manager, + GPM_MANAGER_SOUND_BATTERY_LOW, + TRUE, + GPM_MANAGER_CRITICAL_ALERT_TIMEOUT); + break; + + default: + gpm_manager_play (manager, GPM_MANAGER_SOUND_BATTERY_LOW, TRUE); + } +out: + g_free (icon); + g_free (message); +} + +/** + * gpm_manager_engine_charge_action_cb: + */ +static void +gpm_manager_engine_charge_action_cb (GpmEngine *engine, UpDevice *device, GpmManager *manager) +{ + const gchar *title = NULL; + gchar *action; + gchar *message = NULL; + gchar *icon = NULL; + UpDeviceKind kind; + GpmActionPolicy policy; + + /* get device properties */ + g_object_get (device, + "kind", &kind, + NULL); + + /* check to see if the batteries have not noticed we are on AC */ + if (kind == UP_DEVICE_KIND_BATTERY) { + if (!manager->priv->on_battery) { + egg_warning ("ignoring critically low message as we are not on battery power"); + goto out; + } + } + + if (kind == UP_DEVICE_KIND_BATTERY) { + + /* TRANSLATORS: laptop battery is really, really, low */ + title = _("Laptop battery critically low"); + + /* we have to do different warnings depending on the policy */ + action = gconf_client_get_string (manager->priv->conf, GPM_CONF_ACTIONS_CRITICAL_BATT, NULL); + policy = gpm_action_policy_from_string (action); + + /* use different text for different actions */ + if (policy == GPM_ACTION_POLICY_NOTHING) { + /* TRANSLATORS: computer will shutdown without saving data */ + message = g_strdup (_("The battery is below the critical level and " + "this computer will power-off when the " + "battery becomes completely empty.")); + + } else if (policy == GPM_ACTION_POLICY_SUSPEND) { + /* TRANSLATORS: computer will suspend */ + message = g_strdup (_("The battery is below the critical level and " + "this computer is about to suspend.
" + "NOTE: A small amount of power is required " + "to keep your computer in a suspended state.")); + + } else if (policy == GPM_ACTION_POLICY_HIBERNATE) { + /* TRANSLATORS: computer will hibernate */ + message = g_strdup (_("The battery is below the critical level and " + "this computer is about to hibernate.")); + + } else if (policy == GPM_ACTION_POLICY_SHUTDOWN) { + /* TRANSLATORS: computer will just shutdown */ + message = g_strdup (_("The battery is below the critical level and " + "this computer is about to shutdown.")); + } + + g_free (action); + + /* wait 20 seconds for user-panic */ + g_timeout_add_seconds (20, (GSourceFunc) manager_critical_action_do, manager); + + } else if (kind == UP_DEVICE_KIND_UPS) { + /* TRANSLATORS: UPS is really, really, low */ + title = _("UPS critically low"); + + /* we have to do different warnings depending on the policy */ + action = gconf_client_get_string (manager->priv->conf, GPM_CONF_ACTIONS_CRITICAL_UPS, NULL); + policy = gpm_action_policy_from_string (action); + + /* use different text for different actions */ + if (policy == GPM_ACTION_POLICY_NOTHING) { + /* TRANSLATORS: computer will shutdown without saving data */ + message = g_strdup (_("The UPS is below the critical level and " + "this computer will power-off when the " + "UPS becomes completely empty.")); + + } else if (policy == GPM_ACTION_POLICY_HIBERNATE) { + /* TRANSLATORS: computer will hibernate */ + message = g_strdup (_("The UPS is below the critical level and " + "this computer is about to hibernate.")); + + } else if (policy == GPM_ACTION_POLICY_SHUTDOWN) { + /* TRANSLATORS: computer will just shutdown */ + message = g_strdup (_("The UPS is below the critical level and " + "this computer is about to shutdown.")); + } + + /* wait 20 seconds for user-panic */ + g_timeout_add_seconds (20, (GSourceFunc) manager_critical_action_do, manager); + + g_free (action); + } + + /* not all types have actions */ + if (title == NULL) + return; + + /* get correct icon */ + icon = gpm_upower_get_device_icon (device); + gpm_manager_notify (manager, &manager->priv->notification_warning_low, + title, message, GPM_MANAGER_NOTIFY_TIMEOUT_NEVER, + icon, NOTIFY_URGENCY_CRITICAL); + gpm_manager_play (manager, GPM_MANAGER_SOUND_BATTERY_LOW, TRUE); +out: + g_free (icon); + g_free (message); +} + +/** + * gpm_manager_dpms_mode_changed_cb: + * @mode: The DPMS mode, e.g. GPM_DPMS_MODE_OFF + * @info: This class instance + * + * Log when the DPMS mode is changed. + **/ +static void +gpm_manager_dpms_mode_changed_cb (GpmDpms *dpms, GpmDpmsMode mode, GpmManager *manager) +{ + egg_debug ("DPMS mode changed: %d", mode); + + if (mode == GPM_DPMS_MODE_ON) + egg_debug ("dpms on"); + else if (mode == GPM_DPMS_MODE_STANDBY) + egg_debug ("dpms standby"); + else if (mode == GPM_DPMS_MODE_SUSPEND) + egg_debug ("suspend"); + else if (mode == GPM_DPMS_MODE_OFF) + egg_debug ("dpms off"); + + gpm_manager_update_dpms_throttle (manager); +} + +/* + * gpm_manager_reset_just_resumed_cb + */ +static gboolean +gpm_manager_reset_just_resumed_cb (gpointer user_data) +{ + GpmManager *manager = GPM_MANAGER (user_data); + + if (manager->priv->notification_general != NULL) + gpm_manager_notify_close (manager, manager->priv->notification_general); + if (manager->priv->notification_warning_low != NULL) + gpm_manager_notify_close (manager, manager->priv->notification_warning_low); + if (manager->priv->notification_discharging != NULL) + gpm_manager_notify_close (manager, manager->priv->notification_discharging); + if (manager->priv->notification_fully_charged != NULL) + gpm_manager_notify_close (manager, manager->priv->notification_fully_charged); + + manager->priv->just_resumed = FALSE; + return FALSE; +} + +/** + * gpm_manager_control_resume_cb + **/ +static void +gpm_manager_control_resume_cb (GpmControl *control, GpmControlAction action, GpmManager *manager) +{ + manager->priv->just_resumed = TRUE; + g_timeout_add_seconds (1, gpm_manager_reset_just_resumed_cb, manager); +} + +/** + * gpm_manager_init: + * @manager: This class instance + **/ +static void +gpm_manager_init (GpmManager *manager) +{ + gboolean check_type_cpu; + gint timeout; + DBusGConnection *connection; + GError *error = NULL; + guint version; + + manager->priv = GPM_MANAGER_GET_PRIVATE (manager); + connection = dbus_g_bus_get (DBUS_BUS_SESSION, &error); + + /* init to unthrottled */ + manager->priv->screensaver_ac_throttle_id = 0; + manager->priv->screensaver_dpms_throttle_id = 0; + manager->priv->screensaver_lid_throttle_id = 0; + + manager->priv->critical_alert_timeout_id = 0; + manager->priv->critical_alert_loop_props = NULL; + + /* init to not just_resumed */ + manager->priv->just_resumed = FALSE; + + /* don't apply policy when not active, so listen to ConsoleKit */ + manager->priv->console = egg_console_kit_new (); + + /* this is a singleton, so we keep a master copy open here */ + manager->priv->prefs_server = gpm_prefs_server_new (); + + manager->priv->notification_general = NULL; + manager->priv->notification_warning_low = NULL; + manager->priv->notification_discharging = NULL; + manager->priv->notification_fully_charged = NULL; + manager->priv->disks = gpm_disks_new (); + manager->priv->conf = gconf_client_get_default (); + manager->priv->client = up_client_new (); + g_signal_connect (manager->priv->client, "changed", + G_CALLBACK (gpm_manager_client_changed_cb), manager); + + /* use libnotify */ + notify_init (GPM_NAME); + + /* watch gnome-power-manager keys */ + gconf_client_add_dir (manager->priv->conf, GPM_CONF_DIR, + GCONF_CLIENT_PRELOAD_RECURSIVE, NULL); + gconf_client_notify_add (manager->priv->conf, GPM_CONF_DIR, + (GConfClientNotifyFunc) gpm_conf_gconf_key_changed_cb, + manager, NULL, NULL); + + /* check to see if the user has installed the schema properly */ + version = gconf_client_get_int (manager->priv->conf, GPM_CONF_SCHEMA_VERSION, NULL); + if (version != GPM_CONF_SCHEMA_ID) { + gpm_manager_notify (manager, &manager->priv->notification_general, + /* TRANSLATORS: there was in install problem */ + _("Install problem!"), + /* TRANSLATORS: the GConf schema was not installed properly */ + _("The configuration defaults for GNOME Power Manager have not been installed correctly.\n" + "Please contact your computer administrator."), + GPM_MANAGER_NOTIFY_TIMEOUT_LONG, + GTK_STOCK_DIALOG_WARNING, + NOTIFY_URGENCY_NORMAL); + egg_error ("no gconf schema installed!"); + } + + /* coldplug so we are in the correct state at startup */ + g_object_get (manager->priv->client, + "on-battery", &manager->priv->on_battery, + NULL); + + manager->priv->button = gpm_button_new (); + g_signal_connect (manager->priv->button, "button-pressed", + G_CALLBACK (gpm_manager_button_pressed_cb), manager); + + /* try and start an interactive service */ + manager->priv->screensaver = gpm_screensaver_new (); +#if 0 + g_signal_connect (manager->priv->screensaver, "auth-request", + G_CALLBACK (gpm_manager_screensaver_auth_request_cb), manager); +#endif + + /* try an start an interactive service */ + manager->priv->backlight = gpm_backlight_new (); + if (manager->priv->backlight != NULL) { + /* add the new brightness lcd DBUS interface */ + dbus_g_object_type_install_info (GPM_TYPE_BACKLIGHT, + &dbus_glib_gpm_backlight_object_info); + dbus_g_connection_register_g_object (connection, GPM_DBUS_PATH_BACKLIGHT, + G_OBJECT (manager->priv->backlight)); + } + + manager->priv->idle = gpm_idle_new (); + g_signal_connect (manager->priv->idle, "idle-changed", + G_CALLBACK (gpm_manager_idle_changed_cb), manager); + + /* set up the check_type_cpu, so we can disable the CPU load check */ + check_type_cpu = gconf_client_get_bool (manager->priv->conf, GPM_CONF_IDLE_CHECK_CPU, NULL); + gpm_idle_set_check_cpu (manager->priv->idle, check_type_cpu); + + manager->priv->dpms = gpm_dpms_new (); + g_signal_connect (manager->priv->dpms, "mode-changed", + G_CALLBACK (gpm_manager_dpms_mode_changed_cb), manager); + + /* use the control object */ + egg_debug ("creating new control instance"); + manager->priv->control = gpm_control_new (); + g_signal_connect (manager->priv->control, "resume", + G_CALLBACK (gpm_manager_control_resume_cb), manager); + + egg_debug ("creating new tray icon"); + manager->priv->tray_icon = gpm_tray_icon_new (); + + /* keep a reference for the notifications */ + manager->priv->status_icon = gpm_tray_icon_get_status_icon (manager->priv->tray_icon); + + gpm_manager_sync_policy_sleep (manager); + + manager->priv->engine = gpm_engine_new (); + g_signal_connect (manager->priv->engine, "perhaps-recall", + G_CALLBACK (gpm_manager_engine_perhaps_recall_cb), manager); + g_signal_connect (manager->priv->engine, "low-capacity", + G_CALLBACK (gpm_manager_engine_low_capacity_cb), manager); + g_signal_connect (manager->priv->engine, "icon-changed", + G_CALLBACK (gpm_manager_engine_icon_changed_cb), manager); + g_signal_connect (manager->priv->engine, "summary-changed", + G_CALLBACK (gpm_manager_engine_summary_changed_cb), manager); + g_signal_connect (manager->priv->engine, "fully-charged", + G_CALLBACK (gpm_manager_engine_fully_charged_cb), manager); + g_signal_connect (manager->priv->engine, "discharging", + G_CALLBACK (gpm_manager_engine_discharging_cb), manager); + g_signal_connect (manager->priv->engine, "charge-low", + G_CALLBACK (gpm_manager_engine_charge_low_cb), manager); + g_signal_connect (manager->priv->engine, "charge-critical", + G_CALLBACK (gpm_manager_engine_charge_critical_cb), manager); + g_signal_connect (manager->priv->engine, "charge-action", + G_CALLBACK (gpm_manager_engine_charge_action_cb), manager); + + /* set disk spindown threshold */ + timeout = gpm_manager_get_spindown_timeout (manager); + gpm_disks_set_spindown_timeout (manager->priv->disks, timeout); + + /* update ac throttle */ + gpm_manager_update_ac_throttle (manager); +} + +/** + * gpm_manager_finalize: + * @object: The object to finalize + * + * Finalise the manager, by unref'ing all the depending modules. + **/ +static void +gpm_manager_finalize (GObject *object) +{ + GpmManager *manager; + + g_return_if_fail (object != NULL); + g_return_if_fail (GPM_IS_MANAGER (object)); + + manager = GPM_MANAGER (object); + + g_return_if_fail (manager->priv != NULL); + + /* close any notifications (also unrefs them) */ + if (manager->priv->notification_general != NULL) + gpm_manager_notify_close (manager, manager->priv->notification_general); + if (manager->priv->notification_warning_low != NULL) + gpm_manager_notify_close (manager, manager->priv->notification_warning_low); + if (manager->priv->notification_discharging != NULL) + gpm_manager_notify_close (manager, manager->priv->notification_discharging); + if (manager->priv->notification_fully_charged != NULL) + gpm_manager_notify_close (manager, manager->priv->notification_fully_charged); + if (manager->priv->critical_alert_timeout_id != 0) + g_source_remove (manager->priv->critical_alert_timeout_id); + + g_object_unref (manager->priv->conf); + g_object_unref (manager->priv->disks); + g_object_unref (manager->priv->dpms); + g_object_unref (manager->priv->idle); + g_object_unref (manager->priv->engine); + g_object_unref (manager->priv->tray_icon); + g_object_unref (manager->priv->screensaver); + g_object_unref (manager->priv->prefs_server); + g_object_unref (manager->priv->control); + g_object_unref (manager->priv->button); + g_object_unref (manager->priv->backlight); + g_object_unref (manager->priv->console); + g_object_unref (manager->priv->client); + g_object_unref (manager->priv->status_icon); + + G_OBJECT_CLASS (gpm_manager_parent_class)->finalize (object); +} + +/** + * gpm_manager_new: + * + * Return value: a new GpmManager object. + **/ +GpmManager * +gpm_manager_new (void) +{ + GpmManager *manager; + manager = g_object_new (GPM_TYPE_MANAGER, NULL); + return GPM_MANAGER (manager); +}