util.c revision c2535118
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 = 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    char *basename2;
593
594    if (use_fontset) {
595	if (font->fontset != NULL){
596	    XFreeFontSet(dpy, font->fontset);
597	}
598
599	basename2 = malloc(strlen(font->name) + 3);
600	if (basename2) sprintf(basename2, "%s,*", font->name);
601	else basename2 = font->name;
602	if( (font->fontset = XCreateFontSet(dpy, basename2,
603					    &missing_charset_list_return,
604					    &missing_charset_count_return,
605					    &def_string_return)) == NULL) {
606	    fprintf (stderr, "%s:  unable to open fontset \"%s\"\n",
607			 ProgramName, font->name);
608	    exit(1);
609	}
610	if (basename2 != font->name) free(basename2);
611	for(i=0; i<missing_charset_count_return; i++){
612	    printf("%s: warning: font for charset %s is lacking.\n",
613		   ProgramName, missing_charset_list_return[i]);
614	}
615
616	font_extents = XExtentsOfFontSet(font->fontset);
617	fnum = XFontsOfFontSet(font->fontset, &xfonts, &font_names);
618	for( i = 0, ascent = 0, descent = 0; i<fnum; i++){
619	    if (ascent < (*xfonts)->ascent) ascent = (*xfonts)->ascent;
620	    if (descent < (*xfonts)->descent) descent = (*xfonts)->descent;
621	    xfonts++;
622	}
623	font->height = font_extents->max_logical_extent.height;
624	font->y = ascent;
625	font->ascent = ascent;
626	font->descent = descent;
627	return;
628    }
629
630    if (font->font != NULL)
631	XFreeFont(dpy, font->font);
632
633    if ((font->font = XLoadQueryFont(dpy, font->name)) == NULL)
634    {
635	if (Scr->DefaultFont.name) {
636	    deffontname = Scr->DefaultFont.name;
637	}
638	if ((font->font = XLoadQueryFont(dpy, deffontname)) == NULL)
639	{
640	    fprintf (stderr, "%s:  unable to open fonts \"%s\" or \"%s\"\n",
641		     ProgramName, font->name, deffontname);
642	    exit(1);
643	}
644
645    }
646    font->height = font->font->ascent + font->font->descent;
647    font->y = font->font->ascent;
648    font->ascent = font->font->ascent;
649    font->descent = font->font->descent;
650}
651
652int
653MyFont_TextWidth(MyFont *font, const char *string, int len)
654{
655    XRectangle ink_rect;
656    XRectangle logical_rect;
657
658    if (use_fontset) {
659	XmbTextExtents(font->fontset, string, len,
660		       &ink_rect, &logical_rect);
661	return logical_rect.width;
662    }
663    return XTextWidth(font->font, string, len);
664}
665
666void
667MyFont_DrawImageString(Display *dpy, Drawable d, MyFont *font, GC gc,
668                       int x, int y, const char *string, int len)
669{
670    if (use_fontset) {
671	XmbDrawImageString(dpy, d, font->fontset, gc, x, y, string, len);
672	return;
673    }
674    XDrawImageString (dpy, d, gc, x, y, string, len);
675}
676
677void
678MyFont_DrawString(Display *dpy, Drawable d, MyFont *font, GC gc,
679                  int x, int y, const char *string, int len)
680{
681    if (use_fontset) {
682	XmbDrawString(dpy, d, font->fontset, gc, x, y, string, len);
683	return;
684    }
685    XDrawString (dpy, d, gc, x, y, string, len);
686}
687
688void
689MyFont_ChangeGC(unsigned long fix_fore, unsigned long fix_back,
690                MyFont *fix_font)
691{
692    Gcv.foreground = fix_fore;
693    Gcv.background = fix_back;
694    if (use_fontset) {
695	XChangeGC(dpy, Scr->NormalGC, GCForeground|GCBackground, &Gcv);
696	return;
697    }
698    Gcv.font = fix_font->font->fid;
699    XChangeGC(dpy, Scr->NormalGC, GCFont|GCForeground|GCBackground,&Gcv);
700}
701
702/*
703 * The following functions are internationalized substitutions
704 * for XFetchName and XGetIconName using XGetWMName and
705 * XGetWMIconName.
706 *
707 * Please note that the third arguments have to be freed using free(),
708 * not XFree().
709 */
710Status
711I18N_FetchName(Display *dpy, Window w, char **winname)
712{
713    int    status;
714    XTextProperty text_prop;
715    char **list;
716    int    num;
717
718    status = XGetWMName(dpy, w, &text_prop);
719    if (!status || !text_prop.value || !text_prop.nitems) {
720      *winname = NULL;
721      return 0;
722    }
723    status = XmbTextPropertyToTextList(dpy, &text_prop, &list, &num);
724    if (status < Success || !num || !*list) {
725      *winname = NULL;
726      return 0;
727    }
728    XFree(text_prop.value);
729    *winname = (char *)strdup(*list);
730    XFreeStringList(list);
731    return 1;
732}
733
734Status
735I18N_GetIconName(Display *dpy, Window w, char **iconname)
736{
737    int    status;
738    XTextProperty text_prop;
739    char **list;
740    int    num;
741
742    status = XGetWMIconName(dpy, w, &text_prop);
743    if (!status || !text_prop.value || !text_prop.nitems) return 0;
744    status = XmbTextPropertyToTextList(dpy, &text_prop, &list, &num);
745    if (status < Success || !num || !*list) return 0;
746    XFree(text_prop.value);
747    *iconname = (char *)strdup(*list);
748    XFreeStringList(list);
749    return 1;
750}
751
752/**
753 * separate routine to set focus to make things more understandable
754 * and easier to debug
755 */
756void
757SetFocus (TwmWindow *tmp_win, Time time)
758{
759    Window w = (tmp_win ? tmp_win->w : PointerRoot);
760
761#ifdef TRACE
762    if (tmp_win) {
763	printf ("Focusing on window \"%s\"\n", tmp_win->full_name);
764    } else {
765	printf ("Unfocusing; Scr->Focus was \"%s\"\n",
766		Scr->Focus ? Scr->Focus->full_name : "(nil)");
767    }
768#endif
769
770    XSetInputFocus (dpy, w, RevertToPointerRoot, time);
771}
772
773static Pixmap
774CreateXLogoPixmap (unsigned *widthp, unsigned *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
808static Pixmap
809CreateResizePixmap (unsigned *widthp, unsigned *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
863static Pixmap
864CreateDotPixmap (unsigned *widthp, unsigned *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
891static char questionmark_bits[] = {
892   0x38, 0x7c, 0x64, 0x30, 0x18, 0x00, 0x18, 0x18};
893
894static Pixmap
895CreateQuestionPixmap (unsigned *widthp, unsigned *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
912static Pixmap
913CreateMenuPixmap (unsigned *widthp, unsigned *heightp)
914{
915    return CreateMenuIcon (Scr->TBInfo.width - Scr->TBInfo.border * 2,
916			   widthp,heightp);
917}
918
919Pixmap
920CreateMenuIcon (int height, unsigned *widthp, unsigned *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
993void
994Bell(int type, int percent, Window win)
995{
996#ifdef XKB
997    XkbStdBell(dpy, win, percent, type);
998#else
999    XBell(dpy, percent);
1000#endif
1001    return;
1002}
1003