1 #define GL_GLEXT_PROTOTYPES
8 #include <X11/extensions/Xcomposite.h>
9 #include <X11/extensions/Xdamage.h>
10 #include <X11/extensions/shape.h>
11 #include <X11/extensions/Xrandr.h>
15 typedef struct CompositedWindow
30 typedef struct CompositedMonitor
37 float keystone_vertical;
39 float vertical_center;
41 unsigned vertex_buffer;
42 unsigned index_buffer;
43 unsigned vertex_array;
44 unsigned tessellation;
48 typedef struct CompositedScreen
58 GLXContext glx_context;
61 unsigned geometry_loc;
62 unsigned window_vertex_buffer;
63 unsigned window_vertex_array;
66 CompositedWindow *windows;
68 unsigned windows_capacity;
69 CompositedMonitor *monitors;
74 typedef struct Compositor
77 CompositedScreen *screens;
80 PFNGLXCREATECONTEXTATTRIBSARBPROC glXCreateContextAttribsARB;
81 PFNGLXBINDTEXIMAGEEXTPROC glXBindTexImageEXT;
82 PFNGLXRELEASETEXIMAGEEXTPROC glXReleaseTexImageEXT;
86 static const char *vshader =
88 "uniform vec4 geometry;\n"
90 "in vec2 texture_coord;\n"
91 "out vec2 texcoord;\n"
94 " gl_Position = vec4((geometry.xy+vertex*geometry.zw)*2.0-1.0, 0.0, 1.0);\n"
95 " texcoord = texture_coord;\n"
98 static const char *fshader =
100 "uniform sampler2D image;\n"
101 "in vec2 texcoord;\n"
102 "out vec4 frag_color;\n"
105 " frag_color = texture(image, texcoord);\n"
108 static const float window_vertices[] =
110 /* vertex texcoord */
111 0.0f, 1.0f, 0.0f, 0.0f,
112 0.0f, 0.0f, 0.0f, 1.0f,
113 1.0f, 1.0f, 1.0f, 0.0f,
114 1.0f, 0.0f, 1.0f, 1.0f
117 int terminate_requested = 0;
119 int x_error_handler(Display *display, XErrorEvent *event)
121 printf("Ignoring X error %d on resource %lx\n", event->error_code, event->resourceid);
126 int with_error(const char *message)
128 fprintf(stderr, "%s\n", message);
132 int initialize_gl(Compositor *compositor, CompositedScreen *screen)
136 GLXFBConfig *configs;
139 XSetWindowAttributes win_attr;
142 attribs[i++] = GLX_DRAWABLE_TYPE;
143 attribs[i++] = GLX_WINDOW_BIT;
144 attribs[i++] = GLX_RENDER_TYPE;
145 attribs[i++] = GLX_RGBA_BIT;
146 attribs[i++] = GLX_DOUBLEBUFFER;
148 attribs[i++] = GLX_BIND_TO_TEXTURE_RGBA_EXT;
152 configs = glXChooseFBConfig(compositor->display, screen->number, attribs, &nconfigs);
153 if(!configs || !nconfigs)
154 return with_error("Could not find a suitable FBConfig");
155 screen->fbconfig = configs[0];
158 vi = glXGetVisualFromFBConfig(compositor->display, screen->fbconfig);
159 win_attr.colormap = XCreateColormap(compositor->display, screen->root, vi->visual, AllocNone);
160 screen->render_window = XCreateWindow(compositor->display, screen->overlay, 0, 0, screen->width, screen->height, 0, vi->depth, InputOutput, vi->visual, CWColormap, &win_attr);
161 XMapWindow(compositor->display, screen->render_window);
163 screen->glx_window = glXCreateWindow(compositor->display, screen->fbconfig, screen->render_window, NULL);
166 attribs[i++] = GLX_CONTEXT_FLAGS_ARB;
167 attribs[i++] = GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB;
168 attribs[i++] = GLX_CONTEXT_MAJOR_VERSION_ARB;
170 attribs[i++] = GLX_CONTEXT_MINOR_VERSION_ARB;
174 screen->glx_context = compositor->glXCreateContextAttribsARB(compositor->display, screen->fbconfig, NULL, True, attribs);
181 void use_gl(Compositor *compositor, CompositedScreen *screen)
183 glXMakeContextCurrent(compositor->display, screen->glx_window, screen->glx_window, screen->glx_context);
186 unsigned compile_shader(GLenum type, const char *source)
193 shader = glCreateShader(type);
194 glShaderSource(shader, 1, &source, NULL);
195 glCompileShader(shader);
196 glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
197 glGetShaderInfoLog(shader, sizeof(info_log), &length, info_log);
200 fprintf(stderr, "Shader compilation failed:\n%s\n", info_log);
201 glDeleteShader(shader);
205 printf("Shader info log:\n%s\n", info_log);
210 unsigned link_program(unsigned *shaders, unsigned nshaders)
218 program = glCreateProgram();
219 for(i=0; i<nshaders; ++i)
220 glAttachShader(program, shaders[i]);
221 glBindAttribLocation(program, 0, "vertex");
222 glBindAttribLocation(program, 1, "texture_coord");
223 glBindFragDataLocation(program, 0, "frag_color");
224 glLinkProgram(program);
226 glGetProgramiv(program, GL_LINK_STATUS, &status);
227 glGetProgramInfoLog(program, sizeof(info_log), &length, info_log);
230 fprintf(stderr, "Program link failed:\n%s\n", info_log);
231 glDeleteProgram(program);
235 printf("Program info log:\n%s\n", info_log);
240 int create_gl_resources(Compositor *compositor, CompositedScreen *screen)
244 use_gl(compositor, screen);
246 screen->shaders[0] = compile_shader(GL_VERTEX_SHADER, vshader);
247 screen->shaders[1] = compile_shader(GL_FRAGMENT_SHADER, fshader);
248 if(!screen->shaders[0] || !screen->shaders[1])
251 screen->program = link_program(screen->shaders, 2);
255 screen->geometry_loc = glGetUniformLocation(screen->program, "geometry");
257 glGenBuffers(1, &screen->window_vertex_buffer);
258 glBindBuffer(GL_ARRAY_BUFFER, screen->window_vertex_buffer);
259 glBufferData(GL_ARRAY_BUFFER, sizeof(window_vertices), window_vertices, GL_STATIC_DRAW);
261 stride = 4*sizeof(float);
262 glGenVertexArrays(1, &screen->window_vertex_array);
263 glBindVertexArray(screen->window_vertex_array);
264 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, stride, NULL);
265 glEnableVertexAttribArray(0);
266 glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, stride, (void *)(2*sizeof(float)));
267 glEnableVertexAttribArray(1);
268 glBindVertexArray(0);
270 glBindBuffer(GL_ARRAY_BUFFER, 0);
272 glGenTextures(1, &screen->fb_texture);
273 glBindTexture(GL_TEXTURE_2D, screen->fb_texture);
274 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, screen->width, screen->height, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
275 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
276 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
277 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
278 glBindTexture(GL_TEXTURE_2D, 0);
280 glGenFramebuffers(1, &screen->framebuffer);
281 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, screen->framebuffer);
282 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, screen->fb_texture, 0);
283 glDepthMask(GL_FALSE);
284 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
289 CompositedWindow *find_window(CompositedScreen *screen, Window w)
293 for(i=0; i<screen->nwindows; ++i)
294 if(screen->windows[i].window==w)
295 return &screen->windows[i];
300 void create_window_pixmap(Compositor *compositor, CompositedScreen *screen, CompositedWindow *window)
307 glXDestroyPixmap(compositor->display, window->glx_pixmap);
308 XFreePixmap(compositor->display, window->pixmap);
312 attribs[i++] = GLX_TEXTURE_TARGET_EXT;
313 attribs[i++] = GLX_TEXTURE_2D_EXT;
314 attribs[i++] = GLX_TEXTURE_FORMAT_EXT;
315 attribs[i++] = GLX_TEXTURE_FORMAT_RGBA_EXT;
318 window->pixmap = XCompositeNameWindowPixmap(compositor->display, window->window);
319 window->glx_pixmap = glXCreatePixmap(compositor->display, screen->fbconfig, window->pixmap, attribs);
322 CompositedWindow *add_window(Compositor *compositor, CompositedScreen *screen, Window w)
324 CompositedWindow *window;
325 XWindowAttributes win_attr;
327 if(w==screen->root || w==screen->overlay)
330 if(!XGetWindowAttributes(compositor->display, w, &win_attr))
332 printf("XGetWindowAttributes failed; probably the window was already destroyed\n");
335 if(win_attr.class==InputOnly)
338 if(find_window(screen, w))
341 if(screen->nwindows==screen->windows_capacity)
343 screen->windows = (CompositedWindow *)realloc(screen->windows, (screen->windows_capacity+1)*sizeof(CompositedWindow));
344 ++screen->windows_capacity;
347 window = &screen->windows[screen->nwindows++];
350 window->x = win_attr.x;
351 window->y = win_attr.y;
352 window->width = win_attr.width;
353 window->height = win_attr.height;
354 window->border = win_attr.border_width;
355 window->map_state = win_attr.map_state;
357 window->damage = XDamageCreate(compositor->display, window->window, XDamageReportNonEmpty);
358 window->pixmap = None;
359 window->glx_pixmap = None;
361 XCompositeRedirectWindow(compositor->display, window->window, CompositeRedirectManual);
362 if(window->map_state==IsViewable)
363 create_window_pixmap(compositor, screen, window);
365 glGenTextures(1, &window->texture);
366 glBindTexture(GL_TEXTURE_2D, window->texture);
367 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
368 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
369 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
374 void remove_window(Compositor *compositor, CompositedScreen *screen, CompositedWindow *window, int destroyed)
378 glDeleteTextures(1, &window->texture);
381 XDamageDestroy(compositor->display, window->damage);
384 glXDestroyPixmap(compositor->display, window->glx_pixmap);
385 XFreePixmap(compositor->display, window->pixmap);
387 XCompositeUnredirectWindow(compositor->display, window->window, CompositeRedirectManual);
391 for(i=window-screen->windows; i<screen->nwindows; ++i)
392 screen->windows[i] = screen->windows[i+1];
395 CompositedWindow *reorder_window(CompositedScreen *screen, CompositedWindow *window, Window above)
398 CompositedWindow hold;
400 i = window-screen->windows;
403 for(j=0; j<screen->nwindows; ++j)
404 if(screen->windows[j].window==above)
407 if(j>=screen->nwindows || i==j+1)
420 screen->windows[i] = screen->windows[i+1];
425 screen->windows[i] = screen->windows[i-1];
427 screen->windows[j] = hold;
429 return &screen->windows[j];
432 CompositedScreen *find_screen_by_root(Compositor *compositor, Window root)
436 for(i=0; i<compositor->nscreens; ++i)
437 if(compositor->screens[i].root==root)
438 return &compositor->screens[i];
443 CompositedScreen *find_screen_by_window(Compositor *compositor, Window w)
447 for(i=0; i<compositor->nscreens; ++i)
448 for(j=0; j<compositor->screens[i].nwindows; ++j)
449 if(compositor->screens[i].windows[j].window==w)
450 return &compositor->screens[i];
455 void update_monitor_vertices(CompositedScreen *screen, CompositedMonitor *monitor)
460 unsigned short *index_data;
468 t = monitor->tessellation;
470 data_size = (t+1)*(t+1)*4*sizeof(float);
471 vertex_data = (float *)malloc(data_size);
472 aspect = (float)monitor->width/monitor->height;
473 cyl_w_sq = 0.25f-(0.5f-monitor->cylinder_depth)*(0.5f-monitor->cylinder_depth);
474 sin_ksv = monitor->keystone_vertical/sqrt(1.0f+monitor->keystone_vertical*monitor->keystone_vertical);
475 cos_ksv = sqrt(1.0f-sin_ksv*sin_ksv);
486 v = vertex_data+(y*(t+1)+x)*4;
487 v[2] = (monitor->x+xf*monitor->width)/screen->width;
488 v[3] = (monitor->y+yf*monitor->height)/screen->height;
490 z = sqrt(0.25f-(xf-0.5f)*(xf-0.5f)*4.0f*cyl_w_sq)-0.5f+monitor->cylinder_depth;
491 if(monitor->keystone_vertical>0)
493 rz = (1.0f-yf)/aspect*sin_ksv+z*cos_ksv;
494 yf = 1.0f-((1.0f-yf)*cos_ksv-z*aspect*sin_ksv);
497 else if(monitor->keystone_vertical<0)
499 rz = z*cos_ksv-yf/aspect*sin_ksv;
500 yf = yf*cos_ksv+z*aspect*sin_ksv;
503 scale = monitor->perspective/(monitor->perspective+z);
504 v[0] = 0.5f+(xf-0.5f)*scale;
505 v[1] = monitor->vertical_center+(yf-monitor->vertical_center)*scale;
507 glBindBuffer(GL_ARRAY_BUFFER, monitor->vertex_buffer);
508 glBufferData(GL_ARRAY_BUFFER, data_size, vertex_data, GL_STATIC_DRAW);
509 glBindBuffer(GL_ARRAY_BUFFER, 0);
512 monitor->nelements = t*((t+1)*2+1)-1;
513 data_size = monitor->nelements*sizeof(unsigned short);
514 index_data = (unsigned short *)malloc(data_size);
519 index_data[i++] = 0xFFFF;
522 index_data[i++] = (y+1)*(t+1)+x;
523 index_data[i++] = y*(t+1)+x;
526 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, monitor->index_buffer);
527 glBufferData(GL_ELEMENT_ARRAY_BUFFER, data_size, index_data, GL_STATIC_DRAW);
528 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
532 int initialize_monitor(Compositor *compositor, CompositedScreen *screen, XRRScreenResources *xrr_res, unsigned index)
534 CompositedMonitor *monitor;
535 XRROutputInfo *output;
540 monitor = &screen->monitors[index];
542 output = XRRGetOutputInfo(compositor->display, xrr_res, xrr_res->outputs[index]);
543 monitor->enabled = !!output->crtc;
544 if(!monitor->enabled)
546 XRRFreeOutputInfo(output);
550 crtc = XRRGetCrtcInfo(compositor->display, xrr_res, output->crtc);
551 monitor->x = crtc->x;
552 monitor->y = crtc->y;
553 monitor->width = crtc->width;
554 monitor->height = crtc->height;
555 XRRFreeCrtcInfo(crtc);
556 XRRFreeOutputInfo(output);
558 monitor->keystone_vertical = 0.0f;
559 monitor->cylinder_depth = 0.0f;
560 monitor->vertical_center = 0.5f;
561 monitor->perspective = 1.0f;
563 glGenBuffers(2, buffers);
564 monitor->vertex_buffer = buffers[0];
565 monitor->index_buffer = buffers[1];
567 monitor->tessellation = 50;
568 update_monitor_vertices(screen, monitor);
569 stride = 4*sizeof(float);
571 glGenVertexArrays(1, &monitor->vertex_array);
572 glBindVertexArray(monitor->vertex_array);
573 glBindBuffer(GL_ARRAY_BUFFER, monitor->vertex_buffer);
574 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, stride, NULL);
575 glEnableVertexAttribArray(0);
576 glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, stride, (void *)(2*sizeof(float)));
577 glEnableVertexAttribArray(1);
578 glBindBuffer(GL_ARRAY_BUFFER, 0);
579 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, monitor->index_buffer);
580 glBindVertexArray(0);
585 int initialize_screen(Compositor *compositor, unsigned number)
587 CompositedScreen *screen;
588 const char *extensions;
593 XRRScreenResources *xrr_res;
599 screen = &compositor->screens[number];
600 screen->number = number;
602 extensions = glXQueryExtensionsString(compositor->display, screen->number);
603 if(!strstr(extensions, "GLX_ARB_create_context"))
604 return with_error("GLX_ARB_create_context is required");
605 if(!strstr(extensions, "GLX_EXT_texture_from_pixmap"))
606 return with_error("GLX_EXT_texture_from_pixmap is required");
608 screen->root = RootWindow(compositor->display, screen->number);
609 XSelectInput(compositor->display, screen->root, SubstructureNotifyMask);
610 screen->overlay = XCompositeGetOverlayWindow(compositor->display, screen->root);
611 XGetGeometry(compositor->display, screen->overlay, &dummy_root, &x, &y, &screen->width, &screen->height, &border, &depth);
612 XShapeCombineRectangles(compositor->display, screen->overlay, ShapeInput, 0, 0, NULL, 0, ShapeSet, Unsorted);
614 if(!initialize_gl(compositor, screen))
617 if(!create_gl_resources(compositor, screen))
620 xrr_res = XRRGetScreenResources(compositor->display, screen->root);
621 screen->nmonitors = xrr_res->noutput;
622 screen->monitors = (CompositedMonitor *)malloc(screen->nmonitors*sizeof(CompositedMonitor));
623 for(i=0; i<screen->nmonitors; ++i)
624 if(!initialize_monitor(compositor, screen, xrr_res, i))
626 XRRFreeScreenResources(xrr_res);
628 XQueryTree(compositor->display, screen->root, &dummy_root, &dummy_parent, &children, &nchildren);
630 screen->windows = (CompositedWindow *)malloc(nchildren*sizeof(CompositedWindow));
631 screen->nwindows = 0;
632 screen->windows_capacity = nchildren;
634 for(i=0; i<nchildren; ++i)
635 add_window(compositor, screen, children[i]);
644 int initialize_compositor(Compositor *compositor)
652 compositor->display = XOpenDisplay(NULL);
653 if(!compositor->display)
654 return with_error("Could not open X display");
656 XSetErrorHandler(&x_error_handler);
658 if(!XCompositeQueryExtension(compositor->display, &event_base, &error_base))
659 return with_error("XComposite is required but was not found");
660 else if(!XCompositeQueryVersion(compositor->display, &major_ver, &minor_ver))
661 return with_error("Cannot determine XComposite version");
662 else if(major_ver==0 && minor_ver<3)
663 return with_error("XComposite 0.3 or later is required");
665 if(!glXQueryExtension(compositor->display, &event_base, &error_base))
666 return with_error("GLX is required but was not found");
667 else if(!glXQueryVersion(compositor->display, &major_ver, &minor_ver))
668 return with_error("Cannot determine GLX version");
669 else if(major_ver<1 || (major_ver==1 && minor_ver<4))
670 return with_error("GLX 1.4 or later is required");
672 if(!XDamageQueryExtension(compositor->display, &compositor->damage_event, &error_base))
673 return with_error("XDamage is required but was not found");
674 else if(!XDamageQueryVersion(compositor->display, &major_ver, &minor_ver))
675 return with_error("Cannot determine XDamage version");
677 return with_error("XDamage 1.0 or later is required");
679 if(!XShapeQueryExtension(compositor->display, &event_base, &error_base))
680 return with_error("XShape is required but was not found");
681 else if(!XShapeQueryVersion(compositor->display, &major_ver, &minor_ver))
682 return with_error("Cannot determine XShape version");
683 else if(major_ver<1 || (major_ver==1 && minor_ver<1))
684 return with_error("XShape 1.1 or later is required");
686 if(!XRRQueryExtension(compositor->display, &event_base, &error_base))
687 return with_error("XRandR is required but was not found");
688 else if(!XRRQueryVersion(compositor->display, &major_ver, &minor_ver))
689 return with_error("Cannot determine XRandR version");
690 else if(major_ver<1 || (major_ver==1 && minor_ver<2))
691 return with_error("XRandR 1.2 or later is required");
693 compositor->glXCreateContextAttribsARB = (PFNGLXCREATECONTEXTATTRIBSARBPROC)glXGetProcAddress((unsigned char *)"glXCreateContextAttribsARB");
694 compositor->glXBindTexImageEXT = (PFNGLXBINDTEXIMAGEEXTPROC)glXGetProcAddress((unsigned char *)"glXBindTexImageEXT");
695 compositor->glXReleaseTexImageEXT = (PFNGLXRELEASETEXIMAGEEXTPROC)glXGetProcAddress((unsigned char *)"glXReleaseTexImageEXT");
697 compositor->nscreens = ScreenCount(compositor->display);
698 compositor->screens = (CompositedScreen *)malloc(compositor->nscreens*sizeof(CompositedScreen));
699 for(i=0; i<compositor->nscreens; ++i)
700 if(!initialize_screen(compositor, i))
703 compositor->dirty = 1;
708 void shutdown_screen(Compositor *compositor, CompositedScreen *screen)
712 use_gl(compositor, screen);
714 for(i=0; i<screen->nwindows; ++i)
716 glDeleteTextures(1, &screen->windows[i].texture);
717 if(screen->windows[i].pixmap)
719 glXDestroyPixmap(compositor->display, screen->windows[i].glx_pixmap);
720 XFreePixmap(compositor->display, screen->windows[i].pixmap);
721 XDamageDestroy(compositor->display, screen->windows[i].damage);
725 for(i=0; i<screen->nmonitors; ++i)
726 if(screen->monitors[i].enabled)
728 glDeleteBuffers(1, &screen->monitors[i].vertex_buffer);
729 glDeleteBuffers(1, &screen->monitors[i].index_buffer);
730 glDeleteVertexArrays(1, &screen->monitors[i].vertex_array);
733 glDeleteBuffers(1, &screen->window_vertex_buffer);
734 glDeleteVertexArrays(1, &screen->window_vertex_array);
735 glDeleteFramebuffers(1, &screen->framebuffer);
736 glDeleteTextures(1, &screen->fb_texture);
737 glDeleteProgram(screen->program);
738 glDeleteShader(screen->shaders[0]);
739 glDeleteShader(screen->shaders[1]);
741 glXMakeContextCurrent(compositor->display, 0, 0, NULL);
742 glXDestroyContext(compositor->display, screen->glx_context);
743 glXDestroyWindow(compositor->display, screen->glx_window);
744 XDestroyWindow(compositor->display, screen->render_window);
746 XCompositeReleaseOverlayWindow(compositor->display, screen->overlay);
748 free(screen->windows);
749 free(screen->monitors);
752 void shutdown_compositor(Compositor *compositor)
756 for(i=0; i<compositor->nscreens; ++i)
757 shutdown_screen(compositor, &compositor->screens[i]);
758 free(compositor->screens);
760 XCloseDisplay(compositor->display);
763 void mark_dirty(Compositor *compositor, CompositedScreen *screen)
765 compositor->dirty = 1;
769 void process_create_window_event(Compositor *compositor, XCreateWindowEvent *event)
771 CompositedScreen *screen;
773 if((screen = find_screen_by_root(compositor, event->parent)))
774 add_window(compositor, screen, event->window);
777 void process_destroy_window_event(Compositor *compositor, XDestroyWindowEvent *event)
779 CompositedScreen *screen;
780 CompositedWindow *window;
782 if((screen = find_screen_by_root(compositor, event->event)))
783 if((window = find_window(screen, event->window)))
784 remove_window(compositor, screen, window, 1);
787 void process_map_event(Compositor *compositor, XMapEvent *event)
789 CompositedScreen *screen;
790 CompositedWindow *window;
792 screen = find_screen_by_root(compositor, event->event);
796 window = find_window(screen, event->window);
800 window->map_state = IsViewable;
801 create_window_pixmap(compositor, screen, window);
803 mark_dirty(compositor, screen);
806 void process_unmap_event(Compositor *compositor, XUnmapEvent *event)
808 CompositedScreen *screen;
809 CompositedWindow *window;
811 screen = find_screen_by_root(compositor, event->event);
815 window = find_window(screen, event->window);
817 window->map_state = IsUnviewable;
819 mark_dirty(compositor, screen);
822 void process_reparent_event(Compositor *compositor, XReparentEvent *event)
824 CompositedScreen *screen;
825 CompositedWindow *window;
827 screen = find_screen_by_root(compositor, event->event);
831 if(event->parent==screen->root)
832 window = add_window(compositor, screen, event->window);
835 window = find_window(screen, event->window);
839 remove_window(compositor, screen, window, 0);
842 if(window && window->map_state==IsViewable)
843 mark_dirty(compositor, screen);
846 void process_configure_event(Compositor *compositor, XConfigureEvent *event)
848 CompositedScreen *screen;
849 CompositedWindow *window;
851 screen = find_screen_by_root(compositor, event->event);
855 window = find_window(screen, event->window);
859 window->x = event->x;
860 window->y = event->y;
861 if((unsigned)event->width!=window->width || (unsigned)event->height!=window->height || (unsigned)event->border_width!=window->border)
863 window->width = event->width;
864 window->height = event->height;
865 window->border = event->border_width;
866 create_window_pixmap(compositor, screen, window);
868 reorder_window(screen, window, event->above);
870 if(window->map_state==IsViewable)
871 mark_dirty(compositor, screen);
874 void process_damage_event(Compositor *compositor, XDamageNotifyEvent *event)
876 CompositedScreen *screen;
877 CompositedWindow *window;
879 screen = find_screen_by_window(compositor, event->drawable);
883 window = find_window(screen, event->drawable);
884 if(window->map_state==IsViewable)
885 mark_dirty(compositor, screen);
888 int process_event(Compositor *compositor)
891 if(compositor->dirty)
893 if(!XCheckMaskEvent(compositor->display, -1, &event))
897 XNextEvent(compositor->display, &event);
902 process_create_window_event(compositor, &event.xcreatewindow);
905 process_destroy_window_event(compositor, &event.xdestroywindow);
908 process_map_event(compositor, &event.xmap);
911 process_unmap_event(compositor, &event.xunmap);
914 process_reparent_event(compositor, &event.xreparent);
916 case ConfigureNotify:
917 process_configure_event(compositor, &event.xconfigure);
920 if(event.type==compositor->damage_event+XDamageNotify)
921 process_damage_event(compositor, (XDamageNotifyEvent *)&event);
923 printf("Event %d\n", event.type);
929 void refresh_screen(Compositor *compositor, CompositedScreen *screen)
933 use_gl(compositor, screen);
935 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, screen->framebuffer);
937 glClearColor(0.5f, 0.5f, 0.5f, 0.0f);
938 glClear(GL_COLOR_BUFFER_BIT);
940 glUseProgram(screen->program);
941 glBindVertexArray(screen->window_vertex_array);
942 for(i=0; i<screen->nwindows; ++i)
944 CompositedWindow *window = &screen->windows[i];
945 if(window->map_state!=IsViewable)
948 glBindTexture(GL_TEXTURE_2D, window->texture);
949 compositor->glXBindTexImageEXT(compositor->display, window->glx_pixmap, GLX_FRONT_LEFT_EXT, NULL);
950 glUniform4f(screen->geometry_loc,
951 (float)window->x/screen->width, ((float)screen->height-window->y-window->height)/screen->height,
952 (float)(window->width+2*window->border)/screen->width, (float)(window->height+2*window->border)/screen->height);
953 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
954 compositor->glXReleaseTexImageEXT(compositor->display, window->glx_pixmap, GLX_FRONT_LEFT_EXT);
955 XDamageSubtract(compositor->display, window->damage, None, None);
958 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
959 glClearColor(0.5f, 0.0f, 0.5f, 0.0f);
960 glClear(GL_COLOR_BUFFER_BIT);
961 glBindTexture(GL_TEXTURE_2D, screen->fb_texture);
962 glEnable(GL_PRIMITIVE_RESTART);
963 glPrimitiveRestartIndex(0xFFFF);
965 for(i=0; i<screen->nmonitors; ++i)
967 CompositedMonitor *monitor = &screen->monitors[i];
968 if(!monitor->enabled)
971 glUniform4f(screen->geometry_loc,
972 (float)monitor->x/screen->width, (float)monitor->y/screen->height,
973 (float)monitor->width/screen->width, (float)monitor->height/screen->height);
975 glBindVertexArray(monitor->vertex_array);
976 glDrawElements(GL_TRIANGLE_STRIP, monitor->nelements, GL_UNSIGNED_SHORT, NULL);
979 glBindVertexArray(0);
981 glXSwapBuffers(compositor->display, screen->glx_window);
986 void refresh_all_screens(Compositor *compositor)
990 for(i=0; i<compositor->nscreens; ++i)
992 CompositedScreen *screen = &compositor->screens[i];
994 refresh_screen(compositor, screen);
997 compositor->dirty = 0;
1000 void sighandler(int sig)
1002 terminate_requested = 1;
1008 Compositor compositor;
1010 signal(SIGINT, &sighandler);
1011 signal(SIGTERM, &sighandler);
1013 if(!initialize_compositor(&compositor))
1016 while(!terminate_requested)
1018 if(!process_event(&compositor))
1019 refresh_all_screens(&compositor);
1022 shutdown_compositor(&compositor);