UNIXworkcode

1 /******************************************************************************* 2 * * 3 * help.c -- Nirvana Editor help display * 4 * * 5 * Copyright (C) 1999 Mark Edel * 6 * * 7 * This is free software; you can redistribute it and/or modify it under the * 8 * terms of the GNU General Public License as published by the Free Software * 9 * Foundation; either version 2 of the License, or (at your option) any later * 10 * version. In addition, you may distribute version of this program linked to * 11 * Motif or Open Motif. See README for details. * 12 * * 13 * This software is distributed in the hope that it will be useful, but WITHOUT * 14 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * 15 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * 16 * for more details. * 17 * * 18 * You should have received a copy of the GNU General Public License along with * 19 * software; if not, write to the Free Software Foundation, Inc., 59 Temple * 20 * Place, Suite 330, Boston, MA 02111-1307 USA * 21 * * 22 * Nirvana Text Editor * 23 * September 10, 1991 * 24 * * 25 * Written by Mark Edel, mostly rewritten by Steve Haehn for new help system, * 26 * December, 2001 * 27 * * 28 *******************************************************************************/ 29 30 #ifdef HAVE_CONFIG_H 31 #include "../config.h" 32 #endif 33 34 #include "help.h" 35 #include "textBuf.h" 36 #include "text.h" 37 #include "textP.h" 38 #include "textDisp.h" 39 #include "textSel.h" 40 #include "nedit.h" 41 #include "search.h" 42 #include "window.h" 43 #include "preferences.h" 44 #include "help_data.h" 45 #include "file.h" 46 #include "highlight.h" 47 #include "../util/motif.h" 48 #include "../util/misc.h" 49 #include "../util/DialogF.h" 50 #include "../util/system.h" 51 #include "../util/nedit_malloc.h" 52 53 #include <locale.h> 54 #include <stdlib.h> 55 #include <stdio.h> 56 #include <string.h> 57 58 #include "version.h" 59 60 #ifndef __MVS__ 61 #include <sys/param.h> 62 #endif 63 64 65 #include <Xm/Xm.h> 66 #include <Xm/XmP.h> /* These are for applying style info to help text */ 67 #include <Xm/Form.h> 68 #include <Xm/PrimitiveP.h> 69 #include <Xm/ScrolledW.h> 70 #include <Xm/ScrollBar.h> 71 #include <Xm/PushB.h> 72 #ifdef EDITRES 73 #include <X11/Xmu/Editres.h> 74 /* extern void _XEditResCheckMessages(); */ 75 #endif /* EDITRES */ 76 77 #ifdef HAVE_DEBUG_H 78 #include "../debug.h" 79 #endif 80 81 /*============================================================================*/ 82 /* SYMBOL DEFINITIONS */ 83 /*============================================================================*/ 84 85 #define EOS '\0' /* end-of-string character */ 86 87 #define CLICK_THRESHOLD 5 /* number of pixels mouse may move from its */ 88 /* pressed location for mouse-up to be */ 89 /* considered a valid click (as opposed to */ 90 /* a drag or mouse-pick error) */ 91 92 /*============================================================================*/ 93 /* VARIABLE DECLARATIONS */ 94 /*============================================================================*/ 95 96 static Widget HelpWindows[NUM_TOPICS] = {NULL}; 97 static Widget HelpTextPanes[NUM_TOPICS] = {NULL}; 98 static textBuffer *HelpStyleBuffers[NUM_TOPICS] = {NULL}; 99 static int navHistForw[NUM_TOPICS]; 100 static int navHistBack[NUM_TOPICS]; 101 102 /* Information on the last search for search-again */ 103 static char LastSearchString[DF_MAX_PROMPT_LENGTH] = ""; 104 static int LastSearchTopic = -1; 105 static int LastSearchPos = 0; 106 static int LastSearchWasAllTopics = False; 107 108 /* Fonts for each help text style generated by the help generator (setext). 109 The NEdit text widget uses the first help style, 'A', to calculate window 110 width, so making 'A' a fixed font will yield window widths calibrated to 111 match width-dependent fixed font layouts in the help text. */ 112 static enum helpFonts StyleFonts[] = 113 { 114 /* Fixed fonts, styles: 'A', 'B', 'C', 'D' */ 115 FIXED_HELP_FONT, BOLD_FIXED_HELP_FONT, ITALIC_FIXED_HELP_FONT, 116 BOLD_ITALIC_FIXED_HELP_FONT, 117 118 /* Underlined fixed fonts, styles: 'E', 'F', 'G', 'H' */ 119 FIXED_HELP_FONT, BOLD_FIXED_HELP_FONT, ITALIC_FIXED_HELP_FONT, 120 BOLD_ITALIC_FIXED_HELP_FONT, 121 122 /* Normal (proportional) fonts, styles: 'I', 'J', 'K', 'L' */ 123 HELP_FONT, BOLD_HELP_FONT, ITALIC_HELP_FONT, BOLD_ITALIC_HELP_FONT, 124 125 /* Underlined fonts, styles: 'M', 'N', 'O', 'P' */ 126 HELP_FONT, BOLD_HELP_FONT, ITALIC_HELP_FONT, BOLD_ITALIC_HELP_FONT, 127 128 /* Link font, style: 'Q' */ 129 HELP_FONT, 130 131 /* Heading fonts, styles: 'R', 'S', 'T' */ 132 H1_HELP_FONT, H2_HELP_FONT, H3_HELP_FONT 133 }; 134 135 static int StyleUnderlines[] = 136 { 137 /* Fixed fonts, styles: 'A', 'B', 'C', 'D' */ 138 False, False, False, False, 139 140 /* Underlined fixed fonts, styles: 'E', 'F', 'G', 'H' */ 141 True, True, True, True, 142 143 /* Normal (proportional) fonts, styles: 'I', 'J', 'K', 'L' */ 144 False, False, False, False, 145 146 /* Underlined fonts, styles: 'M', 'N', 'O', 'P' */ 147 True, True, True, True, 148 149 /* Link font, style: 'Q' */ 150 True, 151 152 /* Heading fonts, styles: 'R', 'S', 'T' */ 153 False, False, False 154 }; 155 156 #define N_STYLES (XtNumber(StyleFonts)) 157 158 static styleTableEntry HelpStyleInfo[ N_STYLES ]; 159 160 static int HelpZoom; 161 162 /* Translation table for style codes (A, B, C, ...) to their ASCII codes. 163 For systems using ASCII, this is just a one-to-one mapping, but the 164 table makes it possible to use the style codes also on an EBCDIC system. 165 */ 166 static unsigned char AlphabetToAsciiTable[256]; 167 168 /* Macro that calculates the zero-based index for a given style, taking 169 into account that the character set may not use ASCII coding, but EBCDIC. 170 The "style" argument must be one of the characters A - Z. 171 In ASCII, this comes down to "style - STYLE_PLAIN". */ 172 #define STYLE_INDEX(style) \ 173 (AlphabetToAsciiTable[(unsigned char)style] - \ 174 AlphabetToAsciiTable[(unsigned char)STYLE_PLAIN]) 175 176 /*============================================================================*/ 177 /* PROGRAM PROTOTYPES */ 178 /*============================================================================*/ 179 180 static Widget createHelpPanel(enum HelpTopic topic); 181 static void closeCB(Widget w, XtPointer clientData, XtPointer callData); 182 static void prevTopicCB(Widget w, XtPointer clientData, XtPointer callData); 183 static void nextTopicCB(Widget w, XtPointer clientData, XtPointer callData); 184 static void bwHistoryCB(Widget w, XtPointer clientData, XtPointer callData); 185 static void fwHistoryCB(Widget w, XtPointer clientData, XtPointer callData); 186 static void searchHelpCB(Widget w, XtPointer clientData, XtPointer callData); 187 static void searchHelpAgainCB(Widget w, XtPointer clientData, 188 XtPointer callData); 189 static void printCB(Widget w, XtPointer clientData, XtPointer callData); 190 static char *stitch(Widget parent, char **string_list,char **styleMap); 191 static void searchHelpText(Widget parent, int parentTopic, 192 const char *searchFor, int allSections, int startPos, int startTopic); 193 static void changeWindowTopic(int existingTopic, enum HelpTopic newTopic); 194 static int findTopicFromShellWidget(Widget shellWidget); 195 static void loadFontsAndColors(Widget parent, int style); 196 static void initNavigationHistory(void); 197 198 #ifdef HAVE__XMVERSIONSTRING 199 extern char _XmVersionString[]; 200 #else 201 static char _XmVersionString[] = "unknown"; 202 #endif 203 204 /*============================================================================*/ 205 /*================================= PROGRAMS =================================*/ 206 /*============================================================================*/ 207 208 /* 209 ** Create a string containing information on the build environment. Returned 210 ** string must NOT be freed by caller. 211 */ 212 213 static char *bldInfoString = NULL; 214 215 static void freeBuildInfo(void) 216 { 217 /* This keeps memory leak detectors happy */ 218 NEditFree(bldInfoString); 219 } 220 221 static const char *const warning = 222 "\nThis XNEdit was built with a known-bad version of Motif. Please " 223 "do not report any bugs you encounter unless you can reproduce " 224 "them with a known-good binary from the unixwork.de/xnedit/ website. " 225 "If this binary was supplied with your Linux distribution please " 226 "file a bug report with them asking them to build XNEdit with a " 227 "known-good version of Motif.\n"; 228 229 230 static const char *getBuildInfo(void) 231 { 232 static const char *bldFormat = 233 "%s\n" 234 " Built on: %s, %s, %s\n" 235 " Built at: %s, %s\n" 236 " With Motif: %s%d.%d.%d [%s]\n" 237 "Running Motif: %d.%d [%s]\n" 238 " Server: %s %d\n" 239 " Visual: %s\n" 240 " Locale: %s\n" 241 ; 242 243 static const char *visualClass[] = {"StaticGray", "GrayScale", 244 "StaticColor", "PseudoColor", 245 "TrueColor", "DirectColor"}; 246 247 static const char *const stabilities[] = {"", "(Untested) ", "(Known Bad) "}; 248 249 if (bldInfoString == NULL) 250 { 251 const char *locale; 252 char visualStr[500] = "<unknown>"; 253 const enum MotifStability stab = GetMotifStability(); 254 255 if (TheDisplay) { 256 Visual *visual; 257 int depth; 258 Colormap map; 259 Boolean usingDefaultVisual = FindBestVisual(TheDisplay, APP_NAME, 260 APP_CLASS, &visual, 261 &depth, &map); 262 sprintf(visualStr,"%d-bit %s (ID %#lx%s)", 263 depth, 264 visualClass[visual->class], 265 visual->visualid, 266 usingDefaultVisual ? ", Default" : ""); 267 } 268 269 bldInfoString = (char*)NEditMalloc(strlen(bldFormat) + strlen(warning) + 1024); 270 locale = setlocale(LC_MESSAGES, ""); 271 272 #if defined(XNEDIT_IS_RELEASE) || !defined(XNEDIT_GIT_REV) 273 const char *xneVersion = NEditVersion; 274 #else 275 const char *xneVersion = XNEDIT_VERSION "\n"; 276 #endif 277 sprintf(bldInfoString, bldFormat, 278 xneVersion, 279 COMPILE_OS, COMPILE_MACHINE, COMPILE_COMPILER, 280 linkdate, linktime, 281 stabilities[stab], XmVERSION, XmREVISION, XmUPDATE_LEVEL, 282 XmVERSION_STRING, 283 xmUseVersion/1000, xmUseVersion%1000, 284 _XmVersionString, 285 (NULL == TheDisplay ? "<unknown>" : ServerVendor(TheDisplay)), 286 (NULL == TheDisplay ? 0 : VendorRelease(TheDisplay)), 287 visualStr, 288 locale ? locale : "None"); 289 290 if (stab == MotifKnownBad) 291 strcat(bldInfoString, warning); 292 293 atexit(freeBuildInfo); 294 } 295 296 return bldInfoString; 297 } 298 299 /* 300 ** Initialization for help system data, needs to be done only once. 301 */ 302 static void initHelpStyles (Widget parent) 303 { 304 static int styleTableInitialized = False; 305 306 if (! styleTableInitialized) 307 { 308 Pixel fg; 309 int styleIndex; 310 char ** line; 311 312 XtVaGetValues(parent, XtNforeground, &fg, NULL); 313 314 for (styleIndex = 0; styleIndex < STL_HD + MAX_HEADING; styleIndex++) 315 { 316 HelpStyleInfo[ styleIndex ].color = PixelToColor(parent, fg); 317 HelpStyleInfo[ styleIndex ].underline = StyleUnderlines[styleIndex]; 318 HelpStyleInfo[ styleIndex ].font = NULL; 319 } 320 321 styleTableInitialized = True; 322 323 /*------------------------------------------------------- 324 * Only attempt to add build information to version text 325 * when string formatting symbols are present in the text. 326 * This special case is needed to incorporate this 327 * dynamically created information into the static help. 328 *-------------------------------------------------------*/ 329 for (line = HelpText[ HELP_VERSION ]; *line != NULL; line++) 330 { 331 /*-------------------------------------------------- 332 * If and when this printf format is found in the 333 * version help text, replace that line with the 334 * build information. Then stitching the help text 335 * will have the final count of characters to use. 336 *--------------------------------------------------*/ 337 if (strstr (*line, "%s") != NULL) 338 { 339 const char * bldInfo = getBuildInfo(); 340 char * text = (char*)NEditMalloc(strlen (*line) + strlen (bldInfo)); 341 sprintf (text, *line, bldInfo); 342 *line = text; 343 break; 344 } 345 } 346 347 /*--------------------------------------------------------- 348 * Also initialize the alphabet-to-ASCII-code table (to 349 * make the style mapping also work on EBCDIC). 350 * DON'T use 'A' to initialize the table! 'A' != 65 in EBCDIC. 351 *--------------------------------------------------------*/ 352 AlphabetToAsciiTable[(unsigned char)'A'] = ASCII_A + 0; 353 AlphabetToAsciiTable[(unsigned char)'B'] = ASCII_A + 1; 354 AlphabetToAsciiTable[(unsigned char)'C'] = ASCII_A + 2; 355 AlphabetToAsciiTable[(unsigned char)'D'] = ASCII_A + 3; 356 AlphabetToAsciiTable[(unsigned char)'E'] = ASCII_A + 4; 357 AlphabetToAsciiTable[(unsigned char)'F'] = ASCII_A + 5; 358 AlphabetToAsciiTable[(unsigned char)'G'] = ASCII_A + 6; 359 AlphabetToAsciiTable[(unsigned char)'H'] = ASCII_A + 7; 360 AlphabetToAsciiTable[(unsigned char)'I'] = ASCII_A + 8; 361 AlphabetToAsciiTable[(unsigned char)'J'] = ASCII_A + 9; 362 AlphabetToAsciiTable[(unsigned char)'K'] = ASCII_A + 10; 363 AlphabetToAsciiTable[(unsigned char)'L'] = ASCII_A + 11; 364 AlphabetToAsciiTable[(unsigned char)'M'] = ASCII_A + 12; 365 AlphabetToAsciiTable[(unsigned char)'N'] = ASCII_A + 13; 366 AlphabetToAsciiTable[(unsigned char)'O'] = ASCII_A + 14; 367 AlphabetToAsciiTable[(unsigned char)'P'] = ASCII_A + 15; 368 AlphabetToAsciiTable[(unsigned char)'Q'] = ASCII_A + 16; 369 AlphabetToAsciiTable[(unsigned char)'R'] = ASCII_A + 17; 370 AlphabetToAsciiTable[(unsigned char)'S'] = ASCII_A + 18; 371 AlphabetToAsciiTable[(unsigned char)'T'] = ASCII_A + 19; 372 AlphabetToAsciiTable[(unsigned char)'U'] = ASCII_A + 20; 373 AlphabetToAsciiTable[(unsigned char)'V'] = ASCII_A + 21; 374 AlphabetToAsciiTable[(unsigned char)'W'] = ASCII_A + 22; 375 AlphabetToAsciiTable[(unsigned char)'X'] = ASCII_A + 23; 376 AlphabetToAsciiTable[(unsigned char)'Y'] = ASCII_A + 24; 377 AlphabetToAsciiTable[(unsigned char)'Z'] = ASCII_A + 25; 378 } 379 } 380 381 /* 382 ** Help fonts are not loaded until they're actually needed. This function 383 ** checks if the style's font is loaded, and loads it if it's not. 384 */ 385 static void loadFontsAndColors(Widget parent, int style) 386 { 387 Display *dp = XtDisplay(parent); 388 389 NFont *font; 390 int r,g,b; 391 if (HelpStyleInfo[STYLE_INDEX(style)].font == NULL) 392 { 393 font = FontFromName( 394 dp, 395 GetPrefHelpFontName(StyleFonts[STYLE_INDEX(style)])); 396 397 if (font == NULL) 398 { 399 fprintf(stderr, "XNEdit: help font, %s, not available\n", 400 GetPrefHelpFontName(StyleFonts[STYLE_INDEX(style)])); 401 font = FontFromName(dp, "Monospace"); 402 if (font == NULL) 403 { 404 fprintf(stderr, "XNEdit: fallback help font, \"fixed\", not " 405 "available, cannot continue\n"); 406 exit(EXIT_FAILURE); 407 } 408 } 409 HelpStyleInfo[STYLE_INDEX(style)].font = font; 410 411 if (style == STL_NM_LINK) 412 HelpStyleInfo[STYLE_INDEX(style)].color = PixelToColor(parent, 413 AllocColor(parent, GetPrefHelpLinkColor(), &r, &g, &b)); 414 } 415 } 416 417 static void adaptNavigationButtons(int topic) { 418 Widget btn; 419 420 if(HelpWindows[topic] == NULL) 421 return; /* Shouldn't happen */ 422 423 btn=XtNameToWidget(HelpWindows[topic], "helpForm.prevTopic"); 424 if(btn) 425 { 426 if(topic > 0) 427 XtSetSensitive(btn, True); 428 else 429 XtSetSensitive(btn, False); 430 } 431 432 btn=XtNameToWidget(HelpWindows[topic], "helpForm.nextTopic"); 433 if(btn) 434 { 435 if(topic < (NUM_TOPICS - 1)) 436 XtSetSensitive(btn, True); 437 else 438 XtSetSensitive(btn, False); 439 } 440 441 btn=XtNameToWidget(HelpWindows[topic], "helpForm.histBack"); 442 if(btn) 443 { 444 if(navHistBack[topic] != -1) 445 XtSetSensitive(btn, True); 446 else 447 XtSetSensitive(btn, False); 448 } 449 450 btn=XtNameToWidget(HelpWindows[topic], "helpForm.histForw"); 451 if(btn) 452 { 453 if(navHistForw[topic] != -1) 454 XtSetSensitive(btn, True); 455 else 456 XtSetSensitive(btn, False); 457 } 458 459 } 460 461 /* 462 ** Put together stored help strings to create the text and optionally the style 463 ** information for a given help topic. 464 */ 465 static char * stitch ( 466 467 Widget parent, /* used for dynamic font/color allocation */ 468 char ** string_list, /* given help strings to stitch together */ 469 char ** styleMap /* NULL, or a place to store help styles */ 470 ) 471 { 472 char * cp; 473 char * section, * sp; /* resulting help text section */ 474 char * styleData, * sdp; /* resulting style data for text */ 475 char style = STYLE_PLAIN; /* start off each section with this style */ 476 int total_size = 0; /* help text section size */ 477 char ** crnt_line; 478 479 /*---------------------------------------------------- 480 * How many characters are there going to be displayed? 481 *----------------------------------------------------*/ 482 for (crnt_line = string_list; *crnt_line != NULL; crnt_line++) 483 { 484 for (cp = *crnt_line; *cp != EOS; cp++) 485 { 486 /*--------------------------------------------- 487 * The help text has embedded style information 488 * consisting of the style marker and a single 489 * character style, for a total of 2 characters. 490 * This style information is not to be included 491 * in the character counting below. 492 *---------------------------------------------*/ 493 if (*cp != STYLE_MARKER) { 494 total_size++; 495 } 496 else { 497 cp++; /* skipping style marker, loop will handle style */ 498 } 499 } 500 } 501 502 /*-------------------------------------------------------- 503 * Get the needed space, one area for the help text being 504 * stitched together, another for the styles to be applied. 505 *--------------------------------------------------------*/ 506 sp = section = (char*)NEditMalloc(total_size +1); 507 sdp = styleData = (styleMap) ? (char*)NEditMalloc(total_size +1) : NULL; 508 *sp = EOS; 509 510 /*-------------------------------------------- 511 * Fill in the newly acquired contiguous space 512 * with help text and style information. 513 *--------------------------------------------*/ 514 for (crnt_line = string_list; *crnt_line != NULL; crnt_line++) 515 { 516 for (cp = *crnt_line; *cp != EOS; cp++) 517 { 518 if (*cp == STYLE_MARKER) 519 { 520 style = *(++cp); 521 loadFontsAndColors(parent, style); 522 } else 523 { 524 *(sp++) = *cp; 525 526 /* Beware of possible EBCDIC coding! Use the mapping table. */ 527 if (styleMap) 528 *(sdp++) = AlphabetToAsciiTable[(unsigned char)style]; 529 } 530 } 531 } 532 533 *sp = EOS; 534 535 /*----------------------------------------- 536 * Only deal with style map, when available. 537 *-----------------------------------------*/ 538 if (styleMap) { 539 *styleMap = styleData; 540 *sdp = EOS; 541 } 542 543 return section; 544 } 545 546 /* 547 ** Display help for subject "topic". "parent" is a widget over which the help 548 ** dialog may be posted. Help dialogs are preserved when popped down by the 549 ** user, and may appear posted over a previous parent, regardless of the parent 550 ** argument. 551 */ 552 void Help(enum HelpTopic topic) 553 { 554 if (HelpWindows[topic] != NULL) 555 RaiseShellWindow(HelpWindows[topic], True); 556 else 557 HelpWindows[topic] = createHelpPanel(topic); 558 adaptNavigationButtons(topic); 559 } 560 561 562 /* Setup Window/Icon title for the help window. */ 563 static void setHelpWinTitle(Widget win, enum HelpTopic topic) 564 { 565 char * buf, *topStr=HelpTitles[topic]; 566 567 buf=(char*)NEditMalloc(strlen(topStr) + 24); 568 topic++; 569 570 sprintf(buf, "XNEdit Help (%d)", (int)topic); 571 XtVaSetValues(win, XmNiconName, buf, NULL); 572 573 sprintf(buf, "XNEdit Help: %s (%d)", topStr, (int)topic); 574 XtVaSetValues(win, XmNtitle, buf, NULL); 575 576 free(buf); 577 } 578 579 /* 580 ** Create a new help window displaying a given subject, "topic" 581 ** 582 ** Important hint: If this widget is restructured or the name of the text 583 ** subwidget is changed don't forget to adapt the default translations of the 584 ** help text. They are located in nedit.c, look for 585 ** static char *fallbackResources 586 ** (currently: nedit.helpForm.sw.helpText*translations...) 587 */ 588 static Widget createHelpPanel(enum HelpTopic topic) 589 { 590 Arg al[50]; 591 int ac; 592 Widget appShell, btn, closeBtn, form, btnFW; 593 Widget sw, hScrollBar, vScrollBar; 594 XmString st1; 595 char * helpText = NULL; 596 char * styleData = NULL; 597 598 ac = 0; 599 XtSetArg(al[ac], XmNdeleteResponse, XmDO_NOTHING); ac++; 600 appShell = CreateWidget(TheAppShell, "help", 601 topLevelShellWidgetClass, al, ac); 602 AddSmallIcon(appShell); 603 /* With openmotif 2.1.30, a crash may occur when the text widget of the 604 help window is (slowly) resized to a zero width. By imposing a 605 minimum _window_ width, we can work around this problem. The minimum 606 width should be larger than the width of the scrollbar. 50 is probably 607 a safe value; this leaves room for a few characters */ 608 XtVaSetValues(appShell, XtNminWidth, 50, NULL); 609 form = XtVaCreateManagedWidget("helpForm", xmFormWidgetClass, appShell, 610 NULL); 611 XtVaSetValues(form, XmNshadowThickness, 0, NULL); 612 613 /* Create the bottom row of buttons */ 614 btn = XtVaCreateManagedWidget("find", xmPushButtonWidgetClass, form, 615 XmNlabelString, st1=XmStringCreateSimple("Find..."), 616 XmNmnemonic, 'F', 617 XmNbottomAttachment, XmATTACH_FORM, 618 XmNleftAttachment, XmATTACH_POSITION, 619 XmNleftPosition, 3, 620 XmNrightAttachment, XmATTACH_POSITION, 621 XmNrightPosition, 25, 622 NULL); 623 XtAddCallback(btn, XmNactivateCallback, searchHelpCB, appShell); 624 XmStringFree(st1); 625 626 btn = XtVaCreateManagedWidget("findAgain", xmPushButtonWidgetClass, form, 627 XmNlabelString, st1=XmStringCreateSimple("Find Again"), 628 XmNmnemonic, 'A', 629 XmNbottomAttachment, XmATTACH_FORM, 630 XmNleftAttachment, XmATTACH_POSITION, 631 XmNleftPosition, 27, 632 XmNrightAttachment, XmATTACH_POSITION, 633 XmNrightPosition, 49, 634 NULL); 635 XtAddCallback(btn, XmNactivateCallback, searchHelpAgainCB, appShell); 636 XmStringFree(st1); 637 638 btn = XtVaCreateManagedWidget("print", xmPushButtonWidgetClass, form, 639 XmNlabelString, st1=XmStringCreateSimple("Print..."), 640 XmNmnemonic, 'P', 641 XmNbottomAttachment, XmATTACH_FORM, 642 XmNleftAttachment, XmATTACH_POSITION, 643 XmNleftPosition, 51, 644 XmNrightAttachment, XmATTACH_POSITION, 645 XmNrightPosition, 73, 646 NULL); 647 XtAddCallback(btn, XmNactivateCallback, printCB, appShell); 648 XmStringFree(st1); 649 650 closeBtn = XtVaCreateManagedWidget("close", 651 xmPushButtonWidgetClass, form, 652 XmNlabelString, st1=XmStringCreateSimple("Close"), 653 XmNbottomAttachment, XmATTACH_FORM, 654 XmNleftAttachment, XmATTACH_POSITION, 655 XmNleftPosition, 75, 656 XmNrightAttachment, XmATTACH_POSITION, 657 XmNrightPosition, 97, 658 NULL); 659 XtAddCallback(closeBtn, XmNactivateCallback, closeCB, appShell); 660 XmStringFree(st1); 661 662 /* Create the next row of buttons (for navigation) */ 663 btn = XtVaCreateManagedWidget("prevTopic", xmPushButtonWidgetClass, form, 664 XmNlabelString, st1=XmStringCreateSimple("<< Browse"), 665 XmNmnemonic, 'o', 666 XmNbottomAttachment, XmATTACH_WIDGET, 667 XmNbottomWidget, closeBtn, 668 XmNleftAttachment, XmATTACH_POSITION, 669 XmNleftPosition, 51, 670 XmNrightAttachment, XmATTACH_POSITION, 671 XmNrightPosition, 73, 672 NULL); 673 XtAddCallback(btn, XmNactivateCallback, prevTopicCB, appShell); 674 XmStringFree(st1); 675 676 btn = XtVaCreateManagedWidget("nextTopic", xmPushButtonWidgetClass, form, 677 XmNlabelString, st1=XmStringCreateSimple("Browse >>"), 678 XmNmnemonic, 'e', 679 XmNbottomAttachment, XmATTACH_WIDGET, 680 XmNbottomWidget, closeBtn, 681 XmNleftAttachment, XmATTACH_POSITION, 682 XmNleftPosition, 75, 683 XmNrightAttachment, XmATTACH_POSITION, 684 XmNrightPosition, 97, 685 NULL); 686 XtAddCallback(btn, XmNactivateCallback, nextTopicCB, appShell); 687 XmStringFree(st1); 688 689 btn = XtVaCreateManagedWidget("histBack", xmPushButtonWidgetClass, form, 690 XmNlabelString, st1=XmStringCreateSimple("Back"), 691 XmNmnemonic, 'B', 692 XmNbottomAttachment, XmATTACH_WIDGET, 693 XmNbottomWidget, closeBtn, 694 XmNleftAttachment, XmATTACH_POSITION, 695 XmNleftPosition, 3, 696 XmNrightAttachment, XmATTACH_POSITION, 697 XmNrightPosition, 25, 698 NULL); 699 XtAddCallback(btn, XmNactivateCallback, bwHistoryCB, appShell); 700 XmStringFree(st1); 701 702 btnFW = XtVaCreateManagedWidget("histForw", xmPushButtonWidgetClass, form, 703 XmNlabelString, st1=XmStringCreateSimple("Forward"), 704 XmNmnemonic, 'w', 705 XmNbottomAttachment, XmATTACH_WIDGET, 706 XmNbottomWidget, closeBtn, 707 XmNleftAttachment, XmATTACH_POSITION, 708 XmNleftPosition, 27, 709 XmNrightAttachment, XmATTACH_POSITION, 710 XmNrightPosition, 49, 711 NULL); 712 XtAddCallback(btnFW, XmNactivateCallback, fwHistoryCB, appShell); 713 XmStringFree(st1); 714 715 /* Create a text widget inside of a scrolled window widget */ 716 sw = XtVaCreateManagedWidget("sw", xmScrolledWindowWidgetClass, form, 717 XmNshadowThickness, 2, 718 XmNtopAttachment, XmATTACH_FORM, 719 XmNleftAttachment, XmATTACH_FORM, 720 XmNrightAttachment, XmATTACH_FORM, 721 XmNbottomAttachment, XmATTACH_WIDGET, 722 XmNbottomWidget, btnFW, 723 NULL); 724 hScrollBar = XtVaCreateManagedWidget("hScrollBar", 725 xmScrollBarWidgetClass, sw, 726 XmNorientation, XmHORIZONTAL, 727 XmNrepeatDelay, 10, 728 NULL); 729 vScrollBar = XtVaCreateManagedWidget("vScrollBar", 730 xmScrollBarWidgetClass, sw, 731 XmNorientation, XmVERTICAL, 732 XmNrepeatDelay, 10, 733 NULL); 734 /* Make sure the fixed size help font is loaded, such that we can base 735 our text widget size calculation on it. */ 736 loadFontsAndColors(sw, 'A'); 737 HelpTextPanes[topic] = XtVaCreateManagedWidget("helpText", 738 textWidgetClass, sw, 739 textNXftFont, HelpStyleInfo[0].font, /* MUST correspond to 'A' above */ 740 textNrows, 30, 741 textNcolumns, 65, 742 textNbacklightCharTypes, NULL, 743 textNhScrollBar, hScrollBar, 744 textNvScrollBar, vScrollBar, 745 textNreadOnly, True, 746 textNcontinuousWrap, True, 747 textNautoShowInsertPos, True, 748 NULL); 749 XtVaSetValues(sw, XmNworkWindow, HelpTextPanes[topic], 750 XmNhorizontalScrollBar, hScrollBar, 751 XmNverticalScrollBar, vScrollBar, 752 NULL); 753 754 /* Initialize help style information, if it hasn't already been init'd */ 755 initHelpStyles (HelpTextPanes[topic]); 756 757 /* Put together the text to display and separate it into parallel text 758 and style data for display by the widget */ 759 helpText = stitch (HelpTextPanes[topic], HelpText[topic], &styleData); 760 761 /* Stuff the text into the widget's text buffer */ 762 BufSetAll (TextGetBuffer (HelpTextPanes[topic]) , helpText); 763 NEditFree(helpText); 764 765 /* Create a style buffer for the text widget and fill it with the style 766 data which was generated along with the text content */ 767 HelpStyleBuffers[topic] = BufCreate(); 768 BufSetAll(HelpStyleBuffers[topic], styleData); 769 NEditFree(styleData); 770 TextDAttachHighlightData(((TextWidget)HelpTextPanes[topic])->text.textD, 771 HelpStyleBuffers[topic], HelpStyleInfo, N_STYLES, '\0', NULL, NULL); 772 773 /* This shouldn't be necessary (what's wrong in text.c?) */ 774 HandleXSelections(HelpTextPanes[topic]); 775 776 /* Process dialog mnemonic keys */ 777 AddDialogMnemonicHandler(form, FALSE); 778 779 /* Set the default button */ 780 XtVaSetValues(form, XmNdefaultButton, closeBtn, NULL); 781 XtVaSetValues(form, XmNcancelButton, closeBtn, NULL); 782 783 /* realize all of the widgets in the new window */ 784 RealizeWithoutForcingPosition(appShell); 785 786 /* Give the text pane the initial focus */ 787 XmProcessTraversal(HelpTextPanes[topic], XmTRAVERSE_CURRENT); 788 789 /* Make close command in window menu gracefully prompt for close */ 790 AddMotifCloseCallback(appShell, closeCB, appShell); 791 792 /* Initialize navigation information, if it hasn't already been init'd */ 793 initNavigationHistory(); 794 795 /* Set the window title */ 796 setHelpWinTitle(appShell, topic); 797 798 799 #ifdef EDITRES 800 XtAddEventHandler (appShell, (EventMask)0, True, 801 (XtEventHandler)_XEditResCheckMessages, NULL); 802 #endif /* EDITRES */ 803 804 return appShell; 805 } 806 807 static void changeTopicOrRaise(int existingTopic, int newTopic) { 808 if(HelpWindows[newTopic] == NULL) 809 { 810 changeWindowTopic(existingTopic, (enum HelpTopic) newTopic); 811 adaptNavigationButtons(newTopic); 812 } else 813 { 814 RaiseShellWindow(HelpWindows[newTopic], True); 815 adaptNavigationButtons(existingTopic); 816 adaptNavigationButtons(newTopic); 817 } 818 819 } 820 821 /* 822 ** Callbacks for window controls 823 */ 824 static void closeCB(Widget w, XtPointer clientData, XtPointer callData) 825 { 826 int topic; 827 828 if ((topic = findTopicFromShellWidget((Widget)clientData)) == -1) 829 return; 830 831 /* I don't understand the mechanism by which this can be called with 832 HelpWindows[topic] as NULL, but it has happened */ 833 XtDestroyWidget(HelpWindows[topic]); 834 HelpWindows[topic] = NULL; 835 if (HelpStyleBuffers[topic] != NULL) 836 { 837 BufFree(HelpStyleBuffers[topic]); 838 HelpStyleBuffers[topic] = NULL; 839 } 840 } 841 842 static void prevTopicCB(Widget w, XtPointer clientData, XtPointer callData) 843 { int topic; 844 845 if ((topic = findTopicFromShellWidget((Widget)clientData)) == -1) 846 return; /* shouldn't happen */ 847 848 topic--; 849 if(topic >= 0) 850 changeTopicOrRaise(topic+1, topic); 851 } 852 853 static void nextTopicCB(Widget w, XtPointer clientData, XtPointer callData) 854 { int topic; 855 856 if ((topic = findTopicFromShellWidget((Widget)clientData)) == -1) 857 return; /* shouldn't happen */ 858 859 topic++; 860 if(topic < NUM_TOPICS) 861 changeTopicOrRaise(topic-1, topic); 862 } 863 864 static void bwHistoryCB(Widget w, XtPointer clientData, XtPointer callData) 865 { int topic, goTo; 866 867 if ((topic = findTopicFromShellWidget((Widget)clientData)) == -1) 868 return; /* shouldn't happen */ 869 870 goTo=navHistBack[topic]; 871 if(goTo >= 0 && goTo < NUM_TOPICS) 872 { 873 navHistForw[goTo]=topic; 874 changeTopicOrRaise(topic, goTo); 875 } 876 } 877 878 static void fwHistoryCB(Widget w, XtPointer clientData, XtPointer callData) 879 { int topic, goTo; 880 881 if ((topic = findTopicFromShellWidget((Widget)clientData)) == -1) 882 return; /* shouldn't happen */ 883 884 goTo=navHistForw[topic]; 885 if(goTo >= 0 && goTo < NUM_TOPICS) 886 { 887 navHistBack[goTo]=topic; 888 changeTopicOrRaise(topic, goTo); 889 } 890 } 891 892 static void searchHelpCB(Widget w, XtPointer clientData, XtPointer callData) 893 { 894 char promptText[DF_MAX_PROMPT_LENGTH]; 895 int response, topic; 896 static char **searchHistory = NULL; 897 static int nHistoryStrings = 0; 898 899 if ((topic = findTopicFromShellWidget((Widget)clientData)) == -1) 900 return; /* shouldn't happen */ 901 SetDialogFPromptHistory(searchHistory, nHistoryStrings); 902 response = DialogF(DF_PROMPT, HelpWindows[topic], 3, "Find", 903 "Search for: (use up arrow key to recall previous)", promptText, 904 "This Section", "All Sections", "Cancel"); 905 if (response == 3) 906 return; 907 AddToHistoryList(promptText, &searchHistory, &nHistoryStrings); 908 searchHelpText(HelpWindows[topic], topic, promptText, response == 2, 0, 0); 909 } 910 911 static void searchHelpAgainCB(Widget w, XtPointer clientData, 912 XtPointer callData) 913 { 914 int topic; 915 916 if ((topic = findTopicFromShellWidget((Widget)clientData)) == -1) 917 return; /* shouldn't happen */ 918 searchHelpText(HelpWindows[topic], topic, LastSearchString, 919 LastSearchWasAllTopics, LastSearchPos, LastSearchTopic); 920 } 921 922 static void printCB(Widget w, XtPointer clientData, XtPointer callData) 923 { 924 int topic, helpStringLen; 925 char *helpString; 926 927 if ((topic = findTopicFromShellWidget((Widget)clientData)) == -1) 928 return; /* shouldn't happen */ 929 930 helpString = TextGetWrapped(HelpTextPanes[topic], 0, 931 TextGetBuffer(HelpTextPanes[topic])->length, &helpStringLen); 932 PrintString(helpString, helpStringLen, HelpWindows[topic], 933 HelpTitles[topic]); 934 NEditFree(helpString); 935 } 936 937 938 /* 939 ** Find the topic and text position within that topic targeted by a hyperlink 940 ** with name "link_name". Returns true if the link was successfully interpreted. 941 */ 942 static int is_known_link(char *link_name, int *topic, int *textPosition) 943 { 944 Href * hypertext; 945 946 /*------------------------------ 947 * Direct topic links found here. 948 *------------------------------*/ 949 for (*topic=0; HelpTitles[*topic] != NULL; (*topic)++) 950 { 951 if (strcmp (link_name, HelpTitles[*topic]) == 0) 952 { 953 *textPosition = 0; 954 return 1; 955 } 956 } 957 958 /*------------------------------------ 959 * Links internal to topics found here. 960 *------------------------------------*/ 961 for (hypertext = &H_R[0]; hypertext != NULL; hypertext = hypertext->next) 962 { 963 if (strcmp (link_name, hypertext->source) == 0) 964 { 965 *topic = hypertext->topic; 966 *textPosition = hypertext->location; 967 return 1; 968 } 969 } 970 971 return 0; 972 } 973 974 /* 975 ** Find the text of a hyperlink from a clicked character position somewhere 976 ** within the hyperlink text, and display the help that it links to. 977 */ 978 static void followHyperlink(int topic, int charPosition, int newWindow) 979 { 980 textDisp *textD = ((TextWidget)HelpTextPanes[topic])->text.textD; 981 char * link_text; 982 int link_topic; 983 int link_pos; 984 int end = charPosition; 985 int begin = charPosition; 986 char whatStyle = BufGetCharacter(textD->styleBuffer, end); 987 988 /*-------------------------------------------------- 989 * Locate beginning and ending of current text style. 990 *--------------------------------------------------*/ 991 while (whatStyle == BufGetCharacter(textD->styleBuffer, ++end)); 992 while (whatStyle == BufGetCharacter(textD->styleBuffer, begin-1)) begin--; 993 994 link_text = BufGetRange (textD->buffer, begin, end); 995 996 if (is_known_link (link_text, &link_topic, &link_pos) ) 997 { 998 if (HelpWindows[link_topic] != NULL) 999 { 1000 RaiseShellWindow(HelpWindows[link_topic], True); 1001 } else 1002 { 1003 if (newWindow) 1004 { 1005 HelpWindows[link_topic] 1006 = createHelpPanel((enum HelpTopic) link_topic); 1007 } else 1008 { 1009 changeWindowTopic(topic, (enum HelpTopic) link_topic); 1010 } 1011 } 1012 navHistBack[link_topic] = topic; 1013 navHistForw[topic] = link_topic; 1014 TextSetCursorPos(HelpTextPanes[link_topic], link_pos); 1015 adaptNavigationButtons(link_topic); 1016 adaptNavigationButtons(topic); 1017 } 1018 NEditFree(link_text); 1019 } 1020 1021 static void helpFocusButtonsAP(Widget w, XEvent *event, String *args, 1022 Cardinal *nArgs) 1023 { 1024 XmProcessTraversal(w, XmTRAVERSE_NEXT_TAB_GROUP); 1025 } 1026 1027 /* 1028 * handler for help-button-action(<button-name>) 1029 * Calls the activate callback for the named button widget of the help text win. 1030 */ 1031 static void helpButtonActionAP(Widget w, XEvent *event, String *args, 1032 Cardinal *nArgs) 1033 { 1034 char buf[80]; 1035 int topic; 1036 Widget btn; 1037 1038 if(*nArgs != 1) 1039 { 1040 fprintf(stderr, "help-button-action: requires exactly one argument.\n"); 1041 return; 1042 } 1043 1044 /* Find the topic being displayed by this widget */ 1045 for (topic = 0; topic < NUM_TOPICS; topic++) 1046 if (HelpTextPanes[topic] == w) 1047 break; 1048 1049 if(topic == NUM_TOPICS || HelpWindows[topic] == NULL) 1050 return; /* Shouldn't happen */ 1051 1052 /* Compose the button widget name */ 1053 strcpy(&buf[0], "helpForm."); 1054 if (strlen(args[0]) <= 70) 1055 { 1056 strcat(&buf[0], args[0]); 1057 } else 1058 { 1059 fprintf(stderr, "help-button-action: argument too long"); 1060 return; 1061 } 1062 1063 btn=XtNameToWidget(HelpWindows[topic], buf); 1064 if (btn) 1065 { 1066 XtCallCallbacks(btn, XmNactivateCallback, HelpWindows[topic]); 1067 } else 1068 { 1069 fprintf(stderr, "help-button-action: invalid argument: %s\n", args[0]); 1070 } 1071 } 1072 1073 /* 1074 * Handler for action help-hyperlink() 1075 * Arguments: none - init: record event position 1076 * "current": if clicked on a link, follow link in same window 1077 * "new": if clicked on a link, follow link in new window 1078 * 1079 * With the 1st argument "current" or "new" this action can have two additional 1080 * arguments. These arguments must be valid names of XmText actions. 1081 * In this case, the action named in argument #2 is called if the action 1082 * help-hyperlink is about to follow the hyperlink. The Action in argument #3 1083 * is called if no hyperlink has been recognized at the current event position. 1084 */ 1085 static void helpHyperlinkAP(Widget w, XEvent *event, String *args, 1086 Cardinal *nArgs) 1087 { 1088 XButtonEvent *e = (XButtonEvent *)event; 1089 int topic; 1090 textDisp *textD = ((TextWidget)w)->text.textD; 1091 int clickedPos, newWin; 1092 static int pressX=0, pressY=0; 1093 1094 /* called without arguments we just record coordinates */ 1095 if (*nArgs == 0) 1096 { 1097 pressX = e->x; 1098 pressY = e->y; 1099 return; 1100 } 1101 1102 newWin = !strcmp(args[0], "new"); 1103 1104 if(!newWin && strcmp(args[0], "current")) { 1105 fprintf(stderr, "help-hyperlink: Unrecognized argument %s\n", args[0]); 1106 return; 1107 } 1108 1109 /* 1110 * If for any reason (pointer moved - drag!, no hyperlink found) 1111 * this action can't follow a hyperlink then execute the the action 1112 * named in arg #3 (if provided) 1113 */ 1114 if (abs(pressX - e->x) > CLICK_THRESHOLD 1115 || abs(pressY - e->y) > CLICK_THRESHOLD) 1116 { 1117 if (*nArgs == 3) 1118 XtCallActionProc(w, args[2], event, NULL, 0); 1119 return; 1120 } 1121 1122 clickedPos = TextDXYToCharPos(textD, e->x, e->y); 1123 /* Beware of possible EBCDIC coding! Use the mapping table. */ 1124 if (BufGetCharacter(textD->styleBuffer, clickedPos) != 1125 (char)AlphabetToAsciiTable[(unsigned char)STL_NM_LINK]) 1126 { 1127 if (*nArgs == 3) 1128 XtCallActionProc(w, args[2], event, NULL, 0); 1129 return; 1130 } 1131 1132 /* Find the topic being displayed by this widget */ 1133 for (topic = 0; topic < NUM_TOPICS; topic++) 1134 if (HelpTextPanes[topic] == w) 1135 break; 1136 1137 if (topic == NUM_TOPICS) 1138 { 1139 /* If we get here someone must have bound help-hyperlink to a non-help 1140 * text widget (!) Or some other really strange thing happened. 1141 */ 1142 if (*nArgs == 3) 1143 XtCallActionProc(w, args[2], event, NULL, 0); 1144 return; 1145 } 1146 1147 /* If the action help-hyperlink had 3 arguments execute the action 1148 * named in arg #2 before really following the link. 1149 */ 1150 if (*nArgs == 3) 1151 XtCallActionProc(w, args[1], event, NULL, 0); 1152 1153 followHyperlink(topic, clickedPos, newWin); 1154 } 1155 1156 /* 1157 ** Install the action for following hyperlinks in the help window 1158 */ 1159 void InstallHelpLinkActions(XtAppContext context) 1160 { 1161 static XtActionsRec Actions[] = 1162 { 1163 {"help-hyperlink", helpHyperlinkAP}, 1164 {"help-focus-buttons", helpFocusButtonsAP}, 1165 {"help-button-action", helpButtonActionAP} 1166 }; 1167 1168 XtAppAddActions(context, Actions, XtNumber(Actions)); 1169 } 1170 1171 /* 1172 ** Search the help text. If allSections is true, searches all of the help 1173 ** text, otherwise searches only in parentTopic. 1174 */ 1175 static void searchHelpText(Widget parent, int parentTopic, 1176 const char *searchFor, int allSections, int startPos, int startTopic) 1177 { 1178 int topic, beginMatch, endMatch; 1179 int found = False; 1180 char * helpText = NULL; 1181 1182 /* Search for the string */ 1183 for (topic=startTopic; topic<NUM_TOPICS; topic++) 1184 { 1185 if (!allSections && topic != parentTopic) 1186 continue; 1187 helpText = stitch(parent, HelpText[topic], NULL); 1188 1189 if (SearchString(helpText, searchFor, SEARCH_FORWARD, SEARCH_LITERAL, 1190 False, topic == startTopic ? startPos : 0, &beginMatch, 1191 &endMatch, NULL, NULL, GetPrefDelimiters())) 1192 { 1193 found = True; 1194 NEditFree(helpText); 1195 break; 1196 } 1197 NEditFree(helpText); 1198 } 1199 1200 if (!found) 1201 { 1202 if (startPos != 0 || (allSections && startTopic != 0)) 1203 { 1204 /* Wrap search */ 1205 searchHelpText(parent, parentTopic, searchFor, allSections, 0, 0); 1206 return; 1207 } 1208 DialogF(DF_INF, parent, 1, "String Not Found", "String Not Found", "OK"); 1209 return; 1210 } 1211 1212 /* update navigation history */ 1213 if (parentTopic != topic) 1214 { 1215 navHistForw[parentTopic]= topic; 1216 navHistBack[topic]= parentTopic; 1217 } 1218 1219 /* If the appropriate window is already up, bring it to the top, if not, 1220 make the parent window become this topic */ 1221 changeTopicOrRaise(parentTopic, topic); 1222 BufSelect(TextGetBuffer(HelpTextPanes[topic]), beginMatch, endMatch); 1223 TextSetCursorPos(HelpTextPanes[topic], endMatch); 1224 1225 /* Save the search information for search-again */ 1226 if (searchFor != LastSearchString) /* if srch-again avoid OSX overlap err */ 1227 strncpy(LastSearchString, searchFor, sizeof(LastSearchString)-1); 1228 LastSearchTopic = topic; 1229 LastSearchPos = endMatch; 1230 LastSearchWasAllTopics = allSections; 1231 } 1232 1233 /* 1234 ** Change a help window to display a new topic. (Help window data is stored 1235 ** and indexed by topic so if a given topic is already displayed or has been 1236 ** positioned by the user, it can be found and popped back up in the same 1237 ** place.) To change the topic displayed, the stored data has to be relocated. 1238 */ 1239 static void changeWindowTopic(int existingTopic, enum HelpTopic newTopic) 1240 { 1241 char *helpText, *styleData; 1242 1243 /* Relocate the window/widget/buffer information */ 1244 if (newTopic != existingTopic) 1245 { 1246 HelpWindows[newTopic] = HelpWindows[existingTopic]; 1247 HelpWindows[existingTopic] = NULL; 1248 HelpStyleBuffers[newTopic] = HelpStyleBuffers[existingTopic]; 1249 HelpStyleBuffers[existingTopic] = NULL; 1250 HelpTextPanes[newTopic] = HelpTextPanes[existingTopic]; 1251 HelpTextPanes[existingTopic] = NULL; 1252 setHelpWinTitle(HelpWindows[newTopic], newTopic); 1253 } 1254 1255 /* Set the existing text widget to display the new text. Because it's 1256 highlighted, we have to turn off highlighting before changing the 1257 displayed text to prevent the text widget from trying to apply the 1258 old, mismatched, highlighting to the new text */ 1259 helpText = stitch(HelpTextPanes[newTopic], HelpText[newTopic], &styleData); 1260 TextDAttachHighlightData(((TextWidget)HelpTextPanes[newTopic])->text.textD, 1261 NULL, NULL, 0, '\0', NULL, NULL); 1262 BufSetAll(TextGetBuffer(HelpTextPanes[newTopic]), helpText); 1263 NEditFree(helpText); 1264 BufSetAll(HelpStyleBuffers[newTopic], styleData); 1265 NEditFree(styleData); 1266 TextDAttachHighlightData(((TextWidget)HelpTextPanes[newTopic])->text.textD, 1267 HelpStyleBuffers[newTopic], HelpStyleInfo, N_STYLES, '\0', NULL, 1268 NULL); 1269 } 1270 1271 static int findTopicFromShellWidget(Widget shellWidget) 1272 { 1273 int i; 1274 1275 for (i=0; i<NUM_TOPICS; i++) 1276 if (shellWidget == HelpWindows[i]) 1277 return i; 1278 return -1; 1279 } 1280 1281 static void initNavigationHistory(void) { 1282 static int doInitNavigationHistory = True; 1283 int i; 1284 1285 if (doInitNavigationHistory) 1286 { 1287 for (i=0; i<NUM_TOPICS; i++) 1288 navHistBack[i] = navHistForw[i] = -1; 1289 1290 doInitNavigationHistory = False; 1291 } 1292 } 1293 1294 #if XmVersion == 2000 1295 /* amai: This function may be called before the Motif part 1296 is being initialized. The following, public interface 1297 is known to initialize at least xmUseVersion. 1298 That interface is declared in <Xm/Xm.h> in Motif 1.2 only. 1299 As for Motif 2.1 we don't need this call anymore. 1300 This also holds for the Motif 2.1 version of LessTif 1301 releases > 0.93.0. */ 1302 extern void XmRegisterConverters(void); 1303 #endif 1304 1305 void SetHelpZoom(Widget textWidget, int step) 1306 { 1307 Display *dp = XtDisplay(textWidget); 1308 HelpZoom += step; 1309 1310 for(int i=0;i<N_STYLES;i++) { 1311 if(HelpStyleInfo[i].font) { 1312 int font_sz = HelpStyleInfo[i].font->size + step; 1313 char *fontName = GetPrefHelpFontName(StyleFonts[STYLE_INDEX(i)]); 1314 1315 char *newFontName = ChangeFontSize(fontName, font_sz); 1316 1317 NFont *newFont = FontFromName(dp, newFontName); 1318 NEditFree(newFontName); 1319 1320 if(newFont) { 1321 FontUnref(HelpStyleInfo[i].font); 1322 HelpStyleInfo[i].font = newFont; 1323 } 1324 } 1325 } 1326 1327 XtVaSetValues(textWidget, textNXftFont, HelpStyleInfo[0].font, NULL); 1328 } 1329 1330 /* Print version info to stdout */ 1331 void PrintVersion(void) 1332 { 1333 const char *text; 1334 1335 #if XmVersion < 2001 1336 XmRegisterConverters(); /* see comment above */ 1337 #endif 1338 text = getBuildInfo(); 1339 puts (text); 1340 } 1341