]> icculus.org git repositories - mikachu/openbox.git/blob - src/Image.cc
Initial revision
[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    STDC_HEADERS
54 #  include <stdlib.h>
55 #  include <string.h>
56 #endif // STDC_HEADERS
57
58 #ifdef    HAVE_STDIO_H
59 #  include <stdio.h>
60 #endif // HAVE_STDIO_H
61
62 #ifdef    HAVE_CTYPE_H
63 #  include <ctype.h>
64 #endif // HAVE_CTYPE_H
65
66 #include <algorithm>
67 using namespace std;
68
69 static unsigned long bsqrt(unsigned long x) {
70   if (x <= 0) return 0;
71   if (x == 1) return 1;
72
73   unsigned long r = x >> 1;
74   unsigned long q;
75
76   while (1) {
77     q = x / r;
78     if (q >= r) return r;
79     r = (r + q) >> 1;
80   }
81 }
82
83
84 BImage::BImage(BImageControl *c, unsigned int w, unsigned int h) {
85   control = c;
86
87   width = ((signed) w > 0) ? w : 1;
88   height = ((signed) h > 0) ? h : 1;
89
90   red = new unsigned char[width * height];
91   green = new unsigned char[width * height];
92   blue = new unsigned char[width * height];
93
94   xtable = ytable = (unsigned int *) 0;
95
96   cpc = control->getColorsPerChannel();
97   cpccpc = cpc * cpc;
98
99   control->getColorTables(&red_table, &green_table, &blue_table,
100                           &red_offset, &green_offset, &blue_offset,
101                           &red_bits, &green_bits, &blue_bits);
102
103   if (control->getVisual()->c_class != TrueColor)
104     control->getXColorTable(&colors, &ncolors);
105 }
106
107
108 BImage::~BImage(void) {
109   if (red) delete [] red;
110   if (green) delete [] green;
111   if (blue) delete [] blue;
112 }
113
114
115 Pixmap BImage::render(BTexture *texture) {
116   if (texture->getTexture() & BImage_ParentRelative)
117     return ParentRelative;
118   else if (texture->getTexture() & BImage_Solid)
119     return render_solid(texture);
120   else if (texture->getTexture() & BImage_Gradient)
121     return render_gradient(texture);
122
123   return None;
124 }
125
126
127 Pixmap BImage::render_solid(BTexture *texture) {
128   Pixmap pixmap = XCreatePixmap(control->getBaseDisplay()->getXDisplay(),
129                                 control->getDrawable(), width,
130                                 height, control->getDepth());
131   if (pixmap == None) {
132     fprintf(stderr, i18n->getMessage(ImageSet, ImageErrorCreatingSolidPixmap,
133                        "BImage::render_solid: error creating pixmap\n"));
134     return None;
135   }
136
137   XGCValues gcv;
138   GC gc, hgc, lgc;
139
140   gcv.foreground = texture->getColor()->getPixel();
141   gcv.fill_style = FillSolid;
142   gc = XCreateGC(control->getBaseDisplay()->getXDisplay(), pixmap,
143                  GCForeground | GCFillStyle, &gcv);
144
145   gcv.foreground = texture->getHiColor()->getPixel();
146   hgc = XCreateGC(control->getBaseDisplay()->getXDisplay(), pixmap,
147                   GCForeground, &gcv);
148
149   gcv.foreground = texture->getLoColor()->getPixel();
150   lgc = XCreateGC(control->getBaseDisplay()->getXDisplay(), pixmap,
151                   GCForeground, &gcv);
152
153   XFillRectangle(control->getBaseDisplay()->getXDisplay(), pixmap, gc, 0, 0,
154                  width, height);
155
156 #ifdef    INTERLACE
157   if (texture->getTexture() & BImage_Interlaced) {
158     gcv.foreground = texture->getColorTo()->getPixel();
159     GC igc = XCreateGC(control->getBaseDisplay()->getXDisplay(), pixmap,
160                        GCForeground, &gcv);
161
162     register unsigned int i = 0;
163     for (; i < height; i += 2)
164       XDrawLine(control->getBaseDisplay()->getXDisplay(), pixmap, igc,
165                 0, i, width, i);
166
167     XFreeGC(control->getBaseDisplay()->getXDisplay(), igc);
168   }
169 #endif // INTERLACE
170
171
172   if (texture->getTexture() & BImage_Bevel1) {
173     if (texture->getTexture() & BImage_Raised) {
174       XDrawLine(control->getBaseDisplay()->getXDisplay(), pixmap, lgc,
175                 0, height - 1, width - 1, height - 1);
176       XDrawLine(control->getBaseDisplay()->getXDisplay(), pixmap, lgc,
177                 width - 1, height - 1, width - 1, 0);
178
179       XDrawLine(control->getBaseDisplay()->getXDisplay(), pixmap, hgc,
180                 0, 0, width - 1, 0);
181       XDrawLine(control->getBaseDisplay()->getXDisplay(), pixmap, hgc,
182                 0, height - 1, 0, 0);
183     } else if (texture->getTexture() & BImage_Sunken) {
184       XDrawLine(control->getBaseDisplay()->getXDisplay(), pixmap, hgc,
185                 0, height - 1, width - 1, height - 1);
186       XDrawLine(control->getBaseDisplay()->getXDisplay(), pixmap, hgc,
187                 width - 1, height - 1, width - 1, 0);
188
189       XDrawLine(control->getBaseDisplay()->getXDisplay(), pixmap, lgc,
190                 0, 0, width - 1, 0);
191       XDrawLine(control->getBaseDisplay()->getXDisplay(), pixmap, lgc,
192                 0, height - 1, 0, 0);
193     }
194   } else if (texture->getTexture() & BImage_Bevel2) {
195     if (texture->getTexture() & BImage_Raised) {
196       XDrawLine(control->getBaseDisplay()->getXDisplay(), pixmap, lgc,
197                 1, height - 3, width - 3, height - 3);
198       XDrawLine(control->getBaseDisplay()->getXDisplay(), pixmap, lgc,
199                 width - 3, height - 3, width - 3, 1);
200
201       XDrawLine(control->getBaseDisplay()->getXDisplay(), pixmap, hgc,
202                 1, 1, width - 3, 1);
203       XDrawLine(control->getBaseDisplay()->getXDisplay(), pixmap, hgc,
204                 1, height - 3, 1, 1);
205     } else if (texture->getTexture() & BImage_Sunken) {
206       XDrawLine(control->getBaseDisplay()->getXDisplay(), pixmap, hgc,
207                 1, height - 3, width - 3, height - 3);
208       XDrawLine(control->getBaseDisplay()->getXDisplay(), pixmap, hgc,
209                 width - 3, height - 3, width - 3, 1);
210
211       XDrawLine(control->getBaseDisplay()->getXDisplay(), pixmap, lgc,
212                 1, 1, width - 3, 1);
213       XDrawLine(control->getBaseDisplay()->getXDisplay(), pixmap, lgc,
214                 1, height - 3, 1, 1);
215     }
216   }
217
218   XFreeGC(control->getBaseDisplay()->getXDisplay(), gc);
219   XFreeGC(control->getBaseDisplay()->getXDisplay(), hgc);
220   XFreeGC(control->getBaseDisplay()->getXDisplay(), lgc);
221
222   return pixmap;
223 }
224
225
226 Pixmap BImage::render_gradient(BTexture *texture) {
227  int inverted = 0;
228
229 #ifdef    INTERLACE
230   interlaced = texture->getTexture() & BImage_Interlaced;
231 #endif // INTERLACE
232
233   if (texture->getTexture() & BImage_Sunken) {
234     from = texture->getColorTo();
235     to = texture->getColor();
236
237     if (! (texture->getTexture() & BImage_Invert)) inverted = 1;
238   } else {
239     from = texture->getColor();
240     to = texture->getColorTo();
241
242     if (texture->getTexture() & BImage_Invert) inverted = 1;
243   }
244
245   control->getGradientBuffers(width, height, &xtable, &ytable);
246
247   if (texture->getTexture() & BImage_Diagonal) dgradient();
248   else if (texture->getTexture() & BImage_Elliptic) egradient();
249   else if (texture->getTexture() & BImage_Horizontal) hgradient();
250   else if (texture->getTexture() & BImage_Pyramid) pgradient();
251   else if (texture->getTexture() & BImage_Rectangle) rgradient();
252   else if (texture->getTexture() & BImage_Vertical) vgradient();
253   else if (texture->getTexture() & BImage_CrossDiagonal) cdgradient();
254   else if (texture->getTexture() & BImage_PipeCross) pcgradient();
255
256   if (texture->getTexture() & BImage_Bevel1) bevel1();
257   else if (texture->getTexture() & BImage_Bevel2) bevel2();
258
259   if (inverted) invert();
260
261   Pixmap pixmap = renderPixmap();
262
263   return pixmap;
264
265 }
266
267
268 XImage *BImage::renderXImage(void) {
269   XImage *image =
270     XCreateImage(control->getBaseDisplay()->getXDisplay(),
271                  control->getVisual(), control->getDepth(), ZPixmap, 0, 0,
272                  width, height, 32, 0);
273
274   if (! image) {
275     fprintf(stderr, i18n->getMessage(ImageSet, ImageErrorCreatingXImage,
276                        "BImage::renderXImage: error creating XImage\n"));
277     return (XImage *) 0;
278   }
279
280   // insurance policy
281   image->data = (char *) 0;
282
283   unsigned char *d = new unsigned char[image->bytes_per_line * (height + 1)];
284   register unsigned int x, y, dithx, dithy, r, g, b, o, er, eg, eb, offset;
285
286   unsigned char *pixel_data = d, *ppixel_data = d;
287   unsigned long pixel;
288
289   o = image->bits_per_pixel + ((image->byte_order == MSBFirst) ? 1 : 0);
290
291   if (control->doDither() && width > 1 && height > 1) {
292     unsigned char dither4[4][4] = { {0, 4, 1, 5},
293                                     {6, 2, 7, 3},
294                                     {1, 5, 0, 4},
295                                     {7, 3, 6, 2} };
296
297 #ifdef    ORDEREDPSEUDO
298     unsigned char dither8[8][8] = { { 0,  32, 8,  40, 2,  34, 10, 42 },
299                                     { 48, 16, 56, 24, 50, 18, 58, 26 },
300                                     { 12, 44, 4,  36, 14, 46, 6,  38 },
301                                     { 60, 28, 52, 20, 62, 30, 54, 22 },
302                                     { 3,  35, 11, 43, 1,  33, 9,  41 },
303                                     { 51, 19, 59, 27, 49, 17, 57, 25 },
304                                     { 15, 47, 7,  39, 13, 45, 5,  37 },
305                                     { 63, 31, 55, 23, 61, 29, 53, 21 } };
306 #endif // ORDEREDPSEUDO
307
308     switch (control->getVisual()->c_class) {
309     case TrueColor:
310       // algorithm: ordered dithering... many many thanks to rasterman
311       // (raster@rasterman.com) for telling me about this... portions of this
312       // code is based off of his code in Imlib
313       for (y = 0, offset = 0; y < height; y++) {
314         dithy = y & 0x3;
315
316         for (x = 0; x < width; x++, offset++) {
317           dithx = x & 0x3;
318           r = red[offset];
319           g = green[offset];
320           b = blue[offset];
321
322           er = r & (red_bits - 1);
323           eg = g & (green_bits - 1);
324           eb = b & (blue_bits - 1);
325
326           r = red_table[r];
327           g = green_table[g];
328           b = blue_table[b];
329
330           if ((dither4[dithy][dithx] < er) && (r < red_table[255])) r++;
331           if ((dither4[dithy][dithx] < eg) && (g < green_table[255])) g++;
332           if ((dither4[dithy][dithx] < eb) && (b < blue_table[255])) b++;
333
334           pixel = (r << red_offset) | (g << green_offset) | (b << blue_offset);
335
336           switch (o) {
337           case  8: //  8bpp
338             *pixel_data++ = pixel;
339             break;
340
341           case 16: // 16bpp LSB
342             *pixel_data++ = pixel;
343             *pixel_data++ = pixel >> 8;
344             break;
345
346           case 17: // 16bpp MSB
347             *pixel_data++ = pixel >> 8;
348             *pixel_data++ = pixel;
349             break;
350
351           case 24: // 24bpp LSB
352             *pixel_data++ = pixel;
353             *pixel_data++ = pixel >> 8;
354             *pixel_data++ = pixel >> 16;
355             break;
356
357           case 25: // 24bpp MSB
358             *pixel_data++ = pixel >> 16;
359             *pixel_data++ = pixel >> 8;
360             *pixel_data++ = pixel;
361             break;
362
363           case 32: // 32bpp LSB
364             *pixel_data++ = pixel;
365             *pixel_data++ = pixel >> 8;
366             *pixel_data++ = pixel >> 16;
367             *pixel_data++ = pixel >> 24;
368             break;
369
370           case 33: // 32bpp MSB
371             *pixel_data++ = pixel >> 24;
372             *pixel_data++ = pixel >> 16;
373             *pixel_data++ = pixel >> 8;
374             *pixel_data++ = pixel;
375             break;
376           }
377         }
378
379         pixel_data = (ppixel_data += image->bytes_per_line);
380       }
381
382       break;
383
384     case StaticColor:
385     case PseudoColor: {
386 #ifndef   ORDEREDPSEUDO
387       short *terr,
388         *rerr = new short[width + 2],
389         *gerr = new short[width + 2],
390         *berr = new short[width + 2],
391         *nrerr = new short[width + 2],
392         *ngerr = new short[width + 2],
393         *nberr = new short[width + 2];
394       int rr, gg, bb, rer, ger, ber;
395       int dd = 255 / control->getColorsPerChannel();
396
397       for (x = 0; x < width; x++) {
398         *(rerr + x) = *(red + x);
399         *(gerr + x) = *(green + x);
400         *(berr + x) = *(blue + x);
401       }
402
403       *(rerr + x) = *(gerr + x) = *(berr + x) = 0;
404 #endif // ORDEREDPSEUDO
405
406       for (y = 0, offset = 0; y < height; y++) {
407 #ifdef    ORDEREDPSEUDO
408         dithy = y & 7;
409
410         for (x = 0; x < width; x++, offset++) {
411           dithx = x & 7;
412
413           r = red[offset];
414           g = green[offset];
415           b = blue[offset];
416
417           er = r & (red_bits - 1);
418           eg = g & (green_bits - 1);
419           eb = b & (blue_bits - 1);
420
421           r = red_table[r];
422           g = green_table[g];
423           b = blue_table[b];
424
425           if ((dither8[dithy][dithx] < er) && (r < red_table[255])) r++;
426           if ((dither8[dithy][dithx] < eg) && (g < green_table[255])) g++;
427           if ((dither8[dithy][dithx] < eb) && (b < blue_table[255])) b++;
428
429           pixel = (r * cpccpc) + (g * cpc) + b;
430           *(pixel_data++) = colors[pixel].pixel;
431         }
432
433         pixel_data = (ppixel_data += image->bytes_per_line);
434       }
435 #else // !ORDEREDPSEUDO
436       if (y < (height - 1)) {
437         int i = offset + width;
438         for (x = 0; x < width; x++, i++) {
439           *(nrerr + x) = *(red + i);
440           *(ngerr + x) = *(green + i);
441           *(nberr + x) = *(blue + i);
442         }
443
444         *(nrerr + x) = *(red + (--i));
445         *(ngerr + x) = *(green + i);
446         *(nberr + x) = *(blue + i);
447       }
448
449       for (x = 0; x < width; x++) {
450         rr = rerr[x];
451         gg = gerr[x];
452         bb = berr[x];
453
454         if (rr > 255) rr = 255; else if (rr < 0) rr = 0;
455         if (gg > 255) gg = 255; else if (gg < 0) gg = 0;
456         if (bb > 255) bb = 255; else if (bb < 0) bb = 0;
457
458         r = red_table[rr];
459         g = green_table[gg];
460         b = blue_table[bb];
461
462         rer = rerr[x] - r*dd;
463         ger = gerr[x] - g*dd;
464         ber = berr[x] - b*dd;
465
466         pixel = (r * cpccpc) + (g * cpc) + b;
467         *pixel_data++ = colors[pixel].pixel;
468
469         r = rer >> 1;
470         g = ger >> 1;
471         b = ber >> 1;
472         rerr[x+1] += r;
473         gerr[x+1] += g;
474         berr[x+1] += b;
475         nrerr[x] += r;
476         ngerr[x] += g;
477         nberr[x] += b;
478       }
479
480       offset += width;
481
482       pixel_data = (ppixel_data += image->bytes_per_line);
483
484       terr = rerr;
485       rerr = nrerr;
486       nrerr = terr;
487
488       terr = gerr;
489       gerr = ngerr;
490       ngerr = terr;
491
492       terr = berr;
493       berr = nberr;
494       nberr = terr;
495     }
496
497     delete [] rerr;
498     delete [] gerr;
499     delete [] berr;
500     delete [] nrerr;
501     delete [] ngerr;
502     delete [] nberr;
503 #endif // ORDEREDPSUEDO
504
505     break; }
506
507     default:
508       fprintf(stderr, i18n->getMessage(ImageSet, ImageUnsupVisual,
509                          "BImage::renderXImage: unsupported visual\n"));
510       delete [] d;
511       XDestroyImage(image);
512       return (XImage *) 0;
513     }
514   } else {
515     switch (control->getVisual()->c_class) {
516     case StaticColor:
517     case PseudoColor:
518       for (y = 0, offset = 0; y < height; y++) {
519         for (x = 0; x < width; x++, offset++) {
520           r = red_table[red[offset]];
521           g = green_table[green[offset]];
522           b = blue_table[blue[offset]];
523
524           pixel = (r * cpccpc) + (g * cpc) + b;
525           *pixel_data++ = colors[pixel].pixel;
526         }
527
528         pixel_data = (ppixel_data += image->bytes_per_line);
529       }
530
531       break;
532
533   case TrueColor:
534     for (y = 0, offset = 0; y < height; y++) {
535       for (x = 0; x < width; x++, offset++) {
536         r = red_table[red[offset]];
537         g = green_table[green[offset]];
538         b = blue_table[blue[offset]];
539
540         pixel = (r << red_offset) | (g << green_offset) | (b << blue_offset);
541
542         switch (o) {
543         case  8: //  8bpp
544           *pixel_data++ = pixel;
545           break;
546
547         case 16: // 16bpp LSB
548           *pixel_data++ = pixel;
549           *pixel_data++ = pixel >> 8;
550           break;
551
552         case 17: // 16bpp MSB
553           *pixel_data++ = pixel >> 8;
554           *pixel_data++ = pixel;
555           break;
556
557         case 24: // 24bpp LSB
558           *pixel_data++ = pixel;
559           *pixel_data++ = pixel >> 8;
560           *pixel_data++ = pixel >> 16;
561           break;
562
563         case 25: // 24bpp MSB
564           *pixel_data++ = pixel >> 16;
565           *pixel_data++ = pixel >> 8;
566           *pixel_data++ = pixel;
567           break;
568
569         case 32: // 32bpp LSB
570           *pixel_data++ = pixel;
571           *pixel_data++ = pixel >> 8;
572           *pixel_data++ = pixel >> 16;
573           *pixel_data++ = pixel >> 24;
574           break;
575
576         case 33: // 32bpp MSB
577           *pixel_data++ = pixel >> 24;
578           *pixel_data++ = pixel >> 16;
579           *pixel_data++ = pixel >> 8;
580           *pixel_data++ = pixel;
581           break;
582         }
583       }
584
585       pixel_data = (ppixel_data += image->bytes_per_line);
586     }
587
588     break;
589
590   case StaticGray:
591   case GrayScale:
592     for (y = 0, offset = 0; y < height; y++) {
593       for (x = 0; x < width; x++, offset++) {
594         r = *(red_table + *(red + offset));
595         g = *(green_table + *(green + offset));
596         b = *(blue_table + *(blue + offset));
597
598         g = ((r * 30) + (g * 59) + (b * 11)) / 100;
599         *pixel_data++ = colors[g].pixel;
600       }
601
602       pixel_data = (ppixel_data += image->bytes_per_line);
603     }
604
605     break;
606
607   default:
608     fprintf(stderr, i18n->getMessage(ImageSet, ImageUnsupVisual,
609                        "BImage::renderXImage: unsupported visual\n"));
610     delete [] d;
611     XDestroyImage(image);
612     return (XImage *) 0;
613   }
614 }
615
616   image->data = (char *) d;
617   return image;
618 }
619
620
621 Pixmap BImage::renderPixmap(void) {
622   Pixmap pixmap =
623     XCreatePixmap(control->getBaseDisplay()->getXDisplay(),
624                   control->getDrawable(), width, height, control->getDepth());
625
626   if (pixmap == None) {
627     fprintf(stderr, i18n->getMessage(ImageSet, ImageErrorCreatingPixmap,
628                              "BImage::renderPixmap: error creating pixmap\n"));
629     return None;
630   }
631
632   XImage *image = renderXImage();
633
634   if (! image) {
635     XFreePixmap(control->getBaseDisplay()->getXDisplay(), pixmap);
636     return None;
637   } else if (! image->data) {
638     XDestroyImage(image);
639     XFreePixmap(control->getBaseDisplay()->getXDisplay(), pixmap);
640     return None;
641   }
642
643   XPutImage(control->getBaseDisplay()->getXDisplay(), pixmap,
644             DefaultGC(control->getBaseDisplay()->getXDisplay(),
645                       control->getScreenInfo()->getScreenNumber()),
646             image, 0, 0, 0, 0, width, height);
647
648   if (image->data) {
649     delete [] image->data;
650     image->data = NULL;
651   }
652
653   XDestroyImage(image);
654
655   return pixmap;
656 }
657
658
659 void BImage::bevel1(void) {
660   if (width > 2 && height > 2) {
661     unsigned char *pr = red, *pg = green, *pb = blue;
662
663     register unsigned char r, g, b, rr ,gg ,bb;
664     register unsigned int w = width, h = height - 1, wh = w * h;
665
666     while (--w) {
667       r = *pr;
668       rr = r + (r >> 1);
669       if (rr < r) rr = ~0;
670       g = *pg;
671       gg = g + (g >> 1);
672       if (gg < g) gg = ~0;
673       b = *pb;
674       bb = b + (b >> 1);
675       if (bb < b) bb = ~0;
676
677       *pr = rr;
678       *pg = gg;
679       *pb = bb;
680
681       r = *(pr + wh);
682       rr = (r >> 2) + (r >> 1);
683       if (rr > r) rr = 0;
684       g = *(pg + wh);
685       gg = (g >> 2) + (g >> 1);
686       if (gg > g) gg = 0;
687       b = *(pb + wh);
688       bb = (b >> 2) + (b >> 1);
689       if (bb > b) bb = 0;
690
691       *((pr++) + wh) = rr;
692       *((pg++) + wh) = gg;
693       *((pb++) + wh) = bb;
694     }
695
696     r = *pr;
697     rr = r + (r >> 1);
698     if (rr < r) rr = ~0;
699     g = *pg;
700     gg = g + (g >> 1);
701     if (gg < g) gg = ~0;
702     b = *pb;
703     bb = b + (b >> 1);
704     if (bb < b) bb = ~0;
705
706     *pr = rr;
707     *pg = gg;
708     *pb = bb;
709
710     r = *(pr + wh);
711     rr = (r >> 2) + (r >> 1);
712     if (rr > r) rr = 0;
713     g = *(pg + wh);
714     gg = (g >> 2) + (g >> 1);
715     if (gg > g) gg = 0;
716     b = *(pb + wh);
717     bb = (b >> 2) + (b >> 1);
718     if (bb > b) bb = 0;
719
720     *(pr + wh) = rr;
721     *(pg + wh) = gg;
722     *(pb + wh) = bb;
723
724     pr = red + width;
725     pg = green + width;
726     pb = blue + width;
727
728     while (--h) {
729       r = *pr;
730       rr = r + (r >> 1);
731       if (rr < r) rr = ~0;
732       g = *pg;
733       gg = g + (g >> 1);
734       if (gg < g) gg = ~0;
735       b = *pb;
736       bb = b + (b >> 1);
737       if (bb < b) bb = ~0;
738
739       *pr = rr;
740       *pg = gg;
741       *pb = bb;
742
743       pr += width - 1;
744       pg += width - 1;
745       pb += width - 1;
746
747       r = *pr;
748       rr = (r >> 2) + (r >> 1);
749       if (rr > r) rr = 0;
750       g = *pg;
751       gg = (g >> 2) + (g >> 1);
752       if (gg > g) gg = 0;
753       b = *pb;
754       bb = (b >> 2) + (b >> 1);
755       if (bb > b) bb = 0;
756
757       *(pr++) = rr;
758       *(pg++) = gg;
759       *(pb++) = bb;
760     }
761
762     r = *pr;
763     rr = r + (r >> 1);
764     if (rr < r) rr = ~0;
765     g = *pg;
766     gg = g + (g >> 1);
767     if (gg < g) gg = ~0;
768     b = *pb;
769     bb = b + (b >> 1);
770     if (bb < b) bb = ~0;
771
772     *pr = rr;
773     *pg = gg;
774     *pb = bb;
775
776     pr += width - 1;
777     pg += width - 1;
778     pb += width - 1;
779
780     r = *pr;
781     rr = (r >> 2) + (r >> 1);
782     if (rr > r) rr = 0;
783     g = *pg;
784     gg = (g >> 2) + (g >> 1);
785     if (gg > g) gg = 0;
786     b = *pb;
787     bb = (b >> 2) + (b >> 1);
788     if (bb > b) bb = 0;
789
790     *pr = rr;
791     *pg = gg;
792     *pb = bb;
793   }
794 }
795
796
797 void BImage::bevel2(void) {
798   if (width > 4 && height > 4) {
799     unsigned char r, g, b, rr ,gg ,bb, *pr = red + width + 1,
800       *pg = green + width + 1, *pb = blue + width + 1;
801     unsigned int w = width - 2, h = height - 1, wh = width * (height - 3);
802
803     while (--w) {
804       r = *pr;
805       rr = r + (r >> 1);
806       if (rr < r) rr = ~0;
807       g = *pg;
808       gg = g + (g >> 1);
809       if (gg < g) gg = ~0;
810       b = *pb;
811       bb = b + (b >> 1);
812       if (bb < b) bb = ~0;
813
814       *pr = rr;
815       *pg = gg;
816       *pb = bb;
817
818       r = *(pr + wh);
819       rr = (r >> 2) + (r >> 1);
820       if (rr > r) rr = 0;
821       g = *(pg + wh);
822       gg = (g >> 2) + (g >> 1);
823       if (gg > g) gg = 0;
824       b = *(pb + wh);
825       bb = (b >> 2) + (b >> 1);
826       if (bb > b) bb = 0;
827
828       *((pr++) + wh) = rr;
829       *((pg++) + wh) = gg;
830       *((pb++) + wh) = bb;
831     }
832
833     pr = red + width;
834     pg = green + width;
835     pb = blue + width;
836
837     while (--h) {
838       r = *pr;
839       rr = r + (r >> 1);
840       if (rr < r) rr = ~0;
841       g = *pg;
842       gg = g + (g >> 1);
843       if (gg < g) gg = ~0;
844       b = *pb;
845       bb = b + (b >> 1);
846       if (bb < b) bb = ~0;
847
848       *(++pr) = rr;
849       *(++pg) = gg;
850       *(++pb) = bb;
851
852       pr += width - 3;
853       pg += width - 3;
854       pb += width - 3;
855
856       r = *pr;
857       rr = (r >> 2) + (r >> 1);
858       if (rr > r) rr = 0;
859       g = *pg;
860       gg = (g >> 2) + (g >> 1);
861       if (gg > g) gg = 0;
862       b = *pb;
863       bb = (b >> 2) + (b >> 1);
864       if (bb > b) bb = 0;
865
866       *(pr++) = rr;
867       *(pg++) = gg;
868       *(pb++) = bb;
869
870       pr++; pg++; pb++;
871     }
872   }
873 }
874
875
876 void BImage::invert(void) {
877   register unsigned int i, j, wh = (width * height) - 1;
878   unsigned char tmp;
879
880   for (i = 0, j = wh; j > i; j--, i++) {
881     tmp = *(red + j);
882     *(red + j) = *(red + i);
883     *(red + i) = tmp;
884
885     tmp = *(green + j);
886     *(green + j) = *(green + i);
887     *(green + i) = tmp;
888
889     tmp = *(blue + j);
890     *(blue + j) = *(blue + i);
891     *(blue + i) = tmp;
892   }
893 }
894
895
896 void BImage::dgradient(void) {
897   // diagonal gradient code was written by Mike Cole <mike@mydot.com>
898   // modified for interlacing by Brad Hughes
899
900   float drx, dgx, dbx, dry, dgy, dby, yr = 0.0, yg = 0.0, yb = 0.0,
901     xr = (float) from->getRed(),
902     xg = (float) from->getGreen(),
903     xb = (float) from->getBlue();
904   unsigned char *pr = red, *pg = green, *pb = blue;
905   unsigned int w = width * 2, h = height * 2, *xt = xtable, *yt = ytable;
906
907   register unsigned int x, y;
908
909   dry = drx = (float) (to->getRed() - from->getRed());
910   dgy = dgx = (float) (to->getGreen() - from->getGreen());
911   dby = dbx = (float) (to->getBlue() - from->getBlue());
912
913   // Create X table
914   drx /= w;
915   dgx /= w;
916   dbx /= w;
917
918   for (x = 0; x < width; x++) {
919     *(xt++) = (unsigned char) (xr);
920     *(xt++) = (unsigned char) (xg);
921     *(xt++) = (unsigned char) (xb);
922
923     xr += drx;
924     xg += dgx;
925     xb += dbx;
926   }
927
928   // Create Y table
929   dry /= h;
930   dgy /= h;
931   dby /= h;
932
933   for (y = 0; y < height; y++) {
934     *(yt++) = ((unsigned char) yr);
935     *(yt++) = ((unsigned char) yg);
936     *(yt++) = ((unsigned char) yb);
937
938     yr += dry;
939     yg += dgy;
940     yb += dby;
941   }
942
943   // Combine tables to create gradient
944
945 #ifdef    INTERLACE
946   if (! interlaced) {
947 #endif // INTERLACE
948
949     // normal dgradient
950     for (yt = ytable, y = 0; y < height; y++, yt += 3) {
951       for (xt = xtable, x = 0; x < width; x++) {
952         *(pr++) = *(xt++) + *(yt);
953         *(pg++) = *(xt++) + *(yt + 1);
954         *(pb++) = *(xt++) + *(yt + 2);
955       }
956     }
957
958 #ifdef    INTERLACE
959   } else {
960     // faked interlacing effect
961     unsigned char channel, channel2;
962
963     for (yt = ytable, y = 0; y < height; y++, yt += 3) {
964       for (xt = xtable, x = 0; x < width; x++) {
965         if (y & 1) {
966           channel = *(xt++) + *(yt);
967           channel2 = (channel >> 1) + (channel >> 2);
968           if (channel2 > channel) channel2 = 0;
969           *(pr++) = channel2;
970
971           channel = *(xt++) + *(yt + 1);
972           channel2 = (channel >> 1) + (channel >> 2);
973           if (channel2 > channel) channel2 = 0;
974           *(pg++) = channel2;
975
976           channel = *(xt++) + *(yt + 2);
977           channel2 = (channel >> 1) + (channel >> 2);
978           if (channel2 > channel) channel2 = 0;
979           *(pb++) = channel2;
980         } else {
981           channel = *(xt++) + *(yt);
982           channel2 = channel + (channel >> 3);
983           if (channel2 < channel) channel2 = ~0;
984           *(pr++) = channel2;
985
986           channel = *(xt++) + *(yt + 1);
987           channel2 = channel + (channel >> 3);
988           if (channel2 < channel) channel2 = ~0;
989           *(pg++) = channel2;
990
991           channel = *(xt++) + *(yt + 2);
992           channel2 = channel + (channel >> 3);
993           if (channel2 < channel) channel2 = ~0;
994           *(pb++) = channel2;
995         }
996       }
997     }
998   }
999 #endif // INTERLACE
1000
1001 }
1002
1003
1004 void BImage::hgradient(void) {
1005   float drx, dgx, dbx,
1006     xr = (float) from->getRed(),
1007     xg = (float) from->getGreen(),
1008     xb = (float) from->getBlue();
1009   unsigned char *pr = red, *pg = green, *pb = blue;
1010
1011   register unsigned int x, y;
1012
1013   drx = (float) (to->getRed() - from->getRed());
1014   dgx = (float) (to->getGreen() - from->getGreen());
1015   dbx = (float) (to->getBlue() - from->getBlue());
1016
1017   drx /= width;
1018   dgx /= width;
1019   dbx /= width;
1020
1021 #ifdef    INTERLACE
1022   if (interlaced && height > 2) {
1023     // faked interlacing effect
1024     unsigned char channel, channel2;
1025
1026     for (x = 0; x < width; x++, pr++, pg++, pb++) {
1027       channel = (unsigned char) xr;
1028       channel2 = (channel >> 1) + (channel >> 2);
1029       if (channel2 > channel) channel2 = 0;
1030       *pr = channel2;
1031
1032       channel = (unsigned char) xg;
1033       channel2 = (channel >> 1) + (channel >> 2);
1034       if (channel2 > channel) channel2 = 0;
1035       *pg = channel2;
1036
1037       channel = (unsigned char) xb;
1038       channel2 = (channel >> 1) + (channel >> 2);
1039       if (channel2 > channel) channel2 = 0;
1040       *pb = channel2;
1041
1042
1043       channel = (unsigned char) xr;
1044       channel2 = channel + (channel >> 3);
1045       if (channel2 < channel) channel2 = ~0;
1046       *(pr + width) = channel2;
1047
1048       channel = (unsigned char) xg;
1049       channel2 = channel + (channel >> 3);
1050       if (channel2 < channel) channel2 = ~0;
1051       *(pg + width) = channel2;
1052
1053       channel = (unsigned char) xb;
1054       channel2 = channel + (channel >> 3);
1055       if (channel2 < channel) channel2 = ~0;
1056       *(pb + width) = channel2;
1057
1058       xr += drx;
1059       xg += dgx;
1060       xb += dbx;
1061     }
1062
1063     pr += width;
1064     pg += width;
1065     pb += width;
1066
1067     int offset;
1068
1069     for (y = 2; y < height; y++, pr += width, pg += width, pb += width) {
1070       if (y & 1) offset = width; else offset = 0;
1071
1072       memcpy(pr, (red + offset), width);
1073       memcpy(pg, (green + offset), width);
1074       memcpy(pb, (blue + offset), width);
1075     }
1076   } else {
1077 #endif // INTERLACE
1078
1079     // normal hgradient
1080     for (x = 0; x < width; x++) {
1081       *(pr++) = (unsigned char) (xr);
1082       *(pg++) = (unsigned char) (xg);
1083       *(pb++) = (unsigned char) (xb);
1084
1085       xr += drx;
1086       xg += dgx;
1087       xb += dbx;
1088     }
1089
1090     for (y = 1; y < height; y++, pr += width, pg += width, pb += width) {
1091       memcpy(pr, red, width);
1092       memcpy(pg, green, width);
1093       memcpy(pb, blue, width);
1094     }
1095
1096 #ifdef    INTERLACE
1097   }
1098 #endif // INTERLACE
1099
1100 }
1101
1102
1103 void BImage::vgradient(void) {
1104   float dry, dgy, dby,
1105     yr = (float) from->getRed(),
1106     yg = (float) from->getGreen(),
1107     yb = (float) from->getBlue();
1108   unsigned char *pr = red, *pg = green, *pb = blue;
1109
1110   register unsigned int y;
1111
1112   dry = (float) (to->getRed() - from->getRed());
1113   dgy = (float) (to->getGreen() - from->getGreen());
1114   dby = (float) (to->getBlue() - from->getBlue());
1115
1116   dry /= height;
1117   dgy /= height;
1118   dby /= height;
1119
1120 #ifdef    INTERLACE
1121   if (interlaced) {
1122     // faked interlacing effect
1123     unsigned char channel, channel2;
1124
1125     for (y = 0; y < height; y++, pr += width, pg += width, pb += width) {
1126       if (y & 1) {
1127         channel = (unsigned char) yr;
1128         channel2 = (channel >> 1) + (channel >> 2);
1129         if (channel2 > channel) channel2 = 0;
1130         memset(pr, channel2, width);
1131
1132         channel = (unsigned char) yg;
1133         channel2 = (channel >> 1) + (channel >> 2);
1134         if (channel2 > channel) channel2 = 0;
1135         memset(pg, channel2, width);
1136
1137         channel = (unsigned char) yb;
1138         channel2 = (channel >> 1) + (channel >> 2);
1139         if (channel2 > channel) channel2 = 0;
1140         memset(pb, channel2, width);
1141       } else {
1142         channel = (unsigned char) yr;
1143         channel2 = channel + (channel >> 3);
1144         if (channel2 < channel) channel2 = ~0;
1145         memset(pr, channel2, width);
1146
1147         channel = (unsigned char) yg;
1148         channel2 = channel + (channel >> 3);
1149         if (channel2 < channel) channel2 = ~0;
1150         memset(pg, channel2, width);
1151
1152         channel = (unsigned char) yb;
1153         channel2 = channel + (channel >> 3);
1154         if (channel2 < channel) channel2 = ~0;
1155         memset(pb, channel2, width);
1156       }
1157
1158       yr += dry;
1159       yg += dgy;
1160       yb += dby;
1161     }
1162   } else {
1163 #endif // INTERLACE
1164
1165     // normal vgradient
1166     for (y = 0; y < height; y++, pr += width, pg += width, pb += width) {
1167       memset(pr, (unsigned char) yr, width);
1168       memset(pg, (unsigned char) yg, width);
1169       memset(pb, (unsigned char) yb, width);
1170
1171       yr += dry;
1172       yg += dgy;
1173       yb += dby;
1174     }
1175
1176 #ifdef    INTERLACE
1177   }
1178 #endif // INTERLACE
1179
1180 }
1181
1182
1183 void BImage::pgradient(void) {
1184   // pyramid gradient -  based on original dgradient, written by
1185   // Mosfet (mosfet@kde.org)
1186   // adapted from kde sources for Openbox by Brad Hughes
1187
1188   float yr, yg, yb, drx, dgx, dbx, dry, dgy, dby,
1189     xr, xg, xb;
1190   int rsign, gsign, bsign;
1191   unsigned char *pr = red, *pg = green, *pb = blue;
1192   unsigned int tr = to->getRed(), tg = to->getGreen(), tb = to->getBlue(),
1193     *xt = xtable, *yt = ytable;
1194
1195   register unsigned int x, y;
1196
1197   dry = drx = (float) (to->getRed() - from->getRed());
1198   dgy = dgx = (float) (to->getGreen() - from->getGreen());
1199   dby = dbx = (float) (to->getBlue() - from->getBlue());
1200
1201   rsign = (drx < 0) ? -1 : 1;
1202   gsign = (dgx < 0) ? -1 : 1;
1203   bsign = (dbx < 0) ? -1 : 1;
1204
1205   xr = yr = (drx / 2);
1206   xg = yg = (dgx / 2);
1207   xb = yb = (dbx / 2);
1208
1209   // Create X table
1210   drx /= width;
1211   dgx /= width;
1212   dbx /= width;
1213
1214   for (x = 0; x < width; x++) {
1215     *(xt++) = (unsigned char) ((xr < 0) ? -xr : xr);
1216     *(xt++) = (unsigned char) ((xg < 0) ? -xg : xg);
1217     *(xt++) = (unsigned char) ((xb < 0) ? -xb : xb);
1218
1219     xr -= drx;
1220     xg -= dgx;
1221     xb -= dbx;
1222   }
1223
1224   // Create Y table
1225   dry /= height;
1226   dgy /= height;
1227   dby /= height;
1228
1229   for (y = 0; y < height; y++) {
1230     *(yt++) = ((unsigned char) ((yr < 0) ? -yr : yr));
1231     *(yt++) = ((unsigned char) ((yg < 0) ? -yg : yg));
1232     *(yt++) = ((unsigned char) ((yb < 0) ? -yb : yb));
1233
1234     yr -= dry;
1235     yg -= dgy;
1236     yb -= dby;
1237   }
1238
1239   // Combine tables to create gradient
1240
1241 #ifdef    INTERLACE
1242   if (! interlaced) {
1243 #endif // INTERLACE
1244
1245     // normal pgradient
1246     for (yt = ytable, y = 0; y < height; y++, yt += 3) {
1247       for (xt = xtable, x = 0; x < width; x++) {
1248         *(pr++) = (unsigned char) (tr - (rsign * (*(xt++) + *(yt))));
1249         *(pg++) = (unsigned char) (tg - (gsign * (*(xt++) + *(yt + 1))));
1250         *(pb++) = (unsigned char) (tb - (bsign * (*(xt++) + *(yt + 2))));
1251       }
1252     }
1253
1254 #ifdef    INTERLACE
1255   } else {
1256     // faked interlacing effect
1257     unsigned char channel, channel2;
1258
1259     for (yt = ytable, y = 0; y < height; y++, yt += 3) {
1260       for (xt = xtable, x = 0; x < width; x++) {
1261         if (y & 1) {
1262           channel = (unsigned char) (tr - (rsign * (*(xt++) + *(yt))));
1263           channel2 = (channel >> 1) + (channel >> 2);
1264           if (channel2 > channel) channel2 = 0;
1265           *(pr++) = channel2;
1266
1267           channel = (unsigned char) (tg - (gsign * (*(xt++) + *(yt + 1))));
1268           channel2 = (channel >> 1) + (channel >> 2);
1269           if (channel2 > channel) channel2 = 0;
1270           *(pg++) = channel2;
1271
1272           channel = (unsigned char) (tb - (bsign * (*(xt++) + *(yt + 2))));
1273           channel2 = (channel >> 1) + (channel >> 2);
1274           if (channel2 > channel) channel2 = 0;
1275           *(pb++) = channel2;
1276         } else {
1277           channel = (unsigned char) (tr - (rsign * (*(xt++) + *(yt))));
1278           channel2 = channel + (channel >> 3);
1279           if (channel2 < channel) channel2 = ~0;
1280           *(pr++) = channel2;
1281
1282           channel = (unsigned char) (tg - (gsign * (*(xt++) + *(yt + 1))));
1283           channel2 = channel + (channel >> 3);
1284           if (channel2 < channel) channel2 = ~0;
1285           *(pg++) = channel2;
1286
1287           channel = (unsigned char) (tb - (bsign * (*(xt++) + *(yt + 2))));
1288           channel2 = channel + (channel >> 3);
1289           if (channel2 < channel) channel2 = ~0;
1290           *(pb++) = channel2;
1291         }
1292       }
1293     }
1294   }
1295 #endif // INTERLACE
1296 }
1297
1298
1299 void BImage::rgradient(void) {
1300   // rectangle gradient -  based on original dgradient, written by
1301   // Mosfet (mosfet@kde.org)
1302   // adapted from kde sources for Openbox by Brad Hughes
1303
1304   float drx, dgx, dbx, dry, dgy, dby, xr, xg, xb, yr, yg, yb;
1305   int rsign, gsign, bsign;
1306   unsigned char *pr = red, *pg = green, *pb = blue;
1307   unsigned int tr = to->getRed(), tg = to->getGreen(), tb = to->getBlue(),
1308     *xt = xtable, *yt = ytable;
1309
1310   register unsigned int x, y;
1311
1312   dry = drx = (float) (to->getRed() - from->getRed());
1313   dgy = dgx = (float) (to->getGreen() - from->getGreen());
1314   dby = dbx = (float) (to->getBlue() - from->getBlue());
1315
1316   rsign = (drx < 0) ? -2 : 2;
1317   gsign = (dgx < 0) ? -2 : 2;
1318   bsign = (dbx < 0) ? -2 : 2;
1319
1320   xr = yr = (drx / 2);
1321   xg = yg = (dgx / 2);
1322   xb = yb = (dbx / 2);
1323
1324   // Create X table
1325   drx /= width;
1326   dgx /= width;
1327   dbx /= width;
1328
1329   for (x = 0; x < width; x++) {
1330     *(xt++) = (unsigned char) ((xr < 0) ? -xr : xr);
1331     *(xt++) = (unsigned char) ((xg < 0) ? -xg : xg);
1332     *(xt++) = (unsigned char) ((xb < 0) ? -xb : xb);
1333
1334     xr -= drx;
1335     xg -= dgx;
1336     xb -= dbx;
1337   }
1338
1339   // Create Y table
1340   dry /= height;
1341   dgy /= height;
1342   dby /= height;
1343
1344   for (y = 0; y < height; y++) {
1345     *(yt++) = ((unsigned char) ((yr < 0) ? -yr : yr));
1346     *(yt++) = ((unsigned char) ((yg < 0) ? -yg : yg));
1347     *(yt++) = ((unsigned char) ((yb < 0) ? -yb : yb));
1348
1349     yr -= dry;
1350     yg -= dgy;
1351     yb -= dby;
1352   }
1353
1354   // Combine tables to create gradient
1355
1356 #ifdef    INTERLACE
1357   if (! interlaced) {
1358 #endif // INTERLACE
1359
1360     // normal rgradient
1361     for (yt = ytable, y = 0; y < height; y++, yt += 3) {
1362       for (xt = xtable, x = 0; x < width; x++) {
1363         *(pr++) = (unsigned char) (tr - (rsign * max(*(xt++), *(yt))));
1364         *(pg++) = (unsigned char) (tg - (gsign * max(*(xt++), *(yt + 1))));
1365         *(pb++) = (unsigned char) (tb - (bsign * max(*(xt++), *(yt + 2))));
1366       }
1367     }
1368
1369 #ifdef    INTERLACE
1370   } else {
1371     // faked interlacing effect
1372     unsigned char channel, channel2;
1373
1374     for (yt = ytable, y = 0; y < height; y++, yt += 3) {
1375       for (xt = xtable, x = 0; x < width; x++) {
1376         if (y & 1) {
1377           channel = (unsigned char) (tr - (rsign * max(*(xt++), *(yt))));
1378           channel2 = (channel >> 1) + (channel >> 2);
1379           if (channel2 > channel) channel2 = 0;
1380           *(pr++) = channel2;
1381
1382           channel = (unsigned char) (tg - (gsign * max(*(xt++), *(yt + 1))));
1383           channel2 = (channel >> 1) + (channel >> 2);
1384           if (channel2 > channel) channel2 = 0;
1385           *(pg++) = channel2;
1386
1387           channel = (unsigned char) (tb - (bsign * max(*(xt++), *(yt + 2))));
1388           channel2 = (channel >> 1) + (channel >> 2);
1389           if (channel2 > channel) channel2 = 0;
1390           *(pb++) = channel2;
1391         } else {
1392           channel = (unsigned char) (tr - (rsign * max(*(xt++), *(yt))));
1393           channel2 = channel + (channel >> 3);
1394           if (channel2 < channel) channel2 = ~0;
1395           *(pr++) = channel2;
1396
1397           channel = (unsigned char) (tg - (gsign * max(*(xt++), *(yt + 1))));
1398           channel2 = channel + (channel >> 3);
1399           if (channel2 < channel) channel2 = ~0;
1400           *(pg++) = channel2;
1401
1402           channel = (unsigned char) (tb - (bsign * max(*(xt++), *(yt + 2))));
1403           channel2 = channel + (channel >> 3);
1404           if (channel2 < channel) channel2 = ~0;
1405           *(pb++) = channel2;
1406         }
1407       }
1408     }
1409   }
1410 #endif // INTERLACE
1411 }
1412
1413
1414 void BImage::egradient(void) {
1415   // elliptic gradient -  based on original dgradient, written by
1416   // Mosfet (mosfet@kde.org)
1417   // adapted from kde sources for Openbox by Brad Hughes
1418
1419   float drx, dgx, dbx, dry, dgy, dby, yr, yg, yb, xr, xg, xb;
1420   int rsign, gsign, bsign;
1421   unsigned char *pr = red, *pg = green, *pb = blue;
1422   unsigned int *xt = xtable, *yt = ytable,
1423     tr = (unsigned long) to->getRed(),
1424     tg = (unsigned long) to->getGreen(),
1425     tb = (unsigned long) to->getBlue();
1426
1427   register unsigned int x, y;
1428
1429   dry = drx = (float) (to->getRed() - from->getRed());
1430   dgy = dgx = (float) (to->getGreen() - from->getGreen());
1431   dby = dbx = (float) (to->getBlue() - from->getBlue());
1432
1433   rsign = (drx < 0) ? -1 : 1;
1434   gsign = (dgx < 0) ? -1 : 1;
1435   bsign = (dbx < 0) ? -1 : 1;
1436
1437   xr = yr = (drx / 2);
1438   xg = yg = (dgx / 2);
1439   xb = yb = (dbx / 2);
1440
1441   // Create X table
1442   drx /= width;
1443   dgx /= width;
1444   dbx /= width;
1445
1446   for (x = 0; x < width; x++) {
1447     *(xt++) = (unsigned long) (xr * xr);
1448     *(xt++) = (unsigned long) (xg * xg);
1449     *(xt++) = (unsigned long) (xb * xb);
1450
1451     xr -= drx;
1452     xg -= dgx;
1453     xb -= dbx;
1454   }
1455
1456   // Create Y table
1457   dry /= height;
1458   dgy /= height;
1459   dby /= height;
1460
1461   for (y = 0; y < height; y++) {
1462     *(yt++) = (unsigned long) (yr * yr);
1463     *(yt++) = (unsigned long) (yg * yg);
1464     *(yt++) = (unsigned long) (yb * yb);
1465
1466     yr -= dry;
1467     yg -= dgy;
1468     yb -= dby;
1469   }
1470
1471   // Combine tables to create gradient
1472
1473 #ifdef    INTERLACE
1474   if (! interlaced) {
1475 #endif // INTERLACE
1476
1477     // normal egradient
1478     for (yt = ytable, y = 0; y < height; y++, yt += 3) {
1479       for (xt = xtable, x = 0; x < width; x++) {
1480         *(pr++) = (unsigned char)
1481           (tr - (rsign * control->getSqrt(*(xt++) + *(yt))));
1482         *(pg++) = (unsigned char)
1483           (tg - (gsign * control->getSqrt(*(xt++) + *(yt + 1))));
1484         *(pb++) = (unsigned char)
1485           (tb - (bsign * control->getSqrt(*(xt++) + *(yt + 2))));
1486       }
1487     }
1488
1489 #ifdef    INTERLACE
1490   } else {
1491     // faked interlacing effect
1492     unsigned char channel, channel2;
1493
1494     for (yt = ytable, y = 0; y < height; y++, yt += 3) {
1495       for (xt = xtable, x = 0; x < width; x++) {
1496         if (y & 1) {
1497           channel = (unsigned char)
1498             (tr - (rsign * control->getSqrt(*(xt++) + *(yt))));
1499           channel2 = (channel >> 1) + (channel >> 2);
1500           if (channel2 > channel) channel2 = 0;
1501           *(pr++) = channel2;
1502
1503           channel = (unsigned char)
1504             (tg - (gsign * control->getSqrt(*(xt++) + *(yt + 1))));
1505           channel2 = (channel >> 1) + (channel >> 2);
1506           if (channel2 > channel) channel2 = 0;
1507           *(pg++) = channel2;
1508
1509           channel = (unsigned char)
1510             (tb - (bsign * control->getSqrt(*(xt++) + *(yt + 2))));
1511           channel2 = (channel >> 1) + (channel >> 2);
1512           if (channel2 > channel) channel2 = 0;
1513           *(pb++) = channel2;
1514         } else {
1515           channel = (unsigned char)
1516             (tr - (rsign * control->getSqrt(*(xt++) + *(yt))));
1517           channel2 = channel + (channel >> 3);
1518           if (channel2 < channel) channel2 = ~0;
1519           *(pr++) = channel2;
1520
1521           channel = (unsigned char)
1522           (tg - (gsign * control->getSqrt(*(xt++) + *(yt + 1))));
1523           channel2 = channel + (channel >> 3);
1524           if (channel2 < channel) channel2 = ~0;
1525           *(pg++) = channel2;
1526
1527           channel = (unsigned char)
1528             (tb - (bsign * control->getSqrt(*(xt++) + *(yt + 2))));
1529           channel2 = channel + (channel >> 3);
1530           if (channel2 < channel) channel2 = ~0;
1531           *(pb++) = channel2;
1532         }
1533       }
1534     }
1535   }
1536 #endif // INTERLACE
1537 }
1538
1539
1540 void BImage::pcgradient(void) {
1541   // pipe cross gradient -  based on original dgradient, written by
1542   // Mosfet (mosfet@kde.org)
1543   // adapted from kde sources for Openbox by Brad Hughes
1544
1545   float drx, dgx, dbx, dry, dgy, dby, xr, xg, xb, yr, yg, yb;
1546   int rsign, gsign, bsign;
1547   unsigned char *pr = red, *pg = green, *pb = blue;
1548   unsigned int *xt = xtable, *yt = ytable,
1549     tr = to->getRed(),
1550     tg = to->getGreen(),
1551     tb = to->getBlue();
1552
1553   register unsigned int x, y;
1554
1555   dry = drx = (float) (to->getRed() - from->getRed());
1556   dgy = dgx = (float) (to->getGreen() - from->getGreen());
1557   dby = dbx = (float) (to->getBlue() - from->getBlue());
1558
1559   rsign = (drx < 0) ? -2 : 2;
1560   gsign = (dgx < 0) ? -2 : 2;
1561   bsign = (dbx < 0) ? -2 : 2;
1562
1563   xr = yr = (drx / 2);
1564   xg = yg = (dgx / 2);
1565   xb = yb = (dbx / 2);
1566
1567   // Create X table
1568   drx /= width;
1569   dgx /= width;
1570   dbx /= width;
1571
1572   for (x = 0; x < width; x++) {
1573     *(xt++) = (unsigned char) ((xr < 0) ? -xr : xr);
1574     *(xt++) = (unsigned char) ((xg < 0) ? -xg : xg);
1575     *(xt++) = (unsigned char) ((xb < 0) ? -xb : xb);
1576
1577     xr -= drx;
1578     xg -= dgx;
1579     xb -= dbx;
1580   }
1581
1582   // Create Y table
1583   dry /= height;
1584   dgy /= height;
1585   dby /= height;
1586
1587   for (y = 0; y < height; y++) {
1588     *(yt++) = ((unsigned char) ((yr < 0) ? -yr : yr));
1589     *(yt++) = ((unsigned char) ((yg < 0) ? -yg : yg));
1590     *(yt++) = ((unsigned char) ((yb < 0) ? -yb : yb));
1591
1592     yr -= dry;
1593     yg -= dgy;
1594     yb -= dby;
1595   }
1596
1597   // Combine tables to create gradient
1598
1599 #ifdef    INTERLACE
1600   if (! interlaced) {
1601 #endif // INTERLACE
1602
1603     // normal pcgradient
1604     for (yt = ytable, y = 0; y < height; y++, yt += 3) {
1605       for (xt = xtable, x = 0; x < width; x++) {
1606         *(pr++) = (unsigned char) (tr - (rsign * min(*(xt++), *(yt))));
1607         *(pg++) = (unsigned char) (tg - (gsign * min(*(xt++), *(yt + 1))));
1608         *(pb++) = (unsigned char) (tb - (bsign * min(*(xt++), *(yt + 2))));
1609       }
1610     }
1611
1612 #ifdef    INTERLACE
1613   } else {
1614     // faked interlacing effect
1615     unsigned char channel, channel2;
1616
1617     for (yt = ytable, y = 0; y < height; y++, yt += 3) {
1618       for (xt = xtable, x = 0; x < width; x++) {
1619         if (y & 1) {
1620           channel = (unsigned char) (tr - (rsign * min(*(xt++), *(yt))));
1621           channel2 = (channel >> 1) + (channel >> 2);
1622           if (channel2 > channel) channel2 = 0;
1623           *(pr++) = channel2;
1624
1625           channel = (unsigned char) (tg - (bsign * min(*(xt++), *(yt + 1))));
1626           channel2 = (channel >> 1) + (channel >> 2);
1627           if (channel2 > channel) channel2 = 0;
1628           *(pg++) = channel2;
1629
1630           channel = (unsigned char) (tb - (gsign * min(*(xt++), *(yt + 2))));
1631           channel2 = (channel >> 1) + (channel >> 2);
1632           if (channel2 > channel) channel2 = 0;
1633           *(pb++) = channel2;
1634         } else {
1635           channel = (unsigned char) (tr - (rsign * min(*(xt++), *(yt))));
1636           channel2 = channel + (channel >> 3);
1637           if (channel2 < channel) channel2 = ~0;
1638           *(pr++) = channel2;
1639
1640           channel = (unsigned char) (tg - (gsign * min(*(xt++), *(yt + 1))));
1641           channel2 = channel + (channel >> 3);
1642           if (channel2 < channel) channel2 = ~0;
1643           *(pg++) = channel2;
1644
1645           channel = (unsigned char) (tb - (bsign * min(*(xt++), *(yt + 2))));
1646           channel2 = channel + (channel >> 3);
1647           if (channel2 < channel) channel2 = ~0;
1648           *(pb++) = channel2;
1649         }
1650       }
1651     }
1652   }
1653 #endif // INTERLACE
1654 }
1655
1656
1657 void BImage::cdgradient(void) {
1658   // cross diagonal gradient -  based on original dgradient, written by
1659   // Mosfet (mosfet@kde.org)
1660   // adapted from kde sources for Openbox by Brad Hughes
1661
1662   float drx, dgx, dbx, dry, dgy, dby, yr = 0.0, yg = 0.0, yb = 0.0,
1663     xr = (float) from->getRed(),
1664     xg = (float) from->getGreen(),
1665     xb = (float) from->getBlue();
1666   unsigned char *pr = red, *pg = green, *pb = blue;
1667   unsigned int w = width * 2, h = height * 2, *xt, *yt;
1668
1669   register unsigned int x, y;
1670
1671   dry = drx = (float) (to->getRed() - from->getRed());
1672   dgy = dgx = (float) (to->getGreen() - from->getGreen());
1673   dby = dbx = (float) (to->getBlue() - from->getBlue());
1674
1675   // Create X table
1676   drx /= w;
1677   dgx /= w;
1678   dbx /= w;
1679
1680   for (xt = (xtable + (width * 3) - 1), x = 0; x < width; x++) {
1681     *(xt--) = (unsigned char) xb;
1682     *(xt--) = (unsigned char) xg;
1683     *(xt--) = (unsigned char) xr;
1684
1685     xr += drx;
1686     xg += dgx;
1687     xb += dbx;
1688   }
1689
1690   // Create Y table
1691   dry /= h;
1692   dgy /= h;
1693   dby /= h;
1694
1695   for (yt = ytable, y = 0; y < height; y++) {
1696     *(yt++) = (unsigned char) yr;
1697     *(yt++) = (unsigned char) yg;
1698     *(yt++) = (unsigned char) yb;
1699
1700     yr += dry;
1701     yg += dgy;
1702     yb += dby;
1703   }
1704
1705   // Combine tables to create gradient
1706
1707 #ifdef    INTERLACE
1708   if (! interlaced) {
1709 #endif // INTERLACE
1710
1711     // normal cdgradient
1712     for (yt = ytable, y = 0; y < height; y++, yt += 3) {
1713       for (xt = xtable, x = 0; x < width; x++) {
1714         *(pr++) = *(xt++) + *(yt);
1715         *(pg++) = *(xt++) + *(yt + 1);
1716         *(pb++) = *(xt++) + *(yt + 2);
1717       }
1718     }
1719
1720 #ifdef    INTERLACE
1721   } else {
1722     // faked interlacing effect
1723     unsigned char channel, channel2;
1724
1725     for (yt = ytable, y = 0; y < height; y++, yt += 3) {
1726       for (xt = xtable, x = 0; x < width; x++) {
1727         if (y & 1) {
1728           channel = *(xt++) + *(yt);
1729           channel2 = (channel >> 1) + (channel >> 2);
1730           if (channel2 > channel) channel2 = 0;
1731           *(pr++) = channel2;
1732
1733           channel = *(xt++) + *(yt + 1);
1734           channel2 = (channel >> 1) + (channel >> 2);
1735           if (channel2 > channel) channel2 = 0;
1736           *(pg++) = channel2;
1737
1738           channel = *(xt++) + *(yt + 2);
1739           channel2 = (channel >> 1) + (channel >> 2);
1740           if (channel2 > channel) channel2 = 0;
1741           *(pb++) = channel2;
1742         } else {
1743           channel = *(xt++) + *(yt);
1744           channel2 = channel + (channel >> 3);
1745           if (channel2 < channel) channel2 = ~0;
1746           *(pr++) = channel2;
1747
1748           channel = *(xt++) + *(yt + 1);
1749           channel2 = channel + (channel >> 3);
1750           if (channel2 < channel) channel2 = ~0;
1751           *(pg++) = channel2;
1752
1753           channel = *(xt++) + *(yt + 2);
1754           channel2 = channel + (channel >> 3);
1755           if (channel2 < channel) channel2 = ~0;
1756           *(pb++) = channel2;
1757         }
1758       }
1759     }
1760   }
1761 #endif // INTERLACE
1762 }
1763
1764
1765 BImageControl::BImageControl(BaseDisplay *dpy, ScreenInfo *scrn, Bool _dither,
1766                              int _cpc, unsigned long cache_timeout,
1767                              unsigned long cmax)
1768 {
1769   basedisplay = dpy;
1770   screeninfo = scrn;
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, 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, 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 }