1 /***********************************************************
2 Copyright (c) The Exim Maintainers 2022
3 Copyright 1989 by the Massachusetts Institute of Technology,
4 Cambridge, Massachusetts.
8 Permission to use, copy, modify, and distribute this software and its
9 documentation for any purpose and without fee is hereby granted,
10 provided that the above copyright notice appear in all copies and that
11 both that copyright notice and this permission notice appear in
12 supporting documentation, and that the names of Digital or MIT not be
13 used in advertising or publicity pertaining to distribution of the
14 software without specific, written prior permission.
16 DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
17 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
18 DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
19 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
20 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
21 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
24 ******************************************************************/
27 /****************************************************************************
28 * Modified by Philip Hazel for use with Exim. The "replace" and "insert *
29 * file" features of the search facility have been removed. Also took out *
30 * the declaration of sys_errlist, as it isn't used and causes trouble on *
31 * some systems that declare it differently. September 1996. *
32 * Added the arguments into the static functions declared at the head, to *
33 * stop some compiler warnings. August 1999. *
34 * Took out the separate declarations of errno and sys_nerr at the start, *
35 * because they too aren't actually used, and the declaration causes trouble *
36 * on some systems. December 2002. *
37 ****************************************************************************/
40 /************************************************************
42 * This file is broken up into three sections one dealing with
43 * each of the three popups created here:
45 * FileInsert, Search, and Replace.
47 * There is also a section at the end for utility functions
48 * used by all more than one of these dialogs.
50 * The following functions are the only non-static ones defined
51 * in this module. They are located at the beginning of the
52 * section that contains this dialog box that uses them.
54 * void _XawTextInsertFileAction(w, event, params, num_params);
55 * void _XawTextDoSearchAction(w, event, params, num_params);
56 * void _XawTextDoReplaceAction(w, event, params, num_params);
57 * void _XawTextInsertFile(w, event, params, num_params);
59 *************************************************************/
61 #include <X11/IntrinsicP.h>
62 #include <X11/StringDefs.h>
63 #include <X11/Shell.h>
65 #include <X11/Xaw/TextP.h>
66 #include <X11/Xaw/AsciiText.h>
67 #include <X11/Xaw/Cardinals.h>
68 #include <X11/Xaw/Command.h>
69 #include <X11/Xaw/Form.h>
70 #include <X11/Xaw/Toggle.h>
71 #include <X11/Xmu/CharSet.h>
73 #include <X11/Xos.h> /* for O_RDONLY */
76 /* extern int errno, sys_nerr; */
77 /* extern char* sys_errlist[]; */
79 #define DISMISS_NAME ("cancel")
80 #define DISMISS_NAME_LEN 6
81 #define FORM_NAME ("form")
82 #define LABEL_NAME ("label")
83 #define TEXT_NAME ("text")
87 /* Argument types added by PH August 1999 */
89 static void CenterWidgetOnPoint(Widget, XEvent *);
90 static void PopdownSearch(Widget, XtPointer, XtPointer);
91 static void InitializeSearchWidget(struct SearchAndReplace *,
92 XawTextScanDirection, Boolean);
93 static void SetResource(Widget, char *, XtArgVal);
94 static void SetSearchLabels(struct SearchAndReplace *, String, String,
96 static Widget CreateDialog(Widget, String, String,
97 void (*)(Widget, char *, Widget));
98 static Widget GetShell(Widget);
99 static void SetWMProtocolTranslations(Widget w);
100 static Boolean DoSearch(struct SearchAndReplace *);
101 static String GetString(Widget);
103 static void AddSearchChildren(Widget, char *, Widget);
105 static char radio_trans_string[] =
106 "<Btn1Down>,<Btn1Up>: set() notify()";
108 static char search_text_trans[] =
109 "~Shift<Key>Return: DoSearchAction(Popdown) \n\
110 Ctrl<Key>c: PopdownSearchAction() \n\
115 /************************************************************
117 * This section of the file contains all the functions that
118 * the search dialog box uses.
120 ************************************************************/
122 /* Function Name: _XawTextDoSearchAction
123 * Description: Action routine that can be bound to dialog box's
124 * Text Widget that will search for a string in the main
126 * Arguments: (Standard Action Routine args)
131 * If the search was successful and the argument popdown is passed to
132 * this action routine then the widget will automatically popdown the
138 _XawTextDoSearchAction(w, event, params, num_params)
142 Cardinal * num_params;
144 TextWidget tw = (TextWidget) XtParent(XtParent(XtParent(w)));
145 Boolean popdown = FALSE;
147 if ( (*num_params == 1) &&
148 ((params[0][0] == 'p') || (params[0][0] == 'P')) )
151 if (DoSearch(tw->text.search) && popdown)
152 PopdownSearch(w, (XtPointer) tw->text.search, NULL);
155 /* Function Name: _XawTextPopdownSearchAction
156 * Description: Action routine that can be bound to dialog box's
157 * Text Widget that will popdown the search widget.
158 * Arguments: (Standard Action Routine args)
164 _XawTextPopdownSearchAction(w, event, params, num_params)
168 Cardinal * num_params;
170 TextWidget tw = (TextWidget) XtParent(XtParent(XtParent(w)));
172 PopdownSearch(w, (XtPointer) tw->text.search, NULL);
175 /* Function Name: PopdownSearch
176 * Description: Pops down the search widget and resets it.
177 * Arguments: w - *** NOT USED ***.
178 * closure - a pointer to the search structure.
179 * call_data - *** NOT USED ***.
185 PopdownSearch(w, closure, call_data)
190 struct SearchAndReplace * search = (struct SearchAndReplace *) closure;
192 SetSearchLabels(search, "Search", "", FALSE);
193 XtPopdown( search->search_popup );
196 /* Function Name: SearchButton
197 * Description: Performs a search when the button is clicked.
198 * Arguments: w - *** NOT USED **.
199 * closure - a pointer to the search info.
200 * call_data - *** NOT USED ***.
206 SearchButton(w, closure, call_data)
211 (void) DoSearch( (struct SearchAndReplace *) closure );
214 /* Function Name: _XawTextSearch
215 * Description: Action routine that can be bound to the text widget
216 * it will popup the search dialog box.
217 * Arguments: w - the text widget.
218 * event - X Event (used to get x and y location).
219 * params, num_params - the parameter list.
224 * The parameter list contains one or two entries that may be the following.
226 * First Entry: The first entry is the direction to search by default.
227 * This argument must be specified and may have a value of
230 * Second Entry: This entry is optional and contains the value of the default
231 * string to search for.
234 #define SEARCH_HEADER ("Text Widget - Search():")
237 _XawTextSearch(w, event, params, num_params)
241 Cardinal * num_params;
243 TextWidget ctx = (TextWidget)w;
244 XawTextScanDirection dir;
245 char * ptr, buf[BUFSIZ];
246 XawTextEditType edit_mode;
250 if (!ctx->text.source->Search) {
251 XBell(XtDisplay(w), 0);
256 if ( (*num_params < 1) || (*num_params > 2) ) {
257 sprintf(buf, "%s %s\n%s", SEARCH_HEADER, "This action must have only",
258 "one or two parameters");
259 XtAppWarning(XtWidgetToApplicationContext(w), buf);
262 else if (*num_params == 1)
267 switch(params[0][0]) {
268 case 'b': /* Left. */
272 case 'f': /* Right. */
277 sprintf(buf, "%s %s\n%s", SEARCH_HEADER, "The first parameter must be",
278 "Either 'backward' or 'forward'");
279 XtAppWarning(XtWidgetToApplicationContext(w), buf);
283 if (!ctx->text.search) {
284 ctx->text.search = XtNew(struct SearchAndReplace);
285 ctx->text.search->search_popup = CreateDialog(w, ptr, "search",
287 XtRealizeWidget(ctx->text.search->search_popup);
288 SetWMProtocolTranslations(ctx->text.search->search_popup);
290 else if (*num_params > 1)
291 XtVaSetValues(ctx->text.search->search_text, XtNstring, ptr, NULL);
293 XtSetArg(args[0], XtNeditType,&edit_mode);
294 XtGetValues(ctx->text.source, args, ONE);
296 InitializeSearchWidget(ctx->text.search, dir, (edit_mode == XawtextEdit));
298 CenterWidgetOnPoint(ctx->text.search->search_popup, event);
299 XtPopup(ctx->text.search->search_popup, XtGrabNone);
302 /* Function Name: InitializeSearchWidget
303 * Description: This function initializes the search widget and
304 * is called each time the search widget is poped up.
305 * Arguments: search - the search widget structure.
306 * dir - direction to search.
307 * replace_active - state of the sensitivity for the
313 InitializeSearchWidget(struct SearchAndReplace *search,
314 XawTextScanDirection dir, Boolean replace_active)
316 replace_active = replace_active; /* PH - shuts compilers up */
320 SetResource(search->left_toggle, XtNstate, (XtArgVal) TRUE);
323 SetResource(search->right_toggle, XtNstate, (XtArgVal) TRUE);
330 /* Function Name: AddSearchChildren
331 * Description: Adds all children to the Search Dialog Widget.
332 * Arguments: form - the form widget for the search widget.
333 * ptr - a pointer to the initial string for the Text Widget.
334 * tw - the main text widget.
339 AddSearchChildren(form, ptr, tw)
345 Widget cancel, search_button, s_label, s_text;
346 XtTranslations trans;
347 struct SearchAndReplace * search = ((TextWidget) tw)->text.search;
350 XtSetArg(args[num_args], XtNleft, XtChainLeft); num_args++;
351 XtSetArg(args[num_args], XtNright, XtChainLeft); num_args++;
352 XtSetArg(args[num_args], XtNresizable, TRUE ); num_args++;
353 XtSetArg(args[num_args], XtNborderWidth, 0 ); num_args++;
354 search->label1 = XtCreateManagedWidget("label1", labelWidgetClass,
355 form, args, num_args);
358 * We need to add R_OFFSET to the radio_data, because the value zero (0)
359 * has special meaning.
363 XtSetArg(args[num_args], XtNlabel, "Backward"); num_args++;
364 XtSetArg(args[num_args], XtNfromVert, search->label1); num_args++;
365 XtSetArg(args[num_args], XtNleft, XtChainLeft); num_args++;
366 XtSetArg(args[num_args], XtNright, XtChainLeft); num_args++;
367 XtSetArg(args[num_args], XtNradioData, (caddr_t) XawsdLeft + R_OFFSET);
369 search->left_toggle = XtCreateManagedWidget("backwards", toggleWidgetClass,
370 form, args, num_args);
373 XtSetArg(args[num_args], XtNlabel, "Forward"); num_args++;
374 XtSetArg(args[num_args], XtNfromVert, search->label1); num_args++;
375 XtSetArg(args[num_args], XtNfromHoriz, search->left_toggle); num_args++;
376 XtSetArg(args[num_args], XtNleft, XtChainLeft); num_args++;
377 XtSetArg(args[num_args], XtNright, XtChainLeft); num_args++;
378 XtSetArg(args[num_args], XtNradioGroup, search->left_toggle); num_args++;
379 XtSetArg(args[num_args], XtNradioData, (caddr_t) XawsdRight + R_OFFSET);
381 search->right_toggle = XtCreateManagedWidget("forwards", toggleWidgetClass,
382 form, args, num_args);
385 XtTranslations radio_translations;
387 radio_translations = XtParseTranslationTable(radio_trans_string);
388 XtOverrideTranslations(search->left_toggle, radio_translations);
389 XtOverrideTranslations(search->right_toggle, radio_translations);
393 XtSetArg(args[num_args], XtNfromVert, search->left_toggle); num_args++;
394 XtSetArg(args[num_args], XtNlabel, "Search for: ");num_args++;
395 XtSetArg(args[num_args], XtNleft, XtChainLeft); num_args++;
396 XtSetArg(args[num_args], XtNright, XtChainLeft); num_args++;
397 XtSetArg(args[num_args], XtNborderWidth, 0 ); num_args++;
398 s_label = XtCreateManagedWidget("searchLabel", labelWidgetClass,
399 form, args, num_args);
402 XtSetArg(args[num_args], XtNfromVert, search->left_toggle); num_args++;
403 XtSetArg(args[num_args], XtNfromHoriz, s_label); num_args++;
404 XtSetArg(args[num_args], XtNleft, XtChainLeft); num_args++;
405 XtSetArg(args[num_args], XtNright, XtChainRight); num_args++;
406 XtSetArg(args[num_args], XtNeditType, XawtextEdit); num_args++;
407 XtSetArg(args[num_args], XtNresizable, TRUE); num_args++;
408 XtSetArg(args[num_args], XtNresize, XawtextResizeWidth); num_args++;
409 XtSetArg(args[num_args], XtNstring, ptr); num_args++;
410 s_text = XtCreateManagedWidget("searchText", asciiTextWidgetClass, form,
412 search->search_text = s_text;
415 XtSetArg(args[num_args], XtNlabel, "Search"); num_args++;
416 XtSetArg(args[num_args], XtNfromVert, s_text); num_args++;
417 XtSetArg(args[num_args], XtNleft, XtChainLeft); num_args++;
418 XtSetArg(args[num_args], XtNright, XtChainLeft); num_args++;
419 search_button = XtCreateManagedWidget("search", commandWidgetClass, form,
423 XtSetArg(args[num_args], XtNlabel, "Cancel"); num_args++;
424 XtSetArg(args[num_args], XtNfromVert, s_text); num_args++;
425 XtSetArg(args[num_args], XtNfromHoriz, search_button); num_args++;
426 XtSetArg(args[num_args], XtNleft, XtChainLeft); num_args++;
427 XtSetArg(args[num_args], XtNright, XtChainLeft); num_args++;
428 cancel = XtCreateManagedWidget(DISMISS_NAME, commandWidgetClass, form,
431 XtAddCallback(search_button, XtNcallback, SearchButton, (XtPointer) search);
432 XtAddCallback(cancel, XtNcallback, PopdownSearch, (XtPointer) search);
435 * Initialize the text entry fields.
438 SetSearchLabels(search, "Search", "", FALSE);
439 XtSetKeyboardFocus(form, search->search_text);
442 * Bind Extra translations.
445 trans = XtParseTranslationTable(search_text_trans);
446 XtOverrideTranslations(search->search_text, trans);
449 /* Function Name: DoSearch
450 * Description: Performs a search.
451 * Arguments: search - the search structure.
452 * Returns: TRUE if successful.
458 struct SearchAndReplace * search;
461 Widget tw = XtParent(search->search_popup);
463 XawTextScanDirection dir;
466 text.ptr = GetString(search->search_text);
467 text.length = strlen(text.ptr);
469 text.format = FMT8BIT;
471 dir = (XawTextScanDirection) ((long)XawToggleGetCurrent(search->left_toggle) -
474 pos = XawTextSearch( tw, dir, &text);
476 if (pos == XawTextSearchError)
477 sprintf( msg, "Could not find string '%s'.", text.ptr);
479 if (dir == XawsdRight)
480 XawTextSetInsertionPoint( tw, pos + text.length);
482 XawTextSetInsertionPoint( tw, pos);
484 XawTextSetSelection( tw, pos, pos + text.length);
485 search->selection_changed = FALSE; /* selection is good. */
489 XawTextUnsetSelection(tw);
490 SetSearchLabels(search, msg, "", TRUE);
495 /* Function Name: SetSearchLabels
496 * Description: Sets both the search labels, and also rings the bell
497 * HACKED: Only one label needed now
498 * Arguments: search - the search structure.
499 * msg1, msg2 - message to put in each search label.
500 * bell - if TRUE then ring bell.
505 SetSearchLabels(struct SearchAndReplace *search, String msg1, String msg2,
508 msg2 = msg2; /* PH - shuts compilers up */
509 (void) SetResource( search->label1, XtNlabel, (XtArgVal) msg1);
510 /* (void) SetResource( search->label2, XtNlabel, (XtArgVal) msg2); */
512 XBell(XtDisplay(search->search_popup), 0);
515 /************************************************************
517 * This section of the file contains utility routines used by
518 * other functions in this file.
520 ************************************************************/
523 /* Function Name: SetResource
524 * Description: Sets a resource in a widget
525 * Arguments: w - the widget.
526 * res_name - name of the resource.
527 * value - the value of the resource.
532 SetResource(w, res_name, value)
539 XtSetArg(args[0], res_name, value);
540 XtSetValues( w, args, ONE );
543 /* Function Name: GetString
544 * Description: Gets the value for the string in the popup.
545 * Arguments: text - the text widget whose string we will get.
546 * Returns: the string.
556 XtSetArg( args[0], XtNstring, &string );
557 XtGetValues( text, args, ONE );
561 /* Function Name: CenterWidgetOnPoint.
562 * Description: Centers a shell widget on a point relative to
564 * Arguments: w - the shell widget.
565 * event - event containing the location of the point
568 * NOTE: The widget is not allowed to go off the screen.
572 CenterWidgetOnPoint(w, event)
578 Dimension width, height, b_width;
579 Position x=0, y=0, max_x, max_y;
582 switch (event->type) {
585 x = event->xbutton.x_root;
586 y = event->xbutton.y_root;
590 x = event->xkey.x_root;
591 y = event->xkey.y_root;
599 XtSetArg(args[num_args], XtNwidth, &width); num_args++;
600 XtSetArg(args[num_args], XtNheight, &height); num_args++;
601 XtSetArg(args[num_args], XtNborderWidth, &b_width); num_args++;
602 XtGetValues(w, args, num_args);
604 width += 2 * b_width;
605 height += 2 * b_width;
607 x -= ( (Position) width/2 );
609 if ( x > (max_x = (Position) (XtScreen(w)->width - width)) ) x = max_x;
611 y -= ( (Position) height/2 );
613 if ( y > (max_y = (Position) (XtScreen(w)->height - height)) ) y = max_y;
616 XtSetArg(args[num_args], XtNx, x); num_args++;
617 XtSetArg(args[num_args], XtNy, y); num_args++;
618 XtSetValues(w, args, num_args);
621 /* Function Name: CreateDialog
622 * Description: Actually creates a dialog.
623 * Arguments: parent - the parent of the dialog - the main text widget.
624 * ptr - initial_string for the dialog.
625 * name - name of the dialog.
626 * func - function to create the children of the dialog.
627 * Returns: the popup shell of the dialog.
631 * The function argument is passed the following arguments.
633 * form - the from widget that is the dialog.
634 * ptr - the initial string for the dialog's text widget.
635 * parent - the parent of the dialog - the main text widget.
639 CreateDialog(parent, ptr, name, func)
649 XtSetArg(args[num_args], XtNiconName, name); num_args++;
650 XtSetArg(args[num_args], XtNgeometry, NULL); num_args++;
651 XtSetArg(args[num_args], XtNallowShellResize, TRUE); num_args++;
652 XtSetArg(args[num_args], XtNtransientFor, GetShell(parent)); num_args++;
653 popup = XtCreatePopupShell(name, transientShellWidgetClass,
654 parent, args, num_args);
656 form = XtCreateManagedWidget(FORM_NAME, formWidgetClass, popup,
659 (*func) (form, ptr, parent);
663 /* Function Name: GetShell
664 * Description: Walks up the widget hierarchy to find the
665 * nearest shell widget.
666 * Arguments: w - the widget whose parent shell should be returned.
667 * Returns: The shell widget among the ancestors of w that is the
668 * fewest levels up in the widget hierarchy.
675 while ((w != NULL) && !XtIsShell(w))
681 /* Add proper prototype to keep IRIX 6 compiler happy. PH */
683 static Boolean InParams(String, String *, Cardinal);
685 static Boolean InParams(str, p, n)
691 for (i=0; i < n; p++, i++)
692 if (! XmuCompareISOLatin1(*p, str)) return True;
696 static char *WM_DELETE_WINDOW = "WM_DELETE_WINDOW";
698 static void WMProtocols(w, event, params, num_params)
699 Widget w; /* popup shell */
702 Cardinal *num_params;
704 Atom wm_delete_window;
707 wm_delete_window = XInternAtom(XtDisplay(w), WM_DELETE_WINDOW, True);
708 wm_protocols = XInternAtom(XtDisplay(w), "WM_PROTOCOLS", True);
710 /* Respond to a recognized WM protocol request iff
711 * event type is ClientMessage and no parameters are passed, or
712 * event type is ClientMessage and event data is matched to parameters, or
713 * event type isn't ClientMessage and parameters make a request.
715 #define DO_DELETE_WINDOW InParams(WM_DELETE_WINDOW, params, *num_params)
717 if ((event->type == ClientMessage &&
718 event->xclient.message_type == wm_protocols &&
719 event->xclient.data.l[0] == wm_delete_window &&
720 (*num_params == 0 || DO_DELETE_WINDOW))
722 (event->type != ClientMessage && DO_DELETE_WINDOW)) {
724 #undef DO_DELETE_WINDOW
727 char descendant[DISMISS_NAME_LEN + 2];
728 sprintf(descendant, "*%s", DISMISS_NAME);
729 cancel = XtNameToWidget(w, descendant);
730 if (cancel) XtCallCallbacks(cancel, XtNcallback, (XtPointer)NULL);
734 static void SetWMProtocolTranslations(w)
735 Widget w; /* realized popup shell */
738 XtAppContext app_context;
739 Atom wm_delete_window;
740 static XtTranslations compiled_table; /* initially 0 */
741 static XtAppContext *app_context_list; /* initially 0 */
742 static Cardinal list_size; /* initially 0 */
744 app_context = XtWidgetToApplicationContext(w);
746 /* parse translation table once */
747 if (! compiled_table) compiled_table = XtParseTranslationTable
748 ("<Message>WM_PROTOCOLS: XawWMProtocols()\n");
750 /* add actions once per application context */
751 for (i=0; i < list_size && app_context_list[i] != app_context; i++) ;
752 if (i == list_size) {
753 XtActionsRec actions[1];
754 actions[0].string = "XawWMProtocols";
755 actions[0].proc = WMProtocols;
757 app_context_list = (XtAppContext *) XtRealloc
758 ((char *)app_context_list, list_size * sizeof(XtAppContext));
759 XtAppAddActions(app_context, actions, 1);
760 app_context_list[i] = app_context;
763 /* establish communication between the window manager and each shell */
764 XtAugmentTranslations(w, compiled_table);
765 wm_delete_window = XInternAtom(XtDisplay(w), WM_DELETE_WINDOW, False);
766 (void) XSetWMProtocols(XtDisplay(w), XtWindow(w), &wm_delete_window, 1);