util.c revision 329eaa64
1/*****************************************************************************/ 2/* 3 4Copyright 1989, 1998 The Open Group 5 6Permission to use, copy, modify, distribute, and sell this software and its 7documentation for any purpose is hereby granted without fee, provided that 8the above copyright notice appear in all copies and that both that 9copyright notice and this permission notice appear in supporting 10documentation. 11 12The above copyright notice and this permission notice shall be included in 13all copies or substantial portions of the Software. 14 15THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 19AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 22Except as contained in this notice, the name of The Open Group shall not be 23used in advertising or otherwise to promote the sale, use or other dealings 24in this Software without prior written authorization from The Open Group. 25 26*/ 27/** Copyright 1988 by Evans & Sutherland Computer Corporation, **/ 28/** Salt Lake City, Utah **/ 29/** Cambridge, Massachusetts **/ 30/** **/ 31/** All Rights Reserved **/ 32/** **/ 33/** Permission to use, copy, modify, and distribute this software and **/ 34/** its documentation for any purpose and without fee is hereby **/ 35/** granted, provided that the above copyright notice appear in all **/ 36/** copies and that both that copyright notice and this permis- **/ 37/** sion notice appear in supporting documentation, and that the **/ 38/** name of Evans & Sutherland not be used in advertising **/ 39/** in publicity pertaining to distribution of the software without **/ 40/** specific, written prior permission. **/ 41/** **/ 42/** EVANS & SUTHERLAND DISCLAIMs ALL WARRANTIES WITH REGARD **/ 43/** TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANT- **/ 44/** ABILITY AND FITNESS, IN NO EVENT SHALL EVANS & SUTHERLAND **/ 45/** BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAM- **/ 46/** AGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA **/ 47/** OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER **/ 48/** TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE **/ 49/** OR PERFORMANCE OF THIS SOFTWARE. **/ 50/*****************************************************************************/ 51 52/*********************************************************************** 53 * 54 * utility routines for twm 55 * 56 * 28-Oct-87 Thomas E. LaStrange File created 57 * 58 ***********************************************************************/ 59 60#include "twm.h" 61#include "util.h" 62#include "gram.h" 63#include "screen.h" 64#include <X11/Xos.h> 65#include <X11/Xatom.h> 66#include <stdio.h> 67#include <X11/Xmu/Drawing.h> 68#include <X11/Xmu/CharSet.h> 69 70static Pixmap CreateXLogoPixmap(unsigned int *widthp, unsigned int *heightp); 71static Pixmap CreateResizePixmap(unsigned int *widthp, unsigned int *heightp); 72static Pixmap CreateDotPixmap(unsigned int *widthp, unsigned int *heightp); 73static Pixmap CreateQuestionPixmap(unsigned int *widthp, unsigned int *heightp); 74static Pixmap CreateMenuPixmap(unsigned int *widthp, unsigned int *heightp); 75 76int HotX, HotY; 77 78/** 79 * move a window outline 80 * 81 * \param root window we are outlining 82 * \param x,y upper left coordinate 83 * \param width,height size of the rectangle 84 * \param bw border width of the frame 85 * \param th title height 86 */ 87void 88MoveOutline(Window root, int x, int y, int width, int height, int bw, int th) 89{ 90 static int lastx = 0; 91 static int lasty = 0; 92 static int lastWidth = 0; 93 static int lastHeight = 0; 94 static int lastBW = 0; 95 static int lastTH = 0; 96 int xl, xr, yt, yb, xinnerl, xinnerr, yinnert, yinnerb; 97 int xthird, ythird; 98 XSegment outline[18]; 99 register XSegment *r; 100 101 if (x == lastx && y == lasty && width == lastWidth && height == lastHeight 102 && lastBW == bw && th == lastTH) 103 return; 104 105 r = outline; 106 107#define DRAWIT() \ 108 if (lastWidth || lastHeight) \ 109 { \ 110 xl = lastx; \ 111 xr = lastx + lastWidth - 1; \ 112 yt = lasty; \ 113 yb = lasty + lastHeight - 1; \ 114 xinnerl = xl + lastBW; \ 115 xinnerr = xr - lastBW; \ 116 yinnert = yt + lastTH + lastBW; \ 117 yinnerb = yb - lastBW; \ 118 xthird = (xinnerr - xinnerl) / 3; \ 119 ythird = (yinnerb - yinnert) / 3; \ 120 \ 121 r->x1 = (short)(xl); \ 122 r->y1 = (short)(yt); \ 123 r->x2 = (short)(xr); \ 124 r->y2 = (short)(yt); \ 125 r++; \ 126 \ 127 r->x1 = (short)(xl); \ 128 r->y1 = (short)(yb); \ 129 r->x2 = (short)(xr); \ 130 r->y2 = (short)(yb); \ 131 r++; \ 132 \ 133 r->x1 = (short)(xl); \ 134 r->y1 = (short)(yt); \ 135 r->x2 = (short)(xl); \ 136 r->y2 = (short)(yb); \ 137 r++; \ 138 \ 139 r->x1 = (short)(xr); \ 140 r->y1 = (short)(yt); \ 141 r->x2 = (short)(xr); \ 142 r->y2 = (short)(yb); \ 143 r++; \ 144 \ 145 r->x1 = (short)(xinnerl + xthird); \ 146 r->y1 = (short)(yinnert); \ 147 r->x2 = (short)(r->x1); \ 148 r->y2 = (short)(yinnerb); \ 149 r++; \ 150 \ 151 r->x1 = (short)(xinnerl + (2 * xthird)); \ 152 r->y1 = (short)(yinnert); \ 153 r->x2 = (short)(r->x1); \ 154 r->y2 = (short)(yinnerb); \ 155 r++; \ 156 \ 157 r->x1 = (short)(xinnerl); \ 158 r->y1 = (short)(yinnert + ythird); \ 159 r->x2 = (short)(xinnerr); \ 160 r->y2 = (short)(r->y1); \ 161 r++; \ 162 \ 163 r->x1 = (short)(xinnerl); \ 164 r->y1 = (short)(yinnert + (2 * ythird)); \ 165 r->x2 = (short)(xinnerr); \ 166 r->y2 = (short)(r->y1); \ 167 r++; \ 168 \ 169 if (lastTH != 0) { \ 170 r->x1 = (short)(xl); \ 171 r->y1 = (short)(yt + lastTH); \ 172 r->x2 = (short)(xr); \ 173 r->y2 = (short)(r->y1); \ 174 r++; \ 175 } \ 176 } 177 178 /* undraw the old one, if any */ 179 DRAWIT(); 180 181 lastx = x; 182 lasty = y; 183 lastWidth = width; 184 lastHeight = height; 185 lastBW = bw; 186 lastTH = th; 187 188 /* draw the new one, if any */ 189 DRAWIT(); 190 191#undef DRAWIT 192 193 if (r != outline) { 194 XDrawSegments(dpy, root, Scr->DrawGC, outline, (int) (r - outline)); 195 } 196} 197 198/** 199 * zoom in or out of an icon 200 * 201 * \param wf window to zoom from 202 * \param wt window to zoom to 203 */ 204void 205Zoom(Window wf, Window wt) 206{ 207 int fx, fy, tx, ty; /* from, to */ 208 unsigned int fw, fh, tw, th; /* from, to */ 209 long dx, dy, dw, dh; 210 long z; 211 int j; 212 213 if (!Scr->DoZoom || Scr->ZoomCount < 1) 214 return; 215 216 if (wf == None || wt == None) 217 return; 218 219 XGetGeometry(dpy, wf, &JunkRoot, &fx, &fy, &fw, &fh, &JunkBW, &JunkDepth); 220 XGetGeometry(dpy, wt, &JunkRoot, &tx, &ty, &tw, &th, &JunkBW, &JunkDepth); 221 222 dx = ((long) (tx - fx)); /* going from -> to */ 223 dy = ((long) (ty - fy)); /* going from -> to */ 224 dw = ((long) (tw - fw)); /* going from -> to */ 225 dh = ((long) (th - fh)); /* going from -> to */ 226 z = (long) (Scr->ZoomCount + 1); 227 228 for (j = 0; j < 2; j++) { 229 long i; 230 231 XDrawRectangle(dpy, Scr->Root, Scr->DrawGC, fx, fy, fw, fh); 232 for (i = 1; i < z; i++) { 233 int x = fx + (int) ((dx * i) / z); 234 int y = fy + (int) ((dy * i) / z); 235 unsigned width = (unsigned) (((long) fw) + (dw * i) / z); 236 unsigned height = (unsigned) (((long) fh) + (dh * i) / z); 237 238 XDrawRectangle(dpy, Scr->Root, Scr->DrawGC, x, y, width, height); 239 } 240 XDrawRectangle(dpy, Scr->Root, Scr->DrawGC, tx, ty, tw, th); 241 } 242} 243 244/** 245 * expand the tilde character to HOME if it is the first 246 * character of the filename 247 * 248 * \return a pointer to the new name 249 * 250 * \param name the filename to expand 251 */ 252char * 253ExpandFilename(const char *name) 254{ 255 char *newname; 256 257 if (name[0] != '~') 258 return strdup(name); 259 260 newname = malloc((size_t) HomeLen + strlen(name) + 2); 261 if (!newname) { 262 twmWarning("unable to allocate %lu bytes to expand filename %s/%s", 263 (unsigned long) HomeLen + (unsigned long) strlen(name) + 2, 264 Home, &name[1]); 265 } 266 else { 267 (void) sprintf(newname, "%s/%s", Home, &name[1]); 268 } 269 270 return newname; 271} 272 273/** 274 * read in the bitmap file for the unknown icon 275 * 276 * \param name the filename to read 277 */ 278void 279GetUnknownIcon(const char *name) 280{ 281 if ((Scr->UnknownPm = GetBitmap(name)) != None) { 282 XGetGeometry(dpy, Scr->UnknownPm, &JunkRoot, &JunkX, &JunkY, 283 (unsigned int *) &Scr->UnknownWidth, 284 (unsigned int *) &Scr->UnknownHeight, &JunkBW, &JunkDepth); 285 } 286} 287 288/** 289 * FindBitmap - read in a bitmap file and return size 290 * 291 * \return pixmap associated with bitmap 292 * 293 * \param name filename to read 294 * \param[out] widthp pointer to width of bitmap 295 * \param[out] heightp pointer to height of bitmap 296 */ 297Pixmap 298FindBitmap(const char *name, unsigned *widthp, unsigned *heightp) 299{ 300 char *bigname; 301 Pixmap pm; 302 303 if (!name) 304 return None; 305 306 /* 307 * Names of the form :name refer to hardcoded images that are scaled to 308 * look nice in title buttons. Eventually, it would be nice to put in a 309 * menu symbol as well.... 310 */ 311 if (name[0] == ':') { 312 int i; 313 /* *INDENT-OFF* */ 314 static struct { 315 const char *name; 316 Pixmap (*proc)(unsigned int *, unsigned int *); 317 } pmtab[] = { 318 { TBPM_DOT, CreateDotPixmap }, 319 { TBPM_ICONIFY, CreateDotPixmap }, 320 { TBPM_RESIZE, CreateResizePixmap }, 321 { TBPM_XLOGO, CreateXLogoPixmap }, 322 { TBPM_DELETE, CreateXLogoPixmap }, 323 { TBPM_MENU, CreateMenuPixmap }, 324 { TBPM_QUESTION, CreateQuestionPixmap }, 325 }; 326 /* *INDENT-ON* */ 327 328 for (i = 0; (size_t) i < (sizeof pmtab) / (sizeof pmtab[0]); i++) { 329 if (XmuCompareISOLatin1(pmtab[i].name, name) == 0) 330 return (*pmtab[i].proc) (widthp, heightp); 331 } 332 twmWarning("no such built-in bitmap \"%s\"", name); 333 return None; 334 } 335 336 /* 337 * Generate a full pathname if any special prefix characters (such as ~) 338 * are used. If the bigname is different from name, bigname will need to 339 * be freed. 340 */ 341 bigname = ExpandFilename(name); 342 if (!bigname) 343 return None; 344 345 /* 346 * look along bitmapFilePath resource same as toolkit clients 347 */ 348 pm = XmuLocateBitmapFile(ScreenOfDisplay(dpy, Scr->screen), bigname, NULL, 349 0, (int *) widthp, (int *) heightp, &HotX, &HotY); 350 if (pm == None && Scr->IconDirectory && bigname[0] != '/') { 351 free(bigname); 352 /* 353 * Attempt to find icon in old IconDirectory (now obsolete) 354 */ 355 bigname = malloc(strlen(name) + strlen(Scr->IconDirectory) + 2); 356 if (!bigname) { 357 twmWarning("unable to allocate memory for \"%s/%s\"", 358 Scr->IconDirectory, name); 359 return None; 360 } 361 (void) sprintf(bigname, "%s/%s", Scr->IconDirectory, name); 362 if (XReadBitmapFile(dpy, Scr->Root, bigname, widthp, heightp, &pm, 363 &HotX, &HotY) != BitmapSuccess) { 364 pm = None; 365 } 366 } 367 free(bigname); 368 if (pm == None) { 369 twmWarning("unable to find bitmap \"%s\"", name); 370 } 371 372 return pm; 373} 374 375Pixmap 376GetBitmap(const char *name) 377{ 378 return FindBitmap(name, &JunkWidth, &JunkHeight); 379} 380 381void 382InsertRGBColormap(Atom a, XStandardColormap *maps, int nmaps, Bool replace) 383{ 384 StdCmap *sc = NULL; 385 386 if (replace) { /* locate existing entry */ 387 for (sc = Scr->StdCmapInfo.head; sc; sc = sc->next) { 388 if (sc->atom == a) 389 break; 390 } 391 } 392 393 if (!sc) { /* no existing, allocate new */ 394 sc = malloc(sizeof(StdCmap)); 395 if (!sc) { 396 twmWarning("unable to allocate %lu bytes for StdCmap", 397 (unsigned long) sizeof(StdCmap)); 398 return; 399 } 400 replace = False; 401 } 402 403 if (replace) { /* just update contents */ 404 if (sc->maps) 405 XFree(sc->maps); 406 if (sc == Scr->StdCmapInfo.mru) 407 Scr->StdCmapInfo.mru = NULL; 408 } 409 else { /* else appending */ 410 sc->next = NULL; 411 sc->atom = a; 412 if (Scr->StdCmapInfo.tail) { 413 Scr->StdCmapInfo.tail->next = sc; 414 } 415 else { 416 Scr->StdCmapInfo.head = sc; 417 } 418 Scr->StdCmapInfo.tail = sc; 419 } 420 sc->nmaps = nmaps; 421 sc->maps = maps; 422 423 return; 424} 425 426void 427RemoveRGBColormap(Atom a) 428{ 429 StdCmap *sc, *prev; 430 431 prev = NULL; 432 for (sc = Scr->StdCmapInfo.head; sc; sc = sc->next) { 433 if (sc->atom == a) 434 break; 435 prev = sc; 436 } 437 if (sc) { /* found one */ 438 if (sc->maps) 439 XFree(sc->maps); 440 if (prev) 441 prev->next = sc->next; 442 if (Scr->StdCmapInfo.head == sc) 443 Scr->StdCmapInfo.head = sc->next; 444 if (Scr->StdCmapInfo.tail == sc) 445 Scr->StdCmapInfo.tail = prev; 446 if (Scr->StdCmapInfo.mru == sc) 447 Scr->StdCmapInfo.mru = NULL; 448 } 449 return; 450} 451 452void 453LocateStandardColormaps(void) 454{ 455 Atom *atoms; 456 int natoms; 457 int i; 458 459 atoms = XListProperties(dpy, Scr->Root, &natoms); 460 for (i = 0; i < natoms; i++) { 461 XStandardColormap *maps = NULL; 462 int nmaps; 463 464 if (XGetRGBColormaps(dpy, Scr->Root, &maps, &nmaps, atoms[i])) { 465 /* if got one, then append to current list */ 466 InsertRGBColormap(atoms[i], maps, nmaps, False); 467 } 468 } 469 if (atoms) 470 XFree(atoms); 471 return; 472} 473 474void 475GetColor(int kind, Pixel *what, const char *name) 476{ 477 XColor color, junkcolor; 478 Status stat = 0; 479 Colormap cmap = Scr->TwmRoot.cmaps.cwins[0]->colormap->c; 480 481#ifndef TOM 482 if (!Scr->FirstTime) 483 return; 484#endif 485 486 if (Scr->Monochrome != kind) 487 return; 488 489 if (!XAllocNamedColor(dpy, cmap, name, &color, &junkcolor)) { 490 /* if we could not allocate the color, let's see if this is a 491 * standard colormap 492 */ 493 XStandardColormap *stdcmap = NULL; 494 495 /* parse the named color */ 496 if (name[0] != '#') 497 stat = XParseColor(dpy, cmap, name, &color); 498 if (!stat) { 499 twmWarning("invalid color name \"%s\"", name); 500 return; 501 } 502 503 /* 504 * look through the list of standard colormaps (check cache first) 505 */ 506 if (Scr->StdCmapInfo.mru && Scr->StdCmapInfo.mru->maps && 507 (Scr->StdCmapInfo.mru->maps[Scr->StdCmapInfo.mruindex].colormap == 508 cmap)) { 509 stdcmap = &(Scr->StdCmapInfo.mru->maps[Scr->StdCmapInfo.mruindex]); 510 } 511 else { 512 StdCmap *sc; 513 514 for (sc = Scr->StdCmapInfo.head; sc; sc = sc->next) { 515 int i; 516 517 for (i = 0; i < sc->nmaps; i++) { 518 if (sc->maps[i].colormap == cmap) { 519 Scr->StdCmapInfo.mru = sc; 520 Scr->StdCmapInfo.mruindex = i; 521 stdcmap = &(sc->maps[i]); 522 goto gotit; 523 } 524 } 525 } 526 } 527 528 gotit: 529 if (stdcmap) { 530 color.pixel = (stdcmap->base_pixel + 531 ((Pixel) (((float) color.red / 65535.0) * 532 (double) stdcmap->red_max + 0.5) * 533 stdcmap->red_mult) + 534 ((Pixel) (((float) color.green / 65535.0) * 535 (double) stdcmap->green_max + 0.5) * 536 stdcmap->green_mult) + 537 ((Pixel) (((float) color.blue / 65535.0) * 538 (double) stdcmap->blue_max + 0.5) * 539 stdcmap->blue_mult)); 540 } 541 else { 542 twmWarning("unable to allocate color \"%s\"", name); 543 return; 544 } 545 } 546 547 *what = color.pixel; 548} 549 550void 551GetColorValue(int kind, XColor *what, const char *name) 552{ 553 XColor junkcolor; 554 Colormap cmap = Scr->TwmRoot.cmaps.cwins[0]->colormap->c; 555 556#ifndef TOM 557 if (!Scr->FirstTime) 558 return; 559#endif 560 561 if (Scr->Monochrome != kind) 562 return; 563 564 if (!XLookupColor(dpy, cmap, name, what, &junkcolor)) { 565 twmWarning("invalid color name \"%s\"", name); 566 } 567 else { 568 what->pixel = AllPlanes; 569 } 570} 571 572static Boolean 573FindFontSet(MyFont *font, const char *fontname) 574{ 575 char **missing_charset_list_return; 576 int missing_charset_count_return; 577 char *def_string_return; 578 XFontSetExtents *font_extents; 579 XFontStruct **xfonts; 580 char **font_names; 581 582 if (use_fontset) { 583 int ascent; 584 int descent; 585 int fnum; 586 register int i; 587 588 if (font->fontset != NULL) { 589 XFreeFontSet(dpy, font->fontset); 590 } 591 592 if ((font->fontset = XCreateFontSet(dpy, fontname, 593 &missing_charset_list_return, 594 &missing_charset_count_return, 595 &def_string_return)) == NULL) { 596 return False; 597 } 598 if (missing_charset_count_return) { 599 twmVerbose("%d fonts are missing from fontset", 600 missing_charset_count_return); 601 for (i = 0; i < missing_charset_count_return; i++) { 602 twmVerbose("font for charset %s is lacking.", 603 missing_charset_list_return[i]); 604 } 605 } 606 607 font_extents = XExtentsOfFontSet(font->fontset); 608 fnum = XFontsOfFontSet(font->fontset, &xfonts, &font_names); 609 for (i = 0, ascent = 0, descent = 0; i < fnum; i++) { 610 if (ascent < (*xfonts)->ascent) 611 ascent = (*xfonts)->ascent; 612 if (descent < (*xfonts)->descent) 613 descent = (*xfonts)->descent; 614 xfonts++; 615 } 616 font->height = font_extents->max_logical_extent.height; 617 font->y = ascent; 618 font->ascent = ascent; 619 font->descent = descent; 620 twmMessage("created fontset with %d fonts (%d missing) for \"%s\"", 621 fnum, missing_charset_count_return, 622 fontname ? fontname : "NULL"); 623 return True; 624 } 625 626 if (font->font != NULL) 627 XFreeFont(dpy, font->font); 628 629 if ((font->font = XLoadQueryFont(dpy, fontname)) == NULL) { 630 return False; 631 } 632 font->height = font->font->ascent + font->font->descent; 633 font->y = font->font->ascent; 634 font->ascent = font->font->ascent; 635 font->descent = font->font->descent; 636 return True; 637} 638 639/* 640 * The following functions are sensible to 'use_fontset'. 641 * When 'use_fontset' is True, 642 * - XFontSet-related internationalized functions are used 643 * so as multibyte languages can be displayed. 644 * When 'use_fontset' is False, 645 * - XFontStruct-related conventional functions are used 646 * so as 8-bit characters can be displayed even when 647 * locale is not set properly. 648 */ 649void 650GetFont(MyFont *font) 651{ 652 653 if (!FindFontSet(font, font->name)) { 654 const char *what = "fonts"; 655 const char *deffontname = "fixed"; 656 657 if (use_fontset) { 658 what = "fontsets"; 659 } 660 else if (Scr->DefaultFont.name) { 661 deffontname = Scr->DefaultFont.name; 662 } 663 if (!FindFontSet(font, deffontname)) { 664 twmError("unable to open %s \"%s\" or \"%s\"", 665 what, font->name, deffontname); 666 } 667 } 668} 669 670int 671MyFont_TextWidth(MyFont *font, const char *string, int len) 672{ 673 XRectangle ink_rect; 674 XRectangle logical_rect; 675 676 if (use_fontset) { 677 XmbTextExtents(font->fontset, string, len, &ink_rect, &logical_rect); 678 return logical_rect.width; 679 } 680 return XTextWidth(font->font, string, len); 681} 682 683void 684MyFont_DrawImageString(Display *dpy2, Drawable d, MyFont *font, GC gc, 685 int x, int y, const char *string, int len) 686{ 687 if (use_fontset) { 688 XmbDrawImageString(dpy2, d, font->fontset, gc, x, y, string, len); 689 return; 690 } 691 XDrawImageString(dpy2, d, gc, x, y, string, len); 692} 693 694void 695MyFont_DrawString(Display *dpy2, Drawable d, MyFont *font, GC gc, 696 int x, int y, const char *string, int len) 697{ 698 if (use_fontset) { 699 XmbDrawString(dpy2, d, font->fontset, gc, x, y, string, len); 700 return; 701 } 702 XDrawString(dpy2, d, gc, x, y, string, len); 703} 704 705void 706MyFont_ChangeGC(unsigned long fix_fore, unsigned long fix_back, 707 MyFont *fix_font) 708{ 709 Gcv.foreground = fix_fore; 710 Gcv.background = fix_back; 711 if (use_fontset) { 712 XChangeGC(dpy, Scr->NormalGC, GCForeground | GCBackground, &Gcv); 713 return; 714 } 715 Gcv.font = fix_font->font->fid; 716 XChangeGC(dpy, Scr->NormalGC, GCFont | GCForeground | GCBackground, &Gcv); 717} 718 719/* 720 * The following functions are internationalized substitutions 721 * for XFetchName and XGetIconName using XGetWMName and 722 * XGetWMIconName. 723 * 724 * Please note that the third arguments have to be freed using free(), 725 * not XFree(). 726 */ 727Status 728I18N_FetchName(Display *dpy2, Window w, char **winname) 729{ 730 int status; 731 XTextProperty text_prop; 732 int rc = 0; 733 734 *winname = NULL; 735 736 status = XGetWMName(dpy2, w, &text_prop); 737 if (status && text_prop.value && text_prop.nitems) { 738 char **list = NULL; 739 int num; 740 741 status = XmbTextPropertyToTextList(dpy2, &text_prop, &list, &num); 742 if (status >= Success && num && list && *list) { 743 XFree(text_prop.value); 744 *winname = strdup(*list); 745 XFreeStringList(list); 746 rc = 1; 747 } 748 else { 749 char *value = NULL; 750 751 /* 752 * If the system's locale support is broken (e.g., missing useful 753 * parts), the preceding Xmb call may fail. 754 */ 755 if (XFetchName(dpy2, w, &value) && value != NULL) { 756 *winname = strdup(value); 757 XFree(value); 758 rc = 1; 759 } 760 } 761 } 762 763 return rc; 764} 765 766Status 767I18N_GetIconName(Display *dpy2, Window w, char **iconname) 768{ 769 int status; 770 XTextProperty text_prop; 771 char **list; 772 int num; 773 774 status = XGetWMIconName(dpy2, w, &text_prop); 775 if (!status || !text_prop.value || !text_prop.nitems) 776 return 0; 777 status = XmbTextPropertyToTextList(dpy2, &text_prop, &list, &num); 778 if (status < Success || !num || !*list) 779 return 0; 780 XFree(text_prop.value); 781 *iconname = (char *) strdup(*list); 782 XFreeStringList(list); 783 return 1; 784} 785 786/** 787 * separate routine to set focus to make things more understandable 788 * and easier to debug 789 */ 790void 791SetFocus(TwmWindow *tmp_win, Time time) 792{ 793 Window w = (tmp_win ? tmp_win->w : PointerRoot); 794 795#ifdef TRACE 796 if (tmp_win) { 797 twmMessage("Focusing on window \"%s\"", tmp_win->full_name); 798 } 799 else { 800 twmMessage("Unfocusing; Scr->Focus was \"%s\"", 801 Scr->Focus ? Scr->Focus->full_name : "(nil)"); 802 } 803#endif 804 805 XSetInputFocus(dpy, w, RevertToPointerRoot, time); 806} 807 808static Pixmap 809CreateXLogoPixmap(unsigned *widthp, unsigned *heightp) 810{ 811 int h = Scr->TBInfo.width - Scr->TBInfo.border * 2; 812 813 if (h < 0) 814 h = 0; 815 816 *widthp = *heightp = (unsigned int) h; 817 if (Scr->tbpm.xlogo == None) { 818 GC gc, gcBack; 819 820 Scr->tbpm.xlogo = 821 XCreatePixmap(dpy, Scr->Root, (unsigned) h, (unsigned) h, 1); 822 gc = XCreateGC(dpy, Scr->tbpm.xlogo, 0L, NULL); 823 XSetForeground(dpy, gc, 0); 824 XFillRectangle(dpy, Scr->tbpm.xlogo, gc, 0, 0, (unsigned) h, 825 (unsigned) h); 826 XSetForeground(dpy, gc, 1); 827 gcBack = XCreateGC(dpy, Scr->tbpm.xlogo, 0L, NULL); 828 XSetForeground(dpy, gcBack, 0); 829 830 /* 831 * draw the logo large so that it gets as dense as possible; then white 832 * out the edges so that they look crisp 833 */ 834 XmuDrawLogo(dpy, Scr->tbpm.xlogo, gc, gcBack, -1, -1, 835 (unsigned) (h + 2), (unsigned) (h + 2)); 836 XDrawRectangle(dpy, Scr->tbpm.xlogo, gcBack, 0, 0, (unsigned) (h - 1), 837 (unsigned) (h - 1)); 838 839 /* 840 * done drawing 841 */ 842 XFreeGC(dpy, gc); 843 XFreeGC(dpy, gcBack); 844 } 845 return Scr->tbpm.xlogo; 846} 847 848static Pixmap 849CreateResizePixmap(unsigned *widthp, unsigned *heightp) 850{ 851 int h = Scr->TBInfo.width - Scr->TBInfo.border * 2; 852 853 if (h < 1) 854 h = 1; 855 856 *widthp = *heightp = (unsigned int) h; 857 if (Scr->tbpm.resize == None) { 858 XPoint points[3]; 859 GC gc; 860 int w; 861 int lw; 862 863 /* 864 * create the pixmap 865 */ 866 Scr->tbpm.resize = 867 XCreatePixmap(dpy, Scr->Root, (unsigned) h, (unsigned) h, 1); 868 gc = XCreateGC(dpy, Scr->tbpm.resize, 0L, NULL); 869 XSetForeground(dpy, gc, 0); 870 XFillRectangle(dpy, Scr->tbpm.resize, gc, 0, 0, (unsigned) h, 871 (unsigned) h); 872 XSetForeground(dpy, gc, 1); 873 lw = h / 16; 874 if (lw == 1) 875 lw = 0; 876 XSetLineAttributes(dpy, gc, (unsigned) lw, LineSolid, CapButt, 877 JoinMiter); 878 879 /* 880 * draw the resize button, 881 */ 882 w = (h * 2) / 3; 883 points[0].x = (short) w; 884 points[0].y = 0; 885 points[1].x = (short) w; 886 points[1].y = (short) w; 887 points[2].x = 0; 888 points[2].y = (short) w; 889 XDrawLines(dpy, Scr->tbpm.resize, gc, points, 3, CoordModeOrigin); 890 w = w / 2; 891 points[0].x = (short) w; 892 points[0].y = 0; 893 points[1].x = (short) w; 894 points[1].y = (short) w; 895 points[2].x = 0; 896 points[2].y = (short) w; 897 XDrawLines(dpy, Scr->tbpm.resize, gc, points, 3, CoordModeOrigin); 898 899 /* 900 * done drawing 901 */ 902 XFreeGC(dpy, gc); 903 } 904 return Scr->tbpm.resize; 905} 906 907static Pixmap 908CreateDotPixmap(unsigned *widthp, unsigned *heightp) 909{ 910 int h = Scr->TBInfo.width - Scr->TBInfo.border * 2; 911 912 h = h * 3 / 4; 913 if (h < 1) 914 h = 1; 915 if (!(h & 1)) 916 h--; 917 *widthp = *heightp = (unsigned int) h; 918 if (Scr->tbpm.delete == None) { 919 GC gc; 920 Pixmap pix; 921 922 pix = Scr->tbpm.delete = 923 XCreatePixmap(dpy, Scr->Root, (unsigned) h, (unsigned) h, 1); 924 gc = XCreateGC(dpy, pix, 0L, NULL); 925 XSetLineAttributes(dpy, gc, (unsigned) h, LineSolid, CapRound, 926 JoinRound); 927 XSetForeground(dpy, gc, 0L); 928 XFillRectangle(dpy, pix, gc, 0, 0, (unsigned) h, (unsigned) h); 929 XSetForeground(dpy, gc, 1L); 930 XDrawLine(dpy, pix, gc, h / 2, h / 2, h / 2, h / 2); 931 XFreeGC(dpy, gc); 932 } 933 return Scr->tbpm.delete; 934} 935 936#define questionmark_width 8 937#define questionmark_height 8 938static char questionmark_bits[] = { 939 0x38, 0x7c, 0x64, 0x30, 0x18, 0x00, 0x18, 0x18 940}; 941 942static Pixmap 943CreateQuestionPixmap(unsigned *widthp, unsigned *heightp) 944{ 945 *widthp = questionmark_width; 946 *heightp = questionmark_height; 947 if (Scr->tbpm.question == None) { 948 Scr->tbpm.question = XCreateBitmapFromData(dpy, Scr->Root, 949 questionmark_bits, 950 questionmark_width, 951 questionmark_height); 952 } 953 /* 954 * this must succeed or else we are in deep trouble elsewhere 955 */ 956 return Scr->tbpm.question; 957} 958 959static Pixmap 960CreateMenuPixmap(unsigned *widthp, unsigned *heightp) 961{ 962 return CreateMenuIcon(Scr->TBInfo.width - Scr->TBInfo.border * 2, 963 widthp, heightp); 964} 965 966Pixmap 967CreateMenuIcon(int height, unsigned *widthp, unsigned *heightp) 968{ 969 int h, w; 970 971 h = height; 972 w = h * 7 / 8; 973 if (h < 1) 974 h = 1; 975 if (w < 1) 976 w = 1; 977 *widthp = (unsigned) w; 978 *heightp = (unsigned) h; 979 if (Scr->tbpm.menu == None) { 980 Pixmap pix; 981 GC gc; 982 int ih, iw; 983 int ix, iy; 984 int mh, mw; 985 int tw, th; 986 int lw, lh; 987 int lx, ly; 988 int lines, dly; 989 int off; 990 int bw; 991 992 pix = Scr->tbpm.menu = 993 XCreatePixmap(dpy, Scr->Root, (unsigned) w, (unsigned) h, 1); 994 gc = XCreateGC(dpy, pix, 0L, NULL); 995 XSetForeground(dpy, gc, 0L); 996 XFillRectangle(dpy, pix, gc, 0, 0, (unsigned) w, (unsigned) h); 997 XSetForeground(dpy, gc, 1L); 998 ix = 1; 999 iy = 1; 1000 ih = h - iy * 2; 1001 iw = w - ix * 2; 1002 off = ih / 8; 1003 mh = ih - off; 1004 mw = iw - off; 1005 bw = mh / 16; 1006 if (bw == 0 && mw > 2) 1007 bw = 1; 1008 tw = mw - bw * 2; 1009 th = mh - bw * 2; 1010 XFillRectangle(dpy, pix, gc, ix, iy, (unsigned) mw, (unsigned) mh); 1011 XFillRectangle(dpy, pix, gc, ix + iw - mw, iy + ih - mh, (unsigned) mw, 1012 (unsigned) mh); 1013 XSetForeground(dpy, gc, 0L); 1014 XFillRectangle(dpy, pix, gc, ix + bw, iy + bw, (unsigned) tw, 1015 (unsigned) th); 1016 XSetForeground(dpy, gc, 1L); 1017 lw = tw / 2; 1018 if ((tw & 1) ^ (lw & 1)) 1019 lw++; 1020 lx = ix + bw + (tw - lw) / 2; 1021 1022 lh = th / 2 - bw; 1023 if ((lh & 1) ^ ((th - bw) & 1)) 1024 lh++; 1025 ly = iy + bw + (th - bw - lh) / 2; 1026 1027 lines = 3; 1028 if ((lh & 1) && lh < 6) { 1029 lines--; 1030 } 1031 dly = lh / (lines - 1); 1032 while (lines--) { 1033 XFillRectangle(dpy, pix, gc, lx, ly, (unsigned) lw, (unsigned) bw); 1034 ly += dly; 1035 } 1036 XFreeGC(dpy, gc); 1037 } 1038 return Scr->tbpm.menu; 1039} 1040 1041void 1042Bell(int type _X_UNUSED, int percent, Window win _X_UNUSED) 1043{ 1044#ifdef XKB 1045 XkbStdBell(dpy, win, percent, type); 1046#else 1047 XBell(dpy, percent); 1048#endif 1049 return; 1050} 1051