From 1f9a8e70d90265de8a3e1b0a981d3ef5b1352e52 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 4 Oct 2007 19:03:52 +0000 Subject: [PATCH] Incomplete resize support. --- CHANGES | 10 +++-- Makefile | 4 +- client.c | 4 +- cmd-attach-session.c | 3 +- cmd-new-session.c | 4 +- input.c | 6 ++- resize.c | 102 +++++++++++++++++++++++++++++++++++++++++++ screen.c | 5 ++- server-fn.c | 43 ++++++++++++++++-- server-msg.c | 29 +++--------- server.c | 6 ++- status.c | 4 +- tmux.h | 7 ++- 13 files changed, 182 insertions(+), 45 deletions(-) create mode 100644 resize.c diff --git a/CHANGES b/CHANGES index a43bb656..82b679e0 100644 --- a/CHANGES +++ b/CHANGES @@ -1,8 +1,10 @@ 04 October 2007 -* (mxey) Added my tmux start script as an example (examples/start-tmux.sh) -* (mxey) New sessions can now be given a command for their first window -* (mxey) Fixed usage statemnt for new-window +* (nicm) Partial resizing support. Still buggy. A C-b S and back sometimes fixes + it when it goes wonky. +* (mxey) Added my tmux start script as an example (examples/start-tmux.sh). +* (mxey) New sessions can now be given a command for their first window. +* (mxey) Fixed usage statement for new-window. * (nicm) attach-session (can't believe I forgot it until now!) and list-windows commands. * (nicm) rename-window and select-window commands. @@ -115,5 +117,5 @@ (including mutt, emacs). No status bar yet and no key remapping or other customisation. -$Id: CHANGES,v 1.34 2007-10-04 14:14:12 mxey Exp $ +$Id: CHANGES,v 1.35 2007-10-04 19:03:51 nicm Exp $ diff --git a/Makefile b/Makefile index 4323ca85..b60ebc89 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.22 2007-10-04 11:52:02 nicm Exp $ +# $Id: Makefile,v 1.23 2007-10-04 19:03:51 nicm Exp $ .SUFFIXES: .c .o .y .h .PHONY: clean @@ -18,7 +18,7 @@ META?= \002 # C-b SRCS= tmux.c server.c server-msg.c server-fn.c buffer.c buffer-poll.c status.c \ xmalloc.c xmalloc-debug.c input.c input-keys.c screen.c window.c \ session.c local.c log.c client.c client-msg.c client-fn.c key-string.c \ - key-bindings.c cmd.c cmd-new-session.c cmd-detach-session.c \ + key-bindings.c resize.c cmd.c cmd-new-session.c cmd-detach-session.c \ cmd-list-sessions.c cmd-new-window.c cmd-next-window.c cmd-bind-key.c \ cmd-unbind-key.c cmd-previous-window.c cmd-last-window.c cmd-list-keys.c \ cmd-set-option.c cmd-rename-window.c cmd-select-window.c \ diff --git a/client.c b/client.c index 835c77fe..889ebf20 100644 --- a/client.c +++ b/client.c @@ -1,4 +1,4 @@ -/* $Id: client.c,v 1.12 2007-10-04 11:52:02 nicm Exp $ */ +/* $Id: client.c,v 1.13 2007-10-04 19:03:51 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -175,7 +175,7 @@ client_main(struct client_ctx *cctx) if (error != NULL) { if (*error == '\0') { - printf("[exited]\n", error); + printf("[exited]\n"); return (0); } printf("[error: %s]\n", error); diff --git a/cmd-attach-session.c b/cmd-attach-session.c index 2f25d0a7..f97d802f 100644 --- a/cmd-attach-session.c +++ b/cmd-attach-session.c @@ -1,4 +1,4 @@ -/* $Id: cmd-attach-session.c,v 1.1 2007-10-04 11:52:03 nicm Exp $ */ +/* $Id: cmd-attach-session.c,v 1.2 2007-10-04 19:03:51 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -55,5 +55,6 @@ cmd_attach_session_exec(unused void *ptr, struct cmd_ctx *ctx) c->session = s; server_write_client(c, MSG_READY, NULL, 0); + recalculate_sizes(); server_redraw_client(c); } diff --git a/cmd-new-session.c b/cmd-new-session.c index 206aa3fc..4874d9bb 100644 --- a/cmd-new-session.c +++ b/cmd-new-session.c @@ -1,4 +1,4 @@ -/* $Id: cmd-new-session.c,v 1.6 2007-10-04 13:43:14 mxey Exp $ */ +/* $Id: cmd-new-session.c,v 1.7 2007-10-04 19:03:51 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -99,7 +99,7 @@ cmd_new_session_usage(void) void cmd_new_session_exec(void *ptr, struct cmd_ctx *ctx) { - struct cmd_new_session_data *data = ptr, std = { NULL, 0 }; + struct cmd_new_session_data *data = ptr, std = { NULL, NULL, 0 }; struct client *c = ctx->client; char *cmd; u_int sy; diff --git a/input.c b/input.c index 2434a24f..305a1746 100644 --- a/input.c +++ b/input.c @@ -1,4 +1,4 @@ -/* $Id: input.c,v 1.19 2007-10-03 10:18:32 nicm Exp $ */ +/* $Id: input.c,v 1.20 2007-10-04 19:03:51 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -427,7 +427,9 @@ void input_handle_character(u_char ch, struct input_ctx *ictx) { log_debug2("-- ch %zu: %hhu (%c)", ictx->off, ch, ch); - + + if (ictx->s->cx > ictx->s->sx - 1 || ictx->s->cy > ictx->s->sy - 1) + return; screen_write_character(ictx->s, ch); input_store8(ictx->b, ch); } diff --git a/resize.c b/resize.c new file mode 100644 index 00000000..2b1bd77c --- /dev/null +++ b/resize.c @@ -0,0 +1,102 @@ +/* $Id: resize.c,v 1.1 2007-10-04 19:03:51 nicm Exp $ */ + +/* + * Copyright (c) 2007 Nicholas Marriott + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER + * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include + +#include + +#include "tmux.h" + +/* + * Recalculate window and session sizes. + * + * Every session has the size of the smallest client it is attached to and + * every window the size of the smallest session it is attached to. + * + * So, when a client is resized or a session attached to or detached from a + * client, the window sizes must be recalculated. For each session, find the + * smallest client it is attached to, and resize it to that size. Then for + * every window, find the smallest session it is attached to, resize it to that + * size and clear and redraw every client with it as the current window. + * + * This is quite inefficient - better/additional data structures are needed + * to make it better. + */ + +void +recalculate_sizes(void) +{ + struct session *s; + struct client *c; + struct window *w; + u_int i, j, ssx, ssy; + + for (i = 0; i < ARRAY_LENGTH(&sessions); i++) { + s = ARRAY_ITEM(&sessions, i); + if (s == NULL) + continue; + + ssx = ssy = UINT_MAX; + for (j = 0; j < ARRAY_LENGTH(&clients); j++) { + c = ARRAY_ITEM(&clients, j); + if (c == NULL || c->session != s) + continue; + if (c->sx < ssx) + ssx = c->sx; + if (c->sy < ssy) + ssy = c->sy; + } + if (ssy < status_lines) + ssy = status_lines + 1; + ssy -= status_lines; + if (s->sx == ssx && s->sy == ssy) + continue; + + log_debug( + "session size %u,%u (was %u,%u)", ssx, ssy, s->sx, s->sy); + + s->sx = ssx; + s->sy = ssy; + } + + for (i = 0; i < ARRAY_LENGTH(&windows); i++) { + w = ARRAY_ITEM(&windows, i); + if (w == NULL) + continue; + + ssx = ssy = UINT_MAX; + for (j = 0; j < ARRAY_LENGTH(&sessions); j++) { + s = ARRAY_ITEM(&sessions, j); + if (s == NULL || !session_has(s, w)) + continue; + if (s->sx < ssx) + ssx = s->sx; + if (s->sy < ssy) + ssy = s->sy; + } + if (w->screen.sx == ssx && w->screen.sy == ssy) + continue; + + log_debug("window size %u,%u (was %u,%u)", + ssx, ssy, w->screen.sx, w->screen.sy); + + server_clear_window(w); + window_resize(w, ssx, ssy); + server_redraw_window(w); + } +} diff --git a/screen.c b/screen.c index 5d81afd8..559a3fa8 100644 --- a/screen.c +++ b/screen.c @@ -1,4 +1,4 @@ -/* $Id: screen.c,v 1.19 2007-10-01 14:18:42 nicm Exp $ */ +/* $Id: screen.c,v 1.20 2007-10-04 19:03:51 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -87,6 +87,9 @@ screen_resize(struct screen *s, u_int sx, u_int sy) s->sx = sx; s->sy = sy; + s->ry_upper = 0; + s->ry_lower = screen_last_y(s); + log_debug("resizing screen (%u, %u) -> (%u, %u)", ox, oy, sx, sy); if (sy < oy) { diff --git a/server-fn.c b/server-fn.c index 5237dada..97e0456d 100644 --- a/server-fn.c +++ b/server-fn.c @@ -1,4 +1,4 @@ -/* $Id: server-fn.c,v 1.17 2007-10-04 10:39:07 nicm Exp $ */ +/* $Id: server-fn.c,v 1.18 2007-10-04 19:03:51 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -128,7 +128,7 @@ server_redraw_status(struct client *c) struct hdr hdr; size_t size; - if (status_lines == 0) + if (status_lines == 0 || c->sy <= status_lines) return; buffer_ensure(c->out, sizeof hdr); @@ -144,11 +144,35 @@ server_redraw_status(struct client *c) } void -server_redraw_client(struct client *c) +server_clear_client(struct client *c) { + struct screen *s = &c->session->window->screen; struct hdr hdr; size_t size; + u_int i; + + buffer_ensure(c->out, sizeof hdr); + buffer_add(c->out, sizeof hdr); + size = BUFFER_USED(c->out); + + input_store_zero(c->out, CODE_CURSOROFF); + for (i = 0; i < s->sy; i++) { + input_store_two(c->out, CODE_CURSORMOVE, i + 1, 1); + input_store_zero(c->out, CODE_CLEARLINE); + } + + size = BUFFER_USED(c->out) - size; + hdr.type = MSG_DATA; + hdr.size = size; + memcpy(BUFFER_IN(c->out) - size - sizeof hdr, &hdr, sizeof hdr); +} + +void +server_redraw_client(struct client *c) +{ struct screen *s = &c->session->window->screen; + struct hdr hdr; + size_t size; buffer_ensure(c->out, sizeof hdr); buffer_add(c->out, sizeof hdr); @@ -181,6 +205,19 @@ server_redraw_session(struct session *s) } } +void +server_clear_window(struct window *w) +{ + struct client *c; + u_int i; + + for (i = 0; i < ARRAY_LENGTH(&clients); i++) { + c = ARRAY_ITEM(&clients, i); + if (c != NULL && c->session != NULL && c->session->window == w) + server_clear_client(c); + } +} + void server_redraw_window(struct window *w) { diff --git a/server-msg.c b/server-msg.c index ac67002d..701300f5 100644 --- a/server-msg.c +++ b/server-msg.c @@ -1,4 +1,4 @@ -/* $Id: server-msg.c,v 1.23 2007-10-04 11:52:03 nicm Exp $ */ +/* $Id: server-msg.c,v 1.24 2007-10-04 19:03:52 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -150,7 +150,7 @@ server_msg_fn_identify(struct hdr *hdr, struct client *c) fatalx("bad MSG_IDENTIFY size"); buffer_read(c->in, &data, sizeof data); - log_debug("got identify msg from client: %u,%u", data.sx, data.sy); + log_debug("identify msg from client: %u,%u", data.sx, data.sy); c->sx = data.sx; c->sy = data.sy; @@ -164,12 +164,13 @@ int server_msg_fn_resize(struct hdr *hdr, struct client *c) { struct msg_resize_data data; - u_int sy; if (hdr->size != sizeof data) fatalx("bad MSG_RESIZE size"); buffer_read(c->in, &data, sizeof data); + log_debug("resize msg from client: %u,%u", data.sx, data.sy); + c->sx = data.sx; if (c->sx == 0) c->sx = 80; @@ -177,27 +178,7 @@ server_msg_fn_resize(struct hdr *hdr, struct client *c) if (c->sy == 0) c->sy = 25; - sy = c->sy; - if (sy < status_lines) - sy = status_lines + 1; - sy -= status_lines; - - /* XXX */ - /* - * Okay. Need to be able to recalculate sizes: - * - every session has the size of the smallest client it is - * attached to - * - every window has the size of the smallest session it is - * attached to - * - * So, when a client is resized or a session added to a new client: - * - find the smallest client it is attached to, and resize to - * that size - * And when a session's window changes or a window is added/removed - * from a session: - * - find the smallest session the window is attached to - * and use that - */ + recalculate_sizes(); return (0); } diff --git a/server.c b/server.c index fb033f87..8797d2d6 100644 --- a/server.c +++ b/server.c @@ -1,4 +1,4 @@ -/* $Id: server.c,v 1.23 2007-10-04 11:52:03 nicm Exp $ */ +/* $Id: server.c,v 1.24 2007-10-04 19:03:52 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -309,6 +309,8 @@ server_lost_client(struct client *c) buffer_destroy(c->in); buffer_destroy(c->out); xfree(c); + + recalculate_sizes(); } /* Handle window data. */ @@ -376,5 +378,7 @@ server_lost_window(struct window *w) server_redraw_client(c); } } + + recalculate_sizes(); } diff --git a/status.c b/status.c index e56b7532..18803479 100644 --- a/status.c +++ b/status.c @@ -1,4 +1,4 @@ -/* $Id: status.c,v 1.2 2007-10-03 23:32:26 nicm Exp $ */ +/* $Id: status.c,v 1.3 2007-10-04 19:03:52 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -37,7 +37,7 @@ status_write(struct client *c) input_store_two(b, CODE_CURSORMOVE, c->sy - status_lines + 1, 1); input_store_two(b, CODE_ATTRIBUTES, ATTR_REVERSE, 0x20); - size = s->sx; + size = c->sx; for (i = 0; i < ARRAY_LENGTH(&c->session->windows); i++) { w = ARRAY_ITEM(&c->session->windows, i); if (w == NULL) diff --git a/tmux.h b/tmux.h index 88018747..d70b1a1a 100644 --- a/tmux.h +++ b/tmux.h @@ -1,4 +1,4 @@ -/* $Id: tmux.h,v 1.47 2007-10-04 11:52:03 nicm Exp $ */ +/* $Id: tmux.h,v 1.48 2007-10-04 19:03:52 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -593,14 +593,19 @@ void server_write_session( void server_write_window( struct window *, enum hdrtype, const void *, size_t); void server_redraw_status(struct client *); +void server_clear_client(struct client *); void server_redraw_client(struct client *); void server_redraw_session(struct session *); +void server_clear_window(struct window *); void server_redraw_window(struct window *); void server_write_message(struct client *, const char *, ...); /* status.c */ void status_write(struct client *c); +/* resize.c */ +void recalculate_sizes(void); + /* input.c */ void input_init(struct input_ctx *, struct screen *); void input_free(struct input_ctx *);