TextPop.c revision 5b16253f
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
64static _Xconst char* INSERT_FILE = "Enter Filename:";
65static _Xconst char* SEARCH_LABEL_1 = "Use <Tab> to change fields.";
66static _Xconst char* SEARCH_LABEL_2 = "Use ^q<Tab> for <Tab>.";
67static _Xconst char* DISMISS_NAME = "cancel";
68#define DISMISS_NAME_LEN 6
69static _Xconst char* FORM_NAME = "form";
70static _Xconst char* LABEL_NAME = "label";
71static _Xconst char* TEXT_NAME = "text";
72
73#define R_OFFSET      1
74
75typedef void (*AddFunc)(Widget, String, Widget);
76
77/*
78 * Prototypes
79 */
80static void _SetField(Widget, Widget);
81static void AddSearchChildren(Widget, String, Widget);
82static void AddInsertFileChildren(Widget, String, 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 _XtString GetStringRaw(Widget);
92static void InitializeSearchWidget(struct SearchAndReplace*,
93				   XawTextScanDirection, Bool);
94static Bool InParams(String, String*, unsigned int);
95static Bool InsertFileNamed(Widget, String);
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, String, XtArgVal);
101static Bool SetResourceByName(Widget, String, String, 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 _X_UNUSED,
169			 String *params _X_UNUSED, Cardinal *num_params _X_UNUSED)
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    String 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 _X_UNUSED, XtPointer closure, XtPointer call_data _X_UNUSED)
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 successful, False otherwise.
300 */
301static Bool
302InsertFileNamed(Widget tw, String 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 = (int)ftell(file);
317    text.ptr = XtMalloc((Cardinal)(text.length + 1));
318    text.format = XawFmt8Bit;
319
320    fseek(file, 0L, SEEK_SET);
321    if (fread(text.ptr, 1, (size_t)text.length, file) != (size_t)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, String 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 successful 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 _X_UNUSED,
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 _X_UNUSED,
450			    String *params _X_UNUSED, Cardinal *num_params _X_UNUSED)
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 _X_UNUSED, XtPointer closure, XtPointer call_data _X_UNUSED)
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 _X_UNUSED, XtPointer closure, XtPointer call_data _X_UNUSED)
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 argument 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    String ptr;
533    char buf[BUFSIZ];
534    XawTextEditType edit_mode;
535    Arg args[1];
536    wchar_t wcs[1];
537
538    if (*num_params < 1 || *num_params > 2) {
539	snprintf(buf, sizeof(buf), "%s %s\n%s", SEARCH_HEADER,
540		 "This action must have only",
541		 "one or two parameters");
542	XtAppWarning(XtWidgetToApplicationContext(w), buf);
543	return;
544    }
545
546    if (*num_params == 2)
547	ptr = params[1];
548    else if (XawTextFormat(ctx, XawFmtWide)) {
549	/* This just does the equivalent of
550	   ptr = ""L, a waste because params[1] isn't W aligned */
551	ptr = (char *)wcs;
552	wcs[0] = 0;
553    }
554    else
555	ptr = "";
556
557    switch(params[0][0]) {
558	case 'b':		  /* Left */
559	case 'B':
560	    dir = XawsdLeft;
561	    break;
562	case 'f':		  /* Right */
563	case 'F':
564	    dir = XawsdRight;
565	    break;
566	default:
567	    snprintf(buf, sizeof(buf), "%s %s\n%s", SEARCH_HEADER,
568		     "The first parameter must be",
569		     "Either 'backward' or 'forward'");
570	    XtAppWarning(XtWidgetToApplicationContext(w), buf);
571	    return;
572    }
573
574    if (ctx->text.search== NULL) {
575	ctx->text.search = XtNew(struct SearchAndReplace);
576	ctx->text.search->search_popup = CreateDialog(w, ptr, "search",
577						      AddSearchChildren);
578	XtRealizeWidget(ctx->text.search->search_popup);
579	SetWMProtocolTranslations(ctx->text.search->search_popup);
580    }
581    else if (*num_params > 1)
582	XtVaSetValues(ctx->text.search->search_text, XtNstring, ptr, NULL);
583
584    XtSetArg(args[0], XtNeditType,&edit_mode);
585    XtGetValues(ctx->text.source, args, 1);
586
587    InitializeSearchWidget(ctx->text.search, dir, (edit_mode == XawtextEdit));
588
589    CenterWidgetOnPoint(ctx->text.search->search_popup, event);
590    XtPopup(ctx->text.search->search_popup, XtGrabNone);
591}
592
593/*
594 * Function:
595 *	InitializeSearchWidget
596 *
597 * Parameters:
598 *	search	       - search widget structure
599 *	dir	       - direction to search
600 *	replace_active - state of the sensitivity for the replace button
601 *
602 * Description:
603 *	  This function initializes the search widget and
604 *		   is called each time the search widget is popped up.
605 */
606static void
607InitializeSearchWidget(struct SearchAndReplace *search,
608		       XawTextScanDirection dir, Bool replace_active)
609{
610    SetResource(search->rep_one, XtNsensitive, (XtArgVal)replace_active);
611    SetResource(search->rep_all, XtNsensitive, (XtArgVal)replace_active);
612    SetResource(search->rep_label, XtNsensitive, (XtArgVal)replace_active);
613    SetResource(search->rep_text, XtNsensitive, (XtArgVal)replace_active);
614
615    switch (dir) {
616	case XawsdLeft:
617	    SetResource(search->left_toggle, XtNstate, (XtArgVal)True);
618	    break;
619	case XawsdRight:
620	    SetResource(search->right_toggle, XtNstate, (XtArgVal)True);
621	    break;
622    }
623}
624
625/*
626 * Function:
627 *	AddSearchChildren
628 *
629 * Parameters:
630 *	form - form widget for the search widget
631 *	ptr  - pointer to the initial string for the Text Widget
632 *	tw   - main text widget
633 *
634 * Description:
635 *	Adds all children to the Search Dialog Widget.
636 */
637static void
638AddSearchChildren(Widget form, String ptr, Widget tw)
639{
640    Arg args[10];
641    Cardinal num_args;
642    Widget cancel, search_button, s_label, s_text, r_text;
643    XtTranslations trans;
644    struct SearchAndReplace *search = ((TextWidget)tw)->text.search;
645
646    num_args = 0;
647    XtSetArg(args[num_args], XtNleft, XtChainLeft);	num_args++;
648    XtSetArg(args[num_args], XtNright, XtChainLeft);	num_args++;
649    XtSetArg(args[num_args], XtNresizable, True);	num_args++;
650    XtSetArg(args[num_args], XtNborderWidth, 0);	num_args++;
651    search->label1 = XtCreateManagedWidget("label1", labelWidgetClass, form,
652					   args, num_args);
653
654    num_args = 0;
655    XtSetArg(args[num_args], XtNfromVert, search->label1); num_args++;
656    XtSetArg(args[num_args], XtNleft, XtChainLeft);	   num_args++;
657    XtSetArg(args[num_args], XtNright, XtChainLeft);	   num_args++;
658    XtSetArg(args[num_args], XtNresizable, True);	   num_args++;
659    XtSetArg(args[num_args], XtNborderWidth, 0);	   num_args++;
660    search->label2 = XtCreateManagedWidget("label2", labelWidgetClass, form,
661					   args, num_args);
662
663    /*
664     * We need to add R_OFFSET to the radio_data, because the value zero (0)
665     * has special meaning
666     */
667    num_args = 0;
668    XtSetArg(args[num_args], XtNlabel, "Backward");	   num_args++;
669    XtSetArg(args[num_args], XtNfromVert, search->label2); num_args++;
670    XtSetArg(args[num_args], XtNleft, XtChainLeft);	   num_args++;
671    XtSetArg(args[num_args], XtNright, XtChainLeft);	   num_args++;
672    XtSetArg(args[num_args], XtNradioData, (XPointer)XawsdLeft + R_OFFSET);
673    num_args++;
674    search->left_toggle = XtCreateManagedWidget("backwards", toggleWidgetClass,
675						form, args, num_args);
676
677    num_args = 0;
678    XtSetArg(args[num_args], XtNlabel, "Forward");	   num_args++;
679    XtSetArg(args[num_args], XtNfromVert, search->label2); num_args++;
680    XtSetArg(args[num_args], XtNfromHoriz, search->left_toggle); num_args++;
681    XtSetArg(args[num_args], XtNleft, XtChainLeft);	   num_args++;
682    XtSetArg(args[num_args], XtNright, XtChainLeft);	   num_args++;
683    XtSetArg(args[num_args], XtNradioGroup, search->left_toggle); num_args++;
684    XtSetArg(args[num_args], XtNradioData, (XPointer)XawsdRight + R_OFFSET);
685    num_args++;
686    search->right_toggle = XtCreateManagedWidget("forwards", toggleWidgetClass,
687						 form, args, num_args);
688
689    {
690	XtTranslations radio_translations;
691
692	radio_translations = XtParseTranslationTable(radio_trans_string);
693	XtOverrideTranslations(search->left_toggle, radio_translations);
694	XtOverrideTranslations(search->right_toggle, radio_translations);
695    }
696
697#ifndef OLDXAW
698    if (XawTextFormat((TextWidget)tw, XawFmt8Bit)) {
699	num_args = 0;
700	XtSetArg(args[num_args], XtNlabel, "Case Sensitive");	num_args++;
701	XtSetArg(args[num_args], XtNfromVert, search->label2);	num_args++;
702	XtSetArg(args[num_args], XtNfromHoriz, search->right_toggle); num_args++;
703	XtSetArg(args[num_args], XtNleft, XtChainLeft);		num_args++;
704	XtSetArg(args[num_args], XtNright, XtChainLeft);	num_args++;
705	XtSetArg(args[num_args], XtNstate, True);		num_args++;
706	search->case_sensitive = XtCreateManagedWidget("case", toggleWidgetClass,
707						       form, args, num_args);
708    }
709    else
710	search->case_sensitive = NULL;
711#endif
712
713    num_args = 0;
714    XtSetArg(args[num_args], XtNfromVert, search->left_toggle);	num_args++;
715    XtSetArg(args[num_args], XtNlabel, "Search for:  ");	num_args++;
716    XtSetArg(args[num_args], XtNleft, XtChainLeft);		num_args++;
717    XtSetArg(args[num_args], XtNright, XtChainLeft);		num_args++;
718    XtSetArg(args[num_args], XtNborderWidth, 0 );		num_args++;
719    s_label = XtCreateManagedWidget("searchLabel", labelWidgetClass, form,
720				    args, num_args);
721
722    num_args = 0;
723    XtSetArg(args[num_args], XtNfromVert, search->left_toggle); num_args++;
724    XtSetArg(args[num_args], XtNfromHoriz, s_label);		num_args++;
725    XtSetArg(args[num_args], XtNleft, XtChainLeft);		num_args++;
726    XtSetArg(args[num_args], XtNright, XtChainRight);		num_args++;
727    XtSetArg(args[num_args], XtNeditType, XawtextEdit);		num_args++;
728    XtSetArg(args[num_args], XtNresizable, True);		num_args++;
729    XtSetArg(args[num_args], XtNstring, ptr);			num_args++;
730    s_text = XtCreateManagedWidget("searchText", asciiTextWidgetClass, form,
731				   args, num_args);
732    search->search_text = s_text;
733
734    num_args = 0;
735    XtSetArg(args[num_args], XtNfromVert, s_text);		num_args++;
736    XtSetArg(args[num_args], XtNlabel, "Replace with:");	num_args++;
737    XtSetArg(args[num_args], XtNleft, XtChainLeft);		num_args++;
738    XtSetArg(args[num_args], XtNright, XtChainLeft);		num_args++;
739    XtSetArg(args[num_args], XtNborderWidth, 0);		num_args++;
740    search->rep_label = XtCreateManagedWidget("replaceLabel", labelWidgetClass,
741					      form, args, num_args);
742
743    num_args = 0;
744    XtSetArg(args[num_args], XtNfromHoriz, s_label);		num_args++;
745    XtSetArg(args[num_args], XtNfromVert, s_text);		num_args++;
746    XtSetArg(args[num_args], XtNleft, XtChainLeft);		num_args++;
747    XtSetArg(args[num_args], XtNright, XtChainRight);		num_args++;
748    XtSetArg(args[num_args], XtNeditType, XawtextEdit);		num_args++;
749    XtSetArg(args[num_args], XtNresizable, True);		num_args++;
750    XtSetArg(args[num_args], XtNstring, ""); num_args++;
751    r_text = XtCreateManagedWidget("replaceText", asciiTextWidgetClass,
752				   form, args, num_args);
753    search->rep_text = r_text;
754
755    num_args = 0;
756    XtSetArg(args[num_args], XtNlabel, "Search");		num_args++;
757    XtSetArg(args[num_args], XtNfromVert, r_text);		num_args++;
758    XtSetArg(args[num_args], XtNleft, XtChainLeft);		num_args++;
759    XtSetArg(args[num_args], XtNright, XtChainLeft);		num_args++;
760    search_button = XtCreateManagedWidget("search", commandWidgetClass, form,
761					  args, num_args);
762
763    num_args = 0;
764    XtSetArg(args[num_args], XtNlabel, "Replace");		num_args++;
765    XtSetArg(args[num_args], XtNfromVert, r_text);		num_args++;
766    XtSetArg(args[num_args], XtNfromHoriz, search_button);	num_args++;
767    XtSetArg(args[num_args], XtNleft, XtChainLeft);		num_args++;
768    XtSetArg(args[num_args], XtNright, XtChainLeft);		num_args++;
769    search->rep_one = XtCreateManagedWidget("replaceOne", commandWidgetClass,
770					    form, args, num_args);
771
772    num_args = 0;
773    XtSetArg(args[num_args], XtNlabel, "Replace All");		num_args++;
774    XtSetArg(args[num_args], XtNfromVert, r_text);		num_args++;
775    XtSetArg(args[num_args], XtNfromHoriz, search->rep_one);	num_args++;
776    XtSetArg(args[num_args], XtNleft, XtChainLeft);		num_args++;
777    XtSetArg(args[num_args], XtNright, XtChainLeft);		num_args++;
778    search->rep_all = XtCreateManagedWidget("replaceAll", commandWidgetClass,
779					    form, args, num_args);
780
781    num_args = 0;
782    XtSetArg(args[num_args], XtNlabel, "Cancel");		num_args++;
783    XtSetArg(args[num_args], XtNfromVert, r_text);		num_args++;
784    XtSetArg(args[num_args], XtNfromHoriz, search->rep_all);	num_args++;
785    XtSetArg(args[num_args], XtNleft, XtChainLeft);		num_args++;
786    XtSetArg(args[num_args], XtNright, XtChainLeft);		num_args++;
787    cancel = XtCreateManagedWidget(DISMISS_NAME, commandWidgetClass, form,
788				   args, num_args);
789
790    XtAddCallback(search_button, XtNcallback, SearchButton, (XtPointer)search);
791    XtAddCallback(search->rep_one, XtNcallback, DoReplaceOne, (XtPointer)search);
792    XtAddCallback(search->rep_all, XtNcallback, DoReplaceAll, (XtPointer)search);
793    XtAddCallback(cancel, XtNcallback, PopdownSearch, (XtPointer)search);
794
795    /*
796     * Initialize the text entry fields
797     */
798    {
799	Pixel color;
800
801	num_args = 0;
802	XtSetArg(args[num_args], XtNbackground, &color); num_args++;
803	XtGetValues(search->rep_text, args, num_args);
804	num_args = 0;
805	XtSetArg(args[num_args], XtNborderColor, color); num_args++;
806	XtSetValues(search->rep_text, args, num_args);
807	XtSetKeyboardFocus(form, search->search_text);
808    }
809
810    SetSearchLabels(search, SEARCH_LABEL_1, SEARCH_LABEL_2, False);
811
812    /*
813     * Bind Extra translations
814     */
815    trans = XtParseTranslationTable(search_text_trans);
816    XtOverrideTranslations(search->search_text, trans);
817
818    trans = XtParseTranslationTable(rep_text_trans);
819    XtOverrideTranslations(search->rep_text, trans);
820}
821
822/*
823 * Function:
824 *	DoSearch
825 *
826 * Parameters:
827 *	search - search structure
828 *
829 * Description:
830 *	Performs a search
831 *
832 * Returns:
833 *	True if successful
834 */
835/*ARGSUSED*/
836static Bool
837DoSearch(struct SearchAndReplace *search)
838{
839    char msg[37];
840    Widget tw = XtParent(search->search_popup);
841    XawTextPosition pos;
842    XawTextScanDirection dir;
843    XawTextBlock text;
844    TextWidget ctx = (TextWidget)tw;
845
846    text.firstPos = 0;
847    text.ptr = GetStringRaw(search->search_text);
848    if ((text.format = (unsigned long)_XawTextFormat(ctx)) == XawFmtWide)
849	text.length = (int)wcslen((wchar_t*)text.ptr);
850    else {
851	text.length = (int)strlen(text.ptr);
852
853#ifndef OLDXAW
854	if (search->case_sensitive) {
855	  /* text.firstPos isn't useful here, so I'll use it as an
856	   * options flag.
857	   */
858	    Arg args[1];
859	    Boolean case_sensitive;
860
861	    XtSetArg(args[0], XtNstate, &case_sensitive);
862	    XtGetValues(search->case_sensitive, args, 1);
863	    text.firstPos = !case_sensitive;
864	}
865#endif /* OLDXAW */
866    }
867
868    dir = (XawTextScanDirection)(unsigned long)
869      ((XPointer)XawToggleGetCurrent(search->left_toggle) - R_OFFSET);
870
871    pos = XawTextSearch(tw, dir, &text);
872
873   /* The Raw string in find.ptr may be WC I can't use here, so I re - call
874     GetString to get a tame version */
875
876    if (pos == XawTextSearchError) {
877	String ptr;
878	int len;
879
880	ptr = GetString(search->search_text);
881	len = (int)strlen(ptr);
882	snprintf(msg, sizeof(msg), "%s", ptr);
883
884	ptr = strchr(msg, '\n');
885	if (ptr != NULL || sizeof(msg) - 1 < (size_t)len) {
886	    if (ptr != NULL)
887		len = (int)(ptr - msg + 4);
888	    else
889		len = (int)strlen(msg);
890
891	    if (len < 4)
892		strcpy(msg, "...");
893	    else
894		strcpy(msg + len - 4, "...");
895	}
896	XawTextUnsetSelection(tw);
897	SetSearchLabels(search, "Could not find string", msg, True);
898
899	return (False);
900    }
901    XawTextDisableRedisplay(tw);
902    XawTextSetSelection(tw, pos, pos + text.length);
903    search->selection_changed = False;	/* selection is good */
904
905    if (dir == XawsdRight)
906	XawTextSetInsertionPoint(tw, pos + text.length);
907    else
908	XawTextSetInsertionPoint(tw, pos);
909    _XawTextShowPosition(ctx);
910    XawTextEnableRedisplay(tw);
911
912    return (True);
913}
914
915/*
916 * This section of the file contains all the functions that
917 * the replace dialog box uses
918 */
919/*
920 * Function:
921 *	_XawTextDoReplaceAction
922 *
923 * Description:
924 *	Action routine that can be bound to dialog box's
925 *	Text Widget that will replace a string in the main Text Widget.
926 */
927/*ARGSUSED*/
928void
929_XawTextDoReplaceAction(Widget w, XEvent *event _X_UNUSED,
930			String *params, Cardinal *num_params)
931{
932    TextWidget ctx = (TextWidget)XtParent(XtParent(XtParent(w)));
933    Bool popdown = False;
934
935    if (*num_params == 1 && (params[0][0] == 'p' || params[0][0] == 'P'))
936	popdown = True;
937
938    if (Replace( ctx->text.search, True, popdown) && popdown)
939	PopdownSearch(w, (XtPointer)ctx->text.search, NULL);
940}
941
942/*
943 * Function:
944 *	DoReplaceOne
945 *
946 * Arguments:
947 *	w	  - *** Not Used ***
948 *	closure   - a pointer to the search structure
949 *	call_data - *** Not Used ***
950 *
951 * Description:
952 *	  Replaces the first instance of the string in the search
953 *	dialog's text widget with the one in the replace dialog's text widget.
954 */
955/*ARGSUSED*/
956static void
957DoReplaceOne(Widget w _X_UNUSED, XtPointer closure, XtPointer call_data _X_UNUSED)
958{
959    Replace((struct SearchAndReplace *)closure, True, False);
960}
961
962/*
963 * Function:
964 *	DoReplaceAll
965 *
966 * Parameters:
967 *	w	  - (not used)
968 *	closure	  - pointer to the search structure
969 *	call_data - (not used)
970 *
971 * Description:
972 *	  Replaces every instance of the string in the search dialog's
973 *	text widget with the one in the replace dialog's text widget.
974 */
975/*ARGSUSED*/
976static void
977DoReplaceAll(Widget w _X_UNUSED, XtPointer closure, XtPointer call_data _X_UNUSED)
978{
979    Replace((struct SearchAndReplace *)closure, False, False);
980}
981
982/*
983 * Function:
984 *	Replace
985 *
986 * Parameters:
987 *	tw	      - Text Widget to replce the string in
988 *	once_only     - if True then only replace the first one found,
989 *			else replace all of them
990 *	show_current  - if true then leave the selection on the
991 *		        string that was just replaced, otherwise
992 *		        move it onto the next one
993 *
994 * Description:
995 *	  This is the function that does the real work of
996 *	replacing strings in the main text widget.
997 */
998static Bool
999Replace(struct SearchAndReplace *search, Bool once_only, Bool show_current)
1000{
1001    XawTextPosition pos, new_pos, end_pos, ipos;
1002    XawTextScanDirection dir;
1003    XawTextBlock find, replace;
1004    Widget tw = XtParent(search->search_popup);
1005    int count = 0;
1006    TextWidget ctx = (TextWidget)tw;
1007    Bool redisplay;
1008
1009    find.ptr = GetStringRaw(search->search_text);
1010    if ((find.format = (unsigned long)_XawTextFormat(ctx)) == XawFmtWide)
1011	find.length = (int)(XawTextPosition)wcslen((wchar_t*)find.ptr);
1012    else
1013	find.length = (int)(XawTextPosition)strlen(find.ptr);
1014    find.firstPos = 0;
1015
1016    replace.ptr = GetStringRaw(search->rep_text);
1017    replace.firstPos = 0;
1018    if ((replace.format = (unsigned long)_XawTextFormat(ctx)) == XawFmtWide)
1019	replace.length = (int)wcslen((wchar_t*)replace.ptr);
1020    else
1021	replace.length = (int)strlen(replace.ptr);
1022
1023    dir = (XawTextScanDirection)(unsigned long)
1024      ((XPointer)XawToggleGetCurrent(search->left_toggle) - R_OFFSET);
1025
1026    redisplay = !once_only || (once_only && !show_current);
1027    ipos = XawTextGetInsertionPoint(tw);
1028    if (redisplay)
1029	XawTextDisableRedisplay(tw);
1030    /*CONSTCOND*/
1031    while (True) {
1032	if (count != 0)	{
1033	    new_pos = XawTextSearch(tw, dir, &find);
1034
1035	    if (new_pos == XawTextSearchError) {
1036		if (count == 0) {
1037		    char msg[37];
1038		    String ptr;
1039		    int len;
1040
1041		    ptr = GetString(search->search_text);
1042		    len = (int)strlen(ptr);
1043		    snprintf(msg, sizeof(msg), "%s", ptr);
1044		    ptr = strchr(msg, '\n');
1045		    if (ptr != NULL || sizeof(msg) - 1 < (size_t)len) {
1046			if (ptr != NULL)
1047			    len = (int)(ptr - msg + 4);
1048			else
1049			    len = (int)strlen(msg);
1050
1051			if (len < 4)
1052			    strcpy(msg, "...");
1053			else
1054			    strcpy(msg + len - 4, "...");
1055		    }
1056		    SetSearchLabels(search, "Could not find string", msg, True);
1057
1058		    if (redisplay) {
1059			XawTextSetInsertionPoint(tw, ipos);
1060			_XawTextShowPosition(ctx);
1061			XawTextEnableRedisplay(tw);
1062		    }
1063
1064		    return (False);
1065		}
1066		else
1067		    break;
1068	    }
1069	    pos = new_pos;
1070	    end_pos = pos + find.length;
1071	}
1072	else {
1073	    XawTextGetSelectionPos(tw, &pos, &end_pos);
1074
1075	    if (search->selection_changed) {
1076		SetSearchLabels(search, "Selection modified, aborting.",
1077				"", True);
1078		if (redisplay) {
1079		    XawTextSetInsertionPoint(tw, ipos);
1080		    XawTextEnableRedisplay(tw);
1081		}
1082
1083		return (False);
1084	    }
1085	    if (pos == end_pos) {
1086		if (redisplay) {
1087		    XawTextSetInsertionPoint(tw, ipos);
1088		    XawTextEnableRedisplay(tw);
1089		}
1090
1091		return (False);
1092	    }
1093	}
1094
1095	if (XawTextReplace(tw, pos, end_pos, &replace) != XawEditDone) {
1096	    SetSearchLabels(search, "Error while replacing.", "", True);
1097	    if (redisplay) {
1098		XawTextSetInsertionPoint(tw, ipos);
1099		XawTextEnableRedisplay(tw);
1100	    }
1101
1102	    return (False);
1103	}
1104
1105	if (dir == XawsdRight)
1106	    ipos = pos + replace.length;
1107	else
1108	    ipos = pos;
1109
1110	if (once_only) {
1111	    if (show_current)
1112		break;
1113	    else {
1114		DoSearch(search);
1115		XawTextEnableRedisplay(tw);
1116
1117		return (True);
1118	    }
1119	}
1120	else
1121	    ctx->text.insertPos = ipos;
1122	count++;
1123    }
1124
1125    if (replace.length == 0)
1126	XawTextUnsetSelection(tw);
1127    else
1128	XawTextSetSelection(tw, pos, pos + replace.length);
1129
1130    XawTextSetInsertionPoint(tw, ipos);
1131    _XawTextShowPosition(ctx);
1132    XawTextEnableRedisplay(tw);
1133
1134    return (True);
1135}
1136
1137/*
1138 * Function:
1139 *	SetSearchLabels
1140 *
1141 * Parameters:
1142 *	search - search structure
1143 *	msg1   - message to put in each search label
1144 *	msg2   - ""
1145 *	bell   - if True then ring bell
1146 *
1147 * Description:
1148 *	Sets both the search labels, and also rings the bell.
1149 */
1150static void
1151SetSearchLabels(struct SearchAndReplace *search, String msg1, String msg2,
1152		Bool bell)
1153{
1154    (void)SetResource(search->label1, XtNlabel, (XtArgVal)msg1);
1155    (void)SetResource(search->label2, XtNlabel, (XtArgVal)msg2);
1156    if (bell)
1157	XBell(XtDisplay(search->search_popup), 0);
1158}
1159
1160/*
1161 * This section of the file contains utility routines used by
1162 * other functions in this file
1163 */
1164/*
1165 * Function:
1166 *	_XawTextSetField
1167 *
1168 * Description:
1169 *	  Action routine that can be bound to dialog box's
1170 *		   Text Widget that will send input to the field specified.
1171 */
1172/*ARGSUSED*/
1173void
1174_XawTextSetField(Widget w, XEvent *event _X_UNUSED, String *params, Cardinal *num_params)
1175{
1176    struct SearchAndReplace *search;
1177    Widget cnew, old;
1178
1179    search = ((TextWidget)XtParent(XtParent(XtParent(w))))->text.search;
1180
1181    if (*num_params != 1) {
1182	SetSearchLabels(search, "Error: SetField Action must have",
1183			"exactly one argument", True);
1184	return;
1185    }
1186    switch (params[0][0])  {
1187	case 's':
1188	case 'S':
1189	    cnew = search->search_text;
1190	    old = search->rep_text;
1191	    break;
1192	case 'r':
1193	case 'R':
1194	    old = search->search_text;
1195	    cnew = search->rep_text;
1196	    break;
1197	default:
1198	    SetSearchLabels(search,
1199			    "Error: SetField Action's first Argument must",
1200			    "be either 'Search' or 'Replace'", True);
1201	    return;
1202    }
1203    _SetField(cnew, old);
1204}
1205
1206/*
1207 * Function:
1208 *	_SetField
1209 *
1210 * Parameters:
1211 *	cnew - new and old text fields
1212 *	old  - ""
1213 *
1214 * Description:
1215 *	Sets the current text field.
1216 */
1217static void
1218_SetField(Widget cnew, Widget old)
1219{
1220    Arg args[2];
1221    Pixel new_border, old_border, old_bg;
1222
1223    if (!XtIsSensitive(cnew)) {
1224	XBell(XtDisplay(old), 0);	/* Don't set field to an inactive Widget */
1225	return;
1226    }
1227
1228    XtSetKeyboardFocus(XtParent(cnew), cnew);
1229
1230    XtSetArg(args[0], XtNborderColor, &old_border);
1231    XtSetArg(args[1], XtNbackground, &old_bg);
1232    XtGetValues(cnew, args, 2);
1233
1234    XtSetArg(args[0], XtNborderColor, &new_border);
1235    XtGetValues(old, args, 1);
1236
1237    if (old_border != old_bg)	/* Colors are already correct, return */
1238	return;
1239
1240    SetResource(old, XtNborderColor, (XtArgVal)old_border);
1241    SetResource(cnew, XtNborderColor, (XtArgVal)new_border);
1242}
1243
1244/*
1245 * Function:
1246 *	SetResourceByName
1247 *
1248 * Parameters:
1249 *	shell	 - shell widget of the popup
1250 *	name	 - name of the child
1251 *	res_name - name of the resource
1252 *	value	 - value of the resource
1253 *
1254 * Description:
1255 *	  Sets a resource in any of the dialog children given
1256 *	name of the child and the shell widget of the dialog.
1257 *
1258 * Returns:
1259 *	True if successful
1260 */
1261static Bool
1262SetResourceByName(Widget shell, String name, String res_name, XtArgVal value)
1263{
1264    Widget temp_widget;
1265    char buf[BUFSIZ];
1266
1267    snprintf(buf, sizeof(buf), "%s.%s", FORM_NAME, name);
1268
1269    if ((temp_widget = XtNameToWidget(shell, buf)) != NULL) {
1270	SetResource(temp_widget, res_name, value);
1271	return (True);
1272    }
1273    return (False);
1274}
1275
1276/*
1277 * Function:
1278 *	SetResource
1279 *
1280 * Parameters:
1281 *	w	 - widget
1282 *	res_name - name of the resource
1283 *	value	 - value of the resource
1284 *
1285 * Description:
1286 *	Sets a resource in a widget
1287 */
1288static void
1289SetResource(Widget w, String res_name, XtArgVal value)
1290{
1291    Arg args[1];
1292
1293    XtSetArg(args[0], res_name, value);
1294    XtSetValues( w, args, 1);
1295}
1296
1297/*
1298 * Function:
1299 *	GetString{Raw}
1300 *
1301 * Parameters:
1302 *	text - text widget whose string we will get
1303 *
1304 * Description:
1305 *	Gets the value for the string in the popup.
1306 *
1307 * Returns:
1308 *	GetString:	the string as a MB
1309 *	GetStringRaw:	the exact buffer contents suitable for a search
1310 */
1311static String
1312GetString(Widget text)
1313{
1314    String string;
1315    Arg args[1];
1316
1317    XtSetArg(args[0], XtNstring, &string);
1318    XtGetValues(text, args, 1);
1319
1320    return (string);
1321}
1322
1323static _XtString
1324GetStringRaw(Widget tw)
1325{
1326    TextWidget ctx = (TextWidget)tw;
1327    XawTextPosition last;
1328
1329    last = XawTextSourceScan(ctx->text.source, 0, XawstAll, XawsdRight,
1330			     ctx->text.mult, True);
1331    return (_XawTextGetText(ctx, 0, last));
1332}
1333
1334/*
1335 * Function:
1336 *	CenterWidgetOnPoint
1337 *
1338 * Parameters:
1339 *	w     - shell widget
1340 *		 event - event containing the location of the point
1341 *
1342 * Description:
1343 *	Centers a shell widget on a point relative to the root window.
1344 *
1345 * Note:
1346 *	The widget is not allowed to go off the screen
1347 */
1348static void
1349CenterWidgetOnPoint(Widget w, XEvent *event)
1350{
1351    Arg args[3];
1352    Cardinal num_args;
1353    Dimension width, height, b_width;
1354    Position x, y, max_x, max_y;
1355
1356    if (event != NULL) {
1357	switch (event->type) {
1358	    case ButtonPress:
1359	    case ButtonRelease:
1360		x = (Position)event->xbutton.x_root;
1361		y = (Position)event->xbutton.y_root;
1362		break;
1363	    case KeyPress:
1364	    case KeyRelease:
1365		x = (Position)event->xkey.x_root;
1366		y = (Position)event->xkey.y_root;
1367		break;
1368	    default:
1369		return;
1370	}
1371    }
1372    else
1373	return;
1374
1375    num_args = 0;
1376    XtSetArg(args[num_args], XtNwidth, &width); num_args++;
1377    XtSetArg(args[num_args], XtNheight, &height); num_args++;
1378    XtSetArg(args[num_args], XtNborderWidth, &b_width); num_args++;
1379    XtGetValues(w, args, num_args);
1380
1381    width = (Dimension)(width + (b_width << 1));
1382    height = (Dimension)(height + (b_width << 1));
1383
1384    x = (Position)(x - (width >> 1));
1385    if (x < 0)
1386	x = 0;
1387    if (x > (max_x = (Position)(XtScreen(w)->width - width)))
1388	x = max_x;
1389
1390    y = (Position)(y - (height >> 1));
1391    if (y < 0)
1392	y = 0;
1393    if (y > (max_y = (Position)(XtScreen(w)->height - height)))
1394	y = max_y;
1395
1396    num_args = 0;
1397    XtSetArg(args[num_args], XtNx, x); num_args++;
1398    XtSetArg(args[num_args], XtNy, y); num_args++;
1399    XtSetValues(w, args, num_args);
1400}
1401
1402/*
1403 * Function:
1404 *	CreateDialog
1405 *
1406 * Parameters:
1407 *	parent - parent of the dialog - the main text widget
1408 *	ptr    - initial_string for the dialog
1409 *	name   - name of the dialog
1410 *	func   - function to create the children of the dialog
1411 *
1412 * Returns:
1413 *	Popup shell of the dialog
1414 *
1415 * Note:
1416 *	The function argument is passed the following arguments:
1417 *	form   - from widget that is the dialog
1418 *	ptr    - initial string for the dialog's text widget
1419 *	parent - parent of the dialog - the main text widget
1420 */
1421static Widget
1422CreateDialog(Widget parent, String ptr, String name, AddFunc func)
1423{
1424    Widget popup, form;
1425    Arg args[5];
1426    Cardinal num_args;
1427
1428    num_args = 0;
1429    XtSetArg(args[num_args], XtNiconName, name);		num_args++;
1430    XtSetArg(args[num_args], XtNgeometry, NULL);		num_args++;
1431    XtSetArg(args[num_args], XtNallowShellResize, True);	num_args++;
1432    XtSetArg(args[num_args], XtNtransientFor, GetShell(parent));num_args++;
1433    popup = XtCreatePopupShell(name, transientShellWidgetClass,
1434			       parent, args, num_args);
1435
1436    form = XtCreateManagedWidget(FORM_NAME, formWidgetClass, popup, NULL, 0);
1437    XtManageChild (form);
1438
1439    (*func)(form, ptr, parent);
1440
1441    return (popup);
1442}
1443
1444/*
1445 * Function
1446 *	GetShell
1447 *	nearest shell widget.
1448 *
1449 * Parameters:
1450 *	w - widget whose parent shell should be returned
1451 *
1452 * Returns:
1453 *	  The shell widget among the ancestors of w that is the
1454 *	fewest levels up in the widget hierarchy.
1455 *
1456 * Description:
1457 *	Walks up the widget hierarchy to find the topmost shell widget.
1458 */
1459static Widget
1460GetShell(Widget w)
1461{
1462    while (w != NULL && !XtIsShell(w))
1463	w = XtParent(w);
1464
1465    return (w);
1466}
1467
1468static Bool
1469InParams(String str, String *p, unsigned int n)
1470{
1471    unsigned int i;
1472
1473    for (i = 0; i < n; p++, i++)
1474	if (!XmuCompareISOLatin1(*p, str))
1475	    return (True);
1476    return (False);
1477}
1478
1479static const char *WM_DELETE_WINDOW = "WM_DELETE_WINDOW";
1480
1481static void
1482WMProtocols(Widget w, XEvent *event, String *params, Cardinal *num_params)
1483{
1484    Atom wm_delete_window;
1485    Atom wm_protocols;
1486
1487    wm_delete_window = XInternAtom(XtDisplay(w), WM_DELETE_WINDOW, True);
1488    wm_protocols = XInternAtom(XtDisplay(w), "WM_PROTOCOLS", True);
1489
1490    /* Respond to a recognized WM protocol request if
1491     * event type is ClientMessage and no parameters are passed, or
1492     * event type is ClientMessage and event data is matched to parameters, or
1493     * event type isn't ClientMessage and parameters make a request
1494     */
1495#define DO_DELETE_WINDOW InParams(WM_DELETE_WINDOW, params, *num_params)
1496
1497    if ((event->type == ClientMessage
1498	 && event->xclient.message_type == wm_protocols
1499	 && (Atom)event->xclient.data.l[0] == wm_delete_window
1500	 && (*num_params == 0 || DO_DELETE_WINDOW))
1501	|| (event->type != ClientMessage && DO_DELETE_WINDOW)) {
1502#undef DO_DELETE_WINDOW
1503	Widget cancel;
1504	char descendant[DISMISS_NAME_LEN + 2];
1505
1506	snprintf(descendant, sizeof(descendant), "*%s", DISMISS_NAME);
1507	cancel = XtNameToWidget(w, descendant);
1508	if (cancel)
1509	    XtCallCallbacks(cancel, XtNcallback, NULL);
1510    }
1511}
1512
1513static void
1514SetWMProtocolTranslations(Widget w)
1515{
1516    static XtTranslations compiled_table;
1517    static XtAppContext *app_context_list;
1518    static Cardinal list_size;
1519
1520    unsigned int i;
1521    XtAppContext app_context;
1522    Atom wm_delete_window;
1523
1524    app_context = XtWidgetToApplicationContext(w);
1525
1526    /* parse translation table once */
1527    if (!compiled_table)
1528	compiled_table =
1529	    XtParseTranslationTable("<Message>WM_PROTOCOLS:XawWMProtocols()\n");
1530
1531    /* add actions once per application context */
1532    for (i = 0; i < list_size && app_context_list[i] != app_context; i++)
1533	;
1534    if (i == list_size) {
1535	XtActionsRec actions[1];
1536
1537	actions[0].string = "XawWMProtocols";
1538	actions[0].proc = WMProtocols;
1539	list_size++;
1540	app_context_list = (XtAppContext *)XtRealloc
1541	    ((char *)app_context_list, (Cardinal)(list_size * sizeof(XtAppContext)));
1542	XtAppAddActions(app_context, actions, 1);
1543	app_context_list[i] = app_context;
1544    }
1545
1546    /* establish communication between the window manager and each shell */
1547    XtAugmentTranslations(w, compiled_table);
1548    wm_delete_window = XInternAtom(XtDisplay(w), WM_DELETE_WINDOW, False);
1549    (void)XSetWMProtocols(XtDisplay(w), XtWindow(w), &wm_delete_window, 1);
1550}
1551