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