make fades a little faster
[dana/dcompmgr.git] / fade.c
1 #include "efence.h"
2
3 #include "render.h"
4 #include "screen.h"
5 #include "window.h"
6 #include "time.h"
7 #include "display.h"
8 #include "list.h"
9 #include <stdio.h>
10 #include <assert.h>
11 #include <stdlib.h>
12 #include <xcb/render.h>
13
14 static int plugin_id;
15
16 typedef struct {
17     void (*window_show)(d_window_t *w);
18     void (*window_hide)(d_window_t *w);
19     d_list_t *fades;
20
21 //    unsigned int fade_step_size;
22     unsigned int fade_step_time;
23     unsigned int fade_total_time;
24
25     struct timeval next_timeout;
26 } data_t;
27
28 typedef struct {
29     d_window_t *w;
30     uint16_t    start;
31     uint16_t    end;
32     uint16_t    current;
33     struct timeval start_time;
34     struct timeval end_time;
35 } fade_t;
36
37 static void fade_window_show(d_window_t *w);
38 static void fade_window_hide(d_window_t *w);
39 static void start_fade(d_window_t *w, uint16_t start, uint16_t end);
40
41 void
42 fade_init(d_screen_t *sc, int id)
43 {
44     plugin_id = id;
45
46     data_t *d = malloc(sizeof(data_t));
47     d->window_show = sc->window_show;
48     d->window_hide = sc->window_hide;
49     screen_add_plugin_data(sc, plugin_id, d);
50
51     sc->window_show = fade_window_show;
52     sc->window_hide = fade_window_hide;
53
54     d->fades = list_new();
55     d->fade_step_time = 5000;     /* 5 milliseconds */
56     d->fade_total_time = 150000;  /* 0.15 seconds */
57 }
58
59 void
60 fade_free(d_screen_t *sc)
61 {
62     data_t *d;
63     d_list_it_t *it;
64
65     d = screen_find_plugin_data(sc, plugin_id);
66     screen_remove_plugin_data(sc, plugin_id);
67
68     for (it = list_top(d->fades); it; it = it->next) {
69         fade_t *fade = it->data;
70         window_set_opacity(fade->w, 0xffff);
71         window_zombie_unref(fade->w);
72         window_unref(fade->w);
73         free(fade);
74     }
75     list_unref(d->fades);
76     free(d);
77 }
78
79 static void
80 fade_window_show(d_window_t *w)
81 {
82     data_t *d;
83
84     if (!window_is_input_only(w))
85         start_fade(w, 0, 0xffff);
86
87     d = screen_find_plugin_data(w->sc, plugin_id);
88     d->window_show(w);    
89 }
90
91 static void
92 fade_window_hide(d_window_t *w)
93 {
94     data_t *d;
95
96     if (!window_is_input_only(w))
97         start_fade(w, 0xffff, 0);
98
99     d = screen_find_plugin_data(w->sc, plugin_id);
100     d->window_hide(w);
101 }
102
103 static void
104 start_fade(d_window_t *w, uint16_t start, uint16_t end)
105 {
106     data_t *d;
107     d_list_it_t *it;
108     fade_t *fade;
109     gboolean newfade;
110     struct timeval now;
111
112     d = screen_find_plugin_data(w->sc, plugin_id);
113     gettimeofday(&now, NULL);
114
115     if (list_length(d->fades) == 0) {
116         d->next_timeout = now;
117         time_add(&d->next_timeout, d->fade_step_time);
118     }
119
120     /* look for an existing one */
121     fade = NULL;
122     for (it = list_top(d->fades); it; it = it->next) {
123         fade = it->data;
124         if (fade->w == w) break;
125     }
126     if (!it) {
127         fade = malloc(sizeof(fade_t));
128         fade->w = w;
129         list_append(d->fades, fade);
130         newfade = TRUE;
131     }
132     else
133         newfade = FALSE;
134
135     fade->start = start;
136     fade->end = end;
137
138     if (newfade) {
139         fade->start_time = now;
140         fade->end_time = now;
141         time_add(&fade->end_time, d->fade_total_time);
142         fade->current = start;
143
144         window_set_opacity(w, fade->current);
145
146         window_ref(w);
147         window_zombie_ref(w);
148     }
149     else {
150         /* figure out how far we have to go to finish the fade from where
151            we are from the previous fade */
152         long remain, total;
153         double percent;
154
155         total = ABS(fade->end - fade->start);
156         remain = ABS(fade->current - fade->end);
157         percent = (double)remain / total;
158
159         //printf("start %d end %d current %d\n", fade->start, fade->end,
160         //       fade->current);
161         //printf("remain %lu total %lu percent %f\n", remain, total, percent);
162
163         fade->start_time = now;
164         time_add(&fade->start_time, -(1-percent)*d->fade_total_time);
165         fade->end_time = now;
166         time_add(&fade->end_time, percent*d->fade_total_time);
167     }
168 }
169
170 int
171 fade_next_timeout(struct d_screen *sc, struct timeval *tv)
172 {
173     data_t *d;
174
175     d = screen_find_plugin_data(sc, plugin_id);
176
177     if (list_length(d->fades) == 0)
178         return FALSE;
179     else {
180         *tv = d->next_timeout;
181         return TRUE;
182     }
183 }
184
185 void
186 fade_timeout(struct d_screen *sc, const struct timeval *now)
187 {
188     data_t *d;
189     d_list_it_t *it, *next;
190
191     d = screen_find_plugin_data(sc, plugin_id);
192
193     for (it = list_top(d->fades); it; it = next) {
194         fade_t *fade = it->data;
195         struct timeval time_done, total_time;
196         unsigned long done, total;
197         double percent;
198
199         next = it->next;
200
201         time_difference(now, &fade->start_time, &time_done);
202         time_difference(&fade->end_time, &fade->start_time, &total_time);
203
204         /* count milliseconds */
205         done = time_done.tv_sec * 1000 + time_done.tv_usec / 1000;
206         total = total_time.tv_sec * 1000 + total_time.tv_usec / 1000;
207         percent = (double)done / total;
208
209         //printf("done %lu total %lu percent %f\n", done, total, percent);
210
211         if (percent >= 1)
212             fade->current = fade->end;
213         else if (fade->end > fade->start)
214             fade->current = fade->start + (fade->end - fade->start) * percent;
215         else
216             fade->current = fade->start - (fade->start - fade->end) * percent;
217
218         window_set_opacity(fade->w, fade->current);
219
220         if (fade->current == fade->end) {
221             list_delete_link(d->fades, it);
222             window_zombie_unref(fade->w);
223             window_unref(fade->w);
224
225             g_free(fade);
226         }
227     }
228     time_add(&d->next_timeout, d->fade_step_time);
229 }