xedit.c revision c05e22d7
1/* $XConsortium: xedit.c,v 1.28 94/03/26 17:06:28 rws Exp $ */ 2 3/* 4 * COPYRIGHT 1987 5 * DIGITAL EQUIPMENT CORPORATION 6 * MAYNARD, MASSACHUSETTS 7 * ALL RIGHTS RESERVED. 8 * 9 * THE INFORMATION IN THIS SOFTWARE IS SUBJECT TO CHANGE WITHOUT NOTICE AND 10 * SHOULD NOT BE CONSTRUED AS A COMMITMENT BY DIGITAL EQUIPMENT CORPORATION. 11 * DIGITAL MAKES NO REPRESENTATIONS ABOUT THE SUITABILITY OF THIS SOFTWARE FOR 12 * ANY PURPOSE. IT IS SUPPLIED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY. 13 * 14 * IF THE SOFTWARE IS MODIFIED IN A MANNER CREATING DERIVATIVE COPYRIGHT RIGHTS, 15 * APPROPRIATE LEGENDS MAY BE PLACED ON THE DERIVATIVE WORK IN ADDITION TO THAT 16 * SET FORTH ABOVE. 17 * 18 * 19 * Permission to use, copy, modify, and distribute this software and its 20 * documentation for any purpose and without fee is hereby granted, provided 21 * that the above copyright notice appear in all copies and that both that 22 * copyright notice and this permission notice appear in supporting 23 * documentation, and that the name of Digital Equipment Corporation not be 24 * used in advertising or publicity pertaining to distribution of the software 25 * without specific, written prior permission. 26 */ 27/* $XFree86: xc/programs/xedit/xedit.c,v 1.17 2002/09/22 07:09:05 paulo Exp $ */ 28 29#include "xedit.h" 30#include <X11/Xaw/SmeBSB.h> 31#include <time.h> 32#include <sys/stat.h> 33#include <X11/CoreP.h> 34 35#include <stdlib.h> 36 37#define randomize() srand((unsigned)time((time_t*)NULL)) 38 39static XtActionsRec actions[] = { 40{"quit", QuitAction}, 41{"save-file", SaveFile}, 42{"load-file", LoadFile}, 43{"find-file", FindFile}, 44{"cancel-find-file", CancelFindFile}, 45{"file-completion", FileCompletion}, 46{"popup-menu", PopupMenu}, 47{"kill-file", KillFile}, 48{"split-window", SplitWindow}, 49{"dir-window", DirWindow}, 50{"delete-window", DeleteWindow}, 51{"xedit-focus", XeditFocus}, 52{"other-window", OtherWindow}, 53{"switch-source", SwitchSource}, 54#ifndef __UNIXOS2__ 55{"lisp-eval", XeditLispEval}, 56{"xedit-print-lisp-eval", XeditPrintLispEval}, 57{"xedit-keyboard-reset",XeditKeyboardReset}, 58#endif 59{"ispell", IspellAction}, 60{"line-edit", LineEditAction}, 61{"tags", TagsAction} 62}; 63 64#define DEF_HINT_INTERVAL 300 /* in seconds, 5 minutes */ 65 66static Atom wm_delete_window; 67static Widget hintswindow; 68static int position_format_mask; 69static XawTextPositionInfo infos[3]; 70 71Widget topwindow, textwindow, messwidget, labelwindow, filenamewindow; 72Widget scratch, hpane, vpanes[2], labels[3], texts[3], forms[3], positions[3]; 73Widget options_popup, dirlabel, dirwindow; 74Boolean international; 75Boolean line_edit; 76XawTextWrapMode wrapmodes[3]; 77 78extern void ResetSourceChanged(xedit_flist_item*); 79 80static void makeButtonsAndBoxes(Widget); 81static void HintsTimer(XtPointer, XtIntervalId*); 82static void PositionChanged(Widget, XtPointer, XtPointer); 83static void StartFormatPosition(void); 84static void StartHints(void); 85 86Display *CurDpy; 87 88struct _app_resources app_resources; 89struct _xedit_flist flist; 90 91#define Offset(field) XtOffsetOf(struct _app_resources, field) 92 93static XtResource resources[] = { 94 {"enableBackups", "EnableBackups", XtRBoolean, sizeof(Boolean), 95 Offset(enableBackups), XtRImmediate, FALSE}, 96 {"backupNamePrefix", "BackupNamePrefix", XtRString, sizeof(char *), 97 Offset(backupNamePrefix),XtRString, ""}, 98 {"backupNameSuffix", "BackupNameSuffix", XtRString, sizeof(char *), 99 Offset(backupNameSuffix),XtRString, ".BAK"}, 100 {"hints", "Hint", XtRString, sizeof(char *), 101 Offset(hints.resource), XtRImmediate, NULL}, 102 {"hintsInterval", XtCInterval, XtRInt, sizeof(long), 103 Offset(hints.interval), XtRImmediate, (XtPointer)DEF_HINT_INTERVAL}, 104 {"changedBitmap", XtRBitmap, XtRString, sizeof(char*), 105 Offset(changed_pixmap_name), XtRString, "dot"}, 106 {"positionFormat", "Format", XtRString, sizeof(char*), 107 Offset(position_format), XtRString, "L%l"}, 108 {"autoReplace", "Replace", XtRString, sizeof(char*), 109 Offset(auto_replace), XtRImmediate, NULL}, 110 {"tagsName", "TagsName", XtRString, sizeof(char *), 111 Offset(tagsName), XtRString, "tags"}, 112 {"loadTags", "LoadTags", XtRBoolean, sizeof(Boolean), 113 Offset(loadTags), XtRImmediate, (XtPointer)TRUE}, 114}; 115 116#undef Offset 117 118int 119main(int argc, char *argv[]) 120{ 121 Boolean exists; 122 char *filename; 123 FileAccess file_access; 124 Widget source; 125 XtAppContext appcon; 126 Boolean show_dir; 127 xedit_flist_item *first_item; 128 unsigned int i, lineno; 129 130 lineno = 0; 131 show_dir = FALSE; 132 first_item = NULL; 133 134 topwindow = XtAppInitialize(&appcon, "Xedit", NULL, 0, &argc, argv, 135 NULL, 136 NULL, 0); 137 138 XtAppAddActions(appcon, actions, XtNumber(actions)); 139 XtOverrideTranslations(topwindow, 140 XtParseTranslationTable("<Message>WM_PROTOCOLS: quit()")); 141 142 XtGetApplicationResources(topwindow, (XtPointer) &app_resources, resources, 143 XtNumber(resources), NULL, 0); 144 145 CurDpy = XtDisplay(topwindow); 146 XawSimpleMenuAddGlobalActions(appcon); 147 XtRegisterGrabAction(PopupMenu, True, 148 ButtonPressMask | ButtonReleaseMask, 149 GrabModeAsync, GrabModeAsync); 150 151 makeButtonsAndBoxes(topwindow); 152 153 StartHints(); 154 StartFormatPosition(); 155 (void)StartHooks(appcon); 156 if (position_format_mask == 0) { 157 for (i = 0; i < 3; i++) 158 XtRemoveCallback(texts[i], XtNpositionCallback, 159 PositionChanged, NULL); 160 } 161 XtRealizeWidget(topwindow); 162 163#ifndef __UNIXOS2__ 164 XeditLispInitialize(); 165#endif 166 167 options_popup = XtCreatePopupShell("optionsMenu", simpleMenuWidgetClass, 168 topwindow, NULL, 0); 169 XtRealizeWidget(options_popup); 170 XtAddCallback(XtCreateManagedWidget("ispell", smeBSBObjectClass, 171 options_popup, NULL, 0), 172 XtNcallback, IspellCallback, NULL); 173 CreateEditPopup(); 174 175 wm_delete_window = XInternAtom(XtDisplay(topwindow), "WM_DELETE_WINDOW", 176 False); 177 (void)XSetWMProtocols(XtDisplay(topwindow), XtWindow(topwindow), 178 &wm_delete_window, 1); 179 180 /* This first call is just to save the default font and colors */ 181 UpdateTextProperties(0); 182 183 if (argc > 1) { 184 xedit_flist_item *item; 185 Arg args[2]; 186 unsigned int num_args; 187 188 for (i = 1; i < argc; i++) { 189 struct stat st; 190 191 if (argv[i][0] == '+') { 192 char *endptr; 193 194 lineno = strtol(argv[i], &endptr, 10); 195 /* Don't warn about incorrect input? */ 196 if (*endptr) 197 lineno = 0; 198 continue; 199 } 200 201 filename = ResolveName(argv[i]); 202 if (filename == NULL || FindTextSource(NULL, filename) != NULL) 203 continue; 204 205 num_args = 0; 206 if (stat(filename, &st) == 0 && !S_ISREG(st.st_mode)) { 207 if (S_ISDIR(st.st_mode)) { 208 if (!first_item) { 209 char path[BUFSIZ + 1]; 210 211 strncpy(path, filename, sizeof(path) - 2); 212 path[sizeof(path) - 2] = '\0'; 213 if (*path) { 214 if (path[strlen(path) - 1] != '/') 215 strcat(path, "/"); 216 } 217 else 218 strcpy(path, "./"); 219 XtSetArg(args[0], XtNlabel, ""); 220 XtSetValues(dirlabel, args, 1); 221 SwitchDirWindow(True); 222 DirWindowCB(dirwindow, path, NULL); 223 show_dir = True; 224 } 225 continue; 226 } 227 } 228 229 switch (file_access = CheckFilePermissions(filename, &exists)) { 230 case NO_READ: 231 if (exists) 232 XeditPrintf("File %s exists, and could not be opened for " 233 "reading.\n", argv[i]); 234 else 235 XeditPrintf("File %s does not exist, and the directory " 236 "could not be opened for writing.\n", argv[i]); 237 break; 238 case READ_OK: 239 XtSetArg(args[num_args], XtNeditType, XawtextRead); num_args++; 240 XeditPrintf("File %s opened READ ONLY.\n", argv[i]); 241 break; 242 case WRITE_OK: 243 XtSetArg(args[num_args], XtNeditType, XawtextEdit); num_args++; 244 XeditPrintf("File %s opened read - write.\n", argv[i]); 245 break; 246 } 247 if (file_access != NO_READ) { 248 int flags; 249 250 if (exists) { 251 flags = EXISTS_BIT; 252 XtSetArg(args[num_args], XtNstring, filename);num_args++; 253 } 254 else { 255 flags = 0; 256 XtSetArg(args[num_args], XtNstring, NULL); num_args++; 257 } 258 source = XtVaCreateWidget("textSource", international ? 259 multiSrcObjectClass 260 : asciiSrcObjectClass, topwindow, 261 XtNtype, XawAsciiFile, 262 XtNeditType, XawtextEdit, 263 NULL, NULL); 264 XtSetValues(source, args, num_args); 265 item = AddTextSource(source, argv[i], filename, 266 flags, file_access); 267 XtAddCallback(item->source, XtNcallback, SourceChanged, 268 (XtPointer)item); 269 if (exists && file_access == WRITE_OK) { 270 item->mode = st.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO); 271 item->mtime = st.st_mtime; 272 } 273 if (!first_item && !show_dir) 274 first_item = item; 275 ResetSourceChanged(item); 276 } 277 } 278 } 279 280 if (!flist.pixmap && strlen(app_resources.changed_pixmap_name)) { 281 XrmValue from, to; 282 283 from.size = strlen(app_resources.changed_pixmap_name); 284 from.addr = app_resources.changed_pixmap_name; 285 to.size = sizeof(Pixmap); 286 to.addr = (XtPointer)&(flist.pixmap); 287 288 XtConvertAndStore(flist.popup, XtRString, &from, XtRBitmap, &to); 289 } 290 291 if (first_item == NULL) { 292 XtSetKeyboardFocus(topwindow, filenamewindow); 293 XtVaSetValues(textwindow, XtNwrap, XawtextWrapLine, NULL); 294 } 295 else { 296 SwitchTextSource(first_item); 297 XtSetKeyboardFocus(topwindow, textwindow); 298 if (lineno) { 299 XawTextPosition position; 300 301 source = XawTextGetSource(textwindow); 302 position = RSCAN(XawTextGetInsertionPoint(textwindow), 303 lineno, False); 304 position = LSCAN(position, 1, False); 305 XawTextSetInsertionPoint(textwindow, position); 306 } 307 } 308 309 XtAppMainLoop(appcon); 310 return EXIT_SUCCESS; 311} 312 313static void 314makeButtonsAndBoxes(Widget parent) 315{ 316 Widget outer, b_row, viewport; 317 Arg arglist[10]; 318 Cardinal num_args; 319 xedit_flist_item *item; 320 static char *labelWindow = "labelWindow", *editWindow = "editWindow"; 321 static char *formWindow = "formWindow", *positionWindow = "positionWindow"; 322 323 outer = XtCreateManagedWidget("paned", panedWidgetClass, parent, 324 NULL, ZERO); 325 326 b_row = XtCreateManagedWidget("buttons", panedWidgetClass, outer, NULL, ZERO); 327 { 328 MakeCommandButton(b_row, "quit", DoQuit); 329 MakeCommandButton(b_row, "save", DoSave); 330 MakeCommandButton(b_row, "load", DoLoad); 331 filenamewindow = MakeStringBox(b_row, "filename", NULL); 332 } 333 hintswindow = XtCreateManagedWidget("bc_label", labelWidgetClass, 334 outer, NULL, ZERO); 335 336 num_args = 0; 337 XtSetArg(arglist[num_args], XtNeditType, XawtextEdit); ++num_args; 338 messwidget = XtCreateManagedWidget("messageWindow", asciiTextWidgetClass, 339 outer, arglist, num_args); 340 341 num_args = 0; 342 XtSetArg(arglist[num_args], XtNorientation, XtorientHorizontal); ++num_args; 343 hpane = XtCreateManagedWidget("hpane", panedWidgetClass, outer, 344 arglist, num_args); 345 346 num_args = 0; 347 XtSetArg(arglist[num_args], XtNorientation, XtorientVertical); ++num_args; 348 vpanes[0] = XtCreateManagedWidget("vpane", panedWidgetClass, hpane, 349 arglist, num_args); 350 XtSetArg(arglist[num_args], XtNheight, 1); ++num_args; 351 XtSetArg(arglist[num_args], XtNwidth, 1); ++num_args; 352 vpanes[1] = XtCreateWidget("vpane", panedWidgetClass, hpane, 353 arglist, num_args); 354 355 forms[0] = XtCreateManagedWidget(formWindow, formWidgetClass, 356 vpanes[0], NULL, 0); 357 labelwindow = XtCreateManagedWidget(labelWindow,labelWidgetClass, 358 forms[0], NULL, 0); 359 labels[0] = labelwindow; 360 positions[0] = XtCreateManagedWidget(positionWindow,labelWidgetClass, 361 forms[0], NULL, 0); 362 363 forms[2] = XtCreateWidget(formWindow, formWidgetClass, 364 vpanes[1], NULL, 0); 365 labels[2] = XtCreateManagedWidget(labelWindow,labelWidgetClass, 366 forms[2], NULL, 0); 367 positions[2] = XtCreateManagedWidget(positionWindow,labelWidgetClass, 368 forms[2], NULL, 0); 369 370 num_args = 0; 371 XtSetArg(arglist[num_args], XtNtype, XawAsciiFile); ++num_args; 372 XtSetArg(arglist[num_args], XtNeditType, XawtextEdit); ++num_args; 373 textwindow = XtCreateManagedWidget(editWindow, asciiTextWidgetClass, 374 vpanes[0], arglist, num_args); 375 376 /* Get international resource value form the textwindow */ 377 num_args = 0; 378 XtSetArg(arglist[num_args], XtNinternational, &international); ++num_args; 379 XtGetValues(textwindow, arglist, num_args); 380 381 num_args = 0; 382 XtSetArg(arglist[num_args], XtNtype, XawAsciiFile); ++num_args; 383 XtSetArg(arglist[num_args], XtNeditType, XawtextEdit); ++num_args; 384 scratch = XtVaCreateWidget("textSource", international ? 385 multiSrcObjectClass : 386 asciiSrcObjectClass, topwindow, 387 XtNtype, XawAsciiFile, 388 XtNeditType, XawtextEdit, 389 NULL, NULL); 390 XtSetValues(scratch, arglist, num_args); 391 392 num_args = 0; 393 XtSetArg(arglist[num_args], XtNtextSource, scratch); ++num_args; 394 XtSetValues(textwindow, arglist, num_args); 395 396 texts[0] = textwindow; 397 num_args = 0; 398 XtSetArg(arglist[num_args], XtNtextSource, scratch); ++num_args; 399 XtSetArg(arglist[num_args], XtNdisplayCaret, False); ++num_args; 400 texts[2] = XtCreateWidget(editWindow, asciiTextWidgetClass, 401 vpanes[1], arglist, num_args); 402 403 forms[1] = XtCreateWidget(formWindow, formWidgetClass, 404 vpanes[0], NULL, 0); 405 labels[1] = XtCreateManagedWidget(labelWindow,labelWidgetClass, 406 forms[1], NULL, 0); 407 positions[1] = XtCreateManagedWidget(positionWindow,labelWidgetClass, 408 forms[1], NULL, 0); 409 410 texts[1] = XtCreateWidget(editWindow, asciiTextWidgetClass, 411 vpanes[0], arglist, num_args); 412 413 dirlabel = XtCreateWidget("dirlabel", labelWidgetClass, 414 vpanes[1], NULL, 0); 415 num_args = 0; 416 XtSetArg(arglist[num_args], XtNheight, 1); ++num_args; 417 XtSetArg(arglist[num_args], XtNwidth, 1); ++num_args; 418 viewport = XtCreateWidget("viewport", viewportWidgetClass, 419 vpanes[1], arglist, num_args); 420 dirwindow = XtCreateManagedWidget("dirwindow", listWidgetClass, 421 viewport, NULL, 0); 422 423 item = AddTextSource(scratch, "*scratch*", "*scratch*", 424 0, WRITE_OK); 425 item->wrap = XawtextWrapLine; 426 item->flags |= WRAP_BIT; 427 XtAddCallback(item->source, XtNcallback, SourceChanged, 428 (XtPointer)item); 429 ResetSourceChanged(item); 430 flist.current = item; 431 432 for (num_args = 0; num_args < 3; num_args++) 433 XtAddCallback(texts[num_args], XtNpositionCallback, PositionChanged, NULL); 434 435 for (num_args = 0; num_args < 3; num_args++) { 436 XtSetArg(arglist[0], XtNwrap, &wrapmodes[num_args]); 437 XtGetValues(texts[num_args], arglist, 1); 438 } 439 440 XtAddCallback(dirwindow, XtNcallback, DirWindowCB, NULL); 441} 442 443/* Function Name: Feep 444 * Description: feeps the bell. 445 * Arguments: none. 446 * Returns: none. 447 */ 448 449void 450Feep(void) 451{ 452 XBell(CurDpy, 0); 453} 454 455#define l_BIT 0x01 456#define c_BIT 0x02 457#define p_BIT 0x04 458#define s_BIT 0x08 459#define MAX_FMT_LEN 30 460 461static void 462StartFormatPosition(void) 463{ 464 char *fmt = app_resources.position_format; 465 466 if (fmt) 467 while (*fmt) 468 if (*fmt++ == '%') { 469 int len = 0; 470 471 if (*fmt == '-') { 472 ++fmt; 473 ++len; 474 } 475 while (*fmt >= '0' && *fmt <= '9') { 476 ++fmt; 477 if (++len >= MAX_FMT_LEN) { 478 XtAppWarning(XtWidgetToApplicationContext(topwindow), 479 "Format too large to formatPosition"); 480 position_format_mask = 0; 481 return; 482 } 483 } 484 switch (*fmt++) { 485 case 'l': position_format_mask |= l_BIT; break; 486 case 'c': position_format_mask |= c_BIT; break; 487 case 'p': position_format_mask |= p_BIT; break; 488 case 's': position_format_mask |= s_BIT; break; 489 case '%': break; 490 default: { 491 char msg[256]; 492 493 XmuSnprintf(msg, sizeof(msg), 494 "Unknown format \"%%%c\" in positionFormat", 495 fmt[-1]); 496 XtAppWarning(XtWidgetToApplicationContext(topwindow), 497 msg); 498 position_format_mask = 0; 499 return; 500 } 501 } 502 } 503} 504 505/*ARGSUSED*/ 506static void 507PositionChanged(Widget w, XtPointer client_data, XtPointer call_data) 508{ 509 int idx; 510 XawTextPositionInfo *info = (XawTextPositionInfo*)call_data; 511 512 for (idx = 0; idx < 3; idx++) 513 if (w == texts[idx]) 514 break; 515 if (idx > 2) 516 return; 517 518 if (((position_format_mask & l_BIT) 519 && infos[idx].line_number != info->line_number) 520 || ((position_format_mask & c_BIT) 521 && infos[idx].column_number != info->column_number) 522 || ((position_format_mask & p_BIT) 523 && infos[idx].insert_position != info->insert_position) 524 || ((position_format_mask & s_BIT) 525 && infos[idx].last_position != info->last_position) 526 || infos[idx].overwrite_mode != info->overwrite_mode) { 527 int len = 6; 528 Arg args[1]; 529 char buffer[256], *str = app_resources.position_format; 530 char fmt_buf[MAX_FMT_LEN + 2], *fmt; 531 532 memcpy(&infos[idx], info, sizeof(XawTextPositionInfo)); 533 if (info->overwrite_mode) 534 strcpy(buffer, "Ovrwt "); 535 else 536 strcpy(buffer, " "); 537 while (*str) { 538 switch (*str) { 539 case '%': 540 fmt = fmt_buf; 541 *fmt++ = *str++; 542 if (*str == '-') 543 *fmt++ = *str++; 544 /*CONSTCOND*/ 545 while (*str >= '0' && *str <= '9') { 546 /* StartPositionFormat() already checked the format 547 * length. 548 */ 549 *fmt++ = *str++; 550 } 551 *fmt++ = 'd'; 552 *fmt = '\0'; 553 switch (*str) { 554 case 'l': 555 XmuSnprintf(&buffer[len], sizeof(buffer) - len, 556 fmt_buf, info->line_number); 557 break; 558 case 'c': 559 XmuSnprintf(&buffer[len], sizeof(buffer) - len, 560 fmt_buf, info->column_number); 561 break; 562 case 'p': 563 XmuSnprintf(&buffer[len], sizeof(buffer) - len, 564 fmt_buf, info->insert_position); 565 break; 566 case 's': 567 XmuSnprintf(&buffer[len], sizeof(buffer) - len, 568 fmt_buf, info->last_position); 569 break; 570 case '%': 571 strcpy(&buffer[len], "%"); 572 break; 573 } 574 len += strlen(&buffer[len]); 575 break; 576 default: 577 buffer[len++] = *str; 578 break; 579 } 580 if (len >= sizeof(buffer) - 1) 581 break; 582 ++str; 583 } 584 buffer[len] = '\0'; 585 586 XtSetArg(args[0], XtNlabel, buffer); 587 XtSetValues(positions[idx], args, 1); 588 } 589} 590 591/*ARGSUSED*/ 592static void 593HintsTimer(XtPointer closure, XtIntervalId *id) 594{ 595 Arg args[1]; 596 xedit_hints *hints = (xedit_hints*)closure; 597 598 hints->cur_hint = rand() % hints->num_hints; 599 600 XtSetArg(args[0], XtNlabel, hints->hints[hints->cur_hint]); 601 XtSetValues(hintswindow, args, 1); 602 603 hints->timer = XtAppAddTimeOut(XtWidgetToApplicationContext(topwindow), 604 hints->interval, HintsTimer, closure); 605} 606 607#define MAX_HINT_LEN 255 608#define MIN_HINT_INTERVAL 5 609static void 610StartHints(void) 611{ 612 char *str, *p; 613 unsigned i, len; 614 xedit_hints *hints = &(app_resources.hints); 615 616 /* if resource was not set, or was overriden */ 617 if (hints->resource == NULL || !*hints->resource) 618 return; 619 620 randomize(); 621 622 if (hints->interval < MIN_HINT_INTERVAL) 623 hints->interval = DEF_HINT_INTERVAL; 624 hints->interval *= 1000; 625 hints->hints = (char**)XtMalloc(sizeof(char*)); 626 hints->hints[hints->cur_hint = 0] = p = hints->resource; 627 hints->num_hints = 1; 628 629 while ((p = strchr(p, '\n')) != NULL) { 630 if (*++p == '\0') 631 break; 632 hints->hints = (char**) 633 XtRealloc((char*)hints->hints, 634 sizeof(char*) * (hints->num_hints + 1)); 635 hints->hints[hints->num_hints++] = p; 636 } 637 638 /* make a private copy of the resource values, so that one can change 639 * the Xrm database safely. 640 */ 641 for (i = 0; i < hints->num_hints; i++) { 642 if ((p = strchr(hints->hints[i], '\n')) != NULL) 643 len = p - hints->hints[i]; 644 else 645 len = strlen(hints->hints[i]); 646 if (len > MAX_HINT_LEN) 647 len = MAX_HINT_LEN; 648 str = XtMalloc(len + 1); 649 strncpy(str, hints->hints[i], len); 650 str[len] = '\0'; 651 hints->hints[i] = str; 652 } 653 654 hints->timer = XtAppAddTimeOut(XtWidgetToApplicationContext(topwindow), 655 hints->interval, HintsTimer, 656 (XtPointer)hints); 657} 658