2
* Copyright (c) 1993-2009, Paul Mattes.
5
* Redistribution and use in source and binary forms, with or without
6
* modification, are permitted provided that the following conditions are met:
7
* * Redistributions of source code must retain the above copyright
8
* notice, this list of conditions and the following disclaimer.
9
* * Redistributions in binary form must reproduce the above copyright
10
* notice, this list of conditions and the following disclaimer in the
11
* documentation and/or other materials provided with the distribution.
12
* * Neither the names of Paul Mattes nor the names of his contributors
13
* may be used to endorse or promote products derived from this software
14
* without specific prior written permission.
16
* THIS SOFTWARE IS PROVIDED BY PAUL MATTES "AS IS" AND ANY EXPRESS OR IMPLIED
17
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19
* EVENT SHALL PAUL MATTES BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30
* This module handles the idle command.
35
#if defined(X3270_DISPLAY) || defined(C3270) /*[*/
37
#if defined(X3270_DISPLAY) /*[*/
38
#include <X11/StringDefs.h>
39
#include <X11/Xaw/Toggle.h>
40
#include <X11/Xaw/Command.h>
41
#include <X11/Xaw/Form.h>
42
#include <X11/Shell.h>
43
#include <X11/Xaw/AsciiText.h>
44
#include <X11/Xaw/TextSrc.h>
45
#include <X11/Xaw/TextSink.h>
46
#include <X11/Xaw/AsciiSrc.h>
47
#include <X11/Xaw/AsciiSink.h>
58
#include "resources.h"
59
#include "trace_dsc.h"
63
#define MSEC_PER_SEC 1000L
66
#define IDLE_HR (60L * 60L)
67
#define IDLE_MS (7L * IDLE_MIN * MSEC_PER_SEC)
69
#if defined(X3270_DISPLAY) /*[*/
70
#define FILE_WIDTH 300 /* width of file name widgets */
71
#define MARGIN 3 /* distance from margins to widgets */
72
#define CLOSE_VGAP 0 /* distance between paired toggles */
73
#define FAR_VGAP 10 /* distance between single toggles and groups */
74
#define BUTTON_GAP 5 /* horizontal distance between buttons */
77
#define BN (Boolean *)NULL
80
#if defined(X3270_DISPLAY) && defined(X3270_MENUS) /*[*/
81
extern Pixmap diamond;
82
extern Pixmap no_diamond;
88
Boolean idle_changed = False;
89
char *idle_command = CN;
90
char *idle_timeout_string = CN;
91
enum idle_enum idle_user_enabled = IDLE_DISABLED;
94
static Boolean idle_enabled = False; /* validated and user-enabled */
95
static unsigned long idle_n = 0L;
96
static unsigned long idle_multiplier = IDLE_SEC;
97
static unsigned long idle_id;
98
static unsigned long idle_ms;
99
static Boolean idle_randomize = False;
100
static Boolean idle_ticking = False;
102
static void idle_in3270(Boolean in3270);
103
static int process_timeout_value(char *t);
105
#if defined(X3270_DISPLAY) && defined(X3270_MENUS) /*[*/
106
static enum idle_enum s_disabled = IDLE_DISABLED;
107
static enum idle_enum s_session = IDLE_SESSION;
108
static enum idle_enum s_perm = IDLE_PERM;
109
static char hms = 'm';
110
static Boolean fuzz = False;
111
static char s_hours = 'h';
112
static char s_minutes = 'm';
113
static char s_seconds = 's';
114
static Widget idle_dialog, idle_shell, command_value, timeout_value;
115
static Widget enable_toggle, enable_perm_toggle, disable_toggle;
116
static Widget hours_toggle, minutes_toggle, seconds_toggle, fuzz_toggle;
117
static sr_t *idle_sr = (sr_t *)NULL;
119
static void idle_cancel(Widget w, XtPointer client_data, XtPointer call_data);
120
static void idle_popup_callback(Widget w, XtPointer client_data,
121
XtPointer call_data);
122
static void idle_popup_init(void);
123
static int idle_start(void);
124
static void okay_callback(Widget w, XtPointer call_parms,
125
XtPointer call_data);
126
static void toggle_enable(Widget w, XtPointer client_data,
127
XtPointer call_data);
128
static void mark_toggle(Widget w, Pixmap p);
129
static void toggle_hms(Widget w, XtPointer client_data,
130
XtPointer call_data);
131
static void toggle_fuzz(Widget w, XtPointer client_data,
132
XtPointer call_data);
135
/* Initialization. */
141
/* Register for state changes. */
142
register_schange(ST_3270_MODE, idle_in3270);
143
register_schange(ST_CONNECT, idle_in3270);
145
/* Get values from resources. */
146
cmd = appres.idle_command;
147
idle_command = cmd? NewString(cmd): CN;
148
tmo = appres.idle_timeout;
149
idle_timeout_string = tmo? NewString(tmo): CN;
150
if (appres.idle_command_enabled)
151
idle_user_enabled = IDLE_PERM;
153
idle_user_enabled = IDLE_DISABLED;
154
if (idle_user_enabled &&
155
idle_command != CN &&
156
process_timeout_value(idle_timeout_string) == 0)
159
/* Seed the random number generator (we seem to be the only user). */
160
#if defined(_WIN32) /*[*/
168
* Process a timeout value: <empty> or ~?[0-9]+[HhMmSs]
169
* Returns 0 for success, -1 for failure.
170
* Sets idle_ms and idle_randomize as side-effects.
173
process_timeout_value(char *t)
178
if (s == CN || *s == '\0') {
180
idle_randomize = True;
185
idle_randomize = True;
188
idle_n = strtoul(s, &ptr, 0);
194
idle_multiplier = IDLE_HR;
198
idle_multiplier = IDLE_MIN;
203
idle_multiplier = IDLE_SEC;
208
idle_ms = idle_n * idle_multiplier * MSEC_PER_SEC;
212
popup_an_error("Invalid idle timeout value '%s'", t);
214
idle_randomize = False;
218
/* Called when a host connects or disconnects. */
220
idle_in3270(Boolean in3270 _is_unused)
225
/* Not in 3270 mode any more, turn off the timeout. */
227
RemoveTimeOut(idle_id);
228
idle_ticking = False;
231
/* If the user didn't want it to be permanent, disable it. */
232
if (idle_user_enabled != IDLE_PERM)
233
idle_user_enabled = IDLE_DISABLED;
243
trace_event("Idle timeout\n");
244
idle_ticking = False;
245
push_idle(idle_command);
250
* Reset (and re-enable) the idle timer. Called when the user presses a key or
251
* clicks with the mouse.
254
reset_idle_timer(void)
257
unsigned long idle_ms_now;
260
RemoveTimeOut(idle_id);
261
idle_ticking = False;
263
idle_ms_now = idle_ms;
264
if (idle_randomize) {
265
idle_ms_now = idle_ms;
266
#if defined(_WIN32) /*[*/
267
idle_ms_now -= rand() % (idle_ms / 10L);
269
idle_ms_now -= random() % (idle_ms / 10L);
272
#if defined(DEBUG_IDLE_TIMEOUT) /*[*/
273
trace_event("Setting idle timeout to %lu\n", idle_ms_now);
275
idle_id = AddTimeOut(idle_ms_now, idle_timeout);
281
* Cancel the idle timer. This is called when there is an error in
282
* processing the idle command.
285
cancel_idle_timer(void)
288
RemoveTimeOut(idle_id);
289
idle_ticking = False;
291
idle_enabled = False;
295
get_idle_command(void)
301
get_idle_timeout(void)
303
return idle_timeout_string;
306
#if defined(X3270_DISPLAY) && defined(X3270_MENUS) /*[*/
307
/* "Idle Command" dialog. */
310
* Pop up the "Idle" menu.
311
* Called back from the "Configure Idle Command" option on the Options menu.
320
if (idle_shell == (Widget)NULL)
324
* Split the idle_timeout_string (the raw resource value) into fuzz,
325
* a number, and h/m/s.
327
its = NewString(idle_timeout_string);
357
/* Set the resource values. */
358
dialog_set(&idle_sr, idle_dialog);
359
XtVaSetValues(command_value,
360
XtNstring, idle_command,
362
XtVaSetValues(timeout_value, XtNstring, its, NULL);
363
mark_toggle(enable_toggle, (idle_user_enabled == IDLE_SESSION)?
364
diamond : no_diamond);
365
mark_toggle(enable_perm_toggle, (idle_user_enabled == IDLE_PERM)?
366
diamond : no_diamond);
367
mark_toggle(disable_toggle, (idle_user_enabled == IDLE_DISABLED)?
368
diamond : no_diamond);
369
mark_toggle(hours_toggle, (hms == 'h') ? diamond : no_diamond);
370
mark_toggle(minutes_toggle, (hms == 'm') ? diamond : no_diamond);
371
mark_toggle(seconds_toggle, (hms == 's') ? diamond : no_diamond);
372
mark_toggle(fuzz_toggle, fuzz ? dot : no_dot);
375
popup_popup(idle_shell, XtGrabNone);
378
/* Initialize the idle pop-up. */
380
idle_popup_init(void)
383
Widget cancel_button;
384
Widget command_label, timeout_label;
387
/* Prime the dialog functions. */
388
dialog_set(&idle_sr, idle_dialog);
390
/* Create the menu shell. */
391
idle_shell = XtVaCreatePopupShell(
392
"idlePopup", transientShellWidgetClass, toplevel,
394
XtAddCallback(idle_shell, XtNpopupCallback, place_popup,
396
XtAddCallback(idle_shell, XtNpopupCallback, idle_popup_callback,
399
/* Create the form within the shell. */
400
idle_dialog = XtVaCreateManagedWidget(
401
ObjDialog, formWidgetClass, idle_shell,
404
/* Create the file name widgets. */
405
command_label = XtVaCreateManagedWidget(
406
"command", labelWidgetClass, idle_dialog,
407
XtNvertDistance, FAR_VGAP,
408
XtNhorizDistance, MARGIN,
411
command_value = XtVaCreateManagedWidget(
412
"value", asciiTextWidgetClass, idle_dialog,
413
XtNeditType, XawtextEdit,
414
XtNwidth, FILE_WIDTH,
415
XtNvertDistance, FAR_VGAP,
416
XtNfromHoriz, command_label,
419
dialog_match_dimension(command_label, command_value, XtNheight);
420
w = XawTextGetSource(command_value);
422
XtWarning("Cannot find text source in dialog");
424
XtAddCallback(w, XtNcallback, dialog_text_callback,
425
(XtPointer)&t_command);
426
dialog_register_sensitivity(command_value,
431
timeout_label = XtVaCreateManagedWidget(
432
"timeout", labelWidgetClass, idle_dialog,
433
XtNfromVert, command_label,
435
XtNhorizDistance, MARGIN,
438
timeout_value = XtVaCreateManagedWidget(
439
"value", asciiTextWidgetClass, idle_dialog,
440
XtNeditType, XawtextEdit,
441
XtNwidth, FILE_WIDTH,
442
XtNdisplayCaret, False,
443
XtNfromVert, command_label,
445
XtNfromHoriz, timeout_label,
448
dialog_match_dimension(timeout_label, timeout_value, XtNheight);
449
dialog_match_dimension(command_label, timeout_label, XtNwidth);
450
w = XawTextGetSource(timeout_value);
452
XtWarning("Cannot find text source in dialog");
454
XtAddCallback(w, XtNcallback, dialog_text_callback,
455
(XtPointer)&t_numeric);
456
dialog_register_sensitivity(timeout_value,
461
/* Create the hour/minute/seconds radio buttons. */
462
hours_toggle = XtVaCreateManagedWidget(
463
"hours", commandWidgetClass, idle_dialog,
464
XtNfromVert, timeout_value,
465
XtNvertDistance, CLOSE_VGAP,
466
XtNhorizDistance, MARGIN,
470
dialog_apply_bitmap(hours_toggle, no_diamond);
471
XtAddCallback(hours_toggle, XtNcallback, toggle_hms,
472
(XtPointer)&s_hours);
473
minutes_toggle = XtVaCreateManagedWidget(
474
"minutes", commandWidgetClass, idle_dialog,
475
XtNfromVert, timeout_value,
476
XtNvertDistance, CLOSE_VGAP,
477
XtNfromHoriz, hours_toggle,
478
XtNhorizDistance, MARGIN,
482
dialog_apply_bitmap(minutes_toggle, diamond);
483
XtAddCallback(minutes_toggle, XtNcallback, toggle_hms,
484
(XtPointer)&s_minutes);
485
seconds_toggle = XtVaCreateManagedWidget(
486
"seconds", commandWidgetClass, idle_dialog,
487
XtNfromVert, timeout_value,
488
XtNvertDistance, CLOSE_VGAP,
489
XtNfromHoriz, minutes_toggle,
490
XtNhorizDistance, MARGIN,
494
dialog_apply_bitmap(seconds_toggle, no_diamond);
495
XtAddCallback(seconds_toggle, XtNcallback, toggle_hms,
496
(XtPointer)&s_seconds);
498
/* Create the fuzz toggle. */
499
fuzz_toggle = XtVaCreateManagedWidget(
500
"fuzz", commandWidgetClass, idle_dialog,
501
XtNfromVert, hours_toggle,
502
XtNvertDistance, CLOSE_VGAP,
503
XtNhorizDistance, MARGIN,
507
dialog_apply_bitmap(fuzz_toggle, no_dot);
508
XtAddCallback(fuzz_toggle, XtNcallback, toggle_fuzz, (XtPointer)NULL);
510
/* Create enable/disable toggles. */
511
enable_toggle = XtVaCreateManagedWidget(
512
"enable", commandWidgetClass, idle_dialog,
513
XtNfromVert, fuzz_toggle,
514
XtNvertDistance, FAR_VGAP,
515
XtNhorizDistance, MARGIN,
518
dialog_apply_bitmap(enable_toggle,
519
(idle_user_enabled == IDLE_SESSION)?
520
diamond : no_diamond);
521
XtAddCallback(enable_toggle, XtNcallback, toggle_enable,
522
(XtPointer)&s_session);
523
enable_perm_toggle = XtVaCreateManagedWidget(
524
"enablePerm", commandWidgetClass, idle_dialog,
525
XtNfromVert, enable_toggle,
526
XtNvertDistance, CLOSE_VGAP,
527
XtNhorizDistance, MARGIN,
530
dialog_apply_bitmap(enable_perm_toggle,
531
(idle_user_enabled == IDLE_PERM)?
532
diamond : no_diamond);
533
XtAddCallback(enable_perm_toggle, XtNcallback, toggle_enable,
535
disable_toggle = XtVaCreateManagedWidget(
536
"disable", commandWidgetClass, idle_dialog,
537
XtNfromVert, enable_perm_toggle,
538
XtNvertDistance, CLOSE_VGAP,
539
XtNhorizDistance, MARGIN,
542
dialog_apply_bitmap(disable_toggle,
543
(idle_user_enabled == IDLE_DISABLED)?
544
diamond : no_diamond);
545
XtAddCallback(disable_toggle, XtNcallback, toggle_enable,
546
(XtPointer)&s_disabled);
548
/* Set up the buttons at the bottom. */
549
okay_button = XtVaCreateManagedWidget(
550
ObjConfirmButton, commandWidgetClass, idle_dialog,
551
XtNfromVert, disable_toggle,
552
XtNvertDistance, FAR_VGAP,
553
XtNhorizDistance, MARGIN,
555
XtAddCallback(okay_button, XtNcallback, okay_callback,
558
cancel_button = XtVaCreateManagedWidget(
559
ObjCancelButton, commandWidgetClass, idle_dialog,
560
XtNfromVert, disable_toggle,
561
XtNvertDistance, FAR_VGAP,
562
XtNfromHoriz, okay_button,
563
XtNhorizDistance, BUTTON_GAP,
565
XtAddCallback(cancel_button, XtNcallback, idle_cancel, 0);
568
/* Callbacks for all the idle widgets. */
570
/* Idle pop-up popping up. */
572
idle_popup_callback(Widget w _is_unused, XtPointer client_data _is_unused,
573
XtPointer call_data _is_unused)
575
/* Set the focus to the command widget. */
576
PA_dialog_focus_action(command_value, (XEvent *)NULL, (String *)NULL,
580
/* Cancel button pushed. */
582
idle_cancel(Widget w _is_unused, XtPointer client_data _is_unused,
583
XtPointer call_data _is_unused)
585
XtPopdown(idle_shell);
588
/* OK button pushed. */
590
okay_callback(Widget w _is_unused, XtPointer call_parms _is_unused,
591
XtPointer call_data _is_unused)
593
if (idle_start() == 0) {
595
XtPopdown(idle_shell);
601
mark_toggle(Widget w, Pixmap p)
603
XtVaSetValues(w, XtNleftBitmap, p, NULL);
606
/* Hour/minute/second options. */
608
toggle_hms(Widget w _is_unused, XtPointer client_data,
609
XtPointer call_data _is_unused)
611
/* Toggle the flag */
612
hms = *(char *)client_data;
614
/* Change the widget states. */
615
mark_toggle(hours_toggle, (hms == 'h') ? diamond : no_diamond);
616
mark_toggle(minutes_toggle, (hms == 'm') ? diamond : no_diamond);
617
mark_toggle(seconds_toggle, (hms == 's') ? diamond : no_diamond);
622
toggle_fuzz(Widget w _is_unused, XtPointer client_data,
623
XtPointer call_data _is_unused)
625
/* Toggle the flag */
628
/* Change the widget state. */
629
mark_toggle(fuzz_toggle, fuzz ? dot : no_dot);
632
/* Enable/disable options. */
634
toggle_enable(Widget w _is_unused, XtPointer client_data,
635
XtPointer call_data _is_unused)
637
/* Toggle the flag */
638
idle_user_enabled = *(enum idle_enum *)client_data;
640
/* Change the widget states. */
641
mark_toggle(enable_toggle,
642
(idle_user_enabled == IDLE_SESSION)?
643
diamond: no_diamond);
644
mark_toggle(enable_perm_toggle,
645
(idle_user_enabled == IDLE_PERM)?
646
diamond: no_diamond);
647
mark_toggle(disable_toggle,
648
(idle_user_enabled == IDLE_DISABLED)?
649
diamond: no_diamond);
653
* Called when the user presses the OK button on the idle command dialog.
654
* Returns 0 for success, -1 otherwise.
659
char *cmd, *tmo, *its;
661
/* Update the globals, so the dialog has the same values next time. */
662
XtVaGetValues(command_value, XtNstring, &cmd, NULL);
663
Replace(idle_command, NewString(cmd));
664
XtVaGetValues(timeout_value, XtNstring, &tmo, NULL);
665
its = Malloc(strlen(tmo) + 3);
666
(void) sprintf(its, "%s%s%c", fuzz? "~": "", tmo, hms);
667
Replace(idle_timeout_string, its);
669
/* See if they've turned it off. */
670
if (!idle_user_enabled) {
671
/* If they're turned it off, cancel the timer. */
672
idle_enabled = False;
674
RemoveTimeOut(idle_id);
675
idle_ticking = False;
680
/* They've turned it on, and possibly reconfigured it. */
682
/* Validate the timeout. It should work, yes? */
683
if (process_timeout_value(its) < 0) {
687
/* Seems okay. Reset to the new interval and command. */