13e747e6dSmrg/*****************************************************************************/
23e747e6dSmrg/*
33e747e6dSmrg
43e747e6dSmrgCopyright 1989, 1998  The Open Group
53e747e6dSmrg
63e747e6dSmrgPermission to use, copy, modify, distribute, and sell this software and its
73e747e6dSmrgdocumentation for any purpose is hereby granted without fee, provided that
83e747e6dSmrgthe above copyright notice appear in all copies and that both that
93e747e6dSmrgcopyright notice and this permission notice appear in supporting
103e747e6dSmrgdocumentation.
113e747e6dSmrg
123e747e6dSmrgThe above copyright notice and this permission notice shall be included in
133e747e6dSmrgall copies or substantial portions of the Software.
143e747e6dSmrg
153e747e6dSmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
163e747e6dSmrgIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
173e747e6dSmrgFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
183e747e6dSmrgOPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
193e747e6dSmrgAN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
203e747e6dSmrgCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
213e747e6dSmrg
223e747e6dSmrgExcept as contained in this notice, the name of The Open Group shall not be
233e747e6dSmrgused in advertising or otherwise to promote the sale, use or other dealings
243e747e6dSmrgin this Software without prior written authorization from The Open Group.
253e747e6dSmrg
263e747e6dSmrg*/
273e747e6dSmrg/**       Copyright 1988 by Evans & Sutherland Computer Corporation,        **/
283e747e6dSmrg/**                          Salt Lake City, Utah                           **/
293e747e6dSmrg/**                        Cambridge, Massachusetts                         **/
303e747e6dSmrg/**                                                                         **/
313e747e6dSmrg/**                           All Rights Reserved                           **/
323e747e6dSmrg/**                                                                         **/
333e747e6dSmrg/**    Permission to use, copy, modify, and distribute this software and    **/
343e747e6dSmrg/**    its documentation  for  any  purpose  and  without  fee is hereby    **/
353e747e6dSmrg/**    granted, provided that the above copyright notice appear  in  all    **/
363e747e6dSmrg/**    copies and that both  that  copyright  notice  and  this  permis-    **/
373e747e6dSmrg/**    sion  notice appear in supporting  documentation,  and  that  the    **/
383e747e6dSmrg/**    name of Evans & Sutherland not be used in advertising    **/
393e747e6dSmrg/**    in publicity pertaining to distribution of the  software  without    **/
403e747e6dSmrg/**    specific, written prior permission.                                  **/
413e747e6dSmrg/**                                                                         **/
423e747e6dSmrg/**    EVANS & SUTHERLAND DISCLAIMs ALL WARRANTIES WITH REGARD    **/
433e747e6dSmrg/**    TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES  OF  MERCHANT-    **/
443e747e6dSmrg/**    ABILITY  AND  FITNESS,  IN  NO  EVENT SHALL EVANS & SUTHERLAND    **/
453e747e6dSmrg/**    BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL  DAM-    **/
463e747e6dSmrg/**    AGES OR  ANY DAMAGES WHATSOEVER  RESULTING FROM LOSS OF USE, DATA    **/
473e747e6dSmrg/**    OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER    **/
483e747e6dSmrg/**    TORTIOUS ACTION, ARISING OUT OF OR IN  CONNECTION  WITH  THE  USE    **/
493e747e6dSmrg/**    OR PERFORMANCE OF THIS SOFTWARE.                                     **/
503e747e6dSmrg/*****************************************************************************/
513e747e6dSmrg
523e747e6dSmrg/***********************************************************************
533e747e6dSmrg *
543e747e6dSmrg * utility routines for twm
553e747e6dSmrg *
56329eaa64Smrg * 28-Oct-87 Thomas E. LaStrange        File created
573e747e6dSmrg *
583e747e6dSmrg ***********************************************************************/
593e747e6dSmrg
603e747e6dSmrg#include "twm.h"
613e747e6dSmrg#include "util.h"
62b66deae1Smrg#include "parse.h"
633e747e6dSmrg#include "screen.h"
643e747e6dSmrg#include <X11/Xos.h>
653e747e6dSmrg#include <X11/Xatom.h>
663e747e6dSmrg#include <stdio.h>
673e747e6dSmrg#include <X11/Xmu/Drawing.h>
683e747e6dSmrg#include <X11/Xmu/CharSet.h>
693e747e6dSmrg
70329eaa64Smrgstatic Pixmap CreateXLogoPixmap(unsigned int *widthp, unsigned int *heightp);
71329eaa64Smrgstatic Pixmap CreateResizePixmap(unsigned int *widthp, unsigned int *heightp);
72329eaa64Smrgstatic Pixmap CreateDotPixmap(unsigned int *widthp, unsigned int *heightp);
73329eaa64Smrgstatic Pixmap CreateQuestionPixmap(unsigned int *widthp, unsigned int *heightp);
74329eaa64Smrgstatic Pixmap CreateMenuPixmap(unsigned int *widthp, unsigned int *heightp);
753e747e6dSmrg
763e747e6dSmrgint HotX, HotY;
773e747e6dSmrg
78ffd25bcaSmrg/**
793e747e6dSmrg * move a window outline
803e747e6dSmrg *
813e747e6dSmrg *  \param root         window we are outlining
823e747e6dSmrg *  \param x,y          upper left coordinate
833e747e6dSmrg *  \param width,height size of the rectangle
843e747e6dSmrg *  \param bw           border width of the frame
853e747e6dSmrg *  \param th           title height
863e747e6dSmrg */
87329eaa64Smrgvoid
88329eaa64SmrgMoveOutline(Window root, int x, int y, int width, int height, int bw, int th)
893e747e6dSmrg{
90329eaa64Smrg    static int lastx = 0;
91329eaa64Smrg    static int lasty = 0;
92329eaa64Smrg    static int lastWidth = 0;
93329eaa64Smrg    static int lastHeight = 0;
94329eaa64Smrg    static int lastBW = 0;
95329eaa64Smrg    static int lastTH = 0;
96329eaa64Smrg    int xl, xr, yt, yb, xinnerl, xinnerr, yinnert, yinnerb;
97329eaa64Smrg    int xthird, ythird;
98329eaa64Smrg    XSegment outline[18];
99b66deae1Smrg    XSegment *r;
1003e747e6dSmrg
1013e747e6dSmrg    if (x == lastx && y == lasty && width == lastWidth && height == lastHeight
102329eaa64Smrg        && lastBW == bw && th == lastTH)
103329eaa64Smrg        return;
104ffd25bcaSmrg
1053e747e6dSmrg    r = outline;
1063e747e6dSmrg
1073e747e6dSmrg#define DRAWIT() \
108329eaa64Smrg    if (lastWidth || lastHeight)                        \
109329eaa64Smrg    {                                                   \
110329eaa64Smrg        xl = lastx;                                     \
111329eaa64Smrg        xr = lastx + lastWidth - 1;                     \
112329eaa64Smrg        yt = lasty;                                     \
113329eaa64Smrg        yb = lasty + lastHeight - 1;                    \
114329eaa64Smrg        xinnerl = xl + lastBW;                          \
115329eaa64Smrg        xinnerr = xr - lastBW;                          \
116329eaa64Smrg        yinnert = yt + lastTH + lastBW;                 \
117329eaa64Smrg        yinnerb = yb - lastBW;                          \
118329eaa64Smrg        xthird = (xinnerr - xinnerl) / 3;               \
119329eaa64Smrg        ythird = (yinnerb - yinnert) / 3;               \
120329eaa64Smrg                                                        \
121329eaa64Smrg        r->x1 = (short)(xl);                            \
122329eaa64Smrg        r->y1 = (short)(yt);                            \
123329eaa64Smrg        r->x2 = (short)(xr);                            \
124329eaa64Smrg        r->y2 = (short)(yt);                            \
125329eaa64Smrg        r++;                                            \
126329eaa64Smrg                                                        \
127329eaa64Smrg        r->x1 = (short)(xl);                            \
128329eaa64Smrg        r->y1 = (short)(yb);                            \
129329eaa64Smrg        r->x2 = (short)(xr);                            \
130329eaa64Smrg        r->y2 = (short)(yb);                            \
131329eaa64Smrg        r++;                                            \
132329eaa64Smrg                                                        \
133329eaa64Smrg        r->x1 = (short)(xl);                            \
134329eaa64Smrg        r->y1 = (short)(yt);                            \
135329eaa64Smrg        r->x2 = (short)(xl);                            \
136329eaa64Smrg        r->y2 = (short)(yb);                            \
137329eaa64Smrg        r++;                                            \
138329eaa64Smrg                                                        \
139329eaa64Smrg        r->x1 = (short)(xr);                            \
140329eaa64Smrg        r->y1 = (short)(yt);                            \
141329eaa64Smrg        r->x2 = (short)(xr);                            \
142329eaa64Smrg        r->y2 = (short)(yb);                            \
143329eaa64Smrg        r++;                                            \
144329eaa64Smrg                                                        \
145329eaa64Smrg        r->x1 = (short)(xinnerl + xthird);              \
146329eaa64Smrg        r->y1 = (short)(yinnert);                       \
147329eaa64Smrg        r->x2 = (short)(r->x1);                         \
148329eaa64Smrg        r->y2 = (short)(yinnerb);                       \
149329eaa64Smrg        r++;                                            \
150329eaa64Smrg                                                        \
151329eaa64Smrg        r->x1 = (short)(xinnerl + (2 * xthird));        \
152329eaa64Smrg        r->y1 = (short)(yinnert);                       \
153329eaa64Smrg        r->x2 = (short)(r->x1);                         \
154329eaa64Smrg        r->y2 = (short)(yinnerb);                       \
155329eaa64Smrg        r++;                                            \
156329eaa64Smrg                                                        \
157329eaa64Smrg        r->x1 = (short)(xinnerl);                       \
158329eaa64Smrg        r->y1 = (short)(yinnert + ythird);              \
159329eaa64Smrg        r->x2 = (short)(xinnerr);                       \
160329eaa64Smrg        r->y2 = (short)(r->y1);                         \
161329eaa64Smrg        r++;                                            \
162329eaa64Smrg                                                        \
163329eaa64Smrg        r->x1 = (short)(xinnerl);                       \
164329eaa64Smrg        r->y1 = (short)(yinnert + (2 * ythird));        \
165329eaa64Smrg        r->x2 = (short)(xinnerr);                       \
166329eaa64Smrg        r->y2 = (short)(r->y1);                         \
167329eaa64Smrg        r++;                                            \
168329eaa64Smrg                                                        \
169329eaa64Smrg        if (lastTH != 0) {                              \
170329eaa64Smrg            r->x1 = (short)(xl);                        \
171329eaa64Smrg            r->y1 = (short)(yt + lastTH);               \
172329eaa64Smrg            r->x2 = (short)(xr);                        \
173329eaa64Smrg            r->y2 = (short)(r->y1);                     \
174329eaa64Smrg            r++;                                        \
175329eaa64Smrg        }                                               \
1763e747e6dSmrg    }
1773e747e6dSmrg
1783e747e6dSmrg    /* undraw the old one, if any */
179329eaa64Smrg    DRAWIT();
1803e747e6dSmrg
1813e747e6dSmrg    lastx = x;
1823e747e6dSmrg    lasty = y;
1833e747e6dSmrg    lastWidth = width;
1843e747e6dSmrg    lastHeight = height;
1853e747e6dSmrg    lastBW = bw;
1863e747e6dSmrg    lastTH = th;
1873e747e6dSmrg
1883e747e6dSmrg    /* draw the new one, if any */
189329eaa64Smrg    DRAWIT();
1903e747e6dSmrg
1913e747e6dSmrg#undef DRAWIT
1923e747e6dSmrg
193329eaa64Smrg    if (r != outline) {
194329eaa64Smrg        XDrawSegments(dpy, root, Scr->DrawGC, outline, (int) (r - outline));
1953e747e6dSmrg    }
1963e747e6dSmrg}
1973e747e6dSmrg
1983e747e6dSmrg/**
1993e747e6dSmrg * zoom in or out of an icon
2003e747e6dSmrg *
2013e747e6dSmrg *  \param wf window to zoom from
2023e747e6dSmrg *  \param wt window to zoom to
2033e747e6dSmrg */
2043e747e6dSmrgvoid
2053e747e6dSmrgZoom(Window wf, Window wt)
2063e747e6dSmrg{
207329eaa64Smrg    int fx, fy, tx, ty;         /* from, to */
208329eaa64Smrg    unsigned int fw, fh, tw, th;        /* from, to */
2093e747e6dSmrg    long dx, dy, dw, dh;
2103e747e6dSmrg    long z;
2113e747e6dSmrg    int j;
212b66deae1Smrg    unsigned udummy = 0;
213b66deae1Smrg    Window wdummy = None;
2143e747e6dSmrg
215329eaa64Smrg    if (!Scr->DoZoom || Scr->ZoomCount < 1)
216329eaa64Smrg        return;
2173e747e6dSmrg
218329eaa64Smrg    if (wf == None || wt == None)
219329eaa64Smrg        return;
2203e747e6dSmrg
221b66deae1Smrg    XGetGeometry(dpy, wf, &wdummy, &fx, &fy, &fw, &fh, &udummy, &udummy);
222b66deae1Smrg    XGetGeometry(dpy, wt, &wdummy, &tx, &ty, &tw, &th, &udummy, &udummy);
2233e747e6dSmrg
224329eaa64Smrg    dx = ((long) (tx - fx));    /* going from -> to */
225329eaa64Smrg    dy = ((long) (ty - fy));    /* going from -> to */
226329eaa64Smrg    dw = ((long) (tw - fw));    /* going from -> to */
227329eaa64Smrg    dh = ((long) (th - fh));    /* going from -> to */
2283e747e6dSmrg    z = (long) (Scr->ZoomCount + 1);
2293e747e6dSmrg
2303e747e6dSmrg    for (j = 0; j < 2; j++) {
231329eaa64Smrg        long i;
232329eaa64Smrg
233329eaa64Smrg        XDrawRectangle(dpy, Scr->Root, Scr->DrawGC, fx, fy, fw, fh);
234329eaa64Smrg        for (i = 1; i < z; i++) {
235329eaa64Smrg            int x = fx + (int) ((dx * i) / z);
236329eaa64Smrg            int y = fy + (int) ((dy * i) / z);
237329eaa64Smrg            unsigned width = (unsigned) (((long) fw) + (dw * i) / z);
238329eaa64Smrg            unsigned height = (unsigned) (((long) fh) + (dh * i) / z);
239329eaa64Smrg
240329eaa64Smrg            XDrawRectangle(dpy, Scr->Root, Scr->DrawGC, x, y, width, height);
241329eaa64Smrg        }
242329eaa64Smrg        XDrawRectangle(dpy, Scr->Root, Scr->DrawGC, tx, ty, tw, th);
2433e747e6dSmrg    }
2443e747e6dSmrg}
2453e747e6dSmrg
2463e747e6dSmrg/**
247ffd25bcaSmrg * expand the tilde character to HOME if it is the first
2483e747e6dSmrg * character of the filename
2493e747e6dSmrg *
250329eaa64Smrg *      \return a pointer to the new name
2513e747e6dSmrg *
2523e747e6dSmrg *  \param name  the filename to expand
2533e747e6dSmrg */
2543e747e6dSmrgchar *
255c9398294SchristosExpandFilename(const char *name)
2563e747e6dSmrg{
2573e747e6dSmrg    char *newname;
2583e747e6dSmrg
259329eaa64Smrg    if (name[0] != '~')
260329eaa64Smrg        return strdup(name);
2613e747e6dSmrg
262b66deae1Smrg    newname = (char *) malloc((size_t) HomeLen + strlen(name) + 2);
2633e747e6dSmrg    if (!newname) {
264329eaa64Smrg        twmWarning("unable to allocate %lu bytes to expand filename %s/%s",
265329eaa64Smrg                   (unsigned long) HomeLen + (unsigned long) strlen(name) + 2,
266329eaa64Smrg                   Home, &name[1]);
267329eaa64Smrg    }
268329eaa64Smrg    else {
269329eaa64Smrg        (void) sprintf(newname, "%s/%s", Home, &name[1]);
2703e747e6dSmrg    }
2713e747e6dSmrg
2723e747e6dSmrg    return newname;
2733e747e6dSmrg}
2743e747e6dSmrg
2753e747e6dSmrg/**
2763e747e6dSmrg * read in the bitmap file for the unknown icon
2773e747e6dSmrg *
2783e747e6dSmrg * \param name  the filename to read
2793e747e6dSmrg */
2803e747e6dSmrgvoid
281c2535118SmrgGetUnknownIcon(const char *name)
2823e747e6dSmrg{
283b66deae1Smrg    int dummy = 0;
284b66deae1Smrg    unsigned udummy = 0;
285b66deae1Smrg    Window wdummy = None;
286b66deae1Smrg
287329eaa64Smrg    if ((Scr->UnknownPm = GetBitmap(name)) != None) {
288b66deae1Smrg        XGetGeometry(dpy, Scr->UnknownPm, &wdummy, &dummy, &dummy,
289329eaa64Smrg                     (unsigned int *) &Scr->UnknownWidth,
290b66deae1Smrg                     (unsigned int *) &Scr->UnknownHeight, &udummy, &udummy);
2913e747e6dSmrg    }
2923e747e6dSmrg}
2933e747e6dSmrg
2943e747e6dSmrg/**
295329eaa64Smrg *      FindBitmap - read in a bitmap file and return size
2963e747e6dSmrg *
2973e747e6dSmrg *  \return pixmap associated with bitmap
2983e747e6dSmrg *
2993e747e6dSmrg *  \param name          filename to read
3003e747e6dSmrg *  \param[out] widthp   pointer to width of bitmap
301329eaa64Smrg *  \param[out] heightp  pointer to height of bitmap
3023e747e6dSmrg */
303ffd25bcaSmrgPixmap
304329eaa64SmrgFindBitmap(const char *name, unsigned *widthp, unsigned *heightp)
3053e747e6dSmrg{
3063e747e6dSmrg    char *bigname;
3073e747e6dSmrg    Pixmap pm;
3083e747e6dSmrg
309329eaa64Smrg    if (!name)
310329eaa64Smrg        return None;
3113e747e6dSmrg
3123e747e6dSmrg    /*
3133e747e6dSmrg     * Names of the form :name refer to hardcoded images that are scaled to
3143e747e6dSmrg     * look nice in title buttons.  Eventually, it would be nice to put in a
3153e747e6dSmrg     * menu symbol as well....
3163e747e6dSmrg     */
3173e747e6dSmrg    if (name[0] == ':') {
318329eaa64Smrg        int i;
319329eaa64Smrg	/* *INDENT-OFF* */
320329eaa64Smrg        static struct {
321329eaa64Smrg            const char *name;
322329eaa64Smrg            Pixmap (*proc)(unsigned int *, unsigned int *);
323329eaa64Smrg        } pmtab[] = {
324329eaa64Smrg            { TBPM_DOT,         CreateDotPixmap },
325329eaa64Smrg            { TBPM_ICONIFY,     CreateDotPixmap },
326329eaa64Smrg            { TBPM_RESIZE,      CreateResizePixmap },
327329eaa64Smrg            { TBPM_XLOGO,       CreateXLogoPixmap },
328329eaa64Smrg            { TBPM_DELETE,      CreateXLogoPixmap },
329329eaa64Smrg            { TBPM_MENU,        CreateMenuPixmap },
330329eaa64Smrg            { TBPM_QUESTION,    CreateQuestionPixmap },
331329eaa64Smrg        };
332329eaa64Smrg	/* *INDENT-ON* */
333329eaa64Smrg
334329eaa64Smrg        for (i = 0; (size_t) i < (sizeof pmtab) / (sizeof pmtab[0]); i++) {
335329eaa64Smrg            if (XmuCompareISOLatin1(pmtab[i].name, name) == 0)
336329eaa64Smrg                return (*pmtab[i].proc) (widthp, heightp);
337329eaa64Smrg        }
338329eaa64Smrg        twmWarning("no such built-in bitmap \"%s\"", name);
339329eaa64Smrg        return None;
3403e747e6dSmrg    }
3413e747e6dSmrg
3423e747e6dSmrg    /*
3433e747e6dSmrg     * Generate a full pathname if any special prefix characters (such as ~)
3443e747e6dSmrg     * are used.  If the bigname is different from name, bigname will need to
3453e747e6dSmrg     * be freed.
3463e747e6dSmrg     */
347329eaa64Smrg    bigname = ExpandFilename(name);
348329eaa64Smrg    if (!bigname)
349329eaa64Smrg        return None;
3503e747e6dSmrg
3513e747e6dSmrg    /*
3523e747e6dSmrg     * look along bitmapFilePath resource same as toolkit clients
3533e747e6dSmrg     */
354329eaa64Smrg    pm = XmuLocateBitmapFile(ScreenOfDisplay(dpy, Scr->screen), bigname, NULL,
355329eaa64Smrg                             0, (int *) widthp, (int *) heightp, &HotX, &HotY);
3563e747e6dSmrg    if (pm == None && Scr->IconDirectory && bigname[0] != '/') {
357329eaa64Smrg        free(bigname);
358329eaa64Smrg        /*
359329eaa64Smrg         * Attempt to find icon in old IconDirectory (now obsolete)
360329eaa64Smrg         */
361b66deae1Smrg        bigname = (char *)
362b66deae1Smrg            malloc(strlen(name) + strlen(Scr->IconDirectory) + 2);
363329eaa64Smrg        if (!bigname) {
364329eaa64Smrg            twmWarning("unable to allocate memory for \"%s/%s\"",
365329eaa64Smrg                       Scr->IconDirectory, name);
366329eaa64Smrg            return None;
367329eaa64Smrg        }
368329eaa64Smrg        (void) sprintf(bigname, "%s/%s", Scr->IconDirectory, name);
369329eaa64Smrg        if (XReadBitmapFile(dpy, Scr->Root, bigname, widthp, heightp, &pm,
370329eaa64Smrg                            &HotX, &HotY) != BitmapSuccess) {
371329eaa64Smrg            pm = None;
372329eaa64Smrg        }
373329eaa64Smrg    }
374329eaa64Smrg    free(bigname);
3753e747e6dSmrg    if (pm == None) {
376329eaa64Smrg        twmWarning("unable to find bitmap \"%s\"", name);
3773e747e6dSmrg    }
3783e747e6dSmrg
3793e747e6dSmrg    return pm;
3803e747e6dSmrg}
3813e747e6dSmrg
382ffd25bcaSmrgPixmap
383329eaa64SmrgGetBitmap(const char *name)
3843e747e6dSmrg{
385b66deae1Smrg    unsigned udummy = 0;
386b66deae1Smrg
387b66deae1Smrg    return FindBitmap(name, &udummy, &udummy);
3883e747e6dSmrg}
3893e747e6dSmrg
3903e747e6dSmrgvoid
391329eaa64SmrgInsertRGBColormap(Atom a, XStandardColormap *maps, int nmaps, Bool replace)
3923e747e6dSmrg{
3933e747e6dSmrg    StdCmap *sc = NULL;
3943e747e6dSmrg
395329eaa64Smrg    if (replace) {              /* locate existing entry */
396329eaa64Smrg        for (sc = Scr->StdCmapInfo.head; sc; sc = sc->next) {
397329eaa64Smrg            if (sc->atom == a)
398329eaa64Smrg                break;
399329eaa64Smrg        }
400329eaa64Smrg    }
401329eaa64Smrg
402329eaa64Smrg    if (!sc) {                  /* no existing, allocate new */
403b66deae1Smrg        sc = (StdCmap *) malloc(sizeof(StdCmap));
404329eaa64Smrg        if (!sc) {
405329eaa64Smrg            twmWarning("unable to allocate %lu bytes for StdCmap",
406329eaa64Smrg                       (unsigned long) sizeof(StdCmap));
407329eaa64Smrg            return;
408329eaa64Smrg        }
409329eaa64Smrg        replace = False;
410329eaa64Smrg    }
411329eaa64Smrg
412329eaa64Smrg    if (replace) {              /* just update contents */
413329eaa64Smrg        if (sc->maps)
414329eaa64Smrg            XFree(sc->maps);
415329eaa64Smrg        if (sc == Scr->StdCmapInfo.mru)
416329eaa64Smrg            Scr->StdCmapInfo.mru = NULL;
417329eaa64Smrg    }
418329eaa64Smrg    else {                      /* else appending */
419329eaa64Smrg        sc->next = NULL;
420329eaa64Smrg        sc->atom = a;
421329eaa64Smrg        if (Scr->StdCmapInfo.tail) {
422329eaa64Smrg            Scr->StdCmapInfo.tail->next = sc;
423329eaa64Smrg        }
424329eaa64Smrg        else {
425329eaa64Smrg            Scr->StdCmapInfo.head = sc;
426329eaa64Smrg        }
427329eaa64Smrg        Scr->StdCmapInfo.tail = sc;
4283e747e6dSmrg    }
4293e747e6dSmrg    sc->nmaps = nmaps;
4303e747e6dSmrg    sc->maps = maps;
4313e747e6dSmrg
4323e747e6dSmrg    return;
4333e747e6dSmrg}
4343e747e6dSmrg
4353e747e6dSmrgvoid
436329eaa64SmrgRemoveRGBColormap(Atom a)
4373e747e6dSmrg{
4383e747e6dSmrg    StdCmap *sc, *prev;
4393e747e6dSmrg
4403e747e6dSmrg    prev = NULL;
441ffd25bcaSmrg    for (sc = Scr->StdCmapInfo.head; sc; sc = sc->next) {
442329eaa64Smrg        if (sc->atom == a)
443329eaa64Smrg            break;
444329eaa64Smrg        prev = sc;
4453e747e6dSmrg    }
446329eaa64Smrg    if (sc) {                   /* found one */
447329eaa64Smrg        if (sc->maps)
448329eaa64Smrg            XFree(sc->maps);
449329eaa64Smrg        if (prev)
450329eaa64Smrg            prev->next = sc->next;
451329eaa64Smrg        if (Scr->StdCmapInfo.head == sc)
452329eaa64Smrg            Scr->StdCmapInfo.head = sc->next;
453329eaa64Smrg        if (Scr->StdCmapInfo.tail == sc)
454329eaa64Smrg            Scr->StdCmapInfo.tail = prev;
455329eaa64Smrg        if (Scr->StdCmapInfo.mru == sc)
456329eaa64Smrg            Scr->StdCmapInfo.mru = NULL;
4573e747e6dSmrg    }
4583e747e6dSmrg    return;
4593e747e6dSmrg}
4603e747e6dSmrg
4613e747e6dSmrgvoid
462c2535118SmrgLocateStandardColormaps(void)
4633e747e6dSmrg{
4643e747e6dSmrg    Atom *atoms;
4653e747e6dSmrg    int natoms;
4663e747e6dSmrg    int i;
4673e747e6dSmrg
468329eaa64Smrg    atoms = XListProperties(dpy, Scr->Root, &natoms);
4693e747e6dSmrg    for (i = 0; i < natoms; i++) {
470329eaa64Smrg        XStandardColormap *maps = NULL;
471329eaa64Smrg        int nmaps;
4723e747e6dSmrg
473329eaa64Smrg        if (XGetRGBColormaps(dpy, Scr->Root, &maps, &nmaps, atoms[i])) {
474329eaa64Smrg            /* if got one, then append to current list */
475329eaa64Smrg            InsertRGBColormap(atoms[i], maps, nmaps, False);
476329eaa64Smrg        }
4773e747e6dSmrg    }
478329eaa64Smrg    if (atoms)
479329eaa64Smrg        XFree(atoms);
4803e747e6dSmrg    return;
4813e747e6dSmrg}
4823e747e6dSmrg
4833e747e6dSmrgvoid
484c2535118SmrgGetColor(int kind, Pixel *what, const char *name)
4853e747e6dSmrg{
4863e747e6dSmrg    XColor color, junkcolor;
4873e747e6dSmrg    Status stat = 0;
4883e747e6dSmrg    Colormap cmap = Scr->TwmRoot.cmaps.cwins[0]->colormap->c;
4893e747e6dSmrg
4903e747e6dSmrg    if (!Scr->FirstTime)
491329eaa64Smrg        return;
4923e747e6dSmrg
4933e747e6dSmrg    if (Scr->Monochrome != kind)
494329eaa64Smrg        return;
495329eaa64Smrg
496329eaa64Smrg    if (!XAllocNamedColor(dpy, cmap, name, &color, &junkcolor)) {
497329eaa64Smrg        /* if we could not allocate the color, let's see if this is a
498329eaa64Smrg         * standard colormap
499329eaa64Smrg         */
500329eaa64Smrg        XStandardColormap *stdcmap = NULL;
501329eaa64Smrg
502329eaa64Smrg        /* parse the named color */
503329eaa64Smrg        if (name[0] != '#')
504329eaa64Smrg            stat = XParseColor(dpy, cmap, name, &color);
505329eaa64Smrg        if (!stat) {
506329eaa64Smrg            twmWarning("invalid color name \"%s\"", name);
507329eaa64Smrg            return;
508329eaa64Smrg        }
509329eaa64Smrg
510329eaa64Smrg        /*
511329eaa64Smrg         * look through the list of standard colormaps (check cache first)
512329eaa64Smrg         */
513329eaa64Smrg        if (Scr->StdCmapInfo.mru && Scr->StdCmapInfo.mru->maps &&
514329eaa64Smrg            (Scr->StdCmapInfo.mru->maps[Scr->StdCmapInfo.mruindex].colormap ==
515329eaa64Smrg             cmap)) {
516329eaa64Smrg            stdcmap = &(Scr->StdCmapInfo.mru->maps[Scr->StdCmapInfo.mruindex]);
517329eaa64Smrg        }
518329eaa64Smrg        else {
519329eaa64Smrg            StdCmap *sc;
520329eaa64Smrg
521329eaa64Smrg            for (sc = Scr->StdCmapInfo.head; sc; sc = sc->next) {
522329eaa64Smrg                int i;
523329eaa64Smrg
524329eaa64Smrg                for (i = 0; i < sc->nmaps; i++) {
525329eaa64Smrg                    if (sc->maps[i].colormap == cmap) {
526329eaa64Smrg                        Scr->StdCmapInfo.mru = sc;
527329eaa64Smrg                        Scr->StdCmapInfo.mruindex = i;
528329eaa64Smrg                        stdcmap = &(sc->maps[i]);
529329eaa64Smrg                        goto gotit;
530329eaa64Smrg                    }
531329eaa64Smrg                }
532329eaa64Smrg            }
533329eaa64Smrg        }
534329eaa64Smrg
535329eaa64Smrg gotit:
536329eaa64Smrg        if (stdcmap) {
5373e747e6dSmrg            color.pixel = (stdcmap->base_pixel +
538329eaa64Smrg                           ((Pixel) (((float) color.red / 65535.0) *
539329eaa64Smrg                                     (double) stdcmap->red_max + 0.5) *
540329eaa64Smrg                            stdcmap->red_mult) +
541329eaa64Smrg                           ((Pixel) (((float) color.green / 65535.0) *
542329eaa64Smrg                                     (double) stdcmap->green_max + 0.5) *
543329eaa64Smrg                            stdcmap->green_mult) +
544329eaa64Smrg                           ((Pixel) (((float) color.blue / 65535.0) *
545329eaa64Smrg                                     (double) stdcmap->blue_max + 0.5) *
546329eaa64Smrg                            stdcmap->blue_mult));
547329eaa64Smrg        }
548329eaa64Smrg        else {
549329eaa64Smrg            twmWarning("unable to allocate color \"%s\"", name);
550329eaa64Smrg            return;
551329eaa64Smrg        }
5523e747e6dSmrg    }
5533e747e6dSmrg
5543e747e6dSmrg    *what = color.pixel;
5553e747e6dSmrg}
5563e747e6dSmrg
5573e747e6dSmrgvoid
558c2535118SmrgGetColorValue(int kind, XColor *what, const char *name)
5593e747e6dSmrg{
5603e747e6dSmrg    XColor junkcolor;
5613e747e6dSmrg    Colormap cmap = Scr->TwmRoot.cmaps.cwins[0]->colormap->c;
5623e747e6dSmrg
5633e747e6dSmrg    if (!Scr->FirstTime)
564329eaa64Smrg        return;
5653e747e6dSmrg
5663e747e6dSmrg    if (Scr->Monochrome != kind)
567329eaa64Smrg        return;
5683e747e6dSmrg
569329eaa64Smrg    if (!XLookupColor(dpy, cmap, name, what, &junkcolor)) {
570329eaa64Smrg        twmWarning("invalid color name \"%s\"", name);
5713e747e6dSmrg    }
572329eaa64Smrg    else {
573329eaa64Smrg        what->pixel = AllPlanes;
5743e747e6dSmrg    }
5753e747e6dSmrg}
5763e747e6dSmrg
577329eaa64Smrgstatic Boolean
578329eaa64SmrgFindFontSet(MyFont *font, const char *fontname)
5793e747e6dSmrg{
5803e747e6dSmrg    char **missing_charset_list_return;
5813e747e6dSmrg    int missing_charset_count_return;
5823e747e6dSmrg    char *def_string_return;
5833e747e6dSmrg    XFontSetExtents *font_extents;
5843e747e6dSmrg    XFontStruct **xfonts;
5853e747e6dSmrg    char **font_names;
5863e747e6dSmrg
5873e747e6dSmrg    if (use_fontset) {
588329eaa64Smrg        int ascent;
589329eaa64Smrg        int descent;
590329eaa64Smrg        int fnum;
591b66deae1Smrg        int i;
592329eaa64Smrg
593329eaa64Smrg        if (font->fontset != NULL) {
594329eaa64Smrg            XFreeFontSet(dpy, font->fontset);
595329eaa64Smrg        }
596329eaa64Smrg
597329eaa64Smrg        if ((font->fontset = XCreateFontSet(dpy, fontname,
598329eaa64Smrg                                            &missing_charset_list_return,
599329eaa64Smrg                                            &missing_charset_count_return,
600329eaa64Smrg                                            &def_string_return)) == NULL) {
601329eaa64Smrg            return False;
602329eaa64Smrg        }
603329eaa64Smrg        if (missing_charset_count_return) {
604329eaa64Smrg            twmVerbose("%d fonts are missing from fontset",
605329eaa64Smrg                       missing_charset_count_return);
606329eaa64Smrg            for (i = 0; i < missing_charset_count_return; i++) {
607329eaa64Smrg                twmVerbose("font for charset %s is lacking.",
608329eaa64Smrg                           missing_charset_list_return[i]);
609329eaa64Smrg            }
610b66deae1Smrg            XFreeStringList(missing_charset_list_return);
611329eaa64Smrg        }
612329eaa64Smrg
613329eaa64Smrg        font_extents = XExtentsOfFontSet(font->fontset);
614329eaa64Smrg        fnum = XFontsOfFontSet(font->fontset, &xfonts, &font_names);
615329eaa64Smrg        for (i = 0, ascent = 0, descent = 0; i < fnum; i++) {
616329eaa64Smrg            if (ascent < (*xfonts)->ascent)
617329eaa64Smrg                ascent = (*xfonts)->ascent;
618329eaa64Smrg            if (descent < (*xfonts)->descent)
619329eaa64Smrg                descent = (*xfonts)->descent;
620329eaa64Smrg            xfonts++;
621329eaa64Smrg        }
622329eaa64Smrg        font->height = font_extents->max_logical_extent.height;
623329eaa64Smrg        font->y = ascent;
624329eaa64Smrg        font->ascent = ascent;
625329eaa64Smrg        font->descent = descent;
626329eaa64Smrg        twmMessage("created fontset with %d fonts (%d missing) for \"%s\"",
627329eaa64Smrg                   fnum, missing_charset_count_return,
628329eaa64Smrg                   fontname ? fontname : "NULL");
629329eaa64Smrg        return True;
6303e747e6dSmrg    }
6313e747e6dSmrg
6323e747e6dSmrg    if (font->font != NULL)
633329eaa64Smrg        XFreeFont(dpy, font->font);
6343e747e6dSmrg
635329eaa64Smrg    if ((font->font = XLoadQueryFont(dpy, fontname)) == NULL) {
636329eaa64Smrg        return False;
6373e747e6dSmrg    }
6383e747e6dSmrg    font->height = font->font->ascent + font->font->descent;
6393e747e6dSmrg    font->y = font->font->ascent;
6403e747e6dSmrg    font->ascent = font->font->ascent;
6413e747e6dSmrg    font->descent = font->font->descent;
642329eaa64Smrg    return True;
643329eaa64Smrg}
644329eaa64Smrg
645329eaa64Smrg/*
646329eaa64Smrg * The following functions are sensible to 'use_fontset'.
647329eaa64Smrg * When 'use_fontset' is True,
648329eaa64Smrg *  - XFontSet-related internationalized functions are used
649329eaa64Smrg *     so as multibyte languages can be displayed.
650329eaa64Smrg * When 'use_fontset' is False,
651329eaa64Smrg *  - XFontStruct-related conventional functions are used
652329eaa64Smrg *     so as 8-bit characters can be displayed even when
653329eaa64Smrg *     locale is not set properly.
654329eaa64Smrg */
655329eaa64Smrgvoid
656329eaa64SmrgGetFont(MyFont *font)
657329eaa64Smrg{
658329eaa64Smrg
659329eaa64Smrg    if (!FindFontSet(font, font->name)) {
660329eaa64Smrg        const char *what = "fonts";
661329eaa64Smrg        const char *deffontname = "fixed";
662329eaa64Smrg
663329eaa64Smrg        if (use_fontset) {
664329eaa64Smrg            what = "fontsets";
665329eaa64Smrg        }
666329eaa64Smrg        else if (Scr->DefaultFont.name) {
667329eaa64Smrg            deffontname = Scr->DefaultFont.name;
668329eaa64Smrg        }
669329eaa64Smrg        if (!FindFontSet(font, deffontname)) {
670329eaa64Smrg            twmError("unable to open %s \"%s\" or \"%s\"",
671329eaa64Smrg                     what, font->name, deffontname);
672329eaa64Smrg        }
673329eaa64Smrg    }
6743e747e6dSmrg}
6753e747e6dSmrg
676b66deae1Smrgvoid
677b66deae1SmrgDestroyFont(MyFont *font)
678b66deae1Smrg{
679b66deae1Smrg    if (!font) {
680b66deae1Smrg        return;
681b66deae1Smrg    }
682b66deae1Smrg
683b66deae1Smrg    if (font->fontset) {
684b66deae1Smrg        XFreeFontSet(dpy, font->fontset);
685b66deae1Smrg        font->fontset = NULL;
686b66deae1Smrg    }
687b66deae1Smrg
688b66deae1Smrg    if (font->font) {
689b66deae1Smrg        XFreeFont(dpy, font->font);
690b66deae1Smrg        font->font = NULL;
691b66deae1Smrg    }
692b66deae1Smrg}
693b66deae1Smrg
6943e747e6dSmrgint
695c2535118SmrgMyFont_TextWidth(MyFont *font, const char *string, int len)
6963e747e6dSmrg{
6973e747e6dSmrg    XRectangle ink_rect;
6983e747e6dSmrg    XRectangle logical_rect;
6993e747e6dSmrg
7003e747e6dSmrg    if (use_fontset) {
701329eaa64Smrg        XmbTextExtents(font->fontset, string, len, &ink_rect, &logical_rect);
702329eaa64Smrg        return logical_rect.width;
7033e747e6dSmrg    }
7043e747e6dSmrg    return XTextWidth(font->font, string, len);
7053e747e6dSmrg}
7063e747e6dSmrg
7073e747e6dSmrgvoid
708329eaa64SmrgMyFont_DrawImageString(Display *dpy2, Drawable d, MyFont *font, GC gc,
709c2535118Smrg                       int x, int y, const char *string, int len)
7103e747e6dSmrg{
7113e747e6dSmrg    if (use_fontset) {
712329eaa64Smrg        XmbDrawImageString(dpy2, d, font->fontset, gc, x, y, string, len);
713329eaa64Smrg        return;
7143e747e6dSmrg    }
715329eaa64Smrg    XDrawImageString(dpy2, d, gc, x, y, string, len);
7163e747e6dSmrg}
7173e747e6dSmrg
7183e747e6dSmrgvoid
719329eaa64SmrgMyFont_DrawString(Display *dpy2, Drawable d, MyFont *font, GC gc,
720c2535118Smrg                  int x, int y, const char *string, int len)
7213e747e6dSmrg{
7223e747e6dSmrg    if (use_fontset) {
723329eaa64Smrg        XmbDrawString(dpy2, d, font->fontset, gc, x, y, string, len);
724329eaa64Smrg        return;
7253e747e6dSmrg    }
726329eaa64Smrg    XDrawString(dpy2, d, gc, x, y, string, len);
7273e747e6dSmrg}
7283e747e6dSmrg
7293e747e6dSmrgvoid
730ffd25bcaSmrgMyFont_ChangeGC(unsigned long fix_fore, unsigned long fix_back,
7313e747e6dSmrg                MyFont *fix_font)
7323e747e6dSmrg{
7333e747e6dSmrg    Gcv.foreground = fix_fore;
7343e747e6dSmrg    Gcv.background = fix_back;
7353e747e6dSmrg    if (use_fontset) {
736329eaa64Smrg        XChangeGC(dpy, Scr->NormalGC, GCForeground | GCBackground, &Gcv);
737329eaa64Smrg        return;
7383e747e6dSmrg    }
7393e747e6dSmrg    Gcv.font = fix_font->font->fid;
740329eaa64Smrg    XChangeGC(dpy, Scr->NormalGC, GCFont | GCForeground | GCBackground, &Gcv);
7413e747e6dSmrg}
7423e747e6dSmrg
7433e747e6dSmrg/*
7443e747e6dSmrg * The following functions are internationalized substitutions
7453e747e6dSmrg * for XFetchName and XGetIconName using XGetWMName and
746ffd25bcaSmrg * XGetWMIconName.
7473e747e6dSmrg *
748ffd25bcaSmrg * Please note that the third arguments have to be freed using free(),
7493e747e6dSmrg * not XFree().
7503e747e6dSmrg */
7513e747e6dSmrgStatus
752329eaa64SmrgI18N_FetchName(Display *dpy2, Window w, char **winname)
7533e747e6dSmrg{
754329eaa64Smrg    int status;
7553e747e6dSmrg    XTextProperty text_prop;
756329eaa64Smrg    int rc = 0;
757329eaa64Smrg
758329eaa64Smrg    *winname = NULL;
759329eaa64Smrg
760329eaa64Smrg    status = XGetWMName(dpy2, w, &text_prop);
761329eaa64Smrg    if (status && text_prop.value && text_prop.nitems) {
762329eaa64Smrg        char **list = NULL;
763329eaa64Smrg        int num;
764329eaa64Smrg
765329eaa64Smrg        status = XmbTextPropertyToTextList(dpy2, &text_prop, &list, &num);
766329eaa64Smrg        if (status >= Success && num && list && *list) {
767329eaa64Smrg            XFree(text_prop.value);
768329eaa64Smrg            *winname = strdup(*list);
769329eaa64Smrg            XFreeStringList(list);
770329eaa64Smrg            rc = 1;
771329eaa64Smrg        }
772329eaa64Smrg        else {
773329eaa64Smrg            char *value = NULL;
774329eaa64Smrg
775329eaa64Smrg            /*
776329eaa64Smrg             * If the system's locale support is broken (e.g., missing useful
777329eaa64Smrg             * parts), the preceding Xmb call may fail.
778329eaa64Smrg             */
779329eaa64Smrg            if (XFetchName(dpy2, w, &value) && value != NULL) {
780329eaa64Smrg                *winname = strdup(value);
781329eaa64Smrg                XFree(value);
782329eaa64Smrg                rc = 1;
783329eaa64Smrg            }
784329eaa64Smrg        }
7853e747e6dSmrg    }
786329eaa64Smrg
787329eaa64Smrg    return rc;
7883e747e6dSmrg}
7893e747e6dSmrg
7903e747e6dSmrgStatus
791329eaa64SmrgI18N_GetIconName(Display *dpy2, Window w, char **iconname)
7923e747e6dSmrg{
793329eaa64Smrg    int status;
7943e747e6dSmrg    XTextProperty text_prop;
7953e747e6dSmrg    char **list;
796329eaa64Smrg    int num;
797329eaa64Smrg
798329eaa64Smrg    status = XGetWMIconName(dpy2, w, &text_prop);
799329eaa64Smrg    if (!status || !text_prop.value || !text_prop.nitems)
800329eaa64Smrg        return 0;
801329eaa64Smrg    status = XmbTextPropertyToTextList(dpy2, &text_prop, &list, &num);
802329eaa64Smrg    if (status < Success || !num || !*list)
803329eaa64Smrg        return 0;
8043e747e6dSmrg    XFree(text_prop.value);
805329eaa64Smrg    *iconname = (char *) strdup(*list);
8063e747e6dSmrg    XFreeStringList(list);
8073e747e6dSmrg    return 1;
8083e747e6dSmrg}
8093e747e6dSmrg
8103e747e6dSmrg/**
8113e747e6dSmrg * separate routine to set focus to make things more understandable
8123e747e6dSmrg * and easier to debug
8133e747e6dSmrg */
8143e747e6dSmrgvoid
815329eaa64SmrgSetFocus(TwmWindow *tmp_win, Time time)
8163e747e6dSmrg{
8173e747e6dSmrg    Window w = (tmp_win ? tmp_win->w : PointerRoot);
8183e747e6dSmrg
8193e747e6dSmrg#ifdef TRACE
8203e747e6dSmrg    if (tmp_win) {
821329eaa64Smrg        twmMessage("Focusing on window \"%s\"", tmp_win->full_name);
822329eaa64Smrg    }
823329eaa64Smrg    else {
824329eaa64Smrg        twmMessage("Unfocusing; Scr->Focus was \"%s\"",
825329eaa64Smrg                   Scr->Focus ? Scr->Focus->full_name : "(nil)");
8263e747e6dSmrg    }
8273e747e6dSmrg#endif
8283e747e6dSmrg
829329eaa64Smrg    XSetInputFocus(dpy, w, RevertToPointerRoot, time);
8303e747e6dSmrg}
8313e747e6dSmrg
832ffd25bcaSmrgstatic Pixmap
833329eaa64SmrgCreateXLogoPixmap(unsigned *widthp, unsigned *heightp)
8343e747e6dSmrg{
8353e747e6dSmrg    int h = Scr->TBInfo.width - Scr->TBInfo.border * 2;
836329eaa64Smrg
837329eaa64Smrg    if (h < 0)
838329eaa64Smrg        h = 0;
8393e747e6dSmrg
8403e747e6dSmrg    *widthp = *heightp = (unsigned int) h;
8413e747e6dSmrg    if (Scr->tbpm.xlogo == None) {
842329eaa64Smrg        GC gc, gcBack;
843329eaa64Smrg
844329eaa64Smrg        Scr->tbpm.xlogo =
845329eaa64Smrg            XCreatePixmap(dpy, Scr->Root, (unsigned) h, (unsigned) h, 1);
846329eaa64Smrg        gc = XCreateGC(dpy, Scr->tbpm.xlogo, 0L, NULL);
847329eaa64Smrg        XSetForeground(dpy, gc, 0);
848329eaa64Smrg        XFillRectangle(dpy, Scr->tbpm.xlogo, gc, 0, 0, (unsigned) h,
849329eaa64Smrg                       (unsigned) h);
850329eaa64Smrg        XSetForeground(dpy, gc, 1);
851329eaa64Smrg        gcBack = XCreateGC(dpy, Scr->tbpm.xlogo, 0L, NULL);
852329eaa64Smrg        XSetForeground(dpy, gcBack, 0);
853329eaa64Smrg
854329eaa64Smrg        /*
855329eaa64Smrg         * draw the logo large so that it gets as dense as possible; then white
856329eaa64Smrg         * out the edges so that they look crisp
857329eaa64Smrg         */
858329eaa64Smrg        XmuDrawLogo(dpy, Scr->tbpm.xlogo, gc, gcBack, -1, -1,
859329eaa64Smrg                    (unsigned) (h + 2), (unsigned) (h + 2));
860329eaa64Smrg        XDrawRectangle(dpy, Scr->tbpm.xlogo, gcBack, 0, 0, (unsigned) (h - 1),
861329eaa64Smrg                       (unsigned) (h - 1));
862329eaa64Smrg
863329eaa64Smrg        /*
864329eaa64Smrg         * done drawing
865329eaa64Smrg         */
866329eaa64Smrg        XFreeGC(dpy, gc);
867329eaa64Smrg        XFreeGC(dpy, gcBack);
8683e747e6dSmrg    }
8693e747e6dSmrg    return Scr->tbpm.xlogo;
8703e747e6dSmrg}
8713e747e6dSmrg
872ffd25bcaSmrgstatic Pixmap
873329eaa64SmrgCreateResizePixmap(unsigned *widthp, unsigned *heightp)
8743e747e6dSmrg{
8753e747e6dSmrg    int h = Scr->TBInfo.width - Scr->TBInfo.border * 2;
876329eaa64Smrg
877329eaa64Smrg    if (h < 1)
878329eaa64Smrg        h = 1;
8793e747e6dSmrg
8803e747e6dSmrg    *widthp = *heightp = (unsigned int) h;
8813e747e6dSmrg    if (Scr->tbpm.resize == None) {
882329eaa64Smrg        XPoint points[3];
883329eaa64Smrg        GC gc;
884329eaa64Smrg        int w;
885329eaa64Smrg        int lw;
886329eaa64Smrg
887329eaa64Smrg        /*
888329eaa64Smrg         * create the pixmap
889329eaa64Smrg         */
890329eaa64Smrg        Scr->tbpm.resize =
891329eaa64Smrg            XCreatePixmap(dpy, Scr->Root, (unsigned) h, (unsigned) h, 1);
892329eaa64Smrg        gc = XCreateGC(dpy, Scr->tbpm.resize, 0L, NULL);
893329eaa64Smrg        XSetForeground(dpy, gc, 0);
894329eaa64Smrg        XFillRectangle(dpy, Scr->tbpm.resize, gc, 0, 0, (unsigned) h,
895329eaa64Smrg                       (unsigned) h);
896329eaa64Smrg        XSetForeground(dpy, gc, 1);
897329eaa64Smrg        lw = h / 16;
898329eaa64Smrg        if (lw == 1)
899329eaa64Smrg            lw = 0;
900329eaa64Smrg        XSetLineAttributes(dpy, gc, (unsigned) lw, LineSolid, CapButt,
901329eaa64Smrg                           JoinMiter);
902329eaa64Smrg
903329eaa64Smrg        /*
904329eaa64Smrg         * draw the resize button,
905329eaa64Smrg         */
906329eaa64Smrg        w = (h * 2) / 3;
907329eaa64Smrg        points[0].x = (short) w;
908329eaa64Smrg        points[0].y = 0;
909329eaa64Smrg        points[1].x = (short) w;
910329eaa64Smrg        points[1].y = (short) w;
911329eaa64Smrg        points[2].x = 0;
912329eaa64Smrg        points[2].y = (short) w;
913329eaa64Smrg        XDrawLines(dpy, Scr->tbpm.resize, gc, points, 3, CoordModeOrigin);
914329eaa64Smrg        w = w / 2;
915329eaa64Smrg        points[0].x = (short) w;
916329eaa64Smrg        points[0].y = 0;
917329eaa64Smrg        points[1].x = (short) w;
918329eaa64Smrg        points[1].y = (short) w;
919329eaa64Smrg        points[2].x = 0;
920329eaa64Smrg        points[2].y = (short) w;
921329eaa64Smrg        XDrawLines(dpy, Scr->tbpm.resize, gc, points, 3, CoordModeOrigin);
922329eaa64Smrg
923329eaa64Smrg        /*
924329eaa64Smrg         * done drawing
925329eaa64Smrg         */
926329eaa64Smrg        XFreeGC(dpy, gc);
9273e747e6dSmrg    }
9283e747e6dSmrg    return Scr->tbpm.resize;
9293e747e6dSmrg}
9303e747e6dSmrg
931ffd25bcaSmrgstatic Pixmap
932329eaa64SmrgCreateDotPixmap(unsigned *widthp, unsigned *heightp)
9333e747e6dSmrg{
9343e747e6dSmrg    int h = Scr->TBInfo.width - Scr->TBInfo.border * 2;
9353e747e6dSmrg
9363e747e6dSmrg    h = h * 3 / 4;
937329eaa64Smrg    if (h < 1)
938329eaa64Smrg        h = 1;
9393e747e6dSmrg    if (!(h & 1))
940329eaa64Smrg        h--;
9413e747e6dSmrg    *widthp = *heightp = (unsigned int) h;
942b66deae1Smrg    if (Scr->tbpm.remove == None) {
943329eaa64Smrg        GC gc;
944329eaa64Smrg        Pixmap pix;
945329eaa64Smrg
946b66deae1Smrg        pix = Scr->tbpm.remove =
947329eaa64Smrg            XCreatePixmap(dpy, Scr->Root, (unsigned) h, (unsigned) h, 1);
948329eaa64Smrg        gc = XCreateGC(dpy, pix, 0L, NULL);
949329eaa64Smrg        XSetLineAttributes(dpy, gc, (unsigned) h, LineSolid, CapRound,
950329eaa64Smrg                           JoinRound);
951329eaa64Smrg        XSetForeground(dpy, gc, 0L);
952329eaa64Smrg        XFillRectangle(dpy, pix, gc, 0, 0, (unsigned) h, (unsigned) h);
953329eaa64Smrg        XSetForeground(dpy, gc, 1L);
954329eaa64Smrg        XDrawLine(dpy, pix, gc, h / 2, h / 2, h / 2, h / 2);
955329eaa64Smrg        XFreeGC(dpy, gc);
9563e747e6dSmrg    }
957b66deae1Smrg    return Scr->tbpm.remove;
9583e747e6dSmrg}
9593e747e6dSmrg
9603e747e6dSmrg#define questionmark_width 8
9613e747e6dSmrg#define questionmark_height 8
9623e747e6dSmrgstatic char questionmark_bits[] = {
963329eaa64Smrg    0x38, 0x7c, 0x64, 0x30, 0x18, 0x00, 0x18, 0x18
964329eaa64Smrg};
9653e747e6dSmrg
966ffd25bcaSmrgstatic Pixmap
967329eaa64SmrgCreateQuestionPixmap(unsigned *widthp, unsigned *heightp)
9683e747e6dSmrg{
9693e747e6dSmrg    *widthp = questionmark_width;
9703e747e6dSmrg    *heightp = questionmark_height;
9713e747e6dSmrg    if (Scr->tbpm.question == None) {
972329eaa64Smrg        Scr->tbpm.question = XCreateBitmapFromData(dpy, Scr->Root,
973329eaa64Smrg                                                   questionmark_bits,
974329eaa64Smrg                                                   questionmark_width,
975329eaa64Smrg                                                   questionmark_height);
9763e747e6dSmrg    }
9773e747e6dSmrg    /*
9783e747e6dSmrg     * this must succeed or else we are in deep trouble elsewhere
9793e747e6dSmrg     */
9803e747e6dSmrg    return Scr->tbpm.question;
9813e747e6dSmrg}
9823e747e6dSmrg
983ffd25bcaSmrgstatic Pixmap
984329eaa64SmrgCreateMenuPixmap(unsigned *widthp, unsigned *heightp)
9853e747e6dSmrg{
986329eaa64Smrg    return CreateMenuIcon(Scr->TBInfo.width - Scr->TBInfo.border * 2,
987329eaa64Smrg                          widthp, heightp);
9883e747e6dSmrg}
9893e747e6dSmrg
990ffd25bcaSmrgPixmap
991329eaa64SmrgCreateMenuIcon(int height, unsigned *widthp, unsigned *heightp)
9923e747e6dSmrg{
9933e747e6dSmrg    int h, w;
9943e747e6dSmrg
9953e747e6dSmrg    h = height;
9963e747e6dSmrg    w = h * 7 / 8;
9973e747e6dSmrg    if (h < 1)
998329eaa64Smrg        h = 1;
9993e747e6dSmrg    if (w < 1)
1000329eaa64Smrg        w = 1;
1001329eaa64Smrg    *widthp = (unsigned) w;
1002329eaa64Smrg    *heightp = (unsigned) h;
10033e747e6dSmrg    if (Scr->tbpm.menu == None) {
1004329eaa64Smrg        Pixmap pix;
1005329eaa64Smrg        GC gc;
1006329eaa64Smrg        int ih, iw;
1007329eaa64Smrg        int ix, iy;
1008329eaa64Smrg        int mh, mw;
1009329eaa64Smrg        int tw, th;
1010329eaa64Smrg        int lw, lh;
1011329eaa64Smrg        int lx, ly;
1012329eaa64Smrg        int lines, dly;
1013329eaa64Smrg        int off;
1014329eaa64Smrg        int bw;
1015329eaa64Smrg
1016329eaa64Smrg        pix = Scr->tbpm.menu =
1017329eaa64Smrg            XCreatePixmap(dpy, Scr->Root, (unsigned) w, (unsigned) h, 1);
1018329eaa64Smrg        gc = XCreateGC(dpy, pix, 0L, NULL);
1019329eaa64Smrg        XSetForeground(dpy, gc, 0L);
1020329eaa64Smrg        XFillRectangle(dpy, pix, gc, 0, 0, (unsigned) w, (unsigned) h);
1021329eaa64Smrg        XSetForeground(dpy, gc, 1L);
1022329eaa64Smrg        ix = 1;
1023329eaa64Smrg        iy = 1;
1024329eaa64Smrg        ih = h - iy * 2;
1025329eaa64Smrg        iw = w - ix * 2;
1026329eaa64Smrg        off = ih / 8;
1027329eaa64Smrg        mh = ih - off;
1028329eaa64Smrg        mw = iw - off;
1029329eaa64Smrg        bw = mh / 16;
1030329eaa64Smrg        if (bw == 0 && mw > 2)
1031329eaa64Smrg            bw = 1;
1032329eaa64Smrg        tw = mw - bw * 2;
1033329eaa64Smrg        th = mh - bw * 2;
1034329eaa64Smrg        XFillRectangle(dpy, pix, gc, ix, iy, (unsigned) mw, (unsigned) mh);
1035329eaa64Smrg        XFillRectangle(dpy, pix, gc, ix + iw - mw, iy + ih - mh, (unsigned) mw,
1036329eaa64Smrg                       (unsigned) mh);
1037329eaa64Smrg        XSetForeground(dpy, gc, 0L);
1038329eaa64Smrg        XFillRectangle(dpy, pix, gc, ix + bw, iy + bw, (unsigned) tw,
1039329eaa64Smrg                       (unsigned) th);
1040329eaa64Smrg        XSetForeground(dpy, gc, 1L);
1041329eaa64Smrg        lw = tw / 2;
1042329eaa64Smrg        if ((tw & 1) ^ (lw & 1))
1043329eaa64Smrg            lw++;
1044329eaa64Smrg        lx = ix + bw + (tw - lw) / 2;
1045329eaa64Smrg
1046329eaa64Smrg        lh = th / 2 - bw;
1047329eaa64Smrg        if ((lh & 1) ^ ((th - bw) & 1))
1048329eaa64Smrg            lh++;
1049329eaa64Smrg        ly = iy + bw + (th - bw - lh) / 2;
1050329eaa64Smrg
1051329eaa64Smrg        lines = 3;
1052329eaa64Smrg        if ((lh & 1) && lh < 6) {
1053329eaa64Smrg            lines--;
1054329eaa64Smrg        }
1055329eaa64Smrg        dly = lh / (lines - 1);
1056329eaa64Smrg        while (lines--) {
1057329eaa64Smrg            XFillRectangle(dpy, pix, gc, lx, ly, (unsigned) lw, (unsigned) bw);
1058329eaa64Smrg            ly += dly;
1059329eaa64Smrg        }
1060329eaa64Smrg        XFreeGC(dpy, gc);
10613e747e6dSmrg    }
10623e747e6dSmrg    return Scr->tbpm.menu;
10633e747e6dSmrg}
10643e747e6dSmrg
10653e747e6dSmrgvoid
1066329eaa64SmrgBell(int type _X_UNUSED, int percent, Window win _X_UNUSED)
10673e747e6dSmrg{
10683e747e6dSmrg#ifdef XKB
10693e747e6dSmrg    XkbStdBell(dpy, win, percent, type);
10703e747e6dSmrg#else
10713e747e6dSmrg    XBell(dpy, percent);
10723e747e6dSmrg#endif
10733e747e6dSmrg    return;
10743e747e6dSmrg}
1075