1 /*****************************************************************************/
2 /** Copyright 1988 by Evans & Sutherland Computer Corporation, **/
3 /** Salt Lake City, Utah **/
4 /** Portions Copyright 1989 by the Massachusetts Institute of Technology **/
5 /** Cambridge, Massachusetts **/
6 /** **/
7 /** All Rights Reserved **/
8 /** **/
9 /** Permission to use, copy, modify, and distribute this software and **/
10 /** its documentation for any purpose and without fee is hereby **/
11 /** granted, provided that the above copyright notice appear in all **/
12 /** copies and that both that copyright notice and this permis- **/
13 /** sion notice appear in supporting documentation, and that the **/
14 /** names of Evans & Sutherland and M.I.T. not be used in advertising **/
15 /** in publicity pertaining to distribution of the software without **/
16 /** specific, written prior permission. **/
17 /** **/
18 /** EVANS & SUTHERLAND AND M.I.T. DISCLAIM ALL WARRANTIES WITH REGARD **/
19 /** TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANT- **/
20 /** ABILITY AND FITNESS, IN NO EVENT SHALL EVANS & SUTHERLAND OR **/
21 /** M.I.T. BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAM- **/
22 /** AGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA **/
23 /** OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER **/
24 /** TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE **/
25 /** OR PERFORMANCE OF THIS SOFTWARE. **/
26 /*****************************************************************************/
27
28
29 /***********************************************************************
30 *
31 * $XConsortium: util.c,v 1.47 91/07/14 13:40:37 rws Exp $
32 *
33 * utility routines for twm
34 *
35 * 28-Oct-87 Thomas E. LaStrange File created
36 *
37 ***********************************************************************/
38
39 #include "twm.h"
40 #include "util.h"
41 #include "gram.h"
42 #include "screen.h"
43 #include <X11/Xos.h>
44 #include <X11/Xatom.h>
45 #include <stdio.h>
46 #include <X11/Xmu/Drawing.h>
47 #include <X11/Xmu/CharSet.h> /* for XmuCompareISOLatin1() */
48
49 static Pixmap CreateXLogoPixmap(), CreateResizePixmap();
50 static Pixmap CreateQuestionPixmap(), CreateMenuPixmap();
51 static Pixmap CreateDotPixmap();
52 int HotX, HotY;
53
54 /***********************************************************************
55 *
56 * Procedure:
57 * MoveOutline - move a window outline
58 *
59 * Inputs:
60 * root - the window we are outlining
61 * x - upper left x coordinate
62 * y - upper left y coordinate
63 * width - the width of the rectangle
64 * height - the height of the rectangle
65 * bw - the border width of the frame
66 * th - title height
67 *
68 ***********************************************************************
69 */
70
71 /* ARGSUSED */
MoveOutline(root,x,y,width,height,bw,th)72 void MoveOutline(root, x, y, width, height, bw, th)
73 Window root;
74 int x, y, width, height, bw, th;
75 {
76 static Window lastRoot;
77 static int lastx = 0;
78 static int lasty = 0;
79 static int lastWidth = 0;
80 static int lastHeight = 0;
81 static int lastBW = 0;
82 static int lastTH = 0;
83 int xl, xr, yt, yb, xinnerl, xinnerr, yinnert, yinnerb;
84 int xthird, ythird;
85 XSegment outline[18];
86 register XSegment *r;
87
88 if (x == lastx && y == lasty && width == lastWidth && height == lastHeight
89 && lastBW == bw && th == lastTH)
90 return;
91
92 if (root == None)
93 root = lastRoot;
94 lastRoot = root;
95 r = outline;
96
97 #define DRAWIT() \
98 if (lastWidth || lastHeight) \
99 { \
100 xl = lastx; \
101 xr = lastx + lastWidth - 1; \
102 yt = lasty; \
103 yb = lasty + lastHeight - 1; \
104 xinnerl = xl + lastBW; \
105 xinnerr = xr - lastBW; \
106 yinnert = yt + lastTH + lastBW; \
107 yinnerb = yb - lastBW; \
108 xthird = (xinnerr - xinnerl) / 3; \
109 ythird = (yinnerb - yinnert) / 3; \
110 \
111 r->x1 = xl; \
112 r->y1 = yt; \
113 r->x2 = xr; \
114 r->y2 = yt; \
115 r++; \
116 \
117 r->x1 = xl; \
118 r->y1 = yb; \
119 r->x2 = xr; \
120 r->y2 = yb; \
121 r++; \
122 \
123 r->x1 = xl; \
124 r->y1 = yt; \
125 r->x2 = xl; \
126 r->y2 = yb; \
127 r++; \
128 \
129 r->x1 = xr; \
130 r->y1 = yt; \
131 r->x2 = xr; \
132 r->y2 = yb; \
133 r++; \
134 \
135 r->x1 = xinnerl + xthird; \
136 r->y1 = yinnert; \
137 r->x2 = r->x1; \
138 r->y2 = yinnerb; \
139 r++; \
140 \
141 r->x1 = xinnerl + (2 * xthird); \
142 r->y1 = yinnert; \
143 r->x2 = r->x1; \
144 r->y2 = yinnerb; \
145 r++; \
146 \
147 r->x1 = xinnerl; \
148 r->y1 = yinnert + ythird; \
149 r->x2 = xinnerr; \
150 r->y2 = r->y1; \
151 r++; \
152 \
153 r->x1 = xinnerl; \
154 r->y1 = yinnert + (2 * ythird); \
155 r->x2 = xinnerr; \
156 r->y2 = r->y1; \
157 r++; \
158 \
159 if (lastTH != 0) { \
160 r->x1 = xl; \
161 r->y1 = yt + lastTH; \
162 r->x2 = xr; \
163 r->y2 = r->y1; \
164 r++; \
165 } \
166 }
167
168 /* undraw the old one, if any */
169 DRAWIT ();
170
171 lastx = x;
172 lasty = y;
173 lastWidth = width;
174 lastHeight = height;
175 lastBW = bw;
176 lastTH = th;
177
178 /* draw the new one, if any */
179 DRAWIT ();
180
181 #undef DRAWIT
182
183
184 if (r != outline)
185 {
186 XDrawSegments(dpy, root, Scr->DrawGC, outline, r - outline);
187 }
188 }
189
190 /***********************************************************************
191 *
192 * Procedure:
193 * Zoom - zoom in or out of an icon
194 *
195 * Inputs:
196 * wf - window to zoom from
197 * wt - window to zoom to
198 *
199 ***********************************************************************
200 */
201
202 void
Zoom(wf,wt)203 Zoom(wf, wt)
204 Window wf, wt;
205 {
206 int fx, fy, tx, ty; /* from, to */
207 unsigned int fw, fh, tw, th; /* from, to */
208 long dx, dy, dw, dh;
209 long z;
210 int j;
211
212 if (!Scr->DoZoom || Scr->ZoomCount < 1) return;
213
214 if (wf == None || wt == None) return;
215
216 XGetGeometry (dpy, wf, &JunkRoot, &fx, &fy, &fw, &fh, &JunkBW, &JunkDepth);
217 XGetGeometry (dpy, wt, &JunkRoot, &tx, &ty, &tw, &th, &JunkBW, &JunkDepth);
218
219 dx = ((long) (tx - fx)); /* going from -> to */
220 dy = ((long) (ty - fy)); /* going from -> to */
221 dw = ((long) (tw - fw)); /* going from -> to */
222 dh = ((long) (th - fh)); /* going from -> to */
223 z = (long) (Scr->ZoomCount + 1);
224
225 for (j = 0; j < 2; j++) {
226 long i;
227
228 XDrawRectangle (dpy, Scr->Root, Scr->DrawGC, fx, fy, fw, fh);
229 for (i = 1; i < z; i++) {
230 int x = fx + (int) ((dx * i) / z);
231 int y = fy + (int) ((dy * i) / z);
232 unsigned width = (unsigned) (((long) fw) + (dw * i) / z);
233 unsigned height = (unsigned) (((long) fh) + (dh * i) / z);
234
235 XDrawRectangle (dpy, Scr->Root, Scr->DrawGC,
236 x, y, width, height);
237 }
238 XDrawRectangle (dpy, Scr->Root, Scr->DrawGC, tx, ty, tw, th);
239 }
240 }
241
242
243 /***********************************************************************
244 *
245 * Procedure:
246 * ExpandFilename - expand the tilde character to HOME
247 * if it is the first character of the filename
248 *
249 * Returned Value:
250 * a pointer to the new name
251 *
252 * Inputs:
253 * name - the filename to expand
254 *
255 ***********************************************************************
256 */
257
258 char *
ExpandFilename(name)259 ExpandFilename(name)
260 char *name;
261 {
262 char *newname;
263
264 if (name[0] != '~') return name;
265
266 newname = (char *) malloc (HomeLen + strlen(name) + 2);
267 if (!newname) {
268 fprintf (stderr,
269 "%s: unable to allocate %d bytes to expand filename %s/%s\n",
270 ProgramName, HomeLen + strlen(name) + 2, Home, &name[1]);
271 } else {
272 (void) sprintf (newname, "%s/%s", Home, &name[1]);
273 }
274
275 return newname;
276 }
277
278 /***********************************************************************
279 *
280 * Procedure:
281 * FindPixmap - read in a bitmap file and return size
282 *
283 * Returned Value:
284 * the pixmap associated with the bitmap
285 * widthp - pointer to width of bitmap
286 * heightp - pointer to height of bitmap
287 * isXpm - pointer to an Boolean that says whether it's an Xpm
288 * pixmap or not. Used ifdef XPM.
289 * bg_color - pointer to a Pixel (unsigned long) which is the background
290 * color of the pixmap (for an Xpm). Actually, it's just the
291 * first color in the pixel list, so it's not neccessarily
292 * the "real" background color. Can be passed as NULL. Used
293 * ifdef XPM.
294 * colors - a list of XpmColorSymbol structures containing information
295 * to translate the colors in a bitmap/pixmap file into the colors
296 * that you want for the pixmap returned.
297 * numcolors - number of entries in the above list
298 * shape_mask - pointer to a Pixmap where will be returned the shape
299 * mask of the Pixmap, if XpmReadFileToPixmap returns such.
300 *
301 * Inputs:
302 * name - the filename to read
303 *
304 ***********************************************************************
305 */
306
307 extern int XmuCompareISOLatin1();
308
FindPixmap(name,widthp,heightp,isXpm,bg_color,colors,numcolors,shape_mask)309 Pixmap FindPixmap (name, widthp, heightp, isXpm, bg_color, colors,
310 numcolors, shape_mask)
311 char *name;
312 unsigned int *widthp, *heightp;
313 Bool *isXpm;
314 Pixel *bg_color;
315 #ifdef XPM
316 XpmColorSymbol *colors;
317 #else
318 char *colors;
319 #endif
320 int numcolors;
321 Pixmap *shape_mask;
322 {
323 char *bigname;
324 Pixmap pm;
325 #ifdef XPM
326 int XPMret;
327 XpmAttributes attribs;
328 #endif /* XPM */
329
330 *isXpm = False;
331 if (shape_mask)
332 *shape_mask = None;
333 #ifdef XPM
334 if (numcolors) {
335 attribs.valuemask = XpmColorSymbols;
336 attribs.colorsymbols = colors;
337 attribs.numsymbols = numcolors;
338 } else
339 attribs.valuemask = 0;
340 #endif
341
342 if (!name) return None;
343
344 /*
345 * Names of the form :name refer to hardcoded images that are scaled to
346 * look nice in title buttons. Eventually, it would be nice to put in a
347 * menu symbol as well....
348 */
349 if (name[0] == ':') {
350 int i;
351 static struct {
352 char *name;
353 Pixmap (*proc)();
354 } pmtab[] = {
355 { TBPM_DOT, CreateDotPixmap },
356 { TBPM_ICONIFY, CreateDotPixmap },
357 { TBPM_RESIZE, CreateResizePixmap },
358 { TBPM_XLOGO, CreateXLogoPixmap },
359 { TBPM_DELETE, CreateXLogoPixmap },
360 { TBPM_MENU, CreateMenuPixmap },
361 { TBPM_QUESTION, CreateQuestionPixmap },
362 };
363
364 for (i = 0; i < (sizeof pmtab)/(sizeof pmtab[0]); i++) {
365 if (XmuCompareISOLatin1 (pmtab[i].name, name) == 0)
366 return (*pmtab[i].proc) (widthp, heightp);
367 }
368 fprintf (stderr, "%s: no such built-in bitmap \"%s\"\n",
369 ProgramName, name);
370 return None;
371 }
372
373 if (name[0] == '#') {
374 /* cursor font glyph */
375
376 if (bg_color)
377 *bg_color = BlackPixel(dpy, Scr->screen);
378
379 return GetCursorGlyph(name+1, widthp, heightp, shape_mask);
380 }
381
382 /*
383 * Generate a full pathname if any special prefix characters (such as ~)
384 * are used. If the bigname is different from name, bigname will need to
385 * be freed.
386 */
387 bigname = ExpandFilename (name);
388 if (!bigname) return None;
389
390 /*
391 * look along bitmapFilePath resource same as toolkit clients
392 */
393 #ifdef XPM
394 attribs.valuemask = XpmVisual | XpmColormap | XpmDepth;
395 attribs.visual = Scr->d_visual;
396 attribs.colormap = Scr->TwmRoot.cmaps.cwins[0]->colormap->c;
397 attribs.depth = Scr->d_depth;
398 attribs.pixels = NULL;
399
400 if (bg_color)
401 attribs.valuemask |= XpmReturnPixels;
402
403 pm = XcprLocatePixmapFile (ScreenOfDisplay(dpy, Scr->screen), bigname,
404 colors, numcolors,
405 Scr->d_depth, NULL, 0, widthp, heightp, &HotX, &HotY,
406 isXpm, &attribs, shape_mask);
407 if (bg_color && *isXpm)
408 *bg_color = *attribs.pixels;
409 #else
410 pm = XmuLocateBitmapFile (ScreenOfDisplay(dpy, Scr->screen), bigname, NULL,
411 0, (int *)widthp, (int *)heightp, &HotX, &HotY);
412 #endif /* XPM */
413
414 if (pm == None && Scr->IconDirectory && bigname[0] != '/') {
415 if (bigname != name) free (bigname);
416 /*
417 * Attempt to find icon in old IconDirectory (now obsolete)
418 */
419 bigname = (char *) malloc (strlen(name) + strlen(Scr->IconDirectory) +
420 2);
421 if (!bigname) {
422 fprintf (stderr,
423 "%s: unable to allocate memory for \"%s/%s\"\n",
424 ProgramName, Scr->IconDirectory, name);
425 return None;
426 }
427 (void) sprintf (bigname, "%s/%s", Scr->IconDirectory, name);
428
429 #ifdef XPM
430 attribs.valuemask = XpmVisual | XpmColormap | XpmDepth;
431 attribs.visual = Scr->d_visual;
432 attribs.colormap = Scr->TwmRoot.cmaps.cwins[0]->colormap->c;
433 attribs.depth = Scr->d_depth;
434
435 XPMret = XpmReadFileToPixmap(dpy, RootWindow(dpy, Scr->screen),
436 bigname, &pm, shape_mask, &attribs);
437 switch (XPMret) {
438 case XpmSuccess:
439 case XpmColorError:
440 *isXpm = True;
441 break;
442 case XpmNoMemory:
443 printf("%s: XpmReadFileToPixmap out of memory (reading \"%s\")\n",
444 ProgramName, bigname);
445 break;
446 case XpmColorFailed:
447 printf("%s: Color parse/alloc failed in XpmReadFileToPixmap (reading \"%s\")\n",
448 ProgramName, bigname);
449 break;
450 case XpmOpenFailed:
451 case XpmFileInvalid:
452 default:
453 if (XReadBitmapFile (dpy, Scr->Root, bigname, widthp, heightp,
454 &pm, &HotX, &HotY) != BitmapSuccess)
455 pm = None;
456 if (shape_mask)
457 *shape_mask = None;
458 break;
459 } /* switch */
460 #else
461 if (XReadBitmapFile (dpy, Scr->Root, bigname, widthp, heightp,
462 &pm, &HotX, &HotY) != BitmapSuccess)
463 pm = None;
464 if (shape_mask)
465 *shape_mask = None;
466 #endif /* XPM */
467
468 } /* if */
469 if (bigname != name) free (bigname);
470 if (pm == None) {
471 #ifndef SHAPE
472 fprintf (stderr, "%s: unable to find bitmap \"%s\"\n",
473 ProgramName, name);
474 #else
475 int l = strlen(name);
476
477 if (l <=4 || ((strncmp(&name[l-3],"clp",3) != 0) &&
478 (strncmp(&name[l-3],"msk",3) != 0)) ) {
479 fprintf (stderr, "%s: unable to find bitmap \"%s\"\n",
480 ProgramName, name);
481 }
482 #endif
483 }
484
485 #ifdef XPM
486 XpmFreeAttributes(&attribs);
487 #endif
488 return pm;
489 }
490
GetPixmap(name)491 Pixmap GetPixmap (name)
492 char *name;
493 {
494 return FindPixmap (name, &JunkWidth, &JunkHeight, JunkIsXpm, NULL,
495 NULL, 0, NULL);
496 }
497
498
InsertRGBColormap(a,maps,nmaps,replace)499 InsertRGBColormap (a, maps, nmaps, replace)
500 Atom a;
501 XStandardColormap *maps;
502 int nmaps;
503 Bool replace;
504 {
505 StdCmap *sc = NULL;
506
507 if (replace) { /* locate existing entry */
508 for (sc = Scr->StdCmapInfo.head; sc; sc = sc->next) {
509 if (sc->atom == a) break;
510 }
511 }
512
513 if (!sc) { /* no existing, allocate new */
514 sc = (StdCmap *) malloc (sizeof (StdCmap));
515 if (!sc) {
516 fprintf (stderr, "%s: unable to allocate %d bytes for StdCmap\n",
517 ProgramName, sizeof (StdCmap));
518 return;
519 }
520 }
521
522 if (replace) { /* just update contents */
523 if (sc->maps) XFree ((char *) maps);
524 if (sc == Scr->StdCmapInfo.mru) Scr->StdCmapInfo.mru = NULL;
525 } else { /* else appending */
526 sc->next = NULL;
527 sc->atom = a;
528 if (Scr->StdCmapInfo.tail) {
529 Scr->StdCmapInfo.tail->next = sc;
530 } else {
531 Scr->StdCmapInfo.head = sc;
532 }
533 Scr->StdCmapInfo.tail = sc;
534 }
535 sc->nmaps = nmaps;
536 sc->maps = maps;
537
538 return;
539 }
540
RemoveRGBColormap(a)541 RemoveRGBColormap (a)
542 Atom a;
543 {
544 StdCmap *sc, *prev;
545
546 prev = NULL;
547 for (sc = Scr->StdCmapInfo.head; sc; sc = sc->next) {
548 if (sc->atom == a) break;
549 prev = sc;
550 }
551 if (sc) { /* found one */
552 if (sc->maps) XFree ((char *) sc->maps);
553 if (prev) prev->next = sc->next;
554 if (Scr->StdCmapInfo.head == sc) Scr->StdCmapInfo.head = sc->next;
555 if (Scr->StdCmapInfo.tail == sc) Scr->StdCmapInfo.tail = prev;
556 if (Scr->StdCmapInfo.mru == sc) Scr->StdCmapInfo.mru = NULL;
557 }
558 return;
559 }
560
LocateStandardColormaps()561 LocateStandardColormaps()
562 {
563 Atom *atoms;
564 int natoms;
565 int i;
566
567 atoms = XListProperties (dpy, Scr->Root, &natoms);
568 for (i = 0; i < natoms; i++) {
569 XStandardColormap *maps = NULL;
570 int nmaps;
571
572 if (XGetRGBColormaps (dpy, Scr->Root, &maps, &nmaps, atoms[i])) {
573 /* if got one, then append to current list */
574 InsertRGBColormap (atoms[i], maps, nmaps, False);
575 }
576 }
577 if (atoms) XFree ((char *) atoms);
578 return;
579 }
580
581 int
GetColor(kind,what,name)582 GetColor(kind, what, name)
583 int kind;
584 Pixel *what;
585 char *name;
586 {
587 XColor color, junkcolor;
588 Status stat = 0;
589 Colormap cmap = Scr->TwmRoot.cmaps.cwins[0]->colormap->c;
590
591 if (Scr->Monochrome != kind)
592 return FALSE;
593
594 if (!XAllocNamedColor (dpy, cmap, name, &color, &junkcolor))
595 {
596 /* if we could not allocate the color, let's see if this is a
597 * standard colormap
598 */
599 XStandardColormap *stdcmap = NULL;
600
601 /* parse the named color */
602 if (name[0] != '#')
603 stat = XParseColor (dpy, cmap, name, &color);
604 if (!stat)
605 {
606 fprintf (stderr, "%s: invalid color name \"%s\"\n",
607 ProgramName, name);
608 return FALSE;
609 }
610
611 /*
612 * look through the list of standard colormaps (check cache first)
613 */
614 if (Scr->StdCmapInfo.mru && Scr->StdCmapInfo.mru->maps &&
615 (Scr->StdCmapInfo.mru->maps[Scr->StdCmapInfo.mruindex].colormap ==
616 cmap)) {
617 stdcmap = &(Scr->StdCmapInfo.mru->maps[Scr->StdCmapInfo.mruindex]);
618 } else {
619 StdCmap *sc;
620
621 for (sc = Scr->StdCmapInfo.head; sc; sc = sc->next) {
622 int i;
623
624 for (i = 0; i < sc->nmaps; i++) {
625 if (sc->maps[i].colormap == cmap) {
626 Scr->StdCmapInfo.mru = sc;
627 Scr->StdCmapInfo.mruindex = i;
628 stdcmap = &(sc->maps[i]);
629 goto gotit;
630 }
631 }
632 }
633 }
634
635 gotit:
636 if (stdcmap) {
637 color.pixel = (stdcmap->base_pixel +
638 ((Pixel)(((float)color.red / 65535.0) *
639 stdcmap->red_max + 0.5) *
640 stdcmap->red_mult) +
641 ((Pixel)(((float)color.green /65535.0) *
642 stdcmap->green_max + 0.5) *
643 stdcmap->green_mult) +
644 ((Pixel)(((float)color.blue / 65535.0) *
645 stdcmap->blue_max + 0.5) *
646 stdcmap->blue_mult));
647 } else {
648 fprintf (stderr, "%s: unable to allocate color \"%s\"\n",
649 ProgramName, name);
650 return FALSE;
651 }
652 }
653
654 *what = color.pixel;
655 return TRUE;
656 }
657
GetFont(font)658 GetFont(font)
659 MyFont *font;
660 {
661 char *deffontname = "fixed";
662
663 if (font->font != NULL)
664 XFreeFont(dpy, font->font);
665
666 if ((font->font = XLoadQueryFont(dpy, font->name)) == NULL)
667 {
668 if (Scr->DefaultFont.name) {
669 deffontname = Scr->DefaultFont.name;
670 }
671 if ((font->font = XLoadQueryFont(dpy, deffontname)) == NULL)
672 {
673 fprintf (stderr, "%s: unable to open fonts \"%s\" or \"%s\"\n",
674 ProgramName, font->name, deffontname);
675 exit(1);
676 }
677
678 }
679 font->height = font->font->ascent + font->font->descent;
680 font->y = font->font->ascent;
681 }
682
683
684 /*
685 * SetFocus - separate routine to set focus to make things more understandable
686 * and easier to debug
687 */
SetFocus(tmp_win,time)688 SetFocus (tmp_win, time)
689 TwmWindow *tmp_win;
690 Time time;
691 {
692 Window w = (tmp_win ? tmp_win->w : PointerRoot);
693
694 #ifdef TRACE
695 if (tmp_win) {
696 printf ("Focusing on window \"%s\"\n", tmp_win->full_name);
697 } else {
698 printf ("Unfocusing; Scr->Focus was \"%s\"\n",
699 Scr->Focus ? Scr->Focus->full_name : "(nil)");
700 }
701 #endif
702
703 XSetInputFocus (dpy, w, RevertToPointerRoot, time);
704 }
705
706
707 #ifdef NOPUTENV
708 /*
709 * define our own putenv() if the system doesn't have one.
710 * putenv(s): place s (a string of the form "NAME=value") in
711 * the environment; replacing any existing NAME. s is placed in
712 * environment, so if you change s, the environment changes (like
713 * putenv on a sun). Binding removed if you putenv something else
714 * called NAME.
715 */
716 int
putenv(s)717 putenv(s)
718 char *s;
719 {
720 char *v;
721 int varlen, idx;
722 extern char **environ;
723 char **newenv;
724 static int virgin = 1; /* true while "environ" is a virgin */
725
726 v = index(s, '=');
727 if(v == 0)
728 return 0; /* punt if it's not of the right form */
729 varlen = (v + 1) - s;
730
731 for (idx = 0; environ[idx] != 0; idx++) {
732 if (strncmp(environ[idx], s, varlen) == 0) {
733 if(v[1] != 0) { /* true if there's a value */
734 environ[idx] = s;
735 return 0;
736 } else {
737 do {
738 environ[idx] = environ[idx+1];
739 } while(environ[++idx] != 0);
740 return 0;
741 }
742 }
743 }
744
745 /* add to environment (unless no value; then just return) */
746 if(v[1] == 0)
747 return 0;
748 if(virgin) {
749 register i;
750
751 newenv = (char **) malloc((unsigned) ((idx + 2) * sizeof(char*)));
752 if(newenv == 0)
753 return -1;
754 for(i = idx-1; i >= 0; --i)
755 newenv[i] = environ[i];
756 virgin = 0; /* you're not a virgin anymore, sweety */
757 } else {
758 newenv = (char **) realloc((char *) environ,
759 (unsigned) ((idx + 2) * sizeof(char*)));
760 if (newenv == 0)
761 return -1;
762 }
763
764 environ = newenv;
765 environ[idx] = s;
766 environ[idx+1] = 0;
767
768 return 0;
769 }
770 #endif /* NOPUTENV */
771
772
CreateXLogoPixmap(widthp,heightp)773 static Pixmap CreateXLogoPixmap (widthp, heightp)
774 unsigned int *widthp, *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
CreateResizePixmap(widthp,heightp)808 static Pixmap CreateResizePixmap (widthp, heightp)
809 unsigned int *widthp, *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
CreateDotPixmap(widthp,heightp)863 static Pixmap CreateDotPixmap (widthp, heightp)
864 unsigned int *widthp, *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
891 static char questionmark_bits[] = {
892 0x38, 0x7c, 0x64, 0x30, 0x18, 0x00, 0x18, 0x18};
893
CreateQuestionPixmap(widthp,heightp)894 static Pixmap CreateQuestionPixmap (widthp, heightp)
895 unsigned int *widthp, *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
CreateMenuPixmap(widthp,heightp)912 static Pixmap CreateMenuPixmap (widthp, heightp)
913 int *widthp, *heightp;
914 {
915 CreateMenuIcon (Scr->TBInfo.width - Scr->TBInfo.border * 2,widthp,heightp);
916 }
917
CreateMenuIcon(height,widthp,heightp)918 Pixmap CreateMenuIcon (height, widthp, heightp)
919 int height;
920 int *widthp, *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
993 /********************************************************************
994 *
995 * GetPropertyString -
996 * This function gets a string for the value of a property.
997 * For text valued ones, it returns a string containing all of the
998 * values, separated by newlines. For atoms, it returns a string
999 * of the names of the atoms, again separated by newlines. Any other
1000 * type just returns a boring string. It returns NULL if the
1001 * property is not defined.
1002 */
1003
1004 #define MAX_NUM 20
1005
1006 char *
GetPropertyString(win,atom)1007 GetPropertyString(win, atom)
1008 Window win;
1009 Atom atom;
1010 {
1011 Atom actual_type;
1012 int actual_format;
1013 unsigned long nitems;
1014 unsigned long bytes_after;
1015 unsigned char *value;
1016 int status;
1017 char *s;
1018
1019 if (XGetWindowProperty(dpy, win, atom, 0, (MAX_NUM+3)/4,
1020 False, AnyPropertyType, &actual_type,
1021 &actual_format, &nitems, &bytes_after,
1022 &value) != Success)
1023 return NULL;
1024
1025 switch (actual_type) {
1026 case None:
1027 XFree(value);
1028 return NULL;
1029 case XA_STRING: {
1030 XTextProperty prop;
1031 char **list;
1032 int n, l, i;
1033
1034 prop.value = value;
1035 prop.encoding = XA_STRING;
1036 prop.format = actual_format;
1037 prop.nitems = nitems;
1038
1039 if (!XTextPropertyToStringList(&prop, &list, &n))
1040 return NULL;
1041
1042 l = 0;
1043 for (i = 0; i < n; i++)
1044 l += strlen(list[i]);
1045
1046 s = (char *)malloc(l + n + 1);
1047 *s = '\0';
1048
1049 for (i = 0; i < n; i++) {
1050 strcat(s, list[i]);
1051 if (i < n-1)
1052 strcat(s, "\n");
1053 }
1054
1055 XFreeStringList(list);
1056 }
1057 break;
1058 case XA_ATOM: {
1059 int l, i;
1060 char **list = (char **)malloc(sizeof(char *) * nitems);
1061 Atom *atoms = (Atom *)value;
1062
1063 for (i = 0; i < nitems ; i++)
1064 list[i] = XGetAtomName(dpy, atoms[i]);
1065
1066 l = 0;
1067 for (i = 0 ; i < nitems ; i++)
1068 l += strlen(list[i]);
1069
1070 s = (char *)malloc(l + nitems + 1);
1071 *s = '\0';
1072
1073 for (i = 0; i < nitems ; i++) {
1074 strcat(s, list[i]);
1075 XFree(list[i]);
1076 if (i < nitems-1)
1077 strcat(s, "\n");
1078 }
1079
1080 free(list);
1081 }
1082 break;
1083 default:
1084 s = (char *)malloc(15);
1085 strcpy(s, "<Something>");
1086 }
1087
1088 XFree(value);
1089
1090 return s;
1091 }
1092