Merge branch 'master' of ssh://git.exim.org/home/git/exim
[users/jgh/exim.git] / src / exim_monitor / em_TextPop.c
1 /* $Cambridge: exim/src/exim_monitor/em_TextPop.c,v 1.1 2004/10/07 10:39:01 ph10 Exp $ */
2 /* $XConsortium: TextPop.c,v 1.22 91/07/25 18:10:22 rws Exp $ */
3
4 /***********************************************************
5 Copyright 1989 by the Massachusetts Institute of Technology,
6 Cambridge, Massachusetts.
7
8                         All Rights Reserved
9
10 Permission to use, copy, modify, and distribute this software and its
11 documentation for any purpose and without fee is hereby granted,
12 provided that the above copyright notice appear in all copies and that
13 both that copyright notice and this permission notice appear in
14 supporting documentation, and that the names of Digital or MIT not be
15 used in advertising or publicity pertaining to distribution of the
16 software without specific, written prior permission.
17
18 DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
19 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
20 DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
21 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
22 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
23 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
24 SOFTWARE.
25
26 ******************************************************************/
27
28
29 /****************************************************************************
30 * Modified by Philip Hazel for use with Exim. The "replace" and "insert     *
31 * file" features of the search facility have been removed.  Also took out   *
32 * the declaration of sys_errlist, as it isn't used and causes trouble on    *
33 * some systems that declare it differently. September 1996.                 *
34 * Added the arguments into the static functions declared at the head, to    *
35 * stop some compiler warnings. August 1999.                                 *
36 * Took out the separate declarations of errno and sys_nerr at the start,    *
37 * because they too aren't actually used, and the declaration causes trouble *
38 * on some systems. December 2002.                                           *
39 ****************************************************************************/
40
41
42 /************************************************************
43  *
44  * This file is broken up into three sections one dealing with
45  * each of the three popups created here:
46  *
47  * FileInsert, Search, and Replace.
48  *
49  * There is also a section at the end for utility functions
50  * used by all more than one of these dialogs.
51  *
52  * The following functions are the only non-static ones defined
53  * in this module.  They are located at the begining of the
54  * section that contains this dialog box that uses them.
55  *
56  * void _XawTextInsertFileAction(w, event, params, num_params);
57  * void _XawTextDoSearchAction(w, event, params, num_params);
58  * void _XawTextDoReplaceAction(w, event, params, num_params);
59  * void _XawTextInsertFile(w, event, params, num_params);
60  *
61  *************************************************************/
62
63 #include <X11/IntrinsicP.h>
64 #include <X11/StringDefs.h>
65 #include <X11/Shell.h>
66
67 #include <X11/Xaw/TextP.h>
68 #include <X11/Xaw/AsciiText.h>
69 #include <X11/Xaw/Cardinals.h>
70 #include <X11/Xaw/Command.h>
71 #include <X11/Xaw/Form.h>
72 #include <X11/Xaw/Toggle.h>
73 #include <X11/Xmu/CharSet.h>
74 #include <stdio.h>
75 #include <X11/Xos.h>            /* for O_RDONLY */
76 #include <errno.h>
77
78 /* extern int errno, sys_nerr; */
79 /* extern char* sys_errlist[]; */
80
81 #define DISMISS_NAME  ("cancel")
82 #define DISMISS_NAME_LEN 6
83 #define FORM_NAME     ("form")
84 #define LABEL_NAME    ("label")
85 #define TEXT_NAME     ("text")
86
87 #define R_OFFSET      1
88
89 /* Argument types added by PH August 1999 */
90
91 static void CenterWidgetOnPoint(Widget, XEvent *);
92 static void PopdownSearch(Widget, XtPointer, XtPointer);
93 static void InitializeSearchWidget(struct SearchAndReplace *,
94   XawTextScanDirection, Boolean);
95 static void  SetResource(Widget, char *, XtArgVal);
96 static void  SetSearchLabels(struct SearchAndReplace *, String, String,
97   Boolean);
98 static Widget CreateDialog(Widget, String, String,
99   void (*)(Widget, char *, Widget));
100 static Widget  GetShell(Widget);
101 static void SetWMProtocolTranslations(Widget w);
102 static Boolean DoSearch(struct SearchAndReplace *);
103 static String GetString(Widget);
104
105 static void AddSearchChildren(Widget, char *, Widget);
106
107 static char radio_trans_string[] =
108     "<Btn1Down>,<Btn1Up>:   set() notify()";
109
110 static char search_text_trans[] =
111   "~Shift<Key>Return:      DoSearchAction(Popdown) \n\
112    Ctrl<Key>c:             PopdownSearchAction() \n\
113    ";
114
115
116
117 /************************************************************
118  *
119  * This section of the file contains all the functions that
120  * the search dialog box uses.
121  *
122  ************************************************************/
123
124 /*      Function Name: _XawTextDoSearchAction
125  *      Description: Action routine that can be bound to dialog box's
126  *                   Text Widget that will search for a string in the main
127  *                   Text Widget.
128  *      Arguments:   (Standard Action Routine args)
129  *      Returns:     none.
130  *
131  * Note:
132  *
133  * If the search was sucessful and the argument popdown is passed to
134  * this action routine then the widget will automatically popdown the
135  * search widget.
136  */
137
138 /* ARGSUSED */
139 void
140 _XawTextDoSearchAction(w, event, params, num_params)
141 Widget w;
142 XEvent *event;
143 String * params;
144 Cardinal * num_params;
145 {
146   TextWidget tw = (TextWidget) XtParent(XtParent(XtParent(w)));
147   Boolean popdown = FALSE;
148
149   if ( (*num_params == 1) &&
150        ((params[0][0] == 'p') || (params[0][0] == 'P')) )
151       popdown = TRUE;
152
153   if (DoSearch(tw->text.search) && popdown)
154     PopdownSearch(w, (XtPointer) tw->text.search, NULL);
155 }
156
157 /*      Function Name: _XawTextPopdownSearchAction
158  *      Description: Action routine that can be bound to dialog box's
159  *                   Text Widget that will popdown the search widget.
160  *      Arguments:   (Standard Action Routine args)
161  *      Returns:     none.
162  */
163
164 /* ARGSUSED */
165 void
166 _XawTextPopdownSearchAction(w, event, params, num_params)
167 Widget w;
168 XEvent *event;
169 String * params;
170 Cardinal * num_params;
171 {
172   TextWidget tw = (TextWidget) XtParent(XtParent(XtParent(w)));
173
174   PopdownSearch(w, (XtPointer) tw->text.search, NULL);
175 }
176
177 /*      Function Name: PopdownSeach
178  *      Description: Pops down the search widget and resets it.
179  *      Arguments: w - *** NOT USED ***.
180  *                 closure - a pointer to the search structure.
181  *                 call_data - *** NOT USED ***.
182  *      Returns: none
183  */
184
185 /* ARGSUSED */
186 static void
187 PopdownSearch(w, closure, call_data)
188 Widget w;
189 XtPointer closure;
190 XtPointer call_data;
191 {
192   struct SearchAndReplace * search = (struct SearchAndReplace *) closure;
193
194   SetSearchLabels(search, "Search", "", FALSE);
195   XtPopdown( search->search_popup );
196 }
197
198 /*      Function Name: SearchButton
199  *      Description: Performs a search when the button is clicked.
200  *      Arguments: w - *** NOT USED **.
201  *                 closure - a pointer to the search info.
202  *                 call_data - *** NOT USED ***.
203  *      Returns:
204  */
205
206 /* ARGSUSED */
207 static void
208 SearchButton(w, closure, call_data)
209 Widget w;
210 XtPointer closure;
211 XtPointer call_data;
212 {
213   (void) DoSearch( (struct SearchAndReplace *) closure );
214 }
215
216 /*      Function Name: _XawTextSearch
217  *      Description: Action routine that can be bound to the text widget
218  *                   it will popup the search dialog box.
219  *      Arguments:   w - the text widget.
220  *                   event - X Event (used to get x and y location).
221  *                   params, num_params - the parameter list.
222  *      Returns:     none.
223  *
224  * NOTE:
225  *
226  * The parameter list contains one or two entries that may be the following.
227  *
228  * First Entry:   The first entry is the direction to search by default.
229  *                This arguement must be specified and may have a value of
230  *                "left" or "right".
231  *
232  * Second Entry:  This entry is optional and contains the value of the default
233  *                string to search for.
234  */
235
236 #define SEARCH_HEADER ("Text Widget - Search():")
237
238 void
239 _XawTextSearch(w, event, params, num_params)
240 Widget w;
241 XEvent *event;
242 String * params;
243 Cardinal * num_params;
244 {
245   TextWidget ctx = (TextWidget)w;
246   XawTextScanDirection dir;
247   char * ptr, buf[BUFSIZ];
248   XawTextEditType edit_mode;
249   Arg args[1];
250
251 #ifdef notdef
252   if (ctx->text.source->Search == NULL) {
253       XBell(XtDisplay(w), 0);
254       return;
255   }
256 #endif
257
258   if ( (*num_params < 1) || (*num_params > 2) ) {
259     sprintf(buf, "%s %s\n%s", SEARCH_HEADER, "This action must have only",
260             "one or two parameters");
261     XtAppWarning(XtWidgetToApplicationContext(w), buf);
262     return;
263   }
264   else if (*num_params == 1)
265     ptr = "";
266   else
267     ptr = params[1];
268
269   switch(params[0][0]) {
270   case 'b':                     /* Left. */
271   case 'B':
272     dir = XawsdLeft;
273     break;
274   case 'f':                     /* Right. */
275   case 'F':
276     dir = XawsdRight;
277     break;
278   default:
279     sprintf(buf, "%s %s\n%s", SEARCH_HEADER, "The first parameter must be",
280             "Either 'backward' or 'forward'");
281     XtAppWarning(XtWidgetToApplicationContext(w), buf);
282     return;
283   }
284
285   if (ctx->text.search== NULL) {
286     ctx->text.search = XtNew(struct SearchAndReplace);
287     ctx->text.search->search_popup = CreateDialog(w, ptr, "search",
288                                                   AddSearchChildren);
289     XtRealizeWidget(ctx->text.search->search_popup);
290     SetWMProtocolTranslations(ctx->text.search->search_popup);
291   }
292   else if (*num_params > 1) {
293     XtVaSetValues(ctx->text.search->search_text, XtNstring, ptr, NULL);
294   }
295
296   XtSetArg(args[0], XtNeditType,&edit_mode);
297   XtGetValues(ctx->text.source, args, ONE);
298
299   InitializeSearchWidget(ctx->text.search, dir, (edit_mode == XawtextEdit));
300
301   CenterWidgetOnPoint(ctx->text.search->search_popup, event);
302   XtPopup(ctx->text.search->search_popup, XtGrabNone);
303 }
304
305 /*      Function Name: InitializeSearchWidget
306  *      Description: This function initializes the search widget and
307  *                   is called each time the search widget is poped up.
308  *      Arguments: search - the search widget structure.
309  *                 dir - direction to search.
310  *                 replace_active - state of the sensitivity for the
311  *                                  replace button.
312  *      Returns: none.
313  */
314
315 static void
316 InitializeSearchWidget(struct SearchAndReplace *search,
317   XawTextScanDirection dir, Boolean replace_active)
318 {
319 replace_active = replace_active; /* PH - shuts compilers up */
320
321   switch (dir) {
322   case XawsdLeft:
323     SetResource(search->left_toggle, XtNstate, (XtArgVal) TRUE);
324     break;
325   case XawsdRight:
326     SetResource(search->right_toggle, XtNstate, (XtArgVal) TRUE);
327     break;
328   default:
329     break;
330   }
331 }
332
333 /*      Function Name: AddSearchChildren
334  *      Description: Adds all children to the Search Dialog Widget.
335  *      Arguments: form - the form widget for the search widget.
336  *                 ptr - a pointer to the initial string for the Text Widget.
337  *                 tw - the main text widget.
338  *      Returns: none.
339  */
340
341 static void
342 AddSearchChildren(form, ptr, tw)
343 Widget form, tw;
344 char * ptr;
345 {
346   Arg args[10];
347   Cardinal num_args;
348   Widget cancel, search_button, s_label, s_text;
349   XtTranslations trans;
350   struct SearchAndReplace * search = ((TextWidget) tw)->text.search;
351
352   num_args = 0;
353   XtSetArg(args[num_args], XtNleft, XtChainLeft); num_args++;
354   XtSetArg(args[num_args], XtNright, XtChainLeft); num_args++;
355   XtSetArg(args[num_args], XtNresizable, TRUE ); num_args++;
356   XtSetArg(args[num_args], XtNborderWidth, 0 ); num_args++;
357   search->label1 = XtCreateManagedWidget("label1", labelWidgetClass,
358                                          form, args, num_args);
359
360  /*
361  * We need to add R_OFFSET to the radio_data, because the value zero (0)
362  * has special meaning.
363  */
364
365   num_args = 0;
366   XtSetArg(args[num_args], XtNlabel, "Backward"); num_args++;
367   XtSetArg(args[num_args], XtNfromVert, search->label1); num_args++;
368   XtSetArg(args[num_args], XtNleft, XtChainLeft); num_args++;
369   XtSetArg(args[num_args], XtNright, XtChainLeft); num_args++;
370   XtSetArg(args[num_args], XtNradioData, (caddr_t) XawsdLeft + R_OFFSET);
371   num_args++;
372   search->left_toggle = XtCreateManagedWidget("backwards", toggleWidgetClass,
373                                               form, args, num_args);
374
375   num_args = 0;
376   XtSetArg(args[num_args], XtNlabel, "Forward"); num_args++;
377   XtSetArg(args[num_args], XtNfromVert, search->label1); num_args++;
378   XtSetArg(args[num_args], XtNfromHoriz, search->left_toggle); num_args++;
379   XtSetArg(args[num_args], XtNleft, XtChainLeft); num_args++;
380   XtSetArg(args[num_args], XtNright, XtChainLeft); num_args++;
381   XtSetArg(args[num_args], XtNradioGroup, search->left_toggle); num_args++;
382   XtSetArg(args[num_args], XtNradioData, (caddr_t) XawsdRight + R_OFFSET);
383   num_args++;
384   search->right_toggle = XtCreateManagedWidget("forwards", toggleWidgetClass,
385                                                form, args, num_args);
386
387   {
388     XtTranslations radio_translations;
389
390     radio_translations = XtParseTranslationTable(radio_trans_string);
391     XtOverrideTranslations(search->left_toggle, radio_translations);
392     XtOverrideTranslations(search->right_toggle, radio_translations);
393   }
394
395   num_args = 0;
396   XtSetArg(args[num_args], XtNfromVert, search->left_toggle); num_args++;
397   XtSetArg(args[num_args], XtNlabel, "Search for:  ");num_args++;
398   XtSetArg(args[num_args], XtNleft, XtChainLeft); num_args++;
399   XtSetArg(args[num_args], XtNright, XtChainLeft); num_args++;
400   XtSetArg(args[num_args], XtNborderWidth, 0 ); num_args++;
401   s_label = XtCreateManagedWidget("searchLabel", labelWidgetClass,
402                                   form, args, num_args);
403
404   num_args = 0;
405   XtSetArg(args[num_args], XtNfromVert, search->left_toggle); num_args++;
406   XtSetArg(args[num_args], XtNfromHoriz, s_label); num_args++;
407   XtSetArg(args[num_args], XtNleft, XtChainLeft); num_args++;
408   XtSetArg(args[num_args], XtNright, XtChainRight); num_args++;
409   XtSetArg(args[num_args], XtNeditType, XawtextEdit); num_args++;
410   XtSetArg(args[num_args], XtNresizable, TRUE); num_args++;
411   XtSetArg(args[num_args], XtNresize, XawtextResizeWidth); num_args++;
412   XtSetArg(args[num_args], XtNstring, ptr); num_args++;
413   s_text = XtCreateManagedWidget("searchText", asciiTextWidgetClass, form,
414                                  args, num_args);
415   search->search_text = s_text;
416
417   num_args = 0;
418   XtSetArg(args[num_args], XtNlabel, "Search"); num_args++;
419   XtSetArg(args[num_args], XtNfromVert, s_text); num_args++;
420   XtSetArg(args[num_args], XtNleft, XtChainLeft); num_args++;
421   XtSetArg(args[num_args], XtNright, XtChainLeft); num_args++;
422   search_button = XtCreateManagedWidget("search", commandWidgetClass, form,
423                                         args, num_args);
424
425   num_args = 0;
426   XtSetArg(args[num_args], XtNlabel, "Cancel"); num_args++;
427   XtSetArg(args[num_args], XtNfromVert, s_text); num_args++;
428   XtSetArg(args[num_args], XtNfromHoriz, search_button); num_args++;
429   XtSetArg(args[num_args], XtNleft, XtChainLeft); num_args++;
430   XtSetArg(args[num_args], XtNright, XtChainLeft); num_args++;
431   cancel = XtCreateManagedWidget(DISMISS_NAME, commandWidgetClass, form,
432                                  args, num_args);
433
434   XtAddCallback(search_button, XtNcallback, SearchButton, (XtPointer) search);
435   XtAddCallback(cancel, XtNcallback, PopdownSearch, (XtPointer) search);
436
437 /*
438  * Initialize the text entry fields.
439  */
440
441   SetSearchLabels(search, "Search", "", FALSE);
442   XtSetKeyboardFocus(form, search->search_text);
443
444 /*
445  * Bind Extra translations.
446  */
447
448   trans = XtParseTranslationTable(search_text_trans);
449   XtOverrideTranslations(search->search_text, trans);
450 }
451
452 /*      Function Name: DoSearch
453  *      Description: Performs a search.
454  *      Arguments: search - the serach structure.
455  *      Returns: TRUE if sucessful.
456  */
457
458 /* ARGSUSED */
459 static Boolean
460 DoSearch(search)
461 struct SearchAndReplace * search;
462 {
463   char msg[BUFSIZ];
464   Widget tw = XtParent(search->search_popup);
465   XawTextPosition pos;
466   XawTextScanDirection dir;
467   XawTextBlock text;
468
469   text.ptr = GetString(search->search_text);
470   text.length = strlen(text.ptr);
471   text.firstPos = 0;
472   text.format = FMT8BIT;
473
474   dir = (XawTextScanDirection)(int) ((caddr_t)XawToggleGetCurrent(search->left_toggle) -
475                                 R_OFFSET);
476
477   pos = XawTextSearch( tw, dir, &text);
478
479   if (pos == XawTextSearchError)
480     sprintf( msg, "Could not find string '%s'.", text.ptr);
481   else {
482     if (dir == XawsdRight)
483       XawTextSetInsertionPoint( tw, pos + text.length);
484     else
485       XawTextSetInsertionPoint( tw, pos);
486
487     XawTextSetSelection( tw, pos, pos + text.length);
488     search->selection_changed = FALSE; /* selection is good. */
489     return(TRUE);
490   }
491
492   XawTextUnsetSelection(tw);
493   SetSearchLabels(search, msg, "", TRUE);
494   return(FALSE);
495 }
496
497
498 /*      Function Name: SetSearchLabels
499  *      Description: Sets both the search labels, and also rings the bell
500  *  HACKED: Only one label needed now
501  *      Arguments: search - the search structure.
502  *                 msg1, msg2 - message to put in each search label.
503  *                 bell - if TRUE then ring bell.
504  *      Returns: none.
505  */
506
507 static void
508 SetSearchLabels(struct SearchAndReplace *search, String msg1, String msg2,
509   Boolean bell)
510 {
511 msg2 = msg2; /* PH - shuts compilers up */
512   (void) SetResource( search->label1, XtNlabel, (XtArgVal) msg1);
513   /* (void) SetResource( search->label2, XtNlabel, (XtArgVal) msg2); */
514   if (bell)
515     XBell(XtDisplay(search->search_popup), 0);
516 }
517
518 /************************************************************
519  *
520  * This section of the file contains utility routines used by
521  * other functions in this file.
522  *
523  ************************************************************/
524
525
526 /*      Function Name: SetResource
527  *      Description: Sets a resource in a widget
528  *      Arguments: w - the widget.
529  *                 res_name - name of the resource.
530  *                 value - the value of the resource.
531  *      Returns: none.
532  */
533
534 static void
535 SetResource(w, res_name, value)
536 Widget w;
537 char * res_name;
538 XtArgVal value;
539 {
540   Arg args[1];
541
542   XtSetArg(args[0], res_name, value);
543   XtSetValues( w, args, ONE );
544 }
545
546 /*      Function Name: GetString
547  *      Description:   Gets the value for the string in the popup.
548  *      Arguments:     text - the text widget whose string we will get.
549  *      Returns:       the string.
550  */
551
552 static String
553 GetString(text)
554 Widget text;
555 {
556   String string;
557   Arg args[1];
558
559   XtSetArg( args[0], XtNstring, &string );
560   XtGetValues( text, args, ONE );
561   return(string);
562 }
563
564 /*      Function Name: CenterWidgetOnPoint.
565  *      Description: Centers a shell widget on a point relative to
566  *                   the root window.
567  *      Arguments: w - the shell widget.
568  *                 event - event containing the location of the point
569  *      Returns: none.
570  *
571  * NOTE: The widget is not allowed to go off the screen.
572  */
573
574 static void
575 CenterWidgetOnPoint(w, event)
576 Widget w;
577 XEvent *event;
578 {
579   Arg args[3];
580   Cardinal num_args;
581   Dimension width, height, b_width;
582   Position x=0, y=0, max_x, max_y;
583
584   if (event != NULL) {
585     switch (event->type) {
586     case ButtonPress:
587     case ButtonRelease:
588       x = event->xbutton.x_root;
589       y = event->xbutton.y_root;
590       break;
591     case KeyPress:
592     case KeyRelease:
593       x = event->xkey.x_root;
594       y = event->xkey.y_root;
595       break;
596     default:
597       return;
598     }
599   }
600
601   num_args = 0;
602   XtSetArg(args[num_args], XtNwidth, &width); num_args++;
603   XtSetArg(args[num_args], XtNheight, &height); num_args++;
604   XtSetArg(args[num_args], XtNborderWidth, &b_width); num_args++;
605   XtGetValues(w, args, num_args);
606
607   width += 2 * b_width;
608   height += 2 * b_width;
609
610   x -= ( (Position) width/2 );
611   if (x < 0) x = 0;
612   if ( x > (max_x = (Position) (XtScreen(w)->width - width)) ) x = max_x;
613
614   y -= ( (Position) height/2 );
615   if (y < 0) y = 0;
616   if ( y > (max_y = (Position) (XtScreen(w)->height - height)) ) y = max_y;
617
618   num_args = 0;
619   XtSetArg(args[num_args], XtNx, x); num_args++;
620   XtSetArg(args[num_args], XtNy, y); num_args++;
621   XtSetValues(w, args, num_args);
622 }
623
624 /*      Function Name: CreateDialog
625  *      Description: Actually creates a dialog.
626  *      Arguments: parent - the parent of the dialog - the main text widget.
627  *                 ptr - initial_string for the dialog.
628  *                 name - name of the dialog.
629  *                 func - function to create the children of the dialog.
630  *      Returns: the popup shell of the dialog.
631  *
632  * NOTE:
633  *
634  * The function argument is passed the following arguements.
635  *
636  * form - the from widget that is the dialog.
637  * ptr - the initial string for the dialog's text widget.
638  * parent - the parent of the dialog - the main text widget.
639  */
640
641 static Widget
642 CreateDialog(parent, ptr, name, func)
643 Widget parent;
644 String ptr, name;
645 void (*func)();
646 {
647   Widget popup, form;
648   Arg args[5];
649   Cardinal num_args;
650
651   num_args = 0;
652   XtSetArg(args[num_args], XtNiconName, name); num_args++;
653   XtSetArg(args[num_args], XtNgeometry, NULL); num_args++;
654   XtSetArg(args[num_args], XtNallowShellResize, TRUE); num_args++;
655   XtSetArg(args[num_args], XtNtransientFor, GetShell(parent)); num_args++;
656   popup = XtCreatePopupShell(name, transientShellWidgetClass,
657                              parent, args, num_args);
658
659   form = XtCreateManagedWidget(FORM_NAME, formWidgetClass, popup,
660                                NULL, ZERO);
661
662   (*func) (form, ptr, parent);
663   return(popup);
664 }
665
666  /*     Function Name: GetShell
667   *     Description: Walks up the widget hierarchy to find the
668   *             nearest shell widget.
669   *     Arguments: w - the widget whose parent shell should be returned.
670   *     Returns: The shell widget among the ancestors of w that is the
671   *             fewest levels up in the widget hierarchy.
672   */
673
674 static Widget
675 GetShell(w)
676 Widget w;
677 {
678     while ((w != NULL) && !XtIsShell(w))
679         w = XtParent(w);
680
681     return (w);
682 }
683
684 /* Add proper prototype to keep IRIX 6 compiler happy. PH */
685
686 static Boolean InParams(String, String *, Cardinal);
687
688 static Boolean InParams(str, p, n)
689     String str;
690     String *p;
691     Cardinal n;
692 {
693     int i;
694     for (i=0; i < n; p++, i++)
695         if (! XmuCompareISOLatin1(*p, str)) return True;
696     return False;
697 }
698
699 static char *WM_DELETE_WINDOW = "WM_DELETE_WINDOW";
700
701 static void WMProtocols(w, event, params, num_params)
702     Widget w;           /* popup shell */
703     XEvent *event;
704     String *params;
705     Cardinal *num_params;
706 {
707     Atom wm_delete_window;
708     Atom wm_protocols;
709
710     wm_delete_window = XInternAtom(XtDisplay(w), WM_DELETE_WINDOW, True);
711     wm_protocols = XInternAtom(XtDisplay(w), "WM_PROTOCOLS", True);
712
713     /* Respond to a recognized WM protocol request iff
714      * event type is ClientMessage and no parameters are passed, or
715      * event type is ClientMessage and event data is matched to parameters, or
716      * event type isn't ClientMessage and parameters make a request.
717      */
718 #define DO_DELETE_WINDOW InParams(WM_DELETE_WINDOW, params, *num_params)
719
720     if ((event->type == ClientMessage &&
721          event->xclient.message_type == wm_protocols &&
722          event->xclient.data.l[0] == wm_delete_window &&
723          (*num_params == 0 || DO_DELETE_WINDOW))
724         ||
725         (event->type != ClientMessage && DO_DELETE_WINDOW)) {
726
727 #undef DO_DELETE_WINDOW
728
729         Widget cancel;
730         char descendant[DISMISS_NAME_LEN + 2];
731         sprintf(descendant, "*%s", DISMISS_NAME);
732         cancel = XtNameToWidget(w, descendant);
733         if (cancel) XtCallCallbacks(cancel, XtNcallback, (XtPointer)NULL);
734     }
735 }
736
737 static void SetWMProtocolTranslations(w)
738     Widget      w;      /* realized popup shell */
739 {
740     int i;
741     XtAppContext app_context;
742     Atom wm_delete_window;
743     static XtTranslations compiled_table;       /* initially 0 */
744     static XtAppContext *app_context_list;      /* initially 0 */
745     static Cardinal list_size;                  /* initially 0 */
746
747     app_context = XtWidgetToApplicationContext(w);
748
749     /* parse translation table once */
750     if (! compiled_table) compiled_table = XtParseTranslationTable
751         ("<Message>WM_PROTOCOLS: XawWMProtocols()\n");
752
753     /* add actions once per application context */
754     for (i=0; i < list_size && app_context_list[i] != app_context; i++) ;
755     if (i == list_size) {
756         XtActionsRec actions[1];
757         actions[0].string = "XawWMProtocols";
758         actions[0].proc = WMProtocols;
759         list_size++;
760         app_context_list = (XtAppContext *) XtRealloc
761             ((char *)app_context_list, list_size * sizeof(XtAppContext));
762         XtAppAddActions(app_context, actions, 1);
763         app_context_list[i] = app_context;
764     }
765
766     /* establish communication between the window manager and each shell */
767     XtAugmentTranslations(w, compiled_table);
768     wm_delete_window = XInternAtom(XtDisplay(w), WM_DELETE_WINDOW, False);
769     (void) XSetWMProtocols(XtDisplay(w), XtWindow(w), &wm_delete_window, 1);
770 }