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