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/keysymdef.h>
63 #include <X11/Shell.h>
64 #include <X11/Intrinsic.h>
65 #include <X11/cursorfont.h>
67 /* private includes */
70 #include "DisplayAreaI.h"
75 #include "StringFuncsI.h"
76 #include "HelpDialogI.h"
77 #include "HelpDialogP.h"
78 #include "HelpUtilI.h"
80 #include "MessagesP.h"
81 #include "HelpQuickD.h"
84 #include "HelpAccessI.h"
85 #include "FileUtilsI.h"
86 #include "HourGlassI.h"
89 #include <Dt/DtNlUtils.h>
91 /******* global variables *******/
92 char _DtHelpDefaultHelp4HelpVolume[] = "Help4Help";
93 char _DtHelpDefaultLocationId[] = "_HOMETOPIC";
95 /**** Help Util Error message Defines ****/
97 #define UtilMessage0 _DtHelpMsg_0010
98 #define UtilMessage2 _DtHelpMsg_0011
101 static void _DtMessageClose(
103 XtPointer client_data,
105 static void CloseDefBoxCB(
107 XtPointer client_data,
108 XtPointer call_data);
110 /* Macro for finding a point within a gadget.
111 * Its used for item help
113 #define PT_IN_CHILD(X, Y, CHILD) \
114 ((((int)(X)) >= ((int) (CHILD)->core.x)) && \
115 (((int)(X)) <= ((int)((CHILD)->core.x + (CHILD)->core.width))) && \
116 (((int)(Y)) >= ((int) (CHILD)->core.y)) && \
117 (((int)(Y)) <= ((int)((CHILD)->core.y + (CHILD)->core.height))))
120 /******** useful constants ********/
122 #define DIR_SLASH '/'
124 #define HUSET 8 /* message catalog set */
126 /******** static variables ********/
127 static char DirSlash[] = "/";
129 /******** data structures ********/
130 typedef struct ExecContext
133 XtPointer pDisplayArea;
136 /******** The onitem cursor (32x32, xbm format) ********/
137 #define onitem32_width 32
138 #define onitem32_height 32
139 #define onitem32_x_hot 0
140 #define onitem32_y_hot 0
141 static unsigned char onitem32_bits[] = {
142 0xff, 0xff, 0xff, 0xff, 0xfd, 0xff, 0x1f, 0xfc, 0xf9, 0xff, 0xe7, 0xf3,
143 0xf1, 0xff, 0xfb, 0xef, 0xe1, 0xff, 0xfd, 0xdf, 0xc1, 0xff, 0xfd, 0xdf,
144 0x83, 0xff, 0xfe, 0xbf, 0x03, 0xff, 0x7e, 0x7e, 0x03, 0xfe, 0xbe, 0x7d,
145 0x03, 0xfc, 0xbe, 0x7d, 0x03, 0xf0, 0xc1, 0x7d, 0x03, 0xe0, 0xff, 0x7e,
146 0x07, 0xc0, 0x7f, 0xbf, 0x07, 0x80, 0xbf, 0xbf, 0x07, 0x00, 0xde, 0xdf,
147 0x07, 0x00, 0xdc, 0xef, 0x07, 0x00, 0xdf, 0xf7, 0x07, 0x80, 0xdf, 0xfb,
148 0x0f, 0xc0, 0xdf, 0xfb, 0x0f, 0xc0, 0xdf, 0xfb, 0x0f, 0x81, 0xdf, 0xfb,
149 0xcf, 0x83, 0x3f, 0xfc, 0xef, 0x07, 0xff, 0xff, 0xff, 0x07, 0xff, 0xff,
150 0xff, 0x0f, 0x3e, 0xfc, 0xff, 0x0f, 0xde, 0xfb, 0xff, 0x1f, 0xdc, 0xfb,
151 0xff, 0x1f, 0xdc, 0xfb, 0xff, 0x3f, 0xd8, 0xfb, 0xff, 0x3f, 0x3c, 0xfc,
152 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
154 #define onitem32_m_width 32
155 #define onitem32_m_height 32
156 #define onitem32_m_x_hot 0
157 #define onitem32_m_y_hot 0
158 static unsigned char onitem32_m_bits[] = {
159 0x03, 0x00, 0x00, 0x00, 0x07, 0x00, 0xe0, 0x03, 0x0f, 0x00, 0xf8, 0x0f,
160 0x1f, 0x00, 0xfc, 0x1f, 0x3f, 0x00, 0xfe, 0x3f, 0x7f, 0x00, 0xfe, 0x3f,
161 0xfe, 0x00, 0xff, 0x7f, 0xfe, 0x01, 0xff, 0xff, 0xfe, 0x03, 0x7f, 0xfe,
162 0xfe, 0x0f, 0x7f, 0xfe, 0xfe, 0x1f, 0x3e, 0xfe, 0xfe, 0x3f, 0x00, 0xff,
163 0xfc, 0x7f, 0x80, 0x7f, 0xfc, 0xff, 0xc1, 0x7f, 0xfc, 0xff, 0xe3, 0x3f,
164 0xfc, 0xff, 0xe7, 0x1f, 0xfc, 0xff, 0xe3, 0x0f, 0xfc, 0xff, 0xe0, 0x07,
165 0xf8, 0x7f, 0xe0, 0x07, 0xf8, 0x7f, 0xe0, 0x07, 0xf8, 0xff, 0xe0, 0x07,
166 0xf8, 0xfe, 0xc0, 0x03, 0x38, 0xfc, 0x01, 0x00, 0x18, 0xfc, 0x01, 0x00,
167 0x00, 0xf8, 0xc3, 0x03, 0x00, 0xf8, 0xe3, 0x07, 0x00, 0xf0, 0xe7, 0x07,
168 0x00, 0xf0, 0xe7, 0x07, 0x00, 0xe0, 0xef, 0x07, 0x00, 0xe0, 0xc7, 0x03,
169 0x00, 0xc0, 0x03, 0x00, 0x00, 0x80, 0x00, 0x00};
171 #if 0 /* XPM format */
172 static char * onitem32_xpm[] = {
173 /* width height ncolors cpp [x_hot y_hot] */
176 " s iconColor1 m black c black",
177 ". s background m black c #969696969696",
178 "X s iconColor2 m white c white",
180 " ..............................",
181 " X ..................XXXXX......",
182 " XX ...............XX XX....",
183 " XXX .............X X...",
184 " XXXX ...........X X..",
185 " XXXXX ..........X X..",
186 ". XXXXX ........X X.",
187 ". XXXXXX .......X XX X",
188 ". XXXXXXX ......X X..X X",
189 ". XXXXXXXX ....X X..X X",
190 ". XXXXXXXXXX ....XXXXX...X X",
191 ". XXXXXXXXXXX ..........X X",
192 ".. XXXXXXXXXXX ........X X.",
193 ".. XXXXXXXXXXXX .....X X.",
194 ".. XXXXXXXXXXXXXX ...X X..",
195 ".. XXXXXXXXXXXXXXX ..X X...",
196 ".. XXXXXXXXXXXXX ...X X....",
197 ".. XXXXXXXXXXXX .....X X.....",
198 "... XXXXXXXXXX ......X X.....",
199 "... XXXXXXXXXX ......X X.....",
200 "... XXXX XXXXXX .....X X.....",
201 "... XX . XXXXX ......XXXX......",
202 "... X .... XXXXX ...............",
203 "... ..... XXXXX ...............",
204 "........... XXXXX ....XXXX......",
205 "........... XXXXX ...X X.....",
206 "............ XXXXX ..X X.....",
207 "............ XXXXX ..X X.....",
208 "............. XXXXX .X X.....",
209 "............. XXXX ...XXXX......",
210 ".............. X ..............",
211 "............... ................"};
218 #define NO_CONDITION 0
219 #define MISMATCHING_HOME_DIRS 1
221 /* ------------------------------------------------------------ *
225 ** Purpose Determines if the passed help volume is a
226 ** "trusted" help volume or not. We call it
227 ** trusted if it meets the following conditions:
228 ** 1. File Owner is root, bin, or system.
229 ** 2. File is NOT writable by group or others.
232 ** True - if the help volume IS Trusted
233 ** False - if the help volume is NOT Trusted
235 ** ------------------------------------------------------------ */
236 static Boolean trusted (char *hv_path) /* Full path to the help volume */
241 if ( (stat (hv_path, &buf)) == -1)
245 /* S_IWGRP */ /* write group */
246 /* S_IWOTH */ /* write other */
248 /** ---------------------------------------------------------------------- *
249 ** The help volume MUST be owned by root, bin, or sys to be trusted.
250 ** ---------------------------------------------------------------------- */
252 if ( buf.st_uid != ROOT_USER &&
253 buf.st_uid != BIN_USER &&
254 buf.st_uid != SYS_USER)
259 /** ----------------------------------------------------------------------- *
260 ** The help volume MUST not be writable by group or others to be trusted.
261 ** ----------------------------------------------------------------------- */
263 writable = (((buf.st_mode & S_IWGRP) == 0) && (buf.st_mode & S_IWOTH) == 0) ?
271 /*>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
272 /**** API Error Dialog Support Functions *****/
273 /*>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
276 /************************************************************************
277 * Function: _DtMessageClose
279 * Close the error/info message box.
281 ************************************************************************/
282 static void _DtMessageClose(
284 XtPointer client_data,
287 /* NOTE: ExecuteContextCB() is dependent on this code */
288 if (event->type == UnmapNotify)
290 XtRemoveEventHandler (XtParent (client_data), StructureNotifyMask,
291 True, (XtEventHandler) _DtMessageClose, client_data);
293 XtUnmanageChild (client_data);
294 XtDestroyWidget (client_data);
298 /************************************************************************
299 * Function: ExecuteContextCB
301 * Execute an execution context
303 ************************************************************************/
304 static void ExecuteContextCB(
306 XtPointer client_data,
309 ExecContext * ec = (ExecContext *) client_data;
311 if (ec && ec->command && ec->pDisplayArea)
313 _DtHelpExecProcedure(ec->pDisplayArea,ec->command);
318 /* unmap, rather than unmanage and destroy, because of the code
319 in _DtMessageClose(). _DtMessageClose() is notified when
320 the widget unmaps and it destroys the widget. */
321 XtUnmapWidget(w); /* w is the message dialog */
324 /*****************************************************************************
325 * Function: CreateErrorDialog
327 * Creates an XmMessageDialog with the message and all buttons
328 * except the 'Close' (OK) button unmanaged.
329 * Also adds a callback that destroys the widget when the dialog is closed.
331 *****************************************************************************/
338 Widget messageDialog;
342 XmString label_string;
346 /* Setup the message string and dialog title */
348 ok_string = XmStringCreateLocalized(((char *)_DTGETMESSAGE
349 (HUSET, 2,"Close")));
350 label_string = XmStringCreateLocalized(message);
351 title_string = XtNewString((char *)_DTGETMESSAGE
352 (HUSET, 5,"Help Error"));
355 XtSetArg (args[n], XmNmessageString, label_string); n++;
356 XtSetArg (args[n], XmNtitle,title_string); n++;
357 XtSetArg (args[n], XmNcancelLabelString, ok_string); n++;
358 XtSetArg (args[n], XmNdefaultButtonType, XmDIALOG_CANCEL_BUTTON); n++;
359 messageDialog = XmCreateErrorDialog (parent, "errorDialog",
361 XtSetArg(args[0], XmNmwmDecorations,
362 MWM_DECOR_BORDER | MWM_DECOR_TITLE);
363 XtSetArg(args[1], XmNuseAsyncGeometry, True);
364 XtSetValues(XtParent(messageDialog), args, 2);
366 XmStringFree (label_string);
367 XmStringFree (ok_string);
368 XtFree(title_string);
370 /* unmanage or define the other buttons */
371 button = XmMessageBoxGetChild (messageDialog, XmDIALOG_OK_BUTTON);
372 XtUnmanageChild (button);
373 button = XmMessageBoxGetChild (messageDialog, XmDIALOG_HELP_BUTTON);
374 XtUnmanageChild (button);
376 /* StructureNotifyMask gets Circulate, Configure, Destroy,
377 Gravity, Map, Reparent, & Unmap events */
378 XtAddEventHandler(XtParent(messageDialog),
379 StructureNotifyMask,True,
380 (XtEventHandler) _DtMessageClose, (XtPointer) messageDialog);
382 return messageDialog; /* RETURN */
386 /*****************************************************************************
387 * Function: CreateExecErrorDlg
392 *****************************************************************************/
397 Boolean invalidAlias,
398 _DtHelpCommonHelpStuff * pHelpStuff,
402 DtHelpListStruct *pHelpInfo;
408 /* handle the error case */
411 msg = (char *)_DTGETMESSAGE(HUSET, 12,
412 "The help volume wanted to execute a command alias.\n"
413 "The alias '%s' is not defined.");
416 else if (condition == MISMATCHING_HOME_DIRS)
418 msg = (char *)_DTGETMESSAGE(HUSET, 14,
419 "The help volume wanted to execute a command as the root user, but the\n"
420 "home directory of \"%s\" ($HOME) does not match the root\n"
421 "user's home directory. This could result in executing unexpected\n"
424 "The command is: \"%s\"\n\n"
426 "Note: to avoid this in the future:\n"
427 " execute \"su - root\" rather than \"su root\".\n");
432 msg = (char *)_DTGETMESSAGE(HUSET, 13,
433 "The help volume wanted to execute a command.\n"
434 "For security reasons, automatic command execution is turned off.\n"
435 "The command is: %s");
437 fullmsg = (char *) malloc(strlen(msg)+strlen(cmdStr)+30);
440 if (condition == MISMATCHING_HOME_DIRS)
441 sprintf(fullmsg, msg, current_hd, cmdStr);
443 sprintf(fullmsg,msg,cmdStr);
448 /* create an error dialog, but don't manage it yet */
449 msgDlg = CreateErrorDialog(XtParent(helpWidget),fullmsg);
451 if (msg != fullmsg) free(fullmsg);
453 btn = XmMessageBoxGetChild (msgDlg, XmDIALOG_HELP_BUTTON);
454 XtManageChild (btn); /* re-manage the button */
456 /* add the HelpOnHelp callback */
457 pHelpInfo = _DtHelpListAdd(DtHELP_ExecutionPolicy_STR,
458 helpWidget, pHelpStuff, &pHelpStuff->pHelpListHead);
459 XtAddCallback(btn, XmNactivateCallback, _DtHelpCB, (XtPointer) pHelpInfo);
464 /*****************************************************************************
465 * Function: _DtHelpErrorDialog
470 *****************************************************************************/
471 void _DtHelpErrorDialog(
475 Widget messageDialog;
477 messageDialog = CreateErrorDialog(parent,message);
479 /* Display help window. This used to be before the call
480 to add a StructureNotify event handler */
481 XtManageChild (messageDialog);
485 /*****************************************************************************
486 * Function: _DtHelpFilterExecCmdStr
489 * helpWidget: help widget requesting to exec the command
490 * pDisplayStuff: ptr to the DisplayWidget stuff of the help widget
491 * commandStr: command string to execute
492 * ret_cmdStr: the screened & possibly rewritten command is put here
493 * ret_invalidAlias: was the command an invalid alias?
494 * ret_execPermitted: if executionPolicy permit exec & ret_cmdStr is valid
495 * ret_queryNeeded: if executionPolicy requires a query before exec
498 * ret_cmdStr gets memory owned by the calling function; it should be
499 * freed when no longer needed. The string will be the same as the
500 * commandStr if commandStr was not an alias. If the commandStr
501 * is an alias and if the alias is defined, the ret_cmdStr will be the
502 * value of the alias. If the alias isn't defined, the ret_cmdStr will
503 * be the default command if available, or the alias name otherwise.
505 * ret_invalidAlias will be True if the alias was undefined and
506 * no default command was given.
508 * ret_execPermitted will be True if executionPolicy is DtHELP_EXECUTE_ALL
509 * or DtHELP_EXECUTE_QUERY_xxx and ret_cmdStr is valid
511 * ret_queryNeeded will be True if executionPoilcy is
512 * DtHELP_EXECUTE_QUERY_ALL or if it is DtHELP_EXECUTE_QUERY_UNALIASED
513 * and ret_cmdStr did not derive from an alias (i.e. was hardcoded
514 * in the help volume, not retrieved from a resource).
517 * True: if execPermitted and a valid command string
518 * False: if if execPermitted is False or invalid command string
521 * This code is written such that we don't need nor want to know
522 * whether it is a general or quick help widget.
525 * command string must be writable; it is written, but left
526 * unchanged when the function exits.
528 *****************************************************************************/
529 Boolean _DtHelpFilterExecCmdStr(
531 unsigned char executionPolicy,
532 const char * commandStr,
534 Boolean * ret_invalidAlias,
535 Boolean * ret_execPermitted,
536 Boolean * ret_queryNeeded,
537 char * hv_path) /* Path to the Help Volume */
542 char * aliasCommand = NULL;
545 #define RN_execAlias "executionAlias"
546 #define RC_execAlias "ExecutionAlias"
547 #define ExecAliasCmd "DtHelpExecAlias"
551 *ret_invalidAlias = False;
552 *ret_execPermitted = False;
553 *ret_queryNeeded = False;
555 if (NULL == commandStr)
558 /** ------------------------------------------------------------- *
559 ** If the executionPolicy is query all unaliased (query for all
560 ** execution links that have no execution alias defined), we
561 ** make an exception: only query the user for help volumes
562 ** deemed NOT "trusted".
563 ** ------------------------------------------------------------- */
565 if (DtHELP_EXECUTE_QUERY_UNALIASED == executionPolicy)
567 if ( ! (trusted (hv_path)))
568 *ret_queryNeeded = True; /* Query ALL non-trusted help volumes */
571 *ret_queryNeeded = (DtHELP_EXECUTE_QUERY_ALL == executionPolicy);
573 /* get whether exec permitted */
574 if ( DtHELP_EXECUTE_ALL == executionPolicy
575 || DtHELP_EXECUTE_QUERY_UNALIASED == executionPolicy
576 || DtHELP_EXECUTE_QUERY_ALL == executionPolicy)
577 *ret_execPermitted = True;
579 *ret_execPermitted = False;
581 /* parse apart the command string, looking for DtHelpExecAlias */
582 /* The first call will return true, with the first string */
583 token = (char *) commandStr + DtStrspn((char *)commandStr, " \t");
584 tokenEnd = token + DtStrcspn(token, " \t");
585 tokenEndChar = *tokenEnd;
586 if (tokenEnd) *tokenEnd = EOS;
588 if ( NULL == token || _DtHelpCeStrCaseCmpLatin1(token, ExecAliasCmd) != 0 )
590 /*** the command is not an alias; proceed using execution Policy ***/
592 *tokenEnd = tokenEndChar; /* restore the string */
594 *ret_cmdStr = strdup(commandStr);
595 ret = *ret_execPermitted;
597 return ret; /* RETURN ret */
601 /**** It's an alias; get it , look it up, and return it ****/
603 *tokenEnd = tokenEndChar; /* restore the string */
605 /* get the next token */
606 token = tokenEnd + DtStrspn(tokenEnd, " \t");
607 tokenEnd = token + DtStrcspn(token, " \t");
608 tokenEndChar = *tokenEnd;
609 if (tokenEnd) *tokenEnd = EOS;
613 Display * dpy = XtDisplay(helpWidget);
614 XrmDatabase appDb = XrmGetDatabase(dpy);
616 String appname, appclass;
618 char *rsrc_name, *rsrc_class;
620 rsrc_name = XtMalloc(200);
621 rsrc_class = XtMalloc(200);
623 XtGetApplicationNameAndClass(dpy,&appname,&appclass);
625 /* query the application's database for the alias command */
626 /* build alias resource class and resource */
627 /* e.g. App.executionAlias.<alias> */
628 sprintf(rsrc_name,"%s.%s.%s",appclass, RN_execAlias,token);
629 /* e.g. App.ExecutionAlias.<alias> */
630 sprintf(rsrc_class,"%s.%s.%s",appclass, RC_execAlias,token);
632 /* Get alias command */
633 if (XrmGetResource(appDb,rsrc_name,rsrc_class,&reptype,&value) == True)
634 aliasCommand = value.addr;
636 /* build alias resource name and resource */
637 /* e.g. app.executionAlias.<alias> */
638 sprintf(rsrc_name,"%s.%s.%s",appname, RN_execAlias,token);
639 /* e.g. app.ExecutionAlias.<alias> */
640 sprintf(rsrc_class,"%s.%s.%s",appname, RC_execAlias,token);
642 /* Get alias command and override class with instance, if defined */
643 if (XrmGetResource(appDb,rsrc_name,rsrc_class,&reptype,&value) == True)
644 aliasCommand = value.addr;
646 if (rsrc_name) XtFree(rsrc_name);
647 if (rsrc_class) XtFree(rsrc_class);
648 } /* if alias token */
654 if (tokenEnd) *tokenEnd = tokenEndChar; /* restore the string */
656 /* alias was defined */
659 *ret_cmdStr = strdup(aliasCommand);
660 /* see if query needed; is not if policy is query_unaliased or all */
661 *ret_queryNeeded = !( DtHELP_EXECUTE_QUERY_UNALIASED == executionPolicy
662 || DtHELP_EXECUTE_ALL == executionPolicy);
663 ret = *ret_execPermitted;
665 else /* the alias wasn't defined */
667 char * aliasToken = token; /* token currently pts to alias */
669 /* look for a default command */
670 /* get the next token */
671 token = tokenEnd + DtStrspn(tokenEnd, " \t");
672 tokenEnd = token + DtStrcspn(token, " \t");
674 if (token == tokenEnd)
675 { /* alias wasn't defined and no default command */
676 *ret_cmdStr = strdup(aliasToken);
677 *ret_invalidAlias = True;
678 *ret_queryNeeded = False; /* no query needed on invalid alias, ever */
679 *ret_execPermitted = False; /* can't exec an invalid alias */
683 { /* alias wasn't defined but a default command */
684 /* query is whatever was determined earlier */
685 *ret_cmdStr = strdup(token);
686 ret = *ret_execPermitted;
690 return ret; /* RETURN ret */
693 /*********************************************************************
694 * _DtHelpCeWaitAndProcessEvents
697 * _DtHelpCeWaitAndProcessEvents will process events and call
698 * the waitProc until waitProc returns False. This function
699 * is useful to put up modal dialogs that must be reponded to
700 * in the midst of executing code that must remain on the call stack.
703 * This function should only be used on modal dialogs.
705 *********************************************************************/
708 _DtHelpCeWaitAndProcessEvents (
710 _DtHelpCeWaitProc waitProc,
717 app = XtWidgetToApplicationContext(w);
721 XtAppNextEvent(app,&event);
722 XtDispatchEvent(&event);
726 while (!(mask = XtAppPending(app)))
727 ; /* Busy waiting - so we don't lose our Lock! */
729 if (mask & XtIMXEvent) /* We have an XEvent */
731 /* Get the XEvent - we know it's there! Note that XtAppNextEvent
732 would also process timers/alternate inputs.
734 XtAppNextEvent(app, &event); /* No blocking, since an event is ready */
735 XtDispatchEvent(&event);
737 else /* Not a XEvent, it's an alternate input/timer event */
739 XtAppProcessEvent(app, mask); /* No blocking, since an event is ready */
741 #endif /* XTHREADS */
742 /* check to see if we're done waiting */
743 waitFlag = (*waitProc)(w, clientData);
747 /*****************************************************************************
748 * Function: WaitForBtnActivatedCB
751 * Treats the 'clientData' as a pointer to an integer
752 * and turns its value into a Boolean
754 * Returns: *(int *)clientData < 0
755 *****************************************************************************/
757 WaitForBtnActivatedCB(
761 return (*(int *)clientData < 0);
762 /* True=keep waiting; False= wait no longer */
766 typedef struct ModalMsgDlgCBStruct
773 } ModalMsgDlgCBStruct;
775 /*****************************************************************************
776 * Function: IdentifyActivatedBtnCB
779 * Treats the 'clientData' as a pointer to an integer.
780 * Waits for the value pointed to by clientData to be >= 0.
782 *****************************************************************************/
784 IdentifyActivatedBtnCB(
786 XtPointer clientData,
789 ModalMsgDlgCBStruct * pMd = (ModalMsgDlgCBStruct *) clientData;
791 /* w must be a XmMessageDialog widget */
793 { pMd->activatedBtnId = XmDIALOG_OK_BUTTON; return; /* RETURN */ }
794 if (pMd->cancelBtn == w)
795 { pMd->activatedBtnId = XmDIALOG_CANCEL_BUTTON; return; /* RETURN */ }
796 if (pMd->helpBtn == w)
797 { pMd->activatedBtnId = XmDIALOG_HELP_BUTTON; return; /* RETURN */ }
798 pMd->activatedBtnId = -1; /* unknown button */
802 /*****************************************************************************
803 * Function: _DtHelpFilterExecCmd
806 * helpWidget: help widget requesting to exec the command
807 * command: command string to execute
808 * execPolicy: current policy setting
809 * useQueryDialog: use a dialog to query user whether to exec, if not allowed
810 * pHelpStuff: ptr to the HelpStuff structure of the help widget
811 * ret_filteredCmdStr: filtered command string
814 * 0: no error; filteredCmdStr can be exec'd
815 * -1: error: either internal or executionPolicy denies exec;
816 * filteredCmdStr is NULL
819 * This function filters an execution command string. This can
820 * occur in several ways. In all cases, the command string is
821 * supports command alias replacement. If the final outcome
822 * is that execution is permitted, the returned string is
823 * is the command string to execute. If execution is not
824 * permitted, the return string is a NULL pointer.
826 * Filtering of the command occurs as follows.
827 * If executionPolicy permits execution, only alias replacement occurs.
828 * If executionPolicy does restrict execution and a
829 * dialog is requested, then a modal dialog is posted and the
830 * user can decide whether to execute or not.
831 * If a dialog is not requested, the return string is NULL.
834 * This code is written such that we don't need nor want to know
835 * whether it is a general or quick help widget.
838 * command string must be writable; it is written, but left
839 * unchanged whent the function exits.
841 * This operation is synchronous, meaning that, if a dialog is
842 * posted, it is a modal dialog and the function won't return
843 * until the user selects a button.
846 *****************************************************************************/
847 int _DtHelpFilterExecCmd(
849 const char * commandStr,
850 unsigned char executionPolicy,
851 Boolean useQueryDialog,
852 _DtHelpCommonHelpStuff * pHelpStuff,
853 char * * ret_filteredCmdStr,
856 ModalMsgDlgCBStruct msgDlgCBStruct;
858 Boolean invalidAlias;
859 Boolean execPermitted;
862 char * filteredCmdStr = NULL;
865 XmString labelString;
866 XmString labelString2;
871 goodCmd = _DtHelpFilterExecCmdStr(helpWidget, executionPolicy,
872 commandStr, &filteredCmdStr, &invalidAlias,
873 &execPermitted, &queryNeeded, hv_path);
875 /* if permissions allow immediate execution, do so */
876 if (execPermitted && False == queryNeeded)
878 *ret_filteredCmdStr = filteredCmdStr;
879 return 0; /* RETURN ok */
882 if (False == useQueryDialog)
884 *ret_filteredCmdStr = NULL;
885 return -1; /* RETURN error */
888 /* create the dialog, but don't yet manage it */
889 msgDlg = CreateExecErrorDlg(helpWidget,filteredCmdStr,
890 invalidAlias,pHelpStuff, NO_CONDITION, "");
892 /* if a bad alias or no exec permitted,
893 don't need to wait for a response; dlg has close & Help */
894 if (False == execPermitted || False == queryNeeded)
896 XtManageChild(msgDlg); /* manage modeless dialog */
897 *ret_filteredCmdStr = NULL; /* don't execute */
898 XtFree(filteredCmdStr);
899 return -1; /* RETURN error */
902 /* if got this far, query is needed;make the dialog include
903 Execute Anyway and Don't Execute buttons */
905 /* give the right title to the buttons */
906 labelString = XmStringCreateLocalized(((char *)_DTGETMESSAGE
907 (HUSET, 10,"Execute Anyway")));
908 /* give the right title to the Cancel button */
909 labelString2 = XmStringCreateLocalized(((char *)_DTGETMESSAGE
910 (HUSET, 11,"Don't Execute")));
912 XtSetArg (args[n], XmNokLabelString, labelString); n++;
913 XtSetArg (args[n], XmNcancelLabelString, labelString2); n++;
914 XtSetArg (args[n], XmNdialogStyle, XmDIALOG_PRIMARY_APPLICATION_MODAL); n++;
915 XtSetValues(msgDlg,args,n);
916 XmStringFree(labelString);
917 XmStringFree(labelString2);
919 /* We put an activate callback on the DontExecute and ExecuteAnyway buttons
920 and wait until a button is pressed. */
921 noexecBtn = XmMessageBoxGetChild (msgDlg, XmDIALOG_CANCEL_BUTTON);
922 XtAddCallback(noexecBtn, XmNactivateCallback,
923 IdentifyActivatedBtnCB, (XtPointer) &msgDlgCBStruct);
925 execBtn = XmMessageBoxGetChild (msgDlg, XmDIALOG_OK_BUTTON);
926 XtManageChild (execBtn); /* re-manage the button */
927 XtAddCallback(execBtn, XmNactivateCallback,
928 IdentifyActivatedBtnCB, (XtPointer) &msgDlgCBStruct);
930 /* fill out the CB information structure used by IdentifyActivatedBtnCB */
931 msgDlgCBStruct.msgDlg = msgDlg;
932 msgDlgCBStruct.okBtn = execBtn;
933 msgDlgCBStruct.cancelBtn = noexecBtn;
934 msgDlgCBStruct.activatedBtnId = -1;
936 /* Display message dialog */
937 XtManageChild (msgDlg);
940 * turn on the modal dialog indicator
942 _DtHelpTurnOnNoEnter(helpWidget);
944 /* wait until 'msgDlgCBStruct.activatedBtnId' has a value >= 0 */
945 /* this occurs when the user responds to the msg dialog */
946 _DtHelpCeWaitAndProcessEvents(msgDlg,
947 WaitForBtnActivatedCB, &msgDlgCBStruct.activatedBtnId);
950 * turn off the modal dialog indicator
952 _DtHelpTurnOffNoEnter(helpWidget);
954 /* no need to destroy msgDlg; it has a closeCallback to do that */
956 /* act based on which button was activated */
957 if (msgDlgCBStruct.activatedBtnId == XmDIALOG_OK_BUTTON)
959 *ret_filteredCmdStr = filteredCmdStr; /* do execute command */
960 return 0; /* RETURN ok */
964 *ret_filteredCmdStr = NULL; /* don't execute */
965 XtFree(filteredCmdStr);
966 return -1; /* RETURN error */
970 /*****************************************************************************
971 * Function: _DtHelpExecFilteredCmd
974 * helpWidget: help widget requesting to exec the command
975 * command: command string to execute
976 * modal: is the execution modal (sync) or modeless (async)
977 * helpLocationId: helpOnHelp file location for Help btn in error dialog
978 * pDisplayStuff: ptr to the DisplayWidget stuff of the help widget
979 * pHelpStuff: ptr to the CommonHelp stuff of the help widget
982 * This code is written such that we don't need nor want to know
983 * whether it is a general or quick help widget.
986 * command string must be writable; it is written, but left
987 * unchanged whent the function exits.
989 * At the moment, the helpLocationId is ignored, and the
990 * help location is hardwired to DtHELP_ExecutionPolicy_STR
991 * in CreateExecErrorDialog().
993 *****************************************************************************/
994 void _DtHelpExecFilteredCmd(
997 char * helpLocationId,
998 _DtHelpDisplayWidgetStuff * pDisplayStuff,
999 _DtHelpCommonHelpStuff * pHelpStuff)
1002 Boolean invalidAlias;
1003 Boolean execPermitted;
1004 Boolean queryNeeded;
1005 char * filteredCmdStr = NULL;
1006 ExecContext * execContext;
1007 DtHelpListStruct *pHelpInfo;
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
1027 _Xgetpwparams pwd_buf;
1028 struct passwd * pwd_ret;
1030 /** -------------------------------------------------------------- *
1031 ** If we're running as the root user
1032 ** o check if the value of the HOME env var matches
1033 ** root's home directory (defined by /etc/passwd).
1034 ** o If they do not match, then present a dialog
1035 ** alerting the user of this, along with the command to
1037 ** -------------------------------------------------------------- */
1039 if ( (user=getuid()) == ROOT_USER)
1041 home_dir = getenv ("HOME");
1043 if (home_dir != NULL && strlen(home_dir) >= (size_t) 1)
1045 if (((pwd_ret = _XGetpwuid(user, pwd_buf)) != NULL)
1046 && (strcmp(home_dir, pwd_ret->pw_dir)))
1048 diff_home_dirs = True;
1053 hv_path = _DtHelpFileLocate(DtHelpVOLUME_TYPE, pDisplayStuff->helpVolume,
1054 _DtHelpFileSuffixList, False, R_OK);
1056 /* The desired and intended behaviour is to use _DtHelpFilterExecCmdStr(), but
1057 the other code is left here, should a change be wished. */
1059 /* This function runs a filter for policy and alias but posts no dialog */
1060 goodCmd=_DtHelpFilterExecCmdStr(helpWidget,
1061 pDisplayStuff->executionPolicy, commandStr,
1062 &filteredCmdStr, &invalidAlias, &execPermitted, &queryNeeded, hv_path);
1064 /* This function does an synchronous filter; i.e. the code runs a filter
1065 for policy and alias, and if policy denies exec and the command is
1066 valid, then posts a modal dialog and waits for the user to decide
1067 what to do before returning. */
1068 goodCmd = _DtHelpFilterExecCmd(helpWidget, commandStr,
1069 pDisplayStuff->executionPolicy, True,
1070 pHelpStuff, &filteredCmdStr, hv_path);
1071 execPermitted = (goodCmd == 0); /* convert an error int into a Boolean */
1073 (( pDisplayStuff->executionPolicy==DtHELP_EXECUTE_QUERY_ALL)
1074 || (pDisplayStuff->executionPolicy==DtHELP_EXECUTE_QUERY_UNALIASED))
1078 /* if permissions allow immediate execution, do so */
1079 if (execPermitted && False == queryNeeded && diff_home_dirs == False)
1081 (void) _DtHelpExecProcedure (pHelpStuff->pDisplayArea, filteredCmdStr);
1082 free(filteredCmdStr);
1083 return; /* RETURN */
1086 /* this traps bad cmds and also use of the synchronous filter call */
1087 if (NULL == filteredCmdStr) return; /* RETURN */
1089 /*** Create a modeless dialog to inform the user of the problem
1090 and possibly allow them to execute the command anyway. ***/
1092 /* create the dialog, but don't yet manage it */
1093 if ( diff_home_dirs == True)
1094 msgDlg = CreateExecErrorDlg(helpWidget,filteredCmdStr, invalidAlias,pHelpStuff,
1095 MISMATCHING_HOME_DIRS, home_dir );
1097 msgDlg = CreateExecErrorDlg(helpWidget,filteredCmdStr, invalidAlias,pHelpStuff,
1101 /*** setup ExecuteAnyway and Help buttons ***/
1103 if ( (diff_home_dirs == True)
1105 (queryNeeded && execPermitted) )
1107 /* give the right title to the buttons */
1108 labelString = XmStringCreateLocalized(((char *)_DTGETMESSAGE
1109 (HUSET, 10,"Execute Anyway")));
1110 /* give the right title to the Cancel button */
1111 labelString2 = XmStringCreateLocalized(((char *)_DTGETMESSAGE
1112 (HUSET, 11,"Don't Execute")));
1114 XtSetArg (args[n], XmNokLabelString, labelString); n++;
1115 XtSetArg (args[n], XmNcancelLabelString, labelString2); n++;
1116 XtSetValues(msgDlg,args,n);
1117 XmStringFree(labelString);
1118 XmStringFree(labelString2);
1120 btn = XmMessageBoxGetChild (msgDlg, XmDIALOG_OK_BUTTON);
1121 XtManageChild (btn); /* re-manage the button */
1123 /* add the ExecuteContextCB() client-data and callback */
1124 execContext = malloc(sizeof(ExecContext));
1127 execContext->command = filteredCmdStr;
1128 execContext->pDisplayArea = pHelpStuff->pDisplayArea;
1129 XtAddCallback(btn, XmNactivateCallback,
1130 ExecuteContextCB, (XtPointer) execContext);
1134 free(filteredCmdStr);
1136 } /* cmd wasn't an alias */
1139 free(filteredCmdStr);
1142 /* Display message dialog */
1143 XtManageChild (msgDlg);
1150 /*****************************************************************************
1151 * Function: LocateWidgetId()
1156 *****************************************************************************/
1157 static Widget LocateWidgetId(
1164 static Cursor DfltOnItemCursor = NULL;
1167 CompositeWidget comp_widget;
1179 Boolean notDone=TRUE;
1182 /* Make the target cursor */
1183 if (cursorIn != NULL)
1187 cursor = XCreateFontCursor (dpy, XC_question_arrow);
1190 _DtHelpProcessLock();
1191 if (NULL == DfltOnItemCursor)
1196 unsigned int height;
1197 unsigned int xHotspot;
1198 unsigned int yHotspot;
1203 width = onitem32_width;
1204 height = onitem32_height;
1205 bits = (char *) onitem32_bits;
1206 maskBits = (char *) onitem32_m_bits;
1207 xHotspot = onitem32_x_hot;
1208 yHotspot = onitem32_y_hot;
1210 pixmap = XCreateBitmapFromData (dpy,
1211 RootWindowOfScreen(XtScreen(shellWidget)), bits,
1215 maskPixmap = XCreateBitmapFromData (dpy,
1216 RootWindowOfScreen(XtScreen(shellWidget)), maskBits,
1219 xcolors[0].pixel = BlackPixelOfScreen(ScreenOfDisplay(dpy, screen));
1220 xcolors[1].pixel = WhitePixelOfScreen(ScreenOfDisplay(dpy, screen));
1223 DefaultColormapOfScreen(ScreenOfDisplay(dpy, screen)),
1227 DfltOnItemCursor = XCreatePixmapCursor (dpy, pixmap, maskPixmap,
1228 &(xcolors[0]), &(xcolors[1]),
1229 xHotspot, yHotspot);
1230 XFreePixmap (dpy, pixmap);
1231 XFreePixmap (dpy, maskPixmap);
1232 } /* if dflt cursor not yet created */
1233 cursor = DfltOnItemCursor;
1234 _DtHelpProcessUnlock();
1235 } /* if to use the standard cursor */
1239 /* Grab the pointer using target cursor, letting it roam all over */
1240 status = XtGrabPointer (shellWidget, TRUE,
1241 ButtonPressMask|ButtonReleaseMask, GrabModeAsync,
1242 GrabModeAsync, None, cursor, CurrentTime);
1243 if (status != GrabSuccess)
1245 XmeWarning(shellWidget,(char *)_DTGETMESSAGE(HUSET, 3,
1246 "Internal Error: Could not grab the mouse\nDtHelpReturnSelectedWidget aborted.\n"));
1247 *statusRet = DtHELP_SELECT_ERROR;
1253 /* Grab the Keyboard so we can catch the ESC button press */
1254 status = XtGrabKeyboard(shellWidget, False,
1255 GrabModeAsync, GrabModeAsync, CurrentTime);
1256 if (status != GrabSuccess)
1259 XtUngrabPointer (shellWidget, CurrentTime);
1260 XmeWarning(shellWidget,(char *)_DTGETMESSAGE(HUSET, 4,
1261 "Internal Error: Could not grab the keyboard\nDtHelpReturnSelectedWidget() aborted.\n"));
1262 *statusRet = DtHELP_SELECT_ERROR;
1266 /* We are ok so let the user select a window... */
1269 XtAppContext app = XtWidgetToApplicationContext(shellWidget);
1270 /* allow one more event */
1272 XtAppNextEvent(app, &event);
1276 while (!(mask = XtAppPending(app)))
1277 ; /* Busy waiting - so we don't lose our Lock! */
1279 if (!(mask & XtIMXEvent)) /* Not a XEvent, it's an alternate input/timer event */
1280 XtAppProcessEvent(app, mask); /* No blocking, since an event is ready */
1281 else /* We have an XEvent */
1283 /* Get the XEvent - we know it's there! Note that XtAppNextEvent
1284 would also process timers/alternate inputs.
1286 XtAppNextEvent(app, &event);
1287 #endif /* XTHREADS */
1288 widget = XtWindowToWidget(dpy, event.xany.window);
1290 switch (event.type) {
1297 /* Look for ESC key press and stop if we get one */
1298 if (event.xkey.state & ShiftMask)
1303 keySym = XLookupKeysym((XKeyEvent *)&event, offset);
1304 if (keySym == XK_Escape)
1306 XtUngrabKeyboard (shellWidget, CurrentTime);
1307 XtUngrabPointer (shellWidget, CurrentTime);
1308 *statusRet = DtHELP_SELECT_ABORT;
1312 XtDispatchEvent(&event);
1319 XtUngrabKeyboard (shellWidget, CurrentTime); /* Done with keyboard */
1320 XtUngrabPointer (shellWidget, CurrentTime); /* Done with pointer */
1322 /* If its null then the user selected some area outside our window(s) */
1323 if (widget == shellWidget)
1325 *statusRet = DtHELP_SELECT_INVALID;
1328 if (!XtIsComposite (widget))
1330 *statusRet = DtHELP_SELECT_VALID;
1334 /* Get the x and y and parent relative to the current window */
1335 parent = RootWindow(dpy, screen);
1336 target_win = XtWindow(widget);
1337 x = event.xbutton.x_root;
1338 y = event.xbutton.y_root;
1340 XTranslateCoordinates(dpy, parent, target_win, x, y,
1341 &new_x, &new_y, &sub);
1345 comp_widget = (CompositeWidget)widget;
1347 /* look for gadgets at this point */
1348 for (i = 0; i < comp_widget->composite.num_children; i++) {
1349 child = comp_widget->composite.children[i];
1350 /* put in check for only managed widgets here */
1351 if(XtIsManaged(child))
1352 if (PT_IN_CHILD (x, y, child))
1354 *statusRet = DtHELP_SELECT_VALID;
1359 *statusRet = DtHELP_SELECT_VALID;
1366 /*****************************************************************************
1367 * Function: Boolean RememberDir(String path)
1369 * Parameters: path Specifies the path to check.
1371 * Return Value: Boolean if the path name is good.
1373 * Description: Use the directory caching mechanism to improve performance
1374 * by remembering the directories that have already been
1377 *****************************************************************************/
1379 RememberDir(String path)
1385 if (path == NULL || *path == '\0')
1388 if (_DtHelpCeStrrchr(path, "/", MB_CUR_MAX, &ptr) == 0 && ptr != path)
1391 result = _DtHelpCeCheckAndCacheDir(path);
1394 if (result == 0 && access(path, R_OK) == 0 &&
1395 stat(path, &buf) == 0 && S_ISREG(buf.st_mode))
1401 /*****************************************************************************
1402 * Function: Boolean _DtHelpResolvePathname(
1407 * Return Value: Boolean.
1410 * Description: _DtHelpResolvePathname attempts to validate and expand a path
1411 * to a Cache Creek help access file.
1413 *****************************************************************************/
1414 Boolean _DtHelpResolvePathname(
1416 char * * io_fileName,
1417 _DtHelpVolumeHdl * io_volumeHandle,
1418 char * sysVolumeSearchPath,
1419 char * userVolumeSearchPath)
1421 String newPath = NULL;
1423 /* try to locate file and its entry, if present */
1424 newPath = _DtHelpFileLocate(DtHelpVOLUME_TYPE, *io_fileName,
1425 _DtHelpFileSuffixList,False,R_OK);
1427 /* If we found a valid file let's do some set up here */
1429 if (newPath != NULL) /* We have a valid volume file so open it */
1431 /* Close the current one if we have one open */
1432 if (*io_volumeHandle != NULL)
1433 _DtHelpCloseVolume(*io_volumeHandle);
1435 /* Open the help volume file and save the handle id */
1436 if (_DtHelpOpenVolume(newPath,io_volumeHandle) >= 0)
1438 /* Copy the expanded file location path */
1439 XtFree(*io_fileName);
1440 *io_fileName = newPath;
1446 /* ERROR; leave io_fileName untouched on error
1447 * We used to set it to null here now we just return what came in
1449 /* later NOTE: this seems strange, since we have closed the
1450 old volume, invalidating io_fileName */
1452 XmeWarning(widget,(char*)UtilMessage2);
1456 else /* We have a non-valid path */
1458 /* ERROR; leave io_fileName untouched on error
1459 * We used to set it to null here now we just return what came in
1462 XmeWarning(widget,(char*)UtilMessage0);
1472 /*****************************************************************************
1473 * Function: Boolean _DtHelpExpandHelpVolume(DtHelpDialogWidget nw);
1476 * Parameters: nw Specifies the current help dialog widget.
1478 * Return Value: Boolean.
1481 * Description: _DtHelpExpandHelpVolume looks for a $LANG variable in the
1482 * helpAccesFile string and if found, replaces it with the
1483 * current lang variable.
1485 *****************************************************************************/
1486 Boolean _DtHelpExpandHelpVolume(
1488 _DtHelpDisplayWidgetStuff * display,
1489 _DtHelpCommonHelpStuff * help,
1490 _DtHelpPrintStuff * print)
1492 Boolean validTopic = FALSE;
1493 Boolean validPath = FALSE;
1496 /* Free the old, and Copy the new volumeHandle to printVolume varialbe */
1497 if (print->printVolume != NULL)
1498 XtFree(print->printVolume);
1500 print->printVolume = XtNewString(display->helpVolume);
1502 validPath = _DtHelpResolvePathname((Widget)w,
1503 &print->printVolume,
1504 &display->volumeHandle,
1505 help->sysVolumeSearchPath,
1506 help->userVolumeSearchPath);
1509 /* Check to see that we resolved our path correctly */
1511 return (FALSE); /* RETURN */
1515 /* The following routine will malloc memory for the topLevelId
1516 * variable, so we must free our current version first.
1518 XtFree(help->topLevelId);
1520 /* Assign our top level topic for this help access file */
1521 validTopic = _DtHelpCeGetTopTopicId(display->volumeHandle, &topLevelId);
1525 /* Bad top level topic */
1526 help->topLevelId = NULL;
1531 /* recall that the topLevelId/File vars are malloc'd */
1532 help->topLevelId = topLevelId;
1539 /*****************************************************************************
1540 * Function: char *_DtHelpParseIdString(char * specification);
1543 * Parameters: specification Specifies an author defined help topic.
1545 * Return Value: Void.
1547 * Description: This function copies the locationId portion of the
1548 * specification and returns it to the calling routine.
1550 *****************************************************************************/
1551 char *_DtHelpParseIdString(
1552 char *specification)
1555 char *pAccessFile = NULL;
1557 char *returnStr=NULL;
1560 tmpSpec = XtNewString(specification);
1563 /* First look for a blank in the specification. This will signify that
1564 * we have a HelpAccessFile as part of the specification.
1567 /* The first call will return true, with the first string */
1568 pAccessFile = DtStrtok_r(tmpSpec, " ", &strtok_ptr);
1569 returnStr = XtNewString(pAccessFile);
1571 /* The second call will return true only if we have another string */
1572 pAccessFile = DtStrtok_r(NULL, " ", &strtok_ptr);
1574 if (pAccessFile != NULL)
1576 /* We have a helpAccessFile in our specification */
1580 returnStr = XtNewString(pAccessFile);
1587 /* We don't have a helpAccessFile as part of the specificaiton
1588 * so we just return our locationId.
1598 /*****************************************************************************
1599 * Function: char *_DtHelpParseAccessFile(char * specification);
1602 * Parameters: specification Specifies an author defined help topic.
1604 * Return Value: Void.
1606 * Description: This function copies the helpAccessFile portion of the
1607 * specification and returns it to the calling routine.
1609 *****************************************************************************/
1610 char *_DtHelpParseAccessFile(
1611 char *specification)
1613 char *pAccessFile = NULL;
1615 char *returnStr=NULL;
1618 tmpSpec = XtNewString(specification);
1621 /* First look for a blank in the specification. This will signify that
1622 * we have a HelpAccessFile as part of the specification.
1625 /* The first call will return true, with the first string */
1626 pAccessFile = DtStrtok_r(tmpSpec, " ", &strtok_ptr);
1627 returnStr = XtNewString(pAccessFile);
1629 /* The second call will return true only if we have another string */
1630 pAccessFile = DtStrtok_r(NULL, " ", &strtok_ptr);
1632 if (pAccessFile != NULL)
1634 /* We have a helpAccessFile in our specification */
1637 /* If we have an accessFile, but it's not a full path, then we
1638 * must get the full path from the reg file.
1646 /* We don't have a helpAccessFile as part of the specificaiton
1663 /*****************************************************************************
1664 * Function: DtHelpReturnSelectedWidgetId
1666 * Parameters: parent Specifies the widget ID to use as the bases of
1667 * interaction, usually a top level shell.
1669 * cursor Specifies the cursor to be used for the pointer
1670 * during the interaction. If a value of NULL is
1671 * used this function will use a default cursor
1674 * widget This is the return value (e.g. the selected
1675 * widget). A value of NULL is returned on error.
1677 * Return Value: Status: (-1,0 or 1).
1679 * Purpose: Allows developers to get the widget ID for any widget in their UI
1680 * that the user has selected via the pointer. This function will
1681 * cause the cursor to change and allow a user to select an item in
1684 *****************************************************************************/
1685 int DtHelpReturnSelectedWidgetId(
1694 Widget selectedItem;
1695 int status=DtHELP_SELECT_ERROR;
1698 _DtHelpWidgetToAppContext(parent);
1700 _DtHelpAppLock(app);
1701 /* Setup some needed variables */
1702 dpy = XtDisplay(parent);
1703 retScr = XtScreen(parent);
1705 screen = XScreenNumberOfScreen(retScr);
1707 /* refresh the display */
1708 XmUpdateDisplay(parent);
1710 /* Change the curser to let the user select the desired widget */
1711 selectedItem = LocateWidgetId(dpy, screen, &status, parent, cursor);
1715 case DtHELP_SELECT_VALID:
1716 *widget = selectedItem;
1717 result = DtHELP_SELECT_VALID;
1720 case DtHELP_SELECT_ABORT:
1722 result = DtHELP_SELECT_ABORT;
1725 case DtHELP_SELECT_ERROR:
1727 result = DtHELP_SELECT_ERROR;
1730 case DtHELP_SELECT_INVALID:
1733 result = DtHELP_SELECT_INVALID;
1737 _DtHelpAppUnlock(app);
1748 /*****************************************************************************
1749 * Function: void _DtHelpTopicListAddToHead(
1753 * DtTopicListStruct *pHead,
1754 * DtTopicListStruct *pTale,
1760 * Return Value: Void.
1762 * Purpose: Adds an element to the top of the given topicList.
1764 *****************************************************************************/
1765 void _DtHelpTopicListAddToHead(
1767 XmString topicTitle,
1771 DtTopicListStruct **pHead,
1772 DtTopicListStruct **pTale,
1776 DtTopicListStruct *pTemp=NULL;
1778 /* add the new topic to the top */
1779 pTemp = (DtTopicListStruct *) XtMalloc((sizeof(DtTopicListStruct)));
1781 pTemp->pNext = (*pHead);
1782 pTemp->pPrevious = NULL;
1784 /* Assign the passed in values to our first element */
1785 pTemp->locationId = XtNewString(locationId);
1786 pTemp->topicTitleLbl = NULL;
1787 if (topicTitle != NULL)
1788 pTemp->topicTitleLbl= XmStringCopy(topicTitle);
1789 pTemp->topicType = topicType;
1790 pTemp->helpVolume = XtNewString(accessPath);
1791 pTemp->scrollPosition = scrollPosition;
1793 /* Add locationId as first element if pHead = NULL */
1796 /* Assign our tale pointer */
1797 (*pTale) = (*pHead);
1799 /* Make sure or totalNodes counter is correct, e.g. force it to 1 */
1803 { /* We have a list so add the new topic to the top */
1805 (*pHead)->pPrevious = pTemp;
1807 /* Assign our tale pointer only the first time in this block */
1808 if (*totalNodes == 1)
1809 (*pTale) = (*pHead);
1811 /* Re-Assign our head pointer to point to the new head of the list */
1813 /* Bump our totalNode count */
1814 *totalNodes = *totalNodes +1;
1817 /* set the head to the current entry */
1820 /* If we have reached our maxNodes remove a node from the end of our list */
1821 if (*totalNodes > maxNodes)
1824 (*pTale) = (*pTale)->pPrevious;
1825 (*pTale)->pNext = NULL;
1826 pTemp->pPrevious = NULL;
1828 /* Free the id String and AccessPath elements */
1829 XtFree(pTemp->locationId);
1830 XtFree(pTemp->helpVolume);
1831 if (pTemp->topicTitleLbl != NULL)
1832 XmStringFree(pTemp->topicTitleLbl);
1834 /* Now, free the whole node */
1835 XtFree((char*)pTemp);
1837 /* Bump back our total node counter */
1838 *totalNodes = *totalNodes -1;
1846 /*****************************************************************************
1847 * Function: void _DtHelpTopicListDeleteHead(
1848 * DtTopicListStruct *pHead,
1849 * DtTopicListStruct *pTale,
1855 * Return Value: Void.
1857 * Purpose: Delets an element from the top of the given topicList.
1859 *****************************************************************************/
1860 void _DtHelpTopicListDeleteHead(
1861 DtTopicListStruct **pHead,
1862 DtTopicListStruct **pTale,
1865 DtTopicListStruct *pTemp=NULL;
1867 /* Delete the top node in our topic list */
1871 if(pTemp != (*pTale)) /* (e.g. more than one node in list) */
1873 (*pHead) = pTemp->pNext;
1874 pTemp->pNext = NULL;
1875 (*pHead)->pPrevious = NULL;
1877 /* Free the id String and accessPath elements */
1878 XtFree(pTemp->locationId);
1879 XtFree(pTemp->helpVolume);
1881 /* Now, free the whole node */
1882 XtFree((char*)pTemp);
1884 /* Bump back our total node counter */
1885 *totalNodes = *totalNodes -1;
1895 /*****************************************************************************
1896 * Function: void _DtHelpMapCB()
1900 * Parameters: client_data is the widget in reference to
1901 * which widget w is placed
1903 * Return Value: Void.
1905 * Purpose: Determins where a new child dialog should be mapped in
1906 * relation to its parent.
1908 * Algorithm: 1. attempt left or right placement with no overlap
1909 * 2. if fails, attempt up or down placement with no overlap
1910 * 3. if fails, determines location with least
1911 * amount of overlap, and places there.
1913 *****************************************************************************/
1914 XtCallbackProc _DtHelpMapCB(
1916 XtPointer client_data,
1917 XtPointer call_data )
1921 Position centeredY, bestX, bestY, pX, pY;
1922 Dimension pHeight, myHeight, pWidth, myWidth;
1923 Dimension maxX, maxY;
1924 int rhsX, lhsX, topY, botY; /* needs to be int, not Dimension */
1929 parent = (Widget)client_data;
1930 display = XtDisplay(w);
1931 screen = XtScreen(w);
1932 screenNumber = XScreenNumberOfScreen(screen);
1938 pHeight = XtHeight(parent);
1939 pWidth = XtWidth(parent);
1940 myHeight = XtHeight(w);
1941 myWidth = XtWidth(w);
1942 maxX = XDisplayWidth(display,screenNumber);
1943 maxY = XDisplayHeight(display,screenNumber);
1946 * 1. attempt left or right placement with no overlap
1947 * 2. if fails, attempt up or down placement with no overlap
1948 * 3. if fails, places on the right in the middle
1951 /* first try left right placement */
1952 bestY = pY + pHeight/2 - myHeight/2;
1955 lhsX = pX - myWidth - 8; /* 8: account for border */
1956 if ( ((int)(rhsX + myWidth)) < ((int) maxX) ) bestX = rhsX;
1957 else if ( lhsX > 0 ) bestX = lhsX;
1960 /* then try up down placement */
1961 bestX = pX + pWidth/2 - myWidth/2;
1962 botY = pY + pHeight;
1963 topY = pY - myHeight - 44; /* 44: account for menu border */
1964 if ( ((int)(botY + myWidth)) < ((int) maxY) ) bestY = botY;
1965 else if ( topY > 0 ) bestY = topY;
1968 /* otherwise, center vertically and on the right */
1969 bestX = maxX - myWidth;
1974 XtSetArg(args[0], XmNx, bestX);
1975 XtSetArg(args[1], XmNy, bestY);
1976 XtSetValues(w, args, 2);
1978 return((XtCallbackProc) NULL);
1987 /*****************************************************************************
1988 * Function: void _DtHelpMapCenteredCB(
1994 * Return Value: Void.
1996 * Purpose: Determins where the center of our help dialog is and sets
1997 * where new child dialog should be mapped such that its centered.
1999 *****************************************************************************/
2000 XtCallbackProc _DtHelpMapCenteredCB(
2002 XtPointer client_data,
2003 XtPointer call_data )
2007 Position newX, newY, pY, pX;
2008 Dimension pHeight, myHeight, pWidth, myWidth;
2010 parent = (Widget)client_data;
2014 pHeight = XtHeight(parent);
2015 pWidth = XtWidth(parent);
2016 myHeight = XtHeight(w);
2017 myWidth = XtWidth(w);
2020 newY = ((Position)(pHeight - myHeight) / 2) + pY;
2021 newX = ((Position)(pWidth - myWidth) / 2) + pX;
2023 XtSetArg(args[0], XmNx, newX);
2024 XtSetArg(args[1], XmNy, newY);
2025 XtSetValues(w, args, 2);
2027 return((XtCallbackProc) NULL);
2034 /*****************************************************************************
2035 * Function: void _DtHelpDisplayDefinitionBox(
2037 * Widget definitionBox,
2039 * char * locationId);
2045 * Purpose: This routine will create and post the definition box.
2046 * (e.g. the Quick Help Dialog widget)
2048 ****************************************************************************/
2049 void _DtHelpDisplayDefinitionBox(
2051 Widget **definitionBox,
2058 Widget printWidget, helpWidget, backWidget;
2059 XmString closeString;
2062 /* get the title from the main help dialog and use it here for */
2064 XtSetArg (args[n], XmNtitle, &(title)); ++n;
2065 XtGetValues (XtParent(parent), args, n);
2068 if (*definitionBox == NULL)
2071 /* Create the QuickHelpDialog widget to use as the definition box */
2072 closeString = XmStringCreateLocalized(((char *)_DTGETMESSAGE
2073 (HUSET, 2,"Close")));
2075 XtSetArg (args[n], DtNhelpVolume, path); n++;
2076 XtSetArg (args[n], DtNhelpType, DtHELP_TYPE_TOPIC); n++;
2077 XtSetArg (args[n], DtNlocationId, locationId); n++;
2078 XtSetArg (args[n], DtNcloseLabelString, closeString); n++;
2079 XtSetArg (args[n], XmNtitle, title); n++;
2081 (Widget *)DtCreateHelpQuickDialog(parent, "definitionBox",
2083 XmStringFree(closeString);
2085 /* Catch the close callback so we can destroy the widget */
2086 XtAddCallback((Widget)*definitionBox, DtNcloseCallback,
2087 CloseDefBoxCB, (XtPointer) NULL);
2090 /* We do not want a print button for now so we unmap it */
2091 printWidget = DtHelpQuickDialogGetChild ((Widget)*definitionBox,
2092 DtHELP_QUICK_PRINT_BUTTON);
2093 XtUnmanageChild (printWidget);
2095 /* We do not want a help button for now so we unmap it */
2096 helpWidget = DtHelpQuickDialogGetChild ((Widget)*definitionBox,
2097 DtHELP_QUICK_HELP_BUTTON);
2098 XtUnmanageChild (helpWidget);
2101 /* We do not want a BACK button for now so we unmap it */
2102 backWidget = DtHelpQuickDialogGetChild ((Widget)*definitionBox,
2103 DtHELP_QUICK_BACK_BUTTON);
2104 XtUnmanageChild (backWidget);
2108 /* Adjust the decorations for the dialog shell of the dialog */
2110 XtSetArg(args[n], XmNmwmFunctions, MWM_FUNC_RESIZE | MWM_FUNC_MOVE); n++;
2111 XtSetArg (args[n], XmNmwmDecorations,
2112 MWM_DECOR_BORDER | MWM_DECOR_TITLE | MWM_DECOR_RESIZEH); n++;
2113 XtSetValues (XtParent(*definitionBox), args, n);
2115 /* Add the popup position callback to our history dialog */
2116 XtAddCallback (XtParent(*definitionBox), XmNpopupCallback,
2117 (XtCallbackProc)_DtHelpMapCenteredCB, (XtPointer)XtParent(parent));
2124 /* We already have one so lets use it. */
2126 /* Set the proper title */
2128 XtSetArg (args[n], XmNtitle, title); ++n;
2129 XtSetValues (XtParent(*definitionBox), args, n);
2131 /* Set the proper contents. */
2133 XtSetArg (args[n], DtNhelpType, DtHELP_TYPE_TOPIC); n++;
2134 XtSetArg (args[n], DtNhelpVolume, path); n++;
2135 XtSetArg (args[n], DtNlocationId, locationId); n++;
2136 XtSetValues ((Widget)*definitionBox, args, n);
2141 /* Display the dialog */
2142 XtManageChild((Widget)*definitionBox);
2143 XtMapWidget(XtParent((Widget)*definitionBox));
2148 /*****************************************************************************
2149 * Function: static void CloseDefBoxCB(
2151 * XtPointer client_data,
2152 * XtPointer call_data);
2158 * Purpose: This routine closes and destroys the Definition Box
2159 * Dialog Widget that we create.
2161 ****************************************************************************/
2162 static void CloseDefBoxCB(
2164 XtPointer client_data,
2165 XtPointer call_data )
2177 /*****************************************************************************
2178 * Function: void _DtHelpDisplayFormatError()
2184 * Purpose: This routine generate and display the proper errror
2185 * message to the display area as well as send the proper
2186 * error to XmWarning() function.
2188 ****************************************************************************/
2189 void _DtHelpDisplayFormatError(
2190 XtPointer displayArea,
2195 XtPointer topicHandle;
2197 /* Set the string to the current help dialog */
2198 (void) _DtHelpFormatAsciiStringDynamic(displayArea, userError, &topicHandle);
2200 /* We ignor the status return here, because if we error out here we are
2201 * in big trouble because this is an error routine
2204 _DtHelpDisplayAreaSetList (displayArea, topicHandle, FALSE, -1);
2206 if (systemError != NULL)
2207 XmeWarning((Widget)widget, systemError);
2213 /*****************************************************************************
2214 * Function: void _DtHelpCommonHelpInit()
2220 * Purpose: This routine inits common help stuff
2222 ****************************************************************************/
2223 void _DtHelpCommonHelpInit(
2224 _DtHelpCommonHelpStuff * help)
2226 help->topLevelId = NULL;
2227 help->currentHelpFile = NULL;
2229 /* for help on help */
2230 if ( help->helpOnHelpVolume != _DtHelpDefaultHelp4HelpVolume)
2231 help->helpOnHelpVolume = XtNewString(help->helpOnHelpVolume);
2232 if ( NULL == help->helpOnHelpVolume )
2233 help->helpOnHelpVolume = (char *)_DtHelpDefaultHelp4HelpVolume;
2234 help->pHelpListHead = NULL; /* Help List Pointer */
2235 help->onHelpDialog = NULL; /* help on help dialog */
2236 help->pDisplayArea = NULL; /* Display widget handle */
2238 /* get the search paths used by the widget */
2239 help->userVolumeSearchPath = _DtHelpGetUserSearchPath();
2240 help->sysVolumeSearchPath = _DtHelpGetSystemSearchPath();
2245 /*****************************************************************************
2246 * Function: void _DtHelpCommonHelpClean()
2252 * Purpose: This routine cleans up common help stuff
2254 ****************************************************************************/
2255 void _DtHelpCommonHelpClean(
2256 _DtHelpCommonHelpStuff * help,
2259 free(help->topLevelId);
2260 XtFree(help->currentHelpFile);
2262 help->topLevelId = NULL;
2263 help->currentHelpFile = NULL;
2267 if (help->helpOnHelpVolume != _DtHelpDefaultHelp4HelpVolume)
2268 XtFree(help->helpOnHelpVolume);
2270 /* Free all the info we saved for our help callbacks */
2271 _DtHelpListFree(&help->pHelpListHead);
2273 XtFree(help->userVolumeSearchPath);
2274 XtFree(help->sysVolumeSearchPath);
2276 memset(help,0,sizeof(_DtHelpCommonHelpStuff));
2280 /* Set our display area to a null starting vlaues */
2281 _DtHelpDisplayAreaClean(help->pDisplayArea);
2287 /*****************************************************************************
2288 * Function: void _DtHelpSetDlgButtonsWidth
2294 * Purpose: This routine cleans up common help stuff
2296 ****************************************************************************/
2297 void _DtHelpSetButtonPositions(
2300 Dimension minFormWidth,
2301 Dimension btnMargins,
2302 Dimension minBetweenBtnSpace)
2303 { /* position buttons */
2305 /* This code adds up the sizes of the buttons to go into
2306 the bottom row and calculates the form position percentages.
2307 All buttons are the same size, and are able to hold all
2308 the strings that may be dynamically placed in them.
2309 All buttons are 5% apart. */
2310 /* This code is specifically written to handle 3 buttons
2311 and assumes that the first 3 strings are to the ActionBtn */
2312 Dimension minWidthWithSpace = 0;
2313 Dimension borderWidth = 0;
2314 Dimension sumWidth = 0;
2315 Dimension leftPos = 0;
2316 Dimension rightPos = 0;
2317 Dimension spaceWidth = 0;
2319 Dimension maxBtnWidth = 0;
2321 XmFontList fontList = NULL;
2326 if (numBtns <= 0 || NULL == btnList[0]) return;
2328 /* get the fontList for the button */
2329 XtSetArg (args[0], XmNborderWidth, &borderWidth);
2330 XtSetArg (args[1], XmNfontList, &fontList);
2331 XtGetValues (btnList[0], args, 2);
2332 /* assumption: the fontList that is returned is not owned by me; don't free */
2334 /* cycle through all buttons */
2335 for (i=0; i<numBtns && NULL!=btnList[i]; i++)
2337 XmString labelString;
2339 /* get the label from the button */
2340 XtSetArg (args[0], XmNlabelString, &labelString);
2341 XtGetValues (btnList[i], args, 1);
2343 btnWidth = XmStringWidth(fontList,labelString) + borderWidth + btnMargins;
2344 if (btnWidth > maxBtnWidth) maxBtnWidth = btnWidth;
2346 XmStringFree(labelString);
2347 } /* for calcing widths */
2348 numBtns = i; /* number of valid buttons */
2350 /* calc the space */
2351 sumWidth = maxBtnWidth * numBtns;
2352 minWidthWithSpace = sumWidth + minBetweenBtnSpace * (numBtns * 2);
2353 if (minWidthWithSpace > minWidthWithSpace) minFormWidth = minWidthWithSpace;
2354 spaceWidth = ((int)(minFormWidth - sumWidth) / (numBtns * 2));
2356 /* scale pixels to percent */
2357 scale = 100.0 / (float) minFormWidth;
2359 /* set the positions of each button */
2360 leftPos = spaceWidth;
2361 for ( i=0; i<numBtns; i++ )
2363 rightPos = leftPos + maxBtnWidth;
2366 XtSetArg (args[n], XmNleftAttachment, XmATTACH_POSITION); n++;
2367 XtSetArg (args[n], XmNleftPosition, (Dimension) (((float) leftPos)*scale)); n++;
2368 XtSetArg (args[n], XmNrightAttachment, XmATTACH_POSITION); n++;
2369 XtSetArg (args[n], XmNrightPosition,(Dimension) (((float) rightPos)*scale)); n++;
2370 XtSetValues (btnList[i], args, n);
2372 leftPos = rightPos + spaceWidth + spaceWidth;
2373 } /* setup the positions for all buttons */
2374 } /* _DtHelpSetDlgButtonsWidth */
2378 /*****************************************************************************
2379 * Function: _DtHelpXmFontListGetPropertyMax
2382 * fontList: an XmFontList
2383 * atom: an XA_xxx value (see Vol 1, chpt 6.2.9)
2384 * ret_propertyValue: ptr to long value that will hold the max value
2387 * True: got at least one value
2388 * False: unable to get any value; ret_propertyValue unchanged
2391 * This function returns the max value of XGetFontProperty calls
2392 * for each font in the XmFontList
2393 * If there is an error, ret_propertyValue is left unchanged.
2395 ****************************************************************************/
2397 _DtHelpXmFontListGetPropertyMax(
2398 XmFontList fontList,
2400 unsigned long *ret_propertyValue)
2402 Boolean gotValue = False;
2403 XmFontContext context;
2404 XmFontListEntry entry;
2407 if (NULL == fontList) return False; /* RETURN on error */
2409 /* walk through the fontList entries and add them in */
2410 XmFontListInitFontContext(&context,fontList);
2411 for ( entry = XmFontListNextEntry(context);
2413 entry = XmFontListNextEntry(context) )
2415 unsigned long value;
2418 fontData = XmFontListEntryGetFont(entry,&type);
2419 if (XmFONT_IS_FONT == type)
2421 XFontStruct * fontStruct;
2423 /* cast according to type */
2424 fontStruct = (XFontStruct *) fontData;
2426 if(XGetFontProperty(fontStruct, atom, &value) == TRUE)
2428 if(gotValue == False) /* haven't gotten any prop value yet */
2430 *ret_propertyValue = value;
2433 else /* have a good prop value already...get the max one */
2435 if(value > *ret_propertyValue)
2436 *ret_propertyValue = value;
2438 } /* if the getproperty call was good */
2440 else /* XmFONT_IS_FONTSET */
2443 XFontStruct **font_list;
2448 /* cast according to type */
2449 fontSet = (XFontSet) fontData;
2451 numfont=XFontsOfFontSet(fontSet,&font_list,&name_list);
2452 for(i = 0; i < numfont; i++)
2454 if(XGetFontProperty(font_list[i], atom, &value) == TRUE)
2456 if(gotValue == False) /* haven't gotten any prop value yet */
2458 *ret_propertyValue = value;
2461 else /* have a good prop value already...get the max one */
2463 if(value > *ret_propertyValue)
2464 *ret_propertyValue = value;
2466 } /* if the getproperty call was good */
2467 } /* for all fonts in the font set */
2468 } /* this entry uses a font set */
2469 } /* for all font entries in the font list */
2470 XmFontListFreeFontContext(context);