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