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
29 unsigned mask_texture;
33 typedef struct CompositedMonitor
41 float keystone_vertical;
43 float vertical_center;
45 unsigned vertex_buffer;
46 unsigned index_buffer;
47 unsigned vertex_array;
48 unsigned tessellation;
52 typedef struct CompositedScreen
62 GLXContext glx_context;
66 unsigned masked_program;
67 int masked_geometry_loc;
68 unsigned window_vertex_buffer;
69 unsigned window_vertex_array;
72 CompositedWindow *windows;
74 unsigned windows_capacity;
75 CompositedMonitor *monitors;
80 typedef struct Compositor
83 CompositedScreen *screens;
87 PFNGLXCREATECONTEXTATTRIBSARBPROC glXCreateContextAttribsARB;
88 PFNGLXBINDTEXIMAGEEXTPROC glXBindTexImageEXT;
89 PFNGLXRELEASETEXIMAGEEXTPROC glXReleaseTexImageEXT;
95 static const char *vshader_src =
97 "uniform vec4 geometry;\n"
99 "in vec2 texture_coord;\n"
100 "out vec2 texcoord;\n"
103 " gl_Position = vec4((geometry.xy+vertex*geometry.zw)*2.0-1.0, 0.0, 1.0);\n"
104 " texcoord = texture_coord;\n"
107 static const char *fshader_src =
109 "uniform sampler2D image;\n"
110 "in vec2 texcoord;\n"
111 "out vec4 frag_color;\n"
114 " frag_color = texture(image, texcoord);\n"
117 static const char *masked_fshader_src =
119 "uniform sampler2D image;\n"
120 "uniform sampler2D mask;\n"
121 "in vec2 texcoord;\n"
122 "out vec4 frag_color;\n"
125 " if(texture(mask, texcoord).r==0.0)\n"
127 " frag_color = texture(image, texcoord);\n"
130 static const float window_vertices[] =
132 /* vertex texcoord */
133 0.0f, 1.0f, 0.0f, 0.0f,
134 0.0f, 0.0f, 0.0f, 1.0f,
135 1.0f, 1.0f, 1.0f, 0.0f,
136 1.0f, 0.0f, 1.0f, 1.0f
139 int terminate_requested = 0;
141 int x_error_handler(Display *display, XErrorEvent *event)
143 printf("Ignoring X error %d on resource %lx\n", event->error_code, event->resourceid);
148 int with_error(const char *message)
150 fprintf(stderr, "%s\n", message);
154 int initialize_gl(Compositor *compositor, CompositedScreen *screen)
158 GLXFBConfig *configs;
161 XSetWindowAttributes win_attr;
164 attribs[i++] = GLX_DRAWABLE_TYPE;
165 attribs[i++] = GLX_WINDOW_BIT;
166 attribs[i++] = GLX_RENDER_TYPE;
167 attribs[i++] = GLX_RGBA_BIT;
168 attribs[i++] = GLX_DOUBLEBUFFER;
170 attribs[i++] = GLX_BIND_TO_TEXTURE_RGBA_EXT;
174 configs = glXChooseFBConfig(compositor->display, screen->number, attribs, &nconfigs);
175 if(!configs || !nconfigs)
176 return with_error("Could not find a suitable FBConfig");
177 screen->fbconfig = configs[0];
180 vi = glXGetVisualFromFBConfig(compositor->display, screen->fbconfig);
181 win_attr.colormap = XCreateColormap(compositor->display, screen->root, vi->visual, AllocNone);
182 screen->render_window = XCreateWindow(compositor->display, screen->overlay, 0, 0, screen->width, screen->height, 0, vi->depth, InputOutput, vi->visual, CWColormap, &win_attr);
183 XMapWindow(compositor->display, screen->render_window);
185 screen->glx_window = glXCreateWindow(compositor->display, screen->fbconfig, screen->render_window, NULL);
188 attribs[i++] = GLX_CONTEXT_FLAGS_ARB;
189 attribs[i++] = GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB;
190 attribs[i++] = GLX_CONTEXT_MAJOR_VERSION_ARB;
192 attribs[i++] = GLX_CONTEXT_MINOR_VERSION_ARB;
196 screen->glx_context = compositor->glXCreateContextAttribsARB(compositor->display, screen->fbconfig, NULL, True, attribs);
203 void use_gl(Compositor *compositor, CompositedScreen *screen)
205 glXMakeContextCurrent(compositor->display, screen->glx_window, screen->glx_window, screen->glx_context);
208 unsigned compile_shader(GLenum type, const char *source)
215 shader = glCreateShader(type);
216 glShaderSource(shader, 1, &source, NULL);
217 glCompileShader(shader);
218 glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
219 glGetShaderInfoLog(shader, sizeof(info_log), &length, info_log);
222 fprintf(stderr, "Shader compilation failed:\n%s\n", info_log);
223 glDeleteShader(shader);
227 printf("Shader info log:\n%s\n", info_log);
232 unsigned link_program(unsigned vshader, unsigned fshader)
239 program = glCreateProgram();
240 glAttachShader(program, vshader);
241 glAttachShader(program, fshader);
242 glBindAttribLocation(program, 0, "vertex");
243 glBindAttribLocation(program, 1, "texture_coord");
244 glBindFragDataLocation(program, 0, "frag_color");
245 glLinkProgram(program);
247 glGetProgramiv(program, GL_LINK_STATUS, &status);
248 glGetProgramInfoLog(program, sizeof(info_log), &length, info_log);
251 fprintf(stderr, "Program link failed:\n%s\n", info_log);
252 glDeleteProgram(program);
256 printf("Program info log:\n%s\n", info_log);
261 unsigned create_2d_texture()
264 glGenTextures(1, &texture);
265 glBindTexture(GL_TEXTURE_2D, texture);
266 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
267 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
268 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
272 int create_gl_resources(Compositor *compositor, CompositedScreen *screen)
277 use_gl(compositor, screen);
279 screen->shaders[0] = compile_shader(GL_VERTEX_SHADER, vshader_src);
280 screen->shaders[1] = compile_shader(GL_FRAGMENT_SHADER, fshader_src);
281 screen->shaders[2] = compile_shader(GL_FRAGMENT_SHADER, masked_fshader_src);
282 if(!screen->shaders[0] || !screen->shaders[1] || !screen->shaders[2])
285 screen->program = link_program(screen->shaders[0], screen->shaders[1]);
289 screen->masked_program = link_program(screen->shaders[0], screen->shaders[2]);
290 if(!screen->masked_program)
293 screen->geometry_loc = glGetUniformLocation(screen->program, "geometry");
294 screen->masked_geometry_loc = glGetUniformLocation(screen->masked_program, "geometry");
296 loc = glGetUniformLocation(screen->masked_program, "mask");
299 glUseProgram(screen->masked_program);
303 glGenBuffers(1, &screen->window_vertex_buffer);
304 glBindBuffer(GL_ARRAY_BUFFER, screen->window_vertex_buffer);
305 glBufferData(GL_ARRAY_BUFFER, sizeof(window_vertices), window_vertices, GL_STATIC_DRAW);
307 stride = 4*sizeof(float);
308 glGenVertexArrays(1, &screen->window_vertex_array);
309 glBindVertexArray(screen->window_vertex_array);
310 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, stride, NULL);
311 glEnableVertexAttribArray(0);
312 glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, stride, (void *)(2*sizeof(float)));
313 glEnableVertexAttribArray(1);
314 glBindVertexArray(0);
316 glBindBuffer(GL_ARRAY_BUFFER, 0);
318 screen->fb_texture = create_2d_texture();
319 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, screen->width, screen->height, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
320 glBindTexture(GL_TEXTURE_2D, 0);
322 glGenFramebuffers(1, &screen->framebuffer);
323 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, screen->framebuffer);
324 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, screen->fb_texture, 0);
325 glDepthMask(GL_FALSE);
326 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
331 CompositedWindow *find_window(CompositedScreen *screen, Window w)
335 for(i=0; i<screen->nwindows; ++i)
336 if(screen->windows[i].window==w)
337 return &screen->windows[i];
342 CompositedWindow *find_window_global(Compositor *compositor, Window w, CompositedScreen **screen)
346 for(i=0; i<compositor->nscreens; ++i)
347 for(j=0; j<compositor->screens[i].nwindows; ++j)
348 if(compositor->screens[i].windows[j].window==w)
351 *screen = &compositor->screens[i];
352 return &compositor->screens[i].windows[j];
360 void create_window_pixmap(Compositor *compositor, CompositedScreen *screen, CompositedWindow *window)
367 glXDestroyPixmap(compositor->display, window->glx_pixmap);
368 XFreePixmap(compositor->display, window->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 window->pixmap = XCompositeNameWindowPixmap(compositor->display, window->window);
379 window->glx_pixmap = glXCreatePixmap(compositor->display, screen->fbconfig, window->pixmap, attribs);
382 void update_window_mask(Compositor *compositor, CompositedWindow *window)
384 Bool bounding_shaped;
396 XShapeQueryExtents(compositor->display, window->window, &bounding_shaped, &xi, &yi, &width, &height, &clip_shaped, &xi, &yi, &width, &height);
397 window->use_mask = bounding_shaped;
398 if(!window->use_mask)
401 rects = XShapeGetRectangles(compositor->display, window->window, ShapeBounding, &rect_count, &rect_order);
403 width = window->width+2*window->border;
404 height = window->height+2*window->border;
405 data = (unsigned char *)malloc(width*height);
406 memset(data, 0, width*height);
407 for(i=0; i<rect_count; ++i)
409 rects[i].x += window->border;
410 rects[i].y += window->border;
411 if(rects[i].x>=(int)width || rects[i].y>=(int)height)
416 if(-rects[i].x>rects[i].width)
418 rects[i].width += rects[i].x;
424 if(-rects[i].y>rects[i].height)
426 rects[i].height += rects[i].y;
430 if(rects[i].x+rects[i].width>(int)width)
431 rects[i].width = width-rects[i].x;
432 if(rects[i].y+rects[i].height>(int)height)
433 rects[i].height = height-rects[i].y;
435 for(y=0; y<rects[i].height; ++y)
437 unsigned char *row = data+(rects[i].y+y)*width+rects[i].x;
438 memset(row, 255, rects[i].width);
444 glBindTexture(GL_TEXTURE_2D, window->mask_texture);
445 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
446 glTexImage2D(GL_TEXTURE_2D, 0, GL_R8, width, height, 0, GL_RED, GL_UNSIGNED_BYTE, data);
451 CompositedWindow *add_window(Compositor *compositor, CompositedScreen *screen, Window w)
453 CompositedWindow *window;
454 XWindowAttributes win_attr;
456 if(w==screen->root || w==screen->overlay)
459 if(!XGetWindowAttributes(compositor->display, w, &win_attr))
461 printf("XGetWindowAttributes failed; probably the window was already destroyed\n");
464 if(win_attr.class==InputOnly)
467 if(find_window(screen, w))
470 if(screen->nwindows==screen->windows_capacity)
472 screen->windows = (CompositedWindow *)realloc(screen->windows, (screen->windows_capacity+1)*sizeof(CompositedWindow));
473 ++screen->windows_capacity;
476 window = &screen->windows[screen->nwindows++];
479 window->x = win_attr.x;
480 window->y = win_attr.y;
481 window->width = win_attr.width;
482 window->height = win_attr.height;
483 window->border = win_attr.border_width;
484 window->map_state = win_attr.map_state;
486 window->damage = XDamageCreate(compositor->display, window->window, XDamageReportNonEmpty);
487 window->pixmap = None;
488 window->glx_pixmap = None;
490 XCompositeRedirectWindow(compositor->display, window->window, CompositeRedirectManual);
491 if(window->map_state==IsViewable)
492 create_window_pixmap(compositor, screen, window);
494 window->texture = create_2d_texture();
495 window->mask_texture = create_2d_texture();
497 if(window->map_state==IsViewable)
498 update_window_mask(compositor, window);
500 XShapeSelectInput(compositor->display, window->window, ShapeNotifyMask);
505 void remove_window(Compositor *compositor, CompositedScreen *screen, CompositedWindow *window, int destroyed)
509 glDeleteTextures(1, &window->texture);
512 XDamageDestroy(compositor->display, window->damage);
515 glXDestroyPixmap(compositor->display, window->glx_pixmap);
516 XFreePixmap(compositor->display, window->pixmap);
518 XCompositeUnredirectWindow(compositor->display, window->window, CompositeRedirectManual);
522 for(i=window-screen->windows; i<screen->nwindows; ++i)
523 screen->windows[i] = screen->windows[i+1];
526 CompositedWindow *reorder_window(CompositedScreen *screen, CompositedWindow *window, Window above)
529 CompositedWindow hold;
531 i = window-screen->windows;
534 for(j=0; j<screen->nwindows; ++j)
535 if(screen->windows[j].window==above)
538 if(j>=screen->nwindows || i==j+1)
551 screen->windows[i] = screen->windows[i+1];
556 screen->windows[i] = screen->windows[i-1];
558 screen->windows[j] = hold;
560 return &screen->windows[j];
563 CompositedScreen *find_screen_by_root(Compositor *compositor, Window root)
567 for(i=0; i<compositor->nscreens; ++i)
568 if(compositor->screens[i].root==root)
569 return &compositor->screens[i];
574 void update_monitor_vertices(CompositedScreen *screen, CompositedMonitor *monitor)
579 unsigned short *index_data;
591 t = monitor->tessellation;
593 data_size = (t+1)*(t+1)*4*sizeof(float);
594 vertex_data = (float *)malloc(data_size);
596 aspect = (float)monitor->width/monitor->height;
598 if(monitor->cylinder_depth)
600 cyl_radius = (monitor->cylinder_depth*monitor->cylinder_depth+0.25f)/(2.0f*monitor->cylinder_depth);
601 cyl_arc = 2.0f*asin(0.5f/cyl_radius);
604 sin_ksv = monitor->keystone_vertical/sqrt(1.0f+monitor->keystone_vertical*monitor->keystone_vertical);
605 cos_ksv = sqrt(1.0f-sin_ksv*sin_ksv);
606 distance = monitor->perspective+sin_ksv*((sin_ksv>0)-monitor->vertical_center)/aspect;
609 eye[1] = (monitor->vertical_center-0.5f)/aspect+sin_ksv*distance;
610 eye[2] = cos_ksv*distance;
621 v = vertex_data+(y*(t+1)+x)*3;
622 v[0] = (float)x/t-0.5f;
623 v[1] = ((float)y/t-0.5f)/aspect;
625 if(monitor->cylinder_depth)
627 v[2] = (1.0f-cos(v[0]*cyl_arc))*cyl_radius-monitor->cylinder_depth;
628 v[0] = sin(v[0]*cyl_arc)*cyl_radius;
639 v = vertex_data+(y*(t+1)+x)*3;
641 py = (v[0]-eye[0])*look[0] - (v[1]-eye[1])*look[2] + (v[2]-eye[2])*look[1];
642 pz = (v[0]-eye[0])*look[0] + (v[1]-eye[1])*look[1] + (v[2]-eye[2])*look[2];
643 scale = monitor->perspective/pz;
645 v = vertex_data+(y*(t+1)+x)*4;
646 v[0] = px*scale+0.5f;
647 v[1] = py*aspect*scale+monitor->vertical_center;
648 v[2] = (monitor->x+(float)x*monitor->width/t)/screen->width;
649 v[3] = 1.0f-(monitor->y+(1.0f-(float)y/t)*monitor->height)/screen->height;
652 glBindBuffer(GL_ARRAY_BUFFER, monitor->vertex_buffer);
653 glBufferData(GL_ARRAY_BUFFER, data_size, vertex_data, GL_STATIC_DRAW);
654 glBindBuffer(GL_ARRAY_BUFFER, 0);
657 monitor->nelements = t*((t+1)*2+1)-1;
658 data_size = monitor->nelements*sizeof(unsigned short);
659 index_data = (unsigned short *)malloc(data_size);
664 index_data[i++] = 0xFFFF;
667 index_data[i++] = (y+1)*(t+1)+x;
668 index_data[i++] = y*(t+1)+x;
671 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, monitor->index_buffer);
672 glBufferData(GL_ELEMENT_ARRAY_BUFFER, data_size, index_data, GL_STATIC_DRAW);
673 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
677 int initialize_monitor(Compositor *compositor, CompositedScreen *screen, XRRScreenResources *xrr_res, unsigned index)
679 CompositedMonitor *monitor;
680 XRROutputInfo *output;
686 monitor = &screen->monitors[index];
688 output = XRRGetOutputInfo(compositor->display, xrr_res, xrr_res->outputs[index]);
689 namelen = strlen(output->name);
690 monitor->name = (char *)malloc(namelen+1);
691 strcpy(monitor->name, output->name);
692 monitor->enabled = !!output->crtc;
693 if(!monitor->enabled)
695 XRRFreeOutputInfo(output);
699 crtc = XRRGetCrtcInfo(compositor->display, xrr_res, output->crtc);
700 monitor->x = crtc->x;
701 monitor->y = crtc->y;
702 monitor->width = crtc->width;
703 monitor->height = crtc->height;
704 XRRFreeCrtcInfo(crtc);
705 XRRFreeOutputInfo(output);
707 monitor->keystone_vertical = 0.0f;
708 monitor->cylinder_depth = 0.0f;
709 monitor->vertical_center = 0.5f;
710 monitor->perspective = 1.0f;
712 glGenBuffers(2, buffers);
713 monitor->vertex_buffer = buffers[0];
714 monitor->index_buffer = buffers[1];
716 monitor->tessellation = 50;
717 update_monitor_vertices(screen, monitor);
718 stride = 4*sizeof(float);
720 glGenVertexArrays(1, &monitor->vertex_array);
721 glBindVertexArray(monitor->vertex_array);
722 glBindBuffer(GL_ARRAY_BUFFER, monitor->vertex_buffer);
723 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, stride, NULL);
724 glEnableVertexAttribArray(0);
725 glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, stride, (void *)(2*sizeof(float)));
726 glEnableVertexAttribArray(1);
727 glBindBuffer(GL_ARRAY_BUFFER, 0);
728 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, monitor->index_buffer);
729 glBindVertexArray(0);
734 CompositedMonitor *find_monitor_by_name(CompositedScreen *screen, char *name)
738 for(i=0; i<screen->nmonitors; ++i)
739 if(!strcmp(screen->monitors[i].name, name))
740 return &screen->monitors[i];
745 void update_geometry_correction(Compositor *compositor, CompositedScreen *screen)
749 unsigned long overflow;
750 unsigned long names_length;
752 unsigned long values_length;
757 XGetWindowProperty(compositor->display, screen->root, compositor->monitors_atom, 0, 64, False, XA_STRING,
758 &prop_type, &prop_format, &names_length, &overflow, (unsigned char **)&names);
759 if(prop_type!=XA_STRING || prop_format!=8)
762 XGetWindowProperty(compositor->display, screen->root, compositor->correction_atom, 0, 64, False, XA_INTEGER,
763 &prop_type, &prop_format, &values_length, &overflow, (unsigned char **)&values);
764 if(prop_type!=XA_INTEGER || prop_format!=16)
770 use_gl(compositor, screen);
773 for(i=0; i*4<values_length; ++i)
775 CompositedMonitor *monitor;
777 if(name_ptr>=names+names_length)
780 monitor = find_monitor_by_name(screen, name_ptr);
783 monitor->keystone_vertical = values[i*4]/10000.0f;
784 monitor->cylinder_depth = values[i*4+1]/10000.0f;
785 monitor->vertical_center = values[i*4+2]/10000.0f;
786 monitor->perspective = values[i*4+3]/10000.0f;
789 update_monitor_vertices(screen, monitor);
792 name_ptr += strlen(name_ptr)+1;
799 int initialize_screen(Compositor *compositor, unsigned number)
801 CompositedScreen *screen;
802 const char *extensions;
807 XRRScreenResources *xrr_res;
813 screen = &compositor->screens[number];
814 screen->number = number;
816 extensions = glXQueryExtensionsString(compositor->display, screen->number);
817 if(!strstr(extensions, "GLX_ARB_create_context"))
818 return with_error("GLX_ARB_create_context is required");
819 if(!strstr(extensions, "GLX_EXT_texture_from_pixmap"))
820 return with_error("GLX_EXT_texture_from_pixmap is required");
822 screen->root = RootWindow(compositor->display, screen->number);
823 XSelectInput(compositor->display, screen->root, SubstructureNotifyMask|PropertyChangeMask);
824 screen->overlay = XCompositeGetOverlayWindow(compositor->display, screen->root);
825 XGetGeometry(compositor->display, screen->overlay, &dummy_root, &x, &y, &screen->width, &screen->height, &border, &depth);
826 XShapeCombineRectangles(compositor->display, screen->overlay, ShapeInput, 0, 0, NULL, 0, ShapeSet, Unsorted);
828 if(!initialize_gl(compositor, screen))
831 if(!create_gl_resources(compositor, screen))
834 xrr_res = XRRGetScreenResources(compositor->display, screen->root);
835 screen->nmonitors = xrr_res->noutput;
836 screen->monitors = (CompositedMonitor *)malloc(screen->nmonitors*sizeof(CompositedMonitor));
837 for(i=0; i<screen->nmonitors; ++i)
838 if(!initialize_monitor(compositor, screen, xrr_res, i))
840 XRRFreeScreenResources(xrr_res);
842 update_geometry_correction(compositor, screen);
844 XQueryTree(compositor->display, screen->root, &dummy_root, &dummy_parent, &children, &nchildren);
846 screen->windows = (CompositedWindow *)malloc(nchildren*sizeof(CompositedWindow));
847 screen->nwindows = 0;
848 screen->windows_capacity = nchildren;
850 for(i=0; i<nchildren; ++i)
851 add_window(compositor, screen, children[i]);
860 int initialize_compositor(Compositor *compositor)
868 compositor->display = XOpenDisplay(NULL);
869 if(!compositor->display)
870 return with_error("Could not open X display");
872 XSetErrorHandler(&x_error_handler);
874 if(!XCompositeQueryExtension(compositor->display, &event_base, &error_base))
875 return with_error("XComposite is required but was not found");
876 else if(!XCompositeQueryVersion(compositor->display, &major_ver, &minor_ver))
877 return with_error("Cannot determine XComposite version");
878 else if(major_ver==0 && minor_ver<3)
879 return with_error("XComposite 0.3 or later is required");
881 if(!glXQueryExtension(compositor->display, &event_base, &error_base))
882 return with_error("GLX is required but was not found");
883 else if(!glXQueryVersion(compositor->display, &major_ver, &minor_ver))
884 return with_error("Cannot determine GLX version");
885 else if(major_ver<1 || (major_ver==1 && minor_ver<4))
886 return with_error("GLX 1.4 or later is required");
888 if(!XDamageQueryExtension(compositor->display, &compositor->damage_event, &error_base))
889 return with_error("XDamage is required but was not found");
890 else if(!XDamageQueryVersion(compositor->display, &major_ver, &minor_ver))
891 return with_error("Cannot determine XDamage version");
893 return with_error("XDamage 1.0 or later is required");
895 if(!XShapeQueryExtension(compositor->display, &compositor->shape_event, &error_base))
896 return with_error("XShape is required but was not found");
897 else if(!XShapeQueryVersion(compositor->display, &major_ver, &minor_ver))
898 return with_error("Cannot determine XShape version");
899 else if(major_ver<1 || (major_ver==1 && minor_ver<1))
900 return with_error("XShape 1.1 or later is required");
902 if(!XRRQueryExtension(compositor->display, &event_base, &error_base))
903 return with_error("XRandR is required but was not found");
904 else if(!XRRQueryVersion(compositor->display, &major_ver, &minor_ver))
905 return with_error("Cannot determine XRandR version");
906 else if(major_ver<1 || (major_ver==1 && minor_ver<2))
907 return with_error("XRandR 1.2 or later is required");
909 compositor->glXCreateContextAttribsARB = (PFNGLXCREATECONTEXTATTRIBSARBPROC)glXGetProcAddress((unsigned char *)"glXCreateContextAttribsARB");
910 compositor->glXBindTexImageEXT = (PFNGLXBINDTEXIMAGEEXTPROC)glXGetProcAddress((unsigned char *)"glXBindTexImageEXT");
911 compositor->glXReleaseTexImageEXT = (PFNGLXRELEASETEXIMAGEEXTPROC)glXGetProcAddress((unsigned char *)"glXReleaseTexImageEXT");
913 compositor->correction_atom = XInternAtom(compositor->display, "GEOMETRY_CORRECTION", False);
914 compositor->monitors_atom = XInternAtom(compositor->display, "GEOMETRY_CORRECTION_MONITORS", False);
916 compositor->nscreens = ScreenCount(compositor->display);
917 compositor->screens = (CompositedScreen *)malloc(compositor->nscreens*sizeof(CompositedScreen));
918 for(i=0; i<compositor->nscreens; ++i)
919 if(!initialize_screen(compositor, i))
922 compositor->dirty = 1;
927 void shutdown_screen(Compositor *compositor, CompositedScreen *screen)
931 use_gl(compositor, screen);
933 for(i=0; i<screen->nwindows; ++i)
935 glDeleteTextures(1, &screen->windows[i].texture);
936 glDeleteTextures(1, &screen->windows[i].mask_texture);
937 if(screen->windows[i].pixmap)
939 glXDestroyPixmap(compositor->display, screen->windows[i].glx_pixmap);
940 XFreePixmap(compositor->display, screen->windows[i].pixmap);
941 XDamageDestroy(compositor->display, screen->windows[i].damage);
945 for(i=0; i<screen->nmonitors; ++i)
947 free(screen->monitors[i].name);
948 if(screen->monitors[i].enabled)
950 glDeleteBuffers(1, &screen->monitors[i].vertex_buffer);
951 glDeleteBuffers(1, &screen->monitors[i].index_buffer);
952 glDeleteVertexArrays(1, &screen->monitors[i].vertex_array);
956 glDeleteBuffers(1, &screen->window_vertex_buffer);
957 glDeleteVertexArrays(1, &screen->window_vertex_array);
958 glDeleteFramebuffers(1, &screen->framebuffer);
959 glDeleteTextures(1, &screen->fb_texture);
960 glDeleteProgram(screen->program);
961 glDeleteProgram(screen->masked_program);
963 glDeleteShader(screen->shaders[i]);
965 glXMakeContextCurrent(compositor->display, 0, 0, NULL);
966 glXDestroyContext(compositor->display, screen->glx_context);
967 glXDestroyWindow(compositor->display, screen->glx_window);
968 XDestroyWindow(compositor->display, screen->render_window);
970 XCompositeReleaseOverlayWindow(compositor->display, screen->overlay);
972 free(screen->windows);
973 free(screen->monitors);
976 void shutdown_compositor(Compositor *compositor)
980 for(i=0; i<compositor->nscreens; ++i)
981 shutdown_screen(compositor, &compositor->screens[i]);
982 free(compositor->screens);
984 XCloseDisplay(compositor->display);
987 void mark_dirty(Compositor *compositor, CompositedScreen *screen)
989 compositor->dirty = 1;
993 void process_create_window_event(Compositor *compositor, XCreateWindowEvent *event)
995 CompositedScreen *screen;
997 if((screen = find_screen_by_root(compositor, event->parent)))
998 add_window(compositor, screen, event->window);
1001 void process_destroy_window_event(Compositor *compositor, XDestroyWindowEvent *event)
1003 CompositedScreen *screen;
1004 CompositedWindow *window;
1006 if((screen = find_screen_by_root(compositor, event->event)))
1007 if((window = find_window(screen, event->window)))
1008 remove_window(compositor, screen, window, 1);
1011 void process_map_event(Compositor *compositor, XMapEvent *event)
1013 CompositedScreen *screen;
1014 CompositedWindow *window;
1016 screen = find_screen_by_root(compositor, event->event);
1020 window = find_window(screen, event->window);
1024 window->map_state = IsViewable;
1025 create_window_pixmap(compositor, screen, window);
1026 update_window_mask(compositor, window);
1028 mark_dirty(compositor, screen);
1031 void process_unmap_event(Compositor *compositor, XUnmapEvent *event)
1033 CompositedScreen *screen;
1034 CompositedWindow *window;
1036 screen = find_screen_by_root(compositor, event->event);
1040 window = find_window(screen, event->window);
1042 window->map_state = IsUnviewable;
1044 mark_dirty(compositor, screen);
1047 void process_reparent_event(Compositor *compositor, XReparentEvent *event)
1049 CompositedScreen *screen;
1050 CompositedWindow *window;
1052 screen = find_screen_by_root(compositor, event->event);
1056 if(event->parent==screen->root)
1057 window = add_window(compositor, screen, event->window);
1060 window = find_window(screen, event->window);
1064 remove_window(compositor, screen, window, 0);
1067 if(window && window->map_state==IsViewable)
1068 mark_dirty(compositor, screen);
1071 void process_configure_event(Compositor *compositor, XConfigureEvent *event)
1073 CompositedScreen *screen;
1074 CompositedWindow *window;
1076 screen = find_screen_by_root(compositor, event->event);
1080 window = find_window(screen, event->window);
1084 window->x = event->x;
1085 window->y = event->y;
1086 if((unsigned)event->width!=window->width || (unsigned)event->height!=window->height || (unsigned)event->border_width!=window->border)
1088 window->width = event->width;
1089 window->height = event->height;
1090 window->border = event->border_width;
1091 create_window_pixmap(compositor, screen, window);
1093 reorder_window(screen, window, event->above);
1095 if(window->map_state==IsViewable)
1096 mark_dirty(compositor, screen);
1099 void process_property_event(Compositor *compositor, XPropertyEvent *event)
1101 CompositedScreen *screen;
1103 if(event->atom!=compositor->correction_atom)
1106 screen = find_screen_by_root(compositor, event->window);
1110 update_geometry_correction(compositor, screen);
1113 void process_damage_event(Compositor *compositor, XDamageNotifyEvent *event)
1115 CompositedScreen *screen;
1116 CompositedWindow *window;
1118 window = find_window_global(compositor, event->drawable, &screen);
1119 if(window && window->map_state==IsViewable)
1120 mark_dirty(compositor, screen);
1123 void process_shape_event(Compositor *compositor, XShapeEvent *event)
1125 CompositedScreen *screen;
1126 CompositedWindow *window;
1128 if(event->kind!=ShapeBounding)
1131 window = find_window_global(compositor, event->window, &screen);
1132 if(window && window->map_state==IsViewable)
1134 update_window_mask(compositor, window);
1135 mark_dirty(compositor, screen);
1139 void process_events(Compositor *compositor)
1145 while((pending || !compositor->dirty) && !terminate_requested)
1148 pending = XPending(compositor->display);
1150 XNextEvent(compositor->display, &event);
1157 process_create_window_event(compositor, &event.xcreatewindow);
1160 process_destroy_window_event(compositor, &event.xdestroywindow);
1163 process_map_event(compositor, &event.xmap);
1166 process_unmap_event(compositor, &event.xunmap);
1168 case ReparentNotify:
1169 process_reparent_event(compositor, &event.xreparent);
1171 case ConfigureNotify:
1172 process_configure_event(compositor, &event.xconfigure);
1174 case PropertyNotify:
1175 process_property_event(compositor, &event.xproperty);
1178 if(event.type==compositor->damage_event+XDamageNotify)
1179 process_damage_event(compositor, (XDamageNotifyEvent *)&event);
1180 else if(event.type==compositor->shape_event+ShapeNotify)
1181 process_shape_event(compositor, (XShapeEvent *)&event);
1183 printf("Event %d\n", event.type);
1188 void refresh_screen(Compositor *compositor, CompositedScreen *screen)
1193 use_gl(compositor, screen);
1195 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, screen->framebuffer);
1197 glClearColor(0.5f, 0.5f, 0.5f, 0.0f);
1198 glClear(GL_COLOR_BUFFER_BIT);
1201 glBindVertexArray(screen->window_vertex_array);
1202 for(i=0; i<screen->nwindows; ++i)
1204 CompositedWindow *window;
1206 window = &screen->windows[i];
1207 if(window->map_state!=IsViewable)
1210 if(window->use_mask!=use_mask)
1212 use_mask = window->use_mask;
1213 glUseProgram(use_mask ? screen->masked_program : screen->program);
1216 if(window->use_mask)
1218 glActiveTexture(GL_TEXTURE1);
1219 glBindTexture(GL_TEXTURE_2D, window->mask_texture);
1220 glActiveTexture(GL_TEXTURE0);
1223 XDamageSubtract(compositor->display, window->damage, None, None);
1225 glBindTexture(GL_TEXTURE_2D, window->texture);
1226 compositor->glXBindTexImageEXT(compositor->display, window->glx_pixmap, GLX_FRONT_LEFT_EXT, NULL);
1227 glUniform4f((use_mask ? screen->masked_geometry_loc : screen->geometry_loc),
1228 (float)window->x/screen->width, 1.0f-(float)(window->y+window->height)/screen->height,
1229 (float)(window->width+2*window->border)/screen->width, (float)(window->height+2*window->border)/screen->height);
1230 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
1231 compositor->glXReleaseTexImageEXT(compositor->display, window->glx_pixmap, GLX_FRONT_LEFT_EXT);
1234 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
1235 glClearColor(0.5f, 0.0f, 0.5f, 0.0f);
1236 glClear(GL_COLOR_BUFFER_BIT);
1237 glBindTexture(GL_TEXTURE_2D, screen->fb_texture);
1238 glEnable(GL_PRIMITIVE_RESTART);
1239 glPrimitiveRestartIndex(0xFFFF);
1241 glUseProgram(screen->program);
1243 for(i=0; i<screen->nmonitors; ++i)
1245 CompositedMonitor *monitor = &screen->monitors[i];
1246 if(!monitor->enabled)
1249 glUniform4f(screen->geometry_loc,
1250 (float)monitor->x/screen->width, 1.0f-(float)(monitor->y+monitor->height)/screen->height,
1251 (float)monitor->width/screen->width, (float)monitor->height/screen->height);
1253 glBindVertexArray(monitor->vertex_array);
1254 glDrawElements(GL_TRIANGLE_STRIP, monitor->nelements, GL_UNSIGNED_SHORT, NULL);
1257 glBindVertexArray(0);
1259 glXSwapBuffers(compositor->display, screen->glx_window);
1264 void refresh_all_screens(Compositor *compositor)
1268 for(i=0; i<compositor->nscreens; ++i)
1270 CompositedScreen *screen = &compositor->screens[i];
1272 refresh_screen(compositor, screen);
1275 compositor->dirty = 0;
1278 void sighandler(int sig)
1280 terminate_requested = 1;
1286 Compositor compositor;
1288 signal(SIGINT, &sighandler);
1289 signal(SIGTERM, &sighandler);
1291 if(!initialize_compositor(&compositor))
1294 while(!terminate_requested)
1296 process_events(&compositor);
1297 if(compositor.dirty && !terminate_requested)
1298 refresh_all_screens(&compositor);
1301 shutdown_compositor(&compositor);