diff --git a/CMakeLists.txt b/CMakeLists.txt index dad7d9d..e2d1574 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -78,7 +78,20 @@ set( SOURCES src/config.c src/util/window.c ) if( ENABLE_BATTERY ) - set( SOURCES ${SOURCES} src/battery/battery.c src/battery/linux.c) + set( SOURCES ${SOURCES} src/battery/battery.c) + + if(CMAKE_SYSTEM_NAME STREQUAL "Linux") + set( SOURCES ${SOURCES} src/battery/linux.c) + elseif(CMAKE_SYSTEM_NAME STREQUAL "FreeBSD") + set( SOURCES ${SOURCES} src/battery/freebsd.c) + elseif(CMAKE_SYSTEM_NAME STREQUAL "OpenBSD") + set( SOURCES ${SOURCES} src/battery/openbsd.c) + elseif(CMAKE_SYSTEM_NAME STREQUAL "NetBSD") + set( SOURCES ${SOURCES} src/battery/openbsd.c) + else(CMAKE_SYSTEM_NAME STREQUAL "Linux") + set( SOURCES ${SOURCES} src/battery/dummy.c) + endif(CMAKE_SYSTEM_NAME STREQUAL "Linux") + add_definitions( -DENABLE_BATTERY ) endif( ENABLE_BATTERY ) diff --git a/src/battery/battery.c b/src/battery/battery.c index add8327..058eab2 100644 --- a/src/battery/battery.c +++ b/src/battery/battery.c @@ -1,6 +1,6 @@ /************************************************************************** * -* Tint2 : battery +* Tint2 : Generic battery * * Copyright (C) 2009-2015 Sebastian Reichel * @@ -24,18 +24,6 @@ #include #include -#if defined(__OpenBSD__) || defined(__NetBSD__) -#include -#include -#include -#include -#endif - -#if defined(__FreeBSD__) -#include -#include -#endif - #include "window.h" #include "server.h" #include "panel.h" @@ -56,6 +44,8 @@ static char buf_bat_time[20]; int8_t battery_low_status; unsigned char battery_low_cmd_sent; +char *ac_connected_cmd; +char *ac_disconnected_cmd; char *battery_low_cmd; char *battery_lclick_command; char *battery_mclick_command; @@ -64,10 +54,6 @@ char *battery_uwheel_command; char *battery_dwheel_command; int battery_found; -#if defined(__OpenBSD__) || defined(__NetBSD__) -int apm_fd; -#endif - void update_battery_tick(void* arg) { if (!battery_enabled) @@ -75,6 +61,7 @@ void update_battery_tick(void* arg) int old_found = battery_found; int old_percentage = battery_state.percentage; + int old_ac_connected = battery_state.ac_connected; int16_t old_hours = battery_state.time.hours; int8_t old_minutes = battery_state.time.minutes; @@ -87,6 +74,14 @@ void update_battery_tick(void* arg) // Try again update_battery(); } + + if (old_ac_connected != battery_state.ac_connected) { + if(battery_state.ac_connected) + tint_exec(ac_connected_cmd); + else + tint_exec(ac_disconnected_cmd); + } + if (old_found == battery_found && old_percentage == battery_state.percentage && old_hours == battery_state.time.hours && @@ -154,9 +149,6 @@ void default_battery() battery_state.time.minutes = 0; battery_state.time.seconds = 0; battery_state.state = BATTERY_UNKNOWN; -#if defined(__OpenBSD__) || defined(__NetBSD__) - apm_fd = -1; -#endif } void cleanup_battery() @@ -181,51 +173,22 @@ void cleanup_battery() battery_timeout = NULL; battery_found = 0; -#if defined(__OpenBSD__) || defined(__NetBSD__) - if ((apm_fd != -1) && (close(apm_fd) == -1)) - warn("cannot close /dev/apm"); - apm_fd = -1; -#elif defined(__linux) - free_linux_batteries(); -#endif + battery_os_free(); } void init_battery() { if (!battery_enabled) return; - battery_found = 0; -#if defined(__OpenBSD__) || defined(__NetBSD__) - if (apm_fd > 0) - close(apm_fd); - apm_fd = open("/dev/apm", O_RDONLY); - if (apm_fd < 0) { - warn("ERROR: battery applet cannot open /dev/apm."); - battery_found = 0; - } else { - battery_found = 1; - } -#elif defined(__FreeBSD__) - int sysctl_out = 0; - size_t len = sizeof(sysctl_out); - battery_found = (sysctlbyname("hw.acpi.battery.state", &sysctl_out, &len, NULL, 0) == 0) || - (sysctlbyname("hw.acpi.battery.time", &sysctl_out, &len, NULL, 0) == 0) || - (sysctlbyname("hw.acpi.battery.life", &sysctl_out, &len, NULL, 0) == 0); -#elif defined(__linux) - battery_found = init_linux_batteries(); -#endif + battery_found = battery_os_init(); if (!battery_timeout) battery_timeout = add_timeout(10, 30000, update_battery_tick, 0, &battery_timeout); } -const char* battery_get_tooltip(void* obj) { -#if defined(__linux) - return linux_batteries_get_tooltip(); -#else - return g_strdup("No tooltip support for this OS!"); -#endif +char* battery_get_tooltip(void* obj) { + return battery_os_tooltip(); } void init_battery_panel(void *p) @@ -258,105 +221,22 @@ void init_battery_panel(void *p) int update_battery() { - int64_t energy_now = 0, - energy_full = 0; - int seconds = 0; - int8_t new_percentage = 0; - int errors = 0; + int err; + /* reset */ battery_state.state = BATTERY_UNKNOWN; + battery_state.percentage = 0; + battery_state.ac_connected = FALSE; + batstate_set_time(&battery_state, 0); -#if defined(__OpenBSD__) || defined(__NetBSD__) - struct apm_power_info info; - if (apm_fd > 0 && ioctl(apm_fd, APM_IOC_GETPOWER, &(info)) == 0) { - // best attempt at mapping to Linux battery states - switch (info.battery_state) { - case APM_BATT_CHARGING: - battery_state.state = BATTERY_CHARGING; - break; - default: - battery_state.state = BATTERY_DISCHARGING; - break; - } - - if (info.battery_life == 100) - battery_state.state = BATTERY_FULL; - - // no mapping for openbsd really - energy_full = 0; - energy_now = 0; - - if (info.minutes_left != -1) - seconds = info.minutes_left * 60; - else - seconds = -1; - - new_percentage = info.battery_life; - } else { - warn("power update: APM_IOC_GETPOWER"); - errors = 1; - } -#elif defined(__FreeBSD__) - int sysctl_out = 0; - size_t len = sizeof(sysctl_out); - - if (sysctlbyname("hw.acpi.battery.state", &sysctl_out, &len, NULL, 0) == 0) { - // attemp to map the battery state to Linux - battery_state.state = BATTERY_UNKNOWN; - switch(sysctl_out) { - case 1: - battery_state.state = BATTERY_DISCHARGING; - break; - case 2: - battery_state.state = BATTERY_CHARGING; - break; - default: - battery_state.state = BATTERY_FULL; - break; - } - } else { - fprintf(stderr, "power update: no such sysctl"); - errors = 1; - } - - // no mapping for freebsd - energy_full = 0; - energy_now = 0; - - if (sysctlbyname("hw.acpi.battery.time", &sysctl_out, &len, NULL, 0) != 0) - seconds = -1; - else - seconds = sysctl_out * 60; - - // charging or error - if (seconds < 0) - seconds = 0; - - if (sysctlbyname("hw.acpi.battery.life", &sysctl_out, &len, NULL, 0) != 0) - new_percentage = -1; - else - new_percentage = sysctl_out; -#else - update_linux_batteries(&battery_state.state, &energy_now, &energy_full, &seconds); -#endif - - battery_state.time.hours = seconds / 3600; - seconds -= 3600 * battery_state.time.hours; - battery_state.time.minutes = seconds / 60; - seconds -= 60 * battery_state.time.minutes; - battery_state.time.seconds = seconds; - - if (energy_full > 0) - new_percentage = 0.5 + ((energy_now <= energy_full ? energy_now : energy_full) * 100.0) / energy_full; - - battery_state.percentage = new_percentage; + err = battery_os_update(&battery_state); // clamp percentage to 100 in case battery is misreporting that its current charge is more than its max if (battery_state.percentage > 100) { battery_state.percentage = 100; } - return errors; + return err; } diff --git a/src/battery/battery.h b/src/battery/battery.h index 390661e..8142760 100644 --- a/src/battery/battery.h +++ b/src/battery/battery.h @@ -44,6 +44,7 @@ typedef struct batstate { int percentage; struct battime time; enum chargestate state; + gboolean ac_connected; } batstate; extern struct batstate battery_state; @@ -56,6 +57,9 @@ extern int percentage_hide; extern int8_t battery_low_status; extern char *battery_low_cmd; +extern char *ac_connected_cmd; +extern char *ac_disconnected_cmd; + extern char *battery_lclick_command; extern char *battery_mclick_command; extern char *battery_rclick_command; @@ -76,6 +80,14 @@ static inline gchar* chargestate2str(enum chargestate state) { }; } +static inline void batstate_set_time(struct batstate *state, int seconds) { + state->time.hours = seconds / 3600; + seconds -= 3600 * state->time.hours; + state->time.minutes = seconds / 60; + seconds -= 60 * state->time.minutes; + state->time.seconds = seconds; +} + // default global data void default_battery(); @@ -93,11 +105,10 @@ int resize_battery(void *obj); void battery_action(int button); -#ifdef __linux -gboolean init_linux_batteries(); -void free_linux_batteries(); -void update_linux_batteries(enum chargestate *state, gint64 *energy_now, gint64 *energy_full, int *seconds); -const char* linux_batteries_get_tooltip(); -#endif +/* operating system specific functions */ +gboolean battery_os_init(); +void battery_os_free(); +int battery_os_update(struct batstate *state); +char* battery_os_tooltip(); #endif diff --git a/src/battery/dummy.c b/src/battery/dummy.c new file mode 100644 index 0000000..1639692 --- /dev/null +++ b/src/battery/dummy.c @@ -0,0 +1,40 @@ +/************************************************************************** +* +* Tint2 : Dummy battery (non-functional) +* +* Copyright (C) 2015 Sebastian Reichel +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License version 2 +* or any later version as published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +**************************************************************************/ + +#include +#include "common.h" +#include "battery.h" + +#warning tint2 has no battery support for this operating system! + +gboolean battery_os_init() { + return FALSE; +} + +void battery_os_free() { + return; +} + +int battery_os_update(struct batstate *state) { + return -1; +} + +char* battery_os_tooltip() { + return strdup("Operating System not supported"); +} diff --git a/src/battery/freebsd.c b/src/battery/freebsd.c new file mode 100644 index 0000000..0bdf665 --- /dev/null +++ b/src/battery/freebsd.c @@ -0,0 +1,79 @@ +/************************************************************************** +* +* Tint2 : FreeBSD battery +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License version 2 +* or any later version as published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +**************************************************************************/ + +#if defined(__FreeBSD__) + +#include +#include +#include + +#include "common.h" +#include "battery.h" + +gboolean battery_os_init() { + int sysctl_out = 0; + size_t len = sizeof(sysctl_out); + + return (sysctlbyname("hw.acpi.battery.state", &sysctl_out, &len, NULL, 0) == 0) || + (sysctlbyname("hw.acpi.battery.time", &sysctl_out, &len, NULL, 0) == 0) || + (sysctlbyname("hw.acpi.battery.life", &sysctl_out, &len, NULL, 0) == 0); +} + +void battery_os_free() { + return; +} + +int battery_os_update(struct batstate *state) { + int sysctl_out = 0; + size_t len = sizeof(sysctl_out); + gboolean err = 0; + + if (sysctlbyname("hw.acpi.battery.state", &sysctl_out, &len, NULL, 0) == 0) { + switch(sysctl_out) { + case 1: + state->state = BATTERY_DISCHARGING; + break; + case 2: + state->state = BATTERY_CHARGING; + break; + default: + state->state = BATTERY_FULL; + break; + } + } else { + fprintf(stderr, "power update: no such sysctl"); + err = -1; + } + + if (sysctlbyname("hw.acpi.battery.time", &sysctl_out, &len, NULL, 0) == 0) + batstate_set_time(state, sysctl_out * 60); + else + err = -1; + + if (sysctlbyname("hw.acpi.battery.life", &sysctl_out, &len, NULL, 0) == 0) + state->percentage = sysctl_out; + else + err = -1; + + return err; +} + +char* battery_os_tooltip() { + return strdup("Operating System not supported"); +} + +#endif diff --git a/src/battery/linux.c b/src/battery/linux.c index 7054827..f2ba53e 100644 --- a/src/battery/linux.c +++ b/src/battery/linux.c @@ -24,6 +24,12 @@ #include "common.h" #include "battery.h" +enum psy_type { + PSY_UNKNOWN, + PSY_BATTERY, + PSY_MAINS, +}; + struct psy_battery { /* generic properties */ gchar* name; @@ -44,11 +50,25 @@ struct psy_battery { enum chargestate status; }; +struct psy_mains { + /* generic properties */ + gchar* name; + /* sysfs files */ + gchar* path_online; + /* values */ + gboolean online; +}; + #define RETURN_ON_ERROR(err) if(error) { g_error_free(err); return FALSE; } static GList *batteries = NULL; +static GList *mains = NULL; -static gboolean power_supply_is_battery(const gchar *entryname) { +static guint8 energy_to_percent(gint energy_now, gint energy_full) { + return 0.5 + ((energy_now <= energy_full ? energy_now : energy_full) * 100.0) / energy_full; +} + +static enum psy_type power_supply_get_type(const gchar *entryname) { gchar *path_type = g_build_filename("/sys/class/power_supply", entryname, "type", NULL); GError *error = NULL; gchar *type; @@ -56,16 +76,24 @@ static gboolean power_supply_is_battery(const gchar *entryname) { g_file_get_contents(path_type, &type, &typelen, &error); g_free(path_type); - RETURN_ON_ERROR(error); + if (error) { + g_error_free(error); + return PSY_UNKNOWN; + } - if(g_strcmp0(type, "Battery\n")) { + if(!g_strcmp0(type, "Battery\n")) { g_free(type); - return FALSE; + return PSY_BATTERY; + } + + if(!g_strcmp0(type, "Mains\n")) { + g_free(type); + return PSY_MAINS; } g_free(type); - return TRUE; + return PSY_UNKNOWN; } static gboolean init_linux_battery(struct psy_battery *bat) { @@ -130,7 +158,19 @@ err0: return FALSE; } -void free_linux_batteries() { +static gboolean init_linux_mains(struct psy_mains *ac) { + const gchar *entryname = ac->name; + + ac->path_online = g_build_filename("/sys/class/power_supply", entryname, "online", NULL); + if (!g_file_test(ac->path_online, G_FILE_TEST_EXISTS)) { + g_free(ac->path_online); + return FALSE; + } + + return TRUE; +} + +void battery_os_free() { GList *l = batteries; while (l != NULL) { @@ -148,31 +188,70 @@ void free_linux_batteries() { l = next; } + l = mains; + while (l != NULL) { + GList *next = l->next; + struct psy_mains *ac = l->data; + + g_free(ac->name); + g_free(ac->path_online); + + mains = g_list_delete_link(mains, l); + l = next; + } + batteries = NULL; + mains = NULL; } -gboolean init_linux_batteries() { +static void add_battery(const char *entryname) { + struct psy_battery *bat = g_malloc0(sizeof(*bat)); + bat->name = g_strdup(entryname); + + if(init_linux_battery(bat)) { + batteries = g_list_append(batteries, bat); + fprintf(stdout, "found battery \"%s\"\n", bat->name); + } else { + g_free(bat); + fprintf(stderr, RED "failed to initialize battery \"%s\"\n" RESET, entryname); + } +} + +static void add_mains(const char *entryname) { + struct psy_mains *ac = g_malloc0(sizeof(*ac)); + ac->name = g_strdup(entryname); + + if(init_linux_mains(ac)) { + mains = g_list_append(mains, ac); + fprintf(stdout, "found mains \"%s\"\n", ac->name); + } else { + g_free(ac); + fprintf(stderr, RED "failed to initialize mains \"%s\"\n" RESET, entryname); + } +} + +gboolean battery_os_init() { GDir *directory = 0; GError *error = NULL; const char *entryname; - free_linux_batteries(); + battery_os_free(); directory = g_dir_open("/sys/class/power_supply", 0, &error); RETURN_ON_ERROR(error); while ((entryname = g_dir_read_name(directory))) { - if(!power_supply_is_battery(entryname)) - continue; + enum psy_type type = power_supply_get_type(entryname); - struct psy_battery *bat = g_malloc0(sizeof(*bat)); - bat->name = g_strdup(entryname); - if(init_linux_battery(bat)) { - batteries = g_list_append(batteries, bat); - fprintf(stdout, "found battery \"%s\"\n", bat->name); - } else { - g_free(bat); - fprintf(stderr, RED "failed to initialize battery \"%s\"\n" RESET, entryname); + switch(type) { + case PSY_BATTERY: + add_battery(entryname); + break; + case PSY_MAINS: + add_mains(entryname); + break; + default: + break; } } @@ -237,16 +316,34 @@ static gboolean update_linux_battery(struct psy_battery *bat) { return TRUE; } -void update_linux_batteries(enum chargestate *state, gint64 *energy_now, gint64 *energy_full, int *seconds) { + +static gboolean update_linux_mains(struct psy_mains *ac) { + GError *error = NULL; + gchar *data; + gsize datalen; + ac->online = FALSE; + + /* online */ + g_file_get_contents(ac->path_online, &data, &datalen, &error); + RETURN_ON_ERROR(error); + ac->online = (atoi(data) == 1); + g_free(data); + + return TRUE; +} + +int battery_os_update(struct batstate *state) { GList *l; gint64 total_energy_now = 0; gint64 total_energy_full = 0; gint64 total_power_now = 0; + gint seconds = 0; gboolean charging = FALSE; gboolean discharging = FALSE; gboolean full = FALSE; + gboolean ac_connected = FALSE; for (l = batteries; l != NULL; l = l->next) { struct psy_battery *bat = l->data; @@ -261,27 +358,36 @@ void update_linux_batteries(enum chargestate *state, gint64 *energy_now, gint64 full |= (bat->status == BATTERY_FULL); } - /* global energy stats */ - *energy_now = total_energy_now; - *energy_full = total_energy_full; + for (l = mains; l != NULL; l = l->next) { + struct psy_mains *ac = l->data; + update_linux_mains(ac); + ac_connected |= (ac->online); + } /* build global state */ - *state = BATTERY_UNKNOWN; if (charging && !discharging) - *state = BATTERY_CHARGING; + state->state = BATTERY_CHARGING; else if (!charging && discharging) - *state = BATTERY_DISCHARGING; + state->state = BATTERY_DISCHARGING; else if (!charging && !discharging && full) - *state = BATTERY_FULL; + state->state = BATTERY_FULL; /* calculate seconds */ - *seconds = 0; if (total_power_now > 0) { - if(*state == BATTERY_CHARGING) - *seconds = 3600 * (total_energy_full - total_energy_now) / total_power_now; - else if(*state == BATTERY_DISCHARGING) - *seconds = 3600 * total_energy_now / total_power_now; + if(state->state == BATTERY_CHARGING) + seconds = 3600 * (total_energy_full - total_energy_now) / total_power_now; + else if(state->state == BATTERY_DISCHARGING) + seconds = 3600 * total_energy_now / total_power_now; } + batstate_set_time(state, seconds); + + /* calculate percentage */ + state->percentage = energy_to_percent(total_energy_now, total_energy_full); + + /* AC state */ + state->ac_connected = ac_connected; + + return 0; } static gchar* energy_human_readable(struct psy_battery *bat) { @@ -319,7 +425,7 @@ static gchar* power_human_readable(struct psy_battery *bat) { } } -const char* linux_batteries_get_tooltip() { +char* battery_os_tooltip() { GList *l; GString *tooltip = g_string_new(""); gchar *result; @@ -341,7 +447,7 @@ const char* linux_batteries_get_tooltip() { gchar *energy = energy_human_readable(bat); gchar *state = (bat->status == BATTERY_UNKNOWN) ? "Level" : chargestate2str(bat->status); - guint percentage = 0.5 + ((bat->energy_now <= bat->energy_full ? bat->energy_now : bat->energy_full) * 100.0) / bat->energy_full; + guint8 percentage = energy_to_percent(bat->energy_now, bat->energy_full); g_string_append_printf(tooltip, "\t%s: %s (%u %%)\n\tPower: %s", state, energy, percentage, power); @@ -350,6 +456,16 @@ const char* linux_batteries_get_tooltip() { g_free(energy); } + for (l = mains; l != NULL; l = l->next) { + struct psy_mains *ac = l->data; + + if (tooltip->len) + g_string_append_c(tooltip, '\n'); + + g_string_append_printf(tooltip, "%s\n", ac->name); + g_string_append_printf(tooltip, ac->online ? "\tconnected" : "\tdisconnected"); + } + result = tooltip->str; g_string_free(tooltip, FALSE); diff --git a/src/battery/openbsd.c b/src/battery/openbsd.c new file mode 100644 index 0000000..75d2381 --- /dev/null +++ b/src/battery/openbsd.c @@ -0,0 +1,84 @@ +/************************************************************************** +* +* Tint2 : OpenBSD & NetBSD battery +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License version 2 +* or any later version as published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +**************************************************************************/ + +#if defined(__OpenBSD__) || defined(__NetBSD__) + +//#include +#include +#include +#include +#include + +#include "common.h" +#include "battery.h" + +int apm_fd = -1; + +gboolean battery_os_init() { + if (apm_fd > 0) + close(apm_fd); + + apm_fd = open("/dev/apm", O_RDONLY); + + if (apm_fd < 0) { + warn("ERROR: battery applet cannot open /dev/apm."); + return FALSE; + } else { + return TRUE; + } +} + +void battery_os_free() { + if ((apm_fd != -1) && (close(apm_fd) == -1)) + warn("cannot close /dev/apm"); + apm_fd = -1; +} + +int battery_os_update(struct batstate *state) { + struct apm_power_info info; + + if (apm_fd > 0 && ioctl(apm_fd, APM_IOC_GETPOWER, &(info)) == 0) { + // best attempt at mapping to Linux battery states + switch (info.battery_state) { + case APM_BATT_CHARGING: + state->state = BATTERY_CHARGING; + break; + default: + state->state = BATTERY_DISCHARGING; + break; + } + + if (info.battery_life == 100) + state->state = BATTERY_FULL; + + if (info.minutes_left != -1) + batstate_set_time(state, info.minutes_left * 60); + + state->percentage = info.battery_life; + } else { + warn("power update: APM_IOC_GETPOWER"); + return -1; + } + + return 0; +} + +char* battery_os_tooltip() { + return strdup("Operating System not supported"); +} + +#endif diff --git a/src/clock/clock.c b/src/clock/clock.c index f5dab27..e6805fe 100644 --- a/src/clock/clock.c +++ b/src/clock/clock.c @@ -48,7 +48,6 @@ PangoFontDescription *time1_font_desc; PangoFontDescription *time2_font_desc; static char buf_time[256]; static char buf_date[256]; -static char buf_tooltip[512]; int clock_enabled; static timeout* clock_timeout; @@ -144,10 +143,15 @@ struct tm* clock_gettime_for_tz(const char* timezone) { else return localtime(&time_clock.tv_sec); } -const char* clock_get_tooltip(void* obj) +char* clock_get_tooltip(void* obj) { - strftime(buf_tooltip, sizeof(buf_tooltip), time_tooltip_format, clock_gettime_for_tz(time_tooltip_timezone)); - return buf_tooltip; + GTimeZone *tz = g_time_zone_new(time_tooltip_timezone); + GDateTime *now = g_date_time_new_now(tz); + char *result = g_date_time_format(now, time_tooltip_format); + g_date_time_unref(now); + g_time_zone_unref(tz); + + return result; } int time_format_needs_sec_ticks(char *time_format) @@ -197,7 +201,6 @@ void init_clock_panel(void *p) if (time_tooltip_format) { clock->area._get_tooltip_text = clock_get_tooltip; - strftime(buf_tooltip, sizeof(buf_tooltip), time_tooltip_format, clock_gettime_for_tz(time_tooltip_timezone)); } } diff --git a/src/config.c b/src/config.c index 378e2b6..9a8c625 100644 --- a/src/config.c +++ b/src/config.c @@ -392,6 +392,18 @@ void add_entry (char *key, char *value) #ifdef ENABLE_BATTERY if (strlen(value) > 0) battery_low_cmd = strdup (value); +#endif + } + else if (strcmp (key, "ac_connected_cmd") == 0) { +#ifdef ENABLE_BATTERY + if (strlen(value) > 0) + ac_connected_cmd = strdup (value); +#endif + } + else if (strcmp (key, "ac_disconnected_cmd") == 0) { +#ifdef ENABLE_BATTERY + if (strlen(value) > 0) + ac_disconnected_cmd = strdup (value); #endif } else if (strcmp (key, "bat1_font") == 0) { diff --git a/src/launcher/launcher.c b/src/launcher/launcher.c index f0aaed0..2a637f1 100644 --- a/src/launcher/launcher.c +++ b/src/launcher/launcher.c @@ -347,10 +347,10 @@ void launcher_icon_on_change_layout(void *obj) launcherIcon->area.height = launcherIcon->icon_size; } -const char* launcher_icon_get_tooltip_text(void *obj) +char* launcher_icon_get_tooltip_text(void *obj) { LauncherIcon *launcherIcon = (LauncherIcon*)obj; - return launcherIcon->icon_tooltip; + return strdup(launcherIcon->icon_tooltip); } void draw_launcher_icon(void *obj, cairo_t *c) diff --git a/src/taskbar/task.c b/src/taskbar/task.c index aa9804a..a216d90 100644 --- a/src/taskbar/task.c +++ b/src/taskbar/task.c @@ -38,10 +38,10 @@ timeout* urgent_timeout; GSList* urgent_list; -const char* task_get_tooltip(void* obj) +char* task_get_tooltip(void* obj) { Task* t = obj; - return t->title; + return strdup(t->title); } diff --git a/src/tint2conf/properties.c b/src/tint2conf/properties.c index a4eec73..019a333 100644 --- a/src/tint2conf/properties.c +++ b/src/tint2conf/properties.c @@ -94,6 +94,7 @@ GtkWidget *battery_padding_x, *battery_padding_y, *battery_font_line1, *battery_ GtkWidget *battery_background; GtkWidget *battery_tooltip; GtkWidget *battery_left_command, *battery_mclick_command, *battery_right_command, *battery_uwheel_command, *battery_dwheel_command; +GtkWidget *ac_connected_cmd, *ac_disconnected_cmd; // systray GtkWidget *systray_icon_order, *systray_padding_x, *systray_padding_y, *systray_spacing; @@ -3817,6 +3818,50 @@ void create_battery(GtkWidget *parent) change_paragraph(parent); + label = gtk_label_new(_("AC connection events")); + gtk_misc_set_alignment(GTK_MISC(label), 0, 0); + gtk_label_set_use_markup(GTK_LABEL(label), TRUE); + gtk_widget_show(label); + gtk_box_pack_start(GTK_BOX(parent), label, FALSE, FALSE, 0); + + table = gtk_table_new(2, 10, FALSE); + gtk_widget_show(table); + gtk_box_pack_start(GTK_BOX(parent), table, FALSE, FALSE, 0); + gtk_table_set_row_spacings(GTK_TABLE(table), ROW_SPACING); + gtk_table_set_col_spacings(GTK_TABLE(table), COL_SPACING); + + row = 0, col = 2; + label = gtk_label_new(_("AC connected command")); + gtk_misc_set_alignment(GTK_MISC(label), 0, 0); + gtk_widget_show(label); + gtk_table_attach(GTK_TABLE(table), label, col, col+1, row, row+1, GTK_FILL, 0, 0, 0); + col++; + + ac_connected_cmd = gtk_entry_new(); + gtk_widget_show(ac_connected_cmd); + gtk_entry_set_width_chars(GTK_ENTRY(ac_connected_cmd), 50); + gtk_table_attach(GTK_TABLE(table), ac_connected_cmd, col, col+1, row, row+1, GTK_FILL, 0, 0, 0); + col++; + gtk_tooltips_set_tip(tooltips, ac_connected_cmd, + _("Specifies a command that will be executed when AC is connected to the system."), NULL); + + row++, col = 2; + label = gtk_label_new(_("AC disconnected command")); + gtk_misc_set_alignment(GTK_MISC(label), 0, 0); + gtk_widget_show(label); + gtk_table_attach(GTK_TABLE(table), label, col, col+1, row, row+1, GTK_FILL, 0, 0, 0); + col++; + + ac_disconnected_cmd = gtk_entry_new(); + gtk_widget_show(ac_disconnected_cmd); + gtk_entry_set_width_chars(GTK_ENTRY(ac_disconnected_cmd), 50); + gtk_table_attach(GTK_TABLE(table), ac_disconnected_cmd, col, col+1, row, row+1, GTK_FILL, 0, 0, 0); + col++; + gtk_tooltips_set_tip(tooltips, ac_disconnected_cmd, + _("Specifies a command that will be executed when AC is disconnected to the system."), NULL); + + change_paragraph(parent); + label = gtk_label_new(_("Mouse events")); gtk_misc_set_alignment(GTK_MISC(label), 0, 0); gtk_label_set_use_markup(GTK_LABEL(label), TRUE); diff --git a/src/tint2conf/properties.h b/src/tint2conf/properties.h index 00a94b5..c61821a 100644 --- a/src/tint2conf/properties.h +++ b/src/tint2conf/properties.h @@ -97,6 +97,7 @@ extern GtkWidget *battery_padding_x, *battery_padding_y, *battery_font_line1, *b extern GtkWidget *battery_background; extern GtkWidget *battery_tooltip; extern GtkWidget *battery_left_command, *battery_mclick_command, *battery_right_command, *battery_uwheel_command, *battery_dwheel_command; +extern GtkWidget *ac_connected_cmd, *ac_disconnected_cmd; // systray extern GtkWidget *systray_icon_order, *systray_padding_x, *systray_padding_y, *systray_spacing; diff --git a/src/tint2conf/properties_rw.c b/src/tint2conf/properties_rw.c index 7f3affd..996297a 100644 --- a/src/tint2conf/properties_rw.c +++ b/src/tint2conf/properties_rw.c @@ -583,6 +583,9 @@ void config_write_battery(FILE *fp) fprintf(fp, "battery_uwheel_command = %s\n", gtk_entry_get_text(GTK_ENTRY(battery_uwheel_command))); fprintf(fp, "battery_dwheel_command = %s\n", gtk_entry_get_text(GTK_ENTRY(battery_dwheel_command))); + fprintf(fp, "ac_connected_cmd = %s\n", gtk_entry_get_text(GTK_ENTRY(ac_connected_cmd))); + fprintf(fp, "ac_disconnected_cmd = %s\n", gtk_entry_get_text(GTK_ENTRY(ac_disconnected_cmd))); + fprintf(fp, "\n"); } @@ -958,6 +961,12 @@ void add_entry(char *key, char *value) else if (strcmp(key, "battery_dwheel_command") == 0) { gtk_entry_set_text(GTK_ENTRY(battery_dwheel_command), value); } + else if (strcmp(key, "ac_connected_cmd") == 0) { + gtk_entry_set_text(GTK_ENTRY(ac_connected_cmd), value); + } + else if (strcmp(key, "ac_disconnected_cmd") == 0) { + gtk_entry_set_text(GTK_ENTRY(ac_disconnected_cmd), value); + } /* Clock */ else if (strcmp(key, "time1_format") == 0) { diff --git a/src/tooltip/tooltip.c b/src/tooltip/tooltip.c index f438162..ee5c30a 100644 --- a/src/tooltip/tooltip.c +++ b/src/tooltip/tooltip.c @@ -304,7 +304,7 @@ void tooltip_copy_text(Area* area) { free(g_tooltip.tooltip_text); if (area && area->_get_tooltip_text) - g_tooltip.tooltip_text = strdup(area->_get_tooltip_text(area)); + g_tooltip.tooltip_text = area->_get_tooltip_text(area); else g_tooltip.tooltip_text = NULL; g_tooltip.area = area; diff --git a/src/util/area.h b/src/util/area.h index 1907586..898a7d3 100644 --- a/src/util/area.h +++ b/src/util/area.h @@ -91,7 +91,8 @@ typedef struct { // after pos/size changed, the rendering engine will call _on_change_layout(Area*) int on_changed; void (*_on_change_layout)(void *obj); - const char* (*_get_tooltip_text)(void *obj); + // returns allocated string, that must be free'd after usage + char* (*_get_tooltip_text)(void *obj); } Area; // on startup, initialize fixed pos/size