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