OSDN Git Service

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