10 /* these can be plugins */
12 #include "glxrender.h"
17 #include <sys/select.h>
22 #include <xcb/damage.h>
23 #include <xcb/shape.h>
35 static gboolean quit = FALSE;
36 static gboolean running = FALSE;
43 "Usage: dcompmgr [OPTIONS]\n"
46 " --gl Use OpenGL for drawing\n"
47 " --xrender Use XRender for drawing (the default)\n"
48 " --fade Fade windows in and out of existence (the default)\n"
49 " --no-fade Don't fade windows in and out\n"
51 "Copyright (C) 2008 Dana Jansens\n"
58 read_options(int argc, char **argv, d_options_t *opts)
62 opts->render = USE_RENDER;
65 for (i = 1; i < argc; ++i) {
66 if (strcmp(argv[i], "--gl") == 0)
67 opts->render = USE_OPENGL;
68 else if (strcmp(argv[i], "--xrender") == 0)
69 opts->render = USE_RENDER;
70 else if (strcmp(argv[i], "--fade") == 0)
72 else if (strcmp(argv[i], "--no-fade") == 0)
74 else if (strcmp(argv[i], "--help") == 0) {
82 signal_quit_handler(int sig)
84 printf("caught signal %d, quitting\n", sig);
89 event(d_display_t *dpy)
91 xcb_generic_event_t *ev;
93 while ((ev = xcb_poll_for_event(dpy->conn)) && !quit) {
94 //printf("event %d\n", ev->response_type);
96 if (!ev->response_type) {
97 display_error(dpy, (xcb_generic_error_t*)ev);
102 switch (ev->response_type) {
103 case XCB_CREATE_NOTIFY:
105 xcb_create_notify_event_t *cev;
109 cev = (xcb_create_notify_event_t*)ev;
110 sc = display_screen_from_root(dpy, cev->parent);
112 w = screen_add_window(sc, cev->window);
115 case XCB_DESTROY_NOTIFY:
117 xcb_destroy_notify_event_t *dev;
122 dev = (xcb_destroy_notify_event_t*)ev;
123 sc = display_screen_from_root(dpy, dev->event);
125 w = screen_find_window(sc, dev->window);
126 vis = window_is_mapped(w);
128 sc->window_become_zombie(w);
131 screen_remove_window(sc, w);
132 if (vis) screen_refresh(sc);
135 case XCB_REPARENT_NOTIFY:
137 xcb_reparent_notify_event_t *rev;
141 rev = (xcb_reparent_notify_event_t*)ev;
142 sc = display_screen_from_root(dpy, rev->event);
144 w = screen_find_window(sc, rev->window);
145 if (rev->parent == sc->super->root)
146 screen_add_window(sc, rev->window);
148 if (window_is_mapped(w)) {
149 sc->window_become_zombie(w);
152 screen_remove_window(sc, w);
159 xcb_map_notify_event_t *mev;
163 mev = (xcb_map_notify_event_t*)ev;
164 sc = display_screen_from_root(dpy, mev->event);
166 w = screen_find_window(sc, mev->window);
168 screen_refresh(w->sc);
171 case XCB_UNMAP_NOTIFY:
173 xcb_unmap_notify_event_t *mev;
177 mev = (xcb_unmap_notify_event_t*)ev;
178 sc = display_screen_from_root(dpy, mev->event);
180 w = screen_find_window(sc, mev->window);
181 sc->window_become_zombie(w);
183 screen_refresh(w->sc);
186 case XCB_CIRCULATE_NOTIFY:
188 xcb_circulate_notify_event_t *cev;
192 cev = (xcb_circulate_notify_event_t*)ev;
193 sc = display_screen_from_root(dpy, cev->event);
195 w = screen_find_window(sc, cev->window);
196 if (cev->place == XCB_PLACE_ON_TOP)
197 screen_stacking_move_to_top(sc, w);
199 screen_stacking_move_to_bottom(sc, w);
200 screen_refresh(w->sc);
202 case XCB_CONFIGURE_NOTIFY:
204 xcb_configure_notify_event_t *cev;
206 d_window_t *w, *above;
207 int x, y, width, height, bwidth;
209 cev = (xcb_configure_notify_event_t*)ev;
210 sc = display_screen_from_root(dpy, cev->event);
212 //printf("configure 0x%x", cev->window);
213 w = screen_find_window(sc, cev->window);
214 window_get_area(w, &x, &y, &width, &height, &bwidth);
215 if (x != cev->x || y != cev->y || width != cev->width ||
216 height != cev->height || bwidth != cev->border_width)
218 window_configure(w, cev->x, cev->y,
219 cev->width, cev->height,
221 if (window_is_mapped(w)) {
222 if (x != cev->x || y != cev->y)
224 if (width != cev->width ||
225 height != cev->height || bwidth != cev->border_width)
226 sc->window_resize(w);
229 above = screen_find_window(sc, cev->above_sibling);
230 sc->window_restack(w, above);
231 if (window_is_mapped(w))
232 screen_refresh(w->sc);
235 case XCB_PROPERTY_NOTIFY:
237 xcb_property_notify_event_t *pev;
239 pev = (xcb_property_notify_event_t*)ev;
240 if (pev->atom == dpy->a.xrootpmap_id ||
241 pev->atom == dpy->a.esetroot_pmap_id ||
242 pev->atom == dpy->a.xsetroot_id)
246 sc = display_screen_from_root(dpy, pev->window);
247 if (sc) sc->screen_root_pixmap_change(sc);
249 else if (pev->atom == dpy->a.net_wm_window_opacity) {
252 for (it = list_top(dpy->screens); it; it = it->next) {
253 d_screen_t *sc = it->data;
256 w = screen_find_window(sc, pev->window);
258 window_update_user_opacity(w);
259 if (window_is_mapped(w)) {
260 sc->window_opacity_change(w);
261 screen_refresh(w->sc);
270 if (ev->response_type - dpy->damage.event == XCB_DAMAGE_NOTIFY) {
271 xcb_damage_notify_event_t *dev;
274 dev = (xcb_damage_notify_event_t*)ev;
275 for (it = list_top(dpy->screens); it; it = it->next) {
276 d_screen_t *sc = it->data;
279 w = screen_find_window(sc, dev->drawable);
281 sc->window_damage(w);
282 screen_refresh(w->sc);
286 xcb_damage_subtract(dpy->conn, dev->damage,
289 else if (dpy->shape.present &&
290 ev->response_type - dpy->shape.event == XCB_SHAPE_NOTIFY)
292 xcb_shape_notify_event_t *sev;
295 sev = (xcb_shape_notify_event_t*)ev;
296 for (it = list_top(dpy->screens); it; it = it->next) {
297 d_screen_t *sc = it->data;
300 w = screen_find_window(sc, sev->affected_window);
301 if (w && window_is_mapped(w)) {
302 sc->window_reshape(w);
303 screen_refresh(w->sc);
311 xcb_flush(dpy->conn);
316 timeouts(d_display_t *dpy, const struct timeval *now)
320 for (it = list_top(dpy->screens); it; it = it->next) {
321 d_screen_t *sc = it->data;
324 if (glxrender_next_timeout(sc, &tv) && time_compare(&tv, now) <= 0)
325 glxrender_timeout(sc, now);
326 if (render_next_timeout(sc, &tv) && time_compare(&tv, now) <= 0)
327 render_timeout(sc, now);
328 if (fade_next_timeout(sc, &tv) && time_compare(&tv, now) <= 0)
329 fade_timeout(sc, now);
334 paint(d_display_t *dpy)
338 for (it = list_top(dpy->screens); it; it = it->next) {
339 d_screen_t *sc = it->data;
340 if (sc->need_repaint)
341 sc->screen_paint(sc);
346 run(d_display_t *dpy)
348 struct timeval now, next_repaint;
352 gettimeofday(&now, NULL);
356 struct timeval next, *wait;
357 int r, npaint, ntime;
366 for (it = list_top(dpy->screens); it; it = it->next) {
367 d_screen_t *sc = it->data;
368 struct timeval next_timeout;
370 if (glxrender_next_timeout(sc, &next_timeout)) {
371 if (!ntime || time_compare(&next_timeout, &next) < 0) {
376 if (render_next_timeout(sc, &next_timeout)) {
377 if (!ntime || time_compare(&next_timeout, &next) < 0) {
382 if (fade_next_timeout(sc, &next_timeout)) {
383 if (!ntime || time_compare(&next_timeout, &next) < 0) {
389 if (sc->need_repaint)
394 if (!ntime || time_compare(&next_repaint, &next) < 0) {
399 if (!npaint && !ntime) {
400 /* wait forever, there is nothing that needs drawing */
404 else if (time_compare(&next, &now) > 0) {
405 /* wait until the next allowed redraw time */
406 time_difference(&next, &now, &next);
411 /* don't wait cuz a timer is due now already */
415 //printf("select? %d %d\n", due, npaint);
419 FD_SET(dpy->fd, &fds);
420 r = select(dpy->fd+1, &fds, NULL, NULL, wait);
425 gettimeofday(&now, NULL);
427 //printf("select timeout\n");
429 if (time_compare(&next_repaint, &now) <= 0) {
432 time_add(&next_repaint, 1000000/90); /* 60hz */
434 xcb_flush(dpy->conn);
437 if (xcb_connection_has_error(dpy->conn))
445 setup_functions(d_display_t *dpy, d_options_t *opts)
449 for (it = list_top(dpy->screens); it; it = it->next) {
450 d_screen_t *sc = it->data;
452 screen_setup_default_functions(sc);
454 /* these can be plugins.. */
457 if (opts->render == USE_OPENGL) {
458 if (!dpy->glx.present) {
459 printf("cannot use OpenGL rendering, no glX found\n");
460 printf("using XRender instead\n");
461 opts->render = USE_RENDER;
465 if (opts->render == USE_RENDER)
466 render_init(sc, id++);
468 glxrender_init(sc, id++);
476 cleanup_functions(d_display_t *dpy)
480 for (it = list_top(dpy->screens); it; it = it->next) {
481 d_screen_t *sc = it->data;
483 /* these can be plugins.. */
491 main(int argc, char **argv)
496 read_options(argc, argv, &opts);
498 dpy = display_open(NULL);
500 printf(_("Unable to connect to display\n"));
504 if (!dpy->composite.present) {
505 printf(_("no composite extension present on the display\n"));
509 if (!dpy->xfixes.present) {
510 printf(_("no xfixes extension present on the display\n"));
514 if (!dpy->damage.present) {
515 printf(_("no damage extension present on the display\n"));
519 if (!dpy->render.present) {
520 printf(_("no render extension present on the display\n"));
524 if (dpy->composite.major_version <= 0 && dpy->composite.minor_version < 3)
526 printf(_("composite extension does not support the overlay window\n"));
531 if (!display_claim_screens(dpy)) {
532 printf(_("found no screens to run on\n"));
537 signal(SIGINT, signal_quit_handler);
538 signal(SIGHUP, signal_quit_handler);
539 signal(SIGTERM, signal_quit_handler);
540 signal(SIGQUIT, signal_quit_handler);
542 setup_functions(dpy, &opts);
545 /* some of the windows may already be visible */
548 for (sc_it = list_top(dpy->screens); sc_it; sc_it = sc_it->next) {
549 d_screen_t *sc = sc_it->data;
551 for (it = list_bottom(sc->stacking); it; it = it->prev)
552 if (window_is_attr_mapped(it->data))
553 sc->window_show(it->data);
561 /* make everything hidden */
564 for (sc_it = list_top(dpy->screens); sc_it; sc_it = sc_it->next) {
565 d_screen_t *sc = sc_it->data;
567 for (it = list_top(sc->stacking); it; it = it->next) {
568 if (window_is_mapped(it->data))
569 sc->window_hide(it->data);
574 cleanup_functions(dpy);
581 dcompmgr_running(void)