make the select always prefer X events over the timeouts for painting. also don't...
[dana/dcompmgr.git] / dcompmgr.c
1 #include "screen.h"
2 #include "window.h"
3 #include "list.h"
4 #include "display.h"
5 #include "gettext.h"
6 #include "time.h"
7 #include "render.h"
8
9 #include <glib.h>
10 #include <stdio.h>
11 #include <sys/select.h>
12 #include <stdlib.h>
13 #include <string.h>
14 #include <xcb/xcb.h>
15 #include <xcb/damage.h>
16
17 typedef struct {
18     int foo;
19 } d_options_t;
20
21 static void
22 read_options(int argc, char **argv, d_options_t *opts)
23 {
24     opts->foo = argc && argv;
25 }
26
27 static void
28 event(d_display_t *dpy)
29 {
30     xcb_generic_event_t *ev;
31
32     while ((ev = xcb_poll_for_event(dpy->conn))) {
33         //printf("event %d\n", ev->response_type);
34
35         if (!ev->response_type) {
36             display_error(dpy, (xcb_generic_error_t*)ev);
37             free(ev);
38             continue;
39         }
40
41         switch (ev->response_type) {
42         case XCB_CREATE_NOTIFY:
43         {
44             xcb_create_notify_event_t *cev;
45             d_screen_t *sc;
46
47             cev = (xcb_create_notify_event_t*)ev;
48             sc = display_screen_from_root(dpy, cev->parent);
49             if (!sc) break;
50             screen_add_window(sc, cev->window);
51             break;
52         }
53         case XCB_DESTROY_NOTIFY:
54         {
55             xcb_destroy_notify_event_t *dev;
56             d_screen_t *sc;
57             d_window_t *w;
58             gboolean vis;
59
60             dev = (xcb_destroy_notify_event_t*)ev;
61             sc = display_screen_from_root(dpy, dev->event);
62             if (!sc) break;
63             w = screen_find_window(sc, dev->window);
64             vis = window_is_mapped(w);
65             sc->window_hide(w);
66             screen_remove_window(sc, w);
67             if (vis) screen_refresh(sc);
68             break;
69         }
70         case XCB_REPARENT_NOTIFY:
71         {
72             xcb_reparent_notify_event_t *rev;
73             d_screen_t *sc;
74             d_window_t *w;
75
76             rev = (xcb_reparent_notify_event_t*)ev;
77             sc = display_screen_from_root(dpy, rev->event);
78             if (!sc) break;
79             w = screen_find_window(sc, rev->window);
80             if (rev->parent == sc->super.root)
81                 screen_add_window(sc, rev->window);
82             else {
83                 sc->window_hide(w);
84                 screen_remove_window(sc, w);
85             }
86             screen_refresh(w->sc);
87             break;
88         }
89         case XCB_MAP_NOTIFY:
90         {
91             xcb_map_notify_event_t *mev;
92             d_screen_t *sc;
93             d_window_t *w;
94
95             mev = (xcb_map_notify_event_t*)ev;
96             sc = display_screen_from_root(dpy, mev->event);
97             if (!sc) break;
98             w = screen_find_window(sc, mev->window);
99             sc->window_show(w);
100             screen_refresh(w->sc);
101             break;
102         }
103         case XCB_UNMAP_NOTIFY:
104         {
105             xcb_unmap_notify_event_t *mev;
106             d_screen_t *sc;
107             d_window_t *w;
108
109             mev = (xcb_unmap_notify_event_t*)ev;
110             sc = display_screen_from_root(dpy, mev->event);
111             if (!sc) break;
112             w = screen_find_window(sc, mev->window);
113             sc->window_hide(w);
114             screen_refresh(w->sc);
115             break;
116         }
117         case XCB_CONFIGURE_NOTIFY:
118         {
119             xcb_configure_notify_event_t *cev;
120             d_screen_t *sc;
121             d_window_t *w, *above;
122             int x, y, width, height, bwidth;
123
124             cev = (xcb_configure_notify_event_t*)ev;
125             sc = display_screen_from_root(dpy, cev->event);
126             if (!sc) break;
127             w = screen_find_window(sc, cev->window);
128             window_get_area(w, &x, &y, &width, &height, &bwidth);
129             if (x != cev->x || y != cev->y || width != cev->width ||
130                 height != cev->height || bwidth != cev->border_width)
131             {
132                 window_configure(w, cev->x, cev->y,
133                                  cev->width, cev->height,
134                                  cev->border_width);
135                 if (window_is_mapped(w))
136                     sc->window_reconfigure(w);
137             }
138             above = screen_find_window(sc, cev->above_sibling);
139             screen_stacking_move_above(sc, w, above);
140             screen_refresh(w->sc);
141             break;
142         }
143         default:
144             if (ev->response_type - dpy->damage.event == XCB_DAMAGE_NOTIFY) {
145                 xcb_damage_notify_event_t *dev;
146                 d_list_it_t *it;
147
148                 dev = (xcb_damage_notify_event_t*)ev;
149                 for (it = list_top(dpy->screens); it; it = it->next) {
150                     d_screen_t *sc = it->data;
151                     d_window_t *w;
152
153                     w = screen_find_window(sc, dev->drawable);
154                     if (w) {
155                         screen_refresh(w->sc);
156                         break;
157                     }
158                 }
159                 xcb_damage_subtract(dpy->conn, dev->damage,
160                                     XCB_NONE, XCB_NONE);
161             }
162             break;
163         }
164         free(ev);
165         xcb_flush(dpy->conn);
166     }
167 }
168
169 static void
170 paint(d_display_t *dpy)
171 {
172     d_list_it_t *it;
173     struct timeval now;
174
175     gettimeofday(&now, NULL);
176     
177     for (it = list_top(dpy->screens); it; it = it->next) {
178         d_screen_t *sc = it->data;
179
180         if (time_compare(&sc->next_repaint, &now) <= 0)
181             sc->screen_paint(sc);
182     }
183 }
184
185 static void
186 run(d_display_t *dpy)
187 {
188     gboolean quit;
189
190     quit = FALSE;
191     while (!quit) {
192         struct timeval next, now, *wait;
193         int            r, npaint;
194         d_list_it_t   *it;
195         fd_set         fds;
196
197         event(dpy);
198
199         npaint = 0;
200         for (it = list_top(dpy->screens); it; it = it->next) {
201             d_screen_t *sc = it->data;
202             if (sc->need_repaint &&
203                 (!npaint || time_compare(&sc->next_repaint, &next) < 0))
204             {
205                 next = sc->next_repaint;
206                 ++npaint;
207             }
208         }
209
210         gettimeofday(&now, 0);
211
212         if (!npaint)
213             /* wait forever, there is nothing that needs drawing */
214             wait = NULL;
215         else if (time_compare(&next, &now) > 0) {
216             /* wait until the next allowed redraw time */
217             time_difference(&next, &now, &next);
218             wait = &next;
219         }
220         else {
221             /* don't wait cuz a redraw is due now already */
222             next.tv_sec = 0;
223             next.tv_usec = 1;
224             wait = &next;
225         }
226
227         FD_ZERO(&fds);
228         FD_SET(dpy->fd, &fds);
229
230         //printf("select %d\n", npaint);
231
232         r = select(dpy->fd+1, &fds, NULL, NULL, wait);
233         if (r < 0)
234             printf("select error\n");
235         else if (r == 0) {
236             //printf("select timeout\n");
237             paint(dpy);
238             xcb_flush(dpy->conn);
239         }
240
241         if (xcb_connection_has_error(dpy->conn))
242             quit = TRUE;
243     }
244 }
245
246 static void
247 setup_functions(d_display_t *dpy)
248 {
249     d_list_it_t *it;
250
251     for (it = list_top(dpy->screens); it; it = it->next) {
252         d_screen_t *sc = it->data;
253         screen_setup_default_functions(sc);
254
255         /* these can be plugins.. */
256         render_init(sc);
257     }
258 }
259
260 static void
261 cleanup_functions(d_display_t *dpy)
262 {
263     d_list_it_t *it;
264
265     for (it = list_top(dpy->screens); it; it = it->next) {
266         d_screen_t *sc = it->data;
267
268         /* these can be plugins.. */
269         render_free(sc);
270     }
271 }
272
273 int
274 main(int argc, char **argv)
275 {
276     d_display_t         *dpy;
277     d_options_t          opts;
278
279     read_options(argc, argv, &opts);
280
281     dpy = display_open(NULL);
282     if (!dpy) {
283         printf(_("Unable to connect to display\n"));
284         return 1;
285     }
286
287     if (!dpy->composite.present) {
288         printf(_("no composite extension present on the display\n"));
289         display_unref(dpy);
290         return 1;
291     }
292     if (!dpy->xfixes.present) {
293         printf(_("no xfixes extension present on the display\n"));
294         display_unref(dpy);
295         return 1;
296     }
297     if (!dpy->damage.present) {
298         printf(_("no damage extension present on the display\n"));
299         display_unref(dpy);
300         return 1;
301     }
302     if (!dpy->render.present) {
303         printf(_("no render extension present on the display\n"));
304         display_unref(dpy);
305         return 1;
306     }
307     if (dpy->composite.major_version <= 0 && dpy->composite.minor_version < 3)
308     {
309         printf(_("composite extension does not support the overlay window"));
310         display_unref(dpy);
311         return 1;
312     }
313
314     if (!display_claim_screens(dpy)) {
315         printf(_("found no screens to run on\n"));
316         display_unref(dpy);
317         return 0;
318     }
319
320     setup_functions(dpy);
321
322     {
323         /* some of the windows may already be visible */
324         d_list_it_t *sc_it;
325
326         for (sc_it = list_top(dpy->screens); sc_it; sc_it = sc_it->next) {
327             d_screen_t *sc = sc_it->data;
328             d_list_it_t *it;
329             for (it = list_top(sc->stacking); it; it = it->next)
330                 if (window_is_mapped(it->data))
331                     sc->window_show(it->data);
332         }
333     }
334
335     run(dpy);
336
337     cleanup_functions(dpy);
338
339     display_unref(dpy);
340     return 0;
341 }