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 libraries 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 XtFree(filteredCmdStr);
887 return -1; /* RETURN error */
890 /* create the dialog, but don't yet manage it */
891 msgDlg = CreateExecErrorDlg(helpWidget,filteredCmdStr,
892 invalidAlias,pHelpStuff, NO_CONDITION, "");
894 /* if a bad alias or no exec permitted,
895 don't need to wait for a response; dlg has close & Help */
896 if (False == execPermitted || False == queryNeeded)
898 XtManageChild(msgDlg); /* manage modeless dialog */
899 *ret_filteredCmdStr = NULL; /* don't execute */
900 XtFree(filteredCmdStr);
901 return -1; /* RETURN error */
904 /* if got this far, query is needed;make the dialog include
905 Execute Anyway and Don't Execute buttons */
907 /* give the right title to the buttons */
908 labelString = XmStringCreateLocalized(((char *)_DTGETMESSAGE
909 (HUSET, 10,"Execute Anyway")));
910 /* give the right title to the Cancel button */
911 labelString2 = XmStringCreateLocalized(((char *)_DTGETMESSAGE
912 (HUSET, 11,"Don't Execute")));
914 XtSetArg (args[n], XmNokLabelString, labelString); n++;
915 XtSetArg (args[n], XmNcancelLabelString, labelString2); n++;
916 XtSetArg (args[n], XmNdialogStyle, XmDIALOG_PRIMARY_APPLICATION_MODAL); n++;
917 XtSetValues(msgDlg,args,n);
918 XmStringFree(labelString);
919 XmStringFree(labelString2);
921 /* We put an activate callback on the DontExecute and ExecuteAnyway buttons
922 and wait until a button is pressed. */
923 noexecBtn = XmMessageBoxGetChild (msgDlg, XmDIALOG_CANCEL_BUTTON);
924 XtAddCallback(noexecBtn, XmNactivateCallback,
925 IdentifyActivatedBtnCB, (XtPointer) &msgDlgCBStruct);
927 execBtn = XmMessageBoxGetChild (msgDlg, XmDIALOG_OK_BUTTON);
928 XtManageChild (execBtn); /* re-manage the button */
929 XtAddCallback(execBtn, XmNactivateCallback,
930 IdentifyActivatedBtnCB, (XtPointer) &msgDlgCBStruct);
932 /* fill out the CB information structure used by IdentifyActivatedBtnCB */
933 msgDlgCBStruct.msgDlg = msgDlg;
934 msgDlgCBStruct.okBtn = execBtn;
935 msgDlgCBStruct.cancelBtn = noexecBtn;
936 msgDlgCBStruct.activatedBtnId = -1;
938 /* Display message dialog */
939 XtManageChild (msgDlg);
942 * turn on the modal dialog indicator
944 _DtHelpTurnOnNoEnter(helpWidget);
946 /* wait until 'msgDlgCBStruct.activatedBtnId' has a value >= 0 */
947 /* this occurs when the user responds to the msg dialog */
948 _DtHelpCeWaitAndProcessEvents(msgDlg,
949 WaitForBtnActivatedCB, &msgDlgCBStruct.activatedBtnId);
952 * turn off the modal dialog indicator
954 _DtHelpTurnOffNoEnter(helpWidget);
956 /* no need to destroy msgDlg; it has a closeCallback to do that */
958 /* act based on which button was activated */
959 if (msgDlgCBStruct.activatedBtnId == XmDIALOG_OK_BUTTON)
961 *ret_filteredCmdStr = filteredCmdStr; /* do execute command */
962 return 0; /* RETURN ok */
966 *ret_filteredCmdStr = NULL; /* don't execute */
967 XtFree(filteredCmdStr);
968 return -1; /* RETURN error */
972 /*****************************************************************************
973 * Function: _DtHelpExecFilteredCmd
976 * helpWidget: help widget requesting to exec the command
977 * command: command string to execute
978 * modal: is the execution modal (sync) or modeless (async)
979 * helpLocationId: helpOnHelp file location for Help btn in error dialog
980 * pDisplayStuff: ptr to the DisplayWidget stuff of the help widget
981 * pHelpStuff: ptr to the CommonHelp stuff of the help widget
984 * This code is written such that we don't need nor want to know
985 * whether it is a general or quick help widget.
988 * command string must be writable; it is written, but left
989 * unchanged whent the function exits.
991 * At the moment, the helpLocationId is ignored, and the
992 * help location is hardwired to DtHELP_ExecutionPolicy_STR
993 * in CreateExecErrorDialog().
995 *****************************************************************************/
996 void _DtHelpExecFilteredCmd(
999 char * helpLocationId,
1000 _DtHelpDisplayWidgetStuff * pDisplayStuff,
1001 _DtHelpCommonHelpStuff * pHelpStuff)
1004 Boolean invalidAlias;
1005 Boolean execPermitted;
1006 Boolean queryNeeded;
1007 char * filteredCmdStr = NULL;
1008 ExecContext * execContext;
1009 XmString labelString;
1010 XmString labelString2;
1019 Boolean diff_home_dirs=False; /* True ==> $HOME is different from */
1020 /* root user's $HOME directory */
1022 getpw{uid,nam}_r routines fail on IBM platform when search password info
1023 via NIS (yellow pages). However, in the case of root, we'll assume that
1024 the password info is in /etc/passwd. If this is not the case, the
1025 following code can fail on IBM platform when XTHREADS and XUSE_MTSAFE_API
1029 _Xgetpwparams pwd_buf;
1031 struct passwd * pwd_ret;
1033 /** -------------------------------------------------------------- *
1034 ** If we're running as the root user
1035 ** o check if the value of the HOME env var matches
1036 ** root's home directory (defined by /etc/passwd).
1037 ** o If they do not match, then present a dialog
1038 ** alerting the user of this, along with the command to
1040 ** -------------------------------------------------------------- */
1042 if ( (user=getuid()) == ROOT_USER)
1044 home_dir = getenv ("HOME");
1046 if (home_dir != NULL && strlen(home_dir) >= (size_t) 1)
1048 if (((pwd_ret = _XGetpwuid(user, pwd_buf)) != NULL)
1049 && (strcmp(home_dir, pwd_ret->pw_dir)))
1051 diff_home_dirs = True;
1056 hv_path = _DtHelpFileLocate(DtHelpVOLUME_TYPE, pDisplayStuff->helpVolume,
1057 _DtHelpFileSuffixList, False, R_OK);
1059 /* The desired and intended behaviour is to use _DtHelpFilterExecCmdStr(), but
1060 the other code is left here, should a change be wished. */
1062 /* This function runs a filter for policy and alias but posts no dialog */
1063 goodCmd=_DtHelpFilterExecCmdStr(helpWidget,
1064 pDisplayStuff->executionPolicy, commandStr,
1065 &filteredCmdStr, &invalidAlias, &execPermitted, &queryNeeded, hv_path);
1067 /* This function does an synchronous filter; i.e. the code runs a filter
1068 for policy and alias, and if policy denies exec and the command is
1069 valid, then posts a modal dialog and waits for the user to decide
1070 what to do before returning. */
1071 goodCmd = _DtHelpFilterExecCmd(helpWidget, commandStr,
1072 pDisplayStuff->executionPolicy, True,
1073 pHelpStuff, &filteredCmdStr, hv_path);
1074 execPermitted = (goodCmd == 0); /* convert an error int into a Boolean */
1076 (( pDisplayStuff->executionPolicy==DtHELP_EXECUTE_QUERY_ALL)
1077 || (pDisplayStuff->executionPolicy==DtHELP_EXECUTE_QUERY_UNALIASED))
1081 /* if permissions allow immediate execution, do so */
1082 if (execPermitted && False == queryNeeded && diff_home_dirs == False)
1084 (void) _DtHelpExecProcedure (pHelpStuff->pDisplayArea, filteredCmdStr);
1085 free(filteredCmdStr);
1086 return; /* RETURN */
1089 /* this traps bad cmds and also use of the synchronous filter call */
1090 if (NULL == filteredCmdStr) return; /* RETURN */
1092 /*** Create a modeless dialog to inform the user of the problem
1093 and possibly allow them to execute the command anyway. ***/
1095 /* create the dialog, but don't yet manage it */
1096 if ( diff_home_dirs == True)
1097 msgDlg = CreateExecErrorDlg(helpWidget,filteredCmdStr, invalidAlias,pHelpStuff,
1098 MISMATCHING_HOME_DIRS, home_dir );
1100 msgDlg = CreateExecErrorDlg(helpWidget,filteredCmdStr, invalidAlias,pHelpStuff,
1104 /*** setup ExecuteAnyway and Help buttons ***/
1106 if ( (diff_home_dirs == True)
1108 (queryNeeded && execPermitted) )
1110 /* give the right title to the buttons */
1111 labelString = XmStringCreateLocalized(((char *)_DTGETMESSAGE
1112 (HUSET, 10,"Execute Anyway")));
1113 /* give the right title to the Cancel button */
1114 labelString2 = XmStringCreateLocalized(((char *)_DTGETMESSAGE
1115 (HUSET, 11,"Don't Execute")));
1117 XtSetArg (args[n], XmNokLabelString, labelString); n++;
1118 XtSetArg (args[n], XmNcancelLabelString, labelString2); n++;
1119 XtSetValues(msgDlg,args,n);
1120 XmStringFree(labelString);
1121 XmStringFree(labelString2);
1123 btn = XmMessageBoxGetChild (msgDlg, XmDIALOG_OK_BUTTON);
1124 XtManageChild (btn); /* re-manage the button */
1126 /* add the ExecuteContextCB() client-data and callback */
1127 execContext = malloc(sizeof(ExecContext));
1130 execContext->command = filteredCmdStr;
1131 execContext->pDisplayArea = pHelpStuff->pDisplayArea;
1132 XtAddCallback(btn, XmNactivateCallback,
1133 ExecuteContextCB, (XtPointer) execContext);
1137 free(filteredCmdStr);
1139 } /* cmd wasn't an alias */
1142 free(filteredCmdStr);
1145 /* Display message dialog */
1146 XtManageChild (msgDlg);
1153 /*****************************************************************************
1154 * Function: LocateWidgetId()
1159 *****************************************************************************/
1160 static Widget LocateWidgetId(
1167 static Cursor DfltOnItemCursor = 0;
1170 CompositeWidget comp_widget;
1182 Boolean notDone=TRUE;
1185 /* Make the target cursor */
1190 cursor = XCreateFontCursor (dpy, XC_question_arrow);
1193 _DtHelpProcessLock();
1194 if (0 == DfltOnItemCursor)
1199 unsigned int height;
1200 unsigned int xHotspot;
1201 unsigned int yHotspot;
1206 width = onitem32_width;
1207 height = onitem32_height;
1208 bits = (char *) onitem32_bits;
1209 maskBits = (char *) onitem32_m_bits;
1210 xHotspot = onitem32_x_hot;
1211 yHotspot = onitem32_y_hot;
1213 pixmap = XCreateBitmapFromData (dpy,
1214 RootWindowOfScreen(XtScreen(shellWidget)), bits,
1218 maskPixmap = XCreateBitmapFromData (dpy,
1219 RootWindowOfScreen(XtScreen(shellWidget)), maskBits,
1222 xcolors[0].pixel = BlackPixelOfScreen(ScreenOfDisplay(dpy, screen));
1223 xcolors[1].pixel = WhitePixelOfScreen(ScreenOfDisplay(dpy, screen));
1226 DefaultColormapOfScreen(ScreenOfDisplay(dpy, screen)),
1230 DfltOnItemCursor = XCreatePixmapCursor (dpy, pixmap, maskPixmap,
1231 &(xcolors[0]), &(xcolors[1]),
1232 xHotspot, yHotspot);
1233 XFreePixmap (dpy, pixmap);
1234 XFreePixmap (dpy, maskPixmap);
1235 } /* if dflt cursor not yet created */
1236 cursor = DfltOnItemCursor;
1237 _DtHelpProcessUnlock();
1238 } /* if to use the standard cursor */
1242 /* Grab the pointer using target cursor, letting it roam all over */
1243 status = XtGrabPointer (shellWidget, TRUE,
1244 ButtonPressMask|ButtonReleaseMask, GrabModeAsync,
1245 GrabModeAsync, None, cursor, CurrentTime);
1246 if (status != GrabSuccess)
1248 XmeWarning(shellWidget,(char *)_DTGETMESSAGE(HUSET, 3,
1249 "Internal Error: Could not grab the mouse\nDtHelpReturnSelectedWidget aborted.\n"));
1250 *statusRet = DtHELP_SELECT_ERROR;
1256 /* Grab the Keyboard so we can catch the ESC button press */
1257 status = XtGrabKeyboard(shellWidget, False,
1258 GrabModeAsync, GrabModeAsync, CurrentTime);
1259 if (status != GrabSuccess)
1262 XtUngrabPointer (shellWidget, CurrentTime);
1263 XmeWarning(shellWidget,(char *)_DTGETMESSAGE(HUSET, 4,
1264 "Internal Error: Could not grab the keyboard\nDtHelpReturnSelectedWidget() aborted.\n"));
1265 *statusRet = DtHELP_SELECT_ERROR;
1269 /* We are ok so let the user select a window... */
1272 XtAppContext app = XtWidgetToApplicationContext(shellWidget);
1273 /* allow one more event */
1275 XtAppNextEvent(app, &event);
1279 while (!(mask = XtAppPending(app)))
1280 ; /* Busy waiting - so we don't lose our Lock! */
1282 if (!(mask & XtIMXEvent)) /* Not a XEvent, it's an alternate input/timer event */
1283 XtAppProcessEvent(app, mask); /* No blocking, since an event is ready */
1284 else /* We have an XEvent */
1286 /* Get the XEvent - we know it's there! Note that XtAppNextEvent
1287 would also process timers/alternate inputs.
1289 XtAppNextEvent(app, &event);
1290 #endif /* XTHREADS */
1291 widget = XtWindowToWidget(dpy, event.xany.window);
1293 switch (event.type) {
1300 /* Look for ESC key press and stop if we get one */
1301 if (event.xkey.state & ShiftMask)
1306 keySym = XLookupKeysym((XKeyEvent *)&event, offset);
1307 if (keySym == XK_Escape)
1309 XtUngrabKeyboard (shellWidget, CurrentTime);
1310 XtUngrabPointer (shellWidget, CurrentTime);
1311 *statusRet = DtHELP_SELECT_ABORT;
1315 XtDispatchEvent(&event);
1322 XtUngrabKeyboard (shellWidget, CurrentTime); /* Done with keyboard */
1323 XtUngrabPointer (shellWidget, CurrentTime); /* Done with pointer */
1325 /* If its null then the user selected some area outside our window(s) */
1326 if (widget == shellWidget)
1328 *statusRet = DtHELP_SELECT_INVALID;
1331 if (!XtIsComposite (widget))
1333 *statusRet = DtHELP_SELECT_VALID;
1337 /* Get the x and y and parent relative to the current window */
1338 parent = RootWindow(dpy, screen);
1339 target_win = XtWindow(widget);
1340 x = event.xbutton.x_root;
1341 y = event.xbutton.y_root;
1343 XTranslateCoordinates(dpy, parent, target_win, x, y,
1344 &new_x, &new_y, &sub);
1348 comp_widget = (CompositeWidget)widget;
1350 /* look for gadgets at this point */
1351 for (i = 0; i < comp_widget->composite.num_children; i++) {
1352 child = comp_widget->composite.children[i];
1353 /* put in check for only managed widgets here */
1354 if(XtIsManaged(child))
1355 if (PT_IN_CHILD (x, y, child))
1357 *statusRet = DtHELP_SELECT_VALID;
1362 *statusRet = DtHELP_SELECT_VALID;
1369 /*****************************************************************************
1370 * Function: Boolean RememberDir(String path)
1372 * Parameters: path Specifies the path to check.
1374 * Return Value: Boolean if the path name is good.
1376 * Description: Use the directory caching mechanism to improve performance
1377 * by remembering the directories that have already been
1380 *****************************************************************************/
1382 RememberDir(String path)
1388 if (path == NULL || *path == '\0')
1391 if (_DtHelpCeStrrchr(path, "/", MB_CUR_MAX, &ptr) == 0 && ptr != path)
1394 result = _DtHelpCeCheckAndCacheDir(path);
1397 if (result == 0 && access(path, R_OK) == 0 &&
1398 stat(path, &buf) == 0 && S_ISREG(buf.st_mode))
1404 /*****************************************************************************
1405 * Function: Boolean _DtHelpResolvePathname(
1410 * Return Value: Boolean.
1413 * Description: _DtHelpResolvePathname attempts to validate and expand a path
1414 * to a Cache Creek help access file.
1416 *****************************************************************************/
1417 Boolean _DtHelpResolvePathname(
1419 char * * io_fileName,
1420 _DtHelpVolumeHdl * io_volumeHandle,
1421 char * sysVolumeSearchPath,
1422 char * userVolumeSearchPath)
1424 String newPath = NULL;
1426 /* try to locate file and its entry, if present */
1427 newPath = _DtHelpFileLocate(DtHelpVOLUME_TYPE, *io_fileName,
1428 _DtHelpFileSuffixList,False,R_OK);
1430 /* If we found a valid file let's do some set up here */
1432 if (newPath != NULL) /* We have a valid volume file so open it */
1434 /* Close the current one if we have one open */
1435 if (*io_volumeHandle != NULL)
1436 _DtHelpCloseVolume(*io_volumeHandle);
1438 /* Open the help volume file and save the handle id */
1439 if (_DtHelpOpenVolume(newPath,io_volumeHandle) >= 0)
1441 /* Copy the expanded file location path */
1442 XtFree(*io_fileName);
1443 *io_fileName = newPath;
1449 /* ERROR; leave io_fileName untouched on error
1450 * We used to set it to null here now we just return what came in
1452 /* later NOTE: this seems strange, since we have closed the
1453 old volume, invalidating io_fileName */
1455 XmeWarning(widget,(char*)UtilMessage2);
1459 else /* We have a non-valid path */
1461 /* ERROR; leave io_fileName untouched on error
1462 * We used to set it to null here now we just return what came in
1465 XmeWarning(widget,(char*)UtilMessage0);
1475 /*****************************************************************************
1476 * Function: Boolean _DtHelpExpandHelpVolume(DtHelpDialogWidget nw);
1479 * Parameters: nw Specifies the current help dialog widget.
1481 * Return Value: Boolean.
1484 * Description: _DtHelpExpandHelpVolume looks for a $LANG variable in the
1485 * helpAccesFile string and if found, replaces it with the
1486 * current lang variable.
1488 *****************************************************************************/
1489 Boolean _DtHelpExpandHelpVolume(
1491 _DtHelpDisplayWidgetStuff * display,
1492 _DtHelpCommonHelpStuff * help,
1493 _DtHelpPrintStuff * print)
1495 Boolean validTopic = FALSE;
1496 Boolean validPath = FALSE;
1499 /* Free the old, and Copy the new volumeHandle to printVolume varialbe */
1500 if (print->printVolume != NULL)
1501 XtFree(print->printVolume);
1503 print->printVolume = XtNewString(display->helpVolume);
1505 validPath = _DtHelpResolvePathname((Widget)w,
1506 &print->printVolume,
1507 &display->volumeHandle,
1508 help->sysVolumeSearchPath,
1509 help->userVolumeSearchPath);
1512 /* Check to see that we resolved our path correctly */
1514 return (FALSE); /* RETURN */
1518 /* The following routine will malloc memory for the topLevelId
1519 * variable, so we must free our current version first.
1521 XtFree(help->topLevelId);
1523 /* Assign our top level topic for this help access file */
1524 validTopic = _DtHelpCeGetTopTopicId(display->volumeHandle, &topLevelId);
1528 /* Bad top level topic */
1529 help->topLevelId = NULL;
1534 /* recall that the topLevelId/File vars are malloc'd */
1535 help->topLevelId = topLevelId;
1542 /*****************************************************************************
1543 * Function: char *_DtHelpParseIdString(char * specification);
1546 * Parameters: specification Specifies an author defined help topic.
1548 * Return Value: Void.
1550 * Description: This function copies the locationId portion of the
1551 * specification and returns it to the calling routine.
1553 *****************************************************************************/
1554 char *_DtHelpParseIdString(
1555 char *specification)
1558 char *pAccessFile = NULL;
1560 char *returnStr=NULL;
1561 char *strtok_ptr=NULL;
1563 tmpSpec = XtNewString(specification);
1566 /* First look for a blank in the specification. This will signify that
1567 * we have a HelpAccessFile as part of the specification.
1570 /* The first call will return true, with the first string */
1571 pAccessFile = DtStrtok_r(tmpSpec, " ", &strtok_ptr);
1572 returnStr = XtNewString(pAccessFile);
1574 /* The second call will return true only if we have another string */
1575 pAccessFile = DtStrtok_r(NULL, " ", &strtok_ptr);
1577 if (pAccessFile != NULL)
1579 /* We have a helpAccessFile in our specification */
1583 returnStr = XtNewString(pAccessFile);
1590 /* We don't have a helpAccessFile as part of the specificaiton
1591 * so we just return our locationId.
1601 /*****************************************************************************
1602 * Function: char *_DtHelpParseAccessFile(char * specification);
1605 * Parameters: specification Specifies an author defined help topic.
1607 * Return Value: Void.
1609 * Description: This function copies the helpAccessFile portion of the
1610 * specification and returns it to the calling routine.
1612 *****************************************************************************/
1613 char *_DtHelpParseAccessFile(
1614 char *specification)
1616 char *pAccessFile = NULL;
1618 char *returnStr=NULL;
1619 char *strtok_ptr=NULL;
1621 tmpSpec = XtNewString(specification);
1624 /* First look for a blank in the specification. This will signify that
1625 * we have a HelpAccessFile as part of the specification.
1628 /* The first call will return true, with the first string */
1629 pAccessFile = DtStrtok_r(tmpSpec, " ", &strtok_ptr);
1630 returnStr = XtNewString(pAccessFile);
1632 /* The second call will return true only if we have another string */
1633 pAccessFile = DtStrtok_r(NULL, " ", &strtok_ptr);
1635 if (pAccessFile != NULL)
1637 /* We have a helpAccessFile in our specification */
1640 /* If we have an accessFile, but it's not a full path, then we
1641 * must get the full path from the reg file.
1649 /* We don't have a helpAccessFile as part of the specificaiton
1666 /*****************************************************************************
1667 * Function: DtHelpReturnSelectedWidgetId
1669 * Parameters: parent Specifies the widget ID to use as the bases of
1670 * interaction, usually a top level shell.
1672 * cursor Specifies the cursor to be used for the pointer
1673 * during the interaction. If a value of NULL is
1674 * used this function will use a default cursor
1677 * widget This is the return value (e.g. the selected
1678 * widget). A value of NULL is returned on error.
1680 * Return Value: Status: (-1,0 or 1).
1682 * Purpose: Allows developers to get the widget ID for any widget in their UI
1683 * that the user has selected via the pointer. This function will
1684 * cause the cursor to change and allow a user to select an item in
1687 *****************************************************************************/
1688 int DtHelpReturnSelectedWidgetId(
1697 Widget selectedItem;
1698 int status=DtHELP_SELECT_ERROR;
1701 _DtHelpWidgetToAppContext(parent);
1703 _DtHelpAppLock(app);
1704 /* Setup some needed variables */
1705 dpy = XtDisplay(parent);
1706 retScr = XtScreen(parent);
1708 screen = XScreenNumberOfScreen(retScr);
1710 /* refresh the display */
1711 XmUpdateDisplay(parent);
1713 /* Change the curser to let the user select the desired widget */
1714 selectedItem = LocateWidgetId(dpy, screen, &status, parent, cursor);
1718 case DtHELP_SELECT_VALID:
1719 *widget = selectedItem;
1720 result = DtHELP_SELECT_VALID;
1723 case DtHELP_SELECT_ABORT:
1725 result = DtHELP_SELECT_ABORT;
1728 case DtHELP_SELECT_ERROR:
1730 result = DtHELP_SELECT_ERROR;
1733 case DtHELP_SELECT_INVALID:
1736 result = DtHELP_SELECT_INVALID;
1740 _DtHelpAppUnlock(app);
1751 /*****************************************************************************
1752 * Function: void _DtHelpTopicListAddToHead(
1756 * DtTopicListStruct *pHead,
1757 * DtTopicListStruct *pTale,
1763 * Return Value: Void.
1765 * Purpose: Adds an element to the top of the given topicList.
1767 *****************************************************************************/
1768 void _DtHelpTopicListAddToHead(
1770 XmString topicTitle,
1774 DtTopicListStruct **pHead,
1775 DtTopicListStruct **pTale,
1779 DtTopicListStruct *pTemp=NULL;
1781 /* add the new topic to the top */
1782 pTemp = (DtTopicListStruct *) XtMalloc((sizeof(DtTopicListStruct)));
1784 pTemp->pNext = (*pHead);
1785 pTemp->pPrevious = NULL;
1787 /* Assign the passed in values to our first element */
1788 pTemp->locationId = XtNewString(locationId);
1789 pTemp->topicTitleLbl = NULL;
1790 if (topicTitle != NULL)
1791 pTemp->topicTitleLbl= XmStringCopy(topicTitle);
1792 pTemp->topicType = topicType;
1793 pTemp->helpVolume = XtNewString(accessPath);
1794 pTemp->scrollPosition = scrollPosition;
1796 /* Add locationId as first element if pHead = NULL */
1799 /* Assign our tale pointer */
1800 (*pTale) = (*pHead);
1802 /* Make sure or totalNodes counter is correct, e.g. force it to 1 */
1806 { /* We have a list so add the new topic to the top */
1808 (*pHead)->pPrevious = pTemp;
1810 /* Assign our tale pointer only the first time in this block */
1811 if (*totalNodes == 1)
1812 (*pTale) = (*pHead);
1814 /* Re-Assign our head pointer to point to the new head of the list */
1816 /* Bump our totalNode count */
1817 *totalNodes = *totalNodes +1;
1820 /* set the head to the current entry */
1823 /* If we have reached our maxNodes remove a node from the end of our list */
1824 if (*totalNodes > maxNodes)
1827 (*pTale) = (*pTale)->pPrevious;
1828 (*pTale)->pNext = NULL;
1829 pTemp->pPrevious = NULL;
1831 /* Free the id String and AccessPath elements */
1832 XtFree(pTemp->locationId);
1833 XtFree(pTemp->helpVolume);
1834 if (pTemp->topicTitleLbl != NULL)
1835 XmStringFree(pTemp->topicTitleLbl);
1837 /* Now, free the whole node */
1838 XtFree((char*)pTemp);
1840 /* Bump back our total node counter */
1841 *totalNodes = *totalNodes -1;
1849 /*****************************************************************************
1850 * Function: void _DtHelpTopicListDeleteHead(
1851 * DtTopicListStruct *pHead,
1852 * DtTopicListStruct *pTale,
1858 * Return Value: Void.
1860 * Purpose: Delets an element from the top of the given topicList.
1862 *****************************************************************************/
1863 void _DtHelpTopicListDeleteHead(
1864 DtTopicListStruct **pHead,
1865 DtTopicListStruct **pTale,
1868 DtTopicListStruct *pTemp=NULL;
1870 /* Delete the top node in our topic list */
1874 if(pTemp != (*pTale)) /* (e.g. more than one node in list) */
1876 (*pHead) = pTemp->pNext;
1877 pTemp->pNext = NULL;
1878 (*pHead)->pPrevious = NULL;
1880 /* Free the id String and accessPath elements */
1881 XtFree(pTemp->locationId);
1882 XtFree(pTemp->helpVolume);
1884 /* Now, free the whole node */
1885 XtFree((char*)pTemp);
1887 /* Bump back our total node counter */
1888 *totalNodes = *totalNodes -1;
1898 /*****************************************************************************
1899 * Function: void _DtHelpMapCB()
1903 * Parameters: client_data is the widget in reference to
1904 * which widget w is placed
1906 * Return Value: Void.
1908 * Purpose: Determins where a new child dialog should be mapped in
1909 * relation to its parent.
1911 * Algorithm: 1. attempt left or right placement with no overlap
1912 * 2. if fails, attempt up or down placement with no overlap
1913 * 3. if fails, determines location with least
1914 * amount of overlap, and places there.
1916 *****************************************************************************/
1917 XtCallbackProc _DtHelpMapCB(
1919 XtPointer client_data,
1920 XtPointer call_data )
1924 Position centeredY, bestX, bestY, pX, pY;
1925 Dimension pHeight, myHeight, pWidth, myWidth;
1926 Dimension maxX, maxY;
1927 int rhsX, lhsX, topY, botY; /* needs to be int, not Dimension */
1932 parent = (Widget)client_data;
1933 display = XtDisplay(w);
1934 screen = XtScreen(w);
1935 screenNumber = XScreenNumberOfScreen(screen);
1941 pHeight = XtHeight(parent);
1942 pWidth = XtWidth(parent);
1943 myHeight = XtHeight(w);
1944 myWidth = XtWidth(w);
1945 maxX = XDisplayWidth(display,screenNumber);
1946 maxY = XDisplayHeight(display,screenNumber);
1949 * 1. attempt left or right placement with no overlap
1950 * 2. if fails, attempt up or down placement with no overlap
1951 * 3. if fails, places on the right in the middle
1954 /* first try left right placement */
1955 bestY = pY + pHeight/2 - myHeight/2;
1958 lhsX = pX - myWidth - 8; /* 8: account for border */
1959 if ( ((int)(rhsX + myWidth)) < ((int) maxX) ) bestX = rhsX;
1960 else if ( lhsX > 0 ) bestX = lhsX;
1963 /* then try up down placement */
1964 bestX = pX + pWidth/2 - myWidth/2;
1965 botY = pY + pHeight;
1966 topY = pY - myHeight - 44; /* 44: account for menu border */
1967 if ( ((int)(botY + myWidth)) < ((int) maxY) ) bestY = botY;
1968 else if ( topY > 0 ) bestY = topY;
1971 /* otherwise, center vertically and on the right */
1972 bestX = maxX - myWidth;
1977 XtSetArg(args[0], XmNx, bestX);
1978 XtSetArg(args[1], XmNy, bestY);
1979 XtSetValues(w, args, 2);
1981 return((XtCallbackProc) NULL);
1990 /*****************************************************************************
1991 * Function: void _DtHelpMapCenteredCB(
1997 * Return Value: Void.
1999 * Purpose: Determins where the center of our help dialog is and sets
2000 * where new child dialog should be mapped such that its centered.
2002 *****************************************************************************/
2003 XtCallbackProc _DtHelpMapCenteredCB(
2005 XtPointer client_data,
2006 XtPointer call_data )
2010 Position newX, newY, pY, pX;
2011 Dimension pHeight, myHeight, pWidth, myWidth;
2013 parent = (Widget)client_data;
2017 pHeight = XtHeight(parent);
2018 pWidth = XtWidth(parent);
2019 myHeight = XtHeight(w);
2020 myWidth = XtWidth(w);
2023 newY = ((Position)(pHeight - myHeight) / 2) + pY;
2024 newX = ((Position)(pWidth - myWidth) / 2) + pX;
2026 XtSetArg(args[0], XmNx, newX);
2027 XtSetArg(args[1], XmNy, newY);
2028 XtSetValues(w, args, 2);
2030 return((XtCallbackProc) NULL);
2037 /*****************************************************************************
2038 * Function: void _DtHelpDisplayDefinitionBox(
2040 * Widget definitionBox,
2042 * char * locationId);
2048 * Purpose: This routine will create and post the definition box.
2049 * (e.g. the Quick Help Dialog widget)
2051 ****************************************************************************/
2052 void _DtHelpDisplayDefinitionBox(
2054 Widget **definitionBox,
2061 Widget printWidget, helpWidget, backWidget;
2062 XmString closeString;
2065 /* get the title from the main help dialog and use it here for */
2067 XtSetArg (args[n], XmNtitle, &(title)); ++n;
2068 XtGetValues (XtParent(parent), args, n);
2071 if (*definitionBox == NULL)
2074 /* Create the QuickHelpDialog widget to use as the definition box */
2075 closeString = XmStringCreateLocalized(((char *)_DTGETMESSAGE
2076 (HUSET, 2,"Close")));
2078 XtSetArg (args[n], DtNhelpVolume, path); n++;
2079 XtSetArg (args[n], DtNhelpType, DtHELP_TYPE_TOPIC); n++;
2080 XtSetArg (args[n], DtNlocationId, locationId); n++;
2081 XtSetArg (args[n], DtNcloseLabelString, closeString); n++;
2082 XtSetArg (args[n], XmNtitle, title); n++;
2084 (Widget *)DtCreateHelpQuickDialog(parent, "definitionBox",
2086 XmStringFree(closeString);
2088 /* Catch the close callback so we can destroy the widget */
2089 XtAddCallback((Widget)*definitionBox, DtNcloseCallback,
2090 CloseDefBoxCB, (XtPointer) NULL);
2093 /* We do not want a print button for now so we unmap it */
2094 printWidget = DtHelpQuickDialogGetChild ((Widget)*definitionBox,
2095 DtHELP_QUICK_PRINT_BUTTON);
2096 XtUnmanageChild (printWidget);
2098 /* We do not want a help button for now so we unmap it */
2099 helpWidget = DtHelpQuickDialogGetChild ((Widget)*definitionBox,
2100 DtHELP_QUICK_HELP_BUTTON);
2101 XtUnmanageChild (helpWidget);
2104 /* We do not want a BACK button for now so we unmap it */
2105 backWidget = DtHelpQuickDialogGetChild ((Widget)*definitionBox,
2106 DtHELP_QUICK_BACK_BUTTON);
2107 XtUnmanageChild (backWidget);
2111 /* Adjust the decorations for the dialog shell of the dialog */
2113 XtSetArg(args[n], XmNmwmFunctions, MWM_FUNC_RESIZE | MWM_FUNC_MOVE); n++;
2114 XtSetArg (args[n], XmNmwmDecorations,
2115 MWM_DECOR_BORDER | MWM_DECOR_TITLE | MWM_DECOR_RESIZEH); n++;
2116 XtSetValues (XtParent(*definitionBox), args, n);
2118 /* Add the popup position callback to our history dialog */
2119 XtAddCallback (XtParent(*definitionBox), XmNpopupCallback,
2120 (XtCallbackProc)_DtHelpMapCenteredCB, (XtPointer)XtParent(parent));
2127 /* We already have one so lets use it. */
2129 /* Set the proper title */
2131 XtSetArg (args[n], XmNtitle, title); ++n;
2132 XtSetValues (XtParent(*definitionBox), args, n);
2134 /* Set the proper contents. */
2136 XtSetArg (args[n], DtNhelpType, DtHELP_TYPE_TOPIC); n++;
2137 XtSetArg (args[n], DtNhelpVolume, path); n++;
2138 XtSetArg (args[n], DtNlocationId, locationId); n++;
2139 XtSetValues ((Widget)*definitionBox, args, n);
2144 /* Display the dialog */
2145 XtManageChild((Widget)*definitionBox);
2146 XtMapWidget(XtParent((Widget)*definitionBox));
2151 /*****************************************************************************
2152 * Function: static void CloseDefBoxCB(
2154 * XtPointer client_data,
2155 * XtPointer call_data);
2161 * Purpose: This routine closes and destroys the Definition Box
2162 * Dialog Widget that we create.
2164 ****************************************************************************/
2165 static void CloseDefBoxCB(
2167 XtPointer client_data,
2168 XtPointer call_data )
2180 /*****************************************************************************
2181 * Function: void _DtHelpDisplayFormatError()
2187 * Purpose: This routine generate and display the proper errror
2188 * message to the display area as well as send the proper
2189 * error to XmWarning() function.
2191 ****************************************************************************/
2192 void _DtHelpDisplayFormatError(
2193 XtPointer displayArea,
2198 XtPointer topicHandle;
2200 /* Set the string to the current help dialog */
2201 (void) _DtHelpFormatAsciiStringDynamic(displayArea, userError, &topicHandle);
2203 /* We ignore the status return here, because if we error out here we are
2204 * in big trouble because this is an error routine
2207 _DtHelpDisplayAreaSetList (displayArea, topicHandle, FALSE, -1);
2209 if (systemError != NULL)
2210 XmeWarning((Widget)widget, systemError);
2216 /*****************************************************************************
2217 * Function: void _DtHelpCommonHelpInit()
2223 * Purpose: This routine inits common help stuff
2225 ****************************************************************************/
2226 void _DtHelpCommonHelpInit(
2227 _DtHelpCommonHelpStuff * help)
2229 help->topLevelId = NULL;
2230 help->currentHelpFile = NULL;
2232 /* for help on help */
2233 if ( help->helpOnHelpVolume != _DtHelpDefaultHelp4HelpVolume)
2234 help->helpOnHelpVolume = XtNewString(help->helpOnHelpVolume);
2235 if ( NULL == help->helpOnHelpVolume )
2236 help->helpOnHelpVolume = (char *)_DtHelpDefaultHelp4HelpVolume;
2237 help->pHelpListHead = NULL; /* Help List Pointer */
2238 help->onHelpDialog = NULL; /* help on help dialog */
2239 help->pDisplayArea = NULL; /* Display widget handle */
2241 /* get the search paths used by the widget */
2242 help->userVolumeSearchPath = _DtHelpGetUserSearchPath();
2243 help->sysVolumeSearchPath = _DtHelpGetSystemSearchPath();
2248 /*****************************************************************************
2249 * Function: void _DtHelpCommonHelpClean()
2255 * Purpose: This routine cleans up common help stuff
2257 ****************************************************************************/
2258 void _DtHelpCommonHelpClean(
2259 _DtHelpCommonHelpStuff * help,
2262 free(help->topLevelId);
2263 XtFree(help->currentHelpFile);
2265 help->topLevelId = NULL;
2266 help->currentHelpFile = NULL;
2270 if (help->helpOnHelpVolume != _DtHelpDefaultHelp4HelpVolume)
2271 XtFree(help->helpOnHelpVolume);
2273 /* Free all the info we saved for our help callbacks */
2274 _DtHelpListFree(&help->pHelpListHead);
2276 XtFree(help->userVolumeSearchPath);
2277 XtFree(help->sysVolumeSearchPath);
2279 memset(help,0,sizeof(_DtHelpCommonHelpStuff));
2283 /* Set our display area to a null starting vlaues */
2284 _DtHelpDisplayAreaClean(help->pDisplayArea);
2290 /*****************************************************************************
2291 * Function: void _DtHelpSetDlgButtonsWidth
2297 * Purpose: This routine cleans up common help stuff
2299 ****************************************************************************/
2300 void _DtHelpSetButtonPositions(
2303 Dimension minFormWidth,
2304 Dimension btnMargins,
2305 Dimension minBetweenBtnSpace)
2306 { /* position buttons */
2308 /* This code adds up the sizes of the buttons to go into
2309 the bottom row and calculates the form position percentages.
2310 All buttons are the same size, and are able to hold all
2311 the strings that may be dynamically placed in them.
2312 All buttons are 5% apart. */
2313 /* This code is specifically written to handle 3 buttons
2314 and assumes that the first 3 strings are to the ActionBtn */
2315 Dimension minWidthWithSpace = 0;
2316 Dimension borderWidth = 0;
2317 Dimension sumWidth = 0;
2318 Dimension leftPos = 0;
2319 Dimension rightPos = 0;
2320 Dimension spaceWidth = 0;
2322 Dimension maxBtnWidth = 0;
2324 XmFontList fontList = NULL;
2329 if (numBtns <= 0 || NULL == btnList[0]) return;
2331 /* get the fontList for the button */
2332 XtSetArg (args[0], XmNborderWidth, &borderWidth);
2333 XtSetArg (args[1], XmNfontList, &fontList);
2334 XtGetValues (btnList[0], args, 2);
2335 /* assumption: the fontList that is returned is not owned by me; don't free */
2337 /* cycle through all buttons */
2338 for (i=0; i<numBtns && NULL!=btnList[i]; i++)
2340 XmString labelString;
2342 /* get the label from the button */
2343 XtSetArg (args[0], XmNlabelString, &labelString);
2344 XtGetValues (btnList[i], args, 1);
2346 btnWidth = XmStringWidth(fontList,labelString) + borderWidth + btnMargins;
2347 if (btnWidth > maxBtnWidth) maxBtnWidth = btnWidth;
2349 XmStringFree(labelString);
2350 } /* for calcing widths */
2351 numBtns = i; /* number of valid buttons */
2353 /* calc the space */
2354 sumWidth = maxBtnWidth * numBtns;
2355 minWidthWithSpace = sumWidth + minBetweenBtnSpace * (numBtns * 2);
2356 if (minWidthWithSpace > minWidthWithSpace) minFormWidth = minWidthWithSpace;
2357 spaceWidth = ((int)(minFormWidth - sumWidth) / (numBtns * 2));
2359 /* scale pixels to percent */
2360 scale = 100.0 / (float) minFormWidth;
2362 /* set the positions of each button */
2363 leftPos = spaceWidth;
2364 for ( i=0; i<numBtns; i++ )
2366 rightPos = leftPos + maxBtnWidth;
2369 XtSetArg (args[n], XmNleftAttachment, XmATTACH_POSITION); n++;
2370 XtSetArg (args[n], XmNleftPosition, (Dimension) (((float) leftPos)*scale)); n++;
2371 XtSetArg (args[n], XmNrightAttachment, XmATTACH_POSITION); n++;
2372 XtSetArg (args[n], XmNrightPosition,(Dimension) (((float) rightPos)*scale)); n++;
2373 XtSetValues (btnList[i], args, n);
2375 leftPos = rightPos + spaceWidth + spaceWidth;
2376 } /* setup the positions for all buttons */
2377 } /* _DtHelpSetDlgButtonsWidth */
2381 /*****************************************************************************
2382 * Function: _DtHelpXmFontListGetPropertyMax
2385 * fontList: an XmFontList
2386 * atom: an XA_xxx value (see Vol 1, chpt 6.2.9)
2387 * ret_propertyValue: ptr to long value that will hold the max value
2390 * True: got at least one value
2391 * False: unable to get any value; ret_propertyValue unchanged
2394 * This function returns the max value of XGetFontProperty calls
2395 * for each font in the XmFontList
2396 * If there is an error, ret_propertyValue is left unchanged.
2398 ****************************************************************************/
2400 _DtHelpXmFontListGetPropertyMax(
2401 XmFontList fontList,
2403 unsigned long *ret_propertyValue)
2405 Boolean gotValue = False;
2406 XmFontContext context;
2407 XmFontListEntry entry;
2410 if (NULL == fontList) return False; /* RETURN on error */
2412 /* walk through the fontList entries and add them in */
2413 XmFontListInitFontContext(&context,fontList);
2414 for ( entry = XmFontListNextEntry(context);
2416 entry = XmFontListNextEntry(context) )
2418 unsigned long value;
2421 fontData = XmFontListEntryGetFont(entry,&type);
2422 if (XmFONT_IS_FONT == type)
2424 XFontStruct * fontStruct;
2426 /* cast according to type */
2427 fontStruct = (XFontStruct *) fontData;
2429 if(XGetFontProperty(fontStruct, atom, &value) == TRUE)
2431 if(gotValue == False) /* haven't gotten any prop value yet */
2433 *ret_propertyValue = value;
2436 else /* have a good prop value already...get the max one */
2438 if(value > *ret_propertyValue)
2439 *ret_propertyValue = value;
2441 } /* if the getproperty call was good */
2443 else /* XmFONT_IS_FONTSET */
2446 XFontStruct **font_list;
2451 /* cast according to type */
2452 fontSet = (XFontSet) fontData;
2454 numfont=XFontsOfFontSet(fontSet,&font_list,&name_list);
2455 for(i = 0; i < numfont; i++)
2457 if(XGetFontProperty(font_list[i], atom, &value) == TRUE)
2459 if(gotValue == False) /* haven't gotten any prop value yet */
2461 *ret_propertyValue = value;
2464 else /* have a good prop value already...get the max one */
2466 if(value > *ret_propertyValue)
2467 *ret_propertyValue = value;
2469 } /* if the getproperty call was good */
2470 } /* for all fonts in the font set */
2471 } /* this entry uses a font set */
2472 } /* for all font entries in the font list */
2473 XmFontListFreeFontContext(context);