1 #define GL_GLEXT_PROTOTYPES
9 #include <X11/extensions/Xcomposite.h>
10 #include <X11/extensions/Xdamage.h>
11 #include <X11/extensions/shape.h>
12 #include <X11/extensions/Xrandr.h>
16 typedef struct CompositedWindow
31 typedef struct CompositedMonitor
39 float keystone_vertical;
41 float vertical_center;
43 unsigned vertex_buffer;
44 unsigned index_buffer;
45 unsigned vertex_array;
46 unsigned tessellation;
50 typedef struct CompositedScreen
60 GLXContext glx_context;
63 unsigned geometry_loc;
64 unsigned window_vertex_buffer;
65 unsigned window_vertex_array;
68 CompositedWindow *windows;
70 unsigned windows_capacity;
71 CompositedMonitor *monitors;
76 typedef struct Compositor
79 CompositedScreen *screens;
82 PFNGLXCREATECONTEXTATTRIBSARBPROC glXCreateContextAttribsARB;
83 PFNGLXBINDTEXIMAGEEXTPROC glXBindTexImageEXT;
84 PFNGLXRELEASETEXIMAGEEXTPROC glXReleaseTexImageEXT;
90 static const char *vshader =
92 "uniform vec4 geometry;\n"
94 "in vec2 texture_coord;\n"
95 "out vec2 texcoord;\n"
98 " gl_Position = vec4((geometry.xy+vertex*geometry.zw)*2.0-1.0, 0.0, 1.0);\n"
99 " texcoord = texture_coord;\n"
102 static const char *fshader =
104 "uniform sampler2D image;\n"
105 "in vec2 texcoord;\n"
106 "out vec4 frag_color;\n"
109 " frag_color = texture(image, texcoord);\n"
112 static const float window_vertices[] =
114 /* vertex texcoord */
115 0.0f, 1.0f, 0.0f, 0.0f,
116 0.0f, 0.0f, 0.0f, 1.0f,
117 1.0f, 1.0f, 1.0f, 0.0f,
118 1.0f, 0.0f, 1.0f, 1.0f
121 int terminate_requested = 0;
123 int x_error_handler(Display *display, XErrorEvent *event)
125 printf("Ignoring X error %d on resource %lx\n", event->error_code, event->resourceid);
130 int with_error(const char *message)
132 fprintf(stderr, "%s\n", message);
136 int initialize_gl(Compositor *compositor, CompositedScreen *screen)
140 GLXFBConfig *configs;
143 XSetWindowAttributes win_attr;
146 attribs[i++] = GLX_DRAWABLE_TYPE;
147 attribs[i++] = GLX_WINDOW_BIT;
148 attribs[i++] = GLX_RENDER_TYPE;
149 attribs[i++] = GLX_RGBA_BIT;
150 attribs[i++] = GLX_DOUBLEBUFFER;
152 attribs[i++] = GLX_BIND_TO_TEXTURE_RGBA_EXT;
156 configs = glXChooseFBConfig(compositor->display, screen->number, attribs, &nconfigs);
157 if(!configs || !nconfigs)
158 return with_error("Could not find a suitable FBConfig");
159 screen->fbconfig = configs[0];
162 vi = glXGetVisualFromFBConfig(compositor->display, screen->fbconfig);
163 win_attr.colormap = XCreateColormap(compositor->display, screen->root, vi->visual, AllocNone);
164 screen->render_window = XCreateWindow(compositor->display, screen->overlay, 0, 0, screen->width, screen->height, 0, vi->depth, InputOutput, vi->visual, CWColormap, &win_attr);
165 XMapWindow(compositor->display, screen->render_window);
167 screen->glx_window = glXCreateWindow(compositor->display, screen->fbconfig, screen->render_window, NULL);
170 attribs[i++] = GLX_CONTEXT_FLAGS_ARB;
171 attribs[i++] = GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB;
172 attribs[i++] = GLX_CONTEXT_MAJOR_VERSION_ARB;
174 attribs[i++] = GLX_CONTEXT_MINOR_VERSION_ARB;
178 screen->glx_context = compositor->glXCreateContextAttribsARB(compositor->display, screen->fbconfig, NULL, True, attribs);
185 void use_gl(Compositor *compositor, CompositedScreen *screen)
187 glXMakeContextCurrent(compositor->display, screen->glx_window, screen->glx_window, screen->glx_context);
190 unsigned compile_shader(GLenum type, const char *source)
197 shader = glCreateShader(type);
198 glShaderSource(shader, 1, &source, NULL);
199 glCompileShader(shader);
200 glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
201 glGetShaderInfoLog(shader, sizeof(info_log), &length, info_log);
204 fprintf(stderr, "Shader compilation failed:\n%s\n", info_log);
205 glDeleteShader(shader);
209 printf("Shader info log:\n%s\n", info_log);
214 unsigned link_program(unsigned *shaders, unsigned nshaders)
222 program = glCreateProgram();
223 for(i=0; i<nshaders; ++i)
224 glAttachShader(program, shaders[i]);
225 glBindAttribLocation(program, 0, "vertex");
226 glBindAttribLocation(program, 1, "texture_coord");
227 glBindFragDataLocation(program, 0, "frag_color");
228 glLinkProgram(program);
230 glGetProgramiv(program, GL_LINK_STATUS, &status);
231 glGetProgramInfoLog(program, sizeof(info_log), &length, info_log);
234 fprintf(stderr, "Program link failed:\n%s\n", info_log);
235 glDeleteProgram(program);
239 printf("Program info log:\n%s\n", info_log);
244 int create_gl_resources(Compositor *compositor, CompositedScreen *screen)
248 use_gl(compositor, screen);
250 screen->shaders[0] = compile_shader(GL_VERTEX_SHADER, vshader);
251 screen->shaders[1] = compile_shader(GL_FRAGMENT_SHADER, fshader);
252 if(!screen->shaders[0] || !screen->shaders[1])
255 screen->program = link_program(screen->shaders, 2);
259 screen->geometry_loc = glGetUniformLocation(screen->program, "geometry");
261 glGenBuffers(1, &screen->window_vertex_buffer);
262 glBindBuffer(GL_ARRAY_BUFFER, screen->window_vertex_buffer);
263 glBufferData(GL_ARRAY_BUFFER, sizeof(window_vertices), window_vertices, GL_STATIC_DRAW);
265 stride = 4*sizeof(float);
266 glGenVertexArrays(1, &screen->window_vertex_array);
267 glBindVertexArray(screen->window_vertex_array);
268 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, stride, NULL);
269 glEnableVertexAttribArray(0);
270 glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, stride, (void *)(2*sizeof(float)));
271 glEnableVertexAttribArray(1);
272 glBindVertexArray(0);
274 glBindBuffer(GL_ARRAY_BUFFER, 0);
276 glGenTextures(1, &screen->fb_texture);
277 glBindTexture(GL_TEXTURE_2D, screen->fb_texture);
278 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, screen->width, screen->height, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
279 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
280 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
281 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
282 glBindTexture(GL_TEXTURE_2D, 0);
284 glGenFramebuffers(1, &screen->framebuffer);
285 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, screen->framebuffer);
286 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, screen->fb_texture, 0);
287 glDepthMask(GL_FALSE);
288 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
293 CompositedWindow *find_window(CompositedScreen *screen, Window w)
297 for(i=0; i<screen->nwindows; ++i)
298 if(screen->windows[i].window==w)
299 return &screen->windows[i];
304 void create_window_pixmap(Compositor *compositor, CompositedScreen *screen, CompositedWindow *window)
311 glXDestroyPixmap(compositor->display, window->glx_pixmap);
312 XFreePixmap(compositor->display, window->pixmap);
316 attribs[i++] = GLX_TEXTURE_TARGET_EXT;
317 attribs[i++] = GLX_TEXTURE_2D_EXT;
318 attribs[i++] = GLX_TEXTURE_FORMAT_EXT;
319 attribs[i++] = GLX_TEXTURE_FORMAT_RGBA_EXT;
322 window->pixmap = XCompositeNameWindowPixmap(compositor->display, window->window);
323 window->glx_pixmap = glXCreatePixmap(compositor->display, screen->fbconfig, window->pixmap, attribs);
326 CompositedWindow *add_window(Compositor *compositor, CompositedScreen *screen, Window w)
328 CompositedWindow *window;
329 XWindowAttributes win_attr;
331 if(w==screen->root || w==screen->overlay)
334 if(!XGetWindowAttributes(compositor->display, w, &win_attr))
336 printf("XGetWindowAttributes failed; probably the window was already destroyed\n");
339 if(win_attr.class==InputOnly)
342 if(find_window(screen, w))
345 if(screen->nwindows==screen->windows_capacity)
347 screen->windows = (CompositedWindow *)realloc(screen->windows, (screen->windows_capacity+1)*sizeof(CompositedWindow));
348 ++screen->windows_capacity;
351 window = &screen->windows[screen->nwindows++];
354 window->x = win_attr.x;
355 window->y = win_attr.y;
356 window->width = win_attr.width;
357 window->height = win_attr.height;
358 window->border = win_attr.border_width;
359 window->map_state = win_attr.map_state;
361 window->damage = XDamageCreate(compositor->display, window->window, XDamageReportNonEmpty);
362 window->pixmap = None;
363 window->glx_pixmap = None;
365 XCompositeRedirectWindow(compositor->display, window->window, CompositeRedirectManual);
366 if(window->map_state==IsViewable)
367 create_window_pixmap(compositor, screen, window);
369 glGenTextures(1, &window->texture);
370 glBindTexture(GL_TEXTURE_2D, window->texture);
371 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
372 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
373 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
378 void remove_window(Compositor *compositor, CompositedScreen *screen, CompositedWindow *window, int destroyed)
382 glDeleteTextures(1, &window->texture);
385 XDamageDestroy(compositor->display, window->damage);
388 glXDestroyPixmap(compositor->display, window->glx_pixmap);
389 XFreePixmap(compositor->display, window->pixmap);
391 XCompositeUnredirectWindow(compositor->display, window->window, CompositeRedirectManual);
395 for(i=window-screen->windows; i<screen->nwindows; ++i)
396 screen->windows[i] = screen->windows[i+1];
399 CompositedWindow *reorder_window(CompositedScreen *screen, CompositedWindow *window, Window above)
402 CompositedWindow hold;
404 i = window-screen->windows;
407 for(j=0; j<screen->nwindows; ++j)
408 if(screen->windows[j].window==above)
411 if(j>=screen->nwindows || i==j+1)
424 screen->windows[i] = screen->windows[i+1];
429 screen->windows[i] = screen->windows[i-1];
431 screen->windows[j] = hold;
433 return &screen->windows[j];
436 CompositedScreen *find_screen_by_root(Compositor *compositor, Window root)
440 for(i=0; i<compositor->nscreens; ++i)
441 if(compositor->screens[i].root==root)
442 return &compositor->screens[i];
447 CompositedScreen *find_screen_by_window(Compositor *compositor, Window w)
451 for(i=0; i<compositor->nscreens; ++i)
452 for(j=0; j<compositor->screens[i].nwindows; ++j)
453 if(compositor->screens[i].windows[j].window==w)
454 return &compositor->screens[i];
459 void update_monitor_vertices(CompositedScreen *screen, CompositedMonitor *monitor)
464 unsigned short *index_data;
476 t = monitor->tessellation;
478 data_size = (t+1)*(t+1)*4*sizeof(float);
479 vertex_data = (float *)malloc(data_size);
481 aspect = (float)monitor->width/monitor->height;
483 if(monitor->cylinder_depth)
485 cyl_radius = (monitor->cylinder_depth*monitor->cylinder_depth+0.25f)/(2.0f*monitor->cylinder_depth);
486 cyl_arc = 2.0f*asin(0.5f/cyl_radius);
489 sin_ksv = monitor->keystone_vertical/sqrt(1.0f+monitor->keystone_vertical*monitor->keystone_vertical);
490 cos_ksv = sqrt(1.0f-sin_ksv*sin_ksv);
491 distance = monitor->perspective+sin_ksv*((sin_ksv>0)-monitor->vertical_center)/aspect;
494 eye[1] = (monitor->vertical_center-0.5f)/aspect+sin_ksv*distance;
495 eye[2] = cos_ksv*distance;
506 v = vertex_data+(y*(t+1)+x)*3;
507 v[0] = (float)x/t-0.5f;
508 v[1] = ((float)y/t-0.5f)/aspect;
510 if(monitor->cylinder_depth)
512 v[2] = (1.0f-cos(v[0]*cyl_arc))*cyl_radius-monitor->cylinder_depth;
513 v[0] = sin(v[0]*cyl_arc)*cyl_radius;
524 v = vertex_data+(y*(t+1)+x)*3;
526 py = (v[0]-eye[0])*look[0] - (v[1]-eye[1])*look[2] + (v[2]-eye[2])*look[1];
527 pz = (v[0]-eye[0])*look[0] + (v[1]-eye[1])*look[1] + (v[2]-eye[2])*look[2];
528 scale = monitor->perspective/pz;
530 v = vertex_data+(y*(t+1)+x)*4;
531 v[0] = px*scale+0.5f;
532 v[1] = py*aspect*scale+monitor->vertical_center;
533 v[2] = (monitor->x+(float)x*monitor->width/t)/screen->width;
534 v[3] = 1.0f-(monitor->y+(1.0f-(float)y/t)*monitor->height)/screen->height;
537 glBindBuffer(GL_ARRAY_BUFFER, monitor->vertex_buffer);
538 glBufferData(GL_ARRAY_BUFFER, data_size, vertex_data, GL_STATIC_DRAW);
539 glBindBuffer(GL_ARRAY_BUFFER, 0);
542 monitor->nelements = t*((t+1)*2+1)-1;
543 data_size = monitor->nelements*sizeof(unsigned short);
544 index_data = (unsigned short *)malloc(data_size);
549 index_data[i++] = 0xFFFF;
552 index_data[i++] = (y+1)*(t+1)+x;
553 index_data[i++] = y*(t+1)+x;
556 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, monitor->index_buffer);
557 glBufferData(GL_ELEMENT_ARRAY_BUFFER, data_size, index_data, GL_STATIC_DRAW);
558 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
562 int initialize_monitor(Compositor *compositor, CompositedScreen *screen, XRRScreenResources *xrr_res, unsigned index)
564 CompositedMonitor *monitor;
565 XRROutputInfo *output;
571 monitor = &screen->monitors[index];
573 output = XRRGetOutputInfo(compositor->display, xrr_res, xrr_res->outputs[index]);
574 namelen = strlen(output->name);
575 monitor->name = (char *)malloc(namelen+1);
576 strcpy(monitor->name, output->name);
577 monitor->enabled = !!output->crtc;
578 if(!monitor->enabled)
580 XRRFreeOutputInfo(output);
584 crtc = XRRGetCrtcInfo(compositor->display, xrr_res, output->crtc);
585 monitor->x = crtc->x;
586 monitor->y = crtc->y;
587 monitor->width = crtc->width;
588 monitor->height = crtc->height;
589 XRRFreeCrtcInfo(crtc);
590 XRRFreeOutputInfo(output);
592 monitor->keystone_vertical = 0.0f;
593 monitor->cylinder_depth = 0.0f;
594 monitor->vertical_center = 0.5f;
595 monitor->perspective = 1.0f;
597 glGenBuffers(2, buffers);
598 monitor->vertex_buffer = buffers[0];
599 monitor->index_buffer = buffers[1];
601 monitor->tessellation = 50;
602 update_monitor_vertices(screen, monitor);
603 stride = 4*sizeof(float);
605 glGenVertexArrays(1, &monitor->vertex_array);
606 glBindVertexArray(monitor->vertex_array);
607 glBindBuffer(GL_ARRAY_BUFFER, monitor->vertex_buffer);
608 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, stride, NULL);
609 glEnableVertexAttribArray(0);
610 glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, stride, (void *)(2*sizeof(float)));
611 glEnableVertexAttribArray(1);
612 glBindBuffer(GL_ARRAY_BUFFER, 0);
613 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, monitor->index_buffer);
614 glBindVertexArray(0);
619 CompositedMonitor *find_monitor_by_name(CompositedScreen *screen, char *name)
623 for(i=0; i<screen->nmonitors; ++i)
624 if(!strcmp(screen->monitors[i].name, name))
625 return &screen->monitors[i];
630 void update_geometry_correction(Compositor *compositor, CompositedScreen *screen)
634 unsigned long overflow;
635 unsigned long names_length;
637 unsigned long values_length;
642 XGetWindowProperty(compositor->display, screen->root, compositor->monitors_atom, 0, 64, False, XA_STRING,
643 &prop_type, &prop_format, &names_length, &overflow, (unsigned char **)&names);
644 if(prop_type!=XA_STRING || prop_format!=8)
647 XGetWindowProperty(compositor->display, screen->root, compositor->correction_atom, 0, 64, False, XA_INTEGER,
648 &prop_type, &prop_format, &values_length, &overflow, (unsigned char **)&values);
649 if(prop_type!=XA_INTEGER || prop_format!=16)
655 use_gl(compositor, screen);
658 for(i=0; i*4<values_length; ++i)
660 CompositedMonitor *monitor;
662 if(name_ptr>=names+names_length)
665 monitor = find_monitor_by_name(screen, name_ptr);
668 monitor->keystone_vertical = values[i*4]/10000.0f;
669 monitor->cylinder_depth = values[i*4+1]/10000.0f;
670 monitor->vertical_center = values[i*4+2]/10000.0f;
671 monitor->perspective = values[i*4+3]/10000.0f;
674 update_monitor_vertices(screen, monitor);
677 name_ptr += strlen(name_ptr)+1;
684 int initialize_screen(Compositor *compositor, unsigned number)
686 CompositedScreen *screen;
687 const char *extensions;
692 XRRScreenResources *xrr_res;
698 screen = &compositor->screens[number];
699 screen->number = number;
701 extensions = glXQueryExtensionsString(compositor->display, screen->number);
702 if(!strstr(extensions, "GLX_ARB_create_context"))
703 return with_error("GLX_ARB_create_context is required");
704 if(!strstr(extensions, "GLX_EXT_texture_from_pixmap"))
705 return with_error("GLX_EXT_texture_from_pixmap is required");
707 screen->root = RootWindow(compositor->display, screen->number);
708 XSelectInput(compositor->display, screen->root, SubstructureNotifyMask|PropertyChangeMask);
709 screen->overlay = XCompositeGetOverlayWindow(compositor->display, screen->root);
710 XGetGeometry(compositor->display, screen->overlay, &dummy_root, &x, &y, &screen->width, &screen->height, &border, &depth);
711 XShapeCombineRectangles(compositor->display, screen->overlay, ShapeInput, 0, 0, NULL, 0, ShapeSet, Unsorted);
713 if(!initialize_gl(compositor, screen))
716 if(!create_gl_resources(compositor, screen))
719 xrr_res = XRRGetScreenResources(compositor->display, screen->root);
720 screen->nmonitors = xrr_res->noutput;
721 screen->monitors = (CompositedMonitor *)malloc(screen->nmonitors*sizeof(CompositedMonitor));
722 for(i=0; i<screen->nmonitors; ++i)
723 if(!initialize_monitor(compositor, screen, xrr_res, i))
725 XRRFreeScreenResources(xrr_res);
727 update_geometry_correction(compositor, screen);
729 XQueryTree(compositor->display, screen->root, &dummy_root, &dummy_parent, &children, &nchildren);
731 screen->windows = (CompositedWindow *)malloc(nchildren*sizeof(CompositedWindow));
732 screen->nwindows = 0;
733 screen->windows_capacity = nchildren;
735 for(i=0; i<nchildren; ++i)
736 add_window(compositor, screen, children[i]);
745 int initialize_compositor(Compositor *compositor)
753 compositor->display = XOpenDisplay(NULL);
754 if(!compositor->display)
755 return with_error("Could not open X display");
757 XSetErrorHandler(&x_error_handler);
759 if(!XCompositeQueryExtension(compositor->display, &event_base, &error_base))
760 return with_error("XComposite is required but was not found");
761 else if(!XCompositeQueryVersion(compositor->display, &major_ver, &minor_ver))
762 return with_error("Cannot determine XComposite version");
763 else if(major_ver==0 && minor_ver<3)
764 return with_error("XComposite 0.3 or later is required");
766 if(!glXQueryExtension(compositor->display, &event_base, &error_base))
767 return with_error("GLX is required but was not found");
768 else if(!glXQueryVersion(compositor->display, &major_ver, &minor_ver))
769 return with_error("Cannot determine GLX version");
770 else if(major_ver<1 || (major_ver==1 && minor_ver<4))
771 return with_error("GLX 1.4 or later is required");
773 if(!XDamageQueryExtension(compositor->display, &compositor->damage_event, &error_base))
774 return with_error("XDamage is required but was not found");
775 else if(!XDamageQueryVersion(compositor->display, &major_ver, &minor_ver))
776 return with_error("Cannot determine XDamage version");
778 return with_error("XDamage 1.0 or later is required");
780 if(!XShapeQueryExtension(compositor->display, &event_base, &error_base))
781 return with_error("XShape is required but was not found");
782 else if(!XShapeQueryVersion(compositor->display, &major_ver, &minor_ver))
783 return with_error("Cannot determine XShape version");
784 else if(major_ver<1 || (major_ver==1 && minor_ver<1))
785 return with_error("XShape 1.1 or later is required");
787 if(!XRRQueryExtension(compositor->display, &event_base, &error_base))
788 return with_error("XRandR is required but was not found");
789 else if(!XRRQueryVersion(compositor->display, &major_ver, &minor_ver))
790 return with_error("Cannot determine XRandR version");
791 else if(major_ver<1 || (major_ver==1 && minor_ver<2))
792 return with_error("XRandR 1.2 or later is required");
794 compositor->glXCreateContextAttribsARB = (PFNGLXCREATECONTEXTATTRIBSARBPROC)glXGetProcAddress((unsigned char *)"glXCreateContextAttribsARB");
795 compositor->glXBindTexImageEXT = (PFNGLXBINDTEXIMAGEEXTPROC)glXGetProcAddress((unsigned char *)"glXBindTexImageEXT");
796 compositor->glXReleaseTexImageEXT = (PFNGLXRELEASETEXIMAGEEXTPROC)glXGetProcAddress((unsigned char *)"glXReleaseTexImageEXT");
798 compositor->correction_atom = XInternAtom(compositor->display, "GEOMETRY_CORRECTION", False);
799 compositor->monitors_atom = XInternAtom(compositor->display, "GEOMETRY_CORRECTION_MONITORS", False);
801 compositor->nscreens = ScreenCount(compositor->display);
802 compositor->screens = (CompositedScreen *)malloc(compositor->nscreens*sizeof(CompositedScreen));
803 for(i=0; i<compositor->nscreens; ++i)
804 if(!initialize_screen(compositor, i))
807 compositor->dirty = 1;
812 void shutdown_screen(Compositor *compositor, CompositedScreen *screen)
816 use_gl(compositor, screen);
818 for(i=0; i<screen->nwindows; ++i)
820 glDeleteTextures(1, &screen->windows[i].texture);
821 if(screen->windows[i].pixmap)
823 glXDestroyPixmap(compositor->display, screen->windows[i].glx_pixmap);
824 XFreePixmap(compositor->display, screen->windows[i].pixmap);
825 XDamageDestroy(compositor->display, screen->windows[i].damage);
829 for(i=0; i<screen->nmonitors; ++i)
831 free(screen->monitors[i].name);
832 if(screen->monitors[i].enabled)
834 glDeleteBuffers(1, &screen->monitors[i].vertex_buffer);
835 glDeleteBuffers(1, &screen->monitors[i].index_buffer);
836 glDeleteVertexArrays(1, &screen->monitors[i].vertex_array);
840 glDeleteBuffers(1, &screen->window_vertex_buffer);
841 glDeleteVertexArrays(1, &screen->window_vertex_array);
842 glDeleteFramebuffers(1, &screen->framebuffer);
843 glDeleteTextures(1, &screen->fb_texture);
844 glDeleteProgram(screen->program);
845 glDeleteShader(screen->shaders[0]);
846 glDeleteShader(screen->shaders[1]);
848 glXMakeContextCurrent(compositor->display, 0, 0, NULL);
849 glXDestroyContext(compositor->display, screen->glx_context);
850 glXDestroyWindow(compositor->display, screen->glx_window);
851 XDestroyWindow(compositor->display, screen->render_window);
853 XCompositeReleaseOverlayWindow(compositor->display, screen->overlay);
855 free(screen->windows);
856 free(screen->monitors);
859 void shutdown_compositor(Compositor *compositor)
863 for(i=0; i<compositor->nscreens; ++i)
864 shutdown_screen(compositor, &compositor->screens[i]);
865 free(compositor->screens);
867 XCloseDisplay(compositor->display);
870 void mark_dirty(Compositor *compositor, CompositedScreen *screen)
872 compositor->dirty = 1;
876 void process_create_window_event(Compositor *compositor, XCreateWindowEvent *event)
878 CompositedScreen *screen;
880 if((screen = find_screen_by_root(compositor, event->parent)))
881 add_window(compositor, screen, event->window);
884 void process_destroy_window_event(Compositor *compositor, XDestroyWindowEvent *event)
886 CompositedScreen *screen;
887 CompositedWindow *window;
889 if((screen = find_screen_by_root(compositor, event->event)))
890 if((window = find_window(screen, event->window)))
891 remove_window(compositor, screen, window, 1);
894 void process_map_event(Compositor *compositor, XMapEvent *event)
896 CompositedScreen *screen;
897 CompositedWindow *window;
899 screen = find_screen_by_root(compositor, event->event);
903 window = find_window(screen, event->window);
907 window->map_state = IsViewable;
908 create_window_pixmap(compositor, screen, window);
910 mark_dirty(compositor, screen);
913 void process_unmap_event(Compositor *compositor, XUnmapEvent *event)
915 CompositedScreen *screen;
916 CompositedWindow *window;
918 screen = find_screen_by_root(compositor, event->event);
922 window = find_window(screen, event->window);
924 window->map_state = IsUnviewable;
926 mark_dirty(compositor, screen);
929 void process_reparent_event(Compositor *compositor, XReparentEvent *event)
931 CompositedScreen *screen;
932 CompositedWindow *window;
934 screen = find_screen_by_root(compositor, event->event);
938 if(event->parent==screen->root)
939 window = add_window(compositor, screen, event->window);
942 window = find_window(screen, event->window);
946 remove_window(compositor, screen, window, 0);
949 if(window && window->map_state==IsViewable)
950 mark_dirty(compositor, screen);
953 void process_configure_event(Compositor *compositor, XConfigureEvent *event)
955 CompositedScreen *screen;
956 CompositedWindow *window;
958 screen = find_screen_by_root(compositor, event->event);
962 window = find_window(screen, event->window);
966 window->x = event->x;
967 window->y = event->y;
968 if((unsigned)event->width!=window->width || (unsigned)event->height!=window->height || (unsigned)event->border_width!=window->border)
970 window->width = event->width;
971 window->height = event->height;
972 window->border = event->border_width;
973 create_window_pixmap(compositor, screen, window);
975 reorder_window(screen, window, event->above);
977 if(window->map_state==IsViewable)
978 mark_dirty(compositor, screen);
981 void process_property_event(Compositor *compositor, XPropertyEvent *event)
983 CompositedScreen *screen;
985 if(event->atom!=compositor->correction_atom)
988 screen = find_screen_by_root(compositor, event->window);
992 update_geometry_correction(compositor, screen);
995 void process_damage_event(Compositor *compositor, XDamageNotifyEvent *event)
997 CompositedScreen *screen;
998 CompositedWindow *window;
1000 screen = find_screen_by_window(compositor, event->drawable);
1004 window = find_window(screen, event->drawable);
1005 if(window->map_state==IsViewable)
1006 mark_dirty(compositor, screen);
1009 int process_event(Compositor *compositor)
1012 if(compositor->dirty)
1014 if(!XCheckMaskEvent(compositor->display, -1, &event))
1018 XNextEvent(compositor->display, &event);
1023 process_create_window_event(compositor, &event.xcreatewindow);
1026 process_destroy_window_event(compositor, &event.xdestroywindow);
1029 process_map_event(compositor, &event.xmap);
1032 process_unmap_event(compositor, &event.xunmap);
1034 case ReparentNotify:
1035 process_reparent_event(compositor, &event.xreparent);
1037 case ConfigureNotify:
1038 process_configure_event(compositor, &event.xconfigure);
1040 case PropertyNotify:
1041 process_property_event(compositor, &event.xproperty);
1044 if(event.type==compositor->damage_event+XDamageNotify)
1045 process_damage_event(compositor, (XDamageNotifyEvent *)&event);
1047 printf("Event %d\n", event.type);
1053 void refresh_screen(Compositor *compositor, CompositedScreen *screen)
1057 use_gl(compositor, screen);
1059 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, screen->framebuffer);
1061 glClearColor(0.5f, 0.5f, 0.5f, 0.0f);
1062 glClear(GL_COLOR_BUFFER_BIT);
1064 glUseProgram(screen->program);
1065 glBindVertexArray(screen->window_vertex_array);
1066 for(i=0; i<screen->nwindows; ++i)
1068 CompositedWindow *window = &screen->windows[i];
1069 if(window->map_state!=IsViewable)
1072 XDamageSubtract(compositor->display, window->damage, None, None);
1074 glBindTexture(GL_TEXTURE_2D, window->texture);
1075 compositor->glXBindTexImageEXT(compositor->display, window->glx_pixmap, GLX_FRONT_LEFT_EXT, NULL);
1076 glUniform4f(screen->geometry_loc,
1077 (float)window->x/screen->width, 1.0f-(float)(window->y+window->height)/screen->height,
1078 (float)(window->width+2*window->border)/screen->width, (float)(window->height+2*window->border)/screen->height);
1079 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
1080 compositor->glXReleaseTexImageEXT(compositor->display, window->glx_pixmap, GLX_FRONT_LEFT_EXT);
1083 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
1084 glClearColor(0.5f, 0.0f, 0.5f, 0.0f);
1085 glClear(GL_COLOR_BUFFER_BIT);
1086 glBindTexture(GL_TEXTURE_2D, screen->fb_texture);
1087 glEnable(GL_PRIMITIVE_RESTART);
1088 glPrimitiveRestartIndex(0xFFFF);
1090 for(i=0; i<screen->nmonitors; ++i)
1092 CompositedMonitor *monitor = &screen->monitors[i];
1093 if(!monitor->enabled)
1096 glUniform4f(screen->geometry_loc,
1097 (float)monitor->x/screen->width, 1.0f-(float)(monitor->y+monitor->height)/screen->height,
1098 (float)monitor->width/screen->width, (float)monitor->height/screen->height);
1100 glBindVertexArray(monitor->vertex_array);
1101 glDrawElements(GL_TRIANGLE_STRIP, monitor->nelements, GL_UNSIGNED_SHORT, NULL);
1104 glBindVertexArray(0);
1106 glXSwapBuffers(compositor->display, screen->glx_window);
1111 void refresh_all_screens(Compositor *compositor)
1115 for(i=0; i<compositor->nscreens; ++i)
1117 CompositedScreen *screen = &compositor->screens[i];
1119 refresh_screen(compositor, screen);
1122 compositor->dirty = 0;
1125 void sighandler(int sig)
1127 terminate_requested = 1;
1133 Compositor compositor;
1135 signal(SIGINT, &sighandler);
1136 signal(SIGTERM, &sighandler);
1138 if(!initialize_compositor(&compositor))
1141 while(!terminate_requested)
1143 if(!process_event(&compositor))
1144 refresh_all_screens(&compositor);
1147 shutdown_compositor(&compositor);