1 /*
2  * Copyright (c) 2013-2015, 2019-2020 Paul Mattes.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *     * Redistributions of source code must retain the above copyright
9  *       notice, this list of conditions and the following disclaimer.
10  *     * Redistributions in binary form must reproduce the above copyright
11  *       notice, this list of conditions and the following disclaimer in the
12  *       documentation and/or other materials provided with the distribution.
13  *     * Neither the names of Paul Mattes nor his contributors may be used to
14  *       endorse or promote products derived from this software without
15  *       specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY PAUL MATTES "AS IS" AND ANY EXPRESS OR
18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
20  * EVENT SHALL PAUL MATTES BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
23  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
25  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
26  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 /*
30  *	stmenu.c
31  *		Pop-up window to initiate screen tracing.
32  */
33 
34 #include "globals.h"
35 #include "xglobals.h"
36 
37 #include <X11/Shell.h>
38 #include <X11/StringDefs.h>
39 #include <X11/Xaw/Command.h>
40 #include <X11/Xaw/Form.h>
41 #include <X11/Xaw/Label.h>
42 #include <X11/Xaw/AsciiText.h>
43 #include <X11/Xaw/TextSrc.h>
44 #include <X11/Xaw/TextSink.h>
45 #include <X11/Xaw/AsciiSrc.h>
46 #include <X11/Xaw/AsciiSink.h>
47 #include "appres.h"
48 #include "objects.h"
49 #include "resources.h"
50 
51 #include "dialog.h"
52 #include "popups.h"
53 #include "print_screen.h"
54 #include "stmenu.h"
55 #include "toggles.h"
56 #include "trace.h"
57 #include "screentrace.h"
58 #include "xmenubar.h"
59 #include "xpopups.h"
60 
61 #define CLOSE_VGAP	0
62 #define FAR_VGAP	10
63 #define FAR_HGAP	65
64 #define MARGIN		3
65 #define FILE_WIDTH	300
66 #define BUTTON_GAP	5
67 
68 static Widget stmenu_shell = NULL;
69 static Widget stmenu_form;
70 
71 static bool continuously_flag = true;	/* save continuously */
72 static Widget continuously_toggle = NULL;
73 static Widget once_toggle = NULL;
74 
75 static bool file_flag = true;		/* save in file */
76 static Widget file_toggle = NULL;
77 static Widget printer_toggle = NULL;
78 
79 static ptype_t stm_ptype = P_TEXT;		/* save as text/html/rtf */
80 static Widget text_toggle = NULL;
81 static Widget html_toggle = NULL;
82 static Widget rtf_toggle = NULL;
83 
84 static Widget filename_label = NULL;
85 static Widget filename = NULL;
86 static Widget print_command_label = NULL;
87 static Widget print_command = NULL;
88 
89 static ptype_t s_text = P_TEXT;
90 static ptype_t s_html = P_HTML;
91 static ptype_t s_rtf = P_RTF;
92 
93 /* Called when OK is pressed in the screentrace popup. */
94 static void
screentrace_ok(Widget w _is_unused,XtPointer client_data _is_unused,XtPointer call_data _is_unused)95 screentrace_ok(Widget w _is_unused, XtPointer client_data _is_unused,
96 	XtPointer call_data _is_unused)
97 {
98     String name;
99 
100     if (file_flag) {
101 	XtVaGetValues(filename, XtNstring, &name, NULL);
102     } else {
103 	XtVaGetValues(print_command, XtNstring, &name, NULL);
104     }
105     trace_set_screentrace_file(file_flag? TSS_FILE: TSS_PRINTER,
106 	    file_flag? stm_ptype: P_TEXT, 0, name);
107     do_toggle(SCREEN_TRACE);
108     if (!continuously_flag && toggled(SCREEN_TRACE)) {
109 	do_toggle(SCREEN_TRACE);
110     }
111 
112     XtPopdown(stmenu_shell);
113 }
114 
115 /* Called when Cancel is pressed in the screentrace popup. */
116 static void
screentrace_cancel(Widget w _is_unused,XtPointer client_data _is_unused,XtPointer call_data _is_unused)117 screentrace_cancel(Widget w _is_unused, XtPointer client_data _is_unused,
118 	XtPointer call_data _is_unused)
119 {
120     XtPopdown(stmenu_shell);
121 }
122 
123 /* Screentrace pop-up popping up. */
124 static void
stmenu_popup_callback(Widget w _is_unused,XtPointer client_data _is_unused,XtPointer call_data _is_unused)125 stmenu_popup_callback(Widget w _is_unused, XtPointer client_data _is_unused,
126 	XtPointer call_data _is_unused)
127 {
128     /* Set the focus to the file or printer text widget. */
129     XawTextDisplayCaret(filename, file_flag);
130     XawTextDisplayCaret(print_command, !file_flag);
131     XtSetKeyboardFocus(stmenu_form, file_flag? filename: print_command);
132 }
133 
134 /* Continuously/Once toggle callback. */
135 static void
toggle_continuously(Widget w _is_unused,XtPointer client_data,XtPointer call_data _is_unused)136 toggle_continuously(Widget w _is_unused, XtPointer client_data,
137 	XtPointer call_data _is_unused)
138 {
139     /* Toggle the flag. */
140     continuously_flag = *(bool *)client_data;
141 
142     /* Change the widget states. */
143     dialog_mark_toggle(continuously_toggle,
144 	    continuously_flag? diamond: no_diamond);
145     dialog_mark_toggle(once_toggle,
146 	    continuously_flag? no_diamond: diamond);
147 }
148 
149 /* File/Printer toggle callback. */
150 static void
toggle_file(Widget w _is_unused,XtPointer client_data,XtPointer call_data _is_unused)151 toggle_file(Widget w _is_unused, XtPointer client_data,
152 	XtPointer call_data _is_unused)
153 {
154     /* Toggle the flag. */
155     file_flag = *(bool *)client_data;
156 
157     /* Change the widget states. */
158     dialog_mark_toggle(file_toggle, file_flag? diamond: no_diamond);
159     dialog_mark_toggle(printer_toggle, file_flag? no_diamond: diamond);
160     XtVaSetValues(filename_label, XtNsensitive, file_flag, NULL);
161     XtVaSetValues(filename, XtNsensitive, file_flag, NULL);
162     XtVaSetValues(text_toggle, XtNsensitive, file_flag, NULL);
163     XtVaSetValues(html_toggle, XtNsensitive, file_flag, NULL);
164     XtVaSetValues(rtf_toggle, XtNsensitive, file_flag, NULL);
165     XtVaSetValues(print_command_label, XtNsensitive, !file_flag, NULL);
166     XtVaSetValues(print_command, XtNsensitive, !file_flag, NULL);
167     XawTextDisplayCaret(filename, file_flag);
168     XawTextDisplayCaret(print_command, !file_flag);
169     XtSetKeyboardFocus(stmenu_form, file_flag? filename: print_command);
170 }
171 
172 /* Text/HTML toggle callback. */
173 static void
toggle_ptype(Widget w _is_unused,XtPointer client_data,XtPointer call_data _is_unused)174 toggle_ptype(Widget w _is_unused, XtPointer client_data,
175 	XtPointer call_data _is_unused)
176 {
177     char *d;
178     XawTextBlock b;
179     String name;
180 
181     XtVaGetValues(filename, XtNstring, &name, NULL);
182 
183     /* Toggle the flag. */
184     stm_ptype = *(bool *)client_data;
185 
186     /* Change the widget states. */
187     dialog_mark_toggle(text_toggle,
188 	    (stm_ptype == P_TEXT)? diamond: no_diamond);
189     dialog_mark_toggle(html_toggle,
190 	    (stm_ptype == P_HTML)? diamond: no_diamond);
191     dialog_mark_toggle(rtf_toggle,
192 	    (stm_ptype == P_RTF)? diamond: no_diamond);
193 
194     d = screentrace_default_file(stm_ptype);
195     b.firstPos = 0;
196     b.length = strlen(d);
197     b.ptr = d;
198     b.format = XawFmt8Bit;
199     XawTextReplace(filename, 0, strlen(name), &b);
200     XawTextSetInsertionPoint(filename, strlen(d));
201     XtFree(d);
202 }
203 
204 /*
205  * Initialize the screentrace (Save Screens) pop-up.
206  *
207  * The pop-up consists of:
208  *  A pair of radio buttons for Continuously/Once
209  *  A pair of radio buttons for File/Printer
210  *  A pair of radio buttons for Text/HTML
211  *  A label for "File Name" or "Print Command"
212  *  A text box to fill in the above
213  *  An OK button
214  *  An Abort button
215  *
216  *  The radio buttons work like radio buttons.
217  *  When File/Printer is toggled, the label for the text box flips, and the
218  *  text box contents switch to the last value used for that type (or an
219  *  appropriate default).
220  */
221 void
init_screentrace_popup(void)222 init_screentrace_popup(void)
223 {
224     Widget w = NULL;
225     Widget confirm_button, cancel_button;
226     char *d;
227     XawTextBlock b;
228 
229     /* Get the defaults. */
230     file_flag = trace_get_screentrace_target() == TSS_FILE;
231     stm_ptype = trace_get_screentrace_type();
232 
233     /* Create the popup. */
234     stmenu_shell = XtVaCreatePopupShell(
235 	    "screenTracePopup", transientShellWidgetClass, toplevel,
236 	    NULL);
237     XtAddCallback(stmenu_shell, XtNpopupCallback, place_popup,
238 	    (XtPointer) CenterP);
239     XtAddCallback(stmenu_shell, XtNpopupCallback, stmenu_popup_callback,
240 	    NULL);
241 
242     /* Create a form in the popup. */
243     stmenu_form = XtVaCreateManagedWidget(
244 	    ObjDialog, formWidgetClass, stmenu_shell,
245 	    NULL);
246 
247     /* Create the Continuously/Once radio buttons. */
248     continuously_toggle = XtVaCreateManagedWidget(
249 	    "continuously", commandWidgetClass, stmenu_form,
250 	    XtNvertDistance, MARGIN,
251 	    XtNhorizDistance, MARGIN,
252 	    XtNborderWidth, 0,
253 	    XtNjustify, XtJustifyLeft,
254 	    NULL);
255     dialog_apply_bitmap(continuously_toggle,
256 	    continuously_flag? diamond: no_diamond);
257     XtAddCallback(continuously_toggle, XtNcallback, toggle_continuously,
258 	    (XtPointer)&s_true);
259     once_toggle = XtVaCreateManagedWidget(
260 	    "once", commandWidgetClass, stmenu_form,
261 	    XtNfromVert, continuously_toggle,
262 	    XtNvertDistance, CLOSE_VGAP,
263 	    XtNhorizDistance, MARGIN,
264 	    XtNborderWidth, 0,
265 	    XtNjustify, XtJustifyLeft,
266 	    NULL);
267     dialog_apply_bitmap(once_toggle,
268 	    continuously_flag? no_diamond: diamond);
269     XtAddCallback(once_toggle, XtNcallback, toggle_continuously,
270 	    (XtPointer)&s_false);
271     dialog_match_dimension(continuously_toggle, once_toggle, XtNwidth);
272 
273     /* Create the File radio button. */
274     file_toggle = XtVaCreateManagedWidget(
275 	    "file", commandWidgetClass, stmenu_form,
276 	    XtNfromVert, once_toggle,
277 	    XtNvertDistance, FAR_VGAP,
278 	    XtNhorizDistance, MARGIN,
279 	    XtNborderWidth, 0,
280 	    XtNjustify, XtJustifyLeft,
281 	    NULL);
282     dialog_apply_bitmap(file_toggle,
283 	    file_flag? diamond: no_diamond);
284     XtAddCallback(file_toggle, XtNcallback, toggle_file,
285 	    (XtPointer)&s_true);
286 
287     /* Create the file name label and text widgets. */
288     filename_label = XtVaCreateManagedWidget(
289 	    "fileName", labelWidgetClass, stmenu_form,
290 	    XtNfromVert, file_toggle,
291 	    XtNvertDistance, CLOSE_VGAP,
292 	    XtNhorizDistance, FAR_HGAP,
293 	    XtNborderWidth, 0,
294 	    XtNjustify, XtJustifyLeft,
295 	    XtNsensitive, file_flag,
296 	    NULL);
297     filename = XtVaCreateManagedWidget(
298 	    "value", asciiTextWidgetClass, stmenu_form,
299 	    XtNeditType, XawtextEdit,
300 	    XtNwidth, FILE_WIDTH,
301 	    XtNfromVert, file_toggle,
302 	    XtNvertDistance, CLOSE_VGAP,
303 	    XtNfromHoriz, filename_label,
304 	    XtNhorizDistance, 0,
305 	    XtNsensitive, file_flag,
306 	    NULL);
307     dialog_match_dimension(filename_label, filename, XtNheight);
308     w = XawTextGetSource(filename);
309     if (w == NULL) {
310 	XtWarning("Cannot find text source in dialog");
311     } else {
312 	XtAddCallback(w, XtNcallback, dialog_text_callback,
313 		(XtPointer)&t_unixfile);
314     }
315     d = screentrace_default_file(stm_ptype);
316     b.firstPos = 0;
317     b.length = strlen(d);
318     b.ptr = d;
319     b.format = XawFmt8Bit;
320     XawTextReplace(filename, 0, 0, &b);
321     XawTextSetInsertionPoint(filename, strlen(d));
322     XtFree(d);
323 
324     /* Create the Text/HTML/RTF radio buttons. */
325     text_toggle = XtVaCreateManagedWidget(
326 	    "text", commandWidgetClass, stmenu_form,
327 	    XtNfromVert, filename_label,
328 	    XtNvertDistance, CLOSE_VGAP,
329 	    XtNhorizDistance, FAR_HGAP,
330 	    XtNborderWidth, 0,
331 	    XtNsensitive, file_flag,
332 	    NULL);
333     dialog_apply_bitmap(text_toggle,
334 	    (stm_ptype == P_TEXT)? diamond: no_diamond);
335     XtAddCallback(text_toggle, XtNcallback, toggle_ptype,
336 	    (XtPointer)&s_text);
337     html_toggle = XtVaCreateManagedWidget(
338 	    "html", commandWidgetClass, stmenu_form,
339 	    XtNfromVert, text_toggle,
340 	    XtNvertDistance, CLOSE_VGAP,
341 	    XtNhorizDistance, FAR_HGAP,
342 	    XtNborderWidth, 0,
343 	    XtNsensitive, file_flag,
344 	    NULL);
345     dialog_apply_bitmap(html_toggle,
346 	    (stm_ptype == P_HTML)? diamond: no_diamond);
347     XtAddCallback(html_toggle, XtNcallback, toggle_ptype,
348 	    (XtPointer)&s_html);
349     rtf_toggle = XtVaCreateManagedWidget(
350 	    "rtf", commandWidgetClass, stmenu_form,
351 	    XtNfromVert, html_toggle,
352 	    XtNvertDistance, CLOSE_VGAP,
353 	    XtNhorizDistance, FAR_HGAP,
354 	    XtNborderWidth, 0,
355 	    XtNsensitive, file_flag,
356 	    NULL);
357     dialog_apply_bitmap(rtf_toggle,
358 	    (stm_ptype == P_RTF)? diamond: no_diamond);
359     XtAddCallback(rtf_toggle, XtNcallback, toggle_ptype,
360 	    (XtPointer)&s_rtf);
361 
362     /* Create the printer toggle. */
363     printer_toggle = XtVaCreateManagedWidget(
364 	    "printer", commandWidgetClass, stmenu_form,
365 	    XtNhorizDistance, MARGIN,
366 	    XtNfromVert, rtf_toggle,
367 	    XtNvertDistance, FAR_VGAP,
368 	    XtNborderWidth, 0,
369 	    XtNjustify, XtJustifyLeft,
370 	    NULL);
371     dialog_apply_bitmap(printer_toggle,
372 	    file_flag? no_diamond: diamond);
373     XtAddCallback(printer_toggle, XtNcallback, toggle_file,
374 	    (XtPointer)&s_false);
375 
376     /* Create the print command label and text widgets. */
377     print_command_label = XtVaCreateManagedWidget(
378 	    "printCommand", labelWidgetClass, stmenu_form,
379 	    XtNfromVert, printer_toggle,
380 	    XtNvertDistance, CLOSE_VGAP,
381 	    XtNhorizDistance, FAR_HGAP,
382 	    XtNborderWidth, 0,
383 	    XtNjustify, XtJustifyLeft,
384 	    XtNsensitive, !file_flag,
385 	    NULL);
386     print_command = XtVaCreateManagedWidget(
387 	    "value", asciiTextWidgetClass, stmenu_form,
388 	    XtNeditType, XawtextEdit,
389 	    XtNwidth, FILE_WIDTH,
390 	    XtNfromVert, printer_toggle,
391 	    XtNvertDistance, CLOSE_VGAP,
392 	    XtNfromHoriz, print_command_label,
393 	    XtNhorizDistance, 0,
394 	    XtNsensitive, !file_flag,
395 	    NULL);
396     dialog_match_dimension(print_command_label, print_command, XtNheight);
397     dialog_match_dimension(filename_label, print_command_label, XtNwidth);
398     w = XawTextGetSource(print_command);
399     if (w == NULL) {
400 	    XtWarning("Cannot find text source in dialog");
401     } else {
402 	    XtAddCallback(w, XtNcallback, dialog_text_callback,
403 		    (XtPointer)&t_command);
404     }
405     d = screentrace_default_printer();
406     b.firstPos = 0;
407     b.length = strlen(d);
408     b.ptr = d;
409     b.format = XawFmt8Bit;
410     XawTextReplace(print_command, 0, 0, &b);
411     XawTextSetInsertionPoint(print_command, strlen(d));
412     XtFree(d);
413 
414     /* Create the buttons. */
415     confirm_button = XtVaCreateManagedWidget(
416 	    ObjConfirmButton, commandWidgetClass, stmenu_form,
417 	    XtNfromVert, print_command_label,
418 	    XtNvertDistance, FAR_VGAP,
419 	    XtNhorizDistance, MARGIN,
420 	    NULL);
421     XtAddCallback(confirm_button, XtNcallback, screentrace_ok, NULL);
422     cancel_button = XtVaCreateManagedWidget(
423 	    ObjCancelButton, commandWidgetClass, stmenu_form,
424 	    XtNfromVert, print_command_label,
425 	    XtNvertDistance, FAR_VGAP,
426 	    XtNfromHoriz, confirm_button,
427 	    XtNhorizDistance, BUTTON_GAP,
428 	    NULL);
429     XtAddCallback(cancel_button, XtNcallback, screentrace_cancel, NULL);
430 }
431 
432 /*
433  * Pop up the Screen Trace menu.
434  * Called from the "Save Screen Contents" option on the File menu.
435  */
436 void
stmenu_popup(stmp_t stmp)437 stmenu_popup(stmp_t stmp)
438 {
439     /* If the toggle is set, clear it. */
440     if (toggled(SCREEN_TRACE)) {
441 	do_toggle(SCREEN_TRACE);
442 	return;
443     }
444 
445     /* Initialize it. */
446     if (stmenu_shell == NULL) {
447 	init_screentrace_popup();
448     }
449 
450     switch (stmp) {
451     case STMP_AS_IS:
452 	break;
453     case STMP_TEXT:
454 	/* Force a text file. */
455 	if (!file_flag) {
456 	    toggle_file(NULL, &s_true, NULL);
457 	}
458 	if (stm_ptype != P_TEXT) {
459 	    toggle_ptype(NULL, &s_text, NULL);
460 	}
461 	if (continuously_flag) {
462 	    toggle_continuously(NULL, &s_false, NULL);
463 	}
464 	break;
465     case STMP_PRINTER:
466 	/* Force a printer. */
467 	if (file_flag) {
468 	    toggle_file(NULL, &s_false, NULL);
469 	}
470 	if (continuously_flag) {
471 	    toggle_continuously(NULL, &s_false, NULL);
472 	}
473 	break;
474     }
475 
476     /* Pop it up. */
477     popup_popup(stmenu_shell, XtGrabExclusive);
478 }
479