make sure that when a window is shown it stops being a zombie
[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_alpha;
31     uint16_t    end_alpha;
32     uint16_t    current_alpha;
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_alpha, uint16_t end_alpha,
40                        gboolean refalways);
41
42 void
43 fade_init(d_screen_t *sc, int id)
44 {
45     plugin_id = id;
46
47     data_t *d = malloc(sizeof(data_t));
48     d->window_show = sc->window_show;
49     d->window_hide = sc->window_hide;
50     screen_add_plugin_data(sc, plugin_id, d);
51
52     sc->window_show = fade_window_show;
53     sc->window_hide = fade_window_hide;
54
55     d->fades = list_new();
56     d->fade_step_time = 5000;     /* 5 milliseconds */
57     d->fade_total_time = 180000;  /* 0.18 seconds */
58 }
59
60 void
61 fade_free(d_screen_t *sc)
62 {
63     data_t *d;
64     d_list_it_t *it;
65
66     d = screen_find_plugin_data(sc, plugin_id);
67     screen_remove_plugin_data(sc, plugin_id);
68
69     for (it = list_top(d->fades); it; it = it->next) {
70         fade_t *fade = it->data;
71         window_set_opacity(fade->w, 0xffff);
72         window_zombie_unref(fade->w);
73         window_unref(fade->w);
74         free(fade);
75     }
76     list_unref(d->fades);
77     free(d);
78 }
79
80 static void
81 fade_window_show(d_window_t *w)
82 {
83     data_t *d;
84     d_list_it_t *it;
85
86     d = screen_find_plugin_data(w->sc, plugin_id);
87
88     /* kill the zombies off cuz a new copy is being shown */
89     for (it = list_top(d->fades); it; it = it->next) {
90         fade_t *fade = it->data;
91         if (fade->w == w) {
92             window_zombie_unref(w);
93             window_unref(w);
94             break;
95         }
96     }
97
98     d->window_show(w);    
99
100     if (!window_is_input_only(w))
101         start_fade(w, 0x2000, 0xffff, TRUE);
102 }
103
104 static void
105 fade_window_hide(d_window_t *w)
106 {
107     data_t *d;
108
109     if (!window_is_input_only(w))
110         start_fade(w, 0xffff, 0x0002, FALSE);
111
112     d = screen_find_plugin_data(w->sc, plugin_id);
113     d->window_hide(w);
114 }
115
116 static void
117 start_fade(d_window_t *w, uint16_t start_alpha, uint16_t end_alpha,
118            gboolean refalways)
119 {
120     data_t *d;
121     d_list_it_t *it;
122     fade_t *fade;
123     gboolean newfade;
124     struct timeval now;
125
126     d = screen_find_plugin_data(w->sc, plugin_id);
127     gettimeofday(&now, NULL);
128
129     if (list_length(d->fades) == 0) {
130         d->next_timeout = now;
131         time_add(&d->next_timeout, d->fade_step_time);
132     }
133
134     /* look for an existing one */
135     fade = NULL;
136     for (it = list_top(d->fades); it; it = it->next) {
137         fade = it->data;
138         if (fade->w == w) break;
139     }
140     if (!it) {
141         fade = malloc(sizeof(fade_t));
142         fade->w = w;
143         list_append(d->fades, fade);
144         newfade = TRUE;
145     }
146     else
147         newfade = FALSE;
148
149     fade->start_alpha = start_alpha;
150     fade->end_alpha = end_alpha;
151
152     if (newfade) {
153         fade->start_time = now;
154         fade->end_time = now;
155         time_add(&fade->end_time, d->fade_total_time);
156         fade->current_alpha = start_alpha;
157
158         window_set_opacity(w, fade->current_alpha);
159     }
160     else {
161         /* figure out how far we have to go to finish the fade from where
162            we are from the previous fade */
163         long remain, total;
164         double percent;
165
166         total = ABS(fade->end_alpha - fade->start_alpha);
167         remain = ABS(fade->current_alpha - fade->end_alpha);
168         percent = (double)remain / total;
169
170         //printf("start %d end %d current %d\n", fade->start, fade->end,
171         //       fade->current);
172         //printf("remain %lu total %lu percent %f\n", remain, total, percent);
173
174         fade->start_time = now;
175         time_add(&fade->start_time, -(1-percent)*d->fade_total_time);
176         fade->end_time = now;
177         time_add(&fade->end_time, percent*d->fade_total_time);
178     }
179     if (newfade || refalways) {
180         window_zombie_ref(w);
181         window_ref(w);
182     }
183 }
184
185 int
186 fade_next_timeout(struct d_screen *sc, struct timeval *tv)
187 {
188     data_t *d;
189
190     d = screen_find_plugin_data(sc, plugin_id);
191
192     if (list_length(d->fades) == 0)
193         return FALSE;
194     else {
195         *tv = d->next_timeout;
196         return TRUE;
197     }
198 }
199
200 void
201 fade_timeout(struct d_screen *sc, const struct timeval *now)
202 {
203     data_t *d;
204     d_list_it_t *it, *next;
205
206     d = screen_find_plugin_data(sc, plugin_id);
207
208     for (it = list_top(d->fades); it; it = next) {
209         fade_t *fade = it->data;
210
211         next = it->next;
212
213         if (time_compare(&fade->end_time, now) <= 0) {
214             /* done */
215             fade->current_alpha = fade->end_alpha;
216         }
217         else {
218             struct timeval total_time, time_left;
219             unsigned long remain, total;
220             double percent;
221
222             time_difference(&fade->end_time, now, &time_left);
223             time_difference(&fade->end_time, &fade->start_time, &total_time);
224
225
226             /* count milliseconds */
227             remain = time_left.tv_sec * 1000 + time_left.tv_usec / 1000;
228             total = total_time.tv_sec * 1000 + total_time.tv_usec / 1000;
229             percent = (double)remain / total;
230
231             //printf("done %lu total %lu percent %f\n", done, total, percent);
232
233             if (fade->end_alpha > fade->start_alpha)
234                 /* increasing */
235                 fade->current_alpha = fade->end_alpha -
236                     (fade->end_alpha - fade->start_alpha) * percent;
237             else
238                 /* decreasing */
239                 fade->current_alpha = fade->end_alpha +
240                     (fade->start_alpha - fade->end_alpha) * percent;
241         }
242
243         window_set_opacity(fade->w, fade->current_alpha);
244
245         if (fade->current_alpha == fade->end_alpha) {
246             list_delete_link(d->fades, it);
247             window_zombie_unref(fade->w);
248             window_unref(fade->w);
249
250             g_free(fade);
251         }
252     }
253     d->next_timeout = *now;
254     time_add(&d->next_timeout, d->fade_step_time);
255 }