util.c revision df1c27a6
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 146 147/* 148 * Some color utils 149 */ 150/** 151 * Get info from the server about a given color. 152 */ 153void 154GetColor(int kind, Pixel *what, const char *name) 155{ 156 XColor color; 157 Colormap cmap = Scr->RootColormaps.cwins[0]->colormap->c; 158 159 // If we have no valid X connection (generally means a --cfgchk or 160 // similar run; wont' happen in normal operations), just stub out. 161 if(dpy == NULL) { 162 *what = 0; 163 return; 164 } 165 166#ifndef TOM 167 if(!Scr->FirstTime) { 168 return; 169 } 170#endif 171 172 if(Scr->Monochrome != kind) { 173 return; 174 } 175 176 if(! XParseColor(dpy, cmap, name, &color)) { 177 fprintf(stderr, "%s: invalid color name \"%s\"\n", ProgramName, name); 178 return; 179 } 180 if(! XAllocColor(dpy, cmap, &color)) { 181 /* if we could not allocate the color, let's see if this is a 182 * standard colormap 183 */ 184 XStandardColormap *stdcmap = NULL; 185 186 if(! XParseColor(dpy, cmap, name, &color)) { 187 fprintf(stderr, "%s: invalid color name \"%s\"\n", ProgramName, name); 188 return; 189 } 190 191 /* 192 * look through the list of standard colormaps (check cache first) 193 */ 194 if(Scr->StdCmapInfo.mru && Scr->StdCmapInfo.mru->maps && 195 (Scr->StdCmapInfo.mru->maps[Scr->StdCmapInfo.mruindex].colormap == 196 cmap)) { 197 stdcmap = &(Scr->StdCmapInfo.mru->maps[Scr->StdCmapInfo.mruindex]); 198 } 199 else { 200 StdCmap *sc; 201 202 for(sc = Scr->StdCmapInfo.head; sc; sc = sc->next) { 203 int i; 204 205 for(i = 0; i < sc->nmaps; i++) { 206 if(sc->maps[i].colormap == cmap) { 207 Scr->StdCmapInfo.mru = sc; 208 Scr->StdCmapInfo.mruindex = i; 209 stdcmap = &(sc->maps[i]); 210 goto gotit; 211 } 212 } 213 } 214 } 215 216gotit: 217 if(stdcmap) { 218 color.pixel = (stdcmap->base_pixel + 219 ((Pixel)(((float)color.red / 65535.0) * 220 stdcmap->red_max + 0.5) * 221 stdcmap->red_mult) + 222 ((Pixel)(((float)color.green / 65535.0) * 223 stdcmap->green_max + 0.5) * 224 stdcmap->green_mult) + 225 ((Pixel)(((float)color.blue / 65535.0) * 226 stdcmap->blue_max + 0.5) * 227 stdcmap->blue_mult)); 228 } 229 else { 230 fprintf(stderr, "%s: unable to allocate color \"%s\"\n", 231 ProgramName, name); 232 return; 233 } 234 } 235 236 *what = color.pixel; 237 return; 238} 239 240 241/** 242 * Try and create a 'shaded' version of a color for prettier UI. 243 */ 244void 245GetShadeColors(ColorPair *cp) 246{ 247 XColor xcol; 248 Colormap cmap = Scr->RootColormaps.cwins[0]->colormap->c; 249 bool save; 250 float clearfactor; 251 float darkfactor; 252 char clearcol [32], darkcol [32]; 253 254 // If we have no valid X connection (generally means a --cfgchk or 255 // similar run; wont' happen in normal operations), just stub out. 256 if(dpy == NULL) { 257 cp->shadc = 0; 258 cp->shadd = 0; 259 return; 260 } 261 262 clearfactor = (float) Scr->ClearShadowContrast / 100.0; 263 darkfactor = (100.0 - (float) Scr->DarkShadowContrast) / 100.0; 264 xcol.pixel = cp->back; 265 XQueryColor(dpy, cmap, &xcol); 266 267 sprintf(clearcol, "#%04x%04x%04x", 268 xcol.red + (unsigned short)((65535 - xcol.red) * clearfactor), 269 xcol.green + (unsigned short)((65535 - xcol.green) * clearfactor), 270 xcol.blue + (unsigned short)((65535 - xcol.blue) * clearfactor)); 271 sprintf(darkcol, "#%04x%04x%04x", 272 (unsigned short)(xcol.red * darkfactor), 273 (unsigned short)(xcol.green * darkfactor), 274 (unsigned short)(xcol.blue * darkfactor)); 275 276 save = Scr->FirstTime; 277 Scr->FirstTime = true; 278 GetColor(Scr->Monochrome, &cp->shadc, clearcol); 279 GetColor(Scr->Monochrome, &cp->shadd, darkcol); 280 Scr->FirstTime = save; 281} 282 283 284 285/* 286 * Various font utils 287 */ 288/** 289 * Try adjusting a font's height. Used in drawing the icon manager. 290 */ 291bool 292UpdateFont(MyFont *font, int height) 293{ 294 int prev = font->avg_height; 295 font->avg_fheight = (font->avg_fheight * font->avg_count + height) 296 / (font->avg_count + 1); 297 font->avg_count++; 298 /* Arbitrary limit. */ 299 if(font->avg_count >= 256) { 300 font->avg_count = 256; 301 } 302 font->avg_height = (int)(font->avg_fheight + 0.5); 303 /* fprintf (stderr, "Updating avg with %d(%d) + %d -> %d(%f)\n", 304 * prev, font->avg_count, height, 305 * font->avg_height, font->avg_fheight); */ 306 return (prev != font->avg_height); 307} 308 309 310/** 311 * Load up fontsets from the X server. Only used by CreateFonts() below. 312 */ 313static void 314GetFont(MyFont *font) 315{ 316 char *deffontname = "fixed,*"; 317 char **missing_charset_list_return; 318 int missing_charset_count_return; 319 char *def_string_return; 320 XFontSetExtents *font_extents; 321 XFontStruct **xfonts; 322 char **font_names; 323 int i; 324 int ascent; 325 int descent; 326 int fnum; 327 char *basename2; 328 329 // In special cases where we have no dpy, I don't think we're going 330 // to need details here, so just leave things untouched. We may need 331 // to stub in some magic values; deal with that when we run into the 332 // case. 333 if(dpy == NULL) { 334 return; 335 } 336 337 if(font->font_set != NULL) { 338 XFreeFontSet(dpy, font->font_set); 339 } 340 341 asprintf(&basename2, "%s,*", font->basename); 342 if((font->font_set = XCreateFontSet(dpy, basename2, 343 &missing_charset_list_return, 344 &missing_charset_count_return, 345 &def_string_return)) == NULL) { 346 fprintf(stderr, "Failed to get fontset %s\n", basename2); 347 if(Scr->DefaultFont.basename) { 348 deffontname = Scr->DefaultFont.basename; 349 } 350 if((font->font_set = XCreateFontSet(dpy, deffontname, 351 &missing_charset_list_return, 352 &missing_charset_count_return, 353 &def_string_return)) == NULL) { 354 fprintf(stderr, "%s: unable to open fonts \"%s\" or \"%s\"\n", 355 ProgramName, font->basename, deffontname); 356 exit(1); 357 } 358 } 359 free(basename2); 360 font_extents = XExtentsOfFontSet(font->font_set); 361 362 fnum = XFontsOfFontSet(font->font_set, &xfonts, &font_names); 363 for(i = 0, ascent = 0, descent = 0; i < fnum; i++) { 364 ascent = MaxSize(ascent, (*xfonts)->ascent); 365 descent = MaxSize(descent, (*xfonts)->descent); 366 xfonts++; 367 } 368 369 font->height = font_extents->max_logical_extent.height; 370 font->y = ascent; 371 font->ascent = ascent; 372 font->descent = descent; 373 font->avg_height = 0; 374 font->avg_fheight = 0.0; 375 font->avg_count = 0; 376} 377 378 379/** 380 * Load up our various defined fonts 381 */ 382void 383CreateFonts(ScreenInfo *scr) 384{ 385#define LOADFONT(fld) (GetFont(&scr->fld##Font)) 386 LOADFONT(TitleBar); 387 LOADFONT(Menu); 388 LOADFONT(Icon); 389 LOADFONT(Size); 390 LOADFONT(IconManager); 391 LOADFONT(Default); 392 LOADFONT(workSpaceMgr.window); 393#undef LOADFONT 394 395 scr->HaveFonts = true; 396} 397 398 399 400#if 0 401static void move_to_head(TwmWindow *t) 402{ 403 if(t == NULL) { 404 return; 405 } 406 if(Scr->FirstWindow == t) { 407 return; 408 } 409 410 /* Unlink t from current position */ 411 if(t->prev) { 412 t->prev->next = t->next; 413 } 414 if(t->next) { 415 t->next->prev = t->prev; 416 } 417 418 /* Re-link t at head */ 419 t->next = Scr->FirstWindow; 420 if(Scr->FirstWindow != NULL) { 421 Scr->FirstWindow->prev = t; 422 } 423 t->prev = NULL; 424 Scr->FirstWindow = t; 425} 426 427/* 428 * Moves window 't' after window 'after'. 429 * 430 * If 'after' == NULL, puts it at the head. 431 * If 't' == NULL, does nothing. 432 * If the 't' is already after 'after', does nothing. 433 */ 434 435void move_to_after(TwmWindow *t, TwmWindow *after) 436{ 437 if(after == NULL) { 438 move_to_head(t); 439 return; 440 } 441 if(t == NULL) { 442 return; 443 } 444 if(after->next == t) { 445 return; 446 } 447 448 /* Unlink t from current position */ 449 if(t->prev) { 450 t->prev->next = t->next; 451 } 452 if(t->next) { 453 t->next->prev = t->prev; 454 } 455 456 /* Re-link t after 'after' */ 457 t->next = after->next; 458 if(after->next) { 459 after->next->prev = t; 460 } 461 t->prev = after; 462 after->next = t; 463} 464#endif 465 466 467 468/** 469 * Backend for f.rescuewindows 470 */ 471void RescueWindows(void) 472{ 473 TwmWindow *twm_win = Scr->FirstWindow; 474 475 while(twm_win) { 476 VirtualScreen *vs = twm_win->vs; 477 if(vs) { 478 /* 479 * Check if this window seems completely out of sight. 480 */ 481 int x = twm_win->frame_x; 482 int y = twm_win->frame_y; 483 int w = twm_win->frame_width; 484 int h = twm_win->frame_height; 485 int bw = twm_win->frame_bw; 486 int fullw = w + 2 * bw; 487 int fullh = h + 2 * bw; 488 int old_x = x, old_y = y; 489 struct Icon *i; 490 491#define MARGIN 20 492 493 if(x >= vs->w - MARGIN) { 494 x = vs->w - fullw; 495 } 496 if(y >= vs->h - MARGIN) { 497 y = vs->h - fullh; 498 } 499 if((x + fullw <= MARGIN)) { 500 x = 0; 501 } 502 if((y + fullh <= MARGIN)) { 503 y = 0; 504 } 505 506 if(x != old_x || y != old_y) { 507 SetupWindow(twm_win, x, y, w, h, -1); 508 } 509 510 /* 511 * If there is an icon, check it too. 512 */ 513 i = twm_win->icon; 514 if(i != NULL) { 515 x = i->w_x; 516 y = i->w_y; 517 w = i->w_width; 518 h = i->w_height; 519 old_x = x; 520 old_y = y; 521 522 if(x >= vs->w - MARGIN) { 523 x = vs->w - w; 524 } 525 if(y >= vs->h - MARGIN) { 526 y = vs->h - h; 527 } 528 if((x + w <= MARGIN)) { 529 x = 0; 530 } 531 if((y + h <= MARGIN)) { 532 y = 0; 533 } 534 535 if(x != old_x || y != old_y) { 536 XMoveWindow(dpy, i->w, x, y); 537 i->w_x = x; 538 i->w_y = y; 539 } 540 } 541#undef MARGIN 542 } 543 twm_win = twm_win->next; 544 } 545} 546 547 548 549/** 550 * Backend for f.trace 551 */ 552void 553DebugTrace(char *file) 554{ 555 if(!file) { 556 return; 557 } 558 if(tracefile) { 559 fprintf(stderr, "stop logging events\n"); 560 if(tracefile != stderr) { 561 fclose(tracefile); 562 } 563 tracefile = NULL; 564 } 565 else { 566 if(strcmp(file, "stderr")) { 567 tracefile = fopen(file, "w"); 568 } 569 else { 570 tracefile = stderr; 571 } 572 fprintf(stderr, "logging events to : %s\n", file); 573 } 574} 575 576 577 578/* 579 * A safe strncpy(), which always ensures NUL-termination. 580 * 581 * XXX This is really just a slightly pessimized implementation of 582 * strlcpy(). Maybe we should use that instead, with a local 583 * implementation for systems like glibc-users that lack it? 584 */ 585void 586safe_strncpy(char *dest, const char *src, size_t size) 587{ 588 strncpy(dest, src, size - 1); 589 dest[size - 1] = '\0'; 590} 591