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