]> Dogcows Code - chaz/tint2/blobdiff - src/tint.c
*fix* use XFlush to really make use of the tooltip timeouts and do not rely on some...
[chaz/tint2] / src / tint.c
index 163fd9ea223e8a2b2e649ebda61dd93cad6fac09..9b10732694603585bca70406aa9a00d63ca25787 100644 (file)
 **************************************************************************/
 
 #include <sys/stat.h>
-#include <sys/time.h>
 #include <unistd.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <stdint.h>
 #include <string.h>
 #include <X11/Xutil.h>
 #include <X11/Xatom.h>
@@ -38,7 +38,7 @@
 #include "systraybar.h"
 #include "panel.h"
 #include "tooltip.h"
-
+#include "timer.h"
 
 void signal_handler(int sig)
 {
@@ -74,12 +74,20 @@ void init (int argc, char *argv[])
        }
 
        // Set signal handler
-       signal(SIGUSR1, signal_handler);
-       signal(SIGINT, signal_handler);
-       signal(SIGTERM, signal_handler);
-       signal(SIGHUP, signal_handler);
+       struct sigaction sa = { .sa_handler = signal_handler };
+       sigaction(SIGUSR1, &sa, 0);
+       sigaction(SIGINT, &sa, 0);
+       sigaction(SIGTERM, &sa, 0);
+       sigaction(SIGHUP, &sa, 0);
        signal(SIGCHLD, SIG_IGN);               // don't have to wait() after fork()
-       signal(SIGALRM, tooltip_sighandler);
+       // block all signals, such that no race conditions occur before pselect in our main loop
+       sigset_t block_mask;
+       sigaddset(&block_mask, SIGINT);
+       sigaddset(&block_mask, SIGTERM);
+       sigaddset(&block_mask, SIGHUP);
+       sigaddset(&block_mask, SIGUSR1);
+       sigprocmask(SIG_BLOCK, &block_mask, 0);
+
 
        // set global data
        memset(&server, 0, sizeof(Server_global));
@@ -111,7 +119,7 @@ void init (int argc, char *argv[])
        setlocale (LC_ALL, "");
 
        // load default icon
