From 35e206acc0a7b9dca7611fe4a7e17c7acc381ad0 Mon Sep 17 00:00:00 2001 From: Andreas Fink Date: Sun, 27 Dec 2009 20:33:02 +0000 Subject: [PATCH] *fix* use another timer implementation, coz *BSD does not support timerfd :( --- src/Makefile.am | 2 +- src/battery/battery.c | 5 +- src/clock/clock.c | 8 +- src/config.c | 17 +---- src/taskbar/task.c | 18 +++-- src/tint.c | 35 +++------ src/tooltip/tooltip.c | 52 ++++++------- src/tooltip/tooltip.h | 10 +-- src/util/timer.c | 166 +++++++++++++++++++++++++++++++----------- src/util/timer.h | 39 +++++----- 10 files changed, 205 insertions(+), 147 deletions(-) diff --git a/src/Makefile.am b/src/Makefile.am index d872f43..6813a04 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -3,7 +3,7 @@ SUBDIRS = tint2conf endif AM_CFLAGS += @PANGOCAIRO_CFLAGS@ @PANGO_CFLAGS@ @CAIRO_CFLAGS@ @GLIB2_CFLAGS@ @GOBJECT2_CFLAGS@ @X11_CFLAGS@ @XINERAMA_CFLAGS@ @IMLIB2_CFLAGS@ -LIBS = @PANGOCAIRO_LIBS@ @PANGO_LIBS@ @CAIRO_LIBS@ @GLIB2_LIBS@ @GOBJECT2_LIBS@ @X11_LIBS@ @XINERAMA_LIBS@ @IMLIB2_LIBS@ +LIBS = @PANGOCAIRO_LIBS@ @PANGO_LIBS@ @CAIRO_LIBS@ @GLIB2_LIBS@ @GOBJECT2_LIBS@ @X11_LIBS@ @XINERAMA_LIBS@ @IMLIB2_LIBS@ -lrt INCLUDES = -Iutil -Iclock -Itaskbar -Isystray -Itooltip bin_PROGRAMS = tint2 diff --git a/src/battery/battery.c b/src/battery/battery.c index b1f1913..4db696e 100644 --- a/src/battery/battery.c +++ b/src/battery/battery.c @@ -37,6 +37,7 @@ PangoFontDescription *bat1_font_desc=0; PangoFontDescription *bat2_font_desc=0; struct batstate battery_state; int battery_enabled; +static const struct timeout* battery_timeout=0; static char buf_bat_percentage[10]; static char buf_bat_time[20]; @@ -131,8 +132,8 @@ void init_battery() g_free(path1); g_free(battery_dir); - if (battery_enabled) - install_timer(0, 1000000, 5, 0, update_batterys); + if (battery_enabled && battery_timeout==0) + battery_timeout = add_timeout(10, 5000, update_batterys); } diff --git a/src/clock/clock.c b/src/clock/clock.c index 578a2b2..876536c 100644 --- a/src/clock/clock.c +++ b/src/clock/clock.c @@ -46,6 +46,7 @@ static char buf_time[40]; static char buf_date[40]; static char buf_tooltip[40]; int clock_enabled; +static const struct timeout* clock_timeout=0; void update_clocks() @@ -69,10 +70,11 @@ const char* clock_get_tooltip(void* obj) void init_clock() { - if(time1_format) { + if(time1_format && clock_timeout==0) { if (strchr(time1_format, 'S') || strchr(time1_format, 'T') || strchr(time1_format, 'r')) - install_timer(0, 1000000, 1, 0, update_clocks); - else install_timer(0, 1000000, 60, 0, update_clocks); + clock_timeout = add_timeout(10, 1000, update_clocks); + else + clock_timeout = add_timeout(10, 60000, update_clocks); } } diff --git a/src/config.c b/src/config.c index bc54938..caebe64 100644 --- a/src/config.c +++ b/src/config.c @@ -75,7 +75,6 @@ void init_config() list_back = g_slist_append(0, calloc(1, sizeof(Area))); // tint2 could reload config, so we cleanup objects - uninstall_all_timer(); cleanup_systray(); #ifdef ENABLE_BATTERY cleanup_battery(); @@ -526,20 +525,12 @@ void add_entry (char *key, char *value) else if (strcmp (key, "tooltip") == 0) g_tooltip.enabled = atoi(value); else if (strcmp (key, "tooltip_show_timeout") == 0) { - double timeout = atof(value); - int sec = (int)timeout; - int nsec = (timeout-sec)*1e9; - if (nsec < 0) // can happen because of double is not precise such that (sec > timeout)==TRUE - nsec = 0; - g_tooltip.show_timeout = (struct timespec){.tv_sec=sec, .tv_nsec=nsec}; + int timeout_msec = 1000*atof(value); + g_tooltip.show_timeout_msec = timeout_msec; } else if (strcmp (key, "tooltip_hide_timeout") == 0) { - double timeout = atof(value); - int sec = (int)timeout; - int nsec = (timeout-sec)*1e9; - if (nsec < 0) // can happen because of double is not precise such that (sec > timeout)==TRUE - nsec = 0; - g_tooltip.hide_timeout = (struct timespec){.tv_sec=sec, .tv_nsec=nsec}; + int timeout_msec = 1000*atof(value); + g_tooltip.hide_timeout_msec = timeout_msec; } else if (strcmp (key, "tooltip_padding") == 0) { extract_values(value, &value1, &value2, &value3); diff --git a/src/taskbar/task.c b/src/taskbar/task.c index 3bc9759..21b741b 100644 --- a/src/taskbar/task.c +++ b/src/taskbar/task.c @@ -34,7 +34,7 @@ #include "tooltip.h" #include "timer.h" -static int urgent_timer = 0; +static const struct timeout* urgent_timeout = 0; const char* task_get_tooltip(void* obj) { @@ -99,6 +99,8 @@ Task *add_task (Window win) //printf("add_task panel %d, desktop %d, task %s\n", i, j, new_tsk2->title); } } + if (window_is_urgent(win)) + add_urgent(new_tsk2); return new_tsk2; } @@ -503,10 +505,8 @@ void add_urgent(Task *tsk) t->tick = 0; urgent_list = g_slist_prepend(urgent_list, t); - if (urgent_timer == 0) - urgent_timer = install_timer(0, 1000000, 1, 0, blink_urgent); - else - reset_timer(urgent_timer, 0, 1000000, 1, 0); + if (urgent_timeout == 0) + urgent_timeout = add_timeout(10, 1000, blink_urgent); } @@ -518,8 +518,10 @@ void del_urgent(Task *tsk) if (t->tsk == tsk) { urgent_list = g_slist_remove(urgent_list, t); free(t); - if (!urgent_list) - reset_timer(urgent_timer, 0, 0, 0, 0); + if (!urgent_list) { + stop_timeout(urgent_timeout); + urgent_timeout = 0; + } return; } urgent_task = urgent_task->next; @@ -528,6 +530,8 @@ void del_urgent(Task *tsk) int is_urgent(Task *tsk) { + if (!tsk) + return; GSList* urgent_task = urgent_list; while (urgent_task) { Task_urgent* t = urgent_task->data; diff --git a/src/tint.c b/src/tint.c index 9e64ed3..a91f8cc 100644 --- a/src/tint.c +++ b/src/tint.c @@ -635,8 +635,7 @@ int main (int argc, char *argv[]) int x11_fd, i; Panel *panel; GSList *it; - GSList* timer_iter; - struct timer* timer; + const struct timespec* timeout; init (argc, argv); @@ -695,33 +694,17 @@ int main (int argc, char *argv[]) } // thanks to AngryLlama for the timer - // Create a File Description Set containing x11_fd, and every timer_fd + // Create a File Description Set containing x11_fd FD_ZERO (&fdset); FD_SET (x11_fd, &fdset); - int max_fd = x11_fd; - timer_iter = timer_list; - while (timer_iter) { - timer = timer_iter->data; - max_fd = timer->id > max_fd ? timer->id : max_fd; - FD_SET(timer->id, &fdset); - timer_iter = timer_iter->next; - } + update_next_timeout(); + if (next_timeout.tv_sec >= 0 && next_timeout.tv_nsec >= 0) + timeout = &next_timeout; + else + timeout = 0; // Wait for X Event or a Timer - if (pselect(max_fd+1, &fdset, 0, 0, 0, &empty_mask) > 0) { - // we need to iterate over the whole timer list, since fd_set can only be checked with the - // brute force method FD_ISSET for every possible timer - timer_iter = timer_list; - while (timer_iter) { - timer = timer_iter->data; - if (FD_ISSET(timer->id, &fdset)) { - uint64_t dummy; - if ( -1 != read(timer->id, &dummy, sizeof(uint64_t)) ) - timer->_callback(); - } - timer_iter = timer_iter->next; - } - + if (pselect(x11_fd+1, &fdset, 0, 0, timeout, &empty_mask) > 0) { while (XPending (server.dsp)) { XNextEvent(server.dsp, &e); @@ -800,6 +783,8 @@ int main (int argc, char *argv[]) } } + callback_timeout_expired(); + switch (signal_pending) { case SIGUSR1: // reload config file signal_pending = 0; diff --git a/src/tooltip/tooltip.c b/src/tooltip/tooltip.c index 8e74972..7bfd709 100644 --- a/src/tooltip/tooltip.c +++ b/src/tooltip/tooltip.c @@ -32,7 +32,7 @@ static int x, y, width, height; // the next functions are helper functions for tooltip handling void start_show_timeout(); void start_hide_timeout(); -void stop_timeouts(); +void stop_tooltip_timeout(); void tooltip_copy_text(Area* area); // give the tooltip some reasonable default values @@ -41,8 +41,8 @@ Tooltip g_tooltip = { .area = 0, .panel = 0, .window = 0, - .show_timeout = { 0, 0 }, - .hide_timeout = { 0, 0 }, + .show_timeout_msec = 0, + .hide_timeout_msec = 0, .enabled = False, .mapped = False, .paddingx = 0, @@ -51,8 +51,7 @@ Tooltip g_tooltip = { .background_color = { .color={0.5, 0.4, 0.5}, .alpha=1 }, .border = { .color={0, 0, 0}, .alpha=1, .width=1, .rounded=0 }, .font_desc = 0, - .show_timer_id = 0, - .hide_timer_id = 0 + .timeout = 0 }; void init_tooltip() @@ -60,9 +59,6 @@ void init_tooltip() if (!g_tooltip.font_desc) g_tooltip.font_desc = pango_font_description_from_string("sans 10"); - g_tooltip.show_timer_id = install_timer(0, 0, 0, 0, tooltip_show); - g_tooltip.hide_timer_id = install_timer(0, 0, 0, 0, tooltip_hide); - XSetWindowAttributes attr; attr.override_redirect = True; attr.event_mask = StructureNotifyMask; @@ -73,7 +69,7 @@ void init_tooltip() void cleanup_tooltip() { - stop_timeouts(); + stop_tooltip_timeout(); tooltip_hide(); g_tooltip.enabled = False; tooltip_copy_text(0); @@ -96,7 +92,7 @@ void tooltip_trigger_show(Area* area, Panel* p, int x_root, int y_root) if (g_tooltip.mapped && g_tooltip.area != area) { tooltip_copy_text(area); tooltip_update(); - stop_timeouts(); + stop_tooltip_timeout(); } else if (!g_tooltip.mapped) { start_show_timeout(); @@ -110,7 +106,7 @@ void tooltip_show() Window w; XTranslateCoordinates( server.dsp, server.root_win, g_tooltip.panel->main_win, x, y, &mx, &my, &w); Area* area = click_area(g_tooltip.panel, mx, my); - stop_timeouts(); + stop_tooltip_timeout(); if (!g_tooltip.mapped && area->_get_tooltip_text) { tooltip_copy_text(area); g_tooltip.mapped = True; @@ -204,7 +200,6 @@ void tooltip_update() return; } -// printf("tooltip_update\n"); tooltip_update_geometry(); tooltip_adjust_geometry(); XMoveResizeWindow(server.dsp, g_tooltip.window, x, y, width, height); @@ -253,14 +248,14 @@ void tooltip_trigger_hide(Tooltip* tooltip) } else { // tooltip not visible yet, but maybe a timeout is still pending - stop_timeouts(); + stop_tooltip_timeout(); } } void tooltip_hide() { - stop_timeouts(); + stop_tooltip_timeout(); if (g_tooltip.mapped) { g_tooltip.mapped = False; XUnmapWindow(server.dsp, g_tooltip.window); @@ -271,31 +266,28 @@ void tooltip_hide() void start_show_timeout() { - reset_timer(g_tooltip.hide_timer_id, 0, 0, 0, 0); - struct timespec t = g_tooltip.show_timeout; - if (t.tv_sec == 0 && t.tv_nsec == 0) { - tooltip_show(); - } - else { - reset_timer(g_tooltip.show_timer_id, t.tv_sec, t.tv_nsec, 0, 0); - } + if (g_tooltip.timeout) + change_timeout(g_tooltip.timeout, g_tooltip.show_timeout_msec, 0, tooltip_show); + else + g_tooltip.timeout = add_timeout(g_tooltip.show_timeout_msec, 0, tooltip_show); } void start_hide_timeout() { - reset_timer(g_tooltip.show_timer_id, 0, 0, 0, 0); - struct timespec t = g_tooltip.hide_timeout; - if (t.tv_sec == 0 && t.tv_nsec == 0) - tooltip_hide(); + if (g_tooltip.timeout) + change_timeout(g_tooltip.timeout, g_tooltip.hide_timeout_msec, 0, tooltip_hide); else - reset_timer(g_tooltip.hide_timer_id, t.tv_sec, t.tv_nsec, 0, 0); + g_tooltip.timeout = add_timeout(g_tooltip.hide_timeout_msec, 0, tooltip_hide); } -void stop_timeouts() + +void stop_tooltip_timeout() { - reset_timer(g_tooltip.show_timer_id, 0, 0, 0, 0); - reset_timer(g_tooltip.hide_timer_id, 0, 0, 0, 0); + if (g_tooltip.timeout) { + stop_timeout(g_tooltip.timeout); + g_tooltip.timeout = 0; + } } diff --git a/src/tooltip/tooltip.h b/src/tooltip/tooltip.h index 82752d6..0559e4d 100644 --- a/src/tooltip/tooltip.h +++ b/src/tooltip/tooltip.h @@ -18,10 +18,9 @@ #ifndef TOOLTIP_H #define TOOLTIP_H -#include - #include "task.h" #include "panel.h" +#include "timer.h" typedef struct { @@ -29,8 +28,8 @@ typedef struct { char* tooltip_text; Panel* panel; Window window; - struct timespec show_timeout; - struct timespec hide_timeout; + int show_timeout_msec; + int hide_timeout_msec; Bool enabled; Bool mapped; int paddingx; @@ -39,8 +38,7 @@ typedef struct { config_color font_color; Color background_color; Border border; - int show_timer_id; - int hide_timer_id; + const struct timeout* timeout; } Tooltip; extern Tooltip g_tooltip; diff --git a/src/util/timer.c b/src/util/timer.c index d66fa99..4da7cc3 100644 --- a/src/util/timer.c +++ b/src/util/timer.c @@ -15,68 +15,152 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. **************************************************************************/ -#include +#include #include -#include -#include #include "timer.h" -GSList* timer_list = 0; +GSList* timeout_list = 0; +struct timespec next_timeout; -int install_timer(int value_sec, int value_nsec, int interval_sec, int interval_nsec, void (*_callback)()) -{ - if ( value_sec < 0 || interval_sec < 0 || _callback == 0 ) - return -1; +void add_timeout_intern(int value_msec, int interval_msec, void(*_callback)(), struct timeout* t); +gint compare_timeouts(gconstpointer t1, gconstpointer t2); +gint compare_timespecs(const struct timespec* t1, const struct timespec* t2); +int timespec_subtract(struct timespec* result, struct timespec* x, struct timespec* y); - int timer_fd; - struct itimerspec timer; - timer.it_value = (struct timespec){ .tv_sec=value_sec, .tv_nsec=value_nsec }; - timer.it_interval = (struct timespec){ .tv_sec=interval_sec, .tv_nsec=interval_nsec }; - timer_fd = timerfd_create(CLOCK_MONOTONIC, 0); - timerfd_settime(timer_fd, 0, &timer, 0); - struct timer* t = malloc(sizeof(struct timer)); - t->id=timer_fd; - t->_callback = _callback; - timer_list = g_slist_prepend(timer_list, t); - int flags = fcntl( timer_fd, F_GETFL, 0 ); - if( flags != -1 ) - fcntl( timer_fd, F_SETFL, flags | O_NONBLOCK ); +const struct timeout* add_timeout(int value_msec, int interval_msec, void (*_callback)()) +{ + struct timeout* t = malloc(sizeof(struct timeout)); + add_timeout_intern(value_msec, interval_msec, _callback, t); + return t; +} + - return timer_fd; +void change_timeout(const struct timeout *t, int value_msec, int interval_msec, void(*_callback)()) +{ + timeout_list = g_slist_remove(timeout_list, t); + add_timeout_intern(value_msec, interval_msec, _callback, (struct timeout*)t); } -void reset_timer(int id, int value_sec, int value_nsec, int interval_sec, int interval_nsec) +void update_next_timeout() { - struct itimerspec timer; - timer.it_value = (struct timespec){ .tv_sec=value_sec, .tv_nsec=value_nsec }; - timer.it_interval = (struct timespec){ .tv_sec=interval_sec, .tv_nsec=interval_nsec }; - timerfd_settime(id, 0, &timer, 0); + if (timeout_list) { + struct timeout* t = timeout_list->data; + struct timespec cur_time; + clock_gettime(CLOCK_MONOTONIC, &cur_time); + if (timespec_subtract(&next_timeout, &t->timeout_expires, &cur_time)) { + next_timeout.tv_sec = 0; + next_timeout.tv_nsec = 0; + } + } + else + next_timeout.tv_sec = -1; } -void uninstall_timer(int id) +void callback_timeout_expired() { - close(id); - GSList* timer_iter = timer_list; - while (timer_iter) { - struct timer* t = timer_iter->data; - if (t->id == id) { - timer_list = g_slist_remove(timer_list, t); - free(t); - return; + struct timespec cur_time; + struct timeout* t; + while (timeout_list) { + clock_gettime(CLOCK_MONOTONIC, &cur_time); + t = timeout_list->data; + if (compare_timespecs(&t->timeout_expires, &cur_time) <= 0) { + // it's time for the callback function + t->_callback(); + if (g_slist_find(timeout_list, t)) { + // if _callback() calls stop_timeout(t) the timeout 't' does not exist anymore + timeout_list = g_slist_remove(timeout_list, t); + if (t->interval_msec > 0) + add_timeout_intern(t->interval_msec, t->interval_msec, t->_callback, t); + else + free(t); + } } - timer_iter = timer_iter->next; + else + return; + } +} + + +void stop_timeout(const struct timeout* t) +{ + if (g_slist_find(timeout_list, t)) { + timeout_list = g_slist_remove(timeout_list, t); + free((void*)t); } } -void uninstall_all_timer() +void stop_all_timeouts() { - while (timer_list) { - struct timer* t = timer_list->data; - uninstall_timer(t->id); + while (timeout_list) { + free(timeout_list->data); + timeout_list = g_slist_remove(timeout_list, timeout_list->data); } } + + +void add_timeout_intern(int value_msec, int interval_msec, void(*_callback)(), struct timeout *t) +{ + t->interval_msec = interval_msec; + t->_callback = _callback; + struct timespec expire; + clock_gettime(CLOCK_MONOTONIC, &expire); + expire.tv_sec += value_msec / 1000; + expire.tv_nsec += (value_msec % 1000)*1000000; + if (expire.tv_nsec >= 1000000000) { // 10^9 + expire.tv_sec++; + expire.tv_nsec -= 1000000000; + } + t->timeout_expires = expire; + timeout_list = g_slist_insert_sorted(timeout_list, t, compare_timeouts); +} + + +gint compare_timeouts(gconstpointer t1, gconstpointer t2) +{ + return compare_timespecs(&((const struct timeout*)t1)->timeout_expires, + &((const struct timeout*)t2)->timeout_expires); +} + + +gint compare_timespecs(const struct timespec* t1, const struct timespec* t2) +{ + if (t1->tv_sec < t2->tv_sec) + return -1; + else if (t1->tv_sec == t2->tv_sec) { + if (t1->tv_nsec < t2->tv_nsec) + return -1; + else if (t1->tv_nsec == t2->tv_nsec) + return 0; + else + return 1; + } + else + return 1; +} + +int timespec_subtract(struct timespec* result, struct timespec* x, struct timespec* y) +{ + /* Perform the carry for the later subtraction by updating y. */ + if (x->tv_nsec < y->tv_nsec) { + int nsec = (y->tv_nsec - x->tv_nsec) / 1000000000 + 1; + y->tv_nsec -= 1000000000 * nsec; + y->tv_sec += nsec; + } + if (x->tv_nsec - y->tv_nsec > 1000000000) { + int nsec = (x->tv_nsec - y->tv_nsec) / 1000000000; + y->tv_nsec += 1000000000 * nsec; + y->tv_sec -= nsec; + } + + /* Compute the time remaining to wait. tv_nsec is certainly positive. */ + result->tv_sec = x->tv_sec - y->tv_sec; + result->tv_nsec = x->tv_nsec - y->tv_nsec; + + /* Return 1 if result is negative. */ + return x->tv_sec < y->tv_sec; +} diff --git a/src/util/timer.h b/src/util/timer.h index e938b2f..23aea08 100644 --- a/src/util/timer.h +++ b/src/util/timer.h @@ -21,31 +21,32 @@ #include -extern GSList* timer_list; +extern GSList* timeout_list; +extern struct timespec next_timeout; -struct timer { - int id; +struct timeout { + int interval_msec; + struct timespec timeout_expires; void (*_callback)(); }; // timer functions -/** installs a timer with the first timeout 'value_sec' and then a periodic timeout with interval_sec - * '_callback' is the callback function when the timer reaches the timeout. - * If 'value_sec' == 0 then the timer is disabled (but not uninstalled) - * If 'interval_sec' == 0 the timer is a single shot timer, ie. no periodic timeout occur - * returns the 'id' of the timer, which is needed for uninstalling the timer **/ -int install_timer(int value_sec, int value_nsec, int interval_sec, int interval_nsec, void (*_callback)()); - -/** resets a timer to the new values. If 'id' does not exist nothing happens. - * If value_sec == 0 the timer is stopped **/ -void reset_timer(int id, int value_sec, int value_nsec, int interval_sec, int interval_nsec); - -/** uninstalls a timer with the given 'id'. If no timer is installed with this id nothing happens **/ -void uninstall_timer(int id); - -/** uninstalls all timer. Calls uninstall_timer for all available id's **/ -void uninstall_all_timer(); +/** installs a timeout with the first timeout of 'value_msec' and then a periodic timeout with + * 'interval_msec'. '_callback' is the callback function when the timer reaches the timeout. + * returns a pointer to the timeout, which is needed for stopping it again **/ +const struct timeout* add_timeout(int value_msec, int interval_msec, void (*_callback)()); + +void change_timeout(const struct timeout* t, int value_msec, int interval_msec, void (*_callback)()); + +/** stops the timeout 't' **/ +void stop_timeout(const struct timeout* t); + +/** stops all timeouts **/ +void stop_all_timeouts(); + +void update_next_timeout(); +void callback_timeout_expired(); #endif // TIMER_H -- 2.44.0