/*****************************************************************************/ /* 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 #include #include #include #include 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 = (short)(xl); \ r->y1 = (short)(yt); \ r->x2 = (short)(xr); \ r->y2 = (short)(yt); \ r++; \ \ r->x1 = (short)(xl); \ r->y1 = (short)(yb); \ r->x2 = (short)(xr); \ r->y2 = (short)(yb); \ r++; \ \ r->x1 = (short)(xl); \ r->y1 = (short)(yt); \ r->x2 = (short)(xl); \ r->y2 = (short)(yb); \ r++; \ \ r->x1 = (short)(xr); \ r->y1 = (short)(yt); \ r->x2 = (short)(xr); \ r->y2 = (short)(yb); \ r++; \ \ r->x1 = (short)(xinnerl + xthird); \ r->y1 = (short)(yinnert); \ r->x2 = (short)(r->x1); \ r->y2 = (short)(yinnerb); \ r++; \ \ r->x1 = (short)(xinnerl + (2 * xthird)); \ r->y1 = (short)(yinnert); \ r->x2 = (short)(r->x1); \ r->y2 = (short)(yinnerb); \ r++; \ \ r->x1 = (short)(xinnerl); \ r->y1 = (short)(yinnert + ythird); \ r->x2 = (short)(xinnerr); \ r->y2 = (short)(r->y1); \ r++; \ \ r->x1 = (short)(xinnerl); \ r->y1 = (short)(yinnert + (2 * ythird)); \ r->x2 = (short)(xinnerr); \ r->y2 = (short)(r->y1); \ r++; \ \ if (lastTH != 0) { \ r->x1 = (short)(xl); \ r->y1 = (short)(yt + lastTH); \ r->x2 = (short)(xr); \ r->y2 = (short)(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, (int) (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 */ char * ExpandFilename(const char *name) { char *newname; if (name[0] != '~') return strdup(name); newname = malloc((size_t) HomeLen + strlen(name) + 2); if (!newname) { twmWarning("unable to allocate %lu bytes to expand filename %s/%s", (unsigned long) 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; /* *INDENT-OFF* */ 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 }, }; /* *INDENT-ON* */ for (i = 0; (size_t) i < (sizeof pmtab) / (sizeof pmtab[0]); i++) { if (XmuCompareISOLatin1(pmtab[i].name, name) == 0) return (*pmtab[i].proc) (widthp, heightp); } twmWarning("no such built-in bitmap \"%s\"", 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 = 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] != '/') { free(bigname); /* * Attempt to find icon in old IconDirectory (now obsolete) */ bigname = malloc(strlen(name) + strlen(Scr->IconDirectory) + 2); if (!bigname) { twmWarning("unable to allocate memory for \"%s/%s\"", 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; } } free(bigname); if (pm == None) { twmWarning("unable to find bitmap \"%s\"", 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) { twmWarning("unable to allocate %lu bytes for StdCmap", (unsigned long) sizeof(StdCmap)); return; } replace = False; } if (replace) { /* just update contents */ if (sc->maps) XFree(sc->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; if (!Scr->FirstTime) return; 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) { twmWarning("invalid color name \"%s\"", 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) * (double) stdcmap->red_max + 0.5) * stdcmap->red_mult) + ((Pixel) (((float) color.green / 65535.0) * (double) stdcmap->green_max + 0.5) * stdcmap->green_mult) + ((Pixel) (((float) color.blue / 65535.0) * (double) stdcmap->blue_max + 0.5) * stdcmap->blue_mult)); } else { twmWarning("unable to allocate color \"%s\"", 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; if (!Scr->FirstTime) return; if (Scr->Monochrome != kind) return; if (!XLookupColor(dpy, cmap, name, what, &junkcolor)) { twmWarning("invalid color name \"%s\"", name); } else { what->pixel = AllPlanes; } } static Boolean FindFontSet(MyFont *font, const char *fontname) { char **missing_charset_list_return; int missing_charset_count_return; char *def_string_return; XFontSetExtents *font_extents; XFontStruct **xfonts; char **font_names; if (use_fontset) { int ascent; int descent; int fnum; register int i; if (font->fontset != NULL) { XFreeFontSet(dpy, font->fontset); } if ((font->fontset = XCreateFontSet(dpy, fontname, &missing_charset_list_return, &missing_charset_count_return, &def_string_return)) == NULL) { return False; } if (missing_charset_count_return) { twmVerbose("%d fonts are missing from fontset", missing_charset_count_return); for (i = 0; i < missing_charset_count_return; i++) { twmVerbose("font for charset %s is lacking.", 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; twmMessage("created fontset with %d fonts (%d missing) for \"%s\"", fnum, missing_charset_count_return, fontname ? fontname : "NULL"); return True; } if (font->font != NULL) XFreeFont(dpy, font->font); if ((font->font = XLoadQueryFont(dpy, fontname)) == NULL) { return False; } font->height = font->font->ascent + font->font->descent; font->y = font->font->ascent; font->ascent = font->font->ascent; font->descent = font->font->descent; return True; } /* * 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) { if (!FindFontSet(font, font->name)) { const char *what = "fonts"; const char *deffontname = "fixed"; if (use_fontset) { what = "fontsets"; } else if (Scr->DefaultFont.name) { deffontname = Scr->DefaultFont.name; } if (!FindFontSet(font, deffontname)) { twmError("unable to open %s \"%s\" or \"%s\"", what, font->name, deffontname); } } } 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 *dpy2, Drawable d, MyFont *font, GC gc, int x, int y, const char *string, int len) { if (use_fontset) { XmbDrawImageString(dpy2, d, font->fontset, gc, x, y, string, len); return; } XDrawImageString(dpy2, d, gc, x, y, string, len); } void MyFont_DrawString(Display *dpy2, Drawable d, MyFont *font, GC gc, int x, int y, const char *string, int len) { if (use_fontset) { XmbDrawString(dpy2, d, font->fontset, gc, x, y, string, len); return; } XDrawString(dpy2, 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 *dpy2, Window w, char **winname) { int status; XTextProperty text_prop; int rc = 0; *winname = NULL; status = XGetWMName(dpy2, w, &text_prop); if (status && text_prop.value && text_prop.nitems) { char **list = NULL; int num; status = XmbTextPropertyToTextList(dpy2, &text_prop, &list, &num); if (status >= Success && num && list && *list) { XFree(text_prop.value); *winname = strdup(*list); XFreeStringList(list); rc = 1; } else { char *value = NULL; /* * If the system's locale support is broken (e.g., missing useful * parts), the preceding Xmb call may fail. */ if (XFetchName(dpy2, w, &value) && value != NULL) { *winname = strdup(value); XFree(value); rc = 1; } } } return rc; } Status I18N_GetIconName(Display *dpy2, Window w, char **iconname) { int status; XTextProperty text_prop; char **list; int num; status = XGetWMIconName(dpy2, w, &text_prop); if (!status || !text_prop.value || !text_prop.nitems) return 0; status = XmbTextPropertyToTextList(dpy2, &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) { twmMessage("Focusing on window \"%s\"", tmp_win->full_name); } else { twmMessage("Unfocusing; Scr->Focus was \"%s\"", 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, (unsigned) h, (unsigned) h, 1); gc = XCreateGC(dpy, Scr->tbpm.xlogo, 0L, NULL); XSetForeground(dpy, gc, 0); XFillRectangle(dpy, Scr->tbpm.xlogo, gc, 0, 0, (unsigned) h, (unsigned) 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, (unsigned) (h + 2), (unsigned) (h + 2)); XDrawRectangle(dpy, Scr->tbpm.xlogo, gcBack, 0, 0, (unsigned) (h - 1), (unsigned) (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, (unsigned) h, (unsigned) h, 1); gc = XCreateGC(dpy, Scr->tbpm.resize, 0L, NULL); XSetForeground(dpy, gc, 0); XFillRectangle(dpy, Scr->tbpm.resize, gc, 0, 0, (unsigned) h, (unsigned) h); XSetForeground(dpy, gc, 1); lw = h / 16; if (lw == 1) lw = 0; XSetLineAttributes(dpy, gc, (unsigned) lw, LineSolid, CapButt, JoinMiter); /* * draw the resize button, */ w = (h * 2) / 3; points[0].x = (short) w; points[0].y = 0; points[1].x = (short) w; points[1].y = (short) w; points[2].x = 0; points[2].y = (short) w; XDrawLines(dpy, Scr->tbpm.resize, gc, points, 3, CoordModeOrigin); w = w / 2; points[0].x = (short) w; points[0].y = 0; points[1].x = (short) w; points[1].y = (short) w; points[2].x = 0; points[2].y = (short) 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.delete == None) { GC gc; Pixmap pix; pix = Scr->tbpm.delete = XCreatePixmap(dpy, Scr->Root, (unsigned) h, (unsigned) h, 1); gc = XCreateGC(dpy, pix, 0L, NULL); XSetLineAttributes(dpy, gc, (unsigned) h, LineSolid, CapRound, JoinRound); XSetForeground(dpy, gc, 0L); XFillRectangle(dpy, pix, gc, 0, 0, (unsigned) h, (unsigned) h); XSetForeground(dpy, gc, 1L); XDrawLine(dpy, pix, gc, h / 2, h / 2, h / 2, h / 2); XFreeGC(dpy, gc); } return Scr->tbpm.delete; } #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; h = height; w = h * 7 / 8; if (h < 1) h = 1; if (w < 1) w = 1; *widthp = (unsigned) w; *heightp = (unsigned) h; if (Scr->tbpm.menu == None) { Pixmap pix; GC gc; 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; pix = Scr->tbpm.menu = XCreatePixmap(dpy, Scr->Root, (unsigned) w, (unsigned) h, 1); gc = XCreateGC(dpy, pix, 0L, NULL); XSetForeground(dpy, gc, 0L); XFillRectangle(dpy, pix, gc, 0, 0, (unsigned) w, (unsigned) 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, (unsigned) mw, (unsigned) mh); XFillRectangle(dpy, pix, gc, ix + iw - mw, iy + ih - mh, (unsigned) mw, (unsigned) mh); XSetForeground(dpy, gc, 0L); XFillRectangle(dpy, pix, gc, ix + bw, iy + bw, (unsigned) tw, (unsigned) 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, (unsigned) lw, (unsigned) bw); ly += dly; } XFreeGC(dpy, gc); } return Scr->tbpm.menu; } void Bell(int type _X_UNUSED, int percent, Window win _X_UNUSED) { #ifdef XKB XkbStdBell(dpy, win, percent, type); #else XBell(dpy, percent); #endif return; }