#include "display.h"
#include "gettext.h"
#include "time.h"
+
+/* these can be plugins */
#include "render.h"
+#include "fade.h"
#include <glib.h>
#include <stdio.h>
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;
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);
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;
}
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)
{
d_list_it_t *it;
{
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;
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) {
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;
}
r = select(dpy->fd+1, &fds, NULL, NULL, wait);
if (r == 0) {
//printf("select timeout\n");
+ timeouts(dpy);
paint(dpy);
xcb_flush(dpy->conn);
}
/* these can be plugins.. */
id = 1;
render_init(sc, id++);
+ fade_init(sc, id++);
}
}
d_screen_t *sc = it->data;
/* these can be plugins.. */
+ fade_free(sc);
render_free(sc);
}
}
--- /dev/null
+#include "efence.h"
+
+#include "render.h"
+#include "screen.h"
+#include "window.h"
+#include "time.h"
+#include "display.h"
+#include "list.h"
+#include <stdio.h>
+#include <assert.h>
+#include <stdlib.h>
+#include <xcb/render.h>
+
+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);
+}
--- /dev/null
+#ifndef dc__fade_h
+#define dc__fade_h
+
+#include <sys/time.h>
+
+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
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);
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);
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);
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;
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)
{
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;
}
/* pass it on */
- d->window_hide(w);
+ d->window_zombie_dead(w);
}
static xcb_render_picture_t
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)
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) &&
#ifndef dc__render_h
#define dc__render_h
+#include <sys/time.h>
+
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
window_destroy_damage(w);
g_hash_table_remove(sc->winhash, &w->id);
- sc->window_become_zombie(w);
window_unref(w);
}
break;
}
}
- printf("created timestamp %lu\n", (unsigned long) time);
+ //printf("created timestamp %lu\n", (unsigned long) time);
return time;
}
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;
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);
}
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);
}
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;
}
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;
#include <sys/time.h>
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
/* private stuff */
int ref;
+ int zombieref;
/* queried things, don't read them directly from the struct */
int x, y, w, h, bw;
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;
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);
window_update_user_opacity(pubw);
window_update_type(w);
w->mapped = TRUE;
+
+ /* hold one reference for ourselves */
+ window_zombie_ref(pubw);
}
void
XCB_CW_EVENT_MASK, &mask);
w->mapped = FALSE;
+
+ /* try to free zombie things */
+ window_zombie_unref(pubw);
}
void
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)
{
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
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);
+ }
}
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);
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