From ad50533aef71e9697fe78bb636e64079f198f985 Mon Sep 17 00:00:00 2001 From: Andreas Fink Date: Tue, 5 Jan 2010 20:38:49 +0000 Subject: [PATCH] *add* autohide *fix* issue 182 by using select instead of pselect --- sample/black_single_desktop.tint2rc | 9 ++ sample/default.tint2rc | 9 ++ sample/horizontal_icon_only.tint2rc | 9 ++ sample/rounded_multi_desktop.tint2rc | 9 ++ sample/tint2rc | 9 ++ sample/vertical_icon_only.tint2rc | 10 ++ sample/white_single_desktop.tint2rc | 9 ++ src/battery/battery.c | 4 +- src/clock/clock.c | 12 +- src/config.c | 16 ++ src/panel.c | 229 ++++++++++++++++++++++----- src/panel.h | 15 ++ src/taskbar/task.c | 4 +- src/tint.c | 56 ++++--- src/tooltip/tooltip.c | 16 +- src/tooltip/tooltip.h | 4 +- src/util/timer.c | 37 +++-- src/util/timer.h | 7 +- 18 files changed, 367 insertions(+), 97 deletions(-) diff --git a/sample/black_single_desktop.tint2rc b/sample/black_single_desktop.tint2rc index 8eb245c..8aab308 100644 --- a/sample/black_single_desktop.tint2rc +++ b/sample/black_single_desktop.tint2rc @@ -100,4 +100,13 @@ mouse_right = close mouse_scroll_up = toggle mouse_scroll_down = iconify +#--------------------------------------------- +# AUTOHIDE OPTIONS +#--------------------------------------------- +autohide = 0 +autohide_show_timeout = 0.3 +autohide_hide_timeout = 2 +autohide_height = 4 +strut_policy = minimum + diff --git a/sample/default.tint2rc b/sample/default.tint2rc index 3fbd73c..0def646 100644 --- a/sample/default.tint2rc +++ b/sample/default.tint2rc @@ -127,3 +127,12 @@ mouse_right = close mouse_scroll_up = toggle mouse_scroll_down = iconify +#--------------------------------------------- +# AUTOHIDE OPTIONS +#--------------------------------------------- +autohide = 0 +autohide_show_timeout = 0.3 +autohide_hide_timeout = 2 +autohide_height = 4 +strut_policy = minimum + diff --git a/sample/horizontal_icon_only.tint2rc b/sample/horizontal_icon_only.tint2rc index a8ca313..39e4812 100644 --- a/sample/horizontal_icon_only.tint2rc +++ b/sample/horizontal_icon_only.tint2rc @@ -125,3 +125,12 @@ mouse_right = close mouse_scroll_up = toggle mouse_scroll_down = iconify +#--------------------------------------------- +# AUTOHIDE OPTIONS +#--------------------------------------------- +autohide = 0 +autohide_show_timeout = 0.3 +autohide_hide_timeout = 2 +autohide_height = 4 +strut_policy = minimum + diff --git a/sample/rounded_multi_desktop.tint2rc b/sample/rounded_multi_desktop.tint2rc index 50a78d0..c181a05 100644 --- a/sample/rounded_multi_desktop.tint2rc +++ b/sample/rounded_multi_desktop.tint2rc @@ -105,3 +105,12 @@ mouse_right = close mouse_scroll_up = toggle mouse_scroll_down = iconify +#--------------------------------------------- +# AUTOHIDE OPTIONS +#--------------------------------------------- +autohide = 0 +autohide_show_timeout = 0.3 +autohide_hide_timeout = 2 +autohide_height = 4 +strut_policy = minimum + diff --git a/sample/tint2rc b/sample/tint2rc index 124cca0..ff991e7 100644 --- a/sample/tint2rc +++ b/sample/tint2rc @@ -115,3 +115,12 @@ mouse_right = close mouse_scroll_up = toggle mouse_scroll_down = iconify +#--------------------------------------------- +# AUTOHIDE OPTIONS +#--------------------------------------------- +autohide = 0 +autohide_show_timeout = 0.3 +autohide_hide_timeout = 2 +autohide_height = 4 +strut_policy = minimum + diff --git a/sample/vertical_icon_only.tint2rc b/sample/vertical_icon_only.tint2rc index 1c8342b..6376b15 100644 --- a/sample/vertical_icon_only.tint2rc +++ b/sample/vertical_icon_only.tint2rc @@ -114,3 +114,13 @@ mouse_middle = none mouse_right = close mouse_scroll_up = toggle mouse_scroll_down = iconify + +#--------------------------------------------- +# AUTOHIDE OPTIONS +#--------------------------------------------- +autohide = 0 +autohide_show_timeout = 0.3 +autohide_hide_timeout = 2 +autohide_height = 4 +strut_policy = minimum + diff --git a/sample/white_single_desktop.tint2rc b/sample/white_single_desktop.tint2rc index 4d62cf9..a6cd964 100644 --- a/sample/white_single_desktop.tint2rc +++ b/sample/white_single_desktop.tint2rc @@ -122,3 +122,12 @@ mouse_right = close mouse_scroll_up = toggle mouse_scroll_down = iconify +#--------------------------------------------- +# AUTOHIDE OPTIONS +#--------------------------------------------- +autohide = 0 +autohide_show_timeout = 0.3 +autohide_hide_timeout = 2 +autohide_height = 4 +strut_policy = minimum + diff --git a/src/battery/battery.c b/src/battery/battery.c index 4db696e..99e5aee 100644 --- a/src/battery/battery.c +++ b/src/battery/battery.c @@ -50,7 +50,7 @@ char *path_energy_full=0; char *path_current_now=0; char *path_status=0; -void update_batterys() +void update_batterys(void* arg) { int i; update_battery(); @@ -133,7 +133,7 @@ void init_battery() g_free(battery_dir); if (battery_enabled && battery_timeout==0) - battery_timeout = add_timeout(10, 5000, update_batterys); + battery_timeout = add_timeout(10, 5000, update_batterys, 0); } diff --git a/src/clock/clock.c b/src/clock/clock.c index 115ba9f..3eef5a4 100644 --- a/src/clock/clock.c +++ b/src/clock/clock.c @@ -53,7 +53,7 @@ int clock_enabled; static const struct timeout* clock_timeout=0; -void update_clocks() +void update_clocks(void* arg) { gettimeofday(&time_clock, 0); int i; @@ -87,9 +87,9 @@ void init_clock() { if(time1_format && clock_timeout==0) { if (strchr(time1_format, 'S') || strchr(time1_format, 'T') || strchr(time1_format, 'r')) - clock_timeout = add_timeout(10, 1000, update_clocks); + clock_timeout = add_timeout(10, 1000, update_clocks, 0); else - clock_timeout = add_timeout(10, 60000, update_clocks); + clock_timeout = add_timeout(10, 60000, update_clocks, 0); } } @@ -282,9 +282,9 @@ void clock_action(int button) pid = fork(); if (pid == 0) { // change for the fork the signal mask - sigset_t sigset; - sigprocmask(SIG_SETMASK, &sigset, 0); - sigprocmask(SIG_UNBLOCK, &sigset, 0); +// sigset_t sigset; +// sigprocmask(SIG_SETMASK, &sigset, 0); +// sigprocmask(SIG_UNBLOCK, &sigset, 0); execl("/bin/sh", "/bin/sh", "-c", command, NULL); _exit(0); } diff --git a/src/config.c b/src/config.c index 62a8c58..814bc5d 100644 --- a/src/config.c +++ b/src/config.c @@ -607,6 +607,22 @@ void add_entry (char *key, char *value) else if (strcmp (key, "mouse_scroll_down") == 0) get_action (value, &mouse_scroll_down); + /* autohide options */ + else if (strcmp(key, "autohide") == 0) + panel_autohide = atoi(value); + else if (strcmp(key, "autohide_show_timeout") == 0) + panel_autohide_show_timeout = 1000*atof(value); + else if (strcmp(key, "autohide_hide_timeout") == 0) + panel_autohide_hide_timeout = 1000*atof(value); + else if (strcmp(key, "strut_policy") == 0) { + if (strcmp(value, "follow_size") == 0) + panel_strut_policy = STRUT_FOLLOW_SIZE; + else + panel_strut_policy = STRUT_MINIMUM; + } + else if (strcmp(key, "autohide_height") == 0) + panel_autohide_height = atoi(value); + /* Read tint-0.6 config for backward compatibility */ else if (strcmp (key, "panel_mode") == 0) { diff --git a/src/panel.c b/src/panel.c index e61fe19..9b8ff74 100644 --- a/src/panel.c +++ b/src/panel.c @@ -51,6 +51,12 @@ int panel_position; int panel_horizontal; int panel_refresh; +int panel_autohide = 0; +int panel_autohide_show_timeout = 0; +int panel_autohide_hide_timeout = 0; +int panel_autohide_height = 5; // for vertical panels this is of course the width +int panel_strut_policy = STRUT_MINIMUM; + Task *task_active; Task *task_drag; int max_tick_urgent; @@ -64,6 +70,9 @@ int nb_panel = 0; Imlib_Image default_icon = NULL; +void autohide_hide(void* p); +void autohide_show(void* p); + void init_panel() { @@ -152,6 +161,8 @@ void init_panel() long event_mask = ExposureMask|ButtonPressMask|ButtonReleaseMask; if (g_tooltip.enabled) event_mask |= PointerMotionMask|LeaveWindowMask; + if (panel_autohide) + event_mask |= LeaveWindowMask|EnterWindowMask; XSetWindowAttributes att = { .event_mask=event_mask, .colormap=server.colormap, .background_pixel=0, .border_pixel=0 }; unsigned long mask = CWEventMask|CWColormap|CWBackPixel|CWBorderPixel; p->main_win = XCreateWindow(server.dsp, server.root_win, p->posx, p->posy, p->area.width, p->area.height, 0, server.depth, InputOutput, server.visual, mask, &att); @@ -172,6 +183,9 @@ void init_panel() // map new panel XMapWindow (server.dsp, p->main_win); } + + if (panel_autohide) + add_timeout(panel_autohide_hide_timeout, 0, autohide_hide, p); } panel1 = new_panel; @@ -234,6 +248,18 @@ void init_panel_size_and_position(Panel *panel) panel->posy = server.monitor[panel->monitor].y + ((server.monitor[panel->monitor].height - panel->area.height) / 2); } } + + if (panel_autohide) { + int diff = (panel_horizontal ? panel->area.height : panel->area.width) - panel_autohide_height; + if (panel_horizontal) { + panel->hidden_width = panel->area.width; + panel->hidden_height = panel->area.height - diff; + } + else { + panel->hidden_width = panel->area.width - diff; + panel->hidden_height = panel->area.height; + } + } // printf("panel : posx %d, posy %d, width %d, height %d\n", panel->posx, panel->posy, panel->area.width, panel->area.height); } @@ -258,6 +284,9 @@ void cleanup_panel() XFreePixmap(server.dsp, p->temp_pmap); p->temp_pmap = 0; } + if (p->hidden_pixmap) + XFreePixmap(server.dsp, p->hidden_pixmap); + p->hidden_pixmap = 0; if (p->main_win) { XDestroyWindow(server.dsp, p->main_win); p->main_win = 0; @@ -378,6 +407,54 @@ void visible_object() panel_refresh = 1; } +void update_strut(Panel* p) +{ + // Reserved space + unsigned int d1, screen_width, screen_height; + Window d2; + int d3; + XGetGeometry(server.dsp, server.root_win, &d2, &d3, &d3, &screen_width, &screen_height, &d1, &d1); + Monitor monitor = server.monitor[p->monitor]; + long struts [12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + if (panel_horizontal) { + int height = p->area.height + p->marginy; + if (panel_autohide && (panel_strut_policy == STRUT_MINIMUM || (panel_strut_policy == STRUT_FOLLOW_SIZE && p->is_hidden)) ) + height = p->hidden_height; + if (panel_position & TOP) { + struts[2] = height + monitor.y; + struts[8] = p->posx; + // p->area.width - 1 allowed full screen on monitor 2 + struts[9] = p->posx + p->area.width - 1; + } + else { + struts[3] = height + screen_height - monitor.y - monitor.height; + struts[10] = p->posx; + // p->area.width - 1 allowed full screen on monitor 2 + struts[11] = p->posx + p->area.width - 1; + } + } + else { + int width = p->area.width + p->marginx; + if (panel_autohide && (panel_strut_policy == STRUT_MINIMUM || (panel_strut_policy == STRUT_FOLLOW_SIZE && p->is_hidden)) ) + width = p->hidden_width; + if (panel_position & LEFT) { + struts[0] = width + monitor.x; + struts[4] = p->posy; + // p->area.width - 1 allowed full screen on monitor 2 + struts[5] = p->posy + p->area.height - 1; + } + else { + struts[1] = width + screen_width - monitor.x - monitor.width; + struts[6] = p->posy; + // p->area.width - 1 allowed full screen on monitor 2 + struts[7] = p->posy + p->area.height - 1; + } + } + // Old specification : fluxbox need _NET_WM_STRUT. + XChangeProperty (server.dsp, p->main_win, server.atom._NET_WM_STRUT, XA_CARDINAL, 32, PropModeReplace, (unsigned char *) &struts, 4); + XChangeProperty (server.dsp, p->main_win, server.atom._NET_WM_STRUT_PARTIAL, XA_CARDINAL, 32, PropModeReplace, (unsigned char *) &struts, 12); +} + void set_panel_properties(Panel *p) { @@ -402,7 +479,8 @@ void set_panel_properties(Panel *p) state[1] = server.atom._NET_WM_STATE_SKIP_TASKBAR; state[2] = server.atom._NET_WM_STATE_STICKY; state[3] = panel_layer == BOTTOM_LAYER ? server.atom._NET_WM_STATE_BELOW : server.atom._NET_WM_STATE_ABOVE; - XChangeProperty (server.dsp, p->main_win, server.atom._NET_WM_STATE, XA_ATOM, 32, PropModeReplace, (unsigned char *) state, panel_layer == NORMAL_LAYER ? 3 : 4); + int nb_atoms = panel_layer == NORMAL_LAYER ? 3 : 4; + XChangeProperty (server.dsp, p->main_win, server.atom._NET_WM_STATE, XA_ATOM, 32, PropModeReplace, (unsigned char *) state, nb_atoms); // Unfocusable XWMHints wmhints; @@ -425,51 +503,18 @@ void set_panel_properties(Panel *p) int version=5; XChangeProperty(server.dsp, p->main_win, server.atom.XdndAware, XA_ATOM, 32, PropModeReplace, (unsigned char*)&version, 1); - // Reserved space - unsigned int d1, screen_width, screen_height; - Window d2; - int d3; - XGetGeometry(server.dsp, server.root_win, &d2, &d3, &d3, &screen_width, &screen_height, &d1, &d1); - Monitor monitor = server.monitor[p->monitor]; - long struts [12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; - if (panel_horizontal) { - if (panel_position & TOP) { - struts[2] = p->area.height + p->marginy + monitor.y; - struts[8] = p->posx; - // p->area.width - 1 allowed full screen on monitor 2 - struts[9] = p->posx + p->area.width - 1; - } - else { - struts[3] = p->area.height + p->marginy + screen_height - monitor.y - monitor.height; - struts[10] = p->posx; - // p->area.width - 1 allowed full screen on monitor 2 - struts[11] = p->posx + p->area.width - 1; - } - } - else { - if (panel_position & LEFT) { - struts[0] = p->area.width + p->marginx + monitor.x; - struts[4] = p->posy; - // p->area.width - 1 allowed full screen on monitor 2 - struts[5] = p->posy + p->area.height - 1; - } - else { - struts[1] = p->area.width + p->marginx + screen_width - monitor.x - monitor.width; - struts[6] = p->posy; - // p->area.width - 1 allowed full screen on monitor 2 - struts[7] = p->posy + p->area.height - 1; - } - } - // Old specification : fluxbox need _NET_WM_STRUT. - XChangeProperty (server.dsp, p->main_win, server.atom._NET_WM_STRUT, XA_CARDINAL, 32, PropModeReplace, (unsigned char *) &struts, 4); - XChangeProperty (server.dsp, p->main_win, server.atom._NET_WM_STRUT_PARTIAL, XA_CARDINAL, 32, PropModeReplace, (unsigned char *) &struts, 12); + update_strut(p); // Fixed position and non-resizable window // Allow panel move and resize when tint2 reload config file + int minwidth = panel_autohide ? p->hidden_width : p->area.width; + int minheight = panel_autohide ? p->hidden_height : p->area.height; XSizeHints size_hints; size_hints.flags = PPosition|PMinSize|PMaxSize; - size_hints.min_width = size_hints.max_width = p->area.width; - size_hints.min_height = size_hints.max_height = p->area.height; + size_hints.min_width = minwidth; + size_hints.max_width = p->area.width; + size_hints.min_height = minheight; + size_hints.max_height = p->area.height; XSetWMNormalHints(server.dsp, p->main_win, &size_hints); // Set WM_CLASS @@ -504,12 +549,21 @@ void set_panel_background(Panel *p) cairo_t *c; cs = cairo_xlib_surface_create (server.dsp, p->area.pix.pmap, server.visual, p->area.width, p->area.height); c = cairo_create (cs); - draw_background(&p->area, c, 0); - cairo_destroy (c); cairo_surface_destroy (cs); + if (panel_autohide) { + if (p->hidden_pixmap) XFreePixmap(server.dsp, p->hidden_pixmap); + p->hidden_pixmap = XCreatePixmap(server.dsp, server.root_win, p->hidden_width, p->hidden_height, server.depth); + int xoff=0, yoff=0; + if (panel_horizontal && panel_position & BOTTOM) + yoff = p->area.height-p->hidden_height; + else if (!panel_horizontal && panel_position & RIGHT) + xoff = p->area.width-p->hidden_width; + XCopyArea(server.dsp, p->area.pix.pmap, p->hidden_pixmap, server.gc, xoff, yoff, p->hidden_width, p->hidden_height, 0, 0); + } + // redraw panel's object GSList *l0; Area *a; @@ -637,3 +691,92 @@ Area* click_area(Panel *panel, int x, int y) } while (new_result != result); return result; } + + +void stop_autohide_timeout(Panel* p) +{ + if (p->autohide_timeout) { + stop_timeout(p->autohide_timeout); + p->autohide_timeout = 0; + } +} + + +void autohide_show(void* p) +{ + Panel* panel = p; + stop_autohide_timeout(panel); + panel->is_hidden = 0; + if (panel_strut_policy == STRUT_FOLLOW_SIZE) + update_strut(p); + + XMapSubwindows(server.dsp, panel->main_win); + if (panel_horizontal) { + if (panel_position & TOP) + XResizeWindow(server.dsp, panel->main_win, panel->area.width, panel->area.height); + else + XMoveResizeWindow(server.dsp, panel->main_win, panel->posx, panel->posy, panel->area.width, panel->area.height); + } + else { + if (panel_position & LEFT) + XResizeWindow(server.dsp, panel->main_win, panel->area.width, panel->area.height); + else + XMoveResizeWindow(server.dsp, panel->main_win, panel->posx, panel->posy, panel->area.width, panel->area.height); + } + panel_refresh = 1; +} + + +void autohide_hide(void* p) +{ + Panel* panel = p; + stop_autohide_timeout(panel); + panel->is_hidden = 1; + if (panel_strut_policy == STRUT_FOLLOW_SIZE) + update_strut(p); + + XUnmapSubwindows(server.dsp, panel->main_win); + int diff = (panel_horizontal ? panel->area.height : panel->area.width) - panel_autohide_height; + if (panel_horizontal) { + if (panel_position & TOP) + XResizeWindow(server.dsp, panel->main_win, panel->hidden_width, panel->hidden_height); + else + XMoveResizeWindow(server.dsp, panel->main_win, panel->posx, panel->posy+diff, panel->hidden_width, panel->hidden_height); + } + else { + if (panel_position & LEFT) + XResizeWindow(server.dsp, panel->main_win, panel->hidden_width, panel->hidden_height); + else + XMoveResizeWindow(server.dsp, panel->main_win, panel->posx+diff, panel->posy, panel->hidden_width, panel->hidden_height); + } + panel_refresh = 1; +} + + +void autohide_trigger_show(Panel* p) +{ + if (!p) + return; + if (p->autohide_timeout) + change_timeout(p->autohide_timeout, panel_autohide_show_timeout, 0, autohide_show, p); + else + p->autohide_timeout = add_timeout(panel_autohide_show_timeout, 0, autohide_show, p); +} + + +void autohide_trigger_hide(Panel* p) +{ + if (!p) + return; + + Window root, child; + int xr, yr, xw, yw; + unsigned int mask; + if (XQueryPointer(server.dsp, p->main_win, &root, &child, &xr, &yr, &xw, &yw, &mask)) + if (child) return; // mouse over one of the system tray icons + + if (p->autohide_timeout) + change_timeout(p->autohide_timeout, panel_autohide_hide_timeout, 0, autohide_hide, p); + else + p->autohide_timeout = add_timeout(panel_autohide_hide_timeout, 0, autohide_hide, p); +} diff --git a/src/panel.h b/src/panel.h index 52665cd..a53bc45 100644 --- a/src/panel.h +++ b/src/panel.h @@ -50,6 +50,14 @@ extern int panel_horizontal; extern int panel_refresh; +//panel autohide +enum { STRUT_MINIMUM, STRUT_FOLLOW_SIZE }; +extern int panel_autohide; +extern int panel_autohide_show_timeout; +extern int panel_autohide_hide_timeout; +extern int panel_autohide_height; // for vertical panels this is of course the width +extern int panel_strut_policy; + extern Task *task_active; extern Task *task_drag; extern int max_tick_urgent; @@ -97,6 +105,10 @@ typedef struct { #ifdef ENABLE_BATTERY Battery battery; #endif + int is_hidden; + int hidden_width, hidden_height; + Pixmap hidden_pixmap; + const struct timeout* autohide_timeout; } Panel; @@ -127,4 +139,7 @@ int click_padding(Panel *panel, int x, int y); int click_clock(Panel *panel, int x, int y); Area* click_area(Panel *panel, int x, int y); +void autohide_trigger_show(); +void autohide_trigger_hide(); + #endif diff --git a/src/taskbar/task.c b/src/taskbar/task.c index 98c943a..9859043 100644 --- a/src/taskbar/task.c +++ b/src/taskbar/task.c @@ -469,7 +469,7 @@ void active_task() } -void blink_urgent() +void blink_urgent(void* arg) { GSList* urgent_task = urgent_list; while (urgent_task) { @@ -510,7 +510,7 @@ void add_urgent(Task *tsk) urgent_list = g_slist_concat(urgent_add, urgent_list); if (urgent_timeout == 0) - urgent_timeout = add_timeout(10, 1000, blink_urgent); + urgent_timeout = add_timeout(10, 1000, blink_urgent, 0); } diff --git a/src/tint.c b/src/tint.c index 01db88c..7c167d8 100644 --- a/src/tint.c +++ b/src/tint.c @@ -80,13 +80,16 @@ void init (int argc, char *argv[]) sigaction(SIGTERM, &sa, 0); sigaction(SIGHUP, &sa, 0); signal(SIGCHLD, SIG_IGN); // don't have to wait() after fork() + + // BSD is too stupid to support pselect(), therefore we have to use select and hope that we do not + // end up in a race condition there // 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); +// 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)); @@ -681,7 +684,7 @@ int main (int argc, char *argv[]) int x11_fd, i; Panel *panel; GSList *it; - const struct timespec* timeout; + struct timeval* timeout; init (argc, argv); init_config(); @@ -710,8 +713,8 @@ int main (int argc, char *argv[]) x11_fd = ConnectionNumber(server.dsp); XSync(server.dsp, False); - sigset_t empty_mask; - sigemptyset(&empty_mask); +// sigset_t empty_mask; +// sigemptyset(&empty_mask); while (1) { if (panel_refresh) { @@ -725,15 +728,19 @@ int main (int argc, char *argv[]) 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); + if (panel->is_hidden) + XCopyArea(server.dsp, panel->hidden_pixmap, panel->main_win, server.gc, 0, 0, panel->hidden_width, panel->hidden_height, 0, 0); + else { + 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); + } } XFlush (server.dsp); - if (refresh_systray) { + panel = (Panel*)systray.area.panel; + if (refresh_systray && !panel->is_hidden) { refresh_systray = 0; panel = (Panel*)systray.area.panel; // tint2 doen't draw systray icons. it just redraw background. @@ -748,19 +755,29 @@ int main (int argc, char *argv[]) FD_ZERO (&fdset); FD_SET (x11_fd, &fdset); update_next_timeout(); - if (next_timeout.tv_sec >= 0 && next_timeout.tv_nsec >= 0) + if (next_timeout.tv_sec >= 0 && next_timeout.tv_usec >= 0) timeout = &next_timeout; else timeout = 0; // Wait for X Event or a Timer - if (pselect(x11_fd+1, &fdset, 0, 0, timeout, &empty_mask) > 0) { + if (select(x11_fd+1, &fdset, 0, 0, timeout) > 0) { while (XPending (server.dsp)) { XNextEvent(server.dsp, &e); + panel = get_panel(e.xany.window); + if (panel && panel_autohide) { + if (e.type == EnterNotify) + autohide_trigger_show(panel); + else if (e.type == LeaveNotify) + autohide_trigger_hide(panel); + if (panel->is_hidden) + continue; // discard further processing of this event because the panel is not visible yet + } + switch (e.type) { case ButtonPress: - tooltip_hide(); + tooltip_hide(0); event_button_press (&e); break; @@ -780,7 +797,8 @@ int main (int argc, char *argv[]) } case LeaveNotify: - tooltip_trigger_hide(); + if (g_tooltip.enabled) + tooltip_trigger_hide(); break; case Expose: diff --git a/src/tooltip/tooltip.c b/src/tooltip/tooltip.c index 6c36625..3eadda4 100644 --- a/src/tooltip/tooltip.c +++ b/src/tooltip/tooltip.c @@ -74,7 +74,7 @@ void init_tooltip() void cleanup_tooltip() { stop_tooltip_timeout(); - tooltip_hide(); + tooltip_hide(0); g_tooltip.enabled = False; tooltip_copy_text(0); if (g_tooltip.window) { @@ -104,7 +104,7 @@ void tooltip_trigger_show(Area* area, Panel* p, int x_root, int y_root) } -void tooltip_show() +void tooltip_show(void* arg) { int mx, my; Window w; @@ -200,7 +200,7 @@ void tooltip_adjust_geometry() void tooltip_update() { if (!g_tooltip.tooltip_text) { - tooltip_hide(); + tooltip_hide(0); return; } @@ -265,7 +265,7 @@ void tooltip_trigger_hide(Tooltip* tooltip) } -void tooltip_hide() +void tooltip_hide(void* arg) { stop_tooltip_timeout(); if (g_tooltip.mapped) { @@ -279,18 +279,18 @@ void tooltip_hide() void start_show_timeout() { if (g_tooltip.timeout) - change_timeout(g_tooltip.timeout, g_tooltip.show_timeout_msec, 0, tooltip_show); + change_timeout(g_tooltip.timeout, g_tooltip.show_timeout_msec, 0, tooltip_show, 0); else - g_tooltip.timeout = add_timeout(g_tooltip.show_timeout_msec, 0, tooltip_show); + g_tooltip.timeout = add_timeout(g_tooltip.show_timeout_msec, 0, tooltip_show, 0); } void start_hide_timeout() { if (g_tooltip.timeout) - change_timeout(g_tooltip.timeout, g_tooltip.hide_timeout_msec, 0, tooltip_hide); + change_timeout(g_tooltip.timeout, g_tooltip.hide_timeout_msec, 0, tooltip_hide, 0); else - g_tooltip.timeout = add_timeout(g_tooltip.hide_timeout_msec, 0, tooltip_hide); + g_tooltip.timeout = add_timeout(g_tooltip.hide_timeout_msec, 0, tooltip_hide, 0); } diff --git a/src/tooltip/tooltip.h b/src/tooltip/tooltip.h index 0559e4d..0aa965f 100644 --- a/src/tooltip/tooltip.h +++ b/src/tooltip/tooltip.h @@ -46,9 +46,9 @@ extern Tooltip g_tooltip; void init_tooltip(); void cleanup_tooltip(); void tooltip_trigger_show(Area* area, Panel* p, int x, int y); -void tooltip_show(); +void tooltip_show(void* /*arg*/); void tooltip_update(); void tooltip_trigger_hide(); -void tooltip_hide(); +void tooltip_hide(void* /*arg*/); #endif // TOOLTIP_H diff --git a/src/util/timer.c b/src/util/timer.c index 8ffadc8..6bb7578 100644 --- a/src/util/timer.c +++ b/src/util/timer.c @@ -21,9 +21,9 @@ #include "timer.h" GSList* timeout_list = 0; -struct timespec next_timeout; +struct timeval next_timeout; -void add_timeout_intern(int value_msec, int interval_msec, void(*_callback)(), struct timeout* t); +void add_timeout_intern(int value_msec, int interval_msec, void(*_callback)(void*), void* arg, 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); @@ -36,20 +36,27 @@ int timespec_subtract(struct timespec* result, struct timespec* x, struct timesp * is in the past to the current time. * As time measurement we use clock_gettime(CLOCK_MONOTONIC) because this refers to a timer, which * reference point lies somewhere in the past and cannot be changed, but just queried. + * If a single shot timer is installed it will be automatically deleted. I.e. the returned value + * of add_timeout will not be valid anymore. You do not need to call stop_timeout for these timeouts, + * however it's save to call it. **/ -const struct timeout* add_timeout(int value_msec, int interval_msec, void (*_callback)()) +const struct timeout* add_timeout(int value_msec, int interval_msec, void (*_callback)(void*), void* arg) { struct timeout* t = malloc(sizeof(struct timeout)); - add_timeout_intern(value_msec, interval_msec, _callback, t); + add_timeout_intern(value_msec, interval_msec, _callback, arg, t); return t; } -void change_timeout(const struct timeout *t, int value_msec, int interval_msec, void(*_callback)()) +void change_timeout(const struct timeout *t, int value_msec, int interval_msec, void(*_callback)(), void* arg) { - timeout_list = g_slist_remove(timeout_list, t); - add_timeout_intern(value_msec, interval_msec, _callback, (struct timeout*)t); + if ( g_slist_find(timeout_list, t) == 0 ) + printf("timeout already deleted..."); + else { + timeout_list = g_slist_remove(timeout_list, t); + add_timeout_intern(value_msec, interval_msec, _callback, arg, (struct timeout*)t); + } } @@ -58,10 +65,15 @@ void update_next_timeout() if (timeout_list) { struct timeout* t = timeout_list->data; struct timespec cur_time; + struct timespec next_timeout2 = { .tv_sec=next_timeout.tv_sec, .tv_nsec=next_timeout.tv_usec*1000 }; clock_gettime(CLOCK_MONOTONIC, &cur_time); - if (timespec_subtract(&next_timeout, &t->timeout_expires, &cur_time)) { + if (timespec_subtract(&next_timeout2, &t->timeout_expires, &cur_time)) { next_timeout.tv_sec = 0; - next_timeout.tv_nsec = 0; + next_timeout.tv_usec = 0; + } + else { + next_timeout.tv_sec = next_timeout2.tv_sec; + next_timeout.tv_usec = next_timeout2.tv_nsec/1000; } } else @@ -78,12 +90,12 @@ void callback_timeout_expired() t = timeout_list->data; if (compare_timespecs(&t->timeout_expires, &cur_time) <= 0) { // it's time for the callback function - t->_callback(); + t->_callback(t->arg); if (g_slist_find(timeout_list, t)) { // if _callback() calls stop_timeout(t) the timeout 't' was freed and is not in the timeout_list 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); + add_timeout_intern(t->interval_msec, t->interval_msec, t->_callback, t->arg, t); else free(t); } @@ -113,10 +125,11 @@ void stop_all_timeouts() } -void add_timeout_intern(int value_msec, int interval_msec, void(*_callback)(), struct timeout *t) +void add_timeout_intern(int value_msec, int interval_msec, void(*_callback)(), void* arg, struct timeout *t) { t->interval_msec = interval_msec; t->_callback = _callback; + t->arg = arg; struct timespec expire; clock_gettime(CLOCK_MONOTONIC, &expire); expire.tv_sec += value_msec / 1000; diff --git a/src/util/timer.h b/src/util/timer.h index 23aea08..b816918 100644 --- a/src/util/timer.h +++ b/src/util/timer.h @@ -22,13 +22,14 @@ #include extern GSList* timeout_list; -extern struct timespec next_timeout; +extern struct timeval next_timeout; struct timeout { int interval_msec; struct timespec timeout_expires; void (*_callback)(); + void* arg; }; @@ -36,9 +37,9 @@ struct timeout { /** 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)()); +const struct timeout* add_timeout(int value_msec, int interval_msec, void (*_callback)(void*), void* arg); -void change_timeout(const struct timeout* t, int value_msec, int interval_msec, void (*_callback)()); +void change_timeout(const struct timeout* t, int value_msec, int interval_msec, void (*_callback)(void*), void* arg); /** stops the timeout 't' **/ void stop_timeout(const struct timeout* t); -- 2.44.0