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