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