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