bb8519fbafcf833b0e7a30bd6e9b62b7f00e82fd
[lxde/lxpanel.git] / src / 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 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 *
22 *
23 * This plugin monitors battery usage on ACPI-enabled systems by reading the
24 * battery information found in /sys/class/power_supply. The update interval is
25 * user-configurable and defaults to 3 second.
26 *
27 * The battery's remaining life is estimated from its current charge and current
28 * rate of discharge. The user may configure an alarm command to be run when
29 * their estimated remaining battery life reaches a certain level.
30 */
31
32 /* FIXME:
33 * Here are somethings need to be improvec:
34 * 1. Replace pthread stuff with gthread counterparts for portability.
35 * 3. Add an option to hide the plugin when AC power is used or there is no battery.
36 * 4. Handle failure gracefully under systems other than Linux.
37 */
38
39 #include <glib.h>
40 #include <glib/gi18n.h>
41 #include <pthread.h> /* used by pthread_create() and alarmThread */
42 #include <semaphore.h> /* used by update() and alarmProcess() for alarms */
43 #include <stdlib.h>
44 #include <string.h>
45 #include <stdarg.h>
46
47 #include "dbg.h"
48 #include "batt_sys.h"
49 #include "misc.h" /* used for the line struct */
50 #include "panel.h" /* used to determine panel orientation */
51 #include "plugin.h"
52
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
57 typedef struct {
58 char *alarmCommand,
59 *backgroundColor,
60 *chargingColor1,
61 *chargingColor2,
62 *dischargingColor1,
63 *dischargingColor2;
64 GdkColor background,
65 charging1,
66 charging2,
67 discharging1,
68 discharging2;
69 cairo_surface_t *pixmap;
70 GtkWidget *drawingArea;
71 int 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 } lx_battery;
92
93
94 typedef struct {
95 char *command;
96 sem_t *lock;
97 } Alarm;
98
99 static void destructor(Plugin *p);
100 static void update_display(lx_battery *lx_b, gboolean repaint);
101
102 /* alarmProcess takes the address of a dynamically allocated alarm struct (which
103 it must free). It ensures that alarm commands do not run concurrently. */
104 static void * alarmProcess(void *arg) {
105 Alarm *a = (Alarm *) arg;
106
107 sem_wait(a->lock);
108 system(a->command);
109 sem_post(a->lock);
110
111 g_free(a);
112 return NULL;
113 }
114
115
116 static void append(gchar **tooltip, gchar *fmt, ...)
117 {
118 gchar *old = *tooltip;
119 gchar *new;
120 va_list va;
121
122 va_start(va, fmt);
123 new = g_strdup_vprintf(fmt, va);
124 va_end(va);
125
126 *tooltip = g_strconcat(old, new, NULL);
127
128 g_free(old);
129 g_free(new);
130 }
131
132
133 /* Make a tooltip string, and display remaining charge time if the battery
134 is charging or remaining life if it's discharging */
135 static gchar* make_tooltip(lx_battery* lx_b, gboolean isCharging)
136 {
137 gchar * tooltip;
138 gchar * indent = " ";
139 battery *b = lx_b->b;
140
141 if (isCharging) {
142 int hours = lx_b->b->seconds / 3600;
143 int left_seconds = lx_b->b->seconds - 3600 * hours;
144 int minutes = left_seconds / 60;
145 tooltip = g_strdup_printf(
146 _("Battery: %d%% charged, %d:%02d until full"),
147 lx_b->b->percentage,
148 hours,
149 minutes );
150 } else {
151 /* if we have enough rate information for battery */
152 if (lx_b->b->percentage != 100) {
153 int hours = lx_b->b->seconds / 3600;
154 int left_seconds = lx_b->b->seconds - 3600 * hours;
155 int minutes = left_seconds / 60;
156 tooltip = g_strdup_printf(
157 _("Battery: %d%% charged, %d:%02d left"),
158 lx_b->b->percentage,
159 hours,
160 minutes );
161 } else {
162 tooltip = g_strdup_printf(
163 _("Battery: %d%% charged"),
164 100 );
165 }
166 }
167
168 if (!lx_b->show_extended_information) {
169 return tooltip;
170 }
171
172 if (b->energy_full_design != -1)
173 append(&tooltip, _("\n%sEnergy full design:\t\t%5d mWh"), indent, b->energy_full_design);
174 if (b->energy_full != -1)
175 append(&tooltip, _("\n%sEnergy full:\t\t\t%5d mWh"), indent, b->energy_full);
176 if (b->energy_now != -1)
177 append(&tooltip, _("\n%sEnergy now:\t\t\t%5d mWh"), indent, b->energy_now);
178 if (b->power_now != -1)
179 append(&tooltip, _("\n%sPower now:\t\t\t%5d mW"), indent, b->power_now);
180
181 if (b->charge_full_design != -1)
182 append(&tooltip, _("\n%sCharge full design:\t%5d mAh"), indent, b->charge_full_design);
183 if (b->charge_full != -1)
184 append(&tooltip, _("\n%sCharge full:\t\t\t%5d mAh"), indent, b->charge_full);
185 if (b->charge_now != -1)
186 append(&tooltip, _("\n%sCharge now:\t\t\t%5d mAh"), indent, b->charge_now);
187 if (b->current_now != -1)
188 append(&tooltip, _("\n%sCurrent now:\t\t\t%5d mA"), indent, b->current_now);
189
190 if (b->voltage_now != -1)
191 append(&tooltip, _("\n%sCurrent Voltage:\t\t%.3lf V"), indent, b->voltage_now / 1000.0);
192
193 return tooltip;
194 }
195
196 static void set_tooltip_text(lx_battery* lx_b)
197 {
198 gboolean isCharging = battery_is_charging(lx_b->b);
199 gchar *tooltip = make_tooltip(lx_b, isCharging);
200 gtk_widget_set_tooltip_text(lx_b->drawingArea, tooltip);
201 g_free(tooltip);
202 }
203
204 /* FIXME:
205 Don't repaint if percentage of remaining charge and remaining time aren't changed. */
206 void update_display(lx_battery *lx_b, gboolean repaint) {
207 cairo_t *cr;
208 battery *b = lx_b->b;
209 /* unit: mW */
210 int rate;
211 gboolean isCharging;
212
213 if (! lx_b->pixmap )
214 return;
215
216 cr = cairo_create(lx_b->pixmap);
217 cairo_set_line_width (cr, 1.0);
218
219 /* no battery is found */
220 if( b == NULL )
221 {
222 gtk_widget_set_tooltip_text( lx_b->drawingArea, _("No batteries found") );
223 return;
224 }
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 /* fixme: only one battery supported */
232
233 rate = lx_b->b->current_now;
234 isCharging = battery_is_charging ( b );
235
236 /* Consider running the alarm command */
237 if ( !isCharging && rate > 0 &&
238 ( ( battery_get_remaining( b ) / 60 ) < lx_b->alarmTime ) )
239 {
240 /* Shrug this should be done using glibs process functions */
241 /* Alarms should not run concurrently; determine whether an alarm is
242 already running */
243 int alarmCanRun;
244 sem_getvalue(&(lx_b->alarmProcessLock), &alarmCanRun);
245
246 /* Run the alarm command if it isn't already running */
247 if (alarmCanRun) {
248
249 Alarm *a = (Alarm *) malloc(sizeof(Alarm));
250 a->command = lx_b->alarmCommand;
251 a->lock = &(lx_b->alarmProcessLock);
252
253 /* Manage the alarm process in a new thread, which which will be
254 responsible for freeing the alarm struct it's given */
255 pthread_t alarmThread;
256 pthread_create(&alarmThread, NULL, alarmProcess, a);
257
258 }
259 }
260
261 set_tooltip_text(lx_b);
262
263 int chargeLevel = lx_b->b->percentage * (lx_b->length - 2 * lx_b->border) / 100;
264
265 if (lx_b->orientation == ORIENT_HORIZ) {
266
267 /* Draw the battery bar vertically, using color 1 for the left half and
268 color 2 for the right half */
269 gdk_cairo_set_source_color(cr,
270 isCharging ? &lx_b->charging1 : &lx_b->discharging1);
271 cairo_rectangle(cr, lx_b->border,
272 lx_b->height - lx_b->border - chargeLevel, lx_b->width / 2
273 - lx_b->border, chargeLevel);
274 cairo_fill(cr);
275 gdk_cairo_set_source_color(cr,
276 isCharging ? &lx_b->charging2 : &lx_b->discharging2);
277 cairo_rectangle(cr, lx_b->width / 2,
278 lx_b->height - lx_b->border - chargeLevel, (lx_b->width + 1) / 2
279 - lx_b->border, chargeLevel);
280 cairo_fill(cr);
281
282 }
283 else {
284
285 /* Draw the battery bar horizontally, using color 1 for the top half and
286 color 2 for the bottom half */
287 gdk_cairo_set_source_color(cr,
288 isCharging ? &lx_b->charging1 : &lx_b->discharging1);
289 cairo_rectangle(cr, lx_b->border,
290 lx_b->border, chargeLevel, lx_b->height / 2 - lx_b->border);
291 cairo_fill(cr);
292 gdk_cairo_set_source_color(cr,
293 isCharging ? &lx_b->charging2 : &lx_b->discharging2);
294 cairo_rectangle(cr, lx_b->border, (lx_b->height + 1)
295 / 2, chargeLevel, lx_b->height / 2 - lx_b->border);
296 cairo_fill(cr);
297
298 }
299 if( repaint )
300 gtk_widget_queue_draw( lx_b->drawingArea );
301
302 check_cairo_status(cr);
303 cairo_destroy(cr);
304 }
305
306 /* This callback is called every 3 seconds */
307 static int update_timout(lx_battery *lx_b) {
308 GDK_THREADS_ENTER();
309 lx_b->state_elapsed_time++;
310 lx_b->info_elapsed_time++;
311
312 /* check the batteries every 3 seconds */
313 battery_update( lx_b->b );
314
315 update_display( lx_b, TRUE );
316
317 GDK_THREADS_LEAVE();
318 return TRUE;
319 }
320
321 /* An update will be performed whenever the user clicks on the charge bar */
322 static gint buttonPressEvent(GtkWidget *widget, GdkEventButton *event,
323 Plugin* plugin) {
324
325 lx_battery *lx_b = (lx_battery*)plugin->priv;
326
327 update_display(lx_b, TRUE);
328
329 if( event->button == 3 ) /* right button */
330 {
331 GtkMenu* popup = lxpanel_get_panel_menu( plugin->panel, plugin, FALSE );
332 gtk_menu_popup( popup, NULL, NULL, NULL, NULL, event->button, event->time );
333 return TRUE;
334 }
335 return FALSE;
336 }
337
338
339 static gint configureEvent(GtkWidget *widget, GdkEventConfigure *event,
340 lx_battery *lx_b) {
341
342 ENTER;
343
344 if (lx_b->pixmap)
345 cairo_surface_destroy(lx_b->pixmap);
346
347 /* Update the plugin's dimensions */
348 lx_b->width = widget->allocation.width;
349 lx_b->height = widget->allocation.height;
350 if (lx_b->orientation == ORIENT_HORIZ) {
351 lx_b->length = lx_b->height;
352 lx_b->thickness = lx_b->width;
353 }
354 else {
355 lx_b->length = lx_b->width;
356 lx_b->thickness = lx_b->height;
357 }
358
359 lx_b->pixmap = cairo_image_surface_create (CAIRO_FORMAT_RGB24, widget->allocation.width,
360 widget->allocation.height);
361 check_cairo_surface_status(&lx_b->pixmap);
362
363 /* Perform an update so the bar will look right in its new orientation */
364 update_display(lx_b, FALSE);
365
366 RET(TRUE);
367
368 }
369
370
371 static gint exposeEvent(GtkWidget *widget, GdkEventExpose *event, lx_battery *lx_b) {
372
373 ENTER;
374 cairo_t *cr = gdk_cairo_create(widget->window);
375 gdk_cairo_region(cr, event->region);
376 cairo_clip(cr);
377
378 gdk_cairo_set_source_color(cr, &lx_b->drawingArea->style->black);
379 cairo_set_source_surface(cr, lx_b->pixmap, 0, 0);
380 cairo_paint(cr);
381
382 check_cairo_status(cr);
383 cairo_destroy(cr);
384
385 RET(FALSE);
386 }
387
388
389 static int
390 constructor(Plugin *p, char **fp)
391 {
392 ENTER;
393
394 lx_battery *lx_b;
395 p->priv = lx_b = g_new0(lx_battery, 1);
396
397 /* get available battery */
398 lx_b->b = battery_get ();
399
400 /* no battery available */
401 if ( lx_b->b == NULL )
402 goto error;
403
404 p->pwid = gtk_event_box_new();
405 GTK_WIDGET_SET_FLAGS( p->pwid, GTK_NO_WINDOW );
406 gtk_container_set_border_width( GTK_CONTAINER(p->pwid), 1 );
407
408 lx_b->drawingArea = gtk_drawing_area_new();
409 gtk_widget_add_events( lx_b->drawingArea, GDK_BUTTON_PRESS_MASK );
410
411 gtk_container_add( (GtkContainer*)p->pwid, lx_b->drawingArea );
412
413 if ((lx_b->orientation = p->panel->orientation) == ORIENT_HORIZ) {
414 lx_b->height = lx_b->length = 20;
415 lx_b->thickness = lx_b->width = 8;
416 }
417 else {
418 lx_b->height = lx_b->thickness = 8;
419 lx_b->length = lx_b->width = 20;
420 }
421 gtk_widget_set_size_request(lx_b->drawingArea, lx_b->width, lx_b->height);
422
423 gtk_widget_show(lx_b->drawingArea);
424
425 g_signal_connect (G_OBJECT (lx_b->drawingArea), "button_press_event",
426 G_CALLBACK(buttonPressEvent), (gpointer) p);
427 g_signal_connect (G_OBJECT (lx_b->drawingArea),"configure_event",
428 G_CALLBACK (configureEvent), (gpointer) lx_b);
429 g_signal_connect (G_OBJECT (lx_b->drawingArea), "expose_event",
430 G_CALLBACK (exposeEvent), (gpointer) lx_b);
431
432 sem_init(&(lx_b->alarmProcessLock), 0, 1);
433
434 lx_b->alarmCommand = lx_b->backgroundColor = lx_b->chargingColor1 = lx_b->chargingColor2
435 = lx_b->dischargingColor1 = lx_b->dischargingColor2 = NULL;
436
437 /* Set default values for integers */
438 lx_b->alarmTime = 5;
439 lx_b->requestedBorder = 1;
440
441 line s;
442 s.len = 256;
443
444 lx_b->show_extended_information = false;
445
446 if (fp) {
447
448 /* Apply options */
449 while (lxpanel_get_line(fp, &s) != LINE_BLOCK_END) {
450 if (s.type == LINE_NONE) {
451 ERR( "batt: illegal token %s\n", s.str);
452 goto error;
453 }
454 if (s.type == LINE_VAR) {
455 if (!g_ascii_strcasecmp(s.t[0], "HideIfNoBattery"))
456 lx_b->hide_if_no_battery = atoi(s.t[1]);
457 else if (!g_ascii_strcasecmp(s.t[0], "AlarmCommand"))
458 lx_b->alarmCommand = g_strdup(s.t[1]);
459 else if (!g_ascii_strcasecmp(s.t[0], "BackgroundColor"))
460 lx_b->backgroundColor = g_strdup(s.t[1]);
461 else if (!g_ascii_strcasecmp(s.t[0], "ChargingColor1"))
462 lx_b->chargingColor1 = g_strdup(s.t[1]);
463 else if (!g_ascii_strcasecmp(s.t[0], "ChargingColor2"))
464 lx_b->chargingColor2 = g_strdup(s.t[1]);
465 else if (!g_ascii_strcasecmp(s.t[0], "DischargingColor1"))
466 lx_b->dischargingColor1 = g_strdup(s.t[1]);
467 else if (!g_ascii_strcasecmp(s.t[0], "DischargingColor2"))
468 lx_b->dischargingColor2 = g_strdup(s.t[1]);
469 else if (!g_ascii_strcasecmp(s.t[0], "AlarmTime"))
470 lx_b->alarmTime = atoi(s.t[1]);
471 else if (!g_ascii_strcasecmp(s.t[0], "BorderWidth"))
472 lx_b->requestedBorder = atoi(s.t[1]);
473 else if (!g_ascii_strcasecmp(s.t[0], "Size")) {
474 lx_b->thickness = MAX(1, atoi(s.t[1]));
475 if (lx_b->orientation == ORIENT_HORIZ)
476 lx_b->width = lx_b->thickness;
477 else
478 lx_b->height = lx_b->thickness;
479 gtk_widget_set_size_request(lx_b->drawingArea, lx_b->width,
480 lx_b->height);
481 }
482 else if (!g_ascii_strcasecmp(s.t[0], "ShowExtendedInformation"))
483 lx_b->show_extended_information = atoi(s.t[1]);
484 else {
485 ERR( "batt: unknown var %s\n", s.t[0]);
486 continue;
487 }
488 }
489 else {
490 ERR( "batt: illegal in this context %s\n", s.str);
491 goto error;
492 }
493 }
494
495 }
496
497 /* Make sure the border value is acceptable */
498 lx_b->border = MIN(MAX(0, lx_b->requestedBorder),
499 (MIN(lx_b->length, lx_b->thickness) - 1) / 2);
500
501 /* Apply more default options */
502 if (! lx_b->alarmCommand)
503 lx_b->alarmCommand = g_strdup("xmessage Battery low");
504 if (! lx_b->backgroundColor)
505 lx_b->backgroundColor = g_strdup("black");
506 if (! lx_b->chargingColor1)
507 lx_b->chargingColor1 = g_strdup("#28f200");
508 if (! lx_b->chargingColor2)
509 lx_b->chargingColor2 = g_strdup("#22cc00");
510 if (! lx_b->dischargingColor1)
511 lx_b->dischargingColor1 = g_strdup("#ffee00");
512 if (! lx_b->dischargingColor2)
513 lx_b->dischargingColor2 = g_strdup("#d9ca00");
514
515 gdk_color_parse(lx_b->backgroundColor, &lx_b->background);
516 gdk_color_parse(lx_b->chargingColor1, &lx_b->charging1);
517 gdk_color_parse(lx_b->chargingColor2, &lx_b->charging2);
518 gdk_color_parse(lx_b->dischargingColor1, &lx_b->discharging1);
519 gdk_color_parse(lx_b->dischargingColor2, &lx_b->discharging2);
520
521
522 /* Start the update loop */
523 lx_b->timer = g_timeout_add_seconds( 9, (GSourceFunc) update_timout, (gpointer) lx_b);
524
525 RET(TRUE);
526
527 error:
528 RET(FALSE);
529 }
530
531
532 static void
533 destructor(Plugin *p)
534 {
535 ENTER;
536
537 lx_battery *b = (lx_battery *) p->priv;
538
539 if (b->pixmap)
540 cairo_surface_destroy(b->pixmap);
541
542 g_free(b->alarmCommand);
543 g_free(b->backgroundColor);
544 g_free(b->chargingColor1);
545 g_free(b->chargingColor2);
546 g_free(b->dischargingColor1);
547 g_free(b->dischargingColor2);
548
549 g_free(b->rateSamples);
550 sem_destroy(&(b->alarmProcessLock));
551 if (b->timer)
552 g_source_remove(b->timer);
553 g_free(b);
554
555 RET();
556
557 }
558
559
560 static void orientation(Plugin *p) {
561
562 ENTER;
563
564 lx_battery *b = (lx_battery *) p->priv;
565
566 if (b->orientation != p->panel->orientation) {
567 b->orientation = p->panel->orientation;
568 unsigned int swap = b->height;
569 b->height = b->width;
570 b->width = swap;
571 gtk_widget_set_size_request(b->drawingArea, b->width, b->height);
572 }
573
574 RET();
575 }
576
577
578 static void applyConfig(Plugin* p)
579 {
580 ENTER;
581
582 lx_battery *b = (lx_battery *) p->priv;
583
584 /* Update colors */
585 if (b->backgroundColor &&
586 gdk_color_parse(b->backgroundColor, &b->background));
587 if (b->chargingColor1 && gdk_color_parse(b->chargingColor1, &b->charging1));
588 if (b->chargingColor2 && gdk_color_parse(b->chargingColor2, &b->charging2));
589 if (b->dischargingColor1 &&
590 gdk_color_parse(b->dischargingColor1, &b->discharging1));
591 if (b->dischargingColor2 &&
592 gdk_color_parse(b->dischargingColor2, &b->discharging2));
593
594 /* Make sure the border value is acceptable */
595 b->border = MIN(MAX(0, b->requestedBorder),
596 (MIN(b->length, b->thickness) - 1) / 2);
597
598 /* Resize the widget */
599 if (b->orientation == ORIENT_HORIZ)
600 b->width = b->thickness;
601 else
602 b->height = b->thickness;
603 gtk_widget_set_size_request(b->drawingArea, b->width, b->height);
604
605 /* update tooltip */
606 set_tooltip_text(b);
607
608 RET();
609 }
610
611
612 static void config(Plugin *p, GtkWindow* parent) {
613 ENTER;
614
615 GtkWidget *dialog;
616 lx_battery *b = (lx_battery *) p->priv;
617 dialog = create_generic_config_dlg(_(p->class->name),
618 GTK_WIDGET(parent),
619 (GSourceFunc) applyConfig, (gpointer) p,
620 #if 0
621 _("Hide if there is no battery"), &b->hide_if_no_battery, CONF_TYPE_BOOL,
622 #endif
623 _("Alarm command"), &b->alarmCommand, CONF_TYPE_STR,
624 _("Alarm time (minutes left)"), &b->alarmTime, CONF_TYPE_INT,
625 _("Background color"), &b->backgroundColor, CONF_TYPE_STR,
626 _("Charging color 1"), &b->chargingColor1, CONF_TYPE_STR,
627 _("Charging color 2"), &b->chargingColor2, CONF_TYPE_STR,
628 _("Discharging color 1"), &b->dischargingColor1, CONF_TYPE_STR,
629 _("Discharging color 2"), &b->dischargingColor2, CONF_TYPE_STR,
630 _("Border width"), &b->requestedBorder, CONF_TYPE_INT,
631 _("Size"), &b->thickness, CONF_TYPE_INT,
632 _("Show Extended Information"), &b->show_extended_information, CONF_TYPE_BOOL,
633 NULL);
634 gtk_window_present(GTK_WINDOW(dialog));
635
636 RET();
637 }
638
639
640 static void save(Plugin* p, FILE* fp) {
641 lx_battery *lx_b = (lx_battery *) p->priv;
642
643 lxpanel_put_bool(fp, "HideIfNoBattery",lx_b->hide_if_no_battery);
644 lxpanel_put_str(fp, "AlarmCommand", lx_b->alarmCommand);
645 lxpanel_put_int(fp, "AlarmTime", lx_b->alarmTime);
646 lxpanel_put_str(fp, "BackgroundColor", lx_b->backgroundColor);
647 lxpanel_put_int(fp, "BorderWidth", lx_b->requestedBorder);
648 lxpanel_put_str(fp, "ChargingColor1", lx_b->chargingColor1);
649 lxpanel_put_str(fp, "ChargingColor2", lx_b->chargingColor2);
650 lxpanel_put_str(fp, "DischargingColor1", lx_b->dischargingColor1);
651 lxpanel_put_str(fp, "DischargingColor2", lx_b->dischargingColor2);
652 lxpanel_put_int(fp, "Size", lx_b->thickness);
653 lxpanel_put_bool(fp, "ShowExtendedInformation", lx_b->show_extended_information);
654 }
655
656
657 PluginClass batt_plugin_class = {
658
659 PLUGINCLASS_VERSIONING,
660
661 .type = "batt",
662 .name = N_("Battery Monitor"),
663 .version = "2.0",
664 .description = N_("Display battery status using ACPI"),
665
666 .constructor = constructor,
667 .destructor = destructor,
668 .config = config,
669 .save = save,
670 .panel_configuration_changed = orientation
671 };
672
673
674 /* vim: set sw=4 sts=4 : */