OSDN Git Service

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