initialize gl on the overlay window
[dana/dcompmgr.git] / dcompmgr.c
1 #include "efence.h"
2
3 #include "screen.h"
4 #include "window.h"
5 #include "list.h"
6 #include "display.h"
7 #include "gettext.h"
8 #include "time.h"
9
10 /* these can be plugins */
11 #include "render.h"
12 #include "glxrender.h"
13 #include "fade.h"
14
15 #include <glib.h>
16 #include <stdio.h>
17 #include <sys/select.h>
18 #include <stdlib.h>
19 #include <string.h>
20 #include <signal.h>
21 #include <xcb/xcb.h>
22 #include <xcb/damage.h>
23 #include <xcb/shape.h>
24
25 typedef struct {
26     int foo;
27 } d_options_t;
28
29 static gboolean quit = FALSE;
30 static gboolean running = FALSE;
31
32 static void
33 read_options(int argc, char **argv, d_options_t *opts)
34 {
35     opts->foo = argc && argv;
36 }
37
38 static void
39 signal_quit_handler(int sig)
40 {
41     printf("caught signal %d, quitting\n", sig);
42     quit = TRUE;
43 }
44
45 static void
46 event(d_display_t *dpy)
47 {
48     xcb_generic_event_t *ev;
49
50     while ((ev = xcb_poll_for_event(dpy->conn)) && !quit) {
51         //printf("event %d\n", ev->response_type);
52
53         if (!ev->response_type) {
54             display_error(dpy, (xcb_generic_error_t*)ev);
55             free(ev);
56             continue;
57         }
58
59         switch (ev->response_type) {
60         case XCB_CREATE_NOTIFY:
61         {
62             xcb_create_notify_event_t *cev;
63             d_screen_t *sc;
64             d_window_t *w;
65
66             cev = (xcb_create_notify_event_t*)ev;
67             sc = display_screen_from_root(dpy, cev->parent);
68             if (!sc) break;
69             w = screen_add_window(sc, cev->window);
70             break;
71         }
72         case XCB_DESTROY_NOTIFY:
73         {
74             xcb_destroy_notify_event_t *dev;
75             d_screen_t *sc;
76             d_window_t *w;
77             gboolean vis;
78
79             dev = (xcb_destroy_notify_event_t*)ev;
80             sc = display_screen_from_root(dpy, dev->event);
81             if (!sc) break;
82             w = screen_find_window(sc, dev->window);
83             vis = window_is_mapped(w);
84             if (vis) {
85                 sc->window_become_zombie(w);
86                 sc->window_hide(w);
87             }
88             screen_remove_window(sc, w);
89             if (vis) screen_refresh(sc);
90             break;
91         }
92         case XCB_REPARENT_NOTIFY:
93         {
94             xcb_reparent_notify_event_t *rev;
95             d_screen_t *sc;
96             d_window_t *w;
97
98             rev = (xcb_reparent_notify_event_t*)ev;
99             sc = display_screen_from_root(dpy, rev->event);
100             if (!sc) break;
101             w = screen_find_window(sc, rev->window);
102             if (rev->parent == sc->super.root)
103                 screen_add_window(sc, rev->window);
104             else {
105                 if (window_is_mapped(w)) {
106                     sc->window_become_zombie(w);
107                     sc->window_hide(w);
108                 }
109                 screen_remove_window(sc, w);
110             }
111             screen_refresh(sc);
112             break;
113         }
114         case XCB_MAP_NOTIFY:
115         {
116             xcb_map_notify_event_t *mev;
117             d_screen_t *sc;
118             d_window_t *w;
119
120             mev = (xcb_map_notify_event_t*)ev;
121             sc = display_screen_from_root(dpy, mev->event);
122             if (!sc) break;
123             w = screen_find_window(sc, mev->window);
124             sc->window_show(w);
125             screen_refresh(w->sc);
126             break;
127         }
128         case XCB_UNMAP_NOTIFY:
129         {
130             xcb_unmap_notify_event_t *mev;
131             d_screen_t *sc;
132             d_window_t *w;
133
134             mev = (xcb_unmap_notify_event_t*)ev;
135             sc = display_screen_from_root(dpy, mev->event);
136             if (!sc) break;
137             w = screen_find_window(sc, mev->window);
138             sc->window_become_zombie(w);
139             sc->window_hide(w);
140             screen_refresh(w->sc);
141             break;
142         }
143         case XCB_CIRCULATE_NOTIFY:
144         {
145             xcb_circulate_notify_event_t *cev;
146             d_screen_t *sc;
147             d_window_t *w;
148
149             cev = (xcb_circulate_notify_event_t*)ev;
150             sc = display_screen_from_root(dpy, cev->event);
151             if (!sc) break;
152             w = screen_find_window(sc, cev->window);
153             if (cev->place == XCB_PLACE_ON_TOP)
154                 screen_stacking_move_to_top(sc, w);
155             else
156                 screen_stacking_move_to_bottom(sc, w);
157             screen_refresh(w->sc);
158         }
159         case XCB_CONFIGURE_NOTIFY:
160         {
161             xcb_configure_notify_event_t *cev;
162             d_screen_t *sc;
163             d_window_t *w, *above;
164             int x, y, width, height, bwidth;
165
166             cev = (xcb_configure_notify_event_t*)ev;
167             sc = display_screen_from_root(dpy, cev->event);
168             if (!sc) break;
169             //printf("configure 0x%x", cev->window);
170             w = screen_find_window(sc, cev->window);
171             window_get_area(w, &x, &y, &width, &height, &bwidth);
172             if (x != cev->x || y != cev->y || width != cev->width ||
173                 height != cev->height || bwidth != cev->border_width)
174             {
175                 window_configure(w, cev->x, cev->y,
176                                  cev->width, cev->height,
177                                  cev->border_width);
178                 if (window_is_mapped(w)) {
179                     if (x != cev->x || y != cev->y)
180                         sc->window_move(w);
181                     if (width != cev->width ||
182                         height != cev->height || bwidth != cev->border_width)
183                         sc->window_resize(w);
184                 }
185             }
186             above = screen_find_window(sc, cev->above_sibling);
187             if (window_is_mapped(w))
188                 sc->window_restack(w, above);
189             screen_refresh(w->sc);
190             break;
191         }
192         case XCB_PROPERTY_NOTIFY:
193         {
194             xcb_property_notify_event_t *pev;
195
196             pev = (xcb_property_notify_event_t*)ev;
197             if (pev->atom == dpy->a.xrootpmap_id ||
198                 pev->atom == dpy->a.esetroot_pmap_id ||
199                 pev->atom == dpy->a.xsetroot_id)
200             {
201                 d_screen_t *sc;
202
203                 sc = display_screen_from_root(dpy, pev->window);
204                 if (sc) sc->screen_root_pixmap_change(sc);
205             }
206             else if (pev->atom == dpy->a.net_wm_window_opacity) {
207                 d_list_it_t *it;
208
209                 for (it = list_top(dpy->screens); it; it = it->next) {
210                     d_screen_t *sc = it->data;
211                     d_window_t *w;
212
213                     w = screen_find_window(sc, pev->window);
214                     if (w) {
215                         window_update_user_opacity(w);
216                         if (window_is_mapped(w)) {
217                             sc->window_opacity_change(w);
218                             screen_refresh(w->sc);
219                         }
220                     }
221                 }
222                     
223             }
224             break;
225         }
226         default:
227             if (ev->response_type - dpy->damage.event == XCB_DAMAGE_NOTIFY) {
228                 xcb_damage_notify_event_t *dev;
229                 d_list_it_t *it;
230
231                 dev = (xcb_damage_notify_event_t*)ev;
232                 for (it = list_top(dpy->screens); it; it = it->next) {
233                     d_screen_t *sc = it->data;
234                     d_window_t *w;
235
236                     w = screen_find_window(sc, dev->drawable);
237                     if (w) {
238                         sc->window_damage(w);
239                         screen_refresh(w->sc);
240                         break;
241                     }
242                 }
243                 xcb_damage_subtract(dpy->conn, dev->damage,
244                                     XCB_NONE, XCB_NONE);
245             }
246             else if (dpy->shape.present &&
247                      ev->response_type - dpy->shape.event == XCB_SHAPE_NOTIFY)
248             {
249                 xcb_shape_notify_event_t *sev;
250                 d_list_it_t *it;
251
252                 sev = (xcb_shape_notify_event_t*)ev;
253                 for (it = list_top(dpy->screens); it; it = it->next) {
254                     d_screen_t *sc = it->data;
255                     d_window_t *w;
256
257                     w = screen_find_window(sc, sev->affected_window);
258                     if (w && window_is_mapped(w)) {
259                         sc->window_reshape(w);
260                         screen_refresh(w->sc);
261                         break;
262                     }
263                 }
264             }
265             break;
266         }
267         free(ev);
268         xcb_flush(dpy->conn);
269     }
270 }
271
272 static void
273 timeouts(d_display_t *dpy, const struct timeval *now)
274 {
275     d_list_it_t *it;
276
277     for (it = list_top(dpy->screens); it; it = it->next) {
278         d_screen_t *sc = it->data;
279         struct timeval tv;
280
281         if (glxrender_next_timeout(sc, &tv) && time_compare(&tv, now) <= 0)
282             glxrender_timeout(sc, now);
283         if (render_next_timeout(sc, &tv) && time_compare(&tv, now) <= 0)
284             render_timeout(sc, now);
285         if (fade_next_timeout(sc, &tv) && time_compare(&tv, now) <= 0)
286             fade_timeout(sc, now);
287     }
288 }
289
290 static void
291 paint(d_display_t *dpy)
292 {
293     d_list_it_t *it;
294
295     for (it = list_top(dpy->screens); it; it = it->next) {
296         d_screen_t *sc = it->data;
297         if (sc->need_repaint)
298             sc->screen_paint(sc);
299     }
300 }
301
302 static void
303 run(d_display_t *dpy)
304 {
305     struct timeval now, next_repaint;
306
307     running = TRUE;
308
309     gettimeofday(&now, NULL);
310     next_repaint = now;
311
312     while (!quit) {
313         struct timeval next, *wait;
314         int            r, npaint, ntime;
315         d_list_it_t   *it;
316         fd_set         fds;
317         gboolean due;
318
319         event(dpy);
320
321         npaint = 0;
322         ntime = 0;
323         for (it = list_top(dpy->screens); it; it = it->next) {
324             d_screen_t *sc = it->data;
325             struct timeval next_timeout;
326
327             if (glxrender_next_timeout(sc, &next_timeout)) {
328                 if (!ntime || time_compare(&next_timeout, &next) < 0) {
329                     next = next_timeout;
330                     ++ntime;
331                 }
332             }
333             if (render_next_timeout(sc, &next_timeout)) {
334                 if (!ntime || time_compare(&next_timeout, &next) < 0) {
335                     next = next_timeout;
336                     ++ntime;
337                 }
338             }
339             if (fade_next_timeout(sc, &next_timeout)) {
340                 if (!ntime || time_compare(&next_timeout, &next) < 0) {
341                     next = next_timeout;
342                     ++ntime;
343                 }
344             }
345
346             if (sc->need_repaint)
347                 ++npaint;
348         }
349
350         if (npaint) {
351             if (!ntime || time_compare(&next_repaint, &next) < 0) {
352                 next = next_repaint;
353             }
354         }
355
356         if (!npaint && !ntime) {
357             /* wait forever, there is nothing that needs drawing */
358             wait = NULL;
359             due = FALSE;
360         }
361         else if (time_compare(&next, &now) > 0) {
362             /* wait until the next allowed redraw time */
363             time_difference(&next, &now, &next);
364             wait = &next;
365             due = FALSE;
366         }
367         else {
368             /* don't wait cuz a timer is due now already */
369             due = TRUE;
370         }
371
372         //printf("select? %d %d\n", due, npaint);
373
374         if (!due) {
375             FD_ZERO(&fds);
376             FD_SET(dpy->fd, &fds);
377             r = select(dpy->fd+1, &fds, NULL, NULL, wait);
378         }
379         else
380             r = 0;
381
382         gettimeofday(&now, NULL);
383         if (r == 0) {
384             //printf("select timeout\n");
385             timeouts(dpy, &now);
386             if (time_compare(&next_repaint, &now) <= 0) {
387                 paint(dpy);
388                 next_repaint = now;
389                 time_add(&next_repaint, 1000000/90); /* 60hz */
390             }
391             xcb_flush(dpy->conn);
392         }
393
394         if (xcb_connection_has_error(dpy->conn))
395             quit = TRUE;
396     }
397
398     running = FALSE;
399 }
400
401 static void
402 setup_functions(d_display_t *dpy)
403 {
404     d_list_it_t *it;
405
406     for (it = list_top(dpy->screens); it; it = it->next) {
407         d_screen_t *sc = it->data;
408         int id;
409         screen_setup_default_functions(sc);
410
411         /* these can be plugins.. */
412         id = 1;
413         glxrender_init(sc, id++);
414         //render_init(sc, id++);
415         fade_init(sc, id++);
416     }
417 }
418
419 static void
420 cleanup_functions(d_display_t *dpy)
421 {
422     d_list_it_t *it;
423
424     for (it = list_top(dpy->screens); it; it = it->next) {
425         d_screen_t *sc = it->data;
426
427         /* these can be plugins.. */
428         fade_free(sc);
429         //render_free(sc);
430         glxrender_free(sc);
431     }
432 }
433
434 int
435 main(int argc, char **argv)
436 {
437     d_display_t         *dpy;
438     d_options_t          opts;
439
440     read_options(argc, argv, &opts);
441
442     dpy = display_open(NULL);
443     if (!dpy) {
444         printf(_("Unable to connect to display\n"));
445         return 1;
446     }
447
448     if (!dpy->composite.present) {
449         printf(_("no composite extension present on the display\n"));
450         display_unref(dpy);
451         return 1;
452     }
453     if (!dpy->xfixes.present) {
454         printf(_("no xfixes extension present on the display\n"));
455         display_unref(dpy);
456         return 1;
457     }
458     if (!dpy->damage.present) {
459         printf(_("no damage extension present on the display\n"));
460         display_unref(dpy);
461         return 1;
462     }
463     if (!dpy->render.present) {
464         printf(_("no render extension present on the display\n"));
465         display_unref(dpy);
466         return 1;
467     }
468     if (dpy->composite.major_version <= 0 && dpy->composite.minor_version < 3)
469     {
470         printf(_("composite extension does not support the overlay window"));
471         display_unref(dpy);
472         return 1;
473     }
474
475     if (!display_claim_screens(dpy)) {
476         printf(_("found no screens to run on\n"));
477         display_unref(dpy);
478         return 0;
479     }
480
481     signal(SIGINT, signal_quit_handler);
482     signal(SIGHUP, signal_quit_handler);
483     signal(SIGTERM, signal_quit_handler);
484     signal(SIGQUIT, signal_quit_handler);
485
486     setup_functions(dpy);
487
488     {
489         /* some of the windows may already be visible */
490         d_list_it_t *sc_it;
491
492         for (sc_it = list_top(dpy->screens); sc_it; sc_it = sc_it->next) {
493             d_screen_t *sc = sc_it->data;
494             d_list_it_t *it;
495             for (it = list_bottom(sc->stacking); it; it = it->prev)
496                 if (window_is_attr_mapped(it->data))
497                     sc->window_show(it->data);
498         }
499     }
500
501     printf("running\n");
502     run(dpy);
503
504     {
505         /* make everything hidden */
506         d_list_it_t *sc_it;
507
508         for (sc_it = list_top(dpy->screens); sc_it; sc_it = sc_it->next) {
509             d_screen_t *sc = sc_it->data;
510             d_list_it_t *it;
511             for (it = list_top(sc->stacking); it; it = it->next) {
512                 if (window_is_mapped(it->data))
513                     sc->window_hide(it->data);
514             }
515         }
516     }
517
518     cleanup_functions(dpy);
519
520     display_unref(dpy);
521     return 0;
522 }
523
524 gboolean
525 dcompmgr_running(void)
526 {
527     return running;
528 }