From: Dana Jansens Date: Thu, 6 Mar 2008 14:27:18 +0000 (-0500) Subject: super fading X-Git-Url: http://git.openbox.org/?a=commitdiff_plain;h=699ebccab94d077dc26c0a5f7c5174e4feee6f55;p=dana%2Fdcompmgr.git super fading --- diff --git a/dcompmgr.c b/dcompmgr.c index f6b7019..71f3eee 100644 --- a/dcompmgr.c +++ b/dcompmgr.c @@ -6,7 +6,10 @@ #include "display.h" #include "gettext.h" #include "time.h" + +/* these can be plugins */ #include "render.h" +#include "fade.h" #include #include @@ -76,8 +79,10 @@ event(d_display_t *dpy) if (!sc) break; w = screen_find_window(sc, dev->window); vis = window_is_mapped(w); - if (vis) + if (vis) { + sc->window_become_zombie(w); sc->window_hide(w); + } screen_remove_window(sc, w); if (vis) screen_refresh(sc); break; @@ -95,8 +100,10 @@ event(d_display_t *dpy) if (rev->parent == sc->super.root) screen_add_window(sc, rev->window); else { - if (window_is_mapped(w)) + if (window_is_mapped(w)) { + sc->window_become_zombie(w); sc->window_hide(w); + } screen_remove_window(sc, w); } screen_refresh(sc); @@ -126,6 +133,7 @@ event(d_display_t *dpy) sc = display_screen_from_root(dpy, mev->event); if (!sc) break; w = screen_find_window(sc, mev->window); + sc->window_become_zombie(w); sc->window_hide(w); screen_refresh(w->sc); break; @@ -257,6 +265,22 @@ event(d_display_t *dpy) } } +static void +timeouts(d_display_t *dpy) +{ + d_list_it_t *it; + struct timeval now; + + gettimeofday(&now, NULL); + + for (it = list_top(dpy->screens); it; it = it->next) { + d_screen_t *sc = it->data; + + render_timeout(sc, &now); + fade_timeout(sc, &now); + } +} + static void paint(d_display_t *dpy) { @@ -278,17 +302,38 @@ run(d_display_t *dpy) { while (!quit) { struct timeval next, now, *wait; - int r, npaint; + int r, npaint, ntime; d_list_it_t *it; fd_set fds; event(dpy); npaint = 0; + ntime = 0; for (it = list_top(dpy->screens); it; it = it->next) { d_screen_t *sc = it->data; + struct timeval next_timeout; + + if (render_next_timeout(sc, &next_timeout)) { + if ((!npaint && !ntime) || + time_compare(&next_timeout, &next) < 0) + { + next = next_timeout; + ++ntime; + } + } + if (fade_next_timeout(sc, &next_timeout)) { + if ((!npaint && !ntime) || + time_compare(&next_timeout, &next) < 0) + { + next = next_timeout; + ++ntime; + } + } + if (sc->need_repaint && - (!npaint || time_compare(&sc->next_repaint, &next) < 0)) + ((!npaint && !ntime) || + time_compare(&sc->next_repaint, &next) < 0)) { next = sc->next_repaint; ++npaint; @@ -297,7 +342,7 @@ run(d_display_t *dpy) gettimeofday(&now, 0); - if (!npaint) + if (!npaint && !ntime) /* wait forever, there is nothing that needs drawing */ wait = NULL; else if (time_compare(&next, &now) > 0) { @@ -306,9 +351,9 @@ run(d_display_t *dpy) wait = &next; } else { - /* don't wait cuz a redraw is due now already */ + /* don't wait cuz a timer is due now already */ next.tv_sec = 0; - next.tv_usec = 100; + next.tv_usec = 0; wait = &next; } @@ -320,6 +365,7 @@ run(d_display_t *dpy) r = select(dpy->fd+1, &fds, NULL, NULL, wait); if (r == 0) { //printf("select timeout\n"); + timeouts(dpy); paint(dpy); xcb_flush(dpy->conn); } @@ -342,6 +388,7 @@ setup_functions(d_display_t *dpy) /* these can be plugins.. */ id = 1; render_init(sc, id++); + fade_init(sc, id++); } } @@ -354,6 +401,7 @@ cleanup_functions(d_display_t *dpy) d_screen_t *sc = it->data; /* these can be plugins.. */ + fade_free(sc); render_free(sc); } } diff --git a/fade.c b/fade.c new file mode 100644 index 0000000..40e698e --- /dev/null +++ b/fade.c @@ -0,0 +1,229 @@ +#include "efence.h" + +#include "render.h" +#include "screen.h" +#include "window.h" +#include "time.h" +#include "display.h" +#include "list.h" +#include +#include +#include +#include + +static int plugin_id; + +typedef struct { + void (*window_show)(d_window_t *w); + void (*window_hide)(d_window_t *w); + d_list_t *fades; + +// unsigned int fade_step_size; + unsigned int fade_step_time; + unsigned int fade_total_time; + + struct timeval next_timeout; +} data_t; + +typedef struct { + d_window_t *w; + uint16_t start; + uint16_t end; + uint16_t current; + struct timeval start_time; + struct timeval end_time; +} fade_t; + +static void fade_window_show(d_window_t *w); +static void fade_window_hide(d_window_t *w); +static void start_fade(d_window_t *w, uint16_t start, uint16_t end); + +void +fade_init(d_screen_t *sc, int id) +{ + plugin_id = id; + + data_t *d = malloc(sizeof(data_t)); + d->window_show = sc->window_show; + d->window_hide = sc->window_hide; + screen_add_plugin_data(sc, plugin_id, d); + + sc->window_show = fade_window_show; + sc->window_hide = fade_window_hide; + + d->fades = list_new(); + d->fade_step_time = 10000; /* 10 milliseconds */ + d->fade_total_time = 200000; /* 0.15 seconds */ +} + +void +fade_free(d_screen_t *sc) +{ + data_t *d; + d_list_it_t *it; + + d = screen_find_plugin_data(sc, plugin_id); + screen_remove_plugin_data(sc, plugin_id); + + for (it = list_top(d->fades); it; it = it->next) { + fade_t *fade = it->data; + window_set_opacity(fade->w, 0xffff); + window_zombie_unref(fade->w); + window_unref(fade->w); + free(fade); + } + list_unref(d->fades); + free(d); +} + +static void +fade_window_show(d_window_t *w) +{ + data_t *d; + + if (!window_is_input_only(w)) + start_fade(w, 0, 0xffff); + + d = screen_find_plugin_data(w->sc, plugin_id); + d->window_show(w); +} + +static void +fade_window_hide(d_window_t *w) +{ + data_t *d; + + if (!window_is_input_only(w)) + start_fade(w, 0xffff, 0); + + d = screen_find_plugin_data(w->sc, plugin_id); + d->window_hide(w); +} + +static void +start_fade(d_window_t *w, uint16_t start, uint16_t end) +{ + data_t *d; + d_list_it_t *it; + fade_t *fade; + gboolean newfade; + struct timeval now; + + d = screen_find_plugin_data(w->sc, plugin_id); + gettimeofday(&now, NULL); + + if (list_length(d->fades) == 0) { + d->next_timeout = now; + time_add(&d->next_timeout, d->fade_step_time); + } + + /* look for an existing one */ + fade = NULL; + for (it = list_top(d->fades); it; it = it->next) { + fade = it->data; + if (fade->w == w) break; + } + if (!it) { + fade = malloc(sizeof(fade_t)); + fade->w = w; + list_append(d->fades, fade); + newfade = TRUE; + } + else + newfade = FALSE; + + fade->start = start; + fade->end = end; + + if (newfade) { + fade->start_time = now; + fade->end_time = now; + time_add(&fade->end_time, d->fade_total_time); + fade->current = start; + + window_set_opacity(w, fade->current); + + window_ref(w); + window_zombie_ref(w); + } + else { + /* figure out how far we have to go to finish the fade from where + we are from the previous fade */ + long remain, total; + double percent; + + total = ABS(fade->end - fade->start); + remain = ABS(fade->current - fade->end); + percent = (double)remain / total; + + //printf("start %d end %d current %d\n", fade->start, fade->end, + // fade->current); + //printf("remain %lu total %lu percent %f\n", remain, total, percent); + + fade->start_time = now; + time_add(&fade->start_time, -(1-percent)*d->fade_total_time); + fade->end_time = now; + time_add(&fade->end_time, percent*d->fade_total_time); + } +} + +int +fade_next_timeout(struct d_screen *sc, struct timeval *tv) +{ + data_t *d; + + d = screen_find_plugin_data(sc, plugin_id); + + if (list_length(d->fades) == 0) + return FALSE; + else { + *tv = d->next_timeout; + return TRUE; + } +} + +void +fade_timeout(struct d_screen *sc, const struct timeval *now) +{ + data_t *d; + d_list_it_t *it, *next; + + d = screen_find_plugin_data(sc, plugin_id); + + for (it = list_top(d->fades); it; it = next) { + fade_t *fade = it->data; + struct timeval time_done, total_time; + unsigned long done, total; + double percent; + + next = it->next; + + time_difference(now, &fade->start_time, &time_done); + time_difference(&fade->end_time, &fade->start_time, &total_time); + + /* count milliseconds */ + done = time_done.tv_sec * 1000 + time_done.tv_usec / 1000; + total = total_time.tv_sec * 1000 + total_time.tv_usec / 1000; + percent = (double)done / total; + + //printf("done %lu total %lu percent %f\n", done, total, percent); + + if (percent >= 1) + fade->current = fade->end; + else if (fade->end > fade->start) + fade->current = fade->start + (fade->end - fade->start) * percent; + else + fade->current = fade->start - (fade->start - fade->end) * percent; + + window_set_opacity(fade->w, fade->current); + + if (fade->current == fade->end) { + list_delete_link(d->fades, it); + window_zombie_unref(fade->w); + window_unref(fade->w); + + g_free(fade); + } + } + time_add(&d->next_timeout, d->fade_step_time); +} diff --git a/fade.h b/fade.h new file mode 100644 index 0000000..3acf46d --- /dev/null +++ b/fade.h @@ -0,0 +1,13 @@ +#ifndef dc__fade_h +#define dc__fade_h + +#include + +struct d_screen; + +void fade_init(struct d_screen *sc, int id); +void fade_free(struct d_screen *sc); +int fade_next_timeout(struct d_screen *sc, struct timeval *tv); +void fade_timeout(struct d_screen *sc, const struct timeval *now); + +#endif diff --git a/render.c b/render.c index 795d824..113070e 100644 --- a/render.c +++ b/render.c @@ -16,7 +16,7 @@ typedef struct { void (*screen_paint)(d_screen_t *sc); void (*screen_root_pixmap_change)(d_screen_t *sc); void (*window_show)(d_window_t *w); - void (*window_hide)(d_window_t *w); + void (*window_zombie_dead)(d_window_t *w); void (*window_resize)(d_window_t *w); void (*window_opacity_change)(d_window_t *w); @@ -64,7 +64,7 @@ static xcb_render_picture_t solid_picture(data_t *d, d_screen_t *sc, uint16_t g, uint16_t b); static void render_window_show(d_window_t *window); -static void render_window_hide(d_window_t *window); +static void render_window_zombie_dead(d_window_t *window); static void render_window_resize(d_window_t *window); static void render_window_opacity_change(d_window_t *w); @@ -81,7 +81,7 @@ render_init(d_screen_t *sc, int id) d->screen_paint = sc->screen_paint; d->screen_root_pixmap_change = sc->screen_root_pixmap_change; d->window_show = sc->window_show; - d->window_hide = sc->window_hide; + d->window_zombie_dead = sc->window_zombie_dead; d->window_resize = sc->window_resize; d->window_opacity_change = sc->window_opacity_change; screen_add_plugin_data(sc, plugin_id, d); @@ -89,7 +89,7 @@ render_init(d_screen_t *sc, int id) sc->screen_paint = render_paint; sc->screen_root_pixmap_change = render_root_pixmap_change; sc->window_show = render_window_show; - sc->window_hide = render_window_hide; + sc->window_zombie_dead = render_window_zombie_dead; sc->window_resize = render_window_resize; sc->window_opacity_change = render_window_opacity_change; @@ -150,6 +150,20 @@ render_free(d_screen_t *sc) screen_remove_plugin_data(sc, plugin_id); } +int +render_next_timeout(struct d_screen *sc, struct timeval *tv) +{ + (void)sc; + (void)tv; + return FALSE; +} + +void +render_timeout(struct d_screen *sc, const struct timeval *now) +{ + (void)sc; (void)now; +} + void render_window_free(d_window_t *w, window_data_t *wd) { @@ -188,12 +202,10 @@ render_window_show(d_window_t *w) render_update_shadow_picture(w, d, wd); window_add_plugin_data(w, plugin_id, wd); - - window_ref(w); } static void -render_window_hide(d_window_t *w) +render_window_zombie_dead(d_window_t *w) { data_t *d; window_data_t *wd; @@ -207,7 +219,7 @@ render_window_hide(d_window_t *w) } /* pass it on */ - d->window_hide(w); + d->window_zombie_dead(w); } static xcb_render_picture_t @@ -410,7 +422,8 @@ render_paint(d_screen_t *sc) window_get_area(w, &x, &y, &width, &height, &bwidth); - if (!window_is_input_only(w) && window_is_mapped(w) && + if (!window_is_input_only(w) && + (window_is_mapped(w) || window_is_zombie(w)) && x < sc->super.width_in_pixels && y < sc->super.height_in_pixels && x + width > 0 && y + height > 0) @@ -455,7 +468,8 @@ render_paint(d_screen_t *sc) window_get_area(w, &x, &y, &width, &height, &bwidth); - if (!window_is_input_only(w) && window_is_mapped(w) && + if (!window_is_input_only(w) && + (window_is_mapped(w) || window_is_zombie(w)) && x < sc->super.width_in_pixels && y < sc->super.height_in_pixels && (x + width > 0 || x + width + d->xshadowoff > 0) && diff --git a/render.h b/render.h index 0885883..48a84b1 100644 --- a/render.h +++ b/render.h @@ -1,9 +1,13 @@ #ifndef dc__render_h #define dc__render_h +#include + struct d_screen; void render_init(struct d_screen *sc, int id); void render_free(struct d_screen *sc); +int render_next_timeout(struct d_screen *sc, struct timeval *tv); +void render_timeout(struct d_screen *sc, const struct timeval *now); #endif diff --git a/screen.c b/screen.c index 1633f6a..af7772d 100644 --- a/screen.c +++ b/screen.c @@ -284,7 +284,6 @@ screen_remove_window(d_screen_t *sc, struct d_window *w) window_destroy_damage(w); g_hash_table_remove(sc->winhash, &w->id); - sc->window_become_zombie(w); window_unref(w); } @@ -327,7 +326,7 @@ screen_timestamp(d_screen_t *sc) break; } } - printf("created timestamp %lu\n", (unsigned long) time); + //printf("created timestamp %lu\n", (unsigned long) time); return time; } @@ -381,6 +380,7 @@ screen_setup_default_functions(d_screen_t *sc) sc->window_show = window_show; sc->window_hide = window_hide; sc->window_become_zombie = window_become_zombie; + sc->window_zombie_dead = window_zombie_dead; sc->window_move = window_move; sc->window_resize = window_resize; sc->window_reshape = window_reshape; @@ -428,7 +428,7 @@ screen_get_root_pixmap(d_screen_t *sc) if (rep->type == sc->dpy->a.pixmap && rep->length >= 1) { sc->root_pixmap = ((xcb_pixmap_t*)xcb_get_property_value(rep))[0]; - printf("got root pixmap 0x%x\n", sc->root_pixmap); + //printf("got root pixmap 0x%x\n", sc->root_pixmap); } free(rep); } diff --git a/screen.h b/screen.h index 16e0ad5..15ef143 100644 --- a/screen.h +++ b/screen.h @@ -37,6 +37,7 @@ typedef struct d_screen { void (*window_show)(struct d_window *w); void (*window_hide)(struct d_window *w); void (*window_become_zombie)(struct d_window *w); + void (*window_zombie_dead)(struct d_window *w); void (*window_move)(struct d_window *w); void (*window_resize)(struct d_window *w); void (*window_reshape)(struct d_window *w); diff --git a/time.c b/time.c index a90b1cd..889fdd7 100644 --- a/time.c +++ b/time.c @@ -21,7 +21,7 @@ time_add(struct timeval *tv, long microseconds) } long -time_compare(struct timeval *a, struct timeval *b) +time_compare(const struct timeval *a, const struct timeval *b) { long r; if ((r = a->tv_sec - b->tv_sec)) return r; @@ -29,7 +29,8 @@ time_compare(struct timeval *a, struct timeval *b) } void -time_difference(struct timeval *a, struct timeval *b, struct timeval *r) +time_difference(const struct timeval *a, const struct timeval *b, + struct timeval *r) { struct timeval v; v.tv_sec = a->tv_sec - b->tv_sec; diff --git a/time.h b/time.h index 24cd3f0..c487e77 100644 --- a/time.h +++ b/time.h @@ -4,7 +4,8 @@ #include void time_add(struct timeval *tv, long microseconds); -long time_compare(struct timeval *a, struct timeval *b); -void time_difference(struct timeval *a, struct timeval *b, struct timeval *r); +long time_compare(const struct timeval *a, const struct timeval *b); +void time_difference(const struct timeval *a, const struct timeval *b, + struct timeval *r); #endif diff --git a/window.c b/window.c index 8d420ee..fb26a59 100644 --- a/window.c +++ b/window.c @@ -20,6 +20,7 @@ typedef struct { /* private stuff */ int ref; + int zombieref; /* queried things, don't read them directly from the struct */ int x, y, w, h, bw; @@ -68,6 +69,7 @@ window_new(xcb_window_t id, struct d_screen *sc) w = malloc(sizeof(d_window_priv_t)); w->id = id; w->ref = 1; + w->zombieref = 0; w->sc = sc; w->zombie = FALSE; w->mapped = FALSE; @@ -109,17 +111,9 @@ window_unref(d_window_t *pubw) if (w && --w->ref == 0) { screen_stacking_remove(w->sc, (d_window_t*)w); - if (w->region) { - xcb_xfixes_destroy_region(w->sc->dpy->conn, w->region); - w->region = XCB_NONE; - } - - if (w->pixmap) { - /* this may cause an error if the pixmap was never valid, but - that's fine */ - xcb_free_pixmap(w->sc->dpy->conn, w->pixmap); - w->pixmap = XCB_NONE; - } + assert(w->zombieref == 0); + while (w->zombieref) + window_zombie_unref(pubw); list_unref(w->plugin_data); free(w); @@ -213,6 +207,9 @@ window_show(d_window_t *pubw) window_update_user_opacity(pubw); window_update_type(w); w->mapped = TRUE; + + /* hold one reference for ourselves */ + window_zombie_ref(pubw); } void @@ -231,6 +228,9 @@ window_hide(d_window_t *pubw) XCB_CW_EVENT_MASK, &mask); w->mapped = FALSE; + + /* try to free zombie things */ + window_zombie_unref(pubw); } void @@ -251,6 +251,16 @@ window_become_zombie(d_window_t *pubw) w->zombie = TRUE; } +void +window_zombie_dead(d_window_t *pubw) +{ + d_window_priv_t *w = (d_window_priv_t*)pubw; + + if (!w->zombie) return; + + w->zombie = FALSE; +} + gboolean window_is_zombie(d_window_t *pubw) { @@ -586,8 +596,7 @@ window_update_type(d_window_priv_t *w) w->type = DC_WINDOW_TYPE_NORMAL; w->client = w->id; } - - printf("window 0x%x type %d\n", w->id, w->type); + //printf("window 0x%x type %d\n", w->id, w->type); } d_window_type_t @@ -631,6 +640,41 @@ window_set_opacity(d_window_t *pubw, uint16_t o) d_window_priv_t *w = (d_window_priv_t*)pubw; w->opacity = o; - if (w->mapped) + if (w->mapped || w->zombie) { w->sc->window_opacity_change(pubw); + screen_refresh(w->sc); + } + //printf("mapped %d opacity 0x%x\n", w->mapped, w->opacity); +} + +void +window_zombie_ref(d_window_t *pubw) +{ + d_window_priv_t *w = (d_window_priv_t*)pubw; + + ++w->zombieref; +} + +void +window_zombie_unref(d_window_t *pubw) +{ + d_window_priv_t *w = (d_window_priv_t*)pubw; + + if (--w->zombieref == 0) { + w->zombie = FALSE; + + if (w->region) { + xcb_xfixes_destroy_region(w->sc->dpy->conn, w->region); + w->region = XCB_NONE; + } + + if (w->pixmap) { + /* this may cause an error if the pixmap was never valid, but + that's fine */ + xcb_free_pixmap(w->sc->dpy->conn, w->pixmap); + w->pixmap = XCB_NONE; + } + + w->sc->window_zombie_dead(pubw); + } } diff --git a/window.h b/window.h index 6d0bc50..9787f84 100644 --- a/window.h +++ b/window.h @@ -40,6 +40,7 @@ void window_hide(d_window_t *w); void window_fake_unmapped(d_window_t *w); void window_become_zombie(d_window_t *w); +void window_zombie_dead(d_window_t *w); void window_configure(d_window_t *w, int x, int y, int width, int height, int border_width); @@ -75,4 +76,7 @@ d_window_type_t window_get_type(d_window_t *w); uint16_t window_get_opacity(d_window_t *w); void window_set_opacity(d_window_t *w, uint16_t o); +void window_zombie_ref(d_window_t *w); +void window_zombie_unref(d_window_t *w); + #endif