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
30 unsigned mask_texture;
35 typedef struct CompositedMonitor
43 float keystone_vertical;
45 float vertical_center;
47 unsigned vertex_buffer;
48 unsigned index_buffer;
49 unsigned vertex_array;
50 unsigned tessellation;
54 typedef struct CompositedScreen
64 GLXContext glx_context;
68 unsigned masked_program;
69 int masked_geometry_loc;
70 unsigned window_vertex_buffer;
71 unsigned window_vertex_array;
75 GLXPixmap root_glx_pixmap;
76 unsigned root_texture;
77 CompositedWindow *windows;
79 unsigned windows_capacity;
80 CompositedMonitor *monitors;
85 typedef struct Compositor
88 CompositedScreen *screens;
92 PFNGLXCREATECONTEXTATTRIBSARBPROC glXCreateContextAttribsARB;
93 PFNGLXBINDTEXIMAGEEXTPROC glXBindTexImageEXT;
94 PFNGLXRELEASETEXIMAGEEXTPROC glXReleaseTexImageEXT;
101 static const char *vshader_src =
103 "uniform vec4 geometry;\n"
105 "in vec2 texture_coord;\n"
106 "out vec2 texcoord;\n"
109 " gl_Position = vec4((geometry.xy+vertex*geometry.zw)*2.0-1.0, 0.0, 1.0);\n"
110 " texcoord = texture_coord;\n"
113 static const char *fshader_src =
115 "uniform sampler2D image;\n"
116 "in vec2 texcoord;\n"
117 "out vec4 frag_color;\n"
120 " frag_color = texture(image, texcoord);\n"
123 static const char *masked_fshader_src =
125 "uniform sampler2D image;\n"
126 "uniform sampler2D mask;\n"
127 "in vec2 texcoord;\n"
128 "out vec4 frag_color;\n"
131 " if(texture(mask, texcoord).r==0.0)\n"
133 " frag_color = texture(image, texcoord);\n"
136 static const float window_vertices[] =
138 /* vertex texcoord */
139 0.0f, 1.0f, 0.0f, 0.0f,
140 0.0f, 0.0f, 0.0f, 1.0f,
141 1.0f, 1.0f, 1.0f, 0.0f,
142 1.0f, 0.0f, 1.0f, 1.0f
145 int terminate_requested = 0;
147 int x_error_handler(Display *display, XErrorEvent *event)
149 printf("Ignoring X error %d on resource %lx\n", event->error_code, event->resourceid);
154 int with_error(const char *message)
156 fprintf(stderr, "%s\n", message);
160 int initialize_gl(Compositor *compositor, CompositedScreen *screen)
164 GLXFBConfig *configs;
167 XSetWindowAttributes win_attr;
170 attribs[i++] = GLX_DRAWABLE_TYPE;
171 attribs[i++] = GLX_WINDOW_BIT;
172 attribs[i++] = GLX_RENDER_TYPE;
173 attribs[i++] = GLX_RGBA_BIT;
174 attribs[i++] = GLX_DOUBLEBUFFER;
176 attribs[i++] = GLX_BIND_TO_TEXTURE_RGBA_EXT;
180 configs = glXChooseFBConfig(compositor->display, screen->number, attribs, &nconfigs);
181 if(!configs || !nconfigs)
182 return with_error("Could not find a suitable FBConfig");
183 screen->fbconfig = configs[0];
186 vi = glXGetVisualFromFBConfig(compositor->display, screen->fbconfig);
187 win_attr.colormap = XCreateColormap(compositor->display, screen->root, vi->visual, AllocNone);
188 screen->render_window = XCreateWindow(compositor->display, screen->overlay, 0, 0, screen->width, screen->height, 0, vi->depth, InputOutput, vi->visual, CWColormap, &win_attr);
189 XMapWindow(compositor->display, screen->render_window);
191 screen->glx_window = glXCreateWindow(compositor->display, screen->fbconfig, screen->render_window, NULL);
194 attribs[i++] = GLX_CONTEXT_FLAGS_ARB;
195 attribs[i++] = GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB;
196 attribs[i++] = GLX_CONTEXT_MAJOR_VERSION_ARB;
198 attribs[i++] = GLX_CONTEXT_MINOR_VERSION_ARB;
202 screen->glx_context = compositor->glXCreateContextAttribsARB(compositor->display, screen->fbconfig, NULL, True, attribs);
209 void use_gl(Compositor *compositor, CompositedScreen *screen)
211 glXMakeContextCurrent(compositor->display, screen->glx_window, screen->glx_window, screen->glx_context);
214 unsigned compile_shader(GLenum type, const char *source)
221 shader = glCreateShader(type);
222 glShaderSource(shader, 1, &source, NULL);
223 glCompileShader(shader);
224 glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
225 glGetShaderInfoLog(shader, sizeof(info_log), &length, info_log);
228 fprintf(stderr, "Shader compilation failed:\n%s\n", info_log);
229 glDeleteShader(shader);
233 printf("Shader info log:\n%s\n", info_log);
238 unsigned link_program(unsigned vshader, unsigned fshader)
245 program = glCreateProgram();
246 glAttachShader(program, vshader);
247 glAttachShader(program, fshader);
248 glBindAttribLocation(program, 0, "vertex");
249 glBindAttribLocation(program, 1, "texture_coord");
250 glBindFragDataLocation(program, 0, "frag_color");
251 glLinkProgram(program);
253 glGetProgramiv(program, GL_LINK_STATUS, &status);
254 glGetProgramInfoLog(program, sizeof(info_log), &length, info_log);
257 fprintf(stderr, "Program link failed:\n%s\n", info_log);
258 glDeleteProgram(program);
262 printf("Program info log:\n%s\n", info_log);
267 unsigned create_2d_texture()
270 glGenTextures(1, &texture);
271 glBindTexture(GL_TEXTURE_2D, texture);
272 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
273 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
274 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
278 int create_gl_resources(CompositedScreen *screen)
283 screen->shaders[0] = compile_shader(GL_VERTEX_SHADER, vshader_src);
284 screen->shaders[1] = compile_shader(GL_FRAGMENT_SHADER, fshader_src);
285 screen->shaders[2] = compile_shader(GL_FRAGMENT_SHADER, masked_fshader_src);
286 if(!screen->shaders[0] || !screen->shaders[1] || !screen->shaders[2])
289 screen->program = link_program(screen->shaders[0], screen->shaders[1]);
293 screen->masked_program = link_program(screen->shaders[0], screen->shaders[2]);
294 if(!screen->masked_program)
297 screen->geometry_loc = glGetUniformLocation(screen->program, "geometry");
298 screen->masked_geometry_loc = glGetUniformLocation(screen->masked_program, "geometry");
300 loc = glGetUniformLocation(screen->masked_program, "mask");
303 glUseProgram(screen->masked_program);
307 glGenBuffers(1, &screen->window_vertex_buffer);
308 glBindBuffer(GL_ARRAY_BUFFER, screen->window_vertex_buffer);
309 glBufferData(GL_ARRAY_BUFFER, sizeof(window_vertices), window_vertices, GL_STATIC_DRAW);
311 stride = 4*sizeof(float);
312 glGenVertexArrays(1, &screen->window_vertex_array);
313 glBindVertexArray(screen->window_vertex_array);
314 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, stride, NULL);
315 glEnableVertexAttribArray(0);
316 glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, stride, (void *)(2*sizeof(float)));
317 glEnableVertexAttribArray(1);
318 glBindVertexArray(0);
320 glBindBuffer(GL_ARRAY_BUFFER, 0);
322 screen->fb_texture = create_2d_texture();
323 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, screen->width, screen->height, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
324 glBindTexture(GL_TEXTURE_2D, 0);
326 glGenFramebuffers(1, &screen->framebuffer);
327 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, screen->framebuffer);
328 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, screen->fb_texture, 0);
329 glDepthMask(GL_FALSE);
330 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
332 screen->root_texture = create_2d_texture();
337 CompositedWindow *find_window(CompositedScreen *screen, Window w)
341 for(i=0; i<screen->nwindows; ++i)
342 if(screen->windows[i].window==w)
343 return &screen->windows[i];
348 CompositedWindow *find_window_global(Compositor *compositor, Window w, CompositedScreen **screen)
352 for(i=0; i<compositor->nscreens; ++i)
353 for(j=0; j<compositor->screens[i].nwindows; ++j)
354 if(compositor->screens[i].windows[j].window==w)
357 *screen = &compositor->screens[i];
358 return &compositor->screens[i].windows[j];
366 GLXPixmap pixmap_to_glx_pixmap(Compositor *compositor, CompositedScreen *screen, Pixmap pixmap)
372 attribs[i++] = GLX_TEXTURE_TARGET_EXT;
373 attribs[i++] = GLX_TEXTURE_2D_EXT;
374 attribs[i++] = GLX_TEXTURE_FORMAT_EXT;
375 attribs[i++] = GLX_TEXTURE_FORMAT_RGBA_EXT;
378 return glXCreatePixmap(compositor->display, screen->fbconfig, pixmap, attribs);
381 void create_window_pixmap(Compositor *compositor, CompositedScreen *screen, CompositedWindow *window)
385 glXDestroyPixmap(compositor->display, window->glx_pixmap);
386 XFreePixmap(compositor->display, window->pixmap);
389 window->pixmap = XCompositeNameWindowPixmap(compositor->display, window->window);
390 window->glx_pixmap = pixmap_to_glx_pixmap(compositor, screen, window->pixmap);
391 window->recreate_pixmap = 0;
394 void update_window_mask(Compositor *compositor, CompositedWindow *window)
396 Bool bounding_shaped;
408 XShapeQueryExtents(compositor->display, window->window, &bounding_shaped, &xi, &yi, &width, &height, &clip_shaped, &xi, &yi, &width, &height);
409 window->use_mask = bounding_shaped;
410 if(!window->use_mask)
413 rects = XShapeGetRectangles(compositor->display, window->window, ShapeBounding, &rect_count, &rect_order);
415 width = window->width+2*window->border;
416 height = window->height+2*window->border;
417 data = (unsigned char *)malloc(width*height);
418 memset(data, 0, width*height);
419 for(i=0; i<rect_count; ++i)
421 rects[i].x += window->border;
422 rects[i].y += window->border;
423 if(rects[i].x>=(int)width || rects[i].y>=(int)height)
428 if(-rects[i].x>rects[i].width)
430 rects[i].width += rects[i].x;
436 if(-rects[i].y>rects[i].height)
438 rects[i].height += rects[i].y;
442 if(rects[i].x+rects[i].width>(int)width)
443 rects[i].width = width-rects[i].x;
444 if(rects[i].y+rects[i].height>(int)height)
445 rects[i].height = height-rects[i].y;
447 for(y=0; y<rects[i].height; ++y)
449 unsigned char *row = data+(rects[i].y+y)*width+rects[i].x;
450 memset(row, 255, rects[i].width);
456 glBindTexture(GL_TEXTURE_2D, window->mask_texture);
457 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
458 glTexImage2D(GL_TEXTURE_2D, 0, GL_R8, width, height, 0, GL_RED, GL_UNSIGNED_BYTE, data);
462 window->recreate_mask = 0;
465 CompositedWindow *add_window(Compositor *compositor, CompositedScreen *screen, Window w)
467 CompositedWindow *window;
468 XWindowAttributes win_attr;
470 if(w==screen->root || w==screen->overlay)
473 if(!XGetWindowAttributes(compositor->display, w, &win_attr))
475 printf("XGetWindowAttributes failed; probably the window was already destroyed\n");
478 if(win_attr.class==InputOnly)
481 if(find_window(screen, w))
484 if(screen->nwindows==screen->windows_capacity)
486 screen->windows = (CompositedWindow *)realloc(screen->windows, (screen->windows_capacity+1)*sizeof(CompositedWindow));
487 ++screen->windows_capacity;
490 window = &screen->windows[screen->nwindows++];
493 window->x = win_attr.x;
494 window->y = win_attr.y;
495 window->width = win_attr.width;
496 window->height = win_attr.height;
497 window->border = win_attr.border_width;
498 window->map_state = win_attr.map_state;
500 window->damage = XDamageCreate(compositor->display, window->window, XDamageReportNonEmpty);
501 window->pixmap = None;
502 window->glx_pixmap = None;
504 XCompositeRedirectWindow(compositor->display, window->window, CompositeRedirectManual);
505 window->recreate_pixmap = (window->map_state==IsViewable);
507 window->texture = create_2d_texture();
508 window->mask_texture = create_2d_texture();
509 window->use_mask = 0;
510 window->recreate_mask = (window->map_state==IsViewable);
512 XShapeSelectInput(compositor->display, window->window, ShapeNotifyMask);
517 void remove_window(Compositor *compositor, CompositedScreen *screen, CompositedWindow *window, int destroyed)
521 glDeleteTextures(1, &window->texture);
524 XDamageDestroy(compositor->display, window->damage);
527 glXDestroyPixmap(compositor->display, window->glx_pixmap);
528 XFreePixmap(compositor->display, window->pixmap);
530 XCompositeUnredirectWindow(compositor->display, window->window, CompositeRedirectManual);
534 for(i=window-screen->windows; i<screen->nwindows; ++i)
535 screen->windows[i] = screen->windows[i+1];
538 CompositedWindow *reorder_window(CompositedScreen *screen, CompositedWindow *window, Window above)
541 CompositedWindow hold;
543 i = window-screen->windows;
546 for(j=0; j<screen->nwindows; ++j)
547 if(screen->windows[j].window==above)
550 if(j>=screen->nwindows || i==j+1)
563 screen->windows[i] = screen->windows[i+1];
568 screen->windows[i] = screen->windows[i-1];
570 screen->windows[j] = hold;
572 return &screen->windows[j];
575 CompositedScreen *find_screen_by_root(Compositor *compositor, Window root)
579 for(i=0; i<compositor->nscreens; ++i)
580 if(compositor->screens[i].root==root)
581 return &compositor->screens[i];
586 void update_monitor_vertices(CompositedScreen *screen, CompositedMonitor *monitor)
591 unsigned short *index_data;
603 t = monitor->tessellation;
605 data_size = (t+1)*(t+1)*4*sizeof(float);
606 vertex_data = (float *)malloc(data_size);
608 aspect = (float)monitor->width/monitor->height;
610 if(monitor->cylinder_depth)
612 cyl_radius = (monitor->cylinder_depth*monitor->cylinder_depth+0.25f)/(2.0f*monitor->cylinder_depth);
613 cyl_arc = 2.0f*asin(0.5f/cyl_radius);
616 sin_ksv = monitor->keystone_vertical/sqrt(1.0f+monitor->keystone_vertical*monitor->keystone_vertical);
617 cos_ksv = sqrt(1.0f-sin_ksv*sin_ksv);
618 distance = monitor->perspective+sin_ksv*((sin_ksv>0)-monitor->vertical_center)/aspect;
621 eye[1] = (monitor->vertical_center-0.5f)/aspect+sin_ksv*distance;
622 eye[2] = cos_ksv*distance;
633 v = vertex_data+(y*(t+1)+x)*3;
634 v[0] = (float)x/t-0.5f;
635 v[1] = ((float)y/t-0.5f)/aspect;
637 if(monitor->cylinder_depth)
639 v[2] = (1.0f-cos(v[0]*cyl_arc))*cyl_radius-monitor->cylinder_depth;
640 v[0] = sin(v[0]*cyl_arc)*cyl_radius;
651 v = vertex_data+(y*(t+1)+x)*3;
653 py = (v[0]-eye[0])*look[0] - (v[1]-eye[1])*look[2] + (v[2]-eye[2])*look[1];
654 pz = (v[0]-eye[0])*look[0] + (v[1]-eye[1])*look[1] + (v[2]-eye[2])*look[2];
655 scale = monitor->perspective/pz;
657 v = vertex_data+(y*(t+1)+x)*4;
658 v[0] = px*scale+0.5f;
659 v[1] = py*aspect*scale+monitor->vertical_center;
660 v[2] = (monitor->x+(float)x*monitor->width/t)/screen->width;
661 v[3] = 1.0f-(monitor->y+(1.0f-(float)y/t)*monitor->height)/screen->height;
664 glBindBuffer(GL_ARRAY_BUFFER, monitor->vertex_buffer);
665 glBufferData(GL_ARRAY_BUFFER, data_size, vertex_data, GL_STATIC_DRAW);
666 glBindBuffer(GL_ARRAY_BUFFER, 0);
669 monitor->nelements = t*((t+1)*2+1)-1;
670 data_size = monitor->nelements*sizeof(unsigned short);
671 index_data = (unsigned short *)malloc(data_size);
676 index_data[i++] = 0xFFFF;
679 index_data[i++] = (y+1)*(t+1)+x;
680 index_data[i++] = y*(t+1)+x;
683 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, monitor->index_buffer);
684 glBufferData(GL_ELEMENT_ARRAY_BUFFER, data_size, index_data, GL_STATIC_DRAW);
685 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
689 int initialize_monitor(Compositor *compositor, CompositedScreen *screen, XRRScreenResources *xrr_res, unsigned index)
691 CompositedMonitor *monitor;
692 XRROutputInfo *output;
698 monitor = &screen->monitors[index];
700 output = XRRGetOutputInfo(compositor->display, xrr_res, xrr_res->outputs[index]);
701 namelen = strlen(output->name);
702 monitor->name = (char *)malloc(namelen+1);
703 strcpy(monitor->name, output->name);
704 monitor->enabled = !!output->crtc;
705 if(!monitor->enabled)
707 XRRFreeOutputInfo(output);
711 crtc = XRRGetCrtcInfo(compositor->display, xrr_res, output->crtc);
712 monitor->x = crtc->x;
713 monitor->y = crtc->y;
714 monitor->width = crtc->width;
715 monitor->height = crtc->height;
716 XRRFreeCrtcInfo(crtc);
717 XRRFreeOutputInfo(output);
719 monitor->keystone_vertical = 0.0f;
720 monitor->cylinder_depth = 0.0f;
721 monitor->vertical_center = 0.5f;
722 monitor->perspective = 1.0f;
724 glGenBuffers(2, buffers);
725 monitor->vertex_buffer = buffers[0];
726 monitor->index_buffer = buffers[1];
728 monitor->tessellation = 50;
729 update_monitor_vertices(screen, monitor);
730 stride = 4*sizeof(float);
732 glGenVertexArrays(1, &monitor->vertex_array);
733 glBindVertexArray(monitor->vertex_array);
734 glBindBuffer(GL_ARRAY_BUFFER, monitor->vertex_buffer);
735 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, stride, NULL);
736 glEnableVertexAttribArray(0);
737 glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, stride, (void *)(2*sizeof(float)));
738 glEnableVertexAttribArray(1);
739 glBindBuffer(GL_ARRAY_BUFFER, 0);
740 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, monitor->index_buffer);
741 glBindVertexArray(0);
746 CompositedMonitor *find_monitor_by_name(CompositedScreen *screen, char *name)
750 for(i=0; i<screen->nmonitors; ++i)
751 if(!strcmp(screen->monitors[i].name, name))
752 return &screen->monitors[i];
757 void update_geometry_correction(Compositor *compositor, CompositedScreen *screen)
761 unsigned long overflow;
762 unsigned long names_length;
764 unsigned long values_length;
769 XGetWindowProperty(compositor->display, screen->root, compositor->monitors_atom, 0, 64, False, XA_STRING,
770 &prop_type, &prop_format, &names_length, &overflow, (unsigned char **)&names);
771 if(prop_type!=XA_STRING || prop_format!=8)
774 XGetWindowProperty(compositor->display, screen->root, compositor->correction_atom, 0, 64, False, XA_INTEGER,
775 &prop_type, &prop_format, &values_length, &overflow, (unsigned char **)&values);
776 if(prop_type!=XA_INTEGER || prop_format!=16)
782 use_gl(compositor, screen);
785 for(i=0; i*4<values_length; ++i)
787 CompositedMonitor *monitor;
789 if(name_ptr>=names+names_length)
792 monitor = find_monitor_by_name(screen, name_ptr);
795 monitor->keystone_vertical = values[i*4]/10000.0f;
796 monitor->cylinder_depth = values[i*4+1]/10000.0f;
797 monitor->vertical_center = values[i*4+2]/10000.0f;
798 monitor->perspective = values[i*4+3]/10000.0f;
801 update_monitor_vertices(screen, monitor);
804 name_ptr += strlen(name_ptr)+1;
811 void update_root_pixmap(Compositor *compositor, CompositedScreen *screen)
815 unsigned long overflow;
816 unsigned long length;
825 use_gl(compositor, screen);
827 if(screen->root_glx_pixmap)
829 glXDestroyPixmap(compositor->display, screen->root_glx_pixmap);
830 screen->root_glx_pixmap = 0;
833 XGetWindowProperty(compositor->display, screen->root, compositor->root_pmap_atom, 0, 1, False, XA_PIXMAP,
834 &prop_type, &prop_format, &length, &overflow, (unsigned char **)&pixmap);
835 if(prop_type!=XA_PIXMAP || prop_format!=32)
837 screen->root_pixmap = 0;
841 screen->root_pixmap = pixmap[0];
842 if(XGetGeometry(compositor->display, screen->root_pixmap, &root, &x, &y, &width, &height, &border, &depth))
843 screen->root_glx_pixmap = pixmap_to_glx_pixmap(compositor, screen, screen->root_pixmap);
845 screen->root_pixmap = None;
850 int initialize_screen(Compositor *compositor, unsigned number)
852 CompositedScreen *screen;
853 const char *extensions;
858 XRRScreenResources *xrr_res;
864 screen = &compositor->screens[number];
865 screen->number = number;
867 extensions = glXQueryExtensionsString(compositor->display, screen->number);
868 if(!strstr(extensions, "GLX_ARB_create_context"))
869 return with_error("GLX_ARB_create_context is required");
870 if(!strstr(extensions, "GLX_EXT_texture_from_pixmap"))
871 return with_error("GLX_EXT_texture_from_pixmap is required");
873 screen->root = RootWindow(compositor->display, screen->number);
874 XSelectInput(compositor->display, screen->root, SubstructureNotifyMask|PropertyChangeMask);
875 screen->overlay = XCompositeGetOverlayWindow(compositor->display, screen->root);
876 XGetGeometry(compositor->display, screen->overlay, &dummy_root, &x, &y, &screen->width, &screen->height, &border, &depth);
877 XShapeCombineRectangles(compositor->display, screen->overlay, ShapeInput, 0, 0, NULL, 0, ShapeSet, Unsorted);
879 if(!initialize_gl(compositor, screen))
882 use_gl(compositor, screen);
884 if(!create_gl_resources(screen))
887 xrr_res = XRRGetScreenResources(compositor->display, screen->root);
888 screen->nmonitors = xrr_res->noutput;
889 screen->monitors = (CompositedMonitor *)malloc(screen->nmonitors*sizeof(CompositedMonitor));
890 for(i=0; i<screen->nmonitors; ++i)
891 if(!initialize_monitor(compositor, screen, xrr_res, i))
893 XRRFreeScreenResources(xrr_res);
895 screen->root_pixmap = 0;
896 screen->root_glx_pixmap = 0;
898 update_geometry_correction(compositor, screen);
899 update_root_pixmap(compositor, screen);
901 XQueryTree(compositor->display, screen->root, &dummy_root, &dummy_parent, &children, &nchildren);
903 screen->windows = (CompositedWindow *)malloc(nchildren*sizeof(CompositedWindow));
904 screen->nwindows = 0;
905 screen->windows_capacity = nchildren;
907 for(i=0; i<nchildren; ++i)
908 add_window(compositor, screen, children[i]);
917 int initialize_compositor(Compositor *compositor)
925 compositor->display = XOpenDisplay(NULL);
926 if(!compositor->display)
927 return with_error("Could not open X display");
929 XSetErrorHandler(&x_error_handler);
931 if(!XCompositeQueryExtension(compositor->display, &event_base, &error_base))
932 return with_error("XComposite is required but was not found");
933 else if(!XCompositeQueryVersion(compositor->display, &major_ver, &minor_ver))
934 return with_error("Cannot determine XComposite version");
935 else if(major_ver==0 && minor_ver<3)
936 return with_error("XComposite 0.3 or later is required");
938 if(!glXQueryExtension(compositor->display, &event_base, &error_base))
939 return with_error("GLX is required but was not found");
940 else if(!glXQueryVersion(compositor->display, &major_ver, &minor_ver))
941 return with_error("Cannot determine GLX version");
942 else if(major_ver<1 || (major_ver==1 && minor_ver<4))
943 return with_error("GLX 1.4 or later is required");
945 if(!XDamageQueryExtension(compositor->display, &compositor->damage_event, &error_base))
946 return with_error("XDamage is required but was not found");
947 else if(!XDamageQueryVersion(compositor->display, &major_ver, &minor_ver))
948 return with_error("Cannot determine XDamage version");
950 return with_error("XDamage 1.0 or later is required");
952 if(!XShapeQueryExtension(compositor->display, &compositor->shape_event, &error_base))
953 return with_error("XShape is required but was not found");
954 else if(!XShapeQueryVersion(compositor->display, &major_ver, &minor_ver))
955 return with_error("Cannot determine XShape version");
956 else if(major_ver<1 || (major_ver==1 && minor_ver<1))
957 return with_error("XShape 1.1 or later is required");
959 if(!XRRQueryExtension(compositor->display, &event_base, &error_base))
960 return with_error("XRandR is required but was not found");
961 else if(!XRRQueryVersion(compositor->display, &major_ver, &minor_ver))
962 return with_error("Cannot determine XRandR version");
963 else if(major_ver<1 || (major_ver==1 && minor_ver<2))
964 return with_error("XRandR 1.2 or later is required");
966 compositor->glXCreateContextAttribsARB = (PFNGLXCREATECONTEXTATTRIBSARBPROC)glXGetProcAddress((unsigned char *)"glXCreateContextAttribsARB");
967 compositor->glXBindTexImageEXT = (PFNGLXBINDTEXIMAGEEXTPROC)glXGetProcAddress((unsigned char *)"glXBindTexImageEXT");
968 compositor->glXReleaseTexImageEXT = (PFNGLXRELEASETEXIMAGEEXTPROC)glXGetProcAddress((unsigned char *)"glXReleaseTexImageEXT");
970 compositor->root_pmap_atom = XInternAtom(compositor->display, "_XROOTPMAP_ID", False);
971 compositor->correction_atom = XInternAtom(compositor->display, "GEOMETRY_CORRECTION", False);
972 compositor->monitors_atom = XInternAtom(compositor->display, "GEOMETRY_CORRECTION_MONITORS", False);
974 compositor->nscreens = ScreenCount(compositor->display);
975 compositor->screens = (CompositedScreen *)malloc(compositor->nscreens*sizeof(CompositedScreen));
976 for(i=0; i<compositor->nscreens; ++i)
977 if(!initialize_screen(compositor, i))
980 compositor->dirty = 1;
985 void shutdown_screen(Compositor *compositor, CompositedScreen *screen)
989 use_gl(compositor, screen);
991 for(i=0; i<screen->nwindows; ++i)
993 glDeleteTextures(1, &screen->windows[i].texture);
994 glDeleteTextures(1, &screen->windows[i].mask_texture);
995 if(screen->windows[i].pixmap)
997 glXDestroyPixmap(compositor->display, screen->windows[i].glx_pixmap);
998 XFreePixmap(compositor->display, screen->windows[i].pixmap);
999 XDamageDestroy(compositor->display, screen->windows[i].damage);
1003 for(i=0; i<screen->nmonitors; ++i)
1005 free(screen->monitors[i].name);
1006 if(screen->monitors[i].enabled)
1008 glDeleteBuffers(1, &screen->monitors[i].vertex_buffer);
1009 glDeleteBuffers(1, &screen->monitors[i].index_buffer);
1010 glDeleteVertexArrays(1, &screen->monitors[i].vertex_array);
1014 glDeleteTextures(1, &screen->root_texture);
1015 glXDestroyPixmap(compositor->display, screen->root_glx_pixmap);
1017 glDeleteBuffers(1, &screen->window_vertex_buffer);
1018 glDeleteVertexArrays(1, &screen->window_vertex_array);
1019 glDeleteFramebuffers(1, &screen->framebuffer);
1020 glDeleteTextures(1, &screen->fb_texture);
1021 glDeleteProgram(screen->program);
1022 glDeleteProgram(screen->masked_program);
1024 glDeleteShader(screen->shaders[i]);
1026 glXMakeContextCurrent(compositor->display, 0, 0, NULL);
1027 glXDestroyContext(compositor->display, screen->glx_context);
1028 glXDestroyWindow(compositor->display, screen->glx_window);
1029 XDestroyWindow(compositor->display, screen->render_window);
1031 XCompositeReleaseOverlayWindow(compositor->display, screen->overlay);
1033 free(screen->windows);
1034 free(screen->monitors);
1037 void shutdown_compositor(Compositor *compositor)
1041 for(i=0; i<compositor->nscreens; ++i)
1042 shutdown_screen(compositor, &compositor->screens[i]);
1043 free(compositor->screens);
1045 XCloseDisplay(compositor->display);
1048 void mark_dirty(Compositor *compositor, CompositedScreen *screen)
1050 compositor->dirty = 1;
1054 void process_create_window_event(Compositor *compositor, XCreateWindowEvent *event)
1056 CompositedScreen *screen;
1058 if((screen = find_screen_by_root(compositor, event->parent)))
1059 add_window(compositor, screen, event->window);
1062 void process_destroy_window_event(Compositor *compositor, XDestroyWindowEvent *event)
1064 CompositedScreen *screen;
1065 CompositedWindow *window;
1067 if((screen = find_screen_by_root(compositor, event->event)))
1068 if((window = find_window(screen, event->window)))
1070 use_gl(compositor, screen);
1071 remove_window(compositor, screen, window, 1);
1075 void process_map_event(Compositor *compositor, XMapEvent *event)
1077 CompositedScreen *screen;
1078 CompositedWindow *window;
1080 screen = find_screen_by_root(compositor, event->event);
1084 window = find_window(screen, event->window);
1088 window->map_state = IsViewable;
1089 window->recreate_pixmap = 1;
1090 window->recreate_mask = 1;
1092 mark_dirty(compositor, screen);
1095 void process_unmap_event(Compositor *compositor, XUnmapEvent *event)
1097 CompositedScreen *screen;
1098 CompositedWindow *window;
1100 screen = find_screen_by_root(compositor, event->event);
1104 window = find_window(screen, event->window);
1106 window->map_state = IsUnviewable;
1108 mark_dirty(compositor, screen);
1111 void process_reparent_event(Compositor *compositor, XReparentEvent *event)
1113 CompositedScreen *screen;
1114 CompositedWindow *window;
1116 screen = find_screen_by_root(compositor, event->event);
1120 if(event->parent==screen->root)
1121 window = add_window(compositor, screen, event->window);
1124 window = find_window(screen, event->window);
1128 remove_window(compositor, screen, window, 0);
1131 if(window && window->map_state==IsViewable)
1132 mark_dirty(compositor, screen);
1135 void process_configure_event(Compositor *compositor, XConfigureEvent *event)
1137 CompositedScreen *screen;
1138 CompositedWindow *window;
1140 screen = find_screen_by_root(compositor, event->event);
1144 window = find_window(screen, event->window);
1148 window->x = event->x;
1149 window->y = event->y;
1150 if((unsigned)event->width!=window->width || (unsigned)event->height!=window->height || (unsigned)event->border_width!=window->border)
1152 window->width = event->width;
1153 window->height = event->height;
1154 window->border = event->border_width;
1155 window->recreate_pixmap = 1;
1157 reorder_window(screen, window, event->above);
1159 if(window->map_state==IsViewable)
1160 mark_dirty(compositor, screen);
1163 void process_property_event(Compositor *compositor, XPropertyEvent *event)
1165 CompositedScreen *screen;
1167 screen = find_screen_by_root(compositor, event->window);
1171 if(event->atom==compositor->correction_atom)
1172 update_geometry_correction(compositor, screen);
1173 else if(event->atom==compositor->root_pmap_atom)
1174 update_root_pixmap(compositor, screen);
1177 void process_damage_event(Compositor *compositor, XDamageNotifyEvent *event)
1179 CompositedScreen *screen;
1180 CompositedWindow *window;
1182 window = find_window_global(compositor, event->drawable, &screen);
1183 if(window && window->map_state==IsViewable)
1184 mark_dirty(compositor, screen);
1187 void process_shape_event(Compositor *compositor, XShapeEvent *event)
1189 CompositedScreen *screen;
1190 CompositedWindow *window;
1192 if(event->kind!=ShapeBounding)
1195 window = find_window_global(compositor, event->window, &screen);
1196 if(window && window->map_state==IsViewable)
1198 window->recreate_mask = 1;
1199 mark_dirty(compositor, screen);
1203 void process_events(Compositor *compositor)
1209 while((pending || !compositor->dirty) && !terminate_requested)
1212 pending = XPending(compositor->display);
1214 XNextEvent(compositor->display, &event);
1221 process_create_window_event(compositor, &event.xcreatewindow);
1224 process_destroy_window_event(compositor, &event.xdestroywindow);
1227 process_map_event(compositor, &event.xmap);
1230 process_unmap_event(compositor, &event.xunmap);
1232 case ReparentNotify:
1233 process_reparent_event(compositor, &event.xreparent);
1235 case ConfigureNotify:
1236 process_configure_event(compositor, &event.xconfigure);
1238 case PropertyNotify:
1239 process_property_event(compositor, &event.xproperty);
1242 if(event.type==compositor->damage_event+XDamageNotify)
1243 process_damage_event(compositor, (XDamageNotifyEvent *)&event);
1244 else if(event.type==compositor->shape_event+ShapeNotify)
1245 process_shape_event(compositor, (XShapeEvent *)&event);
1247 printf("Event %d\n", event.type);
1252 void refresh_screen(Compositor *compositor, CompositedScreen *screen)
1257 for(i=0; i<screen->nwindows; ++i)
1258 if(screen->windows[i].map_state==IsViewable)
1259 XDamageSubtract(compositor->display, screen->windows[i].damage, None, None);
1262 use_gl(compositor, screen);
1264 glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
1265 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, screen->framebuffer);
1268 glBindVertexArray(screen->window_vertex_array);
1270 if(screen->root_pixmap)
1273 glUseProgram(screen->program);
1274 glBindTexture(GL_TEXTURE_2D, screen->root_texture);
1275 compositor->glXBindTexImageEXT(compositor->display, screen->root_glx_pixmap, GLX_FRONT_LEFT_EXT, NULL);
1276 glUniform4f(screen->geometry_loc, 0.0f, 0.0f, 1.0f, 1.0f);
1277 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
1278 compositor->glXReleaseTexImageEXT(compositor->display, screen->root_glx_pixmap, GLX_FRONT_LEFT_EXT);
1281 glClear(GL_COLOR_BUFFER_BIT);
1283 for(i=0; i<screen->nwindows; ++i)
1285 CompositedWindow *window;
1287 window = &screen->windows[i];
1288 if(window->map_state!=IsViewable)
1291 if(window->use_mask!=use_mask)
1293 use_mask = window->use_mask;
1294 glUseProgram(use_mask ? screen->masked_program : screen->program);
1297 if(window->use_mask)
1299 glActiveTexture(GL_TEXTURE1);
1300 glBindTexture(GL_TEXTURE_2D, window->mask_texture);
1301 glActiveTexture(GL_TEXTURE0);
1304 if(window->recreate_pixmap)
1305 create_window_pixmap(compositor, screen, window);
1306 if(window->recreate_mask)
1307 update_window_mask(compositor, window);
1309 glBindTexture(GL_TEXTURE_2D, window->texture);
1310 compositor->glXBindTexImageEXT(compositor->display, window->glx_pixmap, GLX_FRONT_LEFT_EXT, NULL);
1311 glUniform4f((use_mask ? screen->masked_geometry_loc : screen->geometry_loc),
1312 (float)window->x/screen->width, 1.0f-(float)(window->y+window->height)/screen->height,
1313 (float)(window->width+2*window->border)/screen->width, (float)(window->height+2*window->border)/screen->height);
1314 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
1315 compositor->glXReleaseTexImageEXT(compositor->display, window->glx_pixmap, GLX_FRONT_LEFT_EXT);
1318 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
1319 glClear(GL_COLOR_BUFFER_BIT);
1320 glBindTexture(GL_TEXTURE_2D, screen->fb_texture);
1321 glEnable(GL_PRIMITIVE_RESTART);
1322 glPrimitiveRestartIndex(0xFFFF);
1324 glUseProgram(screen->program);
1326 for(i=0; i<screen->nmonitors; ++i)
1328 CompositedMonitor *monitor = &screen->monitors[i];
1329 if(!monitor->enabled)
1332 glUniform4f(screen->geometry_loc,
1333 (float)monitor->x/screen->width, 1.0f-(float)(monitor->y+monitor->height)/screen->height,
1334 (float)monitor->width/screen->width, (float)monitor->height/screen->height);
1336 glBindVertexArray(monitor->vertex_array);
1337 glDrawElements(GL_TRIANGLE_STRIP, monitor->nelements, GL_UNSIGNED_SHORT, NULL);
1340 glBindVertexArray(0);
1342 glXSwapBuffers(compositor->display, screen->glx_window);
1347 void refresh_all_screens(Compositor *compositor)
1351 for(i=0; i<compositor->nscreens; ++i)
1353 CompositedScreen *screen = &compositor->screens[i];
1355 refresh_screen(compositor, screen);
1358 compositor->dirty = 0;
1361 void sighandler(int sig)
1363 terminate_requested = 1;
1369 Compositor compositor;
1371 signal(SIGINT, &sighandler);
1372 signal(SIGTERM, &sighandler);
1374 if(!initialize_compositor(&compositor))
1377 while(!terminate_requested)
1379 process_events(&compositor);
1380 if(compositor.dirty && !terminate_requested)
1381 refresh_all_screens(&compositor);
1384 shutdown_compositor(&compositor);