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