util.c revision c2535118
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(char *name) 260{ 261 char *newname; 262 263 if (name[0] != '~') return 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 char *basename2; 593 594 if (use_fontset) { 595 if (font->fontset != NULL){ 596 XFreeFontSet(dpy, font->fontset); 597 } 598 599 basename2 = malloc(strlen(font->name) + 3); 600 if (basename2) sprintf(basename2, "%s,*", font->name); 601 else basename2 = font->name; 602 if( (font->fontset = XCreateFontSet(dpy, basename2, 603 &missing_charset_list_return, 604 &missing_charset_count_return, 605 &def_string_return)) == NULL) { 606 fprintf (stderr, "%s: unable to open fontset \"%s\"\n", 607 ProgramName, font->name); 608 exit(1); 609 } 610 if (basename2 != font->name) free(basename2); 611 for(i=0; i<missing_charset_count_return; i++){ 612 printf("%s: warning: font for charset %s is lacking.\n", 613 ProgramName, missing_charset_list_return[i]); 614 } 615 616 font_extents = XExtentsOfFontSet(font->fontset); 617 fnum = XFontsOfFontSet(font->fontset, &xfonts, &font_names); 618 for( i = 0, ascent = 0, descent = 0; i<fnum; i++){ 619 if (ascent < (*xfonts)->ascent) ascent = (*xfonts)->ascent; 620 if (descent < (*xfonts)->descent) descent = (*xfonts)->descent; 621 xfonts++; 622 } 623 font->height = font_extents->max_logical_extent.height; 624 font->y = ascent; 625 font->ascent = ascent; 626 font->descent = descent; 627 return; 628 } 629 630 if (font->font != NULL) 631 XFreeFont(dpy, font->font); 632 633 if ((font->font = XLoadQueryFont(dpy, font->name)) == NULL) 634 { 635 if (Scr->DefaultFont.name) { 636 deffontname = Scr->DefaultFont.name; 637 } 638 if ((font->font = XLoadQueryFont(dpy, deffontname)) == NULL) 639 { 640 fprintf (stderr, "%s: unable to open fonts \"%s\" or \"%s\"\n", 641 ProgramName, font->name, deffontname); 642 exit(1); 643 } 644 645 } 646 font->height = font->font->ascent + font->font->descent; 647 font->y = font->font->ascent; 648 font->ascent = font->font->ascent; 649 font->descent = font->font->descent; 650} 651 652int 653MyFont_TextWidth(MyFont *font, const char *string, int len) 654{ 655 XRectangle ink_rect; 656 XRectangle logical_rect; 657 658 if (use_fontset) { 659 XmbTextExtents(font->fontset, string, len, 660 &ink_rect, &logical_rect); 661 return logical_rect.width; 662 } 663 return XTextWidth(font->font, string, len); 664} 665 666void 667MyFont_DrawImageString(Display *dpy, Drawable d, MyFont *font, GC gc, 668 int x, int y, const char *string, int len) 669{ 670 if (use_fontset) { 671 XmbDrawImageString(dpy, d, font->fontset, gc, x, y, string, len); 672 return; 673 } 674 XDrawImageString (dpy, d, gc, x, y, string, len); 675} 676 677void 678MyFont_DrawString(Display *dpy, Drawable d, MyFont *font, GC gc, 679 int x, int y, const char *string, int len) 680{ 681 if (use_fontset) { 682 XmbDrawString(dpy, d, font->fontset, gc, x, y, string, len); 683 return; 684 } 685 XDrawString (dpy, d, gc, x, y, string, len); 686} 687 688void 689MyFont_ChangeGC(unsigned long fix_fore, unsigned long fix_back, 690 MyFont *fix_font) 691{ 692 Gcv.foreground = fix_fore; 693 Gcv.background = fix_back; 694 if (use_fontset) { 695 XChangeGC(dpy, Scr->NormalGC, GCForeground|GCBackground, &Gcv); 696 return; 697 } 698 Gcv.font = fix_font->font->fid; 699 XChangeGC(dpy, Scr->NormalGC, GCFont|GCForeground|GCBackground,&Gcv); 700} 701 702/* 703 * The following functions are internationalized substitutions 704 * for XFetchName and XGetIconName using XGetWMName and 705 * XGetWMIconName. 706 * 707 * Please note that the third arguments have to be freed using free(), 708 * not XFree(). 709 */ 710Status 711I18N_FetchName(Display *dpy, Window w, char **winname) 712{ 713 int status; 714 XTextProperty text_prop; 715 char **list; 716 int num; 717 718 status = XGetWMName(dpy, w, &text_prop); 719 if (!status || !text_prop.value || !text_prop.nitems) { 720 *winname = NULL; 721 return 0; 722 } 723 status = XmbTextPropertyToTextList(dpy, &text_prop, &list, &num); 724 if (status < Success || !num || !*list) { 725 *winname = NULL; 726 return 0; 727 } 728 XFree(text_prop.value); 729 *winname = (char *)strdup(*list); 730 XFreeStringList(list); 731 return 1; 732} 733 734Status 735I18N_GetIconName(Display *dpy, Window w, char **iconname) 736{ 737 int status; 738 XTextProperty text_prop; 739 char **list; 740 int num; 741 742 status = XGetWMIconName(dpy, w, &text_prop); 743 if (!status || !text_prop.value || !text_prop.nitems) return 0; 744 status = XmbTextPropertyToTextList(dpy, &text_prop, &list, &num); 745 if (status < Success || !num || !*list) return 0; 746 XFree(text_prop.value); 747 *iconname = (char *)strdup(*list); 748 XFreeStringList(list); 749 return 1; 750} 751 752/** 753 * separate routine to set focus to make things more understandable 754 * and easier to debug 755 */ 756void 757SetFocus (TwmWindow *tmp_win, Time time) 758{ 759 Window w = (tmp_win ? tmp_win->w : PointerRoot); 760 761#ifdef TRACE 762 if (tmp_win) { 763 printf ("Focusing on window \"%s\"\n", tmp_win->full_name); 764 } else { 765 printf ("Unfocusing; Scr->Focus was \"%s\"\n", 766 Scr->Focus ? Scr->Focus->full_name : "(nil)"); 767 } 768#endif 769 770 XSetInputFocus (dpy, w, RevertToPointerRoot, time); 771} 772 773static Pixmap 774CreateXLogoPixmap (unsigned *widthp, unsigned *heightp) 775{ 776 int h = Scr->TBInfo.width - Scr->TBInfo.border * 2; 777 if (h < 0) h = 0; 778 779 *widthp = *heightp = (unsigned int) h; 780 if (Scr->tbpm.xlogo == None) { 781 GC gc, gcBack; 782 783 Scr->tbpm.xlogo = XCreatePixmap (dpy, Scr->Root, h, h, 1); 784 gc = XCreateGC (dpy, Scr->tbpm.xlogo, 0L, NULL); 785 XSetForeground (dpy, gc, 0); 786 XFillRectangle (dpy, Scr->tbpm.xlogo, gc, 0, 0, h, h); 787 XSetForeground (dpy, gc, 1); 788 gcBack = XCreateGC (dpy, Scr->tbpm.xlogo, 0L, NULL); 789 XSetForeground (dpy, gcBack, 0); 790 791 /* 792 * draw the logo large so that it gets as dense as possible; then white 793 * out the edges so that they look crisp 794 */ 795 XmuDrawLogo (dpy, Scr->tbpm.xlogo, gc, gcBack, -1, -1, h + 2, h + 2); 796 XDrawRectangle (dpy, Scr->tbpm.xlogo, gcBack, 0, 0, h - 1, h - 1); 797 798 /* 799 * done drawing 800 */ 801 XFreeGC (dpy, gc); 802 XFreeGC (dpy, gcBack); 803 } 804 return Scr->tbpm.xlogo; 805} 806 807 808static Pixmap 809CreateResizePixmap (unsigned *widthp, unsigned *heightp) 810{ 811 int h = Scr->TBInfo.width - Scr->TBInfo.border * 2; 812 if (h < 1) h = 1; 813 814 *widthp = *heightp = (unsigned int) h; 815 if (Scr->tbpm.resize == None) { 816 XPoint points[3]; 817 GC gc; 818 int w; 819 int lw; 820 821 /* 822 * create the pixmap 823 */ 824 Scr->tbpm.resize = XCreatePixmap (dpy, Scr->Root, h, h, 1); 825 gc = XCreateGC (dpy, Scr->tbpm.resize, 0L, NULL); 826 XSetForeground (dpy, gc, 0); 827 XFillRectangle (dpy, Scr->tbpm.resize, gc, 0, 0, h, h); 828 XSetForeground (dpy, gc, 1); 829 lw = h / 16; 830 if (lw == 1) 831 lw = 0; 832 XSetLineAttributes (dpy, gc, lw, LineSolid, CapButt, JoinMiter); 833 834 /* 835 * draw the resize button, 836 */ 837 w = (h * 2) / 3; 838 points[0].x = w; 839 points[0].y = 0; 840 points[1].x = w; 841 points[1].y = w; 842 points[2].x = 0; 843 points[2].y = w; 844 XDrawLines (dpy, Scr->tbpm.resize, gc, points, 3, CoordModeOrigin); 845 w = w / 2; 846 points[0].x = w; 847 points[0].y = 0; 848 points[1].x = w; 849 points[1].y = w; 850 points[2].x = 0; 851 points[2].y = w; 852 XDrawLines (dpy, Scr->tbpm.resize, gc, points, 3, CoordModeOrigin); 853 854 /* 855 * done drawing 856 */ 857 XFreeGC(dpy, gc); 858 } 859 return Scr->tbpm.resize; 860} 861 862 863static Pixmap 864CreateDotPixmap (unsigned *widthp, unsigned *heightp) 865{ 866 int h = Scr->TBInfo.width - Scr->TBInfo.border * 2; 867 868 h = h * 3 / 4; 869 if (h < 1) h = 1; 870 if (!(h & 1)) 871 h--; 872 *widthp = *heightp = (unsigned int) h; 873 if (Scr->tbpm.delete == None) { 874 GC gc; 875 Pixmap pix; 876 877 pix = Scr->tbpm.delete = XCreatePixmap (dpy, Scr->Root, h, h, 1); 878 gc = XCreateGC (dpy, pix, 0L, NULL); 879 XSetLineAttributes (dpy, gc, h, LineSolid, CapRound, JoinRound); 880 XSetForeground (dpy, gc, 0L); 881 XFillRectangle (dpy, pix, gc, 0, 0, h, h); 882 XSetForeground (dpy, gc, 1L); 883 XDrawLine (dpy, pix, gc, h/2, h/2, h/2, h/2); 884 XFreeGC (dpy, gc); 885 } 886 return Scr->tbpm.delete; 887} 888 889#define questionmark_width 8 890#define questionmark_height 8 891static char questionmark_bits[] = { 892 0x38, 0x7c, 0x64, 0x30, 0x18, 0x00, 0x18, 0x18}; 893 894static Pixmap 895CreateQuestionPixmap (unsigned *widthp, unsigned *heightp) 896{ 897 *widthp = questionmark_width; 898 *heightp = questionmark_height; 899 if (Scr->tbpm.question == None) { 900 Scr->tbpm.question = XCreateBitmapFromData (dpy, Scr->Root, 901 questionmark_bits, 902 questionmark_width, 903 questionmark_height); 904 } 905 /* 906 * this must succeed or else we are in deep trouble elsewhere 907 */ 908 return Scr->tbpm.question; 909} 910 911 912static Pixmap 913CreateMenuPixmap (unsigned *widthp, unsigned *heightp) 914{ 915 return CreateMenuIcon (Scr->TBInfo.width - Scr->TBInfo.border * 2, 916 widthp,heightp); 917} 918 919Pixmap 920CreateMenuIcon (int height, unsigned *widthp, unsigned *heightp) 921{ 922 int h, w; 923 int ih, iw; 924 int ix, iy; 925 int mh, mw; 926 int tw, th; 927 int lw, lh; 928 int lx, ly; 929 int lines, dly; 930 int off; 931 int bw; 932 933 h = height; 934 w = h * 7 / 8; 935 if (h < 1) 936 h = 1; 937 if (w < 1) 938 w = 1; 939 *widthp = w; 940 *heightp = h; 941 if (Scr->tbpm.menu == None) { 942 Pixmap pix; 943 GC gc; 944 945 pix = Scr->tbpm.menu = XCreatePixmap (dpy, Scr->Root, w, h, 1); 946 gc = XCreateGC (dpy, pix, 0L, NULL); 947 XSetForeground (dpy, gc, 0L); 948 XFillRectangle (dpy, pix, gc, 0, 0, w, h); 949 XSetForeground (dpy, gc, 1L); 950 ix = 1; 951 iy = 1; 952 ih = h - iy * 2; 953 iw = w - ix * 2; 954 off = ih / 8; 955 mh = ih - off; 956 mw = iw - off; 957 bw = mh / 16; 958 if (bw == 0 && mw > 2) 959 bw = 1; 960 tw = mw - bw * 2; 961 th = mh - bw * 2; 962 XFillRectangle (dpy, pix, gc, ix, iy, mw, mh); 963 XFillRectangle (dpy, pix, gc, ix + iw - mw, iy + ih - mh, mw, mh); 964 XSetForeground (dpy, gc, 0L); 965 XFillRectangle (dpy, pix, gc, ix+bw, iy+bw, tw, th); 966 XSetForeground (dpy, gc, 1L); 967 lw = tw / 2; 968 if ((tw & 1) ^ (lw & 1)) 969 lw++; 970 lx = ix + bw + (tw - lw) / 2; 971 972 lh = th / 2 - bw; 973 if ((lh & 1) ^ ((th - bw) & 1)) 974 lh++; 975 ly = iy + bw + (th - bw - lh) / 2; 976 977 lines = 3; 978 if ((lh & 1) && lh < 6) 979 { 980 lines--; 981 } 982 dly = lh / (lines - 1); 983 while (lines--) 984 { 985 XFillRectangle (dpy, pix, gc, lx, ly, lw, bw); 986 ly += dly; 987 } 988 XFreeGC (dpy, gc); 989 } 990 return Scr->tbpm.menu; 991} 992 993void 994Bell(int type, int percent, Window win) 995{ 996#ifdef XKB 997 XkbStdBell(dpy, win, percent, type); 998#else 999 XBell(dpy, percent); 1000#endif 1001 return; 1002} 1003