OSDN Git Service

[cleanup] clang-formatによる整形
[hengbandforosx/hengbandosx.git] / src / maid-x11.c
1 /* File: maid-x11.c */
2
3 /*
4  * Copyright (c) 1997 Ben Harrison, and others
5  *
6  * This software may be copied and distributed for educational, research,
7  * and not for profit purposes provided that this copyright and statement
8  * are included in all such copies.
9  */
10
11 #ifdef USE_X11
12
13 #include <math.h>
14 #include "main/x11-gamma-builder.h"
15
16 /*
17  * This file defines some "XImage" manipulation functions for X11.
18  *
19  * Original code by Desvignes Sebastien (desvigne@solar12.eerie.fr).
20  *
21  * BMP format support by Denis Eropkin (denis@dream.homepage.ru).
22  *
23  * Major fixes and cleanup by Ben Harrison (benh@phial.com).
24  *
25  * This file is designed to be "included" by "main-x11.c" or "main-xaw.c",
26  * which will have already "included" several relevant header files.
27  */
28
29
30
31 #ifndef IsModifierKey
32
33 /*
34  * Keysym macros, used on Keysyms to test for classes of symbols
35  * These were stolen from one of the X11 header files
36  *
37  * Also appears in "main-x11.c".
38  */
39
40 #define IsKeypadKey(keysym) \
41   (((unsigned)(keysym) >= XK_KP_Space) && ((unsigned)(keysym) <= XK_KP_Equal))
42
43 #define IsCursorKey(keysym) \
44   (((unsigned)(keysym) >= XK_Home)     && ((unsigned)(keysym) <  XK_Select))
45
46 #define IsPFKey(keysym) \
47   (((unsigned)(keysym) >= XK_KP_F1)     && ((unsigned)(keysym) <= XK_KP_F4))
48
49 #define IsFunctionKey(keysym) \
50   (((unsigned)(keysym) >= XK_F1)       && ((unsigned)(keysym) <= XK_F35))
51
52 #define IsMiscFunctionKey(keysym) \
53   (((unsigned)(keysym) >= XK_Select)   && ((unsigned)(keysym) <  XK_KP_Space))
54
55 #define IsModifierKey(keysym) \
56   (((unsigned)(keysym) >= XK_Shift_L)  && ((unsigned)(keysym) <= XK_Hyper_R))
57
58 #endif /* IsModifierKey */
59
60
61 /*
62  * Checks if the keysym is a special key or a normal key
63  * Assume that XK_MISCELLANY keysyms are special
64  *
65  * Also appears in "main-x11.c".
66  */
67 #define IsSpecialKey(keysym) \
68   ((unsigned)(keysym) >= 0xFF00)
69
70
71 static bool gamma_table_ready = FALSE;
72 static int gamma_val = 0;
73
74
75 /*
76  * Hack -- Convert an RGB value to an X11 Pixel, or die.
77  */
78 #ifdef USE_XFT
79 static XftColor create_pixel(Display *dpy, byte red, byte green, byte blue)
80 #else
81 static unsigned long create_pixel(Display *dpy, byte red, byte green, byte blue)
82 #endif
83 {
84         Colormap cmap = DefaultColormapOfScreen(DefaultScreenOfDisplay(dpy));
85         XColor xcolour;
86         if (!gamma_table_ready)
87         {
88                 concptr str = getenv("ANGBAND_X11_GAMMA");
89                 if (str != NULL) gamma_val = atoi(str);
90                 
91                 gamma_table_ready = TRUE;
92                 
93                 /* Only need to build the table if gamma exists */
94                 if (gamma_val) build_gamma_table(gamma_val);
95         }
96
97         /* Hack -- Gamma Correction */
98         if (gamma_val > 0)
99         {
100                 red = gamma_table[red];
101                 green = gamma_table[green];
102                 blue = gamma_table[blue];
103         }
104
105         /* Build the color */
106         
107         xcolour.red = red * 255;
108         xcolour.green = green * 255;
109         xcolour.blue = blue * 255;
110         xcolour.flags = DoRed | DoGreen | DoBlue;
111
112 #ifdef USE_XFT
113         XftColor color;
114         XRenderColor xcol;
115         xcol.red = xcolour.red;
116         xcol.green = xcolour.green;
117         xcol.blue = xcolour.blue;
118         xcol.alpha = 0xFFFF;
119         if (!XftColorAllocValue(dpy, DefaultVisual(dpy, 0), cmap, &xcol, &color))
120         {
121                 quit_fmt("Couldn't allocate bitmap color '#%02x%02x%02x'\n",
122                          red, green, blue);
123         }
124
125         return color;
126 #else
127         /* Attempt to Allocate the Parsed color */
128         if (!(XAllocColor(dpy, cmap, &xcolour)))
129         {
130                 quit_fmt("Couldn't allocate bitmap color '#%02x%02x%02x'\n",
131                          red, green, blue);
132         }
133
134         return (xcolour.pixel);
135 #endif
136 }
137
138
139 #ifndef USE_XFT
140
141 /*
142  * The Win32 "BITMAPFILEHEADER" type.
143  */
144 typedef struct BITMAPFILEHEADER
145 {
146         u16b bfType;
147         u32b bfSize;
148         u16b bfReserved1;
149         u16b bfReserved2;
150         u32b bfOffBits;
151 } BITMAPFILEHEADER;
152
153 /*
154  * The Win32 "BITMAPINFOHEADER" type.
155  */
156 typedef struct BITMAPINFOHEADER
157 {
158         u32b biSize;
159         u32b biWidth;
160         u32b biHeight;
161         u16b biPlanes;
162         u16b biBitCount;
163         u32b biCompresion;
164         u32b biSizeImage;
165         u32b biXPelsPerMeter;
166         u32b biYPelsPerMeter;
167         u32b biClrUsed;
168         u32b biClrImportand;
169 } BITMAPINFOHEADER;
170
171 /*
172  * The Win32 "RGBQUAD" type.
173  */
174 typedef struct RGBQUAD
175 {
176         unsigned char b, g, r;
177         unsigned char filler;
178 } RGBQUAD;
179
180
181 /*** Helper functions for system independent file loading. ***/
182
183 static byte get_byte(FILE *fff)
184 {
185         /* Get a character, and return it */
186         return (getc(fff) & 0xFF);
187 }
188
189 static void rd_byte(FILE *fff, byte *ip)
190 {
191         *ip = get_byte(fff);
192 }
193
194 static void rd_u16b(FILE *fff, u16b *ip)
195 {
196         (*ip) = get_byte(fff);
197         (*ip) |= ((u16b)(get_byte(fff)) << 8);
198 }
199
200 static void rd_u32b(FILE *fff, u32b *ip)
201 {
202         (*ip) = get_byte(fff);
203         (*ip) |= ((u32b)(get_byte(fff)) << 8);
204         (*ip) |= ((u32b)(get_byte(fff)) << 16);
205         (*ip) |= ((u32b)(get_byte(fff)) << 24);
206 }
207
208
209 /*
210  * Read a Win32 BMP file.
211  *
212  * This function replaces the old ReadRaw and RemapColors functions.
213  *
214  * Assumes that the bitmap has a size such that no padding is needed in
215  * various places.  Currently only handles bitmaps with 3 to 256 colors.
216  */
217 static XImage *ReadBMP(Display *dpy, char *Name)
218 {
219         Visual *visual = DefaultVisual(dpy, DefaultScreen(dpy));
220
221         int depth = DefaultDepth(dpy, DefaultScreen(dpy));
222
223         FILE *f;
224
225         BITMAPFILEHEADER fileheader;
226         BITMAPINFOHEADER infoheader;
227
228         XImage *Res = NULL;
229
230         char *Data;
231
232         int ncol;
233
234         int total;
235
236         int i, j;
237
238         int x, y;
239
240         unsigned long clr_pixels[256];
241
242
243         /* Open the BMP file */
244         f = fopen(Name, "r");
245
246         /* No such file */
247         if (f == NULL)
248         {
249                 return (NULL);
250         }
251
252         /* Read the "BITMAPFILEHEADER" */
253         rd_u16b(f, &(fileheader.bfType));
254         rd_u32b(f, &(fileheader.bfSize));
255         rd_u16b(f, &(fileheader.bfReserved1));
256         rd_u16b(f, &(fileheader.bfReserved2));
257         rd_u32b(f, &(fileheader.bfOffBits));
258
259         /* Read the "BITMAPINFOHEADER" */
260         rd_u32b(f, &(infoheader.biSize));
261         rd_u32b(f, &(infoheader.biWidth));
262         rd_u32b(f, &(infoheader.biHeight));
263         rd_u16b(f, &(infoheader.biPlanes));
264         rd_u16b(f, &(infoheader.biBitCount));
265         rd_u32b(f, &(infoheader.biCompresion));
266         rd_u32b(f, &(infoheader.biSizeImage));
267         rd_u32b(f, &(infoheader.biXPelsPerMeter));
268         rd_u32b(f, &(infoheader.biYPelsPerMeter));
269         rd_u32b(f, &(infoheader.biClrUsed));
270         rd_u32b(f, &(infoheader.biClrImportand));
271
272         /* Verify the header */
273         if (feof(f) ||
274             (fileheader.bfType != 19778) ||
275             (infoheader.biSize != 40))
276         {
277                 quit_fmt("Incorrect BMP file format %s", Name);
278         }
279
280         /* The two headers above occupy 54 bytes total */
281         /* The "bfOffBits" field says where the data starts */
282         /* The "biClrUsed" field does not seem to be reliable */
283         /* Compute number of colors recorded */
284         ncol = (fileheader.bfOffBits - 54) / 4;
285
286         for (i = 0; i < ncol; i++)
287         {
288                 RGBQUAD clrg;
289
290                 /* Read an "RGBQUAD" */
291                 rd_byte(f, &(clrg.b));
292                 rd_byte(f, &(clrg.g));
293                 rd_byte(f, &(clrg.r));
294                 rd_byte(f, &(clrg.filler));
295                 
296                 /* Analyze the color */
297                 clr_pixels[i] = create_pixel(dpy, clrg.r, clrg.g, clrg.b);
298         }
299
300         /* Determine total bytes needed for image */
301         i = 1;
302         j = (depth - 1) >> 2;
303         while (j >>= 1) i <<= 1;
304         total = infoheader.biWidth * infoheader.biHeight * i;
305
306         /* Allocate image memory */
307         C_MAKE(Data, total, char);
308
309         Res = XCreateImage(dpy, visual, depth, ZPixmap, 0 /*offset*/,
310                            Data, infoheader.biWidth, infoheader.biHeight,
311                            8 /*bitmap_pad*/, 0 /*bytes_per_line*/);
312
313         /* Failure */
314         if (Res == NULL)
315         {
316                 C_KILL(Data, total, char);
317                 fclose(f);
318                 return (NULL);
319         }
320
321         for (y = 0; y < infoheader.biHeight; y++)
322         {
323                 int y2 = infoheader.biHeight - y - 1;
324
325                 for (x = 0; x < infoheader.biWidth; x++)
326                 {
327                         int ch = getc(f);
328
329                         /* Verify not at end of file XXX XXX */
330                         if (feof(f)) quit_fmt("Unexpected end of file in %s", Name);
331
332                         if (infoheader.biBitCount == 24)
333                         {
334                                 int c2 = getc(f);
335                                 int c3 = getc(f);
336
337                                 /* Verify not at end of file XXX XXX */
338                                 if (feof(f)) quit_fmt("Unexpected end of file in %s", Name);
339
340                                 XPutPixel(Res, x, y2, create_pixel(dpy, ch, c2, c3));
341                         }
342                         else if (infoheader.biBitCount == 8)
343                         {
344                                 XPutPixel(Res, x, y2, clr_pixels[ch]);
345                         }
346                         else if (infoheader.biBitCount == 4)
347                         {
348                                 XPutPixel(Res, x, y2, clr_pixels[ch / 16]);
349                                 x++;
350                                 XPutPixel(Res, x, y2, clr_pixels[ch % 16]);
351                         }
352                         else
353                         {
354                                 /* Technically 1 bit is legal too */
355                                 quit_fmt("Illegal biBitCount %d in %s",
356                                          infoheader.biBitCount, Name);
357                         }
358                 }
359         }
360
361         fclose(f);
362
363         return Res;
364 }
365
366
367 /* ========================================================*/
368 /* Code for smooth icon rescaling from Uwe Siems, Jan 2000 */
369 /* ========================================================*/
370
371 /*
372  * to save ourselves some labour, define a maximum expected icon width here:
373  */
374 #define MAX_ICON_WIDTH 32
375
376
377 /* some static variables for composing and decomposing pixel values into
378  * red, green and blue values
379  */
380 static unsigned long redMask, greenMask, blueMask;
381 static int redShift, greenShift, blueShift;
382
383
384 /*
385  * Use smooth rescaling?
386  */
387 static bool smoothRescaling = TRUE;
388
389
390 /*
391  * GetScaledRow reads a scan from the given XImage, scales it smoothly
392  * and returns the red, green and blue values in arrays.
393  * The values in this arrays must be divided by a certain value that is
394  * calculated in ScaleIcon.
395  * x, y is the position, iw is the input width and ow the output width
396  * redScan, greenScan and blueScan must be sufficiently sized
397  */
398 static void GetScaledRow(XImage *Im, int x, int y, int iw, int ow,
399                          unsigned long *redScan, unsigned long *greenScan,
400                          unsigned long *blueScan)
401 {
402         int xi, si, sifrac, ci, cifrac, addWhole, addFrac;
403         unsigned long pix;
404         int prevRed, prevGreen, prevBlue, nextRed, nextGreen, nextBlue;
405         bool getNextPix;
406
407         if (iw == ow)
408         {
409                 /* unscaled */
410                 for (xi = 0; xi < ow; xi++)
411                 {
412                         pix = XGetPixel(Im, x + xi, y);
413                         redScan   [xi] = (pix >> redShift) & redMask;
414                         greenScan [xi] = (pix >> greenShift) & greenMask;
415                         blueScan  [xi] = (pix >> blueShift) & blueMask;
416                 }
417         }
418         else if (iw < ow)
419         {
420                 /* scaling by subsampling (grow) */
421                 iw--;
422                 ow--;
423                 /* read first pixel: */
424                 pix = XGetPixel(Im, x, y);
425                 nextRed   = (pix >> redShift) & redMask;
426                 nextGreen = (pix >> greenShift) & greenMask;
427                 nextBlue  = (pix >> blueShift) & blueMask;
428                 prevRed   = nextRed;
429                 prevGreen = nextGreen;
430                 prevBlue  = nextBlue;
431                 /* si and sifrac give the subsampling position: */
432                 si = x;
433                 sifrac = 0;
434                 /* getNextPix tells us, that we need the next pixel */
435                 getNextPix = TRUE;
436
437                 for (xi = 0; xi <= ow; xi++)
438                 {
439                         if (getNextPix)
440                         {
441                                 prevRed   = nextRed;
442                                 prevGreen = nextGreen;
443                                 prevBlue  = nextBlue;
444                                 if (xi < ow)
445                                 {
446                                         /* only get next pixel if in same icon */
447                                         pix = XGetPixel(Im, si + 1, y);
448                                         nextRed   = (pix >> redShift) & redMask;
449                                         nextGreen = (pix >> greenShift) & greenMask;
450                                         nextBlue  = (pix >> blueShift) & blueMask;
451                                 }
452                         }
453
454                         /* calculate subsampled color values: */
455                         /* division by ow occurs in ScaleIcon */
456                         redScan   [xi] = prevRed   * (ow - sifrac) + nextRed   * sifrac;
457                         greenScan [xi] = prevGreen * (ow - sifrac) + nextGreen * sifrac;
458                         blueScan  [xi] = prevBlue  * (ow - sifrac) + nextBlue  * sifrac;
459
460                         /* advance sampling position: */
461                         sifrac += iw;
462                         if (sifrac >= ow)
463                         {
464                                 si++;
465                                 sifrac -= ow;
466                                 getNextPix = TRUE;
467                         }
468                         else
469                         {
470                                 getNextPix = FALSE;
471                         }
472
473                 }
474         }
475         else
476         {
477                 /* scaling by averaging (shrink) */
478                 /* width of an output pixel in input pixels: */
479                 addWhole = iw / ow;
480                 addFrac = iw % ow;
481                 /* start position of the first output pixel: */
482                 si = x;
483                 sifrac = 0;
484                 /* get first input pixel: */
485                 pix = XGetPixel(Im, x, y);
486                 nextRed   = (pix >> redShift) & redMask;
487                 nextGreen = (pix >> greenShift) & greenMask;
488                 nextBlue  = (pix >> blueShift) & blueMask;
489                 for (xi = 0; xi < ow; xi++)
490                 {
491                         /* find endpoint of the current output pixel: */
492                         ci = si + addWhole;
493                         cifrac = sifrac + addFrac;
494                         if (cifrac >= ow)
495                         {
496                                 ci++;
497                                 cifrac -= ow;
498                         }
499                         /* take fraction of current input pixel (starting segment): */
500                         redScan[xi]   = nextRed   * (ow - sifrac);
501                         greenScan[xi] = nextGreen * (ow - sifrac);
502                         blueScan[xi]  = nextBlue  * (ow - sifrac);
503                         si++;
504                         /* add values for whole pixels: */
505                         while (si < ci)
506                         {
507                                 pix = XGetPixel(Im, si, y);
508                                 redScan[xi]   += ((pix >> redShift) & redMask)   *ow;
509                                 greenScan[xi] += ((pix >> greenShift) & greenMask) *ow;
510                                 blueScan[xi]  += ((pix >> blueShift) & blueMask)   *ow;
511                                 si++;
512                         }
513                         /* add fraction of current input pixel (ending segment): */
514                         if (xi < ow - 1)
515                         {
516                                 /* only get next pixel if still in icon: */
517                                 pix = XGetPixel(Im, si, y);
518                                 nextRed   = (pix >> redShift) & redMask;
519                                 nextGreen = (pix >> greenShift) & greenMask;
520                                 nextBlue  = (pix >> blueShift) & blueMask;
521                         }
522                         sifrac = cifrac;
523                         if (sifrac > 0)
524                         {
525                                 redScan[xi]   += nextRed   * sifrac;
526                                 greenScan[xi] += nextGreen * sifrac;
527                                 blueScan[xi]  += nextBlue  * sifrac;
528                         }
529                 }
530         }
531 }
532
533
534 /*
535  * PutRGBScan takes arrays for red, green and blue and writes pixel values
536  * according to this values in the XImage-structure. w is the number of
537  * pixels to write and div is the value by which all red/green/blue values
538  * are divided first.
539  */
540 static void PutRGBScan(XImage *Im, int x, int y, int w, int div,
541                        unsigned long *redScan, unsigned long *greenScan,
542                        unsigned long *blueScan)
543 {
544         int xi;
545         unsigned long pix;
546         unsigned long adj = div / 2;
547         for (xi = 0; xi < w; xi++)
548         {
549                 pix = (((((redScan[xi] + adj) / div) & redMask) << redShift) +
550                        ((((greenScan[xi] + adj) / div) & greenMask) << greenShift) +
551                        ((((blueScan[xi] + adj) / div) & blueMask) << blueShift));
552                 XPutPixel(Im, x + xi, y, pix);
553         }
554 }
555
556
557 /*
558  * ScaleIcon transfers an area from XImage ImIn, locate (x1,y1) to ImOut,
559  * locate (x2, y2).
560  * Source size is (ix, iy) and destination size is (ox, oy).
561  * It does this by getting icon scan line from GetScaledScan and handling
562  * them the same way as pixels are handled in GetScaledScan.
563  * This even allows icons to be scaled differently in horizontal and
564  * vertical directions (eg. shrink horizontal, grow vertical).
565  */
566 static void ScaleIcon(XImage *ImIn, XImage *ImOut,
567                       int x1, int y1, int x2, int y2,
568                       int ix, int iy, int ox, int oy)
569 {
570         int div;
571         int xi, yi, si, sifrac, ci, cifrac, addWhole, addFrac;
572
573         /* buffers for pixel rows: */
574         unsigned long prevRed   [MAX_ICON_WIDTH];
575         unsigned long prevGreen [MAX_ICON_WIDTH];
576         unsigned long prevBlue  [MAX_ICON_WIDTH];
577         unsigned long nextRed   [MAX_ICON_WIDTH];
578         unsigned long nextGreen [MAX_ICON_WIDTH];
579         unsigned long nextBlue  [MAX_ICON_WIDTH];
580         unsigned long tempRed   [MAX_ICON_WIDTH];
581         unsigned long tempGreen [MAX_ICON_WIDTH];
582         unsigned long tempBlue  [MAX_ICON_WIDTH];
583
584         bool getNextRow;
585
586         /* get divider value for the horizontal scaling: */
587         if (ix == ox)
588                 div = 1;
589         else if (ix < ox)
590                 div = ox - 1;
591         else
592                 div = ix;
593
594         if (iy == oy)
595         {
596                 /* no scaling needed vertically: */
597                 for (yi = 0; yi < oy; yi++)
598                 {
599                         GetScaledRow(ImIn, x1, y1 + yi, ix, ox,
600                                      tempRed, tempGreen, tempBlue);
601                         PutRGBScan(ImOut, x2, y2 + yi, ox, div,
602                                    tempRed, tempGreen, tempBlue);
603                 }
604         }
605         else if (iy < oy)
606         {
607                 /* scaling by subsampling (grow): */
608                 iy--;
609                 oy--;
610                 div *= oy;
611                 /* get first row: */
612                 GetScaledRow(ImIn, x1, y1, ix, ox, nextRed, nextGreen, nextBlue);
613                 /* si and sifrac give the subsampling position: */
614                 si = y1;
615                 sifrac = 0;
616                 /* getNextRow tells us, that we need the next row */
617                 getNextRow = TRUE;
618                 for (yi = 0; yi <= oy; yi++)
619                 {
620                         if (getNextRow)
621                         {
622                                 for (xi = 0; xi < ox; xi++)
623                                 {
624                                         prevRed[xi]   = nextRed[xi];
625                                         prevGreen[xi] = nextGreen[xi];
626                                         prevBlue[xi]  = nextBlue[xi];
627                                 }
628                                 if (yi < oy)
629                                 {
630                                         /* only get next row if in same icon */
631                                         GetScaledRow(ImIn, x1, si + 1, ix, ox,
632                                                      nextRed, nextGreen, nextBlue);
633                                 }
634                         }
635
636                         /* calculate subsampled color values: */
637                         /* division by oy occurs in PutRGBScan */
638                         for (xi = 0; xi < ox; xi++)
639                         {
640                                 tempRed[xi] = (prevRed[xi] * (oy - sifrac) +
641                                                nextRed[xi] * sifrac);
642                                 tempGreen[xi] = (prevGreen[xi] * (oy - sifrac) +
643                                                  nextGreen[xi] * sifrac);
644                                 tempBlue[xi] = (prevBlue[xi] * (oy - sifrac) +
645                                                 nextBlue[xi] * sifrac);
646                         }
647
648                         /* write row to output image: */
649                         PutRGBScan(ImOut, x2, y2 + yi, ox, div,
650                                    tempRed, tempGreen, tempBlue);
651
652                         /* advance sampling position: */
653                         sifrac += iy;
654                         if (sifrac >= oy)
655                         {
656                                 si++;
657                                 sifrac -= oy;
658                                 getNextRow = TRUE;
659                         }
660                         else
661                         {
662                                 getNextRow = FALSE;
663                         }
664
665                 }
666         }
667         else
668         {
669                 /* scaling by averaging (shrink) */
670                 div *= iy;
671                 /* height of a output row in input rows: */
672                 addWhole = iy / oy;
673                 addFrac = iy % oy;
674                 /* start position of the first output row: */
675                 si = y1;
676                 sifrac = 0;
677                 /* get first input row: */
678                 GetScaledRow(ImIn, x1, y1, ix, ox, nextRed, nextGreen, nextBlue);
679                 for (yi = 0; yi < oy; yi++)
680                 {
681                         /* find endpoint of the current output row: */
682                         ci = si + addWhole;
683                         cifrac = sifrac + addFrac;
684                         if (cifrac >= oy)
685                         {
686                                 ci++;
687                                 cifrac -= oy;
688                         }
689                         /* take fraction of current input row (starting segment): */
690                         for (xi = 0; xi < ox; xi++)
691                         {
692                                 tempRed[xi]   = nextRed[xi]   * (oy - sifrac);
693                                 tempGreen[xi] = nextGreen[xi] * (oy - sifrac);
694                                 tempBlue[xi]  = nextBlue[xi]  * (oy - sifrac);
695                         }
696                         si++;
697                         /* add values for whole pixels: */
698                         while (si < ci)
699                         {
700                                 GetScaledRow(ImIn, x1, si, ix, ox,
701                                              nextRed, nextGreen, nextBlue);
702                                 for (xi = 0; xi < ox; xi++)
703                                 {
704                                         tempRed[xi]   += nextRed[xi]   * oy;
705                                         tempGreen[xi] += nextGreen[xi] * oy;
706                                         tempBlue[xi]  += nextBlue[xi]  * oy;
707                                 }
708                                 si++;
709                         }
710                         /* add fraction of current input row (ending segment): */
711                         if (yi < oy - 1)
712                         {
713                                 /* only get next row if still in icon: */
714                                 GetScaledRow(ImIn, x1, si, ix, ox,
715                                              nextRed, nextGreen, nextBlue);
716                         }
717                         sifrac = cifrac;
718                         for (xi = 0; xi < ox; xi++)
719                         {
720                                 tempRed[xi]   += nextRed[xi]   * sifrac;
721                                 tempGreen[xi] += nextGreen[xi] * sifrac;
722                                 tempBlue[xi]  += nextBlue[xi]  * sifrac;
723                         }
724                         /* write row to output image: */
725                         PutRGBScan(ImOut, x2, y2 + yi, ox, div,
726                                    tempRed, tempGreen, tempBlue);
727                 }
728         }
729 }
730
731
732
733 static XImage *ResizeImageSmooth(Display *dpy, XImage *Im,
734                                  int ix, int iy, int ox, int oy)
735 {
736         Visual *visual = DefaultVisual(dpy, DefaultScreen(dpy));
737
738         int width1, height1, width2, height2;
739         int x1, x2, y1, y2;
740
741         XImage *Tmp;
742
743         char *Data;
744
745         width1 = Im->width;
746         height1 = Im->height;
747
748         width2 = ox * width1 / ix;
749         height2 = oy * height1 / iy;
750
751         Data = (char *)malloc(width2 * height2 * Im->bits_per_pixel / 8);
752
753         Tmp = XCreateImage(dpy, visual,
754                            Im->depth, ZPixmap, 0, Data, width2, height2,
755                            32, 0);
756
757         /* compute values for decomposing pixel into color values: */
758         redMask = Im->red_mask;
759         redShift = 0;
760         while ((redMask & 1) == 0)
761         {
762             redShift++;
763             redMask >>= 1;
764         }
765         greenMask = Im->green_mask;
766         greenShift = 0;
767         while ((greenMask & 1) == 0)
768         {
769             greenShift++;
770             greenMask >>= 1;
771         }
772         blueMask = Im->blue_mask;
773         blueShift = 0;
774         while ((blueMask & 1) == 0)
775         {
776             blueShift++;
777             blueMask >>= 1;
778         }
779
780         /* scale each icon: */
781         for (y1 = 0, y2 = 0; (y1 < height1) && (y2 < height2); y1 += iy, y2 += oy)
782         {
783                 for (x1 = 0, x2 = 0; (x1 < width1) && (x2 < width2); x1 += ix, x2 += ox)
784                 {
785                         ScaleIcon(Im, Tmp, x1, y1, x2, y2,
786                                   ix, iy, ox, oy);
787                 }
788         }
789
790         return Tmp;
791 }
792
793
794 /*
795  * Resize an image. XXX XXX XXX
796  *
797  * Also appears in "main-xaw.c".
798  */
799 static XImage *ResizeImage(Display *dpy, XImage *Im,
800                            int ix, int iy, int ox, int oy)
801 {
802         Visual *visual = DefaultVisual(dpy, DefaultScreen(dpy));
803
804         int width1, height1, width2, height2;
805         int x1, x2, y1, y2, Tx, Ty;
806         int *px1, *px2, *dx1, *dx2;
807         int *py1, *py2, *dy1, *dy2;
808
809         XImage *Tmp;
810
811         char *Data;
812
813         if (smoothRescaling && (ix != ox || iy != oy) &&
814             visual->class == TrueColor)
815         {
816             return ResizeImageSmooth(dpy, Im, ix, iy, ox, oy);
817         }
818
819         width1 = Im->width;
820         height1 = Im->height;
821
822         width2 = ox * width1 / ix;
823         height2 = oy * height1 / iy;
824
825         Data = (char *)malloc(width2 * height2 * Im->bits_per_pixel / 8);
826
827         Tmp = XCreateImage(dpy, visual,
828                            Im->depth, ZPixmap, 0, Data, width2, height2,
829                            32, 0);
830
831         if (ix > ox)
832         {
833                 px1 = &x1;
834                 px2 = &x2;
835                 dx1 = &ix;
836                 dx2 = &ox;
837         }
838         else
839         {
840                 px1 = &x2;
841                 px2 = &x1;
842                 dx1 = &ox;
843                 dx2 = &ix;
844         }
845
846         if (iy > oy)
847         {
848                 py1 = &y1;
849                 py2 = &y2;
850                 dy1 = &iy;
851                 dy2 = &oy;
852         }
853         else
854         {
855                 py1 = &y2;
856                 py2 = &y1;
857                 dy1 = &oy;
858                 dy2 = &iy;
859         }
860
861         Ty = *dy1/2;
862
863         for (y1 = 0, y2 = 0; (y1 < height1) && (y2 < height2); )
864         {
865                 Tx = *dx1/2;
866
867                 for (x1 = 0, x2 = 0; (x1 < width1) && (x2 < width2); )
868                 {
869                         XPutPixel(Tmp, x2, y2, XGetPixel(Im, x1, y1));
870
871                         (*px1)++;
872
873                         Tx -= *dx2;
874                         if (Tx < 0)
875                         {
876                                 Tx += *dx1;
877                                 (*px2)++;
878                         }
879                 }
880
881                 (*py1)++;
882
883                 Ty -= *dy2;
884                 if (Ty < 0)
885                 {
886                         Ty += *dy1;
887                         (*py2)++;
888                 }
889         }
890
891         return Tmp;
892 }
893
894 #endif /* !USE_XFT */
895
896 #endif /* USE_X11 */