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