]> git.tdb.fi Git - geometrycompositor.git/blob - source/main.c
cd2f1acb5a085bec2e8d33d30fbd49844382e7cd
[geometrycompositor.git] / source / main.c
1 #define GL_GLEXT_PROTOTYPES
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <string.h>
5 #include <signal.h>
6 #include <math.h>
7 #include <X11/Xlib.h>
8 #include <X11/Xatom.h>
9 #include <X11/extensions/Xcomposite.h>
10 #include <X11/extensions/Xdamage.h>
11 #include <X11/extensions/shape.h>
12 #include <X11/extensions/Xrandr.h>
13 #include <GL/gl.h>
14 #include <GL/glx.h>
15
16 typedef struct CompositedWindow
17 {
18         Window window;
19         int x;
20         int y;
21         unsigned width;
22         unsigned height;
23         unsigned border;
24         int map_state;
25         Damage damage;
26         Pixmap pixmap;
27         GLXPixmap glx_pixmap;
28         int recreate_pixmap;
29         unsigned texture;
30         unsigned mask_texture;
31         int use_mask;
32         int recreate_mask;
33 } CompositedWindow;
34
35 enum
36 {
37         CYLINDRICAL = 1,
38         SPHERICAL
39 };
40
41 typedef struct CompositedMonitor
42 {
43         char *name;
44         int enabled;
45         int x;
46         int y;
47         unsigned width;
48         unsigned height;
49         float keystone_vertical;
50         float curvature_type;
51         float curvature_depth;
52         float vertical_center;
53         float perspective;
54         unsigned vertex_buffer;
55         unsigned index_buffer;
56         unsigned vertex_array;
57         unsigned tessellation;
58         unsigned nelements;
59         short *geometry_data;
60         unsigned geometry_data_size;
61 } CompositedMonitor;
62
63 typedef struct CompositedScreen
64
65         int number;
66         Window root;
67         unsigned width;
68         unsigned height;
69         Window overlay;
70         Window render_window;
71         GLXFBConfig fbconfig;
72         GLXWindow glx_window;
73         GLXContext glx_context;
74         unsigned shaders[3];
75         unsigned program;
76         int geometry_loc;
77         unsigned masked_program;
78         int masked_geometry_loc;
79         unsigned window_vertex_buffer;
80         unsigned window_vertex_array;
81         unsigned framebuffer;
82         unsigned fb_texture;
83         Pixmap root_pixmap;
84         GLXPixmap root_glx_pixmap;
85         unsigned root_texture;
86         CompositedWindow *windows;
87         unsigned nwindows;
88         unsigned windows_capacity;
89         CompositedMonitor *monitors;
90         unsigned nmonitors;
91         int dirty;
92 } CompositedScreen;
93
94 typedef struct Compositor
95 {
96         Display *display;
97         CompositedScreen *screens;
98         unsigned nscreens;
99         int damage_event;
100         int shape_event;
101         PFNGLXCREATECONTEXTATTRIBSARBPROC glXCreateContextAttribsARB;
102         PFNGLXBINDTEXIMAGEEXTPROC glXBindTexImageEXT;
103         PFNGLXRELEASETEXIMAGEEXTPROC glXReleaseTexImageEXT;
104         Atom root_pmap_atom;
105         Atom correction_atom;
106         Atom monitors_atom;
107         Atom geometry_data_atom;
108         Window selection_window;
109         int dirty;
110 } Compositor;
111
112 static const char *vshader_src =
113         "#version 130\n"
114         "uniform vec4 geometry;\n"
115         "in vec2 vertex;\n"
116         "in vec2 texture_coord;\n"
117         "out vec2 texcoord;\n"
118         "void main()\n"
119         "{\n"
120         "  gl_Position = vec4((geometry.xy+vertex*geometry.zw)*2.0-1.0, 0.0, 1.0);\n"
121         "  texcoord = texture_coord;\n"
122         "}\n";
123
124 static const char *fshader_src =
125         "#version 130\n"
126         "uniform sampler2D image;\n"
127         "in vec2 texcoord;\n"
128         "out vec4 frag_color;\n"
129         "void main()\n"
130         "{\n"
131         "  frag_color = texture(image, texcoord);\n"
132         "}\n";
133
134 static const char *masked_fshader_src =
135         "#version 130\n"
136         "uniform sampler2D image;\n"
137         "uniform sampler2D mask;\n"
138         "in vec2 texcoord;\n"
139         "out vec4 frag_color;\n"
140         "void main()\n"
141         "{\n"
142         "  if(texture(mask, texcoord).r==0.0)\n"
143         "    discard;\n"
144         "  frag_color = texture(image, texcoord);\n"
145         "}\n";
146
147 static const float window_vertices[] =
148 {
149         /* vertex    texcoord */
150         0.0f, 1.0f,  0.0f, 0.0f,
151         0.0f, 0.0f,  0.0f, 1.0f,
152         1.0f, 1.0f,  1.0f, 0.0f,
153         1.0f, 0.0f,  1.0f, 1.0f
154 };
155
156 int terminate_requested = 0;
157
158 int x_error_handler(Display *display, XErrorEvent *event)
159 {
160         printf("Ignoring X error %d on resource %lx\n", event->error_code, event->resourceid);
161         (void)display;
162         return 0;
163 }
164
165 int with_error(const char *message)
166 {
167         fprintf(stderr, "%s\n", message);
168         return 0;
169 }
170
171 int initialize_gl(Compositor *compositor, CompositedScreen *screen)
172 {
173         int attribs[9];
174         unsigned i;
175         GLXFBConfig *configs;
176         int nconfigs;
177         XVisualInfo *vi;
178         XSetWindowAttributes win_attr;
179
180         i = 0;
181         attribs[i++] = GLX_DRAWABLE_TYPE;
182         attribs[i++] = GLX_WINDOW_BIT;
183         attribs[i++] = GLX_RENDER_TYPE;
184         attribs[i++] = GLX_RGBA_BIT;
185         attribs[i++] = GLX_DOUBLEBUFFER;
186         attribs[i++] = True;
187         attribs[i++] = GLX_BIND_TO_TEXTURE_RGBA_EXT;
188         attribs[i++] = True;
189         attribs[i] = None;
190
191         configs = glXChooseFBConfig(compositor->display, screen->number, attribs, &nconfigs);
192         if(!configs || !nconfigs)
193                 return with_error("Could not find a suitable FBConfig");
194         screen->fbconfig = configs[0];
195         XFree(configs);
196
197         vi = glXGetVisualFromFBConfig(compositor->display, screen->fbconfig);
198         win_attr.colormap = XCreateColormap(compositor->display, screen->root, vi->visual, AllocNone);
199         screen->render_window = XCreateWindow(compositor->display, screen->overlay, 0, 0, screen->width, screen->height, 0, vi->depth, InputOutput, vi->visual, CWColormap, &win_attr);
200         XMapWindow(compositor->display, screen->render_window);
201
202         screen->glx_window = glXCreateWindow(compositor->display, screen->fbconfig, screen->render_window, NULL);
203
204         i = 0;
205         attribs[i++] = GLX_CONTEXT_FLAGS_ARB;
206         attribs[i++] = GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB;
207         attribs[i++] = GLX_CONTEXT_MAJOR_VERSION_ARB;
208         attribs[i++] = 3;
209         attribs[i++] = GLX_CONTEXT_MINOR_VERSION_ARB;
210         attribs[i++] = 1;
211         attribs[i] = None;
212
213         screen->glx_context = compositor->glXCreateContextAttribsARB(compositor->display, screen->fbconfig, NULL, True, attribs);
214
215         XFree(vi);
216
217         return 1;
218 }
219
220 void use_gl(Compositor *compositor, CompositedScreen *screen)
221 {
222         glXMakeContextCurrent(compositor->display, screen->glx_window, screen->glx_window, screen->glx_context);
223 }
224
225 unsigned compile_shader(GLenum type, const char *source)
226 {
227         unsigned shader;
228         int status;
229         char info_log[1024];
230         GLsizei length;
231         
232         shader = glCreateShader(type);
233         glShaderSource(shader, 1, &source, NULL);
234         glCompileShader(shader);
235         glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
236         glGetShaderInfoLog(shader, sizeof(info_log), &length, info_log);
237         if(!status)
238         {
239                 fprintf(stderr, "Shader compilation failed:\n%s\n", info_log);
240                 glDeleteShader(shader);
241                 return 0;
242         }
243         else if(length)
244                 printf("Shader info log:\n%s\n", info_log);
245
246         return shader;
247 }
248
249 unsigned link_program(unsigned vshader, unsigned fshader)
250 {
251         unsigned program;
252         int status;
253         char info_log[1024];
254         GLsizei length;
255
256         program = glCreateProgram();
257         glAttachShader(program, vshader);
258         glAttachShader(program, fshader);
259         glBindAttribLocation(program, 0, "vertex");
260         glBindAttribLocation(program, 1, "texture_coord");
261         glBindFragDataLocation(program, 0, "frag_color");
262         glLinkProgram(program);
263
264         glGetProgramiv(program, GL_LINK_STATUS, &status);
265         glGetProgramInfoLog(program, sizeof(info_log), &length, info_log);
266         if(!status)
267         {
268                 fprintf(stderr, "Program link failed:\n%s\n", info_log);
269                 glDeleteProgram(program);
270                 return 0;
271         }
272         else if(length)
273                 printf("Program info log:\n%s\n", info_log);
274
275         return program;
276 }
277
278 unsigned create_2d_texture()
279 {
280         unsigned texture;
281         glGenTextures(1, &texture);
282         glBindTexture(GL_TEXTURE_2D, texture);
283         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
284         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
285         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
286         return texture;
287 }
288
289 int create_gl_resources(CompositedScreen *screen)
290 {
291         unsigned stride;
292         int loc;
293
294         screen->shaders[0] = compile_shader(GL_VERTEX_SHADER, vshader_src);
295         screen->shaders[1] = compile_shader(GL_FRAGMENT_SHADER, fshader_src);
296         screen->shaders[2] = compile_shader(GL_FRAGMENT_SHADER, masked_fshader_src);
297         if(!screen->shaders[0] || !screen->shaders[1] || !screen->shaders[2])
298                 return 0;
299
300         screen->program = link_program(screen->shaders[0], screen->shaders[1]);
301         if(!screen->program)
302                 return 0;
303
304         screen->masked_program = link_program(screen->shaders[0], screen->shaders[2]);
305         if(!screen->masked_program)
306                 return 0;
307
308         screen->geometry_loc = glGetUniformLocation(screen->program, "geometry");
309         screen->masked_geometry_loc = glGetUniformLocation(screen->masked_program, "geometry");
310
311         loc = glGetUniformLocation(screen->masked_program, "mask");
312         if(loc>=0)
313         {
314                 glUseProgram(screen->masked_program);
315                 glUniform1i(loc, 1);
316         }
317
318         glGenBuffers(1, &screen->window_vertex_buffer);
319         glBindBuffer(GL_ARRAY_BUFFER, screen->window_vertex_buffer);
320         glBufferData(GL_ARRAY_BUFFER, sizeof(window_vertices), window_vertices, GL_STATIC_DRAW);
321
322         stride = 4*sizeof(float);
323         glGenVertexArrays(1, &screen->window_vertex_array);
324         glBindVertexArray(screen->window_vertex_array);
325         glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, stride, NULL);
326         glEnableVertexAttribArray(0);
327         glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, stride, (void *)(2*sizeof(float)));
328         glEnableVertexAttribArray(1);
329         glBindVertexArray(0);
330
331         glBindBuffer(GL_ARRAY_BUFFER, 0);
332
333         screen->fb_texture = create_2d_texture();
334         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, screen->width, screen->height, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
335         glBindTexture(GL_TEXTURE_2D, 0);
336
337         glGenFramebuffers(1, &screen->framebuffer);
338         glBindFramebuffer(GL_DRAW_FRAMEBUFFER, screen->framebuffer);
339         glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, screen->fb_texture, 0);
340         glDepthMask(GL_FALSE);
341         glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
342
343         screen->root_texture = create_2d_texture();
344
345         return 1;
346 }
347
348 CompositedWindow *find_window(CompositedScreen *screen, Window w)
349 {
350         unsigned i;
351
352         for(i=0; i<screen->nwindows; ++i)
353                 if(screen->windows[i].window==w)
354                         return &screen->windows[i];
355
356         return NULL;
357 }
358
359 CompositedWindow *find_window_global(Compositor *compositor, Window w, CompositedScreen **screen)
360 {
361         unsigned i, j;
362
363         for(i=0; i<compositor->nscreens; ++i)
364                 for(j=0; j<compositor->screens[i].nwindows; ++j)
365                         if(compositor->screens[i].windows[j].window==w)
366                         {
367                                 if(screen)
368                                         *screen = &compositor->screens[i];
369                                 return &compositor->screens[i].windows[j];
370                         }
371
372         if(screen)
373                 *screen = NULL;
374         return NULL;
375 }
376
377 GLXPixmap pixmap_to_glx_pixmap(Compositor *compositor, CompositedScreen *screen, Pixmap pixmap)
378 {
379         int attribs[5];
380         unsigned i;
381
382         i = 0;
383         attribs[i++] = GLX_TEXTURE_TARGET_EXT;
384         attribs[i++] = GLX_TEXTURE_2D_EXT;
385         attribs[i++] = GLX_TEXTURE_FORMAT_EXT;
386         attribs[i++] = GLX_TEXTURE_FORMAT_RGBA_EXT;
387         attribs[i++] = None;
388
389         return glXCreatePixmap(compositor->display, screen->fbconfig, pixmap, attribs);
390 }
391
392 void create_window_pixmap(Compositor *compositor, CompositedScreen *screen, CompositedWindow *window)
393 {
394         if(window->pixmap)
395         {
396                 glXDestroyPixmap(compositor->display, window->glx_pixmap);
397                 XFreePixmap(compositor->display, window->pixmap);
398         }
399
400         window->pixmap = XCompositeNameWindowPixmap(compositor->display, window->window);
401         window->glx_pixmap = pixmap_to_glx_pixmap(compositor, screen, window->pixmap);
402         window->recreate_pixmap = 0;
403 }
404
405 void update_window_mask(Compositor *compositor, CompositedWindow *window)
406 {
407         Bool bounding_shaped;
408         Bool clip_shaped;
409         int xi, yi;
410         XRectangle *rects;
411         int rect_count;
412         int rect_order;
413         unsigned width;
414         unsigned height;
415         unsigned char *data;
416         int i;
417         unsigned y;
418
419         XShapeQueryExtents(compositor->display, window->window, &bounding_shaped, &xi, &yi, &width, &height, &clip_shaped, &xi, &yi, &width, &height);
420         window->use_mask = bounding_shaped;
421         if(!window->use_mask)
422                 return;
423
424         rects = XShapeGetRectangles(compositor->display, window->window, ShapeBounding, &rect_count, &rect_order);
425         if(!rects)
426                 return;
427
428         width = window->width+2*window->border;
429         height = window->height+2*window->border;
430         data = (unsigned char *)malloc(width*height);
431         memset(data, 0, width*height);
432         for(i=0; i<rect_count; ++i)
433         {
434                 rects[i].x += window->border;
435                 rects[i].y += window->border;
436                 if(rects[i].x>=(int)width || rects[i].y>=(int)height)
437                         continue;
438
439                 if(rects[i].x<0)
440                 {
441                         if(-rects[i].x>rects[i].width)
442                                 continue;
443                         rects[i].width += rects[i].x;
444                         rects[i].x = 0;
445                 }
446
447                 if(rects[i].y<0)
448                 {
449                         if(-rects[i].y>rects[i].height)
450                                 continue;
451                         rects[i].height += rects[i].y;
452                         rects[i].y = 0;
453                 }
454
455                 if(rects[i].x+rects[i].width>(int)width)
456                         rects[i].width = width-rects[i].x;
457                 if(rects[i].y+rects[i].height>(int)height)
458                         rects[i].height = height-rects[i].y;
459
460                 for(y=0; y<rects[i].height; ++y)
461                 {
462                         unsigned char *row = data+(rects[i].y+y)*width+rects[i].x;
463                         memset(row, 255, rects[i].width);
464                 }
465         }
466
467         XFree(rects);
468
469         glBindTexture(GL_TEXTURE_2D, window->mask_texture);
470         glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
471         glTexImage2D(GL_TEXTURE_2D, 0, GL_R8, width, height, 0, GL_RED, GL_UNSIGNED_BYTE, data);
472
473         free(data);
474
475         window->recreate_mask = 0;
476 }
477
478 CompositedWindow *add_window(Compositor *compositor, CompositedScreen *screen, Window w)
479 {
480         CompositedWindow *window;
481         XWindowAttributes win_attr;
482
483         if(w==screen->root || w==screen->overlay)
484                 return NULL;
485
486         if(!XGetWindowAttributes(compositor->display, w, &win_attr))
487         {
488                 printf("XGetWindowAttributes failed; probably the window was already destroyed\n");
489                 return NULL;
490         }
491         if(win_attr.class==InputOnly)
492                 return NULL;
493
494         if(find_window(screen, w))
495                 return NULL;
496
497         if(screen->nwindows==screen->windows_capacity)
498         {
499                 screen->windows = (CompositedWindow *)realloc(screen->windows, (screen->windows_capacity+1)*sizeof(CompositedWindow));
500                 ++screen->windows_capacity;
501         }
502
503         window = &screen->windows[screen->nwindows++];
504
505         window->window = w;
506         window->x = win_attr.x;
507         window->y = win_attr.y;
508         window->width = win_attr.width;
509         window->height = win_attr.height;
510         window->border = win_attr.border_width;
511         window->map_state = win_attr.map_state;
512
513         window->damage = XDamageCreate(compositor->display, window->window, XDamageReportNonEmpty);
514         window->pixmap = None;
515         window->glx_pixmap = None;
516
517         XCompositeRedirectWindow(compositor->display, window->window, CompositeRedirectManual);
518         window->recreate_pixmap = (window->map_state==IsViewable);
519
520         window->texture = create_2d_texture();
521         window->mask_texture = create_2d_texture();
522         window->use_mask = 0;
523         window->recreate_mask = (window->map_state==IsViewable);
524
525         XShapeSelectInput(compositor->display, window->window, ShapeNotifyMask);
526
527         return window;
528 }
529
530 void remove_window(Compositor *compositor, CompositedScreen *screen, CompositedWindow *window, int destroyed)
531 {
532         unsigned i;
533
534         glDeleteTextures(1, &window->texture);
535         if(!destroyed)
536         {
537                 XDamageDestroy(compositor->display, window->damage);
538                 if(window->pixmap)
539                 {
540                         glXDestroyPixmap(compositor->display, window->glx_pixmap);
541                         XFreePixmap(compositor->display, window->pixmap);
542                 }
543                 XCompositeUnredirectWindow(compositor->display, window->window, CompositeRedirectManual);
544         }
545
546         --screen->nwindows;
547         for(i=window-screen->windows; i<screen->nwindows; ++i)
548                 screen->windows[i] = screen->windows[i+1];
549 }
550
551 CompositedWindow *reorder_window(CompositedScreen *screen, CompositedWindow *window, Window above)
552 {
553         unsigned i, j;
554         CompositedWindow hold;
555
556         i = window-screen->windows;
557         if(above)
558         {
559                 for(j=0; j<screen->nwindows; ++j)
560                         if(screen->windows[j].window==above)
561                                 break;
562
563                 if(j>=screen->nwindows || i==j+1)
564                         return window;
565
566                 if(j<i)
567                         ++j;
568         }
569         else
570                 j = 0;
571
572         hold = *window;
573         if(i<j)
574         {
575                 for(; i<j; ++i)
576                         screen->windows[i] = screen->windows[i+1];
577         }
578         else
579         {
580                 for(; i>j; --i)
581                         screen->windows[i] = screen->windows[i-1];
582         }
583         screen->windows[j] = hold;
584
585         return &screen->windows[j];
586 }
587
588 CompositedScreen *find_screen_by_root(Compositor *compositor, Window root)
589 {
590         unsigned i;
591
592         for(i=0; i<compositor->nscreens; ++i)
593                 if(compositor->screens[i].root==root)
594                         return &compositor->screens[i];
595
596         return NULL;
597 }
598
599 void update_monitor_vertices(CompositedScreen *screen, CompositedMonitor *monitor)
600 {
601         unsigned t;
602         unsigned data_size;
603         float *vertex_data;
604         unsigned short *index_data;
605         unsigned x, y;
606         unsigned i;
607         float aspect;
608         float curve_radius;
609         float curve_arc;
610         float sin_ksv;
611         float cos_ksv;
612         float distance;
613         float eye[3];
614         float look[3];
615
616         t = monitor->tessellation;
617
618         data_size = (t+1)*(t+1)*4*sizeof(float);
619         vertex_data = (float *)malloc(data_size);
620
621         aspect = (float)monitor->width/monitor->height;
622
623         if(monitor->curvature_depth)
624         {
625                 curve_radius = (monitor->curvature_depth*monitor->curvature_depth+0.25f)/(2.0f*monitor->curvature_depth);
626                 curve_arc = 2.0f*asin(0.5f/curve_radius);
627         }
628
629         sin_ksv = monitor->keystone_vertical/sqrt(1.0f+monitor->keystone_vertical*monitor->keystone_vertical);
630         cos_ksv = sqrt(1.0f-sin_ksv*sin_ksv);
631         distance = monitor->perspective+sin_ksv*((sin_ksv>0)-monitor->vertical_center)/aspect;
632         if(monitor->curvature_depth<0)
633                 distance += -monitor->curvature_depth;
634
635         eye[0] = 0.0f;
636         eye[1] = (monitor->vertical_center-0.5f)/aspect+sin_ksv*distance;
637         eye[2] = cos_ksv*distance;
638
639         look[0] = 0.0f;
640         look[1] = -sin_ksv;
641         look[2] = -cos_ksv;
642
643         for(y=0; y<=t; ++y)
644                 for(x=0; x<=t; ++x)
645                 {
646                         float *v;
647
648                         v = vertex_data+(y*(t+1)+x)*3;
649                         v[0] = (float)x/t-0.5f;
650                         v[1] = ((float)y/t-0.5f)/aspect;
651                         v[2] = 0;
652                         if(monitor->curvature_depth)
653                         {
654                                 if(monitor->curvature_type==CYLINDRICAL)
655                                 {
656                                         v[2] = (1.0f-cos(v[0]*curve_arc))*curve_radius-monitor->curvature_depth;
657                                         v[0] = sin(v[0]*curve_arc)*curve_radius;
658                                 }
659                                 else if(monitor->curvature_type==SPHERICAL)
660                                 {
661                                         float r;
662
663                                         v[0] = tan(v[0]*curve_arc)*curve_radius;
664                                         v[1] = tan(v[1]*curve_arc)*curve_radius;
665                                         r = sqrt(v[0]*v[0]+v[1]*v[1]+curve_radius*curve_radius)/fabs(curve_radius);
666                                         v[0] /= r;
667                                         v[1] /= r;
668                                         v[2] = curve_radius-curve_radius/r-monitor->curvature_depth;
669                                 }
670                         }
671                 }
672
673         monitor->geometry_data[0] = t;
674         for(i=0; i<3; ++i)
675                 monitor->geometry_data[1+i] = eye[i]*4096;
676         for(y=0; y<2; ++y)
677                 for(x=0; x<2; ++x)
678                 {
679                         i = 1+(1+y*2+x)*3;
680                         monitor->geometry_data[i] = ((x-0.5f)*distance/monitor->perspective)*4096;
681                         monitor->geometry_data[i+1] = (eye[1]+look[1]*distance-(y-monitor->vertical_center)*look[2]*distance/monitor->perspective/aspect)*4096;
682                         monitor->geometry_data[i+2] = (eye[2]+look[2]*distance+(y-monitor->vertical_center)*look[1]*distance/monitor->perspective/aspect)*4096;
683                 }
684         for(i=0; i<(t+1)*(t+1)*3; ++i)
685                 monitor->geometry_data[16+i] = vertex_data[i]*4096;
686
687         for(y=t; y<=t; --y)
688                 for(x=t; x<=t; --x)
689                 {
690                         float *v;
691                         float px, py, pz;
692                         float scale;
693
694                         v = vertex_data+(y*(t+1)+x)*3;
695                         px = v[0]-eye[0];
696                         py = (v[0]-eye[0])*look[0] - (v[1]-eye[1])*look[2] + (v[2]-eye[2])*look[1];
697                         pz = (v[0]-eye[0])*look[0] + (v[1]-eye[1])*look[1] + (v[2]-eye[2])*look[2];
698                         scale = monitor->perspective/pz;
699
700                         v = vertex_data+(y*(t+1)+x)*4;
701                         v[0] = px*scale+0.5f;
702                         v[1] = py*aspect*scale+monitor->vertical_center;
703                         v[2] = (monitor->x+(float)x*monitor->width/t)/screen->width;
704                         v[3] = 1.0f-(monitor->y+(1.0f-(float)y/t)*monitor->height)/screen->height;
705                 }
706
707         glBindBuffer(GL_ARRAY_BUFFER, monitor->vertex_buffer);
708         glBufferData(GL_ARRAY_BUFFER, data_size, vertex_data, GL_STATIC_DRAW);
709         glBindBuffer(GL_ARRAY_BUFFER, 0);
710         free(vertex_data);
711
712         monitor->nelements = t*((t+1)*2+1)-1;
713         data_size = monitor->nelements*sizeof(unsigned short);
714         index_data = (unsigned short *)malloc(data_size);
715         i = 0;
716         for(y=0; y<t; ++y)
717         {
718                 if(y>0)
719                         index_data[i++] = 0xFFFF;
720                 for(x=0; x<=t; ++x)
721                 {
722                         index_data[i++] = (y+1)*(t+1)+x;
723                         index_data[i++] = y*(t+1)+x;
724                 }
725         }
726         glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, monitor->index_buffer);
727         glBufferData(GL_ELEMENT_ARRAY_BUFFER, data_size, index_data, GL_STATIC_DRAW);
728         glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
729         free(index_data);
730 }
731
732 int initialize_monitor(Compositor *compositor, CompositedScreen *screen, XRRScreenResources *xrr_res, unsigned index)
733 {
734         CompositedMonitor *monitor;
735         XRROutputInfo *output;
736         int namelen;
737         XRRCrtcInfo *crtc;
738         unsigned buffers[2];
739         unsigned stride;
740
741         monitor = &screen->monitors[index];
742
743         output = XRRGetOutputInfo(compositor->display, xrr_res, xrr_res->outputs[index]);
744         namelen = strlen(output->name);
745         monitor->name = (char *)malloc(namelen+1);
746         strcpy(monitor->name, output->name);
747         monitor->enabled = !!output->crtc;
748         if(!monitor->enabled)
749         {
750                 XRRFreeOutputInfo(output);
751                 monitor->geometry_data = NULL;
752                 return 1;
753         }
754
755         crtc = XRRGetCrtcInfo(compositor->display, xrr_res, output->crtc);
756         monitor->x = crtc->x;
757         monitor->y = crtc->y;
758         monitor->width = crtc->width;
759         monitor->height = crtc->height;
760         XRRFreeCrtcInfo(crtc);
761         XRRFreeOutputInfo(output);
762
763         monitor->keystone_vertical = 0.0f;
764         monitor->curvature_type = CYLINDRICAL;
765         monitor->curvature_depth = 0.0f;
766         monitor->vertical_center = 0.5f;
767         monitor->perspective = 1.0f;
768
769         glGenBuffers(2, buffers);
770         monitor->vertex_buffer = buffers[0];
771         monitor->index_buffer = buffers[1];
772
773         monitor->tessellation = 50;
774         monitor->geometry_data_size = (monitor->tessellation+1)*(monitor->tessellation+1)*3+16;
775         monitor->geometry_data = (short *)malloc(monitor->geometry_data_size*sizeof(short));
776         update_monitor_vertices(screen, monitor);
777         stride = 4*sizeof(float);
778
779         glGenVertexArrays(1, &monitor->vertex_array);
780         glBindVertexArray(monitor->vertex_array);
781         glBindBuffer(GL_ARRAY_BUFFER, monitor->vertex_buffer);
782         glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, stride, NULL);
783         glEnableVertexAttribArray(0);
784         glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, stride, (void *)(2*sizeof(float)));
785         glEnableVertexAttribArray(1);
786         glBindBuffer(GL_ARRAY_BUFFER, 0);
787         glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, monitor->index_buffer);
788         glBindVertexArray(0);
789
790         return 1;
791 }
792
793 CompositedMonitor *find_monitor_by_name(CompositedScreen *screen, char *name)
794 {
795         unsigned i;
796
797         for(i=0; i<screen->nmonitors; ++i)
798                 if(!strcmp(screen->monitors[i].name, name))
799                         return &screen->monitors[i];
800
801         return NULL;
802 }
803
804 CompositedMonitor *find_monitor_by_name_global(Compositor *compositor, char *name, CompositedScreen **screen)
805 {
806         unsigned i, j;
807
808         for(i=0; i<compositor->nscreens; ++i)
809                 for(j=0; j<compositor->screens[i].nmonitors; ++j)
810                         if(!strcmp(compositor->screens[i].monitors[j].name, name))
811                         {
812                                 if(screen)
813                                         *screen = &compositor->screens[i];
814                                 return &compositor->screens[i].monitors[j];
815                         }
816
817         if(screen)
818                 *screen = NULL;
819         return NULL;
820 }
821
822 void update_geometry_correction(Compositor *compositor, CompositedScreen *screen)
823 {
824         Atom prop_type;
825         int prop_format;
826         unsigned long overflow;
827         unsigned long names_length;
828         char *names;
829         unsigned long values_length;
830         short *values;
831         char *name_ptr;
832         unsigned i;
833
834         XGetWindowProperty(compositor->display, screen->root, compositor->monitors_atom, 0, 64, False, XA_STRING,
835                 &prop_type, &prop_format, &names_length, &overflow, (unsigned char **)&names);
836         if(prop_type!=XA_STRING || prop_format!=8)
837                 return;
838
839         XGetWindowProperty(compositor->display, screen->root, compositor->correction_atom, 0, 64, False, XA_INTEGER,
840                 &prop_type, &prop_format, &values_length, &overflow, (unsigned char **)&values);
841         if(prop_type!=XA_INTEGER || prop_format!=16)
842         {
843                 XFree(names);
844                 return;
845         }
846
847         use_gl(compositor, screen);
848
849         name_ptr = names;
850         for(i=0; i*5+4<values_length; ++i)
851         {
852                 CompositedMonitor *monitor;
853
854                 if(name_ptr>=names+names_length)
855                         break;
856
857                 monitor = find_monitor_by_name(screen, name_ptr);
858                 if(monitor)
859                 {
860                         monitor->keystone_vertical = values[i*5]/4096.0f;
861                         monitor->curvature_type = values[i*5+1];
862                         monitor->curvature_depth = values[i*5+2]/4096.0f;
863                         monitor->vertical_center = values[i*5+3]/4096.0f;
864                         monitor->perspective = values[i*5+4]/4096.0f;
865
866                         if(monitor->enabled)
867                                 update_monitor_vertices(screen, monitor);
868                 }
869
870                 name_ptr += strlen(name_ptr)+1;
871         }
872
873         XFree(names);
874         XFree(values);
875 }
876
877 void update_root_pixmap(Compositor *compositor, CompositedScreen *screen)
878 {
879         Atom prop_type;
880         int prop_format;
881         unsigned long overflow;
882         unsigned long length;
883         long *pixmap;
884         Window root;
885         int x, y;
886         unsigned width;
887         unsigned height;
888         unsigned border;
889         unsigned depth;
890
891         use_gl(compositor, screen);
892
893         if(screen->root_glx_pixmap)
894         {
895                 glXDestroyPixmap(compositor->display, screen->root_glx_pixmap);
896                 screen->root_glx_pixmap = None;
897         }
898
899         XGetWindowProperty(compositor->display, screen->root, compositor->root_pmap_atom, 0, 1, False, XA_PIXMAP,
900                 &prop_type, &prop_format, &length, &overflow, (unsigned char **)&pixmap);
901         if(prop_type!=XA_PIXMAP || prop_format!=32)
902         {
903                 screen->root_pixmap = None;
904                 return;
905         }
906
907         screen->root_pixmap = pixmap[0];
908         if(XGetGeometry(compositor->display, screen->root_pixmap, &root, &x, &y, &width, &height, &border, &depth))
909                 screen->root_glx_pixmap = pixmap_to_glx_pixmap(compositor, screen, screen->root_pixmap);
910         else
911                 screen->root_pixmap = None;
912
913         XFree(pixmap);
914 }
915
916 int initialize_screen(Compositor *compositor, unsigned number)
917 {
918         CompositedScreen *screen;
919         const char *extensions;
920         Window dummy_root;
921         int x, y;
922         unsigned border;
923         unsigned depth;
924         XRRScreenResources *xrr_res;
925         Window dummy_parent;
926         Window *children;
927         unsigned nchildren;
928         unsigned i;
929
930         screen = &compositor->screens[number];
931         screen->number = number;
932
933         extensions = glXQueryExtensionsString(compositor->display, screen->number);
934         if(!strstr(extensions, "GLX_ARB_create_context"))
935                 return with_error("GLX_ARB_create_context is required");
936         if(!strstr(extensions, "GLX_EXT_texture_from_pixmap"))
937                 return with_error("GLX_EXT_texture_from_pixmap is required");
938
939         screen->root = RootWindow(compositor->display, screen->number);
940         XSelectInput(compositor->display, screen->root, SubstructureNotifyMask|PropertyChangeMask);
941         screen->overlay = XCompositeGetOverlayWindow(compositor->display, screen->root);
942         XGetGeometry(compositor->display, screen->overlay, &dummy_root, &x, &y, &screen->width, &screen->height, &border, &depth);
943         XShapeCombineRectangles(compositor->display, screen->overlay, ShapeInput, 0, 0, NULL, 0, ShapeSet, Unsorted);
944
945         if(!initialize_gl(compositor, screen))
946                 return 0;
947
948         use_gl(compositor, screen);
949
950         if(!create_gl_resources(screen))
951                 return 0;
952
953         xrr_res = XRRGetScreenResources(compositor->display, screen->root);
954         screen->nmonitors = xrr_res->noutput;
955         screen->monitors = (CompositedMonitor *)malloc(screen->nmonitors*sizeof(CompositedMonitor));
956         for(i=0; i<screen->nmonitors; ++i)
957                 if(!initialize_monitor(compositor, screen, xrr_res, i))
958                         return 0;
959         XRRFreeScreenResources(xrr_res);
960
961         screen->root_pixmap = None;
962         screen->root_glx_pixmap = None;
963
964         update_geometry_correction(compositor, screen);
965         update_root_pixmap(compositor, screen);
966
967         XQueryTree(compositor->display, screen->root, &dummy_root, &dummy_parent, &children, &nchildren);
968
969         screen->windows = (CompositedWindow *)malloc(nchildren*sizeof(CompositedWindow));
970         screen->nwindows = 0;
971         screen->windows_capacity = nchildren;
972
973         for(i=0; i<nchildren; ++i)
974                 add_window(compositor, screen, children[i]);
975
976         XFree(children);
977
978         screen->dirty = 1;
979
980         return 1;
981 }
982
983 int initialize_compositor(Compositor *compositor)
984 {
985         int event_base;
986         int error_base;
987         int major_ver;
988         int minor_ver;
989         unsigned i;
990
991         compositor->display = XOpenDisplay(NULL);
992         if(!compositor->display)
993                 return with_error("Could not open X display");
994
995         XSetErrorHandler(&x_error_handler);
996
997         if(!XCompositeQueryExtension(compositor->display, &event_base, &error_base))
998                 return with_error("XComposite is required but was not found");
999         else if(!XCompositeQueryVersion(compositor->display, &major_ver, &minor_ver))
1000                 return with_error("Cannot determine XComposite version");
1001         else if(major_ver==0 && minor_ver<3)
1002                 return with_error("XComposite 0.3 or later is required");
1003
1004         if(!glXQueryExtension(compositor->display, &event_base, &error_base))
1005                 return with_error("GLX is required but was not found");
1006         else if(!glXQueryVersion(compositor->display, &major_ver, &minor_ver))
1007                 return with_error("Cannot determine GLX version");
1008         else if(major_ver<1 || (major_ver==1 && minor_ver<4))
1009                 return with_error("GLX 1.4 or later is required");
1010
1011         if(!XDamageQueryExtension(compositor->display, &compositor->damage_event, &error_base))
1012                 return with_error("XDamage is required but was not found");
1013         else if(!XDamageQueryVersion(compositor->display, &major_ver, &minor_ver))
1014                 return with_error("Cannot determine XDamage version");
1015         else if(major_ver<1)
1016                 return with_error("XDamage 1.0 or later is required");
1017
1018         if(!XShapeQueryExtension(compositor->display, &compositor->shape_event, &error_base))
1019                 return with_error("XShape is required but was not found");
1020         else if(!XShapeQueryVersion(compositor->display, &major_ver, &minor_ver))
1021                 return with_error("Cannot determine XShape version");
1022         else if(major_ver<1 || (major_ver==1 && minor_ver<1))
1023                 return with_error("XShape 1.1 or later is required");
1024
1025         if(!XRRQueryExtension(compositor->display, &event_base, &error_base))
1026                 return with_error("XRandR is required but was not found");
1027         else if(!XRRQueryVersion(compositor->display, &major_ver, &minor_ver))
1028                 return with_error("Cannot determine XRandR version");
1029         else if(major_ver<1 || (major_ver==1 && minor_ver<2))
1030                 return with_error("XRandR 1.2 or later is required");
1031
1032         compositor->glXCreateContextAttribsARB = (PFNGLXCREATECONTEXTATTRIBSARBPROC)glXGetProcAddress((unsigned char *)"glXCreateContextAttribsARB");
1033         compositor->glXBindTexImageEXT = (PFNGLXBINDTEXIMAGEEXTPROC)glXGetProcAddress((unsigned char *)"glXBindTexImageEXT");
1034         compositor->glXReleaseTexImageEXT = (PFNGLXRELEASETEXIMAGEEXTPROC)glXGetProcAddress((unsigned char *)"glXReleaseTexImageEXT");
1035
1036         compositor->root_pmap_atom = XInternAtom(compositor->display, "_XROOTPMAP_ID", False);
1037         compositor->correction_atom = XInternAtom(compositor->display, "_MSP_GEOMETRY_CORRECTION", False);
1038         compositor->monitors_atom = XInternAtom(compositor->display, "_MSP_GEOMETRY_CORRECTION_MONITORS", False);
1039         compositor->geometry_data_atom = XInternAtom(compositor->display, "_MSP_GEOMETRY_CORRECTION_DATA", False);
1040
1041         compositor->nscreens = ScreenCount(compositor->display);
1042         compositor->screens = (CompositedScreen *)malloc(compositor->nscreens*sizeof(CompositedScreen));
1043         for(i=0; i<compositor->nscreens; ++i)
1044                 if(!initialize_screen(compositor, i))
1045                         return 0;
1046
1047         compositor->selection_window = XCreateWindow(compositor->display, compositor->screens[0].root, 0, 0, 1, 1, 0, CopyFromParent, InputOutput, CopyFromParent, 0, NULL);
1048         XSetSelectionOwner(compositor->display, compositor->geometry_data_atom, compositor->selection_window, CurrentTime);
1049
1050         compositor->dirty = 1;
1051
1052         return 1;
1053 }
1054
1055 void shutdown_screen(Compositor *compositor, CompositedScreen *screen)
1056 {
1057         unsigned i;
1058
1059         use_gl(compositor, screen);
1060
1061         for(i=0; i<screen->nwindows; ++i)
1062         {
1063                 glDeleteTextures(1, &screen->windows[i].texture);
1064                 glDeleteTextures(1, &screen->windows[i].mask_texture);
1065                 if(screen->windows[i].pixmap)
1066                 {
1067                         glXDestroyPixmap(compositor->display, screen->windows[i].glx_pixmap);
1068                         XFreePixmap(compositor->display, screen->windows[i].pixmap);
1069                         XDamageDestroy(compositor->display, screen->windows[i].damage);
1070                 }
1071         }
1072
1073         for(i=0; i<screen->nmonitors; ++i)
1074         {
1075                 free(screen->monitors[i].name);
1076                 if(screen->monitors[i].enabled)
1077                 {
1078                         glDeleteBuffers(1, &screen->monitors[i].vertex_buffer);
1079                         glDeleteBuffers(1, &screen->monitors[i].index_buffer);
1080                         glDeleteVertexArrays(1, &screen->monitors[i].vertex_array);
1081                 }
1082                 if(screen->monitors[i].geometry_data)
1083                         free(screen->monitors[i].geometry_data);
1084         }
1085
1086         glDeleteTextures(1, &screen->root_texture);
1087         glXDestroyPixmap(compositor->display, screen->root_glx_pixmap);
1088
1089         glDeleteBuffers(1, &screen->window_vertex_buffer);
1090         glDeleteVertexArrays(1, &screen->window_vertex_array);
1091         glDeleteFramebuffers(1, &screen->framebuffer);
1092         glDeleteTextures(1, &screen->fb_texture);
1093         glDeleteProgram(screen->program);
1094         glDeleteProgram(screen->masked_program);
1095         for(i=0; i<3; ++i)
1096                 glDeleteShader(screen->shaders[i]);
1097
1098         glXMakeContextCurrent(compositor->display, None, None, NULL);
1099         glXDestroyContext(compositor->display, screen->glx_context);
1100         glXDestroyWindow(compositor->display, screen->glx_window);
1101         XDestroyWindow(compositor->display, screen->render_window);
1102
1103         XCompositeReleaseOverlayWindow(compositor->display, screen->overlay);
1104
1105         free(screen->windows);
1106         free(screen->monitors);
1107 }
1108
1109 void shutdown_compositor(Compositor *compositor)
1110 {
1111         unsigned i;
1112
1113         for(i=0; i<compositor->nscreens; ++i)
1114                 shutdown_screen(compositor, &compositor->screens[i]);
1115         free(compositor->screens);
1116
1117         XDestroyWindow(compositor->display, compositor->selection_window);
1118
1119         XCloseDisplay(compositor->display);
1120 }
1121
1122 void mark_dirty(Compositor *compositor, CompositedScreen *screen)
1123 {
1124         compositor->dirty = 1;
1125         screen->dirty = 1;
1126 }
1127
1128 void process_create_window_event(Compositor *compositor, XCreateWindowEvent *event)
1129 {
1130         CompositedScreen *screen;
1131
1132         if((screen = find_screen_by_root(compositor, event->parent)))
1133                 add_window(compositor, screen, event->window);
1134 }
1135
1136 void process_destroy_window_event(Compositor *compositor, XDestroyWindowEvent *event)
1137 {
1138         CompositedScreen *screen;
1139         CompositedWindow *window;
1140
1141         if((screen = find_screen_by_root(compositor, event->event)))
1142                 if((window = find_window(screen, event->window)))
1143                 {
1144                         use_gl(compositor, screen);
1145                         remove_window(compositor, screen, window, 1);
1146                 }
1147 }
1148
1149 void process_map_event(Compositor *compositor, XMapEvent *event)
1150 {
1151         CompositedScreen *screen;
1152         CompositedWindow *window;
1153
1154         screen = find_screen_by_root(compositor, event->event);
1155         if(!screen)
1156                 return;
1157
1158         window = find_window(screen, event->window);
1159         if(!window)
1160                 return;
1161
1162         window->map_state = IsViewable;
1163         window->recreate_pixmap = 1;
1164         window->recreate_mask = 1;
1165
1166         mark_dirty(compositor, screen);
1167 }
1168
1169 void process_unmap_event(Compositor *compositor, XUnmapEvent *event)
1170 {
1171         CompositedScreen *screen;
1172         CompositedWindow *window;
1173
1174         screen = find_screen_by_root(compositor, event->event);
1175         if(!screen)
1176                 return;
1177
1178         window = find_window(screen, event->window);
1179         if(window)
1180                 window->map_state = IsUnviewable;
1181
1182         mark_dirty(compositor, screen);
1183 }
1184
1185 void process_reparent_event(Compositor *compositor, XReparentEvent *event)
1186 {
1187         CompositedScreen *screen;
1188         CompositedWindow *window;
1189
1190         screen = find_screen_by_root(compositor, event->event);
1191         if(!screen)
1192                 return;
1193
1194         if(event->parent==screen->root)
1195                 window = add_window(compositor, screen, event->window);
1196         else
1197         {
1198                 window = find_window(screen, event->window);
1199                 if(!window)
1200                         return;
1201
1202                 remove_window(compositor, screen, window, 0);
1203         }
1204
1205         if(window && window->map_state==IsViewable)
1206                 mark_dirty(compositor, screen);
1207 }
1208
1209 void process_configure_event(Compositor *compositor, XConfigureEvent *event)
1210 {
1211         CompositedScreen *screen;
1212         CompositedWindow *window;
1213
1214         screen = find_screen_by_root(compositor, event->event);
1215         if(!screen)
1216                 return;
1217
1218         window = find_window(screen, event->window);
1219         if(!window)
1220                 return;
1221
1222         window->x = event->x;
1223         window->y = event->y;
1224         if((unsigned)event->width!=window->width || (unsigned)event->height!=window->height || (unsigned)event->border_width!=window->border)
1225         {
1226                 window->width = event->width;
1227                 window->height = event->height;
1228                 window->border = event->border_width;
1229                 window->recreate_pixmap = 1;
1230         }
1231         reorder_window(screen, window, event->above);
1232
1233         if(window->map_state==IsViewable)
1234                 mark_dirty(compositor, screen);
1235 }
1236
1237 void process_property_event(Compositor *compositor, XPropertyEvent *event)
1238 {
1239         CompositedScreen *screen;
1240
1241         screen = find_screen_by_root(compositor, event->window);
1242         if(!screen)
1243                 return;
1244
1245         if(event->atom==compositor->correction_atom)
1246                 update_geometry_correction(compositor, screen);
1247         else if(event->atom==compositor->root_pmap_atom)
1248                 update_root_pixmap(compositor, screen);
1249 }
1250
1251 void process_selection_request_event(Compositor *compositor, XSelectionRequestEvent *event)
1252 {
1253         Atom prop_type;
1254         int prop_format;
1255         unsigned long overflow;
1256         unsigned long names_length;
1257         XSelectionEvent notify;
1258
1259         if(event->selection==compositor->geometry_data_atom)
1260         {
1261                 char *monitor_name;
1262                 CompositedMonitor *monitor;
1263
1264                 XGetWindowProperty(compositor->display, event->requestor, event->property, 0, 64, False, XA_STRING,
1265                         &prop_type, &prop_format, &names_length, &overflow, (unsigned char **)&monitor_name);
1266                 if(prop_type!=XA_STRING || prop_format!=8)
1267                         return;
1268
1269                 monitor = find_monitor_by_name_global(compositor, monitor_name, NULL);
1270                 if(monitor && monitor->enabled)
1271                         XChangeProperty(compositor->display, event->requestor, event->property, XA_INTEGER, 16, PropModeReplace, (unsigned char *)monitor->geometry_data, monitor->geometry_data_size);
1272
1273                 notify.type = SelectionNotify;
1274                 notify.requestor = event->requestor;
1275                 notify.selection = event->selection;
1276                 notify.target = event->target;
1277                 notify.property = (monitor ? event->property : None);
1278                 notify.time = event->time;
1279                 XSendEvent(compositor->display, event->requestor, False, 0, (XEvent *)&notify);
1280         }
1281 }
1282
1283 void process_damage_event(Compositor *compositor, XDamageNotifyEvent *event)
1284 {
1285         CompositedScreen *screen;
1286         CompositedWindow *window;
1287
1288         window = find_window_global(compositor, event->drawable, &screen);
1289         if(window && window->map_state==IsViewable)
1290                 mark_dirty(compositor, screen);
1291 }
1292
1293 void process_shape_event(Compositor *compositor, XShapeEvent *event)
1294 {
1295         CompositedScreen *screen;
1296         CompositedWindow *window;
1297
1298         if(event->kind!=ShapeBounding)
1299                 return;
1300
1301         window = find_window_global(compositor, event->window, &screen);
1302         if(window && window->map_state==IsViewable)
1303         {
1304                 window->recreate_mask = 1;
1305                 mark_dirty(compositor, screen);
1306         }
1307 }
1308
1309 void process_events(Compositor *compositor)
1310 {
1311         int pending;
1312         XEvent event;
1313
1314         pending = 0;
1315         while((pending || !compositor->dirty) && !terminate_requested)
1316         {
1317                 if(!pending)
1318                         pending = XPending(compositor->display);
1319
1320                 XNextEvent(compositor->display, &event);
1321                 if(pending)
1322                         --pending;
1323
1324                 switch(event.type)
1325                 {
1326                 case CreateNotify:
1327                         process_create_window_event(compositor, &event.xcreatewindow);
1328                         break;
1329                 case DestroyNotify:
1330                         process_destroy_window_event(compositor, &event.xdestroywindow);
1331                         break;
1332                 case MapNotify:
1333                         process_map_event(compositor, &event.xmap);
1334                         break;
1335                 case UnmapNotify:
1336                         process_unmap_event(compositor, &event.xunmap);
1337                         break;
1338                 case ReparentNotify:
1339                         process_reparent_event(compositor, &event.xreparent);
1340                         break;
1341                 case ConfigureNotify:
1342                         process_configure_event(compositor, &event.xconfigure);
1343                         break;
1344                 case PropertyNotify:
1345                         process_property_event(compositor, &event.xproperty);
1346                         break;
1347                 case SelectionRequest:
1348                         process_selection_request_event(compositor, &event.xselectionrequest);
1349                         break;
1350                 default:
1351                         if(event.type==compositor->damage_event+XDamageNotify)
1352                                 process_damage_event(compositor, (XDamageNotifyEvent *)&event);
1353                         else if(event.type==compositor->shape_event+ShapeNotify)
1354                                 process_shape_event(compositor, (XShapeEvent *)&event);
1355                 }
1356         }
1357 }
1358
1359 void refresh_screen(Compositor *compositor, CompositedScreen *screen)
1360 {
1361         unsigned i;
1362         int use_mask;
1363
1364         for(i=0; i<screen->nwindows; ++i)
1365                 if(screen->windows[i].map_state==IsViewable)
1366                         XDamageSubtract(compositor->display, screen->windows[i].damage, None, None);
1367         glXWaitX();
1368
1369         use_gl(compositor, screen);
1370
1371         glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
1372         glBindFramebuffer(GL_DRAW_FRAMEBUFFER, screen->framebuffer);
1373
1374         use_mask = -1;
1375         glBindVertexArray(screen->window_vertex_array);
1376
1377         if(screen->root_pixmap)
1378         {
1379                 use_mask = 0;
1380                 glUseProgram(screen->program);
1381                 glBindTexture(GL_TEXTURE_2D, screen->root_texture);
1382                 compositor->glXBindTexImageEXT(compositor->display, screen->root_glx_pixmap, GLX_FRONT_LEFT_EXT, NULL);
1383                 glUniform4f(screen->geometry_loc, 0.0f, 0.0f, 1.0f, 1.0f);
1384                 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
1385                 compositor->glXReleaseTexImageEXT(compositor->display, screen->root_glx_pixmap, GLX_FRONT_LEFT_EXT);
1386         }
1387         else
1388                 glClear(GL_COLOR_BUFFER_BIT);
1389
1390         for(i=0; i<screen->nwindows; ++i)
1391         {
1392                 CompositedWindow *window;
1393
1394                 window = &screen->windows[i];
1395                 if(window->map_state!=IsViewable)
1396                         continue;
1397
1398                 if(window->use_mask!=use_mask)
1399                 {
1400                         use_mask = window->use_mask;
1401                         glUseProgram(use_mask ? screen->masked_program : screen->program);
1402                 }
1403
1404                 if(window->use_mask)
1405                 {
1406                         glActiveTexture(GL_TEXTURE1);
1407                         glBindTexture(GL_TEXTURE_2D, window->mask_texture);
1408                         glActiveTexture(GL_TEXTURE0);
1409                 }
1410
1411                 if(window->recreate_pixmap)
1412                         create_window_pixmap(compositor, screen, window);
1413                 if(window->recreate_mask)
1414                         update_window_mask(compositor, window);
1415
1416                 glBindTexture(GL_TEXTURE_2D, window->texture);
1417                 compositor->glXBindTexImageEXT(compositor->display, window->glx_pixmap, GLX_FRONT_LEFT_EXT, NULL);
1418                 glUniform4f((use_mask ? screen->masked_geometry_loc : screen->geometry_loc),
1419                         (float)window->x/screen->width, 1.0f-(float)(window->y+window->height)/screen->height,
1420                         (float)(window->width+2*window->border)/screen->width, (float)(window->height+2*window->border)/screen->height);
1421                 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
1422                 compositor->glXReleaseTexImageEXT(compositor->display, window->glx_pixmap, GLX_FRONT_LEFT_EXT);
1423         }
1424
1425         glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
1426         glClear(GL_COLOR_BUFFER_BIT);
1427         glBindTexture(GL_TEXTURE_2D, screen->fb_texture);
1428         glEnable(GL_PRIMITIVE_RESTART);
1429         glPrimitiveRestartIndex(0xFFFF);
1430         if(use_mask)
1431                 glUseProgram(screen->program);
1432
1433         for(i=0; i<screen->nmonitors; ++i)
1434         {
1435                 CompositedMonitor *monitor = &screen->monitors[i];
1436                 if(!monitor->enabled)
1437                         continue;
1438
1439                 glUniform4f(screen->geometry_loc,
1440                         (float)monitor->x/screen->width, 1.0f-(float)(monitor->y+monitor->height)/screen->height,
1441                         (float)monitor->width/screen->width, (float)monitor->height/screen->height);
1442
1443                 glBindVertexArray(monitor->vertex_array);
1444                 glDrawElements(GL_TRIANGLE_STRIP, monitor->nelements, GL_UNSIGNED_SHORT, NULL);
1445         }
1446
1447         glBindVertexArray(0);
1448
1449         glXSwapBuffers(compositor->display, screen->glx_window);
1450
1451         screen->dirty = 0;
1452 }
1453
1454 void refresh_all_screens(Compositor *compositor)
1455 {
1456         unsigned i;
1457
1458         for(i=0; i<compositor->nscreens; ++i)
1459         {
1460                 CompositedScreen *screen = &compositor->screens[i];
1461                 if(screen->dirty)
1462                         refresh_screen(compositor, screen);
1463         }
1464
1465         compositor->dirty = 0;
1466 }
1467
1468 void sighandler(int sig)
1469 {
1470         terminate_requested = 1;
1471         (void)sig;
1472 }
1473
1474 int main()
1475 {
1476         Compositor compositor;
1477
1478         signal(SIGINT, &sighandler);
1479         signal(SIGTERM, &sighandler);
1480
1481         if(!initialize_compositor(&compositor))
1482                 return 1;
1483
1484         while(!terminate_requested)
1485         {
1486                 process_events(&compositor);
1487                 if(compositor.dirty && !terminate_requested)
1488                         refresh_all_screens(&compositor);
1489         }
1490
1491         shutdown_compositor(&compositor);
1492
1493         return 0;
1494 }