]> git.tdb.fi Git - geometrycompositor.git/blob - source/main.c
c6f7c3f01e0cbe62d64a1240cd886047b5a554fd
[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
426         width = window->width+2*window->border;
427         height = window->height+2*window->border;
428         data = (unsigned char *)malloc(width*height);
429         memset(data, 0, width*height);
430         for(i=0; i<rect_count; ++i)
431         {
432                 rects[i].x += window->border;
433                 rects[i].y += window->border;
434                 if(rects[i].x>=(int)width || rects[i].y>=(int)height)
435                         continue;
436
437                 if(rects[i].x<0)
438                 {
439                         if(-rects[i].x>rects[i].width)
440                                 continue;
441                         rects[i].width += rects[i].x;
442                         rects[i].x = 0;
443                 }
444
445                 if(rects[i].y<0)
446                 {
447                         if(-rects[i].y>rects[i].height)
448                                 continue;
449                         rects[i].height += rects[i].y;
450                         rects[i].y = 0;
451                 }
452
453                 if(rects[i].x+rects[i].width>(int)width)
454                         rects[i].width = width-rects[i].x;
455                 if(rects[i].y+rects[i].height>(int)height)
456                         rects[i].height = height-rects[i].y;
457
458                 for(y=0; y<rects[i].height; ++y)
459                 {
460                         unsigned char *row = data+(rects[i].y+y)*width+rects[i].x;
461                         memset(row, 255, rects[i].width);
462                 }
463         }
464
465         XFree(rects);
466
467         glBindTexture(GL_TEXTURE_2D, window->mask_texture);
468         glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
469         glTexImage2D(GL_TEXTURE_2D, 0, GL_R8, width, height, 0, GL_RED, GL_UNSIGNED_BYTE, data);
470
471         free(data);
472
473         window->recreate_mask = 0;
474 }
475
476 CompositedWindow *add_window(Compositor *compositor, CompositedScreen *screen, Window w)
477 {
478         CompositedWindow *window;
479         XWindowAttributes win_attr;
480
481         if(w==screen->root || w==screen->overlay)
482                 return NULL;
483
484         if(!XGetWindowAttributes(compositor->display, w, &win_attr))
485         {
486                 printf("XGetWindowAttributes failed; probably the window was already destroyed\n");
487                 return NULL;
488         }
489         if(win_attr.class==InputOnly)
490                 return NULL;
491
492         if(find_window(screen, w))
493                 return NULL;
494
495         if(screen->nwindows==screen->windows_capacity)
496         {
497                 screen->windows = (CompositedWindow *)realloc(screen->windows, (screen->windows_capacity+1)*sizeof(CompositedWindow));
498                 ++screen->windows_capacity;
499         }
500
501         window = &screen->windows[screen->nwindows++];
502
503         window->window = w;
504         window->x = win_attr.x;
505         window->y = win_attr.y;
506         window->width = win_attr.width;
507         window->height = win_attr.height;
508         window->border = win_attr.border_width;
509         window->map_state = win_attr.map_state;
510
511         window->damage = XDamageCreate(compositor->display, window->window, XDamageReportNonEmpty);
512         window->pixmap = None;
513         window->glx_pixmap = None;
514
515         XCompositeRedirectWindow(compositor->display, window->window, CompositeRedirectManual);
516         window->recreate_pixmap = (window->map_state==IsViewable);
517
518         window->texture = create_2d_texture();
519         window->mask_texture = create_2d_texture();
520         window->use_mask = 0;
521         window->recreate_mask = (window->map_state==IsViewable);
522
523         XShapeSelectInput(compositor->display, window->window, ShapeNotifyMask);
524
525         return window;
526 }
527
528 void remove_window(Compositor *compositor, CompositedScreen *screen, CompositedWindow *window, int destroyed)
529 {
530         unsigned i;
531
532         glDeleteTextures(1, &window->texture);
533         if(!destroyed)
534         {
535                 XDamageDestroy(compositor->display, window->damage);
536                 if(window->pixmap)
537                 {
538                         glXDestroyPixmap(compositor->display, window->glx_pixmap);
539                         XFreePixmap(compositor->display, window->pixmap);
540                 }
541                 XCompositeUnredirectWindow(compositor->display, window->window, CompositeRedirectManual);
542         }
543
544         --screen->nwindows;
545         for(i=window-screen->windows; i<screen->nwindows; ++i)
546                 screen->windows[i] = screen->windows[i+1];
547 }
548
549 CompositedWindow *reorder_window(CompositedScreen *screen, CompositedWindow *window, Window above)
550 {
551         unsigned i, j;
552         CompositedWindow hold;
553
554         i = window-screen->windows;
555         if(above)
556         {
557                 for(j=0; j<screen->nwindows; ++j)
558                         if(screen->windows[j].window==above)
559                                 break;
560
561                 if(j>=screen->nwindows || i==j+1)
562                         return window;
563
564                 if(j<i)
565                         ++j;
566         }
567         else
568                 j = 0;
569
570         hold = *window;
571         if(i<j)
572         {
573                 for(; i<j; ++i)
574                         screen->windows[i] = screen->windows[i+1];
575         }
576         else
577         {
578                 for(; i>j; --i)
579                         screen->windows[i] = screen->windows[i-1];
580         }
581         screen->windows[j] = hold;
582
583         return &screen->windows[j];
584 }
585
586 CompositedScreen *find_screen_by_root(Compositor *compositor, Window root)
587 {
588         unsigned i;
589
590         for(i=0; i<compositor->nscreens; ++i)
591                 if(compositor->screens[i].root==root)
592                         return &compositor->screens[i];
593
594         return NULL;
595 }
596
597 void update_monitor_vertices(CompositedScreen *screen, CompositedMonitor *monitor)
598 {
599         unsigned t;
600         unsigned data_size;
601         float *vertex_data;
602         unsigned short *index_data;
603         unsigned x, y;
604         unsigned i;
605         float aspect;
606         float curve_radius;
607         float curve_arc;
608         float sin_ksv;
609         float cos_ksv;
610         float distance;
611         float eye[3];
612         float look[3];
613
614         t = monitor->tessellation;
615
616         data_size = (t+1)*(t+1)*4*sizeof(float);
617         vertex_data = (float *)malloc(data_size);
618
619         aspect = (float)monitor->width/monitor->height;
620
621         if(monitor->curvature_depth)
622         {
623                 curve_radius = (monitor->curvature_depth*monitor->curvature_depth+0.25f)/(2.0f*monitor->curvature_depth);
624                 curve_arc = 2.0f*asin(0.5f/curve_radius);
625         }
626
627         sin_ksv = monitor->keystone_vertical/sqrt(1.0f+monitor->keystone_vertical*monitor->keystone_vertical);
628         cos_ksv = sqrt(1.0f-sin_ksv*sin_ksv);
629         distance = monitor->perspective+sin_ksv*((sin_ksv>0)-monitor->vertical_center)/aspect;
630         if(monitor->curvature_depth<0)
631                 distance += -monitor->curvature_depth;
632
633         eye[0] = 0.0f;
634         eye[1] = (monitor->vertical_center-0.5f)/aspect+sin_ksv*distance;
635         eye[2] = cos_ksv*distance;
636
637         look[0] = 0.0f;
638         look[1] = -sin_ksv;
639         look[2] = -cos_ksv;
640
641         for(y=0; y<=t; ++y)
642                 for(x=0; x<=t; ++x)
643                 {
644                         float *v;
645
646                         v = vertex_data+(y*(t+1)+x)*3;
647                         v[0] = (float)x/t-0.5f;
648                         v[1] = ((float)y/t-0.5f)/aspect;
649                         v[2] = 0;
650                         if(monitor->curvature_depth)
651                         {
652                                 if(monitor->curvature_type==CYLINDRICAL)
653                                 {
654                                         v[2] = (1.0f-cos(v[0]*curve_arc))*curve_radius-monitor->curvature_depth;
655                                         v[0] = sin(v[0]*curve_arc)*curve_radius;
656                                 }
657                                 else if(monitor->curvature_type==SPHERICAL)
658                                 {
659                                         float r;
660
661                                         v[0] = tan(v[0]*curve_arc)*curve_radius;
662                                         v[1] = tan(v[1]*curve_arc)*curve_radius;
663                                         r = sqrt(v[0]*v[0]+v[1]*v[1]+curve_radius*curve_radius)/fabs(curve_radius);
664                                         v[0] /= r;
665                                         v[1] /= r;
666                                         v[2] = curve_radius-curve_radius/r-monitor->curvature_depth;
667                                 }
668                         }
669                 }
670
671         monitor->geometry_data[0] = t;
672         for(i=0; i<3; ++i)
673                 monitor->geometry_data[1+i] = eye[i]*4096;
674         for(y=0; y<2; ++y)
675                 for(x=0; x<2; ++x)
676                 {
677                         i = 1+(1+y*2+x)*3;
678                         monitor->geometry_data[i] = ((x-0.5f)*distance/monitor->perspective)*4096;
679                         monitor->geometry_data[i+1] = (eye[1]+look[1]*distance-(y-monitor->vertical_center)*look[2]*distance/monitor->perspective/aspect)*4096;
680                         monitor->geometry_data[i+2] = (eye[2]+look[2]*distance+(y-monitor->vertical_center)*look[1]*distance/monitor->perspective/aspect)*4096;
681                 }
682         for(i=0; i<(t+1)*(t+1)*3; ++i)
683                 monitor->geometry_data[16+i] = vertex_data[i]*4096;
684
685         for(y=t; y<=t; --y)
686                 for(x=t; x<=t; --x)
687                 {
688                         float *v;
689                         float px, py, pz;
690                         float scale;
691
692                         v = vertex_data+(y*(t+1)+x)*3;
693                         px = v[0]-eye[0];
694                         py = (v[0]-eye[0])*look[0] - (v[1]-eye[1])*look[2] + (v[2]-eye[2])*look[1];
695                         pz = (v[0]-eye[0])*look[0] + (v[1]-eye[1])*look[1] + (v[2]-eye[2])*look[2];
696                         scale = monitor->perspective/pz;
697
698                         v = vertex_data+(y*(t+1)+x)*4;
699                         v[0] = px*scale+0.5f;
700                         v[1] = py*aspect*scale+monitor->vertical_center;
701                         v[2] = (monitor->x+(float)x*monitor->width/t)/screen->width;
702                         v[3] = 1.0f-(monitor->y+(1.0f-(float)y/t)*monitor->height)/screen->height;
703                 }
704
705         glBindBuffer(GL_ARRAY_BUFFER, monitor->vertex_buffer);
706         glBufferData(GL_ARRAY_BUFFER, data_size, vertex_data, GL_STATIC_DRAW);
707         glBindBuffer(GL_ARRAY_BUFFER, 0);
708         free(vertex_data);
709
710         monitor->nelements = t*((t+1)*2+1)-1;
711         data_size = monitor->nelements*sizeof(unsigned short);
712         index_data = (unsigned short *)malloc(data_size);
713         i = 0;
714         for(y=0; y<t; ++y)
715         {
716                 if(y>0)
717                         index_data[i++] = 0xFFFF;
718                 for(x=0; x<=t; ++x)
719                 {
720                         index_data[i++] = (y+1)*(t+1)+x;
721                         index_data[i++] = y*(t+1)+x;
722                 }
723         }
724         glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, monitor->index_buffer);
725         glBufferData(GL_ELEMENT_ARRAY_BUFFER, data_size, index_data, GL_STATIC_DRAW);
726         glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
727         free(index_data);
728 }
729
730 int initialize_monitor(Compositor *compositor, CompositedScreen *screen, XRRScreenResources *xrr_res, unsigned index)
731 {
732         CompositedMonitor *monitor;
733         XRROutputInfo *output;
734         int namelen;
735         XRRCrtcInfo *crtc;
736         unsigned buffers[2];
737         unsigned stride;
738
739         monitor = &screen->monitors[index];
740
741         output = XRRGetOutputInfo(compositor->display, xrr_res, xrr_res->outputs[index]);
742         namelen = strlen(output->name);
743         monitor->name = (char *)malloc(namelen+1);
744         strcpy(monitor->name, output->name);
745         monitor->enabled = !!output->crtc;
746         if(!monitor->enabled)
747         {
748                 XRRFreeOutputInfo(output);
749                 monitor->geometry_data = NULL;
750                 return 1;
751         }
752
753         crtc = XRRGetCrtcInfo(compositor->display, xrr_res, output->crtc);
754         monitor->x = crtc->x;
755         monitor->y = crtc->y;
756         monitor->width = crtc->width;
757         monitor->height = crtc->height;
758         XRRFreeCrtcInfo(crtc);
759         XRRFreeOutputInfo(output);
760
761         monitor->keystone_vertical = 0.0f;
762         monitor->curvature_type = CYLINDRICAL;
763         monitor->curvature_depth = 0.0f;
764         monitor->vertical_center = 0.5f;
765         monitor->perspective = 1.0f;
766
767         glGenBuffers(2, buffers);
768         monitor->vertex_buffer = buffers[0];
769         monitor->index_buffer = buffers[1];
770
771         monitor->tessellation = 50;
772         monitor->geometry_data_size = (monitor->tessellation+1)*(monitor->tessellation+1)*3+16;
773         monitor->geometry_data = (short *)malloc(monitor->geometry_data_size*sizeof(short));
774         update_monitor_vertices(screen, monitor);
775         stride = 4*sizeof(float);
776
777         glGenVertexArrays(1, &monitor->vertex_array);
778         glBindVertexArray(monitor->vertex_array);
779         glBindBuffer(GL_ARRAY_BUFFER, monitor->vertex_buffer);
780         glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, stride, NULL);
781         glEnableVertexAttribArray(0);
782         glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, stride, (void *)(2*sizeof(float)));
783         glEnableVertexAttribArray(1);
784         glBindBuffer(GL_ARRAY_BUFFER, 0);
785         glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, monitor->index_buffer);
786         glBindVertexArray(0);
787
788         return 1;
789 }
790
791 CompositedMonitor *find_monitor_by_name(CompositedScreen *screen, char *name)
792 {
793         unsigned i;
794
795         for(i=0; i<screen->nmonitors; ++i)
796                 if(!strcmp(screen->monitors[i].name, name))
797                         return &screen->monitors[i];
798
799         return NULL;
800 }
801
802 CompositedMonitor *find_monitor_by_name_global(Compositor *compositor, char *name, CompositedScreen **screen)
803 {
804         unsigned i, j;
805
806         for(i=0; i<compositor->nscreens; ++i)
807                 for(j=0; j<compositor->screens[i].nmonitors; ++j)
808                         if(!strcmp(compositor->screens[i].monitors[j].name, name))
809                         {
810                                 if(screen)
811                                         *screen = &compositor->screens[i];
812                                 return &compositor->screens[i].monitors[j];
813                         }
814
815         if(screen)
816                 *screen = NULL;
817         return NULL;
818 }
819
820 void update_geometry_correction(Compositor *compositor, CompositedScreen *screen)
821 {
822         Atom prop_type;
823         int prop_format;
824         unsigned long overflow;
825         unsigned long names_length;
826         char *names;
827         unsigned long values_length;
828         short *values;
829         char *name_ptr;
830         unsigned i;
831
832         XGetWindowProperty(compositor->display, screen->root, compositor->monitors_atom, 0, 64, False, XA_STRING,
833                 &prop_type, &prop_format, &names_length, &overflow, (unsigned char **)&names);
834         if(prop_type!=XA_STRING || prop_format!=8)
835                 return;
836
837         XGetWindowProperty(compositor->display, screen->root, compositor->correction_atom, 0, 64, False, XA_INTEGER,
838                 &prop_type, &prop_format, &values_length, &overflow, (unsigned char **)&values);
839         if(prop_type!=XA_INTEGER || prop_format!=16)
840         {
841                 XFree(names);
842                 return;
843         }
844
845         use_gl(compositor, screen);
846
847         name_ptr = names;
848         for(i=0; i*5+4<values_length; ++i)
849         {
850                 CompositedMonitor *monitor;
851
852                 if(name_ptr>=names+names_length)
853                         break;
854
855                 monitor = find_monitor_by_name(screen, name_ptr);
856                 if(monitor)
857                 {
858                         monitor->keystone_vertical = values[i*5]/4096.0f;
859                         monitor->curvature_type = values[i*5+1];
860                         monitor->curvature_depth = values[i*5+2]/4096.0f;
861                         monitor->vertical_center = values[i*5+3]/4096.0f;
862                         monitor->perspective = values[i*5+4]/4096.0f;
863
864                         if(monitor->enabled)
865                                 update_monitor_vertices(screen, monitor);
866                 }
867
868                 name_ptr += strlen(name_ptr)+1;
869         }
870
871         XFree(names);
872         XFree(values);
873 }
874
875 void update_root_pixmap(Compositor *compositor, CompositedScreen *screen)
876 {
877         Atom prop_type;
878         int prop_format;
879         unsigned long overflow;
880         unsigned long length;
881         long *pixmap;
882         Window root;
883         int x, y;
884         unsigned width;
885         unsigned height;
886         unsigned border;
887         unsigned depth;
888
889         use_gl(compositor, screen);
890
891         if(screen->root_glx_pixmap)
892         {
893                 glXDestroyPixmap(compositor->display, screen->root_glx_pixmap);
894                 screen->root_glx_pixmap = None;
895         }
896
897         XGetWindowProperty(compositor->display, screen->root, compositor->root_pmap_atom, 0, 1, False, XA_PIXMAP,
898                 &prop_type, &prop_format, &length, &overflow, (unsigned char **)&pixmap);
899         if(prop_type!=XA_PIXMAP || prop_format!=32)
900         {
901                 screen->root_pixmap = None;
902                 return;
903         }
904
905         screen->root_pixmap = pixmap[0];
906         if(XGetGeometry(compositor->display, screen->root_pixmap, &root, &x, &y, &width, &height, &border, &depth))
907                 screen->root_glx_pixmap = pixmap_to_glx_pixmap(compositor, screen, screen->root_pixmap);
908         else
909                 screen->root_pixmap = None;
910
911         XFree(pixmap);
912 }
913
914 int initialize_screen(Compositor *compositor, unsigned number)
915 {
916         CompositedScreen *screen;
917         const char *extensions;
918         Window dummy_root;
919         int x, y;
920         unsigned border;
921         unsigned depth;
922         XRRScreenResources *xrr_res;
923         Window dummy_parent;
924         Window *children;
925         unsigned nchildren;
926         unsigned i;
927
928         screen = &compositor->screens[number];
929         screen->number = number;
930
931         extensions = glXQueryExtensionsString(compositor->display, screen->number);
932         if(!strstr(extensions, "GLX_ARB_create_context"))
933                 return with_error("GLX_ARB_create_context is required");
934         if(!strstr(extensions, "GLX_EXT_texture_from_pixmap"))
935                 return with_error("GLX_EXT_texture_from_pixmap is required");
936
937         screen->root = RootWindow(compositor->display, screen->number);
938         XSelectInput(compositor->display, screen->root, SubstructureNotifyMask|PropertyChangeMask);
939         screen->overlay = XCompositeGetOverlayWindow(compositor->display, screen->root);
940         XGetGeometry(compositor->display, screen->overlay, &dummy_root, &x, &y, &screen->width, &screen->height, &border, &depth);
941         XShapeCombineRectangles(compositor->display, screen->overlay, ShapeInput, 0, 0, NULL, 0, ShapeSet, Unsorted);
942
943         if(!initialize_gl(compositor, screen))
944                 return 0;
945
946         use_gl(compositor, screen);
947
948         if(!create_gl_resources(screen))
949                 return 0;
950
951         xrr_res = XRRGetScreenResources(compositor->display, screen->root);
952         screen->nmonitors = xrr_res->noutput;
953         screen->monitors = (CompositedMonitor *)malloc(screen->nmonitors*sizeof(CompositedMonitor));
954         for(i=0; i<screen->nmonitors; ++i)
955                 if(!initialize_monitor(compositor, screen, xrr_res, i))
956                         return 0;
957         XRRFreeScreenResources(xrr_res);
958
959         screen->root_pixmap = None;
960         screen->root_glx_pixmap = None;
961
962         update_geometry_correction(compositor, screen);
963         update_root_pixmap(compositor, screen);
964
965         XQueryTree(compositor->display, screen->root, &dummy_root, &dummy_parent, &children, &nchildren);
966
967         screen->windows = (CompositedWindow *)malloc(nchildren*sizeof(CompositedWindow));
968         screen->nwindows = 0;
969         screen->windows_capacity = nchildren;
970
971         for(i=0; i<nchildren; ++i)
972                 add_window(compositor, screen, children[i]);
973
974         XFree(children);
975
976         screen->dirty = 1;
977
978         return 1;
979 }
980
981 int initialize_compositor(Compositor *compositor)
982 {
983         int event_base;
984         int error_base;
985         int major_ver;
986         int minor_ver;
987         unsigned i;
988
989         compositor->display = XOpenDisplay(NULL);
990         if(!compositor->display)
991                 return with_error("Could not open X display");
992
993         XSetErrorHandler(&x_error_handler);
994
995         if(!XCompositeQueryExtension(compositor->display, &event_base, &error_base))
996                 return with_error("XComposite is required but was not found");
997         else if(!XCompositeQueryVersion(compositor->display, &major_ver, &minor_ver))
998                 return with_error("Cannot determine XComposite version");
999         else if(major_ver==0 && minor_ver<3)
1000                 return with_error("XComposite 0.3 or later is required");
1001
1002         if(!glXQueryExtension(compositor->display, &event_base, &error_base))
1003                 return with_error("GLX is required but was not found");
1004         else if(!glXQueryVersion(compositor->display, &major_ver, &minor_ver))
1005                 return with_error("Cannot determine GLX version");
1006         else if(major_ver<1 || (major_ver==1 && minor_ver<4))
1007                 return with_error("GLX 1.4 or later is required");
1008
1009         if(!XDamageQueryExtension(compositor->display, &compositor->damage_event, &error_base))
1010                 return with_error("XDamage is required but was not found");
1011         else if(!XDamageQueryVersion(compositor->display, &major_ver, &minor_ver))
1012                 return with_error("Cannot determine XDamage version");
1013         else if(major_ver<1)
1014                 return with_error("XDamage 1.0 or later is required");
1015
1016         if(!XShapeQueryExtension(compositor->display, &compositor->shape_event, &error_base))
1017                 return with_error("XShape is required but was not found");
1018         else if(!XShapeQueryVersion(compositor->display, &major_ver, &minor_ver))
1019                 return with_error("Cannot determine XShape version");
1020         else if(major_ver<1 || (major_ver==1 && minor_ver<1))
1021                 return with_error("XShape 1.1 or later is required");
1022
1023         if(!XRRQueryExtension(compositor->display, &event_base, &error_base))
1024                 return with_error("XRandR is required but was not found");
1025         else if(!XRRQueryVersion(compositor->display, &major_ver, &minor_ver))
1026                 return with_error("Cannot determine XRandR version");
1027         else if(major_ver<1 || (major_ver==1 && minor_ver<2))
1028                 return with_error("XRandR 1.2 or later is required");
1029
1030         compositor->glXCreateContextAttribsARB = (PFNGLXCREATECONTEXTATTRIBSARBPROC)glXGetProcAddress((unsigned char *)"glXCreateContextAttribsARB");
1031         compositor->glXBindTexImageEXT = (PFNGLXBINDTEXIMAGEEXTPROC)glXGetProcAddress((unsigned char *)"glXBindTexImageEXT");
1032         compositor->glXReleaseTexImageEXT = (PFNGLXRELEASETEXIMAGEEXTPROC)glXGetProcAddress((unsigned char *)"glXReleaseTexImageEXT");
1033
1034         compositor->root_pmap_atom = XInternAtom(compositor->display, "_XROOTPMAP_ID", False);
1035         compositor->correction_atom = XInternAtom(compositor->display, "_MSP_GEOMETRY_CORRECTION", False);
1036         compositor->monitors_atom = XInternAtom(compositor->display, "_MSP_GEOMETRY_CORRECTION_MONITORS", False);
1037         compositor->geometry_data_atom = XInternAtom(compositor->display, "_MSP_GEOMETRY_CORRECTION_DATA", False);
1038
1039         compositor->nscreens = ScreenCount(compositor->display);
1040         compositor->screens = (CompositedScreen *)malloc(compositor->nscreens*sizeof(CompositedScreen));
1041         for(i=0; i<compositor->nscreens; ++i)
1042                 if(!initialize_screen(compositor, i))
1043                         return 0;
1044
1045         compositor->selection_window = XCreateWindow(compositor->display, compositor->screens[0].root, 0, 0, 1, 1, 0, CopyFromParent, InputOutput, CopyFromParent, 0, NULL);
1046         XSetSelectionOwner(compositor->display, compositor->geometry_data_atom, compositor->selection_window, CurrentTime);
1047
1048         compositor->dirty = 1;
1049
1050         return 1;
1051 }
1052
1053 void shutdown_screen(Compositor *compositor, CompositedScreen *screen)
1054 {
1055         unsigned i;
1056
1057         use_gl(compositor, screen);
1058
1059         for(i=0; i<screen->nwindows; ++i)
1060         {
1061                 glDeleteTextures(1, &screen->windows[i].texture);
1062                 glDeleteTextures(1, &screen->windows[i].mask_texture);
1063                 if(screen->windows[i].pixmap)
1064                 {
1065                         glXDestroyPixmap(compositor->display, screen->windows[i].glx_pixmap);
1066                         XFreePixmap(compositor->display, screen->windows[i].pixmap);
1067                         XDamageDestroy(compositor->display, screen->windows[i].damage);
1068                 }
1069         }
1070
1071         for(i=0; i<screen->nmonitors; ++i)
1072         {
1073                 free(screen->monitors[i].name);
1074                 if(screen->monitors[i].enabled)
1075                 {
1076                         glDeleteBuffers(1, &screen->monitors[i].vertex_buffer);
1077                         glDeleteBuffers(1, &screen->monitors[i].index_buffer);
1078                         glDeleteVertexArrays(1, &screen->monitors[i].vertex_array);
1079                 }
1080                 if(screen->monitors[i].geometry_data)
1081                         free(screen->monitors[i].geometry_data);
1082         }
1083
1084         glDeleteTextures(1, &screen->root_texture);
1085         glXDestroyPixmap(compositor->display, screen->root_glx_pixmap);
1086
1087         glDeleteBuffers(1, &screen->window_vertex_buffer);
1088         glDeleteVertexArrays(1, &screen->window_vertex_array);
1089         glDeleteFramebuffers(1, &screen->framebuffer);
1090         glDeleteTextures(1, &screen->fb_texture);
1091         glDeleteProgram(screen->program);
1092         glDeleteProgram(screen->masked_program);
1093         for(i=0; i<3; ++i)
1094                 glDeleteShader(screen->shaders[i]);
1095
1096         glXMakeContextCurrent(compositor->display, None, None, NULL);
1097         glXDestroyContext(compositor->display, screen->glx_context);
1098         glXDestroyWindow(compositor->display, screen->glx_window);
1099         XDestroyWindow(compositor->display, screen->render_window);
1100
1101         XCompositeReleaseOverlayWindow(compositor->display, screen->overlay);
1102
1103         free(screen->windows);
1104         free(screen->monitors);
1105 }
1106
1107 void shutdown_compositor(Compositor *compositor)
1108 {
1109         unsigned i;
1110
1111         for(i=0; i<compositor->nscreens; ++i)
1112                 shutdown_screen(compositor, &compositor->screens[i]);
1113         free(compositor->screens);
1114
1115         XDestroyWindow(compositor->display, compositor->selection_window);
1116
1117         XCloseDisplay(compositor->display);
1118 }
1119
1120 void mark_dirty(Compositor *compositor, CompositedScreen *screen)
1121 {
1122         compositor->dirty = 1;
1123         screen->dirty = 1;
1124 }
1125
1126 void process_create_window_event(Compositor *compositor, XCreateWindowEvent *event)
1127 {
1128         CompositedScreen *screen;
1129
1130         if((screen = find_screen_by_root(compositor, event->parent)))
1131                 add_window(compositor, screen, event->window);
1132 }
1133
1134 void process_destroy_window_event(Compositor *compositor, XDestroyWindowEvent *event)
1135 {
1136         CompositedScreen *screen;
1137         CompositedWindow *window;
1138
1139         if((screen = find_screen_by_root(compositor, event->event)))
1140                 if((window = find_window(screen, event->window)))
1141                 {
1142                         use_gl(compositor, screen);
1143                         remove_window(compositor, screen, window, 1);
1144                 }
1145 }
1146
1147 void process_map_event(Compositor *compositor, XMapEvent *event)
1148 {
1149         CompositedScreen *screen;
1150         CompositedWindow *window;
1151
1152         screen = find_screen_by_root(compositor, event->event);
1153         if(!screen)
1154                 return;
1155
1156         window = find_window(screen, event->window);
1157         if(!window)
1158                 return;
1159
1160         window->map_state = IsViewable;
1161         window->recreate_pixmap = 1;
1162         window->recreate_mask = 1;
1163
1164         mark_dirty(compositor, screen);
1165 }
1166
1167 void process_unmap_event(Compositor *compositor, XUnmapEvent *event)
1168 {
1169         CompositedScreen *screen;
1170         CompositedWindow *window;
1171
1172         screen = find_screen_by_root(compositor, event->event);
1173         if(!screen)
1174                 return;
1175
1176         window = find_window(screen, event->window);
1177         if(window)
1178                 window->map_state = IsUnviewable;
1179
1180         mark_dirty(compositor, screen);
1181 }
1182
1183 void process_reparent_event(Compositor *compositor, XReparentEvent *event)
1184 {
1185         CompositedScreen *screen;
1186         CompositedWindow *window;
1187
1188         screen = find_screen_by_root(compositor, event->event);
1189         if(!screen)
1190                 return;
1191
1192         if(event->parent==screen->root)
1193                 window = add_window(compositor, screen, event->window);
1194         else
1195         {
1196                 window = find_window(screen, event->window);
1197                 if(!window)
1198                         return;
1199
1200                 remove_window(compositor, screen, window, 0);
1201         }
1202
1203         if(window && window->map_state==IsViewable)
1204                 mark_dirty(compositor, screen);
1205 }
1206
1207 void process_configure_event(Compositor *compositor, XConfigureEvent *event)
1208 {
1209         CompositedScreen *screen;
1210         CompositedWindow *window;
1211
1212         screen = find_screen_by_root(compositor, event->event);
1213         if(!screen)
1214                 return;
1215
1216         window = find_window(screen, event->window);
1217         if(!window)
1218                 return;
1219
1220         window->x = event->x;
1221         window->y = event->y;
1222         if((unsigned)event->width!=window->width || (unsigned)event->height!=window->height || (unsigned)event->border_width!=window->border)
1223         {
1224                 window->width = event->width;
1225                 window->height = event->height;
1226                 window->border = event->border_width;
1227                 window->recreate_pixmap = 1;
1228         }
1229         reorder_window(screen, window, event->above);
1230
1231         if(window->map_state==IsViewable)
1232                 mark_dirty(compositor, screen);
1233 }
1234
1235 void process_property_event(Compositor *compositor, XPropertyEvent *event)
1236 {
1237         CompositedScreen *screen;
1238
1239         screen = find_screen_by_root(compositor, event->window);
1240         if(!screen)
1241                 return;
1242
1243         if(event->atom==compositor->correction_atom)
1244                 update_geometry_correction(compositor, screen);
1245         else if(event->atom==compositor->root_pmap_atom)
1246                 update_root_pixmap(compositor, screen);
1247 }
1248
1249 void process_selection_request_event(Compositor *compositor, XSelectionRequestEvent *event)
1250 {
1251         Atom prop_type;
1252         int prop_format;
1253         unsigned long overflow;
1254         unsigned long names_length;
1255         XSelectionEvent notify;
1256
1257         if(event->selection==compositor->geometry_data_atom)
1258         {
1259                 char *monitor_name;
1260                 CompositedMonitor *monitor;
1261
1262                 XGetWindowProperty(compositor->display, event->requestor, event->property, 0, 64, False, XA_STRING,
1263                         &prop_type, &prop_format, &names_length, &overflow, (unsigned char **)&monitor_name);
1264                 if(prop_type!=XA_STRING || prop_format!=8)
1265                         return;
1266
1267                 monitor = find_monitor_by_name_global(compositor, monitor_name, NULL);
1268                 if(monitor && monitor->enabled)
1269                         XChangeProperty(compositor->display, event->requestor, event->property, XA_INTEGER, 16, PropModeReplace, (unsigned char *)monitor->geometry_data, monitor->geometry_data_size);
1270
1271                 notify.type = SelectionNotify;
1272                 notify.requestor = event->requestor;
1273                 notify.selection = event->selection;
1274                 notify.target = event->target;
1275                 notify.property = (monitor ? event->property : None);
1276                 notify.time = event->time;
1277                 XSendEvent(compositor->display, event->requestor, False, 0, (XEvent *)&notify);
1278         }
1279 }
1280
1281 void process_damage_event(Compositor *compositor, XDamageNotifyEvent *event)
1282 {
1283         CompositedScreen *screen;
1284         CompositedWindow *window;
1285
1286         window = find_window_global(compositor, event->drawable, &screen);
1287         if(window && window->map_state==IsViewable)
1288                 mark_dirty(compositor, screen);
1289 }
1290
1291 void process_shape_event(Compositor *compositor, XShapeEvent *event)
1292 {
1293         CompositedScreen *screen;
1294         CompositedWindow *window;
1295
1296         if(event->kind!=ShapeBounding)
1297                 return;
1298
1299         window = find_window_global(compositor, event->window, &screen);
1300         if(window && window->map_state==IsViewable)
1301         {
1302                 window->recreate_mask = 1;
1303                 mark_dirty(compositor, screen);
1304         }
1305 }
1306
1307 void process_events(Compositor *compositor)
1308 {
1309         int pending;
1310         XEvent event;
1311
1312         pending = 0;
1313         while((pending || !compositor->dirty) && !terminate_requested)
1314         {
1315                 if(!pending)
1316                         pending = XPending(compositor->display);
1317
1318                 XNextEvent(compositor->display, &event);
1319                 if(pending)
1320                         --pending;
1321
1322                 switch(event.type)
1323                 {
1324                 case CreateNotify:
1325                         process_create_window_event(compositor, &event.xcreatewindow);
1326                         break;
1327                 case DestroyNotify:
1328                         process_destroy_window_event(compositor, &event.xdestroywindow);
1329                         break;
1330                 case MapNotify:
1331                         process_map_event(compositor, &event.xmap);
1332                         break;
1333                 case UnmapNotify:
1334                         process_unmap_event(compositor, &event.xunmap);
1335                         break;
1336                 case ReparentNotify:
1337                         process_reparent_event(compositor, &event.xreparent);
1338                         break;
1339                 case ConfigureNotify:
1340                         process_configure_event(compositor, &event.xconfigure);
1341                         break;
1342                 case PropertyNotify:
1343                         process_property_event(compositor, &event.xproperty);
1344                         break;
1345                 case SelectionRequest:
1346                         process_selection_request_event(compositor, &event.xselectionrequest);
1347                         break;
1348                 default:
1349                         if(event.type==compositor->damage_event+XDamageNotify)
1350                                 process_damage_event(compositor, (XDamageNotifyEvent *)&event);
1351                         else if(event.type==compositor->shape_event+ShapeNotify)
1352                                 process_shape_event(compositor, (XShapeEvent *)&event);
1353                         else
1354                                 printf("Event %d\n", event.type);
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 }