Merge branch 'use-libfm'
[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 "private.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 (b == NULL)
142 return NULL;
143
144 if (isCharging) {
145 int hours = lx_b->b->seconds / 3600;
146 int left_seconds = lx_b->b->seconds - 3600 * hours;
147 int minutes = left_seconds / 60;
148 tooltip = g_strdup_printf(
149 _("Battery: %d%% charged, %d:%02d until full"),
150 lx_b->b->percentage,
151 hours,
152 minutes );
153 } else {
154 /* if we have enough rate information for battery */
155 if (lx_b->b->percentage != 100) {
156 int hours = lx_b->b->seconds / 3600;
157 int left_seconds = lx_b->b->seconds - 3600 * hours;
158 int minutes = left_seconds / 60;
159 tooltip = g_strdup_printf(
160 _("Battery: %d%% charged, %d:%02d left"),
161 lx_b->b->percentage,
162 hours,
163 minutes );
164 } else {
165 tooltip = g_strdup_printf(
166 _("Battery: %d%% charged"),
167 100 );
168 }
169 }
170
171 if (!lx_b->show_extended_information) {
172 return tooltip;
173 }
174
175 if (b->energy_full_design != -1)
176 append(&tooltip, _("\n%sEnergy full design:\t\t%5d mWh"), indent, b->energy_full_design);
177 if (b->energy_full != -1)
178 append(&tooltip, _("\n%sEnergy full:\t\t\t%5d mWh"), indent, b->energy_full);
179 if (b->energy_now != -1)
180 append(&tooltip, _("\n%sEnergy now:\t\t\t%5d mWh"), indent, b->energy_now);
181 if (b->power_now != -1)
182 append(&tooltip, _("\n%sPower now:\t\t\t%5d mW"), indent, b->power_now);
183
184 if (b->charge_full_design != -1)
185 append(&tooltip, _("\n%sCharge full design:\t%5d mAh"), indent, b->charge_full_design);
186 if (b->charge_full != -1)
187 append(&tooltip, _("\n%sCharge full:\t\t\t%5d mAh"), indent, b->charge_full);
188 if (b->charge_now != -1)
189 append(&tooltip, _("\n%sCharge now:\t\t\t%5d mAh"), indent, b->charge_now);
190 if (b->current_now != -1)
191 append(&tooltip, _("\n%sCurrent now:\t\t\t%5d mA"), indent, b->current_now);
192
193 if (b->voltage_now != -1)
194 append(&tooltip, _("\n%sCurrent Voltage:\t\t%.3lf V"), indent, b->voltage_now / 1000.0);
195
196 return tooltip;
197 }
198
199 static void set_tooltip_text(lx_battery* lx_b)
200 {
201 if (lx_b->b == NULL)
202 return;
203 gboolean isCharging = battery_is_charging(lx_b->b);
204 gchar *tooltip = make_tooltip(lx_b, isCharging);
205 gtk_widget_set_tooltip_text(lx_b->drawingArea, tooltip);
206 g_free(tooltip);
207 }
208
209 /* FIXME:
210 Don't repaint if percentage of remaining charge and remaining time aren't changed. */
211 void update_display(lx_battery *lx_b, gboolean repaint) {
212 cairo_t *cr;
213 battery *b = lx_b->b;
214 /* unit: mW */
215 int rate;
216 gboolean isCharging;
217
218 if (! lx_b->pixmap )
219 return;
220
221 cr = cairo_create(lx_b->pixmap);
222 cairo_set_line_width (cr, 1.0);
223
224 /* draw background */
225 gdk_cairo_set_source_color(cr, &lx_b->background);
226 cairo_rectangle(cr, 0, 0, lx_b->width, lx_b->height);
227 cairo_fill(cr);
228
229 /* no battery is found */
230 if( b == NULL )
231 {
232 gtk_widget_set_tooltip_text( lx_b->drawingArea, _("No batteries found") );
233 goto update_done;
234 }
235
236 /* fixme: only one battery supported */
237
238 rate = lx_b->b->current_now;
239 isCharging = battery_is_charging ( b );
240
241 /* Consider running the alarm command */
242 if ( !isCharging && rate > 0 &&
243 ( ( battery_get_remaining( b ) / 60 ) < lx_b->alarmTime ) )
244 {
245 /* Shrug this should be done using glibs process functions */
246 /* Alarms should not run concurrently; determine whether an alarm is
247 already running */
248 int alarmCanRun;
249 sem_getvalue(&(lx_b->alarmProcessLock), &alarmCanRun);
250
251 /* Run the alarm command if it isn't already running */
252 if (alarmCanRun) {
253
254 Alarm *a = (Alarm *) malloc(sizeof(Alarm));
255 a->command = lx_b->alarmCommand;
256 a->lock = &(lx_b->alarmProcessLock);
257
258 /* Manage the alarm process in a new thread, which which will be
259 responsible for freeing the alarm struct it's given */
260 pthread_t alarmThread;
261 pthread_create(&alarmThread, NULL, alarmProcess, a);
262
263 }
264 }
265
266 set_tooltip_text(lx_b);
267
268 int chargeLevel = lx_b->b->percentage * (lx_b->length - 2 * lx_b->border) / 100;
269
270 if (lx_b->orientation == GTK_ORIENTATION_HORIZONTAL) {
271
272 /* Draw the battery bar vertically, using color 1 for the left half and
273 color 2 for the right half */
274 gdk_cairo_set_source_color(cr,
275 isCharging ? &lx_b->charging1 : &lx_b->discharging1);
276 cairo_rectangle(cr, lx_b->border,
277 lx_b->height - lx_b->border - chargeLevel, lx_b->width / 2
278 - lx_b->border, chargeLevel);
279 cairo_fill(cr);
280 gdk_cairo_set_source_color(cr,
281 isCharging ? &lx_b->charging2 : &lx_b->discharging2);
282 cairo_rectangle(cr, lx_b->width / 2,
283 lx_b->height - lx_b->border - chargeLevel, (lx_b->width + 1) / 2
284 - lx_b->border, chargeLevel);
285 cairo_fill(cr);
286
287 }
288 else {
289
290 /* Draw the battery bar horizontally, using color 1 for the top half and
291 color 2 for the bottom half */
292 gdk_cairo_set_source_color(cr,
293 isCharging ? &lx_b->charging1 : &lx_b->discharging1);
294 cairo_rectangle(cr, lx_b->border,
295 lx_b->border, chargeLevel, lx_b->height / 2 - lx_b->border);
296 cairo_fill(cr);
297 gdk_cairo_set_source_color(cr,
298 isCharging ? &lx_b->charging2 : &lx_b->discharging2);
299 cairo_rectangle(cr, lx_b->border, (lx_b->height + 1)
300 / 2, chargeLevel, lx_b->height / 2 - lx_b->border);
301 cairo_fill(cr);
302
303 }
304
305 update_done:
306 if( repaint )
307 gtk_widget_queue_draw( lx_b->drawingArea );
308
309 check_cairo_status(cr);
310 cairo_destroy(cr);
311 }
312
313 /* This callback is called every 3 seconds */
314 static int update_timout(lx_battery *lx_b) {
315 battery *bat;
316 GDK_THREADS_ENTER();
317 lx_b->state_elapsed_time++;
318 lx_b->info_elapsed_time++;
319
320 bat = battery_update( lx_b->b );
321 if (bat == NULL)
322 {
323 battery_free(lx_b->b);
324
325 /* maybe in the mean time a battery has been inserted. */
326 lx_b->b = battery_get();
327 }
328
329 update_display( lx_b, TRUE );
330
331 GDK_THREADS_LEAVE();
332 return TRUE;
333 }
334
335 /* An update will be performed whenever the user clicks on the charge bar */
336 static gint buttonPressEvent(GtkWidget *widget, GdkEventButton *event,
337 Plugin* plugin) {
338
339 lx_battery *lx_b = (lx_battery*)plugin->priv;
340
341 update_display(lx_b, TRUE);
342
343 if( event->button == 3 ) /* right button */
344 {
345 GtkMenu* popup = lxpanel_get_panel_menu( plugin->panel, plugin, FALSE );
346 gtk_menu_popup( popup, NULL, NULL, NULL, NULL, event->button, event->time );
347 return TRUE;
348 }
349 return FALSE;
350 }
351
352
353 static gint configureEvent(GtkWidget *widget, GdkEventConfigure *event,
354 lx_battery *lx_b) {
355
356 ENTER;
357
358 if (lx_b->pixmap)
359 cairo_surface_destroy(lx_b->pixmap);
360
361 /* Update the plugin's dimensions */
362 lx_b->width = widget->allocation.width;
363 lx_b->height = widget->allocation.height;
364 if (lx_b->orientation == GTK_ORIENTATION_HORIZONTAL) {
365 lx_b->length = lx_b->height;
366 lx_b->thickness = lx_b->width;
367 }
368 else {
369 lx_b->length = lx_b->width;
370 lx_b->thickness = lx_b->height;
371 }
372
373 lx_b->pixmap = cairo_image_surface_create (CAIRO_FORMAT_RGB24, widget->allocation.width,
374 widget->allocation.height);
375 check_cairo_surface_status(&lx_b->pixmap);
376
377 /* Perform an update so the bar will look right in its new orientation */
378 update_display(lx_b, FALSE);
379
380 RET(TRUE);
381
382 }
383
384
385 static gint exposeEvent(GtkWidget *widget, GdkEventExpose *event, lx_battery *lx_b) {
386
387 ENTER;
388 cairo_t *cr = gdk_cairo_create(widget->window);
389 gdk_cairo_region(cr, event->region);
390 cairo_clip(cr);
391
392 gdk_cairo_set_source_color(cr, &lx_b->drawingArea->style->black);
393 cairo_set_source_surface(cr, lx_b->pixmap, 0, 0);
394 cairo_paint(cr);
395
396 check_cairo_status(cr);
397 cairo_destroy(cr);
398
399 RET(FALSE);
400 }
401
402
403 static int
404 constructor(Plugin *p, char **fp)
405 {
406 ENTER;
407
408 lx_battery *lx_b;
409 p->priv = lx_b = g_new0(lx_battery, 1);
410
411 /* get available battery */
412 lx_b->b = battery_get ();
413
414 p->pwid = gtk_event_box_new();
415 GTK_WIDGET_SET_FLAGS( p->pwid, GTK_NO_WINDOW );
416 gtk_container_set_border_width( GTK_CONTAINER(p->pwid), 1 );
417
418 lx_b->drawingArea = gtk_drawing_area_new();
419 gtk_widget_add_events( lx_b->drawingArea, GDK_BUTTON_PRESS_MASK );
420
421 gtk_container_add( (GtkContainer*)p->pwid, lx_b->drawingArea );
422
423 if ((lx_b->orientation = p->panel->orientation) == GTK_ORIENTATION_HORIZONTAL) {
424 lx_b->height = lx_b->length = 20;
425 lx_b->thickness = lx_b->width = 8;
426 }
427 else {
428 lx_b->height = lx_b->thickness = 8;
429 lx_b->length = lx_b->width = 20;
430 }
431 gtk_widget_set_size_request(lx_b->drawingArea, lx_b->width, lx_b->height);
432
433 gtk_widget_show(lx_b->drawingArea);
434
435 g_signal_connect (G_OBJECT (lx_b->drawingArea), "button-press-event",
436 G_CALLBACK(buttonPressEvent), (gpointer) p);
437 g_signal_connect (G_OBJECT (lx_b->drawingArea),"configure-event",
438 G_CALLBACK (configureEvent), (gpointer) lx_b);
439 g_signal_connect (G_OBJECT (lx_b->drawingArea), "expose-event",
440 G_CALLBACK (exposeEvent), (gpointer) lx_b);
441
442 sem_init(&(lx_b->alarmProcessLock), 0, 1);
443
444 lx_b->alarmCommand = lx_b->backgroundColor = lx_b->chargingColor1 = lx_b->chargingColor2
445 = lx_b->dischargingColor1 = lx_b->dischargingColor2 = NULL;
446
447 /* Set default values for integers */
448 lx_b->alarmTime = 5;
449 lx_b->requestedBorder = 1;
450
451 line s;
452 s.len = 256;
453
454 lx_b->show_extended_information = false;
455
456 if (fp) {
457
458 /* Apply options */
459 while (lxpanel_get_line(fp, &s) != LINE_BLOCK_END) {
460 if (s.type == LINE_NONE) {
461 ERR( "batt: illegal token %s\n", s.str);
462 goto error;
463 }
464 if (s.type == LINE_VAR) {
465 if (!g_ascii_strcasecmp(s.t[0], "HideIfNoBattery"))
466 lx_b->hide_if_no_battery = atoi(s.t[1]);
467 else if (!g_ascii_strcasecmp(s.t[0], "AlarmCommand"))
468 lx_b->alarmCommand = g_strdup(s.t[1]);
469 else if (!g_ascii_strcasecmp(s.t[0], "BackgroundColor"))
470 lx_b->backgroundColor = g_strdup(s.t[1]);
471 else if (!g_ascii_strcasecmp(s.t[0], "ChargingColor1"))
472 lx_b->chargingColor1 = g_strdup(s.t[1]);
473 else if (!g_ascii_strcasecmp(s.t[0], "ChargingColor2"))
474 lx_b->chargingColor2 = g_strdup(s.t[1]);
475 else if (!g_ascii_strcasecmp(s.t[0], "DischargingColor1"))
476 lx_b->dischargingColor1 = g_strdup(s.t[1]);
477 else if (!g_ascii_strcasecmp(s.t[0], "DischargingColor2"))
478 lx_b->dischargingColor2 = g_strdup(s.t[1]);
479 else if (!g_ascii_strcasecmp(s.t[0], "AlarmTime"))
480 lx_b->alarmTime = atoi(s.t[1]);
481 else if (!g_ascii_strcasecmp(s.t[0], "BorderWidth"))
482 lx_b->requestedBorder = atoi(s.t[1]);
483 else if (!g_ascii_strcasecmp(s.t[0], "Size")) {
484 lx_b->thickness = MAX(1, atoi(s.t[1]));
485 if (lx_b->orientation == GTK_ORIENTATION_HORIZONTAL)
486 lx_b->width = lx_b->thickness;
487 else
488 lx_b->height = lx_b->thickness;
489 gtk_widget_set_size_request(lx_b->drawingArea, lx_b->width,
490 lx_b->height);
491 }
492 else if (!g_ascii_strcasecmp(s.t[0], "ShowExtendedInformation"))
493 lx_b->show_extended_information = atoi(s.t[1]);
494 else {
495 ERR( "batt: unknown var %s\n", s.t[0]);
496 continue;
497 }
498 }
499 else {
500 ERR( "batt: illegal in this context %s\n", s.str);
501 goto error;
502 }
503 }
504
505 }
506
507 /* Make sure the border value is acceptable */
508 lx_b->border = MIN(MAX(0, lx_b->requestedBorder),
509 (MIN(lx_b->length, lx_b->thickness) - 1) / 2);
510
511 /* Apply more default options */
512 if (! lx_b->alarmCommand)
513 lx_b->alarmCommand = g_strdup("xmessage Battery low");
514 if (! lx_b->backgroundColor)
515 lx_b->backgroundColor = g_strdup("black");
516 if (! lx_b->chargingColor1)
517 lx_b->chargingColor1 = g_strdup("#28f200");
518 if (! lx_b->chargingColor2)
519 lx_b->chargingColor2 = g_strdup("#22cc00");
520 if (! lx_b->dischargingColor1)
521 lx_b->dischargingColor1 = g_strdup("#ffee00");
522 if (! lx_b->dischargingColor2)
523 lx_b->dischargingColor2 = g_strdup("#d9ca00");
524
525 gdk_color_parse(lx_b->backgroundColor, &lx_b->background);
526 gdk_color_parse(lx_b->chargingColor1, &lx_b->charging1);
527 gdk_color_parse(lx_b->chargingColor2, &lx_b->charging2);
528 gdk_color_parse(lx_b->dischargingColor1, &lx_b->discharging1);
529 gdk_color_parse(lx_b->dischargingColor2, &lx_b->discharging2);
530
531
532 /* Start the update loop */
533 lx_b->timer = g_timeout_add_seconds( 9, (GSourceFunc) update_timout, (gpointer) lx_b);
534
535 RET(TRUE);
536
537 error:
538 RET(FALSE);
539 }
540
541
542 static void
543 destructor(Plugin *p)
544 {
545 ENTER;
546
547 lx_battery *b = (lx_battery *) p->priv;
548
549 if (b->b != NULL)
550 battery_free(b->b);
551
552 if (b->pixmap)
553 cairo_surface_destroy(b->pixmap);
554
555 g_free(b->alarmCommand);
556 g_free(b->backgroundColor);
557 g_free(b->chargingColor1);
558 g_free(b->chargingColor2);
559 g_free(b->dischargingColor1);
560 g_free(b->dischargingColor2);
561
562 g_free(b->rateSamples);
563 sem_destroy(&(b->alarmProcessLock));
564 if (b->timer)
565 g_source_remove(b->timer);
566 g_free(b);
567
568 RET();
569
570 }
571
572
573 static void orientation(Plugin *p) {
574
575 ENTER;
576
577 lx_battery *b = (lx_battery *) p->priv;
578
579 if (b->orientation != p->panel->orientation) {
580 b->orientation = p->panel->orientation;
581 unsigned int swap = b->height;
582 b->height = b->width;
583 b->width = swap;
584 gtk_widget_set_size_request(b->drawingArea, b->width, b->height);
585 }
586
587 RET();
588 }
589
590
591 static void applyConfig(Plugin* p)
592 {
593 ENTER;
594
595 lx_battery *b = (lx_battery *) p->priv;
596
597 /* Update colors */
598 if (b->backgroundColor &&
599 gdk_color_parse(b->backgroundColor, &b->background));
600 if (b->chargingColor1 && gdk_color_parse(b->chargingColor1, &b->charging1));
601 if (b->chargingColor2 && gdk_color_parse(b->chargingColor2, &b->charging2));
602 if (b->dischargingColor1 &&
603 gdk_color_parse(b->dischargingColor1, &b->discharging1));
604 if (b->dischargingColor2 &&
605 gdk_color_parse(b->dischargingColor2, &b->discharging2));
606
607 /* Make sure the border value is acceptable */
608 b->border = MIN(MAX(0, b->requestedBorder),
609 (MIN(b->length, b->thickness) - 1) / 2);
610
611 /* Resize the widget */
612 if (b->orientation == GTK_ORIENTATION_HORIZONTAL)
613 b->width = b->thickness;
614 else
615 b->height = b->thickness;
616 gtk_widget_set_size_request(b->drawingArea, b->width, b->height);
617
618 /* update tooltip */
619 set_tooltip_text(b);
620
621 RET();
622 }
623
624
625 static void config(Plugin *p, GtkWindow* parent) {
626 ENTER;
627
628 GtkWidget *dialog;
629 lx_battery *b = (lx_battery *) p->priv;
630 dialog = create_generic_config_dlg(_(p->class->name),
631 GTK_WIDGET(parent),
632 (GSourceFunc) applyConfig, (gpointer) p,
633 #if 0
634 _("Hide if there is no battery"), &b->hide_if_no_battery, CONF_TYPE_BOOL,
635 #endif
636 _("Alarm command"), &b->alarmCommand, CONF_TYPE_STR,
637 _("Alarm time (minutes left)"), &b->alarmTime, CONF_TYPE_INT,
638 _("Background color"), &b->backgroundColor, CONF_TYPE_STR,
639 _("Charging color 1"), &b->chargingColor1, CONF_TYPE_STR,
640 _("Charging color 2"), &b->chargingColor2, CONF_TYPE_STR,
641 _("Discharging color 1"), &b->dischargingColor1, CONF_TYPE_STR,
642 _("Discharging color 2"), &b->dischargingColor2, CONF_TYPE_STR,
643 _("Border width"), &b->requestedBorder, CONF_TYPE_INT,
644 _("Size"), &b->thickness, CONF_TYPE_INT,
645 _("Show Extended Information"), &b->show_extended_information, CONF_TYPE_BOOL,
646 NULL);
647 gtk_window_present(GTK_WINDOW(dialog));
648
649 RET();
650 }
651
652
653 static void save(Plugin* p, FILE* fp) {
654 lx_battery *lx_b = (lx_battery *) p->priv;
655
656 lxpanel_put_bool(fp, "HideIfNoBattery",lx_b->hide_if_no_battery);
657 lxpanel_put_str(fp, "AlarmCommand", lx_b->alarmCommand);
658 lxpanel_put_int(fp, "AlarmTime", lx_b->alarmTime);
659 lxpanel_put_str(fp, "BackgroundColor", lx_b->backgroundColor);
660 lxpanel_put_int(fp, "BorderWidth", lx_b->requestedBorder);
661 lxpanel_put_str(fp, "ChargingColor1", lx_b->chargingColor1);
662 lxpanel_put_str(fp, "ChargingColor2", lx_b->chargingColor2);
663 lxpanel_put_str(fp, "DischargingColor1", lx_b->dischargingColor1);
664 lxpanel_put_str(fp, "DischargingColor2", lx_b->dischargingColor2);
665 lxpanel_put_int(fp, "Size", lx_b->thickness);
666 lxpanel_put_bool(fp, "ShowExtendedInformation", lx_b->show_extended_information);
667 }
668
669
670 PluginClass batt_plugin_class = {
671
672 PLUGINCLASS_VERSIONING,
673
674 .type = "batt",
675 .name = N_("Battery Monitor"),
676 .version = "2.0",
677 .description = N_("Display battery status using ACPI"),
678
679 .constructor = constructor,
680 .destructor = destructor,
681 .config = config,
682 .save = save,
683 .panel_configuration_changed = orientation
684 };
685
686
687 /* vim: set sw=4 sts=4 : */