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 "parse.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 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 unsigned udummy = 0; 213 Window wdummy = None; 214 215 if (!Scr->DoZoom || Scr->ZoomCount < 1) 216 return; 217 218 if (wf == None || wt == None) 219 return; 220 221 XGetGeometry(dpy, wf, &wdummy, &fx, &fy, &fw, &fh, &udummy, &udummy); 222 XGetGeometry(dpy, wt, &wdummy, &tx, &ty, &tw, &th, &udummy, &udummy); 223 224 dx = ((long) (tx - fx)); /* going from -> to */ 225 dy = ((long) (ty - fy)); /* going from -> to */ 226 dw = ((long) (tw - fw)); /* going from -> to */ 227 dh = ((long) (th - fh)); /* going from -> to */ 228 z = (long) (Scr->ZoomCount + 1); 229 230 for (j = 0; j < 2; j++) { 231 long i; 232 233 XDrawRectangle(dpy, Scr->Root, Scr->DrawGC, fx, fy, fw, fh); 234 for (i = 1; i < z; i++) { 235 int x = fx + (int) ((dx * i) / z); 236 int y = fy + (int) ((dy * i) / z); 237 unsigned width = (unsigned) (((long) fw) + (dw * i) / z); 238 unsigned height = (unsigned) (((long) fh) + (dh * i) / z); 239 240 XDrawRectangle(dpy, Scr->Root, Scr->DrawGC, x, y, width, height); 241 } 242 XDrawRectangle(dpy, Scr->Root, Scr->DrawGC, tx, ty, tw, th); 243 } 244} 245 246/** 247 * expand the tilde character to HOME if it is the first 248 * character of the filename 249 * 250 * \return a pointer to the new name 251 * 252 * \param name the filename to expand 253 */ 254char * 255ExpandFilename(const char *name) 256{ 257 char *newname; 258 259 if (name[0] != '~') 260 return strdup(name); 261 262 newname = (char *) malloc((size_t) HomeLen + strlen(name) + 2); 263 if (!newname) { 264 twmWarning("unable to allocate %lu bytes to expand filename %s/%s", 265 (unsigned long) HomeLen + (unsigned long) strlen(name) + 2, 266 Home, &name[1]); 267 } 268 else { 269 (void) sprintf(newname, "%s/%s", Home, &name[1]); 270 } 271 272 return newname; 273} 274 275/** 276 * read in the bitmap file for the unknown icon 277 * 278 * \param name the filename to read 279 */ 280void 281GetUnknownIcon(const char *name) 282{ 283 int dummy = 0; 284 unsigned udummy = 0; 285 Window wdummy = None; 286 287 if ((Scr->UnknownPm = GetBitmap(name)) != None) { 288 XGetGeometry(dpy, Scr->UnknownPm, &wdummy, &dummy, &dummy, 289 (unsigned int *) &Scr->UnknownWidth, 290 (unsigned int *) &Scr->UnknownHeight, &udummy, &udummy); 291 } 292} 293 294/** 295 * FindBitmap - read in a bitmap file and return size 296 * 297 * \return pixmap associated with bitmap 298 * 299 * \param name filename to read 300 * \param[out] widthp pointer to width of bitmap 301 * \param[out] heightp pointer to height of bitmap 302 */ 303Pixmap 304FindBitmap(const char *name, unsigned *widthp, unsigned *heightp) 305{ 306 char *bigname; 307 Pixmap pm; 308 309 if (!name) 310 return None; 311 312 /* 313 * Names of the form :name refer to hardcoded images that are scaled to 314 * look nice in title buttons. Eventually, it would be nice to put in a 315 * menu symbol as well.... 316 */ 317 if (name[0] == ':') { 318 int i; 319 /* *INDENT-OFF* */ 320 static struct { 321 const char *name; 322 Pixmap (*proc)(unsigned int *, unsigned int *); 323 } pmtab[] = { 324 { TBPM_DOT, CreateDotPixmap }, 325 { TBPM_ICONIFY, CreateDotPixmap }, 326 { TBPM_RESIZE, CreateResizePixmap }, 327 { TBPM_XLOGO, CreateXLogoPixmap }, 328 { TBPM_DELETE, CreateXLogoPixmap }, 329 { TBPM_MENU, CreateMenuPixmap }, 330 { TBPM_QUESTION, CreateQuestionPixmap }, 331 }; 332 /* *INDENT-ON* */ 333 334 for (i = 0; (size_t) i < (sizeof pmtab) / (sizeof pmtab[0]); i++) { 335 if (XmuCompareISOLatin1(pmtab[i].name, name) == 0) 336 return (*pmtab[i].proc) (widthp, heightp); 337 } 338 twmWarning("no such built-in bitmap \"%s\"", name); 339 return None; 340 } 341 342 /* 343 * Generate a full pathname if any special prefix characters (such as ~) 344 * are used. If the bigname is different from name, bigname will need to 345 * be freed. 346 */ 347 bigname = ExpandFilename(name); 348 if (!bigname) 349 return None; 350 351 /* 352 * look along bitmapFilePath resource same as toolkit clients 353 */ 354 pm = XmuLocateBitmapFile(ScreenOfDisplay(dpy, Scr->screen), bigname, NULL, 355 0, (int *) widthp, (int *) heightp, &HotX, &HotY); 356 if (pm == None && Scr->IconDirectory && bigname[0] != '/') { 357 free(bigname); 358 /* 359 * Attempt to find icon in old IconDirectory (now obsolete) 360 */ 361 bigname = (char *) 362 malloc(strlen(name) + strlen(Scr->IconDirectory) + 2); 363 if (!bigname) { 364 twmWarning("unable to allocate memory for \"%s/%s\"", 365 Scr->IconDirectory, name); 366 return None; 367 } 368 (void) sprintf(bigname, "%s/%s", Scr->IconDirectory, name); 369 if (XReadBitmapFile(dpy, Scr->Root, bigname, widthp, heightp, &pm, 370 &HotX, &HotY) != BitmapSuccess) { 371 pm = None; 372 } 373 } 374 free(bigname); 375 if (pm == None) { 376 twmWarning("unable to find bitmap \"%s\"", name); 377 } 378 379 return pm; 380} 381 382Pixmap 383GetBitmap(const char *name) 384{ 385 unsigned udummy = 0; 386 387 return FindBitmap(name, &udummy, &udummy); 388} 389 390void 391InsertRGBColormap(Atom a, XStandardColormap *maps, int nmaps, Bool replace) 392{ 393 StdCmap *sc = NULL; 394 395 if (replace) { /* locate existing entry */ 396 for (sc = Scr->StdCmapInfo.head; sc; sc = sc->next) { 397 if (sc->atom == a) 398 break; 399 } 400 } 401 402 if (!sc) { /* no existing, allocate new */ 403 sc = (StdCmap *) malloc(sizeof(StdCmap)); 404 if (!sc) { 405 twmWarning("unable to allocate %lu bytes for StdCmap", 406 (unsigned long) sizeof(StdCmap)); 407 return; 408 } 409 replace = False; 410 } 411 412 if (replace) { /* just update contents */ 413 if (sc->maps) 414 XFree(sc->maps); 415 if (sc == Scr->StdCmapInfo.mru) 416 Scr->StdCmapInfo.mru = NULL; 417 } 418 else { /* else appending */ 419 sc->next = NULL; 420 sc->atom = a; 421 if (Scr->StdCmapInfo.tail) { 422 Scr->StdCmapInfo.tail->next = sc; 423 } 424 else { 425 Scr->StdCmapInfo.head = sc; 426 } 427 Scr->StdCmapInfo.tail = sc; 428 } 429 sc->nmaps = nmaps; 430 sc->maps = maps; 431 432 return; 433} 434 435void 436RemoveRGBColormap(Atom a) 437{ 438 StdCmap *sc, *prev; 439 440 prev = NULL; 441 for (sc = Scr->StdCmapInfo.head; sc; sc = sc->next) { 442 if (sc->atom == a) 443 break; 444 prev = sc; 445 } 446 if (sc) { /* found one */ 447 if (sc->maps) 448 XFree(sc->maps); 449 if (prev) 450 prev->next = sc->next; 451 if (Scr->StdCmapInfo.head == sc) 452 Scr->StdCmapInfo.head = sc->next; 453 if (Scr->StdCmapInfo.tail == sc) 454 Scr->StdCmapInfo.tail = prev; 455 if (Scr->StdCmapInfo.mru == sc) 456 Scr->StdCmapInfo.mru = NULL; 457 } 458 return; 459} 460 461void 462LocateStandardColormaps(void) 463{ 464 Atom *atoms; 465 int natoms; 466 int i; 467 468 atoms = XListProperties(dpy, Scr->Root, &natoms); 469 for (i = 0; i < natoms; i++) { 470 XStandardColormap *maps = NULL; 471 int nmaps; 472 473 if (XGetRGBColormaps(dpy, Scr->Root, &maps, &nmaps, atoms[i])) { 474 /* if got one, then append to current list */ 475 InsertRGBColormap(atoms[i], maps, nmaps, False); 476 } 477 } 478 if (atoms) 479 XFree(atoms); 480 return; 481} 482 483void 484GetColor(int kind, Pixel *what, const char *name) 485{ 486 XColor color, junkcolor; 487 Status stat = 0; 488 Colormap cmap = Scr->TwmRoot.cmaps.cwins[0]->colormap->c; 489 490 if (!Scr->FirstTime) 491 return; 492 493 if (Scr->Monochrome != kind) 494 return; 495 496 if (!XAllocNamedColor(dpy, cmap, name, &color, &junkcolor)) { 497 /* if we could not allocate the color, let's see if this is a 498 * standard colormap 499 */ 500 XStandardColormap *stdcmap = NULL; 501 502 /* parse the named color */ 503 if (name[0] != '#') 504 stat = XParseColor(dpy, cmap, name, &color); 505 if (!stat) { 506 twmWarning("invalid color name \"%s\"", name); 507 return; 508 } 509 510 /* 511 * look through the list of standard colormaps (check cache first) 512 */ 513 if (Scr->StdCmapInfo.mru && Scr->StdCmapInfo.mru->maps && 514 (Scr->StdCmapInfo.mru->maps[Scr->StdCmapInfo.mruindex].colormap == 515 cmap)) { 516 stdcmap = &(Scr->StdCmapInfo.mru->maps[Scr->StdCmapInfo.mruindex]); 517 } 518 else { 519 StdCmap *sc; 520 521 for (sc = Scr->StdCmapInfo.head; sc; sc = sc->next) { 522 int i; 523 524 for (i = 0; i < sc->nmaps; i++) { 525 if (sc->maps[i].colormap == cmap) { 526 Scr->StdCmapInfo.mru = sc; 527 Scr->StdCmapInfo.mruindex = i; 528 stdcmap = &(sc->maps[i]); 529 goto gotit; 530 } 531 } 532 } 533 } 534 535 gotit: 536 if (stdcmap) { 537 color.pixel = (stdcmap->base_pixel + 538 ((Pixel) (((float) color.red / 65535.0) * 539 (double) stdcmap->red_max + 0.5) * 540 stdcmap->red_mult) + 541 ((Pixel) (((float) color.green / 65535.0) * 542 (double) stdcmap->green_max + 0.5) * 543 stdcmap->green_mult) + 544 ((Pixel) (((float) color.blue / 65535.0) * 545 (double) stdcmap->blue_max + 0.5) * 546 stdcmap->blue_mult)); 547 } 548 else { 549 twmWarning("unable to allocate color \"%s\"", name); 550 return; 551 } 552 } 553 554 *what = color.pixel; 555} 556 557void 558GetColorValue(int kind, XColor *what, const char *name) 559{ 560 XColor junkcolor; 561 Colormap cmap = Scr->TwmRoot.cmaps.cwins[0]->colormap->c; 562 563 if (!Scr->FirstTime) 564 return; 565 566 if (Scr->Monochrome != kind) 567 return; 568 569 if (!XLookupColor(dpy, cmap, name, what, &junkcolor)) { 570 twmWarning("invalid color name \"%s\"", name); 571 } 572 else { 573 what->pixel = AllPlanes; 574 } 575} 576 577static Boolean 578FindFontSet(MyFont *font, const char *fontname) 579{ 580 char **missing_charset_list_return; 581 int missing_charset_count_return; 582 char *def_string_return; 583 XFontSetExtents *font_extents; 584 XFontStruct **xfonts; 585 char **font_names; 586 587 if (use_fontset) { 588 int ascent; 589 int descent; 590 int fnum; 591 int i; 592 593 if (font->fontset != NULL) { 594 XFreeFontSet(dpy, font->fontset); 595 } 596 597 if ((font->fontset = XCreateFontSet(dpy, fontname, 598 &missing_charset_list_return, 599 &missing_charset_count_return, 600 &def_string_return)) == NULL) { 601 return False; 602 } 603 if (missing_charset_count_return) { 604 twmVerbose("%d fonts are missing from fontset", 605 missing_charset_count_return); 606 for (i = 0; i < missing_charset_count_return; i++) { 607 twmVerbose("font for charset %s is lacking.", 608 missing_charset_list_return[i]); 609 } 610 XFreeStringList(missing_charset_list_return); 611 } 612 613 font_extents = XExtentsOfFontSet(font->fontset); 614 fnum = XFontsOfFontSet(font->fontset, &xfonts, &font_names); 615 for (i = 0, ascent = 0, descent = 0; i < fnum; i++) { 616 if (ascent < (*xfonts)->ascent) 617 ascent = (*xfonts)->ascent; 618 if (descent < (*xfonts)->descent) 619 descent = (*xfonts)->descent; 620 xfonts++; 621 } 622 font->height = font_extents->max_logical_extent.height; 623 font->y = ascent; 624 font->ascent = ascent; 625 font->descent = descent; 626 twmMessage("created fontset with %d fonts (%d missing) for \"%s\"", 627 fnum, missing_charset_count_return, 628 fontname ? fontname : "NULL"); 629 return True; 630 } 631 632 if (font->font != NULL) 633 XFreeFont(dpy, font->font); 634 635 if ((font->font = XLoadQueryFont(dpy, fontname)) == NULL) { 636 return False; 637 } 638 font->height = font->font->ascent + font->font->descent; 639 font->y = font->font->ascent; 640 font->ascent = font->font->ascent; 641 font->descent = font->font->descent; 642 return True; 643} 644 645/* 646 * The following functions are sensible to 'use_fontset'. 647 * When 'use_fontset' is True, 648 * - XFontSet-related internationalized functions are used 649 * so as multibyte languages can be displayed. 650 * When 'use_fontset' is False, 651 * - XFontStruct-related conventional functions are used 652 * so as 8-bit characters can be displayed even when 653 * locale is not set properly. 654 */ 655void 656GetFont(MyFont *font) 657{ 658 659 if (!FindFontSet(font, font->name)) { 660 const char *what = "fonts"; 661 const char *deffontname = "fixed"; 662 663 if (use_fontset) { 664 what = "fontsets"; 665 } 666 else if (Scr->DefaultFont.name) { 667 deffontname = Scr->DefaultFont.name; 668 } 669 if (!FindFontSet(font, deffontname)) { 670 twmError("unable to open %s \"%s\" or \"%s\"", 671 what, font->name, deffontname); 672 } 673 } 674} 675 676void 677DestroyFont(MyFont *font) 678{ 679 if (!font) { 680 return; 681 } 682 683 if (font->fontset) { 684 XFreeFontSet(dpy, font->fontset); 685 font->fontset = NULL; 686 } 687 688 if (font->font) { 689 XFreeFont(dpy, font->font); 690 font->font = NULL; 691 } 692} 693 694int 695MyFont_TextWidth(MyFont *font, const char *string, int len) 696{ 697 XRectangle ink_rect; 698 XRectangle logical_rect; 699 700 if (use_fontset) { 701 XmbTextExtents(font->fontset, string, len, &ink_rect, &logical_rect); 702 return logical_rect.width; 703 } 704 return XTextWidth(font->font, string, len); 705} 706 707void 708MyFont_DrawImageString(Display *dpy2, Drawable d, MyFont *font, GC gc, 709 int x, int y, const char *string, int len) 710{ 711 if (use_fontset) { 712 XmbDrawImageString(dpy2, d, font->fontset, gc, x, y, string, len); 713 return; 714 } 715 XDrawImageString(dpy2, d, gc, x, y, string, len); 716} 717 718void 719MyFont_DrawString(Display *dpy2, Drawable d, MyFont *font, GC gc, 720 int x, int y, const char *string, int len) 721{ 722 if (use_fontset) { 723 XmbDrawString(dpy2, d, font->fontset, gc, x, y, string, len); 724 return; 725 } 726 XDrawString(dpy2, d, gc, x, y, string, len); 727} 728 729void 730MyFont_ChangeGC(unsigned long fix_fore, unsigned long fix_back, 731 MyFont *fix_font) 732{ 733 Gcv.foreground = fix_fore; 734 Gcv.background = fix_back; 735 if (use_fontset) { 736 XChangeGC(dpy, Scr->NormalGC, GCForeground | GCBackground, &Gcv); 737 return; 738 } 739 Gcv.font = fix_font->font->fid; 740 XChangeGC(dpy, Scr->NormalGC, GCFont | GCForeground | GCBackground, &Gcv); 741} 742 743/* 744 * The following functions are internationalized substitutions 745 * for XFetchName and XGetIconName using XGetWMName and 746 * XGetWMIconName. 747 * 748 * Please note that the third arguments have to be freed using free(), 749 * not XFree(). 750 */ 751Status 752I18N_FetchName(Display *dpy2, Window w, char **winname) 753{ 754 int status; 755 XTextProperty text_prop; 756 int rc = 0; 757 758 *winname = NULL; 759 760 status = XGetWMName(dpy2, w, &text_prop); 761 if (status && text_prop.value && text_prop.nitems) { 762 char **list = NULL; 763 int num; 764 765 status = XmbTextPropertyToTextList(dpy2, &text_prop, &list, &num); 766 if (status >= Success && num && list && *list) { 767 XFree(text_prop.value); 768 *winname = strdup(*list); 769 XFreeStringList(list); 770 rc = 1; 771 } 772 else { 773 char *value = NULL; 774 775 /* 776 * If the system's locale support is broken (e.g., missing useful 777 * parts), the preceding Xmb call may fail. 778 */ 779 if (XFetchName(dpy2, w, &value) && value != NULL) { 780 *winname = strdup(value); 781 XFree(value); 782 rc = 1; 783 } 784 } 785 } 786 787 return rc; 788} 789 790Status 791I18N_GetIconName(Display *dpy2, Window w, char **iconname) 792{ 793 int status; 794 XTextProperty text_prop; 795 char **list; 796 int num; 797 798 status = XGetWMIconName(dpy2, w, &text_prop); 799 if (!status || !text_prop.value || !text_prop.nitems) 800 return 0; 801 status = XmbTextPropertyToTextList(dpy2, &text_prop, &list, &num); 802 if (status < Success || !num || !*list) 803 return 0; 804 XFree(text_prop.value); 805 *iconname = (char *) strdup(*list); 806 XFreeStringList(list); 807 return 1; 808} 809 810/** 811 * separate routine to set focus to make things more understandable 812 * and easier to debug 813 */ 814void 815SetFocus(TwmWindow *tmp_win, Time time) 816{ 817 Window w = (tmp_win ? tmp_win->w : PointerRoot); 818 819#ifdef TRACE 820 if (tmp_win) { 821 twmMessage("Focusing on window \"%s\"", tmp_win->full_name); 822 } 823 else { 824 twmMessage("Unfocusing; Scr->Focus was \"%s\"", 825 Scr->Focus ? Scr->Focus->full_name : "(nil)"); 826 } 827#endif 828 829 XSetInputFocus(dpy, w, RevertToPointerRoot, time); 830} 831 832static Pixmap 833CreateXLogoPixmap(unsigned *widthp, unsigned *heightp) 834{ 835 int h = Scr->TBInfo.width - Scr->TBInfo.border * 2; 836 837 if (h < 0) 838 h = 0; 839 840 *widthp = *heightp = (unsigned int) h; 841 if (Scr->tbpm.xlogo == None) { 842 GC gc, gcBack; 843 844 Scr->tbpm.xlogo = 845 XCreatePixmap(dpy, Scr->Root, (unsigned) h, (unsigned) h, 1); 846 gc = XCreateGC(dpy, Scr->tbpm.xlogo, 0L, NULL); 847 XSetForeground(dpy, gc, 0); 848 XFillRectangle(dpy, Scr->tbpm.xlogo, gc, 0, 0, (unsigned) h, 849 (unsigned) h); 850 XSetForeground(dpy, gc, 1); 851 gcBack = XCreateGC(dpy, Scr->tbpm.xlogo, 0L, NULL); 852 XSetForeground(dpy, gcBack, 0); 853 854 /* 855 * draw the logo large so that it gets as dense as possible; then white 856 * out the edges so that they look crisp 857 */ 858 XmuDrawLogo(dpy, Scr->tbpm.xlogo, gc, gcBack, -1, -1, 859 (unsigned) (h + 2), (unsigned) (h + 2)); 860 XDrawRectangle(dpy, Scr->tbpm.xlogo, gcBack, 0, 0, (unsigned) (h - 1), 861 (unsigned) (h - 1)); 862 863 /* 864 * done drawing 865 */ 866 XFreeGC(dpy, gc); 867 XFreeGC(dpy, gcBack); 868 } 869 return Scr->tbpm.xlogo; 870} 871 872static Pixmap 873CreateResizePixmap(unsigned *widthp, unsigned *heightp) 874{ 875 int h = Scr->TBInfo.width - Scr->TBInfo.border * 2; 876 877 if (h < 1) 878 h = 1; 879 880 *widthp = *heightp = (unsigned int) h; 881 if (Scr->tbpm.resize == None) { 882 XPoint points[3]; 883 GC gc; 884 int w; 885 int lw; 886 887 /* 888 * create the pixmap 889 */ 890 Scr->tbpm.resize = 891 XCreatePixmap(dpy, Scr->Root, (unsigned) h, (unsigned) h, 1); 892 gc = XCreateGC(dpy, Scr->tbpm.resize, 0L, NULL); 893 XSetForeground(dpy, gc, 0); 894 XFillRectangle(dpy, Scr->tbpm.resize, gc, 0, 0, (unsigned) h, 895 (unsigned) h); 896 XSetForeground(dpy, gc, 1); 897 lw = h / 16; 898 if (lw == 1) 899 lw = 0; 900 XSetLineAttributes(dpy, gc, (unsigned) lw, LineSolid, CapButt, 901 JoinMiter); 902 903 /* 904 * draw the resize button, 905 */ 906 w = (h * 2) / 3; 907 points[0].x = (short) w; 908 points[0].y = 0; 909 points[1].x = (short) w; 910 points[1].y = (short) w; 911 points[2].x = 0; 912 points[2].y = (short) w; 913 XDrawLines(dpy, Scr->tbpm.resize, gc, points, 3, CoordModeOrigin); 914 w = w / 2; 915 points[0].x = (short) w; 916 points[0].y = 0; 917 points[1].x = (short) w; 918 points[1].y = (short) w; 919 points[2].x = 0; 920 points[2].y = (short) w; 921 XDrawLines(dpy, Scr->tbpm.resize, gc, points, 3, CoordModeOrigin); 922 923 /* 924 * done drawing 925 */ 926 XFreeGC(dpy, gc); 927 } 928 return Scr->tbpm.resize; 929} 930 931static Pixmap 932CreateDotPixmap(unsigned *widthp, unsigned *heightp) 933{ 934 int h = Scr->TBInfo.width - Scr->TBInfo.border * 2; 935 936 h = h * 3 / 4; 937 if (h < 1) 938 h = 1; 939 if (!(h & 1)) 940 h--; 941 *widthp = *heightp = (unsigned int) h; 942 if (Scr->tbpm.remove == None) { 943 GC gc; 944 Pixmap pix; 945 946 pix = Scr->tbpm.remove = 947 XCreatePixmap(dpy, Scr->Root, (unsigned) h, (unsigned) h, 1); 948 gc = XCreateGC(dpy, pix, 0L, NULL); 949 XSetLineAttributes(dpy, gc, (unsigned) h, LineSolid, CapRound, 950 JoinRound); 951 XSetForeground(dpy, gc, 0L); 952 XFillRectangle(dpy, pix, gc, 0, 0, (unsigned) h, (unsigned) h); 953 XSetForeground(dpy, gc, 1L); 954 XDrawLine(dpy, pix, gc, h / 2, h / 2, h / 2, h / 2); 955 XFreeGC(dpy, gc); 956 } 957 return Scr->tbpm.remove; 958} 959 960#define questionmark_width 8 961#define questionmark_height 8 962static char questionmark_bits[] = { 963 0x38, 0x7c, 0x64, 0x30, 0x18, 0x00, 0x18, 0x18 964}; 965 966static Pixmap 967CreateQuestionPixmap(unsigned *widthp, unsigned *heightp) 968{ 969 *widthp = questionmark_width; 970 *heightp = questionmark_height; 971 if (Scr->tbpm.question == None) { 972 Scr->tbpm.question = XCreateBitmapFromData(dpy, Scr->Root, 973 questionmark_bits, 974 questionmark_width, 975 questionmark_height); 976 } 977 /* 978 * this must succeed or else we are in deep trouble elsewhere 979 */ 980 return Scr->tbpm.question; 981} 982 983static Pixmap 984CreateMenuPixmap(unsigned *widthp, unsigned *heightp) 985{ 986 return CreateMenuIcon(Scr->TBInfo.width - Scr->TBInfo.border * 2, 987 widthp, heightp); 988} 989 990Pixmap 991CreateMenuIcon(int height, unsigned *widthp, unsigned *heightp) 992{ 993 int h, w; 994 995 h = height; 996 w = h * 7 / 8; 997 if (h < 1) 998 h = 1; 999 if (w < 1) 1000 w = 1; 1001 *widthp = (unsigned) w; 1002 *heightp = (unsigned) h; 1003 if (Scr->tbpm.menu == None) { 1004 Pixmap pix; 1005 GC gc; 1006 int ih, iw; 1007 int ix, iy; 1008 int mh, mw; 1009 int tw, th; 1010 int lw, lh; 1011 int lx, ly; 1012 int lines, dly; 1013 int off; 1014 int bw; 1015 1016 pix = Scr->tbpm.menu = 1017 XCreatePixmap(dpy, Scr->Root, (unsigned) w, (unsigned) h, 1); 1018 gc = XCreateGC(dpy, pix, 0L, NULL); 1019 XSetForeground(dpy, gc, 0L); 1020 XFillRectangle(dpy, pix, gc, 0, 0, (unsigned) w, (unsigned) h); 1021 XSetForeground(dpy, gc, 1L); 1022 ix = 1; 1023 iy = 1; 1024 ih = h - iy * 2; 1025 iw = w - ix * 2; 1026 off = ih / 8; 1027 mh = ih - off; 1028 mw = iw - off; 1029 bw = mh / 16; 1030 if (bw == 0 && mw > 2) 1031 bw = 1; 1032 tw = mw - bw * 2; 1033 th = mh - bw * 2; 1034 XFillRectangle(dpy, pix, gc, ix, iy, (unsigned) mw, (unsigned) mh); 1035 XFillRectangle(dpy, pix, gc, ix + iw - mw, iy + ih - mh, (unsigned) mw, 1036 (unsigned) mh); 1037 XSetForeground(dpy, gc, 0L); 1038 XFillRectangle(dpy, pix, gc, ix + bw, iy + bw, (unsigned) tw, 1039 (unsigned) th); 1040 XSetForeground(dpy, gc, 1L); 1041 lw = tw / 2; 1042 if ((tw & 1) ^ (lw & 1)) 1043 lw++; 1044 lx = ix + bw + (tw - lw) / 2; 1045 1046 lh = th / 2 - bw; 1047 if ((lh & 1) ^ ((th - bw) & 1)) 1048 lh++; 1049 ly = iy + bw + (th - bw - lh) / 2; 1050 1051 lines = 3; 1052 if ((lh & 1) && lh < 6) { 1053 lines--; 1054 } 1055 dly = lh / (lines - 1); 1056 while (lines--) { 1057 XFillRectangle(dpy, pix, gc, lx, ly, (unsigned) lw, (unsigned) bw); 1058 ly += dly; 1059 } 1060 XFreeGC(dpy, gc); 1061 } 1062 return Scr->tbpm.menu; 1063} 1064 1065void 1066Bell(int type _X_UNUSED, int percent, Window win _X_UNUSED) 1067{ 1068#ifdef XKB 1069 XkbStdBell(dpy, win, percent, type); 1070#else 1071 XBell(dpy, percent); 1072#endif 1073 return; 1074} 1075