4775c25d05e00ab4ce64f8cfafab2246f53fc2a3
[framework/uifw/xorg/lib/libxaw.git] / src / TextPop.c
1 /*
2
3 Copyright 1989, 1994, 1998  The Open Group
4
5 Permission to use, copy, modify, distribute, and sell this software and its
6 documentation for any purpose is hereby granted without fee, provided that
7 the above copyright notice appear in all copies and that both that
8 copyright notice and this permission notice appear in supporting
9 documentation.
10
11 The above copyright notice and this permission notice shall be included in
12 all copies or substantial portions of the Software.
13
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
17 OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
18 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20
21 Except as contained in this notice, the name of The Open Group shall not be
22 used in advertising or otherwise to promote the sale, use or other dealings
23 in this Software without prior written authorization from The Open Group.
24
25 */
26
27 /*
28  * This file is broken up into three sections one dealing with
29  * each of the three popups created here:
30  *
31  * FileInsert, Search, and Replace.
32  *
33  * There is also a section at the end for utility functions 
34  * used by all more than one of these dialogs.
35  *
36  * The following functions are the only non-static ones defined
37  * in this module.  They are located at the begining of the
38  * section that contains this dialog box that uses them.
39  * 
40  * void _XawTextInsertFileAction(w, event, params, num_params);
41  * void _XawTextDoSearchAction(w, event, params, num_params);
42  * void _XawTextDoReplaceAction(w, event, params, num_params);
43  * void _XawTextInsertFile(w, event, params, num_params);
44  */
45
46 #ifdef HAVE_CONFIG_H
47 #include <config.h>
48 #endif
49 #include <stdio.h>
50 #include <errno.h>
51 #include <X11/IntrinsicP.h>
52 #include <X11/StringDefs.h>
53 #include <X11/Shell.h> 
54 #include <X11/Xos.h>
55 #include <X11/Xmu/CharSet.h>
56 #include <X11/Xmu/SysUtil.h>
57 #include <X11/Xaw/TextP.h>
58 #include <X11/Xaw/AsciiText.h>
59 #include <X11/Xaw/Cardinals.h>
60 #include <X11/Xaw/Command.h>
61 #include <X11/Xaw/Form.h>
62 #include <X11/Xaw/Toggle.h>
63 #include "XawI18n.h"
64
65 static char* INSERT_FILE = "Enter Filename:";
66 static char* SEARCH_LABEL_1 = "Use <Tab> to change fields.";
67 static char* SEARCH_LABEL_2 = "Use ^q<Tab> for <Tab>.";
68 static char* DISMISS_NAME = "cancel";
69 #define DISMISS_NAME_LEN 6
70 static char* FORM_NAME = "form";
71 static char* LABEL_NAME = "label";
72 static char* TEXT_NAME = "text";
73
74 #define R_OFFSET      1
75
76 typedef void (*AddFunc)(Widget, char*, Widget);
77
78 /*
79  * Prototypes
80  */
81 static void _SetField(Widget, Widget);
82 static void AddSearchChildren(Widget, char*, Widget);
83 static void AddInsertFileChildren(Widget, char*, Widget);
84 static void CenterWidgetOnPoint(Widget, XEvent*);
85 static Widget CreateDialog(Widget, String, String, AddFunc);
86 static void DoInsert(Widget, XtPointer, XtPointer);
87 static void DoReplaceAll(Widget, XtPointer, XtPointer);
88 static void DoReplaceOne(Widget, XtPointer, XtPointer);
89 static Bool DoSearch(struct SearchAndReplace*);
90 static Widget GetShell(Widget);
91 static String GetString(Widget);
92 static String GetStringRaw(Widget);
93 static void InitializeSearchWidget(struct SearchAndReplace*,
94                                    XawTextScanDirection, Bool);
95 static Bool InParams(String, String*, unsigned int);
96 static Bool InsertFileNamed(Widget, char*);
97 static void PopdownFileInsert(Widget, XtPointer, XtPointer);
98 static void PopdownSearch(Widget, XtPointer, XtPointer);
99 static Bool Replace(struct SearchAndReplace*, Bool, Bool);
100 static void SearchButton(Widget, XtPointer, XtPointer);
101 static void SetResource(Widget, char*, XtArgVal);
102 static Bool SetResourceByName(Widget, char*, char*, XtArgVal);
103 static void SetSearchLabels(struct SearchAndReplace*, String, String, Bool);
104 static void SetWMProtocolTranslations(Widget);
105
106 /*
107  * Actions
108  */
109 static void WMProtocols(Widget, XEvent*, String*, Cardinal*);
110
111 /*
112  * External Actions
113  */
114 void _XawTextDoReplaceAction(Widget, XEvent*, String*, Cardinal*);
115 void _XawTextDoSearchAction(Widget, XEvent*, String*, Cardinal*);
116 void _XawTextInsertFile(Widget, XEvent*, String*, Cardinal*);
117 void _XawTextInsertFileAction(Widget, XEvent*, String*, Cardinal*);
118 void _XawTextPopdownSearchAction(Widget, XEvent*, String*, Cardinal*);
119 void _XawTextSearch(Widget, XEvent*, String*, Cardinal*);
120 void _XawTextSetField(Widget, XEvent*, String*, Cardinal*);
121
122 /*
123  * From Text.c
124  */
125 char *_XawTextGetText(TextWidget, XawTextPosition, XawTextPosition);
126 void _XawTextShowPosition(TextWidget);
127
128 /*
129  * Initialization
130  */
131 static char radio_trans_string[] =
132 "<Btn1Down>,<Btn1Up>:"  "set() notify()\n"
133 ;
134
135 static char search_text_trans[] = 
136 "~s<Key>Return:"        "DoSearchAction(Popdown)\n"
137 "s<Key>Return:"         "DoSearchAction() SetField(Replace)\n"
138 "c<Key>c:"              "PopdownSearchAction()\n"
139 "<Btn1Down>:"           "select-start() SetField(Search)\n"
140 "<Key>Tab:"             "DoSearchAction() SetField(Replace)\n"
141 ;
142
143 static char rep_text_trans[] = 
144 "~s<Key>Return:"        "DoReplaceAction(Popdown)\n"
145 "s<Key>Return:"         "SetField(Search)\n"
146 "c<Key>c:"              "PopdownSearchAction()\n"
147 "<Btn1Down>:"           "select-start() DoSearchAction() SetField(Replace)\n"
148 "<Key>Tab:"             "SetField(Search)\n"
149 ;
150
151 /*
152  * Implementation
153  */
154 /*
155  * This section of the file contains all the functions that 
156  * the file insert dialog box uses
157  */
158
159 /*
160  * Function:
161  *      _XawTextInsertFileAction
162  *
163  * Description:
164  *        Action routine that can be bound to dialog box's Text Widget
165  *      that will insert a file into the main Text Widget.
166  */
167 /*ARGSUSED*/
168 void 
169 _XawTextInsertFileAction(Widget w, XEvent *event,
170                          String *params, Cardinal *num_params)
171 {
172     DoInsert(w, (XtPointer)XtParent(XtParent(XtParent(w))), NULL);
173 }
174
175 /*
176  * Function:
177  *      _XawTextInsertFile
178  *
179  * Parameters:
180  *      w          - text widget
181  *      event      - X Event (used to get x and y location)
182  *      params     - parameter list
183  *      num_params - ""
184  *
185  * Description:
186  *        Action routine that can be bound to the text widget
187  *      it will popup the insert file dialog box.
188  *
189  * Note:
190  *      The parameter list may contain one entry
191  *
192  *  Entry:
193  *        This entry is optional and contains the value of the default
194  *      file to insert
195  */
196 void 
197 _XawTextInsertFile(Widget w, XEvent *event,
198                    String *params, Cardinal *num_params)
199 {
200     TextWidget ctx = (TextWidget)w;
201     char *ptr;
202     XawTextEditType edit_mode;
203     Arg args[1];
204
205     XtSetArg(args[0], XtNeditType, &edit_mode);
206     XtGetValues(ctx->text.source, args, 1);
207   
208     if (edit_mode != XawtextEdit) {
209         XBell(XtDisplay(w), 0);
210         return;
211     }
212
213     if (*num_params == 0) 
214         ptr = "";
215     else 
216         ptr = params[0];
217     
218     if (!ctx->text.file_insert) {
219         ctx->text.file_insert = CreateDialog(w, ptr, "insertFile",
220                                              AddInsertFileChildren);
221         XtRealizeWidget(ctx->text.file_insert);
222         SetWMProtocolTranslations(ctx->text.file_insert);
223     }
224
225     CenterWidgetOnPoint(ctx->text.file_insert, event);
226     XtPopup(ctx->text.file_insert, XtGrabNone);
227 }
228
229 /*
230  * Function:
231  *      PopdownFileInsert
232  *
233  * Parameters:
234  *      w         - widget that caused this action
235  *      closure   - pointer to the main text widget that popped up this dialog
236  *      call_data - (not used)
237  *
238  * Description:
239  *      Pops down the file insert button
240  */
241 /*ARGSUSED*/
242 static void 
243 PopdownFileInsert(Widget w, XtPointer closure, XtPointer call_data)
244 {
245     TextWidget ctx = (TextWidget)closure;
246
247     XtPopdown(ctx->text.file_insert);
248     (void)SetResourceByName(ctx->text.file_insert, LABEL_NAME,
249                             XtNlabel, (XtArgVal)INSERT_FILE);
250 }
251
252 /*
253  * Function:
254  *      DoInsert
255  *
256  * Parameters:
257  *      w       - widget that activated this callback
258  *      closure - pointer to the text widget to insert the file into
259  *
260  * Description:
261  *      Actually insert the file named in the text widget of the file dialog
262  */
263 /*ARGSUSED*/
264 static void 
265 DoInsert(Widget w, XtPointer closure, XtPointer call_data)
266 {
267     TextWidget ctx = (TextWidget)closure;
268     char buf[BUFSIZ], msg[BUFSIZ];
269     Widget temp_widget;
270
271     (void)XmuSnprintf(buf, sizeof(buf), "%s.%s", FORM_NAME, TEXT_NAME);
272     if ((temp_widget = XtNameToWidget(ctx->text.file_insert, buf)) == NULL) {
273         (void)strcpy(msg,
274                      "Error: Could not get text widget from file insert popup");
275     }
276     else if (InsertFileNamed((Widget)ctx, GetString(temp_widget))) {
277         PopdownFileInsert(w, closure, call_data);
278         return;
279     }
280     else
281         (void)XmuSnprintf(msg, sizeof(msg), "Error: %s", strerror(errno));
282
283     (void)SetResourceByName(ctx->text.file_insert, 
284                             LABEL_NAME, XtNlabel, (XtArgVal)msg);
285     XBell(XtDisplay(w), 0);
286 }
287
288 /*
289  * Function:
290  *      InsertFileNamed
291  *
292  * Parameters:
293  *      tw  - text widget to insert this file into
294  *      str - name of the file to insert
295  *
296  * Description:
297  *      Inserts a file into the text widget.
298  *
299  * Returns:
300  *      True if the insert was sucessful, False otherwise.
301  */
302 static Bool
303 InsertFileNamed(Widget tw, char *str)
304 {
305     FILE *file;
306     XawTextBlock text;
307     XawTextPosition pos;
308
309     if (str == NULL || strlen(str) == 0 || (file = fopen(str, "r")) == NULL)
310         return (False);
311
312     pos = XawTextGetInsertionPoint(tw);
313
314     fseek(file, 0L, 2);
315
316     text.firstPos = 0;
317     text.length = ftell(file);
318     text.ptr = XtMalloc(text.length + 1);
319     text.format = XawFmt8Bit;
320
321     fseek(file, 0L, 0);
322     if (fread(text.ptr, 1, text.length, file) != text.length)
323         XtErrorMsg("readError", "insertFileNamed", "XawError",
324                    "fread returned error", NULL, NULL);
325
326     if (XawTextReplace(tw, pos, pos, &text) != XawEditDone) {
327         XtFree(text.ptr);
328         fclose(file);
329         return (False);
330     }
331     pos += text.length;
332     XtFree(text.ptr);
333     fclose(file);
334     XawTextSetInsertionPoint(tw, pos);
335     _XawTextShowPosition((TextWidget)tw);
336
337     return (True);
338 }
339
340 /*
341  * Function:
342  *      AddInsertFileChildren
343  *
344  * Parameters:
345  *      form - form widget for the insert dialog widget
346  *      ptr  - pointer to the initial string for the Text Widget
347  *      tw   - main text widget
348  *
349  * Description:
350  *      Adds all children to the InsertFile dialog widget.
351  */
352 static void
353 AddInsertFileChildren(Widget form, char *ptr, Widget tw)
354 {
355     Arg args[10];
356     Cardinal num_args;
357     Widget label, text, cancel, insert;
358     XtTranslations trans;
359
360     num_args = 0;
361     XtSetArg(args[num_args], XtNlabel, INSERT_FILE);    num_args++;
362     XtSetArg(args[num_args], XtNleft, XtChainLeft);     num_args++;
363     XtSetArg(args[num_args], XtNright, XtChainLeft);    num_args++;
364     XtSetArg(args[num_args], XtNresizable, True);       num_args++;
365     XtSetArg(args[num_args], XtNborderWidth, 0);        num_args++;
366     label = XtCreateManagedWidget(LABEL_NAME, labelWidgetClass, form,
367                                   args, num_args);
368   
369     num_args = 0;
370     XtSetArg(args[num_args], XtNfromVert, label);       num_args++;
371     XtSetArg(args[num_args], XtNleft, XtChainLeft);     num_args++;
372     XtSetArg(args[num_args], XtNright, XtChainRight);   num_args++;
373     XtSetArg(args[num_args], XtNeditType, XawtextEdit); num_args++;
374     XtSetArg(args[num_args], XtNresizable, True);       num_args++;
375     XtSetArg(args[num_args], XtNstring, ptr);           num_args++;
376     text = XtCreateManagedWidget(TEXT_NAME, asciiTextWidgetClass, form,
377                                  args, num_args);
378
379     num_args = 0;
380     XtSetArg(args[num_args], XtNlabel, "Insert File");  num_args++;
381     XtSetArg(args[num_args], XtNfromVert, text);        num_args++;
382     XtSetArg(args[num_args], XtNleft, XtChainLeft);     num_args++;
383     XtSetArg(args[num_args], XtNright, XtChainLeft);    num_args++;
384     insert = XtCreateManagedWidget("insert", commandWidgetClass, form,
385                                    args, num_args);
386
387     num_args = 0;
388     XtSetArg(args[num_args], XtNlabel, "Cancel");       num_args++;
389     XtSetArg(args[num_args], XtNfromVert, text);        num_args++;
390     XtSetArg(args[num_args], XtNfromHoriz, insert);     num_args++;
391     XtSetArg(args[num_args], XtNleft, XtChainLeft);     num_args++;
392     XtSetArg(args[num_args], XtNright, XtChainLeft);    num_args++;
393     cancel = XtCreateManagedWidget(DISMISS_NAME, commandWidgetClass, form,
394                                    args, num_args);
395
396     XtAddCallback(cancel, XtNcallback, PopdownFileInsert, (XtPointer)tw);
397     XtAddCallback(insert, XtNcallback, DoInsert, (XtPointer)tw);
398
399     XtSetKeyboardFocus(form, text);
400
401     /*
402      * Bind <CR> to insert file
403      */
404     trans = XtParseTranslationTable("<Key>Return:InsertFileAction()");
405     XtOverrideTranslations(text, trans);
406 }
407
408 /*
409  * This section of the file contains all the functions that 
410  * the search dialog box uses
411  */
412 /*
413  * Function:
414  *      _XawTextDoSearchAction
415  *
416  * Description:
417  *        Action routine that can be bound to dialog box's Text Widget that
418  *      will search for a string in the main Text Widget.
419  *
420  * Note:
421  * If the search was sucessful and the argument popdown is passed to
422  * this action routine then the widget will automatically popdown the 
423  *      search widget
424  */
425 /*ARGSUSED*/
426 void 
427 _XawTextDoSearchAction(Widget w, XEvent *event,
428                        String *params, Cardinal *num_params)
429 {
430     TextWidget tw = (TextWidget)XtParent(XtParent(XtParent(w)));
431     Bool popdown = False;
432
433     if (*num_params == 1 && (params[0][0] == 'p' || params[0][0] == 'P'))
434         popdown = True;
435     
436     if (DoSearch(tw->text.search) && popdown)
437         PopdownSearch(w, (XtPointer)tw->text.search, NULL);
438 }
439
440 /*
441  * Function:
442  *      _XawTextPopdownSearchAction
443  *
444  * Description:
445  *        Action routine that can be bound to dialog box's Text Widget that
446  *      will popdown the search widget.
447  */
448 /*ARGSUSED*/
449 void 
450 _XawTextPopdownSearchAction(Widget w, XEvent *event,
451                             String *params, Cardinal *num_params)
452 {
453     TextWidget tw = (TextWidget)XtParent(XtParent(XtParent(w)));
454
455     PopdownSearch(w, (XtPointer)tw->text.search, NULL);
456 }
457
458 /*
459  * Function:
460  *      PopdownSearch
461  *
462  * Parameters:
463  *      w         - (not used)
464  *      closure   - pointer to the search structure
465  *      call_data - (not used)
466  *
467  * Description:
468  *      Pops down the search widget and resets it
469  */
470 /*ARGSUSED*/
471 static void 
472 PopdownSearch(Widget w, XtPointer closure, XtPointer call_data)
473 {
474     struct SearchAndReplace *search = (struct SearchAndReplace *)closure;
475
476     XtPopdown(search->search_popup);
477     SetSearchLabels(search, SEARCH_LABEL_1, SEARCH_LABEL_2, False);
478 }
479
480 /*
481  * Function:
482  *      SearchButton
483  *
484  * Arguments:
485  *      w         - (not used)
486  *      closure   - pointer to the search info
487  *      call_data - (not used)
488  *
489  * Description:
490  *      Performs a search when the button is clicked.
491  */
492 /*ARGSUSED*/
493 static void 
494 SearchButton(Widget w, XtPointer closure, XtPointer call_data)
495 {
496     (void)DoSearch((struct SearchAndReplace *)closure);
497 }
498
499 /*
500  * Function:
501  *      _XawTextSearch
502  *
503  * Parameters:
504  *      w          - text widget
505  *      event      - X Event (used to get x and y location)
506  *      params     - parameter list
507  *      num_params - ""
508  *
509  * Description:
510  *        Action routine that can be bound to the text widget
511  *      it will popup the search dialog box.
512  *
513  * Note:
514  *        The parameter list contains one or two entries that may be
515  *      the following.
516  *
517  * First Entry:
518  *        The first entry is the direction to search by default.
519  *      This arguement must be specified and may have a value of
520  *      "left" or "right".
521  *
522  * Second Entry:
523  *        This entry is optional and contains the value of the default
524  *      string to search for.
525  */
526
527 #define SEARCH_HEADER   "Text Widget - Search():"
528 void 
529 _XawTextSearch(Widget w, XEvent *event, String *params, Cardinal *num_params)
530 {
531     TextWidget ctx = (TextWidget)w;
532     XawTextScanDirection dir;
533     char *ptr, buf[BUFSIZ];
534     XawTextEditType edit_mode;
535     Arg args[1];
536     wchar_t wcs[1];
537
538     if (*num_params < 1 || *num_params > 2) {
539         (void)XmuSnprintf(buf, sizeof(buf), "%s %s\n%s", SEARCH_HEADER, 
540                           "This action must have only", 
541                           "one or two parameters");
542         XtAppWarning(XtWidgetToApplicationContext(w), buf);
543         return;
544     }
545
546     if (*num_params == 2)
547         ptr = params[1];
548     else if (XawTextFormat(ctx, XawFmtWide)) {
549         /* This just does the equivalent of
550            ptr = ""L, a waste because params[1] isnt W aligned */
551         ptr = (char *)wcs;
552         wcs[0] = 0;
553     }
554     else
555         ptr = "";
556
557     switch(params[0][0]) {
558         case 'b':                 /* Left */
559         case 'B':
560             dir = XawsdLeft;
561             break;
562         case 'f':                 /* Right */
563         case 'F':
564             dir = XawsdRight;
565             break;
566         default:
567             (void)XmuSnprintf(buf, sizeof(buf), "%s %s\n%s", SEARCH_HEADER, 
568                               "The first parameter must be",
569                               "Either 'backward' or 'forward'");
570             XtAppWarning(XtWidgetToApplicationContext(w), buf);
571             return;
572     }
573
574     if (ctx->text.search== NULL) {
575         ctx->text.search = XtNew(struct SearchAndReplace);
576         ctx->text.search->search_popup = CreateDialog(w, ptr, "search",
577                                                       AddSearchChildren);
578         XtRealizeWidget(ctx->text.search->search_popup);
579         SetWMProtocolTranslations(ctx->text.search->search_popup);
580     }
581     else if (*num_params > 1)
582         XtVaSetValues(ctx->text.search->search_text, XtNstring, ptr, NULL);
583
584     XtSetArg(args[0], XtNeditType,&edit_mode);
585     XtGetValues(ctx->text.source, args, 1);
586
587     InitializeSearchWidget(ctx->text.search, dir, (edit_mode == XawtextEdit));
588
589     CenterWidgetOnPoint(ctx->text.search->search_popup, event);
590     XtPopup(ctx->text.search->search_popup, XtGrabNone);
591 }
592
593 /*
594  * Function:
595  *      InitializeSearchWidget
596  *
597  * Parameters:
598  *      search         - search widget structure
599  *      dir            - direction to search
600  *      replace_active - state of the sensitivity for the replace button
601  *
602  * Description:
603  *        This function initializes the search widget and
604  *                 is called each time the search widget is poped up.
605  */
606 static void
607 InitializeSearchWidget(struct SearchAndReplace *search,
608                        XawTextScanDirection dir, Bool replace_active)
609 {
610     SetResource(search->rep_one, XtNsensitive, (XtArgVal)replace_active);
611     SetResource(search->rep_all, XtNsensitive, (XtArgVal)replace_active);
612     SetResource(search->rep_label, XtNsensitive, (XtArgVal)replace_active);
613     SetResource(search->rep_text, XtNsensitive, (XtArgVal)replace_active);
614
615     switch (dir) {
616         case XawsdLeft:
617             SetResource(search->left_toggle, XtNstate, (XtArgVal)True);
618             break;
619         case XawsdRight:
620             SetResource(search->right_toggle, XtNstate, (XtArgVal)True);
621             break;
622     }
623 }  
624
625 /*
626  * Function:
627  *      AddSearchChildren
628  *
629  * Parameters:
630  *      form - form widget for the search widget
631  *      ptr  - pointer to the initial string for the Text Widget
632  *      tw   - main text widget
633  *
634  * Description:
635  *      Adds all children to the Search Dialog Widget.
636  */
637 static void
638 AddSearchChildren(Widget form, char *ptr, Widget tw)
639 {
640     Arg args[10];
641     Cardinal num_args;
642     Widget cancel, search_button, s_label, s_text, r_text;
643     XtTranslations trans;
644     struct SearchAndReplace *search = ((TextWidget)tw)->text.search;
645
646     num_args = 0;
647     XtSetArg(args[num_args], XtNleft, XtChainLeft);     num_args++;
648     XtSetArg(args[num_args], XtNright, XtChainLeft);    num_args++;
649     XtSetArg(args[num_args], XtNresizable, True);       num_args++;
650     XtSetArg(args[num_args], XtNborderWidth, 0);        num_args++;
651     search->label1 = XtCreateManagedWidget("label1", labelWidgetClass, form,
652                                            args, num_args);
653
654     num_args = 0;
655     XtSetArg(args[num_args], XtNfromVert, search->label1); num_args++;
656     XtSetArg(args[num_args], XtNleft, XtChainLeft);        num_args++;
657     XtSetArg(args[num_args], XtNright, XtChainLeft);       num_args++;
658     XtSetArg(args[num_args], XtNresizable, True);          num_args++;
659     XtSetArg(args[num_args], XtNborderWidth, 0);           num_args++;
660     search->label2 = XtCreateManagedWidget("label2", labelWidgetClass, form,
661                                            args, num_args);
662   
663     /*
664      * We need to add R_OFFSET to the radio_data, because the value zero (0)
665      * has special meaning
666      */
667     num_args = 0;
668     XtSetArg(args[num_args], XtNlabel, "Backward");        num_args++;
669     XtSetArg(args[num_args], XtNfromVert, search->label2); num_args++;
670     XtSetArg(args[num_args], XtNleft, XtChainLeft);        num_args++;
671     XtSetArg(args[num_args], XtNright, XtChainLeft);       num_args++;
672     XtSetArg(args[num_args], XtNradioData, (XPointer)XawsdLeft + R_OFFSET);
673     num_args++;
674     search->left_toggle = XtCreateManagedWidget("backwards", toggleWidgetClass,
675                                                 form, args, num_args);
676
677     num_args = 0;
678     XtSetArg(args[num_args], XtNlabel, "Forward");         num_args++;
679     XtSetArg(args[num_args], XtNfromVert, search->label2); num_args++;
680     XtSetArg(args[num_args], XtNfromHoriz, search->left_toggle); num_args++;
681     XtSetArg(args[num_args], XtNleft, XtChainLeft);        num_args++;
682     XtSetArg(args[num_args], XtNright, XtChainLeft);       num_args++;
683     XtSetArg(args[num_args], XtNradioGroup, search->left_toggle); num_args++;
684     XtSetArg(args[num_args], XtNradioData, (XPointer)XawsdRight + R_OFFSET);
685     num_args++;
686     search->right_toggle = XtCreateManagedWidget("forwards", toggleWidgetClass,
687                                                  form, args, num_args);
688
689     {
690         XtTranslations radio_translations;
691
692         radio_translations = XtParseTranslationTable(radio_trans_string);
693         XtOverrideTranslations(search->left_toggle, radio_translations);
694         XtOverrideTranslations(search->right_toggle, radio_translations);
695     }
696
697 #ifndef OLDXAW
698     if (XawTextFormat((TextWidget)tw, XawFmt8Bit)) {
699         num_args = 0;
700         XtSetArg(args[num_args], XtNlabel, "Case Sensitive");   num_args++;
701         XtSetArg(args[num_args], XtNfromVert, search->label2);  num_args++;
702         XtSetArg(args[num_args], XtNfromHoriz, search->right_toggle); num_args++;
703         XtSetArg(args[num_args], XtNleft, XtChainLeft);         num_args++;
704         XtSetArg(args[num_args], XtNright, XtChainLeft);        num_args++;
705         XtSetArg(args[num_args], XtNstate, True);               num_args++;
706         search->case_sensitive = XtCreateManagedWidget("case", toggleWidgetClass,
707                                                        form, args, num_args);
708     }
709     else
710         search->case_sensitive = NULL;
711 #endif
712
713     num_args = 0;
714     XtSetArg(args[num_args], XtNfromVert, search->left_toggle); num_args++;
715     XtSetArg(args[num_args], XtNlabel, "Search for:  ");        num_args++;
716     XtSetArg(args[num_args], XtNleft, XtChainLeft);             num_args++;
717     XtSetArg(args[num_args], XtNright, XtChainLeft);            num_args++;
718     XtSetArg(args[num_args], XtNborderWidth, 0 );               num_args++;
719     s_label = XtCreateManagedWidget("searchLabel", labelWidgetClass, form,
720                                     args, num_args);
721
722     num_args = 0;
723     XtSetArg(args[num_args], XtNfromVert, search->left_toggle); num_args++;
724     XtSetArg(args[num_args], XtNfromHoriz, s_label);            num_args++;
725     XtSetArg(args[num_args], XtNleft, XtChainLeft);             num_args++;
726     XtSetArg(args[num_args], XtNright, XtChainRight);           num_args++;
727     XtSetArg(args[num_args], XtNeditType, XawtextEdit);         num_args++;
728     XtSetArg(args[num_args], XtNresizable, True);               num_args++;
729     XtSetArg(args[num_args], XtNstring, ptr);                   num_args++;
730     s_text = XtCreateManagedWidget("searchText", asciiTextWidgetClass, form,
731                                    args, num_args);
732     search->search_text = s_text;
733
734     num_args = 0;
735     XtSetArg(args[num_args], XtNfromVert, s_text);              num_args++;
736     XtSetArg(args[num_args], XtNlabel, "Replace with:");        num_args++;
737     XtSetArg(args[num_args], XtNleft, XtChainLeft);             num_args++;
738     XtSetArg(args[num_args], XtNright, XtChainLeft);            num_args++;
739     XtSetArg(args[num_args], XtNborderWidth, 0);                num_args++;
740     search->rep_label = XtCreateManagedWidget("replaceLabel", labelWidgetClass,
741                                               form, args, num_args);
742
743     num_args = 0;
744     XtSetArg(args[num_args], XtNfromHoriz, s_label);            num_args++;
745     XtSetArg(args[num_args], XtNfromVert, s_text);              num_args++;
746     XtSetArg(args[num_args], XtNleft, XtChainLeft);             num_args++;
747     XtSetArg(args[num_args], XtNright, XtChainRight);           num_args++;
748     XtSetArg(args[num_args], XtNeditType, XawtextEdit);         num_args++;
749     XtSetArg(args[num_args], XtNresizable, True);               num_args++;
750     XtSetArg(args[num_args], XtNstring, ""); num_args++;
751     r_text = XtCreateManagedWidget("replaceText", asciiTextWidgetClass,
752                                    form, args, num_args);
753     search->rep_text = r_text;
754   
755     num_args = 0;
756     XtSetArg(args[num_args], XtNlabel, "Search");               num_args++;
757     XtSetArg(args[num_args], XtNfromVert, r_text);              num_args++;
758     XtSetArg(args[num_args], XtNleft, XtChainLeft);             num_args++;
759     XtSetArg(args[num_args], XtNright, XtChainLeft);            num_args++;
760     search_button = XtCreateManagedWidget("search", commandWidgetClass, form,
761                                           args, num_args);
762
763     num_args = 0;
764     XtSetArg(args[num_args], XtNlabel, "Replace");              num_args++;
765     XtSetArg(args[num_args], XtNfromVert, r_text);              num_args++;
766     XtSetArg(args[num_args], XtNfromHoriz, search_button);      num_args++;
767     XtSetArg(args[num_args], XtNleft, XtChainLeft);             num_args++;
768     XtSetArg(args[num_args], XtNright, XtChainLeft);            num_args++;
769     search->rep_one = XtCreateManagedWidget("replaceOne", commandWidgetClass,
770                                             form, args, num_args);
771
772     num_args = 0;
773     XtSetArg(args[num_args], XtNlabel, "Replace All");          num_args++;
774     XtSetArg(args[num_args], XtNfromVert, r_text);              num_args++;
775     XtSetArg(args[num_args], XtNfromHoriz, search->rep_one);    num_args++;
776     XtSetArg(args[num_args], XtNleft, XtChainLeft);             num_args++;
777     XtSetArg(args[num_args], XtNright, XtChainLeft);            num_args++;
778     search->rep_all = XtCreateManagedWidget("replaceAll", commandWidgetClass,
779                                             form, args, num_args);
780
781     num_args = 0;
782     XtSetArg(args[num_args], XtNlabel, "Cancel");               num_args++;
783     XtSetArg(args[num_args], XtNfromVert, r_text);              num_args++;
784     XtSetArg(args[num_args], XtNfromHoriz, search->rep_all);    num_args++;
785     XtSetArg(args[num_args], XtNleft, XtChainLeft);             num_args++;
786     XtSetArg(args[num_args], XtNright, XtChainLeft);            num_args++;
787     cancel = XtCreateManagedWidget(DISMISS_NAME, commandWidgetClass, form,
788                                    args, num_args);
789
790     XtAddCallback(search_button, XtNcallback, SearchButton, (XtPointer)search);
791     XtAddCallback(search->rep_one, XtNcallback, DoReplaceOne, (XtPointer)search);
792     XtAddCallback(search->rep_all, XtNcallback, DoReplaceAll, (XtPointer)search);
793     XtAddCallback(cancel, XtNcallback, PopdownSearch, (XtPointer)search);
794
795     /*
796      * Initialize the text entry fields
797      */
798     {
799         Pixel color;
800
801         num_args = 0;
802         XtSetArg(args[num_args], XtNbackground, &color); num_args++;
803         XtGetValues(search->rep_text, args, num_args);
804         num_args = 0;
805         XtSetArg(args[num_args], XtNborderColor, color); num_args++;
806         XtSetValues(search->rep_text, args, num_args);
807         XtSetKeyboardFocus(form, search->search_text);
808     }
809
810     SetSearchLabels(search, SEARCH_LABEL_1, SEARCH_LABEL_2, False);
811
812     /*
813      * Bind Extra translations
814      */
815     trans = XtParseTranslationTable(search_text_trans);
816     XtOverrideTranslations(search->search_text, trans);
817
818     trans = XtParseTranslationTable(rep_text_trans);
819     XtOverrideTranslations(search->rep_text, trans);
820 }
821
822 /*
823  * Function:
824  *      DoSearch
825  *
826  * Parameters:
827  *      search - search structure
828  *
829  * Description:
830  *      Performs a search
831  *
832  * Returns:
833  *      True if sucessful
834  */
835 /*ARGSUSED*/
836 static Bool
837 DoSearch(struct SearchAndReplace *search)
838 {
839     char msg[37];
840     Widget tw = XtParent(search->search_popup);
841     XawTextPosition pos;
842     XawTextScanDirection dir;
843     XawTextBlock text;
844     TextWidget ctx = (TextWidget)tw;
845
846     text.firstPos = 0;
847     text.ptr = GetStringRaw(search->search_text);
848     if ((text.format = _XawTextFormat(ctx)) == XawFmtWide)
849         text.length = wcslen((wchar_t*)text.ptr);
850     else {
851         text.length = strlen(text.ptr);
852
853 #ifndef OLDXAW
854         if (search->case_sensitive) {
855           /* text.firstPos isn't useful here, so I'll use it as an
856            * options flag.
857            */
858             Arg args[1];
859             Boolean case_sensitive;
860
861             XtSetArg(args[0], XtNstate, &case_sensitive);
862             XtGetValues(search->case_sensitive, args, 1);
863             text.firstPos = !case_sensitive;
864         }
865 #endif /* OLDXAW */
866     }
867   
868     dir = (XawTextScanDirection)(unsigned long)
869       ((XPointer)XawToggleGetCurrent(search->left_toggle) - R_OFFSET);
870
871     pos = XawTextSearch(tw, dir, &text);
872
873    /* The Raw string in find.ptr may be WC I can't use here, so I re - call 
874      GetString to get a tame version */
875
876     if (pos == XawTextSearchError) {
877         char *ptr;
878         int len;
879
880         ptr = GetString(search->search_text);
881         len = strlen(ptr);
882         (void)XmuSnprintf(msg, sizeof(msg), "%s", ptr);
883
884         ptr = strchr(msg, '\n');
885         if (ptr != NULL || sizeof(msg) - 1 < len) {
886             if (ptr != NULL)
887                 len = ptr - msg + 4;
888             else
889                 len = strlen(msg);
890
891             if (len < 4)
892                 strcpy(msg, "...");
893             else
894                 strcpy(msg + len - 4, "...");
895         }
896         XawTextUnsetSelection(tw);
897         SetSearchLabels(search, "Could not find string", msg, True);
898
899         return (False);
900     }
901     XawTextDisableRedisplay(tw);
902     XawTextSetSelection(tw, pos, pos + text.length);
903     search->selection_changed = False;  /* selection is good */
904
905     if (dir == XawsdRight)
906         XawTextSetInsertionPoint(tw, pos + text.length);
907     else
908         XawTextSetInsertionPoint(tw, pos);
909     _XawTextShowPosition(ctx);
910     XawTextEnableRedisplay(tw);
911
912     return (True);
913 }
914
915 /*
916  * This section of the file contains all the functions that 
917  * the replace dialog box uses
918  */
919 /*
920  * Function:
921  *      _XawTextDoReplaceAction
922  *
923  * Description:
924  *      Action routine that can be bound to dialog box's
925  *      Text Widget that will replace a string in the main Text Widget.
926  */
927 /*ARGSUSED*/
928 void 
929 _XawTextDoReplaceAction(Widget w, XEvent *event,
930                         String *params, Cardinal *num_params)
931 {
932     TextWidget ctx = (TextWidget)XtParent(XtParent(XtParent(w)));
933     Bool popdown = False;
934
935     if (*num_params == 1 && (params[0][0] == 'p' || params[0][0] == 'P'))
936         popdown = True;
937
938     if (Replace( ctx->text.search, True, popdown) && popdown)
939         PopdownSearch(w, (XtPointer)ctx->text.search, NULL);
940 }
941
942 /*
943  * Function:
944  *      DoReplaceOne
945  *
946  * Arguments:
947  *      w         - *** Not Used ***
948  *      closure   - a pointer to the search structure
949  *      call_data - *** Not Used ***
950  *
951  * Description:
952  *        Replaces the first instance of the string in the search
953  *      dialog's text widget with the one in the replace dialog's text widget.
954  */
955 /*ARGSUSED*/
956 static void
957 DoReplaceOne(Widget w, XtPointer closure, XtPointer call_data)
958 {
959     Replace((struct SearchAndReplace *)closure, True, False);
960 }
961
962 /*
963  * Function:
964  *      DoReplaceAll
965  *
966  * Parameters:
967  *      w         - (not used)
968  *      closure   - pointer to the search structure
969  *      call_data - (not used)
970  *
971  * Description: 
972  *        Replaces every instance of the string in the search dialog's
973  *      text widget with the one in the replace dialog's text widget.
974  */
975 /*ARGSUSED*/
976 static void 
977 DoReplaceAll(Widget w, XtPointer closure, XtPointer call_data)
978 {
979     Replace((struct SearchAndReplace *)closure, False, False);
980 }
981
982 /*
983  * Function:
984  *      Replace
985  *
986  * Parameters:
987  *      tw            - Text Widget to replce the string in
988  *      once_only     - if True then only replace the first one found,
989  *                      else replace all of them
990  *      show_current  - if true then leave the selection on the
991  *                      string that was just replaced, otherwise
992  *                      move it onto the next one
993  *
994  * Description:
995  *        This is the function that does the real work of
996  *      replacing strings in the main text widget.
997  */
998 static Bool
999 Replace(struct SearchAndReplace *search, Bool once_only, Bool show_current)
1000 {
1001     XawTextPosition pos, new_pos, end_pos, ipos;
1002     XawTextScanDirection dir;
1003     XawTextBlock find, replace;
1004     Widget tw = XtParent(search->search_popup);
1005     int count = 0;
1006     TextWidget ctx = (TextWidget)tw;
1007     Bool redisplay;
1008
1009     find.ptr = GetStringRaw(search->search_text);
1010     if ((find.format = _XawTextFormat(ctx)) == XawFmtWide)
1011         find.length = (XawTextPosition)wcslen((wchar_t*)find.ptr);
1012     else
1013         find.length = (XawTextPosition)strlen(find.ptr);
1014     find.firstPos = 0;
1015
1016     replace.ptr = GetStringRaw(search->rep_text);
1017     replace.firstPos = 0;
1018     if ((replace.format = _XawTextFormat(ctx)) == XawFmtWide)
1019         replace.length = wcslen((wchar_t*)replace.ptr);
1020     else
1021         replace.length = strlen(replace.ptr);
1022     
1023     dir = (XawTextScanDirection)(unsigned long)
1024       ((XPointer)XawToggleGetCurrent(search->left_toggle) - R_OFFSET);
1025
1026     redisplay = !once_only || (once_only && !show_current);
1027     ipos = XawTextGetInsertionPoint(tw);
1028     if (redisplay)
1029         XawTextDisableRedisplay(tw);
1030     /*CONSTCOND*/
1031     while (True) {
1032         if (count != 0) {
1033             new_pos = XawTextSearch(tw, dir, &find);
1034
1035             if (new_pos == XawTextSearchError) {
1036                 if (count == 0) {
1037                     char msg[37];
1038                     char *ptr;
1039                     int len;
1040
1041                     ptr = GetString(search->search_text);
1042                     len = strlen(ptr);
1043                     (void)XmuSnprintf(msg, sizeof(msg), "%s", ptr);
1044                     ptr = strchr(msg, '\n');
1045                     if (ptr != NULL || sizeof(msg) - 1 < len) {
1046                         if (ptr != NULL)
1047                             len = ptr - msg + 4;
1048                         else
1049                             len = strlen(msg);
1050
1051                         if (len < 4)
1052                             strcpy(msg, "...");
1053                         else
1054                             strcpy(msg + len - 4, "...");
1055                     }
1056                     SetSearchLabels(search, "Could not find string", msg, True);
1057
1058                     if (redisplay) {
1059                         XawTextSetInsertionPoint(tw, ipos);
1060                         _XawTextShowPosition(ctx);
1061                         XawTextEnableRedisplay(tw);
1062                     }
1063
1064                     return (False);
1065                 }
1066                 else
1067                     break;
1068             }
1069             pos = new_pos;
1070             end_pos = pos + find.length;
1071         }
1072         else {
1073             XawTextGetSelectionPos(tw, &pos, &end_pos);
1074
1075             if (search->selection_changed) {
1076                 SetSearchLabels(search, "Selection modified, aborting.",
1077                                 "", True);
1078                 if (redisplay) {
1079                     XawTextSetInsertionPoint(tw, ipos);
1080                     XawTextEnableRedisplay(tw);
1081                 }
1082
1083                 return (False);
1084             }
1085             if (pos == end_pos) {
1086                 if (redisplay) {
1087                     XawTextSetInsertionPoint(tw, ipos);
1088                     XawTextEnableRedisplay(tw);
1089                 }
1090
1091                 return (False);
1092             }
1093         }
1094
1095         if (XawTextReplace(tw, pos, end_pos, &replace) != XawEditDone) {
1096             SetSearchLabels(search, "Error while replacing.", "", True);
1097             if (redisplay) {
1098                 XawTextSetInsertionPoint(tw, ipos);
1099                 XawTextEnableRedisplay(tw);
1100             }
1101
1102             return (False);
1103         }
1104
1105         if (dir == XawsdRight)
1106             ipos = pos + replace.length;
1107         else
1108             ipos = pos;
1109
1110         if (once_only) {
1111             if (show_current)
1112                 break;
1113             else {
1114                 DoSearch(search);
1115                 XawTextEnableRedisplay(tw);
1116
1117                 return (True);
1118             }
1119         }
1120         else
1121             ctx->text.insertPos = ipos;
1122         count++;
1123     }
1124
1125     if (replace.length == 0)
1126         XawTextUnsetSelection(tw);
1127     else
1128         XawTextSetSelection(tw, pos, pos + replace.length);
1129
1130     XawTextSetInsertionPoint(tw, ipos);
1131     _XawTextShowPosition(ctx);
1132     XawTextEnableRedisplay(tw);
1133
1134     return (True);
1135 }
1136
1137 /*
1138  * Function:
1139  *      SetSearchLabels
1140  *
1141  * Parameters:
1142  *      search - search structure
1143  *      msg1   - message to put in each search label
1144  *      msg2   - ""
1145  *      bell   - if True then ring bell
1146  *
1147  * Description:
1148  *      Sets both the search labels, and also rings the bell.
1149  */
1150 static void
1151 SetSearchLabels(struct SearchAndReplace *search, String msg1, String msg2,
1152                 Bool bell)
1153 {
1154     (void)SetResource(search->label1, XtNlabel, (XtArgVal)msg1);
1155     (void)SetResource(search->label2, XtNlabel, (XtArgVal)msg2);
1156     if (bell) 
1157         XBell(XtDisplay(search->search_popup), 0);
1158 }
1159
1160 /*
1161  * This section of the file contains utility routines used by
1162  * other functions in this file
1163  */
1164 /*
1165  * Function:
1166  *      _XawTextSetField
1167  *
1168  * Description:
1169  *        Action routine that can be bound to dialog box's
1170  *                 Text Widget that will send input to the field specified.
1171  */
1172 /*ARGSUSED*/
1173 void 
1174 _XawTextSetField(Widget w, XEvent *event, String *params, Cardinal *num_params)
1175 {
1176     struct SearchAndReplace *search;
1177     Widget cnew, old;
1178
1179     search = ((TextWidget)XtParent(XtParent(XtParent(w))))->text.search;
1180
1181     if (*num_params != 1) {
1182         SetSearchLabels(search, "Error: SetField Action must have",
1183                         "exactly one argument", True);
1184         return;
1185     }
1186     switch (params[0][0])  {
1187         case 's':
1188         case 'S':
1189             cnew = search->search_text;
1190             old = search->rep_text;
1191             break;
1192         case 'r':
1193         case 'R':
1194             old = search->search_text;
1195             cnew = search->rep_text;
1196             break;
1197         default:
1198             SetSearchLabels(search,
1199                             "Error: SetField Action's first Argument must",
1200                             "be either 'Search' or 'Replace'", True);
1201             return;
1202     }
1203     _SetField(cnew, old);
1204 }
1205
1206 /*
1207  * Function:
1208  *      _SetField
1209  *
1210  * Parameters:
1211  *      cnew - new and old text fields
1212  *      old  - ""
1213  *
1214  * Description:
1215  *      Sets the current text field.
1216  */
1217 static void
1218 _SetField(Widget cnew, Widget old)
1219 {
1220     Arg args[2];
1221     Pixel new_border, old_border, old_bg;
1222
1223     if (!XtIsSensitive(cnew)) {
1224         XBell(XtDisplay(old), 0);       /* Don't set field to an inactive Widget */
1225         return;
1226     }
1227
1228     XtSetKeyboardFocus(XtParent(cnew), cnew);
1229                                                 
1230     XtSetArg(args[0], XtNborderColor, &old_border);
1231     XtSetArg(args[1], XtNbackground, &old_bg);
1232     XtGetValues(cnew, args, 2);
1233
1234     XtSetArg(args[0], XtNborderColor, &new_border);
1235     XtGetValues(old, args, 1);
1236
1237     if (old_border != old_bg)   /* Colors are already correct, return */
1238         return;
1239
1240     SetResource(old, XtNborderColor, (XtArgVal)old_border);
1241     SetResource(cnew, XtNborderColor, (XtArgVal)new_border);
1242 }
1243
1244 /*
1245  * Function:
1246  *      SetResourceByName
1247  *
1248  * Parameters:
1249  *      shell    - shell widget of the popup
1250  *      name     - name of the child
1251  *      res_name - name of the resource
1252  *      value    - value of the resource
1253  *
1254  * Description:
1255  *        Sets a resource in any of the dialog children given
1256  *      name of the child and the shell widget of the dialog.
1257  *
1258  * Returns:
1259  *      True if sucessful
1260  */
1261 static Bool
1262 SetResourceByName(Widget shell, char *name, char *res_name, XtArgVal value)
1263 {
1264     Widget temp_widget;
1265     char buf[BUFSIZ];
1266
1267     (void)XmuSnprintf(buf, sizeof(buf), "%s.%s", FORM_NAME, name);
1268
1269     if ((temp_widget = XtNameToWidget(shell, buf)) != NULL) {
1270         SetResource(temp_widget, res_name, value);
1271         return (True);
1272     }
1273     return (False);
1274 }
1275
1276 /*
1277  * Function:
1278  *      SetResource
1279  *
1280  * Parameters:
1281  *      w        - widget
1282  *      res_name - name of the resource
1283  *      value    - value of the resource
1284  *
1285  * Description:
1286  *      Sets a resource in a widget
1287  */
1288 static void
1289 SetResource(Widget w, char *res_name, XtArgVal value)
1290 {
1291     Arg args[1];
1292   
1293     XtSetArg(args[0], res_name, value);
1294     XtSetValues( w, args, 1);
1295 }
1296
1297 /*
1298  * Function:
1299  *      GetString{Raw}
1300  *
1301  * Parameters:
1302  *      text - text widget whose string we will get
1303  * 
1304  * Description:
1305  *      Gets the value for the string in the popup.
1306  *
1307  * Returns:
1308  *      GetString:      the string as a MB
1309  *      GetStringRaw:   the exact buffer contents suitable for a search
1310  */
1311 static String
1312 GetString(Widget text)
1313 {
1314     String string;
1315     Arg args[1];
1316
1317     XtSetArg(args[0], XtNstring, &string);
1318     XtGetValues(text, args, 1);
1319
1320     return (string);
1321 }
1322
1323 static String
1324 GetStringRaw(Widget tw)
1325 {
1326     TextWidget ctx = (TextWidget)tw;
1327     XawTextPosition last;
1328
1329     last = XawTextSourceScan(ctx->text.source, 0, XawstAll, XawsdRight,
1330                              ctx->text.mult, True);
1331     return (_XawTextGetText(ctx, 0, last));
1332 }
1333
1334 /*
1335  * Function:
1336  *      CenterWidgetOnPoint
1337  *
1338  * Parameters:
1339  *      w     - shell widget
1340  *               event - event containing the location of the point
1341  *
1342  * Description:
1343  *      Centers a shell widget on a point relative to the root window.
1344  *
1345  * Note:
1346  *      The widget is not allowed to go off the screen
1347  */
1348 static void
1349 CenterWidgetOnPoint(Widget w, XEvent *event)
1350 {
1351     Arg args[3];
1352     Cardinal num_args;
1353     Dimension width, height, b_width;
1354     Position x, y, max_x, max_y;
1355   
1356     if (event != NULL) {
1357         switch (event->type) {
1358             case ButtonPress:
1359             case ButtonRelease:
1360                 x = event->xbutton.x_root;
1361                 y = event->xbutton.y_root;
1362                 break;
1363             case KeyPress:
1364             case KeyRelease:
1365                 x = event->xkey.x_root;
1366                 y = event->xkey.y_root;
1367                 break;
1368             default:
1369                 return;
1370         }
1371     }
1372     else
1373         return;
1374
1375     num_args = 0;
1376     XtSetArg(args[num_args], XtNwidth, &width); num_args++;
1377     XtSetArg(args[num_args], XtNheight, &height); num_args++;
1378     XtSetArg(args[num_args], XtNborderWidth, &b_width); num_args++;
1379     XtGetValues(w, args, num_args);
1380
1381     width += b_width << 1;
1382     height += b_width << 1;
1383
1384     x -= (Position)(width >> 1);
1385     if (x < 0)
1386         x = 0;
1387     if (x > (max_x = (Position)(XtScreen(w)->width - width)))
1388         x = max_x;
1389
1390     y -= (Position)(height >> 1);
1391     if (y < 0)
1392         y = 0;
1393     if (y > (max_y = (Position)(XtScreen(w)->height - height)))
1394         y = max_y;
1395   
1396     num_args = 0;
1397     XtSetArg(args[num_args], XtNx, x); num_args++;
1398     XtSetArg(args[num_args], XtNy, y); num_args++;
1399     XtSetValues(w, args, num_args);
1400 }
1401
1402 /*
1403  * Function:
1404  *      CreateDialog
1405  *
1406  * Parameters:
1407  *      parent - parent of the dialog - the main text widget
1408  *      ptr    - initial_string for the dialog
1409  *      name   - name of the dialog
1410  *      func   - function to create the children of the dialog
1411  *
1412  * Returns:
1413  *      Popup shell of the dialog
1414  *
1415  * Note:
1416  *      The function argument is passed the following arguments:
1417  *      form   - from widget that is the dialog
1418  *      ptr    - initial string for the dialog's text widget
1419  *      parent - parent of the dialog - the main text widget
1420  */
1421 static Widget
1422 CreateDialog(Widget parent, String ptr, String name, AddFunc func)
1423 {
1424     Widget popup, form;
1425     Arg args[5];
1426     Cardinal num_args;
1427
1428     num_args = 0;
1429     XtSetArg(args[num_args], XtNiconName, name);                num_args++;
1430     XtSetArg(args[num_args], XtNgeometry, NULL);                num_args++;
1431     XtSetArg(args[num_args], XtNallowShellResize, True);        num_args++;
1432     XtSetArg(args[num_args], XtNtransientFor, GetShell(parent));num_args++;
1433     popup = XtCreatePopupShell(name, transientShellWidgetClass, 
1434                                parent, args, num_args);
1435
1436     form = XtCreateManagedWidget(FORM_NAME, formWidgetClass, popup, NULL, 0);
1437     XtManageChild (form);
1438
1439     (*func)(form, ptr, parent);
1440
1441     return (popup);
1442 }
1443
1444 /*
1445  * Function
1446  *      GetShell
1447  *      nearest shell widget.
1448  *
1449  * Parameters:
1450  *      w - widget whose parent shell should be returned
1451  *
1452  * Returns:
1453  *        The shell widget among the ancestors of w that is the
1454  *      fewest levels up in the widget hierarchy.
1455  *
1456  * Description:
1457  *      Walks up the widget hierarchy to find the topmost shell widget.
1458  */
1459 static Widget
1460 GetShell(Widget w)
1461 {
1462     while (w != NULL && !XtIsShell(w))
1463         w = XtParent(w);
1464     
1465     return (w);
1466 }
1467
1468 static Bool
1469 InParams(String str, String *p, unsigned int n)
1470 {
1471     unsigned int i;
1472
1473     for (i = 0; i < n; p++, i++)
1474         if (!XmuCompareISOLatin1(*p, str))
1475             return (True);
1476     return (False);
1477 }
1478
1479 static char *WM_DELETE_WINDOW = "WM_DELETE_WINDOW";
1480
1481 static void
1482 WMProtocols(Widget w, XEvent *event, String *params, Cardinal *num_params)
1483 {
1484     Atom wm_delete_window;
1485     Atom wm_protocols;
1486
1487     wm_delete_window = XInternAtom(XtDisplay(w), WM_DELETE_WINDOW, True);
1488     wm_protocols = XInternAtom(XtDisplay(w), "WM_PROTOCOLS", True);
1489
1490     /* Respond to a recognized WM protocol request if
1491      * event type is ClientMessage and no parameters are passed, or
1492      * event type is ClientMessage and event data is matched to parameters, or
1493      * event type isn't ClientMessage and parameters make a request
1494      */
1495 #define DO_DELETE_WINDOW InParams(WM_DELETE_WINDOW, params, *num_params)
1496
1497     if ((event->type == ClientMessage
1498          && event->xclient.message_type == wm_protocols
1499          && event->xclient.data.l[0] == wm_delete_window
1500          && (*num_params == 0 || DO_DELETE_WINDOW))
1501         || (event->type != ClientMessage && DO_DELETE_WINDOW)) {
1502 #undef DO_DELETE_WINDOW
1503         Widget cancel;
1504         char descendant[DISMISS_NAME_LEN + 2];
1505
1506         (void)XmuSnprintf(descendant, sizeof(descendant), "*%s", DISMISS_NAME);
1507         cancel = XtNameToWidget(w, descendant);
1508         if (cancel)
1509             XtCallCallbacks(cancel, XtNcallback, NULL);
1510     }
1511 }
1512
1513 static void
1514 SetWMProtocolTranslations(Widget w)
1515 {
1516     static XtTranslations compiled_table;
1517     static XtAppContext *app_context_list;
1518     static Cardinal list_size;
1519
1520     unsigned int i;
1521     XtAppContext app_context;
1522     Atom wm_delete_window;
1523
1524     app_context = XtWidgetToApplicationContext(w);
1525
1526     /* parse translation table once */
1527     if (!compiled_table)
1528         compiled_table =
1529             XtParseTranslationTable("<Message>WM_PROTOCOLS:XawWMProtocols()\n");
1530
1531     /* add actions once per application context */
1532     for (i = 0; i < list_size && app_context_list[i] != app_context; i++)
1533         ;
1534     if (i == list_size) {
1535         XtActionsRec actions[1];
1536
1537         actions[0].string = "XawWMProtocols";
1538         actions[0].proc = WMProtocols;
1539         list_size++;
1540         app_context_list = (XtAppContext *)XtRealloc
1541             ((char *)app_context_list, list_size * sizeof(XtAppContext));
1542         XtAppAddActions(app_context, actions, 1);
1543         app_context_list[i] = app_context;
1544     }
1545
1546     /* establish communication between the window manager and each shell */
1547     XtAugmentTranslations(w, compiled_table);
1548     wm_delete_window = XInternAtom(XtDisplay(w), WM_DELETE_WINDOW, False);
1549     (void)XSetWMProtocols(XtDisplay(w), XtWindow(w), &wm_delete_window, 1);
1550 }