1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
2  *
3  * Copyright (C) 2005-2009 Richard Hughes <richard@hughsie.com>
4  * Copyright (C) 2005 William Jon McCann <mccann@jhu.edu>
5  * Copyright (C) 2012-2021 MATE Developers
6  *
7  * Licensed under the GNU General Public License Version 2
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22  */
23 
24 #ifdef HAVE_CONFIG_H
25 #include <config.h>
26 #endif
27 
28 #include <stdlib.h>
29 #include <stdio.h>
30 #include <time.h>
31 #include <errno.h>
32 
33 #include <string.h>
34 #include <sys/time.h>
35 #include <sys/types.h>
36 #include <math.h>
37 #ifdef HAVE_UNISTD_H
38 #include <unistd.h>
39 #endif /* HAVE_UNISTD_H */
40 
41 #include <glib/gi18n.h>
42 #include <gtk/gtk.h>
43 #include <libupower-glib/upower.h>
44 
45 #include "gpm-button.h"
46 #include "gpm-backlight.h"
47 #include "gpm-brightness.h"
48 #include "gpm-control.h"
49 #include "gpm-common.h"
50 #include "gsd-media-keys-window.h"
51 #include "gpm-dpms.h"
52 #include "gpm-idle.h"
53 #include "gpm-marshal.h"
54 #include "gpm-icon-names.h"
55 #include "egg-console-kit.h"
56 
57 struct GpmBacklightPrivate
58 {
59 	UpClient		*client;
60 	GpmBrightness		*brightness;
61 	GpmButton		*button;
62 	GSettings		*settings;
63 	GtkWidget		*popup;
64 	GpmControl		*control;
65 	GpmDpms			*dpms;
66 	GpmIdle			*idle;
67 	EggConsoleKit		*console;
68 	gboolean		 can_dim;
69 	gboolean		 system_is_idle;
70 	GTimer			*idle_timer;
71 	guint			 idle_dim_timeout;
72 	guint			 master_percentage;
73 };
74 
75 enum {
76 	BRIGHTNESS_CHANGED,
77 	LAST_SIGNAL
78 };
79 
80 static guint signals [LAST_SIGNAL] = { 0 };
81 
G_DEFINE_TYPE_WITH_PRIVATE(GpmBacklight,gpm_backlight,G_TYPE_OBJECT)82 G_DEFINE_TYPE_WITH_PRIVATE (GpmBacklight, gpm_backlight, G_TYPE_OBJECT)
83 
84 /**
85  * gpm_backlight_error_quark:
86  * Return value: Our personal error quark.
87  **/
88 GQuark
89 gpm_backlight_error_quark (void)
90 {
91 	static GQuark quark = 0;
92 	if (!quark)
93 		quark = g_quark_from_static_string ("gpm_backlight_error");
94 	return quark;
95 }
96 
97 /**
98  * gpm_backlight_get_brightness:
99  **/
100 gboolean
gpm_backlight_get_brightness(GpmBacklight * backlight,guint * brightness,GError ** error)101 gpm_backlight_get_brightness (GpmBacklight *backlight, guint *brightness, GError **error)
102 {
103 	guint level;
104 	gboolean ret;
105 	g_return_val_if_fail (backlight != NULL, FALSE);
106 	g_return_val_if_fail (GPM_IS_BACKLIGHT (backlight), FALSE);
107 	g_return_val_if_fail (brightness != NULL, FALSE);
108 
109 	/* check if we have the hw */
110 	if (backlight->priv->can_dim == FALSE) {
111 		g_set_error_literal (error, gpm_backlight_error_quark (),
112 				      GPM_BACKLIGHT_ERROR_HARDWARE_NOT_PRESENT,
113 				      "Dim capable hardware not present");
114 		return FALSE;
115 	}
116 
117 	/* gets the current brightness */
118 	ret = gpm_brightness_get (backlight->priv->brightness, &level);
119 	if (ret) {
120 		*brightness = level;
121 	} else {
122 		g_set_error_literal (error, gpm_backlight_error_quark (),
123 				      GPM_BACKLIGHT_ERROR_DATA_NOT_AVAILABLE,
124 				      "Data not available");
125 	}
126 	return ret;
127 }
128 
129 /**
130  * gpm_backlight_set_brightness:
131  **/
132 gboolean
gpm_backlight_set_brightness(GpmBacklight * backlight,guint percentage,GError ** error)133 gpm_backlight_set_brightness (GpmBacklight *backlight, guint percentage, GError **error)
134 {
135 	gboolean ret;
136 	gboolean hw_changed;
137 
138 	g_return_val_if_fail (backlight != NULL, FALSE);
139 	g_return_val_if_fail (GPM_IS_BACKLIGHT (backlight), FALSE);
140 
141 	/* check if we have the hw */
142 	if (backlight->priv->can_dim == FALSE) {
143 		g_set_error_literal (error, gpm_backlight_error_quark (),
144 				      GPM_BACKLIGHT_ERROR_HARDWARE_NOT_PRESENT,
145 				      "Dim capable hardware not present");
146 		return FALSE;
147 	}
148 
149 	/* just set the master percentage for now, don't try to be clever */
150 	backlight->priv->master_percentage = percentage;
151 
152 	/* sets the current policy brightness */
153 	ret = gpm_brightness_set (backlight->priv->brightness, percentage, &hw_changed);
154 	if (!ret) {
155 		g_set_error_literal (error, gpm_backlight_error_quark (),
156 				      GPM_BACKLIGHT_ERROR_GENERAL,
157 				      "Cannot set policy brightness");
158 	}
159 	/* we emit a signal for the brightness applet */
160 	if (ret && hw_changed) {
161 		g_debug ("emitting brightness-changed : %i", percentage);
162 		g_signal_emit (backlight, signals [BRIGHTNESS_CHANGED], 0, percentage);
163 	}
164 	return ret;
165 }
166 
167 /**
168  * gpm_backlight_dialog_init:
169  *
170  * Initialises the popup, and makes sure that it matches the compositing of the screen.
171  **/
172 static void
gpm_backlight_dialog_init(GpmBacklight * backlight)173 gpm_backlight_dialog_init (GpmBacklight *backlight)
174 {
175 	if (backlight->priv->popup != NULL
176 	    && !msd_osd_window_is_valid (MSD_OSD_WINDOW (backlight->priv->popup))) {
177 		gtk_widget_destroy (backlight->priv->popup);
178 		backlight->priv->popup = NULL;
179 	}
180 
181 	if (backlight->priv->popup == NULL) {
182 		backlight->priv->popup= msd_media_keys_window_new ();
183 		msd_media_keys_window_set_action_custom (MSD_MEDIA_KEYS_WINDOW (backlight->priv->popup),
184 							 "gpm-brightness-lcd",
185 							 TRUE);
186 		gtk_window_set_position (GTK_WINDOW (backlight->priv->popup), GTK_WIN_POS_NONE);
187 	}
188 }
189 
190 /**
191  * gpm_backlight_dialog_show:
192  *
193  * Show the brightness popup, and place it nicely on the screen.
194  **/
195 static void
gpm_backlight_dialog_show(GpmBacklight * backlight)196 gpm_backlight_dialog_show (GpmBacklight *backlight)
197 {
198 	int            orig_w;
199 	int            orig_h;
200 	int            screen_w;
201 	int            screen_h;
202 	int            x;
203 	int            y;
204 	int            pointer_x;
205 	int            pointer_y;
206 	GtkRequisition win_req;
207 	GdkScreen     *pointer_screen;
208 	GdkRectangle   geometry;
209 	GdkMonitor    *monitor;
210 	GdkDisplay    *display;
211 	GdkSeat       *seat;
212 	GdkDevice     *device;
213 
214 	/*
215 	 * get the window size
216 	 * if the window hasn't been mapped, it doesn't necessarily
217 	 * know its true size, yet, so we need to jump through hoops
218 	 */
219 	gtk_window_get_default_size (GTK_WINDOW (backlight->priv->popup), &orig_w, &orig_h);
220 	gtk_widget_get_preferred_size (backlight->priv->popup, NULL, &win_req);
221 
222 	if (win_req.width > orig_w) {
223 		orig_w = win_req.width;
224 	}
225 	if (win_req.height > orig_h) {
226 		orig_h = win_req.height;
227 	}
228 
229 	pointer_screen = NULL;
230 	display = gtk_widget_get_display (backlight->priv->popup);
231 	seat = gdk_display_get_default_seat (display);
232 	device = gdk_seat_get_pointer (seat);
233 	gdk_device_get_position (device,
234 	                         &pointer_screen,
235 	                         &pointer_x,
236 	                         &pointer_y);
237 
238 	monitor = gdk_display_get_monitor_at_point (gdk_screen_get_display (pointer_screen),
239 						    pointer_x,
240 						    pointer_y);
241 
242 	gdk_monitor_get_geometry (monitor, &geometry);
243 
244 	screen_w = geometry.width;
245 	screen_h = geometry.height;
246 
247 	x = ((screen_w - orig_w) / 2) + geometry.x;
248 	y = geometry.y + (screen_h / 2) + (screen_h / 2 - orig_h) / 2;
249 
250 	gtk_window_move (GTK_WINDOW (backlight->priv->popup), x, y);
251 
252 	gtk_widget_show (backlight->priv->popup);
253 
254 	gdk_display_sync (gtk_widget_get_display (backlight->priv->popup));
255 }
256 
257 /**
258  * gpm_common_sum_scale:
259  *
260  * Finds the average between value1 and value2 set on a scale factor
261  **/
262 static inline gfloat
gpm_common_sum_scale(gfloat value1,gfloat value2,gfloat factor)263 gpm_common_sum_scale (gfloat value1, gfloat value2, gfloat factor)
264 {
265 	gfloat diff;
266 	diff = value1 - value2;
267 	return value2 + (diff * factor);
268 }
269 
270 /**
271  * gpm_backlight_brightness_evaluate_and_set:
272  **/
273 static gboolean
gpm_backlight_brightness_evaluate_and_set(GpmBacklight * backlight,gboolean interactive,gboolean use_initial)274 gpm_backlight_brightness_evaluate_and_set (GpmBacklight *backlight, gboolean interactive, gboolean use_initial)
275 {
276 	gfloat brightness;
277 	gfloat scale;
278 	gboolean ret;
279 	gboolean on_battery;
280 	gboolean do_laptop_lcd;
281 	gboolean enable_action;
282 	gboolean battery_reduce;
283 	gboolean hw_changed;
284 	guint value;
285 	guint old_value;
286 
287 	if (backlight->priv->can_dim == FALSE) {
288 		g_debug ("no dimming hardware");
289 		return FALSE;
290 	}
291 
292 	do_laptop_lcd = g_settings_get_boolean (backlight->priv->settings, GPM_SETTINGS_BACKLIGHT_ENABLE);
293 	if (do_laptop_lcd == FALSE) {
294 		g_warning ("policy is no dimming");
295 		return FALSE;
296 	}
297 
298 	/* get the last set brightness */
299 	brightness = backlight->priv->master_percentage / 100.0f;
300 	g_debug ("1. main brightness %f", brightness);
301 
302 	/* get battery status */
303 	g_object_get (backlight->priv->client,
304 		      "on-battery", &on_battery,
305 		      NULL);
306 
307 	/* reduce if on battery power if we should */
308 	if (use_initial) {
309 		g_debug ("Setting initial brightness level");
310 		battery_reduce = g_settings_get_boolean (backlight->priv->settings, GPM_SETTINGS_BACKLIGHT_BATTERY_REDUCE);
311 		if (on_battery && battery_reduce) {
312 			value = g_settings_get_int (backlight->priv->settings, GPM_SETTINGS_BRIGHTNESS_DIM_BATT);
313 			if (value > 100) {
314 				g_warning ("cannot use battery brightness value %i, correcting to 50", value);
315 				value = 50;
316 			}
317 			scale = (100 - value) / 100.0f;
318 			brightness *= scale;
319 		} else {
320 			scale = 1.0f;
321 		}
322 		g_debug ("2. battery scale %f, brightness %f", scale, brightness);
323 	}
324 
325 	/* reduce if system is momentarily idle */
326 	if (!on_battery)
327 		enable_action = g_settings_get_boolean (backlight->priv->settings, GPM_SETTINGS_IDLE_DIM_AC);
328 	else
329 		enable_action = g_settings_get_boolean (backlight->priv->settings, GPM_SETTINGS_IDLE_DIM_BATT);
330 	if (enable_action && backlight->priv->system_is_idle) {
331 		value = g_settings_get_int (backlight->priv->settings, GPM_SETTINGS_IDLE_BRIGHTNESS);
332 		if (value > 100) {
333 			g_warning ("cannot use idle brightness value %i, correcting to 50", value);
334 			value = 50;
335 		}
336 		scale = value / 100.0f;
337 		brightness *= scale;
338 	} else {
339 		scale = 1.0f;
340 	}
341 	g_debug ("3. idle scale %f, brightness %f", scale, brightness);
342 
343 	/* convert to percentage */
344 	value = (guint) ((brightness * 100.0f) + 0.5);
345 
346 	/* only do stuff if the brightness is different */
347 	gpm_brightness_get (backlight->priv->brightness, &old_value);
348 	if (old_value == value) {
349 		g_debug ("values are the same, no action");
350 		return FALSE;
351 	}
352 
353 	/* only show dialog if interactive */
354 	if (interactive) {
355 		gpm_backlight_dialog_init (backlight);
356 		msd_media_keys_window_set_volume_level (MSD_MEDIA_KEYS_WINDOW (backlight->priv->popup),
357 							round (brightness));
358 		gpm_backlight_dialog_show (backlight);
359 	}
360 
361 	ret = gpm_brightness_set (backlight->priv->brightness, value, &hw_changed);
362 	/* we emit a signal for the brightness applet */
363 	if (ret && hw_changed) {
364 		g_debug ("emitting brightness-changed : %i", value);
365 		g_signal_emit (backlight, signals [BRIGHTNESS_CHANGED], 0, value);
366 	}
367 	return TRUE;
368 }
369 
370 /**
371  * gpm_settings_key_changed_cb:
372  *
373  * We might have to do things when the keys change; do them here.
374  **/
375 static void
gpm_settings_key_changed_cb(GSettings * settings,const gchar * key,GpmBacklight * backlight)376 gpm_settings_key_changed_cb (GSettings *settings, const gchar *key, GpmBacklight *backlight)
377 {
378 	gboolean on_battery;
379 
380 	/* get battery status */
381 	g_object_get (backlight->priv->client,
382 		      "on-battery", &on_battery,
383 		      NULL);
384 
385 	if (g_strcmp0 (key, GPM_SETTINGS_BRIGHTNESS_AC) == 0) {
386 		backlight->priv->master_percentage = g_settings_get_double (settings, key);
387 		gpm_backlight_brightness_evaluate_and_set (backlight, FALSE, TRUE);
388 
389 	} else if (on_battery && g_strcmp0 (key, GPM_SETTINGS_BRIGHTNESS_DIM_BATT) == 0) {
390 		gpm_backlight_brightness_evaluate_and_set (backlight, FALSE, TRUE);
391 
392 	} else if (g_strcmp0 (key, GPM_SETTINGS_IDLE_DIM_AC) == 0 ||
393 	           g_strcmp0 (key, GPM_SETTINGS_BACKLIGHT_ENABLE) == 0 ||
394 	           g_strcmp0 (key, GPM_SETTINGS_SLEEP_DISPLAY_BATT) == 0 ||
395 	           g_strcmp0 (key, GPM_SETTINGS_BACKLIGHT_BATTERY_REDUCE) == 0 ||
396 	           g_strcmp0 (key, GPM_SETTINGS_IDLE_BRIGHTNESS) == 0) {
397 		gpm_backlight_brightness_evaluate_and_set (backlight, FALSE, TRUE);
398 
399 	} else if (g_strcmp0 (key, GPM_SETTINGS_IDLE_DIM_TIME) == 0) {
400 		backlight->priv->idle_dim_timeout = g_settings_get_int (settings, key);
401 		gpm_idle_set_timeout_dim (backlight->priv->idle, backlight->priv->idle_dim_timeout);
402 	} else {
403 		g_debug ("unknown key %s", key);
404 	}
405 }
406 
407 /**
408  * gpm_backlight_client_changed_cb:
409  * @client: The up_client class instance
410  * @backlight: This class instance
411  *
412  * Does the actions when the ac power source is inserted/removed.
413  **/
414 static void
gpm_backlight_client_changed_cb(UpClient * client,GParamSpec * pspec,GpmBacklight * backlight)415 gpm_backlight_client_changed_cb (UpClient *client, GParamSpec *pspec, GpmBacklight *backlight)
416 {
417 	gpm_backlight_brightness_evaluate_and_set (backlight, FALSE, TRUE);
418 }
419 
420 /**
421  * gpm_backlight_button_pressed_cb:
422  * @power: The power class instance
423  * @type: The button type, e.g. "power"
424  * @state: The state, where TRUE is depressed or closed
425  * @brightness: This class instance
426  **/
427 static void
gpm_backlight_button_pressed_cb(GpmButton * button,const gchar * type,GpmBacklight * backlight)428 gpm_backlight_button_pressed_cb (GpmButton *button, const gchar *type, GpmBacklight *backlight)
429 {
430 	gboolean ret;
431 	GError *error = NULL;
432 	guint percentage;
433 	gboolean hw_changed;
434 	gboolean on_battery;
435 	g_debug ("Button press event type=%s", type);
436 
437 	if (g_strcmp0 (type, GPM_BUTTON_BRIGHT_UP) == 0) {
438 		/* go up one step */
439 		ret = gpm_brightness_up (backlight->priv->brightness, &hw_changed);
440 
441 		/* show the new value */
442 		if (ret) {
443 			gpm_brightness_get (backlight->priv->brightness, &percentage);
444 			gpm_backlight_dialog_init (backlight);
445 			msd_media_keys_window_set_volume_level (MSD_MEDIA_KEYS_WINDOW (backlight->priv->popup),
446 								percentage);
447 			gpm_backlight_dialog_show (backlight);
448 			/* save the new percentage */
449 			backlight->priv->master_percentage = percentage;
450 			/* if using AC power supply, save the new brightness settings */
451 			g_object_get (backlight->priv->client, "on-battery", &on_battery, NULL);
452 			if (!on_battery) {
453 				g_debug ("saving brightness for ac supply: %i", percentage);
454 				g_settings_set_double (backlight->priv->settings, GPM_SETTINGS_BRIGHTNESS_AC,
455 						       percentage*1.0);
456 			}
457 		}
458 		/* we emit a signal for the brightness applet */
459 		if (ret && hw_changed) {
460 			g_debug ("emitting brightness-changed : %i", percentage);
461 			g_signal_emit (backlight, signals [BRIGHTNESS_CHANGED], 0, percentage);
462 		}
463 	} else if (g_strcmp0 (type, GPM_BUTTON_BRIGHT_DOWN) == 0) {
464 		/* go up down step */
465 		ret = gpm_brightness_down (backlight->priv->brightness, &hw_changed);
466 
467 		/* show the new value */
468 		if (ret) {
469 			gpm_brightness_get (backlight->priv->brightness, &percentage);
470 			gpm_backlight_dialog_init (backlight);
471 			msd_media_keys_window_set_volume_level (MSD_MEDIA_KEYS_WINDOW (backlight->priv->popup),
472 								percentage);
473 			gpm_backlight_dialog_show (backlight);
474 			/* save the new percentage */
475 			backlight->priv->master_percentage = percentage;
476 			/* if using AC power supply, save the new brightness settings */
477 			g_object_get (backlight->priv->client, "on-battery", &on_battery, NULL);
478 			if (!on_battery) {
479 				g_debug ("saving brightness for ac supply: %i", percentage);
480 				g_settings_set_double (backlight->priv->settings, GPM_SETTINGS_BRIGHTNESS_AC,
481 						       percentage*1.0);
482 			}
483 		}
484 		/* we emit a signal for the brightness applet */
485 		if (ret && hw_changed) {
486 			g_debug ("emitting brightness-changed : %i", percentage);
487 			g_signal_emit (backlight, signals [BRIGHTNESS_CHANGED], 0, percentage);
488 		}
489 	} else if (g_strcmp0 (type, GPM_BUTTON_LID_OPEN) == 0) {
490 		/* make sure we undim when we lift the lid */
491 		gpm_backlight_brightness_evaluate_and_set (backlight, FALSE, TRUE);
492 
493 		/* ensure backlight is on */
494 		ret = gpm_dpms_set_mode (backlight->priv->dpms, GPM_DPMS_MODE_ON, &error);
495 		if (!ret) {
496 			g_warning ("failed to turn on DPMS: %s", error->message);
497 			g_error_free (error);
498 		}
499 	}
500 }
501 
502 /**
503  * gpm_backlight_notify_system_idle_changed:
504  **/
505 static gboolean
gpm_backlight_notify_system_idle_changed(GpmBacklight * backlight,gboolean is_idle)506 gpm_backlight_notify_system_idle_changed (GpmBacklight *backlight, gboolean is_idle)
507 {
508 	gdouble elapsed;
509 
510 	/* no point continuing */
511 	if (backlight->priv->system_is_idle == is_idle) {
512 		g_debug ("state not changed");
513 		return FALSE;
514 	}
515 
516 	/* get elapsed time and reset timer */
517 	elapsed = g_timer_elapsed (backlight->priv->idle_timer, NULL);
518 	g_timer_reset (backlight->priv->idle_timer);
519 
520 	if (is_idle == FALSE) {
521 		g_debug ("we have just been idle for %lfs", elapsed);
522 
523 		/* The user immediatly undimmed the screen!
524 		 * We should double the timeout to avoid this happening again */
525 		if (elapsed < 10) {
526 			/* double the event time */
527 			backlight->priv->idle_dim_timeout *= 2.0;
528 			g_debug ("increasing idle dim time to %is", backlight->priv->idle_dim_timeout);
529 			gpm_idle_set_timeout_dim (backlight->priv->idle, backlight->priv->idle_dim_timeout);
530 		}
531 
532 		/* We reset the dimming after 2 minutes of idle,
533 		 * as the user will have changed tasks */
534 		if (elapsed > 2*60) {
535 			/* reset back to our default dimming */
536 			backlight->priv->idle_dim_timeout =
537 				g_settings_get_int (backlight->priv->settings,
538 					   GPM_SETTINGS_IDLE_DIM_TIME);
539 			g_debug ("resetting idle dim time to %is", backlight->priv->idle_dim_timeout);
540 			gpm_idle_set_timeout_dim (backlight->priv->idle, backlight->priv->idle_dim_timeout);
541 		}
542 	} else {
543 		g_debug ("we were active for %lfs", elapsed);
544 	}
545 
546 	g_debug ("changing powersave idle status to %i", is_idle);
547 	backlight->priv->system_is_idle = is_idle;
548 	return TRUE;
549 }
550 
551 /**
552  * idle_changed_cb:
553  * @idle: The idle class instance
554  * @mode: The idle mode, e.g. GPM_IDLE_MODE_BLANK
555  * @manager: This class instance
556  *
557  * This callback is called when mate-screensaver detects that the idle state
558  * has changed. GPM_IDLE_MODE_BLANK is when the session has become inactive,
559  * and GPM_IDLE_MODE_SLEEP is where the session has become inactive, AND the
560  * session timeout has elapsed for the idle action.
561  **/
562 static void
idle_changed_cb(GpmIdle * idle,GpmIdleMode mode,GpmBacklight * backlight)563 idle_changed_cb (GpmIdle *idle, GpmIdleMode mode, GpmBacklight *backlight)
564 {
565 	gboolean ret;
566 	GError *error = NULL;
567 	gboolean on_battery;
568 	GpmDpmsMode dpms_mode;
569 
570 	/* don't dim or undim the screen when the lid is closed */
571 	if (gpm_button_is_lid_closed (backlight->priv->button))
572 		return;
573 
574 	/* don't dim or undim the screen unless ConsoleKit/systemd say we are on the active console */
575 	if (!LOGIND_RUNNING() && !egg_console_kit_is_active (backlight->priv->console)) {
576 		g_debug ("ignoring as not on active console");
577 		return;
578 	}
579 
580 	if (mode == GPM_IDLE_MODE_NORMAL) {
581 		/* sync lcd brightness */
582 		gpm_backlight_notify_system_idle_changed (backlight, FALSE);
583 		gpm_backlight_brightness_evaluate_and_set (backlight, FALSE, TRUE);
584 
585 		/* ensure backlight is on */
586 		ret = gpm_dpms_set_mode (backlight->priv->dpms, GPM_DPMS_MODE_ON, &error);
587 		if (!ret) {
588 			g_warning ("failed to turn on DPMS: %s", error->message);
589 			g_error_free (error);
590 		}
591 
592 	} else if (mode == GPM_IDLE_MODE_DIM) {
593 
594 		/* sync lcd brightness */
595 		gpm_backlight_notify_system_idle_changed (backlight, TRUE);
596 		gpm_backlight_brightness_evaluate_and_set (backlight, FALSE, TRUE);
597 
598 		/* ensure backlight is on */
599 		ret = gpm_dpms_set_mode (backlight->priv->dpms, GPM_DPMS_MODE_ON, &error);
600 		if (!ret) {
601 			g_warning ("failed to turn on DPMS: %s", error->message);
602 			g_error_free (error);
603 		}
604 
605 	} else if (mode == GPM_IDLE_MODE_BLANK) {
606 
607 		/* sync lcd brightness */
608 		gpm_backlight_notify_system_idle_changed (backlight, TRUE);
609 		gpm_backlight_brightness_evaluate_and_set (backlight, FALSE, TRUE);
610 
611 		/* get the DPMS state we're supposed to use on the power state */
612 		g_object_get (backlight->priv->client,
613 			      "on-battery", &on_battery,
614 			      NULL);
615 		if (!on_battery)
616 			dpms_mode = g_settings_get_enum (backlight->priv->settings, GPM_SETTINGS_DPMS_METHOD_AC);
617 		else
618 			dpms_mode = g_settings_get_enum (backlight->priv->settings, GPM_SETTINGS_DPMS_METHOD_BATT);
619 
620 		/* check if method is valid */
621 		if (dpms_mode == GPM_DPMS_MODE_UNKNOWN || dpms_mode == GPM_DPMS_MODE_ON) {
622 			g_warning ("BACKLIGHT method %i unknown. Using OFF.", dpms_mode);
623 			dpms_mode = GPM_DPMS_MODE_OFF;
624 		}
625 
626 		/* turn backlight off */
627 		ret = gpm_dpms_set_mode (backlight->priv->dpms, dpms_mode, &error);
628 		if (!ret) {
629 			g_warning ("failed to change DPMS: %s", error->message);
630 			g_error_free (error);
631 		}
632 
633 	}
634 }
635 
636 /**
637  * brightness_changed_cb:
638  * @brightness: The GpmBrightness class instance
639  * @percentage: The new percentage brightness
640  * @brightness: This class instance
641  *
642  * This callback is called when the brightness value changes.
643  **/
644 static void
brightness_changed_cb(GpmBrightness * brightness,guint percentage,GpmBacklight * backlight)645 brightness_changed_cb (GpmBrightness *brightness, guint percentage, GpmBacklight *backlight)
646 {
647 	/* save the new percentage */
648 	backlight->priv->master_percentage = percentage;
649 
650 	/* we emit a signal for the brightness applet */
651 	g_debug ("emitting brightness-changed : %i", percentage);
652 	g_signal_emit (backlight, signals [BRIGHTNESS_CHANGED], 0, percentage);
653 }
654 
655 /**
656  * control_resume_cb:
657  * @control: The control class instance
658  * @power: This power class instance
659  *
660  * We have to update the caches on resume
661  **/
662 static void
control_resume_cb(GpmControl * control,GpmControlAction action,GpmBacklight * backlight)663 control_resume_cb (GpmControl *control, GpmControlAction action, GpmBacklight *backlight)
664 {
665 	gboolean ret;
666 	GError *error = NULL;
667 
668 	/* ensure backlight is on */
669 	ret = gpm_dpms_set_mode (backlight->priv->dpms, GPM_DPMS_MODE_ON, &error);
670 	if (!ret) {
671 		g_warning ("failed to turn on DPMS: %s", error->message);
672 		g_error_free (error);
673 	}
674 }
675 
676 /**
677  * gpm_backlight_finalize:
678  **/
679 static void
gpm_backlight_finalize(GObject * object)680 gpm_backlight_finalize (GObject *object)
681 {
682 	GpmBacklight *backlight;
683 	g_return_if_fail (object != NULL);
684 	g_return_if_fail (GPM_IS_BACKLIGHT (object));
685 	backlight = GPM_BACKLIGHT (object);
686 
687 	g_timer_destroy (backlight->priv->idle_timer);
688 	gtk_widget_destroy (backlight->priv->popup);
689 
690 	g_object_unref (backlight->priv->dpms);
691 	g_object_unref (backlight->priv->control);
692 	g_object_unref (backlight->priv->settings);
693 	g_object_unref (backlight->priv->client);
694 	g_object_unref (backlight->priv->button);
695 	g_object_unref (backlight->priv->idle);
696 	g_object_unref (backlight->priv->brightness);
697 	g_object_unref (backlight->priv->console);
698 
699 	g_return_if_fail (backlight->priv != NULL);
700 	G_OBJECT_CLASS (gpm_backlight_parent_class)->finalize (object);
701 }
702 
703 /**
704  * gpm_backlight_class_init:
705  **/
706 static void
gpm_backlight_class_init(GpmBacklightClass * klass)707 gpm_backlight_class_init (GpmBacklightClass *klass)
708 {
709 	GObjectClass *object_class = G_OBJECT_CLASS (klass);
710 	object_class->finalize	   = gpm_backlight_finalize;
711 
712 	signals [BRIGHTNESS_CHANGED] =
713 		g_signal_new ("brightness-changed",
714 			      G_TYPE_FROM_CLASS (object_class),
715 			      G_SIGNAL_RUN_LAST,
716 			      G_STRUCT_OFFSET (GpmBacklightClass, brightness_changed),
717 			      NULL, NULL,
718 			      g_cclosure_marshal_VOID__UINT,
719 			      G_TYPE_NONE, 1, G_TYPE_UINT);
720 }
721 
722 /**
723  * gpm_backlight_init:
724  * @brightness: This brightness class instance
725  *
726  * initialises the brightness class. NOTE: We expect laptop_panel objects
727  * to *NOT* be removed or added during the session.
728  * We only control the first laptop_panel object if there are more than one.
729  **/
730 static void
gpm_backlight_init(GpmBacklight * backlight)731 gpm_backlight_init (GpmBacklight *backlight)
732 {
733 	backlight->priv = gpm_backlight_get_instance_private (backlight);
734 
735 	/* record our idle time */
736 	backlight->priv->idle_timer = g_timer_new ();
737 
738 	/* watch for manual brightness changes (for the popup widget) */
739 	backlight->priv->brightness = gpm_brightness_new ();
740 	g_signal_connect (backlight->priv->brightness, "brightness-changed",
741 			  G_CALLBACK (brightness_changed_cb), backlight);
742 
743 	/* we use up_client for the ac-adapter-changed signal */
744 	backlight->priv->client = up_client_new ();
745 	g_signal_connect (backlight->priv->client, "notify",
746 			  G_CALLBACK (gpm_backlight_client_changed_cb), backlight);
747 
748 	/* gets caps */
749 	backlight->priv->can_dim = gpm_brightness_has_hw (backlight->priv->brightness);
750 
751 	/* watch for dim value changes */
752 	backlight->priv->settings = g_settings_new (GPM_SETTINGS_SCHEMA);
753 	g_signal_connect (backlight->priv->settings, "changed", G_CALLBACK (gpm_settings_key_changed_cb), backlight);
754 
755 	/* set the main brightness, this is designed to be updated if the user changes the
756 	 * brightness so we can undim to the 'correct' value */
757 	backlight->priv->master_percentage = g_settings_get_double (backlight->priv->settings, GPM_SETTINGS_BRIGHTNESS_AC);
758 
759 	/* watch for brightness up and down buttons and also check lid state */
760 	backlight->priv->button = gpm_button_new ();
761 	g_signal_connect (backlight->priv->button, "button-pressed",
762 			  G_CALLBACK (gpm_backlight_button_pressed_cb), backlight);
763 
764 	/* watch for idle mode changes */
765 	backlight->priv->idle = gpm_idle_new ();
766 	g_signal_connect (backlight->priv->idle, "idle-changed",
767 			  G_CALLBACK (idle_changed_cb), backlight);
768 
769 	/* assumption */
770 	backlight->priv->system_is_idle = FALSE;
771 	backlight->priv->idle_dim_timeout = g_settings_get_int (backlight->priv->settings, GPM_SETTINGS_IDLE_DIM_TIME);
772 	gpm_idle_set_timeout_dim (backlight->priv->idle, backlight->priv->idle_dim_timeout);
773 
774 	/* use a visual widget */
775 	backlight->priv->popup = msd_media_keys_window_new ();
776 	msd_media_keys_window_set_action_custom (MSD_MEDIA_KEYS_WINDOW (backlight->priv->popup),
777 						 "gpm-brightness-lcd",
778 						 TRUE);
779         gtk_window_set_position (GTK_WINDOW (backlight->priv->popup), GTK_WIN_POS_NONE);
780 
781 	/* DPMS mode poll class */
782 	backlight->priv->dpms = gpm_dpms_new ();
783 
784 	/* we refresh DPMS on resume */
785 	backlight->priv->control = gpm_control_new ();
786 	g_signal_connect (backlight->priv->control, "resume",
787 			  G_CALLBACK (control_resume_cb), backlight);
788 
789 	/* Don't do dimming on inactive console */
790 	backlight->priv->console = egg_console_kit_new ();
791 
792 	/* sync at startup */
793 	gpm_backlight_brightness_evaluate_and_set (backlight, FALSE, TRUE);
794 }
795 
796 /**
797  * gpm_backlight_new:
798  * Return value: A new brightness class instance.
799  **/
800 GpmBacklight *
gpm_backlight_new(void)801 gpm_backlight_new (void)
802 {
803 	GpmBacklight *backlight = g_object_new (GPM_TYPE_BACKLIGHT, NULL);
804 	return backlight;
805 }
806 
807