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 
29 /***********************************************************************
30  *
31  * $XConsortium: util.c,v 1.47 91/07/14 13:40:37 rws Exp $
32  *
33  * utility routines for twm
34  *
35  * 28-Oct-87 Thomas E. LaStrange	File created
36  *
37  ***********************************************************************/
38 
39 #include "twm.h"
40 #include "util.h"
41 #include "gram.h"
42 #include "screen.h"
43 #include <X11/Xos.h>
44 #include <X11/Xatom.h>
45 #include <stdio.h>
46 #include <X11/Xmu/Drawing.h>
47 #include <X11/Xmu/CharSet.h>		/* for XmuCompareISOLatin1() */
48 
49 static Pixmap CreateXLogoPixmap(), CreateResizePixmap();
50 static Pixmap CreateQuestionPixmap(), CreateMenuPixmap();
51 static Pixmap CreateDotPixmap();
52 int HotX, HotY;
53 
54 /***********************************************************************
55  *
56  *  Procedure:
57  *	MoveOutline - move a window outline
58  *
59  *  Inputs:
60  *	root	    - the window we are outlining
61  *	x	    - upper left x coordinate
62  *	y	    - upper left y coordinate
63  *	width	    - the width of the rectangle
64  *	height	    - the height of the rectangle
65  *      bw          - the border width of the frame
66  *      th          - title height
67  *
68  ***********************************************************************
69  */
70 
71 /* ARGSUSED */
MoveOutline(root,x,y,width,height,bw,th)72 void MoveOutline(root, x, y, width, height, bw, th)
73     Window root;
74     int x, y, width, height, bw, th;
75 {
76     static Window lastRoot;
77     static int	lastx = 0;
78     static int	lasty = 0;
79     static int	lastWidth = 0;
80     static int	lastHeight = 0;
81     static int	lastBW = 0;
82     static int	lastTH = 0;
83     int		xl, xr, yt, yb, xinnerl, xinnerr, yinnert, yinnerb;
84     int		xthird, ythird;
85     XSegment	outline[18];
86     register XSegment	*r;
87 
88     if (x == lastx && y == lasty && width == lastWidth && height == lastHeight
89 	&& lastBW == bw && th == lastTH)
90 	return;
91 
92     if (root == None)
93 	root = lastRoot;
94     lastRoot = root;
95     r = outline;
96 
97 #define DRAWIT() \
98     if (lastWidth || lastHeight)			\
99     {							\
100 	xl = lastx;					\
101 	xr = lastx + lastWidth - 1;			\
102 	yt = lasty;					\
103 	yb = lasty + lastHeight - 1;			\
104 	xinnerl = xl + lastBW;				\
105 	xinnerr = xr - lastBW;				\
106 	yinnert = yt + lastTH + lastBW;			\
107 	yinnerb = yb - lastBW;				\
108 	xthird = (xinnerr - xinnerl) / 3;		\
109 	ythird = (yinnerb - yinnert) / 3;		\
110 							\
111 	r->x1 = xl;					\
112 	r->y1 = yt;					\
113 	r->x2 = xr;					\
114 	r->y2 = yt;					\
115 	r++;						\
116 							\
117 	r->x1 = xl;					\
118 	r->y1 = yb;					\
119 	r->x2 = xr;					\
120 	r->y2 = yb;					\
121 	r++;						\
122 							\
123 	r->x1 = xl;					\
124 	r->y1 = yt;					\
125 	r->x2 = xl;					\
126 	r->y2 = yb;					\
127 	r++;						\
128 							\
129 	r->x1 = xr;					\
130 	r->y1 = yt;					\
131 	r->x2 = xr;					\
132 	r->y2 = yb;					\
133 	r++;						\
134 							\
135 	r->x1 = xinnerl + xthird;			\
136 	r->y1 = yinnert;				\
137 	r->x2 = r->x1;					\
138 	r->y2 = yinnerb;				\
139 	r++;						\
140 							\
141 	r->x1 = xinnerl + (2 * xthird);			\
142 	r->y1 = yinnert;				\
143 	r->x2 = r->x1;					\
144 	r->y2 = yinnerb;				\
145 	r++;						\
146 							\
147 	r->x1 = xinnerl;				\
148 	r->y1 = yinnert + ythird;			\
149 	r->x2 = xinnerr;				\
150 	r->y2 = r->y1;					\
151 	r++;						\
152 							\
153 	r->x1 = xinnerl;				\
154 	r->y1 = yinnert + (2 * ythird);			\
155 	r->x2 = xinnerr;				\
156 	r->y2 = r->y1;					\
157 	r++;						\
158 							\
159 	if (lastTH != 0) {				\
160 	    r->x1 = xl;					\
161 	    r->y1 = yt + lastTH;			\
162 	    r->x2 = xr;					\
163 	    r->y2 = r->y1;				\
164 	    r++;					\
165 	}						\
166     }
167 
168     /* undraw the old one, if any */
169     DRAWIT ();
170 
171     lastx = x;
172     lasty = y;
173     lastWidth = width;
174     lastHeight = height;
175     lastBW = bw;
176     lastTH = th;
177 
178     /* draw the new one, if any */
179     DRAWIT ();
180 
181 #undef DRAWIT
182 
183 
184     if (r != outline)
185     {
186 	XDrawSegments(dpy, root, Scr->DrawGC, outline, r - outline);
187     }
188 }
189 
190 /***********************************************************************
191  *
192  *  Procedure:
193  *	Zoom - zoom in or out of an icon
194  *
195  *  Inputs:
196  *	wf	- window to zoom from
197  *	wt	- window to zoom to
198  *
199  ***********************************************************************
200  */
201 
202 void
Zoom(wf,wt)203 Zoom(wf, wt)
204     Window wf, wt;
205 {
206     int fx, fy, tx, ty;			/* from, to */
207     unsigned int fw, fh, tw, th;	/* from, to */
208     long dx, dy, dw, dh;
209     long z;
210     int j;
211 
212     if (!Scr->DoZoom || Scr->ZoomCount < 1) return;
213 
214     if (wf == None || wt == None) return;
215 
216     XGetGeometry (dpy, wf, &JunkRoot, &fx, &fy, &fw, &fh, &JunkBW, &JunkDepth);
217     XGetGeometry (dpy, wt, &JunkRoot, &tx, &ty, &tw, &th, &JunkBW, &JunkDepth);
218 
219     dx = ((long) (tx - fx));	/* going from -> to */
220     dy = ((long) (ty - fy));	/* going from -> to */
221     dw = ((long) (tw - fw));	/* going from -> to */
222     dh = ((long) (th - fh));	/* going from -> to */
223     z = (long) (Scr->ZoomCount + 1);
224 
225     for (j = 0; j < 2; j++) {
226 	long i;
227 
228 	XDrawRectangle (dpy, Scr->Root, Scr->DrawGC, fx, fy, fw, fh);
229 	for (i = 1; i < z; i++) {
230 	    int x = fx + (int) ((dx * i) / z);
231 	    int y = fy + (int) ((dy * i) / z);
232 	    unsigned width = (unsigned) (((long) fw) + (dw * i) / z);
233 	    unsigned height = (unsigned) (((long) fh) + (dh * i) / z);
234 
235 	    XDrawRectangle (dpy, Scr->Root, Scr->DrawGC,
236 			    x, y, width, height);
237 	}
238 	XDrawRectangle (dpy, Scr->Root, Scr->DrawGC, tx, ty, tw, th);
239     }
240 }
241 
242 
243 /***********************************************************************
244  *
245  *  Procedure:
246  *	ExpandFilename - expand the tilde character to HOME
247  *		if it is the first character of the filename
248  *
249  *  Returned Value:
250  *	a pointer to the new name
251  *
252  *  Inputs:
253  *	name	- the filename to expand
254  *
255  ***********************************************************************
256  */
257 
258 char *
ExpandFilename(name)259 ExpandFilename(name)
260 char *name;
261 {
262     char *newname;
263 
264     if (name[0] != '~') return name;
265 
266     newname = (char *) malloc (HomeLen + strlen(name) + 2);
267     if (!newname) {
268 	fprintf (stderr,
269 		 "%s:  unable to allocate %d bytes to expand filename %s/%s\n",
270 		 ProgramName, HomeLen + strlen(name) + 2, Home, &name[1]);
271     } else {
272 	(void) sprintf (newname, "%s/%s", Home, &name[1]);
273     }
274 
275     return newname;
276 }
277 
278 /***********************************************************************
279  *
280  *  Procedure:
281  *	FindPixmap - read in a bitmap file and return size
282  *
283  *  Returned Value:
284  *	the pixmap associated with the bitmap
285  *      widthp	- pointer to width of bitmap
286  *      heightp	- pointer to height of bitmap
287  *	isXpm - pointer to an Boolean that says whether it's an Xpm
288  *		pixmap or not.  Used ifdef XPM.
289  *	bg_color - pointer to a Pixel (unsigned long) which is the background
290  *		color of the pixmap (for an Xpm).  Actually, it's just the
291  *		first color in the pixel list, so it's not neccessarily
292  *		the "real" background color.  Can be passed as NULL.  Used
293  *		ifdef XPM.
294  *	colors - a list of XpmColorSymbol structures containing information
295  *		to translate the colors in a bitmap/pixmap file into the colors
296  *		that you want for the pixmap returned.
297  *	numcolors - number of entries in the above list
298  *	shape_mask - pointer to a Pixmap where will be returned the shape
299  *		mask of the Pixmap, if XpmReadFileToPixmap returns such.
300  *
301  *  Inputs:
302  *	name	- the filename to read
303  *
304  ***********************************************************************
305  */
306 
307 extern int XmuCompareISOLatin1();
308 
FindPixmap(name,widthp,heightp,isXpm,bg_color,colors,numcolors,shape_mask)309 Pixmap FindPixmap (name, widthp, heightp, isXpm, bg_color, colors,
310 			numcolors, shape_mask)
311     char *name;
312     unsigned int *widthp, *heightp;
313     Bool *isXpm;
314     Pixel *bg_color;
315 #ifdef XPM
316     XpmColorSymbol *colors;
317 #else
318     char *colors;
319 #endif
320     int numcolors;
321     Pixmap *shape_mask;
322 {
323     char *bigname;
324     Pixmap pm;
325 #ifdef XPM
326     int XPMret;
327     XpmAttributes attribs;
328 #endif  /* XPM */
329 
330     *isXpm = False;
331     if (shape_mask)
332 	*shape_mask = None;
333 #ifdef XPM
334     if (numcolors) {
335 	attribs.valuemask = XpmColorSymbols;
336 	attribs.colorsymbols = colors;
337 	attribs.numsymbols = numcolors;
338     } else
339 	attribs.valuemask = 0;
340 #endif
341 
342     if (!name) return None;
343 
344     /*
345      * Names of the form :name refer to hardcoded images that are scaled to
346      * look nice in title buttons.  Eventually, it would be nice to put in a
347      * menu symbol as well....
348      */
349     if (name[0] == ':') {
350 	int i;
351 	static struct {
352 	    char *name;
353 	    Pixmap (*proc)();
354 	} pmtab[] = {
355 	    { TBPM_DOT,		CreateDotPixmap },
356 	    { TBPM_ICONIFY,	CreateDotPixmap },
357 	    { TBPM_RESIZE,	CreateResizePixmap },
358 	    { TBPM_XLOGO,	CreateXLogoPixmap },
359 	    { TBPM_DELETE,	CreateXLogoPixmap },
360 	    { TBPM_MENU,	CreateMenuPixmap },
361 	    { TBPM_QUESTION,	CreateQuestionPixmap },
362 	};
363 
364 	for (i = 0; i < (sizeof pmtab)/(sizeof pmtab[0]); i++) {
365 	    if (XmuCompareISOLatin1 (pmtab[i].name, name) == 0)
366 	      return (*pmtab[i].proc) (widthp, heightp);
367 	}
368 	fprintf (stderr, "%s:  no such built-in bitmap \"%s\"\n",
369 		 ProgramName, name);
370 	return None;
371     }
372 
373     if (name[0] == '#') {
374 	/* cursor font glyph */
375 
376 	if (bg_color)
377 	   *bg_color = BlackPixel(dpy, Scr->screen);
378 
379 	return GetCursorGlyph(name+1, widthp, heightp, shape_mask);
380     }
381 
382     /*
383      * Generate a full pathname if any special prefix characters (such as ~)
384      * are used.  If the bigname is different from name, bigname will need to
385      * be freed.
386      */
387     bigname = ExpandFilename (name);
388     if (!bigname) return None;
389 
390     /*
391      * look along bitmapFilePath resource same as toolkit clients
392      */
393 #ifdef XPM
394     attribs.valuemask = XpmVisual | XpmColormap | XpmDepth;
395     attribs.visual = Scr->d_visual;
396     attribs.colormap = Scr->TwmRoot.cmaps.cwins[0]->colormap->c;
397     attribs.depth = Scr->d_depth;
398     attribs.pixels = NULL;
399 
400     if (bg_color)
401 	attribs.valuemask |= XpmReturnPixels;
402 
403     pm = XcprLocatePixmapFile (ScreenOfDisplay(dpy, Scr->screen), bigname,
404 				colors, numcolors,
405 				Scr->d_depth, NULL, 0, widthp, heightp, &HotX, &HotY,
406 				isXpm, &attribs, shape_mask);
407     if (bg_color && *isXpm)
408 	*bg_color = *attribs.pixels;
409 #else
410     pm = XmuLocateBitmapFile (ScreenOfDisplay(dpy, Scr->screen), bigname, NULL,
411 			      0, (int *)widthp, (int *)heightp, &HotX, &HotY);
412 #endif  /* XPM */
413 
414     if (pm == None && Scr->IconDirectory && bigname[0] != '/') {
415 	if (bigname != name) free (bigname);
416 	/*
417 	 * Attempt to find icon in old IconDirectory (now obsolete)
418 	 */
419 	bigname = (char *) malloc (strlen(name) + strlen(Scr->IconDirectory) +
420 				   2);
421 	if (!bigname) {
422 	    fprintf (stderr,
423 		     "%s:  unable to allocate memory for \"%s/%s\"\n",
424 		     ProgramName, Scr->IconDirectory, name);
425 	    return None;
426 	}
427 	(void) sprintf (bigname, "%s/%s", Scr->IconDirectory, name);
428 
429 #ifdef XPM
430 	attribs.valuemask = XpmVisual | XpmColormap | XpmDepth;
431 	attribs.visual = Scr->d_visual;
432 	attribs.colormap = Scr->TwmRoot.cmaps.cwins[0]->colormap->c;
433 	attribs.depth = Scr->d_depth;
434 
435 	XPMret = XpmReadFileToPixmap(dpy, RootWindow(dpy, Scr->screen),
436 		bigname, &pm, shape_mask, &attribs);
437 	switch (XPMret) {
438 	    case XpmSuccess:
439 	    case XpmColorError:
440 		*isXpm = True;
441 		break;
442 	    case XpmNoMemory:
443 		printf("%s: XpmReadFileToPixmap out of memory (reading \"%s\")\n",
444 			ProgramName, bigname);
445 		break;
446 	    case XpmColorFailed:
447 		printf("%s: Color parse/alloc failed in XpmReadFileToPixmap (reading \"%s\")\n",
448 			ProgramName, bigname);
449 		break;
450 	    case XpmOpenFailed:
451 	    case XpmFileInvalid:
452 	    default:
453 		if (XReadBitmapFile (dpy, Scr->Root, bigname, widthp, heightp,
454 				     &pm, &HotX, &HotY) != BitmapSuccess)
455 		    pm = None;
456 		    if (shape_mask)
457 			*shape_mask = None;
458 		break;
459 	}  /* switch */
460 #else
461 	if (XReadBitmapFile (dpy, Scr->Root, bigname, widthp, heightp,
462 			     &pm, &HotX, &HotY) != BitmapSuccess)
463 	    pm = None;
464         if (shape_mask)
465 	    *shape_mask = None;
466 #endif  /* XPM */
467 
468     }  /* if */
469     if (bigname != name) free (bigname);
470     if (pm == None) {
471 #ifndef SHAPE
472 	fprintf (stderr, "%s:  unable to find bitmap \"%s\"\n",
473 		 ProgramName, name);
474 #else
475 	int l = strlen(name);
476 
477         if (l <=4 || ((strncmp(&name[l-3],"clp",3) != 0) &&
478 		      (strncmp(&name[l-3],"msk",3) != 0))    ) {
479 		fprintf (stderr, "%s:  unable to find bitmap \"%s\"\n",
480 		 	ProgramName, name);
481 	}
482 #endif
483     }
484 
485 #ifdef XPM
486     XpmFreeAttributes(&attribs);
487 #endif
488     return pm;
489 }
490 
GetPixmap(name)491 Pixmap GetPixmap (name)
492     char *name;
493 {
494     return FindPixmap (name, &JunkWidth, &JunkHeight, JunkIsXpm, NULL,
495 			NULL, 0, NULL);
496 }
497 
498 
InsertRGBColormap(a,maps,nmaps,replace)499 InsertRGBColormap (a, maps, nmaps, replace)
500     Atom a;
501     XStandardColormap *maps;
502     int nmaps;
503     Bool replace;
504 {
505     StdCmap *sc = NULL;
506 
507     if (replace) {			/* locate existing entry */
508 	for (sc = Scr->StdCmapInfo.head; sc; sc = sc->next) {
509 	    if (sc->atom == a) break;
510 	}
511     }
512 
513     if (!sc) {				/* no existing, allocate new */
514 	sc = (StdCmap *) malloc (sizeof (StdCmap));
515 	if (!sc) {
516 	    fprintf (stderr, "%s:  unable to allocate %d bytes for StdCmap\n",
517 		     ProgramName, sizeof (StdCmap));
518 	    return;
519 	}
520     }
521 
522     if (replace) {			/* just update contents */
523 	if (sc->maps) XFree ((char *) maps);
524 	if (sc == Scr->StdCmapInfo.mru) Scr->StdCmapInfo.mru = NULL;
525     } else {				/* else appending */
526 	sc->next = NULL;
527 	sc->atom = a;
528 	if (Scr->StdCmapInfo.tail) {
529 	    Scr->StdCmapInfo.tail->next = sc;
530 	} else {
531 	    Scr->StdCmapInfo.head = sc;
532 	}
533 	Scr->StdCmapInfo.tail = sc;
534     }
535     sc->nmaps = nmaps;
536     sc->maps = maps;
537 
538     return;
539 }
540 
RemoveRGBColormap(a)541 RemoveRGBColormap (a)
542     Atom a;
543 {
544     StdCmap *sc, *prev;
545 
546     prev = NULL;
547     for (sc = Scr->StdCmapInfo.head; sc; sc = sc->next) {
548 	if (sc->atom == a) break;
549 	prev = sc;
550     }
551     if (sc) {				/* found one */
552 	if (sc->maps) XFree ((char *) sc->maps);
553 	if (prev) prev->next = sc->next;
554 	if (Scr->StdCmapInfo.head == sc) Scr->StdCmapInfo.head = sc->next;
555 	if (Scr->StdCmapInfo.tail == sc) Scr->StdCmapInfo.tail = prev;
556 	if (Scr->StdCmapInfo.mru == sc) Scr->StdCmapInfo.mru = NULL;
557     }
558     return;
559 }
560 
LocateStandardColormaps()561 LocateStandardColormaps()
562 {
563     Atom *atoms;
564     int natoms;
565     int i;
566 
567     atoms = XListProperties (dpy, Scr->Root, &natoms);
568     for (i = 0; i < natoms; i++) {
569 	XStandardColormap *maps = NULL;
570 	int nmaps;
571 
572 	if (XGetRGBColormaps (dpy, Scr->Root, &maps, &nmaps, atoms[i])) {
573 	    /* if got one, then append to current list */
574 	    InsertRGBColormap (atoms[i], maps, nmaps, False);
575 	}
576     }
577     if (atoms) XFree ((char *) atoms);
578     return;
579 }
580 
581 int
GetColor(kind,what,name)582 GetColor(kind, what, name)
583 int kind;
584 Pixel *what;
585 char *name;
586 {
587     XColor color, junkcolor;
588     Status stat = 0;
589     Colormap cmap = Scr->TwmRoot.cmaps.cwins[0]->colormap->c;
590 
591     if (Scr->Monochrome != kind)
592 	return FALSE;
593 
594     if (!XAllocNamedColor (dpy, cmap, name, &color, &junkcolor))
595     {
596 	/* if we could not allocate the color, let's see if this is a
597 	 * standard colormap
598 	 */
599 	XStandardColormap *stdcmap = NULL;
600 
601 	/* parse the named color */
602 	if (name[0] != '#')
603 	    stat = XParseColor (dpy, cmap, name, &color);
604 	if (!stat)
605 	{
606 	    fprintf (stderr, "%s:  invalid color name \"%s\"\n",
607 		     ProgramName, name);
608 	    return FALSE;
609 	}
610 
611 	/*
612 	 * look through the list of standard colormaps (check cache first)
613 	 */
614 	if (Scr->StdCmapInfo.mru && Scr->StdCmapInfo.mru->maps &&
615 	    (Scr->StdCmapInfo.mru->maps[Scr->StdCmapInfo.mruindex].colormap ==
616 	     cmap)) {
617 	    stdcmap = &(Scr->StdCmapInfo.mru->maps[Scr->StdCmapInfo.mruindex]);
618 	} else {
619 	    StdCmap *sc;
620 
621 	    for (sc = Scr->StdCmapInfo.head; sc; sc = sc->next) {
622 		int i;
623 
624 		for (i = 0; i < sc->nmaps; i++) {
625 		    if (sc->maps[i].colormap == cmap) {
626 			Scr->StdCmapInfo.mru = sc;
627 			Scr->StdCmapInfo.mruindex = i;
628 			stdcmap = &(sc->maps[i]);
629 			goto gotit;
630 		    }
631 		}
632 	    }
633 	}
634 
635       gotit:
636 	if (stdcmap) {
637             color.pixel = (stdcmap->base_pixel +
638 			   ((Pixel)(((float)color.red / 65535.0) *
639 				    stdcmap->red_max + 0.5) *
640 			    stdcmap->red_mult) +
641 			   ((Pixel)(((float)color.green /65535.0) *
642 				    stdcmap->green_max + 0.5) *
643 			    stdcmap->green_mult) +
644 			   ((Pixel)(((float)color.blue  / 65535.0) *
645 				    stdcmap->blue_max + 0.5) *
646 			    stdcmap->blue_mult));
647         } else {
648 	    fprintf (stderr, "%s:  unable to allocate color \"%s\"\n",
649 		     ProgramName, name);
650 	    return FALSE;
651 	}
652     }
653 
654     *what = color.pixel;
655     return TRUE;
656 }
657 
GetFont(font)658 GetFont(font)
659 MyFont *font;
660 {
661     char *deffontname = "fixed";
662 
663     if (font->font != NULL)
664 	XFreeFont(dpy, font->font);
665 
666     if ((font->font = XLoadQueryFont(dpy, font->name)) == NULL)
667     {
668 	if (Scr->DefaultFont.name) {
669 	    deffontname = Scr->DefaultFont.name;
670 	}
671 	if ((font->font = XLoadQueryFont(dpy, deffontname)) == NULL)
672 	{
673 	    fprintf (stderr, "%s:  unable to open fonts \"%s\" or \"%s\"\n",
674 		     ProgramName, font->name, deffontname);
675 	    exit(1);
676 	}
677 
678     }
679     font->height = font->font->ascent + font->font->descent;
680     font->y = font->font->ascent;
681 }
682 
683 
684 /*
685  * SetFocus - separate routine to set focus to make things more understandable
686  * and easier to debug
687  */
SetFocus(tmp_win,time)688 SetFocus (tmp_win, time)
689     TwmWindow *tmp_win;
690     Time      time;
691 {
692     Window w = (tmp_win ? tmp_win->w : PointerRoot);
693 
694 #ifdef TRACE
695     if (tmp_win) {
696 	printf ("Focusing on window \"%s\"\n", tmp_win->full_name);
697     } else {
698 	printf ("Unfocusing; Scr->Focus was \"%s\"\n",
699 		Scr->Focus ? Scr->Focus->full_name : "(nil)");
700     }
701 #endif
702 
703     XSetInputFocus (dpy, w, RevertToPointerRoot, time);
704 }
705 
706 
707 #ifdef NOPUTENV
708 /*
709  * define our own putenv() if the system doesn't have one.
710  * putenv(s): place s (a string of the form "NAME=value") in
711  * the environment; replacing any existing NAME.  s is placed in
712  * environment, so if you change s, the environment changes (like
713  * putenv on a sun).  Binding removed if you putenv something else
714  * called NAME.
715  */
716 int
putenv(s)717 putenv(s)
718     char *s;
719 {
720     char *v;
721     int varlen, idx;
722     extern char **environ;
723     char **newenv;
724     static int virgin = 1; /* true while "environ" is a virgin */
725 
726     v = index(s, '=');
727     if(v == 0)
728 	return 0; /* punt if it's not of the right form */
729     varlen = (v + 1) - s;
730 
731     for (idx = 0; environ[idx] != 0; idx++) {
732 	if (strncmp(environ[idx], s, varlen) == 0) {
733 	    if(v[1] != 0) { /* true if there's a value */
734 		environ[idx] = s;
735 		return 0;
736 	    } else {
737 		do {
738 		    environ[idx] = environ[idx+1];
739 		} while(environ[++idx] != 0);
740 		return 0;
741 	    }
742 	}
743     }
744 
745     /* add to environment (unless no value; then just return) */
746     if(v[1] == 0)
747 	return 0;
748     if(virgin) {
749 	register i;
750 
751 	newenv = (char **) malloc((unsigned) ((idx + 2) * sizeof(char*)));
752 	if(newenv == 0)
753 	    return -1;
754 	for(i = idx-1; i >= 0; --i)
755 	    newenv[i] = environ[i];
756 	virgin = 0;     /* you're not a virgin anymore, sweety */
757     } else {
758 	newenv = (char **) realloc((char *) environ,
759 				   (unsigned) ((idx + 2) * sizeof(char*)));
760 	if (newenv == 0)
761 	    return -1;
762     }
763 
764     environ = newenv;
765     environ[idx] = s;
766     environ[idx+1] = 0;
767 
768     return 0;
769 }
770 #endif /* NOPUTENV */
771 
772 
CreateXLogoPixmap(widthp,heightp)773 static Pixmap CreateXLogoPixmap (widthp, heightp)
774     unsigned int *widthp, *heightp;
775 {
776     int h = Scr->TBInfo.width - Scr->TBInfo.border * 2;
777     if (h < 0) h = 0;
778 
779     *widthp = *heightp = (unsigned int) h;
780     if (Scr->tbpm.xlogo == None) {
781 	GC gc, gcBack;
782 
783 	Scr->tbpm.xlogo = XCreatePixmap (dpy, Scr->Root, h, h, 1);
784 	gc = XCreateGC (dpy, Scr->tbpm.xlogo, 0L, NULL);
785 	XSetForeground (dpy, gc, 0);
786 	XFillRectangle (dpy, Scr->tbpm.xlogo, gc, 0, 0, h, h);
787 	XSetForeground (dpy, gc, 1);
788 	gcBack = XCreateGC (dpy, Scr->tbpm.xlogo, 0L, NULL);
789 	XSetForeground (dpy, gcBack, 0);
790 
791 	/*
792 	 * draw the logo large so that it gets as dense as possible; then white
793 	 * out the edges so that they look crisp
794 	 */
795 	XmuDrawLogo (dpy, Scr->tbpm.xlogo, gc, gcBack, -1, -1, h + 2, h + 2);
796 	XDrawRectangle (dpy, Scr->tbpm.xlogo, gcBack, 0, 0, h - 1, h - 1);
797 
798 	/*
799 	 * done drawing
800 	 */
801 	XFreeGC (dpy, gc);
802 	XFreeGC (dpy, gcBack);
803     }
804     return Scr->tbpm.xlogo;
805 }
806 
807 
CreateResizePixmap(widthp,heightp)808 static Pixmap CreateResizePixmap (widthp, heightp)
809     unsigned int *widthp, *heightp;
810 {
811     int h = Scr->TBInfo.width - Scr->TBInfo.border * 2;
812     if (h < 1) h = 1;
813 
814     *widthp = *heightp = (unsigned int) h;
815     if (Scr->tbpm.resize == None) {
816 	XPoint	points[3];
817 	GC gc;
818 	int w;
819 	int lw;
820 
821 	/*
822 	 * create the pixmap
823 	 */
824 	Scr->tbpm.resize = XCreatePixmap (dpy, Scr->Root, h, h, 1);
825 	gc = XCreateGC (dpy, Scr->tbpm.resize, 0L, NULL);
826 	XSetForeground (dpy, gc, 0);
827 	XFillRectangle (dpy, Scr->tbpm.resize, gc, 0, 0, h, h);
828 	XSetForeground (dpy, gc, 1);
829 	lw = h / 16;
830 	if (lw == 1)
831 	    lw = 0;
832 	XSetLineAttributes (dpy, gc, lw, LineSolid, CapButt, JoinMiter);
833 
834 	/*
835 	 * draw the resize button,
836 	 */
837 	w = (h * 2) / 3;
838 	points[0].x = w;
839 	points[0].y = 0;
840 	points[1].x = w;
841 	points[1].y = w;
842 	points[2].x = 0;
843 	points[2].y = w;
844 	XDrawLines (dpy, Scr->tbpm.resize, gc, points, 3, CoordModeOrigin);
845 	w = w / 2;
846 	points[0].x = w;
847 	points[0].y = 0;
848 	points[1].x = w;
849 	points[1].y = w;
850 	points[2].x = 0;
851 	points[2].y = w;
852 	XDrawLines (dpy, Scr->tbpm.resize, gc, points, 3, CoordModeOrigin);
853 
854 	/*
855 	 * done drawing
856 	 */
857 	XFreeGC(dpy, gc);
858     }
859     return Scr->tbpm.resize;
860 }
861 
862 
CreateDotPixmap(widthp,heightp)863 static Pixmap CreateDotPixmap (widthp, heightp)
864     unsigned int *widthp, *heightp;
865 {
866     int h = Scr->TBInfo.width - Scr->TBInfo.border * 2;
867 
868     h = h * 3 / 4;
869     if (h < 1) h = 1;
870     if (!(h & 1))
871 	h--;
872     *widthp = *heightp = (unsigned int) h;
873     if (Scr->tbpm.delete == None) {
874 	GC  gc;
875 	Pixmap pix;
876 
877 	pix = Scr->tbpm.delete = XCreatePixmap (dpy, Scr->Root, h, h, 1);
878 	gc = XCreateGC (dpy, pix, 0L, NULL);
879 	XSetLineAttributes (dpy, gc, h, LineSolid, CapRound, JoinRound);
880 	XSetForeground (dpy, gc, 0L);
881 	XFillRectangle (dpy, pix, gc, 0, 0, h, h);
882 	XSetForeground (dpy, gc, 1L);
883 	XDrawLine (dpy, pix, gc, h/2, h/2, h/2, h/2);
884 	XFreeGC (dpy, gc);
885     }
886     return Scr->tbpm.delete;
887 }
888 
889 #define questionmark_width 8
890 #define questionmark_height 8
891 static char questionmark_bits[] = {
892    0x38, 0x7c, 0x64, 0x30, 0x18, 0x00, 0x18, 0x18};
893 
CreateQuestionPixmap(widthp,heightp)894 static Pixmap CreateQuestionPixmap (widthp, heightp)
895     unsigned int *widthp, *heightp;
896 {
897     *widthp = questionmark_width;
898     *heightp = questionmark_height;
899     if (Scr->tbpm.question == None) {
900 	Scr->tbpm.question = XCreateBitmapFromData (dpy, Scr->Root,
901 						    questionmark_bits,
902 						    questionmark_width,
903 						    questionmark_height);
904     }
905     /*
906      * this must succeed or else we are in deep trouble elsewhere
907      */
908     return Scr->tbpm.question;
909 }
910 
911 
CreateMenuPixmap(widthp,heightp)912 static Pixmap CreateMenuPixmap (widthp, heightp)
913     int *widthp, *heightp;
914 {
915     CreateMenuIcon (Scr->TBInfo.width - Scr->TBInfo.border * 2,widthp,heightp);
916 }
917 
CreateMenuIcon(height,widthp,heightp)918 Pixmap CreateMenuIcon (height, widthp, heightp)
919     int	height;
920     int	*widthp, *heightp;
921 {
922     int h, w;
923     int ih, iw;
924     int	ix, iy;
925     int	mh, mw;
926     int	tw, th;
927     int	lw, lh;
928     int	lx, ly;
929     int	lines, dly;
930     int off;
931     int	bw;
932 
933     h = height;
934     w = h * 7 / 8;
935     if (h < 1)
936 	h = 1;
937     if (w < 1)
938 	w = 1;
939     *widthp = w;
940     *heightp = h;
941     if (Scr->tbpm.menu == None) {
942 	Pixmap  pix;
943 	GC	gc;
944 
945 	pix = Scr->tbpm.menu = XCreatePixmap (dpy, Scr->Root, w, h, 1);
946 	gc = XCreateGC (dpy, pix, 0L, NULL);
947 	XSetForeground (dpy, gc, 0L);
948 	XFillRectangle (dpy, pix, gc, 0, 0, w, h);
949 	XSetForeground (dpy, gc, 1L);
950 	ix = 1;
951 	iy = 1;
952 	ih = h - iy * 2;
953 	iw = w - ix * 2;
954 	off = ih / 8;
955 	mh = ih - off;
956 	mw = iw - off;
957 	bw = mh / 16;
958 	if (bw == 0 && mw > 2)
959 	    bw = 1;
960 	tw = mw - bw * 2;
961 	th = mh - bw * 2;
962 	XFillRectangle (dpy, pix, gc, ix, iy, mw, mh);
963 	XFillRectangle (dpy, pix, gc, ix + iw - mw, iy + ih - mh, mw, mh);
964 	XSetForeground (dpy, gc, 0L);
965 	XFillRectangle (dpy, pix, gc, ix+bw, iy+bw, tw, th);
966 	XSetForeground (dpy, gc, 1L);
967 	lw = tw / 2;
968 	if ((tw & 1) ^ (lw & 1))
969 	    lw++;
970 	lx = ix + bw + (tw - lw) / 2;
971 
972 	lh = th / 2 - bw;
973 	if ((lh & 1) ^ ((th - bw) & 1))
974 	    lh++;
975 	ly = iy + bw + (th - bw - lh) / 2;
976 
977 	lines = 3;
978 	if ((lh & 1) && lh < 6)
979 	{
980 	    lines--;
981 	}
982 	dly = lh / (lines - 1);
983 	while (lines--)
984 	{
985 	    XFillRectangle (dpy, pix, gc, lx, ly, lw, bw);
986 	    ly += dly;
987 	}
988 	XFreeGC (dpy, gc);
989     }
990     return Scr->tbpm.menu;
991 }
992 
993 /********************************************************************
994  *
995  * GetPropertyString -
996  *	This function gets a string for the value of a property.
997  * For text valued ones, it returns a string containing all of the
998  * values, separated by newlines.  For atoms, it returns a string
999  * of the names of the atoms, again separated by newlines.  Any other
1000  * type just returns a boring string.  It returns NULL if the
1001  * property is not defined.
1002  */
1003 
1004 #define MAX_NUM 20
1005 
1006 char *
GetPropertyString(win,atom)1007 GetPropertyString(win, atom)
1008 Window win;
1009 Atom atom;
1010 {
1011     Atom actual_type;
1012     int actual_format;
1013     unsigned long nitems;
1014     unsigned long bytes_after;
1015     unsigned char *value;
1016     int status;
1017     char *s;
1018 
1019     if (XGetWindowProperty(dpy, win, atom, 0, (MAX_NUM+3)/4,
1020 			False, AnyPropertyType, &actual_type,
1021 			&actual_format, &nitems, &bytes_after,
1022 			&value) != Success)
1023 	return NULL;
1024 
1025     switch (actual_type) {
1026 	case None:
1027 	    XFree(value);
1028 	    return NULL;
1029 	case XA_STRING: {
1030 	    XTextProperty prop;
1031 	    char **list;
1032 	    int n, l, i;
1033 
1034 	    prop.value = value;
1035 	    prop.encoding = XA_STRING;
1036 	    prop.format = actual_format;
1037 	    prop.nitems = nitems;
1038 
1039 	    if (!XTextPropertyToStringList(&prop, &list, &n))
1040 		return NULL;
1041 
1042 	    l = 0;
1043 	    for (i = 0; i < n; i++)
1044 		l += strlen(list[i]);
1045 
1046 	    s = (char *)malloc(l + n + 1);
1047 	    *s = '\0';
1048 
1049 	    for (i = 0; i < n; i++) {
1050 		strcat(s, list[i]);
1051 		if (i < n-1)
1052 		   strcat(s, "\n");
1053 	    }
1054 
1055 	    XFreeStringList(list);
1056 	    }
1057 	    break;
1058 	case XA_ATOM: {
1059 	    int l, i;
1060 	    char **list = (char **)malloc(sizeof(char *) * nitems);
1061 	    Atom *atoms = (Atom *)value;
1062 
1063 	    for (i = 0; i < nitems ; i++)
1064 		list[i] = XGetAtomName(dpy, atoms[i]);
1065 
1066 	    l = 0;
1067 	    for (i = 0 ; i < nitems ; i++)
1068 		l += strlen(list[i]);
1069 
1070 	    s = (char *)malloc(l + nitems + 1);
1071 	    *s = '\0';
1072 
1073 	    for (i = 0; i < nitems ; i++) {
1074 		strcat(s, list[i]);
1075 		XFree(list[i]);
1076 		if (i < nitems-1)
1077 		    strcat(s, "\n");
1078 	    }
1079 
1080 	    free(list);
1081 	    }
1082 	    break;
1083 	default:
1084 	    s = (char *)malloc(15);
1085 	    strcpy(s, "<Something>");
1086     }
1087 
1088     XFree(value);
1089 
1090     return s;
1091 }
1092