util.c revision 7d8a9cc2
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 * Copyright 1992 Claude Lecommandeur. 8 */ 9 10/*********************************************************************** 11 * 12 * $XConsortium: util.c,v 1.47 91/07/14 13:40:37 rws Exp $ 13 * 14 * utility routines for twm 15 * 16 * 28-Oct-87 Thomas E. LaStrange File created 17 * 18 * Do the necessary modification to be integrated in ctwm. 19 * Can no longer be used for the standard twm. 20 * 21 * 22-April-92 Claude Lecommandeur. 22 * 23 * Changed behavior of DontMoveOff/MoveOffResistance to allow 24 * moving a window off screen less than #MoveOffResistance pixels. 25 * New code will no longer "snap" windows to #MoveOffResistance 26 * pixels off screen and instead movements will just be stopped and 27 * then resume once movement of #MoveOffResistance have been attempted. 28 * 29 * 15-December-02 Bjorn Knutsson 30 * 31 ***********************************************************************/ 32 33#include "ctwm.h" 34 35#include <stdio.h> 36#include <stdlib.h> 37#include <string.h> 38#include <strings.h> 39 40#include <signal.h> 41#include <sys/time.h> 42 43#include "animate.h" 44#include "add_window.h" 45#include "cursor.h" 46#include "drawing.h" 47#include "gram.tab.h" 48#include "iconmgr.h" 49#include "icons.h" 50#include "image.h" 51#include "screen.h" 52#include "util.h" 53#include "vscreen.h" 54#include "win_decorations.h" 55#include "win_resize.h" 56 57 58/* Handle for debug tracing */ 59FILE *tracefile = NULL; 60 61 62/* 63 * Rewrite this, possibly in terms of replace_substr(). Alternately, the 64 * places it's being used might be better served by being preprocessed 65 * into arrays anyway. 66 */ 67char *ExpandFilePath(char *path) 68{ 69 char *ret, *colon, *p; 70 int len; 71 72 len = 0; 73 p = path; 74 while((colon = strchr(p, ':'))) { 75 len += colon - p + 1; 76 if(*p == '~') { 77 len += HomeLen - 1; 78 } 79 p = colon + 1; 80 } 81 if(*p == '~') { 82 len += HomeLen - 1; 83 } 84 len += strlen(p); 85 ret = malloc(len + 1); 86 *ret = 0; 87 88 p = path; 89 while((colon = strchr(p, ':'))) { 90 *colon = '\0'; 91 if(*p == '~') { 92 strcat(ret, Home); 93 strcat(ret, p + 1); 94 } 95 else { 96 strcat(ret, p); 97 } 98 *colon = ':'; 99 strcat(ret, ":"); 100 p = colon + 1; 101 } 102 if(*p == '~') { 103 strcat(ret, Home); 104 strcat(ret, p + 1); 105 } 106 else { 107 strcat(ret, p); 108 } 109 return ret; 110} 111 112/*********************************************************************** 113 * 114 * Procedure: 115 * ExpandFilename - expand the tilde character to HOME 116 * if it is the first character of the filename 117 * 118 * Returned Value: 119 * a pointer to the new name 120 * 121 * Inputs: 122 * name - the filename to expand 123 * 124 *********************************************************************** 125 * 126 * Currently only used in one place in image_bitmap.c. I've left this 127 * here instead of moving it into images at the moment on the assumption 128 * that there might be other places in the codebase where it's useful. 129 */ 130char * 131ExpandFilename(const char *name) 132{ 133 char *newname; 134 135 /* If it doesn't start with ~/ then it's not our concern */ 136 if(name[0] != '~' || name[1] != '/') { 137 return strdup(name); 138 } 139 140 asprintf(&newname, "%s/%s", Home, &name[1]); 141 142 return newname; 143} 144 145 146void 147GetColor(int kind, Pixel *what, const char *name) 148{ 149 XColor color; 150 Colormap cmap = Scr->RootColormaps.cwins[0]->colormap->c; 151 152#ifndef TOM 153 if(!Scr->FirstTime) { 154 return; 155 } 156#endif 157 158 if(Scr->Monochrome != kind) { 159 return; 160 } 161 162 if(! XParseColor(dpy, cmap, name, &color)) { 163 fprintf(stderr, "%s: invalid color name \"%s\"\n", ProgramName, name); 164 return; 165 } 166 if(! XAllocColor(dpy, cmap, &color)) { 167 /* if we could not allocate the color, let's see if this is a 168 * standard colormap 169 */ 170 XStandardColormap *stdcmap = NULL; 171 172 if(! XParseColor(dpy, cmap, name, &color)) { 173 fprintf(stderr, "%s: invalid color name \"%s\"\n", ProgramName, name); 174 return; 175 } 176 177 /* 178 * look through the list of standard colormaps (check cache first) 179 */ 180 if(Scr->StdCmapInfo.mru && Scr->StdCmapInfo.mru->maps && 181 (Scr->StdCmapInfo.mru->maps[Scr->StdCmapInfo.mruindex].colormap == 182 cmap)) { 183 stdcmap = &(Scr->StdCmapInfo.mru->maps[Scr->StdCmapInfo.mruindex]); 184 } 185 else { 186 StdCmap *sc; 187 188 for(sc = Scr->StdCmapInfo.head; sc; sc = sc->next) { 189 int i; 190 191 for(i = 0; i < sc->nmaps; i++) { 192 if(sc->maps[i].colormap == cmap) { 193 Scr->StdCmapInfo.mru = sc; 194 Scr->StdCmapInfo.mruindex = i; 195 stdcmap = &(sc->maps[i]); 196 goto gotit; 197 } 198 } 199 } 200 } 201 202gotit: 203 if(stdcmap) { 204 color.pixel = (stdcmap->base_pixel + 205 ((Pixel)(((float)color.red / 65535.0) * 206 stdcmap->red_max + 0.5) * 207 stdcmap->red_mult) + 208 ((Pixel)(((float)color.green / 65535.0) * 209 stdcmap->green_max + 0.5) * 210 stdcmap->green_mult) + 211 ((Pixel)(((float)color.blue / 65535.0) * 212 stdcmap->blue_max + 0.5) * 213 stdcmap->blue_mult)); 214 } 215 else { 216 fprintf(stderr, "%s: unable to allocate color \"%s\"\n", 217 ProgramName, name); 218 return; 219 } 220 } 221 222 *what = color.pixel; 223 return; 224} 225 226void GetShadeColors(ColorPair *cp) 227{ 228 XColor xcol; 229 Colormap cmap = Scr->RootColormaps.cwins[0]->colormap->c; 230 bool save; 231 float clearfactor; 232 float darkfactor; 233 char clearcol [32], darkcol [32]; 234 235 clearfactor = (float) Scr->ClearShadowContrast / 100.0; 236 darkfactor = (100.0 - (float) Scr->DarkShadowContrast) / 100.0; 237 xcol.pixel = cp->back; 238 XQueryColor(dpy, cmap, &xcol); 239 240 sprintf(clearcol, "#%04x%04x%04x", 241 xcol.red + (unsigned short)((65535 - xcol.red) * clearfactor), 242 xcol.green + (unsigned short)((65535 - xcol.green) * clearfactor), 243 xcol.blue + (unsigned short)((65535 - xcol.blue) * clearfactor)); 244 sprintf(darkcol, "#%04x%04x%04x", 245 (unsigned short)(xcol.red * darkfactor), 246 (unsigned short)(xcol.green * darkfactor), 247 (unsigned short)(xcol.blue * darkfactor)); 248 249 save = Scr->FirstTime; 250 Scr->FirstTime = true; 251 GetColor(Scr->Monochrome, &cp->shadc, clearcol); 252 GetColor(Scr->Monochrome, &cp->shadd, darkcol); 253 Scr->FirstTime = save; 254} 255 256bool 257UpdateFont(MyFont *font, int height) 258{ 259 int prev = font->avg_height; 260 font->avg_fheight = (font->avg_fheight * font->avg_count + height) 261 / (font->avg_count + 1); 262 font->avg_count++; 263 /* Arbitrary limit. */ 264 if(font->avg_count >= 256) { 265 font->avg_count = 256; 266 } 267 font->avg_height = (int)(font->avg_fheight + 0.5); 268 /* fprintf (stderr, "Updating avg with %d(%d) + %d -> %d(%f)\n", 269 * prev, font->avg_count, height, 270 * font->avg_height, font->avg_fheight); */ 271 return (prev != font->avg_height); 272} 273 274void GetFont(MyFont *font) 275{ 276 char *deffontname = "fixed,*"; 277 char **missing_charset_list_return; 278 int missing_charset_count_return; 279 char *def_string_return; 280 XFontSetExtents *font_extents; 281 XFontStruct **xfonts; 282 char **font_names; 283 int i; 284 int ascent; 285 int descent; 286 int fnum; 287 char *basename2; 288 289 if(font->font_set != NULL) { 290 XFreeFontSet(dpy, font->font_set); 291 } 292 293 asprintf(&basename2, "%s,*", font->basename); 294 if((font->font_set = XCreateFontSet(dpy, basename2, 295 &missing_charset_list_return, 296 &missing_charset_count_return, 297 &def_string_return)) == NULL) { 298 fprintf(stderr, "Failed to get fontset %s\n", basename2); 299 if(Scr->DefaultFont.basename) { 300 deffontname = Scr->DefaultFont.basename; 301 } 302 if((font->font_set = XCreateFontSet(dpy, deffontname, 303 &missing_charset_list_return, 304 &missing_charset_count_return, 305 &def_string_return)) == NULL) { 306 fprintf(stderr, "%s: unable to open fonts \"%s\" or \"%s\"\n", 307 ProgramName, font->basename, deffontname); 308 exit(1); 309 } 310 } 311 free(basename2); 312 font_extents = XExtentsOfFontSet(font->font_set); 313 314 fnum = XFontsOfFontSet(font->font_set, &xfonts, &font_names); 315 for(i = 0, ascent = 0, descent = 0; i < fnum; i++) { 316 ascent = MaxSize(ascent, (*xfonts)->ascent); 317 descent = MaxSize(descent, (*xfonts)->descent); 318 xfonts++; 319 } 320 321 font->height = font_extents->max_logical_extent.height; 322 font->y = ascent; 323 font->ascent = ascent; 324 font->descent = descent; 325 font->avg_height = 0; 326 font->avg_fheight = 0.0; 327 font->avg_count = 0; 328} 329 330 331#if 0 332static void move_to_head(TwmWindow *t) 333{ 334 if(t == NULL) { 335 return; 336 } 337 if(Scr->FirstWindow == t) { 338 return; 339 } 340 341 /* Unlink t from current position */ 342 if(t->prev) { 343 t->prev->next = t->next; 344 } 345 if(t->next) { 346 t->next->prev = t->prev; 347 } 348 349 /* Re-link t at head */ 350 t->next = Scr->FirstWindow; 351 if(Scr->FirstWindow != NULL) { 352 Scr->FirstWindow->prev = t; 353 } 354 t->prev = NULL; 355 Scr->FirstWindow = t; 356} 357 358/* 359 * Moves window 't' after window 'after'. 360 * 361 * If 'after' == NULL, puts it at the head. 362 * If 't' == NULL, does nothing. 363 * If the 't' is already after 'after', does nothing. 364 */ 365 366void move_to_after(TwmWindow *t, TwmWindow *after) 367{ 368 if(after == NULL) { 369 move_to_head(t); 370 return; 371 } 372 if(t == NULL) { 373 return; 374 } 375 if(after->next == t) { 376 return; 377 } 378 379 /* Unlink t from current position */ 380 if(t->prev) { 381 t->prev->next = t->next; 382 } 383 if(t->next) { 384 t->next->prev = t->prev; 385 } 386 387 /* Re-link t after 'after' */ 388 t->next = after->next; 389 if(after->next) { 390 after->next->prev = t; 391 } 392 t->prev = after; 393 after->next = t; 394} 395#endif 396 397 398void RescueWindows(void) 399{ 400 TwmWindow *twm_win = Scr->FirstWindow; 401 402 while(twm_win) { 403 VirtualScreen *vs = twm_win->vs; 404 if(vs) { 405 /* 406 * Check if this window seems completely out of sight. 407 */ 408 int x = twm_win->frame_x; 409 int y = twm_win->frame_y; 410 int w = twm_win->frame_width; 411 int h = twm_win->frame_height; 412 int bw = twm_win->frame_bw; 413 int fullw = w + 2 * bw; 414 int fullh = h + 2 * bw; 415 int old_x = x, old_y = y; 416 struct Icon *i; 417 418#define MARGIN 20 419 420 if(x >= vs->w - MARGIN) { 421 x = vs->w - fullw; 422 } 423 if(y >= vs->h - MARGIN) { 424 y = vs->h - fullh; 425 } 426 if((x + fullw <= MARGIN)) { 427 x = 0; 428 } 429 if((y + fullh <= MARGIN)) { 430 y = 0; 431 } 432 433 if(x != old_x || y != old_y) { 434 SetupWindow(twm_win, x, y, w, h, -1); 435 } 436 437 /* 438 * If there is an icon, check it too. 439 */ 440 i = twm_win->icon; 441 if(i != NULL) { 442 x = i->w_x; 443 y = i->w_y; 444 w = i->w_width; 445 h = i->w_height; 446 old_x = x; 447 old_y = y; 448 449 if(x >= vs->w - MARGIN) { 450 x = vs->w - w; 451 } 452 if(y >= vs->h - MARGIN) { 453 y = vs->h - h; 454 } 455 if((x + w <= MARGIN)) { 456 x = 0; 457 } 458 if((y + h <= MARGIN)) { 459 y = 0; 460 } 461 462 if(x != old_x || y != old_y) { 463 XMoveWindow(dpy, i->w, x, y); 464 i->w_x = x; 465 i->w_y = y; 466 } 467 } 468#undef MARGIN 469 } 470 twm_win = twm_win->next; 471 } 472} 473 474void DebugTrace(char *file) 475{ 476 if(!file) { 477 return; 478 } 479 if(tracefile) { 480 fprintf(stderr, "stop logging events\n"); 481 if(tracefile != stderr) { 482 fclose(tracefile); 483 } 484 tracefile = NULL; 485 } 486 else { 487 if(strcmp(file, "stderr")) { 488 tracefile = fopen(file, "w"); 489 } 490 else { 491 tracefile = stderr; 492 } 493 fprintf(stderr, "logging events to : %s\n", file); 494 } 495} 496 497 498/* 499 * A safe strncpy(), which always ensures NUL-termination. 500 * 501 * XXX This is really just a slightly pessimized implementation of 502 * strlcpy(). Maybe we should use that instead, with a local 503 * implementation for systems like glibc-users that lack it? 504 */ 505void 506safe_strncpy(char *dest, const char *src, size_t size) 507{ 508 strncpy(dest, src, size - 1); 509 dest[size - 1] = '\0'; 510} 511