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