split the round trip to fetch a window's region up so that the request can be sent...
[dana/dcompmgr.git] / glxrender.c
1 #include "efence.h"
2
3 #include "render.h"
4 #include "screen.h"
5 #include "window.h"
6 #include "display.h"
7 #include "list.h"
8 #include <stdio.h>
9 #include <string.h>
10 #include <assert.h>
11 #include <stdlib.h>
12
13 #include <GL/gl.h>
14 #include <GL/glx.h>
15 #include <GL/glxtokens.h>
16 #include <GL/glext.h>
17 #include <GL/glxext.h>
18
19 #define MAX_DEPTH 32
20
21 static int plugin_id;
22
23 #define LEFT   0
24 #define TOP    1
25 #define RIGHT  2
26 #define BOTTOM 3
27
28 typedef void (*BindEXTFunc)(Display *, GLXDrawable, int, const int *);
29 typedef void (*ReleaseEXTFunc)(Display *, GLXDrawable, int);
30
31 typedef struct {
32     void (*screen_paint)(d_screen_t *sc);
33     void (*screen_root_pixmap_change)(d_screen_t *sc);
34     void (*window_show)(d_window_t *w);
35     void (*window_zombie_dead)(d_window_t *w);
36     void (*window_resize)(d_window_t *w);
37     void (*window_reshape)(d_window_t *w);
38
39     float shadowalpha;
40     int xshadowoff;
41     int yshadowoff;
42
43     GLXFBConfig fbconfig[MAX_DEPTH + 1];
44
45     GLXContext context;
46     GLuint root_texname;
47     GLXPixmap root_glpixmap;
48
49     BindEXTFunc bind_func;
50     ReleaseEXTFunc release_func;
51 } data_t;
52
53 typedef struct {
54     GLuint texname;
55     GLXPixmap glpixmap;
56
57     GLfloat *texcoords;
58     GLint *vertices;
59     int nrects;
60
61     xcb_xfixes_fetch_region_cookie_t ck_region;
62     int waiting_region;
63 } window_data_t;
64
65 static gboolean glxrender_find_fb_config(d_screen_t *sc, data_t *d);
66
67 static void glxrender_paint(d_screen_t *sc);
68 static void glxrender_root_pixmap_change(d_screen_t *sc);
69 static void paint_root(d_screen_t *sc, data_t *d);
70 static void paint_window(d_window_t *window, data_t *d, window_data_t *wd,
71                          int x, int y, GLfloat z);
72 static void paint_shadow(data_t *d, window_data_t *wd, int x, int y,
73                          GLfloat z);
74 static void glxrender_update_window_pixmap(d_window_t *w, data_t *d,
75                                            window_data_t *wd);
76 static void glxrender_fetch_window_region(d_window_t *w, window_data_t *wd);
77 static void glxrender_update_window_region(d_window_t *w, window_data_t *wd);
78 static void glxrender_free_window_pixmap(d_window_t *w, data_t *d,
79                                          window_data_t *wd);
80 static void glxrender_free_window_region(window_data_t *wd);
81 static void glxrender_free_root_pixmap(d_screen_t *sc, data_t *d);
82 static void glxrender_update_root_pixmap(d_screen_t *sc, data_t *d);
83
84 static void glxrender_window_show(d_window_t *window);
85 static void glxrender_window_zombie_dead(d_window_t *window);
86 static void glxrender_window_resize(d_window_t *window);
87 static void glxrender_window_reshape(d_window_t *window);
88
89 void
90 glxrender_init(d_screen_t *sc, int id)
91 {
92     static int context_visual_config[] = {
93         GLX_DEPTH_SIZE, 1,
94         GLX_DOUBLEBUFFER,
95         GLX_RGBA,
96         XCB_NONE
97     };
98     XVisualInfo *vi;
99     data_t *d;
100
101     plugin_id = id;
102
103     d = malloc(sizeof(data_t));
104     d->screen_paint = sc->screen_paint;
105     d->screen_root_pixmap_change = sc->screen_root_pixmap_change;
106     d->window_show = sc->window_show;
107     d->window_zombie_dead = sc->window_zombie_dead;
108     d->window_resize = sc->window_resize;
109     d->window_reshape = sc->window_reshape;
110     screen_add_plugin_data(sc, plugin_id, d);
111
112     sc->screen_paint = glxrender_paint;
113     sc->screen_root_pixmap_change = glxrender_root_pixmap_change;
114     sc->window_show = glxrender_window_show;
115     sc->window_zombie_dead = glxrender_window_zombie_dead;
116     sc->window_resize = glxrender_window_resize;
117     sc->window_reshape = glxrender_window_reshape;
118
119     d->shadowalpha = 0.2f; /* 20% */
120     d->xshadowoff = 2;
121     d->yshadowoff = 2;
122
123     vi = glXChooseVisual(sc->dpy->xlib_dpy, sc->num, context_visual_config);
124     if (!vi) {
125         printf("unable to find a valid double buffered GL context to use\n");
126         exit(1);
127     }
128
129     d->context = glXCreateContext(sc->dpy->xlib_dpy, vi, NULL, GL_TRUE);
130     glXMakeCurrent(sc->dpy->xlib_dpy, sc->overlay, d->context);
131
132
133     if (!(glxrender_find_fb_config(sc, d))) {
134         printf("unable to find FB configs\n");
135         exit(1);
136     }
137
138     glViewport(0, 0, sc->super->width_in_pixels, sc->super->height_in_pixels);
139     glMatrixMode(GL_PROJECTION);
140     glLoadIdentity();
141     glOrtho(0, sc->super->width_in_pixels, sc->super->height_in_pixels, 0,
142             -100.0, 100.0);
143     glMatrixMode(GL_MODELVIEW);
144     glLoadIdentity();
145     glEnable(GL_TEXTURE_2D);
146     glEnable(GL_DEPTH_TEST);
147
148     glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
149     glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
150     glDisable(GL_BLEND);
151
152     glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
153     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
154     glXSwapBuffers(sc->dpy->xlib_dpy, sc->overlay);
155
156     d->bind_func = (BindEXTFunc)
157         glXGetProcAddress((const guchar*)"glXBindTexImageEXT");
158     d->release_func = (ReleaseEXTFunc)
159         glXGetProcAddress((const guchar*)"glXReleaseTexImageEXT");
160
161     glGenTextures(1, &d->root_texname);
162     d->root_glpixmap = XCB_NONE;
163 }
164
165 static gboolean
166 glxrender_find_fb_config(d_screen_t *sc, data_t *d)
167 {
168     static const int drawable_tfp_attrs[] = {
169         GLX_CONFIG_CAVEAT, GLX_NONE,
170         GLX_DOUBLEBUFFER, FALSE,
171         GLX_DEPTH_SIZE, 0,
172         GLX_RED_SIZE, 1,
173         GLX_GREEN_SIZE, 1,
174         GLX_BLUE_SIZE, 1,
175         GLX_ALPHA_SIZE, 1,
176         GLX_RENDER_TYPE, GLX_RGBA_BIT,
177         GLX_BIND_TO_TEXTURE_RGBA_EXT, TRUE, /* For TextureFromPixmap */
178         XCB_NONE
179     };
180     int db, stencil, depth, numfb, i;
181     GLXFBConfig *fbcons;
182     XVisualInfo tvis, *visinfo;
183
184     fbcons = glXChooseFBConfig(sc->dpy->xlib_dpy, sc->num,
185                                drawable_tfp_attrs, &numfb);
186     if (!fbcons) return FALSE;
187
188     for (i = 0; i <= MAX_DEPTH; i++) {
189         int j, count, value;
190         VisualID vid;
191
192         vid = 0;
193         d->fbconfig[i] = 0;
194         db = 32767;
195         stencil = 32767;
196         depth = 32767;
197
198         printf("looking for depth %d\n", i);
199
200         tvis.depth = i;
201         visinfo = XGetVisualInfo(sc->dpy->xlib_dpy, VisualDepthMask,
202                                  &tvis, &count);
203         /* pick the nicest visual for the depth */
204         for (j = 0; j < count; j++) {
205             glXGetConfig(sc->dpy->xlib_dpy, &visinfo[j], GLX_USE_GL, &value);
206             if (!value)
207                 continue;
208
209             glXGetConfig(sc->dpy->xlib_dpy, &visinfo[j], GLX_DOUBLEBUFFER,
210                          &value);
211             if (value > db)
212                 continue;
213             db = value;
214
215             glXGetConfig(sc->dpy->xlib_dpy, &visinfo[j], GLX_STENCIL_SIZE,
216                          &value);
217             if (value > stencil)
218                 continue;
219             stencil = value;
220
221             glXGetConfig(sc->dpy->xlib_dpy, &visinfo[j], GLX_DEPTH_SIZE,
222                          &value);
223             if (value > depth)
224                 continue;
225             depth = value;
226
227             /* use this visual */
228             vid = visinfo[j].visualid;
229         }
230
231         if (!vid) continue;
232
233         /* look for an fbconfig for this visual */
234         for (j = 0; j < numfb; ++j) {
235             glXGetFBConfigAttrib(sc->dpy->xlib_dpy, fbcons[j],
236                                  GLX_VISUAL_ID, &value);
237             if ((unsigned)value == vid) {
238                 d->fbconfig[i] = fbcons[j];
239
240                 printf("found visual 0x%x fbconfig 0x%x for depth %d\n",
241                        (uint32_t)vid, (uint32_t)fbcons[j], i);
242                 break;
243             }
244         }
245     }
246
247     XFree(fbcons);
248     return TRUE;
249 }
250
251 void
252 glxrender_free(d_screen_t *sc)
253 {
254     data_t *d = screen_find_plugin_data(sc, plugin_id);
255     if (d) {
256         glxrender_free_root_pixmap(sc, d);
257         free(d);
258     }
259     screen_remove_plugin_data(sc, plugin_id);
260 }
261
262 int
263 glxrender_next_timeout(struct d_screen *sc, struct timeval *tv)
264 {
265     (void)sc;
266     (void)tv;
267     return FALSE;
268 }
269
270 void
271 glxrender_timeout(struct d_screen *sc, const struct timeval *now)
272 {
273     (void)sc; (void)now;
274 }
275
276 void
277 glxrender_window_free_data(d_window_t *w, data_t *d, window_data_t *wd)
278 {
279     glxrender_free_window_pixmap(w, d, wd);
280     glxrender_free_window_region(wd);
281     glDeleteTextures(1, &wd->texname);
282     free(wd);
283 }
284
285 static void
286 glxrender_window_show(d_window_t *w)
287 {
288     data_t *d;
289     window_data_t *wd;
290
291     d = screen_find_plugin_data(w->sc, plugin_id);
292
293     /* pass it on */
294     d->window_show(w);
295
296     wd = window_find_plugin_data(w, plugin_id);
297     if (wd)
298         glxrender_window_free_data(w, d, wd);
299    
300     wd = malloc(sizeof(window_data_t));
301     glGenTextures(1, &wd->texname);
302     wd->glpixmap = XCB_NONE;
303     wd->texcoords = NULL;
304     wd->vertices = NULL;
305     wd->nrects = 0;
306     wd->waiting_region = FALSE;
307
308     window_add_plugin_data(w, plugin_id, wd);
309
310     glxrender_fetch_window_region(w, wd);
311 }
312
313 static void
314 glxrender_window_zombie_dead(d_window_t *w)
315 {
316     data_t *d;
317     window_data_t *wd;
318
319     d = screen_find_plugin_data(w->sc, plugin_id);
320     wd = window_find_plugin_data(w, plugin_id);
321     if (wd) {
322         glxrender_window_free_data(w, d, wd);
323         window_remove_plugin_data(w, plugin_id);
324     }
325
326     /* pass it on */
327     d->window_zombie_dead(w);
328 }
329
330 static void
331 glxrender_free_window_pixmap(d_window_t *w, data_t *d, window_data_t *wd)
332 {
333     /* this might cause an error, oh well */
334     if (wd->glpixmap) {
335         glBindTexture(GL_TEXTURE_2D, wd->texname);
336         d->release_func(w->sc->dpy->xlib_dpy,
337                         wd->glpixmap, GLX_FRONT_LEFT_EXT);
338         glBindTexture(GL_TEXTURE_2D, 0);
339
340         //xcb_glx_destroy_pixmap(w->sc->dpy->conn, wd->glpixmap);
341         glXDestroyPixmap(w->sc->dpy->xlib_dpy, wd->glpixmap);
342         wd->glpixmap = XCB_NONE;
343
344     }
345 }
346
347 static void
348 glxrender_free_window_region(window_data_t *wd)
349 {
350     if (wd->nrects) {
351         free(wd->texcoords);
352         free(wd->vertices);
353         wd->texcoords = NULL;
354         wd->vertices = NULL;
355         wd->nrects = 0;
356     }
357 }
358
359 static void
360 glxrender_free_root_pixmap(d_screen_t *sc, data_t *d)
361 {
362     /* this might cause an error, oh well */
363     if (d->root_glpixmap) {
364         glBindTexture(GL_TEXTURE_2D, d->root_texname);
365         d->release_func(sc->dpy->xlib_dpy,
366                         d->root_glpixmap, GLX_FRONT_LEFT_EXT);
367         glBindTexture(GL_TEXTURE_2D, 0);
368
369         //xcb_glx_destroy_pixmap(w->sc->dpy->conn, wd->glpixmap);
370         glXDestroyPixmap(sc->dpy->xlib_dpy, d->root_glpixmap);
371         d->root_glpixmap = XCB_NONE;
372     }
373 }
374
375 static void
376 glxrender_update_window_pixmap(d_window_t *w, data_t *d, window_data_t *wd)
377 {
378     xcb_pixmap_t px;
379     uint8_t depth;
380
381     static int attrs[] = {
382         GLX_TEXTURE_FORMAT_EXT,
383         XCB_NONE,
384         XCB_NONE
385     };
386
387     px = window_get_pixmap(w);
388     depth = window_get_depth(w);
389
390     if (!px) return;
391
392     if (!d->fbconfig[depth]) {
393         printf("no GL visual for depth %d\n", depth);
394         return;
395     }
396
397     if (window_is_argb(w))
398         attrs[1] = GLX_TEXTURE_FORMAT_RGBA_EXT;
399     else
400         attrs[1] = GLX_TEXTURE_FORMAT_RGB_EXT;
401
402     wd->glpixmap = glXCreatePixmap(w->sc->dpy->xlib_dpy,
403                                    d->fbconfig[depth],
404                                    px, attrs);
405
406
407     glBindTexture(GL_TEXTURE_2D, wd->texname);
408     d->bind_func(w->sc->dpy->xlib_dpy,
409                  wd->glpixmap, GLX_FRONT_LEFT_EXT, NULL);
410
411     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
412     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
413
414     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
415     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
416
417     glBindTexture(GL_TEXTURE_2D, 0);
418
419     glxrender_update_window_region(w, wd);
420 }
421
422 static void
423 glxrender_fetch_window_region(d_window_t *w, window_data_t *wd)
424 {
425     if (wd->waiting_region) return;
426
427     wd->ck_region =
428         xcb_xfixes_fetch_region_unchecked(w->sc->dpy->conn,
429                                           window_get_region(w));
430     wd->waiting_region = TRUE;
431     xcb_flush(w->sc->dpy->conn);
432 }
433
434 static void
435 glxrender_update_window_region(d_window_t *w, window_data_t *wd)
436 {
437     xcb_xfixes_fetch_region_reply_t *rep;
438     xcb_rectangle_t area, *rects;
439     int nrects, i, j, x, y, wid, hei, bwid;
440
441     if (!wd->waiting_region) return;
442
443     window_get_area(w, &x, &y, &wid, &hei, &bwid);
444     area.x = x;
445     area.y = y;
446     area.width = wid + bwid * 2;
447     area.height = hei + bwid * 2;
448
449     rep = xcb_xfixes_fetch_region_reply(w->sc->dpy->conn, wd->ck_region, NULL);
450     if (!rep) {
451         rects = &area;
452         nrects = 1;
453     }
454     else {
455         rects = xcb_xfixes_fetch_region_rectangles(rep);
456         nrects = xcb_xfixes_fetch_region_rectangles_length(rep);
457     }
458
459     wd->texcoords = (GLfloat*)realloc(wd->texcoords,
460                                       sizeof(GLfloat) * (nrects * 4));
461     wd->vertices = (GLint*)realloc(wd->vertices, sizeof(GLint) * (nrects * 4));
462     wd->nrects = nrects;
463
464     for (i = j = 0; i < nrects * 4; ++j, i += 4) {
465         wd->texcoords[i+LEFT] =
466             (GLfloat)(rects[j].x - x) / (GLfloat)area.width;
467         wd->texcoords[i+TOP] =
468             (GLfloat)(rects[j].y - y) / (GLfloat)area.height;
469         wd->texcoords[i+RIGHT] =
470             (GLfloat)(rects[j].x - x + rects[j].width) /
471             (GLfloat)area.width;
472         wd->texcoords[i+BOTTOM] =
473             (GLfloat)(rects[j].y - y + rects[j].height) /
474             (GLfloat)area.height;
475
476         wd->vertices[i+LEFT] = rects[j].x - x;
477         wd->vertices[i+TOP] = rects[j].y - y;
478         wd->vertices[i+RIGHT] = rects[j].x - x + rects[j].width;
479         wd->vertices[i+BOTTOM] = rects[j].y - y + rects[j].height;
480     }
481
482     if (rep)
483         free(rep);
484
485     wd->waiting_region = FALSE;
486 }
487
488 static void
489 glxrender_update_root_pixmap(d_screen_t *sc, data_t *d)
490 {
491     xcb_pixmap_t px;
492     static int attrs[] = {
493         GLX_TEXTURE_FORMAT_EXT,
494         GLX_TEXTURE_FORMAT_RGB_EXT,
495         XCB_NONE
496     };
497
498     px = screen_get_root_pixmap(sc);
499     if (!px) return;
500
501     if (!d->fbconfig[sc->super->root_depth]) {
502         printf("no GL visual for depth %d\n", sc->super->root_depth);
503         return;
504     }
505
506     d->root_glpixmap = glXCreatePixmap(sc->dpy->xlib_dpy,
507                                        d->fbconfig[sc->super->root_depth],
508                                        px, attrs);
509
510
511     glBindTexture(GL_TEXTURE_2D, d->root_texname);
512     d->bind_func(sc->dpy->xlib_dpy,
513                  d->root_glpixmap, GLX_FRONT_LEFT_EXT, NULL);
514
515     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
516     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
517
518     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
519     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
520
521     glBindTexture(GL_TEXTURE_2D, 0);
522 }
523
524 static void
525 glxrender_window_resize(d_window_t *w)
526 {
527     data_t *d;
528     window_data_t *wd;
529
530     d = screen_find_plugin_data(w->sc, plugin_id);
531     wd = window_find_plugin_data(w, plugin_id);
532
533     /* pass it on */
534     d->window_resize(w);
535
536     assert(wd != NULL);
537     glxrender_free_window_pixmap(w, d, wd);
538
539     glxrender_free_window_region(wd);
540     glxrender_fetch_window_region(w, wd);
541 }
542
543 static void
544 glxrender_window_reshape(d_window_t *w)
545 {
546     data_t *d;
547     window_data_t *wd;
548
549     d = screen_find_plugin_data(w->sc, plugin_id);
550     wd = window_find_plugin_data(w, plugin_id);
551
552     /* pass it on */
553     d->window_reshape(w);
554
555     assert(wd != NULL);
556     glxrender_free_window_pixmap(w, d, wd);
557
558     glxrender_free_window_region(wd);
559     glxrender_fetch_window_region(w, wd);
560 }
561
562 static void
563 glxrender_root_pixmap_change(d_screen_t *sc)
564 {
565     data_t *d;
566
567     d = screen_find_plugin_data(sc, plugin_id);
568     glxrender_free_root_pixmap(sc, d);
569
570     /* pass it on */
571     d->screen_root_pixmap_change(sc);
572 }
573
574 static void
575 glxrender_paint(d_screen_t *sc)
576 {
577     data_t *d = screen_find_plugin_data(sc, plugin_id);
578     d_list_it_t *it;
579     GLfloat z;
580
581     //printf("painting\n");
582
583     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
584
585     /* add 0.1f to keep everything above the root */
586     z = list_length(sc->stacking) * 0.1f + 0.1f;
587     for (it = list_top(sc->stacking); it; it = it->next) {
588         d_window_t *w = it->data;
589
590         if (!window_is_input_only(w) &&
591             (window_is_mapped(w) || window_is_zombie(w)))
592         {
593             int x, y, width, height, bwidth;
594             gboolean opaque;
595             window_data_t *wd;
596
597             window_get_area(w, &x, &y, &width, &height, &bwidth);
598
599             if (!(x < sc->super->width_in_pixels &&
600                   y < sc->super->height_in_pixels &&
601                   (x + width > 0 || x + width + d->xshadowoff > 0) &&
602                   (y + height > 0 || y + height + d->yshadowoff > 0)))
603             {
604                 continue;
605             }
606
607             opaque = !window_is_argb(w) && window_get_opacity(w) == 0xffff;
608
609             if (opaque) {
610                 wd = window_find_plugin_data(w, plugin_id);
611
612                 //glPushMatrix();
613
614                 paint_window(w, d, wd, x, y, z - 0.05f);
615
616                 //glPopMatrix();
617             }
618
619             z -= 0.1f;
620         }
621     }
622
623     paint_root(sc, d);
624
625     glEnable(GL_BLEND);
626     glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
627
628     for (it = list_bottom(sc->stacking); it; it = it->prev) {
629         d_window_t *w = it->data;
630
631         if (!window_is_input_only(w) &&
632             (window_is_mapped(w) || window_is_zombie(w)))
633         {
634             int x, y, width, height, bwidth;
635             gboolean opaque;
636             window_data_t *wd;
637             uint16_t opac;
638             GLfloat alpha;
639
640             window_get_area(w, &x, &y, &width, &height, &bwidth);
641
642             if (!(x < sc->super->width_in_pixels &&
643                   y < sc->super->height_in_pixels &&
644                   (x + width > 0 || x + width + d->xshadowoff > 0) &&
645                   (y + height > 0 || y + height + d->yshadowoff > 0)))
646             {
647                 continue;
648             }
649
650             opac = window_get_opacity(w);
651             opaque = !window_is_argb(w) && opac == 0xffff;
652
653             wd = window_find_plugin_data(w, plugin_id);
654
655             //glPushMatrix();
656
657             /* black shadow */
658             alpha = d->shadowalpha;
659             alpha *= opac;
660             alpha /= 0xffff;
661             if (alpha >= 0.01) {
662                 glColor4f(0.0f, 0.0f, 0.0f, alpha);
663                 paint_shadow(d, wd, x, y, z);
664             }
665
666             if (!opaque) {
667                 glColor4us(opac, opac, opac, opac);
668                 paint_window(w, d, wd, x, y, z + 0.05f);
669             }
670
671             //glPopMatrix();
672
673             z += 0.1f;
674         }
675     }
676
677     glColor4f(0.0f, 0.0f, 0.0f, 0.0f);
678     glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
679     glDisable(GL_BLEND);
680
681     //xcb_glx_swap_buffers(sc->dpy->conn, d->context_tag, sc->overlay);
682     glXSwapBuffers(sc->dpy->xlib_dpy, sc->overlay);
683
684     /* call the function we replaced in the chain */
685     d->screen_paint(sc);
686 }
687
688 static void
689 paint_root(d_screen_t *sc, data_t *d)
690 {
691     if (!d->root_glpixmap)
692         glxrender_update_root_pixmap(sc, d);
693
694     glBindTexture(GL_TEXTURE_2D, d->root_texname);
695     glBegin(GL_QUADS);
696     glTexCoord2f(0, 0);
697     glVertex3i(0, 0, 0);
698     glTexCoord2f(1, 0);
699     glVertex3i(sc->super->width_in_pixels, 0, 0);
700     glTexCoord2f(1, 1);
701     glVertex3i(sc->super->width_in_pixels, sc->super->height_in_pixels, 0);
702     glTexCoord2f(0, 1);
703     glVertex3i(0, sc->super->height_in_pixels, 0);
704     glEnd();
705
706     glBindTexture(GL_TEXTURE_2D, 0);
707 }
708
709 static void
710 paint_window(d_window_t *w, data_t *d, window_data_t *wd, int x, int y,
711              GLfloat z)
712 {
713     int i;
714
715     if (!wd->glpixmap)
716         glxrender_update_window_pixmap(w, d, wd);
717
718     if (wd->nrects < 1) return;
719
720     glBindTexture(GL_TEXTURE_2D, wd->texname);
721
722     glBegin(GL_QUADS);
723     for (i = 0; i < wd->nrects * 4; i += 4) {
724         glTexCoord2f(wd->texcoords[i+LEFT], wd->texcoords[i+TOP]);
725         glVertex3f(x+wd->vertices[i+LEFT], y+wd->vertices[i+TOP], z);
726         glTexCoord2f(wd->texcoords[i+RIGHT], wd->texcoords[i+TOP]);
727         glVertex3f(x+wd->vertices[i+RIGHT], y+wd->vertices[i+TOP], z);
728         glTexCoord2f(wd->texcoords[i+RIGHT], wd->texcoords[i+BOTTOM]);
729         glVertex3f(x+wd->vertices[i+RIGHT], y+wd->vertices[i+BOTTOM], z);
730         glTexCoord2f(wd->texcoords[i+LEFT], wd->texcoords[i+BOTTOM]);
731         glVertex3f(x+wd->vertices[i+LEFT], y+wd->vertices[i+BOTTOM], z);
732     }
733     glEnd();
734
735     glBindTexture(GL_TEXTURE_2D, 0);
736 }
737
738 static void
739 paint_shadow(data_t *d, window_data_t *wd, int x, int y, GLfloat z)
740 {
741     int i;
742
743     if (wd->nrects < 1) return;
744
745     /* shape the shadow to the window */
746     glBindTexture(GL_TEXTURE_2D, wd->texname);
747
748     x += d->xshadowoff;
749     y += d->yshadowoff;
750
751     glBegin(GL_QUADS);
752     for (i = 0; i < wd->nrects * 4; i += 4) {
753         glTexCoord2f(wd->texcoords[i+LEFT], wd->texcoords[i+TOP]);
754         glVertex3f(x+wd->vertices[i+LEFT], y+wd->vertices[i+TOP], z);
755         glTexCoord2f(wd->texcoords[i+RIGHT], wd->texcoords[i+TOP]);
756         glVertex3f(x+wd->vertices[i+RIGHT], y+wd->vertices[i+TOP], z);
757         glTexCoord2f(wd->texcoords[i+RIGHT], wd->texcoords[i+BOTTOM]);
758         glVertex3f(x+wd->vertices[i+RIGHT], y+wd->vertices[i+BOTTOM], z);
759         glTexCoord2f(wd->texcoords[i+LEFT], wd->texcoords[i+BOTTOM]);
760         glVertex3f(x+wd->vertices[i+LEFT], y+wd->vertices[i+BOTTOM], z);
761     }
762     glEnd();
763
764     glBindTexture(GL_TEXTURE_2D, 0);
765 }