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