twmruined/src/util.c

1012 lines
26 KiB
C

/*****************************************************************************/
/*
Copyright 1989, 1998 The Open Group
Permission to use, copy, modify, distribute, and sell this software and its
documentation for any purpose is hereby granted without fee, provided that
the above copyright notice appear in all copies and that both that
copyright notice and this permission notice appear in supporting
documentation.
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of The Open Group shall not be
used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from The Open Group.
*/
/** Copyright 1988 by Evans & Sutherland Computer Corporation, **/
/** Salt Lake City, Utah **/
/** Cambridge, Massachusetts **/
/** **/
/** All Rights Reserved **/
/** **/
/** Permission to use, copy, modify, and distribute this software and **/
/** its documentation for any purpose and without fee is hereby **/
/** granted, provided that the above copyright notice appear in all **/
/** copies and that both that copyright notice and this permis- **/
/** sion notice appear in supporting documentation, and that the **/
/** name of Evans & Sutherland not be used in advertising **/
/** in publicity pertaining to distribution of the software without **/
/** specific, written prior permission. **/
/** **/
/** EVANS & SUTHERLAND DISCLAIMs ALL WARRANTIES WITH REGARD **/
/** TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANT- **/
/** ABILITY AND FITNESS, IN NO EVENT SHALL EVANS & SUTHERLAND **/
/** BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAM- **/
/** AGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA **/
/** OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER **/
/** TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE **/
/** OR PERFORMANCE OF THIS SOFTWARE. **/
/*****************************************************************************/
/***********************************************************************
*
* utility routines for twm
*
* 28-Oct-87 Thomas E. LaStrange File created
*
***********************************************************************/
#include "twm.h"
#include "util.h"
#include "gram.h"
#include "screen.h"
#include <X11/Xos.h>
#include <X11/Xatom.h>
#include <stdio.h>
#include <X11/Xmu/Drawing.h>
#include <X11/Xmu/CharSet.h>
static Pixmap CreateXLogoPixmap ( unsigned int *widthp,
unsigned int *heightp );
static Pixmap CreateResizePixmap ( unsigned int *widthp,
unsigned int *heightp );
static Pixmap CreateDotPixmap ( unsigned int *widthp,
unsigned int *heightp );
static Pixmap CreateQuestionPixmap ( unsigned int *widthp,
unsigned int *heightp );
static Pixmap CreateMenuPixmap ( unsigned int *widthp,
unsigned int *heightp );
int HotX, HotY;
/**
* move a window outline
*
* \param root window we are outlining
* \param x,y upper left coordinate
* \param width,height size of the rectangle
* \param bw border width of the frame
* \param th title height
*/
void MoveOutline(Window root, int x, int y, int width, int height, int bw, int th)
{
static int lastx = 0;
static int lasty = 0;
static int lastWidth = 0;
static int lastHeight = 0;
static int lastBW = 0;
static int lastTH = 0;
int xl, xr, yt, yb, xinnerl, xinnerr, yinnert, yinnerb;
int xthird, ythird;
XSegment outline[18];
register XSegment *r;
if (x == lastx && y == lasty && width == lastWidth && height == lastHeight
&& lastBW == bw && th == lastTH)
return;
r = outline;
#define DRAWIT() \
if (lastWidth || lastHeight) \
{ \
xl = lastx; \
xr = lastx + lastWidth - 1; \
yt = lasty; \
yb = lasty + lastHeight - 1; \
xinnerl = xl + lastBW; \
xinnerr = xr - lastBW; \
yinnert = yt + lastTH + lastBW; \
yinnerb = yb - lastBW; \
xthird = (xinnerr - xinnerl) / 3; \
ythird = (yinnerb - yinnert) / 3; \
\
r->x1 = xl; \
r->y1 = yt; \
r->x2 = xr; \
r->y2 = yt; \
r++; \
\
r->x1 = xl; \
r->y1 = yb; \
r->x2 = xr; \
r->y2 = yb; \
r++; \
\
r->x1 = xl; \
r->y1 = yt; \
r->x2 = xl; \
r->y2 = yb; \
r++; \
\
r->x1 = xr; \
r->y1 = yt; \
r->x2 = xr; \
r->y2 = yb; \
r++; \
\
r->x1 = xinnerl + xthird; \
r->y1 = yinnert; \
r->x2 = r->x1; \
r->y2 = yinnerb; \
r++; \
\
r->x1 = xinnerl + (2 * xthird); \
r->y1 = yinnert; \
r->x2 = r->x1; \
r->y2 = yinnerb; \
r++; \
\
r->x1 = xinnerl; \
r->y1 = yinnert + ythird; \
r->x2 = xinnerr; \
r->y2 = r->y1; \
r++; \
\
r->x1 = xinnerl; \
r->y1 = yinnert + (2 * ythird); \
r->x2 = xinnerr; \
r->y2 = r->y1; \
r++; \
\
if (lastTH != 0) { \
r->x1 = xl; \
r->y1 = yt + lastTH; \
r->x2 = xr; \
r->y2 = r->y1; \
r++; \
} \
}
/* undraw the old one, if any */
DRAWIT ();
lastx = x;
lasty = y;
lastWidth = width;
lastHeight = height;
lastBW = bw;
lastTH = th;
/* draw the new one, if any */
DRAWIT ();
#undef DRAWIT
if (r != outline)
{
XDrawSegments(dpy, root, Scr->DrawGC, outline, r - outline);
}
}
/**
* zoom in or out of an icon
*
* \param wf window to zoom from
* \param wt window to zoom to
*/
void
Zoom(Window wf, Window wt)
{
int fx, fy, tx, ty; /* from, to */
unsigned int fw, fh, tw, th; /* from, to */
long dx, dy, dw, dh;
long z;
int j;
if (!Scr->DoZoom || Scr->ZoomCount < 1) return;
if (wf == None || wt == None) return;
XGetGeometry (dpy, wf, &JunkRoot, &fx, &fy, &fw, &fh, &JunkBW, &JunkDepth);
XGetGeometry (dpy, wt, &JunkRoot, &tx, &ty, &tw, &th, &JunkBW, &JunkDepth);
dx = ((long) (tx - fx)); /* going from -> to */
dy = ((long) (ty - fy)); /* going from -> to */
dw = ((long) (tw - fw)); /* going from -> to */
dh = ((long) (th - fh)); /* going from -> to */
z = (long) (Scr->ZoomCount + 1);
for (j = 0; j < 2; j++) {
long i;
XDrawRectangle (dpy, Scr->Root, Scr->DrawGC, fx, fy, fw, fh);
for (i = 1; i < z; i++) {
int x = fx + (int) ((dx * i) / z);
int y = fy + (int) ((dy * i) / z);
unsigned width = (unsigned) (((long) fw) + (dw * i) / z);
unsigned height = (unsigned) (((long) fh) + (dh * i) / z);
XDrawRectangle (dpy, Scr->Root, Scr->DrawGC,
x, y, width, height);
}
XDrawRectangle (dpy, Scr->Root, Scr->DrawGC, tx, ty, tw, th);
}
}
/**
* expand the tilde character to HOME if it is the first
* character of the filename
*
* \return a pointer to the new name
*
* \param name the filename to expand
*/
const char *
ExpandFilename(const char *name)
{
char *newname;
if (name[0] != '~') return name;
newname = malloc(HomeLen + strlen(name) + 2);
if (!newname) {
fprintf(stderr,
"%s: unable to allocate %ld bytes to expand filename %s/%s\n",
ProgramName, HomeLen + (unsigned long)strlen(name) + 2,
Home, &name[1]);
} else {
(void) sprintf(newname, "%s/%s", Home, &name[1]);
}
return newname;
}
/**
* read in the bitmap file for the unknown icon
*
* \param name the filename to read
*/
void
GetUnknownIcon(const char *name)
{
if ((Scr->UnknownPm = GetBitmap(name)) != None)
{
XGetGeometry(dpy, Scr->UnknownPm, &JunkRoot, &JunkX, &JunkY,
(unsigned int *)&Scr->UnknownWidth, (unsigned int *)&Scr->UnknownHeight, &JunkBW, &JunkDepth);
}
}
/**
* FindBitmap - read in a bitmap file and return size
*
* \return pixmap associated with bitmap
*
* \param name filename to read
* \param[out] widthp pointer to width of bitmap
* \param[out] heightp pointer to height of bitmap
*/
Pixmap
FindBitmap (const char *name, unsigned *widthp, unsigned *heightp)
{
char *bigname;
Pixmap pm;
if (!name) return None;
/*
* Names of the form :name refer to hardcoded images that are scaled to
* look nice in title buttons. Eventually, it would be nice to put in a
* menu symbol as well....
*/
if (name[0] == ':') {
int i;
static struct {
const char *name;
Pixmap (*proc)(unsigned int *, unsigned int *);
} pmtab[] = {
{ TBPM_DOT, CreateDotPixmap },
{ TBPM_ICONIFY, CreateDotPixmap },
{ TBPM_RESIZE, CreateResizePixmap },
{ TBPM_XLOGO, CreateXLogoPixmap },
{ TBPM_DELETE, CreateXLogoPixmap },
{ TBPM_MENU, CreateMenuPixmap },
{ TBPM_QUESTION, CreateQuestionPixmap },
};
for (i = 0; i < (sizeof pmtab)/(sizeof pmtab[0]); i++) {
if (XmuCompareISOLatin1 (pmtab[i].name, name) == 0)
return (*pmtab[i].proc) (widthp, heightp);
}
fprintf (stderr, "%s: no such built-in bitmap \"%s\"\n",
ProgramName, name);
return None;
}
/*
* Generate a full pathname if any special prefix characters (such as ~)
* are used. If the bigname is different from name, bigname will need to
* be freed.
*/
bigname = (char*)ExpandFilename(name);
if (!bigname) return None;
/*
* look along bitmapFilePath resource same as toolkit clients
*/
pm = XmuLocateBitmapFile (ScreenOfDisplay(dpy, Scr->screen), bigname, NULL,
0, (int *)widthp, (int *)heightp, &HotX, &HotY);
if (pm == None && Scr->IconDirectory && bigname[0] != '/') {
if (bigname != name) free (bigname);
/*
* Attempt to find icon in old IconDirectory (now obsolete)
*/
bigname = malloc (strlen(name) + strlen(Scr->IconDirectory) + 2);
if (!bigname) {
fprintf (stderr,
"%s: unable to allocate memory for \"%s/%s\"\n",
ProgramName, Scr->IconDirectory, name);
return None;
}
(void) sprintf (bigname, "%s/%s", Scr->IconDirectory, name);
if (XReadBitmapFile (dpy, Scr->Root, bigname, widthp, heightp, &pm,
&HotX, &HotY) != BitmapSuccess) {
pm = None;
}
}
if (bigname != name) free (bigname);
if (pm == None) {
fprintf (stderr, "%s: unable to find bitmap \"%s\"\n",
ProgramName, name);
}
return pm;
}
Pixmap
GetBitmap (const char *name)
{
return FindBitmap (name, &JunkWidth, &JunkHeight);
}
void
InsertRGBColormap (Atom a, XStandardColormap *maps, int nmaps, Bool replace)
{
StdCmap *sc = NULL;
if (replace) { /* locate existing entry */
for (sc = Scr->StdCmapInfo.head; sc; sc = sc->next) {
if (sc->atom == a) break;
}
}
if (!sc) { /* no existing, allocate new */
sc = malloc (sizeof (StdCmap));
if (!sc) {
fprintf (stderr, "%s: unable to allocate %ld bytes for StdCmap\n",
ProgramName, (unsigned long)sizeof (StdCmap));
return;
}
}
if (replace) { /* just update contents */
if (sc->maps) XFree (maps);
if (sc == Scr->StdCmapInfo.mru) Scr->StdCmapInfo.mru = NULL;
} else { /* else appending */
sc->next = NULL;
sc->atom = a;
if (Scr->StdCmapInfo.tail) {
Scr->StdCmapInfo.tail->next = sc;
} else {
Scr->StdCmapInfo.head = sc;
}
Scr->StdCmapInfo.tail = sc;
}
sc->nmaps = nmaps;
sc->maps = maps;
return;
}
void
RemoveRGBColormap (Atom a)
{
StdCmap *sc, *prev;
prev = NULL;
for (sc = Scr->StdCmapInfo.head; sc; sc = sc->next) {
if (sc->atom == a) break;
prev = sc;
}
if (sc) { /* found one */
if (sc->maps) XFree (sc->maps);
if (prev) prev->next = sc->next;
if (Scr->StdCmapInfo.head == sc) Scr->StdCmapInfo.head = sc->next;
if (Scr->StdCmapInfo.tail == sc) Scr->StdCmapInfo.tail = prev;
if (Scr->StdCmapInfo.mru == sc) Scr->StdCmapInfo.mru = NULL;
}
return;
}
void
LocateStandardColormaps(void)
{
Atom *atoms;
int natoms;
int i;
atoms = XListProperties (dpy, Scr->Root, &natoms);
for (i = 0; i < natoms; i++) {
XStandardColormap *maps = NULL;
int nmaps;
if (XGetRGBColormaps (dpy, Scr->Root, &maps, &nmaps, atoms[i])) {
/* if got one, then append to current list */
InsertRGBColormap (atoms[i], maps, nmaps, False);
}
}
if (atoms) XFree (atoms);
return;
}
void
GetColor(int kind, Pixel *what, const char *name)
{
XColor color, junkcolor;
Status stat = 0;
Colormap cmap = Scr->TwmRoot.cmaps.cwins[0]->colormap->c;
#ifndef TOM
if (!Scr->FirstTime)
return;
#endif
if (Scr->Monochrome != kind)
return;
if (!XAllocNamedColor (dpy, cmap, name, &color, &junkcolor))
{
/* if we could not allocate the color, let's see if this is a
* standard colormap
*/
XStandardColormap *stdcmap = NULL;
/* parse the named color */
if (name[0] != '#')
stat = XParseColor (dpy, cmap, name, &color);
if (!stat)
{
fprintf (stderr, "%s: invalid color name \"%s\"\n",
ProgramName, name);
return;
}
/*
* look through the list of standard colormaps (check cache first)
*/
if (Scr->StdCmapInfo.mru && Scr->StdCmapInfo.mru->maps &&
(Scr->StdCmapInfo.mru->maps[Scr->StdCmapInfo.mruindex].colormap ==
cmap)) {
stdcmap = &(Scr->StdCmapInfo.mru->maps[Scr->StdCmapInfo.mruindex]);
} else {
StdCmap *sc;
for (sc = Scr->StdCmapInfo.head; sc; sc = sc->next) {
int i;
for (i = 0; i < sc->nmaps; i++) {
if (sc->maps[i].colormap == cmap) {
Scr->StdCmapInfo.mru = sc;
Scr->StdCmapInfo.mruindex = i;
stdcmap = &(sc->maps[i]);
goto gotit;
}
}
}
}
gotit:
if (stdcmap) {
color.pixel = (stdcmap->base_pixel +
((Pixel)(((float)color.red / 65535.0) *
stdcmap->red_max + 0.5) *
stdcmap->red_mult) +
((Pixel)(((float)color.green /65535.0) *
stdcmap->green_max + 0.5) *
stdcmap->green_mult) +
((Pixel)(((float)color.blue / 65535.0) *
stdcmap->blue_max + 0.5) *
stdcmap->blue_mult));
} else {
fprintf (stderr, "%s: unable to allocate color \"%s\"\n",
ProgramName, name);
return;
}
}
*what = color.pixel;
}
void
GetColorValue(int kind, XColor *what, const char *name)
{
XColor junkcolor;
Colormap cmap = Scr->TwmRoot.cmaps.cwins[0]->colormap->c;
#ifndef TOM
if (!Scr->FirstTime)
return;
#endif
if (Scr->Monochrome != kind)
return;
if (!XLookupColor (dpy, cmap, name, what, &junkcolor))
{
fprintf (stderr, "%s: invalid color name \"%s\"\n",
ProgramName, name);
}
else
{
what->pixel = AllPlanes;
}
}
/*
* The following functions are sensible to 'use_fontset'.
* When 'use_fontset' is True,
* - XFontSet-related internationalized functions are used
* so as multibyte languages can be displayed.
* When 'use_fontset' is False,
* - XFontStruct-related conventional functions are used
* so as 8-bit characters can be displayed even when
* locale is not set properly.
*/
void
GetFont(MyFont *font)
{
const char *deffontname = "fixed";
char **missing_charset_list_return;
int missing_charset_count_return;
char *def_string_return;
XFontSetExtents *font_extents;
XFontStruct **xfonts;
char **font_names;
register int i;
int ascent;
int descent;
int fnum;
char *basename2;
if (use_fontset) {
if (font->fontset != NULL){
XFreeFontSet(dpy, font->fontset);
}
basename2 = malloc(strlen(font->name) + 3);
if (basename2) sprintf(basename2, "%s,*", font->name);
else basename2 = (char*)font->name;
if( (font->fontset = XCreateFontSet(dpy, basename2,
&missing_charset_list_return,
&missing_charset_count_return,
&def_string_return)) == NULL) {
fprintf (stderr, "%s: unable to open fontset \"%s\"\n",
ProgramName, font->name);
exit(1);
}
if (basename2 != font->name) free(basename2);
for(i=0; i<missing_charset_count_return; i++){
printf("%s: warning: font for charset %s is lacking.\n",
ProgramName, missing_charset_list_return[i]);
}
font_extents = XExtentsOfFontSet(font->fontset);
fnum = XFontsOfFontSet(font->fontset, &xfonts, &font_names);
for( i = 0, ascent = 0, descent = 0; i<fnum; i++){
if (ascent < (*xfonts)->ascent) ascent = (*xfonts)->ascent;
if (descent < (*xfonts)->descent) descent = (*xfonts)->descent;
xfonts++;
}
font->height = font_extents->max_logical_extent.height;
font->y = ascent;
font->ascent = ascent;
font->descent = descent;
return;
}
if (font->font != NULL)
XFreeFont(dpy, font->font);
if ((font->font = XLoadQueryFont(dpy, font->name)) == NULL)
{
if (Scr->DefaultFont.name) {
deffontname = Scr->DefaultFont.name;
}
if ((font->font = XLoadQueryFont(dpy, deffontname)) == NULL)
{
fprintf (stderr, "%s: unable to open fonts \"%s\" or \"%s\"\n",
ProgramName, font->name, deffontname);
exit(1);
}
}
font->height = font->font->ascent + font->font->descent;
font->y = font->font->ascent;
font->ascent = font->font->ascent;
font->descent = font->font->descent;
}
int
MyFont_TextWidth(MyFont *font, const char *string, int len)
{
XRectangle ink_rect;
XRectangle logical_rect;
if (use_fontset) {
XmbTextExtents(font->fontset, string, len,
&ink_rect, &logical_rect);
return logical_rect.width;
}
return XTextWidth(font->font, string, len);
}
void
MyFont_DrawImageString(Display *dpy, Drawable d, MyFont *font, GC gc,
int x, int y, const char *string, int len)
{
if (use_fontset) {
XmbDrawImageString(dpy, d, font->fontset, gc, x, y, string, len);
return;
}
XDrawImageString (dpy, d, gc, x, y, string, len);
}
void
MyFont_DrawString(Display *dpy, Drawable d, MyFont *font, GC gc,
int x, int y, const char *string, int len)
{
if (use_fontset) {
XmbDrawString(dpy, d, font->fontset, gc, x, y, string, len);
return;
}
XDrawString (dpy, d, gc, x, y, string, len);
}
void
MyFont_ChangeGC(unsigned long fix_fore, unsigned long fix_back,
MyFont *fix_font)
{
Gcv.foreground = fix_fore;
Gcv.background = fix_back;
if (use_fontset) {
XChangeGC(dpy, Scr->NormalGC, GCForeground|GCBackground, &Gcv);
return;
}
Gcv.font = fix_font->font->fid;
XChangeGC(dpy, Scr->NormalGC, GCFont|GCForeground|GCBackground,&Gcv);
}
/*
* The following functions are internationalized substitutions
* for XFetchName and XGetIconName using XGetWMName and
* XGetWMIconName.
*
* Please note that the third arguments have to be freed using free(),
* not XFree().
*/
Status
I18N_FetchName(Display *dpy, Window w, char **winname)
{
int status;
XTextProperty text_prop;
char **list;
int num;
status = XGetWMName(dpy, w, &text_prop);
if (!status || !text_prop.value || !text_prop.nitems) {
*winname = NULL;
return 0;
}
status = XmbTextPropertyToTextList(dpy, &text_prop, &list, &num);
if (status < Success || !num || !*list) {
*winname = NULL;
return 0;
}
XFree(text_prop.value);
*winname = (char *)strdup(*list);
XFreeStringList(list);
return 1;
}
Status
I18N_GetIconName(Display *dpy, Window w, char **iconname)
{
int status;
XTextProperty text_prop;
char **list;
int num;
status = XGetWMIconName(dpy, w, &text_prop);
if (!status || !text_prop.value || !text_prop.nitems) return 0;
status = XmbTextPropertyToTextList(dpy, &text_prop, &list, &num);
if (status < Success || !num || !*list) return 0;
XFree(text_prop.value);
*iconname = (char *)strdup(*list);
XFreeStringList(list);
return 1;
}
/**
* separate routine to set focus to make things more understandable
* and easier to debug
*/
void
SetFocus (TwmWindow *tmp_win, Time time)
{
Window w = (tmp_win ? tmp_win->w : PointerRoot);
#ifdef TRACE
if (tmp_win) {
printf ("Focusing on window \"%s\"\n", tmp_win->full_name);
} else {
printf ("Unfocusing; Scr->Focus was \"%s\"\n",
Scr->Focus ? Scr->Focus->full_name : "(nil)");
}
#endif
XSetInputFocus (dpy, w, RevertToPointerRoot, time);
}
static Pixmap
CreateXLogoPixmap (unsigned *widthp, unsigned *heightp)
{
int h = Scr->TBInfo.width - Scr->TBInfo.border * 2;
if (h < 0) h = 0;
*widthp = *heightp = (unsigned int) h;
if (Scr->tbpm.xlogo == None) {
GC gc, gcBack;
Scr->tbpm.xlogo = XCreatePixmap (dpy, Scr->Root, h, h, 1);
gc = XCreateGC (dpy, Scr->tbpm.xlogo, 0L, NULL);
XSetForeground (dpy, gc, 0);
XFillRectangle (dpy, Scr->tbpm.xlogo, gc, 0, 0, h, h);
XSetForeground (dpy, gc, 1);
gcBack = XCreateGC (dpy, Scr->tbpm.xlogo, 0L, NULL);
XSetForeground (dpy, gcBack, 0);
/*
* draw the logo large so that it gets as dense as possible; then white
* out the edges so that they look crisp
*/
XmuDrawLogo (dpy, Scr->tbpm.xlogo, gc, gcBack, -1, -1, h + 2, h + 2);
XDrawRectangle (dpy, Scr->tbpm.xlogo, gcBack, 0, 0, h - 1, h - 1);
/*
* done drawing
*/
XFreeGC (dpy, gc);
XFreeGC (dpy, gcBack);
}
return Scr->tbpm.xlogo;
}
static Pixmap
CreateResizePixmap (unsigned *widthp, unsigned *heightp)
{
int h = Scr->TBInfo.width - Scr->TBInfo.border * 2;
if (h < 1) h = 1;
*widthp = *heightp = (unsigned int) h;
if (Scr->tbpm.resize == None) {
XPoint points[3];
GC gc;
int w;
int lw;
/*
* create the pixmap
*/
Scr->tbpm.resize = XCreatePixmap (dpy, Scr->Root, h, h, 1);
gc = XCreateGC (dpy, Scr->tbpm.resize, 0L, NULL);
XSetForeground (dpy, gc, 0);
XFillRectangle (dpy, Scr->tbpm.resize, gc, 0, 0, h, h);
XSetForeground (dpy, gc, 1);
lw = h / 16;
if (lw == 1)
lw = 0;
XSetLineAttributes (dpy, gc, lw, LineSolid, CapButt, JoinMiter);
/*
* draw the resize button,
*/
w = (h * 2) / 3;
points[0].x = w;
points[0].y = 0;
points[1].x = w;
points[1].y = w;
points[2].x = 0;
points[2].y = w;
XDrawLines(dpy, Scr->tbpm.resize, gc, points, 3, CoordModeOrigin);
w = w / 2;
points[0].x = w;
points[0].y = 0;
points[1].x = w;
points[1].y = w;
points[2].x = 0;
points[2].y = w;
XDrawLines(dpy, Scr->tbpm.resize, gc, points, 3, CoordModeOrigin);
w = h - 1;
points[0].x = w;
points[0].y = 0;
points[1].x = w;
points[1].y = w;
points[2].x = 0;
points[2].y = w;
XDrawLines(dpy, Scr->tbpm.resize, gc, points, 3, CoordModeOrigin);
/*
* done drawing
*/
XFreeGC(dpy, gc);
}
return Scr->tbpm.resize;
}
static Pixmap
CreateDotPixmap (unsigned *widthp, unsigned *heightp)
{
int h = Scr->TBInfo.width - Scr->TBInfo.border * 2;
h = h * 3 / 4;
if (h < 1) h = 1;
if (!(h & 1))
h--;
*widthp = *heightp = (unsigned int) h;
if (Scr->tbpm.del == None) {
GC gc;
Pixmap pix;
pix = Scr->tbpm.del = XCreatePixmap (dpy, Scr->Root, h, h, 1);
gc = XCreateGC (dpy, pix, 0L, NULL);
XSetLineAttributes (dpy, gc, h, LineSolid, CapRound, JoinRound);
XSetForeground (dpy, gc, 0L);
XFillRectangle (dpy, pix, gc, 0, 0, h, h);
XSetForeground (dpy, gc, 1L);
XDrawLine (dpy, pix, gc, h/2, h/2, h/2, h/2);
XFreeGC (dpy, gc);
}
return Scr->tbpm.del;
}
#define questionmark_width 8
#define questionmark_height 8
static char questionmark_bits[] = {
0x38, 0x7c, 0x64, 0x30, 0x18, 0x00, 0x18, 0x18};
static Pixmap
CreateQuestionPixmap (unsigned *widthp, unsigned *heightp)
{
*widthp = questionmark_width;
*heightp = questionmark_height;
if (Scr->tbpm.question == None) {
Scr->tbpm.question = XCreateBitmapFromData (dpy, Scr->Root,
questionmark_bits,
questionmark_width,
questionmark_height);
}
/*
* this must succeed or else we are in deep trouble elsewhere
*/
return Scr->tbpm.question;
}
static Pixmap
CreateMenuPixmap(unsigned *widthp, unsigned *heightp)
{
return CreateMenuIcon(Scr->TBInfo.width - Scr->TBInfo.border * 2,
widthp, heightp);
}
Pixmap
CreateMenuIcon(int height, unsigned *widthp, unsigned *heightp)
{
int h, w;
int ih, iw;
int ix, iy;
int mh, mw;
int tw, th;
int lw, lh;
int lx, ly;
int lines, dly;
int off;
int bw;
h = height;
w = h * 7 / 8;
if (h < 1)
h = 1;
if (w < 1)
w = 1;
*widthp = w;
*heightp = h;
if (Scr->tbpm.menu == None) {
Pixmap pix;
GC gc;
pix = Scr->tbpm.menu = XCreatePixmap (dpy, Scr->Root, w, h, 1);
gc = XCreateGC (dpy, pix, 0L, NULL);
XSetForeground (dpy, gc, 0L);
XFillRectangle (dpy, pix, gc, 0, 0, w, h);
XSetForeground (dpy, gc, 1L);
ix = 1;
iy = 1;
ih = h - iy * 2;
iw = w - ix * 2;
off = ih / 8;
mh = ih - off;
mw = iw - off;
bw = mh / 16;
if (bw == 0 && mw > 2)
bw = 1;
tw = mw - bw * 2;
th = mh - bw * 2;
XFillRectangle (dpy, pix, gc, ix, iy, mw, mh);
XFillRectangle (dpy, pix, gc, ix + iw - mw, iy + ih - mh, mw, mh);
XSetForeground (dpy, gc, 0L);
XFillRectangle (dpy, pix, gc, ix+bw, iy+bw, tw, th);
XSetForeground (dpy, gc, 1L);
lw = tw / 2;
if ((tw & 1) ^ (lw & 1))
lw++;
lx = ix + bw + (tw - lw) / 2;
lh = th / 2 - bw;
if ((lh & 1) ^ ((th - bw) & 1))
lh++;
ly = iy + bw + (th - bw - lh) / 2;
lines = 3;
if ((lh & 1) && lh < 6)
{
lines--;
}
dly = lh / (lines - 1);
while (lines--)
{
XFillRectangle (dpy, pix, gc, lx, ly, lw, bw);
ly += dly;
}
XFreeGC (dpy, gc);
}
return Scr->tbpm.menu;
}
void
Bell(int type, int percent, Window win)
{
#ifdef XKB
XkbStdBell(dpy, win, percent, type);
#else
XBell(dpy, percent);
#endif
return;
}