-       char *path;
+       gchar *path;
        const gchar * const *data_dirs;
        data_dirs = g_get_system_data_dirs ();
        for (i = 0; data_dirs[i] != NULL; i++)  {
@@ -265,8 +273,10 @@ void window_action (Task *tsk, int action)
                        XIconifyWindow (server.dsp, tsk->win, server.screen);
                        break;
                case TOGGLE_ICONIFY:
-                       if (tsk == task_active) XIconifyWindow (server.dsp, tsk->win, server.screen);
-                       else set_active (tsk->win);
+                       if (task_active && tsk->win == task_active->win)
+                               XIconifyWindow (server.dsp, tsk->win, server.screen);
+                       else
+                               set_active (tsk->win);
                        break;
                case SHADE:
                        window_toggle_shade (tsk->win);
@@ -478,10 +488,20 @@ void event_property_notify (XEvent *e)
        else {
                tsk = task_get_task (win);
                if (!tsk) {
-                       if ( at != server.atom._NET_WM_STATE)
-                               return;
-                       else if ( !(tsk = add_task(win)) )
+                       if (at != server.atom._NET_WM_STATE)
                                return;
+                       else {
+                               // xfce4 sends _NET_WM_STATE after minimized to tray, so we need to check if window is mapped
+                               // if it is mapped and not set as skip_taskbar, we must add it to our task list
+                               XWindowAttributes wa;
+                               XGetWindowAttributes(server.dsp, win, &wa);
+                               if (wa.map_state == IsViewable && !window_is_skip_taskbar(win)) {
+                                       if ( (tsk = add_task(win)) )
+                                               panel_refresh = 1;
+                                       else
+                                               return;
+                               }
+                       }
                }
                //printf("atom root_win = %s, %s\n", XGetAtomName(server.dsp, at), tsk->title);
 
@@ -507,9 +527,7 @@ void event_property_notify (XEvent *e)
                // Demand attention
                else if (at == server.atom._NET_WM_STATE) {
                        if (window_is_urgent (win)) {
-                               task_urgent = tsk;
-                               tick_urgent = 0;
-                               time_precision = 1;
+                               add_urgent(tsk);
                        }
                        if (window_is_skip_taskbar(win)) {
                                remove_task( tsk );
@@ -580,9 +598,7 @@ void event_property_notify (XEvent *e)
                else if (at == server.atom.WM_HINTS) {
                        XWMHints* wmhints = XGetWMHints(server.dsp, win);
                        if (wmhints && wmhints->flags & XUrgencyHint) {
-                               task_urgent = tsk;
-                               tick_urgent = 0;
-                               time_precision = 1;
+                               add_urgent(tsk);
                        }
                        XFree(wmhints);
                }
@@ -594,15 +610,11 @@ void event_property_notify (XEvent *e)
 
 void event_expose (XEvent *e)
 {
-       if (e->xany.window == g_tooltip.window)
-               tooltip_update();
-       else {
-               Panel *panel;
-               panel = get_panel(e->xany.window);
-               if (!panel) return;
-               // TODO : one panel_refresh per panel ?
-               panel_refresh = 1;
-       }
+       Panel *panel;
+       panel = get_panel(e->xany.window);
+       if (!panel) return;
+       // TODO : one panel_refresh per panel ?
+       panel_refresh = 1;
 }
 
 
@@ -650,44 +662,6 @@ void event_configure_notify (Window win)
 }
 
 
-void event_timer()
-{
-       struct timeval stv;
-       int i;
-
-       if (gettimeofday(&stv, 0)) return;
-
-       if (abs(stv.tv_sec - time_clock.tv_sec) < time_precision) return;
-       time_clock.tv_sec = stv.tv_sec;
-       time_clock.tv_sec -= time_clock.tv_sec % time_precision;
-
-       // urgent task
-       if (task_urgent) {
-               if (tick_urgent < max_tick_urgent) {
-                       task_urgent->area.is_active = !task_urgent->area.is_active;
-                       task_urgent->area.redraw = 1;
-                       tick_urgent++;
-               }
-       }
-
-       // update battery
-#ifdef ENABLE_BATTERY
-       if (battery_enabled) {
-               update_battery();
-               for (i=0 ; i < nb_panel ; i++)
-                       panel1[i].battery.area.resize = 1;
-       }
-#endif
-
-       // update clock
-       if (time1_format) {
-               for (i=0 ; i < nb_panel ; i++)
-                       panel1[i].clock.area.resize = 1;
-       }
-       panel_refresh = 1;
-}
-
-
 void dnd_message(XClientMessageEvent *e)
 {
        Panel *panel = get_panel(e->window);
@@ -721,11 +695,12 @@ void dnd_message(XClientMessageEvent *e)
 int main (int argc, char *argv[])
 {
        XEvent e;
-       fd_set fd;
+       fd_set fdset;
        int x11_fd, i;
-       struct timeval tv;
        Panel *panel;
        GSList *it;
+       GSList* timer_iter;
+       struct timer* timer;
 
        init (argc, argv);
 
@@ -751,17 +726,53 @@ int main (int argc, char *argv[])
        x11_fd = ConnectionNumber(server.dsp);
        XSync(server.dsp, False);
 
+       sigset_t empty_mask;
+       sigemptyset(&empty_mask);
+
        while (1) {
-               // thanks to AngryLlama for the timer
-               // Create a File Description Set containing x11_fd
-               FD_ZERO (&fd);
-               FD_SET (x11_fd, &fd);
+               if (panel_refresh) {
+                       panel_refresh = 0;
+
+                       if (refresh_systray) {
+                               panel = (Panel*)systray.area.panel;
+                               XSetWindowBackgroundPixmap (server.dsp, panel->main_win, None);
+                       }
+                       for (i=0 ; i < nb_panel ; i++) {
+                               panel = &panel1[i];
+
+                               if (panel->temp_pmap) XFreePixmap(server.dsp, panel->temp_pmap);
+                               panel->temp_pmap = XCreatePixmap(server.dsp, server.root_win, panel->area.width, panel->area.height, server.depth);
 
-               tv.tv_usec = 500000;
-               tv.tv_sec = 0;
+                               refresh(&panel->area);
+                               XCopyArea(server.dsp, panel->temp_pmap, panel->main_win, server.gc, 0, 0, panel->area.width, panel->area.height, 0, 0);
+                       }
+                       XFlush (server.dsp);
+
+                       if (refresh_systray) {
+                               refresh_systray = 0;
+                               panel = (Panel*)systray.area.panel;
+                               // tint2 doen't draw systray icons. it just redraw background.
+                               XSetWindowBackgroundPixmap (server.dsp, panel->main_win, panel->temp_pmap);
+                               // force icon's refresh
+                               refresh_systray_icon();
+                       }
+               }
+
+               // thanks to AngryLlama for the timer
+               // Create a File Description Set containing x11_fd, and every timer_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;
+               }
 
                // Wait for X Event or a Timer
-               if (select(x11_fd+1, &fd, 0, 0, &tv)) {
+               if (pselect(max_fd+1, &fdset, 0, 0, 0, &empty_mask) > 0) {
                        while (XPending (server.dsp)) {
                                XNextEvent(server.dsp, &e);
 
@@ -794,6 +805,12 @@ int main (int argc, char *argv[])
                                                event_expose(&e);
                                                break;
 
+                                       case MapNotify:
+                                               if (e.xany.window == g_tooltip.window)
+                                                       tooltip_update();
+                                               break;
+
+
                                        case PropertyNotify:
                                                event_property_notify(&e);
                                                break;
@@ -812,7 +829,7 @@ int main (int argc, char *argv[])
                                                break;
                                        case UnmapNotify:
                                        case DestroyNotify:
-                                               if (!systray.area.on_screen)
+                                               if (e.xany.window == g_tooltip.window || !systray.area.on_screen)
                                                        break;
                                                for (it = systray.list_icons; it; it = g_slist_next(it)) {
                                                        if (((TrayWindow*)it->data)->id == e.xany.window) {
@@ -833,50 +850,34 @@ int main (int argc, char *argv[])
                                                break;
                                }
                        }
-               }
-               event_timer();
-
-               switch (signal_pending) {
-                       case SIGUSR1: // reload config file
-                               signal_pending = 0;
-                               init_config();
-                               config_read_file (config_path);
-                               init_panel();
-                               cleanup_config();
-                               break;
-                       case SIGINT:
-                       case SIGTERM:
-                       case SIGHUP:
-                               cleanup ();
-                               return 0;
-               }
-
-               if (panel_refresh) {
-                       panel_refresh = 0;
 
-                       if (refresh_systray) {
-                               panel = (Panel*)systray.area.panel;
-                               XSetWindowBackgroundPixmap (server.dsp, panel->main_win, None);
-                       }
-                       for (i=0 ; i < nb_panel ; i++) {
-                               panel = &panel1[i];
-
-                               if (panel->temp_pmap) XFreePixmap(server.dsp, panel->temp_pmap);
-                               panel->temp_pmap = XCreatePixmap(server.dsp, server.root_win, panel->area.width, panel->area.height, server.depth);
-
-                               refresh(&panel->area);
-                               XCopyArea(server.dsp, panel->temp_pmap, panel->main_win, server.gc, 0, 0, panel->area.width, panel->area.height, 0, 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;
+                                       read(timer->id, &dummy, sizeof(uint64_t));
+                                       timer->_callback();
+                               }
+                               timer_iter = timer_iter->next;
                        }
-                       XFlush (server.dsp);
+               }
 
-                       if (refresh_systray) {
-                               refresh_systray = 0;
-                               panel = (Panel*)systray.area.panel;
-                               // tint2 doen't draw systray icons. it just redraw background.
-                               XSetWindowBackgroundPixmap (server.dsp, panel->main_win, panel->temp_pmap);
-                               // force icon's refresh
-                               refresh_systray_icon();
-                       }
+               switch (signal_pending) {
+               case SIGUSR1: // reload config file
+                       signal_pending = 0;
+                       init_config();
+                       config_read_file (config_path);
+                       init_panel();
+                       cleanup_config();
+                       break;
+               case SIGINT:
+               case SIGTERM:
+               case SIGHUP:
+                       cleanup ();
+                       return 0;
                }
        }
 }
This page took 0.028815 seconds and 4 git commands to generate.