Merge from master into 4.next
[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 begining 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 sucessful 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: PopdownSeach
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 arguement 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 == NULL) {
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== NULL) {
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
293   XtSetArg(args[0], XtNeditType,&edit_mode);
294   XtGetValues(ctx->text.source, args, ONE);
295
296   InitializeSearchWidget(ctx->text.search, dir, (edit_mode == XawtextEdit));
297
298   CenterWidgetOnPoint(ctx->text.search->search_popup, event);
299   XtPopup(ctx->text.search->search_popup, XtGrabNone);
300 }
301
302 /*      Function Name: InitializeSearchWidget
303  *      Description: This function initializes the search widget and
304  *                   is called each time the search widget is poped up.
305  *      Arguments: search - the search widget structure.
306  *                 dir - direction to search.
307  *                 replace_active - state of the sensitivity for the
308  *                                  replace button.
309  *      Returns: none.
310  */
311
312 static void
313 InitializeSearchWidget(struct SearchAndReplace *search,
314   XawTextScanDirection dir, Boolean replace_active)
315 {
316 replace_active = replace_active; /* PH - shuts compilers up */
317
318   switch (dir) {
319   case XawsdLeft:
320     SetResource(search->left_toggle, XtNstate, (XtArgVal) TRUE);
321     break;
322   case XawsdRight:
323     SetResource(search->right_toggle, XtNstate, (XtArgVal) TRUE);
324     break;
325   default:
326     break;
327   }
328 }
329
330 /*      Function Name: AddSearchChildren
331  *      Description: Adds all children to the Search Dialog Widget.
332  *      Arguments: form - the form widget for the search widget.
333  *                 ptr - a pointer to the initial string for the Text Widget.
334  *                 tw - the main text widget.
335  *      Returns: none.
336  */
337
338 static void
339 AddSearchChildren(form, ptr, tw)
340 Widget form, tw;
341 char * ptr;
342 {
343   Arg args[10];
344   Cardinal num_args;
345   Widget cancel, search_button, s_label, s_text;
346   XtTranslations trans;
347   struct SearchAndReplace * search = ((TextWidget) tw)->text.search;
348
349   num_args = 0;
350   XtSetArg(args[num_args], XtNleft, XtChainLeft); num_args++;
351   XtSetArg(args[num_args], XtNright, XtChainLeft); num_args++;
352   XtSetArg(args[num_args], XtNresizable, TRUE ); num_args++;
353   XtSetArg(args[num_args], XtNborderWidth, 0 ); num_args++;
354   search->label1 = XtCreateManagedWidget("label1", labelWidgetClass,
355                                          form, args, num_args);
356
357  /*
358  * We need to add R_OFFSET to the radio_data, because the value zero (0)
359  * has special meaning.
360  */
361
362   num_args = 0;
363   XtSetArg(args[num_args], XtNlabel, "Backward"); num_args++;
364   XtSetArg(args[num_args], XtNfromVert, search->label1); num_args++;
365   XtSetArg(args[num_args], XtNleft, XtChainLeft); num_args++;
366   XtSetArg(args[num_args], XtNright, XtChainLeft); num_args++;
367   XtSetArg(args[num_args], XtNradioData, (caddr_t) XawsdLeft + R_OFFSET);
368   num_args++;
369   search->left_toggle = XtCreateManagedWidget("backwards", toggleWidgetClass,
370                                               form, args, num_args);
371
372   num_args = 0;
373   XtSetArg(args[num_args], XtNlabel, "Forward"); num_args++;
374   XtSetArg(args[num_args], XtNfromVert, search->label1); num_args++;
375   XtSetArg(args[num_args], XtNfromHoriz, search->left_toggle); num_args++;
376   XtSetArg(args[num_args], XtNleft, XtChainLeft); num_args++;
377   XtSetArg(args[num_args], XtNright, XtChainLeft); num_args++;
378   XtSetArg(args[num_args], XtNradioGroup, search->left_toggle); num_args++;
379   XtSetArg(args[num_args], XtNradioData, (caddr_t) XawsdRight + R_OFFSET);
380   num_args++;
381   search->right_toggle = XtCreateManagedWidget("forwards", toggleWidgetClass,
382                                                form, args, num_args);
383
384   {
385     XtTranslations radio_translations;
386
387     radio_translations = XtParseTranslationTable(radio_trans_string);
388     XtOverrideTranslations(search->left_toggle, radio_translations);
389     XtOverrideTranslations(search->right_toggle, radio_translations);
390   }
391
392   num_args = 0;
393   XtSetArg(args[num_args], XtNfromVert, search->left_toggle); num_args++;
394   XtSetArg(args[num_args], XtNlabel, "Search for:  ");num_args++;
395   XtSetArg(args[num_args], XtNleft, XtChainLeft); num_args++;
396   XtSetArg(args[num_args], XtNright, XtChainLeft); num_args++;
397   XtSetArg(args[num_args], XtNborderWidth, 0 ); num_args++;
398   s_label = XtCreateManagedWidget("searchLabel", labelWidgetClass,
399                                   form, args, num_args);
400
401   num_args = 0;
402   XtSetArg(args[num_args], XtNfromVert, search->left_toggle); num_args++;
403   XtSetArg(args[num_args], XtNfromHoriz, s_label); num_args++;
404   XtSetArg(args[num_args], XtNleft, XtChainLeft); num_args++;
405   XtSetArg(args[num_args], XtNright, XtChainRight); num_args++;
406   XtSetArg(args[num_args], XtNeditType, XawtextEdit); num_args++;
407   XtSetArg(args[num_args], XtNresizable, TRUE); num_args++;
408   XtSetArg(args[num_args], XtNresize, XawtextResizeWidth); num_args++;
409   XtSetArg(args[num_args], XtNstring, ptr); num_args++;
410   s_text = XtCreateManagedWidget("searchText", asciiTextWidgetClass, form,
411                                  args, num_args);
412   search->search_text = s_text;
413
414   num_args = 0;
415   XtSetArg(args[num_args], XtNlabel, "Search"); num_args++;
416   XtSetArg(args[num_args], XtNfromVert, s_text); num_args++;
417   XtSetArg(args[num_args], XtNleft, XtChainLeft); num_args++;
418   XtSetArg(args[num_args], XtNright, XtChainLeft); num_args++;
419   search_button = XtCreateManagedWidget("search", commandWidgetClass, form,
420                                         args, num_args);
421
422   num_args = 0;
423   XtSetArg(args[num_args], XtNlabel, "Cancel"); num_args++;
424   XtSetArg(args[num_args], XtNfromVert, s_text); num_args++;
425   XtSetArg(args[num_args], XtNfromHoriz, search_button); num_args++;
426   XtSetArg(args[num_args], XtNleft, XtChainLeft); num_args++;
427   XtSetArg(args[num_args], XtNright, XtChainLeft); num_args++;
428   cancel = XtCreateManagedWidget(DISMISS_NAME, commandWidgetClass, form,
429                                  args, num_args);
430
431   XtAddCallback(search_button, XtNcallback, SearchButton, (XtPointer) search);
432   XtAddCallback(cancel, XtNcallback, PopdownSearch, (XtPointer) search);
433
434 /*
435  * Initialize the text entry fields.
436  */
437
438   SetSearchLabels(search, "Search", "", FALSE);
439   XtSetKeyboardFocus(form, search->search_text);
440
441 /*
442  * Bind Extra translations.
443  */
444
445   trans = XtParseTranslationTable(search_text_trans);
446   XtOverrideTranslations(search->search_text, trans);
447 }
448
449 /*      Function Name: DoSearch
450  *      Description: Performs a search.
451  *      Arguments: search - the serach structure.
452  *      Returns: TRUE if sucessful.
453  */
454
455 /* ARGSUSED */
456 static Boolean
457 DoSearch(search)
458 struct SearchAndReplace * search;
459 {
460   char msg[BUFSIZ];
461   Widget tw = XtParent(search->search_popup);
462   XawTextPosition pos;
463   XawTextScanDirection dir;
464   XawTextBlock text;
465
466   text.ptr = GetString(search->search_text);
467   text.length = strlen(text.ptr);
468   text.firstPos = 0;
469   text.format = FMT8BIT;
470
471   dir = (XawTextScanDirection) ((long)XawToggleGetCurrent(search->left_toggle) -
472                                 R_OFFSET);
473
474   pos = XawTextSearch( tw, dir, &text);
475
476   if (pos == XawTextSearchError)
477     sprintf( msg, "Could not find string '%s'.", text.ptr);
478   else {
479     if (dir == XawsdRight)
480       XawTextSetInsertionPoint( tw, pos + text.length);
481     else
482       XawTextSetInsertionPoint( tw, pos);
483
484     XawTextSetSelection( tw, pos, pos + text.length);
485     search->selection_changed = FALSE; /* selection is good. */
486     return(TRUE);
487   }
488
489   XawTextUnsetSelection(tw);
490   SetSearchLabels(search, msg, "", TRUE);
491   return(FALSE);
492 }
493
494
495 /*      Function Name: SetSearchLabels
496  *      Description: Sets both the search labels, and also rings the bell
497  *  HACKED: Only one label needed now
498  *      Arguments: search - the search structure.
499  *                 msg1, msg2 - message to put in each search label.
500  *                 bell - if TRUE then ring bell.
501  *      Returns: none.
502  */
503
504 static void
505 SetSearchLabels(struct SearchAndReplace *search, String msg1, String msg2,
506   Boolean bell)
507 {
508 msg2 = msg2; /* PH - shuts compilers up */
509   (void) SetResource( search->label1, XtNlabel, (XtArgVal) msg1);
510   /* (void) SetResource( search->label2, XtNlabel, (XtArgVal) msg2); */
511   if (bell)
512     XBell(XtDisplay(search->search_popup), 0);
513 }
514
515 /************************************************************
516  *
517  * This section of the file contains utility routines used by
518  * other functions in this file.
519  *
520  ************************************************************/
521
522
523 /*      Function Name: SetResource
524  *      Description: Sets a resource in a widget
525  *      Arguments: w - the widget.
526  *                 res_name - name of the resource.
527  *                 value - the value of the resource.
528  *      Returns: none.
529  */
530
531 static void
532 SetResource(w, res_name, value)
533 Widget w;
534 char * res_name;
535 XtArgVal value;
536 {
537   Arg args[1];
538
539   XtSetArg(args[0], res_name, value);
540   XtSetValues( w, args, ONE );
541 }
542
543 /*      Function Name: GetString
544  *      Description:   Gets the value for the string in the popup.
545  *      Arguments:     text - the text widget whose string we will get.
546  *      Returns:       the string.
547  */
548
549 static String
550 GetString(text)
551 Widget text;
552 {
553   String string;
554   Arg args[1];
555
556   XtSetArg( args[0], XtNstring, &string );
557   XtGetValues( text, args, ONE );
558   return(string);
559 }
560
561 /*      Function Name: CenterWidgetOnPoint.
562  *      Description: Centers a shell widget on a point relative to
563  *                   the root window.
564  *      Arguments: w - the shell widget.
565  *                 event - event containing the location of the point
566  *      Returns: none.
567  *
568  * NOTE: The widget is not allowed to go off the screen.
569  */
570
571 static void
572 CenterWidgetOnPoint(w, event)
573 Widget w;
574 XEvent *event;
575 {
576   Arg args[3];
577   Cardinal num_args;
578   Dimension width, height, b_width;
579   Position x=0, y=0, max_x, max_y;
580
581   if (event != NULL) {
582     switch (event->type) {
583     case ButtonPress:
584     case ButtonRelease:
585       x = event->xbutton.x_root;
586       y = event->xbutton.y_root;
587       break;
588     case KeyPress:
589     case KeyRelease:
590       x = event->xkey.x_root;
591       y = event->xkey.y_root;
592       break;
593     default:
594       return;
595     }
596   }
597
598   num_args = 0;
599   XtSetArg(args[num_args], XtNwidth, &width); num_args++;
600   XtSetArg(args[num_args], XtNheight, &height); num_args++;
601   XtSetArg(args[num_args], XtNborderWidth, &b_width); num_args++;
602   XtGetValues(w, args, num_args);
603
604   width += 2 * b_width;
605   height += 2 * b_width;
606
607   x -= ( (Position) width/2 );
608   if (x < 0) x = 0;
609   if ( x > (max_x = (Position) (XtScreen(w)->width - width)) ) x = max_x;
610
611   y -= ( (Position) height/2 );
612   if (y < 0) y = 0;
613   if ( y > (max_y = (Position) (XtScreen(w)->height - height)) ) y = max_y;
614
615   num_args = 0;
616   XtSetArg(args[num_args], XtNx, x); num_args++;
617   XtSetArg(args[num_args], XtNy, y); num_args++;
618   XtSetValues(w, args, num_args);
619 }
620
621 /*      Function Name: CreateDialog
622  *      Description: Actually creates a dialog.
623  *      Arguments: parent - the parent of the dialog - the main text widget.
624  *                 ptr - initial_string for the dialog.
625  *                 name - name of the dialog.
626  *                 func - function to create the children of the dialog.
627  *      Returns: the popup shell of the dialog.
628  *
629  * NOTE:
630  *
631  * The function argument is passed the following arguements.
632  *
633  * form - the from widget that is the dialog.
634  * ptr - the initial string for the dialog's text widget.
635  * parent - the parent of the dialog - the main text widget.
636  */
637
638 static Widget
639 CreateDialog(parent, ptr, name, func)
640 Widget parent;
641 String ptr, name;
642 void (*func)();
643 {
644   Widget popup, form;
645   Arg args[5];
646   Cardinal num_args;
647
648   num_args = 0;
649   XtSetArg(args[num_args], XtNiconName, name); num_args++;
650   XtSetArg(args[num_args], XtNgeometry, NULL); num_args++;
651   XtSetArg(args[num_args], XtNallowShellResize, TRUE); num_args++;
652   XtSetArg(args[num_args], XtNtransientFor, GetShell(parent)); num_args++;
653   popup = XtCreatePopupShell(name, transientShellWidgetClass,
654                              parent, args, num_args);
655
656   form = XtCreateManagedWidget(FORM_NAME, formWidgetClass, popup,
657                                NULL, ZERO);
658
659   (*func) (form, ptr, parent);
660   return(popup);
661 }
662
663  /*     Function Name: GetShell
664   *     Description: Walks up the widget hierarchy to find the
665   *             nearest shell widget.
666   *     Arguments: w - the widget whose parent shell should be returned.
667   *     Returns: The shell widget among the ancestors of w that is the
668   *             fewest levels up in the widget hierarchy.
669   */
670
671 static Widget
672 GetShell(w)
673 Widget w;
674 {
675     while ((w != NULL) && !XtIsShell(w))
676         w = XtParent(w);
677
678     return (w);
679 }
680
681 /* Add proper prototype to keep IRIX 6 compiler happy. PH */
682
683 static Boolean InParams(String, String *, Cardinal);
684
685 static Boolean InParams(str, p, n)
686     String str;
687     String *p;
688     Cardinal n;
689 {
690     int i;
691     for (i=0; i < n; p++, i++)
692         if (! XmuCompareISOLatin1(*p, str)) return True;
693     return False;
694 }
695
696 static char *WM_DELETE_WINDOW = "WM_DELETE_WINDOW";
697
698 static void WMProtocols(w, event, params, num_params)
699     Widget w;           /* popup shell */
700     XEvent *event;
701     String *params;
702     Cardinal *num_params;
703 {
704     Atom wm_delete_window;
705     Atom wm_protocols;
706
707     wm_delete_window = XInternAtom(XtDisplay(w), WM_DELETE_WINDOW, True);
708     wm_protocols = XInternAtom(XtDisplay(w), "WM_PROTOCOLS", True);
709
710     /* Respond to a recognized WM protocol request iff
711      * event type is ClientMessage and no parameters are passed, or
712      * event type is ClientMessage and event data is matched to parameters, or
713      * event type isn't ClientMessage and parameters make a request.
714      */
715 #define DO_DELETE_WINDOW InParams(WM_DELETE_WINDOW, params, *num_params)
716
717     if ((event->type == ClientMessage &&
718          event->xclient.message_type == wm_protocols &&
719          event->xclient.data.l[0] == wm_delete_window &&
720          (*num_params == 0 || DO_DELETE_WINDOW))
721         ||
722         (event->type != ClientMessage && DO_DELETE_WINDOW)) {
723
724 #undef DO_DELETE_WINDOW
725
726         Widget cancel;
727         char descendant[DISMISS_NAME_LEN + 2];
728         sprintf(descendant, "*%s", DISMISS_NAME);
729         cancel = XtNameToWidget(w, descendant);
730         if (cancel) XtCallCallbacks(cancel, XtNcallback, (XtPointer)NULL);
731     }
732 }
733
734 static void SetWMProtocolTranslations(w)
735     Widget      w;      /* realized popup shell */
736 {
737     int i;
738     XtAppContext app_context;
739     Atom wm_delete_window;
740     static XtTranslations compiled_table;       /* initially 0 */
741     static XtAppContext *app_context_list;      /* initially 0 */
742     static Cardinal list_size;                  /* initially 0 */
743
744     app_context = XtWidgetToApplicationContext(w);
745
746     /* parse translation table once */
747     if (! compiled_table) compiled_table = XtParseTranslationTable
748         ("<Message>WM_PROTOCOLS: XawWMProtocols()\n");
749
750     /* add actions once per application context */
751     for (i=0; i < list_size && app_context_list[i] != app_context; i++) ;
752     if (i == list_size) {
753         XtActionsRec actions[1];
754         actions[0].string = "XawWMProtocols";
755         actions[0].proc = WMProtocols;
756         list_size++;
757         app_context_list = (XtAppContext *) XtRealloc
758             ((char *)app_context_list, list_size * sizeof(XtAppContext));
759         XtAppAddActions(app_context, actions, 1);
760         app_context_list[i] = app_context;
761     }
762
763     /* establish communication between the window manager and each shell */
764     XtAugmentTranslations(w, compiled_table);
765     wm_delete_window = XInternAtom(XtDisplay(w), WM_DELETE_WINDOW, False);
766     (void) XSetWMProtocols(XtDisplay(w), XtWindow(w), &wm_delete_window, 1);
767 }