version 1.17, 2009/11/05 00:05:00 |
version 1.18, 2009/11/05 08:45:08 |
|
|
|
|
#include "tmux.h" |
#include "tmux.h" |
|
|
void server_client_handle_data(struct client *); |
void server_client_handle_key(int, struct mouse_event *, void *); |
void server_client_repeat_timer(int, short, void *); |
void server_client_repeat_timer(int, short, void *); |
void server_client_check_redraw(struct client *); |
void server_client_check_redraw(struct client *); |
void server_client_set_title(struct client *); |
void server_client_set_title(struct client *); |
|
void server_client_reset_state(struct client *); |
|
|
int server_client_msg_dispatch(struct client *); |
int server_client_msg_dispatch(struct client *); |
void server_client_msg_command(struct client *, struct msg_command_data *); |
void server_client_msg_command(struct client *, struct msg_command_data *); |
|
|
} |
} |
} |
} |
|
|
/* Client functions that need to happen every loop. */ |
/* Handle data key input from client. */ |
void |
void |
server_client_loop(void) |
server_client_handle_key(int key, struct mouse_event *mouse, void *data) |
{ |
{ |
struct client *c; |
struct client *c = data; |
|
struct session *s; |
struct window *w; |
struct window *w; |
struct window_pane *wp; |
struct window_pane *wp; |
u_int i; |
|
|
|
for (i = 0; i < ARRAY_LENGTH(&clients); i++) { |
|
c = ARRAY_ITEM(&clients, i); |
|
if (c == NULL || c->session == NULL) |
|
continue; |
|
|
|
server_client_handle_data(c); |
|
if (c->session != NULL) |
|
server_client_check_redraw(c); |
|
} |
|
|
|
/* |
|
* Any windows will have been redrawn as part of clients, so clear |
|
* their flags now. |
|
*/ |
|
for (i = 0; i < ARRAY_LENGTH(&windows); i++) { |
|
w = ARRAY_ITEM(&windows, i); |
|
if (w == NULL) |
|
continue; |
|
|
|
w->flags &= ~WINDOW_REDRAW; |
|
TAILQ_FOREACH(wp, &w->panes, entry) |
|
wp->flags &= ~PANE_REDRAW; |
|
} |
|
} |
|
|
|
/* Handle data input or output from client. */ |
|
void |
|
server_client_handle_data(struct client *c) |
|
{ |
|
struct window *w; |
|
struct window_pane *wp; |
|
struct screen *s; |
|
struct options *oo; |
struct options *oo; |
struct timeval tv, tv_now; |
struct timeval tv; |
struct key_binding *bd; |
struct key_binding *bd; |
struct keylist *keylist; |
struct keylist *keylist; |
struct mouse_event mouse; |
int xtimeout, isprefix; |
int key, status, xtimeout, mode, isprefix; |
|
u_int i; |
u_int i; |
|
|
/* Get the time for the activity timer. */ |
/* Check the client is good to accept input. */ |
if (gettimeofday(&tv_now, NULL) != 0) |
if ((c->flags & (CLIENT_DEAD|CLIENT_SUSPENDED)) != 0) |
|
return; |
|
if (c->session == NULL) |
|
return; |
|
s = c->session; |
|
|
|
/* Update the activity timer. */ |
|
if (gettimeofday(&c->activity_time, NULL) != 0) |
fatal("gettimeofday failed"); |
fatal("gettimeofday failed"); |
xtimeout = options_get_number(&c->session->options, "repeat-time"); |
memcpy(&s->activity_time, &c->activity_time, sizeof s->activity_time); |
|
|
/* Process keys. */ |
w = c->session->curw->window; |
keylist = options_get_data(&c->session->options, "prefix"); |
wp = w->active; |
while (tty_keys_next(&c->tty, &key, &mouse) == 0) { |
oo = &c->session->options; |
if (c->session == NULL) |
|
return; |
|
w = c->session->curw->window; |
|
wp = w->active; /* could die */ |
|
oo = &c->session->options; |
|
|
|
/* Update activity timer. */ |
/* Special case: number keys jump to pane in identify mode. */ |
memcpy(&c->activity_time, &tv_now, sizeof c->activity_time); |
if (c->flags & CLIENT_IDENTIFY && key >= '0' && key <= '9') { |
memcpy(&c->session->activity_time, |
wp = window_pane_at_index(w, key - '0'); |
&tv_now, sizeof c->session->activity_time); |
if (wp != NULL && window_pane_visible(wp)) |
|
window_set_active_pane(w, wp); |
/* Special case: number keys jump to pane in identify mode. */ |
|
if (c->flags & CLIENT_IDENTIFY && key >= '0' && key <= '9') { |
|
wp = window_pane_at_index(w, key - '0'); |
|
if (wp != NULL && window_pane_visible(wp)) |
|
window_set_active_pane(w, wp); |
|
server_clear_identify(c); |
|
continue; |
|
} |
|
|
|
status_message_clear(c); |
|
server_clear_identify(c); |
server_clear_identify(c); |
if (c->prompt_string != NULL) { |
return; |
status_prompt_key(c, key); |
} |
continue; |
|
} |
|
|
|
/* Check for mouse keys. */ |
/* Handle status line. */ |
if (key == KEYC_MOUSE) { |
status_message_clear(c); |
if (options_get_number(oo, "mouse-select-pane")) { |
server_clear_identify(c); |
window_set_active_at(w, mouse.x, mouse.y); |
if (c->prompt_string != NULL) { |
wp = w->active; |
status_prompt_key(c, key); |
} |
return; |
window_pane_mouse(wp, c, &mouse); |
} |
continue; |
|
} |
|
|
|
/* Is this a prefix key? */ |
/* Check for mouse keys. */ |
isprefix = 0; |
if (key == KEYC_MOUSE) { |
for (i = 0; i < ARRAY_LENGTH(keylist); i++) { |
if (options_get_number(oo, "mouse-select-pane")) { |
if (key == ARRAY_ITEM(keylist, i)) { |
window_set_active_at(w, mouse->x, mouse->y); |
isprefix = 1; |
wp = w->active; |
break; |
|
} |
|
} |
} |
|
window_pane_mouse(wp, c, mouse); |
|
return; |
|
} |
|
|
/* No previous prefix key. */ |
/* Is this a prefix key? */ |
if (!(c->flags & CLIENT_PREFIX)) { |
keylist = options_get_data(&c->session->options, "prefix"); |
if (isprefix) |
isprefix = 0; |
c->flags |= CLIENT_PREFIX; |
for (i = 0; i < ARRAY_LENGTH(keylist); i++) { |
else { |
if (key == ARRAY_ITEM(keylist, i)) { |
/* Try as a non-prefix key binding. */ |
isprefix = 1; |
if ((bd = key_bindings_lookup(key)) == NULL) |
break; |
window_pane_key(wp, c, key); |
|
else |
|
key_bindings_dispatch(bd, c); |
|
} |
|
continue; |
|
} |
} |
|
} |
|
|
/* Prefix key already pressed. Reset prefix and lookup key. */ |
/* No previous prefix key. */ |
c->flags &= ~CLIENT_PREFIX; |
if (!(c->flags & CLIENT_PREFIX)) { |
if ((bd = key_bindings_lookup(key | KEYC_PREFIX)) == NULL) { |
if (isprefix) |
/* If repeating, treat this as a key, else ignore. */ |
c->flags |= CLIENT_PREFIX; |
if (c->flags & CLIENT_REPEAT) { |
else { |
c->flags &= ~CLIENT_REPEAT; |
/* Try as a non-prefix key binding. */ |
if (isprefix) |
if ((bd = key_bindings_lookup(key)) == NULL) |
c->flags |= CLIENT_PREFIX; |
window_pane_key(wp, c, key); |
else |
else |
window_pane_key(wp, c, key); |
key_bindings_dispatch(bd, c); |
} |
|
continue; |
|
} |
} |
|
return; |
|
} |
|
|
/* If already repeating, but this key can't repeat, skip it. */ |
/* Prefix key already pressed. Reset prefix and lookup key. */ |
if (c->flags & CLIENT_REPEAT && !bd->can_repeat) { |
c->flags &= ~CLIENT_PREFIX; |
|
if ((bd = key_bindings_lookup(key | KEYC_PREFIX)) == NULL) { |
|
/* If repeating, treat this as a key, else ignore. */ |
|
if (c->flags & CLIENT_REPEAT) { |
c->flags &= ~CLIENT_REPEAT; |
c->flags &= ~CLIENT_REPEAT; |
if (isprefix) |
if (isprefix) |
c->flags |= CLIENT_PREFIX; |
c->flags |= CLIENT_PREFIX; |
else |
else |
window_pane_key(wp, c, key); |
window_pane_key(wp, c, key); |
continue; |
|
} |
} |
|
return; |
|
} |
|
|
/* If this key can repeat, reset the repeat flags and timer. */ |
/* If already repeating, but this key can't repeat, skip it. */ |
if (xtimeout != 0 && bd->can_repeat) { |
if (c->flags & CLIENT_REPEAT && !bd->can_repeat) { |
c->flags |= CLIENT_PREFIX|CLIENT_REPEAT; |
c->flags &= ~CLIENT_REPEAT; |
|
if (isprefix) |
|
c->flags |= CLIENT_PREFIX; |
|
else |
|
window_pane_key(wp, c, key); |
|
return; |
|
} |
|
|
tv.tv_sec = xtimeout / 1000; |
/* If this key can repeat, reset the repeat flags and timer. */ |
tv.tv_usec = (xtimeout % 1000) * 1000L; |
xtimeout = options_get_number(&c->session->options, "repeat-time"); |
evtimer_del(&c->repeat_timer); |
if (xtimeout != 0 && bd->can_repeat) { |
evtimer_add(&c->repeat_timer, &tv); |
c->flags |= CLIENT_PREFIX|CLIENT_REPEAT; |
} |
|
|
tv.tv_sec = xtimeout / 1000; |
|
tv.tv_usec = (xtimeout % 1000) * 1000L; |
|
evtimer_del(&c->repeat_timer); |
|
evtimer_add(&c->repeat_timer, &tv); |
|
} |
|
|
/* Dispatch the command. */ |
/* Dispatch the command. */ |
key_bindings_dispatch(bd, c); |
key_bindings_dispatch(bd, c); |
|
} |
|
|
|
/* Client functions that need to happen every loop. */ |
|
void |
|
server_client_loop(void) |
|
{ |
|
struct client *c; |
|
struct window *w; |
|
struct window_pane *wp; |
|
u_int i; |
|
|
|
for (i = 0; i < ARRAY_LENGTH(&clients); i++) { |
|
c = ARRAY_ITEM(&clients, i); |
|
if (c == NULL || c->session == NULL) |
|
continue; |
|
|
|
server_client_check_redraw(c); |
|
server_client_reset_state(c); |
} |
} |
if (c->session == NULL) |
|
return; |
|
w = c->session->curw->window; |
|
wp = w->active; |
|
oo = &c->session->options; |
|
s = wp->screen; |
|
|
|
/* |
/* |
* Update cursor position and mode settings. The scroll region and |
* Any windows will have been redrawn as part of clients, so clear |
* attributes are cleared across poll(2) as this is the most likely |
* their flags now. |
* time a user may interrupt tmux, for example with ~^Z in ssh(1). This |
|
* is a compromise between excessive resets and likelihood of an |
|
* interrupt. |
|
* |
|
* tty_region/tty_reset/tty_update_mode already take care of not |
|
* resetting things that are already in their default state. |
|
*/ |
*/ |
|
for (i = 0; i < ARRAY_LENGTH(&windows); i++) { |
|
w = ARRAY_ITEM(&windows, i); |
|
if (w == NULL) |
|
continue; |
|
|
|
w->flags &= ~WINDOW_REDRAW; |
|
TAILQ_FOREACH(wp, &w->panes, entry) |
|
wp->flags &= ~PANE_REDRAW; |
|
} |
|
} |
|
|
|
/* |
|
* Update cursor position and mode settings. The scroll region and attributes |
|
* are cleared when idle (waiting for an event) as this is the most likely time |
|
* a user may interrupt tmux, for example with ~^Z in ssh(1). This is a |
|
* compromise between excessive resets and likelihood of an interrupt. |
|
* |
|
* tty_region/tty_reset/tty_update_mode already take care of not resetting |
|
* things that are already in their default state. |
|
*/ |
|
void |
|
server_client_reset_state(struct client *c) |
|
{ |
|
struct window *w = c->session->curw->window; |
|
struct window_pane *wp = w->active; |
|
struct screen *s = wp->screen; |
|
struct options *oo = &c->session->options; |
|
int status, mode; |
|
|
tty_region(&c->tty, 0, c->tty.sy - 1); |
tty_region(&c->tty, 0, c->tty.sy - 1); |
|
|
status = options_get_number(oo, "status"); |
status = options_get_number(oo, "status"); |
|
|
c->tty.term_flags |= TERM_256COLOURS; |
c->tty.term_flags |= TERM_256COLOURS; |
else if (data->flags & IDENTIFY_88COLOURS) |
else if (data->flags & IDENTIFY_88COLOURS) |
c->tty.term_flags |= TERM_88COLOURS; |
c->tty.term_flags |= TERM_88COLOURS; |
|
c->tty.key_callback = server_client_handle_key; |
|
c->tty.key_data = c; |
|
|
tty_resize(&c->tty); |
tty_resize(&c->tty); |
|
|