util.c revision 7a2631fc
1/*****************************************************************************/
2/*
3
4Copyright 1989, 1998  The Open Group
5
6Permission to use, copy, modify, distribute, and sell this software and its
7documentation for any purpose is hereby granted without fee, provided that
8the above copyright notice appear in all copies and that both that
9copyright notice and this permission notice appear in supporting
10documentation.
11
12The above copyright notice and this permission notice shall be included in
13all copies or substantial portions of the Software.
14
15THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
18OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
19AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
22Except as contained in this notice, the name of The Open Group shall not be
23used in advertising or otherwise to promote the sale, use or other dealings
24in this Software without prior written authorization from The Open Group.
25
26*/
27/**       Copyright 1988 by Evans & Sutherland Computer Corporation,        **/
28/**                          Salt Lake City, Utah                           **/
29/**                        Cambridge, Massachusetts                         **/
30/**                                                                         **/
31/**                           All Rights Reserved                           **/
32/**                                                                         **/
33/**    Permission to use, copy, modify, and distribute this software and    **/
34/**    its documentation  for  any  purpose  and  without  fee is hereby    **/
35/**    granted, provided that the above copyright notice appear  in  all    **/
36/**    copies and that both  that  copyright  notice  and  this  permis-    **/
37/**    sion  notice appear in supporting  documentation,  and  that  the    **/
38/**    name of Evans & Sutherland not be used in advertising    **/
39/**    in publicity pertaining to distribution of the  software  without    **/
40/**    specific, written prior permission.                                  **/
41/**                                                                         **/
42/**    EVANS & SUTHERLAND DISCLAIMs ALL WARRANTIES WITH REGARD    **/
43/**    TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES  OF  MERCHANT-    **/
44/**    ABILITY  AND  FITNESS,  IN  NO  EVENT SHALL EVANS & SUTHERLAND    **/
45/**    BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL  DAM-    **/
46/**    AGES OR  ANY DAMAGES WHATSOEVER  RESULTING FROM LOSS OF USE, DATA    **/
47/**    OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER    **/
48/**    TORTIOUS ACTION, ARISING OUT OF OR IN  CONNECTION  WITH  THE  USE    **/
49/**    OR PERFORMANCE OF THIS SOFTWARE.                                     **/
50/*****************************************************************************/
51
52
53/***********************************************************************
54 *
55 * utility routines for twm
56 *
57 * 28-Oct-87 Thomas E. LaStrange	File created
58 *
59 ***********************************************************************/
60
61#include "twm.h"
62#include "util.h"
63#include "gram.h"
64#include "screen.h"
65#include <X11/Xos.h>
66#include <X11/Xatom.h>
67#include <stdio.h>
68#include <X11/Xmu/Drawing.h>
69#include <X11/Xmu/CharSet.h>
70
71static Pixmap CreateXLogoPixmap ( unsigned int *widthp,
72				  unsigned int *heightp );
73static Pixmap CreateResizePixmap ( unsigned int *widthp,
74				   unsigned int *heightp );
75static Pixmap CreateDotPixmap ( unsigned int *widthp,
76				unsigned int *heightp );
77static Pixmap CreateQuestionPixmap ( unsigned int *widthp,
78				     unsigned int *heightp );
79static Pixmap CreateMenuPixmap ( unsigned int *widthp,
80				 unsigned int *heightp );
81
82int HotX, HotY;
83
84/**
85 * move a window outline
86 *
87 *  \param root         window we are outlining
88 *  \param x,y          upper left coordinate
89 *  \param width,height size of the rectangle
90 *  \param bw           border width of the frame
91 *  \param th           title height
92 */
93void MoveOutline(Window root, int x, int y, int width, int height, int bw, int th)
94{
95    static int	lastx = 0;
96    static int	lasty = 0;
97    static int	lastWidth = 0;
98    static int	lastHeight = 0;
99    static int	lastBW = 0;
100    static int	lastTH = 0;
101    int		xl, xr, yt, yb, xinnerl, xinnerr, yinnert, yinnerb;
102    int		xthird, ythird;
103    XSegment	outline[18];
104    register XSegment	*r;
105
106    if (x == lastx && y == lasty && width == lastWidth && height == lastHeight
107	&& lastBW == bw && th == lastTH)
108	return;
109
110    r = outline;
111
112#define DRAWIT() \
113    if (lastWidth || lastHeight)			\
114    {							\
115	xl = lastx;					\
116	xr = lastx + lastWidth - 1;			\
117	yt = lasty;					\
118	yb = lasty + lastHeight - 1;			\
119	xinnerl = xl + lastBW;				\
120	xinnerr = xr - lastBW;				\
121	yinnert = yt + lastTH + lastBW;			\
122	yinnerb = yb - lastBW;				\
123	xthird = (xinnerr - xinnerl) / 3;		\
124	ythird = (yinnerb - yinnert) / 3;		\
125							\
126	r->x1 = xl;					\
127	r->y1 = yt;					\
128	r->x2 = xr;					\
129	r->y2 = yt;					\
130	r++;						\
131							\
132	r->x1 = xl;					\
133	r->y1 = yb;					\
134	r->x2 = xr;					\
135	r->y2 = yb;					\
136	r++;						\
137							\
138	r->x1 = xl;					\
139	r->y1 = yt;					\
140	r->x2 = xl;					\
141	r->y2 = yb;					\
142	r++;						\
143							\
144	r->x1 = xr;					\
145	r->y1 = yt;					\
146	r->x2 = xr;					\
147	r->y2 = yb;					\
148	r++;						\
149							\
150	r->x1 = xinnerl + xthird;			\
151	r->y1 = yinnert;				\
152	r->x2 = r->x1;					\
153	r->y2 = yinnerb;				\
154	r++;						\
155							\
156	r->x1 = xinnerl + (2 * xthird);			\
157	r->y1 = yinnert;				\
158	r->x2 = r->x1;					\
159	r->y2 = yinnerb;				\
160	r++;						\
161							\
162	r->x1 = xinnerl;				\
163	r->y1 = yinnert + ythird;			\
164	r->x2 = xinnerr;				\
165	r->y2 = r->y1;					\
166	r++;						\
167							\
168	r->x1 = xinnerl;				\
169	r->y1 = yinnert + (2 * ythird);			\
170	r->x2 = xinnerr;				\
171	r->y2 = r->y1;					\
172	r++;						\
173							\
174	if (lastTH != 0) {				\
175	    r->x1 = xl;					\
176	    r->y1 = yt + lastTH;			\
177	    r->x2 = xr;					\
178	    r->y2 = r->y1;				\
179	    r++;					\
180	}						\
181    }
182
183    /* undraw the old one, if any */
184    DRAWIT ();
185
186    lastx = x;
187    lasty = y;
188    lastWidth = width;
189    lastHeight = height;
190    lastBW = bw;
191    lastTH = th;
192
193    /* draw the new one, if any */
194    DRAWIT ();
195
196#undef DRAWIT
197
198
199    if (r != outline)
200    {
201	XDrawSegments(dpy, root, Scr->DrawGC, outline, r - outline);
202    }
203}
204
205/**
206 * zoom in or out of an icon
207 *
208 *  \param wf window to zoom from
209 *  \param wt window to zoom to
210 */
211void
212Zoom(Window wf, Window wt)
213{
214    int fx, fy, tx, ty;			/* from, to */
215    unsigned int fw, fh, tw, th;	/* from, to */
216    long dx, dy, dw, dh;
217    long z;
218    int j;
219
220    if (!Scr->DoZoom || Scr->ZoomCount < 1) return;
221
222    if (wf == None || wt == None) return;
223
224    XGetGeometry (dpy, wf, &JunkRoot, &fx, &fy, &fw, &fh, &JunkBW, &JunkDepth);
225    XGetGeometry (dpy, wt, &JunkRoot, &tx, &ty, &tw, &th, &JunkBW, &JunkDepth);
226
227    dx = ((long) (tx - fx));	/* going from -> to */
228    dy = ((long) (ty - fy));	/* going from -> to */
229    dw = ((long) (tw - fw));	/* going from -> to */
230    dh = ((long) (th - fh));	/* going from -> to */
231    z = (long) (Scr->ZoomCount + 1);
232
233    for (j = 0; j < 2; j++) {
234	long i;
235
236	XDrawRectangle (dpy, Scr->Root, Scr->DrawGC, fx, fy, fw, fh);
237	for (i = 1; i < z; i++) {
238	    int x = fx + (int) ((dx * i) / z);
239	    int y = fy + (int) ((dy * i) / z);
240	    unsigned width = (unsigned) (((long) fw) + (dw * i) / z);
241	    unsigned height = (unsigned) (((long) fh) + (dh * i) / z);
242
243	    XDrawRectangle (dpy, Scr->Root, Scr->DrawGC,
244			    x, y, width, height);
245	}
246	XDrawRectangle (dpy, Scr->Root, Scr->DrawGC, tx, ty, tw, th);
247    }
248}
249
250/**
251 * expand the tilde character to HOME if it is the first
252 * character of the filename
253 *
254 *	\return a pointer to the new name
255 *
256 *  \param name  the filename to expand
257 */
258char *
259ExpandFilename(char *name)
260{
261    char *newname;
262
263    if (name[0] != '~') return name;
264
265    newname = (char *) malloc (HomeLen + strlen(name) + 2);
266    if (!newname) {
267	fprintf (stderr,
268		 "%s:  unable to allocate %ld bytes to expand filename %s/%s\n",
269		 ProgramName, HomeLen + (unsigned long)strlen(name) + 2,
270		 Home, &name[1]);
271    } else {
272	(void) sprintf (newname, "%s/%s", Home, &name[1]);
273    }
274
275    return newname;
276}
277
278/**
279 * read in the bitmap file for the unknown icon
280 *
281 * \param name  the filename to read
282 */
283void
284GetUnknownIcon(char *name)
285{
286    if ((Scr->UnknownPm = GetBitmap(name)) != None)
287    {
288	XGetGeometry(dpy, Scr->UnknownPm, &JunkRoot, &JunkX, &JunkY,
289	    (unsigned int *)&Scr->UnknownWidth, (unsigned int *)&Scr->UnknownHeight, &JunkBW, &JunkDepth);
290    }
291}
292
293/**
294 *	FindBitmap - read in a bitmap file and return size
295 *
296 *  \return pixmap associated with bitmap
297 *
298 *  \param name          filename to read
299 *  \param[out] widthp   pointer to width of bitmap
300 *  \param[out] heightp	 pointer to height of bitmap
301 */
302Pixmap
303FindBitmap (char *name, unsigned *widthp, unsigned *heightp)
304{
305    char *bigname;
306    Pixmap pm;
307
308    if (!name) return None;
309
310    /*
311     * Names of the form :name refer to hardcoded images that are scaled to
312     * look nice in title buttons.  Eventually, it would be nice to put in a
313     * menu symbol as well....
314     */
315    if (name[0] == ':') {
316	int i;
317	static struct {
318	    char *name;
319	    Pixmap (*proc)(unsigned int *, unsigned int *);
320	} pmtab[] = {
321	    { TBPM_DOT,		CreateDotPixmap },
322	    { TBPM_ICONIFY,	CreateDotPixmap },
323	    { TBPM_RESIZE,	CreateResizePixmap },
324	    { TBPM_XLOGO,	CreateXLogoPixmap },
325	    { TBPM_DELETE,	CreateXLogoPixmap },
326	    { TBPM_MENU,	CreateMenuPixmap },
327	    { TBPM_QUESTION,	CreateQuestionPixmap },
328	};
329
330	for (i = 0; i < (sizeof pmtab)/(sizeof pmtab[0]); i++) {
331	    if (XmuCompareISOLatin1 (pmtab[i].name, name) == 0)
332	      return (*pmtab[i].proc) (widthp, heightp);
333	}
334	fprintf (stderr, "%s:  no such built-in bitmap \"%s\"\n",
335		 ProgramName, name);
336	return None;
337    }
338
339    /*
340     * Generate a full pathname if any special prefix characters (such as ~)
341     * are used.  If the bigname is different from name, bigname will need to
342     * be freed.
343     */
344    bigname = ExpandFilename (name);
345    if (!bigname) return None;
346
347    /*
348     * look along bitmapFilePath resource same as toolkit clients
349     */
350    pm = XmuLocateBitmapFile (ScreenOfDisplay(dpy, Scr->screen), bigname, NULL,
351			      0, (int *)widthp, (int *)heightp, &HotX, &HotY);
352    if (pm == None && Scr->IconDirectory && bigname[0] != '/') {
353	if (bigname != name) free (bigname);
354	/*
355	 * Attempt to find icon in old IconDirectory (now obsolete)
356	 */
357	bigname = (char *) malloc (strlen(name) + strlen(Scr->IconDirectory) +
358				   2);
359	if (!bigname) {
360	    fprintf (stderr,
361		     "%s:  unable to allocate memory for \"%s/%s\"\n",
362		     ProgramName, Scr->IconDirectory, name);
363	    return None;
364	}
365	(void) sprintf (bigname, "%s/%s", Scr->IconDirectory, name);
366	if (XReadBitmapFile (dpy, Scr->Root, bigname, widthp, heightp, &pm,
367			     &HotX, &HotY) != BitmapSuccess) {
368	    pm = None;
369	}
370    }
371    if (bigname != name) free (bigname);
372    if (pm == None) {
373	fprintf (stderr, "%s:  unable to find bitmap \"%s\"\n",
374		 ProgramName, name);
375    }
376
377    return pm;
378}
379
380Pixmap
381GetBitmap (char *name)
382{
383    return FindBitmap (name, &JunkWidth, &JunkHeight);
384}
385
386void
387InsertRGBColormap (Atom a, XStandardColormap *maps, int nmaps, Bool replace)
388{
389    StdCmap *sc = NULL;
390
391    if (replace) {			/* locate existing entry */
392	for (sc = Scr->StdCmapInfo.head; sc; sc = sc->next) {
393	    if (sc->atom == a) break;
394	}
395    }
396
397    if (!sc) {				/* no existing, allocate new */
398	sc = (StdCmap *) malloc (sizeof (StdCmap));
399	if (!sc) {
400	    fprintf (stderr, "%s:  unable to allocate %ld bytes for StdCmap\n",
401		     ProgramName, (unsigned long)sizeof (StdCmap));
402	    return;
403	}
404    }
405
406    if (replace) {			/* just update contents */
407	if (sc->maps) XFree ((char *) maps);
408	if (sc == Scr->StdCmapInfo.mru) Scr->StdCmapInfo.mru = NULL;
409    } else {				/* else appending */
410	sc->next = NULL;
411	sc->atom = a;
412	if (Scr->StdCmapInfo.tail) {
413	    Scr->StdCmapInfo.tail->next = sc;
414	} else {
415	    Scr->StdCmapInfo.head = sc;
416	}
417	Scr->StdCmapInfo.tail = sc;
418    }
419    sc->nmaps = nmaps;
420    sc->maps = maps;
421
422    return;
423}
424
425void
426RemoveRGBColormap (Atom a)
427{
428    StdCmap *sc, *prev;
429
430    prev = NULL;
431    for (sc = Scr->StdCmapInfo.head; sc; sc = sc->next) {
432	if (sc->atom == a) break;
433	prev = sc;
434    }
435    if (sc) {				/* found one */
436	if (sc->maps) XFree ((char *) sc->maps);
437	if (prev) prev->next = sc->next;
438	if (Scr->StdCmapInfo.head == sc) Scr->StdCmapInfo.head = sc->next;
439	if (Scr->StdCmapInfo.tail == sc) Scr->StdCmapInfo.tail = prev;
440	if (Scr->StdCmapInfo.mru == sc) Scr->StdCmapInfo.mru = NULL;
441    }
442    return;
443}
444
445void
446LocateStandardColormaps()
447{
448    Atom *atoms;
449    int natoms;
450    int i;
451
452    atoms = XListProperties (dpy, Scr->Root, &natoms);
453    for (i = 0; i < natoms; i++) {
454	XStandardColormap *maps = NULL;
455	int nmaps;
456
457	if (XGetRGBColormaps (dpy, Scr->Root, &maps, &nmaps, atoms[i])) {
458	    /* if got one, then append to current list */
459	    InsertRGBColormap (atoms[i], maps, nmaps, False);
460	}
461    }
462    if (atoms) XFree ((char *) atoms);
463    return;
464}
465
466void
467GetColor(int kind, Pixel *what, char *name)
468{
469    XColor color, junkcolor;
470    Status stat = 0;
471    Colormap cmap = Scr->TwmRoot.cmaps.cwins[0]->colormap->c;
472
473#ifndef TOM
474    if (!Scr->FirstTime)
475	return;
476#endif
477
478    if (Scr->Monochrome != kind)
479	return;
480
481    if (!XAllocNamedColor (dpy, cmap, name, &color, &junkcolor))
482    {
483	/* if we could not allocate the color, let's see if this is a
484	 * standard colormap
485	 */
486	XStandardColormap *stdcmap = NULL;
487
488	/* parse the named color */
489	if (name[0] != '#')
490	    stat = XParseColor (dpy, cmap, name, &color);
491	if (!stat)
492	{
493	    fprintf (stderr, "%s:  invalid color name \"%s\"\n",
494		     ProgramName, name);
495	    return;
496	}
497
498	/*
499	 * look through the list of standard colormaps (check cache first)
500	 */
501	if (Scr->StdCmapInfo.mru && Scr->StdCmapInfo.mru->maps &&
502	    (Scr->StdCmapInfo.mru->maps[Scr->StdCmapInfo.mruindex].colormap ==
503	     cmap)) {
504	    stdcmap = &(Scr->StdCmapInfo.mru->maps[Scr->StdCmapInfo.mruindex]);
505	} else {
506	    StdCmap *sc;
507
508	    for (sc = Scr->StdCmapInfo.head; sc; sc = sc->next) {
509		int i;
510
511		for (i = 0; i < sc->nmaps; i++) {
512		    if (sc->maps[i].colormap == cmap) {
513			Scr->StdCmapInfo.mru = sc;
514			Scr->StdCmapInfo.mruindex = i;
515			stdcmap = &(sc->maps[i]);
516			goto gotit;
517		    }
518		}
519	    }
520	}
521
522      gotit:
523	if (stdcmap) {
524            color.pixel = (stdcmap->base_pixel +
525			   ((Pixel)(((float)color.red / 65535.0) *
526				    stdcmap->red_max + 0.5) *
527			    stdcmap->red_mult) +
528			   ((Pixel)(((float)color.green /65535.0) *
529				    stdcmap->green_max + 0.5) *
530			    stdcmap->green_mult) +
531			   ((Pixel)(((float)color.blue  / 65535.0) *
532				    stdcmap->blue_max + 0.5) *
533			    stdcmap->blue_mult));
534        } else {
535	    fprintf (stderr, "%s:  unable to allocate color \"%s\"\n",
536		     ProgramName, name);
537	    return;
538	}
539    }
540
541    *what = color.pixel;
542}
543
544void
545GetColorValue(int kind, XColor *what, char *name)
546{
547    XColor junkcolor;
548    Colormap cmap = Scr->TwmRoot.cmaps.cwins[0]->colormap->c;
549
550#ifndef TOM
551    if (!Scr->FirstTime)
552	return;
553#endif
554
555    if (Scr->Monochrome != kind)
556	return;
557
558    if (!XLookupColor (dpy, cmap, name, what, &junkcolor))
559    {
560	fprintf (stderr, "%s:  invalid color name \"%s\"\n",
561		 ProgramName, name);
562    }
563    else
564    {
565	what->pixel = AllPlanes;
566    }
567}
568
569/*
570 * The following functions are sensible to 'use_fontset'.
571 * When 'use_fontset' is True,
572 *  - XFontSet-related internationalized functions are used
573 *     so as multibyte languages can be displayed.
574 * When 'use_fontset' is False,
575 *  - XFontStruct-related conventional functions are used
576 *     so as 8-bit characters can be displayed even when
577 *     locale is not set properly.
578 */
579void
580GetFont(MyFont *font)
581{
582    char *deffontname = "fixed";
583    char **missing_charset_list_return;
584    int missing_charset_count_return;
585    char *def_string_return;
586    XFontSetExtents *font_extents;
587    XFontStruct **xfonts;
588    char **font_names;
589    register int i;
590    int ascent;
591    int descent;
592    int fnum;
593    char *basename2;
594
595    if (use_fontset) {
596	if (font->fontset != NULL){
597	    XFreeFontSet(dpy, font->fontset);
598	}
599
600	basename2 = (char *)malloc(strlen(font->name) + 3);
601	if (basename2) sprintf(basename2, "%s,*", font->name);
602	else basename2 = font->name;
603	if( (font->fontset = XCreateFontSet(dpy, basename2,
604					    &missing_charset_list_return,
605					    &missing_charset_count_return,
606					    &def_string_return)) == NULL) {
607	    fprintf (stderr, "%s:  unable to open fontset \"%s\"\n",
608			 ProgramName, font->name);
609	    exit(1);
610	}
611	if (basename2 != font->name) free(basename2);
612	for(i=0; i<missing_charset_count_return; i++){
613	    printf("%s: warning: font for charset %s is lacking.\n",
614		   ProgramName, missing_charset_list_return[i]);
615	}
616
617	font_extents = XExtentsOfFontSet(font->fontset);
618	fnum = XFontsOfFontSet(font->fontset, &xfonts, &font_names);
619	for( i = 0, ascent = 0, descent = 0; i<fnum; i++){
620	    if (ascent < (*xfonts)->ascent) ascent = (*xfonts)->ascent;
621	    if (descent < (*xfonts)->descent) descent = (*xfonts)->descent;
622	    xfonts++;
623	}
624	font->height = font_extents->max_logical_extent.height;
625	font->y = ascent;
626	font->ascent = ascent;
627	font->descent = descent;
628	return;
629    }
630
631    if (font->font != NULL)
632	XFreeFont(dpy, font->font);
633
634    if ((font->font = XLoadQueryFont(dpy, font->name)) == NULL)
635    {
636	if (Scr->DefaultFont.name) {
637	    deffontname = Scr->DefaultFont.name;
638	}
639	if ((font->font = XLoadQueryFont(dpy, deffontname)) == NULL)
640	{
641	    fprintf (stderr, "%s:  unable to open fonts \"%s\" or \"%s\"\n",
642		     ProgramName, font->name, deffontname);
643	    exit(1);
644	}
645
646    }
647    font->height = font->font->ascent + font->font->descent;
648    font->y = font->font->ascent;
649    font->ascent = font->font->ascent;
650    font->descent = font->font->descent;
651}
652
653int
654MyFont_TextWidth(MyFont *font, char *string, int len)
655{
656    XRectangle ink_rect;
657    XRectangle logical_rect;
658
659    if (use_fontset) {
660	XmbTextExtents(font->fontset, string, len,
661		       &ink_rect, &logical_rect);
662	return logical_rect.width;
663    }
664    return XTextWidth(font->font, string, len);
665}
666
667void
668MyFont_DrawImageString(Display *dpy, Drawable d, MyFont *font, GC gc,
669                       int x, int y, char *string, int len)
670{
671    if (use_fontset) {
672	XmbDrawImageString(dpy, d, font->fontset, gc, x, y, string, len);
673	return;
674    }
675    XDrawImageString (dpy, d, gc, x, y, string, len);
676}
677
678void
679MyFont_DrawString(Display *dpy, Drawable d, MyFont *font, GC gc,
680                  int x, int y, char *string, int len)
681{
682    if (use_fontset) {
683	XmbDrawString(dpy, d, font->fontset, gc, x, y, string, len);
684	return;
685    }
686    XDrawString (dpy, d, gc, x, y, string, len);
687}
688
689void
690MyFont_ChangeGC(unsigned long fix_fore, unsigned long fix_back,
691                MyFont *fix_font)
692{
693    Gcv.foreground = fix_fore;
694    Gcv.background = fix_back;
695    if (use_fontset) {
696	XChangeGC(dpy, Scr->NormalGC, GCForeground|GCBackground, &Gcv);
697	return;
698    }
699    Gcv.font = fix_font->font->fid;
700    XChangeGC(dpy, Scr->NormalGC, GCFont|GCForeground|GCBackground,&Gcv);
701}
702
703/*
704 * The following functions are internationalized substitutions
705 * for XFetchName and XGetIconName using XGetWMName and
706 * XGetWMIconName.
707 *
708 * Please note that the third arguments have to be freed using free(),
709 * not XFree().
710 */
711Status
712I18N_FetchName(Display *dpy, Window w, char **winname)
713{
714    int    status;
715    XTextProperty text_prop;
716    char **list;
717    int    num;
718
719    status = XGetWMName(dpy, w, &text_prop);
720    if (!status || !text_prop.value || !text_prop.nitems) {
721      *winname = NULL;
722      return 0;
723    }
724    status = XmbTextPropertyToTextList(dpy, &text_prop, &list, &num);
725    if (status < Success || !num || !*list) {
726      *winname = NULL;
727      return 0;
728    }
729    XFree(text_prop.value);
730    *winname = (char *)strdup(*list);
731    XFreeStringList(list);
732    return 1;
733}
734
735Status
736I18N_GetIconName(Display *dpy, Window w, char **iconname)
737{
738    int    status;
739    XTextProperty text_prop;
740    char **list;
741    int    num;
742
743    status = XGetWMIconName(dpy, w, &text_prop);
744    if (!status || !text_prop.value || !text_prop.nitems) return 0;
745    status = XmbTextPropertyToTextList(dpy, &text_prop, &list, &num);
746    if (status < Success || !num || !*list) return 0;
747    XFree(text_prop.value);
748    *iconname = (char *)strdup(*list);
749    XFreeStringList(list);
750    return 1;
751}
752
753/**
754 * separate routine to set focus to make things more understandable
755 * and easier to debug
756 */
757void
758SetFocus (TwmWindow *tmp_win, Time time)
759{
760    Window w = (tmp_win ? tmp_win->w : PointerRoot);
761
762#ifdef TRACE
763    if (tmp_win) {
764	printf ("Focusing on window \"%s\"\n", tmp_win->full_name);
765    } else {
766	printf ("Unfocusing; Scr->Focus was \"%s\"\n",
767		Scr->Focus ? Scr->Focus->full_name : "(nil)");
768    }
769#endif
770
771    XSetInputFocus (dpy, w, RevertToPointerRoot, time);
772}
773
774
775#ifdef NOPUTENV
776/**
777 * define our own putenv() if the system doesn't have one.
778 * putenv(s): place s (a string of the form "NAME=value") in
779 * the environment; replacing any existing NAME.  s is placed in
780 * environment, so if you change s, the environment changes (like
781 * putenv on a sun).  Binding removed if you putenv something else
782 * called NAME.
783 */
784int
785putenv(char *s)
786{
787    char *v;
788    int varlen, idx;
789    extern char **environ;
790    char **newenv;
791    static int virgin = 1; /* true while "environ" is a virgin */
792
793    v = index(s, '=');
794    if(v == 0)
795	return 0; /* punt if it's not of the right form */
796    varlen = (v + 1) - s;
797
798    for (idx = 0; environ[idx] != 0; idx++) {
799	if (strncmp(environ[idx], s, varlen) == 0) {
800	    if(v[1] != 0) { /* true if there's a value */
801		environ[idx] = s;
802		return 0;
803	    } else {
804		do {
805		    environ[idx] = environ[idx+1];
806		} while(environ[++idx] != 0);
807		return 0;
808	    }
809	}
810    }
811
812    /* add to environment (unless no value; then just return) */
813    if(v[1] == 0)
814	return 0;
815    if(virgin) {
816	register i;
817
818	newenv = (char **) malloc((unsigned) ((idx + 2) * sizeof(char*)));
819	if(newenv == 0)
820	    return -1;
821	for(i = idx-1; i >= 0; --i)
822	    newenv[i] = environ[i];
823	virgin = 0;     /* you're not a virgin anymore, sweety */
824    } else {
825	newenv = (char **) realloc((char *) environ,
826				   (unsigned) ((idx + 2) * sizeof(char*)));
827	if (newenv == 0)
828	    return -1;
829    }
830
831    environ = newenv;
832    environ[idx] = s;
833    environ[idx+1] = 0;
834
835    return 0;
836}
837#endif /* NOPUTENV */
838
839
840static Pixmap
841CreateXLogoPixmap (unsigned *widthp, unsigned *heightp)
842{
843    int h = Scr->TBInfo.width - Scr->TBInfo.border * 2;
844    if (h < 0) h = 0;
845
846    *widthp = *heightp = (unsigned int) h;
847    if (Scr->tbpm.xlogo == None) {
848	GC gc, gcBack;
849
850	Scr->tbpm.xlogo = XCreatePixmap (dpy, Scr->Root, h, h, 1);
851	gc = XCreateGC (dpy, Scr->tbpm.xlogo, 0L, NULL);
852	XSetForeground (dpy, gc, 0);
853	XFillRectangle (dpy, Scr->tbpm.xlogo, gc, 0, 0, h, h);
854	XSetForeground (dpy, gc, 1);
855	gcBack = XCreateGC (dpy, Scr->tbpm.xlogo, 0L, NULL);
856	XSetForeground (dpy, gcBack, 0);
857
858	/*
859	 * draw the logo large so that it gets as dense as possible; then white
860	 * out the edges so that they look crisp
861	 */
862	XmuDrawLogo (dpy, Scr->tbpm.xlogo, gc, gcBack, -1, -1, h + 2, h + 2);
863	XDrawRectangle (dpy, Scr->tbpm.xlogo, gcBack, 0, 0, h - 1, h - 1);
864
865	/*
866	 * done drawing
867	 */
868	XFreeGC (dpy, gc);
869	XFreeGC (dpy, gcBack);
870    }
871    return Scr->tbpm.xlogo;
872}
873
874
875static Pixmap
876CreateResizePixmap (unsigned *widthp, unsigned *heightp)
877{
878    int h = Scr->TBInfo.width - Scr->TBInfo.border * 2;
879    if (h < 1) h = 1;
880
881    *widthp = *heightp = (unsigned int) h;
882    if (Scr->tbpm.resize == None) {
883	XPoint	points[3];
884	GC gc;
885	int w;
886	int lw;
887
888	/*
889	 * create the pixmap
890	 */
891	Scr->tbpm.resize = XCreatePixmap (dpy, Scr->Root, h, h, 1);
892	gc = XCreateGC (dpy, Scr->tbpm.resize, 0L, NULL);
893	XSetForeground (dpy, gc, 0);
894	XFillRectangle (dpy, Scr->tbpm.resize, gc, 0, 0, h, h);
895	XSetForeground (dpy, gc, 1);
896	lw = h / 16;
897	if (lw == 1)
898	    lw = 0;
899	XSetLineAttributes (dpy, gc, lw, LineSolid, CapButt, JoinMiter);
900
901	/*
902	 * draw the resize button,
903	 */
904	w = (h * 2) / 3;
905	points[0].x = w;
906	points[0].y = 0;
907	points[1].x = w;
908	points[1].y = w;
909	points[2].x = 0;
910	points[2].y = w;
911	XDrawLines (dpy, Scr->tbpm.resize, gc, points, 3, CoordModeOrigin);
912	w = w / 2;
913	points[0].x = w;
914	points[0].y = 0;
915	points[1].x = w;
916	points[1].y = w;
917	points[2].x = 0;
918	points[2].y = w;
919	XDrawLines (dpy, Scr->tbpm.resize, gc, points, 3, CoordModeOrigin);
920
921	/*
922	 * done drawing
923	 */
924	XFreeGC(dpy, gc);
925    }
926    return Scr->tbpm.resize;
927}
928
929
930static Pixmap
931CreateDotPixmap (unsigned *widthp, unsigned *heightp)
932{
933    int h = Scr->TBInfo.width - Scr->TBInfo.border * 2;
934
935    h = h * 3 / 4;
936    if (h < 1) h = 1;
937    if (!(h & 1))
938	h--;
939    *widthp = *heightp = (unsigned int) h;
940    if (Scr->tbpm.delete == None) {
941	GC  gc;
942	Pixmap pix;
943
944	pix = Scr->tbpm.delete = XCreatePixmap (dpy, Scr->Root, h, h, 1);
945	gc = XCreateGC (dpy, pix, 0L, NULL);
946	XSetLineAttributes (dpy, gc, h, LineSolid, CapRound, JoinRound);
947	XSetForeground (dpy, gc, 0L);
948	XFillRectangle (dpy, pix, gc, 0, 0, h, h);
949	XSetForeground (dpy, gc, 1L);
950	XDrawLine (dpy, pix, gc, h/2, h/2, h/2, h/2);
951	XFreeGC (dpy, gc);
952    }
953    return Scr->tbpm.delete;
954}
955
956#define questionmark_width 8
957#define questionmark_height 8
958static char questionmark_bits[] = {
959   0x38, 0x7c, 0x64, 0x30, 0x18, 0x00, 0x18, 0x18};
960
961static Pixmap
962CreateQuestionPixmap (unsigned *widthp, unsigned *heightp)
963{
964    *widthp = questionmark_width;
965    *heightp = questionmark_height;
966    if (Scr->tbpm.question == None) {
967	Scr->tbpm.question = XCreateBitmapFromData (dpy, Scr->Root,
968						    questionmark_bits,
969						    questionmark_width,
970						    questionmark_height);
971    }
972    /*
973     * this must succeed or else we are in deep trouble elsewhere
974     */
975    return Scr->tbpm.question;
976}
977
978
979static Pixmap
980CreateMenuPixmap (unsigned *widthp, unsigned *heightp)
981{
982    return CreateMenuIcon (Scr->TBInfo.width - Scr->TBInfo.border * 2,
983			   widthp,heightp);
984}
985
986Pixmap
987CreateMenuIcon (int height, unsigned *widthp, unsigned *heightp)
988{
989    int h, w;
990    int ih, iw;
991    int	ix, iy;
992    int	mh, mw;
993    int	tw, th;
994    int	lw, lh;
995    int	lx, ly;
996    int	lines, dly;
997    int off;
998    int	bw;
999
1000    h = height;
1001    w = h * 7 / 8;
1002    if (h < 1)
1003	h = 1;
1004    if (w < 1)
1005	w = 1;
1006    *widthp = w;
1007    *heightp = h;
1008    if (Scr->tbpm.menu == None) {
1009	Pixmap  pix;
1010	GC	gc;
1011
1012	pix = Scr->tbpm.menu = XCreatePixmap (dpy, Scr->Root, w, h, 1);
1013	gc = XCreateGC (dpy, pix, 0L, NULL);
1014	XSetForeground (dpy, gc, 0L);
1015	XFillRectangle (dpy, pix, gc, 0, 0, w, h);
1016	XSetForeground (dpy, gc, 1L);
1017	ix = 1;
1018	iy = 1;
1019	ih = h - iy * 2;
1020	iw = w - ix * 2;
1021	off = ih / 8;
1022	mh = ih - off;
1023	mw = iw - off;
1024	bw = mh / 16;
1025	if (bw == 0 && mw > 2)
1026	    bw = 1;
1027	tw = mw - bw * 2;
1028	th = mh - bw * 2;
1029	XFillRectangle (dpy, pix, gc, ix, iy, mw, mh);
1030	XFillRectangle (dpy, pix, gc, ix + iw - mw, iy + ih - mh, mw, mh);
1031	XSetForeground (dpy, gc, 0L);
1032	XFillRectangle (dpy, pix, gc, ix+bw, iy+bw, tw, th);
1033	XSetForeground (dpy, gc, 1L);
1034	lw = tw / 2;
1035	if ((tw & 1) ^ (lw & 1))
1036	    lw++;
1037	lx = ix + bw + (tw - lw) / 2;
1038
1039	lh = th / 2 - bw;
1040	if ((lh & 1) ^ ((th - bw) & 1))
1041	    lh++;
1042	ly = iy + bw + (th - bw - lh) / 2;
1043
1044	lines = 3;
1045	if ((lh & 1) && lh < 6)
1046	{
1047	    lines--;
1048	}
1049	dly = lh / (lines - 1);
1050	while (lines--)
1051	{
1052	    XFillRectangle (dpy, pix, gc, lx, ly, lw, bw);
1053	    ly += dly;
1054	}
1055	XFreeGC (dpy, gc);
1056    }
1057    return Scr->tbpm.menu;
1058}
1059
1060void
1061Bell(int type, int percent, Window win)
1062{
1063#ifdef XKB
1064    XkbStdBell(dpy, win, percent, type);
1065#else
1066    XBell(dpy, percent);
1067#endif
1068    return;
1069}
1070