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