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