8c23196308dbb9e8e1a2b7685d51715862adf284
[lxde/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 * 2015 Balló György <ballogyor@gmail.com>
9 * 2015 Stanislav Kozina, Ersin <xersin@users.sf.net>
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 *
25 *
26 * This plugin monitors battery usage on ACPI-enabled systems by reading the
27 * battery information found in /sys/class/power_supply. The update interval is
28 * user-configurable and defaults to 3 second.
29 *
30 * The battery's remaining life is estimated from its current charge and current
31 * rate of discharge. The user may configure an alarm command to be run when
32 * their estimated remaining battery life reaches a certain level.
33 */
34
35 /* FIXME:
36 * Here are somethings need to be improvec:
37 * 1. Replace pthread stuff with gthread counterparts for portability.
38 * 4. Handle failure gracefully under systems other than Linux.
39 */
40
41 #include <glib.h>
42 #include <glib/gi18n.h>
43 #include <pthread.h> /* used by pthread_create() and alarmThread */
44 #include <semaphore.h> /* used by update() and alarmProcess() for alarms */
45 #include <stdlib.h>
46 #include <string.h>
47 #include <stdarg.h>
48
49 #include "dbg.h" /* for ENTER and RET macros */
50 #include "batt_sys.h"
51 #include "plugin.h" /* all other APIs including panel configuration */
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 GtkContainer *box;
71 GtkWidget *drawingArea;
72 GtkOrientation orientation;
73 unsigned int alarmTime,
74 border,
75 height,
76 length,
77 numSamples,
78 requestedBorder,
79 *rateSamples,
80 rateSamplesSum,
81 thickness,
82 timer,
83 state_elapsed_time,
84 info_elapsed_time,
85 wasCharging,
86 width,
87 hide_if_no_battery;
88 int battery_number;
89 sem_t alarmProcessLock;
90 battery* b;
91 gboolean has_ac_adapter;
92 gboolean show_extended_information;
93 LXPanel *panel;
94 config_setting_t *settings;
95 } lx_battery;
96
97
98 typedef struct {
99 char *command;
100 sem_t *lock;
101 } Alarm;
102
103 static void destructor(gpointer data);
104 static void update_display(lx_battery *lx_b, gboolean repaint);
105
106 /* alarmProcess takes the address of a dynamically allocated alarm struct (which
107 it must free). It ensures that alarm commands do not run concurrently. */
108 static void * alarmProcess(void *arg) {
109 Alarm *a = (Alarm *) arg;
110
111 sem_wait(a->lock);
112 if (system(a->command) != 0)
113 g_warning("plugin batt: failed to execute alarm command \"%s\"", a->command);
114 sem_post(a->lock);
115
116 g_free(a);
117 return NULL;
118 }
119
120
121 static void append(gchar **tooltip, gchar *fmt, ...)
122 {
123 gchar *old = *tooltip;
124 gchar *new;
125 va_list va;
126
127 va_start(va, fmt);
128 new = g_strdup_vprintf(fmt, va);
129 va_end(va);
130
131 *tooltip = g_strconcat(old, new, NULL);
132
133 g_free(old);
134 g_free(new);
135 }
136
137
138 /* Make a tooltip string, and display remaining charge time if the battery
139 is charging or remaining life if it's discharging */
140 static gchar* make_tooltip(lx_battery* lx_b, gboolean isCharging)
141 {
142 gchar * tooltip;
143 gchar * indent = " ";
144 battery *b = lx_b->b;
145
146 if (b == NULL)
147 return NULL;
148
149 if (isCharging) {
150 if (lx_b->b->seconds > 0) {
151 int hours = lx_b->b->seconds / 3600;
152 int left_seconds = lx_b->b->seconds - 3600 * hours;
153 int minutes = left_seconds / 60;
154 tooltip = g_strdup_printf(
155 _("Battery %d: %d%% charged, %d:%02d until full"),
156 lx_b->battery_number, lx_b->b->percentage,
157 hours,
158 minutes );
159 }
160 } else {
161 /* if we have enough rate information for battery */
162 if (lx_b->b->percentage != 100) {
163 int hours = lx_b->b->seconds / 3600;
164 int left_seconds = lx_b->b->seconds - 3600 * hours;
165 int minutes = left_seconds / 60;
166 tooltip = g_strdup_printf(
167 _("Battery %d: %d%% charged, %d:%02d left"),
168 lx_b->battery_number, lx_b->b->percentage,
169 hours,
170 minutes );
171 } else {
172 tooltip = g_strdup_printf(
173 _("Battery %d: %d%% charged"),
174 lx_b->battery_number, 100 );
175 }
176 }
177
178 if (!lx_b->show_extended_information) {
179 return tooltip;
180 }
181
182 if (b->energy_full_design != -1)
183 append(&tooltip, _("\n%sEnergy full design:\t\t%5d mWh"), indent, b->energy_full_design);
184 if (b->energy_full != -1)
185 append(&tooltip, _("\n%sEnergy full:\t\t\t%5d mWh"), indent, b->energy_full);
186 if (b->energy_now != -1)
187 append(&tooltip, _("\n%sEnergy now:\t\t\t%5d mWh"), indent, b->energy_now);
188 if (b->power_now != -1)
189 append(&tooltip, _("\n%sPower now:\t\t\t%5d mW"), indent, b->power_now);
190
191 if (b->charge_full_design != -1)
192 append(&tooltip, _("\n%sCharge full design:\t%5d mAh"), indent, b->charge_full_design);
193 if (b->charge_full != -1)
194 append(&tooltip, _("\n%sCharge full:\t\t\t%5d mAh"), indent, b->charge_full);
195 if (b->charge_now != -1)
196 append(&tooltip, _("\n%sCharge now:\t\t\t%5d mAh"), indent, b->charge_now);
197 if (b->current_now != -1)
198 append(&tooltip, _("\n%sCurrent now:\t\t\t%5d mA"), indent, b->current_now);
199
200 if (b->voltage_now != -1)
201 append(&tooltip, _("\n%sCurrent Voltage:\t\t%.3lf V"), indent, b->voltage_now / 1000.0);
202
203 return tooltip;
204 }
205
206 static void set_tooltip_text(lx_battery* lx_b)
207 {
208 if (lx_b->b == NULL)
209 return;
210 gboolean isCharging = battery_is_charging(lx_b->b);
211 gchar *tooltip = make_tooltip(lx_b, isCharging);
212 gtk_widget_set_tooltip_text(lx_b->drawingArea, tooltip);
213 g_free(tooltip);
214 }
215
216 /* FIXME:
217 Don't repaint if percentage of remaining charge and remaining time aren't changed. */
218 void update_display(lx_battery *lx_b, gboolean repaint) {
219 cairo_t *cr;
220 battery *b = lx_b->b;
221 /* unit: mW */
222 int rate;
223 gboolean isCharging;
224
225 if (! lx_b->pixmap )
226 return;
227
228 cr = cairo_create(lx_b->pixmap);
229 cairo_set_line_width (cr, 1.0);
230
231 /* draw background */
232 gdk_cairo_set_source_color(cr, &lx_b->background);
233 cairo_rectangle(cr, 0, 0, lx_b->width, lx_b->height);
234 cairo_fill(cr);
235
236 /* no battery is found */
237 if( b == NULL )
238 {
239 gtk_widget_set_tooltip_text( lx_b->drawingArea, _("No batteries found") );
240 if (lx_b->hide_if_no_battery)
241 {
242 gtk_widget_hide(gtk_widget_get_parent(lx_b->drawingArea));
243 repaint = FALSE;
244 }
245 goto update_done;
246 }
247
248 /* fixme: only one battery supported */
249
250 rate = lx_b->b->current_now;
251 isCharging = battery_is_charging ( b );
252
253 /* Consider running the alarm command */
254 if ( !isCharging && rate > 0 &&
255 ( ( battery_get_remaining( b ) / 60 ) < (int)lx_b->alarmTime ) )
256 {
257 /* FIXME: this should be done using glibs process functions */
258 /* FIXME: see bug #463: it should not spawn process all the time */
259 /* Alarms should not run concurrently; determine whether an alarm is
260 already running */
261 int alarmCanRun;
262 sem_getvalue(&(lx_b->alarmProcessLock), &alarmCanRun);
263
264 /* Run the alarm command if it isn't already running */
265 if (alarmCanRun) {
266
267 Alarm *a = (Alarm *) malloc(sizeof(Alarm));
268 a->command = lx_b->alarmCommand;
269 a->lock = &(lx_b->alarmProcessLock);
270
271 /* Manage the alarm process in a new thread, which which will be
272 responsible for freeing the alarm struct it's given */
273 pthread_t alarmThread;
274 pthread_create(&alarmThread, NULL, alarmProcess, a);
275 }
276 }
277
278 set_tooltip_text(lx_b);
279
280 int chargeLevel = lx_b->b->percentage * lx_b->length / 100;
281
282 if (lx_b->orientation == GTK_ORIENTATION_HORIZONTAL) {
283
284 /* Draw the battery bar vertically, using color 1 for the left half and
285 color 2 for the right half */
286 gdk_cairo_set_source_color(cr,
287 isCharging ? &lx_b->charging1 : &lx_b->discharging1);
288 cairo_rectangle(cr, 0, lx_b->height - chargeLevel,
289 lx_b->width / 2, chargeLevel);
290 cairo_fill(cr);
291 gdk_cairo_set_source_color(cr,
292 isCharging ? &lx_b->charging2 : &lx_b->discharging2);
293 cairo_rectangle(cr, lx_b->width / 2, lx_b->height - chargeLevel,
294 (lx_b->width + 1) / 2, chargeLevel);
295 cairo_fill(cr);
296
297 }
298 else {
299
300 /* Draw the battery bar horizontally, using color 1 for the top half and
301 color 2 for the bottom half */
302 gdk_cairo_set_source_color(cr,
303 isCharging ? &lx_b->charging1 : &lx_b->discharging1);
304 cairo_rectangle(cr, 0, 0, chargeLevel, lx_b->height / 2);
305 cairo_fill(cr);
306 gdk_cairo_set_source_color(cr,
307 isCharging ? &lx_b->charging2 : &lx_b->discharging2);
308 cairo_rectangle(cr, 0, (lx_b->height + 1) / 2,
309 chargeLevel, lx_b->height / 2);
310 cairo_fill(cr);
311
312 }
313 gtk_widget_show(gtk_widget_get_parent(lx_b->drawingArea));
314
315 update_done:
316 if( repaint )
317 gtk_widget_queue_draw( lx_b->drawingArea );
318
319 check_cairo_status(cr);
320 cairo_destroy(cr);
321 }
322
323 /* This callback is called every 3 seconds */
324 static int update_timout(lx_battery *lx_b) {
325 battery *bat;
326 if (g_source_is_destroyed(g_main_current_source()))
327 return FALSE;
328 GDK_THREADS_ENTER();
329 lx_b->state_elapsed_time++;
330 lx_b->info_elapsed_time++;
331
332 bat = battery_update( lx_b->b );
333 if (bat == NULL)
334 {
335 battery_free(lx_b->b);
336
337 /* maybe in the mean time a battery has been inserted. */
338 lx_b->b = battery_get(lx_b->battery_number);
339 }
340
341 update_display( lx_b, TRUE );
342
343 GDK_THREADS_LEAVE();
344 return TRUE;
345 }
346
347 /* An update will be performed whenever the user clicks on the charge bar */
348 static gboolean buttonPressEvent(GtkWidget *p, GdkEventButton *event,
349 LXPanel *panel)
350 {
351 lx_battery *lx_b = lxpanel_plugin_get_data(p);
352
353 update_display(lx_b, TRUE);
354 /* FIXME: open some application for lid/power management may be? */
355
356 return FALSE;
357 }
358
359 static gint configureEvent(GtkWidget *widget, GdkEventConfigure *event,
360 lx_battery *lx_b)
361 {
362 GtkAllocation allocation;
363
364 ENTER;
365
366 gtk_widget_get_allocation(widget, &allocation);
367 if (allocation.width <= 1 && allocation.height <= 1)
368 {
369 /* If plugin is hidden currently then we get 1x1 here */
370 RET(TRUE);
371 }
372
373 if (lx_b->pixmap)
374 cairo_surface_destroy(lx_b->pixmap);
375
376 /* Update the plugin's dimensions */
377 lx_b->width = allocation.width;
378 lx_b->height = allocation.height;
379 if (lx_b->orientation == GTK_ORIENTATION_HORIZONTAL) {
380 lx_b->length = lx_b->height;
381 }
382 else {
383 lx_b->length = lx_b->width;
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 /* we enforce border width here because panel sets it to 0 */
394 gtk_container_set_border_width(lx_b->box, lx_b->border);
395
396 RET(TRUE);
397 }
398
399
400 #if GTK_CHECK_VERSION(3, 0, 0)
401 static gint draw(GtkWidget *widget, cairo_t *cr, lx_battery *lx_b) {
402 #else
403 static gint exposeEvent(GtkWidget *widget, GdkEventExpose *event, lx_battery *lx_b) {
404 #endif
405
406 ENTER;
407
408 #if GTK_CHECK_VERSION(3, 0, 0)
409 cairo_set_source_rgb(cr, 0, 0, 0); // FIXME: set black color from the style
410 #else
411 cairo_t *cr = gdk_cairo_create(gtk_widget_get_window(widget));
412 GtkStyle *style = gtk_widget_get_style(lx_b->drawingArea);
413
414 gdk_cairo_region(cr, event->region);
415 cairo_clip(cr);
416
417 gdk_cairo_set_source_color(cr, &style->black);
418 #endif
419 cairo_set_source_surface(cr, lx_b->pixmap, 0, 0);
420 cairo_paint(cr);
421
422 check_cairo_status(cr);
423 #if !GTK_CHECK_VERSION(3, 0, 0)
424 cairo_destroy(cr);
425 #endif
426
427 RET(FALSE);
428 }
429
430 /* updates length, border, and height/width appropriate to orientation */
431 static void updateSizes(lx_battery *b)
432 {
433 b->length = panel_get_height(b->panel);
434 b->border = MIN(b->requestedBorder, (MAX(1, b->length) - 1) / 2);
435 b->length -= 2 * b->border;
436 if (b->orientation == GTK_ORIENTATION_HORIZONTAL)
437 b->height = b->length;
438 else
439 b->width = b->length;
440 }
441
442
443 static GtkWidget * constructor(LXPanel *panel, config_setting_t *settings)
444 {
445 ENTER;
446
447 lx_battery *lx_b;
448 GtkWidget *p;
449 const char *str;
450 int tmp_int;
451
452 lx_b = g_new0(lx_battery, 1);
453
454 /* get requested battery */
455 if (config_setting_lookup_int(settings, "BatteryNumber", &tmp_int))
456 lx_b->battery_number = MAX(0, tmp_int);
457 lx_b->b = battery_get(lx_b->battery_number);
458
459 p = gtk_event_box_new();
460 lxpanel_plugin_set_data(p, lx_b, destructor);
461 gtk_widget_set_has_window(p, FALSE);
462
463 lx_b->box = GTK_CONTAINER(p);
464 lx_b->drawingArea = gtk_drawing_area_new();
465
466 gtk_container_add(lx_b->box, lx_b->drawingArea);
467
468 lx_b->orientation = panel_get_orientation(panel);
469
470 gtk_widget_show(lx_b->drawingArea);
471
472 sem_init(&(lx_b->alarmProcessLock), 0, 1);
473
474 lx_b->alarmCommand = lx_b->backgroundColor = lx_b->chargingColor1 = lx_b->chargingColor2
475 = lx_b->dischargingColor1 = lx_b->dischargingColor2 = NULL;
476
477 /* Set default values for integers */
478 lx_b->alarmTime = 5;
479 lx_b->requestedBorder = 1;
480 lx_b->thickness = 8;
481
482 /* remember instance data */
483 lx_b->panel = panel;
484 lx_b->settings = settings;
485
486 lx_b->show_extended_information = FALSE;
487
488 if (config_setting_lookup_int(settings, "HideIfNoBattery", &tmp_int))
489 lx_b->hide_if_no_battery = (tmp_int != 0);
490 if (config_setting_lookup_string(settings, "AlarmCommand", &str))
491 lx_b->alarmCommand = g_strdup(str);
492 if (config_setting_lookup_string(settings, "BackgroundColor", &str))
493 lx_b->backgroundColor = g_strdup(str);
494 if (config_setting_lookup_string(settings, "ChargingColor1", &str))
495 lx_b->chargingColor1 = g_strdup(str);
496 if (config_setting_lookup_string(settings, "ChargingColor2", &str))
497 lx_b->chargingColor2 = g_strdup(str);
498 if (config_setting_lookup_string(settings, "DischargingColor1", &str))
499 lx_b->dischargingColor1 = g_strdup(str);
500 if (config_setting_lookup_string(settings, "DischargingColor2", &str))
501 lx_b->dischargingColor2 = g_strdup(str);
502 if (config_setting_lookup_int(settings, "AlarmTime", &tmp_int))
503 lx_b->alarmTime = MAX(0, tmp_int);
504 if (config_setting_lookup_int(settings, "BorderWidth", &tmp_int))
505 lx_b->requestedBorder = CLAMP(tmp_int, 0, 6);
506 if (config_setting_lookup_int(settings, "Size", &tmp_int))
507 lx_b->thickness = MAX(1, tmp_int);
508 if (config_setting_lookup_int(settings, "ShowExtendedInformation", &tmp_int))
509 lx_b->show_extended_information = (tmp_int != 0);
510
511 /* Make sure the border value is acceptable */
512 updateSizes(lx_b);
513 if (lx_b->orientation == GTK_ORIENTATION_HORIZONTAL)
514 {
515 lx_b->width = lx_b->thickness;
516 gtk_widget_set_size_request(lx_b->drawingArea, lx_b->width, -1);
517 }
518 else
519 {
520 lx_b->height = lx_b->thickness;
521 gtk_widget_set_size_request(lx_b->drawingArea, -1, lx_b->height);
522 }
523
524 g_signal_connect (G_OBJECT (lx_b->drawingArea),"configure-event",
525 G_CALLBACK (configureEvent), (gpointer) lx_b);
526 #if GTK_CHECK_VERSION(3, 0, 0)
527 g_signal_connect (G_OBJECT (lx_b->drawingArea), "draw",
528 G_CALLBACK(draw), (gpointer) lx_b);
529 #else
530 g_signal_connect (G_OBJECT (lx_b->drawingArea), "expose-event",
531 G_CALLBACK (exposeEvent), (gpointer) lx_b);
532 #endif
533
534 /* Apply more default options */
535 if (! lx_b->alarmCommand)
536 lx_b->alarmCommand = g_strconcat("notify-send \"", _("Battery low"), "\" --icon=battery-caution", NULL);
537 if (! lx_b->backgroundColor)
538 lx_b->backgroundColor = g_strdup("black");
539 if (! lx_b->chargingColor1)
540 lx_b->chargingColor1 = g_strdup("#28f200");
541 if (! lx_b->chargingColor2)
542 lx_b->chargingColor2 = g_strdup("#22cc00");
543 if (! lx_b->dischargingColor1)
544 lx_b->dischargingColor1 = g_strdup("#ffee00");
545 if (! lx_b->dischargingColor2)
546 lx_b->dischargingColor2 = g_strdup("#d9ca00");
547
548 gdk_color_parse(lx_b->backgroundColor, &lx_b->background);
549 gdk_color_parse(lx_b->chargingColor1, &lx_b->charging1);
550 gdk_color_parse(lx_b->chargingColor2, &lx_b->charging2);
551 gdk_color_parse(lx_b->dischargingColor1, &lx_b->discharging1);
552 gdk_color_parse(lx_b->dischargingColor2, &lx_b->discharging2);
553
554 /* Start the update loop */
555 lx_b->timer = g_timeout_add_seconds( 9, (GSourceFunc) update_timout, (gpointer) lx_b);
556
557 RET(p);
558 }
559
560
561 static void
562 destructor(gpointer data)
563 {
564 ENTER;
565
566 lx_battery *b = (lx_battery *)data;
567
568 if (b->b != NULL)
569 battery_free(b->b);
570
571 if (b->pixmap)
572 cairo_surface_destroy(b->pixmap);
573
574 g_free(b->alarmCommand);
575 g_free(b->backgroundColor);
576 g_free(b->chargingColor1);
577 g_free(b->chargingColor2);
578 g_free(b->dischargingColor1);
579 g_free(b->dischargingColor2);
580
581 g_free(b->rateSamples);
582 sem_destroy(&(b->alarmProcessLock));
583 if (b->timer)
584 g_source_remove(b->timer);
585 g_free(b);
586
587 RET();
588
589 }
590
591
592 static void orientation(LXPanel *panel, GtkWidget *p) {
593
594 ENTER;
595
596 lx_battery *b = lxpanel_plugin_get_data(p);
597
598 if (b->orientation != panel_get_orientation(panel)) {
599 b->orientation = panel_get_orientation(panel);
600 updateSizes(b);
601 if (b->orientation == GTK_ORIENTATION_HORIZONTAL)
602 {
603 b->width = b->thickness;
604 gtk_widget_set_size_request(b->drawingArea, b->width, -1);
605 }
606 else
607 {
608 b->height = b->thickness;
609 gtk_widget_set_size_request(b->drawingArea, -1, b->height);
610 }
611 }
612
613 RET();
614 }
615
616
617 static gboolean applyConfig(gpointer user_data)
618 {
619 ENTER;
620
621 lx_battery *b = lxpanel_plugin_get_data(user_data);
622
623 /* Update the battery we monitor */
624 battery_free(b->b);
625 b->b = battery_get(b->battery_number);
626
627 /* Update colors */
628 if (b->backgroundColor &&
629 gdk_color_parse(b->backgroundColor, &b->background))
630 config_group_set_string(b->settings, "BackgroundColor", b->backgroundColor);
631 if (b->chargingColor1 && gdk_color_parse(b->chargingColor1, &b->charging1))
632 config_group_set_string(b->settings, "ChargingColor1", b->chargingColor1);
633 if (b->chargingColor2 && gdk_color_parse(b->chargingColor2, &b->charging2))
634 config_group_set_string(b->settings, "ChargingColor2", b->chargingColor2);
635 if (b->dischargingColor1 &&
636 gdk_color_parse(b->dischargingColor1, &b->discharging1))
637 config_group_set_string(b->settings, "DischargingColor1", b->dischargingColor1);
638 if (b->dischargingColor2 &&
639 gdk_color_parse(b->dischargingColor2, &b->discharging2))
640 config_group_set_string(b->settings, "DischargingColor2", b->dischargingColor2);
641
642 /* Make sure it is at least 1 px */
643 if (b->thickness < 1)
644 b->thickness = 1;
645
646 /* Make sure the border value is acceptable */
647 b->requestedBorder = MIN(b->requestedBorder, 6);
648 updateSizes(b);
649
650 /* Resize the widget */
651 gtk_container_set_border_width(b->box, b->border);
652 if (b->orientation == GTK_ORIENTATION_HORIZONTAL)
653 {
654 b->width = b->thickness;
655 gtk_widget_set_size_request(b->drawingArea, b->width, -1);
656 }
657 else
658 {
659 b->height = b->thickness;
660 gtk_widget_set_size_request(b->drawingArea, -1, b->height);
661 }
662 /* ensure visibility if requested */
663 if (!b->hide_if_no_battery)
664 gtk_widget_show(user_data);
665 else if (b->b == NULL)
666 gtk_widget_hide(user_data);
667
668 if (b->alarmCommand == NULL)
669 b->alarmCommand = g_strconcat("xmessage ", _("Battery low"), NULL);
670
671 /* update tooltip */
672 set_tooltip_text(b);
673
674 /* update settings */
675 config_group_set_int(b->settings, "HideIfNoBattery", b->hide_if_no_battery);
676 config_group_set_string(b->settings, "AlarmCommand", b->alarmCommand);
677 config_group_set_int(b->settings, "AlarmTime", b->alarmTime);
678 config_group_set_int(b->settings, "BorderWidth", b->requestedBorder);
679 config_group_set_int(b->settings, "Size", b->thickness);
680 config_group_set_int(b->settings, "ShowExtendedInformation",
681 b->show_extended_information);
682 config_group_set_int(b->settings, "BatteryNumber", b->battery_number);
683
684 update_display(b, TRUE);
685
686 RET(FALSE);
687 }
688
689
690 static GtkWidget *config(LXPanel *panel, GtkWidget *p) {
691 lx_battery *b = lxpanel_plugin_get_data(p);
692 return lxpanel_generic_config_dlg(_("Battery Monitor"),
693 panel, applyConfig, p,
694 _("Hide if there is no battery"), &b->hide_if_no_battery, CONF_TYPE_BOOL,
695 _("Alarm command"), &b->alarmCommand, CONF_TYPE_STR,
696 _("Alarm time (minutes left)"), &b->alarmTime, CONF_TYPE_INT,
697 _("Background color"), &b->backgroundColor, CONF_TYPE_STR,
698 _("Charging color 1"), &b->chargingColor1, CONF_TYPE_STR,
699 _("Charging color 2"), &b->chargingColor2, CONF_TYPE_STR,
700 _("Discharging color 1"), &b->dischargingColor1, CONF_TYPE_STR,
701 _("Discharging color 2"), &b->dischargingColor2, CONF_TYPE_STR,
702 "", panel_config_int_button_new(_("Border width"), (int *)&b->requestedBorder,
703 0, 6), CONF_TYPE_EXTERNAL,
704 "", panel_config_int_button_new(_("Size"), (int *)&b->thickness,
705 1, 50), CONF_TYPE_EXTERNAL,
706 _("Show Extended Information"), &b->show_extended_information, CONF_TYPE_BOOL,
707 _("Number of battery to monitor"), &b->battery_number, CONF_TYPE_INT,
708 NULL);
709 }
710
711
712 FM_DEFINE_MODULE(lxpanel_gtk, batt)
713
714 /* Plugin descriptor. */
715 LXPanelPluginInit fm_module_init_lxpanel_gtk = {
716 .name = N_("Battery Monitor"),
717 .description = N_("Display battery status using ACPI"),
718
719 .new_instance = constructor,
720 .config = config,
721 .reconfigure = orientation,
722 .button_press_event = buttonPressEvent
723 };
724
725
726 /* vim: set sw=4 sts=4 : */