Fix broken panel menus for 'batt' and 'monitors' plugins.
[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 gtk_widget_add_events(lx_b->drawingArea, GDK_BUTTON_PRESS_MASK);
466
467 gtk_container_add(lx_b->box, lx_b->drawingArea);
468
469 lx_b->orientation = panel_get_orientation(panel);
470
471 gtk_widget_show(lx_b->drawingArea);
472
473 sem_init(&(lx_b->alarmProcessLock), 0, 1);
474
475 lx_b->alarmCommand = lx_b->backgroundColor = lx_b->chargingColor1 = lx_b->chargingColor2
476 = lx_b->dischargingColor1 = lx_b->dischargingColor2 = NULL;
477
478 /* Set default values for integers */
479 lx_b->alarmTime = 5;
480 lx_b->requestedBorder = 1;
481 lx_b->thickness = 8;
482
483 /* remember instance data */
484 lx_b->panel = panel;
485 lx_b->settings = settings;
486
487 lx_b->show_extended_information = FALSE;
488
489 if (config_setting_lookup_int(settings, "HideIfNoBattery", &tmp_int))
490 lx_b->hide_if_no_battery = (tmp_int != 0);
491 if (config_setting_lookup_string(settings, "AlarmCommand", &str))
492 lx_b->alarmCommand = g_strdup(str);
493 if (config_setting_lookup_string(settings, "BackgroundColor", &str))
494 lx_b->backgroundColor = g_strdup(str);
495 if (config_setting_lookup_string(settings, "ChargingColor1", &str))
496 lx_b->chargingColor1 = g_strdup(str);
497 if (config_setting_lookup_string(settings, "ChargingColor2", &str))
498 lx_b->chargingColor2 = g_strdup(str);
499 if (config_setting_lookup_string(settings, "DischargingColor1", &str))
500 lx_b->dischargingColor1 = g_strdup(str);
501 if (config_setting_lookup_string(settings, "DischargingColor2", &str))
502 lx_b->dischargingColor2 = g_strdup(str);
503 if (config_setting_lookup_int(settings, "AlarmTime", &tmp_int))
504 lx_b->alarmTime = MAX(0, tmp_int);
505 if (config_setting_lookup_int(settings, "BorderWidth", &tmp_int))
506 lx_b->requestedBorder = CLAMP(tmp_int, 0, 6);
507 if (config_setting_lookup_int(settings, "Size", &tmp_int))
508 lx_b->thickness = MAX(1, tmp_int);
509 if (config_setting_lookup_int(settings, "ShowExtendedInformation", &tmp_int))
510 lx_b->show_extended_information = (tmp_int != 0);
511
512 /* Make sure the border value is acceptable */
513 updateSizes(lx_b);
514 if (lx_b->orientation == GTK_ORIENTATION_HORIZONTAL)
515 {
516 lx_b->width = lx_b->thickness;
517 gtk_widget_set_size_request(lx_b->drawingArea, lx_b->width, -1);
518 }
519 else
520 {
521 lx_b->height = lx_b->thickness;
522 gtk_widget_set_size_request(lx_b->drawingArea, -1, lx_b->height);
523 }
524
525 g_signal_connect (G_OBJECT (lx_b->drawingArea),"configure-event",
526 G_CALLBACK (configureEvent), (gpointer) lx_b);
527 #if GTK_CHECK_VERSION(3, 0, 0)
528 g_signal_connect (G_OBJECT (lx_b->drawingArea), "draw",
529 G_CALLBACK(draw), (gpointer) lx_b);
530 #else
531 g_signal_connect (G_OBJECT (lx_b->drawingArea), "expose-event",
532 G_CALLBACK (exposeEvent), (gpointer) lx_b);
533 #endif
534
535 /* Apply more default options */
536 if (! lx_b->alarmCommand)
537 lx_b->alarmCommand = g_strconcat("notify-send \"", _("Battery low"), "\" --icon=battery-caution", NULL);
538 if (! lx_b->backgroundColor)
539 lx_b->backgroundColor = g_strdup("black");
540 if (! lx_b->chargingColor1)
541 lx_b->chargingColor1 = g_strdup("#28f200");
542 if (! lx_b->chargingColor2)
543 lx_b->chargingColor2 = g_strdup("#22cc00");
544 if (! lx_b->dischargingColor1)
545 lx_b->dischargingColor1 = g_strdup("#ffee00");
546 if (! lx_b->dischargingColor2)
547 lx_b->dischargingColor2 = g_strdup("#d9ca00");
548
549 gdk_color_parse(lx_b->backgroundColor, &lx_b->background);
550 gdk_color_parse(lx_b->chargingColor1, &lx_b->charging1);
551 gdk_color_parse(lx_b->chargingColor2, &lx_b->charging2);
552 gdk_color_parse(lx_b->dischargingColor1, &lx_b->discharging1);
553 gdk_color_parse(lx_b->dischargingColor2, &lx_b->discharging2);
554
555 /* Start the update loop */
556 lx_b->timer = g_timeout_add_seconds( 9, (GSourceFunc) update_timout, (gpointer) lx_b);
557
558 RET(p);
559 }
560
561
562 static void
563 destructor(gpointer data)
564 {
565 ENTER;
566
567 lx_battery *b = (lx_battery *)data;
568
569 if (b->b != NULL)
570 battery_free(b->b);
571
572 if (b->pixmap)
573 cairo_surface_destroy(b->pixmap);
574
575 g_free(b->alarmCommand);
576 g_free(b->backgroundColor);
577 g_free(b->chargingColor1);
578 g_free(b->chargingColor2);
579 g_free(b->dischargingColor1);
580 g_free(b->dischargingColor2);
581
582 g_free(b->rateSamples);
583 sem_destroy(&(b->alarmProcessLock));
584 if (b->timer)
585 g_source_remove(b->timer);
586 g_free(b);
587
588 RET();
589
590 }
591
592
593 static void orientation(LXPanel *panel, GtkWidget *p) {
594
595 ENTER;
596
597 lx_battery *b = lxpanel_plugin_get_data(p);
598
599 if (b->orientation != panel_get_orientation(panel)) {
600 b->orientation = panel_get_orientation(panel);
601 updateSizes(b);
602 if (b->orientation == GTK_ORIENTATION_HORIZONTAL)
603 {
604 b->width = b->thickness;
605 gtk_widget_set_size_request(b->drawingArea, b->width, -1);
606 }
607 else
608 {
609 b->height = b->thickness;
610 gtk_widget_set_size_request(b->drawingArea, -1, b->height);
611 }
612 }
613
614 RET();
615 }
616
617
618 static gboolean applyConfig(gpointer user_data)
619 {
620 ENTER;
621
622 lx_battery *b = lxpanel_plugin_get_data(user_data);
623
624 /* Update the battery we monitor */
625 battery_free(b->b);
626 b->b = battery_get(b->battery_number);
627
628 /* Update colors */
629 if (b->backgroundColor &&
630 gdk_color_parse(b->backgroundColor, &b->background))
631 config_group_set_string(b->settings, "BackgroundColor", b->backgroundColor);
632 if (b->chargingColor1 && gdk_color_parse(b->chargingColor1, &b->charging1))
633 config_group_set_string(b->settings, "ChargingColor1", b->chargingColor1);
634 if (b->chargingColor2 && gdk_color_parse(b->chargingColor2, &b->charging2))
635 config_group_set_string(b->settings, "ChargingColor2", b->chargingColor2);
636 if (b->dischargingColor1 &&
637 gdk_color_parse(b->dischargingColor1, &b->discharging1))
638 config_group_set_string(b->settings, "DischargingColor1", b->dischargingColor1);
639 if (b->dischargingColor2 &&
640 gdk_color_parse(b->dischargingColor2, &b->discharging2))
641 config_group_set_string(b->settings, "DischargingColor2", b->dischargingColor2);
642
643 /* Make sure it is at least 1 px */
644 if (b->thickness < 1)
645 b->thickness = 1;
646
647 /* Make sure the border value is acceptable */
648 b->requestedBorder = MIN(b->requestedBorder, 6);
649 updateSizes(b);
650
651 /* Resize the widget */
652 gtk_container_set_border_width(b->box, b->border);
653 if (b->orientation == GTK_ORIENTATION_HORIZONTAL)
654 {
655 b->width = b->thickness;
656 gtk_widget_set_size_request(b->drawingArea, b->width, -1);
657 }
658 else
659 {
660 b->height = b->thickness;
661 gtk_widget_set_size_request(b->drawingArea, -1, b->height);
662 }
663 /* ensure visibility if requested */
664 if (!b->hide_if_no_battery)
665 gtk_widget_show(user_data);
666 else if (b->b == NULL)
667 gtk_widget_hide(user_data);
668
669 if (b->alarmCommand == NULL)
670 b->alarmCommand = g_strconcat("xmessage ", _("Battery low"), NULL);
671
672 /* update tooltip */
673 set_tooltip_text(b);
674
675 /* update settings */
676 config_group_set_int(b->settings, "HideIfNoBattery", b->hide_if_no_battery);
677 config_group_set_string(b->settings, "AlarmCommand", b->alarmCommand);
678 config_group_set_int(b->settings, "AlarmTime", b->alarmTime);
679 config_group_set_int(b->settings, "BorderWidth", b->requestedBorder);
680 config_group_set_int(b->settings, "Size", b->thickness);
681 config_group_set_int(b->settings, "ShowExtendedInformation",
682 b->show_extended_information);
683 config_group_set_int(b->settings, "BatteryNumber", b->battery_number);
684
685 update_display(b, TRUE);
686
687 RET(FALSE);
688 }
689
690
691 static GtkWidget *config(LXPanel *panel, GtkWidget *p) {
692 lx_battery *b = lxpanel_plugin_get_data(p);
693 return lxpanel_generic_config_dlg(_("Battery Monitor"),
694 panel, applyConfig, p,
695 _("Hide if there is no battery"), &b->hide_if_no_battery, CONF_TYPE_BOOL,
696 _("Alarm command"), &b->alarmCommand, CONF_TYPE_STR,
697 _("Alarm time (minutes left)"), &b->alarmTime, CONF_TYPE_INT,
698 _("Background color"), &b->backgroundColor, CONF_TYPE_STR,
699 _("Charging color 1"), &b->chargingColor1, CONF_TYPE_STR,
700 _("Charging color 2"), &b->chargingColor2, CONF_TYPE_STR,
701 _("Discharging color 1"), &b->dischargingColor1, CONF_TYPE_STR,
702 _("Discharging color 2"), &b->dischargingColor2, CONF_TYPE_STR,
703 "", panel_config_int_button_new(_("Border width"), (int *)&b->requestedBorder,
704 0, 6), CONF_TYPE_EXTERNAL,
705 "", panel_config_int_button_new(_("Size"), (int *)&b->thickness,
706 1, 50), CONF_TYPE_EXTERNAL,
707 _("Show Extended Information"), &b->show_extended_information, CONF_TYPE_BOOL,
708 _("Number of battery to monitor"), &b->battery_number, CONF_TYPE_INT,
709 NULL);
710 }
711
712
713 FM_DEFINE_MODULE(lxpanel_gtk, batt)
714
715 /* Plugin descriptor. */
716 LXPanelPluginInit fm_module_init_lxpanel_gtk = {
717 .name = N_("Battery Monitor"),
718 .description = N_("Display battery status using ACPI"),
719
720 .new_instance = constructor,
721 .config = config,
722 .reconfigure = orientation,
723 .button_press_event = buttonPressEvent
724 };
725
726
727 /* vim: set sw=4 sts=4 : */