mirror of
https://git.tartarus.org/simon/putty.git
synced 2025-06-30 19:12:48 -05:00
New timing infrastructure. There's a new function schedule_timer()
which pretty much any module can call to request a call-back in the future. So terminal.c can do its own handling of blinking, visual bells and deferred screen updates, without having to rely on term_update() being called 50 times a second (fixes: pterm-timer); and ssh.c and telnet.c both invoke a new module pinger.c which takes care of sending keepalives, so they get sent uniformly in all front ends (fixes: plink-keepalives, unix-keepalives). [originally from svn r4906] [this svn revision also touched putty-wishlist]
This commit is contained in:
50
unix/pterm.c
50
unix/pterm.c
@ -40,6 +40,13 @@ GdkAtom compound_text_atom, utf8_string_atom;
|
||||
extern char **pty_argv; /* declared in pty.c */
|
||||
extern int use_pty_argv;
|
||||
|
||||
/*
|
||||
* Timers are global across all sessions (even if we were handling
|
||||
* multiple sessions, which we aren't), so the current timer ID is
|
||||
* a global variable.
|
||||
*/
|
||||
static guint timer_id = 0;
|
||||
|
||||
struct gui_data {
|
||||
GtkWidget *window, *area, *sbar;
|
||||
GtkBox *hbox;
|
||||
@ -1022,7 +1029,6 @@ gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data)
|
||||
|
||||
show_mouseptr(inst, 0);
|
||||
term_seen_key_event(inst->term);
|
||||
term_out(inst->term);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
@ -1130,9 +1136,9 @@ void frontend_keypress(void *handle)
|
||||
exit(0);
|
||||
}
|
||||
|
||||
gint timer_func(gpointer data)
|
||||
void notify_remote_exit(void *frontend)
|
||||
{
|
||||
struct gui_data *inst = (struct gui_data *)data;
|
||||
struct gui_data *inst = (struct gui_data *)frontend;
|
||||
int exitcode;
|
||||
|
||||
if (!inst->exited &&
|
||||
@ -1153,10 +1159,40 @@ gint timer_func(gpointer data)
|
||||
}
|
||||
gtk_widget_show(inst->restartitem);
|
||||
}
|
||||
}
|
||||
|
||||
term_update(inst->term);
|
||||
term_blink(inst->term, 0);
|
||||
return TRUE;
|
||||
static gint timer_trigger(gpointer data)
|
||||
{
|
||||
long now = GPOINTER_TO_INT(data);
|
||||
long next;
|
||||
long ticks;
|
||||
|
||||
if (run_timers(now, &next)) {
|
||||
ticks = next - GETTICKCOUNT();
|
||||
timer_id = gtk_timeout_add(ticks > 0 ? ticks : 1, timer_trigger,
|
||||
GINT_TO_POINTER(next));
|
||||
}
|
||||
|
||||
/*
|
||||
* Never let a timer resume. If we need another one, we've
|
||||
* asked for it explicitly above.
|
||||
*/
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void timer_change_notify(long next)
|
||||
{
|
||||
long ticks;
|
||||
|
||||
if (timer_id)
|
||||
gtk_timeout_remove(timer_id);
|
||||
|
||||
ticks = next - GETTICKCOUNT();
|
||||
if (ticks <= 0)
|
||||
ticks = 1; /* just in case */
|
||||
|
||||
timer_id = gtk_timeout_add(ticks, timer_trigger,
|
||||
GINT_TO_POINTER(next));
|
||||
}
|
||||
|
||||
void fd_input_func(gpointer data, gint sourcefd, GdkInputCondition condition)
|
||||
@ -1183,7 +1219,6 @@ gint focus_event(GtkWidget *widget, GdkEventFocus *event, gpointer data)
|
||||
{
|
||||
struct gui_data *inst = (struct gui_data *)data;
|
||||
inst->term->has_focus = event->in;
|
||||
term_out(inst->term);
|
||||
term_update(inst->term);
|
||||
show_mouseptr(inst, 1);
|
||||
return FALSE;
|
||||
@ -3392,7 +3427,6 @@ int pt_main(int argc, char **argv)
|
||||
if (inst->cfg.scrollbar)
|
||||
gtk_signal_connect(GTK_OBJECT(inst->sbar_adjust), "value_changed",
|
||||
GTK_SIGNAL_FUNC(scrollbar_moved), inst);
|
||||
gtk_timeout_add(20, timer_func, inst);
|
||||
gtk_widget_add_events(GTK_WIDGET(inst->area),
|
||||
GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK |
|
||||
GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
|
||||
|
@ -474,6 +474,8 @@ int pty_select_result(int fd, int event)
|
||||
#endif
|
||||
from_backend(pty_frontend, 0, message, strlen(message));
|
||||
}
|
||||
|
||||
notify_remote_exit(pty_frontend);
|
||||
}
|
||||
return !finished;
|
||||
}
|
||||
|
@ -45,8 +45,8 @@ extern Backend pty_backend;
|
||||
/* Simple wraparound timer function */
|
||||
unsigned long getticks(void); /* based on gettimeofday(2) */
|
||||
#define GETTICKCOUNT getticks
|
||||
#define TICKSPERSEC 1000000 /* gettimeofday returns microseconds */
|
||||
#define CURSORBLINK 450000 /* no standard way to set this */
|
||||
#define TICKSPERSEC 1000 /* we choose to use milliseconds */
|
||||
#define CURSORBLINK 450 /* no standard way to set this */
|
||||
|
||||
#define WCHAR wchar_t
|
||||
#define BYTE unsigned char
|
||||
|
@ -35,6 +35,14 @@ void update_specials_menu(void *frontend)
|
||||
{
|
||||
}
|
||||
|
||||
void notify_remote_exit(void *frontend)
|
||||
{
|
||||
}
|
||||
|
||||
void timer_change_notify(long next)
|
||||
{
|
||||
}
|
||||
|
||||
void verify_ssh_host_key(void *frontend, char *host, int port, char *keytype,
|
||||
char *keystr, char *fingerprint)
|
||||
{
|
||||
|
@ -15,14 +15,13 @@ unsigned long getticks(void)
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv, NULL);
|
||||
/*
|
||||
* This will wrap around approximately every 4000 seconds, i.e.
|
||||
* just over an hour, which is more than enough.
|
||||
* We want to use milliseconds rather than microseconds,
|
||||
* because we need a decent number of them to fit into a 32-bit
|
||||
* word so it can be used for keepalives.
|
||||
*/
|
||||
return tv.tv_sec * 1000000 + tv.tv_usec;
|
||||
return tv.tv_sec * 1000 + tv.tv_usec / 1000;
|
||||
}
|
||||
|
||||
|
||||
|
||||
Filename filename_from_str(const char *str)
|
||||
{
|
||||
Filename ret;
|
||||
|
@ -252,6 +252,7 @@ int main(int argc, char **argv)
|
||||
int errors;
|
||||
int use_subsystem = 0;
|
||||
void *ldisc, *logctx;
|
||||
long now;
|
||||
|
||||
ssh_get_line = console_get_line;
|
||||
|
||||
@ -584,6 +585,7 @@ int main(int argc, char **argv)
|
||||
atexit(cleanup_termios);
|
||||
ldisc_update(NULL, 1, 1);
|
||||
sending = FALSE;
|
||||
now = GETTICKCOUNT();
|
||||
|
||||
while (1) {
|
||||
fd_set rset, wset, xset;
|
||||
@ -644,7 +646,23 @@ int main(int argc, char **argv)
|
||||
}
|
||||
|
||||
do {
|
||||
ret = select(maxfd, &rset, &wset, &xset, NULL);
|
||||
long next, ticks;
|
||||
struct timeval tv, *ptv;
|
||||
|
||||
if (run_timers(now, &next)) {
|
||||
ticks = next - GETTICKCOUNT();
|
||||
if (ticks < 0) ticks = 0; /* just in case */
|
||||
tv.tv_sec = ticks / 1000;
|
||||
tv.tv_usec = ticks % 1000 * 1000;
|
||||
ptv = &tv;
|
||||
} else {
|
||||
ptv = NULL;
|
||||
}
|
||||
ret = select(maxfd, &rset, &wset, &xset, ptv);
|
||||
if (ret == 0)
|
||||
now = next;
|
||||
else
|
||||
now = GETTICKCOUNT();
|
||||
} while (ret < 0 && errno == EINTR);
|
||||
|
||||
if (ret < 0) {
|
||||
|
156
unix/uxsftp.c
156
unix/uxsftp.c
@ -321,55 +321,80 @@ char *dir_file_cat(char *dir, char *file)
|
||||
}
|
||||
|
||||
/*
|
||||
* Wait for some network data and process it.
|
||||
* Do a select() between all currently active network fds and
|
||||
* optionally stdin.
|
||||
*/
|
||||
int ssh_sftp_loop_iteration(void)
|
||||
static int ssh_sftp_do_select(int include_stdin)
|
||||
{
|
||||
fd_set rset, wset, xset;
|
||||
int i, fdcount, fdsize, *fdlist;
|
||||
int fd, fdstate, rwx, ret, maxfd;
|
||||
long now = GETTICKCOUNT();
|
||||
|
||||
fdlist = NULL;
|
||||
fdcount = fdsize = 0;
|
||||
|
||||
/* Count the currently active fds. */
|
||||
i = 0;
|
||||
for (fd = first_fd(&fdstate, &rwx); fd >= 0;
|
||||
fd = next_fd(&fdstate, &rwx)) i++;
|
||||
|
||||
if (i < 1)
|
||||
return -1; /* doom */
|
||||
|
||||
/* Expand the fdlist buffer if necessary. */
|
||||
if (i > fdsize) {
|
||||
fdsize = i + 16;
|
||||
fdlist = sresize(fdlist, fdsize, int);
|
||||
}
|
||||
|
||||
FD_ZERO(&rset);
|
||||
FD_ZERO(&wset);
|
||||
FD_ZERO(&xset);
|
||||
maxfd = 0;
|
||||
|
||||
/*
|
||||
* Add all currently open fds to the select sets, and store
|
||||
* them in fdlist as well.
|
||||
*/
|
||||
fdcount = 0;
|
||||
for (fd = first_fd(&fdstate, &rwx); fd >= 0;
|
||||
fd = next_fd(&fdstate, &rwx)) {
|
||||
fdlist[fdcount++] = fd;
|
||||
if (rwx & 1)
|
||||
FD_SET_MAX(fd, maxfd, rset);
|
||||
if (rwx & 2)
|
||||
FD_SET_MAX(fd, maxfd, wset);
|
||||
if (rwx & 4)
|
||||
FD_SET_MAX(fd, maxfd, xset);
|
||||
}
|
||||
|
||||
do {
|
||||
ret = select(maxfd, &rset, &wset, &xset, NULL);
|
||||
} while (ret < 0 && errno == EINTR);
|
||||
|
||||
/* Count the currently active fds. */
|
||||
i = 0;
|
||||
for (fd = first_fd(&fdstate, &rwx); fd >= 0;
|
||||
fd = next_fd(&fdstate, &rwx)) i++;
|
||||
|
||||
if (i < 1)
|
||||
return -1; /* doom */
|
||||
|
||||
/* Expand the fdlist buffer if necessary. */
|
||||
if (i > fdsize) {
|
||||
fdsize = i + 16;
|
||||
fdlist = sresize(fdlist, fdsize, int);
|
||||
}
|
||||
|
||||
FD_ZERO(&rset);
|
||||
FD_ZERO(&wset);
|
||||
FD_ZERO(&xset);
|
||||
maxfd = 0;
|
||||
|
||||
/*
|
||||
* Add all currently open fds to the select sets, and store
|
||||
* them in fdlist as well.
|
||||
*/
|
||||
fdcount = 0;
|
||||
for (fd = first_fd(&fdstate, &rwx); fd >= 0;
|
||||
fd = next_fd(&fdstate, &rwx)) {
|
||||
fdlist[fdcount++] = fd;
|
||||
if (rwx & 1)
|
||||
FD_SET_MAX(fd, maxfd, rset);
|
||||
if (rwx & 2)
|
||||
FD_SET_MAX(fd, maxfd, wset);
|
||||
if (rwx & 4)
|
||||
FD_SET_MAX(fd, maxfd, xset);
|
||||
}
|
||||
|
||||
if (include_stdin)
|
||||
FD_SET_MAX(0, maxfd, rset);
|
||||
|
||||
do {
|
||||
long next, ticks;
|
||||
struct timeval tv, *ptv;
|
||||
|
||||
if (run_timers(now, &next)) {
|
||||
ticks = next - GETTICKCOUNT();
|
||||
if (ticks <= 0)
|
||||
ticks = 1; /* just in case */
|
||||
tv.tv_sec = ticks / 1000;
|
||||
tv.tv_usec = ticks % 1000 * 1000;
|
||||
ptv = &tv;
|
||||
} else {
|
||||
ptv = NULL;
|
||||
}
|
||||
ret = select(maxfd, &rset, &wset, &xset, ptv);
|
||||
if (ret == 0)
|
||||
now = next;
|
||||
else
|
||||
now = GETTICKCOUNT();
|
||||
} while (ret < 0 && errno != EINTR);
|
||||
} while (ret == 0);
|
||||
|
||||
if (ret < 0) {
|
||||
perror("select");
|
||||
@ -393,7 +418,58 @@ int ssh_sftp_loop_iteration(void)
|
||||
|
||||
sfree(fdlist);
|
||||
|
||||
return 0;
|
||||
return FD_ISSET(0, &rset) ? 1 : 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Wait for some network data and process it.
|
||||
*/
|
||||
int ssh_sftp_loop_iteration(void)
|
||||
{
|
||||
return ssh_sftp_do_select(FALSE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Read a PSFTP command line from stdin.
|
||||
*/
|
||||
char *ssh_sftp_get_cmdline(char *prompt)
|
||||
{
|
||||
char *buf;
|
||||
int buflen, bufsize, ret;
|
||||
|
||||
fputs(prompt, stdout);
|
||||
fflush(stdout);
|
||||
|
||||
buf = NULL;
|
||||
buflen = bufsize = 0;
|
||||
|
||||
while (1) {
|
||||
ret = ssh_sftp_do_select(TRUE);
|
||||
if (ret < 0) {
|
||||
printf("connection died\n");
|
||||
return NULL; /* woop woop */
|
||||
}
|
||||
if (ret > 0) {
|
||||
if (buflen >= bufsize) {
|
||||
bufsize = buflen + 512;
|
||||
buf = sresize(buf, bufsize, char);
|
||||
}
|
||||
ret = read(0, buf+buflen, 1);
|
||||
if (ret < 0) {
|
||||
perror("read");
|
||||
return NULL;
|
||||
}
|
||||
if (ret == 0) {
|
||||
/* eof on stdin; no error, but no answer either */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (buf[buflen++] == '\n') {
|
||||
/* we have a full line */
|
||||
return buf;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -105,29 +105,6 @@ static void make_filename(char *filename, int index, const char *subname)
|
||||
filename[FILENAME_MAX-1] = '\0';
|
||||
}
|
||||
|
||||
/*
|
||||
* Read an entire line of text from a file. Return a buffer
|
||||
* malloced to be as big as necessary (caller must free).
|
||||
*/
|
||||
static char *fgetline(FILE *fp)
|
||||
{
|
||||
char *ret = snewn(512, char);
|
||||
int size = 512, len = 0;
|
||||
while (fgets(ret + len, size - len, fp)) {
|
||||
len += strlen(ret + len);
|
||||
if (ret[len-1] == '\n')
|
||||
break; /* got a newline, we're done */
|
||||
size = len + 512;
|
||||
ret = sresize(ret, size, char);
|
||||
}
|
||||
if (len == 0) { /* first fgets returned NULL */
|
||||
sfree(ret);
|
||||
return NULL;
|
||||
}
|
||||
ret[len] = '\0';
|
||||
return ret;
|
||||
}
|
||||
|
||||
void *open_settings_w(const char *sessionname, char **errmsg)
|
||||
{
|
||||
char filename[FILENAME_MAX];
|
||||
|
Reference in New Issue
Block a user