#ifdef HAVE_CONFIG_H
#include "../config.h"
#endif
#include "help.h"
#include "textBuf.h"
#include "text.h"
#include "textP.h"
#include "textDisp.h"
#include "textSel.h"
#include "nedit.h"
#include "search.h"
#include "window.h"
#include "preferences.h"
#include "help_data.h"
#include "file.h"
#include "highlight.h"
#include "../util/motif.h"
#include "../util/misc.h"
#include "../util/DialogF.h"
#include "../util/system.h"
#include "../util/nedit_malloc.h"
#include <locale.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "version.h"
#ifndef __MVS__
#include <sys/param.h>
#endif
#include <Xm/Xm.h>
#include <Xm/XmP.h>
#include <Xm/Form.h>
#include <Xm/PrimitiveP.h>
#include <Xm/ScrolledW.h>
#include <Xm/ScrollBar.h>
#include <Xm/PushB.h>
#ifdef EDITRES
#include <X11/Xmu/Editres.h>
#endif
#ifdef HAVE_DEBUG_H
#include "../debug.h"
#endif
#define EOS '\0'
#define CLICK_THRESHOLD 5
static Widget HelpWindows[
NUM_TOPICS] = {
NULL};
static Widget HelpTextPanes[
NUM_TOPICS] = {
NULL};
static textBuffer *HelpStyleBuffers[
NUM_TOPICS] = {
NULL};
static int navHistForw[
NUM_TOPICS];
static int navHistBack[
NUM_TOPICS];
static char LastSearchString[
DF_MAX_PROMPT_LENGTH] =
"";
static int LastSearchTopic = -
1;
static int LastSearchPos =
0;
static int LastSearchWasAllTopics = False;
static enum helpFonts StyleFonts[] =
{
FIXED_HELP_FONT,
BOLD_FIXED_HELP_FONT,
ITALIC_FIXED_HELP_FONT,
BOLD_ITALIC_FIXED_HELP_FONT,
FIXED_HELP_FONT,
BOLD_FIXED_HELP_FONT,
ITALIC_FIXED_HELP_FONT,
BOLD_ITALIC_FIXED_HELP_FONT,
HELP_FONT,
BOLD_HELP_FONT,
ITALIC_HELP_FONT,
BOLD_ITALIC_HELP_FONT,
HELP_FONT,
BOLD_HELP_FONT,
ITALIC_HELP_FONT,
BOLD_ITALIC_HELP_FONT,
HELP_FONT,
H1_HELP_FONT,
H2_HELP_FONT,
H3_HELP_FONT
};
static int StyleUnderlines[] =
{
False, False, False, False,
True, True, True, True,
False, False, False, False,
True, True, True, True,
True,
False, False, False
};
#define N_STYLES (XtNumber(StyleFonts))
static styleTableEntry HelpStyleInfo[
N_STYLES ];
static int HelpZoom;
static unsigned char AlphabetToAsciiTable[
256];
#define STYLE_INDEX(style) \
(AlphabetToAsciiTable[(
unsigned char)style] - \
AlphabetToAsciiTable[(
unsigned char)
STYLE_PLAIN])
static Widget createHelpPanel(
enum HelpTopic topic);
static void closeCB(Widget w, XtPointer clientData, XtPointer callData);
static void prevTopicCB(Widget w, XtPointer clientData, XtPointer callData);
static void nextTopicCB(Widget w, XtPointer clientData, XtPointer callData);
static void bwHistoryCB(Widget w, XtPointer clientData, XtPointer callData);
static void fwHistoryCB(Widget w, XtPointer clientData, XtPointer callData);
static void searchHelpCB(Widget w, XtPointer clientData, XtPointer callData);
static void searchHelpAgainCB(Widget w, XtPointer clientData,
XtPointer callData);
static void printCB(Widget w, XtPointer clientData, XtPointer callData);
static char *stitch(Widget parent,
char **string_list,
char **styleMap);
static void searchHelpText(Widget parent,
int parentTopic,
const char *searchFor,
int allSections,
int startPos,
int startTopic);
static void changeWindowTopic(
int existingTopic,
enum HelpTopic newTopic);
static int findTopicFromShellWidget(Widget shellWidget);
static void loadFontsAndColors(Widget parent,
int style);
static void initNavigationHistory(
void);
#ifdef HAVE__XMVERSIONSTRING
extern char _XmVersionString[];
#else
static char _XmVersionString[] =
"unknown";
#endif
static char *bldInfoString =
NULL;
static void freeBuildInfo(
void)
{
NEditFree(bldInfoString);
}
static const char *
const warning =
"\nThis XNEdit was built with a known-bad version of Motif. Please "
"do not report any bugs you encounter unless you can reproduce "
"them with a known-good binary from the unixwork.de/xnedit/ website. "
"If this binary was supplied with your Linux distribution please "
"file a bug report with them asking them to build XNEdit with a "
"known-good version of Motif.\n";
static const char *getBuildInfo(
void)
{
static const char *bldFormat =
"%s\n"
" Built on: %s, %s, %s\n"
" Built at: %s, %s\n"
" With Motif: %s%d.%d.%d [%s]\n"
"Running Motif: %d.%d [%s]\n"
" Server: %s %d\n"
" Visual: %s\n"
" Locale: %s\n"
;
static const char *visualClass[] = {
"StaticGray",
"GrayScale",
"StaticColor",
"PseudoColor",
"TrueColor",
"DirectColor"};
static const char *
const stabilities[] = {
"",
"(Untested) ",
"(Known Bad) "};
if (bldInfoString ==
NULL)
{
const char *locale;
char visualStr[
500] =
"<unknown>";
const enum MotifStability stab = GetMotifStability();
if (TheDisplay) {
Visual *visual;
int depth;
Colormap map;
Boolean usingDefaultVisual = FindBestVisual(TheDisplay,
APP_NAME,
APP_CLASS, &visual,
&depth, &map);
sprintf(visualStr,
"%d-bit %s (ID %#lx%s)",
depth,
visualClass[visual->class],
visual->visualid,
usingDefaultVisual ?
", Default" :
"");
}
bldInfoString = (
char*)NEditMalloc(strlen(bldFormat) + strlen(warning) +
1024);
locale = setlocale(
LC_MESSAGES,
"");
#if defined(
XNEDIT_IS_RELEASE) || !defined(
XNEDIT_GIT_REV)
const char *xneVersion = NEditVersion;
#else
const char *xneVersion =
XNEDIT_VERSION "\n";
#endif
sprintf(bldInfoString, bldFormat,
xneVersion,
COMPILE_OS,
COMPILE_MACHINE,
COMPILE_COMPILER,
linkdate, linktime,
stabilities[stab], XmVERSION, XmREVISION, XmUPDATE_LEVEL,
XmVERSION_STRING,
xmUseVersion/
1000, xmUseVersion%
1000,
_XmVersionString,
(
NULL == TheDisplay ?
"<unknown>" : ServerVendor(TheDisplay)),
(
NULL == TheDisplay ?
0 : VendorRelease(TheDisplay)),
visualStr,
locale ? locale :
"None");
if (stab == MotifKnownBad)
strcat(bldInfoString, warning);
atexit(freeBuildInfo);
}
return bldInfoString;
}
static void initHelpStyles (Widget parent)
{
static int styleTableInitialized = False;
if (! styleTableInitialized)
{
Pixel fg;
int styleIndex;
char ** line;
XtVaGetValues(parent, XtNforeground, &fg,
NULL);
for (styleIndex =
0; styleIndex <
STL_HD +
MAX_HEADING; styleIndex++)
{
HelpStyleInfo[ styleIndex ].color = PixelToColor(parent, fg);
HelpStyleInfo[ styleIndex ].underline = StyleUnderlines[styleIndex];
HelpStyleInfo[ styleIndex ].font =
NULL;
}
styleTableInitialized = True;
for (line = HelpText[
HELP_VERSION ]; *line !=
NULL; line++)
{
if (strstr (*line,
"%s") !=
NULL)
{
const char * bldInfo = getBuildInfo();
char * text = (
char*)NEditMalloc(strlen (*line) + strlen (bldInfo));
sprintf (text, *line, bldInfo);
*line = text;
break;
}
}
AlphabetToAsciiTable[(
unsigned char)
'A'] =
ASCII_A +
0;
AlphabetToAsciiTable[(
unsigned char)
'B'] =
ASCII_A +
1;
AlphabetToAsciiTable[(
unsigned char)
'C'] =
ASCII_A +
2;
AlphabetToAsciiTable[(
unsigned char)
'D'] =
ASCII_A +
3;
AlphabetToAsciiTable[(
unsigned char)
'E'] =
ASCII_A +
4;
AlphabetToAsciiTable[(
unsigned char)
'F'] =
ASCII_A +
5;
AlphabetToAsciiTable[(
unsigned char)
'G'] =
ASCII_A +
6;
AlphabetToAsciiTable[(
unsigned char)
'H'] =
ASCII_A +
7;
AlphabetToAsciiTable[(
unsigned char)
'I'] =
ASCII_A +
8;
AlphabetToAsciiTable[(
unsigned char)
'J'] =
ASCII_A +
9;
AlphabetToAsciiTable[(
unsigned char)
'K'] =
ASCII_A +
10;
AlphabetToAsciiTable[(
unsigned char)
'L'] =
ASCII_A +
11;
AlphabetToAsciiTable[(
unsigned char)
'M'] =
ASCII_A +
12;
AlphabetToAsciiTable[(
unsigned char)
'N'] =
ASCII_A +
13;
AlphabetToAsciiTable[(
unsigned char)
'O'] =
ASCII_A +
14;
AlphabetToAsciiTable[(
unsigned char)
'P'] =
ASCII_A +
15;
AlphabetToAsciiTable[(
unsigned char)
'Q'] =
ASCII_A +
16;
AlphabetToAsciiTable[(
unsigned char)
'R'] =
ASCII_A +
17;
AlphabetToAsciiTable[(
unsigned char)
'S'] =
ASCII_A +
18;
AlphabetToAsciiTable[(
unsigned char)
'T'] =
ASCII_A +
19;
AlphabetToAsciiTable[(
unsigned char)
'U'] =
ASCII_A +
20;
AlphabetToAsciiTable[(
unsigned char)
'V'] =
ASCII_A +
21;
AlphabetToAsciiTable[(
unsigned char)
'W'] =
ASCII_A +
22;
AlphabetToAsciiTable[(
unsigned char)
'X'] =
ASCII_A +
23;
AlphabetToAsciiTable[(
unsigned char)
'Y'] =
ASCII_A +
24;
AlphabetToAsciiTable[(
unsigned char)
'Z'] =
ASCII_A +
25;
}
}
static void loadFontsAndColors(Widget parent,
int style)
{
Display *dp = XtDisplay(parent);
NFont *font;
int r,g,b;
if (HelpStyleInfo[
STYLE_INDEX(style)].font ==
NULL)
{
font = FontFromName(
dp,
GetPrefHelpFontName(StyleFonts[
STYLE_INDEX(style)]));
if (font ==
NULL)
{
fprintf(stderr,
"XNEdit: help font, %s, not available\n",
GetPrefHelpFontName(StyleFonts[
STYLE_INDEX(style)]));
font = FontFromName(dp,
"Monospace");
if (font ==
NULL)
{
fprintf(stderr,
"XNEdit: fallback help font, \"fixed\", not "
"available, cannot continue\n");
exit(
EXIT_FAILURE);
}
}
HelpStyleInfo[
STYLE_INDEX(style)].font = font;
if (style ==
STL_NM_LINK)
HelpStyleInfo[
STYLE_INDEX(style)].color = PixelToColor(parent,
AllocColor(parent, GetPrefHelpLinkColor(), &r, &g, &b));
}
}
static void adaptNavigationButtons(
int topic) {
Widget btn;
if(HelpWindows[topic] ==
NULL)
return;
btn=XtNameToWidget(HelpWindows[topic],
"helpForm.prevTopic");
if(btn)
{
if(topic >
0)
XtSetSensitive(btn, True);
else
XtSetSensitive(btn, False);
}
btn=XtNameToWidget(HelpWindows[topic],
"helpForm.nextTopic");
if(btn)
{
if(topic < (
NUM_TOPICS -
1))
XtSetSensitive(btn, True);
else
XtSetSensitive(btn, False);
}
btn=XtNameToWidget(HelpWindows[topic],
"helpForm.histBack");
if(btn)
{
if(navHistBack[topic] != -
1)
XtSetSensitive(btn, True);
else
XtSetSensitive(btn, False);
}
btn=XtNameToWidget(HelpWindows[topic],
"helpForm.histForw");
if(btn)
{
if(navHistForw[topic] != -
1)
XtSetSensitive(btn, True);
else
XtSetSensitive(btn, False);
}
}
static char * stitch (
Widget parent,
char ** string_list,
char ** styleMap
)
{
char * cp;
char * section, * sp;
char * styleData, * sdp;
char style =
STYLE_PLAIN;
int total_size =
0;
char ** crnt_line;
for (crnt_line = string_list; *crnt_line !=
NULL; crnt_line++)
{
for (cp = *crnt_line; *cp !=
EOS; cp++)
{
if (*cp !=
STYLE_MARKER) {
total_size++;
}
else {
cp++;
}
}
}
sp = section = (
char*)NEditMalloc(total_size +
1);
sdp = styleData = (styleMap) ? (
char*)NEditMalloc(total_size +
1) :
NULL;
*sp =
EOS;
for (crnt_line = string_list; *crnt_line !=
NULL; crnt_line++)
{
for (cp = *crnt_line; *cp !=
EOS; cp++)
{
if (*cp ==
STYLE_MARKER)
{
style = *(++cp);
loadFontsAndColors(parent, style);
}
else
{
*(sp++) = *cp;
if (styleMap)
*(sdp++) = AlphabetToAsciiTable[(
unsigned char)style];
}
}
}
*sp =
EOS;
if (styleMap) {
*styleMap = styleData;
*sdp =
EOS;
}
return section;
}
void Help(
enum HelpTopic topic)
{
if (HelpWindows[topic] !=
NULL)
RaiseShellWindow(HelpWindows[topic], True);
else
HelpWindows[topic] = createHelpPanel(topic);
adaptNavigationButtons(topic);
}
static void setHelpWinTitle(Widget win,
enum HelpTopic topic)
{
char * buf, *topStr=HelpTitles[topic];
buf=(
char*)NEditMalloc(strlen(topStr) +
24);
topic++;
sprintf(buf,
"XNEdit Help (%d)", (
int)topic);
XtVaSetValues(win, XmNiconName, buf,
NULL);
sprintf(buf,
"XNEdit Help: %s (%d)", topStr, (
int)topic);
XtVaSetValues(win, XmNtitle, buf,
NULL);
free(buf);
}
static Widget createHelpPanel(
enum HelpTopic topic)
{
Arg al[
50];
int ac;
Widget appShell, btn, closeBtn, form, btnFW;
Widget sw, hScrollBar, vScrollBar;
XmString st1;
char * helpText =
NULL;
char * styleData =
NULL;
ac =
0;
XtSetArg(al[ac], XmNdeleteResponse, XmDO_NOTHING); ac++;
appShell = CreateWidget(TheAppShell,
"help",
topLevelShellWidgetClass, al, ac);
AddSmallIcon(appShell);
XtVaSetValues(appShell, XtNminWidth,
50,
NULL);
form = XtVaCreateManagedWidget(
"helpForm", xmFormWidgetClass, appShell,
NULL);
XtVaSetValues(form, XmNshadowThickness,
0,
NULL);
btn = XtVaCreateManagedWidget(
"find", xmPushButtonWidgetClass, form,
XmNlabelString, st1=XmStringCreateSimple(
"Find..."),
XmNmnemonic,
'F',
XmNbottomAttachment, XmATTACH_FORM,
XmNleftAttachment, XmATTACH_POSITION,
XmNleftPosition,
3,
XmNrightAttachment, XmATTACH_POSITION,
XmNrightPosition,
25,
NULL);
XtAddCallback(btn, XmNactivateCallback, searchHelpCB, appShell);
XmStringFree(st1);
btn = XtVaCreateManagedWidget(
"findAgain", xmPushButtonWidgetClass, form,
XmNlabelString, st1=XmStringCreateSimple(
"Find Again"),
XmNmnemonic,
'A',
XmNbottomAttachment, XmATTACH_FORM,
XmNleftAttachment, XmATTACH_POSITION,
XmNleftPosition,
27,
XmNrightAttachment, XmATTACH_POSITION,
XmNrightPosition,
49,
NULL);
XtAddCallback(btn, XmNactivateCallback, searchHelpAgainCB, appShell);
XmStringFree(st1);
btn = XtVaCreateManagedWidget(
"print", xmPushButtonWidgetClass, form,
XmNlabelString, st1=XmStringCreateSimple(
"Print..."),
XmNmnemonic,
'P',
XmNbottomAttachment, XmATTACH_FORM,
XmNleftAttachment, XmATTACH_POSITION,
XmNleftPosition,
51,
XmNrightAttachment, XmATTACH_POSITION,
XmNrightPosition,
73,
NULL);
XtAddCallback(btn, XmNactivateCallback, printCB, appShell);
XmStringFree(st1);
closeBtn = XtVaCreateManagedWidget(
"close",
xmPushButtonWidgetClass, form,
XmNlabelString, st1=XmStringCreateSimple(
"Close"),
XmNbottomAttachment, XmATTACH_FORM,
XmNleftAttachment, XmATTACH_POSITION,
XmNleftPosition,
75,
XmNrightAttachment, XmATTACH_POSITION,
XmNrightPosition,
97,
NULL);
XtAddCallback(closeBtn, XmNactivateCallback, closeCB, appShell);
XmStringFree(st1);
btn = XtVaCreateManagedWidget(
"prevTopic", xmPushButtonWidgetClass, form,
XmNlabelString, st1=XmStringCreateSimple(
"<< Browse"),
XmNmnemonic,
'o',
XmNbottomAttachment, XmATTACH_WIDGET,
XmNbottomWidget, closeBtn,
XmNleftAttachment, XmATTACH_POSITION,
XmNleftPosition,
51,
XmNrightAttachment, XmATTACH_POSITION,
XmNrightPosition,
73,
NULL);
XtAddCallback(btn, XmNactivateCallback, prevTopicCB, appShell);
XmStringFree(st1);
btn = XtVaCreateManagedWidget(
"nextTopic", xmPushButtonWidgetClass, form,
XmNlabelString, st1=XmStringCreateSimple(
"Browse >>"),
XmNmnemonic,
'e',
XmNbottomAttachment, XmATTACH_WIDGET,
XmNbottomWidget, closeBtn,
XmNleftAttachment, XmATTACH_POSITION,
XmNleftPosition,
75,
XmNrightAttachment, XmATTACH_POSITION,
XmNrightPosition,
97,
NULL);
XtAddCallback(btn, XmNactivateCallback, nextTopicCB, appShell);
XmStringFree(st1);
btn = XtVaCreateManagedWidget(
"histBack", xmPushButtonWidgetClass, form,
XmNlabelString, st1=XmStringCreateSimple(
"Back"),
XmNmnemonic,
'B',
XmNbottomAttachment, XmATTACH_WIDGET,
XmNbottomWidget, closeBtn,
XmNleftAttachment, XmATTACH_POSITION,
XmNleftPosition,
3,
XmNrightAttachment, XmATTACH_POSITION,
XmNrightPosition,
25,
NULL);
XtAddCallback(btn, XmNactivateCallback, bwHistoryCB, appShell);
XmStringFree(st1);
btnFW = XtVaCreateManagedWidget(
"histForw", xmPushButtonWidgetClass, form,
XmNlabelString, st1=XmStringCreateSimple(
"Forward"),
XmNmnemonic,
'w',
XmNbottomAttachment, XmATTACH_WIDGET,
XmNbottomWidget, closeBtn,
XmNleftAttachment, XmATTACH_POSITION,
XmNleftPosition,
27,
XmNrightAttachment, XmATTACH_POSITION,
XmNrightPosition,
49,
NULL);
XtAddCallback(btnFW, XmNactivateCallback, fwHistoryCB, appShell);
XmStringFree(st1);
sw = XtVaCreateManagedWidget(
"sw", xmScrolledWindowWidgetClass, form,
XmNshadowThickness,
2,
XmNtopAttachment, XmATTACH_FORM,
XmNleftAttachment, XmATTACH_FORM,
XmNrightAttachment, XmATTACH_FORM,
XmNbottomAttachment, XmATTACH_WIDGET,
XmNbottomWidget, btnFW,
NULL);
hScrollBar = XtVaCreateManagedWidget(
"hScrollBar",
xmScrollBarWidgetClass, sw,
XmNorientation, XmHORIZONTAL,
XmNrepeatDelay,
10,
NULL);
vScrollBar = XtVaCreateManagedWidget(
"vScrollBar",
xmScrollBarWidgetClass, sw,
XmNorientation, XmVERTICAL,
XmNrepeatDelay,
10,
NULL);
loadFontsAndColors(sw,
'A');
HelpTextPanes[topic] = XtVaCreateManagedWidget(
"helpText",
textWidgetClass, sw,
textNXftFont, HelpStyleInfo[
0].font,
textNrows,
30,
textNcolumns,
65,
textNbacklightCharTypes,
NULL,
textNhScrollBar, hScrollBar,
textNvScrollBar, vScrollBar,
textNreadOnly, True,
textNcontinuousWrap, True,
textNautoShowInsertPos, True,
NULL);
XtVaSetValues(sw, XmNworkWindow, HelpTextPanes[topic],
XmNhorizontalScrollBar, hScrollBar,
XmNverticalScrollBar, vScrollBar,
NULL);
initHelpStyles (HelpTextPanes[topic]);
helpText = stitch (HelpTextPanes[topic], HelpText[topic], &styleData);
BufSetAll (TextGetBuffer (HelpTextPanes[topic]) , helpText);
NEditFree(helpText);
HelpStyleBuffers[topic] = BufCreate();
BufSetAll(HelpStyleBuffers[topic], styleData);
NEditFree(styleData);
TextDAttachHighlightData(((TextWidget)HelpTextPanes[topic])->text.textD,
HelpStyleBuffers[topic], HelpStyleInfo,
N_STYLES,
'\0',
NULL,
NULL);
HandleXSelections(HelpTextPanes[topic]);
AddDialogMnemonicHandler(form,
FALSE);
XtVaSetValues(form, XmNdefaultButton, closeBtn,
NULL);
XtVaSetValues(form, XmNcancelButton, closeBtn,
NULL);
RealizeWithoutForcingPosition(appShell);
XmProcessTraversal(HelpTextPanes[topic], XmTRAVERSE_CURRENT);
AddMotifCloseCallback(appShell, closeCB, appShell);
initNavigationHistory();
setHelpWinTitle(appShell, topic);
#ifdef EDITRES
XtAddEventHandler (appShell, (EventMask)
0, True,
(XtEventHandler)_XEditResCheckMessages,
NULL);
#endif
return appShell;
}
static void changeTopicOrRaise(
int existingTopic,
int newTopic) {
if(HelpWindows[newTopic] ==
NULL)
{
changeWindowTopic(existingTopic, (
enum HelpTopic) newTopic);
adaptNavigationButtons(newTopic);
}
else
{
RaiseShellWindow(HelpWindows[newTopic], True);
adaptNavigationButtons(existingTopic);
adaptNavigationButtons(newTopic);
}
}
static void closeCB(Widget w, XtPointer clientData, XtPointer callData)
{
int topic;
if ((topic = findTopicFromShellWidget((Widget)clientData)) == -
1)
return;
XtDestroyWidget(HelpWindows[topic]);
HelpWindows[topic] =
NULL;
if (HelpStyleBuffers[topic] !=
NULL)
{
BufFree(HelpStyleBuffers[topic]);
HelpStyleBuffers[topic] =
NULL;
}
}
static void prevTopicCB(Widget w, XtPointer clientData, XtPointer callData)
{
int topic;
if ((topic = findTopicFromShellWidget((Widget)clientData)) == -
1)
return;
topic--;
if(topic >=
0)
changeTopicOrRaise(topic+
1, topic);
}
static void nextTopicCB(Widget w, XtPointer clientData, XtPointer callData)
{
int topic;
if ((topic = findTopicFromShellWidget((Widget)clientData)) == -
1)
return;
topic++;
if(topic <
NUM_TOPICS)
changeTopicOrRaise(topic-
1, topic);
}
static void bwHistoryCB(Widget w, XtPointer clientData, XtPointer callData)
{
int topic, goTo;
if ((topic = findTopicFromShellWidget((Widget)clientData)) == -
1)
return;
goTo=navHistBack[topic];
if(goTo >=
0 && goTo <
NUM_TOPICS)
{
navHistForw[goTo]=topic;
changeTopicOrRaise(topic, goTo);
}
}
static void fwHistoryCB(Widget w, XtPointer clientData, XtPointer callData)
{
int topic, goTo;
if ((topic = findTopicFromShellWidget((Widget)clientData)) == -
1)
return;
goTo=navHistForw[topic];
if(goTo >=
0 && goTo <
NUM_TOPICS)
{
navHistBack[goTo]=topic;
changeTopicOrRaise(topic, goTo);
}
}
static void searchHelpCB(Widget w, XtPointer clientData, XtPointer callData)
{
char promptText[
DF_MAX_PROMPT_LENGTH];
int response, topic;
static char **searchHistory =
NULL;
static int nHistoryStrings =
0;
if ((topic = findTopicFromShellWidget((Widget)clientData)) == -
1)
return;
SetDialogFPromptHistory(searchHistory, nHistoryStrings);
response = DialogF(
DF_PROMPT, HelpWindows[topic],
3,
"Find",
"Search for: (use up arrow key to recall previous)", promptText,
"This Section",
"All Sections",
"Cancel");
if (response ==
3)
return;
AddToHistoryList(promptText, &searchHistory, &nHistoryStrings);
searchHelpText(HelpWindows[topic], topic, promptText, response ==
2,
0,
0);
}
static void searchHelpAgainCB(Widget w, XtPointer clientData,
XtPointer callData)
{
int topic;
if ((topic = findTopicFromShellWidget((Widget)clientData)) == -
1)
return;
searchHelpText(HelpWindows[topic], topic, LastSearchString,
LastSearchWasAllTopics, LastSearchPos, LastSearchTopic);
}
static void printCB(Widget w, XtPointer clientData, XtPointer callData)
{
int topic, helpStringLen;
char *helpString;
if ((topic = findTopicFromShellWidget((Widget)clientData)) == -
1)
return;
helpString = TextGetWrapped(HelpTextPanes[topic],
0,
TextGetBuffer(HelpTextPanes[topic])->length, &helpStringLen);
PrintString(helpString, helpStringLen, HelpWindows[topic],
HelpTitles[topic]);
NEditFree(helpString);
}
static int is_known_link(
char *link_name,
int *topic,
int *textPosition)
{
Href * hypertext;
for (*topic=
0; HelpTitles[*topic] !=
NULL; (*topic)++)
{
if (strcmp (link_name, HelpTitles[*topic]) ==
0)
{
*textPosition =
0;
return 1;
}
}
for (hypertext = &
H_R[
0]; hypertext !=
NULL; hypertext = hypertext->next)
{
if (strcmp (link_name, hypertext->source) ==
0)
{
*topic = hypertext->topic;
*textPosition = hypertext->location;
return 1;
}
}
return 0;
}
static void followHyperlink(
int topic,
int charPosition,
int newWindow)
{
textDisp *textD = ((TextWidget)HelpTextPanes[topic])->text.textD;
char * link_text;
int link_topic;
int link_pos;
int end = charPosition;
int begin = charPosition;
char whatStyle = BufGetCharacter(textD->styleBuffer, end);
while (whatStyle == BufGetCharacter(textD->styleBuffer, ++end));
while (whatStyle == BufGetCharacter(textD->styleBuffer, begin-
1)) begin--;
link_text = BufGetRange (textD->buffer, begin, end);
if (is_known_link (link_text, &link_topic, &link_pos) )
{
if (HelpWindows[link_topic] !=
NULL)
{
RaiseShellWindow(HelpWindows[link_topic], True);
}
else
{
if (newWindow)
{
HelpWindows[link_topic]
= createHelpPanel((
enum HelpTopic) link_topic);
}
else
{
changeWindowTopic(topic, (
enum HelpTopic) link_topic);
}
}
navHistBack[link_topic] = topic;
navHistForw[topic] = link_topic;
TextSetCursorPos(HelpTextPanes[link_topic], link_pos);
adaptNavigationButtons(link_topic);
adaptNavigationButtons(topic);
}
NEditFree(link_text);
}
static void helpFocusButtonsAP(Widget w, XEvent *event, String *args,
Cardinal *nArgs)
{
XmProcessTraversal(w, XmTRAVERSE_NEXT_TAB_GROUP);
}
static void helpButtonActionAP(Widget w, XEvent *event, String *args,
Cardinal *nArgs)
{
char buf[
80];
int topic;
Widget btn;
if(*nArgs !=
1)
{
fprintf(stderr,
"help-button-action: requires exactly one argument.\n");
return;
}
for (topic =
0; topic <
NUM_TOPICS; topic++)
if (HelpTextPanes[topic] == w)
break;
if(topic ==
NUM_TOPICS || HelpWindows[topic] ==
NULL)
return;
strcpy(&buf[
0],
"helpForm.");
if (strlen(args[
0]) <=
70)
{
strcat(&buf[
0], args[
0]);
}
else
{
fprintf(stderr,
"help-button-action: argument too long");
return;
}
btn=XtNameToWidget(HelpWindows[topic], buf);
if (btn)
{
XtCallCallbacks(btn, XmNactivateCallback, HelpWindows[topic]);
}
else
{
fprintf(stderr,
"help-button-action: invalid argument: %s\n", args[
0]);
}
}
static void helpHyperlinkAP(Widget w, XEvent *event, String *args,
Cardinal *nArgs)
{
XButtonEvent *e = (XButtonEvent *)event;
int topic;
textDisp *textD = ((TextWidget)w)->text.textD;
int clickedPos, newWin;
static int pressX=
0, pressY=
0;
if (*nArgs ==
0)
{
pressX = e->x;
pressY = e->y;
return;
}
newWin = !strcmp(args[
0],
"new");
if(!newWin && strcmp(args[
0],
"current")) {
fprintf(stderr,
"help-hyperlink: Unrecognized argument %s\n", args[
0]);
return;
}
if (abs(pressX - e->x) >
CLICK_THRESHOLD
|| abs(pressY - e->y) >
CLICK_THRESHOLD)
{
if (*nArgs ==
3)
XtCallActionProc(w, args[
2], event,
NULL,
0);
return;
}
clickedPos = TextDXYToCharPos(textD, e->x, e->y);
if (BufGetCharacter(textD->styleBuffer, clickedPos) !=
(
char)AlphabetToAsciiTable[(
unsigned char)
STL_NM_LINK])
{
if (*nArgs ==
3)
XtCallActionProc(w, args[
2], event,
NULL,
0);
return;
}
for (topic =
0; topic <
NUM_TOPICS; topic++)
if (HelpTextPanes[topic] == w)
break;
if (topic ==
NUM_TOPICS)
{
if (*nArgs ==
3)
XtCallActionProc(w, args[
2], event,
NULL,
0);
return;
}
if (*nArgs ==
3)
XtCallActionProc(w, args[
1], event,
NULL,
0);
followHyperlink(topic, clickedPos, newWin);
}
void InstallHelpLinkActions(XtAppContext context)
{
static XtActionsRec Actions[] =
{
{
"help-hyperlink", helpHyperlinkAP},
{
"help-focus-buttons", helpFocusButtonsAP},
{
"help-button-action", helpButtonActionAP}
};
XtAppAddActions(context, Actions, XtNumber(Actions));
}
static void searchHelpText(Widget parent,
int parentTopic,
const char *searchFor,
int allSections,
int startPos,
int startTopic)
{
int topic, beginMatch, endMatch;
int found = False;
char * helpText =
NULL;
for (topic=startTopic; topic<
NUM_TOPICS; topic++)
{
if (!allSections && topic != parentTopic)
continue;
helpText = stitch(parent, HelpText[topic],
NULL);
if (SearchString(helpText, searchFor,
SEARCH_FORWARD,
SEARCH_LITERAL,
False, topic == startTopic ? startPos :
0, &beginMatch,
&endMatch,
NULL,
NULL, GetPrefDelimiters()))
{
found = True;
NEditFree(helpText);
break;
}
NEditFree(helpText);
}
if (!found)
{
if (startPos !=
0 || (allSections && startTopic !=
0))
{
searchHelpText(parent, parentTopic, searchFor, allSections,
0,
0);
return;
}
DialogF(
DF_INF, parent,
1,
"String Not Found",
"String Not Found",
"OK");
return;
}
if (parentTopic != topic)
{
navHistForw[parentTopic]= topic;
navHistBack[topic]= parentTopic;
}
changeTopicOrRaise(parentTopic, topic);
BufSelect(TextGetBuffer(HelpTextPanes[topic]), beginMatch, endMatch);
TextSetCursorPos(HelpTextPanes[topic], endMatch);
if (searchFor != LastSearchString)
strncpy(LastSearchString, searchFor,
sizeof(LastSearchString)-
1);
LastSearchTopic = topic;
LastSearchPos = endMatch;
LastSearchWasAllTopics = allSections;
}
static void changeWindowTopic(
int existingTopic,
enum HelpTopic newTopic)
{
char *helpText, *styleData;
if (newTopic != existingTopic)
{
HelpWindows[newTopic] = HelpWindows[existingTopic];
HelpWindows[existingTopic] =
NULL;
HelpStyleBuffers[newTopic] = HelpStyleBuffers[existingTopic];
HelpStyleBuffers[existingTopic] =
NULL;
HelpTextPanes[newTopic] = HelpTextPanes[existingTopic];
HelpTextPanes[existingTopic] =
NULL;
setHelpWinTitle(HelpWindows[newTopic], newTopic);
}
helpText = stitch(HelpTextPanes[newTopic], HelpText[newTopic], &styleData);
TextDAttachHighlightData(((TextWidget)HelpTextPanes[newTopic])->text.textD,
NULL,
NULL,
0,
'\0',
NULL,
NULL);
BufSetAll(TextGetBuffer(HelpTextPanes[newTopic]), helpText);
NEditFree(helpText);
BufSetAll(HelpStyleBuffers[newTopic], styleData);
NEditFree(styleData);
TextDAttachHighlightData(((TextWidget)HelpTextPanes[newTopic])->text.textD,
HelpStyleBuffers[newTopic], HelpStyleInfo,
N_STYLES,
'\0',
NULL,
NULL);
}
static int findTopicFromShellWidget(Widget shellWidget)
{
int i;
for (i=
0; i<
NUM_TOPICS; i++)
if (shellWidget == HelpWindows[i])
return i;
return -
1;
}
static void initNavigationHistory(
void) {
static int doInitNavigationHistory = True;
int i;
if (doInitNavigationHistory)
{
for (i=
0; i<
NUM_TOPICS; i++)
navHistBack[i] = navHistForw[i] = -
1;
doInitNavigationHistory = False;
}
}
#if XmVersion ==
2000
extern void XmRegisterConverters(
void);
#endif
void SetHelpZoom(Widget textWidget,
int step)
{
Display *dp = XtDisplay(textWidget);
HelpZoom += step;
for(
int i=
0;i<
N_STYLES;i++) {
if(HelpStyleInfo[i].font) {
int font_sz = HelpStyleInfo[i].font->size + step;
char *fontName = GetPrefHelpFontName(StyleFonts[
STYLE_INDEX(i)]);
char *newFontName = ChangeFontSize(fontName, font_sz);
NFont *newFont = FontFromName(dp, newFontName);
NEditFree(newFontName);
if(newFont) {
FontUnref(HelpStyleInfo[i].font);
HelpStyleInfo[i].font = newFont;
}
}
}
XtVaSetValues(textWidget, textNXftFont, HelpStyleInfo[
0].font,
NULL);
}
void PrintVersion(
void)
{
const char *text;
#if XmVersion <
2001
XmRegisterConverters();
#endif
text = getBuildInfo();
puts (text);
}