]> icculus.org git repositories - mikachu/openbox.git/blob - src/Image.cc
when a window begins moving, make sure another window is not moving already, and...
[mikachu/openbox.git] / src / Image.cc
1 // Image.cc for Openbox
2 // Copyright (c) 2001 Sean 'Shaleh' Perry <shaleh@debian.org>
3 // Copyright (c) 1997 - 2000 Brad Hughes (bhughes@tcac.net)
4 //
5 // Permission is hereby granted, free of charge, to any person obtaining a
6 // copy of this software and associated documentation files (the "Software"),
7 // to deal in the Software without restriction, including without limitation
8 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 // and/or sell copies of the Software, and to permit persons to whom the
10 // Software is furnished to do so, subject to the following conditions:
11 //
12 // The above copyright notice and this permission notice shall be included in
13 // all copies or substantial portions of the Software.
14 //
15 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21 // DEALINGS IN THE SOFTWARE.
22
23 // stupid macros needed to access some functions in version 2 of the GNU C
24 // library
25 #ifndef   _GNU_SOURCE
26 #define   _GNU_SOURCE
27 #endif // _GNU_SOURCE
28
29 #ifdef    HAVE_CONFIG_H
30 #  include "../config.h"
31 #endif // HAVE_CONFIG_H
32
33 #include "i18n.h"
34 #include "BaseDisplay.h"
35 #include "Image.h"
36
37 #ifdef    HAVE_SYS_TYPES_H
38 #  include <sys/types.h>
39 #endif // HAVE_SYS_TYPES_H
40
41 #ifndef u_int32_t
42 #  ifdef uint_32_t
43 typedef uint32_t u_int32_t;
44 #  else
45 #    ifdef __uint32_t
46 typedef __uint32_t u_int32_t;
47 #    else
48 typedef unsigned int u_int32_t;
49 #    endif
50 #  endif
51 #endif
52
53 #ifdef    HAVE_STDLIB_H
54 #  include <stdlib.h>
55 #endif // HAVE_STDLIB_H
56
57 #ifdef    HAVE_STRING_H
58 #  include <string.h>
59 #endif // HAVE_STRING_H
60
61 #ifdef    HAVE_STDIO_H
62 #  include <stdio.h>
63 #endif // HAVE_STDIO_H
64
65 #ifdef    HAVE_CTYPE_H
66 #  include <ctype.h>
67 #endif // HAVE_CTYPE_H
68
69 #include <algorithm>
70 using namespace std;
71
72 static unsigned long bsqrt(unsigned long x) {
73   if (x <= 0) return 0;
74   if (x == 1) return 1;
75
76   unsigned long r = x >> 1;
77   unsigned long q;
78
79   while (1) {
80     q = x / r;
81     if (q >= r) return r;
82     r = (r + q) >> 1;
83   }
84 }
85
86
87 BImage::BImage(BImageControl &c, unsigned int w, unsigned int h) : control(c) {
88   width = ((signed) w > 0) ? w : 1;
89   height = ((signed) h > 0) ? h : 1;
90
91   red = new unsigned char[width * height];
92   green = new unsigned char[width * height];
93   blue = new unsigned char[width * height];
94
95   xtable = ytable = (unsigned int *) 0;
96
97   cpc = control.getColorsPerChannel();
98   cpccpc = cpc * cpc;
99
100   control.getColorTables(&red_table, &green_table, &blue_table,
101                           &red_offset, &green_offset, &blue_offset,
102                           &red_bits, &green_bits, &blue_bits);
103
104   if (control.getVisual()->c_class != TrueColor)
105     control.getXColorTable(&colors, &ncolors);
106 }
107
108
109 BImage::~BImage(void) {
110   if (red) delete [] red;
111   if (green) delete [] green;
112   if (blue) delete [] blue;
113 }
114
115
116 Pixmap BImage::render(BTexture *texture) {
117   if (texture->getTexture() & BImage_ParentRelative)
118     return ParentRelative;
119   else if (texture->getTexture() & BImage_Solid)
120     return render_solid(texture);
121   else if (texture->getTexture() & BImage_Gradient)
122     return render_gradient(texture);
123
124   return None;
125 }
126
127
128 Pixmap BImage::render_solid(BTexture *texture) {
129   Pixmap pixmap = XCreatePixmap(control.getBaseDisplay().getXDisplay(),
130                                 control.getDrawable(), width,
131                                 height, control.getDepth());
132   if (pixmap == None) {
133     fprintf(stderr, i18n->getMessage(ImageSet, ImageErrorCreatingSolidPixmap,
134                        "BImage::render_solid: error creating pixmap\n"));
135     return None;
136   }
137
138   XGCValues gcv;
139   GC gc, hgc, lgc;
140
141   gcv.foreground = texture->getColor()->getPixel();
142   gcv.fill_style = FillSolid;
143   gc = XCreateGC(control.getBaseDisplay().getXDisplay(), pixmap,
144                  GCForeground | GCFillStyle, &gcv);
145
146   gcv.foreground = texture->getHiColor()->getPixel();
147   hgc = XCreateGC(control.getBaseDisplay().getXDisplay(), pixmap,
148                   GCForeground, &gcv);
149
150   gcv.foreground = texture->getLoColor()->getPixel();
151   lgc = XCreateGC(control.getBaseDisplay().getXDisplay(), pixmap,
152                   GCForeground, &gcv);
153
154   XFillRectangle(control.getBaseDisplay().getXDisplay(), pixmap, gc, 0, 0,
155                  width, height);
156
157 #ifdef    INTERLACE
158   if (texture->getTexture() & BImage_Interlaced) {
159     gcv.foreground = texture->getColorTo()->getPixel();
160     GC igc = XCreateGC(control.getBaseDisplay().getXDisplay(), pixmap,
161                        GCForeground, &gcv);
162
163     register unsigned int i = 0;
164     for (; i < height; i += 2)
165       XDrawLine(control.getBaseDisplay().getXDisplay(), pixmap, igc,
166                 0, i, width, i);
167
168     XFreeGC(control.getBaseDisplay().getXDisplay(), igc);
169   }
170 #endif // INTERLACE
171
172
173   if (texture->getTexture() & BImage_Bevel1) {
174     if (texture->getTexture() & BImage_Raised) {
175       XDrawLine(control.getBaseDisplay().getXDisplay(), pixmap, lgc,
176                 0, height - 1, width - 1, height - 1);
177       XDrawLine(control.getBaseDisplay().getXDisplay(), pixmap, lgc,
178                 width - 1, height - 1, width - 1, 0);
179
180       XDrawLine(control.getBaseDisplay().getXDisplay(), pixmap, hgc,
181                 0, 0, width - 1, 0);
182       XDrawLine(control.getBaseDisplay().getXDisplay(), pixmap, hgc,
183                 0, height - 1, 0, 0);
184     } else if (texture->getTexture() & BImage_Sunken) {
185       XDrawLine(control.getBaseDisplay().getXDisplay(), pixmap, hgc,
186                 0, height - 1, width - 1, height - 1);
187       XDrawLine(control.getBaseDisplay().getXDisplay(), pixmap, hgc,
188                 width - 1, height - 1, width - 1, 0);
189
190       XDrawLine(control.getBaseDisplay().getXDisplay(), pixmap, lgc,
191                 0, 0, width - 1, 0);
192       XDrawLine(control.getBaseDisplay().getXDisplay(), pixmap, lgc,
193                 0, height - 1, 0, 0);
194     }
195   } else if (texture->getTexture() & BImage_Bevel2) {
196     if (texture->getTexture() & BImage_Raised) {
197       XDrawLine(control.getBaseDisplay().getXDisplay(), pixmap, lgc,
198                 1, height - 3, width - 3, height - 3);
199       XDrawLine(control.getBaseDisplay().getXDisplay(), pixmap, lgc,
200                 width - 3, height - 3, width - 3, 1);
201
202       XDrawLine(control.getBaseDisplay().getXDisplay(), pixmap, hgc,
203                 1, 1, width - 3, 1);
204       XDrawLine(control.getBaseDisplay().getXDisplay(), pixmap, hgc,
205                 1, height - 3, 1, 1);
206     } else if (texture->getTexture() & BImage_Sunken) {
207       XDrawLine(control.getBaseDisplay().getXDisplay(), pixmap, hgc,
208                 1, height - 3, width - 3, height - 3);
209       XDrawLine(control.getBaseDisplay().getXDisplay(), pixmap, hgc,
210                 width - 3, height - 3, width - 3, 1);
211
212       XDrawLine(control.getBaseDisplay().getXDisplay(), pixmap, lgc,
213                 1, 1, width - 3, 1);
214       XDrawLine(control.getBaseDisplay().getXDisplay(), pixmap, lgc,
215                 1, height - 3, 1, 1);
216     }
217   }
218
219   XFreeGC(control.getBaseDisplay().getXDisplay(), gc);
220   XFreeGC(control.getBaseDisplay().getXDisplay(), hgc);
221   XFreeGC(control.getBaseDisplay().getXDisplay(), lgc);
222
223   return pixmap;
224 }
225
226
227 Pixmap BImage::render_gradient(BTexture *texture) {
228  int inverted = 0;
229
230 #ifdef    INTERLACE
231   interlaced = texture->getTexture() & BImage_Interlaced;
232 #endif // INTERLACE
233
234   if (texture->getTexture() & BImage_Sunken) {
235     from = texture->getColorTo();
236     to = texture->getColor();
237
238     if (! (texture->getTexture() & BImage_Invert)) inverted = 1;
239   } else {
240     from = texture->getColor();
241     to = texture->getColorTo();
242
243     if (texture->getTexture() & BImage_Invert) inverted = 1;
244   }
245
246   control.getGradientBuffers(width, height, &xtable, &ytable);
247
248   if (texture->getTexture() & BImage_Diagonal) dgradient();
249   else if (texture->getTexture() & BImage_Elliptic) egradient();
250   else if (texture->getTexture() & BImage_Horizontal) hgradient();
251   else if (texture->getTexture() & BImage_Pyramid) pgradient();
252   else if (texture->getTexture() & BImage_Rectangle) rgradient();
253   else if (texture->getTexture() & BImage_Vertical) vgradient();
254   else if (texture->getTexture() & BImage_CrossDiagonal) cdgradient();
255   else if (texture->getTexture() & BImage_PipeCross) pcgradient();
256
257   if (texture->getTexture() & BImage_Bevel1) bevel1();
258   else if (texture->getTexture() & BImage_Bevel2) bevel2();
259
260   if (inverted) invert();
261
262   Pixmap pixmap = renderPixmap();
263
264   return pixmap;
265
266 }
267
268
269 XImage *BImage::renderXImage(void) {
270   XImage *image =
271     XCreateImage(control.getBaseDisplay().getXDisplay(),
272                  control.getVisual(), control.getDepth(), ZPixmap, 0, 0,
273                  width, height, 32, 0);
274
275   if (! image) {
276     fprintf(stderr, i18n->getMessage(ImageSet, ImageErrorCreatingXImage,
277                        "BImage::renderXImage: error creating XImage\n"));
278     return (XImage *) 0;
279   }
280
281   // insurance policy
282   image->data = (char *) 0;
283
284   unsigned char *d = new unsigned char[image->bytes_per_line * (height + 1)];
285   register unsigned int x, y, dithx, dithy, r, g, b, o, er, eg, eb, offset;
286
287   unsigned char *pixel_data = d, *ppixel_data = d;
288   unsigned long pixel;
289
290   o = image->bits_per_pixel + ((image->byte_order == MSBFirst) ? 1 : 0);
291
292   if (control.doDither() && width > 1 && height > 1) {
293     unsigned char dither4[4][4] = { {0, 4, 1, 5},
294                                     {6, 2, 7, 3},
295                                     {1, 5, 0, 4},
296                                     {7, 3, 6, 2} };
297
298 #ifdef    ORDEREDPSEUDO
299     unsigned char dither8[8][8] = { { 0,  32, 8,  40, 2,  34, 10, 42 },
300                                     { 48, 16, 56, 24, 50, 18, 58, 26 },
301                                     { 12, 44, 4,  36, 14, 46, 6,  38 },
302                                     { 60, 28, 52, 20, 62, 30, 54, 22 },
303                                     { 3,  35, 11, 43, 1,  33, 9,  41 },
304                                     { 51, 19, 59, 27, 49, 17, 57, 25 },
305                                     { 15, 47, 7,  39, 13, 45, 5,  37 },
306                                     { 63, 31, 55, 23, 61, 29, 53, 21 } };
307 #endif // ORDEREDPSEUDO
308
309     switch (control.getVisual()->c_class) {
310     case TrueColor:
311       // algorithm: ordered dithering... many many thanks to rasterman
312       // (raster@rasterman.com) for telling me about this... portions of this
313       // code is based off of his code in Imlib
314       for (y = 0, offset = 0; y < height; y++) {
315         dithy = y & 0x3;
316
317         for (x = 0; x < width; x++, offset++) {
318           dithx = x & 0x3;
319           r = red[offset];
320           g = green[offset];
321           b = blue[offset];
322
323           er = r & (red_bits - 1);
324           eg = g & (green_bits - 1);
325           eb = b & (blue_bits - 1);
326
327           r = red_table[r];
328           g = green_table[g];
329           b = blue_table[b];
330
331           if ((dither4[dithy][dithx] < er) && (r < red_table[255])) r++;
332           if ((dither4[dithy][dithx] < eg) && (g < green_table[255])) g++;
333           if ((dither4[dithy][dithx] < eb) && (b < blue_table[255])) b++;
334
335           pixel = (r << red_offset) | (g << green_offset) | (b << blue_offset);
336
337           switch (o) {
338           case  8: //  8bpp
339             *pixel_data++ = pixel;
340             break;
341
342           case 16: // 16bpp LSB
343             *pixel_data++ = pixel;
344             *pixel_data++ = pixel >> 8;
345             break;
346
347           case 17: // 16bpp MSB
348             *pixel_data++ = pixel >> 8;
349             *pixel_data++ = pixel;
350             break;
351
352           case 24: // 24bpp LSB
353             *pixel_data++ = pixel;
354             *pixel_data++ = pixel >> 8;
355             *pixel_data++ = pixel >> 16;
356             break;
357
358           case 25: // 24bpp MSB
359             *pixel_data++ = pixel >> 16;
360             *pixel_data++ = pixel >> 8;
361             *pixel_data++ = pixel;
362             break;
363
364           case 32: // 32bpp LSB
365             *pixel_data++ = pixel;
366             *pixel_data++ = pixel >> 8;
367             *pixel_data++ = pixel >> 16;
368             *pixel_data++ = pixel >> 24;
369             break;
370
371           case 33: // 32bpp MSB
372             *pixel_data++ = pixel >> 24;
373             *pixel_data++ = pixel >> 16;
374             *pixel_data++ = pixel >> 8;
375             *pixel_data++ = pixel;
376             break;
377           }
378         }
379
380         pixel_data = (ppixel_data += image->bytes_per_line);
381       }
382
383       break;
384
385     case StaticColor:
386     case PseudoColor: {
387 #ifndef   ORDEREDPSEUDO
388       short *terr,
389         *rerr = new short[width + 2],
390         *gerr = new short[width + 2],
391         *berr = new short[width + 2],
392         *nrerr = new short[width + 2],
393         *ngerr = new short[width + 2],
394         *nberr = new short[width + 2];
395       int rr, gg, bb, rer, ger, ber;
396       int dd = 255 / control.getColorsPerChannel();
397
398       for (x = 0; x < width; x++) {
399         *(rerr + x) = *(red + x);
400         *(gerr + x) = *(green + x);
401         *(berr + x) = *(blue + x);
402       }
403
404       *(rerr + x) = *(gerr + x) = *(berr + x) = 0;
405 #endif // ORDEREDPSEUDO
406
407       for (y = 0, offset = 0; y < height; y++) {
408 #ifdef    ORDEREDPSEUDO
409         dithy = y & 7;
410
411         for (x = 0; x < width; x++, offset++) {
412           dithx = x & 7;
413
414           r = red[offset];
415           g = green[offset];
416           b = blue[offset];
417
418           er = r & (red_bits - 1);
419           eg = g & (green_bits - 1);
420           eb = b & (blue_bits - 1);
421
422           r = red_table[r];
423           g = green_table[g];
424           b = blue_table[b];
425
426           if ((dither8[dithy][dithx] < er) && (r < red_table[255])) r++;
427           if ((dither8[dithy][dithx] < eg) && (g < green_table[255])) g++;
428           if ((dither8[dithy][dithx] < eb) && (b < blue_table[255])) b++;
429
430           pixel = (r * cpccpc) + (g * cpc) + b;
431           *(pixel_data++) = colors[pixel].pixel;
432         }
433
434         pixel_data = (ppixel_data += image->bytes_per_line);
435       }
436 #else // !ORDEREDPSEUDO
437       if (y < (height - 1)) {
438         int i = offset + width;
439         for (x = 0; x < width; x++, i++) {
440           *(nrerr + x) = *(red + i);
441           *(ngerr + x) = *(green + i);
442           *(nberr + x) = *(blue + i);
443         }
444
445         *(nrerr + x) = *(red + (--i));
446         *(ngerr + x) = *(green + i);
447         *(nberr + x) = *(blue + i);
448       }
449
450       for (x = 0; x < width; x++) {
451         rr = rerr[x];
452         gg = gerr[x];
453         bb = berr[x];
454
455         if (rr > 255) rr = 255; else if (rr < 0) rr = 0;
456         if (gg > 255) gg = 255; else if (gg < 0) gg = 0;
457         if (bb > 255) bb = 255; else if (bb < 0) bb = 0;
458
459         r = red_table[rr];
460         g = green_table[gg];
461         b = blue_table[bb];
462
463         rer = rerr[x] - r*dd;
464         ger = gerr[x] - g*dd;
465         ber = berr[x] - b*dd;
466
467         pixel = (r * cpccpc) + (g * cpc) + b;
468         *pixel_data++ = colors[pixel].pixel;
469
470         r = rer >> 1;
471         g = ger >> 1;
472         b = ber >> 1;
473         rerr[x+1] += r;
474         gerr[x+1] += g;
475         berr[x+1] += b;
476         nrerr[x] += r;
477         ngerr[x] += g;
478         nberr[x] += b;
479       }
480
481       offset += width;
482
483       pixel_data = (ppixel_data += image->bytes_per_line);
484
485       terr = rerr;
486       rerr = nrerr;
487       nrerr = terr;
488
489       terr = gerr;
490       gerr = ngerr;
491       ngerr = terr;
492
493       terr = berr;
494       berr = nberr;
495       nberr = terr;
496     }
497
498     delete [] rerr;
499     delete [] gerr;
500     delete [] berr;
501     delete [] nrerr;
502     delete [] ngerr;
503     delete [] nberr;
504 #endif // ORDEREDPSUEDO
505
506     break; }
507
508     default:
509       fprintf(stderr, i18n->getMessage(ImageSet, ImageUnsupVisual,
510                          "BImage::renderXImage: unsupported visual\n"));
511       delete [] d;
512       XDestroyImage(image);
513       return (XImage *) 0;
514     }
515   } else {
516     switch (control.getVisual()->c_class) {
517     case StaticColor:
518     case PseudoColor:
519       for (y = 0, offset = 0; y < height; y++) {
520         for (x = 0; x < width; x++, offset++) {
521           r = red_table[red[offset]];
522           g = green_table[green[offset]];
523           b = blue_table[blue[offset]];
524
525           pixel = (r * cpccpc) + (g * cpc) + b;
526           *pixel_data++ = colors[pixel].pixel;
527         }
528
529         pixel_data = (ppixel_data += image->bytes_per_line);
530       }
531
532       break;
533
534   case TrueColor:
535     for (y = 0, offset = 0; y < height; y++) {
536       for (x = 0; x < width; x++, offset++) {
537         r = red_table[red[offset]];
538         g = green_table[green[offset]];
539         b = blue_table[blue[offset]];
540
541         pixel = (r << red_offset) | (g << green_offset) | (b << blue_offset);
542
543         switch (o) {
544         case  8: //  8bpp
545           *pixel_data++ = pixel;
546           break;
547
548         case 16: // 16bpp LSB
549           *pixel_data++ = pixel;
550           *pixel_data++ = pixel >> 8;
551           break;
552
553         case 17: // 16bpp MSB
554           *pixel_data++ = pixel >> 8;
555           *pixel_data++ = pixel;
556           break;
557
558         case 24: // 24bpp LSB
559           *pixel_data++ = pixel;
560           *pixel_data++ = pixel >> 8;
561           *pixel_data++ = pixel >> 16;
562           break;
563
564         case 25: // 24bpp MSB
565           *pixel_data++ = pixel >> 16;
566           *pixel_data++ = pixel >> 8;
567           *pixel_data++ = pixel;
568           break;
569
570         case 32: // 32bpp LSB
571           *pixel_data++ = pixel;
572           *pixel_data++ = pixel >> 8;
573           *pixel_data++ = pixel >> 16;
574           *pixel_data++ = pixel >> 24;
575           break;
576
577         case 33: // 32bpp MSB
578           *pixel_data++ = pixel >> 24;
579           *pixel_data++ = pixel >> 16;
580           *pixel_data++ = pixel >> 8;
581           *pixel_data++ = pixel;
582           break;
583         }
584       }
585
586       pixel_data = (ppixel_data += image->bytes_per_line);
587     }
588
589     break;
590
591   case StaticGray:
592   case GrayScale:
593     for (y = 0, offset = 0; y < height; y++) {
594       for (x = 0; x < width; x++, offset++) {
595         r = *(red_table + *(red + offset));
596         g = *(green_table + *(green + offset));
597         b = *(blue_table + *(blue + offset));
598
599         g = ((r * 30) + (g * 59) + (b * 11)) / 100;
600         *pixel_data++ = colors[g].pixel;
601       }
602
603       pixel_data = (ppixel_data += image->bytes_per_line);
604     }
605
606     break;
607
608   default:
609     fprintf(stderr, i18n->getMessage(ImageSet, ImageUnsupVisual,
610                        "BImage::renderXImage: unsupported visual\n"));
611     delete [] d;
612     XDestroyImage(image);
613     return (XImage *) 0;
614   }
615 }
616
617   image->data = (char *) d;
618   return image;
619 }
620
621
622 Pixmap BImage::renderPixmap(void) {
623   Pixmap pixmap =
624     XCreatePixmap(control.getBaseDisplay().getXDisplay(),
625                   control.getDrawable(), width, height, control.getDepth());
626
627   if (pixmap == None) {
628     fprintf(stderr, i18n->getMessage(ImageSet, ImageErrorCreatingPixmap,
629                              "BImage::renderPixmap: error creating pixmap\n"));
630     return None;
631   }
632
633   XImage *image = renderXImage();
634
635   if (! image) {
636     XFreePixmap(control.getBaseDisplay().getXDisplay(), pixmap);
637     return None;
638   } else if (! image->data) {
639     XDestroyImage(image);
640     XFreePixmap(control.getBaseDisplay().getXDisplay(), pixmap);
641     return None;
642   }
643
644   XPutImage(control.getBaseDisplay().getXDisplay(), pixmap,
645             DefaultGC(control.getBaseDisplay().getXDisplay(),
646                       control.getScreenInfo().getScreenNumber()),
647             image, 0, 0, 0, 0, width, height);
648
649   if (image->data) {
650     delete [] image->data;
651     image->data = NULL;
652   }
653
654   XDestroyImage(image);
655
656   return pixmap;
657 }
658
659
660 void BImage::bevel1(void) {
661   if (width > 2 && height > 2) {
662     unsigned char *pr = red, *pg = green, *pb = blue;
663
664     register unsigned char r, g, b, rr ,gg ,bb;
665     register unsigned int w = width, h = height - 1, wh = w * h;
666
667     while (--w) {
668       r = *pr;
669       rr = r + (r >> 1);
670       if (rr < r) rr = ~0;
671       g = *pg;
672       gg = g + (g >> 1);
673       if (gg < g) gg = ~0;
674       b = *pb;
675       bb = b + (b >> 1);
676       if (bb < b) bb = ~0;
677
678       *pr = rr;
679       *pg = gg;
680       *pb = bb;
681
682       r = *(pr + wh);
683       rr = (r >> 2) + (r >> 1);
684       if (rr > r) rr = 0;
685       g = *(pg + wh);
686       gg = (g >> 2) + (g >> 1);
687       if (gg > g) gg = 0;
688       b = *(pb + wh);
689       bb = (b >> 2) + (b >> 1);
690       if (bb > b) bb = 0;
691
692       *((pr++) + wh) = rr;
693       *((pg++) + wh) = gg;
694       *((pb++) + wh) = bb;
695     }
696
697     r = *pr;
698     rr = r + (r >> 1);
699     if (rr < r) rr = ~0;
700     g = *pg;
701     gg = g + (g >> 1);
702     if (gg < g) gg = ~0;
703     b = *pb;
704     bb = b + (b >> 1);
705     if (bb < b) bb = ~0;
706
707     *pr = rr;
708     *pg = gg;
709     *pb = bb;
710
711     r = *(pr + wh);
712     rr = (r >> 2) + (r >> 1);
713     if (rr > r) rr = 0;
714     g = *(pg + wh);
715     gg = (g >> 2) + (g >> 1);
716     if (gg > g) gg = 0;
717     b = *(pb + wh);
718     bb = (b >> 2) + (b >> 1);
719     if (bb > b) bb = 0;
720
721     *(pr + wh) = rr;
722     *(pg + wh) = gg;
723     *(pb + wh) = bb;
724
725     pr = red + width;
726     pg = green + width;
727     pb = blue + width;
728
729     while (--h) {
730       r = *pr;
731       rr = r + (r >> 1);
732       if (rr < r) rr = ~0;
733       g = *pg;
734       gg = g + (g >> 1);
735       if (gg < g) gg = ~0;
736       b = *pb;
737       bb = b + (b >> 1);
738       if (bb < b) bb = ~0;
739
740       *pr = rr;
741       *pg = gg;
742       *pb = bb;
743
744       pr += width - 1;
745       pg += width - 1;
746       pb += width - 1;
747
748       r = *pr;
749       rr = (r >> 2) + (r >> 1);
750       if (rr > r) rr = 0;
751       g = *pg;
752       gg = (g >> 2) + (g >> 1);
753       if (gg > g) gg = 0;
754       b = *pb;
755       bb = (b >> 2) + (b >> 1);
756       if (bb > b) bb = 0;
757
758       *(pr++) = rr;
759       *(pg++) = gg;
760       *(pb++) = bb;
761     }
762
763     r = *pr;
764     rr = r + (r >> 1);
765     if (rr < r) rr = ~0;
766     g = *pg;
767     gg = g + (g >> 1);
768     if (gg < g) gg = ~0;
769     b = *pb;
770     bb = b + (b >> 1);
771     if (bb < b) bb = ~0;
772
773     *pr = rr;
774     *pg = gg;
775     *pb = bb;
776
777     pr += width - 1;
778     pg += width - 1;
779     pb += width - 1;
780
781     r = *pr;
782     rr = (r >> 2) + (r >> 1);
783     if (rr > r) rr = 0;
784     g = *pg;
785     gg = (g >> 2) + (g >> 1);
786     if (gg > g) gg = 0;
787     b = *pb;
788     bb = (b >> 2) + (b >> 1);
789     if (bb > b) bb = 0;
790
791     *pr = rr;
792     *pg = gg;
793     *pb = bb;
794   }
795 }
796
797
798 void BImage::bevel2(void) {
799   if (width > 4 && height > 4) {
800     unsigned char r, g, b, rr ,gg ,bb, *pr = red + width + 1,
801       *pg = green + width + 1, *pb = blue + width + 1;
802     unsigned int w = width - 2, h = height - 1, wh = width * (height - 3);
803
804     while (--w) {
805       r = *pr;
806       rr = r + (r >> 1);
807       if (rr < r) rr = ~0;
808       g = *pg;
809       gg = g + (g >> 1);
810       if (gg < g) gg = ~0;
811       b = *pb;
812       bb = b + (b >> 1);
813       if (bb < b) bb = ~0;
814
815       *pr = rr;
816       *pg = gg;
817       *pb = bb;
818
819       r = *(pr + wh);
820       rr = (r >> 2) + (r >> 1);
821       if (rr > r) rr = 0;
822       g = *(pg + wh);
823       gg = (g >> 2) + (g >> 1);
824       if (gg > g) gg = 0;
825       b = *(pb + wh);
826       bb = (b >> 2) + (b >> 1);
827       if (bb > b) bb = 0;
828
829       *((pr++) + wh) = rr;
830       *((pg++) + wh) = gg;
831       *((pb++) + wh) = bb;
832     }
833
834     pr = red + width;
835     pg = green + width;
836     pb = blue + width;
837
838     while (--h) {
839       r = *pr;
840       rr = r + (r >> 1);
841       if (rr < r) rr = ~0;
842       g = *pg;
843       gg = g + (g >> 1);
844       if (gg < g) gg = ~0;
845       b = *pb;
846       bb = b + (b >> 1);
847       if (bb < b) bb = ~0;
848
849       *(++pr) = rr;
850       *(++pg) = gg;
851       *(++pb) = bb;
852
853       pr += width - 3;
854       pg += width - 3;
855       pb += width - 3;
856
857       r = *pr;
858       rr = (r >> 2) + (r >> 1);
859       if (rr > r) rr = 0;
860       g = *pg;
861       gg = (g >> 2) + (g >> 1);
862       if (gg > g) gg = 0;
863       b = *pb;
864       bb = (b >> 2) + (b >> 1);
865       if (bb > b) bb = 0;
866
867       *(pr++) = rr;
868       *(pg++) = gg;
869       *(pb++) = bb;
870
871       pr++; pg++; pb++;
872     }
873   }
874 }
875
876
877 void BImage::invert(void) {
878   register unsigned int i, j, wh = (width * height) - 1;
879   unsigned char tmp;
880
881   for (i = 0, j = wh; j > i; j--, i++) {
882     tmp = *(red + j);
883     *(red + j) = *(red + i);
884     *(red + i) = tmp;
885
886     tmp = *(green + j);
887     *(green + j) = *(green + i);
888     *(green + i) = tmp;
889
890     tmp = *(blue + j);
891     *(blue + j) = *(blue + i);
892     *(blue + i) = tmp;
893   }
894 }
895
896
897 void BImage::dgradient(void) {
898   // diagonal gradient code was written by Mike Cole <mike@mydot.com>
899   // modified for interlacing by Brad Hughes
900
901   float drx, dgx, dbx, dry, dgy, dby, yr = 0.0, yg = 0.0, yb = 0.0,
902     xr = (float) from->getRed(),
903     xg = (float) from->getGreen(),
904     xb = (float) from->getBlue();
905   unsigned char *pr = red, *pg = green, *pb = blue;
906   unsigned int w = width * 2, h = height * 2, *xt = xtable, *yt = ytable;
907
908   register unsigned int x, y;
909
910   dry = drx = (float) (to->getRed() - from->getRed());
911   dgy = dgx = (float) (to->getGreen() - from->getGreen());
912   dby = dbx = (float) (to->getBlue() - from->getBlue());
913
914   // Create X table
915   drx /= w;
916   dgx /= w;
917   dbx /= w;
918
919   for (x = 0; x < width; x++) {
920     *(xt++) = (unsigned char) (xr);
921     *(xt++) = (unsigned char) (xg);
922     *(xt++) = (unsigned char) (xb);
923
924     xr += drx;
925     xg += dgx;
926     xb += dbx;
927   }
928
929   // Create Y table
930   dry /= h;
931   dgy /= h;
932   dby /= h;
933
934   for (y = 0; y < height; y++) {
935     *(yt++) = ((unsigned char) yr);
936     *(yt++) = ((unsigned char) yg);
937     *(yt++) = ((unsigned char) yb);
938
939     yr += dry;
940     yg += dgy;
941     yb += dby;
942   }
943
944   // Combine tables to create gradient
945
946 #ifdef    INTERLACE
947   if (! interlaced) {
948 #endif // INTERLACE
949
950     // normal dgradient
951     for (yt = ytable, y = 0; y < height; y++, yt += 3) {
952       for (xt = xtable, x = 0; x < width; x++) {
953         *(pr++) = *(xt++) + *(yt);
954         *(pg++) = *(xt++) + *(yt + 1);
955         *(pb++) = *(xt++) + *(yt + 2);
956       }
957     }
958
959 #ifdef    INTERLACE
960   } else {
961     // faked interlacing effect
962     unsigned char channel, channel2;
963
964     for (yt = ytable, y = 0; y < height; y++, yt += 3) {
965       for (xt = xtable, x = 0; x < width; x++) {
966         if (y & 1) {
967           channel = *(xt++) + *(yt);
968           channel2 = (channel >> 1) + (channel >> 2);
969           if (channel2 > channel) channel2 = 0;
970           *(pr++) = channel2;
971
972           channel = *(xt++) + *(yt + 1);
973           channel2 = (channel >> 1) + (channel >> 2);
974           if (channel2 > channel) channel2 = 0;
975           *(pg++) = channel2;
976
977           channel = *(xt++) + *(yt + 2);
978           channel2 = (channel >> 1) + (channel >> 2);
979           if (channel2 > channel) channel2 = 0;
980           *(pb++) = channel2;
981         } else {
982           channel = *(xt++) + *(yt);
983           channel2 = channel + (channel >> 3);
984           if (channel2 < channel) channel2 = ~0;
985           *(pr++) = channel2;
986
987           channel = *(xt++) + *(yt + 1);
988           channel2 = channel + (channel >> 3);
989           if (channel2 < channel) channel2 = ~0;
990           *(pg++) = channel2;
991
992           channel = *(xt++) + *(yt + 2);
993           channel2 = channel + (channel >> 3);
994           if (channel2 < channel) channel2 = ~0;
995           *(pb++) = channel2;
996         }
997       }
998     }
999   }
1000 #endif // INTERLACE
1001
1002 }
1003
1004
1005 void BImage::hgradient(void) {
1006   float drx, dgx, dbx,
1007     xr = (float) from->getRed(),
1008     xg = (float) from->getGreen(),
1009     xb = (float) from->getBlue();
1010   unsigned char *pr = red, *pg = green, *pb = blue;
1011
1012   register unsigned int x, y;
1013
1014   drx = (float) (to->getRed() - from->getRed());
1015   dgx = (float) (to->getGreen() - from->getGreen());
1016   dbx = (float) (to->getBlue() - from->getBlue());
1017
1018   drx /= width;
1019   dgx /= width;
1020   dbx /= width;
1021
1022 #ifdef    INTERLACE
1023   if (interlaced && height > 2) {
1024     // faked interlacing effect
1025     unsigned char channel, channel2;
1026
1027     for (x = 0; x < width; x++, pr++, pg++, pb++) {
1028       channel = (unsigned char) xr;
1029       channel2 = (channel >> 1) + (channel >> 2);
1030       if (channel2 > channel) channel2 = 0;
1031       *pr = channel2;
1032
1033       channel = (unsigned char) xg;
1034       channel2 = (channel >> 1) + (channel >> 2);
1035       if (channel2 > channel) channel2 = 0;
1036       *pg = channel2;
1037
1038       channel = (unsigned char) xb;
1039       channel2 = (channel >> 1) + (channel >> 2);
1040       if (channel2 > channel) channel2 = 0;
1041       *pb = channel2;
1042
1043
1044       channel = (unsigned char) xr;
1045       channel2 = channel + (channel >> 3);
1046       if (channel2 < channel) channel2 = ~0;
1047       *(pr + width) = channel2;
1048
1049       channel = (unsigned char) xg;
1050       channel2 = channel + (channel >> 3);
1051       if (channel2 < channel) channel2 = ~0;
1052       *(pg + width) = channel2;
1053
1054       channel = (unsigned char) xb;
1055       channel2 = channel + (channel >> 3);
1056       if (channel2 < channel) channel2 = ~0;
1057       *(pb + width) = channel2;
1058
1059       xr += drx;
1060       xg += dgx;
1061       xb += dbx;
1062     }
1063
1064     pr += width;
1065     pg += width;
1066     pb += width;
1067
1068     int offset;
1069
1070     for (y = 2; y < height; y++, pr += width, pg += width, pb += width) {
1071       if (y & 1) offset = width; else offset = 0;
1072
1073       memcpy(pr, (red + offset), width);
1074       memcpy(pg, (green + offset), width);
1075       memcpy(pb, (blue + offset), width);
1076     }
1077   } else {
1078 #endif // INTERLACE
1079
1080     // normal hgradient
1081     for (x = 0; x < width; x++) {
1082       *(pr++) = (unsigned char) (xr);
1083       *(pg++) = (unsigned char) (xg);
1084       *(pb++) = (unsigned char) (xb);
1085
1086       xr += drx;
1087       xg += dgx;
1088       xb += dbx;
1089     }
1090
1091     for (y = 1; y < height; y++, pr += width, pg += width, pb += width) {
1092       memcpy(pr, red, width);
1093       memcpy(pg, green, width);
1094       memcpy(pb, blue, width);
1095     }
1096
1097 #ifdef    INTERLACE
1098   }
1099 #endif // INTERLACE
1100
1101 }
1102
1103
1104 void BImage::vgradient(void) {
1105   float dry, dgy, dby,
1106     yr = (float) from->getRed(),
1107     yg = (float) from->getGreen(),
1108     yb = (float) from->getBlue();
1109   unsigned char *pr = red, *pg = green, *pb = blue;
1110
1111   register unsigned int y;
1112
1113   dry = (float) (to->getRed() - from->getRed());
1114   dgy = (float) (to->getGreen() - from->getGreen());
1115   dby = (float) (to->getBlue() - from->getBlue());
1116
1117   dry /= height;
1118   dgy /= height;
1119   dby /= height;
1120
1121 #ifdef    INTERLACE
1122   if (interlaced) {
1123     // faked interlacing effect
1124     unsigned char channel, channel2;
1125
1126     for (y = 0; y < height; y++, pr += width, pg += width, pb += width) {
1127       if (y & 1) {
1128         channel = (unsigned char) yr;
1129         channel2 = (channel >> 1) + (channel >> 2);
1130         if (channel2 > channel) channel2 = 0;
1131         memset(pr, channel2, width);
1132
1133         channel = (unsigned char) yg;
1134         channel2 = (channel >> 1) + (channel >> 2);
1135         if (channel2 > channel) channel2 = 0;
1136         memset(pg, channel2, width);
1137
1138         channel = (unsigned char) yb;
1139         channel2 = (channel >> 1) + (channel >> 2);
1140         if (channel2 > channel) channel2 = 0;
1141         memset(pb, channel2, width);
1142       } else {
1143         channel = (unsigned char) yr;
1144         channel2 = channel + (channel >> 3);
1145         if (channel2 < channel) channel2 = ~0;
1146         memset(pr, channel2, width);
1147
1148         channel = (unsigned char) yg;
1149         channel2 = channel + (channel >> 3);
1150         if (channel2 < channel) channel2 = ~0;
1151         memset(pg, channel2, width);
1152
1153         channel = (unsigned char) yb;
1154         channel2 = channel + (channel >> 3);
1155         if (channel2 < channel) channel2 = ~0;
1156         memset(pb, channel2, width);
1157       }
1158
1159       yr += dry;
1160       yg += dgy;
1161       yb += dby;
1162     }
1163   } else {
1164 #endif // INTERLACE
1165
1166     // normal vgradient
1167     for (y = 0; y < height; y++, pr += width, pg += width, pb += width) {
1168       memset(pr, (unsigned char) yr, width);
1169       memset(pg, (unsigned char) yg, width);
1170       memset(pb, (unsigned char) yb, width);
1171
1172       yr += dry;
1173       yg += dgy;
1174       yb += dby;
1175     }
1176
1177 #ifdef    INTERLACE
1178   }
1179 #endif // INTERLACE
1180
1181 }
1182
1183
1184 void BImage::pgradient(void) {
1185   // pyramid gradient -  based on original dgradient, written by
1186   // Mosfet (mosfet@kde.org)
1187   // adapted from kde sources for Openbox by Brad Hughes
1188
1189   float yr, yg, yb, drx, dgx, dbx, dry, dgy, dby,
1190     xr, xg, xb;
1191   int rsign, gsign, bsign;
1192   unsigned char *pr = red, *pg = green, *pb = blue;
1193   unsigned int tr = to->getRed(), tg = to->getGreen(), tb = to->getBlue(),
1194     *xt = xtable, *yt = ytable;
1195
1196   register unsigned int x, y;
1197
1198   dry = drx = (float) (to->getRed() - from->getRed());
1199   dgy = dgx = (float) (to->getGreen() - from->getGreen());
1200   dby = dbx = (float) (to->getBlue() - from->getBlue());
1201
1202   rsign = (drx < 0) ? -1 : 1;
1203   gsign = (dgx < 0) ? -1 : 1;
1204   bsign = (dbx < 0) ? -1 : 1;
1205
1206   xr = yr = (drx / 2);
1207   xg = yg = (dgx / 2);
1208   xb = yb = (dbx / 2);
1209
1210   // Create X table
1211   drx /= width;
1212   dgx /= width;
1213   dbx /= width;
1214
1215   for (x = 0; x < width; x++) {
1216     *(xt++) = (unsigned char) ((xr < 0) ? -xr : xr);
1217     *(xt++) = (unsigned char) ((xg < 0) ? -xg : xg);
1218     *(xt++) = (unsigned char) ((xb < 0) ? -xb : xb);
1219
1220     xr -= drx;
1221     xg -= dgx;
1222     xb -= dbx;
1223   }
1224
1225   // Create Y table
1226   dry /= height;
1227   dgy /= height;
1228   dby /= height;
1229
1230   for (y = 0; y < height; y++) {
1231     *(yt++) = ((unsigned char) ((yr < 0) ? -yr : yr));
1232     *(yt++) = ((unsigned char) ((yg < 0) ? -yg : yg));
1233     *(yt++) = ((unsigned char) ((yb < 0) ? -yb : yb));
1234
1235     yr -= dry;
1236     yg -= dgy;
1237     yb -= dby;
1238   }
1239
1240   // Combine tables to create gradient
1241
1242 #ifdef    INTERLACE
1243   if (! interlaced) {
1244 #endif // INTERLACE
1245
1246     // normal pgradient
1247     for (yt = ytable, y = 0; y < height; y++, yt += 3) {
1248       for (xt = xtable, x = 0; x < width; x++) {
1249         *(pr++) = (unsigned char) (tr - (rsign * (*(xt++) + *(yt))));
1250         *(pg++) = (unsigned char) (tg - (gsign * (*(xt++) + *(yt + 1))));
1251         *(pb++) = (unsigned char) (tb - (bsign * (*(xt++) + *(yt + 2))));
1252       }
1253     }
1254
1255 #ifdef    INTERLACE
1256   } else {
1257     // faked interlacing effect
1258     unsigned char channel, channel2;
1259
1260     for (yt = ytable, y = 0; y < height; y++, yt += 3) {
1261       for (xt = xtable, x = 0; x < width; x++) {
1262         if (y & 1) {
1263           channel = (unsigned char) (tr - (rsign * (*(xt++) + *(yt))));
1264           channel2 = (channel >> 1) + (channel >> 2);
1265           if (channel2 > channel) channel2 = 0;
1266           *(pr++) = channel2;
1267
1268           channel = (unsigned char) (tg - (gsign * (*(xt++) + *(yt + 1))));
1269           channel2 = (channel >> 1) + (channel >> 2);
1270           if (channel2 > channel) channel2 = 0;
1271           *(pg++) = channel2;
1272
1273           channel = (unsigned char) (tb - (bsign * (*(xt++) + *(yt + 2))));
1274           channel2 = (channel >> 1) + (channel >> 2);
1275           if (channel2 > channel) channel2 = 0;
1276           *(pb++) = channel2;
1277         } else {
1278           channel = (unsigned char) (tr - (rsign * (*(xt++) + *(yt))));
1279           channel2 = channel + (channel >> 3);
1280           if (channel2 < channel) channel2 = ~0;
1281           *(pr++) = channel2;
1282
1283           channel = (unsigned char) (tg - (gsign * (*(xt++) + *(yt + 1))));
1284           channel2 = channel + (channel >> 3);
1285           if (channel2 < channel) channel2 = ~0;
1286           *(pg++) = channel2;
1287
1288           channel = (unsigned char) (tb - (bsign * (*(xt++) + *(yt + 2))));
1289           channel2 = channel + (channel >> 3);
1290           if (channel2 < channel) channel2 = ~0;
1291           *(pb++) = channel2;
1292         }
1293       }
1294     }
1295   }
1296 #endif // INTERLACE
1297 }
1298
1299
1300 void BImage::rgradient(void) {
1301   // rectangle gradient -  based on original dgradient, written by
1302   // Mosfet (mosfet@kde.org)
1303   // adapted from kde sources for Openbox by Brad Hughes
1304
1305   float drx, dgx, dbx, dry, dgy, dby, xr, xg, xb, yr, yg, yb;
1306   int rsign, gsign, bsign;
1307   unsigned char *pr = red, *pg = green, *pb = blue;
1308   unsigned int tr = to->getRed(), tg = to->getGreen(), tb = to->getBlue(),
1309     *xt = xtable, *yt = ytable;
1310
1311   register unsigned int x, y;
1312
1313   dry = drx = (float) (to->getRed() - from->getRed());
1314   dgy = dgx = (float) (to->getGreen() - from->getGreen());
1315   dby = dbx = (float) (to->getBlue() - from->getBlue());
1316
1317   rsign = (drx < 0) ? -2 : 2;
1318   gsign = (dgx < 0) ? -2 : 2;
1319   bsign = (dbx < 0) ? -2 : 2;
1320
1321   xr = yr = (drx / 2);
1322   xg = yg = (dgx / 2);
1323   xb = yb = (dbx / 2);
1324
1325   // Create X table
1326   drx /= width;
1327   dgx /= width;
1328   dbx /= width;
1329
1330   for (x = 0; x < width; x++) {
1331     *(xt++) = (unsigned char) ((xr < 0) ? -xr : xr);
1332     *(xt++) = (unsigned char) ((xg < 0) ? -xg : xg);
1333     *(xt++) = (unsigned char) ((xb < 0) ? -xb : xb);
1334
1335     xr -= drx;
1336     xg -= dgx;
1337     xb -= dbx;
1338   }
1339
1340   // Create Y table
1341   dry /= height;
1342   dgy /= height;
1343   dby /= height;
1344
1345   for (y = 0; y < height; y++) {
1346     *(yt++) = ((unsigned char) ((yr < 0) ? -yr : yr));
1347     *(yt++) = ((unsigned char) ((yg < 0) ? -yg : yg));
1348     *(yt++) = ((unsigned char) ((yb < 0) ? -yb : yb));
1349
1350     yr -= dry;
1351     yg -= dgy;
1352     yb -= dby;
1353   }
1354
1355   // Combine tables to create gradient
1356
1357 #ifdef    INTERLACE
1358   if (! interlaced) {
1359 #endif // INTERLACE
1360
1361     // normal rgradient
1362     for (yt = ytable, y = 0; y < height; y++, yt += 3) {
1363       for (xt = xtable, x = 0; x < width; x++) {
1364         *(pr++) = (unsigned char) (tr - (rsign * max(*(xt++), *(yt))));
1365         *(pg++) = (unsigned char) (tg - (gsign * max(*(xt++), *(yt + 1))));
1366         *(pb++) = (unsigned char) (tb - (bsign * max(*(xt++), *(yt + 2))));
1367       }
1368     }
1369
1370 #ifdef    INTERLACE
1371   } else {
1372     // faked interlacing effect
1373     unsigned char channel, channel2;
1374
1375     for (yt = ytable, y = 0; y < height; y++, yt += 3) {
1376       for (xt = xtable, x = 0; x < width; x++) {
1377         if (y & 1) {
1378           channel = (unsigned char) (tr - (rsign * max(*(xt++), *(yt))));
1379           channel2 = (channel >> 1) + (channel >> 2);
1380           if (channel2 > channel) channel2 = 0;
1381           *(pr++) = channel2;
1382
1383           channel = (unsigned char) (tg - (gsign * max(*(xt++), *(yt + 1))));
1384           channel2 = (channel >> 1) + (channel >> 2);
1385           if (channel2 > channel) channel2 = 0;
1386           *(pg++) = channel2;
1387
1388           channel = (unsigned char) (tb - (bsign * max(*(xt++), *(yt + 2))));
1389           channel2 = (channel >> 1) + (channel >> 2);
1390           if (channel2 > channel) channel2 = 0;
1391           *(pb++) = channel2;
1392         } else {
1393           channel = (unsigned char) (tr - (rsign * max(*(xt++), *(yt))));
1394           channel2 = channel + (channel >> 3);
1395           if (channel2 < channel) channel2 = ~0;
1396           *(pr++) = channel2;
1397
1398           channel = (unsigned char) (tg - (gsign * max(*(xt++), *(yt + 1))));
1399           channel2 = channel + (channel >> 3);
1400           if (channel2 < channel) channel2 = ~0;
1401           *(pg++) = channel2;
1402
1403           channel = (unsigned char) (tb - (bsign * max(*(xt++), *(yt + 2))));
1404           channel2 = channel + (channel >> 3);
1405           if (channel2 < channel) channel2 = ~0;
1406           *(pb++) = channel2;
1407         }
1408       }
1409     }
1410   }
1411 #endif // INTERLACE
1412 }
1413
1414
1415 void BImage::egradient(void) {
1416   // elliptic gradient -  based on original dgradient, written by
1417   // Mosfet (mosfet@kde.org)
1418   // adapted from kde sources for Openbox by Brad Hughes
1419
1420   float drx, dgx, dbx, dry, dgy, dby, yr, yg, yb, xr, xg, xb;
1421   int rsign, gsign, bsign;
1422   unsigned char *pr = red, *pg = green, *pb = blue;
1423   unsigned int *xt = xtable, *yt = ytable,
1424     tr = (unsigned long) to->getRed(),
1425     tg = (unsigned long) to->getGreen(),
1426     tb = (unsigned long) to->getBlue();
1427
1428   register unsigned int x, y;
1429
1430   dry = drx = (float) (to->getRed() - from->getRed());
1431   dgy = dgx = (float) (to->getGreen() - from->getGreen());
1432   dby = dbx = (float) (to->getBlue() - from->getBlue());
1433
1434   rsign = (drx < 0) ? -1 : 1;
1435   gsign = (dgx < 0) ? -1 : 1;
1436   bsign = (dbx < 0) ? -1 : 1;
1437
1438   xr = yr = (drx / 2);
1439   xg = yg = (dgx / 2);
1440   xb = yb = (dbx / 2);
1441
1442   // Create X table
1443   drx /= width;
1444   dgx /= width;
1445   dbx /= width;
1446
1447   for (x = 0; x < width; x++) {
1448     *(xt++) = (unsigned long) (xr * xr);
1449     *(xt++) = (unsigned long) (xg * xg);
1450     *(xt++) = (unsigned long) (xb * xb);
1451
1452     xr -= drx;
1453     xg -= dgx;
1454     xb -= dbx;
1455   }
1456
1457   // Create Y table
1458   dry /= height;
1459   dgy /= height;
1460   dby /= height;
1461
1462   for (y = 0; y < height; y++) {
1463     *(yt++) = (unsigned long) (yr * yr);
1464     *(yt++) = (unsigned long) (yg * yg);
1465     *(yt++) = (unsigned long) (yb * yb);
1466
1467     yr -= dry;
1468     yg -= dgy;
1469     yb -= dby;
1470   }
1471
1472   // Combine tables to create gradient
1473
1474 #ifdef    INTERLACE
1475   if (! interlaced) {
1476 #endif // INTERLACE
1477
1478     // normal egradient
1479     for (yt = ytable, y = 0; y < height; y++, yt += 3) {
1480       for (xt = xtable, x = 0; x < width; x++) {
1481         *(pr++) = (unsigned char)
1482           (tr - (rsign * control.getSqrt(*(xt++) + *(yt))));
1483         *(pg++) = (unsigned char)
1484           (tg - (gsign * control.getSqrt(*(xt++) + *(yt + 1))));
1485         *(pb++) = (unsigned char)
1486           (tb - (bsign * control.getSqrt(*(xt++) + *(yt + 2))));
1487       }
1488     }
1489
1490 #ifdef    INTERLACE
1491   } else {
1492     // faked interlacing effect
1493     unsigned char channel, channel2;
1494
1495     for (yt = ytable, y = 0; y < height; y++, yt += 3) {
1496       for (xt = xtable, x = 0; x < width; x++) {
1497         if (y & 1) {
1498           channel = (unsigned char)
1499             (tr - (rsign * control.getSqrt(*(xt++) + *(yt))));
1500           channel2 = (channel >> 1) + (channel >> 2);
1501           if (channel2 > channel) channel2 = 0;
1502           *(pr++) = channel2;
1503
1504           channel = (unsigned char)
1505             (tg - (gsign * control.getSqrt(*(xt++) + *(yt + 1))));
1506           channel2 = (channel >> 1) + (channel >> 2);
1507           if (channel2 > channel) channel2 = 0;
1508           *(pg++) = channel2;
1509
1510           channel = (unsigned char)
1511             (tb - (bsign * control.getSqrt(*(xt++) + *(yt + 2))));
1512           channel2 = (channel >> 1) + (channel >> 2);
1513           if (channel2 > channel) channel2 = 0;
1514           *(pb++) = channel2;
1515         } else {
1516           channel = (unsigned char)
1517             (tr - (rsign * control.getSqrt(*(xt++) + *(yt))));
1518           channel2 = channel + (channel >> 3);
1519           if (channel2 < channel) channel2 = ~0;
1520           *(pr++) = channel2;
1521
1522           channel = (unsigned char)
1523           (tg - (gsign * control.getSqrt(*(xt++) + *(yt + 1))));
1524           channel2 = channel + (channel >> 3);
1525           if (channel2 < channel) channel2 = ~0;
1526           *(pg++) = channel2;
1527
1528           channel = (unsigned char)
1529             (tb - (bsign * control.getSqrt(*(xt++) + *(yt + 2))));
1530           channel2 = channel + (channel >> 3);
1531           if (channel2 < channel) channel2 = ~0;
1532           *(pb++) = channel2;
1533         }
1534       }
1535     }
1536   }
1537 #endif // INTERLACE
1538 }
1539
1540
1541 void BImage::pcgradient(void) {
1542   // pipe cross gradient -  based on original dgradient, written by
1543   // Mosfet (mosfet@kde.org)
1544   // adapted from kde sources for Openbox by Brad Hughes
1545
1546   float drx, dgx, dbx, dry, dgy, dby, xr, xg, xb, yr, yg, yb;
1547   int rsign, gsign, bsign;
1548   unsigned char *pr = red, *pg = green, *pb = blue;
1549   unsigned int *xt = xtable, *yt = ytable,
1550     tr = to->getRed(),
1551     tg = to->getGreen(),
1552     tb = to->getBlue();
1553
1554   register unsigned int x, y;
1555
1556   dry = drx = (float) (to->getRed() - from->getRed());
1557   dgy = dgx = (float) (to->getGreen() - from->getGreen());
1558   dby = dbx = (float) (to->getBlue() - from->getBlue());
1559
1560   rsign = (drx < 0) ? -2 : 2;
1561   gsign = (dgx < 0) ? -2 : 2;
1562   bsign = (dbx < 0) ? -2 : 2;
1563
1564   xr = yr = (drx / 2);
1565   xg = yg = (dgx / 2);
1566   xb = yb = (dbx / 2);
1567
1568   // Create X table
1569   drx /= width;
1570   dgx /= width;
1571   dbx /= width;
1572
1573   for (x = 0; x < width; x++) {
1574     *(xt++) = (unsigned char) ((xr < 0) ? -xr : xr);
1575     *(xt++) = (unsigned char) ((xg < 0) ? -xg : xg);
1576     *(xt++) = (unsigned char) ((xb < 0) ? -xb : xb);
1577
1578     xr -= drx;
1579     xg -= dgx;
1580     xb -= dbx;
1581   }
1582
1583   // Create Y table
1584   dry /= height;
1585   dgy /= height;
1586   dby /= height;
1587
1588   for (y = 0; y < height; y++) {
1589     *(yt++) = ((unsigned char) ((yr < 0) ? -yr : yr));
1590     *(yt++) = ((unsigned char) ((yg < 0) ? -yg : yg));
1591     *(yt++) = ((unsigned char) ((yb < 0) ? -yb : yb));
1592
1593     yr -= dry;
1594     yg -= dgy;
1595     yb -= dby;
1596   }
1597
1598   // Combine tables to create gradient
1599
1600 #ifdef    INTERLACE
1601   if (! interlaced) {
1602 #endif // INTERLACE
1603
1604     // normal pcgradient
1605     for (yt = ytable, y = 0; y < height; y++, yt += 3) {
1606       for (xt = xtable, x = 0; x < width; x++) {
1607         *(pr++) = (unsigned char) (tr - (rsign * min(*(xt++), *(yt))));
1608         *(pg++) = (unsigned char) (tg - (gsign * min(*(xt++), *(yt + 1))));
1609         *(pb++) = (unsigned char) (tb - (bsign * min(*(xt++), *(yt + 2))));
1610       }
1611     }
1612
1613 #ifdef    INTERLACE
1614   } else {
1615     // faked interlacing effect
1616     unsigned char channel, channel2;
1617
1618     for (yt = ytable, y = 0; y < height; y++, yt += 3) {
1619       for (xt = xtable, x = 0; x < width; x++) {
1620         if (y & 1) {
1621           channel = (unsigned char) (tr - (rsign * min(*(xt++), *(yt))));
1622           channel2 = (channel >> 1) + (channel >> 2);
1623           if (channel2 > channel) channel2 = 0;
1624           *(pr++) = channel2;
1625
1626           channel = (unsigned char) (tg - (bsign * min(*(xt++), *(yt + 1))));
1627           channel2 = (channel >> 1) + (channel >> 2);
1628           if (channel2 > channel) channel2 = 0;
1629           *(pg++) = channel2;
1630
1631           channel = (unsigned char) (tb - (gsign * min(*(xt++), *(yt + 2))));
1632           channel2 = (channel >> 1) + (channel >> 2);
1633           if (channel2 > channel) channel2 = 0;
1634           *(pb++) = channel2;
1635         } else {
1636           channel = (unsigned char) (tr - (rsign * min(*(xt++), *(yt))));
1637           channel2 = channel + (channel >> 3);
1638           if (channel2 < channel) channel2 = ~0;
1639           *(pr++) = channel2;
1640
1641           channel = (unsigned char) (tg - (gsign * min(*(xt++), *(yt + 1))));
1642           channel2 = channel + (channel >> 3);
1643           if (channel2 < channel) channel2 = ~0;
1644           *(pg++) = channel2;
1645
1646           channel = (unsigned char) (tb - (bsign * min(*(xt++), *(yt + 2))));
1647           channel2 = channel + (channel >> 3);
1648           if (channel2 < channel) channel2 = ~0;
1649           *(pb++) = channel2;
1650         }
1651       }
1652     }
1653   }
1654 #endif // INTERLACE
1655 }
1656
1657
1658 void BImage::cdgradient(void) {
1659   // cross diagonal gradient -  based on original dgradient, written by
1660   // Mosfet (mosfet@kde.org)
1661   // adapted from kde sources for Openbox by Brad Hughes
1662
1663   float drx, dgx, dbx, dry, dgy, dby, yr = 0.0, yg = 0.0, yb = 0.0,
1664     xr = (float) from->getRed(),
1665     xg = (float) from->getGreen(),
1666     xb = (float) from->getBlue();
1667   unsigned char *pr = red, *pg = green, *pb = blue;
1668   unsigned int w = width * 2, h = height * 2, *xt, *yt;
1669
1670   register unsigned int x, y;
1671
1672   dry = drx = (float) (to->getRed() - from->getRed());
1673   dgy = dgx = (float) (to->getGreen() - from->getGreen());
1674   dby = dbx = (float) (to->getBlue() - from->getBlue());
1675
1676   // Create X table
1677   drx /= w;
1678   dgx /= w;
1679   dbx /= w;
1680
1681   for (xt = (xtable + (width * 3) - 1), x = 0; x < width; x++) {
1682     *(xt--) = (unsigned char) xb;
1683     *(xt--) = (unsigned char) xg;
1684     *(xt--) = (unsigned char) xr;
1685
1686     xr += drx;
1687     xg += dgx;
1688     xb += dbx;
1689   }
1690
1691   // Create Y table
1692   dry /= h;
1693   dgy /= h;
1694   dby /= h;
1695
1696   for (yt = ytable, y = 0; y < height; y++) {
1697     *(yt++) = (unsigned char) yr;
1698     *(yt++) = (unsigned char) yg;
1699     *(yt++) = (unsigned char) yb;
1700
1701     yr += dry;
1702     yg += dgy;
1703     yb += dby;
1704   }
1705
1706   // Combine tables to create gradient
1707
1708 #ifdef    INTERLACE
1709   if (! interlaced) {
1710 #endif // INTERLACE
1711
1712     // normal cdgradient
1713     for (yt = ytable, y = 0; y < height; y++, yt += 3) {
1714       for (xt = xtable, x = 0; x < width; x++) {
1715         *(pr++) = *(xt++) + *(yt);
1716         *(pg++) = *(xt++) + *(yt + 1);
1717         *(pb++) = *(xt++) + *(yt + 2);
1718       }
1719     }
1720
1721 #ifdef    INTERLACE
1722   } else {
1723     // faked interlacing effect
1724     unsigned char channel, channel2;
1725
1726     for (yt = ytable, y = 0; y < height; y++, yt += 3) {
1727       for (xt = xtable, x = 0; x < width; x++) {
1728         if (y & 1) {
1729           channel = *(xt++) + *(yt);
1730           channel2 = (channel >> 1) + (channel >> 2);
1731           if (channel2 > channel) channel2 = 0;
1732           *(pr++) = channel2;
1733
1734           channel = *(xt++) + *(yt + 1);
1735           channel2 = (channel >> 1) + (channel >> 2);
1736           if (channel2 > channel) channel2 = 0;
1737           *(pg++) = channel2;
1738
1739           channel = *(xt++) + *(yt + 2);
1740           channel2 = (channel >> 1) + (channel >> 2);
1741           if (channel2 > channel) channel2 = 0;
1742           *(pb++) = channel2;
1743         } else {
1744           channel = *(xt++) + *(yt);
1745           channel2 = channel + (channel >> 3);
1746           if (channel2 < channel) channel2 = ~0;
1747           *(pr++) = channel2;
1748
1749           channel = *(xt++) + *(yt + 1);
1750           channel2 = channel + (channel >> 3);
1751           if (channel2 < channel) channel2 = ~0;
1752           *(pg++) = channel2;
1753
1754           channel = *(xt++) + *(yt + 2);
1755           channel2 = channel + (channel >> 3);
1756           if (channel2 < channel) channel2 = ~0;
1757           *(pb++) = channel2;
1758         }
1759       }
1760     }
1761   }
1762 #endif // INTERLACE
1763 }
1764
1765
1766 BImageControl::BImageControl(BaseDisplay &dpy, ScreenInfo &scrn, Bool _dither,
1767                              int _cpc, unsigned long cache_timeout,
1768                              unsigned long cmax) : basedisplay(dpy),
1769                              screeninfo(scrn)
1770 {
1771   setDither(_dither);
1772   setColorsPerChannel(_cpc);
1773
1774   cache_max = cmax;
1775 #ifdef    TIMEDCACHE
1776   if (cache_timeout) {
1777     timer = new BTimer(basedisplay, *this);
1778     timer->setTimeout(cache_timeout);
1779     timer->start();
1780   } else
1781     timer = (BTimer *) 0;
1782 #endif // TIMEDCACHE
1783
1784   colors = (XColor *) 0;
1785   ncolors = 0;
1786
1787   grad_xbuffer = grad_ybuffer = (unsigned int *) 0;
1788   grad_buffer_width = grad_buffer_height = 0;
1789
1790   sqrt_table = (unsigned long *) 0;
1791
1792   screen_depth = screeninfo.getDepth();
1793   window = screeninfo.getRootWindow();
1794   screen_number = screeninfo.getScreenNumber();
1795
1796   int count;
1797   XPixmapFormatValues *pmv = XListPixmapFormats(basedisplay.getXDisplay(),
1798                                                 &count);
1799   colormap = screeninfo.getColormap();
1800
1801   if (pmv) {
1802     bits_per_pixel = 0;
1803     for (int i = 0; i < count; i++)
1804       if (pmv[i].depth == screen_depth) {
1805         bits_per_pixel = pmv[i].bits_per_pixel;
1806         break;
1807       }
1808
1809     XFree(pmv);
1810   }
1811
1812   if (bits_per_pixel == 0) bits_per_pixel = screen_depth;
1813   if (bits_per_pixel >= 24) setDither(False);
1814
1815   red_offset = green_offset = blue_offset = 0;
1816
1817   switch (getVisual()->c_class) {
1818   case TrueColor:
1819     {
1820       int i;
1821
1822       // compute color tables
1823       unsigned long red_mask = getVisual()->red_mask,
1824         green_mask = getVisual()->green_mask,
1825         blue_mask = getVisual()->blue_mask;
1826
1827       while (! (red_mask & 1)) { red_offset++; red_mask >>= 1; }
1828       while (! (green_mask & 1)) { green_offset++; green_mask >>= 1; }
1829       while (! (blue_mask & 1)) { blue_offset++; blue_mask >>= 1; }
1830
1831       red_bits = 255 / red_mask;
1832       green_bits = 255 / green_mask;
1833       blue_bits = 255 / blue_mask;
1834
1835       for (i = 0; i < 256; i++) {
1836         red_color_table[i] = i / red_bits;
1837         green_color_table[i] = i / green_bits;
1838         blue_color_table[i] = i / blue_bits;
1839       }
1840     }
1841
1842     break;
1843
1844   case PseudoColor:
1845   case StaticColor:
1846     {
1847       ncolors = colors_per_channel * colors_per_channel * colors_per_channel;
1848
1849       if (ncolors > (1 << screen_depth)) {
1850         colors_per_channel = (1 << screen_depth) / 3;
1851         ncolors = colors_per_channel * colors_per_channel * colors_per_channel;
1852       }
1853
1854       if (colors_per_channel < 2 || ncolors > (1 << screen_depth)) {
1855         fprintf(stderr, i18n->getMessage(ImageSet, ImageInvalidColormapSize,
1856                       "BImageControl::BImageControl: invalid colormap size %d "
1857                            "(%d/%d/%d) - reducing"),
1858                 ncolors, colors_per_channel, colors_per_channel,
1859                 colors_per_channel);
1860
1861         colors_per_channel = (1 << screen_depth) / 3;
1862       }
1863
1864       colors = new XColor[ncolors];
1865       if (! colors) {
1866         fprintf(stderr, i18n->getMessage(ImageSet,
1867                                          ImageErrorAllocatingColormap,
1868                            "BImageControl::BImageControl: error allocating "
1869                            "colormap\n"));
1870         exit(1);
1871       }
1872
1873       int i = 0, ii, p, r, g, b,
1874
1875 #ifdef    ORDEREDPSEUDO
1876         bits = 256 / colors_per_channel;
1877 #else // !ORDEREDPSEUDO
1878         bits = 255 / (colors_per_channel - 1);
1879 #endif // ORDEREDPSEUDO
1880
1881       red_bits = green_bits = blue_bits = bits;
1882
1883       for (i = 0; i < 256; i++)
1884         red_color_table[i] = green_color_table[i] = blue_color_table[i] =
1885           i / bits;
1886
1887       for (r = 0, i = 0; r < colors_per_channel; r++)
1888         for (g = 0; g < colors_per_channel; g++)
1889           for (b = 0; b < colors_per_channel; b++, i++) {
1890             colors[i].red = (r * 0xffff) / (colors_per_channel - 1);
1891             colors[i].green = (g * 0xffff) / (colors_per_channel - 1);
1892             colors[i].blue = (b * 0xffff) / (colors_per_channel - 1);;
1893             colors[i].flags = DoRed|DoGreen|DoBlue;
1894           }
1895
1896       basedisplay.grab();
1897
1898       for (i = 0; i < ncolors; i++)
1899         if (! XAllocColor(basedisplay.getXDisplay(), colormap, &colors[i])) {
1900           fprintf(stderr, i18n->getMessage(ImageSet, ImageColorAllocFail,
1901                                    "couldn't alloc color %i %i %i\n"),
1902                   colors[i].red, colors[i].green, colors[i].blue);
1903           colors[i].flags = 0;
1904         } else
1905           colors[i].flags = DoRed|DoGreen|DoBlue;
1906
1907       basedisplay.ungrab();
1908
1909       XColor icolors[256];
1910       int incolors = (((1 << screen_depth) > 256) ? 256 : (1 << screen_depth));
1911
1912       for (i = 0; i < incolors; i++)
1913         icolors[i].pixel = i;
1914
1915       XQueryColors(basedisplay.getXDisplay(), colormap, icolors, incolors);
1916       for (i = 0; i < ncolors; i++) {
1917         if (! colors[i].flags) {
1918           unsigned long chk = 0xffffffff, pixel, close = 0;
1919
1920           p = 2;
1921           while (p--) {
1922             for (ii = 0; ii < incolors; ii++) {
1923               r = (colors[i].red - icolors[i].red) >> 8;
1924               g = (colors[i].green - icolors[i].green) >> 8;
1925               b = (colors[i].blue - icolors[i].blue) >> 8;
1926               pixel = (r * r) + (g * g) + (b * b);
1927
1928               if (pixel < chk) {
1929                 chk = pixel;
1930                 close = ii;
1931               }
1932
1933               colors[i].red = icolors[close].red;
1934               colors[i].green = icolors[close].green;
1935               colors[i].blue = icolors[close].blue;
1936
1937               if (XAllocColor(basedisplay.getXDisplay(), colormap,
1938                               &colors[i])) {
1939                 colors[i].flags = DoRed|DoGreen|DoBlue;
1940                 break;
1941               }
1942             }
1943           }
1944         }
1945       }
1946
1947       break;
1948     }
1949
1950   case GrayScale:
1951   case StaticGray:
1952     {
1953
1954       if (getVisual()->c_class == StaticGray) {
1955         ncolors = 1 << screen_depth;
1956       } else {
1957         ncolors = colors_per_channel * colors_per_channel * colors_per_channel;
1958
1959         if (ncolors > (1 << screen_depth)) {
1960           colors_per_channel = (1 << screen_depth) / 3;
1961           ncolors =
1962             colors_per_channel * colors_per_channel * colors_per_channel;
1963         }
1964       }
1965
1966       if (colors_per_channel < 2 || ncolors > (1 << screen_depth)) {
1967         fprintf(stderr, i18n->getMessage(ImageSet, ImageInvalidColormapSize,
1968                       "BImageControl::BImageControl: invalid colormap size %d "
1969                            "(%d/%d/%d) - reducing"),
1970                 ncolors, colors_per_channel, colors_per_channel,
1971                 colors_per_channel);
1972
1973         colors_per_channel = (1 << screen_depth) / 3;
1974       }
1975
1976       colors = new XColor[ncolors];
1977       if (! colors) {
1978         fprintf(stderr, i18n->getMessage(ImageSet,
1979                                          ImageErrorAllocatingColormap,
1980                            "BImageControl::BImageControl: error allocating "
1981                            "colormap\n"));
1982         exit(1);
1983       }
1984
1985       int i = 0, ii, p, bits = 255 / (colors_per_channel - 1);
1986       red_bits = green_bits = blue_bits = bits;
1987
1988       for (i = 0; i < 256; i++)
1989         red_color_table[i] = green_color_table[i] = blue_color_table[i] =
1990           i / bits;
1991
1992       basedisplay.grab();
1993       for (i = 0; i < ncolors; i++) {
1994         colors[i].red = (i * 0xffff) / (colors_per_channel - 1);
1995         colors[i].green = (i * 0xffff) / (colors_per_channel - 1);
1996         colors[i].blue = (i * 0xffff) / (colors_per_channel - 1);;
1997         colors[i].flags = DoRed|DoGreen|DoBlue;
1998
1999         if (! XAllocColor(basedisplay.getXDisplay(), colormap,
2000                           &colors[i])) {
2001           fprintf(stderr, i18n->getMessage(ImageSet, ImageColorAllocFail,
2002                              "couldn't alloc color %i %i %i\n"),
2003                   colors[i].red, colors[i].green, colors[i].blue);
2004           colors[i].flags = 0;
2005         } else
2006           colors[i].flags = DoRed|DoGreen|DoBlue;
2007       }
2008
2009       basedisplay.ungrab();
2010
2011       XColor icolors[256];
2012       int incolors = (((1 << screen_depth) > 256) ? 256 :
2013                       (1 << screen_depth));
2014
2015       for (i = 0; i < incolors; i++)
2016         icolors[i].pixel = i;
2017
2018       XQueryColors(basedisplay.getXDisplay(), colormap, icolors, incolors);
2019       for (i = 0; i < ncolors; i++) {
2020         if (! colors[i].flags) {
2021           unsigned long chk = 0xffffffff, pixel, close = 0;
2022
2023           p = 2;
2024           while (p--) {
2025             for (ii = 0; ii < incolors; ii++) {
2026               int r = (colors[i].red - icolors[i].red) >> 8;
2027               int g = (colors[i].green - icolors[i].green) >> 8;
2028               int b = (colors[i].blue - icolors[i].blue) >> 8;
2029               pixel = (r * r) + (g * g) + (b * b);
2030
2031               if (pixel < chk) {
2032                 chk = pixel;
2033                 close = ii;
2034               }
2035
2036               colors[i].red = icolors[close].red;
2037               colors[i].green = icolors[close].green;
2038               colors[i].blue = icolors[close].blue;
2039
2040               if (XAllocColor(basedisplay.getXDisplay(), colormap,
2041                               &colors[i])) {
2042                 colors[i].flags = DoRed|DoGreen|DoBlue;
2043                 break;
2044               }
2045             }
2046           }
2047         }
2048       }
2049
2050       break;
2051     }
2052
2053   default:
2054     fprintf(stderr, i18n->getMessage(ImageSet, ImageUnsupVisual,
2055                "BImageControl::BImageControl: unsupported visual %d\n"),
2056             getVisual()->c_class);
2057     exit(1);
2058   }
2059
2060   cache = new LinkedList<Cache>;
2061 }
2062
2063
2064 BImageControl::~BImageControl(void) {
2065   if (sqrt_table) {
2066     delete [] sqrt_table;
2067   }
2068
2069   if (grad_xbuffer) {
2070     delete [] grad_xbuffer;
2071   }
2072
2073   if (grad_ybuffer) {
2074     delete [] grad_ybuffer;
2075   }
2076
2077   if (colors) {
2078     unsigned long *pixels = new unsigned long [ncolors];
2079
2080     int i;
2081     for (i = 0; i < ncolors; i++)
2082       *(pixels + i) = (*(colors + i)).pixel;
2083
2084     XFreeColors(basedisplay.getXDisplay(), colormap, pixels, ncolors, 0);
2085
2086     delete [] colors;
2087   }
2088
2089   if (cache->count()) {
2090     int i, n = cache->count();
2091     fprintf(stderr, i18n->getMessage(ImageSet, ImagePixmapRelease,
2092                        "BImageContol::~BImageControl: pixmap cache - "
2093                        "releasing %d pixmaps\n"), n);
2094
2095     for (i = 0; i < n; i++) {
2096       Cache *tmp = cache->first();
2097       XFreePixmap(basedisplay.getXDisplay(), tmp->pixmap);
2098       cache->remove(tmp);
2099       delete tmp;
2100     }
2101
2102 #ifdef    TIMEDCACHE
2103     if (timer) {
2104       timer->stop();
2105       delete timer;
2106     }
2107 #endif // TIMEDCACHE
2108   }
2109
2110   delete cache;
2111 }
2112
2113
2114 Pixmap BImageControl::searchCache(unsigned int width, unsigned int height,
2115                   unsigned long texture,
2116                   BColor *c1, BColor *c2) {
2117   if (cache->count()) {
2118     LinkedListIterator<Cache> it(cache);
2119
2120     for (Cache *tmp = it.current(); tmp; it++, tmp = it.current()) {
2121       if ((tmp->width == width) && (tmp->height == height) &&
2122           (tmp->texture == texture) && (tmp->pixel1 == c1->getPixel()))
2123           if (texture & BImage_Gradient) {
2124             if (tmp->pixel2 == c2->getPixel()) {
2125               tmp->count++;
2126               return tmp->pixmap;
2127             }
2128           } else {
2129             tmp->count++;
2130             return tmp->pixmap;
2131           }
2132         }
2133   }
2134
2135   return None;
2136 }
2137
2138
2139 Pixmap BImageControl::renderImage(unsigned int width, unsigned int height,
2140       BTexture *texture) {
2141   if (texture->getTexture() & BImage_ParentRelative) return ParentRelative;
2142
2143   Pixmap pixmap = searchCache(width, height, texture->getTexture(),
2144                               texture->getColor(), texture->getColorTo());
2145   if (pixmap) return pixmap;
2146
2147   BImage image(*this, width, height);
2148   pixmap = image.render(texture);
2149
2150   if (pixmap) {
2151     Cache *tmp = new Cache;
2152
2153     tmp->pixmap = pixmap;
2154     tmp->width = width;
2155     tmp->height = height;
2156     tmp->count = 1;
2157     tmp->texture = texture->getTexture();
2158     tmp->pixel1 = texture->getColor()->getPixel();
2159
2160     if (texture->getTexture() & BImage_Gradient)
2161       tmp->pixel2 = texture->getColorTo()->getPixel();
2162     else
2163       tmp->pixel2 = 0l;
2164
2165     cache->insert(tmp);
2166
2167     if ((unsigned) cache->count() > cache_max) {
2168 #ifdef    DEBUG
2169       fprintf(stderr, i18n->getMessage(ImageSet, ImagePixmapCacheLarge,
2170                          "BImageControl::renderImage: cache is large, "
2171                          "forcing cleanout\n"));
2172 #endif // DEBUG
2173
2174       timeout();
2175     }
2176
2177     return pixmap;
2178   }
2179
2180   return None;
2181 }
2182
2183
2184 void BImageControl::removeImage(Pixmap pixmap) {
2185   if (pixmap) {
2186     LinkedListIterator<Cache> it(cache);
2187     for (Cache *tmp = it.current(); tmp; it++, tmp = it.current()) {
2188       if (tmp->pixmap == pixmap) {
2189         if (tmp->count) {
2190           tmp->count--;
2191
2192 #ifdef    TIMEDCACHE
2193            if (! timer) timeout();
2194 #else // !TIMEDCACHE
2195            if (! tmp->count) timeout();
2196 #endif // TIMEDCACHE
2197         }
2198
2199         return;
2200       }
2201     }
2202   }
2203 }
2204
2205
2206 unsigned long BImageControl::getColor(const char *colorname,
2207                                       unsigned char *r, unsigned char *g,
2208                                       unsigned char *b)
2209 {
2210   XColor color;
2211   color.pixel = 0;
2212
2213   if (! XParseColor(basedisplay.getXDisplay(), colormap, colorname, &color))
2214     fprintf(stderr, "BImageControl::getColor: color parse error: \"%s\"\n",
2215             colorname);
2216   else if (! XAllocColor(basedisplay.getXDisplay(), colormap, &color))
2217     fprintf(stderr, "BImageControl::getColor: color alloc error: \"%s\"\n",
2218             colorname);
2219
2220   if (color.red == 65535) *r = 0xff;
2221   else *r = (unsigned char) (color.red / 0xff);
2222   if (color.green == 65535) *g = 0xff;
2223   else *g = (unsigned char) (color.green / 0xff);
2224   if (color.blue == 65535) *b = 0xff;
2225   else *b = (unsigned char) (color.blue / 0xff);
2226
2227   return color.pixel;
2228 }
2229
2230
2231 unsigned long BImageControl::getColor(const char *colorname) {
2232   XColor color;
2233   color.pixel = 0;
2234
2235   if (! XParseColor(basedisplay.getXDisplay(), colormap, colorname, &color))
2236     fprintf(stderr, "BImageControl::getColor: color parse error: \"%s\"\n",
2237             colorname);
2238   else if (! XAllocColor(basedisplay.getXDisplay(), colormap, &color))
2239     fprintf(stderr, "BImageControl::getColor: color alloc error: \"%s\"\n",
2240             colorname);
2241
2242   return color.pixel;
2243 }
2244
2245
2246 void BImageControl::getColorTables(unsigned char **rmt, unsigned char **gmt,
2247                                    unsigned char **bmt,
2248                                    int *roff, int *goff, int *boff,
2249                                    int *rbit, int *gbit, int *bbit) {
2250   if (rmt) *rmt = red_color_table;
2251   if (gmt) *gmt = green_color_table;
2252   if (bmt) *bmt = blue_color_table;
2253
2254   if (roff) *roff = red_offset;
2255   if (goff) *goff = green_offset;
2256   if (boff) *boff = blue_offset;
2257
2258   if (rbit) *rbit = red_bits;
2259   if (gbit) *gbit = green_bits;
2260   if (bbit) *bbit = blue_bits;
2261 }
2262
2263
2264 void BImageControl::getXColorTable(XColor **c, int *n) {
2265   if (c) *c = colors;
2266   if (n) *n = ncolors;
2267 }
2268
2269
2270 void BImageControl::getGradientBuffers(unsigned int w,
2271                                        unsigned int h,
2272                                        unsigned int **xbuf,
2273                                        unsigned int **ybuf)
2274 {
2275   if (w > grad_buffer_width) {
2276     if (grad_xbuffer) {
2277       delete [] grad_xbuffer;
2278     }
2279
2280     grad_buffer_width = w;
2281
2282     grad_xbuffer = new unsigned int[grad_buffer_width * 3];
2283   }
2284
2285   if (h > grad_buffer_height) {
2286     if (grad_ybuffer) {
2287       delete [] grad_ybuffer;
2288     }
2289
2290     grad_buffer_height = h;
2291
2292     grad_ybuffer = new unsigned int[grad_buffer_height * 3];
2293   }
2294
2295   *xbuf = grad_xbuffer;
2296   *ybuf = grad_ybuffer;
2297 }
2298
2299
2300 void BImageControl::installRootColormap(void) {
2301   basedisplay.grab();
2302
2303   Bool install = True;
2304   int i = 0, ncmap = 0;
2305   Colormap *cmaps =
2306     XListInstalledColormaps(basedisplay.getXDisplay(), window, &ncmap);
2307
2308   if (cmaps) {
2309     for (i = 0; i < ncmap; i++)
2310       if (*(cmaps + i) == colormap)
2311         install = False;
2312
2313     if (install)
2314       XInstallColormap(basedisplay.getXDisplay(), colormap);
2315
2316     XFree(cmaps);
2317   }
2318
2319   basedisplay.ungrab();
2320 }
2321
2322
2323 void BImageControl::setColorsPerChannel(int cpc) {
2324   if (cpc < 2) cpc = 2;
2325   if (cpc > 6) cpc = 6;
2326
2327   colors_per_channel = cpc;
2328 }
2329
2330
2331 unsigned long BImageControl::getSqrt(unsigned int x) {
2332   if (! sqrt_table) {
2333     // build sqrt table for use with elliptic gradient
2334
2335     sqrt_table = new unsigned long[(256 * 256 * 2) + 1];
2336     int i = 0;
2337
2338     for (; i < (256 * 256 * 2); i++)
2339       *(sqrt_table + i) = bsqrt(i);
2340   }
2341
2342   return (*(sqrt_table + x));
2343 }
2344
2345
2346 void BImageControl::parseTexture(BTexture *texture, const char *t) {
2347   if ((! texture) || (! t)) return;
2348
2349   int t_len = strlen(t) + 1, i;
2350   char *ts = new char[t_len];
2351   if (! ts) return;
2352
2353   // convert to lower case
2354   for (i = 0; i < t_len; i++)
2355     *(ts + i) = tolower(*(t + i));
2356
2357   if (strstr(ts, "parentrelative")) {
2358     texture->setTexture(BImage_ParentRelative);
2359   } else {
2360     texture->setTexture(0);
2361
2362     if (strstr(ts, "solid"))
2363       texture->addTexture(BImage_Solid);
2364     else if (strstr(ts, "gradient")) {
2365       texture->addTexture(BImage_Gradient);
2366       if (strstr(ts, "crossdiagonal"))
2367         texture->addTexture(BImage_CrossDiagonal);
2368       else if (strstr(ts, "rectangle"))
2369         texture->addTexture(BImage_Rectangle);
2370       else if (strstr(ts, "pyramid"))
2371         texture->addTexture(BImage_Pyramid);
2372       else if (strstr(ts, "pipecross"))
2373         texture->addTexture(BImage_PipeCross);
2374       else if (strstr(ts, "elliptic"))
2375         texture->addTexture(BImage_Elliptic);
2376       else if (strstr(ts, "diagonal"))
2377         texture->addTexture(BImage_Diagonal);
2378       else if (strstr(ts, "horizontal"))
2379         texture->addTexture(BImage_Horizontal);
2380       else if (strstr(ts, "vertical"))
2381         texture->addTexture(BImage_Vertical);
2382       else
2383         texture->addTexture(BImage_Diagonal);
2384     } else
2385       texture->addTexture(BImage_Solid);
2386
2387     if (strstr(ts, "raised"))
2388       texture->addTexture(BImage_Raised);
2389     else if (strstr(ts, "sunken"))
2390       texture->addTexture(BImage_Sunken);
2391     else if (strstr(ts, "flat"))
2392       texture->addTexture(BImage_Flat);
2393     else
2394       texture->addTexture(BImage_Raised);
2395
2396     if (! (texture->getTexture() & BImage_Flat))
2397       if (strstr(ts, "bevel2"))
2398         texture->addTexture(BImage_Bevel2);
2399       else
2400         texture->addTexture(BImage_Bevel1);
2401
2402 #ifdef    INTERLACE
2403     if (strstr(ts, "interlaced"))
2404       texture->addTexture(BImage_Interlaced);
2405 #endif // INTERLACE
2406   }
2407
2408   delete [] ts;
2409 }
2410
2411
2412 void BImageControl::parseColor(BColor *color, const char *c) {
2413   if (! color) return;
2414
2415   if (color->isAllocated()) {
2416     unsigned long pixel = color->getPixel();
2417
2418     XFreeColors(basedisplay.getXDisplay(), colormap, &pixel, 1, 0);
2419
2420     color->setPixel(0l);
2421     color->setRGB(0, 0, 0);
2422     color->setAllocated(False);
2423   }
2424
2425   if (c) {
2426     unsigned char r, g, b;
2427
2428     color->setPixel(getColor(c, &r, &g, &b));
2429     color->setRGB(r, g, b);
2430     color->setAllocated(True);
2431   }
2432 }
2433
2434
2435 void BImageControl::timeout(void) {
2436   LinkedListIterator<Cache> it(cache);
2437   for (Cache *tmp = it.current(); tmp; it++, tmp = it.current()) {
2438     if (tmp->count <= 0) {
2439       XFreePixmap(basedisplay.getXDisplay(), tmp->pixmap);
2440       cache->remove(tmp);
2441       delete tmp;
2442     }
2443   }
2444 }