diff --git a/CHANGES b/CHANGES index 10ccce44..2147a210 100644 --- a/CHANGES +++ b/CHANGES @@ -1,5 +1,13 @@ +28 January 2009 + +* Better support for at least the most common variant of mouse input: parse it + and adjust for different panes. Also support mouse in window/session choice + mode. + 27 January 2009 +* Bring back the fancy window titles with session/window names: it is easy to + work around problems with elinks (see FAQ). * -u flag to scroll-mode and copy-mode to start scrolled one page up. scroll-mode -u is bound to prefix,page-up (ppage) by default. * Allow status, mode and message attributes to be changed by three new options: @@ -1027,7 +1035,7 @@ (including mutt, emacs). No status bar yet and no key remapping or other customisation. -$Id: CHANGES,v 1.238 2009-01-27 23:35:44 nicm Exp $ +$Id: CHANGES,v 1.239 2009-01-28 19:52:21 nicm Exp $ LocalWords: showw utf UTF fulvio ciriaco joshe OSC APC gettime abc DEF OA clr LocalWords: rivo nurges lscm Erdely eol smysession mysession ek dstname RB ms diff --git a/FAQ b/FAQ index 46679a50..f7d02b99 100644 --- a/FAQ +++ b/FAQ @@ -161,6 +161,6 @@ The following shell function does this, and also clears the window title on exit (elinks, for some strange reason, sets it to the value of TERM): elinks() { - STY= `which elinks` "$*" + STY= `which elinks` $* echo -ne \\033]0\;\\007; } diff --git a/TODO b/TODO index 1e5b225e..f52d436b 100644 --- a/TODO +++ b/TODO @@ -89,4 +89,5 @@ - document find-window - document split-window -p and -l - attach should have a flag to create session if it doesn't exist -- do mouse mode properly and fix it when window is split +- support mouse in copy mode +- fix page up/down in choice mode AGAIN diff --git a/input-keys.c b/input-keys.c index 5f68f37c..68391147 100644 --- a/input-keys.c +++ b/input-keys.c @@ -1,4 +1,4 @@ -/* $Id: input-keys.c,v 1.24 2009-01-12 22:53:52 nicm Exp $ */ +/* $Id: input-keys.c,v 1.25 2009-01-28 19:52:21 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -205,3 +205,15 @@ input_key(struct window_pane *wp, int key) } buffer_write(wp->out, ike->data, dlen); } + +/* Handle input mouse. */ +void +input_mouse(struct window_pane *wp, u_char b, u_char x, u_char y) +{ + if (wp->screen->mode & MODE_MOUSE) { + buffer_write(wp->out, "\033[M", 3); + buffer_write8(wp->out, b + 32); + buffer_write8(wp->out, x + 33); + buffer_write8(wp->out, y + 33); + } +} diff --git a/screen-write.c b/screen-write.c index 3d534920..14c52d0b 100644 --- a/screen-write.c +++ b/screen-write.c @@ -1,4 +1,4 @@ -/* $Id: screen-write.c,v 1.30 2009-01-27 21:39:14 nicm Exp $ */ +/* $Id: screen-write.c,v 1.31 2009-01-28 19:52:21 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -33,7 +33,7 @@ screen_write_start( ctx->data = wp; if (ctx->s == NULL) ctx->s = wp->screen; - tty_write_cursor_off(ctx->data); + tty_write_update_mode(ctx->data, ctx->s->mode & ~MODE_CURSOR); } else { ctx->write = NULL; ctx->data = NULL; @@ -374,9 +374,6 @@ screen_write_insertmode(struct screen_write_ctx *ctx, int state) { struct screen *s = ctx->s; - if (ctx->write != NULL) - ctx->write(ctx->data, TTY_INSERTMODE, state); - if (state) s->mode |= MODE_INSERT; else @@ -389,9 +386,6 @@ screen_write_mousemode(struct screen_write_ctx *ctx, int state) { struct screen *s = ctx->s; - if (ctx->write != NULL) - ctx->write(ctx->data, TTY_MOUSEMODE, state); - if (state) s->mode |= MODE_MOUSE; else diff --git a/server.c b/server.c index 068d24a4..b8266e42 100644 --- a/server.c +++ b/server.c @@ -1,4 +1,4 @@ -/* $Id: server.c,v 1.114 2009-01-27 22:55:33 nicm Exp $ */ +/* $Id: server.c,v 1.115 2009-01-28 19:52:21 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -417,7 +417,7 @@ void server_check_redraw(struct client *c) { struct session *s; - char *title; + char title[512]; int flags; if (c == NULL || c->session == NULL) @@ -428,7 +428,9 @@ server_check_redraw(struct client *c) c->tty.flags &= ~TTY_FREEZE; if (options_get_number(&s->options, "set-titles")) { - title = s->curw->window->active->screen->title; + xsnprintf(title, sizeof title, "%s:%u:%s - \"%s\"", + s->name, s->curw->idx, s->curw->window->name, + s->curw->window->active->screen->title); if (c->title == NULL || strcmp(title, c->title) != 0) { if (c->title != NULL) xfree(c->title); @@ -624,6 +626,8 @@ server_handle_client(struct client *c) struct key_binding *bd; struct cmd *cmd; int key, prefix, status, xtimeout, can_repeat; + int mode; + u_char mouse[3]; xtimeout = options_get_number(&c->session->options, "repeat-time"); if (xtimeout != 0 && c->flags & CLIENT_REPEAT) { @@ -635,7 +639,7 @@ server_handle_client(struct client *c) /* Process keys. */ prefix = options_get_number(&c->session->options, "prefix"); - while (tty_keys_next(&c->tty, &key) == 0) { + while (tty_keys_next(&c->tty, &key, mouse) == 0) { server_activity = time(NULL); if (c->session == NULL) @@ -650,6 +654,12 @@ server_handle_client(struct client *c) if (server_locked) continue; + /* Check for mouse keys. */ + if (key == KEYC_MOUSE) { + window_pane_mouse(wp, c, mouse[0], mouse[1], mouse[2]); + continue; + } + /* No previous prefix key. */ if (!(c->flags & CLIENT_PREFIX)) { if (key == prefix) @@ -708,15 +718,15 @@ server_handle_client(struct client *c) return; wp = c->session->curw->window->active; /* could die - do each loop */ - /* Ensure the cursor is in the right place and correctly on or off. */ + /* Ensure cursor position and mode settings. */ status = options_get_number(&c->session->options, "status"); - if (c->prompt_string == NULL && c->message_string == NULL && - !server_locked && wp->screen->mode & MODE_CURSOR && - wp->yoff + wp->screen->cy < c->sy - status) { - tty_cursor_on(&c->tty); + if (wp->yoff + wp->screen->cy < c->sy - status) tty_cursor(&c->tty, wp->screen->cx, wp->screen->cy, wp->yoff); - } else - tty_cursor_off(&c->tty); + + mode = wp->screen->mode; + if (server_locked) + mode &= ~TTY_NOCURSOR; + tty_update_mode(&c->tty, mode); } /* Lost a client. */ diff --git a/tmux.h b/tmux.h index 29dde0f5..36e300ca 100644 --- a/tmux.h +++ b/tmux.h @@ -1,4 +1,4 @@ -/* $Id: tmux.h,v 1.254 2009-01-27 23:35:44 nicm Exp $ */ +/* $Id: tmux.h,v 1.255 2009-01-28 19:52:21 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -181,6 +181,9 @@ struct buffer { #define KEYC_REMOVESFT(k) ((k) & ~KEYC_SHIFT) #define KEYC_ISSFT(k) ((k) != KEYC_NONE && ((k) & KEYC_SHIFT)) +/* Mouse key. */ +#define KEYC_MOUSE (KEYC_OFFSET + 0x00) + /* Function keys. */ #define KEYC_F1 (KEYC_OFFSET + 0x01) #define KEYC_F2 (KEYC_OFFSET + 0x02) @@ -339,9 +342,7 @@ enum tty_cmd { TTY_DELETELINE, TTY_INSERTCHARACTER, TTY_INSERTLINE, - TTY_INSERTMODE, TTY_LINEFEED, - TTY_MOUSEMODE, TTY_REVERSEINDEX, }; @@ -570,6 +571,8 @@ struct window_mode { void (*free)(struct window_pane *); void (*resize)(struct window_pane *, u_int, u_int); void (*key)(struct window_pane *, struct client *, int); + void (*mouse)(struct window_pane *, + struct client *, u_char, u_char, u_char); void (*timer)(struct window_pane *); }; @@ -708,7 +711,7 @@ struct tty { u_int cx; u_int cy; - int cursor; + int mode; u_int rlower; u_int rupper; @@ -1010,8 +1013,6 @@ long long options_get_number(struct options *, const char *); /* tty.c */ void tty_cursor(struct tty *, u_int, u_int, u_int); -void tty_cursor_off(struct tty *); -void tty_cursor_on(struct tty *); void tty_putcode(struct tty *, enum tty_code_code); void tty_putcode1(struct tty *, enum tty_code_code, int); void tty_putcode2(struct tty *, enum tty_code_code, int, int); @@ -1021,6 +1022,7 @@ void tty_init(struct tty *, char *, char *); void tty_start_tty(struct tty *); void tty_stop_tty(struct tty *); void tty_set_title(struct tty *, const char *); +void tty_update_mode(struct tty *, int); int tty_open(struct tty *, char **); void tty_close(struct tty *, int); void tty_free(struct tty *, int); @@ -1047,12 +1049,12 @@ int tty_keys_cmp(struct tty_key *, struct tty_key *); RB_PROTOTYPE(tty_keys, tty_key, entry, tty_keys_cmp); void tty_keys_init(struct tty *); void tty_keys_free(struct tty *); -int tty_keys_next(struct tty *, int *); +int tty_keys_next(struct tty *, int *, u_char *); /* tty-write.c */ void tty_write_window(void *, enum tty_cmd, ...); void tty_vwrite_window(void *, enum tty_cmd, va_list); -void tty_write_cursor_off(void *); +void tty_write_update_mode(void *, int); /* options-cmd.c */ void set_option_string(struct cmd_ctx *, @@ -1307,6 +1309,7 @@ void input_parse(struct window_pane *); /* input-key.c */ void input_key(struct window_pane *, int); +void input_mouse(struct window_pane *, u_char, u_char, u_char); /* colour.c */ const char *colour_tostring(u_char); @@ -1452,6 +1455,8 @@ int window_pane_set_mode( void window_pane_reset_mode(struct window_pane *); void window_pane_parse(struct window_pane *); void window_pane_key(struct window_pane *, struct client *, int); +void window_pane_mouse(struct window_pane *, + struct client *, u_char, u_char, u_char); /* window-clock.c */ extern const struct window_mode window_clock_mode; diff --git a/tty-keys.c b/tty-keys.c index 6e57462a..062be838 100644 --- a/tty-keys.c +++ b/tty-keys.c @@ -1,4 +1,4 @@ -/* $Id: tty-keys.c,v 1.20 2009-01-12 22:48:00 nicm Exp $ */ +/* $Id: tty-keys.c,v 1.21 2009-01-28 19:52:21 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -25,6 +25,7 @@ void tty_keys_add(struct tty *, const char *, int, int); int tty_keys_parse_xterm(struct tty *, char *, size_t, size_t *); +int tty_keys_parse_mouse(struct tty *, char *, size_t, size_t *, u_char *); struct tty_key_ent { enum tty_code_code code; @@ -215,7 +216,7 @@ tty_keys_find(struct tty *tty, char *buf, size_t len, size_t *size) } int -tty_keys_next(struct tty *tty, int *key) +tty_keys_next(struct tty *tty, int *key, u_char *mouse) { struct tty_key *tk; struct timeval tv; @@ -244,9 +245,20 @@ tty_keys_next(struct tty *tty, int *key) return (0); } - /* Not found. Try to parse xterm-type arguments. */ - if ((*key = tty_keys_parse_xterm(tty, buf, len, &size)) != KEYC_NONE) { + /* Not found. Is this a mouse key press? */ + *key = tty_keys_parse_mouse(tty, buf, len, &size, mouse); + if (*key != KEYC_NONE) { buffer_remove(tty->in, size); + + tty->flags &= ~TTY_ESCAPE; + return (0); + } + + /* Not found. Try to parse xterm-type arguments. */ + *key = tty_keys_parse_xterm(tty, buf, len, &size); + if (*key != KEYC_NONE) { + buffer_remove(tty->in, size); + tty->flags &= ~TTY_ESCAPE; return (0); } @@ -301,6 +313,29 @@ tty_keys_next(struct tty *tty, int *key) return (0); } +int +tty_keys_parse_mouse( + unused struct tty *tty, char *buf, size_t len, size_t *size, u_char *mouse) +{ + /* + * Mouse sequences are \033[M followed by three characters indicating + * buttons, X and Y, all based at 32 with 1,1 top-left. + */ + + log_debug("mouse input is: %.*s", (int) len, buf); + if (len != 6 || memcmp(buf, "\033[M", 3) != 0) + return (KEYC_NONE); + *size = 6; + + if (buf[3] < 32 || buf[4] < 33 || buf[5] < 33) + return (KEYC_NONE); + + mouse[0] = buf[3] - 32; + mouse[1] = buf[4] - 33; + mouse[2] = buf[5] - 33; + return (KEYC_MOUSE); +} + int tty_keys_parse_xterm(struct tty *tty, char *buf, size_t len, size_t *size) { diff --git a/tty-write.c b/tty-write.c index 409ed08c..ddcca395 100644 --- a/tty-write.c +++ b/tty-write.c @@ -1,4 +1,4 @@ -/* $Id: tty-write.c,v 1.8 2009-01-27 21:39:15 nicm Exp $ */ +/* $Id: tty-write.c,v 1.9 2009-01-28 19:52:21 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -57,7 +57,7 @@ tty_vwrite_window(void *ptr, enum tty_cmd cmd, va_list ap) } void -tty_write_cursor_off(void *ptr) +tty_write_update_mode(void *ptr, int mode) { struct window_pane *wp = ptr; struct client *c; @@ -73,6 +73,7 @@ tty_write_cursor_off(void *ptr) if (c->flags & CLIENT_SUSPENDED) continue; - tty_cursor_off(&c->tty); + tty_update_mode(&c->tty, mode); } } + diff --git a/tty.c b/tty.c index cd0a68c7..82ef0c15 100644 --- a/tty.c +++ b/tty.c @@ -1,4 +1,4 @@ -/* $Id: tty.c,v 1.63 2009-01-27 21:39:15 nicm Exp $ */ +/* $Id: tty.c,v 1.64 2009-01-28 19:52:21 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -71,9 +71,7 @@ void (*tty_cmds[])(struct tty *, struct screen *, u_int, va_list) = { tty_cmd_deleteline, tty_cmd_insertcharacter, tty_cmd_insertline, - tty_cmd_insertmode, tty_cmd_linefeed, - tty_cmd_mousemode, tty_cmd_reverseindex, }; @@ -170,6 +168,8 @@ tty_start_tty(struct tty *tty) tty_putcode(tty, TTYC_CLEAR); tty_putcode(tty, TTYC_CNORM); + if (tty_term_has(tty->term, TTYC_KMOUS)) + tty_puts(tty, "\033[?1000l"); memcpy(&tty->cell, &grid_default_cell, sizeof tty->cell); @@ -179,7 +179,7 @@ tty_start_tty(struct tty *tty) tty->rlower = UINT_MAX; tty->rupper = UINT_MAX; - tty->cursor = 1; + tty->mode = MODE_CURSOR; } void @@ -206,7 +206,10 @@ tty_stop_tty(struct tty *tty) tty_raw(tty, tty_term_string(tty->term, TTYC_CLEAR)); tty_raw(tty, tty_term_string(tty->term, TTYC_RMKX)); tty_raw(tty, tty_term_string(tty->term, TTYC_RMCUP)); + tty_raw(tty, tty_term_string(tty->term, TTYC_CNORM)); + if (tty_term_has(tty->term, TTYC_KMOUS)) + tty_raw(tty, "\033[?1000l"); } } @@ -335,6 +338,30 @@ tty_set_title(struct tty *tty, const char *title) tty_putc(tty, '\007'); } +void +tty_update_mode(struct tty *tty, int mode) +{ + int changed; + + if (tty->flags & TTY_NOCURSOR) + mode &= ~MODE_CURSOR; + + changed = mode ^ tty->mode; + if (changed & MODE_CURSOR) { + if (mode & MODE_CURSOR) + tty_putcode(tty, TTYC_CNORM); + else + tty_putcode(tty, TTYC_CIVIS); + } + if (changed & MODE_MOUSE) { + if (mode & MODE_MOUSE) + tty_puts(tty, "\033[?1000h"); + else + tty_puts(tty, "\033[?1000l"); + } + tty->mode = mode; +} + void tty_emulate_repeat( struct tty *tty, enum tty_code_code code, enum tty_code_code code1, u_int n) @@ -504,32 +531,6 @@ tty_cmd_reverseindex( tty_putcode(tty, TTYC_RI); } -void -tty_cmd_insertmode(unused struct tty *tty, - unused struct screen *s, unused u_int oy, va_list ap) -{ - int ua; - - ua = va_arg(ap, int); -} - -void -tty_cmd_mousemode( - struct tty *tty, unused struct screen *s, unused u_int oy, va_list ap) -{ - int ua; - - if (!tty_term_has(tty->term, TTYC_KMOUS)) - return; - - ua = va_arg(ap, int); - - if (ua) - tty_puts(tty, "\033[?1000h"); - else - tty_puts(tty, "\033[?1000l"); -} - void tty_cmd_linefeed(struct tty *tty, struct screen *s, u_int oy, unused va_list ap) { @@ -708,26 +709,6 @@ tty_cursor(struct tty *tty, u_int cx, u_int cy, u_int oy) } } -void -tty_cursor_off(struct tty *tty) -{ - if (!tty->cursor) - return; - tty->cursor = 0; - - tty_putcode(tty, TTYC_CIVIS); -} - -void -tty_cursor_on(struct tty *tty) -{ - if (tty->cursor || tty->flags & TTY_NOCURSOR) - return; - tty->cursor = 1; - - tty_putcode(tty, TTYC_CNORM); -} - void tty_attributes(struct tty *tty, const struct grid_cell *gc) { diff --git a/window-choose.c b/window-choose.c index f865b156..2141fb1b 100644 --- a/window-choose.c +++ b/window-choose.c @@ -1,4 +1,4 @@ -/* $Id: window-choose.c,v 1.7 2009-01-27 20:22:33 nicm Exp $ */ +/* $Id: window-choose.c,v 1.8 2009-01-28 19:52:21 nicm Exp $ */ /* * Copyright (c) 2009 Nicholas Marriott @@ -26,6 +26,8 @@ struct screen *window_choose_init(struct window_pane *); void window_choose_free(struct window_pane *); void window_choose_resize(struct window_pane *, u_int, u_int); void window_choose_key(struct window_pane *, struct client *, int); +void window_choose_mouse( + struct window_pane *, struct client *, u_char, u_char, u_char); void window_choose_redraw_screen(struct window_pane *); void window_choose_write_line( @@ -39,7 +41,8 @@ const struct window_mode window_choose_mode = { window_choose_free, window_choose_resize, window_choose_key, - NULL + window_choose_mouse, + NULL, }; struct window_choose_mode_item { @@ -111,6 +114,7 @@ window_choose_init(struct window_pane *wp) s = &data->screen; screen_init(s, screen_size_x(&wp->base), screen_size_y(&wp->base), 0); s->mode &= ~MODE_CURSOR; + s->mode |= MODE_MOUSE; return (s); } @@ -220,7 +224,7 @@ window_choose_key(struct window_pane *wp, unused struct client *c, int key) else data->top -= screen_size_y(s); } - window_choose_redraw_screen(wp); + window_choose_redraw_screen(wp); break; case MODEKEY_NONE: if (key != ' ') @@ -244,6 +248,32 @@ window_choose_key(struct window_pane *wp, unused struct client *c, int key) } } +void +window_choose_mouse(struct window_pane *wp, + unused struct client *c, u_char b, u_char x, u_char y) +{ + struct window_choose_mode_data *data = wp->modedata; + struct screen *s = &data->screen; + struct window_choose_mode_item *item; + u_int idx; + + if ((b & 3) == 0) + return; + if (x >= screen_size_x(s)) + return; + if (y >= screen_size_y(s)) + return; + + idx = data->top + y; + if (idx >= ARRAY_LENGTH(&data->list)) + return; + data->selected = idx; + + item = &ARRAY_ITEM(&data->list, data->selected); + data->callback(data->data, item->idx); + window_pane_reset_mode(wp); +} + void window_choose_write_line( struct window_pane *wp, struct screen_write_ctx *ctx, u_int py) diff --git a/window-clock.c b/window-clock.c index 84435396..f4bcc526 100644 --- a/window-clock.c +++ b/window-clock.c @@ -1,4 +1,4 @@ -/* $Id: window-clock.c,v 1.4 2009-01-11 23:31:46 nicm Exp $ */ +/* $Id: window-clock.c,v 1.5 2009-01-28 19:52:21 nicm Exp $ */ /* * Copyright (c) 2009 Nicholas Marriott @@ -36,7 +36,8 @@ const struct window_mode window_clock_mode = { window_clock_free, window_clock_resize, window_clock_key, - window_clock_timer + NULL, + window_clock_timer, }; struct window_clock_mode_data { diff --git a/window-copy.c b/window-copy.c index d4ade00e..148d3a23 100644 --- a/window-copy.c +++ b/window-copy.c @@ -1,4 +1,4 @@ -/* $Id: window-copy.c,v 1.47 2009-01-27 23:35:44 nicm Exp $ */ +/* $Id: window-copy.c,v 1.48 2009-01-28 19:52:21 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -64,7 +64,8 @@ const struct window_mode window_copy_mode = { window_copy_free, window_copy_resize, window_copy_key, - NULL + NULL, + NULL, }; struct window_copy_mode_data { diff --git a/window-more.c b/window-more.c index 7cbf0004..e397f3e1 100644 --- a/window-more.c +++ b/window-more.c @@ -1,4 +1,4 @@ -/* $Id: window-more.c,v 1.27 2009-01-27 20:22:33 nicm Exp $ */ +/* $Id: window-more.c,v 1.28 2009-01-28 19:52:21 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -39,7 +39,8 @@ const struct window_mode window_more_mode = { window_more_free, window_more_resize, window_more_key, - NULL + NULL, + NULL, }; struct window_more_mode_data { diff --git a/window-scroll.c b/window-scroll.c index 6938220c..0d72294f 100644 --- a/window-scroll.c +++ b/window-scroll.c @@ -1,4 +1,4 @@ -/* $Id: window-scroll.c,v 1.30 2009-01-27 23:35:44 nicm Exp $ */ +/* $Id: window-scroll.c,v 1.31 2009-01-28 19:52:21 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -43,7 +43,8 @@ const struct window_mode window_scroll_mode = { window_scroll_free, window_scroll_resize, window_scroll_key, - NULL + NULL, + NULL, }; struct window_scroll_mode_data { diff --git a/window.c b/window.c index 76dd1960..2526289e 100644 --- a/window.c +++ b/window.c @@ -1,4 +1,4 @@ -/* $Id: window.c,v 1.63 2009-01-26 22:57:20 nicm Exp $ */ +/* $Id: window.c,v 1.64 2009-01-28 19:52:21 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -659,8 +659,26 @@ window_pane_parse(struct window_pane *wp) void window_pane_key(struct window_pane *wp, struct client *c, int key) { - if (wp->mode != NULL) - wp->mode->key(wp, c, key); - else + if (wp->mode != NULL) { + if (wp->mode->key != NULL) + wp->mode->key(wp, c, key); + } else input_key(wp, key); } + +void +window_pane_mouse( + struct window_pane *wp, struct client *c, u_char b, u_char x, u_char y) +{ + /* XXX convert from 1-based? */ + + if (y < wp->yoff || y >= wp->yoff + wp->sy) + return; + y -= wp->yoff; + + if (wp->mode != NULL) { + if (wp->mode->mouse != NULL) + wp->mode->mouse(wp, c, b, x, y); + } else + input_mouse(wp, b, x, y); +}