1 /***********************************************************
2 Copyright (c) The Exim Maintainers 2022
3 Copyright 1989 by the Massachusetts Institute of Technology,
4 Cambridge, Massachusetts.
5 SPDX-License-Identifier: GPL-2.0-or-later
9 Permission to use, copy, modify, and distribute this software and its
10 documentation for any purpose and without fee is hereby granted,
11 provided that the above copyright notice appear in all copies and that
12 both that copyright notice and this permission notice appear in
13 supporting documentation, and that the names of Digital or MIT not be
14 used in advertising or publicity pertaining to distribution of the
15 software without specific, written prior permission.
17 DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
18 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
19 DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
20 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
21 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
22 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
25 ******************************************************************/
28 /****************************************************************************
29 * Modified by Philip Hazel for use with Exim. The "replace" and "insert *
30 * file" features of the search facility have been removed. Also took out *
31 * the declaration of sys_errlist, as it isn't used and causes trouble on *
32 * some systems that declare it differently. September 1996. *
33 * Added the arguments into the static functions declared at the head, to *
34 * stop some compiler warnings. August 1999. *
35 * Took out the separate declarations of errno and sys_nerr at the start, *
36 * because they too aren't actually used, and the declaration causes trouble *
37 * on some systems. December 2002. *
38 ****************************************************************************/
41 /************************************************************
43 * This file is broken up into three sections one dealing with
44 * each of the three popups created here:
46 * FileInsert, Search, and Replace.
48 * There is also a section at the end for utility functions
49 * used by all more than one of these dialogs.
51 * The following functions are the only non-static ones defined
52 * in this module. They are located at the beginning of the
53 * section that contains this dialog box that uses them.
55 * void _XawTextInsertFileAction(w, event, params, num_params);
56 * void _XawTextDoSearchAction(w, event, params, num_params);
57 * void _XawTextDoReplaceAction(w, event, params, num_params);
58 * void _XawTextInsertFile(w, event, params, num_params);
60 *************************************************************/
62 #include <X11/IntrinsicP.h>
63 #include <X11/StringDefs.h>
64 #include <X11/Shell.h>
66 #include <X11/Xaw/TextP.h>
67 #include <X11/Xaw/AsciiText.h>
68 #include <X11/Xaw/Cardinals.h>
69 #include <X11/Xaw/Command.h>
70 #include <X11/Xaw/Form.h>
71 #include <X11/Xaw/Toggle.h>
72 #include <X11/Xmu/CharSet.h>
74 #include <X11/Xos.h> /* for O_RDONLY */
77 /* extern int errno, sys_nerr; */
78 /* extern char* sys_errlist[]; */
80 #define DISMISS_NAME ("cancel")
81 #define DISMISS_NAME_LEN 6
82 #define FORM_NAME ("form")
83 #define LABEL_NAME ("label")
84 #define TEXT_NAME ("text")
88 /* Argument types added by PH August 1999 */
90 static void CenterWidgetOnPoint(Widget, XEvent *);
91 static void PopdownSearch(Widget, XtPointer, XtPointer);
92 static void InitializeSearchWidget(struct SearchAndReplace *,
93 XawTextScanDirection, Boolean);
94 static void SetResource(Widget, char *, XtArgVal);
95 static void SetSearchLabels(struct SearchAndReplace *, String, String,
97 static Widget CreateDialog(Widget, String, String,
98 void (*)(Widget, char *, Widget));
99 static Widget GetShell(Widget);
100 static void SetWMProtocolTranslations(Widget w);
101 static Boolean DoSearch(struct SearchAndReplace *);
102 static String GetString(Widget);
104 static void AddSearchChildren(Widget, char *, Widget);
106 static char radio_trans_string[] =
107 "<Btn1Down>,<Btn1Up>: set() notify()";
109 static char search_text_trans[] =
110 "~Shift<Key>Return: DoSearchAction(Popdown) \n\
111 Ctrl<Key>c: PopdownSearchAction() \n\
116 /************************************************************
118 * This section of the file contains all the functions that
119 * the search dialog box uses.
121 ************************************************************/
123 /* Function Name: _XawTextDoSearchAction
124 * Description: Action routine that can be bound to dialog box's
125 * Text Widget that will search for a string in the main
127 * Arguments: (Standard Action Routine args)
132 * If the search was successful and the argument popdown is passed to
133 * this action routine then the widget will automatically popdown the
139 _XawTextDoSearchAction(w, event, params, num_params)
143 Cardinal * num_params;
145 TextWidget tw = (TextWidget) XtParent(XtParent(XtParent(w)));
146 Boolean popdown = FALSE;
148 if ( (*num_params == 1) &&
149 ((params[0][0] == 'p') || (params[0][0] == 'P')) )
152 if (DoSearch(tw->text.search) && popdown)
153 PopdownSearch(w, (XtPointer) tw->text.search, NULL);
156 /* Function Name: _XawTextPopdownSearchAction
157 * Description: Action routine that can be bound to dialog box's
158 * Text Widget that will popdown the search widget.
159 * Arguments: (Standard Action Routine args)
165 _XawTextPopdownSearchAction(w, event, params, num_params)
169 Cardinal * num_params;
171 TextWidget tw = (TextWidget) XtParent(XtParent(XtParent(w)));
173 PopdownSearch(w, (XtPointer) tw->text.search, NULL);
176 /* Function Name: PopdownSearch
177 * Description: Pops down the search widget and resets it.
178 * Arguments: w - *** NOT USED ***.
179 * closure - a pointer to the search structure.
180 * call_data - *** NOT USED ***.
186 PopdownSearch(w, closure, call_data)
191 struct SearchAndReplace * search = (struct SearchAndReplace *) closure;
193 SetSearchLabels(search, "Search", "", FALSE);
194 XtPopdown( search->search_popup );
197 /* Function Name: SearchButton
198 * Description: Performs a search when the button is clicked.
199 * Arguments: w - *** NOT USED **.
200 * closure - a pointer to the search info.
201 * call_data - *** NOT USED ***.
207 SearchButton(w, closure, call_data)
212 (void) DoSearch( (struct SearchAndReplace *) closure );
215 /* Function Name: _XawTextSearch
216 * Description: Action routine that can be bound to the text widget
217 * it will popup the search dialog box.
218 * Arguments: w - the text widget.
219 * event - X Event (used to get x and y location).
220 * params, num_params - the parameter list.
225 * The parameter list contains one or two entries that may be the following.
227 * First Entry: The first entry is the direction to search by default.
228 * This argument must be specified and may have a value of
231 * Second Entry: This entry is optional and contains the value of the default
232 * string to search for.
235 #define SEARCH_HEADER ("Text Widget - Search():")
238 _XawTextSearch(w, event, params, num_params)
242 Cardinal * num_params;
244 TextWidget ctx = (TextWidget)w;
245 XawTextScanDirection dir;
246 char * ptr, buf[BUFSIZ];
247 XawTextEditType edit_mode;
251 if (!ctx->text.source->Search) {
252 XBell(XtDisplay(w), 0);
257 if ( (*num_params < 1) || (*num_params > 2) ) {
258 sprintf(buf, "%s %s\n%s", SEARCH_HEADER, "This action must have only",
259 "one or two parameters");
260 XtAppWarning(XtWidgetToApplicationContext(w), buf);
263 else if (*num_params == 1)
268 switch(params[0][0]) {
269 case 'b': /* Left. */
273 case 'f': /* Right. */
278 sprintf(buf, "%s %s\n%s", SEARCH_HEADER, "The first parameter must be",
279 "Either 'backward' or 'forward'");
280 XtAppWarning(XtWidgetToApplicationContext(w), buf);
284 if (!ctx->text.search) {
285 ctx->text.search = XtNew(struct SearchAndReplace);
286 ctx->text.search->search_popup = CreateDialog(w, ptr, "search",
288 XtRealizeWidget(ctx->text.search->search_popup);
289 SetWMProtocolTranslations(ctx->text.search->search_popup);
291 else if (*num_params > 1)
292 XtVaSetValues(ctx->text.search->search_text, XtNstring, ptr, NULL);
294 XtSetArg(args[0], XtNeditType,&edit_mode);
295 XtGetValues(ctx->text.source, args, ONE);
297 InitializeSearchWidget(ctx->text.search, dir, (edit_mode == XawtextEdit));
299 CenterWidgetOnPoint(ctx->text.search->search_popup, event);
300 XtPopup(ctx->text.search->search_popup, XtGrabNone);
303 /* Function Name: InitializeSearchWidget
304 * Description: This function initializes the search widget and
305 * is called each time the search widget is poped up.
306 * Arguments: search - the search widget structure.
307 * dir - direction to search.
308 * replace_active - state of the sensitivity for the
314 InitializeSearchWidget(struct SearchAndReplace *search,
315 XawTextScanDirection dir, Boolean replace_active)
317 replace_active = replace_active; /* PH - shuts compilers up */
321 SetResource(search->left_toggle, XtNstate, (XtArgVal) TRUE);
324 SetResource(search->right_toggle, XtNstate, (XtArgVal) TRUE);
331 /* Function Name: AddSearchChildren
332 * Description: Adds all children to the Search Dialog Widget.
333 * Arguments: form - the form widget for the search widget.
334 * ptr - a pointer to the initial string for the Text Widget.
335 * tw - the main text widget.
340 AddSearchChildren(form, ptr, tw)
346 Widget cancel, search_button, s_label, s_text;
347 XtTranslations trans;
348 struct SearchAndReplace * search = ((TextWidget) tw)->text.search;
351 XtSetArg(args[num_args], XtNleft, XtChainLeft); num_args++;
352 XtSetArg(args[num_args], XtNright, XtChainLeft); num_args++;
353 XtSetArg(args[num_args], XtNresizable, TRUE ); num_args++;
354 XtSetArg(args[num_args], XtNborderWidth, 0 ); num_args++;
355 search->label1 = XtCreateManagedWidget("label1", labelWidgetClass,
356 form, args, num_args);
359 * We need to add R_OFFSET to the radio_data, because the value zero (0)
360 * has special meaning.
364 XtSetArg(args[num_args], XtNlabel, "Backward"); num_args++;
365 XtSetArg(args[num_args], XtNfromVert, search->label1); num_args++;
366 XtSetArg(args[num_args], XtNleft, XtChainLeft); num_args++;
367 XtSetArg(args[num_args], XtNright, XtChainLeft); num_args++;
368 XtSetArg(args[num_args], XtNradioData, (caddr_t) XawsdLeft + R_OFFSET);
370 search->left_toggle = XtCreateManagedWidget("backwards", toggleWidgetClass,
371 form, args, num_args);
374 XtSetArg(args[num_args], XtNlabel, "Forward"); num_args++;
375 XtSetArg(args[num_args], XtNfromVert, search->label1); num_args++;
376 XtSetArg(args[num_args], XtNfromHoriz, search->left_toggle); num_args++;
377 XtSetArg(args[num_args], XtNleft, XtChainLeft); num_args++;
378 XtSetArg(args[num_args], XtNright, XtChainLeft); num_args++;
379 XtSetArg(args[num_args], XtNradioGroup, search->left_toggle); num_args++;
380 XtSetArg(args[num_args], XtNradioData, (caddr_t) XawsdRight + R_OFFSET);
382 search->right_toggle = XtCreateManagedWidget("forwards", toggleWidgetClass,
383 form, args, num_args);
386 XtTranslations radio_translations;
388 radio_translations = XtParseTranslationTable(radio_trans_string);
389 XtOverrideTranslations(search->left_toggle, radio_translations);
390 XtOverrideTranslations(search->right_toggle, radio_translations);
394 XtSetArg(args[num_args], XtNfromVert, search->left_toggle); num_args++;
395 XtSetArg(args[num_args], XtNlabel, "Search for: ");num_args++;
396 XtSetArg(args[num_args], XtNleft, XtChainLeft); num_args++;
397 XtSetArg(args[num_args], XtNright, XtChainLeft); num_args++;
398 XtSetArg(args[num_args], XtNborderWidth, 0 ); num_args++;
399 s_label = XtCreateManagedWidget("searchLabel", labelWidgetClass,
400 form, args, num_args);
403 XtSetArg(args[num_args], XtNfromVert, search->left_toggle); num_args++;
404 XtSetArg(args[num_args], XtNfromHoriz, s_label); num_args++;
405 XtSetArg(args[num_args], XtNleft, XtChainLeft); num_args++;
406 XtSetArg(args[num_args], XtNright, XtChainRight); num_args++;
407 XtSetArg(args[num_args], XtNeditType, XawtextEdit); num_args++;
408 XtSetArg(args[num_args], XtNresizable, TRUE); num_args++;
409 XtSetArg(args[num_args], XtNresize, XawtextResizeWidth); num_args++;
410 XtSetArg(args[num_args], XtNstring, ptr); num_args++;
411 s_text = XtCreateManagedWidget("searchText", asciiTextWidgetClass, form,
413 search->search_text = s_text;
416 XtSetArg(args[num_args], XtNlabel, "Search"); num_args++;
417 XtSetArg(args[num_args], XtNfromVert, s_text); num_args++;
418 XtSetArg(args[num_args], XtNleft, XtChainLeft); num_args++;
419 XtSetArg(args[num_args], XtNright, XtChainLeft); num_args++;
420 search_button = XtCreateManagedWidget("search", commandWidgetClass, form,
424 XtSetArg(args[num_args], XtNlabel, "Cancel"); num_args++;
425 XtSetArg(args[num_args], XtNfromVert, s_text); num_args++;
426 XtSetArg(args[num_args], XtNfromHoriz, search_button); num_args++;
427 XtSetArg(args[num_args], XtNleft, XtChainLeft); num_args++;
428 XtSetArg(args[num_args], XtNright, XtChainLeft); num_args++;
429 cancel = XtCreateManagedWidget(DISMISS_NAME, commandWidgetClass, form,
432 XtAddCallback(search_button, XtNcallback, SearchButton, (XtPointer) search);
433 XtAddCallback(cancel, XtNcallback, PopdownSearch, (XtPointer) search);
436 * Initialize the text entry fields.
439 SetSearchLabels(search, "Search", "", FALSE);
440 XtSetKeyboardFocus(form, search->search_text);
443 * Bind Extra translations.
446 trans = XtParseTranslationTable(search_text_trans);
447 XtOverrideTranslations(search->search_text, trans);
450 /* Function Name: DoSearch
451 * Description: Performs a search.
452 * Arguments: search - the search structure.
453 * Returns: TRUE if successful.
459 struct SearchAndReplace * search;
462 Widget tw = XtParent(search->search_popup);
464 XawTextScanDirection dir;
467 text.ptr = GetString(search->search_text);
468 text.length = strlen(text.ptr);
470 text.format = FMT8BIT;
472 dir = (XawTextScanDirection) ((long)XawToggleGetCurrent(search->left_toggle) -
475 pos = XawTextSearch( tw, dir, &text);
477 if (pos == XawTextSearchError)
478 sprintf( msg, "Could not find string '%s'.", text.ptr);
480 if (dir == XawsdRight)
481 XawTextSetInsertionPoint( tw, pos + text.length);
483 XawTextSetInsertionPoint( tw, pos);
485 XawTextSetSelection( tw, pos, pos + text.length);
486 search->selection_changed = FALSE; /* selection is good. */
490 XawTextUnsetSelection(tw);
491 SetSearchLabels(search, msg, "", TRUE);
496 /* Function Name: SetSearchLabels
497 * Description: Sets both the search labels, and also rings the bell
498 * HACKED: Only one label needed now
499 * Arguments: search - the search structure.
500 * msg1, msg2 - message to put in each search label.
501 * bell - if TRUE then ring bell.
506 SetSearchLabels(struct SearchAndReplace *search, String msg1, String msg2,
509 msg2 = msg2; /* PH - shuts compilers up */
510 (void) SetResource( search->label1, XtNlabel, (XtArgVal) msg1);
511 /* (void) SetResource( search->label2, XtNlabel, (XtArgVal) msg2); */
513 XBell(XtDisplay(search->search_popup), 0);
516 /************************************************************
518 * This section of the file contains utility routines used by
519 * other functions in this file.
521 ************************************************************/
524 /* Function Name: SetResource
525 * Description: Sets a resource in a widget
526 * Arguments: w - the widget.
527 * res_name - name of the resource.
528 * value - the value of the resource.
533 SetResource(w, res_name, value)
540 XtSetArg(args[0], res_name, value);
541 XtSetValues( w, args, ONE );
544 /* Function Name: GetString
545 * Description: Gets the value for the string in the popup.
546 * Arguments: text - the text widget whose string we will get.
547 * Returns: the string.
557 XtSetArg( args[0], XtNstring, &string );
558 XtGetValues( text, args, ONE );
562 /* Function Name: CenterWidgetOnPoint.
563 * Description: Centers a shell widget on a point relative to
565 * Arguments: w - the shell widget.
566 * event - event containing the location of the point
569 * NOTE: The widget is not allowed to go off the screen.
573 CenterWidgetOnPoint(w, event)
579 Dimension width, height, b_width;
580 Position x=0, y=0, max_x, max_y;
583 switch (event->type) {
586 x = event->xbutton.x_root;
587 y = event->xbutton.y_root;
591 x = event->xkey.x_root;
592 y = event->xkey.y_root;
600 XtSetArg(args[num_args], XtNwidth, &width); num_args++;
601 XtSetArg(args[num_args], XtNheight, &height); num_args++;
602 XtSetArg(args[num_args], XtNborderWidth, &b_width); num_args++;
603 XtGetValues(w, args, num_args);
605 width += 2 * b_width;
606 height += 2 * b_width;
608 x -= ( (Position) width/2 );
610 if ( x > (max_x = (Position) (XtScreen(w)->width - width)) ) x = max_x;
612 y -= ( (Position) height/2 );
614 if ( y > (max_y = (Position) (XtScreen(w)->height - height)) ) y = max_y;
617 XtSetArg(args[num_args], XtNx, x); num_args++;
618 XtSetArg(args[num_args], XtNy, y); num_args++;
619 XtSetValues(w, args, num_args);
622 /* Function Name: CreateDialog
623 * Description: Actually creates a dialog.
624 * Arguments: parent - the parent of the dialog - the main text widget.
625 * ptr - initial_string for the dialog.
626 * name - name of the dialog.
627 * func - function to create the children of the dialog.
628 * Returns: the popup shell of the dialog.
632 * The function argument is passed the following arguments.
634 * form - the from widget that is the dialog.
635 * ptr - the initial string for the dialog's text widget.
636 * parent - the parent of the dialog - the main text widget.
640 CreateDialog(parent, ptr, name, func)
650 XtSetArg(args[num_args], XtNiconName, name); num_args++;
651 XtSetArg(args[num_args], XtNgeometry, NULL); num_args++;
652 XtSetArg(args[num_args], XtNallowShellResize, TRUE); num_args++;
653 XtSetArg(args[num_args], XtNtransientFor, GetShell(parent)); num_args++;
654 popup = XtCreatePopupShell(name, transientShellWidgetClass,
655 parent, args, num_args);
657 form = XtCreateManagedWidget(FORM_NAME, formWidgetClass, popup,
660 (*func) (form, ptr, parent);
664 /* Function Name: GetShell
665 * Description: Walks up the widget hierarchy to find the
666 * nearest shell widget.
667 * Arguments: w - the widget whose parent shell should be returned.
668 * Returns: The shell widget among the ancestors of w that is the
669 * fewest levels up in the widget hierarchy.
676 while ((w != NULL) && !XtIsShell(w))
682 /* Add proper prototype to keep IRIX 6 compiler happy. PH */
684 static Boolean InParams(String, String *, Cardinal);
686 static Boolean InParams(str, p, n)
692 for (i=0; i < n; p++, i++)
693 if (! XmuCompareISOLatin1(*p, str)) return True;
697 static char *WM_DELETE_WINDOW = "WM_DELETE_WINDOW";
699 static void WMProtocols(w, event, params, num_params)
700 Widget w; /* popup shell */
703 Cardinal *num_params;
705 Atom wm_delete_window;
708 wm_delete_window = XInternAtom(XtDisplay(w), WM_DELETE_WINDOW, True);
709 wm_protocols = XInternAtom(XtDisplay(w), "WM_PROTOCOLS", True);
711 /* Respond to a recognized WM protocol request iff
712 * event type is ClientMessage and no parameters are passed, or
713 * event type is ClientMessage and event data is matched to parameters, or
714 * event type isn't ClientMessage and parameters make a request.
716 #define DO_DELETE_WINDOW InParams(WM_DELETE_WINDOW, params, *num_params)
718 if ((event->type == ClientMessage &&
719 event->xclient.message_type == wm_protocols &&
720 event->xclient.data.l[0] == wm_delete_window &&
721 (*num_params == 0 || DO_DELETE_WINDOW))
723 (event->type != ClientMessage && DO_DELETE_WINDOW)) {
725 #undef DO_DELETE_WINDOW
728 char descendant[DISMISS_NAME_LEN + 2];
729 sprintf(descendant, "*%s", DISMISS_NAME);
730 cancel = XtNameToWidget(w, descendant);
731 if (cancel) XtCallCallbacks(cancel, XtNcallback, (XtPointer)NULL);
735 static void SetWMProtocolTranslations(w)
736 Widget w; /* realized popup shell */
739 XtAppContext app_context;
740 Atom wm_delete_window;
741 static XtTranslations compiled_table; /* initially 0 */
742 static XtAppContext *app_context_list; /* initially 0 */
743 static Cardinal list_size; /* initially 0 */
745 app_context = XtWidgetToApplicationContext(w);
747 /* parse translation table once */
748 if (! compiled_table) compiled_table = XtParseTranslationTable
749 ("<Message>WM_PROTOCOLS: XawWMProtocols()\n");
751 /* add actions once per application context */
752 for (i=0; i < list_size && app_context_list[i] != app_context; i++) ;
753 if (i == list_size) {
754 XtActionsRec actions[1];
755 actions[0].string = "XawWMProtocols";
756 actions[0].proc = WMProtocols;
758 app_context_list = (XtAppContext *) XtRealloc
759 ((char *)app_context_list, list_size * sizeof(XtAppContext));
760 XtAppAddActions(app_context, actions, 1);
761 app_context_list[i] = app_context;
764 /* establish communication between the window manager and each shell */
765 XtAugmentTranslations(w, compiled_table);
766 wm_delete_window = XInternAtom(XtDisplay(w), WM_DELETE_WINDOW, False);
767 (void) XSetWMProtocols(XtDisplay(w), XtWindow(w), &wm_delete_window, 1);