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