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
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];
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);
}
static char buf_date[40];
static char buf_tooltip[40];
int clock_enabled;
+static const struct timeout* clock_timeout=0;
void update_clocks()
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);
}
}
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();
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);
#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)
{
//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;
}
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);
}
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;
int is_urgent(Task *tsk)
{
+ if (!tsk)
+ return;
GSList* urgent_task = urgent_list;
while (urgent_task) {
Task_urgent* t = urgent_task->data;
int x11_fd, i;
Panel *panel;
GSList *it;
- GSList* timer_iter;
- struct timer* timer;
+ const struct timespec* timeout;
init (argc, 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);
}
}
+ callback_timeout_expired();
+
switch (signal_pending) {
case SIGUSR1: // reload config file
signal_pending = 0;
// 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
.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,
.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()
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;
void cleanup_tooltip()
{
- stop_timeouts();
+ stop_tooltip_timeout();
tooltip_hide();
g_tooltip.enabled = False;
tooltip_copy_text(0);
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();
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;
return;
}
-// printf("tooltip_update\n");
tooltip_update_geometry();
tooltip_adjust_geometry();
XMoveResizeWindow(server.dsp, g_tooltip.window, x, y, width, height);
}
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);
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;
+ }
}
#ifndef TOOLTIP_H
#define TOOLTIP_H
-#include <sys/time.h>
-
#include "task.h"
#include "panel.h"
+#include "timer.h"
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;
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;
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
**************************************************************************/
-#include <sys/timerfd.h>
+#include <time.h>
#include <stdlib.h>
-#include <unistd.h>
-#include <fcntl.h>
#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;
+}
#include <glib.h>
-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