util.c revision 7a2631fc
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 = (char *) 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(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 (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 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 = (char *) malloc (strlen(name) + strlen(Scr->IconDirectory) + 358 2); 359 if (!bigname) { 360 fprintf (stderr, 361 "%s: unable to allocate memory for \"%s/%s\"\n", 362 ProgramName, Scr->IconDirectory, name); 363 return None; 364 } 365 (void) sprintf (bigname, "%s/%s", Scr->IconDirectory, name); 366 if (XReadBitmapFile (dpy, Scr->Root, bigname, widthp, heightp, &pm, 367 &HotX, &HotY) != BitmapSuccess) { 368 pm = None; 369 } 370 } 371 if (bigname != name) free (bigname); 372 if (pm == None) { 373 fprintf (stderr, "%s: unable to find bitmap \"%s\"\n", 374 ProgramName, name); 375 } 376 377 return pm; 378} 379 380Pixmap 381GetBitmap (char *name) 382{ 383 return FindBitmap (name, &JunkWidth, &JunkHeight); 384} 385 386void 387InsertRGBColormap (Atom a, XStandardColormap *maps, int nmaps, Bool replace) 388{ 389 StdCmap *sc = NULL; 390 391 if (replace) { /* locate existing entry */ 392 for (sc = Scr->StdCmapInfo.head; sc; sc = sc->next) { 393 if (sc->atom == a) break; 394 } 395 } 396 397 if (!sc) { /* no existing, allocate new */ 398 sc = (StdCmap *) malloc (sizeof (StdCmap)); 399 if (!sc) { 400 fprintf (stderr, "%s: unable to allocate %ld bytes for StdCmap\n", 401 ProgramName, (unsigned long)sizeof (StdCmap)); 402 return; 403 } 404 } 405 406 if (replace) { /* just update contents */ 407 if (sc->maps) XFree ((char *) maps); 408 if (sc == Scr->StdCmapInfo.mru) Scr->StdCmapInfo.mru = NULL; 409 } else { /* else appending */ 410 sc->next = NULL; 411 sc->atom = a; 412 if (Scr->StdCmapInfo.tail) { 413 Scr->StdCmapInfo.tail->next = sc; 414 } else { 415 Scr->StdCmapInfo.head = sc; 416 } 417 Scr->StdCmapInfo.tail = sc; 418 } 419 sc->nmaps = nmaps; 420 sc->maps = maps; 421 422 return; 423} 424 425void 426RemoveRGBColormap (Atom a) 427{ 428 StdCmap *sc, *prev; 429 430 prev = NULL; 431 for (sc = Scr->StdCmapInfo.head; sc; sc = sc->next) { 432 if (sc->atom == a) break; 433 prev = sc; 434 } 435 if (sc) { /* found one */ 436 if (sc->maps) XFree ((char *) sc->maps); 437 if (prev) prev->next = sc->next; 438 if (Scr->StdCmapInfo.head == sc) Scr->StdCmapInfo.head = sc->next; 439 if (Scr->StdCmapInfo.tail == sc) Scr->StdCmapInfo.tail = prev; 440 if (Scr->StdCmapInfo.mru == sc) Scr->StdCmapInfo.mru = NULL; 441 } 442 return; 443} 444 445void 446LocateStandardColormaps() 447{ 448 Atom *atoms; 449 int natoms; 450 int i; 451 452 atoms = XListProperties (dpy, Scr->Root, &natoms); 453 for (i = 0; i < natoms; i++) { 454 XStandardColormap *maps = NULL; 455 int nmaps; 456 457 if (XGetRGBColormaps (dpy, Scr->Root, &maps, &nmaps, atoms[i])) { 458 /* if got one, then append to current list */ 459 InsertRGBColormap (atoms[i], maps, nmaps, False); 460 } 461 } 462 if (atoms) XFree ((char *) atoms); 463 return; 464} 465 466void 467GetColor(int kind, Pixel *what, char *name) 468{ 469 XColor color, junkcolor; 470 Status stat = 0; 471 Colormap cmap = Scr->TwmRoot.cmaps.cwins[0]->colormap->c; 472 473#ifndef TOM 474 if (!Scr->FirstTime) 475 return; 476#endif 477 478 if (Scr->Monochrome != kind) 479 return; 480 481 if (!XAllocNamedColor (dpy, cmap, name, &color, &junkcolor)) 482 { 483 /* if we could not allocate the color, let's see if this is a 484 * standard colormap 485 */ 486 XStandardColormap *stdcmap = NULL; 487 488 /* parse the named color */ 489 if (name[0] != '#') 490 stat = XParseColor (dpy, cmap, name, &color); 491 if (!stat) 492 { 493 fprintf (stderr, "%s: invalid color name \"%s\"\n", 494 ProgramName, name); 495 return; 496 } 497 498 /* 499 * look through the list of standard colormaps (check cache first) 500 */ 501 if (Scr->StdCmapInfo.mru && Scr->StdCmapInfo.mru->maps && 502 (Scr->StdCmapInfo.mru->maps[Scr->StdCmapInfo.mruindex].colormap == 503 cmap)) { 504 stdcmap = &(Scr->StdCmapInfo.mru->maps[Scr->StdCmapInfo.mruindex]); 505 } else { 506 StdCmap *sc; 507 508 for (sc = Scr->StdCmapInfo.head; sc; sc = sc->next) { 509 int i; 510 511 for (i = 0; i < sc->nmaps; i++) { 512 if (sc->maps[i].colormap == cmap) { 513 Scr->StdCmapInfo.mru = sc; 514 Scr->StdCmapInfo.mruindex = i; 515 stdcmap = &(sc->maps[i]); 516 goto gotit; 517 } 518 } 519 } 520 } 521 522 gotit: 523 if (stdcmap) { 524 color.pixel = (stdcmap->base_pixel + 525 ((Pixel)(((float)color.red / 65535.0) * 526 stdcmap->red_max + 0.5) * 527 stdcmap->red_mult) + 528 ((Pixel)(((float)color.green /65535.0) * 529 stdcmap->green_max + 0.5) * 530 stdcmap->green_mult) + 531 ((Pixel)(((float)color.blue / 65535.0) * 532 stdcmap->blue_max + 0.5) * 533 stdcmap->blue_mult)); 534 } else { 535 fprintf (stderr, "%s: unable to allocate color \"%s\"\n", 536 ProgramName, name); 537 return; 538 } 539 } 540 541 *what = color.pixel; 542} 543 544void 545GetColorValue(int kind, XColor *what, char *name) 546{ 547 XColor junkcolor; 548 Colormap cmap = Scr->TwmRoot.cmaps.cwins[0]->colormap->c; 549 550#ifndef TOM 551 if (!Scr->FirstTime) 552 return; 553#endif 554 555 if (Scr->Monochrome != kind) 556 return; 557 558 if (!XLookupColor (dpy, cmap, name, what, &junkcolor)) 559 { 560 fprintf (stderr, "%s: invalid color name \"%s\"\n", 561 ProgramName, name); 562 } 563 else 564 { 565 what->pixel = AllPlanes; 566 } 567} 568 569/* 570 * The following functions are sensible to 'use_fontset'. 571 * When 'use_fontset' is True, 572 * - XFontSet-related internationalized functions are used 573 * so as multibyte languages can be displayed. 574 * When 'use_fontset' is False, 575 * - XFontStruct-related conventional functions are used 576 * so as 8-bit characters can be displayed even when 577 * locale is not set properly. 578 */ 579void 580GetFont(MyFont *font) 581{ 582 char *deffontname = "fixed"; 583 char **missing_charset_list_return; 584 int missing_charset_count_return; 585 char *def_string_return; 586 XFontSetExtents *font_extents; 587 XFontStruct **xfonts; 588 char **font_names; 589 register int i; 590 int ascent; 591 int descent; 592 int fnum; 593 char *basename2; 594 595 if (use_fontset) { 596 if (font->fontset != NULL){ 597 XFreeFontSet(dpy, font->fontset); 598 } 599 600 basename2 = (char *)malloc(strlen(font->name) + 3); 601 if (basename2) sprintf(basename2, "%s,*", font->name); 602 else basename2 = font->name; 603 if( (font->fontset = XCreateFontSet(dpy, basename2, 604 &missing_charset_list_return, 605 &missing_charset_count_return, 606 &def_string_return)) == NULL) { 607 fprintf (stderr, "%s: unable to open fontset \"%s\"\n", 608 ProgramName, font->name); 609 exit(1); 610 } 611 if (basename2 != font->name) free(basename2); 612 for(i=0; i<missing_charset_count_return; i++){ 613 printf("%s: warning: font for charset %s is lacking.\n", 614 ProgramName, missing_charset_list_return[i]); 615 } 616 617 font_extents = XExtentsOfFontSet(font->fontset); 618 fnum = XFontsOfFontSet(font->fontset, &xfonts, &font_names); 619 for( i = 0, ascent = 0, descent = 0; i<fnum; i++){ 620 if (ascent < (*xfonts)->ascent) ascent = (*xfonts)->ascent; 621 if (descent < (*xfonts)->descent) descent = (*xfonts)->descent; 622 xfonts++; 623 } 624 font->height = font_extents->max_logical_extent.height; 625 font->y = ascent; 626 font->ascent = ascent; 627 font->descent = descent; 628 return; 629 } 630 631 if (font->font != NULL) 632 XFreeFont(dpy, font->font); 633 634 if ((font->font = XLoadQueryFont(dpy, font->name)) == NULL) 635 { 636 if (Scr->DefaultFont.name) { 637 deffontname = Scr->DefaultFont.name; 638 } 639 if ((font->font = XLoadQueryFont(dpy, deffontname)) == NULL) 640 { 641 fprintf (stderr, "%s: unable to open fonts \"%s\" or \"%s\"\n", 642 ProgramName, font->name, deffontname); 643 exit(1); 644 } 645 646 } 647 font->height = font->font->ascent + font->font->descent; 648 font->y = font->font->ascent; 649 font->ascent = font->font->ascent; 650 font->descent = font->font->descent; 651} 652 653int 654MyFont_TextWidth(MyFont *font, char *string, int len) 655{ 656 XRectangle ink_rect; 657 XRectangle logical_rect; 658 659 if (use_fontset) { 660 XmbTextExtents(font->fontset, string, len, 661 &ink_rect, &logical_rect); 662 return logical_rect.width; 663 } 664 return XTextWidth(font->font, string, len); 665} 666 667void 668MyFont_DrawImageString(Display *dpy, Drawable d, MyFont *font, GC gc, 669 int x, int y, char *string, int len) 670{ 671 if (use_fontset) { 672 XmbDrawImageString(dpy, d, font->fontset, gc, x, y, string, len); 673 return; 674 } 675 XDrawImageString (dpy, d, gc, x, y, string, len); 676} 677 678void 679MyFont_DrawString(Display *dpy, Drawable d, MyFont *font, GC gc, 680 int x, int y, char *string, int len) 681{ 682 if (use_fontset) { 683 XmbDrawString(dpy, d, font->fontset, gc, x, y, string, len); 684 return; 685 } 686 XDrawString (dpy, d, gc, x, y, string, len); 687} 688 689void 690MyFont_ChangeGC(unsigned long fix_fore, unsigned long fix_back, 691 MyFont *fix_font) 692{ 693 Gcv.foreground = fix_fore; 694 Gcv.background = fix_back; 695 if (use_fontset) { 696 XChangeGC(dpy, Scr->NormalGC, GCForeground|GCBackground, &Gcv); 697 return; 698 } 699 Gcv.font = fix_font->font->fid; 700 XChangeGC(dpy, Scr->NormalGC, GCFont|GCForeground|GCBackground,&Gcv); 701} 702 703/* 704 * The following functions are internationalized substitutions 705 * for XFetchName and XGetIconName using XGetWMName and 706 * XGetWMIconName. 707 * 708 * Please note that the third arguments have to be freed using free(), 709 * not XFree(). 710 */ 711Status 712I18N_FetchName(Display *dpy, Window w, char **winname) 713{ 714 int status; 715 XTextProperty text_prop; 716 char **list; 717 int num; 718 719 status = XGetWMName(dpy, w, &text_prop); 720 if (!status || !text_prop.value || !text_prop.nitems) { 721 *winname = NULL; 722 return 0; 723 } 724 status = XmbTextPropertyToTextList(dpy, &text_prop, &list, &num); 725 if (status < Success || !num || !*list) { 726 *winname = NULL; 727 return 0; 728 } 729 XFree(text_prop.value); 730 *winname = (char *)strdup(*list); 731 XFreeStringList(list); 732 return 1; 733} 734 735Status 736I18N_GetIconName(Display *dpy, Window w, char **iconname) 737{ 738 int status; 739 XTextProperty text_prop; 740 char **list; 741 int num; 742 743 status = XGetWMIconName(dpy, w, &text_prop); 744 if (!status || !text_prop.value || !text_prop.nitems) return 0; 745 status = XmbTextPropertyToTextList(dpy, &text_prop, &list, &num); 746 if (status < Success || !num || !*list) return 0; 747 XFree(text_prop.value); 748 *iconname = (char *)strdup(*list); 749 XFreeStringList(list); 750 return 1; 751} 752 753/** 754 * separate routine to set focus to make things more understandable 755 * and easier to debug 756 */ 757void 758SetFocus (TwmWindow *tmp_win, Time time) 759{ 760 Window w = (tmp_win ? tmp_win->w : PointerRoot); 761 762#ifdef TRACE 763 if (tmp_win) { 764 printf ("Focusing on window \"%s\"\n", tmp_win->full_name); 765 } else { 766 printf ("Unfocusing; Scr->Focus was \"%s\"\n", 767 Scr->Focus ? Scr->Focus->full_name : "(nil)"); 768 } 769#endif 770 771 XSetInputFocus (dpy, w, RevertToPointerRoot, time); 772} 773 774 775#ifdef NOPUTENV 776/** 777 * define our own putenv() if the system doesn't have one. 778 * putenv(s): place s (a string of the form "NAME=value") in 779 * the environment; replacing any existing NAME. s is placed in 780 * environment, so if you change s, the environment changes (like 781 * putenv on a sun). Binding removed if you putenv something else 782 * called NAME. 783 */ 784int 785putenv(char *s) 786{ 787 char *v; 788 int varlen, idx; 789 extern char **environ; 790 char **newenv; 791 static int virgin = 1; /* true while "environ" is a virgin */ 792 793 v = index(s, '='); 794 if(v == 0) 795 return 0; /* punt if it's not of the right form */ 796 varlen = (v + 1) - s; 797 798 for (idx = 0; environ[idx] != 0; idx++) { 799 if (strncmp(environ[idx], s, varlen) == 0) { 800 if(v[1] != 0) { /* true if there's a value */ 801 environ[idx] = s; 802 return 0; 803 } else { 804 do { 805 environ[idx] = environ[idx+1]; 806 } while(environ[++idx] != 0); 807 return 0; 808 } 809 } 810 } 811 812 /* add to environment (unless no value; then just return) */ 813 if(v[1] == 0) 814 return 0; 815 if(virgin) { 816 register i; 817 818 newenv = (char **) malloc((unsigned) ((idx + 2) * sizeof(char*))); 819 if(newenv == 0) 820 return -1; 821 for(i = idx-1; i >= 0; --i) 822 newenv[i] = environ[i]; 823 virgin = 0; /* you're not a virgin anymore, sweety */ 824 } else { 825 newenv = (char **) realloc((char *) environ, 826 (unsigned) ((idx + 2) * sizeof(char*))); 827 if (newenv == 0) 828 return -1; 829 } 830 831 environ = newenv; 832 environ[idx] = s; 833 environ[idx+1] = 0; 834 835 return 0; 836} 837#endif /* NOPUTENV */ 838 839 840static Pixmap 841CreateXLogoPixmap (unsigned *widthp, unsigned *heightp) 842{ 843 int h = Scr->TBInfo.width - Scr->TBInfo.border * 2; 844 if (h < 0) h = 0; 845 846 *widthp = *heightp = (unsigned int) h; 847 if (Scr->tbpm.xlogo == None) { 848 GC gc, gcBack; 849 850 Scr->tbpm.xlogo = XCreatePixmap (dpy, Scr->Root, h, h, 1); 851 gc = XCreateGC (dpy, Scr->tbpm.xlogo, 0L, NULL); 852 XSetForeground (dpy, gc, 0); 853 XFillRectangle (dpy, Scr->tbpm.xlogo, gc, 0, 0, h, h); 854 XSetForeground (dpy, gc, 1); 855 gcBack = XCreateGC (dpy, Scr->tbpm.xlogo, 0L, NULL); 856 XSetForeground (dpy, gcBack, 0); 857 858 /* 859 * draw the logo large so that it gets as dense as possible; then white 860 * out the edges so that they look crisp 861 */ 862 XmuDrawLogo (dpy, Scr->tbpm.xlogo, gc, gcBack, -1, -1, h + 2, h + 2); 863 XDrawRectangle (dpy, Scr->tbpm.xlogo, gcBack, 0, 0, h - 1, h - 1); 864 865 /* 866 * done drawing 867 */ 868 XFreeGC (dpy, gc); 869 XFreeGC (dpy, gcBack); 870 } 871 return Scr->tbpm.xlogo; 872} 873 874 875static Pixmap 876CreateResizePixmap (unsigned *widthp, unsigned *heightp) 877{ 878 int h = Scr->TBInfo.width - Scr->TBInfo.border * 2; 879 if (h < 1) h = 1; 880 881 *widthp = *heightp = (unsigned int) h; 882 if (Scr->tbpm.resize == None) { 883 XPoint points[3]; 884 GC gc; 885 int w; 886 int lw; 887 888 /* 889 * create the pixmap 890 */ 891 Scr->tbpm.resize = XCreatePixmap (dpy, Scr->Root, h, 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, h, h); 895 XSetForeground (dpy, gc, 1); 896 lw = h / 16; 897 if (lw == 1) 898 lw = 0; 899 XSetLineAttributes (dpy, gc, lw, LineSolid, CapButt, JoinMiter); 900 901 /* 902 * draw the resize button, 903 */ 904 w = (h * 2) / 3; 905 points[0].x = w; 906 points[0].y = 0; 907 points[1].x = w; 908 points[1].y = w; 909 points[2].x = 0; 910 points[2].y = w; 911 XDrawLines (dpy, Scr->tbpm.resize, gc, points, 3, CoordModeOrigin); 912 w = w / 2; 913 points[0].x = w; 914 points[0].y = 0; 915 points[1].x = w; 916 points[1].y = w; 917 points[2].x = 0; 918 points[2].y = w; 919 XDrawLines (dpy, Scr->tbpm.resize, gc, points, 3, CoordModeOrigin); 920 921 /* 922 * done drawing 923 */ 924 XFreeGC(dpy, gc); 925 } 926 return Scr->tbpm.resize; 927} 928 929 930static Pixmap 931CreateDotPixmap (unsigned *widthp, unsigned *heightp) 932{ 933 int h = Scr->TBInfo.width - Scr->TBInfo.border * 2; 934 935 h = h * 3 / 4; 936 if (h < 1) h = 1; 937 if (!(h & 1)) 938 h--; 939 *widthp = *heightp = (unsigned int) h; 940 if (Scr->tbpm.delete == None) { 941 GC gc; 942 Pixmap pix; 943 944 pix = Scr->tbpm.delete = XCreatePixmap (dpy, Scr->Root, h, h, 1); 945 gc = XCreateGC (dpy, pix, 0L, NULL); 946 XSetLineAttributes (dpy, gc, h, LineSolid, CapRound, JoinRound); 947 XSetForeground (dpy, gc, 0L); 948 XFillRectangle (dpy, pix, gc, 0, 0, h, h); 949 XSetForeground (dpy, gc, 1L); 950 XDrawLine (dpy, pix, gc, h/2, h/2, h/2, h/2); 951 XFreeGC (dpy, gc); 952 } 953 return Scr->tbpm.delete; 954} 955 956#define questionmark_width 8 957#define questionmark_height 8 958static char questionmark_bits[] = { 959 0x38, 0x7c, 0x64, 0x30, 0x18, 0x00, 0x18, 0x18}; 960 961static Pixmap 962CreateQuestionPixmap (unsigned *widthp, unsigned *heightp) 963{ 964 *widthp = questionmark_width; 965 *heightp = questionmark_height; 966 if (Scr->tbpm.question == None) { 967 Scr->tbpm.question = XCreateBitmapFromData (dpy, Scr->Root, 968 questionmark_bits, 969 questionmark_width, 970 questionmark_height); 971 } 972 /* 973 * this must succeed or else we are in deep trouble elsewhere 974 */ 975 return Scr->tbpm.question; 976} 977 978 979static Pixmap 980CreateMenuPixmap (unsigned *widthp, unsigned *heightp) 981{ 982 return CreateMenuIcon (Scr->TBInfo.width - Scr->TBInfo.border * 2, 983 widthp,heightp); 984} 985 986Pixmap 987CreateMenuIcon (int height, unsigned *widthp, unsigned *heightp) 988{ 989 int h, w; 990 int ih, iw; 991 int ix, iy; 992 int mh, mw; 993 int tw, th; 994 int lw, lh; 995 int lx, ly; 996 int lines, dly; 997 int off; 998 int bw; 999 1000 h = height; 1001 w = h * 7 / 8; 1002 if (h < 1) 1003 h = 1; 1004 if (w < 1) 1005 w = 1; 1006 *widthp = w; 1007 *heightp = h; 1008 if (Scr->tbpm.menu == None) { 1009 Pixmap pix; 1010 GC gc; 1011 1012 pix = Scr->tbpm.menu = XCreatePixmap (dpy, Scr->Root, w, h, 1); 1013 gc = XCreateGC (dpy, pix, 0L, NULL); 1014 XSetForeground (dpy, gc, 0L); 1015 XFillRectangle (dpy, pix, gc, 0, 0, w, h); 1016 XSetForeground (dpy, gc, 1L); 1017 ix = 1; 1018 iy = 1; 1019 ih = h - iy * 2; 1020 iw = w - ix * 2; 1021 off = ih / 8; 1022 mh = ih - off; 1023 mw = iw - off; 1024 bw = mh / 16; 1025 if (bw == 0 && mw > 2) 1026 bw = 1; 1027 tw = mw - bw * 2; 1028 th = mh - bw * 2; 1029 XFillRectangle (dpy, pix, gc, ix, iy, mw, mh); 1030 XFillRectangle (dpy, pix, gc, ix + iw - mw, iy + ih - mh, mw, mh); 1031 XSetForeground (dpy, gc, 0L); 1032 XFillRectangle (dpy, pix, gc, ix+bw, iy+bw, tw, th); 1033 XSetForeground (dpy, gc, 1L); 1034 lw = tw / 2; 1035 if ((tw & 1) ^ (lw & 1)) 1036 lw++; 1037 lx = ix + bw + (tw - lw) / 2; 1038 1039 lh = th / 2 - bw; 1040 if ((lh & 1) ^ ((th - bw) & 1)) 1041 lh++; 1042 ly = iy + bw + (th - bw - lh) / 2; 1043 1044 lines = 3; 1045 if ((lh & 1) && lh < 6) 1046 { 1047 lines--; 1048 } 1049 dly = lh / (lines - 1); 1050 while (lines--) 1051 { 1052 XFillRectangle (dpy, pix, gc, lx, ly, lw, bw); 1053 ly += dly; 1054 } 1055 XFreeGC (dpy, gc); 1056 } 1057 return Scr->tbpm.menu; 1058} 1059 1060void 1061Bell(int type, int percent, Window win) 1062{ 1063#ifdef XKB 1064 XkbStdBell(dpy, win, percent, type); 1065#else 1066 XBell(dpy, percent); 1067#endif 1068 return; 1069} 1070