diff --git a/cmd-resize-pane.c b/cmd-resize-pane.c index bae6a691b..25e2393da 100644 --- a/cmd-resize-pane.c +++ b/cmd-resize-pane.c @@ -40,9 +40,9 @@ const struct cmd_entry cmd_resize_pane_entry = { .name = "resize-pane", .alias = "resizep", - .args = { "DLMRTt:Ux:y:Z", 0, 1, NULL }, - .usage = "[-DLMRTUZ] [-x width] [-y height] " CMD_TARGET_PANE_USAGE " " - "[adjustment]", + .args = { "D::L::MR::Tt:U::x:y:Z", 0, 1, NULL }, + .usage = "[-MTZ] [-U lines] [-D lines] [-L columns] [-R columns] " + "[-x width] [-y height] " CMD_TARGET_PANE_USAGE, .target = { 't', CMD_FIND_PANE, 0 }, @@ -58,17 +58,21 @@ cmd_resize_pane_exec(struct cmd *self, struct cmdq_item *item) struct window_pane *wp = target->wp; struct winlink *wl = target->wl; struct window *w = wl->window; - const char *errstr; - char *cause; - u_int adjust; - int x, y, status; + struct layout_cell *lc = wp->layout_cell; + enum layout_type type; + const char *errstr, *argval; + const char flags[4] = { 'U', 'D', 'L', 'R' }; + char *cause = NULL, flag; + u_int opposite = 0; + int adjust, x, y, status; + long unsigned i; struct grid *gd = wp->base.grid; if (args_has(args, 'T')) { if (!TAILQ_EMPTY(&wp->modes)) return (CMD_RETURN_NORMAL); adjust = screen_size_y(&wp->base) - 1 - wp->base.cy; - if (adjust > gd->hsize) + if (adjust > (int)gd->hsize) adjust = gd->hsize; grid_remove_history(gd, adjust); wp->base.cy += adjust; @@ -89,16 +93,6 @@ cmd_resize_pane_exec(struct cmd *self, struct cmdq_item *item) } server_unzoom_window(w); - if (args_count(args) == 0) - adjust = 1; - else { - adjust = strtonum(args_string(args, 0), 1, INT_MAX, &errstr); - if (errstr != NULL) { - cmdq_error(item, "adjustment %s", errstr); - return (CMD_RETURN_ERROR); - } - } - if (args_has(args, 'x')) { x = args_percentage(args, 'x', 0, INT_MAX, w->sx, &cause); if (cause != NULL) { @@ -106,7 +100,16 @@ cmd_resize_pane_exec(struct cmd *self, struct cmdq_item *item) free(cause); return (CMD_RETURN_ERROR); } - layout_resize_pane_to(wp, LAYOUT_LEFTRIGHT, x); + if (window_pane_is_floating(wp)) { + layout_resize_floating_pane_to(wp, LAYOUT_LEFTRIGHT, x, + &cause); + if (cause != NULL) { + cmdq_error(item, "size %s", cause); + free(cause); + return (CMD_RETURN_ERROR); + } + } else + layout_resize_pane_to(wp, LAYOUT_LEFTRIGHT, x); } if (args_has(args, 'y')) { y = args_percentage(args, 'y', 0, INT_MAX, w->sy, &cause); @@ -126,18 +129,60 @@ cmd_resize_pane_exec(struct cmd *self, struct cmdq_item *item) y++; break; } - layout_resize_pane_to(wp, LAYOUT_TOPBOTTOM, y); + if (window_pane_is_floating(wp)) { + layout_resize_floating_pane_to(wp, LAYOUT_TOPBOTTOM, y, + &cause); + if (cause != NULL) { + cmdq_error(item, "size %s", cause); + free(cause); + return (CMD_RETURN_ERROR); + } + } else + layout_resize_pane_to(wp, LAYOUT_TOPBOTTOM, y); } - if (args_has(args, 'L')) - layout_resize_pane(wp, LAYOUT_LEFTRIGHT, -adjust, 1); - else if (args_has(args, 'R')) - layout_resize_pane(wp, LAYOUT_LEFTRIGHT, adjust, 1); - else if (args_has(args, 'U')) - layout_resize_pane(wp, LAYOUT_TOPBOTTOM, -adjust, 1); - else if (args_has(args, 'D')) - layout_resize_pane(wp, LAYOUT_TOPBOTTOM, adjust, 1); - server_redraw_window(wl->window); + for (i = 0; i < nitems(flags); i++) { + flag = flags[i]; + if (!args_has(args, flag)) + continue; + + argval = args_get(args, flag); + if (argval == NULL) + argval = "1"; + + adjust = strtonum(argval, INT_MIN, INT_MAX, &errstr); + if (errstr != NULL) { + cmdq_error(item, "adjustment %s", errstr); + return (CMD_RETURN_ERROR); + } + + type = LAYOUT_TOPBOTTOM; + if (flag == 'L' || flag == 'R') + type = LAYOUT_LEFTRIGHT; + + if (window_pane_is_floating(wp)) { + if (flag == 'L' || flag == 'U') + opposite = 1; + + layout_resize_floating_pane(wp, type, adjust, opposite, + &cause); + if (cause != NULL) { + cmdq_error(item, "adjustment %s", cause); + free(cause); + return (CMD_RETURN_ERROR); + } + } else { + if (flag == 'L' || flag == 'U') + adjust = -adjust; + layout_resize_pane(wp, type, adjust, 1); + } + } + + if (lc->parent != NULL) + layout_fix_offsets(w); + layout_fix_panes(w, NULL); + notify_window("window-layout-changed", w); + server_redraw_window(w); return (CMD_RETURN_NORMAL); } diff --git a/key-bindings.c b/key-bindings.c index 647971a2b..5ef7706c4 100644 --- a/key-bindings.c +++ b/key-bindings.c @@ -65,7 +65,7 @@ " ''" \ " '#{?#{&&:#{!:#{pane_floating_flag}},#{>:#{window_panes},1}},Swap Up,}' 'u' {swap-pane -U}" \ " '#{?#{&&:#{!:#{pane_floating_flag}},#{>:#{window_panes},1}},Swap Down,}' 'd' {swap-pane -D}" \ - " '#{?pane_marked_set,,-}Swap Marked' 's' {swap-pane}" \ + " '#{?#{!:#{pane_floating_flag}},#{?pane_marked_set,,-}Swap Marked,}' 's' {swap-pane}" \ " ''" \ " 'Kill' 'X' {kill-pane}" \ " 'Respawn' 'R' {respawn-pane -k}" \ diff --git a/layout.c b/layout.c index 853b0b6f5..ad11d0133 100644 --- a/layout.c +++ b/layout.c @@ -880,6 +880,63 @@ layout_resize_pane_to(struct window_pane *wp, enum layout_type type, layout_resize_pane(wp, type, change, 1); } +/* Resize a floating pane to an absolute size. */ +void +layout_resize_floating_pane_to(struct window_pane *wp, enum layout_type type, + u_int size, char **cause) +{ + struct layout_cell *lc = wp->layout_cell; + + if (~lc->flags & LAYOUT_CELL_FLOATING) { + *cause = xstrdup("pane is not floating"); + return; + } + + if (size < PANE_MINIMUM || size > PANE_MAXIMUM) { + *cause = xstrdup("size is too big or too small"); + return; + } + + if (type == LAYOUT_TOPBOTTOM) + lc->sy = size; + else + lc->sx = size; +} + +/* Resize a floating pane relative to its current size. */ +void +layout_resize_floating_pane(struct window_pane *wp, enum layout_type type, + int change, int opposite, char **cause) +{ + struct layout_cell *lc = wp->layout_cell; + u_int size; + + if (~lc->flags & LAYOUT_CELL_FLOATING) { + *cause = xstrdup("pane is not floating"); + return; + } + + if (type == LAYOUT_TOPBOTTOM) { + size = lc->sy + change; + if (size < PANE_MINIMUM || size > PANE_MAXIMUM) { + *cause = xstrdup("change is too big or too small"); + return; + } + lc->sy = size; + if (opposite) + lc->yoff -= change; + } else { + size = lc->sx + change; + if (size < PANE_MINIMUM || size > PANE_MAXIMUM) { + *cause = xstrdup("change is too big or too small"); + return; + } + lc->sx = size; + if (opposite) + lc->xoff -= change; + } +} + void layout_resize_layout(struct window *w, struct layout_cell *lc, enum layout_type type, int change, int opposite) @@ -913,9 +970,7 @@ void layout_resize_pane(struct window_pane *wp, enum layout_type type, int change, int opposite) { - struct layout_cell *lc, *lcparent; - - lc = wp->layout_cell; + struct layout_cell *lc = wp->layout_cell, *lcparent; /* Find next parent of the same type. */ lcparent = lc->parent; @@ -1606,6 +1661,15 @@ layout_get_floating_cell(struct cmdq_item *item, struct args *args, w->last_new_pane_y = oy; } + if (sx < PANE_MINIMUM || sx > PANE_MAXIMUM) { + *cause = xstrdup("invalid width"); + return (NULL); + } + if (sy < PANE_MINIMUM || sy > PANE_MAXIMUM) { + *cause = xstrdup("invalid height"); + return (NULL); + } + lcnew = layout_floating_pane(w, wp, sx, sy, ox, oy); return (lcnew); } diff --git a/screen-write.c b/screen-write.c index d28c2bb46..df7ea0f9b 100644 --- a/screen-write.c +++ b/screen-write.c @@ -2934,7 +2934,6 @@ screen_write_alternateon(struct screen_write_ctx *ctx, struct grid_cell *gc, { struct tty_ctx ttyctx; struct window_pane *wp = ctx->wp; - struct window_pane_resize *r, *r1; if (wp != NULL && !options_get_number(wp->options, "alternate-screen")) return; @@ -2944,10 +2943,7 @@ screen_write_alternateon(struct screen_write_ctx *ctx, struct grid_cell *gc, return; if (wp != NULL) { - TAILQ_FOREACH_SAFE (r, &wp->resize_queue, entry, r1) { - TAILQ_REMOVE(&wp->resize_queue, r, entry); - free(r); - } + window_pane_clear_resizes(wp, NULL); layout_fix_panes(wp->window, NULL); server_redraw_window_borders(wp->window); } diff --git a/server-client.c b/server-client.c index ccce9e0d0..9838ca1a6 100644 --- a/server-client.c +++ b/server-client.c @@ -1619,7 +1619,7 @@ server_client_resize_timer(__unused int fd, __unused short events, void *data) static void server_client_check_pane_resize(struct window_pane *wp) { - struct window_pane_resize *r, *r1, *first, *last; + struct window_pane_resize *r, *first, *last; struct timeval tv = { .tv_usec = 250000 }; if (TAILQ_EMPTY(&wp->resize_queue)) @@ -1659,10 +1659,7 @@ server_client_check_pane_resize(struct window_pane *wp) } else if (last->sx != first->osx || last->sy != first->osy) { /* Multiple resizes ending up with a different size. */ window_pane_send_resize(wp, last->sx, last->sy); - TAILQ_FOREACH_SAFE(r, &wp->resize_queue, entry, r1) { - TAILQ_REMOVE(&wp->resize_queue, r, entry); - free(r); - } + window_pane_clear_resizes(wp, NULL); } else { /* * Multiple resizes ending up with the same size. There will @@ -1673,12 +1670,7 @@ server_client_check_pane_resize(struct window_pane *wp) */ r = TAILQ_PREV(last, window_pane_resizes, entry); window_pane_send_resize(wp, r->sx, r->sy); - TAILQ_FOREACH_SAFE(r, &wp->resize_queue, entry, r1) { - if (r == last) - break; - TAILQ_REMOVE(&wp->resize_queue, r, entry); - free(r); - } + window_pane_clear_resizes(wp, last); tv.tv_usec = 10000; } evtimer_add(&wp->resize_timer, &tv); diff --git a/tmux.1 b/tmux.1 index 97a0d6089..fe2e8a256 100644 --- a/tmux.1 +++ b/tmux.1 @@ -3664,16 +3664,17 @@ if specified, to .Ar new\-name . .Tg resizep .It Xo Ic resize\-pane -.Op Fl DLMRTUZ +.Op Fl MTZ .Op Fl t Ar target\-pane +.Op Fl U Ar lines +.Op Fl D Ar lines +.Op Fl L Ar columns +.Op Fl R Ar columns .Op Fl x Ar width .Op Fl y Ar height -.Op Ar adjustment .Xc .D1 Pq alias: Ic resizep -Resize a pane, up, down, left or right by -.Ar adjustment -with +Resize a pane, up, down, left or right by a specified adjustment with .Fl U , .Fl D , .Fl L @@ -3685,16 +3686,31 @@ with .Fl x or .Fl y . -The -.Ar adjustment -is given in lines or columns (the default is 1); +The adjustment is given in +.Ar lines +or +.Ar columns +(the default is 1); .Fl x and .Fl y -may be a given as a number of lines or columns or followed by +may be a given as a number of +.Ar lines +or +.Ar columns +or followed by .Ql % for a percentage of the window size (for example .Ql \-x 10% ) . +If +.Ar target\-pane +is floating, +.Fl U , +.Fl D , +.Fl L , +and +.Fl R +target their respective borders, and negative values may be given. With .Fl Z , the active pane is toggled between zoomed (occupying the whole of the window) diff --git a/tmux.h b/tmux.h index 48b90eb97..d2179cf3b 100644 --- a/tmux.h +++ b/tmux.h @@ -96,8 +96,9 @@ struct winlink; #define TMUX_LOCK_CMD "lock -np" #endif -/* Minimum layout cell size, NOT including border lines. */ +/* Minimum and maximum layout cell size, NOT including border lines. */ #define PANE_MINIMUM 1 +#define PANE_MAXIMUM 10000 /* Minimum and maximum window size. */ #define WINDOW_MINIMUM PANE_MINIMUM @@ -3476,6 +3477,8 @@ struct window_pane *window_pane_find_by_id_str(const char *); struct window_pane *window_pane_find_by_id(u_int); int window_pane_destroy_ready(struct window_pane *); void window_pane_resize(struct window_pane *, u_int, u_int); +void window_pane_clear_resizes(struct window_pane *, + struct window_pane_resize *); int window_pane_set_mode(struct window_pane *, struct window_pane *, const struct window_mode *, struct cmd_find_state *, struct args *); @@ -3557,6 +3560,10 @@ void layout_resize_pane(struct window_pane *, enum layout_type, int, int); void layout_resize_pane_to(struct window_pane *, enum layout_type, u_int); +void layout_resize_floating_pane(struct window_pane *, + enum layout_type, int, int, char **); +void layout_resize_floating_pane_to(struct window_pane *, + enum layout_type, u_int, char **); void layout_assign_pane(struct layout_cell *, struct window_pane *, int); struct layout_cell *layout_split_pane(struct window_pane *, enum layout_type, diff --git a/window.c b/window.c index fa7bdd657..8d40cf964 100644 --- a/window.c +++ b/window.c @@ -1149,9 +1149,6 @@ window_pane_wait_finish(struct window_pane *wp) static void window_pane_destroy(struct window_pane *wp) { - struct window_pane_resize *r; - struct window_pane_resize *r1; - window_pane_wait_finish(wp); window_pane_reset_mode_all(wp); @@ -1181,10 +1178,7 @@ window_pane_destroy(struct window_pane *wp) event_del(&wp->resize_timer); if (event_initialized(&wp->sync_timer)) event_del(&wp->sync_timer); - TAILQ_FOREACH_SAFE(r, &wp->resize_queue, entry, r1) { - TAILQ_REMOVE(&wp->resize_queue, r, entry); - free(r); - } + window_pane_clear_resizes(wp, NULL); RB_REMOVE(window_pane_tree, &all_window_panes, wp); @@ -1252,6 +1246,19 @@ window_pane_set_event(struct window_pane *wp) bufferevent_enable(wp->event, EV_READ|EV_WRITE); } +void +window_pane_clear_resizes(struct window_pane *wp, struct window_pane_resize *except) +{ + struct window_pane_resize *r, *r1; + + TAILQ_FOREACH_SAFE(r, &wp->resize_queue, entry, r1) { + if (r == except) + continue; + TAILQ_REMOVE(&wp->resize_queue, r, entry); + free(r); + } +} + void window_pane_resize(struct window_pane *wp, u_int sx, u_int sy) {