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