Adding upstream version 0.9.0.
[debian/lxpanel.git] / plugins / batt / batt.c
CommitLineData
6b775dbb
AG
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>
7a1c5048
AG
8 * 2015 Balló György <ballogyor@gmail.com>
9 * 2015 Stanislav Kozina, Ersin <xersin@users.sf.net>
6b775dbb
AG
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.
6b775dbb
AG
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
57typedef 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;
f7ecd6ce 70 GtkContainer *box;
6b775dbb
AG
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;
7a1c5048 88 int battery_number;
6b775dbb
AG
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
98typedef struct {
99 char *command;
100 sem_t *lock;
101} Alarm;
102
103static void destructor(gpointer data);
104static 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. */
108static 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
121static 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 */
140static 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) {
7a1c5048
AG
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 goto _charged;
6b775dbb
AG
162 } else {
163 /* if we have enough rate information for battery */
164 if (lx_b->b->percentage != 100) {
165 int hours = lx_b->b->seconds / 3600;
166 int left_seconds = lx_b->b->seconds - 3600 * hours;
167 int minutes = left_seconds / 60;
168 tooltip = g_strdup_printf(
7a1c5048
AG
169 _("Battery %d: %d%% charged, %d:%02d left"),
170 lx_b->battery_number, lx_b->b->percentage,
6b775dbb
AG
171 hours,
172 minutes );
173 } else {
7a1c5048 174_charged:
6b775dbb 175 tooltip = g_strdup_printf(
7a1c5048
AG
176 _("Battery %d: %d%% charged"),
177 lx_b->battery_number, lx_b->b->percentage);
6b775dbb
AG
178 }
179 }
180
181 if (!lx_b->show_extended_information) {
182 return tooltip;
183 }
184
185 if (b->energy_full_design != -1)
186 append(&tooltip, _("\n%sEnergy full design:\t\t%5d mWh"), indent, b->energy_full_design);
187 if (b->energy_full != -1)
188 append(&tooltip, _("\n%sEnergy full:\t\t\t%5d mWh"), indent, b->energy_full);
189 if (b->energy_now != -1)
190 append(&tooltip, _("\n%sEnergy now:\t\t\t%5d mWh"), indent, b->energy_now);
191 if (b->power_now != -1)
192 append(&tooltip, _("\n%sPower now:\t\t\t%5d mW"), indent, b->power_now);
193
194 if (b->charge_full_design != -1)
195 append(&tooltip, _("\n%sCharge full design:\t%5d mAh"), indent, b->charge_full_design);
196 if (b->charge_full != -1)
197 append(&tooltip, _("\n%sCharge full:\t\t\t%5d mAh"), indent, b->charge_full);
198 if (b->charge_now != -1)
199 append(&tooltip, _("\n%sCharge now:\t\t\t%5d mAh"), indent, b->charge_now);
200 if (b->current_now != -1)
201 append(&tooltip, _("\n%sCurrent now:\t\t\t%5d mA"), indent, b->current_now);
202
203 if (b->voltage_now != -1)
204 append(&tooltip, _("\n%sCurrent Voltage:\t\t%.3lf V"), indent, b->voltage_now / 1000.0);
205
206 return tooltip;
207}
208
209static void set_tooltip_text(lx_battery* lx_b)
210{
211 if (lx_b->b == NULL)
212 return;
213 gboolean isCharging = battery_is_charging(lx_b->b);
214 gchar *tooltip = make_tooltip(lx_b, isCharging);
215 gtk_widget_set_tooltip_text(lx_b->drawingArea, tooltip);
216 g_free(tooltip);
217}
218
219/* FIXME:
220 Don't repaint if percentage of remaining charge and remaining time aren't changed. */
221void update_display(lx_battery *lx_b, gboolean repaint) {
222 cairo_t *cr;
223 battery *b = lx_b->b;
224 /* unit: mW */
225 int rate;
226 gboolean isCharging;
227
228 if (! lx_b->pixmap )
229 return;
230
231 cr = cairo_create(lx_b->pixmap);
232 cairo_set_line_width (cr, 1.0);
233
234 /* draw background */
235 gdk_cairo_set_source_color(cr, &lx_b->background);
236 cairo_rectangle(cr, 0, 0, lx_b->width, lx_b->height);
237 cairo_fill(cr);
238
239 /* no battery is found */
240 if( b == NULL )
241 {
242 gtk_widget_set_tooltip_text( lx_b->drawingArea, _("No batteries found") );
243 if (lx_b->hide_if_no_battery)
244 {
245 gtk_widget_hide(gtk_widget_get_parent(lx_b->drawingArea));
246 repaint = FALSE;
247 }
248 goto update_done;
249 }
250
251 /* fixme: only one battery supported */
252
253 rate = lx_b->b->current_now;
254 isCharging = battery_is_charging ( b );
255
256 /* Consider running the alarm command */
257 if ( !isCharging && rate > 0 &&
258 ( ( battery_get_remaining( b ) / 60 ) < (int)lx_b->alarmTime ) )
259 {
f7ecd6ce
AG
260 /* FIXME: this should be done using glibs process functions */
261 /* FIXME: see bug #463: it should not spawn process all the time */
6b775dbb
AG
262 /* Alarms should not run concurrently; determine whether an alarm is
263 already running */
264 int alarmCanRun;
265 sem_getvalue(&(lx_b->alarmProcessLock), &alarmCanRun);
266
267 /* Run the alarm command if it isn't already running */
268 if (alarmCanRun) {
269
270 Alarm *a = (Alarm *) malloc(sizeof(Alarm));
271 a->command = lx_b->alarmCommand;
272 a->lock = &(lx_b->alarmProcessLock);
273
274 /* Manage the alarm process in a new thread, which which will be
275 responsible for freeing the alarm struct it's given */
276 pthread_t alarmThread;
277 pthread_create(&alarmThread, NULL, alarmProcess, a);
278 }
279 }
280
281 set_tooltip_text(lx_b);
282
f7ecd6ce 283 int chargeLevel = lx_b->b->percentage * lx_b->length / 100;
6b775dbb
AG
284
285 if (lx_b->orientation == GTK_ORIENTATION_HORIZONTAL) {
286
287 /* Draw the battery bar vertically, using color 1 for the left half and
288 color 2 for the right half */
289 gdk_cairo_set_source_color(cr,
290 isCharging ? &lx_b->charging1 : &lx_b->discharging1);
f7ecd6ce
AG
291 cairo_rectangle(cr, 0, lx_b->height - chargeLevel,
292 lx_b->width / 2, chargeLevel);
6b775dbb
AG
293 cairo_fill(cr);
294 gdk_cairo_set_source_color(cr,
295 isCharging ? &lx_b->charging2 : &lx_b->discharging2);
f7ecd6ce
AG
296 cairo_rectangle(cr, lx_b->width / 2, lx_b->height - chargeLevel,
297 (lx_b->width + 1) / 2, chargeLevel);
6b775dbb
AG
298 cairo_fill(cr);
299
300 }
301 else {
302
303 /* Draw the battery bar horizontally, using color 1 for the top half and
304 color 2 for the bottom half */
305 gdk_cairo_set_source_color(cr,
306 isCharging ? &lx_b->charging1 : &lx_b->discharging1);
f7ecd6ce 307 cairo_rectangle(cr, 0, 0, chargeLevel, lx_b->height / 2);
6b775dbb
AG
308 cairo_fill(cr);
309 gdk_cairo_set_source_color(cr,
310 isCharging ? &lx_b->charging2 : &lx_b->discharging2);
f7ecd6ce
AG
311 cairo_rectangle(cr, 0, (lx_b->height + 1) / 2,
312 chargeLevel, lx_b->height / 2);
6b775dbb
AG
313 cairo_fill(cr);
314
315 }
316 gtk_widget_show(gtk_widget_get_parent(lx_b->drawingArea));
317
318update_done:
319 if( repaint )
320 gtk_widget_queue_draw( lx_b->drawingArea );
321
322 check_cairo_status(cr);
323 cairo_destroy(cr);
324}
325
326/* This callback is called every 3 seconds */
327static int update_timout(lx_battery *lx_b) {
328 battery *bat;
329 if (g_source_is_destroyed(g_main_current_source()))
330 return FALSE;
331 GDK_THREADS_ENTER();
332 lx_b->state_elapsed_time++;
333 lx_b->info_elapsed_time++;
334
335 bat = battery_update( lx_b->b );
336 if (bat == NULL)
337 {
338 battery_free(lx_b->b);
339
340 /* maybe in the mean time a battery has been inserted. */
7a1c5048 341 lx_b->b = battery_get(lx_b->battery_number);
6b775dbb
AG
342 }
343
344 update_display( lx_b, TRUE );
345
346 GDK_THREADS_LEAVE();
347 return TRUE;
348}
349
350/* An update will be performed whenever the user clicks on the charge bar */
351static gboolean buttonPressEvent(GtkWidget *p, GdkEventButton *event,
352 LXPanel *panel)
353{
354 lx_battery *lx_b = lxpanel_plugin_get_data(p);
355
356 update_display(lx_b, TRUE);
357 /* FIXME: open some application for lid/power management may be? */
358
359 return FALSE;
360}
361
6b775dbb
AG
362static gint configureEvent(GtkWidget *widget, GdkEventConfigure *event,
363 lx_battery *lx_b)
364{
365 GtkAllocation allocation;
366
367 ENTER;
368
369 gtk_widget_get_allocation(widget, &allocation);
370 if (allocation.width <= 1 && allocation.height <= 1)
371 {
372 /* If plugin is hidden currently then we get 1x1 here */
373 RET(TRUE);
374 }
375
376 if (lx_b->pixmap)
377 cairo_surface_destroy(lx_b->pixmap);
378
379 /* Update the plugin's dimensions */
380 lx_b->width = allocation.width;
381 lx_b->height = allocation.height;
382 if (lx_b->orientation == GTK_ORIENTATION_HORIZONTAL) {
383 lx_b->length = lx_b->height;
6b775dbb
AG
384 }
385 else {
386 lx_b->length = lx_b->width;
6b775dbb
AG
387 }
388
389 lx_b->pixmap = cairo_image_surface_create (CAIRO_FORMAT_RGB24, allocation.width,
390 allocation.height);
391 check_cairo_surface_status(&lx_b->pixmap);
392
393 /* Perform an update so the bar will look right in its new orientation */
394 update_display(lx_b, FALSE);
395
f7ecd6ce
AG
396 /* we enforce border width here because panel sets it to 0 */
397 gtk_container_set_border_width(lx_b->box, lx_b->border);
398
6b775dbb
AG
399 RET(TRUE);
400}
401
402
7a1c5048
AG
403#if GTK_CHECK_VERSION(3, 0, 0)
404static gint draw(GtkWidget *widget, cairo_t *cr, lx_battery *lx_b) {
405#else
6b775dbb 406static gint exposeEvent(GtkWidget *widget, GdkEventExpose *event, lx_battery *lx_b) {
7a1c5048 407#endif
6b775dbb
AG
408
409 ENTER;
7a1c5048
AG
410
411#if GTK_CHECK_VERSION(3, 0, 0)
412 cairo_set_source_rgb(cr, 0, 0, 0); // FIXME: set black color from the style
413#else
6b775dbb
AG
414 cairo_t *cr = gdk_cairo_create(gtk_widget_get_window(widget));
415 GtkStyle *style = gtk_widget_get_style(lx_b->drawingArea);
416
417 gdk_cairo_region(cr, event->region);
418 cairo_clip(cr);
419
420 gdk_cairo_set_source_color(cr, &style->black);
7a1c5048 421#endif
6b775dbb
AG
422 cairo_set_source_surface(cr, lx_b->pixmap, 0, 0);
423 cairo_paint(cr);
424
425 check_cairo_status(cr);
7a1c5048 426#if !GTK_CHECK_VERSION(3, 0, 0)
6b775dbb 427 cairo_destroy(cr);
7a1c5048 428#endif
6b775dbb
AG
429
430 RET(FALSE);
431}
432
f7ecd6ce
AG
433/* updates length, border, and height/width appropriate to orientation */
434static void updateSizes(lx_battery *b)
435{
436 b->length = panel_get_height(b->panel);
437 b->border = MIN(b->requestedBorder, (MAX(1, b->length) - 1) / 2);
438 b->length -= 2 * b->border;
439 if (b->orientation == GTK_ORIENTATION_HORIZONTAL)
440 b->height = b->length;
441 else
442 b->width = b->length;
443}
444
6b775dbb
AG
445
446static GtkWidget * constructor(LXPanel *panel, config_setting_t *settings)
447{
448 ENTER;
449
450 lx_battery *lx_b;
451 GtkWidget *p;
452 const char *str;
453 int tmp_int;
454
455 lx_b = g_new0(lx_battery, 1);
456
7a1c5048
AG
457 /* get requested battery */
458 if (config_setting_lookup_int(settings, "BatteryNumber", &tmp_int))
459 lx_b->battery_number = MAX(0, tmp_int);
460 lx_b->b = battery_get(lx_b->battery_number);
6b775dbb
AG
461
462 p = gtk_event_box_new();
463 lxpanel_plugin_set_data(p, lx_b, destructor);
464 gtk_widget_set_has_window(p, FALSE);
6b775dbb 465
f7ecd6ce 466 lx_b->box = GTK_CONTAINER(p);
6b775dbb 467 lx_b->drawingArea = gtk_drawing_area_new();
7a1c5048
AG
468 gtk_widget_add_events(lx_b->drawingArea, GDK_BUTTON_PRESS_MASK |
469 GDK_BUTTON_RELEASE_MASK |
470 GDK_BUTTON_MOTION_MASK);
6b775dbb 471
f7ecd6ce 472 gtk_container_add(lx_b->box, lx_b->drawingArea);
6b775dbb
AG
473
474 lx_b->orientation = panel_get_orientation(panel);
6b775dbb
AG
475
476 gtk_widget_show(lx_b->drawingArea);
477
6b775dbb
AG
478 sem_init(&(lx_b->alarmProcessLock), 0, 1);
479
480 lx_b->alarmCommand = lx_b->backgroundColor = lx_b->chargingColor1 = lx_b->chargingColor2
481 = lx_b->dischargingColor1 = lx_b->dischargingColor2 = NULL;
482
483 /* Set default values for integers */
484 lx_b->alarmTime = 5;
485 lx_b->requestedBorder = 1;
f7ecd6ce 486 lx_b->thickness = 8;
6b775dbb
AG
487
488 /* remember instance data */
489 lx_b->panel = panel;
490 lx_b->settings = settings;
491
492 lx_b->show_extended_information = FALSE;
493
494 if (config_setting_lookup_int(settings, "HideIfNoBattery", &tmp_int))
495 lx_b->hide_if_no_battery = (tmp_int != 0);
496 if (config_setting_lookup_string(settings, "AlarmCommand", &str))
497 lx_b->alarmCommand = g_strdup(str);
498 if (config_setting_lookup_string(settings, "BackgroundColor", &str))
499 lx_b->backgroundColor = g_strdup(str);
500 if (config_setting_lookup_string(settings, "ChargingColor1", &str))
501 lx_b->chargingColor1 = g_strdup(str);
502 if (config_setting_lookup_string(settings, "ChargingColor2", &str))
503 lx_b->chargingColor2 = g_strdup(str);
504 if (config_setting_lookup_string(settings, "DischargingColor1", &str))
505 lx_b->dischargingColor1 = g_strdup(str);
506 if (config_setting_lookup_string(settings, "DischargingColor2", &str))
507 lx_b->dischargingColor2 = g_strdup(str);
508 if (config_setting_lookup_int(settings, "AlarmTime", &tmp_int))
509 lx_b->alarmTime = MAX(0, tmp_int);
510 if (config_setting_lookup_int(settings, "BorderWidth", &tmp_int))
f7ecd6ce
AG
511 lx_b->requestedBorder = CLAMP(tmp_int, 0, 6);
512 if (config_setting_lookup_int(settings, "Size", &tmp_int))
6b775dbb 513 lx_b->thickness = MAX(1, tmp_int);
6b775dbb
AG
514 if (config_setting_lookup_int(settings, "ShowExtendedInformation", &tmp_int))
515 lx_b->show_extended_information = (tmp_int != 0);
516
517 /* Make sure the border value is acceptable */
f7ecd6ce
AG
518 updateSizes(lx_b);
519 if (lx_b->orientation == GTK_ORIENTATION_HORIZONTAL)
520 {
521 lx_b->width = lx_b->thickness;
522 gtk_widget_set_size_request(lx_b->drawingArea, lx_b->width, -1);
523 }
524 else
525 {
526 lx_b->height = lx_b->thickness;
527 gtk_widget_set_size_request(lx_b->drawingArea, -1, lx_b->height);
528 }
529
530 g_signal_connect (G_OBJECT (lx_b->drawingArea),"configure-event",
531 G_CALLBACK (configureEvent), (gpointer) lx_b);
7a1c5048
AG
532#if GTK_CHECK_VERSION(3, 0, 0)
533 g_signal_connect (G_OBJECT (lx_b->drawingArea), "draw",
534 G_CALLBACK(draw), (gpointer) lx_b);
535#else
f7ecd6ce
AG
536 g_signal_connect (G_OBJECT (lx_b->drawingArea), "expose-event",
537 G_CALLBACK (exposeEvent), (gpointer) lx_b);
7a1c5048 538#endif
6b775dbb
AG
539
540 /* Apply more default options */
541 if (! lx_b->alarmCommand)
0688b017 542 lx_b->alarmCommand = g_strconcat("notify-send \"", _("Battery low"), "\" --icon=battery-caution", NULL);
6b775dbb
AG
543 if (! lx_b->backgroundColor)
544 lx_b->backgroundColor = g_strdup("black");
545 if (! lx_b->chargingColor1)
546 lx_b->chargingColor1 = g_strdup("#28f200");
547 if (! lx_b->chargingColor2)
548 lx_b->chargingColor2 = g_strdup("#22cc00");
549 if (! lx_b->dischargingColor1)
550 lx_b->dischargingColor1 = g_strdup("#ffee00");
551 if (! lx_b->dischargingColor2)
552 lx_b->dischargingColor2 = g_strdup("#d9ca00");
553
554 gdk_color_parse(lx_b->backgroundColor, &lx_b->background);
555 gdk_color_parse(lx_b->chargingColor1, &lx_b->charging1);
556 gdk_color_parse(lx_b->chargingColor2, &lx_b->charging2);
557 gdk_color_parse(lx_b->dischargingColor1, &lx_b->discharging1);
558 gdk_color_parse(lx_b->dischargingColor2, &lx_b->discharging2);
559
560 /* Start the update loop */
561 lx_b->timer = g_timeout_add_seconds( 9, (GSourceFunc) update_timout, (gpointer) lx_b);
562
563 RET(p);
564}
565
566
567static void
568destructor(gpointer data)
569{
570 ENTER;
571
572 lx_battery *b = (lx_battery *)data;
573
574 if (b->b != NULL)
575 battery_free(b->b);
576
577 if (b->pixmap)
578 cairo_surface_destroy(b->pixmap);
579
580 g_free(b->alarmCommand);
581 g_free(b->backgroundColor);
582 g_free(b->chargingColor1);
583 g_free(b->chargingColor2);
584 g_free(b->dischargingColor1);
585 g_free(b->dischargingColor2);
586
587 g_free(b->rateSamples);
588 sem_destroy(&(b->alarmProcessLock));
589 if (b->timer)
590 g_source_remove(b->timer);
591 g_free(b);
592
593 RET();
594
595}
596
597
598static void orientation(LXPanel *panel, GtkWidget *p) {
599
600 ENTER;
601
602 lx_battery *b = lxpanel_plugin_get_data(p);
603
604 if (b->orientation != panel_get_orientation(panel)) {
605 b->orientation = panel_get_orientation(panel);
f7ecd6ce
AG
606 updateSizes(b);
607 if (b->orientation == GTK_ORIENTATION_HORIZONTAL)
608 {
609 b->width = b->thickness;
610 gtk_widget_set_size_request(b->drawingArea, b->width, -1);
611 }
612 else
613 {
614 b->height = b->thickness;
615 gtk_widget_set_size_request(b->drawingArea, -1, b->height);
616 }
6b775dbb
AG
617 }
618
619 RET();
620}
621
622
623static gboolean applyConfig(gpointer user_data)
624{
625 ENTER;
626
627 lx_battery *b = lxpanel_plugin_get_data(user_data);
628
7a1c5048
AG
629 /* Update the battery we monitor */
630 battery_free(b->b);
631 b->b = battery_get(b->battery_number);
632
6b775dbb
AG
633 /* Update colors */
634 if (b->backgroundColor &&
635 gdk_color_parse(b->backgroundColor, &b->background))
636 config_group_set_string(b->settings, "BackgroundColor", b->backgroundColor);
637 if (b->chargingColor1 && gdk_color_parse(b->chargingColor1, &b->charging1))
638 config_group_set_string(b->settings, "ChargingColor1", b->chargingColor1);
639 if (b->chargingColor2 && gdk_color_parse(b->chargingColor2, &b->charging2))
640 config_group_set_string(b->settings, "ChargingColor2", b->chargingColor2);
641 if (b->dischargingColor1 &&
642 gdk_color_parse(b->dischargingColor1, &b->discharging1))
643 config_group_set_string(b->settings, "DischargingColor1", b->dischargingColor1);
644 if (b->dischargingColor2 &&
645 gdk_color_parse(b->dischargingColor2, &b->discharging2))
646 config_group_set_string(b->settings, "DischargingColor2", b->dischargingColor2);
647
f7ecd6ce
AG
648 /* Make sure it is at least 1 px */
649 if (b->thickness < 1)
650 b->thickness = 1;
651
6b775dbb 652 /* Make sure the border value is acceptable */
f7ecd6ce
AG
653 b->requestedBorder = MIN(b->requestedBorder, 6);
654 updateSizes(b);
6b775dbb
AG
655
656 /* Resize the widget */
f7ecd6ce 657 gtk_container_set_border_width(b->box, b->border);
6b775dbb 658 if (b->orientation == GTK_ORIENTATION_HORIZONTAL)
f7ecd6ce 659 {
6b775dbb 660 b->width = b->thickness;
f7ecd6ce
AG
661 gtk_widget_set_size_request(b->drawingArea, b->width, -1);
662 }
6b775dbb 663 else
f7ecd6ce 664 {
6b775dbb 665 b->height = b->thickness;
f7ecd6ce
AG
666 gtk_widget_set_size_request(b->drawingArea, -1, b->height);
667 }
6b775dbb
AG
668 /* ensure visibility if requested */
669 if (!b->hide_if_no_battery)
670 gtk_widget_show(user_data);
671 else if (b->b == NULL)
672 gtk_widget_hide(user_data);
673
f7ecd6ce
AG
674 if (b->alarmCommand == NULL)
675 b->alarmCommand = g_strconcat("xmessage ", _("Battery low"), NULL);
676
6b775dbb
AG
677 /* update tooltip */
678 set_tooltip_text(b);
679
680 /* update settings */
681 config_group_set_int(b->settings, "HideIfNoBattery", b->hide_if_no_battery);
682 config_group_set_string(b->settings, "AlarmCommand", b->alarmCommand);
683 config_group_set_int(b->settings, "AlarmTime", b->alarmTime);
684 config_group_set_int(b->settings, "BorderWidth", b->requestedBorder);
685 config_group_set_int(b->settings, "Size", b->thickness);
686 config_group_set_int(b->settings, "ShowExtendedInformation",
687 b->show_extended_information);
7a1c5048
AG
688 config_group_set_int(b->settings, "BatteryNumber", b->battery_number);
689
690 update_display(b, TRUE);
6b775dbb
AG
691
692 RET(FALSE);
693}
694
695
696static GtkWidget *config(LXPanel *panel, GtkWidget *p) {
697 lx_battery *b = lxpanel_plugin_get_data(p);
698 return lxpanel_generic_config_dlg(_("Battery Monitor"),
699 panel, applyConfig, p,
700 _("Hide if there is no battery"), &b->hide_if_no_battery, CONF_TYPE_BOOL,
701 _("Alarm command"), &b->alarmCommand, CONF_TYPE_STR,
702 _("Alarm time (minutes left)"), &b->alarmTime, CONF_TYPE_INT,
703 _("Background color"), &b->backgroundColor, CONF_TYPE_STR,
704 _("Charging color 1"), &b->chargingColor1, CONF_TYPE_STR,
705 _("Charging color 2"), &b->chargingColor2, CONF_TYPE_STR,
706 _("Discharging color 1"), &b->dischargingColor1, CONF_TYPE_STR,
707 _("Discharging color 2"), &b->dischargingColor2, CONF_TYPE_STR,
f7ecd6ce
AG
708 "", panel_config_int_button_new(_("Border width"), (int *)&b->requestedBorder,
709 0, 6), CONF_TYPE_EXTERNAL,
710 "", panel_config_int_button_new(_("Size"), (int *)&b->thickness,
711 1, 50), CONF_TYPE_EXTERNAL,
6b775dbb 712 _("Show Extended Information"), &b->show_extended_information, CONF_TYPE_BOOL,
7a1c5048 713 _("Number of battery to monitor"), &b->battery_number, CONF_TYPE_INT,
6b775dbb
AG
714 NULL);
715}
716
717
718FM_DEFINE_MODULE(lxpanel_gtk, batt)
719
720/* Plugin descriptor. */
721LXPanelPluginInit fm_module_init_lxpanel_gtk = {
722 .name = N_("Battery Monitor"),
723 .description = N_("Display battery status using ACPI"),
724
725 .new_instance = constructor,
726 .config = config,
727 .reconfigure = orientation,
728 .button_press_event = buttonPressEvent
729};
730
731
732/* vim: set sw=4 sts=4 : */