Fix broken panel menus for 'batt' and 'monitors' plugins.
[lxde/lxpanel.git] / plugins / batt / batt.c
CommitLineData
8f11d5f8
HJYP
1/*
2 * ACPI battery monitor plugin for LXPanel
3 *
4 * Copyright (C) 2007 by Greg McNew <gmcnew@gmail.com>
802d5540 5 * Copyright (C) 2008 by Hong Jen Yee <pcman.tw@gmail.com>
c887dfa0 6 * Copyright (C) 2009 by Juergen Hoetzel <juergen@archlinux.org>
b840f7cc 7 * Copyright (C) 2014 by Andriy Grytsenko <andrej@rep.kiev.ua>
d5b4b3fe 8 * 2015 Balló György <ballogyor@gmail.com>
ac5ee186 9 * 2015 Stanislav Kozina, Ersin <xersin@users.sf.net>
8f11d5f8
HJYP
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
c887dfa0
JH
27 * battery information found in /sys/class/power_supply. The update interval is
28 * user-configurable and defaults to 3 second.
8f11d5f8
HJYP
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
e751fe05
HJYP
35/* FIXME:
36 * Here are somethings need to be improvec:
37 * 1. Replace pthread stuff with gthread counterparts for portability.
e751fe05
HJYP
38 * 4. Handle failure gracefully under systems other than Linux.
39*/
40
41#include <glib.h>
8f11d5f8 42#include <glib/gi18n.h>
c0ed75bf 43#include <pthread.h> /* used by pthread_create() and alarmThread */
8f11d5f8
HJYP
44#include <semaphore.h> /* used by update() and alarmProcess() for alarms */
45#include <stdlib.h>
802d5540 46#include <string.h>
9c9d3a00 47#include <stdarg.h>
8f11d5f8 48
811afd8f 49#include "dbg.h" /* for ENTER and RET macros */
c887dfa0 50#include "batt_sys.h"
813c2d44 51#include "plugin.h" /* all other APIs including panel configuration */
8f11d5f8 52
8f11d5f8
HJYP
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
802d5540 57typedef struct {
8f11d5f8
HJYP
58 char *alarmCommand,
59 *backgroundColor,
60 *chargingColor1,
61 *chargingColor2,
62 *dischargingColor1,
802d5540
HJYP
63 *dischargingColor2;
64 GdkColor background,
65 charging1,
66 charging2,
67 discharging1,
68 discharging2;
f176735a 69 cairo_surface_t *pixmap;
4ebd3285 70 GtkContainer *box;
802d5540 71 GtkWidget *drawingArea;
6a1a639e 72 GtkOrientation orientation;
8f11d5f8
HJYP
73 unsigned int alarmTime,
74 border,
75 height,
76 length,
77 numSamples,
78 requestedBorder,
79 *rateSamples,
80 rateSamplesSum,
81 thickness,
82 timer,
802d5540
HJYP
83 state_elapsed_time,
84 info_elapsed_time,
8f11d5f8 85 wasCharging,
04a2f050
HJYP
86 width,
87 hide_if_no_battery;
1c8a4455 88 int battery_number;
8f11d5f8 89 sem_t alarmProcessLock;
c887dfa0 90 battery* b;
3051b49c 91 gboolean has_ac_adapter;
5c0c599d 92 gboolean show_extended_information;
a7bd16a4 93 LXPanel *panel;
813c2d44 94 config_setting_t *settings;
c887dfa0 95} lx_battery;
8f11d5f8
HJYP
96
97
98typedef struct {
99 char *command;
100 sem_t *lock;
4a974f26 101} Alarm;
8f11d5f8 102
813c2d44 103static void destructor(gpointer data);
c887dfa0 104static void update_display(lx_battery *lx_b, gboolean repaint);
3051b49c 105
8f11d5f8
HJYP
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. */
c0ed75bf 108static void * alarmProcess(void *arg) {
4a974f26 109 Alarm *a = (Alarm *) arg;
8f11d5f8
HJYP
110
111 sem_wait(a->lock);
6a1a639e
AG
112 if (system(a->command) != 0)
113 g_warning("plugin batt: failed to execute alarm command \"%s\"", a->command);
8f11d5f8
HJYP
114 sem_post(a->lock);
115
116 g_free(a);
c0ed75bf 117 return NULL;
8f11d5f8
HJYP
118}
119
9c9d3a00
HG
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
f855ac58
HG
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;
9c9d3a00
HG
143 gchar * indent = " ";
144 battery *b = lx_b->b;
f855ac58 145
029d9f0c 146 if (b == NULL)
811afd8f 147 return NULL;
029d9f0c 148
f855ac58 149 if (isCharging) {
f10625d7
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 }
f855ac58 160 } else {
811afd8f
AG
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(
1c8a4455
SKE
167 _("Battery %d: %d%% charged, %d:%02d left"),
168 lx_b->battery_number, lx_b->b->percentage,
811afd8f
AG
169 hours,
170 minutes );
171 } else {
172 tooltip = g_strdup_printf(
1c8a4455
SKE
173 _("Battery %d: %d%% charged"),
174 lx_b->battery_number, 100 );
811afd8f 175 }
f855ac58
HG
176 }
177
5c0c599d 178 if (!lx_b->show_extended_information) {
811afd8f 179 return tooltip;
5c0c599d
HG
180 }
181
9c9d3a00 182 if (b->energy_full_design != -1)
811afd8f 183 append(&tooltip, _("\n%sEnergy full design:\t\t%5d mWh"), indent, b->energy_full_design);
9c9d3a00 184 if (b->energy_full != -1)
811afd8f 185 append(&tooltip, _("\n%sEnergy full:\t\t\t%5d mWh"), indent, b->energy_full);
9c9d3a00 186 if (b->energy_now != -1)
811afd8f 187 append(&tooltip, _("\n%sEnergy now:\t\t\t%5d mWh"), indent, b->energy_now);
9c9d3a00 188 if (b->power_now != -1)
811afd8f 189 append(&tooltip, _("\n%sPower now:\t\t\t%5d mW"), indent, b->power_now);
9c9d3a00
HG
190
191 if (b->charge_full_design != -1)
811afd8f 192 append(&tooltip, _("\n%sCharge full design:\t%5d mAh"), indent, b->charge_full_design);
9c9d3a00 193 if (b->charge_full != -1)
811afd8f 194 append(&tooltip, _("\n%sCharge full:\t\t\t%5d mAh"), indent, b->charge_full);
9c9d3a00 195 if (b->charge_now != -1)
811afd8f 196 append(&tooltip, _("\n%sCharge now:\t\t\t%5d mAh"), indent, b->charge_now);
9c9d3a00 197 if (b->current_now != -1)
811afd8f 198 append(&tooltip, _("\n%sCurrent now:\t\t\t%5d mA"), indent, b->current_now);
9c9d3a00
HG
199
200 if (b->voltage_now != -1)
811afd8f 201 append(&tooltip, _("\n%sCurrent Voltage:\t\t%.3lf V"), indent, b->voltage_now / 1000.0);
9c9d3a00 202
f855ac58
HG
203 return tooltip;
204}
205
5c0c599d
HG
206static void set_tooltip_text(lx_battery* lx_b)
207{
029d9f0c 208 if (lx_b->b == NULL)
811afd8f 209 return;
5c0c599d
HG
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}
8f11d5f8 215
802d5540
HJYP
216/* FIXME:
217 Don't repaint if percentage of remaining charge and remaining time aren't changed. */
c887dfa0 218void update_display(lx_battery *lx_b, gboolean repaint) {
f176735a 219 cairo_t *cr;
c887dfa0
JH
220 battery *b = lx_b->b;
221 /* unit: mW */
7f9ba86b 222 int rate;
eef7d6f6 223 gboolean isCharging;
8f11d5f8 224
c887dfa0 225 if (! lx_b->pixmap )
802d5540 226 return;
8f11d5f8 227
f176735a
RM
228 cr = cairo_create(lx_b->pixmap);
229 cairo_set_line_width (cr, 1.0);
230
dc9d3b94
HG
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
c887dfa0 236 /* no battery is found */
811afd8f 237 if( b == NULL )
802d5540 238 {
811afd8f 239 gtk_widget_set_tooltip_text( lx_b->drawingArea, _("No batteries found") );
f50948df
AG
240 if (lx_b->hide_if_no_battery)
241 {
242 gtk_widget_hide(gtk_widget_get_parent(lx_b->drawingArea));
243 repaint = FALSE;
244 }
811afd8f 245 goto update_done;
c887dfa0 246 }
811afd8f 247
c887dfa0 248 /* fixme: only one battery supported */
8f11d5f8 249
7f9ba86b 250 rate = lx_b->b->current_now;
c887dfa0 251 isCharging = battery_is_charging ( b );
811afd8f 252
c887dfa0 253 /* Consider running the alarm command */
b37f46a0 254 if ( !isCharging && rate > 0 &&
6a1a639e 255 ( ( battery_get_remaining( b ) / 60 ) < (int)lx_b->alarmTime ) )
c887dfa0 256 {
affe59e1
AG
257 /* FIXME: this should be done using glibs process functions */
258 /* FIXME: see bug #463: it should not spawn process all the time */
811afd8f
AG
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 }
c887dfa0 276 }
8f11d5f8 277
5c0c599d 278 set_tooltip_text(lx_b);
eef7d6f6 279
4ebd3285 280 int chargeLevel = lx_b->b->percentage * lx_b->length / 100;
eef7d6f6 281
cfde283a 282 if (lx_b->orientation == GTK_ORIENTATION_HORIZONTAL) {
eef7d6f6 283
811afd8f
AG
284 /* Draw the battery bar vertically, using color 1 for the left half and
285 color 2 for the right half */
f176735a
RM
286 gdk_cairo_set_source_color(cr,
287 isCharging ? &lx_b->charging1 : &lx_b->discharging1);
4ebd3285
AG
288 cairo_rectangle(cr, 0, lx_b->height - chargeLevel,
289 lx_b->width / 2, chargeLevel);
f176735a
RM
290 cairo_fill(cr);
291 gdk_cairo_set_source_color(cr,
292 isCharging ? &lx_b->charging2 : &lx_b->discharging2);
4ebd3285
AG
293 cairo_rectangle(cr, lx_b->width / 2, lx_b->height - chargeLevel,
294 (lx_b->width + 1) / 2, chargeLevel);
f176735a 295 cairo_fill(cr);
eef7d6f6
HG
296
297 }
298 else {
299
811afd8f
AG
300 /* Draw the battery bar horizontally, using color 1 for the top half and
301 color 2 for the bottom half */
f176735a
RM
302 gdk_cairo_set_source_color(cr,
303 isCharging ? &lx_b->charging1 : &lx_b->discharging1);
4ebd3285 304 cairo_rectangle(cr, 0, 0, chargeLevel, lx_b->height / 2);
f176735a
RM
305 cairo_fill(cr);
306 gdk_cairo_set_source_color(cr,
307 isCharging ? &lx_b->charging2 : &lx_b->discharging2);
4ebd3285
AG
308 cairo_rectangle(cr, 0, (lx_b->height + 1) / 2,
309 chargeLevel, lx_b->height / 2);
f176735a 310 cairo_fill(cr);
eef7d6f6
HG
311
312 }
f50948df 313 gtk_widget_show(gtk_widget_get_parent(lx_b->drawingArea));
dc9d3b94
HG
314
315update_done:
eef7d6f6 316 if( repaint )
811afd8f 317 gtk_widget_queue_draw( lx_b->drawingArea );
e4f8b15f
HG
318
319 check_cairo_status(cr);
320 cairo_destroy(cr);
8f11d5f8
HJYP
321}
322
71671bf6 323/* This callback is called every 3 seconds */
c887dfa0 324static int update_timout(lx_battery *lx_b) {
dc9d3b94 325 battery *bat;
251cfd3e
AG
326 if (g_source_is_destroyed(g_main_current_source()))
327 return FALSE;
52cb5b58 328 GDK_THREADS_ENTER();
c887dfa0
JH
329 lx_b->state_elapsed_time++;
330 lx_b->info_elapsed_time++;
71671bf6 331
dc9d3b94
HG
332 bat = battery_update( lx_b->b );
333 if (bat == NULL)
334 {
811afd8f 335 battery_free(lx_b->b);
dc9d3b94 336
811afd8f 337 /* maybe in the mean time a battery has been inserted. */
1c8a4455 338 lx_b->b = battery_get(lx_b->battery_number);
dc9d3b94 339 }
802d5540 340
c887dfa0 341 update_display( lx_b, TRUE );
802d5540 342
52cb5b58 343 GDK_THREADS_LEAVE();
7c2a8701 344 return TRUE;
52cb5b58 345}
8f11d5f8
HJYP
346
347/* An update will be performed whenever the user clicks on the charge bar */
813c2d44 348static gboolean buttonPressEvent(GtkWidget *p, GdkEventButton *event,
a7bd16a4 349 LXPanel *panel)
813c2d44
AG
350{
351 lx_battery *lx_b = lxpanel_plugin_get_data(p);
8f11d5f8 352
c887dfa0 353 update_display(lx_b, TRUE);
f50948df 354 /* FIXME: open some application for lid/power management may be? */
8f11d5f8 355
1639d6b3 356 return FALSE;
8f11d5f8
HJYP
357}
358
8f11d5f8 359static gint configureEvent(GtkWidget *widget, GdkEventConfigure *event,
175f73d1
AG
360 lx_battery *lx_b)
361{
362 GtkAllocation allocation;
8f11d5f8
HJYP
363
364 ENTER;
365
175f73d1 366 gtk_widget_get_allocation(widget, &allocation);
f50948df
AG
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
c887dfa0 373 if (lx_b->pixmap)
f176735a 374 cairo_surface_destroy(lx_b->pixmap);
8f11d5f8
HJYP
375
376 /* Update the plugin's dimensions */
175f73d1
AG
377 lx_b->width = allocation.width;
378 lx_b->height = allocation.height;
cfde283a 379 if (lx_b->orientation == GTK_ORIENTATION_HORIZONTAL) {
c887dfa0 380 lx_b->length = lx_b->height;
8f11d5f8
HJYP
381 }
382 else {
c887dfa0 383 lx_b->length = lx_b->width;
8f11d5f8
HJYP
384 }
385
175f73d1
AG
386 lx_b->pixmap = cairo_image_surface_create (CAIRO_FORMAT_RGB24, allocation.width,
387 allocation.height);
e4f8b15f 388 check_cairo_surface_status(&lx_b->pixmap);
8f11d5f8
HJYP
389
390 /* Perform an update so the bar will look right in its new orientation */
c887dfa0 391 update_display(lx_b, FALSE);
8f11d5f8 392
b0b2dcd7 393 /* we enforce border width here because panel sets it to 0 */
4ebd3285
AG
394 gtk_container_set_border_width(lx_b->box, lx_b->border);
395
8f11d5f8 396 RET(TRUE);
8f11d5f8
HJYP
397}
398
399
2a5577c3
BG
400#if GTK_CHECK_VERSION(3, 0, 0)
401static gint draw(GtkWidget *widget, cairo_t *cr, lx_battery *lx_b) {
402#else
c887dfa0 403static gint exposeEvent(GtkWidget *widget, GdkEventExpose *event, lx_battery *lx_b) {
2a5577c3 404#endif
8f11d5f8 405
e4f8b15f 406 ENTER;
d5b4b3fe
BG
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
175f73d1
AG
411 cairo_t *cr = gdk_cairo_create(gtk_widget_get_window(widget));
412 GtkStyle *style = gtk_widget_get_style(lx_b->drawingArea);
413
f176735a
RM
414 gdk_cairo_region(cr, event->region);
415 cairo_clip(cr);
8f11d5f8 416
175f73d1 417 gdk_cairo_set_source_color(cr, &style->black);
d5b4b3fe 418#endif
f176735a
RM
419 cairo_set_source_surface(cr, lx_b->pixmap, 0, 0);
420 cairo_paint(cr);
e4f8b15f
HG
421
422 check_cairo_status(cr);
d5b4b3fe 423#if !GTK_CHECK_VERSION(3, 0, 0)
f176735a 424 cairo_destroy(cr);
d5b4b3fe 425#endif
e751fe05 426
8f11d5f8 427 RET(FALSE);
8f11d5f8
HJYP
428}
429
4ebd3285
AG
430/* updates length, border, and height/width appropriate to orientation */
431static 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
8f11d5f8 442
a7bd16a4 443static GtkWidget * constructor(LXPanel *panel, config_setting_t *settings)
8f11d5f8 444{
8f11d5f8
HJYP
445 ENTER;
446
c887dfa0 447 lx_battery *lx_b;
813c2d44
AG
448 GtkWidget *p;
449 const char *str;
450 int tmp_int;
451
452 lx_b = g_new0(lx_battery, 1);
c887dfa0 453
1c8a4455
SKE
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);
813c2d44
AG
458
459 p = gtk_event_box_new();
460 lxpanel_plugin_set_data(p, lx_b, destructor);
09fa171b 461 gtk_widget_set_has_window(p, FALSE);
4542c20d 462
4ebd3285 463 lx_b->box = GTK_CONTAINER(p);
c887dfa0 464 lx_b->drawingArea = gtk_drawing_area_new();
cf07fc23 465 gtk_widget_add_events(lx_b->drawingArea, GDK_BUTTON_PRESS_MASK);
8f11d5f8 466
4ebd3285 467 gtk_container_add(lx_b->box, lx_b->drawingArea);
4542c20d 468
813c2d44 469 lx_b->orientation = panel_get_orientation(panel);
8f11d5f8 470
c887dfa0 471 gtk_widget_show(lx_b->drawingArea);
8f11d5f8 472
c887dfa0 473 sem_init(&(lx_b->alarmProcessLock), 0, 1);
8f11d5f8 474
c887dfa0
JH
475 lx_b->alarmCommand = lx_b->backgroundColor = lx_b->chargingColor1 = lx_b->chargingColor2
476 = lx_b->dischargingColor1 = lx_b->dischargingColor2 = NULL;
8f11d5f8
HJYP
477
478 /* Set default values for integers */
c887dfa0
JH
479 lx_b->alarmTime = 5;
480 lx_b->requestedBorder = 1;
4ebd3285 481 lx_b->thickness = 8;
8f11d5f8 482
813c2d44
AG
483 /* remember instance data */
484 lx_b->panel = panel;
485 lx_b->settings = settings;
8f11d5f8 486
06e29ce1 487 lx_b->show_extended_information = FALSE;
5c0c599d 488
6a1a639e
AG
489 if (config_setting_lookup_int(settings, "HideIfNoBattery", &tmp_int))
490 lx_b->hide_if_no_battery = (tmp_int != 0);
813c2d44
AG
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);
6a1a639e
AG
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))
4ebd3285
AG
506 lx_b->requestedBorder = CLAMP(tmp_int, 0, 6);
507 if (config_setting_lookup_int(settings, "Size", &tmp_int))
813c2d44 508 lx_b->thickness = MAX(1, tmp_int);
813c2d44
AG
509 if (config_setting_lookup_int(settings, "ShowExtendedInformation", &tmp_int))
510 lx_b->show_extended_information = (tmp_int != 0);
8f11d5f8
HJYP
511
512 /* Make sure the border value is acceptable */
4ebd3285
AG
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 }
4ebd3285
AG
524
525 g_signal_connect (G_OBJECT (lx_b->drawingArea),"configure-event",
526 G_CALLBACK (configureEvent), (gpointer) lx_b);
d5b4b3fe
BG
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
4ebd3285
AG
531 g_signal_connect (G_OBJECT (lx_b->drawingArea), "expose-event",
532 G_CALLBACK (exposeEvent), (gpointer) lx_b);
d5b4b3fe 533#endif
8f11d5f8
HJYP
534
535 /* Apply more default options */
c887dfa0 536 if (! lx_b->alarmCommand)
846b229d 537 lx_b->alarmCommand = g_strconcat("notify-send \"", _("Battery low"), "\" --icon=battery-caution", NULL);
c887dfa0
JH
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);
8f11d5f8
HJYP
554
555 /* Start the update loop */
13d82f29 556 lx_b->timer = g_timeout_add_seconds( 9, (GSourceFunc) update_timout, (gpointer) lx_b);
c887dfa0 557
813c2d44 558 RET(p);
8f11d5f8
HJYP
559}
560
561
562static void
813c2d44 563destructor(gpointer data)
8f11d5f8 564{
8f11d5f8
HJYP
565 ENTER;
566
813c2d44 567 lx_battery *b = (lx_battery *)data;
52cb5b58 568
029d9f0c 569 if (b->b != NULL)
811afd8f 570 battery_free(b->b);
029d9f0c 571
52cb5b58 572 if (b->pixmap)
f176735a 573 cairo_surface_destroy(b->pixmap);
8f11d5f8 574
8f11d5f8
HJYP
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);
802d5540 581
8f11d5f8 582 g_free(b->rateSamples);
8f11d5f8 583 sem_destroy(&(b->alarmProcessLock));
3396dfea 584 if (b->timer)
585 g_source_remove(b->timer);
8f11d5f8
HJYP
586 g_free(b);
587
588 RET();
589
590}
591
592
a7bd16a4 593static void orientation(LXPanel *panel, GtkWidget *p) {
8f11d5f8
HJYP
594
595 ENTER;
596
813c2d44 597 lx_battery *b = lxpanel_plugin_get_data(p);
8f11d5f8 598
813c2d44
AG
599 if (b->orientation != panel_get_orientation(panel)) {
600 b->orientation = panel_get_orientation(panel);
4ebd3285
AG
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 }
8f11d5f8
HJYP
612 }
613
614 RET();
615}
616
617
813c2d44 618static gboolean applyConfig(gpointer user_data)
8f11d5f8 619{
8f11d5f8
HJYP
620 ENTER;
621
813c2d44 622 lx_battery *b = lxpanel_plugin_get_data(user_data);
8f11d5f8 623
1c8a4455
SKE
624 /* Update the battery we monitor */
625 battery_free(b->b);
626 b->b = battery_get(b->battery_number);
627
8f11d5f8
HJYP
628 /* Update colors */
629 if (b->backgroundColor &&
813c2d44
AG
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);
8f11d5f8 636 if (b->dischargingColor1 &&
813c2d44
AG
637 gdk_color_parse(b->dischargingColor1, &b->discharging1))
638 config_group_set_string(b->settings, "DischargingColor1", b->dischargingColor1);
8f11d5f8 639 if (b->dischargingColor2 &&
813c2d44
AG
640 gdk_color_parse(b->dischargingColor2, &b->discharging2))
641 config_group_set_string(b->settings, "DischargingColor2", b->dischargingColor2);
8f11d5f8 642
7538019a
AG
643 /* Make sure it is at least 1 px */
644 if (b->thickness < 1)
645 b->thickness = 1;
646
e751fe05 647 /* Make sure the border value is acceptable */
4ebd3285
AG
648 b->requestedBorder = MIN(b->requestedBorder, 6);
649 updateSizes(b);
8f11d5f8 650
8f11d5f8 651 /* Resize the widget */
4ebd3285 652 gtk_container_set_border_width(b->box, b->border);
cfde283a 653 if (b->orientation == GTK_ORIENTATION_HORIZONTAL)
4ebd3285 654 {
8f11d5f8 655 b->width = b->thickness;
4ebd3285
AG
656 gtk_widget_set_size_request(b->drawingArea, b->width, -1);
657 }
8f11d5f8 658 else
4ebd3285 659 {
8f11d5f8 660 b->height = b->thickness;
4ebd3285
AG
661 gtk_widget_set_size_request(b->drawingArea, -1, b->height);
662 }
f50948df
AG
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);
8f11d5f8 668
2bbdeeca
AG
669 if (b->alarmCommand == NULL)
670 b->alarmCommand = g_strconcat("xmessage ", _("Battery low"), NULL);
671
5c0c599d
HG
672 /* update tooltip */
673 set_tooltip_text(b);
674
813c2d44 675 /* update settings */
813c2d44 676 config_group_set_int(b->settings, "HideIfNoBattery", b->hide_if_no_battery);
813c2d44
AG
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);
1c8a4455 683 config_group_set_int(b->settings, "BatteryNumber", b->battery_number);
813c2d44 684
0c7311d2
HG
685 update_display(b, TRUE);
686
6a1a639e 687 RET(FALSE);
8f11d5f8
HJYP
688}
689
690
752ee4e2 691static GtkWidget *config(LXPanel *panel, GtkWidget *p) {
813c2d44 692 lx_battery *b = lxpanel_plugin_get_data(p);
131514c9 693 return lxpanel_generic_config_dlg(_("Battery Monitor"),
813c2d44 694 panel, applyConfig, p,
e2957bd2 695 _("Hide if there is no battery"), &b->hide_if_no_battery, CONF_TYPE_BOOL,
e2957bd2
HJYP
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,
f1591a0f
AG
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,
5c0c599d 707 _("Show Extended Information"), &b->show_extended_information, CONF_TYPE_BOOL,
1c8a4455 708 _("Number of battery to monitor"), &b->battery_number, CONF_TYPE_INT,
8f11d5f8 709 NULL);
8f11d5f8
HJYP
710}
711
712
813c2d44 713FM_DEFINE_MODULE(lxpanel_gtk, batt)
8f11d5f8 714
813c2d44
AG
715/* Plugin descriptor. */
716LXPanelPluginInit fm_module_init_lxpanel_gtk = {
3c3e9c9e 717 .name = N_("Battery Monitor"),
3c3e9c9e
HG
718 .description = N_("Display battery status using ACPI"),
719
813c2d44 720 .new_instance = constructor,
3c3e9c9e 721 .config = config,
813c2d44
AG
722 .reconfigure = orientation,
723 .button_press_event = buttonPressEvent
8f11d5f8 724};
f855ac58
HG
725
726
727/* vim: set sw=4 sts=4 : */