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;
41 typedef struct CompositedMonitor
49 float keystone_vertical;
51 float curvature_depth;
52 float vertical_center;
54 unsigned vertex_buffer;
55 unsigned index_buffer;
56 unsigned vertex_array;
57 unsigned tessellation;
60 unsigned geometry_data_size;
63 typedef struct CompositedScreen
73 GLXContext glx_context;
77 unsigned masked_program;
78 int masked_geometry_loc;
79 unsigned window_vertex_buffer;
80 unsigned window_vertex_array;
84 GLXPixmap root_glx_pixmap;
85 unsigned root_texture;
86 CompositedWindow *windows;
88 unsigned windows_capacity;
89 CompositedMonitor *monitors;
94 typedef struct Compositor
97 CompositedScreen *screens;
102 PFNGLXCREATECONTEXTATTRIBSARBPROC glXCreateContextAttribsARB;
103 PFNGLXBINDTEXIMAGEEXTPROC glXBindTexImageEXT;
104 PFNGLXRELEASETEXIMAGEEXTPROC glXReleaseTexImageEXT;
106 Atom correction_atom;
108 Atom geometry_data_atom;
109 Window selection_window;
113 static const char *vshader_src =
115 "uniform vec4 geometry;\n"
117 "in vec2 texture_coord;\n"
118 "out vec2 texcoord;\n"
121 " gl_Position = vec4((geometry.xy+vertex*geometry.zw)*2.0-1.0, 0.0, 1.0);\n"
122 " texcoord = texture_coord;\n"
125 static const char *fshader_src =
127 "uniform sampler2D image;\n"
128 "in vec2 texcoord;\n"
129 "out vec4 frag_color;\n"
132 " frag_color = texture(image, texcoord);\n"
135 static const char *masked_fshader_src =
137 "uniform sampler2D image;\n"
138 "uniform sampler2D mask;\n"
139 "in vec2 texcoord;\n"
140 "out vec4 frag_color;\n"
143 " if(texture(mask, texcoord).r==0.0)\n"
145 " frag_color = texture(image, texcoord);\n"
148 static const float window_vertices[] =
150 /* vertex texcoord */
151 0.0f, 1.0f, 0.0f, 0.0f,
152 0.0f, 0.0f, 0.0f, 1.0f,
153 1.0f, 1.0f, 1.0f, 0.0f,
154 1.0f, 0.0f, 1.0f, 1.0f
157 int terminate_requested = 0;
159 int x_error_handler(Display *display, XErrorEvent *event)
161 printf("Ignoring X error %d on resource %lx\n", event->error_code, event->resourceid);
166 int with_error(const char *message)
168 fprintf(stderr, "%s\n", message);
172 int initialize_gl(Compositor *compositor, CompositedScreen *screen)
176 GLXFBConfig *configs;
179 XSetWindowAttributes win_attr;
182 attribs[i++] = GLX_DRAWABLE_TYPE;
183 attribs[i++] = GLX_WINDOW_BIT;
184 attribs[i++] = GLX_RENDER_TYPE;
185 attribs[i++] = GLX_RGBA_BIT;
186 attribs[i++] = GLX_DOUBLEBUFFER;
188 attribs[i++] = GLX_BIND_TO_TEXTURE_RGBA_EXT;
192 configs = glXChooseFBConfig(compositor->display, screen->number, attribs, &nconfigs);
193 if(!configs || !nconfigs)
194 return with_error("Could not find a suitable FBConfig");
195 screen->fbconfig = configs[0];
198 vi = glXGetVisualFromFBConfig(compositor->display, screen->fbconfig);
199 win_attr.colormap = XCreateColormap(compositor->display, screen->root, vi->visual, AllocNone);
200 screen->render_window = XCreateWindow(compositor->display, screen->overlay, 0, 0, screen->width, screen->height, 0, vi->depth, InputOutput, vi->visual, CWColormap, &win_attr);
201 XMapWindow(compositor->display, screen->render_window);
203 screen->glx_window = glXCreateWindow(compositor->display, screen->fbconfig, screen->render_window, NULL);
206 attribs[i++] = GLX_CONTEXT_FLAGS_ARB;
207 attribs[i++] = GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB;
208 attribs[i++] = GLX_CONTEXT_MAJOR_VERSION_ARB;
210 attribs[i++] = GLX_CONTEXT_MINOR_VERSION_ARB;
214 screen->glx_context = compositor->glXCreateContextAttribsARB(compositor->display, screen->fbconfig, NULL, True, attribs);
221 void use_gl(Compositor *compositor, CompositedScreen *screen)
223 glXMakeContextCurrent(compositor->display, screen->glx_window, screen->glx_window, screen->glx_context);
226 unsigned compile_shader(GLenum type, const char *source)
233 shader = glCreateShader(type);
234 glShaderSource(shader, 1, &source, NULL);
235 glCompileShader(shader);
236 glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
237 glGetShaderInfoLog(shader, sizeof(info_log), &length, info_log);
240 fprintf(stderr, "Shader compilation failed:\n%s\n", info_log);
241 glDeleteShader(shader);
245 printf("Shader info log:\n%s\n", info_log);
250 unsigned link_program(unsigned vshader, unsigned fshader)
257 program = glCreateProgram();
258 glAttachShader(program, vshader);
259 glAttachShader(program, fshader);
260 glBindAttribLocation(program, 0, "vertex");
261 glBindAttribLocation(program, 1, "texture_coord");
262 glBindFragDataLocation(program, 0, "frag_color");
263 glLinkProgram(program);
265 glGetProgramiv(program, GL_LINK_STATUS, &status);
266 glGetProgramInfoLog(program, sizeof(info_log), &length, info_log);
269 fprintf(stderr, "Program link failed:\n%s\n", info_log);
270 glDeleteProgram(program);
274 printf("Program info log:\n%s\n", info_log);
279 unsigned create_2d_texture()
282 glGenTextures(1, &texture);
283 glBindTexture(GL_TEXTURE_2D, texture);
284 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
285 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
286 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
290 int create_gl_resources(CompositedScreen *screen)
295 screen->shaders[0] = compile_shader(GL_VERTEX_SHADER, vshader_src);
296 screen->shaders[1] = compile_shader(GL_FRAGMENT_SHADER, fshader_src);
297 screen->shaders[2] = compile_shader(GL_FRAGMENT_SHADER, masked_fshader_src);
298 if(!screen->shaders[0] || !screen->shaders[1] || !screen->shaders[2])
301 screen->program = link_program(screen->shaders[0], screen->shaders[1]);
305 screen->masked_program = link_program(screen->shaders[0], screen->shaders[2]);
306 if(!screen->masked_program)
309 screen->geometry_loc = glGetUniformLocation(screen->program, "geometry");
310 screen->masked_geometry_loc = glGetUniformLocation(screen->masked_program, "geometry");
312 loc = glGetUniformLocation(screen->masked_program, "mask");
315 glUseProgram(screen->masked_program);
319 glGenBuffers(1, &screen->window_vertex_buffer);
320 glBindBuffer(GL_ARRAY_BUFFER, screen->window_vertex_buffer);
321 glBufferData(GL_ARRAY_BUFFER, sizeof(window_vertices), window_vertices, GL_STATIC_DRAW);
323 stride = 4*sizeof(float);
324 glGenVertexArrays(1, &screen->window_vertex_array);
325 glBindVertexArray(screen->window_vertex_array);
326 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, stride, NULL);
327 glEnableVertexAttribArray(0);
328 glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, stride, (void *)(2*sizeof(float)));
329 glEnableVertexAttribArray(1);
330 glBindVertexArray(0);
332 glBindBuffer(GL_ARRAY_BUFFER, 0);
334 screen->fb_texture = create_2d_texture();
335 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, screen->width, screen->height, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
336 glBindTexture(GL_TEXTURE_2D, 0);
338 glGenFramebuffers(1, &screen->framebuffer);
339 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, screen->framebuffer);
340 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, screen->fb_texture, 0);
341 glDepthMask(GL_FALSE);
342 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
344 screen->root_texture = create_2d_texture();
349 CompositedWindow *find_window(CompositedScreen *screen, Window w)
353 for(i=0; i<screen->nwindows; ++i)
354 if(screen->windows[i].window==w)
355 return &screen->windows[i];
360 CompositedWindow *find_window_global(Compositor *compositor, Window w, CompositedScreen **screen)
364 for(i=0; i<compositor->nscreens; ++i)
365 for(j=0; j<compositor->screens[i].nwindows; ++j)
366 if(compositor->screens[i].windows[j].window==w)
369 *screen = &compositor->screens[i];
370 return &compositor->screens[i].windows[j];
378 GLXPixmap pixmap_to_glx_pixmap(Compositor *compositor, CompositedScreen *screen, Pixmap pixmap)
384 attribs[i++] = GLX_TEXTURE_TARGET_EXT;
385 attribs[i++] = GLX_TEXTURE_2D_EXT;
386 attribs[i++] = GLX_TEXTURE_FORMAT_EXT;
387 attribs[i++] = GLX_TEXTURE_FORMAT_RGBA_EXT;
390 return glXCreatePixmap(compositor->display, screen->fbconfig, pixmap, attribs);
393 void create_window_pixmap(Compositor *compositor, CompositedScreen *screen, CompositedWindow *window)
397 glXDestroyPixmap(compositor->display, window->glx_pixmap);
398 XFreePixmap(compositor->display, window->pixmap);
401 window->pixmap = XCompositeNameWindowPixmap(compositor->display, window->window);
402 window->glx_pixmap = pixmap_to_glx_pixmap(compositor, screen, window->pixmap);
403 window->recreate_pixmap = 0;
406 void update_window_mask(Compositor *compositor, CompositedWindow *window)
408 Bool bounding_shaped;
420 XShapeQueryExtents(compositor->display, window->window, &bounding_shaped, &xi, &yi, &width, &height, &clip_shaped, &xi, &yi, &width, &height);
421 window->use_mask = bounding_shaped;
422 if(!window->use_mask)
425 rects = XShapeGetRectangles(compositor->display, window->window, ShapeBounding, &rect_count, &rect_order);
429 width = window->width+2*window->border;
430 height = window->height+2*window->border;
431 data = (unsigned char *)malloc(width*height);
432 memset(data, 0, width*height);
433 for(i=0; i<rect_count; ++i)
435 rects[i].x += window->border;
436 rects[i].y += window->border;
437 if(rects[i].x>=(int)width || rects[i].y>=(int)height)
442 if(-rects[i].x>rects[i].width)
444 rects[i].width += rects[i].x;
450 if(-rects[i].y>rects[i].height)
452 rects[i].height += rects[i].y;
456 if(rects[i].x+rects[i].width>(int)width)
457 rects[i].width = width-rects[i].x;
458 if(rects[i].y+rects[i].height>(int)height)
459 rects[i].height = height-rects[i].y;
461 for(y=0; y<rects[i].height; ++y)
463 unsigned char *row = data+(rects[i].y+y)*width+rects[i].x;
464 memset(row, 255, rects[i].width);
470 glBindTexture(GL_TEXTURE_2D, window->mask_texture);
471 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
472 glTexImage2D(GL_TEXTURE_2D, 0, GL_R8, width, height, 0, GL_RED, GL_UNSIGNED_BYTE, data);
476 window->recreate_mask = 0;
479 CompositedWindow *add_window(Compositor *compositor, CompositedScreen *screen, Window w)
481 CompositedWindow *window;
482 XWindowAttributes win_attr;
484 if(w==screen->root || w==screen->overlay)
487 if(!XGetWindowAttributes(compositor->display, w, &win_attr))
489 printf("XGetWindowAttributes failed; probably the window was already destroyed\n");
492 if(win_attr.class==InputOnly)
495 if(find_window(screen, w))
498 if(screen->nwindows==screen->windows_capacity)
500 screen->windows = (CompositedWindow *)realloc(screen->windows, (screen->windows_capacity+1)*sizeof(CompositedWindow));
501 ++screen->windows_capacity;
504 window = &screen->windows[screen->nwindows++];
507 window->x = win_attr.x;
508 window->y = win_attr.y;
509 window->width = win_attr.width;
510 window->height = win_attr.height;
511 window->border = win_attr.border_width;
512 window->map_state = win_attr.map_state;
514 window->damage = XDamageCreate(compositor->display, window->window, XDamageReportNonEmpty);
515 window->pixmap = None;
516 window->glx_pixmap = None;
518 XCompositeRedirectWindow(compositor->display, window->window, CompositeRedirectManual);
519 window->recreate_pixmap = (window->map_state==IsViewable);
521 window->texture = create_2d_texture();
522 window->mask_texture = create_2d_texture();
523 window->use_mask = 0;
524 window->recreate_mask = (window->map_state==IsViewable);
526 XShapeSelectInput(compositor->display, window->window, ShapeNotifyMask);
531 void remove_window(Compositor *compositor, CompositedScreen *screen, CompositedWindow *window, int destroyed)
535 glDeleteTextures(1, &window->texture);
538 XDamageDestroy(compositor->display, window->damage);
541 glXDestroyPixmap(compositor->display, window->glx_pixmap);
542 XFreePixmap(compositor->display, window->pixmap);
544 XCompositeUnredirectWindow(compositor->display, window->window, CompositeRedirectManual);
548 for(i=window-screen->windows; i<screen->nwindows; ++i)
549 screen->windows[i] = screen->windows[i+1];
552 CompositedWindow *reorder_window(CompositedScreen *screen, CompositedWindow *window, Window above)
555 CompositedWindow hold;
557 i = window-screen->windows;
558 if((i>0 && screen->windows[i-1].window==above) || (i==0 && !above))
563 for(j=0; j<screen->nwindows; ++j)
564 if(screen->windows[j].window==above)
567 if(j>=screen->nwindows || i==j+1)
580 screen->windows[i] = screen->windows[i+1];
585 screen->windows[i] = screen->windows[i-1];
587 screen->windows[j] = hold;
589 return &screen->windows[j];
592 CompositedScreen *find_screen_by_root(Compositor *compositor, Window root)
596 for(i=0; i<compositor->nscreens; ++i)
597 if(compositor->screens[i].root==root)
598 return &compositor->screens[i];
603 void create_geometry_correction(CompositedMonitor *monitor)
608 glGenBuffers(2, buffers);
609 monitor->vertex_buffer = buffers[0];
610 monitor->index_buffer = buffers[1];
612 monitor->tessellation = 50;
613 monitor->geometry_data_size = (monitor->tessellation+1)*(monitor->tessellation+1)*3+16;
614 monitor->geometry_data = (short *)malloc(monitor->geometry_data_size*sizeof(short));
615 stride = 4*sizeof(float);
617 glGenVertexArrays(1, &monitor->vertex_array);
618 glBindVertexArray(monitor->vertex_array);
619 glBindBuffer(GL_ARRAY_BUFFER, monitor->vertex_buffer);
620 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, stride, NULL);
621 glEnableVertexAttribArray(0);
622 glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, stride, (void *)(2*sizeof(float)));
623 glEnableVertexAttribArray(1);
624 glBindBuffer(GL_ARRAY_BUFFER, 0);
625 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, monitor->index_buffer);
626 glBindVertexArray(0);
629 void free_geometry_correction(CompositedMonitor *monitor)
633 buffers[0] = monitor->vertex_buffer;
634 buffers[1] = monitor->index_buffer;
635 glDeleteBuffers(2, buffers);
636 monitor->vertex_buffer = 0;
637 monitor->index_buffer = 0;
639 glDeleteVertexArrays(1, &monitor->vertex_array);
641 free(monitor->geometry_data);
642 monitor->geometry_data = 0;
645 void update_monitor_vertices(CompositedScreen *screen, CompositedMonitor *monitor)
650 unsigned short *index_data;
662 t = monitor->tessellation;
664 data_size = (t+1)*(t+1)*4*sizeof(float);
665 vertex_data = (float *)malloc(data_size);
667 aspect = (float)monitor->width/monitor->height;
669 if(monitor->curvature_depth)
671 curve_radius = (monitor->curvature_depth*monitor->curvature_depth+0.25f)/(2.0f*monitor->curvature_depth);
672 curve_arc = 2.0f*asin(0.5f/curve_radius);
675 sin_ksv = monitor->keystone_vertical/sqrt(1.0f+monitor->keystone_vertical*monitor->keystone_vertical);
676 cos_ksv = sqrt(1.0f-sin_ksv*sin_ksv);
677 distance = monitor->perspective+sin_ksv*((sin_ksv>0)-monitor->vertical_center)/aspect;
678 if(monitor->curvature_depth<0)
679 distance += -monitor->curvature_depth;
682 eye[1] = (monitor->vertical_center-0.5f)/aspect+sin_ksv*distance;
683 eye[2] = cos_ksv*distance;
694 v = vertex_data+(y*(t+1)+x)*3;
695 v[0] = (float)x/t-0.5f;
696 v[1] = ((float)y/t-0.5f)/aspect;
698 if(monitor->curvature_depth)
700 if(monitor->curvature_type==CYLINDRICAL)
702 v[2] = (1.0f-cos(v[0]*curve_arc))*curve_radius-monitor->curvature_depth;
703 v[0] = sin(v[0]*curve_arc)*curve_radius;
705 else if(monitor->curvature_type==SPHERICAL)
709 v[0] = tan(v[0]*curve_arc)*curve_radius;
710 v[1] = tan(v[1]*curve_arc)*curve_radius;
711 r = sqrt(v[0]*v[0]+v[1]*v[1]+curve_radius*curve_radius)/fabs(curve_radius);
714 v[2] = curve_radius-curve_radius/r-monitor->curvature_depth;
719 monitor->geometry_data[0] = t;
721 monitor->geometry_data[1+i] = eye[i]*4096;
726 monitor->geometry_data[i] = ((x-0.5f)*distance/monitor->perspective)*4096;
727 monitor->geometry_data[i+1] = (eye[1]+look[1]*distance-(y-monitor->vertical_center)*look[2]*distance/monitor->perspective/aspect)*4096;
728 monitor->geometry_data[i+2] = (eye[2]+look[2]*distance+(y-monitor->vertical_center)*look[1]*distance/monitor->perspective/aspect)*4096;
730 for(i=0; i<(t+1)*(t+1)*3; ++i)
731 monitor->geometry_data[16+i] = vertex_data[i]*4096;
740 v = vertex_data+(y*(t+1)+x)*3;
742 py = (v[0]-eye[0])*look[0] - (v[1]-eye[1])*look[2] + (v[2]-eye[2])*look[1];
743 pz = (v[0]-eye[0])*look[0] + (v[1]-eye[1])*look[1] + (v[2]-eye[2])*look[2];
744 scale = monitor->perspective/pz;
746 v = vertex_data+(y*(t+1)+x)*4;
747 v[0] = px*scale+0.5f;
748 v[1] = py*aspect*scale+monitor->vertical_center;
749 v[2] = (monitor->x+(float)x*monitor->width/t)/screen->width;
750 v[3] = 1.0f-(monitor->y+(1.0f-(float)y/t)*monitor->height)/screen->height;
753 glBindBuffer(GL_ARRAY_BUFFER, monitor->vertex_buffer);
754 glBufferData(GL_ARRAY_BUFFER, data_size, vertex_data, GL_STATIC_DRAW);
755 glBindBuffer(GL_ARRAY_BUFFER, 0);
758 monitor->nelements = t*((t+1)*2+1)-1;
759 data_size = monitor->nelements*sizeof(unsigned short);
760 index_data = (unsigned short *)malloc(data_size);
765 index_data[i++] = 0xFFFF;
768 index_data[i++] = (y+1)*(t+1)+x;
769 index_data[i++] = y*(t+1)+x;
772 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, monitor->index_buffer);
773 glBufferData(GL_ELEMENT_ARRAY_BUFFER, data_size, index_data, GL_STATIC_DRAW);
774 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
778 int initialize_monitor(Compositor *compositor, CompositedScreen *screen, XRRScreenResources *xrr_res, unsigned index)
780 CompositedMonitor *monitor;
781 XRROutputInfo *output;
785 monitor = &screen->monitors[index];
787 output = XRRGetOutputInfo(compositor->display, xrr_res, xrr_res->outputs[index]);
788 namelen = strlen(output->name);
789 monitor->name = (char *)malloc(namelen+1);
790 strcpy(monitor->name, output->name);
791 monitor->enabled = !!output->crtc;
792 if(!monitor->enabled)
794 XRRFreeOutputInfo(output);
795 monitor->vertex_buffer = 0;
796 monitor->index_buffer = 0;
797 monitor->vertex_array = 0;
798 monitor->geometry_data = NULL;
802 crtc = XRRGetCrtcInfo(compositor->display, xrr_res, output->crtc);
803 monitor->x = crtc->x;
804 monitor->y = crtc->y;
805 monitor->width = crtc->width;
806 monitor->height = crtc->height;
807 XRRFreeCrtcInfo(crtc);
808 XRRFreeOutputInfo(output);
810 monitor->keystone_vertical = 0.0f;
811 monitor->curvature_type = CYLINDRICAL;
812 monitor->curvature_depth = 0.0f;
813 monitor->vertical_center = 0.5f;
814 monitor->perspective = 1.0f;
816 create_geometry_correction(monitor);
817 update_monitor_vertices(screen, monitor);
822 CompositedMonitor *find_monitor_by_name(CompositedScreen *screen, char *name)
826 for(i=0; i<screen->nmonitors; ++i)
827 if(!strcmp(screen->monitors[i].name, name))
828 return &screen->monitors[i];
833 CompositedMonitor *find_monitor_by_name_global(Compositor *compositor, char *name, CompositedScreen **screen)
837 for(i=0; i<compositor->nscreens; ++i)
838 for(j=0; j<compositor->screens[i].nmonitors; ++j)
839 if(!strcmp(compositor->screens[i].monitors[j].name, name))
842 *screen = &compositor->screens[i];
843 return &compositor->screens[i].monitors[j];
851 void update_monitors(Compositor *compositor, CompositedScreen *screen)
853 XRRScreenResources *xrr_res;
856 xrr_res = XRRGetScreenResources(compositor->display, screen->root);
857 for(i=0; i<xrr_res->noutput; ++i)
859 XRROutputInfo *output;
860 CompositedMonitor *monitor;
864 output = XRRGetOutputInfo(compositor->display, xrr_res, xrr_res->outputs[i]);
865 monitor = find_monitor_by_name(screen, output->name);
869 was_enabled = monitor->enabled;
870 monitor->enabled = !!output->crtc;
871 if(!monitor->enabled)
873 XRRFreeOutputInfo(output);
875 free_geometry_correction(monitor);
879 crtc = XRRGetCrtcInfo(compositor->display, xrr_res, output->crtc);
880 monitor->x = crtc->x;
881 monitor->y = crtc->y;
882 monitor->width = crtc->width;
883 monitor->height = crtc->height;
884 XRRFreeCrtcInfo(crtc);
885 XRRFreeOutputInfo(output);
888 create_geometry_correction(monitor);
890 update_monitor_vertices(screen, monitor);
892 XRRFreeScreenResources(xrr_res);
895 void update_geometry_correction(Compositor *compositor, CompositedScreen *screen)
899 unsigned long overflow;
900 unsigned long names_length;
902 unsigned long values_length;
907 XGetWindowProperty(compositor->display, screen->root, compositor->monitors_atom, 0, 64, False, XA_STRING,
908 &prop_type, &prop_format, &names_length, &overflow, (unsigned char **)&names);
909 if(prop_type!=XA_STRING || prop_format!=8)
912 XGetWindowProperty(compositor->display, screen->root, compositor->correction_atom, 0, 64, False, XA_INTEGER,
913 &prop_type, &prop_format, &values_length, &overflow, (unsigned char **)&values);
914 if(prop_type!=XA_INTEGER || prop_format!=16)
920 use_gl(compositor, screen);
923 for(i=0; i*5+4<values_length; ++i)
925 CompositedMonitor *monitor;
927 if(name_ptr>=names+names_length)
930 monitor = find_monitor_by_name(screen, name_ptr);
933 monitor->keystone_vertical = values[i*5]/4096.0f;
934 monitor->curvature_type = values[i*5+1];
935 monitor->curvature_depth = values[i*5+2]/4096.0f;
936 monitor->vertical_center = values[i*5+3]/4096.0f;
937 monitor->perspective = values[i*5+4]/4096.0f;
940 update_monitor_vertices(screen, monitor);
943 name_ptr += strlen(name_ptr)+1;
950 void update_root_pixmap(Compositor *compositor, CompositedScreen *screen)
954 unsigned long overflow;
955 unsigned long length;
964 use_gl(compositor, screen);
966 if(screen->root_glx_pixmap)
968 glXDestroyPixmap(compositor->display, screen->root_glx_pixmap);
969 screen->root_glx_pixmap = None;
972 XGetWindowProperty(compositor->display, screen->root, compositor->root_pmap_atom, 0, 1, False, XA_PIXMAP,
973 &prop_type, &prop_format, &length, &overflow, (unsigned char **)&pixmap);
974 if(prop_type!=XA_PIXMAP || prop_format!=32)
976 screen->root_pixmap = None;
980 screen->root_pixmap = pixmap[0];
981 if(XGetGeometry(compositor->display, screen->root_pixmap, &root, &x, &y, &width, &height, &border, &depth))
982 screen->root_glx_pixmap = pixmap_to_glx_pixmap(compositor, screen, screen->root_pixmap);
984 screen->root_pixmap = None;
989 int initialize_screen(Compositor *compositor, unsigned number)
991 CompositedScreen *screen;
992 const char *extensions;
997 XRRScreenResources *xrr_res;
1003 screen = &compositor->screens[number];
1004 screen->number = number;
1006 extensions = glXQueryExtensionsString(compositor->display, screen->number);
1007 if(!strstr(extensions, "GLX_ARB_create_context"))
1008 return with_error("GLX_ARB_create_context is required");
1009 if(!strstr(extensions, "GLX_EXT_texture_from_pixmap"))
1010 return with_error("GLX_EXT_texture_from_pixmap is required");
1012 screen->root = RootWindow(compositor->display, screen->number);
1013 XSelectInput(compositor->display, screen->root, SubstructureNotifyMask|PropertyChangeMask);
1014 screen->overlay = XCompositeGetOverlayWindow(compositor->display, screen->root);
1015 XSelectInput(compositor->display, screen->overlay, StructureNotifyMask);
1016 XGetGeometry(compositor->display, screen->overlay, &dummy_root, &x, &y, &screen->width, &screen->height, &border, &depth);
1017 XShapeCombineRectangles(compositor->display, screen->overlay, ShapeInput, 0, 0, NULL, 0, ShapeSet, Unsorted);
1019 if(!initialize_gl(compositor, screen))
1022 use_gl(compositor, screen);
1024 if(!create_gl_resources(screen))
1027 xrr_res = XRRGetScreenResources(compositor->display, screen->root);
1028 screen->nmonitors = xrr_res->noutput;
1029 screen->monitors = (CompositedMonitor *)malloc(screen->nmonitors*sizeof(CompositedMonitor));
1030 for(i=0; i<screen->nmonitors; ++i)
1031 if(!initialize_monitor(compositor, screen, xrr_res, i))
1033 XRRFreeScreenResources(xrr_res);
1034 XRRSelectInput(compositor->display, screen->root, RRScreenChangeNotifyMask);
1036 screen->root_pixmap = None;
1037 screen->root_glx_pixmap = None;
1039 update_geometry_correction(compositor, screen);
1040 update_root_pixmap(compositor, screen);
1042 XQueryTree(compositor->display, screen->root, &dummy_root, &dummy_parent, &children, &nchildren);
1044 screen->windows = (CompositedWindow *)malloc(nchildren*sizeof(CompositedWindow));
1045 screen->nwindows = 0;
1046 screen->windows_capacity = nchildren;
1048 for(i=0; i<nchildren; ++i)
1049 add_window(compositor, screen, children[i]);
1058 int initialize_compositor(Compositor *compositor)
1066 compositor->display = XOpenDisplay(NULL);
1067 if(!compositor->display)
1068 return with_error("Could not open X display");
1070 XSetErrorHandler(&x_error_handler);
1072 if(!XCompositeQueryExtension(compositor->display, &event_base, &error_base))
1073 return with_error("XComposite is required but was not found");
1074 else if(!XCompositeQueryVersion(compositor->display, &major_ver, &minor_ver))
1075 return with_error("Cannot determine XComposite version");
1076 else if(major_ver==0 && minor_ver<3)
1077 return with_error("XComposite 0.3 or later is required");
1079 if(!glXQueryExtension(compositor->display, &event_base, &error_base))
1080 return with_error("GLX is required but was not found");
1081 else if(!glXQueryVersion(compositor->display, &major_ver, &minor_ver))
1082 return with_error("Cannot determine GLX version");
1083 else if(major_ver<1 || (major_ver==1 && minor_ver<4))
1084 return with_error("GLX 1.4 or later is required");
1086 if(!XDamageQueryExtension(compositor->display, &compositor->damage_event, &error_base))
1087 return with_error("XDamage is required but was not found");
1088 else if(!XDamageQueryVersion(compositor->display, &major_ver, &minor_ver))
1089 return with_error("Cannot determine XDamage version");
1090 else if(major_ver<1)
1091 return with_error("XDamage 1.0 or later is required");
1093 if(!XShapeQueryExtension(compositor->display, &compositor->shape_event, &error_base))
1094 return with_error("XShape is required but was not found");
1095 else if(!XShapeQueryVersion(compositor->display, &major_ver, &minor_ver))
1096 return with_error("Cannot determine XShape version");
1097 else if(major_ver<1 || (major_ver==1 && minor_ver<1))
1098 return with_error("XShape 1.1 or later is required");
1100 if(!XRRQueryExtension(compositor->display, &compositor->randr_event, &error_base))
1101 return with_error("XRandR is required but was not found");
1102 else if(!XRRQueryVersion(compositor->display, &major_ver, &minor_ver))
1103 return with_error("Cannot determine XRandR version");
1104 else if(major_ver<1 || (major_ver==1 && minor_ver<2))
1105 return with_error("XRandR 1.2 or later is required");
1107 compositor->glXCreateContextAttribsARB = (PFNGLXCREATECONTEXTATTRIBSARBPROC)glXGetProcAddress((unsigned char *)"glXCreateContextAttribsARB");
1108 compositor->glXBindTexImageEXT = (PFNGLXBINDTEXIMAGEEXTPROC)glXGetProcAddress((unsigned char *)"glXBindTexImageEXT");
1109 compositor->glXReleaseTexImageEXT = (PFNGLXRELEASETEXIMAGEEXTPROC)glXGetProcAddress((unsigned char *)"glXReleaseTexImageEXT");
1111 compositor->root_pmap_atom = XInternAtom(compositor->display, "_XROOTPMAP_ID", False);
1112 compositor->correction_atom = XInternAtom(compositor->display, "_MSP_GEOMETRY_CORRECTION", False);
1113 compositor->monitors_atom = XInternAtom(compositor->display, "_MSP_GEOMETRY_CORRECTION_MONITORS", False);
1114 compositor->geometry_data_atom = XInternAtom(compositor->display, "_MSP_GEOMETRY_CORRECTION_DATA", False);
1116 compositor->nscreens = ScreenCount(compositor->display);
1117 compositor->screens = (CompositedScreen *)malloc(compositor->nscreens*sizeof(CompositedScreen));
1118 for(i=0; i<compositor->nscreens; ++i)
1119 if(!initialize_screen(compositor, i))
1122 compositor->selection_window = XCreateWindow(compositor->display, compositor->screens[0].root, 0, 0, 1, 1, 0, CopyFromParent, InputOutput, CopyFromParent, 0, NULL);
1123 XSetSelectionOwner(compositor->display, compositor->geometry_data_atom, compositor->selection_window, CurrentTime);
1125 compositor->dirty = 1;
1130 void shutdown_screen(Compositor *compositor, CompositedScreen *screen)
1134 use_gl(compositor, screen);
1136 for(i=0; i<screen->nwindows; ++i)
1138 glDeleteTextures(1, &screen->windows[i].texture);
1139 glDeleteTextures(1, &screen->windows[i].mask_texture);
1140 if(screen->windows[i].pixmap)
1142 glXDestroyPixmap(compositor->display, screen->windows[i].glx_pixmap);
1143 XFreePixmap(compositor->display, screen->windows[i].pixmap);
1144 XDamageDestroy(compositor->display, screen->windows[i].damage);
1148 for(i=0; i<screen->nmonitors; ++i)
1150 free(screen->monitors[i].name);
1151 if(screen->monitors[i].enabled)
1152 free_geometry_correction(&screen->monitors[i]);
1155 glDeleteTextures(1, &screen->root_texture);
1156 glXDestroyPixmap(compositor->display, screen->root_glx_pixmap);
1158 glDeleteBuffers(1, &screen->window_vertex_buffer);
1159 glDeleteVertexArrays(1, &screen->window_vertex_array);
1160 glDeleteFramebuffers(1, &screen->framebuffer);
1161 glDeleteTextures(1, &screen->fb_texture);
1162 glDeleteProgram(screen->program);
1163 glDeleteProgram(screen->masked_program);
1165 glDeleteShader(screen->shaders[i]);
1167 glXMakeContextCurrent(compositor->display, None, None, NULL);
1168 glXDestroyContext(compositor->display, screen->glx_context);
1169 glXDestroyWindow(compositor->display, screen->glx_window);
1170 XDestroyWindow(compositor->display, screen->render_window);
1172 XCompositeReleaseOverlayWindow(compositor->display, screen->overlay);
1174 free(screen->windows);
1175 free(screen->monitors);
1178 void shutdown_compositor(Compositor *compositor)
1182 for(i=0; i<compositor->nscreens; ++i)
1183 shutdown_screen(compositor, &compositor->screens[i]);
1184 free(compositor->screens);
1186 XDestroyWindow(compositor->display, compositor->selection_window);
1188 XCloseDisplay(compositor->display);
1191 void mark_dirty(Compositor *compositor, CompositedScreen *screen)
1193 compositor->dirty = 1;
1197 void process_create_window_event(Compositor *compositor, XCreateWindowEvent *event)
1199 CompositedScreen *screen;
1201 if((screen = find_screen_by_root(compositor, event->parent)))
1202 add_window(compositor, screen, event->window);
1205 void process_destroy_window_event(Compositor *compositor, XDestroyWindowEvent *event)
1207 CompositedScreen *screen;
1208 CompositedWindow *window;
1210 if((screen = find_screen_by_root(compositor, event->event)))
1211 if((window = find_window(screen, event->window)))
1213 use_gl(compositor, screen);
1214 remove_window(compositor, screen, window, 1);
1218 void process_map_event(Compositor *compositor, XMapEvent *event)
1220 CompositedScreen *screen;
1221 CompositedWindow *window;
1223 screen = find_screen_by_root(compositor, event->event);
1227 window = find_window(screen, event->window);
1231 window->map_state = IsViewable;
1232 window->recreate_pixmap = 1;
1233 window->recreate_mask = 1;
1235 mark_dirty(compositor, screen);
1238 void process_unmap_event(Compositor *compositor, XUnmapEvent *event)
1240 CompositedScreen *screen;
1241 CompositedWindow *window;
1243 screen = find_screen_by_root(compositor, event->event);
1247 window = find_window(screen, event->window);
1249 window->map_state = IsUnviewable;
1251 mark_dirty(compositor, screen);
1254 void process_reparent_event(Compositor *compositor, XReparentEvent *event)
1256 CompositedScreen *screen;
1257 CompositedWindow *window;
1259 screen = find_screen_by_root(compositor, event->event);
1263 if(event->parent==screen->root)
1264 window = add_window(compositor, screen, event->window);
1267 window = find_window(screen, event->window);
1271 remove_window(compositor, screen, window, 0);
1274 if(window && window->map_state==IsViewable)
1275 mark_dirty(compositor, screen);
1278 void process_configure_event(Compositor *compositor, XConfigureEvent *event)
1280 CompositedScreen *screen;
1281 CompositedWindow *window;
1283 screen = find_screen_by_root(compositor, event->event);
1287 if(event->window==screen->overlay)
1289 screen->width = event->width;
1290 screen->height = event->height;
1292 XResizeWindow(compositor->display, screen->render_window, screen->width, screen->height);
1293 use_gl(compositor, screen);
1294 glBindTexture(GL_TEXTURE_2D, screen->fb_texture);
1295 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, screen->width, screen->height, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
1296 glBindTexture(GL_TEXTURE_2D, 0);
1300 window = find_window(screen, event->window);
1304 window->x = event->x;
1305 window->y = event->y;
1306 if((unsigned)event->width!=window->width || (unsigned)event->height!=window->height || (unsigned)event->border_width!=window->border)
1308 window->width = event->width;
1309 window->height = event->height;
1310 window->border = event->border_width;
1311 window->recreate_pixmap = 1;
1313 window = reorder_window(screen, window, event->above);
1315 if(window->map_state==IsViewable)
1316 mark_dirty(compositor, screen);
1319 void process_property_event(Compositor *compositor, XPropertyEvent *event)
1321 CompositedScreen *screen;
1323 screen = find_screen_by_root(compositor, event->window);
1327 if(event->atom==compositor->correction_atom)
1329 update_geometry_correction(compositor, screen);
1330 mark_dirty(compositor, screen);
1332 else if(event->atom==compositor->root_pmap_atom)
1334 update_root_pixmap(compositor, screen);
1335 mark_dirty(compositor, screen);
1339 void process_selection_request_event(Compositor *compositor, XSelectionRequestEvent *event)
1343 unsigned long overflow;
1344 unsigned long names_length;
1345 XSelectionEvent notify;
1347 if(event->selection==compositor->geometry_data_atom)
1350 CompositedMonitor *monitor;
1352 XGetWindowProperty(compositor->display, event->requestor, event->property, 0, 64, False, XA_STRING,
1353 &prop_type, &prop_format, &names_length, &overflow, (unsigned char **)&monitor_name);
1354 if(prop_type!=XA_STRING || prop_format!=8)
1357 monitor = find_monitor_by_name_global(compositor, monitor_name, NULL);
1358 if(monitor && monitor->enabled)
1359 XChangeProperty(compositor->display, event->requestor, event->property, XA_INTEGER, 16, PropModeReplace, (unsigned char *)monitor->geometry_data, monitor->geometry_data_size);
1361 notify.type = SelectionNotify;
1362 notify.requestor = event->requestor;
1363 notify.selection = event->selection;
1364 notify.target = event->target;
1365 notify.property = (monitor ? event->property : None);
1366 notify.time = event->time;
1367 XSendEvent(compositor->display, event->requestor, False, 0, (XEvent *)¬ify);
1371 void process_damage_event(Compositor *compositor, XDamageNotifyEvent *event)
1373 CompositedScreen *screen;
1374 CompositedWindow *window;
1376 window = find_window_global(compositor, event->drawable, &screen);
1377 if(window && window->map_state==IsViewable)
1378 mark_dirty(compositor, screen);
1381 void process_shape_event(Compositor *compositor, XShapeEvent *event)
1383 CompositedScreen *screen;
1384 CompositedWindow *window;
1386 if(event->kind!=ShapeBounding)
1389 window = find_window_global(compositor, event->window, &screen);
1390 if(window && window->map_state==IsViewable)
1392 window->recreate_mask = 1;
1393 mark_dirty(compositor, screen);
1397 void process_randr_event(Compositor *compositor, XRRScreenChangeNotifyEvent *event)
1399 CompositedScreen *screen;
1401 if((screen = find_screen_by_root(compositor, event->root)))
1402 update_monitors(compositor, screen);
1405 void process_events(Compositor *compositor)
1411 while((pending || !compositor->dirty) && !terminate_requested)
1414 pending = XPending(compositor->display);
1416 XNextEvent(compositor->display, &event);
1423 process_create_window_event(compositor, &event.xcreatewindow);
1426 process_destroy_window_event(compositor, &event.xdestroywindow);
1429 process_map_event(compositor, &event.xmap);
1432 process_unmap_event(compositor, &event.xunmap);
1434 case ReparentNotify:
1435 process_reparent_event(compositor, &event.xreparent);
1437 case ConfigureNotify:
1438 process_configure_event(compositor, &event.xconfigure);
1440 case PropertyNotify:
1441 process_property_event(compositor, &event.xproperty);
1443 case SelectionRequest:
1444 process_selection_request_event(compositor, &event.xselectionrequest);
1447 if(event.type==compositor->damage_event+XDamageNotify)
1448 process_damage_event(compositor, (XDamageNotifyEvent *)&event);
1449 else if(event.type==compositor->shape_event+ShapeNotify)
1450 process_shape_event(compositor, (XShapeEvent *)&event);
1451 else if(event.type==compositor->randr_event+RRScreenChangeNotify)
1452 process_randr_event(compositor, (XRRScreenChangeNotifyEvent *)&event);
1457 void refresh_screen(Compositor *compositor, CompositedScreen *screen)
1462 for(i=0; i<screen->nwindows; ++i)
1463 if(screen->windows[i].map_state==IsViewable)
1464 XDamageSubtract(compositor->display, screen->windows[i].damage, None, None);
1467 use_gl(compositor, screen);
1469 glViewport(0, 0, screen->width, screen->height);
1470 glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
1471 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, screen->framebuffer);
1474 glBindVertexArray(screen->window_vertex_array);
1476 if(screen->root_pixmap)
1479 glUseProgram(screen->program);
1480 glBindTexture(GL_TEXTURE_2D, screen->root_texture);
1481 compositor->glXBindTexImageEXT(compositor->display, screen->root_glx_pixmap, GLX_FRONT_LEFT_EXT, NULL);
1482 glUniform4f(screen->geometry_loc, 0.0f, 0.0f, 1.0f, 1.0f);
1483 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
1484 compositor->glXReleaseTexImageEXT(compositor->display, screen->root_glx_pixmap, GLX_FRONT_LEFT_EXT);
1487 glClear(GL_COLOR_BUFFER_BIT);
1489 for(i=0; i<screen->nwindows; ++i)
1491 CompositedWindow *window;
1493 window = &screen->windows[i];
1494 if(window->map_state!=IsViewable)
1497 if(window->use_mask!=use_mask)
1499 use_mask = window->use_mask;
1500 glUseProgram(use_mask ? screen->masked_program : screen->program);
1503 if(window->use_mask)
1505 glActiveTexture(GL_TEXTURE1);
1506 glBindTexture(GL_TEXTURE_2D, window->mask_texture);
1507 glActiveTexture(GL_TEXTURE0);
1510 if(window->recreate_pixmap)
1511 create_window_pixmap(compositor, screen, window);
1512 if(window->recreate_mask)
1513 update_window_mask(compositor, window);
1515 glBindTexture(GL_TEXTURE_2D, window->texture);
1516 compositor->glXBindTexImageEXT(compositor->display, window->glx_pixmap, GLX_FRONT_LEFT_EXT, NULL);
1517 glUniform4f((use_mask ? screen->masked_geometry_loc : screen->geometry_loc),
1518 (float)window->x/screen->width, 1.0f-(float)(window->y+window->height)/screen->height,
1519 (float)(window->width+2*window->border)/screen->width, (float)(window->height+2*window->border)/screen->height);
1520 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
1521 compositor->glXReleaseTexImageEXT(compositor->display, window->glx_pixmap, GLX_FRONT_LEFT_EXT);
1524 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
1525 glClear(GL_COLOR_BUFFER_BIT);
1526 glBindTexture(GL_TEXTURE_2D, screen->fb_texture);
1527 glEnable(GL_PRIMITIVE_RESTART);
1528 glPrimitiveRestartIndex(0xFFFF);
1530 glUseProgram(screen->program);
1532 for(i=0; i<screen->nmonitors; ++i)
1534 CompositedMonitor *monitor = &screen->monitors[i];
1535 if(!monitor->enabled)
1538 glUniform4f(screen->geometry_loc,
1539 (float)monitor->x/screen->width, 1.0f-(float)(monitor->y+monitor->height)/screen->height,
1540 (float)monitor->width/screen->width, (float)monitor->height/screen->height);
1542 glBindVertexArray(monitor->vertex_array);
1543 glDrawElements(GL_TRIANGLE_STRIP, monitor->nelements, GL_UNSIGNED_SHORT, NULL);
1546 glBindVertexArray(0);
1548 glXSwapBuffers(compositor->display, screen->glx_window);
1553 void refresh_all_screens(Compositor *compositor)
1557 for(i=0; i<compositor->nscreens; ++i)
1559 CompositedScreen *screen = &compositor->screens[i];
1561 refresh_screen(compositor, screen);
1564 compositor->dirty = 0;
1567 void sighandler(int sig)
1569 terminate_requested = 1;
1575 Compositor compositor;
1577 signal(SIGINT, &sighandler);
1578 signal(SIGTERM, &sighandler);
1580 if(!initialize_compositor(&compositor))
1583 while(!terminate_requested)
1585 process_events(&compositor);
1586 if(compositor.dirty && !terminate_requested)
1587 refresh_all_screens(&compositor);
1590 shutdown_compositor(&compositor);