]> git.tdb.fi Git - geometrycompositor.git/blob - source/main.c
Move shader program linking to a separate function
[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 <X11/Xlib.h>
7 #include <X11/extensions/Xcomposite.h>
8 #include <X11/extensions/Xdamage.h>
9 #include <X11/extensions/shape.h>
10 #include <GL/gl.h>
11 #include <GL/glx.h>
12
13 typedef struct CompositedWindow
14 {
15         Window window;
16         int x;
17         int y;
18         unsigned width;
19         unsigned height;
20         unsigned border;
21         int map_state;
22         Damage damage;
23         Pixmap pixmap;
24         GLXPixmap glx_pixmap;
25         unsigned texture;
26 } CompositedWindow;
27
28 typedef struct CompositedScreen
29
30         int number;
31         Window root;
32         unsigned width;
33         unsigned height;
34         Window overlay;
35         Window render_window;
36         GLXFBConfig fbconfig;
37         GLXWindow glx_window;
38         GLXContext glx_context;
39         unsigned shaders[2];
40         unsigned program;
41         unsigned geometry_loc;
42         unsigned vertex_buffer;
43         unsigned vertex_array;
44         CompositedWindow *windows;
45         unsigned nwindows;
46         unsigned windows_capacity;
47         int dirty;
48 } CompositedScreen;
49
50 typedef struct Compositor
51 {
52         Display *display;
53         CompositedScreen *screens;
54         unsigned nscreens;
55         int damage_event;
56         PFNGLXCREATECONTEXTATTRIBSARBPROC glXCreateContextAttribsARB;
57         PFNGLXBINDTEXIMAGEEXTPROC glXBindTexImageEXT;
58         PFNGLXRELEASETEXIMAGEEXTPROC glXReleaseTexImageEXT;
59         int dirty;
60 } Compositor;
61
62 static const char *vshader =
63         "#version 150\n"
64         "uniform vec4 geometry;\n"
65         "in vec2 vertex;\n"
66         "out vec2 texcoord;\n"
67         "void main()\n"
68         "{\n"
69         "  gl_Position = vec4((geometry.xy+vertex*geometry.zw)*2.0-1.0, 0.0, 1.0);\n"
70         "  texcoord = vec2(vertex.x, 1.0-vertex.y);\n"
71         "}\n";
72
73 static const char *fshader =
74         "#version 150\n"
75         "uniform sampler2D window;\n"
76         "in vec2 texcoord;\n"
77         "out vec4 frag_color;\n"
78         "void main()\n"
79         "{\n"
80         "       frag_color = texture(window, texcoord);\n"
81         "}\n";
82
83 static const float vertices[] =
84 {
85         0.0f, 1.0f,
86         0.0f, 0.0f,
87         1.0f, 1.0f,
88         1.0f, 0.0f
89 };
90
91 int terminate_requested = 0;
92
93 int x_error_handler(Display *display, XErrorEvent *event)
94 {
95         printf("Ignoring X error %d on resource %lx\n", event->error_code, event->resourceid);
96         (void)display;
97         return 0;
98 }
99
100 int with_error(const char *message)
101 {
102         fprintf(stderr, "%s\n", message);
103         return 0;
104 }
105
106 int initialize_gl(Compositor *compositor, CompositedScreen *screen)
107 {
108         int attribs[9];
109         unsigned i;
110         GLXFBConfig *configs;
111         int nconfigs;
112         XVisualInfo *vi;
113         XSetWindowAttributes win_attr;
114
115         i = 0;
116         attribs[i++] = GLX_DRAWABLE_TYPE;
117         attribs[i++] = GLX_WINDOW_BIT;
118         attribs[i++] = GLX_RENDER_TYPE;
119         attribs[i++] = GLX_RGBA_BIT;
120         attribs[i++] = GLX_DOUBLEBUFFER;
121         attribs[i++] = True;
122         attribs[i++] = GLX_BIND_TO_TEXTURE_RGBA_EXT;
123         attribs[i++] = True;
124         attribs[i] = None;
125
126         configs = glXChooseFBConfig(compositor->display, screen->number, attribs, &nconfigs);
127         if(!configs || !nconfigs)
128                 return with_error("Could not find a suitable FBConfig");
129         screen->fbconfig = configs[0];
130         XFree(configs);
131
132         vi = glXGetVisualFromFBConfig(compositor->display, screen->fbconfig);
133         win_attr.colormap = XCreateColormap(compositor->display, screen->root, vi->visual, AllocNone);
134         screen->render_window = XCreateWindow(compositor->display, screen->overlay, 0, 0, screen->width, screen->height, 0, vi->depth, InputOutput, vi->visual, CWColormap, &win_attr);
135         XMapWindow(compositor->display, screen->render_window);
136
137         screen->glx_window = glXCreateWindow(compositor->display, screen->fbconfig, screen->render_window, NULL);
138
139         i = 0;
140         attribs[i++] = GLX_CONTEXT_FLAGS_ARB;
141         attribs[i++] = GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB;
142         attribs[i++] = GLX_CONTEXT_MAJOR_VERSION_ARB;
143         attribs[i++] = 3;
144         attribs[i++] = GLX_CONTEXT_MINOR_VERSION_ARB;
145         attribs[i++] = 0;
146         attribs[i] = None;
147
148         screen->glx_context = compositor->glXCreateContextAttribsARB(compositor->display, screen->fbconfig, NULL, True, attribs);
149
150         XFree(vi);
151
152         return 1;
153 }
154
155 void use_gl(Compositor *compositor, CompositedScreen *screen)
156 {
157         glXMakeContextCurrent(compositor->display, screen->glx_window, screen->glx_window, screen->glx_context);
158 }
159
160 unsigned compile_shader(GLenum type, const char *source)
161 {
162         unsigned shader;
163         int status;
164         char info_log[1024];
165         GLsizei length;
166         
167         shader = glCreateShader(type);
168         glShaderSource(shader, 1, &source, NULL);
169         glCompileShader(shader);
170         glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
171         glGetShaderInfoLog(shader, sizeof(info_log), &length, info_log);
172         if(!status)
173         {
174                 fprintf(stderr, "Shader compilation failed:\n%s\n", info_log);
175                 glDeleteShader(shader);
176                 return 0;
177         }
178         else if(length)
179                 printf("Shader info log:\n%s\n", info_log);
180
181         return shader;
182 }
183
184 unsigned link_program(unsigned *shaders, unsigned nshaders)
185 {
186         unsigned program;
187         unsigned i;
188         int status;
189         char info_log[1024];
190         GLsizei length;
191
192         program = glCreateProgram();
193         for(i=0; i<nshaders; ++i)
194                 glAttachShader(program, shaders[i]);
195         glBindAttribLocation(program, 0, "vertex");
196         glLinkProgram(program);
197
198         glGetProgramiv(program, GL_LINK_STATUS, &status);
199         glGetProgramInfoLog(program, sizeof(info_log), &length, info_log);
200         if(!status)
201         {
202                 fprintf(stderr, "Program link failed:\n%s\n", info_log);
203                 glDeleteProgram(program);
204                 return 0;
205         }
206         else if(length)
207                 printf("Program info log:\n%s\n", info_log);
208
209         return program;
210 }
211
212 int create_gl_resources(Compositor *compositor, CompositedScreen *screen)
213 {
214         use_gl(compositor, screen);
215
216         screen->shaders[0] = compile_shader(GL_VERTEX_SHADER, vshader);
217         screen->shaders[1] = compile_shader(GL_FRAGMENT_SHADER, fshader);
218         if(!screen->shaders[0] || !screen->shaders[1])
219                 return 0;
220
221         screen->program = link_program(screen->shaders, 2);
222         if(!screen->program)
223                 return 0;
224
225         screen->geometry_loc = glGetUniformLocation(screen->program, "geometry");
226
227         glGenBuffers(1, &screen->vertex_buffer);
228         glBindBuffer(GL_ARRAY_BUFFER, screen->vertex_buffer);
229         glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
230
231         glGenVertexArrays(1, &screen->vertex_array);
232         glBindVertexArray(screen->vertex_array);
233         glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, NULL);
234         glEnableVertexAttribArray(0);
235
236         glBindBuffer(GL_ARRAY_BUFFER, 0);
237
238         return 1;
239 }
240
241 CompositedWindow *find_window(CompositedScreen *screen, Window w)
242 {
243         unsigned i;
244
245         for(i=0; i<screen->nwindows; ++i)
246                 if(screen->windows[i].window==w)
247                         return &screen->windows[i];
248
249         return NULL;
250 }
251
252 void create_window_pixmap(Compositor *compositor, CompositedScreen *screen, CompositedWindow *window)
253 {
254         int attribs[5];
255         unsigned i;
256
257         if(window->pixmap)
258         {
259                 glXDestroyPixmap(compositor->display, window->glx_pixmap);
260                 XFreePixmap(compositor->display, window->pixmap);
261         }
262
263         i = 0;
264         attribs[i++] = GLX_TEXTURE_TARGET_EXT;
265         attribs[i++] = GLX_TEXTURE_2D_EXT;
266         attribs[i++] = GLX_TEXTURE_FORMAT_EXT;
267         attribs[i++] = GLX_TEXTURE_FORMAT_RGBA_EXT;
268         attribs[i++] = None;
269
270         window->pixmap = XCompositeNameWindowPixmap(compositor->display, window->window);
271         window->glx_pixmap = glXCreatePixmap(compositor->display, screen->fbconfig, window->pixmap, attribs);
272 }
273
274 CompositedWindow *add_window(Compositor *compositor, CompositedScreen *screen, Window w)
275 {
276         CompositedWindow *window;
277         XWindowAttributes win_attr;
278
279         if(w==screen->root || w==screen->overlay)
280                 return NULL;
281
282         if(!XGetWindowAttributes(compositor->display, w, &win_attr))
283         {
284                 printf("XGetWindowAttributes failed; probably the window was already destroyed\n");
285                 return NULL;
286         }
287         if(win_attr.class==InputOnly)
288                 return NULL;
289
290         if(find_window(screen, w))
291                 return NULL;
292
293         if(screen->nwindows==screen->windows_capacity)
294         {
295                 screen->windows = (CompositedWindow *)realloc(screen->windows, (screen->windows_capacity+1)*sizeof(CompositedWindow));
296                 ++screen->windows_capacity;
297         }
298
299         window = &screen->windows[screen->nwindows++];
300
301         window->window = w;
302         window->x = win_attr.x;
303         window->y = win_attr.y;
304         window->width = win_attr.width;
305         window->height = win_attr.height;
306         window->border = win_attr.border_width;
307         window->map_state = win_attr.map_state;
308
309         window->damage = XDamageCreate(compositor->display, window->window, XDamageReportNonEmpty);
310         window->pixmap = None;
311         window->glx_pixmap = None;
312
313         XCompositeRedirectWindow(compositor->display, window->window, CompositeRedirectManual);
314         if(window->map_state==IsViewable)
315                 create_window_pixmap(compositor, screen, window);
316
317         glGenTextures(1, &window->texture);
318         glBindTexture(GL_TEXTURE_2D, window->texture);
319         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
320         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
321         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
322
323         return window;
324 }
325
326 void remove_window(Compositor *compositor, CompositedScreen *screen, CompositedWindow *window, int destroyed)
327 {
328         unsigned i;
329
330         glDeleteTextures(1, &window->texture);
331         if(!destroyed)
332         {
333                 XDamageDestroy(compositor->display, window->damage);
334                 if(window->pixmap)
335                 {
336                         glXDestroyPixmap(compositor->display, window->glx_pixmap);
337                         XFreePixmap(compositor->display, window->pixmap);
338                 }
339                 XCompositeUnredirectWindow(compositor->display, window->window, CompositeRedirectManual);
340         }
341
342         --screen->nwindows;
343         for(i=window-screen->windows; i<screen->nwindows; ++i)
344                 screen->windows[i] = screen->windows[i+1];
345 }
346
347 CompositedWindow *reorder_window(CompositedScreen *screen, CompositedWindow *window, Window above)
348 {
349         unsigned i, j;
350         CompositedWindow hold;
351
352         i = window-screen->windows;
353         if(above)
354         {
355                 for(j=0; j<screen->nwindows; ++j)
356                         if(screen->windows[j].window==above)
357                                 break;
358
359                 if(j>=screen->nwindows || i==j+1)
360                         return window;
361
362                 if(j<i)
363                         ++j;
364         }
365         else
366                 j = 0;
367
368         hold = *window;
369         if(i<j)
370         {
371                 for(; i<j; ++i)
372                         screen->windows[i] = screen->windows[i+1];
373         }
374         else
375         {
376                 for(; i>j; --i)
377                         screen->windows[i] = screen->windows[i-1];
378         }
379         screen->windows[j] = hold;
380
381         return &screen->windows[j];
382 }
383
384 CompositedScreen *find_screen_by_root(Compositor *compositor, Window root)
385 {
386         unsigned i;
387
388         for(i=0; i<compositor->nscreens; ++i)
389                 if(compositor->screens[i].root==root)
390                         return &compositor->screens[i];
391
392         return NULL;
393 }
394
395 CompositedScreen *find_screen_by_window(Compositor *compositor, Window w)
396 {
397         unsigned i, j;
398
399         for(i=0; i<compositor->nscreens; ++i)
400                 for(j=0; j<compositor->screens[i].nwindows; ++j)
401                         if(compositor->screens[i].windows[j].window==w)
402                                 return &compositor->screens[i];
403
404         return NULL;
405 }
406
407 int initialize_screen(Compositor *compositor, unsigned number)
408 {
409         CompositedScreen *screen;
410         const char *extensions;
411         Window dummy_root;
412         int x, y;
413         unsigned border;
414         unsigned depth;
415         Window dummy_parent;
416         Window *children;
417         unsigned nchildren;
418         unsigned i;
419
420         screen = &compositor->screens[number];
421         screen->number = number;
422
423         extensions = glXQueryExtensionsString(compositor->display, screen->number);
424         if(!strstr(extensions, "GLX_ARB_create_context"))
425                 return with_error("GLX_ARB_create_context is required");
426         if(!strstr(extensions, "GLX_EXT_texture_from_pixmap"))
427                 return with_error("GLX_EXT_texture_from_pixmap is required");
428
429         screen->root = RootWindow(compositor->display, screen->number);
430         XSelectInput(compositor->display, screen->root, SubstructureNotifyMask);
431         screen->overlay = XCompositeGetOverlayWindow(compositor->display, screen->root);
432         XGetGeometry(compositor->display, screen->overlay, &dummy_root, &x, &y, &screen->width, &screen->height, &border, &depth);
433         XShapeCombineRectangles(compositor->display, screen->overlay, ShapeInput, 0, 0, NULL, 0, ShapeSet, Unsorted);
434
435         if(!initialize_gl(compositor, screen))
436                 return 0;
437
438         if(!create_gl_resources(compositor, screen))
439                 return 0;
440
441         XQueryTree(compositor->display, screen->root, &dummy_root, &dummy_parent, &children, &nchildren);
442
443         screen->windows = (CompositedWindow *)malloc(nchildren*sizeof(CompositedWindow));
444         screen->nwindows = 0;
445         screen->windows_capacity = nchildren;
446
447         for(i=0; i<nchildren; ++i)
448                 add_window(compositor, screen, children[i]);
449
450         XFree(children);
451
452         screen->dirty = 1;
453
454         return 1;
455 }
456
457 int initialize_compositor(Compositor *compositor)
458 {
459         int event_base;
460         int error_base;
461         int major_ver;
462         int minor_ver;
463         unsigned i;
464
465         compositor->display = XOpenDisplay(NULL);
466         if(!compositor->display)
467                 return with_error("Could not open X display");
468
469         XSetErrorHandler(&x_error_handler);
470
471         if(!XCompositeQueryExtension(compositor->display, &event_base, &error_base))
472                 return with_error("XComposite is required but was not found");
473         else if(!XCompositeQueryVersion(compositor->display, &major_ver, &minor_ver))
474                 return with_error("Cannot determine XComposite version");
475         else if(major_ver==0 && minor_ver<3)
476                 return with_error("XComposite 0.3 or later is required");
477
478         if(!glXQueryExtension(compositor->display, &event_base, &error_base))
479                 return with_error("GLX is required but was not found");
480         else if(!glXQueryVersion(compositor->display, &major_ver, &minor_ver))
481                 return with_error("Cannot determine GLX version");
482         else if(major_ver<1 || (major_ver==1 && minor_ver<4))
483                 return with_error("GLX 1.4 or later is required");
484
485         if(!XDamageQueryExtension(compositor->display, &compositor->damage_event, &error_base))
486                 return with_error("XDamage is required but was not found");
487         else if(!XDamageQueryVersion(compositor->display, &major_ver, &minor_ver))
488                 return with_error("Cannot determine XDamage version");
489         else if(major_ver<1)
490                 return with_error("XDamage 1.0 or later is required");
491
492         if(!XShapeQueryExtension(compositor->display, &event_base, &error_base))
493                 return with_error("XShape is required but was not found");
494         else if(!XShapeQueryVersion(compositor->display, &major_ver, &minor_ver))
495                 return with_error("Cannot determine XShape version");
496         else if(major_ver<1 || (major_ver==1 && minor_ver<1))
497                 return with_error("XShape 1.1 or later is required");
498
499         compositor->glXCreateContextAttribsARB = (PFNGLXCREATECONTEXTATTRIBSARBPROC)glXGetProcAddress((unsigned char *)"glXCreateContextAttribsARB");
500         compositor->glXBindTexImageEXT = (PFNGLXBINDTEXIMAGEEXTPROC)glXGetProcAddress((unsigned char *)"glXBindTexImageEXT");
501         compositor->glXReleaseTexImageEXT = (PFNGLXRELEASETEXIMAGEEXTPROC)glXGetProcAddress((unsigned char *)"glXReleaseTexImageEXT");
502
503         compositor->nscreens = ScreenCount(compositor->display);
504         compositor->screens = (CompositedScreen *)malloc(compositor->nscreens*sizeof(CompositedScreen));
505         for(i=0; i<compositor->nscreens; ++i)
506                 if(!initialize_screen(compositor, i))
507                         return 0;
508
509         compositor->dirty = 1;
510
511         return 1;
512 }
513
514 void shutdown_screen(Compositor *compositor, CompositedScreen *screen)
515 {
516         unsigned i;
517
518         use_gl(compositor, screen);
519
520         for(i=0; i<screen->nwindows; ++i)
521         {
522                 glDeleteTextures(1, &screen->windows[i].texture);
523                 if(screen->windows[i].pixmap)
524                 {
525                         glXDestroyPixmap(compositor->display, screen->windows[i].glx_pixmap);
526                         XFreePixmap(compositor->display, screen->windows[i].pixmap);
527                         XDamageDestroy(compositor->display, screen->windows[i].damage);
528                 }
529         }
530
531         glXMakeContextCurrent(compositor->display, 0, 0, NULL);
532         glXDestroyContext(compositor->display, screen->glx_context);
533         glXDestroyWindow(compositor->display, screen->glx_window);
534         XDestroyWindow(compositor->display, screen->render_window);
535
536         XCompositeReleaseOverlayWindow(compositor->display, screen->overlay);
537
538         free(screen->windows);
539 }
540
541 void shutdown_compositor(Compositor *compositor)
542 {
543         unsigned i;
544
545         for(i=0; i<compositor->nscreens; ++i)
546                 shutdown_screen(compositor, &compositor->screens[i]);
547         free(compositor->screens);
548
549         XCloseDisplay(compositor->display);
550 }
551
552 void mark_dirty(Compositor *compositor, CompositedScreen *screen)
553 {
554         compositor->dirty = 1;
555         screen->dirty = 1;
556 }
557
558 void process_create_window_event(Compositor *compositor, XCreateWindowEvent *event)
559 {
560         CompositedScreen *screen = find_screen_by_root(compositor, event->parent);
561         if(!screen)
562                 return;
563
564         add_window(compositor, screen, event->window);
565 }
566
567 void process_destroy_window_event(Compositor *compositor, XDestroyWindowEvent *event)
568 {
569         CompositedScreen *screen;
570         CompositedWindow *window;
571
572         screen = find_screen_by_root(compositor, event->event);
573         if(!screen)
574                 return;
575
576         window = find_window(screen, event->window);
577         if(window)
578                 remove_window(compositor, screen, window, 1);
579 }
580
581 void process_map_event(Compositor *compositor, XMapEvent *event)
582 {
583         CompositedScreen *screen;
584         CompositedWindow *window;
585
586         screen = find_screen_by_root(compositor, event->event);
587         if(!screen)
588                 return;
589
590         window = find_window(screen, event->window);
591         if(!window)
592                 return;
593
594         window->map_state = IsViewable;
595         create_window_pixmap(compositor, screen, window);
596
597         mark_dirty(compositor, screen);
598 }
599
600 void process_unmap_event(Compositor *compositor, XUnmapEvent *event)
601 {
602         CompositedScreen *screen;
603         CompositedWindow *window;
604
605         screen = find_screen_by_root(compositor, event->event);
606         if(!screen)
607                 return;
608
609         window = find_window(screen, event->window);
610         if(window)
611                 window->map_state = IsUnviewable;
612
613         mark_dirty(compositor, screen);
614 }
615
616 void process_reparent_event(Compositor *compositor, XReparentEvent *event)
617 {
618         CompositedScreen *screen;
619         CompositedWindow *window;
620
621         screen = find_screen_by_root(compositor, event->event);
622         if(!screen)
623                 return;
624
625         if(event->parent==screen->root)
626                 window = add_window(compositor, screen, event->window);
627         else
628         {
629                 window = find_window(screen, event->window);
630                 if(!window)
631                         return;
632
633                 remove_window(compositor, screen, window, 0);
634         }
635
636         if(window && window->map_state==IsViewable)
637                 mark_dirty(compositor, screen);
638 }
639
640 void process_configure_event(Compositor *compositor, XConfigureEvent *event)
641 {
642         CompositedScreen *screen;
643         CompositedWindow *window;
644
645         screen = find_screen_by_root(compositor, event->event);
646         if(!screen)
647                 return;
648
649         window = find_window(screen, event->window);
650         if(!window)
651                 return;
652
653         window->x = event->x;
654         window->y = event->y;
655         if((unsigned)event->width!=window->width || (unsigned)event->height!=window->height || (unsigned)event->border_width!=window->border)
656         {
657                 window->width = event->width;
658                 window->height = event->height;
659                 window->border = event->border_width;
660                 create_window_pixmap(compositor, screen, window);
661         }
662         reorder_window(screen, window, event->above);
663
664         if(window->map_state==IsViewable)
665                 mark_dirty(compositor, screen);
666 }
667
668 void process_damage_event(Compositor *compositor, XDamageNotifyEvent *event)
669 {
670         CompositedScreen *screen;
671         CompositedWindow *window;
672
673         screen = find_screen_by_window(compositor, event->drawable);
674         if(!screen)
675                 return;
676
677         window = find_window(screen, event->drawable);
678         if(window->map_state==IsViewable)
679                 mark_dirty(compositor, screen);
680 }
681
682 int process_event(Compositor *compositor)
683 {
684         XEvent event;
685         if(compositor->dirty)
686         {
687                 if(!XCheckMaskEvent(compositor->display, -1, &event))
688                         return 0;
689         }
690         else
691                 XNextEvent(compositor->display, &event);
692
693         switch(event.type)
694         {
695         case CreateNotify:
696                 process_create_window_event(compositor, &event.xcreatewindow);
697                 break;
698         case DestroyNotify:
699                 process_destroy_window_event(compositor, &event.xdestroywindow);
700                 break;
701         case MapNotify:
702                 process_map_event(compositor, &event.xmap);
703                 break;
704         case UnmapNotify:
705                 process_unmap_event(compositor, &event.xunmap);
706                 break;
707         case ReparentNotify:
708                 process_reparent_event(compositor, &event.xreparent);
709                 break;
710         case ConfigureNotify:
711                 process_configure_event(compositor, &event.xconfigure);
712                 break;
713         default:
714                 if(event.type==compositor->damage_event+XDamageNotify)
715                         process_damage_event(compositor, (XDamageNotifyEvent *)&event);
716                 else
717                         printf("Event %d\n", event.type);
718         }
719
720         return 1;
721 }
722
723 void refresh_screens(Compositor *compositor)
724 {
725         unsigned i, j;
726
727         for(i=0; i<compositor->nscreens; ++i)
728         {
729                 CompositedScreen *screen = &compositor->screens[i];
730                 if(!screen->dirty)
731                         continue;
732
733                 use_gl(compositor, screen);
734
735                 glClearColor(0.5f, 0.5f, 0.5f, 0.0f);
736                 glClear(GL_COLOR_BUFFER_BIT);
737
738                 glUseProgram(screen->program);
739                 glBindVertexArray(screen->vertex_array);
740                 for(j=0; j<screen->nwindows; ++j)
741                 {
742                         CompositedWindow *window = &screen->windows[j];
743                         if(window->map_state==IsViewable)
744                         {
745                                 glBindTexture(GL_TEXTURE_2D, window->texture);
746                                 compositor->glXBindTexImageEXT(compositor->display, window->glx_pixmap, GLX_FRONT_LEFT_EXT, NULL);
747                                 glUniform4f(screen->geometry_loc, (float)window->x/screen->width, (float)(screen->height-window->y-window->height)/screen->height, (float)(window->width+2*window->border)/screen->width, (float)(window->height+2*window->border)/screen->height);
748                                 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
749                                 compositor->glXReleaseTexImageEXT(compositor->display, window->glx_pixmap, GLX_FRONT_LEFT_EXT);
750                                 XDamageSubtract(compositor->display, window->damage, None, None);
751                         }
752                 }
753                 glXSwapBuffers(compositor->display, screen->glx_window);
754
755                 screen->dirty = 0;
756         }
757
758         compositor->dirty = 0;
759 }
760
761 void sighandler(int sig)
762 {
763         terminate_requested = 1;
764         (void)sig;
765 }
766
767 int main()
768 {
769         Compositor compositor;
770
771         signal(SIGINT, &sighandler);
772         signal(SIGTERM, &sighandler);
773
774         if(!initialize_compositor(&compositor))
775                 return 1;
776
777         while(!terminate_requested)
778         {
779                 if(!process_event(&compositor))
780                         refresh_screens(&compositor);
781         }
782
783         shutdown_compositor(&compositor);
784
785         return 0;
786 }