util.c revision 645f5050
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	Scr->WelcomeImage  = GetImage ("xwd:welcome.xwd", WelcomeCp);
912#ifdef XPM
913	if (Scr->WelcomeImage == None)
914		Scr->WelcomeImage  = GetImage ("xpm:welcome.xpm", WelcomeCp);
915#endif
916    }
917    else {
918	Scr->WelcomeImage  = GetImage (file, WelcomeCp);
919    }
920    AlternateCmap = None;
921    reportfilenotfound = 1;
922    if (Scr->WelcomeImage == None) return;
923
924    if (captive) {
925	XSetWindowColormap (dpy, Scr->WindowMask, Scr->WelcomeCmap);
926	XSetWMColormapWindows (dpy, Scr->Root, &(Scr->WindowMask), 1);
927    }
928    else XInstallColormap (dpy, Scr->WelcomeCmap);
929
930    Scr->WelcomeGC = XCreateGC (dpy, Scr->WindowMask, 0, NULL);
931    x = (Scr->rootw  -  Scr->WelcomeImage->width) / 2;
932    y = (Scr->rooth - Scr->WelcomeImage->height) / 2;
933
934    XSetWindowBackground (dpy, Scr->WindowMask, black.pixel);
935    XClearWindow (dpy, Scr->WindowMask);
936    XCopyArea (dpy, Scr->WelcomeImage->pixmap, Scr->WindowMask, Scr->WelcomeGC, 0, 0,
937		Scr->WelcomeImage->width, Scr->WelcomeImage->height, x, y);
938}
939
940void UnmaskScreen (void)
941{
942#ifdef VMS
943    float  timeout;
944#else
945    struct timeval	timeout;
946#endif
947    Colormap            stdcmap = Scr->RootColormaps.cwins[0]->colormap->c;
948    Colormap		cmap;
949    XColor		colors [256], stdcolors [256];
950    int			i, j, usec;
951
952#ifdef VMS
953    timeout = 0.017;
954#else
955    usec = 10000;
956    timeout.tv_usec = usec % (unsigned long) 1000000;
957    timeout.tv_sec  = usec / (unsigned long) 1000000;
958#endif
959
960    if (Scr->WelcomeImage) {
961	Pixel pixels [256];
962
963	cmap = Scr->WelcomeCmap;
964	for (i = 0; i < 256; i++) {
965	    pixels [i] = i;
966	    colors [i].pixel = i;
967	}
968	XQueryColors (dpy, cmap, colors, 256);
969	XFreeColors  (dpy, cmap, pixels, 256, 0L);
970	XFreeColors  (dpy, cmap, pixels, 256, 0L); /* Ah Ah */
971
972	for (i = 0; i < 256; i++) {
973	    colors [i].pixel = i;
974	    colors [i].flags = DoRed | DoGreen | DoBlue;
975	    stdcolors [i].red   = colors [i].red;
976	    stdcolors [i].green = colors [i].green;
977	    stdcolors [i].blue  = colors [i].blue;
978	}
979	for (i = 0; i < 128; i++) {
980	    for (j = 0; j < 256; j++) {
981		colors [j].red   = stdcolors [j].red   * ((127.0 - i) / 128.0);
982		colors [j].green = stdcolors [j].green * ((127.0 - i) / 128.0);
983		colors [j].blue  = stdcolors [j].blue  * ((127.0 - i) / 128.0);
984	    }
985	    XStoreColors (dpy, cmap, colors, 256);
986#ifdef VMS
987	    lib$wait(&timeout);
988#else
989	    select (0, (void *) 0, (void *) 0, (void *) 0, &timeout);
990#endif
991	}
992	XFreeColors   (dpy, cmap, pixels, 256, 0L);
993	XFreeGC       (dpy, Scr->WelcomeGC);
994	FreeImage     (Scr->WelcomeImage);
995    }
996    if (Scr->Monochrome != COLOR) goto fin;
997
998    cmap = XCreateColormap (dpy, Scr->Root, Scr->d_visual, AllocNone);
999    if (! cmap) goto fin;
1000    for (i = 0; i < 256; i++) {
1001	colors [i].pixel = i;
1002	colors [i].red   = 0;
1003	colors [i].green = 0;
1004	colors [i].blue  = 0;
1005	colors [i].flags = DoRed | DoGreen | DoBlue;
1006    }
1007    XStoreColors (dpy, cmap, colors, 256);
1008
1009    if (captive) XSetWindowColormap (dpy, Scr->Root, cmap);
1010    else XInstallColormap (dpy, cmap);
1011
1012    XUnmapWindow (dpy, Scr->WindowMask);
1013    XClearWindow (dpy, Scr->Root);
1014    XSync (dpy, 0);
1015    PaintAllDecoration ();
1016
1017    for (i = 0; i < 256; i++) stdcolors [i].pixel = i;
1018    XQueryColors (dpy, stdcmap, stdcolors, 256);
1019    for (i = 0; i < 128; i++) {
1020	for (j = 0; j < 256; j++) {
1021	    colors [j].pixel = j;
1022	    colors [j].red   = stdcolors [j].red   * (i / 127.0);
1023	    colors [j].green = stdcolors [j].green * (i / 127.0);
1024	    colors [j].blue  = stdcolors [j].blue  * (i / 127.0);
1025	    colors [j].flags = DoRed | DoGreen | DoBlue;
1026	}
1027	XStoreColors (dpy, cmap, colors, 256);
1028#ifdef VMS
1029        lib$wait(&timeout);
1030#else
1031	select (0, (void *) 0, (void *) 0, (void *) 0, &timeout);
1032#endif
1033    }
1034
1035    if (captive) XSetWindowColormap (dpy, Scr->Root, stdcmap);
1036    else XInstallColormap (dpy, stdcmap);
1037
1038    XFreeColormap (dpy, cmap);
1039
1040fin:
1041    if (Scr->WelcomeCmap) XFreeColormap (dpy, Scr->WelcomeCmap);
1042    XDestroyWindow (dpy, Scr->WindowMask);
1043    Scr->WindowMask = (Window) 0;
1044}
1045
1046#ifdef VMS
1047
1048/* use the VMS system services to request the timer to issue an AST */
1049void AnimateHandler (void);
1050
1051unsigned int tv[2];
1052int status;
1053static unsigned long timefi;
1054/* unsigned long timefe = 17; */
1055unsigned long timefe;
1056
1057#define TIMID 12L
1058
1059void StartAnimation (void)
1060{
1061    if (AnimationSpeed > MAXANIMATIONSPEED) AnimationSpeed = MAXANIMATIONSPEED;
1062    if (AnimationSpeed <= 0) return;
1063    if (AnimationActive) return;
1064
1065    if (!timefi) lib$get_ef(&timefi);
1066    if (!timefe) lib$get_ef(&timefe);
1067
1068    tv[1] = 0xFFFFFFFF;                   /* quadword negative for relative */
1069    tv[0] = -(10000000 / AnimationSpeed); /* time. In units of 100ns. */
1070    sys$clref(timefe);
1071    status = sys$setimr (timefi, &tv, AnimateHandler, TIMID );
1072    if (status != SS$_NORMAL) lib$signal(status);
1073    AnimationActive = True;
1074}
1075
1076void StopAnimation () {
1077    if (AnimationSpeed <= 0) return;
1078    if (! AnimationActive) return;
1079    AnimationActive = False;
1080
1081    status = sys$cantim(TIMID, PSL$C_USER);
1082    if (status != SS$_NORMAL) lib$signal(status);
1083}
1084
1085void SetAnimationSpeed (int speed)
1086{
1087    AnimationSpeed = speed;
1088    if (AnimationSpeed > MAXANIMATIONSPEED) AnimationSpeed = MAXANIMATIONSPEED;
1089}
1090
1091void ModifyAnimationSpeed (int incr)
1092{
1093    if ((AnimationSpeed + incr) < 0) return;
1094    if ((AnimationSpeed + incr) == 0) {
1095	if (AnimationActive) StopAnimation ();
1096	AnimationSpeed = 0;
1097	return;
1098    }
1099    AnimationSpeed += incr;
1100
1101    status = sys$cantim(TIMID, PSL$C_USER);
1102    if (status != SS$_NORMAL) lib$signal(status);
1103
1104    tv[1] = 0xFFFFFFFF;
1105    tv[0] = -(10000000 / AnimationSpeed);
1106
1107    sys$clref(timefe);
1108    status = sys$setimr (timefi, &tv, AnimateHandler, TIMID);
1109    if (status != SS$_NORMAL) lib$signal(status);
1110
1111    AnimationActive = True;
1112}
1113
1114void AnimateHandler (void) {
1115    AnimationPending = True;
1116
1117    sys$setef(timefe);
1118    status = sys$setimr (timefi, &tv, AnimateHandler, TIMID);
1119    if (status != SS$_NORMAL) lib$signal(status);
1120}
1121#else /* VMS */
1122
1123#ifdef USE_SIGNALS
1124SIGNAL_T AnimateHandler ();
1125#endif
1126
1127#ifndef USE_SIGNALS
1128void TryToAnimate (void)
1129{
1130    struct timeval  tp;
1131    struct timezone tzp;
1132    static unsigned long lastsec;
1133    static long lastusec;
1134    unsigned long gap;
1135
1136    gettimeofday (&tp, &tzp);
1137    gap = ((tp.tv_sec - lastsec) * 1000000) + (tp.tv_usec - lastusec);
1138    if (tracefile) {
1139	fprintf (tracefile, "Time = %lu, %ld, %ld, %ld, %lu\n", lastsec,
1140		lastusec, (long)tp.tv_sec, (long)tp.tv_usec, gap);
1141	fflush (tracefile);
1142    }
1143    gap *= AnimationSpeed;
1144    if (gap < 1000000) return;
1145    if (tracefile) {
1146	fprintf (tracefile, "Animate\n");
1147	fflush (tracefile);
1148    }
1149    Animate ();
1150    lastsec  = tp.tv_sec;
1151    lastusec = tp.tv_usec;
1152}
1153#endif /* USE_SIGNALS */
1154
1155void StartAnimation (void)
1156{
1157#ifdef USE_SIGNALS
1158    struct itimerval tv;
1159#endif
1160
1161    if (AnimationSpeed > MAXANIMATIONSPEED) AnimationSpeed = MAXANIMATIONSPEED;
1162    if (AnimationSpeed <= 0) AnimationSpeed = 0;
1163    if (AnimationActive) return;
1164#ifdef USE_SIGNALS
1165    if (AnimationSpeed == 0) return;
1166    signal (SIGALRM, AnimateHandler);
1167    if (AnimationSpeed == 1) {
1168	tv.it_interval.tv_sec  = 1;
1169	tv.it_interval.tv_usec = 0;
1170	tv.it_value.tv_sec     = 1;
1171	tv.it_value.tv_usec    = 0;
1172    }
1173    else {
1174	tv.it_interval.tv_sec  = 0;
1175	tv.it_interval.tv_usec = 1000000 / AnimationSpeed;
1176	tv.it_value.tv_sec     = 0;
1177	tv.it_value.tv_usec    = 1000000 / AnimationSpeed;
1178    }
1179    setitimer (ITIMER_REAL, &tv, (struct itimerval*) NULL);
1180#else /* USE_SIGNALS */
1181    switch (AnimationSpeed) {
1182	case 0 :
1183	    return;
1184	case 1 :
1185	    AnimateTimeout.tv_sec  = 1;
1186	    AnimateTimeout.tv_usec = 0;
1187	    break;
1188	default :
1189	    AnimateTimeout.tv_sec  = 0;
1190	    AnimateTimeout.tv_usec = 1000000 / AnimationSpeed;
1191    }
1192#endif /* USE_SIGNALS */
1193    AnimationActive = True;
1194}
1195
1196void StopAnimation (void)
1197{
1198#ifdef USE_SIGNALS
1199    struct itimerval tv;
1200
1201    if (AnimationSpeed <= 0) return;
1202    if (! AnimationActive) return;
1203    signal (SIGALRM, SIG_IGN);
1204
1205    tv.it_value.tv_sec     = 0;
1206    tv.it_value.tv_usec    = 0;
1207    setitimer (ITIMER_REAL, &tv, (struct itimerval*) NULL);
1208#endif
1209    AnimationActive = False;
1210}
1211
1212void SetAnimationSpeed (int speed)
1213{
1214    AnimationSpeed = speed;
1215    if (AnimationSpeed > MAXANIMATIONSPEED) AnimationSpeed = MAXANIMATIONSPEED;
1216}
1217
1218void ModifyAnimationSpeed (int incr)
1219{
1220#ifdef USE_SIGNALS
1221    struct itimerval tv;
1222#endif
1223
1224    if ((AnimationSpeed + incr) < 0) return;
1225    if ((AnimationSpeed + incr) == 0) {
1226	if (AnimationActive) StopAnimation ();
1227	AnimationSpeed = 0;
1228	return;
1229    }
1230    AnimationSpeed += incr;
1231    if (AnimationSpeed > MAXANIMATIONSPEED) AnimationSpeed = MAXANIMATIONSPEED;
1232
1233#ifdef USE_SIGNALS
1234    signal (SIGALRM, AnimateHandler);
1235    if (AnimationSpeed == 1) {
1236	tv.it_interval.tv_sec  = 1;
1237	tv.it_interval.tv_usec = 0;
1238	tv.it_value.tv_sec     = 1;
1239	tv.it_value.tv_usec    = 0;
1240    }
1241    else {
1242	tv.it_interval.tv_sec  = 0;
1243	tv.it_interval.tv_usec = 1000000 / AnimationSpeed;
1244	tv.it_value.tv_sec     = 0;
1245	tv.it_value.tv_usec    = 1000000 / AnimationSpeed;
1246    }
1247    setitimer (ITIMER_REAL, &tv, (struct itimerval*) NULL);
1248#else /* USE_SIGNALS */
1249    if (AnimationSpeed == 1) {
1250	AnimateTimeout.tv_sec  = 1;
1251	AnimateTimeout.tv_usec = 0;
1252    }
1253    else {
1254	AnimateTimeout.tv_sec  = 0;
1255	AnimateTimeout.tv_usec = 1000000 / AnimationSpeed;
1256    }
1257#endif /* USE_SIGNALS */
1258    AnimationActive = True;
1259}
1260
1261#ifdef USE_SIGNALS
1262SIGNAL_T AnimateHandler (int dummy)
1263{
1264    signal (SIGALRM, AnimateHandler);
1265    AnimationPending = True;
1266}
1267#endif
1268#endif /* VMS */
1269
1270void Animate (void)
1271{
1272    TwmWindow	*t;
1273    int		scrnum;
1274    ScreenInfo	*scr;
1275    int		i;
1276    TBWindow	*tbw;
1277    int		nb;
1278
1279    if (AnimationSpeed == 0) return;
1280#ifdef USE_SIGNALS
1281    AnimationPending = False;
1282#endif
1283
1284    MaybeAnimate = False;
1285    for (scrnum = 0; scrnum < NumScreens; scrnum++) {
1286	if ((scr = ScreenList [scrnum]) == NULL) continue;
1287
1288	for (t = scr->FirstWindow; t != NULL; t = t->next) {
1289	    if (! visible (t)) continue;
1290	    if (t->icon_on && t->icon && t->icon->bm_w && t->icon->image &&
1291		t->icon->image->next) {
1292		AnimateIcons (scr, t->icon);
1293		MaybeAnimate = True;
1294	    }
1295	    else
1296	    if (t->mapped && t->titlebuttons) {
1297		nb = scr->TBInfo.nleft + scr->TBInfo.nright;
1298		for (i = 0, tbw = t->titlebuttons; i < nb; i++, tbw++) {
1299		    if (tbw->image && tbw->image->next) {
1300			AnimateButton (tbw);
1301			MaybeAnimate = True;
1302		    }
1303		}
1304	    }
1305	}
1306	if (scr->Focus) {
1307	    t = scr->Focus;
1308	    if (t->mapped && t->titlehighlight && t->title_height &&
1309		t->HiliteImage && t->HiliteImage->next) {
1310		AnimateHighlight (t);
1311		MaybeAnimate = True;
1312	    }
1313	}
1314    }
1315    MaybeAnimate |= AnimateRoot ();
1316    XFlush (dpy);
1317    return;
1318}
1319
1320void InsertRGBColormap (Atom a, XStandardColormap *maps, int nmaps,
1321			Bool replace)
1322{
1323    StdCmap *sc = NULL;
1324
1325    if (replace) {			/* locate existing entry */
1326	for (sc = Scr->StdCmapInfo.head; sc; sc = sc->next) {
1327	    if (sc->atom == a) break;
1328	}
1329    }
1330
1331    if (!sc) {				/* no existing, allocate new */
1332	sc = (StdCmap *) malloc (sizeof (StdCmap));
1333	if (!sc) {
1334	    fprintf (stderr, "%s:  unable to allocate %lu bytes for StdCmap\n",
1335		     ProgramName, (unsigned long) sizeof(StdCmap));
1336	    return;
1337	}
1338    }
1339
1340    if (replace) {			/* just update contents */
1341	if (sc->maps) XFree ((char *) maps);
1342	if (sc == Scr->StdCmapInfo.mru) Scr->StdCmapInfo.mru = NULL;
1343    } else {				/* else appending */
1344	sc->next = NULL;
1345	sc->atom = a;
1346	if (Scr->StdCmapInfo.tail) {
1347	    Scr->StdCmapInfo.tail->next = sc;
1348	} else {
1349	    Scr->StdCmapInfo.head = sc;
1350	}
1351	Scr->StdCmapInfo.tail = sc;
1352    }
1353    sc->nmaps = nmaps;
1354    sc->maps = maps;
1355
1356    return;
1357}
1358
1359void RemoveRGBColormap (Atom a)
1360{
1361    StdCmap *sc, *prev;
1362
1363    prev = NULL;
1364    for (sc = Scr->StdCmapInfo.head; sc; sc = sc->next) {
1365	if (sc->atom == a) break;
1366	prev = sc;
1367    }
1368    if (sc) {				/* found one */
1369	if (sc->maps) XFree ((char *) sc->maps);
1370	if (prev) prev->next = sc->next;
1371	if (Scr->StdCmapInfo.head == sc) Scr->StdCmapInfo.head = sc->next;
1372	if (Scr->StdCmapInfo.tail == sc) Scr->StdCmapInfo.tail = prev;
1373	if (Scr->StdCmapInfo.mru == sc) Scr->StdCmapInfo.mru = NULL;
1374    }
1375    return;
1376}
1377
1378void LocateStandardColormaps(void)
1379{
1380    Atom *atoms;
1381    int natoms;
1382    int i;
1383
1384    atoms = XListProperties (dpy, Scr->Root, &natoms);
1385    for (i = 0; i < natoms; i++) {
1386	XStandardColormap *maps = NULL;
1387	int nmaps;
1388
1389	if (XGetRGBColormaps (dpy, Scr->Root, &maps, &nmaps, atoms[i])) {
1390	    /* if got one, then append to current list */
1391	    InsertRGBColormap (atoms[i], maps, nmaps, False);
1392	}
1393    }
1394    if (atoms) XFree ((char *) atoms);
1395    return;
1396}
1397
1398void GetColor(int kind, Pixel *what, char *name)
1399{
1400    XColor color;
1401    Colormap cmap = Scr->RootColormaps.cwins[0]->colormap->c;
1402
1403#ifndef TOM
1404    if (!Scr->FirstTime)
1405	return;
1406#endif
1407
1408    if (Scr->Monochrome != kind)
1409	return;
1410
1411    if (! XParseColor (dpy, cmap, name, &color)) {
1412	fprintf (stderr, "%s:  invalid color name \"%s\"\n", ProgramName, name);
1413	return;
1414    }
1415    if (! XAllocColor (dpy, cmap, &color))
1416    {
1417	/* if we could not allocate the color, let's see if this is a
1418	 * standard colormap
1419	 */
1420	XStandardColormap *stdcmap = NULL;
1421
1422	if (! XParseColor (dpy, cmap, name, &color)) {
1423	    fprintf (stderr, "%s:  invalid color name \"%s\"\n", ProgramName, name);
1424	    return;
1425	}
1426
1427	/*
1428	 * look through the list of standard colormaps (check cache first)
1429	 */
1430	if (Scr->StdCmapInfo.mru && Scr->StdCmapInfo.mru->maps &&
1431	    (Scr->StdCmapInfo.mru->maps[Scr->StdCmapInfo.mruindex].colormap ==
1432	     cmap)) {
1433	    stdcmap = &(Scr->StdCmapInfo.mru->maps[Scr->StdCmapInfo.mruindex]);
1434	} else {
1435	    StdCmap *sc;
1436
1437	    for (sc = Scr->StdCmapInfo.head; sc; sc = sc->next) {
1438		int i;
1439
1440		for (i = 0; i < sc->nmaps; i++) {
1441		    if (sc->maps[i].colormap == cmap) {
1442			Scr->StdCmapInfo.mru = sc;
1443			Scr->StdCmapInfo.mruindex = i;
1444			stdcmap = &(sc->maps[i]);
1445			goto gotit;
1446		    }
1447		}
1448	    }
1449	}
1450
1451      gotit:
1452	if (stdcmap) {
1453            color.pixel = (stdcmap->base_pixel +
1454			   ((Pixel)(((float)color.red / 65535.0) *
1455				    stdcmap->red_max + 0.5) *
1456			    stdcmap->red_mult) +
1457			   ((Pixel)(((float)color.green /65535.0) *
1458				    stdcmap->green_max + 0.5) *
1459			    stdcmap->green_mult) +
1460			   ((Pixel)(((float)color.blue  / 65535.0) *
1461				    stdcmap->blue_max + 0.5) *
1462			    stdcmap->blue_mult));
1463        } else {
1464	    fprintf (stderr, "%s:  unable to allocate color \"%s\"\n",
1465		     ProgramName, name);
1466	    return;
1467	}
1468    }
1469
1470    *what = color.pixel;
1471    return;
1472}
1473
1474void GetShadeColors (ColorPair *cp)
1475{
1476    XColor	xcol;
1477    Colormap	cmap = Scr->RootColormaps.cwins[0]->colormap->c;
1478    int		save;
1479    float	clearfactor;
1480    float	darkfactor;
1481    char	clearcol [32], darkcol [32];
1482
1483    clearfactor = (float) Scr->ClearShadowContrast / 100.0;
1484    darkfactor  = (100.0 - (float) Scr->DarkShadowContrast)  / 100.0;
1485    xcol.pixel = cp->back;
1486    XQueryColor (dpy, cmap, &xcol);
1487
1488    sprintf (clearcol, "#%04x%04x%04x",
1489		xcol.red   + (unsigned short) ((65535 -   xcol.red) * clearfactor),
1490		xcol.green + (unsigned short) ((65535 - xcol.green) * clearfactor),
1491		xcol.blue  + (unsigned short) ((65535 -  xcol.blue) * clearfactor));
1492    sprintf (darkcol,  "#%04x%04x%04x",
1493		(unsigned short) (xcol.red   * darkfactor),
1494		(unsigned short) (xcol.green * darkfactor),
1495		(unsigned short) (xcol.blue  * darkfactor));
1496
1497    save = Scr->FirstTime;
1498    Scr->FirstTime = True;
1499    GetColor (Scr->Monochrome, &cp->shadc, clearcol);
1500    GetColor (Scr->Monochrome, &cp->shadd,  darkcol);
1501    Scr->FirstTime = save;
1502}
1503
1504void GetFont(MyFont *font)
1505{
1506    char *deffontname = "fixed,*";
1507    char **missing_charset_list_return;
1508    int missing_charset_count_return;
1509    char *def_string_return;
1510    XFontSetExtents *font_extents;
1511    XFontStruct **xfonts;
1512    char **font_names;
1513    register int i;
1514    int ascent;
1515    int descent;
1516    int fnum;
1517    char *basename2;
1518
1519    if (font->font_set != NULL){
1520	XFreeFontSet(dpy, font->font_set);
1521    }
1522
1523    basename2 = (char *)malloc(strlen(font->basename) + 3);
1524    if (basename2) sprintf(basename2, "%s,*", font->basename);
1525    else basename2 = font->basename;
1526    if( (font->font_set = XCreateFontSet(dpy, basename2,
1527				    &missing_charset_list_return,
1528				    &missing_charset_count_return,
1529				    &def_string_return)) == NULL) {
1530	if (Scr->DefaultFont.basename) {
1531	    deffontname = Scr->DefaultFont.basename;
1532	}
1533	if ((font->font_set = XCreateFontSet(dpy, deffontname,
1534					     &missing_charset_list_return,
1535					     &missing_charset_count_return,
1536					     &def_string_return)) == NULL)
1537	{
1538	    fprintf (stderr, "%s:  unable to open fonts \"%s\" or \"%s\"\n",
1539		     ProgramName, font->basename, deffontname);
1540	    exit(1);
1541	}
1542    }
1543    if (basename2 != font->basename) free(basename2);
1544    font_extents = XExtentsOfFontSet(font->font_set);
1545
1546    fnum = XFontsOfFontSet(font->font_set, &xfonts, &font_names);
1547    for( i = 0, ascent = 0, descent = 0; i<fnum; i++){
1548	ascent = MaxSize(ascent, (*xfonts)->ascent);
1549	descent = MaxSize(descent, (*xfonts)->descent);
1550	xfonts++;
1551    }
1552
1553    font->height = font_extents->max_logical_extent.height;
1554    font->y = ascent;
1555    font->ascent = ascent;
1556    font->descent = descent;
1557}
1558
1559
1560void SetFocusVisualAttributes (TwmWindow *tmp_win, Bool focus)
1561{
1562    if (! tmp_win) return;
1563
1564    if (focus == tmp_win->hasfocusvisible) return;
1565    if (tmp_win->highlight) {
1566	if (Scr->use3Dborders) {
1567	    PaintBorders (tmp_win, focus);
1568	}
1569	else {
1570	    if (focus) {
1571		XSetWindowBorder (dpy, tmp_win->frame, tmp_win->borderC.back);
1572		if (tmp_win->title_w)
1573		    XSetWindowBorder (dpy, tmp_win->title_w, tmp_win->borderC.back);
1574	    } else {
1575		XSetWindowBorderPixmap (dpy, tmp_win->frame, tmp_win->gray);
1576		if (tmp_win->title_w)
1577		    XSetWindowBorderPixmap (dpy, tmp_win->title_w, tmp_win->gray);
1578	    }
1579	}
1580    }
1581
1582    if (focus) {
1583	Bool hil = False;
1584
1585	if (tmp_win->lolite_wl) XUnmapWindow (dpy, tmp_win->lolite_wl);
1586	if (tmp_win->lolite_wr) XUnmapWindow (dpy, tmp_win->lolite_wr);
1587	if (tmp_win->hilite_wl) {
1588	    XMapWindow (dpy, tmp_win->hilite_wl);
1589	    hil = True;
1590	}
1591	if (tmp_win->hilite_wr) {
1592	    XMapWindow (dpy, tmp_win->hilite_wr);
1593	    hil = True;
1594	}
1595	if (hil && tmp_win->HiliteImage && tmp_win->HiliteImage->next) {
1596	    MaybeAnimate = True;
1597	}
1598	if (tmp_win->iconmanagerlist)
1599	    ActiveIconManager (tmp_win->iconmanagerlist);
1600    }
1601    else {
1602	if (tmp_win->hilite_wl) XUnmapWindow (dpy, tmp_win->hilite_wl);
1603	if (tmp_win->hilite_wr) XUnmapWindow (dpy, tmp_win->hilite_wr);
1604	if (tmp_win->lolite_wl) XMapWindow (dpy, tmp_win->lolite_wl);
1605	if (tmp_win->lolite_wr) XMapWindow (dpy, tmp_win->lolite_wr);
1606	if (tmp_win->iconmanagerlist)
1607	    NotActiveIconManager (tmp_win->iconmanagerlist);
1608    }
1609    if (Scr->use3Dtitles && Scr->SunkFocusWindowTitle && tmp_win->title_height) {
1610	ButtonState bs;
1611
1612	bs = focus ? on : off;
1613	Draw3DBorder (tmp_win->title_w, Scr->TBInfo.titlex, 0,
1614			tmp_win->title_width - Scr->TBInfo.titlex -
1615			Scr->TBInfo.rightoff - Scr->TitlePadding,
1616			Scr->TitleHeight, Scr->TitleShadowDepth,
1617			tmp_win->title, bs, False, False);
1618    }
1619    tmp_win->hasfocusvisible = focus;
1620}
1621
1622static void move_to_head (TwmWindow *t)
1623{
1624    if (t == NULL) return;
1625    if (Scr->FirstWindow == t) return;
1626
1627    if (t->prev) t->prev->next = t->next;
1628    if (t->next) t->next->prev = t->prev;
1629
1630    t->next = Scr->FirstWindow;
1631    if (Scr->FirstWindow != NULL)
1632	Scr->FirstWindow->prev = t;
1633    t->prev = NULL;
1634    Scr->FirstWindow = t;
1635}
1636
1637/*
1638 * SetFocus - separate routine to set focus to make things more understandable
1639 * and easier to debug
1640 */
1641void SetFocus (TwmWindow *tmp_win, Time	tim)
1642{
1643    Window w = (tmp_win ? tmp_win->w : PointerRoot);
1644    int f_iconmgr = 0;
1645
1646    if (Scr->Focus && (Scr->Focus->iconmgr)) f_iconmgr = 1;
1647    if (Scr->SloppyFocus && (w == PointerRoot) && (!f_iconmgr)) return;
1648
1649    XSetInputFocus (dpy, w, RevertToPointerRoot, tim);
1650    if (Scr->Focus == tmp_win) return;
1651
1652    if (Scr->Focus) {
1653	if (Scr->Focus->AutoSqueeze && !Scr->Focus->squeezed) {
1654	    AutoSqueeze (Scr->Focus);
1655	}
1656	SetFocusVisualAttributes (Scr->Focus, False);
1657    }
1658    if (tmp_win)    {
1659	if (tmp_win->AutoSqueeze && tmp_win->squeezed) {
1660	    AutoSqueeze (tmp_win);
1661	}
1662	SetFocusVisualAttributes (tmp_win, True);
1663    }
1664    Scr->Focus = tmp_win;
1665    move_to_head (tmp_win);
1666}
1667
1668#
1669#ifdef NOPUTENV
1670/*
1671 * define our own putenv() if the system doesn't have one.
1672 * putenv(s): place s (a string of the form "NAME=value") in
1673 * the environment; replacing any existing NAME.  s is placed in
1674 * environment, so if you change s, the environment changes (like
1675 * putenv on a sun).  Binding removed if you putenv something else
1676 * called NAME.
1677 */
1678int
1679putenv(s)
1680    char *s;
1681{
1682    char *v;
1683    int varlen, idx;
1684    extern char **environ;
1685    char **newenv;
1686    static int virgin = 1; /* true while "environ" is a virgin */
1687
1688    v = strchr(s, '=');
1689    if(v == 0)
1690	return 0; /* punt if it's not of the right form */
1691    varlen = (v + 1) - s;
1692
1693    for (idx = 0; environ[idx] != 0; idx++) {
1694	if (strncmp(environ[idx], s, varlen) == 0) {
1695	    if(v[1] != 0) { /* true if there's a value */
1696		environ[idx] = s;
1697		return 0;
1698	    } else {
1699		do {
1700		    environ[idx] = environ[idx+1];
1701		} while(environ[++idx] != 0);
1702		return 0;
1703	    }
1704	}
1705    }
1706
1707    /* add to environment (unless no value; then just return) */
1708    if(v[1] == 0)
1709	return 0;
1710    if(virgin) {
1711	register i;
1712
1713	newenv = (char **) malloc((unsigned) ((idx + 2) * sizeof(char*)));
1714	if(newenv == 0)
1715	    return -1;
1716	for(i = idx-1; i >= 0; --i)
1717	    newenv[i] = environ[i];
1718	virgin = 0;     /* you're not a virgin anymore, sweety */
1719    } else {
1720	newenv = (char **) realloc((char *) environ,
1721				   (unsigned) ((idx + 2) * sizeof(char*)));
1722	if (newenv == 0)
1723	    return -1;
1724    }
1725
1726    environ = newenv;
1727    environ[idx] = s;
1728    environ[idx+1] = 0;
1729
1730    return 0;
1731}
1732#endif /* NOPUTENV */
1733
1734
1735static Pixmap CreateXLogoPixmap (unsigned int *widthp, unsigned int *heightp)
1736{
1737    int h = Scr->TBInfo.width - Scr->TBInfo.border * 2;
1738    if (h < 0) h = 0;
1739
1740    *widthp = *heightp = (unsigned int) h;
1741    if (Scr->tbpm.xlogo == None) {
1742	GC gc, gcBack;
1743
1744	Scr->tbpm.xlogo = XCreatePixmap (dpy, Scr->Root, h, h, 1);
1745	gc = XCreateGC (dpy, Scr->tbpm.xlogo, 0L, NULL);
1746	XSetForeground (dpy, gc, 0);
1747	XFillRectangle (dpy, Scr->tbpm.xlogo, gc, 0, 0, h, h);
1748	XSetForeground (dpy, gc, 1);
1749	gcBack = XCreateGC (dpy, Scr->tbpm.xlogo, 0L, NULL);
1750	XSetForeground (dpy, gcBack, 0);
1751
1752	/*
1753	 * draw the logo large so that it gets as dense as possible; then white
1754	 * out the edges so that they look crisp
1755	 */
1756	XmuDrawLogo (dpy, Scr->tbpm.xlogo, gc, gcBack, -1, -1, h + 2, h + 2);
1757	XDrawRectangle (dpy, Scr->tbpm.xlogo, gcBack, 0, 0, h - 1, h - 1);
1758
1759	/*
1760	 * done drawing
1761	 */
1762	XFreeGC (dpy, gc);
1763	XFreeGC (dpy, gcBack);
1764    }
1765    return Scr->tbpm.xlogo;
1766}
1767
1768
1769static Pixmap CreateResizePixmap (unsigned int *widthp, unsigned int *heightp)
1770{
1771    int h = Scr->TBInfo.width - Scr->TBInfo.border * 2;
1772    if (h < 1) h = 1;
1773
1774    *widthp = *heightp = (unsigned int) h;
1775    if (Scr->tbpm.resize == None) {
1776	XPoint	points[3];
1777	GC gc;
1778	int w;
1779	int lw;
1780
1781	/*
1782	 * create the pixmap
1783	 */
1784	Scr->tbpm.resize = XCreatePixmap (dpy, Scr->Root, h, h, 1);
1785	gc = XCreateGC (dpy, Scr->tbpm.resize, 0L, NULL);
1786	XSetForeground (dpy, gc, 0);
1787	XFillRectangle (dpy, Scr->tbpm.resize, gc, 0, 0, h, h);
1788	XSetForeground (dpy, gc, 1);
1789	lw = h / 16;
1790	if (lw == 1)
1791	    lw = 0;
1792	XSetLineAttributes (dpy, gc, lw, LineSolid, CapButt, JoinMiter);
1793
1794	/*
1795	 * draw the resize button,
1796	 */
1797	w = (h * 2) / 3;
1798	points[0].x = w;
1799	points[0].y = 0;
1800	points[1].x = w;
1801	points[1].y = w;
1802	points[2].x = 0;
1803	points[2].y = w;
1804	XDrawLines (dpy, Scr->tbpm.resize, gc, points, 3, CoordModeOrigin);
1805	w = w / 2;
1806	points[0].x = w;
1807	points[0].y = 0;
1808	points[1].x = w;
1809	points[1].y = w;
1810	points[2].x = 0;
1811	points[2].y = w;
1812	XDrawLines (dpy, Scr->tbpm.resize, gc, points, 3, CoordModeOrigin);
1813
1814	/*
1815	 * done drawing
1816	 */
1817	XFreeGC(dpy, gc);
1818    }
1819    return Scr->tbpm.resize;
1820}
1821
1822static Pixmap CreateDotPixmap (unsigned int *widthp, unsigned int *heightp)
1823{
1824    int h = Scr->TBInfo.width - Scr->TBInfo.border * 2;
1825
1826    h = h * 3 / 4;
1827    if (h < 1) h = 1;
1828    if (!(h & 1))
1829	h--;
1830    *widthp = *heightp = (unsigned int) h;
1831    if (Scr->tbpm.delete == None) {
1832	GC  gc;
1833	Pixmap pix;
1834
1835	pix = Scr->tbpm.delete = XCreatePixmap (dpy, Scr->Root, h, h, 1);
1836	gc = XCreateGC (dpy, pix, 0L, NULL);
1837	XSetLineAttributes (dpy, gc, h, LineSolid, CapRound, JoinRound);
1838	XSetForeground (dpy, gc, 0L);
1839	XFillRectangle (dpy, pix, gc, 0, 0, h, h);
1840	XSetForeground (dpy, gc, 1L);
1841	XDrawLine (dpy, pix, gc, h/2, h/2, h/2, h/2);
1842	XFreeGC (dpy, gc);
1843    }
1844    return Scr->tbpm.delete;
1845}
1846
1847static Image *Create3DCrossImage (ColorPair cp)
1848{
1849    Image *image;
1850    int        h;
1851    int    point;
1852    int midpoint;
1853
1854    h = Scr->TBInfo.width - Scr->TBInfo.border * 2;
1855    if (!(h & 1)) h--;
1856    point = 4;
1857    midpoint = h/2;
1858
1859    image = (Image*) malloc (sizeof (struct _Image));
1860    if (! image) return (None);
1861    image->pixmap = XCreatePixmap (dpy, Scr->Root, h, h, Scr->d_depth);
1862    if (image->pixmap == None) return (None);
1863
1864    Draw3DBorder (image->pixmap, 0, 0, h, h, Scr->TitleButtonShadowDepth, cp, off, True, False);
1865
1866#ifdef LEVITTE_TEST
1867    FB (cp.shadc, cp.shadd);
1868    XDrawLine (dpy, image->pixmap, Scr->NormalGC, point+1, point-1, point-1, point+1);
1869    XDrawLine (dpy, image->pixmap, Scr->NormalGC, point+1, point, point, point+1);
1870    XDrawLine (dpy, image->pixmap, Scr->NormalGC, point-1, point+1, midpoint-2, midpoint);
1871    XDrawLine (dpy, image->pixmap, Scr->NormalGC, midpoint, midpoint+2, h-point-3, h-point-1);
1872    XDrawLine (dpy, image->pixmap, Scr->NormalGC, point, point+1, h-point-3, h-point-2);
1873    XDrawLine (dpy, image->pixmap, Scr->NormalGC, point-1, h-point-2, midpoint-2, midpoint);
1874    XDrawLine (dpy, image->pixmap, Scr->NormalGC, midpoint, midpoint-2, h-point-2, point-1);
1875    XDrawLine (dpy, image->pixmap, Scr->NormalGC, point, h-point-2, h-point-2, point);
1876#endif
1877
1878    FB (cp.shadd, cp.shadc);
1879#ifdef LEVITTE_TEST
1880    XDrawLine (dpy, image->pixmap, Scr->NormalGC, point+2, point+1, h-point-1, h-point-2);
1881    XDrawLine (dpy, image->pixmap, Scr->NormalGC, point+2, point, midpoint, midpoint-2);
1882    XDrawLine (dpy, image->pixmap, Scr->NormalGC, midpoint+2, midpoint, h-point, h-point-2);
1883    XDrawLine (dpy, image->pixmap, Scr->NormalGC, h-point, h-point-2, h-point-2, h-point);
1884    XDrawLine (dpy, image->pixmap, Scr->NormalGC, h-point-1, h-point-2, h-point-2, h-point-1);
1885#else
1886    XDrawLine (dpy, image->pixmap, Scr->NormalGC, point, point, h-point-1, h-point-1);
1887    XDrawLine (dpy, image->pixmap, Scr->NormalGC, point-1, point, h-point-1, h-point);
1888    XDrawLine (dpy, image->pixmap, Scr->NormalGC, point, point-1, h-point, h-point-1);
1889#endif
1890
1891#ifdef LEVITTE_TEST
1892    XDrawLine (dpy, image->pixmap, Scr->NormalGC, point, h-point-1, point, h-point-1);
1893    XDrawLine (dpy, image->pixmap, Scr->NormalGC, h-point-1, point, h-point-1, point);
1894#else
1895    XDrawLine (dpy, image->pixmap, Scr->NormalGC, point, h-point-1, h-point-1, point);
1896#endif
1897#ifdef LEVITTE_TEST
1898    XDrawLine (dpy, image->pixmap, Scr->NormalGC, point+1, h-point-1, h-point-1, point+1);
1899    XDrawLine (dpy, image->pixmap, Scr->NormalGC, point+1, h-point, midpoint, midpoint+2);
1900    XDrawLine (dpy, image->pixmap, Scr->NormalGC, midpoint+2, midpoint, h-point, point+1);
1901#else
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, h-point, h-point, point);
1904#endif
1905
1906    image->mask   = None;
1907    image->width  = h;
1908    image->height = h;
1909    image->next   = None;
1910
1911    return (image);
1912}
1913
1914static Image *Create3DIconifyImage (ColorPair cp)
1915{
1916    Image *image;
1917    int     h;
1918    int point;
1919
1920    h = Scr->TBInfo.width - Scr->TBInfo.border * 2;
1921    if (!(h & 1)) h--;
1922    point = ((h/2-2) * 2+1) / 3;
1923
1924    image = (Image*) malloc (sizeof (struct _Image));
1925    if (! image) return (None);
1926    image->pixmap = XCreatePixmap (dpy, Scr->Root, h, h, Scr->d_depth);
1927    if (image->pixmap == None) return (None);
1928
1929    Draw3DBorder (image->pixmap, 0, 0, h, h, Scr->TitleButtonShadowDepth, cp, off, True, False);
1930    FB (cp.shadd, cp.shadc);
1931    XDrawLine (dpy, image->pixmap, Scr->NormalGC, point, point, h/2, h-point);
1932    XDrawLine (dpy, image->pixmap, Scr->NormalGC, point, point, h-point, point);
1933
1934    FB (cp.shadc, cp.shadd);
1935    XDrawLine (dpy, image->pixmap, Scr->NormalGC, h-point, point, h/2+1, h-point);
1936    XDrawLine (dpy, image->pixmap, Scr->NormalGC, h-point-1, point+1, h/2+1, h-point-1);
1937
1938    image->mask   = None;
1939    image->width  = h;
1940    image->height = h;
1941    image->next   = None;
1942
1943    return (image);
1944}
1945
1946static Image *Create3DSunkenResizeImage (ColorPair cp)
1947{
1948    int     h;
1949    Image *image;
1950
1951    h = Scr->TBInfo.width - Scr->TBInfo.border * 2;
1952    if (!(h & 1)) h--;
1953
1954    image = (Image*) malloc (sizeof (struct _Image));
1955    if (! image) return (None);
1956    image->pixmap = XCreatePixmap (dpy, Scr->Root, h, h, Scr->d_depth);
1957    if (image->pixmap == None) return (None);
1958
1959    Draw3DBorder (image->pixmap, 0, 0, h, h, Scr->TitleButtonShadowDepth, cp, off, True, False);
1960    Draw3DBorder (image->pixmap, 3, 3, h-6, h-6, 1, cp, on, True, False);
1961    Draw3DBorder (image->pixmap, 3, ((h-6)/3)+3, ((h-6)*2/3)+1,
1962     ((h-6)*2/3)+1, 1, cp, on, True, False);
1963    Draw3DBorder (image->pixmap, 3, ((h-6)*2/3)+3, ((h-6)/3)+1,
1964     ((h-6)/3)+1, 1, cp, on, True, False);
1965
1966    image->mask   = None;
1967    image->width  = h;
1968    image->height = h;
1969    image->next   = None;
1970
1971    return (image);
1972}
1973
1974static Image *Create3DBoxImage (ColorPair cp)
1975{
1976    int     h;
1977    Image   *image;
1978
1979    h = Scr->TBInfo.width - Scr->TBInfo.border * 2;
1980    if (! (h & 1)) h--;
1981
1982    image = (Image*) malloc (sizeof (struct _Image));
1983    if (! image) return (None);
1984    image->pixmap = XCreatePixmap (dpy, Scr->Root, h, h, Scr->d_depth);
1985    if (image->pixmap == None) return (None);
1986
1987    Draw3DBorder (image->pixmap, 0, 0, h, h, Scr->TitleButtonShadowDepth, cp, off, True, False);
1988    Draw3DBorder (image->pixmap, (h / 2) - 4, (h / 2) - 4, 9, 9, 1, cp,
1989     off, True, False);
1990
1991    image->mask   = None;
1992    image->width  = h;
1993    image->height = h;
1994    image->next   = None;
1995
1996    return (image);
1997}
1998
1999static Image *Create3DDotImage (ColorPair cp)
2000{
2001    Image *image;
2002    int	  h;
2003    static int idepth = 2;
2004
2005    h = Scr->TBInfo.width - Scr->TBInfo.border * 2;
2006    if (!(h & 1)) h--;
2007
2008    image = (Image*) malloc (sizeof (struct _Image));
2009    if (! image) return (None);
2010    image->pixmap = XCreatePixmap (dpy, Scr->Root, h, h, Scr->d_depth);
2011    if (image->pixmap == None) return (None);
2012
2013    Draw3DBorder (image->pixmap, 0, 0, h, h, Scr->TitleButtonShadowDepth, cp, off, True, False);
2014    Draw3DBorder (image->pixmap, (h / 2) - idepth,
2015				 (h / 2) - idepth,
2016				 2 * idepth + 1,
2017				 2 * idepth + 1,
2018				 idepth, cp, off, True, False);
2019    image->mask   = None;
2020    image->width  = h;
2021    image->height = h;
2022    image->next   = None;
2023    return (image);
2024}
2025
2026static Image *Create3DBarImage (ColorPair cp)
2027{
2028    Image *image;
2029    int	  h;
2030    static int idepth = 2;
2031
2032    h = Scr->TBInfo.width - Scr->TBInfo.border * 2;
2033    if (!(h & 1)) h--;
2034
2035    image = (Image*) malloc (sizeof (struct _Image));
2036    if (! image) return (None);
2037    image->pixmap = XCreatePixmap (dpy, Scr->Root, h, h, Scr->d_depth);
2038    if (image->pixmap == None) return (None);
2039
2040    Draw3DBorder (image->pixmap, 0, 0, h, h, Scr->TitleButtonShadowDepth, cp, off, True, False);
2041    Draw3DBorder (image->pixmap,
2042			Scr->TitleButtonShadowDepth + 2,
2043			(h / 2) - idepth,
2044			h - 2 * (Scr->TitleButtonShadowDepth + 2),
2045			2 * idepth + 1,
2046			idepth, cp, off, True, False);
2047    image->mask   = None;
2048    image->width  = h;
2049    image->height = h;
2050    image->next   = None;
2051    return (image);
2052}
2053
2054static Image *Create3DVertBarImage (ColorPair cp)
2055{
2056    Image *image;
2057    int	  h;
2058    static int idepth = 2;
2059
2060    h = Scr->TBInfo.width - Scr->TBInfo.border * 2;
2061    if (!(h & 1)) h--;
2062
2063    image = (Image*) malloc (sizeof (struct _Image));
2064    if (! image) return (None);
2065    image->pixmap = XCreatePixmap (dpy, Scr->Root, h, h, Scr->d_depth);
2066    if (image->pixmap == None) return (None);
2067
2068    Draw3DBorder (image->pixmap, 0, 0, h, h, Scr->TitleButtonShadowDepth, cp, off, True, False);
2069    Draw3DBorder (image->pixmap,
2070			(h / 2) - idepth,
2071			Scr->TitleButtonShadowDepth + 2,
2072			2 * idepth + 1,
2073			h - 2 * (Scr->TitleButtonShadowDepth + 2),
2074			idepth, cp, off, True, False);
2075    image->mask   = None;
2076    image->width  = h;
2077    image->height = h;
2078    image->next   = None;
2079    return (image);
2080}
2081
2082static Image *Create3DMenuImage (ColorPair cp)
2083{
2084    Image *image;
2085    int	  h, i;
2086
2087    h = Scr->TBInfo.width - Scr->TBInfo.border * 2;
2088    if (!(h & 1)) h--;
2089
2090    image = (Image*) malloc (sizeof (struct _Image));
2091    if (! image) return (None);
2092    image->pixmap = XCreatePixmap (dpy, Scr->Root, h, h, Scr->d_depth);
2093    if (image->pixmap == None) return (None);
2094
2095    Draw3DBorder (image->pixmap, 0, 0, h, h, Scr->TitleButtonShadowDepth, cp, off, True, False);
2096    for (i = 4; i < h - 7; i += 5) {
2097	Draw3DBorder (image->pixmap, 4, i, h - 8, 4, 2, cp, off, True, False);
2098    }
2099    image->mask   = None;
2100    image->width  = h;
2101    image->height = h;
2102    image->next   = None;
2103    return (image);
2104}
2105
2106static Image *Create3DResizeImage (ColorPair cp)
2107{
2108    Image *image;
2109    int	  h;
2110
2111    h = Scr->TBInfo.width - Scr->TBInfo.border * 2;
2112    if (!(h & 1)) h--;
2113
2114    image = (Image*) malloc (sizeof (struct _Image));
2115    if (! image) return (None);
2116    image->pixmap = XCreatePixmap (dpy, Scr->Root, h, h, Scr->d_depth);
2117    if (image->pixmap == None) return (None);
2118
2119    Draw3DBorder (image->pixmap, 0, 0, h, h, Scr->TitleButtonShadowDepth, cp, off, True, False);
2120    Draw3DBorder (image->pixmap, 0, h / 4, ((3 * h) / 4) + 1, ((3 * h) / 4) + 1, 2,
2121		cp, off, True, False);
2122    Draw3DBorder (image->pixmap, 0, h / 2, (h / 2) + 1, (h / 2) + 1, 2, cp, off, True, False);
2123    image->mask   = None;
2124    image->width  = h;
2125    image->height = h;
2126    image->next   = None;
2127    return (image);
2128}
2129
2130static Image *Create3DZoomImage (ColorPair cp)
2131{
2132    Image *image;
2133    int		h;
2134    static int idepth = 2;
2135
2136    h = Scr->TBInfo.width - Scr->TBInfo.border * 2;
2137    if (!(h & 1)) h--;
2138
2139    image = (Image*) malloc (sizeof (struct _Image));
2140    if (! image) return (None);
2141    image->pixmap = XCreatePixmap (dpy, Scr->Root, h, h, Scr->d_depth);
2142    if (image->pixmap == None) return (None);
2143
2144    Draw3DBorder (image->pixmap, 0, 0, h, h, Scr->TitleButtonShadowDepth, cp, off, True, False);
2145    Draw3DBorder (image->pixmap, Scr->TitleButtonShadowDepth + 2,
2146				 Scr->TitleButtonShadowDepth + 2,
2147				 h - 2 * (Scr->TitleButtonShadowDepth + 2),
2148				 h - 2 * (Scr->TitleButtonShadowDepth + 2),
2149				 idepth, cp, off, True, False);
2150
2151    image->mask   = None;
2152    image->width  = h;
2153    image->height = h;
2154    image->next   = None;
2155    return (image);
2156}
2157
2158struct Colori {
2159    Pixel color;
2160    Pixmap pix;
2161    struct Colori *next;
2162};
2163
2164Pixmap Create3DMenuIcon (unsigned int height,
2165			 unsigned int *widthp, unsigned int *heightp,
2166			 ColorPair cp)
2167{
2168    unsigned int h, w;
2169    int		i;
2170    struct Colori *col;
2171    static struct Colori *colori = NULL;
2172
2173    h = height;
2174    w = h * 7 / 8;
2175    if (h < 1) h = 1;
2176    if (w < 1) w = 1;
2177    *widthp  = w;
2178    *heightp = h;
2179
2180    for (col = colori; col; col = col->next) {
2181	if (col->color == cp.back) break;
2182    }
2183    if (col != NULL) {
2184	return (col->pix);
2185    }
2186    col = (struct Colori*) malloc (sizeof (struct Colori));
2187    col->color = cp.back;
2188    col->pix   = XCreatePixmap (dpy, Scr->Root, h, h, Scr->d_depth);
2189    col->next = colori;
2190    colori = col;
2191
2192    Draw3DBorder (col->pix, 0, 0, w, h, 1, cp, off, True, False);
2193    for (i = 3; i + 5 < h; i += 5) {
2194	Draw3DBorder (col->pix, 4, i, w - 8, 3, 1, Scr->MenuC, off, True, False);
2195    }
2196    return (colori->pix);
2197}
2198
2199#include "siconify.bm"
2200
2201Pixmap Create3DIconManagerIcon (ColorPair cp)
2202{
2203    unsigned int w, h;
2204    struct Colori *col;
2205    static struct Colori *colori = NULL;
2206
2207    w = (unsigned int) siconify_width;
2208    h = (unsigned int) siconify_height;
2209
2210    for (col = colori; col; col = col->next) {
2211	if (col->color == cp.back) break;
2212    }
2213    if (col != NULL) {
2214	return (col->pix);
2215    }
2216    col = (struct Colori*) malloc (sizeof (struct Colori));
2217    col->color = cp.back;
2218    col->pix   = XCreatePixmap (dpy, Scr->Root, w, h, Scr->d_depth);
2219    Draw3DBorder (col->pix, 0, 0, w, h, 4, cp, off, True, False);
2220    col->next = colori;
2221    colori = col;
2222
2223    return (colori->pix);
2224}
2225
2226static Image *Create3DResizeAnimation (Bool in, Bool left, Bool top,
2227				       ColorPair cp)
2228{
2229    int		h, i, j;
2230    Image	*image, *im, *im1;
2231
2232    h = Scr->TBInfo.width - Scr->TBInfo.border * 2;
2233    if (!(h & 1)) h--;
2234
2235    image = im1 = None;
2236    for (i = (in ? 0 : (h/4)-1); (i < h/4) && (i >= 0); i += (in ? 1 : -1)) {
2237	im = (Image*) malloc (sizeof (struct _Image));
2238	if (! im) return (None);
2239	im->pixmap = XCreatePixmap (dpy, Scr->Root, h, h, Scr->d_depth);
2240	if (im->pixmap == None) {
2241	    free (im);
2242	    return (None);
2243	}
2244	Draw3DBorder (im->pixmap, 0, 0, h, h, Scr->TitleButtonShadowDepth, cp, off, True, False);
2245	for (j = i; j <= h; j += (h/4)){
2246	    Draw3DBorder (im->pixmap, (left ? 0 : j), (top ? 0 : j),
2247			  h - j, h - j, 2, cp, off, True, False);
2248	}
2249	im->mask   = None;
2250	im->width  = h;
2251	im->height = h;
2252	im->next   = None;
2253	if (image == None) {
2254	    image = im1 = im;
2255	}
2256	else {
2257	    im1->next = im;
2258	    im1 = im;
2259	}
2260    }
2261    if (im1 != None) im1->next = image;
2262    return (image);
2263}
2264
2265static Image *Create3DResizeInTopAnimation (ColorPair cp)
2266{
2267    return Create3DResizeAnimation (TRUE, FALSE, TRUE, cp);
2268}
2269
2270static Image *Create3DResizeOutTopAnimation (ColorPair cp)
2271{
2272    return Create3DResizeAnimation (False, FALSE, TRUE, cp);
2273}
2274
2275static Image *Create3DResizeInBotAnimation (ColorPair cp)
2276{
2277    return Create3DResizeAnimation (TRUE, TRUE, FALSE, cp);
2278}
2279
2280static Image *Create3DResizeOutBotAnimation (ColorPair cp)
2281{
2282    return Create3DResizeAnimation (False, TRUE, FALSE, cp);
2283}
2284
2285static Image *Create3DMenuAnimation (Bool up, ColorPair cp)
2286{
2287    int               h, i, j;
2288    Image     *image, *im, *im1;
2289
2290    h = Scr->TBInfo.width - Scr->TBInfo.border * 2;
2291    if (!(h & 1)) h--;
2292
2293    image = im1 = None;
2294    for (j = (up ? 4 : 0); j != (up ? -1 : 5); j+= (up ? -1 : 1)) {
2295	im = (Image*) malloc (sizeof (struct _Image));
2296	if (! im) return (None);
2297	im->pixmap = XCreatePixmap (dpy, Scr->Root, h, h, Scr->d_depth);
2298	if (im->pixmap == None) {
2299	    free (im);
2300	    return (None);
2301	}
2302	Draw3DBorder (im->pixmap, 0, 0, h, h, Scr->TitleButtonShadowDepth, cp, off, True, False);
2303	for (i = j; i < h - 3; i += 5) {
2304	    Draw3DBorder (im->pixmap, 4, i, h - 8, 4, 2, cp, off, True, False);
2305	}
2306	im->mask   = None;
2307	im->width  = h;
2308	im->height = h;
2309	im->next   = None;
2310	if (image == None) {
2311	    image = im1 = im;
2312	}
2313	else {
2314	    im1->next = im;
2315	    im1 = im;
2316	}
2317    }
2318    if (im1 != None) im1->next = image;
2319    return (image);
2320}
2321
2322static Image *Create3DMenuUpAnimation (ColorPair cp)
2323{
2324    return Create3DMenuAnimation (TRUE, cp);
2325}
2326
2327static Image *Create3DMenuDownAnimation (ColorPair cp)
2328{
2329    return Create3DMenuAnimation (False, cp);
2330}
2331
2332static Image *Create3DZoomAnimation (Bool in, Bool out, int n, ColorPair cp)
2333{
2334    int		h, i, j, k;
2335    Image	*image, *im, *im1;
2336
2337    h = Scr->TBInfo.width - Scr->TBInfo.border * 2;
2338    if (!(h & 1)) h--;
2339
2340    if (n == 0) n = (h/2) - 2;
2341
2342    image = im1 = None;
2343    for (j = (out ? -1 : 1) ; j < (in ? 2 : 0); j += 2){
2344	for(k = (j > 0 ? 0 : n-1) ; (k >= 0) && (k < n); k += j){
2345	    im = (Image*) malloc (sizeof (struct _Image));
2346	    im->pixmap = XCreatePixmap (dpy, Scr->Root, h, h, Scr->d_depth);
2347	    Draw3DBorder (im->pixmap, 0, 0, h, h, Scr->TitleButtonShadowDepth, cp, off, True, False);
2348	    for (i = 2 + k; i < (h / 2); i += n) {
2349		Draw3DBorder (im->pixmap, i, i, h - (2 * i), h - (2 * i), 2, cp, off, True, False);
2350	    }
2351	    im->mask   = None;
2352	    im->width  = h;
2353	    im->height = h;
2354	    im->next   = None;
2355	    if (image == None) {
2356		image = im1 = im;
2357	    }
2358	    else {
2359		im1->next = im;
2360		im1 = im;
2361	    }
2362	}
2363    }
2364    if (im1 != None) im1->next = image;
2365    return (image);
2366}
2367
2368static Image *Create3DMazeInAnimation (ColorPair cp)
2369{
2370    return Create3DZoomAnimation(TRUE, FALSE, 6, cp);
2371}
2372
2373static Image *Create3DMazeOutAnimation (ColorPair cp)
2374{
2375    return Create3DZoomAnimation(FALSE, TRUE, 6, cp);
2376}
2377
2378static Image *Create3DZoomInAnimation (ColorPair cp)
2379{
2380    return Create3DZoomAnimation(TRUE, FALSE, 0, cp);
2381}
2382
2383static Image *Create3DZoomOutAnimation (ColorPair cp)
2384{
2385    return Create3DZoomAnimation(FALSE, TRUE, 0, cp);
2386}
2387
2388static Image *Create3DZoomInOutAnimation (ColorPair cp)
2389{
2390    return Create3DZoomAnimation(TRUE, TRUE, 0, cp);
2391}
2392
2393#define questionmark_width 8
2394#define questionmark_height 8
2395static char questionmark_bits[] = {
2396   0x38, 0x7c, 0x64, 0x30, 0x18, 0x00, 0x18, 0x18};
2397
2398static Pixmap CreateQuestionPixmap (unsigned int *widthp,
2399				    unsigned int *heightp)
2400{
2401    *widthp = questionmark_width;
2402    *heightp = questionmark_height;
2403    if (Scr->tbpm.question == None) {
2404	Scr->tbpm.question = XCreateBitmapFromData (dpy, Scr->Root,
2405						    questionmark_bits,
2406						    questionmark_width,
2407						    questionmark_height);
2408    }
2409    /*
2410     * this must succeed or else we are in deep trouble elsewhere
2411     */
2412    return Scr->tbpm.question;
2413}
2414
2415
2416static Pixmap CreateMenuPixmap (unsigned int *widthp, unsigned int *heightp)
2417{
2418    return (CreateMenuIcon (Scr->TBInfo.width - Scr->TBInfo.border * 2,widthp,heightp));
2419}
2420
2421Pixmap CreateMenuIcon (int height, unsigned int *widthp, unsigned int *heightp)
2422{
2423    int h, w;
2424    int ih, iw;
2425    int	ix, iy;
2426    int	mh, mw;
2427    int	tw, th;
2428    int	lw, lh;
2429    int	lx, ly;
2430    int	lines, dly;
2431    int offset;
2432    int	bw;
2433
2434    h = height;
2435    w = h * 7 / 8;
2436    if (h < 1)
2437	h = 1;
2438    if (w < 1)
2439	w = 1;
2440    *widthp = w;
2441    *heightp = h;
2442    if (Scr->tbpm.menu == None) {
2443	Pixmap  pix;
2444	GC	gc;
2445
2446	pix = Scr->tbpm.menu = XCreatePixmap (dpy, Scr->Root, w, h, 1);
2447	gc = XCreateGC (dpy, pix, 0L, NULL);
2448	XSetForeground (dpy, gc, 0L);
2449	XFillRectangle (dpy, pix, gc, 0, 0, w, h);
2450	XSetForeground (dpy, gc, 1L);
2451	ix = 1;
2452	iy = 1;
2453	ih = h - iy * 2;
2454	iw = w - ix * 2;
2455	offset = ih / 8;
2456	mh = ih - offset;
2457	mw = iw - offset;
2458	bw = mh / 16;
2459	if (bw == 0 && mw > 2)
2460	    bw = 1;
2461	tw = mw - bw * 2;
2462	th = mh - bw * 2;
2463	XFillRectangle (dpy, pix, gc, ix, iy, mw, mh);
2464	XFillRectangle (dpy, pix, gc, ix + iw - mw, iy + ih - mh, mw, mh);
2465	XSetForeground (dpy, gc, 0L);
2466	XFillRectangle (dpy, pix, gc, ix+bw, iy+bw, tw, th);
2467	XSetForeground (dpy, gc, 1L);
2468	lw = tw / 2;
2469	if ((tw & 1) ^ (lw & 1))
2470	    lw++;
2471	lx = ix + bw + (tw - lw) / 2;
2472
2473	lh = th / 2 - bw;
2474	if ((lh & 1) ^ ((th - bw) & 1))
2475	    lh++;
2476	ly = iy + bw + (th - bw - lh) / 2;
2477
2478	lines = 3;
2479	if ((lh & 1) && lh < 6)
2480	{
2481	    lines--;
2482	}
2483	dly = lh / (lines - 1);
2484	while (lines--)
2485	{
2486	    XFillRectangle (dpy, pix, gc, lx, ly, lw, bw);
2487	    ly += dly;
2488	}
2489	XFreeGC (dpy, gc);
2490    }
2491    return Scr->tbpm.menu;
2492}
2493
2494#define FBGC(gc, fix_fore, fix_back)\
2495    Gcv.foreground = fix_fore;\
2496    Gcv.background = fix_back;\
2497    XChangeGC(dpy, gc, GCForeground|GCBackground,&Gcv)
2498
2499void Draw3DBorder (Window w, int x, int y, int width, int height, int bw,
2500		   ColorPair cp, int state, int fill, int forcebw)
2501{
2502    int		  i;
2503    XGCValues	  gcv;
2504    unsigned long gcm;
2505
2506    if ((width < 1) || (height < 1)) return;
2507    if (Scr->Monochrome != COLOR) {
2508	if (fill) {
2509	    gcm = GCFillStyle;
2510	    gcv.fill_style = FillOpaqueStippled;
2511	    XChangeGC (dpy, Scr->BorderGC, gcm, &gcv);
2512	    XFillRectangle (dpy, w, Scr->BorderGC, x, y, width, height);
2513	}
2514	gcm  = 0;
2515	gcm |= GCLineStyle;
2516	gcv.line_style = (state == on) ? LineSolid : LineDoubleDash;
2517	gcm |= GCFillStyle;
2518	gcv.fill_style = FillSolid;
2519	XChangeGC (dpy, Scr->BorderGC, gcm, &gcv);
2520	for (i = 0; i < bw; i++) {
2521	    XDrawLine (dpy, w, Scr->BorderGC, x,                 y + i,
2522					    x + width - i - 1, y + i);
2523	    XDrawLine (dpy, w, Scr->BorderGC, x + i,                  y,
2524					    x + i, y + height - i - 1);
2525	}
2526
2527	gcm  = 0;
2528	gcm |= GCLineStyle;
2529	gcv.line_style = (state == on) ? LineDoubleDash : LineSolid;
2530	gcm |= GCFillStyle;
2531	gcv.fill_style = FillSolid;
2532	XChangeGC (dpy, Scr->BorderGC, gcm, &gcv);
2533	for (i = 0; i < bw; i++) {
2534	    XDrawLine (dpy, w, Scr->BorderGC, x + width - i - 1,          y + i,
2535					    x + width - i - 1, y + height - 1);
2536	    XDrawLine (dpy, w, Scr->BorderGC, x + i,         y + height - i - 1,
2537					    x + width - 1, y + height - i - 1);
2538	}
2539	return;
2540    }
2541
2542    if (fill) {
2543	FBGC (Scr->BorderGC, cp.back, cp.fore);
2544	XFillRectangle (dpy, w, Scr->BorderGC, x, y, width, height);
2545    }
2546    if (Scr->BeNiceToColormap) {
2547	int dashoffset = 0;
2548
2549	gcm  = 0;
2550	gcm |= GCLineStyle;
2551	gcv.line_style = (forcebw) ? LineSolid : LineDoubleDash;
2552	gcm |= GCBackground;
2553	gcv.background = cp.back;
2554	XChangeGC (dpy, Scr->BorderGC, gcm, &gcv);
2555
2556	if (state == on)
2557	    XSetForeground (dpy, Scr->BorderGC, Scr->Black);
2558	else
2559	    XSetForeground (dpy, Scr->BorderGC, Scr->White);
2560	for (i = 0; i < bw; i++) {
2561	    XDrawLine (dpy, w, Scr->BorderGC, x + i,     y + dashoffset,
2562					    x + i, y + height - i - 1);
2563	    XDrawLine (dpy, w, Scr->BorderGC, x + dashoffset,    y + i,
2564					    x + width - i - 1, y + i);
2565	    dashoffset = 1 - dashoffset;
2566	}
2567	XSetForeground (dpy, Scr->BorderGC, ((state == on) ? Scr->White : Scr->Black));
2568	for (i = 0; i < bw; i++) {
2569	    XDrawLine (dpy, w, Scr->BorderGC, x + i,         y + height - i - 1,
2570					    x + width - 1, y + height - i - 1);
2571	    XDrawLine (dpy, w, Scr->BorderGC, x + width - i - 1,          y + i,
2572					    x + width - i - 1, y + height - 1);
2573	}
2574	return;
2575    }
2576    if (state == on) { FBGC (Scr->BorderGC, cp.shadd, cp.shadc); }
2577    else             { FBGC (Scr->BorderGC, cp.shadc, cp.shadd); }
2578    for (i = 0; i < bw; i++) {
2579	XDrawLine (dpy, w, Scr->BorderGC, x,                 y + i,
2580					  x + width - i - 1, y + i);
2581	XDrawLine (dpy, w, Scr->BorderGC, x + i,                  y,
2582					  x + i, y + height - i - 1);
2583    }
2584
2585    if (state == on) { FBGC (Scr->BorderGC, cp.shadc, cp.shadd); }
2586    else             { FBGC (Scr->BorderGC, cp.shadd, cp.shadc); }
2587    for (i = 0; i < bw; i++) {
2588	XDrawLine (dpy, w, Scr->BorderGC, x + width - i - 1,          y + i,
2589					  x + width - i - 1, y + height - 1);
2590	XDrawLine (dpy, w, Scr->BorderGC, x + i,         y + height - i - 1,
2591					  x + width - 1, y + height - i - 1);
2592    }
2593    return;
2594}
2595
2596void Draw3DCorner (Window w,
2597		   int x, int y, int width, int height, int thick, int bw,
2598		   ColorPair cp, int type)
2599{
2600    XRectangle rects [2];
2601
2602    switch (type) {
2603	case 0 :
2604	    Draw3DBorder (w, x, y, width, height, bw, cp, off, True, False);
2605	    Draw3DBorder (w, x + thick - bw, y + thick - bw,
2606			width - thick + 2 * bw, height - thick + 2 * bw,
2607			bw, cp, on, True, False);
2608	    break;
2609	case 1 :
2610	    Draw3DBorder (w, x, y, width, height, bw, cp, off, True, False);
2611	    Draw3DBorder (w, x, y + thick - bw,
2612			width - thick + bw, height - thick,
2613			bw, cp, on, True, False);
2614	    break;
2615	case 2 :
2616	    rects [0].x      = x + width - thick;
2617	    rects [0].y      = y;
2618	    rects [0].width  = thick;
2619	    rects [0].height = height;
2620	    rects [1].x      = x;
2621	    rects [1].y      = y + width - thick;
2622	    rects [1].width  = width - thick;
2623	    rects [1].height = thick;
2624	    XSetClipRectangles (dpy, Scr->BorderGC, 0, 0, rects, 2, Unsorted);
2625	    Draw3DBorder (w, x, y, width, height, bw, cp, off, True, False);
2626	    Draw3DBorder (w, x, y,
2627			width - thick + bw, height - thick + bw,
2628			bw, cp, on, True, False);
2629	    XSetClipMask (dpy, Scr->BorderGC, None);
2630	    break;
2631	case 3 :
2632	    rects [0].x      = x;
2633	    rects [0].y      = y;
2634	    rects [0].width  = thick;
2635	    rects [0].height = height;
2636	    rects [1].x      = x + thick;
2637	    rects [1].y      = y + height - thick;
2638	    rects [1].width  = width - thick;
2639	    rects [1].height = thick;
2640	    XSetClipRectangles (dpy, Scr->BorderGC, 0, 0, rects, 2, Unsorted);
2641	    Draw3DBorder (w, x, y, width, height, bw, cp, off, True, False);
2642	    Draw3DBorder (w, x + thick - bw, y,
2643			width - thick, height - thick + bw,
2644			bw, cp, on, True, False);
2645	    XSetClipMask (dpy, Scr->BorderGC, None);
2646	    break;
2647    }
2648    return;
2649}
2650
2651void PaintAllDecoration (void)
2652{
2653    TwmWindow *tmp_win;
2654    virtualScreen *vs;
2655
2656    for (tmp_win = Scr->FirstWindow; tmp_win != NULL; tmp_win = tmp_win->next) {
2657	if (! visible (tmp_win)) continue;
2658	if (tmp_win->mapped == TRUE) {
2659	    if (tmp_win->frame_bw3D) {
2660		if (tmp_win->highlight && tmp_win == Scr->Focus)
2661		    PaintBorders (tmp_win, True);
2662		else
2663		    PaintBorders (tmp_win, False);
2664	    }
2665	    if (tmp_win->title_w)      PaintTitle        (tmp_win);
2666	    if (tmp_win->titlebuttons) PaintTitleButtons (tmp_win);
2667	}
2668	else
2669	if ((tmp_win->icon_on == TRUE)  &&
2670		!tmp_win->icon_not_ours &&
2671		!Scr->NoIconTitlebar    &&
2672		tmp_win->icon           &&
2673		tmp_win->icon->w        &&
2674		! LookInList (Scr->NoIconTitle, tmp_win->full_name, &tmp_win->class)) {
2675	    PaintIcon (tmp_win);
2676	}
2677    }
2678    for (vs = Scr->vScreenList; vs != NULL; vs = vs->next) {
2679      PaintWorkSpaceManager (vs);
2680    }
2681}
2682
2683void PaintBorders (TwmWindow *tmp_win, Bool focus)
2684{
2685    ColorPair cp;
2686
2687    cp = (focus && tmp_win->highlight) ? tmp_win->borderC : tmp_win->border_tile;
2688    if (tmp_win->title_height == 0) {
2689	Draw3DBorder (tmp_win->frame,
2690	    0,
2691	    0,
2692	    tmp_win->frame_width,
2693	    tmp_win->frame_height,
2694	    Scr->BorderShadowDepth, cp, off, True, False);
2695	Draw3DBorder (tmp_win->frame,
2696	    tmp_win->frame_bw3D - Scr->BorderShadowDepth,
2697	    tmp_win->frame_bw3D - Scr->BorderShadowDepth,
2698	    tmp_win->frame_width  - 2 * tmp_win->frame_bw3D + 2 * Scr->BorderShadowDepth,
2699	    tmp_win->frame_height - 2 * tmp_win->frame_bw3D + 2 * Scr->BorderShadowDepth,
2700	    Scr->BorderShadowDepth, cp, on, True, False);
2701	return;
2702    }
2703    Draw3DCorner (tmp_win->frame,
2704		tmp_win->title_x - tmp_win->frame_bw3D,
2705		0,
2706		Scr->TitleHeight + tmp_win->frame_bw3D,
2707		Scr->TitleHeight + tmp_win->frame_bw3D,
2708		tmp_win->frame_bw3D, Scr->BorderShadowDepth, cp, 0);
2709    Draw3DCorner (tmp_win->frame,
2710		tmp_win->title_x + tmp_win->title_width - Scr->TitleHeight,
2711		0,
2712		Scr->TitleHeight + tmp_win->frame_bw3D,
2713		Scr->TitleHeight + tmp_win->frame_bw3D,
2714		tmp_win->frame_bw3D, Scr->BorderShadowDepth, cp, 1);
2715    Draw3DCorner (tmp_win->frame,
2716		tmp_win->frame_width  - (Scr->TitleHeight + tmp_win->frame_bw3D),
2717		tmp_win->frame_height - (Scr->TitleHeight + tmp_win->frame_bw3D),
2718		Scr->TitleHeight + tmp_win->frame_bw3D,
2719		Scr->TitleHeight + tmp_win->frame_bw3D,
2720		tmp_win->frame_bw3D, Scr->BorderShadowDepth, cp, 2);
2721    Draw3DCorner (tmp_win->frame,
2722		0,
2723		tmp_win->frame_height - (Scr->TitleHeight + tmp_win->frame_bw3D),
2724		Scr->TitleHeight + tmp_win->frame_bw3D,
2725		Scr->TitleHeight + tmp_win->frame_bw3D,
2726		tmp_win->frame_bw3D, Scr->BorderShadowDepth, cp, 3);
2727
2728    Draw3DBorder (tmp_win->frame,
2729		tmp_win->title_x + Scr->TitleHeight,
2730		0,
2731		tmp_win->title_width - 2 * Scr->TitleHeight,
2732		tmp_win->frame_bw3D,
2733		Scr->BorderShadowDepth, cp, off, True, False);
2734    Draw3DBorder (tmp_win->frame,
2735		tmp_win->frame_bw3D + Scr->TitleHeight,
2736		tmp_win->frame_height - tmp_win->frame_bw3D,
2737		tmp_win->frame_width - 2 * (Scr->TitleHeight + tmp_win->frame_bw3D),
2738		tmp_win->frame_bw3D,
2739		Scr->BorderShadowDepth, cp, off, True, False);
2740    Draw3DBorder (tmp_win->frame,
2741		0,
2742		Scr->TitleHeight + tmp_win->frame_bw3D,
2743		tmp_win->frame_bw3D,
2744		tmp_win->frame_height - 2 * (Scr->TitleHeight + tmp_win->frame_bw3D),
2745		Scr->BorderShadowDepth, cp, off, True, False);
2746    Draw3DBorder (tmp_win->frame,
2747		tmp_win->frame_width  - tmp_win->frame_bw3D,
2748		Scr->TitleHeight + tmp_win->frame_bw3D,
2749		tmp_win->frame_bw3D,
2750		tmp_win->frame_height - 2 * (Scr->TitleHeight + tmp_win->frame_bw3D),
2751		Scr->BorderShadowDepth, cp, off, True, False);
2752
2753    if (tmp_win->squeeze_info && !tmp_win->squeezed) {
2754	Draw3DBorder (tmp_win->frame,
2755		0,
2756		Scr->TitleHeight,
2757		tmp_win->title_x,
2758		tmp_win->frame_bw3D,
2759		Scr->BorderShadowDepth, cp, off, True, False);
2760	Draw3DBorder (tmp_win->frame,
2761		tmp_win->title_x + tmp_win->title_width,
2762		Scr->TitleHeight,
2763		tmp_win->frame_width - tmp_win->title_x - tmp_win->title_width,
2764		tmp_win->frame_bw3D,
2765		Scr->BorderShadowDepth, cp, off, True, False);
2766    }
2767}
2768
2769void PaintTitle (TwmWindow *tmp_win)
2770{
2771    int width, mwidth, len;
2772    XRectangle inc_rect;
2773    XRectangle logical_rect;
2774
2775    if (Scr->use3Dtitles) {
2776	if (Scr->SunkFocusWindowTitle && (Scr->Focus == tmp_win) &&
2777	    (tmp_win->title_height != 0))
2778	    Draw3DBorder (tmp_win->title_w, Scr->TBInfo.titlex, 0,
2779		tmp_win->title_width - Scr->TBInfo.titlex -
2780		Scr->TBInfo.rightoff - Scr->TitlePadding,
2781		Scr->TitleHeight, Scr->TitleShadowDepth,
2782		tmp_win->title, on, True, False);
2783	else
2784	    Draw3DBorder (tmp_win->title_w, Scr->TBInfo.titlex, 0,
2785		tmp_win->title_width - Scr->TBInfo.titlex -
2786		Scr->TBInfo.rightoff - Scr->TitlePadding,
2787		Scr->TitleHeight, Scr->TitleShadowDepth,
2788		tmp_win->title, off, True, False);
2789    }
2790    FB(tmp_win->title.fore, tmp_win->title.back);
2791    if (Scr->use3Dtitles) {
2792	len    = strlen(tmp_win->name);
2793	XmbTextExtents(Scr->TitleBarFont.font_set,
2794		       tmp_win->name, strlen (tmp_win->name),
2795		       &inc_rect, &logical_rect);
2796	width = logical_rect.width;
2797	mwidth = tmp_win->title_width  - Scr->TBInfo.titlex -
2798		 Scr->TBInfo.rightoff  - Scr->TitlePadding  -
2799		 Scr->TitleShadowDepth - 4;
2800	while ((len > 0) && (width > mwidth)) {
2801	    len--;
2802	    XmbTextExtents(Scr->TitleBarFont.font_set,
2803			   tmp_win->name, len,
2804			   &inc_rect, &logical_rect);
2805	    width = logical_rect.width;
2806	}
2807	if (Scr->Monochrome != COLOR) {
2808	    XmbDrawImageString(dpy, tmp_win->title_w, Scr->TitleBarFont.font_set,
2809			     Scr->NormalGC,
2810			     tmp_win->name_x,
2811			     Scr->TitleBarFont.y + Scr->TitleShadowDepth,
2812			     tmp_win->name, len);
2813	}
2814	else {
2815	    XmbDrawString (dpy, tmp_win->title_w, Scr->TitleBarFont.font_set,
2816			   Scr->NormalGC, tmp_win->name_x,
2817			   Scr->TitleBarFont.y + Scr->TitleShadowDepth,
2818			   tmp_win->name, len);
2819	}
2820    }
2821    else
2822        XmbDrawString (dpy, tmp_win->title_w, Scr->TitleBarFont.font_set,
2823		       Scr->NormalGC,
2824		       tmp_win->name_x, Scr->TitleBarFont.y,
2825		       tmp_win->name, strlen(tmp_win->name));
2826}
2827
2828void PaintIcon (TwmWindow *tmp_win)
2829{
2830    int		width, twidth, mwidth, len, x;
2831    Icon	*icon;
2832    XRectangle inc_rect;
2833    XRectangle logical_rect;
2834
2835    if (!tmp_win || !tmp_win->icon) return;
2836    icon = tmp_win->icon;
2837    if (!icon->has_title) return;
2838
2839    x     = 0;
2840    width = icon->w_width;
2841    if (Scr->ShrinkIconTitles && icon->title_shrunk) {
2842	x     = GetIconOffset (icon);
2843	width = icon->width;
2844    }
2845    len    = strlen (tmp_win->icon_name);
2846    XmbTextExtents(Scr->IconFont.font_set,
2847		   tmp_win->icon_name, len,
2848		   &inc_rect, &logical_rect);
2849    twidth = logical_rect.width;
2850    mwidth = width - 2 * Scr->IconManagerShadowDepth - 6;
2851    if (Scr->use3Diconmanagers) {
2852	Draw3DBorder (icon->w, x, icon->height, width,
2853		Scr->IconFont.height + 2 * Scr->IconManagerShadowDepth + 6,
2854		Scr->IconManagerShadowDepth, icon->iconc, off, False, False);
2855    }
2856    while ((len > 0) && (twidth > mwidth)) {
2857	len--;
2858	XmbTextExtents(Scr->IconFont.font_set,
2859		       tmp_win->icon_name, len,
2860		       &inc_rect, &logical_rect);
2861	twidth = logical_rect.width;
2862    }
2863    FB (icon->iconc.fore, icon->iconc.back);
2864    XmbDrawString(dpy, icon->w, Scr->IconFont.font_set, Scr->NormalGC,
2865		  x + ((mwidth - twidth)/2) + Scr->IconManagerShadowDepth + 3,
2866		  icon->y, tmp_win->icon_name, len);
2867}
2868
2869void PaintTitleButton (TwmWindow *tmp_win, TBWindow  *tbw)
2870{
2871    TitleButton *tb = tbw->info;
2872
2873    XCopyArea (dpy, tbw->image->pixmap, tbw->window, Scr->NormalGC,
2874		tb->srcx, tb->srcy, tb->width, tb->height,
2875		tb->dstx, tb->dsty);
2876    return;
2877}
2878
2879void PaintTitleButtons (TwmWindow *tmp_win)
2880{
2881    int i;
2882    TBWindow *tbw;
2883    int nb = Scr->TBInfo.nleft + Scr->TBInfo.nright;
2884
2885    for (i = 0, tbw = tmp_win->titlebuttons; i < nb; i++, tbw++) {
2886	if (tbw) PaintTitleButton (tmp_win, tbw);
2887    }
2888}
2889
2890void adoptWindow (void)
2891{
2892    unsigned long	data [2];
2893    Window		localroot, w;
2894    unsigned char	*prop;
2895    unsigned long	bytesafter;
2896    unsigned long	len;
2897    Atom		actual_type;
2898    int			actual_format;
2899    XEvent		event;
2900    Window		root, parent, child, *children;
2901    unsigned int	nchildren, key_buttons;
2902    int			root_x, root_y, win_x, win_y;
2903    int			ret;
2904
2905    localroot = w = RootWindow (dpy, Scr->screen);
2906    XGrabPointer (dpy, localroot, False,
2907			ButtonPressMask | ButtonReleaseMask,
2908			GrabModeAsync, GrabModeAsync,
2909		        None, Scr->SelectCursor, CurrentTime);
2910
2911    XMaskEvent (dpy, ButtonPressMask | ButtonReleaseMask, &event);
2912    child = event.xbutton.subwindow;
2913    while (1) {
2914	if (child == (Window) 0) break;
2915
2916	w = XmuClientWindow (dpy, child);
2917	ret = XGetWindowProperty (dpy, w, _XA_WM_WORKSPACESLIST, 0L, 512,
2918			False, XA_STRING, &actual_type, &actual_format, &len,
2919			&bytesafter, &prop);
2920	XFree ((char *)prop); /* Don't ever do anything with it */
2921	if (ret != Success)
2922		break;
2923	if (len == 0) /* it is not a local root window */
2924		break; /* it is not a local root window */
2925	localroot = w;
2926	XQueryPointer (dpy, localroot, &root, &child, &root_x, &root_y,
2927					&win_x, &win_y, &key_buttons);
2928    }
2929    XMaskEvent (dpy, ButtonPressMask | ButtonReleaseMask, &event);
2930    XUngrabPointer (dpy, CurrentTime);
2931
2932    if (localroot == Scr->Root) return;
2933    if (w == localroot) {  /* try to not adopt an ancestor */
2934	XQueryTree (dpy, Scr->Root, &root, &parent, &children, &nchildren);
2935	while (parent != (Window) 0) {
2936	    XFree ((char *) children);
2937	    if (w == parent) return;
2938	    XQueryTree (dpy, parent, &root, &parent, &children, &nchildren);
2939	}
2940	XFree ((char *) children);
2941	if (w == root) return;
2942    }
2943    if (localroot == RootWindow (dpy, Scr->screen)) {
2944	XWithdrawWindow (dpy, w, Scr->screen);
2945    }
2946    else {
2947	XUnmapWindow (dpy, w);
2948    }
2949    XReparentWindow (dpy, w, Scr->Root, 0, 0);
2950
2951    data [0] = (unsigned long) NormalState;
2952    data [1] = (unsigned long) None;
2953
2954    XChangeProperty (dpy, w, _XA_WM_STATE, _XA_WM_STATE, 32,
2955			PropModeReplace, (unsigned char *) data, 2);
2956    XFlush (dpy);
2957    SimulateMapRequest (w);
2958    return;
2959}
2960
2961void DebugTrace (char *file)
2962{
2963    if (!file) return;
2964    if (tracefile) {
2965	fprintf (stderr, "stop logging events\n");
2966	if (tracefile != stderr) fclose (tracefile);
2967	tracefile = NULL;
2968    }
2969    else {
2970	if (strcmp (file, "stderr"))
2971	    tracefile = fopen (file, "w");
2972	else
2973	    tracefile = stderr;
2974	fprintf (stderr, "logging events to : %s\n", file);
2975    }
2976}
2977
2978extern Cursor	TopRightCursor, TopLeftCursor, BottomRightCursor, BottomLeftCursor,
2979		LeftCursor, RightCursor, TopCursor, BottomCursor;
2980
2981void SetBorderCursor (TwmWindow *tmp_win, int x, int y)
2982{
2983    Cursor cursor;
2984    XSetWindowAttributes attr;
2985    int h, fw, fh, wd;
2986
2987    if (!tmp_win)
2988	return;
2989
2990    /* Use the max of these, but since one is always 0 we can add them. */
2991    wd = tmp_win->frame_bw + tmp_win->frame_bw3D;
2992    h = Scr->TitleHeight + wd;
2993    fw = tmp_win->frame_width;
2994    fh = tmp_win->frame_height;
2995
2996#if defined DEBUG && DEBUG
2997    fprintf(stderr, "wd=%d h=%d, fw=%d fh=%d x=%d y=%d\n",
2998	    wd, h, fw, fh, x, y);
2999#endif
3000
3001    /*
3002     * If not using 3D borders:
3003     *
3004     * The left border has negative x coordinates,
3005     * The top border (above the title) has negative y coordinates.
3006     * The title is TitleHeight high, the next wd pixels are border.
3007     * The bottom border has coordinates >= the frame height.
3008     * The right border has coordinates >= the frame width.
3009     *
3010     * If using 3D borders: all coordinates are >= 0, and all coordinates
3011     * are higher by the border width.
3012     *
3013     * Since we only get events when we're actually in the border, we simply
3014     * allow for both cases at the same time.
3015     */
3016
3017    if ((x < -wd) || (y < -wd)) {
3018	cursor = Scr->FrameCursor;
3019    } else if (x < h) {
3020	if (y < h)
3021	    cursor = TopLeftCursor;
3022	else if (y >= fh - h)
3023	    cursor = BottomLeftCursor;
3024	else
3025	    cursor = LeftCursor;
3026    } else if (x >= fw - h) {
3027	if (y < h)
3028	    cursor = TopRightCursor;
3029	else if (y >= fh - h)
3030	    cursor = BottomRightCursor;
3031	else
3032	    cursor = RightCursor;
3033    } else if (y < h) {	/* also include title bar in top border area */
3034	cursor = TopCursor;
3035    } else if (y >= fh - h) {
3036	cursor = BottomCursor;
3037    } else {
3038	cursor = Scr->FrameCursor;
3039    }
3040    attr.cursor = cursor;
3041    XChangeWindowAttributes (dpy, tmp_win->frame, CWCursor, &attr);
3042    tmp_win->curcurs = cursor;
3043}
3044
3045Image *GetImage (char *name, ColorPair cp)
3046{
3047    name_list **list;
3048    char fullname [256];
3049    Image *image;
3050
3051    if (name == NULL) return (None);
3052    image = None;
3053
3054    list = &Scr->ImageCache;
3055#ifdef XPM
3056    if ((name [0] == '@') || (strncmp (name, "xpm:", 4) == 0)) {
3057	sprintf (fullname, "%s%dx%d", name, (int) cp.fore, (int) cp.back);
3058
3059	if ((image = (Image*) LookInNameList (*list, fullname)) == None) {
3060	    int startn = (name [0] == '@') ? 1 : 4;
3061	    if ((image = GetXpmImage (name + startn, cp)) != None) {
3062	        AddToList (list, fullname, (char*) image);
3063	    }
3064	}
3065    }
3066    else
3067#endif
3068#ifdef JPEG
3069    if (strncmp (name, "jpeg:", 5) == 0) {
3070	if ((image = (Image*) LookInNameList (*list, name)) == None) {
3071	    if ((image = GetJpegImage (&name [5])) != None) {
3072		AddToList (list, name, (char*) image);
3073	    }
3074	}
3075    }
3076    else
3077#endif
3078#ifdef IMCONV
3079    if (strncmp (name, "im:", 3) == 0) {
3080	if ((image = (Image*) LookInNameList (*list, name)) == None) {
3081	    if ((image = GetImconvImage (&name [3])) != None) {
3082		AddToList (list, name, (char*) image);
3083	    }
3084	}
3085    }
3086    else
3087#endif
3088#if !defined(VMS) || defined(HAVE_XWDFILE_H)
3089    if ((strncmp (name, "xwd:", 4) == 0) || (name [0] == '|')) {
3090	int startn = (name [0] == '|') ? 0 : 4;
3091	if ((image = (Image*) LookInNameList (*list, name)) == None) {
3092	    if ((image = GetXwdImage (&name [startn], cp)) != None) {
3093		AddToList (list, name, (char*) image);
3094	    }
3095	}
3096    }
3097    else
3098#endif
3099    if (strncmp (name, ":xpm:", 5) == 0) {
3100	int    i;
3101	static struct {
3102	    char *name;
3103	    Image* (*proc)(ColorPair colorpair);
3104	} pmtab[] = {
3105	    { TBPM_3DDOT,	Create3DDotImage },
3106	    { TBPM_3DRESIZE,	Create3DResizeImage },
3107	    { TBPM_3DMENU,	Create3DMenuImage },
3108	    { TBPM_3DZOOM,	Create3DZoomImage },
3109	    { TBPM_3DBAR,	Create3DBarImage },
3110	    { TBPM_3DVBAR,	Create3DVertBarImage },
3111	    { TBPM_3DCROSS,     Create3DCrossImage },
3112	    { TBPM_3DICONIFY,   Create3DIconifyImage },
3113	    { TBPM_3DSUNKEN_RESIZE,     Create3DSunkenResizeImage },
3114	    { TBPM_3DBOX,       Create3DBoxImage }
3115	};
3116
3117	sprintf (fullname, "%s%dx%d", name, (int) cp.fore, (int) cp.back);
3118	if ((image = (Image*) LookInNameList (*list, fullname)) == None) {
3119	    for (i = 0; i < (sizeof pmtab) / (sizeof pmtab[0]); i++) {
3120		if (XmuCompareISOLatin1 (pmtab[i].name, name) == 0) {
3121		    image = (*pmtab[i].proc) (cp);
3122		    if (image == None) {
3123			fprintf (stderr,
3124			    "%s:  unable to build pixmap \"%s\"\n", ProgramName, name);
3125			return (None);
3126		    }
3127		    break;
3128		}
3129	    }
3130	    if (image == None) {
3131		fprintf (stderr, "%s:  no such built-in pixmap \"%s\"\n", ProgramName, name);
3132		return (None);
3133	    }
3134	    AddToList (list, fullname, (char*) image);
3135	}
3136    }
3137    else
3138    if (strncmp (name, "%xpm:", 5) == 0) {
3139	int    i;
3140	static struct {
3141	    char *name;
3142	    Image* (*proc)(ColorPair colorpair);
3143	} pmtab[] = {
3144	    { "%xpm:menu-up", Create3DMenuUpAnimation },
3145	    { "%xpm:menu-down", Create3DMenuDownAnimation },
3146	    { "%xpm:resize", Create3DZoomOutAnimation }, /* compatibility */
3147	    { "%xpm:resize-out-top", Create3DResizeInTopAnimation },
3148	    { "%xpm:resize-in-top", Create3DResizeOutTopAnimation },
3149	    { "%xpm:resize-out-bot", Create3DResizeInBotAnimation },
3150	    { "%xpm:resize-in-bot", Create3DResizeOutBotAnimation },
3151	    { "%xpm:maze-out", Create3DMazeOutAnimation },
3152	    { "%xpm:maze-in", Create3DMazeInAnimation },
3153	    { "%xpm:zoom-out", Create3DZoomOutAnimation },
3154	    { "%xpm:zoom-in", Create3DZoomInAnimation },
3155	    { "%xpm:zoom-inout", Create3DZoomInOutAnimation }
3156	};
3157
3158	sprintf (fullname, "%s%dx%d", name, (int) cp.fore, (int) cp.back);
3159	if ((image = (Image*) LookInNameList (*list, fullname)) == None) {
3160	    for (i = 0; i < (sizeof pmtab) / (sizeof pmtab[0]); i++) {
3161		if (XmuCompareISOLatin1 (pmtab[i].name, name) == 0) {
3162		    image = (*pmtab[i].proc) (cp);
3163		    if (image == None) {
3164			fprintf (stderr,
3165			    "%s:  unable to build pixmap \"%s\"\n", ProgramName, name);
3166			return (None);
3167		    }
3168		    break;
3169		}
3170	    }
3171	    if (image == None) {
3172		fprintf (stderr, "%s:  no such built-in pixmap \"%s\"\n", ProgramName, name);
3173		return (None);
3174	    }
3175	    AddToList (list, fullname, (char*) image);
3176	}
3177    }
3178    else
3179    if (name [0] == ':') {
3180	int		i;
3181	unsigned int	width, height;
3182	Pixmap		pm = 0;
3183	XGCValues	gcvalues;
3184	static struct {
3185	    char *name;
3186	    Pixmap (*proc)(unsigned int *widthp, unsigned int *heightp);
3187	} pmtab[] = {
3188	    { TBPM_DOT,		CreateDotPixmap },
3189	    { TBPM_ICONIFY,	CreateDotPixmap },
3190	    { TBPM_RESIZE,	CreateResizePixmap },
3191	    { TBPM_XLOGO,	CreateXLogoPixmap },
3192	    { TBPM_DELETE,	CreateXLogoPixmap },
3193	    { TBPM_MENU,	CreateMenuPixmap },
3194	    { TBPM_QUESTION,	CreateQuestionPixmap },
3195	};
3196
3197	sprintf (fullname, "%s%dx%d", name, (int) cp.fore, (int) cp.back);
3198	if ((image = (Image*) LookInNameList (*list, fullname)) == None) {
3199	    for (i = 0; i < (sizeof pmtab) / (sizeof pmtab[0]); i++) {
3200		if (XmuCompareISOLatin1 (pmtab[i].name, name) == 0) {
3201		    pm = (*pmtab[i].proc) (&width, &height);
3202		    if (pm == None) {
3203			fprintf (stderr,
3204			    "%s:  unable to build pixmap \"%s\"\n", ProgramName, name);
3205			return (None);
3206		    }
3207		    break;
3208		}
3209	    }
3210	    if (pm == None) {
3211		fprintf (stderr, "%s:  no such built-in bitmap \"%s\"\n", ProgramName, name);
3212		return (None);
3213	    }
3214	    image = (Image*) malloc (sizeof (struct _Image));
3215	    image->pixmap = XCreatePixmap (dpy, Scr->Root, width, height, Scr->d_depth);
3216	    if (Scr->rootGC == (GC) 0) Scr->rootGC = XCreateGC (dpy, Scr->Root, 0, &gcvalues);
3217	    gcvalues.background = cp.back;
3218	    gcvalues.foreground = cp.fore;
3219	    XChangeGC   (dpy, Scr->rootGC, GCForeground | GCBackground, &gcvalues);
3220	    XCopyPlane  (dpy, pm, image->pixmap, Scr->rootGC, 0, 0, width, height, 0, 0,
3221			(unsigned long) 1);
3222	    image->mask   = None;
3223	    image->width  = width;
3224	    image->height = height;
3225	    image->next   = None;
3226	    AddToList (list, fullname, (char*) image);
3227	}
3228    }
3229    else {
3230	sprintf (fullname, "%s%dx%d", name, (int) cp.fore, (int) cp.back);
3231	if ((image = (Image*) LookInNameList (*list, fullname)) == None) {
3232	    if ((image = GetBitmapImage (name, cp)) != None) {
3233		AddToList (list, fullname, (char*) image);
3234	    }
3235	}
3236    }
3237    return (image);
3238}
3239
3240void FreeImage (Image *image)
3241{
3242    Image *im, *im2;
3243
3244    im = image;
3245    while (im != None) {
3246	if (im->pixmap) XFreePixmap (dpy, im->pixmap);
3247	if (im->mask)   XFreePixmap (dpy, im->mask);
3248	im2 = im->next;
3249	free (im);
3250	im = im2;
3251    }
3252}
3253
3254#if !defined(VMS) || defined(HAVE_XWDFILE_H)
3255static void compress (XImage *image, XColor *colors, int *ncolors);
3256
3257static Image *LoadXwdImage (char *filename, ColorPair cp)
3258{
3259    FILE	*file;
3260    char	*fullname;
3261    XColor	colors [256];
3262    XWDColor	xwdcolors [256];
3263    unsigned	buffer_size;
3264    XImage	*image;
3265    unsigned char *imagedata;
3266    Pixmap	pixret;
3267    Visual	*visual;
3268    char	win_name [256];
3269    int		win_name_size;
3270    int		ispipe;
3271    int		i, len;
3272    int		w, h, depth, ncolors;
3273    int		scrn;
3274    Colormap	cmap;
3275    Colormap	stdcmap = Scr->RootColormaps.cwins[0]->colormap->c;
3276    GC		gc;
3277    XGCValues   gcvalues;
3278    XWDFileHeader header;
3279    Image	*ret;
3280    Bool	anim;
3281    unsigned long swaptest = 1;
3282
3283    ispipe = 0;
3284    anim   = False;
3285#ifndef VMS
3286    if (filename [0] == '|') {
3287	file = (FILE*) popen (filename + 1, "r");
3288	if (file == NULL) return (None);
3289	ispipe = 1;
3290	anim = AnimationActive;
3291	if (anim) StopAnimation ();
3292	goto file_opened;
3293    }
3294#endif
3295    fullname = ExpandPixmapPath (filename);
3296    if (! fullname) return (None);
3297    file = fopen (fullname, "r");
3298    free (fullname);
3299    if (file == NULL) {
3300	if (reportfilenotfound) fprintf (stderr, "unable to locate %s\n", filename);
3301        return (None);
3302    }
3303file_opened:
3304    len = fread ((char *) &header, sizeof (header), 1, file);
3305    if (len != 1) {
3306	fprintf (stderr, "ctwm: cannot read %s\n", filename);
3307#ifdef USE_SIGNALS
3308	if (ispipe && anim) StartAnimation ();
3309#endif
3310	return (None);
3311    }
3312    if (*(char *) &swaptest) _swaplong ((char *) &header, sizeof (header));
3313    if (header.file_version != XWD_FILE_VERSION) {
3314	fprintf(stderr,"ctwm: XWD file format version mismatch : %s\n", filename);
3315	return (None);
3316    }
3317    win_name_size = header.header_size - sizeof (header);
3318    len = fread (win_name, win_name_size, 1, file);
3319    if (len != 1) {
3320	fprintf (stderr, "file %s has not the correct format\n", filename);
3321#ifdef USE_SIGNALS
3322	if (ispipe && anim) StartAnimation ();
3323#endif
3324	return (None);
3325    }
3326
3327    if (header.pixmap_format == XYPixmap) {
3328	fprintf (stderr,"ctwm: XYPixmap XWD file not supported : %s\n", filename);
3329	return (None);
3330    }
3331    w       = header.pixmap_width;
3332    h       = header.pixmap_height;
3333    depth   = header.pixmap_depth;
3334    ncolors = header.ncolors;
3335    len = fread ((char *) xwdcolors, sizeof (XWDColor), ncolors, file);
3336    if (len != ncolors) {
3337	fprintf (stderr, "file %s has not the correct format\n", filename);
3338#ifdef USE_SIGNALS
3339	if (ispipe && anim) StartAnimation ();
3340#endif
3341	return (None);
3342    }
3343    if (*(char *) &swaptest) {
3344	for (i = 0; i < ncolors; i++) {
3345	    _swaplong  ((char *) &xwdcolors [i].pixel, 4);
3346	    _swapshort ((char *) &xwdcolors [i].red, 3 * 2);
3347	}
3348    }
3349    for (i = 0; i < ncolors; i++) {
3350	colors [i].pixel = xwdcolors [i].pixel;
3351	colors [i].red   = xwdcolors [i].red;
3352	colors [i].green = xwdcolors [i].green;
3353	colors [i].blue  = xwdcolors [i].blue;
3354	colors [i].flags = xwdcolors [i].flags;
3355	colors [i].pad   = xwdcolors [i].pad;
3356    }
3357
3358    scrn    = Scr->screen;
3359    cmap    = AlternateCmap ? AlternateCmap : stdcmap;
3360    visual  = Scr->d_visual;
3361    gc      = DefaultGC (dpy, scrn);
3362
3363    buffer_size = header.bytes_per_line * h;
3364    imagedata = (unsigned char*) malloc (buffer_size);
3365    if (! imagedata) {
3366	fprintf (stderr, "cannot allocate memory for image %s\n", filename);
3367#ifdef USE_SIGNALS
3368	if (ispipe && anim) StartAnimation ();
3369#endif
3370	return (None);
3371    }
3372    len = fread (imagedata, (int) buffer_size, 1, file);
3373    if (len != 1) {
3374	free (imagedata);
3375	fprintf (stderr, "file %s has not the correct format\n", filename);
3376#ifdef USE_SIGNALS
3377	if (ispipe && anim) StartAnimation ();
3378#endif
3379	return (None);
3380    }
3381#ifndef VMS
3382    if (ispipe)
3383      pclose (file);
3384    else
3385#endif
3386      fclose (file);
3387
3388    image = XCreateImage (dpy, visual,  depth, header.pixmap_format,
3389                          0, (char*) imagedata, w, h,
3390                          header.bitmap_pad, header.bytes_per_line);
3391    if (image == None) {
3392	free (imagedata);
3393	fprintf (stderr, "cannot create image for %s\n", filename);
3394#ifdef USE_SIGNALS
3395	if (ispipe && anim) StartAnimation ();
3396#endif
3397	return (None);
3398    }
3399    if (header.pixmap_format == ZPixmap) {
3400	compress (image, colors, &ncolors);
3401    }
3402    if (header.pixmap_format != XYBitmap) {
3403	for (i = 0; i < ncolors; i++) {
3404            XAllocColor (dpy, cmap, &(colors [i]));
3405	}
3406	for (i = 0; i < buffer_size; i++) {
3407            imagedata [i] = (unsigned char) colors [imagedata [i]].pixel;
3408	}
3409    }
3410    if (w > Scr->rootw)  w = Scr->rootw;
3411    if (h > Scr->rooth) h = Scr->rooth;
3412
3413    ret = (Image*) malloc (sizeof (struct _Image));
3414    if (! ret) {
3415	fprintf (stderr, "unable to allocate memory for image : %s\n", filename);
3416	free (image);
3417	free (imagedata);
3418	for (i = 0; i < ncolors; i++) {
3419            XFreeColors (dpy, cmap, &(colors [i].pixel), 1, 0L);
3420	}
3421#ifdef USE_SIGNALS
3422	if (ispipe && anim) StartAnimation ();
3423#endif
3424	return (None);
3425    }
3426    if (header.pixmap_format == XYBitmap) {
3427	gcvalues.foreground = cp.fore;
3428	gcvalues.background = cp.back;
3429	XChangeGC (dpy, gc, GCForeground | GCBackground, &gcvalues);
3430    }
3431    if ((w > (Scr->rootw / 2)) || (h > (Scr->rooth / 2))) {
3432	int x, y;
3433
3434	pixret = XCreatePixmap (dpy, Scr->Root, Scr->rootw,
3435				Scr->rooth, Scr->d_depth);
3436	x = (Scr->rootw  - w) / 2;
3437	y = (Scr->rooth - h) / 2;
3438	XFillRectangle (dpy, pixret, gc, 0, 0, Scr->rootw, Scr->rooth);
3439	XPutImage (dpy, pixret, gc, image, 0, 0, x, y, w, h);
3440	ret->width  = Scr->rootw;
3441	ret->height = Scr->rooth;
3442    }
3443    else {
3444	pixret = XCreatePixmap (dpy, Scr->Root, w, h, depth);
3445	XPutImage (dpy, pixret, gc, image, 0, 0, 0, 0, w, h);
3446	ret->width  = w;
3447	ret->height = h;
3448    }
3449    XDestroyImage (image);
3450
3451    ret->pixmap = pixret;
3452    ret->mask   = None;
3453    ret->next   = None;
3454#ifdef USE_SIGNALS
3455    if (ispipe && anim) StartAnimation ();
3456#endif
3457    return (ret);
3458}
3459
3460static Image *GetXwdImage (char *name, ColorPair cp)
3461{
3462    Image *image, *r, *s;
3463    char  path [128];
3464    char  pref [128], *perc;
3465    int   i;
3466
3467    if (! strchr (name, '%')) return (LoadXwdImage (name, cp));
3468    s = image = None;
3469    strcpy (pref, name);
3470    perc  = strchr (pref, '%');
3471    *perc = '\0';
3472    reportfilenotfound = 0;
3473    for (i = 1;; i++) {
3474	sprintf (path, "%s%d%s", pref, i, perc + 1);
3475	r = LoadXwdImage (path, cp);
3476	if (r == None) break;
3477	r->next   = None;
3478	if (image == None) s = image = r;
3479	else {
3480	    s->next = r;
3481	    s = r;
3482	}
3483    }
3484    reportfilenotfound = 1;
3485    if (s != None) s->next = image;
3486    if (image == None) {
3487	fprintf (stderr, "Cannot open any %s xwd file\n", name);
3488    }
3489    return (image);
3490}
3491
3492static void compress (XImage *image, XColor *colors, int *ncolors)
3493{
3494    unsigned char ind  [256];
3495    unsigned int  used [256];
3496    int           i, j, size, nused;
3497    unsigned char color;
3498    XColor        newcolors [256];
3499    unsigned char *imagedata;
3500
3501    for (i = 0; i < 256; i++) {
3502	used [i] = 0;
3503	ind  [i] = 0;
3504    }
3505    nused = 0;
3506    size  = image->bytes_per_line * image->height;
3507    imagedata = (unsigned char *) image->data;
3508    for (i = 0; i < size; i++) {
3509	if ((i % image->bytes_per_line) > image->width) continue;
3510        color = imagedata [i];
3511        if (used [color] == 0) {
3512            for (j = 0; j < nused; j++) {
3513                if ((colors [color].red   == newcolors [j].red)   &&
3514                    (colors [color].green == newcolors [j].green) &&
3515                    (colors [color].blue  == newcolors [j].blue)) break;
3516            }
3517            ind  [color] = j;
3518            used [color] = 1;
3519            if (j == nused) {
3520                newcolors [j].red   = colors [color].red;
3521                newcolors [j].green = colors [color].green;
3522                newcolors [j].blue  = colors [color].blue;
3523                nused++;
3524            }
3525        }
3526    }
3527    for (i = 0; i < size; i++) {
3528        imagedata [i] = ind [imagedata [i]];
3529    }
3530    for (i = 0; i < nused; i++) {
3531        colors [i] = newcolors [i];
3532    }
3533    *ncolors = nused;
3534}
3535#endif
3536
3537#ifdef IMCONV
3538
3539static void free_images  ();
3540
3541static Image *GetImconvImage (char *filename,
3542			      unsigned int *widthp, unsigned int *heightp)
3543{
3544    TagTable		*toolInTable;
3545    ImVfb		*sourceVfb;
3546    ImVfbPtr		vptr;
3547    ImClt		*clt;
3548    int			i, j, ij, k, retval;
3549
3550    XColor		colors [256];
3551    unsigned		buffer_size;
3552    XImage		*image;
3553    unsigned char	*imagedata;
3554    Pixmap		pixret;
3555    Visual		*visual;
3556    int			w, h, depth, ncolors;
3557    int			scrn;
3558    Colormap		cmap;
3559    Colormap		stdcmap = Scr->RootColormaps.cwins[0]->colormap->c;
3560    GC			gc;
3561    unsigned char	red, green, blue;
3562    int			icol;
3563    char		*fullname;
3564
3565    TagEntry		*dataEntry;
3566    FILE		*fp;
3567    char		the_format[1024];
3568    char		*tmp_format;
3569    Image		*ret;
3570
3571    if (*filename == NULL) return (None);
3572    fullname = ExpandPixmapPath (filename);
3573    if (! fullname) return (None);
3574
3575    fp = fopen (fullname, "r");
3576    if (!fp) {
3577	if (reportfilenotfound) fprintf (stderr, "Cannot open the image %s\n", filename);
3578	free (fullname);
3579	return (None);
3580    }
3581    if ((toolInTable = TagTableAlloc ()) == TAGTABLENULL ) {
3582	fprintf (stderr, "TagTableAlloc failed\n");
3583	free_images (toolInTable);
3584	free (fullname);
3585	return (None);
3586    }
3587    if ((tmp_format = ImFileQFFormat (fp, fullname)) == NULL)  {
3588	fprintf (stderr, "Cannot determine image type of %s\n", filename);
3589	free_images  (toolInTable);
3590	free (fullname);
3591	return (None);
3592    }
3593    strcpy (the_format, tmp_format);
3594    retval = ImFileFRead (fp, the_format, NULL, toolInTable);
3595    if(retval < 0) {
3596	fprintf(stderr, "Cannot read image file %s: ", fullname);
3597	switch(ImErrNo) {
3598	    case IMESYS:
3599		fprintf (stderr, "System call error\n");
3600		break;
3601	    case IMEMALLOC:
3602		fprintf (stderr, "Cannot allocate memory\n");
3603		break;
3604	    case IMEFORMAT:
3605		fprintf (stderr, "Data in file is corrupt\n");
3606		break;
3607	    case IMENOREAD:
3608		fprintf (stderr, "Sorry, this format is write-only\n");
3609		break;
3610	    case IMEMAGIC:
3611		fprintf (stderr, "Bad magic number in image file\n");
3612		break;
3613	    case IMEDEPTH:
3614		fprintf (stderr, "Unknown image depth\n");
3615		break;
3616	    default:
3617		fprintf(stderr, "Unknown error\n");
3618		break;
3619	}
3620	free_images (toolInTable);
3621	free (fullname);
3622	return (None);
3623    }
3624
3625    if (TagTableQNEntry (toolInTable, "image vfb") == 0)  {
3626	fprintf (stderr, "Image file %s contains no images\n", fullname);
3627	free_images (toolInTable);
3628	free (fullname);
3629	return (None);
3630    }
3631    dataEntry = TagTableQDirect (toolInTable, "image vfb", 0);
3632    TagEntryQValue (dataEntry, &sourceVfb);
3633    fclose (fp);
3634
3635    w = ImVfbQWidth  (sourceVfb);
3636    h = ImVfbQHeight (sourceVfb);
3637    depth = 8 * ImVfbQNBytes (sourceVfb);
3638    if (depth != 8) {
3639	fprintf (stderr, "I don't know yet how to deal with images not of 8 planes depth\n");
3640	free_images (toolInTable);
3641	return (None);
3642    }
3643
3644    *width  = w;
3645    *height = h;
3646
3647    scrn   = Scr->screen;
3648    cmap   = AlternateCmap ? AlternateCmap : stdcmap;
3649    visual = Scr->d_visual;
3650    gc     = DefaultGC (dpy, scrn);
3651
3652    buffer_size = w * h;
3653    imagedata = (unsigned char*) malloc (buffer_size);
3654    if (imagedata == (unsigned char*) 0) {
3655	fprintf (stderr, "Can't alloc enough space for background images\n");
3656	free_images (toolInTable);
3657	return (None);
3658    }
3659
3660    clt  = ImVfbQClt   (sourceVfb);
3661    vptr = ImVfbQFirst (sourceVfb);
3662    ncolors = 0;
3663    for (i = 0; i < h - 1; i++) {
3664	for (j = 0; j < w; j++) {
3665	    ij = (i * w) + j;
3666	    red   = ImCltQRed   (ImCltQPtr (clt, ImVfbQIndex (sourceVfb, vptr)));
3667	    green = ImCltQGreen (ImCltQPtr (clt, ImVfbQIndex (sourceVfb, vptr)));
3668	    blue  = ImCltQBlue  (ImCltQPtr (clt, ImVfbQIndex (sourceVfb, vptr)));
3669	    for (k = 0; k < ncolors; k++) {
3670		if ((colors [k].red   == red) &&
3671		    (colors [k].green == green) &&
3672		    (colors [k].blue  == blue)) {
3673		    icol = k;
3674		    break;
3675		}
3676	    }
3677	    if (k == ncolors) {
3678		icol = ncolors;
3679		ncolors++;
3680	    }
3681	    imagedata [ij] = icol;
3682	    colors [icol].red   = red;
3683	    colors [icol].green = green;
3684	    colors [icol].blue  = blue;
3685	    ImVfbSInc (sourceVfb, vptr);
3686	}
3687    }
3688    for (i = 0; i < ncolors; i++) {
3689	colors [i].red   *= 256;
3690	colors [i].green *= 256;
3691	colors [i].blue  *= 256;
3692    }
3693    for (i = 0; i < ncolors; i++) {
3694        if (! XAllocColor (dpy, cmap, &(colors [i]))) {
3695	    fprintf (stderr, "can't alloc color for image %s\n", filename);
3696	}
3697    }
3698    for (i = 0; i < buffer_size; i++) {
3699        imagedata [i] = (unsigned char) colors [imagedata [i]].pixel;
3700    }
3701
3702    image  = XCreateImage  (dpy, visual, depth, ZPixmap, 0, (char*) imagedata, w, h, 8, 0);
3703    if (w > Scr->rootw)  w = Scr->rootw;
3704    if (h > Scr->rooth) h = Scr->rooth;
3705
3706    if ((w > (Scr->rootw / 2)) || (h > (Scr->rooth / 2))) {
3707	int x, y;
3708
3709	pixret = XCreatePixmap (dpy, Scr->Root, Scr->rootw, Scr->rooth, depth);
3710	x = (Scr->rootw  - w) / 2;
3711	y = (Scr->rooth - h) / 2;
3712	XFillRectangle (dpy, pixret, gc, 0, 0, Scr->rootw, Scr->rooth);
3713	XPutImage (dpy, pixret, gc, image, 0, 0, x, y, w, h);
3714	ret->width  = Scr->rootw;
3715	ret->height = Scr->rooth;
3716    }
3717    else {
3718	pixret = XCreatePixmap (dpy, Scr->Root, w, h, depth);
3719	XPutImage (dpy, pixret, gc, image, 0, 0, 0, 0, w, h);
3720	ret->width  = w;
3721	ret->height = h;
3722    }
3723    XFree (image);
3724    ret = (Image*) malloc (sizeof (struct _Image));
3725    ret->pixmap = pixret;
3726    ret->mask   = None;
3727    ret->next   = None;
3728    return (ret);
3729
3730}
3731
3732static void free_images (table)
3733TagTable *table;
3734{
3735    int		i, n;
3736    ImVfb	*v;
3737    ImClt	*c;
3738    TagEntry	*dataEntry;
3739
3740    n = TagTableQNEntry (table, "image vfb");
3741    for (i = 0 ; i < n ; i++) {
3742	dataEntry = TagTableQDirect (table, "image vfb", i);
3743	TagEntryQValue (dataEntry, &v);
3744	ImVfbFree (v);
3745    }
3746    n = TagTableQNEntry (table, "image clt");
3747    for (i = 0 ; i < n ; i++) {
3748	dataEntry = TagTableQDirect (table, "image clt", i );
3749	TagEntryQValue (dataEntry, &c);
3750	ImCltFree (c);
3751    }
3752    TagTableFree (table);
3753}
3754
3755#endif
3756
3757void _swapshort (register char *bp, register unsigned n)
3758{
3759    register char c;
3760    register char *ep = bp + n;
3761
3762    while (bp < ep) {
3763	c = *bp;
3764	*bp = *(bp + 1);
3765	bp++;
3766	*bp++ = c;
3767    }
3768}
3769
3770void _swaplong (register char *bp, register unsigned n)
3771{
3772    register char c;
3773    register char *ep = bp + n;
3774    register char *sp;
3775
3776    while (bp < ep) {
3777	sp = bp + 3;
3778	c = *sp;
3779	*sp = *bp;
3780	*bp++ = c;
3781	sp = bp + 1;
3782	c = *sp;
3783	*sp = *bp;
3784	*bp++ = c;
3785	bp += 2;
3786    }
3787}
3788
3789/***********************************************************************
3790 *
3791 *  Procedure:
3792 *	GetWMPropertyString - Get Window Manager text property and
3793 *				convert it to a string.
3794 *
3795 *  Returned Value:
3796 *	(char *) - pointer to the malloc'd string or NULL
3797 *
3798 *  Inputs:
3799 *	w	- the id of the window whose property is to be retrieved
3800 *	prop	- property atom (typically WM_NAME or WM_ICON_NAME)
3801 *
3802 ***********************************************************************
3803 */
3804
3805unsigned char *GetWMPropertyString(Window w, Atom prop)
3806{
3807    XTextProperty	text_prop;
3808    char 		**text_list;
3809    int 		text_list_count;
3810    Atom 		XA_COMPOUND_TEXT = XInternAtom(dpy, "COMPOUND_TEXT", False);
3811    unsigned char	*stringptr;
3812    int			status, len = -1;
3813
3814    (void)XGetTextProperty(dpy, w, &text_prop, prop);
3815    if (text_prop.value != NULL) {
3816	if (text_prop.encoding == XA_STRING
3817	    || text_prop.encoding == XA_COMPOUND_TEXT) {
3818	    /* property is encoded as compound text - convert to locale string */
3819	    status = XmbTextPropertyToTextList(dpy, &text_prop,
3820					       &text_list, &text_list_count);
3821	    if (text_list_count == 0) {
3822		stringptr = NULL;
3823	    } else
3824	    if (text_list == (char **)0) {
3825		stringptr = NULL;
3826	    } else
3827	    if (text_list [0] == (char *)0) {
3828		stringptr = NULL;
3829	    } else
3830	    if (status < 0 || text_list_count < 0) {
3831		switch (status) {
3832		case XConverterNotFound:
3833		    fprintf (stderr, "%s: Converter not found; unable to convert property %s of window ID %lx.\n",
3834			     ProgramName, XGetAtomName(dpy, prop), w);
3835		    break;
3836		case XNoMemory:
3837		    fprintf (stderr, "%s: Insufficient memory; unable to convert property %s of window ID %lx.\n",
3838			     ProgramName, XGetAtomName(dpy, prop), w);
3839		    break;
3840		case XLocaleNotSupported:
3841		    fprintf (stderr, "%s: Locale not supported; unable to convert property %s of window ID %lx.\n",
3842			     ProgramName, XGetAtomName(dpy, prop), w);
3843		    break;
3844		}
3845		stringptr = NULL;
3846		/*
3847		   don't call XFreeStringList - text_list appears to have
3848		   invalid address if status is bad
3849		   XFreeStringList(text_list);
3850		*/
3851	    } else {
3852		len = strlen(text_list[0]);
3853		stringptr = memcpy(malloc(len+1), text_list[0], len+1);
3854		XFreeStringList(text_list);
3855	    }
3856	} else {
3857	    /* property is encoded in a format we don't understand */
3858	    fprintf (stderr, "%s: Encoding not STRING or COMPOUND_TEXT; unable to decode property %s of window ID %lx.\n",
3859		     ProgramName, XGetAtomName(dpy, prop), w);
3860	    stringptr = NULL;
3861	}
3862	XFree (text_prop.value);
3863    } else {
3864	stringptr = NULL;
3865    }
3866
3867    return stringptr;
3868}
3869
3870void FreeWMPropertyString(char *prop)
3871{
3872    if (prop && (char *)prop != NoName) {
3873	free(prop);
3874    }
3875}
3876
3877static void ConstrainLeftTop (int *value, int border)
3878{
3879  if (*value < border) {
3880    if (Scr->MoveOffResistance < 0 ||
3881	*value > border - Scr->MoveOffResistance)
3882    {
3883        *value = border;
3884    } else if (Scr->MoveOffResistance > 0 &&
3885	       *value <= border - Scr->MoveOffResistance)
3886    {
3887      *value = *value + Scr->MoveOffResistance;
3888    }
3889    }
3890}
3891
3892static void ConstrainRightBottom (int *value, int size1, int border, int size2)
3893{
3894    if (*value + size1 > size2 - border) {
3895      if (Scr->MoveOffResistance < 0 ||
3896         *value + size1 < size2 - border + Scr->MoveOffResistance)
3897    {
3898        *value = size2 - size1 - border;
3899	} else if (Scr->MoveOffResistance > 0 &&
3900		   *value + size1 >= size2 - border + Scr->MoveOffResistance) {
3901	  *value = *value - Scr->MoveOffResistance;
3902	}
3903    }
3904}
3905
3906void ConstrainByBorders1 (int *left, int width, int *top, int height)
3907{
3908    ConstrainRightBottom (left, width, Scr->BorderRight, Scr->rootw);
3909    ConstrainLeftTop     (left, Scr->BorderLeft);
3910    ConstrainRightBottom (top, height, Scr->BorderBottom, Scr->rooth);
3911    ConstrainLeftTop     (top, Scr->BorderTop);
3912}
3913
3914void ConstrainByBorders (TwmWindow *twmwin,
3915			 int *left, int width, int *top, int height)
3916{
3917    if (twmwin->winbox) {
3918	XWindowAttributes attr;
3919	XGetWindowAttributes (dpy, twmwin->winbox->window, &attr);
3920	ConstrainRightBottom (left, width, 0, attr.width);
3921	ConstrainLeftTop     (left, 0);
3922	ConstrainRightBottom (top, height, 0, attr.height);
3923	ConstrainLeftTop     (top, 0);
3924    } else {
3925	ConstrainByBorders1 (left, width, top, height);
3926    }
3927}
3928
3929#ifdef JPEG
3930
3931uint16_t *buffer_16bpp;
3932uint32_t *buffer_32bpp;
3933
3934static void convert_for_16 (int w, int x, int y, int r, int g, int b) {
3935  buffer_16bpp [y * w + x] = ((r >> 3) << 11) + ((g >> 2) << 5) + (b >> 3);
3936}
3937
3938static void convert_for_32 (int w, int x, int y, int r, int g, int b) {
3939  buffer_32bpp [y * w + x] = ((r << 16) + (g << 8) + b) & 0xFFFFFFFF;
3940}
3941
3942static void jpeg_error_exit (j_common_ptr cinfo) {
3943  jerr_ptr errmgr = (jerr_ptr) cinfo->err;
3944  cinfo->err->output_message (cinfo);
3945  siglongjmp (errmgr->setjmp_buffer, 1);
3946  return;
3947}
3948
3949static Image *GetJpegImage (char *name)
3950{
3951    Image *image, *r, *s;
3952    char  path [128];
3953    char  pref [128], *perc;
3954    int   i;
3955
3956    if (! strchr (name, '%')) return (LoadJpegImage (name));
3957    s = image = None;
3958    strcpy (pref, name);
3959    perc  = strchr (pref, '%');
3960    *perc = '\0';
3961    reportfilenotfound = 0;
3962    for (i = 1;; i++) {
3963	sprintf (path, "%s%d%s", pref, i, perc + 1);
3964	r = LoadJpegImage (path);
3965	if (r == None) break;
3966	r->next   = None;
3967	if (image == None) s = image = r;
3968	else {
3969	    s->next = r;
3970	    s = r;
3971	}
3972    }
3973    reportfilenotfound = 1;
3974    if (s != None) s->next = image;
3975    if (image == None) {
3976	fprintf (stderr, "Cannot open any %s jpeg file\n", name);
3977    }
3978    return (image);
3979}
3980
3981static Image *LoadJpegImage (char *name)
3982{
3983  char   *fullname;
3984  XImage *ximage;
3985  FILE   *infile;
3986  Image  *image;
3987  Pixmap pixret;
3988  void   (*store_data) (int w, int x, int y, int r, int g, int b);
3989  struct jpeg_decompress_struct cinfo;
3990  struct jpeg_error jerr;
3991  JSAMPARRAY buffer;
3992  int width, height;
3993  int row_stride;
3994  int g, i, a;
3995  int bpix;
3996  GC  gc;
3997
3998  fullname = ExpandPixmapPath (name);
3999  if (! fullname) return (None);
4000
4001  image = (Image*) malloc (sizeof (struct _Image));
4002  if (image == None) return (None);
4003
4004  if ((infile = fopen (fullname, "rb")) == NULL) {
4005    if (!reportfilenotfound) fprintf (stderr, "unable to locate %s\n", fullname);
4006    fflush (stdout);
4007    return None;
4008  }
4009  cinfo.err = jpeg_std_error (&jerr.pub);
4010  jerr.pub.error_exit = jpeg_error_exit;
4011
4012  if (sigsetjmp(jerr.setjmp_buffer, 1)) {
4013    jpeg_destroy_decompress (&cinfo);
4014    fclose (infile);
4015    return None;
4016  }
4017  jpeg_create_decompress (&cinfo);
4018  jpeg_stdio_src (&cinfo, infile);
4019  jpeg_read_header (&cinfo, FALSE);
4020  cinfo.do_fancy_upsampling = FALSE;
4021  cinfo.do_block_smoothing = FALSE;
4022  jpeg_start_decompress (&cinfo);
4023  width  = cinfo.output_width;
4024  height = cinfo.output_height;
4025
4026  if (Scr->d_depth == 16) {
4027    store_data = &convert_for_16;
4028    buffer_16bpp = (unsigned short int *) malloc ((width) * (height) * 2);
4029    ximage = XCreateImage (dpy, CopyFromParent, Scr->d_depth, ZPixmap, 0,
4030			   (char *) buffer_16bpp, width, height, 16, width * 2);
4031  } else {
4032    if (Scr->d_depth == 24) {
4033      store_data = &convert_for_32;
4034      buffer_32bpp = malloc (width * height * 4);
4035      ximage = XCreateImage (dpy, CopyFromParent, Scr->d_depth, ZPixmap, 0,
4036			     (char *) buffer_32bpp, width, height, 32, width * 4);
4037    } else
4038    if (Scr->d_depth == 32) {
4039      store_data = &convert_for_32;
4040      buffer_32bpp = malloc (width * height * 4);
4041      ximage = XCreateImage (dpy, CopyFromParent, Scr->d_depth, ZPixmap, 0,
4042			     (char *) buffer_32bpp, width, height, 32, width * 4);
4043    } else {
4044      fprintf (stderr, "Image %s unsupported depth : %d\n", name, Scr->d_depth);
4045      return None;
4046    }
4047  }
4048  if (ximage == None) {
4049    fprintf (stderr, "cannot create image for %s\n", name);
4050  }
4051  g = 0;
4052  row_stride = cinfo.output_width * cinfo.output_components;
4053  buffer = (*cinfo.mem->alloc_sarray)
4054    ((j_common_ptr) & cinfo, JPOOL_IMAGE, row_stride, 1);
4055
4056  bpix = cinfo.output_components;
4057  while (cinfo.output_scanline < cinfo.output_height) {
4058    jpeg_read_scanlines (&cinfo, buffer, 1);
4059    a = 0;
4060    for (i = 0; i < bpix * cinfo.output_width; i += bpix) {
4061      (*store_data) (width, a, g, buffer[0][i],  buffer[0][i + 1], buffer[0][i + 2]);
4062      a++;
4063    }
4064    g++;
4065  }
4066  jpeg_finish_decompress (&cinfo);
4067  jpeg_destroy_decompress (&cinfo);
4068  fclose (infile);
4069
4070  gc = DefaultGC (dpy, Scr->screen);
4071  if ((width > (Scr->rootw / 2)) || (height > (Scr->rooth / 2))) {
4072    int x, y;
4073
4074    pixret = XCreatePixmap (dpy, Scr->Root, Scr->rootw, Scr->rooth, Scr->d_depth);
4075    x = (Scr->rootw  -  width) / 2;
4076    y = (Scr->rooth  - height) / 2;
4077    XFillRectangle (dpy, pixret, gc, 0, 0, Scr->rootw, Scr->rooth);
4078    XPutImage (dpy, pixret, gc, ximage, 0, 0, x, y, width, height);
4079    image->width  = Scr->rootw;
4080    image->height = Scr->rooth;
4081  } else {
4082    pixret = XCreatePixmap (dpy, Scr->Root, width, height, Scr->d_depth);
4083    XPutImage (dpy, pixret, gc, ximage, 0, 0, 0, 0, width, height);
4084    image->width  = width;
4085    image->height = height;
4086  }
4087  XDestroyImage (ximage);
4088  image->pixmap = pixret;
4089  image->mask   = None;
4090  image->next   = None;
4091
4092  return image;
4093}
4094
4095#endif /* JPEG */
4096