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