2 * CDE - Common Desktop Environment
4 * Copyright (c) 1993-2012, The Open Group. All rights reserved.
6 * These libraries and programs are free software; you can
7 * redistribute them and/or modify them under the terms of the GNU
8 * Lesser General Public License as published by the Free Software
9 * Foundation; either version 2 of the License, or (at your option)
12 * These libraries and programs are distributed in the hope that
13 * they will be useful, but WITHOUT ANY WARRANTY; without even the
14 * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 * PURPOSE. See the GNU Lesser General Public License for more
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with these librararies and programs; if not, write
20 * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21 * Floor, Boston, MA 02110-1301 USA
23 /* $TOG: HelpUtil.c /main/19 1998/04/09 17:43:30 mgreess $ */
24 /************************************<+>*************************************
25 ****************************************************************************
29 ** Project: Rivers Project
34 ** (c) Copyright 1987, 1988, 1989, 1990, 1991, 1992 Hewlett-Packard Company
36 ** (c) Copyright 1993, 1994 Hewlett-Packard Company
37 ** (c) Copyright 1993, 1994 International Business Machines Corp.
38 ** (c) Copyright 1993, 1994 Sun Microsystems, Inc.
39 ** (c) Copyright 1993, 1994 Novell, Inc.
41 ****************************************************************************
42 ************************************<+>*************************************/
45 #include <sys/param.h>
49 #include <unistd.h> /* R_OK */
52 #include <sys/types.h>
53 #define X_INCLUDE_PWD_H
54 #define XOS_USE_XT_LOCKING
55 #include <X11/Xos_r.h>
59 #include <Xm/MwmUtil.h>
61 #include <Xm/MessageB.h>
62 #include <X11/Shell.h>
63 #include <X11/Intrinsic.h>
64 #include <X11/cursorfont.h>
66 /* private includes */
69 #include "DisplayAreaI.h"
70 #include "DisplayAreaP.h"
75 #include "StringFuncsI.h"
76 #include "HelpDialogI.h"
77 #include "HelpDialogP.h"
78 #include "HelpUtilI.h"
80 #include "HyperTextI.h"
82 #include "MessagesP.h"
83 #include "HelpQuickD.h"
86 #include "HelpAccessI.h"
87 #include "FileUtilsI.h"
88 #include "HourGlassI.h"
91 #include <Dt/DtNlUtils.h>
93 /******* global variables *******/
94 char _DtHelpDefaultHelp4HelpVolume[] = "Help4Help";
95 char _DtHelpDefaultLocationId[] = "_HOMETOPIC";
97 /**** Help Util Error message Defines ****/
99 #define UtilMessage0 _DtHelpMsg_0010
100 #define UtilMessage2 _DtHelpMsg_0011
103 static void _DtMessageClose(
105 XtPointer client_data,
107 static void CloseDefBoxCB(
109 XtPointer client_data,
110 XtPointer call_data);
112 /* Macro for finding a point within a gadget.
113 * Its used for item help
115 #define PT_IN_CHILD(X, Y, CHILD) \
116 ((((int)(X)) >= ((int) (CHILD)->core.x)) && \
117 (((int)(X)) <= ((int)((CHILD)->core.x + (CHILD)->core.width))) && \
118 (((int)(Y)) >= ((int) (CHILD)->core.y)) && \
119 (((int)(Y)) <= ((int)((CHILD)->core.y + (CHILD)->core.height))))
122 /******** useful constants ********/
124 #define DIR_SLASH '/'
126 #define HUSET 8 /* message catalog set */
128 /******** static variables ********/
131 /******** data structures ********/
132 typedef struct ExecContext
135 XtPointer pDisplayArea;
138 /******** The onitem cursor (32x32, xbm format) ********/
139 #define onitem32_width 32
140 #define onitem32_height 32
141 #define onitem32_x_hot 0
142 #define onitem32_y_hot 0
143 static unsigned char onitem32_bits[] = {
144 0xff, 0xff, 0xff, 0xff, 0xfd, 0xff, 0x1f, 0xfc, 0xf9, 0xff, 0xe7, 0xf3,
145 0xf1, 0xff, 0xfb, 0xef, 0xe1, 0xff, 0xfd, 0xdf, 0xc1, 0xff, 0xfd, 0xdf,
146 0x83, 0xff, 0xfe, 0xbf, 0x03, 0xff, 0x7e, 0x7e, 0x03, 0xfe, 0xbe, 0x7d,
147 0x03, 0xfc, 0xbe, 0x7d, 0x03, 0xf0, 0xc1, 0x7d, 0x03, 0xe0, 0xff, 0x7e,
148 0x07, 0xc0, 0x7f, 0xbf, 0x07, 0x80, 0xbf, 0xbf, 0x07, 0x00, 0xde, 0xdf,
149 0x07, 0x00, 0xdc, 0xef, 0x07, 0x00, 0xdf, 0xf7, 0x07, 0x80, 0xdf, 0xfb,
150 0x0f, 0xc0, 0xdf, 0xfb, 0x0f, 0xc0, 0xdf, 0xfb, 0x0f, 0x81, 0xdf, 0xfb,
151 0xcf, 0x83, 0x3f, 0xfc, 0xef, 0x07, 0xff, 0xff, 0xff, 0x07, 0xff, 0xff,
152 0xff, 0x0f, 0x3e, 0xfc, 0xff, 0x0f, 0xde, 0xfb, 0xff, 0x1f, 0xdc, 0xfb,
153 0xff, 0x1f, 0xdc, 0xfb, 0xff, 0x3f, 0xd8, 0xfb, 0xff, 0x3f, 0x3c, 0xfc,
154 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
156 #define onitem32_m_width 32
157 #define onitem32_m_height 32
158 #define onitem32_m_x_hot 0
159 #define onitem32_m_y_hot 0
160 static unsigned char onitem32_m_bits[] = {
161 0x03, 0x00, 0x00, 0x00, 0x07, 0x00, 0xe0, 0x03, 0x0f, 0x00, 0xf8, 0x0f,
162 0x1f, 0x00, 0xfc, 0x1f, 0x3f, 0x00, 0xfe, 0x3f, 0x7f, 0x00, 0xfe, 0x3f,
163 0xfe, 0x00, 0xff, 0x7f, 0xfe, 0x01, 0xff, 0xff, 0xfe, 0x03, 0x7f, 0xfe,
164 0xfe, 0x0f, 0x7f, 0xfe, 0xfe, 0x1f, 0x3e, 0xfe, 0xfe, 0x3f, 0x00, 0xff,
165 0xfc, 0x7f, 0x80, 0x7f, 0xfc, 0xff, 0xc1, 0x7f, 0xfc, 0xff, 0xe3, 0x3f,
166 0xfc, 0xff, 0xe7, 0x1f, 0xfc, 0xff, 0xe3, 0x0f, 0xfc, 0xff, 0xe0, 0x07,
167 0xf8, 0x7f, 0xe0, 0x07, 0xf8, 0x7f, 0xe0, 0x07, 0xf8, 0xff, 0xe0, 0x07,
168 0xf8, 0xfe, 0xc0, 0x03, 0x38, 0xfc, 0x01, 0x00, 0x18, 0xfc, 0x01, 0x00,
169 0x00, 0xf8, 0xc3, 0x03, 0x00, 0xf8, 0xe3, 0x07, 0x00, 0xf0, 0xe7, 0x07,
170 0x00, 0xf0, 0xe7, 0x07, 0x00, 0xe0, 0xef, 0x07, 0x00, 0xe0, 0xc7, 0x03,
171 0x00, 0xc0, 0x03, 0x00, 0x00, 0x80, 0x00, 0x00};
173 #if 0 /* XPM format */
174 static char * onitem32_xpm[] = {
175 /* width height ncolors cpp [x_hot y_hot] */
178 " s iconColor1 m black c black",
179 ". s background m black c #969696969696",
180 "X s iconColor2 m white c white",
182 " ..............................",
183 " X ..................XXXXX......",
184 " XX ...............XX XX....",
185 " XXX .............X X...",
186 " XXXX ...........X X..",
187 " XXXXX ..........X X..",
188 ". XXXXX ........X X.",
189 ". XXXXXX .......X XX X",
190 ". XXXXXXX ......X X..X X",
191 ". XXXXXXXX ....X X..X X",
192 ". XXXXXXXXXX ....XXXXX...X X",
193 ". XXXXXXXXXXX ..........X X",
194 ".. XXXXXXXXXXX ........X X.",
195 ".. XXXXXXXXXXXX .....X X.",
196 ".. XXXXXXXXXXXXXX ...X X..",
197 ".. XXXXXXXXXXXXXXX ..X X...",
198 ".. XXXXXXXXXXXXX ...X X....",
199 ".. XXXXXXXXXXXX .....X X.....",
200 "... XXXXXXXXXX ......X X.....",
201 "... XXXXXXXXXX ......X X.....",
202 "... XXXX XXXXXX .....X X.....",
203 "... XX . XXXXX ......XXXX......",
204 "... X .... XXXXX ...............",
205 "... ..... XXXXX ...............",
206 "........... XXXXX ....XXXX......",
207 "........... XXXXX ...X X.....",
208 "............ XXXXX ..X X.....",
209 "............ XXXXX ..X X.....",
210 "............. XXXXX .X X.....",
211 "............. XXXX ...XXXX......",
212 ".............. X ..............",
213 "............... ................"};
220 #define NO_CONDITION 0
221 #define MISMATCHING_HOME_DIRS 1
223 /* ------------------------------------------------------------ *
227 ** Purpose Determines if the passed help volume is a
228 ** "trusted" help volume or not. We call it
229 ** trusted if it meets the following conditions:
230 ** 1. File Owner is root, bin, or system.
231 ** 2. File is NOT writable by group or others.
234 ** True - if the help volume IS Trusted
235 ** False - if the help volume is NOT Trusted
237 ** ------------------------------------------------------------ */
238 static Boolean trusted (char *hv_path) /* Full path to the help volume */
243 if ( (stat (hv_path, &buf)) == -1)
247 /* S_IWGRP */ /* write group */
248 /* S_IWOTH */ /* write other */
250 /** ---------------------------------------------------------------------- *
251 ** The help volume MUST be owned by root, bin, or sys to be trusted.
252 ** ---------------------------------------------------------------------- */
254 if ( buf.st_uid != ROOT_USER &&
255 buf.st_uid != BIN_USER &&
256 buf.st_uid != SYS_USER)
261 /** ----------------------------------------------------------------------- *
262 ** The help volume MUST not be writable by group or others to be trusted.
263 ** ----------------------------------------------------------------------- */
265 writable = (((buf.st_mode & S_IWGRP) == 0) && (buf.st_mode & S_IWOTH) == 0) ?
273 /*>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
274 /**** API Error Dialog Support Functions *****/
275 /*>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
278 /************************************************************************
279 * Function: _DtMessageClose
281 * Close the error/info message box.
283 ************************************************************************/
284 static void _DtMessageClose(
286 XtPointer client_data,
289 /* NOTE: ExecuteContextCB() is dependent on this code */
290 if (event->type == UnmapNotify)
292 XtRemoveEventHandler (XtParent (client_data), StructureNotifyMask,
293 True, (XtEventHandler) _DtMessageClose, client_data);
295 XtUnmanageChild (client_data);
296 XtDestroyWidget (client_data);
300 /************************************************************************
301 * Function: ExecuteContextCB
303 * Execute an execution context
305 ************************************************************************/
306 static void ExecuteContextCB(
308 XtPointer client_data,
311 ExecContext * ec = (ExecContext *) client_data;
313 if (ec && ec->command && ec->pDisplayArea)
315 _DtHelpExecProcedure(ec->pDisplayArea,ec->command);
320 /* unmap, rather than unmanage and destroy, because of the code
321 in _DtMessageClose(). _DtMessageClose() is notified when
322 the widget unmaps and it destroys the widget. */
323 XtUnmapWidget(w); /* w is the message dialog */
326 /*****************************************************************************
327 * Function: CreateErrorDialog
329 * Creates an XmMessageDialog with the message and all buttons
330 * except the 'Close' (OK) button unmanaged.
331 * Also adds a callback that destroys the widget when the dialog is closed.
333 *****************************************************************************/
340 Widget messageDialog;
344 XmString label_string;
348 /* Setup the message string and dialog title */
350 ok_string = XmStringCreateLocalized(((char *)_DTGETMESSAGE
351 (HUSET, 2,"Close")));
352 label_string = XmStringCreateLocalized(message);
353 title_string = XtNewString((char *)_DTGETMESSAGE
354 (HUSET, 5,"Help Error"));
357 XtSetArg (args[n], XmNmessageString, label_string); n++;
358 XtSetArg (args[n], XmNtitle,title_string); n++;
359 XtSetArg (args[n], XmNcancelLabelString, ok_string); n++;
360 XtSetArg (args[n], XmNdefaultButtonType, XmDIALOG_CANCEL_BUTTON); n++;
361 messageDialog = XmCreateErrorDialog (parent, "errorDialog",
363 XtSetArg(args[0], XmNmwmDecorations,
364 MWM_DECOR_BORDER | MWM_DECOR_TITLE);
365 XtSetArg(args[1], XmNuseAsyncGeometry, True);
366 XtSetValues(XtParent(messageDialog), args, 2);
368 XmStringFree (label_string);
369 XmStringFree (ok_string);
370 XtFree(title_string);
372 /* unmanage or define the other buttons */
373 button = XmMessageBoxGetChild (messageDialog, XmDIALOG_OK_BUTTON);
374 XtUnmanageChild (button);
375 button = XmMessageBoxGetChild (messageDialog, XmDIALOG_HELP_BUTTON);
376 XtUnmanageChild (button);
378 /* StructureNotifyMask gets Circulate, Configure, Destroy,
379 Gravity, Map, Reparent, & Unmap events */
380 XtAddEventHandler(XtParent(messageDialog),
381 StructureNotifyMask,True,
382 (XtEventHandler) _DtMessageClose, (XtPointer) messageDialog);
384 return messageDialog; /* RETURN */
388 /*****************************************************************************
389 * Function: CreateExecErrorDlg
394 *****************************************************************************/
399 Boolean invalidAlias,
400 _DtHelpCommonHelpStuff * pHelpStuff,
404 DtHelpListStruct *pHelpInfo;
410 /* handle the error case */
413 msg = (char *)_DTGETMESSAGE(HUSET, 12,
414 "The help volume wanted to execute a command alias.\n"
415 "The alias '%s' is not defined.");
418 else if (condition == MISMATCHING_HOME_DIRS)
420 msg = (char *)_DTGETMESSAGE(HUSET, 14,
421 "The help volume wanted to execute a command as the root user, but the\n"
422 "home directory of \"%s\" ($HOME) does not match the root\n"
423 "user's home directory. This could result in executing unexpected\n"
426 "The command is: \"%s\"\n\n"
428 "Note: to avoid this in the future:\n"
429 " execute \"su - root\" rather than \"su root\".\n");
434 msg = (char *)_DTGETMESSAGE(HUSET, 13,
435 "The help volume wanted to execute a command.\n"
436 "For security reasons, automatic command execution is turned off.\n"
437 "The command is: %s");
439 fullmsg = (char *) malloc(strlen(msg)+strlen(cmdStr)+30);
442 if (condition == MISMATCHING_HOME_DIRS)
443 sprintf(fullmsg, msg, current_hd, cmdStr);
445 sprintf(fullmsg,msg,cmdStr);
450 /* create an error dialog, but don't manage it yet */
451 msgDlg = CreateErrorDialog(XtParent(helpWidget),fullmsg);
453 if (msg != fullmsg) free(fullmsg);
455 btn = XmMessageBoxGetChild (msgDlg, XmDIALOG_HELP_BUTTON);
456 XtManageChild (btn); /* re-manage the button */
458 /* add the HelpOnHelp callback */
459 pHelpInfo = _DtHelpListAdd(DtHELP_ExecutionPolicy_STR,
460 helpWidget, pHelpStuff, &pHelpStuff->pHelpListHead);
461 XtAddCallback(btn, XmNactivateCallback, _DtHelpCB, (XtPointer) pHelpInfo);
466 /*****************************************************************************
467 * Function: _DtHelpErrorDialog
472 *****************************************************************************/
473 void _DtHelpErrorDialog(
477 Widget messageDialog;
479 messageDialog = CreateErrorDialog(parent,message);
481 /* Display help window. This used to be before the call
482 to add a StructureNotify event handler */
483 XtManageChild (messageDialog);
487 /*****************************************************************************
488 * Function: _DtHelpFilterExecCmdStr
491 * helpWidget: help widget requesting to exec the command
492 * pDisplayStuff: ptr to the DisplayWidget stuff of the help widget
493 * commandStr: command string to execute
494 * ret_cmdStr: the screened & possibly rewritten command is put here
495 * ret_invalidAlias: was the command an invalid alias?
496 * ret_execPermitted: if executionPolicy permit exec & ret_cmdStr is valid
497 * ret_queryNeeded: if executionPolicy requires a query before exec
500 * ret_cmdStr gets memory owned by the calling function; it should be
501 * freed when no longer needed. The string will be the same as the
502 * commandStr if commandStr was not an alias. If the commandStr
503 * is an alias and if the alias is defined, the ret_cmdStr will be the
504 * value of the alias. If the alias isn't defined, the ret_cmdStr will
505 * be the default command if available, or the alias name otherwise.
507 * ret_invalidAlias will be True if the alias was undefined and
508 * no default command was given.
510 * ret_execPermitted will be True if executionPolicy is DtHELP_EXECUTE_ALL
511 * or DtHELP_EXECUTE_QUERY_xxx and ret_cmdStr is valid
513 * ret_queryNeeded will be True if executionPoilcy is
514 * DtHELP_EXECUTE_QUERY_ALL or if it is DtHELP_EXECUTE_QUERY_UNALIASED
515 * and ret_cmdStr did not derive from an alias (i.e. was hardcoded
516 * in the help volume, not retrieved from a resource).
519 * True: if execPermitted and a valid command string
520 * False: if if execPermitted is False or invalid command string
523 * This code is written such that we don't need nor want to know
524 * whether it is a general or quick help widget.
527 * command string must be writable; it is written, but left
528 * unchanged when the function exits.
530 *****************************************************************************/
531 Boolean _DtHelpFilterExecCmdStr(
533 unsigned char executionPolicy,
534 const char * commandStr,
536 Boolean * ret_invalidAlias,
537 Boolean * ret_execPermitted,
538 Boolean * ret_queryNeeded,
539 char * hv_path) /* Path to the Help Volume */
544 char * aliasCommand = NULL;
547 #define RN_execAlias "executionAlias"
548 #define RC_execAlias "ExecutionAlias"
549 #define ExecAliasCmd "DtHelpExecAlias"
553 *ret_invalidAlias = False;
554 *ret_execPermitted = False;
555 *ret_queryNeeded = False;
557 if (NULL == commandStr)
560 /** ------------------------------------------------------------- *
561 ** If the executionPolicy is query all unaliased (query for all
562 ** execution links that have no execution alias defined), we
563 ** make an exception: only query the user for help volumes
564 ** deemed NOT "trusted".
565 ** ------------------------------------------------------------- */
567 if (DtHELP_EXECUTE_QUERY_UNALIASED == executionPolicy)
569 if ( ! (trusted (hv_path)))
570 *ret_queryNeeded = True; /* Query ALL non-trusted help volumes */
573 *ret_queryNeeded = (DtHELP_EXECUTE_QUERY_ALL == executionPolicy);
575 /* get whether exec permitted */
576 if ( DtHELP_EXECUTE_ALL == executionPolicy
577 || DtHELP_EXECUTE_QUERY_UNALIASED == executionPolicy
578 || DtHELP_EXECUTE_QUERY_ALL == executionPolicy)
579 *ret_execPermitted = True;
581 *ret_execPermitted = False;
583 /* parse apart the command string, looking for DtHelpExecAlias */
584 /* The first call will return true, with the first string */
585 token = (char *) commandStr + DtStrspn((char *)commandStr, " \t");
586 tokenEnd = token + DtStrcspn(token, " \t");
587 tokenEndChar = *tokenEnd;
588 if (tokenEnd) *tokenEnd = EOS;
590 if ( NULL == token || _DtHelpCeStrCaseCmpLatin1(token, ExecAliasCmd) != 0 )
592 /*** the command is not an alias; proceed using execution Policy ***/
594 *tokenEnd = tokenEndChar; /* restore the string */
596 *ret_cmdStr = strdup(commandStr);
597 ret = *ret_execPermitted;
599 return ret; /* RETURN ret */
603 /**** It's an alias; get it , look it up, and return it ****/
605 *tokenEnd = tokenEndChar; /* restore the string */
607 /* get the next token */
608 token = tokenEnd + DtStrspn(tokenEnd, " \t");
609 tokenEnd = token + DtStrcspn(token, " \t");
610 tokenEndChar = *tokenEnd;
611 if (tokenEnd) *tokenEnd = EOS;
615 Display * dpy = XtDisplay(helpWidget);
616 XrmDatabase appDb = XrmGetDatabase(dpy);
618 String appname, appclass;
620 char *rsrc_name, *rsrc_class;
622 rsrc_name = XtMalloc(200);
623 rsrc_class = XtMalloc(200);
625 XtGetApplicationNameAndClass(dpy,&appname,&appclass);
627 /* query the application's database for the alias command */
628 /* build alias resource class and resource */
629 /* e.g. App.executionAlias.<alias> */
630 sprintf(rsrc_name,"%s.%s.%s",appclass, RN_execAlias,token);
631 /* e.g. App.ExecutionAlias.<alias> */
632 sprintf(rsrc_class,"%s.%s.%s",appclass, RC_execAlias,token);
634 /* Get alias command */
635 if (XrmGetResource(appDb,rsrc_name,rsrc_class,&reptype,&value) == True)
636 aliasCommand = value.addr;
638 /* build alias resource name and resource */
639 /* e.g. app.executionAlias.<alias> */
640 sprintf(rsrc_name,"%s.%s.%s",appname, RN_execAlias,token);
641 /* e.g. app.ExecutionAlias.<alias> */
642 sprintf(rsrc_class,"%s.%s.%s",appname, RC_execAlias,token);
644 /* Get alias command and override class with instance, if defined */
645 if (XrmGetResource(appDb,rsrc_name,rsrc_class,&reptype,&value) == True)
646 aliasCommand = value.addr;
648 if (rsrc_name) XtFree(rsrc_name);
649 if (rsrc_class) XtFree(rsrc_class);
650 } /* if alias token */
656 if (tokenEnd) *tokenEnd = tokenEndChar; /* restore the string */
658 /* alias was defined */
661 *ret_cmdStr = strdup(aliasCommand);
662 /* see if query needed; is not if policy is query_unaliased or all */
663 *ret_queryNeeded = !( DtHELP_EXECUTE_QUERY_UNALIASED == executionPolicy
664 || DtHELP_EXECUTE_ALL == executionPolicy);
665 ret = *ret_execPermitted;
667 else /* the alias wasn't defined */
669 char * aliasToken = token; /* token currently pts to alias */
671 /* look for a default command */
672 /* get the next token */
673 token = tokenEnd + DtStrspn(tokenEnd, " \t");
674 tokenEnd = token + DtStrcspn(token, " \t");
676 if (token == tokenEnd)
677 { /* alias wasn't defined and no default command */
678 *ret_cmdStr = strdup(aliasToken);
679 *ret_invalidAlias = True;
680 *ret_queryNeeded = False; /* no query needed on invalid alias, ever */
681 *ret_execPermitted = False; /* can't exec an invalid alias */
685 { /* alias wasn't defined but a default command */
686 /* query is whatever was determined earlier */
687 *ret_cmdStr = strdup(token);
688 ret = *ret_execPermitted;
692 return ret; /* RETURN ret */
695 /*********************************************************************
696 * _DtHelpCeWaitAndProcessEvents
699 * _DtHelpCeWaitAndProcessEvents will process events and call
700 * the waitProc until waitProc returns False. This function
701 * is useful to put up modal dialogs that must be reponded to
702 * in the midst of executing code that must remain on the call stack.
705 * This function should only be used on modal dialogs.
707 *********************************************************************/
710 _DtHelpCeWaitAndProcessEvents (
712 _DtHelpCeWaitProc waitProc,
719 app = XtWidgetToApplicationContext(w);
723 XtAppNextEvent(app,&event);
724 XtDispatchEvent(&event);
728 while (!(mask = XtAppPending(app)))
729 ; /* Busy waiting - so we don't lose our Lock! */
731 if (mask & XtIMXEvent) /* We have an XEvent */
733 /* Get the XEvent - we know it's there! Note that XtAppNextEvent
734 would also process timers/alternate inputs.
736 XtAppNextEvent(app, &event); /* No blocking, since an event is ready */
737 XtDispatchEvent(&event);
739 else /* Not a XEvent, it's an alternate input/timer event */
741 XtAppProcessEvent(app, mask); /* No blocking, since an event is ready */
743 #endif /* XTHREADS */
744 /* check to see if we're done waiting */
745 waitFlag = (*waitProc)(w, clientData);
749 /*****************************************************************************
750 * Function: WaitForBtnActivatedCB
753 * Treats the 'clientData' as a pointer to an integer
754 * and turns its value into a Boolean
756 * Returns: *(int *)clientData < 0
757 *****************************************************************************/
759 WaitForBtnActivatedCB(
763 return (*(int *)clientData < 0);
764 /* True=keep waiting; False= wait no longer */
768 typedef struct ModalMsgDlgCBStruct
775 } ModalMsgDlgCBStruct;
777 /*****************************************************************************
778 * Function: IdentifyActivatedBtnCB
781 * Treats the 'clientData' as a pointer to an integer.
782 * Waits for the value pointed to by clientData to be >= 0.
784 *****************************************************************************/
786 IdentifyActivatedBtnCB(
788 XtPointer clientData,
791 ModalMsgDlgCBStruct * pMd = (ModalMsgDlgCBStruct *) clientData;
793 /* w must be a XmMessageDialog widget */
795 { pMd->activatedBtnId = XmDIALOG_OK_BUTTON; return; /* RETURN */ }
796 if (pMd->cancelBtn == w)
797 { pMd->activatedBtnId = XmDIALOG_CANCEL_BUTTON; return; /* RETURN */ }
798 if (pMd->helpBtn == w)
799 { pMd->activatedBtnId = XmDIALOG_HELP_BUTTON; return; /* RETURN */ }
800 pMd->activatedBtnId = -1; /* unknown button */
804 /*****************************************************************************
805 * Function: _DtHelpFilterExecCmd
808 * helpWidget: help widget requesting to exec the command
809 * command: command string to execute
810 * execPolicy: current policy setting
811 * useQueryDialog: use a dialog to query user whether to exec, if not allowed
812 * pHelpStuff: ptr to the HelpStuff structure of the help widget
813 * ret_filteredCmdStr: filtered command string
816 * 0: no error; filteredCmdStr can be exec'd
817 * -1: error: either internal or executionPolicy denies exec;
818 * filteredCmdStr is NULL
821 * This function filters an execution command string. This can
822 * occur in several ways. In all cases, the command string is
823 * supports command alias replacement. If the final outcome
824 * is that execution is permitted, the returned string is
825 * is the command string to execute. If execution is not
826 * permitted, the return string is a NULL pointer.
828 * Filtering of the command occurs as follows.
829 * If executionPolicy permits execution, only alias replacement occurs.
830 * If executionPolicy does restrict execution and a
831 * dialog is requested, then a modal dialog is posted and the
832 * user can decide whether to execute or not.
833 * If a dialog is not requested, the return string is NULL.
836 * This code is written such that we don't need nor want to know
837 * whether it is a general or quick help widget.
840 * command string must be writable; it is written, but left
841 * unchanged whent the function exits.
843 * This operation is synchronous, meaning that, if a dialog is
844 * posted, it is a modal dialog and the function won't return
845 * until the user selects a button.
848 *****************************************************************************/
849 int _DtHelpFilterExecCmd(
851 const char * commandStr,
852 unsigned char executionPolicy,
853 Boolean useQueryDialog,
854 _DtHelpCommonHelpStuff * pHelpStuff,
855 char * * ret_filteredCmdStr,
858 ModalMsgDlgCBStruct msgDlgCBStruct;
860 Boolean invalidAlias;
861 Boolean execPermitted;
864 char * filteredCmdStr = NULL;
867 XmString labelString;
868 XmString labelString2;
872 goodCmd = _DtHelpFilterExecCmdStr(helpWidget, executionPolicy,
873 commandStr, &filteredCmdStr, &invalidAlias,
874 &execPermitted, &queryNeeded, hv_path);
876 /* if permissions allow immediate execution, do so */
877 if (execPermitted && False == queryNeeded)
879 *ret_filteredCmdStr = filteredCmdStr;
880 return 0; /* RETURN ok */
883 if (False == useQueryDialog)
885 *ret_filteredCmdStr = NULL;
886 return -1; /* RETURN error */
889 /* create the dialog, but don't yet manage it */
890 msgDlg = CreateExecErrorDlg(helpWidget,filteredCmdStr,
891 invalidAlias,pHelpStuff, NO_CONDITION, "");
893 /* if a bad alias or no exec permitted,
894 don't need to wait for a response; dlg has close & Help */
895 if (False == execPermitted || False == queryNeeded)
897 XtManageChild(msgDlg); /* manage modeless dialog */
898 *ret_filteredCmdStr = NULL; /* don't execute */
899 XtFree(filteredCmdStr);
900 return -1; /* RETURN error */
903 /* if got this far, query is needed;make the dialog include
904 Execute Anyway and Don't Execute buttons */
906 /* give the right title to the buttons */
907 labelString = XmStringCreateLocalized(((char *)_DTGETMESSAGE
908 (HUSET, 10,"Execute Anyway")));
909 /* give the right title to the Cancel button */
910 labelString2 = XmStringCreateLocalized(((char *)_DTGETMESSAGE
911 (HUSET, 11,"Don't Execute")));
913 XtSetArg (args[n], XmNokLabelString, labelString); n++;
914 XtSetArg (args[n], XmNcancelLabelString, labelString2); n++;
915 XtSetArg (args[n], XmNdialogStyle, XmDIALOG_PRIMARY_APPLICATION_MODAL); n++;
916 XtSetValues(msgDlg,args,n);
917 XmStringFree(labelString);
918 XmStringFree(labelString2);
920 /* We put an activate callback on the DontExecute and ExecuteAnyway buttons
921 and wait until a button is pressed. */
922 noexecBtn = XmMessageBoxGetChild (msgDlg, XmDIALOG_CANCEL_BUTTON);
923 XtAddCallback(noexecBtn, XmNactivateCallback,
924 IdentifyActivatedBtnCB, (XtPointer) &msgDlgCBStruct);
926 execBtn = XmMessageBoxGetChild (msgDlg, XmDIALOG_OK_BUTTON);
927 XtManageChild (execBtn); /* re-manage the button */
928 XtAddCallback(execBtn, XmNactivateCallback,
929 IdentifyActivatedBtnCB, (XtPointer) &msgDlgCBStruct);
931 /* fill out the CB information structure used by IdentifyActivatedBtnCB */
932 msgDlgCBStruct.msgDlg = msgDlg;
933 msgDlgCBStruct.okBtn = execBtn;
934 msgDlgCBStruct.cancelBtn = noexecBtn;
935 msgDlgCBStruct.activatedBtnId = -1;
937 /* Display message dialog */
938 XtManageChild (msgDlg);
941 * turn on the modal dialog indicator
943 _DtHelpTurnOnNoEnter(helpWidget);
945 /* wait until 'msgDlgCBStruct.activatedBtnId' has a value >= 0 */
946 /* this occurs when the user responds to the msg dialog */
947 _DtHelpCeWaitAndProcessEvents(msgDlg,
948 WaitForBtnActivatedCB, &msgDlgCBStruct.activatedBtnId);
951 * turn off the modal dialog indicator
953 _DtHelpTurnOffNoEnter(helpWidget);
955 /* no need to destroy msgDlg; it has a closeCallback to do that */
957 /* act based on which button was activated */
958 if (msgDlgCBStruct.activatedBtnId == XmDIALOG_OK_BUTTON)
960 *ret_filteredCmdStr = filteredCmdStr; /* do execute command */
961 return 0; /* RETURN ok */
965 *ret_filteredCmdStr = NULL; /* don't execute */
966 XtFree(filteredCmdStr);
967 return -1; /* RETURN error */
971 /*****************************************************************************
972 * Function: _DtHelpExecFilteredCmd
975 * helpWidget: help widget requesting to exec the command
976 * command: command string to execute
977 * modal: is the execution modal (sync) or modeless (async)
978 * helpLocationId: helpOnHelp file location for Help btn in error dialog
979 * pDisplayStuff: ptr to the DisplayWidget stuff of the help widget
980 * pHelpStuff: ptr to the CommonHelp stuff of the help widget
983 * This code is written such that we don't need nor want to know
984 * whether it is a general or quick help widget.
987 * command string must be writable; it is written, but left
988 * unchanged whent the function exits.
990 * At the moment, the helpLocationId is ignored, and the
991 * help location is hardwired to DtHELP_ExecutionPolicy_STR
992 * in CreateExecErrorDialog().
994 *****************************************************************************/
995 void _DtHelpExecFilteredCmd(
998 char * helpLocationId,
999 _DtHelpDisplayWidgetStuff * pDisplayStuff,
1000 _DtHelpCommonHelpStuff * pHelpStuff)
1003 Boolean invalidAlias;
1004 Boolean execPermitted;
1005 Boolean queryNeeded;
1006 char * filteredCmdStr = NULL;
1007 ExecContext * execContext;
1008 XmString labelString;
1009 XmString labelString2;
1018 Boolean diff_home_dirs=False; /* True ==> $HOME is different from */
1019 /* root user's $HOME directory */
1021 getpw{uid,nam}_r routines fail on IBM platform when search password info
1022 via NIS (yellow pages). However, in the case of root, we'll assume that
1023 the password info is in /etc/passwd. If this is not the case, the
1024 following code can fail on IBM platform when XTHREADS and XUSE_MTSAFE_API
1028 _Xgetpwparams pwd_buf;
1030 struct passwd * pwd_ret;
1032 /** -------------------------------------------------------------- *
1033 ** If we're running as the root user
1034 ** o check if the value of the HOME env var matches
1035 ** root's home directory (defined by /etc/passwd).
1036 ** o If they do not match, then present a dialog
1037 ** alerting the user of this, along with the command to
1039 ** -------------------------------------------------------------- */
1041 if ( (user=getuid()) == ROOT_USER)
1043 home_dir = getenv ("HOME");
1045 if (home_dir != NULL && strlen(home_dir) >= (size_t) 1)
1047 if (((pwd_ret = _XGetpwuid(user, pwd_buf)) != NULL)
1048 && (strcmp(home_dir, pwd_ret->pw_dir)))
1050 diff_home_dirs = True;
1055 hv_path = _DtHelpFileLocate(DtHelpVOLUME_TYPE, pDisplayStuff->helpVolume,
1056 _DtHelpFileSuffixList, False, R_OK);
1058 /* The desired and intended behaviour is to use _DtHelpFilterExecCmdStr(), but
1059 the other code is left here, should a change be wished. */
1061 /* This function runs a filter for policy and alias but posts no dialog */
1062 goodCmd=_DtHelpFilterExecCmdStr(helpWidget,
1063 pDisplayStuff->executionPolicy, commandStr,
1064 &filteredCmdStr, &invalidAlias, &execPermitted, &queryNeeded, hv_path);
1066 /* This function does an synchronous filter; i.e. the code runs a filter
1067 for policy and alias, and if policy denies exec and the command is
1068 valid, then posts a modal dialog and waits for the user to decide
1069 what to do before returning. */
1070 goodCmd = _DtHelpFilterExecCmd(helpWidget, commandStr,
1071 pDisplayStuff->executionPolicy, True,
1072 pHelpStuff, &filteredCmdStr, hv_path);
1073 execPermitted = (goodCmd == 0); /* convert an error int into a Boolean */
1075 (( pDisplayStuff->executionPolicy==DtHELP_EXECUTE_QUERY_ALL)
1076 || (pDisplayStuff->executionPolicy==DtHELP_EXECUTE_QUERY_UNALIASED))
1080 /* if permissions allow immediate execution, do so */
1081 if (execPermitted && False == queryNeeded && diff_home_dirs == False)
1083 (void) _DtHelpExecProcedure (pHelpStuff->pDisplayArea, filteredCmdStr);
1084 free(filteredCmdStr);
1085 return; /* RETURN */
1088 /* this traps bad cmds and also use of the synchronous filter call */
1089 if (NULL == filteredCmdStr) return; /* RETURN */
1091 /*** Create a modeless dialog to inform the user of the problem
1092 and possibly allow them to execute the command anyway. ***/
1094 /* create the dialog, but don't yet manage it */
1095 if ( diff_home_dirs == True)
1096 msgDlg = CreateExecErrorDlg(helpWidget,filteredCmdStr, invalidAlias,pHelpStuff,
1097 MISMATCHING_HOME_DIRS, home_dir );
1099 msgDlg = CreateExecErrorDlg(helpWidget,filteredCmdStr, invalidAlias,pHelpStuff,
1103 /*** setup ExecuteAnyway and Help buttons ***/
1105 if ( (diff_home_dirs == True)
1107 (queryNeeded && execPermitted) )
1109 /* give the right title to the buttons */
1110 labelString = XmStringCreateLocalized(((char *)_DTGETMESSAGE
1111 (HUSET, 10,"Execute Anyway")));
1112 /* give the right title to the Cancel button */
1113 labelString2 = XmStringCreateLocalized(((char *)_DTGETMESSAGE
1114 (HUSET, 11,"Don't Execute")));
1116 XtSetArg (args[n], XmNokLabelString, labelString); n++;
1117 XtSetArg (args[n], XmNcancelLabelString, labelString2); n++;
1118 XtSetValues(msgDlg,args,n);
1119 XmStringFree(labelString);
1120 XmStringFree(labelString2);
1122 btn = XmMessageBoxGetChild (msgDlg, XmDIALOG_OK_BUTTON);
1123 XtManageChild (btn); /* re-manage the button */
1125 /* add the ExecuteContextCB() client-data and callback */
1126 execContext = malloc(sizeof(ExecContext));
1129 execContext->command = filteredCmdStr;
1130 execContext->pDisplayArea = pHelpStuff->pDisplayArea;
1131 XtAddCallback(btn, XmNactivateCallback,
1132 ExecuteContextCB, (XtPointer) execContext);
1136 free(filteredCmdStr);
1138 } /* cmd wasn't an alias */
1141 free(filteredCmdStr);
1144 /* Display message dialog */
1145 XtManageChild (msgDlg);
1152 /*****************************************************************************
1153 * Function: LocateWidgetId()
1158 *****************************************************************************/
1159 static Widget LocateWidgetId(
1166 static Cursor DfltOnItemCursor = 0;
1169 CompositeWidget comp_widget;
1181 Boolean notDone=TRUE;
1184 /* Make the target cursor */
1189 cursor = XCreateFontCursor (dpy, XC_question_arrow);
1192 _DtHelpProcessLock();
1193 if (0 == DfltOnItemCursor)
1198 unsigned int height;
1199 unsigned int xHotspot;
1200 unsigned int yHotspot;
1205 width = onitem32_width;
1206 height = onitem32_height;
1207 bits = (char *) onitem32_bits;
1208 maskBits = (char *) onitem32_m_bits;
1209 xHotspot = onitem32_x_hot;
1210 yHotspot = onitem32_y_hot;
1212 pixmap = XCreateBitmapFromData (dpy,
1213 RootWindowOfScreen(XtScreen(shellWidget)), bits,
1217 maskPixmap = XCreateBitmapFromData (dpy,
1218 RootWindowOfScreen(XtScreen(shellWidget)), maskBits,
1221 xcolors[0].pixel = BlackPixelOfScreen(ScreenOfDisplay(dpy, screen));
1222 xcolors[1].pixel = WhitePixelOfScreen(ScreenOfDisplay(dpy, screen));
1225 DefaultColormapOfScreen(ScreenOfDisplay(dpy, screen)),
1229 DfltOnItemCursor = XCreatePixmapCursor (dpy, pixmap, maskPixmap,
1230 &(xcolors[0]), &(xcolors[1]),
1231 xHotspot, yHotspot);
1232 XFreePixmap (dpy, pixmap);
1233 XFreePixmap (dpy, maskPixmap);
1234 } /* if dflt cursor not yet created */
1235 cursor = DfltOnItemCursor;
1236 _DtHelpProcessUnlock();
1237 } /* if to use the standard cursor */
1241 /* Grab the pointer using target cursor, letting it roam all over */
1242 status = XtGrabPointer (shellWidget, TRUE,
1243 ButtonPressMask|ButtonReleaseMask, GrabModeAsync,
1244 GrabModeAsync, None, cursor, CurrentTime);
1245 if (status != GrabSuccess)
1247 XmeWarning(shellWidget,(char *)_DTGETMESSAGE(HUSET, 3,
1248 "Internal Error: Could not grab the mouse\nDtHelpReturnSelectedWidget aborted.\n"));
1249 *statusRet = DtHELP_SELECT_ERROR;
1255 /* Grab the Keyboard so we can catch the ESC button press */
1256 status = XtGrabKeyboard(shellWidget, False,
1257 GrabModeAsync, GrabModeAsync, CurrentTime);
1258 if (status != GrabSuccess)
1261 XtUngrabPointer (shellWidget, CurrentTime);
1262 XmeWarning(shellWidget,(char *)_DTGETMESSAGE(HUSET, 4,
1263 "Internal Error: Could not grab the keyboard\nDtHelpReturnSelectedWidget() aborted.\n"));
1264 *statusRet = DtHELP_SELECT_ERROR;
1268 /* We are ok so let the user select a window... */
1271 XtAppContext app = XtWidgetToApplicationContext(shellWidget);
1272 /* allow one more event */
1274 XtAppNextEvent(app, &event);
1278 while (!(mask = XtAppPending(app)))
1279 ; /* Busy waiting - so we don't lose our Lock! */
1281 if (!(mask & XtIMXEvent)) /* Not a XEvent, it's an alternate input/timer event */
1282 XtAppProcessEvent(app, mask); /* No blocking, since an event is ready */
1283 else /* We have an XEvent */
1285 /* Get the XEvent - we know it's there! Note that XtAppNextEvent
1286 would also process timers/alternate inputs.
1288 XtAppNextEvent(app, &event);
1289 #endif /* XTHREADS */
1290 widget = XtWindowToWidget(dpy, event.xany.window);
1292 switch (event.type) {
1299 /* Look for ESC key press and stop if we get one */
1300 if (event.xkey.state & ShiftMask)
1305 keySym = XLookupKeysym((XKeyEvent *)&event, offset);
1306 if (keySym == XK_Escape)
1308 XtUngrabKeyboard (shellWidget, CurrentTime);
1309 XtUngrabPointer (shellWidget, CurrentTime);
1310 *statusRet = DtHELP_SELECT_ABORT;
1314 XtDispatchEvent(&event);
1321 XtUngrabKeyboard (shellWidget, CurrentTime); /* Done with keyboard */
1322 XtUngrabPointer (shellWidget, CurrentTime); /* Done with pointer */
1324 /* If its null then the user selected some area outside our window(s) */
1325 if (widget == shellWidget)
1327 *statusRet = DtHELP_SELECT_INVALID;
1330 if (!XtIsComposite (widget))
1332 *statusRet = DtHELP_SELECT_VALID;
1336 /* Get the x and y and parent relative to the current window */
1337 parent = RootWindow(dpy, screen);
1338 target_win = XtWindow(widget);
1339 x = event.xbutton.x_root;
1340 y = event.xbutton.y_root;
1342 XTranslateCoordinates(dpy, parent, target_win, x, y,
1343 &new_x, &new_y, &sub);
1347 comp_widget = (CompositeWidget)widget;
1349 /* look for gadgets at this point */
1350 for (i = 0; i < comp_widget->composite.num_children; i++) {
1351 child = comp_widget->composite.children[i];
1352 /* put in check for only managed widgets here */
1353 if(XtIsManaged(child))
1354 if (PT_IN_CHILD (x, y, child))
1356 *statusRet = DtHELP_SELECT_VALID;
1361 *statusRet = DtHELP_SELECT_VALID;
1368 /*****************************************************************************
1369 * Function: Boolean RememberDir(String path)
1371 * Parameters: path Specifies the path to check.
1373 * Return Value: Boolean if the path name is good.
1375 * Description: Use the directory caching mechanism to improve performance
1376 * by remembering the directories that have already been
1379 *****************************************************************************/
1381 RememberDir(String path)
1387 if (path == NULL || *path == '\0')
1390 if (_DtHelpCeStrrchr(path, "/", MB_CUR_MAX, &ptr) == 0 && ptr != path)
1393 result = _DtHelpCeCheckAndCacheDir(path);
1396 if (result == 0 && access(path, R_OK) == 0 &&
1397 stat(path, &buf) == 0 && S_ISREG(buf.st_mode))
1403 /*****************************************************************************
1404 * Function: Boolean _DtHelpResolvePathname(
1409 * Return Value: Boolean.
1412 * Description: _DtHelpResolvePathname attempts to validate and expand a path
1413 * to a Cache Creek help access file.
1415 *****************************************************************************/
1416 Boolean _DtHelpResolvePathname(
1418 char * * io_fileName,
1419 _DtHelpVolumeHdl * io_volumeHandle,
1420 char * sysVolumeSearchPath,
1421 char * userVolumeSearchPath)
1423 String newPath = NULL;
1425 /* try to locate file and its entry, if present */
1426 newPath = _DtHelpFileLocate(DtHelpVOLUME_TYPE, *io_fileName,
1427 _DtHelpFileSuffixList,False,R_OK);
1429 /* If we found a valid file let's do some set up here */
1431 if (newPath != NULL) /* We have a valid volume file so open it */
1433 /* Close the current one if we have one open */
1434 if (*io_volumeHandle != NULL)
1435 _DtHelpCloseVolume(*io_volumeHandle);
1437 /* Open the help volume file and save the handle id */
1438 if (_DtHelpOpenVolume(newPath,io_volumeHandle) >= 0)
1440 /* Copy the expanded file location path */
1441 XtFree(*io_fileName);
1442 *io_fileName = newPath;
1448 /* ERROR; leave io_fileName untouched on error
1449 * We used to set it to null here now we just return what came in
1451 /* later NOTE: this seems strange, since we have closed the
1452 old volume, invalidating io_fileName */
1454 XmeWarning(widget,(char*)UtilMessage2);
1458 else /* We have a non-valid path */
1460 /* ERROR; leave io_fileName untouched on error
1461 * We used to set it to null here now we just return what came in
1464 XmeWarning(widget,(char*)UtilMessage0);
1474 /*****************************************************************************
1475 * Function: Boolean _DtHelpExpandHelpVolume(DtHelpDialogWidget nw);
1478 * Parameters: nw Specifies the current help dialog widget.
1480 * Return Value: Boolean.
1483 * Description: _DtHelpExpandHelpVolume looks for a $LANG variable in the
1484 * helpAccesFile string and if found, replaces it with the
1485 * current lang variable.
1487 *****************************************************************************/
1488 Boolean _DtHelpExpandHelpVolume(
1490 _DtHelpDisplayWidgetStuff * display,
1491 _DtHelpCommonHelpStuff * help,
1492 _DtHelpPrintStuff * print)
1494 Boolean validTopic = FALSE;
1495 Boolean validPath = FALSE;
1498 /* Free the old, and Copy the new volumeHandle to printVolume varialbe */
1499 if (print->printVolume != NULL)
1500 XtFree(print->printVolume);
1502 print->printVolume = XtNewString(display->helpVolume);
1504 validPath = _DtHelpResolvePathname((Widget)w,
1505 &print->printVolume,
1506 &display->volumeHandle,
1507 help->sysVolumeSearchPath,
1508 help->userVolumeSearchPath);
1511 /* Check to see that we resolved our path correctly */
1513 return (FALSE); /* RETURN */
1517 /* The following routine will malloc memory for the topLevelId
1518 * variable, so we must free our current version first.
1520 XtFree(help->topLevelId);
1522 /* Assign our top level topic for this help access file */
1523 validTopic = _DtHelpCeGetTopTopicId(display->volumeHandle, &topLevelId);
1527 /* Bad top level topic */
1528 help->topLevelId = NULL;
1533 /* recall that the topLevelId/File vars are malloc'd */
1534 help->topLevelId = topLevelId;
1541 /*****************************************************************************
1542 * Function: char *_DtHelpParseIdString(char * specification);
1545 * Parameters: specification Specifies an author defined help topic.
1547 * Return Value: Void.
1549 * Description: This function copies the locationId portion of the
1550 * specification and returns it to the calling routine.
1552 *****************************************************************************/
1553 char *_DtHelpParseIdString(
1554 char *specification)
1557 char *pAccessFile = NULL;
1559 char *returnStr=NULL;
1562 tmpSpec = XtNewString(specification);
1565 /* First look for a blank in the specification. This will signify that
1566 * we have a HelpAccessFile as part of the specification.
1569 /* The first call will return true, with the first string */
1570 pAccessFile = DtStrtok_r(tmpSpec, " ", &strtok_ptr);
1571 returnStr = XtNewString(pAccessFile);
1573 /* The second call will return true only if we have another string */
1574 pAccessFile = DtStrtok_r(NULL, " ", &strtok_ptr);
1576 if (pAccessFile != NULL)
1578 /* We have a helpAccessFile in our specification */
1582 returnStr = XtNewString(pAccessFile);
1589 /* We don't have a helpAccessFile as part of the specificaiton
1590 * so we just return our locationId.
1600 /*****************************************************************************
1601 * Function: char *_DtHelpParseAccessFile(char * specification);
1604 * Parameters: specification Specifies an author defined help topic.
1606 * Return Value: Void.
1608 * Description: This function copies the helpAccessFile portion of the
1609 * specification and returns it to the calling routine.
1611 *****************************************************************************/
1612 char *_DtHelpParseAccessFile(
1613 char *specification)
1615 char *pAccessFile = NULL;
1617 char *returnStr=NULL;
1620 tmpSpec = XtNewString(specification);
1623 /* First look for a blank in the specification. This will signify that
1624 * we have a HelpAccessFile as part of the specification.
1627 /* The first call will return true, with the first string */
1628 pAccessFile = DtStrtok_r(tmpSpec, " ", &strtok_ptr);
1629 returnStr = XtNewString(pAccessFile);
1631 /* The second call will return true only if we have another string */
1632 pAccessFile = DtStrtok_r(NULL, " ", &strtok_ptr);
1634 if (pAccessFile != NULL)
1636 /* We have a helpAccessFile in our specification */
1639 /* If we have an accessFile, but it's not a full path, then we
1640 * must get the full path from the reg file.
1648 /* We don't have a helpAccessFile as part of the specificaiton
1665 /*****************************************************************************
1666 * Function: DtHelpReturnSelectedWidgetId
1668 * Parameters: parent Specifies the widget ID to use as the bases of
1669 * interaction, usually a top level shell.
1671 * cursor Specifies the cursor to be used for the pointer
1672 * during the interaction. If a value of NULL is
1673 * used this function will use a default cursor
1676 * widget This is the return value (e.g. the selected
1677 * widget). A value of NULL is returned on error.
1679 * Return Value: Status: (-1,0 or 1).
1681 * Purpose: Allows developers to get the widget ID for any widget in their UI
1682 * that the user has selected via the pointer. This function will
1683 * cause the cursor to change and allow a user to select an item in
1686 *****************************************************************************/
1687 int DtHelpReturnSelectedWidgetId(
1696 Widget selectedItem;
1697 int status=DtHELP_SELECT_ERROR;
1700 _DtHelpWidgetToAppContext(parent);
1702 _DtHelpAppLock(app);
1703 /* Setup some needed variables */
1704 dpy = XtDisplay(parent);
1705 retScr = XtScreen(parent);
1707 screen = XScreenNumberOfScreen(retScr);
1709 /* refresh the display */
1710 XmUpdateDisplay(parent);
1712 /* Change the curser to let the user select the desired widget */
1713 selectedItem = LocateWidgetId(dpy, screen, &status, parent, cursor);
1717 case DtHELP_SELECT_VALID:
1718 *widget = selectedItem;
1719 result = DtHELP_SELECT_VALID;
1722 case DtHELP_SELECT_ABORT:
1724 result = DtHELP_SELECT_ABORT;
1727 case DtHELP_SELECT_ERROR:
1729 result = DtHELP_SELECT_ERROR;
1732 case DtHELP_SELECT_INVALID:
1735 result = DtHELP_SELECT_INVALID;
1739 _DtHelpAppUnlock(app);
1750 /*****************************************************************************
1751 * Function: void _DtHelpTopicListAddToHead(
1755 * DtTopicListStruct *pHead,
1756 * DtTopicListStruct *pTale,
1762 * Return Value: Void.
1764 * Purpose: Adds an element to the top of the given topicList.
1766 *****************************************************************************/
1767 void _DtHelpTopicListAddToHead(
1769 XmString topicTitle,
1773 DtTopicListStruct **pHead,
1774 DtTopicListStruct **pTale,
1778 DtTopicListStruct *pTemp=NULL;
1780 /* add the new topic to the top */
1781 pTemp = (DtTopicListStruct *) XtMalloc((sizeof(DtTopicListStruct)));
1783 pTemp->pNext = (*pHead);
1784 pTemp->pPrevious = NULL;
1786 /* Assign the passed in values to our first element */
1787 pTemp->locationId = XtNewString(locationId);
1788 pTemp->topicTitleLbl = NULL;
1789 if (topicTitle != NULL)
1790 pTemp->topicTitleLbl= XmStringCopy(topicTitle);
1791 pTemp->topicType = topicType;
1792 pTemp->helpVolume = XtNewString(accessPath);
1793 pTemp->scrollPosition = scrollPosition;
1795 /* Add locationId as first element if pHead = NULL */
1798 /* Assign our tale pointer */
1799 (*pTale) = (*pHead);
1801 /* Make sure or totalNodes counter is correct, e.g. force it to 1 */
1805 { /* We have a list so add the new topic to the top */
1807 (*pHead)->pPrevious = pTemp;
1809 /* Assign our tale pointer only the first time in this block */
1810 if (*totalNodes == 1)
1811 (*pTale) = (*pHead);
1813 /* Re-Assign our head pointer to point to the new head of the list */
1815 /* Bump our totalNode count */
1816 *totalNodes = *totalNodes +1;
1819 /* set the head to the current entry */
1822 /* If we have reached our maxNodes remove a node from the end of our list */
1823 if (*totalNodes > maxNodes)
1826 (*pTale) = (*pTale)->pPrevious;
1827 (*pTale)->pNext = NULL;
1828 pTemp->pPrevious = NULL;
1830 /* Free the id String and AccessPath elements */
1831 XtFree(pTemp->locationId);
1832 XtFree(pTemp->helpVolume);
1833 if (pTemp->topicTitleLbl != NULL)
1834 XmStringFree(pTemp->topicTitleLbl);
1836 /* Now, free the whole node */
1837 XtFree((char*)pTemp);
1839 /* Bump back our total node counter */
1840 *totalNodes = *totalNodes -1;
1848 /*****************************************************************************
1849 * Function: void _DtHelpTopicListDeleteHead(
1850 * DtTopicListStruct *pHead,
1851 * DtTopicListStruct *pTale,
1857 * Return Value: Void.
1859 * Purpose: Delets an element from the top of the given topicList.
1861 *****************************************************************************/
1862 void _DtHelpTopicListDeleteHead(
1863 DtTopicListStruct **pHead,
1864 DtTopicListStruct **pTale,
1867 DtTopicListStruct *pTemp=NULL;
1869 /* Delete the top node in our topic list */
1873 if(pTemp != (*pTale)) /* (e.g. more than one node in list) */
1875 (*pHead) = pTemp->pNext;
1876 pTemp->pNext = NULL;
1877 (*pHead)->pPrevious = NULL;
1879 /* Free the id String and accessPath elements */
1880 XtFree(pTemp->locationId);
1881 XtFree(pTemp->helpVolume);
1883 /* Now, free the whole node */
1884 XtFree((char*)pTemp);
1886 /* Bump back our total node counter */
1887 *totalNodes = *totalNodes -1;
1897 /*****************************************************************************
1898 * Function: void _DtHelpMapCB()
1902 * Parameters: client_data is the widget in reference to
1903 * which widget w is placed
1905 * Return Value: Void.
1907 * Purpose: Determins where a new child dialog should be mapped in
1908 * relation to its parent.
1910 * Algorithm: 1. attempt left or right placement with no overlap
1911 * 2. if fails, attempt up or down placement with no overlap
1912 * 3. if fails, determines location with least
1913 * amount of overlap, and places there.
1915 *****************************************************************************/
1916 XtCallbackProc _DtHelpMapCB(
1918 XtPointer client_data,
1919 XtPointer call_data )
1923 Position centeredY, bestX, bestY, pX, pY;
1924 Dimension pHeight, myHeight, pWidth, myWidth;
1925 Dimension maxX, maxY;
1926 int rhsX, lhsX, topY, botY; /* needs to be int, not Dimension */
1931 parent = (Widget)client_data;
1932 display = XtDisplay(w);
1933 screen = XtScreen(w);
1934 screenNumber = XScreenNumberOfScreen(screen);
1940 pHeight = XtHeight(parent);
1941 pWidth = XtWidth(parent);
1942 myHeight = XtHeight(w);
1943 myWidth = XtWidth(w);
1944 maxX = XDisplayWidth(display,screenNumber);
1945 maxY = XDisplayHeight(display,screenNumber);
1948 * 1. attempt left or right placement with no overlap
1949 * 2. if fails, attempt up or down placement with no overlap
1950 * 3. if fails, places on the right in the middle
1953 /* first try left right placement */
1954 bestY = pY + pHeight/2 - myHeight/2;
1957 lhsX = pX - myWidth - 8; /* 8: account for border */
1958 if ( ((int)(rhsX + myWidth)) < ((int) maxX) ) bestX = rhsX;
1959 else if ( lhsX > 0 ) bestX = lhsX;
1962 /* then try up down placement */
1963 bestX = pX + pWidth/2 - myWidth/2;
1964 botY = pY + pHeight;
1965 topY = pY - myHeight - 44; /* 44: account for menu border */
1966 if ( ((int)(botY + myWidth)) < ((int) maxY) ) bestY = botY;
1967 else if ( topY > 0 ) bestY = topY;
1970 /* otherwise, center vertically and on the right */
1971 bestX = maxX - myWidth;
1976 XtSetArg(args[0], XmNx, bestX);
1977 XtSetArg(args[1], XmNy, bestY);
1978 XtSetValues(w, args, 2);
1980 return((XtCallbackProc) NULL);
1989 /*****************************************************************************
1990 * Function: void _DtHelpMapCenteredCB(
1996 * Return Value: Void.
1998 * Purpose: Determins where the center of our help dialog is and sets
1999 * where new child dialog should be mapped such that its centered.
2001 *****************************************************************************/
2002 XtCallbackProc _DtHelpMapCenteredCB(
2004 XtPointer client_data,
2005 XtPointer call_data )
2009 Position newX, newY, pY, pX;
2010 Dimension pHeight, myHeight, pWidth, myWidth;
2012 parent = (Widget)client_data;
2016 pHeight = XtHeight(parent);
2017 pWidth = XtWidth(parent);
2018 myHeight = XtHeight(w);
2019 myWidth = XtWidth(w);
2022 newY = ((Position)(pHeight - myHeight) / 2) + pY;
2023 newX = ((Position)(pWidth - myWidth) / 2) + pX;
2025 XtSetArg(args[0], XmNx, newX);
2026 XtSetArg(args[1], XmNy, newY);
2027 XtSetValues(w, args, 2);
2029 return((XtCallbackProc) NULL);
2036 /*****************************************************************************
2037 * Function: void _DtHelpDisplayDefinitionBox(
2039 * Widget definitionBox,
2041 * char * locationId);
2047 * Purpose: This routine will create and post the definition box.
2048 * (e.g. the Quick Help Dialog widget)
2050 ****************************************************************************/
2051 void _DtHelpDisplayDefinitionBox(
2053 Widget **definitionBox,
2060 Widget printWidget, helpWidget, backWidget;
2061 XmString closeString;
2064 /* get the title from the main help dialog and use it here for */
2066 XtSetArg (args[n], XmNtitle, &(title)); ++n;
2067 XtGetValues (XtParent(parent), args, n);
2070 if (*definitionBox == NULL)
2073 /* Create the QuickHelpDialog widget to use as the definition box */
2074 closeString = XmStringCreateLocalized(((char *)_DTGETMESSAGE
2075 (HUSET, 2,"Close")));
2077 XtSetArg (args[n], DtNhelpVolume, path); n++;
2078 XtSetArg (args[n], DtNhelpType, DtHELP_TYPE_TOPIC); n++;
2079 XtSetArg (args[n], DtNlocationId, locationId); n++;
2080 XtSetArg (args[n], DtNcloseLabelString, closeString); n++;
2081 XtSetArg (args[n], XmNtitle, title); n++;
2083 (Widget *)DtCreateHelpQuickDialog(parent, "definitionBox",
2085 XmStringFree(closeString);
2087 /* Catch the close callback so we can destroy the widget */
2088 XtAddCallback((Widget)*definitionBox, DtNcloseCallback,
2089 CloseDefBoxCB, (XtPointer) NULL);
2092 /* We do not want a print button for now so we unmap it */
2093 printWidget = DtHelpQuickDialogGetChild ((Widget)*definitionBox,
2094 DtHELP_QUICK_PRINT_BUTTON);
2095 XtUnmanageChild (printWidget);
2097 /* We do not want a help button for now so we unmap it */
2098 helpWidget = DtHelpQuickDialogGetChild ((Widget)*definitionBox,
2099 DtHELP_QUICK_HELP_BUTTON);
2100 XtUnmanageChild (helpWidget);
2103 /* We do not want a BACK button for now so we unmap it */
2104 backWidget = DtHelpQuickDialogGetChild ((Widget)*definitionBox,
2105 DtHELP_QUICK_BACK_BUTTON);
2106 XtUnmanageChild (backWidget);
2110 /* Adjust the decorations for the dialog shell of the dialog */
2112 XtSetArg(args[n], XmNmwmFunctions, MWM_FUNC_RESIZE | MWM_FUNC_MOVE); n++;
2113 XtSetArg (args[n], XmNmwmDecorations,
2114 MWM_DECOR_BORDER | MWM_DECOR_TITLE | MWM_DECOR_RESIZEH); n++;
2115 XtSetValues (XtParent(*definitionBox), args, n);
2117 /* Add the popup position callback to our history dialog */
2118 XtAddCallback (XtParent(*definitionBox), XmNpopupCallback,
2119 (XtCallbackProc)_DtHelpMapCenteredCB, (XtPointer)XtParent(parent));
2126 /* We already have one so lets use it. */
2128 /* Set the proper title */
2130 XtSetArg (args[n], XmNtitle, title); ++n;
2131 XtSetValues (XtParent(*definitionBox), args, n);
2133 /* Set the proper contents. */
2135 XtSetArg (args[n], DtNhelpType, DtHELP_TYPE_TOPIC); n++;
2136 XtSetArg (args[n], DtNhelpVolume, path); n++;
2137 XtSetArg (args[n], DtNlocationId, locationId); n++;
2138 XtSetValues ((Widget)*definitionBox, args, n);
2143 /* Display the dialog */
2144 XtManageChild((Widget)*definitionBox);
2145 XtMapWidget(XtParent((Widget)*definitionBox));
2150 /*****************************************************************************
2151 * Function: static void CloseDefBoxCB(
2153 * XtPointer client_data,
2154 * XtPointer call_data);
2160 * Purpose: This routine closes and destroys the Definition Box
2161 * Dialog Widget that we create.
2163 ****************************************************************************/
2164 static void CloseDefBoxCB(
2166 XtPointer client_data,
2167 XtPointer call_data )
2179 /*****************************************************************************
2180 * Function: void _DtHelpDisplayFormatError()
2186 * Purpose: This routine generate and display the proper errror
2187 * message to the display area as well as send the proper
2188 * error to XmWarning() function.
2190 ****************************************************************************/
2191 void _DtHelpDisplayFormatError(
2192 XtPointer displayArea,
2197 XtPointer topicHandle;
2199 /* Set the string to the current help dialog */
2200 (void) _DtHelpFormatAsciiStringDynamic(displayArea, userError, &topicHandle);
2202 /* We ignor the status return here, because if we error out here we are
2203 * in big trouble because this is an error routine
2206 _DtHelpDisplayAreaSetList (displayArea, topicHandle, FALSE, -1);
2208 if (systemError != NULL)
2209 XmeWarning((Widget)widget, systemError);
2215 /*****************************************************************************
2216 * Function: void _DtHelpCommonHelpInit()
2222 * Purpose: This routine inits common help stuff
2224 ****************************************************************************/
2225 void _DtHelpCommonHelpInit(
2226 _DtHelpCommonHelpStuff * help)
2228 help->topLevelId = NULL;
2229 help->currentHelpFile = NULL;
2231 /* for help on help */
2232 if ( help->helpOnHelpVolume != _DtHelpDefaultHelp4HelpVolume)
2233 help->helpOnHelpVolume = XtNewString(help->helpOnHelpVolume);
2234 if ( NULL == help->helpOnHelpVolume )
2235 help->helpOnHelpVolume = (char *)_DtHelpDefaultHelp4HelpVolume;
2236 help->pHelpListHead = NULL; /* Help List Pointer */
2237 help->onHelpDialog = NULL; /* help on help dialog */
2238 help->pDisplayArea = NULL; /* Display widget handle */
2240 /* get the search paths used by the widget */
2241 help->userVolumeSearchPath = _DtHelpGetUserSearchPath();
2242 help->sysVolumeSearchPath = _DtHelpGetSystemSearchPath();
2247 /*****************************************************************************
2248 * Function: void _DtHelpCommonHelpClean()
2254 * Purpose: This routine cleans up common help stuff
2256 ****************************************************************************/
2257 void _DtHelpCommonHelpClean(
2258 _DtHelpCommonHelpStuff * help,
2261 free(help->topLevelId);
2262 XtFree(help->currentHelpFile);
2264 help->topLevelId = NULL;
2265 help->currentHelpFile = NULL;
2269 if (help->helpOnHelpVolume != _DtHelpDefaultHelp4HelpVolume)
2270 XtFree(help->helpOnHelpVolume);
2272 /* Free all the info we saved for our help callbacks */
2273 _DtHelpListFree(&help->pHelpListHead);
2275 XtFree(help->userVolumeSearchPath);
2276 XtFree(help->sysVolumeSearchPath);
2278 memset(help,0,sizeof(_DtHelpCommonHelpStuff));
2282 /* Set our display area to a null starting vlaues */
2283 _DtHelpDisplayAreaClean(help->pDisplayArea);
2289 /*****************************************************************************
2290 * Function: void _DtHelpSetDlgButtonsWidth
2296 * Purpose: This routine cleans up common help stuff
2298 ****************************************************************************/
2299 void _DtHelpSetButtonPositions(
2302 Dimension minFormWidth,
2303 Dimension btnMargins,
2304 Dimension minBetweenBtnSpace)
2305 { /* position buttons */
2307 /* This code adds up the sizes of the buttons to go into
2308 the bottom row and calculates the form position percentages.
2309 All buttons are the same size, and are able to hold all
2310 the strings that may be dynamically placed in them.
2311 All buttons are 5% apart. */
2312 /* This code is specifically written to handle 3 buttons
2313 and assumes that the first 3 strings are to the ActionBtn */
2314 Dimension minWidthWithSpace = 0;
2315 Dimension borderWidth = 0;
2316 Dimension sumWidth = 0;
2317 Dimension leftPos = 0;
2318 Dimension rightPos = 0;
2319 Dimension spaceWidth = 0;
2321 Dimension maxBtnWidth = 0;
2323 XmFontList fontList = NULL;
2328 if (numBtns <= 0 || NULL == btnList[0]) return;
2330 /* get the fontList for the button */
2331 XtSetArg (args[0], XmNborderWidth, &borderWidth);
2332 XtSetArg (args[1], XmNfontList, &fontList);
2333 XtGetValues (btnList[0], args, 2);
2334 /* assumption: the fontList that is returned is not owned by me; don't free */
2336 /* cycle through all buttons */
2337 for (i=0; i<numBtns && NULL!=btnList[i]; i++)
2339 XmString labelString;
2341 /* get the label from the button */
2342 XtSetArg (args[0], XmNlabelString, &labelString);
2343 XtGetValues (btnList[i], args, 1);
2345 btnWidth = XmStringWidth(fontList,labelString) + borderWidth + btnMargins;
2346 if (btnWidth > maxBtnWidth) maxBtnWidth = btnWidth;
2348 XmStringFree(labelString);
2349 } /* for calcing widths */
2350 numBtns = i; /* number of valid buttons */
2352 /* calc the space */
2353 sumWidth = maxBtnWidth * numBtns;
2354 minWidthWithSpace = sumWidth + minBetweenBtnSpace * (numBtns * 2);
2355 if (minWidthWithSpace > minWidthWithSpace) minFormWidth = minWidthWithSpace;
2356 spaceWidth = ((int)(minFormWidth - sumWidth) / (numBtns * 2));
2358 /* scale pixels to percent */
2359 scale = 100.0 / (float) minFormWidth;
2361 /* set the positions of each button */
2362 leftPos = spaceWidth;
2363 for ( i=0; i<numBtns; i++ )
2365 rightPos = leftPos + maxBtnWidth;
2368 XtSetArg (args[n], XmNleftAttachment, XmATTACH_POSITION); n++;
2369 XtSetArg (args[n], XmNleftPosition, (Dimension) (((float) leftPos)*scale)); n++;
2370 XtSetArg (args[n], XmNrightAttachment, XmATTACH_POSITION); n++;
2371 XtSetArg (args[n], XmNrightPosition,(Dimension) (((float) rightPos)*scale)); n++;
2372 XtSetValues (btnList[i], args, n);
2374 leftPos = rightPos + spaceWidth + spaceWidth;
2375 } /* setup the positions for all buttons */
2376 } /* _DtHelpSetDlgButtonsWidth */
2380 /*****************************************************************************
2381 * Function: _DtHelpXmFontListGetPropertyMax
2384 * fontList: an XmFontList
2385 * atom: an XA_xxx value (see Vol 1, chpt 6.2.9)
2386 * ret_propertyValue: ptr to long value that will hold the max value
2389 * True: got at least one value
2390 * False: unable to get any value; ret_propertyValue unchanged
2393 * This function returns the max value of XGetFontProperty calls
2394 * for each font in the XmFontList
2395 * If there is an error, ret_propertyValue is left unchanged.
2397 ****************************************************************************/
2399 _DtHelpXmFontListGetPropertyMax(
2400 XmFontList fontList,
2402 unsigned long *ret_propertyValue)
2404 Boolean gotValue = False;
2405 XmFontContext context;
2406 XmFontListEntry entry;
2409 if (NULL == fontList) return False; /* RETURN on error */
2411 /* walk through the fontList entries and add them in */
2412 XmFontListInitFontContext(&context,fontList);
2413 for ( entry = XmFontListNextEntry(context);
2415 entry = XmFontListNextEntry(context) )
2417 unsigned long value;
2420 fontData = XmFontListEntryGetFont(entry,&type);
2421 if (XmFONT_IS_FONT == type)
2423 XFontStruct * fontStruct;
2425 /* cast according to type */
2426 fontStruct = (XFontStruct *) fontData;
2428 if(XGetFontProperty(fontStruct, atom, &value) == TRUE)
2430 if(gotValue == False) /* haven't gotten any prop value yet */
2432 *ret_propertyValue = value;
2435 else /* have a good prop value already...get the max one */
2437 if(value > *ret_propertyValue)
2438 *ret_propertyValue = value;
2440 } /* if the getproperty call was good */
2442 else /* XmFONT_IS_FONTSET */
2445 XFontStruct **font_list;
2450 /* cast according to type */
2451 fontSet = (XFontSet) fontData;
2453 numfont=XFontsOfFontSet(fontSet,&font_list,&name_list);
2454 for(i = 0; i < numfont; i++)
2456 if(XGetFontProperty(font_list[i], atom, &value) == TRUE)
2458 if(gotValue == False) /* haven't gotten any prop value yet */
2460 *ret_propertyValue = value;
2463 else /* have a good prop value already...get the max one */
2465 if(value > *ret_propertyValue)
2466 *ret_propertyValue = value;
2468 } /* if the getproperty call was good */
2469 } /* for all fonts in the font set */
2470 } /* this entry uses a font set */
2471 } /* for all font entries in the font list */
2472 XmFontListFreeFontContext(context);