10 /* these can be plugins */
12 #include "glxrender.h"
17 #include <sys/select.h>
22 #include <xcb/damage.h>
23 #include <xcb/shape.h>
34 static gboolean quit = FALSE;
35 static gboolean running = FALSE;
42 "Usage: dcompmgr [OPTIONS]\n"
45 " --gl Use OpenGL for drawing\n"
46 " --xrender Use XRender for drawing (the default)\n"
48 "Copyright (C) 2008 Dana Jansens\n"
55 read_options(int argc, char **argv, d_options_t *opts)
59 opts->render = USE_RENDER;
61 for (i = 1; i < argc; ++i) {
62 if (strcmp(argv[i], "--gl") == 0)
63 opts->render = USE_OPENGL;
64 else if (strcmp(argv[i], "--xrender") == 0)
65 opts->render = USE_RENDER;
66 else if (strcmp(argv[i], "--help") == 0) {
74 signal_quit_handler(int sig)
76 printf("caught signal %d, quitting\n", sig);
81 event(d_display_t *dpy)
83 xcb_generic_event_t *ev;
85 while ((ev = xcb_poll_for_event(dpy->conn)) && !quit) {
86 //printf("event %d\n", ev->response_type);
88 if (!ev->response_type) {
89 display_error(dpy, (xcb_generic_error_t*)ev);
94 switch (ev->response_type) {
95 case XCB_CREATE_NOTIFY:
97 xcb_create_notify_event_t *cev;
101 cev = (xcb_create_notify_event_t*)ev;
102 sc = display_screen_from_root(dpy, cev->parent);
104 w = screen_add_window(sc, cev->window);
107 case XCB_DESTROY_NOTIFY:
109 xcb_destroy_notify_event_t *dev;
114 dev = (xcb_destroy_notify_event_t*)ev;
115 sc = display_screen_from_root(dpy, dev->event);
117 w = screen_find_window(sc, dev->window);
118 vis = window_is_mapped(w);
120 sc->window_become_zombie(w);
123 screen_remove_window(sc, w);
124 if (vis) screen_refresh(sc);
127 case XCB_REPARENT_NOTIFY:
129 xcb_reparent_notify_event_t *rev;
133 rev = (xcb_reparent_notify_event_t*)ev;
134 sc = display_screen_from_root(dpy, rev->event);
136 w = screen_find_window(sc, rev->window);
137 if (rev->parent == sc->super->root)
138 screen_add_window(sc, rev->window);
140 if (window_is_mapped(w)) {
141 sc->window_become_zombie(w);
144 screen_remove_window(sc, w);
151 xcb_map_notify_event_t *mev;
155 mev = (xcb_map_notify_event_t*)ev;
156 sc = display_screen_from_root(dpy, mev->event);
158 w = screen_find_window(sc, mev->window);
160 screen_refresh(w->sc);
163 case XCB_UNMAP_NOTIFY:
165 xcb_unmap_notify_event_t *mev;
169 mev = (xcb_unmap_notify_event_t*)ev;
170 sc = display_screen_from_root(dpy, mev->event);
172 w = screen_find_window(sc, mev->window);
173 sc->window_become_zombie(w);
175 screen_refresh(w->sc);
178 case XCB_CIRCULATE_NOTIFY:
180 xcb_circulate_notify_event_t *cev;
184 cev = (xcb_circulate_notify_event_t*)ev;
185 sc = display_screen_from_root(dpy, cev->event);
187 w = screen_find_window(sc, cev->window);
188 if (cev->place == XCB_PLACE_ON_TOP)
189 screen_stacking_move_to_top(sc, w);
191 screen_stacking_move_to_bottom(sc, w);
192 screen_refresh(w->sc);
194 case XCB_CONFIGURE_NOTIFY:
196 xcb_configure_notify_event_t *cev;
198 d_window_t *w, *above;
199 int x, y, width, height, bwidth;
201 cev = (xcb_configure_notify_event_t*)ev;
202 sc = display_screen_from_root(dpy, cev->event);
204 //printf("configure 0x%x", cev->window);
205 w = screen_find_window(sc, cev->window);
206 window_get_area(w, &x, &y, &width, &height, &bwidth);
207 if (x != cev->x || y != cev->y || width != cev->width ||
208 height != cev->height || bwidth != cev->border_width)
210 window_configure(w, cev->x, cev->y,
211 cev->width, cev->height,
213 if (window_is_mapped(w)) {
214 if (x != cev->x || y != cev->y)
216 if (width != cev->width ||
217 height != cev->height || bwidth != cev->border_width)
218 sc->window_resize(w);
221 above = screen_find_window(sc, cev->above_sibling);
222 sc->window_restack(w, above);
223 if (window_is_mapped(w))
224 screen_refresh(w->sc);
227 case XCB_PROPERTY_NOTIFY:
229 xcb_property_notify_event_t *pev;
231 pev = (xcb_property_notify_event_t*)ev;
232 if (pev->atom == dpy->a.xrootpmap_id ||
233 pev->atom == dpy->a.esetroot_pmap_id ||
234 pev->atom == dpy->a.xsetroot_id)
238 sc = display_screen_from_root(dpy, pev->window);
239 if (sc) sc->screen_root_pixmap_change(sc);
241 else if (pev->atom == dpy->a.net_wm_window_opacity) {
244 for (it = list_top(dpy->screens); it; it = it->next) {
245 d_screen_t *sc = it->data;
248 w = screen_find_window(sc, pev->window);
250 window_update_user_opacity(w);
251 if (window_is_mapped(w)) {
252 sc->window_opacity_change(w);
253 screen_refresh(w->sc);
262 if (ev->response_type - dpy->damage.event == XCB_DAMAGE_NOTIFY) {
263 xcb_damage_notify_event_t *dev;
266 dev = (xcb_damage_notify_event_t*)ev;
267 for (it = list_top(dpy->screens); it; it = it->next) {
268 d_screen_t *sc = it->data;
271 w = screen_find_window(sc, dev->drawable);
273 sc->window_damage(w);
274 screen_refresh(w->sc);
278 xcb_damage_subtract(dpy->conn, dev->damage,
281 else if (dpy->shape.present &&
282 ev->response_type - dpy->shape.event == XCB_SHAPE_NOTIFY)
284 xcb_shape_notify_event_t *sev;
287 sev = (xcb_shape_notify_event_t*)ev;
288 for (it = list_top(dpy->screens); it; it = it->next) {
289 d_screen_t *sc = it->data;
292 w = screen_find_window(sc, sev->affected_window);
293 if (w && window_is_mapped(w)) {
294 sc->window_reshape(w);
295 screen_refresh(w->sc);
303 xcb_flush(dpy->conn);
308 timeouts(d_display_t *dpy, const struct timeval *now)
312 for (it = list_top(dpy->screens); it; it = it->next) {
313 d_screen_t *sc = it->data;
316 if (glxrender_next_timeout(sc, &tv) && time_compare(&tv, now) <= 0)
317 glxrender_timeout(sc, now);
318 if (render_next_timeout(sc, &tv) && time_compare(&tv, now) <= 0)
319 render_timeout(sc, now);
320 if (fade_next_timeout(sc, &tv) && time_compare(&tv, now) <= 0)
321 fade_timeout(sc, now);
326 paint(d_display_t *dpy)
330 for (it = list_top(dpy->screens); it; it = it->next) {
331 d_screen_t *sc = it->data;
332 if (sc->need_repaint)
333 sc->screen_paint(sc);
338 run(d_display_t *dpy)
340 struct timeval now, next_repaint;
344 gettimeofday(&now, NULL);
348 struct timeval next, *wait;
349 int r, npaint, ntime;
358 for (it = list_top(dpy->screens); it; it = it->next) {
359 d_screen_t *sc = it->data;
360 struct timeval next_timeout;
362 if (glxrender_next_timeout(sc, &next_timeout)) {
363 if (!ntime || time_compare(&next_timeout, &next) < 0) {
368 if (render_next_timeout(sc, &next_timeout)) {
369 if (!ntime || time_compare(&next_timeout, &next) < 0) {
374 if (fade_next_timeout(sc, &next_timeout)) {
375 if (!ntime || time_compare(&next_timeout, &next) < 0) {
381 if (sc->need_repaint)
386 if (!ntime || time_compare(&next_repaint, &next) < 0) {
391 if (!npaint && !ntime) {
392 /* wait forever, there is nothing that needs drawing */
396 else if (time_compare(&next, &now) > 0) {
397 /* wait until the next allowed redraw time */
398 time_difference(&next, &now, &next);
403 /* don't wait cuz a timer is due now already */
407 //printf("select? %d %d\n", due, npaint);
411 FD_SET(dpy->fd, &fds);
412 r = select(dpy->fd+1, &fds, NULL, NULL, wait);
417 gettimeofday(&now, NULL);
419 //printf("select timeout\n");
421 if (time_compare(&next_repaint, &now) <= 0) {
424 time_add(&next_repaint, 1000000/90); /* 60hz */
426 xcb_flush(dpy->conn);
429 if (xcb_connection_has_error(dpy->conn))
437 setup_functions(d_display_t *dpy, d_options_t *opts)
441 for (it = list_top(dpy->screens); it; it = it->next) {
442 d_screen_t *sc = it->data;
444 screen_setup_default_functions(sc);
446 /* these can be plugins.. */
449 if (opts->render == USE_RENDER)
450 render_init(sc, id++);
452 glxrender_init(sc, id++);
459 cleanup_functions(d_display_t *dpy)
463 for (it = list_top(dpy->screens); it; it = it->next) {
464 d_screen_t *sc = it->data;
466 /* these can be plugins.. */
474 main(int argc, char **argv)
479 read_options(argc, argv, &opts);
481 dpy = display_open(NULL);
483 printf(_("Unable to connect to display\n"));
487 if (!dpy->composite.present) {
488 printf(_("no composite extension present on the display\n"));
492 if (!dpy->xfixes.present) {
493 printf(_("no xfixes extension present on the display\n"));
497 if (!dpy->damage.present) {
498 printf(_("no damage extension present on the display\n"));
502 if (!dpy->render.present) {
503 printf(_("no render extension present on the display\n"));
507 if (dpy->composite.major_version <= 0 && dpy->composite.minor_version < 3)
509 printf(_("composite extension does not support the overlay window"));
514 if (!display_claim_screens(dpy)) {
515 printf(_("found no screens to run on\n"));
520 signal(SIGINT, signal_quit_handler);
521 signal(SIGHUP, signal_quit_handler);
522 signal(SIGTERM, signal_quit_handler);
523 signal(SIGQUIT, signal_quit_handler);
525 setup_functions(dpy, &opts);
528 /* some of the windows may already be visible */
531 for (sc_it = list_top(dpy->screens); sc_it; sc_it = sc_it->next) {
532 d_screen_t *sc = sc_it->data;
534 for (it = list_bottom(sc->stacking); it; it = it->prev)
535 if (window_is_attr_mapped(it->data))
536 sc->window_show(it->data);
544 /* make everything hidden */
547 for (sc_it = list_top(dpy->screens); sc_it; sc_it = sc_it->next) {
548 d_screen_t *sc = sc_it->data;
550 for (it = list_top(sc->stacking); it; it = it->next) {
551 if (window_is_mapped(it->data))
552 sc->window_hide(it->data);
557 cleanup_functions(dpy);
564 dcompmgr_running(void)