GLOBAL int has_focus;
+GLOBAL int in_vbell;
+GLOBAL long vbell_timeout;
+
GLOBAL int app_cursor_keys, app_keypad_keys, vt52_mode;
GLOBAL int repeat_off, cr_lf_return;
int lfhascr;
int cursor_type; /* 0=block 1=underline 2=vertical */
int blink_cur;
- int beep;
+ int beep; /* 0=none 1=defaultsound 2=visual */
+ int bellovl; /* bell overload protection active? */
+ int bellovl_n; /* number of bells to cause overload */
+ int bellovl_t; /* time interval for overload (seconds) */
+ int bellovl_s; /* period of silence to re-enable bell (s) */
int scrollbar;
int locksize;
int bce;
write_setting_i (sesskey, "CurType", cfg->cursor_type);
write_setting_i (sesskey, "BlinkCur", cfg->blink_cur);
write_setting_i (sesskey, "Beep", cfg->beep);
+ write_setting_i (sesskey, "BellOverload", cfg->bellovl);
+ write_setting_i (sesskey, "BellOverloadN", cfg->bellovl_n);
+ write_setting_i (sesskey, "BellOverloadT", cfg->bellovl_t);
+ write_setting_i (sesskey, "BellOverloadS", cfg->bellovl_s);
write_setting_i (sesskey, "ScrollbackLines", cfg->savelines);
write_setting_i (sesskey, "DECOriginMode", cfg->dec_om);
write_setting_i (sesskey, "AutoWrapMode", cfg->wrap_mode);
gppi (sesskey, "CurType", 0, &cfg->cursor_type);
gppi (sesskey, "BlinkCur", 0, &cfg->blink_cur);
gppi (sesskey, "Beep", 1, &cfg->beep);
+ gppi (sesskey, "BellOverload", 1, &cfg->bellovl);
+ gppi (sesskey, "BellOverloadN", 5, &cfg->bellovl_n);
+ gppi (sesskey, "BellOverloadT", 2, &cfg->bellovl_t);
+ gppi (sesskey, "BellOverloadS", 5, &cfg->bellovl_s);
gppi (sesskey, "ScrollbackLines", 200, &cfg->savelines);
gppi (sesskey, "DECOriginMode", 0, &cfg->dec_om);
gppi (sesskey, "AutoWrapMode", 1, &cfg->wrap_mode);
static unsigned long *wanttext; /* buffer of text we want on screen */
static unsigned long *alttext; /* buffer of text on alt. screen */
+#define VBELL_TIMEOUT 100 /* millisecond duration of visual bell */
+
+struct beeptime {
+ struct beeptime *next;
+ long ticks;
+};
+static struct beeptime *beephead, *beeptail;
+int nbeeps;
+int beep_overloaded;
+long lastbeep;
+
static unsigned char *selspace; /* buffer for building selections in */
#define TSIZE (sizeof(*text))
alt_cset = cset = 0;
cset_attr[0] = cset_attr[1] = ATTR_ASCII;
rvideo = 0;
+ in_vbell = FALSE;
cursor_on = 1;
save_attr = curr_attr = ATTR_DEFAULT;
term_editing = term_echoing = FALSE;
deselect();
rows = cols = -1;
power_on();
+ beephead = beeptail = NULL;
+ nbeeps = 0;
+ lastbeep = FALSE;
+ beep_overloaded = FALSE;
}
/*
void term_out(void) {
int c, inbuf_reap;
-static int beep_overload = 0;
- int beep_count = 0;
-
for(inbuf_reap = 0; inbuf_reap < inbuf_head; inbuf_reap++)
{
c = inbuf[inbuf_reap];
}
break;
case '\007':
- beep_count++;
- if(beep_count>6) beep_overload=1;
- disptop = scrtop;
+ {
+ struct beeptime *newbeep;
+ long ticks;
+
+ ticks = GetTickCount();
+debug(("beep received at %ld, last was %ld, nbeeps=%d\n", ticks, lastbeep, nbeeps));
+
+ if (!beep_overloaded) {
+ newbeep = smalloc(sizeof(struct beeptime));
+ newbeep->ticks = ticks;
+ newbeep->next = NULL;
+ if (!beephead)
+ beephead = newbeep;
+ else
+ beeptail->next = newbeep;
+ beeptail = newbeep;
+ nbeeps++;
+ }
+
+ /*
+ * Throw out any beeps that happened more than
+ * t seconds ago.
+ */
+ while (beephead &&
+ beephead->ticks < ticks - cfg.bellovl_t*1000) {
+ struct beeptime *tmp = beephead;
+ beephead = tmp->next;
+debug(("throwing out beep received at %ld\n", tmp->ticks));
+ sfree(tmp);
+ if (!beephead)
+ beeptail = NULL;
+ nbeeps--;
+ }
+
+ if (cfg.bellovl && beep_overloaded &&
+ ticks-lastbeep >= cfg.bellovl_s * 1000) {
+ /*
+ * If we're currently overloaded and the
+ * last beep was more than s seconds ago,
+ * leave overload mode.
+ */
+debug(("silence reigns, leaving overload mode\n"));
+ beep_overloaded = FALSE;
+ } else if (cfg.bellovl && !beep_overloaded &&
+ nbeeps >= cfg.bellovl_n) {
+ /*
+ * Now, if we have n or more beeps
+ * remaining in the queue, go into overload
+ * mode.
+ */
+debug(("%d beeps between times %ld and %ld, overload!\n",
+ nbeeps, beephead->ticks, ticks));
+ beep_overloaded = TRUE;
+ }
+ lastbeep = ticks;
+
+ /*
+ * Perform an actual beep if we're not overloaded.
+ */
+ if ((!cfg.bellovl || !beep_overloaded) && cfg.beep != 0) {
+debug(("not overloaded; performing a beep\n"));
+ if (cfg.beep != 2)
+ beep(cfg.beep);
+ else if(cfg.beep == 2) {
+ in_vbell = TRUE;
+ vbell_timeout = ticks + VBELL_TIMEOUT;
+ term_update();
+ }
+ }
+ disptop = scrtop;
+ }
break;
case '\b':
if (curs_x == 0 && curs_y == 0)
check_selection (cpos, cpos+1);
}
inbuf_head = 0;
-
- if (beep_overload)
- {
- if(!beep_count) beep_overload=0;
- }
- else if(beep_count && beep_count<5 && cfg.beep)
- beep(beep_count/3);
}
/*
int i, j, start, our_curs_y;
unsigned long attr, rv, cursor;
char ch[1024];
+ long ticks;
+ /*
+ * Check the visual bell state.
+ */
+ if (in_vbell) {
+ ticks = GetTickCount();
+ if (ticks - vbell_timeout >= 0)
+ in_vbell = FALSE;
+ }
+
+ /* Depends on:
+ * screen array, disptop, scrtop,
+ * selection, rv,
+ * cfg.blinkpc, blink_is_real, tblinker,
+ * curs_y, curs_x, blinker, cfg.blink_cur, cursor_on, has_focus
+ */
if (cursor_on) {
if (has_focus) {
if (blinker || !cfg.blink_cur)
if (wrapnext)
cursor |= ATTR_RIGHTCURS;
}
- else cursor = 0;
- rv = (rvideo ? ATTR_REVERSE : 0);
+ else
+ cursor = 0;
+ rv = (!rvideo ^ !in_vbell ? ATTR_REVERSE : 0);
our_curs_y = curs_y + (scrtop - disptop) / (cols+1);
for (i=0; i<rows; i++) {
sessionpanelend,
loggingpanelstart,
+ IDC_TITLE_LOGGING,
IDC_BOX_LOGGING1,
IDC_LSTATSTATIC,
IDC_LSTATOFF,
IDC_WRAPMODE,
IDC_DECOM,
IDC_LFHASCR,
- IDC_BEEP,
IDC_BCE,
IDC_BLINKTEXT,
IDC_ANSWERBACK,
IDC_EDITNO,
terminalpanelend,
+ bellpanelstart,
+ IDC_TITLE_BELL,
+ IDC_BOX_BELL1,
+ IDC_BOX_BELL2,
+ IDC_BELLSTATIC,
+ IDC_BELL_DISABLED,
+ IDC_BELL_DEFAULT,
+ IDC_BELL_VISUAL,
+ IDC_BELLOVL,
+ IDC_BELLOVLNSTATIC,
+ IDC_BELLOVLN,
+ IDC_BELLOVLTSTATIC,
+ IDC_BELLOVLT,
+ IDC_BELLOVLEXPLAIN,
+ IDC_BELLOVLSSTATIC,
+ IDC_BELLOVLS,
+ bellpanelend,
+
windowpanelstart,
IDC_TITLE_WINDOW,
IDC_BOX_WINDOW1,
SetDlgItemInt (hwnd, IDC_SAVEEDIT, cfg.savelines, FALSE);
fmtfont (fontstatic);
SetDlgItemText (hwnd, IDC_FONTSTATIC, fontstatic);
- CheckDlgButton (hwnd, IDC_BEEP, cfg.beep);
+ CheckRadioButton (hwnd, IDC_BELL_DISABLED, IDC_BELL_VISUAL,
+ cfg.beep==0 ? IDC_BELL_DISABLED :
+ cfg.beep==1 ? IDC_BELL_DEFAULT : IDC_BELL_VISUAL);
+ CheckDlgButton (hwnd, IDC_BELLOVL, cfg.bellovl);
+ SetDlgItemInt (hwnd, IDC_BELLOVLN, cfg.bellovl_n, FALSE);
+ SetDlgItemInt (hwnd, IDC_BELLOVLT, cfg.bellovl_t, FALSE);
+ SetDlgItemInt (hwnd, IDC_BELLOVLS, cfg.bellovl_s, FALSE);
+
CheckDlgButton (hwnd, IDC_BCE, cfg.bce);
CheckDlgButton (hwnd, IDC_BLINKTEXT, cfg.blinktext);
struct ctlpos cp;
ctlposinit(&cp, hwnd, 80, 3, 13);
bartitle(&cp, "Options controlling session logging",
- IDC_TITLE_TERMINAL);
+ IDC_TITLE_LOGGING);
beginbox(&cp, NULL, IDC_BOX_LOGGING1);
radiobig(&cp,
"Session logging:", IDC_LSTATSTATIC,
}
if (panel == terminalpanelstart) {
- /* The Terminal panel. Accelerators used: [acgo] wdlben hts */
+ /* The Terminal panel. Accelerators used: [acgo] wdlen hts */
struct ctlpos cp;
ctlposinit(&cp, hwnd, 80, 3, 13);
bartitle(&cp, "Options controlling the terminal emulation",
checkbox(&cp, "Auto &wrap mode initially on", IDC_WRAPMODE);
checkbox(&cp, "&DEC Origin Mode initially on", IDC_DECOM);
checkbox(&cp, "Implicit CR in every &LF", IDC_LFHASCR);
- checkbox(&cp, "&Beep enabled", IDC_BEEP);
checkbox(&cp, "Use background colour to &erase screen", IDC_BCE);
checkbox(&cp, "Enable bli&nking text", IDC_BLINKTEXT);
multiedit(&cp,
endbox(&cp);
}
+ if (panel == bellpanelstart) {
+ /* The Bell panel. Accelerators used: [acgo] bdsm */
+ struct ctlpos cp;
+ ctlposinit(&cp, hwnd, 80, 3, 13);
+ bartitle(&cp, "Options controlling the terminal bell",
+ IDC_TITLE_BELL);
+ beginbox(&cp, "Set the style of bell",
+ IDC_BOX_BELL1);
+ radiobig(&cp,
+ "Action to happen when a &bell occurs:", IDC_BELLSTATIC,
+ "None (bell disabled)", IDC_BELL_DISABLED,
+ "Play Windows Default Sound", IDC_BELL_DEFAULT,
+ "Visual bell (flash window)", IDC_BELL_VISUAL, NULL);
+ endbox(&cp);
+ beginbox(&cp, "Control the bell overload behaviour",
+ IDC_BOX_BELL2);
+ checkbox(&cp, "Bell is temporarily &disabled when over-used",
+ IDC_BELLOVL);
+ staticedit(&cp, "Over-use means this &many bells...",
+ IDC_BELLOVLNSTATIC, IDC_BELLOVLN, 20);
+ staticedit(&cp, "... in this many &seconds",
+ IDC_BELLOVLTSTATIC, IDC_BELLOVLT, 20);
+ statictext(&cp, "The bell is re-enabled after a few seconds of silence.",
+ IDC_BELLOVLEXPLAIN);
+ staticedit(&cp, "Seconds of silence required",
+ IDC_BELLOVLSSTATIC, IDC_BELLOVLS, 20);
+ endbox(&cp);
+ }
+
if (panel == keyboardpanelstart) {
/* The Keyboard panel. Accelerators used: [acgo] h?sr~lxvunpymietd */
struct ctlpos cp;
treeview_insert(&tvfaff, 1, "Logging");
treeview_insert(&tvfaff, 0, "Terminal");
treeview_insert(&tvfaff, 1, "Keyboard");
+ treeview_insert(&tvfaff, 1, "Bell");
treeview_insert(&tvfaff, 0, "Window");
treeview_insert(&tvfaff, 1, "Appearance");
treeview_insert(&tvfaff, 1, "Translation");
create_controls(hwnd, dlgtype, keyboardpanelstart);
if (!strcmp(buffer, "Terminal"))
create_controls(hwnd, dlgtype, terminalpanelstart);
+ if (!strcmp(buffer, "Bell"))
+ create_controls(hwnd, dlgtype, bellpanelstart);
if (!strcmp(buffer, "Window"))
create_controls(hwnd, dlgtype, windowpanelstart);
if (!strcmp(buffer, "Appearance"))
SetDlgItemText (hwnd, IDC_FONTSTATIC, fontstatic);
}
break;
- case IDC_BEEP:
+ case IDC_BELL_DISABLED:
+ case IDC_BELL_DEFAULT:
+ case IDC_BELL_VISUAL:
+ if (HIWORD(wParam) == BN_CLICKED ||
+ HIWORD(wParam) == BN_DOUBLECLICKED) {
+ if (LOWORD(wParam)==IDC_BELL_DISABLED) cfg.beep = 0;
+ if (LOWORD(wParam)==IDC_BELL_DEFAULT) cfg.beep = 1;
+ if (LOWORD(wParam)==IDC_BELL_VISUAL) cfg.beep = 2;
+ }
+ break;
+ case IDC_BELLOVL:
if (HIWORD(wParam) == BN_CLICKED ||
HIWORD(wParam) == BN_DOUBLECLICKED)
- cfg.beep = IsDlgButtonChecked (hwnd, IDC_BEEP);
+ cfg.bellovl = IsDlgButtonChecked (hwnd, IDC_BELLOVL);
break;
+ case IDC_BELLOVLN:
+ if (HIWORD(wParam) == EN_CHANGE)
+ MyGetDlgItemInt (hwnd, IDC_BELLOVLN, &cfg.bellovl_n);
+ break;
+ case IDC_BELLOVLT:
+ if (HIWORD(wParam) == EN_CHANGE)
+ MyGetDlgItemInt (hwnd, IDC_BELLOVLT, &cfg.bellovl_t);
+ break;
+ case IDC_BELLOVLS:
+ if (HIWORD(wParam) == EN_CHANGE)
+ MyGetDlgItemInt (hwnd, IDC_BELLOVLS, &cfg.bellovl_s);
+ break;
case IDC_BLINKTEXT:
if (HIWORD(wParam) == BN_CLICKED ||
HIWORD(wParam) == BN_DOUBLECLICKED)
term_out();
term_update();
ShowCaret(hwnd);
- if (!has_focus)
+ if (in_vbell)
+ /* Hmm, term_update didn't want to do an update too soon ... */
+ timer_id = SetTimer(hwnd, 1, 50, NULL);
+ else if (!has_focus)
timer_id = SetTimer(hwnd, 1, 59500, NULL);
else
timer_id = SetTimer(hwnd, 1, 100, NULL);
long_timer = 1;
/* There's no point rescanning everything in the message queue
- * so we do an apperently unneccesary wait here
+ * so we do an apparently unnecessary wait here
*/
WaitMessage();
if (GetMessage (&msg, NULL, 0, 0) != 1)
/*
* Beep.
*/
-void beep(int errorbeep) {
- static long last_beep = 0;
- long now, beep_diff;
-
- now = GetTickCount();
- beep_diff = now-last_beep;
-
- /* Make sure we only respond to one beep per packet or so */
- if (beep_diff>=0 && beep_diff<50)
- return;
-
- if(errorbeep)
- MessageBeep(MB_ICONHAND);
- else
- MessageBeep(MB_OK);
-
- last_beep = GetTickCount();
+void beep(int mode) {
+ if (mode == 1)
+ MessageBeep(MB_OK);
}