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;
53 unsigned geometry_data_size;
56 typedef struct CompositedScreen
66 GLXContext glx_context;
70 unsigned masked_program;
71 int masked_geometry_loc;
72 unsigned window_vertex_buffer;
73 unsigned window_vertex_array;
77 GLXPixmap root_glx_pixmap;
78 unsigned root_texture;
79 CompositedWindow *windows;
81 unsigned windows_capacity;
82 CompositedMonitor *monitors;
87 typedef struct Compositor
90 CompositedScreen *screens;
94 PFNGLXCREATECONTEXTATTRIBSARBPROC glXCreateContextAttribsARB;
95 PFNGLXBINDTEXIMAGEEXTPROC glXBindTexImageEXT;
96 PFNGLXRELEASETEXIMAGEEXTPROC glXReleaseTexImageEXT;
100 Atom geometry_data_atom;
101 Window selection_window;
105 static const char *vshader_src =
107 "uniform vec4 geometry;\n"
109 "in vec2 texture_coord;\n"
110 "out vec2 texcoord;\n"
113 " gl_Position = vec4((geometry.xy+vertex*geometry.zw)*2.0-1.0, 0.0, 1.0);\n"
114 " texcoord = texture_coord;\n"
117 static const char *fshader_src =
119 "uniform sampler2D image;\n"
120 "in vec2 texcoord;\n"
121 "out vec4 frag_color;\n"
124 " frag_color = texture(image, texcoord);\n"
127 static const char *masked_fshader_src =
129 "uniform sampler2D image;\n"
130 "uniform sampler2D mask;\n"
131 "in vec2 texcoord;\n"
132 "out vec4 frag_color;\n"
135 " if(texture(mask, texcoord).r==0.0)\n"
137 " frag_color = texture(image, texcoord);\n"
140 static const float window_vertices[] =
142 /* vertex texcoord */
143 0.0f, 1.0f, 0.0f, 0.0f,
144 0.0f, 0.0f, 0.0f, 1.0f,
145 1.0f, 1.0f, 1.0f, 0.0f,
146 1.0f, 0.0f, 1.0f, 1.0f
149 int terminate_requested = 0;
151 int x_error_handler(Display *display, XErrorEvent *event)
153 printf("Ignoring X error %d on resource %lx\n", event->error_code, event->resourceid);
158 int with_error(const char *message)
160 fprintf(stderr, "%s\n", message);
164 int initialize_gl(Compositor *compositor, CompositedScreen *screen)
168 GLXFBConfig *configs;
171 XSetWindowAttributes win_attr;
174 attribs[i++] = GLX_DRAWABLE_TYPE;
175 attribs[i++] = GLX_WINDOW_BIT;
176 attribs[i++] = GLX_RENDER_TYPE;
177 attribs[i++] = GLX_RGBA_BIT;
178 attribs[i++] = GLX_DOUBLEBUFFER;
180 attribs[i++] = GLX_BIND_TO_TEXTURE_RGBA_EXT;
184 configs = glXChooseFBConfig(compositor->display, screen->number, attribs, &nconfigs);
185 if(!configs || !nconfigs)
186 return with_error("Could not find a suitable FBConfig");
187 screen->fbconfig = configs[0];
190 vi = glXGetVisualFromFBConfig(compositor->display, screen->fbconfig);
191 win_attr.colormap = XCreateColormap(compositor->display, screen->root, vi->visual, AllocNone);
192 screen->render_window = XCreateWindow(compositor->display, screen->overlay, 0, 0, screen->width, screen->height, 0, vi->depth, InputOutput, vi->visual, CWColormap, &win_attr);
193 XMapWindow(compositor->display, screen->render_window);
195 screen->glx_window = glXCreateWindow(compositor->display, screen->fbconfig, screen->render_window, NULL);
198 attribs[i++] = GLX_CONTEXT_FLAGS_ARB;
199 attribs[i++] = GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB;
200 attribs[i++] = GLX_CONTEXT_MAJOR_VERSION_ARB;
202 attribs[i++] = GLX_CONTEXT_MINOR_VERSION_ARB;
206 screen->glx_context = compositor->glXCreateContextAttribsARB(compositor->display, screen->fbconfig, NULL, True, attribs);
213 void use_gl(Compositor *compositor, CompositedScreen *screen)
215 glXMakeContextCurrent(compositor->display, screen->glx_window, screen->glx_window, screen->glx_context);
218 unsigned compile_shader(GLenum type, const char *source)
225 shader = glCreateShader(type);
226 glShaderSource(shader, 1, &source, NULL);
227 glCompileShader(shader);
228 glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
229 glGetShaderInfoLog(shader, sizeof(info_log), &length, info_log);
232 fprintf(stderr, "Shader compilation failed:\n%s\n", info_log);
233 glDeleteShader(shader);
237 printf("Shader info log:\n%s\n", info_log);
242 unsigned link_program(unsigned vshader, unsigned fshader)
249 program = glCreateProgram();
250 glAttachShader(program, vshader);
251 glAttachShader(program, fshader);
252 glBindAttribLocation(program, 0, "vertex");
253 glBindAttribLocation(program, 1, "texture_coord");
254 glBindFragDataLocation(program, 0, "frag_color");
255 glLinkProgram(program);
257 glGetProgramiv(program, GL_LINK_STATUS, &status);
258 glGetProgramInfoLog(program, sizeof(info_log), &length, info_log);
261 fprintf(stderr, "Program link failed:\n%s\n", info_log);
262 glDeleteProgram(program);
266 printf("Program info log:\n%s\n", info_log);
271 unsigned create_2d_texture()
274 glGenTextures(1, &texture);
275 glBindTexture(GL_TEXTURE_2D, texture);
276 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
277 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
278 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
282 int create_gl_resources(CompositedScreen *screen)
287 screen->shaders[0] = compile_shader(GL_VERTEX_SHADER, vshader_src);
288 screen->shaders[1] = compile_shader(GL_FRAGMENT_SHADER, fshader_src);
289 screen->shaders[2] = compile_shader(GL_FRAGMENT_SHADER, masked_fshader_src);
290 if(!screen->shaders[0] || !screen->shaders[1] || !screen->shaders[2])
293 screen->program = link_program(screen->shaders[0], screen->shaders[1]);
297 screen->masked_program = link_program(screen->shaders[0], screen->shaders[2]);
298 if(!screen->masked_program)
301 screen->geometry_loc = glGetUniformLocation(screen->program, "geometry");
302 screen->masked_geometry_loc = glGetUniformLocation(screen->masked_program, "geometry");
304 loc = glGetUniformLocation(screen->masked_program, "mask");
307 glUseProgram(screen->masked_program);
311 glGenBuffers(1, &screen->window_vertex_buffer);
312 glBindBuffer(GL_ARRAY_BUFFER, screen->window_vertex_buffer);
313 glBufferData(GL_ARRAY_BUFFER, sizeof(window_vertices), window_vertices, GL_STATIC_DRAW);
315 stride = 4*sizeof(float);
316 glGenVertexArrays(1, &screen->window_vertex_array);
317 glBindVertexArray(screen->window_vertex_array);
318 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, stride, NULL);
319 glEnableVertexAttribArray(0);
320 glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, stride, (void *)(2*sizeof(float)));
321 glEnableVertexAttribArray(1);
322 glBindVertexArray(0);
324 glBindBuffer(GL_ARRAY_BUFFER, 0);
326 screen->fb_texture = create_2d_texture();
327 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, screen->width, screen->height, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
328 glBindTexture(GL_TEXTURE_2D, 0);
330 glGenFramebuffers(1, &screen->framebuffer);
331 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, screen->framebuffer);
332 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, screen->fb_texture, 0);
333 glDepthMask(GL_FALSE);
334 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
336 screen->root_texture = create_2d_texture();
341 CompositedWindow *find_window(CompositedScreen *screen, Window w)
345 for(i=0; i<screen->nwindows; ++i)
346 if(screen->windows[i].window==w)
347 return &screen->windows[i];
352 CompositedWindow *find_window_global(Compositor *compositor, Window w, CompositedScreen **screen)
356 for(i=0; i<compositor->nscreens; ++i)
357 for(j=0; j<compositor->screens[i].nwindows; ++j)
358 if(compositor->screens[i].windows[j].window==w)
361 *screen = &compositor->screens[i];
362 return &compositor->screens[i].windows[j];
370 GLXPixmap pixmap_to_glx_pixmap(Compositor *compositor, CompositedScreen *screen, Pixmap pixmap)
376 attribs[i++] = GLX_TEXTURE_TARGET_EXT;
377 attribs[i++] = GLX_TEXTURE_2D_EXT;
378 attribs[i++] = GLX_TEXTURE_FORMAT_EXT;
379 attribs[i++] = GLX_TEXTURE_FORMAT_RGBA_EXT;
382 return glXCreatePixmap(compositor->display, screen->fbconfig, pixmap, attribs);
385 void create_window_pixmap(Compositor *compositor, CompositedScreen *screen, CompositedWindow *window)
389 glXDestroyPixmap(compositor->display, window->glx_pixmap);
390 XFreePixmap(compositor->display, window->pixmap);
393 window->pixmap = XCompositeNameWindowPixmap(compositor->display, window->window);
394 window->glx_pixmap = pixmap_to_glx_pixmap(compositor, screen, window->pixmap);
395 window->recreate_pixmap = 0;
398 void update_window_mask(Compositor *compositor, CompositedWindow *window)
400 Bool bounding_shaped;
412 XShapeQueryExtents(compositor->display, window->window, &bounding_shaped, &xi, &yi, &width, &height, &clip_shaped, &xi, &yi, &width, &height);
413 window->use_mask = bounding_shaped;
414 if(!window->use_mask)
417 rects = XShapeGetRectangles(compositor->display, window->window, ShapeBounding, &rect_count, &rect_order);
419 width = window->width+2*window->border;
420 height = window->height+2*window->border;
421 data = (unsigned char *)malloc(width*height);
422 memset(data, 0, width*height);
423 for(i=0; i<rect_count; ++i)
425 rects[i].x += window->border;
426 rects[i].y += window->border;
427 if(rects[i].x>=(int)width || rects[i].y>=(int)height)
432 if(-rects[i].x>rects[i].width)
434 rects[i].width += rects[i].x;
440 if(-rects[i].y>rects[i].height)
442 rects[i].height += rects[i].y;
446 if(rects[i].x+rects[i].width>(int)width)
447 rects[i].width = width-rects[i].x;
448 if(rects[i].y+rects[i].height>(int)height)
449 rects[i].height = height-rects[i].y;
451 for(y=0; y<rects[i].height; ++y)
453 unsigned char *row = data+(rects[i].y+y)*width+rects[i].x;
454 memset(row, 255, rects[i].width);
460 glBindTexture(GL_TEXTURE_2D, window->mask_texture);
461 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
462 glTexImage2D(GL_TEXTURE_2D, 0, GL_R8, width, height, 0, GL_RED, GL_UNSIGNED_BYTE, data);
466 window->recreate_mask = 0;
469 CompositedWindow *add_window(Compositor *compositor, CompositedScreen *screen, Window w)
471 CompositedWindow *window;
472 XWindowAttributes win_attr;
474 if(w==screen->root || w==screen->overlay)
477 if(!XGetWindowAttributes(compositor->display, w, &win_attr))
479 printf("XGetWindowAttributes failed; probably the window was already destroyed\n");
482 if(win_attr.class==InputOnly)
485 if(find_window(screen, w))
488 if(screen->nwindows==screen->windows_capacity)
490 screen->windows = (CompositedWindow *)realloc(screen->windows, (screen->windows_capacity+1)*sizeof(CompositedWindow));
491 ++screen->windows_capacity;
494 window = &screen->windows[screen->nwindows++];
497 window->x = win_attr.x;
498 window->y = win_attr.y;
499 window->width = win_attr.width;
500 window->height = win_attr.height;
501 window->border = win_attr.border_width;
502 window->map_state = win_attr.map_state;
504 window->damage = XDamageCreate(compositor->display, window->window, XDamageReportNonEmpty);
505 window->pixmap = None;
506 window->glx_pixmap = None;
508 XCompositeRedirectWindow(compositor->display, window->window, CompositeRedirectManual);
509 window->recreate_pixmap = (window->map_state==IsViewable);
511 window->texture = create_2d_texture();
512 window->mask_texture = create_2d_texture();
513 window->use_mask = 0;
514 window->recreate_mask = (window->map_state==IsViewable);
516 XShapeSelectInput(compositor->display, window->window, ShapeNotifyMask);
521 void remove_window(Compositor *compositor, CompositedScreen *screen, CompositedWindow *window, int destroyed)
525 glDeleteTextures(1, &window->texture);
528 XDamageDestroy(compositor->display, window->damage);
531 glXDestroyPixmap(compositor->display, window->glx_pixmap);
532 XFreePixmap(compositor->display, window->pixmap);
534 XCompositeUnredirectWindow(compositor->display, window->window, CompositeRedirectManual);
538 for(i=window-screen->windows; i<screen->nwindows; ++i)
539 screen->windows[i] = screen->windows[i+1];
542 CompositedWindow *reorder_window(CompositedScreen *screen, CompositedWindow *window, Window above)
545 CompositedWindow hold;
547 i = window-screen->windows;
550 for(j=0; j<screen->nwindows; ++j)
551 if(screen->windows[j].window==above)
554 if(j>=screen->nwindows || i==j+1)
567 screen->windows[i] = screen->windows[i+1];
572 screen->windows[i] = screen->windows[i-1];
574 screen->windows[j] = hold;
576 return &screen->windows[j];
579 CompositedScreen *find_screen_by_root(Compositor *compositor, Window root)
583 for(i=0; i<compositor->nscreens; ++i)
584 if(compositor->screens[i].root==root)
585 return &compositor->screens[i];
590 void update_monitor_vertices(CompositedScreen *screen, CompositedMonitor *monitor)
595 unsigned short *index_data;
607 t = monitor->tessellation;
609 data_size = (t+1)*(t+1)*4*sizeof(float);
610 vertex_data = (float *)malloc(data_size);
612 aspect = (float)monitor->width/monitor->height;
614 if(monitor->cylinder_depth)
616 cyl_radius = (monitor->cylinder_depth*monitor->cylinder_depth+0.25f)/(2.0f*monitor->cylinder_depth);
617 cyl_arc = 2.0f*asin(0.5f/cyl_radius);
620 sin_ksv = monitor->keystone_vertical/sqrt(1.0f+monitor->keystone_vertical*monitor->keystone_vertical);
621 cos_ksv = sqrt(1.0f-sin_ksv*sin_ksv);
622 distance = monitor->perspective+sin_ksv*((sin_ksv>0)-monitor->vertical_center)/aspect;
625 eye[1] = (monitor->vertical_center-0.5f)/aspect+sin_ksv*distance;
626 eye[2] = cos_ksv*distance;
637 v = vertex_data+(y*(t+1)+x)*3;
638 v[0] = (float)x/t-0.5f;
639 v[1] = ((float)y/t-0.5f)/aspect;
641 if(monitor->cylinder_depth)
643 v[2] = (1.0f-cos(v[0]*cyl_arc))*cyl_radius-monitor->cylinder_depth;
644 v[0] = sin(v[0]*cyl_arc)*cyl_radius;
648 monitor->geometry_data[0] = t;
650 monitor->geometry_data[1+i] = eye[i]*10000;
655 monitor->geometry_data[i] = ((x-0.5f)*distance/monitor->perspective)*10000;
656 monitor->geometry_data[i+1] = (eye[1]+look[1]*distance-(y-0.5f)*look[2]*distance/monitor->perspective/aspect)*10000;
657 monitor->geometry_data[i+2] = (eye[2]+look[2]*distance+(y-0.5f)*look[1]*distance/monitor->perspective/aspect)*10000;
659 for(i=0; i<(t+1)*(t+1)*3; ++i)
660 monitor->geometry_data[16+i] = vertex_data[i]*10000;
669 v = vertex_data+(y*(t+1)+x)*3;
671 py = (v[0]-eye[0])*look[0] - (v[1]-eye[1])*look[2] + (v[2]-eye[2])*look[1];
672 pz = (v[0]-eye[0])*look[0] + (v[1]-eye[1])*look[1] + (v[2]-eye[2])*look[2];
673 scale = monitor->perspective/pz;
675 v = vertex_data+(y*(t+1)+x)*4;
676 v[0] = px*scale+0.5f;
677 v[1] = py*aspect*scale+monitor->vertical_center;
678 v[2] = (monitor->x+(float)x*monitor->width/t)/screen->width;
679 v[3] = 1.0f-(monitor->y+(1.0f-(float)y/t)*monitor->height)/screen->height;
682 glBindBuffer(GL_ARRAY_BUFFER, monitor->vertex_buffer);
683 glBufferData(GL_ARRAY_BUFFER, data_size, vertex_data, GL_STATIC_DRAW);
684 glBindBuffer(GL_ARRAY_BUFFER, 0);
687 monitor->nelements = t*((t+1)*2+1)-1;
688 data_size = monitor->nelements*sizeof(unsigned short);
689 index_data = (unsigned short *)malloc(data_size);
694 index_data[i++] = 0xFFFF;
697 index_data[i++] = (y+1)*(t+1)+x;
698 index_data[i++] = y*(t+1)+x;
701 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, monitor->index_buffer);
702 glBufferData(GL_ELEMENT_ARRAY_BUFFER, data_size, index_data, GL_STATIC_DRAW);
703 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
707 int initialize_monitor(Compositor *compositor, CompositedScreen *screen, XRRScreenResources *xrr_res, unsigned index)
709 CompositedMonitor *monitor;
710 XRROutputInfo *output;
716 monitor = &screen->monitors[index];
718 output = XRRGetOutputInfo(compositor->display, xrr_res, xrr_res->outputs[index]);
719 namelen = strlen(output->name);
720 monitor->name = (char *)malloc(namelen+1);
721 strcpy(monitor->name, output->name);
722 monitor->enabled = !!output->crtc;
723 if(!monitor->enabled)
725 XRRFreeOutputInfo(output);
726 monitor->geometry_data = NULL;
730 crtc = XRRGetCrtcInfo(compositor->display, xrr_res, output->crtc);
731 monitor->x = crtc->x;
732 monitor->y = crtc->y;
733 monitor->width = crtc->width;
734 monitor->height = crtc->height;
735 XRRFreeCrtcInfo(crtc);
736 XRRFreeOutputInfo(output);
738 monitor->keystone_vertical = 0.0f;
739 monitor->cylinder_depth = 0.0f;
740 monitor->vertical_center = 0.5f;
741 monitor->perspective = 1.0f;
743 glGenBuffers(2, buffers);
744 monitor->vertex_buffer = buffers[0];
745 monitor->index_buffer = buffers[1];
747 monitor->tessellation = 50;
748 monitor->geometry_data_size = (monitor->tessellation+1)*(monitor->tessellation+1)*3+16;
749 monitor->geometry_data = (short *)malloc(monitor->geometry_data_size*sizeof(short));
750 update_monitor_vertices(screen, monitor);
751 stride = 4*sizeof(float);
753 glGenVertexArrays(1, &monitor->vertex_array);
754 glBindVertexArray(monitor->vertex_array);
755 glBindBuffer(GL_ARRAY_BUFFER, monitor->vertex_buffer);
756 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, stride, NULL);
757 glEnableVertexAttribArray(0);
758 glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, stride, (void *)(2*sizeof(float)));
759 glEnableVertexAttribArray(1);
760 glBindBuffer(GL_ARRAY_BUFFER, 0);
761 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, monitor->index_buffer);
762 glBindVertexArray(0);
767 CompositedMonitor *find_monitor_by_name(CompositedScreen *screen, char *name)
771 for(i=0; i<screen->nmonitors; ++i)
772 if(!strcmp(screen->monitors[i].name, name))
773 return &screen->monitors[i];
778 CompositedMonitor *find_monitor_by_name_global(Compositor *compositor, char *name, CompositedScreen **screen)
782 for(i=0; i<compositor->nscreens; ++i)
783 for(j=0; j<compositor->screens[i].nmonitors; ++j)
784 if(!strcmp(compositor->screens[i].monitors[j].name, name))
787 *screen = &compositor->screens[i];
788 return &compositor->screens[i].monitors[j];
796 void update_geometry_correction(Compositor *compositor, CompositedScreen *screen)
800 unsigned long overflow;
801 unsigned long names_length;
803 unsigned long values_length;
808 XGetWindowProperty(compositor->display, screen->root, compositor->monitors_atom, 0, 64, False, XA_STRING,
809 &prop_type, &prop_format, &names_length, &overflow, (unsigned char **)&names);
810 if(prop_type!=XA_STRING || prop_format!=8)
813 XGetWindowProperty(compositor->display, screen->root, compositor->correction_atom, 0, 64, False, XA_INTEGER,
814 &prop_type, &prop_format, &values_length, &overflow, (unsigned char **)&values);
815 if(prop_type!=XA_INTEGER || prop_format!=16)
821 use_gl(compositor, screen);
824 for(i=0; i*4<values_length; ++i)
826 CompositedMonitor *monitor;
828 if(name_ptr>=names+names_length)
831 monitor = find_monitor_by_name(screen, name_ptr);
834 monitor->keystone_vertical = values[i*4]/10000.0f;
835 monitor->cylinder_depth = values[i*4+1]/10000.0f;
836 monitor->vertical_center = values[i*4+2]/10000.0f;
837 monitor->perspective = values[i*4+3]/10000.0f;
840 update_monitor_vertices(screen, monitor);
843 name_ptr += strlen(name_ptr)+1;
850 void update_root_pixmap(Compositor *compositor, CompositedScreen *screen)
854 unsigned long overflow;
855 unsigned long length;
864 use_gl(compositor, screen);
866 if(screen->root_glx_pixmap)
868 glXDestroyPixmap(compositor->display, screen->root_glx_pixmap);
869 screen->root_glx_pixmap = None;
872 XGetWindowProperty(compositor->display, screen->root, compositor->root_pmap_atom, 0, 1, False, XA_PIXMAP,
873 &prop_type, &prop_format, &length, &overflow, (unsigned char **)&pixmap);
874 if(prop_type!=XA_PIXMAP || prop_format!=32)
876 screen->root_pixmap = None;
880 screen->root_pixmap = pixmap[0];
881 if(XGetGeometry(compositor->display, screen->root_pixmap, &root, &x, &y, &width, &height, &border, &depth))
882 screen->root_glx_pixmap = pixmap_to_glx_pixmap(compositor, screen, screen->root_pixmap);
884 screen->root_pixmap = None;
889 int initialize_screen(Compositor *compositor, unsigned number)
891 CompositedScreen *screen;
892 const char *extensions;
897 XRRScreenResources *xrr_res;
903 screen = &compositor->screens[number];
904 screen->number = number;
906 extensions = glXQueryExtensionsString(compositor->display, screen->number);
907 if(!strstr(extensions, "GLX_ARB_create_context"))
908 return with_error("GLX_ARB_create_context is required");
909 if(!strstr(extensions, "GLX_EXT_texture_from_pixmap"))
910 return with_error("GLX_EXT_texture_from_pixmap is required");
912 screen->root = RootWindow(compositor->display, screen->number);
913 XSelectInput(compositor->display, screen->root, SubstructureNotifyMask|PropertyChangeMask);
914 screen->overlay = XCompositeGetOverlayWindow(compositor->display, screen->root);
915 XGetGeometry(compositor->display, screen->overlay, &dummy_root, &x, &y, &screen->width, &screen->height, &border, &depth);
916 XShapeCombineRectangles(compositor->display, screen->overlay, ShapeInput, 0, 0, NULL, 0, ShapeSet, Unsorted);
918 if(!initialize_gl(compositor, screen))
921 use_gl(compositor, screen);
923 if(!create_gl_resources(screen))
926 xrr_res = XRRGetScreenResources(compositor->display, screen->root);
927 screen->nmonitors = xrr_res->noutput;
928 screen->monitors = (CompositedMonitor *)malloc(screen->nmonitors*sizeof(CompositedMonitor));
929 for(i=0; i<screen->nmonitors; ++i)
930 if(!initialize_monitor(compositor, screen, xrr_res, i))
932 XRRFreeScreenResources(xrr_res);
934 screen->root_pixmap = None;
935 screen->root_glx_pixmap = None;
937 update_geometry_correction(compositor, screen);
938 update_root_pixmap(compositor, screen);
940 XQueryTree(compositor->display, screen->root, &dummy_root, &dummy_parent, &children, &nchildren);
942 screen->windows = (CompositedWindow *)malloc(nchildren*sizeof(CompositedWindow));
943 screen->nwindows = 0;
944 screen->windows_capacity = nchildren;
946 for(i=0; i<nchildren; ++i)
947 add_window(compositor, screen, children[i]);
956 int initialize_compositor(Compositor *compositor)
964 compositor->display = XOpenDisplay(NULL);
965 if(!compositor->display)
966 return with_error("Could not open X display");
968 XSetErrorHandler(&x_error_handler);
970 if(!XCompositeQueryExtension(compositor->display, &event_base, &error_base))
971 return with_error("XComposite is required but was not found");
972 else if(!XCompositeQueryVersion(compositor->display, &major_ver, &minor_ver))
973 return with_error("Cannot determine XComposite version");
974 else if(major_ver==0 && minor_ver<3)
975 return with_error("XComposite 0.3 or later is required");
977 if(!glXQueryExtension(compositor->display, &event_base, &error_base))
978 return with_error("GLX is required but was not found");
979 else if(!glXQueryVersion(compositor->display, &major_ver, &minor_ver))
980 return with_error("Cannot determine GLX version");
981 else if(major_ver<1 || (major_ver==1 && minor_ver<4))
982 return with_error("GLX 1.4 or later is required");
984 if(!XDamageQueryExtension(compositor->display, &compositor->damage_event, &error_base))
985 return with_error("XDamage is required but was not found");
986 else if(!XDamageQueryVersion(compositor->display, &major_ver, &minor_ver))
987 return with_error("Cannot determine XDamage version");
989 return with_error("XDamage 1.0 or later is required");
991 if(!XShapeQueryExtension(compositor->display, &compositor->shape_event, &error_base))
992 return with_error("XShape is required but was not found");
993 else if(!XShapeQueryVersion(compositor->display, &major_ver, &minor_ver))
994 return with_error("Cannot determine XShape version");
995 else if(major_ver<1 || (major_ver==1 && minor_ver<1))
996 return with_error("XShape 1.1 or later is required");
998 if(!XRRQueryExtension(compositor->display, &event_base, &error_base))
999 return with_error("XRandR is required but was not found");
1000 else if(!XRRQueryVersion(compositor->display, &major_ver, &minor_ver))
1001 return with_error("Cannot determine XRandR version");
1002 else if(major_ver<1 || (major_ver==1 && minor_ver<2))
1003 return with_error("XRandR 1.2 or later is required");
1005 compositor->glXCreateContextAttribsARB = (PFNGLXCREATECONTEXTATTRIBSARBPROC)glXGetProcAddress((unsigned char *)"glXCreateContextAttribsARB");
1006 compositor->glXBindTexImageEXT = (PFNGLXBINDTEXIMAGEEXTPROC)glXGetProcAddress((unsigned char *)"glXBindTexImageEXT");
1007 compositor->glXReleaseTexImageEXT = (PFNGLXRELEASETEXIMAGEEXTPROC)glXGetProcAddress((unsigned char *)"glXReleaseTexImageEXT");
1009 compositor->root_pmap_atom = XInternAtom(compositor->display, "_XROOTPMAP_ID", False);
1010 compositor->correction_atom = XInternAtom(compositor->display, "_MSP_GEOMETRY_CORRECTION", False);
1011 compositor->monitors_atom = XInternAtom(compositor->display, "_MSP_GEOMETRY_CORRECTION_MONITORS", False);
1012 compositor->geometry_data_atom = XInternAtom(compositor->display, "_MSP_GEOMETRY_CORRECTION_DATA", False);
1014 compositor->nscreens = ScreenCount(compositor->display);
1015 compositor->screens = (CompositedScreen *)malloc(compositor->nscreens*sizeof(CompositedScreen));
1016 for(i=0; i<compositor->nscreens; ++i)
1017 if(!initialize_screen(compositor, i))
1020 compositor->selection_window = XCreateWindow(compositor->display, compositor->screens[0].root, 0, 0, 1, 1, 0, CopyFromParent, InputOutput, CopyFromParent, 0, NULL);
1021 XSetSelectionOwner(compositor->display, compositor->geometry_data_atom, compositor->selection_window, CurrentTime);
1023 compositor->dirty = 1;
1028 void shutdown_screen(Compositor *compositor, CompositedScreen *screen)
1032 use_gl(compositor, screen);
1034 for(i=0; i<screen->nwindows; ++i)
1036 glDeleteTextures(1, &screen->windows[i].texture);
1037 glDeleteTextures(1, &screen->windows[i].mask_texture);
1038 if(screen->windows[i].pixmap)
1040 glXDestroyPixmap(compositor->display, screen->windows[i].glx_pixmap);
1041 XFreePixmap(compositor->display, screen->windows[i].pixmap);
1042 XDamageDestroy(compositor->display, screen->windows[i].damage);
1046 for(i=0; i<screen->nmonitors; ++i)
1048 free(screen->monitors[i].name);
1049 if(screen->monitors[i].enabled)
1051 glDeleteBuffers(1, &screen->monitors[i].vertex_buffer);
1052 glDeleteBuffers(1, &screen->monitors[i].index_buffer);
1053 glDeleteVertexArrays(1, &screen->monitors[i].vertex_array);
1055 if(screen->monitors[i].geometry_data)
1056 free(screen->monitors[i].geometry_data);
1059 glDeleteTextures(1, &screen->root_texture);
1060 glXDestroyPixmap(compositor->display, screen->root_glx_pixmap);
1062 glDeleteBuffers(1, &screen->window_vertex_buffer);
1063 glDeleteVertexArrays(1, &screen->window_vertex_array);
1064 glDeleteFramebuffers(1, &screen->framebuffer);
1065 glDeleteTextures(1, &screen->fb_texture);
1066 glDeleteProgram(screen->program);
1067 glDeleteProgram(screen->masked_program);
1069 glDeleteShader(screen->shaders[i]);
1071 glXMakeContextCurrent(compositor->display, None, None, NULL);
1072 glXDestroyContext(compositor->display, screen->glx_context);
1073 glXDestroyWindow(compositor->display, screen->glx_window);
1074 XDestroyWindow(compositor->display, screen->render_window);
1076 XCompositeReleaseOverlayWindow(compositor->display, screen->overlay);
1078 free(screen->windows);
1079 free(screen->monitors);
1082 void shutdown_compositor(Compositor *compositor)
1086 for(i=0; i<compositor->nscreens; ++i)
1087 shutdown_screen(compositor, &compositor->screens[i]);
1088 free(compositor->screens);
1090 XDestroyWindow(compositor->display, compositor->selection_window);
1092 XCloseDisplay(compositor->display);
1095 void mark_dirty(Compositor *compositor, CompositedScreen *screen)
1097 compositor->dirty = 1;
1101 void process_create_window_event(Compositor *compositor, XCreateWindowEvent *event)
1103 CompositedScreen *screen;
1105 if((screen = find_screen_by_root(compositor, event->parent)))
1106 add_window(compositor, screen, event->window);
1109 void process_destroy_window_event(Compositor *compositor, XDestroyWindowEvent *event)
1111 CompositedScreen *screen;
1112 CompositedWindow *window;
1114 if((screen = find_screen_by_root(compositor, event->event)))
1115 if((window = find_window(screen, event->window)))
1117 use_gl(compositor, screen);
1118 remove_window(compositor, screen, window, 1);
1122 void process_map_event(Compositor *compositor, XMapEvent *event)
1124 CompositedScreen *screen;
1125 CompositedWindow *window;
1127 screen = find_screen_by_root(compositor, event->event);
1131 window = find_window(screen, event->window);
1135 window->map_state = IsViewable;
1136 window->recreate_pixmap = 1;
1137 window->recreate_mask = 1;
1139 mark_dirty(compositor, screen);
1142 void process_unmap_event(Compositor *compositor, XUnmapEvent *event)
1144 CompositedScreen *screen;
1145 CompositedWindow *window;
1147 screen = find_screen_by_root(compositor, event->event);
1151 window = find_window(screen, event->window);
1153 window->map_state = IsUnviewable;
1155 mark_dirty(compositor, screen);
1158 void process_reparent_event(Compositor *compositor, XReparentEvent *event)
1160 CompositedScreen *screen;
1161 CompositedWindow *window;
1163 screen = find_screen_by_root(compositor, event->event);
1167 if(event->parent==screen->root)
1168 window = add_window(compositor, screen, event->window);
1171 window = find_window(screen, event->window);
1175 remove_window(compositor, screen, window, 0);
1178 if(window && window->map_state==IsViewable)
1179 mark_dirty(compositor, screen);
1182 void process_configure_event(Compositor *compositor, XConfigureEvent *event)
1184 CompositedScreen *screen;
1185 CompositedWindow *window;
1187 screen = find_screen_by_root(compositor, event->event);
1191 window = find_window(screen, event->window);
1195 window->x = event->x;
1196 window->y = event->y;
1197 if((unsigned)event->width!=window->width || (unsigned)event->height!=window->height || (unsigned)event->border_width!=window->border)
1199 window->width = event->width;
1200 window->height = event->height;
1201 window->border = event->border_width;
1202 window->recreate_pixmap = 1;
1204 reorder_window(screen, window, event->above);
1206 if(window->map_state==IsViewable)
1207 mark_dirty(compositor, screen);
1210 void process_property_event(Compositor *compositor, XPropertyEvent *event)
1212 CompositedScreen *screen;
1214 screen = find_screen_by_root(compositor, event->window);
1218 if(event->atom==compositor->correction_atom)
1219 update_geometry_correction(compositor, screen);
1220 else if(event->atom==compositor->root_pmap_atom)
1221 update_root_pixmap(compositor, screen);
1224 void process_selection_request_event(Compositor *compositor, XSelectionRequestEvent *event)
1228 unsigned long overflow;
1229 unsigned long names_length;
1230 XSelectionEvent notify;
1232 if(event->selection==compositor->geometry_data_atom)
1235 CompositedMonitor *monitor;
1237 XGetWindowProperty(compositor->display, event->requestor, event->property, 0, 64, False, XA_STRING,
1238 &prop_type, &prop_format, &names_length, &overflow, (unsigned char **)&monitor_name);
1239 if(prop_type!=XA_STRING || prop_format!=8)
1242 monitor = find_monitor_by_name_global(compositor, monitor_name, NULL);
1243 if(monitor && monitor->enabled)
1244 XChangeProperty(compositor->display, event->requestor, event->property, XA_INTEGER, 16, PropModeReplace, (unsigned char *)monitor->geometry_data, monitor->geometry_data_size);
1246 notify.type = SelectionNotify;
1247 notify.requestor = event->requestor;
1248 notify.selection = event->selection;
1249 notify.target = event->target;
1250 notify.property = (monitor ? event->property : None);
1251 notify.time = event->time;
1252 XSendEvent(compositor->display, event->requestor, False, 0, (XEvent *)¬ify);
1256 void process_damage_event(Compositor *compositor, XDamageNotifyEvent *event)
1258 CompositedScreen *screen;
1259 CompositedWindow *window;
1261 window = find_window_global(compositor, event->drawable, &screen);
1262 if(window && window->map_state==IsViewable)
1263 mark_dirty(compositor, screen);
1266 void process_shape_event(Compositor *compositor, XShapeEvent *event)
1268 CompositedScreen *screen;
1269 CompositedWindow *window;
1271 if(event->kind!=ShapeBounding)
1274 window = find_window_global(compositor, event->window, &screen);
1275 if(window && window->map_state==IsViewable)
1277 window->recreate_mask = 1;
1278 mark_dirty(compositor, screen);
1282 void process_events(Compositor *compositor)
1288 while((pending || !compositor->dirty) && !terminate_requested)
1291 pending = XPending(compositor->display);
1293 XNextEvent(compositor->display, &event);
1300 process_create_window_event(compositor, &event.xcreatewindow);
1303 process_destroy_window_event(compositor, &event.xdestroywindow);
1306 process_map_event(compositor, &event.xmap);
1309 process_unmap_event(compositor, &event.xunmap);
1311 case ReparentNotify:
1312 process_reparent_event(compositor, &event.xreparent);
1314 case ConfigureNotify:
1315 process_configure_event(compositor, &event.xconfigure);
1317 case PropertyNotify:
1318 process_property_event(compositor, &event.xproperty);
1320 case SelectionRequest:
1321 process_selection_request_event(compositor, &event.xselectionrequest);
1324 if(event.type==compositor->damage_event+XDamageNotify)
1325 process_damage_event(compositor, (XDamageNotifyEvent *)&event);
1326 else if(event.type==compositor->shape_event+ShapeNotify)
1327 process_shape_event(compositor, (XShapeEvent *)&event);
1329 printf("Event %d\n", event.type);
1334 void refresh_screen(Compositor *compositor, CompositedScreen *screen)
1339 for(i=0; i<screen->nwindows; ++i)
1340 if(screen->windows[i].map_state==IsViewable)
1341 XDamageSubtract(compositor->display, screen->windows[i].damage, None, None);
1344 use_gl(compositor, screen);
1346 glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
1347 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, screen->framebuffer);
1350 glBindVertexArray(screen->window_vertex_array);
1352 if(screen->root_pixmap)
1355 glUseProgram(screen->program);
1356 glBindTexture(GL_TEXTURE_2D, screen->root_texture);
1357 compositor->glXBindTexImageEXT(compositor->display, screen->root_glx_pixmap, GLX_FRONT_LEFT_EXT, NULL);
1358 glUniform4f(screen->geometry_loc, 0.0f, 0.0f, 1.0f, 1.0f);
1359 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
1360 compositor->glXReleaseTexImageEXT(compositor->display, screen->root_glx_pixmap, GLX_FRONT_LEFT_EXT);
1363 glClear(GL_COLOR_BUFFER_BIT);
1365 for(i=0; i<screen->nwindows; ++i)
1367 CompositedWindow *window;
1369 window = &screen->windows[i];
1370 if(window->map_state!=IsViewable)
1373 if(window->use_mask!=use_mask)
1375 use_mask = window->use_mask;
1376 glUseProgram(use_mask ? screen->masked_program : screen->program);
1379 if(window->use_mask)
1381 glActiveTexture(GL_TEXTURE1);
1382 glBindTexture(GL_TEXTURE_2D, window->mask_texture);
1383 glActiveTexture(GL_TEXTURE0);
1386 if(window->recreate_pixmap)
1387 create_window_pixmap(compositor, screen, window);
1388 if(window->recreate_mask)
1389 update_window_mask(compositor, window);
1391 glBindTexture(GL_TEXTURE_2D, window->texture);
1392 compositor->glXBindTexImageEXT(compositor->display, window->glx_pixmap, GLX_FRONT_LEFT_EXT, NULL);
1393 glUniform4f((use_mask ? screen->masked_geometry_loc : screen->geometry_loc),
1394 (float)window->x/screen->width, 1.0f-(float)(window->y+window->height)/screen->height,
1395 (float)(window->width+2*window->border)/screen->width, (float)(window->height+2*window->border)/screen->height);
1396 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
1397 compositor->glXReleaseTexImageEXT(compositor->display, window->glx_pixmap, GLX_FRONT_LEFT_EXT);
1400 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
1401 glClear(GL_COLOR_BUFFER_BIT);
1402 glBindTexture(GL_TEXTURE_2D, screen->fb_texture);
1403 glEnable(GL_PRIMITIVE_RESTART);
1404 glPrimitiveRestartIndex(0xFFFF);
1406 glUseProgram(screen->program);
1408 for(i=0; i<screen->nmonitors; ++i)
1410 CompositedMonitor *monitor = &screen->monitors[i];
1411 if(!monitor->enabled)
1414 glUniform4f(screen->geometry_loc,
1415 (float)monitor->x/screen->width, 1.0f-(float)(monitor->y+monitor->height)/screen->height,
1416 (float)monitor->width/screen->width, (float)monitor->height/screen->height);
1418 glBindVertexArray(monitor->vertex_array);
1419 glDrawElements(GL_TRIANGLE_STRIP, monitor->nelements, GL_UNSIGNED_SHORT, NULL);
1422 glBindVertexArray(0);
1424 glXSwapBuffers(compositor->display, screen->glx_window);
1429 void refresh_all_screens(Compositor *compositor)
1433 for(i=0; i<compositor->nscreens; ++i)
1435 CompositedScreen *screen = &compositor->screens[i];
1437 refresh_screen(compositor, screen);
1440 compositor->dirty = 0;
1443 void sighandler(int sig)
1445 terminate_requested = 1;
1451 Compositor compositor;
1453 signal(SIGINT, &sighandler);
1454 signal(SIGTERM, &sighandler);
1456 if(!initialize_compositor(&compositor))
1459 while(!terminate_requested)
1461 process_events(&compositor);
1462 if(compositor.dirty && !terminate_requested)
1463 refresh_all_screens(&compositor);
1466 shutdown_compositor(&compositor);