util.c revision c9398294
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(const char *name)
260{
261    char *newname;
262
263    if (name[0] != '~') return strdup(name);
264
265    newname = 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(const 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 (const 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	    const 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 = malloc (strlen(name) + strlen(Scr->IconDirectory) + 2);
358	if (!bigname) {
359	    fprintf (stderr,
360		     "%s:  unable to allocate memory for \"%s/%s\"\n",
361		     ProgramName, Scr->IconDirectory, name);
362	    return None;
363	}
364	(void) sprintf (bigname, "%s/%s", Scr->IconDirectory, name);
365	if (XReadBitmapFile (dpy, Scr->Root, bigname, widthp, heightp, &pm,
366			     &HotX, &HotY) != BitmapSuccess) {
367	    pm = None;
368	}
369    }
370    if (bigname != name) free (bigname);
371    if (pm == None) {
372	fprintf (stderr, "%s:  unable to find bitmap \"%s\"\n",
373		 ProgramName, name);
374    }
375
376    return pm;
377}
378
379Pixmap
380GetBitmap (const char *name)
381{
382    return FindBitmap (name, &JunkWidth, &JunkHeight);
383}
384
385void
386InsertRGBColormap (Atom a, XStandardColormap *maps, int nmaps, Bool replace)
387{
388    StdCmap *sc = NULL;
389
390    if (replace) {			/* locate existing entry */
391	for (sc = Scr->StdCmapInfo.head; sc; sc = sc->next) {
392	    if (sc->atom == a) break;
393	}
394    }
395
396    if (!sc) {				/* no existing, allocate new */
397	sc = malloc (sizeof (StdCmap));
398	if (!sc) {
399	    fprintf (stderr, "%s:  unable to allocate %ld bytes for StdCmap\n",
400		     ProgramName, (unsigned long)sizeof (StdCmap));
401	    return;
402	}
403    }
404
405    if (replace) {			/* just update contents */
406	if (sc->maps) XFree (maps);
407	if (sc == Scr->StdCmapInfo.mru) Scr->StdCmapInfo.mru = NULL;
408    } else {				/* else appending */
409	sc->next = NULL;
410	sc->atom = a;
411	if (Scr->StdCmapInfo.tail) {
412	    Scr->StdCmapInfo.tail->next = sc;
413	} else {
414	    Scr->StdCmapInfo.head = sc;
415	}
416	Scr->StdCmapInfo.tail = sc;
417    }
418    sc->nmaps = nmaps;
419    sc->maps = maps;
420
421    return;
422}
423
424void
425RemoveRGBColormap (Atom a)
426{
427    StdCmap *sc, *prev;
428
429    prev = NULL;
430    for (sc = Scr->StdCmapInfo.head; sc; sc = sc->next) {
431	if (sc->atom == a) break;
432	prev = sc;
433    }
434    if (sc) {				/* found one */
435	if (sc->maps) XFree (sc->maps);
436	if (prev) prev->next = sc->next;
437	if (Scr->StdCmapInfo.head == sc) Scr->StdCmapInfo.head = sc->next;
438	if (Scr->StdCmapInfo.tail == sc) Scr->StdCmapInfo.tail = prev;
439	if (Scr->StdCmapInfo.mru == sc) Scr->StdCmapInfo.mru = NULL;
440    }
441    return;
442}
443
444void
445LocateStandardColormaps(void)
446{
447    Atom *atoms;
448    int natoms;
449    int i;
450
451    atoms = XListProperties (dpy, Scr->Root, &natoms);
452    for (i = 0; i < natoms; i++) {
453	XStandardColormap *maps = NULL;
454	int nmaps;
455
456	if (XGetRGBColormaps (dpy, Scr->Root, &maps, &nmaps, atoms[i])) {
457	    /* if got one, then append to current list */
458	    InsertRGBColormap (atoms[i], maps, nmaps, False);
459	}
460    }
461    if (atoms) XFree (atoms);
462    return;
463}
464
465void
466GetColor(int kind, Pixel *what, const char *name)
467{
468    XColor color, junkcolor;
469    Status stat = 0;
470    Colormap cmap = Scr->TwmRoot.cmaps.cwins[0]->colormap->c;
471
472#ifndef TOM
473    if (!Scr->FirstTime)
474	return;
475#endif
476
477    if (Scr->Monochrome != kind)
478	return;
479
480    if (!XAllocNamedColor (dpy, cmap, name, &color, &junkcolor))
481    {
482	/* if we could not allocate the color, let's see if this is a
483	 * standard colormap
484	 */
485	XStandardColormap *stdcmap = NULL;
486
487	/* parse the named color */
488	if (name[0] != '#')
489	    stat = XParseColor (dpy, cmap, name, &color);
490	if (!stat)
491	{
492	    fprintf (stderr, "%s:  invalid color name \"%s\"\n",
493		     ProgramName, name);
494	    return;
495	}
496
497	/*
498	 * look through the list of standard colormaps (check cache first)
499	 */
500	if (Scr->StdCmapInfo.mru && Scr->StdCmapInfo.mru->maps &&
501	    (Scr->StdCmapInfo.mru->maps[Scr->StdCmapInfo.mruindex].colormap ==
502	     cmap)) {
503	    stdcmap = &(Scr->StdCmapInfo.mru->maps[Scr->StdCmapInfo.mruindex]);
504	} else {
505	    StdCmap *sc;
506
507	    for (sc = Scr->StdCmapInfo.head; sc; sc = sc->next) {
508		int i;
509
510		for (i = 0; i < sc->nmaps; i++) {
511		    if (sc->maps[i].colormap == cmap) {
512			Scr->StdCmapInfo.mru = sc;
513			Scr->StdCmapInfo.mruindex = i;
514			stdcmap = &(sc->maps[i]);
515			goto gotit;
516		    }
517		}
518	    }
519	}
520
521      gotit:
522	if (stdcmap) {
523            color.pixel = (stdcmap->base_pixel +
524			   ((Pixel)(((float)color.red / 65535.0) *
525				    stdcmap->red_max + 0.5) *
526			    stdcmap->red_mult) +
527			   ((Pixel)(((float)color.green /65535.0) *
528				    stdcmap->green_max + 0.5) *
529			    stdcmap->green_mult) +
530			   ((Pixel)(((float)color.blue  / 65535.0) *
531				    stdcmap->blue_max + 0.5) *
532			    stdcmap->blue_mult));
533        } else {
534	    fprintf (stderr, "%s:  unable to allocate color \"%s\"\n",
535		     ProgramName, name);
536	    return;
537	}
538    }
539
540    *what = color.pixel;
541}
542
543void
544GetColorValue(int kind, XColor *what, const char *name)
545{
546    XColor junkcolor;
547    Colormap cmap = Scr->TwmRoot.cmaps.cwins[0]->colormap->c;
548
549#ifndef TOM
550    if (!Scr->FirstTime)
551	return;
552#endif
553
554    if (Scr->Monochrome != kind)
555	return;
556
557    if (!XLookupColor (dpy, cmap, name, what, &junkcolor))
558    {
559	fprintf (stderr, "%s:  invalid color name \"%s\"\n",
560		 ProgramName, name);
561    }
562    else
563    {
564	what->pixel = AllPlanes;
565    }
566}
567
568/*
569 * The following functions are sensible to 'use_fontset'.
570 * When 'use_fontset' is True,
571 *  - XFontSet-related internationalized functions are used
572 *     so as multibyte languages can be displayed.
573 * When 'use_fontset' is False,
574 *  - XFontStruct-related conventional functions are used
575 *     so as 8-bit characters can be displayed even when
576 *     locale is not set properly.
577 */
578void
579GetFont(MyFont *font)
580{
581    const char *deffontname = "fixed";
582    char **missing_charset_list_return;
583    int missing_charset_count_return;
584    char *def_string_return;
585    XFontSetExtents *font_extents;
586    XFontStruct **xfonts;
587    char **font_names;
588    register int i;
589    int ascent;
590    int descent;
591    int fnum;
592
593    if (use_fontset) {
594	if (font->fontset != NULL){
595	    XFreeFontSet(dpy, font->fontset);
596	}
597
598	if( (font->fontset = XCreateFontSet(dpy, font->name,
599					    &missing_charset_list_return,
600					    &missing_charset_count_return,
601					    &def_string_return)) == NULL) {
602	    fprintf (stderr, "%s:  unable to open fontset \"%s\"\n",
603			 ProgramName, font->name);
604	    exit(1);
605	}
606	for(i=0; i<missing_charset_count_return; i++){
607	    printf("%s: warning: font for charset %s is lacking.\n",
608		   ProgramName, missing_charset_list_return[i]);
609	}
610
611	font_extents = XExtentsOfFontSet(font->fontset);
612	fnum = XFontsOfFontSet(font->fontset, &xfonts, &font_names);
613	for( i = 0, ascent = 0, descent = 0; i<fnum; i++){
614	    if (ascent < (*xfonts)->ascent) ascent = (*xfonts)->ascent;
615	    if (descent < (*xfonts)->descent) descent = (*xfonts)->descent;
616	    xfonts++;
617	}
618	font->height = font_extents->max_logical_extent.height;
619	font->y = ascent;
620	font->ascent = ascent;
621	font->descent = descent;
622	return;
623    }
624
625    if (font->font != NULL)
626	XFreeFont(dpy, font->font);
627
628    if ((font->font = XLoadQueryFont(dpy, font->name)) == NULL)
629    {
630	if (Scr->DefaultFont.name) {
631	    deffontname = Scr->DefaultFont.name;
632	}
633	if ((font->font = XLoadQueryFont(dpy, deffontname)) == NULL)
634	{
635	    fprintf (stderr, "%s:  unable to open fonts \"%s\" or \"%s\"\n",
636		     ProgramName, font->name, deffontname);
637	    exit(1);
638	}
639
640    }
641    font->height = font->font->ascent + font->font->descent;
642    font->y = font->font->ascent;
643    font->ascent = font->font->ascent;
644    font->descent = font->font->descent;
645}
646
647int
648MyFont_TextWidth(MyFont *font, const char *string, int len)
649{
650    XRectangle ink_rect;
651    XRectangle logical_rect;
652
653    if (use_fontset) {
654	XmbTextExtents(font->fontset, string, len,
655		       &ink_rect, &logical_rect);
656	return logical_rect.width;
657    }
658    return XTextWidth(font->font, string, len);
659}
660
661void
662MyFont_DrawImageString(Display *dpy, Drawable d, MyFont *font, GC gc,
663                       int x, int y, const char *string, int len)
664{
665    if (use_fontset) {
666	XmbDrawImageString(dpy, d, font->fontset, gc, x, y, string, len);
667	return;
668    }
669    XDrawImageString (dpy, d, gc, x, y, string, len);
670}
671
672void
673MyFont_DrawString(Display *dpy, Drawable d, MyFont *font, GC gc,
674                  int x, int y, const char *string, int len)
675{
676    if (use_fontset) {
677	XmbDrawString(dpy, d, font->fontset, gc, x, y, string, len);
678	return;
679    }
680    XDrawString (dpy, d, gc, x, y, string, len);
681}
682
683void
684MyFont_ChangeGC(unsigned long fix_fore, unsigned long fix_back,
685                MyFont *fix_font)
686{
687    Gcv.foreground = fix_fore;
688    Gcv.background = fix_back;
689    if (use_fontset) {
690	XChangeGC(dpy, Scr->NormalGC, GCForeground|GCBackground, &Gcv);
691	return;
692    }
693    Gcv.font = fix_font->font->fid;
694    XChangeGC(dpy, Scr->NormalGC, GCFont|GCForeground|GCBackground,&Gcv);
695}
696
697/*
698 * The following functions are internationalized substitutions
699 * for XFetchName and XGetIconName using XGetWMName and
700 * XGetWMIconName.
701 *
702 * Please note that the third arguments have to be freed using free(),
703 * not XFree().
704 */
705Status
706I18N_FetchName(Display *dpy, Window w, char **winname)
707{
708    int    status;
709    XTextProperty text_prop;
710    char **list;
711    int    num;
712
713    status = XGetWMName(dpy, w, &text_prop);
714    if (!status || !text_prop.value || !text_prop.nitems) {
715      *winname = NULL;
716      return 0;
717    }
718    status = XmbTextPropertyToTextList(dpy, &text_prop, &list, &num);
719    if (status < Success || !num || !*list) {
720      *winname = NULL;
721      return 0;
722    }
723    XFree(text_prop.value);
724    *winname = (char *)strdup(*list);
725    XFreeStringList(list);
726    return 1;
727}
728
729Status
730I18N_GetIconName(Display *dpy, Window w, char **iconname)
731{
732    int    status;
733    XTextProperty text_prop;
734    char **list;
735    int    num;
736
737    status = XGetWMIconName(dpy, w, &text_prop);
738    if (!status || !text_prop.value || !text_prop.nitems) return 0;
739    status = XmbTextPropertyToTextList(dpy, &text_prop, &list, &num);
740    if (status < Success || !num || !*list) return 0;
741    XFree(text_prop.value);
742    *iconname = (char *)strdup(*list);
743    XFreeStringList(list);
744    return 1;
745}
746
747/**
748 * separate routine to set focus to make things more understandable
749 * and easier to debug
750 */
751void
752SetFocus (TwmWindow *tmp_win, Time time)
753{
754    Window w = (tmp_win ? tmp_win->w : PointerRoot);
755
756#ifdef TRACE
757    if (tmp_win) {
758	printf ("Focusing on window \"%s\"\n", tmp_win->full_name);
759    } else {
760	printf ("Unfocusing; Scr->Focus was \"%s\"\n",
761		Scr->Focus ? Scr->Focus->full_name : "(nil)");
762    }
763#endif
764
765    XSetInputFocus (dpy, w, RevertToPointerRoot, time);
766}
767
768static Pixmap
769CreateXLogoPixmap (unsigned *widthp, unsigned *heightp)
770{
771    int h = Scr->TBInfo.width - Scr->TBInfo.border * 2;
772    if (h < 0) h = 0;
773
774    *widthp = *heightp = (unsigned int) h;
775    if (Scr->tbpm.xlogo == None) {
776	GC gc, gcBack;
777
778	Scr->tbpm.xlogo = XCreatePixmap (dpy, Scr->Root, h, h, 1);
779	gc = XCreateGC (dpy, Scr->tbpm.xlogo, 0L, NULL);
780	XSetForeground (dpy, gc, 0);
781	XFillRectangle (dpy, Scr->tbpm.xlogo, gc, 0, 0, h, h);
782	XSetForeground (dpy, gc, 1);
783	gcBack = XCreateGC (dpy, Scr->tbpm.xlogo, 0L, NULL);
784	XSetForeground (dpy, gcBack, 0);
785
786	/*
787	 * draw the logo large so that it gets as dense as possible; then white
788	 * out the edges so that they look crisp
789	 */
790	XmuDrawLogo (dpy, Scr->tbpm.xlogo, gc, gcBack, -1, -1, h + 2, h + 2);
791	XDrawRectangle (dpy, Scr->tbpm.xlogo, gcBack, 0, 0, h - 1, h - 1);
792
793	/*
794	 * done drawing
795	 */
796	XFreeGC (dpy, gc);
797	XFreeGC (dpy, gcBack);
798    }
799    return Scr->tbpm.xlogo;
800}
801
802
803static Pixmap
804CreateResizePixmap (unsigned *widthp, unsigned *heightp)
805{
806    int h = Scr->TBInfo.width - Scr->TBInfo.border * 2;
807    if (h < 1) h = 1;
808
809    *widthp = *heightp = (unsigned int) h;
810    if (Scr->tbpm.resize == None) {
811	XPoint	points[3];
812	GC gc;
813	int w;
814	int lw;
815
816	/*
817	 * create the pixmap
818	 */
819	Scr->tbpm.resize = XCreatePixmap (dpy, Scr->Root, h, h, 1);
820	gc = XCreateGC (dpy, Scr->tbpm.resize, 0L, NULL);
821	XSetForeground (dpy, gc, 0);
822	XFillRectangle (dpy, Scr->tbpm.resize, gc, 0, 0, h, h);
823	XSetForeground (dpy, gc, 1);
824	lw = h / 16;
825	if (lw == 1)
826	    lw = 0;
827	XSetLineAttributes (dpy, gc, lw, LineSolid, CapButt, JoinMiter);
828
829	/*
830	 * draw the resize button,
831	 */
832	w = (h * 2) / 3;
833	points[0].x = w;
834	points[0].y = 0;
835	points[1].x = w;
836	points[1].y = w;
837	points[2].x = 0;
838	points[2].y = w;
839	XDrawLines (dpy, Scr->tbpm.resize, gc, points, 3, CoordModeOrigin);
840	w = w / 2;
841	points[0].x = w;
842	points[0].y = 0;
843	points[1].x = w;
844	points[1].y = w;
845	points[2].x = 0;
846	points[2].y = w;
847	XDrawLines (dpy, Scr->tbpm.resize, gc, points, 3, CoordModeOrigin);
848
849	/*
850	 * done drawing
851	 */
852	XFreeGC(dpy, gc);
853    }
854    return Scr->tbpm.resize;
855}
856
857
858static Pixmap
859CreateDotPixmap (unsigned *widthp, unsigned *heightp)
860{
861    int h = Scr->TBInfo.width - Scr->TBInfo.border * 2;
862
863    h = h * 3 / 4;
864    if (h < 1) h = 1;
865    if (!(h & 1))
866	h--;
867    *widthp = *heightp = (unsigned int) h;
868    if (Scr->tbpm.delete == None) {
869	GC  gc;
870	Pixmap pix;
871
872	pix = Scr->tbpm.delete = XCreatePixmap (dpy, Scr->Root, h, h, 1);
873	gc = XCreateGC (dpy, pix, 0L, NULL);
874	XSetLineAttributes (dpy, gc, h, LineSolid, CapRound, JoinRound);
875	XSetForeground (dpy, gc, 0L);
876	XFillRectangle (dpy, pix, gc, 0, 0, h, h);
877	XSetForeground (dpy, gc, 1L);
878	XDrawLine (dpy, pix, gc, h/2, h/2, h/2, h/2);
879	XFreeGC (dpy, gc);
880    }
881    return Scr->tbpm.delete;
882}
883
884#define questionmark_width 8
885#define questionmark_height 8
886static char questionmark_bits[] = {
887   0x38, 0x7c, 0x64, 0x30, 0x18, 0x00, 0x18, 0x18};
888
889static Pixmap
890CreateQuestionPixmap (unsigned *widthp, unsigned *heightp)
891{
892    *widthp = questionmark_width;
893    *heightp = questionmark_height;
894    if (Scr->tbpm.question == None) {
895	Scr->tbpm.question = XCreateBitmapFromData (dpy, Scr->Root,
896						    questionmark_bits,
897						    questionmark_width,
898						    questionmark_height);
899    }
900    /*
901     * this must succeed or else we are in deep trouble elsewhere
902     */
903    return Scr->tbpm.question;
904}
905
906
907static Pixmap
908CreateMenuPixmap (unsigned *widthp, unsigned *heightp)
909{
910    return CreateMenuIcon (Scr->TBInfo.width - Scr->TBInfo.border * 2,
911			   widthp,heightp);
912}
913
914Pixmap
915CreateMenuIcon (int height, unsigned *widthp, unsigned *heightp)
916{
917    int h, w;
918    int ih, iw;
919    int	ix, iy;
920    int	mh, mw;
921    int	tw, th;
922    int	lw, lh;
923    int	lx, ly;
924    int	lines, dly;
925    int off;
926    int	bw;
927
928    h = height;
929    w = h * 7 / 8;
930    if (h < 1)
931	h = 1;
932    if (w < 1)
933	w = 1;
934    *widthp = w;
935    *heightp = h;
936    if (Scr->tbpm.menu == None) {
937	Pixmap  pix;
938	GC	gc;
939
940	pix = Scr->tbpm.menu = XCreatePixmap (dpy, Scr->Root, w, h, 1);
941	gc = XCreateGC (dpy, pix, 0L, NULL);
942	XSetForeground (dpy, gc, 0L);
943	XFillRectangle (dpy, pix, gc, 0, 0, w, h);
944	XSetForeground (dpy, gc, 1L);
945	ix = 1;
946	iy = 1;
947	ih = h - iy * 2;
948	iw = w - ix * 2;
949	off = ih / 8;
950	mh = ih - off;
951	mw = iw - off;
952	bw = mh / 16;
953	if (bw == 0 && mw > 2)
954	    bw = 1;
955	tw = mw - bw * 2;
956	th = mh - bw * 2;
957	XFillRectangle (dpy, pix, gc, ix, iy, mw, mh);
958	XFillRectangle (dpy, pix, gc, ix + iw - mw, iy + ih - mh, mw, mh);
959	XSetForeground (dpy, gc, 0L);
960	XFillRectangle (dpy, pix, gc, ix+bw, iy+bw, tw, th);
961	XSetForeground (dpy, gc, 1L);
962	lw = tw / 2;
963	if ((tw & 1) ^ (lw & 1))
964	    lw++;
965	lx = ix + bw + (tw - lw) / 2;
966
967	lh = th / 2 - bw;
968	if ((lh & 1) ^ ((th - bw) & 1))
969	    lh++;
970	ly = iy + bw + (th - bw - lh) / 2;
971
972	lines = 3;
973	if ((lh & 1) && lh < 6)
974	{
975	    lines--;
976	}
977	dly = lh / (lines - 1);
978	while (lines--)
979	{
980	    XFillRectangle (dpy, pix, gc, lx, ly, lw, bw);
981	    ly += dly;
982	}
983	XFreeGC (dpy, gc);
984    }
985    return Scr->tbpm.menu;
986}
987
988void
989Bell(int type, int percent, Window win)
990{
991#ifdef XKB
992    XkbStdBell(dpy, win, percent, type);
993#else
994    XBell(dpy, percent);
995#endif
996    return;
997}
998