util.c revision 8ae3b938
1/*****************************************************************************/
2/**       Copyright 1988 by Evans & Sutherland Computer Corporation,        **/
3/**                          Salt Lake City, Utah                           **/
4/**  Portions Copyright 1989 by the Massachusetts Institute of Technology   **/
5/**                        Cambridge, Massachusetts                         **/
6/**                                                                         **/
7/**                           All Rights Reserved                           **/
8/**                                                                         **/
9/**    Permission to use, copy, modify, and distribute this software and    **/
10/**    its documentation  for  any  purpose  and  without  fee is hereby    **/
11/**    granted, provided that the above copyright notice appear  in  all    **/
12/**    copies and that both  that  copyright  notice  and  this  permis-    **/
13/**    sion  notice appear in supporting  documentation,  and  that  the    **/
14/**    names of Evans & Sutherland and M.I.T. not be used in advertising    **/
15/**    in publicity pertaining to distribution of the  software  without    **/
16/**    specific, written prior permission.                                  **/
17/**                                                                         **/
18/**    EVANS & SUTHERLAND AND M.I.T. DISCLAIM ALL WARRANTIES WITH REGARD    **/
19/**    TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES  OF  MERCHANT-    **/
20/**    ABILITY  AND  FITNESS,  IN  NO  EVENT SHALL EVANS & SUTHERLAND OR    **/
21/**    M.I.T. BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL  DAM-    **/
22/**    AGES OR  ANY DAMAGES WHATSOEVER  RESULTING FROM LOSS OF USE, DATA    **/
23/**    OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER    **/
24/**    TORTIOUS ACTION, ARISING OUT OF OR IN  CONNECTION  WITH  THE  USE    **/
25/**    OR PERFORMANCE OF THIS SOFTWARE.                                     **/
26/*****************************************************************************/
27/*
28 *  [ ctwm ]
29 *
30 *  Copyright 1992 Claude Lecommandeur.
31 *
32 * Permission to use, copy, modify  and distribute this software  [ctwm] and
33 * its documentation for any purpose is hereby granted without fee, provided
34 * that the above  copyright notice appear  in all copies and that both that
35 * copyright notice and this permission notice appear in supporting documen-
36 * tation, and that the name of  Claude Lecommandeur not be used in adverti-
37 * sing or  publicity  pertaining to  distribution of  the software  without
38 * specific, written prior permission. Claude Lecommandeur make no represen-
39 * tations  about the suitability  of this software  for any purpose.  It is
40 * provided "as is" without express or implied warranty.
41 *
42 * Claude Lecommandeur DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
43 * INCLUDING ALL  IMPLIED WARRANTIES OF  MERCHANTABILITY AND FITNESS.  IN NO
44 * EVENT SHALL  Claude Lecommandeur  BE LIABLE FOR ANY SPECIAL,  INDIRECT OR
45 * CONSEQUENTIAL  DAMAGES OR ANY  DAMAGES WHATSOEVER  RESULTING FROM LOSS OF
46 * USE, DATA  OR PROFITS,  WHETHER IN AN ACTION  OF CONTRACT,  NEGLIGENCE OR
47 * OTHER  TORTIOUS ACTION,  ARISING OUT OF OR IN  CONNECTION WITH THE USE OR
48 * PERFORMANCE OF THIS SOFTWARE.
49 *
50 * Author:  Claude Lecommandeur [ lecom@sic.epfl.ch ][ April 1992 ]
51 */
52
53
54/***********************************************************************
55 *
56 * $XConsortium: util.c,v 1.47 91/07/14 13:40:37 rws Exp $
57 *
58 * utility routines for twm
59 *
60 * 28-Oct-87 Thomas E. LaStrange	File created
61 *
62 * Do the necessary modification to be integrated in ctwm.
63 * Can no longer be used for the standard twm.
64 *
65 * 22-April-92 Claude Lecommandeur.
66 *
67 * Changed behavior of DontMoveOff/MoveOffResistance to allow
68 * moving a window off screen less than #MoveOffResistance pixels.
69 * New code will no longer "snap" windows to #MoveOffResistance
70 * pixels off screen and instead movements will just be stopped and
71 * then resume once movement of #MoveOffResistance have been attempted.
72 *
73 * 15-December-02 Bjorn Knutsson
74 *
75 ***********************************************************************/
76
77#define LEVITTE_TEST
78
79#include "twm.h"
80#include "util.h"
81#include "events.h"
82#include "add_window.h"
83#include "gram.tab.h"
84#include "screen.h"
85#include "icons.h"
86#include "cursor.h"
87#include <stdio.h>
88
89/*
90 * Need this for the fixed-size uint_*'s used below.  stdint.h would be
91 * the more appropriate include, but there exist systems that don't have
92 * it, but do have inttypes.h (FreeBSD 4, Solaris 7-9 I've heard of,
93 * probably more).
94 */
95#include <inttypes.h>
96
97#ifdef VMS
98#include <decw$include/Xos.h>
99#include <decw$include/Xatom.h>
100#include <decw$include/Xutil.h>
101#include <X11Xmu/Drawing.h>
102#include <X11Xmu/CharSet.h>
103#include <X11Xmu/WinUtil.h>
104#ifdef HAVE_XWDFILE_H
105#include "XWDFile.h"		/* We do some tricks, since the original
106				   has bugs...		/Richard Levitte */
107#endif /* HAVE_XWDFILE_H */
108#include <unixlib.h>
109#include <starlet.h>
110#include <ssdef.h>
111#include <psldef.h>
112#include <lib$routines.h>
113#ifdef __DECC
114#include <unistd.h>
115#endif /* __DECC */
116#define USE_SIGNALS
117#ifndef F_OK
118#  define F_OK 0
119#endif
120#ifndef X_OK
121#  define X_OK 1
122#endif
123#ifndef W_OK
124#  define W_OK 2
125#endif
126#ifndef R_OK
127#  define R_OK 4
128#endif
129#else /* !VMS */
130#include <X11/Xos.h>
131#include <X11/Xatom.h>
132#include <X11/Xmu/Drawing.h>
133#include <X11/Xmu/CharSet.h>
134#include <X11/Xmu/WinUtil.h>
135#include <X11/XWDFile.h>
136#endif /* VMS */
137
138#if defined(USE_SIGNALS) && defined(__sgi)
139#  define _BSD_SIGNALS
140#endif
141
142#include <signal.h>
143#ifndef VMS
144#include <sys/time.h>
145#endif
146
147#if defined (XPM)
148#ifdef VMS
149#include "xpm.h"
150#else
151#   include <X11/xpm.h>
152#endif
153#endif
154
155#ifdef JPEG
156# include <setjmp.h>
157# include <jpeglib.h>
158# include <jerror.h>
159  static Image *LoadJpegImage (char *name);
160  static Image *GetJpegImage  (char *name);
161
162  struct jpeg_error {
163    struct jpeg_error_mgr pub;
164    sigjmp_buf setjmp_buffer;
165  };
166
167  typedef struct jpeg_error *jerr_ptr;
168#endif /* JPEG */
169
170#ifdef IMCONV
171#   include "im.h"
172#   include "sdsc.h"
173#endif
174
175#define MAXANIMATIONSPEED 20
176
177extern Atom _XA_WM_WORKSPACESLIST;
178
179static Image *LoadBitmapImage (char  *name, ColorPair cp);
180static Image *GetBitmapImage  (char  *name, ColorPair cp);
181#if !defined(VMS) || defined(HAVE_XWDFILE_H)
182static Image *LoadXwdImage    (char  *filename, ColorPair cp);
183static Image *GetXwdImage     (char  *name, ColorPair cp);
184#endif
185#ifdef XPM
186static Image *LoadXpmImage    (char  *name, ColorPair cp);
187static Image *GetXpmImage     (char  *name, ColorPair cp);
188static void   xpmErrorMessage (int status, char *name, char *fullname);
189#endif
190#ifdef IMCONV
191static Image *GetImconvImage  (char *filename,
192			       unsigned int *widthp, unsigned int *heightp);
193#endif
194static Pixmap CreateXLogoPixmap(unsigned int *widthp, unsigned int *heightp);
195static Pixmap CreateResizePixmap(unsigned int *widthp, unsigned int *heightp);
196static Pixmap CreateQuestionPixmap(unsigned int *widthp, unsigned int *heightp);
197static Pixmap CreateMenuPixmap(unsigned int *widthp, unsigned int *heightp);
198static Pixmap CreateDotPixmap (unsigned int *widthp, unsigned int *heightp);
199static Image  *Create3DMenuImage (ColorPair cp);
200static Image  *Create3DDotImage (ColorPair cp);
201static Image  *Create3DResizeImage (ColorPair cp);
202static Image  *Create3DZoomImage (ColorPair cp);
203static Image  *Create3DBarImage (ColorPair cp);
204static Image  *Create3DVertBarImage (ColorPair cp);
205static Image  *Create3DResizeAnimation (Bool in, Bool left, Bool top,
206					ColorPair cp);
207static Image  *Create3DCrossImage (ColorPair cp);
208static Image  *Create3DIconifyImage (ColorPair cp);
209static Image  *Create3DSunkenResizeImage (ColorPair cp);
210static Image  *Create3DBoxImage (ColorPair cp);
211
212extern FILE *tracefile;
213
214void FreeImage (Image *image);
215
216void _swapshort (register char *bp, register unsigned n);
217void _swaplong (register char *bp, register unsigned n);
218
219static int    reportfilenotfound = 1;
220static Colormap AlternateCmap = None;
221
222int  HotX, HotY;
223
224int  AnimationSpeed   = 0;
225Bool AnimationActive  = False;
226Bool MaybeAnimate     = True;
227#ifdef USE_SIGNALS
228   Bool AnimationPending = False;
229#else
230   struct timeval AnimateTimeout;
231#endif /* USE_SIGNALS */
232
233/***********************************************************************
234 *
235 *  Procedure:
236 *	MoveOutline - move a window outline
237 *
238 *  Inputs:
239 *	root	    - the window we are outlining
240 *	x	    - upper left x coordinate
241 *	y	    - upper left y coordinate
242 *	width	    - the width of the rectangle
243 *	height	    - the height of the rectangle
244 *      bw          - the border width of the frame
245 *      th          - title height
246 *
247 ***********************************************************************
248 */
249
250/* ARGSUSED */
251void MoveOutline(Window root,
252		 int x, int y, int width, int height, int bw, int th)
253{
254    static int	lastx = 0;
255    static int	lasty = 0;
256    static int	lastWidth = 0;
257    static int	lastHeight = 0;
258    static int	lastBW = 0;
259    static int	lastTH = 0;
260    int		xl, xr, yt, yb, xinnerl, xinnerr, yinnert, yinnerb;
261    int		xthird, ythird;
262    XSegment	outline[18];
263    register XSegment	*r;
264
265    if (x == lastx && y == lasty && width == lastWidth && height == lastHeight
266	&& lastBW == bw && th == lastTH)
267	return;
268
269    r = outline;
270
271#define DRAWIT() \
272    if (lastWidth || lastHeight)			\
273    {							\
274	xl = lastx;					\
275	xr = lastx + lastWidth - 1;			\
276	yt = lasty;					\
277	yb = lasty + lastHeight - 1;			\
278	xinnerl = xl + lastBW;				\
279	xinnerr = xr - lastBW;				\
280	yinnert = yt + lastTH + lastBW;			\
281	yinnerb = yb - lastBW;				\
282	xthird = (xinnerr - xinnerl) / 3;		\
283	ythird = (yinnerb - yinnert) / 3;		\
284							\
285	r->x1 = xl;					\
286	r->y1 = yt;					\
287	r->x2 = xr;					\
288	r->y2 = yt;					\
289	r++;						\
290							\
291	r->x1 = xl;					\
292	r->y1 = yb;					\
293	r->x2 = xr;					\
294	r->y2 = yb;					\
295	r++;						\
296							\
297	r->x1 = xl;					\
298	r->y1 = yt;					\
299	r->x2 = xl;					\
300	r->y2 = yb;					\
301	r++;						\
302							\
303	r->x1 = xr;					\
304	r->y1 = yt;					\
305	r->x2 = xr;					\
306	r->y2 = yb;					\
307	r++;						\
308							\
309	r->x1 = xinnerl + xthird;			\
310	r->y1 = yinnert;				\
311	r->x2 = r->x1;					\
312	r->y2 = yinnerb;				\
313	r++;						\
314							\
315	r->x1 = xinnerl + (2 * xthird);			\
316	r->y1 = yinnert;				\
317	r->x2 = r->x1;					\
318	r->y2 = yinnerb;				\
319	r++;						\
320							\
321	r->x1 = xinnerl;				\
322	r->y1 = yinnert + ythird;			\
323	r->x2 = xinnerr;				\
324	r->y2 = r->y1;					\
325	r++;						\
326							\
327	r->x1 = xinnerl;				\
328	r->y1 = yinnert + (2 * ythird);			\
329	r->x2 = xinnerr;				\
330	r->y2 = r->y1;					\
331	r++;						\
332							\
333	if (lastTH != 0) {				\
334	    r->x1 = xl;					\
335	    r->y1 = yt + lastTH;			\
336	    r->x2 = xr;					\
337	    r->y2 = r->y1;				\
338	    r++;					\
339	}						\
340    }
341
342    /* undraw the old one, if any */
343    DRAWIT ();
344
345    lastx = x;
346    lasty = y;
347    lastWidth = width;
348    lastHeight = height;
349    lastBW = bw;
350    lastTH = th;
351
352    /* draw the new one, if any */
353    DRAWIT ();
354
355#undef DRAWIT
356
357
358    if (r != outline)
359    {
360	XDrawSegments(dpy, root, Scr->DrawGC, outline, r - outline);
361    }
362}
363
364/***********************************************************************
365 *
366 *  Procedure:
367 *	Zoom - zoom in or out of an icon
368 *
369 *  Inputs:
370 *	wf	- window to zoom from
371 *	wt	- window to zoom to
372 *
373 ***********************************************************************
374 */
375
376void Zoom(Window wf, Window wt)
377{
378    int fx, fy, tx, ty;			/* from, to */
379    unsigned int fw, fh, tw, th;	/* from, to */
380    long dx, dy, dw, dh;
381    long z;
382    int j;
383
384    if ((Scr->IconifyStyle != ICONIFY_NORMAL) || !Scr->DoZoom || Scr->ZoomCount < 1) return;
385
386    if (wf == None || wt == None) return;
387
388    XGetGeometry (dpy, wf, &JunkRoot, &fx, &fy, &fw, &fh, &JunkBW, &JunkDepth);
389    XGetGeometry (dpy, wt, &JunkRoot, &tx, &ty, &tw, &th, &JunkBW, &JunkDepth);
390
391    dx = (long) tx - (long) fx;	/* going from -> to */
392    dy = (long) ty - (long) fy;	/* going from -> to */
393    dw = (long) tw - (long) fw;	/* going from -> to */
394    dh = (long) th - (long) fh;	/* going from -> to */
395    z = (long) (Scr->ZoomCount + 1);
396
397    for (j = 0; j < 2; j++) {
398	long i;
399
400	XDrawRectangle (dpy, Scr->Root, Scr->DrawGC, fx, fy, fw, fh);
401	for (i = 1; i < z; i++) {
402	    int x = fx + (int) ((dx * i) / z);
403	    int y = fy + (int) ((dy * i) / z);
404	    unsigned width = (unsigned) (((long) fw) + (dw * i) / z);
405	    unsigned height = (unsigned) (((long) fh) + (dh * i) / z);
406
407	    XDrawRectangle (dpy, Scr->Root, Scr->DrawGC,
408			    x, y, width, height);
409	}
410	XDrawRectangle (dpy, Scr->Root, Scr->DrawGC, tx, ty, tw, th);
411    }
412}
413
414
415char *ExpandFilePath (char *path)
416{
417    char *ret, *colon, *p;
418    int  len;
419
420    len = 0;
421    p   = path;
422    while ((colon = strchr (p, ':'))) {
423	len += colon - p + 1;
424	if (*p == '~') len += HomeLen - 1;
425	p = colon + 1;
426    }
427    if (*p == '~') len += HomeLen - 1;
428    len += strlen (p);
429    ret = (char*) malloc (len + 1);
430    *ret = 0;
431
432    p   = path;
433    while ((colon = strchr (p, ':'))) {
434	*colon = '\0';
435	if (*p == '~') {
436	    strcat (ret, Home);
437	    strcat (ret, p + 1);
438	} else {
439	    strcat (ret, p);
440	}
441	*colon = ':';
442	strcat (ret, ":");
443	p = colon + 1;
444    }
445    if (*p == '~') {
446	strcat (ret, Home);
447	strcat (ret, p + 1);
448    } else {
449	strcat (ret, p);
450    }
451    return ret;
452}
453
454/***********************************************************************
455 *
456 *  Procedure:
457 *	ExpandFilename - expand the tilde character to HOME
458 *		if it is the first character of the filename
459 *
460 *  Returned Value:
461 *	a pointer to the new name
462 *
463 *  Inputs:
464 *	name	- the filename to expand
465 *
466 ***********************************************************************
467 */
468
469char *ExpandFilename(char *name)
470{
471    char *newname;
472
473    if (name[0] != '~') return name;
474
475#ifdef VMS
476    newname = (char *) malloc (HomeLen + strlen(name) + 1);
477    if (!newname) {
478        fprintf (stderr,
479 		 "%s:  unable to allocate %d bytes to expand filename %s%s\n",
480 		 ProgramName, HomeLen + strlen(name) + 1, Home, &name[1]);
481    } else {
482        (void) sprintf (newname, "%s%s", Home, &name[1]);
483    }
484#else
485    newname = (char *) malloc (HomeLen + strlen(name) + 2);
486    if (!newname) {
487	fprintf (stderr,
488		 "%s:  unable to allocate %lu bytes to expand filename %s/%s\n",
489		 ProgramName, (unsigned long) HomeLen + strlen(name) + 2,
490		 Home, &name[1]);
491    } else {
492	(void) sprintf (newname, "%s/%s", Home, &name[1]);
493    }
494#endif
495
496    return newname;
497}
498
499char *ExpandPixmapPath (char *name)
500{
501    char    *ret, *colon;
502
503    ret = NULL;
504#ifdef VMS
505    if (name[0] == '~') {
506	ret = (char *) malloc (HomeLen + strlen (name) + 1);
507	sprintf (ret, "%s%s", Home, &name[1]);
508    }
509    if (name[0] == '/') {
510	ret = (char *) malloc (strlen (name));
511	sprintf (ret, "%s", &name[1]);
512    }
513    else
514    if (Scr->PixmapDirectory) {
515	char *p = Scr->PixmapDirectory;
516	while (colon = strchr (p, ':')) {
517	    *colon = '\0';
518	    ret = (char *) malloc (strlen (p) + strlen (name) + 1);
519	    sprintf (ret, "%s%s", p, name);
520	    *colon = ':';
521	    if (!access (ret, R_OK)) return (ret);
522	    p = colon + 1;
523	}
524        ret = (char *) malloc (strlen (Scr->PixmapDirectory) + strlen (name) + 1);
525	sprintf (ret, "%s%s", Scr->PixmapDirectory, name);
526    }
527#else
528    if (name[0] == '~') {
529	ret = (char *) malloc (HomeLen + strlen (name) + 2);
530	sprintf (ret, "%s/%s", Home, &name[1]);
531    }
532    else
533    if (name[0] == '/') {
534	ret = (char *) malloc (strlen (name) + 1);
535	strcpy (ret, name);
536    }
537    else
538    if (Scr->PixmapDirectory) {
539	char *p = Scr->PixmapDirectory;
540	while ((colon = strchr (p, ':'))) {
541	    *colon = '\0';
542	    ret = (char *) malloc (strlen (p) + strlen (name) + 2);
543	    sprintf (ret, "%s/%s", p, name);
544	    *colon = ':';
545	    if (!access (ret, R_OK)) return (ret);
546	    p = colon + 1;
547	}
548	ret = (char *) malloc (strlen (p) + strlen (name) + 2);
549	sprintf (ret, "%s/%s", p, name);
550    }
551#endif
552    return (ret);
553}
554
555/***********************************************************************
556 *
557 *  Procedure:
558 *	GetUnknownIcon - read in the bitmap file for the unknown icon
559 *
560 *  Inputs:
561 *	name - the filename to read
562 *
563 ***********************************************************************
564 */
565
566void GetUnknownIcon(char *name)
567{
568    Scr->UnknownImage = GetImage (name, Scr->IconC);
569}
570
571/***********************************************************************
572 *
573 *  Procedure:
574 *	FindBitmap - read in a bitmap file and return size
575 *
576 *  Returned Value:
577 *	the pixmap associated with the bitmap
578 *      widthp	- pointer to width of bitmap
579 *      heightp	- pointer to height of bitmap
580 *
581 *  Inputs:
582 *	name	- the filename to read
583 *
584 ***********************************************************************
585 */
586
587Pixmap FindBitmap (char *name, unsigned int *widthp, unsigned int *heightp)
588{
589    char *bigname;
590    Pixmap pm;
591
592    if (!name) return None;
593
594    /*
595     * Names of the form :name refer to hardcoded images that are scaled to
596     * look nice in title buttons.  Eventually, it would be nice to put in a
597     * menu symbol as well....
598     */
599    if (name[0] == ':') {
600	int i;
601	static struct {
602	    char *name;
603	    Pixmap (*proc)(unsigned int *wp, unsigned int *hp);
604	} pmtab[] = {
605	    { TBPM_DOT,		CreateDotPixmap },
606	    { TBPM_ICONIFY,	CreateDotPixmap },
607	    { TBPM_RESIZE,	CreateResizePixmap },
608	    { TBPM_XLOGO,	CreateXLogoPixmap },
609	    { TBPM_DELETE,	CreateXLogoPixmap },
610	    { TBPM_MENU,	CreateMenuPixmap },
611	    { TBPM_QUESTION,	CreateQuestionPixmap },
612	};
613
614	for (i = 0; i < (sizeof pmtab)/(sizeof pmtab[0]); i++) {
615	    if (XmuCompareISOLatin1 (pmtab[i].name, name) == 0)
616	      return (*pmtab[i].proc) (widthp, heightp);
617	}
618	fprintf (stderr, "%s:  no such built-in bitmap \"%s\"\n",
619		 ProgramName, name);
620	return None;
621    }
622
623    /*
624     * Generate a full pathname if any special prefix characters (such as ~)
625     * are used.  If the bigname is different from name, bigname will need to
626     * be freed.
627     */
628    bigname = ExpandFilename (name);
629    if (!bigname) return None;
630
631    /*
632     * look along bitmapFilePath resource same as toolkit clients
633     */
634    pm = XmuLocateBitmapFile (ScreenOfDisplay(dpy, Scr->screen), bigname, NULL,
635			      0, (int *)widthp, (int *)heightp, &HotX, &HotY);
636    if (pm == None && Scr->IconDirectory && bigname[0] != '/') {
637	if (bigname != name) free (bigname);
638	/*
639	 * Attempt to find icon in old IconDirectory (now obsolete)
640	 */
641#ifdef VMS
642	bigname = (char *) malloc (strlen(name) + strlen(Scr->IconDirectory) + 1);
643	if (!bigname) {
644	    fprintf (stderr,
645		"%s:  unable to allocate memory for \"%s%s\"\n",
646		ProgramName, Scr->IconDirectory, name);
647	    return None;
648	}
649	(void) sprintf (bigname, "%s%s", Scr->IconDirectory, name);
650#else
651	bigname = (char *) malloc (strlen(name) + strlen(Scr->IconDirectory) + 2);
652	if (!bigname) {
653	    fprintf (stderr,
654		     "%s:  unable to allocate memory for \"%s/%s\"\n",
655		     ProgramName, Scr->IconDirectory, name);
656	    return None;
657	}
658	(void) sprintf (bigname, "%s/%s", Scr->IconDirectory, name);
659#endif
660	if (XReadBitmapFile (dpy, Scr->Root, bigname, widthp, heightp, &pm,
661			     &HotX, &HotY) != BitmapSuccess) {
662	    pm = None;
663	}
664    }
665    if (bigname != name) free (bigname);
666    if ((pm == None) && reportfilenotfound) {
667	fprintf (stderr, "%s:  unable to find bitmap \"%s\"\n", ProgramName, name);
668    }
669
670    return pm;
671}
672
673Pixmap GetBitmap (char *name)
674{
675    return FindBitmap (name, &JunkWidth, &JunkHeight);
676}
677
678static Image *LoadBitmapImage (char  *name, ColorPair cp)
679{
680    Image	 *image;
681    Pixmap	 bm;
682    unsigned int width, height;
683    XGCValues	 gcvalues;
684
685    if (Scr->rootGC == (GC) 0) Scr->rootGC = XCreateGC (dpy, Scr->Root, 0, &gcvalues);
686    bm = FindBitmap (name, &width, &height);
687    if (bm == None) return (None);
688
689    image = (Image*) malloc (sizeof (struct _Image));
690    image->pixmap = XCreatePixmap (dpy, Scr->Root, width, height, Scr->d_depth);
691    gcvalues.background = cp.back;
692    gcvalues.foreground = cp.fore;
693    XChangeGC   (dpy, Scr->rootGC, GCForeground | GCBackground, &gcvalues);
694    XCopyPlane  (dpy, bm, image->pixmap, Scr->rootGC, 0, 0, width, height,
695		0, 0, (unsigned long) 1);
696    XFreePixmap (dpy, bm);
697    image->mask   = None;
698    image->width  = width;
699    image->height = height;
700    image->next   = None;
701    return (image);
702}
703
704static Image *GetBitmapImage (char  *name, ColorPair cp)
705{
706    Image	*image, *r, *s;
707    char	path [128], pref [128];
708    char	*perc;
709    int		i;
710
711    if (! strchr (name, '%')) return (LoadBitmapImage (name, cp));
712    s = image = None;
713    strcpy (pref, name);
714    perc  = strchr (pref, '%');
715    *perc = '\0';
716    reportfilenotfound = 0;
717    for (i = 1;; i++) {
718	sprintf (path, "%s%d%s", pref, i, perc + 1);
719	r = LoadBitmapImage (path, cp);
720	if (r == None) break;
721	r->next = None;
722	if (image == None) s = image = r;
723	else {
724	    s->next = r;
725	    s = r;
726	}
727    }
728    reportfilenotfound = 1;
729    if (s != None) s->next = image;
730    if (image == None) {
731	fprintf (stderr, "Cannot open any %s bitmap file\n", name);
732    }
733    return (image);
734}
735
736#ifdef XPM
737static int reportxpmerror = 1;
738
739static Image *LoadXpmImage (char *name, ColorPair cp)
740{
741    char	*fullname;
742    Image	*image;
743    int		status;
744    Colormap    stdcmap = Scr->RootColormaps.cwins[0]->colormap->c;
745    XpmAttributes attributes;
746    static XpmColorSymbol overrides[] = {
747	{"Foreground", NULL, 0},
748	{"Background", NULL, 0},
749	{"HiShadow", NULL, 0},
750	{"LoShadow", NULL, 0}
751    };
752
753    fullname = ExpandPixmapPath (name);
754    if (! fullname) return (None);
755
756    image = (Image*) malloc (sizeof (struct _Image));
757    if (image == None) return (None);
758
759    attributes.valuemask  = 0;
760    attributes.valuemask |= XpmSize;
761    attributes.valuemask |= XpmReturnPixels;
762    attributes.valuemask |= XpmColormap;
763    attributes.valuemask |= XpmDepth;
764    attributes.valuemask |= XpmVisual;
765    attributes.valuemask |= XpmCloseness;
766    attributes.valuemask |= XpmColorSymbols;
767
768    attributes.numsymbols = 4;
769    attributes.colorsymbols = overrides;
770    overrides[0].pixel = cp.fore;
771    overrides[1].pixel = cp.back;
772    overrides[2].pixel = cp.shadd;
773    overrides[3].pixel = cp.shadc;
774
775
776    attributes.colormap  = AlternateCmap ? AlternateCmap : stdcmap;
777    attributes.depth     = Scr->d_depth;
778    attributes.visual    = Scr->d_visual;
779    attributes.closeness = 65535; /* Never fail */
780    status = XpmReadFileToPixmap(dpy, Scr->Root, fullname,
781				 &(image->pixmap), &(image->mask), &attributes);
782    if (status != XpmSuccess) {
783	xpmErrorMessage (status, name, fullname);
784	free (image);
785	return (None);
786    }
787    free (fullname);
788    image->width  = attributes.width;
789    image->height = attributes.height;
790    image->next   = None;
791    return (image);
792}
793
794static Image *GetXpmImage (char *name, ColorPair cp)
795{
796    char    path [128], pref [128];
797    Image   *image, *r, *s;
798    char    *perc;
799    int     i;
800
801    if (! strchr (name, '%')) return (LoadXpmImage (name, cp));
802    s = image = None;
803    strcpy (pref, name);
804    perc  = strchr (pref, '%');
805    *perc = '\0';
806    reportfilenotfound = 0;
807    for (i = 1;; i++) {
808	sprintf (path, "%s%d%s", pref, i, perc + 1);
809	r = LoadXpmImage (path, cp);
810	if (r == None) break;
811	r->next = None;
812	if (image == None) s = image = r;
813	else {
814	    s->next = r;
815	    s = r;
816	}
817    }
818    reportfilenotfound = 1;
819    if (s != None) s->next = image;
820    if (image == None) {
821	fprintf (stderr, "Cannot open any %s XPM file\n", name);
822    }
823    return (image);
824}
825
826static void xpmErrorMessage (int status, char *name, char *fullname)
827{
828    switch (status) {
829	case XpmSuccess:
830	    break;
831
832	case XpmColorError:
833	    if (reportxpmerror)
834		fprintf (stderr,
835			"Could not parse or alloc requested color : %s\n",
836			fullname);
837	    return;
838
839	case XpmOpenFailed:
840	    if (reportxpmerror && reportfilenotfound)
841		fprintf (stderr, "unable to locate XPM file : %s\n", fullname);
842	    return;
843
844	case XpmFileInvalid:
845	    fprintf (stderr, "invalid XPM file : %s\n", fullname);
846	    return;
847
848	case XpmNoMemory:
849	    if (reportxpmerror)
850		fprintf (stderr, "Not enough memory for XPM file : %s\n", fullname);
851	    return;
852
853	case XpmColorFailed:
854	    if (reportxpmerror)
855		fprintf (stderr, "Color not found in : %s\n", fullname);
856	    return;
857
858	default :
859	    fprintf (stderr, "Unknown error in : %s\n", fullname);
860	    return;
861    }
862}
863
864#endif
865
866void MaskScreen (char *file)
867{
868    unsigned long valuemask;
869    XSetWindowAttributes attributes;
870    XEvent event;
871    Cursor waitcursor;
872    int x, y;
873    ColorPair WelcomeCp;
874    XColor black;
875
876    NewFontCursor (&waitcursor, "watch");
877
878    valuemask = (CWBackingStore | CWSaveUnder | CWBackPixel |
879		 CWOverrideRedirect | CWEventMask | CWCursor);
880    attributes.backing_store	 = NotUseful;
881    attributes.save_under	 = False;
882    attributes.override_redirect = True;
883    attributes.event_mask	 = ExposureMask;
884    attributes.cursor		 = waitcursor;
885    attributes.background_pixel	 = Scr->Black;
886    Scr->WindowMask = XCreateWindow (dpy, Scr->Root, 0, 0,
887			(unsigned int) Scr->rootw,
888			(unsigned int) Scr->rooth,
889			(unsigned int) 0,
890			CopyFromParent, (unsigned int) CopyFromParent,
891			(Visual *) CopyFromParent, valuemask,
892			&attributes);
893    XMapWindow (dpy, Scr->WindowMask);
894    XMaskEvent (dpy, ExposureMask, &event);
895
896    if (Scr->Monochrome != COLOR) return;
897
898    WelcomeCp.fore = Scr->Black;
899    WelcomeCp.back = Scr->White;
900    Scr->WelcomeCmap  = XCreateColormap (dpy, Scr->WindowMask, Scr->d_visual, AllocNone);
901    if (! Scr->WelcomeCmap) return;
902    XSetWindowColormap (dpy, Scr->WindowMask, Scr->WelcomeCmap);
903    black.red   = 0;
904    black.green = 0;
905    black.blue  = 0;
906    XAllocColor (dpy, Scr->WelcomeCmap, &black);
907
908    reportfilenotfound = 0;
909    AlternateCmap = Scr->WelcomeCmap;
910    if (! file) {
911#ifdef CTWM_WELCOME_FILE
912	Scr->WelcomeImage  = GetImage (CTWM_WELCOME_FILE, WelcomeCp);
913	if (Scr->WelcomeImage == None)
914#endif
915	Scr->WelcomeImage  = GetImage ("xwd:welcome.xwd", WelcomeCp);
916#ifdef XPM
917	if (Scr->WelcomeImage == None)
918		Scr->WelcomeImage  = GetImage ("xpm:welcome.xpm", WelcomeCp);
919#endif
920    }
921    else {
922	Scr->WelcomeImage  = GetImage (file, WelcomeCp);
923    }
924    AlternateCmap = None;
925    reportfilenotfound = 1;
926    if (Scr->WelcomeImage == None) return;
927
928    if (captive) {
929	XSetWindowColormap (dpy, Scr->WindowMask, Scr->WelcomeCmap);
930	XSetWMColormapWindows (dpy, Scr->Root, &(Scr->WindowMask), 1);
931    }
932    else XInstallColormap (dpy, Scr->WelcomeCmap);
933
934    Scr->WelcomeGC = XCreateGC (dpy, Scr->WindowMask, 0, NULL);
935    x = (Scr->rootw  -  Scr->WelcomeImage->width) / 2;
936    y = (Scr->rooth - Scr->WelcomeImage->height) / 2;
937
938    XSetWindowBackground (dpy, Scr->WindowMask, black.pixel);
939    XClearWindow (dpy, Scr->WindowMask);
940    XCopyArea (dpy, Scr->WelcomeImage->pixmap, Scr->WindowMask, Scr->WelcomeGC, 0, 0,
941		Scr->WelcomeImage->width, Scr->WelcomeImage->height, x, y);
942}
943
944void UnmaskScreen (void)
945{
946#ifdef VMS
947    float  timeout;
948#else
949    struct timeval	timeout;
950#endif
951    Colormap            stdcmap = Scr->RootColormaps.cwins[0]->colormap->c;
952    Colormap		cmap;
953    XColor		colors [256], stdcolors [256];
954    int			i, j, usec;
955
956#ifdef VMS
957    timeout = 0.017;
958#else
959    usec = 10000;
960    timeout.tv_usec = usec % (unsigned long) 1000000;
961    timeout.tv_sec  = usec / (unsigned long) 1000000;
962#endif
963
964    if (Scr->WelcomeImage) {
965	Pixel pixels [256];
966
967	cmap = Scr->WelcomeCmap;
968	for (i = 0; i < 256; i++) {
969	    pixels [i] = i;
970	    colors [i].pixel = i;
971	}
972	XQueryColors (dpy, cmap, colors, 256);
973	XFreeColors  (dpy, cmap, pixels, 256, 0L);
974	XFreeColors  (dpy, cmap, pixels, 256, 0L); /* Ah Ah */
975
976	for (i = 0; i < 256; i++) {
977	    colors [i].pixel = i;
978	    colors [i].flags = DoRed | DoGreen | DoBlue;
979	    stdcolors [i].red   = colors [i].red;
980	    stdcolors [i].green = colors [i].green;
981	    stdcolors [i].blue  = colors [i].blue;
982	}
983	for (i = 0; i < 128; i++) {
984	    for (j = 0; j < 256; j++) {
985		colors [j].red   = stdcolors [j].red   * ((127.0 - i) / 128.0);
986		colors [j].green = stdcolors [j].green * ((127.0 - i) / 128.0);
987		colors [j].blue  = stdcolors [j].blue  * ((127.0 - i) / 128.0);
988	    }
989	    XStoreColors (dpy, cmap, colors, 256);
990#ifdef VMS
991	    lib$wait(&timeout);
992#else
993	    select (0, (void *) 0, (void *) 0, (void *) 0, &timeout);
994#endif
995	}
996	XFreeColors   (dpy, cmap, pixels, 256, 0L);
997	XFreeGC       (dpy, Scr->WelcomeGC);
998	FreeImage     (Scr->WelcomeImage);
999    }
1000    if (Scr->Monochrome != COLOR) goto fin;
1001
1002    cmap = XCreateColormap (dpy, Scr->Root, Scr->d_visual, AllocNone);
1003    if (! cmap) goto fin;
1004    for (i = 0; i < 256; i++) {
1005	colors [i].pixel = i;
1006	colors [i].red   = 0;
1007	colors [i].green = 0;
1008	colors [i].blue  = 0;
1009	colors [i].flags = DoRed | DoGreen | DoBlue;
1010    }
1011    XStoreColors (dpy, cmap, colors, 256);
1012
1013    if (captive) XSetWindowColormap (dpy, Scr->Root, cmap);
1014    else XInstallColormap (dpy, cmap);
1015
1016    XUnmapWindow (dpy, Scr->WindowMask);
1017    XClearWindow (dpy, Scr->Root);
1018    XSync (dpy, 0);
1019    PaintAllDecoration ();
1020
1021    for (i = 0; i < 256; i++) stdcolors [i].pixel = i;
1022    XQueryColors (dpy, stdcmap, stdcolors, 256);
1023    for (i = 0; i < 128; i++) {
1024	for (j = 0; j < 256; j++) {
1025	    colors [j].pixel = j;
1026	    colors [j].red   = stdcolors [j].red   * (i / 127.0);
1027	    colors [j].green = stdcolors [j].green * (i / 127.0);
1028	    colors [j].blue  = stdcolors [j].blue  * (i / 127.0);
1029	    colors [j].flags = DoRed | DoGreen | DoBlue;
1030	}
1031	XStoreColors (dpy, cmap, colors, 256);
1032#ifdef VMS
1033        lib$wait(&timeout);
1034#else
1035	select (0, (void *) 0, (void *) 0, (void *) 0, &timeout);
1036#endif
1037    }
1038
1039    if (captive) XSetWindowColormap (dpy, Scr->Root, stdcmap);
1040    else XInstallColormap (dpy, stdcmap);
1041
1042    XFreeColormap (dpy, cmap);
1043
1044fin:
1045    if (Scr->WelcomeCmap) XFreeColormap (dpy, Scr->WelcomeCmap);
1046    XDestroyWindow (dpy, Scr->WindowMask);
1047    Scr->WindowMask = (Window) 0;
1048}
1049
1050#ifdef VMS
1051
1052/* use the VMS system services to request the timer to issue an AST */
1053void AnimateHandler (void);
1054
1055unsigned int tv[2];
1056int status;
1057static unsigned long timefi;
1058/* unsigned long timefe = 17; */
1059unsigned long timefe;
1060
1061#define TIMID 12L
1062
1063void StartAnimation (void)
1064{
1065    if (AnimationSpeed > MAXANIMATIONSPEED) AnimationSpeed = MAXANIMATIONSPEED;
1066    if (AnimationSpeed <= 0) return;
1067    if (AnimationActive) return;
1068
1069    if (!timefi) lib$get_ef(&timefi);
1070    if (!timefe) lib$get_ef(&timefe);
1071
1072    tv[1] = 0xFFFFFFFF;                   /* quadword negative for relative */
1073    tv[0] = -(10000000 / AnimationSpeed); /* time. In units of 100ns. */
1074    sys$clref(timefe);
1075    status = sys$setimr (timefi, &tv, AnimateHandler, TIMID );
1076    if (status != SS$_NORMAL) lib$signal(status);
1077    AnimationActive = True;
1078}
1079
1080void StopAnimation () {
1081    if (AnimationSpeed <= 0) return;
1082    if (! AnimationActive) return;
1083    AnimationActive = False;
1084
1085    status = sys$cantim(TIMID, PSL$C_USER);
1086    if (status != SS$_NORMAL) lib$signal(status);
1087}
1088
1089void SetAnimationSpeed (int speed)
1090{
1091    AnimationSpeed = speed;
1092    if (AnimationSpeed > MAXANIMATIONSPEED) AnimationSpeed = MAXANIMATIONSPEED;
1093}
1094
1095void ModifyAnimationSpeed (int incr)
1096{
1097    if ((AnimationSpeed + incr) < 0) return;
1098    if ((AnimationSpeed + incr) == 0) {
1099	if (AnimationActive) StopAnimation ();
1100	AnimationSpeed = 0;
1101	return;
1102    }
1103    AnimationSpeed += incr;
1104
1105    status = sys$cantim(TIMID, PSL$C_USER);
1106    if (status != SS$_NORMAL) lib$signal(status);
1107
1108    tv[1] = 0xFFFFFFFF;
1109    tv[0] = -(10000000 / AnimationSpeed);
1110
1111    sys$clref(timefe);
1112    status = sys$setimr (timefi, &tv, AnimateHandler, TIMID);
1113    if (status != SS$_NORMAL) lib$signal(status);
1114
1115    AnimationActive = True;
1116}
1117
1118void AnimateHandler (void) {
1119    AnimationPending = True;
1120
1121    sys$setef(timefe);
1122    status = sys$setimr (timefi, &tv, AnimateHandler, TIMID);
1123    if (status != SS$_NORMAL) lib$signal(status);
1124}
1125#else /* VMS */
1126
1127#ifdef USE_SIGNALS
1128SIGNAL_T AnimateHandler ();
1129#endif
1130
1131#ifndef USE_SIGNALS
1132void TryToAnimate (void)
1133{
1134    struct timeval  tp;
1135    struct timezone tzp;
1136    static unsigned long lastsec;
1137    static long lastusec;
1138    unsigned long gap;
1139
1140    gettimeofday (&tp, &tzp);
1141    gap = ((tp.tv_sec - lastsec) * 1000000) + (tp.tv_usec - lastusec);
1142    if (tracefile) {
1143	fprintf (tracefile, "Time = %lu, %ld, %ld, %ld, %lu\n", lastsec,
1144		lastusec, (long)tp.tv_sec, (long)tp.tv_usec, gap);
1145	fflush (tracefile);
1146    }
1147    gap *= AnimationSpeed;
1148    if (gap < 1000000) return;
1149    if (tracefile) {
1150	fprintf (tracefile, "Animate\n");
1151	fflush (tracefile);
1152    }
1153    Animate ();
1154    lastsec  = tp.tv_sec;
1155    lastusec = tp.tv_usec;
1156}
1157#endif /* USE_SIGNALS */
1158
1159void StartAnimation (void)
1160{
1161#ifdef USE_SIGNALS
1162    struct itimerval tv;
1163#endif
1164
1165    if (AnimationSpeed > MAXANIMATIONSPEED) AnimationSpeed = MAXANIMATIONSPEED;
1166    if (AnimationSpeed <= 0) AnimationSpeed = 0;
1167    if (AnimationActive) return;
1168#ifdef USE_SIGNALS
1169    if (AnimationSpeed == 0) return;
1170    signal (SIGALRM, AnimateHandler);
1171    if (AnimationSpeed == 1) {
1172	tv.it_interval.tv_sec  = 1;
1173	tv.it_interval.tv_usec = 0;
1174	tv.it_value.tv_sec     = 1;
1175	tv.it_value.tv_usec    = 0;
1176    }
1177    else {
1178	tv.it_interval.tv_sec  = 0;
1179	tv.it_interval.tv_usec = 1000000 / AnimationSpeed;
1180	tv.it_value.tv_sec     = 0;
1181	tv.it_value.tv_usec    = 1000000 / AnimationSpeed;
1182    }
1183    setitimer (ITIMER_REAL, &tv, (struct itimerval*) NULL);
1184#else /* USE_SIGNALS */
1185    switch (AnimationSpeed) {
1186	case 0 :
1187	    return;
1188	case 1 :
1189	    AnimateTimeout.tv_sec  = 1;
1190	    AnimateTimeout.tv_usec = 0;
1191	    break;
1192	default :
1193	    AnimateTimeout.tv_sec  = 0;
1194	    AnimateTimeout.tv_usec = 1000000 / AnimationSpeed;
1195    }
1196#endif /* USE_SIGNALS */
1197    AnimationActive = True;
1198}
1199
1200void StopAnimation (void)
1201{
1202#ifdef USE_SIGNALS
1203    struct itimerval tv;
1204
1205    if (AnimationSpeed <= 0) return;
1206    if (! AnimationActive) return;
1207    signal (SIGALRM, SIG_IGN);
1208
1209    tv.it_value.tv_sec     = 0;
1210    tv.it_value.tv_usec    = 0;
1211    setitimer (ITIMER_REAL, &tv, (struct itimerval*) NULL);
1212#endif
1213    AnimationActive = False;
1214}
1215
1216void SetAnimationSpeed (int speed)
1217{
1218    AnimationSpeed = speed;
1219    if (AnimationSpeed > MAXANIMATIONSPEED) AnimationSpeed = MAXANIMATIONSPEED;
1220}
1221
1222void ModifyAnimationSpeed (int incr)
1223{
1224#ifdef USE_SIGNALS
1225    struct itimerval tv;
1226#endif
1227
1228    if ((AnimationSpeed + incr) < 0) return;
1229    if ((AnimationSpeed + incr) == 0) {
1230	if (AnimationActive) StopAnimation ();
1231	AnimationSpeed = 0;
1232	return;
1233    }
1234    AnimationSpeed += incr;
1235    if (AnimationSpeed > MAXANIMATIONSPEED) AnimationSpeed = MAXANIMATIONSPEED;
1236
1237#ifdef USE_SIGNALS
1238    signal (SIGALRM, AnimateHandler);
1239    if (AnimationSpeed == 1) {
1240	tv.it_interval.tv_sec  = 1;
1241	tv.it_interval.tv_usec = 0;
1242	tv.it_value.tv_sec     = 1;
1243	tv.it_value.tv_usec    = 0;
1244    }
1245    else {
1246	tv.it_interval.tv_sec  = 0;
1247	tv.it_interval.tv_usec = 1000000 / AnimationSpeed;
1248	tv.it_value.tv_sec     = 0;
1249	tv.it_value.tv_usec    = 1000000 / AnimationSpeed;
1250    }
1251    setitimer (ITIMER_REAL, &tv, (struct itimerval*) NULL);
1252#else /* USE_SIGNALS */
1253    if (AnimationSpeed == 1) {
1254	AnimateTimeout.tv_sec  = 1;
1255	AnimateTimeout.tv_usec = 0;
1256    }
1257    else {
1258	AnimateTimeout.tv_sec  = 0;
1259	AnimateTimeout.tv_usec = 1000000 / AnimationSpeed;
1260    }
1261#endif /* USE_SIGNALS */
1262    AnimationActive = True;
1263}
1264
1265#ifdef USE_SIGNALS
1266SIGNAL_T AnimateHandler (int dummy)
1267{
1268    signal (SIGALRM, AnimateHandler);
1269    AnimationPending = True;
1270}
1271#endif
1272#endif /* VMS */
1273
1274void Animate (void)
1275{
1276    TwmWindow	*t;
1277    int		scrnum;
1278    ScreenInfo	*scr;
1279    int		i;
1280    TBWindow	*tbw;
1281    int		nb;
1282
1283    if (AnimationSpeed == 0) return;
1284#ifdef USE_SIGNALS
1285    AnimationPending = False;
1286#endif
1287
1288    MaybeAnimate = False;
1289    for (scrnum = 0; scrnum < NumScreens; scrnum++) {
1290	if ((scr = ScreenList [scrnum]) == NULL) continue;
1291
1292	for (t = scr->FirstWindow; t != NULL; t = t->next) {
1293	    if (! visible (t)) continue;
1294	    if (t->icon_on && t->icon && t->icon->bm_w && t->icon->image &&
1295		t->icon->image->next) {
1296		AnimateIcons (scr, t->icon);
1297		MaybeAnimate = True;
1298	    }
1299	    else
1300	    if (t->mapped && t->titlebuttons) {
1301		nb = scr->TBInfo.nleft + scr->TBInfo.nright;
1302		for (i = 0, tbw = t->titlebuttons; i < nb; i++, tbw++) {
1303		    if (tbw->image && tbw->image->next) {
1304			AnimateButton (tbw);
1305			MaybeAnimate = True;
1306		    }
1307		}
1308	    }
1309	}
1310	if (scr->Focus) {
1311	    t = scr->Focus;
1312	    if (t->mapped && t->titlehighlight && t->title_height &&
1313		t->HiliteImage && t->HiliteImage->next) {
1314		AnimateHighlight (t);
1315		MaybeAnimate = True;
1316	    }
1317	}
1318    }
1319    MaybeAnimate |= AnimateRoot ();
1320    XFlush (dpy);
1321    return;
1322}
1323
1324void InsertRGBColormap (Atom a, XStandardColormap *maps, int nmaps,
1325			Bool replace)
1326{
1327    StdCmap *sc = NULL;
1328
1329    if (replace) {			/* locate existing entry */
1330	for (sc = Scr->StdCmapInfo.head; sc; sc = sc->next) {
1331	    if (sc->atom == a) break;
1332	}
1333    }
1334
1335    if (!sc) {				/* no existing, allocate new */
1336	sc = (StdCmap *) malloc (sizeof (StdCmap));
1337	if (!sc) {
1338	    fprintf (stderr, "%s:  unable to allocate %lu bytes for StdCmap\n",
1339		     ProgramName, (unsigned long) sizeof(StdCmap));
1340	    return;
1341	}
1342    }
1343
1344    if (replace) {			/* just update contents */
1345	if (sc->maps) XFree ((char *) maps);
1346	if (sc == Scr->StdCmapInfo.mru) Scr->StdCmapInfo.mru = NULL;
1347    } else {				/* else appending */
1348	sc->next = NULL;
1349	sc->atom = a;
1350	if (Scr->StdCmapInfo.tail) {
1351	    Scr->StdCmapInfo.tail->next = sc;
1352	} else {
1353	    Scr->StdCmapInfo.head = sc;
1354	}
1355	Scr->StdCmapInfo.tail = sc;
1356    }
1357    sc->nmaps = nmaps;
1358    sc->maps = maps;
1359
1360    return;
1361}
1362
1363void RemoveRGBColormap (Atom a)
1364{
1365    StdCmap *sc, *prev;
1366
1367    prev = NULL;
1368    for (sc = Scr->StdCmapInfo.head; sc; sc = sc->next) {
1369	if (sc->atom == a) break;
1370	prev = sc;
1371    }
1372    if (sc) {				/* found one */
1373	if (sc->maps) XFree ((char *) sc->maps);
1374	if (prev) prev->next = sc->next;
1375	if (Scr->StdCmapInfo.head == sc) Scr->StdCmapInfo.head = sc->next;
1376	if (Scr->StdCmapInfo.tail == sc) Scr->StdCmapInfo.tail = prev;
1377	if (Scr->StdCmapInfo.mru == sc) Scr->StdCmapInfo.mru = NULL;
1378    }
1379    return;
1380}
1381
1382void LocateStandardColormaps(void)
1383{
1384    Atom *atoms;
1385    int natoms;
1386    int i;
1387
1388    atoms = XListProperties (dpy, Scr->Root, &natoms);
1389    for (i = 0; i < natoms; i++) {
1390	XStandardColormap *maps = NULL;
1391	int nmaps;
1392
1393	if (XGetRGBColormaps (dpy, Scr->Root, &maps, &nmaps, atoms[i])) {
1394	    /* if got one, then append to current list */
1395	    InsertRGBColormap (atoms[i], maps, nmaps, False);
1396	}
1397    }
1398    if (atoms) XFree ((char *) atoms);
1399    return;
1400}
1401
1402void GetColor(int kind, Pixel *what, char *name)
1403{
1404    XColor color;
1405    Colormap cmap = Scr->RootColormaps.cwins[0]->colormap->c;
1406
1407#ifndef TOM
1408    if (!Scr->FirstTime)
1409	return;
1410#endif
1411
1412    if (Scr->Monochrome != kind)
1413	return;
1414
1415    if (! XParseColor (dpy, cmap, name, &color)) {
1416	fprintf (stderr, "%s:  invalid color name \"%s\"\n", ProgramName, name);
1417	return;
1418    }
1419    if (! XAllocColor (dpy, cmap, &color))
1420    {
1421	/* if we could not allocate the color, let's see if this is a
1422	 * standard colormap
1423	 */
1424	XStandardColormap *stdcmap = NULL;
1425
1426	if (! XParseColor (dpy, cmap, name, &color)) {
1427	    fprintf (stderr, "%s:  invalid color name \"%s\"\n", ProgramName, name);
1428	    return;
1429	}
1430
1431	/*
1432	 * look through the list of standard colormaps (check cache first)
1433	 */
1434	if (Scr->StdCmapInfo.mru && Scr->StdCmapInfo.mru->maps &&
1435	    (Scr->StdCmapInfo.mru->maps[Scr->StdCmapInfo.mruindex].colormap ==
1436	     cmap)) {
1437	    stdcmap = &(Scr->StdCmapInfo.mru->maps[Scr->StdCmapInfo.mruindex]);
1438	} else {
1439	    StdCmap *sc;
1440
1441	    for (sc = Scr->StdCmapInfo.head; sc; sc = sc->next) {
1442		int i;
1443
1444		for (i = 0; i < sc->nmaps; i++) {
1445		    if (sc->maps[i].colormap == cmap) {
1446			Scr->StdCmapInfo.mru = sc;
1447			Scr->StdCmapInfo.mruindex = i;
1448			stdcmap = &(sc->maps[i]);
1449			goto gotit;
1450		    }
1451		}
1452	    }
1453	}
1454
1455      gotit:
1456	if (stdcmap) {
1457            color.pixel = (stdcmap->base_pixel +
1458			   ((Pixel)(((float)color.red / 65535.0) *
1459				    stdcmap->red_max + 0.5) *
1460			    stdcmap->red_mult) +
1461			   ((Pixel)(((float)color.green /65535.0) *
1462				    stdcmap->green_max + 0.5) *
1463			    stdcmap->green_mult) +
1464			   ((Pixel)(((float)color.blue  / 65535.0) *
1465				    stdcmap->blue_max + 0.5) *
1466			    stdcmap->blue_mult));
1467        } else {
1468	    fprintf (stderr, "%s:  unable to allocate color \"%s\"\n",
1469		     ProgramName, name);
1470	    return;
1471	}
1472    }
1473
1474    *what = color.pixel;
1475    return;
1476}
1477
1478void GetShadeColors (ColorPair *cp)
1479{
1480    XColor	xcol;
1481    Colormap	cmap = Scr->RootColormaps.cwins[0]->colormap->c;
1482    int		save;
1483    float	clearfactor;
1484    float	darkfactor;
1485    char	clearcol [32], darkcol [32];
1486
1487    clearfactor = (float) Scr->ClearShadowContrast / 100.0;
1488    darkfactor  = (100.0 - (float) Scr->DarkShadowContrast)  / 100.0;
1489    xcol.pixel = cp->back;
1490    XQueryColor (dpy, cmap, &xcol);
1491
1492    sprintf (clearcol, "#%04x%04x%04x",
1493		xcol.red   + (unsigned short) ((65535 -   xcol.red) * clearfactor),
1494		xcol.green + (unsigned short) ((65535 - xcol.green) * clearfactor),
1495		xcol.blue  + (unsigned short) ((65535 -  xcol.blue) * clearfactor));
1496    sprintf (darkcol,  "#%04x%04x%04x",
1497		(unsigned short) (xcol.red   * darkfactor),
1498		(unsigned short) (xcol.green * darkfactor),
1499		(unsigned short) (xcol.blue  * darkfactor));
1500
1501    save = Scr->FirstTime;
1502    Scr->FirstTime = True;
1503    GetColor (Scr->Monochrome, &cp->shadc, clearcol);
1504    GetColor (Scr->Monochrome, &cp->shadd,  darkcol);
1505    Scr->FirstTime = save;
1506}
1507
1508void GetFont(MyFont *font)
1509{
1510    char *deffontname = "fixed,*";
1511    char **missing_charset_list_return;
1512    int missing_charset_count_return;
1513    char *def_string_return;
1514    XFontSetExtents *font_extents;
1515    XFontStruct **xfonts;
1516    char **font_names;
1517    register int i;
1518    int ascent;
1519    int descent;
1520    int fnum;
1521    char *basename2;
1522
1523    if (font->font_set != NULL){
1524	XFreeFontSet(dpy, font->font_set);
1525    }
1526
1527    basename2 = (char *)malloc(strlen(font->basename) + 3);
1528    if (basename2) sprintf(basename2, "%s,*", font->basename);
1529    else basename2 = font->basename;
1530    if( (font->font_set = XCreateFontSet(dpy, basename2,
1531				    &missing_charset_list_return,
1532				    &missing_charset_count_return,
1533				    &def_string_return)) == NULL) {
1534	if (Scr->DefaultFont.basename) {
1535	    deffontname = Scr->DefaultFont.basename;
1536	}
1537	if ((font->font_set = XCreateFontSet(dpy, deffontname,
1538					     &missing_charset_list_return,
1539					     &missing_charset_count_return,
1540					     &def_string_return)) == NULL)
1541	{
1542	    fprintf (stderr, "%s:  unable to open fonts \"%s\" or \"%s\"\n",
1543		     ProgramName, font->basename, deffontname);
1544	    exit(1);
1545	}
1546    }
1547    if (basename2 != font->basename) free(basename2);
1548    font_extents = XExtentsOfFontSet(font->font_set);
1549
1550    fnum = XFontsOfFontSet(font->font_set, &xfonts, &font_names);
1551    for( i = 0, ascent = 0, descent = 0; i<fnum; i++){
1552	ascent = MaxSize(ascent, (*xfonts)->ascent);
1553	descent = MaxSize(descent, (*xfonts)->descent);
1554	xfonts++;
1555    }
1556
1557    font->height = font_extents->max_logical_extent.height;
1558    font->y = ascent;
1559    font->ascent = ascent;
1560    font->descent = descent;
1561}
1562
1563
1564void SetFocusVisualAttributes (TwmWindow *tmp_win, Bool focus)
1565{
1566    if (! tmp_win) return;
1567
1568    if (focus == tmp_win->hasfocusvisible) return;
1569    if (tmp_win->highlight) {
1570	if (Scr->use3Dborders) {
1571	    PaintBorders (tmp_win, focus);
1572	}
1573	else {
1574	    if (focus) {
1575		XSetWindowBorder (dpy, tmp_win->frame, tmp_win->borderC.back);
1576		if (tmp_win->title_w)
1577		    XSetWindowBorder (dpy, tmp_win->title_w, tmp_win->borderC.back);
1578	    } else {
1579		XSetWindowBorderPixmap (dpy, tmp_win->frame, tmp_win->gray);
1580		if (tmp_win->title_w)
1581		    XSetWindowBorderPixmap (dpy, tmp_win->title_w, tmp_win->gray);
1582	    }
1583	}
1584    }
1585
1586    if (focus) {
1587	Bool hil = False;
1588
1589	if (tmp_win->lolite_wl) XUnmapWindow (dpy, tmp_win->lolite_wl);
1590	if (tmp_win->lolite_wr) XUnmapWindow (dpy, tmp_win->lolite_wr);
1591	if (tmp_win->hilite_wl) {
1592	    XMapWindow (dpy, tmp_win->hilite_wl);
1593	    hil = True;
1594	}
1595	if (tmp_win->hilite_wr) {
1596	    XMapWindow (dpy, tmp_win->hilite_wr);
1597	    hil = True;
1598	}
1599	if (hil && tmp_win->HiliteImage && tmp_win->HiliteImage->next) {
1600	    MaybeAnimate = True;
1601	}
1602	if (tmp_win->iconmanagerlist)
1603	    ActiveIconManager (tmp_win->iconmanagerlist);
1604    }
1605    else {
1606	if (tmp_win->hilite_wl) XUnmapWindow (dpy, tmp_win->hilite_wl);
1607	if (tmp_win->hilite_wr) XUnmapWindow (dpy, tmp_win->hilite_wr);
1608	if (tmp_win->lolite_wl) XMapWindow (dpy, tmp_win->lolite_wl);
1609	if (tmp_win->lolite_wr) XMapWindow (dpy, tmp_win->lolite_wr);
1610	if (tmp_win->iconmanagerlist)
1611	    NotActiveIconManager (tmp_win->iconmanagerlist);
1612    }
1613    if (Scr->use3Dtitles && Scr->SunkFocusWindowTitle && tmp_win->title_height) {
1614	ButtonState bs;
1615
1616	bs = focus ? on : off;
1617	Draw3DBorder (tmp_win->title_w, Scr->TBInfo.titlex, 0,
1618			tmp_win->title_width - Scr->TBInfo.titlex -
1619			Scr->TBInfo.rightoff - Scr->TitlePadding,
1620			Scr->TitleHeight, Scr->TitleShadowDepth,
1621			tmp_win->title, bs, False, False);
1622    }
1623    tmp_win->hasfocusvisible = focus;
1624}
1625
1626static void move_to_head (TwmWindow *t)
1627{
1628    if (t == NULL) return;
1629    if (Scr->FirstWindow == t) return;
1630
1631    if (t->prev) t->prev->next = t->next;
1632    if (t->next) t->next->prev = t->prev;
1633
1634    t->next = Scr->FirstWindow;
1635    if (Scr->FirstWindow != NULL)
1636	Scr->FirstWindow->prev = t;
1637    t->prev = NULL;
1638    Scr->FirstWindow = t;
1639}
1640
1641/*
1642 * SetFocus - separate routine to set focus to make things more understandable
1643 * and easier to debug
1644 */
1645void SetFocus (TwmWindow *tmp_win, Time	tim)
1646{
1647    Window w = (tmp_win ? tmp_win->w : PointerRoot);
1648    int f_iconmgr = 0;
1649
1650    if (Scr->Focus && (Scr->Focus->iconmgr)) f_iconmgr = 1;
1651    if (Scr->SloppyFocus && (w == PointerRoot) && (!f_iconmgr)) return;
1652
1653    XSetInputFocus (dpy, w, RevertToPointerRoot, tim);
1654    if (Scr->Focus == tmp_win) return;
1655
1656    if (Scr->Focus) {
1657	if (Scr->Focus->AutoSqueeze && !Scr->Focus->squeezed) {
1658	    AutoSqueeze (Scr->Focus);
1659	}
1660	SetFocusVisualAttributes (Scr->Focus, False);
1661    }
1662    if (tmp_win)    {
1663	if (tmp_win->AutoSqueeze && tmp_win->squeezed) {
1664	    AutoSqueeze (tmp_win);
1665	}
1666	SetFocusVisualAttributes (tmp_win, True);
1667    }
1668    Scr->Focus = tmp_win;
1669    move_to_head (tmp_win);
1670}
1671
1672#
1673#ifdef NOPUTENV
1674/*
1675 * define our own putenv() if the system doesn't have one.
1676 * putenv(s): place s (a string of the form "NAME=value") in
1677 * the environment; replacing any existing NAME.  s is placed in
1678 * environment, so if you change s, the environment changes (like
1679 * putenv on a sun).  Binding removed if you putenv something else
1680 * called NAME.
1681 */
1682int
1683putenv(s)
1684    char *s;
1685{
1686    char *v;
1687    int varlen, idx;
1688    extern char **environ;
1689    char **newenv;
1690    static int virgin = 1; /* true while "environ" is a virgin */
1691
1692    v = strchr(s, '=');
1693    if(v == 0)
1694	return 0; /* punt if it's not of the right form */
1695    varlen = (v + 1) - s;
1696
1697    for (idx = 0; environ[idx] != 0; idx++) {
1698	if (strncmp(environ[idx], s, varlen) == 0) {
1699	    if(v[1] != 0) { /* true if there's a value */
1700		environ[idx] = s;
1701		return 0;
1702	    } else {
1703		do {
1704		    environ[idx] = environ[idx+1];
1705		} while(environ[++idx] != 0);
1706		return 0;
1707	    }
1708	}
1709    }
1710
1711    /* add to environment (unless no value; then just return) */
1712    if(v[1] == 0)
1713	return 0;
1714    if(virgin) {
1715	register i;
1716
1717	newenv = (char **) malloc((unsigned) ((idx + 2) * sizeof(char*)));
1718	if(newenv == 0)
1719	    return -1;
1720	for(i = idx-1; i >= 0; --i)
1721	    newenv[i] = environ[i];
1722	virgin = 0;     /* you're not a virgin anymore, sweety */
1723    } else {
1724	newenv = (char **) realloc((char *) environ,
1725				   (unsigned) ((idx + 2) * sizeof(char*)));
1726	if (newenv == 0)
1727	    return -1;
1728    }
1729
1730    environ = newenv;
1731    environ[idx] = s;
1732    environ[idx+1] = 0;
1733
1734    return 0;
1735}
1736#endif /* NOPUTENV */
1737
1738
1739static Pixmap CreateXLogoPixmap (unsigned int *widthp, unsigned int *heightp)
1740{
1741    int h = Scr->TBInfo.width - Scr->TBInfo.border * 2;
1742    if (h < 0) h = 0;
1743
1744    *widthp = *heightp = (unsigned int) h;
1745    if (Scr->tbpm.xlogo == None) {
1746	GC gc, gcBack;
1747
1748	Scr->tbpm.xlogo = XCreatePixmap (dpy, Scr->Root, h, h, 1);
1749	gc = XCreateGC (dpy, Scr->tbpm.xlogo, 0L, NULL);
1750	XSetForeground (dpy, gc, 0);
1751	XFillRectangle (dpy, Scr->tbpm.xlogo, gc, 0, 0, h, h);
1752	XSetForeground (dpy, gc, 1);
1753	gcBack = XCreateGC (dpy, Scr->tbpm.xlogo, 0L, NULL);
1754	XSetForeground (dpy, gcBack, 0);
1755
1756	/*
1757	 * draw the logo large so that it gets as dense as possible; then white
1758	 * out the edges so that they look crisp
1759	 */
1760	XmuDrawLogo (dpy, Scr->tbpm.xlogo, gc, gcBack, -1, -1, h + 2, h + 2);
1761	XDrawRectangle (dpy, Scr->tbpm.xlogo, gcBack, 0, 0, h - 1, h - 1);
1762
1763	/*
1764	 * done drawing
1765	 */
1766	XFreeGC (dpy, gc);
1767	XFreeGC (dpy, gcBack);
1768    }
1769    return Scr->tbpm.xlogo;
1770}
1771
1772
1773static Pixmap CreateResizePixmap (unsigned int *widthp, unsigned int *heightp)
1774{
1775    int h = Scr->TBInfo.width - Scr->TBInfo.border * 2;
1776    if (h < 1) h = 1;
1777
1778    *widthp = *heightp = (unsigned int) h;
1779    if (Scr->tbpm.resize == None) {
1780	XPoint	points[3];
1781	GC gc;
1782	int w;
1783	int lw;
1784
1785	/*
1786	 * create the pixmap
1787	 */
1788	Scr->tbpm.resize = XCreatePixmap (dpy, Scr->Root, h, h, 1);
1789	gc = XCreateGC (dpy, Scr->tbpm.resize, 0L, NULL);
1790	XSetForeground (dpy, gc, 0);
1791	XFillRectangle (dpy, Scr->tbpm.resize, gc, 0, 0, h, h);
1792	XSetForeground (dpy, gc, 1);
1793	lw = h / 16;
1794	if (lw == 1)
1795	    lw = 0;
1796	XSetLineAttributes (dpy, gc, lw, LineSolid, CapButt, JoinMiter);
1797
1798	/*
1799	 * draw the resize button,
1800	 */
1801	w = (h * 2) / 3;
1802	points[0].x = w;
1803	points[0].y = 0;
1804	points[1].x = w;
1805	points[1].y = w;
1806	points[2].x = 0;
1807	points[2].y = w;
1808	XDrawLines (dpy, Scr->tbpm.resize, gc, points, 3, CoordModeOrigin);
1809	w = w / 2;
1810	points[0].x = w;
1811	points[0].y = 0;
1812	points[1].x = w;
1813	points[1].y = w;
1814	points[2].x = 0;
1815	points[2].y = w;
1816	XDrawLines (dpy, Scr->tbpm.resize, gc, points, 3, CoordModeOrigin);
1817
1818	/*
1819	 * done drawing
1820	 */
1821	XFreeGC(dpy, gc);
1822    }
1823    return Scr->tbpm.resize;
1824}
1825
1826static Pixmap CreateDotPixmap (unsigned int *widthp, unsigned int *heightp)
1827{
1828    int h = Scr->TBInfo.width - Scr->TBInfo.border * 2;
1829
1830    h = h * 3 / 4;
1831    if (h < 1) h = 1;
1832    if (!(h & 1))
1833	h--;
1834    *widthp = *heightp = (unsigned int) h;
1835    if (Scr->tbpm.delete == None) {
1836	GC  gc;
1837	Pixmap pix;
1838
1839	pix = Scr->tbpm.delete = XCreatePixmap (dpy, Scr->Root, h, h, 1);
1840	gc = XCreateGC (dpy, pix, 0L, NULL);
1841	XSetLineAttributes (dpy, gc, h, LineSolid, CapRound, JoinRound);
1842	XSetForeground (dpy, gc, 0L);
1843	XFillRectangle (dpy, pix, gc, 0, 0, h, h);
1844	XSetForeground (dpy, gc, 1L);
1845	XDrawLine (dpy, pix, gc, h/2, h/2, h/2, h/2);
1846	XFreeGC (dpy, gc);
1847    }
1848    return Scr->tbpm.delete;
1849}
1850
1851static Image *Create3DCrossImage (ColorPair cp)
1852{
1853    Image *image;
1854    int        h;
1855    int    point;
1856    int midpoint;
1857
1858    h = Scr->TBInfo.width - Scr->TBInfo.border * 2;
1859    if (!(h & 1)) h--;
1860    point = 4;
1861    midpoint = h/2;
1862
1863    image = (Image*) malloc (sizeof (struct _Image));
1864    if (! image) return (None);
1865    image->pixmap = XCreatePixmap (dpy, Scr->Root, h, h, Scr->d_depth);
1866    if (image->pixmap == None) return (None);
1867
1868    Draw3DBorder (image->pixmap, 0, 0, h, h, Scr->TitleButtonShadowDepth, cp, off, True, False);
1869
1870#ifdef LEVITTE_TEST
1871    FB (cp.shadc, cp.shadd);
1872    XDrawLine (dpy, image->pixmap, Scr->NormalGC, point+1, point-1, point-1, point+1);
1873    XDrawLine (dpy, image->pixmap, Scr->NormalGC, point+1, point, point, point+1);
1874    XDrawLine (dpy, image->pixmap, Scr->NormalGC, point-1, point+1, midpoint-2, midpoint);
1875    XDrawLine (dpy, image->pixmap, Scr->NormalGC, midpoint, midpoint+2, h-point-3, h-point-1);
1876    XDrawLine (dpy, image->pixmap, Scr->NormalGC, point, point+1, h-point-3, h-point-2);
1877    XDrawLine (dpy, image->pixmap, Scr->NormalGC, point-1, h-point-2, midpoint-2, midpoint);
1878    XDrawLine (dpy, image->pixmap, Scr->NormalGC, midpoint, midpoint-2, h-point-2, point-1);
1879    XDrawLine (dpy, image->pixmap, Scr->NormalGC, point, h-point-2, h-point-2, point);
1880#endif
1881
1882    FB (cp.shadd, cp.shadc);
1883#ifdef LEVITTE_TEST
1884    XDrawLine (dpy, image->pixmap, Scr->NormalGC, point+2, point+1, h-point-1, h-point-2);
1885    XDrawLine (dpy, image->pixmap, Scr->NormalGC, point+2, point, midpoint, midpoint-2);
1886    XDrawLine (dpy, image->pixmap, Scr->NormalGC, midpoint+2, midpoint, h-point, h-point-2);
1887    XDrawLine (dpy, image->pixmap, Scr->NormalGC, h-point, h-point-2, h-point-2, h-point);
1888    XDrawLine (dpy, image->pixmap, Scr->NormalGC, h-point-1, h-point-2, h-point-2, h-point-1);
1889#else
1890    XDrawLine (dpy, image->pixmap, Scr->NormalGC, point, point, h-point-1, h-point-1);
1891    XDrawLine (dpy, image->pixmap, Scr->NormalGC, point-1, point, h-point-1, h-point);
1892    XDrawLine (dpy, image->pixmap, Scr->NormalGC, point, point-1, h-point, h-point-1);
1893#endif
1894
1895#ifdef LEVITTE_TEST
1896    XDrawLine (dpy, image->pixmap, Scr->NormalGC, point, h-point-1, point, h-point-1);
1897    XDrawLine (dpy, image->pixmap, Scr->NormalGC, h-point-1, point, h-point-1, point);
1898#else
1899    XDrawLine (dpy, image->pixmap, Scr->NormalGC, point, h-point-1, h-point-1, point);
1900#endif
1901#ifdef LEVITTE_TEST
1902    XDrawLine (dpy, image->pixmap, Scr->NormalGC, point+1, h-point-1, h-point-1, point+1);
1903    XDrawLine (dpy, image->pixmap, Scr->NormalGC, point+1, h-point, midpoint, midpoint+2);
1904    XDrawLine (dpy, image->pixmap, Scr->NormalGC, midpoint+2, midpoint, h-point, point+1);
1905#else
1906    XDrawLine (dpy, image->pixmap, Scr->NormalGC, point-1, h-point-1, h-point-1, point-1);
1907    XDrawLine (dpy, image->pixmap, Scr->NormalGC, point, h-point, h-point, point);
1908#endif
1909
1910    image->mask   = None;
1911    image->width  = h;
1912    image->height = h;
1913    image->next   = None;
1914
1915    return (image);
1916}
1917
1918static Image *Create3DIconifyImage (ColorPair cp)
1919{
1920    Image *image;
1921    int     h;
1922    int point;
1923
1924    h = Scr->TBInfo.width - Scr->TBInfo.border * 2;
1925    if (!(h & 1)) h--;
1926    point = ((h/2-2) * 2+1) / 3;
1927
1928    image = (Image*) malloc (sizeof (struct _Image));
1929    if (! image) return (None);
1930    image->pixmap = XCreatePixmap (dpy, Scr->Root, h, h, Scr->d_depth);
1931    if (image->pixmap == None) return (None);
1932
1933    Draw3DBorder (image->pixmap, 0, 0, h, h, Scr->TitleButtonShadowDepth, cp, off, True, False);
1934    FB (cp.shadd, cp.shadc);
1935    XDrawLine (dpy, image->pixmap, Scr->NormalGC, point, point, h/2, h-point);
1936    XDrawLine (dpy, image->pixmap, Scr->NormalGC, point, point, h-point, point);
1937
1938    FB (cp.shadc, cp.shadd);
1939    XDrawLine (dpy, image->pixmap, Scr->NormalGC, h-point, point, h/2+1, h-point);
1940    XDrawLine (dpy, image->pixmap, Scr->NormalGC, h-point-1, point+1, h/2+1, h-point-1);
1941
1942    image->mask   = None;
1943    image->width  = h;
1944    image->height = h;
1945    image->next   = None;
1946
1947    return (image);
1948}
1949
1950static Image *Create3DSunkenResizeImage (ColorPair cp)
1951{
1952    int     h;
1953    Image *image;
1954
1955    h = Scr->TBInfo.width - Scr->TBInfo.border * 2;
1956    if (!(h & 1)) h--;
1957
1958    image = (Image*) malloc (sizeof (struct _Image));
1959    if (! image) return (None);
1960    image->pixmap = XCreatePixmap (dpy, Scr->Root, h, h, Scr->d_depth);
1961    if (image->pixmap == None) return (None);
1962
1963    Draw3DBorder (image->pixmap, 0, 0, h, h, Scr->TitleButtonShadowDepth, cp, off, True, False);
1964    Draw3DBorder (image->pixmap, 3, 3, h-6, h-6, 1, cp, on, True, False);
1965    Draw3DBorder (image->pixmap, 3, ((h-6)/3)+3, ((h-6)*2/3)+1,
1966     ((h-6)*2/3)+1, 1, cp, on, True, False);
1967    Draw3DBorder (image->pixmap, 3, ((h-6)*2/3)+3, ((h-6)/3)+1,
1968     ((h-6)/3)+1, 1, cp, on, True, False);
1969
1970    image->mask   = None;
1971    image->width  = h;
1972    image->height = h;
1973    image->next   = None;
1974
1975    return (image);
1976}
1977
1978static Image *Create3DBoxImage (ColorPair cp)
1979{
1980    int     h;
1981    Image   *image;
1982
1983    h = Scr->TBInfo.width - Scr->TBInfo.border * 2;
1984    if (! (h & 1)) h--;
1985
1986    image = (Image*) malloc (sizeof (struct _Image));
1987    if (! image) return (None);
1988    image->pixmap = XCreatePixmap (dpy, Scr->Root, h, h, Scr->d_depth);
1989    if (image->pixmap == None) return (None);
1990
1991    Draw3DBorder (image->pixmap, 0, 0, h, h, Scr->TitleButtonShadowDepth, cp, off, True, False);
1992    Draw3DBorder (image->pixmap, (h / 2) - 4, (h / 2) - 4, 9, 9, 1, cp,
1993     off, True, False);
1994
1995    image->mask   = None;
1996    image->width  = h;
1997    image->height = h;
1998    image->next   = None;
1999
2000    return (image);
2001}
2002
2003static Image *Create3DDotImage (ColorPair cp)
2004{
2005    Image *image;
2006    int	  h;
2007    static int idepth = 2;
2008
2009    h = Scr->TBInfo.width - Scr->TBInfo.border * 2;
2010    if (!(h & 1)) h--;
2011
2012    image = (Image*) malloc (sizeof (struct _Image));
2013    if (! image) return (None);
2014    image->pixmap = XCreatePixmap (dpy, Scr->Root, h, h, Scr->d_depth);
2015    if (image->pixmap == None) return (None);
2016
2017    Draw3DBorder (image->pixmap, 0, 0, h, h, Scr->TitleButtonShadowDepth, cp, off, True, False);
2018    Draw3DBorder (image->pixmap, (h / 2) - idepth,
2019				 (h / 2) - idepth,
2020				 2 * idepth + 1,
2021				 2 * idepth + 1,
2022				 idepth, cp, off, True, False);
2023    image->mask   = None;
2024    image->width  = h;
2025    image->height = h;
2026    image->next   = None;
2027    return (image);
2028}
2029
2030static Image *Create3DBarImage (ColorPair cp)
2031{
2032    Image *image;
2033    int	  h;
2034    static int idepth = 2;
2035
2036    h = Scr->TBInfo.width - Scr->TBInfo.border * 2;
2037    if (!(h & 1)) h--;
2038
2039    image = (Image*) malloc (sizeof (struct _Image));
2040    if (! image) return (None);
2041    image->pixmap = XCreatePixmap (dpy, Scr->Root, h, h, Scr->d_depth);
2042    if (image->pixmap == None) return (None);
2043
2044    Draw3DBorder (image->pixmap, 0, 0, h, h, Scr->TitleButtonShadowDepth, cp, off, True, False);
2045    Draw3DBorder (image->pixmap,
2046			Scr->TitleButtonShadowDepth + 2,
2047			(h / 2) - idepth,
2048			h - 2 * (Scr->TitleButtonShadowDepth + 2),
2049			2 * idepth + 1,
2050			idepth, cp, off, True, False);
2051    image->mask   = None;
2052    image->width  = h;
2053    image->height = h;
2054    image->next   = None;
2055    return (image);
2056}
2057
2058static Image *Create3DVertBarImage (ColorPair cp)
2059{
2060    Image *image;
2061    int	  h;
2062    static int idepth = 2;
2063
2064    h = Scr->TBInfo.width - Scr->TBInfo.border * 2;
2065    if (!(h & 1)) h--;
2066
2067    image = (Image*) malloc (sizeof (struct _Image));
2068    if (! image) return (None);
2069    image->pixmap = XCreatePixmap (dpy, Scr->Root, h, h, Scr->d_depth);
2070    if (image->pixmap == None) return (None);
2071
2072    Draw3DBorder (image->pixmap, 0, 0, h, h, Scr->TitleButtonShadowDepth, cp, off, True, False);
2073    Draw3DBorder (image->pixmap,
2074			(h / 2) - idepth,
2075			Scr->TitleButtonShadowDepth + 2,
2076			2 * idepth + 1,
2077			h - 2 * (Scr->TitleButtonShadowDepth + 2),
2078			idepth, cp, off, True, False);
2079    image->mask   = None;
2080    image->width  = h;
2081    image->height = h;
2082    image->next   = None;
2083    return (image);
2084}
2085
2086static Image *Create3DMenuImage (ColorPair cp)
2087{
2088    Image *image;
2089    int	  h, i;
2090
2091    h = Scr->TBInfo.width - Scr->TBInfo.border * 2;
2092    if (!(h & 1)) h--;
2093
2094    image = (Image*) malloc (sizeof (struct _Image));
2095    if (! image) return (None);
2096    image->pixmap = XCreatePixmap (dpy, Scr->Root, h, h, Scr->d_depth);
2097    if (image->pixmap == None) return (None);
2098
2099    Draw3DBorder (image->pixmap, 0, 0, h, h, Scr->TitleButtonShadowDepth, cp, off, True, False);
2100    for (i = 4; i < h - 7; i += 5) {
2101	Draw3DBorder (image->pixmap, 4, i, h - 8, 4, 2, cp, off, True, False);
2102    }
2103    image->mask   = None;
2104    image->width  = h;
2105    image->height = h;
2106    image->next   = None;
2107    return (image);
2108}
2109
2110static Image *Create3DResizeImage (ColorPair cp)
2111{
2112    Image *image;
2113    int	  h;
2114
2115    h = Scr->TBInfo.width - Scr->TBInfo.border * 2;
2116    if (!(h & 1)) h--;
2117
2118    image = (Image*) malloc (sizeof (struct _Image));
2119    if (! image) return (None);
2120    image->pixmap = XCreatePixmap (dpy, Scr->Root, h, h, Scr->d_depth);
2121    if (image->pixmap == None) return (None);
2122
2123    Draw3DBorder (image->pixmap, 0, 0, h, h, Scr->TitleButtonShadowDepth, cp, off, True, False);
2124    Draw3DBorder (image->pixmap, 0, h / 4, ((3 * h) / 4) + 1, ((3 * h) / 4) + 1, 2,
2125		cp, off, True, False);
2126    Draw3DBorder (image->pixmap, 0, h / 2, (h / 2) + 1, (h / 2) + 1, 2, cp, off, True, False);
2127    image->mask   = None;
2128    image->width  = h;
2129    image->height = h;
2130    image->next   = None;
2131    return (image);
2132}
2133
2134static Image *Create3DZoomImage (ColorPair cp)
2135{
2136    Image *image;
2137    int		h;
2138    static int idepth = 2;
2139
2140    h = Scr->TBInfo.width - Scr->TBInfo.border * 2;
2141    if (!(h & 1)) h--;
2142
2143    image = (Image*) malloc (sizeof (struct _Image));
2144    if (! image) return (None);
2145    image->pixmap = XCreatePixmap (dpy, Scr->Root, h, h, Scr->d_depth);
2146    if (image->pixmap == None) return (None);
2147
2148    Draw3DBorder (image->pixmap, 0, 0, h, h, Scr->TitleButtonShadowDepth, cp, off, True, False);
2149    Draw3DBorder (image->pixmap, Scr->TitleButtonShadowDepth + 2,
2150				 Scr->TitleButtonShadowDepth + 2,
2151				 h - 2 * (Scr->TitleButtonShadowDepth + 2),
2152				 h - 2 * (Scr->TitleButtonShadowDepth + 2),
2153				 idepth, cp, off, True, False);
2154
2155    image->mask   = None;
2156    image->width  = h;
2157    image->height = h;
2158    image->next   = None;
2159    return (image);
2160}
2161
2162struct Colori {
2163    Pixel color;
2164    Pixmap pix;
2165    struct Colori *next;
2166};
2167
2168Pixmap Create3DMenuIcon (unsigned int height,
2169			 unsigned int *widthp, unsigned int *heightp,
2170			 ColorPair cp)
2171{
2172    unsigned int h, w;
2173    int		i;
2174    struct Colori *col;
2175    static struct Colori *colori = NULL;
2176
2177    h = height;
2178    w = h * 7 / 8;
2179    if (h < 1) h = 1;
2180    if (w < 1) w = 1;
2181    *widthp  = w;
2182    *heightp = h;
2183
2184    for (col = colori; col; col = col->next) {
2185	if (col->color == cp.back) break;
2186    }
2187    if (col != NULL) {
2188	return (col->pix);
2189    }
2190    col = (struct Colori*) malloc (sizeof (struct Colori));
2191    col->color = cp.back;
2192    col->pix   = XCreatePixmap (dpy, Scr->Root, h, h, Scr->d_depth);
2193    col->next = colori;
2194    colori = col;
2195
2196    Draw3DBorder (col->pix, 0, 0, w, h, 1, cp, off, True, False);
2197    for (i = 3; i + 5 < h; i += 5) {
2198	Draw3DBorder (col->pix, 4, i, w - 8, 3, 1, Scr->MenuC, off, True, False);
2199    }
2200    return (colori->pix);
2201}
2202
2203#include "siconify.bm"
2204
2205Pixmap Create3DIconManagerIcon (ColorPair cp)
2206{
2207    unsigned int w, h;
2208    struct Colori *col;
2209    static struct Colori *colori = NULL;
2210
2211    w = (unsigned int) siconify_width;
2212    h = (unsigned int) siconify_height;
2213
2214    for (col = colori; col; col = col->next) {
2215	if (col->color == cp.back) break;
2216    }
2217    if (col != NULL) {
2218	return (col->pix);
2219    }
2220    col = (struct Colori*) malloc (sizeof (struct Colori));
2221    col->color = cp.back;
2222    col->pix   = XCreatePixmap (dpy, Scr->Root, w, h, Scr->d_depth);
2223    Draw3DBorder (col->pix, 0, 0, w, h, 4, cp, off, True, False);
2224    col->next = colori;
2225    colori = col;
2226
2227    return (colori->pix);
2228}
2229
2230static Image *Create3DResizeAnimation (Bool in, Bool left, Bool top,
2231				       ColorPair cp)
2232{
2233    int		h, i, j;
2234    Image	*image, *im, *im1;
2235
2236    h = Scr->TBInfo.width - Scr->TBInfo.border * 2;
2237    if (!(h & 1)) h--;
2238
2239    image = im1 = None;
2240    for (i = (in ? 0 : (h/4)-1); (i < h/4) && (i >= 0); i += (in ? 1 : -1)) {
2241	im = (Image*) malloc (sizeof (struct _Image));
2242	if (! im) return (None);
2243	im->pixmap = XCreatePixmap (dpy, Scr->Root, h, h, Scr->d_depth);
2244	if (im->pixmap == None) {
2245	    free (im);
2246	    return (None);
2247	}
2248	Draw3DBorder (im->pixmap, 0, 0, h, h, Scr->TitleButtonShadowDepth, cp, off, True, False);
2249	for (j = i; j <= h; j += (h/4)){
2250	    Draw3DBorder (im->pixmap, (left ? 0 : j), (top ? 0 : j),
2251			  h - j, h - j, 2, cp, off, True, False);
2252	}
2253	im->mask   = None;
2254	im->width  = h;
2255	im->height = h;
2256	im->next   = None;
2257	if (image == None) {
2258	    image = im1 = im;
2259	}
2260	else {
2261	    im1->next = im;
2262	    im1 = im;
2263	}
2264    }
2265    if (im1 != None) im1->next = image;
2266    return (image);
2267}
2268
2269static Image *Create3DResizeInTopAnimation (ColorPair cp)
2270{
2271    return Create3DResizeAnimation (TRUE, FALSE, TRUE, cp);
2272}
2273
2274static Image *Create3DResizeOutTopAnimation (ColorPair cp)
2275{
2276    return Create3DResizeAnimation (False, FALSE, TRUE, cp);
2277}
2278
2279static Image *Create3DResizeInBotAnimation (ColorPair cp)
2280{
2281    return Create3DResizeAnimation (TRUE, TRUE, FALSE, cp);
2282}
2283
2284static Image *Create3DResizeOutBotAnimation (ColorPair cp)
2285{
2286    return Create3DResizeAnimation (False, TRUE, FALSE, cp);
2287}
2288
2289static Image *Create3DMenuAnimation (Bool up, ColorPair cp)
2290{
2291    int               h, i, j;
2292    Image     *image, *im, *im1;
2293
2294    h = Scr->TBInfo.width - Scr->TBInfo.border * 2;
2295    if (!(h & 1)) h--;
2296
2297    image = im1 = None;
2298    for (j = (up ? 4 : 0); j != (up ? -1 : 5); j+= (up ? -1 : 1)) {
2299	im = (Image*) malloc (sizeof (struct _Image));
2300	if (! im) return (None);
2301	im->pixmap = XCreatePixmap (dpy, Scr->Root, h, h, Scr->d_depth);
2302	if (im->pixmap == None) {
2303	    free (im);
2304	    return (None);
2305	}
2306	Draw3DBorder (im->pixmap, 0, 0, h, h, Scr->TitleButtonShadowDepth, cp, off, True, False);
2307	for (i = j; i < h - 3; i += 5) {
2308	    Draw3DBorder (im->pixmap, 4, i, h - 8, 4, 2, cp, off, True, False);
2309	}
2310	im->mask   = None;
2311	im->width  = h;
2312	im->height = h;
2313	im->next   = None;
2314	if (image == None) {
2315	    image = im1 = im;
2316	}
2317	else {
2318	    im1->next = im;
2319	    im1 = im;
2320	}
2321    }
2322    if (im1 != None) im1->next = image;
2323    return (image);
2324}
2325
2326static Image *Create3DMenuUpAnimation (ColorPair cp)
2327{
2328    return Create3DMenuAnimation (TRUE, cp);
2329}
2330
2331static Image *Create3DMenuDownAnimation (ColorPair cp)
2332{
2333    return Create3DMenuAnimation (False, cp);
2334}
2335
2336static Image *Create3DZoomAnimation (Bool in, Bool out, int n, ColorPair cp)
2337{
2338    int		h, i, j, k;
2339    Image	*image, *im, *im1;
2340
2341    h = Scr->TBInfo.width - Scr->TBInfo.border * 2;
2342    if (!(h & 1)) h--;
2343
2344    if (n == 0) n = (h/2) - 2;
2345
2346    image = im1 = None;
2347    for (j = (out ? -1 : 1) ; j < (in ? 2 : 0); j += 2){
2348	for(k = (j > 0 ? 0 : n-1) ; (k >= 0) && (k < n); k += j){
2349	    im = (Image*) malloc (sizeof (struct _Image));
2350	    im->pixmap = XCreatePixmap (dpy, Scr->Root, h, h, Scr->d_depth);
2351	    Draw3DBorder (im->pixmap, 0, 0, h, h, Scr->TitleButtonShadowDepth, cp, off, True, False);
2352	    for (i = 2 + k; i < (h / 2); i += n) {
2353		Draw3DBorder (im->pixmap, i, i, h - (2 * i), h - (2 * i), 2, cp, off, True, False);
2354	    }
2355	    im->mask   = None;
2356	    im->width  = h;
2357	    im->height = h;
2358	    im->next   = None;
2359	    if (image == None) {
2360		image = im1 = im;
2361	    }
2362	    else {
2363		im1->next = im;
2364		im1 = im;
2365	    }
2366	}
2367    }
2368    if (im1 != None) im1->next = image;
2369    return (image);
2370}
2371
2372static Image *Create3DMazeInAnimation (ColorPair cp)
2373{
2374    return Create3DZoomAnimation(TRUE, FALSE, 6, cp);
2375}
2376
2377static Image *Create3DMazeOutAnimation (ColorPair cp)
2378{
2379    return Create3DZoomAnimation(FALSE, TRUE, 6, cp);
2380}
2381
2382static Image *Create3DZoomInAnimation (ColorPair cp)
2383{
2384    return Create3DZoomAnimation(TRUE, FALSE, 0, cp);
2385}
2386
2387static Image *Create3DZoomOutAnimation (ColorPair cp)
2388{
2389    return Create3DZoomAnimation(FALSE, TRUE, 0, cp);
2390}
2391
2392static Image *Create3DZoomInOutAnimation (ColorPair cp)
2393{
2394    return Create3DZoomAnimation(TRUE, TRUE, 0, cp);
2395}
2396
2397#define questionmark_width 8
2398#define questionmark_height 8
2399static char questionmark_bits[] = {
2400   0x38, 0x7c, 0x64, 0x30, 0x18, 0x00, 0x18, 0x18};
2401
2402static Pixmap CreateQuestionPixmap (unsigned int *widthp,
2403				    unsigned int *heightp)
2404{
2405    *widthp = questionmark_width;
2406    *heightp = questionmark_height;
2407    if (Scr->tbpm.question == None) {
2408	Scr->tbpm.question = XCreateBitmapFromData (dpy, Scr->Root,
2409						    questionmark_bits,
2410						    questionmark_width,
2411						    questionmark_height);
2412    }
2413    /*
2414     * this must succeed or else we are in deep trouble elsewhere
2415     */
2416    return Scr->tbpm.question;
2417}
2418
2419
2420static Pixmap CreateMenuPixmap (unsigned int *widthp, unsigned int *heightp)
2421{
2422    return (CreateMenuIcon (Scr->TBInfo.width - Scr->TBInfo.border * 2,widthp,heightp));
2423}
2424
2425Pixmap CreateMenuIcon (int height, unsigned int *widthp, unsigned int *heightp)
2426{
2427    int h, w;
2428    int ih, iw;
2429    int	ix, iy;
2430    int	mh, mw;
2431    int	tw, th;
2432    int	lw, lh;
2433    int	lx, ly;
2434    int	lines, dly;
2435    int offset;
2436    int	bw;
2437
2438    h = height;
2439    w = h * 7 / 8;
2440    if (h < 1)
2441	h = 1;
2442    if (w < 1)
2443	w = 1;
2444    *widthp = w;
2445    *heightp = h;
2446    if (Scr->tbpm.menu == None) {
2447	Pixmap  pix;
2448	GC	gc;
2449
2450	pix = Scr->tbpm.menu = XCreatePixmap (dpy, Scr->Root, w, h, 1);
2451	gc = XCreateGC (dpy, pix, 0L, NULL);
2452	XSetForeground (dpy, gc, 0L);
2453	XFillRectangle (dpy, pix, gc, 0, 0, w, h);
2454	XSetForeground (dpy, gc, 1L);
2455	ix = 1;
2456	iy = 1;
2457	ih = h - iy * 2;
2458	iw = w - ix * 2;
2459	offset = ih / 8;
2460	mh = ih - offset;
2461	mw = iw - offset;
2462	bw = mh / 16;
2463	if (bw == 0 && mw > 2)
2464	    bw = 1;
2465	tw = mw - bw * 2;
2466	th = mh - bw * 2;
2467	XFillRectangle (dpy, pix, gc, ix, iy, mw, mh);
2468	XFillRectangle (dpy, pix, gc, ix + iw - mw, iy + ih - mh, mw, mh);
2469	XSetForeground (dpy, gc, 0L);
2470	XFillRectangle (dpy, pix, gc, ix+bw, iy+bw, tw, th);
2471	XSetForeground (dpy, gc, 1L);
2472	lw = tw / 2;
2473	if ((tw & 1) ^ (lw & 1))
2474	    lw++;
2475	lx = ix + bw + (tw - lw) / 2;
2476
2477	lh = th / 2 - bw;
2478	if ((lh & 1) ^ ((th - bw) & 1))
2479	    lh++;
2480	ly = iy + bw + (th - bw - lh) / 2;
2481
2482	lines = 3;
2483	if ((lh & 1) && lh < 6)
2484	{
2485	    lines--;
2486	}
2487	dly = lh / (lines - 1);
2488	while (lines--)
2489	{
2490	    XFillRectangle (dpy, pix, gc, lx, ly, lw, bw);
2491	    ly += dly;
2492	}
2493	XFreeGC (dpy, gc);
2494    }
2495    return Scr->tbpm.menu;
2496}
2497
2498#define FBGC(gc, fix_fore, fix_back)\
2499    Gcv.foreground = fix_fore;\
2500    Gcv.background = fix_back;\
2501    XChangeGC(dpy, gc, GCForeground|GCBackground,&Gcv)
2502
2503void Draw3DBorder (Window w, int x, int y, int width, int height, int bw,
2504		   ColorPair cp, int state, int fill, int forcebw)
2505{
2506    int		  i;
2507    XGCValues	  gcv;
2508    unsigned long gcm;
2509
2510    if ((width < 1) || (height < 1)) return;
2511    if (Scr->Monochrome != COLOR) {
2512	if (fill) {
2513	    gcm = GCFillStyle;
2514	    gcv.fill_style = FillOpaqueStippled;
2515	    XChangeGC (dpy, Scr->BorderGC, gcm, &gcv);
2516	    XFillRectangle (dpy, w, Scr->BorderGC, x, y, width, height);
2517	}
2518	gcm  = 0;
2519	gcm |= GCLineStyle;
2520	gcv.line_style = (state == on) ? LineSolid : LineDoubleDash;
2521	gcm |= GCFillStyle;
2522	gcv.fill_style = FillSolid;
2523	XChangeGC (dpy, Scr->BorderGC, gcm, &gcv);
2524	for (i = 0; i < bw; i++) {
2525	    XDrawLine (dpy, w, Scr->BorderGC, x,                 y + i,
2526					    x + width - i - 1, y + i);
2527	    XDrawLine (dpy, w, Scr->BorderGC, x + i,                  y,
2528					    x + i, y + height - i - 1);
2529	}
2530
2531	gcm  = 0;
2532	gcm |= GCLineStyle;
2533	gcv.line_style = (state == on) ? LineDoubleDash : LineSolid;
2534	gcm |= GCFillStyle;
2535	gcv.fill_style = FillSolid;
2536	XChangeGC (dpy, Scr->BorderGC, gcm, &gcv);
2537	for (i = 0; i < bw; i++) {
2538	    XDrawLine (dpy, w, Scr->BorderGC, x + width - i - 1,          y + i,
2539					    x + width - i - 1, y + height - 1);
2540	    XDrawLine (dpy, w, Scr->BorderGC, x + i,         y + height - i - 1,
2541					    x + width - 1, y + height - i - 1);
2542	}
2543	return;
2544    }
2545
2546    if (fill) {
2547	FBGC (Scr->BorderGC, cp.back, cp.fore);
2548	XFillRectangle (dpy, w, Scr->BorderGC, x, y, width, height);
2549    }
2550    if (Scr->BeNiceToColormap) {
2551	int dashoffset = 0;
2552
2553	gcm  = 0;
2554	gcm |= GCLineStyle;
2555	gcv.line_style = (forcebw) ? LineSolid : LineDoubleDash;
2556	gcm |= GCBackground;
2557	gcv.background = cp.back;
2558	XChangeGC (dpy, Scr->BorderGC, gcm, &gcv);
2559
2560	if (state == on)
2561	    XSetForeground (dpy, Scr->BorderGC, Scr->Black);
2562	else
2563	    XSetForeground (dpy, Scr->BorderGC, Scr->White);
2564	for (i = 0; i < bw; i++) {
2565	    XDrawLine (dpy, w, Scr->BorderGC, x + i,     y + dashoffset,
2566					    x + i, y + height - i - 1);
2567	    XDrawLine (dpy, w, Scr->BorderGC, x + dashoffset,    y + i,
2568					    x + width - i - 1, y + i);
2569	    dashoffset = 1 - dashoffset;
2570	}
2571	XSetForeground (dpy, Scr->BorderGC, ((state == on) ? Scr->White : Scr->Black));
2572	for (i = 0; i < bw; i++) {
2573	    XDrawLine (dpy, w, Scr->BorderGC, x + i,         y + height - i - 1,
2574					    x + width - 1, y + height - i - 1);
2575	    XDrawLine (dpy, w, Scr->BorderGC, x + width - i - 1,          y + i,
2576					    x + width - i - 1, y + height - 1);
2577	}
2578	return;
2579    }
2580    if (state == on) { FBGC (Scr->BorderGC, cp.shadd, cp.shadc); }
2581    else             { FBGC (Scr->BorderGC, cp.shadc, cp.shadd); }
2582    for (i = 0; i < bw; i++) {
2583	XDrawLine (dpy, w, Scr->BorderGC, x,                 y + i,
2584					  x + width - i - 1, y + i);
2585	XDrawLine (dpy, w, Scr->BorderGC, x + i,                  y,
2586					  x + i, y + height - i - 1);
2587    }
2588
2589    if (state == on) { FBGC (Scr->BorderGC, cp.shadc, cp.shadd); }
2590    else             { FBGC (Scr->BorderGC, cp.shadd, cp.shadc); }
2591    for (i = 0; i < bw; i++) {
2592	XDrawLine (dpy, w, Scr->BorderGC, x + width - i - 1,          y + i,
2593					  x + width - i - 1, y + height - 1);
2594	XDrawLine (dpy, w, Scr->BorderGC, x + i,         y + height - i - 1,
2595					  x + width - 1, y + height - i - 1);
2596    }
2597    return;
2598}
2599
2600void Draw3DCorner (Window w,
2601		   int x, int y, int width, int height, int thick, int bw,
2602		   ColorPair cp, int type)
2603{
2604    XRectangle rects [2];
2605
2606    switch (type) {
2607	case 0 :
2608	    Draw3DBorder (w, x, y, width, height, bw, cp, off, True, False);
2609	    Draw3DBorder (w, x + thick - bw, y + thick - bw,
2610			width - thick + 2 * bw, height - thick + 2 * bw,
2611			bw, cp, on, True, False);
2612	    break;
2613	case 1 :
2614	    Draw3DBorder (w, x, y, width, height, bw, cp, off, True, False);
2615	    Draw3DBorder (w, x, y + thick - bw,
2616			width - thick + bw, height - thick,
2617			bw, cp, on, True, False);
2618	    break;
2619	case 2 :
2620	    rects [0].x      = x + width - thick;
2621	    rects [0].y      = y;
2622	    rects [0].width  = thick;
2623	    rects [0].height = height;
2624	    rects [1].x      = x;
2625	    rects [1].y      = y + width - thick;
2626	    rects [1].width  = width - thick;
2627	    rects [1].height = thick;
2628	    XSetClipRectangles (dpy, Scr->BorderGC, 0, 0, rects, 2, Unsorted);
2629	    Draw3DBorder (w, x, y, width, height, bw, cp, off, True, False);
2630	    Draw3DBorder (w, x, y,
2631			width - thick + bw, height - thick + bw,
2632			bw, cp, on, True, False);
2633	    XSetClipMask (dpy, Scr->BorderGC, None);
2634	    break;
2635	case 3 :
2636	    rects [0].x      = x;
2637	    rects [0].y      = y;
2638	    rects [0].width  = thick;
2639	    rects [0].height = height;
2640	    rects [1].x      = x + thick;
2641	    rects [1].y      = y + height - thick;
2642	    rects [1].width  = width - thick;
2643	    rects [1].height = thick;
2644	    XSetClipRectangles (dpy, Scr->BorderGC, 0, 0, rects, 2, Unsorted);
2645	    Draw3DBorder (w, x, y, width, height, bw, cp, off, True, False);
2646	    Draw3DBorder (w, x + thick - bw, y,
2647			width - thick, height - thick + bw,
2648			bw, cp, on, True, False);
2649	    XSetClipMask (dpy, Scr->BorderGC, None);
2650	    break;
2651    }
2652    return;
2653}
2654
2655void PaintAllDecoration (void)
2656{
2657    TwmWindow *tmp_win;
2658    virtualScreen *vs;
2659
2660    for (tmp_win = Scr->FirstWindow; tmp_win != NULL; tmp_win = tmp_win->next) {
2661	if (! visible (tmp_win)) continue;
2662	if (tmp_win->mapped == TRUE) {
2663	    if (tmp_win->frame_bw3D) {
2664		if (tmp_win->highlight && tmp_win == Scr->Focus)
2665		    PaintBorders (tmp_win, True);
2666		else
2667		    PaintBorders (tmp_win, False);
2668	    }
2669	    if (tmp_win->title_w)      PaintTitle        (tmp_win);
2670	    if (tmp_win->titlebuttons) PaintTitleButtons (tmp_win);
2671	}
2672	else
2673	if ((tmp_win->icon_on == TRUE)  &&
2674		!tmp_win->icon_not_ours &&
2675		!Scr->NoIconTitlebar    &&
2676		tmp_win->icon           &&
2677		tmp_win->icon->w        &&
2678		! LookInList (Scr->NoIconTitle, tmp_win->full_name, &tmp_win->class)) {
2679	    PaintIcon (tmp_win);
2680	}
2681    }
2682    for (vs = Scr->vScreenList; vs != NULL; vs = vs->next) {
2683      PaintWorkSpaceManager (vs);
2684    }
2685}
2686
2687void PaintBorders (TwmWindow *tmp_win, Bool focus)
2688{
2689    ColorPair cp;
2690
2691    cp = (focus && tmp_win->highlight) ? tmp_win->borderC : tmp_win->border_tile;
2692    if (tmp_win->title_height == 0) {
2693	Draw3DBorder (tmp_win->frame,
2694	    0,
2695	    0,
2696	    tmp_win->frame_width,
2697	    tmp_win->frame_height,
2698	    Scr->BorderShadowDepth, cp, off, True, False);
2699	Draw3DBorder (tmp_win->frame,
2700	    tmp_win->frame_bw3D - Scr->BorderShadowDepth,
2701	    tmp_win->frame_bw3D - Scr->BorderShadowDepth,
2702	    tmp_win->frame_width  - 2 * tmp_win->frame_bw3D + 2 * Scr->BorderShadowDepth,
2703	    tmp_win->frame_height - 2 * tmp_win->frame_bw3D + 2 * Scr->BorderShadowDepth,
2704	    Scr->BorderShadowDepth, cp, on, True, False);
2705	return;
2706    }
2707    Draw3DCorner (tmp_win->frame,
2708		tmp_win->title_x - tmp_win->frame_bw3D,
2709		0,
2710		Scr->TitleHeight + tmp_win->frame_bw3D,
2711		Scr->TitleHeight + tmp_win->frame_bw3D,
2712		tmp_win->frame_bw3D, Scr->BorderShadowDepth, cp, 0);
2713    Draw3DCorner (tmp_win->frame,
2714		tmp_win->title_x + tmp_win->title_width - Scr->TitleHeight,
2715		0,
2716		Scr->TitleHeight + tmp_win->frame_bw3D,
2717		Scr->TitleHeight + tmp_win->frame_bw3D,
2718		tmp_win->frame_bw3D, Scr->BorderShadowDepth, cp, 1);
2719    Draw3DCorner (tmp_win->frame,
2720		tmp_win->frame_width  - (Scr->TitleHeight + tmp_win->frame_bw3D),
2721		tmp_win->frame_height - (Scr->TitleHeight + tmp_win->frame_bw3D),
2722		Scr->TitleHeight + tmp_win->frame_bw3D,
2723		Scr->TitleHeight + tmp_win->frame_bw3D,
2724		tmp_win->frame_bw3D, Scr->BorderShadowDepth, cp, 2);
2725    Draw3DCorner (tmp_win->frame,
2726		0,
2727		tmp_win->frame_height - (Scr->TitleHeight + tmp_win->frame_bw3D),
2728		Scr->TitleHeight + tmp_win->frame_bw3D,
2729		Scr->TitleHeight + tmp_win->frame_bw3D,
2730		tmp_win->frame_bw3D, Scr->BorderShadowDepth, cp, 3);
2731
2732    Draw3DBorder (tmp_win->frame,
2733		tmp_win->title_x + Scr->TitleHeight,
2734		0,
2735		tmp_win->title_width - 2 * Scr->TitleHeight,
2736		tmp_win->frame_bw3D,
2737		Scr->BorderShadowDepth, cp, off, True, False);
2738    Draw3DBorder (tmp_win->frame,
2739		tmp_win->frame_bw3D + Scr->TitleHeight,
2740		tmp_win->frame_height - tmp_win->frame_bw3D,
2741		tmp_win->frame_width - 2 * (Scr->TitleHeight + tmp_win->frame_bw3D),
2742		tmp_win->frame_bw3D,
2743		Scr->BorderShadowDepth, cp, off, True, False);
2744    Draw3DBorder (tmp_win->frame,
2745		0,
2746		Scr->TitleHeight + tmp_win->frame_bw3D,
2747		tmp_win->frame_bw3D,
2748		tmp_win->frame_height - 2 * (Scr->TitleHeight + tmp_win->frame_bw3D),
2749		Scr->BorderShadowDepth, cp, off, True, False);
2750    Draw3DBorder (tmp_win->frame,
2751		tmp_win->frame_width  - tmp_win->frame_bw3D,
2752		Scr->TitleHeight + tmp_win->frame_bw3D,
2753		tmp_win->frame_bw3D,
2754		tmp_win->frame_height - 2 * (Scr->TitleHeight + tmp_win->frame_bw3D),
2755		Scr->BorderShadowDepth, cp, off, True, False);
2756
2757    if (tmp_win->squeeze_info && !tmp_win->squeezed) {
2758	Draw3DBorder (tmp_win->frame,
2759		0,
2760		Scr->TitleHeight,
2761		tmp_win->title_x,
2762		tmp_win->frame_bw3D,
2763		Scr->BorderShadowDepth, cp, off, True, False);
2764	Draw3DBorder (tmp_win->frame,
2765		tmp_win->title_x + tmp_win->title_width,
2766		Scr->TitleHeight,
2767		tmp_win->frame_width - tmp_win->title_x - tmp_win->title_width,
2768		tmp_win->frame_bw3D,
2769		Scr->BorderShadowDepth, cp, off, True, False);
2770    }
2771}
2772
2773void PaintTitle (TwmWindow *tmp_win)
2774{
2775    int width, mwidth, len;
2776    XRectangle inc_rect;
2777    XRectangle logical_rect;
2778
2779    if (Scr->use3Dtitles) {
2780	if (Scr->SunkFocusWindowTitle && (Scr->Focus == tmp_win) &&
2781	    (tmp_win->title_height != 0))
2782	    Draw3DBorder (tmp_win->title_w, Scr->TBInfo.titlex, 0,
2783		tmp_win->title_width - Scr->TBInfo.titlex -
2784		Scr->TBInfo.rightoff - Scr->TitlePadding,
2785		Scr->TitleHeight, Scr->TitleShadowDepth,
2786		tmp_win->title, on, True, False);
2787	else
2788	    Draw3DBorder (tmp_win->title_w, Scr->TBInfo.titlex, 0,
2789		tmp_win->title_width - Scr->TBInfo.titlex -
2790		Scr->TBInfo.rightoff - Scr->TitlePadding,
2791		Scr->TitleHeight, Scr->TitleShadowDepth,
2792		tmp_win->title, off, True, False);
2793    }
2794    FB(tmp_win->title.fore, tmp_win->title.back);
2795    if (Scr->use3Dtitles) {
2796	len    = strlen(tmp_win->name);
2797	XmbTextExtents(Scr->TitleBarFont.font_set,
2798		       tmp_win->name, strlen (tmp_win->name),
2799		       &inc_rect, &logical_rect);
2800	width = logical_rect.width;
2801	mwidth = tmp_win->title_width  - Scr->TBInfo.titlex -
2802		 Scr->TBInfo.rightoff  - Scr->TitlePadding  -
2803		 Scr->TitleShadowDepth - 4;
2804	while ((len > 0) && (width > mwidth)) {
2805	    len--;
2806	    XmbTextExtents(Scr->TitleBarFont.font_set,
2807			   tmp_win->name, len,
2808			   &inc_rect, &logical_rect);
2809	    width = logical_rect.width;
2810	}
2811	if (Scr->Monochrome != COLOR) {
2812	    XmbDrawImageString(dpy, tmp_win->title_w, Scr->TitleBarFont.font_set,
2813			     Scr->NormalGC,
2814			     tmp_win->name_x,
2815			     Scr->TitleBarFont.y + Scr->TitleShadowDepth,
2816			     tmp_win->name, len);
2817	}
2818	else {
2819	    XmbDrawString (dpy, tmp_win->title_w, Scr->TitleBarFont.font_set,
2820			   Scr->NormalGC, tmp_win->name_x,
2821			   Scr->TitleBarFont.y + Scr->TitleShadowDepth,
2822			   tmp_win->name, len);
2823	}
2824    }
2825    else
2826        XmbDrawString (dpy, tmp_win->title_w, Scr->TitleBarFont.font_set,
2827		       Scr->NormalGC,
2828		       tmp_win->name_x, Scr->TitleBarFont.y,
2829		       tmp_win->name, strlen(tmp_win->name));
2830}
2831
2832void PaintIcon (TwmWindow *tmp_win)
2833{
2834    int		width, twidth, mwidth, len, x;
2835    Icon	*icon;
2836    XRectangle inc_rect;
2837    XRectangle logical_rect;
2838
2839    if (!tmp_win || !tmp_win->icon) return;
2840    icon = tmp_win->icon;
2841    if (!icon->has_title) return;
2842
2843    x     = 0;
2844    width = icon->w_width;
2845    if (Scr->ShrinkIconTitles && icon->title_shrunk) {
2846	x     = GetIconOffset (icon);
2847	width = icon->width;
2848    }
2849    len    = strlen (tmp_win->icon_name);
2850    XmbTextExtents(Scr->IconFont.font_set,
2851		   tmp_win->icon_name, len,
2852		   &inc_rect, &logical_rect);
2853    twidth = logical_rect.width;
2854    mwidth = width - 2 * Scr->IconManagerShadowDepth - 6;
2855    if (Scr->use3Diconmanagers) {
2856	Draw3DBorder (icon->w, x, icon->height, width,
2857		Scr->IconFont.height + 2 * Scr->IconManagerShadowDepth + 6,
2858		Scr->IconManagerShadowDepth, icon->iconc, off, False, False);
2859    }
2860    while ((len > 0) && (twidth > mwidth)) {
2861	len--;
2862	XmbTextExtents(Scr->IconFont.font_set,
2863		       tmp_win->icon_name, len,
2864		       &inc_rect, &logical_rect);
2865	twidth = logical_rect.width;
2866    }
2867    FB (icon->iconc.fore, icon->iconc.back);
2868    XmbDrawString(dpy, icon->w, Scr->IconFont.font_set, Scr->NormalGC,
2869		  x + ((mwidth - twidth)/2) + Scr->IconManagerShadowDepth + 3,
2870		  icon->y, tmp_win->icon_name, len);
2871}
2872
2873void PaintTitleButton (TwmWindow *tmp_win, TBWindow  *tbw)
2874{
2875    TitleButton *tb = tbw->info;
2876
2877    XCopyArea (dpy, tbw->image->pixmap, tbw->window, Scr->NormalGC,
2878		tb->srcx, tb->srcy, tb->width, tb->height,
2879		tb->dstx, tb->dsty);
2880    return;
2881}
2882
2883void PaintTitleButtons (TwmWindow *tmp_win)
2884{
2885    int i;
2886    TBWindow *tbw = tmp_win->titlebuttons;
2887    int nb = Scr->TBInfo.nleft + Scr->TBInfo.nright;
2888
2889    if (tbw == NULL)
2890	return;
2891
2892    for (i = 0; i < nb; i++, tbw++) {
2893	PaintTitleButton (tmp_win, tbw);
2894    }
2895}
2896
2897void adoptWindow (void)
2898{
2899    unsigned long	data [2];
2900    Window		localroot, w;
2901    unsigned char	*prop;
2902    unsigned long	bytesafter;
2903    unsigned long	len;
2904    Atom		actual_type;
2905    int			actual_format;
2906    XEvent		event;
2907    Window		root, parent, child, *children;
2908    unsigned int	nchildren, key_buttons;
2909    int			root_x, root_y, win_x, win_y;
2910    int			ret;
2911
2912    localroot = w = RootWindow (dpy, Scr->screen);
2913    XGrabPointer (dpy, localroot, False,
2914			ButtonPressMask | ButtonReleaseMask,
2915			GrabModeAsync, GrabModeAsync,
2916		        None, Scr->SelectCursor, CurrentTime);
2917
2918    XMaskEvent (dpy, ButtonPressMask | ButtonReleaseMask, &event);
2919    child = event.xbutton.subwindow;
2920    while (1) {
2921	if (child == (Window) 0) break;
2922
2923	w = XmuClientWindow (dpy, child);
2924	ret = XGetWindowProperty (dpy, w, _XA_WM_WORKSPACESLIST, 0L, 512,
2925			False, XA_STRING, &actual_type, &actual_format, &len,
2926			&bytesafter, &prop);
2927	XFree ((char *)prop); /* Don't ever do anything with it */
2928	if (ret != Success)
2929		break;
2930	if (len == 0) /* it is not a local root window */
2931		break; /* it is not a local root window */
2932	localroot = w;
2933	XQueryPointer (dpy, localroot, &root, &child, &root_x, &root_y,
2934					&win_x, &win_y, &key_buttons);
2935    }
2936    XMaskEvent (dpy, ButtonPressMask | ButtonReleaseMask, &event);
2937    XUngrabPointer (dpy, CurrentTime);
2938
2939    if (localroot == Scr->Root) return;
2940    if (w == localroot) {  /* try to not adopt an ancestor */
2941	XQueryTree (dpy, Scr->Root, &root, &parent, &children, &nchildren);
2942	while (parent != (Window) 0) {
2943	    XFree ((char *) children);
2944	    if (w == parent) return;
2945	    XQueryTree (dpy, parent, &root, &parent, &children, &nchildren);
2946	}
2947	XFree ((char *) children);
2948	if (w == root) return;
2949    }
2950    if (localroot == RootWindow (dpy, Scr->screen)) {
2951	XWithdrawWindow (dpy, w, Scr->screen);
2952    }
2953    else {
2954	XUnmapWindow (dpy, w);
2955    }
2956    XReparentWindow (dpy, w, Scr->Root, 0, 0);
2957
2958    data [0] = (unsigned long) NormalState;
2959    data [1] = (unsigned long) None;
2960
2961    XChangeProperty (dpy, w, _XA_WM_STATE, _XA_WM_STATE, 32,
2962			PropModeReplace, (unsigned char *) data, 2);
2963    XFlush (dpy);
2964    SimulateMapRequest (w);
2965    return;
2966}
2967
2968void DebugTrace (char *file)
2969{
2970    if (!file) return;
2971    if (tracefile) {
2972	fprintf (stderr, "stop logging events\n");
2973	if (tracefile != stderr) fclose (tracefile);
2974	tracefile = NULL;
2975    }
2976    else {
2977	if (strcmp (file, "stderr"))
2978	    tracefile = fopen (file, "w");
2979	else
2980	    tracefile = stderr;
2981	fprintf (stderr, "logging events to : %s\n", file);
2982    }
2983}
2984
2985extern Cursor	TopRightCursor, TopLeftCursor, BottomRightCursor, BottomLeftCursor,
2986		LeftCursor, RightCursor, TopCursor, BottomCursor;
2987
2988void SetBorderCursor (TwmWindow *tmp_win, int x, int y)
2989{
2990    Cursor cursor;
2991    XSetWindowAttributes attr;
2992    int h, fw, fh, wd;
2993
2994    if (!tmp_win)
2995	return;
2996
2997    /* Use the max of these, but since one is always 0 we can add them. */
2998    wd = tmp_win->frame_bw + tmp_win->frame_bw3D;
2999    h = Scr->TitleHeight + wd;
3000    fw = tmp_win->frame_width;
3001    fh = tmp_win->frame_height;
3002
3003#if defined DEBUG && DEBUG
3004    fprintf(stderr, "wd=%d h=%d, fw=%d fh=%d x=%d y=%d\n",
3005	    wd, h, fw, fh, x, y);
3006#endif
3007
3008    /*
3009     * If not using 3D borders:
3010     *
3011     * The left border has negative x coordinates,
3012     * The top border (above the title) has negative y coordinates.
3013     * The title is TitleHeight high, the next wd pixels are border.
3014     * The bottom border has coordinates >= the frame height.
3015     * The right border has coordinates >= the frame width.
3016     *
3017     * If using 3D borders: all coordinates are >= 0, and all coordinates
3018     * are higher by the border width.
3019     *
3020     * Since we only get events when we're actually in the border, we simply
3021     * allow for both cases at the same time.
3022     */
3023
3024    if ((x < -wd) || (y < -wd)) {
3025	cursor = Scr->FrameCursor;
3026    } else if (x < h) {
3027	if (y < h)
3028	    cursor = TopLeftCursor;
3029	else if (y >= fh - h)
3030	    cursor = BottomLeftCursor;
3031	else
3032	    cursor = LeftCursor;
3033    } else if (x >= fw - h) {
3034	if (y < h)
3035	    cursor = TopRightCursor;
3036	else if (y >= fh - h)
3037	    cursor = BottomRightCursor;
3038	else
3039	    cursor = RightCursor;
3040    } else if (y < h) {	/* also include title bar in top border area */
3041	cursor = TopCursor;
3042    } else if (y >= fh - h) {
3043	cursor = BottomCursor;
3044    } else {
3045	cursor = Scr->FrameCursor;
3046    }
3047    attr.cursor = cursor;
3048    XChangeWindowAttributes (dpy, tmp_win->frame, CWCursor, &attr);
3049    tmp_win->curcurs = cursor;
3050}
3051
3052Image *GetImage (char *name, ColorPair cp)
3053{
3054    name_list **list;
3055    char fullname [256];
3056    Image *image;
3057
3058    if (name == NULL) return (None);
3059    image = None;
3060
3061    list = &Scr->ImageCache;
3062#ifdef XPM
3063    if ((name [0] == '@') || (strncmp (name, "xpm:", 4) == 0)) {
3064	sprintf (fullname, "%s%dx%d", name, (int) cp.fore, (int) cp.back);
3065
3066	if ((image = (Image*) LookInNameList (*list, fullname)) == None) {
3067	    int startn = (name [0] == '@') ? 1 : 4;
3068	    if ((image = GetXpmImage (name + startn, cp)) != None) {
3069	        AddToList (list, fullname, (char*) image);
3070	    }
3071	}
3072    }
3073    else
3074#endif
3075#ifdef JPEG
3076    if (strncmp (name, "jpeg:", 5) == 0) {
3077	if ((image = (Image*) LookInNameList (*list, name)) == None) {
3078	    if ((image = GetJpegImage (&name [5])) != None) {
3079		AddToList (list, name, (char*) image);
3080	    }
3081	}
3082    }
3083    else
3084#endif
3085#ifdef IMCONV
3086    if (strncmp (name, "im:", 3) == 0) {
3087	if ((image = (Image*) LookInNameList (*list, name)) == None) {
3088	    if ((image = GetImconvImage (&name [3])) != None) {
3089		AddToList (list, name, (char*) image);
3090	    }
3091	}
3092    }
3093    else
3094#endif
3095#if !defined(VMS) || defined(HAVE_XWDFILE_H)
3096    if ((strncmp (name, "xwd:", 4) == 0) || (name [0] == '|')) {
3097	int startn = (name [0] == '|') ? 0 : 4;
3098	if ((image = (Image*) LookInNameList (*list, name)) == None) {
3099	    if ((image = GetXwdImage (&name [startn], cp)) != None) {
3100		AddToList (list, name, (char*) image);
3101	    }
3102	}
3103    }
3104    else
3105#endif
3106    if (strncmp (name, ":xpm:", 5) == 0) {
3107	int    i;
3108	static struct {
3109	    char *name;
3110	    Image* (*proc)(ColorPair colorpair);
3111	} pmtab[] = {
3112	    { TBPM_3DDOT,	Create3DDotImage },
3113	    { TBPM_3DRESIZE,	Create3DResizeImage },
3114	    { TBPM_3DMENU,	Create3DMenuImage },
3115	    { TBPM_3DZOOM,	Create3DZoomImage },
3116	    { TBPM_3DBAR,	Create3DBarImage },
3117	    { TBPM_3DVBAR,	Create3DVertBarImage },
3118	    { TBPM_3DCROSS,     Create3DCrossImage },
3119	    { TBPM_3DICONIFY,   Create3DIconifyImage },
3120	    { TBPM_3DSUNKEN_RESIZE,     Create3DSunkenResizeImage },
3121	    { TBPM_3DBOX,       Create3DBoxImage }
3122	};
3123
3124	sprintf (fullname, "%s%dx%d", name, (int) cp.fore, (int) cp.back);
3125	if ((image = (Image*) LookInNameList (*list, fullname)) == None) {
3126	    for (i = 0; i < (sizeof pmtab) / (sizeof pmtab[0]); i++) {
3127		if (XmuCompareISOLatin1 (pmtab[i].name, name) == 0) {
3128		    image = (*pmtab[i].proc) (cp);
3129		    if (image == None) {
3130			fprintf (stderr,
3131			    "%s:  unable to build pixmap \"%s\"\n", ProgramName, name);
3132			return (None);
3133		    }
3134		    break;
3135		}
3136	    }
3137	    if (image == None) {
3138		fprintf (stderr, "%s:  no such built-in pixmap \"%s\"\n", ProgramName, name);
3139		return (None);
3140	    }
3141	    AddToList (list, fullname, (char*) image);
3142	}
3143    }
3144    else
3145    if (strncmp (name, "%xpm:", 5) == 0) {
3146	int    i;
3147	static struct {
3148	    char *name;
3149	    Image* (*proc)(ColorPair colorpair);
3150	} pmtab[] = {
3151	    { "%xpm:menu-up", Create3DMenuUpAnimation },
3152	    { "%xpm:menu-down", Create3DMenuDownAnimation },
3153	    { "%xpm:resize", Create3DZoomOutAnimation }, /* compatibility */
3154	    { "%xpm:resize-out-top", Create3DResizeInTopAnimation },
3155	    { "%xpm:resize-in-top", Create3DResizeOutTopAnimation },
3156	    { "%xpm:resize-out-bot", Create3DResizeInBotAnimation },
3157	    { "%xpm:resize-in-bot", Create3DResizeOutBotAnimation },
3158	    { "%xpm:maze-out", Create3DMazeOutAnimation },
3159	    { "%xpm:maze-in", Create3DMazeInAnimation },
3160	    { "%xpm:zoom-out", Create3DZoomOutAnimation },
3161	    { "%xpm:zoom-in", Create3DZoomInAnimation },
3162	    { "%xpm:zoom-inout", Create3DZoomInOutAnimation }
3163	};
3164
3165	sprintf (fullname, "%s%dx%d", name, (int) cp.fore, (int) cp.back);
3166	if ((image = (Image*) LookInNameList (*list, fullname)) == None) {
3167	    for (i = 0; i < (sizeof pmtab) / (sizeof pmtab[0]); i++) {
3168		if (XmuCompareISOLatin1 (pmtab[i].name, name) == 0) {
3169		    image = (*pmtab[i].proc) (cp);
3170		    if (image == None) {
3171			fprintf (stderr,
3172			    "%s:  unable to build pixmap \"%s\"\n", ProgramName, name);
3173			return (None);
3174		    }
3175		    break;
3176		}
3177	    }
3178	    if (image == None) {
3179		fprintf (stderr, "%s:  no such built-in pixmap \"%s\"\n", ProgramName, name);
3180		return (None);
3181	    }
3182	    AddToList (list, fullname, (char*) image);
3183	}
3184    }
3185    else
3186    if (name [0] == ':') {
3187	int		i;
3188	unsigned int	width, height;
3189	Pixmap		pm = 0;
3190	XGCValues	gcvalues;
3191	static struct {
3192	    char *name;
3193	    Pixmap (*proc)(unsigned int *widthp, unsigned int *heightp);
3194	} pmtab[] = {
3195	    { TBPM_DOT,		CreateDotPixmap },
3196	    { TBPM_ICONIFY,	CreateDotPixmap },
3197	    { TBPM_RESIZE,	CreateResizePixmap },
3198	    { TBPM_XLOGO,	CreateXLogoPixmap },
3199	    { TBPM_DELETE,	CreateXLogoPixmap },
3200	    { TBPM_MENU,	CreateMenuPixmap },
3201	    { TBPM_QUESTION,	CreateQuestionPixmap },
3202	};
3203
3204	sprintf (fullname, "%s%dx%d", name, (int) cp.fore, (int) cp.back);
3205	if ((image = (Image*) LookInNameList (*list, fullname)) == None) {
3206	    for (i = 0; i < (sizeof pmtab) / (sizeof pmtab[0]); i++) {
3207		if (XmuCompareISOLatin1 (pmtab[i].name, name) == 0) {
3208		    pm = (*pmtab[i].proc) (&width, &height);
3209		    if (pm == None) {
3210			fprintf (stderr,
3211			    "%s:  unable to build pixmap \"%s\"\n", ProgramName, name);
3212			return (None);
3213		    }
3214		    break;
3215		}
3216	    }
3217	    if (pm == None) {
3218		fprintf (stderr, "%s:  no such built-in bitmap \"%s\"\n", ProgramName, name);
3219		return (None);
3220	    }
3221	    image = (Image*) malloc (sizeof (struct _Image));
3222	    image->pixmap = XCreatePixmap (dpy, Scr->Root, width, height, Scr->d_depth);
3223	    if (Scr->rootGC == (GC) 0) Scr->rootGC = XCreateGC (dpy, Scr->Root, 0, &gcvalues);
3224	    gcvalues.background = cp.back;
3225	    gcvalues.foreground = cp.fore;
3226	    XChangeGC   (dpy, Scr->rootGC, GCForeground | GCBackground, &gcvalues);
3227	    XCopyPlane  (dpy, pm, image->pixmap, Scr->rootGC, 0, 0, width, height, 0, 0,
3228			(unsigned long) 1);
3229	    image->mask   = None;
3230	    image->width  = width;
3231	    image->height = height;
3232	    image->next   = None;
3233	    AddToList (list, fullname, (char*) image);
3234	}
3235    }
3236    else {
3237	sprintf (fullname, "%s%dx%d", name, (int) cp.fore, (int) cp.back);
3238	if ((image = (Image*) LookInNameList (*list, fullname)) == None) {
3239	    if ((image = GetBitmapImage (name, cp)) != None) {
3240		AddToList (list, fullname, (char*) image);
3241	    }
3242	}
3243    }
3244    return (image);
3245}
3246
3247void FreeImage (Image *image)
3248{
3249    Image *im, *im2;
3250
3251    im = image;
3252    while (im != None) {
3253	if (im->pixmap) XFreePixmap (dpy, im->pixmap);
3254	if (im->mask)   XFreePixmap (dpy, im->mask);
3255	im2 = im->next;
3256	free (im);
3257	im = im2;
3258    }
3259}
3260
3261#if !defined(VMS) || defined(HAVE_XWDFILE_H)
3262static void compress (XImage *image, XColor *colors, int *ncolors);
3263
3264static Image *LoadXwdImage (char *filename, ColorPair cp)
3265{
3266    FILE	*file;
3267    char	*fullname;
3268    XColor	colors [256];
3269    XWDColor	xwdcolors [256];
3270    unsigned	buffer_size;
3271    XImage	*image;
3272    unsigned char *imagedata;
3273    Pixmap	pixret;
3274    Visual	*visual;
3275    char	win_name [256];
3276    int		win_name_size;
3277    int		ispipe;
3278    int		i, len;
3279    int		w, h, depth, ncolors;
3280    int		scrn;
3281    Colormap	cmap;
3282    Colormap	stdcmap = Scr->RootColormaps.cwins[0]->colormap->c;
3283    GC		gc;
3284    XGCValues   gcvalues;
3285    XWDFileHeader header;
3286    Image	*ret;
3287    Bool	anim;
3288    unsigned long swaptest = 1;
3289
3290    ispipe = 0;
3291    anim   = False;
3292#ifndef VMS
3293    if (filename [0] == '|') {
3294	file = (FILE*) popen (filename + 1, "r");
3295	if (file == NULL) return (None);
3296	ispipe = 1;
3297	anim = AnimationActive;
3298	if (anim) StopAnimation ();
3299	goto file_opened;
3300    }
3301#endif
3302    fullname = ExpandPixmapPath (filename);
3303    if (! fullname) return (None);
3304    file = fopen (fullname, "r");
3305    free (fullname);
3306    if (file == NULL) {
3307	if (reportfilenotfound) fprintf (stderr, "unable to locate %s\n", filename);
3308        return (None);
3309    }
3310file_opened:
3311    len = fread ((char *) &header, sizeof (header), 1, file);
3312    if (len != 1) {
3313	fprintf (stderr, "ctwm: cannot read %s\n", filename);
3314#ifdef USE_SIGNALS
3315	if (ispipe && anim) StartAnimation ();
3316#endif
3317	return (None);
3318    }
3319    if (*(char *) &swaptest) _swaplong ((char *) &header, sizeof (header));
3320    if (header.file_version != XWD_FILE_VERSION) {
3321	fprintf(stderr,"ctwm: XWD file format version mismatch : %s\n", filename);
3322	return (None);
3323    }
3324    win_name_size = header.header_size - sizeof (header);
3325    len = fread (win_name, win_name_size, 1, file);
3326    if (len != 1) {
3327	fprintf (stderr, "file %s has not the correct format\n", filename);
3328#ifdef USE_SIGNALS
3329	if (ispipe && anim) StartAnimation ();
3330#endif
3331	return (None);
3332    }
3333
3334    if (header.pixmap_format == XYPixmap) {
3335	fprintf (stderr,"ctwm: XYPixmap XWD file not supported : %s\n", filename);
3336	return (None);
3337    }
3338    w       = header.pixmap_width;
3339    h       = header.pixmap_height;
3340    depth   = header.pixmap_depth;
3341    ncolors = header.ncolors;
3342    len = fread ((char *) xwdcolors, sizeof (XWDColor), ncolors, file);
3343    if (len != ncolors) {
3344	fprintf (stderr, "file %s has not the correct format\n", filename);
3345#ifdef USE_SIGNALS
3346	if (ispipe && anim) StartAnimation ();
3347#endif
3348	return (None);
3349    }
3350    if (*(char *) &swaptest) {
3351	for (i = 0; i < ncolors; i++) {
3352	    _swaplong  ((char *) &xwdcolors [i].pixel, 4);
3353	    _swapshort ((char *) &xwdcolors [i].red, 3 * 2);
3354	}
3355    }
3356    for (i = 0; i < ncolors; i++) {
3357	colors [i].pixel = xwdcolors [i].pixel;
3358	colors [i].red   = xwdcolors [i].red;
3359	colors [i].green = xwdcolors [i].green;
3360	colors [i].blue  = xwdcolors [i].blue;
3361	colors [i].flags = xwdcolors [i].flags;
3362	colors [i].pad   = xwdcolors [i].pad;
3363    }
3364
3365    scrn    = Scr->screen;
3366    cmap    = AlternateCmap ? AlternateCmap : stdcmap;
3367    visual  = Scr->d_visual;
3368    gc      = DefaultGC (dpy, scrn);
3369
3370    buffer_size = header.bytes_per_line * h;
3371    imagedata = (unsigned char*) malloc (buffer_size);
3372    if (! imagedata) {
3373	fprintf (stderr, "cannot allocate memory for image %s\n", filename);
3374#ifdef USE_SIGNALS
3375	if (ispipe && anim) StartAnimation ();
3376#endif
3377	return (None);
3378    }
3379    len = fread (imagedata, (int) buffer_size, 1, file);
3380    if (len != 1) {
3381	free (imagedata);
3382	fprintf (stderr, "file %s has not the correct format\n", filename);
3383#ifdef USE_SIGNALS
3384	if (ispipe && anim) StartAnimation ();
3385#endif
3386	return (None);
3387    }
3388#ifndef VMS
3389    if (ispipe)
3390      pclose (file);
3391    else
3392#endif
3393      fclose (file);
3394
3395    image = XCreateImage (dpy, visual,  depth, header.pixmap_format,
3396                          0, (char*) imagedata, w, h,
3397                          header.bitmap_pad, header.bytes_per_line);
3398    if (image == None) {
3399	free (imagedata);
3400	fprintf (stderr, "cannot create image for %s\n", filename);
3401#ifdef USE_SIGNALS
3402	if (ispipe && anim) StartAnimation ();
3403#endif
3404	return (None);
3405    }
3406    if (header.pixmap_format == ZPixmap) {
3407	compress (image, colors, &ncolors);
3408    }
3409    if (header.pixmap_format != XYBitmap) {
3410	for (i = 0; i < ncolors; i++) {
3411            XAllocColor (dpy, cmap, &(colors [i]));
3412	}
3413	for (i = 0; i < buffer_size; i++) {
3414            imagedata [i] = (unsigned char) colors [imagedata [i]].pixel;
3415	}
3416    }
3417    if (w > Scr->rootw)  w = Scr->rootw;
3418    if (h > Scr->rooth) h = Scr->rooth;
3419
3420    ret = (Image*) malloc (sizeof (struct _Image));
3421    if (! ret) {
3422	fprintf (stderr, "unable to allocate memory for image : %s\n", filename);
3423	free (image);
3424	free (imagedata);
3425	for (i = 0; i < ncolors; i++) {
3426            XFreeColors (dpy, cmap, &(colors [i].pixel), 1, 0L);
3427	}
3428#ifdef USE_SIGNALS
3429	if (ispipe && anim) StartAnimation ();
3430#endif
3431	return (None);
3432    }
3433    if (header.pixmap_format == XYBitmap) {
3434	gcvalues.foreground = cp.fore;
3435	gcvalues.background = cp.back;
3436	XChangeGC (dpy, gc, GCForeground | GCBackground, &gcvalues);
3437    }
3438    if ((w > (Scr->rootw / 2)) || (h > (Scr->rooth / 2))) {
3439	int x, y;
3440
3441	pixret = XCreatePixmap (dpy, Scr->Root, Scr->rootw,
3442				Scr->rooth, Scr->d_depth);
3443	x = (Scr->rootw  - w) / 2;
3444	y = (Scr->rooth - h) / 2;
3445	XFillRectangle (dpy, pixret, gc, 0, 0, Scr->rootw, Scr->rooth);
3446	XPutImage (dpy, pixret, gc, image, 0, 0, x, y, w, h);
3447	ret->width  = Scr->rootw;
3448	ret->height = Scr->rooth;
3449    }
3450    else {
3451	pixret = XCreatePixmap (dpy, Scr->Root, w, h, depth);
3452	XPutImage (dpy, pixret, gc, image, 0, 0, 0, 0, w, h);
3453	ret->width  = w;
3454	ret->height = h;
3455    }
3456    XDestroyImage (image);
3457
3458    ret->pixmap = pixret;
3459    ret->mask   = None;
3460    ret->next   = None;
3461#ifdef USE_SIGNALS
3462    if (ispipe && anim) StartAnimation ();
3463#endif
3464    return (ret);
3465}
3466
3467static Image *GetXwdImage (char *name, ColorPair cp)
3468{
3469    Image *image, *r, *s;
3470    char  path [128];
3471    char  pref [128], *perc;
3472    int   i;
3473
3474    if (! strchr (name, '%')) return (LoadXwdImage (name, cp));
3475    s = image = None;
3476    strcpy (pref, name);
3477    perc  = strchr (pref, '%');
3478    *perc = '\0';
3479    reportfilenotfound = 0;
3480    for (i = 1;; i++) {
3481	sprintf (path, "%s%d%s", pref, i, perc + 1);
3482	r = LoadXwdImage (path, cp);
3483	if (r == None) break;
3484	r->next   = None;
3485	if (image == None) s = image = r;
3486	else {
3487	    s->next = r;
3488	    s = r;
3489	}
3490    }
3491    reportfilenotfound = 1;
3492    if (s != None) s->next = image;
3493    if (image == None) {
3494	fprintf (stderr, "Cannot open any %s xwd file\n", name);
3495    }
3496    return (image);
3497}
3498
3499static void compress (XImage *image, XColor *colors, int *ncolors)
3500{
3501    unsigned char ind  [256];
3502    unsigned int  used [256];
3503    int           i, j, size, nused;
3504    unsigned char color;
3505    XColor        newcolors [256];
3506    unsigned char *imagedata;
3507
3508    for (i = 0; i < 256; i++) {
3509	used [i] = 0;
3510	ind  [i] = 0;
3511    }
3512    nused = 0;
3513    size  = image->bytes_per_line * image->height;
3514    imagedata = (unsigned char *) image->data;
3515    for (i = 0; i < size; i++) {
3516	if ((i % image->bytes_per_line) > image->width) continue;
3517        color = imagedata [i];
3518        if (used [color] == 0) {
3519            for (j = 0; j < nused; j++) {
3520                if ((colors [color].red   == newcolors [j].red)   &&
3521                    (colors [color].green == newcolors [j].green) &&
3522                    (colors [color].blue  == newcolors [j].blue)) break;
3523            }
3524            ind  [color] = j;
3525            used [color] = 1;
3526            if (j == nused) {
3527                newcolors [j].red   = colors [color].red;
3528                newcolors [j].green = colors [color].green;
3529                newcolors [j].blue  = colors [color].blue;
3530                nused++;
3531            }
3532        }
3533    }
3534    for (i = 0; i < size; i++) {
3535        imagedata [i] = ind [imagedata [i]];
3536    }
3537    for (i = 0; i < nused; i++) {
3538        colors [i] = newcolors [i];
3539    }
3540    *ncolors = nused;
3541}
3542#endif
3543
3544#ifdef IMCONV
3545
3546static void free_images  ();
3547
3548static Image *GetImconvImage (char *filename,
3549			      unsigned int *widthp, unsigned int *heightp)
3550{
3551    TagTable		*toolInTable;
3552    ImVfb		*sourceVfb;
3553    ImVfbPtr		vptr;
3554    ImClt		*clt;
3555    int			i, j, ij, k, retval;
3556
3557    XColor		colors [256];
3558    unsigned		buffer_size;
3559    XImage		*image;
3560    unsigned char	*imagedata;
3561    Pixmap		pixret;
3562    Visual		*visual;
3563    int			w, h, depth, ncolors;
3564    int			scrn;
3565    Colormap		cmap;
3566    Colormap		stdcmap = Scr->RootColormaps.cwins[0]->colormap->c;
3567    GC			gc;
3568    unsigned char	red, green, blue;
3569    int			icol;
3570    char		*fullname;
3571
3572    TagEntry		*dataEntry;
3573    FILE		*fp;
3574    char		the_format[1024];
3575    char		*tmp_format;
3576    Image		*ret;
3577
3578    if (*filename == NULL) return (None);
3579    fullname = ExpandPixmapPath (filename);
3580    if (! fullname) return (None);
3581
3582    fp = fopen (fullname, "r");
3583    if (!fp) {
3584	if (reportfilenotfound) fprintf (stderr, "Cannot open the image %s\n", filename);
3585	free (fullname);
3586	return (None);
3587    }
3588    if ((toolInTable = TagTableAlloc ()) == TAGTABLENULL ) {
3589	fprintf (stderr, "TagTableAlloc failed\n");
3590	free_images (toolInTable);
3591	free (fullname);
3592	return (None);
3593    }
3594    if ((tmp_format = ImFileQFFormat (fp, fullname)) == NULL)  {
3595	fprintf (stderr, "Cannot determine image type of %s\n", filename);
3596	free_images  (toolInTable);
3597	free (fullname);
3598	return (None);
3599    }
3600    strcpy (the_format, tmp_format);
3601    retval = ImFileFRead (fp, the_format, NULL, toolInTable);
3602    if(retval < 0) {
3603	fprintf(stderr, "Cannot read image file %s: ", fullname);
3604	switch(ImErrNo) {
3605	    case IMESYS:
3606		fprintf (stderr, "System call error\n");
3607		break;
3608	    case IMEMALLOC:
3609		fprintf (stderr, "Cannot allocate memory\n");
3610		break;
3611	    case IMEFORMAT:
3612		fprintf (stderr, "Data in file is corrupt\n");
3613		break;
3614	    case IMENOREAD:
3615		fprintf (stderr, "Sorry, this format is write-only\n");
3616		break;
3617	    case IMEMAGIC:
3618		fprintf (stderr, "Bad magic number in image file\n");
3619		break;
3620	    case IMEDEPTH:
3621		fprintf (stderr, "Unknown image depth\n");
3622		break;
3623	    default:
3624		fprintf(stderr, "Unknown error\n");
3625		break;
3626	}
3627	free_images (toolInTable);
3628	free (fullname);
3629	return (None);
3630    }
3631
3632    if (TagTableQNEntry (toolInTable, "image vfb") == 0)  {
3633	fprintf (stderr, "Image file %s contains no images\n", fullname);
3634	free_images (toolInTable);
3635	free (fullname);
3636	return (None);
3637    }
3638    dataEntry = TagTableQDirect (toolInTable, "image vfb", 0);
3639    TagEntryQValue (dataEntry, &sourceVfb);
3640    fclose (fp);
3641
3642    w = ImVfbQWidth  (sourceVfb);
3643    h = ImVfbQHeight (sourceVfb);
3644    depth = 8 * ImVfbQNBytes (sourceVfb);
3645    if (depth != 8) {
3646	fprintf (stderr, "I don't know yet how to deal with images not of 8 planes depth\n");
3647	free_images (toolInTable);
3648	return (None);
3649    }
3650
3651    *width  = w;
3652    *height = h;
3653
3654    scrn   = Scr->screen;
3655    cmap   = AlternateCmap ? AlternateCmap : stdcmap;
3656    visual = Scr->d_visual;
3657    gc     = DefaultGC (dpy, scrn);
3658
3659    buffer_size = w * h;
3660    imagedata = (unsigned char*) malloc (buffer_size);
3661    if (imagedata == (unsigned char*) 0) {
3662	fprintf (stderr, "Can't alloc enough space for background images\n");
3663	free_images (toolInTable);
3664	return (None);
3665    }
3666
3667    clt  = ImVfbQClt   (sourceVfb);
3668    vptr = ImVfbQFirst (sourceVfb);
3669    ncolors = 0;
3670    for (i = 0; i < h - 1; i++) {
3671	for (j = 0; j < w; j++) {
3672	    ij = (i * w) + j;
3673	    red   = ImCltQRed   (ImCltQPtr (clt, ImVfbQIndex (sourceVfb, vptr)));
3674	    green = ImCltQGreen (ImCltQPtr (clt, ImVfbQIndex (sourceVfb, vptr)));
3675	    blue  = ImCltQBlue  (ImCltQPtr (clt, ImVfbQIndex (sourceVfb, vptr)));
3676	    for (k = 0; k < ncolors; k++) {
3677		if ((colors [k].red   == red) &&
3678		    (colors [k].green == green) &&
3679		    (colors [k].blue  == blue)) {
3680		    icol = k;
3681		    break;
3682		}
3683	    }
3684	    if (k == ncolors) {
3685		icol = ncolors;
3686		ncolors++;
3687	    }
3688	    imagedata [ij] = icol;
3689	    colors [icol].red   = red;
3690	    colors [icol].green = green;
3691	    colors [icol].blue  = blue;
3692	    ImVfbSInc (sourceVfb, vptr);
3693	}
3694    }
3695    for (i = 0; i < ncolors; i++) {
3696	colors [i].red   *= 256;
3697	colors [i].green *= 256;
3698	colors [i].blue  *= 256;
3699    }
3700    for (i = 0; i < ncolors; i++) {
3701        if (! XAllocColor (dpy, cmap, &(colors [i]))) {
3702	    fprintf (stderr, "can't alloc color for image %s\n", filename);
3703	}
3704    }
3705    for (i = 0; i < buffer_size; i++) {
3706        imagedata [i] = (unsigned char) colors [imagedata [i]].pixel;
3707    }
3708
3709    image  = XCreateImage  (dpy, visual, depth, ZPixmap, 0, (char*) imagedata, w, h, 8, 0);
3710    if (w > Scr->rootw)  w = Scr->rootw;
3711    if (h > Scr->rooth) h = Scr->rooth;
3712
3713    if ((w > (Scr->rootw / 2)) || (h > (Scr->rooth / 2))) {
3714	int x, y;
3715
3716	pixret = XCreatePixmap (dpy, Scr->Root, Scr->rootw, Scr->rooth, depth);
3717	x = (Scr->rootw  - w) / 2;
3718	y = (Scr->rooth - h) / 2;
3719	XFillRectangle (dpy, pixret, gc, 0, 0, Scr->rootw, Scr->rooth);
3720	XPutImage (dpy, pixret, gc, image, 0, 0, x, y, w, h);
3721	ret->width  = Scr->rootw;
3722	ret->height = Scr->rooth;
3723    }
3724    else {
3725	pixret = XCreatePixmap (dpy, Scr->Root, w, h, depth);
3726	XPutImage (dpy, pixret, gc, image, 0, 0, 0, 0, w, h);
3727	ret->width  = w;
3728	ret->height = h;
3729    }
3730    XFree (image);
3731    ret = (Image*) malloc (sizeof (struct _Image));
3732    ret->pixmap = pixret;
3733    ret->mask   = None;
3734    ret->next   = None;
3735    return (ret);
3736
3737}
3738
3739static void free_images (table)
3740TagTable *table;
3741{
3742    int		i, n;
3743    ImVfb	*v;
3744    ImClt	*c;
3745    TagEntry	*dataEntry;
3746
3747    n = TagTableQNEntry (table, "image vfb");
3748    for (i = 0 ; i < n ; i++) {
3749	dataEntry = TagTableQDirect (table, "image vfb", i);
3750	TagEntryQValue (dataEntry, &v);
3751	ImVfbFree (v);
3752    }
3753    n = TagTableQNEntry (table, "image clt");
3754    for (i = 0 ; i < n ; i++) {
3755	dataEntry = TagTableQDirect (table, "image clt", i );
3756	TagEntryQValue (dataEntry, &c);
3757	ImCltFree (c);
3758    }
3759    TagTableFree (table);
3760}
3761
3762#endif
3763
3764void _swapshort (register char *bp, register unsigned n)
3765{
3766    register char c;
3767    register char *ep = bp + n;
3768
3769    while (bp < ep) {
3770	c = *bp;
3771	*bp = *(bp + 1);
3772	bp++;
3773	*bp++ = c;
3774    }
3775}
3776
3777void _swaplong (register char *bp, register unsigned n)
3778{
3779    register char c;
3780    register char *ep = bp + n;
3781    register char *sp;
3782
3783    while (bp < ep) {
3784	sp = bp + 3;
3785	c = *sp;
3786	*sp = *bp;
3787	*bp++ = c;
3788	sp = bp + 1;
3789	c = *sp;
3790	*sp = *bp;
3791	*bp++ = c;
3792	bp += 2;
3793    }
3794}
3795
3796/***********************************************************************
3797 *
3798 *  Procedure:
3799 *	GetWMPropertyString - Get Window Manager text property and
3800 *				convert it to a string.
3801 *
3802 *  Returned Value:
3803 *	(char *) - pointer to the malloc'd string or NULL
3804 *
3805 *  Inputs:
3806 *	w	- the id of the window whose property is to be retrieved
3807 *	prop	- property atom (typically WM_NAME or WM_ICON_NAME)
3808 *
3809 ***********************************************************************
3810 */
3811
3812unsigned char *GetWMPropertyString(Window w, Atom prop)
3813{
3814    XTextProperty	text_prop;
3815    char 		**text_list;
3816    int 		text_list_count;
3817    Atom 		XA_COMPOUND_TEXT = XInternAtom(dpy, "COMPOUND_TEXT", False);
3818    unsigned char	*stringptr;
3819    int			status, len = -1;
3820
3821    (void)XGetTextProperty(dpy, w, &text_prop, prop);
3822    if (text_prop.value != NULL) {
3823	if (text_prop.encoding == XA_STRING
3824	    || text_prop.encoding == XA_COMPOUND_TEXT) {
3825	    /* property is encoded as compound text - convert to locale string */
3826	    status = XmbTextPropertyToTextList(dpy, &text_prop,
3827					       &text_list, &text_list_count);
3828	    if (text_list_count == 0) {
3829		stringptr = NULL;
3830	    } else
3831	    if (text_list == (char **)0) {
3832		stringptr = NULL;
3833	    } else
3834	    if (text_list [0] == (char *)0) {
3835		stringptr = NULL;
3836	    } else
3837	    if (status < 0 || text_list_count < 0) {
3838		switch (status) {
3839		case XConverterNotFound:
3840		    fprintf (stderr, "%s: Converter not found; unable to convert property %s of window ID %lx.\n",
3841			     ProgramName, XGetAtomName(dpy, prop), w);
3842		    break;
3843		case XNoMemory:
3844		    fprintf (stderr, "%s: Insufficient memory; unable to convert property %s of window ID %lx.\n",
3845			     ProgramName, XGetAtomName(dpy, prop), w);
3846		    break;
3847		case XLocaleNotSupported:
3848		    fprintf (stderr, "%s: Locale not supported; unable to convert property %s of window ID %lx.\n",
3849			     ProgramName, XGetAtomName(dpy, prop), w);
3850		    break;
3851		}
3852		stringptr = NULL;
3853		/*
3854		   don't call XFreeStringList - text_list appears to have
3855		   invalid address if status is bad
3856		   XFreeStringList(text_list);
3857		*/
3858	    } else {
3859		len = strlen(text_list[0]);
3860		stringptr = memcpy(malloc(len+1), text_list[0], len+1);
3861		XFreeStringList(text_list);
3862	    }
3863	} else {
3864	    /* property is encoded in a format we don't understand */
3865	    fprintf (stderr, "%s: Encoding not STRING or COMPOUND_TEXT; unable to decode property %s of window ID %lx.\n",
3866		     ProgramName, XGetAtomName(dpy, prop), w);
3867	    stringptr = NULL;
3868	}
3869	XFree (text_prop.value);
3870    } else {
3871	stringptr = NULL;
3872    }
3873
3874    return stringptr;
3875}
3876
3877void FreeWMPropertyString(char *prop)
3878{
3879    if (prop && (char *)prop != NoName) {
3880	free(prop);
3881    }
3882}
3883
3884static void ConstrainLeftTop (int *value, int border)
3885{
3886  if (*value < border) {
3887    if (Scr->MoveOffResistance < 0 ||
3888	*value > border - Scr->MoveOffResistance)
3889    {
3890        *value = border;
3891    } else if (Scr->MoveOffResistance > 0 &&
3892	       *value <= border - Scr->MoveOffResistance)
3893    {
3894      *value = *value + Scr->MoveOffResistance;
3895    }
3896    }
3897}
3898
3899static void ConstrainRightBottom (int *value, int size1, int border, int size2)
3900{
3901    if (*value + size1 > size2 - border) {
3902      if (Scr->MoveOffResistance < 0 ||
3903         *value + size1 < size2 - border + Scr->MoveOffResistance)
3904    {
3905        *value = size2 - size1 - border;
3906	} else if (Scr->MoveOffResistance > 0 &&
3907		   *value + size1 >= size2 - border + Scr->MoveOffResistance) {
3908	  *value = *value - Scr->MoveOffResistance;
3909	}
3910    }
3911}
3912
3913void ConstrainByBorders1 (int *left, int width, int *top, int height)
3914{
3915    ConstrainRightBottom (left, width, Scr->BorderRight, Scr->rootw);
3916    ConstrainLeftTop     (left, Scr->BorderLeft);
3917    ConstrainRightBottom (top, height, Scr->BorderBottom, Scr->rooth);
3918    ConstrainLeftTop     (top, Scr->BorderTop);
3919}
3920
3921void ConstrainByBorders (TwmWindow *twmwin,
3922			 int *left, int width, int *top, int height)
3923{
3924    if (twmwin->winbox) {
3925	XWindowAttributes attr;
3926	XGetWindowAttributes (dpy, twmwin->winbox->window, &attr);
3927	ConstrainRightBottom (left, width, 0, attr.width);
3928	ConstrainLeftTop     (left, 0);
3929	ConstrainRightBottom (top, height, 0, attr.height);
3930	ConstrainLeftTop     (top, 0);
3931    } else {
3932	ConstrainByBorders1 (left, width, top, height);
3933    }
3934}
3935
3936#ifdef JPEG
3937
3938uint16_t *buffer_16bpp;
3939uint32_t *buffer_32bpp;
3940
3941static void convert_for_16 (int w, int x, int y, int r, int g, int b) {
3942  buffer_16bpp [y * w + x] = ((r >> 3) << 11) + ((g >> 2) << 5) + (b >> 3);
3943}
3944
3945static void convert_for_32 (int w, int x, int y, int r, int g, int b) {
3946  buffer_32bpp [y * w + x] = ((r << 16) + (g << 8) + b) & 0xFFFFFFFF;
3947}
3948
3949static void jpeg_error_exit (j_common_ptr cinfo) {
3950  jerr_ptr errmgr = (jerr_ptr) cinfo->err;
3951  cinfo->err->output_message (cinfo);
3952  siglongjmp (errmgr->setjmp_buffer, 1);
3953  return;
3954}
3955
3956static Image *GetJpegImage (char *name)
3957{
3958    Image *image, *r, *s;
3959    char  path [128];
3960    char  pref [128], *perc;
3961    int   i;
3962
3963    if (! strchr (name, '%')) return (LoadJpegImage (name));
3964    s = image = None;
3965    strcpy (pref, name);
3966    perc  = strchr (pref, '%');
3967    *perc = '\0';
3968    reportfilenotfound = 0;
3969    for (i = 1;; i++) {
3970	sprintf (path, "%s%d%s", pref, i, perc + 1);
3971	r = LoadJpegImage (path);
3972	if (r == None) break;
3973	r->next   = None;
3974	if (image == None) s = image = r;
3975	else {
3976	    s->next = r;
3977	    s = r;
3978	}
3979    }
3980    reportfilenotfound = 1;
3981    if (s != None) s->next = image;
3982    if (image == None) {
3983	fprintf (stderr, "Cannot open any %s jpeg file\n", name);
3984    }
3985    return (image);
3986}
3987
3988static Image *LoadJpegImage (char *name)
3989{
3990  char   *fullname;
3991  XImage *ximage;
3992  FILE   *infile;
3993  Image  *image;
3994  Pixmap pixret;
3995  void   (*store_data) (int w, int x, int y, int r, int g, int b);
3996  struct jpeg_decompress_struct cinfo;
3997  struct jpeg_error jerr;
3998  JSAMPARRAY buffer;
3999  int width, height;
4000  int row_stride;
4001  int g, i, a;
4002  int bpix;
4003  GC  gc;
4004
4005  fullname = ExpandPixmapPath (name);
4006  if (! fullname) return (None);
4007
4008  image = (Image*) malloc (sizeof (struct _Image));
4009  if (image == None) return (None);
4010
4011  if ((infile = fopen (fullname, "rb")) == NULL) {
4012    if (!reportfilenotfound) fprintf (stderr, "unable to locate %s\n", fullname);
4013    fflush (stdout);
4014    return None;
4015  }
4016  cinfo.err = jpeg_std_error (&jerr.pub);
4017  jerr.pub.error_exit = jpeg_error_exit;
4018
4019  if (sigsetjmp(jerr.setjmp_buffer, 1)) {
4020    jpeg_destroy_decompress (&cinfo);
4021    fclose (infile);
4022    return None;
4023  }
4024  jpeg_create_decompress (&cinfo);
4025  jpeg_stdio_src (&cinfo, infile);
4026  jpeg_read_header (&cinfo, FALSE);
4027  cinfo.do_fancy_upsampling = FALSE;
4028  cinfo.do_block_smoothing = FALSE;
4029  jpeg_start_decompress (&cinfo);
4030  width  = cinfo.output_width;
4031  height = cinfo.output_height;
4032
4033  if (Scr->d_depth == 16) {
4034    store_data = &convert_for_16;
4035    buffer_16bpp = (unsigned short int *) malloc ((width) * (height) * 2);
4036    ximage = XCreateImage (dpy, CopyFromParent, Scr->d_depth, ZPixmap, 0,
4037			   (char *) buffer_16bpp, width, height, 16, width * 2);
4038  } else {
4039    if (Scr->d_depth == 24) {
4040      store_data = &convert_for_32;
4041      buffer_32bpp = malloc (width * height * 4);
4042      ximage = XCreateImage (dpy, CopyFromParent, Scr->d_depth, ZPixmap, 0,
4043			     (char *) buffer_32bpp, width, height, 32, width * 4);
4044    } else
4045    if (Scr->d_depth == 32) {
4046      store_data = &convert_for_32;
4047      buffer_32bpp = malloc (width * height * 4);
4048      ximage = XCreateImage (dpy, CopyFromParent, Scr->d_depth, ZPixmap, 0,
4049			     (char *) buffer_32bpp, width, height, 32, width * 4);
4050    } else {
4051      fprintf (stderr, "Image %s unsupported depth : %d\n", name, Scr->d_depth);
4052      return None;
4053    }
4054  }
4055  if (ximage == None) {
4056    fprintf (stderr, "cannot create image for %s\n", name);
4057  }
4058  g = 0;
4059  row_stride = cinfo.output_width * cinfo.output_components;
4060  buffer = (*cinfo.mem->alloc_sarray)
4061    ((j_common_ptr) & cinfo, JPOOL_IMAGE, row_stride, 1);
4062
4063  bpix = cinfo.output_components;
4064  while (cinfo.output_scanline < cinfo.output_height) {
4065    jpeg_read_scanlines (&cinfo, buffer, 1);
4066    a = 0;
4067    for (i = 0; i < bpix * cinfo.output_width; i += bpix) {
4068      (*store_data) (width, a, g, buffer[0][i],  buffer[0][i + 1], buffer[0][i + 2]);
4069      a++;
4070    }
4071    g++;
4072  }
4073  jpeg_finish_decompress (&cinfo);
4074  jpeg_destroy_decompress (&cinfo);
4075  fclose (infile);
4076
4077  gc = DefaultGC (dpy, Scr->screen);
4078  if ((width > (Scr->rootw / 2)) || (height > (Scr->rooth / 2))) {
4079    int x, y;
4080
4081    pixret = XCreatePixmap (dpy, Scr->Root, Scr->rootw, Scr->rooth, Scr->d_depth);
4082    x = (Scr->rootw  -  width) / 2;
4083    y = (Scr->rooth  - height) / 2;
4084    XFillRectangle (dpy, pixret, gc, 0, 0, Scr->rootw, Scr->rooth);
4085    XPutImage (dpy, pixret, gc, ximage, 0, 0, x, y, width, height);
4086    image->width  = Scr->rootw;
4087    image->height = Scr->rooth;
4088  } else {
4089    pixret = XCreatePixmap (dpy, Scr->Root, width, height, Scr->d_depth);
4090    XPutImage (dpy, pixret, gc, ximage, 0, 0, 0, 0, width, height);
4091    image->width  = width;
4092    image->height = height;
4093  }
4094  XDestroyImage (ximage);
4095  image->pixmap = pixret;
4096  image->mask   = None;
4097  image->next   = None;
4098
4099  return image;
4100}
4101
4102#endif /* JPEG */
4103