Update copyrights everywhere.
[lxde/lxpanel.git] / src / plugins / batt / batt.c
CommitLineData
8f11d5f8
HJYP
1/*
2 * ACPI battery monitor plugin for LXPanel
3 *
4 * Copyright (C) 2007 by Greg McNew <gmcnew@gmail.com>
802d5540 5 * Copyright (C) 2008 by Hong Jen Yee <pcman.tw@gmail.com>
c887dfa0 6 * Copyright (C) 2009 by Juergen Hoetzel <juergen@archlinux.org>
b840f7cc 7 * Copyright (C) 2014 by Andriy Grytsenko <andrej@rep.kiev.ua>
8f11d5f8
HJYP
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 GNU
17 * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 *
23 *
24 * This plugin monitors battery usage on ACPI-enabled systems by reading the
c887dfa0
JH
25 * battery information found in /sys/class/power_supply. The update interval is
26 * user-configurable and defaults to 3 second.
8f11d5f8
HJYP
27 *
28 * The battery's remaining life is estimated from its current charge and current
29 * rate of discharge. The user may configure an alarm command to be run when
30 * their estimated remaining battery life reaches a certain level.
31 */
32
e751fe05
HJYP
33/* FIXME:
34 * Here are somethings need to be improvec:
35 * 1. Replace pthread stuff with gthread counterparts for portability.
e751fe05
HJYP
36 * 3. Add an option to hide the plugin when AC power is used or there is no battery.
37 * 4. Handle failure gracefully under systems other than Linux.
38*/
39
40#include <glib.h>
8f11d5f8 41#include <glib/gi18n.h>
c0ed75bf 42#include <pthread.h> /* used by pthread_create() and alarmThread */
8f11d5f8
HJYP
43#include <semaphore.h> /* used by update() and alarmProcess() for alarms */
44#include <stdlib.h>
802d5540 45#include <string.h>
9c9d3a00 46#include <stdarg.h>
8f11d5f8 47
811afd8f 48#include "dbg.h" /* for ENTER and RET macros */
c887dfa0 49#include "batt_sys.h"
813c2d44
AG
50#include "misc.h" /* used for lxpanel_generic_config_dlg() */
51#include "plugin.h" /* all other APIs including panel configuration */
8f11d5f8 52
8f11d5f8
HJYP
53/* The last MAX_SAMPLES samples are averaged when charge rates are evaluated.
54 This helps prevent spikes in the "time left" values the user sees. */
55#define MAX_SAMPLES 10
56
802d5540 57typedef struct {
8f11d5f8
HJYP
58 char *alarmCommand,
59 *backgroundColor,
60 *chargingColor1,
61 *chargingColor2,
62 *dischargingColor1,
802d5540
HJYP
63 *dischargingColor2;
64 GdkColor background,
65 charging1,
66 charging2,
67 discharging1,
68 discharging2;
f176735a 69 cairo_surface_t *pixmap;
802d5540 70 GtkWidget *drawingArea;
6a1a639e 71 GtkOrientation orientation;
8f11d5f8
HJYP
72 unsigned int alarmTime,
73 border,
74 height,
75 length,
76 numSamples,
77 requestedBorder,
78 *rateSamples,
79 rateSamplesSum,
80 thickness,
81 timer,
802d5540
HJYP
82 state_elapsed_time,
83 info_elapsed_time,
8f11d5f8 84 wasCharging,
04a2f050
HJYP
85 width,
86 hide_if_no_battery;
8f11d5f8 87 sem_t alarmProcessLock;
c887dfa0 88 battery* b;
3051b49c 89 gboolean has_ac_adapter;
5c0c599d 90 gboolean show_extended_information;
a7bd16a4 91 LXPanel *panel;
813c2d44 92 config_setting_t *settings;
c887dfa0 93} lx_battery;
8f11d5f8
HJYP
94
95
96typedef struct {
97 char *command;
98 sem_t *lock;
4a974f26 99} Alarm;
8f11d5f8 100
813c2d44 101static void destructor(gpointer data);
c887dfa0 102static void update_display(lx_battery *lx_b, gboolean repaint);
3051b49c 103
8f11d5f8
HJYP
104/* alarmProcess takes the address of a dynamically allocated alarm struct (which
105 it must free). It ensures that alarm commands do not run concurrently. */
c0ed75bf 106static void * alarmProcess(void *arg) {
4a974f26 107 Alarm *a = (Alarm *) arg;
8f11d5f8
HJYP
108
109 sem_wait(a->lock);
6a1a639e
AG
110 if (system(a->command) != 0)
111 g_warning("plugin batt: failed to execute alarm command \"%s\"", a->command);
8f11d5f8
HJYP
112 sem_post(a->lock);
113
114 g_free(a);
c0ed75bf 115 return NULL;
8f11d5f8
HJYP
116}
117
9c9d3a00
HG
118
119static void append(gchar **tooltip, gchar *fmt, ...)
120{
121 gchar *old = *tooltip;
122 gchar *new;
123 va_list va;
124
125 va_start(va, fmt);
126 new = g_strdup_vprintf(fmt, va);
127 va_end(va);
128
129 *tooltip = g_strconcat(old, new, NULL);
130
131 g_free(old);
132 g_free(new);
133}
134
135
f855ac58
HG
136/* Make a tooltip string, and display remaining charge time if the battery
137 is charging or remaining life if it's discharging */
138static gchar* make_tooltip(lx_battery* lx_b, gboolean isCharging)
139{
140 gchar * tooltip;
9c9d3a00
HG
141 gchar * indent = " ";
142 battery *b = lx_b->b;
f855ac58 143
029d9f0c 144 if (b == NULL)
811afd8f 145 return NULL;
029d9f0c 146
f855ac58 147 if (isCharging) {
811afd8f
AG
148 int hours = lx_b->b->seconds / 3600;
149 int left_seconds = lx_b->b->seconds - 3600 * hours;
150 int minutes = left_seconds / 60;
151 tooltip = g_strdup_printf(
152 _("Battery: %d%% charged, %d:%02d until full"),
153 lx_b->b->percentage,
154 hours,
155 minutes );
f855ac58 156 } else {
811afd8f
AG
157 /* if we have enough rate information for battery */
158 if (lx_b->b->percentage != 100) {
159 int hours = lx_b->b->seconds / 3600;
160 int left_seconds = lx_b->b->seconds - 3600 * hours;
161 int minutes = left_seconds / 60;
162 tooltip = g_strdup_printf(
163 _("Battery: %d%% charged, %d:%02d left"),
164 lx_b->b->percentage,
165 hours,
166 minutes );
167 } else {
168 tooltip = g_strdup_printf(
169 _("Battery: %d%% charged"),
170 100 );
171 }
f855ac58
HG
172 }
173
5c0c599d 174 if (!lx_b->show_extended_information) {
811afd8f 175 return tooltip;
5c0c599d
HG
176 }
177
9c9d3a00 178 if (b->energy_full_design != -1)
811afd8f 179 append(&tooltip, _("\n%sEnergy full design:\t\t%5d mWh"), indent, b->energy_full_design);
9c9d3a00 180 if (b->energy_full != -1)
811afd8f 181 append(&tooltip, _("\n%sEnergy full:\t\t\t%5d mWh"), indent, b->energy_full);
9c9d3a00 182 if (b->energy_now != -1)
811afd8f 183 append(&tooltip, _("\n%sEnergy now:\t\t\t%5d mWh"), indent, b->energy_now);
9c9d3a00 184 if (b->power_now != -1)
811afd8f 185 append(&tooltip, _("\n%sPower now:\t\t\t%5d mW"), indent, b->power_now);
9c9d3a00
HG
186
187 if (b->charge_full_design != -1)
811afd8f 188 append(&tooltip, _("\n%sCharge full design:\t%5d mAh"), indent, b->charge_full_design);
9c9d3a00 189 if (b->charge_full != -1)
811afd8f 190 append(&tooltip, _("\n%sCharge full:\t\t\t%5d mAh"), indent, b->charge_full);
9c9d3a00 191 if (b->charge_now != -1)
811afd8f 192 append(&tooltip, _("\n%sCharge now:\t\t\t%5d mAh"), indent, b->charge_now);
9c9d3a00 193 if (b->current_now != -1)
811afd8f 194 append(&tooltip, _("\n%sCurrent now:\t\t\t%5d mA"), indent, b->current_now);
9c9d3a00
HG
195
196 if (b->voltage_now != -1)
811afd8f 197 append(&tooltip, _("\n%sCurrent Voltage:\t\t%.3lf V"), indent, b->voltage_now / 1000.0);
9c9d3a00 198
f855ac58
HG
199 return tooltip;
200}
201
5c0c599d
HG
202static void set_tooltip_text(lx_battery* lx_b)
203{
029d9f0c 204 if (lx_b->b == NULL)
811afd8f 205 return;
5c0c599d
HG
206 gboolean isCharging = battery_is_charging(lx_b->b);
207 gchar *tooltip = make_tooltip(lx_b, isCharging);
208 gtk_widget_set_tooltip_text(lx_b->drawingArea, tooltip);
209 g_free(tooltip);
210}
8f11d5f8 211
802d5540
HJYP
212/* FIXME:
213 Don't repaint if percentage of remaining charge and remaining time aren't changed. */
c887dfa0 214void update_display(lx_battery *lx_b, gboolean repaint) {
f176735a 215 cairo_t *cr;
c887dfa0
JH
216 battery *b = lx_b->b;
217 /* unit: mW */
7f9ba86b 218 int rate;
eef7d6f6 219 gboolean isCharging;
8f11d5f8 220
c887dfa0 221 if (! lx_b->pixmap )
802d5540 222 return;
8f11d5f8 223
f176735a
RM
224 cr = cairo_create(lx_b->pixmap);
225 cairo_set_line_width (cr, 1.0);
226
dc9d3b94
HG
227 /* draw background */
228 gdk_cairo_set_source_color(cr, &lx_b->background);
229 cairo_rectangle(cr, 0, 0, lx_b->width, lx_b->height);
230 cairo_fill(cr);
231
c887dfa0 232 /* no battery is found */
811afd8f 233 if( b == NULL )
802d5540 234 {
811afd8f 235 gtk_widget_set_tooltip_text( lx_b->drawingArea, _("No batteries found") );
f50948df
AG
236 if (lx_b->hide_if_no_battery)
237 {
238 gtk_widget_hide(gtk_widget_get_parent(lx_b->drawingArea));
239 repaint = FALSE;
240 }
811afd8f 241 goto update_done;
c887dfa0 242 }
811afd8f 243
c887dfa0 244 /* fixme: only one battery supported */
8f11d5f8 245
7f9ba86b 246 rate = lx_b->b->current_now;
c887dfa0 247 isCharging = battery_is_charging ( b );
811afd8f 248
c887dfa0 249 /* Consider running the alarm command */
b37f46a0 250 if ( !isCharging && rate > 0 &&
6a1a639e 251 ( ( battery_get_remaining( b ) / 60 ) < (int)lx_b->alarmTime ) )
c887dfa0 252 {
811afd8f
AG
253 /* Shrug this should be done using glibs process functions */
254 /* Alarms should not run concurrently; determine whether an alarm is
255 already running */
256 int alarmCanRun;
257 sem_getvalue(&(lx_b->alarmProcessLock), &alarmCanRun);
258
259 /* Run the alarm command if it isn't already running */
260 if (alarmCanRun) {
261
262 Alarm *a = (Alarm *) malloc(sizeof(Alarm));
263 a->command = lx_b->alarmCommand;
264 a->lock = &(lx_b->alarmProcessLock);
265
266 /* Manage the alarm process in a new thread, which which will be
267 responsible for freeing the alarm struct it's given */
268 pthread_t alarmThread;
269 pthread_create(&alarmThread, NULL, alarmProcess, a);
270 }
c887dfa0 271 }
8f11d5f8 272
5c0c599d 273 set_tooltip_text(lx_b);
eef7d6f6
HG
274
275 int chargeLevel = lx_b->b->percentage * (lx_b->length - 2 * lx_b->border) / 100;
276
cfde283a 277 if (lx_b->orientation == GTK_ORIENTATION_HORIZONTAL) {
eef7d6f6 278
811afd8f
AG
279 /* Draw the battery bar vertically, using color 1 for the left half and
280 color 2 for the right half */
f176735a
RM
281 gdk_cairo_set_source_color(cr,
282 isCharging ? &lx_b->charging1 : &lx_b->discharging1);
283 cairo_rectangle(cr, lx_b->border,
284 lx_b->height - lx_b->border - chargeLevel, lx_b->width / 2
285 - lx_b->border, chargeLevel);
286 cairo_fill(cr);
287 gdk_cairo_set_source_color(cr,
288 isCharging ? &lx_b->charging2 : &lx_b->discharging2);
289 cairo_rectangle(cr, lx_b->width / 2,
290 lx_b->height - lx_b->border - chargeLevel, (lx_b->width + 1) / 2
291 - lx_b->border, chargeLevel);
292 cairo_fill(cr);
eef7d6f6
HG
293
294 }
295 else {
296
811afd8f
AG
297 /* Draw the battery bar horizontally, using color 1 for the top half and
298 color 2 for the bottom half */
f176735a
RM
299 gdk_cairo_set_source_color(cr,
300 isCharging ? &lx_b->charging1 : &lx_b->discharging1);
301 cairo_rectangle(cr, lx_b->border,
302 lx_b->border, chargeLevel, lx_b->height / 2 - lx_b->border);
303 cairo_fill(cr);
304 gdk_cairo_set_source_color(cr,
305 isCharging ? &lx_b->charging2 : &lx_b->discharging2);
306 cairo_rectangle(cr, lx_b->border, (lx_b->height + 1)
307 / 2, chargeLevel, lx_b->height / 2 - lx_b->border);
308 cairo_fill(cr);
eef7d6f6
HG
309
310 }
f50948df 311 gtk_widget_show(gtk_widget_get_parent(lx_b->drawingArea));
dc9d3b94
HG
312
313update_done:
eef7d6f6 314 if( repaint )
811afd8f 315 gtk_widget_queue_draw( lx_b->drawingArea );
e4f8b15f
HG
316
317 check_cairo_status(cr);
318 cairo_destroy(cr);
8f11d5f8
HJYP
319}
320
71671bf6 321/* This callback is called every 3 seconds */
c887dfa0 322static int update_timout(lx_battery *lx_b) {
dc9d3b94 323 battery *bat;
251cfd3e
AG
324 if (g_source_is_destroyed(g_main_current_source()))
325 return FALSE;
52cb5b58 326 GDK_THREADS_ENTER();
c887dfa0
JH
327 lx_b->state_elapsed_time++;
328 lx_b->info_elapsed_time++;
71671bf6 329
dc9d3b94
HG
330 bat = battery_update( lx_b->b );
331 if (bat == NULL)
332 {
811afd8f 333 battery_free(lx_b->b);
dc9d3b94 334
811afd8f
AG
335 /* maybe in the mean time a battery has been inserted. */
336 lx_b->b = battery_get();
dc9d3b94 337 }
802d5540 338
c887dfa0 339 update_display( lx_b, TRUE );
802d5540 340
52cb5b58 341 GDK_THREADS_LEAVE();
7c2a8701 342 return TRUE;
52cb5b58 343}
8f11d5f8
HJYP
344
345/* An update will be performed whenever the user clicks on the charge bar */
813c2d44 346static gboolean buttonPressEvent(GtkWidget *p, GdkEventButton *event,
a7bd16a4 347 LXPanel *panel)
813c2d44
AG
348{
349 lx_battery *lx_b = lxpanel_plugin_get_data(p);
8f11d5f8 350
c887dfa0 351 update_display(lx_b, TRUE);
f50948df 352 /* FIXME: open some application for lid/power management may be? */
8f11d5f8 353
1639d6b3 354 return FALSE;
8f11d5f8
HJYP
355}
356
357
358static gint configureEvent(GtkWidget *widget, GdkEventConfigure *event,
175f73d1
AG
359 lx_battery *lx_b)
360{
361 GtkAllocation allocation;
8f11d5f8
HJYP
362
363 ENTER;
364
175f73d1 365 gtk_widget_get_allocation(widget, &allocation);
f50948df
AG
366 if (allocation.width <= 1 && allocation.height <= 1)
367 {
368 /* If plugin is hidden currently then we get 1x1 here */
369 RET(TRUE);
370 }
371
c887dfa0 372 if (lx_b->pixmap)
f176735a 373 cairo_surface_destroy(lx_b->pixmap);
8f11d5f8
HJYP
374
375 /* Update the plugin's dimensions */
175f73d1
AG
376 lx_b->width = allocation.width;
377 lx_b->height = allocation.height;
cfde283a 378 if (lx_b->orientation == GTK_ORIENTATION_HORIZONTAL) {
c887dfa0
JH
379 lx_b->length = lx_b->height;
380 lx_b->thickness = lx_b->width;
8f11d5f8
HJYP
381 }
382 else {
c887dfa0
JH
383 lx_b->length = lx_b->width;
384 lx_b->thickness = lx_b->height;
8f11d5f8
HJYP
385 }
386
175f73d1
AG
387 lx_b->pixmap = cairo_image_surface_create (CAIRO_FORMAT_RGB24, allocation.width,
388 allocation.height);
e4f8b15f 389 check_cairo_surface_status(&lx_b->pixmap);
8f11d5f8
HJYP
390
391 /* Perform an update so the bar will look right in its new orientation */
c887dfa0 392 update_display(lx_b, FALSE);
8f11d5f8
HJYP
393
394 RET(TRUE);
8f11d5f8
HJYP
395}
396
397
c887dfa0 398static gint exposeEvent(GtkWidget *widget, GdkEventExpose *event, lx_battery *lx_b) {
8f11d5f8 399
e4f8b15f 400 ENTER;
175f73d1
AG
401 cairo_t *cr = gdk_cairo_create(gtk_widget_get_window(widget));
402 GtkStyle *style = gtk_widget_get_style(lx_b->drawingArea);
403
f176735a
RM
404 gdk_cairo_region(cr, event->region);
405 cairo_clip(cr);
8f11d5f8 406
175f73d1 407 gdk_cairo_set_source_color(cr, &style->black);
f176735a
RM
408 cairo_set_source_surface(cr, lx_b->pixmap, 0, 0);
409 cairo_paint(cr);
e4f8b15f
HG
410
411 check_cairo_status(cr);
f176735a 412 cairo_destroy(cr);
e751fe05 413
8f11d5f8 414 RET(FALSE);
8f11d5f8
HJYP
415}
416
417
a7bd16a4 418static GtkWidget * constructor(LXPanel *panel, config_setting_t *settings)
8f11d5f8 419{
8f11d5f8
HJYP
420 ENTER;
421
c887dfa0 422 lx_battery *lx_b;
813c2d44
AG
423 GtkWidget *p;
424 const char *str;
425 int tmp_int;
426
427 lx_b = g_new0(lx_battery, 1);
c887dfa0
JH
428
429 /* get available battery */
430 lx_b->b = battery_get ();
813c2d44
AG
431
432 p = gtk_event_box_new();
433 lxpanel_plugin_set_data(p, lx_b, destructor);
09fa171b 434 gtk_widget_set_has_window(p, FALSE);
813c2d44 435 gtk_container_set_border_width( GTK_CONTAINER(p), 1 );
4542c20d 436
c887dfa0
JH
437 lx_b->drawingArea = gtk_drawing_area_new();
438 gtk_widget_add_events( lx_b->drawingArea, GDK_BUTTON_PRESS_MASK );
8f11d5f8 439
813c2d44 440 gtk_container_add( (GtkContainer*)p, lx_b->drawingArea );
4542c20d 441
813c2d44
AG
442 lx_b->orientation = panel_get_orientation(panel);
443 if (lx_b->orientation == GTK_ORIENTATION_HORIZONTAL) {
c887dfa0
JH
444 lx_b->height = lx_b->length = 20;
445 lx_b->thickness = lx_b->width = 8;
8f11d5f8
HJYP
446 }
447 else {
c887dfa0
JH
448 lx_b->height = lx_b->thickness = 8;
449 lx_b->length = lx_b->width = 20;
8f11d5f8 450 }
c887dfa0 451 gtk_widget_set_size_request(lx_b->drawingArea, lx_b->width, lx_b->height);
8f11d5f8 452
c887dfa0 453 gtk_widget_show(lx_b->drawingArea);
8f11d5f8 454
8e05828e 455 g_signal_connect (G_OBJECT (lx_b->drawingArea),"configure-event",
c887dfa0 456 G_CALLBACK (configureEvent), (gpointer) lx_b);
8e05828e 457 g_signal_connect (G_OBJECT (lx_b->drawingArea), "expose-event",
c887dfa0 458 G_CALLBACK (exposeEvent), (gpointer) lx_b);
8f11d5f8 459
c887dfa0 460 sem_init(&(lx_b->alarmProcessLock), 0, 1);
8f11d5f8 461
c887dfa0
JH
462 lx_b->alarmCommand = lx_b->backgroundColor = lx_b->chargingColor1 = lx_b->chargingColor2
463 = lx_b->dischargingColor1 = lx_b->dischargingColor2 = NULL;
8f11d5f8
HJYP
464
465 /* Set default values for integers */
c887dfa0
JH
466 lx_b->alarmTime = 5;
467 lx_b->requestedBorder = 1;
8f11d5f8 468
813c2d44
AG
469 /* remember instance data */
470 lx_b->panel = panel;
471 lx_b->settings = settings;
8f11d5f8 472
5c0c599d
HG
473 lx_b->show_extended_information = false;
474
6a1a639e
AG
475 if (config_setting_lookup_int(settings, "HideIfNoBattery", &tmp_int))
476 lx_b->hide_if_no_battery = (tmp_int != 0);
813c2d44
AG
477 if (config_setting_lookup_string(settings, "AlarmCommand", &str))
478 lx_b->alarmCommand = g_strdup(str);
479 if (config_setting_lookup_string(settings, "BackgroundColor", &str))
480 lx_b->backgroundColor = g_strdup(str);
481 if (config_setting_lookup_string(settings, "ChargingColor1", &str))
482 lx_b->chargingColor1 = g_strdup(str);
483 if (config_setting_lookup_string(settings, "ChargingColor2", &str))
484 lx_b->chargingColor2 = g_strdup(str);
485 if (config_setting_lookup_string(settings, "DischargingColor1", &str))
486 lx_b->dischargingColor1 = g_strdup(str);
487 if (config_setting_lookup_string(settings, "DischargingColor2", &str))
488 lx_b->dischargingColor2 = g_strdup(str);
6a1a639e
AG
489 if (config_setting_lookup_int(settings, "AlarmTime", &tmp_int))
490 lx_b->alarmTime = MAX(0, tmp_int);
491 if (config_setting_lookup_int(settings, "BorderWidth", &tmp_int))
492 lx_b->requestedBorder = MAX(0, tmp_int);
813c2d44
AG
493 if (config_setting_lookup_int(settings, "Size", &tmp_int)) {
494 lx_b->thickness = MAX(1, tmp_int);
495 if (lx_b->orientation == GTK_ORIENTATION_HORIZONTAL)
496 lx_b->width = lx_b->thickness;
497 else
498 lx_b->height = lx_b->thickness;
499 gtk_widget_set_size_request(lx_b->drawingArea, lx_b->width,
500 lx_b->height);
8f11d5f8 501 }
813c2d44
AG
502 if (config_setting_lookup_int(settings, "ShowExtendedInformation", &tmp_int))
503 lx_b->show_extended_information = (tmp_int != 0);
8f11d5f8
HJYP
504
505 /* Make sure the border value is acceptable */
6a1a639e
AG
506 lx_b->border = MIN(lx_b->requestedBorder,
507 (MAX(1, MIN(lx_b->length, lx_b->thickness)) - 1) / 2);
8f11d5f8
HJYP
508
509 /* Apply more default options */
c887dfa0
JH
510 if (! lx_b->alarmCommand)
511 lx_b->alarmCommand = g_strdup("xmessage Battery low");
512 if (! lx_b->backgroundColor)
513 lx_b->backgroundColor = g_strdup("black");
514 if (! lx_b->chargingColor1)
515 lx_b->chargingColor1 = g_strdup("#28f200");
516 if (! lx_b->chargingColor2)
517 lx_b->chargingColor2 = g_strdup("#22cc00");
518 if (! lx_b->dischargingColor1)
519 lx_b->dischargingColor1 = g_strdup("#ffee00");
520 if (! lx_b->dischargingColor2)
521 lx_b->dischargingColor2 = g_strdup("#d9ca00");
522
523 gdk_color_parse(lx_b->backgroundColor, &lx_b->background);
524 gdk_color_parse(lx_b->chargingColor1, &lx_b->charging1);
525 gdk_color_parse(lx_b->chargingColor2, &lx_b->charging2);
526 gdk_color_parse(lx_b->dischargingColor1, &lx_b->discharging1);
527 gdk_color_parse(lx_b->dischargingColor2, &lx_b->discharging2);
8f11d5f8
HJYP
528
529 /* Start the update loop */
13d82f29 530 lx_b->timer = g_timeout_add_seconds( 9, (GSourceFunc) update_timout, (gpointer) lx_b);
c887dfa0 531
813c2d44 532 RET(p);
8f11d5f8
HJYP
533}
534
535
536static void
813c2d44 537destructor(gpointer data)
8f11d5f8 538{
8f11d5f8
HJYP
539 ENTER;
540
813c2d44 541 lx_battery *b = (lx_battery *)data;
52cb5b58 542
029d9f0c 543 if (b->b != NULL)
811afd8f 544 battery_free(b->b);
029d9f0c 545
52cb5b58 546 if (b->pixmap)
f176735a 547 cairo_surface_destroy(b->pixmap);
8f11d5f8 548
8f11d5f8
HJYP
549 g_free(b->alarmCommand);
550 g_free(b->backgroundColor);
551 g_free(b->chargingColor1);
552 g_free(b->chargingColor2);
553 g_free(b->dischargingColor1);
554 g_free(b->dischargingColor2);
802d5540 555
8f11d5f8 556 g_free(b->rateSamples);
8f11d5f8 557 sem_destroy(&(b->alarmProcessLock));
3396dfea 558 if (b->timer)
559 g_source_remove(b->timer);
8f11d5f8
HJYP
560 g_free(b);
561
562 RET();
563
564}
565
566
a7bd16a4 567static void orientation(LXPanel *panel, GtkWidget *p) {
8f11d5f8
HJYP
568
569 ENTER;
570
813c2d44 571 lx_battery *b = lxpanel_plugin_get_data(p);
8f11d5f8 572
813c2d44
AG
573 if (b->orientation != panel_get_orientation(panel)) {
574 b->orientation = panel_get_orientation(panel);
8f11d5f8
HJYP
575 unsigned int swap = b->height;
576 b->height = b->width;
577 b->width = swap;
578 gtk_widget_set_size_request(b->drawingArea, b->width, b->height);
579 }
580
581 RET();
582}
583
584
813c2d44 585static gboolean applyConfig(gpointer user_data)
8f11d5f8 586{
8f11d5f8
HJYP
587 ENTER;
588
813c2d44 589 lx_battery *b = lxpanel_plugin_get_data(user_data);
8f11d5f8
HJYP
590
591 /* Update colors */
592 if (b->backgroundColor &&
813c2d44
AG
593 gdk_color_parse(b->backgroundColor, &b->background))
594 config_group_set_string(b->settings, "BackgroundColor", b->backgroundColor);
595 if (b->chargingColor1 && gdk_color_parse(b->chargingColor1, &b->charging1))
596 config_group_set_string(b->settings, "ChargingColor1", b->chargingColor1);
597 if (b->chargingColor2 && gdk_color_parse(b->chargingColor2, &b->charging2))
598 config_group_set_string(b->settings, "ChargingColor2", b->chargingColor2);
8f11d5f8 599 if (b->dischargingColor1 &&
813c2d44
AG
600 gdk_color_parse(b->dischargingColor1, &b->discharging1))
601 config_group_set_string(b->settings, "DischargingColor1", b->dischargingColor1);
8f11d5f8 602 if (b->dischargingColor2 &&
813c2d44
AG
603 gdk_color_parse(b->dischargingColor2, &b->discharging2))
604 config_group_set_string(b->settings, "DischargingColor2", b->dischargingColor2);
8f11d5f8 605
e751fe05 606 /* Make sure the border value is acceptable */
6a1a639e
AG
607 b->border = MIN(b->requestedBorder,
608 (MAX(1, MIN(b->length, b->thickness)) - 1) / 2);
8f11d5f8 609
8f11d5f8 610 /* Resize the widget */
f50948df 611 b->width = b->height = b->length;
cfde283a 612 if (b->orientation == GTK_ORIENTATION_HORIZONTAL)
8f11d5f8
HJYP
613 b->width = b->thickness;
614 else
615 b->height = b->thickness;
616 gtk_widget_set_size_request(b->drawingArea, b->width, b->height);
f50948df
AG
617 /* ensure visibility if requested */
618 if (!b->hide_if_no_battery)
619 gtk_widget_show(user_data);
620 else if (b->b == NULL)
621 gtk_widget_hide(user_data);
8f11d5f8 622
5c0c599d
HG
623 /* update tooltip */
624 set_tooltip_text(b);
625
813c2d44 626 /* update settings */
813c2d44 627 config_group_set_int(b->settings, "HideIfNoBattery", b->hide_if_no_battery);
813c2d44
AG
628 config_group_set_string(b->settings, "AlarmCommand", b->alarmCommand);
629 config_group_set_int(b->settings, "AlarmTime", b->alarmTime);
630 config_group_set_int(b->settings, "BorderWidth", b->requestedBorder);
631 config_group_set_int(b->settings, "Size", b->thickness);
632 config_group_set_int(b->settings, "ShowExtendedInformation",
633 b->show_extended_information);
634
6a1a639e 635 RET(FALSE);
8f11d5f8
HJYP
636}
637
638
752ee4e2 639static GtkWidget *config(LXPanel *panel, GtkWidget *p) {
813c2d44 640 lx_battery *b = lxpanel_plugin_get_data(p);
131514c9 641 return lxpanel_generic_config_dlg(_("Battery Monitor"),
813c2d44 642 panel, applyConfig, p,
e2957bd2 643 _("Hide if there is no battery"), &b->hide_if_no_battery, CONF_TYPE_BOOL,
e2957bd2
HJYP
644 _("Alarm command"), &b->alarmCommand, CONF_TYPE_STR,
645 _("Alarm time (minutes left)"), &b->alarmTime, CONF_TYPE_INT,
646 _("Background color"), &b->backgroundColor, CONF_TYPE_STR,
647 _("Charging color 1"), &b->chargingColor1, CONF_TYPE_STR,
648 _("Charging color 2"), &b->chargingColor2, CONF_TYPE_STR,
649 _("Discharging color 1"), &b->dischargingColor1, CONF_TYPE_STR,
650 _("Discharging color 2"), &b->dischargingColor2, CONF_TYPE_STR,
651 _("Border width"), &b->requestedBorder, CONF_TYPE_INT,
652 _("Size"), &b->thickness, CONF_TYPE_INT,
5c0c599d 653 _("Show Extended Information"), &b->show_extended_information, CONF_TYPE_BOOL,
8f11d5f8 654 NULL);
8f11d5f8
HJYP
655}
656
657
813c2d44 658FM_DEFINE_MODULE(lxpanel_gtk, batt)
8f11d5f8 659
813c2d44
AG
660/* Plugin descriptor. */
661LXPanelPluginInit fm_module_init_lxpanel_gtk = {
3c3e9c9e 662 .name = N_("Battery Monitor"),
3c3e9c9e
HG
663 .description = N_("Display battery status using ACPI"),
664
813c2d44 665 .new_instance = constructor,
3c3e9c9e 666 .config = config,
813c2d44
AG
667 .reconfigure = orientation,
668 .button_press_event = buttonPressEvent
8f11d5f8 669};
f855ac58
HG
670
671
672/* vim: set sw=4 sts=4 : */