1 #define GL_GLEXT_PROTOTYPES
8 #include <X11/extensions/Xcomposite.h>
9 #include <X11/extensions/Xdamage.h>
10 #include <X11/extensions/shape.h>
11 #include <X11/extensions/Xrandr.h>
15 typedef struct CompositedWindow
30 typedef struct CompositedMonitor
37 float keystone_vertical;
39 float vertical_center;
41 unsigned vertex_buffer;
42 unsigned index_buffer;
43 unsigned vertex_array;
44 unsigned tessellation;
48 typedef struct CompositedScreen
58 GLXContext glx_context;
61 unsigned geometry_loc;
62 unsigned window_vertex_buffer;
63 unsigned window_vertex_array;
66 CompositedWindow *windows;
68 unsigned windows_capacity;
69 CompositedMonitor *monitors;
74 typedef struct Compositor
77 CompositedScreen *screens;
80 PFNGLXCREATECONTEXTATTRIBSARBPROC glXCreateContextAttribsARB;
81 PFNGLXBINDTEXIMAGEEXTPROC glXBindTexImageEXT;
82 PFNGLXRELEASETEXIMAGEEXTPROC glXReleaseTexImageEXT;
86 static const char *vshader =
88 "uniform vec4 geometry;\n"
90 "in vec2 texture_coord;\n"
91 "out vec2 texcoord;\n"
94 " gl_Position = vec4((geometry.xy+vertex*geometry.zw)*2.0-1.0, 0.0, 1.0);\n"
95 " texcoord = texture_coord;\n"
98 static const char *fshader =
100 "uniform sampler2D image;\n"
101 "in vec2 texcoord;\n"
102 "out vec4 frag_color;\n"
105 " frag_color = texture(image, texcoord);\n"
108 static const float window_vertices[] =
110 /* vertex texcoord */
111 0.0f, 1.0f, 0.0f, 0.0f,
112 0.0f, 0.0f, 0.0f, 1.0f,
113 1.0f, 1.0f, 1.0f, 0.0f,
114 1.0f, 0.0f, 1.0f, 1.0f
117 int terminate_requested = 0;
119 int x_error_handler(Display *display, XErrorEvent *event)
121 printf("Ignoring X error %d on resource %lx\n", event->error_code, event->resourceid);
126 int with_error(const char *message)
128 fprintf(stderr, "%s\n", message);
132 int initialize_gl(Compositor *compositor, CompositedScreen *screen)
136 GLXFBConfig *configs;
139 XSetWindowAttributes win_attr;
142 attribs[i++] = GLX_DRAWABLE_TYPE;
143 attribs[i++] = GLX_WINDOW_BIT;
144 attribs[i++] = GLX_RENDER_TYPE;
145 attribs[i++] = GLX_RGBA_BIT;
146 attribs[i++] = GLX_DOUBLEBUFFER;
148 attribs[i++] = GLX_BIND_TO_TEXTURE_RGBA_EXT;
152 configs = glXChooseFBConfig(compositor->display, screen->number, attribs, &nconfigs);
153 if(!configs || !nconfigs)
154 return with_error("Could not find a suitable FBConfig");
155 screen->fbconfig = configs[0];
158 vi = glXGetVisualFromFBConfig(compositor->display, screen->fbconfig);
159 win_attr.colormap = XCreateColormap(compositor->display, screen->root, vi->visual, AllocNone);
160 screen->render_window = XCreateWindow(compositor->display, screen->overlay, 0, 0, screen->width, screen->height, 0, vi->depth, InputOutput, vi->visual, CWColormap, &win_attr);
161 XMapWindow(compositor->display, screen->render_window);
163 screen->glx_window = glXCreateWindow(compositor->display, screen->fbconfig, screen->render_window, NULL);
166 attribs[i++] = GLX_CONTEXT_FLAGS_ARB;
167 attribs[i++] = GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB;
168 attribs[i++] = GLX_CONTEXT_MAJOR_VERSION_ARB;
170 attribs[i++] = GLX_CONTEXT_MINOR_VERSION_ARB;
174 screen->glx_context = compositor->glXCreateContextAttribsARB(compositor->display, screen->fbconfig, NULL, True, attribs);
181 void use_gl(Compositor *compositor, CompositedScreen *screen)
183 glXMakeContextCurrent(compositor->display, screen->glx_window, screen->glx_window, screen->glx_context);
186 unsigned compile_shader(GLenum type, const char *source)
193 shader = glCreateShader(type);
194 glShaderSource(shader, 1, &source, NULL);
195 glCompileShader(shader);
196 glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
197 glGetShaderInfoLog(shader, sizeof(info_log), &length, info_log);
200 fprintf(stderr, "Shader compilation failed:\n%s\n", info_log);
201 glDeleteShader(shader);
205 printf("Shader info log:\n%s\n", info_log);
210 unsigned link_program(unsigned *shaders, unsigned nshaders)
218 program = glCreateProgram();
219 for(i=0; i<nshaders; ++i)
220 glAttachShader(program, shaders[i]);
221 glBindAttribLocation(program, 0, "vertex");
222 glBindAttribLocation(program, 1, "texture_coord");
223 glBindFragDataLocation(program, 0, "frag_color");
224 glLinkProgram(program);
226 glGetProgramiv(program, GL_LINK_STATUS, &status);
227 glGetProgramInfoLog(program, sizeof(info_log), &length, info_log);
230 fprintf(stderr, "Program link failed:\n%s\n", info_log);
231 glDeleteProgram(program);
235 printf("Program info log:\n%s\n", info_log);
240 int create_gl_resources(Compositor *compositor, CompositedScreen *screen)
244 use_gl(compositor, screen);
246 screen->shaders[0] = compile_shader(GL_VERTEX_SHADER, vshader);
247 screen->shaders[1] = compile_shader(GL_FRAGMENT_SHADER, fshader);
248 if(!screen->shaders[0] || !screen->shaders[1])
251 screen->program = link_program(screen->shaders, 2);
255 screen->geometry_loc = glGetUniformLocation(screen->program, "geometry");
257 glGenBuffers(1, &screen->window_vertex_buffer);
258 glBindBuffer(GL_ARRAY_BUFFER, screen->window_vertex_buffer);
259 glBufferData(GL_ARRAY_BUFFER, sizeof(window_vertices), window_vertices, GL_STATIC_DRAW);
261 stride = 4*sizeof(float);
262 glGenVertexArrays(1, &screen->window_vertex_array);
263 glBindVertexArray(screen->window_vertex_array);
264 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, stride, NULL);
265 glEnableVertexAttribArray(0);
266 glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, stride, (void *)(2*sizeof(float)));
267 glEnableVertexAttribArray(1);
268 glBindVertexArray(0);
270 glBindBuffer(GL_ARRAY_BUFFER, 0);
272 glGenTextures(1, &screen->fb_texture);
273 glBindTexture(GL_TEXTURE_2D, screen->fb_texture);
274 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, screen->width, screen->height, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
275 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
276 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
277 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
278 glBindTexture(GL_TEXTURE_2D, 0);
280 glGenFramebuffers(1, &screen->framebuffer);
281 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, screen->framebuffer);
282 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, screen->fb_texture, 0);
283 glDepthMask(GL_FALSE);
284 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
289 CompositedWindow *find_window(CompositedScreen *screen, Window w)
293 for(i=0; i<screen->nwindows; ++i)
294 if(screen->windows[i].window==w)
295 return &screen->windows[i];
300 void create_window_pixmap(Compositor *compositor, CompositedScreen *screen, CompositedWindow *window)
307 glXDestroyPixmap(compositor->display, window->glx_pixmap);
308 XFreePixmap(compositor->display, window->pixmap);
312 attribs[i++] = GLX_TEXTURE_TARGET_EXT;
313 attribs[i++] = GLX_TEXTURE_2D_EXT;
314 attribs[i++] = GLX_TEXTURE_FORMAT_EXT;
315 attribs[i++] = GLX_TEXTURE_FORMAT_RGBA_EXT;
318 window->pixmap = XCompositeNameWindowPixmap(compositor->display, window->window);
319 window->glx_pixmap = glXCreatePixmap(compositor->display, screen->fbconfig, window->pixmap, attribs);
322 CompositedWindow *add_window(Compositor *compositor, CompositedScreen *screen, Window w)
324 CompositedWindow *window;
325 XWindowAttributes win_attr;
327 if(w==screen->root || w==screen->overlay)
330 if(!XGetWindowAttributes(compositor->display, w, &win_attr))
332 printf("XGetWindowAttributes failed; probably the window was already destroyed\n");
335 if(win_attr.class==InputOnly)
338 if(find_window(screen, w))
341 if(screen->nwindows==screen->windows_capacity)
343 screen->windows = (CompositedWindow *)realloc(screen->windows, (screen->windows_capacity+1)*sizeof(CompositedWindow));
344 ++screen->windows_capacity;
347 window = &screen->windows[screen->nwindows++];
350 window->x = win_attr.x;
351 window->y = win_attr.y;
352 window->width = win_attr.width;
353 window->height = win_attr.height;
354 window->border = win_attr.border_width;
355 window->map_state = win_attr.map_state;
357 window->damage = XDamageCreate(compositor->display, window->window, XDamageReportNonEmpty);
358 window->pixmap = None;
359 window->glx_pixmap = None;
361 XCompositeRedirectWindow(compositor->display, window->window, CompositeRedirectManual);
362 if(window->map_state==IsViewable)
363 create_window_pixmap(compositor, screen, window);
365 glGenTextures(1, &window->texture);
366 glBindTexture(GL_TEXTURE_2D, window->texture);
367 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
368 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
369 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
374 void remove_window(Compositor *compositor, CompositedScreen *screen, CompositedWindow *window, int destroyed)
378 glDeleteTextures(1, &window->texture);
381 XDamageDestroy(compositor->display, window->damage);
384 glXDestroyPixmap(compositor->display, window->glx_pixmap);
385 XFreePixmap(compositor->display, window->pixmap);
387 XCompositeUnredirectWindow(compositor->display, window->window, CompositeRedirectManual);
391 for(i=window-screen->windows; i<screen->nwindows; ++i)
392 screen->windows[i] = screen->windows[i+1];
395 CompositedWindow *reorder_window(CompositedScreen *screen, CompositedWindow *window, Window above)
398 CompositedWindow hold;
400 i = window-screen->windows;
403 for(j=0; j<screen->nwindows; ++j)
404 if(screen->windows[j].window==above)
407 if(j>=screen->nwindows || i==j+1)
420 screen->windows[i] = screen->windows[i+1];
425 screen->windows[i] = screen->windows[i-1];
427 screen->windows[j] = hold;
429 return &screen->windows[j];
432 CompositedScreen *find_screen_by_root(Compositor *compositor, Window root)
436 for(i=0; i<compositor->nscreens; ++i)
437 if(compositor->screens[i].root==root)
438 return &compositor->screens[i];
443 CompositedScreen *find_screen_by_window(Compositor *compositor, Window w)
447 for(i=0; i<compositor->nscreens; ++i)
448 for(j=0; j<compositor->screens[i].nwindows; ++j)
449 if(compositor->screens[i].windows[j].window==w)
450 return &compositor->screens[i];
455 void update_monitor_vertices(CompositedScreen *screen, CompositedMonitor *monitor)
460 unsigned short *index_data;
468 t = monitor->tessellation;
470 data_size = (t+1)*(t+1)*4*sizeof(float);
471 vertex_data = (float *)malloc(data_size);
472 aspect = (float)monitor->width/monitor->height;
473 cyl_w_sq = 0.25f-(0.5f-monitor->cylinder_depth)*(0.5f-monitor->cylinder_depth);
474 sin_ksv = monitor->keystone_vertical/sqrt(1.0f+monitor->keystone_vertical*monitor->keystone_vertical);
475 cos_ksv = sqrt(1.0f-sin_ksv*sin_ksv);
486 v = vertex_data+(y*(t+1)+x)*4;
487 v[2] = (monitor->x+xf*monitor->width)/screen->width;
488 v[3] = (monitor->y+yf*monitor->height)/screen->height;
490 z = sqrt(0.25f-(xf-0.5f)*(xf-0.5f)*4.0f*cyl_w_sq)-0.5f+monitor->cylinder_depth;
491 if(monitor->keystone_vertical>0)
493 rz = (1.0f-yf)/aspect*sin_ksv+z*cos_ksv;
494 yf = 1.0f-((1.0f-yf)*cos_ksv-z*aspect*sin_ksv);
497 else if(monitor->keystone_vertical<0)
499 rz = z*cos_ksv-yf/aspect*sin_ksv;
500 yf = yf*cos_ksv+z*aspect*sin_ksv;
503 scale = monitor->perspective/(monitor->perspective+z);
504 v[0] = 0.5f+(xf-0.5f)*scale;
505 v[1] = monitor->vertical_center+(yf-monitor->vertical_center)*scale;
507 glBindBuffer(GL_ARRAY_BUFFER, monitor->vertex_buffer);
508 glBufferData(GL_ARRAY_BUFFER, data_size, vertex_data, GL_STATIC_DRAW);
509 glBindBuffer(GL_ARRAY_BUFFER, 0);
512 monitor->nelements = t*((t+1)*2+1)-1;
513 data_size = monitor->nelements*sizeof(unsigned short);
514 index_data = (unsigned short *)malloc(data_size);
519 index_data[i++] = 0xFFFF;
522 index_data[i++] = (y+1)*(t+1)+x;
523 index_data[i++] = y*(t+1)+x;
526 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, monitor->index_buffer);
527 glBufferData(GL_ELEMENT_ARRAY_BUFFER, data_size, index_data, GL_STATIC_DRAW);
528 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
532 int initialize_monitor(Compositor *compositor, CompositedScreen *screen, CompositedMonitor *monitor, XRRScreenResources *xrr_res, unsigned index)
534 XRROutputInfo *output;
539 output = XRRGetOutputInfo(compositor->display, xrr_res, xrr_res->outputs[index]);
540 monitor->enabled = !!output->crtc;
541 if(!monitor->enabled)
543 XRRFreeOutputInfo(output);
547 crtc = XRRGetCrtcInfo(compositor->display, xrr_res, output->crtc);
548 monitor->x = crtc->x;
549 monitor->y = crtc->y;
550 monitor->width = crtc->width;
551 monitor->height = crtc->height;
552 XRRFreeCrtcInfo(crtc);
553 XRRFreeOutputInfo(output);
555 monitor->keystone_vertical = 0.0f;
556 monitor->cylinder_depth = 0.0f;
557 monitor->vertical_center = 0.5f;
558 monitor->perspective = 1.0f;
560 glGenBuffers(2, buffers);
561 monitor->vertex_buffer = buffers[0];
562 monitor->index_buffer = buffers[1];
564 monitor->tessellation = 50;
565 update_monitor_vertices(screen, monitor);
566 stride = 4*sizeof(float);
568 glGenVertexArrays(1, &monitor->vertex_array);
569 glBindVertexArray(monitor->vertex_array);
570 glBindBuffer(GL_ARRAY_BUFFER, monitor->vertex_buffer);
571 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, stride, NULL);
572 glEnableVertexAttribArray(0);
573 glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, stride, (void *)(2*sizeof(float)));
574 glEnableVertexAttribArray(1);
575 glBindBuffer(GL_ARRAY_BUFFER, 0);
576 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, monitor->index_buffer);
577 glBindVertexArray(0);
582 int initialize_screen(Compositor *compositor, unsigned number)
584 CompositedScreen *screen;
585 const char *extensions;
590 XRRScreenResources *xrr_res;
596 screen = &compositor->screens[number];
597 screen->number = number;
599 extensions = glXQueryExtensionsString(compositor->display, screen->number);
600 if(!strstr(extensions, "GLX_ARB_create_context"))
601 return with_error("GLX_ARB_create_context is required");
602 if(!strstr(extensions, "GLX_EXT_texture_from_pixmap"))
603 return with_error("GLX_EXT_texture_from_pixmap is required");
605 screen->root = RootWindow(compositor->display, screen->number);
606 XSelectInput(compositor->display, screen->root, SubstructureNotifyMask);
607 screen->overlay = XCompositeGetOverlayWindow(compositor->display, screen->root);
608 XGetGeometry(compositor->display, screen->overlay, &dummy_root, &x, &y, &screen->width, &screen->height, &border, &depth);
609 XShapeCombineRectangles(compositor->display, screen->overlay, ShapeInput, 0, 0, NULL, 0, ShapeSet, Unsorted);
611 if(!initialize_gl(compositor, screen))
614 if(!create_gl_resources(compositor, screen))
617 xrr_res = XRRGetScreenResources(compositor->display, screen->root);
618 screen->nmonitors = xrr_res->noutput;
619 screen->monitors = (CompositedMonitor *)malloc(screen->nmonitors*sizeof(CompositedMonitor));
620 for(i=0; i<screen->nmonitors; ++i)
621 if(!initialize_monitor(compositor, screen, &screen->monitors[i], xrr_res, i))
623 XRRFreeScreenResources(xrr_res);
625 XQueryTree(compositor->display, screen->root, &dummy_root, &dummy_parent, &children, &nchildren);
627 screen->windows = (CompositedWindow *)malloc(nchildren*sizeof(CompositedWindow));
628 screen->nwindows = 0;
629 screen->windows_capacity = nchildren;
631 for(i=0; i<nchildren; ++i)
632 add_window(compositor, screen, children[i]);
641 int initialize_compositor(Compositor *compositor)
649 compositor->display = XOpenDisplay(NULL);
650 if(!compositor->display)
651 return with_error("Could not open X display");
653 XSetErrorHandler(&x_error_handler);
655 if(!XCompositeQueryExtension(compositor->display, &event_base, &error_base))
656 return with_error("XComposite is required but was not found");
657 else if(!XCompositeQueryVersion(compositor->display, &major_ver, &minor_ver))
658 return with_error("Cannot determine XComposite version");
659 else if(major_ver==0 && minor_ver<3)
660 return with_error("XComposite 0.3 or later is required");
662 if(!glXQueryExtension(compositor->display, &event_base, &error_base))
663 return with_error("GLX is required but was not found");
664 else if(!glXQueryVersion(compositor->display, &major_ver, &minor_ver))
665 return with_error("Cannot determine GLX version");
666 else if(major_ver<1 || (major_ver==1 && minor_ver<4))
667 return with_error("GLX 1.4 or later is required");
669 if(!XDamageQueryExtension(compositor->display, &compositor->damage_event, &error_base))
670 return with_error("XDamage is required but was not found");
671 else if(!XDamageQueryVersion(compositor->display, &major_ver, &minor_ver))
672 return with_error("Cannot determine XDamage version");
674 return with_error("XDamage 1.0 or later is required");
676 if(!XShapeQueryExtension(compositor->display, &event_base, &error_base))
677 return with_error("XShape is required but was not found");
678 else if(!XShapeQueryVersion(compositor->display, &major_ver, &minor_ver))
679 return with_error("Cannot determine XShape version");
680 else if(major_ver<1 || (major_ver==1 && minor_ver<1))
681 return with_error("XShape 1.1 or later is required");
683 if(!XRRQueryExtension(compositor->display, &event_base, &error_base))
684 return with_error("XRandR is required but was not found");
685 else if(!XRRQueryVersion(compositor->display, &major_ver, &minor_ver))
686 return with_error("Cannot determine XRandR version");
687 else if(major_ver<1 || (major_ver==1 && minor_ver<2))
688 return with_error("XRandR 1.2 or later is required");
690 compositor->glXCreateContextAttribsARB = (PFNGLXCREATECONTEXTATTRIBSARBPROC)glXGetProcAddress((unsigned char *)"glXCreateContextAttribsARB");
691 compositor->glXBindTexImageEXT = (PFNGLXBINDTEXIMAGEEXTPROC)glXGetProcAddress((unsigned char *)"glXBindTexImageEXT");
692 compositor->glXReleaseTexImageEXT = (PFNGLXRELEASETEXIMAGEEXTPROC)glXGetProcAddress((unsigned char *)"glXReleaseTexImageEXT");
694 compositor->nscreens = ScreenCount(compositor->display);
695 compositor->screens = (CompositedScreen *)malloc(compositor->nscreens*sizeof(CompositedScreen));
696 for(i=0; i<compositor->nscreens; ++i)
697 if(!initialize_screen(compositor, i))
700 compositor->dirty = 1;
705 void shutdown_screen(Compositor *compositor, CompositedScreen *screen)
709 use_gl(compositor, screen);
711 for(i=0; i<screen->nwindows; ++i)
713 glDeleteTextures(1, &screen->windows[i].texture);
714 if(screen->windows[i].pixmap)
716 glXDestroyPixmap(compositor->display, screen->windows[i].glx_pixmap);
717 XFreePixmap(compositor->display, screen->windows[i].pixmap);
718 XDamageDestroy(compositor->display, screen->windows[i].damage);
722 for(i=0; i<screen->nmonitors; ++i)
723 if(screen->monitors[i].enabled)
725 glDeleteBuffers(1, &screen->monitors[i].vertex_buffer);
726 glDeleteBuffers(1, &screen->monitors[i].index_buffer);
727 glDeleteVertexArrays(1, &screen->monitors[i].vertex_array);
730 glDeleteBuffers(1, &screen->window_vertex_buffer);
731 glDeleteVertexArrays(1, &screen->window_vertex_array);
732 glDeleteFramebuffers(1, &screen->framebuffer);
733 glDeleteTextures(1, &screen->fb_texture);
734 glDeleteProgram(screen->program);
735 glDeleteShader(screen->shaders[0]);
736 glDeleteShader(screen->shaders[1]);
738 glXMakeContextCurrent(compositor->display, 0, 0, NULL);
739 glXDestroyContext(compositor->display, screen->glx_context);
740 glXDestroyWindow(compositor->display, screen->glx_window);
741 XDestroyWindow(compositor->display, screen->render_window);
743 XCompositeReleaseOverlayWindow(compositor->display, screen->overlay);
745 free(screen->windows);
746 free(screen->monitors);
749 void shutdown_compositor(Compositor *compositor)
753 for(i=0; i<compositor->nscreens; ++i)
754 shutdown_screen(compositor, &compositor->screens[i]);
755 free(compositor->screens);
757 XCloseDisplay(compositor->display);
760 void mark_dirty(Compositor *compositor, CompositedScreen *screen)
762 compositor->dirty = 1;
766 void process_create_window_event(Compositor *compositor, XCreateWindowEvent *event)
768 CompositedScreen *screen;
770 if((screen = find_screen_by_root(compositor, event->parent)))
771 add_window(compositor, screen, event->window);
774 void process_destroy_window_event(Compositor *compositor, XDestroyWindowEvent *event)
776 CompositedScreen *screen;
777 CompositedWindow *window;
779 if((screen = find_screen_by_root(compositor, event->event)))
780 if((window = find_window(screen, event->window)))
781 remove_window(compositor, screen, window, 1);
784 void process_map_event(Compositor *compositor, XMapEvent *event)
786 CompositedScreen *screen;
787 CompositedWindow *window;
789 screen = find_screen_by_root(compositor, event->event);
793 window = find_window(screen, event->window);
797 window->map_state = IsViewable;
798 create_window_pixmap(compositor, screen, window);
800 mark_dirty(compositor, screen);
803 void process_unmap_event(Compositor *compositor, XUnmapEvent *event)
805 CompositedScreen *screen;
806 CompositedWindow *window;
808 screen = find_screen_by_root(compositor, event->event);
812 window = find_window(screen, event->window);
814 window->map_state = IsUnviewable;
816 mark_dirty(compositor, screen);
819 void process_reparent_event(Compositor *compositor, XReparentEvent *event)
821 CompositedScreen *screen;
822 CompositedWindow *window;
824 screen = find_screen_by_root(compositor, event->event);
828 if(event->parent==screen->root)
829 window = add_window(compositor, screen, event->window);
832 window = find_window(screen, event->window);
836 remove_window(compositor, screen, window, 0);
839 if(window && window->map_state==IsViewable)
840 mark_dirty(compositor, screen);
843 void process_configure_event(Compositor *compositor, XConfigureEvent *event)
845 CompositedScreen *screen;
846 CompositedWindow *window;
848 screen = find_screen_by_root(compositor, event->event);
852 window = find_window(screen, event->window);
856 window->x = event->x;
857 window->y = event->y;
858 if((unsigned)event->width!=window->width || (unsigned)event->height!=window->height || (unsigned)event->border_width!=window->border)
860 window->width = event->width;
861 window->height = event->height;
862 window->border = event->border_width;
863 create_window_pixmap(compositor, screen, window);
865 reorder_window(screen, window, event->above);
867 if(window->map_state==IsViewable)
868 mark_dirty(compositor, screen);
871 void process_damage_event(Compositor *compositor, XDamageNotifyEvent *event)
873 CompositedScreen *screen;
874 CompositedWindow *window;
876 screen = find_screen_by_window(compositor, event->drawable);
880 window = find_window(screen, event->drawable);
881 if(window->map_state==IsViewable)
882 mark_dirty(compositor, screen);
885 int process_event(Compositor *compositor)
888 if(compositor->dirty)
890 if(!XCheckMaskEvent(compositor->display, -1, &event))
894 XNextEvent(compositor->display, &event);
899 process_create_window_event(compositor, &event.xcreatewindow);
902 process_destroy_window_event(compositor, &event.xdestroywindow);
905 process_map_event(compositor, &event.xmap);
908 process_unmap_event(compositor, &event.xunmap);
911 process_reparent_event(compositor, &event.xreparent);
913 case ConfigureNotify:
914 process_configure_event(compositor, &event.xconfigure);
917 if(event.type==compositor->damage_event+XDamageNotify)
918 process_damage_event(compositor, (XDamageNotifyEvent *)&event);
920 printf("Event %d\n", event.type);
926 void refresh_screen(Compositor *compositor, CompositedScreen *screen)
930 use_gl(compositor, screen);
932 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, screen->framebuffer);
934 glClearColor(0.5f, 0.5f, 0.5f, 0.0f);
935 glClear(GL_COLOR_BUFFER_BIT);
937 glUseProgram(screen->program);
938 glBindVertexArray(screen->window_vertex_array);
939 for(i=0; i<screen->nwindows; ++i)
941 CompositedWindow *window = &screen->windows[i];
942 if(window->map_state!=IsViewable)
945 glBindTexture(GL_TEXTURE_2D, window->texture);
946 compositor->glXBindTexImageEXT(compositor->display, window->glx_pixmap, GLX_FRONT_LEFT_EXT, NULL);
947 glUniform4f(screen->geometry_loc,
948 (float)window->x/screen->width, ((float)screen->height-window->y-window->height)/screen->height,
949 (float)(window->width+2*window->border)/screen->width, (float)(window->height+2*window->border)/screen->height);
950 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
951 compositor->glXReleaseTexImageEXT(compositor->display, window->glx_pixmap, GLX_FRONT_LEFT_EXT);
952 XDamageSubtract(compositor->display, window->damage, None, None);
955 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
956 glClearColor(0.5f, 0.0f, 0.5f, 0.0f);
957 glClear(GL_COLOR_BUFFER_BIT);
958 glBindTexture(GL_TEXTURE_2D, screen->fb_texture);
959 glEnable(GL_PRIMITIVE_RESTART);
960 glPrimitiveRestartIndex(0xFFFF);
962 for(i=0; i<screen->nmonitors; ++i)
964 CompositedMonitor *monitor = &screen->monitors[i];
965 if(!monitor->enabled)
968 glUniform4f(screen->geometry_loc,
969 (float)monitor->x/screen->width, (float)monitor->y/screen->height,
970 (float)monitor->width/screen->width, (float)monitor->height/screen->height);
972 glBindVertexArray(monitor->vertex_array);
973 glDrawElements(GL_TRIANGLE_STRIP, monitor->nelements, GL_UNSIGNED_SHORT, NULL);
976 glXSwapBuffers(compositor->display, screen->glx_window);
981 void refresh_all_screens(Compositor *compositor)
985 for(i=0; i<compositor->nscreens; ++i)
987 CompositedScreen *screen = &compositor->screens[i];
989 refresh_screen(compositor, screen);
992 compositor->dirty = 0;
995 void sighandler(int sig)
997 terminate_requested = 1;
1003 Compositor compositor;
1005 signal(SIGINT, &sighandler);
1006 signal(SIGTERM, &sighandler);
1008 if(!initialize_compositor(&compositor))
1011 while(!terminate_requested)
1013 if(!process_event(&compositor))
1014 refresh_all_screens(&compositor);
1017 shutdown_compositor(&compositor);